src/eric7/QScintilla/EditorButtonsWidget.py

branch
eric7
changeset 9221
bf71ee032bb4
parent 9209
b99e7fd55fd3
child 9413
80c06d472826
equal deleted inserted replaced
9220:e9e7eca7efee 9221:bf71ee032bb4
10 10
11 import contextlib 11 import contextlib
12 12
13 from PyQt6.QtCore import pyqtSlot, Qt 13 from PyQt6.QtCore import pyqtSlot, Qt
14 from PyQt6.QtWidgets import ( 14 from PyQt6.QtWidgets import (
15 QWidget, QVBoxLayout, QToolButton, QFrame, QMenu, QSizePolicy, QScrollArea 15 QWidget,
16 QVBoxLayout,
17 QToolButton,
18 QFrame,
19 QMenu,
20 QSizePolicy,
21 QScrollArea,
16 ) 22 )
17 23
18 import UI.PixmapCache 24 import UI.PixmapCache
19 import Preferences 25 import Preferences
20 26
24 class EditorButtonsWidget(QWidget): 30 class EditorButtonsWidget(QWidget):
25 """ 31 """
26 Class implementing a widget containing various buttons for accessing 32 Class implementing a widget containing various buttons for accessing
27 editor actions. 33 editor actions.
28 """ 34 """
35
29 def __init__(self, editor, parent=None): 36 def __init__(self, editor, parent=None):
30 """ 37 """
31 Constructor 38 Constructor
32 39
33 @param editor reference to the editor 40 @param editor reference to the editor
34 @type Editor 41 @type Editor
35 @param parent reference to the parent widget 42 @param parent reference to the parent widget
36 @type QWidget 43 @type QWidget
37 """ 44 """
38 super().__init__(parent) 45 super().__init__(parent)
39 46
40 margin = 2 47 margin = 2
41 spacing = 3 48 spacing = 3
42 49
43 self.__buttonsWidget = QWidget(self) 50 self.__buttonsWidget = QWidget(self)
44 51
45 self.__layout = QVBoxLayout(self.__buttonsWidget) 52 self.__layout = QVBoxLayout(self.__buttonsWidget)
46 self.__layout.setContentsMargins(0, 0, 0, 0) 53 self.__layout.setContentsMargins(0, 0, 0, 0)
47 self.__layout.setSpacing(spacing) 54 self.__layout.setSpacing(spacing)
48 55
49 self.__provider = None 56 self.__provider = None
50 57
51 self.__editor = editor 58 self.__editor = editor
52 self.__editor.languageChanged.connect(self.__updateButtonStates) 59 self.__editor.languageChanged.connect(self.__updateButtonStates)
53 self.__editor.editorSaved.connect(self.__updateButtonStates) 60 self.__editor.editorSaved.connect(self.__updateButtonStates)
54 self.__editor.editorRenamed.connect(self.__updateButtonStates) 61 self.__editor.editorRenamed.connect(self.__updateButtonStates)
55 self.__editor.selectionChanged.connect(self.__editorSelectionChanged) 62 self.__editor.selectionChanged.connect(self.__editorSelectionChanged)
56 self.__editor.settingsRead.connect(self.__editorSettingsRead) 63 self.__editor.settingsRead.connect(self.__editorSettingsRead)
57 64
58 self.__createButtons() 65 self.__createButtons()
59 66
60 self.__layout.addStretch() 67 self.__layout.addStretch()
61 68
62 self.__outerLayout = QVBoxLayout(self) 69 self.__outerLayout = QVBoxLayout(self)
63 self.__outerLayout.setContentsMargins(margin, margin, margin, margin) 70 self.__outerLayout.setContentsMargins(margin, margin, margin, margin)
64 self.__outerLayout.setSpacing(spacing) 71 self.__outerLayout.setSpacing(spacing)
65 self.__outerLayout.setAlignment(Qt.AlignmentFlag.AlignHCenter) 72 self.__outerLayout.setAlignment(Qt.AlignmentFlag.AlignHCenter)
66 73
67 self.__upButton = QToolButton(self) 74 self.__upButton = QToolButton(self)
68 self.__upButton.setArrowType(Qt.ArrowType.UpArrow) 75 self.__upButton.setArrowType(Qt.ArrowType.UpArrow)
69 self.__upButton.setSizePolicy( 76 self.__upButton.setSizePolicy(
70 QSizePolicy.Policy.MinimumExpanding, QSizePolicy.Policy.Minimum) 77 QSizePolicy.Policy.MinimumExpanding, QSizePolicy.Policy.Minimum
78 )
71 self.__upButton.setAutoRepeat(True) 79 self.__upButton.setAutoRepeat(True)
72 80
73 self.__scroller = QScrollArea(self) 81 self.__scroller = QScrollArea(self)
74 self.__scroller.setWidget(self.__buttonsWidget) 82 self.__scroller.setWidget(self.__buttonsWidget)
75 self.__scroller.setSizePolicy( 83 self.__scroller.setSizePolicy(
76 QSizePolicy.Policy.Minimum, QSizePolicy.Policy.Expanding) 84 QSizePolicy.Policy.Minimum, QSizePolicy.Policy.Expanding
85 )
77 self.__scroller.setFrameShape(QFrame.Shape.NoFrame) 86 self.__scroller.setFrameShape(QFrame.Shape.NoFrame)
78 self.__scroller.setVerticalScrollBarPolicy( 87 self.__scroller.setVerticalScrollBarPolicy(
79 Qt.ScrollBarPolicy.ScrollBarAlwaysOff) 88 Qt.ScrollBarPolicy.ScrollBarAlwaysOff
89 )
80 self.__scroller.setHorizontalScrollBarPolicy( 90 self.__scroller.setHorizontalScrollBarPolicy(
81 Qt.ScrollBarPolicy.ScrollBarAlwaysOff) 91 Qt.ScrollBarPolicy.ScrollBarAlwaysOff
92 )
82 self.__scroller.setWidgetResizable(False) 93 self.__scroller.setWidgetResizable(False)
83 94
84 self.__downButton = QToolButton(self) 95 self.__downButton = QToolButton(self)
85 self.__downButton.setArrowType(Qt.ArrowType.DownArrow) 96 self.__downButton.setArrowType(Qt.ArrowType.DownArrow)
86 self.__downButton.setSizePolicy( 97 self.__downButton.setSizePolicy(
87 QSizePolicy.Policy.MinimumExpanding, QSizePolicy.Policy.Minimum) 98 QSizePolicy.Policy.MinimumExpanding, QSizePolicy.Policy.Minimum
99 )
88 self.__downButton.setAutoRepeat(True) 100 self.__downButton.setAutoRepeat(True)
89 101
90 self.__outerLayout.addWidget(self.__upButton) 102 self.__outerLayout.addWidget(self.__upButton)
91 self.__outerLayout.addWidget(self.__scroller) 103 self.__outerLayout.addWidget(self.__scroller)
92 self.__outerLayout.addWidget(self.__downButton) 104 self.__outerLayout.addWidget(self.__downButton)
93 105
94 self.__upButton.clicked.connect(self.__slideUp) 106 self.__upButton.clicked.connect(self.__slideUp)
95 self.__downButton.clicked.connect(self.__slideDown) 107 self.__downButton.clicked.connect(self.__slideDown)
96 108
97 self.setMaximumWidth( 109 self.setMaximumWidth(self.__buttons["bold"].sizeHint().width() + 2 * margin)
98 self.__buttons["bold"].sizeHint().width() + 2 * margin) 110
99
100 self.__updateButtonStates() 111 self.__updateButtonStates()
101 112
102 ####################################################################### 113 #######################################################################
103 ## Methods below implement some event handlers 114 ## Methods below implement some event handlers
104 ####################################################################### 115 #######################################################################
105 116
106 def show(self): 117 def show(self):
107 """ 118 """
108 Public slot to show the widget. 119 Public slot to show the widget.
109 """ 120 """
110 super().show() 121 super().show()
111 self.__enableScrollerButtons() 122 self.__enableScrollerButtons()
112 123
113 def resizeEvent(self, evt): 124 def resizeEvent(self, evt):
114 """ 125 """
115 Protected method to handle resize events. 126 Protected method to handle resize events.
116 127
117 @param evt reference to the resize event (QResizeEvent) 128 @param evt reference to the resize event (QResizeEvent)
118 """ 129 """
119 self.__enableScrollerButtons() 130 self.__enableScrollerButtons()
120 super().resizeEvent(evt) 131 super().resizeEvent(evt)
121 132
122 ####################################################################### 133 #######################################################################
123 ## Methods below implement scroller related functions 134 ## Methods below implement scroller related functions
124 ####################################################################### 135 #######################################################################
125 136
126 def __enableScrollerButtons(self): 137 def __enableScrollerButtons(self):
127 """ 138 """
128 Private method to set the enabled state of the scroll buttons. 139 Private method to set the enabled state of the scroll buttons.
129 """ 140 """
130 scrollBar = self.__scroller.verticalScrollBar() 141 scrollBar = self.__scroller.verticalScrollBar()
131 self.__upButton.setEnabled(scrollBar.value() > 0) 142 self.__upButton.setEnabled(scrollBar.value() > 0)
132 self.__downButton.setEnabled(scrollBar.value() < scrollBar.maximum()) 143 self.__downButton.setEnabled(scrollBar.value() < scrollBar.maximum())
133 144
134 def __slideUp(self): 145 def __slideUp(self):
135 """ 146 """
136 Private slot to move the widget upwards, i.e. show contents to the 147 Private slot to move the widget upwards, i.e. show contents to the
137 bottom. 148 bottom.
138 """ 149 """
139 self.__slide(True) 150 self.__slide(True)
140 151
141 def __slideDown(self): 152 def __slideDown(self):
142 """ 153 """
143 Private slot to move the widget downwards, i.e. show contents to 154 Private slot to move the widget downwards, i.e. show contents to
144 the top. 155 the top.
145 """ 156 """
146 self.__slide(False) 157 self.__slide(False)
147 158
148 def __slide(self, up): 159 def __slide(self, up):
149 """ 160 """
150 Private method to move the sliding widget. 161 Private method to move the sliding widget.
151 162
152 @param up flag indicating to move upwards (boolean) 163 @param up flag indicating to move upwards (boolean)
153 """ 164 """
154 scrollBar = self.__scroller.verticalScrollBar() 165 scrollBar = self.__scroller.verticalScrollBar()
155 stepSize = scrollBar.singleStep() 166 stepSize = scrollBar.singleStep()
156 if up: 167 if up:
160 newValue = 0 171 newValue = 0
161 elif newValue > scrollBar.maximum(): 172 elif newValue > scrollBar.maximum():
162 newValue = scrollBar.maximum() 173 newValue = scrollBar.maximum()
163 scrollBar.setValue(newValue) 174 scrollBar.setValue(newValue)
164 self.__enableScrollerButtons() 175 self.__enableScrollerButtons()
165 176
166 ####################################################################### 177 #######################################################################
167 ## Methods below implement the format button functions 178 ## Methods below implement the format button functions
168 ####################################################################### 179 #######################################################################
169 180
170 def __createButtons(self): 181 def __createButtons(self):
171 """ 182 """
172 Private slot to create the various tool buttons. 183 Private slot to create the various tool buttons.
173 """ 184 """
174 self.__buttons = {} 185 self.__buttons = {}
175 self.__separators = [] 186 self.__separators = []
176 self.__headerMenu = QMenu() 187 self.__headerMenu = QMenu()
177 188
178 self.__addButton("bold", "formatTextBold", 189 self.__addButton("bold", "formatTextBold", self.tr("Bold"))
179 self.tr("Bold")) 190 self.__addButton("italic", "formatTextItalic", self.tr("Italic"))
180 self.__addButton("italic", "formatTextItalic", 191 self.__addButton(
181 self.tr("Italic")) 192 "strikethrough", "formatTextStrikethrough", self.tr("Strike Through")
182 self.__addButton("strikethrough", "formatTextStrikethrough", 193 )
183 self.tr("Strike Through"))
184 self.__addSeparator() 194 self.__addSeparator()
185 self.__addButton("header1", "formatTextHeader1", 195 self.__addButton("header1", "formatTextHeader1", self.tr("Header 1"))
186 self.tr("Header 1")) 196 self.__addButton("header2", "formatTextHeader2", self.tr("Header 2"))
187 self.__addButton("header2", "formatTextHeader2", 197 self.__addButton("header3", "formatTextHeader3", self.tr("Header 3"))
188 self.tr("Header 2")) 198 button = self.__addButton("header", "formatTextHeader", self.tr("Header"))
189 self.__addButton("header3", "formatTextHeader3",
190 self.tr("Header 3"))
191 button = self.__addButton("header", "formatTextHeader",
192 self.tr("Header"))
193 button.setPopupMode(QToolButton.ToolButtonPopupMode.InstantPopup) 199 button.setPopupMode(QToolButton.ToolButtonPopupMode.InstantPopup)
194 button.setMenu(self.__headerMenu) 200 button.setMenu(self.__headerMenu)
195 self.__addSeparator() 201 self.__addSeparator()
196 self.__addButton("code", "formatTextInlineCode", 202 self.__addButton("code", "formatTextInlineCode", self.tr("Inline Code"))
197 self.tr("Inline Code")) 203 self.__addButton("codeBlock", "formatTextCodeBlock", self.tr("Code Block"))
198 self.__addButton("codeBlock", "formatTextCodeBlock", 204 self.__addButton("quote", "formatTextQuote", self.tr("Quote"))
199 self.tr("Code Block"))
200 self.__addButton("quote", "formatTextQuote",
201 self.tr("Quote"))
202 self.__addSeparator() 205 self.__addSeparator()
203 self.__addButton("hyperlink", "formatTextHyperlink", 206 self.__addButton("hyperlink", "formatTextHyperlink", self.tr("Add Hyperlink"))
204 self.tr("Add Hyperlink")) 207 self.__addButton(
205 self.__addButton("line", "formatTextHorizontalLine", 208 "line", "formatTextHorizontalLine", self.tr("Add Horizontal Line")
206 self.tr("Add Horizontal Line")) 209 )
207 self.__addButton("image", "formatTextImage", 210 self.__addButton("image", "formatTextImage", self.tr("Add Image"))
208 self.tr("Add Image"))
209 self.__addSeparator() 211 self.__addSeparator()
210 self.__addButton("bulletedList", "formatTextBulletedList", 212 self.__addButton(
211 self.tr("Add Bulleted List")) 213 "bulletedList", "formatTextBulletedList", self.tr("Add Bulleted List")
212 self.__addButton("numberedList", "formatTextNumberedList", 214 )
213 self.tr("Add Numbered List")) 215 self.__addButton(
214 216 "numberedList", "formatTextNumberedList", self.tr("Add Numbered List")
217 )
218
215 self.__headerMenu.triggered.connect(self.__headerMenuTriggered) 219 self.__headerMenu.triggered.connect(self.__headerMenuTriggered)
216 220
217 def __addButton(self, formatName, iconName, toolTip): 221 def __addButton(self, formatName, iconName, toolTip):
218 """ 222 """
219 Private method to add a format button. 223 Private method to add a format button.
220 224
221 @param formatName unique name of the format 225 @param formatName unique name of the format
222 @type str 226 @type str
223 @param iconName name of the icon for the button 227 @param iconName name of the icon for the button
224 @type str 228 @type str
225 @param toolTip text for the tool tip 229 @param toolTip text for the tool tip
231 button.setIcon(UI.PixmapCache.getIcon(iconName)) 235 button.setIcon(UI.PixmapCache.getIcon(iconName))
232 button.setToolTip(toolTip) 236 button.setToolTip(toolTip)
233 button.clicked.connect(lambda: self.__formatClicked(formatName)) 237 button.clicked.connect(lambda: self.__formatClicked(formatName))
234 self.__layout.addWidget(button) 238 self.__layout.addWidget(button)
235 self.__buttons[formatName] = button 239 self.__buttons[formatName] = button
236 240
237 return button 241 return button
238 242
239 def __addSeparator(self): 243 def __addSeparator(self):
240 """ 244 """
241 Private method to add a separator line. 245 Private method to add a separator line.
242 """ 246 """
243 line = QFrame(self.__buttonsWidget) 247 line = QFrame(self.__buttonsWidget)
245 if isinstance(self.__layout, QVBoxLayout): 249 if isinstance(self.__layout, QVBoxLayout):
246 line.setFrameShape(QFrame.Shape.HLine) 250 line.setFrameShape(QFrame.Shape.HLine)
247 else: 251 else:
248 line.setFrameShape(QFrame.Shape.VLine) 252 line.setFrameShape(QFrame.Shape.VLine)
249 line.setFrameShadow(QFrame.Shadow.Sunken) 253 line.setFrameShadow(QFrame.Shadow.Sunken)
250 254
251 self.__layout.addWidget(line) 255 self.__layout.addWidget(line)
252 self.__separators.append(line) 256 self.__separators.append(line)
253 257
254 @pyqtSlot() 258 @pyqtSlot()
255 def __updateButtonStates(self): 259 def __updateButtonStates(self):
256 """ 260 """
257 Private slot to change the button states. 261 Private slot to change the button states.
258 """ 262 """
259 provider = MarkupProviders.getMarkupProvider(self.__editor) 263 provider = MarkupProviders.getMarkupProvider(self.__editor)
260 if ( 264 if self.__provider is None or provider.kind() != self.__provider.kind():
261 self.__provider is None or
262 provider.kind() != self.__provider.kind()
263 ):
264 self.__provider = provider 265 self.__provider = provider
265 266
266 self.__buttons["bold"].setEnabled(self.__provider.hasBold()) 267 self.__buttons["bold"].setEnabled(self.__provider.hasBold())
267 self.__buttons["italic"].setEnabled(self.__provider.hasItalic()) 268 self.__buttons["italic"].setEnabled(self.__provider.hasItalic())
268 self.__buttons["strikethrough"].setEnabled( 269 self.__buttons["strikethrough"].setEnabled(
269 self.__provider.hasStrikethrough()) 270 self.__provider.hasStrikethrough()
270 271 )
272
271 headerLevels = self.__provider.headerLevels() 273 headerLevels = self.__provider.headerLevels()
272 self.__buttons["header1"].setEnabled(headerLevels >= 1) 274 self.__buttons["header1"].setEnabled(headerLevels >= 1)
273 self.__buttons["header2"].setEnabled(headerLevels >= 2) 275 self.__buttons["header2"].setEnabled(headerLevels >= 2)
274 self.__buttons["header3"].setEnabled(headerLevels >= 3) 276 self.__buttons["header3"].setEnabled(headerLevels >= 3)
275 self.__buttons["header"].setEnabled(headerLevels > 3) 277 self.__buttons["header"].setEnabled(headerLevels > 3)
276 self.__headerMenu.clear() 278 self.__headerMenu.clear()
277 for level in range(1, headerLevels + 1): 279 for level in range(1, headerLevels + 1):
278 act = self.__headerMenu.addAction( 280 act = self.__headerMenu.addAction(self.tr("Level {0}").format(level))
279 self.tr("Level {0}").format(level))
280 act.setData("header{0}".format(level)) 281 act.setData("header{0}".format(level))
281 282
282 self.__buttons["code"].setEnabled(self.__provider.hasCode()) 283 self.__buttons["code"].setEnabled(self.__provider.hasCode())
283 self.__buttons["codeBlock"].setEnabled( 284 self.__buttons["codeBlock"].setEnabled(self.__provider.hasCodeBlock())
284 self.__provider.hasCodeBlock()) 285
285 286 self.__buttons["bulletedList"].setEnabled(self.__provider.hasBulletedList())
286 self.__buttons["bulletedList"].setEnabled( 287 self.__buttons["numberedList"].setEnabled(self.__provider.hasNumberedList())
287 self.__provider.hasBulletedList()) 288
288 self.__buttons["numberedList"].setEnabled(
289 self.__provider.hasNumberedList())
290
291 self.__editorSelectionChanged() 289 self.__editorSelectionChanged()
292 290
293 if Preferences.getEditor("HideFormatButtons"): 291 if Preferences.getEditor("HideFormatButtons"):
294 self.setVisible(self.__provider.kind() != "none") 292 self.setVisible(self.__provider.kind() != "none")
295 293
296 def __formatClicked(self, formatName): 294 def __formatClicked(self, formatName):
297 """ 295 """
298 Private slot to handle a format button being clicked. 296 Private slot to handle a format button being clicked.
299 297
300 @param formatName format type of the button 298 @param formatName format type of the button
301 @type str 299 @type str
302 """ 300 """
303 if formatName == "bold": 301 if formatName == "bold":
304 self.__provider.bold(self.__editor) 302 self.__provider.bold(self.__editor)
324 self.__provider.image(self.__editor) 322 self.__provider.image(self.__editor)
325 elif formatName == "bulletedList": 323 elif formatName == "bulletedList":
326 self.__provider.bulletedList(self.__editor) 324 self.__provider.bulletedList(self.__editor)
327 elif formatName == "numberedList": 325 elif formatName == "numberedList":
328 self.__provider.numberedList(self.__editor) 326 self.__provider.numberedList(self.__editor)
329 327
330 def __headerMenuTriggered(self, act): 328 def __headerMenuTriggered(self, act):
331 """ 329 """
332 Private method handling the selection of a header menu entry. 330 Private method handling the selection of a header menu entry.
333 331
334 @param act action of the headers menu that was triggered 332 @param act action of the headers menu that was triggered
335 @type QAction 333 @type QAction
336 """ 334 """
337 formatName = act.data() 335 formatName = act.data()
338 self.__formatClicked(formatName) 336 self.__formatClicked(formatName)
339 337
340 def __editorSelectionChanged(self): 338 def __editorSelectionChanged(self):
341 """ 339 """
342 Private slot to handle a change of the editor's selection. 340 Private slot to handle a change of the editor's selection.
343 """ 341 """
344 hasSelection = self.__editor.hasSelectedText() 342 hasSelection = self.__editor.hasSelectedText()
345 if self.__provider: 343 if self.__provider:
346 self.__buttons["quote"].setEnabled( 344 self.__buttons["quote"].setEnabled(
347 self.__provider.hasQuote() and ( 345 self.__provider.hasQuote()
348 self.__provider.kind() == "html" or hasSelection 346 and (self.__provider.kind() == "html" or hasSelection)
349 )
350 ) 347 )
351 self.__buttons["hyperlink"].setEnabled( 348 self.__buttons["hyperlink"].setEnabled(
352 self.__provider.hasHyperlink() and not hasSelection) 349 self.__provider.hasHyperlink() and not hasSelection
350 )
353 self.__buttons["line"].setEnabled( 351 self.__buttons["line"].setEnabled(
354 self.__provider.hasLine() and not hasSelection) 352 self.__provider.hasLine() and not hasSelection
353 )
355 self.__buttons["image"].setEnabled( 354 self.__buttons["image"].setEnabled(
356 self.__provider.hasImage() and not hasSelection) 355 self.__provider.hasImage() and not hasSelection
357 356 )
357
358 def __editorSettingsRead(self): 358 def __editorSettingsRead(self):
359 """ 359 """
360 Private slot to handle a change of the editor related settings. 360 Private slot to handle a change of the editor related settings.
361 """ 361 """
362 if Preferences.getEditor("HideFormatButtons"): 362 if Preferences.getEditor("HideFormatButtons"):

eric ide

mercurial