def determine_get_nodes_func(ui): """ Determine which function to use to retrieve the nodes which we should scan for keyframes. Args: ui (QMainWindow): loaded UI instance Returns: func: function to use to retrieve nodes or NoneType: if no function was matched to the corresponding radio button option """ nodes_func_map = { "nodeSection_propertiesPanel_radioButton": get_nodes_in_properties_bin, "nodeSection_selectedNodes_radioButton": get_selected_nodes, "nodeSection_specificNodes_radioButton": get_specific_nodes } button_name = "" for button_name in NODE_SELECTION_RADIO_BUTTONS: button = ui.findChild(QtWidgets.QRadioButton, button_name) if not button: continue elif button.isChecked(): # Found which button is checked. break get_nodes_func = nodes_func_map.get(button_name) if not callable(get_nodes_func): msg = "Failed to retrieve relevant function for button '{0}'." COMMUNICATOR.report_message_with_error(msg.format(button_name), error_type=RuntimeError) return get_nodes_func
def _init_ui(self): try: # Do a stat check to make sure the UI file can be accessed, error if not because we need it. os.stat(PANEL_UI_PATH) except OSError: msg = "UI file necessary for Gapframes was not found. Is the tool installed correctly?" COMMUNICATOR.report_message_with_error(msg, error_type=OSError) self.ui = QtUiTools.QUiLoader().load(PANEL_UI_PATH) self.ui.node_selection_button_group = QtWidgets.QButtonGroup() for button_name in NODE_SELECTION_RADIO_BUTTONS: button = getattr(self.ui, button_name) self.ui.node_selection_button_group.addButton(button) # This is necessary so that this class can override the closeEvent from the UI. self.setCentralWidget(self.ui) self.setMaximumSize(self.ui.maximumSize()) self.setMinimumSize(self.ui.minimumSize()) self._toggle_window_stays_on_top(force_state=True, force_show=False) self._setup_input_sanitization() self._pass_signal_connections() self.restore_preferences() self._add_hotkeys()
def open_panel(): active_widgets = [ w.objectName() for w in QApplication.instance().allWidgets() ] if PANEL_OBJECT_NAME not in active_widgets: # If panel was somehow destroyed, re-initialize it. _initialize_panel() COMMUNICATOR.show_gapframes_panel()
def get_selected_nodes(*args): selection = nuke.selectedNodes() if not selection: msg = "Please select node(s)." COMMUNICATOR.report_message_with_error(msg, error_type=ValueError) for node in selection: # Recurse groups to find all child nodes. if node.Class() == "Group": nodes_in_group = nuke.allNodes(group=node, recurseGroups=True) selection.extend(nodes_in_group) return selection
def _clean_input(input_text): """ Clean up the user input and double check the input sanitization. """ input_items = input_text.replace(" ", "").split(",") pattern = r"^[\d\w_]*$" # Only allow nums, letters and underscores. sanitized = re.match(pattern, "".join(input_items)) if not sanitized: error_msg = "Illegal characters provided in node/knob names." COMMUNICATOR.report_message_with_error(error_msg, error_type=ValueError) return input_items
def find_all_gaps(nodes, allow_knobs=None, exclude_knobs=None, boundary_in=None, boundary_out=None): """ Given a sorted array of any numbers, find each chronological pair of keyframe numbers. Args: nodes (list): list of nodes to get all key frames for allow_knobs (list, optional): list of specific knobs names which to scan for keyframes exclude_knobs (list, optional): list of knobs names which to ignore when scanning for keyframes boundary_in (int, optional): any keyframes on the timeline below this number will not be factored when finding the largest gap boundary_out (int, optional): any keyframes on the timeline above this number will not be factored when finding the largest gap Return: list: list of tuples, each containing neighbouring numbers """ keyframes = get_all_key_frame_nums(nodes, allow_knobs, exclude_knobs, boundary_in, boundary_out) if len(keyframes) < 2: error_msg = "Need input with 2 or more key frames." COMMUNICATOR.report_message_with_error(error_msg, error_type=ValueError) all_gaps = [] for x in range(1, len(keyframes)): first = keyframes[x - 1] second = keyframes[x] all_gaps.append((first, second)) return all_gaps
def get_nodes_in_properties_bin(*args): nodes = [n for n in nuke.allNodes(recurseGroups=True) if n.shown()] if not nodes: msg = "No nodes' Properties are currently open." COMMUNICATOR.report_message_with_error(msg, error_type=ValueError) return nodes
def update_gap_list(): COMMUNICATOR.emit_update_gap_list()
def cycle_gap_distance(): COMMUNICATOR.emit_cycle_gap_distance()
def cycle_prev_gapframe(): COMMUNICATOR.emit_cycle_prev()
def cycle_next_gapframe(): COMMUNICATOR.emit_cycle_next()