class SpinBoxPySlot(UsesQApplication, BasicPySlotCase): """Tests the connection of python slots to QSpinBox signals""" def setUp(self): super(SpinBoxPySlot, self).setUp() self.spin = QSpinBox() def tearDown(self): del self.spin super(SpinBoxPySlot, self).tearDown() def testSpinBoxValueChanged(self): """Connection of a python slot to QSpinBox.valueChanged(int)""" QObject.connect(self.spin, SIGNAL('valueChanged(int)'), self.cb) self.args = [3] self.spin.emit(SIGNAL('valueChanged(int)'), *self.args) self.assert_(self.called) def testSpinBoxValueChangedImplicit(self): """Indirect qt signal emission using QSpinBox.setValue(int)""" QObject.connect(self.spin, SIGNAL('valueChanged(int)'), self.cb) self.args = [42] self.spin.setValue(self.args[0]) self.assert_(self.called) def atestSpinBoxValueChangedFewArgs(self): """Emission of signals with fewer arguments than needed""" # XXX: PyQt4 crashes on the assertRaises QObject.connect(self.spin, SIGNAL('valueChanged(int)'), self.cb) self.args = (554,) self.assertRaises(TypeError, self.spin.emit, SIGNAL('valueChanged(int)'))
class SpinBoxPySignal(UsesQApplication): """Tests the connection of python signals to QSpinBox qt slots.""" def setUp(self): super(SpinBoxPySignal, self).setUp() self.obj = Dummy() self.spin = QSpinBox() self.spin.setValue(0) def tearDown(self): super(SpinBoxPySignal, self).tearDown() del self.obj del self.spin def testValueChanged(self): """Emission of a python signal to QSpinBox setValue(int)""" QObject.connect(self.obj, SIGNAL("dummy(int)"), self.spin, SLOT("setValue(int)")) self.assertEqual(self.spin.value(), 0) self.obj.emit(SIGNAL("dummy(int)"), 4) self.assertEqual(self.spin.value(), 4) def testValueChangedMultiple(self): """Multiple emissions of a python signal to QSpinBox setValue(int)""" QObject.connect(self.obj, SIGNAL("dummy(int)"), self.spin, SLOT("setValue(int)")) self.assertEqual(self.spin.value(), 0) self.obj.emit(SIGNAL("dummy(int)"), 4) self.assertEqual(self.spin.value(), 4) self.obj.emit(SIGNAL("dummy(int)"), 77) self.assertEqual(self.spin.value(), 77)
def testSpinButton(self): #Connecting a lambda to a QPushButton.clicked() obj = QSpinBox() ctr = Control() arg = 444 func = lambda x: setattr(ctr, 'arg', 444) QObject.connect(obj, SIGNAL('valueChanged(int)'), func) obj.setValue(444) self.assertEqual(ctr.arg, arg) QObject.disconnect(obj, SIGNAL('valueChanged(int)'), func)
def testSetValueIndirect(self): """Indirect signal emission: QSpinBox using valueChanged(int)/setValue(int)""" spinSend = QSpinBox() spinRec = QSpinBox() spinRec.setValue(5) QObject.connect(spinSend, SIGNAL('valueChanged(int)'), spinRec, SLOT('setValue(int)')) self.assertEqual(spinRec.value(), 5) spinSend.setValue(3) self.assertEqual(spinRec.value(), 3) self.assertEqual(spinSend.value(), 3)
def testSetValue(self): """Direct signal emission: QSpinBox using valueChanged(int)/setValue(int)""" spinSend = QSpinBox() spinRec = QSpinBox() spinRec.setValue(5) spinSend.setValue(42) QObject.connect(spinSend, SIGNAL('valueChanged(int)'), spinRec, SLOT('setValue(int)')) self.assertEqual(spinRec.value(), 5) self.assertEqual(spinSend.value(), 42) spinSend.emit(SIGNAL('valueChanged(int)'), 3) self.assertEqual(spinRec.value(), 3) #Direct emission shouldn't change the value of the emitter self.assertEqual(spinSend.value(), 42) spinSend.emit(SIGNAL('valueChanged(int)'), 66) self.assertEqual(spinRec.value(), 66) self.assertEqual(spinSend.value(), 42)
class DownloadComponent(QGroupBox): reportFormatChanged = Signal(ReportWriter) saveCompleted = Signal(bool) def __init__(self): super().__init__() self._report_writer = None self._report_writer_thread = ReportWriterThread() self._report_writer_thread.completed.connect(self._saveCompleted) self._progress_message = ProgressMessageBox(self.parentWidget(), "Export des données en cours...", "Export des données en cours...", 0, 0) self._report_types = { "summary": {"name": "Résumé", "description": "Le résumé inclu les statistiques générales sur les images analysées"}, "full": {"name": "Complet", "description": "Le rapport complet inclu les statistiques détaillées sur les images analysées"}, "annotations": {"name": "Annotations", "description": "Converti les résultats de l'analyse en annotation utilisable pour l'entrainement"} } self._report_formats = { "summary": { "PDF": {"type": "Document PDF", "extension": "*.pdf"}, "Texte": {"type": "Fichier texte", "extension": "*.txt"} }, "full": { "CSV": {"type": "Fichier CSV", "extension": "*.csv"}, "JSON": {"type": "Fichier JSON", "extension": "*.json"}, "XML": {"type": "Fichier XML", "extension": "*.xml"}, }, "annotations": { "Annotations YOLOv4": {"type": "Fichier zip", "extension": "*.zip"} } } self._default_report_type = "summary" self.setTitle("Paramètres") self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Minimum) self._form_layout = QFormLayout() self._form_layout.setHorizontalSpacing(20) self._form_layout.setVerticalSpacing(14) self._report_type_cbox = QComboBox() for report_type, v in self._report_types.items(): self._report_type_cbox.addItem(v["name"], report_type) self._form_layout.addRow("Type de rapport :", self._report_type_cbox) self._info_text = QLabel(self._report_types[self._default_report_type]["description"]) self._info_text.setObjectName("info") self._form_layout.addRow(self._info_text) self._report_format_cbox = QComboBox() for format, data in self._report_formats[self._default_report_type].items(): self._report_format_cbox.addItem(format, data) self._form_layout.addRow("Format du rapport :", self._report_format_cbox) self._detection_shape_cbox = QComboBox() self._detection_shape_cbox.addItem("Rectangle", "rectangle") self._detection_shape_cbox.addItem("Cercle", "circle") self._detection_shape_cbox.hide() self._separator_cbox = QComboBox() self._separator_cbox.addItem("Point virgule", ";") self._separator_cbox.addItem("Virgule", ",") self._separator_cbox.hide() self._nb_keeped_spinbox = QSpinBox(self) self._nb_keeped_spinbox.setRange(1, 1) self._nb_keeped_spinbox.hide() download_button = StylizedButton("Télécharger", "blue") download_button.setSizePolicy(QSizePolicy.Maximum, QSizePolicy.Maximum) button_layout = QHBoxLayout() button_layout.setAlignment(Qt.AlignRight) button_layout.addWidget(download_button) main_layout = QVBoxLayout(self) main_layout.addLayout(self._form_layout) main_layout.addStretch(1) main_layout.addLayout(button_layout) # Signals download_button.clicked.connect(self._exportReport) self._report_type_cbox.currentIndexChanged.connect(self._reportTypeChanged) self._report_format_cbox.currentTextChanged.connect(self._reportFormatChanged) self._detection_shape_cbox.currentIndexChanged.connect(self._reportParamsChanged) self._separator_cbox.currentIndexChanged.connect(self._reportParamsChanged) def reset(self, analysis: Analysis): self._analysis = analysis self._report_type_cbox.setCurrentIndex(0) self._report_format_cbox.setCurrentIndex(0) self._nb_keeped_spinbox.setMaximum(analysis.imagesWithDetections()) self._nb_keeped_spinbox.setValue(min(100, analysis.imagesWithDetections())) self._loadWriter() def _loadWriter(self): format_text = self._report_format_cbox.currentText() if format_text == "PDF": self._report_writer = PDFReportWriter(self._analysis) elif format_text == "Texte": self._report_writer = TextReportWriter(self._analysis) elif format_text == "CSV": self._report_writer = CSVReportWriter(self._analysis, self._separator_cbox.currentData(), self._detection_shape_cbox.currentData()) elif format_text == "JSON": self._report_writer = JSONReportWriter(self._analysis, shape=self._detection_shape_cbox.currentData()) elif format_text == "XML": self._report_writer = XMLReportWriter(self._analysis, shape=self._detection_shape_cbox.currentData()) elif format_text == "Annotations YOLOv4": self._report_writer = Yolov4AnnotationsWriter(self._analysis) self.reportFormatChanged.emit(self._report_writer) @Slot(int) def _reportTypeChanged(self, index: int): report_type = self._report_type_cbox.currentData() self._info_text.setText(self._report_types[report_type]["description"]) self._report_format_cbox.clear() for format, data in self._report_formats[report_type].items(): self._report_format_cbox.addItem(format, data) if report_type == "summary": self._showDetectionShape(False) self._showSeparator(False) self._showKeepedNumber(False) elif report_type == "full": self._showDetectionShape(True) self._showKeepedNumber(False) elif report_type == "annotations": self._showDetectionShape(False) self._showSeparator(False) self._showKeepedNumber(True) @Slot(str) def _reportFormatChanged(self, format: str): if format == "CSV": self._showSeparator(True) else: # JSON & XSML self._showSeparator(False) self._loadWriter() def _showDetectionShape(self, show: bool): self._showRow("Détection :", self._detection_shape_cbox, show) def _showSeparator(self, show: bool): self._showRow("Séparateur :", self._separator_cbox, show) def _showKeepedNumber(self, show: bool): self._showRow("Images à exporter :", self._nb_keeped_spinbox, show) def _showRow(self, label: str, widget: QWidget, show: bool): if show and not widget.isVisible(): widget.show() self._form_layout.addRow(label, widget) elif not show and widget.isVisible(): label = self._form_layout.labelForField(widget) widget.hide() label.hide() self._form_layout.removeWidget(widget) self._form_layout.removeWidget(label) del label @Slot(int) def _reportParamsChanged(self, index: int): self._loadWriter() @Slot() def _exportReport(self): report_type = self._report_type_cbox.currentData() if report_type == "annotations": self._report_writer.setKeep(self._nb_keeped_spinbox.value()) error = self._report_writer.checkErrors() if error: QMessageBox.warning(self.parentWidget(), "Impossible de générer le rapport", error) return filename = self._analysis.parameters().name() report_format = self._report_format_cbox.currentData() path = QStandardPaths.writableLocation(QStandardPaths.DocumentsLocation) + "/" + filename filter = "Fichier %s (%s)" % (report_format["type"], report_format["extension"]) result = QFileDialog.getSaveFileName(self, "Enregistrer le fichier", path, filter) filepath = result[0] if filepath == '': return self._report_writer_thread.start(self._report_writer, filepath) self._progress_message.exec_() @Slot() def _saveCompleted(self, success: bool): if self._progress_message: self._progress_message.close() self.saveCompleted.emit(success)
class segmentForm(baseForm): """ Segmentation (grabcut) form """ layerTitle = "Segmentation" iterDefault = 3 contourMarginDefault = 1 @classmethod def getNewWindow(cls, targetImage=None, layer=None, mainForm=None): wdgt = segmentForm(layer=layer) return wdgt def __init__(self, layer=None): super(segmentForm, self).__init__() self.setWindowTitle('grabcut') self.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Preferred) self.setMinimumSize(200, 200) self.setAttribute(Qt.WA_DeleteOnClose) # link back to image layer self.layer = weakProxy(layer) pushButton = QPushButton('apply') # button slot def f(): self.layer.noSegment = False self.layer.applyToStack() window.label.img.onImageChanged() # do manual segmentation only layer.noSegment = True pushButton.clicked.connect(f) pushButton1 = QPushButton('Reset') pushButton1.clicked.connect(lambda : self.reset()) self.spBox = QSpinBox() self.spBox.setRange(1,10) # spBox Slot def f2(iterCount): self.spBox.valueChanged.disconnect() self.dataChanged.emit() self.spBox.valueChanged.connect(f2) self.spBox.valueChanged.connect(f2) spBoxLabel = QLabel() spBoxLabel.setText('Iterations') self.spBox1 = QSpinBox() self.spBox1.setRange(0, 20) spBox1Label = QLabel() spBox1Label.setText('Contour Margin') # spBox1 slot def f1(margin): self.spBox1.valueChanged.disconnect() self.dataChanged.emit() self.spBox1.valueChanged.connect(f1) self.spBox1.valueChanged.connect(f1) # options optionList1, optionNames1 = ['Clipping Layer'], ['Clipping Layer'] self.listWidget1 = optionsWidget(options=optionList1, optionNames=optionNames1, exclusive=False) self.options = self.listWidget1.options # option changed slot def g(item): self.layer.isClipping = self.options['Clipping Layer'] self.layer.applyToStack() self.layer.parentImage.onImageChanged() self.listWidget1.onSelect = g # attributes initialized in setDefaults, declared here # for the sake of correctness self.start = None self.nbIter = None self.contourMargin = None # layout hLay = QHBoxLayout() hLay.addWidget(spBoxLabel) hLay.addWidget(self.spBox) hLay.addStretch(1) hLay1 = QHBoxLayout() hLay1.addWidget(spBox1Label) hLay1.addWidget(self.spBox1) hLay1.addStretch(1) h2 = QHBoxLayout() h2.addWidget(self.listWidget1) vLay = QVBoxLayout() vLay.setAlignment(Qt.AlignTop) vLay.setContentsMargins(20, 8, 20, 25) # left, top, right, bottom vLay.addLayout(hLay) vLay.addLayout(hLay1) vLay.addLayout(h2) h3 = QHBoxLayout() h3.addWidget(pushButton) h3.addWidget(pushButton1) vLay.addLayout(h3) self.setLayout(vLay) self.setDefaults() self.setWhatsThis( """ <b>Object extraction</b><br> Select the object to extract with the rectangle Marquee Tool. Next, click the Apply button.<br> Correct (roughly) if needed the foreground (FG) and the background (BG) regions using the FG and BG tools (Ctrl to undo) and click again the Apply button.<br> To get a smoother contour increase the value of the Contour Margin and click the Apply Button.<br> By default the mask is displayed as a color mask. To view it as an opacity mask, right click on the Segmentation layer row in the right pane and check Enable Mask As > Opacity Mask in the context menu. Use the same context menu to copy/paste the object to a new image layer or the mask to another layer.<br> """ ) # end setWhatsThis def setDefaults(self): # prevent multiple updates try: self.dataChanged.disconnect() except RuntimeError: pass self.listWidget1.unCheckAll() self.spBox.setValue(self.iterDefault) self.spBox1.setValue(self.contourMarginDefault) self.start = True self.dataChanged.connect(self.updateLayer) # self.dataChanged.emit() # TODO 30/10/18 removed validate def updateLayer(self): self.nbIter = self.spBox.value() self.contourMargin = self.spBox1.value() def reset(self): layer = self.layer layer.maskIsEnabled = True layer.maskIsSelected = True # mask pixels are not yet painted as FG or BG # so we mark them as invalid layer.mask.fill(vImage.defaultColor_Invalid) layer.paintedMask = layer.mask.copy() layer.isClipping = False self.setDefaults() self.dataChanged.emit() # TODO added 30/10/18 validate layer.updatePixmap()
class QSettingsWindow(QDialog): def __init__(self, game: Game): super(QSettingsWindow, self).__init__() self.game = game self.pluginsPage = None self.pluginsOptionsPage = None self.campaign_management_page = QWidget() self.setModal(True) self.setWindowTitle("Settings") self.setWindowIcon(CONST.ICONS["Settings"]) self.setMinimumSize(600, 250) self.initUi() def initUi(self): self.layout = QGridLayout() self.categoryList = QListView() self.right_layout = QStackedLayout() self.categoryList.setMaximumWidth(175) self.categoryModel = QStandardItemModel(self.categoryList) self.categoryList.setIconSize(QSize(32, 32)) self.initDifficultyLayout() difficulty = QStandardItem("Difficulty") difficulty.setIcon(CONST.ICONS["Missile"]) difficulty.setEditable(False) difficulty.setSelectable(True) self.categoryModel.appendRow(difficulty) self.right_layout.addWidget(self.difficultyPage) self.init_campaign_management_layout() campaign_management = QStandardItem("Campaign Management") campaign_management.setIcon(CONST.ICONS["Money"]) campaign_management.setEditable(False) campaign_management.setSelectable(True) self.categoryModel.appendRow(campaign_management) self.right_layout.addWidget(self.campaign_management_page) self.initGeneratorLayout() generator = QStandardItem("Mission Generator") generator.setIcon(CONST.ICONS["Generator"]) generator.setEditable(False) generator.setSelectable(True) self.categoryModel.appendRow(generator) self.right_layout.addWidget(self.generatorPage) self.initCheatLayout() cheat = QStandardItem("Cheat Menu") cheat.setIcon(CONST.ICONS["Cheat"]) cheat.setEditable(False) cheat.setSelectable(True) self.categoryModel.appendRow(cheat) self.right_layout.addWidget(self.cheatPage) self.pluginsPage = PluginsPage() plugins = QStandardItem("LUA Plugins") plugins.setIcon(CONST.ICONS["Plugins"]) plugins.setEditable(False) plugins.setSelectable(True) self.categoryModel.appendRow(plugins) self.right_layout.addWidget(self.pluginsPage) self.pluginsOptionsPage = PluginOptionsPage() pluginsOptions = QStandardItem("LUA Plugins Options") pluginsOptions.setIcon(CONST.ICONS["PluginsOptions"]) pluginsOptions.setEditable(False) pluginsOptions.setSelectable(True) self.categoryModel.appendRow(pluginsOptions) self.right_layout.addWidget(self.pluginsOptionsPage) self.categoryList.setSelectionBehavior(QAbstractItemView.SelectRows) self.categoryList.setModel(self.categoryModel) self.categoryList.selectionModel().setCurrentIndex(self.categoryList.indexAt(QPoint(1,1)), QItemSelectionModel.Select) self.categoryList.selectionModel().selectionChanged.connect(self.onSelectionChanged) self.layout.addWidget(self.categoryList, 0, 0, 1, 1) self.layout.addLayout(self.right_layout, 0, 1, 5, 1) self.setLayout(self.layout) def init(self): pass def initDifficultyLayout(self): self.difficultyPage = QWidget() self.difficultyLayout = QVBoxLayout() self.difficultyLayout.setAlignment(Qt.AlignTop) self.difficultyPage.setLayout(self.difficultyLayout) # DCS AI difficulty settings self.aiDifficultySettings = QGroupBox("AI Difficulty") self.aiDifficultyLayout = QGridLayout() self.playerCoalitionSkill = QComboBox() self.enemyCoalitionSkill = QComboBox() self.enemyAASkill = QComboBox() for skill in CONST.SKILL_OPTIONS: self.playerCoalitionSkill.addItem(skill) self.enemyCoalitionSkill.addItem(skill) self.enemyAASkill.addItem(skill) self.playerCoalitionSkill.setCurrentIndex(CONST.SKILL_OPTIONS.index(self.game.settings.player_skill)) self.enemyCoalitionSkill.setCurrentIndex(CONST.SKILL_OPTIONS.index(self.game.settings.enemy_skill)) self.enemyAASkill.setCurrentIndex(CONST.SKILL_OPTIONS.index(self.game.settings.enemy_vehicle_skill)) self.player_income = TenthsSpinSlider( "Player income multiplier", 1, 50, int(self.game.settings.player_income_multiplier * 10)) self.player_income.spinner.valueChanged.connect(self.applySettings) self.enemy_income = TenthsSpinSlider( "Enemy income multiplier", 1, 50, int(self.game.settings.enemy_income_multiplier * 10)) self.enemy_income.spinner.valueChanged.connect(self.applySettings) self.playerCoalitionSkill.currentIndexChanged.connect(self.applySettings) self.enemyCoalitionSkill.currentIndexChanged.connect(self.applySettings) self.enemyAASkill.currentIndexChanged.connect(self.applySettings) # Mission generation settings related to difficulty self.missionSettings = QGroupBox("Mission Difficulty") self.missionLayout = QGridLayout() self.manpads = QCheckBox() self.manpads.setChecked(self.game.settings.manpads) self.manpads.toggled.connect(self.applySettings) self.noNightMission = QCheckBox() self.noNightMission.setChecked(self.game.settings.night_disabled) self.noNightMission.toggled.connect(self.applySettings) # DCS Mission options self.missionRestrictionsSettings = QGroupBox("Mission Restrictions") self.missionRestrictionsLayout = QGridLayout() self.difficultyLabel = QComboBox() [self.difficultyLabel.addItem(t) for t in CONST.LABELS_OPTIONS] self.difficultyLabel.setCurrentIndex(CONST.LABELS_OPTIONS.index(self.game.settings.labels)) self.difficultyLabel.currentIndexChanged.connect(self.applySettings) self.mapVisibiitySelection = QComboBox() self.mapVisibiitySelection.addItem("All", ForcedOptions.Views.All) if self.game.settings.map_coalition_visibility == ForcedOptions.Views.All: self.mapVisibiitySelection.setCurrentIndex(0) self.mapVisibiitySelection.addItem("Fog of War", ForcedOptions.Views.Allies) if self.game.settings.map_coalition_visibility == ForcedOptions.Views.Allies: self.mapVisibiitySelection.setCurrentIndex(1) self.mapVisibiitySelection.addItem("Allies Only", ForcedOptions.Views.OnlyAllies) if self.game.settings.map_coalition_visibility == ForcedOptions.Views.OnlyAllies: self.mapVisibiitySelection.setCurrentIndex(2) self.mapVisibiitySelection.addItem("Own Aircraft Only", ForcedOptions.Views.MyAircraft) if self.game.settings.map_coalition_visibility == ForcedOptions.Views.MyAircraft: self.mapVisibiitySelection.setCurrentIndex(3) self.mapVisibiitySelection.addItem("Map Only", ForcedOptions.Views.OnlyMap) if self.game.settings.map_coalition_visibility == ForcedOptions.Views.OnlyMap: self.mapVisibiitySelection.setCurrentIndex(4) self.mapVisibiitySelection.currentIndexChanged.connect(self.applySettings) self.ext_views = QCheckBox() self.ext_views.setChecked(self.game.settings.external_views_allowed) self.ext_views.toggled.connect(self.applySettings) self.aiDifficultyLayout.addWidget(QLabel("Player coalition skill"), 0, 0) self.aiDifficultyLayout.addWidget(self.playerCoalitionSkill, 0, 1, Qt.AlignRight) self.aiDifficultyLayout.addWidget(QLabel("Enemy coalition skill"), 1, 0) self.aiDifficultyLayout.addWidget(self.enemyCoalitionSkill, 1, 1, Qt.AlignRight) self.aiDifficultyLayout.addWidget(QLabel("Enemy AA and vehicles skill"), 2, 0) self.aiDifficultyLayout.addWidget(self.enemyAASkill, 2, 1, Qt.AlignRight) self.aiDifficultyLayout.addLayout(self.player_income, 3, 0) self.aiDifficultyLayout.addLayout(self.enemy_income, 4, 0) self.aiDifficultySettings.setLayout(self.aiDifficultyLayout) self.difficultyLayout.addWidget(self.aiDifficultySettings) self.missionLayout.addWidget(QLabel("Manpads on frontlines"), 0, 0) self.missionLayout.addWidget(self.manpads, 0, 1, Qt.AlignRight) self.missionLayout.addWidget(QLabel("No night missions"), 1, 0) self.missionLayout.addWidget(self.noNightMission, 1, 1, Qt.AlignRight) self.missionSettings.setLayout(self.missionLayout) self.difficultyLayout.addWidget(self.missionSettings) self.missionRestrictionsLayout.addWidget(QLabel("In Game Labels"), 0, 0) self.missionRestrictionsLayout.addWidget(self.difficultyLabel, 0, 1, Qt.AlignRight) self.missionRestrictionsLayout.addWidget(QLabel("Map visibility options"), 1, 0) self.missionRestrictionsLayout.addWidget(self.mapVisibiitySelection, 1, 1, Qt.AlignRight) self.missionRestrictionsLayout.addWidget(QLabel("Allow external views"), 2, 0) self.missionRestrictionsLayout.addWidget(self.ext_views, 2, 1, Qt.AlignRight) self.missionRestrictionsSettings.setLayout(self.missionRestrictionsLayout) self.difficultyLayout.addWidget(self.missionRestrictionsSettings) def init_campaign_management_layout(self) -> None: campaign_layout = QVBoxLayout() campaign_layout.setAlignment(Qt.AlignTop) self.campaign_management_page.setLayout(campaign_layout) general = QGroupBox("General") campaign_layout.addWidget(general) general_layout = QGridLayout() general.setLayout(general_layout) def set_restict_weapons_by_date(value: bool) -> None: self.game.settings.restrict_weapons_by_date = value restrict_weapons = QCheckBox() restrict_weapons.setChecked(self.game.settings.restrict_weapons_by_date) restrict_weapons.toggled.connect(set_restict_weapons_by_date) tooltip_text = ( "Restricts weapon availability based on the campaign date. Data is " "extremely incomplete so does not affect all weapons." ) restrict_weapons.setToolTip(tooltip_text) restrict_weapons_label = QLabel("Restrict weapons by date (WIP)") restrict_weapons_label.setToolTip(tooltip_text) general_layout.addWidget(restrict_weapons_label, 0, 0) general_layout.addWidget(restrict_weapons, 0, 1, Qt.AlignRight) automation = QGroupBox("HQ Automation") campaign_layout.addWidget(automation) automation_layout = QGridLayout() automation.setLayout(automation_layout) def set_runway_automation(value: bool) -> None: self.game.settings.automate_runway_repair = value def set_front_line_automation(value: bool) -> None: self.game.settings.automate_front_line_reinforcements = value def set_aircraft_automation(value: bool) -> None: self.game.settings.automate_aircraft_reinforcements = value runway_repair = QCheckBox() runway_repair.setChecked( self.game.settings.automate_runway_repair) runway_repair.toggled.connect(set_runway_automation) automation_layout.addWidget(QLabel("Automate runway repairs"), 0, 0) automation_layout.addWidget(runway_repair, 0, 1, Qt.AlignRight) front_line = QCheckBox() front_line.setChecked( self.game.settings.automate_front_line_reinforcements) front_line.toggled.connect(set_front_line_automation) automation_layout.addWidget( QLabel("Automate front-line purchases"), 1, 0) automation_layout.addWidget(front_line, 1, 1, Qt.AlignRight) aircraft = QCheckBox() aircraft.setChecked( self.game.settings.automate_aircraft_reinforcements) aircraft.toggled.connect(set_aircraft_automation) automation_layout.addWidget(QLabel("Automate aircraft purchases"), 2, 0) automation_layout.addWidget(aircraft, 2, 1, Qt.AlignRight) def initGeneratorLayout(self): self.generatorPage = QWidget() self.generatorLayout = QVBoxLayout() self.generatorLayout.setAlignment(Qt.AlignTop) self.generatorPage.setLayout(self.generatorLayout) self.gameplay = QGroupBox("Gameplay") self.gameplayLayout = QGridLayout() self.gameplayLayout.setAlignment(Qt.AlignTop) self.gameplay.setLayout(self.gameplayLayout) self.supercarrier = QCheckBox() self.supercarrier.setChecked(self.game.settings.supercarrier) self.supercarrier.toggled.connect(self.applySettings) self.generate_marks = QCheckBox() self.generate_marks.setChecked(self.game.settings.generate_marks) self.generate_marks.toggled.connect(self.applySettings) self.never_delay_players = QCheckBox() self.never_delay_players.setChecked( self.game.settings.never_delay_player_flights) self.never_delay_players.toggled.connect(self.applySettings) self.never_delay_players.setToolTip( "When checked, player flights with a delayed start time will be " "spawned immediately. AI wingmen may begin startup immediately." ) self.gameplayLayout.addWidget(QLabel("Use Supercarrier Module"), 0, 0) self.gameplayLayout.addWidget(self.supercarrier, 0, 1, Qt.AlignRight) self.gameplayLayout.addWidget(QLabel("Put Objective Markers on Map"), 1, 0) self.gameplayLayout.addWidget(self.generate_marks, 1, 1, Qt.AlignRight) self.gameplayLayout.addWidget( QLabel("Never delay player flights"), 2, 0) self.gameplayLayout.addWidget(self.never_delay_players, 2, 1, Qt.AlignRight) start_type_label = QLabel( "Default start type for AI aircraft:<br /><strong>Warning: " + "Any option other than Cold breaks OCA/Aircraft missions.</strong>" ) start_type_label.setToolTip(START_TYPE_TOOLTIP) start_type = StartTypeComboBox(self.game.settings) start_type.setCurrentText(self.game.settings.default_start_type) self.gameplayLayout.addWidget(start_type_label, 3, 0) self.gameplayLayout.addWidget(start_type, 3, 1) self.performance = QGroupBox("Performance") self.performanceLayout = QGridLayout() self.performanceLayout.setAlignment(Qt.AlignTop) self.performance.setLayout(self.performanceLayout) self.smoke = QCheckBox() self.smoke.setChecked(self.game.settings.perf_smoke_gen) self.smoke.toggled.connect(self.applySettings) self.red_alert = QCheckBox() self.red_alert.setChecked(self.game.settings.perf_red_alert_state) self.red_alert.toggled.connect(self.applySettings) self.arti = QCheckBox() self.arti.setChecked(self.game.settings.perf_artillery) self.arti.toggled.connect(self.applySettings) self.moving_units = QCheckBox() self.moving_units.setChecked(self.game.settings.perf_moving_units) self.moving_units.toggled.connect(self.applySettings) self.infantry = QCheckBox() self.infantry.setChecked(self.game.settings.perf_infantry) self.infantry.toggled.connect(self.applySettings) self.destroyed_units = QCheckBox() self.destroyed_units.setChecked(self.game.settings.perf_destroyed_units) self.destroyed_units.toggled.connect(self.applySettings) self.culling = QCheckBox() self.culling.setChecked(self.game.settings.perf_culling) self.culling.toggled.connect(self.applySettings) self.culling_distance = QSpinBox() self.culling_distance.setMinimum(10) self.culling_distance.setMaximum(10000) self.culling_distance.setValue(self.game.settings.perf_culling_distance) self.culling_distance.valueChanged.connect(self.applySettings) self.culling_do_not_cull_carrier = QCheckBox() self.culling_do_not_cull_carrier.setChecked(self.game.settings.perf_do_not_cull_carrier) self.culling_do_not_cull_carrier.toggled.connect(self.applySettings) self.performanceLayout.addWidget(QLabel("Smoke visual effect on frontline"), 0, 0) self.performanceLayout.addWidget(self.smoke, 0, 1, alignment=Qt.AlignRight) self.performanceLayout.addWidget(QLabel("SAM starts in RED alert mode"), 1, 0) self.performanceLayout.addWidget(self.red_alert, 1, 1, alignment=Qt.AlignRight) self.performanceLayout.addWidget(QLabel("Artillery strikes"), 2, 0) self.performanceLayout.addWidget(self.arti, 2, 1, alignment=Qt.AlignRight) self.performanceLayout.addWidget(QLabel("Moving ground units"), 3, 0) self.performanceLayout.addWidget(self.moving_units, 3, 1, alignment=Qt.AlignRight) self.performanceLayout.addWidget(QLabel("Generate infantry squads along vehicles"), 4, 0) self.performanceLayout.addWidget(self.infantry, 4, 1, alignment=Qt.AlignRight) self.performanceLayout.addWidget(QLabel("Include destroyed units carcass"), 6, 0) self.performanceLayout.addWidget(self.destroyed_units, 6, 1, alignment=Qt.AlignRight) self.performanceLayout.addWidget(QHorizontalSeparationLine(), 7, 0, 1, 2) self.performanceLayout.addWidget(QLabel("Culling of distant units enabled"), 8, 0) self.performanceLayout.addWidget(self.culling, 8, 1, alignment=Qt.AlignRight) self.performanceLayout.addWidget(QLabel("Culling distance (km)"), 9, 0) self.performanceLayout.addWidget(self.culling_distance, 9, 1, alignment=Qt.AlignRight) self.performanceLayout.addWidget(QLabel("Do not cull carrier's surroundings"), 10, 0) self.performanceLayout.addWidget(self.culling_do_not_cull_carrier, 10, 1, alignment=Qt.AlignRight) self.generatorLayout.addWidget(self.gameplay) self.generatorLayout.addWidget(QLabel("Disabling settings below may improve performance, but will impact the overall quality of the experience.")) self.generatorLayout.addWidget(self.performance) def initCheatLayout(self): self.cheatPage = QWidget() self.cheatLayout = QVBoxLayout() self.cheatPage.setLayout(self.cheatLayout) self.cheat_options = CheatSettingsBox(self.game, self.applySettings) self.cheatLayout.addWidget(self.cheat_options) self.moneyCheatBox = QGroupBox("Money Cheat") self.moneyCheatBox.setAlignment(Qt.AlignTop) self.moneyCheatBoxLayout = QGridLayout() self.moneyCheatBox.setLayout(self.moneyCheatBoxLayout) cheats_amounts = [25, 50, 100, 200, 500, 1000, -25, -50, -100, -200] for i, amount in enumerate(cheats_amounts): if amount > 0: btn = QPushButton("Cheat +" + str(amount) + "M") btn.setProperty("style", "btn-success") else: btn = QPushButton("Cheat " + str(amount) + "M") btn.setProperty("style", "btn-danger") btn.clicked.connect(self.cheatLambda(amount)) self.moneyCheatBoxLayout.addWidget(btn, i/2, i%2) self.cheatLayout.addWidget(self.moneyCheatBox, stretch=1) def cheatLambda(self, amount): return lambda: self.cheatMoney(amount) def cheatMoney(self, amount): logging.info("CHEATING FOR AMOUNT : " + str(amount) + "M") self.game.budget += amount if amount > 0: self.game.informations.append(Information("CHEATER", "You are a cheater and you should feel bad", self.game.turn)) else: self.game.informations.append(Information("CHEATER", "You are still a cheater !", self.game.turn)) GameUpdateSignal.get_instance().updateGame(self.game) def applySettings(self): self.game.settings.player_skill = CONST.SKILL_OPTIONS[self.playerCoalitionSkill.currentIndex()] self.game.settings.enemy_skill = CONST.SKILL_OPTIONS[self.enemyCoalitionSkill.currentIndex()] self.game.settings.enemy_vehicle_skill = CONST.SKILL_OPTIONS[self.enemyAASkill.currentIndex()] self.game.settings.player_income_multiplier = self.player_income.value self.game.settings.enemy_income_multiplier = self.enemy_income.value self.game.settings.manpads = self.manpads.isChecked() self.game.settings.labels = CONST.LABELS_OPTIONS[self.difficultyLabel.currentIndex()] self.game.settings.night_disabled = self.noNightMission.isChecked() self.game.settings.map_coalition_visibility = self.mapVisibiitySelection.currentData() self.game.settings.external_views_allowed = self.ext_views.isChecked() self.game.settings.generate_marks = self.generate_marks.isChecked() self.game.settings.never_delay_player_flights = self.never_delay_players.isChecked() self.game.settings.supercarrier = self.supercarrier.isChecked() self.game.settings.perf_red_alert_state = self.red_alert.isChecked() self.game.settings.perf_smoke_gen = self.smoke.isChecked() self.game.settings.perf_artillery = self.arti.isChecked() self.game.settings.perf_moving_units = self.moving_units.isChecked() self.game.settings.perf_infantry = self.infantry.isChecked() self.game.settings.perf_destroyed_units = self.destroyed_units.isChecked() self.game.settings.perf_culling = self.culling.isChecked() self.game.settings.perf_culling_distance = int(self.culling_distance.value()) self.game.settings.perf_do_not_cull_carrier = self.culling_do_not_cull_carrier.isChecked() self.game.settings.show_red_ato = self.cheat_options.show_red_ato self.game.settings.enable_frontline_cheats = self.cheat_options.show_frontline_cheat self.game.settings.enable_base_capture_cheat = self.cheat_options.show_base_capture_cheat self.game.compute_conflicts_position() GameUpdateSignal.get_instance().updateGame(self.game) def onSelectionChanged(self): index = self.categoryList.selectionModel().currentIndex().row() self.right_layout.setCurrentIndex(index)
class QSettingsWindow(QDialog): def __init__(self, game: Game): super(QSettingsWindow, self).__init__() self.game = game self.setModal(True) self.setWindowTitle("Settings") self.setWindowIcon(CONST.ICONS["Settings"]) self.setMinimumSize(600, 250) self.initUi() def initUi(self): self.layout = QGridLayout() self.categoryList = QListView() self.right_layout = QStackedLayout() self.categoryList.setMaximumWidth(175) self.categoryModel = QStandardItemModel(self.categoryList) difficulty = QStandardItem("Difficulty") difficulty.setIcon(CONST.ICONS["Missile"]) difficulty.setEditable(False) difficulty.setSelectable(True) generator = QStandardItem("Mission Generator") generator.setIcon(CONST.ICONS["Generator"]) generator.setEditable(False) generator.setSelectable(True) cheat = QStandardItem("Cheat Menu") cheat.setIcon(CONST.ICONS["Cheat"]) cheat.setEditable(False) cheat.setSelectable(True) self.categoryList.setIconSize(QSize(32, 32)) self.categoryModel.appendRow(difficulty) self.categoryModel.appendRow(generator) self.categoryModel.appendRow(cheat) self.categoryList.setSelectionBehavior(QAbstractItemView.SelectRows) self.categoryList.setModel(self.categoryModel) self.categoryList.selectionModel().setCurrentIndex( self.categoryList.indexAt(QPoint(1, 1)), QItemSelectionModel.Select) self.categoryList.selectionModel().selectionChanged.connect( self.onSelectionChanged) self.initDifficultyLayout() self.initGeneratorLayout() self.initCheatLayout() self.right_layout.addWidget(self.difficultyPage) self.right_layout.addWidget(self.generatorPage) self.right_layout.addWidget(self.cheatPage) self.layout.addWidget(self.categoryList, 0, 0, 1, 1) self.layout.addLayout(self.right_layout, 0, 1, 5, 1) self.setLayout(self.layout) def init(self): pass def initDifficultyLayout(self): self.difficultyPage = QWidget() self.difficultyLayout = QGridLayout() self.difficultyLayout.setAlignment(Qt.AlignTop) self.difficultyPage.setLayout(self.difficultyLayout) self.playerCoalitionSkill = QComboBox() self.enemyCoalitionSkill = QComboBox() self.enemyAASkill = QComboBox() for skill in CONST.SKILL_OPTIONS: self.playerCoalitionSkill.addItem(skill) self.enemyCoalitionSkill.addItem(skill) self.enemyAASkill.addItem(skill) self.playerCoalitionSkill.setCurrentIndex( CONST.SKILL_OPTIONS.index(self.game.settings.player_skill)) self.enemyCoalitionSkill.setCurrentIndex( CONST.SKILL_OPTIONS.index(self.game.settings.enemy_skill)) self.enemyAASkill.setCurrentIndex( CONST.SKILL_OPTIONS.index(self.game.settings.enemy_vehicle_skill)) self.playerCoalitionSkill.currentIndexChanged.connect( self.applySettings) self.enemyCoalitionSkill.currentIndexChanged.connect( self.applySettings) self.enemyAASkill.currentIndexChanged.connect(self.applySettings) self.difficultyLayout.addWidget(QLabel("Player coalition skill"), 0, 0) self.difficultyLayout.addWidget(self.playerCoalitionSkill, 0, 1, Qt.AlignRight) self.difficultyLayout.addWidget(QLabel("Enemy skill"), 1, 0) self.difficultyLayout.addWidget(self.enemyCoalitionSkill, 1, 1, Qt.AlignRight) self.difficultyLayout.addWidget(QLabel("Enemy AA and vehicles skill"), 2, 0) self.difficultyLayout.addWidget(self.enemyAASkill, 2, 1, Qt.AlignRight) self.difficultyLabel = QComboBox() [self.difficultyLabel.addItem(t) for t in CONST.LABELS_OPTIONS] self.difficultyLabel.setCurrentIndex( CONST.LABELS_OPTIONS.index(self.game.settings.labels)) self.difficultyLabel.currentIndexChanged.connect(self.applySettings) self.difficultyLayout.addWidget(QLabel("In Game Labels"), 3, 0) self.difficultyLayout.addWidget(self.difficultyLabel, 3, 1, Qt.AlignRight) self.noNightMission = QCheckBox() self.noNightMission.setChecked(self.game.settings.night_disabled) self.noNightMission.toggled.connect(self.applySettings) self.difficultyLayout.addWidget(QLabel("No night missions"), 4, 0) self.difficultyLayout.addWidget(self.noNightMission, 4, 1, Qt.AlignRight) self.mapVisibiitySelection = QComboBox() self.mapVisibiitySelection.addItem("All", ForcedOptions.Views.All) if self.game.settings.map_coalition_visibility == ForcedOptions.Views.All: self.mapVisibiitySelection.setCurrentIndex(0) self.mapVisibiitySelection.addItem("Fog of War", ForcedOptions.Views.Allies) if self.game.settings.map_coalition_visibility == ForcedOptions.Views.Allies: self.mapVisibiitySelection.setCurrentIndex(1) self.mapVisibiitySelection.addItem("Allies Only", ForcedOptions.Views.OnlyAllies) if self.game.settings.map_coalition_visibility == ForcedOptions.Views.OnlyAllies: self.mapVisibiitySelection.setCurrentIndex(2) self.mapVisibiitySelection.addItem("Own Aircraft Only", ForcedOptions.Views.MyAircraft) if self.game.settings.map_coalition_visibility == ForcedOptions.Views.MyAircraft: self.mapVisibiitySelection.setCurrentIndex(3) self.mapVisibiitySelection.addItem("Map Only", ForcedOptions.Views.OnlyMap) if self.game.settings.map_coalition_visibility == ForcedOptions.Views.OnlyMap: self.mapVisibiitySelection.setCurrentIndex(4) self.mapVisibiitySelection.currentIndexChanged.connect( self.applySettings) self.difficultyLayout.addWidget(QLabel("Map visibility options"), 5, 0) self.difficultyLayout.addWidget(self.mapVisibiitySelection, 5, 1, Qt.AlignRight) self.ext_views = QCheckBox() self.ext_views.setChecked(self.game.settings.external_views_allowed) self.ext_views.toggled.connect(self.applySettings) self.difficultyLayout.addWidget(QLabel("Allow external views"), 6, 0) self.difficultyLayout.addWidget(self.ext_views, 6, 1, Qt.AlignRight) def initGeneratorLayout(self): self.generatorPage = QWidget() self.generatorLayout = QVBoxLayout() self.generatorLayout.setAlignment(Qt.AlignTop) self.generatorPage.setLayout(self.generatorLayout) self.gameplay = QGroupBox("Gameplay") self.gameplayLayout = QGridLayout() self.gameplayLayout.setAlignment(Qt.AlignTop) self.gameplay.setLayout(self.gameplayLayout) self.supercarrier = QCheckBox() self.supercarrier.setChecked(self.game.settings.supercarrier) self.supercarrier.toggled.connect(self.applySettings) self.generate_marks = QCheckBox() self.generate_marks.setChecked(self.game.settings.generate_marks) self.generate_marks.toggled.connect(self.applySettings) self.gameplayLayout.addWidget(QLabel("Use Supercarrier Module"), 0, 0) self.gameplayLayout.addWidget(self.supercarrier, 0, 1, Qt.AlignRight) self.gameplayLayout.addWidget(QLabel("Put Objective Markers on Map"), 1, 0) self.gameplayLayout.addWidget(self.generate_marks, 1, 1, Qt.AlignRight) self.performance = QGroupBox("Performance") self.performanceLayout = QGridLayout() self.performanceLayout.setAlignment(Qt.AlignTop) self.performance.setLayout(self.performanceLayout) self.smoke = QCheckBox() self.smoke.setChecked(self.game.settings.perf_smoke_gen) self.smoke.toggled.connect(self.applySettings) self.red_alert = QCheckBox() self.red_alert.setChecked(self.game.settings.perf_red_alert_state) self.red_alert.toggled.connect(self.applySettings) self.arti = QCheckBox() self.arti.setChecked(self.game.settings.perf_artillery) self.arti.toggled.connect(self.applySettings) self.moving_units = QCheckBox() self.moving_units.setChecked(self.game.settings.perf_moving_units) self.moving_units.toggled.connect(self.applySettings) self.infantry = QCheckBox() self.infantry.setChecked(self.game.settings.perf_infantry) self.infantry.toggled.connect(self.applySettings) self.ai_parking_start = QCheckBox() self.ai_parking_start.setChecked( self.game.settings.perf_ai_parking_start) self.ai_parking_start.toggled.connect(self.applySettings) self.culling = QCheckBox() self.culling.setChecked(self.game.settings.perf_culling) self.culling.toggled.connect(self.applySettings) self.culling_distance = QSpinBox() self.culling_distance.setMinimum(50) self.culling_distance.setMaximum(10000) self.culling_distance.setValue( self.game.settings.perf_culling_distance) self.culling_distance.valueChanged.connect(self.applySettings) self.performanceLayout.addWidget( QLabel("Smoke visual effect on frontline"), 0, 0) self.performanceLayout.addWidget(self.smoke, 0, 1, alignment=Qt.AlignRight) self.performanceLayout.addWidget( QLabel("SAM starts in RED alert mode"), 1, 0) self.performanceLayout.addWidget(self.red_alert, 1, 1, alignment=Qt.AlignRight) self.performanceLayout.addWidget(QLabel("Artillery strikes"), 2, 0) self.performanceLayout.addWidget(self.arti, 2, 1, alignment=Qt.AlignRight) self.performanceLayout.addWidget(QLabel("Moving ground units"), 3, 0) self.performanceLayout.addWidget(self.moving_units, 3, 1, alignment=Qt.AlignRight) self.performanceLayout.addWidget( QLabel("Generate infantry squads along vehicles"), 4, 0) self.performanceLayout.addWidget(self.infantry, 4, 1, alignment=Qt.AlignRight) self.performanceLayout.addWidget( QLabel( "AI planes parking start (AI starts in flight if disabled)"), 5, 0) self.performanceLayout.addWidget(self.ai_parking_start, 5, 1, alignment=Qt.AlignRight) self.performanceLayout.addWidget(QHorizontalSeparationLine(), 6, 0, 1, 2) self.performanceLayout.addWidget( QLabel("Culling of distant units enabled"), 7, 0) self.performanceLayout.addWidget(self.culling, 7, 1, alignment=Qt.AlignRight) self.performanceLayout.addWidget(QLabel("Culling distance (km)"), 8, 0) self.performanceLayout.addWidget(self.culling_distance, 8, 1, alignment=Qt.AlignRight) self.generatorLayout.addWidget(self.gameplay) self.generatorLayout.addWidget( QLabel( "Disabling settings below may improve performance, but will impact the overall quality of the experience." )) self.generatorLayout.addWidget(self.performance) def initCheatLayout(self): self.cheatPage = QWidget() self.cheatLayout = QGridLayout() self.cheatPage.setLayout(self.cheatLayout) self.moneyCheatBox = QGroupBox("Money Cheat") self.moneyCheatBox.setAlignment(Qt.AlignTop) self.moneyCheatBoxLayout = QGridLayout() self.moneyCheatBox.setLayout(self.moneyCheatBoxLayout) self.cheat25M = QPushButton("Cheat +25M") self.cheat50M = QPushButton("Cheat +50M") self.cheat100M = QPushButton("Cheat +100M") self.cheat200M = QPushButton("Cheat +200M") self.cheat500M = QPushButton("Cheat +500M") self.cheat1000M = QPushButton("Cheat +1000M") self.cheat25M.clicked.connect(lambda: self.cheatMoney(25)) self.cheat50M.clicked.connect(lambda: self.cheatMoney(50)) self.cheat100M.clicked.connect(lambda: self.cheatMoney(100)) self.cheat200M.clicked.connect(lambda: self.cheatMoney(200)) self.cheat500M.clicked.connect(lambda: self.cheatMoney(500)) self.cheat1000M.clicked.connect(lambda: self.cheatMoney(1000)) self.moneyCheatBoxLayout.addWidget(self.cheat25M, 0, 0) self.moneyCheatBoxLayout.addWidget(self.cheat50M, 0, 1) self.moneyCheatBoxLayout.addWidget(self.cheat100M, 1, 0) self.moneyCheatBoxLayout.addWidget(self.cheat200M, 1, 1) self.moneyCheatBoxLayout.addWidget(self.cheat500M, 2, 0) self.moneyCheatBoxLayout.addWidget(self.cheat1000M, 2, 1) self.cheatLayout.addWidget(self.moneyCheatBox, 0, 0) def cheatMoney(self, amount): self.game.budget += amount self.game.informations.append( Information("CHEATER", "You are a cheater and you should feel bad", self.game.turn)) GameUpdateSignal.get_instance().updateGame(self.game) def applySettings(self): self.game.settings.player_skill = CONST.SKILL_OPTIONS[ self.playerCoalitionSkill.currentIndex()] self.game.settings.enemy_skill = CONST.SKILL_OPTIONS[ self.enemyCoalitionSkill.currentIndex()] self.game.settings.enemy_vehicle_skill = CONST.SKILL_OPTIONS[ self.enemyAASkill.currentIndex()] self.game.settings.labels = CONST.LABELS_OPTIONS[ self.difficultyLabel.currentIndex()] self.game.settings.night_disabled = self.noNightMission.isChecked() self.game.settings.map_coalition_visibility = self.mapVisibiitySelection.currentData( ) self.game.settings.external_views_allowed = self.ext_views.isChecked() self.game.settings.generate_marks = self.generate_marks.isChecked() print(self.game.settings.map_coalition_visibility) self.game.settings.supercarrier = self.supercarrier.isChecked() self.game.settings.perf_red_alert_state = self.red_alert.isChecked() self.game.settings.perf_smoke_gen = self.smoke.isChecked() self.game.settings.perf_artillery = self.arti.isChecked() self.game.settings.perf_moving_units = self.moving_units.isChecked() self.game.settings.perf_infantry = self.infantry.isChecked() self.game.settings.perf_ai_parking_start = self.ai_parking_start.isChecked( ) self.game.settings.perf_culling = self.culling.isChecked() self.game.settings.perf_culling_distance = int( self.culling_distance.value()) GameUpdateSignal.get_instance().updateGame(self.game) def onSelectionChanged(self): index = self.categoryList.selectionModel().currentIndex().row() self.right_layout.setCurrentIndex(index)
class JointStatePublisherGui(QWidget): sliderUpdateTrigger = Signal() def __init__(self, title, jsp, num_rows=0): super(JointStatePublisherGui, self).__init__() self.jsp = jsp self.joint_map = {} self.vlayout = QVBoxLayout(self) self.scrollable = QWidget() self.gridlayout = QGridLayout() self.scroll = QScrollArea() self.scroll.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOn) self.scroll.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.scroll.setWidgetResizable(True) font = QFont("Helvetica", 9, QFont.Bold) ### Generate sliders ### sliders = [] for name in self.jsp.joint_list: if name not in self.jsp.free_joints: continue joint = self.jsp.free_joints[name] if joint['min'] == joint['max']: continue joint_layout = QVBoxLayout() row_layout = QHBoxLayout() label = QLabel(name) label.setFont(font) row_layout.addWidget(label) display = QLineEdit("0.00") display.setAlignment(Qt.AlignRight) display.setFont(font) display.setReadOnly(True) row_layout.addWidget(display) joint_layout.addLayout(row_layout) slider = QSlider(Qt.Horizontal) slider.setFont(font) slider.setRange(0, RANGE) slider.setValue(RANGE / 2) joint_layout.addWidget(slider) self.joint_map[name] = { 'slidervalue': 0, 'display': display, 'slider': slider, 'joint': joint } # Connect to the signal provided by QSignal slider.valueChanged.connect(self.onValueChanged) sliders.append(joint_layout) # Determine number of rows to be used in grid self.num_rows = num_rows # if desired num of rows wasn't set, default behaviour is a vertical layout if self.num_rows == 0: self.num_rows = len(sliders) # equals VBoxLayout # Generate positions in grid and place sliders there self.positions = self.generate_grid_positions(len(sliders), self.num_rows) for item, pos in zip(sliders, self.positions): self.gridlayout.addLayout(item, *pos) # Set zero positions read from parameters self.center() # Synchronize slider and displayed value self.sliderUpdate(None) # Set up a signal for updating the sliders based on external joint info self.sliderUpdateTrigger.connect(self.updateSliders) self.scrollable.setLayout(self.gridlayout) self.scroll.setWidget(self.scrollable) self.vlayout.addWidget(self.scroll) # Buttons for randomizing and centering sliders and # Spinbox for on-the-fly selecting number of rows self.randbutton = QPushButton('Randomize', self) self.randbutton.clicked.connect(self.randomize_event) self.vlayout.addWidget(self.randbutton) self.ctrbutton = QPushButton('Center', self) self.ctrbutton.clicked.connect(self.center_event) self.vlayout.addWidget(self.ctrbutton) self.maxrowsupdown = QSpinBox() self.maxrowsupdown.setMinimum(1) self.maxrowsupdown.setMaximum(len(sliders)) self.maxrowsupdown.setValue(self.num_rows) self.maxrowsupdown.lineEdit().setReadOnly( True) # don't edit it by hand to avoid weird resizing of window self.maxrowsupdown.valueChanged.connect(self.reorggrid_event) self.vlayout.addWidget(self.maxrowsupdown) self.setLayout(self.vlayout) @pyqtSlot(int) def onValueChanged(self, event): # A slider value was changed, but we need to change the joint_info metadata. for name, joint_info in self.joint_map.items(): joint_info['slidervalue'] = joint_info['slider'].value() joint = joint_info['joint'] joint['position'] = self.sliderToValue(joint_info['slidervalue'], joint) joint_info['display'].setText("%.2f" % joint['position']) @pyqtSlot() def updateSliders(self): self.update_sliders() def update_sliders(self): for name, joint_info in self.joint_map.items(): joint = joint_info['joint'] joint_info['slidervalue'] = self.valueToSlider( joint['position'], joint) joint_info['slider'].setValue(joint_info['slidervalue']) def center_event(self, event): self.center() def center(self): rospy.loginfo("Centering") for name, joint_info in self.joint_map.items(): joint = joint_info['joint'] joint_info['slider'].setValue( self.valueToSlider(joint['zero'], joint)) def reorggrid_event(self, event): self.reorganize_grid(event) def reorganize_grid(self, number_of_rows): self.num_rows = number_of_rows # Remove items from layout (won't destroy them!) items = [] for pos in self.positions: item = self.gridlayout.itemAtPosition(*pos) items.append(item) self.gridlayout.removeItem(item) # Generate new positions for sliders and place them in their new spots self.positions = self.generate_grid_positions(len(items), self.num_rows) for item, pos in zip(items, self.positions): self.gridlayout.addLayout(item, *pos) def generate_grid_positions(self, num_items, num_rows): if num_rows == 0: return [] positions = [ (y, x) for x in range(int((math.ceil(float(num_items) / num_rows)))) for y in range(num_rows) ] positions = positions[:num_items] return positions def randomize_event(self, event): self.randomize() def randomize(self): rospy.loginfo("Randomizing") for name, joint_info in self.joint_map.items(): joint = joint_info['joint'] joint_info['slider'].setValue( self.valueToSlider(random.uniform(joint['min'], joint['max']), joint)) def sliderUpdate(self, event): for name, joint_info in self.joint_map.items(): joint_info['slidervalue'] = joint_info['slider'].value() self.update_sliders() def valueToSlider(self, value, joint): return (value - joint['min']) * float(RANGE) / (joint['max'] - joint['min']) def sliderToValue(self, slider, joint): pctvalue = slider / float(RANGE) return joint['min'] + (joint['max'] - joint['min']) * pctvalue
class TeamworkPropertiesDialog(QDialog): def __init__(self): super().__init__(GlobalAccess().get_main_window()) self.time_format = 'hh:mm:ss' def exec_(self): self.init_ui() return super().exec_() def init_ui(self): # self.setFixedWidth(500) self.setWindowTitle(_('Teamwork')) # self.setWindowIcon(QIcon(icon_dir('sportident.png'))) self.setSizeGripEnabled(False) self.setModal(True) self.tab_widget = QTabWidget() # client/server self.teamwork_tab = QWidget() self.teamwork_layout = QFormLayout() self.teamwork_item_host = QLineEdit() self.teamwork_item_port = QSpinBox() self.teamwork_item_port.setMinimum(0) self.teamwork_item_port.setMaximum(65535) self.teamwork_item_token = QLineEdit() self.teamwork_groupbox = QGroupBox() self.teamwork_groupbox.setTitle(_('Type connection')) self.teamwork_groupbox_layout = QFormLayout() self.teamwork_item_client = QRadioButton(_('Client')) self.teamwork_item_server = QRadioButton(_('Server')) self.teamwork_groupbox_layout.addRow(self.teamwork_item_client) self.teamwork_groupbox_layout.addRow(self.teamwork_item_server) self.teamwork_groupbox.setLayout(self.teamwork_groupbox_layout) self.teamwork_layout.addRow(QLabel(_('Host')), self.teamwork_item_host) self.teamwork_layout.addRow(QLabel(_('Port')), self.teamwork_item_port) # self.teamwork_layout.addRow(QLabel(_('Token')), self.teamwork_item_token) self.teamwork_layout.addRow(self.teamwork_groupbox) self.teamwork_tab.setLayout(self.teamwork_layout) self.tab_widget.addTab(self.teamwork_tab, _('Client/Server')) def cancel_changes(): self.close() def apply_changes(): try: self.apply_changes_impl() except Exception as e: logging.error(str(e)) self.close() button_box = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel) self.button_ok = button_box.button(QDialogButtonBox.Ok) self.button_ok.setText(_('OK')) self.button_ok.clicked.connect(apply_changes) self.button_cancel = button_box.button(QDialogButtonBox.Cancel) self.button_cancel.setText(_('Cancel')) self.button_cancel.clicked.connect(cancel_changes) self.layout = QFormLayout(self) self.layout.addRow(self.tab_widget) self.layout.addRow(button_box) self.set_values_from_model() self.show() def set_values_from_model(self): obj = race() # teamwork teamwork_host = obj.get_setting('teamwork_host', 'localhost') teamwork_port = obj.get_setting('teamwork_port', 50010) teamwork_token = obj.get_setting('teamwork_token', str(uuid.uuid4())[:8]) teamwork_type_connection = obj.get_setting('teamwork_type_connection', 'client') self.teamwork_item_host.setText(teamwork_host) self.teamwork_item_port.setValue(teamwork_port) self.teamwork_item_token.setText(teamwork_token) if teamwork_type_connection == 'client': self.teamwork_item_client.setChecked(True) elif teamwork_type_connection == 'server': self.teamwork_item_server.setChecked(True) def apply_changes_impl(self): obj = race() # teamwork teamwork_host = self.teamwork_item_host.text() teamwork_port = self.teamwork_item_port.value() teamwork_token = self.teamwork_item_token.text() teamwork_type_connection = 'client' if self.teamwork_item_server.isChecked(): teamwork_type_connection = 'server' obj.set_setting('teamwork_host', teamwork_host) obj.set_setting('teamwork_port', teamwork_port) obj.set_setting('teamwork_token', teamwork_token) obj.set_setting('teamwork_type_connection', teamwork_type_connection)
class MainWindow(QMainWindow, design.Ui_MainWindow): def __init__(self): super().__init__() self.setupUi(self) # Уточнить необходимость наличия (если краши - удалить) self.dialog = None self.spinbox = [] self.doublebox = [] self.box_row = None self.baseInfo.setEditTriggers(QAbstractItemView.NoEditTriggers) self.resultTable.setEditTriggers(QAbstractItemView.NoEditTriggers) self.addItemBtn.clicked.connect(self.add_new_element) self.addXlsBtn.clicked.connect(self.input_database) self.changeItemBtn.clicked.connect(self.change_item) self.deleteBaseBtn.clicked.connect(self.delete_base) self.deleteItemBtn.clicked.connect(self.delete_item_from_base) self.printBtn.clicked.connect(self.print_specification) self.workBtn.clicked.connect(self.upd_result_table) self.BDBox.currentTextChanged.connect(self.show_chosen_bd) self.categoryBox.currentTextChanged.connect(self.current_text_changed) self.countryBox.currentTextChanged.connect(self.current_text_changed) self.listWidget.itemChanged.connect(self.item_selection_changed) self.create_bd.triggered.connect(self.clear_all) self.exit_action.triggered.connect(sys.exit) self.load_bd.triggered.connect(self.load_xls) self.save_bd.triggered.connect(self.save_xls) self.baseInfo.cellClicked.connect(self.signal_delete) self.ru_lang.toggled.connect(self.change_language_in_table) def add_new_element(self): # Вызывает класс добавления нового элемента и, если успешно, обновляет отображаемую таблицу index_base = self.BDBox.currentIndex() self.dialog = AddElementClass([index_base]) if self.dialog.exec() == QDialog.Accepted: self.show_chosen_bd() def algo(self, df): # bug скорее всего, достаточно заменить название на RU, роли не играет же? df['Итог'] = 1 sum_res = self.maxValue.text() sum_res = float(sum_res.replace(",", ".")) for item in range(len(df['цена $'])): if ',' in str(df['цена $'].iloc[item]): df['цена $'].iloc[item] = str(df['цена $'].iloc[item]).replace(',', '.') df['цена $'] = df['цена $'].astype(float) df['Количество'] = df['Количество'].astype(int) items_ratio = 3.5 # Допустимое отношение максимального кол-ва элементов к минимальному price_ratio = 0.01 # Допустимое различие между заданной и полученной суммой finish = True max_item = sys.maxsize max_name = None # Проверка на достижимость суммы выбранным поддатасетом? df['total'] = df['Количество'] * df['цена $'] agg = df['total'].aggregate(np.sum) if agg < sum_res: print("Ne, dont work") # Соответственно, вопрос к обработке return agg = df['цена $'].aggregate(np.sum) if agg > sum_res: print("Always too much") return prob = LpProblem('Sell', LpMaximize) # Objective function if self.ru_lang.isChecked(): inv_items = list(df['Название RU']) # Variable name else: inv_items = list(df['Name EN']) inv_items.sort() items = dict(zip(inv_items, df['Количество'])) # Function prices = dict(zip(inv_items, df['цена $'])) inv_vars = LpVariable.dicts('Var', inv_items, lowBound=1, cat='Integer') prob += lpSum([prices[i] * inv_vars[i] for i in inv_items]) prob += lpSum([prices[i] * inv_vars[i] for i in inv_items]) <= sum_res, 'Общая функция' for val in items: prob += inv_vars[val] <= items[val], val+' Demand' # values_check = [None,None] values_list = [] old_values = None while finish: if max_name: prob += inv_vars[max_name] <= max_item prob.solve() values_list = [] print('The optimal answer\n'+'-'*70) for v in prob.variables(): item = v.varValue if item > 0: values_list.append(item) if len(values_list) < len(inv_items): ''' Причина, почему просто вернуть: Можно было бы обработать, но продавать одновременно одни и те же позиции, но с разными ценами/кол-вом - бред. Поэтому просто вернуть и не обращать внимания. ''' print("баг с одинаковыми названиями") return max_item = max(values_list) - 1 balance = float(max_item / min(values_list)) max_name = inv_items[values_list.index(max(values_list))] print(values_list, max_item, max_name) t = list(prices.values()) if len(values_list) == len(t): price_res = [t[i] * values_list[i] for i in range(len(t))] price_res = sum(price_res) else: # В настройках функции стоит, что минимум должен быть один элемент. # Если уже меньше, чем нужно - то значит 100% ошибка. Значит выходим. print("Обыграть перевызов функции с новым датасетом") return if old_values == values_list: ''' Тут два варианта развития событий: 1. Утыкаемся в невозможность на второй итерации. Во времени не теряем, так что можно и вывести результаты. 2. Важнее, но маловероятнее - если долго считаем и упираемся. Обидно терять прогресс, лучше вывести что получилось. ''' print("Stop NOW") if price_res < sum_res: finish = False else: return self.result_label.setText(str(('%.2f' % price_res))) curr_price_ratio = (sum_res - price_res) / sum_res if balance <= items_ratio and curr_price_ratio <= price_ratio: finish = False old_values = values_list print("Ответ:") # пока что, для отладки for i in range(len(values_list)): print(inv_items[i], ":, ", values_list[i]) return values_list def change_item(self): #name = self.BDBox.currentText() #index_base = listOfXls.loc[listOfXls['Name'] == name] #index_base = index_base.index[0] index_base = self.return_index() #index_base = self.BDBox.currentIndex() index_row = self.baseInfo.currentRow() modified_row = base[index_base].loc[index_row] modified_row = modified_row.to_list() modified_row.insert(0, index_base) modified_row.insert(1, index_row) self.dialog = AddElementClass(modified_row) if self.dialog.exec() == QDialog.Accepted: self.show_chosen_bd() self.changeItemBtn.setEnabled(False) self.deleteItemBtn.setEnabled(False) def change_language_in_table(self): # Переключает язык в базе, если там есть элементы self.changeItemBtn.setEnabled(False) self.deleteItemBtn.setEnabled(False) if self.baseInfo.rowCount() > 0: self.show_chosen_bd() return def clear_all(self): # Функция для создания новой сессии global listOfXls self.categoryBox.blockSignals(True) self.countryBox.blockSignals(True) self.BDBox.blockSignals(True) if len(base) > 0: msg = QMessageBox.question(self, "Новая сессия", "Вы действительно хотите начать работу с новой базой?", QMessageBox.Yes | QMessageBox.No) if msg == QMessageBox.No: self.categoryBox.blockSignals(False) self.countryBox.blockSignals(False) self.BDBox.blockSignals(False) return base.clear() listOfXls = listOfXls[0:0] countries.clear() categories.clear() self.update_boxes() self.update_list(listOfXls) self.categoryBox.blockSignals(False) self.countryBox.blockSignals(False) self.BDBox.setEnabled(False) self.BDBox.blockSignals(False) self.workBtn.setEnabled(False) self.printBtn.setEnabled(False) self.deleteBaseBtn.setEnabled(False) self.addItemBtn.setEnabled(False) self.changeItemBtn.setEnabled(False) self.deleteItemBtn.setEnabled(False) self.langBox.setEnabled(False) self.baseInfo.setRowCount(0) self.resultTable.setRowCount(0) self.positions.setValue(1) self.maxValue.setValue(1.00) self.result_label.setText("") def current_text_changed(self): # Переопределение функции выбранного элемента комбобокса # для заполнения срезами таблицы listOfXls print("changed") current_category = self.categoryBox.currentText() current_country = self.countryBox.currentText() temp_df = listOfXls # проверить насчёт копии if current_category != 'Все': temp_df = temp_df[temp_df.Category.astype(str).str.contains(current_category)] if current_country != 'Все': temp_df = temp_df[temp_df.Country.astype(str).str.contains(current_country)] temp_df = temp_df.reset_index() if not temp_df.empty: self.update_list(temp_df) else: self.listWidget.clear() self.update_bd_list(temp_df) return # Нумерация остаётся как взяли (т.е. 2,5... вместо 0,1...). Норм? def delete_base(self): global listOfXls msg = QMessageBox.question(self, 'Удаление базы', 'Вы действительно хотите удалить эту базу?', QMessageBox.Yes | QMessageBox.No) if msg == QMessageBox.Yes: index_base = self.BDBox.currentIndex() - 1 base.pop(index_base) listOfXls.drop(index_base, inplace=True) listOfXls = listOfXls.reset_index(drop=True) self.update_boxes() self.update_list() if len(base) == 0: self.workBtn.setEnabled(False) self.printBtn.setEnabled(False) def delete_item_from_base(self): #index_base = self.BDBox.currentIndex() #name = self.BDBox.currentText() #index_base = listOfXls.loc[listOfXls['Name'] == name] #index_base = index_base.index[0] index_base = self.return_index() index_item = self.baseInfo.currentRow() if index_item >= 0: base[index_base] = base[index_base].drop(index=index_item).reset_index(drop=True) self.baseInfo.removeRow(index_item) if len(base[index_base]) == 0: self.changeItemBtn.setEnabled(False) self.deleteItemBtn.setEnabled(False) def input_database(self): self.dialog = InputDBClass() # Блокируем сигналы, чтобы нормально заполнялись боксы после их изменений self.categoryBox.blockSignals(True) self.countryBox.blockSignals(True) if self.dialog.exec() == QDialog.Accepted: self.update_boxes() self.update_list() self.BDBox.setEnabled(True) self.current_text_changed() self.workBtn.setEnabled(True) # self.update_bd_list() self.categoryBox.blockSignals(False) self.countryBox.blockSignals(False) def item_selection_changed(self, item): # Изменение состояния "включения" в базе (галочки в листбоксе) item_index = listOfXls.loc[listOfXls['Name'] == item.text()] item_index = item_index.index[0] if not item.checkState(): listOfXls['Activated'].iloc[item_index] = False else: listOfXls['Activated'].iloc[item_index] = True def load_xls(self): global base, listOfXls, countries, categories self.categoryBox.blockSignals(True) self.countryBox.blockSignals(True) bd_path = QFileDialog.getOpenFileName(self, "Выберите БД", filter="*.xlsx") if bd_path[0]: if not listOfXls.empty: self.clear_all() bd_item = pd.ExcelFile(bd_path[0], engine='openpyxl') listOfXls = pd.concat([listOfXls, bd_item.parse('info')]).copy() categories = listOfXls.Category.unique().tolist() countries = listOfXls.Country.unique().tolist() categories = list(map(str, categories)) countries = list(map(str, countries)) for it in listOfXls.index: name = listOfXls.Name[it] new_base = bd_item.parse(name) base.append(new_base) self.update_list() self.update_boxes() self.BDBox.setEnabled(True) self.workBtn.setEnabled(True) self.langBox.setEnabled(True) self.current_text_changed() self.categoryBox.blockSignals(False) self.countryBox.blockSignals(False) def print_specification(self): doc = DocxTemplate("Data\Templates\spec_template.docx") date = datetime.today().strftime('%d.%m.%Y') tbl_contents = [] num_rows = self.resultTable.rowCount() for i in range(num_rows): label = i+1 name = self.resultTable.item(i, 0).text() piece = "шт/ рс" #nums = self.resultTable.item(i, 1).text() nums = self.spinbox[i].value() #price = self.resultTable.item(i, 2).text() price = self.doublebox[i].value() total = self.resultTable.item(i, 3).text() tbl_contents.append({'label': label, 'cols': [name, piece, nums, price, total]}) total_price = ('%.2f' % float(self.result_label.text())) context = {'date': date, 'total_price': total_price, 'tbl_contents': tbl_contents} doc.render(context) doc_result = QFileDialog.getSaveFileName(self, "Сохраните файл:", filter="*.docx") if doc_result[0]: doc.save(doc_result[0]) QMessageBox.information(self, "Сохранение файла", "Файл сохранён успешно!") os.startfile(doc_result[0]) def return_index(self): name = self.BDBox.currentText() index_base = listOfXls.loc[listOfXls['Name'] == name] index_base = index_base.index[0] return index_base def save_xls(self): if not base: # base = [] return xls_result = QFileDialog.getSaveFileName(self, "Сохраните файл:", filter="*.xlsx") if xls_result[0]: with pd.ExcelWriter(xls_result[0]) as writer: listOfXls.to_excel(writer, sheet_name='info', index=False) for table in range(len(base)): table_name = listOfXls.iloc[table].Name base[table].to_excel(writer, sheet_name=table_name, index=False) def set_item(self, item, status): # Пока просто выставляет пустой элемент, переписать под заполнение # из класса InputDBClass # Каким образом - смотреть, что выбрано в категориях и делать срез # с пандаса и вставлять его поэлементно # Подумать на тему того, чтобы изначально был пункт "Все", # и как это красиво можно связать со структурами # (в плане редактирования, чтобы не удалить случайно) checkbox_item = QListWidgetItem(item) checkbox_item.setFlags(Qt.ItemIsUserCheckable | Qt.ItemIsEnabled) if status: checkbox_item.setCheckState(Qt.Checked) else: checkbox_item.setCheckState(Qt.Unchecked) self.listWidget.addItem(checkbox_item) def show_chosen_bd(self): name = self.BDBox.currentText() index = listOfXls.loc[listOfXls['Name'] == name] if not index.empty: self.deleteBaseBtn.setEnabled(True) self.addItemBtn.setEnabled(True) self.langBox.setEnabled(True) self.baseInfo.setRowCount(0) self.baseInfo.clearContents() self.baseInfo.horizontalHeader().setSectionResizeMode(0, QHeaderView.Stretch) self.baseInfo.setColumnWidth(1, 80) self.baseInfo.setColumnWidth(2, 80) index = index.index[0] target = base[index] for i, row in target.iterrows(): # row_name = row['Название'] if self.ru_lang.isChecked(): row_name = row['Название RU'] else: row_name = row['Name EN'] row_number = str(int(row['Количество'])) row_price = str(row['цена $']) if "," in row_price: row_price = str(row['цена $']).replace(',', '.') row_price = float(row_price) row_price = str(f"{row_price:.{2}f}") row_price = row_price.replace('.', ',') self.baseInfo.setRowCount(i+1) self.baseInfo.setItem(i, 0, QTableWidgetItem(row_name)) self.baseInfo.setItem(i, 1, QTableWidgetItem(row_number)) self.baseInfo.setItem(i, 2, QTableWidgetItem(row_price)) else: self.baseInfo.setRowCount(0) self.changeItemBtn.setEnabled(False) self.deleteItemBtn.setEnabled(False) self.deleteBaseBtn.setEnabled(False) self.addItemBtn.setEnabled(False) def signal_delete(self): # Фиксирует сигнал нажатие на элемент подбазы и даёт доступ # на редактирование\удаление элемента (если было недоступно) self.changeItemBtn.setEnabled(True) self.deleteItemBtn.setEnabled(True) def update_bd_list(self, df): # Функция для обновления списка баз в комбобоксе BDBox (самый правый) self.categoryBox.blockSignals(True) self.BDBox.clear() self.BDBox.addItem("Выберите базу...") name = df['Name'] if not name.empty: self.BDBox.setEnabled(True) for item in name: self.BDBox.addItem(item) else: self.BDBox.setEnabled(False) self.categoryBox.blockSignals(False) def update_boxes(self): # Функция, вызываемая при добавлении\изменении категориальных признаков # для обновления списков на главном окне self.categoryBox.clear() self.categoryBox.addItem("Все") for item in categories: self.categoryBox.addItem(item) self.countryBox.clear() self.countryBox.addItem("Все") for item in countries: self.countryBox.addItem(item) def update_list(self, *args): # Функция для вывода списка (по фильтрам) if args: db = args[0] else: db = listOfXls self.listWidget.clear() for item in range(len(db)): name = db.loc[item].Name status = db.loc[item].Activated self.set_item(name, status) def upd_result_table(self): """ В чём суть: сначала формируем общий фрейм, откуда брать вырезку. Вырезка берётся как df.sample(n=count), count = число позиций Соответственно, берем только те, которые "включены" И, наверное, добавляется столбец с индексом/названием, чтобы потом взять и изменить количество при необходимости в исходном месте Сразу же: надо сделать так, чтобы нельзя было запросить позиций больше, чем есть в проге. То есть, сейчас лимит 20, а пускай у нас лежит 5 позиций. И чтобы не было такого, мол max = размер если меньше 20. """ self.spinbox = [] self.doublebox = [] activated = listOfXls[listOfXls.Activated.astype(str).str.contains('True')] if activated.empty: QMessageBox.warning(self, "Ошибка", "Ни одна база не активна", QMessageBox.Ok) return self.result_label.setText("") finish_alg = False count_tries = 0 while not finish_alg: if count_tries > 20: QMessageBox.warning(self, "Ошибка", "Не считается:( Возможно, что-то не так с данными", QMessageBox.Ok) self.printBtn.setEnabled(False) return full_list = base[0].copy() full_list = full_list[0:0] for it in activated.index: full_list = pd.concat([full_list, base[it]]).copy() count = int(self.positions.text()) # print(full_list.sample(n = count)) self.resultTable.setRowCount(0) if len(full_list) < count: QMessageBox.warning(self, "Ошибка", "Позиций в базах меньше, чем запрашивается", QMessageBox.Ok) return full_list = full_list.sample(n=count) # Возможно, индексы надо и сохранить, но тут хз full_list = full_list.reset_index() # А тут идёт блок расчётов, потому что заполнять нужно с итогом ''' import tkinter.messagebox try: nums = self.algo(full_list) tkinter.messagebox.showinfo('Save', 'Ok') except: import traceback tkinter.messagebox.showinfo("ERROR", traceback.format_exc()) raise ''' nums = self.algo(full_list) if nums: for i, row in full_list.iterrows(): row_name = row['Название RU'] + '/' + row['Name EN'] row_number = str(int(nums[i])) row_price = str('%.2f' % row['цена $']) total = row['цена $']*int(nums[i]) total = ('%.2f' % total) row_total = str(total) self.resultTable.setRowCount(self.resultTable.rowCount() + 1) self.resultTable.setItem(i, 0, QTableWidgetItem(row_name)) # self.resultTable.setItem(i, 1, QTableWidgetItem(row_number)) # self.resultTable.setItem(i, 2, QTableWidgetItem(row_price)) self.cur_sbox = QSpinBox() self.cur_sbox.setMinimum(1) self.cur_sbox.setMaximum(99999) self.cur_sbox.setValue(int(row_number)) self.resultTable.setCellWidget(i, 1, self.cur_sbox) self.spinbox.append(self.cur_sbox) self.cur_dbox = QDoubleSpinBox() self.cur_dbox.setMaximum(99999999.99) self.cur_dbox.setValue(float(row_price)) self.resultTable.setCellWidget(i, 2, self.cur_dbox) self.doublebox.append(self.cur_dbox) self.cur_sbox.valueChanged.connect(self.spins_changed) self.cur_dbox.valueChanged.connect(self.spins_changed) self.resultTable.setItem(i, 3, QTableWidgetItem(row_total)) finish_alg = True count_tries += 1 self.printBtn.setEnabled(True) self.resultTable.horizontalHeader().setSectionResizeMode(0, QHeaderView.Stretch) self.resultTable.setColumnWidth(1, 80) self.resultTable.setColumnWidth(2, 80) self.resultTable.setColumnWidth(3, 80) def spins_changed(self, value): row = self.resultTable.currentRow() num = self.spinbox[row].value() price = self.doublebox[row].value() total = int(num) * float(price) total = ('%.2f' % total) row_total = str(total) self.resultTable.setItem(row, 3, QTableWidgetItem(row_total)) sum_price = 0 for i in range(0, self.resultTable.rowCount()): price_pack = self.resultTable.item(i, 3) price_pack = price_pack.text() sum_price += float(price_pack) self.result_label.setText(str(sum_price)) '''
class CloningWidget(ToolWidget): def __init__(self, image, parent=None): super(CloningWidget, self).__init__(parent) self.detector_combo = QComboBox() self.detector_combo.addItems( [self.tr('BRISK'), self.tr('ORB'), self.tr('AKAZE')]) self.detector_combo.setCurrentIndex(0) self.detector_combo.setToolTip( self.tr('Algorithm used for localization and description')) self.response_spin = QSpinBox() self.response_spin.setRange(0, 100) self.response_spin.setSuffix(self.tr('%')) self.response_spin.setValue(90) self.response_spin.setToolTip( self.tr('Maximum keypoint response to perform matching')) self.matching_spin = QSpinBox() self.matching_spin.setRange(1, 100) self.matching_spin.setSuffix(self.tr('%')) self.matching_spin.setValue(20) self.matching_spin.setToolTip( self.tr('Maximum metric difference to accept matching')) self.distance_spin = QSpinBox() self.distance_spin.setRange(1, 100) self.distance_spin.setSuffix(self.tr('%')) self.distance_spin.setValue(15) self.distance_spin.setToolTip( self.tr('Maximum distance between matches in the same cluster')) self.cluster_spin = QSpinBox() self.cluster_spin.setRange(1, 20) self.cluster_spin.setValue(5) self.cluster_spin.setToolTip( self.tr('Minimum number of keypoints to create a new cluster')) self.nolines_check = QCheckBox(self.tr('Hide lines')) self.nolines_check.setToolTip(self.tr('Disable match line drawing')) self.process_button = QToolButton() self.process_button.setText(self.tr('Process')) self.process_button.setToolTip(self.tr('Perform automatic detection')) modify_font(self.process_button, bold=True) self.status_label = QLabel() self.mask_label = QLabel() self.mask_button = QToolButton() self.mask_button.setText(self.tr('Load mask...')) self.mask_button.setToolTip( self.tr('Load an image to be used as mask')) self.onoff_button = QToolButton() self.onoff_button.setText(self.tr('OFF')) self.onoff_button.setCheckable(True) self.onoff_button.setToolTip(self.tr('Toggle keypoint detection mask')) self.image = image self.viewer = ImageViewer(self.image, self.image) self.gray = cv.cvtColor(self.image, cv.COLOR_BGR2GRAY) self.total = self.kpts = self.desc = self.matches = self.clusters = self.mask = None self.canceled = False self.detector_combo.currentIndexChanged.connect(self.update_detector) self.response_spin.valueChanged.connect(self.update_detector) self.matching_spin.valueChanged.connect(self.update_matching) self.distance_spin.valueChanged.connect(self.update_cluster) self.cluster_spin.valueChanged.connect(self.update_cluster) self.nolines_check.stateChanged.connect(self.process) self.process_button.clicked.connect(self.process) self.mask_button.clicked.connect(self.load_mask) self.onoff_button.toggled.connect(self.toggle_mask) self.onoff_button.setEnabled(False) top_layout = QHBoxLayout() top_layout.addWidget(QLabel(self.tr('Detector:'))) top_layout.addWidget(self.detector_combo) top_layout.addWidget(QLabel(self.tr('Response:'))) top_layout.addWidget(self.response_spin) top_layout.addWidget(QLabel(self.tr('Matching:'))) top_layout.addWidget(self.matching_spin) top_layout.addWidget(QLabel(self.tr('Distance:'))) top_layout.addWidget(self.distance_spin) top_layout.addWidget(QLabel(self.tr('Cluster:'))) top_layout.addWidget(self.cluster_spin) top_layout.addWidget(self.nolines_check) top_layout.addStretch() bottom_layout = QHBoxLayout() bottom_layout.addWidget(self.process_button) bottom_layout.addWidget(self.status_label) bottom_layout.addStretch() bottom_layout.addWidget(self.mask_button) bottom_layout.addWidget(self.onoff_button) main_layout = QVBoxLayout() main_layout.addLayout(top_layout) main_layout.addLayout(bottom_layout) main_layout.addWidget(self.viewer) self.setLayout(main_layout) def toggle_mask(self, checked): self.onoff_button.setText('ON' if checked else 'OFF') if checked: self.viewer.update_processed( cv.merge([c * self.mask for c in cv.split(self.image)])) else: self.viewer.update_processed(self.image) self.update_detector() def load_mask(self): filename, basename, mask = load_image(self) if filename is None: return if self.image.shape[:-1] != mask.shape[:-1]: QMessageBox.critical( self, self.tr('Error'), self.tr('Image and mask must have the same size!')) return _, self.mask = cv.threshold(cv.cvtColor(mask, cv.COLOR_BGR2GRAY), 0, 1, cv.THRESH_BINARY) self.onoff_button.setEnabled(True) self.onoff_button.setChecked(True) self.mask_button.setText('"{}"'.format(splitext(basename)[0])) self.mask_button.setToolTip(self.tr('Current detection mask image')) def update_detector(self): self.total = self.kpts = self.desc = self.matches = self.clusters = None self.status_label.setText('') self.process_button.setEnabled(True) def update_matching(self): self.matches = self.clusters = None self.process_button.setEnabled(True) def update_cluster(self): self.clusters = None self.process_button.setEnabled(True) def cancel(self): self.canceled = True self.total = self.kpts = self.desc = self.matches = self.clusters = None self.status_label.setText(self.tr('Processing interrupted!')) modify_font(self.status_label, bold=False, italic=False) def process(self): start = time() self.status_label.setText(self.tr('Processing, please wait...')) algorithm = self.detector_combo.currentIndex() response = 100 - self.response_spin.value() matching = self.matching_spin.value() / 100 * 255 distance = self.distance_spin.value() / 100 cluster = self.cluster_spin.value() modify_font(self.status_label, bold=False, italic=True) QCoreApplication.processEvents() if self.kpts is None: if algorithm == 0: detector = cv.BRISK_create() elif algorithm == 1: detector = cv.ORB_create() elif algorithm == 2: detector = cv.AKAZE_create() else: return mask = self.mask if self.onoff_button.isChecked() else None self.kpts, self.desc = detector.detectAndCompute(self.gray, mask) self.total = len(self.kpts) responses = np.array([k.response for k in self.kpts]) strongest = (cv.normalize(responses, None, 0, 100, cv.NORM_MINMAX) >= response).flatten() self.kpts = list(compress(self.kpts, strongest)) self.desc = self.desc[strongest] if self.matches is None: matcher = cv.BFMatcher_create(cv.NORM_HAMMING, True) self.matches = matcher.radiusMatch(self.desc, self.desc, matching) if self.matches is None: self.status_label.setText( self.tr('No keypoint match found with current settings')) modify_font(self.status_label, italic=False, bold=True) return self.matches = [ item for sublist in self.matches for item in sublist ] self.matches = [ m for m in self.matches if m.queryIdx != m.trainIdx ] if self.clusters is None: self.clusters = [] total = len(self.matches) min_dist = distance * np.min(self.gray.shape) / 2 progress = QProgressDialog(self.tr('Clustering matches...'), self.tr('Cancel'), 0, total, self) progress.canceled.connect(self.cancel) progress.setWindowModality(Qt.WindowModal) for i in range(total): match0 = self.matches[i] query0 = match0.queryIdx train0 = match0.trainIdx group = [match0] a0 = np.array(self.kpts[query0].pt) b0 = np.array(self.kpts[train0].pt) d0 = np.linalg.norm(a0 - b0) if d0 < min_dist: continue for j in range(i + 1, total): match1 = self.matches[j] query1 = match1.queryIdx train1 = match1.trainIdx if query1 == train0 and train1 == query0: continue a1 = np.array(self.kpts[query1].pt) b1 = np.array(self.kpts[train1].pt) d1 = np.linalg.norm(a1 - b1) if d1 < min_dist or np.abs(d0 - d1) > min_dist: continue aa = np.linalg.norm(a0 - a1) bb = np.linalg.norm(b0 - b1) ab = np.linalg.norm(a0 - b1) ba = np.linalg.norm(b0 - a1) smallest = np.partition(np.array([aa, bb, ab, ba]), 1)[:2] if np.all(np.logical_and(smallest > 0, smallest < min_dist)): for g in group: if g.queryIdx == train1 and g.trainIdx == query1: break else: group.append(match1) if len(group) >= cluster: self.clusters.append(group) progress.setValue(i) if self.canceled: self.canceled = False return progress.setValue(total) output = np.copy(self.image) hsv = np.zeros((1, 1, 3)) nolines = self.nolines_check.isChecked() angles = [] for c in self.clusters: for m in c: ka = self.kpts[m.queryIdx] pa = tuple(map(int, ka.pt)) sa = int(np.round(ka.size)) kb = self.kpts[m.trainIdx] pb = tuple(map(int, kb.pt)) sb = int(np.round(kb.size)) angle = np.arctan2(pb[1] - pa[1], pb[0] - pa[0]) if angle < 0: angle += np.pi angles.append(angle) hsv[0, 0, 0] = angle / np.pi * 180 hsv[0, 0, 1] = 255 hsv[0, 0, 2] = m.distance / matching * 255 rgb = cv.cvtColor(hsv.astype(np.uint8), cv.COLOR_HSV2BGR) rgb = tuple([int(x) for x in rgb[0, 0]]) cv.circle(output, pa, sa, rgb, 1, cv.LINE_AA) cv.circle(output, pb, sb, rgb, 1, cv.LINE_AA) if not nolines: cv.line(output, pa, pb, rgb, 1, cv.LINE_AA) regions = 0 if angles: angles = np.reshape(np.array(angles, dtype=np.float32), (len(angles), 1)) if np.std(angles) < 0.1: regions = 1 else: criteria = (cv.TERM_CRITERIA_EPS + cv.TERM_CRITERIA_MAX_ITER, 10, 1.0) attempts = 10 flags = cv.KMEANS_PP_CENTERS compact = [ cv.kmeans(angles, k, None, criteria, attempts, flags)[0] for k in range(1, 11) ] compact = cv.normalize(np.array(compact), None, 0, 1, cv.NORM_MINMAX) regions = np.argmax(compact < 0.005) + 1 self.viewer.update_processed(output) self.process_button.setEnabled(False) modify_font(self.status_label, italic=False, bold=True) self.status_label.setText( self. tr('Keypoints: {} --> Filtered: {} --> Matches: {} --> Clusters: {} --> Regions: {}' .format(self.total, len(self.kpts), len(self.matches), len(self.clusters), regions))) self.info_message.emit( self.tr('Copy-Move Forgery = {}'.format(elapsed_time(start))))
class GroupEditDialog(QDialog): def __init__(self, group, is_new=False): super().__init__(GlobalAccess().get_main_window()) assert (isinstance(group, Group)) self.current_object = group self.is_new = is_new self.time_format = 'hh:mm:ss' def exec_(self): self.init_ui() self.set_values_from_model() return super().exec_() def init_ui(self): self.setWindowTitle(_('Group properties')) self.setWindowIcon(QIcon(config.ICON)) self.setSizeGripEnabled(False) self.setModal(True) self.layout = QFormLayout(self) self.label_name = QLabel(_('Name')) self.item_name = QLineEdit() self.item_name.textChanged.connect(self.check_name) self.layout.addRow(self.label_name, self.item_name) self.label_full_name = QLabel(_('Full name')) self.item_full_name = QLineEdit() self.layout.addRow(self.label_full_name, self.item_full_name) self.label_course = QLabel(_('Course')) self.item_course = AdvComboBox() self.item_course.addItems(get_race_courses()) self.layout.addRow(self.label_course, self.item_course) self.label_is_any_course = QLabel(_('Is any course')) self.item_is_any_course = QCheckBox() self.item_is_any_course.stateChanged.connect(self.is_any_course_update) self.layout.addRow(self.label_is_any_course, self.item_is_any_course) self.label_sex = QLabel(_('Sex')) self.item_sex = AdvComboBox() self.item_sex.addItems(Sex.get_titles()) self.layout.addRow(self.label_sex, self.item_sex) self.label_age_min = QLabel(_('Min age')) self.item_age_min = QSpinBox() # self.layout.addRow(self.label_age_min, self.item_age_min) self.label_age_max = QLabel(_('Max age')) self.item_age_max = QSpinBox() # self.layout.addRow(self.label_age_max, self.item_age_max) self.label_year_min = QLabel(_('Min year')) self.item_year_min = QSpinBox() self.item_year_min.setMaximum(date.today().year) self.item_year_min.editingFinished.connect(self.year_change) self.layout.addRow(self.label_year_min, self.item_year_min) self.label_year_max = QLabel(_('Max year')) self.item_year_max = QSpinBox() self.item_year_max.setMaximum(date.today().year) self.item_year_max.editingFinished.connect(self.year_change) self.layout.addRow(self.label_year_max, self.item_year_max) self.label_max_time = QLabel(_('Max time')) self.item_max_time = QTimeEdit() self.item_max_time.setDisplayFormat(self.time_format) self.layout.addRow(self.label_max_time, self.item_max_time) self.label_corridor = QLabel(_('Start corridor')) self.item_corridor = QSpinBox() self.layout.addRow(self.label_corridor, self.item_corridor) self.label_corridor_order = QLabel(_('Order in corridor')) self.item_corridor_order = QSpinBox() self.layout.addRow(self.label_corridor_order, self.item_corridor_order) self.label_start_interval = QLabel(_('Start interval')) self.item_start_interval = QTimeEdit() self.item_start_interval.setDisplayFormat(self.time_format) self.layout.addRow(self.label_start_interval, self.item_start_interval) self.label_price = QLabel(_('Start fee')) self.item_price = QSpinBox() self.item_price.setSingleStep(50) self.item_price.setMaximum(Limit.PRICE) self.layout.addRow(self.label_price, self.item_price) self.type_label = QLabel(_('Type')) self.type_combo = AdvComboBox() self.type_combo.addItems(RaceType.get_titles()) self.layout.addRow(self.type_label, self.type_combo) self.rank_checkbox = QCheckBox(_('Rank calculation')) self.rank_button = QPushButton(_('Configuration')) self.layout.addRow(self.rank_checkbox, self.rank_button) def cancel_changes(): self.close() def apply_changes(): try: self.apply_changes_impl() except Exception as e: logging.error(str(e)) self.close() button_box = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel) self.button_ok = button_box.button(QDialogButtonBox.Ok) self.button_ok.setText(_('OK')) self.button_ok.clicked.connect(apply_changes) self.button_cancel = button_box.button(QDialogButtonBox.Cancel) self.button_cancel.setText(_('Cancel')) self.button_cancel.clicked.connect(cancel_changes) self.layout.addRow(button_box) self.show() self.button_ok.setFocus() def check_name(self): name = self.item_name.text() self.button_ok.setDisabled(False) if name and name != self.current_object.name: group = find(race().groups, name=name) if group: self.button_ok.setDisabled(True) def year_change(self): """ Convert 2 digits of year to 4 2 -> 2002 11 - > 2011 33 -> 1933 56 -> 1956 98 - > 1998 0 -> 0 exception! """ widget = self.sender() assert isinstance(widget, QSpinBox) year = widget.value() if 0 < year < 100: cur_year = date.today().year new_year = cur_year - cur_year % 100 + year if new_year > cur_year: new_year -= 100 widget.setValue(new_year) def is_any_course_update(self): if self.item_is_any_course.isChecked(): self.item_course.setDisabled(True) else: self.item_course.setDisabled(False) def set_values_from_model(self): self.item_name.setText(self.current_object.name) if self.current_object.long_name: self.item_full_name.setText(self.current_object.long_name) if self.current_object.course: self.item_course.setCurrentText(self.current_object.course.name) if self.current_object.sex: self.item_sex.setCurrentText(self.current_object.sex.get_title()) if self.current_object.min_age: self.item_age_min.setValue(self.current_object.min_age) if self.current_object.max_age: self.item_age_max.setValue(self.current_object.max_age) if self.current_object.min_year: self.item_year_min.setValue(self.current_object.min_year) if self.current_object.max_year: self.item_year_max.setValue(self.current_object.max_year) if self.current_object.max_time: self.item_max_time.setTime( time_to_qtime(self.current_object.max_time)) if self.current_object.start_interval: self.item_start_interval.setTime( time_to_qtime(self.current_object.start_interval)) if self.current_object.start_corridor: self.item_corridor.setValue(self.current_object.start_corridor) if self.current_object.order_in_corridor: self.item_corridor_order.setValue( self.current_object.order_in_corridor) if self.current_object.price: self.item_price.setValue(self.current_object.price) self.item_is_any_course.setChecked(self.current_object.is_any_course) self.rank_checkbox.setChecked(self.current_object.ranking.is_active) self.type_combo.setCurrentText(race().get_type( self.current_object).get_title()) def rank_configuration(): group = self.current_object GroupRankingDialog(group).exec_() self.rank_button.clicked.connect(rank_configuration) def apply_changes_impl(self): group = self.current_object assert (isinstance(group, Group)) if self.is_new: race().groups.insert(0, group) if group.name != self.item_name.text(): group.name = self.item_name.text() if group.long_name != self.item_full_name.text(): group.long_name = self.item_full_name.text() if (group.course is not None and group.course.name != self.item_course.currentText()) \ or (group.course is None and len(self.item_course.currentText()) > 0): group.course = find(race().courses, name=self.item_course.currentText()) if group.sex.get_title() != self.item_sex.currentText(): group.sex = Sex(self.item_sex.currentIndex()) if group.min_age != self.item_age_min.value(): group.min_age = self.item_age_min.value() if group.max_age != self.item_age_max.value(): group.max_age = self.item_age_max.value() if group.min_year != self.item_year_min.value(): group.min_year = self.item_year_min.value() if group.max_year != self.item_year_max.value(): group.max_year = self.item_year_max.value() if group.start_corridor != self.item_corridor.value(): group.start_corridor = self.item_corridor.value() if group.order_in_corridor != self.item_corridor_order.value(): group.order_in_corridor = self.item_corridor_order.value() if group.price != self.item_price.value(): group.price = self.item_price.value() time = time_to_otime(self.item_start_interval.time()) if group.start_interval != time: group.start_interval = time time = time_to_otime(self.item_max_time.time()) if group.max_time != time: group.max_time = time if group.ranking.is_active != self.rank_checkbox.isChecked(): group.ranking.is_active = self.rank_checkbox.isChecked() t = RaceType.get_by_name(self.type_combo.currentText()) selected_type = t if t is not None else group.get_type() if group.get_type() != selected_type: group.set_type(selected_type) group.is_any_course = self.item_is_any_course.isChecked() ResultCalculation(race()).set_rank(group) Teamwork().send(group.to_dict())
class MedianWidget(ToolWidget): def __init__(self, image, parent=None): super(MedianWidget, self).__init__(parent) self.variance_spin = QSpinBox() self.variance_spin.setRange(0, 50) self.variance_spin.setValue(10) self.threshold_spin = QDoubleSpinBox() self.threshold_spin.setRange(0, 1) self.threshold_spin.setValue(0.45) self.threshold_spin.setSingleStep(0.01) self.showprob_check = QCheckBox(self.tr('Probability map')) self.filter_check = QCheckBox(self.tr('Speckle filter')) self.filter_check.setChecked(True) self.process_button = QPushButton(self.tr('Process')) self.avgprob_label = QLabel(self.tr('Press "Process" to start')) top_layout = QHBoxLayout() top_layout.addWidget(QLabel(self.tr('Min variance:'))) top_layout.addWidget(self.variance_spin) top_layout.addWidget(QLabel(self.tr('Threshold:'))) top_layout.addWidget(self.threshold_spin) top_layout.addWidget(self.showprob_check) top_layout.addWidget(self.filter_check) top_layout.addWidget(self.process_button) # top_layout.addWidget(self.avgprob_label) top_layout.addStretch() self.image = image self.viewer = ImageViewer(self.image, self.image) self.gray = cv.cvtColor(self.image, cv.COLOR_BGR2GRAY) self.prob = self.var = None self.block = 64 self.canceled = False self.process_button.clicked.connect(self.prepare) self.variance_spin.valueChanged.connect(self.process) self.threshold_spin.valueChanged.connect(self.process) self.showprob_check.stateChanged.connect(self.process) self.filter_check.stateChanged.connect(self.process) main_layout = QVBoxLayout() main_layout.addLayout(top_layout) main_layout.addWidget(self.viewer) self.setLayout(main_layout) def prepare(self): modelfile = 'models/median_b{}.mdl'.format(self.block) try: model = load(modelfile) except FileNotFoundError: QMessageBox.critical( self, self.tr('Error'), self.tr('Model not found ("{}")!'.format(modelfile))) return limit = model.best_ntree_limit if hasattr(model, 'best_ntree_limit') else None columns = model._features_count if columns == 8: levels = 1 windows = 1 elif columns == 24: levels = 3 windows = 1 elif columns == 96: levels = 3 windows = 4 elif columns == 128: levels = 4 windows = 4 else: QMessageBox.critical(self, self.tr('Error'), self.tr('Unknown model format!')) return padded = pad_image(self.gray, self.block) rows, cols = padded.shape self.prob = np.zeros( ((rows // self.block) + 1, (cols // self.block) + 1)) self.var = np.zeros_like(self.prob) progress = QProgressDialog(self.tr('Detecting median filter...'), self.tr('Cancel'), 0, self.prob.size, self) progress.canceled.connect(self.cancel) progress.setWindowModality(Qt.WindowModal) k = 0 self.canceled = False for i in range(0, rows, self.block): for j in range(0, cols, self.block): roi = padded[i:i + self.block, j:j + self.block] x = np.reshape(get_features(roi, levels, windows), (1, columns)) y = model.predict_proba(x, ntree_limit=limit)[0, 1] ib = i // self.block jb = j // self.block self.var[ib, jb] = np.var(roi) self.prob[ib, jb] = y if self.canceled: self.prob = self.var = None progress.close() return progress.setValue(k) k += 1 progress.close() self.process() def cancel(self): self.canceled = True def process(self): if self.prob is None: return mask = self.var < self.variance_spin.value() if self.filter_check.isChecked(): prob = cv.medianBlur(self.prob.astype(np.float32), 3) else: prob = self.prob.astype(np.float32) if self.showprob_check.isChecked(): output = np.repeat(prob[:, :, np.newaxis], 3, axis=2) output[mask] = 0 else: thr = self.threshold_spin.value() output = np.zeros((prob.shape[0], prob.shape[1], 3)) blue, green, red = cv.split(output) blue[mask] = 1 green[prob < thr] = 1 green[mask] = 0 red[prob >= thr] = 1 red[mask] = 0 output = cv.merge((blue, green, red)) output = cv.convertScaleAbs(output, None, 255) output = cv.resize(output, None, None, self.block, self.block, cv.INTER_LINEAR) self.viewer.update_processed( np.copy(output[:self.image.shape[0], :self.image.shape[1]])) avgprob = cv.mean(prob, 1 - mask.astype(np.uint8))[0] * 100 self.avgprob_label.setText(self.tr( 'Average = {:.2f}%'.format(avgprob))) modify_font(self.avgprob_label, italic=False, bold=True) self.process_button.setEnabled(False)
class PersonEditDialog(QDialog): GROUP_NAME = '' ORGANIZATION_NAME = '' def __init__(self, person, is_new=False): super().__init__(GlobalAccess().get_main_window()) self.is_ok = {} assert (isinstance(person, Person)) self.current_object = person self.is_new = is_new self.time_format = 'hh:mm:ss' time_accuracy = race().get_setting('time_accuracy', 0) if time_accuracy: self.time_format = 'hh:mm:ss.zzz' def exec_(self): self.init_ui() self.set_values_from_model() return super().exec_() def init_ui(self): self.setWindowTitle(_('Entry properties')) self.setWindowIcon(QIcon(config.ICON)) self.setSizeGripEnabled(False) self.setModal(True) self.layout = QFormLayout(self) self.label_surname = QLabel(_('Last name')) self.item_surname = QLineEdit() self.layout.addRow(self.label_surname, self.item_surname) self.label_name = QLabel(_('First name')) self.item_name = AdvComboBox() self.item_name.addItems(get_names()) self.layout.addRow(self.label_name, self.item_name) self.label_group = QLabel(_('Group')) self.item_group = AdvComboBox() self.item_group.addItems(get_race_groups()) self.layout.addRow(self.label_group, self.item_group) self.label_team = QLabel(_('Team')) self.item_team = AdvComboBox() self.item_team.addItems(get_race_teams()) self.layout.addRow(self.label_team, self.item_team) use_birthday = Config().configuration.get('use_birthday', False) if use_birthday: self.label_birthday = QLabel(_('Birthday')) self.item_birthday = QDateEdit() self.item_birthday.setDate(date.today()) self.item_birthday.setMaximumDate(date.today()) self.layout.addRow(self.label_birthday, self.item_birthday) else: self.label_year = QLabel(_('Year of birth')) self.item_year = QSpinBox() self.item_year.setMinimum(0) self.item_year.setMaximum(date.today().year) self.item_year.editingFinished.connect(self.year_change) self.layout.addRow(self.label_year, self.item_year) self.label_qual = QLabel(_('Qualification')) self.item_qual = AdvComboBox() for i in list(Qualification): self.item_qual.addItem(i.get_title()) self.layout.addRow(self.label_qual, self.item_qual) self.is_ok['bib'] = True self.label_bib = QLabel(_('Bib')) self.item_bib = QSpinBox() self.item_bib.setMinimum(0) self.item_bib.setMaximum(Limit.BIB) self.item_bib.valueChanged.connect(self.check_bib) self.layout.addRow(self.label_bib, self.item_bib) self.label_bib_info = QLabel('') self.layout.addRow(QLabel(''), self.label_bib_info) self.label_start = QLabel(_('Start time')) self.item_start = QTimeEdit() self.item_start.setDisplayFormat(self.time_format) self.layout.addRow(self.label_start, self.item_start) self.label_start_group = QLabel(_('Start group')) self.item_start_group = QSpinBox() self.item_start_group.setMinimum(0) self.item_start_group.setMaximum(99) self.layout.addRow(self.label_start_group, self.item_start_group) self.is_ok['card'] = True self.label_card = QLabel(_('Punch card #')) self.item_card = QSpinBox() self.item_card.setMinimum(0) self.item_card.setMaximum(9999999) self.item_card.valueChanged.connect(self.check_card) self.layout.addRow(self.label_card, self.item_card) self.label_card_info = QLabel('') self.layout.addRow(QLabel(''), self.label_card_info) self.item_rented = QCheckBox(_('rented card')) self.item_paid = QCheckBox(_('is paid')) self.item_out_of_competition = QCheckBox(_('out of competition')) self.item_personal = QCheckBox(_('personal participation')) self.layout.addRow(self.item_rented, self.item_out_of_competition) self.layout.addRow(self.item_paid, self.item_personal) self.label_comment = QLabel(_('Comment')) self.item_comment = QTextEdit() self.item_comment.setTabChangesFocus(True) self.layout.addRow(self.label_comment, self.item_comment) def cancel_changes(): self.close() def apply_changes(): try: self.apply_changes_impl() except Exception as e: logging.error(str(e)) self.close() button_box = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel) self.button_ok = button_box.button(QDialogButtonBox.Ok) self.button_ok.setText(_('OK')) self.button_ok.clicked.connect(apply_changes) self.button_cancel = button_box.button(QDialogButtonBox.Cancel) self.button_cancel.setText(_('Cancel')) self.button_cancel.clicked.connect(cancel_changes) self.layout.addRow(button_box) self.show() def year_change(self): """ Convert 2 digits of year to 4 2 -> 2002 11 - > 2011 33 -> 1933 56 -> 1956 98 - > 1998 0 -> 0 exception! """ widget = self.sender() assert isinstance(widget, QSpinBox) year = widget.value() if 0 < year < 100: cur_year = date.today().year new_year = cur_year - cur_year % 100 + year if new_year > cur_year: new_year -= 100 widget.setValue(new_year) def items_ok(self): ret = True for item_name in self.is_ok.keys(): if self.is_ok[item_name] is not True: ret = False break return ret def check_bib(self): bib = self.item_bib.value() self.label_bib_info.setText('') if bib: person = find(race().persons, bib=bib) if person: if person.bib == self.current_object.bib: self.button_ok.setEnabled(True) return self.button_ok.setDisabled(True) self.is_ok['bib'] = False info = '{}\n{}'.format(_('Number already exists'), person.full_name) if person.group: info = '{}\n{}: {}'.format(info, _('Group'), person.group.name) self.label_bib_info.setText(info) else: self.label_bib_info.setText(_('Number is unique')) self.is_ok['bib'] = True if self.items_ok(): self.button_ok.setEnabled(True) else: self.button_ok.setEnabled(True) def check_card(self): number = self.item_card.value() self.label_card_info.setText('') if number: person = None for _p in race().persons: if _p.card_number and _p.card_number == number: person = _p break if person: if person.card_number == self.current_object.card_number: self.button_ok.setEnabled(True) return self.button_ok.setDisabled(True) self.is_ok['card'] = False info = '{}\n{}'.format(_('Card number already exists'), person.full_name) if person.group: info = '{}\n{}: {}'.format(info, _('Group'), person.group.name) if person.bib: info = '{}\n{}: {}'.format(info, _('Bib'), person.bib) self.label_card_info.setText(info) else: self.label_card_info.setText(_('Card number is unique')) self.is_ok['card'] = True if self.items_ok(): self.button_ok.setEnabled(True) else: self.button_ok.setEnabled(True) def set_values_from_model(self): self.item_surname.setText(self.current_object.surname) self.item_surname.selectAll() self.item_name.setCurrentText(self.current_object.name) if self.current_object.group is not None: self.item_group.setCurrentText(self.current_object.group.name) else: self.item_group.setCurrentText(self.GROUP_NAME) if self.current_object.organization is not None: self.item_team.setCurrentText( self.current_object.organization.name) else: self.item_team.setCurrentText(self.ORGANIZATION_NAME) if self.current_object.qual: self.item_qual.setCurrentText(self.current_object.qual.get_title()) if self.current_object.bib: self.item_bib.setValue(int(self.current_object.bib)) if self.current_object.start_time is not None: time = time_to_qtime(self.current_object.start_time) self.item_start.setTime(time) if self.current_object.start_group is not None: self.item_start_group.setValue(int( self.current_object.start_group)) if self.current_object.card_number: self.item_card.setValue(self.current_object.card_number) self.item_out_of_competition.setChecked( self.current_object.is_out_of_competition) self.item_paid.setChecked(self.current_object.is_paid) self.item_paid.setChecked(self.current_object.is_paid) self.item_personal.setChecked(self.current_object.is_personal) self.item_rented.setChecked(self.current_object.is_rented_card) self.item_comment.setText(self.current_object.comment) use_birthday = Config().configuration.get('use_birthday', False) if use_birthday: if self.current_object.birth_date: self.item_birthday.setDate(self.current_object.birth_date) else: if self.current_object.get_year(): self.item_year.setValue(self.current_object.get_year()) def apply_changes_impl(self): person = self.current_object assert (isinstance(person, Person)) if self.is_new: race().persons.insert(0, person) if person.name != self.item_name.currentText(): person.name = self.item_name.currentText() if person.surname != self.item_surname.text(): person.surname = self.item_surname.text() if (person.group is not None and person.group.name != self.item_group.currentText()) or\ (person.group is None and len(self.item_group.currentText()) > 0): person.group = find(race().groups, name=self.item_group.currentText()) if (person.organization is not None and person.organization.name != self.item_team.currentText()) or \ (person.organization is None and len(self.item_team.currentText()) > 0): organization = find(race().organizations, name=self.item_team.currentText()) if organization is None: organization = Organization() organization.name = self.item_team.currentText() race().organizations.append(organization) Teamwork().send(organization.to_dict()) person.organization = organization if person.qual.get_title() != self.item_qual.currentText(): person.qual = Qualification.get_qual_by_name( self.item_qual.currentText()) if person.bib != self.item_bib.value(): person.bib = self.item_bib.value() new_time = time_to_otime(self.item_start.time()) if person.start_time != new_time: person.start_time = new_time if person.start_group != self.item_start_group.value( ) and self.item_start_group.value(): person.start_group = self.item_start_group.value() if (not person.card_number or int(person.card_number) != self.item_card.value()) \ and self.item_card.value: race().person_card_number(person, self.item_card.value()) if person.is_out_of_competition != self.item_out_of_competition.isChecked( ): person.is_out_of_competition = self.item_out_of_competition.isChecked( ) if person.is_paid != self.item_paid.isChecked(): person.is_paid = self.item_paid.isChecked() if person.is_rented_card != self.item_rented.isChecked(): person.is_rented_card = self.item_rented.isChecked() if person.is_personal != self.item_personal.isChecked(): person.is_personal = self.item_personal.isChecked() if person.comment != self.item_comment.toPlainText(): person.comment = self.item_comment.toPlainText() use_birthday = Config().configuration.get('use_birthday', False) if use_birthday: new_birthday = qdate_to_date(self.item_birthday.date()) if person.birth_date != new_birthday and new_birthday: if person.birth_date or new_birthday != date.today(): person.birth_date = new_birthday else: if person.get_year() != self.item_year.value(): person.set_year(self.item_year.value()) ResultCalculation(race()).process_results() Teamwork().send(person.to_dict())
class MainWindow(QMainWindow): def __init__(self) -> None: QMainWindow.__init__(self) self.lib_chapters = self.__create_libchapters() self.prefs = Prefs() self.current_file: Optional[str] = None self.current_file_type: Optional[str] = None # UI components self.setWindowTitle(libchapters.APPLICATION_NAME) self.setMinimumSize(480, 320) self.resize(900, 500) self.__create_menu() self.podcast_title = QLineEdit() self.episode_title = QLineEdit() self.episode_number = QSpinBox() self.episode_number.setMaximumWidth(55) self.chapters_table_view = QTableView() self.chapters_table_model = ChaptersTableModel( self.chapters_table_view) self.chapters_table_view.setModel(self.chapters_table_model) self.chapters_table_view.horizontalHeader().setStretchLastSection(True) self.add_chapter_button = QPushButton("Add") self.add_chapter_button.clicked.connect( self.chapters_table_model.add_chapter) self.delete_chapter_button = QPushButton("Delete") self.delete_chapter_button.clicked.connect( self.chapters_table_model.remove_selected_chapters) self.progress_bar = QProgressBar() self.setCentralWidget(self.__create_center_widget()) self.__create_status_bar() def __create_libchapters(self) -> LibChapters: listener = LibChaptersListener() listener.signals.encode_started.connect(self.__encode_started) listener.signals.encode_progress.connect(self.__encode_progress) listener.signals.encode_complete.connect(self.__encode_complete) listener.signals.read_metadata_started.connect( self.__read_metadata_started) listener.signals.read_metadata_complete.connect( self.__read_metadata_complete) listener.signals.write_mp3_file_started.connect( self.__write_mp3_started) listener.signals.write_mp3_file_progress.connect( self.__write_mp3_progress) listener.signals.write_mp3_file_complete.connect( self.__write_mp3_complete) return LibChapters(listener) def __create_center_widget(self) -> QWidget: episode_info_layout = QFormLayout() episode_info_layout.addRow("Podcast Title:", self.podcast_title) episode_info_layout.addRow("Episode Title:", self.episode_title) episode_info_layout.addRow("Episode Number:", self.episode_number) add_remove_chapters_layout = QHBoxLayout() add_remove_chapters_layout.addWidget(self.add_chapter_button) add_remove_chapters_layout.addWidget(self.delete_chapter_button) add_remove_chapters_layout.setAlignment(Qt.AlignLeft) center_widget_layout = QVBoxLayout() center_widget_layout.addLayout(episode_info_layout) center_widget_layout.addWidget(self.chapters_table_view) center_widget_layout.addLayout(add_remove_chapters_layout) center_widget = QWidget() center_widget.setLayout(center_widget_layout) return center_widget def __create_menu(self) -> None: menu_bar = self.menuBar() file_menu = menu_bar.addMenu("File") import_action = file_menu.addAction("Import Audio...") import_action.setShortcut(QKeySequence("Ctrl+I")) import_action.triggered.connect(self.__import_audio) open_file_action = file_menu.addAction("Open...") open_file_action.setShortcut(QKeySequence("Ctrl+O")) open_file_action.triggered.connect(self.__open_file) file_menu.addSeparator() save_action = file_menu.addAction("Save") save_action.setShortcut(QKeySequence("Ctrl+S")) save_action.triggered.connect(self.__save_current_file) save_as_action = file_menu.addAction("Save As...") save_as_action.setShortcut(QKeySequence("Ctrl+Shift+S")) save_as_action.triggered.connect(self.__save_current_file_as) file_menu.addSeparator() exit_action = file_menu.addAction("Exit") exit_action.setShortcut(QKeySequence("Alt+f4")) exit_action.triggered.connect(QCoreApplication.quit) help_menu = menu_bar.addMenu("Help") documentation_action = help_menu.addAction("Open Documentation...") documentation_action.triggered.connect( lambda: QDesktopServices.openUrl(libchapters.DOCUMENTATION)) help_menu.addSeparator() about_action = help_menu.addAction("About...") about_action.triggered.connect(self.__show_about_dialog) def __create_status_bar(self) -> None: status_bar = self.statusBar() status_bar.addPermanentWidget(self.progress_bar) def __import_audio(self) -> None: file = self.__show_open_dialog("*.wav") if file: self.__set_current_file(file, "wav") self.lib_chapters.read_metadata_from_wav_file(file) self.lib_chapters.encode_wav_file(file) def __open_file(self) -> None: file = self.__show_open_dialog("*.mp3") if file: self.__set_current_file(file, "mp3") self.lib_chapters.read_metadata_from_mp3_file(file) def __encode_started(self) -> None: self.progress_bar.setValue(0) self.statusBar().showMessage("Importing file...") def __encode_progress(self, progress: int) -> None: self.progress_bar.setValue(progress) def __encode_complete(self) -> None: self.centralWidget().setDisabled(False) self.menuBar().setDisabled(False) self.statusBar().showMessage("Import complete") def __read_metadata_started(self) -> None: self.chapters_table_view.setDisabled(True) def __read_metadata_complete(self, metadata: MetaData) -> None: self.chapters_table_view.setDisabled(False) if metadata.podcast_title: self.podcast_title.setText(metadata.podcast_title) else: self.podcast_title.clear() if metadata.episode_title: self.episode_title.setText(metadata.episode_title) else: self.episode_title.clear() if metadata.episode_number: self.episode_number.setValue(metadata.episode_number) else: self.episode_number.clear() if metadata.chapters: self.chapters_table_model.set_chapters(metadata.chapters) else: self.chapters_table_model.clear_chapters() def __save_current_file(self) -> None: if self.current_file: meta_data = MetaData( podcast_title=self.podcast_title.text(), episode_title=self.episode_title.text(), episode_number=self.episode_number.value(), chapters=self.chapters_table_model.get_chapters()) if self.current_file_type == "wav": output_file = self.__show_save_dialog("*.mp3") if output_file: self.lib_chapters.write_mp3_data_with_metadata( meta_data, output_file) elif self.current_file_type == "mp3": self.lib_chapters.write_metadata_to_file( meta_data, self.current_file) def __save_current_file_as(self) -> None: if self.current_file: output_file = self.__show_save_dialog("*.mp3") if output_file: meta_data = MetaData( podcast_title=self.podcast_title.text(), episode_title=self.episode_title.text(), episode_number=self.episode_number.value(), chapters=self.chapters_table_model.get_chapters()) if self.current_file_type == "wav": self.lib_chapters.write_mp3_data_with_metadata( meta_data, output_file) elif self.current_file_type == "mp3": self.lib_chapters.copy_mp3_with_metadata( self.current_file, output_file, meta_data) def __write_mp3_started(self) -> None: self.menuBar().setDisabled(True) self.centralWidget().setDisabled(True) self.progress_bar.setValue(0) self.statusBar().showMessage("Saving MP3...") def __write_mp3_progress(self, progress: int) -> None: self.progress_bar.setValue(progress) def __write_mp3_complete(self, path_to_mp3: str) -> None: self.menuBar().setDisabled(False) self.centralWidget().setDisabled(False) self.__set_current_file(path_to_mp3, "mp3") self.statusBar().showMessage("Save complete") def __show_about_dialog(self) -> None: about_dialog = AboutDialog(self) about_dialog.show() def __set_current_file(self, current_file: str, current_file_type: str) -> None: self.current_file = current_file self.current_file_type = current_file_type self.setWindowTitle( f"{libchapters.APPLICATION_NAME} - {os.path.basename(current_file)}" ) def __show_open_dialog(self, type_filter: str) -> Optional[str]: file, _ = QFileDialog.getOpenFileName( parent=self, dir=self.prefs.get_pref_open_dir(), filter=type_filter) if file: self.prefs.set_pref_open_dir(file) return file def __show_save_dialog(self, type_filter: str) -> Optional[str]: file, _ = QFileDialog.getSaveFileName( parent=self, dir=self.prefs.get_pref_save_dir(), filter=type_filter) if file: self.prefs.set_pref_save_dir(file) return file
class ElaWidget(ToolWidget): def __init__(self, image, parent=None): super(ElaWidget, self).__init__(parent) self.quality_spin = QSpinBox() self.quality_spin.setRange(1, 100) self.quality_spin.setSuffix(self.tr(" %")) self.quality_spin.setToolTip(self.tr("JPEG reference quality level")) self.scale_spin = QSpinBox() self.scale_spin.setRange(1, 100) self.scale_spin.setSuffix(" %") self.scale_spin.setToolTip(self.tr("Output multiplicative gain")) self.contrast_spin = QSpinBox() self.contrast_spin.setRange(0, 100) self.contrast_spin.setSuffix(" %") self.contrast_spin.setToolTip(self.tr("Output tonality compression")) self.linear_check = QCheckBox(self.tr("Linear")) self.linear_check.setToolTip(self.tr("Linearize absolute difference")) self.gray_check = QCheckBox(self.tr("Grayscale")) self.gray_check.setToolTip(self.tr("Desaturated output")) default_button = QPushButton(self.tr("Default")) default_button.setToolTip(self.tr("Revert to default parameters")) params_layout = QHBoxLayout() params_layout.addWidget(QLabel(self.tr("Quality:"))) params_layout.addWidget(self.quality_spin) params_layout.addWidget(QLabel(self.tr("Scale:"))) params_layout.addWidget(self.scale_spin) params_layout.addWidget(QLabel(self.tr("Contrast:"))) params_layout.addWidget(self.contrast_spin) params_layout.addWidget(self.linear_check) params_layout.addWidget(self.gray_check) params_layout.addWidget(default_button) params_layout.addStretch() self.image = image self.original = image.astype(np.float32) / 255 self.compressed = None self.viewer = ImageViewer(self.image, self.image) self.default() self.quality_spin.valueChanged.connect(self.preprocess) self.scale_spin.valueChanged.connect(self.process) self.contrast_spin.valueChanged.connect(self.process) self.linear_check.stateChanged.connect(self.process) self.gray_check.stateChanged.connect(self.process) default_button.clicked.connect(self.default) main_layout = QVBoxLayout() main_layout.addLayout(params_layout) main_layout.addWidget(self.viewer) self.setLayout(main_layout) def preprocess(self): quality = self.quality_spin.value() self.compressed = compress_jpg(self.image, quality) self.process() def process(self): start = time() scale = self.scale_spin.value() contrast = int(self.contrast_spin.value() / 100 * 128) linear = self.linear_check.isChecked() grayscale = self.gray_check.isChecked() if not linear: difference = cv.absdiff(self.original, self.compressed.astype(np.float32) / 255) ela = cv.convertScaleAbs(cv.sqrt(difference) * 255, None, scale / 20) else: ela = cv.convertScaleAbs(cv.subtract(self.compressed, self.image), None, scale) ela = cv.LUT(ela, create_lut(contrast, contrast)) if grayscale: ela = desaturate(ela) self.viewer.update_processed(ela) self.info_message.emit(self.tr(f"Error Level Analysis = {elapsed_time(start)}")) def default(self): self.blockSignals(True) self.linear_check.setChecked(False) self.gray_check.setChecked(False) self.quality_spin.setValue(75) self.scale_spin.setValue(50) self.contrast_spin.setValue(25) self.blockSignals(False) self.preprocess()
class OptionsDock(QDockWidget): def __init__(self, model, FM, parent=None): super(OptionsDock, self).__init__(parent) self.model = model self.FM = FM self.mw = parent self.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Expanding) # Doesn't work? self.setAllowedAreas(QtCore.Qt.LeftDockWidgetArea | QtCore.Qt.RightDockWidgetArea) # Create Controls self.createOriginBox() self.createOptionsBox() self.createResolutionBox() # Create submit button self.applyButton = QPushButton("Apply Changes") self.applyButton.setMinimumHeight(self.FM.height() * 1.6) # Mac bug fix self.applyButton.clicked.connect(self.mw.applyChanges) # Create Zoom box self.zoomBox = QSpinBox() self.zoomBox.setSuffix(' %') self.zoomBox.setRange(25, 2000) self.zoomBox.setValue(100) self.zoomBox.setSingleStep(25) self.zoomBox.valueChanged.connect(self.mw.editZoom) self.zoomLayout = QHBoxLayout() self.zoomLayout.addWidget(QLabel('Zoom:')) self.zoomLayout.addWidget(self.zoomBox) self.zoomLayout.setContentsMargins(0, 0, 0, 0) self.zoomWidget = QWidget() self.zoomWidget.setLayout(self.zoomLayout) # Create Layout self.dockLayout = QVBoxLayout() self.dockLayout.addWidget(self.originGroupBox) self.dockLayout.addWidget(self.optionsGroupBox) self.dockLayout.addWidget(self.resGroupBox) self.dockLayout.addWidget(self.applyButton) self.dockLayout.addStretch() self.dockLayout.addWidget(HorizontalLine()) self.dockLayout.addWidget(self.zoomWidget) self.optionsWidget = QWidget() self.optionsWidget.setLayout(self.dockLayout) self.setWidget(self.optionsWidget) def createOriginBox(self): # X Origin self.xOrBox = QDoubleSpinBox() self.xOrBox.setDecimals(9) self.xOrBox.setRange(-99999, 99999) self.xOrBox.valueChanged.connect( lambda value: self.mw.editSingleOrigin(value, 0)) # Y Origin self.yOrBox = QDoubleSpinBox() self.yOrBox.setDecimals(9) self.yOrBox.setRange(-99999, 99999) self.yOrBox.valueChanged.connect( lambda value: self.mw.editSingleOrigin(value, 1)) # Z Origin self.zOrBox = QDoubleSpinBox() self.zOrBox.setDecimals(9) self.zOrBox.setRange(-99999, 99999) self.zOrBox.valueChanged.connect( lambda value: self.mw.editSingleOrigin(value, 2)) # Origin Form Layout self.orLayout = QFormLayout() self.orLayout.addRow('X:', self.xOrBox) self.orLayout.addRow('Y:', self.yOrBox) self.orLayout.addRow('Z:', self.zOrBox) #self.orLayout.setVerticalSpacing(4) self.orLayout.setLabelAlignment(QtCore.Qt.AlignLeft) self.orLayout.setFieldGrowthPolicy(QFormLayout.AllNonFixedFieldsGrow) # Origin Group Box self.originGroupBox = QGroupBox('Origin') self.originGroupBox.setLayout(self.orLayout) def createOptionsBox(self): # Width self.widthBox = QDoubleSpinBox(self) self.widthBox.setRange(.1, 99999) self.widthBox.valueChanged.connect(self.mw.editWidth) # Height self.heightBox = QDoubleSpinBox(self) self.heightBox.setRange(.1, 99999) self.heightBox.valueChanged.connect(self.mw.editHeight) # ColorBy self.colorbyBox = QComboBox(self) self.colorbyBox.addItem("material") self.colorbyBox.addItem("cell") self.colorbyBox.currentTextChanged[str].connect(self.mw.editColorBy) # Basis self.basisBox = QComboBox(self) self.basisBox.addItem("xy") self.basisBox.addItem("xz") self.basisBox.addItem("yz") self.basisBox.currentTextChanged.connect(self.mw.editBasis) # Advanced Color Options self.colorOptionsButton = QPushButton('Color Options...') self.colorOptionsButton.setMinimumHeight(self.FM.height() * 1.6) self.colorOptionsButton.clicked.connect(self.mw.showColorDialog) # Options Form Layout self.opLayout = QFormLayout() self.opLayout.addRow('Width:', self.widthBox) self.opLayout.addRow('Height:', self.heightBox) self.opLayout.addRow('Basis:', self.basisBox) self.opLayout.addRow('Color By:', self.colorbyBox) self.opLayout.addRow(self.colorOptionsButton) self.opLayout.setLabelAlignment(QtCore.Qt.AlignLeft) self.opLayout.setFieldGrowthPolicy(QFormLayout.AllNonFixedFieldsGrow) # Options Group Box self.optionsGroupBox = QGroupBox('Options') self.optionsGroupBox.setLayout(self.opLayout) def createResolutionBox(self): # Horizontal Resolution self.hResBox = QSpinBox(self) self.hResBox.setRange(1, 99999) self.hResBox.setSingleStep(25) self.hResBox.setSuffix(' px') self.hResBox.valueChanged.connect(self.mw.editHRes) # Vertical Resolution self.vResLabel = QLabel('Pixel Height:') self.vResBox = QSpinBox(self) self.vResBox.setRange(1, 99999) self.vResBox.setSingleStep(25) self.vResBox.setSuffix(' px') self.vResBox.valueChanged.connect(self.mw.editVRes) # Ratio checkbox self.ratioCheck = QCheckBox("Fixed Aspect Ratio", self) self.ratioCheck.stateChanged.connect(self.mw.toggleAspectLock) # Resolution Form Layout self.resLayout = QFormLayout() self.resLayout.addRow(self.ratioCheck) self.resLayout.addRow('Pixel Width:', self.hResBox) self.resLayout.addRow(self.vResLabel, self.vResBox) self.resLayout.setLabelAlignment(QtCore.Qt.AlignLeft) self.resLayout.setFieldGrowthPolicy(QFormLayout.AllNonFixedFieldsGrow) # Resolution Group Box self.resGroupBox = QGroupBox("Resolution") self.resGroupBox.setLayout(self.resLayout) def updateDock(self): self.updateOrigin() self.updateWidth() self.updateHeight() self.updateColorBy() self.updateBasis() self.updateAspectLock() self.updateHRes() self.updateVRes() def updateOrigin(self): self.xOrBox.setValue(self.model.activeView.origin[0]) self.yOrBox.setValue(self.model.activeView.origin[1]) self.zOrBox.setValue(self.model.activeView.origin[2]) def updateWidth(self): self.widthBox.setValue(self.model.activeView.width) def updateHeight(self): self.heightBox.setValue(self.model.activeView.height) def updateColorBy(self): self.colorbyBox.setCurrentText(self.model.activeView.colorby) def updateBasis(self): self.basisBox.setCurrentText(self.model.activeView.basis) def updateAspectLock(self): if self.model.activeView.aspectLock: self.ratioCheck.setChecked(True) self.vResBox.setDisabled(True) self.vResLabel.setDisabled(True) else: self.ratioCheck.setChecked(False) self.vResBox.setDisabled(False) self.vResLabel.setDisabled(False) def updateHRes(self): self.hResBox.setValue(self.model.activeView.hRes) def updateVRes(self): self.vResBox.setValue(self.model.activeView.vRes) def revertToCurrent(self): cv = self.model.currentView self.xOrBox.setValue(cv.origin[0]) self.yOrBox.setValue(cv.origin[1]) self.zOrBox.setValue(cv.origin[2]) self.widthBox.setValue(cv.width) self.heightBox.setValue(cv.height) def resizeEvent(self, event): self.mw.resizeEvent(event) def hideEvent(self, event): self.mw.resizeEvent(event) def showEvent(self, event): self.mw.resizeEvent(event) def moveEvent(self, event): self.mw.resizeEvent(event)
class GameSettingsDialog(QDialog): def __init__(self, parent=None): super(GameSettingsDialog, self).__init__(parent) self.parent = parent self.setModal(True) self.setWindowTitle("Game settings") self.create_widgets() self.set_layouts() def create_widgets(self): self.label_player1 = QLabel("Player 1") self.input_player1_name = QLineEdit() self.input_player1_name.setPlaceholderText("Player 1") self.input_player1_name.setFocus() self.player1_completer = QCompleter() self.input_player1_name.setCompleter(self.player1_completer) self.label_player2 = QLabel("Player 2") self.input_player2_name = QLineEdit() self.input_player2_name.setPlaceholderText("Player 2") self.player2_completer = QCompleter() self.input_player2_name.setCompleter(self.player2_completer) # player widget-ek feltültése a db-ben szereplő nevekkel, autocomplete-hez self.get_player_name() self.gomb_301 = QRadioButton("301") self.gomb_401 = QRadioButton("401") self.gomb_501 = QRadioButton("501") self.gomb_501.setChecked(True) self.gomb_701 = QRadioButton("701") self.label_bestof = QLabel("Best Of.. (Egyébként First To..)") self.best_of = QCheckBox() self.spin_legs = QSpinBox() self.spin_legs.setValue(3) self.spin_legs.setMinimum(1) self.spin_legs.setMaximum(21) self.spin_sets = QSpinBox() self.spin_sets.setValue(1) self.spin_sets.setMinimum(1) self.spin_sets.setMaximum(15) self.handi1 = QSpinBox() self.handi1.setValue(0) self.handi1.setMinimum(-100) self.handi1.setMaximum(100) self.handi2 = QSpinBox() self.handi2.setValue(0) self.handi2.setMinimum(-100) self.handi2.setMaximum(100) self.buttonbox = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel | QDialogButtonBox.Reset) self.buttonbox.clicked.connect(self.buttonbox_click) def set_layouts(self): self.layout = QVBoxLayout() self.setLayout(self.layout) self.kontener_names = QHBoxLayout() self.kontener_names.addWidget(self.label_player1) self.kontener_names.addWidget(self.input_player1_name) self.kontener_names.addWidget(self.label_player2) self.kontener_names.addWidget(self.input_player2_name) self.kontener_buttons = QHBoxLayout() self.kontener_buttons.addWidget(self.gomb_301) self.kontener_buttons.addWidget(self.gomb_401) self.kontener_buttons.addWidget(self.gomb_501) self.kontener_buttons.addWidget(self.gomb_701) self.bestof_layout = QHBoxLayout() self.bestof_layout.addWidget(self.label_bestof) self.bestof_layout.addWidget(self.best_of) self.kontener_szovegek1 = QVBoxLayout() self.kontener_szovegek1.addWidget( QLabel("Leave Player 2 blank for single player")) self.kontener_szovegek1.addWidget(QLabel("Variant")) self.kontener_sets = QHBoxLayout() self.kontener_sets.addWidget(QLabel("Legs per set: ")) self.kontener_sets.addWidget(self.spin_legs) self.kontener_sets.addWidget(QLabel("Number os sets: ")) self.kontener_sets.addWidget(self.spin_sets) self.kontener_handi = QHBoxLayout() self.kontener_handi.addWidget(QLabel("Handicap (1)")) self.kontener_handi.addWidget(self.handi1) self.kontener_handi.addWidget(QLabel("Handicap (2)")) self.kontener_handi.addWidget(self.handi2) self.layout.addLayout(self.kontener_names) self.layout.addLayout(self.kontener_szovegek1) self.layout.addLayout(self.kontener_buttons) self.layout.addLayout(self.bestof_layout) self.layout.addLayout(self.kontener_sets) self.layout.addLayout(self.kontener_handi) self.layout.addWidget(self.buttonbox) def get_player_name(self): player_name_model = QSqlQueryModel() query = QSqlQuery( "SELECT player_name FROM players where type='local' and aktiv=1 order by player_name", db=db) player_name_model.setQuery(query) self.player1_completer.setModel(player_name_model) self.player2_completer.setModel(player_name_model) def buttonbox_click(self, b): if b.text() == "OK": self.accept() elif b.text() == "Cancel": self.reject() else: self.alapertekek() def alapertekek(self): self.input_player1_name.setText("") self.input_player1_name.setPlaceholderText("Player 1 name") self.input_player2_name.setText("") self.input_player2_name.setPlaceholderText("Player 2 name") self.gomb_501.setChecked(True) self.best_of.setChecked(False) self.spin_legs.setValue(3) self.spin_sets.setValue(1) self.handi1.setValue(0) self.handi2.setValue(0) def accept(self): params = [] m_id = p1_id = p2_id = set = leg = hc1 = hc2 = 0 var = "" player1 = self.input_player1_name.text() player2 = self.input_player2_name.text() # todo A MATCH_ID-T VALAMI EGYEDI MÓDON KELL GENERÁLNI(pl. az időbélyeg bizonyos részével) m_id = random.randint(10, 1000000) leg = self.spin_legs.value() set = self.spin_sets.value() hc1 = self.handi1.value() hc2 = self.handi2.value() if self.gomb_301.isChecked(): var = "301" elif self.gomb_401.isChecked(): var = "401" elif self.gomb_501.isChecked(): var = "501" else: var = "701" if self.best_of.isChecked(): bestof = 1 else: bestof = 0 if len(player1) == 0: p1_id = 1 player1 = "Player 1" else: player1_id_model = QSqlQueryModel() query1 = QSqlQuery( f"SELECT player_id FROM players where player_name = '{player1}' and type='local' and aktiv=1", db=db) player1_id_model.setQuery(query1) # todo megnézni, hogy sima query.exec_ -el hogyan működik, lehet-e ellenőrizni, hogy üres vagy nem if player1_id_model.record(0).value(0): p1_id = int(player1_id_model.record(0).value(0)) else: # todo beszúrás előtt ellenőritni, hogy egyedi-e. Létezhet versenyen felvitt ugyanolyan név player_model1 = QSqlTableModel() player_model1.setTable("players") rec_play1 = player_model1.record() rec_play1.remove(0) rec_play1.setValue(0, player1) rec_play1.setValue(1, 'local') rec_play1.setValue(2, 1) if player_model1.insertRecord(-1, rec_play1): player_model1.submitAll() else: db.rollback() query1 = QSqlQuery( f"SELECT player_id FROM players where player_name = '{player1}' and type='local' and aktiv=1", db=db) player1_id_model.setQuery(query1) # todo megnézni, hogy sima query.exec_ -el hogyan működik, lehet-e ellenőrizni, hogy üres vagy nem p1_id = int(player1_id_model.record(0).value(0)) if len(player2) == 0: p2_id = 2 player2 = "Player 2" else: player2_id_model = QSqlQueryModel() query2 = QSqlQuery( f"SELECT player_id FROM players where player_name = '{player2}' and type='local' and aktiv=1", db=db) player2_id_model.setQuery(query2) # todo megnézni, hogy sima query.exec_ -el hogyan működik, lehet-e ellenőrizni, hogy üres vagy nem if player2_id_model.record(0).value(0): p2_id = int(player2_id_model.record(0).value(0)) else: player_model2 = QSqlTableModel() player_model2.setTable("players") rec_play2 = player_model2.record() rec_play2.remove(0) rec_play2.setValue(0, player2) rec_play2.setValue(1, 'local') rec_play2.setValue(2, 1) if player_model2.insertRecord(-1, rec_play2): player_model2.submitAll() else: db.rollback() query2 = QSqlQuery( f"SELECT player_id FROM players where player_name = '{player2}' and type='local' and aktiv=1", db=db) player2_id_model.setQuery(query2) # todo megnézni, hogy sima query.exec_ -el hogyan működik, lehet-e ellenőrizni, hogy üres vagy nem p2_id = int(player2_id_model.record(0).value(0)) # Match paremeterek rögzítése now = QDateTime.currentDateTime() match_model = QSqlTableModel() match_model.setTable("match_settings") # todo Best Of... nincs db-ben tárolva record = match_model.record() record.setValue(0, m_id) record.setValue(1, p1_id) record.setValue(2, p2_id) record.setValue(3, var) record.setValue(4, leg) record.setValue(5, set) record.setValue(6, hc1) record.setValue(7, hc2) record.setValue(8, now) if match_model.insertRecord(-1, record): match_model.submitAll() else: db.rollback() params.append(player1) params.append(player2) params.append(m_id) params.append(p1_id) params.append(p2_id) params.append(var) params.append(leg) params.append(set) params.append(hc1) params.append(hc2) params.append(bestof) self.parent.new_game_window.params = params self.parent.new_game_window.refresh() super().accept() def reject(self): self.parent.new_game_window.close() super().reject()
class ColorDialog(QDialog): def __init__(self, model, FM, parent=None): super(ColorDialog, self).__init__(parent) self.setWindowTitle('Color Options') self.model = model self.FM = FM self.mw = parent self.createDialogLayout() def createDialogLayout(self): self.createGeneralTab() self.cellTable = self.createDomainTable(self.mw.cellsModel) self.matTable = self.createDomainTable(self.mw.materialsModel) self.cellTab = self.createDomainTab(self.cellTable) self.matTab = self.createDomainTab(self.matTable) self.tabs = QTabWidget() self.tabs.setMaximumHeight(800) self.tabs.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) self.tabs.addTab(self.generalTab, 'General') self.tabs.addTab(self.cellTab, 'Cells') self.tabs.addTab(self.matTab, 'Materials') self.createButtonBox() self.colorDialogLayout = QVBoxLayout() #self.colorDialogLayout.setContentsMargins(0, 0, 0, 0) self.colorDialogLayout.addWidget(self.tabs) self.colorDialogLayout.addWidget(self.buttonBox) self.setLayout(self.colorDialogLayout) def createGeneralTab(self): # Masking options self.maskingCheck = QCheckBox('') self.maskingCheck.stateChanged.connect(self.mw.toggleMasking) self.maskColorButton = QPushButton() self.maskColorButton.setCursor(QtCore.Qt.PointingHandCursor) self.maskColorButton.setFixedWidth(self.FM.width("XXXXXXXXXX")) self.maskColorButton.setFixedHeight(self.FM.height() * 1.5) self.maskColorButton.clicked.connect(self.mw.editMaskingColor) # Highlighting options self.hlCheck = QCheckBox('') self.hlCheck.stateChanged.connect(self.mw.toggleHighlighting) self.hlColorButton = QPushButton() self.hlColorButton.setCursor(QtCore.Qt.PointingHandCursor) self.hlColorButton.setFixedWidth(self.FM.width("XXXXXXXXXX")) self.hlColorButton.setFixedHeight(self.FM.height() * 1.5) self.hlColorButton.clicked.connect(self.mw.editHighlightColor) self.alphaBox = QDoubleSpinBox() self.alphaBox.setRange(0, 1) self.alphaBox.setSingleStep(.05) self.alphaBox.valueChanged.connect(self.mw.editAlpha) self.seedBox = QSpinBox() self.seedBox.setRange(1, 999) self.seedBox.valueChanged.connect(self.mw.editSeed) # General options self.bgButton = QPushButton() self.bgButton.setCursor(QtCore.Qt.PointingHandCursor) self.bgButton.setFixedWidth(self.FM.width("XXXXXXXXXX")) self.bgButton.setFixedHeight(self.FM.height() * 1.5) self.bgButton.clicked.connect(self.mw.editBackgroundColor) self.colorbyBox = QComboBox(self) self.colorbyBox.addItem("material") self.colorbyBox.addItem("cell") self.colorbyBox.currentTextChanged[str].connect(self.mw.editColorBy) formLayout = QFormLayout() formLayout.setAlignment(QtCore.Qt.AlignHCenter) formLayout.setFormAlignment(QtCore.Qt.AlignHCenter) formLayout.setLabelAlignment(QtCore.Qt.AlignLeft) #formLayout.setFieldGrowthPolicy(QFormLayout.AllNonFixedFieldsGrow) formLayout.addRow('Masking:', self.maskingCheck) formLayout.addRow('Mask Color:', self.maskColorButton) formLayout.addRow(HorizontalLine()) formLayout.addRow('Highlighting:', self.hlCheck) formLayout.addRow('Highlight Color:', self.hlColorButton) formLayout.addRow('Highlight Alpha:', self.alphaBox) formLayout.addRow('Highlight Seed:', self.seedBox) formLayout.addRow(HorizontalLine()) formLayout.addRow('Background Color: ', self.bgButton) formLayout.addRow('Color Plot By:', self.colorbyBox) generalLayout = QHBoxLayout() innerWidget = QWidget() generalLayout.setAlignment(QtCore.Qt.AlignVCenter) innerWidget.setLayout(formLayout) generalLayout.addStretch(1) generalLayout.addWidget(innerWidget) generalLayout.addStretch(1) self.generalTab = QWidget() self.generalTab.setLayout(generalLayout) def createDomainTable(self, domainmodel): domainTable = QTableView() domainTable.setModel(domainmodel) domainTable.setItemDelegate(DomainDelegate(domainTable)) domainTable.verticalHeader().setVisible(False) domainTable.resizeColumnsToContents() domainTable.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) domainTable.horizontalHeader().setSectionResizeMode( 1, QHeaderView.Stretch) return domainTable def createDomainTab(self, domaintable): domainTab = QWidget() domainTab.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) domainLayout = QVBoxLayout() domainLayout.addWidget(domaintable) domainTab.setLayout(domainLayout) return domainTab def createButtonBox(self): applyButton = QPushButton("Apply Changes") applyButton.clicked.connect(self.mw.applyChanges) closeButton = QPushButton("Close") closeButton.clicked.connect(self.hide) buttonLayout = QHBoxLayout() buttonLayout.addStretch(1) buttonLayout.addWidget(applyButton) buttonLayout.addWidget(closeButton) self.buttonBox = QWidget() self.buttonBox.setLayout(buttonLayout) def updateDialogValues(self): self.updateMasking() self.updateMaskingColor() self.updateHighlighting() self.updateHighlightColor() self.updateAlpha() self.updateSeed() self.updateBackgroundColor() self.updateColorBy() self.updateDomainTabs() def updateMasking(self): masking = self.model.activeView.masking self.maskingCheck.setChecked(masking) self.maskColorButton.setDisabled(not masking) if masking: self.cellTable.showColumn(4) self.matTable.showColumn(4) else: self.cellTable.hideColumn(4) self.matTable.hideColumn(4) def updateMaskingColor(self): color = self.model.activeView.maskBackground self.maskColorButton.setStyleSheet("border-radius: 8px;" "background-color: rgb%s" % (str(color))) def updateHighlighting(self): highlighting = self.model.activeView.highlighting self.hlCheck.setChecked(highlighting) self.hlColorButton.setDisabled(not highlighting) self.alphaBox.setDisabled(not highlighting) self.seedBox.setDisabled(not highlighting) if highlighting: self.cellTable.showColumn(5) self.cellTable.hideColumn(2) self.cellTable.hideColumn(3) self.matTable.showColumn(5) self.matTable.hideColumn(2) self.matTable.hideColumn(3) else: self.cellTable.hideColumn(5) self.cellTable.showColumn(2) self.cellTable.showColumn(3) self.matTable.hideColumn(5) self.matTable.showColumn(2) self.matTable.showColumn(3) def updateHighlightColor(self): color = self.model.activeView.highlightBackground self.hlColorButton.setStyleSheet("border-radius: 8px;" "background-color: rgb%s" % (str(color))) def updateAlpha(self): self.alphaBox.setValue(self.model.activeView.highlightAlpha) def updateSeed(self): self.seedBox.setValue(self.model.activeView.highlightSeed) def updateBackgroundColor(self): color = self.model.activeView.plotBackground self.bgButton.setStyleSheet("border-radius: 8px;" "background-color: rgb%s" % (str(color))) def updateColorBy(self): self.colorbyBox.setCurrentText(self.model.activeView.colorby) def updateDomainTabs(self): self.cellTable.setModel(self.mw.cellsModel) self.matTable.setModel(self.mw.materialsModel)
class ElaWidget(ToolWidget): def __init__(self, image, parent=None): super(ElaWidget, self).__init__(parent) self.quality_spin = QSpinBox() self.quality_spin.setRange(0, 100) self.quality_spin.setSuffix(self.tr(' %')) self.quality_spin.setToolTip(self.tr('JPEG reference quality level')) self.scale_spin = QSpinBox() self.scale_spin.setRange(1, 100) self.scale_spin.setSuffix(' %') self.scale_spin.setToolTip(self.tr('Output multiplicative gain')) self.contrast_spin = QSpinBox() self.contrast_spin.setRange(0, 100) self.contrast_spin.setSuffix(' %') self.contrast_spin.setToolTip(self.tr('Output tonality compression')) self.equalize_check = QCheckBox(self.tr('Equalized')) self.equalize_check.setToolTip(self.tr('Apply histogram equalization')) self.gray_check = QCheckBox(self.tr('Grayscale')) self.gray_check.setToolTip(self.tr('Desaturated output')) default_button = QPushButton(self.tr('Default')) default_button.setToolTip(self.tr('Revert to default parameters')) params_layout = QHBoxLayout() params_layout.addWidget(QLabel(self.tr('Quality:'))) params_layout.addWidget(self.quality_spin) params_layout.addWidget(QLabel(self.tr('Scale:'))) params_layout.addWidget(self.scale_spin) params_layout.addWidget(QLabel(self.tr('Contrast:'))) params_layout.addWidget(self.contrast_spin) params_layout.addWidget(self.equalize_check) params_layout.addWidget(self.gray_check) params_layout.addWidget(default_button) params_layout.addStretch() self.image = image self.original = image.astype(np.float32) / 255 self.viewer = ImageViewer(self.image, self.image) self.default() self.quality_spin.valueChanged.connect(self.process) self.scale_spin.valueChanged.connect(self.process) self.contrast_spin.valueChanged.connect(self.process) self.equalize_check.stateChanged.connect(self.process) self.gray_check.stateChanged.connect(self.process) default_button.clicked.connect(self.default) main_layout = QVBoxLayout() main_layout.addLayout(params_layout) main_layout.addWidget(self.viewer) self.setLayout(main_layout) def process(self): start = time() quality = self.quality_spin.value() scale = self.scale_spin.value() / 20 contrast = int(self.contrast_spin.value() / 100 * 128) equalize = self.equalize_check.isChecked() grayscale = self.gray_check.isChecked() self.scale_spin.setEnabled(not equalize) self.contrast_spin.setEnabled(not equalize) compressed = compress_jpeg(self.image, quality).astype(np.float32) / 255 difference = cv.absdiff(self.original, compressed) if equalize: ela = equalize_img((difference * 255).astype(np.uint8)) else: ela = cv.convertScaleAbs(cv.sqrt(difference) * 255, None, scale) ela = cv.LUT(ela, create_lut(contrast, contrast)) if grayscale: ela = desaturate(ela) self.viewer.update_processed(ela) self.info_message.emit(self.tr('Error Level Analysis = {}'.format(elapsed_time(start)))) def default(self): self.blockSignals(True) self.equalize_check.setChecked(False) self.gray_check.setChecked(False) self.quality_spin.setValue(75) self.scale_spin.setValue(50) self.contrast_spin.setValue(20) self.process() self.blockSignals(False)
class ResultEditDialog(QDialog): def __init__(self, result, is_new=False): super().__init__(GlobalAccess().get_main_window()) assert (isinstance(result, Result)) self.current_object = result self.is_new = is_new self.time_format = 'hh:mm:ss' time_accuracy = race().get_setting('time_accuracy', 0) if time_accuracy: self.time_format = 'hh:mm:ss.zzz' def exec_(self): self.init_ui() self.set_values_from_model() return super().exec_() def init_ui(self): self.setWindowTitle(_('Result')) self.setWindowIcon(QIcon(config.ICON)) self.setSizeGripEnabled(False) self.setModal(True) self.setMaximumWidth(300) self.layout = QFormLayout(self) self.item_created_at = QTimeEdit() self.item_created_at.setDisplayFormat(self.time_format) self.item_created_at.setReadOnly(True) self.item_card_number = QSpinBox() self.item_card_number.setMaximum(9999999) self.item_bib = QSpinBox() self.item_bib.setMaximum(Limit.BIB) self.item_bib.valueChanged.connect(self.show_person_info) self.label_person_info = QLabel('') self.item_days = QSpinBox() self.item_days.setMaximum(365) self.item_finish = QTimeEdit() self.item_finish.setDisplayFormat(self.time_format) self.item_start = QTimeEdit() self.item_start.setDisplayFormat(self.time_format) self.item_result = QLineEdit() self.item_result.setEnabled(False) self.item_credit = QTimeEdit() self.item_credit.setDisplayFormat(self.time_format) self.item_penalty = QTimeEdit() self.item_penalty.setDisplayFormat(self.time_format) self.item_penalty_laps = QSpinBox() self.item_penalty_laps.setMaximum(1000000) self.item_status = QComboBox() self.item_status.addItems(ResultStatus.get_titles()) self.item_status_comment = AdvComboBox() self.item_status_comment.setMaximumWidth(300) self.item_status_comment.view().setMinimumWidth(600) self.item_status_comment.addItems(StatusComments().get_all()) for i, k in enumerate(StatusComments().get_all()): self.item_status_comment.setItemData(i, k, Qt.ToolTipRole) more24 = race().get_setting('time_format_24', 'less24') == 'more24' self.splits = SplitsText(more24=more24) self.layout.addRow(QLabel(_('Created at')), self.item_created_at) if self.current_object.is_punch(): self.layout.addRow(QLabel(_('Card')), self.item_card_number) self.layout.addRow(QLabel(_('Bib')), self.item_bib) self.layout.addRow(QLabel(''), self.label_person_info) if more24: self.layout.addRow(QLabel(_('Days')), self.item_days) self.layout.addRow(QLabel(_('Start')), self.item_start) self.layout.addRow(QLabel(_('Finish')), self.item_finish) self.layout.addRow(QLabel(_('Credit')), self.item_credit) self.layout.addRow(QLabel(_('Penalty')), self.item_penalty) self.layout.addRow(QLabel(_('Penalty legs')), self.item_penalty_laps) self.layout.addRow(QLabel(_('Result')), self.item_result) self.layout.addRow(QLabel(_('Status')), self.item_status) self.layout.addRow(QLabel(_('Comment')), self.item_status_comment) if self.current_object.is_punch(): start_source = race().get_setting('system_start_source', 'protocol') finish_source = race().get_setting('system_finish_source', 'station') if start_source == 'protocol' or start_source == 'cp': self.item_start.setDisabled(True) if finish_source == 'cp': self.item_finish.setDisabled(True) self.layout.addRow(self.splits.widget) def cancel_changes(): self.close() def apply_changes(): try: self.apply_changes_impl() except Exception as e: logging.error(str(e)) self.close() button_box = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel) self.button_ok = button_box.button(QDialogButtonBox.Ok) self.button_ok.setText(_('OK')) self.button_ok.clicked.connect(apply_changes) self.button_cancel = button_box.button(QDialogButtonBox.Cancel) self.button_cancel.setText(_('Cancel')) self.button_cancel.clicked.connect(cancel_changes) if self.current_object.person: button_person = button_box.addButton(_('Entry properties'), QDialogButtonBox.ActionRole) button_person.clicked.connect(self.open_person) self.layout.addRow(button_box) self.show() self.item_bib.setFocus() def show_person_info(self): bib = self.item_bib.value() self.label_person_info.setText('') if bib: person = find(race().persons, bib=bib) if person: info = person.full_name if person.group: info = '{}\n{}: {}'.format(info, _('Group'), person.group.name) if person.card_number: info = '{}\n{}: {}'.format(info, _('Card'), person.card_number) self.label_person_info.setText(info) else: self.label_person_info.setText(_('not found')) def set_values_from_model(self): if self.current_object.is_punch(): if self.current_object.card_number: self.item_card_number.setValue(int(self.current_object.card_number)) self.splits.splits(self.current_object.splits) self.splits.show() if self.current_object.created_at: self.item_created_at.setTime(time_to_qtime(datetime.fromtimestamp(self.current_object.created_at))) if self.current_object.finish_time: self.item_finish.setTime(time_to_qtime(self.current_object.finish_time)) if self.current_object.start_time is not None: self.item_start.setTime(time_to_qtime(self.current_object.start_time)) if self.current_object.finish_time: self.item_result.setText(str(self.current_object.get_result())) if self.current_object.credit_time is not None: self.item_credit.setTime(time_to_qtime(self.current_object.credit_time)) if self.current_object.penalty_time is not None: self.item_penalty.setTime(time_to_qtime(self.current_object.penalty_time)) if self.current_object.penalty_laps: self.item_penalty_laps.setValue(self.current_object.penalty_laps) self.item_bib.setValue(self.current_object.get_bib()) self.item_days.setValue(self.current_object.days) self.item_status.setCurrentText(self.current_object.status.get_title()) self.item_status_comment.setCurrentText(self.current_object.status_comment) self.item_bib.selectAll() def open_person(self): try: PersonEditDialog(self.current_object.person).exec_() except Exception as e: logging.error(str(e)) def apply_changes_impl(self): result = self.current_object if self.is_new: race().results.insert(0, result) if result.is_punch(): if result.card_number != self.item_card_number.value(): result.card_number = self.item_card_number.value() new_splits = self.splits.splits() if len(result.splits) == len(new_splits): for i, split in enumerate(result.splits): if split != new_splits[i]: break result.splits = new_splits time_ = time_to_otime(self.item_finish.time()) if result.finish_time != time_: result.finish_time = time_ time_ = time_to_otime(self.item_start.time()) if result.start_time != time_: result.start_time = time_ time_ = time_to_otime(self.item_credit.time()) if result.credit_time != time_: result.credit_time = time_ time_ = time_to_otime(self.item_penalty.time()) if result.penalty_time != time_: result.penalty_time = time_ if result.penalty_laps != self.item_penalty_laps.value(): result.penalty_laps = self.item_penalty_laps.value() cur_bib = -1 new_bib = self.item_bib.value() if result.person: cur_bib = result.person.bib if new_bib == 0: if result.person and result.is_punch(): if result.person.card_number == result.card_number: result.person.card_number = 0 result.person = None elif cur_bib != new_bib: new_person = find(race().persons, bib=new_bib) if new_person is not None: assert isinstance(new_person, Person) if result.person: if result.is_punch(): result.person.card_number = 0 result.person = new_person if result.is_punch(): race().person_card_number(result.person, result.card_number) result.bib = new_bib GlobalAccess().get_main_window().get_result_table().model().init_cache() if self.item_days.value() != result.days: result.days = self.item_days.value() result.status = ResultStatus.get_by_name(self.item_status.currentText()) status = StatusComments().remove_hint(self.item_status_comment.currentText()) if result.status_comment != status: result.status_comment = status if result.is_punch(): result.clear() try: ResultChecker.checking(result) ResultChecker.calculate_penalty(result) if result.person and result.person.group: GroupSplits(race(), result.person.group).generate(True) except ResultCheckerException as e: logging.error(str(e)) ResultCalculation(race()).process_results() Teamwork().send(result.to_dict())
class WaveletWidget(ToolWidget): def __init__(self, image, parent=None): super(WaveletWidget, self).__init__(parent) self.family_combo = QComboBox() self.family_combo.addItems([ self.tr("Daubechies"), self.tr("Symlets"), self.tr("Coiflets"), self.tr("Biorthogonal") ]) self.wavelet_combo = QComboBox() self.wavelet_combo.setMinimumWidth(70) self.threshold_spin = QSpinBox() self.threshold_spin.setRange(0, 100) self.threshold_spin.setSuffix("%") self.mode_combo = QComboBox() self.mode_combo.addItems([ self.tr("Soft"), self.tr("Hard"), self.tr("Garrote"), self.tr("Greater"), self.tr("Less") ]) self.level_spin = QSpinBox() self.image = image self.coeffs = None self.viewer = ImageViewer(self.image, self.image) self.update_wavelet() self.family_combo.activated.connect(self.update_wavelet) self.wavelet_combo.activated.connect(self.update_level) self.threshold_spin.valueChanged.connect(self.compute_idwt) self.mode_combo.activated.connect(self.compute_idwt) self.level_spin.valueChanged.connect(self.compute_idwt) top_layout = QHBoxLayout() top_layout.addWidget(QLabel(self.tr("Family:"))) top_layout.addWidget(self.family_combo) top_layout.addWidget(QLabel(self.tr("Wavelet:"))) top_layout.addWidget(self.wavelet_combo) top_layout.addWidget(QLabel(self.tr("Threshold:"))) top_layout.addWidget(self.threshold_spin) top_layout.addWidget(QLabel(self.tr("Mode:"))) top_layout.addWidget(self.mode_combo) top_layout.addWidget(QLabel(self.tr("Level:"))) top_layout.addWidget(self.level_spin) top_layout.addStretch() main_layout = QVBoxLayout() main_layout.addLayout(top_layout) main_layout.addWidget(self.viewer) self.setLayout(main_layout) def update_wavelet(self): self.wavelet_combo.clear() family = self.family_combo.currentIndex() if family == 0: self.wavelet_combo.addItems([f"db{i}" for i in range(1, 21)]) elif family == 1: self.wavelet_combo.addItems([f"sym{i}" for i in range(2, 21)]) elif family == 2: self.wavelet_combo.addItems([f"coif{i}" for i in range(1, 6)]) else: types = [ "1.1", "1.3", "1.5", "2.2", "2.4", "2.6", "2.8", "3.1", "3.3", "3.5", "3.7", "3.9", "4.4", "5.5", "6.8", ] self.wavelet_combo.addItems([f"bior{t}" for t in types]) self.update_level() def update_level(self): wavelet = self.wavelet_combo.currentText() max_level = pywt.dwtn_max_level(self.image.shape[:-1], wavelet) self.level_spin.blockSignals(True) self.level_spin.setRange(1, max_level) self.level_spin.setValue(max_level // 2) self.level_spin.blockSignals(False) self.compute_dwt() def compute_dwt(self): wavelet = self.wavelet_combo.currentText() self.coeffs = pywt.wavedec2(self.image[:, :, 0], wavelet) self.compute_idwt() def compute_idwt(self): thr = self.threshold_spin.value() if thr > 0: level = self.level_spin.value() coeffs = deepcopy(self.coeffs) threshold = self.threshold_spin.value() / 100 mode = self.mode_combo.currentText().lower() for i in range(1, level + 1): octave = [None] * 3 for j in range(3): plane = coeffs[-i][j] t = threshold * np.max(np.abs(plane)) octave[j] = pywt.threshold(plane, t, mode) coeffs[-i] = tuple(octave) else: coeffs = self.coeffs wavelet = self.wavelet_combo.currentText() image = cv.cvtColor( pywt.waverec2(coeffs, wavelet).astype(np.uint8), cv.COLOR_GRAY2BGR) self.viewer.update_processed(image)
class GradientWidget(ToolWidget): def __init__(self, image, parent=None): super(GradientWidget, self).__init__(parent) self.intensity_spin = QSpinBox() self.intensity_spin.setRange(0, 100) self.intensity_spin.setValue(95) self.intensity_spin.setSuffix(self.tr(' %')) self.intensity_spin.setToolTip(self.tr('Tonality compression amount')) self.blue_combo = QComboBox() self.blue_combo.addItems([self.tr('None'), self.tr('Flat'), self.tr('Abs'), self.tr('Norm')]) self.blue_combo.setCurrentIndex(2) self.blue_combo.setToolTip(self.tr('Blue component inclusion mode')) self.invert_check = QCheckBox(self.tr('Invert')) self.invert_check.setToolTip(self.tr('Reverse lighting direction')) self.equalize_check = QCheckBox(self.tr('Equalize')) self.equalize_check.setToolTip(self.tr('Apply histogram equalization')) self.image = image self.viewer = ImageViewer(self.image, self.image) self.dx, self.dy = cv.spatialGradient(cv.cvtColor(self.image, cv.COLOR_BGR2GRAY)) self.process() self.intensity_spin.valueChanged.connect(self.process) self.blue_combo.currentIndexChanged.connect(self.process) self.invert_check.stateChanged.connect(self.process) self.equalize_check.stateChanged.connect(self.process) top_layout = QHBoxLayout() top_layout.addWidget(QLabel(self.tr('Intensity:'))) top_layout.addWidget(self.intensity_spin) top_layout.addWidget(QLabel(self.tr('Blue channel:'))) top_layout.addWidget(self.blue_combo) top_layout.addWidget(self.invert_check) top_layout.addWidget(self.equalize_check) top_layout.addStretch() main_layout = QVBoxLayout() main_layout.addLayout(top_layout) main_layout.addWidget(self.viewer) self.setLayout(main_layout) def process(self): start = time() intensity = int(self.intensity_spin.value() / 100 * 127) invert = self.invert_check.isChecked() equalize = self.equalize_check.isChecked() self.intensity_spin.setEnabled(not equalize) blue_mode = self.blue_combo.currentIndex() if invert: dx = (-self.dx).astype(np.float32) dy = (-self.dy).astype(np.float32) else: dx = (+self.dx).astype(np.float32) dy = (+self.dy).astype(np.float32) dx_abs = np.abs(dx) dy_abs = np.abs(dy) red = ((dx / np.max(dx_abs) * 127) + 127).astype(np.uint8) green = ((dy / np.max(dy_abs) * 127) + 127).astype(np.uint8) if blue_mode == 0: blue = np.zeros_like(red) elif blue_mode == 1: blue = np.full_like(red, 255) elif blue_mode == 2: blue = norm_mat(dx_abs + dy_abs) elif blue_mode == 3: blue = norm_mat(np.linalg.norm(cv.merge((red, green)), axis=2)) else: blue = None gradient = cv.merge([blue, green, red]) if equalize: gradient = equalize_img(gradient) elif intensity > 0: gradient = cv.LUT(gradient, create_lut(intensity, intensity)) self.viewer.update_processed(gradient) self.info_message.emit(self.tr('Luminance Gradient = {}'.format(elapsed_time(start))))
class GradientWidget(ToolWidget): def __init__(self, image, parent=None): super(GradientWidget, self).__init__(parent) self.levels_spin = QSpinBox() self.levels_spin.setRange(-1, 16) self.levels_spin.setSpecialValueText(self.tr('Auto')) self.levels_spin.setValue(-1) self.invert_check = QCheckBox(self.tr('Invert')) self.abs_check = QCheckBox(self.tr('Absolute')) self.grad_viewer = ImageViewer(image, image) self.image = image self.process() self.levels_spin.valueChanged.connect(self.process) self.invert_check.toggled.connect(self.process) self.abs_check.toggled.connect(self.process) top_layout = QHBoxLayout() top_layout.addWidget(QLabel(self.tr('Levels:'))) top_layout.addWidget(self.levels_spin) top_layout.addWidget(self.invert_check) top_layout.addWidget(self.abs_check) top_layout.addStretch() main_layout = QVBoxLayout() main_layout.addLayout(top_layout) main_layout.addWidget(self.grad_viewer) self.setLayout(main_layout) def process(self): intensity = self.levels_spin.value() invert = self.invert_check.isChecked() absolute = self.abs_check.isChecked() self.levels_spin.setEnabled(not absolute) self.invert_check.setEnabled(not absolute) gray = cv.cvtColor(self.image, cv.COLOR_BGR2GRAY) diff_x = cv.Scharr(gray, cv.CV_32F, 1, 0) diff_y = cv.Scharr(gray, cv.CV_32F, 0, 1) diff_z = cv.normalize(np.abs(diff_x + diff_y), None, 0, 255, cv.NORM_MINMAX) diff_z = cv.LUT(diff_z.astype(np.uint8), create_lut(0, 90)) grad_x = +diff_x if invert else -diff_x grad_y = +diff_y if invert else -diff_y grad_z = diff_z if not absolute: min_x, max_x, _, _ = cv.minMaxLoc(grad_x) lim_x = max(abs(min_x), abs(max_x)) grad_x = (grad_x / lim_x + 1) * 127 min_y, max_y, _, _ = cv.minMaxLoc(grad_y) lim_y = max(abs(min_y), abs(max_y)) grad_y = (grad_y / lim_y + 1) * 127 else: grad_x = cv.normalize(np.abs(grad_x), None, 0, 255, cv.NORM_MINMAX) grad_y = cv.normalize(np.abs(grad_y), None, 0, 255, cv.NORM_MINMAX) grad_x = grad_x.astype(np.uint8) grad_y = grad_y.astype(np.uint8) if intensity >= 0 and not absolute: max_intensity = self.levels_spin.maximum() low = 127 - (max_intensity - intensity) high = 127 + (max_intensity - intensity) lut_xy = create_lut(low, high) grad_x = cv.LUT(grad_x, lut_xy) grad_y = cv.LUT(grad_y, lut_xy) else: grad_x = cv.equalizeHist(grad_x) grad_y = cv.equalizeHist(grad_y) gradient = np.stack((grad_z, grad_x, grad_y), axis=2) self.grad_viewer.update_processed(gradient)
class App(QMainWindow): def __init__(self): super().__init__() self.init_ui() self.attach_event() self.setAcceptDrops(True) def init_ui(self): # Define & Configure Components normal_button_size = QSize(80, 24) icon_button_size = QSize(24, 24) icon_size = QSize(18, 18) self.central_widget = QWidget() self.central_layout = QGridLayout() self.central_widget.setLayout(self.central_layout) self.tab_group_widget = QTabWidget() self.tab_group_widget.setMinimumSize(400, 0) self.tab_group_widget.setFixedHeight(150) self.tab1_name = '스폰서 변환' self.tab2_name = '싱크 조절(초)' self.tab3_name = '싱크 조절(%)' self.tab_page_1 = QWidget() self.tab_grid_1 = QGridLayout() self.tab1_search_label = QLabel('검색 텍스트') self.tab1_search = QLineEdit() self.tab1_sponsor = QWidget() self.tab1_sponsor_layout = QHBoxLayout() self.tab1_sponsor_layout.setContentsMargins(0, 0, 0, 0) self.tab1_sponsor_label = QLabel('스폰서 영상 길이') self.tab1_sponsor_value = QDoubleSpinBox() self.tab1_sponsor_value.setFixedWidth(60) self.tab1_sponsor_value.setMinimum(-1000000000) self.tab1_sponsor_value.setValue(10) self.tab1_offset = QWidget() self.tab1_offset_layout = QHBoxLayout() self.tab1_offset_layout.setContentsMargins(0, 0, 0, 0) self.tab1_offset_label = QLabel('라인 오프셋') self.tab1_offset_value = QSpinBox() self.tab1_offset_value.setMinimum(-1000000000) self.tab1_offset_value.setValue(2) self.tab1_offset_value.setFixedWidth(50) self.tab1_ignore = QWidget() self.tab1_ignore_layout = QHBoxLayout() self.tab1_ignore_layout.setContentsMargins(0, 0, 0, 0) self.tab1_ignore_label1 = QLabel('시작부터') self.tab1_ignore_value = QSpinBox() self.tab1_ignore_value.setFixedWidth(50) self.tab1_ignore_value.setValue(5) self.tab1_ignore_label2 = QLabel('줄 ') self.tab1_ignore_sec = QSpinBox() self.tab1_ignore_sec.setFixedWidth(60) self.tab1_ignore_sec.setMaximum(1000) self.tab1_ignore_sec.setValue(90) self.tab1_ignore_label3 = QLabel('초 무시하기') self.tab1_add_button = QPushButton('추가하기') self.tab_page_2 = QWidget() self.tab_grid_2 = QGridLayout() self.tab2_shift = QWidget() self.tab2_shift_layout = QHBoxLayout() self.tab2_shift_layout.setContentsMargins(0, 0, 0, 0) self.tab2_shift_label1 = QLabel('자막 싱크') self.tab2_shift_value = QDoubleSpinBox() self.tab2_shift_value.setFixedWidth(60) self.tab2_shift_label2 = QLabel('초 ') self.tab2_slow_radio = QRadioButton('느리게') self.tab2_slow_radio.setChecked(True) self.tab2_fast_radio = QRadioButton('빠르게') self.tab2_add_button = QPushButton('추가하기') self.tab_page_3 = QWidget() self.tab_grid_3 = QGridLayout() self.tab3_speed_label1 = QLabel('자막 싱크') self.tab3_speed_value = QSpinBox() self.tab3_speed_value.setFixedWidth(70) self.tab3_speed_value.setRange(1, 1000) self.tab3_speed_value.setValue(100) self.tab3_speed_label2 = QLabel('%') self.tab3_add_button = QPushButton('추가하기') self.que_label = QLabel('작업 목록') self.que_label.setFixedHeight(24) self.que_widget = QWidget() self.que_widget.setFixedHeight(114) self.que_layout = QGridLayout() self.que_layout.setContentsMargins(0, 0, 0, 0) self.que_list = QTreeWidget() self.que_list.setHeaderLabels(['작업', '옵션']) self.que_delete_button = QPushButton(QIcon(':/remove.png'), '') self.que_delete_button.setFixedSize(icon_button_size) self.que_delete_button.setIconSize(icon_size) self.que_delete_button.setToolTip('목록 삭제') self.que_up_button = QPushButton(QIcon(':/up.png'), '') self.que_up_button.setIconSize(icon_size) self.que_up_button.setFixedSize(icon_button_size) self.que_up_button.setToolTip('위로') self.que_down_button = QPushButton(QIcon(':/down.png'), '') self.que_down_button.setIconSize(icon_size) self.que_down_button.setFixedSize(icon_button_size) self.que_down_button.setToolTip('아래로') self.que_clear_button = QPushButton(QIcon(':/clear.png'), '') self.que_clear_button.setIconSize(icon_size) self.que_clear_button.setFixedSize(icon_button_size) self.que_clear_button.setToolTip('비우기') self.file_label = QLabel('파일 목록') self.file_label.setFixedHeight(24) self.file_widget = QWidget() self.file_layout = QGridLayout() self.file_layout.setContentsMargins(0, 0, 0, 0) self.file_list = QTreeWidget() self.file_list.setAcceptDrops(True) self.file_list.setHeaderLabels(['이름', '경로']) self.file_file_open = QPushButton(QIcon(':/file.png'), '') self.file_file_open.setFixedSize(icon_button_size) self.file_file_open.setIconSize(icon_size) self.file_file_open.setToolTip('파일 열기') self.file_dir_open = QPushButton(QIcon(':/folder.png'), '') self.file_dir_open.setFixedSize(icon_button_size) self.file_dir_open.setIconSize(icon_size) self.file_dir_open.setToolTip('폴더 열기') self.file_delete = QPushButton(QIcon(':/remove.png'), '') self.file_delete.setFixedSize(icon_button_size) self.file_delete.setIconSize(icon_size) self.file_delete.setToolTip('목록 삭제') self.file_clear = QPushButton(QIcon(':/clear.png'), '') self.file_clear.setFixedSize(icon_button_size) self.file_clear.setIconSize(icon_size) self.file_clear.setToolTip('비우기') self.file_encode = QPushButton(QIcon(':/encode.png'), '') self.file_encode.setFixedSize(icon_button_size) self.file_encode.setIconSize(icon_size) self.file_encode.setToolTip('인코딩 설정') self.save_widget = QGroupBox('저장 옵션') self.save_widget.setMinimumSize(400, 0) self.save_widget.setFixedHeight(82) self.save_layout = QGridLayout() self.save_orig_radio = QRadioButton('원본 위치에 저장') self.save_orig_radio.setChecked(True) self.save_strip = QCheckBox('싱크 꼬임 무시') self.save_strip.setToolTip('싱크 꼬임을 무시하고 모든 자막을 보존합니다.') self.save_dir_radio = QRadioButton('다른 위치에 저장') self.save_dir_line = QLineEdit() self.save_dir_find = QPushButton('...') self.save_dir_find.setFixedWidth(40) self.ok_button = QPushButton('적용') self.ok_button.setFixedSize(normal_button_size) self.cancel_button = QPushButton('취소') self.cancel_button.setFixedSize(normal_button_size) # Display GUI Components self.central_layout.addWidget(self.tab_group_widget, 0, 0, 1, 3) self.central_layout.addWidget(self.que_label, 1, 0, 1, 3) self.central_layout.addWidget(self.que_widget, 2, 0, 1, 3) self.central_layout.addWidget(self.file_label, 3, 0, 1, 3) self.central_layout.addWidget(self.file_widget, 4, 0, 1, 3) self.central_layout.addWidget(self.save_widget, 5, 0, 1, 3) self.central_layout.addWidget(self.ok_button, 6, 1, 1, 1) self.central_layout.addWidget(self.cancel_button, 6, 2, 1, 1) self.tab_group_widget.addTab(self.tab_page_1, QIcon(), self.tab1_name) self.tab_group_widget.addTab(self.tab_page_2, QIcon(), self.tab2_name) self.tab_group_widget.addTab(self.tab_page_3, QIcon(), self.tab3_name) self.tab_page_1.setLayout(self.tab_grid_1) self.tab_grid_1.addWidget(self.tab1_search_label, 0, 0, 1, 1) self.tab_grid_1.addWidget(self.tab1_search, 0, 1, 1, 2) self.tab_grid_1.addWidget(self.tab1_sponsor, 1, 1, 1, 1) self.tab_grid_1.addWidget(self.tab1_offset, 1, 2, 1, 1) self.tab_grid_1.addWidget(self.tab1_ignore, 2, 1, 1, 2) self.tab_grid_1.addWidget(self.tab1_add_button, 3, 0, 1, 3) self.tab1_sponsor.setLayout(self.tab1_sponsor_layout) self.tab1_sponsor_layout.addWidget(self.tab1_sponsor_label) self.tab1_sponsor_layout.addWidget(self.tab1_sponsor_value) self.tab1_sponsor_layout.addStretch(1) self.tab1_offset.setLayout(self.tab1_offset_layout) self.tab1_offset_layout.addWidget(self.tab1_offset_label) self.tab1_offset_layout.addWidget(self.tab1_offset_value) self.tab1_offset_layout.addStretch(1) self.tab1_ignore.setLayout(self.tab1_ignore_layout) self.tab1_ignore_layout.addWidget(self.tab1_ignore_label1) self.tab1_ignore_layout.addWidget(self.tab1_ignore_value) self.tab1_ignore_layout.addWidget(self.tab1_ignore_label2) self.tab1_ignore_layout.addWidget(self.tab1_ignore_sec) self.tab1_ignore_layout.addWidget(self.tab1_ignore_label3) self.tab1_ignore_layout.addStretch(1) self.tab_page_2.setLayout(self.tab_grid_2) self.tab_grid_2.setRowStretch(0, 1) self.tab_grid_2.addWidget(self.tab2_shift, 1, 0, 2, 1) self.tab_grid_2.addWidget(self.tab2_slow_radio, 1, 1, 1, 1) self.tab_grid_2.addWidget(self.tab2_fast_radio, 2, 1, 1, 1) self.tab_grid_2.setColumnStretch(2, 1) self.tab_grid_2.setRowStretch(3, 1) self.tab_grid_2.addWidget(self.tab2_add_button, 4, 0, 1, 3) self.tab2_shift.setLayout(self.tab2_shift_layout) self.tab2_shift_layout.addWidget(self.tab2_shift_label1) self.tab2_shift_layout.addWidget(self.tab2_shift_value) self.tab2_shift_layout.addWidget(self.tab2_shift_label2) self.tab_page_3.setLayout(self.tab_grid_3) self.tab_grid_3.setRowStretch(0, 1) self.tab_grid_3.addWidget(self.tab3_speed_label1, 1, 0, 1, 1) self.tab_grid_3.addWidget(self.tab3_speed_value, 1, 1, 1, 1) self.tab_grid_3.addWidget(self.tab3_speed_label2, 1, 2, 1, 1) self.tab_grid_3.setColumnStretch(3, 1) self.tab_grid_3.setRowStretch(2, 1) self.tab_grid_3.addWidget(self.tab3_add_button, 3, 0, 1, 4) self.que_widget.setLayout(self.que_layout) self.que_layout.addWidget(self.que_list, 0, 0, 4, 1) self.que_layout.addWidget(self.que_delete_button, 0, 1, 1, 1) self.que_layout.addWidget(self.que_up_button, 1, 1, 1, 1) self.que_layout.addWidget(self.que_down_button, 2, 1, 1, 1) self.que_layout.addWidget(self.que_clear_button, 3, 1, 1, 1) self.file_widget.setLayout(self.file_layout) self.file_layout.addWidget(self.file_list, 0, 0, 6, 1) self.file_layout.addWidget(self.file_file_open, 0, 1, 1, 1) self.file_layout.addWidget(self.file_dir_open, 1, 1, 1, 1) self.file_layout.addWidget(self.file_delete, 2, 1, 1, 1) self.file_layout.addWidget(self.file_clear, 3, 1, 1, 1) self.file_layout.addWidget(self.file_encode, 5, 1, 1, 1) self.save_widget.setLayout(self.save_layout) self.save_layout.addWidget(self.save_orig_radio, 0, 0, 1, 1) self.save_layout.setColumnStretch(1, 1) self.save_layout.addWidget(self.save_strip, 0, 2, 1, 2) self.save_layout.addWidget(self.save_dir_radio, 1, 0, 1, 1) self.save_layout.addWidget(self.save_dir_line, 1, 1, 1, 2) self.save_layout.addWidget(self.save_dir_find, 1, 3, 1, 1) self.setWindowTitle('Batch SAMI Sync v0.2') self.setCentralWidget(self.central_widget) self.adjustSize() def attach_event(self): # Default encoding hack self.encoding = '자동' # Define and Connect event handlers def tab1_add(): sponsor_text = self.tab1_search.text() sponsor_time = self.tab1_sponsor_value.value() line_offset = self.tab1_offset_value.value() line_ignore = self.tab1_ignore_value.value() time_ignore = self.tab1_ignore_sec.value() data = [1, sponsor_time, sponsor_text, line_offset, line_ignore, time_ignore] item = QTreeWidgetItem(self.que_list, [self.tab1_name, '스폰서 영상 시간 : ' + str(sponsor_time) + '초, 오프셋 : ' + str(line_offset) + '줄, 시작부터 ' + str(line_ignore) + '번째 줄, ' + str(time_ignore) + '초 무시 - 검색어 : ' + sponsor_text]) item.setData(2, 2, data) def tab2_add(): shift_time = self.tab2_shift_value.value() shift_direction = self.tab2_fast_radio.isChecked() direction_text = '빠르게' if shift_direction else '느리게' data = [2, shift_time, shift_direction] item = QTreeWidgetItem(self.que_list, [self.tab2_name, '자막 싱크 ' + str(shift_time) + '초 ' + direction_text]) item.setData(2, 2, data) def tab3_add(): speed_rate = self.tab3_speed_value.value() data = [3, speed_rate] item = QTreeWidgetItem(self.que_list, [self.tab3_name, '자막 속도 ' + str(speed_rate) + '%']) item.setData(2, 2, data) def file_open(): selected = QFileDialog.getOpenFileNames(self, "자막 파일 선택", "", "SAMI Files (*.smi);;All Files (*)") for file in selected[0]: name = ntpath.basename(file) Utils.insert_list(self.file_list, name, file) def dir_open(): selected = QFileDialog.getExistingDirectory(self, "자막 폴더 선택") for paths, subdirs, files in os.walk(selected): for file in files: if fnmatch(file, '*.smi'): name = ntpath.basename(file) Utils.insert_list(self.file_list, name, file) def open_encode_dialog(): self.dialog = QInputDialog(self) self.dialog.setWindowTitle('인코딩 설정') self.dialog.setLabelText('텍스트 인코딩 설정') self.dialog.setComboBoxItems(['자동', 'EUC-KR', 'UTF-8', 'UTF-16LE', 'UTF-16BE', '직접 입력']) self.dialog.show() self.dialog.textValueChanged.connect(type_encode) self.dialog.textValueSelected.connect(set_encode) def type_encode(text): if text == '직접 입력': self.dialog.setComboBoxItems([]) self.dialog.setComboBoxEditable(True) def set_encode(text): self.encoding = text def save_dir(): selected = QFileDialog.getExistingDirectory(self, "저장 위치 선택") self.save_dir_line.setText(selected) def apply(): self.ok_button.setEnabled(False) ques = Utils.read_list(self.que_list, False) files = Utils.read_list(self.file_list, False) strip = False if self.save_strip.isChecked() else True log = [] for file in files: try: text = Utils.launch_que(file[1], ques, self.encoding, strip) if len(text): if self.save_orig_radio.isChecked(): savepath = file[1] else: savepath = self.save_dir_line.text() + '/' + file[0] Utils.save_file(savepath, text) except Exception as e: log.append(file[0] + ' 처리 오류 : ' + str(e)) if log: ScrollMessageBox(QMessageBox.Warning, 'Batch SAMI Sync', "\n".join(log)) else: QMessageBox.information(self, 'Batch SAMI Sync', '변환 완료!') self.ok_button.setEnabled(True) self.tab1_add_button.clicked.connect(tab1_add) self.tab2_add_button.clicked.connect(tab2_add) self.tab3_add_button.clicked.connect(tab3_add) self.que_delete_button.clicked.connect(lambda: Utils.delete_list(self.que_list)) self.que_clear_button.clicked.connect(lambda: Utils.clear_list(self.que_list)) self.que_up_button.clicked.connect(lambda: Utils.up_list(self.que_list)) self.que_down_button.clicked.connect(lambda: Utils.down_list(self.que_list)) self.file_file_open.clicked.connect(file_open) self.file_dir_open.clicked.connect(dir_open) self.file_delete.clicked.connect(lambda: Utils.delete_list(self.file_list)) self.file_clear.clicked.connect(lambda: Utils.clear_list(self.file_list)) self.file_encode.clicked.connect(open_encode_dialog) self.save_dir_find.clicked.connect(save_dir) self.ok_button.clicked.connect(apply) self.cancel_button.clicked.connect(sys.exit) def dragEnterEvent(self, event): if event.mimeData().hasUrls: event.accept() else: event.ignore() def dragMoveEvent(self, event): if event.mimeData().hasUrls(): event.setDropAction(Qt.CopyAction) event.accept() else: event.ignore() def dropEvent(self, event): if event.mimeData().hasUrls(): event.setDropAction(Qt.CopyAction) event.accept() for url in event.mimeData().urls(): if url.isLocalFile(): file = str(url.toLocalFile()) if fnmatch(file, '*.smi'): name = ntpath.basename(file) Utils.insert_list(self.file_list, name, file) elif not fnmatch(file, '*.*'): for paths, subdirs, files in os.walk(file): for file in files: if fnmatch(file, '*.smi'): name = ntpath.basename(file) Utils.insert_list(self.file_list, name, file) else: event.ignore()
class GradientWidget(ToolWidget): def __init__(self, image, parent=None): super(GradientWidget, self).__init__(parent) self.intensity_spin = QSpinBox() self.intensity_spin.setRange(0, 127) self.intensity_spin.setValue(90) self.blue_combo = QComboBox() self.blue_combo.addItems( [self.tr('None'), self.tr('Flat'), self.tr('Norm')]) self.invert_check = QCheckBox(self.tr('Invert')) self.equalize_check = QCheckBox(self.tr('Equalize')) self.grad_viewer = ImageViewer(image, image) self.image = image self.process() self.intensity_spin.valueChanged.connect(self.process) self.blue_combo.currentIndexChanged.connect(self.process) self.invert_check.stateChanged.connect(self.process) self.equalize_check.stateChanged.connect(self.process) top_layout = QHBoxLayout() top_layout.addWidget(QLabel(self.tr('Intensity:'))) top_layout.addWidget(self.intensity_spin) top_layout.addWidget(QLabel(self.tr('Blue channel:'))) top_layout.addWidget(self.blue_combo) top_layout.addWidget(self.invert_check) top_layout.addWidget(self.equalize_check) top_layout.addStretch() main_layout = QVBoxLayout() main_layout.addLayout(top_layout) main_layout.addWidget(self.grad_viewer) self.setLayout(main_layout) def process(self): intensity = self.intensity_spin.value() invert = self.invert_check.isChecked() equalize = self.equalize_check.isChecked() blue_mode = self.blue_combo.currentIndex() dx, dy = cv.spatialGradient(cv.cvtColor(self.image, cv.COLOR_BGR2GRAY)) if invert: dx = -dx dy = -dy red = ((dx.astype(np.float32) / np.max(np.abs(dx)) * 127) + 127).astype(np.uint8) green = ((dy.astype(np.float32) / np.max(np.abs(dy)) * 127) + 127).astype(np.uint8) if blue_mode == 0: blue = np.zeros_like(red) elif blue_mode == 1: blue = np.full_like(red, 255) elif blue_mode == 2: blue = normalize_mat(np.linalg.norm(cv.merge((red, green)), axis=2)) else: blue = None gradient = cv.merge([blue, green, red]) if intensity > 0: gradient = cv.LUT(gradient, create_lut(intensity, intensity)) if equalize: gradient = equalize_image(gradient) self.grad_viewer.update_processed(gradient)
class RandomDatasetGenerator(QDialog): logger = logging.getLogger("root.ui.RandomGeneratorWidget") gui_logger = logging.getLogger("GUI") def __init__(self, parent=None): super().__init__(parent=parent, f=Qt.Window) self.setWindowTitle(self.tr("Dataset Generator")) self.last_n_components = 0 self.components = [] # typing.List[RandomGeneratorComponentWidget] self.component_series = [] self.init_ui() self.target = LOESS self.minimum_size_input.setValue(0.02) self.maximum_size_input.setValue(2000.0) self.n_classes_input.setValue(101) self.precision_input.setValue(4) self.file_dialog = QFileDialog(parent=self) self.update_timer = QTimer() self.update_timer.timeout.connect(lambda: self.update_chart(True)) self.cancel_flag = False def init_ui(self): self.setAttribute(Qt.WA_StyledBackground, True) self.main_layout = QGridLayout(self) # self.main_layout.setContentsMargins(0, 0, 0, 0) self.sampling_group = QGroupBox(self.tr("Sampling")) # self.control_group.setFixedSize(400, 160) self.control_layout = QGridLayout(self.sampling_group) self.minimum_size_label = QLabel(self.tr("Minimum Size [μm]")) self.minimum_size_input = QDoubleSpinBox() self.minimum_size_input.setDecimals(2) self.minimum_size_input.setRange(1e-4, 1e6) self.minimum_size_input.setValue(0.0200) self.maximum_size_label = QLabel(self.tr("Maximum Size [μm]")) self.maximum_size_input = QDoubleSpinBox() self.maximum_size_input.setDecimals(2) self.maximum_size_input.setRange(1e-4, 1e6) self.maximum_size_input.setValue(2000.0000) self.control_layout.addWidget(self.minimum_size_label, 0, 0) self.control_layout.addWidget(self.minimum_size_input, 0, 1) self.control_layout.addWidget(self.maximum_size_label, 0, 2) self.control_layout.addWidget(self.maximum_size_input, 0, 3) self.n_classes_label = QLabel(self.tr("N<sub>classes</sub>")) self.n_classes_input = QSpinBox() self.n_classes_input.setRange(10, 1e4) self.n_classes_input.setValue(101) self.precision_label = QLabel(self.tr("Data Precision")) self.precision_input = QSpinBox() self.precision_input.setRange(2, 8) self.precision_input.setValue(4) self.control_layout.addWidget(self.n_classes_label, 1, 0) self.control_layout.addWidget(self.n_classes_input, 1, 1) self.control_layout.addWidget(self.precision_label, 1, 2) self.control_layout.addWidget(self.precision_input, 1, 3) self.component_number_label = QLabel(self.tr("N<sub>components</sub>")) self.component_number_input = QSpinBox() self.component_number_input.setRange(1, 10) self.component_number_input.valueChanged.connect( self.on_n_components_changed) self.preview_button = QPushButton(qta.icon("mdi.animation-play"), self.tr("Preview")) self.preview_button.clicked.connect(self.on_preview_clicked) self.control_layout.addWidget(self.component_number_label, 2, 0) self.control_layout.addWidget(self.component_number_input, 2, 1) self.control_layout.addWidget(self.preview_button, 2, 2, 1, 2) self.main_layout.addWidget(self.sampling_group, 0, 0) self.save_group = QGroupBox(self.tr("Save")) # self.save_group.setFixedHeight(160) self.save_layout = QGridLayout(self.save_group) self.n_samples_label = QLabel(self.tr("N<sub>samples</sub>")) self.n_samples_input = QSpinBox() self.n_samples_input.setRange(100, 100000) self.save_layout.addWidget(self.n_samples_label, 0, 0) self.save_layout.addWidget(self.n_samples_input, 0, 1) self.cancel_button = QPushButton(qta.icon("mdi.cancel"), self.tr("Cancel")) self.cancel_button.setEnabled(False) self.cancel_button.clicked.connect(self.on_cancel_clicked) self.generate_button = QPushButton(qta.icon("mdi.cube-send"), self.tr("Generate")) self.generate_button.clicked.connect(self.on_generate_clicked) self.progress_bar = QProgressBar() self.progress_bar.setRange(0, 100) self.progress_bar.setOrientation(Qt.Horizontal) self.progress_bar.setAlignment(Qt.AlignLeft | Qt.AlignVCenter) self.save_layout.addWidget(self.cancel_button, 1, 0) self.save_layout.addWidget(self.generate_button, 1, 1) self.save_layout.addWidget(self.progress_bar, 2, 0, 1, 2) self.main_layout.addWidget(self.save_group, 0, 1) self.param_group = QGroupBox("Random Parameter") # self.param_group.setFixedWidth(400) self.param_layout = QGridLayout(self.param_group) self.main_layout.addWidget(self.param_group, 1, 0) self.preview_group = QGroupBox(self.tr("Preview")) self.chart_layout = QGridLayout(self.preview_group) self.chart = MixedDistributionChart(parent=self, toolbar=False) self.chart_layout.addWidget(self.chart, 0, 0) self.chart.setSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.MinimumExpanding) self.main_layout.addWidget(self.preview_group, 1, 1) @staticmethod def to_points(x, y): return [QPointF(x_value, y_value) for x_value, y_value in zip(x, y)] def on_n_components_changed(self, n_components: int): if self.last_n_components < n_components: for component_index in range(self.last_n_components, n_components): component = RandomGeneratorComponentWidget( name=f"AC{component_index+1}") component.value_changed.connect(self.on_value_changed) self.param_layout.addWidget(component, component_index + 1, 0) self.components.append(component) if self.last_n_components > n_components: for i in range(n_components, self.last_n_components): before_component = self.components[i] before_component.value_changed.disconnect( self.on_value_changed) self.param_layout.removeWidget(before_component) # if not hide, the widget will still display on screen before_component.hide() self.components.pop(n_components) self.last_n_components = n_components def on_preview_clicked(self): if self.update_timer.isActive(): self.preview_button.setText(self.tr("Preview")) self.update_timer.stop() self.update_chart() else: self.preview_button.setText(self.tr("Stop")) self.update_timer.start(200) def on_cancel_clicked(self): self.cancel_flag = True def on_generate_clicked(self): if self.update_timer.isActive(): self.preview_button.setText(self.tr("Preview")) self.update_timer.stop() self.update_chart() filename, _ = self.file_dialog.getSaveFileName( self, self.tr("Choose a filename to save the generated dataset"), None, "Microsoft Excel (*.xlsx)") if filename is None or filename == "": return n_samples = self.n_samples_input.value() dataset = self.get_random_dataset(n_samples) # generate samples self.cancel_button.setEnabled(True) self.generate_button.setEnabled(False) format_str = self.tr("Generating {0} samples: %p%").format(n_samples) self.progress_bar.setFormat(format_str) self.progress_bar.setValue(0) def cancel(): self.progress_bar.setFormat(self.tr("Task canceled")) self.progress_bar.setValue(0) self.cancel_button.setEnabled(False) self.generate_button.setEnabled(True) self.cancel_flag = False samples = [] for i in range(n_samples): if self.cancel_flag: cancel() return sample = dataset.get_sample(i) samples.append(sample) progress = (i + 1) / n_samples * 50 self.progress_bar.setValue(progress) QCoreApplication.processEvents() # save file to excel file format_str = self.tr("Writing {0} samples to excel file: %p%").format( n_samples) self.progress_bar.setFormat(format_str) self.progress_bar.setValue(50) wb = openpyxl.Workbook() prepare_styles(wb) ws = wb.active ws.title = self.tr("README") description = \ """ This Excel file was generated by QGrain ({0}). Please cite: Liu, Y., Liu, X., Sun, Y., 2021. QGrain: An open-source and easy-to-use software for the comprehensive analysis of grain size distributions. Sedimentary Geology 423, 105980. https://doi.org/10.1016/j.sedgeo.2021.105980 It contanins n_components + 3 sheets: 1. The first sheet is the random settings which were used to generate random parameters. 2. The second sheet is the generated dataset. 3. The third sheet is random parameters which were used to calulate the component distributions and their mixture. 4. The left sheets are the component distributions of all samples. Artificial dataset Using skew normal distribution as the base distribution of each component (i.e. end-member). Skew normal distribution has three parameters, shape, location and scale. Where shape controls the skewness, location and scale are simliar to that of the Normal distribution. When shape = 0, it becomes Normal distribution. The weight parameter controls the fraction of the component, where fraction_i = weight_i / sum(weight_i). By assigning the mean and std of each parameter, random parameters was generate by the `scipy.stats.truncnorm.rvs` function of Scipy. Sampling settings Minimum size [μm]: {1}, Maximum size [μm]: {2}, N_classes: {3}, Precision: {4}, Noise: {5}, N_samples: {6} """.format(QGRAIN_VERSION, self.minimum_size_input.value(), self.maximum_size_input.value(), self.n_classes_input.value(), self.precision_input.value(), self.precision_input.value()+1, n_samples) def write(row, col, value, style="normal_light"): cell = ws.cell(row + 1, col + 1, value=value) cell.style = style lines_of_desc = description.split("\n") for row, line in enumerate(lines_of_desc): write(row, 0, line, style="description") ws.column_dimensions[column_to_char(0)].width = 200 ws = wb.create_sheet(self.tr("Random Settings")) write(0, 0, self.tr("Parameter"), style="header") ws.merge_cells(start_row=1, start_column=1, end_row=2, end_column=1) write(0, 1, self.tr("Shape"), style="header") ws.merge_cells(start_row=1, start_column=2, end_row=1, end_column=3) write(0, 3, self.tr("Location"), style="header") ws.merge_cells(start_row=1, start_column=4, end_row=1, end_column=5) write(0, 5, self.tr("Scale"), style="header") ws.merge_cells(start_row=1, start_column=6, end_row=1, end_column=7) write(0, 7, self.tr("Weight"), style="header") ws.merge_cells(start_row=1, start_column=8, end_row=1, end_column=9) ws.column_dimensions[column_to_char(0)].width = 16 for col in range(1, 9): ws.column_dimensions[column_to_char(col)].width = 16 if col % 2 == 0: write(1, col, self.tr("Mean"), style="header") else: write(1, col, self.tr("STD"), style="header") for row, comp_params in enumerate(self.target, 2): if row % 2 == 1: style = "normal_dark" else: style = "normal_light" write(row, 0, self.tr("Component{0}").format(row - 1), style=style) for i, key in enumerate(["shape", "loc", "scale", "weight"]): mean, std = comp_params[key] write(row, i * 2 + 1, mean, style=style) write(row, i * 2 + 2, std, style=style) ws = wb.create_sheet(self.tr("Dataset")) write(0, 0, self.tr("Sample Name"), style="header") ws.column_dimensions[column_to_char(0)].width = 24 for col, value in enumerate(dataset.classes_μm, 1): write(0, col, value, style="header") ws.column_dimensions[column_to_char(col)].width = 10 for row, sample in enumerate(samples, 1): if row % 2 == 0: style = "normal_dark" else: style = "normal_light" write(row, 0, sample.name, style=style) for col, value in enumerate(sample.distribution, 1): write(row, col, value, style=style) if self.cancel_flag: cancel() return progress = 50 + (row / n_samples) * 10 self.progress_bar.setValue(progress) QCoreApplication.processEvents() ws = wb.create_sheet(self.tr("Parameters")) write(0, 0, self.tr("Sample Name"), style="header") ws.merge_cells(start_row=1, start_column=1, end_row=2, end_column=1) ws.column_dimensions[column_to_char(0)].width = 24 for i in range(dataset.n_components): write(0, 4 * i + 1, self.tr("Component{0}").format(i + 1), style="header") ws.merge_cells(start_row=1, start_column=4 * i + 2, end_row=1, end_column=4 * i + 5) for j, header_name in enumerate([ self.tr("Shape"), self.tr("Location"), self.tr("Scale"), self.tr("Weight") ]): write(1, 4 * i + 1 + j, header_name, style="header") ws.column_dimensions[column_to_char(4 * i + 1 + j)].width = 16 for row, sample in enumerate(samples, 2): if row % 2 == 1: style = "normal_dark" else: style = "normal_light" write(row, 0, sample.name, style=style) for i, comp_param in enumerate(sample.parameter.components): write(row, 4 * i + 1, comp_param.shape, style=style) write(row, 4 * i + 2, comp_param.loc, style=style) write(row, 4 * i + 3, comp_param.scale, style=style) write(row, 4 * i + 4, comp_param.weight, style=style) if self.cancel_flag: cancel() return progress = 60 + (row / n_samples) * 10 self.progress_bar.setValue(progress) QCoreApplication.processEvents() for i in range(dataset.n_components): ws = wb.create_sheet(self.tr("Component{0}").format(i + 1)) write(0, 0, self.tr("Sample Name"), style="header") ws.column_dimensions[column_to_char(0)].width = 24 for col, value in enumerate(dataset.classes_μm, 1): write(0, col, value, style="header") ws.column_dimensions[column_to_char(col)].width = 10 for row, sample in enumerate(samples, 1): if row % 2 == 0: style = "normal_dark" else: style = "normal_light" write(row, 0, sample.name, style=style) for col, value in enumerate(sample.components[i].distribution, 1): write(row, col, value, style=style) if self.cancel_flag: cancel() return progress = 70 + ( (i * n_samples + row) / n_samples * dataset.n_components) * 30 self.progress_bar.setValue(progress) QCoreApplication.processEvents() wb.save(filename) wb.close() self.progress_bar.setValue(100) self.progress_bar.setFormat(self.tr("Task finished")) self.cancel_button.setEnabled(False) self.generate_button.setEnabled(True) @property def target(self): return [comp.target for comp in self.components] @target.setter def target(self, values): if len(values) != len(self.components): self.component_number_input.setValue(len(values)) for comp, comp_target in zip(self.components, values): comp.blockSignals(True) comp.target = comp_target comp.blockSignals(False) self.update_chart() def get_random_sample(self): dataset = self.get_random_dataset(n_samples=1) sample = dataset.get_sample(0) sample.name = self.tr("Artificial Sample") return sample def get_random_mean(self): dataset = self.get_random_dataset(n_samples=1) random_setting = RandomSetting(self.target) sample = dataset.get_sample_by_params(self.tr("Artificial Sample"), random_setting.mean_param) return sample def get_random_dataset(self, n_samples): min_μm = self.minimum_size_input.value() max_μm = self.maximum_size_input.value() n_classes = self.n_classes_input.value() if min_μm == max_μm: return if min_μm > max_μm: min_μm, max_μm = max_μm, min_μm precision = self.precision_input.value() noise = precision + 1 dataset = get_random_dataset(target=self.target, n_samples=n_samples, min_μm=min_μm, max_μm=max_μm, n_classes=n_classes, precision=precision, noise=noise) return dataset def on_value_changed(self): self.update_chart() def update_chart(self, random=False): if not random: sample = self.get_random_mean() else: sample = self.get_random_sample() self.chart.show_model(sample.view_model) def closeEvent(self, event): if self.cancel_button.isEnabled(): self.on_cancel_clicked() event.accept()
def get_widget_by_type(obj): if type(obj) == int: widget = QSpinBox() widget.setRange(INT_RANGE_MIN, INT_RANGE_MAX) widget.setSingleStep(INT_RANGE_STEP) widget.setValue(obj) widget.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Minimum) elif type(obj) == float: widget = QDoubleSpinBox() widget.setRange(FLOAT_RANGE_MIN, FLOAT_RANGE_MAX) widget.setSingleStep(FLOAT_RANGE_STEP) widget.setValue(obj) widget.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Minimum) elif type(obj) == str: widget = QLineEdit() widget.setText(obj) elif type(obj) == bool: widget = QCheckBox() widget.setChecked(obj) elif type(obj) == list: widget = QComboBox() widget.addItems(obj) widget.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Minimum) elif type(obj) == tuple: widget = QFrame() if len(obj) <= 3: box = QHBoxLayout() else: box = QVBoxLayout() box.setMargin(0) for item in obj: value_widget = QLabel(f"{item}") value_widget.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Minimum) value_widget.setObjectName("tuple") box.addWidget(value_widget) widget.setLayout(box) elif type(obj) == dict: widget = QFrame() # If less than 3 items, lay it out horizontally else vertically # if len(obj) <= 3: # box = QHBoxLayout() # else: # box = QVBoxLayout() # box.setMargin(0) grid = QGridLayout() grid.setMargin(0) row = 0 for key in obj: label = QLabel(f"{key.capitalize()}:") grid.addWidget(label, row, 0) value_widget = get_widget_by_type(obj[key]) value_widget.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Minimum) grid.addWidget(value_widget, row, 1) try: value_widget.setRange(INT_RANGE_MIN, INT_RANGE_MAX) value_widget.setSingleStep(INT_RANGE_STEP) value_widget.setValue(obj[key]) except: pass row += 1 widget.setLayout(grid) # TODO: Lists inside of lists. Should probably use QTreeView # elif type(obj) == list: # widget = [] # for l in obj: # widget.append(QComboBox()) # widget[-1].addItems(obj) # widget[-1].setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Minimum) return widget
class SettingsEditionDialog(QDialog): languages = {"Français": "fr", "English": "en"} def __init__(self): QDialog.__init__(self) self.setWindowTitle(tr("btn_config")) self.setFixedSize(QSize(700, 675)) # Retrieve current settings self.settings = AssetManager.getInstance().config_to_dico( AssetManager.getInstance().get_config_parser()) self.__restart_needed = False self.__restore_required = False # Version self.lab_version = QLabel(self.settings['main']['version']) # Language self.combo_language = QComboBox() self.combo_language.addItems(list(self.languages.keys())) for lang in self.languages: # Look for the current language to select it if self.languages[lang] == self.settings['main']['language']: self.combo_language.setCurrentText(lang) break # CSV separator self.csv_sep_edit = QLineEdit() self.csv_sep_edit.setMaxLength(2) self.csv_sep_edit.setFixedWidth(25) self.csv_sep_edit.setAlignment(Qt.AlignCenter) self.csv_sep_edit.setText(self.settings['main']['csv_separator']) # BDD path self.btn_bdd_path = QPushButton(self.settings['main']['bdd_path']) self.btn_bdd_path.clicked.connect(self.choose_bdd_path) # Port self.wepapp_port = QSpinBox() self.wepapp_port.setMinimum(1024) self.wepapp_port.setMaximum(65535) self.wepapp_port.setValue(int(self.settings['webapp']['port'])) # Colors self.tile_color = ColorChooser(self.settings['colors']['tile']) self.hovered_tile_color = ColorChooser( self.settings['colors']['hovered_tile']) self.hovered_empty_tile_color = ColorChooser( self.settings['colors']['hovered_empty_tile']) self.dragged_tile_color = ColorChooser( self.settings['colors']['dragged_tile']) self.drag_selected_tile_color = ColorChooser( self.settings['colors']['drag_selected_tile']) self.selected_tile_color = ColorChooser( self.settings['colors']['selected_tile']) self.tile_text_color = ColorChooser( self.settings['colors']['tile_text']) self.room_bg_color = ColorChooser(self.settings['colors']['room_bg']) self.room_grid_color = ColorChooser( self.settings['colors']['room_grid']) self.main_bg_color = ColorChooser(self.settings['colors']['main_bg']) self.board_bg_color = ColorChooser(self.settings['colors']['board_bg']) self.attr_colors = "" # Chosen colors self.attributes_colors_chooser = AttrColorsChooser( self.settings['colors']['attr_colors'].split()) # Sizes # Desk sizes self.desk_size_h = QSpinBox() self.desk_size_h.setMinimum(10) self.desk_size_h.setMaximum(200) self.desk_size_h.setValue(int(self.settings['size']['desk_height'])) self.desk_size_h.setFixedWidth(50) self.desk_size_w = QSpinBox() self.desk_size_w.setMinimum(10) self.desk_size_w.setMaximum(200) self.desk_size_w.setValue(int(self.settings['size']['desk_width'])) self.desk_size_w.setFixedWidth(50) # Font size self.desk_font_size = QSpinBox() self.desk_font_size.setMinimum(4) self.desk_font_size.setValue(int(self.settings['size']['font_size'])) self.desk_font_size.setFixedWidth(50) # Grid rows self.grid_rows = QSpinBox() self.grid_rows.setMinimum(1) self.grid_rows.setMaximum(40) self.grid_rows.setValue(int( self.settings['size']['default_room_rows'])) self.grid_rows.setFixedWidth(50) # Grid columns self.grid_cols = QSpinBox() self.grid_cols.setMinimum(1) self.grid_cols.setMaximum(40) self.grid_cols.setValue( int(self.settings['size']['default_room_columns'])) self.grid_cols.setFixedWidth(50) # --- Buttons --- # Confirm button self.ok_btn = QPushButton(tr("btn_save")) self.ok_btn.clicked.connect(self.accept) self.ok_btn.setFixedWidth(200) self.ok_btn.setFocus() # Cancel button self.cancel_btn = QPushButton(tr("btn_cancel")) self.cancel_btn.clicked.connect(self.reject) self.cancel_btn.setFixedWidth(200) # Restore defaults button self.restore_btn = QPushButton(tr("btn_restore")) self.restore_btn.clicked.connect(self.__restore) self.restore_btn.setFixedWidth(200) self.__set_layout() def __set_layout(self) -> None: """ Sets the dialog layout """ # Main layout layout = QVBoxLayout() layout.setMargin(0) layout.addSpacing(5) # Main section main_layout = SettingsFormLayout() main_layout.addRow(tr("app_version"), self.lab_version) main_layout.addRow(tr("language"), self.combo_language) main_layout.addRow(tr("csv_sep"), self.csv_sep_edit) main_layout.addRow(tr("bdd_path"), self.btn_bdd_path) # Web app widget_port = QWidget() layout_port = QHBoxLayout() layout_port.setMargin(0) layout_port.addWidget(self.wepapp_port) layout_port.addWidget(WarningToolTip("shutdown_required")) widget_port.setLayout(layout_port) main_layout.addRow(tr("web_port"), widget_port) layout.addLayout(main_layout) Separator(self.width(), layout) # Colors colors_layout1 = SettingsFormLayout() colors_layout1.addRow(tr("tile"), self.tile_color) colors_layout1.addRow(tr("hovered_tile"), self.hovered_tile_color) colors_layout1.addRow(tr("hovered_empty_tile"), self.hovered_empty_tile_color) colors_layout1.addRow(tr("dragged_tile"), self.dragged_tile_color) colors_layout1.addRow(tr("drag_selected_tile"), self.drag_selected_tile_color) colors_layout1.addRow(tr("selected_tile"), self.selected_tile_color) colors_layout2 = SettingsFormLayout() colors_layout2.addRow(tr("tile_text"), self.tile_text_color) colors_layout2.addRow(tr("room_bg"), self.room_bg_color) colors_layout2.addRow(tr("room_grid"), self.room_grid_color) colors_layout2.addRow(tr("main_bg"), self.main_bg_color) colors_layout2.addRow(tr("board_bg"), self.board_bg_color) colors_layout = QHBoxLayout() colors_layout.setMargin(0) colors_layout.addLayout(colors_layout1) colors_layout.addLayout(colors_layout2) layout.addLayout(colors_layout) layout.addSpacing(15) colors_layout3 = SettingsFormLayout() colors_layout3.setMargin(0) colors_layout3.addRow(tr("attr_colors"), self.attributes_colors_chooser) layout.addLayout(colors_layout3) Separator(self.width(), layout) # size data sizes_layout = SettingsFormLayout() sizes_layout.setMargin(0) widget_desk = QWidget() layout_desk = QHBoxLayout() layout_desk.setMargin(0) layout_desk.addWidget(self.desk_size_h) layout_desk.addWidget(self.desk_size_w) layout_desk.addWidget(WarningToolTip("dangerous_parameter")) widget_desk.setLayout(layout_desk) sizes_layout.addRow(tr("desk_size"), widget_desk) sizes_layout.addRow(tr("font_size"), self.desk_font_size) widget_rows = QWidget() layout_rows = QHBoxLayout() layout_rows.setMargin(0) layout_rows.addWidget(self.grid_rows) layout_rows.addWidget(WarningToolTip("dangerous_parameter")) widget_rows.setLayout(layout_rows) sizes_layout.addRow(tr("grid_rows"), widget_rows) widget_cols = QWidget() layout_cols = QHBoxLayout() layout_cols.setMargin(0) layout_cols.addWidget(self.grid_cols) layout_cols.addWidget(WarningToolTip("dangerous_parameter")) widget_cols.setLayout(layout_cols) sizes_layout.addRow(tr("grid_cols"), widget_cols) layout.addLayout(sizes_layout) Separator(self.width(), layout) # Buttons layout_buttons = QHBoxLayout() layout_buttons.addWidget(self.ok_btn) layout_buttons.addWidget(self.restore_btn) layout_buttons.addWidget(self.cancel_btn) layout.addLayout(layout_buttons) layout.addSpacing(5) self.setLayout(layout) self.setStyleSheet(get_stylesheet("dialog2")) def __restore(self) -> None: """ Restore default parameters before closing dialog """ self.__restart_needed = True self.__restore_required = True self.accept() def __new_settings(self) -> dict: """ Retrieves the new settings to use """ settings = self.settings # Language language = self.languages[self.combo_language.currentText()] if language != settings['main']['language']: settings['main']['language'] = language self.__restart_needed = True # CSV separator settings['main']['csv_separator'] = self.csv_sep_edit.text() # BDD path if self.btn_bdd_path.text() != settings['main']['bdd_path']: if self.btn_bdd_path.text().endswith("sdc_db"): settings['main']['bdd_path'] = self.btn_bdd_path.text() else: settings['main']['bdd_path'] = "" self.__restart_needed = True # Port if str(self.wepapp_port.value()) != settings['webapp']['port']: settings['webapp']['port'] = str(self.wepapp_port.value()) # Colors settings['colors']['tile'] = self.tile_color.get_color() settings['colors']['hovered_tile'] = self.hovered_tile_color.get_color( ) settings['colors'][ 'hovered_empty_tile'] = self.hovered_empty_tile_color.get_color() settings['colors']['dragged_tile'] = self.dragged_tile_color.get_color( ) settings['colors'][ 'drag_selected_tile'] = self.drag_selected_tile_color.get_color() settings['colors'][ 'selected_tile'] = self.selected_tile_color.get_color() settings['colors']['tile_text'] = self.tile_text_color.get_color() settings['colors']['room_grid'] = self.room_grid_color.get_color() if self.room_bg_color.get_color() != settings['colors']['room_bg']: settings['colors']['room_bg'] = self.room_bg_color.get_color() self.__restart_needed = True if self.main_bg_color.get_color() != settings['colors']['main_bg']: settings['colors']['main_bg'] = self.main_bg_color.get_color() self.__restart_needed = True if self.board_bg_color.get_color() != settings['colors']['board_bg']: settings['colors']['board_bg'] = self.board_bg_color.get_color() self.__restart_needed = True settings['colors']['attr_colors'] = self.attr_colors # Size settings if str(self.desk_size_h.value()) != settings['size']['desk_height']: settings['size']['desk_height'] = str(self.desk_size_h.value()) self.__restart_needed = True if str(self.desk_size_w.value()) != settings['size']['desk_width']: settings['size']['desk_width'] = str(self.desk_size_w.value()) self.__restart_needed = True if str(self.desk_font_size.value()) != settings['size']['font_size']: settings['size']['font_size'] = str(self.desk_font_size.value()) #self.__restart_needed = False if str(self.grid_rows.value() ) != settings['size']['default_room_rows']: settings['size']['default_room_rows'] = str(self.grid_rows.value()) self.__restart_needed = True if str(self.grid_cols.value() ) != settings['size']['default_room_columns']: settings['size']['default_room_columns'] = str( self.grid_cols.value()) self.__restart_needed = True return settings def new_config(self) -> ConfigParser: """ Retrieves the new config parser object """ conf = ConfigParser() conf.read_dict(self.__new_settings()) return conf def need_restart(self): return self.__restart_needed def restore_default(self) -> bool: return self.__restore_required def accept(self) -> None: """ Performs actions before calling parent's accept method """ self.attr_colors = self.attributes_colors_chooser.get_colors_to_str() super().accept() def choose_bdd_path(self) -> None: """ Opens a file chooser to select the bdd path. Then sets the name as button text. """ bdd_path = QFileDialog.getOpenFileName(self, tr("bdd_path"), self.btn_bdd_path.text())[0] if bdd_path: self.btn_bdd_path.setText(bdd_path)
def initialise(self): self.settingsFile = os.path.join(self.findNukeHomeDir(), "deadline_settings.ini") print("Loading settings: " + self.settingsFile) # Initialize the submission settings. self.settings = QSettings(self.settingsFile, QSettings.IniFormat) print("Grabbing submitter info...") try: dcOutput = CallDeadlineCommand([ "-prettyJSON", "-GetSubmissionInfo", "Pools", "Groups", "MaxPriority", "TaskLimit", "UserHomeDir", "RepoDir:submission/Hiero/Main", "RepoDir:submission/Integration/Main", ], useDeadlineBg=True) output = json.loads(dcOutput, encoding="utf-8") except ValueError as e: print("Unable to get submitter info from Deadline:\n\n" + e.message) raise if output["ok"]: self.submissionInfo = output["result"] else: raise ValueError( "DeadlineCommand returned a bad result and was unable to grab the submitter info.\n\n" + output["result"]) # Get the Deadline temp directory. deadlineHome = self.submissionInfo["UserHomeDir"].strip() self.deadlineTemp = os.path.join(deadlineHome, "temp") self.integrationDir = self.submissionInfo["RepoDirs"][ "submission/Integration/Main"].strip() # Get maximum priority. maximumPriority = self.submissionInfo["MaxPriority"] # Collect the pools and groups. pools = self.submissionInfo["Pools"] secondaryPools = [""] secondaryPools.extend(pools) groups = self.submissionInfo["Groups"] # Set up the other default arrays. onJobComplete = ("Nothing", "Archive", "Delete") nukeVersions = ("6.0", "6.1", "6.2", "6.3", "6.4", "7.0", "7.1", "7.2", "7.3", "7.4", "8.0", "8.1", "8.2", "8.3", "8.4", "9.0", "9.1", "9.2", "9.3", "9.4", "10.0", "10.1", "10.2", "10.3", "10.4", "11.0", "11.1", "11.2", "11.3") buildsToForce = ("None", "32bit", "64bit") # Main Window mainWindow = hiero.ui.mainWindow() dialog = QDialog(mainWindow) self.dialog = dialog dialog.setWindowTitle("Submit to Deadline (and render with Nuke)") # Main Layout topLayout = QVBoxLayout() dialog.setLayout(topLayout) tabWidget = QTabWidget(dialog) jobTab = QWidget() jobTabLayout = QVBoxLayout() jobTab.setLayout(jobTabLayout) # Job Info Layout jobInfoGroupBox = QGroupBox("Job Description") jobTabLayout.addWidget(jobInfoGroupBox) jobInfoLayout = QGridLayout() jobInfoGroupBox.setLayout(jobInfoLayout) # Job Name jobInfoLayout.addWidget(QLabel("Job Name"), 0, 0) jobNameWidget = QLineEdit(self.settings.value("JobName", "")) jobInfoLayout.addWidget(jobNameWidget, 0, 1) # Comment jobInfoLayout.addWidget(QLabel("Comment"), 1, 0) commentWidget = QLineEdit(self.settings.value("Comment", "")) jobInfoLayout.addWidget(commentWidget, 1, 1) # Department jobInfoLayout.addWidget(QLabel("Department"), 2, 0) departmentWidget = QLineEdit(self.settings.value("Department", "")) jobInfoLayout.addWidget(departmentWidget, 2, 1) # Job Options Layout jobOptionsGroupBox = QGroupBox("Job Options") jobTabLayout.addWidget(jobOptionsGroupBox) jobOptionsLayout = QGridLayout() jobOptionsGroupBox.setLayout(jobOptionsLayout) # Pool jobOptionsLayout.addWidget(QLabel("Pool"), 0, 0) poolWidget = QComboBox() for pool in pools: poolWidget.addItem(pool) defaultPool = self.settings.value("Pool", "none") defaultIndex = poolWidget.findText(defaultPool) if defaultIndex != -1: poolWidget.setCurrentIndex(defaultIndex) jobOptionsLayout.addWidget(poolWidget, 0, 1, 1, 3) # Secondary Pool jobOptionsLayout.addWidget(QLabel("Secondary Pool"), 1, 0) secondaryPoolWidget = QComboBox() for secondaryPool in secondaryPools: secondaryPoolWidget.addItem(secondaryPool) defaultSecondaryPool = self.settings.value("SecondaryPool", "") defaultIndex = secondaryPoolWidget.findText(defaultSecondaryPool) if defaultIndex != -1: secondaryPoolWidget.setCurrentIndex(defaultIndex) jobOptionsLayout.addWidget(secondaryPoolWidget, 1, 1, 1, 3) # Group jobOptionsLayout.addWidget(QLabel("Group"), 2, 0) groupWidget = QComboBox() for group in groups: groupWidget.addItem(group) defaultGroup = self.settings.value("Group", "none") defaultIndex = groupWidget.findText(defaultGroup) if defaultIndex != -1: groupWidget.setCurrentIndex(defaultIndex) jobOptionsLayout.addWidget(groupWidget, 2, 1, 1, 3) # Priority initPriority = int(self.settings.value("Priority", "50")) if initPriority > maximumPriority: initPriority = maximumPriority / 2 jobOptionsLayout.addWidget(QLabel("Priority"), 3, 0) priorityWidget = QSpinBox() priorityWidget.setRange(0, maximumPriority) priorityWidget.setValue(initPriority) jobOptionsLayout.addWidget(priorityWidget, 3, 1) # Task Timeout jobOptionsLayout.addWidget(QLabel("Task Timeout"), 4, 0) taskTimeoutWidget = QSpinBox() taskTimeoutWidget.setRange(0, 1000000) taskTimeoutWidget.setValue(int(self.settings.value("TaskTimeout", "0"))) jobOptionsLayout.addWidget(taskTimeoutWidget, 4, 1) # Auto Task Timeout autoTaskTimeoutWidget = QCheckBox("Enable Auto Task Timeout") autoTaskTimeoutWidget.setChecked( strtobool(self.settings.value("AutoTaskTimeout", "False"))) jobOptionsLayout.addWidget(autoTaskTimeoutWidget, 4, 2) # Concurrent Tasks jobOptionsLayout.addWidget(QLabel("Concurrent Tasks"), 5, 0) concurrentTasksWidget = QSpinBox() concurrentTasksWidget.setRange(1, 16) concurrentTasksWidget.setValue( int(self.settings.value("ConcurrentTasks", "1"))) jobOptionsLayout.addWidget(concurrentTasksWidget, 5, 1) # Limit Tasks To Slave's Task Limit limitConcurrentTasksWidget = QCheckBox( "Limit Tasks To Slave's Task Limit") limitConcurrentTasksWidget.setChecked( strtobool(self.settings.value("LimitConcurrentTasks", "True"))) jobOptionsLayout.addWidget(limitConcurrentTasksWidget, 5, 2) # Machine Limit jobOptionsLayout.addWidget(QLabel("Machine Limit"), 6, 0) machineLimitWidget = QSpinBox() machineLimitWidget.setRange(0, 1000000) machineLimitWidget.setValue( int(self.settings.value("MachineLimit", "1"))) jobOptionsLayout.addWidget(machineLimitWidget, 6, 1) # Machine List Is A Blacklist isBlacklistWidget = QCheckBox("Machine List Is A Blacklist") isBlacklistWidget.setChecked( strtobool(self.settings.value("IsBlacklist", "False"))) jobOptionsLayout.addWidget(isBlacklistWidget, 6, 2) # Machine List jobOptionsLayout.addWidget(QLabel("Machine List"), 7, 0) machineListWidget = QLineEdit(self.settings.value("MachineList", "")) jobOptionsLayout.addWidget(machineListWidget, 7, 1, 1, 2) def browseMachineList(): output = CallDeadlineCommand( ["-selectmachinelist", str(machineListWidget.text())], False) output = output.replace("\r", "").replace("\n", "") if output != "Action was cancelled by user": machineListWidget.setText(output) machineListButton = QPushButton("Browse") machineListButton.pressed.connect(browseMachineList) jobOptionsLayout.addWidget(machineListButton, 7, 3) # Limits jobOptionsLayout.addWidget(QLabel("Limits"), 8, 0) limitsWidget = QLineEdit(self.settings.value("Limits", "")) jobOptionsLayout.addWidget(limitsWidget, 8, 1, 1, 2) def browseLimitList(): output = CallDeadlineCommand( ["-selectlimitgroups", str(limitsWidget.text())], False) output = output.replace("\r", "").replace("\n", "") if output != "Action was cancelled by user": limitsWidget.setText(output) limitsButton = QPushButton("Browse") limitsButton.pressed.connect(browseLimitList) jobOptionsLayout.addWidget(limitsButton, 8, 3) # On Job Complete jobOptionsLayout.addWidget(QLabel("On Job Complete"), 9, 0) onJobCompleteWidget = QComboBox() for option in onJobComplete: onJobCompleteWidget.addItem(option) defaultOption = self.settings.value("OnJobComplete", "Nothing") defaultIndex = onJobCompleteWidget.findText(defaultOption) if defaultIndex != -1: onJobCompleteWidget.setCurrentIndex(defaultIndex) jobOptionsLayout.addWidget(onJobCompleteWidget, 9, 1) # Submit Job As Suspended submitSuspendedWidget = QCheckBox("Submit Job As Suspended") submitSuspendedWidget.setChecked( strtobool(self.settings.value("SubmitSuspended", "False"))) jobOptionsLayout.addWidget(submitSuspendedWidget, 9, 2) # Nuke Options nukeOptionsGroupBox = QGroupBox("Nuke Options") jobTabLayout.addWidget(nukeOptionsGroupBox) nukeOptionsLayout = QGridLayout() nukeOptionsGroupBox.setLayout(nukeOptionsLayout) # Version nukeOptionsLayout.addWidget(QLabel("Version"), 0, 0) versionWidget = QComboBox() for version in nukeVersions: versionWidget.addItem(version) defaultVersion = self.settings.value("Version", "7.0") defaultIndex = versionWidget.findText(defaultVersion) if defaultIndex != -1: versionWidget.setCurrentIndex(defaultIndex) nukeOptionsLayout.addWidget(versionWidget, 0, 1) # Submit Nuke Script File With Job submitScriptWidget = QCheckBox("Submit Nuke Script File With Job") submitScriptWidget.setChecked( strtobool(self.settings.value("SubmitScript", "False"))) nukeOptionsLayout.addWidget(submitScriptWidget, 0, 2) # Build To Force nukeOptionsLayout.addWidget(QLabel("Build To Force"), 1, 0) buildWidget = QComboBox() for build in buildsToForce: buildWidget.addItem(build) defaultBuild = self.settings.value("Build", "None") defaultIndex = buildWidget.findText(defaultBuild) if defaultIndex != -1: buildWidget.setCurrentIndex(defaultIndex) nukeOptionsLayout.addWidget(buildWidget, 1, 1) # Render With NukeX useNukeXWidget = QCheckBox("Render With NukeX") useNukeXWidget.setChecked( strtobool(self.settings.value("UseNukeX", "False"))) nukeOptionsLayout.addWidget(useNukeXWidget, 1, 2) # Max RAM Usage (MB) nukeOptionsLayout.addWidget(QLabel("Max RAM Usage (MB)"), 2, 0) memoryWidget = QSpinBox() memoryWidget.setRange(0, 5000) memoryWidget.setValue(int(self.settings.value("Memory", "0"))) nukeOptionsLayout.addWidget(memoryWidget, 2, 1) # Continue On Error continueOnErrorWidget = QCheckBox("Continue On Error") continueOnErrorWidget.setChecked( strtobool(self.settings.value("ContinueOnError", "False"))) nukeOptionsLayout.addWidget(continueOnErrorWidget, 2, 2) # Threads nukeOptionsLayout.addWidget(QLabel("Threads"), 3, 0) threadsWidget = QSpinBox() threadsWidget.setRange(0, 256) threadsWidget.setValue(int(self.settings.value("Threads", "0"))) nukeOptionsLayout.addWidget(threadsWidget, 3, 1) # Use Batch Mode batchModeWidget = QCheckBox("Use Batch Mode") batchModeWidget.setChecked( strtobool(self.settings.value("BatchMode", "False"))) nukeOptionsLayout.addWidget(batchModeWidget, 3, 2) # Frames Per Task nukeOptionsLayout.addWidget(QLabel("Frames Per Task"), 4, 0) framesPerTaskWidget = QSpinBox() framesPerTaskWidget.setRange(1, 1000000) framesPerTaskWidget.setValue( int(self.settings.value("FramesPerTask", "1"))) nukeOptionsLayout.addWidget(framesPerTaskWidget, 4, 1) nukeOptionsLayout.addWidget( QLabel("(this only affects non-movie jobs)"), 4, 2) tabWidget.addTab(jobTab, "Job Options") # Button Box (Extra work required to get the custom ordering we want) self.pipelineToolStatusLabel.setAlignment(Qt.AlignRight | Qt.AlignVCenter) pipelineToolStatus = self.retrievePipelineToolStatus() self.updatePipelineToolStatusLabel(pipelineToolStatus) integrationButton = QPushButton("Pipeline Tools") integrationButton.clicked.connect(self.OpenIntegrationWindow) submitButton = QPushButton("Submit") submitButton.clicked.connect(dialog.accept) submitButton.setDefault(True) cancelButton = QPushButton("Cancel") cancelButton.clicked.connect(dialog.reject) buttonGroupBox = QGroupBox() buttonLayout = QGridLayout() buttonLayout.setColumnStretch( 0, 1) # Makes the pipeline status label expand, not the buttons buttonGroupBox.setLayout(buttonLayout) buttonGroupBox.setAlignment(Qt.AlignRight) buttonGroupBox.setFlat(True) buttonLayout.addWidget(self.pipelineToolStatusLabel, 0, 0) buttonLayout.addWidget(integrationButton, 0, 1) buttonLayout.addWidget(submitButton, 0, 2) buttonLayout.addWidget(cancelButton, 0, 3) topLayout.addWidget(tabWidget) topLayout.addWidget(buttonGroupBox) # Show the dialog. result = (dialog.exec_() == QDialog.DialogCode.Accepted) if result: # Need to pass integration dir path to render task self.settings.setValue("IntegrationDir", self.integrationDir) self.settings.setValue("JobName", jobNameWidget.text()) self.settings.setValue("Comment", commentWidget.text()) self.settings.setValue("Department", departmentWidget.text()) self.settings.setValue("Pool", poolWidget.currentText()) self.settings.setValue("SecondaryPool", secondaryPoolWidget.currentText()) self.settings.setValue("Group", groupWidget.currentText()) self.settings.setValue("Priority", priorityWidget.value()) self.settings.setValue("TaskTimeout", taskTimeoutWidget.value()) self.settings.setValue("AutoTaskTimeout", str(autoTaskTimeoutWidget.isChecked())) self.settings.setValue("ConcurrentTasks", concurrentTasksWidget.value()) self.settings.setValue("LimitConcurrentTasks", str(limitConcurrentTasksWidget.isChecked())) self.settings.setValue("MachineLimit", machineLimitWidget.value()) self.settings.setValue("IsBlacklist", str(isBlacklistWidget.isChecked())) self.settings.setValue("MachineList", machineListWidget.text()) self.settings.setValue("Limits", limitsWidget.text()) self.settings.setValue("OnJobComplete", onJobCompleteWidget.currentText()) self.settings.setValue("SubmitSuspended", str(submitSuspendedWidget.isChecked())) self.settings.setValue("Version", versionWidget.currentText()) self.settings.setValue("SubmitScript", str(submitScriptWidget.isChecked())) self.settings.setValue("Build", buildWidget.currentText()) self.settings.setValue("UseNukeX", str(useNukeXWidget.isChecked())) self.settings.setValue("FramesPerTask", framesPerTaskWidget.value()) self.settings.setValue("ContinueOnError", str(continueOnErrorWidget.isChecked())) self.settings.setValue("Threads", threadsWidget.value()) self.settings.setValue("BatchMode", str(batchModeWidget.isChecked())) self.settings.setValue("Memory", memoryWidget.value()) print("Saving settings: " + self.settingsFile) self.settings.sync() else: print("Submission canceled") self.settings = None # Not sure if there is a better way to stop the export process. This works, but it leaves all the tasks # in the Queued state. self.setError("Submission was canceled")
class StreamFieldsWidget(QDialog): """ A stream widget containing schema-specific properties. """ def __init__(self, parent): super().__init__() self.setParent(parent) self.setLayout(QGridLayout()) self.setWindowModality(Qt.WindowModal) self.setModal(True) self.minimum_spinbox_value = 0 self.maximum_spinbox_value = 100_000_000 self.advanced_options_enabled = False self.hs00_unimplemented_label = QLabel( "hs00 (Event histograms) has not yet been fully implemented.") self.schema_label = QLabel("Schema: ") self.schema_combo = QComboBox() self.topic_label = QLabel("Topic: ") self.topic_line_edit = QLineEdit() self.topic_line_edit.setPlaceholderText( "[broker][:port, default=9092]/topic") self.source_label = QLabel("Source: ") self.source_line_edit = QLineEdit() self.array_size_label = QLabel("Array size") self.array_size_spinbox = QSpinBox() self.array_size_spinbox.setMaximum(np.iinfo(np.int32).max) self.type_label = QLabel("Type: ") self.type_combo = QComboBox() self.type_combo.addItems(F142_TYPES) self.value_units_edit = QLineEdit() self.value_units_label = QLabel("Value Units:") self.show_advanced_options_button = QPushButton( text="Show/hide advanced options") self.show_advanced_options_button.setCheckable(True) self.show_advanced_options_button.clicked.connect( self.advanced_options_button_clicked) self._set_up_f142_group_box() self._set_up_ev42_group_box() self.scalar_radio = QRadioButton(text="Scalar") self.scalar_radio.clicked.connect(partial(self._show_array_size, False)) self.scalar_radio.setChecked(True) self.scalar_radio.clicked.emit() self.array_radio = QRadioButton(text="Array") self.array_radio.clicked.connect(partial(self._show_array_size, True)) self.schema_combo.currentTextChanged.connect(self._schema_type_changed) self.schema_combo.addItems([e.value for e in WriterModules]) self.ok_button = QPushButton("OK") self.ok_button.clicked.connect(self.parent().close) self.layout().addWidget(self.schema_label, 0, 0) self.layout().addWidget(self.schema_combo, 0, 1) self.layout().addWidget(self.topic_label, 1, 0) self.layout().addWidget(self.topic_line_edit, 1, 1) self.layout().addWidget(self.source_label, 2, 0) self.layout().addWidget(self.source_line_edit, 2, 1) self.layout().addWidget(self.value_units_label, 3, 0) self.layout().addWidget(self.value_units_edit, 3, 1) self.value_units_label.setVisible(False) self.value_units_edit.setVisible(False) self.layout().addWidget(self.type_label, 4, 0) self.layout().addWidget(self.type_combo, 4, 1) self.layout().addWidget(self.scalar_radio, 5, 0) self.layout().addWidget(self.array_radio, 5, 1) self.layout().addWidget(self.array_size_label, 6, 0) self.layout().addWidget(self.array_size_spinbox, 6, 1) self.layout().addWidget(self.hs00_unimplemented_label, 7, 0, 1, 2) # Spans both rows self.layout().addWidget(self.show_advanced_options_button, 8, 0, 1, 2) self.layout().addWidget(self.f142_advanced_group_box, 9, 0, 1, 2) self.layout().addWidget(self.ev42_advanced_group_box, 10, 0, 1, 2) self.layout().addWidget(self.ok_button, 11, 0, 1, 2) self._schema_type_changed(self.schema_combo.currentText()) def advanced_options_button_clicked(self): self._show_advanced_options( show=self.show_advanced_options_button.isChecked()) def _set_up_ev42_group_box(self): """ Sets up the UI for ev42 advanced options. """ self.ev42_nexus_elements = [ NEXUS_INDICES_INDEX_EVERY_MB, NEXUS_INDICES_INDEX_EVERY_KB, NEXUS_CHUNK_CHUNK_MB, NEXUS_CHUNK_CHUNK_KB, ] self.ev42_nexus_to_spinner_ui_element = {} self.ev42_advanced_group_box = QGroupBox( parent=self.show_advanced_options_button) self.ev42_advanced_group_box.setLayout(QFormLayout()) self.ev42_adc_pulse_debug_label = QLabel(ADC_PULSE_DEBUG) self.ev42_adc_pulse_debug_checkbox = QCheckBox() self.ev42_advanced_group_box.layout().addRow( self.ev42_adc_pulse_debug_label, self.ev42_adc_pulse_debug_checkbox) self.add_labels_and_spinboxes_for_advanced_options( self.ev42_nexus_elements, self.ev42_advanced_group_box, self.ev42_nexus_to_spinner_ui_element, ) def add_labels_and_spinboxes_for_advanced_options(self, elements, group_box, nexus_to_spinner): for nexus_string in elements: label = QLabel(nexus_string) spinner = QSpinBox() spinner.setRange(self.minimum_spinbox_value, self.maximum_spinbox_value) group_box.layout().addRow(label, spinner) nexus_to_spinner[nexus_string] = spinner def _set_up_f142_group_box(self): """ Sets up the UI for the f142 advanced options. """ self.f142_advanced_group_box = QGroupBox( parent=self.show_advanced_options_button) self.f142_advanced_group_box.setLayout(QFormLayout()) self.f142_nexus_to_spinner_ui_element = {} self.f142_nexus_elements = [ NEXUS_INDICES_INDEX_EVERY_MB, NEXUS_INDICES_INDEX_EVERY_KB, STORE_LATEST_INTO, ] self.add_labels_and_spinboxes_for_advanced_options( self.f142_nexus_elements, self.f142_advanced_group_box, self.f142_nexus_to_spinner_ui_element, ) def _show_advanced_options(self, show): schema = self.schema_combo.currentText() if schema == WriterModules.F142.value: self.f142_advanced_group_box.setVisible(show) elif schema == WriterModules.EV42.value: self.ev42_advanced_group_box.setVisible(show) self.advanced_options_enabled = show def _show_array_size(self, show: bool): self.array_size_spinbox.setVisible(show) self.array_size_label.setVisible(show) def _schema_type_changed(self, schema: str): self.parent().setWindowTitle(f"Editing {schema} stream field") self.hs00_unimplemented_label.setVisible(False) self.f142_advanced_group_box.setVisible(False) self.ev42_advanced_group_box.setVisible(False) self.show_advanced_options_button.setVisible(False) self.show_advanced_options_button.setChecked(False) self.value_units_label.setVisible(False) self.value_units_edit.setVisible(False) if schema == WriterModules.F142.value: self.value_units_label.setVisible(True) self.value_units_edit.setVisible(True) self._set_edits_visible(True, True) self.show_advanced_options_button.setVisible(True) self.f142_advanced_group_box.setVisible(False) elif schema == WriterModules.EV42.value: self._set_edits_visible(True, False) self.show_advanced_options_button.setVisible(True) self.ev42_advanced_group_box.setVisible(False) elif schema == WriterModules.HS00.value: self._set_edits_visible(True, False) self.hs00_unimplemented_label.setVisible(True) elif schema == WriterModules.NS10.value: self._set_edits_visible(True, False, "nicos/<device>/<parameter>") elif (schema == WriterModules.TDCTIME.value or schema == WriterModules.SENV.value): self._set_edits_visible(True, False) def _set_edits_visible(self, source: bool, type: bool, source_hint=None): self.source_label.setVisible(source) self.source_line_edit.setVisible(source) self.type_label.setVisible(type) self.type_combo.setVisible(type) self.array_radio.setVisible(type) self.scalar_radio.setVisible(type) if source_hint: self.source_line_edit.setPlaceholderText(source_hint) else: self.source_line_edit.setPlaceholderText("") def get_stream_group(self) -> h5py.Group: """ Create the stream group with a temporary in-memory HDF5 file. :return: The created HDF group. """ temp_file = create_temporary_in_memory_file() group = temp_file.create_group("children") group.create_dataset(name="type", dtype=STRING_DTYPE, data="stream") stream_group = group.create_group( self.parent().parent().field_name_edit.text()) stream_group.attrs[CommonAttrs.NX_CLASS] = CommonAttrs.NC_STREAM stream_group.create_dataset(name="topic", dtype=STRING_DTYPE, data=self.topic_line_edit.text()) stream_group.create_dataset( name="writer_module", dtype=STRING_DTYPE, data=self.schema_combo.currentText(), ) schema = self.schema_combo.currentText() stream_group.create_dataset("source", dtype=STRING_DTYPE, data=self.source_line_edit.text()) if schema == WriterModules.F142.value: self._create_f142_fields(stream_group) elif schema == WriterModules.EV42.value: self._create_ev42_fields(stream_group) return stream_group def _create_ev42_fields(self, stream_group: h5py.Group): """ Create ev42 fields in the given group if advanced options are specified. :param stream_group: The group to apply fields to. """ if self.advanced_options_enabled: if self.ev42_adc_pulse_debug_checkbox.isChecked(): stream_group.create_dataset( ADC_PULSE_DEBUG, dtype=bool, data=self.ev42_adc_pulse_debug_checkbox.isChecked(), ) self._create_dataset_from_spinner( stream_group, self.ev42_nexus_to_spinner_ui_element) def _create_f142_fields(self, stream_group: h5py.Group): """ Create f142 fields in the given group if advanced options are specified. :param stream_group: The group to apply fields to. """ stream_group.create_dataset("type", dtype=STRING_DTYPE, data=self.type_combo.currentText()) if self.array_radio.isChecked(): stream_group.create_dataset("array_size", data=self.array_size_spinbox.value()) if self.value_units_edit.text(): stream_group.create_dataset("value_units", data=self.value_units_edit.text()) if self.advanced_options_enabled: self._create_dataset_from_spinner( stream_group, self.f142_nexus_to_spinner_ui_element) @staticmethod def _create_dataset_from_spinner(stream_group: h5py.Group, nexus_to_spinner_dict: Dict[str, QSpinBox]): for (nexus_string, ui_element) in nexus_to_spinner_dict.items(): if ui_element.value() > 0: stream_group.create_dataset(nexus_string, dtype=int, data=ui_element.value()) def fill_in_existing_ev42_fields(self, field: h5py.Group): """ Fill in specific existing ev42 fields into the new UI field. :param field: The stream group :param new_ui_field: The new UI field to be filled in """ all_ev42_elements = list(self.ev42_nexus_elements) all_ev42_elements.append(ADC_PULSE_DEBUG) if check_if_advanced_options_should_be_enabled(all_ev42_elements, field): self._show_advanced_options(True) if ADC_PULSE_DEBUG in field.keys(): self.ev42_adc_pulse_debug_checkbox.setChecked( bool(field[ADC_PULSE_DEBUG][()])) fill_in_advanced_options( self.ev42_nexus_to_spinner_ui_element.items(), field) def fill_in_existing_f142_fields(self, field: h5py.Group): """ Fill in specific existing f142 fields into the new UI field. :param field: The stream group :param new_ui_field: The new UI field to be filled in """ self.type_combo.setCurrentText(field["type"][()]) if "array_size" in field.keys(): self.array_radio.setChecked(True) self.scalar_radio.setChecked(False) self.array_size_spinbox.setValue(field["array_size"][()]) else: self.array_radio.setChecked(False) self.scalar_radio.setChecked(True) if check_if_advanced_options_should_be_enabled( self.f142_nexus_elements, field): self._show_advanced_options(True) fill_in_advanced_options( self.f142_nexus_to_spinner_ui_element.items(), field) def update_existing_stream_info(self, field: h5py.Group): """ Fill in stream fields and properties into the new UI field. :param field: The stream group :param new_ui_field: The new UI field to be filled in """ schema = field["writer_module"][()] self.schema_combo.setCurrentText(str(schema)) self.topic_line_edit.setText(str(field["topic"][()])) self.source_line_edit.setText(str(field["source"][()])) if schema == WriterModules.F142.value: self.fill_in_existing_f142_fields(field) elif schema == WriterModules.EV42.value: self.fill_in_existing_ev42_fields(field)
class QBuyGroupForGroundObjectDialog(QDialog): changed = QtCore.Signal() def __init__(self, parent, ground_object: TheaterGroundObject, cp: ControlPoint, game: Game, current_group_value: int): super(QBuyGroupForGroundObjectDialog, self).__init__(parent) self.setMinimumWidth(350) self.ground_object = ground_object self.cp = cp self.game = game self.current_group_value = current_group_value self.setWindowTitle("Buy units @ " + self.ground_object.obj_name) self.setWindowIcon(EVENT_ICONS["capture"]) self.buySamButton = QPushButton("Buy") self.buyArmorButton = QPushButton("Buy") self.buySamLayout = QGridLayout() self.buyArmorLayout = QGridLayout() self.amount = QSpinBox() self.buyArmorCombo = QComboBox() self.samCombo = QComboBox() self.buySamBox = QGroupBox("Buy SAM site :") self.buyArmorBox = QGroupBox("Buy defensive position :") self.init_ui() def init_ui(self): faction = self.game.player_faction # Sams possible_sams = get_faction_possible_sams_generator(faction) for sam in possible_sams: self.samCombo.addItem(sam.name + " [$" + str(sam.price) + "M]", userData=sam) self.samCombo.currentIndexChanged.connect(self.samComboChanged) self.buySamLayout.addWidget(QLabel("Site Type :"), 0, 0, Qt.AlignLeft) self.buySamLayout.addWidget(self.samCombo, 0, 1, alignment=Qt.AlignRight) self.buySamLayout.addWidget(self.buySamButton, 1, 1, alignment=Qt.AlignRight) stretch = QVBoxLayout() stretch.addStretch() self.buySamLayout.addLayout(stretch, 2, 0) self.buySamButton.clicked.connect(self.buySam) # Armored units armored_units = db.find_unittype( PinpointStrike, faction.name) # Todo : refactor this legacy nonsense for unit in set(armored_units): self.buyArmorCombo.addItem(db.unit_type_name_2(unit) + " [$" + str(db.PRICES[unit]) + "M]", userData=unit) self.buyArmorCombo.currentIndexChanged.connect(self.armorComboChanged) self.amount.setMinimum(2) self.amount.setMaximum(8) self.amount.setValue(2) self.amount.valueChanged.connect(self.amountComboChanged) self.buyArmorLayout.addWidget(QLabel("Unit type :"), 0, 0, Qt.AlignLeft) self.buyArmorLayout.addWidget(self.buyArmorCombo, 0, 1, alignment=Qt.AlignRight) self.buyArmorLayout.addWidget(QLabel("Group size :"), 1, 0, alignment=Qt.AlignLeft) self.buyArmorLayout.addWidget(self.amount, 1, 1, alignment=Qt.AlignRight) self.buyArmorLayout.addWidget(self.buyArmorButton, 2, 1, alignment=Qt.AlignRight) stretch2 = QVBoxLayout() stretch2.addStretch() self.buyArmorLayout.addLayout(stretch2, 3, 0) self.buyArmorButton.clicked.connect(self.buyArmor) # Do layout self.buySamBox.setLayout(self.buySamLayout) self.buyArmorBox.setLayout(self.buyArmorLayout) self.mainLayout = QHBoxLayout() self.mainLayout.addWidget(self.buySamBox) if self.ground_object.airbase_group: self.mainLayout.addWidget(self.buyArmorBox) self.setLayout(self.mainLayout) try: self.samComboChanged(0) self.armorComboChanged(0) except: pass def samComboChanged(self, index): self.buySamButton.setText("Buy [$" + str(self.samCombo.itemData(index).price) + "M] [-$" + str(self.current_group_value) + "M]") def armorComboChanged(self, index): self.buyArmorButton.setText( "Buy [$" + str(db.PRICES[self.buyArmorCombo.itemData(index)] * self.amount.value()) + "M][-$" + str(self.current_group_value) + "M]") def amountComboChanged(self): self.buyArmorButton.setText("Buy [$" + str(db.PRICES[ self.buyArmorCombo.itemData(self.buyArmorCombo.currentIndex())] * self.amount.value()) + "M][-$" + str(self.current_group_value) + "M]") def buyArmor(self): logging.info("Buying Armor ") utype = self.buyArmorCombo.itemData(self.buyArmorCombo.currentIndex()) logging.info(utype) price = db.PRICES[utype] * self.amount.value( ) - self.current_group_value if price > self.game.budget: self.error_money() self.close() return else: self.game.budget -= price # Generate Armor group = generate_armor_group_of_type_and_size(self.game, self.ground_object, utype, int(self.amount.value())) self.ground_object.groups = [group] GameUpdateSignal.get_instance().updateBudget(self.game) self.changed.emit() self.close() def buySam(self): sam_generator = self.samCombo.itemData(self.samCombo.currentIndex()) price = sam_generator.price - self.current_group_value if price > self.game.budget: self.error_money() return else: self.game.budget -= price # Generate SAM generator = sam_generator(self.game, self.ground_object) generator.generate() self.ground_object.groups = list(generator.groups) GameUpdateSignal.get_instance().updateBudget(self.game) self.changed.emit() self.close() def error_money(self): msg = QMessageBox() msg.setIcon(QMessageBox.Information) msg.setText("Not enough money to buy these units !") msg.setWindowTitle("Not enough money") msg.setStandardButtons(QMessageBox.Ok) msg.setWindowFlags(Qt.WindowStaysOnTopHint) msg.exec_() self.close()
class MagnifierWidget(ToolWidget): def __init__(self, image, parent=None): super(MagnifierWidget, self).__init__(parent) self.equalize_radio = QRadioButton(self.tr('Equalization')) self.equalize_radio.setToolTip(self.tr('RGB histogram equalization')) self.contrast_radio = QRadioButton(self.tr('Auto Contrast')) self.contrast_radio.setToolTip(self.tr('Compress luminance tonality')) self.centile_spin = QSpinBox() self.centile_spin.setRange(0, 100) self.centile_spin.setValue(20) self.centile_spin.setSuffix(self.tr(' %')) self.centile_spin.setToolTip(self.tr('Histogram percentile amount')) self.channel_check = QCheckBox(self.tr('By channel')) self.channel_check.setToolTip(self.tr('Independent RGB compression')) self.equalize_radio.setChecked(True) self.last_radio = self.equalize_radio self.image = image self.viewer = ImageViewer(self.image, self.image) self.change() self.viewer.viewChanged.connect(self.process) self.equalize_radio.clicked.connect(self.change) self.contrast_radio.clicked.connect(self.change) self.centile_spin.valueChanged.connect(self.change) self.channel_check.stateChanged.connect(self.change) top_layout = QHBoxLayout() top_layout.addWidget(QLabel(self.tr('Mode:'))) top_layout.addWidget(self.equalize_radio) top_layout.addWidget(self.contrast_radio) top_layout.addWidget(self.centile_spin) top_layout.addWidget(self.channel_check) top_layout.addStretch() main_layout = QVBoxLayout() main_layout.addLayout(top_layout) main_layout.addWidget(self.viewer) self.setLayout(main_layout) def process(self, rect): y1 = rect.top() y2 = rect.bottom() x1 = rect.left() x2 = rect.right() roi = self.image[y1:y2, x1:x2] if self.equalize_radio.isChecked(): self.centile_spin.setEnabled(False) self.channel_check.setEnabled(False) roi = equalize_img(roi) self.last_radio = self.equalize_radio elif self.contrast_radio.isChecked(): self.centile_spin.setEnabled(True) self.channel_check.setEnabled(True) centile = self.centile_spin.value() / 200 if self.channel_check.isChecked(): roi = cv.merge( [cv.LUT(c, auto_lut(c, centile)) for c in cv.split(roi)]) else: roi = cv.LUT( roi, auto_lut(cv.cvtColor(roi, cv.COLOR_BGR2GRAY), centile)) self.last_radio = self.contrast_radio else: self.last_radio.setChecked(True) return processed = np.copy(self.image) processed[y1:y2, x1:x2] = roi self.viewer.update_processed(processed) def change(self): self.process(self.viewer.get_rect())
class MainWindow(QMainWindow): def __init__(self, app, parent=None): super(MainWindow, self).__init__(parent) self.imagesDir = app.dir + '/images/' self.setWindowIcon(QIcon(self.imagesDir + 'icon.png')) self.path = '' self.settings = QSettings() self.lastDir = self.settings.value('lastDir', '') self.setMinimumWidth(540) self.supportedFormats = [] for f in QImageReader.supportedImageFormats(): self.supportedFormats.append(str(f.data(), encoding="utf-8")) self.fileWatcher = QFileSystemWatcher() self.fileWatcher.fileChanged.connect(self.fileChanged) # widgets self.showPixmapWidget = None self.tileWidthSpinBox = QSpinBox() self.tileWidthSpinBox.setValue(16) self.tileWidthSpinBox.setFixedWidth(50) self.tileWidthSpinBox.setMinimum(1) self.tileHeightSpinBox = QSpinBox() self.tileHeightSpinBox.setValue(16) self.tileHeightSpinBox.setFixedWidth(50) self.tileHeightSpinBox.setMinimum(1) self.paddingSpinBox = QSpinBox() self.paddingSpinBox.setFixedWidth(50) self.paddingSpinBox.setMinimum(1) self.transparentCheckbox = QCheckBox("Transparent") self.transparentCheckbox.setChecked(True) self.transparentCheckbox.stateChanged.connect(self.transparentChanged) self.backgroundColorEdit = ColorEdit() self.backgroundColorEdit.setEnabled(False) self.backgroundColorLabel = QLabel("Background color:") self.backgroundColorLabel.setEnabled(False) self.forcePotCheckBox = QCheckBox("Force PoT") self.forcePotCheckBox.setChecked(True) self.forcePotCheckBox.stateChanged.connect(self.forcePotChanged) self.reorderTilesCheckBox = QCheckBox("Reorder tiles") self.generateAndExportButton = QPushButton("Generate and export") self.generateAndExportButton.setFixedHeight(32) self.generateAndExportButton.clicked.connect(self.generateAndExportClicked) self.generateAndExportButton.setEnabled(False) self.pixmapWidget = PixmapWidget() self.pixmapWidget.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) self.pixmapWidget.setPixmap(self.createDropTextPixmap()) self.pixmapWidget.dropSignal.connect(self.fileDropped) self.pixmapWidget.setMinimumHeight(300) # load settings self.tileWidthSpinBox.setValue(int(self.settings.value('tileWidth', 16))) self.tileHeightSpinBox.setValue(int(self.settings.value('tileHeight', 16))) self.paddingSpinBox.setValue(int(self.settings.value('padding', 1))) self.forcePotCheckBox.setChecked(True if self.settings.value('forcePot', 'true') == 'true' else False) self.reorderTilesCheckBox.setChecked(True if self.settings.value('reorderTiles', 'false') == 'true' else False) self.transparentCheckbox.setChecked(True if self.settings.value('transparent', 'false') == 'true' else False) self.backgroundColorEdit.setColorText(str(self.settings.value('backgroundColor', '#FF00FF'))) self.restoreGeometry(QByteArray(self.settings.value('MainWindow/geometry'))) self.restoreState(QByteArray(self.settings.value('MainWindow/windowState'))) # layout hl1 = QHBoxLayout() hl1.setContentsMargins(5, 5, 5, 5) hl1.addWidget(QLabel("Tile width:")) hl1.addSpacing(5) hl1.addWidget(self.tileWidthSpinBox) hl1.addSpacing(15) hl1.addWidget(QLabel("Tile height:")) hl1.addSpacing(5) hl1.addWidget(self.tileHeightSpinBox) hl1.addSpacing(15) hl1.addWidget(QLabel("Padding:")) hl1.addSpacing(5) hl1.addWidget(self.paddingSpinBox) hl1.addSpacing(15) hl1.addWidget(self.forcePotCheckBox) hl1.addSpacing(15) hl1.addWidget(self.reorderTilesCheckBox) hl1.addStretch() hl2 = QHBoxLayout() hl2.setContentsMargins(5, 5, 5, 5) hl2.addWidget(self.transparentCheckbox) hl2.addSpacing(15) hl2.addWidget(self.backgroundColorLabel) hl2.addSpacing(5) hl2.addWidget(self.backgroundColorEdit) hl2.addStretch() hl3 = QHBoxLayout() hl3.setContentsMargins(5, 5, 5, 5) hl3.addWidget(self.generateAndExportButton) vl = QVBoxLayout() vl.setContentsMargins(0, 0, 0, 0) vl.setSpacing(0) vl.addLayout(hl1) vl.addLayout(hl2) vl.addWidget(self.pixmapWidget) vl.addLayout(hl3) w = QWidget() w.setLayout(vl) self.setCentralWidget(w) self.setTitle() def setTitle(self): p = ' - ' + os.path.basename(self.path) if self.path else '' self.setWindowTitle(QCoreApplication.applicationName() + ' ' + QCoreApplication.applicationVersion() + p) def createDropTextPixmap(self): pixmap = QPixmap(481, 300) pixmap.fill(QColor("#333333")) painter = QPainter(pixmap) font = QFont("Arial") font.setPixelSize(28) font.setBold(True) fm = QFontMetrics(font) painter.setFont(font) painter.setPen(QPen(QColor("#888888"), 1)) text = "Drop the tileset image here" x = (pixmap.width()-fm.width(text))/2 y = (pixmap.height()+fm.height())/2 painter.drawText(x, y, text) del painter return pixmap def fileDropped(self, path): path = str(path) name, ext = os.path.splitext(path) ext = ext[1:] if not ext in self.supportedFormats: QMessageBox.warning(self, "Warning", "The dropped file is not supported") return pixmap = QPixmap(path) if pixmap.isNull(): QMessageBox.warning(self, "Warning", "Can't load the image") return if self.path: self.fileWatcher.removePath(self.path) self.path = path self.fileWatcher.addPath(self.path) self.pixmapWidget.setPixmap(pixmap) self.generateAndExportButton.setEnabled(True) self.setTitle() self.activateWindow() def fileChanged(self, path): #self.fileDropped(path) pass def transparentChanged(self): e = self.transparentCheckbox.isChecked() self.backgroundColorEdit.setEnabled(not e) self.backgroundColorLabel.setEnabled(not e) def forcePotChanged(self): e = self.forcePotCheckBox.isChecked() self.reorderTilesCheckBox.setEnabled(e) def generateAndExportClicked(self): g = Generator() g.tileWidth = self.tileWidthSpinBox.value() g.tileHeight = self.tileHeightSpinBox.value() g.forcePot = self.forcePotCheckBox.isChecked() g.isTransparent = self.transparentCheckbox.isChecked() g.bgColor = self.backgroundColorEdit.getColor() g.reorder = self.reorderTilesCheckBox.isChecked() g.padding = self.paddingSpinBox.value() target = g.create(self.pixmapWidget.pixmap); # export self.lastDir = os.path.dirname(self.path) targetPath = QFileDialog.getSaveFileName(self, 'Export', self.lastDir, 'PNG (*.png)') if targetPath: target.save(targetPath[0]) showPixmap = QPixmap.fromImage(target) if self.showPixmapWidget: self.showPixmapWidget.deleteLater() del self.showPixmapWidget self.showPixmapWidget = PixmapWidget() self.showPixmapWidget.setWindowIcon(self.windowIcon()) self.showPixmapWidget.setWindowTitle(os.path.basename(targetPath[0])) self.showPixmapWidget.resize(showPixmap.width(), showPixmap.height()) self.showPixmapWidget.setPixmap(showPixmap) self.showPixmapWidget.show() def closeEvent(self, event): if self.showPixmapWidget: self.showPixmapWidget.close() # save settings self.settings.setValue('tileWidth', self.tileWidthSpinBox.value()) self.settings.setValue('tileHeight', self.tileHeightSpinBox.value()) self.settings.setValue('padding', self.paddingSpinBox.value()) self.settings.setValue('forcePot', self.forcePotCheckBox.isChecked()) self.settings.setValue('reorderTiles', self.reorderTilesCheckBox.isChecked()) self.settings.setValue('transparent', self.transparentCheckbox.isChecked()) self.settings.setValue('backgroundColor', self.backgroundColorEdit.getColor().name()) self.settings.setValue('lastDir', self.lastDir) self.settings.setValue('MainWindow/geometry', self.saveGeometry()) self.settings.setValue('MainWindow/windowState', self.saveState()) super(MainWindow, self).closeEvent(event)