Source code for pyqtlineeditprogressbar


"""
.. module:: pyqtlineeditprogressbar
   :synopsis: A custom PyQt widget that creates a configurable progress bar as the background color of a QLineEdit widget.

.. moduleauthor: E.R. Uber <eruber@gmail.com>


PyQtLineEditProgressBar

This module subclass Qt's QtLineEdit widget to manage a progress
bar the is displayed as the background color of the QtLineEdit.

REFERENCE:
https://stackoverflow.com/questions/36972132/how-to-turn-qlineedit-background-into-a-progress-bar

GPL LICENSE
This file is part of the PyQtLineEditProgressBar package.

AutoFoE is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

AutoFoE is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with AutoFoE in the file named COPYING. If not, 
see <https://www.gnu.org/licenses/>.

COPYRIGHT (C) 2019-2020 E.R. Uber (eruber@gmail.com)

"""
# ----------------------------------------------------------------------------
# ------------------------ Python Standard Library ---------------------------
# ----------------------------------------------------------------------------
import time

# ----------------------------------------------------------------------------
# -------------------------- Third Party Packages ----------------------------
# ----------------------------------------------------------------------------
from PyQt5 import QtCore
from PyQt5 import QtGui
from PyQt5 import QtWidgets

from colour import Color  # https://pypi.org/project/colour/

# ----------------------------------------------------------------------------
# ----------------------- Module Global & Constants --------------------------
# ----------------------------------------------------------------------------

# Default Embedded Color Names
DECN = ['green', 'red', 'blue', 'orange', 'yellow', 'purple']

DEFAULT_COLOR_GREEN  = '#aaff7f'   # A pastel mint green
DEFAULT_COLOR_RED    = '#ffa5aa'   # A pastel red
DEFAULT_COLOR_BLUE   = '#b3fff4'   # A pastel blue   
DEFAULT_COLOR_ORANGE = '#ffcc74'   # A pastel orange
DEFAULT_COLOR_YELLOW = '#ffff00'   # A pastel yellow
DEFAULT_COLOR_PURPLE = '#e4b7ff'   # A pastel yellow

EMBEDDED_COLORS = {
	DECN[0] : DEFAULT_COLOR_GREEN, 
	DECN[1] : DEFAULT_COLOR_RED,   
	DECN[2] : DEFAULT_COLOR_BLUE,  
	DECN[3] : DEFAULT_COLOR_ORANGE,
	DECN[4] : DEFAULT_COLOR_YELLOW,
	DECN[5] : DEFAULT_COLOR_PURPLE,
}

DEFAULT_COLOR_NAME = DECN[0]

STARTS_EMPTY_FILLS_LEFT_TO_RIGHT  = 'starts-empty-fills-left-to-right'
STARTS_EMPTY_FILLS_RIGHT_TO_LEFT  = 'starts-empty-fills-right-to-left'
STARTS_FULL_EMPTIES_LEFT_TO_RIGHT = 'starts-filled-empties-left-to-right'
STARTS_FULL_EMPTIES_RIGHT_TO_LEFT = 'starts-filled-empties-right-to-left'

BEHAVIORS = [STARTS_EMPTY_FILLS_LEFT_TO_RIGHT,  STARTS_EMPTY_FILLS_RIGHT_TO_LEFT,
			 STARTS_FULL_EMPTIES_LEFT_TO_RIGHT, STARTS_FULL_EMPTIES_RIGHT_TO_LEFT]

LEFT_2_RIGHT = [STARTS_EMPTY_FILLS_LEFT_TO_RIGHT, STARTS_FULL_EMPTIES_LEFT_TO_RIGHT]
RIGHT_2_LEFT = [STARTS_EMPTY_FILLS_RIGHT_TO_LEFT, STARTS_FULL_EMPTIES_RIGHT_TO_LEFT]

BEHAVIOR_MAP = { # init_value, set_color_at_1, set_color_at_3, delta_sign
	BEHAVIORS[0] : [0.001, -0.001,  0.001,  1],  # Count up
	BEHAVIORS[1] : [0.999,  0.001, -0.001, -1],  # Count up
	BEHAVIORS[2] : [0.001,  0.001, -0.001,  1],  # Count down
	BEHAVIORS[3] : [0.999, -0.001,  0.001, -1],  # Count down
}

DEFAULT_BEHAVIOR = STARTS_EMPTY_FILLS_LEFT_TO_RIGHT

# ----------------------------------------------------------------------------
# --------------------- Module Classes & Functions ---------------------------
# ----------------------------------------------------------------------------
# https://doc.qt.io/qt-5/qlineedit.html
[docs]class PyQtLineEditProgressBar(QtWidgets.QLineEdit): def __init__(self, contents=None, parent=None, read_only=True, progressbar_color=EMBEDDED_COLORS[DECN[0]], behavior=DEFAULT_BEHAVIOR, text_for_bounding_rect=None, ): """ Constructor for the PyQtLineEditProgressBar Class Parameters ---------- contents : str Text displayed in the LineEdit widget (optional, can be set later with setText() method). parent : widget reference The parent widget. read_only : bool Defaults to True which makes the LineEdit widget read only. progressbar_color : str This must be a string describing a color, such as #1435fe, or some other color representation like, 'blue', or 'rgb(112,255,90)'. This field is validated using the `colour package <https://pypi.org/project/colour/>`_. An color specifier accepted by colour will pass input validation. There are six built-in colors that can be specified here: pyqtlineeditprogressbar.DEFAULT_COLOR_GREEN pyqtlineeditprogressbar.DEFAULT_COLOR_RED pyqtlineeditprogressbar.DEFAULT_COLOR_ORANGE pyqtlineeditprogressbar.DEFAULT_COLOR_BLUE pyqtlineeditprogressbar.DEFAULT_COLOR_YELLOW pyqtlineeditprogressbar.DEFAULT_COLOR_PURPLE If not specified, DEFAULT_COLOR_GREEN, is used. behavior : str A rather complicated looking string that identifies one of the four possible behaviors of the progress bar: pyqtlineeditprogressbar.STARTS_EMPTY_FILLS_LEFT_TO_RIGHT pyqtlineeditprogressbar.STARTS_EMPTY_FILLS_RIGHT_TO_LEFT pyqtlineeditprogressbar.STARTS_FULL_EMPTIES_LEFT_TO_RIGHT pyqtlineeditprogressbar.STARTS_FULL_EMPTIES_RIGHT_TO_LEFT If not specified, the default behavior is STARTS_EMPTY_FILLS_LEFT_TO_RIGHT. text_for_bounding_rect : str If you have trouble sizing the LineEdit widget's width, and the contents of this LineEdit widget have a fixed format, then this parameter may be specified to be used by the overridden sizeHint() method to access the Qt Font Metrics sub-system to specify a width width for the font being used. For example: text_for_bounding_rect=" 888/888 [88] " If not specified, then the standard Qt sizeHint() is called. """ super(PyQtLineEditProgressBar, self).__init__(parent=parent) self._parent = parent self._contents = contents self._text_for_bounding_rect = text_for_bounding_rect self._size_hint_qrect = None if self._contents: self.setText(self._contents) self.setReadOnly(read_only) self.setProgressBarColor(progressbar_color) self.setProgressBarBehavior(behavior) self._update_progress_bar() # https://doc.qt.io/qtforpython/PySide2/QtGui/QLinearGradient.html#detailed-description # https://doc.qt.io/qt-5/qlineargradient.html#details def _update_progress_bar(self): palette = self.palette() QRectF = QtCore.QRectF(self.rect()) gradient = QtGui.QLinearGradient(QRectF.topLeft(), QRectF.topRight()) # https://doc.qt.io/qt-5/qgradient.html#setColorAt gradient.setColorAt(self._value+self._param_1, QtGui.QColor(self._color)) gradient.setColorAt(self._value, QtGui.QColor('#ffffff')) gradient.setColorAt(self._value+self._param_3, QtGui.QColor('#ffffff')) palette.setBrush(QtGui.QPalette.Base, QtGui.QBrush(gradient)) self.setPalette(palette) def _clear_progress_bar(self): palette = self.palette() QRectF = QtCore.QRectF(self.rect()) gradient = QtGui.QLinearGradient(QRectF.topLeft(), QRectF.topRight()) # https://doc.qt.io/qt-5/qgradient.html#setColorAt gradient.setColorAt(0, QtGui.QColor('#ffffff')) #gradient.setColorAt(value, QtGui.QColor('#ffffff')) gradient.setColorAt(1, QtGui.QColor('#ffffff')) palette.setBrush(QtGui.QPalette.Base, QtGui.QBrush(gradient)) self.setPalette(palette) # ------------------------------------------------------------------------- # QLineEdit Methods that are over-ridden # -------------------------------------------------------------------------
[docs] def sizeHint(self): if self._text_for_bounding_rect: if self._size_hint_qrect: # We cache these rather than doing the expensive font calls # over and over w = self._size_hint_qrect.width() h = self._size_hint_qrect.height() else: metrics = QtGui.QFontMetrics(self.font()) # These are probably the widest integers... self._size_hint_qrect = metrics.boundingRect(self._text_for_bounding_rect) w = self._size_hint_qrect.width() h = self._size_hint_qrect.height() return(QtCore.QSize(w, h)) else: return(super(PyQtLineEditProgressBar, self).sizeHint())
# ------------------------------------------------------------------------- # Public API # -------------------------------------------------------------------------
[docs] def updateProgress(self, delta_float): if self._progressbar_behavior in LEFT_2_RIGHT: if self._value >= 0.998: self._value = 0.001 elif self._value > 0.9: self._value = 0.999 else: self._value = self._value + (self._delta_sign * delta_float) elif self._progressbar_behavior in RIGHT_2_LEFT: if self._value <= 0.0010: self._value = 0.999 elif self._value < 0.100: self._value = 0.001 else: self._value = self._value + (self._delta_sign * delta_float) if self._value > 0.999: self._value = 0.999 if self._value < 0.001: self._value = 0.001 self._update_progress_bar()
[docs] def removeProgressBar(self): self._clear_progress_bar()
[docs] def setProgressBarColor(self, color_text): if isinstance(color_text, str): color_text = color_text.lower() try: c = Color(color_text) self._color = c.hex_l except ValueError: self._color = EMBEDDED_COLORS[DEFAULT_COLOR_NAME] else: self._color = EMBEDDED_COLORS[DEFAULT_COLOR_NAME]
[docs] def getProgressBarColor(self): return(self._color)
[docs] def setProgressBarBehavior(self, behavior): if isinstance(behavior, str): behavior = behavior.lower() if behavior in BEHAVIORS: self._progressbar_behavior = behavior else: self._progressbar_behavior = DEFAULT_BEHAVIOR else: self._progressbar_behavior = DEFAULT_BEHAVIOR self._value, self._param_1, self._param_3, self._delta_sign = BEHAVIOR_MAP[self._progressbar_behavior]
[docs] def getBehavior(self): return(self._progressbar_behavior)
[docs] def getValue(self): return(self._value)