Ejemplo n.º 1
0
    def addThreadList(self,threads):

        if not self.groupBoxThreadInfo:
            self.groupBoxThreadInfo = QGroupBox()
            self.threadInfo = QLabel("Thread Info.")
            self.groupBoxThreadInfo.setStyleSheet("QGroupBox {border: 1px solid gray; border-radius: 9px; margin-top: 0.5em} QGroupBox::title {subcontrol-origin: margin; left: 10px; padding: 0 3px 0 3px;")

        if not self.threadvbox:
            self.threadvbox = QVBoxLayout()

        if not self.listThread:
            self.listThread = QListWidget()
            
        self.listThread.setFixedWidth(200)
        self.listThread.setSelectionMode(QAbstractItemView.MultiSelection)
        QtCore.QObject.connect(self.listThread, QtCore.SIGNAL("itemClicked(QListWidgetItem *)"), self.toggleThreadDisplay)
        self.threadvbox.addWidget(self.threadInfo)
        self.threadvbox.addWidget(self.listThread)
        self.groupBoxThreadInfo.setLayout(self.threadvbox)
        self.addWidget(self.groupBoxThreadInfo)
        self.groupBoxThreadInfo.setSizePolicy(self.sizePolicy)

        for id in threads:
            item = QListWidgetItem(id)
            self.listThread.addItem(item)
Ejemplo n.º 2
0
    def createRotableGroupBox(self):
        self.rotableGroupBox = QGroupBox("Rotable Widgets")

        self.rotableWidgets.append(QSpinBox())
        self.rotableWidgets.append(QSlider())
        self.rotableWidgets.append(QDial())
        self.rotableWidgets.append(QProgressBar())
        count = len(self.rotableWidgets)
        for i in range(count):
            self.rotableWidgets[i].valueChanged[int].\
                connect(self.rotableWidgets[(i+1) % count].setValue)

        self.rotableLayout = QGridLayout()
        self.rotableGroupBox.setLayout(self.rotableLayout)

        self.rotateWidgets()
Ejemplo n.º 3
0
    def createOptionsGroupBox(self):
        self.optionsGroupBox = QGroupBox("Options")

        buttonsOrientationLabel = QLabel("Orientation of buttons:")

        buttonsOrientationComboBox = QComboBox()
        buttonsOrientationComboBox.addItem("Horizontal", Qt.Horizontal)
        buttonsOrientationComboBox.addItem("Vertical", Qt.Vertical)
        buttonsOrientationComboBox.currentIndexChanged[int].connect(self.buttonsOrientationChanged)

        self.buttonsOrientationComboBox = buttonsOrientationComboBox

        optionsLayout = QGridLayout()
        optionsLayout.addWidget(buttonsOrientationLabel, 0, 0)
        optionsLayout.addWidget(self.buttonsOrientationComboBox, 0, 1)
        optionsLayout.setColumnStretch(2, 1)
        self.optionsGroupBox.setLayout(optionsLayout)
Ejemplo n.º 4
0
    def create_gestures_group_box(self):
        gestures_group_box = QGroupBox()
        gridLayout = QGridLayout()

        icon_size = QSize(150, 100)
        path_to_images = '../gestures/photos/'

        button_nothing = QPushButton()
        button_nothing.clicked.connect(
            lambda: self.on_gesture_selection(Gestures.nothing))
        button_nothing.setIcon(QIcon(path_to_images + 'nothing.jpg'))
        gridLayout.addWidget(button_nothing, 0, 0)
        self.gesture_buttons[Gestures.nothing] = button_nothing

        button_rock = QPushButton()
        button_rock.clicked.connect(
            lambda: self.on_gesture_selection(Gestures.rock))
        button_rock.setIcon(QIcon(path_to_images + 'rock.jpg'))
        gridLayout.addWidget(button_rock, 0, 1)
        self.gesture_buttons[Gestures.rock] = button_rock

        button_scissors = QPushButton()
        button_scissors.clicked.connect(
            lambda: self.on_gesture_selection(Gestures.scissors))
        button_scissors.setIcon(QIcon(path_to_images + 'scissors.jpg'))
        gridLayout.addWidget(button_scissors, 0, 2)
        self.gesture_buttons[Gestures.scissors] = button_scissors

        button_paper = QPushButton()
        button_paper.clicked.connect(
            lambda: self.on_gesture_selection(Gestures.paper))
        button_paper.setIcon(QIcon(path_to_images + 'paper.jpg'))
        gridLayout.addWidget(button_paper, 1, 0)
        self.gesture_buttons[Gestures.paper] = button_paper

        button_ok = QPushButton()
        button_ok.clicked.connect(
            lambda: self.on_gesture_selection(Gestures.ok))
        button_ok.setIcon(QIcon(path_to_images + 'ok.jpg'))
        gridLayout.addWidget(button_ok, 1, 1)
        self.gesture_buttons[Gestures.ok] = button_ok

        button_horns = QPushButton()
        button_horns.clicked.connect(
            lambda: self.on_gesture_selection(Gestures.horns))
        button_horns.setIcon(QIcon(path_to_images + 'horns.jpg'))
        gridLayout.addWidget(button_horns, 1, 2)
        self.gesture_buttons[Gestures.horns] = button_horns

        button_shaka = QPushButton()
        button_shaka.clicked.connect(
            lambda: self.on_gesture_selection(Gestures.shaka))
        button_shaka.setIcon(QIcon(path_to_images + 'shaka.jpg'))
        gridLayout.addWidget(button_shaka, 2, 0)
        self.gesture_buttons[Gestures.shaka] = button_shaka

        button_gun = QPushButton()
        button_gun.clicked.connect(
            lambda: self.on_gesture_selection(Gestures.gun))
        button_gun.setIcon(QIcon(path_to_images + 'gun.jpg'))
        gridLayout.addWidget(button_gun, 2, 1)
        self.gesture_buttons[Gestures.gun] = button_gun

        button_thumb = QPushButton()
        button_thumb.clicked.connect(
            lambda: self.on_gesture_selection(Gestures.thumbs_up))
        button_thumb.setIcon(QIcon(path_to_images + 'thumbs_up.jpg'))
        gridLayout.addWidget(button_thumb, 2, 2)
        self.gesture_buttons[Gestures.thumbs_up] = button_thumb

        for button in self.gesture_buttons.values():
            button.setEnabled(False)
            button.setCheckable(True)
            button.setIconSize(icon_size)

        gestures_group_box.setLayout(gridLayout)
        return gestures_group_box
Ejemplo n.º 5
0
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)
Ejemplo n.º 6
0
    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)
Ejemplo n.º 7
0
class MyDockWidget(cutter.CutterDockWidget):
    def __init__(self, parent, action):
        super(MyDockWidget, self).__init__(parent, action)
        self.setObjectName("Capa explorer")
        self.setWindowTitle("Capa explorer")

        self._config = CutterBindings.Configuration.instance()
        self.model_data = CapaExplorerDataModel()

        self.range_model_proxy = CapaExplorerRangeProxyModel()
        self.range_model_proxy.setSourceModel(self.model_data)
        self.search_model_proxy = CapaExplorerSearchProxyModel()
        self.search_model_proxy.setSourceModel(self.range_model_proxy)

        self.create_view_tabs()
        self.create_menu()
        self.create_tree_tab_ui()
        self.create_view_attack()

        self.connect_signals()
        self.setWidget(self.tabs)
        self.show()

    def create_view_tabs(self):

        # Create tabs container
        self.tabs = QTabWidget()

        # Create the tabs
        self.tab_attack = QWidget(self.tabs)
        self.tab_tree_w_model = QWidget(self.tabs)

        self.tabs.addTab(self.tab_tree_w_model, "Tree View")
        self.tabs.addTab(self.tab_attack, "MITRE")

    def create_menu(self):
        # Define menu actions
        # Text, tooltip, function, enabled before file load
        self.disabled_menu_items = []

        menu_actions = [
            ("Load JSON file", '', self.cma_load_file, True),
            (),
            ("Auto rename functions",
             'Auto renames functions according to capa detections, can result in very long function names.',
             self.cma_analyze_and_rename, False),
            ("Create flags",
             'Creates flagspaces and flags from capa detections.',
             self.cma_create_flags, False),
            (),
            ("About", '', self.cma_display_about, True),
        ]

        self.capa_menu = QMenu()
        self.capa_menu.setToolTipsVisible(True)

        # Create qactions
        for action in menu_actions:
            if not len(action):
                # Create separator on empty
                self.capa_menu.addSeparator()
                continue

            a = QAction(self)
            a.setText(action[0])
            a.setToolTip(action[1])
            a.triggered.connect(action[2])
            a.setEnabled(action[3])
            if not action[3]:
                self.disabled_menu_items.append(a)
            self.capa_menu.addAction(a)

            # Create menu button
            font = QFont()
            font.setBold(True)
            self.btn_menu = QToolButton()
            self.btn_menu.setText('...')
            self.btn_menu.setFont(font)
            self.btn_menu.setPopupMode(QToolButton.InstantPopup)
            self.btn_menu.setMenu(self.capa_menu)
            self.btn_menu.setStyleSheet(
                'QToolButton::menu-indicator { image: none; }')
            self.tabs.setCornerWidget(self.btn_menu, corner=Qt.TopRightCorner)

    def create_tree_tab_ui(self):
        self.capa_tree_view_layout = QVBoxLayout()
        self.capa_tree_view_layout.setAlignment(Qt.AlignTop)

        self.chk_fcn_scope = QCheckBox("Limit to Current function")
        #TODO: reset state on load file
        self.chk_fcn_scope.setChecked(False)
        self.chk_fcn_scope.stateChanged.connect(
            self.slot_checkbox_limit_by_changed)

        self.input_search = QLineEdit()
        self.input_search.setStyleSheet("margin:0px; padding:0px;")
        self.input_search.setPlaceholderText("search...")
        self.input_search.textChanged.connect(
            self.slot_limit_results_to_search)

        self.filter_controls_container = QGroupBox()
        self.filter_controls_container.setObjectName("scope")
        self.filter_controls_container.setFlat(True)
        self.filter_controls_container.setStyleSheet(
            "#scope{border:0px; padding:0px; margin:0px;subcontrol-origin: padding; subcontrol-position: left top;}"
        )
        self.filter_controls_layout = QHBoxLayout(
            self.filter_controls_container)
        self.filter_controls_layout.setContentsMargins(0, 0, 0, 0)
        self.filter_controls_layout.addWidget(self.input_search)
        self.filter_controls_layout.addWidget(self.chk_fcn_scope)

        self.view_tree = CapaExplorerQtreeView(self.search_model_proxy)
        self.view_tree.setModel(self.search_model_proxy)

        # Make it look a little nicer when no results are loaded
        self.view_tree.header().setStretchLastSection(True)

        self.capa_tree_view_layout.addWidget(self.filter_controls_container)
        self.capa_tree_view_layout.addWidget(self.view_tree)
        self.tab_tree_w_model.setLayout(self.capa_tree_view_layout)

    def create_view_attack(self):
        table_headers = [
            "ATT&CK Tactic",
            "ATT&CK Technique ",
        ]
        table = QTableWidget()
        table.setColumnCount(len(table_headers))
        table.verticalHeader().setVisible(False)
        table.setSortingEnabled(False)
        table.setEditTriggers(QAbstractItemView.NoEditTriggers)
        table.setFocusPolicy(Qt.NoFocus)
        table.setSelectionMode(QAbstractItemView.NoSelection)
        table.setHorizontalHeaderLabels(table_headers)
        table.horizontalHeader().setDefaultAlignment(Qt.AlignLeft)
        table.horizontalHeader().setStretchLastSection(True)
        table.setShowGrid(False)
        table.horizontalHeader().setSectionResizeMode(
            0, QHeaderView.ResizeToContents)
        table.horizontalHeader().setSectionResizeMode(1, QHeaderView.Stretch)
        #table.setStyleSheet("QTableWidget::item { padding: 25px; }")

        attack_view_layout = QVBoxLayout()
        attack_view_layout.setAlignment(Qt.AlignTop)

        self.attack_table = table

        attack_view_layout.addWidget(self.attack_table)
        self.tab_attack.setLayout(attack_view_layout)

        return table

    def connect_signals(self):

        QObject.connect(cutter.core(), SIGNAL("functionRenamed(RVA, QString)"),
                        self.model_data.refresh_function_names)
        QObject.connect(cutter.core(), SIGNAL("functionsChanged()"),
                        self.model_data.refresh_function_names)
        QObject.connect(cutter.core(), SIGNAL("seekChanged(RVA)"),
                        self.signal_shim_slot_checkbox_limit_by_changed)

    def render_new_table_header_item(self, text):
        """create new table header item with our style
        @param text: header text to display
        """
        item = QTableWidgetItem(text)
        item.setForeground(self._config.getColor("graph.true"))
        font = QFont()
        font.setBold(True)
        item.setFont(font)
        return item

    def fill_attack_table(self, rules):
        tactics = collections.defaultdict(set)
        for key, rule in rules.items():
            if not rule["meta"].get("att&ck"):
                continue

            for attack in rule["meta"]["att&ck"]:
                tactic, _, rest = attack.partition("::")
            if "::" in rest:
                technique, _, rest = rest.partition("::")
                subtechnique, _, id = rest.rpartition(" ")
                tactics[tactic].add((technique, subtechnique, id))
            else:
                technique, _, id = rest.rpartition(" ")
                tactics[tactic].add((technique, id))

        column_one = []
        column_two = []

        for (tactic, techniques) in sorted(tactics.items()):
            column_one.append(tactic.upper())
            # add extra space when more than one technique
            column_one.extend(["" for i in range(len(techniques) - 1)])

            for spec in sorted(techniques):
                if len(spec) == 2:
                    technique, id = spec
                    column_two.append("%s %s" % (technique, id))
                elif len(spec) == 3:
                    technique, subtechnique, id = spec
                    column_two.append("%s::%s %s" %
                                      (technique, subtechnique, id))
                else:
                    raise RuntimeError("unexpected ATT&CK spec format")

        self.attack_table.setRowCount(max(len(column_one), len(column_two)))

        for (row, value) in enumerate(column_one):
            self.attack_table.setItem(row, 0,
                                      self.render_new_table_header_item(value))

        for (row, value) in enumerate(column_two):
            self.attack_table.setItem(row, 1, QTableWidgetItem(value))

    def enable_menu_items_after_load(self):
        # enables menu actions after file is loaded
        for action in self.disabled_menu_items:
            action.setEnabled(True)

    def slot_limit_results_to_search(self, text):
        """limit tree view results to search matches
        reset view after filter to maintain level 1 expansion
        """
        self.search_model_proxy.set_query(text)
        self.view_tree.reset_ui(should_sort=False)

    def signal_shim_slot_checkbox_limit_by_changed(self):
        if self.chk_fcn_scope.isChecked():
            self.slot_checkbox_limit_by_changed(Qt.Checked)

    def slot_checkbox_limit_by_changed(self, state):
        """slot activated if checkbox clicked
        if checked, configure function filter if screen location is located in function, otherwise clear filter
        @param state: checked state
        """
        invoke_reset = True

        if state == Qt.Checked:
            minbound, maxbound = util.get_function_boundries_at_current_location(
            )

            if self.range_model_proxy.min_ea == minbound and self.range_model_proxy.max_ea == maxbound:
                # Seek only changed within current function, avoid resetting tree
                invoke_reset = False

            self.limit_results_to_function((minbound, maxbound))
        else:
            self.range_model_proxy.reset_address_range_filter()

        if invoke_reset:
            self.view_tree.reset_ui()

    def limit_results_to_function(self, f):
        """add filter to limit results to current function
        adds new address range filter to include function bounds, allowing basic blocks matched within a function
        to be included in the results
        @param f: (tuple (maxbound, minbound))
        """
        if f:
            self.range_model_proxy.add_address_range_filter(f[0], f[1])
        else:
            # if function not exists don't display any results (assume address never -1)
            self.range_model_proxy.add_address_range_filter(-1, -1)

    # --- Menu Actions

    def cma_analyze_and_rename(self):
        message_box = QMessageBox()

        message_box.setStyleSheet("QLabel{min-width: 370px;}")
        message_box.setStandardButtons(QMessageBox.Cancel | QMessageBox.Ok)
        message_box.setEscapeButton(QMessageBox.Cancel)
        message_box.setDefaultButton(QMessageBox.Ok)

        message_box.setWindowTitle('Warning')
        message_box.setText(
            'Depending on the size of the binary and the'
            ' amount of \n'
            'capa matches this feature can take some time to \n'
            'complete and might make the UI freeze temporarily.')
        message_box.setInformativeText('Are you sure you want to proceed ?')

        ret = message_box.exec_()

        # Ok = 1024
        if ret == 1024:
            self.model_data.auto_rename_functions()

    def cma_create_flags(self):
        self.model_data.create_flags()

    def cma_display_about(self):
        c = CAPAExplorerPlugin()

        info_text = ("{description}\n\n"
                     "https://github.com/ninewayhandshake/capa-explorer\n\n"
                     "Version: {version}\n"
                     "Author: {author}\n"
                     "License: Apache License 2.0\n").format(
                         version=c.version,
                         author=c.author,
                         description=c.description,
                     )

        text = CAPAExplorerPlugin().name
        message_box = QMessageBox()
        message_box.setStyleSheet("QLabel{min-width: 370px;}")

        message_box.setWindowTitle('About')
        message_box.setText(text)
        message_box.setInformativeText(info_text)
        message_box.setStandardButtons(QMessageBox.Close)

        for i in message_box.findChildren(QLabel):
            i.setFocusPolicy(Qt.NoFocus)

        message_box.exec_()

    def cma_load_file(self):

        filename = QFileDialog.getOpenFileName()
        path = filename[0]

        if len(path):
            try:
                data = util.load_capa_json(path)

                self.fill_attack_table(data['rules'])
                self.model_data.clear()
                self.model_data.render_capa_doc(data)

                # Restore ability to scroll on last column
                self.view_tree.header().setStretchLastSection(False)

                self.view_tree.slot_resize_columns_to_content()
                self.enable_menu_items_after_load()
            except Exception as e:
                util.log('Could not load json file.')
        else:
            util.log('No file selected.')
Ejemplo n.º 8
0
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.type_combo.setCurrentText("double")

        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)
Ejemplo n.º 9
0
    def __init__(self):
        QMainWindow.__init__(self)
        self.setWindowTitle("Spot Extractor")

        menuBar = self.buildMenuBar()
        widget = QWidget(self)
        layout = QGridLayout(widget)

        # Main Image Window
        self.scrollArea = QScrollArea()
        self.imageLabel = ImageLabel(self)
        self.scrollArea.setWidget(self.imageLabel)

        # Text Label for Lot Name
        self.lotNameTextField = QLineEdit()
        self.lotNameTextField.setFixedWidth(300)

        # Spot List
        self.spotList = SpotListWidget(self)

        # Image Box Layout
        imageGroupBox = QGroupBox("Image")
        imageLayout = QHBoxLayout()
        imageLayout.addWidget(self.scrollArea)
        imageGroupBox.setLayout(imageLayout)

        # Spot List Box Layout
        rightGroupBox = QGroupBox()
        rightGroupBox.setMaximumWidth(300)
        rightGroupLayout = QVBoxLayout()

        lotNameGroupBox = QGroupBox("Lot Name")
        lotNameLayout = QHBoxLayout()
        lotNameLayout.addWidget(self.lotNameTextField)
        lotNameGroupBox.setLayout(lotNameLayout)

        spotsGroupBox = QGroupBox("Spot List")
        spotsLayout = QHBoxLayout()
        spotsLayout.addWidget(self.spotList)
        spotsGroupBox.setLayout(spotsLayout)

        rightGroupLayout.addWidget(lotNameGroupBox)
        rightGroupLayout.addWidget(spotsGroupBox)
        rightGroupBox.setLayout(rightGroupLayout)

        # Control Buttons Box Layout
        horizontalGroupBox = QGroupBox("Control Buttons")
        controlButtonLayout = QHBoxLayout()
        checkAllButton = QPushButton("Check All")
        uncheckAllButton = QPushButton("Uncheck All")
        deleteCheckedButton = QPushButton("Delete Checked")
        checkAllButton.clicked.connect(self.checkAll)
        uncheckAllButton.clicked.connect(self.uncheckAll)
        deleteCheckedButton.clicked.connect(self.deleteAllChecked)
        controlButtonLayout.addWidget(checkAllButton)
        controlButtonLayout.addWidget(uncheckAllButton)
        controlButtonLayout.addWidget(deleteCheckedButton)
        horizontalGroupBox.setLayout(controlButtonLayout)

        layout.addWidget(imageGroupBox, 0, 0)
        layout.addWidget(rightGroupBox, 0, 1)
        layout.addWidget(horizontalGroupBox, 1, 0, 1, 2)

        self.setMenuBar(menuBar)
        self.setLayout(layout)
        self.setCentralWidget(widget)
Ejemplo n.º 10
0
class QGroundObjectMenu(QDialog):

    changed = QtCore.Signal()

    def __init__(self, parent, ground_object: TheaterGroundObject,
                 buildings: [], cp: ControlPoint, game: Game):
        super(QGroundObjectMenu, self).__init__(parent)
        self.setMinimumWidth(350)
        self.ground_object = ground_object
        self.buildings = buildings
        self.cp = cp
        self.game = game
        self.setWindowTitle("Location " + self.ground_object.obj_name)
        self.setWindowIcon(EVENT_ICONS["capture"])
        self.intelBox = QGroupBox("Units :")
        self.buildingBox = QGroupBox("Buildings :")
        self.intelLayout = QGridLayout()
        self.buildingsLayout = QGridLayout()
        self.sell_all_button = None
        self.total_value = 0
        self.init_ui()

    def init_ui(self):

        self.mainLayout = QVBoxLayout()
        self.budget = QBudgetBox(self.game)
        self.budget.setGame(self.game)

        self.doLayout()

        if self.ground_object.dcs_identifier == "AA":
            self.mainLayout.addWidget(self.intelBox)
        else:
            self.mainLayout.addWidget(self.buildingBox)

        self.actionLayout = QHBoxLayout()

        self.sell_all_button = QPushButton("Disband (+" +
                                           str(self.total_value) + "M)")
        self.sell_all_button.clicked.connect(self.sell_all)
        self.sell_all_button.setProperty("style", "btn-danger")

        self.buy_replace = QPushButton("Buy/Replace")
        self.buy_replace.clicked.connect(self.buy_group)
        self.buy_replace.setProperty("style", "btn-success")

        if self.total_value > 0:
            self.actionLayout.addWidget(self.sell_all_button)
        self.actionLayout.addWidget(self.buy_replace)

        if self.cp.captured and self.ground_object.dcs_identifier == "AA":
            self.mainLayout.addLayout(self.actionLayout)
        self.setLayout(self.mainLayout)

    def doLayout(self):

        self.update_total_value()
        self.intelBox = QGroupBox("Units :")
        self.intelLayout = QGridLayout()
        i = 0
        for g in self.ground_object.groups:
            if not hasattr(g, "units_losts"):
                g.units_losts = []
            for u in g.units:
                self.intelLayout.addWidget(
                    QLabel("<b>Unit #" + str(u.id) + " - " + str(u.type) +
                           "</b>"), i, 0)
                i = i + 1

            for u in g.units_losts:

                utype = unit_type_of(u)
                if utype in PRICES:
                    price = PRICES[utype]
                else:
                    price = 6

                self.intelLayout.addWidget(
                    QLabel("<b>Unit #" + str(u.id) + " - " + str(u.type) +
                           "</b> [DEAD]"), i, 0)
                if self.cp.captured:
                    repair = QPushButton("Repair [" + str(price) + "M]")
                    repair.setProperty("style", "btn-success")
                    repair.clicked.connect(
                        lambda u=u, g=g, p=price: self.repair_unit(g, u, p))
                    self.intelLayout.addWidget(repair, i, 1)
                i = i + 1
        stretch = QVBoxLayout()
        stretch.addStretch()
        self.intelLayout.addLayout(stretch, i, 0)

        self.buildingBox = QGroupBox("Buildings :")
        self.buildingsLayout = QGridLayout()
        j = 0
        for i, building in enumerate(self.buildings):
            if building.dcs_identifier not in FORTIFICATION_BUILDINGS:
                self.buildingsLayout.addWidget(
                    QBuildingInfo(building, self.ground_object), j / 3, j % 3)
                j = j + 1

        self.buildingBox.setLayout(self.buildingsLayout)
        self.intelBox.setLayout(self.intelLayout)

    def do_refresh_layout(self):
        try:
            for i in range(self.mainLayout.count()):
                item = self.mainLayout.itemAt(i)
                if item is not None and item.widget() is not None:
                    item.widget().setParent(None)
            self.sell_all_button.setParent(None)
            self.buy_replace.setParent(None)
            self.actionLayout.setParent(None)

            self.doLayout()
            if self.ground_object.dcs_identifier == "AA":
                self.mainLayout.addWidget(self.intelBox)
            else:
                self.mainLayout.addWidget(self.buildingBox)

            self.actionLayout = QHBoxLayout()
            if self.total_value > 0:
                self.actionLayout.addWidget(self.sell_all_button)
            self.actionLayout.addWidget(self.buy_replace)

            if self.cp.captured and self.ground_object.dcs_identifier == "AA":
                self.mainLayout.addLayout(self.actionLayout)

        except Exception as e:
            print(e)
        self.update_total_value()
        self.changed.emit()

    def update_total_value(self):
        total_value = 0
        for group in self.ground_object.groups:
            for u in group.units:
                utype = unit_type_of(u)
                if utype in PRICES:
                    total_value = total_value + PRICES[utype]
                else:
                    total_value = total_value + 1
        if self.sell_all_button is not None:
            self.sell_all_button.setText("Disband (+$" +
                                         str(self.total_value) + "M)")
        self.total_value = total_value

    def repair_unit(self, group, unit, price):
        if self.game.budget > price:
            self.game.budget -= price
            group.units_losts = [
                u for u in group.units_losts if u.id != unit.id
            ]
            group.units.append(unit)
            GameUpdateSignal.get_instance().updateGame(self.game)

            # Remove destroyed units in the vicinity
            destroyed_units = self.game.get_destroyed_units()
            for d in destroyed_units:
                p = Point(d["x"], d["z"])
                if p.distance_to_point(unit.position) < 15:
                    destroyed_units.remove(d)
                    logging.info("Removed destroyed units " + str(d))
            logging.info("Repaired unit : " + str(unit.id) + " " +
                         str(unit.type))

        self.do_refresh_layout()
        self.changed.emit()

    def sell_all(self):
        self.update_total_value()
        self.game.budget = self.game.budget + self.total_value
        self.ground_object.groups = []
        self.do_refresh_layout()
        GameUpdateSignal.get_instance().updateBudget(self.game)

    def buy_group(self):
        self.subwindow = QBuyGroupForGroundObjectDialog(
            self, self.ground_object, self.cp, self.game, self.total_value)
        self.subwindow.changed.connect(self.do_refresh_layout)
        self.subwindow.show()
Ejemplo n.º 11
0
    def initUI(self):

        self.layout = QVBoxLayout()

        header = QLabel(self)
        header.setGeometry(0, 0, 655, 106)
        pixmap = QPixmap("./resources/ui/debriefing.png")
        header.setPixmap(pixmap)
        self.layout.addWidget(header)
        self.layout.addStretch()

        # Result
        #if self.gameEvent.is_successfull(self.debriefing):
        #    title = QLabel("<b>Operation end !</b>")
        #    title.setProperty("style", "title-success")
        #else:
        #    title = QLabel("<b>Operation end !</b>")
        #    title.setProperty("style", "title-danger")
        title = QLabel("<b>Casualty report</b>")
        self.layout.addWidget(title)

        # Player lost units
        lostUnits = QGroupBox(self.game.player_country + "'s lost units :")
        lostUnitsLayout = QGridLayout()
        lostUnits.setLayout(lostUnitsLayout)

        row = 0
        for unit_type, count in self.debriefing.player_dead_aircraft_dict.items(
        ):
            try:
                lostUnitsLayout.addWidget(QLabel(db.unit_type_name(unit_type)),
                                          row, 0)
                lostUnitsLayout.addWidget(QLabel("{}".format(count)), row, 1)
                row += 1
            except:
                print("Issue adding " + str(unit_type) +
                      " to debriefing information")

        for unit_type, count in self.debriefing.player_dead_units_dict.items():
            try:
                lostUnitsLayout.addWidget(QLabel(db.unit_type_name(unit_type)),
                                          row, 0)
                lostUnitsLayout.addWidget(QLabel("{}".format(count)), row, 1)
                row += 1
            except:
                print("Issue adding " + str(unit_type) +
                      " to debriefing information")

        for building, count in self.debriefing.player_dead_buildings_dict.items(
        ):
            try:
                lostUnitsLayout.addWidget(QLabel(building, row, 0))
                lostUnitsLayout.addWidget(QLabel("{}".format(count)), row, 1)
                row += 1
            except:
                print("Issue adding " + str(building) +
                      " to debriefing information")

        self.layout.addWidget(lostUnits)

        # Enemy lost units
        enemylostUnits = QGroupBox(self.game.enemy_country + "'s lost units :")
        enemylostUnitsLayout = QGridLayout()
        enemylostUnits.setLayout(enemylostUnitsLayout)

        #row = 0
        #if self.debriefing.destroyed_objects:
        #    enemylostUnitsLayout.addWidget(QLabel("Ground assets"), row, 0)
        #    enemylostUnitsLayout.addWidget(QLabel("{}".format(len(self.debriefing.destroyed_objects))), row, 1)
        #    row += 1

        for unit_type, count in self.debriefing.enemy_dead_aircraft_dict.items(
        ):
            if count == 0:
                continue
            try:
                enemylostUnitsLayout.addWidget(
                    QLabel(db.unit_type_name(unit_type)), row, 0)
                enemylostUnitsLayout.addWidget(QLabel("{}".format(count)), row,
                                               1)
                row += 1
            except:
                print("Issue adding " + str(unit_type) +
                      " to debriefing information")

        for unit_type, count in self.debriefing.enemy_dead_units_dict.items():
            if count == 0:
                continue
            enemylostUnitsLayout.addWidget(
                QLabel(db.unit_type_name(unit_type)), row, 0)
            enemylostUnitsLayout.addWidget(QLabel("{}".format(count)), row, 1)
            row += 1

        for building, count in self.debriefing.enemy_dead_buildings_dict.items(
        ):
            try:
                enemylostUnitsLayout.addWidget(QLabel(building), row, 0)
                enemylostUnitsLayout.addWidget(QLabel("{}".format(count)), row,
                                               1)
                row += 1
            except:
                print("Issue adding " + str(building) +
                      " to debriefing information")

        self.layout.addWidget(enemylostUnits)

        # confirm button
        okay = QPushButton("Okay")
        okay.clicked.connect(self.close)
        self.layout.addWidget(okay)

        self.setLayout(self.layout)
    def __init__(self, m1m3):
        super().__init__()
        self.m1m3 = m1m3

        self.xIndex = self.yIndex = self.zIndex = self.sIndex = self.testedId = None
        self._testRunning = False

        actuatorBox = QGroupBox("Actuator")
        self.actuatorsTable = QTableWidget(
            max([row[FATABLE_ID] for row in FATABLE]) % 100, 12
        )
        self.actuatorsTable.setShowGrid(False)

        def setNone(r, c):
            item = QTableWidgetItem("")
            item.setFlags(Qt.NoItemFlags)
            self.actuatorsTable.setItem(r, c, item)

        for i in range(4):
            mr = min(
                [
                    row[FATABLE_ID]
                    for row in FATABLE
                    if row[FATABLE_ID] > (100 + 100 * i)
                ]
            )
            for r in range(mr):
                for c in range(i * 3, (i * 3) + 2):
                    setNone(r, c)

        for tr in range(len(FATABLE)):
            actuatorId = FATABLE[tr][FATABLE_ID]
            row = (actuatorId % 100) - 1
            colOffset = 3 * (int(actuatorId / 100) - 1)

            def getItem(text):
                item = QTableWidgetItem(text)
                item.setData(Qt.UserRole, actuatorId)
                return item

            self.actuatorsTable.setItem(row, 0 + colOffset, getItem(str(actuatorId)))
            self.actuatorsTable.setItem(row, 1 + colOffset, getItem("P"))
            if FATABLE[tr][FATABLE_SINDEX] is None:
                setNone(row, 2 + colOffset)
            else:
                self.actuatorsTable.setItem(
                    row,
                    2 + colOffset,
                    getItem("Y" if (FATABLE[tr][FATABLE_XINDEX] is None) else "X"),
                )

        self.actuatorsTable.horizontalHeader().hide()
        self.actuatorsTable.horizontalHeader().setSectionResizeMode(
            QHeaderView.ResizeToContents
        )
        self.actuatorsTable.horizontalHeader().setStretchLastSection(False)
        self.actuatorsTable.verticalHeader().hide()
        self.actuatorsTable.verticalHeader().setSectionResizeMode(
            QHeaderView.ResizeToContents
        )

        self.actuatorsTable.itemSelectionChanged.connect(self.itemSelectionChanged)
        self.actuatorsTable.setSizePolicy(
            QSizePolicy.Minimum, QSizePolicy.MinimumExpanding
        )
        self.actuatorsTable.setFixedWidth(
            sum([self.actuatorsTable.columnWidth(c) for c in range(12)])
            + self.actuatorsTable.verticalScrollBar().geometry().height() / 2
            + 1
        )
        actuatorLayout = QVBoxLayout()
        actuatorLayout.addWidget(self.actuatorsTable)
        actuatorBox.setLayout(actuatorLayout)

        def testPB():
            pb = QProgressBar()
            pb.setMaximum(6)
            return pb

        self.primaryPB = testPB()
        self.primaryLabelPB = QLabel("Primary")

        self.secondaryPB = testPB()
        self.secondaryLabelPB = QLabel("Seconday")

        self.progressGroup = QGroupBox("Test progress")
        progressLayout = QGridLayout()
        progressLayout.addWidget(self.primaryLabelPB, 0, 0)
        progressLayout.addWidget(self.primaryPB, 0, 1)
        progressLayout.addWidget(self.secondaryLabelPB, 1, 0)
        progressLayout.addWidget(self.secondaryPB, 1, 1)
        # progressLayout.addStretch(1)
        self.progressGroup.setLayout(progressLayout)
        self.progressGroup.setMaximumWidth(410)

        self.chart = None
        self.chart_view = TimeChartView()
        self.chart_view.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)

        def makeButton(text, clicked):
            button = QPushButton(text)
            button.setEnabled(False)
            button.clicked.connect(clicked)
            return button

        self.bumpTestAllButton = makeButton("Bump test all", self.bumpTestAll)
        self.bumpTestButton = makeButton("Run bump test", self.issueCommandBumpTest)
        self.killBumpTestButton = makeButton(
            "Stop bump test", self.issueCommandKillBumpTest
        )

        self.buttonLayout = QHBoxLayout()
        self.buttonLayout.addWidget(self.bumpTestAllButton)
        self.buttonLayout.addWidget(self.bumpTestButton)
        self.buttonLayout.addWidget(self.killBumpTestButton)

        self.layout = QVBoxLayout()
        self.forms = QHBoxLayout()
        self.forms.addWidget(actuatorBox)
        self.forms.addWidget(self.progressGroup)
        self.forms.addWidget(SALLog.Widget(self.m1m3))
        self.layout.addLayout(self.forms)
        self.layout.addWidget(self.chart_view)
        self.layout.addLayout(self.buttonLayout)
        self.setLayout(self.layout)

        self.m1m3.detailedState.connect(self.detailedState)
        self.m1m3.forceActuatorBumpTestStatus.connect(self.forceActuatorBumpTestStatus)
Ejemplo n.º 13
0
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)

        # Alpha
        self.plotAlphaBox = QDoubleSpinBox(self)
        self.plotAlphaBox.setValue(self.model.activeView.plotAlpha)
        self.plotAlphaBox.setSingleStep(0.05)
        self.plotAlphaBox.setDecimals(2)
        self.plotAlphaBox.setRange(0.0, 1.0)
        self.plotAlphaBox.valueChanged.connect(self.mw.editPlotAlpha)

        # 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('Plot alpha:', self.plotAlphaBox)
        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.updatePlotAlpha()
        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 updatePlotAlpha(self):
        self.plotAlphaBox.setValue(self.model.activeView.plotAlpha)

    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.h_res)

    def updateVRes(self):
        self.vResBox.setValue(self.model.activeView.v_res)

    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 ForceActuatorBumpTestPageWidget(QWidget):
    """
    Enable user to select actuator for bump test. Show graphs depicting actual
    demand and measured forces. Shows button to run a bump test and stop any
    running bump test.

    Parameters
    ----------

    m1m3 : `SALComm object`
        SALComm communication object.
    """

    def __init__(self, m1m3):
        super().__init__()
        self.m1m3 = m1m3

        self.xIndex = self.yIndex = self.zIndex = self.sIndex = self.testedId = None
        self._testRunning = False

        actuatorBox = QGroupBox("Actuator")
        self.actuatorsTable = QTableWidget(
            max([row[FATABLE_ID] for row in FATABLE]) % 100, 12
        )
        self.actuatorsTable.setShowGrid(False)

        def setNone(r, c):
            item = QTableWidgetItem("")
            item.setFlags(Qt.NoItemFlags)
            self.actuatorsTable.setItem(r, c, item)

        for i in range(4):
            mr = min(
                [
                    row[FATABLE_ID]
                    for row in FATABLE
                    if row[FATABLE_ID] > (100 + 100 * i)
                ]
            )
            for r in range(mr):
                for c in range(i * 3, (i * 3) + 2):
                    setNone(r, c)

        for tr in range(len(FATABLE)):
            actuatorId = FATABLE[tr][FATABLE_ID]
            row = (actuatorId % 100) - 1
            colOffset = 3 * (int(actuatorId / 100) - 1)

            def getItem(text):
                item = QTableWidgetItem(text)
                item.setData(Qt.UserRole, actuatorId)
                return item

            self.actuatorsTable.setItem(row, 0 + colOffset, getItem(str(actuatorId)))
            self.actuatorsTable.setItem(row, 1 + colOffset, getItem("P"))
            if FATABLE[tr][FATABLE_SINDEX] is None:
                setNone(row, 2 + colOffset)
            else:
                self.actuatorsTable.setItem(
                    row,
                    2 + colOffset,
                    getItem("Y" if (FATABLE[tr][FATABLE_XINDEX] is None) else "X"),
                )

        self.actuatorsTable.horizontalHeader().hide()
        self.actuatorsTable.horizontalHeader().setSectionResizeMode(
            QHeaderView.ResizeToContents
        )
        self.actuatorsTable.horizontalHeader().setStretchLastSection(False)
        self.actuatorsTable.verticalHeader().hide()
        self.actuatorsTable.verticalHeader().setSectionResizeMode(
            QHeaderView.ResizeToContents
        )

        self.actuatorsTable.itemSelectionChanged.connect(self.itemSelectionChanged)
        self.actuatorsTable.setSizePolicy(
            QSizePolicy.Minimum, QSizePolicy.MinimumExpanding
        )
        self.actuatorsTable.setFixedWidth(
            sum([self.actuatorsTable.columnWidth(c) for c in range(12)])
            + self.actuatorsTable.verticalScrollBar().geometry().height() / 2
            + 1
        )
        actuatorLayout = QVBoxLayout()
        actuatorLayout.addWidget(self.actuatorsTable)
        actuatorBox.setLayout(actuatorLayout)

        def testPB():
            pb = QProgressBar()
            pb.setMaximum(6)
            return pb

        self.primaryPB = testPB()
        self.primaryLabelPB = QLabel("Primary")

        self.secondaryPB = testPB()
        self.secondaryLabelPB = QLabel("Seconday")

        self.progressGroup = QGroupBox("Test progress")
        progressLayout = QGridLayout()
        progressLayout.addWidget(self.primaryLabelPB, 0, 0)
        progressLayout.addWidget(self.primaryPB, 0, 1)
        progressLayout.addWidget(self.secondaryLabelPB, 1, 0)
        progressLayout.addWidget(self.secondaryPB, 1, 1)
        # progressLayout.addStretch(1)
        self.progressGroup.setLayout(progressLayout)
        self.progressGroup.setMaximumWidth(410)

        self.chart = None
        self.chart_view = TimeChartView()
        self.chart_view.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)

        def makeButton(text, clicked):
            button = QPushButton(text)
            button.setEnabled(False)
            button.clicked.connect(clicked)
            return button

        self.bumpTestAllButton = makeButton("Bump test all", self.bumpTestAll)
        self.bumpTestButton = makeButton("Run bump test", self.issueCommandBumpTest)
        self.killBumpTestButton = makeButton(
            "Stop bump test", self.issueCommandKillBumpTest
        )

        self.buttonLayout = QHBoxLayout()
        self.buttonLayout.addWidget(self.bumpTestAllButton)
        self.buttonLayout.addWidget(self.bumpTestButton)
        self.buttonLayout.addWidget(self.killBumpTestButton)

        self.layout = QVBoxLayout()
        self.forms = QHBoxLayout()
        self.forms.addWidget(actuatorBox)
        self.forms.addWidget(self.progressGroup)
        self.forms.addWidget(SALLog.Widget(self.m1m3))
        self.layout.addLayout(self.forms)
        self.layout.addWidget(self.chart_view)
        self.layout.addLayout(self.buttonLayout)
        self.setLayout(self.layout)

        self.m1m3.detailedState.connect(self.detailedState)
        self.m1m3.forceActuatorBumpTestStatus.connect(self.forceActuatorBumpTestStatus)

    @Slot()
    def itemSelectionChanged(self):
        """Called when an actuator is selected from the list."""
        items = self.actuatorsTable.selectedItems()
        if len(items) == 0:
            return
        if len(items) > 1:
            actuators = f"{items[0].data(Qt.UserRole)}..{items[-1].data(Qt.UserRole)}"
        else:
            actuators = f"{items[0].data(Qt.UserRole)}"

        self.bumpTestButton.setEnabled(not (self._anyCylinderRunning()))
        self.bumpTestButton.setText(f"Run bump test for FA ID {actuators}")

    def toggledTest(self, toggled):
        """Called when primary or secondary tests check box are toggled."""
        self.bumpTestButton.setEnabled(
            self.actuatorsTable.currentItem() is not None
            and not (self._anyCylinderRunning())
        )

    @asyncSlot()
    async def bumpTestAll(self):
        for i in range(4):
            colOffset = i * 3
            self.actuatorsTable.setRangeSelected(
                QTableWidgetSelectionRange(
                    0,
                    1 + colOffset,
                    self.actuatorsTable.rowCount() - 1,
                    2 + colOffset,
                ),
                False,
            )
            self.actuatorsTable.setRangeSelected(
                QTableWidgetSelectionRange(
                    0, colOffset, self.actuatorsTable.rowCount() - 1, colOffset
                ),
                True,
            )
        await self._testItem(self.actuatorsTable.selectedItems()[0])
        self.bumpTestButton.setEnabled(False)

    @asyncSlot()
    async def issueCommandBumpTest(self):
        """Call M1M3 bump test command."""
        await self._testItem(self.actuatorsTable.selectedItems()[0])

    async def _testItem(self, item):
        self.actuatorsTable.scrollToItem(item)
        self.testedId = item.data(Qt.UserRole)
        item.setSelected(False)
        self.zIndex = actuatorIDToIndex(self.testedId)

        self.xIndex = FATABLE[self.zIndex][FATABLE_XINDEX]
        self.yIndex = FATABLE[self.zIndex][FATABLE_YINDEX]
        self.sIndex = FATABLE[self.zIndex][FATABLE_SINDEX]

        items = []
        if self.xIndex is not None:
            items.append("X")
        if self.yIndex is not None:
            items.append("Y")
        items.append("Z")
        items = (
            list(map(lambda s: "Applied " + s, items))
            + [None]
            + list(map(lambda s: "Measured " + s, items))
        )

        if self.chart is not None:
            self.chart.clearData()

        self.chart = TimeChart({"Force (N)": items})

        self.chart_view.setChart(self.chart)

        self.progressGroup.setTitle(f"Test progress {self.testedId}")
        if self.sIndex is not None:
            self.secondaryLabelPB.setText("Y" if self.xIndex is None else "X")

        await self.m1m3.remote.cmd_forceActuatorBumpTest.set_start(
            actuatorId=self.testedId,
            testPrimary=not (item.text() == "X" or item.text() == "Y"),
            testSecondary=not (item.text() == "P") and self.sIndex is not None,
        )
        self.killBumpTestButton.setText(f"Stop bump test FA ID {self.testedId}")

    @asyncSlot()
    async def issueCommandKillBumpTest(self):
        """Kill bump test."""
        self.actuatorsTable.setRangeSelected(
            QTableWidgetSelectionRange(0, 0, self.actuatorsTable.rowCount() - 1, 11),
            False,
        )
        await self.m1m3.remote.cmd_killForceActuatorBumpTest.start()

    @Slot(map)
    def detailedState(self, data):
        """Called when detailedState event is received. Intercept to enable/disable form buttons."""
        if data.detailedState == MTM1M3.DetailedState.PARKEDENGINEERING:
            self.bumpTestAllButton.setEnabled(True)
            self.bumpTestButton.setEnabled(
                self.actuatorsTable.currentItem() is not None
            )
            self.killBumpTestButton.setEnabled(False)
            self.xIndex = self.yIndex = self.zIndex = None
        else:
            self.bumpTestAllButton.setEnabled(False)
            self.bumpTestButton.setEnabled(False)
            self.killBumpTestButton.setEnabled(False)

    @Slot(map)
    def appliedForces(self, data):
        """Adds applied forces to graph."""
        chartData = []
        if self.xIndex is not None:
            chartData.append(data.xForces[self.xIndex])
        if self.yIndex is not None:
            chartData.append(data.yForces[self.yIndex])
        if self.zIndex is not None:
            chartData.append(data.zForces[self.zIndex])

        self.chart.append(data.timestamp, chartData, cache_index=0)

    @Slot(map)
    def forceActuatorData(self, data):
        """Adds measured forces to graph."""
        chartData = []
        if self.xIndex is not None:
            chartData.append(data.xForce[self.xIndex])
        if self.yIndex is not None:
            chartData.append(data.yForce[self.yIndex])
        if self.zIndex is not None:
            chartData.append(data.zForce[self.zIndex])

        self.chart.append(data.timestamp, chartData, cache_index=1)

    @asyncSlot(map)
    async def forceActuatorBumpTestStatus(self, data):
        """Received when an actuator finish/start running bump tests or the actuator reports progress of the bump test."""

        testProgress = [
            "Not tested",
            "Testing start zero",
            "Testing positive",
            "Positive wait zero",
            "Testing negative",
            "Negative wait zero",
            "Passed",
            "Failed",
        ]

        # test progress
        if self.zIndex is not None:
            self.primaryPB.setEnabled(True)
            val = data.primaryTest[self.zIndex]
            self.primaryPB.setFormat(f"ID {self.testedId} - {testProgress[val]} - %v")
            self.primaryPB.setValue(min(6, val))
        else:
            self.primaryPB.setEnabled(False)

        if self.sIndex is not None:
            self.secondaryPB.setEnabled(True)
            val = data.secondaryTest[self.sIndex]
            self.secondaryPB.setFormat(f"ID {self.testedId} - {testProgress[val]} - %v")
            self.secondaryPB.setValue(min(6, val))
        else:
            self.secondaryPB.setEnabled(False)

        # list display
        for index in range(156):
            actuatorId = FATABLE[index][FATABLE_ID]
            row = (actuatorId % 100) - 1
            colOffset = 3 * (int(actuatorId / 100) - 1)

            def getColor(value):
                if value == 6:
                    return Qt.green
                elif value == 7:
                    return Qt.red
                elif not (value == 0):
                    return Qt.magenta
                return Qt.transparent

            pColor = getColor(data.primaryTest[index])

            self.actuatorsTable.item(row, colOffset + 1).setBackground(pColor)
            sIndex = FATABLE[index][FATABLE_SINDEX]
            if sIndex is not None:
                sColor = getColor(data.secondaryTest[sIndex])
                self.actuatorsTable.item(row, colOffset + 2).setBackground(sColor)
                if pColor == sColor:
                    self.actuatorsTable.item(row, colOffset).setBackground(pColor)
            else:
                self.actuatorsTable.item(row, colOffset).setBackground(pColor)

        # no tests running..
        if data.actuatorId < 0:
            selected = self.actuatorsTable.selectedItems()
            if len(selected) > 0:
                await self._testItem(selected[0])
            elif self._testRunning:
                self.bumpTestAllButton.setEnabled(True)
                self.bumpTestButton.setEnabled(
                    self.actuatorsTable.currentItem() is not None
                    and self._anyCylinder()
                )
                self.killBumpTestButton.setEnabled(False)
                self.xIndex = self.yIndex = self.zIndex = None
                self.m1m3.appliedForces.disconnect(self.appliedForces)
                self.m1m3.forceActuatorData.disconnect(self.forceActuatorData)
                self._testRunning = False

        elif self._testRunning is False:
            self.bumpTestButton.setEnabled(False)
            self.killBumpTestButton.setEnabled(True)
            self.m1m3.appliedForces.connect(self.appliedForces)
            self.m1m3.forceActuatorData.connect(self.forceActuatorData)
            self._testRunning = True

    # helper functions. Helps correctly enable/disable Run bump test button.
    def _anyCylinderRunning(self):
        return self._testRunning is True and self._anyCylinder()

    def _anyCylinder(self):
        return len(self.actuatorsTable.selectedItems()) > 0
Ejemplo n.º 15
0
class DLPSettingsGUI(QWidget):

    def __init__(self, dlp_controller=None, dlp_slicer=None, parent=None):
        QWidget.__init__(self, parent)
        self.parent = parent
        self.dlp_controller = dlp_controller
        self.dlp_slicer = dlp_slicer
        self.dlp_color_calibrator = DLPColorCalibrator()
        self.dlp_color_calibrator.analysis_completed_signal.connect(self.update_charts)
        self.__printer_parameters_list = {}
        self.__slicer_parameters_list = {}
        self.data_fit_chart_view = None
        self.data_fit_chart = None
        self.main_layout = QHBoxLayout()
        self.__init_table_widget__()
        self.__init_color_calibration_widget()
        self.__default_parameters_widget.setSizePolicy(QSizePolicy.Maximum, QSizePolicy.MinimumExpanding)
        self.main_layout.addWidget(self.__default_parameters_widget, stretch=1)
        self.main_layout.addWidget(self.__color_calibration_widget, stretch=2)
        self.setLayout(self.main_layout)
        self.main_layout.update()

    def __init_color_calibration_widget(self, parent=None):
        self.__color_calibration_widget = QGroupBox("Color Correction Options", parent)
        self.__color_calibration_widget.setSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.MinimumExpanding)
        color_calibration_layout = QVBoxLayout(self.__color_calibration_widget)

        chart_widget = QWidget(self.__color_calibration_widget)
        chart_layout = QGridLayout(chart_widget)
        self.data_fit_chart = QtCharts.QChart()
        self.data_fit_chart_view = QtCharts.QChartView(self.data_fit_chart)
        self.axis_x = QtCharts.QValueAxis()
        self.axis_x.setTitleText("Pixel Intensity")
        self.axis_x.setRange(0, 1)
        self.data_fit_chart.addAxis(self.axis_x, Qt.AlignBottom)
        self.axis_y = QtCharts.QValueAxis()
        self.axis_y.setTitleText("Voxel Height (\u03BCm)")
        self.axis_y.setRange(0, 10)
        self.data_fit_chart.addAxis(self.axis_y, Qt.AlignLeft)
        chart_layout.addWidget(self.data_fit_chart_view, 0, 0, 1, 4)
        chart_widget.setLayout(chart_layout)

        buttons_widget = QWidget(self.__color_calibration_widget)
        buttons_layout = QHBoxLayout(buttons_widget)
        analyze_data_button = QPushButton("Analyze Data")
        analyze_data_button.clicked.connect(self.analyze_images)
        self.parameters_estimation_label = QLabel(f'Estimated parameters: \u03B1 = {self.dlp_color_calibrator.optimized_parameters[0]:.3f}, \u03B2 = {self.dlp_color_calibrator.optimized_parameters[1]:.3f}, \u03B3 =  {self.dlp_color_calibrator.optimized_parameters[2]:.3f}',
                                buttons_widget)
        buttons_layout.addWidget(analyze_data_button)
        buttons_layout.addWidget(self.parameters_estimation_label)
        buttons_widget.setLayout(buttons_layout)
        color_calibration_layout.addWidget(chart_widget)
        color_calibration_layout.addWidget(buttons_widget)
        self.__color_calibration_widget.setLayout(color_calibration_layout)

    @Slot()
    def analyze_images(self):
        file_names = QFileDialog.getOpenFileNames(caption='Select data', dir='../measured_data/grayscale_measured_data',
                                                  filter="Image Files (*.asc)")
        self.dlp_color_calibrator.analyze_data_files(file_names[0])

    @Slot()
    def update_charts(self):
        self.data_fit_chart = QtCharts.QChart()
        self.data_fit_chart.setAnimationOptions(QtCharts.QChart.AllAnimations)
        self.add_series(self.data_fit_chart, "Measured Data", self.dlp_color_calibrator.input_values, self.dlp_color_calibrator.average_data)
        self.add_series(self.data_fit_chart, "Fitted Curve", self.dlp_color_calibrator.input_values,
                        self.dlp_color_calibrator.fitted_curve)
        self.add_series(self.data_fit_chart, "Predicted Result", self.dlp_color_calibrator.input_values,
                        self.dlp_color_calibrator.corrected_output_values)
        series = self.data_fit_chart.series()
        self.data_fit_chart.addAxis(self.axis_x, Qt.AlignBottom)
        self.axis_y.setRange(0, self.dlp_color_calibrator.measured_thickness)
        self.data_fit_chart.addAxis(self.axis_y, Qt.AlignLeft)
        for s in series:
            s.attachAxis(self.axis_x)
            s.attachAxis(self.axis_y)

        self.data_fit_chart_view.setRenderHint(QPainter.Antialiasing)
        self.data_fit_chart_view.setChart(self.data_fit_chart)

        self.parameters_estimation_label.setText(f'Estimated parameters: \u03B1 = {self.dlp_color_calibrator.optimized_parameters[0]:.3f}, \u03B2 = {self.dlp_color_calibrator.optimized_parameters[1]:.3f}, \u03B3 =  {self.dlp_color_calibrator.optimized_parameters[2]:.3f}')

    def add_series(self, chart, title, x, y):
        series = QtCharts.QLineSeries()
        series.setName(title)
        for idx, elem in enumerate(x):
            series.append(x[idx], y[idx])
        chart.addSeries(series)

    def __init_table_widget__(self, parent=None):
        self.__default_parameters_widget = QGroupBox("Default Parameters", parent)
        self.printer_parameters_list = self.dlp_controller.get_default_parameters()
        self.table_view = QTableView()
        self.table_model = self.MyTableModel(parent=self.__default_parameters_widget, data_list=self.printer_parameters_list)
        self.table_view.setModel(self.table_model)
        self.table_view.horizontalHeader().setVisible(False)
        self.table_view.verticalHeader().setVisible(False)
        self.table_view.horizontalHeader().setStretchLastSection(False)
        # self.table_view.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
        self.table_view.resizeColumnsToContents()
        self.table_view.update()
        # self.table_view.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Minimum)
        # self.table_view.setSizeAdjustPolicy(QAbstractScrollArea.AdjustToContents)
        apply_button = QPushButton("Apply Changes", self.__default_parameters_widget)
        apply_button.setSizePolicy(QSizePolicy.Maximum, QSizePolicy.Maximum)
        apply_button.clicked.connect(self.dlp_controller.save_default_parameters)
        default_parameters_layout = QVBoxLayout(self.__default_parameters_widget)
        default_parameters_layout.addWidget(self.table_view)
        default_parameters_layout.addWidget(apply_button)
        self.__default_parameters_widget.setLayout(default_parameters_layout)
        self.__default_parameters_widget.updateGeometry()
        # default_parameters_layout.update()
        # QGuiApplication.processEvents()

    @Slot()
    def __adjust_table_size__(self):
        self.table_view.resizeColumnToContents(0)
        self.table_view.resizeColumnToContents(1)
        rect = self.table_view.geometry()
        rect.setWidth(1 + self.table_view.verticalHeader().width() + self.table_view.columnWidth(0) +
                      self.table_view.columnWidth(1) + self.table_view.verticalScrollBar().width())
        self.table_view.setGeometry(rect)
        self.table_view.resize(rect.width(), rect.height())

    class MyTableModel(QAbstractTableModel):
        def __init__(self, parent, data_list, *args):
            QAbstractTableModel.__init__(self, parent, *args)
            self.parent = parent
            self.data_list = data_list

        def rowCount(self, parent):
            return len(self.data_list)

        def columnCount(self, parent):
            return 2

        def data(self, index, role):
            if not index.isValid():
                return None
            elif role != Qt.DisplayRole:
                return None
            return list(self.data_list.items())[index.row()][index.column()]

        def setData(self, index, value, role):
            if role == Qt.EditRole:
                if not index.isValid():
                    return False
                elif index.column() == 0:
                    return False
                else:
                    key = list(self.data_list.items())[index.row()][0]
                    old_value = list(self.data_list.items())[index.row()][1]
                    try:
                        if isinstance(old_value, float):
                            self.data_list[key] = float(value)
                        elif isinstance(old_value, bool):
                            if value == "True" or value == "true":
                                self.data_list[key] = True
                            else:
                                self.data_list[key] = False
                        elif isinstance(old_value, str):
                            if index.row() == 0:
                                if not (value.upper() == "TOP-DOWN" or value.upper() == "BOTTOM-UP"):
                                    return False
                            self.data_list[key] = str(value).upper()
                    except ValueError:
                        return False
                    self.dataChanged.emit(index, index)
                    return True
            else:
                return False

        def flags(self, index):
            if not index.isValid() or index.column() == 0:
                return Qt.ItemIsEnabled
            return Qt.ItemFlags(QAbstractTableModel.flags(self, index) |
                                Qt.ItemIsEditable)
Ejemplo n.º 16
0
class JobInfoPanel(QWidget):
    def __init__(self):
        super().__init__()
        self.setStyleSheet(Style.INFO_PANEL.value)

        self.__create_title()
        self.__create_description_groupbox()
        self.__create_res_req_groupbox()
        self.__create_contact_groupbox()

        main_layout = QVBoxLayout()
        main_layout.addWidget(self.title)
        main_layout.addWidget(self.horizontal_groupbox)
        main_layout.addLayout(self.restrictions_layout)
        main_layout.addLayout(self.contact_layout)

        self.setLayout(main_layout)

    def __create_title(self):
        self.title = QLabel()
        self.title.setAlignment(Qt.AlignCenter)
        font = QFont()
        font.setPixelSize(17)
        self.title.setFont(font)
        self.title.setStyleSheet(
            'padding: 12px; border: 1px solid #212121; border-radius: 10px;')

    def __create_description_groupbox(self):
        self.horizontal_groupbox = QGroupBox('Description:')

        self.description = QTextEdit()
        self.description.setReadOnly(True)

        layout = QHBoxLayout()
        layout.addWidget(self.description, Style.TWO_THIRDS.value)

        window = QWidget()
        window.setMinimumSize(320, 625)
        self.web = QWebEngineView(window)
        self.web.setHtml(self.generate_html_map(0, 0))
        self.webpage = self.web.page()
        layout.addWidget(self.web, Style.ONE_THIRD.value)

        self.horizontal_groupbox.setLayout(layout)

    def generate_html_map(self, lat, lng):
        initialize = (
            "var earth; var marker; var zoomLevel = 3.5;"
            "function initialize() {"
            "  var options={zoom: zoomLevel, position: [" + str(lat) + "," +
            str(lng) + "]};"
            "  earth = new WE.map('earth_div', options);"
            "  WE.tileLayer('http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png').addTo(earth);"
            f" add_marker({lat}, {lng})"
            "}"
            "function rm_marker() {marker.removeFrom(earth)}"
            "function add_marker(lat,lng) {"
            "  try {rm_marker()} catch(e) {}"
            "  marker = WE.marker([lat,lng]).addTo(earth);"
            "  earth.setView([lat,lng], zoomLevel);}")

        style = '''
            html, body {
              padding: 0;
              margin: 0;
            }
            #earth_div {
              top: 0;
              right: 0;
              bottom: 0;
              left: 0;
              position: absolute !important;
            }
        '''

        return f'''
            <!DOCTYPE HTML>
            <html>
              <head>
                <script src="http://www.webglearth.com/v2/api.js"></script>
                <script>{initialize}</script>
              <style>{style}</style>
              </head>
              <body onload="initialize()">
                <div id="earth_div"></div>
              </body>
            </html>
        '''

    def __create_res_req_groupbox(self):
        hbox = QHBoxLayout()
        restrictions_group = QGroupBox('Restrictions:')
        self.restrictions = QTextEdit()
        self.restrictions.setReadOnly(True)
        hbox.addWidget(self.restrictions)
        restrictions_group.setLayout(hbox)

        hbox = QHBoxLayout()
        requirements_group = QGroupBox('Requirements:')
        self.requirements = QTextEdit()
        self.requirements.setReadOnly(True)
        hbox.addWidget(self.requirements)
        requirements_group.setLayout(hbox)

        self.restrictions_layout = QHBoxLayout()
        self.restrictions_layout.addWidget(requirements_group,
                                           Style.TWO_THIRDS.value)
        self.restrictions_layout.addWidget(restrictions_group,
                                           Style.ONE_THIRD.value)

    def __create_contact_groupbox(self):
        hbox = QHBoxLayout()
        about_group = QGroupBox('About:')
        self.about = QTextEdit()
        self.about.setReadOnly(True)
        hbox.addWidget(self.about)
        about_group.setLayout(hbox)

        layout = QFormLayout()
        contact_group = QGroupBox('Contact Info')
        self.contact_name = QLabel()
        self.contact_email = QLabel()
        self.contact_website = QPushButton('Apply')
        self.contact_website.clicked.connect(
            lambda: webbrowser.open(self.apply_website))
        layout.addRow(QLabel('Contact:'), self.contact_name)
        layout.addRow(QLabel('Email:'), self.contact_email)
        layout.addRow(QLabel('Website:'), self.contact_website)
        contact_group.setLayout(layout)

        self.contact_layout = QHBoxLayout()
        self.contact_layout.addWidget(about_group, Style.TWO_THIRDS.value)
        self.contact_layout.addWidget(contact_group, Style.ONE_THIRD.value)

    def set_contact_info(self, contact: str, email: str, website: str,
                         company: str):
        self.contact_name.setText(contact)
        self.contact_email.setText(email)

        self.apply_website = website
        if self.apply_website is None:
            self.apply_website = f'https://duckduckgo.com/?q={company}&t=ffab&ia=web'
Ejemplo n.º 17
0
 def plot_box(self):
     self.plot = QGroupBox()
     layout = QVBoxLayout()
     self.pw.showGrid(True, True, 0.5)
     layout.addWidget(self.pw)
     self.plot.setLayout(layout)
Ejemplo n.º 18
0
class Dialog(QDialog):
    def __init__(self):
        super(Dialog, self).__init__()

        self.rotableWidgets = []

        self.createRotableGroupBox()
        self.createOptionsGroupBox()
        self.createButtonBox()

        mainLayout = QGridLayout()
        mainLayout.addWidget(self.rotableGroupBox, 0, 0)
        mainLayout.addWidget(self.optionsGroupBox, 1, 0)
        mainLayout.addWidget(self.buttonBox, 2, 0)
        mainLayout.setSizeConstraint(QLayout.SetMinimumSize)

        self.mainLayout = mainLayout
        self.setLayout(self.mainLayout)

        self.setWindowTitle("Dynamic Layouts")

    def rotateWidgets(self):
        count = len(self.rotableWidgets)
        if count % 2 == 1:
            raise AssertionError("Number of widgets must be even")

        for widget in self.rotableWidgets:
            self.rotableLayout.removeWidget(widget)

        self.rotableWidgets.append(self.rotableWidgets.pop(0))

        for i in range(count//2):
            self.rotableLayout.addWidget(self.rotableWidgets[count - i - 1], 0, i)
            self.rotableLayout.addWidget(self.rotableWidgets[i], 1, i)


    def buttonsOrientationChanged(self, index):
        self.mainLayout.setSizeConstraint(QLayout.SetNoConstraint)
        self.setMinimumSize(0, 0)

        orientation = Qt.Orientation(int(self.buttonsOrientationComboBox.itemData(index)))

        if orientation == self.buttonBox.orientation():
            return

        self.mainLayout.removeWidget(self.buttonBox)

        spacing = self.mainLayout.spacing()

        oldSizeHint = self.buttonBox.sizeHint() + QSize(spacing, spacing)
        self.buttonBox.setOrientation(orientation)
        newSizeHint = self.buttonBox.sizeHint() + QSize(spacing, spacing)

        if orientation == Qt.Horizontal:
            self.mainLayout.addWidget(self.buttonBox, 2, 0)
            self.resize(self.size() + QSize(-oldSizeHint.width(), newSizeHint.height()))
        else:
            self.mainLayout.addWidget(self.buttonBox, 0, 3, 2, 1)
            self.resize(self.size() + QSize(newSizeHint.width(), -oldSizeHint.height()))

        self.mainLayout.setSizeConstraint(QLayout.SetDefaultConstraint)

    def show_help(self):
        QMessageBox.information(self, "Dynamic Layouts Help",
                            "This example shows how to change layouts "
                            "dynamically.")

    def createRotableGroupBox(self):
        self.rotableGroupBox = QGroupBox("Rotable Widgets")

        self.rotableWidgets.append(QSpinBox())
        self.rotableWidgets.append(QSlider())
        self.rotableWidgets.append(QDial())
        self.rotableWidgets.append(QProgressBar())
        count = len(self.rotableWidgets)
        for i in range(count):
            self.rotableWidgets[i].valueChanged[int].\
                connect(self.rotableWidgets[(i+1) % count].setValue)

        self.rotableLayout = QGridLayout()
        self.rotableGroupBox.setLayout(self.rotableLayout)

        self.rotateWidgets()

    def createOptionsGroupBox(self):
        self.optionsGroupBox = QGroupBox("Options")

        buttonsOrientationLabel = QLabel("Orientation of buttons:")

        buttonsOrientationComboBox = QComboBox()
        buttonsOrientationComboBox.addItem("Horizontal", Qt.Horizontal)
        buttonsOrientationComboBox.addItem("Vertical", Qt.Vertical)
        buttonsOrientationComboBox.currentIndexChanged[int].connect(self.buttonsOrientationChanged)

        self.buttonsOrientationComboBox = buttonsOrientationComboBox

        optionsLayout = QGridLayout()
        optionsLayout.addWidget(buttonsOrientationLabel, 0, 0)
        optionsLayout.addWidget(self.buttonsOrientationComboBox, 0, 1)
        optionsLayout.setColumnStretch(2, 1)
        self.optionsGroupBox.setLayout(optionsLayout)

    def createButtonBox(self):
        self.buttonBox = QDialogButtonBox()

        closeButton = self.buttonBox.addButton(QDialogButtonBox.Close)
        helpButton = self.buttonBox.addButton(QDialogButtonBox.Help)
        rotateWidgetsButton = self.buttonBox.addButton("Rotate &Widgets", QDialogButtonBox.ActionRole)

        rotateWidgetsButton.clicked.connect(self.rotateWidgets)
        closeButton.clicked.connect(self.close)
        helpButton.clicked.connect(self.show_help)
Ejemplo n.º 19
0
    def initUI(self):

        self.layout = QVBoxLayout()

        header = QLabel(self)
        header.setGeometry(0, 0, 655, 106)
        pixmap = QPixmap("./resources/ui/debriefing.png")
        header.setPixmap(pixmap)
        self.layout.addWidget(header)
        self.layout.addStretch()

        title = QLabel("<b>Casualty report</b>")
        self.layout.addWidget(title)

        # Player lost units
        lostUnits = QGroupBox(
            f"{self.debriefing.player_country}'s lost units:")
        lostUnitsLayout = QGridLayout()
        lostUnits.setLayout(lostUnitsLayout)

        row = 0
        player_air_losses = self.debriefing.air_losses.by_type(player=True)
        for unit_type, count in player_air_losses.items():
            try:
                lostUnitsLayout.addWidget(
                    QLabel(db.unit_get_expanded_info(self.debriefing.player_country, unit_type, 'name')), row, 0)
                lostUnitsLayout.addWidget(QLabel(str(count)), row, 1)
                row += 1
            except AttributeError:
                logging.exception(
                    f"Issue adding {unit_type} to debriefing information")

        front_line_losses = self.debriefing.front_line_losses_by_type(
            player=True
        )
        for unit_type, count in front_line_losses.items():
            try:
                lostUnitsLayout.addWidget(
                    QLabel(db.unit_type_name(unit_type)), row, 0)
                lostUnitsLayout.addWidget(QLabel(str(count)), row, 1)
                row += 1
            except AttributeError:
                logging.exception(
                    f"Issue adding {unit_type} to debriefing information")

        building_losses = self.debriefing.building_losses_by_type(player=True)
        for building, count in building_losses.items():
            try:
                lostUnitsLayout.addWidget(QLabel(building), row, 0)
                lostUnitsLayout.addWidget(QLabel(str(count)), row, 1)
                row += 1
            except AttributeError:
                logging.exception(
                    f"Issue adding {building} to debriefing information")

        self.layout.addWidget(lostUnits)

        # Enemy lost units
        enemylostUnits = QGroupBox(
            f"{self.debriefing.enemy_country}'s lost units:")
        enemylostUnitsLayout = QGridLayout()
        enemylostUnits.setLayout(enemylostUnitsLayout)

        enemy_air_losses = self.debriefing.air_losses.by_type(player=False)
        for unit_type, count in enemy_air_losses.items():
            try:
                enemylostUnitsLayout.addWidget(
                    QLabel(db.unit_get_expanded_info(self.debriefing.enemy_country, unit_type, 'name')), row, 0)
                enemylostUnitsLayout.addWidget(QLabel(str(count)), row, 1)
                row += 1
            except AttributeError:
                logging.exception(
                    f"Issue adding {unit_type} to debriefing information")

        front_line_losses = self.debriefing.front_line_losses_by_type(
            player=False
        )
        for unit_type, count in front_line_losses.items():
            if count == 0:
                continue
            enemylostUnitsLayout.addWidget(QLabel(db.unit_type_name(unit_type)), row, 0)
            enemylostUnitsLayout.addWidget(QLabel("{}".format(count)), row, 1)
            row += 1

        building_losses = self.debriefing.building_losses_by_type(player=False)
        for building, count in building_losses.items():
            try:
                enemylostUnitsLayout.addWidget(QLabel(building), row, 0)
                enemylostUnitsLayout.addWidget(QLabel("{}".format(count)), row, 1)
                row += 1
            except AttributeError:
                logging.exception(
                    f"Issue adding {building} to debriefing information")

        self.layout.addWidget(enemylostUnits)

        # TODO: Display dead ground object units and runways.

        # confirm button
        okay = QPushButton("Okay")
        okay.clicked.connect(self.close)
        self.layout.addWidget(okay)

        self.setLayout(self.layout)
Ejemplo n.º 20
0
    def setupUi(self, MainWindow):
        def fun(spoiler):
            if spoiler.isOpened():
                spoiler.close()
            else:
                spoiler.open()

    # app = QApplication(sys.argv)

        w = QMainWindow()
        cw = QWidget()
        mainLayout = QHBoxLayout()
        cw.setLayout(mainLayout)

        gridLayout = QGridLayout()

        spacerItem1 = QSpacerItem(40, 20, QSizePolicy.Expanding,
                                  QSizePolicy.Minimum)
        gridLayout.addItem(spacerItem1, 0, 0, 1, 1)

        pushButton1 = QPushButton()
        pushButton1.setSizePolicy(QSizePolicy.Maximum, QSizePolicy.Preferred)
        pushButton1.setText("")
        # gridLayout.addWidget(pushButton1, 0, 1, 1, 1)

        self.label1 = QLabel()
        self.label1.setSizePolicy(QSizePolicy.Maximum, QSizePolicy.Maximum)
        self.label1.setObjectName("")
        gridLayout.addWidget(self.label1, 0, 2, 1, 1)

        datePicker1 = DatePicker()
        gridLayout.addWidget(datePicker1, 0, 1, 1, 1)

        datePicker1.selectionChanged.connect(lambda: self.__setLableDate__(
            self.label1, datePicker1.selectedDate()))

        spacerItem2 = QSpacerItem(40, 20, QSizePolicy.Expanding,
                                  QSizePolicy.Minimum)
        gridLayout.addItem(spacerItem2, 0, 3, 1, 1)

        self.label2 = QLabel()
        self.label2.setSizePolicy(QSizePolicy.Maximum, QSizePolicy.Maximum)
        self.label2.setObjectName("")

        gridLayout.addWidget(self.label2, 0, 4, 1, 1)

        datePicker2 = DatePicker()
        gridLayout.addWidget(datePicker2, 0, 5, 1, 1)

        datePicker2.selectionChanged.connect(lambda: self.__setLableDate__(
            self.label2, datePicker2.selectedDate()))

        pushButton2 = QPushButton()
        pushButton2.setSizePolicy(QSizePolicy.Maximum, QSizePolicy.Preferred)
        pushButton2.setText("")
        #gridLayout.addWidget(pushButton2, 0, 5, 1, 1)

        spacerItem3 = QSpacerItem(40, 20, QSizePolicy.Expanding,
                                  QSizePolicy.Minimum)
        gridLayout.addItem(spacerItem3, 0, 6, 1, 1)

        groupBox = QGroupBox()
        groupBox.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Maximum)
        verticalLayout = QVBoxLayout(groupBox)

        radioButton1 = QRadioButton(groupBox)
        radioButton1.setText("Subscribers")
        verticalLayout.addWidget(radioButton1)

        radioButton2 = QRadioButton(groupBox)
        radioButton1.setText("PatientsServices")
        verticalLayout.addWidget(radioButton2)

        export_btn = QPushButton()
        export_btn.setText("export")
        gridLayout.addWidget(export_btn)
        export_btn.clicked.connect(lambda: self.onExport_btn())

        gridLayout.addWidget(groupBox, 1, 1, 1, 2, Qt.AlignTop)

        self.comboBox = QComboBox()
        self.h_values = [
            "all", "مستشفي الصفوة الدولي", "مستشفي السلام الدولي",
            "مختبر مصراتة المركزي", "مستشفي الحكمة الحديث",
            "مستشفى المدينه السكنيه"
        ]
        self.comboBox.addItems(self.h_values)

        self.comboBox.activated.connect(self.oncomboBoxChanged)
        gridLayout.addWidget(self.comboBox, 1, 4, 1, 2, Qt.AlignTop)
        btn = QPushButton("Click me")
        btn.setSizePolicy(QSizePolicy.Maximum, QSizePolicy.Maximum)
        spoiler = Spoiler(Spoiler.Orientation.VERTICAL)
        spoiler.setContentLayout(gridLayout)
        mainLayout.addWidget(btn)
        #self.searchGridLayout.addWidget(spoiler)
        # mainLayout.setAlignment(Qt.AlignRight)
        MainWindow.setObjectName(_fromUtf8("MainWindow"))
        MainWindow.resize(716, 392)
        self.centralwidget = QtWidgets.QWidget(MainWindow)
        self.centralwidget.setObjectName(_fromUtf8("centralwidget"))
        self.verticalLayout = QtWidgets.QVBoxLayout(self.centralwidget)
        self.verticalLayout.setObjectName(_fromUtf8("verticalLayout"))
        self.tabWidget = QtWidgets.QTabWidget(self.centralwidget)
        self.tabWidget.setTabsClosable(False)
        self.tabWidget.setObjectName(_fromUtf8("tabWidget"))
        self.InsertTab = QtWidgets.QWidget()
        self.InsertTab.setObjectName(_fromUtf8("InsertTab"))
        self.verticalLayout_2 = QtWidgets.QVBoxLayout(self.InsertTab)
        self.verticalLayout_2.setObjectName(_fromUtf8("verticalLayout_2"))
        spacerItem = QtWidgets.QSpacerItem(20, 109,
                                           QtWidgets.QSizePolicy.Minimum,
                                           QtWidgets.QSizePolicy.Expanding)
        self.verticalLayout_2.addItem(spacerItem)
        self.insertGridLayout = QtWidgets.QGridLayout()
        self.insertGridLayout.setObjectName(_fromUtf8("insertGridLayout"))
        self.run_btn = QtWidgets.QPushButton(self.InsertTab)
        sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed,
                                           QtWidgets.QSizePolicy.Fixed)
        sizePolicy.setHorizontalStretch(0)
        sizePolicy.setVerticalStretch(0)
        sizePolicy.setHeightForWidth(
            self.run_btn.sizePolicy().hasHeightForWidth())
        self.run_btn.setSizePolicy(sizePolicy)
        self.run_btn.setMouseTracking(False)
        self.run_btn.setAutoFillBackground(False)
        self.run_btn.setStyleSheet(_fromUtf8("border: none"))
        self.run_btn.setText(_fromUtf8(""))
        icon = QtGui.QIcon()
        icon.addPixmap(QtGui.QPixmap(_fromUtf8(".\\icons\\run.png")),
                       QtGui.QIcon.Normal, QtGui.QIcon.Off)
        self.run_btn.setIcon(icon)
        self.run_btn.setIconSize(QtCore.QSize(64, 64))
        self.run_btn.setObjectName(_fromUtf8("runBtn"))
        self.insertGridLayout.addWidget(self.run_btn, 0, 3, 2, 1)
        spacerItem1 = QtWidgets.QSpacerItem(40, 20,
                                            QtWidgets.QSizePolicy.Expanding,
                                            QtWidgets.QSizePolicy.Minimum)
        self.combo = QComboBox()
        self.values = [
            "مستشفي الصفوة الدولي", "مستشفي السلام الدولي",
            "مختبر مصراتة المركزي", "مستشفي الحكمة الحديث",
            "مستشفى المدينه السكنيه"
        ]
        self.combo.addItems(self.values)

        if self.combo.currentIndex() == 1:
            print("kln")
        self.combo.activated.connect(self.oncomboChanged)
        self.insertGridLayout.addWidget(self.combo, 1, 4, 1, 2, Qt.AlignTop)
        self.insertGridLayout.addItem(spacerItem1, 0, 5, 1, 1)
        self.excel_label = QtWidgets.QLabel(self.InsertTab)
        self.excel_label.setText(_fromUtf8(""))
        self.excel_label.setAlignment(QtCore.Qt.AlignRight
                                      | QtCore.Qt.AlignTrailing
                                      | QtCore.Qt.AlignVCenter)
        self.excel_label.setObjectName(_fromUtf8("excelLabel"))
        self.insertGridLayout.addWidget(self.excel_label, 1, 0, 1, 3)
        self.sqlBtn = QtWidgets.QPushButton(self.InsertTab)
        self.sqlBtn.setMinimumSize(QtCore.QSize(200, 0))
        self.sqlBtn.setObjectName(_fromUtf8("sqlBtn"))
        self.insertGridLayout.addWidget(self.sqlBtn, 0, 4, 1, 1)
        self.excelBtn = QtWidgets.QPushButton(self.InsertTab)
        self.excelBtn.setMinimumSize(QtCore.QSize(200, 0))
        self.excelBtn.setObjectName(_fromUtf8("excelBtn"))
        self.insertGridLayout.addWidget(self.excelBtn, 0, 2, 1, 1)
        spacerItem2 = QtWidgets.QSpacerItem(40, 20,
                                            QtWidgets.QSizePolicy.Expanding,
                                            QtWidgets.QSizePolicy.Minimum)
        self.insertGridLayout.addItem(spacerItem2, 0, 1, 1, 1)
        self.sqlLabel = QtWidgets.QLabel(self.InsertTab)
        self.sqlLabel.setText(_fromUtf8(""))
        self.sqlLabel.setObjectName(_fromUtf8("sqlLabel"))
        self.insertGridLayout.addWidget(self.sqlLabel, 1, 4, 1, 2)
        self.verticalLayout_2.addLayout(self.insertGridLayout)
        spacerItem3 = QtWidgets.QSpacerItem(20, 108,
                                            QtWidgets.QSizePolicy.Minimum,
                                            QtWidgets.QSizePolicy.Expanding)
        self.verticalLayout_2.addItem(spacerItem3)
        self.tabWidget.addTab(self.InsertTab, _fromUtf8(""))
        # self.filterBtn = QtWidgets.QPushButton(self.searchTab)
        # self.filterBtn.setStyleSheet(_fromUtf8("border: none"))
        # icon2 = QtGui.QIcon()
        # icon2.addPixmap(QtGui.QPixmap(_fromUtf8("icons/filter_icon.png")), QtGui.QIcon.Normal, QtGui.QIcon.Off)
        # self.filterBtn.setIcon(icon2)
        # self.filterBtn.setObjectName(_fromUtf8("filterBtn"))
        # self.searchGridLayout.addWidget(self.filterBtn, 0, 3, 1, 1)
        # self.searchGridLayout.addWidget(spoiler)

        self.export_btn = QPushButton()
        self.export_btn.setText("export")
        #self.gridLayout.addWidget(export_btn)
        self.export_btn.clicked.connect(
            lambda: self.onExport_btn_subscribers())
        #self.exprt_btn = QtWidgets.QPushButton()
        #self.exprt_btn.setText("export")
        #self.exprt_btn.setObjectName(_fromUtf8("exprt_btn"))
        #self.searchGridLayout1.addWidget(self.exprt_btn, 0, 0, 2, 1)
        self.verticalLayout.addWidget(self.tabWidget)
        MainWindow.setCentralWidget(self.centralwidget)
        self.statusbar = QtWidgets.QStatusBar(MainWindow)
        self.statusbar.setObjectName(_fromUtf8("statusbar"))
        MainWindow.setStatusBar(self.statusbar)
        self.retranslateUi(MainWindow)
        self.tabWidget.setCurrentIndex(1)
        QtCore.QMetaObject.connectSlotsByName(MainWindow)
        self.excelBtn.clicked.connect(MainWindow,
                                      QtCore.SLOT("on_excel_btn_clicked()"))
        self.sqlBtn.clicked.connect(MainWindow,
                                    QtCore.SLOT("on_sql_btn_clicked()"))
        self.run_btn.clicked.connect(MainWindow,
                                     QtCore.SLOT("on_run_btn_clicked()"))
        self.excel_file_name = None
        self.sql_file_name = "C:\\Users\\PC WORLD\\Downloads\\test.sqlite"
        self.sqlLabel.setText(self.sql_file_name)
        conn = sqlite3.connect("C:\\Users\\PC WORLD\\Downloads\\test.sqlite")
        result = conn.execute("SELECT * FROM Subscribers")
        conn.close()
Ejemplo n.º 21
0
 def _add_grouped(self, form, title, widget):
     box = QGroupBox(title)
     vbox = QVBoxLayout()
     vbox.addWidget(widget)
     box.setLayout(vbox)
     form.addRow(box)
Ejemplo n.º 22
0
    def gui_init(self):
        control_group_layout = QVBoxLayout()
        control_group_widget = QWidget()
        control_group_widget.setLayout(control_group_layout)
        self.layout.addWidget(control_group_widget)

        rows = int(len(self._stepMotorAxies) / 2)
        columns = rows + int(len(self._stepMotorAxies) % 2)
        '''Добавляем шаговики'''
        steps_group = QGroupBox("{}".format(self.app.tr("Steppers")))
        steps_group.setContentsMargins(0, 0, 0, 0)
        steps_group.setStyleSheet("QGroupBox::title {"
                                  "text-align: left;"
                                  "font: bold 14px;"
                                  "})")
        steps_group_layout = QGridLayout()
        steps_group.setLayout(steps_group_layout)
        row = 0
        column = 0
        for i, step_axis in enumerate(self._stepMotorAxies):
            row = int(i / (rows))
            column = i - columns * row
            step_block = stepAxisWidget(step_axis, 1000, self.app, self)
            if self.__motorActions:
                step_block.changed.connect(self.__motorActions)
            steps_group_layout.addWidget(step_block, row, column,
                                         Qt.AlignCenter)
        # spacer = QSpacerItem(20, 40, QSizePolicy.Minimum, QSizePolicy.Expanding)
        # steps_group_layout.addItem(spacer)
        control_group_layout.addWidget(steps_group)

        servo_group = QGroupBox("{}".format(self.app.tr("Servos")))
        servo_group.setContentsMargins(0, 0, 0, 0)
        servo_group.setStyleSheet("QGroupBox::title {"
                                  "text-align: left;"
                                  "font: bold 14px;"
                                  "})")

        servo_group_layout = QGridLayout()
        servo_group.setLayout(servo_group_layout)
        row = 0
        column = 0
        for i, servo_axis in enumerate(self._servoMotorAxies):
            row = int(i / (rows))
            column = i - columns * row
            servo_block = servoAxisWidget(servo_axis, 1000, self.app, 180,
                                          self)
            if self.__motorActions:
                servo_block.changed.connect(self.__motorActions)
            servo_group_layout.addWidget(servo_block, row, column,
                                         Qt.AlignCenter)
        control_group_layout.addWidget(servo_group)

        led_group = QGroupBox("{}".format(self.app.tr("LED")))
        led_group.setStyleSheet("QGroupBox::title {"
                                "text-align: left;"
                                "font: bold 14px;"
                                "})")

        led_group_layout = QHBoxLayout()
        led_group.setLayout(led_group_layout)
        for pin, labels in self._controlPins.items():
            switch = LedSwitch(
                self, target=pin) if len(labels) == 0 else LedSwitch(
                    self, target=pin, leftText=labels[0], rightText=labels[1])
            if self.__pinAcions: switch.switched.connect(self.__pinAcions)
            led_group_layout.addWidget(switch)
        control_group_layout.addWidget(led_group)

        spacer = QSpacerItem(20, 40, QSizePolicy.Minimum,
                             QSizePolicy.Expanding)
        control_group_layout.addItem(spacer)

        spacer = QSpacerItem(40, 20, QSizePolicy.Expanding,
                             QSizePolicy.Minimum)
        self.layout.addItem(spacer)
Ejemplo n.º 23
0
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_name

        # 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)  # 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):
        print("Buy Armor ")
        utype = self.buyArmorCombo.itemData(self.buyArmorCombo.currentIndex())
        print(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()
        generated_group = generator.get_generated_group()
        self.ground_object.groups = [generated_group]

        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()
Ejemplo n.º 24
0
class Dialog(QDialog):
    def __init__(self):
        super(Dialog, self).__init__()

        self.rotableWidgets = []

        self.createRotableGroupBox()
        self.createOptionsGroupBox()
        self.createButtonBox()

        mainLayout = QGridLayout()
        mainLayout.addWidget(self.rotableGroupBox, 0, 0)
        mainLayout.addWidget(self.optionsGroupBox, 1, 0)
        mainLayout.addWidget(self.buttonBox, 2, 0)
        mainLayout.setSizeConstraint(QLayout.SetMinimumSize)

        self.mainLayout = mainLayout
        self.setLayout(self.mainLayout)

        self.setWindowTitle("Dynamic Layouts")

    def rotateWidgets(self):
        count = len(self.rotableWidgets)
        if count % 2 == 1:
            raise AssertionError("Number of widgets must be even")

        for widget in self.rotableWidgets:
            self.rotableLayout.removeWidget(widget)

        self.rotableWidgets.append(self.rotableWidgets.pop(0))

        for i in range(count//2):
            self.rotableLayout.addWidget(
                self.rotableWidgets[count - i - 1], 0, i)
            self.rotableLayout.addWidget(self.rotableWidgets[i], 1, i)

    def buttonsOrientationChanged(self, index):
        self.mainLayout.setSizeConstraint(QLayout.SetNoConstraint)
        self.setMinimumSize(0, 0)

        orientation = Qt.Orientation(
            int(self.buttonsOrientationComboBox.itemData(index)))

        if orientation == self.buttonBox.orientation():
            return

        self.mainLayout.removeWidget(self.buttonBox)

        spacing = self.mainLayout.spacing()

        oldSizeHint = self.buttonBox.sizeHint() + QSize(spacing, spacing)
        self.buttonBox.setOrientation(orientation)
        newSizeHint = self.buttonBox.sizeHint() + QSize(spacing, spacing)

        if orientation == Qt.Horizontal:
            self.mainLayout.addWidget(self.buttonBox, 2, 0)
            self.resize(
                self.size() + QSize(-oldSizeHint.width(), newSizeHint.height()))
        else:
            self.mainLayout.addWidget(self.buttonBox, 0, 3, 2, 1)
            self.resize(
                self.size() + QSize(newSizeHint.width(), -oldSizeHint.height()))

        self.mainLayout.setSizeConstraint(QLayout.SetDefaultConstraint)

    def show_help(self):
        QMessageBox.information(self, "Dynamic Layouts Help","This example shows how to change layouts dynamically.")

    def createRotableGroupBox(self):
        self.rotableGroupBox = QGroupBox("Rotable Widgets")

        self.rotableWidgets.append(QSpinBox())
        self.rotableWidgets.append(QSlider())
        self.rotableWidgets.append(QDial())
        self.rotableWidgets.append(QProgressBar())
        count = len(self.rotableWidgets)
        for i in range(count):
            self.rotableWidgets[i].valueChanged[int].connect(self.rotableWidgets[(i+1) % count].setValue)

        self.rotableLayout = QGridLayout()
        self.rotableGroupBox.setLayout(self.rotableLayout)

        self.rotateWidgets()

    def createOptionsGroupBox(self):
        self.optionsGroupBox = QGroupBox("Options")

        buttonsOrientationLabel = QLabel("Orientation of buttons:")

        buttonsOrientationComboBox = QComboBox()
        buttonsOrientationComboBox.addItem("Horizontal", Qt.Horizontal)
        buttonsOrientationComboBox.addItem("Vertical", Qt.Vertical)
        buttonsOrientationComboBox.currentIndexChanged[int].connect(self.buttonsOrientationChanged)

        self.buttonsOrientationComboBox = buttonsOrientationComboBox

        optionsLayout = QGridLayout()
        optionsLayout.addWidget(buttonsOrientationLabel, 0, 0)
        optionsLayout.addWidget(self.buttonsOrientationComboBox, 0, 1)
        optionsLayout.setColumnStretch(2, 1)
        self.optionsGroupBox.setLayout(optionsLayout)

    def createButtonBox(self):
        self.buttonBox = QDialogButtonBox()

        closeButton = self.buttonBox.addButton(QDialogButtonBox.Close)
        helpButton = self.buttonBox.addButton(QDialogButtonBox.Help)
        rotateWidgetsButton = self.buttonBox.addButton("Rotate &Widgets", QDialogButtonBox.ActionRole)

        rotateWidgetsButton.clicked.connect(self.rotateWidgets)
        closeButton.clicked.connect(self.close)
        helpButton.clicked.connect(self.show_help)
Ejemplo n.º 25
0
    def _create_ammo_pickup_boxes(self, size_policy,
                                  item_database: ItemDatabase):
        """
        Creates the GroupBox with SpinBoxes for selecting the pickup count of all the ammo
        :param item_database:
        :return:
        """

        self._ammo_maximum_spinboxes = collections.defaultdict(list)
        self._ammo_pickup_widgets = {}

        resource_database = default_database.resource_database_for(self.game)
        broad_to_category = {
            ItemCategory.BEAM_RELATED: ItemCategory.BEAM,
            ItemCategory.MORPH_BALL_RELATED: ItemCategory.MORPH_BALL,
            ItemCategory.MISSILE_RELATED: ItemCategory.MISSILE,
        }

        for ammo in item_database.ammo.values():
            category_box, category_layout, _ = self._boxes_for_category[
                broad_to_category[ammo.broad_category]]

            pickup_box = QGroupBox(category_box)
            pickup_box.setSizePolicy(size_policy)
            pickup_box.setTitle(ammo.name + "s")
            layout = QGridLayout(pickup_box)
            layout.setObjectName(f"{ammo.name} Box Layout")
            current_row = 0

            for ammo_item in ammo.items:
                item = resource_database.get_by_type_and_index(
                    ResourceType.ITEM, ammo_item)

                target_count_label = QLabel(pickup_box)
                target_count_label.setText(f"{item.long_name} Target" if len(
                    ammo.items) > 1 else "Target count")

                maximum_spinbox = QSpinBox(pickup_box)
                maximum_spinbox.setMaximum(ammo.maximum)
                maximum_spinbox.valueChanged.connect(
                    partial(self._on_update_ammo_maximum_spinbox, ammo_item))
                self._ammo_maximum_spinboxes[ammo_item].append(maximum_spinbox)

                layout.addWidget(target_count_label, current_row, 0)
                layout.addWidget(maximum_spinbox, current_row, 1)
                current_row += 1

            count_label = QLabel(pickup_box)
            count_label.setText("Pickup Count")
            count_label.setToolTip(
                "How many instances of this expansion should be placed.")

            pickup_spinbox = QSpinBox(pickup_box)
            pickup_spinbox.setMaximum(AmmoState.maximum_pickup_count())
            pickup_spinbox.valueChanged.connect(
                partial(self._on_update_ammo_pickup_spinbox, ammo))

            layout.addWidget(count_label, current_row, 0)
            layout.addWidget(pickup_spinbox, current_row, 1)
            current_row += 1

            if ammo.temporaries:
                require_major_item_check = QCheckBox(pickup_box)
                require_major_item_check.setText(
                    "Requires the major item to work?")
                require_major_item_check.stateChanged.connect(
                    partial(self._on_update_ammo_require_major_item, ammo))
                layout.addWidget(require_major_item_check, current_row, 0, 1,
                                 2)
                current_row += 1
            else:
                require_major_item_check = None

            expected_count = QLabel(pickup_box)
            expected_count.setWordWrap(True)
            expected_count.setText(_EXPECTED_COUNT_TEXT_TEMPLATE)
            expected_count.setToolTip(
                "Some expansions may provide 1 extra, even with no variance, if the total count "
                "is not divisible by the pickup count.")
            layout.addWidget(expected_count, current_row, 0, 1, 2)
            current_row += 1

            self._ammo_pickup_widgets[ammo] = AmmoPickupWidgets(
                pickup_spinbox, expected_count, pickup_box,
                require_major_item_check)
            category_layout.addWidget(pickup_box)
Ejemplo n.º 26
0
    def init_ui(self):
        self.setAttribute(Qt.WA_StyledBackground, True)
        self.main_layout = QGridLayout(self)
        # self.main_layout.setContentsMargins(0, 0, 0, 0)
        # control group
        self.control_group = QGroupBox(self.tr("Control"))
        self.control_layout = QGridLayout(self.control_group)
        self.resolver_label = QLabel(self.tr("Resolver"))
        self.resolver_combo_box = QComboBox()
        self.resolver_combo_box.addItems(["classic", "neural"])
        self.control_layout.addWidget(self.resolver_label, 0, 0)
        self.control_layout.addWidget(self.resolver_combo_box, 0, 1)
        self.load_dataset_button = QPushButton(qta.icon("fa.database"),
                                               self.tr("Load Dataset"))
        self.load_dataset_button.clicked.connect(self.on_load_dataset_clicked)
        self.configure_fitting_button = QPushButton(
            qta.icon("fa.gears"), self.tr("Configure Fitting Algorithm"))
        self.configure_fitting_button.clicked.connect(
            self.on_configure_fitting_clicked)
        self.control_layout.addWidget(self.load_dataset_button, 1, 0)
        self.control_layout.addWidget(self.configure_fitting_button, 1, 1)
        self.distribution_label = QLabel(self.tr("Distribution Type"))
        self.distribution_combo_box = QComboBox()
        self.distribution_combo_box.addItems(
            [name for _, name in self.distribution_types])
        self.component_number_label = QLabel(self.tr("N<sub>components</sub>"))
        self.n_components_input = QSpinBox()
        self.n_components_input.setRange(1, 10)
        self.n_components_input.setValue(3)
        self.control_layout.addWidget(self.distribution_label, 2, 0)
        self.control_layout.addWidget(self.distribution_combo_box, 2, 1)
        self.control_layout.addWidget(self.component_number_label, 3, 0)
        self.control_layout.addWidget(self.n_components_input, 3, 1)

        self.n_samples_label = QLabel(self.tr("N<sub>samples</sub>"))
        self.n_samples_display = QLabel(self.tr("Unknown"))
        self.control_layout.addWidget(self.n_samples_label, 4, 0)
        self.control_layout.addWidget(self.n_samples_display, 4, 1)
        self.sample_index_label = QLabel(self.tr("Sample Index"))
        self.sample_index_input = QSpinBox()
        self.sample_index_input.valueChanged.connect(
            self.on_sample_index_changed)
        self.sample_index_input.setEnabled(False)
        self.control_layout.addWidget(self.sample_index_label, 5, 0)
        self.control_layout.addWidget(self.sample_index_input, 5, 1)
        self.sample_name_label = QLabel(self.tr("Sample Name"))
        self.sample_name_display = QLabel(self.tr("Unknown"))
        self.control_layout.addWidget(self.sample_name_label, 6, 0)
        self.control_layout.addWidget(self.sample_name_display, 6, 1)

        self.manual_test_button = QPushButton(qta.icon("fa.sliders"),
                                              self.tr("Manual Test"))
        self.manual_test_button.setEnabled(False)
        self.manual_test_button.clicked.connect(self.on_manual_test_clicked)
        self.load_reference_button = QPushButton(qta.icon("mdi.map-check"),
                                                 self.tr("Load Reference"))
        self.load_reference_button.clicked.connect(
            lambda: self.reference_view.load_dump(mark_ref=True))
        self.control_layout.addWidget(self.manual_test_button, 7, 0)
        self.control_layout.addWidget(self.load_reference_button, 7, 1)

        self.single_test_button = QPushButton(qta.icon("fa.play-circle"),
                                              self.tr("Single Test"))
        self.single_test_button.setEnabled(False)
        self.single_test_button.clicked.connect(self.on_single_test_clicked)
        self.continuous_test_button = QPushButton(
            qta.icon("mdi.playlist-play"), self.tr("Continuous Test"))
        self.continuous_test_button.setEnabled(False)
        self.continuous_test_button.clicked.connect(
            self.on_continuous_test_clicked)
        self.control_layout.addWidget(self.single_test_button, 8, 0)
        self.control_layout.addWidget(self.continuous_test_button, 8, 1)

        self.test_previous_button = QPushButton(
            qta.icon("mdi.skip-previous-circle"), self.tr("Test Previous"))
        self.test_previous_button.setEnabled(False)
        self.test_previous_button.clicked.connect(
            self.on_test_previous_clicked)
        self.test_next_button = QPushButton(qta.icon("mdi.skip-next-circle"),
                                            self.tr("Test Next"))
        self.test_next_button.setEnabled(False)
        self.test_next_button.clicked.connect(self.on_test_next_clicked)
        self.control_layout.addWidget(self.test_previous_button, 9, 0)
        self.control_layout.addWidget(self.test_next_button, 9, 1)

        # chart group
        self.chart_group = QGroupBox(self.tr("Chart"))
        self.chart_layout = QGridLayout(self.chart_group)
        self.result_chart = MixedDistributionChart(show_mode=True,
                                                   toolbar=False)
        self.chart_layout.addWidget(self.result_chart, 0, 0)

        # table group
        self.table_group = QGroupBox(self.tr("Table"))
        self.reference_view = ReferenceResultViewer()
        self.result_view = FittingResultViewer(self.reference_view)
        self.result_view.result_marked.connect(
            lambda result: self.reference_view.add_references([result]))
        self.table_tab = QTabWidget()
        self.table_tab.addTab(self.result_view, qta.icon("fa.cubes"),
                              self.tr("Result"))
        self.table_tab.addTab(self.reference_view, qta.icon("fa5s.key"),
                              self.tr("Reference"))
        self.result_layout = QGridLayout(self.table_group)
        self.result_layout.addWidget(self.table_tab, 0, 0)

        # pack all group
        self.splitter1 = QSplitter(Qt.Orientation.Vertical)
        self.splitter1.addWidget(self.control_group)
        self.splitter1.addWidget(self.chart_group)
        self.splitter2 = QSplitter(Qt.Orientation.Horizontal)
        self.splitter2.addWidget(self.splitter1)
        self.splitter2.addWidget(self.table_group)
        self.main_layout.addWidget(self.splitter2, 0, 0)
Ejemplo n.º 27
0
    def add_purchase_row(self, unit_type, layout, row):
        exist = QGroupBox()
        exist.setProperty("style", "buy-box")
        exist.setMaximumHeight(36)
        exist.setMinimumHeight(36)
        existLayout = QHBoxLayout()
        exist.setLayout(existLayout)

        existing_units = self.cp.base.total_units_of_type(unit_type)
        scheduled_units = self.deliveryEvent.units.get(unit_type, 0)

        unitName = QLabel("<b>" + db.unit_type_name_2(unit_type) + "</b>")
        unitName.setSizePolicy(QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding))

        existing_units = QLabel(str(existing_units))
        existing_units.setSizePolicy(QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed))

        amount_bought = QLabel("<b>{}</b>".format(str(scheduled_units)))
        amount_bought.setSizePolicy(QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed))

        self.existing_units_labels[unit_type] = existing_units
        self.bought_amount_labels[unit_type] = amount_bought

        price = QLabel("<b>$ {:02d}</b> m".format(db.PRICES[unit_type]))
        price.setSizePolicy(QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed))

        buysell = QGroupBox()
        buysell.setProperty("style", "buy-box")
        buysell.setMaximumHeight(36)
        buysell.setMinimumHeight(36)
        buysellayout = QHBoxLayout()
        buysell.setLayout(buysellayout)

        buy = QPushButton("+")
        buy.setProperty("style", "btn-buy")
        buy.setMinimumSize(16, 16)
        buy.setMaximumSize(16, 16)
        buy.clicked.connect(lambda: self.buy(unit_type))
        buy.setSizePolicy(QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed))

        sell = QPushButton("-")
        sell.setProperty("style", "btn-sell")
        sell.setMinimumSize(16, 16)
        sell.setMaximumSize(16, 16)
        sell.setSizePolicy(QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed))
        sell.clicked.connect(lambda: self.sell(unit_type))

        existLayout.addWidget(unitName)
        existLayout.addItem(QSpacerItem(20, 0, QSizePolicy.Minimum, QSizePolicy.Minimum))
        existLayout.addWidget(existing_units)
        existLayout.addItem(QSpacerItem(20, 0, QSizePolicy.Minimum, QSizePolicy.Minimum))
        existLayout.addWidget(price)

        buysellayout.addWidget(sell)
        buysellayout.addWidget(amount_bought)
        buysellayout.addWidget(buy)

        layout.addWidget(exist, row, 1)
        layout.addWidget(buysell, row, 2)

        return row + 1
class QWaitingForMissionResultWindow(QDialog):
    def __init__(self, gameEvent: Event, game: Game,
                 unit_map: UnitMap) -> None:
        super(QWaitingForMissionResultWindow, self).__init__()
        self.setModal(True)
        self.gameEvent = gameEvent
        self.game = game
        self.unit_map = unit_map
        self.setWindowTitle("Waiting for mission completion.")
        self.setWindowIcon(QIcon("./resources/icon.png"))
        self.setMinimumHeight(570)

        self.initUi()
        DebriefingFileWrittenSignal.get_instance().debriefingReceived.connect(
            self.updateLayout)
        self.wait_thread = wait_for_debriefing(
            lambda debriefing: self.on_debriefing_update(debriefing),
            self.game, self.unit_map)

    def initUi(self):
        self.layout = QGridLayout()

        header = QLabel(self)
        header.setGeometry(0, 0, 655, 106)
        pixmap = QPixmap("./resources/ui/conflict.png")
        header.setPixmap(pixmap)
        self.layout.addWidget(header, 0, 0)

        self.gridLayout = QGridLayout()

        jinja = Environment(
            loader=FileSystemLoader("resources/ui/templates"),
            autoescape=select_autoescape(
                disabled_extensions=("", ),
                default_for_string=True,
                default=True,
            ),
            trim_blocks=True,
            lstrip_blocks=True,
        )
        self.instructions_text = QTextBrowser()
        self.instructions_text.setHtml(
            jinja.get_template("mission_start_EN.j2").render())
        self.instructions_text.setOpenExternalLinks(True)
        self.gridLayout.addWidget(self.instructions_text, 1, 0)

        progress = QLabel("")
        progress.setAlignment(QtCore.Qt.AlignCenter)
        progress_bar = QMovie("./resources/ui/loader.gif")
        progress.setMovie(progress_bar)

        self.actions = QGroupBox("Actions :")
        self.actions_layout = QHBoxLayout()
        self.actions.setLayout(self.actions_layout)

        self.manually_submit = QPushButton("Manually Submit [Advanced users]")
        self.manually_submit.clicked.connect(self.submit_manually)
        self.actions_layout.addWidget(self.manually_submit)
        self.cancel = QPushButton("Abort mission")
        self.cancel.clicked.connect(self.close)
        self.actions_layout.addWidget(self.cancel)
        self.gridLayout.addWidget(self.actions, 2, 0)

        self.actions2 = QGroupBox("Actions :")
        self.actions2_layout = QHBoxLayout()
        self.actions2.setLayout(self.actions2_layout)
        self.manually_submit2 = QPushButton("Manually Submit [Advanced users]")
        self.manually_submit2.clicked.connect(self.submit_manually)
        self.actions2_layout.addWidget(self.manually_submit2)
        self.cancel2 = QPushButton("Abort mission")
        self.cancel2.clicked.connect(self.close)
        self.actions2_layout.addWidget(self.cancel2)
        self.proceed = QPushButton("Accept results")
        self.proceed.setProperty("style", "btn-success")
        self.proceed.clicked.connect(self.process_debriefing)
        self.actions2_layout.addWidget(self.proceed)

        progress_bar.start()
        self.layout.addLayout(self.gridLayout, 1, 0)
        self.setLayout(self.layout)

    def updateLayout(self, debriefing: Debriefing) -> None:
        updateBox = QGroupBox("Mission status")
        updateLayout = QGridLayout()
        updateBox.setLayout(updateLayout)
        self.debriefing = debriefing

        updateLayout.addWidget(QLabel("<b>Aircraft destroyed</b>"), 0, 0)
        updateLayout.addWidget(
            QLabel(str(len(list(debriefing.air_losses.losses)))), 0, 1)

        updateLayout.addWidget(QLabel("<b>Front line units destroyed</b>"), 1,
                               0)
        updateLayout.addWidget(
            QLabel(str(len(list(debriefing.front_line_losses)))), 1, 1)

        updateLayout.addWidget(QLabel("<b>Other ground units destroyed</b>"),
                               2, 0)
        updateLayout.addWidget(
            QLabel(str(len(list(debriefing.ground_object_losses)))), 2, 1)

        updateLayout.addWidget(QLabel("<b>Buildings destroyed</b>"), 3, 0)
        updateLayout.addWidget(
            QLabel(str(len(list(debriefing.building_losses)))), 3, 1)

        updateLayout.addWidget(QLabel("<b>Base Capture Events</b>"), 4, 0)
        updateLayout.addWidget(
            QLabel(str(len(debriefing.base_capture_events))), 4, 1)

        # Clear previous content of the window
        for i in reversed(range(self.gridLayout.count())):
            try:
                self.gridLayout.itemAt(i).widget().setParent(None)
            except:
                logging.exception("Failed to clear window")

        # Set new window content
        self.gridLayout.addWidget(updateBox, 0, 0)

        if not debriefing.state_data.mission_ended:
            self.gridLayout.addWidget(QLabel("<b>Mission is being played</b>"),
                                      1, 0)
            self.gridLayout.addWidget(self.actions, 2, 0)
        else:
            self.gridLayout.addWidget(QLabel("<b>Mission is over</b>"), 1, 0)
            self.gridLayout.addWidget(self.actions2, 2, 0)

    def on_debriefing_update(self, debriefing: Debriefing) -> None:
        try:
            logging.info("On Debriefing update")
            logging.debug(debriefing)
            DebriefingFileWrittenSignal.get_instance().sendDebriefing(
                debriefing)
        except Exception:
            logging.exception("Got an error while sending debriefing")
        self.wait_thread = wait_for_debriefing(
            lambda d: self.on_debriefing_update(d), self.game, self.unit_map)

    def process_debriefing(self):
        start = timeit.default_timer()
        self.game.finish_event(event=self.gameEvent,
                               debriefing=self.debriefing)
        self.game.pass_turn()

        GameUpdateSignal.get_instance().sendDebriefing(self.debriefing)
        GameUpdateSignal.get_instance().updateGame(self.game)
        end = timeit.default_timer()
        logging.info("Turn processing took %s", timedelta(seconds=end - start))
        self.close()

    def debriefing_directory_location(self) -> str:
        return os.path.join(base_path(), "liberation_debriefings")

    def closeEvent(self, evt):
        super(QWaitingForMissionResultWindow, self).closeEvent(evt)
        if self.wait_thread is not None:
            self.wait_thread.stop()

    def submit_manually(self):
        file = QFileDialog.getOpenFileName(self,
                                           "Select game file to open",
                                           filter="json(*.json)",
                                           dir=".")
        print(file)
        try:
            with open(file[0], "r") as json_file:
                json_data = json.load(json_file)
                json_data["mission_ended"] = True
                debriefing = Debriefing(json_data, self.game, self.unit_map)
                self.on_debriefing_update(debriefing)
        except Exception as e:
            logging.error(e)
            msg = QMessageBox()
            msg.setIcon(QMessageBox.Information)
            msg.setText("Invalid file : " + file[0])
            msg.setWindowTitle("Invalid file.")
            msg.setStandardButtons(QMessageBox.Ok)
            msg.setWindowFlags(Qt.WindowStaysOnTopHint)
            msg.exec_()
            return
Ejemplo n.º 29
0
    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 initUi(self):
        self.layout = QGridLayout()

        header = QLabel(self)
        header.setGeometry(0, 0, 655, 106)
        pixmap = QPixmap("./resources/ui/conflict.png")
        header.setPixmap(pixmap)
        self.layout.addWidget(header, 0, 0)

        self.gridLayout = QGridLayout()

        jinja = Environment(
            loader=FileSystemLoader("resources/ui/templates"),
            autoescape=select_autoescape(
                disabled_extensions=("", ),
                default_for_string=True,
                default=True,
            ),
            trim_blocks=True,
            lstrip_blocks=True,
        )
        self.instructions_text = QTextBrowser()
        self.instructions_text.setHtml(
            jinja.get_template("mission_start_EN.j2").render())
        self.instructions_text.setOpenExternalLinks(True)
        self.gridLayout.addWidget(self.instructions_text, 1, 0)

        progress = QLabel("")
        progress.setAlignment(QtCore.Qt.AlignCenter)
        progress_bar = QMovie("./resources/ui/loader.gif")
        progress.setMovie(progress_bar)

        self.actions = QGroupBox("Actions :")
        self.actions_layout = QHBoxLayout()
        self.actions.setLayout(self.actions_layout)

        self.manually_submit = QPushButton("Manually Submit [Advanced users]")
        self.manually_submit.clicked.connect(self.submit_manually)
        self.actions_layout.addWidget(self.manually_submit)
        self.cancel = QPushButton("Abort mission")
        self.cancel.clicked.connect(self.close)
        self.actions_layout.addWidget(self.cancel)
        self.gridLayout.addWidget(self.actions, 2, 0)

        self.actions2 = QGroupBox("Actions :")
        self.actions2_layout = QHBoxLayout()
        self.actions2.setLayout(self.actions2_layout)
        self.manually_submit2 = QPushButton("Manually Submit [Advanced users]")
        self.manually_submit2.clicked.connect(self.submit_manually)
        self.actions2_layout.addWidget(self.manually_submit2)
        self.cancel2 = QPushButton("Abort mission")
        self.cancel2.clicked.connect(self.close)
        self.actions2_layout.addWidget(self.cancel2)
        self.proceed = QPushButton("Accept results")
        self.proceed.setProperty("style", "btn-success")
        self.proceed.clicked.connect(self.process_debriefing)
        self.actions2_layout.addWidget(self.proceed)

        progress_bar.start()
        self.layout.addLayout(self.gridLayout, 1, 0)
        self.setLayout(self.layout)
Ejemplo n.º 31
0
    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)
Ejemplo n.º 32
0
    def createTurnTableControllerTabWidget(self):
        ipAddressLabel = QLabel("IP Address: ")
        self.ipAddressLineEdit = createLineEdit(
            self.configManager.turnTableIPAddress)

        self.watchdogPortLineEdit = createLineEdit(
            self.configManager.watchdogPort)
        self.shaftEncoderPortLineEdit = createLineEdit(
            self.configManager.shaftEncoderPort)
        self.motorControllerPortLineEdit = createLineEdit(
            self.configManager.motorControllerPort)

        portSettingsLayout = QFormLayout()
        portSettingsLayout.addRow(QLabel("Watchdog Port: "),
                                  self.watchdogPortLineEdit)
        portSettingsLayout.addRow(QLabel("Shaft Encoder Port: "),
                                  self.shaftEncoderPortLineEdit)
        portSettingsLayout.addRow(QLabel("Motor Controller Port: "),
                                  self.motorControllerPortLineEdit)

        portsGroupBox = QGroupBox("Ports")
        portsGroupBox.setLayout(portSettingsLayout)

        ipAddressLayout = QHBoxLayout()
        ipAddressLayout.addWidget(ipAddressLabel)
        ipAddressLayout.addWidget(self.ipAddressLineEdit)

        settingsLayout = QVBoxLayout()
        settingsLayout.addLayout(ipAddressLayout)
        settingsLayout.addWidget(portsGroupBox)

        connectionSettingsGroupBox = QGroupBox("Connection Settings")
        connectionSettingsGroupBox.setLayout(settingsLayout)

        self.proportionalGainLineEdit = createLineEdit(
            self.configManager.controlProportionalGain)
        self.integralGainLineEdit = createLineEdit(
            self.configManager.controlIntegralGain)
        self.derivativeGainLineEdit = createLineEdit(
            self.configManager.controlDerivativeGain)
        self.minimumControlSignalLineEdit = createLineEdit(
            self.configManager.minimumControlSignalValue)

        pidControllerSettingsLayout = QFormLayout()
        pidControllerSettingsLayout.addRow(QLabel("Proportional Gain: "),
                                           self.proportionalGainLineEdit)
        pidControllerSettingsLayout.addRow(QLabel("Integral Gain: "),
                                           self.integralGainLineEdit)
        pidControllerSettingsLayout.addRow(QLabel("Derivative Gain: "),
                                           self.derivativeGainLineEdit)
        pidControllerSettingsLayout.addRow(QLabel("Minimum Control Signal: "),
                                           self.minimumControlSignalLineEdit)

        pidControllerSettingsGroupBox = QGroupBox("PID Controller")
        pidControllerSettingsGroupBox.setLayout(pidControllerSettingsLayout)

        self.minimumGotoPositionLineEdit = createLineEdit(
            self.configManager.minimumGotoPosition)
        self.maximumGotoPositionLineEdit = createLineEdit(
            self.configManager.maximumGotoPosition)
        self.minimumStepSizeLineEdit = createLineEdit(
            self.configManager.minimumStepSize)
        self.maximumStepSizeLineEdit = createLineEdit(
            self.configManager.maximumStepSize)

        positionSettingsLayout = QFormLayout()
        positionSettingsLayout.addRow(QLabel("Minimum Goto Position: "),
                                      self.minimumGotoPositionLineEdit)
        positionSettingsLayout.addRow(QLabel("Maximum Goto Position: "),
                                      self.maximumGotoPositionLineEdit)
        positionSettingsLayout.addRow(QLabel("Minimum Step Size: "),
                                      self.minimumStepSizeLineEdit)
        positionSettingsLayout.addRow(QLabel("Maximum Step Size: "),
                                      self.maximumStepSizeLineEdit)

        positionSettingsGroupBox = QGroupBox("Position Settings")
        positionSettingsGroupBox.setLayout(positionSettingsLayout)

        settingsLayout = QVBoxLayout()
        settingsLayout.addWidget(connectionSettingsGroupBox)
        settingsLayout.addWidget(pidControllerSettingsGroupBox)
        settingsLayout.addWidget(positionSettingsGroupBox)

        settingsTabWidget = QWidget()
        settingsTabWidget.setLayout(settingsLayout)

        return settingsTabWidget
Ejemplo n.º 33
0
    def __init__(self, mode, parentQWidget = None):
        QVBoxLayout.__init__(self)

        self.sig.connect(self.addThreadList)
        self.mode = mode

        self.sizePolicy = QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Expanding)

        self.groupBoxSearch = QGroupBox()
        self.groupBoxSearch.setStyleSheet("QGroupBox {border: 1px solid gray; border-radius: 4px; };")
        vboxSearch = QVBoxLayout()
        self.searchTitle = QLabel("Search Messages")
        vboxSearch.addWidget(self.searchTitle)
        self.searchHLayout = QHBoxLayout()
        self.editTextSearch = QTextEdit('')
        self.editTextSearch.setFixedSize(200,30)
        self.buttonSearch = QPushButton('Search')
        self.buttonSearch.setFixedSize(100,30)
        self.buttonSearch.clicked.connect(self.searchMsg)
        vboxSearch.addWidget(self.editTextSearch)
        self.searchHLayout.addWidget(self.buttonSearch)
        self.searchCursor = QLabel()
        self.searchHLayout.addWidget(self.searchCursor)
        vboxSearch.addLayout(self.searchHLayout)
        self.browseHLayout = QHBoxLayout()
        self.buttonLookUp = QPushButton('\u21e7')  #Arrow up
        self.buttonLookUp.setFixedWidth(100)
        self.buttonLookUp.clicked.connect(self.moveToPrev)
        self.buttonLookDown = QPushButton('\u21e9') #Arrow down
        self.buttonLookDown.setFixedWidth(100)
        self.buttonLookDown.clicked.connect(self.moveToNext)
        self.browseHLayout.addWidget(self.buttonLookUp)
        self.browseHLayout.addWidget(self.buttonLookDown)
        vboxSearch.addLayout(self.browseHLayout)
        self.groupBoxSearch.setLayout(vboxSearch)
        self.addWidget(self.groupBoxSearch)
        self.groupBoxSearch.setSizePolicy(QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed))

        self.buttonHiddenLifelines = QPushButton('Show hidden life-lines')
        self.buttonHiddenLifelines.setFixedWidth(200)
        self.buttonHiddenLifelines.clicked.connect(self.showHiddenLifelines)
        self.addWidget(self.buttonHiddenLifelines)

        self.buttonHiddenMessages = QPushButton('Show hidden Messages')
        self.buttonHiddenMessages.setFixedWidth(200)
        self.buttonHiddenMessages.clicked.connect(self.showHiddenMessages)
        self.addWidget(self.buttonHiddenMessages)

        if const.mode_interactive == mode:
            self.buttonCapture = QPushButton('Capture')
            self.buttonCapture.setFixedWidth(200)
            self.buttonCapture.clicked.connect(self.notifyCapture)
            self.addWidget(self.buttonCapture)
        self.msgRcv = []
        self.msgInfo = QLabel("Message Info.")
        self.groupBoxMessageInfo = QGroupBox()
        self.groupBoxMessageInfo.setStyleSheet("QGroupBox {border: 1px solid gray; border-radius: 9px; margin-top: 0.5em} QGroupBox::title {subcontrol-origin: margin; left: 10px; padding: 0 3px 0 3px;")
        vbox = QVBoxLayout()
        vbox.addWidget(self.msgInfo)
        self.tableTime = QTableWidget(3,2)
        self.tableTime.setHorizontalHeaderLabels(['-','time'])
        self.tableTime.setColumnWidth(0,80)
        self.tableTime.setColumnWidth(1,150)
        vwidth = self.tableTime.verticalHeader().length()
        hwidth = self.tableTime.horizontalHeader().height()
        fwidth = self.tableTime.frameWidth() * 2
        self.tableTime.setFixedHeight(vwidth + hwidth + fwidth)
        self.tableTime.horizontalHeader().setStretchLastSection(True)
        self.tableTime.setItem(0,0,QTableWidgetItem('begin'))
        self.tableTime.setItem(0,1,QTableWidgetItem(' - '))
        self.tableTime.setItem(1,0,QTableWidgetItem('end'))
        self.tableTime.setItem(1,1,QTableWidgetItem(' - '))
        self.tableTime.setItem(2,0,QTableWidgetItem('duration'))
        self.tableTime.setItem(2,1,QTableWidgetItem(' - '))
        vbox.addWidget(self.tableTime)

        self.titleArg = QLabel('Argument List')
        vbox.addWidget(self.titleArg)

        max_arg_num = 10
        self.tableArgs = QTableWidget(max_arg_num,2)
        self.tableArgs.setHorizontalHeaderLabels(['type','value'])
        for idx in range(0,max_arg_num):
            self.tableArgs.setItem(idx,0,QTableWidgetItem())
            self.tableArgs.setItem(idx,1,QTableWidgetItem())
        self.tableArgs.horizontalHeader().setStretchLastSection(True)
        vbox.addWidget(self.tableArgs)

        self.titleArg = QLabel('Return Value List')
        vbox.addWidget(self.titleArg)

        max_ret_num = 4
        self.tableRet = QTableWidget(max_ret_num,2)
        self.tableRet.setHorizontalHeaderLabels(['type','value'])
        for idx in range(0,max_ret_num):
            self.tableRet.setItem(idx,0,QTableWidgetItem())
            self.tableRet.setItem(idx,1,QTableWidgetItem())
        self.tableRet.horizontalHeader().setStretchLastSection(True)
        vwidth = self.tableRet.verticalHeader().length()
        hwidth = self.tableRet.horizontalHeader().height()
        fwidth = self.tableRet.frameWidth() * 2
        self.tableRet.setFixedHeight(vwidth + hwidth + fwidth)
        vbox.addWidget(self.tableRet)

        self.buttonSrcView = QPushButton('view code')
        self.buttonSrcView.setFixedWidth(200)
        self.buttonSrcView.clicked.connect(self.openSourceViewer)
        self.buttonHide = QPushButton('Hide')
        self.buttonHide.setFixedWidth(200)
        self.buttonHide.clicked.connect(self.notifyHide)
        self.buttonHideAllMsg = QPushButton('Hide All')
        self.buttonHideAllMsg.setFixedWidth(200)
        self.buttonHideAllMsg.clicked.connect(self.hideAllMsgNamedAsSelected)
        self.groupBoxMessageInfo.setLayout(vbox)
        self.checkHideCircular = QCheckBox('Hide Circular Messages')
        self.checkHideCircular.setCheckState(QtCore.Qt.Unchecked)
        self.checkHideCircular.stateChanged.connect(self.changeHideCircularMessage)
        self.addWidget(self.checkHideCircular)
        self.addWidget(self.groupBoxMessageInfo)
        self.groupBoxMessageInfo.setSizePolicy(self.sizePolicy)
Ejemplo n.º 34
0
class View(QMainWindow):
    def __init__(self, model):
        super().__init__()

        self.setWindowTitle("OpenHRV")
        self.setWindowIcon(QIcon(":/logo.png"))
        self.setGeometry(50, 50, 1750, 850)

        self.model = model
        self.signals = ViewSignals()

        self.scanner = SensorScanner()
        self.scanner_thread = QThread(self)
        self.scanner.moveToThread(self.scanner_thread)
        self.scanner.mac_update.connect(self.model.set_mac_addresses)

        self.sensor = SensorClient()
        self.sensor_thread = QThread(self)
        self.sensor.moveToThread(self.sensor_thread)
        self.sensor.ibi_update.connect(self.model.set_ibis_buffer)
        self.sensor_thread.started.connect(self.sensor.run)

        self.redis_publisher = RedisPublisher()
        self.redis_publisher_thread = QThread(self)
        self.redis_publisher.moveToThread(self.redis_publisher_thread)
        self.model.ibis_buffer_update.connect(self.redis_publisher.publish)
        self.model.mean_hrv_update.connect(self.redis_publisher.publish)
        self.model.mac_addresses_update.connect(self.redis_publisher.publish)
        self.model.pacer_rate_update.connect(self.redis_publisher.publish)
        self.model.hrv_target_update.connect(self.redis_publisher.publish)
        self.model.biofeedback_update.connect(self.redis_publisher.publish)
        self.signals.annotation.connect(self.redis_publisher.publish)
        self.redis_publisher_thread.started.connect(
            self.redis_publisher.monitor.start)

        self.redis_logger = RedisLogger()
        self.redis_logger_thread = QThread(self)
        self.redis_logger.moveToThread(self.redis_logger_thread)
        self.redis_logger_thread.finished.connect(
            self.redis_logger.save_recording)
        self.redis_logger.recording_status.connect(self.show_recording_status)

        self.ibis_plot = pg.PlotWidget()
        self.ibis_plot.setBackground("w")
        self.ibis_plot.setLabel("left", "Inter-Beat-Interval (msec)",
                                **{"font-size": "25px"})
        self.ibis_plot.setLabel("bottom", "Seconds", **{"font-size": "25px"})
        self.ibis_plot.showGrid(y=True)
        self.ibis_plot.setYRange(300, 1500, padding=0)
        self.ibis_plot.setMouseEnabled(x=False, y=False)

        self.ibis_signal = pg.PlotCurveItem()
        pen = pg.mkPen(color=(0, 191, 255), width=7.5)
        self.ibis_signal.setPen(pen)
        self.ibis_signal.setData(self.model.ibis_seconds,
                                 self.model.ibis_buffer)
        self.ibis_plot.addItem(self.ibis_signal)

        self.mean_hrv_plot = pg.PlotWidget()
        self.mean_hrv_plot.setBackground("w")
        self.mean_hrv_plot.setLabel("left", "HRV (msec)",
                                    **{"font-size": "25px"})
        self.mean_hrv_plot.setLabel("bottom", "Seconds",
                                    **{"font-size": "25px"})
        self.mean_hrv_plot.showGrid(y=True)
        self.mean_hrv_plot.setYRange(0, 600, padding=0)
        self.mean_hrv_plot.setMouseEnabled(x=False, y=False)
        colorgrad = QLinearGradient(0, 0, 0, 1)  # horizontal gradient
        colorgrad.setCoordinateMode(QGradient.ObjectMode)
        colorgrad.setColorAt(0, pg.mkColor("g"))
        colorgrad.setColorAt(.5, pg.mkColor("y"))
        colorgrad.setColorAt(1, pg.mkColor("r"))
        brush = QBrush(colorgrad)
        self.mean_hrv_plot.getViewBox().setBackgroundColor(brush)

        self.mean_hrv_signal = pg.PlotCurveItem()
        pen = pg.mkPen(color="w", width=7.5)
        self.mean_hrv_signal.setPen(pen)
        self.mean_hrv_signal.setData(self.model.mean_hrv_seconds,
                                     self.model.mean_hrv_buffer)
        self.mean_hrv_plot.addItem(self.mean_hrv_signal)

        self.pacer_plot = pg.PlotWidget()
        self.pacer_plot.setBackground("w")
        self.pacer_plot.setAspectLocked(lock=True, ratio=1)
        self.pacer_plot.setMouseEnabled(x=False, y=False)
        self.pacer_plot.disableAutoRange()
        self.pacer_plot.setXRange(-1, 1, padding=0)
        self.pacer_plot.setYRange(-1, 1, padding=0)
        self.pacer_plot.hideAxis("left")
        self.pacer_plot.hideAxis("bottom")

        self.pacer_disc = pg.PlotCurveItem()
        brush = pg.mkBrush(color=(135, 206, 250))
        self.pacer_disc.setBrush(brush)
        self.pacer_disc.setFillLevel(1)
        self.pacer_plot.addItem(self.pacer_disc)

        self.pacer_rate = QSlider(Qt.Horizontal)
        self.pacer_rate.setTracking(False)
        self.pacer_rate.setRange(
            0, 6)  # transformed to bpm [4, 7], step .5 by model
        self.pacer_rate.valueChanged.connect(self.model.set_breathing_rate)
        self.pacer_rate.setSliderPosition(4)  # corresponds to 6 bpm
        self.pacer_label = QLabel(f"Rate: {self.model.breathing_rate}")

        self.pacer_toggle = QCheckBox("Show pacer", self)
        self.pacer_toggle.setChecked(True)
        self.pacer_toggle.stateChanged.connect(self.toggle_pacer)

        self.hrv_target_label = QLabel(f"Target: {self.model.hrv_target}")

        self.hrv_target = QSlider(Qt.Horizontal)
        self.hrv_target.setRange(50, 600)
        self.hrv_target.setSingleStep(10)
        self.hrv_target.valueChanged.connect(self.model.set_hrv_target)
        self.hrv_target.setSliderPosition(self.model.hrv_target)
        self.mean_hrv_plot.setYRange(0, self.model.hrv_target, padding=0)

        self.scan_button = QPushButton("Scan")
        self.scan_button.clicked.connect(self.scanner.scan)

        self.mac_menu = QComboBox()

        self.connect_button = QPushButton("Connect")
        self.connect_button.clicked.connect(self.connect_sensor)

        self.start_recording_button = QPushButton("Start")
        self.start_recording_button.clicked.connect(
            self.redis_logger.start_recording)

        self.save_recording_button = QPushButton("Save")
        self.save_recording_button.clicked.connect(
            self.redis_logger.save_recording)

        self.annotation = QComboBox()
        self.annotation.setEditable(True)
        self.annotation.setDuplicatesEnabled(False)
        self.annotation.addItems([
            "start_baseline", "end_baseline", "start_bf", "end_bf",
            "start_nobf", "end_nobf"
        ])
        self.annotation.setMaxCount(
            10)  # user can configure up to 4 additional custom annotations
        self.annotation_button = QPushButton("Annotate")
        self.annotation_button.clicked.connect(self.emit_annotation)
        self.central_widget = QWidget()
        self.setCentralWidget(self.central_widget)

        self.recording_status_label = QLabel("Status:")
        self.recording_statusbar = QProgressBar()
        self.recording_statusbar.setRange(0, 1)

        self.vlayout0 = QVBoxLayout(self.central_widget)

        self.hlayout0 = QHBoxLayout()
        self.hlayout0.addWidget(self.ibis_plot, stretch=80)
        self.hlayout0.addWidget(self.pacer_plot, stretch=20)
        self.vlayout0.addLayout(self.hlayout0)

        self.vlayout0.addWidget(self.mean_hrv_plot)

        self.hlayout1 = QHBoxLayout()

        self.device_config = QFormLayout()
        self.device_config.addRow(self.scan_button, self.mac_menu)
        self.device_config.addRow(self.connect_button)
        self.device_panel = QGroupBox("ECG Devices")
        self.device_panel.setLayout(self.device_config)
        self.hlayout1.addWidget(self.device_panel, stretch=25)

        self.hrv_config = QFormLayout()
        self.hrv_config.addRow(self.hrv_target_label, self.hrv_target)
        self.hrv_panel = QGroupBox("HRV Settings")
        self.hrv_panel.setLayout(self.hrv_config)
        self.hlayout1.addWidget(self.hrv_panel, stretch=25)

        self.pacer_config = QFormLayout()
        self.pacer_config.addRow(self.pacer_label, self.pacer_rate)
        self.pacer_config.addRow(self.pacer_toggle)
        self.pacer_panel = QGroupBox("Breathing Pacer")
        self.pacer_panel.setLayout(self.pacer_config)
        self.hlayout1.addWidget(self.pacer_panel, stretch=25)

        self.recording_config = QGridLayout()
        self.recording_config.addWidget(self.start_recording_button, 0, 0)
        self.recording_config.addWidget(self.save_recording_button, 0, 1)
        self.recording_config.addWidget(self.recording_statusbar, 0, 2)
        self.recording_config.addWidget(self.annotation, 1, 0, 1,
                                        2)  # row, column, rowspan, columnspan
        self.recording_config.addWidget(self.annotation_button, 1, 2)

        self.recording_panel = QGroupBox("Recording")
        self.recording_panel.setLayout(self.recording_config)
        self.hlayout1.addWidget(self.recording_panel, stretch=25)

        self.vlayout0.addLayout(self.hlayout1)

        self.model.ibis_buffer_update.connect(self.plot_ibis)
        self.model.mean_hrv_update.connect(self.plot_hrv)
        self.model.mac_addresses_update.connect(self.list_macs)
        self.model.pacer_disk_update.connect(self.plot_pacer_disk)
        self.model.pacer_rate_update.connect(self.update_pacer_label)
        self.model.hrv_target_update.connect(self.update_hrv_target)

        self.scanner_thread.start()
        self.sensor_thread.start()
        self.redis_publisher_thread.start()
        self.redis_logger_thread.start()

    def closeEvent(self, event):
        """Properly shut down all threads."""
        print("Closing threads...")
        self.scanner_thread.quit()
        self.scanner_thread.wait()

        self.sensor_thread.quit(
        )  # since quit() only works if the thread has a running event loop...
        asyncio.run_coroutine_threadsafe(
            self.sensor.stop(), self.sensor.loop
        )  # ...the event loop must only be stopped AFTER quit() has been called!
        self.sensor_thread.wait()

        self.redis_publisher_thread.quit()
        self.redis_publisher_thread.wait()

        self.redis_logger_thread.quit()
        self.redis_logger_thread.wait()

    def connect_sensor(self):
        mac = self.mac_menu.currentText()
        if not valid_mac(mac):
            print("Invalid MAC.")
            return
        asyncio.run_coroutine_threadsafe(self.sensor.connect_client(mac),
                                         self.sensor.loop)

    def plot_ibis(self, ibis):
        self.ibis_signal.setData(self.model.ibis_seconds, ibis[1])

    def plot_hrv(self, hrv):
        self.mean_hrv_signal.setData(self.model.mean_hrv_seconds, hrv[1])

    def list_macs(self, macs):
        self.mac_menu.clear()
        self.mac_menu.addItems(macs[1])

    def plot_pacer_disk(self, coordinates):
        self.pacer_disc.setData(*coordinates[1])

    def update_pacer_label(self, rate):
        self.pacer_label.setText(f"Rate: {rate[1]}")

    def update_hrv_target(self, target):
        self.mean_hrv_plot.setYRange(0, target[1], padding=0)
        self.hrv_target_label.setText(f"Target: {target[1]}")

    def toggle_pacer(self):
        visible = self.pacer_plot.isVisible()
        self.pacer_plot.setVisible(not visible)

    def show_recording_status(self, status):
        self.recording_statusbar.setRange(
            0, status)  # indicates busy state if progress is 0

    def emit_annotation(self):
        self.signals.annotation.emit(
            ("eventmarker", self.annotation.currentText()))
Ejemplo n.º 35
0
class ToolBox(QVBoxLayout):

    sig = QtCore.Signal(object)
    listThread = None
    groupBoxThreadInfo = None
    threadvbox = None
    mode = None

    def __init__(self, mode, parentQWidget = None):
        QVBoxLayout.__init__(self)

        self.sig.connect(self.addThreadList)
        self.mode = mode

        self.sizePolicy = QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Expanding)

        self.groupBoxSearch = QGroupBox()
        self.groupBoxSearch.setStyleSheet("QGroupBox {border: 1px solid gray; border-radius: 4px; };")
        vboxSearch = QVBoxLayout()
        self.searchTitle = QLabel("Search Messages")
        vboxSearch.addWidget(self.searchTitle)
        self.searchHLayout = QHBoxLayout()
        self.editTextSearch = QTextEdit('')
        self.editTextSearch.setFixedSize(200,30)
        self.buttonSearch = QPushButton('Search')
        self.buttonSearch.setFixedSize(100,30)
        self.buttonSearch.clicked.connect(self.searchMsg)
        vboxSearch.addWidget(self.editTextSearch)
        self.searchHLayout.addWidget(self.buttonSearch)
        self.searchCursor = QLabel()
        self.searchHLayout.addWidget(self.searchCursor)
        vboxSearch.addLayout(self.searchHLayout)
        self.browseHLayout = QHBoxLayout()
        self.buttonLookUp = QPushButton('\u21e7')  #Arrow up
        self.buttonLookUp.setFixedWidth(100)
        self.buttonLookUp.clicked.connect(self.moveToPrev)
        self.buttonLookDown = QPushButton('\u21e9') #Arrow down
        self.buttonLookDown.setFixedWidth(100)
        self.buttonLookDown.clicked.connect(self.moveToNext)
        self.browseHLayout.addWidget(self.buttonLookUp)
        self.browseHLayout.addWidget(self.buttonLookDown)
        vboxSearch.addLayout(self.browseHLayout)
        self.groupBoxSearch.setLayout(vboxSearch)
        self.addWidget(self.groupBoxSearch)
        self.groupBoxSearch.setSizePolicy(QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed))

        self.buttonHiddenLifelines = QPushButton('Show hidden life-lines')
        self.buttonHiddenLifelines.setFixedWidth(200)
        self.buttonHiddenLifelines.clicked.connect(self.showHiddenLifelines)
        self.addWidget(self.buttonHiddenLifelines)

        self.buttonHiddenMessages = QPushButton('Show hidden Messages')
        self.buttonHiddenMessages.setFixedWidth(200)
        self.buttonHiddenMessages.clicked.connect(self.showHiddenMessages)
        self.addWidget(self.buttonHiddenMessages)

        if const.mode_interactive == mode:
            self.buttonCapture = QPushButton('Capture')
            self.buttonCapture.setFixedWidth(200)
            self.buttonCapture.clicked.connect(self.notifyCapture)
            self.addWidget(self.buttonCapture)
        self.msgRcv = []
        self.msgInfo = QLabel("Message Info.")
        self.groupBoxMessageInfo = QGroupBox()
        self.groupBoxMessageInfo.setStyleSheet("QGroupBox {border: 1px solid gray; border-radius: 9px; margin-top: 0.5em} QGroupBox::title {subcontrol-origin: margin; left: 10px; padding: 0 3px 0 3px;")
        vbox = QVBoxLayout()
        vbox.addWidget(self.msgInfo)
        self.tableTime = QTableWidget(3,2)
        self.tableTime.setHorizontalHeaderLabels(['-','time'])
        self.tableTime.setColumnWidth(0,80)
        self.tableTime.setColumnWidth(1,150)
        vwidth = self.tableTime.verticalHeader().length()
        hwidth = self.tableTime.horizontalHeader().height()
        fwidth = self.tableTime.frameWidth() * 2
        self.tableTime.setFixedHeight(vwidth + hwidth + fwidth)
        self.tableTime.horizontalHeader().setStretchLastSection(True)
        self.tableTime.setItem(0,0,QTableWidgetItem('begin'))
        self.tableTime.setItem(0,1,QTableWidgetItem(' - '))
        self.tableTime.setItem(1,0,QTableWidgetItem('end'))
        self.tableTime.setItem(1,1,QTableWidgetItem(' - '))
        self.tableTime.setItem(2,0,QTableWidgetItem('duration'))
        self.tableTime.setItem(2,1,QTableWidgetItem(' - '))
        vbox.addWidget(self.tableTime)

        self.titleArg = QLabel('Argument List')
        vbox.addWidget(self.titleArg)

        max_arg_num = 10
        self.tableArgs = QTableWidget(max_arg_num,2)
        self.tableArgs.setHorizontalHeaderLabels(['type','value'])
        for idx in range(0,max_arg_num):
            self.tableArgs.setItem(idx,0,QTableWidgetItem())
            self.tableArgs.setItem(idx,1,QTableWidgetItem())
        self.tableArgs.horizontalHeader().setStretchLastSection(True)
        vbox.addWidget(self.tableArgs)

        self.titleArg = QLabel('Return Value List')
        vbox.addWidget(self.titleArg)

        max_ret_num = 4
        self.tableRet = QTableWidget(max_ret_num,2)
        self.tableRet.setHorizontalHeaderLabels(['type','value'])
        for idx in range(0,max_ret_num):
            self.tableRet.setItem(idx,0,QTableWidgetItem())
            self.tableRet.setItem(idx,1,QTableWidgetItem())
        self.tableRet.horizontalHeader().setStretchLastSection(True)
        vwidth = self.tableRet.verticalHeader().length()
        hwidth = self.tableRet.horizontalHeader().height()
        fwidth = self.tableRet.frameWidth() * 2
        self.tableRet.setFixedHeight(vwidth + hwidth + fwidth)
        vbox.addWidget(self.tableRet)

        self.buttonSrcView = QPushButton('view code')
        self.buttonSrcView.setFixedWidth(200)
        self.buttonSrcView.clicked.connect(self.openSourceViewer)
        self.buttonHide = QPushButton('Hide')
        self.buttonHide.setFixedWidth(200)
        self.buttonHide.clicked.connect(self.notifyHide)
        self.buttonHideAllMsg = QPushButton('Hide All')
        self.buttonHideAllMsg.setFixedWidth(200)
        self.buttonHideAllMsg.clicked.connect(self.hideAllMsgNamedAsSelected)
        self.groupBoxMessageInfo.setLayout(vbox)
        self.checkHideCircular = QCheckBox('Hide Circular Messages')
        self.checkHideCircular.setCheckState(QtCore.Qt.Unchecked)
        self.checkHideCircular.stateChanged.connect(self.changeHideCircularMessage)
        self.addWidget(self.checkHideCircular)
        self.addWidget(self.groupBoxMessageInfo)
        self.groupBoxMessageInfo.setSizePolicy(self.sizePolicy)

    def reset(self):
        for idx in reversed(range(0,self.listThread.count())):
            self.listThread.takeItem(idx)

    def setMsgInfoMessage(self,msg):
        self.strMessage = msg

    def changeHideCircularMessage(self,state):
        if state == QtCore.Qt.Unchecked:
            self.diagramView.hideCircularChanged(False)
        elif state == QtCore.Qt.Checked:
            self.diagramView.hideCircularChanged(True)
    
    def setMsgInfoModule(self,module):
        self.strModule = module

    def updateSearchStatus(self,curr,number):
        self.searchCursor.setText("%d/%d" % (curr,number))

    def connectSourceViewer(self,viewer):
        self.srcViewer = viewer

    def openSourceViewer(self):
        self.srcViewer.openViewer(self.strModule,self.strMessage)

    def setMessageInfoTime(self,begin,end,duration):
        self.tableTime.item(0,1).setText(begin)
        self.tableTime.item(1,1).setText(end)
        self.tableTime.item(2,1).setText(duration + ' msec')

    def setMessageInfoArg(self,listParam,listArg):
        # Clear the contents in the table
        max_arg_num = 10
        for idx in range(0,max_arg_num):
            self.tableArgs.item(idx,0).setText('')
            self.tableArgs.item(idx,1).setText('')

        if listArg:
            for idx, text in enumerate(listArg):
                self.tableArgs.item(idx,1).setText(text)
            for idx, text in enumerate(listParam):
                self.tableArgs.item(idx,0).setText(text)
        else:
            for idx in range(0,self.tableArgs.rowCount()):
                self.tableArgs.item(idx,1).setText('')
                self.tableArgs.item(idx,0).setText('')

    def setMessageInfoRet(self,listRet):
        if listRet:
            for idx, text in enumerate(listRet):
                self.tableRet.item(idx,1).setText(text)
        else:
            for idx in range(0,self.tableRet.rowCount()):
                self.tableRet.item(idx,1).setText('')
                self.tableRet.item(idx,0).setText('')

    def notifyInteractiveStateChanged(self,state):
        if const.mode_interactive != self.mode:
            return

        if const.STATE_INTERACTIVE_CAPTURING == state:
            self.buttonCapture.setEnabled(True)
            self.buttonCapture.setText('Stop Capture')
        if const.STATE_INTERACTIVE_PROCESSING == state:
            self.buttonCapture.setEnabled(False)
        if const.STATE_INTERACTIVE_IDLE == state:
            self.buttonCapture.setEnabled(True)
            self.buttonCapture.setText('Capture')
        if const.STATE_INTERACTIVE_RESET == state:
            self.buttonCapture.setEnabled(True)
            self.buttonCapture.setText('Capture')
        elif const.STATE_INTERACTIVE_ACTIVE == state:
            self.buttonCapture.setEnabled(True)
            self.buttonCapture.setText('Capture')

    def setMessageInfo(self,info):
        self.msgInfo.setText(info)

    def setAvailable(self,threads):
        self.sig.emit(threads)

    def toggleThreadDisplay(self,item):
        print(self.listThread.currentRow())
        #if item.isSelected():
        #    print(item.text() + "  is selected")
        #else:
        #    print(item.text() + "  is not selected")
        self.diagramView.showThread(self.listThread.currentRow(),item.isSelected())

    def hideAllMsgNamedAsSelected(self):
        self.diagramView.hideAllMessageSelected()

    def addThreadList(self,threads):

        if not self.groupBoxThreadInfo:
            self.groupBoxThreadInfo = QGroupBox()
            self.threadInfo = QLabel("Thread Info.")
            self.groupBoxThreadInfo.setStyleSheet("QGroupBox {border: 1px solid gray; border-radius: 9px; margin-top: 0.5em} QGroupBox::title {subcontrol-origin: margin; left: 10px; padding: 0 3px 0 3px;")

        if not self.threadvbox:
            self.threadvbox = QVBoxLayout()

        if not self.listThread:
            self.listThread = QListWidget()
            
        self.listThread.setFixedWidth(200)
        self.listThread.setSelectionMode(QAbstractItemView.MultiSelection)
        QtCore.QObject.connect(self.listThread, QtCore.SIGNAL("itemClicked(QListWidgetItem *)"), self.toggleThreadDisplay)
        self.threadvbox.addWidget(self.threadInfo)
        self.threadvbox.addWidget(self.listThread)
        self.groupBoxThreadInfo.setLayout(self.threadvbox)
        self.addWidget(self.groupBoxThreadInfo)
        self.groupBoxThreadInfo.setSizePolicy(self.sizePolicy)

        for id in threads:
            item = QListWidgetItem(id)
            self.listThread.addItem(item)

    def connectController(self,controller):
        self.controller = controller
        self.connect(controller,QtCore.SIGNAL('setAvailable()'),self.setAvailable)
       
    def connectDiagramView(self,view):
        self.diagramView = view
 
    def disconnectMsgRcv(self,receiver):
        print("Implement this method !!! disconnectMsgRcv")

    def connectMsgRcv(self,receiver):
        self.msgRcv.append(receiver)

    def notifyHide(self):
        for rcv in self.msgRcv:
            rcv.activateHide(True)

    def showHiddenLifelines(self):
        response, selected_items = HiddenDialog.HiddenDialog.getSelectedItems(self.diagramView.getHiddenLifeLines())
        if response:
            self.diagramView.showLifelines(selected_items)

    def showHiddenMessages(self):
        response, selected_items = HiddenMessageDialog.HiddenMessageDialog.getSelectedItems(self.diagramView.getHiddenMessages(),self.diagramView.getHiddenLifeLines())
        if response:
            if selected_items[3] in self.diagramView.getHiddenLifeLines():
                confirmation = ShowLifeLineDialog.ShowLifeLineDialog.confirmToShowLifeLine(selected_items[3])
                if confirmation:
                    self.diagramView.showLifelines([selected_items[3]])
                    self.diagramView.showMessages(selected_items)
            else:
                self.diagramView.showMessages(selected_items)

    def notifyCapture(self):
        for rcv in self.msgRcv:
            rcv.activateCapture(True)
    
    def moveToPrev(self):
        for rcv in self.msgRcv:
            rcv.moveToPrev()
        
    def moveToNext(self):
        for rcv in self.msgRcv:
            rcv.moveToNext()

    def searchMsg(self):
        str = self.editTextSearch.toPlainText()
        for rcv in self.msgRcv:
            rcv.searchMessage(str)
Ejemplo n.º 36
0
    def __init__(self, model):
        super().__init__()

        self.setWindowTitle("OpenHRV")
        self.setWindowIcon(QIcon(":/logo.png"))
        self.setGeometry(50, 50, 1750, 850)

        self.model = model
        self.signals = ViewSignals()

        self.scanner = SensorScanner()
        self.scanner_thread = QThread(self)
        self.scanner.moveToThread(self.scanner_thread)
        self.scanner.mac_update.connect(self.model.set_mac_addresses)

        self.sensor = SensorClient()
        self.sensor_thread = QThread(self)
        self.sensor.moveToThread(self.sensor_thread)
        self.sensor.ibi_update.connect(self.model.set_ibis_buffer)
        self.sensor_thread.started.connect(self.sensor.run)

        self.redis_publisher = RedisPublisher()
        self.redis_publisher_thread = QThread(self)
        self.redis_publisher.moveToThread(self.redis_publisher_thread)
        self.model.ibis_buffer_update.connect(self.redis_publisher.publish)
        self.model.mean_hrv_update.connect(self.redis_publisher.publish)
        self.model.mac_addresses_update.connect(self.redis_publisher.publish)
        self.model.pacer_rate_update.connect(self.redis_publisher.publish)
        self.model.hrv_target_update.connect(self.redis_publisher.publish)
        self.model.biofeedback_update.connect(self.redis_publisher.publish)
        self.signals.annotation.connect(self.redis_publisher.publish)
        self.redis_publisher_thread.started.connect(
            self.redis_publisher.monitor.start)

        self.redis_logger = RedisLogger()
        self.redis_logger_thread = QThread(self)
        self.redis_logger.moveToThread(self.redis_logger_thread)
        self.redis_logger_thread.finished.connect(
            self.redis_logger.save_recording)
        self.redis_logger.recording_status.connect(self.show_recording_status)

        self.ibis_plot = pg.PlotWidget()
        self.ibis_plot.setBackground("w")
        self.ibis_plot.setLabel("left", "Inter-Beat-Interval (msec)",
                                **{"font-size": "25px"})
        self.ibis_plot.setLabel("bottom", "Seconds", **{"font-size": "25px"})
        self.ibis_plot.showGrid(y=True)
        self.ibis_plot.setYRange(300, 1500, padding=0)
        self.ibis_plot.setMouseEnabled(x=False, y=False)

        self.ibis_signal = pg.PlotCurveItem()
        pen = pg.mkPen(color=(0, 191, 255), width=7.5)
        self.ibis_signal.setPen(pen)
        self.ibis_signal.setData(self.model.ibis_seconds,
                                 self.model.ibis_buffer)
        self.ibis_plot.addItem(self.ibis_signal)

        self.mean_hrv_plot = pg.PlotWidget()
        self.mean_hrv_plot.setBackground("w")
        self.mean_hrv_plot.setLabel("left", "HRV (msec)",
                                    **{"font-size": "25px"})
        self.mean_hrv_plot.setLabel("bottom", "Seconds",
                                    **{"font-size": "25px"})
        self.mean_hrv_plot.showGrid(y=True)
        self.mean_hrv_plot.setYRange(0, 600, padding=0)
        self.mean_hrv_plot.setMouseEnabled(x=False, y=False)
        colorgrad = QLinearGradient(0, 0, 0, 1)  # horizontal gradient
        colorgrad.setCoordinateMode(QGradient.ObjectMode)
        colorgrad.setColorAt(0, pg.mkColor("g"))
        colorgrad.setColorAt(.5, pg.mkColor("y"))
        colorgrad.setColorAt(1, pg.mkColor("r"))
        brush = QBrush(colorgrad)
        self.mean_hrv_plot.getViewBox().setBackgroundColor(brush)

        self.mean_hrv_signal = pg.PlotCurveItem()
        pen = pg.mkPen(color="w", width=7.5)
        self.mean_hrv_signal.setPen(pen)
        self.mean_hrv_signal.setData(self.model.mean_hrv_seconds,
                                     self.model.mean_hrv_buffer)
        self.mean_hrv_plot.addItem(self.mean_hrv_signal)

        self.pacer_plot = pg.PlotWidget()
        self.pacer_plot.setBackground("w")
        self.pacer_plot.setAspectLocked(lock=True, ratio=1)
        self.pacer_plot.setMouseEnabled(x=False, y=False)
        self.pacer_plot.disableAutoRange()
        self.pacer_plot.setXRange(-1, 1, padding=0)
        self.pacer_plot.setYRange(-1, 1, padding=0)
        self.pacer_plot.hideAxis("left")
        self.pacer_plot.hideAxis("bottom")

        self.pacer_disc = pg.PlotCurveItem()
        brush = pg.mkBrush(color=(135, 206, 250))
        self.pacer_disc.setBrush(brush)
        self.pacer_disc.setFillLevel(1)
        self.pacer_plot.addItem(self.pacer_disc)

        self.pacer_rate = QSlider(Qt.Horizontal)
        self.pacer_rate.setTracking(False)
        self.pacer_rate.setRange(
            0, 6)  # transformed to bpm [4, 7], step .5 by model
        self.pacer_rate.valueChanged.connect(self.model.set_breathing_rate)
        self.pacer_rate.setSliderPosition(4)  # corresponds to 6 bpm
        self.pacer_label = QLabel(f"Rate: {self.model.breathing_rate}")

        self.pacer_toggle = QCheckBox("Show pacer", self)
        self.pacer_toggle.setChecked(True)
        self.pacer_toggle.stateChanged.connect(self.toggle_pacer)

        self.hrv_target_label = QLabel(f"Target: {self.model.hrv_target}")

        self.hrv_target = QSlider(Qt.Horizontal)
        self.hrv_target.setRange(50, 600)
        self.hrv_target.setSingleStep(10)
        self.hrv_target.valueChanged.connect(self.model.set_hrv_target)
        self.hrv_target.setSliderPosition(self.model.hrv_target)
        self.mean_hrv_plot.setYRange(0, self.model.hrv_target, padding=0)

        self.scan_button = QPushButton("Scan")
        self.scan_button.clicked.connect(self.scanner.scan)

        self.mac_menu = QComboBox()

        self.connect_button = QPushButton("Connect")
        self.connect_button.clicked.connect(self.connect_sensor)

        self.start_recording_button = QPushButton("Start")
        self.start_recording_button.clicked.connect(
            self.redis_logger.start_recording)

        self.save_recording_button = QPushButton("Save")
        self.save_recording_button.clicked.connect(
            self.redis_logger.save_recording)

        self.annotation = QComboBox()
        self.annotation.setEditable(True)
        self.annotation.setDuplicatesEnabled(False)
        self.annotation.addItems([
            "start_baseline", "end_baseline", "start_bf", "end_bf",
            "start_nobf", "end_nobf"
        ])
        self.annotation.setMaxCount(
            10)  # user can configure up to 4 additional custom annotations
        self.annotation_button = QPushButton("Annotate")
        self.annotation_button.clicked.connect(self.emit_annotation)
        self.central_widget = QWidget()
        self.setCentralWidget(self.central_widget)

        self.recording_status_label = QLabel("Status:")
        self.recording_statusbar = QProgressBar()
        self.recording_statusbar.setRange(0, 1)

        self.vlayout0 = QVBoxLayout(self.central_widget)

        self.hlayout0 = QHBoxLayout()
        self.hlayout0.addWidget(self.ibis_plot, stretch=80)
        self.hlayout0.addWidget(self.pacer_plot, stretch=20)
        self.vlayout0.addLayout(self.hlayout0)

        self.vlayout0.addWidget(self.mean_hrv_plot)

        self.hlayout1 = QHBoxLayout()

        self.device_config = QFormLayout()
        self.device_config.addRow(self.scan_button, self.mac_menu)
        self.device_config.addRow(self.connect_button)
        self.device_panel = QGroupBox("ECG Devices")
        self.device_panel.setLayout(self.device_config)
        self.hlayout1.addWidget(self.device_panel, stretch=25)

        self.hrv_config = QFormLayout()
        self.hrv_config.addRow(self.hrv_target_label, self.hrv_target)
        self.hrv_panel = QGroupBox("HRV Settings")
        self.hrv_panel.setLayout(self.hrv_config)
        self.hlayout1.addWidget(self.hrv_panel, stretch=25)

        self.pacer_config = QFormLayout()
        self.pacer_config.addRow(self.pacer_label, self.pacer_rate)
        self.pacer_config.addRow(self.pacer_toggle)
        self.pacer_panel = QGroupBox("Breathing Pacer")
        self.pacer_panel.setLayout(self.pacer_config)
        self.hlayout1.addWidget(self.pacer_panel, stretch=25)

        self.recording_config = QGridLayout()
        self.recording_config.addWidget(self.start_recording_button, 0, 0)
        self.recording_config.addWidget(self.save_recording_button, 0, 1)
        self.recording_config.addWidget(self.recording_statusbar, 0, 2)
        self.recording_config.addWidget(self.annotation, 1, 0, 1,
                                        2)  # row, column, rowspan, columnspan
        self.recording_config.addWidget(self.annotation_button, 1, 2)

        self.recording_panel = QGroupBox("Recording")
        self.recording_panel.setLayout(self.recording_config)
        self.hlayout1.addWidget(self.recording_panel, stretch=25)

        self.vlayout0.addLayout(self.hlayout1)

        self.model.ibis_buffer_update.connect(self.plot_ibis)
        self.model.mean_hrv_update.connect(self.plot_hrv)
        self.model.mac_addresses_update.connect(self.list_macs)
        self.model.pacer_disk_update.connect(self.plot_pacer_disk)
        self.model.pacer_rate_update.connect(self.update_pacer_label)
        self.model.hrv_target_update.connect(self.update_hrv_target)

        self.scanner_thread.start()
        self.sensor_thread.start()
        self.redis_publisher_thread.start()
        self.redis_logger_thread.start()