diff --git a/.gitignore b/.gitignore
index 2e635ba..5c0fa89 100644
--- a/.gitignore
+++ b/.gitignore
@@ -139,3 +139,4 @@ history.db
commies/
test/
src/data/cache_word
+src/data/local_read.db
diff --git a/src/component/list/comic_list_widget.py b/src/component/list/comic_list_widget.py
index bf184b6..d934f68 100644
--- a/src/component/list/comic_list_widget.py
+++ b/src/component/list/comic_list_widget.py
@@ -115,9 +115,9 @@ def AddBookByLocal(self, v, category=""):
widget.picNum = v.picCnt
widget.url = v.file
if len(v.eps) > 0:
- title += "{}".format("(" + str(len(v.eps)) + "E)")
+ fontColor = "{}".format("(" + str(len(v.eps)) + "E)")
else:
- title += "{}".format("(" + str(v.picCnt) + "P)")
+ fontColor = "{}".format("(" + str(v.picCnt) + "P)")
if v.lastReadTime:
categories = "{} {}".format(ToolUtil.GetUpdateStrByTick(v.lastReadTime), Str.GetStr(Str.Looked))
@@ -132,7 +132,9 @@ def AddBookByLocal(self, v, category=""):
widget.categoryLabel.setVisible(True)
widget.toolButton.setVisible(False)
- widget.nameLable.setText(title)
+ # widget.nameLable.setText(title)
+ widget.SetTitle(title,fontColor)
+
item = QListWidgetItem(self)
item.setFlags(item.flags() & ~Qt.ItemIsSelectable)
item.setSizeHint(widget.sizeHint())
@@ -200,13 +202,15 @@ def AddBookItem(self, _id, title, categoryStr="", url="", path="", likesCount=""
widget.starButton.setVisible(True)
else:
widget.starButton.setVisible(False)
-
+ fontColor = ""
if pagesCount:
- title += "{}".format("("+str(pagesCount)+"P)")
- if finished:
- title += "{}".format("({})".format(Str.GetStr(Str.ComicFinished)))
+ fontColor += "{}".format("("+str(pagesCount)+"P)")
+ # if finished:
+ # fontColor += "{}".format("({})".format(Str.GetStr(Str.ComicFinished)))
+
+ # widget.nameLable.setText(title)
- widget.nameLable.setText(title)
+ widget.SetTitle(title,fontColor)
item = QListWidgetItem(self)
item.setFlags(item.flags() & ~Qt.ItemIsSelectable)
item.setSizeHint(widget.sizeHint())
diff --git a/src/component/scroll/read_scroll.py b/src/component/scroll/read_scroll.py
index 94797cc..fbf062c 100644
--- a/src/component/scroll/read_scroll.py
+++ b/src/component/scroll/read_scroll.py
@@ -1,40 +1,228 @@
+import weakref
+
from PySide6.QtCore import QPropertyAnimation, QEasingCurve, QAbstractAnimation
from PySide6.QtWidgets import QScrollBar
from qt_owner import QtOwner
+from tools.str import Str
+from view.read.read_enum import ReadMode
class ReadScroll(QScrollBar):
- def __init__(self):
+ def __init__(self, parent):
QScrollBar.__init__(self)
- self.animation = QPropertyAnimation()
- self.animation.setTargetObject(self)
- self.animation.setPropertyName(b"value")
- self.scrollTime = 1000
- self.animation.setDuration(self.scrollTime)
- self.animation.setEasingCurve(QEasingCurve.Linear)
- self.animationValue = self.value()
- self.backTick = 0
- self.laveValue = 0
- self.lastV = 0
- self.animation.finished.connect(self.Finished)
+ self._owner = weakref.ref(parent)
+ self.scrollTime = 200
+ self.maxScrollTme = 500
+ self.maxRate = 10
+
+ self.ani = QPropertyAnimation()
+ self.ani.setTargetObject(self)
+ self.ani.setPropertyName(b"value")
+ self.ani.setEasingCurve(QEasingCurve.Linear)
+ self.ani.setDuration(self.scrollTime)
+ self.__value = self.value()
+ self.ani.finished.connect(self.Finished)
+ self.setSingleStep(1)
+ # self.oldupdateCurrentValue = self.ani.updateCurrentValue
+ # self.ani.updateCurrentValue = self.UpdateCurrentValue
+ # self.ani.valueChanged.connect(self.AniValueChange)
+ self.priV = 0
+
+ self.lastAniStartV = 0
+ self.lastAniEndV = 0
+ self.lastScrollTime = 0
+ # self.valueChanged.connect(self.ValueChange)
+ self.oldv = 0
+
+ # def ValueChange(self,value):
+ # self.oldv = value
+ # print("2, {}".format(value))
+
+ # def AniValueChange(self, value):
+ # print("1, {}".format(value))
+
+ #
+ # def UpdateCurrentValue(self, value):
+ # print("2, {}".format(value))
+ # self.oldupdateCurrentValue(value)
+
+ def ResetAniValueByAdd(self, oldV, addV):
+ # print("reset1 setV, {}".format(oldV+addV))
+ QScrollBar.setValue(self, oldV+addV)
+ changeV = self.lastAniEndV - self.lastAniStartV
+ laveV = self.lastAniEndV - oldV
+ scrollTime = 0
+ if changeV != 0:
+ scrollTime = min(self.maxScrollTme, int(laveV / changeV * self.lastScrollTime))
+ if scrollTime > 0:
+ self.ani.stop()
+ self.StartAni(self.value(), self.lastAniEndV, scrollTime)
+ else:
+ self.ani.stop()
+ self.StartAni(self.value(), self.value(), self.scrollTime)
+
+ def AniValueByAdd(self, addV):
+ changeV = self.lastAniEndV - self.lastAniStartV
+ addV2 = self.lastAniEndV - self.value()
+ self.lastAniStartV = self.value()
+ if addV <= 0 :
+ v = max(self.maxRate * addV, addV + addV2)
+ else:
+ v = min(self.maxRate * addV, addV + addV2)
+ self.lastAniEndV = self.lastAniStartV + v
+ laveV = self.lastAniEndV - self.lastAniStartV
+
+ scrollTime = 0
+ if changeV != 0:
+ scrollTime = min(self.maxScrollTme, int(laveV / changeV * self.lastScrollTime))
+ if scrollTime <= 0:
+ scrollTime = self.scrollTime
+
+ # print("add setV, {}".format(self.lastAniEndV))
+ self.ani.stop()
+ self.StartAni(self.value(), self.lastAniEndV, scrollTime)
+
+ # def AniValueChange(self, value):
+ # print("{}, {}".format(value, value - self.priV))
+ # self.priV = value
+
+ @property
+ def frame(self):
+ return self._owner()
+
+ @property
+ def scrollArea(self):
+ return self._owner().scrollArea
+
+ @property
+ def labelSize(self):
+ return self.scrollArea.labelSize
+
+ @property
+ def readImg(self):
+ return self.scrollArea.readImg
def Finished(self):
- QtOwner().owner.readView.frame.scrollArea.OnValueChange(self.value())
+ self.OnValueChange(self.value())
def StopScroll(self):
- self.backTick = 0
- self.animation.stop()
-
- def Scroll(self, value, time=0):
- if self.animation.state() == QAbstractAnimation.State.Running:
- self.animation.stop()
- oldValue = self.value()
- self.animation.setStartValue(oldValue)
- if not time:
- self.animation.setDuration(self.scrollTime)
+ self.ani.stop()
+ #
+ # def Scroll(self, value, time=0):
+ # if self.ani.state() == QAbstractAnimation.State.Running:
+ # self.ani.stop()
+ # oldValue = self.value()
+ # self.ani.setStartValue(oldValue)
+ # if not time:
+ # self.ani.setDuration(self.scrollTime)
+ # else:
+ # self.ani.setDuration(time)
+ # self.ani.setEndValue(oldValue + value)
+ # self.ani.start()
+
+ def ForceSetValue(self, value):
+ self.ani.stop()
+ # print("force setV, {}".format(value))
+ QScrollBar.setValue(self, value)
+ self.StartAni(value, value, self.scrollTime)
+
+ def StartAni(self, start, end, duration):
+ self.lastAniEndV = end
+ self.lastAniStartV = start
+ self.lastScrollTime = duration
+ self.ani.setStartValue(start)
+ self.ani.setEndValue(end)
+ self.ani.setDuration(duration)
+ self.ani.start()
+
+ def setValue(self, value: int):
+ # print("setV, {}".format(value))
+ if value == self.value():
+ return
+
+ # stop running animation
+ if self.ani.state() == self.ani.State.Running:
+ self.AniValueByAdd(value-self.value())
+ else:
+ self.ani.stop()
+ self.StartAni(self.value(), value, self.scrollTime)
+
+ def scrollValue(self, value: int):
+ """ scroll the specified distance """
+ # self.__value += value
+ # self.__value = max(self.minimum(), self.__value)
+ # self.__value = min(self.maximum(), self.__value)
+ self.setValue(self.value()+value)
+
+ # def scrollTo(self, value: int):
+ # """ scroll to the specified position """
+ # self.__value = value
+ # self.__value = max(self.minimum(), self.__value)
+ # self.__value = min(self.maximum(), self.__value)
+ # self.setValue(self.__value)
+
+ def OnValueChange(self, value):
+ addValue = value - self.__value
+ # self.UpdateScrollBar(value)
+ self.__value = value
+
+ if not ReadMode.isScroll(self.scrollArea.initReadMode):
+ return
+
+ curPictureSize = self.labelSize.get(self.readImg.curIndex)
+ nextPictureSize = self.labelSize.get(self.readImg.curIndex + 1, 0)
+ changeIndex = self.readImg.curIndex
+ if self.scrollArea.initReadMode == ReadMode.RightLeftScroll:
+ newValue = value + self.scrollArea.width()
+ while True:
+ ## 切换上一图片
+ if addValue > 0 and newValue >= nextPictureSize:
+ if changeIndex <= 0:
+ break
+ changeIndex -= 1
+ # print(self.readImg.curIndex)
+
+ # self.scrollArea.changeLastPage.emit(self.readImg.curIndex)
+
+ ## 切换下一图片
+ elif addValue < 0 and newValue < curPictureSize:
+ if changeIndex >= self.readImg.maxPic - 1:
+ break
+ changeIndex += 1
+ # print(self.readImg.curIndex)
+ # self.scrollArea.changeNextPage.emit(self.readImg.curIndex)
+ else:
+ break
+ curPictureSize = self.labelSize.get(changeIndex)
+ nextPictureSize = self.labelSize.get(changeIndex + 1, 0)
else:
- self.animation.setDuration(time)
- self.animation.setEndValue(oldValue + value)
- self.animation.start()
+ while True:
+ ## 切换上一图片
+ if addValue < 0 and value < curPictureSize:
+ if changeIndex <= 0:
+ break
+ changeIndex -= 1
+ # print("last page, addv:{}, val:{}, cur:{}, next:{}".format(addValue, value, curPictureSize, nextPictureSize))
+ # self.scrollArea.changeLastPage.emit(self.readImg.curIndex)
+ ## 切换下一图片
+ elif addValue > 0 and value >= nextPictureSize:
+ if changeIndex >= self.readImg.maxPic - 1:
+ break
+ changeIndex += 1
+ # print("next page, addv:{}, val:{}, cur:{}, next:{}".format(addValue, value, curPictureSize, nextPictureSize))
+ # self.scrollArea.changeNextPage.emit(self.readImg.curIndex)
+ else:
+ break
+ curPictureSize = self.labelSize.get(changeIndex)
+ nextPictureSize = self.labelSize.get(changeIndex + 1, 0)
+ if self.readImg.curIndex == changeIndex:
+ return
+ elif self.readImg.curIndex > changeIndex:
+ self.readImg.curIndex = changeIndex
+ self.scrollArea.changeLastPage.emit(self.readImg.curIndex)
+ elif self.readImg.curIndex < changeIndex:
+ self.readImg.curIndex = changeIndex
+ self.scrollArea.changeNextPage.emit(self.readImg.curIndex)
+ return
diff --git a/src/component/scroll/smooth_scroll.py b/src/component/scroll/smooth_scroll.py
index 11723e4..de6caaa 100644
--- a/src/component/scroll/smooth_scroll.py
+++ b/src/component/scroll/smooth_scroll.py
@@ -19,35 +19,36 @@ def __init__(self):
self.lastWheelEvent = None
self.scrollStamps = deque()
self.stepsLeftQueue = deque()
- self.smoothMoveTimer = QTimer(self)
+
+ # self.smoothMoveTimer = QTimer(self)
self.smoothMode = SmoothMode(SmoothMode.LINEAR)
- self.smoothMoveTimer.timeout.connect(self.__smoothMove)
+ # self.smoothMoveTimer.timeout.connect(self.__smoothMove)
self.qEventParam = []
def setSMoothMode(self, smoothMode):
""" 设置滚动模式 """
self.smoothMode = smoothMode
- def wheelEvent(self, e):
- # 将当前时间点插入队尾
- now = QDateTime.currentDateTime().toMSecsSinceEpoch()
- self.scrollStamps.append(now)
- while now - self.scrollStamps[0] > 500:
- self.scrollStamps.popleft()
- # 根据未处理完的事件调整移动速率增益
- accerationRatio = min(len(self.scrollStamps) / 15, 1)
- self.qEventParam = (e.position(), e.globalPosition(), e.buttons())
- # 计算步数
- self.stepsTotal = self.fps * self.duration / 1000
- # 计算每一个事件对应的移动距离
- delta = e.angleDelta().y() * self.stepRatio
- if self.acceleration > 0:
- delta += delta * self.acceleration * accerationRatio
- # 将移动距离和步数组成列表,插入队列等待处理
- self.stepsLeftQueue.append([delta, self.stepsTotal])
- # 定时器的溢出时间t=1000ms/帧数
- self.smoothMoveTimer.start(1000 // self.fps)
- return False
+ # def wheelEvent(self, e):
+ # # 将当前时间点插入队尾
+ # now = QDateTime.currentDateTime().toMSecsSinceEpoch()
+ # self.scrollStamps.append(now)
+ # while now - self.scrollStamps[0] > 500:
+ # self.scrollStamps.popleft()
+ # # 根据未处理完的事件调整移动速率增益
+ # accerationRatio = min(len(self.scrollStamps) / 15, 1)
+ # self.qEventParam = (e.position(), e.globalPosition(), e.buttons())
+ # # 计算步数
+ # self.stepsTotal = self.fps * self.duration / 1000
+ # # 计算每一个事件对应的移动距离
+ # delta = e.angleDelta().y() * self.stepRatio
+ # if self.acceleration > 0:
+ # delta += delta * self.acceleration * accerationRatio
+ # # 将移动距离和步数组成列表,插入队列等待处理
+ # self.stepsLeftQueue.append([delta, self.stepsTotal])
+ # # 定时器的溢出时间t=1000ms/帧数
+ # self.smoothMoveTimer.start(1000 // self.fps)
+ # return False
def __smoothMove(self):
""" 计时器溢出时进行平滑滚动 """
diff --git a/src/component/widget/comic_item_widget.py b/src/component/widget/comic_item_widget.py
index cb7bb5f..97e5ddd 100644
--- a/src/component/widget/comic_item_widget.py
+++ b/src/component/widget/comic_item_widget.py
@@ -1,5 +1,5 @@
from PySide6.QtCore import Qt, QSize, Signal
-from PySide6.QtGui import QPixmap, QIcon, QFont
+from PySide6.QtGui import QPixmap, QIcon, QFont, QFontMetrics
from PySide6.QtWidgets import QWidget
from config import config
@@ -21,9 +21,9 @@ def __init__(self, isCategory=False):
self.picNum = 0
self.category = ""
+ self.index = 0
self.url = ""
self.path = ""
- self.index = 0
# TODO 如何自适应
if not isCategory:
rate = Setting.CoverSize.value
@@ -75,8 +75,66 @@ def __init__(self, isCategory=False):
self.isWaifu2xLoading = False
self.isLoadPicture = False
+ def SetTitle(self, title, fontColor):
+ self.title = title
+ if Setting.NotCategoryShow.value:
+ self.categoryLabel.setVisible(False)
+
+ if Setting.TitleLine.value == 0:
+ self.nameLable.setVisible(False)
+ elif Setting.TitleLine.value == 1:
+ self.nameLable.setWordWrap(False)
+ self.nameLable.setText(title + fontColor)
+ elif Setting.TitleLine.value > 3:
+ self.nameLable.setText(title+fontColor)
+ else:
+ title2 = self.ElidedLineText(fontColor)
+ self.nameLable.setText(title2)
+
+ def ElidedLineText(self, fontColor):
+ line = Setting.TitleLine.value
+ if line <= 0 :
+ line = 2
+ f = QFontMetrics(self.nameLable.font())
+ if (line == 1):
+ return f.elidedText(self.title + fontColor, Qt.ElideRight, self.nameLable.maximumWidth())
+
+ strList = []
+ start = 0
+ isEnd = False
+ for i in range(1, len(self.title)):
+ if f.boundingRect(self.title[start:i]).width() >= self.nameLable.maximumWidth()-10:
+ strList.append(self.title[start:i])
+ if len(strList) >= line:
+ isEnd = True
+ break
+ start = i
+
+ if not isEnd:
+ strList.append(self.title[start:])
+
+ if not strList:
+ strList.append(self.title)
+
+ # strList[-1] = strList[-1] + fontColor
+
+ hasElided = True
+ endIndex = len(strList) - 1
+ endString = strList[endIndex]
+ if f.boundingRect(endString).width() < self.nameLable.maximumWidth() -10:
+ strList[endIndex] += fontColor
+ hasElided = False
+
+ if (hasElided):
+ if len(endString) > 8 :
+ endString = endString[0:len(endString) - 8] + "..." + fontColor
+ strList[endIndex] = endString
+ else:
+ strList[endIndex] += fontColor
+ return "".join(strList)
+
def GetTitle(self):
- return self.nameLable.text()
+ return self.title
def SetPicture(self, data):
self.picData = data
@@ -103,8 +161,8 @@ def SetWaifu2xData(self, data):
newPic = pic.scaled(self.picLabel.width()*radio, self.picLabel.height()*radio, Qt.KeepAspectRatio, Qt.SmoothTransformation)
self.picLabel.setPixmap(newPic)
- def SetPictureErr(self, st):
- self.picLabel.setText(Str.GetStr(st))
+ def SetPictureErr(self, status):
+ self.picLabel.setText(Str.GetStr(status))
def paintEvent(self, event) -> None:
if self.url and not self.isLoadPicture and config.IsLoadingPicture:
diff --git a/src/component/widget/main_widget.py b/src/component/widget/main_widget.py
index ee8ea05..7cbe542 100644
--- a/src/component/widget/main_widget.py
+++ b/src/component/widget/main_widget.py
@@ -10,14 +10,15 @@
Main = None
-if sys.platform == "win32" and Setting.IsUseTitleBar.value:
+if Setting.IsUseTitleBar.value:
try:
from interface.ui_main_windows import Ui_MainWindows
- from .windows.frame_less_widget import FrameLessWidget
+ # from .windows.frame_less_widget import FrameLessWidget
+ from .qframelesswindow import FramelessMainWindow
- class MainWidget(FrameLessWidget, Ui_MainWindows):
+ class MainWidget(FramelessMainWindow, Ui_MainWindows):
def __init__(self):
- FrameLessWidget.__init__(self)
+ FramelessMainWindow.__init__(self)
Ui_MainWindows.__init__(self)
self.setupUi(self)
self.totalStackWidget.setAttribute(Qt.WA_TranslucentBackground)
@@ -26,17 +27,17 @@ def __init__(self):
def showFullScreen(self):
self.widget.setVisible(False)
self.verticalLayout.setContentsMargins(0, 0, 0, 0)
- return FrameLessWidget.showFullScreen(self)
+ return FramelessMainWindow.showFullScreen(self)
def showNormal(self):
self.widget.setVisible(True)
self.verticalLayout.setContentsMargins(3, 3, 3, 3)
- return FrameLessWidget.showNormal(self)
+ return FramelessMainWindow.showNormal(self)
def showMaximized(self):
self.widget.setVisible(True)
self.verticalLayout.setContentsMargins(3, 3, 3, 3)
- return FrameLessWidget.showMaximized(self)
+ return FramelessMainWindow.showMaximized(self)
def setSubTitle(self, text):
self.widget.subTitle.setText(text)
diff --git a/src/component/widget/navigation_widget.py b/src/component/widget/navigation_widget.py
index d70b227..a6f4c68 100644
--- a/src/component/widget/navigation_widget.py
+++ b/src/component/widget/navigation_widget.py
@@ -20,7 +20,9 @@ def __init__(self, parent=None):
super().__init__(parent)
QtTaskBase.__init__(self)
self.setupUi(self)
- self.resize(260, 800)
+ if Setting.IsUseTitleBar.value:
+ self.scrollArea.setFixedHeight(300)
+ # self.resize(260, 800)
self.__ani = QPropertyAnimation(self, b"geometry")
self.__connect = None
self.pictureData = ""
@@ -44,6 +46,12 @@ def __init__(self, parent=None):
propertiesOne.setScrollMetric(QScrollerProperties.VerticalOvershootPolicy, QScrollerProperties.OvershootAlwaysOff)
propertiesOne.setScrollMetric(QScrollerProperties.HorizontalOvershootPolicy, QScrollerProperties.OvershootAlwaysOff)
QScroller.scroller(self.scrollArea).setScrollerProperties(propertiesOne)
+ self.proxyImgName.clicked.connect(self.OpenProxy)
+ self.proxyName.clicked.connect(self.OpenProxy)
+
+ def OpenProxy(self):
+ QtOwner().OpenProxy()
+ self.UpdateProxyName()
def SwitchOffline(self, state):
QtOwner().isOfflineModel = state
diff --git a/src/component/widget/qframelesswindow/__init__.py b/src/component/widget/qframelesswindow/__init__.py
new file mode 100644
index 0000000..c3c145f
--- /dev/null
+++ b/src/component/widget/qframelesswindow/__init__.py
@@ -0,0 +1,53 @@
+"""
+PyQt5-Frameless-Window
+======================
+A cross-platform frameless window based on pyqt5, support Win32, Linux and macOS.
+
+Documentation is available in the docstrings and
+online at https://pyqt-frameless-window.readthedocs.io.
+
+Examples are available at https://github.com/zhiyiYo/PyQt-Frameless-Window/tree/master/examples.
+
+:copyright: (c) 2021 by zhiyiYo.
+:license: GPLv3, see LICENSE for more details.
+"""
+
+__version__ = "0.3.8"
+
+import sys
+
+from PySide6.QtWidgets import QDialog, QMainWindow
+
+from .titlebar import TitleBar, TitleBarButton, SvgTitleBarButton, StandardTitleBar, TitleBarBase
+
+if sys.platform == "win32":
+ from .windows import AcrylicWindow
+ from .windows import WindowsFramelessWindow as FramelessWindow
+ from .windows import WindowsWindowEffect as WindowEffect
+elif sys.platform == "darwin":
+ from .mac import AcrylicWindow
+ from .mac import MacFramelessWindow as FramelessWindow
+ from .mac import MacWindowEffect as WindowEffect
+else:
+ from .linux import LinuxFramelessWindow as FramelessWindow
+ from .linux import LinuxWindowEffect as WindowEffect
+
+ AcrylicWindow = FramelessWindow
+
+
+class FramelessDialog(QDialog, FramelessWindow):
+ """ Frameless dialog """
+
+ def __init__(self, parent=None):
+ FramelessWindow.__init__(self, parent)
+ self.titleBar.minBtn.hide()
+ self.titleBar.maxBtn.hide()
+ self.titleBar.setDoubleClickEnabled(False)
+ self.windowEffect.disableMaximizeButton(self.winId())
+
+
+class FramelessMainWindow(QMainWindow, FramelessWindow):
+ """ Frameless main window """
+
+ def __init__(self, parent=None):
+ FramelessWindow.__init__(self, parent)
\ No newline at end of file
diff --git a/src/component/widget/qframelesswindow/_rc/__init__.py b/src/component/widget/qframelesswindow/_rc/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/src/component/widget/qframelesswindow/_rc/resource.py b/src/component/widget/qframelesswindow/_rc/resource.py
new file mode 100644
index 0000000..7594bd7
--- /dev/null
+++ b/src/component/widget/qframelesswindow/_rc/resource.py
@@ -0,0 +1,73 @@
+# -*- coding: utf-8 -*-
+
+# Resource object code
+#
+# Created by: The Resource Compiler for PyQt5 (Qt v5.15.2)
+#
+# WARNING! All changes made in this file will be lost!
+
+from PySide6 import QtCore
+
+qt_resource_data = b"\
+\x00\x00\x01\x0e\
+\x3c\
+\x73\x76\x67\x20\x77\x69\x64\x74\x68\x3d\x22\x34\x35\x70\x74\x22\
+\x20\x68\x65\x69\x67\x68\x74\x3d\x22\x33\x30\x70\x74\x22\x20\x76\
+\x65\x72\x73\x69\x6f\x6e\x3d\x22\x31\x2e\x31\x22\x20\x76\x69\x65\
+\x77\x42\x6f\x78\x3d\x22\x30\x20\x30\x20\x31\x35\x2e\x38\x37\x35\
+\x20\x31\x30\x2e\x35\x38\x33\x22\x20\x78\x6d\x6c\x6e\x73\x3d\x22\
+\x68\x74\x74\x70\x3a\x2f\x2f\x77\x77\x77\x2e\x77\x33\x2e\x6f\x72\
+\x67\x2f\x32\x30\x30\x30\x2f\x73\x76\x67\x22\x3e\x0d\x0a\x20\x3c\
+\x67\x20\x66\x69\x6c\x6c\x3d\x22\x6e\x6f\x6e\x65\x22\x20\x73\x74\
+\x72\x6f\x6b\x65\x3d\x22\x23\x30\x30\x30\x22\x20\x73\x74\x72\x6f\
+\x6b\x65\x2d\x77\x69\x64\x74\x68\x3d\x22\x2e\x31\x37\x36\x33\x39\
+\x22\x3e\x0d\x0a\x20\x20\x3c\x70\x61\x74\x68\x20\x64\x3d\x22\x6d\
+\x36\x2e\x31\x32\x39\x35\x20\x33\x2e\x36\x36\x30\x31\x20\x33\x2e\
+\x32\x36\x33\x32\x20\x33\x2e\x32\x36\x33\x32\x7a\x22\x2f\x3e\x0d\
+\x0a\x20\x20\x3c\x70\x61\x74\x68\x20\x64\x3d\x22\x6d\x39\x2e\x33\
+\x39\x32\x37\x20\x33\x2e\x36\x36\x30\x31\x2d\x33\x2e\x32\x36\x33\
+\x32\x20\x33\x2e\x32\x36\x33\x32\x7a\x22\x2f\x3e\x0d\x0a\x20\x3c\
+\x2f\x67\x3e\x0d\x0a\x3c\x2f\x73\x76\x67\x3e\x0d\x0a\
+"
+
+qt_resource_name = b"\
+\x00\x10\
+\x0a\xb5\xe4\x07\
+\x00\x71\
+\x00\x66\x00\x72\x00\x61\x00\x6d\x00\x65\x00\x6c\x00\x65\x00\x73\x00\x73\x00\x77\x00\x69\x00\x6e\x00\x64\x00\x6f\x00\x77\
+\x00\x09\
+\x06\x98\x8e\xa7\
+\x00\x63\
+\x00\x6c\x00\x6f\x00\x73\x00\x65\x00\x2e\x00\x73\x00\x76\x00\x67\
+"
+
+qt_resource_struct_v1 = b"\
+\x00\x00\x00\x00\x00\x02\x00\x00\x00\x01\x00\x00\x00\x01\
+\x00\x00\x00\x00\x00\x02\x00\x00\x00\x01\x00\x00\x00\x02\
+\x00\x00\x00\x26\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\
+"
+
+qt_resource_struct_v2 = b"\
+\x00\x00\x00\x00\x00\x02\x00\x00\x00\x01\x00\x00\x00\x01\
+\x00\x00\x00\x00\x00\x00\x00\x00\
+\x00\x00\x00\x00\x00\x02\x00\x00\x00\x01\x00\x00\x00\x02\
+\x00\x00\x00\x00\x00\x00\x00\x00\
+\x00\x00\x00\x26\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\
+\x00\x00\x01\x85\x86\x8c\x35\x15\
+"
+
+qt_version = [int(v) for v in QtCore.qVersion().split('.')]
+if qt_version < [5, 8, 0]:
+ rcc_version = 1
+ qt_resource_struct = qt_resource_struct_v1
+else:
+ rcc_version = 2
+ qt_resource_struct = qt_resource_struct_v2
+
+def qInitResources():
+ QtCore.qRegisterResourceData(rcc_version, qt_resource_struct, qt_resource_name, qt_resource_data)
+
+def qCleanupResources():
+ QtCore.qUnregisterResourceData(rcc_version, qt_resource_struct, qt_resource_name, qt_resource_data)
+
+qInitResources()
diff --git a/src/component/widget/qframelesswindow/_rc/resource.qrc b/src/component/widget/qframelesswindow/_rc/resource.qrc
new file mode 100644
index 0000000..8c60155
--- /dev/null
+++ b/src/component/widget/qframelesswindow/_rc/resource.qrc
@@ -0,0 +1,5 @@
+
+
+ title_bar/close.svg
+
+
\ No newline at end of file
diff --git a/src/component/widget/qframelesswindow/_rc/title_bar/close.svg b/src/component/widget/qframelesswindow/_rc/title_bar/close.svg
new file mode 100644
index 0000000..6f1f03b
--- /dev/null
+++ b/src/component/widget/qframelesswindow/_rc/title_bar/close.svg
@@ -0,0 +1,6 @@
+
diff --git a/src/component/widget/qframelesswindow/demo.py b/src/component/widget/qframelesswindow/demo.py
new file mode 100644
index 0000000..578b03f
--- /dev/null
+++ b/src/component/widget/qframelesswindow/demo.py
@@ -0,0 +1,73 @@
+# coding:utf-8
+import sys
+
+from PySide6.QtCore import Qt
+from PySide6.QtGui import QColor, QPixmap, QIcon
+from PySide6.QtWidgets import QApplication, QLabel
+
+from component.widget.qframelesswindow import FramelessWindow, StandardTitleBar
+
+
+class CustomTitleBar(StandardTitleBar):
+ """ Custom title bar """
+
+ def __init__(self, parent):
+ super().__init__(parent)
+
+ # customize the style of title bar button
+ self.minBtn.setHoverColor(Qt.white)
+ self.minBtn.setHoverBackgroundColor(QColor(0, 100, 182))
+ self.minBtn.setPressedColor(Qt.white)
+ self.minBtn.setPressedBackgroundColor(QColor(54, 57, 65))
+
+ # use qss to customize title bar button
+ self.maxBtn.setStyleSheet("""
+ TitleBarButton {
+ qproperty-hoverColor: white;
+ qproperty-hoverBackgroundColor: rgb(0, 100, 182);
+ qproperty-pressedColor: white;
+ qproperty-pressedBackgroundColor: rgb(54, 57, 65);
+ }
+ """)
+
+
+class Window(FramelessWindow):
+
+ def __init__(self, parent=None):
+ super().__init__(parent=parent)
+ # change the default title bar if you like
+ self.setTitleBar(CustomTitleBar(self))
+
+ self.label = QLabel(self)
+ self.label.setScaledContents(True)
+ self.label.setPixmap(QPixmap("screenshot/shoko.png"))
+
+ self.setWindowIcon(QIcon("screenshot/logo.png"))
+ self.setWindowTitle("PyQt-Frameless-Window")
+ self.setStyleSheet("background:white")
+
+ self.titleBar.raise_()
+
+ def resizeEvent(self, e):
+ # don't forget to call the resizeEvent() of super class
+ super().resizeEvent(e)
+ length = min(self.width(), self.height())
+ self.label.resize(length, length)
+ self.label.move(
+ self.width() // 2 - length // 2,
+ self.height() // 2 - length // 2
+ )
+
+
+if __name__ == "__main__":
+ # enable dpi scale
+ QApplication.setHighDpiScaleFactorRoundingPolicy(
+ Qt.HighDpiScaleFactorRoundingPolicy.PassThrough)
+ QApplication.setAttribute(Qt.AA_EnableHighDpiScaling)
+ QApplication.setAttribute(Qt.AA_UseHighDpiPixmaps)
+
+ # run app
+ app = QApplication(sys.argv)
+ demo = Window()
+ demo.show()
+ sys.exit(app.exec())
diff --git a/src/component/widget/qframelesswindow/linux/__init__.py b/src/component/widget/qframelesswindow/linux/__init__.py
new file mode 100644
index 0000000..35e5ba8
--- /dev/null
+++ b/src/component/widget/qframelesswindow/linux/__init__.py
@@ -0,0 +1,85 @@
+# coding:utf-8
+from PySide6.QtCore import QCoreApplication, QEvent, Qt
+from PySide6.QtGui import QMouseEvent
+from PySide6.QtWidgets import QWidget
+
+from ..titlebar import TitleBar
+from ..utils.linux_utils import LinuxMoveResize
+from .window_effect import LinuxWindowEffect
+
+
+class LinuxFramelessWindow(QWidget):
+ """ Frameless window for Linux system """
+
+ BORDER_WIDTH = 5
+
+ def __init__(self, parent=None):
+ super().__init__(parent=parent)
+ self.windowEffect = LinuxWindowEffect(self)
+ self.titleBar = TitleBar(self)
+ self._isResizeEnabled = True
+
+ self.updateFrameless()
+ QCoreApplication.instance().installEventFilter(self)
+
+ self.titleBar.raise_()
+ self.resize(500, 500)
+
+ def resizeEvent(self, e):
+ super().resizeEvent(e)
+ self.titleBar.resize(self.width(), self.titleBar.height())
+
+ def updateFrameless(self):
+ self.setWindowFlags(self.windowFlags() | Qt.FramelessWindowHint)
+
+ def setTitleBar(self, titleBar):
+ """ set custom title bar
+
+ Parameters
+ ----------
+ titleBar: TitleBar
+ title bar
+ """
+ self.titleBar.deleteLater()
+ self.titleBar.hide()
+ self.titleBar = titleBar
+ self.titleBar.setParent(self)
+ self.titleBar.raise_()
+
+ def setResizeEnabled(self, isEnabled: bool):
+ """ set whether resizing is enabled """
+ self._isResizeEnabled = isEnabled
+
+ def eventFilter(self, obj, event):
+ et = event.type()
+ if et != QEvent.MouseButtonPress and et != QEvent.MouseMove or not self._isResizeEnabled:
+ return False
+
+ edges = Qt.Edges()
+ pos = QMouseEvent(event).globalPos() - self.pos()
+ if pos.x() < self.BORDER_WIDTH:
+ edges |= Qt.LeftEdge
+ if pos.x() >= self.width()-self.BORDER_WIDTH:
+ edges |= Qt.RightEdge
+ if pos.y() < self.BORDER_WIDTH:
+ edges |= Qt.TopEdge
+ if pos.y() >= self.height()-self.BORDER_WIDTH:
+ edges |= Qt.BottomEdge
+
+ # change cursor
+ if et == QEvent.MouseMove and self.windowState() == Qt.WindowNoState:
+ if edges in (Qt.LeftEdge | Qt.TopEdge, Qt.RightEdge | Qt.BottomEdge):
+ self.setCursor(Qt.SizeFDiagCursor)
+ elif edges in (Qt.RightEdge | Qt.TopEdge, Qt.LeftEdge | Qt.BottomEdge):
+ self.setCursor(Qt.SizeBDiagCursor)
+ elif edges in (Qt.TopEdge, Qt.BottomEdge):
+ self.setCursor(Qt.SizeVerCursor)
+ elif edges in (Qt.LeftEdge, Qt.RightEdge):
+ self.setCursor(Qt.SizeHorCursor)
+ else:
+ self.setCursor(Qt.ArrowCursor)
+
+ elif obj in (self, self.titleBar) and et == QEvent.MouseButtonPress and edges:
+ LinuxMoveResize.starSystemResize(self, event.globalPos(), edges)
+
+ return super().eventFilter(obj, event)
diff --git a/src/component/widget/qframelesswindow/linux/window_effect.py b/src/component/widget/qframelesswindow/linux/window_effect.py
new file mode 100644
index 0000000..372abfb
--- /dev/null
+++ b/src/component/widget/qframelesswindow/linux/window_effect.py
@@ -0,0 +1,141 @@
+# coding:utf-8
+
+class LinuxWindowEffect:
+ """ Linux window effect """
+
+ def __init__(self, window):
+ self.window = window
+
+ def setAcrylicEffect(self, hWnd, gradientColor="F2F2F230", isEnableShadow=True, animationId=0):
+ """ set acrylic effect for window
+
+ Parameter
+ ----------
+ hWnd: int or `sip.voidptr`
+ window handle
+
+ gradientColor: str
+ hexadecimal acrylic mixed color, corresponding to RGBA components
+
+ isEnableShadow: bool
+ whether to enable window shadow
+
+ animationId: int
+ turn on blur animation or not
+ """
+ pass
+
+ def setMicaEffect(self, hWnd, isDarkMode=False, isAlt=False):
+ """ Add mica effect to the window (Win11 only)
+
+ Parameters
+ ----------
+ hWnd: int or `sip.voidptr`
+ Window handle
+
+ isDarkMode: bool
+ whether to use dark mode mica effect
+
+ isAlt: bool
+ whether to use mica alt effect
+ """
+ pass
+
+ def setAeroEffect(self, hWnd):
+ """ add Aero effect to the window
+
+ Parameter
+ ----------
+ hWnd: int or `sip.voidptr`
+ Window handle
+ """
+ pass
+
+ def setTransparentEffect(self, hWnd):
+ """ set transparent effect for window
+
+ Parameters
+ ----------
+ hWnd : int or `sip.voidptr`
+ Window handle
+ """
+ pass
+
+ def removeBackgroundEffect(self, hWnd):
+ """ Remove background effect
+
+ Parameters
+ ----------
+ hWnd : int or `sip.voidptr`
+ Window handle
+ """
+ pass
+
+ def addShadowEffect(self, hWnd):
+ """ add shadow to window
+
+ Parameter
+ ----------
+ hWnd: int or `sip.voidptr`
+ Window handle
+ """
+ pass
+
+ def addMenuShadowEffect(self, hWnd):
+ """ add shadow to menu
+
+ Parameter
+ ----------
+ hWnd: int or `sip.voidptr`
+ Window handle
+ """
+ pass
+
+ @staticmethod
+ def removeMenuShadowEffect(hWnd):
+ """ Remove shadow from pop-up menu
+
+ Parameters
+ ----------
+ hWnd: int or `sip.voidptr`
+ Window handle
+ """
+ pass
+
+ def removeShadowEffect(self, hWnd):
+ """ Remove shadow from the window
+
+ Parameters
+ ----------
+ hWnd: int or `sip.voidptr`
+ Window handle
+ """
+ pass
+
+ @staticmethod
+ def addWindowAnimation(hWnd):
+ """ Enables the maximize and minimize animation of the window
+
+ Parameters
+ ----------
+ hWnd : int or `sip.voidptr`
+ Window handle
+ """
+
+ @staticmethod
+ def disableMaximizeButton(hWnd):
+ """ Disable the maximize button of window
+
+ Parameters
+ ----------
+ hWnd : int or `sip.voidptr`
+ Window handle
+ """
+
+ def enableBlurBehindWindow(self, hWnd):
+ """ enable the blur effect behind the whole client
+ Parameters
+ ----------
+ hWnd: int or `sip.voidptr`
+ Window handle
+ """
\ No newline at end of file
diff --git a/src/component/widget/qframelesswindow/mac/__init__.py b/src/component/widget/qframelesswindow/mac/__init__.py
new file mode 100644
index 0000000..7ae8517
--- /dev/null
+++ b/src/component/widget/qframelesswindow/mac/__init__.py
@@ -0,0 +1,93 @@
+# coding:utf-8
+import Cocoa
+import objc
+from PySide6.QtCore import QEvent, Qt
+from PySide6.QtWidgets import QWidget
+
+from ..titlebar import TitleBar
+from .window_effect import MacWindowEffect
+
+
+class MacFramelessWindow(QWidget):
+ """ Frameless window for Linux system """
+
+ def __init__(self, parent=None):
+ super().__init__(parent=parent)
+ self.windowEffect = MacWindowEffect(self)
+ # must enable acrylic effect before creating title bar
+ if isinstance(self, AcrylicWindow):
+ self.windowEffect.setAcrylicEffect(self.winId())
+
+ self.titleBar = TitleBar(self)
+ self._isResizeEnabled = True
+
+ self.updateFrameless()
+
+ self.resize(500, 500)
+ self.titleBar.raise_()
+
+ def updateFrameless(self):
+ """ update frameless window """
+ view = objc.objc_object(c_void_p=self.winId().__int__())
+ self.__nsWindow = view.window()
+
+ # hide system title bar
+ self.__hideSystemTitleBar()
+
+ def setTitleBar(self, titleBar):
+ """ set custom title bar
+
+ Parameters
+ ----------
+ titleBar: TitleBar
+ title bar
+ """
+ self.titleBar.deleteLater()
+ self.titleBar.hide()
+ self.titleBar = titleBar
+ self.titleBar.setParent(self)
+ self.titleBar.raise_()
+
+ def setResizeEnabled(self, isEnabled: bool):
+ """ set whether resizing is enabled """
+ self._isResizeEnabled = isEnabled
+
+ def resizeEvent(self, e):
+ super().resizeEvent(e)
+ self.titleBar.resize(self.width(), self.titleBar.height())
+
+ def paintEvent(self, e):
+ super().paintEvent(e)
+ self.__hideSystemTitleBar()
+
+ def changeEvent(self, event):
+ super().changeEvent(event)
+ if event.type() == QEvent.WindowStateChange:
+ self.__hideSystemTitleBar()
+
+ def __hideSystemTitleBar(self):
+ # extend view to title bar region
+ self.__nsWindow.setStyleMask_(
+ self.__nsWindow.styleMask() | Cocoa.NSFullSizeContentViewWindowMask)
+ self.__nsWindow.setTitlebarAppearsTransparent_(True)
+
+ # disable the moving behavior of system
+ self.__nsWindow.setMovableByWindowBackground_(False)
+ self.__nsWindow.setMovable_(False)
+
+ # hide title bar buttons and title
+ self.__nsWindow.setShowsToolbarButton_(False)
+ self.__nsWindow.setTitleVisibility_(Cocoa.NSWindowTitleHidden)
+ self.__nsWindow.standardWindowButton_(Cocoa.NSWindowCloseButton).setHidden_(True)
+ self.__nsWindow.standardWindowButton_(Cocoa.NSWindowZoomButton).setHidden_(True)
+ self.__nsWindow.standardWindowButton_(Cocoa.NSWindowMiniaturizeButton).setHidden_(True)
+
+
+class AcrylicWindow(MacFramelessWindow):
+ """ A frameless window with acrylic effect """
+
+ def __init__(self, parent=None):
+ super().__init__(parent)
+ self.setAttribute(Qt.WA_TranslucentBackground)
+ self.windowEffect.setAcrylicEffect(self.winId())
+ self.setStyleSheet("background: transparent")
diff --git a/src/component/widget/qframelesswindow/mac/window_effect.py b/src/component/widget/qframelesswindow/mac/window_effect.py
new file mode 100644
index 0000000..56cf202
--- /dev/null
+++ b/src/component/widget/qframelesswindow/mac/window_effect.py
@@ -0,0 +1,162 @@
+# coding:utf-8
+import objc
+import Cocoa
+from PySide6.QtWidgets import QMacCocoaViewContainer
+from ..utils.mac_utils import getNSWindow
+
+class MacWindowEffect:
+ """ Mac OS window effect """
+
+ def __init__(self, window):
+ self.window = window
+
+ def setAcrylicEffect(self, hWnd, gradientColor="F2F2F230", isEnableShadow=True, animationId=0):
+ """ set acrylic effect for window
+
+ Parameter
+ ----------
+ hWnd: int or `sip.voidptr`
+ window handle
+
+ gradientColor: str
+ hexadecimal acrylic mixed color, corresponding to RGBA components
+
+ isEnableShadow: bool
+ whether to enable window shadow
+
+ animationId: int
+ turn on blur animation or not
+ """
+ frame = Cocoa.NSMakeRect(
+ 0, 0, self.window.width(), self.window.height())
+ visualEffectView = Cocoa.NSVisualEffectView.new()
+ visualEffectView.setAutoresizingMask_(
+ Cocoa.NSViewWidthSizable | Cocoa.NSViewHeightSizable) # window resizable
+ visualEffectView.setFrame_(frame)
+ visualEffectView.setState_(Cocoa.NSVisualEffectStateActive)
+
+ # https://developer.apple.com/documentation/appkit/nsvisualeffectmaterial
+ visualEffectView.setMaterial_(Cocoa.NSVisualEffectMaterialPopover)
+ visualEffectView.setBlendingMode_(
+ Cocoa.NSVisualEffectBlendingModeBehindWindow)
+
+ nsWindow = getNSWindow(self.window.winId())
+ content = nsWindow.contentView()
+ container = QMacCocoaViewContainer(0, self.window)
+ content.addSubview_positioned_relativeTo_(
+ visualEffectView, Cocoa.NSWindowBelow, container)
+
+ def setMicaEffect(self, hWnd, isDarkMode=False, isAlt=False):
+ """ Add mica effect to the window (Win11 only)
+
+ Parameters
+ ----------
+ hWnd: int or `sip.voidptr`
+ Window handle
+
+ isDarkMode: bool
+ whether to use dark mode mica effect
+
+ isAlt: bool
+ whether to use mica alt effect
+ """
+ self.setAcrylicEffect(hWnd)
+
+ def setAeroEffect(self, hWnd):
+ """ add Aero effect to the window
+
+ Parameter
+ ----------
+ hWnd: int or `sip.voidptr`
+ Window handle
+ """
+ self.setAcrylicEffect(hWnd)
+
+ def setTransparentEffect(self, hWnd):
+ """ set transparent effect for window
+
+ Parameters
+ ----------
+ hWnd : int or `sip.voidptr`
+ Window handle
+ """
+ pass
+
+ def removeBackgroundEffect(self, hWnd):
+ """ Remove background effect
+
+ Parameters
+ ----------
+ hWnd : int or `sip.voidptr`
+ Window handle
+ """
+ pass
+
+ def addShadowEffect(self, hWnd):
+ """ add shadow to window
+
+ Parameter
+ ----------
+ hWnd: int or `sip.voidptr`
+ Window handle
+ """
+ getNSWindow(hWnd).setHasShadow_(True)
+
+ def addMenuShadowEffect(self, hWnd):
+ """ add shadow to menu
+
+ Parameter
+ ----------
+ hWnd: int or `sip.voidptr`
+ Window handle
+ """
+ self.addShadowEffect(hWnd)
+
+ @staticmethod
+ def removeMenuShadowEffect(hWnd):
+ """ Remove shadow from pop-up menu
+
+ Parameters
+ ----------
+ hWnd: int or `sip.voidptr`
+ Window handle
+ """
+ getNSWindow(hWnd).setHasShadow_(False)
+
+ def removeShadowEffect(self, hWnd):
+ """ Remove shadow from the window
+
+ Parameters
+ ----------
+ hWnd: int or `sip.voidptr`
+ Window handle
+ """
+ getNSWindow(hWnd).setHasShadow_(False)
+
+ @staticmethod
+ def addWindowAnimation(hWnd):
+ """ Enables the maximize and minimize animation of the window
+
+ Parameters
+ ----------
+ hWnd : int or `sip.voidptr`
+ Window handle
+ """
+
+ @staticmethod
+ def disableMaximizeButton(hWnd):
+ """ Disable the maximize button of window
+
+ Parameters
+ ----------
+ hWnd : int or `sip.voidptr`
+ Window handle
+ """
+
+ def enableBlurBehindWindow(self, hWnd):
+ """ enable the blur effect behind the whole client
+ Parameters
+ ----------
+ hWnd: int or `sip.voidptr`
+ Window handle
+ """
\ No newline at end of file
diff --git a/src/component/widget/qframelesswindow/titlebar/__init__.py b/src/component/widget/qframelesswindow/titlebar/__init__.py
new file mode 100644
index 0000000..1c7cdcf
--- /dev/null
+++ b/src/component/widget/qframelesswindow/titlebar/__init__.py
@@ -0,0 +1,157 @@
+# coding:utf-8
+import sys
+
+from PySide6.QtCore import QEvent, Qt
+from PySide6.QtGui import QIcon
+from PySide6.QtWidgets import QHBoxLayout, QLabel, QWidget
+
+from ..utils import startSystemMove
+from .title_bar_buttons import (CloseButton, MaximizeButton, MinimizeButton,
+ SvgTitleBarButton, TitleBarButton)
+
+
+class TitleBarBase(QWidget):
+ """ Title bar base class """
+
+ def __init__(self, parent):
+ super().__init__(parent)
+ self.minBtn = MinimizeButton(parent=self)
+ self.closeBtn = CloseButton(parent=self)
+ self.maxBtn = MaximizeButton(parent=self)
+
+ self._isDoubleClickEnabled = True
+
+ self.resize(200, 32)
+ self.setFixedHeight(32)
+
+ # connect signal to slot
+ self.minBtn.clicked.connect(self.window().showMinimized)
+ self.maxBtn.clicked.connect(self.__toggleMaxState)
+ self.closeBtn.clicked.connect(self.window().close)
+
+ self.window().installEventFilter(self)
+
+ def eventFilter(self, obj, e):
+ if obj is self.window():
+ if e.type() == QEvent.WindowStateChange:
+ self.maxBtn.setMaxState(self.window().isMaximized())
+ return False
+
+ return super().eventFilter(obj, e)
+
+ def mouseDoubleClickEvent(self, event):
+ """ Toggles the maximization state of the window """
+ if event.button() != Qt.LeftButton or not self._isDoubleClickEnabled:
+ return
+
+ self.__toggleMaxState()
+
+ def mouseMoveEvent(self, e):
+ if sys.platform != "win32" or not self.canDrag(e.pos()):
+ return
+
+ startSystemMove(self.window(), e.globalPos())
+
+ def mousePressEvent(self, e):
+ if sys.platform == "win32" or not self.canDrag(e.pos()):
+ return
+
+ startSystemMove(self.window(), e.globalPos())
+
+ def __toggleMaxState(self):
+ """ Toggles the maximization state of the window and change icon """
+ if self.window().isMaximized():
+ self.window().showNormal()
+ else:
+ self.window().showMaximized()
+
+ def _isDragRegion(self, pos):
+ """ Check whether the position belongs to the area where dragging is allowed """
+ width = 0
+ for button in self.findChildren(TitleBarButton):
+ if button.isVisible():
+ width += button.width()
+
+ return 0 < pos.x() < self.width() - width
+
+ def _hasButtonPressed(self):
+ """ whether any button is pressed """
+ return any(btn.isPressed() for btn in self.findChildren(TitleBarButton))
+
+ def canDrag(self, pos):
+ """ whether the position is draggable """
+ return self._isDragRegion(pos) and not self._hasButtonPressed()
+
+ def setDoubleClickEnabled(self, isEnabled):
+ """ whether to switch window maximization status when double clicked
+
+ Parameters
+ ----------
+ isEnabled: bool
+ whether to enable double click
+ """
+ self._isDoubleClickEnabled = isEnabled
+
+
+
+class TitleBar(TitleBarBase):
+ """ Title bar with minimize, maximum and close button """
+
+ def __init__(self, parent):
+ super().__init__(parent)
+ self.hBoxLayout = QHBoxLayout(self)
+
+ # add buttons to layout
+ self.hBoxLayout.setSpacing(0)
+ self.hBoxLayout.setContentsMargins(0, 0, 0, 0)
+ self.hBoxLayout.setAlignment(Qt.AlignVCenter | Qt.AlignLeft)
+ self.hBoxLayout.addStretch(1)
+ self.hBoxLayout.addWidget(self.minBtn, 0, Qt.AlignRight)
+ self.hBoxLayout.addWidget(self.maxBtn, 0, Qt.AlignRight)
+ self.hBoxLayout.addWidget(self.closeBtn, 0, Qt.AlignRight)
+
+
+class StandardTitleBar(TitleBar):
+ """ Title bar with icon and title """
+
+ def __init__(self, parent):
+ super().__init__(parent)
+ # add window icon
+ self.iconLabel = QLabel(self)
+ self.iconLabel.setFixedSize(20, 20)
+ self.hBoxLayout.insertSpacing(0, 10)
+ self.hBoxLayout.insertWidget(1, self.iconLabel, 0, Qt.AlignLeft)
+ self.window().windowIconChanged.connect(self.setIcon)
+
+ # add title label
+ self.titleLabel = QLabel(self)
+ self.hBoxLayout.insertWidget(2, self.titleLabel, 0, Qt.AlignLeft)
+ self.titleLabel.setStyleSheet("""
+ QLabel{
+ background: transparent;
+ font: 13px 'Segoe UI';
+ padding: 0 4px
+ }
+ """)
+ self.window().windowTitleChanged.connect(self.setTitle)
+
+ def setTitle(self, title):
+ """ set the title of title bar
+
+ Parameters
+ ----------
+ title: str
+ the title of title bar
+ """
+ self.titleLabel.setText(title)
+ self.titleLabel.adjustSize()
+
+ def setIcon(self, icon):
+ """ set the icon of title bar
+
+ Parameters
+ ----------
+ icon: QIcon | QPixmap | str
+ the icon of title bar
+ """
+ self.iconLabel.setPixmap(QIcon(icon).pixmap(20, 20))
diff --git a/src/component/widget/qframelesswindow/titlebar/title_bar_buttons.py b/src/component/widget/qframelesswindow/titlebar/title_bar_buttons.py
new file mode 100644
index 0000000..7c52f6d
--- /dev/null
+++ b/src/component/widget/qframelesswindow/titlebar/title_bar_buttons.py
@@ -0,0 +1,305 @@
+# coding:utf-8
+from enum import Enum
+
+from PySide6.QtCore import QFile, QPointF, QRectF, Qt, Property
+from PySide6.QtGui import QColor, QPainter, QPainterPath, QPen
+from PySide6.QtWidgets import QAbstractButton
+from PySide6.QtSvg import QSvgRenderer
+from PySide6.QtXml import QDomDocument
+
+from .._rc import resource
+
+
+class TitleBarButtonState(Enum):
+ """ Title bar button state """
+ NORMAL = 0
+ HOVER = 1
+ PRESSED = 2
+
+
+class TitleBarButton(QAbstractButton):
+ """ Title bar button """
+
+ def __init__(self, parent=None):
+ super().__init__(parent=parent)
+ self.setCursor(Qt.ArrowCursor)
+ self.setFixedSize(46, 32)
+ self._state = TitleBarButtonState.NORMAL
+
+ # icon color
+ self._normalColor = QColor(0, 0, 0)
+ self._hoverColor = QColor(0, 0, 0)
+ self._pressedColor = QColor(0, 0, 0)
+
+ # background color
+ self._normalBgColor = QColor(0, 0, 0, 0)
+ self._hoverBgColor = QColor(0, 0, 0, 26)
+ self._pressedBgColor = QColor(0, 0, 0, 51)
+
+ def setState(self, state):
+ """ set the state of button
+
+ Parameters
+ ----------
+ state: TitleBarButtonState
+ the state of button
+ """
+ self._state = state
+ self.update()
+
+ def isPressed(self):
+ """ whether the button is pressed """
+ return self._state == TitleBarButtonState.PRESSED
+
+ def getNormalColor(self):
+ """ get the icon color of the button in normal state """
+ return self._normalColor
+
+ def getHoverColor(self):
+ """ get the icon color of the button in hover state """
+ return self._hoverColor
+
+ def getPressedColor(self):
+ """ get the icon color of the button in pressed state """
+ return self._pressedColor
+
+ def getNormalBackgroundColor(self):
+ """ get the background color of the button in normal state """
+ return self._normalBgColor
+
+ def getHoverBackgroundColor(self):
+ """ get the background color of the button in hover state """
+ return self._hoverBgColor
+
+ def getPressedBackgroundColor(self):
+ """ get the background color of the button in pressed state """
+ return self._pressedBgColor
+
+ def setNormalColor(self, color):
+ """ set the icon color of the button in normal state
+
+ Parameters
+ ----------
+ color: QColor
+ icon color
+ """
+ self._normalColor = QColor(color)
+ self.update()
+
+ def setHoverColor(self, color):
+ """ set the icon color of the button in hover state
+
+ Parameters
+ ----------
+ color: QColor
+ icon color
+ """
+ self._hoverColor = QColor(color)
+ self.update()
+
+ def setPressedColor(self, color):
+ """ set the icon color of the button in pressed state
+
+ Parameters
+ ----------
+ color: QColor
+ icon color
+ """
+ self._pressedColor = QColor(color)
+ self.update()
+
+ def setNormalBackgroundColor(self, color):
+ """ set the background color of the button in normal state
+
+ Parameters
+ ----------
+ color: QColor
+ background color
+ """
+ self._normalBgColor = QColor(color)
+ self.update()
+
+ def setHoverBackgroundColor(self, color):
+ """ set the background color of the button in hover state
+
+ Parameters
+ ----------
+ color: QColor
+ background color
+ """
+ self._hoverBgColor = QColor(color)
+ self.update()
+
+ def setPressedBackgroundColor(self, color):
+ """ set the background color of the button in pressed state
+
+ Parameters
+ ----------
+ color: QColor
+ background color
+ """
+ self._pressedBgColor = QColor(color)
+ self.update()
+
+ def enterEvent(self, e):
+ self.setState(TitleBarButtonState.HOVER)
+ super().enterEvent(e)
+
+ def leaveEvent(self, e):
+ self.setState(TitleBarButtonState.NORMAL)
+ super().leaveEvent(e)
+
+ def mousePressEvent(self, e):
+ if e.button() != Qt.LeftButton:
+ return
+
+ self.setState(TitleBarButtonState.PRESSED)
+ super().mousePressEvent(e)
+
+ def _getColors(self):
+ """ get the icon color and background color """
+ if self._state == TitleBarButtonState.NORMAL:
+ return self._normalColor, self._normalBgColor
+ elif self._state == TitleBarButtonState.HOVER:
+ return self._hoverColor, self._hoverBgColor
+
+ return self._pressedColor, self._pressedBgColor
+
+ normalColor = Property(QColor, getNormalColor, setNormalColor)
+ hoverColor = Property(QColor, getHoverColor, setHoverColor)
+ pressedColor = Property(QColor, getPressedColor, setPressedColor)
+ normalBackgroundColor = Property(
+ QColor, getNormalBackgroundColor, setNormalBackgroundColor)
+ hoverBackgroundColor = Property(
+ QColor, getHoverBackgroundColor, setHoverBackgroundColor)
+ pressedBackgroundColor = Property(
+ QColor, getPressedBackgroundColor, setPressedBackgroundColor)
+
+
+class SvgTitleBarButton(TitleBarButton):
+ """ Title bar button using svg icon """
+
+ def __init__(self, iconPath, parent=None):
+ """
+ Parameters
+ ----------
+ iconPath: str
+ the path of icon
+
+ parent: QWidget
+ parent widget
+ """
+ super().__init__(parent)
+ self._svgDom = QDomDocument()
+ self.setIcon(iconPath)
+
+ def setIcon(self, iconPath):
+ """ set the icon of button
+
+ Parameters
+ ----------
+ iconPath: str
+ the path of icon
+ """
+ f = QFile(iconPath)
+ f.open(QFile.ReadOnly)
+ self._svgDom.setContent(f.readAll())
+ f.close()
+
+ def paintEvent(self, e):
+ painter = QPainter(self)
+ painter.setRenderHints(QPainter.Antialiasing | QPainter.SmoothPixmapTransform)
+ color, bgColor = self._getColors()
+
+ # draw background
+ painter.setBrush(bgColor)
+ painter.setPen(Qt.NoPen)
+ painter.drawRect(self.rect())
+
+ # draw icon
+ color = color.name()
+ pathNodes = self._svgDom.elementsByTagName('path')
+ for i in range(pathNodes.length()):
+ element = pathNodes.at(i).toElement()
+ element.setAttribute('stroke', color)
+
+ renderer = QSvgRenderer(self._svgDom.toByteArray())
+ renderer.render(painter, QRectF(self.rect()))
+
+
+class MinimizeButton(TitleBarButton):
+ """ Minimize button """
+
+ def paintEvent(self, e):
+ painter = QPainter(self)
+ color, bgColor = self._getColors()
+
+ # draw background
+ painter.setBrush(bgColor)
+ painter.setPen(Qt.NoPen)
+ painter.drawRect(self.rect())
+
+ # draw icon
+ painter.setBrush(Qt.NoBrush)
+ pen = QPen(color, 1)
+ pen.setCosmetic(True)
+ painter.setPen(pen)
+ painter.drawLine(18, 16, 28, 16)
+
+
+class MaximizeButton(TitleBarButton):
+ """ Maximize button """
+
+ def __init__(self, parent=None):
+ super().__init__(parent)
+ self._isMax = False
+
+ def setMaxState(self, isMax):
+ """ update the maximized state and icon """
+ if self._isMax == isMax:
+ return
+
+ self._isMax = isMax
+ self.setState(TitleBarButtonState.NORMAL)
+
+ def paintEvent(self, e):
+ painter = QPainter(self)
+ color, bgColor = self._getColors()
+
+ # draw background
+ painter.setBrush(bgColor)
+ painter.setPen(Qt.NoPen)
+ painter.drawRect(self.rect())
+
+ # draw icon
+ painter.setBrush(Qt.NoBrush)
+ pen = QPen(color, 1)
+ pen.setCosmetic(True)
+ painter.setPen(pen)
+
+ r = self.devicePixelRatioF()
+ painter.scale(1/r, 1/r)
+ if not self._isMax:
+ painter.drawRect(int(18*r), int(11*r), int(10*r), int(10*r))
+ else:
+ painter.drawRect(int(18*r), int(13*r), int(8*r), int(8*r))
+ x0 = int(18*r)+int(2*r)
+ y0 = 13*r
+ dw = int(2*r)
+ path = QPainterPath(QPointF(x0, y0))
+ path.lineTo(x0, y0-dw)
+ path.lineTo(x0+8*r, y0-dw)
+ path.lineTo(x0+8*r, y0-dw+8*r)
+ path.lineTo(x0+8*r-dw, y0-dw+8*r)
+ painter.drawPath(path)
+
+
+class CloseButton(SvgTitleBarButton):
+ """ Close button """
+
+ def __init__(self, parent=None):
+ super().__init__(":/qframelesswindow/close.svg", parent)
+ self.setHoverColor(Qt.white)
+ self.setPressedColor(Qt.white)
+ self.setHoverBackgroundColor(QColor(232, 17, 35))
+ self.setPressedBackgroundColor(QColor(241, 112, 122))
diff --git a/src/component/widget/qframelesswindow/utils/__init__.py b/src/component/widget/qframelesswindow/utils/__init__.py
new file mode 100644
index 0000000..8313586
--- /dev/null
+++ b/src/component/widget/qframelesswindow/utils/__init__.py
@@ -0,0 +1,40 @@
+# coding:utf-8
+import sys
+
+if sys.platform == "win32":
+ from .win32_utils import WindowsMoveResize as MoveResize
+elif sys.platform == "darwin":
+ from .mac_utils import MacMoveResize as MoveResize
+else:
+ from .linux_utils import LinuxMoveResize as MoveResize
+
+
+def startSystemMove(window, globalPos):
+ """ resize window
+
+ Parameters
+ ----------
+ window: QWidget
+ window
+
+ globalPos: QPoint
+ the global point of mouse release event
+ """
+ MoveResize.startSystemMove(window, globalPos)
+
+
+def starSystemResize(window, globalPos, edges):
+ """ resize window
+
+ Parameters
+ ----------
+ window: QWidget
+ window
+
+ globalPos: QPoint
+ the global point of mouse release event
+
+ edges: `Qt.Edges`
+ window edges
+ """
+ MoveResize.starSystemResize(window, globalPos, edges)
diff --git a/src/component/widget/qframelesswindow/utils/linux_utils.py b/src/component/widget/qframelesswindow/utils/linux_utils.py
new file mode 100644
index 0000000..d6188ba
--- /dev/null
+++ b/src/component/widget/qframelesswindow/utils/linux_utils.py
@@ -0,0 +1,168 @@
+# coding: utf-8
+from enum import Enum
+
+import xcffib as xcb
+from PySide6 import sip
+from PySide6.QtCore import QPointF, Qt, QEvent, QPoint
+from PySide6.QtGui import QMouseEvent
+from PySide6.QtWidgets import QWidget, QApplication
+from PySide6.QtX11Extras import QX11Info
+from xcffib.xproto import (ButtonIndex, ButtonMask, ButtonReleaseEvent,
+ ClientMessageData, ClientMessageEvent, EventMask,
+ xprotoExtension)
+
+
+class WindowMessage(Enum):
+ """ Window message enum class """
+ # refer to: https://specifications.freedesktop.org/wm-spec/1.1/x170.html
+ _NET_WM_MOVERESIZE_SIZE_TOPLEFT = 0
+ _NET_WM_MOVERESIZE_SIZE_TOP = 1
+ _NET_WM_MOVERESIZE_SIZE_TOPRIGHT = 2
+ _NET_WM_MOVERESIZE_SIZE_RIGHT = 3
+ _NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT = 4
+ _NET_WM_MOVERESIZE_SIZE_BOTTOM = 5
+ _NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT = 6
+ _NET_WM_MOVERESIZE_SIZE_LEFT = 7
+ _NET_WM_MOVERESIZE_MOVE = 8
+ _NET_WM_MOVERESIZE_SIZE_KEYBOARD = 9
+ _NET_WM_MOVERESIZE_MOVE_KEYBOARD = 10
+ _NET_WM_MOVERESIZE_CANCEL = 11
+
+
+class LinuxMoveResize:
+ """ Tool class for moving and resizing window """
+
+ moveResizeAtom = None
+
+ @classmethod
+ def sendButtonReleaseEvent(cls, window, globalPos):
+ """ send button release event
+
+ Parameters
+ ----------
+ window: QWidget
+ window to be moved or resized
+
+ globalPos: QPoint
+ the global point of mouse release event
+ """
+ globalPos = QPointF(QPointF(globalPos) *
+ window.devicePixelRatio()).toPoint()
+ pos = window.mapFromGlobal(globalPos)
+
+ # open the connection to X server
+ conn = xcb.wrap(sip.unwrapinstance(QX11Info.connection()))
+ windowId = int(window.winId())
+ xproto = xprotoExtension(conn)
+
+ # refer to: https://www.x.org/releases/X11R7.5/doc/libxcb/tutorial/
+ event = ButtonReleaseEvent.synthetic(
+ detail=ButtonIndex._1,
+ time=xcb.CurrentTime,
+ root=QX11Info.appRootWindow(QX11Info.appScreen()),
+ event=windowId,
+ child=xcb.NONE,
+ root_x=globalPos.x(),
+ root_y=globalPos.y(),
+ event_x=pos.x(),
+ event_y=pos.y(),
+ state=ButtonMask._1,
+ same_screen=True,
+ )
+ xproto.SendEvent(True, windowId, EventMask.ButtonRelease, event.pack())
+ conn.flush()
+
+ @classmethod
+ def startSystemMoveResize(cls, window, globalPos, message):
+ """ resize window
+
+ Parameters
+ ----------
+ window: QWidget
+ window to be moved or resized
+
+ globalPos: QPoint
+ the global point of mouse release event
+
+ message: int
+ window message
+ """
+ cls.sendButtonReleaseEvent(window, globalPos)
+
+ globalPos = QPointF(QPointF(globalPos) *
+ window.devicePixelRatio()).toPoint()
+
+ # open the connection to X server
+ conn = xcb.wrap(sip.unwrapinstance(QX11Info.connection()))
+ xproto = xprotoExtension(conn)
+
+ if not cls.moveResizeAtom:
+ cls.moveResizeAtom = xproto.InternAtom(
+ False, len("_NET_WM_MOVERESIZE"), "_NET_WM_MOVERESIZE").reply().atom
+
+ union = ClientMessageData.synthetic([
+ globalPos.x(),
+ globalPos.y(),
+ message,
+ ButtonIndex._1,
+ 0
+ ], "I"*5)
+ event = ClientMessageEvent.synthetic(
+ format=32,
+ window=int(window.winId()),
+ type=cls.moveResizeAtom,
+ data=union
+ )
+ xproto.UngrabPointer(xcb.CurrentTime)
+ xproto.SendEvent(
+ False,
+ QX11Info.appRootWindow(QX11Info.appScreen()),
+ EventMask.SubstructureRedirect | EventMask.SubstructureNotify,
+ event.pack()
+ )
+ conn.flush()
+
+ @classmethod
+ def startSystemMove(cls, window, globalPos):
+ """ move window """
+ if QX11Info.isPlatformX11():
+ cls.startSystemMoveResize(
+ window, globalPos, WindowMessage._NET_WM_MOVERESIZE_MOVE.value)
+ else:
+ window.windowHandle().startSystemMove()
+ event = QMouseEvent(QEvent.MouseButtonRelease, QPoint(-1, -1),
+ Qt.LeftButton, Qt.NoButton, Qt.NoModifier)
+ QApplication.instance().postEvent(window.windowHandle(), event)
+
+ @classmethod
+ def starSystemResize(cls, window, globalPos, edges):
+ """ resize window
+
+ Parameters
+ ----------
+ window: QWidget
+ window
+
+ globalPos: QPoint
+ the global point of mouse release event
+
+ edges: `Qt.Edges`
+ window edges
+ """
+ if not edges:
+ return
+
+ if QX11Info.isPlatformX11():
+ messageMap = {
+ Qt.TopEdge: WindowMessage._NET_WM_MOVERESIZE_SIZE_TOP,
+ Qt.TopEdge | Qt.LeftEdge: WindowMessage._NET_WM_MOVERESIZE_SIZE_TOPLEFT,
+ Qt.TopEdge | Qt.RightEdge: WindowMessage._NET_WM_MOVERESIZE_SIZE_TOPRIGHT,
+ Qt.BottomEdge: WindowMessage._NET_WM_MOVERESIZE_SIZE_BOTTOM,
+ Qt.BottomEdge | Qt.LeftEdge: WindowMessage._NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT,
+ Qt.BottomEdge | Qt.RightEdge: WindowMessage._NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT,
+ Qt.LeftEdge: WindowMessage._NET_WM_MOVERESIZE_SIZE_LEFT,
+ Qt.RightEdge: WindowMessage._NET_WM_MOVERESIZE_SIZE_RIGHT,
+ }
+ cls.startSystemMoveResize(window, globalPos, messageMap[edges].value)
+ else:
+ window.windowHandle().startSystemResize(edges)
diff --git a/src/component/widget/qframelesswindow/utils/mac_utils.py b/src/component/widget/qframelesswindow/utils/mac_utils.py
new file mode 100644
index 0000000..a339f63
--- /dev/null
+++ b/src/component/widget/qframelesswindow/utils/mac_utils.py
@@ -0,0 +1,72 @@
+# coding:utf-8
+from ctypes import c_void_p
+
+import Cocoa
+import objc
+from PySide6.QtCore import QT_VERSION_STR
+from PySide6.QtWidgets import QWidget
+from Quartz.CoreGraphics import (CGEventCreateMouseEvent,
+ kCGEventLeftMouseDown, kCGMouseButtonLeft)
+
+QT_VERSION = tuple(int(v) for v in QT_VERSION_STR.split('.'))
+
+
+class MacMoveResize:
+ """ Tool class for moving and resizing Mac OS window """
+
+ @staticmethod
+ def startSystemMove(window: QWidget, globalPos):
+ """ resize window
+
+ Parameters
+ ----------
+ window: QWidget
+ window
+
+ globalPos: QPoint
+ the global point of mouse release event
+ """
+ if QT_VERSION >= (5, 15, 0):
+ window.windowHandle().startSystemMove()
+ return
+
+ nsWindow = getNSWindow(window.winId())
+
+ # send click event
+ cgEvent = CGEventCreateMouseEvent(
+ None, kCGEventLeftMouseDown, (globalPos.x(), globalPos.y()), kCGMouseButtonLeft)
+ clickEvent = Cocoa.NSEvent.eventWithCGEvent_(cgEvent)
+
+ if clickEvent:
+ nsWindow.performWindowDragWithEvent_(clickEvent)
+
+ # CFRelease(cgEvent)
+
+ @classmethod
+ def starSystemResize(cls, window, globalPos, edges):
+ """ resize window
+
+ Parameters
+ ----------
+ window: QWidget
+ window
+
+ globalPos: QPoint
+ the global point of mouse release event
+
+ edges: `Qt.Edges`
+ window edges
+ """
+ pass
+
+
+def getNSWindow(winId):
+ """ convert window handle to NSWindow
+
+ Parameters
+ ----------
+ winId: int or `sip.voidptr`
+ window handle
+ """
+ view = objc.objc_object(c_void_p=c_void_p(int(winId)))
+ return view.window()
diff --git a/src/component/widget/qframelesswindow/utils/win32_utils.py b/src/component/widget/qframelesswindow/utils/win32_utils.py
new file mode 100644
index 0000000..b5e7139
--- /dev/null
+++ b/src/component/widget/qframelesswindow/utils/win32_utils.py
@@ -0,0 +1,310 @@
+# coding:utf-8
+from ctypes import Structure, byref, sizeof, windll, c_int
+from ctypes.wintypes import DWORD, HWND, LPARAM, RECT, UINT
+from platform import platform
+import sys
+
+import win32api
+import win32con
+import win32gui
+import win32print
+from PySide6.QtCore import QOperatingSystemVersion
+from PySide6.QtGui import QGuiApplication
+from win32comext.shell import shellcon
+
+
+def isMaximized(hWnd):
+ """ Determine whether the window is maximized
+
+ Parameters
+ ----------
+ hWnd: int or `sip.voidptr`
+ window handle
+ """
+ windowPlacement = win32gui.GetWindowPlacement(hWnd)
+ if not windowPlacement:
+ return False
+
+ return windowPlacement[1] == win32con.SW_MAXIMIZE
+
+
+def isFullScreen(hWnd):
+ """ Determine whether the window is full screen
+
+ Parameters
+ ----------
+ hWnd: int or `sip.voidptr`
+ window handle
+ """
+ if not hWnd:
+ return False
+
+ hWnd = int(hWnd)
+ winRect = win32gui.GetWindowRect(hWnd)
+ if not winRect:
+ return False
+
+ monitorInfo = getMonitorInfo(hWnd, win32con.MONITOR_DEFAULTTOPRIMARY)
+ if not monitorInfo:
+ return False
+
+ monitorRect = monitorInfo["Monitor"]
+ return all(i == j for i, j in zip(winRect, monitorRect))
+
+
+def isCompositionEnabled():
+ """ detect if dwm composition is enabled """
+ bResult = c_int(0)
+ windll.dwmapi.DwmIsCompositionEnabled(byref(bResult))
+ return bool(bResult.value)
+
+
+def getMonitorInfo(hWnd, dwFlags):
+ """ get monitor info, return `None` if failed
+
+ Parameters
+ ----------
+ hWnd: int or `sip.voidptr`
+ window handle
+
+ dwFlags: int
+ Determines the return value if the window does not intersect any display monitor
+ """
+ monitor = win32api.MonitorFromWindow(hWnd, dwFlags)
+ if not monitor:
+ return
+
+ return win32api.GetMonitorInfo(monitor)
+
+
+def getResizeBorderThickness(hWnd, horizontal=True):
+ """ get resize border thickness of widget
+
+ Parameters
+ ----------
+ hWnd: int or `sip.voidptr`
+ window handle
+
+ dpiScale: bool
+ whether to use dpi scale
+ """
+ window = findWindow(hWnd)
+ if not window:
+ return 0
+
+ frame = win32con.SM_CXSIZEFRAME if horizontal else win32con.SM_CYSIZEFRAME
+ result = getSystemMetrics(hWnd, frame, horizontal) + getSystemMetrics(hWnd, 92, horizontal)
+
+ if result > 0:
+ return result
+
+ thickness = 8 if isCompositionEnabled() else 4
+ return round(thickness*window.devicePixelRatio())
+
+
+def getSystemMetrics(hWnd, index, horizontal):
+ """ get system metrics """
+ if not hasattr(windll.user32, 'GetSystemMetricsForDpi'):
+ return win32api.GetSystemMetrics(index)
+
+ dpi = getDpiForWindow(hWnd, horizontal)
+ return windll.user32.GetSystemMetricsForDpi(index, dpi)
+
+
+def getDpiForWindow(hWnd, horizontal=True):
+ """ get dpi for window
+
+ Parameters
+ ----------
+ hWnd: int or `sip.voidptr`
+ window handle
+
+ dpiScale: bool
+ whether to use dpi scale
+ """
+ if hasattr(windll.user32, 'GetDpiForWindow'):
+ return windll.user32.GetDpiForWindow(hWnd)
+
+ hdc = win32gui.GetDC(hWnd)
+ if not hdc:
+ return 96
+
+ dpiX = win32print.GetDeviceCaps(hdc, win32con.LOGPIXELSX)
+ dpiY = win32print.GetDeviceCaps(hdc, win32con.LOGPIXELSY)
+ win32gui.ReleaseDC(hWnd, hdc)
+ if dpiX > 0 and horizontal:
+ return dpiX
+ elif dpiY > 0 and not horizontal:
+ return dpiY
+
+ return 96
+
+
+def findWindow(hWnd):
+ """ find window by hWnd, return `None` if not found
+
+ Parameters
+ ----------
+ hWnd: int or `sip.voidptr`
+ window handle
+ """
+ if not hWnd:
+ return
+
+ windows = QGuiApplication.topLevelWindows()
+ if not windows:
+ return
+
+ hWnd = int(hWnd)
+ for window in windows:
+ if window and int(window.winId()) == hWnd:
+ return window
+
+
+def isGreaterEqualVersion(version):
+ """ determine if the windows version ≥ the specifics version
+
+ Parameters
+ ----------
+ version: QOperatingSystemVersion
+ windows version
+ """
+ return QOperatingSystemVersion.current() >= version
+
+
+def isGreaterEqualWin8_1():
+ """ determine if the windows version ≥ Win8.1 """
+ return isGreaterEqualVersion(QOperatingSystemVersion.Windows8_1)
+
+
+def isGreaterEqualWin10():
+ """ determine if the windows version ≥ Win10 """
+ return isGreaterEqualVersion(QOperatingSystemVersion.Windows10)
+
+
+def isGreaterEqualWin11():
+ """ determine if the windows version ≥ Win10 """
+ return isGreaterEqualVersion(QOperatingSystemVersion.Windows10) and sys.getwindowsversion().build >= 22000
+
+
+def isWin7():
+ """ determine if the windows version is Win7 """
+ return "Windows-7" in platform()
+
+
+class APPBARDATA(Structure):
+ _fields_ = [
+ ('cbSize', DWORD),
+ ('hWnd', HWND),
+ ('uCallbackMessage', UINT),
+ ('uEdge', UINT),
+ ('rc', RECT),
+ ('lParam', LPARAM),
+ ]
+
+
+class Taskbar:
+
+ LEFT = 0
+ TOP = 1
+ RIGHT = 2
+ BOTTOM = 3
+ NO_POSITION = 4
+
+ AUTO_HIDE_THICKNESS = 2
+
+ @staticmethod
+ def isAutoHide():
+ """ detect whether the taskbar is hidden automatically """
+ appbarData = APPBARDATA(sizeof(APPBARDATA), 0,
+ 0, 0, RECT(0, 0, 0, 0), 0)
+ taskbarState = windll.shell32.SHAppBarMessage(
+ shellcon.ABM_GETSTATE, byref(appbarData))
+
+ return taskbarState == shellcon.ABS_AUTOHIDE
+
+ @classmethod
+ def getPosition(cls, hWnd):
+ """ get the position of auto-hide task bar
+
+ Parameters
+ ----------
+ hWnd: int or `sip.voidptr`
+ window handle
+ """
+ if isGreaterEqualWin8_1():
+ monitorInfo = getMonitorInfo(
+ hWnd, win32con.MONITOR_DEFAULTTONEAREST)
+ if not monitorInfo:
+ return cls.NO_POSITION
+
+ monitor = RECT(*monitorInfo['Monitor'])
+ appbarData = APPBARDATA(sizeof(APPBARDATA), 0, 0, 0, monitor, 0)
+ positions = [cls.LEFT, cls.TOP, cls.RIGHT, cls.BOTTOM]
+ for position in positions:
+ appbarData.uEdge = position
+ if windll.shell32.SHAppBarMessage(11, byref(appbarData)):
+ return position
+
+ return cls.NO_POSITION
+
+ appbarData = APPBARDATA(sizeof(APPBARDATA), win32gui.FindWindow(
+ "Shell_TrayWnd", None), 0, 0, RECT(0, 0, 0, 0), 0)
+ if appbarData.hWnd:
+ windowMonitor = win32api.MonitorFromWindow(
+ hWnd, win32con.MONITOR_DEFAULTTONEAREST)
+ if not windowMonitor:
+ return cls.NO_POSITION
+
+ taskbarMonitor = win32api.MonitorFromWindow(
+ appbarData.hWnd, win32con.MONITOR_DEFAULTTOPRIMARY)
+ if not taskbarMonitor:
+ return cls.NO_POSITION
+
+ if taskbarMonitor == windowMonitor:
+ windll.shell32.SHAppBarMessage(
+ shellcon.ABM_GETTASKBARPOS, byref(appbarData))
+ return appbarData.uEdge
+
+ return cls.NO_POSITION
+
+
+class WindowsMoveResize:
+ """ Tool class for moving and resizing Mac OS window """
+
+ @staticmethod
+ def startSystemMove(window, globalPos):
+ """ resize window
+
+ Parameters
+ ----------
+ window: QWidget
+ window
+
+ globalPos: QPoint
+ the global point of mouse release event
+ """
+ win32gui.ReleaseCapture()
+ win32api.SendMessage(
+ int(window.winId()),
+ win32con.WM_SYSCOMMAND,
+ win32con.SC_MOVE | win32con.HTCAPTION,
+ 0
+ )
+
+ @classmethod
+ def starSystemResize(cls, window, globalPos, edges):
+ """ resize window
+
+ Parameters
+ ----------
+ window: QWidget
+ window
+
+ globalPos: QPoint
+ the global point of mouse release event
+
+ edges: `Qt.Edges`
+ window edges
+ """
+ pass
diff --git a/src/component/widget/qframelesswindow/windows/__init__.py b/src/component/widget/qframelesswindow/windows/__init__.py
new file mode 100644
index 0000000..51d298e
--- /dev/null
+++ b/src/component/widget/qframelesswindow/windows/__init__.py
@@ -0,0 +1,199 @@
+# coding:utf-8
+import sys
+from ctypes import cast
+from ctypes.wintypes import LPRECT, MSG
+
+import win32api
+import win32con
+import win32gui
+from PySide6.QtCore import Qt
+from PySide6.QtGui import QCloseEvent, QCursor
+from PySide6.QtWidgets import QApplication, QWidget
+
+from ..titlebar import TitleBar
+from ..utils import win32_utils as win_utils
+from ..utils.win32_utils import Taskbar
+from .c_structures import LPNCCALCSIZE_PARAMS
+from .window_effect import WindowsWindowEffect
+
+
+class WindowsFramelessWindow(QWidget):
+ """ Frameless window for Windows system """
+
+ BORDER_WIDTH = 5
+
+ def __init__(self, parent=None):
+ super().__init__(parent=parent)
+ self.windowEffect = WindowsWindowEffect(self)
+ self.titleBar = TitleBar(self)
+ self._isResizeEnabled = True
+
+ self.updateFrameless()
+
+ # solve issue #5
+ self.windowHandle().screenChanged.connect(self.__onScreenChanged)
+
+ self.resize(500, 500)
+ self.titleBar.raise_()
+
+ def updateFrameless(self):
+ """ update frameless window """
+ if not win_utils.isWin7():
+ self.setWindowFlags(self.windowFlags() | Qt.FramelessWindowHint)
+ elif self.parent():
+ self.setWindowFlags(self.parent().windowFlags() | Qt.FramelessWindowHint | Qt.WindowMinMaxButtonsHint)
+ else:
+ self.setWindowFlags(Qt.FramelessWindowHint | Qt.WindowMinMaxButtonsHint)
+
+ # add DWM shadow and window animation
+ self.windowEffect.addWindowAnimation(self.winId())
+ if not isinstance(self, AcrylicWindow):
+ self.windowEffect.addShadowEffect(self.winId())
+
+ def setTitleBar(self, titleBar):
+ """ set custom title bar
+
+ Parameters
+ ----------
+ titleBar: TitleBar
+ title bar
+ """
+ self.titleBar.deleteLater()
+ self.titleBar.hide()
+ self.titleBar = titleBar
+ self.titleBar.setParent(self)
+ self.titleBar.raise_()
+
+ def setResizeEnabled(self, isEnabled: bool):
+ """ set whether resizing is enabled """
+ self._isResizeEnabled = isEnabled
+
+ def resizeEvent(self, e):
+ super().resizeEvent(e)
+ self.titleBar.resize(self.width(), self.titleBar.height())
+
+ def nativeEvent(self, eventType, message):
+ """ Handle the Windows message """
+ msg = MSG.from_address(message.__int__())
+ if not msg.hWnd:
+ return super().nativeEvent(eventType, message)
+
+ if msg.message == win32con.WM_NCHITTEST and self._isResizeEnabled:
+ pos = QCursor.pos()
+ xPos = pos.x() - self.x()
+ yPos = pos.y() - self.y()
+ w = self.frameGeometry().width()
+ h = self.frameGeometry().height()
+
+ # fixes issue https://github.com/zhiyiYo/PyQt-Frameless-Window/issues/98
+ bw = 0 if win_utils.isMaximized(msg.hWnd) or win_utils.isFullScreen(msg.hWnd) else self.BORDER_WIDTH
+ lx = xPos < bw
+ rx = xPos > w - bw
+ ty = yPos < bw
+ by = yPos > h - bw
+ if lx and ty:
+ return True, win32con.HTTOPLEFT
+ elif rx and by:
+ return True, win32con.HTBOTTOMRIGHT
+ elif rx and ty:
+ return True, win32con.HTTOPRIGHT
+ elif lx and by:
+ return True, win32con.HTBOTTOMLEFT
+ elif ty:
+ return True, win32con.HTTOP
+ elif by:
+ return True, win32con.HTBOTTOM
+ elif lx:
+ return True, win32con.HTLEFT
+ elif rx:
+ return True, win32con.HTRIGHT
+ elif msg.message == win32con.WM_NCCALCSIZE:
+ if msg.wParam:
+ rect = cast(msg.lParam, LPNCCALCSIZE_PARAMS).contents.rgrc[0]
+ else:
+ rect = cast(msg.lParam, LPRECT).contents
+
+ isMax = win_utils.isMaximized(msg.hWnd)
+ isFull = win_utils.isFullScreen(msg.hWnd)
+
+ # adjust the size of client rect
+ if isMax and not isFull:
+ ty = win_utils.getResizeBorderThickness(msg.hWnd, False)
+ rect.top += ty
+ rect.bottom -= ty
+
+ tx = win_utils.getResizeBorderThickness(msg.hWnd, True)
+ rect.left += tx
+ rect.right -= tx
+
+ # handle the situation that an auto-hide taskbar is enabled
+ if (isMax or isFull) and Taskbar.isAutoHide():
+ position = Taskbar.getPosition(msg.hWnd)
+ if position == Taskbar.LEFT:
+ rect.top += Taskbar.AUTO_HIDE_THICKNESS
+ elif position == Taskbar.BOTTOM:
+ rect.bottom -= Taskbar.AUTO_HIDE_THICKNESS
+ elif position == Taskbar.LEFT:
+ rect.left += Taskbar.AUTO_HIDE_THICKNESS
+ elif position == Taskbar.RIGHT:
+ rect.right -= Taskbar.AUTO_HIDE_THICKNESS
+
+ result = 0 if not msg.wParam else win32con.WVR_REDRAW
+ return True, result
+
+ return super().nativeEvent(eventType, message)
+
+ def __onScreenChanged(self):
+ hWnd = int(self.windowHandle().winId())
+ win32gui.SetWindowPos(hWnd, None, 0, 0, 0, 0, win32con.SWP_NOMOVE |
+ win32con.SWP_NOSIZE | win32con.SWP_FRAMECHANGED)
+
+
+class AcrylicWindow(WindowsFramelessWindow):
+ """ A frameless window with acrylic effect """
+
+ def __init__(self, parent=None):
+ super().__init__(parent=parent)
+ self.__closedByKey = False
+ self.setStyleSheet("AcrylicWindow{background:transparent}")
+
+ def updateFrameless(self):
+ super().updateFrameless()
+ self.windowEffect.enableBlurBehindWindow(self.winId())
+
+ if win_utils.isWin7() and self.parent():
+ self.setWindowFlags(self.parent().windowFlags() | Qt.FramelessWindowHint | Qt.WindowMinMaxButtonsHint)
+ else:
+ self.setWindowFlags(Qt.FramelessWindowHint | Qt.WindowMinMaxButtonsHint)
+
+ self.windowEffect.addWindowAnimation(self.winId())
+
+ if win_utils.isWin7():
+ self.windowEffect.addShadowEffect(self.winId())
+ self.windowEffect.setAeroEffect(self.winId())
+ else:
+ self.windowEffect.setAcrylicEffect(self.winId())
+ if win_utils.isGreaterEqualWin11():
+ self.windowEffect.addShadowEffect(self.winId())
+
+ def nativeEvent(self, eventType, message):
+ """ Handle the Windows message """
+ msg = MSG.from_address(message.__int__())
+
+ # handle Alt+F4
+ if msg.message == win32con.WM_SYSKEYDOWN:
+ if msg.wParam == win32con.VK_F4:
+ self.__closedByKey = True
+ QApplication.sendEvent(self, QCloseEvent())
+ return False, 0
+
+ return super().nativeEvent(eventType, message)
+
+ def closeEvent(self, e):
+ if not self.__closedByKey or QApplication.quitOnLastWindowClosed():
+ self.__closedByKey = False
+ return super().closeEvent(e)
+
+ # system tray icon
+ self.__closedByKey = False
+ self.hide()
diff --git a/src/component/widget/qframelesswindow/windows/c_structures.py b/src/component/widget/qframelesswindow/windows/c_structures.py
new file mode 100644
index 0000000..bcb20df
--- /dev/null
+++ b/src/component/widget/qframelesswindow/windows/c_structures.py
@@ -0,0 +1,153 @@
+# coding:utf-8
+from ctypes import POINTER, Structure, c_int
+from ctypes.wintypes import DWORD, HWND, ULONG, POINT, RECT, UINT, BOOL, HRGN
+from enum import Enum
+
+
+class WINDOWCOMPOSITIONATTRIB(Enum):
+ WCA_UNDEFINED = 0
+ WCA_NCRENDERING_ENABLED = 1
+ WCA_NCRENDERING_POLICY = 2
+ WCA_TRANSITIONS_FORCEDISABLED = 3
+ WCA_ALLOW_NCPAINT = 4
+ WCA_CAPTION_BUTTON_BOUNDS = 5
+ WCA_NONCLIENT_RTL_LAYOUT = 6
+ WCA_FORCE_ICONIC_REPRESENTATION = 7
+ WCA_EXTENDED_FRAME_BOUNDS = 8
+ WCA_HAS_ICONIC_BITMAP = 9
+ WCA_THEME_ATTRIBUTES = 10
+ WCA_NCRENDERING_EXILED = 11
+ WCA_NCADORNMENTINFO = 12
+ WCA_EXCLUDED_FROM_LIVEPREVIEW = 13
+ WCA_VIDEO_OVERLAY_ACTIVE = 14
+ WCA_FORCE_ACTIVEWINDOW_APPEARANCE = 15
+ WCA_DISALLOW_PEEK = 16
+ WCA_CLOAK = 17
+ WCA_CLOAKED = 18
+ WCA_ACCENT_POLICY = 19
+ WCA_FREEZE_REPRESENTATION = 20
+ WCA_EVER_UNCLOAKED = 21
+ WCA_VISUAL_OWNER = 22
+ WCA_HOLOGRAPHIC = 23
+ WCA_EXCLUDED_FROM_DDA = 24
+ WCA_PASSIVEUPDATEMODE = 25
+ WCA_USEDARKMODECOLORS = 26
+ WCA_CORNER_STYLE = 27
+ WCA_PART_COLOR = 28
+ WCA_DISABLE_MOVESIZE_FEEDBACK = 29
+ WCA_LAST = 30
+
+
+class ACCENT_STATE(Enum):
+ """ Client area status enumeration class """
+ ACCENT_DISABLED = 0
+ ACCENT_ENABLE_GRADIENT = 1
+ ACCENT_ENABLE_TRANSPARENTGRADIENT = 2
+ ACCENT_ENABLE_BLURBEHIND = 3 # Aero effect
+ ACCENT_ENABLE_ACRYLICBLURBEHIND = 4 # Acrylic effect
+ ACCENT_ENABLE_HOSTBACKDROP = 5 # Mica effect
+ ACCENT_INVALID_STATE = 6
+
+
+class ACCENT_POLICY(Structure):
+ """ Specific attributes of client area """
+
+ _fields_ = [
+ ("AccentState", DWORD),
+ ("AccentFlags", DWORD),
+ ("GradientColor", DWORD),
+ ("AnimationId", DWORD),
+ ]
+
+
+class WINDOWCOMPOSITIONATTRIBDATA(Structure):
+ _fields_ = [
+ ("Attribute", DWORD),
+ # Pointer() receives any ctypes type and returns a pointer type
+ ("Data", POINTER(ACCENT_POLICY)),
+ ("SizeOfData", ULONG),
+ ]
+
+
+class DWMNCRENDERINGPOLICY(Enum):
+ DWMNCRP_USEWINDOWSTYLE = 0
+ DWMNCRP_DISABLED = 1
+ DWMNCRP_ENABLED = 2
+ DWMNCRP_LAS = 3
+
+
+class DWMWINDOWATTRIBUTE(Enum):
+ DWMWA_NCRENDERING_ENABLED = 1
+ DWMWA_NCRENDERING_POLICY = 2
+ DWMWA_TRANSITIONS_FORCEDISABLED = 3
+ DWMWA_ALLOW_NCPAINT = 4
+ DWMWA_CAPTION_BUTTON_BOUNDS = 5
+ DWMWA_NONCLIENT_RTL_LAYOUT = 6
+ DWMWA_FORCE_ICONIC_REPRESENTATION = 7
+ DWMWA_FLIP3D_POLICY = 8
+ DWMWA_EXTENDED_FRAME_BOUNDS = 9
+ DWMWA_HAS_ICONIC_BITMAP = 10
+ DWMWA_DISALLOW_PEEK = 11
+ DWMWA_EXCLUDED_FROM_PEEK = 12
+ DWMWA_CLOAK = 13
+ DWMWA_CLOAKED = 14
+ DWMWA_FREEZE_REPRESENTATION = 15
+ DWMWA_PASSIVE_UPDATE_MODE = 16
+ DWMWA_USE_HOSTBACKDROPBRUSH = 17
+ DWMWA_USE_IMMERSIVE_DARK_MODE = 18
+ DWMWA_WINDOW_CORNER_PREFERENCE = 19
+ DWMWA_BORDER_COLOR = 20
+ DWMWA_CAPTION_COLOR = 21
+ DWMWA_TEXT_COLOR = 22
+ DWMWA_VISIBLE_FRAME_BORDER_THICKNESS = 23
+ DWMWA_LAST = 24
+
+
+class MARGINS(Structure):
+ _fields_ = [
+ ("cxLeftWidth", c_int),
+ ("cxRightWidth", c_int),
+ ("cyTopHeight", c_int),
+ ("cyBottomHeight", c_int),
+ ]
+
+
+class MINMAXINFO(Structure):
+ _fields_ = [
+ ("ptReserved", POINT),
+ ("ptMaxSize", POINT),
+ ("ptMaxPosition", POINT),
+ ("ptMinTrackSize", POINT),
+ ("ptMaxTrackSize", POINT),
+ ]
+
+
+class PWINDOWPOS(Structure):
+ _fields_ = [
+ ('hWnd', HWND),
+ ('hwndInsertAfter', HWND),
+ ('x', c_int),
+ ('y', c_int),
+ ('cx', c_int),
+ ('cy', c_int),
+ ('flags', UINT)
+ ]
+
+
+class NCCALCSIZE_PARAMS(Structure):
+ _fields_ = [
+ ('rgrc', RECT*3),
+ ('lppos', POINTER(PWINDOWPOS))
+ ]
+
+
+LPNCCALCSIZE_PARAMS = POINTER(NCCALCSIZE_PARAMS)
+
+
+class DWM_BLURBEHIND(Structure):
+ _fields_ = [
+ ('dwFlags', DWORD),
+ ('fEnable', BOOL),
+ ('hRgnBlur', HRGN),
+ ('fTransitionOnMaximized', BOOL),
+ ]
diff --git a/src/component/widget/qframelesswindow/windows/window_effect.py b/src/component/widget/qframelesswindow/windows/window_effect.py
new file mode 100644
index 0000000..7a437a3
--- /dev/null
+++ b/src/component/widget/qframelesswindow/windows/window_effect.py
@@ -0,0 +1,260 @@
+# coding:utf-8
+import sys
+import warnings
+from ctypes import POINTER, byref, c_bool, c_int, pointer, sizeof, WinDLL
+from ctypes.wintypes import DWORD, LONG, LPCVOID
+
+import win32api
+import win32con
+import win32gui
+
+from .c_structures import (ACCENT_POLICY, ACCENT_STATE, DWMNCRENDERINGPOLICY,
+ DWMWINDOWATTRIBUTE, MARGINS,
+ WINDOWCOMPOSITIONATTRIB,
+ WINDOWCOMPOSITIONATTRIBDATA, DWM_BLURBEHIND)
+from ..utils.win32_utils import isGreaterEqualWin10, isGreaterEqualWin11, isCompositionEnabled
+
+
+class WindowsWindowEffect:
+ """ Windows window effect """
+
+ def __init__(self, window):
+ self.window = window
+
+ # Declare the function signature of the API
+ self.user32 = WinDLL("user32")
+ self.dwmapi = WinDLL("dwmapi")
+ self.SetWindowCompositionAttribute = self.user32.SetWindowCompositionAttribute
+ self.DwmExtendFrameIntoClientArea = self.dwmapi.DwmExtendFrameIntoClientArea
+ self.DwmEnableBlurBehindWindow = self.dwmapi.DwmEnableBlurBehindWindow
+ self.DwmSetWindowAttribute = self.dwmapi.DwmSetWindowAttribute
+
+ self.SetWindowCompositionAttribute.restype = c_bool
+ self.DwmExtendFrameIntoClientArea.restype = LONG
+ self.DwmEnableBlurBehindWindow.restype = LONG
+ self.DwmSetWindowAttribute.restype = LONG
+
+ self.SetWindowCompositionAttribute.argtypes = [
+ c_int,
+ POINTER(WINDOWCOMPOSITIONATTRIBDATA),
+ ]
+ self.DwmSetWindowAttribute.argtypes = [c_int, DWORD, LPCVOID, DWORD]
+ self.DwmExtendFrameIntoClientArea.argtypes = [c_int, POINTER(MARGINS)]
+ self.DwmEnableBlurBehindWindow.argtypes = [c_int, POINTER(DWM_BLURBEHIND)]
+
+ # Initialize structure
+ self.accentPolicy = ACCENT_POLICY()
+ self.winCompAttrData = WINDOWCOMPOSITIONATTRIBDATA()
+ self.winCompAttrData.Attribute = WINDOWCOMPOSITIONATTRIB.WCA_ACCENT_POLICY.value
+ self.winCompAttrData.SizeOfData = sizeof(self.accentPolicy)
+ self.winCompAttrData.Data = pointer(self.accentPolicy)
+
+ def setAcrylicEffect(self, hWnd, gradientColor="F2F2F299", enableShadow=True, animationId=0):
+ """ Add the acrylic effect to the window
+
+ Parameters
+ ----------
+ hWnd: int or `sip.voidptr`
+ Window handle
+
+ gradientColor: str
+ Hexadecimal acrylic mixed color, corresponding to four RGBA channels
+
+ isEnableShadow: bool
+ Enable window shadows
+
+ animationId: int
+ Turn on matte animation
+ """
+ if not isGreaterEqualWin10():
+ warnings.warn("The acrylic effect is only available on Win10+")
+ return
+
+ hWnd = int(hWnd)
+ gradientColor = ''.join(gradientColor[i:i+2] for i in range(6, -1, -2))
+ gradientColor = DWORD(int(gradientColor, base=16))
+ animationId = DWORD(animationId)
+ accentFlags = DWORD(0x20 | 0x40 | 0x80 | 0x100) if enableShadow else DWORD(0)
+ self.accentPolicy.AccentState = ACCENT_STATE.ACCENT_ENABLE_ACRYLICBLURBEHIND.value
+ self.accentPolicy.GradientColor = gradientColor
+ self.accentPolicy.AccentFlags = accentFlags
+ self.accentPolicy.AnimationId = animationId
+ self.winCompAttrData.Attribute = WINDOWCOMPOSITIONATTRIB.WCA_ACCENT_POLICY.value
+ self.SetWindowCompositionAttribute(hWnd, pointer(self.winCompAttrData))
+
+ def setMicaEffect(self, hWnd, isDarkMode=False, isAlt=False):
+ """ Add the mica effect to the window (Win11 only)
+
+ Parameters
+ ----------
+ hWnd: int or `sip.voidptr`
+ Window handle
+
+ isDarkMode: bool
+ whether to use dark mode mica effect
+
+ isAlt: bool
+ whether to enable mica alt effect
+ """
+ if not isGreaterEqualWin11():
+ warnings.warn("The mica effect is only available on Win11")
+ return
+
+ hWnd = int(hWnd)
+ margins = MARGINS(-1, -1, -1, -1)
+ self.DwmExtendFrameIntoClientArea(hWnd, byref(margins))
+
+ self.winCompAttrData.Attribute = WINDOWCOMPOSITIONATTRIB.WCA_ACCENT_POLICY.value
+ self.accentPolicy.AccentState = ACCENT_STATE.ACCENT_ENABLE_HOSTBACKDROP.value
+ self.SetWindowCompositionAttribute(hWnd, pointer(self.winCompAttrData))
+
+ if isDarkMode:
+ self.winCompAttrData.Attribute = WINDOWCOMPOSITIONATTRIB.WCA_USEDARKMODECOLORS.value
+ self.SetWindowCompositionAttribute(hWnd, pointer(self.winCompAttrData))
+
+ if sys.getwindowsversion().build < 22523:
+ self.DwmSetWindowAttribute(hWnd, 1029, byref(c_int(1)), 4)
+ else:
+ self.DwmSetWindowAttribute(hWnd, 38, byref(c_int(4 if isAlt else 2)), 4)
+
+ self.DwmSetWindowAttribute(hWnd, 20, byref(c_int(1*isDarkMode)), 4)
+
+ def setAeroEffect(self, hWnd):
+ """ Add the aero effect to the window
+
+ Parameters
+ ----------
+ hWnd: int or `sip.voidptr`
+ Window handle
+ """
+ hWnd = int(hWnd)
+ self.winCompAttrData.Attribute = WINDOWCOMPOSITIONATTRIB.WCA_ACCENT_POLICY.value
+ self.accentPolicy.AccentState = ACCENT_STATE.ACCENT_ENABLE_BLURBEHIND.value
+ self.SetWindowCompositionAttribute(hWnd, pointer(self.winCompAttrData))
+
+ def removeBackgroundEffect(self, hWnd):
+ """ Remove background effect
+
+ Parameters
+ ----------
+ hWnd: int or `sip.voidptr`
+ Window handle
+ """
+ hWnd = int(hWnd)
+ self.accentPolicy.AccentState = ACCENT_STATE.ACCENT_DISABLED.value
+ self.SetWindowCompositionAttribute(hWnd, pointer(self.winCompAttrData))
+
+ def addShadowEffect(self, hWnd):
+ """ Add DWM shadow to window
+
+ Parameters
+ ----------
+ hWnd: int or `sip.voidptr`
+ Window handle
+ """
+ if not isCompositionEnabled():
+ return
+
+ hWnd = int(hWnd)
+ margins = MARGINS(-1, -1, -1, -1)
+ self.DwmExtendFrameIntoClientArea(hWnd, byref(margins))
+
+ def addMenuShadowEffect(self, hWnd):
+ """ Add DWM shadow to menu
+
+ Parameters
+ ----------
+ hWnd: int or `sip.voidptr`
+ Window handle
+ """
+ if not isCompositionEnabled():
+ return
+
+ hWnd = int(hWnd)
+ self.DwmSetWindowAttribute(
+ hWnd,
+ DWMWINDOWATTRIBUTE.DWMWA_NCRENDERING_POLICY.value,
+ byref(c_int(DWMNCRENDERINGPOLICY.DWMNCRP_ENABLED.value)),
+ 4,
+ )
+ margins = MARGINS(-1, -1, -1, -1)
+ self.DwmExtendFrameIntoClientArea(hWnd, byref(margins))
+
+ def removeShadowEffect(self, hWnd):
+ """ Remove DWM shadow from the window
+
+ Parameters
+ ----------
+ hWnd: int or `sip.voidptr`
+ Window handle
+ """
+ hWnd = int(hWnd)
+ self.DwmSetWindowAttribute(
+ hWnd,
+ DWMWINDOWATTRIBUTE.DWMWA_NCRENDERING_POLICY.value,
+ byref(c_int(DWMNCRENDERINGPOLICY.DWMNCRP_DISABLED.value)),
+ 4,
+ )
+
+ @staticmethod
+ def removeMenuShadowEffect(hWnd):
+ """ Remove shadow from pop-up menu
+
+ Parameters
+ ----------
+ hWnd: int or `sip.voidptr`
+ Window handle
+ """
+ hWnd = int(hWnd)
+ style = win32gui.GetClassLong(hWnd, win32con.GCL_STYLE)
+ style &= ~0x00020000 # CS_DROPSHADOW
+ win32api.SetClassLong(hWnd, win32con.GCL_STYLE, style)
+
+ @staticmethod
+ def addWindowAnimation(hWnd):
+ """ Enables the maximize and minimize animation of the window
+
+ Parameters
+ ----------
+ hWnd : int or `sip.voidptr`
+ Window handle
+ """
+ hWnd = int(hWnd)
+ style = win32gui.GetWindowLong(hWnd, win32con.GWL_STYLE)
+ win32gui.SetWindowLong(
+ hWnd,
+ win32con.GWL_STYLE,
+ style
+ | win32con.WS_MINIMIZEBOX
+ | win32con.WS_MAXIMIZEBOX
+ | win32con.WS_CAPTION
+ | win32con.CS_DBLCLKS
+ | win32con.WS_THICKFRAME,
+ )
+
+ @staticmethod
+ def disableMaximizeButton(hWnd):
+ """ Disable the maximize button of window
+
+ Parameters
+ ----------
+ hWnd : int or `sip.voidptr`
+ Window handle
+ """
+ hWnd = int(hWnd)
+ style = win32gui.GetWindowLong(hWnd, win32con.GWL_STYLE)
+ win32gui.SetWindowLong(
+ hWnd,
+ win32con.GWL_STYLE,
+ style & ~win32con.WS_MAXIMIZEBOX,
+ )
+
+ def enableBlurBehindWindow(self, hWnd):
+ """ enable the blur effect behind the whole client
+ Parameters
+ ----------
+ hWnd: int or `sip.voidptr`
+ Window handle
+ """
+ blurBehind = DWM_BLURBEHIND(1, True, 0, False)
+ self.DwmEnableBlurBehindWindow(int(hWnd), byref(blurBehind))
diff --git a/src/config/config.py b/src/config/config.py
index cf563d2..610b998 100644
--- a/src/config/config.py
+++ b/src/config/config.py
@@ -50,9 +50,9 @@
Issues2 = "https://hub.ggo.icu/tonquer/picacg-qt/issues"
Issues3 = "https://hub.fastgit.xyz/tonquer/picacg-qt/issues"
-UpdateVersion = "v1.4.8"
-RealVersion = "v1.4.8"
-TimeVersion = "2024-1-12"
+UpdateVersion = "v1.4.9"
+RealVersion = "v1.4.9"
+TimeVersion = "2024-4-6"
Waifu2xVersion = "1.1.6"
@@ -78,14 +78,14 @@
# Waifu2x相关
Waifu2xUrl = "https://github.com/tonquer/picacg-qt/discussions/76"
-Address = ["188.114.98.153", "104.21.91.145"] # 分类2,3 Ip列表
-AddressIpv6 = ["2606:4700:d:28:dbf4:26f3:c265:73bc", "2a06:98c1:3120:ca71:be2c:c721:d2b5:5dbf"]
+# Address = ["188.114.98.153", "104.21.91.145"] # 分类2,3 Ip列表
+# AddressIpv6 = ["2606:4700:d:28:dbf4:26f3:c265:73bc", "2a06:98c1:3120:ca71:be2c:c721:d2b5:5dbf"]
-ImageServer2 = 's3.picacomic.com' # 分流2 使用的图片服务器
-ImageServer2Jump = 'img.picacomic.com' # 分流2 跳转的图片服务器
+# ImageServer2 = 's3.picacomic.com' # 分流2 使用的图片服务器
+# ImageServer2Jump = 'img.picacomic.com' # 分流2 跳转的图片服务器
-ImageServer3 = 'storage.diwodiwo.xyz' # 分流3 使用的图片服务器
-ImageServer3Jump = 'img.diwodiwo.xyz' # 分流3 使用的图片服务器
+# ImageServer3 = 'storage.diwodiwo.xyz' # 分流3 使用的图片服务器
+# ImageServer3Jump = 'img.diwodiwo.xyz' # 分流3 使用的图片服务器
ProxyApiDomain = "bika-api.ggo.icu"
ProxyImgDomain = "bika-img.ggo.icu"
@@ -100,14 +100,13 @@
ImageDomain = [
"s3.picacomic.com",
- # "storage.diwodiwo.xyz",
+ "storage.diwodiwo.xyz",
# "img.diwodiwo.xyz",
"storage1.picacomic.com",
- "img.tipatipa.xyz",
- "img.picacomic.com",
+ # "img.tipatipa.xyz",
+ # "img.picacomic.com",
"storage.tipatipa.xyz",
# "pica-pica.wikawika.xyz",
"www.picacomic.com",
"storage-b.picacomic.com",
-
-]
+]
\ No newline at end of file
diff --git a/src/config/global_config.py b/src/config/global_config.py
new file mode 100644
index 0000000..d3af0b0
--- /dev/null
+++ b/src/config/global_config.py
@@ -0,0 +1,115 @@
+from config.setting import Setting
+from tools.log import Log
+from tools.singleton import Singleton
+
+
+class GlobalItem(object):
+ def __init__(self, default):
+ self.value = default
+ self.def_value = default
+
+ def is_same(self):
+ return self.value == self.def_value
+
+ def set_value(self, value):
+ if isinstance(self.def_value, int):
+ self.value = int(value)
+ elif isinstance(self.def_value, list) and isinstance(value, str):
+ self.value = value.split(",")
+ else:
+ self.value = value
+
+
+class GlobalConfig:
+ Ver = GlobalItem(0)
+ LocalProxyIndex = [2, 3]
+ Address = GlobalItem(["104.21.91.145", "188.114.98.153"])
+ AddressIpv6 = GlobalItem(["2606:4700:d:28:dbf4:26f3:c265:73bc", "2a06:98c1:3120:ca71:be2c:c721:d2b5:5dbf"])
+ ImageUrl = GlobalItem("s3.picacomic.com")
+ ImageServerList = GlobalItem(["s3.picacomic.com", "storage.diwodiwo.xyz", "storage-b.picacomic.com", "storage1.picacomic.com"])
+ ImageJumList = GlobalItem(["img.picacomic.com", "img.diwodiwo.xyz"])
+
+ def __init__(self):
+ pass
+
+ @staticmethod
+ def GetAddress(index):
+ if index in GlobalConfig.LocalProxyIndex:
+ i = GlobalConfig.LocalProxyIndex.index(index)
+ if Setting.PreIpv6.value > 0:
+ return GlobalConfig.AddressIpv6.value[i]
+ else:
+ return GlobalConfig.Address.value[i]
+ else:
+ return ""
+ #
+ # @staticmethod
+ # def GetImageServer(index):
+ # if index in GlobalConfig.LocalProxyIndex:
+ # i = GlobalConfig.LocalProxyIndex.index(index)
+ # return GlobalConfig.ImageServerList.value[i]
+ # else:
+ # return ""
+
+ @staticmethod
+ def GetImageAdress(index):
+ if index in GlobalConfig.LocalProxyIndex:
+ i = GlobalConfig.LocalProxyIndex.index(index)
+ if Setting.PreIpv6.value > 0:
+ return GlobalConfig.AddressIpv6.value[i]
+ else:
+ return GlobalConfig.Address.value[i]
+ else:
+ return ""
+
+ @staticmethod
+ def LoadSetting():
+ try:
+ for k, v in dict(Setting.GlobalConfig.value).items():
+ Log.Debug("load global setting, k={}, v={}".format(k, v))
+ value = getattr(GlobalConfig, k)
+ if isinstance(value, GlobalItem) :
+ value.set_value(v)
+ except Exception as es:
+ Log.Error(es)
+ pass
+
+ @staticmethod
+ def SaveSetting():
+ saveData = {}
+ try:
+ for name in dir(GlobalConfig):
+ value = getattr(GlobalConfig, name)
+ if isinstance(value, GlobalItem) and not value.is_same():
+ saveData[name] = value.value
+ Setting.GlobalConfig.SetValue(saveData)
+ except Exception as es:
+ Log.Error(es)
+ pass
+
+ @staticmethod
+ def SetSetting(k, v):
+ value = getattr(GlobalConfig, k)
+ if isinstance(value, GlobalItem):
+ Log.Info("set setting, k:{}, v:{}".format(k, v))
+ value.set_value(v)
+ GlobalConfig.SaveSetting()
+
+ # 下载配置文件
+ @staticmethod
+ def UpdateSetting(data):
+ allKvs = {}
+ for v in data.replace("\r", "").split("\n"):
+ if not v:
+ continue
+ [k, v2] = v.split("=")
+ allKvs[k] = v2
+ ver = int(allKvs.get("Ver", 0))
+ if ver > GlobalConfig.Ver.value:
+ Log.Info("update setting, {}".format(allKvs))
+ for name, value in allKvs.items():
+ item = getattr(GlobalConfig, name)
+ if isinstance(item, GlobalItem):
+ item.set_value(value)
+ GlobalConfig.SaveSetting()
+ pass
diff --git a/src/config/setting.py b/src/config/setting.py
index 56eab20..fffcc5d 100644
--- a/src/config/setting.py
+++ b/src/config/setting.py
@@ -79,7 +79,13 @@ class Setting:
Language = SettingValue("GeneraSetting", 0, False, ["Auto", "zh", "hk", "en"]) # ch-zh ch-hk eu
ThemeIndex = SettingValue("GeneraSetting", 0, False, ["Auto", "dark", "light"]) #
LogIndex = SettingValue("GeneraSetting", 0, False, ["warn", "info", "debug"]) # Warn Info Debug
+
+ LogDirPath = SettingValue("GeneraSetting", "", False)
+
CoverSize = SettingValue("GeneraSetting", 100, False) #
+ TitleLine = SettingValue("GeneraSetting", 2, False) #
+ NotCategoryShow = SettingValue("GeneraSetting", 0, False) #
+
CategorySize = SettingValue("GeneraSetting", 80, False) #
ScaleLevel = SettingValue("GeneraSetting", 0, True, ["Auto", 100, 125, 150, 175, 200])
IsUseTitleBar = SettingValue("GeneraSetting", 1, True)
@@ -99,6 +105,7 @@ class Setting:
PreferCDNIP = SettingValue("ProxySetting", "104.18.227.172", False)
IsUseHttps = SettingValue("ProxySetting", 1, False)
PreIpv6 = SettingValue("ProxySetting", 0, False)
+ LastProxyResult = SettingValue("ProxySetting", {}, False)
ProxySelectIndex = SettingValue("ProxySetting", 1, False)
ProxyImgSelectIndex = SettingValue("ProxySetting", 1, False)
@@ -152,6 +159,7 @@ class Setting:
IsPreUpdate = SettingValue("Other", 0, False)
SaveCacheAddress = SettingValue("Other", "104.21.91.145", False)
IsReDownload = SettingValue("Other", 0, False)
+ GlobalConfig = SettingValue("Other", "", False)
@staticmethod
def InitLoadSetting():
@@ -219,6 +227,9 @@ def GetConfigPath():
@staticmethod
def GetLogPath():
import sys
+ if Setting.LogDirPath.value:
+ return Setting.LogDirPath.value
+
if sys.platform == "win32":
return "logs"
else:
diff --git a/src/db/book.db b/src/db/book.db
index e8c3f67..14699b2 100644
Binary files a/src/db/book.db and b/src/db/book.db differ
diff --git a/src/interface/ui_download.py b/src/interface/ui_download.py
index c58b3f8..d3d43f8 100644
--- a/src/interface/ui_download.py
+++ b/src/interface/ui_download.py
@@ -23,11 +23,40 @@ class Ui_Download(object):
def setupUi(self, Download):
if not Download.objectName():
Download.setObjectName(u"Download")
- Download.resize(707, 361)
+ Download.resize(820, 361)
self.gridLayout_2 = QGridLayout(Download)
self.gridLayout_2.setObjectName(u"gridLayout_2")
self.gridLayout = QGridLayout()
self.gridLayout.setObjectName(u"gridLayout")
+ self.tableWidget = QTableWidget(Download)
+ if (self.tableWidget.columnCount() < 11):
+ self.tableWidget.setColumnCount(11)
+ __qtablewidgetitem = QTableWidgetItem()
+ self.tableWidget.setHorizontalHeaderItem(0, __qtablewidgetitem)
+ __qtablewidgetitem1 = QTableWidgetItem()
+ self.tableWidget.setHorizontalHeaderItem(1, __qtablewidgetitem1)
+ __qtablewidgetitem2 = QTableWidgetItem()
+ self.tableWidget.setHorizontalHeaderItem(2, __qtablewidgetitem2)
+ __qtablewidgetitem3 = QTableWidgetItem()
+ self.tableWidget.setHorizontalHeaderItem(3, __qtablewidgetitem3)
+ __qtablewidgetitem4 = QTableWidgetItem()
+ self.tableWidget.setHorizontalHeaderItem(4, __qtablewidgetitem4)
+ __qtablewidgetitem5 = QTableWidgetItem()
+ self.tableWidget.setHorizontalHeaderItem(5, __qtablewidgetitem5)
+ __qtablewidgetitem6 = QTableWidgetItem()
+ self.tableWidget.setHorizontalHeaderItem(6, __qtablewidgetitem6)
+ __qtablewidgetitem7 = QTableWidgetItem()
+ self.tableWidget.setHorizontalHeaderItem(7, __qtablewidgetitem7)
+ __qtablewidgetitem8 = QTableWidgetItem()
+ self.tableWidget.setHorizontalHeaderItem(8, __qtablewidgetitem8)
+ __qtablewidgetitem9 = QTableWidgetItem()
+ self.tableWidget.setHorizontalHeaderItem(9, __qtablewidgetitem9)
+ __qtablewidgetitem10 = QTableWidgetItem()
+ self.tableWidget.setHorizontalHeaderItem(10, __qtablewidgetitem10)
+ self.tableWidget.setObjectName(u"tableWidget")
+
+ self.gridLayout.addWidget(self.tableWidget, 4, 0, 1, 1)
+
self.horizontalLayout = QHBoxLayout()
self.horizontalLayout.setObjectName(u"horizontalLayout")
self.horizontalSpacer = QSpacerItem(40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum)
@@ -72,36 +101,7 @@ def setupUi(self, Download):
self.horizontalLayout.addWidget(self.radioButton)
- self.gridLayout.addLayout(self.horizontalLayout, 2, 0, 1, 1)
-
- self.tableWidget = QTableWidget(Download)
- if (self.tableWidget.columnCount() < 11):
- self.tableWidget.setColumnCount(11)
- __qtablewidgetitem = QTableWidgetItem()
- self.tableWidget.setHorizontalHeaderItem(0, __qtablewidgetitem)
- __qtablewidgetitem1 = QTableWidgetItem()
- self.tableWidget.setHorizontalHeaderItem(1, __qtablewidgetitem1)
- __qtablewidgetitem2 = QTableWidgetItem()
- self.tableWidget.setHorizontalHeaderItem(2, __qtablewidgetitem2)
- __qtablewidgetitem3 = QTableWidgetItem()
- self.tableWidget.setHorizontalHeaderItem(3, __qtablewidgetitem3)
- __qtablewidgetitem4 = QTableWidgetItem()
- self.tableWidget.setHorizontalHeaderItem(4, __qtablewidgetitem4)
- __qtablewidgetitem5 = QTableWidgetItem()
- self.tableWidget.setHorizontalHeaderItem(5, __qtablewidgetitem5)
- __qtablewidgetitem6 = QTableWidgetItem()
- self.tableWidget.setHorizontalHeaderItem(6, __qtablewidgetitem6)
- __qtablewidgetitem7 = QTableWidgetItem()
- self.tableWidget.setHorizontalHeaderItem(7, __qtablewidgetitem7)
- __qtablewidgetitem8 = QTableWidgetItem()
- self.tableWidget.setHorizontalHeaderItem(8, __qtablewidgetitem8)
- __qtablewidgetitem9 = QTableWidgetItem()
- self.tableWidget.setHorizontalHeaderItem(9, __qtablewidgetitem9)
- __qtablewidgetitem10 = QTableWidgetItem()
- self.tableWidget.setHorizontalHeaderItem(10, __qtablewidgetitem10)
- self.tableWidget.setObjectName(u"tableWidget")
-
- self.gridLayout.addWidget(self.tableWidget, 5, 0, 1, 1)
+ self.gridLayout.addLayout(self.horizontalLayout, 1, 0, 1, 1)
self.gridLayout_2.addLayout(self.gridLayout, 0, 0, 1, 1)
@@ -119,13 +119,6 @@ def setupUi(self, Download):
def retranslateUi(self, Download):
Download.setWindowTitle(QCoreApplication.translate("Download", u"\u4e0b\u8f7d", None))
- self.redownloadRadio.setText(QCoreApplication.translate("Download", u"\u4e0b\u8f7d\u5931\u8d25\u540e1\u5206\u949f\u81ea\u52a8\u91cd\u8bd5", None))
- self.updateNew.setText(QCoreApplication.translate("Download", u"\u66f4\u65b0\u6240\u6709New\u7ae0\u8282", None))
- self.pushButton.setText(QCoreApplication.translate("Download", u"\u5168\u90e8\u5f00\u59cb\u4e0b\u8f7d", None))
- self.pushButton_3.setText(QCoreApplication.translate("Download", u"\u5168\u90e8\u6682\u505c\u4e0b\u8f7d", None))
- self.pushButton_2.setText(QCoreApplication.translate("Download", u"\u5168\u90e8\u5f00\u59cb\u8f6c\u6362", None))
- self.pushButton_4.setText(QCoreApplication.translate("Download", u"\u5168\u90e8\u6682\u505c\u8f6c\u6362", None))
- self.radioButton.setText(QCoreApplication.translate("Download", u"\u4e0b\u8f7d\u81ea\u52a8\u8fdb\u884cWaifu2x\u8f6c\u6362", None))
___qtablewidgetitem = self.tableWidget.horizontalHeaderItem(0)
___qtablewidgetitem.setText(QCoreApplication.translate("Download", u"id", None));
___qtablewidgetitem1 = self.tableWidget.horizontalHeaderItem(1)
@@ -148,5 +141,12 @@ def retranslateUi(self, Download):
___qtablewidgetitem9.setText(QCoreApplication.translate("Download", u"\u8f6c\u6362\u8017\u65f6", None));
___qtablewidgetitem10 = self.tableWidget.horizontalHeaderItem(10)
___qtablewidgetitem10.setText(QCoreApplication.translate("Download", u"\u8f6c\u6362\u72b6\u6001", None));
+ self.redownloadRadio.setText(QCoreApplication.translate("Download", u"\u4e0b\u8f7d\u5931\u8d25\u540e1\u5206\u949f\u81ea\u52a8\u91cd\u8bd5", None))
+ self.updateNew.setText(QCoreApplication.translate("Download", u"\u66f4\u65b0\u6240\u6709New\u7ae0\u8282", None))
+ self.pushButton.setText(QCoreApplication.translate("Download", u"\u5168\u90e8\u5f00\u59cb\u4e0b\u8f7d", None))
+ self.pushButton_3.setText(QCoreApplication.translate("Download", u"\u5168\u90e8\u6682\u505c\u4e0b\u8f7d", None))
+ self.pushButton_2.setText(QCoreApplication.translate("Download", u"\u5168\u90e8\u5f00\u59cb\u8f6c\u6362", None))
+ self.pushButton_4.setText(QCoreApplication.translate("Download", u"\u5168\u90e8\u6682\u505c\u8f6c\u6362", None))
+ self.radioButton.setText(QCoreApplication.translate("Download", u"\u4e0b\u8f7d\u81ea\u52a8\u8fdb\u884cWaifu2x\u8f6c\u6362", None))
# retranslateUi
diff --git a/src/interface/ui_local.py b/src/interface/ui_local.py
index 4ddd1d8..8325946 100644
--- a/src/interface/ui_local.py
+++ b/src/interface/ui_local.py
@@ -27,7 +27,7 @@ class Ui_Local(object):
def setupUi(self, Local):
if not Local.objectName():
Local.setObjectName(u"Local")
- Local.resize(628, 334)
+ Local.resize(626, 327)
self.gridLayout_2 = QGridLayout(Local)
self.gridLayout_2.setObjectName(u"gridLayout_2")
self.gridLayout_3 = QGridLayout()
diff --git a/src/interface/ui_local_all.py b/src/interface/ui_local_all.py
index f97b0dd..f1e86ef 100644
--- a/src/interface/ui_local_all.py
+++ b/src/interface/ui_local_all.py
@@ -25,7 +25,7 @@ class Ui_LocalAll(object):
def setupUi(self, LocalAll):
if not LocalAll.objectName():
LocalAll.setObjectName(u"LocalAll")
- LocalAll.resize(543, 300)
+ LocalAll.resize(541, 293)
self.verticalLayout = QVBoxLayout(LocalAll)
self.verticalLayout.setObjectName(u"verticalLayout")
self.horizontalLayout_4 = QHBoxLayout()
diff --git a/src/interface/ui_local_favorite.py b/src/interface/ui_local_favorite.py
new file mode 100644
index 0000000..e68f92f
--- /dev/null
+++ b/src/interface/ui_local_favorite.py
@@ -0,0 +1,171 @@
+# -*- coding: utf-8 -*-
+
+################################################################################
+## Form generated from reading UI file 'ui_local_favorite.ui'
+##
+## Created by: Qt User Interface Compiler version 6.2.4
+##
+## WARNING! All changes made in this file will be lost when recompiling UI file!
+################################################################################
+
+from PySide6.QtCore import (QCoreApplication, QDate, QDateTime, QLocale,
+ QMetaObject, QObject, QPoint, QRect,
+ QSize, QTime, QUrl, Qt)
+from PySide6.QtGui import (QBrush, QColor, QConicalGradient, QCursor,
+ QFont, QFontDatabase, QGradient, QIcon,
+ QImage, QKeySequence, QLinearGradient, QPainter,
+ QPalette, QPixmap, QRadialGradient, QTransform)
+from PySide6.QtWidgets import (QApplication, QComboBox, QFrame, QGridLayout,
+ QHBoxLayout, QLabel, QLineEdit, QListWidgetItem,
+ QPushButton, QSizePolicy, QSpacerItem, QSpinBox,
+ QWidget)
+
+from component.list.comic_list_widget import ComicListWidget
+
+class Ui_LocalFavorite(object):
+ def setupUi(self, LocalFavorite):
+ if not LocalFavorite.objectName():
+ LocalFavorite.setObjectName(u"LocalFavorite")
+ LocalFavorite.resize(628, 334)
+ self.gridLayout_2 = QGridLayout(LocalFavorite)
+ self.gridLayout_2.setObjectName(u"gridLayout_2")
+ self.gridLayout_3 = QGridLayout()
+ self.gridLayout_3.setObjectName(u"gridLayout_3")
+ self.bookList = ComicListWidget(LocalFavorite)
+ self.bookList.setObjectName(u"bookList")
+ self.bookList.setStyleSheet(u"")
+
+ self.gridLayout_3.addWidget(self.bookList, 0, 0, 1, 1)
+
+
+ self.gridLayout_2.addLayout(self.gridLayout_3, 1, 0, 1, 1)
+
+ self.gridLayout_4 = QGridLayout()
+ self.gridLayout_4.setObjectName(u"gridLayout_4")
+ self.horizontalLayout = QHBoxLayout()
+ self.horizontalLayout.setObjectName(u"horizontalLayout")
+ self.msgLabel = QLabel(LocalFavorite)
+ self.msgLabel.setObjectName(u"msgLabel")
+
+ self.horizontalLayout.addWidget(self.msgLabel)
+
+ self.sortKeyCombox = QComboBox(LocalFavorite)
+ self.sortKeyCombox.addItem("")
+ self.sortKeyCombox.setObjectName(u"sortKeyCombox")
+ self.sortKeyCombox.setEnabled(True)
+ self.sortKeyCombox.setMinimumSize(QSize(100, 0))
+
+ self.horizontalLayout.addWidget(self.sortKeyCombox)
+
+ self.sortIdCombox = QComboBox(LocalFavorite)
+ self.sortIdCombox.addItem("")
+ self.sortIdCombox.addItem("")
+ self.sortIdCombox.setObjectName(u"sortIdCombox")
+ self.sortIdCombox.setEnabled(True)
+
+ self.horizontalLayout.addWidget(self.sortIdCombox)
+
+ self.horizontalSpacer = QSpacerItem(40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum)
+
+ self.horizontalLayout.addItem(self.horizontalSpacer)
+
+ self.line_2 = QFrame(LocalFavorite)
+ self.line_2.setObjectName(u"line_2")
+ self.line_2.setFrameShape(QFrame.VLine)
+ self.line_2.setFrameShadow(QFrame.Sunken)
+
+ self.horizontalLayout.addWidget(self.line_2)
+
+ self.nums = QLabel(LocalFavorite)
+ self.nums.setObjectName(u"nums")
+ self.nums.setMinimumSize(QSize(0, 30))
+
+ self.horizontalLayout.addWidget(self.nums)
+
+ self.pages = QLabel(LocalFavorite)
+ self.pages.setObjectName(u"pages")
+
+ self.horizontalLayout.addWidget(self.pages)
+
+ self.line = QFrame(LocalFavorite)
+ self.line.setObjectName(u"line")
+ self.line.setFrameShape(QFrame.VLine)
+ self.line.setFrameShadow(QFrame.Sunken)
+
+ self.horizontalLayout.addWidget(self.line)
+
+ self.line_4 = QFrame(LocalFavorite)
+ self.line_4.setObjectName(u"line_4")
+ self.line_4.setFrameShape(QFrame.VLine)
+ self.line_4.setFrameShadow(QFrame.Sunken)
+
+ self.horizontalLayout.addWidget(self.line_4)
+
+ self.spinBox = QSpinBox(LocalFavorite)
+ self.spinBox.setObjectName(u"spinBox")
+ self.spinBox.setMinimumSize(QSize(50, 30))
+ self.spinBox.setMinimum(1)
+ self.spinBox.setMaximum(1)
+
+ self.horizontalLayout.addWidget(self.spinBox)
+
+ self.line_3 = QFrame(LocalFavorite)
+ self.line_3.setObjectName(u"line_3")
+ self.line_3.setFrameShape(QFrame.VLine)
+ self.line_3.setFrameShadow(QFrame.Sunken)
+
+ self.horizontalLayout.addWidget(self.line_3)
+
+ self.jumpButton = QPushButton(LocalFavorite)
+ self.jumpButton.setObjectName(u"jumpButton")
+ self.jumpButton.setMinimumSize(QSize(0, 30))
+
+ self.horizontalLayout.addWidget(self.jumpButton)
+
+
+ self.gridLayout_4.addLayout(self.horizontalLayout, 0, 0, 1, 1)
+
+
+ self.gridLayout_2.addLayout(self.gridLayout_4, 2, 0, 1, 1)
+
+ self.widget = QWidget(LocalFavorite)
+ self.widget.setObjectName(u"widget")
+ self.horizontalLayout_2 = QHBoxLayout(self.widget)
+ self.horizontalLayout_2.setObjectName(u"horizontalLayout_2")
+ self.label = QLabel(self.widget)
+ self.label.setObjectName(u"label")
+
+ self.horizontalLayout_2.addWidget(self.label)
+
+ self.lineEdit = QLineEdit(self.widget)
+ self.lineEdit.setObjectName(u"lineEdit")
+
+ self.horizontalLayout_2.addWidget(self.lineEdit)
+
+
+ self.gridLayout_2.addWidget(self.widget, 0, 0, 1, 1)
+
+
+ self.retranslateUi(LocalFavorite)
+ self.jumpButton.clicked.connect(LocalFavorite.JumpPage)
+
+ QMetaObject.connectSlotsByName(LocalFavorite)
+ # setupUi
+
+ def retranslateUi(self, LocalFavorite):
+ LocalFavorite.setWindowTitle(QCoreApplication.translate("LocalFavorite", u"\u6536\u85cf", None))
+ self.msgLabel.setText("")
+ self.sortKeyCombox.setItemText(0, QCoreApplication.translate("LocalFavorite", u"\u6536\u85cf\u65f6\u95f4", None))
+
+ self.sortIdCombox.setItemText(0, QCoreApplication.translate("LocalFavorite", u"\u964d\u5e8f", None))
+ self.sortIdCombox.setItemText(1, QCoreApplication.translate("LocalFavorite", u"\u5347\u5e8f", None))
+
+ self.nums.setText(QCoreApplication.translate("LocalFavorite", u"\u6536\u85cf\u6570\uff1a", None))
+ self.pages.setText(QCoreApplication.translate("LocalFavorite", u"\u9875", None))
+ self.jumpButton.setText(QCoreApplication.translate("LocalFavorite", u"\u8df3\u8f6c", None))
+#if QT_CONFIG(shortcut)
+ self.jumpButton.setShortcut(QCoreApplication.translate("LocalFavorite", u"Return", None))
+#endif // QT_CONFIG(shortcut)
+ self.label.setText(QCoreApplication.translate("LocalFavorite", u"\u641c\u7d22\uff1a", None))
+ # retranslateUi
+
diff --git a/src/interface/ui_login_proxy_widget.py b/src/interface/ui_login_proxy_widget.py
index 85844ef..b3aef26 100644
--- a/src/interface/ui_login_proxy_widget.py
+++ b/src/interface/ui_login_proxy_widget.py
@@ -20,14 +20,15 @@
QLineEdit, QPushButton, QRadioButton, QSizePolicy,
QSpacerItem, QVBoxLayout, QWidget)
+from component.box.wheel_combo_box import WheelComboBox
from component.scroll_area.smooth_scroll_area import SmoothScrollArea
class Ui_LoginProxyWidget(object):
def setupUi(self, LoginProxyWidget):
if not LoginProxyWidget.objectName():
LoginProxyWidget.setObjectName(u"LoginProxyWidget")
- LoginProxyWidget.resize(495, 483)
- LoginProxyWidget.setMinimumSize(QSize(450, 0))
+ LoginProxyWidget.resize(577, 473)
+ LoginProxyWidget.setMinimumSize(QSize(550, 0))
self.gridLayout = QGridLayout(LoginProxyWidget)
self.gridLayout.setSpacing(12)
self.gridLayout.setObjectName(u"gridLayout")
@@ -36,7 +37,7 @@ def setupUi(self, LoginProxyWidget):
self.scrollArea.setWidgetResizable(True)
self.scrollAreaWidgetContents = QWidget()
self.scrollAreaWidgetContents.setObjectName(u"scrollAreaWidgetContents")
- self.scrollAreaWidgetContents.setGeometry(QRect(0, 0, 458, 483))
+ self.scrollAreaWidgetContents.setGeometry(QRect(0, 0, 540, 512))
self.verticalLayout = QVBoxLayout(self.scrollAreaWidgetContents)
self.verticalLayout.setObjectName(u"verticalLayout")
self.horizontalLayout_11 = QHBoxLayout()
@@ -163,6 +164,25 @@ def setupUi(self, LoginProxyWidget):
self.verticalLayout.addLayout(self.horizontalLayout_9)
+ self.horizontalLayout_3 = QHBoxLayout()
+ self.horizontalLayout_3.setObjectName(u"horizontalLayout_3")
+ self.label_9 = QLabel(self.scrollAreaWidgetContents)
+ self.label_9.setObjectName(u"label_9")
+
+ self.horizontalLayout_3.addWidget(self.label_9)
+
+ self.imgCombox = WheelComboBox(self.scrollAreaWidgetContents)
+ self.imgCombox.setObjectName(u"imgCombox")
+
+ self.horizontalLayout_3.addWidget(self.imgCombox)
+
+ self.horizontalSpacer_2 = QSpacerItem(40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum)
+
+ self.horizontalLayout_3.addItem(self.horizontalSpacer_2)
+
+
+ self.verticalLayout.addLayout(self.horizontalLayout_3)
+
self.testSpeedButton = QPushButton(self.scrollAreaWidgetContents)
self.testSpeedButton.setObjectName(u"testSpeedButton")
@@ -177,110 +197,110 @@ def setupUi(self, LoginProxyWidget):
self.gridLayout_2 = QGridLayout()
self.gridLayout_2.setObjectName(u"gridLayout_2")
- self.label_api_2 = QLabel(self.scrollAreaWidgetContents)
- self.label_api_2.setObjectName(u"label_api_2")
+ self.label_img_5 = QLabel(self.scrollAreaWidgetContents)
+ self.label_img_5.setObjectName(u"label_img_5")
- self.gridLayout_2.addWidget(self.label_api_2, 3, 1, 1, 1)
+ self.gridLayout_2.addWidget(self.label_img_5, 5, 3, 1, 1)
- self.label_2 = QLabel(self.scrollAreaWidgetContents)
- self.label_2.setObjectName(u"label_2")
- self.label_2.setAlignment(Qt.AlignCenter)
+ self.radioButton_3 = QRadioButton(self.scrollAreaWidgetContents)
+ self.radioApiGroup = QButtonGroup(LoginProxyWidget)
+ self.radioApiGroup.setObjectName(u"radioApiGroup")
+ self.radioApiGroup.addButton(self.radioButton_3)
+ self.radioButton_3.setObjectName(u"radioButton_3")
- self.gridLayout_2.addWidget(self.label_2, 1, 0, 1, 1)
+ self.gridLayout_2.addWidget(self.radioButton_3, 4, 0, 1, 1)
self.radioButton_2 = QRadioButton(self.scrollAreaWidgetContents)
- self.radioApiGroup = QButtonGroup(LoginProxyWidget)
- self.radioApiGroup.setObjectName(u"radioApiGroup")
self.radioApiGroup.addButton(self.radioButton_2)
self.radioButton_2.setObjectName(u"radioButton_2")
self.gridLayout_2.addWidget(self.radioButton_2, 3, 0, 1, 1)
- self.cdn_api_ip = QLineEdit(self.scrollAreaWidgetContents)
- self.cdn_api_ip.setObjectName(u"cdn_api_ip")
- self.cdn_api_ip.setMaximumSize(QSize(120, 16777215))
+ self.cdn_img_ip = QLineEdit(self.scrollAreaWidgetContents)
+ self.cdn_img_ip.setObjectName(u"cdn_img_ip")
+ self.cdn_img_ip.setMaximumSize(QSize(120, 16777215))
- self.gridLayout_2.addWidget(self.cdn_api_ip, 8, 1, 1, 1)
+ self.gridLayout_2.addWidget(self.cdn_img_ip, 8, 3, 1, 1)
- self.label_api_1 = QLabel(self.scrollAreaWidgetContents)
- self.label_api_1.setObjectName(u"label_api_1")
+ self.radio_img_6 = QRadioButton(self.scrollAreaWidgetContents)
+ self.radioImgGroup = QButtonGroup(LoginProxyWidget)
+ self.radioImgGroup.setObjectName(u"radioImgGroup")
+ self.radioImgGroup.addButton(self.radio_img_6)
+ self.radio_img_6.setObjectName(u"radio_img_6")
- self.gridLayout_2.addWidget(self.label_api_1, 2, 1, 1, 1)
+ self.gridLayout_2.addWidget(self.radio_img_6, 6, 2, 1, 1)
- self.radioButton_5 = QRadioButton(self.scrollAreaWidgetContents)
- self.radioApiGroup.addButton(self.radioButton_5)
- self.radioButton_5.setObjectName(u"radioButton_5")
+ self.radioButton_6 = QRadioButton(self.scrollAreaWidgetContents)
+ self.radioApiGroup.addButton(self.radioButton_6)
+ self.radioButton_6.setObjectName(u"radioButton_6")
- self.gridLayout_2.addWidget(self.radioButton_5, 5, 0, 1, 1)
+ self.gridLayout_2.addWidget(self.radioButton_6, 6, 0, 1, 1)
- self.label_api_3 = QLabel(self.scrollAreaWidgetContents)
- self.label_api_3.setObjectName(u"label_api_3")
+ self.radio_img_3 = QRadioButton(self.scrollAreaWidgetContents)
+ self.radioImgGroup.addButton(self.radio_img_3)
+ self.radio_img_3.setObjectName(u"radio_img_3")
- self.gridLayout_2.addWidget(self.label_api_3, 4, 1, 1, 1)
+ self.gridLayout_2.addWidget(self.radio_img_3, 4, 2, 1, 1)
- self.radioButton_1 = QRadioButton(self.scrollAreaWidgetContents)
- self.radioApiGroup.addButton(self.radioButton_1)
- self.radioButton_1.setObjectName(u"radioButton_1")
- self.radioButton_1.setChecked(True)
+ self.label_11 = QLabel(self.scrollAreaWidgetContents)
+ self.label_11.setObjectName(u"label_11")
+ self.label_11.setAlignment(Qt.AlignLeading|Qt.AlignLeft|Qt.AlignVCenter)
- self.gridLayout_2.addWidget(self.radioButton_1, 2, 0, 1, 1)
+ self.gridLayout_2.addWidget(self.label_11, 8, 0, 1, 1)
- self.label_api_5 = QLabel(self.scrollAreaWidgetContents)
- self.label_api_5.setObjectName(u"label_api_5")
+ self.radioButton_4 = QRadioButton(self.scrollAreaWidgetContents)
+ self.radioApiGroup.addButton(self.radioButton_4)
+ self.radioButton_4.setObjectName(u"radioButton_4")
- self.gridLayout_2.addWidget(self.label_api_5, 5, 1, 1, 1)
+ self.gridLayout_2.addWidget(self.radioButton_4, 7, 0, 1, 1)
- self.cdn_img_ip = QLineEdit(self.scrollAreaWidgetContents)
- self.cdn_img_ip.setObjectName(u"cdn_img_ip")
- self.cdn_img_ip.setMaximumSize(QSize(120, 16777215))
+ self.label_img_6 = QLabel(self.scrollAreaWidgetContents)
+ self.label_img_6.setObjectName(u"label_img_6")
- self.gridLayout_2.addWidget(self.cdn_img_ip, 8, 3, 1, 1)
+ self.gridLayout_2.addWidget(self.label_img_6, 6, 3, 1, 1)
- self.label_api_4 = QLabel(self.scrollAreaWidgetContents)
- self.label_api_4.setObjectName(u"label_api_4")
+ self.label_8 = QLabel(self.scrollAreaWidgetContents)
+ self.label_8.setObjectName(u"label_8")
- self.gridLayout_2.addWidget(self.label_api_4, 7, 1, 1, 1)
+ self.gridLayout_2.addWidget(self.label_8, 8, 2, 1, 1)
- self.label_img_3 = QLabel(self.scrollAreaWidgetContents)
- self.label_img_3.setObjectName(u"label_img_3")
+ self.cdn_api_ip = QLineEdit(self.scrollAreaWidgetContents)
+ self.cdn_api_ip.setObjectName(u"cdn_api_ip")
+ self.cdn_api_ip.setMaximumSize(QSize(120, 16777215))
- self.gridLayout_2.addWidget(self.label_img_3, 4, 3, 1, 1)
+ self.gridLayout_2.addWidget(self.cdn_api_ip, 8, 1, 1, 1)
- self.label_img_5 = QLabel(self.scrollAreaWidgetContents)
- self.label_img_5.setObjectName(u"label_img_5")
+ self.label_api_3 = QLabel(self.scrollAreaWidgetContents)
+ self.label_api_3.setObjectName(u"label_api_3")
- self.gridLayout_2.addWidget(self.label_img_5, 5, 3, 1, 1)
+ self.gridLayout_2.addWidget(self.label_api_3, 4, 1, 1, 1)
- self.label_8 = QLabel(self.scrollAreaWidgetContents)
- self.label_8.setObjectName(u"label_8")
+ self.label_api_2 = QLabel(self.scrollAreaWidgetContents)
+ self.label_api_2.setObjectName(u"label_api_2")
- self.gridLayout_2.addWidget(self.label_8, 8, 2, 1, 1)
+ self.gridLayout_2.addWidget(self.label_api_2, 3, 1, 1, 1)
- self.radio_img_1 = QRadioButton(self.scrollAreaWidgetContents)
- self.radioImgGroup = QButtonGroup(LoginProxyWidget)
- self.radioImgGroup.setObjectName(u"radioImgGroup")
- self.radioImgGroup.addButton(self.radio_img_1)
- self.radio_img_1.setObjectName(u"radio_img_1")
- self.radio_img_1.setChecked(True)
+ self.label_img_3 = QLabel(self.scrollAreaWidgetContents)
+ self.label_img_3.setObjectName(u"label_img_3")
- self.gridLayout_2.addWidget(self.radio_img_1, 2, 2, 1, 1)
+ self.gridLayout_2.addWidget(self.label_img_3, 4, 3, 1, 1)
- self.radio_img_2 = QRadioButton(self.scrollAreaWidgetContents)
- self.radioImgGroup.addButton(self.radio_img_2)
- self.radio_img_2.setObjectName(u"radio_img_2")
+ self.label_img_1 = QLabel(self.scrollAreaWidgetContents)
+ self.label_img_1.setObjectName(u"label_img_1")
- self.gridLayout_2.addWidget(self.radio_img_2, 3, 2, 1, 1)
+ self.gridLayout_2.addWidget(self.label_img_1, 2, 3, 1, 1)
- self.label_img_4 = QLabel(self.scrollAreaWidgetContents)
- self.label_img_4.setObjectName(u"label_img_4")
+ self.label_7 = QLabel(self.scrollAreaWidgetContents)
+ self.label_7.setObjectName(u"label_7")
+ self.label_7.setAlignment(Qt.AlignCenter)
- self.gridLayout_2.addWidget(self.label_img_4, 7, 3, 1, 1)
+ self.gridLayout_2.addWidget(self.label_7, 1, 2, 1, 1)
- self.radio_img_4 = QRadioButton(self.scrollAreaWidgetContents)
- self.radioImgGroup.addButton(self.radio_img_4)
- self.radio_img_4.setObjectName(u"radio_img_4")
+ self.label_6 = QLabel(self.scrollAreaWidgetContents)
+ self.label_6.setObjectName(u"label_6")
+ self.label_6.setAlignment(Qt.AlignCenter)
- self.gridLayout_2.addWidget(self.radio_img_4, 7, 2, 1, 1)
+ self.gridLayout_2.addWidget(self.label_6, 1, 1, 1, 1)
self.radio_img_5 = QRadioButton(self.scrollAreaWidgetContents)
self.radioImgGroup.addButton(self.radio_img_5)
@@ -288,79 +308,79 @@ def setupUi(self, LoginProxyWidget):
self.gridLayout_2.addWidget(self.radio_img_5, 5, 2, 1, 1)
- self.radioButton_4 = QRadioButton(self.scrollAreaWidgetContents)
- self.radioApiGroup.addButton(self.radioButton_4)
- self.radioButton_4.setObjectName(u"radioButton_4")
+ self.label_4 = QLabel(self.scrollAreaWidgetContents)
+ self.label_4.setObjectName(u"label_4")
+ self.label_4.setAlignment(Qt.AlignCenter)
- self.gridLayout_2.addWidget(self.radioButton_4, 7, 0, 1, 1)
+ self.gridLayout_2.addWidget(self.label_4, 1, 3, 1, 1)
- self.radioButton_3 = QRadioButton(self.scrollAreaWidgetContents)
- self.radioApiGroup.addButton(self.radioButton_3)
- self.radioButton_3.setObjectName(u"radioButton_3")
+ self.radioButton_1 = QRadioButton(self.scrollAreaWidgetContents)
+ self.radioApiGroup.addButton(self.radioButton_1)
+ self.radioButton_1.setObjectName(u"radioButton_1")
+ self.radioButton_1.setChecked(True)
- self.gridLayout_2.addWidget(self.radioButton_3, 4, 0, 1, 1)
+ self.gridLayout_2.addWidget(self.radioButton_1, 2, 0, 1, 1)
- self.radio_img_3 = QRadioButton(self.scrollAreaWidgetContents)
- self.radioImgGroup.addButton(self.radio_img_3)
- self.radio_img_3.setObjectName(u"radio_img_3")
+ self.radio_img_4 = QRadioButton(self.scrollAreaWidgetContents)
+ self.radioImgGroup.addButton(self.radio_img_4)
+ self.radio_img_4.setObjectName(u"radio_img_4")
- self.gridLayout_2.addWidget(self.radio_img_3, 4, 2, 1, 1)
+ self.gridLayout_2.addWidget(self.radio_img_4, 7, 2, 1, 1)
- self.label_11 = QLabel(self.scrollAreaWidgetContents)
- self.label_11.setObjectName(u"label_11")
- self.label_11.setAlignment(Qt.AlignLeading|Qt.AlignLeft|Qt.AlignVCenter)
+ self.label_api_5 = QLabel(self.scrollAreaWidgetContents)
+ self.label_api_5.setObjectName(u"label_api_5")
- self.gridLayout_2.addWidget(self.label_11, 8, 0, 1, 1)
+ self.gridLayout_2.addWidget(self.label_api_5, 5, 1, 1, 1)
- self.label_6 = QLabel(self.scrollAreaWidgetContents)
- self.label_6.setObjectName(u"label_6")
- self.label_6.setAlignment(Qt.AlignCenter)
+ self.label_2 = QLabel(self.scrollAreaWidgetContents)
+ self.label_2.setObjectName(u"label_2")
+ self.label_2.setAlignment(Qt.AlignCenter)
- self.gridLayout_2.addWidget(self.label_6, 1, 1, 1, 1)
+ self.gridLayout_2.addWidget(self.label_2, 1, 0, 1, 1)
- self.label_img_2 = QLabel(self.scrollAreaWidgetContents)
- self.label_img_2.setObjectName(u"label_img_2")
+ self.label_img_4 = QLabel(self.scrollAreaWidgetContents)
+ self.label_img_4.setObjectName(u"label_img_4")
- self.gridLayout_2.addWidget(self.label_img_2, 3, 3, 1, 1)
+ self.gridLayout_2.addWidget(self.label_img_4, 7, 3, 1, 1)
- self.label_7 = QLabel(self.scrollAreaWidgetContents)
- self.label_7.setObjectName(u"label_7")
- self.label_7.setAlignment(Qt.AlignCenter)
+ self.label_api_6 = QLabel(self.scrollAreaWidgetContents)
+ self.label_api_6.setObjectName(u"label_api_6")
- self.gridLayout_2.addWidget(self.label_7, 1, 2, 1, 1)
+ self.gridLayout_2.addWidget(self.label_api_6, 6, 1, 1, 1)
- self.label_4 = QLabel(self.scrollAreaWidgetContents)
- self.label_4.setObjectName(u"label_4")
- self.label_4.setAlignment(Qt.AlignCenter)
+ self.label_img_2 = QLabel(self.scrollAreaWidgetContents)
+ self.label_img_2.setObjectName(u"label_img_2")
- self.gridLayout_2.addWidget(self.label_4, 1, 3, 1, 1)
+ self.gridLayout_2.addWidget(self.label_img_2, 3, 3, 1, 1)
- self.label_img_1 = QLabel(self.scrollAreaWidgetContents)
- self.label_img_1.setObjectName(u"label_img_1")
+ self.radio_img_1 = QRadioButton(self.scrollAreaWidgetContents)
+ self.radioImgGroup.addButton(self.radio_img_1)
+ self.radio_img_1.setObjectName(u"radio_img_1")
+ self.radio_img_1.setChecked(True)
- self.gridLayout_2.addWidget(self.label_img_1, 2, 3, 1, 1)
+ self.gridLayout_2.addWidget(self.radio_img_1, 2, 2, 1, 1)
- self.radioButton_6 = QRadioButton(self.scrollAreaWidgetContents)
- self.radioApiGroup.addButton(self.radioButton_6)
- self.radioButton_6.setObjectName(u"radioButton_6")
+ self.label_api_4 = QLabel(self.scrollAreaWidgetContents)
+ self.label_api_4.setObjectName(u"label_api_4")
- self.gridLayout_2.addWidget(self.radioButton_6, 6, 0, 1, 1)
+ self.gridLayout_2.addWidget(self.label_api_4, 7, 1, 1, 1)
- self.radio_img_6 = QRadioButton(self.scrollAreaWidgetContents)
- self.radioImgGroup.addButton(self.radio_img_6)
- self.radio_img_6.setObjectName(u"radio_img_6")
+ self.label_api_1 = QLabel(self.scrollAreaWidgetContents)
+ self.label_api_1.setObjectName(u"label_api_1")
- self.gridLayout_2.addWidget(self.radio_img_6, 6, 2, 1, 1)
+ self.gridLayout_2.addWidget(self.label_api_1, 2, 1, 1, 1)
- self.label_api_6 = QLabel(self.scrollAreaWidgetContents)
- self.label_api_6.setObjectName(u"label_api_6")
+ self.radio_img_2 = QRadioButton(self.scrollAreaWidgetContents)
+ self.radioImgGroup.addButton(self.radio_img_2)
+ self.radio_img_2.setObjectName(u"radio_img_2")
- self.gridLayout_2.addWidget(self.label_api_6, 6, 1, 1, 1)
+ self.gridLayout_2.addWidget(self.radio_img_2, 3, 2, 1, 1)
- self.label_img_6 = QLabel(self.scrollAreaWidgetContents)
- self.label_img_6.setObjectName(u"label_img_6")
+ self.radioButton_5 = QRadioButton(self.scrollAreaWidgetContents)
+ self.radioApiGroup.addButton(self.radioButton_5)
+ self.radioButton_5.setObjectName(u"radioButton_5")
- self.gridLayout_2.addWidget(self.label_img_6, 6, 3, 1, 1)
+ self.gridLayout_2.addWidget(self.radioButton_5, 5, 0, 1, 1)
self.verticalLayout.addLayout(self.gridLayout_2)
@@ -410,43 +430,44 @@ def retranslateUi(self, LoginProxyWidget):
self.checkLabel.setText(QCoreApplication.translate("LoginProxyWidget", u"\u672a\u68c0\u6d4b\u5230\u7cfb\u7edf\u4ee3\u7406", None))
self.ipv6Check.setText(QCoreApplication.translate("LoginProxyWidget", u"\u4f18\u5148\u4f7f\u7528IPV6\u5206\u6d41\uff08\u5206\u6d412\u30013\u652f\u6301\uff09", None))
self.httpsBox.setText(QCoreApplication.translate("LoginProxyWidget", u"\u542f\u7528Https\uff08\u5982\u679c\u51fa\u73b0\u8fde\u63a5\u88ab\u91cd\u7f6e\uff0c\u5efa\u8bae\u5173\u95ed\u8bd5\u8bd5\uff09", None))
+ self.label_9.setText(QCoreApplication.translate("LoginProxyWidget", u"\u56fe\u7247\u5730\u5740\u9009\u62e9\uff1a", None))
self.testSpeedButton.setText(QCoreApplication.translate("LoginProxyWidget", u"\u6d4b\u901f", None))
- self.label_api_2.setText("")
- self.label_2.setText(QCoreApplication.translate("LoginProxyWidget", u"Api\u5206\u6d41", None))
+ self.label_img_5.setText("")
+ self.radioButton_3.setText(QCoreApplication.translate("LoginProxyWidget", u"\u5206\u6d413", None))
self.radioButton_2.setText(QCoreApplication.translate("LoginProxyWidget", u"\u5206\u6d412", None))
- self.label_api_1.setText("")
-#if QT_CONFIG(tooltip)
- self.radioButton_5.setToolTip(QCoreApplication.translate("LoginProxyWidget", u"\u6240\u4ee5\u5206\u6d41\u4e0d\u53ef\u4f7f\u7528\u65f6\uff0c\u81ea\u52a8\u89e3\u9501", None))
-#endif // QT_CONFIG(tooltip)
- self.radioButton_5.setText(QCoreApplication.translate("LoginProxyWidget", u"JP\u53cd\u4ee3\u5206\u6d41", None))
+ self.radio_img_6.setText(QCoreApplication.translate("LoginProxyWidget", u"US\u53cd\u4ee3\u5206\u6d41", None))
+ self.radioButton_6.setText(QCoreApplication.translate("LoginProxyWidget", u"US\u53cd\u4ee3\u5206\u6d41", None))
+ self.radio_img_3.setText(QCoreApplication.translate("LoginProxyWidget", u"\u5206\u6d413", None))
+ self.label_11.setText(QCoreApplication.translate("LoginProxyWidget", u" CDN\u5730\u5740 ", None))
+ self.radioButton_4.setText(QCoreApplication.translate("LoginProxyWidget", u"CDN\u5206\u6d41", None))
+ self.label_img_6.setText("")
+ self.label_8.setText(QCoreApplication.translate("LoginProxyWidget", u"CDN\u5730\u5740", None))
self.label_api_3.setText("")
- self.radioButton_1.setText(QCoreApplication.translate("LoginProxyWidget", u"\u5206\u6d411", None))
- self.label_api_5.setText("")
- self.label_api_4.setText("")
+ self.label_api_2.setText("")
self.label_img_3.setText("")
- self.label_img_5.setText("")
- self.label_8.setText(QCoreApplication.translate("LoginProxyWidget", u"CDN\u5730\u5740", None))
- self.radio_img_1.setText(QCoreApplication.translate("LoginProxyWidget", u"\u5206\u6d411", None))
- self.radio_img_2.setText(QCoreApplication.translate("LoginProxyWidget", u"\u5206\u6d412", None))
- self.label_img_4.setText("")
- self.radio_img_4.setText(QCoreApplication.translate("LoginProxyWidget", u"CDN\u5206\u6d41", None))
+ self.label_img_1.setText("")
+ self.label_7.setText(QCoreApplication.translate("LoginProxyWidget", u"\u56fe\u7247\u5206\u6d41", None))
+ self.label_6.setText(QCoreApplication.translate("LoginProxyWidget", u"\u5ef6\u8fdf", None))
#if QT_CONFIG(tooltip)
self.radio_img_5.setToolTip(QCoreApplication.translate("LoginProxyWidget", u"\u6240\u4ee5\u5206\u6d41\u4e0d\u53ef\u4f7f\u7528\u65f6\uff0c\u81ea\u52a8\u89e3\u9501", None))
#endif // QT_CONFIG(tooltip)
self.radio_img_5.setText(QCoreApplication.translate("LoginProxyWidget", u"JP\u53cd\u4ee3\u5206\u6d41", None))
- self.radioButton_4.setText(QCoreApplication.translate("LoginProxyWidget", u"CDN\u5206\u6d41", None))
- self.radioButton_3.setText(QCoreApplication.translate("LoginProxyWidget", u"\u5206\u6d413", None))
- self.radio_img_3.setText(QCoreApplication.translate("LoginProxyWidget", u"\u5206\u6d413", None))
- self.label_11.setText(QCoreApplication.translate("LoginProxyWidget", u" CDN\u5730\u5740 ", None))
- self.label_6.setText(QCoreApplication.translate("LoginProxyWidget", u"\u5ef6\u8fdf", None))
- self.label_img_2.setText("")
- self.label_7.setText(QCoreApplication.translate("LoginProxyWidget", u"\u56fe\u7247\u5206\u6d41", None))
self.label_4.setText(QCoreApplication.translate("LoginProxyWidget", u"\u901f\u5ea6", None))
- self.label_img_1.setText("")
- self.radioButton_6.setText(QCoreApplication.translate("LoginProxyWidget", u"US\u53cd\u4ee3\u5206\u6d41", None))
- self.radio_img_6.setText(QCoreApplication.translate("LoginProxyWidget", u"US\u53cd\u4ee3\u5206\u6d41", None))
+ self.radioButton_1.setText(QCoreApplication.translate("LoginProxyWidget", u"\u5206\u6d411", None))
+ self.radio_img_4.setText(QCoreApplication.translate("LoginProxyWidget", u"CDN\u5206\u6d41", None))
+ self.label_api_5.setText("")
+ self.label_2.setText(QCoreApplication.translate("LoginProxyWidget", u"Api\u5206\u6d41", None))
+ self.label_img_4.setText("")
self.label_api_6.setText("")
- self.label_img_6.setText("")
+ self.label_img_2.setText("")
+ self.radio_img_1.setText(QCoreApplication.translate("LoginProxyWidget", u"\u5206\u6d411", None))
+ self.label_api_4.setText("")
+ self.label_api_1.setText("")
+ self.radio_img_2.setText(QCoreApplication.translate("LoginProxyWidget", u"\u5206\u6d412", None))
+#if QT_CONFIG(tooltip)
+ self.radioButton_5.setToolTip(QCoreApplication.translate("LoginProxyWidget", u"\u6240\u4ee5\u5206\u6d41\u4e0d\u53ef\u4f7f\u7528\u65f6\uff0c\u81ea\u52a8\u89e3\u9501", None))
+#endif // QT_CONFIG(tooltip)
+ self.radioButton_5.setText(QCoreApplication.translate("LoginProxyWidget", u"JP\u53cd\u4ee3\u5206\u6d41", None))
self.label_3.setText(QCoreApplication.translate("LoginProxyWidget", u"CDN\u8bbe\u7f6e\u8bf7\u770b\u8bf4\u660e\u83b7\u53d6", None))
self.commandLinkButton.setText(QCoreApplication.translate("LoginProxyWidget", u"\u8bf4\u660e", None))
# retranslateUi
diff --git a/src/interface/ui_navigation.py b/src/interface/ui_navigation.py
index 2dc9a47..567f37a 100644
--- a/src/interface/ui_navigation.py
+++ b/src/interface/ui_navigation.py
@@ -15,9 +15,9 @@
QFont, QFontDatabase, QGradient, QIcon,
QImage, QKeySequence, QLinearGradient, QPainter,
QPalette, QPixmap, QRadialGradient, QTransform)
-from PySide6.QtWidgets import (QApplication, QButtonGroup, QFrame, QHBoxLayout,
- QLabel, QPushButton, QSizePolicy, QSpacerItem,
- QToolButton, QVBoxLayout, QWidget)
+from PySide6.QtWidgets import (QApplication, QButtonGroup, QCommandLinkButton, QFrame,
+ QHBoxLayout, QLabel, QPushButton, QSizePolicy,
+ QSpacerItem, QToolButton, QVBoxLayout, QWidget)
from component.button.switch_button import SwitchButton
from component.label.head_label import HeadLabel
@@ -28,7 +28,7 @@ class Ui_Navigation(object):
def setupUi(self, Navigation):
if not Navigation.objectName():
Navigation.setObjectName(u"Navigation")
- Navigation.resize(248, 496)
+ Navigation.resize(376, 772)
Navigation.setStyleSheet(u"")
self.verticalLayout_2 = QVBoxLayout(Navigation)
self.verticalLayout_2.setSpacing(6)
@@ -103,7 +103,7 @@ def setupUi(self, Navigation):
self.horizontalLayout_3.addWidget(self.label_4)
- self.proxyName = QLabel(self.widget)
+ self.proxyName = QCommandLinkButton(self.widget)
self.proxyName.setObjectName(u"proxyName")
self.horizontalLayout_3.addWidget(self.proxyName)
@@ -118,7 +118,7 @@ def setupUi(self, Navigation):
self.horizontalLayout_5.addWidget(self.label_6)
- self.proxyImgName = QLabel(self.widget)
+ self.proxyImgName = QCommandLinkButton(self.widget)
self.proxyImgName.setObjectName(u"proxyImgName")
self.horizontalLayout_5.addWidget(self.proxyImgName)
@@ -148,12 +148,18 @@ def setupUi(self, Navigation):
self.verticalLayout.addWidget(self.line_4)
+ self.verticalSpacer = QSpacerItem(20, 40, QSizePolicy.Minimum, QSizePolicy.Expanding)
+
+ self.verticalLayout.addItem(self.verticalSpacer)
+
self.scrollArea = SmoothScrollArea(self.widget)
self.scrollArea.setObjectName(u"scrollArea")
- self.scrollArea.setWidgetResizable(True)
+ self.scrollArea.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOn)
+ self.scrollArea.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
+ self.scrollArea.setWidgetResizable(False)
self.scrollAreaWidgetContents = QWidget()
self.scrollAreaWidgetContents.setObjectName(u"scrollAreaWidgetContents")
- self.scrollAreaWidgetContents.setGeometry(QRect(0, -431, 211, 792))
+ self.scrollAreaWidgetContents.setGeometry(QRect(0, 0, 339, 800))
self.verticalLayout_3 = QVBoxLayout(self.scrollAreaWidgetContents)
self.verticalLayout_3.setSpacing(6)
self.verticalLayout_3.setObjectName(u"verticalLayout_3")
@@ -173,7 +179,7 @@ def setupUi(self, Navigation):
sizePolicy1.setVerticalStretch(0)
sizePolicy1.setHeightForWidth(self.collectButton.sizePolicy().hasHeightForWidth())
self.collectButton.setSizePolicy(sizePolicy1)
- self.collectButton.setMinimumSize(QSize(150, 40))
+ self.collectButton.setMinimumSize(QSize(150, 0))
self.collectButton.setFocusPolicy(Qt.NoFocus)
icon = QIcon()
icon.addFile(u":/images/menu/Contact.png", QSize(), QIcon.Normal, QIcon.Off)
@@ -189,7 +195,7 @@ def setupUi(self, Navigation):
self.myCommentButton.setObjectName(u"myCommentButton")
sizePolicy1.setHeightForWidth(self.myCommentButton.sizePolicy().hasHeightForWidth())
self.myCommentButton.setSizePolicy(sizePolicy1)
- self.myCommentButton.setMinimumSize(QSize(150, 40))
+ self.myCommentButton.setMinimumSize(QSize(150, 0))
self.myCommentButton.setFocusPolicy(Qt.NoFocus)
self.myCommentButton.setStyleSheet(u"")
icon1 = QIcon()
@@ -206,7 +212,7 @@ def setupUi(self, Navigation):
self.lookButton.setObjectName(u"lookButton")
sizePolicy1.setHeightForWidth(self.lookButton.sizePolicy().hasHeightForWidth())
self.lookButton.setSizePolicy(sizePolicy1)
- self.lookButton.setMinimumSize(QSize(150, 40))
+ self.lookButton.setMinimumSize(QSize(150, 0))
self.lookButton.setFocusPolicy(Qt.NoFocus)
self.lookButton.setIcon(icon)
self.lookButton.setIconSize(QSize(32, 32))
@@ -232,7 +238,7 @@ def setupUi(self, Navigation):
self.indexButton.setObjectName(u"indexButton")
sizePolicy1.setHeightForWidth(self.indexButton.sizePolicy().hasHeightForWidth())
self.indexButton.setSizePolicy(sizePolicy1)
- self.indexButton.setMinimumSize(QSize(150, 40))
+ self.indexButton.setMinimumSize(QSize(150, 0))
self.indexButton.setFocusPolicy(Qt.NoFocus)
self.indexButton.setIcon(icon)
self.indexButton.setIconSize(QSize(32, 32))
@@ -249,7 +255,7 @@ def setupUi(self, Navigation):
self.searchButton.setObjectName(u"searchButton")
sizePolicy1.setHeightForWidth(self.searchButton.sizePolicy().hasHeightForWidth())
self.searchButton.setSizePolicy(sizePolicy1)
- self.searchButton.setMinimumSize(QSize(150, 40))
+ self.searchButton.setMinimumSize(QSize(150, 0))
self.searchButton.setFocusPolicy(Qt.NoFocus)
self.searchButton.setIcon(icon)
self.searchButton.setIconSize(QSize(32, 32))
@@ -265,7 +271,7 @@ def setupUi(self, Navigation):
self.msgButton.setObjectName(u"msgButton")
sizePolicy1.setHeightForWidth(self.msgButton.sizePolicy().hasHeightForWidth())
self.msgButton.setSizePolicy(sizePolicy1)
- self.msgButton.setMinimumSize(QSize(150, 40))
+ self.msgButton.setMinimumSize(QSize(150, 0))
self.msgButton.setFocusPolicy(Qt.NoFocus)
self.msgButton.setIcon(icon)
self.msgButton.setIconSize(QSize(32, 32))
@@ -281,7 +287,7 @@ def setupUi(self, Navigation):
self.categoryButton.setObjectName(u"categoryButton")
sizePolicy1.setHeightForWidth(self.categoryButton.sizePolicy().hasHeightForWidth())
self.categoryButton.setSizePolicy(sizePolicy1)
- self.categoryButton.setMinimumSize(QSize(150, 40))
+ self.categoryButton.setMinimumSize(QSize(150, 0))
self.categoryButton.setFocusPolicy(Qt.NoFocus)
self.categoryButton.setIcon(icon)
self.categoryButton.setIconSize(QSize(32, 32))
@@ -295,7 +301,7 @@ def setupUi(self, Navigation):
self.rankButton.setObjectName(u"rankButton")
sizePolicy1.setHeightForWidth(self.rankButton.sizePolicy().hasHeightForWidth())
self.rankButton.setSizePolicy(sizePolicy1)
- self.rankButton.setMinimumSize(QSize(150, 40))
+ self.rankButton.setMinimumSize(QSize(150, 0))
self.rankButton.setFocusPolicy(Qt.NoFocus)
self.rankButton.setIcon(icon)
self.rankButton.setIconSize(QSize(32, 32))
@@ -309,7 +315,7 @@ def setupUi(self, Navigation):
self.chatButton.setObjectName(u"chatButton")
sizePolicy1.setHeightForWidth(self.chatButton.sizePolicy().hasHeightForWidth())
self.chatButton.setSizePolicy(sizePolicy1)
- self.chatButton.setMinimumSize(QSize(150, 40))
+ self.chatButton.setMinimumSize(QSize(150, 0))
self.chatButton.setFocusPolicy(Qt.NoFocus)
self.chatButton.setIcon(icon)
self.chatButton.setIconSize(QSize(32, 32))
@@ -323,7 +329,7 @@ def setupUi(self, Navigation):
self.chatNewButton.setObjectName(u"chatNewButton")
sizePolicy1.setHeightForWidth(self.chatNewButton.sizePolicy().hasHeightForWidth())
self.chatNewButton.setSizePolicy(sizePolicy1)
- self.chatNewButton.setMinimumSize(QSize(150, 40))
+ self.chatNewButton.setMinimumSize(QSize(150, 0))
self.chatNewButton.setFocusPolicy(Qt.NoFocus)
self.chatNewButton.setIcon(icon)
self.chatNewButton.setIconSize(QSize(32, 32))
@@ -337,7 +343,7 @@ def setupUi(self, Navigation):
self.gameButton.setObjectName(u"gameButton")
sizePolicy1.setHeightForWidth(self.gameButton.sizePolicy().hasHeightForWidth())
self.gameButton.setSizePolicy(sizePolicy1)
- self.gameButton.setMinimumSize(QSize(150, 40))
+ self.gameButton.setMinimumSize(QSize(150, 0))
self.gameButton.setFocusPolicy(Qt.NoFocus)
self.gameButton.setIcon(icon)
self.gameButton.setIconSize(QSize(32, 32))
@@ -351,7 +357,7 @@ def setupUi(self, Navigation):
self.friedButton.setObjectName(u"friedButton")
sizePolicy1.setHeightForWidth(self.friedButton.sizePolicy().hasHeightForWidth())
self.friedButton.setSizePolicy(sizePolicy1)
- self.friedButton.setMinimumSize(QSize(150, 40))
+ self.friedButton.setMinimumSize(QSize(150, 0))
self.friedButton.setFocusPolicy(Qt.NoFocus)
self.friedButton.setIcon(icon)
self.friedButton.setIconSize(QSize(32, 32))
@@ -377,7 +383,7 @@ def setupUi(self, Navigation):
self.downloadButton.setObjectName(u"downloadButton")
sizePolicy1.setHeightForWidth(self.downloadButton.sizePolicy().hasHeightForWidth())
self.downloadButton.setSizePolicy(sizePolicy1)
- self.downloadButton.setMinimumSize(QSize(150, 40))
+ self.downloadButton.setMinimumSize(QSize(150, 0))
self.downloadButton.setFocusPolicy(Qt.NoFocus)
self.downloadButton.setIcon(icon)
self.downloadButton.setIconSize(QSize(32, 32))
@@ -391,7 +397,7 @@ def setupUi(self, Navigation):
self.localReadButton.setObjectName(u"localReadButton")
sizePolicy1.setHeightForWidth(self.localReadButton.sizePolicy().hasHeightForWidth())
self.localReadButton.setSizePolicy(sizePolicy1)
- self.localReadButton.setMinimumSize(QSize(0, 40))
+ self.localReadButton.setMinimumSize(QSize(150, 0))
self.localReadButton.setFocusPolicy(Qt.NoFocus)
self.localReadButton.setIcon(icon)
self.localReadButton.setIconSize(QSize(32, 32))
@@ -405,7 +411,7 @@ def setupUi(self, Navigation):
self.convertButton.setObjectName(u"convertButton")
sizePolicy1.setHeightForWidth(self.convertButton.sizePolicy().hasHeightForWidth())
self.convertButton.setSizePolicy(sizePolicy1)
- self.convertButton.setMinimumSize(QSize(150, 40))
+ self.convertButton.setMinimumSize(QSize(150, 0))
self.convertButton.setFocusPolicy(Qt.NoFocus)
self.convertButton.setIcon(icon)
self.convertButton.setIconSize(QSize(32, 32))
@@ -419,7 +425,7 @@ def setupUi(self, Navigation):
self.waifu2xButton.setObjectName(u"waifu2xButton")
sizePolicy1.setHeightForWidth(self.waifu2xButton.sizePolicy().hasHeightForWidth())
self.waifu2xButton.setSizePolicy(sizePolicy1)
- self.waifu2xButton.setMinimumSize(QSize(150, 40))
+ self.waifu2xButton.setMinimumSize(QSize(150, 0))
self.waifu2xButton.setFocusPolicy(Qt.NoFocus)
self.waifu2xButton.setIcon(icon)
self.waifu2xButton.setIconSize(QSize(32, 32))
@@ -428,10 +434,6 @@ def setupUi(self, Navigation):
self.verticalLayout_3.addWidget(self.waifu2xButton)
- self.verticalSpacer = QSpacerItem(20, 40, QSizePolicy.Minimum, QSizePolicy.Expanding)
-
- self.verticalLayout_3.addItem(self.verticalSpacer)
-
self.scrollArea.setWidget(self.scrollAreaWidgetContents)
self.verticalLayout.addWidget(self.scrollArea)
diff --git a/src/interface/ui_read_tool.py b/src/interface/ui_read_tool.py
index 891bdf0..b310999 100644
--- a/src/interface/ui_read_tool.py
+++ b/src/interface/ui_read_tool.py
@@ -40,7 +40,7 @@ def setupUi(self, ReadImg):
self.scrollArea22.setWidgetResizable(True)
self.scrollAreaWidgetContents = QWidget()
self.scrollAreaWidgetContents.setObjectName(u"scrollAreaWidgetContents")
- self.scrollAreaWidgetContents.setGeometry(QRect(0, 0, 310, 825))
+ self.scrollAreaWidgetContents.setGeometry(QRect(0, -27, 310, 825))
self.verticalLayout_2 = QVBoxLayout(self.scrollAreaWidgetContents)
self.verticalLayout_2.setObjectName(u"verticalLayout_2")
self.verticalLayout = QVBoxLayout()
@@ -538,8 +538,8 @@ def retranslateUi(self, ReadImg):
self.comboBox.setItemText(7, QCoreApplication.translate("ReadImg", u"\u7b49\u5bbd\u6a21\u5f0f", None))
self.zoomLabel.setText(QCoreApplication.translate("ReadImg", u"\u7f29\u653e\uff08120%\uff09", None))
- self.label_7.setText(QCoreApplication.translate("ReadImg", u"\u81ea\u52a8\u6eda\u52a8/\u7ffb\u9875", None))
- self.label_10.setText(QCoreApplication.translate("ReadImg", u"\u6eda\u52a8\u901f\u5ea6\uff08\u50cf\u7d20\uff09\uff1a", None))
+ self.label_7.setText(QCoreApplication.translate("ReadImg", u"\u6eda\u52a8/\u7ffb\u9875", None))
+ self.label_10.setText(QCoreApplication.translate("ReadImg", u"\u6eda\u52a8\u901f\u5ea6\uff1a", None))
self.label_11.setText(QCoreApplication.translate("ReadImg", u"\u7ffb\u9875\u901f\u5ea6\uff08\u79d2\uff09\uff1a", None))
self.pushButton_2.setText(QCoreApplication.translate("ReadImg", u"\u9690\u85cf", None))
self.fullButton.setText(QCoreApplication.translate("ReadImg", u"\u5168\u5c4f", None))
diff --git a/src/interface/ui_setting_new.py b/src/interface/ui_setting_new.py
index 65b01ab..4a0aacf 100644
--- a/src/interface/ui_setting_new.py
+++ b/src/interface/ui_setting_new.py
@@ -29,7 +29,7 @@ class Ui_SettingNew(object):
def setupUi(self, SettingNew):
if not SettingNew.objectName():
SettingNew.setObjectName(u"SettingNew")
- SettingNew.resize(880, 789)
+ SettingNew.resize(946, 789)
SettingNew.setStyleSheet(u"")
self.verticalLayout_2 = QVBoxLayout(SettingNew)
self.verticalLayout_2.setObjectName(u"verticalLayout_2")
@@ -83,7 +83,7 @@ def setupUi(self, SettingNew):
self.scrollArea.setWidgetResizable(True)
self.scrollAreaWidgetContents = QWidget()
self.scrollAreaWidgetContents.setObjectName(u"scrollAreaWidgetContents")
- self.scrollAreaWidgetContents.setGeometry(QRect(0, -541, 661, 2891))
+ self.scrollAreaWidgetContents.setGeometry(QRect(0, 0, 727, 3043))
self.scrollAreaWidgetContents.setStyleSheet(u"")
self.verticalLayout_4 = QVBoxLayout(self.scrollAreaWidgetContents)
self.verticalLayout_4.setObjectName(u"verticalLayout_4")
@@ -471,6 +471,56 @@ def setupUi(self, SettingNew):
self.verticalLayout_17.addLayout(self.horizontalLayout_22)
+ self.label_44 = QLabel(self.frame_14)
+ self.label_44.setObjectName(u"label_44")
+ font2 = QFont()
+ font2.setPointSize(12)
+ font2.setBold(True)
+ self.label_44.setFont(font2)
+
+ self.verticalLayout_17.addWidget(self.label_44)
+
+ self.horizontalLayout_34 = QHBoxLayout()
+ self.horizontalLayout_34.setObjectName(u"horizontalLayout_34")
+ self.titleLineBox = WheelComboBox(self.frame_14)
+ self.titleLineBox.addItem("")
+ self.titleLineBox.addItem("")
+ self.titleLineBox.addItem("")
+ self.titleLineBox.addItem("")
+ self.titleLineBox.addItem("")
+ self.titleLineBox.setObjectName(u"titleLineBox")
+
+ self.horizontalLayout_34.addWidget(self.titleLineBox)
+
+ self.horizontalSpacer_32 = QSpacerItem(40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum)
+
+ self.horizontalLayout_34.addItem(self.horizontalSpacer_32)
+
+
+ self.verticalLayout_17.addLayout(self.horizontalLayout_34)
+
+ self.label_45 = QLabel(self.frame_14)
+ self.label_45.setObjectName(u"label_45")
+ self.label_45.setFont(font2)
+
+ self.verticalLayout_17.addWidget(self.label_45)
+
+ self.horizontalLayout_35 = QHBoxLayout()
+ self.horizontalLayout_35.setObjectName(u"horizontalLayout_35")
+ self.categoryBox = WheelComboBox(self.frame_14)
+ self.categoryBox.addItem("")
+ self.categoryBox.addItem("")
+ self.categoryBox.setObjectName(u"categoryBox")
+
+ self.horizontalLayout_35.addWidget(self.categoryBox)
+
+ self.horizontalSpacer_33 = QSpacerItem(40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum)
+
+ self.horizontalLayout_35.addItem(self.horizontalSpacer_33)
+
+
+ self.verticalLayout_17.addLayout(self.horizontalLayout_35)
+
self.verticalLayout_4.addWidget(self.frame_14)
@@ -1192,6 +1242,11 @@ def setupUi(self, SettingNew):
self.horizontalLayout_10.addWidget(self.setDirButton)
+ self.setLogDirButton = QPushButton(self.frame_11)
+ self.setLogDirButton.setObjectName(u"setLogDirButton")
+
+ self.horizontalLayout_10.addWidget(self.setLogDirButton)
+
self.horizontalSpacer_8 = QSpacerItem(40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum)
self.horizontalLayout_10.addItem(self.horizontalSpacer_8)
@@ -1303,6 +1358,37 @@ def setupUi(self, SettingNew):
self.verticalLayout_13.addLayout(self.horizontalLayout_19)
+ self.horizontalLayout_31 = QHBoxLayout()
+ self.horizontalLayout_31.setObjectName(u"horizontalLayout_31")
+ self.label_42 = QLabel(self.frame_11)
+ self.label_42.setObjectName(u"label_42")
+ self.label_42.setMinimumSize(QSize(80, 0))
+
+ self.horizontalLayout_31.addWidget(self.label_42)
+
+ self.logLabel = QLabel(self.frame_11)
+ self.logLabel.setObjectName(u"logLabel")
+ self.logLabel.setMinimumSize(QSize(150, 0))
+
+ self.horizontalLayout_31.addWidget(self.logLabel)
+
+ self.openLogDir = QPushButton(self.frame_11)
+ self.openLogDir.setObjectName(u"openLogDir")
+
+ self.horizontalLayout_31.addWidget(self.openLogDir)
+
+ self.horizontalSpacer_28 = QSpacerItem(40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum)
+
+ self.horizontalLayout_31.addItem(self.horizontalSpacer_28)
+
+
+ self.verticalLayout_13.addLayout(self.horizontalLayout_31)
+
+ self.horizontalLayout_30 = QHBoxLayout()
+ self.horizontalLayout_30.setObjectName(u"horizontalLayout_30")
+
+ self.verticalLayout_13.addLayout(self.horizontalLayout_30)
+
self.verticalLayout_4.addWidget(self.frame_11)
@@ -1380,10 +1466,21 @@ def retranslateUi(self, SettingNew):
self.showCloseButton1.setText(QCoreApplication.translate("SettingNew", u"\u5173\u95ed\u540e\u6700\u5c0f\u5316\u5230\u6258\u76d8", None))
self.label_2.setText(QCoreApplication.translate("SettingNew", u"\u5c01\u9762\u663e\u793a\u5927\u5c0f\uff08\u9ed8\u8ba4\u4e3a100%\uff09\uff1a", None))
self.label_29.setText(QCoreApplication.translate("SettingNew", u"\u5206\u7c7b\u5c01\u9762\u5927\u5c0f\uff1a", None))
+ self.label_44.setText(QCoreApplication.translate("SettingNew", u"\u6807\u9898\u663e\u793a\u884c\u6570", None))
+ self.titleLineBox.setItemText(0, QCoreApplication.translate("SettingNew", u"\u4e0d\u663e\u793a", None))
+ self.titleLineBox.setItemText(1, QCoreApplication.translate("SettingNew", u"1\u884c", None))
+ self.titleLineBox.setItemText(2, QCoreApplication.translate("SettingNew", u"2\u884c", None))
+ self.titleLineBox.setItemText(3, QCoreApplication.translate("SettingNew", u"3\u884c", None))
+ self.titleLineBox.setItemText(4, QCoreApplication.translate("SettingNew", u"\u5168\u90e8", None))
+
+ self.label_45.setText(QCoreApplication.translate("SettingNew", u"\u5206\u7c7b\u663e\u793a", None))
+ self.categoryBox.setItemText(0, QCoreApplication.translate("SettingNew", u"\u663e\u793a", None))
+ self.categoryBox.setItemText(1, QCoreApplication.translate("SettingNew", u"\u4e0d\u663e\u793a", None))
+
self.label_10.setText(QCoreApplication.translate("SettingNew", u"\u65e5\u5fd7\u7b49\u7ea7\uff1a", None))
self.logutton0.setText(QCoreApplication.translate("SettingNew", u"Warn", None))
self.logutton1.setText(QCoreApplication.translate("SettingNew", u"Info", None))
- self.logutton2.setText(QCoreApplication.translate("SettingNew", u"Debug", None))
+ self.logutton2.setText(QCoreApplication.translate("SettingNew", u"Debug\uff08\u8be5\u8bbe\u7f6e\u5185\u542b\u654f\u611f\u6570\u636e\uff0clog\u6587\u4ef6\u8bf7\u52ff\u5206\u4eab\uff09", None))
self.proxyLabel.setText(QCoreApplication.translate("SettingNew", u"\u4ee3\u7406", None))
self.label_7.setText(QCoreApplication.translate("SettingNew", u"Http\u4ee3\u7406\uff1a", None))
self.proxy0.setText(QCoreApplication.translate("SettingNew", u"\u65e0\u4ee3\u7406", None))
@@ -1461,6 +1558,7 @@ def retranslateUi(self, SettingNew):
self.saveNameButton2.setText(QCoreApplication.translate("SettingNew", u"\u4f5c\u8005\u540d\u5355\u72ec\u76ee\u5f55\uff08\u5982\u65e0\u4f5c\u8005\u540d\u5c06\u653e\u5165default\u76ee\u5f55\uff09", None))
self.label_21.setText(QCoreApplication.translate("SettingNew", u"\u4e0b\u8f7d\u548c\u7f13\u5b58\u8def\u5f84\uff08\u7f13\u5b58\u6587\u4ef6\u9700\u81ea\u5df1\u624b\u52a8\u6e05\u9664\uff09", None))
self.setDirButton.setText(QCoreApplication.translate("SettingNew", u"\u8bbe\u7f6e\u76ee\u5f55", None))
+ self.setLogDirButton.setText(QCoreApplication.translate("SettingNew", u"\u8bbe\u7f6e\u65e5\u5fd7\u76ee\u5f55", None))
self.label_3.setText(QCoreApplication.translate("SettingNew", u"\u4e0b\u8f7d", None))
self.downloadDir.setText("")
self.openDownloadDir.setText(QCoreApplication.translate("SettingNew", u"\u6253\u5f00\u76ee\u5f55", None))
@@ -1473,5 +1571,8 @@ def retranslateUi(self, SettingNew):
self.label_5.setText(QCoreApplication.translate("SettingNew", u"Waifu2x\u7f13\u5b58", None))
self.waifu2xDir.setText("")
self.openWaifu2xDir.setText(QCoreApplication.translate("SettingNew", u"\u6253\u5f00\u76ee\u5f55", None))
+ self.label_42.setText(QCoreApplication.translate("SettingNew", u"\u65e5\u5fd7", None))
+ self.logLabel.setText("")
+ self.openLogDir.setText(QCoreApplication.translate("SettingNew", u"\u6253\u5f00\u76ee\u5f55", None))
# retranslateUi
diff --git a/src/qt_owner.py b/src/qt_owner.py
index 52db1d8..4b31c8d 100644
--- a/src/qt_owner.py
+++ b/src/qt_owner.py
@@ -78,6 +78,19 @@ def CopyText(self, text):
from tools.str import Str
QtOwner().ShowMsg(Str.GetStr(Str.CopySuc))
+ def OpenProxy(self):
+ from view.user.login_view import LoginView
+ loginView = LoginView(QtOwner().owner, False)
+ loginView.tabWidget.setCurrentIndex(3)
+ loginView.tabWidget.removeTab(0)
+ loginView.tabWidget.removeTab(0)
+ loginView.tabWidget.removeTab(0)
+ loginView.loginButton.setText(Str.GetStr(Str.Save))
+ loginView.show()
+
+ loginView.closed.connect(QtOwner().owner.navigationWidget.UpdateProxyName)
+ return
+
@property
def owner(self):
from view.main.main_view import MainView
diff --git a/src/requirements.txt b/src/requirements.txt
index d7f51e5..e4a0c50 100644
--- a/src/requirements.txt
+++ b/src/requirements.txt
@@ -1,9 +1,10 @@
-PySide6>=6.1,<6.5
-Pillow>=9.5
-PySocks>=1.7
-natsort>=8.2
-requests>=2.26
-urllib3>=2
+PySide6==6.2.4
+websocket-client==0.59.0
+requests==2.26.0
+urllib3==1.25.11
+
+pillow==8.3.2
waifu2x-vulkan==1.1.6
-websocket-client>=1.6
-# pywin32>=302
+Pysocks==1.7.1
+natsort==8.2.0
+# pywin32==302
\ No newline at end of file
diff --git a/src/server/req.py b/src/server/req.py
index 4c22757..2d376d5 100644
--- a/src/server/req.py
+++ b/src/server/req.py
@@ -1,5 +1,6 @@
import base64
import os
+import platform
import random
import uuid
from datetime import datetime, timedelta
@@ -57,8 +58,11 @@ def __str__(self):
# headers["authorization"] = "**********"
params = dict()
params.update(self.params)
- if Setting.LogIndex.value == 1 and "password" in params:
- params["password"] = "******"
+ ## 脱敏数据
+ # if self.__class__.__name__ in ["LoginReq", "RegisterReq"]:
+ # params = "******"
+ # if Setting.LogIndex.value == 1 and "password" in params:
+ # params["password"] = "******"
return "{}, url:{}, method:{}, params:{}".format(self.__class__.__name__, self.url, self.method, params)
@@ -357,6 +361,7 @@ def __init__(self, isPre=False):
method = "GET"
data = dict()
data["version"] = config.UpdateVersion
+ data["platform"] = platform.platform()
if not isPre:
url = config.AppUrl + "/version.txt?"
else:
@@ -373,13 +378,27 @@ def __init__(self, newVersion):
method = "GET"
data = dict()
data["version"] = config.UpdateVersion
+ data["platform"] = platform.platform()
url = config.AppUrl + "/{}.txt?".format(newVersion)
url += ToolUtil.DictToUrl(data)
super(self.__class__, self).__init__(url, {}, {}, method)
self.isParseRes = False
self.useImgProxy = False
-
-
+
+
+# 检查更新配置
+class CheckUpdateConfigReq(ServerReq):
+ def __init__(self):
+ method = "GET"
+ data = dict()
+ data["version"] = config.UpdateVersion
+ data["platform"] = platform.platform()
+ url = config.AppUrl + "/config.txt?"
+ url += ToolUtil.DictToUrl(data)
+ super(self.__class__, self).__init__(url, {}, {}, method)
+ self.isParseRes = False
+ self.useImgProxy = False
+
# 检查更新
class CheckUpdateDatabaseReq(ServerReq):
def __init__(self, url):
@@ -489,12 +508,17 @@ def __init__(self):
if SpeedTestReq.Index >= len(SpeedTestReq.URLS):
SpeedTestReq.Index = 0
method = "Download"
+ host = ToolUtil.GetUrlHost(url)
+ if host in config.ApiDomain and Setting.ProxySelectIndex.value == 5:
+ self.headers.pop("user-agent")
+ self.proxyUrl = config.ProxyApiDomain
+
header = ToolUtil.GetHeader(url, method)
header['cache-control'] = 'no-cache'
header['expires'] = '0'
header['pragma'] = 'no-cache'
self.isReload = False
- self.resetCnt = 2
+ self.resetCnt = 1
self.isReset = False
super(self.__class__, self).__init__(url, header,
{}, method)
diff --git a/src/server/res.py b/src/server/res.py
index 8040742..8fb75e2 100644
--- a/src/server/res.py
+++ b/src/server/res.py
@@ -4,8 +4,9 @@
class BaseRes(object):
- def __init__(self, data, isParseRes) -> None:
+ def __init__(self, data, isParseRes, reqName) -> None:
super().__init__()
+ self.reqName = reqName
self.raw = data
self.data = {}
self.code = 0
@@ -25,6 +26,9 @@ def __str__(self):
data = self.GetText()
else:
data = ""
+ # 脱敏数据
+ # if self.reqName in ["LoginReq", "RegisterReq"]:
+ # return "code:{}, raw:{}".format(self.code, data.replace("\n", "")[:20])
return "code:{}, raw:{}".format(self.code, data.replace("\n", ""))
def GetText(self):
diff --git a/src/server/server.py b/src/server/server.py
index 82a84db..4d166e7 100644
--- a/src/server/server.py
+++ b/src/server/server.py
@@ -11,6 +11,7 @@
import server.req as req
import server.res as res
from config import config
+from config.global_config import GlobalConfig
from qt_owner import QtOwner
from task.qt_task import TaskBase
from tools.log import Log
@@ -81,6 +82,7 @@ def __init__(self) -> None:
self.session = requests.session()
self.address = ""
self.imageServer = ""
+ self.imageAddress = ""
self.token = ""
self._inQueue = Queue()
@@ -131,13 +133,14 @@ def RunDownload(self):
Log.Error(es)
pass
- def UpdateDns(self, address, imageAddress):
- self.imageServer = imageAddress
+ def UpdateDns(self, address, imageUrl, imageAdress):
+ self.imageServer = imageUrl
self.address = address
+ self.imageAddress = imageAdress
AllDomain = config.ApiDomain[:]
- AllDomain.append(config.ImageServer2)
- AllDomain.append(config.ImageServer2Jump)
+ # AllDomain.append(config.ImageServer2)
+ # AllDomain.append(config.ImageServer2Jump)
# AllDomain.append(config.ImageServer3Jump)
for domain in AllDomain:
if is_ipaddress(address):
@@ -145,10 +148,16 @@ def UpdateDns(self, address, imageAddress):
elif not address and domain in host_table:
host_table.pop(domain)
- for domain in config.ImageDomain:
- if is_ipaddress(imageAddress):
- host_table[domain] = imageAddress
- elif not imageAddress and domain in host_table:
+ for domain in GlobalConfig.ImageServerList.value:
+ if is_ipaddress(imageAdress):
+ host_table[domain] = imageAdress
+ elif not imageAdress and domain in host_table:
+ host_table.pop(domain)
+
+ for domain in GlobalConfig.ImageJumList.value:
+ if is_ipaddress(imageAdress):
+ host_table[domain] = imageAdress
+ elif not imageAdress and domain in host_table:
host_table.pop(domain)
# 换一个,清空pool
@@ -162,7 +171,7 @@ def __DealHeaders(self, request, token):
request.headers["authorization"] = token
host = ToolUtil.GetUrlHost(request.url)
- if self.imageServer and host in config.ImageDomain:
+ if self.imageServer and host in GlobalConfig.ImageServerList.value:
if not is_ipaddress(self.imageServer):
request.url = request.url.replace(host, self.imageServer)
@@ -170,6 +179,7 @@ def __DealHeaders(self, request, token):
request.url = request.url.replace("https://", "http://")
if request.proxyUrl:
+ host = ToolUtil.GetUrlHost(request.url)
request.url = request.url.replace(host, request.proxyUrl+"/"+host)
# host = ToolUtil.GetUrlHost(request.url)
@@ -258,14 +268,14 @@ def Post(self, task):
if request.headers == None:
request.headers = {}
- task.res = res.BaseRes("", False)
+ task.res = res.BaseRes("", False, task.req.__class__.__name__)
if request.file:
r = self.session.post(request.url, proxies=request.proxy, headers=request.headers, files=request.file,
timeout=task.timeout, verify=False)
else:
r = self.session.post(request.url, proxies=request.proxy, headers=request.headers,
data=json.dumps(request.params), timeout=task.timeout, verify=False)
- task.res = res.BaseRes(r, request.isParseRes)
+ task.res = res.BaseRes(r, request.isParseRes, task.req.__class__.__name__)
return task
def Put(self, task):
@@ -276,9 +286,9 @@ def Put(self, task):
if request.headers == None:
request.headers = {}
- task.res = res.BaseRes("", False)
+ task.res = res.BaseRes("", False, task.req.__class__.__name__)
r = self.session.put(request.url, proxies=request.proxy, headers=request.headers, data=json.dumps(request.params), timeout=60, verify=False)
- task.res = res.BaseRes(r, request.isParseRes)
+ task.res = res.BaseRes(r, request.isParseRes, task.req.__class__.__name__)
return task
def Get(self, task):
@@ -289,9 +299,9 @@ def Get(self, task):
if request.headers == None:
request.headers = {}
- task.res = res.BaseRes("", False)
+ task.res = res.BaseRes("", False, task.req.__class__.__name__)
r = self.session.get(request.url, proxies=request.proxy, headers=request.headers, timeout=task.timeout, verify=False)
- task.res = res.BaseRes(r, request.isParseRes)
+ task.res = res.BaseRes(r, request.isParseRes, task.req.__class__.__name__)
return task
def Download(self, request, token="", backParams="", isASync=True):
@@ -337,6 +347,7 @@ def _Download(self, task):
Log.Info("request reset:{} -> backId:{}, {}".format(task.req.resetCnt, task.bakParam, task.req))
history = []
+ # oldHost = ToolUtil.GetUrlHost(request.url)
for i in range(10):
r = self.session.get(request.url, proxies=request.proxy, headers=request.headers, timeout=task.timeout,
verify=False, allow_redirects=False, stream=True)
@@ -351,7 +362,7 @@ def _Download(self, task):
Log.Info("request 301 reset:{} -> backId:{}, {}".format(task.req.resetCnt, task.bakParam, task.req))
history.append(r)
- self.__DealHeaders(request, "")
+ # self.__DealHeaders(request, "")
else:
break
r.history = history
@@ -387,6 +398,7 @@ def TestSpeed(self, request, bakParams=""):
self.__DealHeaders(request, "")
task = Task(request, bakParams)
task.timeout = 5
+
self._downloadQueue.put(task)
def TestSpeedPing(self, request, bakParams=""):
diff --git a/src/server/sql_server.py b/src/server/sql_server.py
index b2252d7..0469d16 100644
--- a/src/server/sql_server.py
+++ b/src/server/sql_server.py
@@ -511,6 +511,10 @@ def Search2(wordList, isTitle, isAuthor, isDes, isTag, isCategory, isCreator, ca
else:
orWords.append(words)
+ if not andWords and not exclude:
+ orWords = []
+ orWords.append(wordList)
+
data = ""
data2 = ""
for word in orWords:
diff --git a/src/server/user_handler.py b/src/server/user_handler.py
index e57add0..d6a4935 100644
--- a/src/server/user_handler.py
+++ b/src/server/user_handler.py
@@ -304,7 +304,6 @@ def __call__(self, task):
return
if task.res.raw.status_code != 200:
return
-
verData = task.res.GetText()
info = verData.replace("v", "").split(".")
version = int(info[0]) * 100 + int(info[1]) * 10 + int(info[2]) * 1
@@ -339,7 +338,26 @@ def __call__(self, task):
finally:
if task.bakParam:
TaskBase.taskObj.taskBack.emit(task.bakParam, pickle.dumps(data))
-
+
+
+@handler(req.CheckUpdateConfigReq)
+class CheckUpdateConfigHandler(object):
+ def __call__(self, task):
+ data = {"st": task.status, "data": ""}
+ try:
+ if not task.res.GetText() or task.status == Status.NetError:
+ return
+ if task.res.raw.status_code != 200:
+ return
+
+ data["data"] = task.res.GetText()
+ except Exception as es:
+ pass
+ finally:
+ if task.bakParam:
+ TaskBase.taskObj.taskBack.emit(task.bakParam, pickle.dumps(data))
+
+
@handler(req.SpeedTestReq)
class SpeedTestHandler(object):
def __call__(self, backData):
diff --git a/src/start.py b/src/start.py
index cd530c1..a1d380d 100644
--- a/src/start.py
+++ b/src/start.py
@@ -90,7 +90,6 @@
if config.CanWaifu2x:
waifu2x_vulkan.stop()
sys.exit(-111)
-
sts = app.exec()
socket.close()
main.Close()
diff --git a/src/task/task_convert_epub.py b/src/task/task_convert_epub.py
new file mode 100644
index 0000000..99418b3
--- /dev/null
+++ b/src/task/task_convert_epub.py
@@ -0,0 +1,13 @@
+
+
+class TaskConvertEpub(object):
+ def __init__(self):
+ pass
+
+ def start(self):
+ return
+
+
+if __name__ == "__main__":
+ t = TaskConvertEpub()
+ t.start()
diff --git a/src/task/task_download.py b/src/task/task_download.py
index 89d9b48..1d5d28a 100644
--- a/src/task/task_download.py
+++ b/src/task/task_download.py
@@ -22,6 +22,8 @@ class QtDownloadTask(object):
Error = Str.Error
Cache = Str.Cache
SpaceEps = Str.SpaceEps
+ UnderReviewBook = Str.UnderReviewBook
+ # Str.UnderReviewBook
def __init__(self, downloadId=0):
self.downloadId = downloadId
@@ -204,32 +206,45 @@ def HandlerDownload(self, data, v):
return
isReset = False
+ st = data['st']
if data["st"] != Status.Ok:
task.resetCnt += 1
+ if data['st'] == Status.UnderReviewBook:
+ self.SetTaskStatus(taskId, backData, task.UnderReviewBook)
+ return
+
# 失败了
- if task.resetCnt >= 5:
+ if task.resetCnt >= 10:
self.SetTaskStatus(taskId, backData, task.Error)
return
isReset = True
else:
+ # 防止死循环
+ if task.resetCnt >= 50:
+ self.SetTaskStatus(taskId, backData, task.Error)
+ return
task.status = newStatus
+
info = BookMgr().GetBook(task.bookId)
if task.status == task.Waiting:
- isReset or self.SetTaskStatus(taskId, backData, task.Reading)
+ # isReset or self.SetTaskStatus(taskId, backData, task.Reading)
if not info:
if task.isLocal:
task.isLocal = False
+ task.resetCnt += 1
self.AddSqlTask("book", task.bookId, SqlServer.TaskTypeCacheBook, self.HandlerDownload, (taskId, task.Waiting))
else:
+ task.resetCnt += 1
self.AddHttpTask(req.GetComicsBookReq(task.bookId), self.HandlerDownload, (taskId, task.Reading), task.cleanFlag)
return
task.status = task.Reading
if task.status == task.Reading:
- isReset or self.SetTaskStatus(taskId, backData, task.ReadingEps)
+ # isReset or self.SetTaskStatus(taskId, backData, task.ReadingEps)
if info.maxLoadEps <= 0:
+ task.resetCnt += 1
self.AddHttpTask(req.GetComicsBookEpsReq(task.bookId), self.HandlerDownload, (taskId, task.Reading), task.cleanFlag)
return
@@ -239,13 +254,16 @@ def HandlerDownload(self, data, v):
if task.epsId not in info.epsDict:
loadPage = (info.epsCount - task.epsId - 1) // info.epsLimit
+
+ task.resetCnt += 1
self.AddHttpTask(req.GetComicsBookEpsReq(task.bookId, loadPage+1), self.HandlerDownload, (taskId, task.Reading), task.cleanFlag)
return
task.status = task.ReadingEps
if task.status == task.ReadingEps:
- isReset or self.SetTaskStatus(taskId, backData, task.ReadingPicture)
+ # isReset or self.SetTaskStatus(taskId, backData, task.ReadingPicture)
if task.epsId not in info.epsDict:
+ Log.Warn("eps space error, book_id:{}, eps_id:{}".format(task.bookId, task.epsId))
self.SetTaskStatus(taskId, backData, task.SpaceEps)
return
@@ -253,14 +271,17 @@ def HandlerDownload(self, data, v):
assert isinstance(epsInfo, BookEps)
if epsInfo.isSpace:
+ Log.Warn("eps space error, book_id:{}, eps:{}".format(task.bookId, epsInfo))
self.SetTaskStatus(taskId, backData, task.SpaceEps)
return
if epsInfo.maxPicPages <= 0:
+ task.resetCnt += 1
self.AddHttpTask(req.GetComicsBookOrderReq(task.bookId, task.epsId+1), self.HandlerDownload, (taskId, task.ReadingEps), task.cleanFlag)
return
if task.index not in epsInfo.pics:
loadPage = task.index // epsInfo.picLimit + 1
+ task.resetCnt += 1
self.AddHttpTask(req.GetComicsBookOrderReq(task.bookId, task.epsId+1, loadPage), self.HandlerDownload, (taskId, task.ReadingPicture), task.cleanFlag)
return
@@ -269,6 +290,11 @@ def HandlerDownload(self, data, v):
epsInfo = info.epsDict[task.epsId]
assert isinstance(epsInfo, BookEps)
if epsInfo.isSpace:
+ Log.Warn("eps space error, book_id:{}, eps:{}".format(task.bookId, epsInfo))
+ self.SetTaskStatus(taskId, backData, task.SpaceEps)
+ return
+ if epsInfo.maxPics <= 0:
+ Log.Warn("eps maxPics error, book_id:{}, eps:{}".format(task.bookId, epsInfo))
self.SetTaskStatus(taskId, backData, task.SpaceEps)
return
@@ -351,7 +377,7 @@ def HandlerTaskSt(self, downloadId, data):
task.status = st
# print("st:{} {}".format(task.status, data))
status = task.status
- if status == task.Downloading or status == task.Error or status == task.SpaceEps or status == task.Cache:
+ if status == task.Downloading or status == task.Error or status == task.SpaceEps or status == task.Cache or status == task.UnderReviewBook:
self.ClearDownloadTask(downloadId)
except Exception as es:
Log.Error(es)
diff --git a/src/tools/book.py b/src/tools/book.py
index 310b1ff..05cc6c3 100644
--- a/src/tools/book.py
+++ b/src/tools/book.py
@@ -20,7 +20,7 @@ def __init__(self):
self.title = "" # 章节名
self.order = 0 # 排序
self.id = "" # id
- self.maxPics = 1 # 总页数
+ self.maxPics = 0 # 总页数
self.pics = {} # 图片
self.curLoadPicPages = set()
@@ -28,6 +28,9 @@ def __init__(self):
self.isSpace = False # 某些章节出现了空白的问题,导致死循环了
self.picLimit = 0
+ def __str__(self):
+ return "order:{}, maxPics:{}, pics:{}, curLoadPicPages:{}, maxPicPages:{}, picLimit:{}".format(self.order, self.maxPics, len(self.pics), self.curLoadPicPages, self.maxPicPages, self.picLimit)
+
# 一本书
class Book(object):
@@ -197,6 +200,7 @@ def AddBookEpsPicInfoBack(self, backData):
# 空白章节
if epsInfo.maxPics == 0:
+ Log.Warn("eps space, book_id:{}, data:{}".format(bookId, r.GetText()))
epsInfo.isSpace = True
# 重新初始化
diff --git a/src/tools/str.py b/src/tools/str.py
index 8caa242..4cd2fcb 100644
--- a/src/tools/str.py
+++ b/src/tools/str.py
@@ -77,6 +77,7 @@ class Str:
ErrorPath = 4005 # "错误的路径"
NotPictureFile = 4006 # "没有发现图片文件"
FileLock = 4007 # "文件已加密"
+ SpacePic = 4008 # "文件已加密"
CvSuccess = 5001 # "完成"
CvReading = 5002 # 获取信息
@@ -237,6 +238,7 @@ class Str:
ImportDouble = 152 # 导入多章节目录
ImportLocal = 153 # 导入本地漫画中
NotUpdateEps = 154 # 没有可更新的章节
+ CurRead = 155 # 正在看
@classmethod
@@ -311,6 +313,7 @@ def Reload(cls):
cls.strDict[cls.ErrorPath] = QCoreApplication.translate("cls.obj", "错误的路径", None)
cls.strDict[cls.NotPictureFile] = QCoreApplication.translate("cls.obj", "没有发现图片文件", None)
cls.strDict[cls.FileLock] = QCoreApplication.translate("cls.obj", "文件已加密", None)
+ cls.strDict[cls.SpacePic] = QCoreApplication.translate("cls.obj", "空白章节", None)
cls.strDict[cls.CvSuccess] = QCoreApplication.translate("cls.obj", "完成", None)
cls.strDict[cls.CvReading] = QCoreApplication.translate("cls.obj", "获取信息", None)
@@ -463,6 +466,7 @@ def Reload(cls):
cls.strDict[cls.ImportDouble] = QCoreApplication.translate("cls.obj", "导入多章节目录", None)
cls.strDict[cls.ImportLocal] = QCoreApplication.translate("cls.obj", "导入到本地漫画中", None)
cls.strDict[cls.NotUpdateEps] = QCoreApplication.translate("cls.obj", "没有可更新章节", None)
+ cls.strDict[cls.CurRead] = QCoreApplication.translate("cls.obj", "正在看", None)
@classmethod
def GetStr(cls, enumType, defualt=""):
diff --git a/src/tools/user.py b/src/tools/user.py
index d745a51..53745d3 100644
--- a/src/tools/user.py
+++ b/src/tools/user.py
@@ -58,48 +58,48 @@ def address(self):
def address(self, value):
self.server.address = value
- def InitBack(self, backData):
- try:
- if backData.status == Status.Ok and backData.res.status == "ok":
-
- from config.setting import Setting
- if len(backData.res.addresses) >= 1:
- # 只更新分流三 第一个地址
- config.Address[1] = backData.res.addresses[0]
- Setting.SaveCacheAddress.SetValue(backData.res.addresses[0])
- # self.address = backData.res.addresses[0]
- Log.Info("初始化成功, Ips:{}, {}".format(backData.res.addresses, config.Address))
- # 需要更新DNS
- if Setting.ProxySelectIndex.value == 3:
- imageServer = config.ImageServer3
- address = config.Address[1]
- if not Setting.PreIpv6.value:
- self.server.UpdateDns(address, imageServer)
- self.initRes = backData.res
- return Status.Ok
- else:
- Log.Info("初始化失败, info:{}".format(backData.res))
- return Status.Error
- except Exception as es:
- Log.Error(es)
- return Status.Error
-
- def InitImageServer(self, backData):
- try:
- if self.server.address:
- self.server.imageServer = self.imageServer
- if backData.res.code == 200:
- # 选择了分流才设置
- # if self.server.address:
- # self.server.imageServer = ToolUtil.GetUrlHost(backData.res.data["imageServer"])
- # Log.Info("初始化图片服务器成功, info:{}".format(self.server.imageServer))
-
- return Status.Ok
- else:
- return Status.Error
- except Exception as es:
- Log.Error(es)
- return Status.Error
+ # def InitBack(self, backData):
+ # try:
+ # if backData.status == Status.Ok and backData.res.status == "ok":
+ #
+ # from config.setting import Setting
+ # if len(backData.res.address) >= 1:
+ # # 只更新分流三 第一个地址
+ # config.Address[1] = backData.res.address[0]
+ # Setting.SaveCacheAddress.SetValue(backData.res.address[0])
+ # # self.address = backData.res.addresses[0]
+ # Log.Info("初始化成功, Ips:{}, {}".format(backData.res.address, config.Address))
+ # # 需要更新DNS
+ # if Setting.ProxySelectIndex.value == 3:
+ # imageServer = config.ImageServer3
+ # address = config.Address[1]
+ # if not Setting.PreIpv6.value:
+ # self.server.UpdateDns(address, imageServer)
+ # self.initRes = backData.res
+ # return Status.Ok
+ # else:
+ # Log.Info("初始化失败, info:{}".format(backData.res))
+ # return Status.Error
+ # except Exception as es:
+ # Log.Error(es)
+ # return Status.Error
+
+ # def InitImageServer(self, backData):
+ # try:
+ # if self.server.address:
+ # self.server.imageServer = self.imageServer
+ # if backData.res.code == 200:
+ # # 选择了分流才设置
+ # # if self.server.address:
+ # # self.server.imageServer = ToolUtil.GetUrlHost(backData.res.data["imageServer"])
+ # # Log.Info("初始化图片服务器成功, info:{}".format(self.server.imageServer))
+ #
+ # return Status.Ok
+ # else:
+ # return Status.Error
+ # except Exception as es:
+ # Log.Error(es)
+ # return Status.Error
def SetUserInfo(self, userId, passwd):
self.userId = userId
diff --git a/src/view/download/download_item.py b/src/view/download/download_item.py
index e65409a..7bb022a 100644
--- a/src/view/download/download_item.py
+++ b/src/view/download/download_item.py
@@ -21,6 +21,7 @@ class DownloadItem(QtTaskBase):
Pause = Str.Pause
Error = Str.Error
SpaceEps = Str.SpaceEps
+ UnderReviewBook = Str.UnderReviewBook
Converting = Str.Converting
ConvertSuccess = Str.ConvertSuccess
diff --git a/src/view/download/download_status.py b/src/view/download/download_status.py
index 395ef47..13e6513 100644
--- a/src/view/download/download_status.py
+++ b/src/view/download/download_status.py
@@ -28,11 +28,15 @@ def SetNewStatus(self, task, status, statusMsg=""):
self._SetTaskWait(task)
elif status == task.Pause:
self._SetTaskPause(task)
- elif status == task.Error or status == task.SpaceEps:
+ elif status == task.Error or status == task.SpaceEps or status == task.UnderReviewBook:
+ task.speedStr = ""
+ task.speed = 0
self._SetDownloadTaskNone(task)
elif status == task.Downloading:
self._SetTaskDownloading(task)
elif status == task.Success:
+ task.speedStr = ""
+ task.speed = 0
self._SetDownloadTaskNone(task)
else:
assert False
@@ -48,7 +52,7 @@ def SetNewCovertStatus(self, task, status, msg=""):
self._SetTaskConvertWait(task)
elif status == task.Pause:
self._SetTaskConvertPause(task)
- elif status == task.Error or status == task.SpaceEps:
+ elif status == task.Error or status == task.SpaceEps or status == task.UnderReviewBook:
self._SetTaskConvertNone(task)
elif status == task.Converting:
self._SetTaskConverting(task)
@@ -207,6 +211,12 @@ def DownloadStCallBack(self, data, taskId):
self.UpdateTableItem(task)
elif st == Str.SpaceEps:
self.SetNewStatus(task, task.SpaceEps)
+ elif st == Str.UnderReviewBook:
+ from tools.book import BookMgr
+ info = BookMgr().GetBook(task.bookId)
+ if info:
+ task.title = info.title
+ self.SetNewStatus(task, task.UnderReviewBook)
else:
self.SetNewStatus(task, task.Error)
return
diff --git a/src/view/download/download_view.py b/src/view/download/download_view.py
index 0a37c0a..42c4817 100644
--- a/src/view/download/download_view.py
+++ b/src/view/download/download_view.py
@@ -186,7 +186,7 @@ def SendLocalBack(self, books, bookID):
def AddDownload(self, bookId, downloadIds):
if not downloadIds:
return
-
+ Log.Info("add download, book_id={}, eps={}".format(bookId, downloadIds))
if bookId not in self.downloadDict:
task = DownloadItem()
task.bookId = bookId
@@ -369,14 +369,14 @@ def SelectMenu(self, pos):
menu.addAction(openDirAction)
menu.addAction(selectEpsAction)
assert isinstance(task, DownloadItem)
- if task.status in [task.Pause, task.Error, task.SpaceEps]:
+ if task.status in [task.Pause, task.Error, task.SpaceEps, task.UnderReviewBook]:
menu.addAction(startAction)
elif task.status in [task.Downloading, task.Waiting]:
menu.addAction(pauseAction)
if task.convertStatus in [task.Converting, task.Waiting]:
menu.addAction(pauseConvertAction)
- elif task.convertStatus in [task.Pause, task.Error, task.SpaceEps]:
+ elif task.convertStatus in [task.Pause, task.Error, task.SpaceEps, task.UnderReviewBook]:
menu.addAction(startConvertAction)
else:
menu = QMenu(self.tableWidget)
diff --git a/src/view/help/help_view.py b/src/view/help/help_view.py
index bdb54f0..c07827a 100644
--- a/src/view/help/help_view.py
+++ b/src/view/help/help_view.py
@@ -10,6 +10,7 @@
from PySide6.QtWidgets import QWidget, QMessageBox
from config import config
+from config.global_config import GlobalConfig
from config.setting import Setting
from interface.ui_help import Ui_Help
from qt_owner import QtOwner
@@ -69,6 +70,7 @@ def SwitchCheckPre(self):
Setting.IsPreUpdate.SetValue(int(self.preCheckBox.isChecked()))
def Init(self):
+ # self.InitUpdateConfig()
self.CheckDb()
# self.UpdateDbInfo()
@@ -106,8 +108,22 @@ def InitUpdateBack(self, raw):
def InitUpdateInfoBack(self, raw):
data = raw.get("data")
self.SetNewUpdate(self.updateBackUrl[self.checkUpdateIndex], Str.GetStr(Str.CurVersion) + config.UpdateVersion + ", "+ Str.GetStr(Str.CheckUpdateAndUp) + "\n\n" + data)
-
-
+
+ def InitUpdateConfig(self):
+ self.AddHttpTask(req.CheckUpdateConfigReq(), self.InitUpdateConfigBack)
+
+ def InitUpdateConfigBack(self, raw):
+ try:
+ st = raw.get("st")
+ if st != Str.Ok:
+ return
+ data = raw.get("data")
+ if not data:
+ return
+ GlobalConfig.UpdateSetting(data)
+ except Exception as es:
+ Log.Error(es)
+
def CheckDb(self):
self.AddSqlTask("book", "", SqlServer.TaskCheck, self.CheckDbBack)
diff --git a/src/view/main/main_view.py b/src/view/main/main_view.py
index 4e4719e..25063e2 100644
--- a/src/view/main/main_view.py
+++ b/src/view/main/main_view.py
@@ -1,6 +1,6 @@
from functools import partial
-from PySide6.QtCore import Qt, QEvent, QPoint, Signal, QTimer
+from PySide6.QtCore import Qt, QEvent, QPoint, Signal, QTimer, QSize
from PySide6.QtGui import QIcon, QMouseEvent, QGuiApplication, QFont
from PySide6.QtWidgets import QButtonGroup, QToolButton, QLabel
@@ -10,6 +10,7 @@
from component.system_tray_icon.my_system_tray_icon import MySystemTrayIcon
from component.widget.main_widget import Main
from config import config
+from config.global_config import GlobalConfig
from config.setting import Setting
from qt_owner import QtOwner
from server import req
@@ -36,7 +37,7 @@ def __init__(self):
# self.setAttribute(Qt.WA_TranslucentBackground)
self.setAttribute(Qt.WA_QuitOnClose, True)
self.timer = QTimer()
- self.timer.setInterval(10000)
+ self.timer.setInterval(1000)
# self.timer.timeout.connect(self.AfterStartSuc)
screens = QGuiApplication.screens()
# print(screens[0].geometry(), screens[1].geometry())
@@ -46,6 +47,7 @@ def __init__(self):
desktop = screens[Setting.ScreenIndex.value].geometry()
self.adjustSize()
+ self.myInitSize = QSize(desktop.width() // 4 * 3, desktop.height() // 4 * 3)
self.resize(desktop.width() // 4 * 3, desktop.height() // 4 * 3)
self.move(self.width() // 8+desktop.x(), max(0, desktop.height()-self.height()) // 2+desktop.y())
print(desktop.size(), self.size())
@@ -64,6 +66,7 @@ def __init__(self):
self.subStackWidget.setCurrentIndex(0)
self.settingView.LoadSetting()
+ GlobalConfig.LoadSetting()
self.searchView.searchTab.hide()
self.searchView2.searchWidget.hide()
@@ -150,6 +153,7 @@ def RetranslateUi(self):
self.navigationWidget.retranslateUi(self.navigationWidget)
def Init(self):
+ print(self.size())
IsCanUse = False
self.downloadView.Init()
self.InitApiProxy()
@@ -204,7 +208,7 @@ def Init(self):
if Setting.IsUpdate.value:
self.helpView.InitUpdate()
-
+ self.helpView.InitUpdateConfig()
self.searchView.InitWord()
self.msgLabel = MsgLabel(self)
self.msgLabel.hide()
@@ -217,13 +221,13 @@ def Init(self):
# self.timer.start()
# def AfterStartSuc(self):
- # self.timer.stop()
- # QtOwner().SetFont(self)
+ # # self.timer.stop()
+ # self.resize(self.myInitSize.width(), self.myInitSize.height())
def InitApiProxy(self):
request = req.InitReq()
request.proxy = {}
- self.AddHttpTask(request)
+ # self.AddHttpTask(request)
def ClearTabBar(self):
for toolButton in self.toolButtons:
diff --git a/src/view/read/read_graphics.py b/src/view/read/read_graphics.py
index 14a33da..e30ffb1 100644
--- a/src/view/read/read_graphics.py
+++ b/src/view/read/read_graphics.py
@@ -1,7 +1,8 @@
import time
from PySide6.QtCore import Qt, QEvent, QPoint, Signal, QRect, QFile
-from PySide6.QtGui import QPainter, QFont, QPixmap, QFontMetrics, QWheelEvent
+from PySide6.QtGui import QPainter, QFont, QPixmap, QFontMetrics, QWheelEvent, QSurfaceFormat
+from PySide6.QtOpenGLWidgets import QOpenGLWidget
from PySide6.QtWidgets import QGraphicsView, QFrame, QGraphicsItem, QGraphicsScene, \
QGraphicsPixmapItem, QGraphicsProxyWidget, QScroller, QAbstractSlider, QApplication
@@ -27,15 +28,17 @@ def __init__(self, parent=None):
QGraphicsView.__init__(self, parent)
SmoothScroll.__init__(self)
- self.vScrollBar = ReadScroll()
+ self.vScrollBar = ReadScroll(parent)
self.vScrollBar.setOrientation(Qt.Orientation.Vertical)
self.setVerticalScrollBar(self.vScrollBar)
+
# self.animation.finished.connect(self.Finished)
- self.hScrollBar = ReadScroll()
+ self.hScrollBar = ReadScroll(parent)
self.hScrollBar.setOrientation(Qt.Orientation.Horizontal)
self.setHorizontalScrollBar(self.hScrollBar)
+
# self.horizontalScrollBar().valueChanged.connect(self.HValueChange)
self.changeLastPage.connect(self.ChangeLastPage)
self.changeNextPage.connect(self.ChangeNextPage)
@@ -56,6 +59,11 @@ def __init__(self, parent=None):
self.setRenderHints(QPainter.Antialiasing | QPainter.SmoothPixmapTransform)
self.setCacheMode(QGraphicsView.CacheBackground)
# self.setCacheMode(QGraphicsView.CacheNone)
+ self.openGl = QOpenGLWidget()
+ f = QSurfaceFormat()
+ f.setSamples(4)
+ self.openGl.setFormat(f)
+ self.setViewport(self.openGl)
self.setViewportUpdateMode(QGraphicsView.FullViewportUpdate)
# self.setViewportUpdateMode(QGraphicsView.SmartViewportUpdate)
@@ -91,13 +99,13 @@ def __init__(self, parent=None):
# QScroller.scroller(self).setScrollerProperties(properties)
self.labelSize = {} # index: value
- self.oldValue = 0
+ # self.oldValue = 0
self.resetImg = False
# QScroller.scroller(self).stateChanged.connect(self.StateChanged)
- self.verticalScrollBar().actionTriggered.connect(self.OnActionTriggered)
+ # self.verticalScrollBar().actionTriggered.connect(self.OnActionTriggered)
- self.horizontalScrollBar().actionTriggered.connect(self.OnActionTriggered)
+ # self.horizontalScrollBar().actionTriggered.connect(self.OnActionTriggered)
self.verticalScrollBar()
self.startPos = QPoint()
self.labelWaifu2xState = {}
@@ -105,6 +113,7 @@ def __init__(self, parent=None):
QtOwner().owner.WindowsSizeChange.connect(self.ResetSize)
self.isLastPageMode = False # 是否切换到上一页
+
@property
def readImg(self):
return self.parent().readImg
@@ -171,19 +180,26 @@ def wheelEvent(self, e: QWheelEvent):
if self.verticalScrollBar().value() <= 5:
self.parent().qtTool.LastPage()
return
-
- return SmoothScroll.wheelEvent(self, e)
+ if e.angleDelta().y() < 0:
+ value = int(self.qtTool.scrollSpeed.value())
+ else:
+ value = - int(self.qtTool.scrollSpeed.value())
+ if self.initReadMode != ReadMode.RightLeftScroll:
+ self.vScrollBar.scrollValue(value)
+ else:
+ self.hScrollBar.scrollValue(value)
def Scale(self, ratio):
+ oldValue = self.verticalScrollBar().value()
self.scale(ratio, ratio)
self.ScaleResetVer()
for k, v in self.labelSize.items():
self.labelSize[k] *= ratio
if self.qtTool.stripModel == ReadMode.UpDown:
- self.verticalScrollBar().setValue(self.verticalScrollBar().value() * ratio)
+ self.verticalScrollBar().ForceSetValue( oldValue* ratio)
elif ReadMode.isScroll(self.qtTool.stripModel):
- self.horizontalScrollBar().setValue(self.horizontalScrollBar().value() * ratio)
+ self.horizontalScrollBar().ForceSetValue(oldValue * ratio)
self.ResetMaxNum()
def ScaleReset(self, oldScaleCnt):
@@ -200,9 +216,9 @@ def ScaleReset(self, oldScaleCnt):
else:
ratio = 0.9
if self.qtTool.stripModel == ReadMode.UpDown:
- self.verticalScrollBar().setValue(self.verticalScrollBar().value() * ratio)
+ self.verticalScrollBar().ForceSetValue(self.verticalScrollBar().value() * ratio)
elif ReadMode.isScroll(self.qtTool.stripModel):
- self.horizontalScrollBar().setValue(self.horizontalScrollBar().value() * ratio)
+ self.horizontalScrollBar().ForceSetValue(self.horizontalScrollBar().value() * ratio)
newV2 = self.verticalScrollBar().value()
# print(oldV, newV, newV2)
# if oldScaleCnt != 0:
@@ -220,14 +236,14 @@ def ResetSize(self):
def ScaleResetVer(self):
if not ReadMode.isScroll(self.initReadMode) or self.initReadMode == ReadMode.UpDown:
if self.scaleCnt != 0:
- self.horizontalScrollBar().setValue((self.horizontalScrollBar().maximum() / 2))
+ self.horizontalScrollBar().ForceSetValue((self.horizontalScrollBar().maximum() / 2))
else:
- self.horizontalScrollBar().setValue(0)
+ self.horizontalScrollBar().ForceSetValue(0)
else:
if self.scaleCnt != 0:
- self.verticalScrollBar().setValue((self.verticalScrollBar().maximum() / 2))
+ self.verticalScrollBar().ForceSetValue((self.verticalScrollBar().maximum() / 2))
else:
- self.verticalScrollBar().setValue(0)
+ self.verticalScrollBar().ForceSetValue(0)
def SetLabel(self, label, i):
text = str(i + 1)
@@ -263,10 +279,10 @@ def ScrollValue(self, value):
if self.initReadMode == ReadMode.Samewight and self.vScrollBar.value() >= self.vScrollBar.maximum():
self.ScrollNextPage()
else:
- self.vScrollBar.Scroll(value, 100)
+ self.vScrollBar.scrollValue(value)
# QScroller.scroller(self).scrollTo(QPoint(0, self.verticalScrollBar().value() + value), 500)
else:
- self.hScrollBar.Scroll(value, 100)
+ self.hScrollBar.scrollValue(value)
# QScroller.scroller(self).scrollTo(QPoint(self.horizontalScrollBar().value() + value, 0), 500)
return
@@ -353,9 +369,9 @@ def eventFilter(self, obj, ev) -> bool:
self.ScrollNextPage()
return False
- def StateChanged(self, state):
- if state == QScroller.State.Inactive:
- self.OnValueChange(self.GetScrollBar().value())
+ # def StateChanged(self, state):
+ # if state == QScroller.State.Inactive:
+ # self.OnValueChange(self.GetScrollBar().value())
# return print(state)
def GetScrollBar(self):
@@ -370,77 +386,17 @@ def GetOtherScrollBar(self):
else:
return self.verticalScrollBar()
- def OnActionTriggered(self, action):
- if action != QAbstractSlider.SliderMove:
- return
- self.OnValueChange(self.GetScrollBar().value())
-
- def OnValueChange(self, value):
- addValue = value - self.oldValue
- # self.UpdateScrollBar(value)
- self.oldValue = value
-
- if not ReadMode.isScroll(self.initReadMode):
- return
-
- curPictureSize = self.labelSize.get(self.readImg.curIndex)
- nextPictureSize = self.labelSize.get(self.readImg.curIndex + 1, 0)
- if self.initReadMode == ReadMode.RightLeftScroll:
- while True:
- newValue = value + self.width()
- ## 切换上一图片
- if addValue > 0 and value >= nextPictureSize:
- if self.readImg.curIndex <= 0:
- QtOwner().ShowMsg(Str.GetStr(Str.AlreadyLastPage))
- return
- self.readImg.curIndex -= 1
- # print(self.readImg.curIndex)
- self.changeLastPage.emit(self.readImg.curIndex)
-
- ## 切换下一图片
- elif addValue < 0 and newValue < curPictureSize:
- if self.readImg.curIndex >= self.readImg.maxPic - 1:
- QtOwner().ShowMsg(Str.GetStr(Str.AlreadyNextPage))
- return
- self.readImg.curIndex += 1
- # print(self.readImg.curIndex)
- self.changeNextPage.emit(self.readImg.curIndex)
- else:
- break
- curPictureSize = self.labelSize.get(self.readImg.curIndex)
- nextPictureSize = self.labelSize.get(self.readImg.curIndex + 1, 0)
- else:
- while True:
- ## 切换上一图片
- if addValue < 0 and value < curPictureSize:
- if self.readImg.curIndex <= 0:
- QtOwner().ShowMsg(Str.GetStr(Str.AlreadyLastPage))
- return
- self.readImg.curIndex -= 1
- # print("last page, addv:{}, val:{}, cur:{}, next:{}".format(addValue, value, curPictureSize, nextPictureSize))
- self.changeLastPage.emit(self.readImg.curIndex)
-
- ## 切换下一图片
- elif addValue > 0 and value >= nextPictureSize:
- if self.readImg.curIndex >= self.readImg.maxPic - 1:
- QtOwner().ShowMsg(Str.GetStr(Str.AlreadyNextPage))
- return
- self.readImg.curIndex += 1
- # print("next page, addv:{}, val:{}, cur:{}, next:{}".format(addValue, value, curPictureSize, nextPictureSize))
- self.changeNextPage.emit(self.readImg.curIndex)
- else:
- break
-
- curPictureSize = self.labelSize.get(self.readImg.curIndex)
- nextPictureSize = self.labelSize.get(self.readImg.curIndex + 1, 0)
- return
+ # def OnActionTriggered(self, action):
+ # if action != QAbstractSlider.SliderMove:
+ # return
+ # self.OnValueChange(self.GetScrollBar().value())
def InitAllQLabel(self, maxNum, curIndex):
if not maxNum:
return
- self.verticalScrollBar().setValue(0)
+ self.verticalScrollBar().ForceSetValue(0)
# self.horizontalScrollBar().setValue(0)
- self.oldValue = 0
+ # self.oldValue = 0
self.qtTool.CloseScrollAndTurn()
# if self.initReadMode and self.readImg.stripModel != self.initReadMode:
if self.initReadMode:
@@ -488,8 +444,8 @@ def InitAllQLabel(self, maxNum, curIndex):
proxy.setPos(value/self.GetScaleCntRatio(), 0)
value = self.labelSize.get(curIndex)
- self.oldValue = value
- self.GetScrollBar().setValue(value)
+ # self.oldValue = value
+ self.GetScrollBar().ForceSetValue(value)
# print(value)
# print(self.labelSize)
elif self.initReadMode in [ReadMode.LeftRight, ReadMode.Samewight]:
@@ -506,15 +462,20 @@ def InitAllQLabel(self, maxNum, curIndex):
self.ResetMaxNum()
return
- def ResetMaxNum(self):
+ def ResetMaxNum(self, addHeight=0):
maxNum = self.maxPic
if maxNum <= 0:
return
if self.initReadMode == ReadMode.RightLeftScroll:
maxSize = max(self.width(), self.labelSize.get(-1, 0) - self.width()) + 50
+ oldV = self.GetScrollBar().value()
self.graphicsScene.setSceneRect(0, 0, maxSize, self.height())
self.GetScrollBar().setMaximum(maxSize)
+ if addHeight > 0:
+ self.GetScrollBar().ResetAniValueByAdd(oldV, addHeight)
+ else:
+ self.GetScrollBar().ForceSetValue(oldV+ addHeight)
self.ScaleResetVer()
elif self.initReadMode in [ReadMode.LeftRightScroll]:
maxSize = max(self.width(), self.labelSize.get(maxNum, 0) - self.width()) + 50
@@ -522,14 +483,20 @@ def ResetMaxNum(self):
oldV = self.GetScrollBar().value()
self.graphicsScene.setSceneRect(0, 0, maxSize, self.height())
self.GetScrollBar().setMaximum(maxSize)
- self.GetScrollBar().setValue(oldV)
+ if addHeight > 0:
+ self.GetScrollBar().ResetAniValueByAdd(oldV, addHeight)
+ else:
+ self.GetScrollBar().ForceSetValue(oldV + addHeight)
self.ScaleResetVer()
elif self.initReadMode in [ReadMode.UpDown]:
maxSize = max(self.height(), self.labelSize.get(maxNum, 0) - self.height()) + 50
oldV = self.GetScrollBar().value()
self.graphicsScene.setSceneRect(0, 0, self.width(), maxSize)
self.GetScrollBar().setMaximum(maxSize)
- self.GetScrollBar().setValue(oldV)
+ if addHeight > 0:
+ self.GetScrollBar().ResetAniValueByAdd(oldV, addHeight)
+ else:
+ self.GetScrollBar().ForceSetValue(oldV)
self.ScaleResetVer()
else:
self.graphicsScene.setSceneRect(0, 0, self.width(), max(self.height(),
@@ -786,29 +753,31 @@ def UpdateOtherHeight(self, index, oldHeight, height):
return
oldValue = self.GetScrollBar().value()
-
+ needAddHeight = 0
if self.initReadMode == ReadMode.RightLeftScroll:
indexList = list(range(index - 1, -1, -1))
indexList.append(-1)
# TODO 需要重新定位
curPixcurSize = self.labelSize.get(index)
if curPixcurSize <= oldValue:
- self.GetScrollBar().setValue(oldValue + addHeight2)
- self.oldValue = self.GetScrollBar().value()
+ needAddHeight = addHeight
+ # self.GetScrollBar().ResetAniValueByAdd(oldValue, addHeight2)
+ # self.oldValue = self.GetScrollBar().value()
elif self.initReadMode in [ReadMode.LeftRightScroll, ReadMode.UpDown]:
indexList = list(range(index + 1, self.readImg.maxPic))
indexList.append(self.readImg.maxPic)
curPixcurSize = self.labelSize.get(index)
# TODO 需要重新定位
- if curPixcurSize <= oldValue:
- self.GetScrollBar().setValue(oldValue + addHeight2)
- self.oldValue = self.GetScrollBar().value()
+ if curPixcurSize < oldValue:
+ needAddHeight = addHeight
+ # self.GetScrollBar().ResetAniValueByAdd(oldValue, addHeight2)
+ # self.oldValue = self.GetScrollBar().value()
else:
self.ResetMaxNum()
if self.initReadMode in [ReadMode.Samewight, ReadMode.LeftRight] and self.isLastPageMode:
- self.verticalScrollBar().setValue(self.verticalScrollBar().maximum())
+ self.verticalScrollBar().ForceSetValue(self.verticalScrollBar().maximum())
return
for lenSize, i in enumerate(indexList):
@@ -834,13 +803,13 @@ def UpdateOtherHeight(self, index, oldHeight, height):
else:
proxy.setPos(oldPos.x() + addHeight, oldPos.y())
- self.ResetMaxNum()
+ self.ResetMaxNum(needAddHeight)
return
def ResetScrollValue(self, index):
if ReadMode.isScroll(self.initReadMode):
value = self.labelSize.get(index)
- self.GetScrollBar().setValue(value)
+ self.GetScrollBar().ForceSetValue(value)
# 上一页
def ChangeLastPage(self, index):
@@ -875,7 +844,7 @@ def ChangePage(self, oldIndex, index):
for newIndex in range(oldIndex + 1, min(oldIndex + config.PreLoading, self.maxPic)):
self.SetPixIem(newIndex, None)
value = self.labelSize.get(index)
- self.GetScrollBar().setValue(value)
+ self.GetScrollBar().ForceSetValue(value)
self.isLastPageMode = False
self.ReloadImg()
return
@@ -914,7 +883,7 @@ def ChangeScale(self, scale=1):
def ReloadImg(self):
if self.initReadMode in [ReadMode.LeftRightDouble, ReadMode.RightLeftDouble2, ReadMode.RightLeftDouble,
ReadMode.LeftRight, ReadMode.Samewight]:
- self.verticalScrollBar().setValue(0)
+ self.verticalScrollBar().ForceSetValue(0)
# self.UpdateAllPixIem()
self.readImg.CheckClearProcess()
self.readImg.ShowImgAll()
diff --git a/src/view/read/read_tool.py b/src/view/read/read_tool.py
index 0e4b25d..81bf0f8 100644
--- a/src/view/read/read_tool.py
+++ b/src/view/read/read_tool.py
@@ -626,15 +626,15 @@ def TimeOut(self):
if self.stripModel == ReadMode.UpDown:
if self.imgFrame.scrollArea.vScrollBar.value() >= self.imgFrame.scrollArea.vScrollBar.maximum():
self.CloseScrollAndTurn()
- self.imgFrame.scrollArea.vScrollBar.Scroll(value)
+ self.imgFrame.scrollArea.vScrollBar.scrollValue(value)
elif self.stripModel == ReadMode.LeftRightScroll:
if self.imgFrame.scrollArea.hScrollBar.value() >= self.imgFrame.scrollArea.hScrollBar.maximum():
self.CloseScrollAndTurn()
- self.imgFrame.scrollArea.hScrollBar.Scroll(value)
+ self.imgFrame.scrollArea.hScrollBar.scrollValue(value)
elif self.stripModel == ReadMode.RightLeftScroll:
if self.imgFrame.scrollArea.hScrollBar.value() <= self.imgFrame.scrollArea.hScrollBar.minimum():
self.CloseScrollAndTurn()
- self.imgFrame.scrollArea.hScrollBar.Scroll(-value)
+ self.imgFrame.scrollArea.hScrollBar.scrollValue(-value)
else:
self._NextPage()
pass
\ No newline at end of file
diff --git a/src/view/setting/setting_view.py b/src/view/setting/setting_view.py
index b7409e8..a32e77c 100644
--- a/src/view/setting/setting_view.py
+++ b/src/view/setting/setting_view.py
@@ -71,6 +71,9 @@ def __init__(self, parent=None):
self.downNoise.currentIndexChanged.connect(partial(self.CheckRadioEvent, Setting.DownloadNoise))
self.encodeSelect.currentTextChanged.connect(partial(self.CheckRadioEvent, Setting.SelectEncodeGpu))
self.threadSelect.currentIndexChanged.connect(partial(self.CheckRadioEvent, Setting.Waifu2xCpuCore))
+ self.titleLineBox.currentIndexChanged.connect(partial(self.CheckRadioEvent, Setting.TitleLine))
+ self.categoryBox.currentIndexChanged.connect(partial(self.CheckRadioEvent, Setting.NotCategoryShow))
+
self.fontBox.currentTextChanged.connect(partial(self.CheckRadioEvent, Setting.FontName))
self.fontSize.currentTextChanged.connect(partial(self.CheckRadioEvent, Setting.FontSize))
self.fontStyle.currentIndexChanged.connect(partial(self.CheckRadioEvent, Setting.FontStyle))
@@ -93,12 +96,14 @@ def __init__(self, parent=None):
self.downloadButton.clicked.connect(partial(self.MoveToLabel, self.downloadLabel))
self.setDirButton.clicked.connect(self.SelectSavePath)
+ self.setLogDirButton.clicked.connect(self.SelectSaveLogPath)
self.openDownloadDir.clicked.connect(partial(self.OpenDir, self.downloadDir))
self.openChatDir.clicked.connect(partial(self.OpenDir, self.chatDir))
self.openCacheDir.clicked.connect(partial(self.OpenDir, self.cacheDir))
self.openWaifu2xDir.clicked.connect(partial(self.OpenDir, self.waifu2xDir))
+ self.openLogDir.clicked.connect(partial(self.OpenDir, self.logLabel))
- self.openProxy.clicked.connect(self.OpenProxy)
+ self.openProxy.clicked.connect(QtOwner().OpenProxy)
# TODO
# self.languageButton3.setVisible(False)
@@ -242,6 +247,8 @@ def InitSetting(self):
self.readScale.setValue(Setting.LookScale.value)
self.readModel.setCurrentIndex(Setting.LookModel.value)
+ self.categoryBox.setCurrentIndex(Setting.NotCategoryShow.value)
+ self.titleLineBox.setCurrentIndex(Setting.TitleLine.value)
self.tileComboBox.setCurrentIndex(Setting.Waifu2xTileSize.value)
self.coverCheckBox.setChecked(Setting.CoverIsOpenWaifu.value)
self.coverNoise.setCurrentIndex(Setting.CoverLookNoise.value)
@@ -254,18 +261,6 @@ def InitSetting(self):
self.downModel.setCurrentIndex(Setting.DownloadModel.value)
self.SetDownloadLabel()
- def OpenProxy(self):
- loginView = LoginView(QtOwner().owner, False)
- loginView.tabWidget.setCurrentIndex(3)
- loginView.tabWidget.removeTab(0)
- loginView.tabWidget.removeTab(0)
- loginView.tabWidget.removeTab(0)
- loginView.loginButton.setText(Str.GetStr(Str.Save))
- loginView.show()
-
- loginView.closed.connect(QtOwner().owner.navigationWidget.UpdateProxyName)
- return
-
def retranslateUi(self, SettingNew):
Ui_SettingNew.retranslateUi(self, SettingNew)
self.SetDownloadLabel()
@@ -417,6 +412,14 @@ def SelectSavePath(self):
Setting.SavePath.SetValue(url)
self.SetDownloadLabel()
+ def SelectSaveLogPath(self):
+ url = QFileDialog.getExistingDirectory(self, Str.GetStr(Str.SelectFold))
+ if url:
+ Setting.LogDirPath.SetValue(url)
+ Log.Init()
+
+ self.SetDownloadLabel()
+
def SetDownloadLabel(self):
url = Setting.SavePath.value
if not url:
@@ -426,6 +429,8 @@ def SetDownloadLabel(self):
self.cacheDir.setText(os.path.join(url, config.CachePathDir))
self.waifu2xDir.setText(os.path.join(os.path.join(url, config.CachePathDir), config.Waifu2xPath))
+ self.logLabel.setText(Setting.GetLogPath())
+
def OpenDir(self, label):
QDesktopServices.openUrl(QUrl.fromLocalFile(label.text()))
return
diff --git a/src/view/tool/local_fold_view.py b/src/view/tool/local_fold_view.py
index 05e091d..bbe783e 100644
--- a/src/view/tool/local_fold_view.py
+++ b/src/view/tool/local_fold_view.py
@@ -121,7 +121,7 @@ def _SwitchEdit(self):
for i in range(self.listWidget.count()):
item = self.listWidget.item(i)
w = self.listWidget.itemWidget(item)
- if i == 0:
+ if i <= 0:
continue
w.SetEditEnable(True)
# item.setFlags(item.flags() & ~Qt.ItemIsSelectable)
@@ -195,6 +195,13 @@ def _DoAddItem(self, item):
name = w.lineEdit.text()
if not name:
return
+ if name == Str.GetStr(Str.All):
+ QtOwner().ShowError(Str.GetStr(Str.AlreadyHave))
+ return
+ if name == Str.GetStr(Str.CurRead):
+ QtOwner().ShowError(Str.GetStr(Str.AlreadyHave))
+ return
+
if name in self.categoryBook:
QtOwner().ShowError(Str.GetStr(Str.AlreadyHave))
return
diff --git a/src/view/tool/local_read_view.py b/src/view/tool/local_read_view.py
index 8f0bfb0..50ddee6 100644
--- a/src/view/tool/local_read_view.py
+++ b/src/view/tool/local_read_view.py
@@ -10,7 +10,7 @@
from interface.ui_index import Ui_Index
from interface.ui_local import Ui_Local
from qt_owner import QtOwner
-from server import Status, time
+from server import Status, time
from task.qt_task import QtTaskBase
from task.task_local import LocalData
from tools.str import Str
@@ -63,14 +63,16 @@ def __init__(self, parent=None):
self.bookList.ReDownloadPicture = self.LoadingPicture
self.bookList.LoadCallBack = self.LoadNextPage
self.lastPath = ""
-
+ self.sortKeyCombox.setCurrentIndex(1)
self.sortIdCombox.currentIndexChanged.connect(self.Init)
self.sortKeyCombox.currentIndexChanged.connect(self.Init)
+
self.setAcceptDrops(True)
self.categoryBook = {}
self.bookCategory = {}
self.tagsList.clicked.connect(self.ClickTagsItem)
self.curSelectCategory = ""
+ self.isCurRead = False
self.bookList.isMoveMenu = True
self.bookList.MoveHandler = self.MoveCallBack
self.bookList.openMenu = True
@@ -79,6 +81,8 @@ def __init__(self, parent=None):
self.delAll.clicked.connect(self.ShowDelAll)
self.searchText = ""
+ self.sortAllBookIds = []
+
def SearchTextChange(self, text):
self.searchText = text
self.InitBook()
@@ -87,6 +91,9 @@ def Init(self):
self.categoryBook, self.bookCategory = self.db.LoadCategory()
self.tagsList.clear()
self.tagsList.AddItem(Str.GetStr(Str.All), True)
+ item = self.tagsList.AddItem(Str.GetStr(Str.CurRead), True)
+ if self.isCurRead:
+ item.setSelected(True)
for category in self.categoryBook.keys():
item = self.tagsList.AddItem(category, True)
@@ -107,44 +114,56 @@ def InitBook(self):
oldV = oldDict.get(v.id)
if oldV:
v.CopyData(oldV)
+ self.ResetSortBookIds()
self.ShowPages()
- @time_me
- def ShowPages(self, page=1):
+ def ResetSortBookIds(self):
if self.curSelectCategory:
allBookId = self.categoryBook.get(self.curSelectCategory, [])
else:
allBookId = self.allBookInfos.keys()
-
allBookId2 = self.db.Search(self.searchText)
showIds = list(set(allBookId) & set(allBookId2))
+ self.sortAllBookIds = []
+ allBookInfos = []
+ for i in showIds:
+ v = self.allBookInfos.get(i)
+ if v:
+ if self.isCurRead:
+ if v.lastReadTime > 0:
+ allBookInfos.append(v)
+ else:
+ allBookInfos.append(v)
+
+ for v in self.ToSortData(allBookInfos):
+ if v.id in showIds:
+ self.sortAllBookIds.append(v.id)
+
+ @time_me
+ def ShowPages(self, page=1):
showLen = 30
- maxPage = len(showIds) // showLen + 1
- showStart = (page-1)*showLen
- showEnd = page * showLen - 1
+ maxPage = len(self.sortAllBookIds) // showLen + 1
+ showStart = (page - 1) * showLen
+ showEnd = page * showLen
+
self.spinBox.setValue(page)
self.spinBox.setMaximum(maxPage)
self.bookList.UpdatePage(page, maxPage)
self.pages.setText(self.bookList.GetPageStr())
- self.nums.setText("{}:{} ".format(Str.GetStr(Str.FavoriteNum), len(self.allBookInfos)))
- sortShowIds = []
- for v in self.ToSortData(list(self.allBookInfos.values())):
- if v.id in showIds:
- sortShowIds.append(v.id)
+ self.nums.setText("{}:{} ".format(Str.GetStr(Str.FavoriteNum), len(self.sortAllBookIds)))
- showIds2 = sortShowIds[showStart:showEnd]
+ showIds2 = self.sortAllBookIds[showStart:showEnd]
for id in showIds2:
v = self.allBookInfos.get(id)
if v:
categoryList = self.bookCategory.get(v.id, [])
categoryStr = ",".join(categoryList)
-
if not self.searchText or self.searchText in v.title:
self.bookList.AddBookByLocal(v, categoryStr)
return
def LoadNextPage(self):
- self.ShowPages(self.bookList.page+1)
+ self.ShowPages(self.bookList.page + 1)
def JumpPage(self):
page = int(self.spinBox.text())
@@ -162,11 +181,20 @@ def ClickTagsItem(self, modelIndex):
widget = self.tagsList.itemWidget(item)
text = widget.text()
# print(text)
+ self.isCurRead = False
if text == "+":
self.OpenFavoriteFold()
- elif text == Str.GetStr(Str.All):
+ elif index == 0:
self.curSelectCategory = ""
self.Init()
+ self.sortIdCombox.setCurrentIndex(0)
+ self.sortKeyCombox.setCurrentIndex(1)
+ elif index == 1:
+ self.curSelectCategory = ""
+ self.isCurRead = True
+ self.Init()
+ self.sortIdCombox.setCurrentIndex(0)
+ self.sortKeyCombox.setCurrentIndex(0)
else:
self.curSelectCategory = text
self.Init()
@@ -182,7 +210,7 @@ def ToSortData(self, value):
if sortKeyID == 0:
datas.sort(key=lambda a: a.lastReadTime, reverse=isRevert)
elif sortKeyID == 2:
- datas = natsorted(datas, key=lambda a:a.title, reverse=isRevert)
+ datas = natsorted(datas, key=lambda a: a.title, reverse=isRevert)
else:
datas.sort(key=lambda a: a.addTime, reverse=isRevert)
return datas
@@ -344,8 +372,10 @@ def CheckAction1LoadBack(self, st, books, url):
self.AddDataToDB(v.id)
QtOwner().ShowMsg("已添加{}本到书架, {}本存在已忽略".format(addNum, alreadyNum))
self.lineEdit.setText("")
+ self.isCurRead = False
self.sortIdCombox.setCurrentIndex(0)
self.sortKeyCombox.setCurrentIndex(1)
+ self.Init()
return
# 导入单本Zip
@@ -379,11 +409,12 @@ def CheckAction4(self):
# 批量导入下载目录
def ImportDownloadDirs(self, dirs):
+ self.curSelectCategory = ""
self.AddLocalTaskLoad(LocalData.Type6, dirs, "", self.CheckAction1LoadBack)
return
-
+
def dragEnterEvent(self, event):
- if(event.mimeData().hasUrls()):
+ if (event.mimeData().hasUrls()):
event.acceptProposedAction()
else:
event.ignore()
@@ -392,8 +423,8 @@ def dragMoveEvent(self, evemt):
return
def dropEvent(self, event):
- mimeData = event.mimeData()
- if(mimeData.hasUrls()):
+ mimeData = event.mimeData()
+ if (mimeData.hasUrls()):
urls = mimeData.urls()
QtOwner().ShowLoading()
fileNames = [str(i.toLocalFile()) for i in urls]
diff --git a/src/view/user/login_proxy_widget.py b/src/view/user/login_proxy_widget.py
index 3ebe44c..fde7825 100644
--- a/src/view/user/login_proxy_widget.py
+++ b/src/view/user/login_proxy_widget.py
@@ -6,6 +6,7 @@
from PySide6.QtGui import QDesktopServices
from config import config
+from config.global_config import GlobalConfig
from config.setting import Setting
from interface.ui_login_proxy_widget import Ui_LoginProxyWidget
from qt_owner import QtOwner
@@ -34,6 +35,8 @@ def __init__(self):
self.radioApiGroup.setId(self.radioButton_4, 4)
self.radioApiGroup.setId(self.radioButton_5, 5)
self.radioApiGroup.setId(self.radioButton_6, 6)
+ # self.radioApiGroup.setId(self.radioButton_7, 7)
+ # self.radioApiGroup.setId(self.radioButton_8, 8)
self.radioImgGroup.setId(self.radio_img_1, 1)
self.radioImgGroup.setId(self.radio_img_2, 2)
@@ -41,7 +44,9 @@ def __init__(self):
self.radioImgGroup.setId(self.radio_img_4, 4)
self.radioImgGroup.setId(self.radio_img_5, 5)
self.radioImgGroup.setId(self.radio_img_6, 6)
- config.Address[1] = Setting.SaveCacheAddress.value
+ # self.radioImgGroup.setId(self.radio_img_7, 7)
+ # self.radioImgGroup.setId(self.radio_img_8, 8)
+ # config.Address[1] = Setting.SaveCacheAddress.value
self.LoadSetting()
self.UpdateServer()
@@ -57,15 +62,42 @@ def __init__(self):
self.radio_img_5.setEnabled(True)
self.maxNum = 6
+ self.lastResult = {}
+ self.LoadHistory()
def Init(self):
self.LoadSetting()
+ self.InitImgUrlList()
proxy = urllib.request.getproxies()
if isinstance(proxy, dict) and proxy.get("http"):
self.checkLabel.setVisible(False)
else:
self.checkLabel.setVisible(True)
+ def InitImgUrlList(self):
+ self.imgCombox.clear()
+ self.imgCombox.addItem("")
+ if GlobalConfig.ImageUrl.value not in GlobalConfig.ImageServerList.value:
+ GlobalConfig.ImageUrl.value = ""
+ for index, name in enumerate(GlobalConfig.ImageServerList.value):
+ self.imgCombox.addItem(name)
+ if name == GlobalConfig.ImageUrl.value:
+ self.imgCombox.setCurrentIndex(index+1)
+ return
+
+ def LoadHistory(self):
+ if not Setting.LastProxyResult.value:
+ return
+ try:
+ for k, v in Setting.LastProxyResult.value.items():
+ if hasattr(self, k):
+ getattr(self, k).setText(str(v))
+ except Exception as es:
+ Log.Error(es)
+
+ def SaveHistory(self):
+ Setting.LastProxyResult.SetValue(dict(self.lastResult))
+
def ClickButton(self):
self.SaveSetting()
@@ -85,14 +117,19 @@ def SetEnabled(self, enabled):
self.radioButton_4.setEnabled(enabled)
self.radioButton_5.setEnabled(enabled)
self.radioButton_6.setEnabled(enabled)
+ # self.radioButton_7.setEnabled(enabled)
+ # self.radioButton_8.setEnabled(enabled)
self.radio_img_1.setEnabled(enabled)
self.radio_img_2.setEnabled(enabled)
self.radio_img_3.setEnabled(enabled)
self.radio_img_4.setEnabled(enabled)
self.radio_img_5.setEnabled(enabled)
self.radio_img_6.setEnabled(enabled)
+ # self.radio_img_7.setEnabled(enabled)
+ # self.radio_img_8.setEnabled(enabled)
self.httpsBox.setEnabled(enabled)
self.ipv6Check.setEnabled(enabled)
+ self.imgCombox.setEnabled(enabled)
if not self.isShowProxy5:
self.radio_img_5.setEnabled(False)
@@ -112,11 +149,15 @@ def SpeedTest(self):
self.speedTest = [("", "", False, False, 1)]
i = 2
- adress = config.AddressIpv6[0] if self.ipv6Check.isChecked() else config.Address[0]
- self.speedTest.append((adress, config.ImageServer2, False, False, i))
+
+ adress = GlobalConfig.GetAddress(2)
+ image = GlobalConfig.GetImageAdress(2)
+ self.speedTest.append((adress, image, False, False, i))
i += 1
- adress1 = config.AddressIpv6[1] if self.ipv6Check.isChecked() else config.Address[1]
- self.speedTest.append((adress1, config.ImageServer3, False, False, i))
+
+ adress1 = GlobalConfig.GetAddress(3)
+ image = GlobalConfig.GetImageAdress(3)
+ self.speedTest.append((adress1, image, False, False, i))
i += 1
PreferCDNIP = self.cdn_api_ip.text()
@@ -132,9 +173,21 @@ def SpeedTest(self):
self.speedTest.append(("", "", False, (config.ProxyApiDomain2, config.ProxyImgDomain2), i))
i += 1
+ # adress1 = GlobalConfig.GetAddress(7)
+ # image = GlobalConfig.GetImageServer(7)
+ # self.speedTest.append((adress1, image, False, False, i))
+ # i += 1
+ #
+ # adress1 = GlobalConfig.GetAddress(8)
+ # image = GlobalConfig.GetImageServer(8)
+ # self.speedTest.append((adress1, image, False, False, i))
+ # i += 1
+
self.SetEnabled(False)
self.needBackNum = 0
self.speedPingNum = 0
+
+ self.lastResult.clear()
self.StartSpeedPing()
def StartSpeedPing(self):
@@ -176,7 +229,9 @@ def StartSpeedPing(self):
else:
self.SetSock5Proxy(False)
- Server().UpdateDns(address, imageProxy)
+ # imageAdress = GlobalConfig.GetImageAdress(i)
+ imgUrl = self.imgCombox.currentText()
+ Server().UpdateDns(address, imgUrl, imageProxy)
self.pingBackNumCnt[i] = 0
self.pingBackNumDict[i] = [0, 0, 0]
request1 = deepcopy(request)
@@ -191,7 +246,8 @@ def SpeedTestPingBack(self, raw, v):
i, backNum = v
data = raw["data"]
st = raw["st"]
- label = getattr(self, "label_api_" + str(i))
+ objectName = "label_api_" + str(i)
+ label = getattr(self, objectName)
if float(data) > 0.0:
self.pingBackNumDict[i][backNum] = int(float(data))
label.setText("{}".format(str(int(float(data))) + "ms"))
@@ -211,10 +267,12 @@ def SpeedTestPingBack(self, raw, v):
else:
sumSt = data
if sumCnt >= 1:
- label.setText("{}".format(str(int(float(sumData/sumCnt))) + "ms") )
+ text = "{}".format(str(int(float(sumData/sumCnt))) + "ms")
+ label.setText(text)
else:
- label.setText("{}".format(Str.GetStr(int(sumSt))) )
-
+ text = "{}".format(Str.GetStr(int(sumSt)))
+ label.setText(text)
+ self.lastResult[objectName] = text
self.speedPingNum += 1
self.StartSpeedPing()
return
@@ -234,6 +292,7 @@ def StartSpeedTest(self):
self.UpdateServer()
self.SetEnabled(True)
self.CheckShow5()
+ self.SaveHistory()
return
address, imageProxy, isHttpProxy, isProxyUrl, i = self.speedTest[self.speedIndex]
@@ -267,8 +326,8 @@ def StartSpeedTest(self):
self.SetSock5Proxy(True)
else:
self.SetSock5Proxy(False)
-
- Server().UpdateDns(address, imageProxy)
+ imgUrl = self.imgCombox.currentText()
+ Server().UpdateDns(address, imgUrl, imageProxy)
self.AddHttpTask(lambda x: Server().TestSpeed(request, x), self.SpeedTestBack, i)
return
@@ -279,7 +338,10 @@ def SpeedTestBack(self, raw, i):
data = "{}".format(Str.GetStr(st))
else:
data = "{}".format(data)
- label = getattr(self, "label_img_" + str(i))
+ objectName = "label_img_" + str(i)
+ label = getattr(self, objectName)
+ self.lastResult[objectName] = data
+
label.setText(data)
self.speedIndex += 1
self.StartSpeedTest()
@@ -307,12 +369,15 @@ def LoadSetting(self):
self.httpsBox.setChecked(Setting.IsUseHttps.value)
self.httpLine.setText(Setting.HttpProxy.value)
self.sockEdit.setText(Setting.Sock5Proxy.value)
- button = getattr(self, "radioButton_{}".format(Setting.ProxySelectIndex.value))
- button.setChecked(True)
- button = getattr(self, "proxy_{}".format(int(Setting.IsHttpProxy.value)))
- button.setChecked(True)
- button = getattr(self, "radio_img_{}".format(int(Setting.ProxyImgSelectIndex.value)))
- button.setChecked(True)
+ button = getattr(self, "radioButton_{}".format(Setting.ProxySelectIndex.value), None)
+ if button:
+ button.setChecked(True)
+ button = getattr(self, "proxy_{}".format(int(Setting.IsHttpProxy.value)), None)
+ if button:
+ button.setChecked(True)
+ button = getattr(self, "radio_img_{}".format(int(Setting.ProxyImgSelectIndex.value)), None)
+ if button:
+ button.setChecked(True)
self.cdn_api_ip.setText(Setting.PreferCDNIP.value)
self.cdn_img_ip.setText(Setting.PreferCDNIPImg.value)
@@ -326,35 +391,20 @@ def LoadSetting(self):
self.radio_img_5.setEnabled(True)
def UpdateServer(self):
- if Setting.ProxySelectIndex.value == 1:
- address = ""
- elif Setting.ProxySelectIndex.value == 2:
- address = config.AddressIpv6[0] if Setting.PreIpv6.value > 0 else config.Address[0]
- elif Setting.ProxySelectIndex.value == 3:
- address = config.AddressIpv6[1] if Setting.PreIpv6.value > 0 else config.Address[1]
- elif Setting.ProxySelectIndex.value == 5:
- address = ""
- elif Setting.ProxySelectIndex.value == 6:
- address = ""
- else:
+ address = GlobalConfig.GetAddress(Setting.ProxySelectIndex.value)
+ # imageServer = GlobalConfig.GetImageServer(Setting.ProxyImgSelectIndex.value)
+ imageAdress = GlobalConfig.GetImageAdress(Setting.ProxyImgSelectIndex.value)
+ imageServer = GlobalConfig.ImageUrl.value
+ if Setting.ProxySelectIndex.value == 4:
address = Setting.PreferCDNIP.value
- if Setting.ProxyImgSelectIndex.value == 1:
- imageServer = ""
- elif Setting.ProxyImgSelectIndex.value == 2:
- imageServer = config.ImageServer2
- elif Setting.ProxyImgSelectIndex.value == 3:
- imageServer = config.ImageServer3
- elif Setting.ProxyImgSelectIndex.value == 5:
- imageServer = ""
- elif Setting.ProxyImgSelectIndex.value == 6:
- imageServer = ""
- else:
- imageServer = Setting.PreferCDNIPImg.value
+ if Setting.ProxyImgSelectIndex.value == 4:
+ # imageServer = Setting.PreferCDNIPImg.value
+ imageAdress = Setting.PreferCDNIPImg.value
QtOwner().settingView.SetSock5Proxy()
- Server().UpdateDns(address, imageServer)
- Log.Info("update proxy, apiSetId:{}, imgSetID:{}, image server:{}, address:{}".format(Setting.ProxySelectIndex.value, Setting.ProxyImgSelectIndex.value, Server().imageServer, Server().address))
+ Server().UpdateDns(address, imageServer, imageAdress)
+ Log.Info("update proxy, apiSetId:{}, imgSetID:{}, image server:{}:{}, address:{}".format(Setting.ProxySelectIndex.value, Setting.ProxyImgSelectIndex.value, Server().imageServer, Server().imageAddress, Server().address))
def SaveSetting(self):
Setting.PreferCDNIP.SetValue(self.cdn_api_ip.text())
@@ -366,7 +416,7 @@ def SaveSetting(self):
Setting.ProxyImgSelectIndex.SetValue(self.radioImgGroup.checkedId())
Setting.IsUseHttps.SetValue(int(self.httpsBox.isChecked()))
Setting.PreIpv6.SetValue(int(self.ipv6Check.isChecked()))
-
+ GlobalConfig.SetSetting("ImageUrl", self.imgCombox.currentText())
# QtOwner().settingView.SetSettingV("Proxy/ProxySelectIndex", config.ProxySelectIndex)
# QtOwner().settingView.SetSettingV("Proxy/PreferCDNIP", config.PreferCDNIP)
# QtOwner().settingView.SetSettingV("Proxy/Http", httpProxy)
diff --git a/ui/component/ui_login_proxy_widget.ui b/ui/component/ui_login_proxy_widget.ui
index 398130d..4d81e0c 100644
--- a/ui/component/ui_login_proxy_widget.ui
+++ b/ui/component/ui_login_proxy_widget.ui
@@ -6,13 +6,13 @@
0
0
- 495
- 483
+ 577
+ 473
- 450
+ 550
0
@@ -33,8 +33,8 @@
0
0
- 458
- 483
+ 540
+ 512
@@ -217,6 +217,33 @@
+ -
+
+
-
+
+
+ 图片地址选择:
+
+
+
+ -
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+
+ 40
+ 20
+
+
+
+
+
+
-
@@ -233,21 +260,21 @@
-
-
-
-
+
-
+
- -
-
+
-
+
- Api分流
-
-
- Qt::AlignCenter
+ 分流3
+
+ radioApiGroup
+
-
@@ -260,8 +287,8 @@
- -
-
+
-
+
120
@@ -270,55 +297,72 @@
- -
-
+
-
+
-
+ US反代分流
+
+ radioImgGroup
+
- -
-
-
- 所以分流不可使用时,自动解锁
-
+
-
+
- JP反代分流
+ US反代分流
radioApiGroup
- -
-
+
-
+
-
+ 分流3
+
+ radioImgGroup
+
- -
-
+
-
+
- 分流1
+ CDN地址
-
- true
+
+ Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter
+
+
+
+ -
+
+
+ CDN分流
radioApiGroup
- -
-
+
-
+
- -
-
+
-
+
+
+ CDN地址
+
+
+
+ -
+
120
@@ -327,72 +371,52 @@
- -
-
+
-
+
- -
-
+
-
+
- -
-
+
-
+
- -
-
+
-
+
- CDN地址
+
- -
-
+
-
+
- 分流1
-
-
- true
+ 图片分流
-
- radioImgGroup
-
-
-
- -
-
-
- 分流2
+
+ Qt::AlignCenter
-
- radioImgGroup
-
- -
-
+
-
+
-
+ 延迟
-
-
- -
-
-
- CDN分流
+
+ Qt::AlignCenter
-
- radioImgGroup
-
-
@@ -408,122 +432,125 @@
- -
-
+
-
+
- CDN分流
+ 速度
+
+
+ Qt::AlignCenter
-
- radioApiGroup
-
- -
-
+
-
+
- 分流3
+ 分流1
+
+
+ true
radioApiGroup
- -
-
+
-
+
- 分流3
+ CDN分流
radioImgGroup
- -
-
+
-
+
- CDN地址
-
-
- Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter
+
- -
-
+
-
+
- 延迟
+ Api分流
Qt::AlignCenter
- -
-
+
-
+
- -
-
+
-
+
- 图片分流
+
-
- Qt::AlignCenter
+
+
+ -
+
+
+
- -
-
+
-
+
- 速度
+ 分流1
-
- Qt::AlignCenter
+
+ true
+
+ radioImgGroup
+
- -
-
+
-
+
- -
-
+
-
+
- US反代分流
+
-
- radioApiGroup
-
- -
-
+
-
+
- US反代分流
+ 分流2
radioImgGroup
- -
-
-
-
+
-
+
+
+ 所以分流不可使用时,自动解锁
-
-
- -
-
-
+ JP反代分流
+
+ radioApiGroup
+
@@ -559,6 +586,11 @@
component.scroll_area.smooth_scroll_area.h
1
+
+ WheelComboBox
+ QComboBox
+ component.box.wheel_combo_box.h
+
@@ -588,7 +620,7 @@
-
+
diff --git a/ui/component/ui_navigation.ui b/ui/component/ui_navigation.ui
index 6c3deeb..5e62a9f 100644
--- a/ui/component/ui_navigation.ui
+++ b/ui/component/ui_navigation.ui
@@ -6,8 +6,8 @@
0
0
- 248
- 496
+ 376
+ 772
@@ -141,7 +141,7 @@
-
-
+
@@ -159,7 +159,7 @@
-
-
+
@@ -188,18 +188,37 @@
+ -
+
+
+ Qt::Vertical
+
+
+
+ 20
+ 40
+
+
+
+
-
+
+ Qt::ScrollBarAlwaysOn
+
+
+ Qt::ScrollBarAlwaysOff
+
- true
+ false
0
- -431
- 211
- 792
+ 0
+ 339
+ 800
@@ -236,7 +255,7 @@
150
- 40
+ 0
@@ -277,7 +296,7 @@
150
- 40
+ 0
@@ -321,7 +340,7 @@
150
- 40
+ 0
@@ -376,7 +395,7 @@
150
- 40
+ 0
@@ -426,7 +445,7 @@
150
- 40
+ 0
@@ -473,7 +492,7 @@
150
- 40
+ 0
@@ -520,7 +539,7 @@
150
- 40
+ 0
@@ -561,7 +580,7 @@
150
- 40
+ 0
@@ -602,7 +621,7 @@
150
- 40
+ 0
@@ -643,7 +662,7 @@
150
- 40
+ 0
@@ -684,7 +703,7 @@
150
- 40
+ 0
@@ -725,7 +744,7 @@
150
- 40
+ 0
@@ -780,7 +799,7 @@
150
- 40
+ 0
@@ -820,8 +839,8 @@
- 0
- 40
+ 150
+ 0
@@ -851,7 +870,6 @@
-
-
@@ -863,7 +881,7 @@
150
- 40
+ 0
@@ -904,7 +922,7 @@
150
- 40
+ 0
@@ -934,19 +952,6 @@
- -
-
-
- Qt::Vertical
-
-
-
- 20
- 40
-
-
-
-
diff --git a/ui/component/ui_read_tool.ui b/ui/component/ui_read_tool.ui
index 04a50d4..08f5a1e 100644
--- a/ui/component/ui_read_tool.ui
+++ b/ui/component/ui_read_tool.ui
@@ -41,7 +41,7 @@
0
- 0
+ -27
310
825
@@ -531,7 +531,7 @@
color: #ee2a24
- 自动滚动/翻页
+ 滚动/翻页
Qt::AlignCenter
@@ -549,7 +549,7 @@
- 滚动速度(像素):
+ 滚动速度:
diff --git a/ui/ui_download.ui b/ui/ui_download.ui
index 7f71b90..91d79a9 100644
--- a/ui/ui_download.ui
+++ b/ui/ui_download.ui
@@ -6,7 +6,7 @@
0
0
- 707
+ 820
361
@@ -16,7 +16,66 @@
-
-
-
+
-
+
+
+
+ id
+
+
+
+
+ 时间
+
+
+
+
+ 标题
+
+
+
+
+ 下载进度
+
+
+
+
+ 下载章节
+
+
+
+
+ 下载速度
+
+
+
+
+ 下载状态
+
+
+
+
+ 转换进度
+
+
+
+
+ 转换章节
+
+
+
+
+ 转换耗时
+
+
+
+
+ 转换状态
+
+
+
+
+ -
-
@@ -88,65 +147,6 @@
- -
-
-
-
- id
-
-
-
-
- 时间
-
-
-
-
- 标题
-
-
-
-
- 下载进度
-
-
-
-
- 下载章节
-
-
-
-
- 下载速度
-
-
-
-
- 下载状态
-
-
-
-
- 转换进度
-
-
-
-
- 转换章节
-
-
-
-
- 转换耗时
-
-
-
-
- 转换状态
-
-
-
-
diff --git a/ui/ui_local.ui b/ui/ui_local.ui
index 5d07ddf..1f28143 100644
--- a/ui/ui_local.ui
+++ b/ui/ui_local.ui
@@ -6,8 +6,8 @@
0
0
- 628
- 334
+ 626
+ 327
diff --git a/ui/ui_local_all.ui b/ui/ui_local_all.ui
index ad2923e..51e6052 100644
--- a/ui/ui_local_all.ui
+++ b/ui/ui_local_all.ui
@@ -6,8 +6,8 @@
0
0
- 543
- 300
+ 541
+ 293
diff --git a/ui/ui_local_favorite.ui b/ui/ui_local_favorite.ui
new file mode 100644
index 0000000..f9960a3
--- /dev/null
+++ b/ui/ui_local_favorite.ui
@@ -0,0 +1,219 @@
+
+
+ LocalFavorite
+
+
+
+ 0
+ 0
+ 628
+ 334
+
+
+
+ 收藏
+
+
+ -
+
+
-
+
+
+
+
+
+
+
+
+ -
+
+
-
+
+
-
+
+
+
+
+
+
+ -
+
+
+ true
+
+
+
+ 100
+ 0
+
+
+
-
+
+ 收藏时间
+
+
+
+
+ -
+
+
+ true
+
+
-
+
+ 降序
+
+
+ -
+
+ 升序
+
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+
+ 40
+ 20
+
+
+
+
+ -
+
+
+ Qt::Vertical
+
+
+
+ -
+
+
+
+ 0
+ 30
+
+
+
+ 收藏数:
+
+
+
+ -
+
+
+ 页
+
+
+
+ -
+
+
+ Qt::Vertical
+
+
+
+ -
+
+
+ Qt::Vertical
+
+
+
+ -
+
+
+
+ 50
+ 30
+
+
+
+ 1
+
+
+ 1
+
+
+
+ -
+
+
+ Qt::Vertical
+
+
+
+ -
+
+
+
+ 0
+ 30
+
+
+
+ 跳转
+
+
+ Return
+
+
+
+
+
+
+
+ -
+
+
+
-
+
+
+ 搜索:
+
+
+
+ -
+
+
+
+
+
+
+
+
+
+ ComicListWidget
+ QListWidget
+ component.list.comic_list_widget.h
+
+
+
+
+
+ jumpButton
+ clicked()
+ LocalFavorite
+ JumpPage()
+
+
+ 439
+ 280
+
+
+ 361
+ 291
+
+
+
+
+
+ JumpPage()
+ RefreshDataFocus()
+
+
diff --git a/ui/ui_setting_new.ui b/ui/ui_setting_new.ui
index 40be88d..04d5566 100644
--- a/ui/ui_setting_new.ui
+++ b/ui/ui_setting_new.ui
@@ -6,7 +6,7 @@
0
0
- 880
+ 946
789
@@ -95,9 +95,9 @@
0
- -541
- 661
- 2891
+ 0
+ 727
+ 3043
@@ -824,6 +824,109 @@
+ -
+
+
+
+ 12
+ true
+
+
+
+ 标题显示行数
+
+
+
+ -
+
+
-
+
+
-
+
+ 不显示
+
+
+ -
+
+ 1行
+
+
+ -
+
+ 2行
+
+
+ -
+
+ 3行
+
+
+ -
+
+ 全部
+
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+
+ 40
+ 20
+
+
+
+
+
+
+ -
+
+
+
+ 12
+ true
+
+
+
+ 分类显示
+
+
+
+ -
+
+
-
+
+
-
+
+ 显示
+
+
+ -
+
+ 不显示
+
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+
+ 40
+ 20
+
+
+
+
+
+
@@ -882,7 +985,7 @@
-
- Debug
+ Debug(该设置内含敏感数据,log文件请勿分享)
logGroup
@@ -2278,6 +2381,13 @@
+ -
+
+
+ 设置日志目录
+
+
+
-
@@ -2493,6 +2603,59 @@
+ -
+
+
-
+
+
+
+ 80
+ 0
+
+
+
+ 日志
+
+
+
+ -
+
+
+
+ 150
+ 0
+
+
+
+
+
+
+
+ -
+
+
+ 打开目录
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+
+ 40
+ 20
+
+
+
+
+
+
+ -
+
+
@@ -2530,12 +2693,12 @@
+
-
-
-
+
+