def onMonoFontChange(self, propagate=True): font = QFont(self.monoFontComboBox.currentFont()) font.setPointSize(self.monoFontSizeSpinBox.value()) if propagate and bool(self.state.model): self.state.model.setConfig(Gconf.Key.MonoFont, font.family()) self.state.model.setConfig(Gconf.Key.MonoFontSize, font.pointSize())
def createFontBoxesFor(parent, name, family, size, *, mono=False, tooltips=None, which="Font"): font = QFont(family, size) fontComboBox = QFontComboBox(parent) if not mono: fontFilter = QFontComboBox.ScalableFonts else: fontFilter = (QFontComboBox.ScalableFonts | QFontComboBox.MonospacedFonts) fontComboBox.setFontFilters(fontFilter) fontComboBox.setCurrentFont(font) fontSizeSpinBox = QSpinBox(parent) fontSizeSpinBox.setAlignment(Qt.AlignRight) fontSizeSpinBox.setRange(6, 36) fontSizeSpinBox.setSuffix(" pt") fontSizeSpinBox.setAlignment(Qt.AlignVCenter | Qt.AlignRight) fontSizeSpinBox.setValue(font.pointSize()) if tooltips is not None: tooltips.append((fontComboBox, """\ <p><b>{0} Font</b></p><p>The font family to use for the {0} Font.</p>""". format(which))) tooltips.append((fontSizeSpinBox, """\ <p><b>{0} Font Size</b></p><p>The font point size to use for the {0} Font.</p>""".format(which))) setattr(parent, "{}FontComboBox".format(name.lower()), fontComboBox) setattr(parent, "{}FontSizeSpinBox".format(name.lower()), fontSizeSpinBox)
def setTitleFont(self): ''' Sets font for the widget text ''' fontValue = QFont('Times New Roman') fontValue.setPointSize(fontValue.pointSize() + 15) self.setFont(fontValue)
def onDisplayMonoFontChange(self, propagate=True): font = QFont(self.displaymonoFontComboBox.currentFont()) font.setPointSize(self.displaymonoFontSizeSpinBox.value()) if propagate: settings = QSettings() settings.setValue(Gopt.Key.MonoFont, font.family()) settings.setValue(Gopt.Key.MonoFontSize, font.pointSize()) self.state.updateDisplayFonts()
def __init__(self, parent=None): super(AutoInfo, self).__init__(parent) self.setupUi(self) # Remove the question mark widget from dialog # self.setWindowFlags(self.windowFlags() ^ # Qt.WindowContextHelpButtonHint) self.setWindowFlags(Qt.Tool | Qt.FramelessWindowHint) self.hide() font = QFont() font.setBold(True) font.setPointSize(QFont.pointSize(QFont()) + 3) self.label.setFont(font)
class Panel(QWidget): characterSelected = Signal(str) fontResized = Signal(float) def __init__(self, parent=None): super().__init__(parent) self.displayFont = QFont() self.displayFont.setStyleStrategy(QFont.PreferDefault) self.updateFont(self.displayFont.family()) self.currentChar = "" self.setMouseTracking(True) self.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Expanding) def updateFont(self, family): self.displayFont.setFamily(family) self.updateSize(self.displayFont.pointSize()) def updateSize(self, size): size = int(size) self.displayFont.setPointSize(size) self.squareSize = max(SQUARE_SIZE, QFontMetrics(self.displayFont).xHeight() * 3) self.fontResized.emit(self.squareSize) self.adjustSize() self.update() def minimumWidth(self): return COLUMNS * self.squareSize def sizeHint(self): return QSize(self.minimumWidth(), (MAX_CHAR / COLUMNS) * self.squareSize) def mousePressEvent(self, event): if event.button() == Qt.LeftButton: self.currentChar = chr((event.y() // self.squareSize) * COLUMNS + event.x() // self.squareSize) if not unicodedata.category(self.currentChar).startswith("C"): self.characterSelected.emit(self.currentChar) self.update() else: super().mousePressEvent(event) def mouseMoveEvent(self, event): pos = self.mapFromGlobal(event.globalPos()) code = ((pos.y() // self.squareSize) * COLUMNS + pos.x() // self.squareSize) name = "unnamed" try: name = unicodedata.name(chr(code)).capitalize() except ValueError: pass text = """<p><span style="font-size: 18pt;">{0:c}</span></p> <p><span style="font-size: 13pt;">U+{0:04X}<br>{1}</span></p>""".format( code, name) QToolTip.showText(event.globalPos(), text, self) def paintEvent(self, event): painter = QPainter(self) painter.fillRect(event.rect(), Qt.white) painter.setFont(self.displayFont) redrawRect = event.rect() beginRow = redrawRect.top() // self.squareSize endRow = redrawRect.bottom() // self.squareSize beginColumn = redrawRect.left() // self.squareSize endColumn = redrawRect.right() // self.squareSize painter.setPen(Qt.gray) for row in range(beginRow, endRow + 1): for column in range(beginColumn, endColumn + 1): painter.drawRect(column * self.squareSize, row * self.squareSize, self.squareSize, self.squareSize) fontMetrics = QFontMetrics(self.displayFont) painter.setPen(Qt.black) for row in range(beginRow, endRow + 1): for column in range(beginColumn, endColumn + 1): char = chr(row * COLUMNS + column) painter.setClipRect(column * self.squareSize, row * self.squareSize, self.squareSize, self.squareSize) if char == self.currentChar: painter.fillRect(column * self.squareSize + 1, row * self.squareSize + 1, self.squareSize, self.squareSize, Qt.green) painter.drawText( column * self.squareSize + (self.squareSize / 2) - fontMetrics.width(char) / 2, row * self.squareSize + 4 + fontMetrics.ascent(), char)
class HooverBar(QGraphicsRectItem): def __init__(self, x, y, w, h, hoover_text, doubleclick_callback_widget, order_part_id): """ doubleclick_callback_widget : we will call the set_on_orderpart method of that object if a doubleclik happens here. """ super(HooverBar, self).__init__(x, y, w, h) self.setAcceptHoverEvents(True) self.gi = None self.hoover_text = hoover_text self.description = None self.doubleclick_callback_widget = doubleclick_callback_widget self.order_part_id = order_part_id self.base_font = QFont() if configuration.font_select: self.base_font.setPointSize(self.base_font.pointSize() * 2) def hoverEnterEvent(self, event): # QGraphicsSceneHoverEvent * event ) # BUG I had a crash running this, I suspect ownership issues regarding # graphics items... global configuration #mainlog.debug("hoverEnterEvent pos={}-{}".format(event.scenePos().x(),event.scenePos().y())) # mainlog.debug("hoverEnterEvent data={}".format(self.data)) super(HooverBar, self).hoverEnterEvent(event) if self.gi == None: if self.hoover_text: self.gi = QGraphicsRectItem(0, 0, 100, 100) self.gi.setBrush(QBrush(QColor(0, 64, 0, 192))) self.gi.setPen(QPen(Qt.transparent)) self.gi.setPos(event.scenePos().x() + 20, event.scenePos().y() + 20) # txt = [ "" ] # txt = [ u"{} {}".format(self.data.production_file.order_part.human_identifier, # date_to_dmy(self.data.production_file.order_part.deadline)), # nstr(self.data.production_file.order_part.description), # nstr(self.data.description), # _("{}x{}={}h, rest:{}h").format(self.data.production_file.order_part.qty, # nice_round(self.data.planned_hours), # nice_round(self.data.production_file.order_part.qty*self.data.planned_hours), # nice_round(self.data.planned_hours*self.data.production_file.order_part.qty - self.data.done_hours))] x = y = 10 w = 0 for t in self.hoover_text: description = QGraphicsSimpleTextItem() description.setFont(self.base_font) description.setBrush(QBrush(Qt.white)) description.setText(t) description.setParentItem(self.gi) description.setPos(x, y) y += description.boundingRect().height() w = max(w, description.boundingRect().width()) y += x w += 2 * x # description.setHtml(u"|{}| <b>{}</b><br/>{}<br>{}x{}={}h".format( # self.data.production_file.order_part.human_identifier, # self.data.production_file.order_part.description, # self.data.description, # self.data.production_file.order_part.qty, self.data.planned_hours, self.data.production_file.order_part.qty*self.data.planned_hours)) # description.setDefaultTextColor(Qt.white) # br = description.boundingRect() self.gi.setRect(0, 0, w, y) self.scene().addItem(self.gi) #mainlog.debug("hoverEnterEvent GI={}".format(self.gi)) # mainlog.debug("hoverEnterEvent Done") def hoverMoveEvent(self, event): super(HooverBar, self).hoverMoveEvent(event) # if self.gi: # mainlog.debug("hoverMoveEvent GI pos={}-{}".format(self.gi.pos().x(),self.gi.pos().y())) # mainlog.debug("hoverMoveEvent pos={}-{}".format(event.scenePos().x(),event.scenePos().y())) if self.gi: self.gi.setPos(event.scenePos().x() + 20, event.scenePos().y() + 20) def hoverLeaveEvent(self, event): super(HooverBar, self).hoverLeaveEvent(event) if self.gi: # mainlog.debug("hoverLeaveEvent GI={}".format(self.gi)) # self.gi.setActive(False) # self.gi.setVisible(False) # return if self.description: # I do this so that I can handle the destruction of description # graphics item myself (i.e. description won't be deleted # as a children of self.gi) self.description.setParentItem(None) self.description = None # and delete... # QtDoc : Removes the item item and all its children from the scene. # The ownership of item is passed on to the caller self.gi.setParentItem(None) # self.scene().removeItem(self.gi) self.gi = None # mainlog.debug("hoverLeaveEvent -- done") # order_part_double_clicked = Signal(int) def mouseDoubleClickEvent(self, event): # QGraphicsSceneHoverEvent * event ) # mainlog.debug("mouseDoubleClickEvent {}".format(self.data)) super(HooverBar, self).mouseDoubleClickEvent(event) self.doubleclick_callback_widget.set_on_order_part(self.order_part_id)
class PostViewScene(QGraphicsScene): def set_cursor_on(self, opdef_id): if opdef_id in self.posts_offsets: coord = self.posts_offsets[opdef_id] cover = self.cursor.rect().united(coord) self.cursor.setRect(coord) self.update(cover) def _operation_hoover_description(self, op): # order_part = op.production_file.order_part txt = [ u"{} {}".format(op.order_part_human_identifier, date_to_dmy(op.deadline)), # order_part.deadline op.order_part_description or "", op.description or "", _("{}x{}={}h, rest:{}h").format( op.qty, nice_round(op.planned_hours), nice_round(op.qty * op.planned_hours), nice_round(op.planned_hours * op.qty - op.done_hours)) ] return txt def reload(self, order_overview_widget, all_ops, all_operations, sort=1): # mainlog.debug("reload...") progress = QProgressDialog(_("Collecting data..."), None, 0, len(all_ops) + 3, order_overview_widget) progress.setWindowTitle("Horse") progress.setMinimumDuration(0) progress.setWindowModality(Qt.WindowModal) progress.setValue(progress.value() + 1) progress.show() for i in self.items(): self.removeItem(i) self.posts_offsets = dict() self.drawn_operations_data = dict() self.cursor = QGraphicsRectItem(0, 0, 50, 300) self.cursor.setBrush(QBrush(QColor(208, 208, 255, 255))) self.cursor.setPen(QPen(Qt.transparent)) self.addItem(self.cursor) bar_width = 8 bar_height = int(bar_width * 60.0 / 8.0) ascent = QFontMetrics(self.base_font).ascent() ascent_big = QFontMetrics(self.base_font_big).ascent() post_ops = {} # mainlog.debug("reload...2") # z = 0 # for op,order_part,parts in all_operations: # z = op.planned_hours # z = order_part.deadline # z = order_part.qty # z = order_part.human_identifier # all_operations = map(lambda i:i[0],all_operations) y = 0 for opdef in all_ops: progress.setValue(progress.value() + 1) operations = filter( lambda op: op.operation_definition_id == opdef. operation_definition_id, all_operations) # We're only interested in the effort/time that remains # to be put on an operation. We're only interested in # the future. # We want the oeprations that are either # - ongoing # - ready to start. # In all cases we're only interested in operations # that are "active" if sort == 1: operations = sorted( operations, key=lambda op: op.deadline or date(3000, 1, 1)) elif sort == 2: operations = sorted( operations, key=lambda op: op.planned_hours * op.qty - op.done_hours) else: # Don't sort pass maximum = 16.0 #float ! small_hours = 0 op_ndx = 0 current_x = 50 bar_drawn = False total_done_hours = total_estimated = 0 # -------------------------------------------------------------- # Started operations bars_line = BarsLine(16, bar_width, bar_height, current_x, y, self, order_overview_widget) total_hours_to_do = 0 for op in filter(lambda op: op.done_hours > 0, operations): hours_to_do = max( 0, op.planned_hours * op.qty - op.done_hours) # max protects against reporting errors total_hours_to_do += hours_to_do total_estimated += op.planned_hours * op.qty total_done_hours += op.done_hours bars_line.add_bar(hours_to_do, QBrush(Qt.green), self._operation_hoover_description(op), False, None) # op.production_file.order_part) # -------------------------------------------------------------- bars_line_unstarted_operations = BarsLine(16, bar_width, bar_height, current_x + 30, y, self, order_overview_widget) total_hours_to_do_on_unstarted_operations = 0 for op in filter(lambda op: op.done_hours == 0, operations): hours_to_do = op.planned_hours * op.qty total_hours_to_do_on_unstarted_operations += hours_to_do total_estimated += hours_to_do bars_line_unstarted_operations.add_bar( hours_to_do, QBrush(Qt.yellow), self._operation_hoover_description(op), False, None) #op.production_file.order_part) y_start = y total = total_hours_to_do + total_hours_to_do_on_unstarted_operations if total > 0: self.drawn_operations_data[ opdef.operation_definition_id] = "{}h".format( int(round(total_estimated))) gi = QGraphicsSimpleTextItem( _("{} - Estimated to do : {}h; done : {}h").format( opdef.description, int(round(total)), int(round(total_done_hours)))) gi.setFont(self.base_font_big) gi.setPos(0, y - gi.boundingRect().height()) self.addItem(gi) th = gi.boundingRect().height() gi = QGraphicsLineItem(-ascent_big, y, 1024 + 2 * ascent_big, y) gi.setPen(QPen(Qt.black)) self.addItem(gi) y += th else: continue y_bars = y if total_hours_to_do > 0: # There's something to draw head = QGraphicsSimpleTextItem(_("Started")) head.setFont(self.base_font) head.setPos(current_x, y) self.addItem(head) y += head.boundingRect().height() y += bar_height bars_line.set_start_pos(current_x, y) bars_line.finish_bar() foot = QGraphicsSimpleTextItem( _("{}h").format(int(total_hours_to_do + 0.5))) foot.setFont(self.base_font) foot.setPos(current_x, y) self.addItem(foot) y += foot.boundingRect().height() current_x = max(current_x + bars_line.estimate_width(), head.boundingRect().right(), foot.boundingRect().right()) bar_drawn = True if total_hours_to_do_on_unstarted_operations > 0: if bars_line_unstarted_operations.estimate_width( ) + current_x > 1200: x = 50 y += ascent_big else: y = y_bars x = current_x + 50 head = QGraphicsSimpleTextItem(_("Not started yet")) head.setFont(self.base_font) head.setPos(x, y) self.addItem(head) y += head.boundingRect().height() y += bar_height bars_line_unstarted_operations.set_start_pos(x, y) bars_line_unstarted_operations.finish_bar() foot = QGraphicsSimpleTextItem( _("{}h").format( int(total_hours_to_do_on_unstarted_operations + 0.5))) foot.setFont(self.base_font) foot.setPos(x, y) self.addItem(foot) y += foot.boundingRect().height() bar_drawn = True y += 3 * ascent_big r = self.sceneRect() self.posts_offsets[opdef.operation_definition_id] = \ QRectF(r.x() - 2*ascent_big, y_start - 1.5*ascent_big, r.width() + 4*ascent_big, (y - ascent_big) - (y_start - 1.5*ascent_big) ) y += ascent_big # mainlog.debug("reload...3") import functools max_width = functools.reduce(lambda acc, po: max(acc, po.width()), self.posts_offsets.values(), 0) map(lambda po: po.setWidth(max_width), self.posts_offsets.values()) # for r in self.posts_offsets.values(): # gi = QGraphicsLineItem(r.x(),r.y(),r.x()+r.width(),r.y()) # gi.setPen(QPen(Qt.lightGray)) # self.addItem(gi) progress.close() def __init__(self, parent, order_overview_widget): global configuration super(PostViewScene, self).__init__(parent) self.base_font = QFont() self.base_font_big = QFont() self.base_font_big.setPointSize(self.base_font.pointSize() * 1.5) if configuration.font_select: self.base_font_big.setPointSize(self.base_font.pointSize() * 2)
class OrderWorkflowDialog(QDialog): def _makeArrow( self, ra, rb, both_ways=True): ca = QPointF( ra.x() + float(ra.width()) / 2.0, ra.y() + float(ra.height()) / 2.0) cb = QPointF( rb.x() + rb.width() / 2.0, rb.y() + rb.height() / 2.0) dx = cb.x() - ca.x() dy = cb.y() - ca.y() d = dist(dx,dy) a = math.atan2(float(dy),float(dx)) # The result is between -pi and pi # ra_rad = dist(ra.width() / 2, ra.height() / 2) # rb_rad = dist(rb.width() / 2, rb.height() / 2) x,y = squircle(ra.width() / 2, ra.height() / 2, to_squircle_angle(ra.width() / 2, ra.height() / 2,a)) ra_rad = dist(x,y) + 10 # painter.drawLine(ca,QPoint(ca.x() + x, ca.y() + y)) na = a if a < 0: na += math.pi else: na -= math.pi x,y = squircle(float(rb.width()) / 2.0, float(rb.height()) / 2.0, to_squircle_angle(float(rb.width()) / 2.0, float(rb.height()) / 2.0,na)) rb_rad = dist(x,y)+10 # ra_rad = rb_rad = 0 # painter.drawLine(ca,cb) # painter.drawRect(ra) # painter.setPen(Qt.GlobalColor.red) # painter.drawRect(rb) # painter.setPen(Qt.GlobalColor.black) # for t in range(100): # ang = 6.28/100.0*float(t) # x,y = squircle( 200,50,ang) # painter.drawPoint(300 + x,100 + y) qp = QPolygonF() h = 5 v = [] v.append(QPointF(ra_rad,0)) if not both_ways: v.append(QPointF(ra_rad,-h/2)) else: v.append(QPointF(ra_rad + 2*h,-2*h)) v.append(QPointF(ra_rad + 2*h,-h/2)) v.append(QPointF(d - rb_rad - 2*h,-h/2)) v.append(QPointF(d - rb_rad - 2*h,-2*h)) v.append(QPointF(d - rb_rad, 0)) v.append(QPointF(d - rb_rad - 2*h,+2*h)) v.append(QPointF(d - rb_rad - 2*h,+h/2)) if not both_ways: v.append(QPointF(ra_rad,+h/2)) else: v.append(QPointF(ra_rad + 2*h,+h/2)) v.append(QPointF(ra_rad + 2*h,+2*h)) v.append(QPointF(ra_rad,0)) p = QPolygonF(v) item = QGraphicsPolygonItem(p) item.translate(ca.x(),ca.y()) item.rotate(math.degrees(a)) return item def _drawNodes(self,scene,selected_state,initial_state): for i in scene.items(): scene.removeItem(i) pos = dict() sx = 1 sy = 1 if configuration.font_select: sx = sx * 2 sy = sy pos[OrderStatusType.preorder_definition] = (200*sx,200*sy) pos[OrderStatusType.order_definition] = (10*sx,300*sy) pos[OrderStatusType.order_ready_for_production] = (300*sx,300*sy) pos[OrderStatusType.order_production_paused] = (200*sx,550*sy) pos[OrderStatusType.order_completed] = (400*sx,600*sy) pos[OrderStatusType.order_aborted] = (10*sx,600*sy) mainlog.debug("_drawNodes : selected_state {}".format(selected_state)) mainlog.debug("_drawNodes : initial_state {}".format(initial_state)) for org in OrderStatusType.symbols(): x,y = pos[org] item = QGraphicsSimpleTextItem(org.description) if (selected_state and org in OrderStatusType.next_states(selected_state)) or org == initial_state or org == selected_state: item = MyQGraphicsSimpleTextItem(org, self) item.setFlags( item.flags() | QGraphicsItem.ItemIsSelectable) if org == selected_state: mainlog.debug("Preselcting {}".format(org)) item.setSelected(True) item.setFont(self.thinfont) item.setPos(x,y) scene.addItem(item) pos[org] = item.boundingRegion( item.sceneTransform()).boundingRect() # scene.addRect(pos[org]) g_orgs = dict() for org in OrderStatusType.symbols(): g_orgs[org] = OrderStatusType.next_states(org) # Draw all arrows which don't end up or leave the selected_state drawn = [] for org,dests in g_orgs.iteritems(): for dest in dests: if selected_state != org and ((org,dest) not in drawn) and ((dest,org) not in drawn): # If an arrow must have two directions, we draw it # like that directly. item = self._makeArrow( pos[org],pos[dest],dest in g_orgs and org in g_orgs[dest]) item.setPen(self.grey_pen) scene.addItem( item) drawn.append((org,dest)) if initial_state: scene.addRect(pos[initial_state]) if selected_state: for dest in OrderStatusType.next_states(selected_state): item = self._makeArrow( pos[selected_state],pos[dest],False) item.setBrush(QBrush(Qt.green)) scene.addItem( item) drawn.append((org,dest)) @Slot() def selectionChanged(self): pass def __init__(self,parent): global configuration super(OrderWorkflowDialog,self).__init__(parent) self.grey_pen = QPen(Qt.gray) title = _("Order workflow") self.setWindowTitle(title) self.title_widget = TitleWidget(title,self) self.buttons = QDialogButtonBox() self.buttons.addButton( QDialogButtonBox.Ok) self.buttons.addButton( QDialogButtonBox.Cancel) self.thinfont = QFont() if configuration.font_select: self.thinfont.setPointSize(self.thinfont.pointSize()*2) self.scene = QGraphicsScene() self.scene.selectionChanged.connect(self.selectionChanged) self.view = QGraphicsView(self) self.view.setRenderHint(QPainter.Antialiasing) self.view.setScene(self.scene) top_layout = QVBoxLayout() top_layout.addWidget(self.title_widget) top_layout.addWidget(self.view) top_layout.addWidget(self.buttons) self.setLayout(top_layout) # QWidget takes ownership of the layout self.buttons.accepted.connect(self.save_and_accept) self.buttons.rejected.connect(self.cancel) self.initial_state = None self.selected_state = None self._drawNodes(self.scene,self.selected_state,self.initial_state) def set_selected_state(self,selected_state,initial_state): mainlog.debug("selected_state {}".format(selected_state)) mainlog.debug("initial_state {}".format(initial_state)) self.initial_state = initial_state self.selected_state = selected_state self._drawNodes(self.scene,selected_state,self.initial_state) @Slot() def cancel(self): return super(OrderWorkflowDialog,self).reject() @Slot() def save_and_accept(self): super(OrderWorkflowDialog,self).accept() s = self.scene.selectedItems() if s: # In cas there are more than one item selected, # we pick the first one (arbitrarily) self.selected_state = s[0].state else: self.selected_state = self.initial_state