Skip to content

Commit

Permalink
Merge pull request #24 from nucleic/bitmap-buttons
Browse files Browse the repository at this point in the history
Bitmap buttons
  • Loading branch information
sccolbert committed May 26, 2013
2 parents bbe4848 + 0f8918f commit 5877335
Show file tree
Hide file tree
Showing 13 changed files with 827 additions and 465 deletions.
129 changes: 129 additions & 0 deletions enaml/qt/docking/q_bitmap_button.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
#------------------------------------------------------------------------------
# Copyright (c) 2013, Nucleic Development Team.
#
# Distributed under the terms of the Modified BSD License.
#
# The full license is in the file COPYING.txt, distributed with this software.
#------------------------------------------------------------------------------
from PyQt4.QtCore import QPoint, QRect
from PyQt4.QtGui import QAbstractButton, QColor, QPainter, QStyle, QStyleOption


class QBitmapButton(QAbstractButton):
""" A button widget which renders a bitmap.
This class is used to render the various maximize, restore, and
close buttons in the docking framework. Bitmap images are chosen
for rendering so that the button can be fully styled using Qt
style sheets.
"""
_bitmap = None

def bitmap(self):
""" Get the bitmap associated with the button.
"""
return self._bitmap

def setBitmap(self, bitmap):
""" Set the bitmap associate with the button.
"""
self._bitmap = bitmap
self.update()

def sizeHint(self):
""" Get the size hint for the bitmap button.
The size hint of the button is equal to it's icon size.
"""
return self.minimumSizeHint()

def minimumSizeHint(self):
""" Get the minimum size hint for the bitmap button.
The minimum size hint of the button is equal to it's icon size.
"""
return self.iconSize()

def enterEvent(self, event):
""" Handle the enter event for the button.
"""
if self.isEnabled():
self.update()
super(QBitmapButton, self).enterEvent(event)

def leaveEvent(self, event):
""" Handle the leave event for the button.
"""
if self.isEnabled():
self.update()
super(QBitmapButton, self).leaveEvent(event)

def styleOption(self):
""" Get a filled style option for the button.
Returns
-------
result : QStyleOption
A style option initialized for the current button state.
"""
opt = QStyleOption()
opt.initFrom(self)
opt.state |= QStyle.State_AutoRaise
is_down = self.isDown()
is_enabled = self.isEnabled()
is_checked = self.isChecked()
under_mouse = self.underMouse()
if is_enabled and under_mouse and not is_checked and not is_down:
opt.state |= QStyle.State_Raised
if is_checked:
opt.state |= QStyle.State_On
if is_down:
opt.state |= QStyle.State_Sunken
return opt

def drawBitmap(self, opt, painter):
""" Draw the bitmap for the button.
The bitmap will be drawn with the foreground color set by
the style sheet and the style option.
Parameters
----------
opt : QStyleOption
The style option to use for drawing.
painter : QPainter
The painter to use for drawing.
"""
bmp = self._bitmap
if bmp is not None:
# hack to get the current stylesheet foreground color
hint = QStyle.SH_GroupBox_TextLabelColor
fg = self.style().styleHint(hint, opt, self)
# mask signed to unsigned which 'fromRgba' requires
painter.setPen(QColor.fromRgba(0xffffffff & fg))
size = self.size()
im_size = bmp.size()
x = size.width() / 2 - im_size.width() / 2
y = size.height() / 2 - im_size.height() / 2
source = QRect(QPoint(0, 0), im_size)
dest = QRect(QPoint(x, y), im_size)
painter.drawPixmap(dest, bmp, source)

def paintEvent(self, event):
""" Handle the paint event for the button.
"""
painter = QPainter(self)
opt = self.styleOption()
self.style().drawPrimitive(QStyle.PE_Widget, opt, painter, self)
self.drawBitmap(opt, painter)
61 changes: 54 additions & 7 deletions enaml/qt/docking/q_dock_tab_widget.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,36 @@
#
# The full license is in the file COPYING.txt, distributed with this software.
#------------------------------------------------------------------------------
from PyQt4.QtCore import Qt, QPoint, QMetaObject, QEvent
from PyQt4.QtCore import Qt, QPoint, QSize, QMetaObject, QEvent
from PyQt4.QtGui import (
QApplication, QTabBar, QTabWidget, QMouseEvent, QResizeEvent
QApplication, QTabBar, QTabWidget, QMouseEvent, QResizeEvent, QStyle
)

from .q_bitmap_button import QBitmapButton
from .xbms import CLOSE_BUTTON


class QDockTabCloseButton(QBitmapButton):
""" A bitmap button subclass used as a dock tab close button.
"""
def styleOption(self):
""" Get a filled style option for the button.
Returns
-------
result : QStyleOption
A style option initialized for the current button state.
"""
opt = super(QDockTabCloseButton, self).styleOption()
parent = self.parent()
if isinstance(parent, QDockTabBar):
index = parent.currentIndex()
if parent.tabButton(index, QTabBar.RightSide) is self:
opt.state |= QStyle.State_Selected
return opt


class QDockTabBar(QTabBar):
""" A custom QTabBar that manages safetly undocking a tab.
Expand Down Expand Up @@ -59,25 +84,47 @@ def setCloseButtonVisible(self, index, visible):
# A workaround is to send a dummy resize event.
button.setVisible(visible)
if not visible:
button.resize(0, 0)
button.resize(0, 0)
else:
button.resize(button.sizeHint())
button.resize(button.sizeHint())
size = self.size()
event = QResizeEvent(size, size)
QApplication.sendEvent(self, event)
self.update()

#--------------------------------------------------------------------------
# Private API
#--------------------------------------------------------------------------
def _onCloseButtonClicked(self):
""" Handle the 'clicked' signal on the tab close buttons.
This handler will find the tab index for the clicked button
and emit the 'tabCloseRequested' signal with that index.
"""
button = self.sender()
for index in xrange(self.count()):
if self.tabButton(index, QTabBar.RightSide) is button:
self.tabCloseRequested.emit(index)

#--------------------------------------------------------------------------
# Reimplementations
#--------------------------------------------------------------------------
def tabInserted(self, index):
""" Handle a tab insertion in the tab bar.
This handler will update the visibilty of close button for
the inserted tab. This method assumes that this tab bar is
properly parented by a QDockTabWidget.
This handler will create the close button for the tab and then
update its visibilty depending on whether or not the dock item
is closable. This method assumes that this tab bar is parented
by a QDockTabWidget.
"""
button = QDockTabCloseButton(self)
button.setObjectName("docktab-close-button")
button.setBitmap(CLOSE_BUTTON.toBitmap())
button.setIconSize(QSize(14, 13))
button.clicked.connect(self._onCloseButtonClicked)
self.setTabButton(index, QTabBar.RightSide, button)
visible = self.parent().widget(index).closable()
self.setCloseButtonVisible(index, visible)

Expand Down
38 changes: 12 additions & 26 deletions enaml/qt/docking/q_dock_title_bar.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,12 @@
# The full license is in the file COPYING.txt, distributed with this software.
#------------------------------------------------------------------------------
from PyQt4.QtCore import QSize, QMargins, pyqtSignal
from PyQt4.QtGui import QWidget, QFrame, QHBoxLayout, QIcon
from PyQt4.QtGui import QWidget, QFrame, QHBoxLayout

from .q_icon_button import QIconButton
from .q_bitmap_button import QBitmapButton
from .q_icon_widget import QIconWidget
from .q_text_label import QTextLabel

# Make sure the resources get registered.
from . import dock_resources
from .xbms import CLOSE_BUTTON, MAXIMIZE_BUTTON, RESTORE_BUTTON


class IDockTitleBar(QWidget):
Expand Down Expand Up @@ -163,35 +161,23 @@ def __init__(self, parent=None):

title_label = self._title_label = QTextLabel(self)

max_icon = QIcon()
max_icon.addFile(':dock_images/maxbtn_s.png')
max_icon.addFile(':dock_images/maxbtn_h.png', mode=QIcon.Active)
max_icon.addFile(':dock_images/maxbtn_p.png', mode=QIcon.Selected)

restore_icon = QIcon()
restore_icon.addFile(':dock_images/rstrbtn_s.png')
restore_icon.addFile(':dock_images/rstrbtn_h.png', mode=QIcon.Active)
restore_icon.addFile(':dock_images/rstrbtn_p.png', mode=QIcon.Selected)

close_icon = QIcon()
close_icon.addFile(':dock_images/closebtn_s.png')
close_icon.addFile(':dock_images/closebtn_h.png', mode=QIcon.Active)
close_icon.addFile(':dock_images/closebtn_p.png', mode=QIcon.Selected)

btn_size = QSize(14, 13)

max_button = self._max_button = QIconButton(self)
max_button.setIcon(max_icon)
max_button = self._max_button = QBitmapButton(self)
max_button.setObjectName('docktitlebar-maximize-button')
max_button.setBitmap(MAXIMIZE_BUTTON.toBitmap())
max_button.setIconSize(btn_size)
max_button.setVisible(self._buttons & self.MaximizeButton)

restore_button = self._restore_button = QIconButton(self)
restore_button.setIcon(restore_icon)
restore_button = self._restore_button = QBitmapButton(self)
restore_button.setObjectName('docktitlebar-restore-button')
restore_button.setBitmap(RESTORE_BUTTON.toBitmap())
restore_button.setIconSize(btn_size)
restore_button.setVisible(self._buttons & self.RestoreButton)

close_button = self._close_button = QIconButton(self)
close_button.setIcon(close_icon)
close_button = self._close_button = QBitmapButton(self)
close_button.setObjectName('docktitlebar-close-button')
close_button.setBitmap(CLOSE_BUTTON.toBitmap())
close_button.setIconSize(btn_size)
close_button.setVisible(self._buttons & self.CloseButton)

Expand Down
49 changes: 16 additions & 33 deletions enaml/qt/docking/q_dock_window.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,16 @@
#
# The full license is in the file COPYING.txt, distributed with this software.
#------------------------------------------------------------------------------
from PyQt4.QtCore import Qt, QMargins, QPoint, QRect, pyqtSignal
from PyQt4.QtGui import QFrame, QHBoxLayout, QIcon, QLayout
from PyQt4.QtCore import Qt, QMargins, QPoint, QRect, QSize, pyqtSignal
from PyQt4.QtGui import QFrame, QHBoxLayout, QLayout

from atom.api import Bool, Typed

from .q_bitmap_button import QBitmapButton
from .q_dock_area import QDockArea
from .q_dock_frame import QDockFrame
from .q_dock_frame_layout import QDockFrameLayout
from .q_icon_button import QIconButton

# Make sure the resources get registered.
from . import dock_resources
from .xbms import CLOSE_BUTTON, MAXIMIZE_BUTTON, RESTORE_BUTTON


#: The maximum number of free windows to keep in the free list.
Expand Down Expand Up @@ -64,37 +62,22 @@ def __init__(self, parent=None):
super(QDockWindowButtons, self).__init__(parent)
self._buttons = self.CloseButton | self.MaximizeButton

hovered = QIcon.Active
pressed = QIcon.Selected

max_icon = QIcon()
max_icon.addFile(':dock_images/maxbtn_large_s.png')
max_icon.addFile(':dock_images/maxbtn_large_h.png', mode=hovered)
max_icon.addFile(':dock_images/maxbtn_large_p.png', mode=pressed)

restore_icon = QIcon()
restore_icon.addFile(':dock_images/rstrbtn_large_s.png')
restore_icon.addFile(':dock_images/rstrbtn_large_h.png', mode=hovered)
restore_icon.addFile(':dock_images/rstrbtn_large_p.png', mode=pressed)

close_icon = QIcon()
close_icon.addFile(':dock_images/closebtn_large_s.png')
close_icon.addFile(':dock_images/closebtn_large_h.png', mode=hovered)
close_icon.addFile(':dock_images/closebtn_large_p.png', mode=pressed)

max_button = self._max_button = QIconButton(self)
max_button.setIcon(max_icon)
max_button.setIconSize(max_icon.availableSizes()[0])
max_button = self._max_button = QBitmapButton(self)
max_button.setObjectName("dockwindow-maximize-button")
max_button.setBitmap(MAXIMIZE_BUTTON.toBitmap())
max_button.setIconSize(QSize(20, 15))
max_button.setVisible(self._buttons & self.MaximizeButton)

restore_button = self._restore_button = QIconButton(self)
restore_button.setIcon(restore_icon)
restore_button.setIconSize(restore_icon.availableSizes()[0])
restore_button = self._restore_button = QBitmapButton(self)
restore_button.setObjectName("dockwindow-restore-button")
restore_button.setBitmap(RESTORE_BUTTON.toBitmap())
restore_button.setIconSize(QSize(20, 15))
restore_button.setVisible(self._buttons & self.RestoreButton)

close_button = self._close_button = QIconButton()
close_button.setIcon(close_icon)
close_button.setIconSize(close_icon.availableSizes()[0])
close_button = self._close_button = QBitmapButton(self)
close_button.setObjectName("dockwindow-close-button")
close_button.setBitmap(CLOSE_BUTTON.toBitmap())
close_button.setIconSize(QSize(34, 15))
close_button.setVisible(self._buttons & self.CloseButton)

layout = QHBoxLayout()
Expand Down
Loading

0 comments on commit 5877335

Please sign in to comment.