-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathtutorialBubble.py
153 lines (133 loc) · 5.65 KB
/
tutorialBubble.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
from PySide6.QtWidgets import QDialog, QLabel, QMessageBox, QVBoxLayout, QWidget, QHBoxLayout, QPushButton, QCheckBox
from PySide6.QtCore import Qt
from PySide6.QtGui import QPainterPath, QGuiApplication
import configparser
import os
class TutorialBubble(QMessageBox):
tutorialIniFile = "reimage.ini"
def __init__(self,
text: str,
parent: QWidget = None,
relativeToParent: tuple = None,
key: str = None):
"""
Instantiate the bubble dialog with some text.
Parameters
----------
text : str
The bubble dialog's text.
parent : QWidget, optional
Parent widget. Defaults to None.
Use this to help center the widget, or if it should be placed
relative to it using relativeToParent.
relativeToParent : tuple, optional
(x, y) coordinates with respect to the parent widget. Defaults to None.
key : str, optional
Key to identify the type of bubble dialog.
Used to check whether to show it depending on whether the user
has previously selected to hide further tutorial bubbles.
Defaults to None, which will always show it.
"""
self.key = key
self.parent = parent
super().__init__(parent=parent)
# QMessageBox implementation
self.setText(text)
self.setInformativeText(
"<i>github.com/icyveins7/reimage</i>"
)
# Set frameless
self.setWindowFlag(Qt.WindowType.FramelessWindowHint, True)
# Set attributes for rounded corners
# self.setAttribute(Qt.WidgetAttribute.WA_StyledBackground, True)
# self.setAttribute(Qt.WidgetAttribute.WA_TranslucentBackground, True)
# self.setAttribute(Qt.WidgetAttribute.WA_NoSystemBackground, True)
# Set stylesheet for rounded corners
# self.setStyleSheet(
# """
# QMessageBox {
# border-radius: 10px;
# border: 2px solid rgb(0,0,0);
# background-color: rgba(255, 255, 255, 255);
# }
# QMessageBox QLabel {
# color: #000000;
# }
# QMessageBox QPushButton#Don't Show Again {
# background-color: blue;
# color: white;
# }
# """
# )
# If key is present we display an additional checkbox
shouldShow = True
if key is not None:
# Try to open the ini file and see the state
try:
cfg = configparser.ConfigParser()
cfg.read(TutorialBubble.tutorialIniFile)
shouldShow = cfg['tutorials'].getboolean(self.key)
print("ini file: {}".format(shouldShow))
except Exception as e:
print("Error reading ini file: {}".format(e))
shouldShow = True
if shouldShow:
self.rejectBtn = self.addButton(
"Don't Show Again", QMessageBox.ButtonRole.RejectRole)
# Must do this for the custom button, or else reject() doesn't get called
self.rejectBtn.clicked.connect(self.reject)
self.addButton(QMessageBox.StandardButtons.Ok)
if relativeToParent is None:
# Move to center of screen
self.centerPos()
else:
self.moveRelativeToParent(relativeToParent)
# You must show first, before the .width()/.height() is properly evaluated
# self.setModal(True) # Doing this makes it flicker back and forth, just set parent and it should work
if shouldShow:
self.show()
# This seems like a decent way to get it working...
# Taken from https://forum.qt.io/topic/61117/setting-border-radius-does-not-clip-the-background/3
self.painterPath = QPainterPath()
self.painterPath.addRoundedRect(
0, 0, self.width(), self.height(), 10, 10)
# TODO: handle all 4 edges?
self.setMask(self.painterPath.toFillPolygon().toPolygon())
def centerPos(self):
"""Centre in the middle of the screen, not the parent widget."""
# Taken from https://stackoverflow.com/questions/12432740/pyqt4-what-is-the-best-way-to-center-dialog-windows
# Note that QGuiApplication is used now in PySide6
# This works the best out of all the googled methods!
qr = self.frameGeometry()
cp = QGuiApplication.primaryScreen().availableGeometry().center()
qr.moveCenter(cp)
self.move(qr.topLeft())
def moveRelativeToParent(self, pixelsRelativeToParent):
"""
Move relative to top left corner of parent widget,
accounting for current size of the bubble?
"""
self.move(
self.parent.x()-self.frameGeometry().width() +
pixelsRelativeToParent[0],
self.parent.y()-self.frameGeometry().height() +
pixelsRelativeToParent[1]
)
# Overload reject()
def reject(self):
print("Custom TutorialBubble.reject()")
cfg = configparser.ConfigParser()
if not os.path.exists(self.tutorialIniFile):
print("No .ini file found. Creating one...")
cfg['tutorials'] = {
self.key: False
}
with open(self.tutorialIniFile, "w") as f:
cfg.write(f)
else:
cfg.read(self.tutorialIniFile)
# TODO: doesn't like me setting bools
cfg['tutorials'][self.key] = 'False'
with open(self.tutorialIniFile, "w") as f:
cfg.write(f)
super().reject()