Beispiel #1
0
 def set_head_location(self, point, rotation):
     matrix = QMatrix()
     matrix.rotate(rotation)
     rotated_head_pixmap = self.head_pixmap.transformed(matrix)
     self.head_pixmap_item.setPixmap(rotated_head_pixmap)
     self.head_pixmap_item.setX(point.x)
     self.head_pixmap_item.setY(point.y)
 def paintVerticalCell(self, painter: QPainter, hv: QHeaderView,
                       cellIndex: QModelIndex, leafIndex: QModelIndex,
                       logicalLeafIndex: int,
                       styleOptions: QStyleOptionHeader,
                       sectionRect: QRect, left: int):
     uniopt = QStyleOptionHeader(styleOptions)
     self.setForegroundBrush(uniopt, cellIndex)
     self.setBackgroundBrush(uniopt, cellIndex)
     width = self.cellSize(cellIndex, hv, uniopt).width()
     if cellIndex == leafIndex:
         width = sectionRect.width() - left
     top = self.currentCellLeft(cellIndex, leafIndex, logicalLeafIndex,
                                sectionRect.top(), hv)
     height = self.currentCellWidth(cellIndex, leafIndex,
                                    logicalLeafIndex, hv)
     r = QRect(left, top, width, height)
     uniopt.text = cellIndex.data(Qt.DisplayRole)
     painter.save()
     uniopt.rect = r
     if cellIndex.data(Qt.UserRole):
         hv.style().drawControl(QStyle.CE_HeaderSection, uniopt,
                                painter, hv)
         m = QMatrix()
         m.rotate(-90)
         painter.setWorldMatrix(m, True)
         new_r = QRect(0, 0, r.height(), r.width())
         new_r.moveCenter(QPoint(-r.center().y(), r.center().x()))
         uniopt.rect = new_r
         hv.style().drawControl(QStyle.CE_HeaderLabel, uniopt, painter,
                                hv)
     else:
         hv.style().drawControl(QStyle.CE_Header, uniopt, painter, hv)
     painter.restore()
     return left + width
Beispiel #3
0
 def rotate(self, angle):
   matrix = QMatrix()
   matrix.rotate(angle)
   self.currentImage = self.currentImage.transformed(matrix)
   self.baseImage = self.baseImage.transformed(matrix)
   self.setPixmap(QPixmap.fromImage(self.currentImage))
   self.adjustSize()
Beispiel #4
0
 def __init__(self, parent):
     QLabel.__init__(self)
     self.parent = parent
     self.baseImage = QImage()
     self.matrix = QMatrix()
     self.zoomer = 1
     self.maxsize = 1024 * 10 * 10 * 10 * 25
     self.setSizePolicy(QSizePolicy.Ignored, QSizePolicy.Ignored)
     self.setAlignment(Qt.AlignCenter)
Beispiel #5
0
 def __init__(self):
   QLabel.__init__(self)
   #self.setSizePolicy(QSizePolicy.Ignored, QSizePolicy.Ignored)
   self.node = None
   self.angle = 0
   self.factor = 1
   self.imgWidth = 0
   self.baseImage = QImage()
   self.cpixmap = QPixmap()
   self.matrix = QMatrix()
Beispiel #6
0
 def __init__(self, parent):
     QLabel.__init__(self)
     self.parent = parent
     self.copyMenu = CopyMenu(self)
     self.copySelectionMenu = CopySelectionMenu(self)
     self.baseImage = QImage()
     self.matrix = QMatrix()
     self.zoomer = 1
     self.maxsize = 1024 * 10 * 10 * 10 * 25
     self.setSizePolicy(QSizePolicy.Ignored, QSizePolicy.Ignored)
     self.setAlignment(Qt.AlignCenter)
     self.rubberBand = None
Beispiel #7
0
    def setupTransformationMatrix(self, w, h):
        """
        use a matrix to translate in the gl landmark
        """

        m = QMatrix()
        m.translate(-w / 2, h / 2)
        m.scale(300. / w, 300. / h)
        print w, h, w / 300., 1 - ((h / 300) - 1)
        #m.scale((self.width()*100)/300, -(self.height()*100)/300)
        #self.currentSize.x = w
        #self.currentSize.y = h
        return m
Beispiel #8
0
 def _renderPixmaps(self):
     self._pixmaps=[]
     for i in range(self._steps+1):
         angle = int(i * 360.0 / self._steps)
         pixmap = QPixmap(self._resource)
         # if problem with loading png
         if pixmap.size().width()==0:
             self._pixmaps=None
             return
         rotate_matrix = QMatrix()
         rotate_matrix.rotate(angle)
         pixmap_rotated = pixmap.transformed(rotate_matrix)
         pixmap_moved = QPixmap(pixmap.size())
         pixmap_moved.fill(Qt.transparent)
         painter = QPainter()
         painter.begin(pixmap_moved)
         painter.drawPixmap((pixmap_moved.width() - pixmap_rotated.width()) / 2.0, (pixmap_moved.height() - pixmap_rotated.height()) / 2.0, pixmap_rotated)
         painter.end()
         self._pixmaps+=[pixmap_moved.scaled(self._width, self._height)]
    def play(self):

        line = 0

        scene_info = self.nonstop.script_pack[line].scene_info
        sprite_id = scene_info.sprite
        sprite_id.sprite_type = SPRITE_TYPE.stand
        sprite = get_sprite(sprite_id)

        self.lblSprite = QLabel(self.ui.lblPreview)
        self.lblSprite.setGeometry(0, 0, 480, 272)

        qt_pixmap = QtGui.QPixmap.fromImage(sprite)
        self.lblSprite.setPixmap(qt_pixmap)

        line = 18

        text_img = self.lines[line]
        line_info = self.nonstop.lines[line]

        matrix = QMatrix()
        matrix.rotate(line_info.rot_angle)
        matrix.scale(line_info.zoom_start / 100.0,
                     line_info.zoom_start / 100.0)

        text_img = text_img.transformed(matrix, Qt.Qt.SmoothTransformation)

        x_start = line_info.x_start - (text_img.width() / 2.0)
        y_start = line_info.y_start - (text_img.height() / 2.0)
        x_vel = line_info.velocity * math.cos(
            math.radians(90 - line_info.angle))
        y_vel = -line_info.velocity * math.sin(
            math.radians(90 - line_info.angle))

        time_visible = line_info.time_visible / 60.0

        width_start = text_img.width()
        height_start = text_img.height()
        width_end = width_start * (
            (line_info.zoom_change / 100.0)**time_visible)
        height_end = height_start * (
            (line_info.zoom_change / 100.0)**time_visible)

        x_end = x_start + (x_vel * time_visible)
        y_end = y_start + (y_vel * time_visible)
        #x_end = line_info.x_start + (x_vel * time_visible) - (width_end / 2.0)
        #y_end = line_info.y_start + (y_vel * time_visible) - (height_end / 2.0)

        print x_start, y_start, width_start, height_start, line_info.zoom_start
        print x_end, y_end, width_end, height_end

        self.lblText = QLabel(self.ui.lblPreview)
        self.lblText.setGeometry(x_start, y_start, text_img.width(),
                                 text_img.height())
        #self.lblText2 = QLabel(self.ui.lblPreview)
        #self.lblText2.setGeometry(x_end, y_end, text_img.width(), text_img.height())

        qt_pixmap = QtGui.QPixmap.fromImage(text_img)
        self.lblText.setPixmap(qt_pixmap)
        #self.lblText2.setPixmap(qt_pixmap)

        self.anim = QtCore.QPropertyAnimation(self.lblText, "geometry")
        self.anim.setDuration(time_visible * 1000)
        self.anim.setStartValue(
            QRectF(x_start, y_start, width_start, height_start))
        self.anim.setEndValue(QRectF(x_end, y_end, width_start, height_start))

        self.anim.start()
def paintVerticalCell(self, painter: QPainter, hv: QHeaderView, cellIndex: QModelIndex, leafIndex: QModelIndex, logicalLeafIndex: int, styleOptions: QStyleOptionHeader, sectionRect: QRect, left: int):
uniopt = QStyleOptionHeader(styleOptions)
self.setForegroundBrush(uniopt, cellIndex)
self.setBackgroundBrush(uniopt, cellIndex)
width=self.cellSize(cellIndex, hv, uniopt).width()
if cellIndex==leafIndex:
    width=sectionRect.width()-left
top=self.currentCellLeft(cellIndex, leafIndex, logicalLeafIndex, sectionRect.top(), hv)
height=self.currentCellWidth(cellIndex, leafIndex, logicalLeafIndex, hv)
r = QRect(left, top, width, height)
uniopt.text = cellIndex.data(Qt.DisplayRole)
painter.save()
uniopt.rect = r
if cellIndex.data(Qt.UserRole):
    hv.style().drawControl(QStyle.CE_HeaderSection, uniopt, painter, hv)
    m = QMatrix()
    m.rotate(-90)
    painter.setWorldMatrix(m, True)
    new_r = QRect(0, 0,  r.height(), r.width())
    new_r.moveCenter(QPoint(-r.center().y(), r.center().x()))
    uniopt.rect = new_r
    hv.style().drawControl(QStyle.CE_HeaderLabel, uniopt, painter, hv)
else:
    hv.style().drawControl(QStyle.CE_Header, uniopt, painter, hv)
painter.restore()
return left+width

def paintVerticalSection(self, painter: QPainter, sectionRect: QRect, logicalLeafIndex: int, hv: QHeaderView, styleOptions: QStyleOptionHeader, leafIndex: QModelIndex):
oldBO = painter.brushOrigin()
left = sectionRect.x()
indexes = QModelIndexList(self.parentIndexes(leafIndex))
for i in range(indexes.size()):
    realStyleOptions = QStyleOptionHeader(styleOptions)
    if i<indexes.size()-1 and (realStyleOptions.state&QStyle.State_Sunken or realStyleOptions.state&QStyle.State_On):
        t = QStyle.State(QStyle.State_Sunken | QStyle.State_On)
        realStyleOptions.state = realStyleOptions.state&~t #FIXME: parent items are not highlighted
    left=self.paintVerticalCell(painter, hv, indexes[i], leafIndex, logicalLeafIndex, realStyleOptions, sectionRect, left)
painter.setBrushOrigin(oldBO)

def __init__(self, orientation: Qt.Orientation, parent: QWidget):
super().__init__(orientation, parent)
self._pd = self.private_data()
self.sectionResized.connect(self.on_sectionResized)
self.setHighlightSections(self.options.get("highlightSections"))
self.setClickable(self.options.get("clickable"))
self.show() #force to be visible
getattr(parent, "set%sHeader"%("Horizontal", "Vertical")[orientation!=Qt.Horizontal])(self)
self.sectionMoved.connect(self.on_sectionMoved)

def on_sectionMoved(self, logicalIndex, oldVisualIndex, newVisualIndex):
    view, model = self.parent(), self.parent().model()
    if not hasattr(model, "reorder"):
        return #reorder underlying data of models with /reorder/ def only
    if getattr(self, "manual_move", False):
        self.manual_move=False
        return
    self.manual_move=True
    self.moveSection(newVisualIndex, oldVisualIndex) #cancel move
    if model.reorder(oldVisualIndex, newVisualIndex, self.orientation()):
        #Reorder column widths / row heights
        horizontal = self.orientation()==Qt.Horizontal
        itemSize = (view.rowHeight, view.columnWidth)[horizontal]
        setItemSize = (view.setRowHeight, view.setColumnWidth)[horizontal]
        rng = sorted((oldVisualIndex, newVisualIndex))
        options = [(itemSize(i), i) for i in range(rng[0], rng[1]+1)]
        options.insert(newVisualIndex-rng[0], options.pop(oldVisualIndex-rng[0]))
        for i, col in enumerate(range(rng[0], rng[1]+1)):
            setItemSize(col, options[i][0])
        getattr(view, "select"+("Row", "Column")[horizontal])(newVisualIndex) #FIXME: don't select if sorting is enable?
        if self.isSortIndicatorShown():
            sortIndIndex = next((i for i, o in enumerate(options) if o[1]==self.sortIndicatorSection()), None)
            if sortIndIndex is not None: #sort indicator is among sections being reordered
                self.setSortIndicator(sortIndIndex+rng[0], self.sortIndicatorOrder()) #FIXME: does unnecessary sorting
        model.layoutChanged.emit() #update view

def styleOptionForCell(self, logicalInd: int)->QStyleOptionHeader:
opt = QStyleOptionHeader()
self.initStyleOption(opt)
if self.isSortIndicatorShown() and self.sortIndicatorSection()==logicalInd:
    opt.sortIndicator = (QStyleOptionHeader.SortUp, QStyleOptionHeader.SortDown)[self.sortIndicatorOrder()==Qt.AscendingOrder]
if self.window().isActiveWindow():
    opt.state = opt.state|QStyle.State_Active
opt.textAlignment = Qt.AlignCenter
opt.iconAlignment = Qt.AlignVCenter
opt.section = logicalInd
visual = self.visualIndex(logicalInd)
if self.count() == 1:
    opt.position = QStyleOptionHeader.OnlyOneSection
else:
    if visual == 0:
        opt.position = QStyleOptionHeader.Beginning
    else:
        opt.position = QStyleOptionHeader.End if visual==self.count()-1 else QStyleOptionHeader.Middle
if self.isClickable():
    #            if logicalIndex == d.hover:
    #            ...
    if self.highlightSections() and self.selectionModel():
        if self.orientation()==Qt.Horizontal:
            if self.selectionModel().columnIntersectsSelection(logicalInd, self.rootIndex()):
                opt.state = opt.state|QStyle.State_On
            if self.selectionModel().isColumnSelected(logicalInd, self.rootIndex()):
                opt.state = opt.state|QStyle.State_Sunken
        else:
            if self.selectionModel().rowIntersectsSelection(logicalInd, self.rootIndex()):
                opt.state = opt.state|QStyle.State_On
            if self.selectionModel().isRowSelected(logicalInd, self.rootIndex()):
                opt.state = opt.state|QStyle.State_Sunken
if self.selectionModel():
    previousSelected=False
    if self.orientation()==Qt.Horizontal:
        previousSelected = self.selectionModel().isColumnSelected(self.logicalIndex(visual - 1), self.rootIndex())
    else:
        previousSelected = self.selectionModel().isRowSelected(self.logicalIndex(visual - 1), self.rootIndex())
    nextSelected=False
    if self.orientation()==Qt.Horizontal:
        nextSelected = self.selectionModel().isColumnSelected(self.logicalIndex(visual + 1), self.rootIndex())
    else:
        nextSelected = self.selectionModel().isRowSelected(self.logicalIndex(visual + 1), self.rootIndex())
    if previousSelected and nextSelected:
        opt.selectedPosition = QStyleOptionHeader.NextAndPreviousAreSelected
    else:
        if previousSelected:
            opt.selectedPosition = QStyleOptionHeader.PreviousIsSelected
        else:
            if nextSelected:
                opt.selectedPosition = QStyleOptionHeader.NextIsSelected
            else:
                opt.selectedPosition = QStyleOptionHeader.NotAdjacent
return opt

def sectionSizeFromContents(self, logicalIndex: int)->QSize:
if self._pd.headerModel:
    curLeafIndex = QModelIndex(self._pd.leafIndex(logicalIndex))
    if curLeafIndex.isValid():
        styleOption = QStyleOptionHeader(self.styleOptionForCell(logicalIndex))
        s = QSize(self._pd.cellSize(curLeafIndex, self, styleOption))
        curLeafIndex=curLeafIndex.parent()
        while curLeafIndex.isValid():
            if self.orientation() == Qt.Horizontal:
                s.setHeight(s.height()+self._pd.cellSize(curLeafIndex, self, styleOption).height())
            else:
                s.setWidth(s.width()+self._pd.cellSize(curLeafIndex, self, styleOption).width())
            curLeafIndex=curLeafIndex.parent()
        return s
return super().sectionSizeFromContents(logicalIndex)

def paintSection(self, painter: QPainter, rect: QRect, logicalIndex: int):
if rect.isValid():
    leafIndex = QModelIndex(self._pd.leafIndex(logicalIndex))
    if leafIndex.isValid():
        if self.orientation() == Qt.Horizontal:
            self._pd.paintHorizontalSection(painter, rect, logicalIndex, self, self.styleOptionForCell(logicalIndex), leafIndex)
        else:
            self._pd.paintVerticalSection(painter, rect, logicalIndex, self, self.styleOptionForCell(logicalIndex), leafIndex)
        return
super().paintSection(painter, rect, logicalIndex)

def on_sectionResized(self, logicalIndex: int):
if self.isSectionHidden(logicalIndex):
    return
leafIndex = QModelIndex(self._pd.leafIndex(logicalIndex))
if leafIndex.isValid():
    leafsList = QModelIndexList(self._pd.leafs(self._pd.findRootIndex(leafIndex)))
    for n in range(leafsList.indexOf(leafIndex), 0, -1):
        logicalIndex-=1
        w = self.viewport().width()
        h = self.viewport().height()
        pos = self.sectionViewportPosition(logicalIndex)
        r = QRect(pos, 0, w - pos, h)
        if self.orientation() == Qt.Horizontal:
            if self.isRightToLeft():
                r.setRect(0, 0, pos + self.sectionSize(logicalIndex), h)
        else:
            r.setRect(0, pos, w, h - pos)
        self.viewport().update(r.normalized())

def setModel(self, model):
    super().setModel(model)
    model.layoutChanged.connect(self.layoutChanged)
    self.layoutChanged()

def layoutChanged(self):
    if self.model():
        self._pd.initFromNewModel(self.orientation(), self.model())
        axis = ("column", "row")[self.orientation()!=Qt.Horizontal]
        cnt = getattr(self.model(), axis+"Count")(QModelIndex())
        if cnt:
            self.initializeSections(0, cnt-1)
MultiIndexHeaderView=HierarchicalHeaderView

class DataFrameModel(QtCore.QAbstractTableModel):
    #na_values:least|greatest - for sorting
    options = {"striped": True, "stripesColor": "#fafafa", "na_values": "least",
               "tooltip_min_len": 21}
    def __init__(self, dataframe=None):
        super().__init__()
        self.setDataFrame(dataframe if dataframe is not None else pd.DataFrame())

    def setDataFrame(self, dataframe):
        self.df = dataframe.copy()
        #        self.df_full = self.df
        self.layoutChanged.emit()

    def rowCount(self, parent):
        return len(self.df)

    def columnCount(self, parent):
        return len(self.df.columns)

    def readLevel(self, y=0, xs=0, xe=None, orient=None):
        c = getattr(self.df, ("columns", "index")[orient!=HorizontalHeaderDataRole])
        if not hasattr(c, "levels"): #not MultiIndex
            return [QtGui.QStandardItem(str(i)) for i in c]
        sibl = []
        section_start, v, xe = xs, None, xe or len(c)
        for i in range(xs, xe):
            label = c.labels[y][i]
            if label!=v:
                if y+1<len(c.levels) and i>xs:
                    children = self.readLevel(y+1, section_start, i, orient=orient)
                    sibl[-1].appendRow(children)
                item = QtGui.QStandardItem(str(c.levels[y][label]))
                sibl.append(item)
                section_start = i
                v=label
        if y+1<len(c.levels):
            children = self.readLevel(y+1, section_start, orient=orient)
            sibl[-1].appendRow(children)
        return sibl

    def data(self, index, role):
        row, col = index.row(), index.column()
        if role in (Qt.DisplayRole, Qt.ToolTipRole):
            ret = self.df.iat[row, col]
            if ret is not None and ret==ret: #convert to str except for None, NaN, NaT
                if isinstance(ret, float):
                    ret = "{:n}".format(ret)
                elif isinstance(ret, datetime.date):
                    #FIXME: show microseconds optionally
                    ret = ret.strftime(("%x", "%c")[isinstance(ret, datetime.datetime)])
                else: ret = str(ret)
                if role == Qt.ToolTipRole:
                    if len(ret)<self.options["tooltip_min_len"]: ret = ""
                return ret
        elif role == Qt.BackgroundRole:
            if self.options["striped"] and row%2:
                return QBrush(QColor(self.options["stripesColor"]))
        elif role in (HorizontalHeaderDataRole, VerticalHeaderDataRole):
            hm = QtGui.QStandardItemModel()
            hm.appendRow(self.readLevel(orient=role))
            return hm

    def reorder(self, oldIndex, newIndex, orientation):
        "Reorder columns / rows"
        horizontal = orientation==Qt.Horizontal
        cols = list(self.df.columns if horizontal else self.df.index)
        cols.insert(newIndex, cols.pop(oldIndex))
        self.df = self.df[cols] if horizontal else self.df.T[cols].T
        return True

    #    def filter(self, filt=None):
    #        self.df = self.df_full if filt is None else self.df[filt]
    #        self.layoutChanged.emit()

    def headerData(self, section, orientation, role):
        if role != Qt.DisplayRole: return
        label = getattr(self.df, ("columns", "index")[orientation!=Qt.Horizontal])[section]
        #        return label if type(label) is tuple else label
        return ("\n", " | ")[orientation!=Qt.Horizontal].join(str(i) for i in label) if type(label) is tuple else str(label)

    def dataFrame(self):
        return self.df

    def sort(self, column, order):
        #        print("sort", column, order) #FIXME: double sort after setSortingEnabled(True)
        if len(self.df):
            asc = order==Qt.AscendingOrder
            na_pos = 'first' if (self.options["na_values"]=="least")==asc else 'last'
            self.df.sort_values(self.df.columns[column], ascending=asc,
                                inplace=True, na_position=na_pos)
            self.layoutChanged.emit()

if __name__=="__main__":
    import sys, locale
    locale.setlocale(locale.LC_ALL, '') #system locale settings
    app = QtGui.QApplication(sys.argv)
    form = QtGui.QWidget()
    form.setAttribute(Qt.WA_DeleteOnClose) #http://stackoverflow.com/a/27178019/1119602
    form.setMinimumSize(700, 260)
    view = QtGui.QTableView()
    QtGui.QVBoxLayout(form).addWidget(view)
    form.show()

    #Prepare data
    tuples=[('bar', 'one', 'q'), ('bar', 'two', 'q'), ('baz', 'one', 'q'), ('baz', 'two', 'q'),
            ('foo', 'one', 'q'), ('foo', 'two', 'q'), ('qux', 'one', 'q'), ('qux', 'two', 'q')]
    index = pd.MultiIndex.from_tuples(tuples, names=['first', 'second', 'third'])
    df=pd.DataFrame(pd.np.random.randn(6, 6), index=index[:6], columns=index[:6])
    print("DataFrame:\n%s"%df)

    #Prepare view
    #    oldh, oldv = view.horizontalHeader(), view.verticalHeader()
    #    oldh.setParent(form), oldv.setParent(form) #Save old headers for some reason
    MultiIndexHeaderView(Qt.Horizontal, view)
    MultiIndexHeaderView(Qt.Vertical, view)
    view.horizontalHeader().setMovable(True) #reorder DataFrame columns manually

    #Set data
    view.setModel(DataFrameModel(df))
    view.resizeColumnsToContents()
    view.resizeRowsToContents()

    #Set sorting enabled (after setting model)
    view.setSortingEnabled(True)
    sys.exit(app.exec())
Beispiel #11
0
 def matrix(self):
     return QMatrix(self.scaleFactor * self.physicalDpiX() / 72.0, 0, 0,
                    self.scaleFactor * self.physicalDpiY() / 72.0, 0, 0)
Beispiel #12
0
    def show_line(self, line, queue_next=True):

        scene_info = self.nonstop.script_pack[line].scene_info
        voice = scene_info.voice
        format = scene_info.format
        sprite_id = scene_info.sprite
        sprite_id.sprite_type = SPRITE_TYPE.stand
        sprite = get_sprite(sprite_id)

        if self.auto_play:
            self.voice_player.play(voice)

        if sprite:
            qt_pixmap = QtGui.QPixmap.fromImage(sprite)
            self.lblSprite.setPixmap(qt_pixmap)

        text_img = self.lines[line]
        line_info = self.nonstop.lines[line]

        matrix = QMatrix()
        matrix.rotate(line_info.rot_angle -
                      (90 if format.orient == TEXT_ORIENT.ver else 0))
        text_img = text_img.transformed(matrix, Qt.Qt.SmoothTransformation)

        time_visible = line_info.time_visible / 60.0

        width_start = text_img.width() * line_info.zoom_start / 100.0
        height_start = text_img.height() * line_info.zoom_start / 100.0
        width_end = width_start * (
            (line_info.zoom_change / 100.0)**time_visible)
        height_end = height_start * (
            (line_info.zoom_change / 100.0)**time_visible)

        x_start = line_info.x_start - (width_start / 2.0)
        y_start = line_info.y_start - (height_start / 2.0)
        x_vel = line_info.velocity * math.cos(
            math.radians(90 - line_info.angle))
        y_vel = -line_info.velocity * math.sin(
            math.radians(90 - line_info.angle))

        x_end = x_start + (x_vel * time_visible) - (
            (width_end - width_start) / 2.0)
        y_end = y_start + (y_vel * time_visible) - (
            (height_end - height_start) / 2.0)

        self.labels[line] = QLabel(self.ui.lblPreview)
        self.labels[line].setScaledContents(True)
        self.labels[line].setGeometry(x_start, y_start, text_img.width(),
                                      text_img.height())
        self.labels[line].setPixmap(text_img)
        self.labels[line].show()

        self.anims[line] = QtCore.QPropertyAnimation(self.labels[line],
                                                     "geometry")
        self.anims[line].setDuration(time_visible * 1000)
        self.anims[line].setStartValue(
            QRectF(x_start, y_start, width_start, height_start))
        self.anims[line].setEndValue(
            QRectF(x_end, y_end, width_end, height_end))
        self.anims[line].finished.connect(lambda: self._finished(line))

        self.anims[line].start(QtCore.QAbstractAnimation.DeleteWhenStopped)

        if queue_next:
            next_line = line + 1
            if next_line < len(self.lines):
                self.timers[line] = QtCore.QTimer()
                self.timers[line].timeout.connect(
                    lambda: self.show_line(next_line, queue_next=True))
                self.timers[line].setSingleShot(True)
                self.timers[line].start(line_info.delay / 60.0 * 1000)
def get_letter(clt, char):
  
  if not clt in CLT:
    clt = 0
  
  font    = CLT[clt]['font']
  hscale  = CLT[clt]['hscale']
  vscale  = CLT[clt]['vscale']
  
  try:
    info = FONT_DATA[font][char]
  except:
    # This is the character the game replaces unknown characters with.
    info = FONT_DATA[font][u'\u2261']
  
  expand_l = 0
  expand_r = 0
  expand_t = 0
  expand_b = 0
  
  if clt in CLT_EXPAND:
    expand_l = CLT_EXPAND[clt][0]
    expand_r = CLT_EXPAND[clt][1]
    expand_t = CLT_EXPAND[clt][2]
    expand_b = CLT_EXPAND[clt][3]
  
  box = QRect(info['x'] - expand_l, info['y'] - expand_t, info['w'] + expand_l + expand_r, info['h'] + expand_t + expand_b)
  #box = QRect(info['x'] - expand_l, info['y'] - expand_t, info['w'], info['h'])
  
  if clt in CLT_BORDER:
    expand_l += CLT_BORDER[clt]['size']
    expand_r += CLT_BORDER[clt]['size']
    expand_t += CLT_BORDER[clt]['size']
    expand_b += CLT_BORDER[clt]['size']
  
  xshift = -expand_l
  yshift = -expand_t
  
  if font == 1:
    yshift += 6
  #elif font == 2:
    #yshift += 2
  
  base_w = info['w'] + expand_l + expand_r
  base_h = info['h'] + expand_t + expand_b
  
  final_w = base_w
  final_h = base_h
  
  if hscale != 1.0:
    final_w = (final_w * hscale)
  
  if vscale != 1.0:
    old_h   = final_h
    final_h = (final_h * vscale)
    
    yshift = yshift + old_h - final_h
  
  letter = FONTS[CLT[clt]['font']].copy(box)
  
  if hscale != 1.0 or vscale != 1.0:
    matrix = QMatrix()
    matrix.scale(hscale, vscale)
    letter = letter.transformed(matrix, Qt.Qt.SmoothTransformation)
    #letter = letter.scaled(int(final_w), int(final_h), Qt.Qt.IgnoreAspectRatio, Qt.Qt.SmoothTransformation)
  
  if clt in CLT_INSIDE:
    if 'color' in CLT_INSIDE[clt]:
      letter = replace_all_colors(letter, CLT_INSIDE[clt]['color'])
    elif 'gradient' in CLT_INSIDE[clt]:
      letter = add_v_gradient(letter, CLT_INSIDE[clt]['gradient'])
  
  if clt in CLT_BORDER:
    letter = add_border(letter, CLT_BORDER[clt]['color'], CLT_BORDER[clt]['size'])
  
  return letter, (xshift, yshift, final_w, final_h)