def add_square(self, pos, size, col='black', thickness=None): """Draw a square. Args: pos (QPoint): square position size (QSize): square size col (str): square colour thickness (float): line thickness """ from psyhive import qt _pos = qt.get_p(pos) _size = qt.get_size(size) _rect = QtCore.QRect(_pos, _size) _brush = QtGui.QBrush(qt.HColor(0, 0, 0, 0)) _col = qt.get_col(col) _pen = QtGui.QPen(_col) if thickness: _pen.setWidthF(thickness) _pnt = qt.HPainter() _pnt.begin(self) _pnt.setPen(_pen) _pnt.setBrush(_brush) _pnt.drawRect(_rect) _pnt.end() return _rect
def _callback__PlaySeq(self): _work = get_single(self.ui.Work.selected_data(), catch=True) if not _work: return _c_work = self.c_works[_work] _viewables = [ _out for _out in _c_work.find_outputs() if _out.format in ['mov', 'jpg'] ] if len(_viewables) == 1: _viewable = get_single(_viewables) _seq = get_single(_viewable.find_files()) _seq.view() return _menu = qt.HMenu(self.ui.PlaySeq) for _viewable in _viewables: _seq = get_single(_viewable.find_files()) _menu.add_action('View ' + _viewable.output_type, func=_seq.view, icon=icons.EMOJI.find('Blue Circle')) _pos = qt.get_p(self.ui.PlaySeq.size() / 2) _menu.exec_(self.ui.PlaySeq.mapToGlobal(_pos))
def add_polygon(self, pts, col, outline='black', thickness=1.0): """Draw a polygon on this pixmap. Args: pts (QPointF list): polygon points col (QColor): fill colour outline (str|None): outline colour (if any) thickness (float): line thickness """ from psyhive import qt if outline: _pen = QtGui.QPen(outline) _pen.setCapStyle(Qt.RoundCap) if thickness: _pen.setWidthF(thickness) else: _pen = QtGui.QPen() _pen.setStyle(Qt.NoPen) _col = qt.get_col(col) _brush = QtGui.QBrush(_col) _poly = QtGui.QPolygonF() for _pt in pts: _pt = qt.get_p(_pt) _poly.append(_pt) _pnt = HPainter() _pnt.begin(self) _pnt.setBrush(_brush) _pnt.setPen(_pen) _pnt.drawPolygon(_poly) _pnt.end()
def add_circle(self, pos, col='black', radius=10, thickness=None, operation=None, pen=None): """Draw a circle on this pixmap. Args: pos (QPoint): centre point col (str): line colour radius (int): circle radius thickness (float): line thickness operation (str): compositing operation pen (QPen): override pen """ from psyhive import qt _pos = qt.get_p(pos) _col = qt.get_col(col) _pen = pen or QtGui.QPen(_col) if thickness: _pen.setWidthF(thickness) _rect = QtCore.QRect(_pos.x() - radius, _pos.y() - radius, radius * 2, radius * 2) _pnt = HPainter() _pnt.begin(self) _pnt.set_operation(operation) _pnt.setPen(_pen) _pnt.drawArc(_rect, 0, 360 * 16) _pnt.end() return _rect
def read_input(msg="Enter input:", title="Input dialog", default=None, type_=str, width=300, required=False, parent=None): """Show an input dialog requesting the user enter data. Args: msg (str): dialog message title (str): dialog title default (any): default value for dialog type_ (type): type of data to receive width (int): dialog width required (bool): whether data is required parent (QDialog): parent dialog Returns: (any): entered data of requested type """ from psyhive import qt _locals = locals() _args = [parent] if parent else [] # Get pos _pos = None if parent: _pos = parent.get_c() if type_ is str: _default = default or '' _dialog = QtWidgets.QInputDialog(*_args) _dialog.setInputMode(QtWidgets.QInputDialog.TextInput) _dialog.setWindowTitle(title) _dialog.setLabelText(msg) _dialog.setTextValue(_default) _dialog.resize(width, 100) if _pos: _dialog.move(_pos - qt.get_p(_dialog.size()) / 2) _responded = _dialog.exec_() _result = str(_dialog.textValue()) elif type_ is int: _default = default or 1 _result, _responded = QtWidgets.QInputDialog.getInt( None, title, msg, _default) else: raise ValueError('Unhandled type: {}'.format(type_.__name__)) if _responded in [0, False]: raise DialogCancelled if required and not _result: notify_warning( 'This dialog requires information to be entered.\n\nPlease enter ' 'some text or press cancel to exit.') _result = read_input(**_locals) return _result return _result
def get_c(self): """Get centre point of this pixmap. Returns: (QPoint): centre """ from psyhive import qt return qt.get_p(self.size()) / 2
def get_c(self): """Get interface centre. Returns: (QPoint): centre """ from psyhive import qt return self.pos() + qt.get_p(self.size() / 2)
def _get_rect(anchor, pos, size): """Get rect for the given pos/size and anchor position. Args: anchor (str): anchor point pos (QPoint): anchor position size (QSize): rect size Returns: (QRect): rectangle """ from psyhive import qt _size = qt.get_size(size) _pos = qt.get_p(pos) if anchor == 'C': _root = _pos - qt.get_p(_size) / 2 elif anchor == 'L': _root = _pos - qt.get_p(0, _size.height() / 2) elif anchor == 'R': _root = _pos - qt.get_p(_size.width(), _size.height() / 2) elif anchor == 'T': _root = _pos - qt.get_p(_size.width() / 2, 0) elif anchor == 'TL': _root = _pos elif anchor == 'TR': _root = _pos - qt.get_p(_size.width(), 0) elif anchor == 'BL': _root = _pos - qt.get_p(0, _size.height()) else: raise ValueError(anchor) return QtCore.QRect(_root, _size)
def add_line(self, pt1, pt2, col='black', thickness=None, operation=None, pen=None, verbose=0): """Draw a straight line on this pixmap. Args: pt1 (QPoint): start point pt2 (QPoint): end point col (str): line colour thickness (float): line thickness operation (str): compositing operation pen (QPen): override pen (ignores all other pen attrs) verbose (int): print process data """ from psyhive import qt _pt1 = qt.get_p(pt1) _pt2 = qt.get_p(pt2) # Get pen if pen: _pen = pen else: _col = qt.get_col(col) _pen = QtGui.QPen(_col) _pen.setCapStyle(Qt.RoundCap) _pen.setJoinStyle(Qt.RoundJoin) if thickness: _pen.setWidthF(thickness) lprint("COL", _col, verbose=verbose) _pnt = HPainter() _pnt.begin(self) _pnt.setPen(_pen) _pnt.set_operation(operation) _pnt.drawLine(_pt1.x(), _pt1.y(), _pt2.x(), _pt2.y()) _pnt.end()
def add_dot(self, pos, col='black', radius=1.0, outline=None, thickness=None, operation=None, render_hint=None): """Draw a circle on this pixmap. Args: pos (QPoint): centre point col (str): dot colour radius (float): dot radius outline (QPen): apply outline pen thickness (float): line thickness operation (str): compositing operation render_hint (RenderHint): add render hint """ from psyhive import qt _pos = qt.get_p(pos) _col = qt.get_col(col) _brush = QtGui.QBrush(_col) # Set outline if thickness: _pen = QtGui.QPen(qt.get_col('Black')) _pen.setWidthF(thickness) elif not outline: _pen = QtGui.QPen(_col) _pen.setStyle(Qt.NoPen) elif isinstance(outline, QtGui.QPen): _pen = outline elif isinstance(outline, six.string_types): _out_col = qt.get_col(outline) _pen = QtGui.QPen(_out_col) else: raise ValueError(outline) _pnt = HPainter() _pnt.begin(self) _pnt.setBrush(_brush) _pnt.setPen(_pen) if render_hint: _pnt.setRenderHint(render_hint) _pnt.set_operation(operation) _pnt.drawEllipse(_pos.x() - radius, _pos.y() - radius, radius * 2, radius * 2) _pnt.end()
def add_path(self, pts, col='black', thickness=None, pen=None): """Draw a path on this pixmap. Args: pts (QPoint list): list of points in path col (str): path colour thickness (float): line thickness pen (QPen): override pen (ignores all other pen attrs) """ from psyhive import qt # Set pen if pen: _pen = pen else: _col = qt.get_col(col) _pen = pen or QtGui.QPen(_col) _pen.setCapStyle(Qt.RoundCap) if thickness: _pen.setWidthF(thickness) _brush = QtGui.QBrush() _brush.setStyle(Qt.NoBrush) # Make path object _path = QtGui.QPainterPath() _path.moveTo(qt.get_p(pts[0])) for _pt in pts[1:]: _path.lineTo(qt.get_p(_pt)) _pnt = HPainter() _pnt.begin(self) _pnt.setPen(_pen) _pnt.setBrush(_brush) _pnt.drawPath(_path) _pnt.end()
def add_overlay(self, pix, pos=None, anchor='TL', operation=None, resize=None): """Add overlay to this pixmap. Args: pix (QPixmap|str): image to overlay pos (QPoint|tuple): position of overlay anchor (str): anchor position operation (str): overlay mode resize (int|QSize): apply resize to overlay Returns: (QRect): rectangle that was drawn """ from psyhive import qt _pix = qt.get_pixmap(pix) if resize: _pix = _pix.resize(resize) _pos = qt.get_p(pos) if pos else QtCore.QPoint() # Set offset if anchor == 'C': _pos = _pos - qt.get_p([_pix.width() / 2, _pix.height() / 2]) elif anchor == 'BL': _pos = _pos - qt.get_p([0, _pix.height()]) elif anchor == 'BR': _pos = _pos - qt.get_p([_pix.width(), _pix.height()]) elif anchor == 'TL': pass elif anchor == 'TR': _pos = _pos - qt.get_p([_pix.width(), 0]) elif anchor == 'T': _pos = _pos - qt.get_p([_pix.width() / 2, 0]) else: raise ValueError(anchor) _pnt = HPainter() _pnt.begin(self) _pnt.set_operation(operation) _pnt.drawPixmap(_pos.x(), _pos.y(), _pix) _pnt.end() return QtCore.QRect(_pos, _pix.size())
def multi_select( items, msg='Select items:', title="Select", multi=True, default=None, select='Select', width=None, pos=None, parent=None, labels=None): """Raise a dialog requesting selection from a list of items. Args: items (list): list of objects to display msg (str): message for dialog title (str): dialog title multi (bool): allow multiple selection (default is True) default (any): default value select (str): label for select button width (int): override dialog width pos (QPoint): position for dialog parent (QDialog): parent dialog labels (str list): list of display names for items (length must match item list length) """ from psyhive import qt global _DIALOG if not items: raise RuntimeError('No items') get_application() # Raise dialog _DIALOG = _MultiSelectDialog( items=items, multi=multi, msg=msg, select=select, title=title, width=width, default=default, parent=parent, labels=labels) if pos: _pos = pos - qt.get_p(_DIALOG.size()/2) _DIALOG.move(_pos) _DIALOG.exec_() if _DIALOG and _DIALOG.result is None: raise qt.DialogCancelled return _DIALOG and _DIALOG.result
def _add_psyhive_btn(label, icon, cmd, tooltip, add_dots=True, verbose=0): """Add styled button to PsyHive shelf. Args: label (str): button label icon (str): button icon name cmd (fn): button command tooltip (str): button tooltip add_dots (bool): add speckled dots to button background verbose (int): print process data Returns: (str): button element """ global _BUTTON_IDX # Set name/tmp_file lprint('ADDING', label, verbose=verbose) _name = 'PsyHive_' + label for _find, _replace in [('/', ''), (' ', ''), ('\n', '')]: _name = _name.replace(_find, _replace) _tmp_file = '{}/pixmaps/{}.png'.format(tempfile.gettempdir(), _name) _rand = str_to_seed(_name) lprint(' - NAME', _name, verbose=verbose) # Get colour _cols = ['RoyalBlue', 'CornflowerBlue', 'DodgerBlue'] _col_name = _rand.choice(_cols) _col = qt.get_col(_col_name) lprint(' - COL NAME', _col_name, verbose=verbose) # Draw base _pix = qt.HPixmap(32, 32) _pix.fill('Transparent') _col = _col.whiten(0.3) _pix.add_rounded_rect(pos=(0, 0), size=(32, 32), col=_col, outline=None, bevel=4) _col = _col.whiten(0.3) _pix.add_rounded_rect(pos=(2, 2), size=(28, 28), col=_col, outline=None) if add_dots: for _ in range(8): if _rand.random() > 0.3: _pos = qt.get_p([int(33 * _rand.random()) for _ in range(2)]) _rad = ValueRange('2-6').rand(random_=_rand) _alpha = ValueRange('80-100').rand(random_=_rand) _col = QtGui.QColor(255, 255, 255, _alpha) _pix.add_dot(pos=_pos, radius=_rad, col=_col) # Add icon if icon: _pix.add_overlay(icon, pos=qt.get_p(15, 2), resize=12, anchor='T') # Add text _lines = label.split('\n') for _jdx, _line in enumerate(_lines): _r_jdx = len(_lines) - _jdx - 1 _pix.add_text(_line, pos=qt.get_p(16, 31 - _r_jdx * 7), font=_get_btn_font(), anchor='B') _pix.save_as(_tmp_file, force=True) lprint(' - TMP FILE', _tmp_file, verbose=verbose) _btn = ui.add_shelf_button(_name, image=_tmp_file, command=cmd, parent='PsyHive', annotation=tooltip) lprint(verbose=verbose) _BUTTON_IDX += 1 return _btn
def add_text(self, text, pos=(0, 0), anchor='TL', col='white', font=None, size=None, verbose=0): """Write text to the image. Args: text (str): text to add pos (tuple|QPoint): text position anchor (str): text anchor col (str|QColor): text colour font (QFont): text font size (int): apply font size verbose (int): print process data """ from psyhive.qt import get_p, get_col lprint("Adding text", text, verbose=verbose) _window = self.window() _pos = get_p(pos) _x, _y = _pos.x(), _pos.y() _w, _h = _window.width(), _window.height() if anchor == 'BL': _rect = QtCore.QRect(_x, 0, _w - _x, _y) _align = Qt.AlignLeft | Qt.AlignBottom elif anchor == 'BR': _rect = QtCore.QRect(0, 0, _x, _y) _align = Qt.AlignRight | Qt.AlignBottom elif anchor == 'B': _rect = QtCore.QRect(0, 0, 2 * _x, _y) _align = Qt.AlignHCenter | Qt.AlignBottom elif anchor == 'C': _rect = QtCore.QRect(0, 0, 2 * _x, 2 * _y) _align = Qt.AlignHCenter | Qt.AlignVCenter elif anchor == 'L': _rect = QtCore.QRect(_x, 0, _w, 2 * _y) _align = Qt.AlignVCenter | Qt.AlignLeft elif anchor == 'R': _rect = QtCore.QRect(0, 0, _x, 2 * _y) _align = Qt.AlignRight | Qt.AlignVCenter elif anchor in ('T', 'TC'): _rect = QtCore.QRect(0, _y, 2 * _x, _h) _align = Qt.AlignHCenter | Qt.AlignTop elif anchor == 'TL': _rect = QtCore.QRect(_x, _y, _w, _h) _align = Qt.AlignLeft | Qt.AlignTop elif anchor == 'TR': _rect = QtCore.QRect(0, _y, _x, _h - _y) _align = Qt.AlignRight | Qt.AlignTop else: raise ValueError('Unhandled anchor: %s' % anchor) if font: self.setFont(font) elif size is not None: _font = QtGui.QFont() _font.setPointSize(size) self.setFont(_font) # Draw text self.setPen(get_col(col or 'white')) self.drawText(_rect, _align, text)