# Path: vise/config.py
# def color(key, default):
#     ans = colors().get(key)
#     if not ans or ans == 'default':
#         ans = default
#     return ans
# 
# Path: vise/downloads.py
# DOWNLOAD_ICON_NAME = 'download.svg'
# 
# DOWNLOADS_URL = QUrl(DU)
# 
# Path: vise/resources.py
# def get_data_as_path(name):
#     base = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), 'resources')
#     return os.path.join(base, name)
# 
# @lru_cache(maxsize=512)
# def get_icon(name):
#     if not name.startswith('images/'):
#         name = 'images/' + name
#     return QIcon(get_data_as_path(name))
# 
# Path: vise/utils.py
# class RotatingIcon(QObject):
# 
#     updated = pyqtSignal(QPixmap)
# 
#     def __init__(self, icon_name='busy.svg', icon_size=24, duration=2, frames=120, parent=None):
#         QObject.__init__(self, parent)
#         pmap = get_icon(icon_name).pixmap(icon_size, icon_size)
#         self.interval = duration * 1000 // frames
#         self.timer = t = QTimer(self)
#         t.setInterval(self.interval)
#         t.timeout.connect(self.do_update)
#         self.frame_number = 0
#         self.frames = []
#         angle_delta = 360 / frames
#         angle = -angle_delta
#         for i in range(frames):
#             angle += angle_delta
#             p = pmap
#             if angle:
#                 p = self.rotated_by(pmap, angle)
#             self.frames.append(p)
# 
#     def rotated_by(self, pixmap, angle):
#         ans = pixmap.copy()
#         ans.fill(Qt.GlobalColor.transparent)
#         p = QPainter(ans)
#         p.setRenderHint(QPainter.RenderHint.SmoothPixmapTransform)
#         p.setRenderHint(QPainter.RenderHint.Antialiasing)
#         sz = ans.size().width() / ans.devicePixelRatio()
#         p.translate(sz // 2, sz // 2)
#         p.rotate(angle)
#         p.translate(-sz // 2, -sz // 2)
#         p.drawPixmap(0, 0, pixmap)
#         p.end()
#         return ans
# 
#     def do_update(self):
#         self.frame_number = (self.frame_number + 1) % len(self.frames)
#         self.updated.emit(self.frames[self.frame_number])
# 
#     @property
#     def first_frame(self):
#         return self.frames[0]
# 
#     def start(self):
#         self.timer.start()
# 
#     def stop(self):
#         self.timer.stop()
# 
# @lru_cache(maxsize=500)
# def elided_text(text, font=None, width=300, pos='middle'):
#     ''' Return a version of text that is no wider than width pixels when
#     rendered, replacing characters from the left, middle or right (as per pos)
#     of the string with an ellipsis. Results in a string much closer to the
#     limit than Qt's elidedText() '''
#     fm = QFontMetrics(QApplication.font()) if font is None else (font if isinstance(font, QFontMetrics) else QFontMetrics(font))
#     delta = 4
#     ellipsis = u'\u2026'
# 
#     def remove_middle(x):
#         mid = len(x) // 2
#         return x[:max(0, mid - (delta // 2))] + ellipsis + x[mid + (delta // 2):]
# 
#     chomp = {'middle': remove_middle, 'left': lambda x: (ellipsis + x[delta:]), 'right': lambda x: (x[:-delta] + ellipsis)}[pos]
#     while len(text) > delta and fm.horizontalAdvance(text) > width:
#         text = chomp(text)
#     return text
# 
# Path: vise/welcome.py
# WELCOME_URL = QUrl(WU)
# 
# def welcome_icon():
#     if not hasattr(welcome_icon, 'icon'):
#         welcome_icon.icon = get_icon('vise.svg')
#     return welcome_icon.icon


import string
import weakref
from contextlib import closing
from functools import partial
from gettext import gettext as _
from PyQt6.QtCore import QEvent, QRect, QRectF, QSize, Qt, QTimer, pyqtSignal
from PyQt6.QtGui import (QBrush, QColor, QFont, QIcon, QPainter, QPainterPath,
                         QPalette, QPen, QPixmap)
from PyQt6.QtWidgets import (QAbstractItemView, QApplication, QMenu, QStyle,
                             QStyledItemDelegate, QTreeWidget, QTreeWidgetItem)
from .config import color
from .downloads import DOWNLOAD_ICON_NAME, DOWNLOADS_URL
from .resources import get_data_as_path, get_icon
from .utils import RotatingIcon, elided_text
from .welcome import WELCOME_URL, welcome_icon

    def set_data(self, role, data):
        try:
            self.setData(0, role, data)
        except RuntimeError:
            pass

    def __hash__(self):
        return self.uid

    def has_ancestor(self, a):
        p = self.parent()
        while p:
            if p is a:
                return True
            p = p.parent()
        return False


class TabTree(QTreeWidget):

    tab_activated = pyqtSignal(object)
    tab_close_requested = pyqtSignal(object)
    delete_tabs = pyqtSignal(object)

    def __init__(self, parent):
        QTreeWidget.__init__(self, parent)
        self.deleted_parent_map = {}
        pal = self.palette()
        pal.setColor(QPalette.ColorRole.Highlight, pal.color(QPalette.ColorRole.Base))

# Path: vise/config.py
# def color(key, default):
#     ans = colors().get(key)
#     if not ans or ans == 'default':
#         ans = default
#     return ans
# 
# Path: vise/downloads.py
# DOWNLOAD_ICON_NAME = 'download.svg'
# 
# DOWNLOADS_URL = QUrl(DU)
# 
# Path: vise/resources.py
# def get_data_as_path(name):
#     base = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), 'resources')
#     return os.path.join(base, name)
# 
# @lru_cache(maxsize=512)
# def get_icon(name):
#     if not name.startswith('images/'):
#         name = 'images/' + name
#     return QIcon(get_data_as_path(name))
# 
# Path: vise/utils.py
# class RotatingIcon(QObject):
# 
#     updated = pyqtSignal(QPixmap)
# 
#     def __init__(self, icon_name='busy.svg', icon_size=24, duration=2, frames=120, parent=None):
#         QObject.__init__(self, parent)
#         pmap = get_icon(icon_name).pixmap(icon_size, icon_size)
#         self.interval = duration * 1000 // frames
#         self.timer = t = QTimer(self)
#         t.setInterval(self.interval)
#         t.timeout.connect(self.do_update)
#         self.frame_number = 0
#         self.frames = []
#         angle_delta = 360 / frames
#         angle = -angle_delta
#         for i in range(frames):
#             angle += angle_delta
#             p = pmap
#             if angle:
#                 p = self.rotated_by(pmap, angle)
#             self.frames.append(p)
# 
#     def rotated_by(self, pixmap, angle):
#         ans = pixmap.copy()
#         ans.fill(Qt.GlobalColor.transparent)
#         p = QPainter(ans)
#         p.setRenderHint(QPainter.RenderHint.SmoothPixmapTransform)
#         p.setRenderHint(QPainter.RenderHint.Antialiasing)
#         sz = ans.size().width() / ans.devicePixelRatio()
#         p.translate(sz // 2, sz // 2)
#         p.rotate(angle)
#         p.translate(-sz // 2, -sz // 2)
#         p.drawPixmap(0, 0, pixmap)
#         p.end()
#         return ans
# 
#     def do_update(self):
#         self.frame_number = (self.frame_number + 1) % len(self.frames)
#         self.updated.emit(self.frames[self.frame_number])
# 
#     @property
#     def first_frame(self):
#         return self.frames[0]
# 
#     def start(self):
#         self.timer.start()
# 
#     def stop(self):
#         self.timer.stop()
# 
# @lru_cache(maxsize=500)
# def elided_text(text, font=None, width=300, pos='middle'):
#     ''' Return a version of text that is no wider than width pixels when
#     rendered, replacing characters from the left, middle or right (as per pos)
#     of the string with an ellipsis. Results in a string much closer to the
#     limit than Qt's elidedText() '''
#     fm = QFontMetrics(QApplication.font()) if font is None else (font if isinstance(font, QFontMetrics) else QFontMetrics(font))
#     delta = 4
#     ellipsis = u'\u2026'
# 
#     def remove_middle(x):
#         mid = len(x) // 2
#         return x[:max(0, mid - (delta // 2))] + ellipsis + x[mid + (delta // 2):]
# 
#     chomp = {'middle': remove_middle, 'left': lambda x: (ellipsis + x[delta:]), 'right': lambda x: (x[:-delta] + ellipsis)}[pos]
#     while len(text) > delta and fm.horizontalAdvance(text) > width:
#         text = chomp(text)
#     return text
# 
# Path: vise/welcome.py
# WELCOME_URL = QUrl(WU)
# 
# def welcome_icon():
#     if not hasattr(welcome_icon, 'icon'):
#         welcome_icon.icon = get_icon('vise.svg')
#     return welcome_icon.icon


# Path: vise/tab_tree.py
import string
import weakref
from contextlib import closing
from functools import partial
from gettext import gettext as _
from PyQt6.QtCore import QEvent, QRect, QRectF, QSize, Qt, QTimer, pyqtSignal
from PyQt6.QtGui import (QBrush, QColor, QFont, QIcon, QPainter, QPainterPath,
                         QPalette, QPen, QPixmap)
from PyQt6.QtWidgets import (QAbstractItemView, QApplication, QMenu, QStyle,
                             QStyledItemDelegate, QTreeWidget, QTreeWidgetItem)
from .config import color
from .downloads import DOWNLOAD_ICON_NAME, DOWNLOADS_URL
from .resources import get_data_as_path, get_icon
from .utils import RotatingIcon, elided_text
from .welcome import WELCOME_URL, welcome_icon


    def set_data(self, role, data):
        try:
            self.setData(0, role, data)
        except RuntimeError:
            pass

    def __hash__(self):
        return self.uid

    def has_ancestor(self, a):
        p = self.parent()
        while p:
            if p is a:
                return True
            p = p.parent()
        return False


class TabTree(QTreeWidget):

    tab_activated = pyqtSignal(object)
    tab_close_requested = pyqtSignal(object)
    delete_tabs = pyqtSignal(object)

    def __init__(self, parent):
        QTreeWidget.__init__(self, parent)
        self.deleted_parent_map = {}
        pal = self.palette()
        pal.setColor(QPalette.ColorRole.Highlight, pal.color(QPalette.ColorRole.Base))

        pal.setColor(QPalette.ColorRole.HighlightedText, pal.color(QPalette.ColorRole.Text))