def create_spinbox(self, prefix, suffix, option, min_=None, max_=None, step=None, tip=None): if prefix: plabel = QLabel(prefix) else: plabel = None if suffix: slabel = QLabel(suffix) else: slabel = None spinbox = QSpinBox() if min_ is not None: spinbox.setMinimum(min_) if max_ is not None: spinbox.setMaximum(max_) if step is not None: spinbox.setSingleStep(step) if tip is not None: spinbox.setToolTip(tip) self.spinboxes[spinbox] = option layout = QHBoxLayout() for subwidget in (plabel, spinbox, slabel): if subwidget is not None: layout.addWidget(subwidget) layout.addStretch(1) layout.setContentsMargins(0, 0, 0, 0) widget = QWidget(self) widget.setLayout(layout) widget.spin = spinbox return widget
def create_spinbox(self, prefix, suffix, option, default=NoDefault, min_=None, max_=None, step=None, tip=None): if prefix: plabel = QLabel(prefix) else: plabel = None if suffix: slabel = QLabel(suffix) else: slabel = None spinbox = QSpinBox() if min_ is not None: spinbox.setMinimum(min_) if max_ is not None: spinbox.setMaximum(max_) if step is not None: spinbox.setSingleStep(step) if tip is not None: spinbox.setToolTip(tip) self.spinboxes[spinbox] = (option, default) layout = QHBoxLayout() for subwidget in (plabel, spinbox, slabel): if subwidget is not None: layout.addWidget(subwidget) layout.addStretch(1) layout.setContentsMargins(0, 0, 0, 0) widget = QWidget(self) widget.setLayout(layout) return widget
def __init__(self, parent, prefix = None, suffix = None, option = None, min_ = None, max_ = None, step = None, tip = None, value = None, changed =None): super(MySpinBox, self).__init__(parent) if prefix: plabel = QLabel(prefix) else: plabel = None if suffix: slabel = QLabel(suffix) else: slabel = None spinbox = QSpinBox(parent) if min_ is not None: spinbox.setMinimum(min_) if max_ is not None: spinbox.setMaximum(max_) if step is not None: spinbox.setSingleStep(step) if tip is not None: spinbox.setToolTip(tip) layout = QHBoxLayout() for subwidget in (plabel, spinbox, slabel): if subwidget is not None: layout.addWidget(subwidget) if value is not None: spinbox.setValue(value) if changed is not None: self.connect(spinbox, SIGNAL('valueChanged(int)'), changed) layout.addStretch(1) layout.setContentsMargins(0, 0, 0, 0) self.setLayout(layout) self.spin = spinbox
class Organ(KeyboardPart): @staticmethod def title(_=_base.translate): return _("Organ") @staticmethod def short(_=_base.translate): return _("abbreviation for Organ", "Org.") midiInstrument = 'church organ' def createWidgets(self, layout): super(Organ, self).createWidgets(layout) grid = layout.itemAt(layout.count() - 1).layout() self.pedalVoices = QSpinBox(minimum=0, maximum=4, value=1) self.pedalVoicesLabel = QLabel() self.pedalVoicesLabel.setBuddy(self.pedalVoices) grid.addWidget(self.pedalVoicesLabel, 2, 0) grid.addWidget(self.pedalVoices) def translateWidgets(self): super(Organ, self).translateWidgets() self.pedalVoicesLabel.setText(_("Pedal:")) self.pedalVoices.setToolTip(_( "Set to 0 to disable the pedal altogether.")) def build(self, data, builder): super(Organ, self).build(data, builder) if self.pedalVoices.value(): data.nodes.append(self.buildStaff(data, builder, 'pedal', -1, self.pedalVoices.value(), clef="bass"))
class IntegerParameterWidget(NumericParameterWidget): """Widget class for Integer parameter.""" def __init__(self, parameter, parent=None): """Constructor .. versionadded:: 2.2 :param parameter: A IntegerParameter object. :type parameter: IntegerParameter """ super(IntegerParameterWidget, self).__init__(parameter, parent) self._input = QSpinBox() self._input.setValue(self._parameter.value) self._input.setMinimum(self._parameter.minimum_allowed_value) self._input.setMaximum(self._parameter.maximum_allowed_value) tool_tip = 'Choose a number between %d and %d' % ( self._parameter.minimum_allowed_value, self._parameter.maximum_allowed_value) self._input.setToolTip(tool_tip) self._input.setSizePolicy(self._spin_box_size_policy) self.inner_input_layout.addWidget(self._input) self.inner_input_layout.addWidget(self._unit_widget)
class IntegerParameterWidget(NumericParameterWidget): """Widget class for Integer parameter.""" def __init__(self, parameter, parent=None): """Constructor .. versionadded:: 2.2 :param parameter: A IntegerParameter object. :type parameter: IntegerParameter """ super(IntegerParameterWidget, self).__init__(parameter, parent) self._input = QSpinBox() self._input.setValue(self._parameter.value) self._input.setMinimum(self._parameter.minimum_allowed_value) self._input.setMaximum(self._parameter.maximum_allowed_value) tool_tip = 'Choose a number between %d and %d' % ( self._parameter.minimum_allowed_value, self._parameter.maximum_allowed_value) self._input.setToolTip(tool_tip) self._input.setSizePolicy(self._spin_box_size_policy) self._inner_input_layout.addWidget(self._input) self._inner_input_layout.addWidget(self._unit_widget)
class SpinBoxImageView(QHBoxLayout): valueChanged = pyqtSignal(int) def __init__(self, parentView, backgroundColor, foregroundColor, value, height, fontSize): QHBoxLayout.__init__(self) self.backgroundColor = backgroundColor self.foregroundColor = foregroundColor self.labelLayout = QVBoxLayout() self.upLabel = LabelButtons('spin-up', parentView, backgroundColor, foregroundColor, height/2, height/2) self.labelLayout.addWidget(self.upLabel) self.upLabel.clicked.connect(self.on_upLabel) self.downLabel = LabelButtons('spin-down', parentView, backgroundColor, foregroundColor, height/2, height/2) self.labelLayout.addWidget(self.downLabel) self.downLabel.clicked.connect(self.on_downLabel) self.addLayout(self.labelLayout) self.spinBox = QSpinBox() self.spinBox.valueChanged.connect(self.spinBoxValueChanged) self.addWidget(self.spinBox) self.spinBox.setToolTip("Spinbox") self.spinBox.setButtonSymbols(QAbstractSpinBox.NoButtons) self.spinBox.setAlignment(Qt.AlignRight) self.spinBox.setMaximum(value) self.spinBox.setMaximumHeight(height) self.spinBox.setSuffix("/" + str(value)) font = self.spinBox.font() font.setPixelSize(fontSize) self.spinBox.setFont(font) self.do_draw() def do_draw(self): r, g, b, a = self.foregroundColor.getRgb() rgb = "rgb({0},{1},{2})".format(r, g, b) sheet = TEMPLATE.format(rgb, self.backgroundColor.name()) self.spinBox.setStyleSheet(sheet) def spinBoxValueChanged(self, value): self.valueChanged.emit(value) def setValue(self, value): self.spinBox.setValue(value) def setNewValue(self, value): self.spinBox.setMaximum(value) self.spinBox.setSuffix("/" + str(value)) def on_upLabel(self): self.spinBox.setValue(self.spinBox.value() + 1) def on_downLabel(self): self.spinBox.setValue(self.spinBox.value() - 1)
def addSpinBox(self, attribute_name, title, tool_tip=None, min_value=1, max_value=10, single_step=1): sb = QSpinBox() self[attribute_name] = sb sb.setMaximumHeight(25) sb_layout = QHBoxLayout() sb_layout.addWidget(sb) sb_layout.addStretch() self.addRow(title, sb_layout) if tool_tip is not None: sb.setToolTip(tool_tip) sb.setMinimum(min_value) sb.setMaximum(max_value) sb.setSingleStep(single_step) def getter(self): return self[attribute_name].value() def setter(self, value): self[attribute_name].setValue(value) self.updateProperty(attribute_name, getter, setter) return sb
class Organ(KeyboardPart): @staticmethod def title(_=__builtin__._): return _("Organ") @staticmethod def short(_=__builtin__._): return _("abbreviation for Organ", "Org.") midiInstrument = 'church organ' def createWidgets(self, layout): super(Organ, self).createWidgets(layout) grid = layout.itemAt(layout.count() - 1).layout() self.pedalVoices = QSpinBox(minimum=0, maximum=4, value=1) self.pedalVoicesLabel = QLabel() self.pedalVoicesLabel.setBuddy(self.pedalVoices) grid.addWidget(self.pedalVoicesLabel, 2, 0) grid.addWidget(self.pedalVoices) def translateWidgets(self): super(Organ, self).translateWidgets() self.pedalVoicesLabel.setText(_("Pedal:")) self.pedalVoices.setToolTip(_( "Set to 0 to disable the pedal altogether.")) def build(self, data, builder): super(Organ, self).build(data, builder) if self.pedalVoices.value(): data.nodes.append(self.buildStaff(data, builder, 'pedal', -1, self.pedalVoices.value(), clef="bass"))
class Prefs(preferences.Group): def __init__(self, page): super(Prefs, self).__init__(page) self._closeOutputs = QCheckBox(clicked=self.changed) self._pollingLabel = QLabel() self._pollingTime = QSpinBox() self._pollingTime.setRange(0, 1000) self._pollingTime.setSuffix(" ms") self._pollingTime.valueChanged.connect(self.changed) layout = QVBoxLayout() self.setLayout(layout) layout.addWidget(self._closeOutputs) app.translateUI(self) hbox = QHBoxLayout() layout.addLayout(hbox) hbox.addWidget(self._pollingLabel) hbox.addWidget(self._pollingTime) def translateUI(self): self.setTitle(_("Preferences")) self._closeOutputs.setText(_("Close unused MIDI output")) self._closeOutputs.setToolTip( _("Closes unused MIDI ports after one minute. " 'See "What\'s This" for more information.') ) self._closeOutputs.setWhatsThis( _( "<p>If checked, Frescobaldi will close MIDI output ports that are not " "used for one minute.</p>\n" "<p>This could free up system resources that a software MIDI synthesizer " "might be using, thus saving battery power.</p>\n" "<p>A side effect is that if you pause a MIDI file for a long time " "the instruments are reset to the default piano (instrument 0). " "In that case, playing the file from the beginning sets up the " "instruments again.</p>\n" ) ) self._pollingLabel.setText(_("Polling time for input:")) self._pollingTime.setToolTip(_("Polling time for MIDI input. " 'See "What\'s This" for more information.')) self._pollingTime.setWhatsThis( _( "Sets the time between the polling of the MIDI input port in milliseconds. " "Small values lead to faster recognition of incoming MIDI events, but stress " "the CPU. 10 ms should be a good value." ) ) def loadSettings(self): s = QSettings() self._closeOutputs.setChecked(s.value("midi/close_outputs", False, bool)) self._pollingTime.setValue(s.value("midi/polling_time", 10, int)) def saveSettings(self): s = QSettings() s.setValue("midi/close_outputs", self._closeOutputs.isChecked()) s.setValue("midi/polling_time", self._pollingTime.value())
class SpinBoxImageView(QHBoxLayout): valueChanged = pyqtSignal(int) def __init__(self, backgroundColor, foregroundColor, value, height, fontSize): QHBoxLayout.__init__(self) self.backgroundColor = backgroundColor self.foregroundColor = foregroundColor self.labelLayout = QVBoxLayout() self.upLabel = LabelButtons(backgroundColor, foregroundColor, height/2, height/2) self.labelLayout.addWidget(self.upLabel) self.upLabel.setSpinBoxUpIcon() self.upLabel.clicked.connect(self.on_upLabel) self.downLabel = LabelButtons(backgroundColor, foregroundColor, height/2, height/2) self.labelLayout.addWidget(self.downLabel) self.downLabel.setSpinBoxDownIcon() self.downLabel.clicked.connect(self.on_downLabel) self.addLayout(self.labelLayout) self.spinBox = QSpinBox() self.spinBox.valueChanged.connect(self.spinBoxValueChanged) self.addWidget(self.spinBox) self.spinBox.setToolTip("Spinbox") self.spinBox.setButtonSymbols(QAbstractSpinBox.NoButtons) self.spinBox.setAlignment(Qt.AlignRight) self.spinBox.setMaximum(value) self.spinBox.setMaximumHeight(height) self.spinBox.setSuffix("/" + str(value)) font = self.spinBox.font() font.setPixelSize(fontSize) self.spinBox.setFont(font) rgb = foregroundColor.getRgb() rgba_string = "rgba("+str(rgb[0])+","+str(rgb[1])+","+str(rgb[2])+","+str(0.6*100)+"%)" self.spinBox.setStyleSheet("QSpinBox { color: " + rgba_string + "; font: bold; background-color: " + str(backgroundColor.name()) + "; border:0;}") def changeOpacity(self, opacity): rgb = self.foregroundColor.getRgb() rgba_string = "rgba("+str(rgb[0])+","+str(rgb[1])+","+str(rgb[2])+","+str(opacity*100)+"%)" self.spinBox.setStyleSheet("QSpinBox { color: " + rgba_string + "; font: bold; background-color: " + str(self.backgroundColor.name()) + "; border:0;}") self.upLabel.changeOpacity(opacity) self.downLabel.changeOpacity(opacity) def spinBoxValueChanged(self, value): self.valueChanged.emit(value) def setValue(self, value): self.spinBox.setValue(value) def setNewValue(self, value): self.spinBox.setMaximum(value) self.spinBox.setSuffix("/" + str(value)) def on_upLabel(self): self.spinBox.setValue(self.spinBox.value() + 1) def on_downLabel(self): self.spinBox.setValue(self.spinBox.value() - 1)
class Prefs(preferences.Group): def __init__(self, page): super(Prefs, self).__init__(page) self._closeOutputs = QCheckBox(clicked=self.changed) self._pollingLabel = QLabel() self._pollingTime = QSpinBox() self._pollingTime.setRange(0, 1000) self._pollingTime.setSuffix(" ms") self._pollingTime.valueChanged.connect(self.changed) layout = QVBoxLayout() self.setLayout(layout) layout.addWidget(self._closeOutputs) app.translateUI(self) hbox = QHBoxLayout() layout.addLayout(hbox) hbox.addWidget(self._pollingLabel) hbox.addWidget(self._pollingTime) def translateUI(self): self.setTitle(_("Preferences")) self._closeOutputs.setText(_("Close unused MIDI output")) self._closeOutputs.setToolTip( _("Closes unused MIDI ports after one minute. " "See \"What's This\" for more information.")) self._closeOutputs.setWhatsThis( _("<p>If checked, Frescobaldi will close MIDI output ports that are not " "used for one minute.</p>\n" "<p>This could free up system resources that a software MIDI synthesizer " "might be using, thus saving battery power.</p>\n" "<p>A side effect is that if you pause a MIDI file for a long time " "the instruments are reset to the default piano (instrument 0). " "In that case, playing the file from the beginning sets up the " "instruments again.</p>\n")) self._pollingLabel.setText(_("Polling time for input:")) self._pollingTime.setToolTip( _("Polling time for MIDI input. " "See \"What's This\" for more information.")) self._pollingTime.setWhatsThis( _("Sets the time between the polling of the MIDI input port in milliseconds. " "Small values lead to faster recognition of incoming MIDI events, but stress " "the CPU. 10 ms should be a good value.")) def loadSettings(self): s = QSettings() self._closeOutputs.setChecked( s.value("midi/close_outputs", False, bool)) self._pollingTime.setValue(s.value("midi/polling_time", 10, int)) def saveSettings(self): s = QSettings() s.setValue("midi/close_outputs", self._closeOutputs.isChecked()) s.setValue("midi/polling_time", self._pollingTime.value())
class ViewSettings(preferences.Group): def __init__(self, page): super(ViewSettings, self).__init__(page) layout = QGridLayout(spacing=1) self.setLayout(layout) self.wrapLines = QCheckBox(toggled=self.changed) self.numContextLines = QSpinBox(minimum=0, maximum=20, valueChanged=self.changed) self.numContextLinesLabel = l = QLabel() l.setBuddy(self.numContextLines) layout.addWidget(self.wrapLines, 0, 0, 1, 1) layout.addWidget(self.numContextLinesLabel, 1, 0) layout.addWidget(self.numContextLines, 1, 1) app.translateUI(self) def translateUI(self): self.setTitle(_("View Preferences")) self.wrapLines.setText(_("Wrap long lines by default")) self.wrapLines.setToolTip('<qt>' + _( "If enabled, lines that don't fit in the editor width are wrapped " "by default. " "Note: when the document is displayed by multiple views, they all " "share the same line wrapping width, which might look strange.")) self.numContextLinesLabel.setText(_("Number of surrounding lines:")) self.numContextLines.setToolTip('<qt>' + _( "When jumping between search results or clicking on a link, the " "text view tries to scroll as few lines as possible. " "Here you can speficy how many surrounding lines at least should " "be visible.")) self.numContextLinesLabel.setToolTip(self.numContextLines.toolTip()) def loadSettings(self): s = QSettings() s.beginGroup("view_preferences") self.wrapLines.setChecked(s.value("wrap_lines", False, bool)) self.numContextLines.setValue(s.value("context_lines", 3, int)) def saveSettings(self): s = QSettings() s.beginGroup("view_preferences") s.setValue("wrap_lines", self.wrapLines.isChecked()) s.setValue("context_lines", self.numContextLines.value())
class ViewSettings(preferences.Group): def __init__(self, page): super(ViewSettings, self).__init__(page) layout = QGridLayout(spacing=1) self.setLayout(layout) self.wrapLines = QCheckBox(toggled=self.changed) self.numContextLines = QSpinBox(minimum=0, maximum=20, valueChanged=self.changed) self.numContextLinesLabel = l = QLabel() l.setBuddy(self.numContextLines) layout.addWidget(self.wrapLines, 0, 0, 1, 1) layout.addWidget(self.numContextLinesLabel, 1, 0) layout.addWidget(self.numContextLines, 1, 1) app.translateUI(self) def translateUI(self): self.setTitle(_("View Preferences")) self.wrapLines.setText(_("Wrap long lines by default")) self.wrapLines.setToolTip('<qt>' + _( "If enabled, lines that don't fit in the editor width are wrapped " "by default. " "Note: when the document is displayed by multiple views, they all " "share the same line wrapping width, which might look strange.")) self.numContextLinesLabel.setText(_("Number of surrounding lines:")) self.numContextLines.setToolTip('<qt>' + _( "When jumping between search results or clicking on a link, the " "text view tries to scroll as few lines as possible. " "Here you can specify how many surrounding lines at least should " "be visible.")) self.numContextLinesLabel.setToolTip(self.numContextLines.toolTip()) def loadSettings(self): s = QSettings() s.beginGroup("view_preferences") self.wrapLines.setChecked(s.value("wrap_lines", False, bool)) self.numContextLines.setValue(s.value("context_lines", 3, int)) def saveSettings(self): s = QSettings() s.beginGroup("view_preferences") s.setValue("wrap_lines", self.wrapLines.isChecked()) s.setValue("context_lines", self.numContextLines.value())
def __init__(self, parent, prefix=None, suffix=None, option=None, min_=None, max_=None, step=None, tip=None, value=None, changed=None): super(MySpinBox, self).__init__(parent) if prefix: plabel = QLabel(prefix) else: plabel = None if suffix: slabel = QLabel(suffix) else: slabel = None spinbox = QSpinBox(parent) if min_ is not None: spinbox.setMinimum(min_) if max_ is not None: spinbox.setMaximum(max_) if step is not None: spinbox.setSingleStep(step) if tip is not None: spinbox.setToolTip(tip) layout = QHBoxLayout() for subwidget in (plabel, spinbox, slabel): if subwidget is not None: layout.addWidget(subwidget) if value is not None: spinbox.setValue(value) if changed is not None: self.connect(spinbox, SIGNAL('valueChanged(int)'), changed) layout.addStretch(1) layout.setContentsMargins(0, 0, 0, 0) self.setLayout(layout) self.spin = spinbox
def _get_pos_widget(name, backgroundColor, foregroundColor): label = QLabel() label.setAttribute(Qt.WA_TransparentForMouseEvents, True) pixmap = QPixmap(25*10, 25*10) pixmap.fill(backgroundColor) painter = QPainter() painter.begin(pixmap) pen = QPen(foregroundColor) painter.setPen(pen) painter.setRenderHint(QPainter.Antialiasing) font = QFont() font.setBold(True) font.setPixelSize(25*10-30) path = QPainterPath() path.addText(QPointF(50, 25*10-50), font, name) brush = QBrush(foregroundColor) painter.setBrush(brush) painter.drawPath(path) painter.setFont(font) painter.end() pixmap = pixmap.scaled(QSize(20,20), Qt.KeepAspectRatio, Qt.SmoothTransformation) label.setPixmap(pixmap) spinbox = QSpinBox() spinbox.setAttribute(Qt.WA_TransparentForMouseEvents, True) spinbox.setEnabled(False) spinbox.setAlignment(Qt.AlignCenter) spinbox.setToolTip("{0} Spin Box".format(name)) spinbox.setButtonSymbols(QAbstractSpinBox.NoButtons) spinbox.setMaximumHeight(20) spinbox.setMaximum(9999) font = spinbox.font() font.setPixelSize(14) spinbox.setFont(font) sheet = TEMPLATE.format(foregroundColor.name(), backgroundColor.name()) spinbox.setStyleSheet(sheet) return label, spinbox
class PointParameterWidget(GenericParameterWidget): """Widget class for Integer parameter.""" def __init__(self, parameter, parent=None): """Constructor .. versionadded:: 2.2 :param parameter: A IntegerParameter object. :type parameter: IntegerParameter """ # Size policy self._spin_box_size_policy = QSizePolicy( QSizePolicy.Fixed, QSizePolicy.Fixed) super(PointParameterWidget, self).__init__(parameter, parent) self._input_x = QSpinBox() self._input_x.setValue(self._parameter.value[0]) tool_tip = 'X' self._input_x.setToolTip(tool_tip) self._input_x.setSizePolicy(self._spin_box_size_policy) self._input_y = QSpinBox() self._input_y.setValue(self._parameter.value[1]) tool_tip = 'Y' self._input_y.setToolTip(tool_tip) self._input_y.setSizePolicy(self._spin_box_size_policy) self._inner_input_layout.addWidget(self._input_x) self._inner_input_layout.addWidget(self._input_y) def get_parameter(self): """Obtain boolean parameter object from the current widget state. :returns: A BooleanParameter from the current state of widget """ self._parameter.value = (self._input_x.value(), self._input_y.value()) return self._parameter
class CADOptionsToolbar_RPolygon(CADOptionsToolbar): def __init__(self): super(CADOptionsToolbar_RPolygon, self).__init__() self.settings = QSettings() self.spinBox = QSpinBox(self.optionsToolBar) self.spinBox.setMinimum(3) self.spinBox.setMaximum(3600) segvalue = self.settings.value("/CADDigitize/rpolygon/nbedges", 5, type=int) if not segvalue: self.settings.setValue("/CADDigitize/rpolygon/nbedges", 5) self.spinBox.setValue(segvalue) self.spinBox.setSingleStep(1) self.spinBoxAction = self.optionsToolBar.addWidget(self.spinBox) self.spinBox.setToolTip(tr(u"Number of edges")) self.spinBoxAction.setEnabled(True) self.spinBox.valueChanged["int"].connect(self.edgesSettingsRPolygon) def edgesSettingsRPolygon(self): self.settings.setValue("/CADDigitize/rpolygon/nbedges", self.spinBox.value())
class CADOptionsToolbar_Ellipse(CADOptionsToolbar): def __init__(self): super(CADOptionsToolbar_Ellipse, self).__init__() self.settings = QSettings() self.spinBox = QSpinBox(self.optionsToolBar) self.spinBox.setMinimum(3) self.spinBox.setMaximum(3600) segvalue = self.settings.value("/CADDigitize/ellipse/segments", 36, type=int) if not segvalue: self.settings.setValue("/CADDigitize/ellipse/segments", 36) self.spinBox.setValue(segvalue) self.spinBox.setSingleStep(1) self.spinBoxAction = self.optionsToolBar.addWidget(self.spinBox) self.spinBox.setToolTip(tr(u"Number of points")) self.spinBoxAction.setEnabled(True) self.spinBox.valueChanged["int"].connect(self.segmentsettingsEllipse) def segmentsettingsEllipse(self): self.settings.setValue("/CADDigitize/ellipse/segments", self.spinBox.value())
class QuadStatusBar(QHBoxLayout): def __init__(self, parent=None ): QHBoxLayout.__init__(self, parent) self.setContentsMargins(0,4,0,0) self.setSpacing(0) def createQuadViewStatusBar(self, xbackgroundColor, xforegroundColor, ybackgroundColor, yforegroundColor, zbackgroundColor, zforegroundColor, graybackgroundColor, grayforegroundColor): self.xLabel = QLabel() self.xLabel.setAttribute(Qt.WA_TransparentForMouseEvents, True) self.addWidget(self.xLabel) pixmap = QPixmap(25*10, 25*10) pixmap.fill(xbackgroundColor) painter = QPainter() painter.begin(pixmap) pen = QPen(xforegroundColor) painter.setPen(pen) painter.setRenderHint(QPainter.Antialiasing) font = QFont() font.setBold(True) font.setPixelSize(25*10-30) path = QPainterPath() path.addText(QPointF(50, 25*10-50), font, "X") brush = QBrush(xforegroundColor) painter.setBrush(brush) painter.drawPath(path) painter.setFont(font) painter.end() pixmap = pixmap.scaled(QSize(20,20),Qt.KeepAspectRatio, Qt.SmoothTransformation) self.xLabel.setPixmap(pixmap) self.xSpinBox = QSpinBox() self.xSpinBox.setAttribute(Qt.WA_TransparentForMouseEvents, True) self.xSpinBox.setEnabled(False) self.xSpinBox.setAlignment(Qt.AlignCenter) self.xSpinBox.setToolTip("xSpinBox") self.xSpinBox.setButtonSymbols(QAbstractSpinBox.NoButtons) self.xSpinBox.setMaximumHeight(20) self.xSpinBox.setMaximum(9999) font = self.xSpinBox.font() font.setPixelSize(14) self.xSpinBox.setFont(font) self.xSpinBox.setStyleSheet("QSpinBox { color: " + str(xforegroundColor.name()) + "; font: bold; background-color: " + str(xbackgroundColor.name()) + "; border:0;}") self.addWidget(self.xSpinBox) self.yLabel = QLabel() self.yLabel.setAttribute(Qt.WA_TransparentForMouseEvents, True) self.addWidget(self.yLabel) pixmap = QPixmap(25*10, 25*10) pixmap.fill(ybackgroundColor) painter = QPainter() painter.begin(pixmap) pen = QPen(yforegroundColor) painter.setPen(pen) painter.setRenderHint(QPainter.Antialiasing) font = QFont() font.setBold(True) font.setPixelSize(25*10-30) path = QPainterPath() path.addText(QPointF(50, 25*10-50), font, "Y") brush = QBrush(yforegroundColor) painter.setBrush(brush) painter.drawPath(path) painter.setFont(font) painter.end() pixmap = pixmap.scaled(QSize(20,20),Qt.KeepAspectRatio, Qt.SmoothTransformation) self.yLabel.setPixmap(pixmap) self.ySpinBox = QSpinBox() self.ySpinBox.setAttribute(Qt.WA_TransparentForMouseEvents, True) self.ySpinBox.setEnabled(False) self.ySpinBox.setAlignment(Qt.AlignCenter) self.ySpinBox.setToolTip("ySpinBox") self.ySpinBox.setButtonSymbols(QAbstractSpinBox.NoButtons) self.ySpinBox.setMaximumHeight(20) self.ySpinBox.setMaximum(9999) font = self.ySpinBox.font() font.setPixelSize(14) self.ySpinBox.setFont(font) self.ySpinBox.setStyleSheet("QSpinBox { color: " + str(yforegroundColor.name()) + "; font: bold; background-color: " + str(ybackgroundColor.name()) + "; border:0;}") self.addWidget(self.ySpinBox) self.zLabel = QLabel() self.zLabel.setAttribute(Qt.WA_TransparentForMouseEvents, True) self.addWidget(self.zLabel) pixmap = QPixmap(25*10, 25*10) pixmap.fill(zbackgroundColor) painter = QPainter() painter.begin(pixmap) pen = QPen(zforegroundColor) painter.setPen(pen) painter.setRenderHint(QPainter.Antialiasing) font = QFont() font.setBold(True) font.setPixelSize(25*10-30) path = QPainterPath() path.addText(QPointF(50, 25*10-50), font, "Z") brush = QBrush(zforegroundColor) painter.setBrush(brush) painter.drawPath(path) painter.setFont(font) painter.end() pixmap = pixmap.scaled(QSize(20,20),Qt.KeepAspectRatio, Qt.SmoothTransformation) self.zLabel.setPixmap(pixmap) self.zSpinBox = QSpinBox() self.zSpinBox.setAttribute(Qt.WA_TransparentForMouseEvents, True) self.zSpinBox.setEnabled(False) self.zSpinBox.setAlignment(Qt.AlignCenter) self.zSpinBox.setToolTip("zSpinBox") self.zSpinBox.setButtonSymbols(QAbstractSpinBox.NoButtons) self.zSpinBox.setMaximumHeight(20) self.zSpinBox.setMaximum(9999) font = self.zSpinBox.font() font.setPixelSize(14) self.zSpinBox.setFont(font) self.zSpinBox.setStyleSheet("QSpinBox { color: " + str(zforegroundColor.name()) + "; font: bold; background-color: " + str(zbackgroundColor.name()) + "; border:0;}") self.addWidget(self.zSpinBox) self.addSpacing(4) self.grayScaleLabel = QLabel() self.grayScaleLabel.setAttribute(Qt.WA_TransparentForMouseEvents, True) self.addWidget(self.grayScaleLabel) pixmap = QPixmap(610, 250) pixmap.fill(graybackgroundColor) painter = QPainter() painter.begin(pixmap) pen = QPen(grayforegroundColor) painter.setPen(pen) painter.setRenderHint(QPainter.Antialiasing) font = QFont() font.setBold(True) font.setPixelSize(25*10-30) path = QPainterPath() path.addText(QPointF(50, 25*10-50), font, "Gray") brush = QBrush(grayforegroundColor) painter.setBrush(brush) painter.drawPath(path) painter.setFont(font) painter.end() pixmap = pixmap.scaled(QSize(61,20),Qt.KeepAspectRatio, Qt.SmoothTransformation) """ self.grayScaleLabel.setPixmap(pixmap) self.grayScaleSpinBox = QSpinBox() self.grayScaleSpinBox.setAttribute(Qt.WA_TransparentForMouseEvents, True) self.grayScaleSpinBox.setEnabled(False) self.grayScaleSpinBox.setAlignment(Qt.AlignCenter) self.grayScaleSpinBox.setToolTip("grayscaleSpinBox") self.grayScaleSpinBox.setButtonSymbols(QAbstractSpinBox.NoButtons) self.grayScaleSpinBox.setMaximum(255) self.grayScaleSpinBox.setMaximumHeight(20) self.grayScaleSpinBox.setMaximum(255) font = self.grayScaleSpinBox.font() font.setPixelSize(14) self.grayScaleSpinBox.setFont(font) self.grayScaleSpinBox.setStyleSheet("QSpinBox { color: " + str(grayforegroundColor.name()) + "; font: bold; background-color: " + str(graybackgroundColor.name()) + "; border:0;}") self.addWidget(self.grayScaleSpinBox) """ self.addStretch() self.positionCheckBox = QCheckBox() self.positionCheckBox.setChecked(True) self.positionCheckBox.setCheckable(True) self.positionCheckBox.setText("Position") self.addWidget(self.positionCheckBox) self.addSpacing(20) self.channelLabel = QLabel("Channel:") self.addWidget(self.channelLabel) self.channelSpinBox = QSpinBox() self.addWidget(self.channelSpinBox) self.addSpacing(20) self.timeLabel = QLabel("Time:") self.addWidget(self.timeLabel) self.timeSpinBox = QSpinBox() self.addWidget(self.timeSpinBox) """ def setGrayScale(self, gray): self.grayScaleSpinBox.setValue(gray) """ def setMouseCoords(self, x, y, z): self.xSpinBox.setValue(x) self.ySpinBox.setValue(y) self.zSpinBox.setValue(z)
class TabLaTeX(Panel_simple): titre = u"Tableaux LaTeX" # Donner un titre a chaque module def __init__(self, *args, **kw): Panel_simple.__init__(self, *args, **kw) self.sizer = QVBoxLayout() self.entree = LigneCommande(self, longueur = 500, action = self.generer_code) self.sizer.addWidget(self.entree) self.sizer_type = QHBoxLayout() self.type_tableau = QComboBox(self) self.type_tableau.addItems([u"Tableau de variations", u"Tableau de signes", u"Tableau de valeurs"]) self.type_tableau.setCurrentIndex(self._param_.mode) self.sizer_type.addWidget(QLabel(u"Type de tableau :", self)) self.sizer_type.addWidget(self.type_tableau) self.sizer_type.addSpacing(15) self.utiliser_cellspace = QCheckBox(u"Utiliser le paquetage cellspace.", self) self.utiliser_cellspace.setChecked(self._param_.utiliser_cellspace) self.utiliser_cellspace.setToolTip(u"Le paquetage cellspace évite que " "certains objets (comme les fractions) touchent les bordures du tableaux.") self.sizer_type.addSpacing(10) self.sizer_type.addWidget(self.utiliser_cellspace) self.derivee = QCheckBox(u"Dérivée.", self) self.derivee.setChecked(self._param_.derivee) self.derivee.setToolTip(u"Afficher une ligne indiquant le signe de la dérivée.") self.sizer_type.addSpacing(10) self.sizer_type.addWidget(self.derivee) self.limites = QCheckBox(u"Limites.", self) self.limites.setChecked(self._param_.limites) self.limites.setToolTip(u"Afficher les limites dans le tableau de variations.") self.sizer_type.addSpacing(10) self.sizer_type.addWidget(self.limites) self.decimales_tabvar = QSpinBox() self.decimales_tabvar.setRange(-1, 20) self.decimales_tabvar.setSuffix(u" décimales") self.decimales_tabvar.setSpecialValueText(u"Valeurs exactes") self.decimales_tabvar.setValue(self._param_.decimales_tabvar) ##self.decimales_tabvar.setAccelerated(True) aide = u"Nombre de décimales pour l'affichage des extrema, ou valeur exacte." self.decimales_tabvar.setToolTip(aide) self.sizer_type.addSpacing(10) self.sizer_type.addWidget(self.decimales_tabvar) self.decimales_tabval = QSpinBox() self.decimales_tabval.setRange(0, 20) self.decimales_tabval.setSuffix(u" décimales") self.decimales_tabval.setValue(self._param_.decimales_tabval) ##self.decimales_tabval.setAccelerated(True) aide = u"Nombre de décimales pour les valeurs du tableau." self.decimales_tabval.setToolTip(aide) self.sizer_type.addSpacing(10) self.sizer_type.addWidget(self.decimales_tabval) self.sizer_type.addSpacing(15) self.lbl_formatage = lbl = QLabel(u"Formatage des résultats :") self.sizer_type.addWidget(lbl) self.formatage_images = QLineEdit() ##self.formatage_images.setMinimumWidth(200) self.formatage_images.setText(self._param_.formatage_images) aide = u"Formatage à appliquer au résultat (VAL est la valeur du résultat)." lbl.setToolTip(aide) self.formatage_images.setToolTip(aide) self.sizer_type.addSpacing(10) self.sizer_type.addWidget(self.formatage_images) self.sizer_type.addStretch() self.sizer.addLayout(self.sizer_type) box = QGroupBox(u"Code LaTeX permettant de de générer le tableau", self) self.bsizer = QVBoxLayout() box.setLayout(self.bsizer) self.code_tableau = QTextEdit(self) self.code_tableau.setMinimumSize(700, 200) self.code_tableau.setReadOnly(True) self.bsizer.addWidget(self.code_tableau) self.copier_code = QPushButton(u"Copier dans le presse-papier", self) self.bsizer.addWidget(self.copier_code) txt = u"Pensez à rajouter dans l'entête de votre fichier LaTeX la ligne suivante :" self.bsizer.addWidget(QLabel(txt, self)) self.sizer_entete = QHBoxLayout() self.code_entete = QLineEdit(self) self.code_entete.setMinimumWidth(200) self.code_entete.setReadOnly(True) self.code_entete.setText(u"\\usepackage{tabvar}") self.sizer_entete.addWidget(self.code_entete) self.copier_entete = QPushButton(u"Copier cette ligne", self) self.sizer_entete.addWidget(self.copier_entete) self.bsizer.addLayout(self.sizer_entete) self.sizer.addWidget(box) self.cb = QCheckBox(u"Copier automatiquement le code LaTeX dans le presse-papier.", self) self.cb.setChecked(self._param_.copie_automatique) self.sizer.addWidget(self.cb) self.setLayout(self.sizer) self.adjustSize() self.type_tableau.currentIndexChanged.connect(self.EvtChoix) self.EvtChoix() def copier_code(): return self.vers_presse_papier(self.code_tableau.toPlainText()) self.copier_code.clicked.connect(copier_code) def copier_entete(): return self.vers_presse_papier(self.code_entete.text()) self.copier_entete.clicked.connect(copier_entete) def regler_mode_copie(): self._param_.copie_automatique = self.cb.isChecked() if self._param_.copie_automatique: copier_code() self.cb.stateChanged.connect(regler_mode_copie) def regler_cellspace(): self._param_.utiliser_cellspace = self.utiliser_cellspace.isChecked() if self._param_.utiliser_cellspace: self.code_entete.setText(u"\\usepackage{cellspace}") else: self.code_entete.setText(u"") self.valider() self.utiliser_cellspace.stateChanged.connect(regler_cellspace) def regler_parametres(event=None): self._param_.derivee = self.derivee.isChecked() self._param_.limites = self.limites.isChecked() self._param_.formatage_images = self.formatage_images.text() self.valider() def regler_decimales(event=None): try: self.focus_widget = app.focusWidget() self._param_.decimales_tabvar = self.decimales_tabvar.value() self._param_.decimales_tabval = self.decimales_tabval.value() self.valider() finally: self.focus_widget = self.entree self.derivee.stateChanged.connect(regler_parametres) self.limites.stateChanged.connect(regler_parametres) self.formatage_images.editingFinished.connect(regler_parametres) self.decimales_tabvar.valueChanged.connect(regler_decimales) self.decimales_tabval.valueChanged.connect(regler_decimales) self.focus_widget = self.entree def activer(self): Panel_simple.activer(self) # Actions à effectuer lorsque l'onglet devient actif self.entree.setFocus() def generer_code(self, commande, **kw): if not commande.strip(): return # Utilisé pour la sauvegarde automatique:x+3 self.modifie = True try: if self._param_.mode == 0: code_latex = tabvar(commande, derivee=self._param_.derivee, limites=self._param_.limites, decimales=self._param_.decimales_tabvar, approche=(self._param_.decimales_tabvar != -1)) elif self._param_.mode == 1: code_latex = tabsign(commande, cellspace=self._param_.utiliser_cellspace) elif self._param_.mode == 2: code_latex = tabval(commande, formatage_antecedents=self._param_.formatage_antecedents, formatage_images=self._param_.formatage_images, precision=10**-self._param_.decimales_tabval) else: warning("Type de tableau non reconnu.") self.code_tableau.setText(code_latex) if self._param_.copie_automatique: self.vers_presse_papier(texte = code_latex) self.focus_widget.setFocus() self.message(u"Le code LaTeX a bien été généré.") except BaseException, erreur: self.message(u"Impossible de générer le code LaTeX. " + message(erreur)) self.code_tableau.setText(u"<i><b>Erreur.</b> Impossible de générer le code LaTeX.</i>") self.entree.setFocus() if param.debug: raise
class Indenting(preferences.Group): def __init__(self, page): super(Indenting, self).__init__(page) layout = QGridLayout(spacing=1) self.setLayout(layout) self.tabwidthBox = QSpinBox(minimum=1, maximum=99) self.tabwidthLabel = l = QLabel() l.setBuddy(self.tabwidthBox) self.nspacesBox = QSpinBox(minimum=0, maximum=99) self.nspacesLabel = l = QLabel() l.setBuddy(self.nspacesBox) self.dspacesBox = QSpinBox(minimum=0, maximum=99) self.dspacesLabel = l = QLabel() l.setBuddy(self.dspacesBox) layout.addWidget(self.tabwidthLabel, 0, 0) layout.addWidget(self.tabwidthBox, 0, 1) layout.addWidget(self.nspacesLabel, 1, 0) layout.addWidget(self.nspacesBox, 1, 1) layout.addWidget(self.dspacesLabel, 2, 0) layout.addWidget(self.dspacesBox, 2, 1) self.tabwidthBox.valueChanged.connect(page.changed) self.nspacesBox.valueChanged.connect(page.changed) self.dspacesBox.valueChanged.connect(page.changed) self.translateUI() def translateUI(self): self.setTitle(_("Indenting Preferences")) self.tabwidthLabel.setText(_("Visible Tab Width:")) self.tabwidthBox.setToolTip(_( "The visible width of a Tab character in the editor.")) self.nspacesLabel.setText(_("Indent text with:")) self.nspacesBox.setToolTip(_( "How many spaces to use for indenting one level.\n" "Move to zero to use a Tab character for indenting.")) self.nspacesBox.setSpecialValueText(_("Tab")) self.dspacesLabel.setText(_("Tab outside indent inserts:")) self.dspacesBox.setToolTip(_( "How many spaces to insert when Tab is pressed outside the indent, " "elsewhere in the document.\n" "Move to zero to insert a literal Tab character in this case.")) self.nspacesBox.setSpecialValueText(_("Tab")) self.dspacesBox.setSpecialValueText(_("Tab")) # L10N: abbreviation for "n spaces" in spinbox, n >= 1, no plural forms prefix, suffix = _("{num} spaces").split("{num}") self.nspacesBox.setPrefix(prefix) self.nspacesBox.setSuffix(suffix) self.dspacesBox.setPrefix(prefix) self.dspacesBox.setSuffix(suffix) def loadSettings(self): s = QSettings() s.beginGroup("indent") self.tabwidthBox.setValue(s.value("tab_width", 8, int)) self.nspacesBox.setValue(s.value("indent_spaces", 2, int)) self.dspacesBox.setValue(s.value("document_spaces", 8, int)) def saveSettings(self): s = QSettings() s.beginGroup("indent") s.setValue("tab_width", self.tabwidthBox.value()) s.setValue("indent_spaces", self.nspacesBox.value()) s.setValue("document_spaces", self.dspacesBox.value())
def initAppletDrawerUi(self): """ Overridden from base class (LayerViewerGui) """ op = self.topLevelOperatorView def configure_update_handlers(qt_signal, op_slot): qt_signal.connect(self.configure_operator_from_gui) op_slot.notifyDirty(self.configure_gui_from_operator) self.__cleanup_fns.append( partial(op_slot.unregisterDirty, self.configure_gui_from_operator)) def control_layout(label_text, widget): row_layout = QHBoxLayout() row_layout.addWidget(QLabel(label_text)) row_layout.addSpacerItem(QSpacerItem(10, 0, QSizePolicy.Expanding)) row_layout.addWidget(widget) return row_layout drawer_layout = QVBoxLayout() channel_button = QPushButton() self.channel_menu = QMenu( self) # Must retain menus (in self) or else they get deleted. channel_button.setMenu(self.channel_menu) channel_button.clicked.connect(channel_button.showMenu) def populate_channel_menu(*args): if sip.isdeleted(channel_button): return self.channel_menu.clear() self.channel_actions = [] for ch in range(op.Input.meta.getTaggedShape()['c']): action = QAction("Channel {}".format(ch), self.channel_menu) action.setCheckable(True) self.channel_menu.addAction(action) self.channel_actions.append(action) configure_update_handlers(action.toggled, op.ChannelSelections) populate_channel_menu() op.Input.notifyMetaChanged(populate_channel_menu) self.__cleanup_fns.append( partial(op.Input.unregisterMetaChanged, populate_channel_menu)) channel_button.setToolTip( "Boundary channel index in the probability map") drawer_layout.addLayout(control_layout("Input Channel", channel_button)) self.channel_button = channel_button threshold_box = QDoubleSpinBox() threshold_box.setDecimals(2) threshold_box.setMinimum(0.00) threshold_box.setMaximum(1.0) threshold_box.setSingleStep(0.1) configure_update_handlers(threshold_box.valueChanged, op.Pmin) threshold_box.setToolTip("Boundary probability threshold") drawer_layout.addLayout(control_layout("Threshold", threshold_box)) self.threshold_box = threshold_box membrane_size_box = QSpinBox() membrane_size_box.setMinimum(0) membrane_size_box.setMaximum(1000000) configure_update_handlers(membrane_size_box.valueChanged, op.MinMembraneSize) membrane_size_box.setToolTip( "Size filter for boundary pieces, in pixels") drawer_layout.addLayout( control_layout("Min Boundary Size", membrane_size_box)) self.membrane_size_box = membrane_size_box seed_presmoothing_box = QDoubleSpinBox() seed_presmoothing_box.setDecimals(1) seed_presmoothing_box.setMinimum(0.0) seed_presmoothing_box.setMaximum(10.0) seed_presmoothing_box.setSingleStep(0.1) configure_update_handlers(seed_presmoothing_box.valueChanged, op.SigmaMinima) seed_presmoothing_box.setToolTip( "Smooth the distance transform map with this sigma") drawer_layout.addLayout( control_layout("Presmooth before Seeds", seed_presmoothing_box)) self.seed_presmoothing_box = seed_presmoothing_box seed_method_combo = QComboBox() seed_method_combo.addItem("Connected") seed_method_combo.addItem("Clustered") configure_update_handlers(seed_method_combo.currentIndexChanged, op.GroupSeeds) seed_method_combo.setToolTip( "Connected: combine directly adjacent pixels into seeds (more superpixels). Clustered: group pixels into seeds by distance heuristic (less superpixels)" ) drawer_layout.addLayout( control_layout("Seed Labeling", seed_method_combo)) self.seed_method_combo = seed_method_combo superpixel_size_box = QSpinBox() superpixel_size_box.setMinimum(0) superpixel_size_box.setMaximum(1000000) configure_update_handlers(superpixel_size_box.valueChanged, op.MinSegmentSize) superpixel_size_box.setToolTip("Minimal size of a superpixel") drawer_layout.addLayout( control_layout("Min Superpixel Size", superpixel_size_box)) self.superpixel_size_box = superpixel_size_box preserve_pmaps_box = QCheckBox() configure_update_handlers(preserve_pmaps_box.toggled, op.PreserveMembranePmaps) preserve_pmaps_box.setToolTip( "Preserve thin structures. Use that option when some of your foreground objects have long and thin parts" ) drawer_layout.addLayout( control_layout("Preserve Thin Structures", preserve_pmaps_box)) self.preserve_pmaps_box = preserve_pmaps_box enable_debug_box = QCheckBox() configure_update_handlers(enable_debug_box.toggled, op.EnableDebugOutputs) drawer_layout.addLayout( control_layout("Show Debug Layers", enable_debug_box)) self.enable_debug_box = enable_debug_box op.Superpixels.notifyReady(self.configure_gui_from_operator) op.Superpixels.notifyUnready(self.configure_gui_from_operator) self.__cleanup_fns.append( partial(op.Superpixels.unregisterReady, self.configure_gui_from_operator)) self.__cleanup_fns.append( partial(op.Superpixels.unregisterUnready, self.configure_gui_from_operator)) self.update_ws_button = QPushButton( "Update Watershed", clicked=self.onUpdateWatershedsButton) drawer_layout.addWidget(self.update_ws_button) drawer_layout.setSpacing(0) drawer_layout.addSpacerItem( QSpacerItem(0, 10, QSizePolicy.Minimum, QSizePolicy.Expanding)) # Finally, the whole drawer widget drawer = QWidget(parent=self) drawer.setLayout(drawer_layout) # Save these members for later use self._drawer = drawer # Initialize everything with the operator's initial values self.configure_gui_from_operator()
class AnimationWindow(PyDialog): """ +-------------------+ | Animation | +-------------------------+ | icase ______ | | scale ______ Default | | time ______ Default | | | | nframes ______ Default | | resolu. ______ Default | | Dir ______ Browse | | iFrame ______ | | | | Animations: | | o Scale, Phase, Time | # TODO: add time | | | x delete images | | x repeat | # TODO: change to an integer | x make gif | | | | Step, RunAll | | Close | +-------------------------+ TODO: add key-frame support """ def __init__(self, data, win_parent=None): PyDialog.__init__(self, data, win_parent) self.set_font_size(data['font_size']) self.istep = 0 self._animate_type = 'time' self._updated_animation = False self._icase = data['icase'] self._default_name = data['name'] self._default_time = data['time'] self._default_fps = data['frames/sec'] self._default_resolution = data['resolution'] self._scale = data['scale'] self._default_scale = data['default_scale'] self._default_is_scale = data['is_scale'] self._phase = data['phase'] self._default_phase = data['default_phase'] self._default_dirname = data['dirname'] self._default_gif_name = os.path.join(self._default_dirname, data['name'] + '.gif') self.animation_types = [ 'Animate Scale', ] #'Animate Phase', #'Animate Time', #'Animate Frequency Sweep' #] self.setWindowTitle('Animate Model') self.create_widgets() self.create_layout() self.set_connections() self.is_gui = False if hasattr(self.win_parent, '_updated_legend'): self.win_parent.is_animate_open = True self.is_gui = True def create_widgets(self): """creates the menu objects""" icase_max = 1000 # TODO: update 1000 self.icase = QLabel("iCase:") self.icase_edit = QSpinBox(self) self.icase_edit.setRange(1, icase_max) self.icase_edit.setSingleStep(1) self.icase_edit.setValue(self._icase) self.icase_edit.setToolTip( 'Case Number for the Scale/Phase Animation Type.\n' 'Defaults to the result you had shown when you clicked "Create Animation".\n' 'iCase can be seen by clicking "Apply" on a result.') self.scale = QLabel("Scale:") self.scale_edit = QLineEdit(str(self._scale)) self.scale_button = QPushButton("Default") self.scale_edit.setToolTip('Scale factor of the "deflection"') self.scale_button.setToolTip('Sets the scale factor of the gif to %s' % self._scale) self.time = QLabel("Total Time (sec):") self.time_edit = QDoubleSpinBox(self) self.time_edit.setValue(self._default_time) self.time_edit.setRange(0.1, 10.0) self.time_edit.setDecimals(2) self.time_edit.setSingleStep(0.1) self.time_button = QPushButton("Default") self.time_edit.setToolTip("Total time of the gif") self.time_button.setToolTip('Sets the total time of the gif to %.2f' % self._default_time) self.fps = QLabel("Frames/Second:") self.fps_edit = QSpinBox(self) self.fps_edit.setRange(1, 60) self.fps_edit.setSingleStep(1) self.fps_edit.setValue(self._default_fps) self.fps_button = QPushButton("Default") self.fps_edit.setToolTip( "A higher FPS is smoother, but may not play well for large gifs") self.fps_button.setToolTip('Sets the FPS to %s' % self._default_fps) self.resolution = QLabel("Resolution Scale:") self.resolution_edit = QSpinBox(self) self.resolution_edit.setRange(1, 5) self.resolution_edit.setSingleStep(1) self.resolution_edit.setValue(self._default_resolution) self.resolution_button = QPushButton("Default") self.resolution_edit.setToolTip( 'Scales the window resolution by an integer factor') self.resolution_button.setToolTip('Sets the resolution to %s' % self._default_resolution) #----------------- # Time plot self.icase_start = QLabel("iCase Start:") self.icase_start_edit = QSpinBox(self) self.icase_start_edit.setRange(0, icase_max) self.icase_start_edit.setSingleStep(1) self.icase_start_edit.setValue(self._icase) self.icase_start_button = QPushButton("Default") self.icase_end = QLabel("iCase End:") self.icase_end_edit = QSpinBox(self) self.icase_end_edit.setRange(0, icase_max) self.icase_end_edit.setSingleStep(1) self.icase_end_edit.setValue(self._icase) self.icase_end_button = QPushButton("Default") self.icase_delta = QLabel("iCase Delta:") self.icase_delta_edit = QSpinBox(self) self.icase_delta_edit.setRange(1, icase_max) self.icase_delta_edit.setSingleStep(1) self.icase_delta_edit.setValue(1) self.icase_delta_button = QPushButton("Default") self.min_value = QLabel("Min Value:") self.min_value_edit = QLineEdit(str(0.)) #self.min_value_edit.setRange(1, 1000) #self.min_value_edit.setSingleStep(1) #self.min_value_edit.setValue(1) self.min_value_button = QPushButton("Default") self.max_value = QLabel("Max Value:") self.max_value_edit = QLineEdit(str(1.)) #self.min_value_edit.setRange(1, 1000) # TODO: update 1000 #self.min_value_edit.setSingleStep(1) #self.min_value_edit.setValue(1) self.max_value_button = QPushButton("Default") self.icase_start_edit.setToolTip('The first frame of the animation') self.icase_end_edit.setToolTip( 'The last frame of the animation\n' 'Assumes icase_start + nframes * icase_delta = icase_end') self.icase_delta_edit.setToolTip( 'The frame step size (to skip non-consecutive results).\n' 'Frame skipping can be used to:\n' " - skip across results that you don't want to plot\n" ' - adjust the FPS') self.min_value_edit.setToolTip( 'Min value of the legend (not supported)') self.max_value_edit.setToolTip( 'Max value of the legend (not supported)') #'time' : 0., #'default_time' : 0, #'icase_start' : 10, #'icase_delta' : 3, #'min_value' : 0., #'max_value' : 1000., self.browse_folder = QLabel('Output Directory:') self.browse_folder_edit = QLineEdit(str(self._default_dirname)) self.browse_folder_button = QPushButton('Browse') self.browse_folder_edit.setToolTip( 'Location to save the png/gif files') self.gif = QLabel("Gif Filename:") self.gif_edit = QLineEdit(str(self._default_name + '.gif')) self.gif_button = QPushButton('Default') self.gif_edit.setToolTip('Name of the gif') self.gif_button.setToolTip('Sets the name of the gif to %s.gif' % self._default_name) # scale / phase self.animate_scale_radio = QRadioButton("Animate Scale") self.animate_phase_radio = QRadioButton("Animate Phase") self.animate_time_radio = QRadioButton("Animate Time") self.animate_freq_sweeep_radio = QRadioButton( "Animate Frequency Sweep") self.animate_scale_radio.setToolTip( 'Animates the scale factor based on the "Animation Type"') self.animate_time_radio.setToolTip('Animates the time/load/mode step') self.animate_scale_radio.setChecked(self._default_is_scale) self.animate_phase_radio.setChecked(not self._default_is_scale) self.animate_time_radio.setChecked(False) msg = 'Scale : Animates the scale factor based on the "Animation Profile"\n' if self._default_phase is None: self.animate_phase_radio.setDisabled(True) self.animate_phase_radio.setToolTip('Animates the phase angle ' '(only for complex results)') msg += 'Phase : Animates the phase angle (only for complex results)\n' else: self.animate_phase_radio.setToolTip("Animates the phase angle") msg += 'Phase : Animates the phase angle\n' msg += ( 'Time : Animates the time/load/mode step\n' 'Freq Sweep : Animates a complex result across a range of frequencies ' '(not supported)\n') self.animate_freq_sweeep_radio.setDisabled(True) self.animate_freq_sweeep_radio.setToolTip( 'Animates a complex result across a range of frequencies (not supported)' ) self.animation_type = QLabel("Animation Type:") animation_type = OrderedDict() #scale_msg = 'Scale\n' #phase_msg = 'Phase\n' #time_msg = 'Time\n' #animation_types = [ #('Animate Scale', scale_msg), #('Animate Phase', phase_msg), #('Animate Time', time_msg), ##'Animate Frequency Sweep' #] if self._phase is not None: self.animation_types.append('Animate Phase') self.animation_types.append('Animate Time') self.animation_profile = QLabel("Animation Profile:") self.animation_profile_edit = QComboBox() for animation_profile in ANIMATION_PROFILES: self.animation_profile_edit.addItem(animation_profile) self.animation_profile_edit.setToolTip('The profile for a scaled GIF') self.animation_type_edit = QComboBox() # TODO: add a tooltip for each item for animation_type in self.animation_types: self.animation_type_edit.addItem(animation_type) #self.animation_type_edit.setToolTip('The profile for a scaled GIF') self.animation_type_edit.setToolTip(msg) self.csv_profile = QLabel("CSV profile:") self.csv_profile_edit = QLineEdit() self.csv_profile_browse_button = QPushButton('Browse') self.csv_profile_edit.setToolTip( 'The path to the CSV file of (Scale1, Scale2, Scale3, ...)') widget = QWidget(self) horizontal_vertical_group = QButtonGroup(widget) horizontal_vertical_group.addButton(self.animate_scale_radio) horizontal_vertical_group.addButton(self.animate_phase_radio) horizontal_vertical_group.addButton(self.animate_time_radio) horizontal_vertical_group.addButton(self.animate_freq_sweeep_radio) # one / two sided self.onesided_radio = QRadioButton("One Sided") self.onesided_radio.setToolTip( "A one sided gif doesn't return to the starting point (e.g., 0 to 360 degrees)" ) self.twosided_radio = QRadioButton("Two Sided") self.twosided_radio.setToolTip( 'A two sided gif returns to the starting point (e.g., 0 to 10 to 0)' ) if self._default_phase is None: self.onesided_radio.setChecked(False) self.twosided_radio.setChecked(True) else: self.onesided_radio.setChecked(True) self.twosided_radio.setChecked(False) widget = QWidget(self) horizontal_vertical_group = QButtonGroup(widget) horizontal_vertical_group.addButton(self.onesided_radio) horizontal_vertical_group.addButton(self.twosided_radio) # animate in gui self.animate_in_gui_checkbox = QCheckBox("Animate In GUI?") self.animate_in_gui_checkbox.setChecked(True) # make images self.make_images_checkbox = QCheckBox("Make images?") self.make_images_checkbox.setChecked(True) # make images self.overwrite_images_checkbox = QCheckBox("Overwrite images?") self.overwrite_images_checkbox.setChecked(True) # delete images when finished self.delete_images_checkbox = QCheckBox("Delete images when finished?") self.delete_images_checkbox.setChecked(True) # endless loop self.repeat_checkbox = QCheckBox("Repeat?") self.repeat_checkbox.setChecked(True) self.repeat_checkbox.setToolTip( "Repeating creates an infinitely looping gif") # endless loop self.make_gif_checkbox = QCheckBox("Make Gif?") if IS_IMAGEIO: self.make_gif_checkbox.setChecked(True) else: self.make_gif_checkbox.setChecked(False) self.make_gif_checkbox.setEnabled(False) self.make_gif_checkbox.setToolTip( 'imageio is not available; install it') # bottom buttons self.step_button = QPushButton("Step") self.stop_button = QPushButton("Stop") self.run_button = QPushButton("Run All") #self.apply_button = QPushButton("Apply") #self.ok_button = QPushButton("OK") self.cancel_button = QPushButton("Close") #self.set_grid_time(enabled=False) #self.set_grid_scale(enabled=self._default_is_scale) if self._default_phase: self.on_animate_phase(force=True) else: self.on_animate_scale(force=True) def set_connections(self): """creates button actions""" self.scale_button.clicked.connect(self.on_default_scale) self.time_button.clicked.connect(self.on_default_time) self.fps_button.clicked.connect(self.on_default_fps) self.resolution_button.clicked.connect(self.on_default_resolution) self.browse_folder_button.clicked.connect(self.on_browse_folder) self.csv_profile_browse_button.clicked.connect(self.on_browse_csv) self.gif_button.clicked.connect(self.on_default_name) self.step_button.clicked.connect(self.on_step) self.stop_button.clicked.connect(self.on_stop) self.run_button.clicked.connect(self.on_run) #self.animate_scale_radio.clicked.connect(self.on_animate_scale) #self.animate_phase_radio.clicked.connect(self.on_animate_phase) #self.animate_time_radio.clicked.connect(self.on_animate_time) self.animation_type_edit.currentIndexChanged.connect(self.on_animate) #self.animate_freq_sweeep_radio #self.apply_button.clicked.connect(self.on_apply) #self.ok_button.clicked.connect(self.on_ok) self.cancel_button.clicked.connect(self.on_cancel) self.animate_in_gui_checkbox.clicked.connect(self.on_animate_in_gui) self.animate_in_gui_checkbox.setChecked(True) self.on_animate_in_gui() def on_animate_in_gui(self): animate_in_gui = self.animate_in_gui_checkbox.isChecked() enable = not animate_in_gui self.make_images_checkbox.setEnabled(enable) self.delete_images_checkbox.setEnabled(enable) self.make_gif_checkbox.setEnabled(enable) self.repeat_checkbox.setEnabled(enable) self.resolution_button.setEnabled(enable) self.resolution_edit.setEnabled(enable) self.gif_edit.setEnabled(enable) self.gif_button.setEnabled(enable) self.browse_folder_button.setEnabled(enable) self.browse_folder_edit.setEnabled(enable) self.step_button.setEnabled(enable) def on_animate(self, value): """ animate pulldown Parameters ---------- value : int index in animation_types """ #animation_types = ['Animate Scale', 'Animate Phase', 'Animate Time', #'Animate Frequency Sweep'] animation_type = self.animation_types[value] if animation_type == 'Animate Scale': self.on_animate_scale() elif animation_type == 'Animate Phase': self.on_animate_phase() elif animation_type == 'Animate Time': self.on_animate_time() else: raise NotImplementedError('value = ', value) def on_animate_time(self, force=False): """enables the secondary input""" #print('on_animate_time') if self._animate_type == 'scale' or force: self.set_grid_scale(False, 'time') self.set_grid_time(True, 'time') self._animate_type = 'time' def on_animate_scale(self, force=False): """enables the secondary input""" #print('on_animate_scale') self.set_grid_scale(True, 'scale') if self._animate_type == 'time' or force: self.set_grid_time(False, 'scale') self._animate_type = 'scale' def on_animate_phase(self, force=False): """enables the secondary input""" #print('on_animate_phase') if self._animate_type == 'scale' or force: self.set_grid_scale(False, 'phase') if self._animate_type == 'time' or force: self.set_grid_time(False, 'phase') self._animate_type = 'phase' def set_grid_scale(self, enabled=True, word=''): """enables/disables the secondary input""" #print('%s-set_grid_scale; enabled = %r' % (word, enabled)) self.animation_profile.setEnabled(enabled) self.animation_profile_edit.setEnabled(enabled) # TODO: doesn't work... #self.csv_profile.setEnabled(enabled) #self.csv_profile_edit.setEnabled(enabled) #self.csv_profile_button.setEnabled(enabled) def set_grid_time(self, enabled=True, word=''): """enables/disables the secondary input""" #print('%s-set_grid_time; enabled = %r' % (word, enabled)) self.icase_start.setEnabled(enabled) self.icase_start_edit.setEnabled(enabled) self.icase_start_button.setEnabled(enabled) self.icase_end.setEnabled(enabled) self.icase_end_edit.setEnabled(enabled) self.icase_end_button.setEnabled(enabled) self.icase_delta.setEnabled(enabled) self.icase_delta_edit.setEnabled(enabled) self.icase_delta_button.setEnabled(enabled) self.min_value.setEnabled(enabled) self.min_value_edit.setEnabled(enabled) self.min_value_button.setEnabled(enabled) self.max_value.setEnabled(enabled) self.max_value_edit.setEnabled(enabled) self.max_value_button.setEnabled(enabled) self.icase.setEnabled(not enabled) self.icase_edit.setEnabled(not enabled) self.fps.setEnabled(not enabled) self.fps_edit.setEnabled(not enabled) self.fps_button.setEnabled(not enabled) def on_browse_folder(self): """opens a folder dialog""" dirname = open_directory_dialog(self, 'Select a Directory') if not dirname: return self.browse_folder_edit.setText(dirname) def on_browse_csv(self): """opens a file dialog""" default_filename = '' file_types = 'Delimited Text (*.txt; *.dat; *.csv)' dirname = open_file_dialog(self, 'Select a CSV File', default_filename, file_types) if not dirname: return self.csv_profile_browse_button.setText(dirname) def on_default_name(self): """sets the default gif name""" self.gif_edit.setText(self._default_name + '.gif') def on_default_scale(self): """sets the default displacement scale factor""" self.scale_edit.setText(str(self._default_scale)) self.scale_edit.setStyleSheet("QLineEdit{background: white;}") def on_default_time(self): """sets the default gif time""" self.time_edit.setValue(self._default_time) def on_default_fps(self): """sets the default FPS""" self.fps_edit.setValue(self._default_fps) def on_default_resolution(self): """sets the default image resolution scale factor""" self.resolution_edit.setValue(self._default_resolution) def create_layout(self): """displays the menu objects""" grid = QGridLayout() grid.addWidget(self.icase, 0, 0) grid.addWidget(self.icase_edit, 0, 1) grid.addWidget(self.scale, 1, 0) grid.addWidget(self.scale_edit, 1, 1) grid.addWidget(self.scale_button, 1, 2) grid.addWidget(self.time, 2, 0) grid.addWidget(self.time_edit, 2, 1) grid.addWidget(self.time_button, 2, 2) # spacer spacer = QLabel('') grid.addWidget(self.fps, 3, 0) grid.addWidget(self.fps_edit, 3, 1) grid.addWidget(self.fps_button, 3, 2) grid.addWidget(self.resolution, 4, 0) grid.addWidget(self.resolution_edit, 4, 1) grid.addWidget(self.resolution_button, 4, 2) grid.addWidget(self.browse_folder, 5, 0) grid.addWidget(self.browse_folder_edit, 5, 1) grid.addWidget(self.browse_folder_button, 5, 2) grid.addWidget(self.gif, 6, 0) grid.addWidget(self.gif_edit, 6, 1) grid.addWidget(self.gif_button, 6, 2) grid.addWidget(self.animation_type, 7, 0) grid.addWidget(self.animation_type_edit, 7, 1) grid.addWidget(spacer, 8, 0) #---------- #Time grid_time = QGridLayout() grid_time.addWidget(self.icase_start, 0, 0) grid_time.addWidget(self.icase_start_edit, 0, 1) #grid_time.addWidget(self.icase_start_button, 0, 2) grid_time.addWidget(self.icase_end, 1, 0) grid_time.addWidget(self.icase_end_edit, 1, 1) #grid_time.addWidget(self.icase_end_button, 1, 2) grid_time.addWidget(self.icase_delta, 2, 0) grid_time.addWidget(self.icase_delta_edit, 2, 1) #grid_time.addWidget(self.icase_delta_button, 2, 2) #grid_time.addWidget(self.min_value, 3, 0) #grid_time.addWidget(self.min_value_edit, 3, 1) #grid_time.addWidget(self.min_value_button, 3, 2) #grid_time.addWidget(self.max_value, 4, 0) #grid_time.addWidget(self.max_value_edit, 4, 1) #grid_time.addWidget(self.max_value_button, 4, 2) grid_time.addWidget(spacer, 5, 0) #-------------- grid_scale = QGridLayout() grid_scale.addWidget(self.animation_profile, 0, 0) grid_scale.addWidget(self.animation_profile_edit, 0, 1) #grid_scale.addWidget(self.csv_profile, 1, 0) #grid_scale.addWidget(self.csv_profile_edit, 1, 1) #grid_scale.addWidget(self.csv_profile_browse_button, 1, 2) self.csv_profile = QLabel("CSV profile:") self.csv_profile_edit = QLineEdit() self.csv_profile_button = QPushButton('Browse') #box_time = QVBoxLayout() # TODO: It's super annoying that the animate time box doesn't # line up with the previous box box_scale = QGroupBox('Animate Scale') box_scale.setLayout(grid_scale) box_time = QGroupBox('Animate Time') box_time.setLayout(grid_time) #---------- grid2 = QGridLayout() #grid2.addWidget(self.animate_scale_radio, 8, 0) #grid2.addWidget(self.animate_phase_radio, 8, 1) #grid2.addWidget(self.animate_time_radio, 8, 2) #grid2.addWidget(self.animate_freq_sweeep_radio, 8, 3) grid2.addWidget(self.animate_in_gui_checkbox, 10, 0) grid2.addWidget(self.make_images_checkbox, 11, 0) #grid2.addWidget(self.overwrite_images_checkbox, 11, 0) grid2.addWidget(self.delete_images_checkbox, 11, 1) grid2.addWidget(self.make_gif_checkbox, 11, 2) grid2.addWidget(self.repeat_checkbox, 12, 0) grid2.addWidget(spacer, 13, 0) grid_hbox = QHBoxLayout() grid_hbox.addWidget(spacer) grid_hbox.addLayout(grid2) grid_hbox.addWidget(spacer) # bottom buttons step_run_box = QHBoxLayout() step_run_box.addWidget(self.step_button) step_run_box.addWidget(self.stop_button) step_run_box.addWidget(self.run_button) ok_cancel_box = QHBoxLayout() ok_cancel_box.addWidget(self.cancel_button) vbox = QVBoxLayout() vbox.addLayout(grid) vbox.addWidget(box_scale) vbox.addWidget(box_time) #vbox.addLayout(checkboxes) vbox.addLayout(grid_hbox) vbox.addStretch() vbox.addLayout(step_run_box) vbox.addLayout(ok_cancel_box) self.setLayout(vbox) def on_step(self): """click the Step button""" passed, validate_out = self.on_validate() if passed: try: self._make_gif(validate_out, istep=self.istep) self.istep += 1 except IndexError: self._make_gif(validate_out, istep=0) self.istep += 1 def on_stop(self): passed, validate_out = self.on_validate() if passed: self._make_gif(validate_out, stop_animation=True) def on_run(self): """click the Run button""" self.istep = 0 passed, validate_out = self.on_validate() if passed: self._make_gif(validate_out, istep=None) return passed def _make_gif(self, validate_out, istep=None, stop_animation=False): """interface for making the gif""" icase, scale, time, fps, animate_in_gui, magnify, output_dir, gifbase = validate_out gif_filename = None if not stop_animation and not animate_in_gui: if gifbase.lower().endswith('.gif'): gifbase = gifbase[:-4] gif_filename = os.path.join(output_dir, gifbase + '.gif') animate_scale = self.animate_scale_radio.isChecked() animate_phase = self.animate_phase_radio.isChecked() animate_time = self.animate_time_radio.isChecked() animate_scale = False animate_phase = False animate_time = False if self._animate_type == 'scale': animate_scale = True elif self._animate_type == 'phase': animate_phase = True elif self._animate_type == 'time': animate_time = True else: raise NotImplementedError(self._animate_type) make_images = self.make_images_checkbox.isChecked() delete_images = self.delete_images_checkbox.isChecked() make_gif = self.make_gif_checkbox.isChecked() key = str(self.animation_profile_edit.currentText()) #profile = ANIMATION_PROFILES[key] #ANIMATION_PROFILES['0 to Scale'] = [0., 1.] #ANIMATION_PROFILES['0 to Scale to 0'] = [0., 1., 0.] if key == '0 to Scale': onesided = True else: onesided = False icase_start = self.icase_start_edit.value() icase_end = self.icase_end_edit.value() icase_delta = self.icase_delta_edit.value() #onesided = self.onesided_radio.isChecked() bool_repeat = self.repeat_checkbox.isChecked( ) # TODO: change this to an integer if bool_repeat: nrepeat = 0 else: nrepeat = 1 #self.out_data['is_shown'] = self.show_radio.isChecked() #icase = self._icase if self.is_gui: self.win_parent.win_parent.make_gif( gif_filename, scale, istep=istep, animate_scale=animate_scale, animate_phase=animate_phase, animate_time=animate_time, icase=icase, icase_start=icase_start, icase_end=icase_end, icase_delta=icase_delta, time=time, onesided=onesided, nrepeat=nrepeat, fps=fps, magnify=magnify, make_images=make_images, delete_images=delete_images, make_gif=make_gif, stop_animation=stop_animation, animate_in_gui=animate_in_gui, ) self.out_data['clicked_ok'] = True self.out_data['close'] = True def on_validate(self): """checks to see if the input is valid""" icase, flag0 = self.check_int(self.icase_edit) scale, flag1 = self.check_float(self.scale_edit) time, flag2 = self.check_float(self.time_edit) fps, flag3 = self.check_float(self.fps_edit) animate_in_gui = self.animate_in_gui_checkbox.isChecked() if animate_in_gui: passed = all([flag0, flag1, flag2, flag3]) return passed, (icase, scale, time, fps, animate_in_gui, None, None, None) magnify, flag4 = self.check_int(self.resolution_edit) output_dir, flag5 = self.check_path(self.browse_folder_edit) gifbase, flag6 = self.check_name(self.gif_edit) passed = all([flag0, flag1, flag2, flag3, flag4, flag5, flag6]) return passed, (icase, scale, time, fps, animate_in_gui, magnify, output_dir, gifbase) @staticmethod def check_name(cell): """verifies that the data is string-able""" cell_value = cell.text() try: text = str(cell_value).strip() except UnicodeEncodeError: cell.setStyleSheet("QLineEdit{background: red;}") return None, False if len(text): cell.setStyleSheet("QLineEdit{background: white;}") return text, True else: cell.setStyleSheet("QLineEdit{background: red;}") return None, False def check_path(self, cell): """verifies that the path exists""" text, passed = self.check_name(cell) if not passed: return None, False if os.path.exists(text): cell.setStyleSheet("QLineEdit{background: white;}") return text, True else: cell.setStyleSheet("QLineEdit{background: red;}") return None, False #def on_ok(self): #"""click the OK button""" #passed = self.on_apply() #if passed: #self.win_parent._animation_window_shown = False #self.close() ##self.destroy() def on_cancel(self): """click the Cancel button""" self.on_stop() self.out_data['close'] = True self.close()
class SizeWidget(QWidget): def __init__(self, obj = None, parent= None): QWidget.__init__(self, parent) self.Settings = obj.Settings self.obj = obj self.Settings.beginGroup("Size") self.marginVar = self.Settings.value('Margin', 3).toString() self.thicknessVar = self.Settings.value('Thickness', 5).toString() self.handlerThicknessVar = self.Settings.value('HThickness', 5).toString() self.handlerLedgeVar = self.Settings.value('HLedge', 3).toString() self.Settings.endGroup() self.testSliders = TestSliders(obj, self) self.VBLayout = QGridLayout() self.marginBox = QSpinBox() self.marginBox.setToolTip("Margin around slider") self.marginBox.setMinimum(3) self.marginBox.setMaximum(400) self.marginBox.setSingleStep(1) self.VBLayout.addWidget(self.marginBox, 0, 0) self.thicknessBox = QSpinBox() self.thicknessBox.setToolTip("Thickness of slider") self.thicknessBox.setMinimum(5) self.thicknessBox.setMaximum(400) self.thicknessBox.setSingleStep(1) self.VBLayout.addWidget(self.thicknessBox, 0, 1) self.handlerThicknessBox = QSpinBox() self.handlerThicknessBox.setToolTip("Thickness of handler") self.handlerThicknessBox.setMinimum(5) self.handlerThicknessBox.setMaximum(100) self.handlerThicknessBox.setSingleStep(1) self.VBLayout.addWidget(self.handlerThicknessBox, 1, 0) self.handlerLedgeBox = QSpinBox() self.handlerLedgeBox.setToolTip("Ledge of handler") self.handlerLedgeBox.setMinimum(3) self.handlerLedgeBox.setMaximum(100) self.handlerLedgeBox.setSingleStep(1) self.VBLayout.addWidget(self.handlerLedgeBox, 1, 1) self.VBLayout.addWidget(self.testSliders, 2, 0, 3, 2, Qt.AlignCenter) self.setLayout(self.VBLayout) self.restoreValues() self.marginBox.valueChanged[int].connect(self.marginSet) self.thicknessBox.valueChanged[int].connect(self.thicknessSet) self.handlerThicknessBox.valueChanged[int].connect(self.handlerThicknessSet) self.handlerLedgeBox.valueChanged[int].connect(self.handlerLedgeSet) def restoreValues(self): self.Settings.beginGroup("Size") self.marginVar = self.Settings.value('Margin', 3).toString() self.thicknessVar = self.Settings.value('Thickness', 5).toString() self.handlerThicknessVar = self.Settings.value('HThickness', 5).toString() self.handlerLedgeVar = self.Settings.value('HLedge', 3).toString() self.Settings.endGroup() self.marginBox.setValue(int(self.marginVar)) self.thicknessBox.setValue(int(self.thicknessVar)) self.handlerThicknessBox.setValue(int(self.handlerThicknessVar)) self.handlerLedgeBox.setValue(int(self.handlerLedgeVar)) def marginSet(self, value = 0): self.marginVar = str(value) self._updateStyle() def thicknessSet(self, value = 0): self.thicknessVar = str(value) self._updateStyle() def handlerThicknessSet(self, value = 0): self.handlerThicknessVar = str(value) self._updateStyle() def handlerLedgeSet(self, value = 0): self.handlerLedgeVar = str(value) self._updateStyle() def _updateStyle(self): self.testSliders.setSlidersStyleSheet() self.obj.colorSelect.testSliders.setSlidersStyleSheet() def setSlidersSize(self, get_Style = None): return self.testSliders.setSlidersSize(\ self.marginVar, self.thicknessVar, \ self.handlerThicknessVar, \ self.handlerLedgeVar, get_Style) def refreshInterfaceSettings(self): self.Settings.beginGroup("Size") self.Settings.setValue('Margin', self.marginVar) self.Settings.setValue('Thickness', self.thicknessVar) self.Settings.setValue('HThickness', self.handlerThicknessVar) self.Settings.setValue('HLedge', self.handlerLedgeVar) self.Settings.endGroup() self.Settings.sync()
class Window(QMainWindow): def __init__(self, parent=None): super(Window, self).__init__(parent) self.image = QImage() self.dirty = False self.filename = None self.dbFilename = None self.mirroredvertically = False self.mirroredhorizontally = False self.printer = None self.exampleForm= None self.matlPopup= None self.matlPropsHere= None self.create_widgets() self.create_actions() self.load_settings() self.setWindowTitle("Thermapythia") self.updateFileMenu() self.openStackupDB() QTimer.singleShot(0, self.loadInitialFile) def create_widgets(self): self.imageLabel = QLabel() self.imageLabel.setMinimumSize(200, 200) self.imageLabel.setAlignment(Qt.AlignCenter) self.imageLabel.setContextMenuPolicy(Qt.ActionsContextMenu) self.setCentralWidget(self.imageLabel) logDockWidget = QDockWidget("Log", self) logDockWidget.setObjectName("LogDockWidget") logDockWidget.setAllowedAreas(Qt.LeftDockWidgetArea| Qt.RightDockWidgetArea) self.listWidget = QListWidget() logDockWidget.setWidget(self.listWidget) self.addDockWidget(Qt.RightDockWidgetArea, logDockWidget) self.sizeLabel = QLabel() self.sizeLabel.setFrameStyle(QFrame.StyledPanel|QFrame.Sunken) status = self.statusBar() status.setSizeGripEnabled(False) status.addPermanentWidget(self.sizeLabel) status.showMessage("Ready", 5000) def create_actions(self): fileNewAction = self.createAction("&New...", self.fileNew, QKeySequence.New, "filenew", "Create an image file") fileOpenAction = self.createAction("&Open...", self.fileOpen, QKeySequence.Open, "fileopen", "Open an existing image file") fileSaveAction = self.createAction("&Save", self.fileSave, QKeySequence.Save, "filesave", "Save the image") fileSaveAsAction = self.createAction("Save &As...", self.fileSaveAs, icon="filesaveas", tip="Save the image using a new name") filePrintAction = self.createAction("&Print", self.filePrint, QKeySequence.Print, "fileprint", "Print the image") fileQuitAction = self.createAction("&Quit", self.close, "Ctrl+Q", "filequit", "Close the application") # createAction(String, slot, shortcut, icon, tip, checkable matlEditAction = self.createAction("&Materials", self.matlEdit, None, "matls", "Edit materials") layerEditAction= self.createAction("&Layers", self.layerEdit, None, "layers", "Edit layers") viaEditAction= self.createAction("&Vias", self.viaEdit, None, "vias", "Edit vias") zzzEditAction= self.createAction("&Zzz", self.zzzEdit, None, "zzz", "Edit zzz") editInvertAction = self.createAction("&Invert", None, "Ctrl+I", "editinvert", "Invert the image's colors", True) editInvertAction.toggled.connect(self.editInvert) editSwapRedAndBlueAction = self.createAction("Sw&ap Red and Blue", None, "Ctrl+A", "editswap", "Swap the image's red and blue color components", True) editSwapRedAndBlueAction.toggled.connect(self.editSwapRedAndBlue) editZoomAction = self.createAction("&Zoom...", self.editZoom, "Alt+Z", "editzoom", "Zoom the image") mirrorGroup = QActionGroup(self) editUnMirrorAction = self.createAction("&Unmirror", None, "Ctrl+U", "editunmirror", "Unmirror the image", True) editUnMirrorAction.toggled.connect(self.editUnMirror) mirrorGroup.addAction(editUnMirrorAction) editMirrorHorizontalAction = self.createAction( "Mirror &Horizontally", None, "Ctrl+H", "editmirrorhoriz", "Horizontally mirror the image", True) editMirrorHorizontalAction.toggled.connect( self.editMirrorHorizontal) mirrorGroup.addAction(editMirrorHorizontalAction) editMirrorVerticalAction = self.createAction("Mirror &Vertically", None, "Ctrl+V", "editmirrorvert", "Vertically mirror the image", True) editMirrorVerticalAction.toggled.connect(self.editMirrorVertical) mirrorGroup.addAction(editMirrorVerticalAction) editUnMirrorAction.setChecked(True) helpAboutAction = self.createAction("&About Thermapythia", self.helpAbout) helpHelpAction = self.createAction("&Help", self.helpHelp, QKeySequence.HelpContents) self.fileMenu = self.menuBar().addMenu("&File") self.fileMenuActions = (fileNewAction, fileOpenAction, fileSaveAction, fileSaveAsAction, None, filePrintAction, fileQuitAction) self.fileMenu.aboutToShow.connect(self.updateFileMenu) stackupMenu = self.menuBar().addMenu("&Stackup") self.addActions(stackupMenu, (matlEditAction, layerEditAction, viaEditAction)) editMenu = self.menuBar().addMenu("&Edit") self.addActions(editMenu, (editInvertAction, editSwapRedAndBlueAction, editZoomAction)) mirrorMenu = editMenu.addMenu(QIcon(":/editmirror.png"), "&Mirror") self.addActions(mirrorMenu, (editUnMirrorAction, editMirrorHorizontalAction, editMirrorVerticalAction)) helpMenu = self.menuBar().addMenu("&Help") self.addActions(helpMenu, (helpAboutAction, helpHelpAction)) fileToolbar = self.addToolBar("File") fileToolbar.setObjectName("FileToolBar") self.addActions(fileToolbar, (fileNewAction, fileOpenAction, fileSaveAsAction)) stackupToolbar = self.addToolBar("Stackup") stackupToolbar.setObjectName("StackupToolBar") self.addActions(stackupToolbar, (matlEditAction, layerEditAction, viaEditAction)) editToolbar = self.addToolBar("Edit") editToolbar.setObjectName("EditToolBar") self.addActions(editToolbar, (editInvertAction, editSwapRedAndBlueAction, editUnMirrorAction, editMirrorVerticalAction, editMirrorHorizontalAction)) self.zoomSpinBox = QSpinBox() self.zoomSpinBox.setRange(1, 400) self.zoomSpinBox.setSuffix(" %") self.zoomSpinBox.setValue(100) self.zoomSpinBox.setToolTip("Zoom the image") self.zoomSpinBox.setStatusTip(self.zoomSpinBox.toolTip()) self.zoomSpinBox.setFocusPolicy(Qt.NoFocus) self.zoomSpinBox.valueChanged.connect(self.showImage) editToolbar.addWidget(self.zoomSpinBox) self.addActions(self.imageLabel, (editInvertAction, editSwapRedAndBlueAction, editUnMirrorAction, editMirrorVerticalAction, editMirrorHorizontalAction)) self.resetableActions = ((editInvertAction, False), (editSwapRedAndBlueAction, False), (editUnMirrorAction, True)) def load_settings(self): settings = QSettings() self.recentFiles = settings.value("RecentFiles").toStringList() self.restoreGeometry( settings.value("MainWindow/Geometry").toByteArray()) self.restoreState(settings.value("MainWindow/State").toByteArray()) def createAction(self, text, slot=None, shortcut=None, icon=None, tip=None, checkable=False): action = QAction(text, self) if icon is not None: action.setIcon(QIcon(":/{0}.png".format(icon))) if shortcut is not None: action.setShortcut(shortcut) if tip is not None: action.setToolTip(tip) action.setStatusTip(tip) if slot is not None: action.triggered.connect(slot) if checkable: action.setCheckable(True) return action def addActions(self, target, actions): for action in actions: if action is None: target.addSeparator() else: target.addAction(action) def closeEvent(self, event): if self.okToContinue(): settings = QSettings() filename = (QVariant(QString(self.filename)) if self.filename is not None else QVariant()) settings.setValue("LastFile", filename) recentFiles = (QVariant(self.recentFiles) if self.recentFiles else QVariant()) settings.setValue("RecentFiles", recentFiles) settings.setValue("MainWindow/Geometry", QVariant( self.saveGeometry())) settings.setValue("MainWindow/State", QVariant( self.saveState())) else: event.ignore() def okToContinue(self): if self.dirty: reply = QMessageBox.question(self, "Thermapythia - Unsaved Changes", "Save unsaved changes?", QMessageBox.Yes|QMessageBox.No|QMessageBox.Cancel) if reply == QMessageBox.Cancel: return False elif reply == QMessageBox.Yes: return self.fileSave() return True def loadInitialFile(self): settings = QSettings() fname = unicode(settings.value("LastFile").toString()) if fname and QFile.exists(fname): self.loadFile(fname) def updateStatus(self, message): self.statusBar().showMessage(message, 5000) self.listWidget.addItem(message) if self.filename is not None: self.setWindowTitle("Thermapythia - {0}[*]".format( os.path.basename(self.filename))) elif not self.image.isNull(): self.setWindowTitle("Thermapythia - Unnamed[*]") else: self.setWindowTitle("Thermapythia[*]") self.setWindowModified(self.dirty) def updateFileMenu(self): self.fileMenu.clear() self.addActions(self.fileMenu, self.fileMenuActions[:-1]) current = (QString(self.filename) if self.filename is not None else None) recentFiles = [] for fname in self.recentFiles: if fname != current and QFile.exists(fname): recentFiles.append(fname) if recentFiles: self.fileMenu.addSeparator() for i, fname in enumerate(recentFiles): action = QAction(QIcon(":/icon.png"), "&{0} {1}".format(i + 1, QFileInfo( fname).fileName()), self) action.setData(QVariant(fname)) action.triggered.connect(self.loadFile) self.fileMenu.addAction(action) self.fileMenu.addSeparator() self.fileMenu.addAction(self.fileMenuActions[-1]) def fileNew(self): if not self.okToContinue(): return dialog = newimagedlg.NewImageDlg(self) if dialog.exec_(): self.addRecentFile(self.filename) self.image = QImage() for action, check in self.resetableActions: action.setChecked(check) self.image = dialog.image() self.filename = None self.dirty = True self.showImage() self.sizeLabel.setText("{0} x {1}".format(self.image.width(), self.image.height())) self.updateStatus("Created new image") def fileOpen(self): if not self.okToContinue(): return dir = (os.path.dirname(self.filename) if self.filename is not None else ".") formats = (["*.{0}".format(unicode(format).lower()) for format in QImageReader.supportedImageFormats()]) fname = unicode(QFileDialog.getOpenFileName(self, "Thermapythia - Choose Image", dir, "Image files ({0})".format(" ".join(formats)))) if fname: self.loadFile(fname) def loadFile(self, fname=None): if fname is None: action = self.sender() if isinstance(action, QAction): fname = unicode(action.data().toString()) if not self.okToContinue(): return else: return if fname: self.filename = None image = QImage(fname) if image.isNull(): message = "Failed to read {0}".format(fname) else: self.addRecentFile(fname) self.image = QImage() for action, check in self.resetableActions: action.setChecked(check) self.image = image self.filename = fname self.showImage() self.dirty = False self.sizeLabel.setText("{0} x {1}".format( image.width(), image.height())) message = "Loaded {0}".format(os.path.basename(fname)) self.updateStatus(message) def addRecentFile(self, fname): if fname is None: return if not self.recentFiles.contains(fname): self.recentFiles.prepend(QString(fname)) while self.recentFiles.count() > 9: self.recentFiles.takeLast() def fileSave(self): if self.image.isNull(): return True if self.filename is None: return self.fileSaveAs() else: if self.image.save(self.filename, None): self.updateStatus("Saved as {0}".format(self.filename)) self.dirty = False return True else: self.updateStatus("Failed to save {0}".format( self.filename)) return False def fileSaveAs(self): if self.image.isNull(): return True fname = self.filename if self.filename is not None else "." formats = (["*.{0}".format(unicode(format).lower()) for format in QImageWriter.supportedImageFormats()]) fname = unicode(QFileDialog.getSaveFileName(self, "Thermapythia - Save Image", fname, "Image files ({0})".format(" ".join(formats)))) if fname: if "." not in fname: fname += ".png" self.addRecentFile(fname) self.filename = fname return self.fileSave() return False def filePrint(self): if self.image.isNull(): return if self.printer is None: self.printer = QPrinter(QPrinter.HighResolution) self.printer.setPageSize(QPrinter.Letter) form = QPrintDialog(self.printer, self) if form.exec_(): painter = QPainter(self.printer) rect = painter.viewport() size = self.image.size() size.scale(rect.size(), Qt.KeepAspectRatio) painter.setViewport(rect.x(), rect.y(), size.width(), size.height()) painter.drawImage(0, 0, self.image) # def openStackupDB(self): if self.dbFilename != None: return self.dbFilename = os.path.join(os.path.dirname(__file__), "stackup.db") create = not QFile.exists(self.dbFilename) db = QSqlDatabase.addDatabase("QSQLITE") db.setDatabaseName(self.dbFilename) if not db.open(): QMessageBox.warning(None, "Can't open stackup database", QString("Database Error: %1").arg(db.lastError().text())) sys.exit(1) if create == False: self.updateStatus("Found stackup database file: " + str(self.dbFilename)) self.createDatabaseTables() with open('test2.js', "r") as jsonHandle: jsonContents= jsonHandle.read() config= yaml.load(jsonContents) matlCount= self.countDatabaseTableRows("matl") if matlCount == 0: self.updateStatus("material editor call goes here.") # # TODO: Put the guess-what-I'm thinking Qt table editor thing here. # # self.loadDefaultMatls() matls = Matls.Matls(config['matl_config']) self.loadDefaultData('matl', matls) viaCount= self.countDatabaseTableRows("via") if viaCount == 0: vias = Vias.Vias(config['via_config']) self.loadDefaultData('via', vias) layerCount= self.countDatabaseTableRows("layer") if layerCount == 0: layers = Layers.Layers(config['layer_config']) self.loadDefaultData('layer', layers) # initialize zzz new content here, perhaps def createDatabaseTables(self): query = QSqlQuery() self.updateStatus("Creating database tables") # "id" INTEGER PRIMARY KEY AUTOINCREMENT UNIQUE NOT NULL, statusMatl = query.exec_("""CREATE TABLE IF NOT EXISTS "matl" ( "name" TEXT, "type" TEXT, "density" real, "color" TEXT, "specific_heat" real, "conductivity" real, "conductivityXX" real, "conductivityYY" real, "conductivityZZ" real, "reflection_coeff" real, "emissivity" real, "max_height" real, "thickness" real );""") if statusMatl == False: self.updateStatus("Could not create material property database table 'matl'") self.updateStatus("Database error message: " + query.lastError().text()) statusPhylayer = query.exec_("""CREATE TABLE IF NOT EXISTS "layer" ( "id" INTEGER PRIMARY KEY AUTOINCREMENT UNIQUE NOT NULL, "name" TEXT, "matl" TEXT, "type" TEXT, "thickness" real, "displaces" TEXT, "coverage" real, "z_bottom" real, "z_top" real, "adheres_to" TEXT);""") if statusPhylayer == False: self.updateStatus("Could not create material property database table 'layer'") self.updateStatus("Database error message: " + query.lastError().text()) statusVia = query.exec_("""CREATE TABLE IF NOT EXISTS "via" ( "id" INTEGER PRIMARY KEY AUTOINCREMENT UNIQUE NOT NULL, "name" TEXT, "matl" TEXT, "to" TEXT, "from" TEXT);""") if statusVia == False: self.updateStatus("Could not create material property database table 'via'") self.updateStatus("Database error message: " + query.lastError().text()) def countDatabaseTableRows(self, tablename): query = QSqlQuery() self.updateStatus("Loading database tables") query.prepare("select count(*) from " + tablename + ";") status = query.exec_() if status == False: self.updateStatus("Could not count entries in table '" + tablename + "'") self.updateStatus("Database error message: " + query.lastError().text()) query.first() count, ok = query.value(0).toInt() # self.updateStatus("There are " + str(count) + " rows in the " + tablename + " table") return count def loadDefaultData(self, table, data): query = QSqlQuery() insertList= "', '".join(data.tableCols) insertList= "'" + insertList + "'" colCount= len(data.tableCols) quest= "" for i in range(0, colCount): quest = quest + "?," quest= quest[:-1] sql= "INSERT INTO " + table + "(" + insertList + ") VALUES (" + quest + ");" # self.updateStatus(sql) status= query.prepare(sql) if status == False: self.updateStatus("Could not prepare material property database table " + table) self.updateStatus("Database error message: " + query.lastError().text()) for row in data.propDict: for prop in data.tableCols: propval= data.propDict[row][prop] if data.tableColSQLTypes[prop] == 'TEXT': query.addBindValue(QVariant(QString(propval))) # self.updateStatus("Setting TEXT property " + prop + " to value " + str(propval) + " in row " + str(row)) elif data.tableColSQLTypes[prop] == 'real': if (propval == '-'): propreal= -999.9 else: propreal= float(propval) query.addBindValue(QVariant(propreal)) # self.updateStatus("Setting real property " + prop + " to value " + str(propreal) + " in row " + str(row)) status= query.exec_() if status == False: self.updateStatus("Could not load property database table " + table + " with " + str(row)) self.updateStatus("Database error message: " + query.lastError().text()) def matlEdit(self): self.dirty= True self.updateStatus("Call edit material code here") # This ends up in a little child window self.matlPopup= QLabel("<font color=green size=72><b> Material Editor </b></font>") # self.matlPopup.setWindowFlags(Qt.SplashScreen) self.matlPopup.setWindowTitle("Material edit popup") self.matlPropsHere= QLabel("<font color=red size=24><b> Data goes here </b></font>") # self.matlPopup.setWindowFlags(Qt.SplashScreen) if 1 == 0: dataLayout= QVBoxLayout() dataLayout.addWidget(self.matlPopup) dataLayout.addWidget(self.matlPropsHere) self.setLayout(dataLayout) self.matlPopup.show() self.matlPropsHere.show() # self.exampleForm= MatlForm() # First need a layout manager, and add the widget to that. # Then attach the layout manager to a window. # addWidget(self.exampleForm) # self.exampleForm.show() QTimer.singleShot(5000, self.update) self.updateStatus("Created stackup db") def layerEdit(self): self.dirty= True self.updateStatus("Call edit layer code here") # This way of doing it is modal - window doesn't go away and covers up other windows until it is dismissed. form= MatlForm() form.exec_() def viaEdit(self): self.dirty= True self.updateStatus("Call edit via code here") def zzzEdit(self): self.dirty= True self.updateStatus("Call code to be triggered by zzz button here") def editInvert(self, on): if self.image.isNull(): return self.image.invertPixels() self.showImage() self.dirty = True self.updateStatus("Inverted" if on else "Uninverted") def editSwapRedAndBlue(self, on): if self.image.isNull(): return self.image = self.image.rgbSwapped() self.showImage() self.dirty = True self.updateStatus(("Swapped Red and Blue" if on else "Unswapped Red and Blue")) def editUnMirror(self, on): if self.image.isNull(): return if self.mirroredhorizontally: self.editMirrorHorizontal(False) if self.mirroredvertically: self.editMirrorVertical(False) def editMirrorHorizontal(self, on): if self.image.isNull(): return self.image = self.image.mirrored(True, False) self.showImage() self.mirroredhorizontally = not self.mirroredhorizontally self.dirty = True self.updateStatus(("Mirrored Horizontally" if on else "Unmirrored Horizontally")) def editMirrorVertical(self, on): if self.image.isNull(): return self.image = self.image.mirrored(False, True) self.showImage() self.mirroredvertically = not self.mirroredvertically self.dirty = True self.updateStatus(("Mirrored Vertically" if on else "Unmirrored Vertically")) def editZoom(self): if self.image.isNull(): return percent, ok = QInputDialog.getInteger(self, "Thermapythia - Zoom", "Percent:", self.zoomSpinBox.value(), 1, 400) if ok: self.zoomSpinBox.setValue(percent) def showImage(self, percent=None): if self.image.isNull(): return if percent is None: percent = self.zoomSpinBox.value() factor = percent / 100.0 width = self.image.width() * factor height = self.image.height() * factor image = self.image.scaled(width, height, Qt.KeepAspectRatio) self.imageLabel.setPixmap(QPixmap.fromImage(image)) def helpAbout(self): QMessageBox.about(self, "About Thermapythia", """<b>Thermapythia</b> v {0} <p>Thermal Analyzer in Python predicts circuit board temperature <p>Python {1} - Qt {2} - PyQt {3} on {4}""".format( __version__, platform.python_version(), QT_VERSION_STR, PYQT_VERSION_STR, platform.system())) def helpHelp(self): form = HelpForm.HelpForm("index.html", self) form.show()
class Img2GifWidget(QDialog): AppName = u"GIF生成工具" def __init__(self, parent=None): super(Img2GifWidget, self).__init__(parent) self.setWindowTitle(Img2GifWidget.AppName) self.listWidget = QListWidget() self.listWidget.setMinimumSize(400, 300) self.btnAdd = QPushButton("&Add") self.btnUp = QPushButton("&Up") self.btnDown = QPushButton("&Down") self.btnDel = QPushButton("&Delete") self.btnClear = QPushButton("&Clear") topLeftLay = QVBoxLayout() topLeftLay.addWidget(self.btnAdd) topLeftLay.addWidget(self.btnUp) topLeftLay.addWidget(self.btnDown) topLeftLay.addWidget(self.btnDel) topLeftLay.addWidget(self.btnClear) topLeftLay.addStretch() topLay = QHBoxLayout() topLay.addWidget(self.listWidget) topLay.addLayout(topLeftLay) label = QLabel(u"Gif文件路径:") self.txtGifPath = QLineEdit() self.btnBrowser = QPushButton('...') midLay = QHBoxLayout() midLay.addWidget(label) midLay.addWidget(self.txtGifPath) midLay.addWidget(self.btnBrowser) timeLabel = QLabel(u"时间间隔:") self.spbTime = QDoubleSpinBox() self.spbTime.setRange(0.001, 10) self.spbTime.setSingleStep(0.001) self.spbTime.setValue(1) self.spbTime.setSuffix('s') loopLabel = QLabel(u"循环:") self.spbLoop = QDoubleSpinBox() self.spbLoop = QSpinBox() self.spbLoop.setRange(0, 1000) self.spbLoop.setSingleStep(1) self.spbLoop.setValue(0) self.spbLoop.setToolTip(u"0次循环表示永久循环") self.spbLoop.setSuffix(u"次") self.btnBox = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel) bottomLay = QHBoxLayout() bottomLay.addWidget(timeLabel) bottomLay.addWidget(self.spbTime) bottomLay.addWidget(loopLabel) bottomLay.addWidget(self.spbLoop) bottomLay.addStretch() bottomLay.addWidget(self.btnBox) mainLay = QVBoxLayout() mainLay.addLayout(topLay) mainLay.addLayout(midLay) mainLay.addLayout(bottomLay) self.setLayout(mainLay) self.btnAdd.clicked.connect(self.itemAdd) self.btnUp.clicked.connect(self.itemUp) self.btnDown.clicked.connect(self.itemDown) self.btnDel.clicked.connect(self.itemDel) self.btnClear.clicked.connect(self.listWidget.clear) self.btnBrowser.clicked.connect(self.setGifPath) self.btnBox.rejected.connect(self.close) self.btnBox.accepted.connect(self.makeGif) self.txtGifPath.returnPressed.connect(self.updateGifPath) def itemAdd(self): fileNames = QFileDialog.getOpenFileNames(None, u"{0} -- {1}".format(qApp.applicationName(), Img2GifWidget.AppName), '.', u'所有文件(*.*);;BMP文件(*.bmp);;PNG文件(*.png);;JPG文件(*.jpg *.jpeg)') for fn in fileNames: f = QFileInfo(fn) if unicode(f.suffix().toLower()) in ['jpg', 'png', 'bmp', 'jpeg']: self.listWidget.addItem(fn) def itemUp(self): row = self.listWidget.currentRow() if row <= 0: return item = self.listWidget.currentItem() self.listWidget.takeItem(row) self.listWidget.insertItem(row - 1, item) self.listWidget.setCurrentRow(row - 1) def itemDown(self): rows = self.listWidget.count() row = self.listWidget.currentRow() if (row < 0) or (row == rows - 1): return item = self.listWidget.currentItem() self.listWidget.takeItem(row) self.listWidget.insertItem(row + 1, item) self.listWidget.setCurrentRow(row + 1) def itemDel(self): row = self.listWidget.currentRow() if row >= 0: self.listWidget.takeItem(row) def setGifPath(self): filename = QFileDialog.getSaveFileName(self, u"{0} -- {1}".format(qApp.applicationName(), Img2GifWidget.AppName), ".", "Gif(*.gif)") self.txtGifPath.setText(filename) def updateGifPath(self): fileName = self.txtGifPath.text() f = QFileInfo(fileName) if f.dir().exists and not f.baseName().isEmpty() and not f.suffix().isEmpty(): self.txtGifPath.setText(fileName) return True else: QMessageBox.warning(self, u"{0} -- warning".format(Img2GifWidget.AppName), u"要生成的GIF存储路径{0}不是有效的GIF文件".format(unicode(fileName))) return False def makeGif(self): imgs = [unicode(self.listWidget.item(i).text()) for i in range(self.listWidget.count())] if len(imgs) <= 1: QMessageBox.warning(self, u"{0} - {1}".format(qApp.applicationName(), Img2GifWidget.AppName), u"GIF动画文件必须要给定大于一张图片。") return if not self.updateGifPath(): return durations = self.spbTime.value() loops = self.spbLoop.value() ok, msg = img2gif.images2gif(imgs, self.txtGifPath.text(), durations=durations, loops=loops) if ok: QMessageBox.about(self, u"{0} - {1}".format(qApp.applicationName(), Img2GifWidget.AppName), u"Succeed!\n{0}".format(msg)) qApp.processEvents() else: QMessageBox.about(u"{0} - {1}".format(qApp.applicationName(), Img2GifWidget.AppName), u"sorry! Failed to generate the {0}".format(unicode(self.txtGifPath)))
class VocalPart(_base.Part): """Base class for vocal parts.""" midiInstrument = 'choir aahs' def createWidgets(self, layout): self.createStanzaWidget(layout) self.createAmbitusWidget(layout) def translateWidgets(self): self.translateStanzaWidget() self.translateAmbitusWidget() def createStanzaWidget(self, layout): self.stanzas = QSpinBox(minimum=1, maximum=99, value=1) self.stanzasLabel = QLabel() self.stanzasLabel.setBuddy(self.stanzas) box = QHBoxLayout(spacing=0) box.addWidget(self.stanzasLabel) box.addWidget(self.stanzas) layout.addLayout(box) def translateStanzaWidget(self): self.stanzasLabel.setText(_("Stanzas:")) self.stanzas.setToolTip(_("The number of stanzas.")) def createAmbitusWidget(self, layout): self.ambitus = QCheckBox() layout.addWidget(self.ambitus) def translateAmbitusWidget(self): self.ambitus.setText(_("Ambitus")) self.ambitus.setToolTip(_( "Show the pitch range of the voice at the beginning of the staff.")) def assignLyrics(self, data, name, verse=0): """Creates an empty assignment for lyrics. Returns the assignment. """ l = ly.dom.LyricMode() if verse: name = name + ly.util.int2text(verse) ly.dom.Line('\\set stanza = "{0}."'.format(verse), l) a = data.assign(name) a.append(l) ly.dom.LineComment(_("Lyrics follow here."), l) ly.dom.BlankLine(l) return a def addStanzas(self, data, node): """Add stanzas to the given (Voice) node. The stanzas (as configured in self.stanzas.value()) are added using \\addlyrics. """ if self.stanzas.value() == 1: ly.dom.Identifier(self.assignLyrics(data, 'verse').name, ly.dom.AddLyrics(node)) else: for i in range(self.stanzas.value()): ly.dom.Identifier(self.assignLyrics(data, 'verse', i + 1).name, ly.dom.AddLyrics(node))
class LayoutWindow(QWidget): SLIDER_RESOLUTION = 1000 DIAL_RESOLUTION = 50 def __init__(self,parent=None): QWidget.__init__(self,parent) self.initWidgets() def initWidgets(self): self.ui_VideoFrame = VideoWidget(self) self.ui_Slider = QtGui.QSlider(QtCore.Qt.Horizontal) #contribution: #self.ui_Slider.setStyleSheet(stylesheet(self)) self.ui_Slider.setMinimum(0) self.ui_Slider.setMaximum(self.SLIDER_RESOLUTION) self.ui_Slider.setToolTip("Video track") #self.ui_Slider.setTickPosition(Qt.TicksAbove) self.ui_Dial = QDial(self) self.ui_Dial.setProperty("value", 0) self.ui_Dial.setNotchesVisible(True) self.ui_Dial.setWrapping(False) self.ui_Dial.setNotchTarget(5.0) self.ui_Dial.setToolTip("Fine tuning") self.setDialResolution(self.DIAL_RESOLUTION) self.ui_GotoField = QSpinBox(self) self.ui_GotoField.setValue(1) self.ui_GotoField.setToolTip("Goto Frame") self.ui_InfoLabel = QLabel(self) changeBackgroundColor(self.ui_InfoLabel , "lightblue") self.ui_InfoLabel.setText("") self.ui_InfoLabel.setToolTip("Infos about the video position") self.ui_CB_Reencode = QCheckBox(self) self.ui_CB_Reencode.setText("Exact cut") self.ui_CB_Reencode.setChecked(False) self.ui_CB_Reencode.setToolTip("Exact cut is slow, but precise") self.ui_List = self.__createListWidget() #self._listSplitter = QSplitter() ->add as widget...+QVBoxLayout #self._listSplitter.addWidget(iconList) #status bar self.statusbar = QStatusBar(self) self.statusbar.setSizeGripEnabled(True) self.statusbar.showMessage("Idle") self.statusbar.addPermanentWidget(self.__createProgressBar()) self.setLayout(self.makeGridLayout()) self.adjustSize() def makeGridLayout(self): gridLayout = QGridLayout() self.ui_List.setSizePolicy(QSizePolicy.Minimum,QSizePolicy.Expanding) gridLayout.addWidget(self.ui_List,0,0,5,1) #row column, rowSpan, columnSpan gridLayout.addWidget(self.ui_VideoFrame,0,2,3,-1); gridLayout.addWidget(self.ui_GotoField,4,1,1,20) gridLayout.addWidget(self.ui_InfoLabel,4,26,1,90) gridLayout.addWidget(self.ui_CB_Reencode,4,121) gridLayout.addWidget(self.ui_Slider,5,0,1,120) gridLayout.addWidget(self.ui_Dial,5,121) gridLayout.addWidget(self.statusbar,6,0,1,122) return gridLayout def makeBoxLayout(self): vbox = QVBoxLayout() vbox.addWidget(self.ui_VideoFrame) vbox.addWidget(self.ui_InfoLabel ); slidehbox = QHBoxLayout() slidehbox.addWidget(self.ui_Slider) slidehbox.addWidget(self.ui_Dial) midHBox = QHBoxLayout() midHBox.addWidget(self.ui_List) self.ui_List.setSizePolicy(QSizePolicy.Minimum,QSizePolicy.Expanding) midHBox.addLayout(vbox) mainVBox = QVBoxLayout() mainVBox.addLayout(midHBox) mainVBox.addStretch(1) mainVBox.addLayout(slidehbox) return mainVBox def showInfo(self,text): self.ui_InfoLabel.setText(text) def showStatusMessage(self,text): self.statusbar.showMessage(text) def setDialResolution(self,resolution): self.ui_Dial.setMinimum(-resolution/2) self.ui_Dial.setMaximum(resolution/2) def syncSliderPos(self,pos): self.ui_Slider.setSliderPosition(pos) def setSliderTicks(self,ticks): self.ui_Slider.setSingleStep(ticks) self.ui_Slider.setPageStep(ticks*2) def setGotoFieldMaximum(self,count): self.ui_GotoField.setMaximum(count) def clearVideoFrame(self): self.ui_VideoFrame.showFrame(None) ### Marks def addCutMark(self,frame,cutEntry,rowIndex): item = QListWidgetItem() img = CVImage(frame).scaled(self.ui_VideoFrame.imageRatio*SIZE_ICON, SIZE_ICON) pix = QtGui.QPixmap.fromImage(img) item.setIcon(QIcon(pix)) if cutEntry.isStartMode(): item.setBackgroundColor(QColor(224,255,224)) else: item.setBackgroundColor(QColor(255,224,224)) self.ui_List.insertItem(rowIndex,item) text = "%s <br> F: %s<br> T: %s" %(cutEntry.modeString,str(cutEntry.frameNumber),str(cutEntry.getTimeString())) marker = QLabel(text) marker.setWordWrap(True) marker.layout() self.ui_List.setItemWidget(item,marker) self.ui_List.setIconSize(QSize(SIZE_ICON,SIZE_ICON)) #Forces an update! self.ui_List.setCurrentItem(item) def hookEvents(self,aVideoController): self.__videoController=aVideoController #for menu callbacks self.ui_Slider.valueChanged.connect(aVideoController.sliderMoved) self.ui_Dial.valueChanged.connect(aVideoController.dialChanged) self.ui_Dial.sliderReleased.connect(self.__resetDial) self.ui_GotoField.editingFinished.connect(self.__gotoFrame) self.ui_CB_Reencode.stateChanged.connect(aVideoController.setExactCut) self.statusMessenger = StatusDispatcher() self.connect(self.statusMessenger,self.statusMessenger.signal,self.showStatusMessage) self._hookListActions() def keyReleaseEvent(self,event): self.__resetDial() def _hookListActions(self): #TOO bad-the list model -should be here... rmAction = QtGui.QAction(QtGui.QIcon('icons/close-x.png'), 'Delete', self) rmAction.triggered.connect(self._removeMarker) rmAllAction = QtGui.QAction(QtGui.QIcon('icons/clear-all.png'), 'Remove all', self) rmAllAction.triggered.connect(self.purgeMarker) self.gotoAction = QtGui.QAction(QtGui.QIcon('icons/go-next.png'), 'Goto', self) self.gotoAction.triggered.connect(self._gotoFromMarker) #menus self.ui_List.customContextMenuRequested.connect(self._openListMenu) self._listMenu = QMenu() self._listMenu.addAction(self.gotoAction) self._listMenu.addSeparator() self._listMenu.addAction(rmAction) self._listMenu.addAction(rmAllAction) def __resetDial(self): self.ui_Dial.setProperty("value", 0) def __gotoFrame(self): self.__videoController._gotoFrame(self.ui_GotoField.value()) def __createProgressBar(self): self.progressBar = QtGui.QProgressBar(self) #self.progressBar.setRange(0,1) #self.progressBar.setValue(-1) #self.progressBar.reset() self.progressBar.setMinimum(0) self.progressBar.setMaximumWidth(150) self.progressBar.setVisible(False) return self.progressBar def showBusy(self): self.progressBar.setRange(0,0) self.progressBar.setVisible(True) def stopProgress(self): self.progressBar.setVisible(False) def __createListWidget(self): iconList=QListWidget() iconList.setAlternatingRowColors(True) iconList.setContextMenuPolicy(Qt.CustomContextMenu) #iconList.setStyleSheet("QListWidget { background: red; } QListWidget::item { background: yellow; } QListWidget::item:selected { background: blue; }") iconList.setStyleSheet("QListWidget::item:selected:active { background: #28D9FF; color:#FFFFFF; } ")#that text color seems not to work! return iconList #---List widget context menu def _removeMarker(self,whatis): selectionList = self.ui_List.selectedIndexes() if len(selectionList)==0: return item = selectionList[0] self.ui_List.takeItem(item.row()) self.__videoController.removeVideoCutIndex(item.row()) def clearMarkerList(self): self.ui_List.clear() #remove contents, remove file def purgeMarker(self): self.ui_List.clear() self.__videoController.purgeVideoCuts() def _gotoFromMarker(self,whatis): selectionList = self.ui_List.selectedIndexes() if len(selectionList)==0: return item = selectionList[0] self.__videoController.gotoCutIndex(item.row()) def _openListMenu(self,position): selectionList = self.ui_List.selectedIndexes() if len(selectionList)==0: return self._listMenu.exec_(self.ui_List.viewport().mapToGlobal(position))
class Window(QMainWindow): def __init__(self, parent=None): super(Window, self).__init__(parent) self.image = QImage() self.dirty = False self.filename = None self.mirroredvertically = False self.mirroredhorizontally = False self.printer = None self.create_widgets() self.create_actions() self.load_settings() self.setWindowTitle("Image Changer") self.updateFileMenu() QTimer.singleShot(0, self.loadInitialFile) def create_widgets(self): self.imageLabel = QLabel() self.imageLabel.setMinimumSize(200, 200) self.imageLabel.setAlignment(Qt.AlignCenter) self.imageLabel.setContextMenuPolicy(Qt.ActionsContextMenu) self.setCentralWidget(self.imageLabel) logDockWidget = QDockWidget("Log", self) logDockWidget.setObjectName("LogDockWidget") logDockWidget.setAllowedAreas(Qt.LeftDockWidgetArea| Qt.RightDockWidgetArea) self.listWidget = QListWidget() logDockWidget.setWidget(self.listWidget) self.addDockWidget(Qt.RightDockWidgetArea, logDockWidget) self.sizeLabel = QLabel() self.sizeLabel.setFrameStyle(QFrame.StyledPanel|QFrame.Sunken) status = self.statusBar() status.setSizeGripEnabled(False) status.addPermanentWidget(self.sizeLabel) status.showMessage("Ready", 5000) def create_actions(self): fileNewAction = self.createAction("&New...", self.fileNew, QKeySequence.New, "filenew", "Create an image file") fileOpenAction = self.createAction("&Open...", self.fileOpen, QKeySequence.Open, "fileopen", "Open an existing image file") fileSaveAction = self.createAction("&Save", self.fileSave, QKeySequence.Save, "filesave", "Save the image") fileSaveAsAction = self.createAction("Save &As...", self.fileSaveAs, icon="filesaveas", tip="Save the image using a new name") filePrintAction = self.createAction("&Print", self.filePrint, QKeySequence.Print, "fileprint", "Print the image") fileQuitAction = self.createAction("&Quit", self.close, "Ctrl+Q", "filequit", "Close the application") editInvertAction = self.createAction("&Invert", None, "Ctrl+I", "editinvert", "Invert the image's colors", True) editInvertAction.toggled.connect(self.editInvert) editSwapRedAndBlueAction = self.createAction("Sw&ap Red and Blue", None, "Ctrl+A", "editswap", "Swap the image's red and blue color components", True) editSwapRedAndBlueAction.toggled.connect(self.editSwapRedAndBlue) editZoomAction = self.createAction("&Zoom...", self.editZoom, "Alt+Z", "editzoom", "Zoom the image") editResizeAction = self.createAction("&Resize...", self.editResize, "Ctrl+R", "editresize", "Resize the image") mirrorGroup = QActionGroup(self) editUnMirrorAction = self.createAction("&Unmirror", None, "Ctrl+U", "editunmirror", "Unmirror the image", True) editUnMirrorAction.toggled.connect(self.editUnMirror) mirrorGroup.addAction(editUnMirrorAction) editMirrorHorizontalAction = self.createAction( "Mirror &Horizontally", None, "Ctrl+H", "editmirrorhoriz", "Horizontally mirror the image", True) editMirrorHorizontalAction.toggled.connect( self.editMirrorHorizontal) mirrorGroup.addAction(editMirrorHorizontalAction) editMirrorVerticalAction = self.createAction( "Mirror &Vertically", None, "Ctrl+V", "editmirrorvert", "Vertically mirror the image", True) editMirrorVerticalAction.toggled.connect(self.editMirrorVertical) mirrorGroup.addAction(editMirrorVerticalAction) editUnMirrorAction.setChecked(True) helpAboutAction = self.createAction("&About Image Changer", self.helpAbout) helpHelpAction = self.createAction("&Help", self.helpHelp, QKeySequence.HelpContents) self.fileMenu = self.menuBar().addMenu("&File") self.fileMenuActions = (fileNewAction, fileOpenAction, fileSaveAction, fileSaveAsAction, None, filePrintAction, fileQuitAction) self.fileMenu.aboutToShow.connect(self.updateFileMenu) editMenu = self.menuBar().addMenu("&Edit") self.addActions(editMenu, (editInvertAction, editSwapRedAndBlueAction, editZoomAction, editResizeAction)) mirrorMenu = editMenu.addMenu(QIcon(":/editmirror.png"), "&Mirror") self.addActions(mirrorMenu, (editUnMirrorAction, editMirrorHorizontalAction, editMirrorVerticalAction)) helpMenu = self.menuBar().addMenu("&Help") self.addActions(helpMenu, (helpAboutAction, helpHelpAction)) fileToolbar = self.addToolBar("File") fileToolbar.setObjectName("FileToolBar") self.addActions(fileToolbar, (fileNewAction, fileOpenAction, fileSaveAsAction)) editToolbar = self.addToolBar("Edit") editToolbar.setObjectName("EditToolBar") self.addActions(editToolbar, (editInvertAction, editSwapRedAndBlueAction, editUnMirrorAction, editMirrorVerticalAction, editMirrorHorizontalAction)) self.zoomSpinBox = QSpinBox() self.zoomSpinBox.setRange(1, 400) self.zoomSpinBox.setSuffix(" %") self.zoomSpinBox.setValue(100) self.zoomSpinBox.setToolTip("Zoom the image") self.zoomSpinBox.setStatusTip(self.zoomSpinBox.toolTip()) self.zoomSpinBox.setFocusPolicy(Qt.NoFocus) self.zoomSpinBox.valueChanged.connect(self.showImage) editToolbar.addWidget(self.zoomSpinBox) self.addActions(self.imageLabel, (editInvertAction, editSwapRedAndBlueAction, editUnMirrorAction, editMirrorVerticalAction, editMirrorHorizontalAction)) self.resetableActions = ((editInvertAction, False), (editSwapRedAndBlueAction, False), (editUnMirrorAction, True)) def load_settings(self): settings = QSettings() self.recentFiles = settings.value("RecentFiles").toStringList() self.restoreGeometry( settings.value("MainWindow/Geometry").toByteArray()) self.restoreState(settings.value("MainWindow/State").toByteArray()) def createAction(self, text, slot=None, shortcut=None, icon=None, tip=None, checkable=False): action = QAction(text, self) if icon is not None: action.setIcon(QIcon(":/{0}.png".format(icon))) if shortcut is not None: action.setShortcut(shortcut) if tip is not None: action.setToolTip(tip) action.setStatusTip(tip) if slot is not None: action.triggered.connect(slot) if checkable: action.setCheckable(True) return action def addActions(self, target, actions): for action in actions: if action is None: target.addSeparator() else: target.addAction(action) def closeEvent(self, event): if self.okToContinue(): settings = QSettings() filename = (QVariant(QString(self.filename)) if self.filename is not None else QVariant()) settings.setValue("LastFile", filename) recentFiles = (QVariant(self.recentFiles) if self.recentFiles else QVariant()) settings.setValue("RecentFiles", recentFiles) settings.setValue("MainWindow/Geometry", QVariant( self.saveGeometry())) settings.setValue("MainWindow/State", QVariant( self.saveState())) else: event.ignore() def okToContinue(self): if self.dirty: reply = QMessageBox.question(self, "Image Changer - Unsaved Changes", "Save unsaved changes?", QMessageBox.Yes|QMessageBox.No|QMessageBox.Cancel) if reply == QMessageBox.Cancel: return False elif reply == QMessageBox.Yes: return self.fileSave() return True def loadInitialFile(self): settings = QSettings() fname = unicode(settings.value("LastFile").toString()) if fname and QFile.exists(fname): self.loadFile(fname) def updateStatus(self, message): self.statusBar().showMessage(message, 5000) self.listWidget.addItem(message) if self.filename is not None: self.setWindowTitle("Image Changer - {0}[*]".format( os.path.basename(self.filename))) elif not self.image.isNull(): self.setWindowTitle("Image Changer - Unnamed[*]") else: self.setWindowTitle("Image Changer[*]") self.setWindowModified(self.dirty) def updateFileMenu(self): self.fileMenu.clear() self.addActions(self.fileMenu, self.fileMenuActions[:-1]) current = (QString(self.filename) if self.filename is not None else None) recentFiles = [] for fname in self.recentFiles: if fname != current and QFile.exists(fname): recentFiles.append(fname) if recentFiles: self.fileMenu.addSeparator() for i, fname in enumerate(recentFiles): action = QAction(QIcon(":/icon.png"), "&{0} {1}".format(i + 1, QFileInfo( fname).fileName()), self) action.setData(QVariant(fname)) action.triggered.connect(self.loadFile) self.fileMenu.addAction(action) self.fileMenu.addSeparator() self.fileMenu.addAction(self.fileMenuActions[-1]) def fileNew(self): if not self.okToContinue(): return dialog = newimagedlg.NewImageDlg(self) if dialog.exec_(): self.addRecentFile(self.filename) self.image = QImage() for action, check in self.resetableActions: action.setChecked(check) self.image = dialog.image() self.filename = None self.dirty = True self.showImage() self.sizeLabel.setText("{0} x {1}".format(self.image.width(), self.image.height())) self.updateStatus("Created new image") def fileOpen(self): if not self.okToContinue(): return dir = (os.path.dirname(self.filename) if self.filename is not None else ".") formats = (["*.{0}".format(unicode(format).lower()) for format in QImageReader.supportedImageFormats()]) fname = unicode(QFileDialog.getOpenFileName(self, "Image Changer - Choose Image", dir, "Image files ({0})".format(" ".join(formats)))) if fname: self.loadFile(fname) def loadFile(self, fname=None): if fname is None: action = self.sender() if isinstance(action, QAction): fname = unicode(action.data().toString()) if not self.okToContinue(): return else: return if fname: self.filename = None image = QImage(fname) if image.isNull(): message = "Failed to read {0}".format(fname) else: self.addRecentFile(fname) self.image = QImage() for action, check in self.resetableActions: action.setChecked(check) self.image = image self.filename = fname self.showImage() self.dirty = False self.sizeLabel.setText("{0} x {1}".format( image.width(), image.height())) message = "Loaded {0}".format(os.path.basename(fname)) self.updateStatus(message) def addRecentFile(self, fname): if fname is None: return if not self.recentFiles.contains(fname): self.recentFiles.prepend(QString(fname)) while self.recentFiles.count() > 9: self.recentFiles.takeLast() def fileSave(self): if self.image.isNull(): return True if self.filename is None: return self.fileSaveAs() else: if self.image.save(self.filename, None): self.updateStatus("Saved as {0}".format(self.filename)) self.dirty = False return True else: self.updateStatus("Failed to save {0}".format( self.filename)) return False def fileSaveAs(self): if self.image.isNull(): return True fname = self.filename if self.filename is not None else "." formats = (["*.{0}".format(unicode(format).lower()) for format in QImageWriter.supportedImageFormats()]) fname = unicode(QFileDialog.getSaveFileName(self, "Image Changer - Save Image", fname, "Image files ({0})".format(" ".join(formats)))) if fname: if "." not in fname: fname += ".png" self.addRecentFile(fname) self.filename = fname return self.fileSave() return False def filePrint(self): if self.image.isNull(): return if self.printer is None: self.printer = QPrinter(QPrinter.HighResolution) self.printer.setPageSize(QPrinter.Letter) form = QPrintDialog(self.printer, self) if form.exec_(): painter = QPainter(self.printer) rect = painter.viewport() size = self.image.size() size.scale(rect.size(), Qt.KeepAspectRatio) painter.setViewport(rect.x(), rect.y(), size.width(), size.height()) painter.drawImage(0, 0, self.image) def editInvert(self, on): if self.image.isNull(): return self.image.invertPixels() self.showImage() self.dirty = True self.updateStatus("Inverted" if on else "Uninverted") def editSwapRedAndBlue(self, on): if self.image.isNull(): return self.image = self.image.rgbSwapped() self.showImage() self.dirty = True self.updateStatus(("Swapped Red and Blue" if on else "Unswapped Red and Blue")) def editUnMirror(self, on): if self.image.isNull(): return if self.mirroredhorizontally: self.editMirrorHorizontal(False) if self.mirroredvertically: self.editMirrorVertical(False) def editMirrorHorizontal(self, on): if self.image.isNull(): return self.image = self.image.mirrored(True, False) self.showImage() self.mirroredhorizontally = not self.mirroredhorizontally self.dirty = True self.updateStatus(("Mirrored Horizontally" if on else "Unmirrored Horizontally")) def editMirrorVertical(self, on): if self.image.isNull(): return self.image = self.image.mirrored(False, True) self.showImage() self.mirroredvertically = not self.mirroredvertically self.dirty = True self.updateStatus(("Mirrored Vertically" if on else "Unmirrored Vertically")) def editZoom(self): if self.image.isNull(): return percent, ok = QInputDialog.getInteger(self, "Image Changer - Zoom", "Percent:", self.zoomSpinBox.value(), 1, 400) if ok: self.zoomSpinBox.setValue(percent) def editResize(self): if self.image.isNull(): return form = resizedlg.ResizeDlg(self.image.width(), self.image.height(), self) if form.exec_(): width, height = form.result() if (width == self.image.width() and height == self.image.height()): self.statusBar().showMessage("Resized to the same size", 5000) else: self.image = self.image.scaled(width, height) self.showImage() self.dirty = True size = "{0} x {1}".format(self.image.width(), self.image.height()) self.sizeLabel.setText(size) self.updateStatus("Resized to {0}".format(size)) def showImage(self, percent=None): if self.image.isNull(): return if percent is None: percent = self.zoomSpinBox.value() factor = percent / 100.0 width = self.image.width() * factor height = self.image.height() * factor image = self.image.scaled(width, height, Qt.KeepAspectRatio) self.imageLabel.setPixmap(QPixmap.fromImage(image)) def helpAbout(self): QMessageBox.about(self, "About Image Changer", """<b>Image Changer</b> v {0} <p>Copyright © 2008 Qtrac Ltd. All rights reserved. <p>This application can be used to perform simple image manipulations. <p>Python {1} - Qt {2} - PyQt {3} on {4}""".format( __version__, platform.python_version(), QT_VERSION_STR, PYQT_VERSION_STR, platform.system())) def helpHelp(self): form = helpform.HelpForm("index.html", self) form.show()
class LayerItemWidget( QWidget ): @property def layer(self): return self._layer @layer.setter def layer(self, layer): if self._layer: self._layer.changed.disconnect(self._updateState) self._layer = layer self._updateState() self._layer.changed.connect(self._updateState) def __init__( self, parent=None ): QWidget.__init__( self, parent=parent ) self._layer = None self._font = QFont(QFont().defaultFamily(), 9) self._fm = QFontMetrics( self._font ) self.bar = FractionSelectionBar( initial_fraction = 0. ) self.bar.setFixedHeight(10) self.nameLabel = QLabel() self.nameLabel.setFont( self._font ) self.nameLabel.setText( "None" ) self.opacityLabel = QLabel() self.opacityLabel.setAlignment(Qt.AlignRight) self.opacityLabel.setFont( self._font ) self.opacityLabel.setText( u"\u03B1=%0.1f%%" % (100.0*(self.bar.fraction()))) self.toggleEye = ToggleEye() self.toggleEye.setActive(False) self.toggleEye.setFixedWidth(35) self.toggleEye.setToolTip("Visibility") self.channelSelector = QSpinBox() self.channelSelector.setFrame( False ) self.channelSelector.setFont( self._font ) self.channelSelector.setMaximumWidth( 35 ) self.channelSelector.setAlignment(Qt.AlignRight) self.channelSelector.setToolTip("Channel") self.channelSelector.setVisible(False) self._layout = QGridLayout() self._layout.addWidget( self.toggleEye, 0, 0 ) self._layout.addWidget( self.nameLabel, 0, 1 ) self._layout.addWidget( self.opacityLabel, 0, 2 ) self._layout.addWidget( self.channelSelector, 1, 0) self._layout.addWidget( self.bar, 1, 1, 1, 2 ) self._layout.setColumnMinimumWidth( 0, 35 ) self._layout.setSpacing(0) self._layout.setContentsMargins(5,2,5,2) self.setLayout( self._layout) self.bar.fractionChanged.connect( self._onFractionChanged ) self.toggleEye.activeChanged.connect( self._onEyeToggle ) self.channelSelector.valueChanged.connect( self._onChannelChanged ) def mousePressEvent( self, ev ): print "plonk", ev.pos(), ev.globalPos() QWidget.mousePressEvent( self, ev ) def _onFractionChanged( self, fraction ): if self._layer and (fraction != self._layer.opacity): self._layer.opacity = fraction def _onEyeToggle( self, active ): if self._layer and (active != self._layer.visible): self._layer.visible = active def _onChannelChanged( self, channel ): if self._layer and (channel != self._layer.channel): self._layer.channel = channel def _updateState( self ): if self._layer: self.toggleEye.setActive(self._layer.visible) self.bar.setFraction( self._layer.opacity ) self.opacityLabel.setText( u"\u03B1=%0.1f%%" % (100.0*(self.bar.fraction()))) self.nameLabel.setText( self._layer.name ) if self._layer.numberOfChannels > 1: self.channelSelector.setVisible( True ) self.channelSelector.setMaximum( self._layer.numberOfChannels - 1 ) self.channelSelector.setValue( self._layer.channel ) else: self.channelSelector.setVisible( False ) self.channelSelector.setMaximum( self._layer.numberOfChannels - 1) self.channelSelector.setValue( self._layer.channel ) self.update()
class Indenting(preferences.Group): def __init__(self, page): super(Indenting, self).__init__(page) layout = QGridLayout(spacing=1) self.setLayout(layout) self.tabwidthBox = QSpinBox(minimum=1, maximum=99) self.tabwidthLabel = l = QLabel() l.setBuddy(self.tabwidthBox) self.nspacesBox = QSpinBox(minimum=0, maximum=99) self.nspacesLabel = l = QLabel() l.setBuddy(self.nspacesBox) self.dspacesBox = QSpinBox(minimum=0, maximum=99) self.dspacesLabel = l = QLabel() l.setBuddy(self.dspacesBox) layout.addWidget(self.tabwidthLabel, 0, 0) layout.addWidget(self.tabwidthBox, 0, 1) layout.addWidget(self.nspacesLabel, 1, 0) layout.addWidget(self.nspacesBox, 1, 1) layout.addWidget(self.dspacesLabel, 2, 0) layout.addWidget(self.dspacesBox, 2, 1) self.tabwidthBox.valueChanged.connect(page.changed) self.nspacesBox.valueChanged.connect(page.changed) self.dspacesBox.valueChanged.connect(page.changed) self.translateUI() def translateUI(self): self.setTitle(_("Indenting Preferences")) self.tabwidthLabel.setText(_("Visible Tab Width:")) self.tabwidthBox.setToolTip(_( "The visible width of a Tab character in the editor.")) self.nspacesLabel.setText(_("Indent text with:")) self.nspacesBox.setToolTip(_( "How many spaces to use for indenting one level.\n" "Move to zero to use a Tab character for indenting.")) self.nspacesBox.setSpecialValueText(_("Tab")) self.dspacesLabel.setText(_("Tab ouside indent inserts:")) self.dspacesBox.setToolTip(_( "How many spaces to insert when Tab is pressed outside the indent, " "elsewhere in the document.\n" "Move to zero to insert a literal Tab character in this case.")) self.nspacesBox.setSpecialValueText(_("Tab")) self.dspacesBox.setSpecialValueText(_("Tab")) # L10N: abbreviation for "n spaces" in spinbox, n >= 1, no plural forms prefix, suffix = _("{num} spaces").split("{num}") self.nspacesBox.setPrefix(prefix) self.nspacesBox.setSuffix(suffix) self.dspacesBox.setPrefix(prefix) self.dspacesBox.setSuffix(suffix) def loadSettings(self): s = QSettings() s.beginGroup("indent") self.tabwidthBox.setValue(s.value("tab_width", 8, int)) self.nspacesBox.setValue(s.value("indent_spaces", 2, int)) self.dspacesBox.setValue(s.value("document_spaces", 8, int)) def saveSettings(self): s = QSettings() s.beginGroup("indent") s.setValue("tab_width", self.tabwidthBox.value()) s.setValue("indent_spaces", self.nspacesBox.value()) s.setValue("document_spaces", self.dspacesBox.value())
class LayerItemWidget( QWidget ): @property def layer(self): return self._layer @layer.setter def layer(self, layer): if self._layer: self._layer.changed.disconnect(self._updateState) self._layer = layer self._updateState() self._layer.changed.connect(self._updateState) def __init__( self, parent=None ): super(LayerItemWidget, self).__init__( parent=parent ) self._layer = None self._font = QFont(QFont().defaultFamily(), 9) self._fm = QFontMetrics( self._font ) self.bar = FractionSelectionBar( initial_fraction = 0. ) self.bar.setFixedHeight(10) self.nameLabel = QLabel( parent=self ) self.nameLabel.setFont( self._font ) self.nameLabel.setText( "None" ) self.opacityLabel = QLabel( parent=self ) self.opacityLabel.setAlignment(Qt.AlignRight) self.opacityLabel.setFont( self._font ) self.opacityLabel.setText( u"\u03B1=%0.1f%%" % (100.0*(self.bar.fraction()))) self.toggleEye = ToggleEye( parent=self ) self.toggleEye.setActive(False) self.toggleEye.setFixedWidth(35) self.toggleEye.setToolTip("Visibility") self.channelSelector = QSpinBox( parent=self ) self.channelSelector.setFrame( False ) self.channelSelector.setFont( self._font ) self.channelSelector.setMaximumWidth( 35 ) self.channelSelector.setAlignment(Qt.AlignRight) self.channelSelector.setToolTip("Channel") self.channelSelector.setVisible(False) self._layout = QGridLayout( self ) self._layout.addWidget( self.toggleEye, 0, 0 ) self._layout.addWidget( self.nameLabel, 0, 1 ) self._layout.addWidget( self.opacityLabel, 0, 2 ) self._layout.addWidget( self.channelSelector, 1, 0) self._layout.addWidget( self.bar, 1, 1, 1, 2 ) self._layout.setColumnMinimumWidth( 0, 35 ) self._layout.setSpacing(0) self._layout.setContentsMargins(5,2,5,2) self.setLayout( self._layout ) self.bar.fractionChanged.connect( self._onFractionChanged ) self.toggleEye.activeChanged.connect( self._onEyeToggle ) self.channelSelector.valueChanged.connect( self._onChannelChanged ) def mousePressEvent( self, ev ): super(LayerItemWidget, self).mousePressEvent( ev ) def _onFractionChanged( self, fraction ): if self._layer and (fraction != self._layer.opacity): self._layer.opacity = fraction def _onEyeToggle( self, active ): if self._layer and (active != self._layer.visible): if self._layer._allowToggleVisible: self._layer.visible = active else: self.toggleEye.setActive(True) def _onChannelChanged( self, channel ): if self._layer and (channel != self._layer.channel): self._layer.channel = channel def _updateState( self ): if self._layer: self.toggleEye.setActive(self._layer.visible) self.bar.setFraction( self._layer.opacity ) self.opacityLabel.setText( u"\u03B1=%0.1f%%" % (100.0*(self.bar.fraction()))) self.nameLabel.setText( self._layer.name ) if self._layer.numberOfChannels > 1: self.channelSelector.setVisible( True ) self.channelSelector.setMaximum( self._layer.numberOfChannels - 1 ) self.channelSelector.setValue( self._layer.channel ) else: self.channelSelector.setVisible( False ) self.channelSelector.setMaximum( self._layer.numberOfChannels - 1) self.channelSelector.setValue( self._layer.channel ) self.update()
class Window(QMainWindow): def __init__(self, parent=None): super(Window, self).__init__(parent) self.image = QImage() self.dirty = False self.filename = None self.mirroredvertically = False self.mirroredhorizontally = False self.printer = None self.create_widgets() self.create_actions() self.load_settings() self.setWindowTitle("Image Changer") self.updateFileMenu() QTimer.singleShot(0, self.loadInitialFile) def create_widgets(self): self.imageLabel = QLabel() self.imageLabel.setMinimumSize(200, 200) self.imageLabel.setAlignment(Qt.AlignCenter) self.imageLabel.setContextMenuPolicy(Qt.ActionsContextMenu) self.setCentralWidget(self.imageLabel) logDockWidget = QDockWidget("Log", self) logDockWidget.setObjectName("LogDockWidget") logDockWidget.setAllowedAreas(Qt.LeftDockWidgetArea | Qt.RightDockWidgetArea) self.listWidget = QListWidget() logDockWidget.setWidget(self.listWidget) self.addDockWidget(Qt.RightDockWidgetArea, logDockWidget) self.sizeLabel = QLabel() self.sizeLabel.setFrameStyle(QFrame.StyledPanel | QFrame.Sunken) status = self.statusBar() status.setSizeGripEnabled(False) status.addPermanentWidget(self.sizeLabel) status.showMessage("Ready", 5000) def create_actions(self): fileNewAction = self.createAction("&New...", self.fileNew, QKeySequence.New, "filenew", "Create an image file") fileOpenAction = self.createAction("&Open...", self.fileOpen, QKeySequence.Open, "fileopen", "Open an existing image file") fileSaveAction = self.createAction("&Save", self.fileSave, QKeySequence.Save, "filesave", "Save the image") fileSaveAsAction = self.createAction( "Save &As...", self.fileSaveAs, icon="filesaveas", tip="Save the image using a new name") filePrintAction = self.createAction("&Print", self.filePrint, QKeySequence.Print, "fileprint", "Print the image") fileQuitAction = self.createAction("&Quit", self.close, "Ctrl+Q", "filequit", "Close the application") editInvertAction = self.createAction("&Invert", None, "Ctrl+I", "editinvert", "Invert the image's colors", True) editInvertAction.toggled.connect(self.editInvert) editSwapRedAndBlueAction = self.createAction( "Sw&ap Red and Blue", None, "Ctrl+A", "editswap", "Swap the image's red and blue color components", True) editSwapRedAndBlueAction.toggled.connect(self.editSwapRedAndBlue) editZoomAction = self.createAction("&Zoom...", self.editZoom, "Alt+Z", "editzoom", "Zoom the image") mirrorGroup = QActionGroup(self) editUnMirrorAction = self.createAction("&Unmirror", None, "Ctrl+U", "editunmirror", "Unmirror the image", True) editUnMirrorAction.toggled.connect(self.editUnMirror) mirrorGroup.addAction(editUnMirrorAction) editMirrorHorizontalAction = self.createAction( "Mirror &Horizontally", None, "Ctrl+H", "editmirrorhoriz", "Horizontally mirror the image", True) editMirrorHorizontalAction.toggled.connect(self.editMirrorHorizontal) mirrorGroup.addAction(editMirrorHorizontalAction) editMirrorVerticalAction = self.createAction( "Mirror &Vertically", None, "Ctrl+V", "editmirrorvert", "Vertically mirror the image", True) editMirrorVerticalAction.toggled.connect(self.editMirrorVertical) mirrorGroup.addAction(editMirrorVerticalAction) editUnMirrorAction.setChecked(True) helpAboutAction = self.createAction("&About Image Changer", self.helpAbout) helpHelpAction = self.createAction("&Help", self.helpHelp, QKeySequence.HelpContents) self.fileMenu = self.menuBar().addMenu("&File") self.fileMenuActions = (fileNewAction, fileOpenAction, fileSaveAction, fileSaveAsAction, None, filePrintAction, fileQuitAction) self.fileMenu.aboutToShow.connect(self.updateFileMenu) editMenu = self.menuBar().addMenu("&Edit") self.addActions( editMenu, (editInvertAction, editSwapRedAndBlueAction, editZoomAction)) mirrorMenu = editMenu.addMenu(QIcon(":/editmirror.png"), "&Mirror") self.addActions(mirrorMenu, (editUnMirrorAction, editMirrorHorizontalAction, editMirrorVerticalAction)) helpMenu = self.menuBar().addMenu("&Help") self.addActions(helpMenu, (helpAboutAction, helpHelpAction)) fileToolbar = self.addToolBar("File") fileToolbar.setObjectName("FileToolBar") self.addActions(fileToolbar, (fileNewAction, fileOpenAction, fileSaveAsAction)) editToolbar = self.addToolBar("Edit") editToolbar.setObjectName("EditToolBar") self.addActions( editToolbar, (editInvertAction, editSwapRedAndBlueAction, editUnMirrorAction, editMirrorVerticalAction, editMirrorHorizontalAction)) self.zoomSpinBox = QSpinBox() self.zoomSpinBox.setRange(1, 400) self.zoomSpinBox.setSuffix(" %") self.zoomSpinBox.setValue(100) self.zoomSpinBox.setToolTip("Zoom the image") self.zoomSpinBox.setStatusTip(self.zoomSpinBox.toolTip()) self.zoomSpinBox.setFocusPolicy(Qt.NoFocus) self.zoomSpinBox.valueChanged.connect(self.showImage) editToolbar.addWidget(self.zoomSpinBox) self.addActions( self.imageLabel, (editInvertAction, editSwapRedAndBlueAction, editUnMirrorAction, editMirrorVerticalAction, editMirrorHorizontalAction)) self.resetableActions = ((editInvertAction, False), (editSwapRedAndBlueAction, False), (editUnMirrorAction, True)) def load_settings(self): settings = QSettings() self.recentFiles = settings.value("RecentFiles").toStringList() self.restoreGeometry( settings.value("MainWindow/Geometry").toByteArray()) self.restoreState(settings.value("MainWindow/State").toByteArray()) def createAction(self, text, slot=None, shortcut=None, icon=None, tip=None, checkable=False): action = QAction(text, self) if icon is not None: action.setIcon(QIcon(":/{0}.png".format(icon))) if shortcut is not None: action.setShortcut(shortcut) if tip is not None: action.setToolTip(tip) action.setStatusTip(tip) if slot is not None: action.triggered.connect(slot) if checkable: action.setCheckable(True) return action def addActions(self, target, actions): for action in actions: if action is None: target.addSeparator() else: target.addAction(action) def closeEvent(self, event): if self.okToContinue(): settings = QSettings() filename = (QVariant(QString(self.filename)) if self.filename is not None else QVariant()) settings.setValue("LastFile", filename) recentFiles = (QVariant(self.recentFiles) if self.recentFiles else QVariant()) settings.setValue("RecentFiles", recentFiles) settings.setValue("MainWindow/Geometry", QVariant(self.saveGeometry())) settings.setValue("MainWindow/State", QVariant(self.saveState())) else: event.ignore() def okToContinue(self): if self.dirty: reply = QMessageBox.question( self, "Image Changer - Unsaved Changes", "Save unsaved changes?", QMessageBox.Yes | QMessageBox.No | QMessageBox.Cancel) if reply == QMessageBox.Cancel: return False elif reply == QMessageBox.Yes: return self.fileSave() return True def loadInitialFile(self): settings = QSettings() fname = unicode(settings.value("LastFile").toString()) if fname and QFile.exists(fname): self.loadFile(fname) def updateStatus(self, message): self.statusBar().showMessage(message, 5000) self.listWidget.addItem(message) if self.filename is not None: self.setWindowTitle("Image Changer - {0}[*]".format( os.path.basename(self.filename))) elif not self.image.isNull(): self.setWindowTitle("Image Changer - Unnamed[*]") else: self.setWindowTitle("Image Changer[*]") self.setWindowModified(self.dirty) def updateFileMenu(self): self.fileMenu.clear() self.addActions(self.fileMenu, self.fileMenuActions[:-1]) current = (QString(self.filename) if self.filename is not None else None) recentFiles = [] for fname in self.recentFiles: if fname != current and QFile.exists(fname): recentFiles.append(fname) if recentFiles: self.fileMenu.addSeparator() for i, fname in enumerate(recentFiles): action = QAction( QIcon(":/icon.png"), "&{0} {1}".format(i + 1, QFileInfo(fname).fileName()), self) action.setData(QVariant(fname)) action.triggered.connect(self.loadFile) self.fileMenu.addAction(action) self.fileMenu.addSeparator() self.fileMenu.addAction(self.fileMenuActions[-1]) def fileNew(self): if not self.okToContinue(): return dialog = newimagedlg.NewImageDlg(self) if dialog.exec_(): self.addRecentFile(self.filename) self.image = QImage() for action, check in self.resetableActions: action.setChecked(check) self.image = dialog.image() self.filename = None self.dirty = True self.showImage() self.sizeLabel.setText("{0} x {1}".format(self.image.width(), self.image.height())) self.updateStatus("Created new image") def fileOpen(self): if not self.okToContinue(): return dir = (os.path.dirname(self.filename) if self.filename is not None else ".") formats = ([ "*.{0}".format(unicode(format).lower()) for format in QImageReader.supportedImageFormats() ]) fname = unicode( QFileDialog.getOpenFileName( self, "Image Changer - Choose Image", dir, "Image files ({0})".format(" ".join(formats)))) if fname: self.loadFile(fname) def loadFile(self, fname=None): if fname is None: action = self.sender() if isinstance(action, QAction): fname = unicode(action.data().toString()) if not self.okToContinue(): return else: return if fname: self.filename = None image = QImage(fname) if image.isNull(): message = "Failed to read {0}".format(fname) else: self.addRecentFile(fname) self.image = QImage() for action, check in self.resetableActions: action.setChecked(check) self.image = image self.filename = fname self.showImage() self.dirty = False self.sizeLabel.setText("{0} x {1}".format( image.width(), image.height())) message = "Loaded {0}".format(os.path.basename(fname)) self.updateStatus(message) def addRecentFile(self, fname): if fname is None: return if not self.recentFiles.contains(fname): self.recentFiles.prepend(QString(fname)) while self.recentFiles.count() > 9: self.recentFiles.takeLast() def fileSave(self): if self.image.isNull(): return True if self.filename is None: return self.fileSaveAs() else: if self.image.save(self.filename, None): self.updateStatus("Saved as {0}".format(self.filename)) self.dirty = False return True else: self.updateStatus("Failed to save {0}".format(self.filename)) return False def fileSaveAs(self): if self.image.isNull(): return True fname = self.filename if self.filename is not None else "." formats = ([ "*.{0}".format(unicode(format).lower()) for format in QImageWriter.supportedImageFormats() ]) fname = unicode( QFileDialog.getSaveFileName( self, "Image Changer - Save Image", fname, "Image files ({0})".format(" ".join(formats)))) if fname: if "." not in fname: fname += ".png" self.addRecentFile(fname) self.filename = fname return self.fileSave() return False def filePrint(self): if self.image.isNull(): return if self.printer is None: self.printer = QPrinter(QPrinter.HighResolution) self.printer.setPageSize(QPrinter.Letter) form = QPrintDialog(self.printer, self) if form.exec_(): painter = QPainter(self.printer) rect = painter.viewport() size = self.image.size() size.scale(rect.size(), Qt.KeepAspectRatio) painter.setViewport(rect.x(), rect.y(), size.width(), size.height()) painter.drawImage(0, 0, self.image) def editInvert(self, on): if self.image.isNull(): return self.image.invertPixels() self.showImage() self.dirty = True self.updateStatus("Inverted" if on else "Uninverted") def editSwapRedAndBlue(self, on): if self.image.isNull(): return self.image = self.image.rgbSwapped() self.showImage() self.dirty = True self.updateStatus( ("Swapped Red and Blue" if on else "Unswapped Red and Blue")) def editUnMirror(self, on): if self.image.isNull(): return if self.mirroredhorizontally: self.editMirrorHorizontal(False) if self.mirroredvertically: self.editMirrorVertical(False) def editMirrorHorizontal(self, on): if self.image.isNull(): return self.image = self.image.mirrored(True, False) self.showImage() self.mirroredhorizontally = not self.mirroredhorizontally self.dirty = True self.updateStatus( ("Mirrored Horizontally" if on else "Unmirrored Horizontally")) def editMirrorVertical(self, on): if self.image.isNull(): return self.image = self.image.mirrored(False, True) self.showImage() self.mirroredvertically = not self.mirroredvertically self.dirty = True self.updateStatus( ("Mirrored Vertically" if on else "Unmirrored Vertically")) def editZoom(self): if self.image.isNull(): return percent, ok = QInputDialog.getInteger(self, "Image Changer - Zoom", "Percent:", self.zoomSpinBox.value(), 1, 400) if ok: self.zoomSpinBox.setValue(percent) def showImage(self, percent=None): if self.image.isNull(): return if percent is None: percent = self.zoomSpinBox.value() factor = percent / 100.0 width = self.image.width() * factor height = self.image.height() * factor image = self.image.scaled(width, height, Qt.KeepAspectRatio) self.imageLabel.setPixmap(QPixmap.fromImage(image)) def helpAbout(self): QMessageBox.about( self, "About Image Changer", """<b>Image Changer</b> v {0} <p>Copyright © 2008-14 Qtrac Ltd. All rights reserved. <p>This application can be used to perform simple image manipulations. <p>Python {1} - Qt {2} - PyQt {3} on {4}""".format( __version__, platform.python_version(), QT_VERSION_STR, PYQT_VERSION_STR, platform.system())) def helpHelp(self): form = helpform.HelpForm("index.html", self) form.show()
class Main(plugin.Plugin): ' main class for plugin ' def initialize(self, *args, **kwargs): ' class init ' super(Main, self).initialize(*args, **kwargs) self.process = QProcess() self.process.readyReadStandardOutput.connect(self.readOutput) self.process.readyReadStandardError.connect(self.readErrors) self.process.finished.connect(self._process_finished) self.process.error.connect(self._process_finished) # directory auto completer self.completer, self.dirs = QCompleter(self), QDirModel(self) self.dirs.setFilter(QDir.Dirs | QDir.NoDotAndDotDot) self.completer.setModel(self.dirs) self.completer.setCaseSensitivity(Qt.CaseInsensitive) self.completer.setCompletionMode(QCompleter.PopupCompletion) menu = QMenu('Clones') menu.addAction('Analyze for Code Clones here', lambda: self.make_clon()) self.locator.get_service('explorer').add_project_menu(menu, lang='all') self.group1 = QGroupBox() self.group1.setTitle(' Target ') self.outdir, self.igndir = QLineEdit(path.expanduser("~")), QLineEdit() self.outdir.setCompleter(self.completer) self.btn1 = QPushButton(QIcon.fromTheme("document-open"), ' Open ') self.btn1.clicked.connect(lambda: self.outdir.setText(str( QFileDialog.getExistingDirectory(self.dock, 'Please, Open a Target Directory...', path.expanduser("~"))))) self.btn1a = QPushButton(QIcon.fromTheme("face-smile"), 'Get from Ninja active project') self.btn1a.clicked.connect(lambda: self.outdir.setText( self.locator.get_service('explorer').get_current_project_item().path)) self.ignckb, self.ignmor = QComboBox(), QTextEdit() self.ignckb.addItems(['Single Directory', 'Multiple Directories CSV']) self.ignckb.currentIndexChanged.connect(self.on_ignore_changed) self.ignmor.hide() self.igndir.setPlaceholderText('Exclude directory') self.igndir.setCompleter(self.completer) self.btn2 = QPushButton(QIcon.fromTheme("document-open"), ' Open ') self.btn2.clicked.connect(lambda: self.igndir.setText(str( QFileDialog.getExistingDirectory(self.dock, 'Please, Open a Ignore Directory...', path.expanduser("~"))))) vboxg1 = QVBoxLayout(self.group1) for each_widget in (QLabel('<b>Target directory path: '), self.outdir, self.btn1, self.btn1a, QLabel('<b>Ignore directory path: '), self.ignckb, self.ignmor, self.igndir, self.btn2, ): vboxg1.addWidget(each_widget) self.group2 = QGroupBox() self.group2.setTitle(' Output ') self.outfle = QLineEdit(path.join(path.expanduser("~"), 'output.html')) self.outfle.setPlaceholderText('Exclude directory') self.outfle.setCompleter(self.completer) self.btn3 = QPushButton(QIcon.fromTheme("document-save"), ' Save ') self.btn3.clicked.connect(lambda: self.outfle.setText( QFileDialog.getSaveFileName(self.dock, 'Save', path.expanduser("~"), 'XML(*.xml)' if self.xmlo.isChecked() is True else 'HTML(*.html)'))) vboxg2 = QVBoxLayout(self.group2) for each_widget in (QLabel('<b>Output report file path:'), self.outfle, self.btn3): vboxg2.addWidget(each_widget) self.group3 = QGroupBox() self.group3.setTitle(' Options ') self.group3.setCheckable(True) self.group3.setGraphicsEffect(QGraphicsBlurEffect(self)) self.group3.graphicsEffect().setEnabled(False) self.group3.toggled.connect(self.toggle_options_group) self.qckb1, self.qckb2 = QCheckBox('Recursive'), QCheckBox('Time-less') self.qckb3, self.qckb4 = QCheckBox('Force Diff'), QCheckBox('Fast Mode') self.qckb5, self.tm = QCheckBox('Save a LOG file to target'), QLabel('') self.xmlo = QCheckBox('XML Output instead of HTML') self.opeo = QCheckBox('Open Clones Report when done') self.chrt = QCheckBox('LOW CPU priority for Backend Process') self.mdist, self.hdep, self.output = QSpinBox(), QSpinBox(), QTextEdit() self.ign_func = QLineEdit('test, forward, backward, Migration') self.mdist.setValue(5) self.hdep.setValue(1) self.mdist.setToolTip('''<b>Maximum amount of difference between pair of sequences in clone pair (5 default).Larger value more false positive''') self.hdep.setToolTip('''<b>Computation can be speeded up by increasing this value, but some clones can be missed (1 default)''') [a.setChecked(True) for a in (self.qckb1, self.qckb3, self.qckb5, self.chrt, self.opeo)] vboxg3 = QVBoxLayout(self.group3) for each_widget in (self.qckb1, self.qckb2, self.qckb3, self.qckb4, self.qckb5, self.chrt, self.xmlo, self.opeo, QLabel('<b>Max Distance Threshold:'), self.mdist, QLabel('<b>Max Hashing Depth:'), self.hdep, QLabel('<b>Ignore code block prefix:'), self.ign_func): vboxg3.addWidget(each_widget) self.group4, self.auto = QGroupBox(), QComboBox() self.group4.setTitle(' Automation ') self.group4.setCheckable(True) self.group4.setToolTip('<font color="red"><b>WARNING:Advanced Setting!') self.group4.toggled.connect(lambda: self.group4.hide()) self.auto.addItems(['Never run automatically', 'Run when File Saved', 'Run when File Executed', 'Run when Tab Changed', 'Run when File Opened', 'Run before File Saved']) self.auto.currentIndexChanged.connect(self.on_auto_changed) QVBoxLayout(self.group4).addWidget(self.auto) self.button = QPushButton(' Analyze for Clones ') self.button.setMinimumSize(75, 50) self.button.clicked.connect(self.run) glow = QGraphicsDropShadowEffect(self) glow.setOffset(0) glow.setBlurRadius(99) glow.setColor(QColor(99, 255, 255)) self.button.setGraphicsEffect(glow) self.butkil = QPushButton(' Force Kill Clones ') self.butkil.clicked.connect(lambda: self.process.kill()) class TransientWidget(QWidget): ' persistant widget thingy ' def __init__(self, widget_list): ' init sub class ' super(TransientWidget, self).__init__() vbox = QVBoxLayout(self) for each_widget in widget_list: vbox.addWidget(each_widget) tw = TransientWidget((QLabel('<i>D.R.Y. principle analyzer'), self.group1, self.group2, self.group3, self.group4, QLabel('<b>Backend Logs'), self.output, self.tm, self.button, self.butkil)) self.scrollable, self.dock = QScrollArea(), QDockWidget() self.scrollable.setWidgetResizable(True) self.scrollable.setWidget(tw) self.dock.setWindowTitle(__doc__) self.dock.setStyleSheet('QDockWidget::title{text-align: center;}') self.dock.setWidget(self.scrollable) ExplorerContainer().addTab(self.dock, "Clones") QPushButton(QIcon.fromTheme("help-about"), 'About', self.dock ).clicked.connect(lambda: QMessageBox.information(self.dock, __doc__, HELPMSG)) def readOutput(self): """Read and append output to the logBrowser""" self.output.append(str(self.process.readAllStandardOutput()).strip()) def readErrors(self): """Read and append errors to the logBrowser""" self.output.append(self.formatErrorMsg(str( self.process.readAllStandardError()))) def formatErrorMsg(self, msg): """Format error messages in red color""" return self.formatMsg(msg, 'red') def formatInfoMsg(self, msg): """Format informative messages in blue color""" return self.formatMsg(msg, 'green') def formatMsg(self, msg, color): """Format message with the given color""" return '<font color="{}">{}</font>'.format(color, msg) def make_clon(self): ' make clones analyze from contextual sub menu ' self.outdir.setText( self.locator.get_service('explorer').get_current_project_item().path) self.run() def run(self): ' run the actions ' self.output.clear() self.output.append(self.formatInfoMsg('INFO:{}'.format(datetime.now()))) self.tm.setText('<center><b>Last Clone: </b>' + datetime.now().isoformat().split('.')[0]) self.button.setDisabled(True) if not len(self.outdir.text()) and not len(self.outfle.text()): self.output.append(self.formatErrorMsg('ERROR: FAIL: Target empty')) self.button.setEnabled(True) return # run the subprocesses cmd = ' '.join(( 'chrt -i 0' if self.chrt.isChecked() is True else '', 'clonedigger', '' if self.qckb1.isChecked() is True else '--no-recursion', '--dont-print-time' if self.qckb2.isChecked() is True else '', '--force' if self.qckb3.isChecked() is True else '', '--fast' if self.qckb4.isChecked() is True else '', '--cpd-output' if self.xmlo.isChecked() is True else '', '' if self.xmlo.isChecked() is True else '--report-unifiers', '--distance-threshold={}'.format(self.mdist.value()), '--hashing-depth={}'.format(self.hdep.value()), '--ignore-dir="{}"'.format(self.igndir.text() if self.ignckb.currentIndex() is 0 else self.ignmor.toPlainText()), '--func-prefixes="{}"'.format(self.ign_func.text()), '--output="{}"'.format(self.outfle.text()), '--language=python', path.abspath(self.outdir.text()), )) self.output.append(self.formatInfoMsg('INFO:OK:Command:{}'.format(cmd))) self.process.start(cmd) if not self.process.waitForStarted(): self.output.append(self.formatErrorMsg(' ERROR: FAIL: Meh. ')) self.output.append(self.formatErrorMsg('ERROR:FAIL:{}'.format(cmd))) self.button.setEnabled(True) return self.readOutput() self.readErrors() self.button.setEnabled(True) def _process_finished(self): """ finished sucessfully """ self.output.append(self.formatInfoMsg('INFO:{}'.format(datetime.now()))) # write a .log file on target if self.qckb5.isChecked() is True: log_file = 'ninja_clones.log' with open(path.join(str(self.outdir.text()), log_file), 'w') as log: self.output.append(self.formatInfoMsg('''INFO: OK: Writing Logs: {}'''.format(path.join(str(self.outdir.text()), log_file)))) log.write(self.output.toPlainText()) log.close() # open target output if self.opeo.isChecked() is True and self.xmlo.isChecked() is False: try: startfile(self.outfle.text()) except: Popen(["xdg-open", self.outfle.text()]) self.output.selectAll() self.output.setFocus() def toggle_options_group(self): ' toggle on off the options group ' if self.group3.isChecked() is True: [a.setChecked(True) for a in (self.qckb1, self.qckb3, self.qckb5, self.chrt, self.opeo)] self.mdist.setValue(5) self.hdep.setValue(1) self.group3.graphicsEffect().setEnabled(False) else: [a.setChecked(False) for a in (self.qckb1, self.qckb3, self.qckb5, self.chrt, self.opeo)] self.group3.graphicsEffect().setEnabled(True) def on_ignore_changed(self): 'hide or show one widget or another depending what kind of input need' if self.ignckb.currentIndex() is 0: self.igndir.show() self.btn2.show() self.ignmor.hide() else: self.igndir.hide() self.btn2.hide() self.ignmor.show() def on_auto_changed(self): ' automation connects ' if self.auto.currentIndex() is 1: self.locator.get_service('editor').fileSaved.connect(lambda: self.run()) QMessageBox.information(self.dock, __doc__, '<b>Now Actions will Run Automatically when any File is Saved !') elif self.auto.currentIndex() is 2: self.locator.get_service('editor').fileExecuted.connect(lambda: self.run()) QMessageBox.information(self.dock, __doc__, '<b>Now Actions will Run Automatically when any File is Executed !') elif self.auto.currentIndex() is 3: self.locator.get_service('editor').currentTabChanged.connect(lambda: self.run()) QMessageBox.information(self.dock, __doc__, '<b>Now Actions will Run Automatically when current Tab is Changed') elif self.auto.currentIndex() is 4: self.locator.get_service('editor').fileOpened.connect(lambda: self.run()) QMessageBox.information(self.dock, __doc__, '<b>Now Actions will Run Automatically when any File is Opened !') elif self.auto.currentIndex() is 5: self.locator.get_service('editor').beforeFileSaved.connect(lambda: self.run()) QMessageBox.information(self.dock, __doc__, '<b>Now Actions will Run Automatically before any File is Saved !') self.group4.setDisabled(True) def finish(self): ' clear when finish ' self.process.kill()