diff --git a/README.md b/README.md
index 946fff171e1c8e9be3937091d855c809b0c029cb..54e5b9ef2b66021b2e3194b96dbfd8f066a2c639 100644
--- a/README.md
+++ b/README.md
@@ -124,6 +124,19 @@ A collection of commonly used widgets.
+
+
+ Tooltip
+ |
+
+ Tooltip
+ |
+
+
+
+
+ |
+
Flow Layout
@@ -147,7 +160,7 @@ A collection of commonly used widgets.
|
-
+
|
diff --git a/screenshot/ToolTip.gif b/screenshot/ToolTip.gif
new file mode 100644
index 0000000000000000000000000000000000000000..c35fb0b5d2502b768ecbb4073670ba34ae352255
Binary files /dev/null and b/screenshot/ToolTip.gif differ
diff --git a/widgets/tool_tip/demo.py b/widgets/tool_tip/demo.py
new file mode 100644
index 0000000000000000000000000000000000000000..7f80825f42bf5c16295f3072cf71bfd1ed343dad
--- /dev/null
+++ b/widgets/tool_tip/demo.py
@@ -0,0 +1,69 @@
+# coding:utf-8
+import sys
+from PyQt5.QtCore import QEvent, QPoint
+from PyQt5.QtWidgets import QApplication, QWidget, QPushButton, QHBoxLayout
+
+from tool_tip import ToolTip
+
+
+class Demo(QWidget):
+
+ def __init__(self):
+ super().__init__()
+ self.hBox = QHBoxLayout(self)
+ self.button1 = QPushButton('キラキラ', self)
+ self.button2 = QPushButton('食べた愛', self)
+ self._toolTip = ToolTip(parent=self)
+ # self._tooltip.setDarkTheme(True)
+
+ self.button1.setToolTip('aiko - キラキラ ✨')
+ self.button2.setToolTip('aiko - 食べた愛 🥰')
+ self.button1.setToolTipDuration(1000)
+ self.button2.setToolTipDuration(5000)
+
+ self.button1.installEventFilter(self)
+ self.button2.installEventFilter(self)
+
+ self.hBox.setContentsMargins(30, 30, 30, 30)
+ self.hBox.setSpacing(20)
+ self.hBox.addWidget(self.button1)
+ self.hBox.addWidget(self.button2)
+
+ self.resize(600, 300)
+ self._toolTip.hide()
+
+ with open('resource/demo.qss', encoding='utf-8') as f:
+ self.setStyleSheet(f.read())
+
+ def eventFilter(self, obj, e: QEvent):
+ if obj is self:
+ return super().eventFilter(obj, e)
+
+ tip = self._toolTip
+ if e.type() == QEvent.Enter:
+ tip.setText(obj.toolTip())
+ tip.setDuration(obj.toolTipDuration())
+
+ pos = obj.mapTo(self, QPoint(0, 0))
+ x = pos.x() + obj.width()//2 - tip.width()//2
+ y = pos.y() - 5 - tip.height()
+
+ # adjust postion to prevent tooltips from appearing outside the window
+ x = min(max(5, x), self.width() - tip.width() - 5)
+ y = min(max(5, y), self.height() - tip.height() - 5)
+
+ tip.move(x, y)
+ tip.show()
+ elif e.type() == QEvent.Leave:
+ tip.hide()
+ elif e.type() == QEvent.ToolTip:
+ return True
+
+ return super().eventFilter(obj, e)
+
+
+if __name__ == '__main__':
+ app = QApplication(sys.argv)
+ w = Demo()
+ w.show()
+ app.exec_()
diff --git a/widgets/tool_tip/resource/demo.qss b/widgets/tool_tip/resource/demo.qss
new file mode 100644
index 0000000000000000000000000000000000000000..b21a8959254bac942d1ff652f55e05eca91cc3e9
--- /dev/null
+++ b/widgets/tool_tip/resource/demo.qss
@@ -0,0 +1,25 @@
+QWidget{
+ background-color: white;
+}
+
+QPushButton {
+ background-color: rgb(204, 204, 204);
+ padding: 10px 64px 10px 64px;
+ font: 19px 'Microsoft YaHei';
+ border: transparent;
+ border-radius: 4px;
+ /* height: 40px; */
+}
+
+QPushButton:pressed:hover {
+ background-color: rgb(153, 153, 153);
+}
+
+QPushButton:hover {
+ background-color: rgb(230, 230, 230);
+}
+
+QPushButton:disabled {
+ background-color: rgb(204, 204, 204);
+ color: rgb(122, 122, 122);
+}
\ No newline at end of file
diff --git a/widgets/tool_tip/resource/tooltip.qss b/widgets/tool_tip/resource/tooltip.qss
new file mode 100644
index 0000000000000000000000000000000000000000..c86567b90f47b8bfe9ec0584d6e8649c68eb135f
--- /dev/null
+++ b/widgets/tool_tip/resource/tooltip.qss
@@ -0,0 +1,24 @@
+ToolTip[dark="false"] {
+ border: 1px solid rgba(0, 0, 0, 0.06);
+ border-radius: 5px;
+ background-color: rgb(243, 243, 243);
+}
+
+ToolTip[dark="true"] {
+ border: 1px solid rgb(28, 28, 28);
+ border-radius: 5px;
+ background-color: rgb(43, 43, 43);
+}
+
+QLabel {
+ background-color: transparent;
+ font: 15px 'Segoe UI', 'Microsoft YaHei';
+}
+
+QLabel[dark="false"] {
+ color: black;
+}
+
+QLabel[dark="true"] {
+ color: white;
+}
\ No newline at end of file
diff --git a/widgets/tool_tip/tool_tip.py b/widgets/tool_tip/tool_tip.py
new file mode 100644
index 0000000000000000000000000000000000000000..20aa539c30ffa4d38a6503ec4d53056a866d8536
--- /dev/null
+++ b/widgets/tool_tip/tool_tip.py
@@ -0,0 +1,79 @@
+# coding:utf-8
+from PyQt5.QtCore import QFile, QPropertyAnimation, QTimer, Qt
+from PyQt5.QtGui import QColor
+from PyQt5.QtWidgets import (QApplication, QFrame, QGraphicsDropShadowEffect,
+ QHBoxLayout, QLabel)
+
+
+class ToolTip(QFrame):
+
+ def __init__(self, text='', parent=None):
+ super().__init__(parent=parent)
+ self.__text = text
+ self.__duration = 1000
+ self.timer = QTimer(self)
+ self.hBox = QHBoxLayout(self)
+ self.label = QLabel(text, self)
+ self.ani = QPropertyAnimation(self, b'windowOpacity', self)
+
+ # set layout
+ self.hBox.addWidget(self.label)
+ self.hBox.setContentsMargins(10, 7, 10, 7)
+
+ # add shadow
+ self.shadowEffect = QGraphicsDropShadowEffect(self)
+ self.shadowEffect.setBlurRadius(32)
+ self.shadowEffect.setColor(QColor(0, 0, 0, 60))
+ self.shadowEffect.setOffset(0, 5)
+ self.setGraphicsEffect(self.shadowEffect)
+
+ self.timer.setSingleShot(True)
+ self.timer.timeout.connect(self.hide)
+
+ # set style
+ self.setAttribute(Qt.WA_StyledBackground)
+ self.setDarkTheme(False)
+ self.__setQss()
+
+ def text(self):
+ return self.__text
+
+ def setText(self, text: str):
+ """ set text on tooltip """
+ self.__text = text
+ self.label.setText(text)
+ self.label.adjustSize()
+ self.adjustSize()
+
+ def duration(self):
+ return self.__duration
+
+ def setDuration(self, duration: int):
+ """ set tooltip duration in milliseconds """
+ self.__duration = abs(duration)
+
+ def __setQss(self):
+ """ set style sheet """
+ f = QFile("resource/tooltip.qss")
+ f.open(QFile.ReadOnly)
+ self.setStyleSheet(str(f.readAll(), encoding='utf-8'))
+ f.close()
+
+ self.label.adjustSize()
+ self.adjustSize()
+
+ def setDarkTheme(self, dark=False):
+ """ set dark theme """
+ dark = 'true' if dark else 'false'
+ self.setProperty('dark', dark)
+ self.label.setProperty('dark', dark)
+ self.setStyle(QApplication.style())
+
+ def showEvent(self, e):
+ self.timer.stop()
+ self.timer.start(self.__duration)
+ super().showEvent(e)
+
+ def hideEvent(self, e):
+ self.timer.stop()
+ super().hideEvent(e)
\ No newline at end of file