def drawInitialization(self): progress = self.doInitialisation() msg = "Initialisation ... " + progress fm = QFontMetrics(self.font()) tw = fm.width(msg) self.drawText((self.width() - tw) / 2, self.height() / 2, msg) QTimer.singleShot(1, self.updateGL)
def __computeTextPosition(self): if not self.__text is None: qf = QFontMetrics(self.font) self.__textx = self.x + self.margin self.__texty = self.y + self.margin + qf.ascent() + ( self.height - 2 * self.margin - len(self.__text) * qf.height()) / 2 self.__texth = qf.height()
def _initFonts(): """Initializes fonts on fitrst call""" if SkyModelTreeWidgetItem._fonts is None: stdfont = QApplication.font() boldfont = QFont(stdfont) boldfont.setBold(True) SkyModelTreeWidgetItem._fonts = [stdfont, boldfont] SkyModelTreeWidgetItem._fontmetrics = QFontMetrics(boldfont)
def setText(self, text): if len(text) == 0: return lines = text.split('\n') qf = QFontMetrics(self.font) fmw = max(qf.maxWidth(), 10) nlines = [] w = self.width - 2 * self.margin for line in lines: if qf.width(line) > w: while qf.width(line) > w: for i in xrange(w / fmw, len(line)): if qf.width(line, i) > w: if line[i].isalnum() and line[i - 1].isalnum(): nlines.append(line[0:i - 1] + ( '-' if line[i - 2].isalnum() else '')) line = line[i - 1:] else: nlines.append(line[0:i]) line = line[i:] break nlines.append(QString(line)) else: nlines.append(QString(line)) self.__text = nlines self.__computeTextPosition()
def elided_text(text, font=None, width=300, pos='middle'): ''' Return a version of text that is no wider than width pixels when rendered, replacing characters from the left, middle or right (as per pos) of the string with an ellipsis. Results in a string much closer to the limit than Qt's elidedText().''' from PyQt4.Qt import QFontMetrics, QApplication fm = QApplication.fontMetrics() if font is None else QFontMetrics(font) delta = 4 ellipsis = u'\u2026' def remove_middle(x): mid = len(x) // 2 return x[:max(0, mid - (delta//2))] + ellipsis + x[mid + (delta//2):] chomp = {'middle':remove_middle, 'left':lambda x:(ellipsis + x[delta:]), 'right':lambda x:(x[:-delta] + ellipsis)}[pos] while len(text) > delta and fm.width(text) > width: text = chomp(text) return unicode(text)
def do_size_hint(self, option, index): text = index.data(Qt.DisplayRole).toString() font = QFont(option.font) font.setPointSize(QFontInfo(font).pointSize() * 1.5) m = QFontMetrics(font) return QSize(m.width(text), m.height())
def renderTextNearCursor(self, textString, offset = 10, textColor = black, fontSize = 11): """ Renders text near the cursor position, on the top right side of the cursor (slightly above it). See example in DNA Line mode. @param textString: string @param offset: The offset that will be added to x and y values of the cursor position to get the base position of the text to be rendered. @see: DnaLineMode.Draw @see: self._getFontForTextNearCursor() @see: self.renderTextAtPosition() """ if not textString: return #Extra precaution if the caller passes a junk value such as None #for the color if not isinstance(textColor, tuple) and isinstance(textColor, list): textColor = black pos = self.cursor().pos() # x, y coordinates need to be in window coordinate system. # See QGLWidget.mapToGlobal for more details. pos = self.mapFromGlobal(pos) # Important to turn off the lighting. Otherwise the text color would # be dull and may also become even more light if some other object # is rendered as a transparent object. Example in DNA Line mode, when the # second axis end sphere is rendered as a transparent sphere, it affects # the text rendering as well (if GL_LIGHTING is not disabled) # [-- Ninad 2007-12-03] glDisable(GL_LIGHTING) #Add 'stoppers' for the cursor text. Example: If the cursor is near the #extreme right hand corner of the 3D workspace, the following code #ensures that all the text string is visible. It does this check for #right(x) and top(for y) borders of the glpane. xOffset = offset yOffset = offset #signForDX and signForDY are used by the code that draws the same #text in the background (offset by 1 pixel in 4 directions) signForDX = 1 signForDY = 1 xLimit = self.width - pos.x() #Note that at the top edge, y coord is 0 yLimit = pos.y() textString = QString(textString) font = self._getFontForTextNearCursor(fontSize = fontSize, isBold = True) #Now determine the total x and y pixels used to render the text #(add some tolerance to that number) fm = QFontMetrics(font) xPixels = fm.width(textString) + 10 yPixels = fm.height() + 10 if xLimit < xPixels: xOffset = - (xPixels - xLimit) signForDX = -1 if yLimit < yPixels: yOffset = - (yPixels - pos.y()) signForDY = -1 x = pos.x() + xOffset y = pos.y() - yOffset offset_val = 1 deltas_for_halo_color = (( offset_val, offset_val), (-offset_val, -offset_val), (-offset_val, offset_val), ( offset_val, -offset_val)) # halo color halo_color = getTextHaloColor(textColor) for dx, dy in deltas_for_halo_color: self.qglColor(RGBf_to_QColor(halo_color)) # Note: self.renderText is QGLWidget.renderText method. self.renderText(x + dx*signForDX , y + dy*signForDY, textString, font) ## self.qglClearColor(RGBf_to_QColor(halo_color)) ## # REVIEW: why is qglClearColor needed here? Why is it done *after* renderText? ## # [bruce 081204 questions; same Qs for the other uses of qglClearColor in this file] # Note: It is necessary to set the font color, otherwise it may change! self.qglColor(RGBf_to_QColor(textColor)) x = pos.x() + xOffset y = pos.y() - yOffset self.renderText(x , y , textString, font) ## self.qglClearColor(RGBf_to_QColor(textColor)) ## # is qglClearColor related to glClearColor? [bruce 071214 question] glEnable(GL_LIGHTING)
def elided_text(font, text, width=200, mode=None): from PyQt4.Qt import QFontMetrics, Qt if mode is None: mode = Qt.ElideMiddle fm = QFontMetrics(font) return unicode(fm.elidedText(text, mode, int(width)))
class Guides(object): """ Creates a set of vertical and horizontal rulers in the 3D graphics area. A 2D window (pixel) coordinate system is created locally, where: - The lower left corner is ( 0.0, 0.0, 0.0) - The upper right corner is ( width, height, 0.0) This schematic shows the 2D window coodinate system with the rulers positioned in the lower left corner (their default position). (width, height) / +---+--------------------------------------+ | | | | v | | | e | | | r | | | t | | | i | | | c | | | a | ruler_start_pt | | l | (vr_thickness, hr_thickness, 0.0) | | |/ | +---+--------------------------------------+ | A | horizontal | +---+--------------------------------------+ / ruler_origin (0.0, 0.0, 0.0) It doesn't matter what coordinate system you are in when you call this function, and the system will not be harmed, but it does use one level on each matrix stack, and it does set matrixmode to GL_MODELVIEW before returning. Still to do: - Optimize. Don't call drawLine() multiple times; create a point list and render all tick marks at once. - Add support for 2D grid lines. - Allow user to control ruler thickness, ruler font size, tick mark color, etc via user preferences. (nice to have) - Center unit text in origin square (using QFontMetrics class to do this). (fixed by piotr 080326) @param glpane: the 3D graphics area. @type glpane: L{GLPane) @note: There is a pref key called I{displayRulers_prefs_key} that is set from the "View > Rulers" menu item. It is used in this function's sole caller (GLPane.standard_repaint_0()) to determine whether to draw any ruler(s). It is not used here. """ ruler_position = None scale = 0.0 zoomFactor = 0.0 aspect = 0.0 ruler_drawing_params = () if sys.platform == "darwin": # WARNING: Anything smaller than 9 pt on Mac OS X results in # un-rendered text. Not sure why. --Mark 2008-02-27 rulerFontPointSize = 9 else: rulerFontPointSize = 7 rulerFont = QFont( QString("Helvetica"), rulerFontPointSize) rulerFontMetrics = QFontMetrics(rulerFont) # piotr 080326 def __init__(self, glpane): """ Constructor for the guide objects (i.e. rulers). """ self.glpane = glpane def draw(self): """ Draws the rulers. """ width = self.glpane.width height = self.glpane.height # These 3 attrs (scale, aspect, and ruler_position) are checked to # determine if they've changed. If any of them have, # getRulerDrawingParameters() must be called to get new drawing parms. if (self.scale != self.glpane.scale) or \ (self.zoomFactor != self.glpane.zoomFactor) or \ (self.aspect != self.glpane.aspect) or \ (self.ruler_position != env.prefs[rulerPosition_prefs_key]): self.scale = self.glpane.scale self.zoomFactor = self.glpane.zoomFactor self.aspect = self.glpane.aspect self.ruler_position = env.prefs[rulerPosition_prefs_key] self.ruler_drawing_params = \ getRulerDrawingParameters(width, height, self.aspect, self.scale, self.zoomFactor, self.ruler_position) (draw_ticks_and_text, units_text, units_format, units_scale, unit_label_inc, long_tickmark_inc, medium_tickmark_inc, num_vert_ticks, num_horz_ticks, tickmark_spacing_multiplier, ruler_origin, ruler_start_pt, units_text_origin, origin_square_pt1, origin_square_pt2, vr_thickness, vr_tickmark_spacing, vr_long_tick_len, vr_medium_tick_len, vr_short_tick_len, vr_rect_pt1, vr_rect_pt2, vr_line_pt1, vr_line_pt2, vr_units_x_offset, vr_units_y_offset, hr_thickness, hr_tickmark_spacing, hr_long_tick_len, hr_medium_tick_len, hr_short_tick_len, hr_rect_pt1, hr_rect_pt2, hr_line_pt1, hr_line_pt2, hr_units_x_offset, hr_units_y_offset) = self.ruler_drawing_params ruler_color = env.prefs[rulerColor_prefs_key] ruler_opacity = env.prefs[rulerOpacity_prefs_key] # These may become user preferences in the future. tickmark_color = darkgray text_color = black # Set up 2D (window) coordinate system. # Bruce - please review this section. glMatrixMode(GL_MODELVIEW) glPushMatrix() glLoadIdentity() glMatrixMode(GL_PROJECTION) glPushMatrix() glLoadIdentity() # needed! gluOrtho2D(0.0, float(width), 0.0, float(height)) glMatrixMode(GL_MODELVIEW) # About this glMatrixMode(GL_MODELVIEW) call, Bruce wrote in a review: # The only reason this is desirable (it's not really needed) is if, # when someone is editing the large body of drawing code after this, # they inadvertently do something which is only correct if the matrix # mode is GL_MODELVIEW (e.g. if they use glTranslate to shift a ruler # or tickmark position). Most of our drawing code assumes it can do # this, so a typical NE1 OpenGL programmer may naturally assume this, # which is why it's good to leave the matrix mode as GL_MODELVIEW when # entering into a large hunk of ordinary drawing code (especially if # it might call other drawing functions, now or in the future). # Mark 2008-03-03 glDisable(GL_LIGHTING) glDisable(GL_DEPTH_TEST) # Suppress writing into the depth buffer so anything behind the ruler # can still be highlighted/selected. glDepthMask(GL_FALSE) # Draw v/h ruler rectangles in the user defined color and opacity. ##### glColor4fv(list(ruler_color) + [ruler_opacity]) glEnable(GL_BLEND) glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) glRectf(origin_square_pt1[0], origin_square_pt1[1], origin_square_pt2[0], origin_square_pt2[1]) # Origin square if env.prefs[displayVertRuler_prefs_key]: glRectf(vr_rect_pt1[0], vr_rect_pt1[1], vr_rect_pt2[0], vr_rect_pt2[1]) # Vertical ruler if env.prefs[displayHorzRuler_prefs_key]: glRectf(hr_rect_pt1[0], hr_rect_pt1[1], hr_rect_pt2[0], hr_rect_pt2[1]) # Horizontal ruler glDisable(GL_BLEND) # Set color of ruler lines, tick marks and text. glColor3fv(tickmark_color) self.glpane.qglColor(RGBf_to_QColor(text_color)) # Draw unit of measurement in corner (A or nm). # piotr 080326: replaced drawText with drawCenteredText self.drawCenteredText(units_text, units_text_origin) # Kludge alert. Finish drawing ruler edge(s) if we will not be # drawing the ruler tick marks and text (only happens when the user # is zoomed out to an "absured scale factor". if not draw_ticks_and_text: if env.prefs[displayVertRuler_prefs_key]: self.drawLine(vr_line_pt1, vr_line_pt2) if env.prefs[displayHorzRuler_prefs_key]: self.drawLine(hr_line_pt1, hr_line_pt2) # Draw vertical ruler line(s) and tick marks ########################## if env.prefs[displayVertRuler_prefs_key] and draw_ticks_and_text: # Draw vertical line along right/left edge of ruler. self.drawLine(vr_line_pt1, vr_line_pt2) # Initialize pt1 and pt2, the tick mark endpoints. The first tick # mark will span the entire width of the ruler, which serves as a # divider b/w the unit of measure text (i.e. A or nm) and the rest # of the ruler. pt1 = ruler_start_pt pt2 = ruler_start_pt + V(-vr_thickness, 0.0, 0.0) # Draw vertical ruler tickmarks, including numeric unit labels for tick_num in range(num_horz_ticks + 1): # pt1 and pt2 are modified by each iteration of the loop. self.drawLine(pt1, pt2) # Draw units number beside long tickmarks. if not tick_num % unit_label_inc: units_num_origin = pt1 \ + V(vr_units_x_offset, vr_units_y_offset, 0.0) units_num = units_format % (tick_num * units_scale) self.drawText(units_num, units_num_origin) # Update tickmark endpoints for next tickmark. pt1 = ruler_start_pt + \ V(0.0, vr_tickmark_spacing * tickmark_spacing_multiplier * (tick_num + 1), 0.0) if not (tick_num + 1) % long_tickmark_inc: pt2 = pt1 + V(vr_long_tick_len, 0.0, 0.0) elif not (tick_num + 1) % medium_tickmark_inc: pt2 = pt1 + V(vr_medium_tick_len, 0.0, 0.0) else: pt2 = pt1 + V(vr_short_tick_len, 0.0, 0.0) # End vertical ruler # Draw horizontal ruler line(s) and tick marks ######################### if env.prefs[displayHorzRuler_prefs_key] and draw_ticks_and_text: # Draw horizontal line along top/bottom edge of ruler. self.drawLine(hr_line_pt1, hr_line_pt2) # Initialize pt1 and pt2, the tick mark endpoints. The first tick # mark will span the entire width of the ruler, which serves as a # divider b/w the unit of measure text (i.e. A or nm) and the rest # of the ruler. pt1 = ruler_start_pt pt2 = ruler_start_pt + V(0.0, -hr_thickness, 0.0) # Draw horizontal ruler (with vertical) tickmarks, including its # numeric unit labels for tick_num in range(num_vert_ticks + 1): # pt1 and pt2 are modified by each iteration of the loop. self.drawLine(pt1, pt2) # Draw units number beside long tickmarks. if not tick_num % unit_label_inc: units_num_origin = pt1 \ + V(hr_units_x_offset, hr_units_y_offset, 0.0) units_num = units_format % (tick_num * units_scale) self.drawText(units_num, units_num_origin) # Update tickmark endpoints for next tickmark. pt1 = \ ruler_start_pt + \ V(hr_tickmark_spacing * tickmark_spacing_multiplier * (tick_num + 1), 0.0, 0.0) if not (tick_num + 1) % long_tickmark_inc: pt2 = pt1 + V(0.0, hr_long_tick_len, 0.0) elif not (tick_num + 1) % medium_tickmark_inc: pt2 = pt1 + V(0.0, hr_medium_tick_len, 0.0) else: pt2 = pt1 + V(0.0, hr_short_tick_len, 0.0) # End horizontal ruler # Restore OpenGL state. glDepthMask(GL_TRUE) glEnable(GL_DEPTH_TEST) glEnable(GL_LIGHTING) glDepthMask(GL_TRUE) glMatrixMode(GL_PROJECTION) glPopMatrix() glMatrixMode(GL_MODELVIEW) glPopMatrix() return # from drawRulers def drawLine(self, pt1, pt2): """ Draws ruler lines that are 1 pixel wide. """ if 0: # Used for debugging. return glBegin(GL_LINES) glVertex(pt1[0], pt1[1], pt1[2]) glVertex(pt2[0], pt2[1], pt2[2]) glEnd() return def drawText(self, text, origin): """ Draws ruler text. """ if not text: return self.glpane.renderText(origin[0], origin[1], origin[2], \ QString(text), self.rulerFont) return def drawCenteredText(self, text, origin): """ Draws ruler text centered, so text center == origin. """ # added by piotr 080326 if not text: return fm = self.rulerFontMetrics # get the text dimensions in world coordinates x0, y0, z0 = gluUnProject(0,0,0) x1, y1, z1 = gluUnProject(fm.width(text),fm.ascent(),0) # compute a new origin relative to the old one new_origin = origin - 0.5 * V(x1-x0, y1-y0, z1-z0) # render the text self.glpane.renderText(new_origin[0], new_origin[1], new_origin[2], \ QString(text), self.rulerFont) return
def elided_text(font, text, width=200, mode=Qt.ElideMiddle): fm = QFontMetrics(font) return unicode(fm.elidedText(text, mode, int(width)))
def mouseMoveEvent(self, event): if self.drag is not None: QTreeView.mouseMoveEvent(self, event) return if ((event.globalPos() - self.mouse_press_qpoint).manhattanLength() < QApplication.startDragDistance()): return # # starting a drag # [logic bug, after bruce change 070507: should not do this # if we already started dragging out a selection. How can we tell? # Only by whether the initial press had eventInRect, I think # (not yet recorded), or at least, the initial move (#e could record here).] # index = self.indexAt(event.pos()) sellst = self.selectedList() # bruce 070507 move earlier DEBUG2 = True if index.isValid(): thisnode = index.internalPointer().node #bruce 070507 bring in some code from modelTreeGui.py alreadySelected = (thisnode in sellst) item = index.internalPointer() rect = self.visualRect(index) if DEBUG2: print "visualRect coords", rect.left(), rect.right(), rect.top( ), rect.bottom() qfm = QFontMetrics(QLineEdit(self).font()) rect.setWidth(qfm.width(item.node.name) + _ICONSIZE[0] + 4) if DEBUG2: print "visualRect coords, modified:", rect.left(), rect.right( ), rect.top(), rect.bottom() # looks like icon and text, a bit taller than text (guesses) eventInRect = rect.contains(event.pos()) if DEBUG2: print "valid index: eventInRect = %r, item = %r, index = %r, alreadySelected = %r" % \ (eventInRect, item, index, alreadySelected)####### else: thisnode = item = None alreadySelected = eventInRect = False if not eventInRect: # nothing to drag, but [bruce 070507] let super handle it (for dragging over nodes to select) self.drag_is_not_DND = True ### not yet used QTreeView.mouseMoveEvent(self, event) return if thisnode in sellst: # if dragging something selected, drag along all other selected ones dragged_nodes = sellst else: # if dragging something unselected, ignore any selected ones dragged_nodes = [thisnode] qdrag = QDrag(self) drag_type = 'move' # how do I decide between 'move' and 'copy'? self.drag = (dragged_nodes, drag_type, qdrag) mimedata = QMimeData() mimedata.setText("need a string here for a valid mimetype") qdrag.setMimeData(mimedata) display_prefs = {} pixmap = dragged_nodes[0].node_icon(display_prefs) qdrag.setPixmap(pixmap) qdrag.setHotSpot(QPoint(-8, 8)) qdrag.start()
def initialize(self, parent): ''' __init__ is called on SizePersistedDialog() ''' #self.connected_device = parent.opts.gui.device_manager.device self.parent = parent self.prefs = parent.prefs self.verbose = parent.verbose self.setupUi(self) self._log_location() # Subscribe to Marvin driver change events #self.connected_device.marvin_device_signals.reader_app_status_changed.connect( # self.marvin_status_changed) self.setWindowTitle("Edit CSS") # Remove the placeholder self.placeholder.setParent(None) self.placeholder.deleteLater() self.placeholder = None # Replace the placeholder self.html_wv = QWebView() self.html_wv.sizeHint = self.wv_sizeHint self.html_wv.setSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.MinimumExpanding) self.html_wv.page().setLinkDelegationPolicy(QWebPage.DelegateAllLinks) self.html_wv.linkClicked.connect(self.link_clicked) self.splitter.insertWidget(0, self.html_wv) # Add the Accept button self.accept_button = self.bb.addButton('Update', QDialogButtonBox.AcceptRole) self.accept_button.setDefault(True) # ~~~~~~~~ Configure the CSS control ~~~~~~~~ if isosx: FONT = QFont('Monaco', 11) elif iswindows: FONT = QFont('Lucida Console', 9) elif islinux: FONT = QFont('Monospace', 9) FONT.setStyleHint(QFont.TypeWriter) self.css_pte.setFont(FONT) # Tab width width = QFontMetrics(FONT).width(" ") * 4 self.css_pte.setTabStopWidth(width) # Restore/init the stored CSS self.css_pte.setPlainText(self.prefs.get('injected_css', '')) # Populate the HTML content rendered_html = self.inject_css(SAMPLE_HTML) self.html_wv.setHtml(rendered_html) # Restore the splitter split_points = self.prefs.get('css_editor_split_points') if split_points: self.splitter.setSizes(split_points) # Hook the QPlainTextEdit box self.css_pte.textChanged.connect(self.preview_css) # Hook the button events self.bb.clicked.connect(self.dispatch_button_click) self.resize_dialog()
def mouseMoveEvent(self, event): if self.drag is not None: QTreeView.mouseMoveEvent(self, event) return if ((event.globalPos() - self.mouse_press_qpoint).manhattanLength() < QApplication.startDragDistance()): return # # starting a drag # [logic bug, after bruce change 070507: should not do this # if we already started dragging out a selection. How can we tell? # Only by whether the initial press had eventInRect, I think # (not yet recorded), or at least, the initial move (#e could record here).] # index = self.indexAt(event.pos()) sellst = self.selectedList() # bruce 070507 move earlier DEBUG2 = True if index.isValid(): thisnode = index.internalPointer().node #bruce 070507 bring in some code from modelTreeGui.py alreadySelected = (thisnode in sellst) item = index.internalPointer() rect = self.visualRect(index) if DEBUG2: print "visualRect coords",rect.left(), rect.right(), rect.top(), rect.bottom() qfm = QFontMetrics(QLineEdit(self).font()) rect.setWidth(qfm.width(item.node.name) + _ICONSIZE[0] + 4) if DEBUG2: print "visualRect coords, modified:",rect.left(), rect.right(), rect.top(), rect.bottom() # looks like icon and text, a bit taller than text (guesses) eventInRect = rect.contains(event.pos()) if DEBUG2: print "valid index: eventInRect = %r, item = %r, index = %r, alreadySelected = %r" % \ (eventInRect, item, index, alreadySelected)####### else: thisnode = item = None alreadySelected = eventInRect = False if not eventInRect: # nothing to drag, but [bruce 070507] let super handle it (for dragging over nodes to select) self.drag_is_not_DND = True ### not yet used QTreeView.mouseMoveEvent(self, event) return if thisnode in sellst: # if dragging something selected, drag along all other selected ones dragged_nodes = sellst else: # if dragging something unselected, ignore any selected ones dragged_nodes = [ thisnode ] qdrag = QDrag(self) drag_type = 'move' # how do I decide between 'move' and 'copy'? self.drag = (dragged_nodes, drag_type, qdrag) mimedata = QMimeData() mimedata.setText("need a string here for a valid mimetype") qdrag.setMimeData(mimedata) display_prefs = { } pixmap = dragged_nodes[0].node_icon(display_prefs) qdrag.setPixmap(pixmap) qdrag.setHotSpot(QPoint(-8, 8)) qdrag.start()
def __computeTextPosition(self): if not self.__text is None: qf = QFontMetrics(self.parent.font()) self.__textx = self.x + (self.width - qf.width(self.__text)) / 2 self.__texty = self.y + qf.ascent() + (self.height - qf.height()) / 2