Files
Nexus/2023/scripts/animation_tools/dwpicker/main.py
2025-11-25 00:17:12 +08:00

871 lines
33 KiB
Python

# -*- coding: utf-8 -*-
import os
import json
import webbrowser
from copy import deepcopy
from functools import partial
from .pyside import QtWidgets, QtCore, QtGui
from maya import cmds
import maya.OpenMaya as om
from .appinfos import (
VERSION, RELEASE_DATE, DW_GITHUB, DW_WEBSITE, PICKER_DOCUMENTATION)
from .compatibility import ensure_retro_compatibility
from .document import PickerDocument
from .designer.editor import PickerEditor
from .dialog import (
question, get_image_path, NamespaceDialog)
from .ingest import animschool
from .hotkeys import get_hotkeys_config
from .namespace import (
switch_namespace, selected_namespace, detect_picker_namespace,
pickers_namespaces)
from .optionvar import (
AUTO_FOCUS_BEHAVIOR, AUTO_SWITCH_TAB, AUTO_RESIZE_NAMESPACE_COMBO,
CHECK_IMAGES_PATHS, AUTO_SET_NAMESPACE, DISABLE_IMPORT_CALLBACKS,
DISPLAY_HIERARCHY_IN_PICKER, DISPLAY_QUICK_OPTIONS,
INSERT_TAB_AFTER_CURRENT, LAST_OPEN_DIRECTORY, LAST_IMPORT_DIRECTORY,
LAST_SAVE_DIRECTORY, NAMESPACE_TOOLBAR, USE_ICON_FOR_UNSAVED_TAB,
WARN_ON_TAB_CLOSED, save_optionvar, append_recent_filename,
save_opened_filenames)
from .path import get_import_directory, get_open_directory, format_path
from .picker import PickerStackedView, list_targets
from .preference import PreferencesWindow
from .qtutils import set_shortcut, icon, maya_main_window, DockableBase
from .quick import QuickOptions
from .references import ensure_images_path_exists
from .scenedata import (
load_local_picker_data, store_local_picker_data,
clean_stray_picker_holder_nodes)
from .templates import PICKER, BACKGROUND
ABOUT = """\
DreamWall Picker
Licence MIT
Version: {version}
Release date: {release}
Authors: Lionel Brouyère, Olivier Evers
Contributor(s):
Herizo Ran, fabiencollet, c-morten, kalemas (Konstantin Maslyuk),
Markus Ng, Jerome Drese, Renaud Lessard Larouche
Features:
Animation picker widget.
Quick picker creation.
Advanced picker editing.
Read AnimSchoolPicker files (december 2021 version and latest)
Free and open source, today and forever.
This tool is a fork of Hotbox Designer (Lionel Brouyère).
A menus, markmenu and hotbox designer cross DCC.
https://github.com/luckylyk/hotbox_designer
""".format(
version=".".join(str(n) for n in VERSION),
release=RELEASE_DATE)
WINDOW_TITLE = "DreamWall - Picker"
WINDOW_CONTROL_NAME = "dwPickerWindow"
CLOSE_CALLBACK_COMMAND = "import animation_tools.dwpicker as dwpicker;dwpicker._dwpicker.close_event() if dwpicker._dwpicker else None"
CLOSE_TAB_WARNING = """\
Close the tab will remove completely the picker data from the scene.
Are you sure to continue ?"""
class DwPicker(DockableBase, QtWidgets.QWidget):
def __init__(
self,
replace_namespace_function=None,
list_namespaces_function=None):
super(DwPicker, self).__init__(control_name=WINDOW_CONTROL_NAME)
self.setWindowTitle(WINDOW_TITLE)
self.shortcuts = {}
self.replace_namespace_custom_function = replace_namespace_function
self.list_namespaces_function = list_namespaces_function
self.editable = True
self.callbacks = []
self.stored_focus = None
self.editors = []
self.pickers = []
self.preferences_window = PreferencesWindow(
callback=self.load_ui_states, parent=maya_main_window())
self.preferences_window.need_update_callbacks.connect(
self.reload_callbacks)
self.preferences_window.hotkey_changed.connect(self.register_shortcuts)
self.sub_panels_view = QtWidgets.QToolButton()
self.sub_panels_view.setCheckable(True)
self.sub_panels_view.setChecked(True)
self.sub_panels_view.setIcon(icon("panels.png"))
self.sub_panels_view.setFixedSize(17, 17)
self.sub_panels_view.released.connect(self.update_panels_display_mode)
self.sub_tabs_view = QtWidgets.QToolButton()
self.sub_tabs_view.setCheckable(True)
self.sub_tabs_view.setIcon(icon("tabs.png"))
self.sub_tabs_view.setFixedSize(17, 17)
self.sub_tabs_view.released.connect(self.update_panels_display_mode)
self.panel_buttons = QtWidgets.QButtonGroup()
self.panel_buttons.addButton(self.sub_panels_view, 0)
self.panel_buttons.addButton(self.sub_tabs_view, 1)
self.namespace_label = QtWidgets.QLabel("Namespace: ")
self.namespace_combo = QtWidgets.QComboBox()
self.namespace_combo.setMinimumWidth(200)
method = self.change_namespace_combo
self.namespace_combo.currentIndexChanged.connect(method)
self.namespace_refresh = QtWidgets.QPushButton("")
self.namespace_refresh.setIcon(icon("reload.png"))
self.namespace_refresh.setFixedSize(17, 17)
self.namespace_refresh.setIconSize(QtCore.QSize(15, 15))
self.namespace_refresh.released.connect(self.update_namespaces)
self.namespace_picker = QtWidgets.QPushButton("")
self.namespace_picker.setIcon(icon("picker.png"))
self.namespace_picker.setFixedSize(17, 17)
self.namespace_picker.setIconSize(QtCore.QSize(15, 15))
self.namespace_picker.released.connect(self.pick_namespace)
self.namespace_widget = QtWidgets.QWidget()
self.namespace_layout = QtWidgets.QHBoxLayout(self.namespace_widget)
self.namespace_layout.setContentsMargins(10, 2, 2, 2)
self.namespace_layout.setSpacing(0)
self.namespace_layout.addWidget(self.namespace_label)
self.namespace_layout.addSpacing(4)
self.namespace_layout.addWidget(self.namespace_combo)
self.namespace_layout.addSpacing(2)
self.namespace_layout.addWidget(self.namespace_refresh)
self.namespace_layout.addWidget(self.namespace_picker)
self.namespace_layout.addStretch(1)
self.namespace_layout.addWidget(self.sub_panels_view)
self.namespace_layout.addWidget(self.sub_tabs_view)
self.tab = QtWidgets.QTabWidget()
self.tab.setTabsClosable(True)
self.tab.setMovable(True)
self.tab.tabBar().tabMoved.connect(self.tab_moved)
self.tab.tabBar().tabBarDoubleClicked.connect(self.change_title)
self.tab.currentChanged.connect(self.tab_index_changed)
method = partial(self.close_tab, store=True)
self.tab.tabCloseRequested.connect(method)
self.quick_options = QuickOptions()
self.menubar = DwPickerMenu(parent=self)
self.menubar.new.triggered.connect(self.call_new)
self.menubar.open.triggered.connect(self.call_open)
self.menubar.save.triggered.connect(self.call_save)
self.menubar.save_as.triggered.connect(self.call_save_as)
self.menubar.exit.triggered.connect(self.close)
self.menubar.import_.triggered.connect(self.call_import)
self.menubar.undo.triggered.connect(self.call_undo)
self.menubar.redo.triggered.connect(self.call_redo)
self.menubar.advanced_edit.triggered.connect(self.call_edit)
self.menubar.preferences.triggered.connect(self.call_preferences)
self.menubar.change_title.triggered.connect(self.change_title)
self.menubar.toggle_display.triggered.connect(self.toggle_display_mode)
method = self.toggle_hierarchy_display
self.menubar.toggle_hierarchy_display.triggered.connect(method)
method = self.change_namespace_dialog
self.menubar.change_namespace.triggered.connect(method)
self.menubar.add_background.triggered.connect(self.add_background)
self.menubar.tools.triggered.connect(self.call_tools)
self.menubar.documentation.triggered.connect(self.call_documentation)
self.menubar.dw.triggered.connect(self.call_dreamwall)
self.menubar.about.triggered.connect(self.call_about)
self.layout = QtWidgets.QVBoxLayout(self)
self.layout.setContentsMargins(0, 0, 0, 0)
self.layout.setSpacing(0)
self.layout.setMenuBar(self.menubar)
self.layout.addWidget(self.namespace_widget)
self.layout.addWidget(self.tab)
self.layout.addWidget(self.quick_options)
self.load_ui_states()
self.register_shortcuts()
def register_shortcuts(self):
# Unregister all shortcuts before create new ones
function_names_actions = {
'focus': (self.reset, None),
'new': (self.call_new, self.menubar.new),
'open': (self.call_open, self.menubar.open),
'save': (self.call_save, self.menubar.save),
'close': (self.close, self.menubar.exit),
'undo': (self.call_undo, self.menubar.undo),
'redo': (self.call_redo, self.menubar.redo),
'edit': (self.call_edit, self.menubar.advanced_edit),
'next_tab': (self.call_next_tab, None),
'previous_tab': (self.call_previous_tab, None),
'toggle_display': (
self.toggle_display_mode, self.menubar.toggle_display),
'display_hierarchy': (
self.toggle_hierarchy_display,
self.menubar.toggle_hierarchy_display)
}
for function_name, sc in self.shortcuts.items():
sc.activated.disconnect(function_names_actions[function_name][0])
seq = QtGui.QKeySequence()
action = function_names_actions[function_name][1]
if not action:
continue
action.setShortcut(seq)
self.shortcuts = {}
shortcut_context = QtCore.Qt.WidgetWithChildrenShortcut
for function_name, data in get_hotkeys_config().items():
if not data['enabled']:
continue
method = function_names_actions[function_name][0]
ks = data['key_sequence']
if ks is None:
continue
sc = set_shortcut(ks, self, method, shortcut_context)
self.shortcuts[function_name] = sc
# HACK: Need to implement twice the shortcut to display key
# sequence in the menu and keep it active when the view is docked.
action = function_names_actions[function_name][1]
if action is None:
continue
action.setShortcut(ks)
action.setShortcutContext(shortcut_context)
def show(self, *args, **kwargs):
super(DwPicker, self).show(
closeCallback=CLOSE_CALLBACK_COMMAND, *args, **kwargs)
self.register_callbacks()
def close_event(self):
self.preferences_window.close()
def list_scene_namespaces(self):
if self.list_namespaces_function:
ns = self.list_namespaces_function()
else:
ns = cmds.namespaceInfo(listOnlyNamespaces=True, recurse=True)
ns = ns or []
namespaces = ns + pickers_namespaces(self.pickers)
return sorted(list(set(namespaces)))
def update_namespaces(self, *_):
self.namespace_combo.blockSignals(True)
self.namespace_combo.clear()
self.namespace_combo.addItem("*Root*")
namespaces = self.list_scene_namespaces()
self.namespace_combo.addItems(namespaces)
self.namespace_combo.blockSignals(False)
# Auto update namespace combo to namespace size.
if not cmds.optionVar(query=AUTO_RESIZE_NAMESPACE_COMBO):
self.namespace_combo.setSizePolicy(
QtWidgets.QSizePolicy.MinimumExpanding,
QtWidgets.QSizePolicy.Minimum)
self.namespace_combo.setMinimumWidth(200)
return
max_width = 0
for i in range(self.namespace_combo.count()):
t = self.namespace_combo.itemText(i)
width = self.namespace_combo.fontMetrics().horizontalAdvance(t)
max_width = max(max_width, width)
width = max_width + 20 # padding
self.namespace_combo.setFixedWidth(max((200, width)))
def toggle_display_mode(self):
index = int(not bool(self.panel_buttons.checkedId()))
self.panel_buttons.button(index).setChecked(True)
self.update_panels_display_mode()
self.setFocus()
def toggle_hierarchy_display(self):
state = not bool(cmds.optionVar(query=DISPLAY_HIERARCHY_IN_PICKER))
save_optionvar(DISPLAY_HIERARCHY_IN_PICKER, int(state))
self.update()
self.setFocus()
def update_panels_display_mode(self, *_):
state = bool(self.panel_buttons.checkedId())
picker = self.tab.currentWidget()
if picker is None:
return
focused_panel = picker.reset()
picker.as_sub_tab = state
picker.create_pickers()
picker.create_panels(panel=focused_panel)
QtCore.QTimer.singleShot(10, partial(picker.reset, force_all=True))
picker.update()
def tab_index_changed(self, index):
if not self.pickers:
return
picker = self.pickers[index]
index = int(picker.as_sub_tab)
self.panel_buttons.button(index).setChecked(True)
if not picker:
return
namespace = detect_picker_namespace(picker.document.shapes)
self.namespace_combo.blockSignals(True)
if self.namespace_combo.findText(namespace) == -1 and namespace:
self.namespace_combo.addItem(namespace)
if namespace:
self.namespace_combo.setCurrentText(namespace)
else:
self.namespace_combo.setCurrentIndex(0)
self.namespace_combo.blockSignals(False)
def tab_moved(self, newindex, oldindex):
for l in (self.editors, self.pickers):
l.insert(newindex, l.pop(oldindex))
self.store_local_pickers_data()
def leaveEvent(self, _):
mode = cmds.optionVar(query=AUTO_FOCUS_BEHAVIOR)
if mode == 'off':
return
cmds.setFocus("MayaWindow")
def enterEvent(self, _):
mode = cmds.optionVar(query=AUTO_FOCUS_BEHAVIOR)
if mode == 'bilateral':
cmds.setFocus(self.objectName())
def dockCloseEventTriggered(self):
save_opened_filenames([
p.document.filename for p in self.pickers
if p.document.filename])
modified = [p.document.modified_state for p in self.pickers]
if not any(modified):
return super(DwPicker, self).dockCloseEventTriggered()
msg = (
'Some picker have unsaved modification. \n'
'Would you like to save them ?')
result = QtWidgets.QMessageBox.question(
None, 'Save ?', msg,
buttons=(
QtWidgets.QMessageBox.SaveAll |
QtWidgets.QMessageBox.Close),
defaultButton=QtWidgets.QMessageBox.SaveAll)
if result == QtWidgets.QMessageBox.Close:
return
for i in range(self.tab.count()-1, -1, -1):
self.save_tab(i)
save_opened_filenames([p.document.filename for p in self.pickers])
return super(DwPicker, self).dockCloseEventTriggered()
def reload_callbacks(self):
self.unregister_callbacks()
self.register_callbacks()
def register_callbacks(self):
self.unregister_callbacks()
callbacks = {
om.MSceneMessage.kBeforeNew: [
self.close_tabs, self.update_namespaces],
om.MSceneMessage.kAfterOpen: [
self.load_saved_pickers, self.update_namespaces],
om.MSceneMessage.kAfterCreateReference: [
self.load_saved_pickers, self.update_namespaces]}
if not cmds.optionVar(query=DISABLE_IMPORT_CALLBACKS):
callbacks[om.MSceneMessage.kAfterImport] = [
self.load_saved_pickers, self.update_namespaces]
for event, methods in callbacks.items():
for method in methods:
callback = om.MSceneMessage.addCallback(event, method)
self.callbacks.append(callback)
method = self.auto_switch_tab
cb = om.MEventMessage.addEventCallback('SelectionChanged', method)
self.callbacks.append(cb)
method = self.auto_switch_namespace
cb = om.MEventMessage.addEventCallback('SelectionChanged', method)
self.callbacks.append(cb)
for picker in self.pickers:
picker.register_callbacks()
def unregister_callbacks(self):
for cb in self.callbacks:
om.MMessage.removeCallback(cb)
self.callbacks.remove(cb)
for picker in self.pickers:
picker.unregister_callbacks()
def auto_switch_namespace(self, *_, **__):
if not cmds.optionVar(query=AUTO_SET_NAMESPACE):
return
self.pick_namespace()
def auto_switch_tab(self, *_, **__):
if not cmds.optionVar(query=AUTO_SWITCH_TAB):
return
nodes = cmds.ls(selection=True)
if not nodes:
return
picker = self.tab.currentWidget()
if not picker:
return
targets = list_targets(picker.document.shapes)
if nodes[-1] in targets:
return
for i, picker in enumerate(self.pickers):
if nodes[-1] in list_targets(picker.document.shapes):
self.tab.setCurrentIndex(i)
return
def load_saved_pickers(self, *_, **__):
self.clear()
pickers = load_local_picker_data()
if cmds.optionVar(query=CHECK_IMAGES_PATHS):
ensure_images_path_exists(pickers)
for picker in pickers:
self.add_picker(picker)
clean_stray_picker_holder_nodes()
def store_local_pickers_data(self):
if not self.editable:
return
if not self.tab.count():
store_local_picker_data([])
return
pickers = [self.document(i).data for i in range(self.tab.count())]
store_local_picker_data(pickers)
def save_tab(self, index):
msg = (
'Picker contain unsaved modification !\n'
'Woud you like to continue ?')
result = QtWidgets.QMessageBox.question(
None, 'Save ?', msg,
buttons=(
QtWidgets.QMessageBox.Save |
QtWidgets.QMessageBox.Yes |
QtWidgets.QMessageBox.Cancel),
defaultButton=QtWidgets.QMessageBox.Cancel)
if result == QtWidgets.QMessageBox.Cancel:
return False
elif result == QtWidgets.QMessageBox.Save and not self.call_save(index):
return False
return True
def close_tabs(self, *_):
for i in range(self.tab.count()-1, -1, -1):
self.close_tab(i)
self.store_local_pickers_data()
def clear(self):
for i in range(self.tab.count()-1, -1, -1):
self.close_tab(i, force=True)
def close_tab(self, index, force=False, store=False):
if self.document(index).modified_state and force is False:
if not self.save_tab(index):
return
elif (cmds.optionVar(query=WARN_ON_TAB_CLOSED) and
not question('Warning', CLOSE_TAB_WARNING)):
return
editor = self.editors.pop(index)
if editor:
editor.close()
picker = self.pickers.pop(index)
picker.unregister_callbacks()
picker.close()
self.tab.removeTab(index)
if store:
self.store_local_pickers_data()
def load_ui_states(self):
value = bool(cmds.optionVar(query=DISPLAY_QUICK_OPTIONS))
self.quick_options.setVisible(value)
value = bool(cmds.optionVar(query=NAMESPACE_TOOLBAR))
self.namespace_widget.setVisible(value)
self.update_namespaces()
self.update_modified_states()
def add_picker_from_file(self, filename):
with open(filename, "r") as f:
data = ensure_retro_compatibility(json.load(f))
ensure_images_path_exists([data])
self.add_picker(data, filename=filename)
append_recent_filename(filename)
def reset(self):
picker = self.tab.currentWidget()
if picker:
picker.reset()
def general_changed(self, origin, option):
if option == 'name' and origin != 'main_window':
self.update_names()
if option == 'panels.as_sub_tab' and origin != 'main_window':
index = int(self.document().data['general']['panels.as_sub_tab'])
self.panel_buttons.button(index).setChecked(True)
def update_names(self):
for i in range(self.tab.count()):
self.set_title(i, self.document(i).data['general']['name'])
def create_picker(self, data):
document = PickerDocument(data)
document.changed.connect(self.store_local_pickers_data)
document.general_option_changed.connect(self.general_changed)
document.data_changed.connect(self.update_names)
document.changed.connect(self.update_modified_states)
picker = PickerStackedView(document, self.editable)
picker.register_callbacks()
return picker
def add_picker(self, data, filename=None, modified_state=False):
picker = self.create_picker(data)
picker.document.filename = filename
picker.document.modified_state = modified_state
insert = cmds.optionVar(query=INSERT_TAB_AFTER_CURRENT)
if not insert or self.tab.currentIndex() == self.tab.count() - 1:
self.pickers.append(picker)
self.editors.append(None)
self.tab.addTab(picker, data['general']['name'])
self.tab.setCurrentIndex(self.tab.count() - 1)
else:
index = self.tab.currentIndex() + 1
self.pickers.insert(index, picker)
self.editors.insert(index, None)
self.tab.insertTab(index, picker, data['general']['name'])
self.tab.setCurrentIndex(index)
picker.reset(force_all=True)
def call_open(self):
filenames = QtWidgets.QFileDialog.getOpenFileNames(
None, "Open a picker...",
get_open_directory(),
filter="Dreamwall Picker (*.json)")[0]
if not filenames:
return
save_optionvar(LAST_OPEN_DIRECTORY, os.path.dirname(filenames[0]))
for filename in filenames:
self.add_picker_from_file(filename)
self.store_local_pickers_data()
def call_preferences(self):
self.preferences_window.show()
def call_save(self, index=None):
index = self.tab.currentIndex() if type(index) is not int else index
filename = self.document(index).filename
if not filename:
return self.call_save_as(index=index)
return self.save_picker(index, filename)
def call_save_as(self, index=None):
index = self.tab.currentIndex() if type(index) is not int else index
filename = QtWidgets.QFileDialog.getSaveFileName(
None, "Save a picker ...",
cmds.optionVar(query=LAST_SAVE_DIRECTORY),
filter="Dreamwall Picker (*.json)")[0]
if not filename:
return False
if os.path.exists(filename):
msg = '{} already, exists. Do you want to erase it ?'
if not question('File exist', msg.format(filename)):
return False
self.save_picker(index, filename)
def call_undo(self):
index = self.tab.currentIndex()
if index < 0:
return
self.document(index).undo()
self.document(index).changed.emit()
def call_redo(self):
index = self.tab.currentIndex()
if index < 0:
return
self.document(index).redo()
self.document(index).changed.emit()
def save_picker(self, index, filename):
self.document(index).filename = filename
save_optionvar(LAST_SAVE_DIRECTORY, os.path.dirname(filename))
append_recent_filename(filename)
with open(filename, 'w') as f:
json.dump(self.document(index).data, f, indent=2)
self.set_modified_state(index, False)
return True
def call_import(self):
sources = QtWidgets.QFileDialog.getOpenFileNames(
None, "Import a picker...",
get_import_directory(),
filter="Anim School Picker (*.pkr)")[0]
if not sources:
return
dst = QtWidgets.QFileDialog.getExistingDirectory(
None,
"Conversion destination",
os.path.dirname(sources[0]),
options=QtWidgets.QFileDialog.ShowDirsOnly)
if not dst:
return
save_optionvar(LAST_IMPORT_DIRECTORY, os.path.dirname(sources[0]))
for src in sources:
filename = animschool.convert(src, dst)
self.add_picker_from_file(filename)
def call_new(self):
self.add_picker({
'general': deepcopy(PICKER),
'shapes': []})
self.store_local_pickers_data()
def document(self, index=None):
index = self.tab.currentIndex() if type(index) is not int else index
if index < 0:
return None
picker = self.tab.widget(index)
return picker.document
def call_edit(self):
index = self.tab.currentIndex()
if index < 0:
QtWidgets.QMessageBox.warning(self, "Warning", "No picker set")
return
if self.editors[index] is None:
document = self.document()
editor = PickerEditor(
document,
parent=self)
self.editors[index] = editor
self.editors[index].show()
self.editors[index].shape_canvas.focus()
def call_next_tab(self):
index = self.tab.currentIndex() + 1
if index == self.tab.count():
index = 0
self.tab.setCurrentIndex(index)
def call_previous_tab(self):
index = self.tab.currentIndex() - 1
if index < 0:
index = self.tab.count() - 1
self.tab.setCurrentIndex(index)
def set_editable(self, state):
self.editable = state
self.menubar.set_editable(state)
for picker in self.pickers:
picker.editable = state
def update_modified_states(self):
for index, picker in enumerate(self.pickers):
state = picker.document.modified_state
use_icon = cmds.optionVar(query=USE_ICON_FOR_UNSAVED_TAB)
icon_ = icon('save.png') if state and use_icon else QtGui.QIcon()
self.tab.setTabIcon(index, icon_)
title = self.document(index).data['general']['name']
title = "*" + title if state and not use_icon else title
self.tab.setTabText(index, title)
def set_modified_state(self, index, state):
"""
Update the tab icon. Add a "save" icon if tab contains unsaved
modifications.
"""
if not self.document(index).filename:
return
self.document(index).modified_state = state
use_icon = cmds.optionVar(query=USE_ICON_FOR_UNSAVED_TAB)
icon_ = icon('save.png') if state and use_icon else QtGui.QIcon()
self.tab.setTabIcon(index, icon_)
title = self.document(index).data['general']['name']
title = "*" + title if state and not use_icon else title
self.tab.setTabText(index, title)
def call_tools(self):
webbrowser.open(DW_GITHUB)
def call_dreamwall(self):
webbrowser.open(DW_WEBSITE)
def call_documentation(self):
webbrowser.open(PICKER_DOCUMENTATION)
def call_about(self):
QtWidgets.QMessageBox.about(self, 'About', ABOUT)
def sizeHint(self):
return QtCore.QSize(500, 800)
def change_title(self, index=None):
if not self.editable:
return
index = (
self.tab.currentIndex() if not isinstance(index, int) else index)
if index < 0:
return
title, operate = QtWidgets.QInputDialog.getText(
None, 'Change picker title', 'New title',
text=self.document(index).data['general']['name'])
if not operate:
return
self.set_title(index, title)
index = (
self.tab.currentIndex() if not isinstance(index, int) else index)
if index < 0:
return
document = self.document(index)
document.data['general']['name'] = title
document.general_option_changed.emit('main_window', 'name')
self.document(index).record_undo()
self.set_title(index, title)
def set_title(self, index=None, title=''):
use_icon = cmds.optionVar(query=USE_ICON_FOR_UNSAVED_TAB)
if not use_icon and self.document(index).modified_state:
title = "*" + title
self.tab.setTabText(index, title)
def change_namespace_dialog(self):
dialog = NamespaceDialog()
if not dialog.exec_():
return
namespace = dialog.namespace
self.change_namespace(namespace)
def change_namespace_combo(self):
index = self.namespace_combo.currentIndex()
text = self.namespace_combo.currentText()
namespace = text if index else ":"
self.change_namespace(namespace)
def pick_namespace(self):
namespace = selected_namespace()
self.namespace_combo.setCurrentText(namespace)
def change_namespace(self, namespace):
document = self.document()
if not document:
return
switch_namespace_function = (
self.replace_namespace_custom_function or switch_namespace)
for shape in document.shapes:
if not shape.targets():
continue
targets = [
switch_namespace_function(t, namespace)
for t in shape.targets()]
shape.options['action.targets'] = targets
document.record_undo()
document.shapes_changed.emit()
def add_background(self):
filename = get_image_path(self)
if not filename:
return
filename = format_path(filename)
shape = deepcopy(BACKGROUND)
shape['image.path'] = filename
image = QtGui.QImage(filename)
shape['image.width'] = image.size().width()
shape['image.height'] = image.size().height()
shape['shape.width'] = image.size().width()
shape['shape.height'] = image.size().height()
shape['bgcolor.transparency'] = 255
self.document().add_shapes([shape], prepend=True)
self.document().record_undo()
self.document().shapes_changed.emit()
class DwPickerMenu(QtWidgets.QMenuBar):
def __init__(self, parent=None):
super(DwPickerMenu, self).__init__(parent)
self.new = QtWidgets.QAction('&New', parent)
self.open = QtWidgets.QAction('&Open', parent)
self.import_ = QtWidgets.QAction('&Import', parent)
self.save = QtWidgets.QAction('&Save', parent)
self.save_as = QtWidgets.QAction('&Save as', parent)
self.exit = QtWidgets.QAction('Exit', parent)
self.undo = QtWidgets.QAction('Undo', parent)
self.redo = QtWidgets.QAction('Redo', parent)
self.advanced_edit = QtWidgets.QAction('Advanced &editing', parent)
self.preferences = QtWidgets.QAction('Preferences', parent)
text = 'Toggle panel display mode'
self.toggle_display = QtWidgets.QAction(text, parent)
text = 'Toggle hierarchy display'
self.toggle_hierarchy_display = QtWidgets.QAction(text, parent)
self.change_title = QtWidgets.QAction('Change picker title', parent)
self.change_namespace = QtWidgets.QAction('Change namespace', parent)
self.add_background = QtWidgets.QAction('Add background item', parent)
self.documentation = QtWidgets.QAction('Documentation', parent)
self.tools = QtWidgets.QAction('Other DreamWall &tools', parent)
self.dw = QtWidgets.QAction('&About DreamWall', parent)
self.about = QtWidgets.QAction('&About DwPicker', parent)
self.file = QtWidgets.QMenu('&File', parent)
self.file.addAction(self.new)
self.file.addAction(self.open)
self.file.addAction(self.import_)
self.file.addSeparator()
self.file.addAction(self.save)
self.file.addAction(self.save_as)
self.file.addSeparator()
self.file.addAction(self.exit)
self.edit = QtWidgets.QMenu('&Edit', parent)
self.edit.addAction(self.undo)
self.edit.addAction(self.redo)
self.edit.addSeparator()
self.edit.addAction(self.advanced_edit)
self.edit.addAction(self.preferences)
self.edit.addSeparator()
self.edit.addAction(self.toggle_display)
self.edit.addAction(self.toggle_hierarchy_display)
self.edit.addSeparator()
self.edit.addAction(self.change_title)
self.edit.addSeparator()
self.edit.addAction(self.change_namespace)
self.edit.addAction(self.add_background)
self.help = QtWidgets.QMenu('&Help', parent)
self.help.addAction(self.documentation)
self.help.addSeparator()
self.help.addAction(self.tools)
self.help.addAction(self.dw)
self.help.addSeparator()
self.help.addAction(self.about)
self.addMenu(self.file)
self.addMenu(self.edit)
self.addMenu(self.help)
def set_editable(self, state):
self.undo.setEnabled(state)
self.redo.setEnabled(state)
self.change_title.setEnabled(state)
self.advanced_edit.setEnabled(state)
self.add_background.setEnabled(state)