Example #1
0
    def save_file(self, obj, filetype):
        if obj[filetype.lower()] is None:
            with wx.MessageDialog(self, " No {} Loaded".format(filetype),
                                  "Warning", wx.OK) as dlg:
                dlg.ShowModal()
            return

        with wx.FileDialog(self, "Choose a file", obj['dirname'], "",
                           "*." + filetype.lower(), wx.FD_SAVE) as dlg:
            if dlg.ShowModal() == wx.ID_OK:
                filename = dlg.GetFilename()
                obj['dirname'] = dlg.GetDirectory()
                self.statusbar.SetStatusText("Saving...")
                create_backup(obj['dirname'], filename)
                path = os.path.join(obj['dirname'], filename)
                removed_nodes = obj[filetype.lower()].save(path)
                msg = ''
                if removed_nodes:
                    msg = "The following animation nodes were removed:\n{}".format(
                        '\n'.join(
                            [' * ' + node for node in sorted(removed_nodes)]))
                self.statusbar.SetStatusText("Saved {}".format(path))
                with MultiMessageDialog(
                        self, "Saved to {} successfully".format(path),
                        filetype + " Saved", msg, wx.OK) as saved:
                    saved.ShowModal()
Example #2
0
def show_multi_rename_dialog(root, obj_type, obj_list, names, selected, rename_func):
    with MultiRenameDialog(root) as dlg:
        if dlg.ShowModal() == wx.ID_OK:
            pattern = dlg.GetPattern()
            repl = dlg.GetReplace()
            changed_bones = ''
            for obj in obj_list:
                new_name = pattern.sub(repl, obj.name)
                if new_name in names and new_name != obj.name:
                    changed_bones += ' * {} (skipping due to naming conflict)\n'.format(obj.name)
                elif new_name == obj.name:
                    changed_bones += ' * {} (no change)\n'.format(obj.name)
                else:
                    changed_bones += ' * {} -> {}\n'.format(obj.name, new_name)
            msg = "You are about to change multiple {}.  Are you sure you want to do that?\n".format(obj_type)
            with MultiMessageDialog(root, msg, "Warning", changed_bones, wx.YES | wx.NO) as warn:
                if warn.ShowModal() != wx.ID_YES:
                    return
            for i, obj in enumerate(obj_list):
                new_name = pattern.sub(repl, obj.name)
                if new_name in names:
                    continue
                old_name, obj.name = obj.name, new_name
                rename_func(selected[i], obj, old_name, new_name)
            root.SetStatusText("Renamed {} {}".format(len(obj_list), obj_type))
Example #3
0
 def transform(self, selected, bone_index, flag, found_func, w, x, y, z):
     animations = [self.root.main['ean'].animations[i] for i in selected]
     msg = ''
     animations_changed = len(selected)
     for animation in animations:
         for node in animation.nodes:
             if node.bone_index == bone_index:
                 for keyframed_animation in node.keyframed_animations:
                     if keyframed_animation.flag == flag:
                         for keyframe in keyframed_animation.keyframes:
                             found_func(keyframe, w, x, y, z)
                         break
                 else:
                     keyframed_animation = KeyframedAnimation()
                     keyframed_animation.flag = flag
                     keyframed_animation.keyframes.append(
                         Keyframe(0, w, x, y, z))
                     keyframed_animation.keyframes.append(
                         Keyframe(animation.frame_count - 1, w, x, y, z))
                     node.keyframed_animations.append(keyframed_animation)
                 break
         else:
             msg += ' * {}\n'.format(animation.name)
             animations_changed -= 1
     if msg:
         with MultiMessageDialog(self, 'Skipped animations:', "Warning",
                                 msg, wx.OK) as dlg:
             dlg.ShowModal()
     self.root.SetStatusText("Edited {} animation(s)".format(len(selected)))
Example #4
0
 def show_invalid_colors(self, invalid_colors):
     if not invalid_colors:
         return
     msg = "\n".join(
         f" * Part Color ({c.part_colors}, {c.color})"
         for c in sorted(invalid_colors,
                         key=lambda x: (x.part_colors, x.color)))
     with MultiMessageDialog(
             self,
             'Some color selectors were not added because they referenced invalid Part Colors',
             'Warning', msg, wx.OK) as dlg:
         dlg.ShowModal()
Example #5
0
    def on_paste(self, _):
        selected = self.entry_list.GetSelections()
        if not selected:
            return

        success = False
        cdo = wx.CustomDataObject("BDMEntry")
        if wx.TheClipboard.Open():
            success = wx.TheClipboard.GetData(cdo)
            wx.TheClipboard.Close()
        if success:
            paste_data = pickle.loads(cdo.GetData())
            paste_length = len(paste_data)
            selected_length = len(selected)
            if selected_length > paste_length:
                for item in selected[paste_length:]:
                    self.entry_list.Unselect(item)
                selected = selected[:paste_length]

            item = selected[-1]
            self.entry_list.Select(item)
            for n in range(paste_length - selected_length):
                item = self.entry_list.GetNextItem(item)
                if not item.IsOk():
                    with wx.MessageDialog(
                            self,
                            f'Not enough entries to paste over. Expected {paste_length}'
                    ) as dlg:
                        dlg.ShowModal()
                        return
                self.entry_list.Select(item)
                selected.append(item)

            if len(selected) > 1:
                msg = '\n'.join([
                    f' * {self.entry_list.GetItemData(item).id}: Entry'
                    for item in selected
                ])
                with MultiMessageDialog(
                        self,
                        'Are you sure you want to replace the following entries?',
                        'Warning', msg, wx.YES | wx.NO) as dlg:
                    if dlg.ShowModal() != wx.ID_YES:
                        return

            for n, paste in enumerate(paste_data):
                data = self.entry_list.GetItemData(selected[n])
                data.paste(paste)

            self.on_select(None)
            pub.sendMessage('set_status_bar',
                            text=f'Pasted {len(paste_data)} entry(s)')
Example #6
0
    def on_paste(self, _):
        selected = self.bone_list.GetSelections()
        if not selected or not self.copied_bones:
            return
        copied_bones = pickle.loads(self.copied_bones)
        if len(selected) > 1:
            with wx.MessageDialog(
                    self, 'Only one pyxenoverse can be selected to paste over',
                    'Warning') as dlg:
                dlg.ShowModal()
            return
        temp_bone_list = {}
        root = selected[-1]
        root_bone = self.bone_list.GetItemData(root)
        self.bone_list.UnselectAll()
        all_bone_list = self.get_bone_names_index(
            self.bone_list.GetFirstItem())
        current_bone_list = {root_bone.name: root}
        current_bone_list.update(
            self.get_bone_names_index(self.bone_list.GetFirstChild(root)))
        changed_bones = ''
        for bone in copied_bones:
            if bone.name in current_bone_list:
                changed_bones += ' * ' + bone.name + '\n'
        if changed_bones:
            msg = "You are about to change multiple bones.  Are you sure you want to do that?"
            with MultiMessageDialog(self, msg, "Warning", changed_bones,
                                    wx.YES | wx.NO) as dlg:
                if dlg.ShowModal() != wx.ID_YES:
                    return

        for bone in copied_bones:
            new_bone = Bone()
            new_bone.paste(bone)
            if new_bone.name in current_bone_list:
                item = current_bone_list[new_bone.name]
                self.bone_list.SetItemData(item, new_bone)
            else:
                new_bone = get_unique_name(new_bone, all_bone_list)
                if new_bone.parent_index in temp_bone_list:
                    item = self.bone_list.AppendItem(
                        temp_bone_list[new_bone.parent_index],
                        '',
                        data=new_bone)
                else:
                    item = self.bone_list.AppendItem(root, '', data=new_bone)
            self.bone_list.Select(item)
            self.bone_list.Expand(item)
            self.bone_list.CheckItem(item)
            temp_bone_list[new_bone.index] = item
        self.recalculate_bone_tree()
        self.root.SetStatusText("Pasted {} bones".format(len(copied_bones)))
Example #7
0
    def on_replace_all(self, _):
        if not color_db.bcs:
            self.status_bar.SetStatusText("BCS Not Loaded")
            return
        item_type, fields = FIND_ITEM_TYPES[self.items.GetSelection()]
        entry_type = fields[self.entry.GetSelection()]
        find = self.find_ctrl.GetValue()
        replace = self.replace_ctrl.GetValue()
        if "name" not in entry_type:
            try:
                find = int(self.find_ctrl.GetValue(), 0)
                replace = int(self.replace_ctrl.GetValue(), 0)
            except ValueError:
                self.status_bar.SetStatusText("Invalid Value")
                return
        count = 0
        skipped = 0
        skipped_entries = set()
        item, _ = get_first_item(self.part_sets_list)
        while item.IsOk():
            data = self.part_sets_list.GetItemData(item)
            res = self.replace_item(data, item_type, entry_type, find, replace,
                                    skipped_entries)
            if res == Replace.REPLACED:
                count += 1
            elif res == Replace.SKIPPED:
                skipped += 1
            item = get_next_item(self.part_sets_list, item)

        self.main_panel.pages["Part Sets"].on_select(None)
        pub.sendMessage('reindex_part_sets')
        msg = f'Replaced {count} entry(s) (skipped {skipped}). '
        if skipped:
            msg += "Check your part colors"
        self.status_bar.SetStatusText(msg)

        if item_type == ColorSelector and skipped_entries:
            if entry_type == "part_colors":
                msg = "\n".join(
                    f" * Color Selector ({cs[0]}, {cs[1]}) -> ({replace}, {cs[1]})"
                    for cs in sorted(skipped_entries))
            else:
                msg = "\n".join(
                    f" * Color Selector ({cs[0]}, {cs[1]}) -> ({cs[0]}, {replace})"
                    for cs in sorted(skipped_entries))
            with MultiMessageDialog(
                    self, f"The following Color Selectors were skipped.\n"
                    f"Please check your part colors.", "Warning", msg,
                    wx.OK) as dlg:
                dlg.ShowModal()
Example #8
0
 def exception_hook(self, e, value, trace):
     with MultiMessageDialog(
             self, '', 'Error',
             ''.join(traceback.format_exception(e, value,
                                                trace)), wx.OK) as dlg:
         dlg.ShowModal()
Example #9
0
    def on_paste(self, _):
        if not self.parent.copied:
            with wx.MessageDialog(
                    self,
                    f'No entries are copied from the right panel to Paste'
            ) as dlg:
                dlg.ShowModal()
            return

        selected = self.entry_list.GetSelections()
        if not selected:
            with wx.MessageDialog(
                    self, f'No entries are selected to Paste onto') as dlg:
                dlg.ShowModal()
            return

        copied = pickle.loads(self.parent.copied)

        # Cut length of selected to match copied
        copy_length = len(copied)
        selected_length = len(selected)
        if selected_length > copy_length:
            for item in selected[copy_length:]:
                self.entry_list.Unselect(item)
            selected = selected[:copy_length]
        item = selected[-1]
        self.entry_list.Select(item)

        # Increase length to match selected
        for n in range(copy_length - selected_length):
            item = self.entry_list.GetNextItem(item)
            if not item.IsOk():
                with wx.MessageDialog(
                        self,
                        f'Not enough entries to paste over. Expected {copy_length}'
                ) as dlg:
                    dlg.ShowModal()
                    return
            self.entry_list.Select(item)
            selected.append(item)

        selected_data = [
            self.entry_list.GetItemData(item) for item in selected
        ]

        # Warn about changing multiple entries
        if len(copied) > 1:
            msg = ''
            for n, copied_data in enumerate(copied):
                msg += f' * {selected_data[n].index} -> {copied_data.index}\n'
            with MultiMessageDialog(
                    self,
                    'Are you sure you want to replace the following entries?',
                    'Warning', msg, wx.YES | wx.NO) as dlg:
                if dlg.ShowModal() != wx.ID_YES:
                    return

        # Paste entries
        selected_values = []
        copied_values = []
        changed_values = defaultdict(list)

        for n, copied_data in enumerate(copied):
            selected_values.append(
                (selected_data[n].index, selected_data[n].get_static_values()))
            copied_values.append(copied_data.get_static_values())

        for selected_val, copied_val in zip(selected_values, copied_values):
            # Example:
            # Item type: Animation
            # entry: Index
            # dependency: Type
            # depend_value: 5
            # entry_values: {1, 2, 3}
            for item_type, v1 in copied_val.items():
                if item_type not in [Animation, Hitbox, Camera]:
                    continue
                for entry_pair, v2 in v1.items():
                    for depend_value, entry_values in v2.items():
                        # Skip if dependency isn't a character
                        if item_type.dependencies[entry_pair][
                                depend_value] != 'Character':
                            continue
                        if not self.get_changed_values(
                                changed_values, item_type, entry_pair,
                                depend_value, entry_values, selected_val,
                                selected_data):
                            return

        # Finally copy BAC Entries
        for n, copied_data in enumerate(copied):
            entry = self.entry_list.GetItemData(selected[n])
            entry.paste(copied_data, self.links)

        # Display message
        msg = f'Pasted {len(copied)} entry(s)'
        pub.sendMessage('set_status_bar', text=msg)
        with ChangedDialog(self, changed_values) as dlg:
            dlg.ShowModal()
Example #10
0
    def on_paste(self, _):
        selected = list(get_selected_items(self.anim_list))
        if not self.copied_animations or not selected:
            return
        copied_animations = pickle.loads(self.copied_animations)
        bone_list = self.root.main['ean_bone_list']

        # Expand/truncate selection
        selected = selected[:len(copied_animations)]
        difference = len(copied_animations) - len(selected)
        if difference:
            last_index = selected[-1]
            selected.extend(
                list(range(last_index + 1, last_index + difference + 1)))
        for i in range(self.anim_list.GetItemCount()):
            self.anim_list.Select(i, i in selected)

        bone_filters = set()
        item = bone_list.GetFirstItem()
        while item.IsOk():
            if bone_list.GetCheckedState(item) != wx.CHK_UNCHECKED:
                bone_filters.add(bone_list.GetItemData(item).name)
            item = bone_list.GetNextItem(item)

        # Warn if multiple animations are being copied
        if len(copied_animations) > 1:
            changed_animations = ''
            for i, animation in enumerate(copied_animations):
                changed_animations += ' * '
                dst_index = selected[i]
                if dst_index < len(self.root.main['ean'].animations):
                    changed_animations += self.root.main['ean'].animations[
                        dst_index].name
                changed_animations += ' -> {}\n'.format(animation.name)
            with wx.MessageDialog(
                    self,
                    "You are about to change multiple animations. Are you sure you want to do that?\n"
                    + changed_animations, "Warning", wx.YES | wx.NO) as dlg:
                if dlg.ShowModal() != wx.ID_YES:
                    return

        skipped_nodes = set()

        # Add missing bones
        bone_filters.update(
            self.root.main['ean_bone_panel'].add_missing_bones())

        # Do the copying
        names = [
            animation.name for animation in self.root.main['ean'].animations
        ]
        for i, copied_animation in enumerate(copied_animations):
            dst_index = selected[i]
            if dst_index < len(self.root.main['ean'].animations):
                animation = self.root.main['ean'].animations[dst_index]
                skipped_nodes.update(
                    animation.paste(copied_animation, bone_filters, True))
            else:
                animation = Animation(self.root.main['ean'])
                animation.frame_float_size = copied_animation.frame_float_size
                skipped_nodes.update(animation.paste(copied_animation))
                animation = get_unique_name(animation, names)
                self.root.main['ean'].animations.append(animation)
                self.anim_list.InsertItem(dst_index, str(dst_index))
                self.anim_list.SetItem(dst_index, 1, animation.name)
            self.anim_list.SetItem(dst_index, 2, str(animation.frame_count))
            self.anim_list.Select(dst_index)
        self.reindex()
        pasted_msg = "Pasted {} animation(s)".format(len(copied_animations))
        self.root.SetStatusText(pasted_msg)

        msg = ''
        if skipped_nodes:
            skipped_list = '\n'.join(
                [' * ' + node for node in sorted(skipped_nodes)])
            msg = 'The following animation nodes were skipped:\n' + skipped_list
        with MultiMessageDialog(self, pasted_msg, "Warning", msg,
                                wx.OK) as dlg:
            dlg.ShowModal()
Example #11
0
 def generate_xml(self, _, part_set):
     xml = part_set.generate_xml(color_db.bcs.part_colors)
     pyperclip.copy(xml)
     with MultiMessageDialog(self, "The generated XML has been copied to the clipboard", "Info", xml, wx.OK) as dlg:
         dlg.ShowModal()
Example #12
0
    def on_delete(self, _):
        items_to_delete = self.get_selected_root_nodes()
        if not items_to_delete:
            return

        for item in reversed(items_to_delete):
            data = self.entry_list.GetItemData(item)
            text = self.entry_list.GetItemText(item)
            parent = self.entry_list.GetItemParent(item)
            parent_data = self.entry_list.GetItemData(parent)
            index = -1
            conflicts = []
            # Get Index
            if not isinstance(data, list):
                index = int(text.split(':')[0])

            # Delete from BCS
            if isinstance(data, list) and isinstance(data[0], Physics):
                parent_data.physics.clear()
            elif isinstance(data, list) and isinstance(data[0], ColorSelector):
                parent_data.color_selectors.clear()
            elif isinstance(data, PartSet):
                color_db.bcs.part_sets.pop(index)
            elif isinstance(data, Part):
                name = text.split(':')[1].strip().replace(' ', '_').lower()
                parent_data.parts.pop(name)
            elif isinstance(data, ColorSelector):
                part_set_item = self.entry_list.GetItemParent(parent)
                part_set = self.entry_list.GetItemData(part_set_item)
                part_set.color_selectors.pop(index)
            elif isinstance(data, Physics):
                part_set_item = self.entry_list.GetItemParent(parent)
                part_set = self.entry_list.GetItemData(part_set_item)
                part_set.physics.pop(index)
            elif isinstance(data, PartColor):
                conflicts = self.check_color_conflicts(index)
                if conflicts:
                    msg = "\n".join([f"* Part Set {c[0]}, {c[1]}" for c in conflicts])
                    with MultiMessageDialog(self, f"Cannot delete Part Color {index}."
                                            "The following parts are still using it:",
                                            "Warning", msg, wx.OK) as dlg:
                        dlg.ShowModal()
                else:
                    color_db.bcs.part_colors.pop(index)
                    color_db.pop(index)
                    self.adjust_colors(index, delete=True)
            elif isinstance(data, Color):
                parent_text = self.entry_list.GetItemText(parent)
                parent_index = int(parent_text.split(':')[0])
                conflicts = self.check_color_conflicts(parent_index, index)
                if conflicts:
                    msg = "\n".join([f"* Part Set {c[0]}, {c[1]}" for c in conflicts])
                    with MultiMessageDialog(self, f"Cannot delete Part Color {parent_index}, Color {index}."
                                            "The following parts are still using it:",
                                            "Warning", msg, wx.OK) as dlg:
                        dlg.ShowModal()
                else:
                    parent_data.colors.pop(index)
                    color_db[parent_index].pop(index)
                    self.adjust_colors(parent_index, index, delete=True)
            elif isinstance(data, Body):
                color_db.bcs.bodies.pop(index)
            elif isinstance(data, BoneScale):
                parent_data.bone_scales.pop(index)
            elif isinstance(data, Skeleton):
                color_db.bcs.skeletons.pop(index)
            elif isinstance(data, Bone):
                parent_data.bones.pop(index)

            # Finally Delete from Tree
            if not conflicts:
                self.entry_list.Delete(item)

        pub.sendMessage(self.reindex_name)
        pub.sendMessage('set_status_bar', text="Deleted successfully")