UI: Introduce View pie in more editors

#### Motivation

The View pie menu is a convenient way to access operators such as `Frame Selected` and `Frame All` which are usually mapped to `PERIOD` or `HOME` keys on the right side of most keyboard, making it hard hard to reach with the left hand.

The motivation for this patch comes from working with a 75% keyboard (no numpad). Most laptops face a similar problem.

#### Implementation

The View pie menu has been added to the following editors and sub-modes where applicable:

* Node Editor
* Video Sequencer
* Dopesheet
* Graph
* NLA
* Image
* Clip
* Outliner

More options could definitely be added to this menu for convenience, as long as it maintains the common options in the same place (Frame Selected on the left, Frame All on the right).

For positioning I went with the following layout:
{F11791186, size=full}

I've added `Zoom 1:1`to the Image Editor and the VSE Preview since there is no way to reset the zoom on keyboards without numpad (unless Emulate Numpad is turned on).

The Outliner uses `Show Active` and `Show Hierarchy` which are the closest ones to the equivalent in other editors. Should `Show Active` be renamed to `Frame Selected`?

The shortcut assigned is the same as the 3D Viewport (`ACCENT_GRAVE`).

#### Screenshots

Node Editor
{F11778387, size=full}

Dopesheet
{F11778400, size=full}

Graph
{F11778403, size=full}

Image Editor (Paint and View)
{F11791113, size=full}

Image Editor (Mask)
{F11791114, size=full}

UV Editor
{F11791119, size=full}

Clip Editor (Tracking)
{F11791137, size=full}

Clip Editor (Mask)
{F11791140, size=full}

Clip Editor (Graph)
{F11791151, size=full}
View operators are not yet implemented in Clip Editor Dopesheet mode (left a note about this in the menu poll).

Reviewed By: #user_interface, campbellbarton

Differential Revision: https://developer.blender.org/D13169
This commit is contained in:
Pablo Vazquez 2021-11-10 02:17:24 +01:00
parent f1a8644121
commit e1bd4bbb66
9 changed files with 163 additions and 0 deletions

View File

@ -1097,6 +1097,7 @@ def km_outliner(params):
# Fall through to generic context menu if the item(s) selected have no type specific actions.
("outliner.operation", {"type": 'RIGHTMOUSE', "value": 'PRESS'}, None),
op_menu("OUTLINER_MT_context_menu", {"type": 'RIGHTMOUSE', "value": 'PRESS'}),
op_menu_pie("OUTLINER_MT_view_pie", {"type": 'ACCENT_GRAVE', "value": 'PRESS'}),
("outliner.item_drag_drop", {"type": 'EVT_TWEAK_L', "value": 'ANY'}, None),
("outliner.item_drag_drop", {"type": 'EVT_TWEAK_L', "value": 'ANY', "shift": True}, None),
("outliner.show_hierarchy", {"type": 'HOME', "value": 'PRESS'}, None),
@ -1748,6 +1749,7 @@ def km_graph_editor(params):
("graph.view_all", {"type": 'NDOF_BUTTON_FIT', "value": 'PRESS'}, None),
("graph.view_selected", {"type": 'NUMPAD_PERIOD', "value": 'PRESS'}, None),
("graph.view_frame", {"type": 'NUMPAD_0', "value": 'PRESS'}, None),
op_menu_pie("GRAPH_MT_view_pie", {"type": 'ACCENT_GRAVE', "value": 'PRESS'}),
("graph.fmodifier_add", {"type": 'M', "value": 'PRESS', "shift": True, "ctrl": True},
{"properties": [("only_active", False)]}),
("anim.channels_editable_toggle", {"type": 'TAB', "value": 'PRESS'}, None),
@ -1815,6 +1817,7 @@ def km_image_generic(params):
("image.cycle_render_slot", {"type": 'J', "value": 'PRESS', "repeat": True}, None),
("image.cycle_render_slot", {"type": 'J', "value": 'PRESS', "alt": True, "repeat": True},
{"properties": [("reverse", True)]}),
op_menu_pie("IMAGE_MT_view_pie", {"type": 'ACCENT_GRAVE', "value": 'PRESS'}),
])
if not params.legacy:
@ -2027,6 +2030,7 @@ def km_node_editor(params):
("node.view_all", {"type": 'HOME', "value": 'PRESS'}, None),
("node.view_all", {"type": 'NDOF_BUTTON_FIT', "value": 'PRESS'}, None),
("node.view_selected", {"type": 'NUMPAD_PERIOD', "value": 'PRESS'}, None),
op_menu_pie("NODE_MT_view_pie", {"type": 'ACCENT_GRAVE', "value": 'PRESS'}),
("node.delete", {"type": 'X', "value": 'PRESS'}, None),
("node.delete", {"type": 'DEL', "value": 'PRESS'}, None),
("node.delete_reconnect", {"type": 'X', "value": 'PRESS', "ctrl": True}, None),
@ -2389,6 +2393,7 @@ def km_dopesheet(params):
("action.view_all", {"type": 'NDOF_BUTTON_FIT', "value": 'PRESS'}, None),
("action.view_selected", {"type": 'NUMPAD_PERIOD', "value": 'PRESS'}, None),
("action.view_frame", {"type": 'NUMPAD_0', "value": 'PRESS'}, None),
op_menu_pie("DOPESHEET_MT_view_pie", {"type": 'ACCENT_GRAVE', "value": 'PRESS'}),
("anim.channels_editable_toggle", {"type": 'TAB', "value": 'PRESS'}, None),
("anim.channels_select_filter", {"type": 'F', "value": 'PRESS', "ctrl": True}, None),
("transform.transform", {"type": 'G', "value": 'PRESS'},
@ -2503,6 +2508,7 @@ def km_nla_editor(params):
("nla.view_all", {"type": 'NDOF_BUTTON_FIT', "value": 'PRESS'}, None),
("nla.view_selected", {"type": 'NUMPAD_PERIOD', "value": 'PRESS'}, None),
("nla.view_frame", {"type": 'NUMPAD_0', "value": 'PRESS'}, None),
op_menu_pie("NLA_MT_view_pie", {"type": 'ACCENT_GRAVE', "value": 'PRESS'}),
("nla.actionclip_add", {"type": 'A', "value": 'PRESS', "shift": True}, None),
("nla.transition_add", {"type": 'T', "value": 'PRESS', "shift": True}, None),
("nla.soundclip_add", {"type": 'K', "value": 'PRESS', "shift": True}, None),
@ -2835,6 +2841,7 @@ def km_sequencer(params):
("sequencer.select_grouped", {"type": 'G', "value": 'PRESS', "shift": True}, None),
op_menu("SEQUENCER_MT_add", {"type": 'A', "value": 'PRESS', "shift": True}),
op_menu("SEQUENCER_MT_change", {"type": 'C', "value": 'PRESS'}),
op_menu_pie("SEQUENCER_MT_view_pie", {"type": 'ACCENT_GRAVE', "value": 'PRESS'}),
("sequencer.slip", {"type": 'S', "value": 'PRESS'}, None),
("wm.context_set_int", {"type": 'O', "value": 'PRESS'},
{"properties": [("data_path", 'scene.sequence_editor.overlay_frame'), ("value", 0)]}),
@ -2892,6 +2899,7 @@ def km_sequencerpreview(params):
{"properties": [("ratio", 0.25)]}),
("sequencer.view_zoom_ratio", {"type": 'NUMPAD_8', "value": 'PRESS'},
{"properties": [("ratio", 0.125)]}),
op_menu_pie("SEQUENCER_MT_preview_view_pie", {"type": 'ACCENT_GRAVE', "value": 'PRESS'}),
# Edit.
("transform.translate", {"type": params.select_tweak, "value": 'ANY'}, None),
@ -3042,6 +3050,7 @@ def km_clip(_params):
op_menu_pie("CLIP_MT_solving_pie", {"type": 'S', "value": 'PRESS', "shift": True}),
op_menu_pie("CLIP_MT_marker_pie", {"type": 'E', "value": 'PRESS', "shift": True}),
op_menu_pie("CLIP_MT_reconstruction_pie", {"type": 'W', "value": 'PRESS', "shift": True}),
op_menu_pie("CLIP_MT_view_pie", {"type": 'ACCENT_GRAVE', "value": 'PRESS'}),
])
return keymap

View File

@ -1858,6 +1858,43 @@ class CLIP_MT_reconstruction_pie(Menu):
pie.operator("clip.apply_solution_scale", icon='ARROW_LEFTRIGHT')
class CLIP_MT_view_pie(Menu):
bl_label = "View"
@classmethod
def poll(cls, context):
space = context.space_data
# View operators are not yet implemented in Dopesheet mode.
return space.view != 'DOPESHEET'
def draw(self, context):
layout = self.layout
sc = context.space_data
pie = layout.menu_pie()
if sc.view == 'CLIP':
pie.operator("clip.view_all")
pie.operator("clip.view_selected", icon='ZOOM_SELECTED')
if sc.mode == 'MASK':
pie.operator("clip.view_center_cursor")
pie.separator()
else:
# Add spaces so items stay in the same position through all modes.
pie.separator()
pie.separator()
pie.operator("clip.view_all", text="Frame All Fit").fit_view = True
if sc.view == 'GRAPH':
pie.operator_context = 'INVOKE_REGION_PREVIEW'
pie.operator("clip.graph_view_all")
pie.separator()
pie.operator("clip.graph_center_current_frame")
classes = (
CLIP_UL_tracking_objects,
CLIP_HT_header,
@ -1925,6 +1962,7 @@ classes = (
CLIP_MT_tracking_pie,
CLIP_MT_reconstruction_pie,
CLIP_MT_solving_pie,
CLIP_MT_view_pie,
)
if __name__ == "__main__": # only for live edit.

View File

@ -379,6 +379,18 @@ class DOPESHEET_MT_view(Menu):
layout.menu("INFO_MT_area")
class DOPESHEET_MT_view_pie(Menu):
bl_label = "View"
def draw(self, context):
layout = self.layout
pie = layout.menu_pie()
pie.operator("action.view_all")
pie.operator("action.view_selected", icon='ZOOM_SELECTED')
pie.operator("action.view_frame")
class DOPESHEET_MT_select(Menu):
bl_label = "Select"
@ -778,6 +790,7 @@ classes = (
DOPESHEET_MT_context_menu,
DOPESHEET_MT_channel_context_menu,
DOPESHEET_MT_snap_pie,
DOPESHEET_MT_view_pie,
DOPESHEET_PT_filters,
DOPESHEET_PT_gpencil_mode,
DOPESHEET_PT_gpencil_layer_masks,

View File

@ -338,6 +338,18 @@ class GRAPH_MT_key_snap(Menu):
layout.operator("graph.snap_cursor_value", text="Cursor Value to Selection")
class GRAPH_MT_view_pie(Menu):
bl_label = "View"
def draw(self, context):
layout = self.layout
pie = layout.menu_pie()
pie.operator("graph.view_all")
pie.operator("graph.view_selected", icon='ZOOM_SELECTED')
pie.operator("graph.view_frame")
class GRAPH_MT_delete(Menu):
bl_label = "Delete"
@ -468,6 +480,7 @@ classes = (
GRAPH_MT_channel_context_menu,
GRAPH_MT_pivot_pie,
GRAPH_MT_snap_pie,
GRAPH_MT_view_pie,
GRAPH_PT_filters,
)

View File

@ -591,6 +591,31 @@ class IMAGE_MT_uvs_snap_pie(Menu):
).target = 'ADJACENT_UNSELECTED'
class IMAGE_MT_view_pie(Menu):
bl_label = "View"
def draw(self, context):
layout = self.layout
sima = context.space_data
show_uvedit = sima.show_uvedit
show_maskedit = sima.show_maskedit
pie = layout.menu_pie()
pie.operator("image.view_all")
if show_uvedit or show_maskedit:
pie.operator("image.view_selected", text="Frame Selected", icon='ZOOM_SELECTED')
pie.operator("image.view_center_cursor", text="Center View to Cursor")
else:
# Add spaces so items stay in the same position through all modes.
pie.separator()
pie.separator()
pie.operator("image.view_zoom_ratio", text="Zoom 1:1").ratio = 1
pie.operator("image.view_all", text="Frame All Fit").fit_view = True
class IMAGE_HT_tool_header(Header):
bl_space_type = 'IMAGE_EDITOR'
bl_region_type = 'TOOL_HEADER'
@ -1633,6 +1658,7 @@ classes = (
IMAGE_MT_mask_context_menu,
IMAGE_MT_pivot_pie,
IMAGE_MT_uvs_snap_pie,
IMAGE_MT_view_pie,
IMAGE_HT_tool_header,
IMAGE_HT_header,
IMAGE_MT_editor_menus,

View File

@ -247,6 +247,18 @@ class NLA_MT_snap_pie(Menu):
pie.operator("nla.snap", text="Selection to Nearest Marker").type = 'NEAREST_MARKER'
class NLA_MT_view_pie(Menu):
bl_label = "View"
def draw(self, context):
layout = self.layout
pie = layout.menu_pie()
pie.operator("nla.view_all")
pie.operator("nla.view_selected", icon='ZOOM_SELECTED')
pie.operator("nla.view_frame")
class NLA_MT_context_menu(Menu):
bl_label = "NLA Context Menu"
@ -300,6 +312,7 @@ classes = (
NLA_MT_add,
NLA_MT_edit_transform,
NLA_MT_snap_pie,
NLA_MT_view_pie,
NLA_MT_context_menu,
NLA_MT_channel_context_menu,
NLA_PT_filters,

View File

@ -367,6 +367,17 @@ class NODE_MT_node(Menu):
layout.operator("node.read_viewlayers")
class NODE_MT_view_pie(Menu):
bl_label = "View"
def draw(self, context):
layout = self.layout
pie = layout.menu_pie()
pie.operator("node.view_all")
pie.operator("node.view_selected", icon='ZOOM_SELECTED')
class NODE_PT_active_tool(ToolActivePanelHelper, Panel):
bl_space_type = 'NODE_EDITOR'
bl_region_type = 'UI'
@ -877,6 +888,7 @@ classes = (
NODE_MT_node,
NODE_MT_node_color_context_menu,
NODE_MT_context_menu,
NODE_MT_view_pie,
NODE_PT_material_slots,
NODE_PT_node_color_presets,
NODE_PT_active_node_generic,

View File

@ -142,6 +142,17 @@ class OUTLINER_MT_context_menu_view(Menu):
layout.operator("outliner.show_one_level", text="Hide One Level").open = False
class OUTLINER_MT_view_pie(Menu):
bl_label = "View"
def draw(self, context):
layout = self.layout
pie = layout.menu_pie()
pie.operator("outliner.show_hierarchy")
pie.operator("outliner.show_active", icon='ZOOM_SELECTED')
class OUTLINER_MT_edit_datablocks(Menu):
bl_label = "Edit"
@ -471,6 +482,7 @@ classes = (
OUTLINER_MT_asset,
OUTLINER_MT_context_menu,
OUTLINER_MT_context_menu_view,
OUTLINER_MT_view_pie,
OUTLINER_PT_filter,
)

View File

@ -1173,6 +1173,31 @@ class SEQUENCER_MT_pivot_pie(Menu):
pie.prop_enum(sequencer_tool_settings, "pivot_point", value='MEDIAN')
class SEQUENCER_MT_view_pie(Menu):
bl_label = "View"
def draw(self, context):
layout = self.layout
pie = layout.menu_pie()
pie.operator("sequencer.view_all")
pie.operator("sequencer.view_selected", text="Frame Selected", icon='ZOOM_SELECTED')
class SEQUENCER_MT_preview_view_pie(Menu):
bl_label = "View"
def draw(self, context):
layout = self.layout
pie = layout.menu_pie()
pie.operator_context = 'INVOKE_REGION_PREVIEW'
pie.operator("sequencer.view_all_preview")
pie.operator("sequencer.view_selected", text="Frame Selected", icon='ZOOM_SELECTED')
pie.separator()
pie.operator("sequencer.view_zoom_ratio", text="Zoom 1:1").ratio = 1
class SequencerButtonsPanel:
bl_space_type = 'SEQUENCE_EDITOR'
bl_region_type = 'UI'
@ -2615,6 +2640,8 @@ classes = (
SEQUENCER_MT_context_menu,
SEQUENCER_MT_preview_context_menu,
SEQUENCER_MT_pivot_pie,
SEQUENCER_MT_view_pie,
SEQUENCER_MT_preview_view_pie,
SEQUENCER_PT_color_tag_picker,