Exemplo n.º 1
0
    def _load(self):
        if self.loaded:
            return

        self.service = locator.get_scoped("DialogueService")
        module_service = locator.get_scoped("ModuleService")
        characters_model = module_service.get_module(
            "Characters").entries_model

        layout = QHBoxLayout(self)
        characters_list = QListView()
        characters_list.setModel(characters_model)
        characters_list.setSizePolicy(
            QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Expanding))
        characters_list.selectionModel().currentRowChanged.connect(
            self._update_selection)
        self.list = characters_list

        scroll_area = QScrollArea()
        form_container = QWidget()
        form = QFormLayout()
        self.editors = []
        for dialogue in self.service.dialogues:
            label = QLabel(dialogue.name)
            editor = QLineEdit()
            editor.editingFinished.connect(
                lambda e=editor, d=dialogue: self._on_editor_change(e, d))
            self.editors.append(editor)
            form.addRow(label, editor)
        form_container.setLayout(form)
        scroll_area.setWidgetResizable(True)
        scroll_area.setWidget(form_container)

        layout.addWidget(characters_list)
        layout.addWidget(scroll_area)
        self.setLayout(layout)

        self.service.load()
        self.loaded = True
Exemplo n.º 2
0
class QSettingsWindow(QDialog):

    def __init__(self, game: Game):
        super(QSettingsWindow, self).__init__()

        self.game = game

        self.setModal(True)
        self.setWindowTitle("Settings")
        self.setWindowIcon(CONST.ICONS["Settings"])
        self.setMinimumSize(600, 250)

        self.initUi()

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

        self.categoryList = QListView()
        self.right_layout = QStackedLayout()

        self.categoryList.setMaximumWidth(175)

        self.categoryModel = QStandardItemModel(self.categoryList)

        difficulty = QStandardItem("Difficulty")
        difficulty.setIcon(CONST.ICONS["Missile"])
        difficulty.setEditable(False)
        difficulty.setSelectable(True)

        generator = QStandardItem("Mission Generator")
        generator.setIcon(CONST.ICONS["Generator"])
        generator.setEditable(False)
        generator.setSelectable(True)

        cheat = QStandardItem("Cheat Menu")
        cheat.setIcon(CONST.ICONS["Cheat"])
        cheat.setEditable(False)
        cheat.setSelectable(True)

        self.categoryList.setIconSize(QSize(32, 32))
        self.categoryModel.appendRow(difficulty)
        self.categoryModel.appendRow(generator)
        self.categoryModel.appendRow(cheat)

        self.categoryList.setSelectionBehavior(QAbstractItemView.SelectRows)
        self.categoryList.setModel(self.categoryModel)
        self.categoryList.selectionModel().setCurrentIndex(self.categoryList.indexAt(QPoint(1,1)), QItemSelectionModel.Select)
        self.categoryList.selectionModel().selectionChanged.connect(self.onSelectionChanged)

        self.initDifficultyLayout()
        self.initGeneratorLayout()
        self.initCheatLayout()

        self.right_layout.addWidget(self.difficultyPage)
        self.right_layout.addWidget(self.generatorPage)
        self.right_layout.addWidget(self.cheatPage)

        self.layout.addWidget(self.categoryList, 0, 0, 1, 1)
        self.layout.addLayout(self.right_layout, 0, 1, 5, 1)

        self.setLayout(self.layout)

    def init(self):
        pass

    def initDifficultyLayout(self):

        self.difficultyPage = QWidget()
        self.difficultyLayout = QGridLayout()
        self.difficultyLayout.setAlignment(Qt.AlignTop)
        self.difficultyPage.setLayout(self.difficultyLayout)

        self.playerCoalitionSkill = QComboBox()
        self.enemyCoalitionSkill = QComboBox()
        self.enemyAASkill = QComboBox()
        for skill in CONST.SKILL_OPTIONS:
            self.playerCoalitionSkill.addItem(skill)
            self.enemyCoalitionSkill.addItem(skill)
            self.enemyAASkill.addItem(skill)

        self.playerCoalitionSkill.setCurrentIndex(CONST.SKILL_OPTIONS.index(self.game.settings.player_skill))
        self.enemyCoalitionSkill.setCurrentIndex(CONST.SKILL_OPTIONS.index(self.game.settings.enemy_skill))
        self.enemyAASkill.setCurrentIndex(CONST.SKILL_OPTIONS.index(self.game.settings.enemy_vehicle_skill))

        self.playerCoalitionSkill.currentIndexChanged.connect(self.applySettings)
        self.enemyCoalitionSkill.currentIndexChanged.connect(self.applySettings)
        self.enemyAASkill.currentIndexChanged.connect(self.applySettings)

        self.difficultyLayout.addWidget(QLabel("Player coalition skill"), 0, 0)
        self.difficultyLayout.addWidget(self.playerCoalitionSkill, 0, 1, Qt.AlignRight)
        self.difficultyLayout.addWidget(QLabel("Enemy skill"), 1, 0)
        self.difficultyLayout.addWidget(self.enemyCoalitionSkill, 1, 1, Qt.AlignRight)
        self.difficultyLayout.addWidget(QLabel("Enemy AA and vehicles skill"), 2, 0)
        self.difficultyLayout.addWidget(self.enemyAASkill, 2, 1, Qt.AlignRight)

        self.difficultyLabel = QComboBox()
        [self.difficultyLabel.addItem(t) for t in CONST.LABELS_OPTIONS]
        self.difficultyLabel.setCurrentIndex(CONST.LABELS_OPTIONS.index(self.game.settings.labels))
        self.difficultyLabel.currentIndexChanged.connect(self.applySettings)

        self.difficultyLayout.addWidget(QLabel("In Game Labels"), 3, 0)
        self.difficultyLayout.addWidget(self.difficultyLabel, 3, 1, Qt.AlignRight)

        self.noNightMission = QCheckBox()
        self.noNightMission.setChecked(self.game.settings.night_disabled)
        self.noNightMission.toggled.connect(self.applySettings)
        self.difficultyLayout.addWidget(QLabel("No night missions"), 4, 0)
        self.difficultyLayout.addWidget(self.noNightMission, 4, 1, Qt.AlignRight)

        self.mapVisibiitySelection = QComboBox()
        self.mapVisibiitySelection.addItem("All", ForcedOptions.Views.All)
        if self.game.settings.map_coalition_visibility == ForcedOptions.Views.All:
            self.mapVisibiitySelection.setCurrentIndex(0)
        self.mapVisibiitySelection.addItem("Fog of War", ForcedOptions.Views.Allies)
        if self.game.settings.map_coalition_visibility == ForcedOptions.Views.Allies:
            self.mapVisibiitySelection.setCurrentIndex(1)
        self.mapVisibiitySelection.addItem("Allies Only", ForcedOptions.Views.OnlyAllies)
        if self.game.settings.map_coalition_visibility == ForcedOptions.Views.OnlyAllies:
            self.mapVisibiitySelection.setCurrentIndex(2)
        self.mapVisibiitySelection.addItem("Own Aircraft Only", ForcedOptions.Views.MyAircraft)
        if self.game.settings.map_coalition_visibility == ForcedOptions.Views.MyAircraft:
            self.mapVisibiitySelection.setCurrentIndex(3)
        self.mapVisibiitySelection.addItem("Map Only", ForcedOptions.Views.OnlyMap)
        if self.game.settings.map_coalition_visibility == ForcedOptions.Views.OnlyMap:
            self.mapVisibiitySelection.setCurrentIndex(4)
        self.mapVisibiitySelection.currentIndexChanged.connect(self.applySettings)
        self.difficultyLayout.addWidget(QLabel("Map visibility options"), 5, 0)
        self.difficultyLayout.addWidget(self.mapVisibiitySelection, 5, 1, Qt.AlignRight)

        self.ext_views = QCheckBox()
        self.ext_views.setChecked(self.game.settings.external_views_allowed)
        self.ext_views.toggled.connect(self.applySettings)
        self.difficultyLayout.addWidget(QLabel("Allow external views"), 6, 0)
        self.difficultyLayout.addWidget(self.ext_views, 6, 1, Qt.AlignRight)


    def initGeneratorLayout(self):
        self.generatorPage = QWidget()
        self.generatorLayout = QVBoxLayout()
        self.generatorLayout.setAlignment(Qt.AlignTop)
        self.generatorPage.setLayout(self.generatorLayout)

        self.gameplay = QGroupBox("Gameplay")
        self.gameplayLayout = QGridLayout();
        self.gameplayLayout.setAlignment(Qt.AlignTop)
        self.gameplay.setLayout(self.gameplayLayout)

        self.supercarrier = QCheckBox()
        self.supercarrier.setChecked(self.game.settings.supercarrier)
        self.supercarrier.toggled.connect(self.applySettings)

        self.generate_marks = QCheckBox()
        self.generate_marks.setChecked(self.game.settings.generate_marks)
        self.generate_marks.toggled.connect(self.applySettings)


        if not hasattr(self.game.settings, "include_jtac_if_available"):
            self.game.settings.include_jtac_if_available = True

        self.include_jtac_if_available = QCheckBox()
        self.include_jtac_if_available.setChecked(self.game.settings.include_jtac_if_available)
        self.include_jtac_if_available.toggled.connect(self.applySettings)

        self.gameplayLayout.addWidget(QLabel("Use Supercarrier Module"), 0, 0)
        self.gameplayLayout.addWidget(self.supercarrier, 0, 1, Qt.AlignRight)
        self.gameplayLayout.addWidget(QLabel("Put Objective Markers on Map"), 1, 0)
        self.gameplayLayout.addWidget(self.generate_marks, 1, 1, Qt.AlignRight)
        self.gameplayLayout.addWidget(QLabel("Include JTAC (If available)"), 2, 0)
        self.gameplayLayout.addWidget(self.include_jtac_if_available, 2, 1, Qt.AlignRight)

        self.performance = QGroupBox("Performance")
        self.performanceLayout = QGridLayout()
        self.performanceLayout.setAlignment(Qt.AlignTop)
        self.performance.setLayout(self.performanceLayout)

        self.smoke = QCheckBox()
        self.smoke.setChecked(self.game.settings.perf_smoke_gen)
        self.smoke.toggled.connect(self.applySettings)

        self.red_alert = QCheckBox()
        self.red_alert.setChecked(self.game.settings.perf_red_alert_state)
        self.red_alert.toggled.connect(self.applySettings)

        self.arti = QCheckBox()
        self.arti.setChecked(self.game.settings.perf_artillery)
        self.arti.toggled.connect(self.applySettings)

        self.moving_units = QCheckBox()
        self.moving_units.setChecked(self.game.settings.perf_moving_units)
        self.moving_units.toggled.connect(self.applySettings)

        self.infantry = QCheckBox()
        self.infantry.setChecked(self.game.settings.perf_infantry)
        self.infantry.toggled.connect(self.applySettings)

        self.ai_parking_start = QCheckBox()
        self.ai_parking_start.setChecked(self.game.settings.perf_ai_parking_start)
        self.ai_parking_start.toggled.connect(self.applySettings)

        self.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(50)
        self.culling_distance.setMaximum(10000)
        self.culling_distance.setValue(self.game.settings.perf_culling_distance)
        self.culling_distance.valueChanged.connect(self.applySettings)

        self.performanceLayout.addWidget(QLabel("Smoke visual effect on frontline"), 0, 0)
        self.performanceLayout.addWidget(self.smoke, 0, 1, alignment=Qt.AlignRight)
        self.performanceLayout.addWidget(QLabel("SAM starts in RED alert mode"), 1, 0)
        self.performanceLayout.addWidget(self.red_alert, 1, 1, alignment=Qt.AlignRight)
        self.performanceLayout.addWidget(QLabel("Artillery strikes"), 2, 0)
        self.performanceLayout.addWidget(self.arti, 2, 1, alignment=Qt.AlignRight)
        self.performanceLayout.addWidget(QLabel("Moving ground units"), 3, 0)
        self.performanceLayout.addWidget(self.moving_units, 3, 1, alignment=Qt.AlignRight)
        self.performanceLayout.addWidget(QLabel("Generate infantry squads along vehicles"), 4, 0)
        self.performanceLayout.addWidget(self.infantry, 4, 1, alignment=Qt.AlignRight)
        self.performanceLayout.addWidget(QLabel("AI planes parking start (AI starts in flight if disabled)"), 5, 0)
        self.performanceLayout.addWidget(self.ai_parking_start, 5, 1, alignment=Qt.AlignRight)
        self.performanceLayout.addWidget(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.generatorLayout.addWidget(self.gameplay)
        self.generatorLayout.addWidget(QLabel("Disabling settings below may improve performance, but will impact the overall quality of the experience."))
        self.generatorLayout.addWidget(self.performance)


    def initCheatLayout(self):

        self.cheatPage = QWidget()
        self.cheatLayout = QGridLayout()
        self.cheatPage.setLayout(self.cheatLayout)

        self.moneyCheatBox = QGroupBox("Money Cheat")
        self.moneyCheatBox.setAlignment(Qt.AlignTop)
        self.moneyCheatBoxLayout = QGridLayout()
        self.moneyCheatBox.setLayout(self.moneyCheatBoxLayout)

        self.cheat25M = QPushButton("Cheat +25M")
        self.cheat50M = QPushButton("Cheat +50M")
        self.cheat100M = QPushButton("Cheat +100M")
        self.cheat200M = QPushButton("Cheat +200M")
        self.cheat500M = QPushButton("Cheat +500M")
        self.cheat1000M = QPushButton("Cheat +1000M")

        self.cheat25M.clicked.connect(lambda: self.cheatMoney(25))
        self.cheat50M.clicked.connect(lambda: self.cheatMoney(50))
        self.cheat100M.clicked.connect(lambda: self.cheatMoney(100))
        self.cheat200M.clicked.connect(lambda: self.cheatMoney(200))
        self.cheat500M.clicked.connect(lambda: self.cheatMoney(500))
        self.cheat1000M.clicked.connect(lambda: self.cheatMoney(1000))

        self.moneyCheatBoxLayout.addWidget(self.cheat25M, 0, 0)
        self.moneyCheatBoxLayout.addWidget(self.cheat50M, 0, 1)
        self.moneyCheatBoxLayout.addWidget(self.cheat100M, 1, 0)
        self.moneyCheatBoxLayout.addWidget(self.cheat200M, 1, 1)
        self.moneyCheatBoxLayout.addWidget(self.cheat500M, 2, 0)
        self.moneyCheatBoxLayout.addWidget(self.cheat1000M, 2, 1)

        self.cheatLayout.addWidget(self.moneyCheatBox, 0, 0)

    def cheatMoney(self, amount):
        self.game.budget += amount
        self.game.informations.append(Information("CHEATER", "You are a cheater and you should feel bad", self.game.turn))
        GameUpdateSignal.get_instance().updateGame(self.game)

    def applySettings(self):
        self.game.settings.player_skill = CONST.SKILL_OPTIONS[self.playerCoalitionSkill.currentIndex()]
        self.game.settings.enemy_skill = CONST.SKILL_OPTIONS[self.enemyCoalitionSkill.currentIndex()]
        self.game.settings.enemy_vehicle_skill = CONST.SKILL_OPTIONS[self.enemyAASkill.currentIndex()]
        self.game.settings.labels = CONST.LABELS_OPTIONS[self.difficultyLabel.currentIndex()]
        self.game.settings.night_disabled = self.noNightMission.isChecked()
        self.game.settings.map_coalition_visibility = self.mapVisibiitySelection.currentData()
        self.game.settings.external_views_allowed = self.ext_views.isChecked()
        self.game.settings.generate_marks = self.generate_marks.isChecked()
        self.game.settings.include_jtac_if_available = self.include_jtac_if_available.isChecked()

        print(self.game.settings.map_coalition_visibility)

        self.game.settings.supercarrier = self.supercarrier.isChecked()

        self.game.settings.perf_red_alert_state = self.red_alert.isChecked()
        self.game.settings.perf_smoke_gen = self.smoke.isChecked()
        self.game.settings.perf_artillery = self.arti.isChecked()
        self.game.settings.perf_moving_units = self.moving_units.isChecked()
        self.game.settings.perf_infantry = self.infantry.isChecked()
        self.game.settings.perf_ai_parking_start = self.ai_parking_start.isChecked()
        self.game.settings.perf_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())

        GameUpdateSignal.get_instance().updateGame(self.game)

    def onSelectionChanged(self):
        index = self.categoryList.selectionModel().currentIndex().row()
        self.right_layout.setCurrentIndex(index)
Exemplo n.º 3
0
class SourceCodeManager:
    def __init__(self, window):
        self.text_edit = QtGui.QTextEdit(window)
        self.text_edit.setReadOnly(True)
        # FIXME: write an optimized model
        self.traceback = None
        self.traceback_model = QStringListModel()
        self.traceback_view = QListView(window)
        self.traceback_view.setModel(self.traceback_model)
        self.traceback_view.setEditTriggers(
            QtGui.QAbstractItemView.NoEditTriggers)
        window.connect(
            self.traceback_view.selectionModel(),
            QtCore.SIGNAL(
                "selectionChanged(const QItemSelection&, const QItemSelection&)"
            ), self.frame_selection_changed)
        # filename => (lines, mtime)
        self._file_cache = {}
        self.clear()

    def clear(self):
        self._current_file = None
        self._current_lineno = None
        self.traceback_model.setStringList([])
        self.text_edit.setText('')
        self._file_cache.clear()

    def frame_selection_changed(self, selected, unselected):
        indexes = selected.indexes()
        if not indexes:
            return
        row = indexes[0].row()
        frame = self.traceback[row]
        self.show_frame(frame)

    def set_traceback(self, traceback, show_lineno):
        self.traceback = traceback
        if show_lineno:
            lines = [
                '%s:%s' % (frame.filename, frame.lineno) for frame in traceback
            ]
        else:
            lines = [frame.filename for frame in traceback]
        self.traceback_model.setStringList(lines)

    def read_file(self, filename):
        try:
            mtime = os.stat(filename).st_mtime
        except OSError:
            return None

        if filename in self._file_cache:
            text, cache_mtime = self._file_cache[filename]
            if mtime == cache_mtime:
                return text

        print("Read %s content (mtime: %s)" % (filename, mtime))
        with open(filename, 'rb') as fp:
            encoding, lines = detect_encoding(fp.readline)
        lineno = 1
        lines = []
        with io.open(filename, 'r', encoding=encoding) as fp:
            for lineno, line in enumerate(fp, 1):
                lines.append('%d: %s' % (lineno, line.rstrip()))

        text = '\n'.join(lines)
        self._file_cache[filename] = (text, mtime)
        return text

    def load_file(self, filename):
        if filename.startswith("<") and filename.startswith(">"):
            return False
        if self._current_file == filename:
            return True
        text = self.read_file(filename)
        if text is None:
            return False
        self.text_edit.setText(text)
        self._current_file = filename
        self._current_lineno = None
        return True

    def set_line_number(self, lineno):
        if self._current_lineno == lineno:
            return
        self._current_lineno = lineno
        doc = self.text_edit.document()
        # FIXME: complexity in O(number of lines)?
        block = doc.findBlockByLineNumber(lineno - 1)
        cursor = QTextCursor(block)
        cursor.select(QTextCursor.BlockUnderCursor)
        # FIXME: complexity in O(number of lines)?
        self.text_edit.setTextCursor(cursor)

    def show_frame(self, frame):
        filename = frame.filename
        if not self.load_file(filename):
            self._current_file = None
            self.text_edit.setText('')
            return
        if frame.lineno > 0:
            self.set_line_number(frame.lineno)
Exemplo n.º 4
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",
            0,
            50,
            int(self.game.settings.player_income_multiplier * 10),
        )
        self.player_income.spinner.valueChanged.connect(self.applySettings)
        self.enemy_income = TenthsSpinSlider(
            "Enemy income multiplier",
            0,
            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)

        def set_old_awec(value: bool) -> None:
            self.game.settings.disable_legacy_aewc = value

        old_awac = QCheckBox()
        old_awac.setChecked(self.game.settings.disable_legacy_aewc)
        old_awac.toggled.connect(set_old_awec)

        old_awec_info = (
            "If checked, the invulnerable friendly AEW&C aircraft that begins "
            "the mission in the air will not be spawned. AEW&C missions must "
            "be planned in the ATO and will take time to arrive on-station.")

        old_awac.setToolTip(old_awec_info)
        old_awac_label = QLabel(
            "Disable invulnerable, always-available AEW&C (WIP)")
        old_awac_label.setToolTip(old_awec_info)

        general_layout.addWidget(old_awac_label, 1, 0)
        general_layout.addWidget(old_awac, 1, 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.generate_dark_kneeboard = QCheckBox()
        self.generate_dark_kneeboard.setChecked(
            self.game.settings.generate_dark_kneeboard)
        self.generate_dark_kneeboard.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)

        dark_kneeboard_label = QLabel(
            "Generate Dark Kneeboard <br />"
            "<strong>Dark kneeboard for night missions.<br />"
            "This will likely make the kneeboard on the pilot leg unreadable.</strong>"
        )
        self.gameplayLayout.addWidget(dark_kneeboard_label, 2, 0)
        self.gameplayLayout.addWidget(self.generate_dark_kneeboard, 2, 1,
                                      Qt.AlignRight)

        spawn_players_immediately_tooltip = (
            "Always spawns player aircraft immediately, even if their start time is "
            "more than 10 minutes after the start of the mission. <strong>This does "
            "not alter the timing of your mission. Your TOT will not change. This "
            "option only allows the player to wait on the ground.</strong>")
        spawn_immediately_label = QLabel(
            "Player flights ignore TOT and spawn immediately<br />"
            "<strong>Does not adjust package waypoint times.<br />"
            "Should not be used if players have runway or in-air starts.</strong>"
        )
        spawn_immediately_label.setToolTip(spawn_players_immediately_tooltip)
        self.gameplayLayout.addWidget(spawn_immediately_label, 3, 0)
        self.gameplayLayout.addWidget(self.never_delay_players, 3, 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, 4, 0)
        self.gameplayLayout.addWidget(start_type, 4, 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.generate_dark_kneeboard = (
            self.generate_dark_kneeboard.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)
Exemplo n.º 5
0
class MainWindowV2(QMainWindow):
    def newChart(self):
        item = ChartItemModel()
        item.setText('New Chart')
        self.model.appendRow(item)

        widget = ChartWidget(item, self.tabWidget, self)
        self.tabWidget.addTab(widget, "New Chart")

        item.tab = widget

        pass

    def newTable(self):
        item = TableItemModel()
        item.setText('New Table')
        self.model.appendRow(item)

        widget = TableWidget(item, self)
        self.tabWidget.addTab(widget, "New Table")

        item.tab = widget

        pass

    def newDashboard(self):
        item = DashboardItemModel()
        item.setText('New Dashboard')
        self.model.appendRow(item)

        widget = DashboardWidget(item, self)
        self.tabWidget.addTab(widget, "New Dashboard")

        item.tab = widget

        pass

    def closeTab(self):

        indexes = self.navListView.selectionModel().selectedIndexes()
        if indexes:
            ind = indexes[0]
            model = self.navListView.model().itemFromIndex(ind)
            self.navListView.model().removeRow(ind.row())

            self.tabWidget.removeTab(self.tabWidget.indexOf(model.tab))

    def closeTabFromTabWidget(self, i):

        widget = self.tabWidget.widget(i)
        modelIndex = widget.model.index()

        self.navListView.model().removeRow(modelIndex.row())
        self.tabWidget.removeTab(self.tabWidget.indexOf(widget.model.tab))

    # создаём объекты QAction,
    # их удобно вешать на Toolbars, Menus, Buttons

    # QActions - действия - их реализации отделены от того, как именно они вызываются
    # (по button click, toolbar click, menu item click, и так далее)
    # это позволяет легко их вешать в несколько мест

    def createActions(self):
        self.newChartAction = QAction("New Chart",
                                      self,
                                      icon=QIcon('icons/chart.svg'))
        self.newChartAction.triggered.connect(self.newChart)

        self.newTableAction = QAction("New Table",
                                      self,
                                      icon=QIcon('icons/table.svg'))
        self.newTableAction.triggered.connect(self.newTable)

        self.newDashboardAction = QAction("New Dashboard",
                                          self,
                                          icon=QIcon('icons/dashboard.svg'))
        self.newDashboardAction.triggered.connect(self.newDashboard)

        self.closeTabAction = QAction("Close Tab",
                                      self,
                                      icon=QIcon('icons/close.svg'))
        self.closeTabAction.triggered.connect(self.closeTab)

    def setActiveTab(self):
        selectedModel = self.model.itemFromIndex(
            self.navListView.selectedIndexes()[0])
        self.tabWidget.setCurrentWidget(selectedModel.tab)

    def __init__(self):
        super(MainWindowV2, self).__init__()

        # self.model - вместо трёх отдельных lists (arr_sheet, arr_Dash, arr_Tab)
        # в QStandardItemModel будем append-ить
        # один из трёх классов, наследующихся от QStandardItem

        self.model = QStandardItemModel(self)

        self.tabWidget = QTabWidget(self)
        self.tabWidget.setTabPosition(QTabWidget.South)
        self.tabWidget.setTabsClosable(True)  # можно премещать вкладки
        self.tabWidget.setMovable(
            True)  # но пока по нажатию ничего не происходит

        self.tabWidget.tabCloseRequested.connect(self.closeTabFromTabWidget)

        self.setCentralWidget(self.tabWidget)

        # summerfield "Rapid GUI Programming" ch6
        logDockWidget = QDockWidget("Tabs", self)
        logDockWidget.setTitleBarWidget(QWidget())

        # logDockWidget = QDockWidget(self)
        logDockWidget.setObjectName("LogDockWidget")
        logDockWidget.setAllowedAreas(Qt.LeftDockWidgetArea
                                      | Qt.RightDockWidgetArea)
        logDockWidget.setFeatures(QDockWidget.DockWidgetMovable)
        # logDockWidget.setMinimumSize(100, 0)

        self.navListView = QListView()
        self.navListView.setModel(self.model)

        logDockWidget.setWidget(self.navListView)
        self.addDockWidget(Qt.LeftDockWidgetArea, logDockWidget)

        self.createActions()

        tabsToolbar = self.addToolBar("Tabs")
        tabsToolbar.setObjectName("tabsToolBar")
        tabsToolbar.setToolButtonStyle(Qt.ToolButtonTextUnderIcon)

        for action in [
                self.newChartAction, self.newTableAction,
                self.newDashboardAction, self.closeTabAction
        ]:
            tabsToolbar.addAction(action)

        self.navListView.selectionModel().selectionChanged.connect(
            self.setActiveTab)

        # easy start
        self.newChart()
Exemplo n.º 6
0
class Shell(QMainWindow):
    def __init__(self):  # constructor
        super().__init__()  # call the parent's constructor

        # Test data in a model
        self.users = ['User 1', 'User 2', 'User 3']
        self.lv_model = QStringListModel()
        self.lv_model.setStringList(self.users)

        # Create the main window content widget
        w = QWidget()

        # Setup the rest of the main window appearance
        self.setGeometry(300, 300, 640, 480)
        self.setWindowTitle('PySide2 Listview Experiments')
        self.setWindowIcon(QIcon('assets/icons/moon_64x64.png'))

        # Create and set the main layout
        layout = QVBoxLayout()
        w.setLayout(layout)  # Set the layout of the main window content widget
        self.setCentralWidget(w)

        # Create and add components to the layout
        self.lv_label = QLabel('QListView with QStringListModel')
        layout.addWidget(self.lv_label)

        self.lv = QListView()
        self.lv.setSelectionMode(
            QListView.MultiSelection)  # single selection is the default
        self.lv.setModel(self.lv_model)
        self.lv.selectionModel().selectionChanged.connect(self.item_selected)
        layout.addWidget(self.lv)

        self.button = QPushButton('Update model')
        self.button.clicked.connect(self.change_model)
        layout.addWidget(self.button)

        self.selected_label = QLabel('Selected item: none')
        layout.addWidget(self.selected_label)
        layout.addStretch(1)

        self.show()  # display the UI

    def change_model(self):
        the_list = self.lv_model.stringList()
        the_list.append('Another User')
        self.lv_model.setStringList(the_list)

    def item_selected(self):
        # Get the current index (a QModelIndex object) from the QListView
        # From the index, get the data (a QVariant) that you can convert to a QString

        index = self.lv.currentIndex()  # returns the primary QModelIndex
        indices = self.lv.selectedIndexes()  # returns a list of QModelIndex

        selected_text = ''
        for i in indices:
            selected_text += i.data(
            ) + '\n'  # use .data() to get the value from QModelIndex

        self.selected_label.setText(selected_text)
Exemplo n.º 7
0
class QSettingsWindow(QDialog):
    def __init__(self, game: Game):
        super().__init__()

        self.game = game
        self.pluginsPage = None
        self.pluginsOptionsPage = None

        self.pages: dict[str, AutoSettingsPage] = {}
        for page in Settings.pages():
            self.pages[page] = AutoSettingsPage(page, game.settings, self.applySettings)

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

        for name, page in self.pages.items():
            page_item = QStandardItem(name)
            if name in CONST.ICONS:
                page_item.setIcon(CONST.ICONS[name])
            else:
                page_item.setIcon(CONST.ICONS["Generator"])
            page_item.setEditable(False)
            page_item.setSelectable(True)
            self.categoryModel.appendRow(page_item)
            self.right_layout.addWidget(page)

        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 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.blue.budget += amount
        GameUpdateSignal.get_instance().updateGame(self.game)

    def applySettings(self):
        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_unculled_zones()
        GameUpdateSignal.get_instance().updateGame(self.game)

    def onSelectionChanged(self):
        index = self.categoryList.selectionModel().currentIndex().row()
        self.right_layout.setCurrentIndex(index)
Exemplo n.º 8
0
class WordListDialog(QDialog):
    """Window to handle the edition of words in a word set"""
    def __init__(self, parent=None):
        super().__init__(parent)

        self.setWindowTitle(self.tr("Edit Word set"))
        self.setWindowIcon(QIcon(cm.DIR_ICONS + "app.png"))

        box = QVBoxLayout()
        self.add_button = QPushButton(self.tr("Add"))
        self.add_file_button = QPushButton(self.tr("Add from file..."))
        self.del_button = QPushButton(self.tr("Remove"))
        self.del_button.setDisabled(True)

        self.save_button = QPushButton(self.tr("Save"))
        self.save_button.setDisabled(True)
        self.cancel_button = QPushButton(self.tr("Cancel"))

        box.addWidget(self.add_button)
        box.addWidget(self.del_button)
        box.addWidget(self.add_file_button)
        box.addStretch()
        box.addWidget(self.save_button)
        box.addWidget(self.cancel_button)

        self.view = QListView()
        self.model = QStringListModel()
        self.view.setModel(self.model)
        self.view.setSelectionMode(QAbstractItemView.ExtendedSelection)

        hlayout = QHBoxLayout()
        hlayout.addWidget(self.view)
        hlayout.addLayout(box)

        self.setLayout(hlayout)

        self.add_button.pressed.connect(self.on_add)
        self.del_button.pressed.connect(self.on_remove)
        self.add_file_button.pressed.connect(self.on_load_file)

        self.cancel_button.pressed.connect(self.reject)
        self.save_button.pressed.connect(self.accept)
        # Item selected in view
        self.view.selectionModel().selectionChanged.connect(
            self.on_item_selected)
        # Data changed in model
        self.model.dataChanged.connect(self.on_data_changed)
        self.model.rowsInserted.connect(self.on_data_changed)
        self.model.rowsRemoved.connect(self.on_data_changed)

    def on_item_selected(self, *args):
        """Enable the remove button when an item is selected"""
        self.del_button.setEnabled(True)

    def on_data_changed(self, *args):
        """Enable the save button when data in model is changed"""
        self.save_button.setEnabled(True)

    def on_add(self):
        """Allow to manually add a word to the list

        Notes:
            A user must click on save for the changes to take effect.
        """
        data = self.model.stringList()
        data.append(self.tr("<double click to edit>"))
        self.model.setStringList(data)

    def on_remove(self):
        """Remove the selected rows of the list

        Notes:
            A user must click on save for the changes to take effect.
        """
        indexes = self.view.selectionModel().selectedRows()
        while indexes:
            self.model.removeRows(indexes[0].row(), 1)
            indexes = self.view.selectionModel().selectedRows()

        self.del_button.setDisabled(True)

    def on_load_file(self):
        """Allow to automatically add words from a file

        See Also:
            :meth:`load_file`
        """
        # Reload last directory used
        last_directory = QSettings().value("last_directory", QDir.homePath())

        filepath, _ = QFileDialog.getOpenFileName(self,
                                                  self.tr("Open Word set"),
                                                  last_directory,
                                                  self.tr("Text file (*.txt)"))

        if filepath:
            self.load_file(filepath)

    def load_file(self, filename: str):
        """Load file into the view

        Args:
            filename(str): A simple file with a list of words (1 per line)

        Current data filtering:
            - Strip trailing spaces and EOL characters
            - Skip empty lines
            - Skip lines with whitespaces characters (`[ \t\n\r\f\v]`)

        Examples:
            - The following line will be skipped:
            `"abc  def\tghi\t  \r\n"`
            - The following line will be cleaned:
            `"abc\r\n"`
        """
        if not os.path.exists(filename):
            return

        # Sanitize words
        with open(filename, "r") as f_h:
            data = sanitize_words(f_h)

        data.update(self.model.stringList())
        self.model.setStringList(list(data))
        # Simulate signal... TODO: check the syntax...
        self.model.rowsInserted.emit(0, 0, 0)
Exemplo n.º 9
0
class PipelineEditor(QGroupBox):
    def __init__(self, file_picker):
        super().__init__("Pipeline Editor")

        self.setLayout(QVBoxLayout())

        self.file_picker = file_picker

        self.pipeline = Pipeline()
        self.pipelineView = QListView()
        self.pipelineView.setEditTriggers(QAbstractItemView.NoEditTriggers)
        self.pipelineView.setModel(QStandardItemModel())

        self.layout().addWidget(self.pipelineView)

        # === BUTTON CONTAINER ===
        button_rows = QWidget()
        self.layout().addWidget(button_rows)
        button_rows_layout = QVBoxLayout(button_rows)
        button_rows_layout.setContentsMargins(0, 0, 0, 0)

        # === ROW 1 ===
        row_1 = QWidget()
        button_rows_layout.addWidget(row_1)
        row_1_layout = QHBoxLayout(row_1)
        row_1_layout.setContentsMargins(0, 0, 0, 0)

        self.moveUpButton = QPushButton("Move Up")
        row_1_layout.addWidget(self.moveUpButton)
        self.moveUpButton.clicked.connect(self._move_up_listener)

        self.moveDownButton = QPushButton("Move Down")
        row_1_layout.addWidget(self.moveDownButton)
        self.moveDownButton.clicked.connect(self._move_down_listener)

        self.deleteButton = QPushButton("Delete")
        row_1_layout.addWidget(self.deleteButton)
        self.deleteButton.clicked.connect(self._delete_listener)

        # === ROW 2 ===
        row_2 = QWidget()
        button_rows_layout.addWidget(row_2)
        row_2_layout = QHBoxLayout(row_2)
        row_2_layout.setContentsMargins(0, 0, 0, 0)

        self.applyButton = QPushButton("Apply Pipeline")
        row_2_layout.addWidget(self.applyButton)
        self.applyButton.clicked.connect(self._apply_pipeline_listener)

        self.update_pipeline_view()

    def update_pipeline_view(self):
        logging.debug(self.pipeline)
        model = self.pipelineView.model()
        model.clear()

        for t in range(self.pipeline.rowCount()):
            item = QStandardItem()
            item.setText(repr(self.pipeline.data(t)))
            model.appendRow(item)

    def _modify_transformation_listener(self):
        # TODO
        raise NotImplementedError

    def _move_up_listener(self):
        try:
            to_move = self.pipelineView.selectionModel().selectedIndexes(
            )[0].row()
            if to_move < 1:
                return
            self.pipeline.move_transformation_up(to_move)
            self.update_pipeline_view()
            self.pipelineView.setCurrentIndex(self.pipelineView.model().index(
                to_move - 1, 0))
        except IndexError:
            return

    def _move_down_listener(self):
        try:
            to_move = self.pipelineView.selectionModel().selectedIndexes(
            )[0].row()
            if to_move > self.pipelineView.model().rowCount() - 2:
                return
            self.pipeline.move_transformation_down(to_move)
            self.update_pipeline_view()
            self.pipelineView.setCurrentIndex(self.pipelineView.model().index(
                to_move + 1, 0))
        except IndexError:
            return

    def _delete_listener(self):
        try:
            to_delete = self.pipelineView.selectionModel().selectedIndexes(
            )[0].row()
            self.pipeline.remove_transformation(to_delete)
            self.update_pipeline_view()
            if to_delete > self.pipelineView.model().rowCount() - 1:
                self.pipelineView.setCurrentIndex(
                    self.pipelineView.model().index(to_delete - 1, 0))
            else:
                self.pipelineView.setCurrentIndex(
                    self.pipelineView.model().index(to_delete, 0))
        except IndexError:
            return

    def _apply_pipeline_listener(self):
        # Check that at least one transformation has been added to the pipeline
        if self.pipeline.rowCount() == 0:
            no_transformations_messagebox = QMessageBox(self)
            no_transformations_messagebox.setText(
                "ERROR: No transformations selected")
            no_transformations_messagebox.exec_()
            return

        file_sequence = self.file_picker.file_sequence.files

        # Check that at least one file has been added to the file sequence
        if len(file_sequence) == 0:
            no_files_messagebox = QMessageBox(self)
            no_files_messagebox.setText("ERROR: No files selected")
            no_files_messagebox.exec_()
            return

        transformed_sequence = self.pipeline.resolve(file_sequence)

        before_after = list(zip(file_sequence, transformed_sequence))

        preview_text_lines = []
        for rename in before_after:
            preview_text_lines.append(f"{rename[0].name} -> {rename[1].name}")
        preview_text = "\n".join(preview_text_lines)

        confirmation = QMessageBox(self)
        confirmation.setText("Are you sure you want to apply the pipeline?")
        confirmation.setDetailedText(preview_text)
        confirmation.setStandardButtons(QMessageBox.Yes | QMessageBox.No)
        confirmation.setDefaultButton(QMessageBox.No)
        ret = confirmation.exec_()

        if ret == int(QMessageBox.Yes):
            for rename in before_after:
                from_path = rename[0]
                to_path = rename[1]

                shutil.move(str(from_path), str(to_path))
            self.file_picker.clear_file_list()
Exemplo n.º 10
0
class MainWindow(QFrame):
    def __init__(self):
        super().__init__()
        self._linkHistoryModel = ImageModel()
        self._linkHistoryView = QListView()
        self._autoTimer = QTimer()
        self._viewer = QLabel()
        self._play = QPushButton('START')
        self._stop = QPushButton('STOP')

        self._linkHistoryView.setFixedWidth(200)
        self._linkHistoryView.setModel(self._linkHistoryModel)

        self._autoTimer.setInterval(100)
        self._autoTimer.timeout.connect(
            lambda: AsyncRequestManager.downloadRequest(random=True))

        self.setLayout(QHBoxLayout())
        self._innerLayout = QVBoxLayout()
        self._buttonLayout = QHBoxLayout()
        self.layout().addWidget(self._linkHistoryView)
        self.layout().addLayout(self._innerLayout)
        self._innerLayout.addWidget(self._viewer, alignment=Qt.AlignCenter)
        self._innerLayout.addLayout(self._buttonLayout,
                                    alignment=Qt.AlignBottom)
        self._buttonLayout.addWidget(self._play)
        self._buttonLayout.addWidget(self._stop)
        self._linkHistoryView.selectionModel().selectionChanged.connect(
            self._updateViewer)

        AsyncRequestManager.responseReceived.connect(self._newImage)
        AsyncRequestManager.downloadRequest(random=True)
        self._play.clicked.connect(self._autoTimer.start)
        self._stop.clicked.connect(self._autoTimer.stop)

    def _updateViewer(self, selected, deselected):
        # Updates viewer
        index = selected.indexes()[0]
        response = index.data(role=ImageElement.response)
        if not index.data(role=ImageElement.image):
            pixmap = self._makeImage(response)
            self._linkHistoryModel.setData(index,
                                           pixmap,
                                           role=ImageElement.image)

        # if response.headers['Content-Type'] == 'image/gif': #TODO: Find out why QMovie crashes with start()
        #     movie = index.data(role=ImageElement.image)
        #     self._viewer.setMovie(movie)
        #     movie.start()
        # else:
        self._viewer.setPixmap(index.data(role=ImageElement.image))

    def _saveImage(self, response=None):
        # Saves the given response if any, else uses the image stored in the currently selected index
        if response:
            name, data = response.url.rsplit('/', 1)[-1], response.content
        else:
            item = self._linkHistoryView.selectionModel().selectedIndexes()[0]
            name = item.data(role=ImageElement.url).rsplit('/', 1)[-1]
            data = item.data(role=ImageElement.response).content
        saveDirectory = './images'
        if not os.path.exists(saveDirectory):
            os.makedirs(saveDirectory)
        saveDirectory += '/' + name
        with open(saveDirectory, 'wb') as f:
            f.write(data)

    def _makeImage(self, response, maxWidth=700, maxHeight=700):
        # Makes an image for the given response
        # if response.headers['Content-Type'] == 'image/gif':
        #     byteArray = QByteArray(response.content)
        #     buffer = QBuffer(byteArray)
        #     buffer.open(QIODevice.ReadOnly)
        #     mov = QMovie(buffer, b'GIF')
        #     mov.setCacheMode(QMovie.CacheAll)
        #     mov.setSpeed(100)
        #     return mov

        pixmap = QPixmap()
        pixmap.loadFromData(response.content)
        width, height = pixmap.width(), pixmap.height()
        if width > height and width > maxWidth:
            dx = maxWidth / width
            width = min(width, maxWidth)
            height *= dx
        elif height > width and height > maxHeight:
            dy = maxHeight / height
            height = min(height, maxHeight)
            width *= dy
        elif height == width:
            width = height = maxWidth
        scaled = pixmap.scaled(width,
                               height,
                               transformMode=Qt.SmoothTransformation)

        return scaled

    def _makeItem(self, response):
        # Creates an image item from the given response
        item = QStandardItem()
        item.setData(response.url, role=ImageElement.url)
        item.setData(response, role=ImageElement.response)
        item.setData(self._makeImage(response), role=ImageElement.image)

        return item

    def _newImage(self, response):
        # Creates a new image item, adds it to the model, then updates the view
        item = self._makeItem(response)
        self._linkHistoryModel.appendRow(item)
        self._linkHistoryView.selectionModel().select(
            self._linkHistoryModel.indexFromItem(item),
            QItemSelectionModel.ClearAndSelect)

        return item

    def mousePressEvent(self, event):
        if event.button() == Qt.LeftButton:
            AsyncRequestManager.downloadRequest(random=True)
        elif event.button() == Qt.RightButton:
            self._saveImage()

    def keyReleaseEvent(self, event):
        if event.key() == Qt.Key_R:
            for response in randomImgurResponses(10000):
                # newImageItem = self._newImage(response)
                # QApplication.processEvents()
                self._saveImage(response)
Exemplo n.º 11
0
class Completer(QWidget):
    """docstring for ClassName

    Attributes:
        delegate (CompleterDelegate): the delegate use by the view
        model (CompleterModel): the model
        proxy_model (QSortFilterProxyModel ): the proxy model used to filter model
        panel (QLabel): The description widget
        view (QListView): the view 
    
    Signals:
        activated (str): return the keyword selected 
    """

    activated = Signal(str)

    def __init__(self, parent=None):
        super().__init__(parent)

        self._target = None
        self._completion_prefix = ""

        self.setWindowFlag(Qt.Popup)
        self.setFocusPolicy(Qt.NoFocus)

        #  create model
        self.model = CompleterModel()
        self.proxy_model = QSortFilterProxyModel()
        self.proxy_model.setSourceModel(self.model)
        self.proxy_model.setFilterCaseSensitivity(Qt.CaseInsensitive)

        #  create delegate
        self.delegate = CompleterDelegate()
        # create view
        self.view = QListView()
        self.view.setSelectionMode(QAbstractItemView.SingleSelection)
        self.view.setFocusPolicy(Qt.NoFocus)
        self.view.installEventFilter(self)
        self.view.setModel(self.proxy_model)
        self.view.setItemDelegate(self.delegate)
        self.view.setMinimumWidth(200)
        self.view.setUniformItemSizes(True)
        self.view.setSpacing(0)

        self.view.selectionModel().currentRowChanged.connect(
            self._on_row_changed)
        self.setFocusProxy(self.view)

        #  create panel info
        self.panel = QLabel()
        self.panel.setAlignment(Qt.AlignTop)
        self.panel.setMinimumWidth(300)
        self.panel.setWordWrap(True)
        self.panel.setFrameShape(QFrame.StyledPanel)

        # Create layout
        vlayout = QHBoxLayout()
        vlayout.setContentsMargins(0, 0, 0, 0)
        vlayout.setSpacing(0)
        vlayout.addWidget(self.view)
        vlayout.addWidget(self.panel)
        self.setLayout(vlayout)

    def set_target(self, target):
        """Set CodeEdit  
        
        Args:
            target (CodeEdit): The CodeEdit 
        """
        self._target = target
        self.installEventFilter(self._target)

    def eventFilter(self, obj: QObject, event: QEvent) -> bool:
        """Filter event from CodeEdit and QListView
        
        Args:
            obj (QObject): Description
            event (QEvent): Description
        
        Returns:
            bool
        """

        #  Intercept CodeEdit event
        if obj == self._target:
            if event.type() == QEvent.FocusOut:
                # Ignore lost focus!
                return True
            else:
                obj.event(event)
                return True

        # Intercept QListView event
        if obj == self.view:
            #  Redirect event to QTextExit

            if event.type() == QEvent.KeyPress and self._target:

                current = self.view.selectionModel().currentIndex()

                # emit signal when user press return
                if event.key() == Qt.Key_Return:
                    word = current.data()
                    self.activated.emit(word)
                    self.hide()
                    event.ignore()
                    return True

                # use tab to move down/up in the list
                if event.key() == Qt.Key_Tab:
                    if current.row() < self.proxy_model.rowCount() - 1:
                        self.view.setCurrentIndex(
                            self.proxy_model.index(current.row() + 1, 0))
                if event.key() == Qt.Key_Backtab:
                    if current.row() > 0:
                        self.view.setCurrentIndex(
                            self.proxy_model.index(current.row() - 1, 0))

                # Route other key event to the target ! This make possible to write text when completer is visible
                self._target.event(event)

        return super().eventFilter(obj, event)

    def complete(self, rect: QRect):
        """Show completer as popup
        
        Args:
            rect (QRect): the area where to display the completer
        
        """
        if self.proxy_model.rowCount() == 0:
            self.hide()
            return

        if self._target:
            pos = self._target.mapToGlobal(rect.bottomRight())
            self.move(pos)
            self.setFocus()
            if not self.isVisible():
                width = 400
                #height = self.view.sizeHintForRow(0) * self.proxy_model.rowCount() + 3
                #  HACK.. TODO better !
                #height = min(self._target.height() / 2, height)

                #self.resize(width, height)
                self.adjustSize()
                self.show()

    def set_completion_prefix(self, prefix: str):
        """Set prefix and filter model 
        
        Args:
            prefix (str): A prefix keyword used to filter model
        """
        self.view.clearSelection()
        self._completion_prefix = prefix
        self.proxy_model.setFilterRegularExpression(
            QRegularExpression(f"^{prefix}.*",
                               QRegularExpression.CaseInsensitiveOption))
        if self.proxy_model.rowCount() > 0:
            self.select_row(0)

    def select_row(self, row: int):
        """Select a row in the model
        
        Args:
            row (int): a row number
        """
        index = self.proxy_model.index(row, 0)
        self.view.selectionModel().setCurrentIndex(index,
                                                   QItemSelectionModel.Select)

    def completion_prefix(self) -> str:
        """getter of completion_prefix
        
        TODO: use getter / setter 
        
        Returns:
            str: Return the completion_prefix
        """
        return self._completion_prefix

    def hide(self):
        """Override from QWidget

        Hide the completer 
        """
        self.set_completion_prefix("")
        super().hide()

    def _on_row_changed(self, current: QModelIndex, previous: QModelIndex):
        """Slot received when user select a new item in the list.
        This is used to update the panel
        
        Args:
            current (QModelIndex): the selection index
            previous (QModelIndex): UNUSED
        """
        description = current.data(Qt.ToolTipRole)
        self.panel.setText(description)
class InstallPluginDialog(QDialog):

    item_selected = Signal(str)

    def __init__(self, parent):
        """Initialize class"""
        super().__init__(parent)
        self.setWindowTitle('Install plugin')
        QVBoxLayout(self)
        self._line_edit = QLineEdit(self)
        self._line_edit.setPlaceholderText("Search registry...")
        self._list_view = QListView(self)
        self._model = QSortFilterProxyModel(self)
        self._source_model = _InstallPluginModel(self)
        self._model.setSourceModel(self._source_model)
        self._model.setFilterCaseSensitivity(Qt.CaseInsensitive)
        self._list_view.setModel(self._model)
        self._timer = QTimer(self)
        self._timer.setInterval(200)
        self._button_box = QDialogButtonBox(self)
        self._button_box.setStandardButtons(QDialogButtonBox.Cancel
                                            | QDialogButtonBox.Ok)
        self._button_box.button(QDialogButtonBox.Ok).setEnabled(False)
        self.layout().addWidget(self._line_edit)
        self.layout().addWidget(self._list_view)
        self.layout().addWidget(self._button_box)
        self.setAttribute(Qt.WA_DeleteOnClose)
        self.setMinimumWidth(400)
        self._button_box.button(QDialogButtonBox.Cancel).clicked.connect(
            self.close)
        self._button_box.button(QDialogButtonBox.Ok).clicked.connect(
            self._handle_ok_clicked)
        self._list_view.doubleClicked.connect(self._emit_item_selected)
        self._list_view.selectionModel().selectionChanged.connect(
            self._update_ok_button_enabled)
        self._line_edit.textEdited.connect(self._handle_search_text_changed)
        self._timer.timeout.connect(self._filter_model)

    def populate_list(self, names):
        for name in names:
            self._source_model.appendRow(QStandardItem(name))

    @Slot(str)
    def _handle_search_text_changed(self, _text):
        self._timer.start()

    def _filter_model(self):
        self._model.setFilterRegExp(self._line_edit.text())

    @Slot(bool)
    def _handle_ok_clicked(self, _=False):
        index = self._list_view.currentIndex()
        self._emit_item_selected(index)

    @Slot("QModelIndex")
    def _emit_item_selected(self, index):
        if not index.isValid():
            return
        self.item_selected.emit(index.data(Qt.DisplayRole))
        self.close()

    @Slot("QItemSelection", "QItemSelection")
    def _update_ok_button_enabled(self, _selected, _deselected):
        on = self._list_view.selectionModel().hasSelection()
        self._button_box.button(QDialogButtonBox.Ok).setEnabled(on)