diff --git a/.gitignore b/.gitignore
index 00154fa..45eb732 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,6 +1,7 @@
-settings.json
+preferences.json
bin
deploy.sh
__pycache__/
venv
.venv
+settings.json
diff --git a/README.md b/README.md
index c1b378b..b430d1a 100644
--- a/README.md
+++ b/README.md
@@ -33,7 +33,7 @@ The viewport has be updated to use 3 interactive "hot regions" to control the ca
If you are a pen tablet user; the pen will still draw, while your finger can be used to control the camera.
-If your tablet doesn't support touch; you can set the middle mouse button to activate the control regions in the add-on settings.
+If your tablet doesn't support touch; you can set the middle mouse button to activate the control regions in the add-on prefs.
- Pan by dragging for the middle of the viewport
- Zoom by dragging along the left or right edge of the viewport
@@ -123,7 +123,7 @@ This feature allows you to quickly access the UI for brush resizing and strength
-This button allows you to assign up to 8 commands, unique to each edit mode (object, sculpt, texture paint, weight paint, etc) and reposition it where ever you want, to best fit your workspace. If you don't need it, simply disable it in the settings menu.
+This button allows you to assign up to 8 commands, unique to each edit mode (object, sculpt, texture paint, weight paint, etc) and reposition it where ever you want, to best fit your workspace. If you don't need it, simply disable it in the prefs menu.
# Feature Roadmap
@@ -151,15 +151,15 @@ It will output the files to include and generate a new ZIP file:
```
$ ./bundle.sh
adding: touchview/ (stored 0%)
- adding: touchview/lib/ (stored 0%)
- adding: touchview/lib/Gizmos.py (deflated 77%)
- adding: touchview/lib/items.py (deflated 68%)
- adding: touchview/lib/Operators.py (deflated 80%)
- adding: touchview/lib/Overlay.py (deflated 73%)
- adding: touchview/lib/Panel.py (deflated 69%)
- adding: touchview/lib/touch_input.py (deflated 69%)
- adding: touchview/lib/__init__.py (deflated 70%)
- adding: touchview/Settings.py (deflated 76%)
+ adding: touchview/source/ (stored 0%)
+ adding: touchview/source/gizmos.py (deflated 77%)
+ adding: touchview/source/items.py (deflated 68%)
+ adding: touchview/source/operators.py (deflated 80%)
+ adding: touchview/source/overlay.py (deflated 73%)
+ adding: touchview/source/panel.py (deflated 69%)
+ adding: touchview/source/touch_input.py (deflated 69%)
+ adding: touchview/source/__init__.py (deflated 70%)
+ adding: touchview/prefs.py (deflated 76%)
adding: touchview/__init__.py (deflated 51%)
```
@@ -183,346 +183,361 @@ Select it and click `Install Add-on`.
# Changelog
-v4.0.5
+v4.2.0
-- `ADDED` : switch 2D header toggle UI position
+- `ADDED`: Support for Blender v4.2 (Extensions).
+- `FIXED`: Gizmo size and overlapping.
+- `FIXED`: Mouse position after moving the gizmo.
+- `FIXED`: Broken reference to full control mode in enabled check.
+- `CHANGED`: Class names, `register()`, and `unregister()` according to Blender conventions.
+- `CHANGED`: EnumProperty items according to Blender conventions.
+- `CHANGED`: Cursor type on hover over the gizmo.
+- `CHANGED`: Folder structure.
+- `IMPROVED`: Gizmo safe area.
+- `IMPROVED`: UI and tooltips.
-v4.0.4
+v4.0.5
-- `ADDED` : optional enable floating toggle for touch controls in mixed mode
-- `ADDED` : toggle touch controls button in node editor and image editor headers
+- `ADDED`: switch 2D header toggle UI position
-v4.0.3
+v4.0.4
-- `UPDATED` : fixed bug where hotkeys aren't assigned when opening Blender directly by file
+- `ADDED`: optional enable floating toggle for touch controls in mixed mode
+- `ADDED`: toggle touch controls button in node editor and image editor headers
-v4.0.2
+v4.0.3
-- `ADDED` : Nendo Tools Menu (limited options) for Image Editor and Node Editor
-- `REMOVED` : Right-Click Action for Image Editor and Node Editor
+- `UPDATED`: fixed bug where hotkeys aren't assigned when opening Blender directly by file
-v4.0.0
+v4.0.2
+
+- `ADDED`: Nendo Tools Menu (limited options) for Image Editor and Node Editor
+- `REMOVED`: Right-Click Action for Image Editor and Node Editor
+
+
+
+v4.0.0
Compatibility update for Blender 4.0
-- `ADDED` : support for Blender 4.0
-- `ADDED` : auto-save/load preferences
-- `UPDATED` : replace bgl module refs with gpu module implementation
-- `UPDATED` : Swap Control Regions fixed context override implementation
-- `UPDATED` : early exit when dragging gizmo near edge of viewport to prevent negative overflow
-- `REMOVED` : argument renaming to disregard unused args (currently breaking CI/CD)
+- `ADDED`: support for Blender 4.0
+- `ADDED`: auto-save/load preferences
+- `UPDATED`: replace bgl module refs with gpu module implementation
+- `UPDATED`: Swap Control Regions fixed context override implementation
+- `UPDATED`: early exit when dragging gizmo near edge of viewport to prevent negative overflow
+- `REMOVED`: argument renaming to disregard unused args (currently breaking CI/CD)
-v2.12.0
+v2.12.0
-- `UPDATED` : fixed bug with unindexed modes breaking gizmo menus
-- `UPDATED` : updated resize and change strength for 2D views
-- `UPDATED` : improved support for multi-mode devices
+- `UPDATED`: fixed bug with unindexed modes breaking gizmo menus
+- `UPDATED`: updated resize and change strength for 2D views
+- `UPDATED`: improved support for multi-mode devices
-v2.11.0
+v2.11.0
-- `UPDATED` : added various GPENCIL modes to edit mode list
-- `UPDATED` : updated viewport gizmo panel to support v3.6 changes
+- `UPDATED`: added various GPENCIL modes to edit mode list
+- `UPDATED`: updated viewport gizmo panel to support v3.6 changes
-v2.10.0
+v2.10.0
-- `ADDED` : lazy camera control toggle in sculpt mode
-- `UPDATED` : add support for Weylus (\*nix) sending 0.0 for pressure on touch events
-- `UPDATED` : changed all new operator namespaces to `nendo` for easier identification
-- `ADDED` : control mode icon when using signle-input mode
-- `UPDATED` : control mode toggle and floating action button now use same sizing as gizmos
-- `ADDED` : additional fine-tuning controls for gizmo spacing
+- `ADDED`: lazy camera control toggle in sculpt mode
+- `UPDATED`: add support for Weylus (\*nix) sending 0.0 for pressure on touch events
+- `UPDATED`: changed all new operator namespaces to `nendo` for easier identification
+- `ADDED`: control mode icon when using signle-input mode
+- `UPDATED`: control mode toggle and floating action button now use same sizing as gizmos
+- `ADDED`: additional fine-tuning controls for gizmo spacing
-v2.9.0
+v2.9.0
-- `UPDATED` : additional changes to gizmo spacing
-- `UPDATED` : fixed bug preventing custom actions being assigned for radial menu
+- `UPDATED`: additional changes to gizmo spacing
+- `UPDATED`: fixed bug preventing custom actions being assigned for radial menu
-v2.8.0
+v2.8.0
-- `UPDATED` : fixed issues with menu bar spacing
-- `REMOVED` : floating menu bar
+- `UPDATED`: fixed issues with menu bar spacing
+- `REMOVED`: floating menu bar
-v2.7.1
+v2.7.1
-- `UPDATED` : replaced region_full_area with window_fullscreen
+- `UPDATED`: replaced region_full_area with window_fullscreen
-v2.7.0
+v2.7.0
-- `ADDED` : relative remesh
-- `UPDATED` : fixed error when disabling add-on
+- `ADDED`: relative remesh
+- `UPDATED`: fixed error when disabling add-on
-v2.6.0
+v2.6.0
-- `UPDATED` : code spec now based on flake8
-- `UPDATED` : added alternative action for TransferMode when used in OBJECT mode
-- `UPDATED` : fixed desktop scaling issue with radial gizmo menu
-- `UPDATED` : fixed toggle touch gizmo and RC/DC action
-- `UPDATED` : fixed error message when rotation locked and pan/rotate swapped
+- `UPDATED`: code spec now based on flake8
+- `UPDATED`: added alternative action for TransferMode when used in OBJECT mode
+- `UPDATED`: fixed desktop scaling issue with radial gizmo menu
+- `UPDATED`: fixed toggle touch gizmo and RC/DC action
+- `UPDATED`: fixed error message when rotation locked and pan/rotate swapped
v2.5.0
-- `ADDED` : Gizmo size control
-- `UPDATED` : moved operators into folder
+- `ADDED`: Gizmo size control
+- `UPDATED`: moved operators into folder
v2.4.0
-- `UPDATED` : preferences access simplified with utility function
-- `ADDED` : single-input mode now activates large floating toggle button
+- `UPDATED`: preferences access simplified with utility function
+- `ADDED`: single-input mode now activates large floating toggle button
v2.3.0
-- `ADDED` : Input Mode selection (for devices with only touch or pen support)
+- `ADDED`: Input Mode selection (for devices with only touch or pen support)
v2.2.0
-- `ADDED` : Toggle control gizmo (translate, rotate, scale, none)
-- `UPDATED` : Added Brush dynamics (from sculpt mode) to paint modes
+- `ADDED`: Toggle control gizmo (translate, rotate, scale, none)
+- `UPDATED`: Added Brush dynamics (from sculpt mode) to paint modes
- NOTE: some paint/sculpt modes when in 2D/Draw canvas mode aren't yet hooked up to brush dynamics
v2.1.0
-- `ADDED` : Right Click Actions
-- `UPDATED` : Preferences and N-Panel restructure
+- `ADDED`: Right Click Actions
+- `UPDATED`: Preferences and N-Panel restructure
v2.0.0
-- `UPDATED` : Gizmos-related code simplified and reorganized for easier management
-- `ADDED` : floating gizmo bar and floating gizmo radial menu modes
-- `ADDED` : customizable gizmo menu spacing
-- `UPDATED` : viewport safe area calculation
-- `UPDATED` : floating action menu to use same move/access functionality as floating radial menu
-- `ADDED` : 8th custom action for floating action menu
+- `UPDATED`: Gizmos-related code simplified and reorganized for easier management
+- `ADDED`: floating gizmo bar and floating gizmo radial menu modes
+- `ADDED`: customizable gizmo menu spacing
+- `UPDATED`: viewport safe area calculation
+- `UPDATED`: floating action menu to use same move/access functionality as floating radial menu
+- `ADDED`: 8th custom action for floating action menu
v1.2.4
-- `ADDED` : Toggle Double-tap action on/off
+- `ADDED`: Toggle Double-tap action on/off
v1.2.3
-- `ADDED` : Sculpt Brush Dynamics
-- `UPDATED` : Viewport rotation in sculpt mode automatically sets pivot to mesh under touch point
+- `ADDED`: Sculpt Brush Dynamics
+- `UPDATED`: Viewport rotation in sculpt mode automatically sets pivot to mesh under touch point
v1.2.2
-- `UPDATED` : Gizmo panel layout split
+- `UPDATED`: Gizmo panel layout split
v1.2.1
-- `REMOVED` : Middle Mouse keybind
-- `REMOVED` : viewport rotation lock when using the Grease Pencil
+- `REMOVED`: Middle Mouse keybind
+- `REMOVED`: viewport rotation lock when using the Grease Pencil
v1.2.0
- `BREAKING`: This version requires previous version to be disabled before install
-- `UPDATED` : Improved Pen detection and simplified key configs
-- `ADDED` : Support for various 2D and 2D-like views (Image Editor, UV Editor, 2D Animation, Compositing, etc)
+- `UPDATED`: Improved Pen detection and simplified key configs
+- `ADDED`: Support for various 2D and 2D-like views (Image Editor, UV Editor, 2D Animation, Compositing, etc)
v1.1.2
-- `ADDED` : Support for Node Editor
+- `ADDED`: Support for Node Editor
v1.1.1
-- `ADDED` : minor fix to pen detection
+- `ADDED`: minor fix to pen detection
v1.1.0
-- `ADDED` : Independent toggle for entire gizmo bar
-- `ADDED` : Customizable double-tap actions
-- `ADDED` : Multi-resolution level limiter and gizmo status color
+- `ADDED`: Independent toggle for entire gizmo bar
+- `ADDED`: Customizable double-tap actions
+- `ADDED`: Multi-resolution level limiter and gizmo status color
v1.0.1
-- `ADDED` : Optional include for MIDDLEMOUSE when disabling/enabling touch controls
-- `FIXED` : Preferences bug preventing toggle of floating Gizmo
+- `ADDED`: Optional include for MIDDLEMOUSE when disabling/enabling touch controls
+- `FIXED`: Preferences bug preventing toggle of floating Gizmo
v1.0.0
-- `ADDED` : Toggle swap pan/rotate regions
-- `ADDED` : Toggle floating menu button to N Panel
-- `UPDATED` : Disabling touch controls no longer removes overlay (hot regions still work with custom keybinds and MIDDLEMOUSE)
-- `UPDATED` : Disabling touch controls restores default LEFTMOUSE functionality
+- `ADDED`: Toggle swap pan/rotate regions
+- `ADDED`: Toggle floating menu button to N Panel
+- `UPDATED`: Disabling touch controls no longer removes overlay (hot regions still work with custom keybinds and MIDDLEMOUSE)
+- `UPDATED`: Disabling touch controls restores default LEFTMOUSE functionality
v0.9.6
-- `ADDED` : undo/redo gizmo
-- `ADDED` : overlay color selection
-- `ADDED` : touch control toggle in settings
-- `ADDED` : Alt+T to toggle touch controls
-- `UPDATED` : N Panel now includes extra settings from addon menu
-- `UPDATED` : Lock Rotation now addresses quadview data replication bug
-- `UPDATED` : Limited floating gizmo to viewport area
-- `UPDATED` : code cleanup and additional structure tweaks
-- `REMOVED` : Gizmo Tooltips
+- `ADDED`: undo/redo gizmo
+- `ADDED`: overlay color selection
+- `ADDED`: touch control toggle in prefs
+- `ADDED`: Alt+T to toggle touch controls
+- `UPDATED`: N Panel now includes extra prefs from addon menu
+- `UPDATED`: Lock Rotation now addresses quadview data replication bug
+- `UPDATED`: Limited floating gizmo to viewport area
+- `UPDATED`: code cleanup and additional structure tweaks
+- `REMOVED`: Gizmo Tooltips
v0.9.5
-- `ADDED` : multires modifier support to gizmo bar (shows retopology tools when no modifier is present)
-- `FIXED` : Gizmos now properly follow mode visibility rules
-- `FIXED` : Double-tap selection now only runs in appropriate viewport modes
+- `ADDED`: multires modifier support to gizmo bar (shows retopology tools when no modifier is present)
+- `FIXED`: Gizmos now properly follow mode visibility rules
+- `FIXED`: Double-tap selection now only runs in appropriate viewport modes
v0.9.4
-- `ADDED` : Support for menus in floating gizmo
-- `ADDED` : Mode-specific options for floating gizmo
-- `UPDATED` : Dependence on active_object for mode detection
-- `UPDATED` : Classes to follow Blender naming conventions
-- `UPDATED` : Keymaps for touchview in all context
-- `UPDATED` : Keymaps for context action assigned to pen
+- `ADDED`: Support for menus in floating gizmo
+- `ADDED`: Mode-specific options for floating gizmo
+- `UPDATED`: Dependence on active_object for mode detection
+- `UPDATED`: Classes to follow Blender naming conventions
+- `UPDATED`: Keymaps for touchview in all context
+- `UPDATED`: Keymaps for context action assigned to pen
v0.9.3
-- `ADDED` : Sculpt pivot mode gizmo
-- `ADDED` : Customizable floating menu
+- `ADDED`: Sculpt pivot mode gizmo
+- `ADDED`: Customizable floating menu
v0.9.2
-- `FIXED` : Issue delaying overlay viewport binding
-- `FIXED` : Gizmo tools/panel overlap issue when "Region Overlap" enabled
-- `REMOVED` : Viewport manager class
-- `REMOVED` : Default keymap causing Move Operator to trigger when dragging over non-modal gizmos
+- `FIXED`: Issue delaying overlay viewport binding
+- `FIXED`: Gizmo tools/panel overlap issue when "Region Overlap" enabled
+- `REMOVED`: Viewport manager class
+- `REMOVED`: Default keymap causing Move Operator to trigger when dragging over non-modal gizmos
v0.9.1
-- `ADDED` : Tap for menu scroll
+- `ADDED`: Tap for menu scroll
v0.9
-- `ADDED` : N-Panel gizmo
-- `UPDATED` : Code restructure
-- `FIXED` : Dragging over gizmo moves selected object
+- `ADDED`: N-Panel gizmo
+- `UPDATED`: Code restructure
+- `FIXED`: Dragging over gizmo moves selected object
v0.8
-- `ADDED` : Gizmo to toggle fullscreen mode
-- `UPDATED` : Settings to addon preferences to save across projects and scenes
-- `FIXED` : Bugs impacting user experience
-- `FIXED` : Doubletap now selects/activates tapped object instead of triggering fullscreen
+- `ADDED`: Gizmo to toggle fullscreen mode
+- `UPDATED`: Settings to addon preferences to save across projects and scenes
+- `FIXED`: Bugs impacting user experience
+- `FIXED`: Doubletap now selects/activates tapped object instead of triggering fullscreen
v0.7
-- `ADDED` : Gizmos for key features
-- `ADDED` : Hide/show Gizmo and layout options
-- `ADDED` : Locked viewport rotation for isometric viewports in quadview to address lock/unlock inconsistencies
-- `FIXED` : Fullscreen Toggle no longer maximizes the window, only expands the View3D region
+- `ADDED`: Gizmos for key features
+- `ADDED`: Hide/show Gizmo and layout options
+- `ADDED`: Locked viewport rotation for isometric viewports in quadview to address lock/unlock inconsistencies
+- `FIXED`: Fullscreen Toggle no longer maximizes the window, only expands the View3D region
v0.6
-- `UPDATED` : Scale of viewport overlay settings for more precision
-- `FIXED` : Issues with determining locked state with quadviews
+- `UPDATED`: Scale of viewport overlay prefs for more precision
+- `FIXED`: Issues with determining locked state with quadviews
v0.5
-- `ADDED` : Camera rotation lock in N-panel
-- `FIXED` : Quad-view overlay compatibility
-- `FIXED` : Rotation with panning when rotation is locked
-- `FIXED` : Issue when locking view to Object or 3D Cursor
+- `ADDED`: Camera rotation lock in N-panel
+- `FIXED`: Quad-view overlay compatibility
+- `FIXED`: Rotation with panning when rotation is locked
+- `FIXED`: Issue when locking view to Object or 3D Cursor
v0.4
-- `ADDED` : Double-tap to toggle "focus" mode
-- `ADDED` : Toggle Tools LEFT/RIGHT in UI
+- `ADDED`: Double-tap to toggle "focus" mode
+- `ADDED`: Toggle Tools LEFT/RIGHT in UI
v0.3
-- `FIXED` : Incorrect viewport calculation when N-panel is open
-- `FIXED` : Refactored screen/area management code (additional major refactor needed)
+- `FIXED`: Incorrect viewport calculation when N-panel is open
+- `FIXED`: Refactored screen/area management code (additional major refactor needed)
v0.2
-- `FIXED` : Minor bug fixes and code cleanup
+- `FIXED`: Minor bug fixes and code cleanup
v0.1
-- `ADDED` : Camera dolly on left and right of viewport
-- `ADDED` : Camera pan from center of viewport
-- `ADDED` : Camera rotate in any other area of viewport
-- `ADDED` : Toggleable overlay to simplify resizing controls
+- `ADDED`: Camera dolly on left and right of viewport
+- `ADDED`: Camera pan from center of viewport
+- `ADDED`: Camera rotate in any other area of viewport
+- `ADDED`: Toggleable overlay to simplify resizing controls
diff --git a/__init__.py b/__init__.py
index 5e72f57..9983dd0 100644
--- a/__init__.py
+++ b/__init__.py
@@ -15,35 +15,34 @@
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# ##### END GPL LICENSE BLOCK #####
-import bpy
-from . import lib
-from .Settings import MenuModeGroup, OverlaySettings
bl_info = {
"name": "Touch Viewport",
- "description": "Creates active touch zones over View 2D and 3D areas for"
- "easier viewport navigation with touch screens and pen tablets.",
- "author": "NENDO",
- "version": (4, 0, 5),
+ "description": "Creates active touch zones over View 2D and 3D areas for easier viewport navigation with touch screens and pen tablets.",
+ "author": "NENDO, Karan(b3dhub)",
"blender": (2, 93, 0),
+ "version": (4, 2, 0),
+ "category": "3D View",
"location": "View3D > Tools > NENDO",
"warning": "",
- "doc_url": "",
+ "doc_url": "https://github.com/nendotools/touchview",
"tracker_url": "https://github.com/nendotools/touchview/issues",
- "category": "3D View",
}
+import bpy
+
+from . import preferences, source
+
+
def register():
- bpy.utils.register_class(MenuModeGroup)
- bpy.utils.register_class(OverlaySettings)
- bpy.context.preferences.addons[__package__.split(".")[0]].preferences.load() # type: ignore
- lib.register()
+ source.register()
+ preferences.register()
+ bpy.context.preferences.addons[__package__].preferences.load() # type: ignore
def unregister():
- lib.unregister()
- bpy.context.preferences.addons[__package__.split(".")[0]].preferences.save() # type: ignore
- bpy.utils.unregister_class(OverlaySettings)
- bpy.utils.unregister_class(MenuModeGroup)
+ bpy.context.preferences.addons[__package__].preferences.save() # type: ignore
+ source.unregister()
+ preferences.unregister()
diff --git a/blender_manifest.toml b/blender_manifest.toml
new file mode 100644
index 0000000..c004c3a
--- /dev/null
+++ b/blender_manifest.toml
@@ -0,0 +1,36 @@
+schema_version = "1.0.0"
+
+id = "touchview"
+version = "4.2.0"
+name = "Touch Viewport"
+tagline = "Creates active touch zones over View 2D and 3D areas for easier viewport navigation with touch screens and pen tablets"
+maintainer = "NENDO, Karan(b3dhub)"
+type = "add-on"
+
+permissions = ["files"]
+
+website = "https://github.com/nendotools/touchview"
+
+# Optional list defined by Blender and server, see:
+# https://docs.blender.org/manual/en/dev/extensions/tags.html
+tags = ["3D View", "User Interface"]
+
+blender_version_min = "4.2.0"
+
+# License conforming to https://spdx.org/licenses/ (use "SPDX: prefix)
+license = ["SPDX:GPL-2.0-or-later"]
+
+[build]
+paths_exclude_pattern = [
+ "__pycache__/",
+ "/.git/",
+ "docs/",
+ ".gitignore",
+ "/*.zip",
+ "/bin",
+ "settings.json",
+ "bundle.sh",
+ "mypy.ini",
+ "requirements.txt",
+ "README.md"
+]
diff --git a/bundle.sh b/bundle.sh
index 180f400..b0afc06 100755
--- a/bundle.sh
+++ b/bundle.sh
@@ -5,8 +5,8 @@ bundle ()
dir="bin/touchview"
mkdir -p "$dir"
cp "__init__.py" "$dir"
- cp "Settings.py" "$dir"
- cp -r "lib" "$dir"
+ cp "preferences.py" "$dir"
+ cp -r "source" "$dir"
cd "$dest"
zip -r "touchview.zip" "touchview"
cd ".."
diff --git a/lib/Panel.py b/lib/Panel.py
deleted file mode 100644
index 413e539..0000000
--- a/lib/Panel.py
+++ /dev/null
@@ -1,282 +0,0 @@
-# type: ignore
-import bpy
-from bpy.types import Context, Menu, Panel
-
-from .utils import get_settings
-
-
-class IMAGE_PT_NendoPanel:
- bl_space_type = "IMAGE_EDITOR"
- bl_region_type = "UI"
- bl_category = "NENDO"
-
-
-class IMAGE_PT_NendoViewport(IMAGE_PT_NendoPanel, Panel):
- bl_idname = "IMAGE_PT_NendoViewport"
- bl_label = "Touchview Settings"
-
- def draw(self, _: Context):
- settings = get_settings()
- col = self.layout.column()
- col.label(text="Input Mode")
- box = col.box()
- if settings.input_mode == "full":
- box.label(text="pen, mouse, and touch input", icon="CON_CAMERASOLVER")
- if settings.input_mode == "pen":
- box.label(text="pen-only input", icon="STYLUS_PRESSURE")
- if settings.input_mode == "touch":
- box.label(text="mouse/touch only input", icon="VIEW_PAN")
- r = box.row()
- r.prop(settings, "input_mode", expand=True)
- box.prop(settings, "is_enabled", toggle=1)
- box.label(text="2D Header Toggle Position")
- box.row().prop(settings, "header_toggle_position", expand=True)
-
-
-class NODE_PT_NendoPanel:
- bl_space_type = "NODE_EDITOR"
- bl_region_type = "UI"
- bl_category = "NENDO"
-
-
-class NODE_PT_NendoViewport(NODE_PT_NendoPanel, Panel):
- bl_idname = "NODE_PT_NendoViewport"
- bl_label = "Touchview Settings"
-
- def draw(self, _: Context):
- settings = get_settings()
- col = self.layout.column()
- col.label(text="Input Mode")
- box = col.box()
- if settings.input_mode == "full":
- box.label(text="pen, mouse, and touch input", icon="CON_CAMERASOLVER")
- if settings.input_mode == "pen":
- box.label(text="pen-only input", icon="STYLUS_PRESSURE")
- if settings.input_mode == "touch":
- box.label(text="mouse/touch only input", icon="VIEW_PAN")
- r = box.row()
- r.prop(settings, "input_mode", expand=True)
- box.prop(settings, "is_enabled", toggle=1)
- box.label(text="2D Header Toggle Position")
- box.row().prop(settings, "header_toggle_position", expand=True)
-
-
-class VIEW3D_PT_NendoPanel:
- bl_space_type = "VIEW_3D"
- bl_region_type = "UI"
- bl_category = "NENDO"
-
-
-class VIEW3D_PT_NendoViewport(VIEW3D_PT_NendoPanel, Panel):
- bl_idname = "VIEW3D_PT_NendoViewport"
- bl_label = "Touchview Settings"
-
- def draw(self, _: Context):
- pass
-
-
-class VIEW3D_PT_ControlZones(VIEW3D_PT_NendoPanel, Panel):
- bl_label = "Control Zones"
- bl_parent_id = "VIEW3D_PT_NendoViewport"
-
- def draw(self, _: Context):
- settings = get_settings()
-
- col = self.layout.column()
- col.label(text="Input Mode")
- box = col.box()
- if settings.input_mode == "full":
- box.label(text="pen, mouse, and touch input", icon="CON_CAMERASOLVER")
- if settings.input_mode == "pen":
- box.label(text="pen-only input", icon="STYLUS_PRESSURE")
- if settings.input_mode == "touch":
- box.label(text="mouse/touch only input", icon="VIEW_PAN")
- r = box.row()
- r.prop(settings, "input_mode", expand=True)
- box.prop(settings, "lazy_mode", toggle=1)
- box.prop(settings, "is_enabled", toggle=1)
- box.label(text="2D Header Toggle Position")
- box.row().prop(settings, "header_toggle_position", expand=True)
-
- col.prop(settings, "swap_panrotate")
- col.prop(settings, "isVisible", text="Show Overlay")
- col.prop(settings, "use_multiple_colors")
- col.prop(settings, "overlay_main_color", text="Main Color")
- if settings.use_multiple_colors:
- col.prop(settings, "overlay_secondary_color", text="Secondary Color")
- col.prop(settings, "width")
- col.prop(settings, "radius")
- col.separator()
-
-
-class VIEW3D_PT_RightClick_Menu(VIEW3D_PT_NendoPanel, Panel):
- bl_label = "Right Click Actions"
- bl_parent_id = "VIEW3D_PT_NendoViewport"
-
- def draw(self, _: Context):
- settings = get_settings()
- group = self.layout.column()
- r = group.split(factor=0.3, align=True)
- r.label(text="Input Source")
- r = r.row()
- r.prop(settings, "right_click_source", expand=True)
-
- r = group.split(factor=0.3, align=True)
- r.label(text="Click Action")
- c = r.column()
- c.prop(settings, "right_click_mode", expand=True)
-
-
-class VIEW3D_PT_DoubleClick_Menu(VIEW3D_PT_NendoPanel, Panel):
- bl_label = "Double Click Actions"
- bl_parent_id = "VIEW3D_PT_NendoViewport"
-
- def draw(self, _: Context):
- settings = get_settings()
- group = self.layout.column()
- r = group.split(factor=0.3, align=True)
- group.separator()
- group.prop(settings, "enable_double_click", toggle=1)
- r = group.split(factor=0.3, align=True)
- r.label(text="Click Action")
- c = r.column()
- c.prop(settings, "double_click_mode", expand=True)
-
-
-class VIEW3D_PT_GizmoBar(VIEW3D_PT_NendoPanel, Panel):
- bl_label = "Gizmo Bar"
- bl_parent_id = "VIEW3D_PT_NendoViewport"
-
- def draw(self, _: Context):
- settings = get_settings()
- group = self.layout.column()
- group.label(text="Menu Style")
- r = group.row()
- r.prop(settings, "menu_style", expand=True)
- if settings.menu_style == "fixed.bar":
- group.prop_menu_enum(settings, "gizmo_position")
- group.prop(settings, "menu_spacing", slider=True)
- if settings.menu_style == "float.radial":
- group.prop(settings, "gizmo_padding", slider=True)
- group.prop(settings, "gizmo_scale", slider=True)
-
-
-class VIEW3D_PT_ToolSettings(VIEW3D_PT_NendoPanel, Panel):
- bl_label = "Tool Options"
- bl_parent_id = "VIEW3D_PT_NendoViewport"
-
- def draw(self, _: Context):
- settings = get_settings()
- group = self.layout.column()
- group.prop(settings, "subdivision_limit", slider=True)
-
-
-class VIEW3D_PT_ViewportOptions(VIEW3D_PT_NendoPanel, Panel):
- bl_label = "Viewport Options"
- bl_parent_id = "VIEW3D_PT_NendoViewport"
-
- def draw(self, context: Context):
- settings = get_settings()
- view = context.space_data
- space = context.area.spaces.active
- group = self.layout.column()
- group.prop(settings, "show_float_menu", toggle=1)
- group.operator("view3d.tools_region_flip", text="Flip Tools")
- if len(space.region_quadviews) > 0:
- group.operator("screen.region_quadview", text="Disable Quadview")
- else:
- group.operator("screen.region_quadview", text="Enable Quadview")
- group.prop(space, "lock_cursor", text="Lock to Cursor")
- group.prop(view.region_3d, "lock_rotation", text="Lock Rotation")
- context.area.tag_redraw()
-
-
-class PIE_MT_Floating_Menu(Menu):
- """Open a custom menu"""
-
- bl_idname = "PIE_MT_Floating_Menu"
- bl_label = "Floating Menu"
- bl_description = "Customized Floating Menu"
-
- def draw(self, context: Context):
- settings = get_settings()
- menu = settings.getMenuSettings(context.mode)
-
- layout = self.layout
- pie = layout.menu_pie()
- for i in range(8):
- op = getattr(menu, "menu_slot_" + str(i + 1))
- if op == "":
- continue
- elif "_MT_" in op:
- pie.menu(op)
- continue
- elif self.__operator_exists(op):
- pie.operator(op)
-
- def __operator_exists(self, idname):
- try:
- names = idname.split(".")
- a = bpy.ops
- for prop in names:
- a = getattr(a, prop)
- a.__repr__()
- except Exception as _:
- return False
- return True
-
-
-# UI panel to append Gizmo menu
-class VIEW3D_PT_Gizmo_Panel(bpy.types.Panel):
- bl_label = "Gizmo display control"
- bl_idname = "VIEW3D_PT_Gizmo_Panel"
- bl_parent_id = "VIEW3D_PT_gizmo_display"
- bl_space_type = "VIEW_3D"
- bl_region_type = "HEADER"
- bl_label = "Gizmos"
- bl_ui_units_x = 16
-
- def draw(self, context: Context):
- layout = self.layout
-
- col = layout.column()
- col.label(text="Touch Gizmos")
- settings = get_settings()
- available_gizmos = settings.getGizmoSet(context.object.mode)
-
- col = col.column(align=True)
- col.active = context.space_data.show_gizmo
- col.prop(settings, "show_menu")
- col = col.column()
- col.active = settings.show_menu
- for toggle in available_gizmos:
- col.prop(settings, "show_" + toggle)
-
-
-__classes__ = (
- PIE_MT_Floating_Menu,
- VIEW3D_PT_NendoViewport,
- VIEW3D_PT_ControlZones,
- VIEW3D_PT_ViewportOptions,
- VIEW3D_PT_RightClick_Menu,
- VIEW3D_PT_DoubleClick_Menu,
- VIEW3D_PT_GizmoBar,
- VIEW3D_PT_ToolSettings,
- VIEW3D_PT_Gizmo_Panel,
- IMAGE_PT_NendoViewport,
- NODE_PT_NendoViewport,
-)
-
-
-def register():
- from bpy.utils import register_class
-
- for cls in __classes__:
- register_class(cls)
-
-
-def unregister():
- from bpy.utils import unregister_class
-
- for cls in reversed(__classes__):
- unregister_class(cls)
diff --git a/lib/__init__.py b/lib/__init__.py
deleted file mode 100644
index 60f98e0..0000000
--- a/lib/__init__.py
+++ /dev/null
@@ -1,26 +0,0 @@
-from . import Panel, operators, ui_gizmo
-from .Overlay import Overlay
-
-ov = Overlay()
-
-
-def register():
- from .touch_input import register_keymaps
-
- Panel.register()
-
- operators.register()
- ui_gizmo.register()
- ov.drawUI()
- register_keymaps()
-
-
-def unregister():
- from .touch_input import unregister_keymaps
-
- unregister_keymaps()
-
- ov.clear_overlays()
- ui_gizmo.unregister()
- Panel.unregister()
- operators.unregister()
diff --git a/lib/operators/__init__.py b/lib/operators/__init__.py
deleted file mode 100644
index 2a8f246..0000000
--- a/lib/operators/__init__.py
+++ /dev/null
@@ -1,40 +0,0 @@
-# flake8: noqa
-from .actions import *
-from .touch import *
-from .ui import *
-
-__classes__ = (
- VIEW3D_OT_TouchInput,
- VIEW2D_OT_TouchInput,
- VIEW3D_OT_Doubletap_Action,
- VIEW3D_OT_RightClick_Action,
- VIEW3D_OT_CycleControlGizmo,
- VIEW3D_OT_FloatController,
- VIEW3D_OT_MoveFloatMenu,
- VIEW3D_OT_MenuController,
- VIEW3D_OT_FlipTools,
- VIEW3D_OT_NextPivotMode,
- VIEW3D_OT_BrushResize,
- VIEW3D_OT_BrushStrength,
- VIEW3D_OT_ToggleNPanel,
- VIEW3D_OT_ToggleFloatingMenu,
- VIEW3D_OT_ToggleTouchControls,
- VIEW3D_OT_ViewportLock,
- VIEW3D_OT_ViewportRecenter,
- VIEW3D_OT_IncreaseMultires,
- VIEW3D_OT_DecreaseMultires,
- VIEW3D_OT_DensityUp,
- VIEW3D_OT_DensityDown,
-)
-
-
-def register():
- from bpy.utils import register_class
- for cls in __classes__:
- register_class(cls)
-
-
-def unregister():
- from bpy.utils import unregister_class
- for cls in reversed(__classes__):
- unregister_class(cls)
diff --git a/lib/utils.py b/lib/utils.py
deleted file mode 100644
index 0ff5e1a..0000000
--- a/lib/utils.py
+++ /dev/null
@@ -1,70 +0,0 @@
-import bpy
-from mathutils import Vector
-
-from ..Settings import OverlaySettings
-
-
-def get_settings() -> OverlaySettings:
- prefs = (
- bpy.context.preferences.addons[__package__.split(".")[0]].preferences # type: ignore
- )
- if isinstance(prefs, OverlaySettings):
- return prefs
- raise RuntimeWarning("Invalid Preferences")
-
-
-def panel(type) -> tuple:
- """Panel in the region.
-
- type (enum in ['WINDOW', 'HEADER', 'CHANNELS', 'TEMPORARY', 'UI', 'TOOLS',
- 'TOOL_PROPS', 'PREVIEW', 'HUD', 'NAVIGATION_BAR', 'EXECUTE',
- 'FOOTER', 'TOOL_HEADER', 'XR']) - Type of the region.
- return (tuple) - Dimension of the region.
- """
- width = 0
- height = 0
- alignment = "NONE"
- for region in bpy.context.area.regions:
- if region.type == type:
- width = region.width
- height = region.height
- alignment = region.alignment
- return (width, height, alignment)
-
-
-# returns dpi scale factor for UI
-def dpi_factor() -> float:
- retinaFactor = getattr(bpy.context.preferences.system, "pixel_size", 1)
- return int(bpy.context.preferences.system.dpi * retinaFactor) / 72.0
-
-
-# returns a tuple (bottom-left, top-right)
-# safe area in viewport for UI elements
-def buildSafeArea() -> tuple[Vector, Vector]:
- buffer = 30 * dpi_factor()
- min = Vector((buffer, buffer))
- max = Vector((
- bpy.context.region.width - buffer,
- bpy.context.region.height - buffer,
- ))
-
- if panel("TOOLS")[2] == "LEFT":
- min.x += 22.0 * dpi_factor() + panel("TOOLS")[0]
- if panel("TOOLS")[2] == "RIGHT":
- max.x -= 22.0 * dpi_factor() + panel("TOOLS")[0]
-
- if panel("UI")[2] == "LEFT":
- min.x += 22.0 * dpi_factor() + panel("UI")[0]
- if panel("UI")[2] == "RIGHT":
- max.x -= 22.0 * dpi_factor() + panel("UI")[0]
-
- if panel("HEADER")[2] == "BOTTOM":
- min.y = panel("HEADER")[1]
- if panel("HEADER")[2] == "TOP":
- max.y -= panel("HEADER")[1]
-
- if panel("TOOL_HEADER")[2] == "BOTTOM":
- min.y = panel("TOOL_HEADER")[1]
- if panel("TOOL_HEADER")[2] == "TOP":
- max.y -= panel("TOOL_HEADER")[1]
- return (min, max)
diff --git a/Settings.py b/preferences.py
similarity index 56%
rename from Settings.py
rename to preferences.py
index 79eef8e..eeb21e6 100644
--- a/Settings.py
+++ b/preferences.py
@@ -2,40 +2,39 @@
import json
from os import path
-from bpy.props import (BoolProperty, CollectionProperty, EnumProperty,
- FloatProperty, FloatVectorProperty, IntProperty,
- StringProperty)
-from bpy.types import (AddonPreferences, Context, IMAGE_HT_header,
- NODE_HT_header, PropertyGroup)
+import bpy
+from bpy.props import *
+from bpy.types import AddonPreferences, PropertyGroup, UILayout
-from .lib.constants import (double_click_items, edit_modes, gizmo_sets,
- menu_defaults, menu_orientation_items,
- menu_style_items, pivot_items, position_items)
+from .source.utils.constants import (double_click_items, edit_modes,
+ gizmo_sets, menu_defaults,
+ menu_orientation_items, menu_style_items,
+ pivot_items, position_items)
def NODE_HT_nendo_header(s, c):
- settings = c.preferences.addons[__package__.split(".")[0]].preferences
+ prefs = c.preferences.addons[__package__].preferences
layout = s.layout
layout.separator()
- layout.prop(settings, "is_enabled", toggle=1)
+ layout.prop(prefs, "is_enabled", toggle=True)
def update_header_toggle_position(c):
- settings = c.preferences.addons[__package__.split(".")[0]].preferences
- NODE_HT_header.remove(NODE_HT_nendo_header)
- IMAGE_HT_header.remove(NODE_HT_nendo_header)
- if settings.header_toggle_position == "LEFT":
- NODE_HT_header.prepend(NODE_HT_nendo_header)
- IMAGE_HT_header.prepend(NODE_HT_nendo_header)
+ prefs = c.preferences.addons[__package__].preferences
+ bpy.types.NODE_HT_header.remove(NODE_HT_nendo_header)
+ bpy.types.IMAGE_HT_header.remove(NODE_HT_nendo_header)
+ if prefs.header_toggle_position == "LEFT":
+ bpy.types.NODE_HT_header.prepend(NODE_HT_nendo_header)
+ bpy.types.IMAGE_HT_header.prepend(NODE_HT_nendo_header)
else:
- NODE_HT_header.append(NODE_HT_nendo_header)
- IMAGE_HT_header.append(NODE_HT_nendo_header)
+ bpy.types.NODE_HT_header.append(NODE_HT_nendo_header)
+ bpy.types.IMAGE_HT_header.append(NODE_HT_nendo_header)
##
# Action Menu Settings
##
-class MenuModeGroup(PropertyGroup):
+class TOUCHVIEW_PG_MenuModeGroup(PropertyGroup):
mode: StringProperty(name="mode", default="OBJECT")
menu_slot_1: StringProperty(name="Menu Item", default="")
menu_slot_2: StringProperty(name="Menu Item", default="")
@@ -71,13 +70,18 @@ def from_dict(self, data: dict):
self.menu_slot_8 = data.get("menu_slot_8", "")
-class OverlaySettings(AddonPreferences):
+class TOUCHVIEW_AP_OverlaySettings(AddonPreferences):
bl_idname = __package__
##
# Viewport Control Options
##
- is_enabled: BoolProperty(name="Enable Controls", default=True)
+
+ is_enabled: BoolProperty(
+ name="Enable Controls",
+ default=True,
+ )
+
header_toggle_position: EnumProperty(
items=[
("LEFT", "Left", "Toggle position on the left"),
@@ -93,9 +97,15 @@ class OverlaySettings(AddonPreferences):
default=False,
description="always control camera when not touching selected object",
)
+
toggle_position: FloatVectorProperty(
- name="Toggle Position", subtype="XYZ", default=(0.5, 0.5, 0.0)
+ name="Toggle Position",
+ soft_min=0,
+ soft_max=100,
+ size=2,
+ default=(0, 0),
)
+
toggle_color: FloatVectorProperty(
name="Toggle Button Color",
default=(0.1, 0.1, 0.2, 0.5),
@@ -105,52 +115,83 @@ class OverlaySettings(AddonPreferences):
size=4,
)
- isVisible: BoolProperty(name="Show Overlay", default=False)
+ isVisible: BoolProperty(
+ name="Show Overlay",
+ default=False,
+ )
input_mode: EnumProperty(
+ name="Input Mode",
items=[
- ("full", "full", "mouse/touch and pen input"),
- ("pen", "pen", "pen input only"),
- ("touch", "touch", "mouse/touch input only"),
+ ("FULL", "Full", "Mouse/Touch and Pen input", "CON_CAMERASOLVER", 0),
+ ("PEN", "Pen", "Pen input only", "STYLUS_PRESSURE", 1),
+ ("TOUCH", "Touch", "Mouse/Touch input only", "VIEW_PAN", 2),
],
- name="Input Mode",
- default="full",
+ default="FULL",
)
+
enable_floating_toggle: BoolProperty(
- name="Enable Floating Toggle",
+ name="Floating Toggle",
description="Allows using floating toggle on mixed input mode",
default=False,
)
- enable_double_click: BoolProperty(name="Enable Double Click", default=True)
+ enable_double_click: BoolProperty(
+ name="Double Click",
+ default=True,
+ )
+
double_click_mode: EnumProperty(
- items=double_click_items,
name="Double Click Mode",
+ items=double_click_items,
default="screen.screen_full_area",
)
- enable_right_click: BoolProperty(name="Enable Right Click", default=True)
+ enable_right_click: BoolProperty(
+ name="Enable Right Click",
+ default=True,
+ )
+
right_click_mode: EnumProperty(
- items=double_click_items,
name="Right Click Mode",
+ items=double_click_items,
default="wm.window_fullscreen_toggle",
)
+
right_click_source: EnumProperty(
+ name="Right Click Source",
items=[
- ("none", "none", "disabled"),
- ("mouse", "mouse", "mouse/touch right click"),
- ("pen", "pen", "pen right click"),
+ ("MOUSE", "Mouse", "Mouse/Touch right click"),
+ ("PEN", "Pen", "Pen right click"),
+ ("NONE", "None", "Disabled"),
],
- name="Right Click Source",
- default="mouse",
+ default="MOUSE",
)
- swap_panrotate: BoolProperty(name="Swap Pan/Rotate", default=False)
+ swap_panrotate: BoolProperty(
+ name="Swap Pan/Rotate",
+ default=False,
+ )
- width: FloatProperty(name="Width", default=40.0, min=10.0, max=100)
- radius: FloatProperty(name="Radius", default=35.0, min=10.0, max=100.0)
+ width: FloatProperty(
+ name="Width",
+ default=40.0,
+ min=10.0,
+ max=100,
+ )
+
+ radius: FloatProperty(
+ name="Radius",
+ default=35.0,
+ min=10.0,
+ max=100.0,
+ )
+
+ use_multiple_colors: BoolProperty(
+ name="Multicolor Overlay",
+ default=False,
+ )
- use_multiple_colors: BoolProperty(name="Multicolor Overlay", default=False)
overlay_main_color: FloatVectorProperty(
name="Overlay Main Color",
default=(1.0, 1.0, 1.0, 0.01),
@@ -159,6 +200,7 @@ class OverlaySettings(AddonPreferences):
max=1.0,
size=4,
)
+
overlay_secondary_color: FloatVectorProperty(
name="Overlay Secondary Color",
default=(1.0, 1.0, 1.0, 0.01),
@@ -171,56 +213,141 @@ class OverlaySettings(AddonPreferences):
##
# Gizmo Options
##
- show_menu: BoolProperty(name="Toggle Menu Display", default=True)
- show_gizmos: BoolProperty(name="Toggle Gizmos on Menu", default=True)
+
+ show_menu: BoolProperty(
+ name="Toggle Menu Display",
+ default=True,
+ )
+
+ show_gizmos: BoolProperty(
+ name="Toggle Gizmos on Menu",
+ default=True,
+ )
+
menu_style: EnumProperty(
- name="Menu Style", default="float.radial", items=menu_style_items
+ name="Menu Style",
+ items=menu_style_items,
+ default="float.radial",
+ )
+
+ gizmo_position: EnumProperty(
+ name="Gizmo Position",
+ items=position_items,
+ default="RIGHT",
)
+
menu_orientation: EnumProperty(
- name="Menu Orientation", default="HORIZONTAL", items=menu_orientation_items
+ name="Menu Orientation",
+ items=menu_orientation_items,
+ default="HORIZONTAL",
)
+
menu_spacing: FloatProperty(
- name="Menu Size", default=20.0, precision=2, step=1, min=0.0, max=200.0
- )
- gizmo_padding: FloatProperty(
- name="Gizmo Padding", default=10, precision=1, step=1, min=1, max=200
+ name="Menu Scale",
+ min=1,
+ max=2,
+ default=1,
)
+
gizmo_scale: FloatProperty(
- name="Gizmo Scale", default=4.0, precision=2, step=1, min=1, max=10.0
+ name="Gizmo Scale",
+ min=1,
+ max=2,
+ default=1,
)
+
+ gizmo_padding: FloatProperty(
+ name="Gizmo Padding",
+ subtype="PIXEL",
+ min=0,
+ soft_max=24,
+ default=4,
+ )
+
menu_position: FloatVectorProperty(
name="Menu Position",
- default=(95.00, 5.00),
- size=2,
- precision=2,
- step=1,
- soft_min=5,
+ soft_min=0,
soft_max=100,
+ size=2,
+ default=(100, 0),
)
- show_undoredo: BoolProperty(name="Undo/Redo", default=True)
- show_is_enabled: BoolProperty(name="Toggle Touch", default=True)
- show_control_gizmo: BoolProperty(name="Toggle Control Gizmo", default=True)
- show_show_fullscreen: BoolProperty(name="Fullscreen", default=True)
- show_region_quadviews: BoolProperty(name="Quadview", default=True)
- show_pivot_mode: BoolProperty(name="Pivot Mode", default=True)
- show_snap_view: BoolProperty(name="Snap View", default=True)
- show_n_panel: BoolProperty(name="N Panel", default=True)
- show_lock_rotation: BoolProperty(name="Rotation Lock", default=True)
- show_multires: BoolProperty(name="Multires", default=True)
- show_voxel_remesh: BoolProperty(name="Voxel Remesh", default=True)
- show_brush_dynamics: BoolProperty(name="Brush Dynamics", default=True)
- gizmo_position: EnumProperty(
- items=position_items, name="Gizmo Position", default="RIGHT"
+ show_undoredo: BoolProperty(
+ name="Undo/Redo",
+ default=True,
)
- subdivision_limit: IntProperty(name="Subdivision Limit", default=4, min=1, max=7)
+
+ show_is_enabled: BoolProperty(
+ name="Toggle Touch",
+ default=True,
+ )
+
+ show_control_gizmo: BoolProperty(
+ name="Toggle Control Gizmo",
+ default=True,
+ )
+
+ show_show_fullscreen: BoolProperty(
+ name="Fullscreen",
+ default=True,
+ )
+
+ show_region_quadviews: BoolProperty(
+ name="Quadview",
+ default=True,
+ )
+
+ show_pivot_mode: BoolProperty(
+ name="Pivot Mode",
+ default=True,
+ )
+
+ show_snap_view: BoolProperty(
+ name="Snap View",
+ default=True,
+ )
+
+ show_n_panel: BoolProperty(
+ name="N Panel",
+ default=True,
+ )
+
+ show_lock_rotation: BoolProperty(
+ name="Rotation Lock",
+ default=True,
+ )
+
+ show_multires: BoolProperty(
+ name="Multires",
+ default=True,
+ )
+
+ show_voxel_remesh: BoolProperty(
+ name="Voxel Remesh",
+ default=True,
+ )
+ show_brush_dynamics: BoolProperty(
+ name="Brush Dynamics",
+ default=True,
+ )
+
+ subdivision_limit: IntProperty(
+ name="Subdivision Limit",
+ default=4,
+ min=1,
+ max=7,
+ )
+
pivot_mode: EnumProperty(
- name="Sculpt Pivot Mode", items=pivot_items, default="SURFACE"
+ name="Sculpt Pivot Mode",
+ items=pivot_items,
+ default="SURFACE",
)
##
# Topology Control
##
+
topology_mode: EnumProperty(
name="Topology Mode",
items=[
@@ -238,32 +365,47 @@ class OverlaySettings(AddonPreferences):
##
# Action Menu Options
##
- show_float_menu: BoolProperty(name="Enable Floating Menu", default=False)
+
+ show_float_menu: BoolProperty(
+ name="Floating Menu",
+ default=False,
+ )
+
floating_position: FloatVectorProperty(
name="Floating Offset",
- default=(95.00, 5.00),
- size=2,
- precision=2,
- step=1,
- soft_min=5,
+ soft_min=0,
soft_max=100,
+ size=2,
+ default=(100, 0),
)
double_click_mode: EnumProperty(
- items=double_click_items,
name="Double Click Mode",
+ items=double_click_items,
default="wm.window_fullscreen_toggle",
)
- menu_sets: CollectionProperty(type=MenuModeGroup, options={"LIBRARY_EDITABLE"})
+
+ menu_sets: CollectionProperty(
+ type=TOUCHVIEW_PG_MenuModeGroup,
+ options={"LIBRARY_EDITABLE"},
+ )
##
# UI Panel Controls
##
- active_menu: EnumProperty(name="Mode Settings", items=edit_modes)
+
+ active_menu: EnumProperty(
+ name="Mode Settings",
+ items=edit_modes,
+ )
+
gizmo_tabs: EnumProperty(
name="Gizmo Tabs",
- items=[("MENU", "Gizmo Menu", "", 0), ("ACTIONS", "Action Menu", "", 1)],
- default="MENU",
+ items=[
+ ("GIZMO", "Gizmo", "", 0),
+ ("ACTIONS", "Action", "", 1),
+ ],
+ default="GIZMO",
)
def to_dict(self):
@@ -323,35 +465,29 @@ def from_dict(self, data: dict):
self.header_toggle_position = data.get("header_toggle_position", "RIGHT")
self.lazy_mode = data.get("lazy_mode", False)
self.enable_floating_toggle = data.get("enable_floating_toggle", False)
- self.toggle_position = data.get("toggle_position", (0.5, 0.5, 0.0))
+ self.toggle_position = data.get("toggle_position", (0, 0))
self.toggle_color = data.get("toggle_color", (0.1, 0.1, 0.2, 0.5))
self.isVisible = data.get("is_visible", False)
- self.input_mode = data.get("input_mode", "full")
+ self.input_mode = data.get("input_mode", "FULL")
self.enable_double_click = data.get("enable_double_click", True)
- self.double_click_mode = data.get(
- "double_click_mode", "screen.screen_full_area"
- )
+ self.double_click_mode = data.get("double_click_mode", "screen.screen_full_area")
self.enable_right_click = data.get("enable_right_click", True)
- self.right_click_mode = data.get(
- "right_click_mode", "wm.window_fullscreen_toggle"
- )
- self.right_click_source = data.get("right_click_source", "mouse")
+ self.right_click_mode = data.get("right_click_mode", "wm.window_fullscreen_toggle")
+ self.right_click_source = data.get("right_click_source", "MOUSE")
self.swap_panrotate = data.get("swap_panrotate", False)
self.width = data.get("width", 40.0)
self.radius = data.get("radius", 35.0)
self.use_multiple_colors = data.get("use_multiple_colors", False)
self.overlay_main_color = data.get("overlay_main_color", (1.0, 1.0, 1.0, 0.01))
- self.overlay_secondary_color = data.get(
- "overlay_secondary_color", (1.0, 1.0, 1.0, 0.01)
- )
+ self.overlay_secondary_color = data.get("overlay_secondary_color", (1.0, 1.0, 1.0, 0.01))
self.show_menu = data.get("show_menu", True)
self.show_gizmos = data.get("show_gizmos", True)
self.menu_style = data.get("menu_style", "float.radial")
self.menu_orientation = data.get("menu_orientation", "HORIZONTAL")
- self.menu_spacing = data.get("menu_spacing", 20.0)
- self.gizmo_padding = data.get("gizmo_padding", 10)
- self.gizmo_scale = data.get("gizmo_scale", 4.0)
- self.menu_position = data.get("menu_position", (95.00, 5.00))
+ self.menu_spacing = data.get("menu_spacing", 1.0)
+ self.gizmo_scale = data.get("gizmo_scale", 1.0)
+ self.gizmo_padding = data.get("gizmo_padding", 4.0)
+ self.menu_position = data.get("menu_position", (100, 0))
self.show_undoredo = data.get("show_undoredo", True)
self.show_is_enabled = data.get("show_is_enabled", True)
self.show_control_gizmo = data.get("show_control_gizmo", True)
@@ -369,18 +505,14 @@ def from_dict(self, data: dict):
self.pivot_mode = data.get("pivot_mode", "SURFACE")
self.topology_mode = data.get("topology_mode", "MANUAL")
self.show_float_menu = data.get("show_float_menu", False)
- self.floating_position = data.get("floating_position", (95.00, 5.00))
- self.double_click_mode = data.get(
- "double_click_mode", "wm.window_fullscreen_toggle"
- )
+ self.floating_position = data.get("floating_position", (100, 0))
+ self.double_click_mode = data.get("double_click_mode", "wm.window_fullscreen_toggle")
self.active_menu = data.get("active_menu", "VIEW3D")
- self.gizmo_tabs = data.get("gizmo_tabs", "MENU")
- self.menu_sets = [
- MenuModeGroup().from_dict(m) for m in data.get("menu_sets", [])
- ]
+ self.gizmo_tabs = data.get("gizmo_tabs", "GIZMO")
+ self.menu_sets = [TOUCHVIEW_PG_MenuModeGroup().from_dict(m) for m in data.get("menu_sets", [])]
def load(self):
- filename = path.abspath(path.dirname(__file__) + "/settings.json")
+ filename = path.abspath(path.dirname(__file__) + "/preferences.json")
if not path.exists(filename):
return None
@@ -393,110 +525,102 @@ def load(self):
return None
def save(self):
- filename = path.abspath(path.dirname(__file__) + "/settings.json")
+ filename = path.abspath(path.dirname(__file__) + "/preferences.json")
with open(filename, "w") as file:
json.dump(self.to_dict(), file)
+ def draw_v4(self, context):
+ pass
+
# set up addon preferences UI
- def draw(self, _: Context):
+ def draw(self, context):
+ layout = self.layout
+ layout.use_property_decorate = False
+
# Input Mode
- col = self.layout.column()
- col.label(text="Input Mode")
- col = col.box()
- if self.input_mode == "full":
- col.label(text="pen, mouse, touch input", icon="CON_CAMERASOLVER")
- if self.input_mode == "pen":
- col.label(text="pen-only input", icon="STYLUS_PRESSURE")
- if self.input_mode == "touch":
- col.label(text="mouse/touch only input", icon="VIEW_PAN")
- tabs = col.column_flow(columns=3, align=True)
- tabs.prop_tabs_enum(self, "input_mode")
- col.prop(self, "lazy_mode", toggle=1)
- if self.input_mode == "full":
- col.prop(self, "enable_floating_toggle", toggle=1)
-
- # main settings
- row = self.layout.split(factor=0.4)
- ##
- # Viewport Settings
- ##
- col = row.column()
- col.label(text="Control Zones")
- col.label(text="Input Mode")
- col.prop(self, "is_enabled", toggle=1)
- col.label(text="2D Header Toggle Position")
- tabs = col.column_flow(columns=2, align=True)
- tabs.prop_tabs_enum(self, "header_toggle_position")
- col.prop(self, "swap_panrotate")
+ box = layout.box()
+ box.label(text="Input Mode")
+ box.use_property_split = True
+
+ col = box.column()
+ col.prop(self, "input_mode", text=UILayout.enum_item_description(self, "input_mode", self.input_mode), expand=True)
+ col = box.column(align=True)
+ col.prop(self, "lazy_mode")
+ if self.input_mode == "FULL":
+ col.prop(self, "enable_floating_toggle")
+
+ # Control Zones
+ box = layout.box()
+ box.prop(self, "is_enabled", text="Control Zones")
+
+ col = box.column()
+ col.use_property_split = True
+ col.active = self.is_enabled
+
+ col = col.column()
+ col.prop(self, "header_toggle_position", expand=True)
+ col = col.column(align=True)
col.prop(self, "isVisible", text="Show Overlay")
+ col.prop(self, "swap_panrotate")
col.prop(self, "use_multiple_colors")
+ col = col.column()
col.prop(self, "overlay_main_color", text="Main Color")
if self.use_multiple_colors:
col.prop(self, "overlay_secondary_color", text="Secondary Color")
col.prop(self, "width", slider=True)
col.prop(self, "radius", slider=True)
- ##
- # Gizmo Settings
- ##
- col = row.column()
- col.label(text="Gizmo Options")
- tabs = col.column_flow(columns=3, align=True)
- tabs.prop_tabs_enum(self, "gizmo_tabs")
+ # Gixmo Options
+ main_box = layout.box()
- main = col.box()
- if self.gizmo_tabs == "MENU":
- main.label(text="Gizmo Menu Style")
- tabs = main.column_flow(columns=2, align=True)
- tabs.prop_tabs_enum(self, "menu_style")
+ col = main_box.row(align=True)
+ col.prop(self, "gizmo_tabs", expand=True)
+
+ main_box.use_property_split = True
+ col = main_box.column()
+
+ if self.gizmo_tabs == "GIZMO":
+ row = col.row()
+ row.prop(self, "menu_style", expand=True)
if self.menu_style == "fixed.bar":
- main.prop_menu_enum(self, "gizmo_position")
- main.prop(self, "menu_spacing", slider=True)
- if self.menu_style == "float.radial":
- main.prop(self, "gizmo_padding", slider=True)
- main.prop(self, "gizmo_scale", slider=True)
-
- main.separator()
- main.label(text="Input Options")
- wrapper = main.box()
- wrapper.label(text="Right Click Actions")
- r = wrapper.split(factor=0.3, align=True)
- r.label(text="Input Source")
- r = r.row()
- r.prop(self, "right_click_source", expand=True)
-
- r = wrapper.split(factor=0.3, align=True)
- r.label(text="Click Action")
- c = r.column()
- c.prop(self, "right_click_mode", expand=True)
- main.separator()
- wrapper = main.box()
- wrapper.label(text="Double Click Actions")
- wrapper.prop(self, "enable_double_click", toggle=1)
- r = wrapper.split(factor=0.3, align=True)
- r.label(text="Click Action")
- c = r.column()
- c.prop(self, "double_click_mode", expand=True)
-
- main.separator()
- main.label(text="Tool Settings")
- main.prop(self, "subdivision_limit", slider=True)
+ col.prop(self, "gizmo_position")
+ elif self.menu_style == "float.radial":
+ col.prop(self, "menu_spacing", slider=True)
+
+ col.prop(self, "gizmo_scale", slider=True)
+ col.prop(self, "gizmo_padding", slider=True)
+
+ column = main_box.column()
+ box = column.box()
+ box.label(text="Right Click Actions")
+ col = box.column()
+ row = col.row()
+ row.prop(self, "right_click_source", text="Source", expand=True)
+ col.prop(self, "right_click_mode", text="Mode", expand=True)
+
+ box = main_box.box()
+ box.label(text="Double Click Actions")
+ col = box.column()
+ col.prop(self, "enable_double_click")
+ col.prop(self, "double_click_mode", text="Mode", expand=True)
+
+ col = main_box.column()
+ col.label(text="Tool Settings")
+ col.prop(self, "subdivision_limit", slider=True)
if self.gizmo_tabs == "ACTIONS":
if not self.show_float_menu:
- main.operator("view3d.toggle_floating_menu", text="Show Action Menu")
+ col.operator("view3d.toggle_floating_menu", text="Show Action Menu")
else:
- main.operator(
- "view3d.toggle_floating_menu", text="Hide Action Menu", depress=True
- )
- box = main.box()
+ col.operator("view3d.toggle_floating_menu", text="Hide Action Menu", depress=True)
+ box = col.box()
box.active = self.show_float_menu
- main = box.column()
- main.prop(self, "active_menu")
+ col = box.column()
+ col.prop(self, "active_menu")
mList = self.getMenuSettings(self.active_menu)
for i in range(7):
- main.prop(mList, "menu_slot_" + str(i + 1))
+ col.prop(mList, "menu_slot_" + str(i + 1))
##
# Data Accessors
@@ -529,3 +653,22 @@ def getWidth(self):
def getRadius(self):
return self.radius / 100
+
+
+classes = (
+ TOUCHVIEW_PG_MenuModeGroup,
+ TOUCHVIEW_AP_OverlaySettings,
+)
+
+
+def register():
+ for cls in classes:
+ bpy.utils.register_class(cls)
+
+
+def unregister():
+ for cls in reversed(classes):
+ bpy.utils.unregister_class(cls)
+
+ bpy.types.NODE_HT_header.remove(NODE_HT_nendo_header)
+ bpy.types.IMAGE_HT_header.remove(NODE_HT_nendo_header)
diff --git a/source/__init__.py b/source/__init__.py
new file mode 100644
index 0000000..41d61dc
--- /dev/null
+++ b/source/__init__.py
@@ -0,0 +1,13 @@
+from . import ops, ui, utils
+
+
+def register():
+ ops.register()
+ ui.register()
+ utils.register()
+
+
+def unregister():
+ ops.unregister()
+ ui.unregister()
+ utils.unregister()
diff --git a/source/ops/__init__.py b/source/ops/__init__.py
new file mode 100644
index 0000000..c6c865b
--- /dev/null
+++ b/source/ops/__init__.py
@@ -0,0 +1,14 @@
+# flake8: noqa
+from . import actions, gizmo, touch
+
+
+def register():
+ actions.register()
+ touch.register()
+ gizmo.register()
+
+
+def unregister():
+ actions.unregister()
+ touch.unregister()
+ gizmo.unregister()
diff --git a/lib/operators/actions.py b/source/ops/actions.py
similarity index 69%
rename from lib/operators/actions.py
rename to source/ops/actions.py
index 73d7105..13a0071 100644
--- a/lib/operators/actions.py
+++ b/source/ops/actions.py
@@ -1,20 +1,24 @@
import math
import bpy
-from bpy.types import Context, Event, MultiresModifier, Operator, SpaceView3D
+from bpy.types import Operator
-from ..constants import CANCEL, FINISHED, pivot_items
-from ..utils import get_settings
+from ..utils.blender import preferences
+from ..utils.constants import CANCEL, FINISHED, pivot_items
-class VIEW3D_OT_FlipTools(Operator):
+class TOUCHVIEW_OT_flip_tools(Operator):
"""Relocate Tools panel between left and right"""
- bl_idname = "view3d.tools_region_flip"
bl_label = "Tools Region Swap"
+ bl_idname = "view3d.tools_region_flip"
+
+ @classmethod
+ def poll(cls, context):
+ return context.area.type == "VIEW_3D" and context.region.type == "WINDOW"
- def execute(self, context: Context):
- override: Context = context.copy()
+ def execute(self, context):
+ override = context.copy()
override["area"] = context.area
override["region"] = context.region
for r in context.area.regions:
@@ -24,87 +28,83 @@ def execute(self, context: Context):
bpy.ops.screen.region_flip()
return FINISHED
- @classmethod
- def poll(cls, context: Context):
- return context.area.type == "VIEW_3D" and context.region.type == "WINDOW"
-
-class VIEW3D_OT_NextPivotMode(Operator):
+class TOUCHVIEW_OT_next_pivot_mode(Operator):
"""Step through Pivot modes"""
- bl_idname = "view3d.step_pivot_mode"
bl_label = "Use next Pivot mode"
+ bl_idname = "view3d.step_pivot_mode"
- def execute(self, context: Context):
- settings = get_settings()
+ @classmethod
+ def poll(cls, context):
+ return context.area.type == "VIEW_3D" and context.region.type == "WINDOW"
+
+ def execute(self, context):
+ prefs = preferences()
count = 0
for enum, _, _ in pivot_items:
- if enum == settings.pivot_mode:
+ if enum == prefs.pivot_mode:
count += 1
if count == len(pivot_items):
count = 0
pivot = pivot_items[count][0]
bpy.ops.sculpt.set_pivot_position(mode=pivot)
- settings.pivot_mode = pivot
+ prefs.pivot_mode = pivot
context.area.tag_redraw()
return FINISHED
count += 1
return FINISHED
- @classmethod
- def poll(cls, context: Context):
- return context.area.type == "VIEW_3D" and context.region.type == "WINDOW"
-
-class VIEW3D_OT_ToggleTouchControls(Operator):
+class TOUCHVIEW_OT_toggle_touch_controls(Operator):
"""Toggle Touch Controls"""
- bl_idname = "nendo.toggle_touch"
bl_label = "Toggle Touch Controls"
+ bl_idname = "touchview.toggle_touch"
- def execute(self, context: Context):
- settings = get_settings()
- settings.is_enabled = not settings.is_enabled
+ def execute(self, context):
+ prefs = preferences()
+ prefs.is_enabled = not prefs.is_enabled
context.area.tag_redraw()
return FINISHED
-class VIEW3D_OT_ToggleNPanel(Operator):
+class TOUCHVIEW_OT_toggle_npanel(Operator):
"""Toggle Settings Panel"""
- bl_idname = "nendo.toggle_n_panel"
- bl_label = "Display settings Panel"
+ bl_label = "Display prefs Panel"
+ bl_idname = "touchview.toggle_n_panel"
+
+ @classmethod
+ def poll(cls, context):
+ return context.area.type == "VIEW_3D" and context.region.type == "WINDOW"
- def execute(self, context: Context):
- if not isinstance(context.space_data, SpaceView3D):
+ def execute(self, context):
+ if not isinstance(context.space_data, bpy.types.SpaceView3D):
return CANCEL
context.space_data.show_region_ui ^= True
return FINISHED
- @classmethod
- def poll(cls, context: Context):
- return context.area.type == "VIEW_3D" and context.region.type == "WINDOW"
-
-class VIEW3D_OT_ToggleFloatingMenu(Operator):
+class TOUCHVIEW_OT_toggle_floating_menu(Operator):
"""Toggle Floating Menu"""
- bl_idname = "view3d.toggle_floating_menu"
bl_label = "Toggle Floating Menu"
+ bl_idname = "view3d.toggle_floating_menu"
- def execute(self, context: Context):
- settings = get_settings()
- settings.show_float_menu = not settings.show_float_menu
+ def execute(self, context):
+ prefs = preferences()
+ prefs.show_float_menu = not prefs.show_float_menu
return FINISHED
-class VIEW3D_OT_ViewportRecenter(Operator):
+class TOUCHVIEW_OT_viewport_recenter(Operator):
"""Recenter Viewport and Cursor on Selected Object"""
- bl_idname = "nendo.viewport_recenter"
bl_label = "Recenter Viewport and Cursor on Selected"
+ bl_idname = "touchview.viewport_recenter"
- def execute(self, context: Context):
+ def execute(self, context):
current = context.scene.tool_settings.transform_pivot_point
context.scene.tool_settings.transform_pivot_point = "ACTIVE_ELEMENT"
bpy.ops.view3d.snap_cursor_to_selected()
@@ -114,16 +114,16 @@ def execute(self, context: Context):
return FINISHED
-class VIEW3D_OT_ViewportLock(Operator):
+class TOUCHVIEW_OT_viewport_lock(Operator):
"""Toggle Viewport Rotation"""
- bl_idname = "nendo.viewport_lock"
bl_label = "Viewport rotation lock toggle"
+ bl_idname = "touchview.viewport_lock"
region_ids = []
- def execute(self, context: Context):
- if not isinstance(context.area.spaces.active, SpaceView3D):
+ def execute(self, context):
+ if not isinstance(context.area.spaces.active, bpy.types.SpaceView3D):
return CANCEL
if len(context.area.spaces.active.region_quadviews) == 0:
context.region_data.lock_rotation ^= True
@@ -147,24 +147,26 @@ def execute(self, context: Context):
return FINISHED
-class VIEW3D_OT_BrushResize(Operator):
+class TOUCHVIEW_OT_brush_resize(Operator):
"""Brush Resize"""
- bl_idname = "nendo.brush_resize"
bl_label = "Brush Size Adjust"
+ bl_idname = "touchview.brush_resize"
+
+ def invoke(self, context, event):
+ self.mouse_x = event.mouse_region_x
+ self.mouse_y = event.mouse_region_y
+ self.execute(context)
+ return FINISHED
# activate radial_control to change sculpt brush size
- def execute(self, context: Context):
- settings = get_settings()
- if settings.menu_style in ["fixed.bar"]:
- if settings.gizmo_position in ["LEFT", "RIGHT"]:
- context.window.cursor_warp(
- math.floor(context.region.width / 2), self.mousey
- )
+ def execute(self, context):
+ prefs = preferences()
+ if prefs.menu_style in {"fixed.bar"}:
+ if prefs.gizmo_position in ["LEFT", "RIGHT"]:
+ context.window.cursor_warp(math.floor(context.region.width / 2), self.mouse_y)
else:
- context.window.cursor_warp(
- self.mousex, math.floor(context.region.height / 2)
- )
+ context.window.cursor_warp(self.mouse_x, math.floor(context.region.height / 2))
if context.mode in [
"PAINT_GPENCIL",
"EDIT_GPENCIL",
@@ -175,7 +177,7 @@ def execute(self, context: Context):
return self.resize2d(context)
return self.resize3d(context)
- def resize2d(self, context: Context):
+ def resize2d(self, context):
data_path = "tool_settings.gpencil_paint.brush.size"
if context.mode == "SCULPT_GPENCIL":
data_path = "tool_settings.gpencil_sculpt_paint.brush.size"
@@ -189,7 +191,7 @@ def resize2d(self, context: Context):
)
return FINISHED
- def resize3d(self, context: Context):
+ def resize3d(self, context):
data_path = "tool_settings.sculpt.brush.size"
if context.mode == "PAINT_VERTEX":
data_path = "tool_settings.vertex_paint.brush.size"
@@ -210,31 +212,27 @@ def resize3d(self, context: Context):
)
return FINISHED
- def invoke(self, context: Context, event: Event):
- self.mousex = event.mouse_region_x
- self.mousey = event.mouse_region_y
- self.execute(context)
- return FINISHED
-
-class VIEW3D_OT_BrushStrength(Operator):
+class TOUCHVIEW_OT_brush_strength(Operator):
"""Brush Strength"""
- bl_idname = "nendo.brush_strength"
bl_label = "Brush Strength Adjust"
+ bl_idname = "touchview.brush_strength"
+
+ def invoke(self, context, event):
+ self.mouse_x = event.mouse_region_x
+ self.mouse_y = event.mouse_region_y
+ self.execute(context)
+ return FINISHED
# activate radial_control to change sculpt brush size
- def execute(self, context: Context):
- settings = get_settings()
- if settings.menu_style in ["fixed.bar"]:
- if settings.gizmo_position in ["LEFT", "RIGHT"]:
- context.window.cursor_warp(
- math.floor(context.region.width / 2), self.mousey
- )
+ def execute(self, context):
+ prefs = preferences()
+ if prefs.menu_style in {"fixed.bar"}:
+ if prefs.gizmo_position in ["LEFT", "RIGHT"]:
+ context.window.cursor_warp(math.floor(context.region.width / 2), self.mouse_y)
else:
- context.window.cursor_warp(
- self.mousex, math.floor(context.region.height / 2)
- )
+ context.window.cursor_warp(self.mouse_x, math.floor(context.region.height / 2))
if context.mode in [
"PAINT_GPENCIL",
"EDIT_GPENCIL",
@@ -245,23 +243,21 @@ def execute(self, context: Context):
return self.resize2d(context)
return self.resize3d(context)
- def resize2d(self, context: Context):
+ def resize2d(self, context):
data_path = "tool_settings.gpencil_paint.brush.gpencil_settings.pen_strength"
if context.mode == "SCULPT_GPENCIL":
data_path = "tool_settings.gpencil_sculpt_paint.brush.strength"
if context.mode == "WEIGHT_GPENCIL":
data_path = "tool_settings.gpencil_weight_paint.brush.strength"
if context.mode == "VERTEX_GPENCIL":
- data_path = (
- "tool_settings.gpencil_vertex_paint.brush.gpencil_settings.pen_strength"
- )
+ data_path = "tool_settings.gpencil_vertex_paint.brush.gpencil_settings.pen_strength"
bpy.ops.wm.radial_control(
"INVOKE_DEFAULT", # type: ignore
data_path_primary=data_path,
)
return FINISHED
- def resize3d(self, context: Context):
+ def resize3d(self, context):
data_path = "tool_settings.sculpt.brush.strength"
if context.mode == "PAINT_VERTEX":
data_path = "tool_settings.vertex_paint.brush.strength"
@@ -282,35 +278,29 @@ def resize3d(self, context: Context):
)
return FINISHED
- def invoke(self, context: Context, event: Event):
- self.mousex = event.mouse_region_x
- self.mousey = event.mouse_region_y
- self.execute(context)
- return FINISHED
-
-class VIEW3D_OT_IncreaseMultires(Operator):
+class TOUCHVIEW_OT_increase_multires(Operator):
"""Increment Multires by 1 or add subdivision"""
- bl_idname = "nendo.increment_multires"
bl_label = "Increment Multires modifier by 1 or add subdivision level"
+ bl_idname = "touchview.increment_multires"
- def execute(self, context: Context):
- settings = get_settings()
+ def execute(self, context):
+ prefs = preferences()
if not context.active_object or not len(context.active_object.modifiers):
return CANCEL
for mod in context.active_object.modifiers:
- # if mod is type of MultiresModifier
- if isinstance(mod, MultiresModifier):
+ # if mod is type of bpy.types.MultiresModifier
+ if isinstance(mod, bpy.types.MultiresModifier):
if context.mode == "SCULPT":
if mod.sculpt_levels == mod.total_levels:
- if mod.sculpt_levels < settings.subdivision_limit:
+ if mod.sculpt_levels < prefs.subdivision_limit:
bpy.ops.object.multires_subdivide(modifier=mod.name)
else:
mod.sculpt_levels += 1
else:
if mod.levels == mod.total_levels:
- if mod.levels < settings.subdivision_limit:
+ if mod.levels < prefs.subdivision_limit:
bpy.ops.object.multires_subdivide(modifier=mod.name)
else:
mod.levels += 1
@@ -318,17 +308,17 @@ def execute(self, context: Context):
return CANCEL
-class VIEW3D_OT_DecreaseMultires(Operator):
+class TOUCHVIEW_OT_decrease_multires(Operator):
"""Decrement Multires by 1"""
- bl_idname = "nendo.decrement_multires"
bl_label = "decrement Multires modifier by 1"
+ bl_idname = "touchview.decrement_multires"
- def execute(self, context: Context):
+ def execute(self, context):
if not context.active_object or not len(context.active_object.modifiers):
return CANCEL
for mod in context.active_object.modifiers:
- if not isinstance(mod, MultiresModifier):
+ if not isinstance(mod, bpy.types.MultiresModifier):
return FINISHED
if context.mode == "SCULPT":
if mod.sculpt_levels == 0:
@@ -344,17 +334,17 @@ def execute(self, context: Context):
return CANCEL
-class VIEW3D_OT_DensityUp(Operator):
+class TOUCHVIEW_OT_density_up(Operator):
"""Increase voxel density"""
- bl_idname = "nendo.density_up"
bl_label = "Increase voxel density and remesh"
+ bl_idname = "touchview.density_up"
- def execute(self, context: Context):
+ def execute(self, context):
if not context.active_object:
return CANCEL
for mod in context.active_object.modifiers:
- if isinstance(mod, MultiresModifier):
+ if isinstance(mod, bpy.types.MultiresModifier):
return CANCEL
mesh = bpy.data.meshes[context.active_object.name]
mesh.remesh_voxel_size *= 0.8
@@ -362,19 +352,39 @@ def execute(self, context: Context):
return FINISHED
-class VIEW3D_OT_DensityDown(Operator):
+class TOUCHVIEW_OT_density_down(Operator):
"""Decrease voxel density"""
- bl_idname = "nendo.density_down"
bl_label = "Decrease voxel density and remesh"
+ bl_idname = "touchview.density_down"
- def execute(self, context: Context):
+ def execute(self, context):
if not context.active_object:
return CANCEL
for mod in context.active_object.modifiers:
- if isinstance(mod, MultiresModifier):
+ if isinstance(mod, bpy.types.MultiresModifier):
return CANCEL
mesh = bpy.data.meshes[context.active_object.name]
mesh.remesh_voxel_size /= 0.8
bpy.ops.object.voxel_remesh()
return FINISHED
+
+
+classes = (
+ TOUCHVIEW_OT_brush_resize,
+ TOUCHVIEW_OT_brush_strength,
+ TOUCHVIEW_OT_decrease_multires,
+ TOUCHVIEW_OT_density_down,
+ TOUCHVIEW_OT_density_up,
+ TOUCHVIEW_OT_flip_tools,
+ TOUCHVIEW_OT_increase_multires,
+ TOUCHVIEW_OT_next_pivot_mode,
+ TOUCHVIEW_OT_toggle_floating_menu,
+ TOUCHVIEW_OT_toggle_npanel,
+ TOUCHVIEW_OT_toggle_touch_controls,
+ TOUCHVIEW_OT_viewport_lock,
+ TOUCHVIEW_OT_viewport_recenter,
+)
+
+
+register, unregister = bpy.utils.register_classes_factory(classes)
diff --git a/lib/operators/ui.py b/source/ops/gizmo.py
similarity index 51%
rename from lib/operators/ui.py
rename to source/ops/gizmo.py
index 08f7e92..4b4be1f 100644
--- a/lib/operators/ui.py
+++ b/source/ops/gizmo.py
@@ -1,30 +1,47 @@
import bpy
-from bpy.types import Context, Event, Operator, SpaceView3D
+from bpy.types import Operator
from mathutils import Vector
-from ..constants import CANCEL, FINISHED, MODAL
-from ..utils import buildSafeArea, get_settings
+from ..utils.blender import *
+from ..utils.constants import CANCEL, FINISHED, MODAL
-class VIEW3D_OT_MoveFloatMenu(Operator):
- bl_idname = "nendo.move_float_menu"
+class TOUCHVIEW_OT_move_float_menu(Operator):
bl_label = "Relocate Gizmo Menu"
+ bl_idname = "touchview.move_float_menu"
- def execute(self, context: Context):
- settings = get_settings()
- fence = buildSafeArea()
+ def invoke(self, context, event):
+ self.has_moved = False
+ prefs = preferences()
+ fence = safe_area_3d(padding=90)
span = Vector((fence[1].x - fence[0].x, fence[1].y - fence[0].y))
- settings.menu_position[0] = min(
- max((self.x - fence[0].x + self.offset.x) / (span.x) * 100.0, 0.0), 100.0
- )
- settings.menu_position[1] = min(
- max((self.y - fence[0].y + self.offset.y) / (span.y) * 100.0, 0.0), 100.0
+ self.init_x = prefs.menu_position[0]
+ self.init_y = prefs.menu_position[1]
+ self.mouse_init_x = self.x = event.mouse_region_x
+ self.mouse_init_y = self.y = event.mouse_region_y
+ self.offset = Vector(
+ (
+ (span.x * self.init_x * 0.01 + fence[0].x) - self.x,
+ (span.y * self.init_y * 0.01 + fence[0].y) - self.y,
+ )
)
+ self.execute(context)
+
+ context.window_manager.modal_handler_add(self)
+ return MODAL
+
+ def execute(self, context):
+ prefs = preferences()
+ fence = safe_area_3d(padding=90)
+ span = Vector((fence[1].x - fence[0].x, fence[1].y - fence[0].y))
+
+ prefs.menu_position[0] = min(max((self.x - fence[0].x + self.offset.x) / (span.x) * 100.0, 0.0), 100.0)
+ prefs.menu_position[1] = min(max((self.y - fence[0].y + self.offset.y) / (span.y) * 100.0, 0.0), 100.0)
return FINISHED
- def modal(self, context: Context, event: Event):
- settings = get_settings()
+ def modal(self, context, event):
+ prefs = preferences()
if event.type == "MOUSEMOVE" and event.value != "RELEASE": # Apply
context.region.tag_redraw()
self.x = event.mouse_region_x
@@ -32,58 +49,57 @@ def modal(self, context: Context, event: Event):
self.execute(context)
elif event.value == "RELEASE": # Confirm
if not self.__hasMoved():
- settings.menu_position[0] = self.init_x
- settings.menu_position[1] = self.init_y
- settings.show_gizmos = not settings.show_gizmos
+ prefs.menu_position[0] = self.init_x
+ prefs.menu_position[1] = self.init_y
+ prefs.show_gizmos = not prefs.show_gizmos
return FINISHED
return MODAL
def __hasMoved(self) -> bool:
- settings = get_settings()
+ prefs = preferences()
init = Vector((self.mouse_init_x, self.mouse_init_y))
final = Vector((self.x, self.y))
- if (final - init).length > settings.menu_spacing / 2:
+ if (final - init).length > prefs.menu_spacing / 2:
return True
return False
- def invoke(self, context: Context, event: Event):
+
+class TOUCHVIEW_OT_menu_controller(Operator):
+ bl_label = "Relocate Action Menu"
+ bl_idname = "touchview.move_action_menu"
+
+ def invoke(self, context, event):
self.has_moved = False
- settings = get_settings()
- fence = buildSafeArea()
+ prefs = preferences()
+ fence = safe_area_3d()
+
span = Vector((fence[1].x - fence[0].x, fence[1].y - fence[0].y))
- self.init_x = settings.menu_position[0]
- self.init_y = settings.menu_position[1]
+ self.init_x = prefs.floating_position[0]
+ self.init_y = prefs.floating_position[1]
self.mouse_init_x = self.x = event.mouse_region_x
self.mouse_init_y = self.y = event.mouse_region_y
- self.offset = Vector((
- (span.x * self.init_x * 0.01 + fence[0].x) - self.x,
- (span.y * self.init_y * 0.01 + fence[0].y) - self.y,
- ))
+ self.offset = Vector(
+ (
+ (span.x * self.init_x * 0.01 + fence[0].x) - self.x,
+ (span.y * self.init_y * 0.01 + fence[0].y) - self.y,
+ )
+ )
self.execute(context)
context.window_manager.modal_handler_add(self)
return MODAL
-
-class VIEW3D_OT_MenuController(Operator):
- bl_idname = "nendo.move_action_menu"
- bl_label = "Relocate Action Menu"
-
- def execute(self, context: Context):
- settings = get_settings()
- fence = buildSafeArea()
+ def execute(self, context):
+ prefs = preferences()
+ fence = safe_area_3d()
span = Vector((fence[1].x - fence[0].x, fence[1].y - fence[0].y))
- settings.floating_position[0] = min(
- max((self.x - fence[0].x + self.offset.x) / (span.x) * 100.0, 0.0), 100.0
- )
- settings.floating_position[1] = min(
- max((self.y - fence[0].y + self.offset.y) / (span.y) * 100.0, 0.0), 100.0
- )
+ prefs.floating_position[0] = min(max((self.x - fence[0].x + self.offset.x) / (span.x) * 100.0, 0.0), 100.0)
+ prefs.floating_position[1] = min(max((self.y - fence[0].y + self.offset.y) / (span.y) * 100.0, 0.0), 100.0)
return FINISHED
- def modal(self, context: Context, event: Event):
- settings = get_settings()
+ def modal(self, context, event):
+ prefs = preferences()
if event.type == "MOUSEMOVE" and event.value != "RELEASE": # Apply
context.region.tag_redraw()
self.x = event.mouse_region_x
@@ -91,49 +107,35 @@ def modal(self, context: Context, event: Event):
self.execute(context)
elif event.value == "RELEASE": # Confirm
if not self.__hasMoved():
- settings.floating_position[0] = self.init_x
- settings.floating_position[1] = self.init_y
+ prefs.floating_position[0] = self.init_x
+ prefs.floating_position[1] = self.init_y
bpy.ops.wm.call_menu_pie(
"INVOKE_DEFAULT", # type: ignore
- name="PIE_MT_Floating_Menu",
+ name="TOUCHVIEW_MT_floating",
)
return FINISHED
return MODAL
def __hasMoved(self) -> bool:
- settings = get_settings()
+ prefs = preferences()
init = Vector((self.mouse_init_x, self.mouse_init_y))
final = Vector((self.x, self.y))
- if (final - init).length > settings.menu_spacing / 2:
+ if (final - init).length > prefs.menu_spacing / 2:
return True
return False
- def invoke(self, context: Context, event: Event):
- self.has_moved = False
- settings = get_settings()
- fence = buildSafeArea()
- span = Vector((fence[1].x - fence[0].x, fence[1].y - fence[0].y))
- self.init_x = settings.floating_position[0]
- self.init_y = settings.floating_position[1]
- self.mouse_init_x = self.x = event.mouse_region_x
- self.mouse_init_y = self.y = event.mouse_region_y
- self.offset = Vector((
- (span.x * self.init_x * 0.01 + fence[0].x) - self.x,
- (span.y * self.init_y * 0.01 + fence[0].y) - self.y,
- ))
- self.execute(context)
-
- context.window_manager.modal_handler_add(self)
- return MODAL
-
-class VIEW3D_OT_CycleControlGizmo(Operator):
- bl_idname = "nendo.cycle_control_gizmo"
+class TOUCHVIEW_OT_cycle_controlGizmo(Operator):
bl_label = "switch object control gizmo"
+ bl_idname = "touchview.cycle_control_gizmo"
+
+ @classmethod
+ def poll(cls, context):
+ return context.area.type in ["VIEW_2D", "VIEW_3D"] and context.region.type == "WINDOW"
- def execute(self, context: Context):
+ def execute(self, context):
space = context.space_data
- if not isinstance(space, SpaceView3D):
+ if not isinstance(space, bpy.types.SpaceView3D):
return CANCEL
mode = self.getMode(space)
self.clearControls(space)
@@ -145,7 +147,7 @@ def execute(self, context: Context):
space.show_gizmo_object_scale = True
return FINISHED
- def getMode(self, space: SpaceView3D):
+ def getMode(self, space: bpy.types.SpaceView3D):
if space.show_gizmo_object_translate:
return "translate"
if space.show_gizmo_object_rotate:
@@ -154,38 +156,48 @@ def getMode(self, space: SpaceView3D):
return "scale"
return "none"
- def clearControls(self, space: SpaceView3D):
+ def clearControls(self, space: bpy.types.SpaceView3D):
space.show_gizmo_object_translate = False
space.show_gizmo_object_rotate = False
space.show_gizmo_object_scale = False
- @classmethod
- def poll(cls, context: Context):
- return (
- context.area.type in ["VIEW_2D", "VIEW_3D"]
- and context.region.type == "WINDOW"
- )
-
-class VIEW3D_OT_FloatController(Operator):
- bl_idname = "nendo.move_toggle_button"
+class TOUCHVIEW_OT_float_controller(Operator):
bl_label = "Relocate Toggle Button"
+ bl_idname = "touchview.move_toggle_button"
- def execute(self, context: Context):
- settings = get_settings()
- fence = buildSafeArea()
- span = Vector((fence[1].x - fence[0].x, fence[1].y - fence[0].y))
+ def invoke(self, context, event):
+ self.has_moved = False
+ prefs = preferences()
+ fence = safe_area_3d()
- settings.toggle_position[0] = min(
- max((self.x - fence[0].x + self.offset.x) / (span.x) * 100.0, 0.0), 100.0
- )
- settings.toggle_position[1] = min(
- max((self.y - fence[0].y + self.offset.y) / (span.y) * 100.0, 0.0), 100.0
+ span = Vector((fence[1].x - fence[0].x, fence[1].y - fence[0].y))
+ self.init_x = prefs.toggle_position[0]
+ self.init_y = prefs.toggle_position[1]
+ self.mouse_init_x = self.x = event.mouse_region_x
+ self.mouse_init_y = self.y = event.mouse_region_y
+ self.offset = Vector(
+ (
+ (span.x * self.init_x * 0.01 + fence[0].x) - self.x,
+ (span.y * self.init_y * 0.01 + fence[0].y) - self.y,
+ )
)
+ self.execute(context)
+
+ context.window_manager.modal_handler_add(self)
+ return MODAL
+
+ def execute(self, context):
+ prefs = preferences()
+ fence = safe_area_3d()
+ span = Vector((fence[1].x - fence[0].x, fence[1].y - fence[0].y))
+
+ prefs.toggle_position[0] = min(max((self.x - fence[0].x + self.offset.x) / (span.x) * 100.0, 0.0), 100.0)
+ prefs.toggle_position[1] = min(max((self.y - fence[0].y + self.offset.y) / (span.y) * 100.0, 0.0), 100.0)
return FINISHED
- def modal(self, context: Context, event: Event):
- settings = get_settings()
+ def modal(self, context, event):
+ prefs = preferences()
if (
event.mouse_region_x < 0
or event.mouse_region_y < 0
@@ -201,34 +213,27 @@ def modal(self, context: Context, event: Event):
self.execute(context)
elif event.value == "RELEASE": # Confirm
if not self.__hasMoved():
- settings.toggle_position[0] = self.init_x
- settings.toggle_position[1] = self.init_y
- settings.is_enabled = not settings.is_enabled
+ prefs.toggle_position[0] = self.init_x
+ prefs.toggle_position[1] = self.init_y
+ prefs.is_enabled = not prefs.is_enabled
return FINISHED
return MODAL
def __hasMoved(self) -> bool:
- settings = get_settings()
+ prefs = preferences()
init = Vector((self.mouse_init_x, self.mouse_init_y))
final = Vector((self.x, self.y))
- if (final - init).length > settings.menu_spacing / 2:
+ if (final - init).length > prefs.menu_spacing / 2:
return True
return False
- def invoke(self, context: Context, event: Event):
- self.has_moved = False
- settings = get_settings()
- fence = buildSafeArea()
- span = Vector((fence[1].x - fence[0].x, fence[1].y - fence[0].y))
- self.init_x = settings.toggle_position[0]
- self.init_y = settings.toggle_position[1]
- self.mouse_init_x = self.x = event.mouse_region_x
- self.mouse_init_y = self.y = event.mouse_region_y
- self.offset = Vector((
- (span.x * self.init_x * 0.01 + fence[0].x) - self.x,
- (span.y * self.init_y * 0.01 + fence[0].y) - self.y,
- ))
- self.execute(context)
- context.window_manager.modal_handler_add(self)
- return MODAL
+classes = (
+ TOUCHVIEW_OT_move_float_menu,
+ TOUCHVIEW_OT_menu_controller,
+ TOUCHVIEW_OT_cycle_controlGizmo,
+ TOUCHVIEW_OT_float_controller,
+)
+
+
+register, unregister = bpy.utils.register_classes_factory(classes)
diff --git a/lib/operators/touch.py b/source/ops/touch.py
similarity index 64%
rename from lib/operators/touch.py
rename to source/ops/touch.py
index e10a23f..21211dd 100644
--- a/lib/operators/touch.py
+++ b/source/ops/touch.py
@@ -1,104 +1,98 @@
import math
import bpy
-from bpy import ops
from bpy.props import EnumProperty
-from bpy.types import Context, Event, Operator
-from bpy_extras import view3d_utils
+from bpy.types import Operator
+from bpy_extras.view3d_utils import (region_2d_to_origin_3d,
+ region_2d_to_vector_3d)
from mathutils import Vector
-from ..constants import (FINISHED, LMOUSE, PASSTHROUGH, PEN, PRESS, RMOUSE,
- brush_modes, input_mode_items)
-from ..utils import get_settings
+from ..utils.blender import preferences
+from ..utils.constants import (FINISHED, LMOUSE, PASSTHROUGH, PEN, PRESS,
+ RMOUSE, brush_modes, input_mode_items)
-def isTouch(event: Event):
+def is_touch(event):
return event.pressure in [0.0, 1.0]
-class VIEW3D_OT_RightClick_Action(Operator):
+class TOUCHVIEW_OT_right_click_action(Operator):
"""Viewport right-click shortcut"""
- bl_idname = "nendo.rc_action"
bl_label = "Viewport right-click shortcut"
+ bl_idname = "touchview.rc_action"
- def execute(self, context: Context):
- settings = get_settings()
- op = settings.right_click_mode.split(".")
- if op[1] == "transfer_mode" and context.area.type != "VIEW_3D":
- return PASSTHROUGH
- if op[1] == "transfer_mode" and context.mode == "OBJECT":
- bpy.ops.view3d.select("INVOKE_DEFAULT") # type: ignore
- return PASSTHROUGH
- opgrp = getattr(bpy.ops, op[0])
- getattr(opgrp, op[1])("INVOKE_DEFAULT")
- return FINISHED
+ @classmethod
+ def poll(cls, context):
+ return context.area.type in {"VIEW_2D", "VIEW_3D"} and context.region.type == "WINDOW"
- def invoke(self, context: Context, event: Event):
- settings = get_settings()
- if settings.right_click_source == "none":
+ def invoke(self, context, event):
+ prefs = preferences()
+ if prefs.right_click_source == "NONE":
return PASSTHROUGH
if event.type not in [RMOUSE]:
return PASSTHROUGH
- if isTouch(event) and settings.right_click_source == "pen":
+ if is_touch(event) and prefs.right_click_source == "PEN":
return PASSTHROUGH
- if not isTouch(event) and settings.right_click_source == "mouse":
+ if not is_touch(event) and prefs.right_click_source == "MOUSE":
return PASSTHROUGH
if event.value == "DOUBLE_CLICK":
return PASSTHROUGH
self.execute(context)
return FINISHED
- @classmethod
- def poll(cls, context: Context):
- return (
- context.area.type in ["VIEW_2D", "VIEW_3D"]
- and context.region.type == "WINDOW"
- )
-
-
-class VIEW3D_OT_Doubletap_Action(Operator):
- """Viewport double-tap shortcut"""
-
- bl_idname = "nendo.dt_action"
- bl_label = "Viewport double-tap shortcut"
-
- def execute(self, context: Context):
- settings = get_settings()
- if not settings.enable_double_click:
- return PASSTHROUGH
- op = settings.double_click_mode.split(".")
- opgrp = getattr(bpy.ops, op[0])
+ def execute(self, context):
+ prefs = preferences()
+ op = prefs.right_click_mode.split(".")
if op[1] == "transfer_mode" and context.area.type != "VIEW_3D":
return PASSTHROUGH
if op[1] == "transfer_mode" and context.mode == "OBJECT":
bpy.ops.view3d.select("INVOKE_DEFAULT") # type: ignore
return PASSTHROUGH
+ opgrp = getattr(bpy.ops, op[0])
getattr(opgrp, op[1])("INVOKE_DEFAULT")
return FINISHED
- def invoke(self, context: Context, event: Event):
+
+class TOUCHVIEW_OT_double_click_action(Operator):
+ """Viewport double-tap shortcut"""
+
+ bl_label = "Viewport double-tap shortcut"
+ bl_idname = "touchview.dt_action"
+
+ @classmethod
+ def poll(cls, context):
+ return context.area.type in {"NODE_EDITOR", "VIEW_2D", "VIEW_3D", "IMAGE_EDITOR"} and context.region.type == "WINDOW"
+
+ def invoke(self, context, event):
if event.type not in [PEN, LMOUSE]:
return PASSTHROUGH
- if not isTouch(event):
+ if not is_touch(event):
return PASSTHROUGH
if event.value != "DOUBLE_CLICK":
return PASSTHROUGH
return self.execute(context)
- @classmethod
- def poll(cls, context: Context):
- return (
- context.area.type in ["NODE_EDITOR", "VIEW_2D", "VIEW_3D", "IMAGE_EDITOR"]
- and context.region.type == "WINDOW"
- )
+ def execute(self, context):
+ prefs = preferences()
+ if not prefs.enable_double_click:
+ return PASSTHROUGH
+ op = prefs.double_click_mode.split(".")
+ opgrp = getattr(bpy.ops, op[0])
+ if op[1] == "transfer_mode" and context.area.type != "VIEW_3D":
+ return PASSTHROUGH
+ if op[1] == "transfer_mode" and context.mode == "OBJECT":
+ bpy.ops.view3d.select("INVOKE_DEFAULT") # type: ignore
+ return PASSTHROUGH
+ getattr(opgrp, op[1])("INVOKE_DEFAULT")
+ return FINISHED
-class VIEW2D_OT_TouchInput(Operator):
+class TOUCHVIEW_OT_touch_input_2d(Operator):
"""Active Viewport control zones"""
- bl_idname = "nendo.view_ops_2d"
bl_label = "2D Viewport Control Regions"
+ bl_idname = "touchview.view_ops_2d"
delta: tuple[float, float]
@@ -110,25 +104,13 @@ class VIEW2D_OT_TouchInput(Operator):
options={"HIDDEN"},
)
- def execute(self, context: Context):
- if context.area.type == "IMAGE_EDITOR":
- return self.exec_image_editor(context)
- if self.mode == "DOLLY":
- bpy.ops.view2d.zoom("INVOKE_DEFAULT") # type: ignore
- elif self.mode == "PAN":
- bpy.ops.view2d.pan("INVOKE_DEFAULT") # type: ignore
- return FINISHED
-
- def exec_image_editor(self, _: Context):
- if self.mode == "PAN":
- bpy.ops.image.view_pan("INVOKE_DEFAULT") # type: ignore
- elif self.mode == "DOLLY":
- bpy.ops.image.view_zoom("INVOKE_DEFAULT") # type: ignore
- return FINISHED
+ @classmethod
+ def poll(cls, context):
+ return context.area.type in {"NODE_EDITOR", "VIEW_2D", "IMAGE_EDITOR"} and context.region.type == "WINDOW"
- def invoke(self, context: Context, event: Event):
- settings = get_settings()
- if not settings.is_enabled:
+ def invoke(self, context, event):
+ prefs = preferences()
+ if not prefs.is_enabled:
return PASSTHROUGH
if settings.input_mode == "full" and (event.type == PEN or not isTouch(event)):
return PASSTHROUGH
@@ -139,18 +121,15 @@ def invoke(self, context: Context, event: Event):
mid_point = Vector((context.region.width / 2, context.region.height / 2))
- dolly_scale = settings.getWidth()
+ dolly_scale = prefs.getWidth()
dolly_wid = mid_point.x * dolly_scale
- if (
- dolly_wid > self.delta[0]
- or self.delta[0] > context.region.width - dolly_wid
- ):
+ if dolly_wid > self.delta[0] or self.delta[0] > context.region.width - dolly_wid:
self.mode = "DOLLY"
else:
self.mode = "PAN"
- if settings.swap_panrotate:
+ if prefs.swap_panrotate:
if self.mode == "PAN":
self.mode = "ORBIT"
elif self.mode == "ORBIT":
@@ -159,19 +138,28 @@ def invoke(self, context: Context, event: Event):
self.execute(context)
return FINISHED
- @classmethod
- def poll(cls, context: Context):
- return (
- context.area.type in ["NODE_EDITOR", "VIEW_2D", "IMAGE_EDITOR"]
- and context.region.type == "WINDOW"
- )
+ def execute(self, context):
+ if context.area.type == "IMAGE_EDITOR":
+ return self.exec_image_editor(context)
+ if self.mode == "DOLLY":
+ bpy.ops.view2d.zoom("INVOKE_DEFAULT") # type: ignore
+ elif self.mode == "PAN":
+ bpy.ops.view2d.pan("INVOKE_DEFAULT") # type: ignore
+ return FINISHED
+ def exec_image_editor(self, context):
+ if self.mode == "PAN":
+ bpy.ops.image.view_pan("INVOKE_DEFAULT") # type: ignore
+ elif self.mode == "DOLLY":
+ bpy.ops.image.view_zoom("INVOKE_DEFAULT") # type: ignore
+ return FINISHED
-class VIEW3D_OT_TouchInput(Operator):
+
+class TOUCHVIEW_OT_touch_input_3d(Operator):
"""Active Viewport control zones"""
- bl_idname = "nendo.view_ops_3d"
bl_label = "Viewport Control Regions"
+ bl_idname = "touchview.view_ops_3d"
delta: tuple[float, float]
@@ -179,48 +167,16 @@ class VIEW3D_OT_TouchInput(Operator):
name="Mode",
description="Sets the viewport control type",
items=input_mode_items,
- default="ORBIT",
options={"HIDDEN"},
+ default="ORBIT",
)
- def execute(self, context: Context):
- if self.mode == "DOLLY":
- ops.view3d.zoom("INVOKE_DEFAULT") # type: ignore
- elif self.mode == "ORBIT":
- if context.mode == "SCULPT":
- ops.sculpt.set_pivot_position(
- mode="SURFACE", mouse_x=self.delta[0], mouse_y=self.delta[1]
- )
- ops.view3d.rotate("INVOKE_DEFAULT") # type: ignore
- elif self.mode == "PAN":
- bpy.ops.view3d.move("INVOKE_DEFAULT") # type: ignore
- return FINISHED
-
- def should_pass(self, context: Context, event: Event):
- settings = get_settings()
-
- # experimental passthrough in drawing mode
- if (
- settings.lazy_mode
- and not settings.is_enabled
- and event.value == PRESS
- and brush_modes.__contains__(context.mode)
- and self.mouseTarget(context, event) != context.active_object
- ):
- return False
-
- if not settings.is_enabled:
- return True
-
- if settings.input_mode == "full" and (event.type == PEN or not isTouch(event)):
- return True
-
- if event.value != PRESS:
- return True
- return False
+ @classmethod
+ def poll(cls, context):
+ return context.area.type == "VIEW_3D" and context.region.type == "WINDOW"
- def invoke(self, context: Context, event: Event):
- settings = get_settings()
+ def invoke(self, context, event):
+ prefs = preferences()
passcheck = self.should_pass(context, event)
if passcheck:
return PASSTHROUGH
@@ -229,8 +185,8 @@ def invoke(self, context: Context, event: Event):
mid_point = Vector((context.region.width / 2, context.region.height / 2))
- dolly_scale = settings.getWidth()
- pan_scale = settings.getRadius()
+ dolly_scale = prefs.getWidth()
+ pan_scale = prefs.getRadius()
dolly_wid = mid_point.x * dolly_scale
pan_diameter = math.dist(
@@ -238,16 +194,10 @@ def invoke(self, context: Context, event: Event):
mid_point, # type: ignore
) * (pan_scale * 0.5)
- is_quadview_orthographic = (
- context.region_data.is_orthographic_side_view
- and context.region.alignment == "QUAD_SPLIT"
- )
+ is_quadview_orthographic = context.region_data.is_orthographic_side_view and context.region.alignment == "QUAD_SPLIT"
is_locked = context.region_data.lock_rotation or is_quadview_orthographic
- if (
- dolly_wid > self.delta[0]
- or self.delta[0] > context.region.width - dolly_wid
- ):
+ if dolly_wid > self.delta[0] or self.delta[0] > context.region.width - dolly_wid:
self.mode = "DOLLY"
elif (
math.dist(
@@ -261,31 +211,65 @@ def invoke(self, context: Context, event: Event):
else:
self.mode = "ORBIT"
- if settings.swap_panrotate and not is_locked:
+ if prefs.swap_panrotate and not is_locked:
if self.mode == "PAN":
self.mode = "ORBIT"
elif self.mode == "ORBIT":
self.mode = "PAN"
if context.mode == "SCULPT":
- bpy.ops.sculpt.set_pivot_position(mode=settings.pivot_mode)
+ bpy.ops.sculpt.set_pivot_position(mode=prefs.pivot_mode)
self.execute(context)
return FINISHED
- def mouseTarget(self, context: Context, event: Event):
+ def execute(self, context):
+ if self.mode == "DOLLY":
+ bpy.ops.view3d.zoom("INVOKE_DEFAULT") # type: ignore
+ elif self.mode == "ORBIT":
+ if context.mode == "SCULPT":
+ bpy.ops.sculpt.set_pivot_position(mode="SURFACE", mouse_x=self.delta[0], mouse_y=self.delta[1])
+ bpy.ops.view3d.rotate("INVOKE_DEFAULT") # type: ignore
+ elif self.mode == "PAN":
+ bpy.ops.view3d.move("INVOKE_DEFAULT") # type: ignore
+ return FINISHED
+
+ def should_pass(self, context, event):
+ prefs = preferences()
+
+ # experimental passthrough in drawing mode
+ if (
+ prefs.lazy_mode
+ and not prefs.is_enabled
+ and event.value == PRESS
+ and brush_modes.__contains__(context.mode)
+ and self.mouseTarget(context, event) != context.active_object
+ ):
+ return False
+
+ if not prefs.is_enabled:
+ return True
+
+ if prefs.input_mode == "FULL" and (event.type == PEN or not is_touch(event)):
+ return True
+
+ if event.value != PRESS:
+ return True
+ return False
+
+ def mouseTarget(self, context, event):
# get the context arguments
region = context.region
rv3d = context.region_data
coord = Vector((event.mouse_region_x, event.mouse_region_y))
# get the ray from the viewport and mouse
- view_vector = view3d_utils.region_2d_to_vector_3d(region, rv3d, coord)
- self.ray_origin = view3d_utils.region_2d_to_origin_3d(region, rv3d, coord)
+ view_vector = region_2d_to_vector_3d(region, rv3d, coord)
+ self.ray_origin = region_2d_to_origin_3d(region, rv3d, coord)
self.ray_target = self.ray_origin + view_vector
return self.isCurrentObject(context)
- def visible_objects_and_duplis(self, context: Context):
+ def visible_objects_and_duplicates(self, context):
depsgraph = context.evaluated_depsgraph_get()
for dup in depsgraph.object_instances:
if dup.is_instance: # Real dupli instance
@@ -303,21 +287,19 @@ def obj_ray_cast(self, obj, matrix):
ray_direction_obj = ray_target_obj - ray_origin_obj
# cast the ray
- success, location, normal, face_index = obj.ray_cast(
- ray_origin_obj, ray_direction_obj
- )
+ success, location, normal, face_index = obj.ray_cast(ray_origin_obj, ray_direction_obj)
if success:
return location, normal, face_index
else:
return None, None, None
- def isCurrentObject(self, context: Context):
+ def isCurrentObject(self, context):
# cast rays and find the closest object
best_length_squared = -1.0
best_obj = None
- for obj, matrix in self.visible_objects_and_duplis(context):
+ for obj, matrix in self.visible_objects_and_duplicates(context):
if obj.type == "MESH":
hit, _, _ = self.obj_ray_cast(obj, matrix)
if hit is not None:
@@ -329,6 +311,13 @@ def isCurrentObject(self, context: Context):
return best_obj.original if best_obj is not None else None
- @classmethod
- def poll(cls, context: Context):
- return context.area.type == "VIEW_3D" and context.region.type == "WINDOW"
+
+classes = (
+ TOUCHVIEW_OT_right_click_action,
+ TOUCHVIEW_OT_double_click_action,
+ TOUCHVIEW_OT_touch_input_2d,
+ TOUCHVIEW_OT_touch_input_3d,
+)
+
+
+register, unregister = bpy.utils.register_classes_factory(classes)
diff --git a/lib/ui_gizmo/__init__.py b/source/ui/__init__.py
similarity index 50%
rename from lib/ui_gizmo/__init__.py
rename to source/ui/__init__.py
index 166c3f2..4160036 100644
--- a/lib/ui_gizmo/__init__.py
+++ b/source/ui/__init__.py
@@ -6,16 +6,14 @@
# layout (vertical, horizontal, etc)
# to be managed through inheritance.
###
-from .gizmo_group_2d import GIZMO_GT_ViewportGizmoGroup
-
-__classes__ = (GIZMO_GT_ViewportGizmoGroup)
+from . import gizmo_group_2d, panel
def register():
- from bpy.utils import register_class
- register_class(GIZMO_GT_ViewportGizmoGroup)
+ gizmo_group_2d.register()
+ panel.register()
def unregister():
- from bpy.utils import unregister_class
- unregister_class(GIZMO_GT_ViewportGizmoGroup)
+ gizmo_group_2d.unregister()
+ panel.unregister()
diff --git a/source/ui/gizmo_2d.py b/source/ui/gizmo_2d.py
new file mode 100644
index 0000000..d7017a5
--- /dev/null
+++ b/source/ui/gizmo_2d.py
@@ -0,0 +1,190 @@
+import bpy
+from mathutils import Matrix, Vector
+
+from ..utils.blender import *
+from .gizmo_config import gizmo_colors, toggle_colors
+
+##
+# GizmoSet
+# - single-state
+# - one icon
+# - one action
+# - possible toggle by variable state
+#
+# - 2-state (boolean)
+# - 2 icons
+# - 2 actions (or 1 action for both icons)
+#
+##
+
+
+class GizmoSet:
+ group: bpy.types.GizmoGroup
+
+ def setup(self, group: bpy.types.GizmoGroup, config: dict):
+ self.visible = True
+ self.config = config
+ self.has_dependent = "has_dependent" in config or False
+ self.group = group
+ self.scale = config["scale"] if ("scale" in config) else 14
+ self.binding = config["binding"]
+ self.has_attribute_bind = self.binding["attribute"] if "attribute" in self.binding else False
+ self.primary = self.__buildGizmo(config["command"], config["icon"])
+
+ def draw_prepare(self):
+ prefs = preferences()
+ self.hidden = not prefs.show_gizmos
+ self.skip_draw = False
+ self.__updatevisible()
+
+ if self.binding["name"] == "float_menu":
+ self.primary.hide = not prefs.show_float_menu
+ self.primary.use_grab_cursor = False
+ if self.binding["name"] in {"menu_controller"}:
+ self.primary.hide = "float" not in prefs.menu_style or not prefs.show_menu
+ self.primary.use_grab_cursor = False
+ self.primary.show_drag = True
+ if self.binding["name"] in {"menu_controller"}:
+ self.primary.scale_basis = (36 * prefs.menu_spacing) * prefs.gizmo_scale
+ self.primary.use_grab_cursor = False
+ self.primary.show_drag = True
+ else:
+ self.primary.scale_basis = 18 * prefs.gizmo_scale
+
+ def move(self, position: Vector):
+ self.primary.matrix_basis = Matrix.Translation(position)
+
+ def __updatevisible(self):
+ if not preferences().show_menu and self.binding["name"] not in ["float_menu"]:
+ self.visible = False
+ self.primary.hide = True
+ return
+ if self.binding["location"] == "prefs":
+ self.visible = getattr(preferences(), "show_" + self.binding["name"]) and self.binding["name"] in preferences().getGizmoSet(
+ bpy.context.mode
+ )
+
+ if self.visible:
+ self.visible = self.__visibilityLock() and not self.__checkAttributeBind()
+ self.primary.hide = not self.visible
+
+ def __visibilityLock(self) -> bool:
+ if preferences().menu_style == "fixed.bar":
+ return True
+ return not self.hidden
+
+ # if an attribute being assigned to active_object should hide/show bpy.types.Gizmo
+ def __checkAttributeBind(self):
+ if not self.has_attribute_bind:
+ return False
+ bind = self.binding["attribute"]
+ state = self.__findAttribute(bind["path"], bind["value"]) == bind["state"]
+ return not state
+
+ # search for attribute, value through context.
+ # will traverse bpy.types.bpy_prop_collection entries
+ # by next attr to value comparison
+ def __findAttribute(self, path: str, value: str):
+ names = path.split(".")
+ current = bpy.context
+ for i, prop in enumerate(names):
+ current = getattr(current, prop)
+ if current is None:
+ return False
+
+ if isinstance(current, bpy.types.bpy_prop_collection):
+ item = ""
+ for item in current:
+ if getattr(item, names[i + 1]) == value:
+ return True
+ return False
+ return getattr(current, value)
+
+ # initialize each gizmo, add them to named list with icon name(s)
+ def __buildGizmo(self, command: str, icon: str) -> bpy.types.Gizmo:
+ gizmo = self.group.gizmos.new("GIZMO_GT_button_2d")
+ gizmo.target_set_operator(command)
+ gizmo.icon = icon # type: ignore
+ gizmo.use_tooltip = False # show tooltip
+ gizmo.use_event_handle_all = True # don't pass events e.g. shift+a to add
+ gizmo.use_grab_cursor = "use_grab_cursor" in self.config
+ gizmo.show_drag = False # show default cursor
+ gizmo.line_width = 5.0
+ gizmo.use_draw_modal = True # show gizmo while dragging
+ gizmo.draw_options = {"BACKDROP", "OUTLINE"} # type: ignore
+ self.__setColors(gizmo)
+ gizmo.scale_basis = 0.1
+ return gizmo
+
+ def __setColors(self, gizmo: bpy.types.Gizmo):
+ gizmo.color = gizmo_colors["active"]["color"]
+ gizmo.color_highlight = gizmo_colors["active"]["color_highlight"]
+ gizmo.alpha = gizmo_colors["active"]["alpha"]
+ gizmo.alpha_highlight = gizmo_colors["active"]["alpha_highlight"]
+
+
+class GizmoSetBoolean(GizmoSet):
+ def setup(self, group: bpy.types.GizmoGroup, config: dict):
+ self.visible = True
+ self.config = config
+ self.has_dependent = "has_dependent" in config or False
+ self.group = group
+ self.scale = config["scale"] if ("scale" in config) else 14
+ self.binding = config["binding"]
+ self.has_attribute_bind = self.binding["attribute"] if "attribute" in self.binding else False
+ self.onGizmo = self._GizmoSet__buildGizmo(config["command"], config["onIcon"]) # type: ignore
+ self.offGizmo = self._GizmoSet__buildGizmo(config["command"], config["offIcon"]) # type: ignore
+ self.__setActiveGizmo(True)
+
+ def __setActiveGizmo(self, state: bool):
+ self.onGizmo.hide = True
+ self.offGizmo.hide = True
+ self.primary = self.onGizmo if state else self.offGizmo
+
+ def draw_prepare(self):
+ prefs = preferences()
+ self.hidden = not prefs.show_gizmos
+ self.skip_draw = False
+ self.__updatevisible()
+ self.primary.scale_basis = 18 * prefs.gizmo_scale
+ self.primary.use_grab_cursor = False
+ if self.binding["name"] == "float_toggle":
+ self.__setToggleColors(self.primary)
+
+ def __updatevisible(self):
+ prefs = preferences()
+ bind = self.binding
+ if not preferences().show_menu and (bind["name"] not in ["float_menu"]):
+ self.visible = False
+ self.primary.hide = True
+ return
+ if bind["name"] == "float_toggle":
+ self.visible = prefs.input_mode != "FULL" or prefs.enable_floating_toggle
+ else:
+ self.visible = getattr(preferences(), "show_" + self.binding["name"])
+
+ if self.visible:
+ self.visible = (
+ self._GizmoSet__visibilityLock() # type: ignore
+ and not self._GizmoSet__checkAttributeBind() # type: ignore
+ ) # type: ignore
+
+ if bind["name"] == "float_toggle":
+ self.__setActiveGizmo(prefs.is_enabled)
+ else:
+ self.__setActiveGizmo(self._GizmoSet__findAttribute(bind["location"], bind["name"])) # type: ignore
+ self.primary.hide = not self.visible
+
+ def __setToggleColors(self, gizmo: bpy.types.Gizmo):
+ mode = "active" if preferences().is_enabled else "inactive"
+ gizmo.color = toggle_colors[mode]["color"]
+ gizmo.color_highlight = toggle_colors[mode]["color_highlight"]
+ gizmo.alpha = toggle_colors[mode]["alpha"]
+ gizmo.alpha_highlight = toggle_colors[mode]["alpha_highlight"]
+
+
+class GizmoSetEnum(GizmoSet):
+ gizmos: list[bpy.types.Gizmo]
+
+ def setup(self, group: bpy.types.GizmoGroup, config):
+ pass
diff --git a/lib/ui_gizmo/gizmo_config.py b/source/ui/gizmo_config.py
similarity index 89%
rename from lib/ui_gizmo/gizmo_config.py
rename to source/ui/gizmo_config.py
index e7d39b2..821e2e9 100644
--- a/lib/ui_gizmo/gizmo_config.py
+++ b/source/ui/gizmo_config.py
@@ -1,4 +1,4 @@
-from ..constants import pivot_icon_items
+from ..utils.constants import pivot_icon_items
###
# Config Standard
@@ -13,7 +13,7 @@
controllerConfig = {
"type": "default",
"binding": {"location": "", "name": "menu_controller"},
- "command": "nendo.move_float_menu",
+ "command": "touchview.move_float_menu",
"icon": "BLANK1",
"use_grab_cursor": True,
}
@@ -21,7 +21,7 @@
floatingConfig = {
"type": "default",
"binding": {"location": "prefs", "name": "float_menu"},
- "command": "nendo.move_action_menu",
+ "command": "touchview.move_action_menu",
"icon": "SETTINGS",
"use_grab_cursor": True,
}
@@ -29,7 +29,7 @@
floatingToggleConfig = {
"type": "boolean",
"binding": {"location": "", "name": "float_toggle"},
- "command": "nendo.move_toggle_button",
+ "command": "touchview.move_toggle_button",
"onIcon": "OUTLINER_DATA_CAMERA",
"offIcon": "GREASEPENCIL",
"use_grab_cursor": True,
@@ -56,7 +56,7 @@
"location": "prefs",
"name": "is_enabled",
},
- "command": "nendo.toggle_touch",
+ "command": "touchview.toggle_touch",
"icon": "VIEW_PAN",
}
@@ -66,21 +66,21 @@
"location": "prefs",
"name": "control_gizmo",
},
- "command": "nendo.cycle_control_gizmo",
+ "command": "touchview.cycle_control_gizmo",
"icon": "ORIENTATION_LOCAL",
}
snapViewConfig = {
"type": "default",
"binding": {"location": "prefs", "name": "snap_view"},
- "command": "nendo.viewport_recenter",
+ "command": "touchview.viewport_recenter",
"icon": "CURSOR",
}
nPanelConfig = {
"type": "default",
"binding": {"location": "prefs", "name": "n_panel"},
- "command": "nendo.toggle_n_panel",
+ "command": "touchview.toggle_n_panel",
"icon": "EVENT_N",
}
@@ -125,7 +125,7 @@
"state": False,
},
},
- "command": "nendo.density_down",
+ "command": "touchview.density_down",
"icon": "TRIA_DOWN",
}
@@ -140,7 +140,7 @@
"state": False,
},
},
- "command": "nendo.density_up",
+ "command": "touchview.density_up",
"icon": "TRIA_UP",
}
@@ -156,7 +156,7 @@
},
},
"has_dependent": True,
- "command": "nendo.increment_multires",
+ "command": "touchview.increment_multires",
"icon": "TRIA_UP",
}
@@ -171,21 +171,21 @@
"state": True,
},
},
- "command": "nendo.decrement_multires",
+ "command": "touchview.decrement_multires",
"icon": "TRIA_DOWN",
}
brushResizeConfig = {
"type": "default",
"binding": {"location": "prefs", "name": "brush_dynamics"},
- "command": "nendo.brush_resize",
+ "command": "touchview.brush_resize",
"icon": "ANTIALIASED",
}
brushStrengthConfig = {
"type": "default",
"binding": {"location": "prefs", "name": "brush_dynamics"},
- "command": "nendo.brush_strength",
+ "command": "touchview.brush_strength",
"icon": "SMOOTHCURVE",
}
@@ -212,7 +212,7 @@
rotLocToggleConfig = {
"type": "boolean",
"binding": {"location": "region_data", "name": "lock_rotation"},
- "command": "nendo.viewport_lock",
+ "command": "touchview.viewport_lock",
"onIcon": "LOCKED",
"offIcon": "UNLOCKED",
}
diff --git a/lib/ui_gizmo/gizmo_group_2d.py b/source/ui/gizmo_group_2d.py
similarity index 56%
rename from lib/ui_gizmo/gizmo_group_2d.py
rename to source/ui/gizmo_group_2d.py
index 67d564d..0948d7e 100644
--- a/lib/ui_gizmo/gizmo_group_2d.py
+++ b/source/ui/gizmo_group_2d.py
@@ -1,9 +1,10 @@
from math import cos, radians, sin
-from bpy.types import Context, GizmoGroup
+import bpy
+from bpy.types import GizmoGroup
from mathutils import Vector
-from ..utils import buildSafeArea, dpi_factor, get_settings
+from ..utils.blender import *
from .gizmo_2d import GizmoSet, GizmoSetBoolean
from .gizmo_config import (brushResizeConfig, brushStrengthConfig,
controlGizmoConfig, controllerConfig,
@@ -53,24 +54,23 @@
# - holds reference to Gizmos for related action
# - position applied to references
# - hold state to determine what icons,actions to provide
-# - applies color and visibility based on settings
+# - applies color and visibility based on prefs
#
###
-class GIZMO_GT_ViewportGizmoGroup(GizmoGroup):
- bl_idname = "GIZMO_GT_touch_tools"
+class GIZMO_GT_viewport_gizmo_group(GizmoGroup):
bl_label = "Fast access tools for touch viewport"
bl_space_type = "VIEW_3D"
bl_region_type = "WINDOW"
bl_options = {"PERSISTENT", "SCALE"}
# set up gizmo collection
- def setup(self, context: Context):
+ def setup(self, context):
self.gizmo_2d_sets = []
self.__buildController(context)
- settings = get_settings()
- self.spacing = settings.menu_spacing
+ prefs = preferences()
+ self.spacing = prefs.menu_spacing
for conf in configs:
if conf["type"] == "boolean":
gizmo = GizmoSetBoolean()
@@ -80,7 +80,7 @@ def setup(self, context: Context):
gizmo.setup(self, conf)
self.gizmo_2d_sets.append(gizmo)
- def __buildController(self, _: Context):
+ def __buildController(self, context):
self.controller = GizmoSet()
self.controller.setup(self, controllerConfig)
self.action_menu = GizmoSet()
@@ -88,9 +88,9 @@ def __buildController(self, _: Context):
self.toggle = GizmoSetBoolean()
self.toggle.setup(self, floatingToggleConfig)
- def draw_prepare(self, context: Context):
+ def draw_prepare(self, context):
self.context = context
- settings = get_settings()
+ prefs = preferences()
self.__updateOrigin()
self.__updateActionOrigin()
self.__updateToggleOrigin()
@@ -107,58 +107,53 @@ def draw_prepare(self, context: Context):
if gizmo.visible:
visible_gizmos.append(gizmo)
- if settings.menu_style == "float.radial":
+ if prefs.menu_style == "float.radial":
self.__menuRadial(visible_gizmos)
- if settings.menu_style == "fixed.bar":
+ if prefs.menu_style == "fixed.bar":
self.__menuBar(visible_gizmos)
def __menuBar(self, visible_gizmos: list[GizmoSet]):
- settings = get_settings()
+ prefs = preferences()
origin = self.origin
- scalar = 22 * dpi_factor()
count = len(visible_gizmos)
- safe_area = buildSafeArea()
- origin = Vector((
- (safe_area[0].x + safe_area[1].x) / 2,
- (safe_area[0].y + safe_area[1].y) / 2,
- 0.0,
- ))
-
- if settings.gizmo_position == "TOP":
+ safe_area = safe_area_3d()
+ origin = Vector(
+ (
+ (safe_area[0].x + safe_area[1].x) / 2,
+ (safe_area[0].y + safe_area[1].y) / 2,
+ 0.0,
+ )
+ )
+
+ if prefs.gizmo_position == "TOP":
origin.y = safe_area[1].y
- elif settings.gizmo_position == "BOTTOM":
+ elif prefs.gizmo_position == "BOTTOM":
origin.y = safe_area[0].y
- else:
- if settings.gizmo_position == "LEFT":
- origin.x = safe_area[0].x
- elif settings.gizmo_position == "RIGHT":
- origin.x = safe_area[1].x
-
- gizmo_spacing = settings.menu_spacing + scalar
- if (
- settings.gizmo_position in ["TOP", "BOTTOM"]
- and settings.menu_style == "fixed.bar"
- ):
- start = origin.x - ((count - 1) * gizmo_spacing) / 2
+ elif prefs.gizmo_position == "LEFT":
+ origin.x = safe_area[0].x
+ elif prefs.gizmo_position == "RIGHT":
+ origin.x = safe_area[1].x # - 54 # to avoid overlapping
+
+ gizmo_scale = (36 * prefs.gizmo_scale) + prefs.gizmo_padding
+ gizmo_padding = prefs.gizmo_padding
+ spacing = (gizmo_scale + gizmo_padding) * ui_scale()
+
+ if prefs.gizmo_position in {"TOP", "BOTTOM"} and prefs.menu_style == "fixed.bar":
+ start = origin.x - ((count - 1) * spacing) / 2
for i, gizmo in enumerate(visible_gizmos):
- self.__move_gizmo(
- gizmo, Vector((start + (i * gizmo_spacing), origin.y, 0.0))
- )
+ self.__move_gizmo(gizmo, Vector((start + (i * spacing), origin.y, 0.0)))
else:
- start = origin.y + (count * gizmo_spacing) / 2
+ start = origin.y + (count * spacing) / 2
for i, gizmo in enumerate(visible_gizmos):
- self.__move_gizmo(
- gizmo, Vector((origin.x, start - (i * gizmo_spacing), 0.0))
- )
+ self.__move_gizmo(gizmo, Vector((origin.x, start - (i * spacing), 0.0)))
def __menuRadial(self, visible_gizmos: list[GizmoSet]):
- settings = get_settings()
+ prefs = preferences()
# calculate minimum radius to prevent overlapping buttons
- gui_scale = dpi_factor() * 3
- radial_size = gui_scale + settings.menu_spacing
- spacing = (
- radial_size + (gui_scale * settings.gizmo_scale) + settings.gizmo_padding
- )
+ menu_spacing = (36 * prefs.menu_spacing) * prefs.gizmo_scale + prefs.gizmo_padding
+ gizmo_scale = 18 * prefs.gizmo_scale
+ gizmo_padding = prefs.gizmo_padding
+ spacing = (menu_spacing + gizmo_scale + gizmo_padding) * ui_scale()
count = len(visible_gizmos)
# reposition Gizmos to origin
@@ -175,63 +170,83 @@ def __menuRadial(self, visible_gizmos: list[GizmoSet]):
def __calcMove(self, gizmo: GizmoSet, step: int, size: int, spacing: float):
distance = step / size
- offset = Vector((
- sin(radians(distance * 360)),
- cos(radians(distance * 360)),
- 0.0,
- ))
+ offset = Vector(
+ (
+ sin(radians(distance * 360)),
+ cos(radians(distance * 360)),
+ 0.0,
+ )
+ )
self.__move_gizmo(gizmo, self.origin + offset * spacing)
def __updateOrigin(self):
- safe_area = buildSafeArea()
- settings = get_settings()
+ prefs = preferences()
+ safe_area = safe_area_3d(padding=90)
# distance across viewport between menus
- span = Vector((
- safe_area[1].x - safe_area[0].x,
- safe_area[1].y - safe_area[0].y,
- ))
+ span = Vector(
+ (
+ safe_area[1].x - safe_area[0].x,
+ safe_area[1].y - safe_area[0].y,
+ )
+ )
# apply position ratio to safe area
- self.origin = Vector((
- safe_area[0].x + span.x * settings.menu_position[0] * 0.01,
- safe_area[0].y + span.y * settings.menu_position[1] * 0.01,
- 0.0,
- ))
+ self.origin = Vector(
+ (
+ safe_area[0].x + span.x * prefs.menu_position[0] * 0.01,
+ safe_area[0].y + span.y * prefs.menu_position[1] * 0.01,
+ 0.0,
+ )
+ )
def __updateActionOrigin(self):
- safe_area = buildSafeArea()
- settings = get_settings()
+ prefs = preferences()
+ safe_area = safe_area_3d()
# distance across viewport between menus
- span = Vector((
- safe_area[1].x - safe_area[0].x,
- safe_area[1].y - safe_area[0].y,
- ))
+ span = Vector(
+ (
+ safe_area[1].x - safe_area[0].x,
+ safe_area[1].y - safe_area[0].y,
+ )
+ )
# apply position ratio to safe area
- self.action_origin = Vector((
- safe_area[0].x + span.x * settings.floating_position[0] * 0.01,
- safe_area[0].y + span.y * settings.floating_position[1] * 0.01,
- 0.0,
- ))
+ self.action_origin = Vector(
+ (
+ safe_area[0].x + span.x * prefs.floating_position[0] * 0.01,
+ safe_area[0].y + span.y * prefs.floating_position[1] * 0.01,
+ 0.0,
+ )
+ )
def __updateToggleOrigin(self):
- safe_area = buildSafeArea()
- settings = get_settings()
+ prefs = preferences()
+ safe_area = safe_area_3d()
# distance across viewport between menus
- span = Vector((
- safe_area[1].x - safe_area[0].x,
- safe_area[1].y - safe_area[0].y,
- ))
+ span = Vector(
+ (
+ safe_area[1].x - safe_area[0].x,
+ safe_area[1].y - safe_area[0].y,
+ )
+ )
# apply position ratio to safe area
- self.toggle_origin = Vector((
- safe_area[0].x + span.x * settings.toggle_position[0] * 0.01,
- safe_area[0].y + span.y * settings.toggle_position[1] * 0.01,
- 0.0,
- ))
+ self.toggle_origin = Vector(
+ (
+ safe_area[0].x + span.x * prefs.toggle_position[0] * 0.01,
+ safe_area[0].y + span.y * prefs.toggle_position[1] * 0.01,
+ 0.0,
+ )
+ )
def __move_gizmo(self, gizmo: GizmoSet, position: Vector):
gizmo.move(position)
+
+
+classes = (GIZMO_GT_viewport_gizmo_group,)
+
+
+register, unregister = bpy.utils.register_classes_factory(classes)
diff --git a/source/ui/panel.py b/source/ui/panel.py
new file mode 100644
index 0000000..6ff900c
--- /dev/null
+++ b/source/ui/panel.py
@@ -0,0 +1,299 @@
+# type: ignore
+import bpy
+from bpy.types import Menu, Panel, UILayout
+
+from ..utils.blender import preferences
+
+
+class TouchView:
+ bl_label = "Touchview Settings"
+ bl_space_type = "VIEW_3D"
+ bl_region_type = "UI"
+ bl_category = "Touchview"
+
+
+class TOUCHVIEW_PT_view_3d_panel(TouchView, Panel):
+ # bl_label = "Touchview Settings"
+
+ def draw(self, context):
+ prefs = preferences()
+
+ layout = self.layout
+ layout.use_property_decorate = False
+
+ box = layout.box()
+ box.label(
+ text=UILayout.enum_item_description(prefs, "input_mode", prefs.input_mode),
+ icon_value=UILayout.enum_item_icon(prefs, "input_mode", prefs.input_mode),
+ )
+
+ row = box.row()
+ row.prop(prefs, "input_mode", expand=True)
+
+ col = box.column(align=True)
+ col.use_property_split = True
+ col.prop(prefs, "lazy_mode")
+ if prefs.input_mode == "FULL":
+ col.prop(prefs, "enable_floating_toggle")
+
+
+class TOUCHVIEW_PT_ControlZones(TouchView, Panel):
+ bl_label = "Control Zones"
+ bl_parent_id = "TOUCHVIEW_PT_view_3d_panel"
+
+ def draw_header(self, context):
+ prefs = preferences()
+
+ layout = self.layout
+ layout.use_property_decorate = False
+
+ layout.prop(prefs, "is_enabled", text="")
+
+ def draw(self, context):
+ layout = self.layout
+ layout.use_property_decorate = False
+
+ prefs = preferences()
+
+ layout.active = prefs.is_enabled
+
+ row = layout.row()
+ row.prop(prefs, "header_toggle_position", expand=True)
+
+ layout.use_property_split = True
+
+ col = layout.column(align=True)
+ col.prop(prefs, "isVisible", text="Show Overlay")
+ col.prop(prefs, "swap_panrotate")
+ col.prop(prefs, "use_multiple_colors")
+
+ col = layout.column()
+ col.prop(prefs, "overlay_main_color", text="Main Color")
+ if prefs.use_multiple_colors:
+ col.prop(prefs, "overlay_secondary_color", text="Secondary Color")
+ col.prop(prefs, "width", slider=True)
+ col.prop(prefs, "radius", slider=True)
+
+
+class TOUCHVIEW_PT_gizmo_bar(TouchView, Panel):
+ bl_label = "Gizmo"
+ bl_parent_id = "TOUCHVIEW_PT_view_3d_panel"
+
+ def draw(self, context):
+ prefs = preferences()
+
+ layout = self.layout
+ layout.use_property_decorate = False
+ layout.use_property_split = True
+
+ col = layout.column()
+ col.prop(prefs, "menu_style", expand=True)
+
+ if prefs.menu_style == "fixed.bar":
+ col.prop(prefs, "gizmo_position")
+ elif prefs.menu_style == "float.radial":
+ col.prop(prefs, "menu_spacing", slider=True)
+
+ col.prop(prefs, "gizmo_scale", slider=True)
+ col.prop(prefs, "gizmo_padding", slider=True)
+
+
+class TOUCHVIEW_PT_right_click(TouchView, Panel):
+ bl_label = "Right Click Actions"
+ bl_parent_id = "TOUCHVIEW_PT_view_3d_panel"
+
+ def draw(self, context):
+ prefs = preferences()
+
+ layout = self.layout
+ layout.use_property_decorate = False
+ layout.use_property_split = True
+
+ col = layout.column()
+ col.prop(prefs, "right_click_source", text="Source", expand=True)
+ col.prop(prefs, "right_click_mode", text="Mode", expand=True)
+
+
+class TOUCHVIEW_PT_double_click(TouchView, Panel):
+ bl_label = "Double Click Actions"
+ bl_parent_id = "TOUCHVIEW_PT_view_3d_panel"
+
+ def draw(self, context):
+ prefs = preferences()
+
+ layout = self.layout
+ layout.use_property_decorate = False
+ layout.use_property_split = True
+
+ col = layout.column()
+ col.prop(prefs, "enable_double_click")
+ col.prop(prefs, "double_click_mode", text="Mode", expand=True)
+
+
+class TOUCHVIEW_PT_tool_settings(TouchView, Panel):
+ bl_label = "Tool Options"
+ bl_parent_id = "TOUCHVIEW_PT_view_3d_panel"
+
+ def draw(self, context):
+ prefs = preferences()
+
+ layout = self.layout
+ layout.use_property_decorate = False
+ layout.use_property_split = True
+
+ layout.prop(prefs, "subdivision_limit", slider=True)
+
+
+class TOUCHVIEW_PT_viewport_options(TouchView, Panel):
+ bl_label = "Viewport Options"
+ bl_parent_id = "TOUCHVIEW_PT_view_3d_panel"
+
+ def draw(self, context):
+ prefs = preferences()
+
+ layout = self.layout
+ layout.use_property_decorate = False
+ layout.use_property_split = True
+
+ view = context.space_data
+ space = context.area.spaces.active
+
+ col = layout.column()
+ col.operator("view3d.tools_region_flip", text="Flip Tools")
+ if len(space.region_quadviews) > 0:
+ col.operator("screen.region_quadview", text="Disable Quadview")
+ else:
+ col.operator("screen.region_quadview", text="Enable Quadview")
+
+ col = layout.column(align=True)
+ col.prop(prefs, "show_float_menu")
+ if not len(space.region_quadviews) > 0:
+ col.prop(space, "lock_cursor", text="Lock to Cursor")
+ col.prop(view.region_3d, "lock_rotation", text="Lock Rotation")
+
+
+class TOUCHVIEW_PT_image_editor_panel(TouchView, Panel):
+ bl_space_type = "IMAGE_EDITOR"
+
+ def draw(self, context):
+ prefs = preferences()
+
+ layout = self.layout
+ layout.use_property_decorate = False
+
+ box = layout.box()
+ box.label(
+ text=UILayout.enum_item_description(prefs, "input_mode", prefs.input_mode),
+ icon_value=UILayout.enum_item_icon(prefs, "input_mode", prefs.input_mode),
+ )
+
+ row = box.row()
+ row.prop(prefs, "input_mode", expand=True)
+
+ col = box.column(align=True)
+ col.use_property_split = True
+ col.prop(prefs, "is_enabled")
+ subcol = col.column(align=True)
+ subcol.active = prefs.is_enabled
+ subcol.prop(prefs, "header_toggle_position", expand=True)
+
+
+class TOUCHVIEW_PT_node_editor_panel(TouchView, Panel):
+ bl_space_type = "NODE_EDITOR"
+
+ def draw(self, context):
+ prefs = preferences()
+
+ layout = self.layout
+ layout.use_property_decorate = False
+
+ box = layout.box()
+ box.label(
+ text=UILayout.enum_item_description(prefs, "input_mode", prefs.input_mode),
+ icon_value=UILayout.enum_item_icon(prefs, "input_mode", prefs.input_mode),
+ )
+
+ row = box.row()
+ row.prop(prefs, "input_mode", expand=True)
+
+ col = box.column(align=True)
+ col.use_property_split = True
+ col.prop(prefs, "is_enabled")
+ subcol = col.column(align=True)
+ subcol.active = prefs.is_enabled
+ subcol.prop(prefs, "header_toggle_position", expand=True)
+
+
+# UI panel to append Gizmo menu
+class TOUCHVIEW_PT_gizmo_display(Panel):
+ bl_label = "Touchview Gizmos"
+ bl_parent_id = "VIEW3D_PT_gizmo_display"
+ bl_space_type = "VIEW_3D"
+ bl_region_type = "HEADER"
+
+ def draw(self, context):
+ prefs = preferences()
+
+ layout = self.layout
+ col = layout.column()
+ available_gizmos = prefs.getGizmoSet(context.object.mode)
+
+ col = col.column(align=True)
+ col.active = context.space_data.show_gizmo
+ col.prop(prefs, "show_menu")
+ col = col.column()
+ col.active = prefs.show_menu
+ for toggle in available_gizmos:
+ col.prop(prefs, "show_" + toggle)
+
+
+class TOUCHVIEW_MT_floating(Menu):
+ """Open a custom menu"""
+
+ bl_label = "Floating Menu"
+ bl_description = "Customized Floating Menu"
+
+ def draw(self, context):
+ prefs = preferences()
+ menu = prefs.getMenuSettings(context.mode)
+
+ layout = self.layout
+ pie = layout.menu_pie()
+ for i in range(8):
+ op = getattr(menu, "menu_slot_" + str(i + 1))
+ if op == "":
+ continue
+ elif "_MT_" in op:
+ pie.menu(op)
+ continue
+ elif self.__operator_exists(op):
+ pie.operator(op)
+
+ def __operator_exists(self, idname):
+ try:
+ names = idname.split(".")
+ a = bpy.ops
+ for prop in names:
+ a = getattr(a, prop)
+ a.__repr__()
+ except Exception as _:
+ return False
+ return True
+
+
+classes = (
+ TOUCHVIEW_PT_view_3d_panel,
+ TOUCHVIEW_PT_ControlZones,
+ TOUCHVIEW_PT_gizmo_bar,
+ TOUCHVIEW_PT_right_click,
+ TOUCHVIEW_PT_double_click,
+ TOUCHVIEW_PT_tool_settings,
+ TOUCHVIEW_PT_viewport_options,
+ TOUCHVIEW_PT_image_editor_panel,
+ TOUCHVIEW_PT_node_editor_panel,
+ TOUCHVIEW_PT_gizmo_display,
+ TOUCHVIEW_MT_floating,
+)
+
+
+register, unregister = bpy.utils.register_classes_factory(classes)
diff --git a/source/utils/__init__.py b/source/utils/__init__.py
new file mode 100644
index 0000000..c28c785
--- /dev/null
+++ b/source/utils/__init__.py
@@ -0,0 +1,14 @@
+from . import keymaps
+from .overlay import Overlay
+
+ov = Overlay()
+
+
+def register():
+ keymaps.register()
+ ov.drawUI()
+
+
+def unregister():
+ ov.clear_overlays()
+ keymaps.unregister()
diff --git a/source/utils/blender.py b/source/utils/blender.py
new file mode 100644
index 0000000..f686809
--- /dev/null
+++ b/source/utils/blender.py
@@ -0,0 +1,72 @@
+import bpy
+from mathutils import Vector
+
+from ... import \
+ __package__ as package # relative import from the root directory
+
+
+def preferences() -> dict:
+ """Get the addon preferences."""
+ return bpy.context.preferences.addons[package].preferences # type: ignore
+
+
+def panel(type) -> tuple:
+ """Panel in the region.
+
+ type (enum in ['WINDOW', 'HEADER', 'CHANNELS', 'TEMPORARY', 'UI', 'TOOLS',
+ 'TOOL_PROPS', 'PREVIEW', 'HUD', 'NAVIGATION_BAR', 'EXECUTE',
+ 'FOOTER', 'TOOL_HEADER', 'XR']) - Type of the region.
+ return (tuple) - Dimension of the region.
+ """
+ width = 0
+ height = 0
+ alignment = "NONE"
+ for region in bpy.context.area.regions:
+ if region.type == type:
+ width = region.width
+ height = region.height
+ alignment = region.alignment
+ return (width, height, alignment)
+
+
+def ui_scale() -> float:
+ return bpy.context.preferences.system.ui_scale
+
+
+# used in text drawing
+def dpi() -> int:
+ return bpy.context.preferences.system.dpi
+
+
+# returns a tuple (bottom-left, top-right)
+# safe area in viewport for UI elements
+def safe_area_3d(padding: float = 28) -> tuple[Vector, Vector]:
+ buffer = padding * ui_scale()
+ min = Vector((buffer, buffer))
+ max = Vector(
+ (
+ bpy.context.area.width - buffer,
+ bpy.context.area.height - buffer,
+ )
+ )
+
+ if panel("TOOLS")[2] == "LEFT":
+ min.x += panel("TOOLS")[0]
+ elif panel("TOOLS")[2] == "RIGHT":
+ max.x -= panel("TOOLS")[0]
+
+ if panel("UI")[2] == "LEFT":
+ min.x += panel("UI")[0]
+ elif panel("UI")[2] == "RIGHT":
+ max.x -= panel("UI")[0]
+
+ if panel("HEADER")[2] == "BOTTOM":
+ min.y += panel("HEADER")[1]
+ elif panel("HEADER")[2] == "TOP":
+ max.y -= panel("HEADER")[1]
+
+ if panel("TOOL_HEADER")[2] == "BOTTOM":
+ min.y += panel("TOOL_HEADER")[1]
+ elif panel("TOOL_HEADER")[2] == "TOP":
+ max.y -= panel("TOOL_HEADER")[1]
+ return (min, max)
diff --git a/lib/constants.py b/source/utils/constants.py
similarity index 84%
rename from lib/constants.py
rename to source/utils/constants.py
index 579b7d7..15c2a8d 100644
--- a/lib/constants.py
+++ b/source/utils/constants.py
@@ -15,7 +15,14 @@
PASSTHROUGH = {"PASS_THROUGH"}
# DICTIONARIES
-flat_modes = ["Node Editor", "Image", "Image Paint", "UV Editor", "View2D"]
+flat_modes = [
+ "Node Editor",
+ "Image",
+ "Image Paint",
+ "UV Editor",
+ "View2D",
+]
+
top_level_names = (
"Node Editor",
"UV Editor",
@@ -28,16 +35,16 @@
)
input_mode_items = [
- ("ORBIT", "rotate", "Rotate the viewport"),
- ("PAN", "pan", "Move the viewport"),
- ("DOLLY", "zoom", "Zoom in/out the viewport"),
+ ("ORBIT", "Rotate", "Rotate the viewport"),
+ ("PAN", "Pan", "Move the viewport"),
+ ("DOLLY", "Zoom", "Zoom in/out the viewport"),
]
position_items = [
- ("TOP", "top", "Set Gizmo position to top of viewport"),
- ("RIGHT", "right", "Set Gizmo position to right of viewport"),
- ("BOTTOM", "bottom", "Set Gizmo position to bottom of viewport"),
- ("LEFT", "left", "Set Gizmo position to left of viewport"),
+ ("TOP", "Top", "Set Gizmo position to top of viewport"),
+ ("RIGHT", "Right", "Set Gizmo position to right of viewport"),
+ ("BOTTOM", "Bottom", "Set Gizmo position to bottom of viewport"),
+ ("LEFT", "Left", "Set Gizmo position to left of viewport"),
]
pivot_items = [
@@ -71,7 +78,13 @@
("SURFACE", "PIVOT_MEDIAN"),
]
-brush_modes = ["SCULPT", "PAINT_VERTEX", "PAINT_WEIGHT", "PAINT_TEXTURE"]
+brush_modes = [
+ "SCULPT",
+ "PAINT_VERTEX",
+ "PAINT_WEIGHT",
+ "PAINT_TEXTURE",
+]
+
edit_modes = [
("OBJECT", "Object Mode", ""),
("EDIT_MESH", "Edit Mode", ""),
@@ -93,14 +106,14 @@
double_click_items = [
("object.transfer_mode", "Transfer Mode", ""),
- ("nendo.toggle_touch", "Toggle Touch View", ""),
+ ("touchview.toggle_touch", "Toggle Touch View", ""),
("view3d.localview", "Toggle Local View", ""),
("wm.window_fullscreen_toggle", "Toggle Full Screen", ""),
]
menu_style_items = [
- ("fixed.bar", "Fixed Bar", ""),
("float.radial", "Floating Radial", ""),
+ ("fixed.bar", "Fixed Bar", ""),
]
menu_orientation_items = [
diff --git a/lib/ui_gizmo/gizmo_2d.py b/source/utils/gizmo_2d.py
similarity index 62%
rename from lib/ui_gizmo/gizmo_2d.py
rename to source/utils/gizmo_2d.py
index f26f637..c01831e 100644
--- a/lib/ui_gizmo/gizmo_2d.py
+++ b/source/utils/gizmo_2d.py
@@ -1,8 +1,7 @@
import bpy
-from bpy.types import Gizmo, GizmoGroup, bpy_prop_collection
from mathutils import Matrix, Vector
-from ..utils import dpi_factor, get_settings
+from .blender import *
from .gizmo_config import gizmo_colors, toggle_colors
##
@@ -20,63 +19,60 @@
class GizmoSet:
- group: GizmoGroup
+ group: bpy.types.GizmoGroup
- def setup(self, group: GizmoGroup, config: dict):
+ def setup(self, group: bpy.types.GizmoGroup, config: dict):
self.visible = True
self.config = config
self.has_dependent = "has_dependent" in config or False
self.group = group
self.scale = config["scale"] if ("scale" in config) else 14
self.binding = config["binding"]
- self.has_attribute_bind = (
- self.binding["attribute"] if "attribute" in self.binding else False
- )
+ self.has_attribute_bind = self.binding["attribute"] if "attribute" in self.binding else False
self.primary = self.__buildGizmo(config["command"], config["icon"])
def draw_prepare(self):
- settings = get_settings()
- self.hidden = not settings.show_gizmos
+ prefs = preferences()
+ self.hidden = not prefs.show_gizmos
self.skip_draw = False
self.__updatevisible()
- gui_scale = dpi_factor() * 3
if self.binding["name"] == "float_menu":
- self.primary.hide = not settings.show_float_menu
+ self.primary.hide = not prefs.show_float_menu
if self.binding["name"] in ["menu_controller"]:
- self.primary.hide = (
- "float" not in settings.menu_style or not settings.show_menu
- )
+ self.primary.hide = "float" not in prefs.menu_style or not prefs.show_menu
if self.binding["name"] in [
"menu_controller",
]:
- self.primary.scale_basis = gui_scale + settings.menu_spacing
+ self.primary.scale_basis = (36 * prefs.menu_spacing) * prefs.gizmo_scale
+ self.primary.use_grab_cursor = False
+ self.primary.show_drag = True
else:
- self.primary.scale_basis = gui_scale * settings.gizmo_scale
+ self.primary.scale_basis = 18 * prefs.gizmo_scale
def move(self, position: Vector):
self.primary.matrix_basis = Matrix.Translation(position)
def __updatevisible(self):
- if not get_settings().show_menu and self.binding["name"] not in ["float_menu"]:
+ if not preferences().show_menu and self.binding["name"] not in ["float_menu"]:
self.visible = False
self.primary.hide = True
return
if self.binding["location"] == "prefs":
- self.visible = getattr(
- get_settings(), "show_" + self.binding["name"]
- ) and self.binding["name"] in get_settings().getGizmoSet(bpy.context.mode)
+ self.visible = getattr(preferences(), "show_" + self.binding["name"]) and self.binding["name"] in preferences().getGizmoSet(
+ bpy.context.mode
+ )
if self.visible:
self.visible = self.__visibilityLock() and not self.__checkAttributeBind()
self.primary.hide = not self.visible
def __visibilityLock(self) -> bool:
- if get_settings().menu_style == "fixed.bar":
+ if preferences().menu_style == "fixed.bar":
return True
return not self.hidden
- # if an attribute being assigned to active_object should hide/show Gizmo
+ # if an attribute being assigned to active_object should hide/show bpy.types.Gizmo
def __checkAttributeBind(self):
if not self.has_attribute_bind:
return False
@@ -85,7 +81,7 @@ def __checkAttributeBind(self):
return not state
# search for attribute, value through context.
- # will traverse bpy_prop_collection entries
+ # will traverse bpy.types.bpy_prop_collection entries
# by next attr to value comparison
def __findAttribute(self, path: str, value: str):
names = path.split(".")
@@ -95,7 +91,7 @@ def __findAttribute(self, path: str, value: str):
if current is None:
return False
- if isinstance(current, bpy_prop_collection):
+ if isinstance(current, bpy.types.bpy_prop_collection):
item = ""
for item in current:
if getattr(item, names[i + 1]) == value:
@@ -104,21 +100,22 @@ def __findAttribute(self, path: str, value: str):
return getattr(current, value)
# initialize each gizmo, add them to named list with icon name(s)
- def __buildGizmo(self, command: str, icon: str) -> Gizmo:
+ def __buildGizmo(self, command: str, icon: str) -> bpy.types.Gizmo:
gizmo = self.group.gizmos.new("GIZMO_GT_button_2d")
gizmo.target_set_operator(command)
gizmo.icon = icon # type: ignore
- gizmo.use_tooltip = False
- gizmo.use_event_handle_all = True
+ gizmo.use_tooltip = False # show tooltip
+ gizmo.use_event_handle_all = True # don't pass events e.g. shift+a to add
gizmo.use_grab_cursor = "use_grab_cursor" in self.config
+ gizmo.show_drag = False # show default cursor
gizmo.line_width = 5.0
- gizmo.use_draw_modal = True
+ gizmo.use_draw_modal = True # show gizmo while dragging
gizmo.draw_options = {"BACKDROP", "OUTLINE"} # type: ignore
self.__setColors(gizmo)
- gizmo.scale_basis = self.scale or 14
+ gizmo.scale_basis = 0.1
return gizmo
- def __setColors(self, gizmo: Gizmo):
+ def __setColors(self, gizmo: bpy.types.Gizmo):
gizmo.color = gizmo_colors["active"]["color"]
gizmo.color_highlight = gizmo_colors["active"]["color_highlight"]
gizmo.alpha = gizmo_colors["active"]["alpha"]
@@ -126,22 +123,16 @@ def __setColors(self, gizmo: Gizmo):
class GizmoSetBoolean(GizmoSet):
- def setup(self, group: GizmoGroup, config: dict):
+ def setup(self, group: bpy.types.GizmoGroup, config: dict):
self.visible = True
self.config = config
self.has_dependent = "has_dependent" in config or False
self.group = group
self.scale = config["scale"] if ("scale" in config) else 14
self.binding = config["binding"]
- self.has_attribute_bind = (
- self.binding["attribute"] if "attribute" in self.binding else False
- )
- self.onGizmo = self._GizmoSet__buildGizmo( # type: ignore
- config["command"], config["onIcon"]
- )
- self.offGizmo = self._GizmoSet__buildGizmo( # type: ignore
- config["command"], config["offIcon"]
- )
+ self.has_attribute_bind = self.binding["attribute"] if "attribute" in self.binding else False
+ self.onGizmo = self._GizmoSet__buildGizmo(config["command"], config["onIcon"]) # type: ignore
+ self.offGizmo = self._GizmoSet__buildGizmo(config["command"], config["offIcon"]) # type: ignore
self.__setActiveGizmo(True)
def __setActiveGizmo(self, state: bool):
@@ -150,28 +141,25 @@ def __setActiveGizmo(self, state: bool):
self.primary = self.onGizmo if state else self.offGizmo
def draw_prepare(self):
- settings = get_settings()
- self.hidden = not settings.show_gizmos
+ prefs = preferences()
+ self.hidden = not prefs.show_gizmos
self.skip_draw = False
self.__updatevisible()
- gui_scale = dpi_factor() * 3
- self.primary.scale_basis = gui_scale * settings.gizmo_scale
+ self.primary.scale_basis = 18 * prefs.gizmo_scale
if self.binding["name"] == "float_toggle":
self.__setToggleColors(self.primary)
def __updatevisible(self):
- settings = get_settings()
+ prefs = preferences()
bind = self.binding
- if not get_settings().show_menu and (bind["name"] not in ["float_menu"]):
+ if not preferences().show_menu and (bind["name"] not in ["float_menu"]):
self.visible = False
self.primary.hide = True
return
if bind["name"] == "float_toggle":
- self.visible = (
- settings.input_mode != "full" or settings.enable_floating_toggle
- )
+ self.visible = prefs.input_mode != "FULL" or prefs.enable_floating_toggle
else:
- self.visible = getattr(get_settings(), "show_" + self.binding["name"])
+ self.visible = getattr(preferences(), "show_" + self.binding["name"])
if self.visible:
self.visible = (
@@ -180,17 +168,13 @@ def __updatevisible(self):
) # type: ignore
if bind["name"] == "float_toggle":
- self.__setActiveGizmo(settings.is_enabled)
+ self.__setActiveGizmo(prefs.is_enabled)
else:
- self.__setActiveGizmo(
- self._GizmoSet__findAttribute( # type: ignore
- bind["location"], bind["name"]
- )
- )
+ self.__setActiveGizmo(self._GizmoSet__findAttribute(bind["location"], bind["name"])) # type: ignore
self.primary.hide = not self.visible
- def __setToggleColors(self, gizmo: Gizmo):
- mode = "active" if get_settings().is_enabled else "inactive"
+ def __setToggleColors(self, gizmo: bpy.types.Gizmo):
+ mode = "active" if preferences().is_enabled else "inactive"
gizmo.color = toggle_colors[mode]["color"]
gizmo.color_highlight = toggle_colors[mode]["color_highlight"]
gizmo.alpha = toggle_colors[mode]["alpha"]
@@ -198,7 +182,7 @@ def __setToggleColors(self, gizmo: Gizmo):
class GizmoSetEnum(GizmoSet):
- gizmos: list[Gizmo]
+ gizmos: list[bpy.types.Gizmo]
- def setup(self, group: GizmoGroup, config):
+ def setup(self, group: bpy.types.GizmoGroup, config):
pass
diff --git a/source/utils/gizmo_config.py b/source/utils/gizmo_config.py
new file mode 100644
index 0000000..821e2e9
--- /dev/null
+++ b/source/utils/gizmo_config.py
@@ -0,0 +1,270 @@
+from ..utils.constants import pivot_icon_items
+
+###
+# Config Standard
+# ( TYPE BINDING COMMAND ICON )
+# @TYPE - button type to instance (enum, bool, simple/default)
+# @BINDING - used to determine context and visibility
+# @COMMAND - operator to call when activated
+# @ICON - icon to show on Gizmo
+###
+
+# Simple 2D Gizmo
+controllerConfig = {
+ "type": "default",
+ "binding": {"location": "", "name": "menu_controller"},
+ "command": "touchview.move_float_menu",
+ "icon": "BLANK1",
+ "use_grab_cursor": True,
+}
+
+floatingConfig = {
+ "type": "default",
+ "binding": {"location": "prefs", "name": "float_menu"},
+ "command": "touchview.move_action_menu",
+ "icon": "SETTINGS",
+ "use_grab_cursor": True,
+}
+
+floatingToggleConfig = {
+ "type": "boolean",
+ "binding": {"location": "", "name": "float_toggle"},
+ "command": "touchview.move_toggle_button",
+ "onIcon": "OUTLINER_DATA_CAMERA",
+ "offIcon": "GREASEPENCIL",
+ "use_grab_cursor": True,
+}
+
+undoConfig = {
+ "type": "default",
+ "binding": {"location": "prefs", "name": "undoredo"},
+ "has_dependent": True,
+ "command": "ed.undo",
+ "icon": "LOOP_BACK",
+}
+
+redoConfig = {
+ "type": "default",
+ "binding": {"location": "prefs", "name": "undoredo"},
+ "command": "ed.redo",
+ "icon": "LOOP_FORWARDS",
+}
+
+touchViewConfig = {
+ "type": "default",
+ "binding": {
+ "location": "prefs",
+ "name": "is_enabled",
+ },
+ "command": "touchview.toggle_touch",
+ "icon": "VIEW_PAN",
+}
+
+controlGizmoConfig = {
+ "type": "default",
+ "binding": {
+ "location": "prefs",
+ "name": "control_gizmo",
+ },
+ "command": "touchview.cycle_control_gizmo",
+ "icon": "ORIENTATION_LOCAL",
+}
+
+snapViewConfig = {
+ "type": "default",
+ "binding": {"location": "prefs", "name": "snap_view"},
+ "command": "touchview.viewport_recenter",
+ "icon": "CURSOR",
+}
+
+nPanelConfig = {
+ "type": "default",
+ "binding": {"location": "prefs", "name": "n_panel"},
+ "command": "touchview.toggle_n_panel",
+ "icon": "EVENT_N",
+}
+
+voxelSizeConfig = {
+ "type": "default",
+ "binding": {
+ "location": "prefs",
+ "name": "voxel_remesh",
+ "attribute": {
+ "path": "active_object.modifiers.type",
+ "value": "MULTIRES",
+ "state": False,
+ },
+ },
+ "command": "object.voxel_size_edit",
+ "icon": "MESH_GRID",
+}
+
+voxelRemeshConfig = {
+ "type": "default",
+ "binding": {
+ "location": "prefs",
+ "name": "voxel_remesh",
+ "attribute": {
+ "path": "active_object.modifiers.type",
+ "value": "MULTIRES",
+ "state": False,
+ },
+ },
+ "command": "object.voxel_remesh",
+ "icon": "MOD_UVPROJECT",
+}
+
+voxelStepDownConfig = {
+ "type": "default",
+ "binding": {
+ "location": "prefs",
+ "name": "voxel_remesh",
+ "attribute": {
+ "path": "active_object.modifiers.type",
+ "value": "MULTIRES",
+ "state": False,
+ },
+ },
+ "command": "touchview.density_down",
+ "icon": "TRIA_DOWN",
+}
+
+voxelStepUpConfig = {
+ "type": "default",
+ "binding": {
+ "location": "prefs",
+ "name": "voxel_remesh",
+ "attribute": {
+ "path": "active_object.modifiers.type",
+ "value": "MULTIRES",
+ "state": False,
+ },
+ },
+ "command": "touchview.density_up",
+ "icon": "TRIA_UP",
+}
+
+subdivConfig = {
+ "type": "default",
+ "binding": {
+ "location": "prefs",
+ "name": "multires",
+ "attribute": {
+ "path": "active_object.modifiers.type",
+ "value": "MULTIRES",
+ "state": True,
+ },
+ },
+ "has_dependent": True,
+ "command": "touchview.increment_multires",
+ "icon": "TRIA_UP",
+}
+
+unsubdivConfig = {
+ "type": "default",
+ "binding": {
+ "location": "prefs",
+ "name": "multires",
+ "attribute": {
+ "path": "active_object.modifiers.type",
+ "value": "MULTIRES",
+ "state": True,
+ },
+ },
+ "command": "touchview.decrement_multires",
+ "icon": "TRIA_DOWN",
+}
+
+brushResizeConfig = {
+ "type": "default",
+ "binding": {"location": "prefs", "name": "brush_dynamics"},
+ "command": "touchview.brush_resize",
+ "icon": "ANTIALIASED",
+}
+
+brushStrengthConfig = {
+ "type": "default",
+ "binding": {"location": "prefs", "name": "brush_dynamics"},
+ "command": "touchview.brush_strength",
+ "icon": "SMOOTHCURVE",
+}
+
+# Boolean 2D Gizmo
+fullscreenToggleConfig = {
+ "type": "boolean",
+ "binding": {
+ "location": "screen",
+ "name": "show_fullscreen",
+ }, # property location, watch-boolean
+ "command": "screen.screen_full_area",
+ "onIcon": "FULLSCREEN_EXIT", # on-state
+ "offIcon": "FULLSCREEN_ENTER", # off-state
+}
+
+quadviewToggleConfig = {
+ "type": "boolean",
+ "binding": {"location": "space_data", "name": "region_quadviews"},
+ "command": "screen.region_quadview",
+ "onIcon": "IMGDISPLAY",
+ "offIcon": "MESH_PLANE",
+}
+
+rotLocToggleConfig = {
+ "type": "boolean",
+ "binding": {"location": "region_data", "name": "lock_rotation"},
+ "command": "touchview.viewport_lock",
+ "onIcon": "LOCKED",
+ "offIcon": "UNLOCKED",
+}
+
+gizmo_colors = {
+ "disabled": {
+ "color": [0.0, 0.0, 0.0],
+ "color_highlight": [0.0, 0.0, 0.0],
+ "alpha": 0.3,
+ "alpha_highlight": 0.3,
+ },
+ "active": {
+ "color": [0.0, 0.0, 0.0],
+ "alpha": 0.5,
+ "color_highlight": [0.5, 0.5, 0.5],
+ "alpha_highlight": 0.5,
+ },
+ "error": {
+ "color": [0.3, 0.0, 0.0],
+ "alpha": 0.15,
+ "color_highlight": [1.0, 0.2, 0.2],
+ "alpha_highlight": 0.5,
+ },
+ "warn": {
+ "color": [0.35, 0.3, 0.14],
+ "alpha": 0.15,
+ "color_highlight": [0.8, 0.7, 0.3],
+ "alpha_highlight": 0.3,
+ },
+}
+
+toggle_colors = {
+ "active": {
+ "color": [0.1, 0.1, 0.2],
+ "alpha": 0.5,
+ "color_highlight": [0.15, 0.15, 0.3],
+ "alpha_highlight": 0.7,
+ },
+ "inactive": {
+ "color": [0.0, 0.0, 0.0],
+ "alpha": 0.5,
+ "color_highlight": [0.05, 0.05, 0.05],
+ "alpha_highlight": 0.7,
+ },
+}
+
+# Enum 2D Gizmo
+#
+# not implemented yet
+pivotModeConfig = {
+ "type": "enum",
+ "binding": {"location": "prefs", "name": "pivot_mode"},
+ "command": "",
+ "icons": pivot_icon_items,
+}
diff --git a/lib/touch_input.py b/source/utils/keymaps.py
similarity index 74%
rename from lib/touch_input.py
rename to source/utils/keymaps.py
index 857970a..deab216 100644
--- a/lib/touch_input.py
+++ b/source/utils/keymaps.py
@@ -8,7 +8,7 @@
# added timer to ensure Blender keyconfig is fully populated before running
-def register_keymaps():
+def register():
assign_keymaps()
@@ -22,7 +22,7 @@ def assign_keymaps():
# add global default action
km = wm.keyconfigs.addon.keymaps.new(name="3D View", space_type="VIEW_3D")
- kmi = km.keymap_items.new("nendo.toggle_touch", type="T", value=PRESS, alt=True)
+ kmi = km.keymap_items.new("touchview.toggle_touch", type="T", value=PRESS, alt=True)
modified_keymaps.append((km, kmi))
# make menus draggable
@@ -32,26 +32,24 @@ def assign_keymaps():
# add LEFT MOUSE ACTION for view3d.view_ops
for kmap in wm.keyconfigs["Blender"].keymaps:
- km = wm.keyconfigs.addon.keymaps.new(
- name=kmap.name, space_type=kmap.space_type, region_type=kmap.region_type
- )
+ km = wm.keyconfigs.addon.keymaps.new(name=kmap.name, space_type=kmap.space_type, region_type=kmap.region_type)
if kmap.name in top_level_names:
if kmap.name in flat_modes:
- main_action = "nendo.view_ops_2d"
+ main_action = "touchview.view_ops_2d"
else:
- main_action = "nendo.view_ops_3d"
+ main_action = "touchview.view_ops_3d"
kmi = km.keymap_items.new(main_action, LMOUSE, PRESS)
modified_keymaps.append((km, kmi))
- kmi = km.keymap_items.new("nendo.dt_action", LMOUSE, DCLICK)
+ kmi = km.keymap_items.new("touchview.dt_action", LMOUSE, DCLICK)
modified_keymaps.append((km, kmi))
- kmi = km.keymap_items.new("nendo.rc_action", RMOUSE, PRESS)
+ kmi = km.keymap_items.new("touchview.rc_action", RMOUSE, PRESS)
modified_keymaps.append((km, kmi))
# unset MOUSE viewport control, reset PEN to MOUSE input
-def unregister_keymaps():
+def unregister():
for km, kmi in modified_keymaps:
km.keymap_items.remove(kmi)
diff --git a/lib/Overlay.py b/source/utils/overlay.py
similarity index 58%
rename from lib/Overlay.py
rename to source/utils/overlay.py
index e63c959..1837c98 100644
--- a/lib/Overlay.py
+++ b/source/utils/overlay.py
@@ -2,72 +2,66 @@
import bpy
import gpu
-from bpy.types import Region, SpaceView3D
from gpu_extras.batch import batch_for_shader
from mathutils import Vector
-from .utils import get_settings
+from .blender import preferences
class Overlay:
def __init__(self):
+
self.meshes = []
def clear_overlays(self):
for mesh in self.meshes:
- SpaceView3D.draw_handler_remove(mesh, "WINDOW")
+ bpy.types.SpaceView3D.draw_handler_remove(mesh, "WINDOW")
self.meshes = []
- def __getMidpoint(self, view: Region) -> Vector:
+ def __getMidpoint(self, view: bpy.types.Region) -> Vector:
return self.__getSize(view, 0.5)
- def __getSize(self, view: Region, scalar: float = 1) -> Vector:
+ def __getSize(self, view: bpy.types.Region, scalar: float = 1) -> Vector:
return Vector((view.width * scalar, view.height * scalar))
def __getColors(self, type: str):
- settings = get_settings()
- if not settings.is_enabled and not settings.lazy_mode:
+ prefs = preferences()
+ if not prefs.is_enabled and not prefs.lazy_mode:
return (0.0, 0.0, 0.0, 0.0)
- if type == "main" or not settings.use_multiple_colors:
- return settings.overlay_main_color
+ if type == "main" or not prefs.use_multiple_colors:
+ return prefs.overlay_main_color
elif type == "secondary":
- return settings.overlay_secondary_color
+ return prefs.overlay_secondary_color
else:
return (0.0, 0.0, 0.0, 0.0)
def drawUI(self):
- _handle = SpaceView3D.draw_handler_add(
- self.__renderCircle,
- (),
- "WINDOW",
- "POST_PIXEL",
- )
+ _handle = bpy.types.SpaceView3D.draw_handler_add(self.__renderCircle, (), "WINDOW", "POST_PIXEL")
self.meshes.append(_handle)
- _handle = SpaceView3D.draw_handler_add(
- self.__renderRailing, (), "WINDOW", "POST_PIXEL"
- )
+ _handle = bpy.types.SpaceView3D.draw_handler_add(self.__renderRailing, (), "WINDOW", "POST_PIXEL")
self.meshes.append(_handle)
def __renderRailing(self):
- settings = get_settings()
- view = bpy.context.area
- if not settings.isVisible:
+ prefs = preferences()
+ if not prefs.isVisible:
return
+
+ view = bpy.context.area
for region in view.regions:
if bpy.context.region.as_pointer() == region.as_pointer():
self.__makeBox(region, self.__getColors("main"))
- def __makeBox(self, view: Region, color: tuple[float, float, float, float]):
- settings = get_settings()
+ def __makeBox(self, view: bpy.types.Region, color: tuple[float, float, float, float]):
+ prefs = preferences()
mid = self.__getMidpoint(view)
dimensions = self.__getSize(view)
left_rail = (
Vector((0.0, 0.0)),
- Vector((mid.x * settings.getWidth(), dimensions.y)),
+ Vector((mid.x * prefs.getWidth(), dimensions.y)),
)
right_rail = (
Vector((dimensions.x, 0.0)),
- Vector((dimensions.x - mid.x * settings.getWidth(), dimensions.y)),
+ Vector((dimensions.x - mid.x * prefs.getWidth(), dimensions.y)),
)
self.__drawVectorBox(left_rail[0], left_rail[1], color)
@@ -80,21 +74,19 @@ def __drawVectorBox(self, a, b, color):
self.__drawGeometry(vertices, indices, color, "TRIS")
def __renderCircle(self):
- settings = get_settings()
- view = bpy.context.area
- if not settings.isVisible:
+ prefs = preferences()
+ if not prefs.isVisible:
return
+
+ view = bpy.context.area
for region in view.regions:
- if (
- bpy.context.region.as_pointer() == region.as_pointer()
- and not region.data.lock_rotation
- ):
+ if bpy.context.region.as_pointer() == region.as_pointer() and not region.data.lock_rotation:
self.__makeCircle(region, self.__getColors("secondary"))
- def __makeCircle(self, view: Region, color: tuple[float, float, float, float]):
- settings = get_settings()
+ def __makeCircle(self, view: bpy.types.Region, color: tuple[float, float, float, float]):
+ prefs = preferences()
mid = self.__getMidpoint(view)
- radius = math.dist((0, 0), mid) * (settings.getRadius() * 0.5) # type: ignore
+ radius = math.dist((0, 0), mid) * (prefs.getRadius() * 0.5) # type: ignore
self.__drawCircle(mid, radius, color)
def __drawCircle(self, mid: Vector, radius: float, color: tuple):
@@ -104,10 +96,12 @@ def __drawCircle(self, mid: Vector, radius: float, color: tuple):
p = 0
for p in range(segments):
if p > 0:
- point = Vector((
- mid.x + radius * math.cos(math.radians(360 / segments) * p),
- mid.y + radius * math.sin(math.radians(360 / segments) * p),
- ))
+ point = Vector(
+ (
+ mid.x + radius * math.cos(math.radians(360 / segments) * p),
+ mid.y + radius * math.sin(math.radians(360 / segments) * p),
+ )
+ )
vertices.append(point)
indices.append((0, p - 1, p))
indices.append((0, 1, p))