Beispiel #1
0
class PlayerInfoField(QWidget): #Widget for inputting player info. 
    names = ['Alex', 'Clifford', 'Tyrone', 'Ava', 'Ralph', 'Emily', 'Falcon', 'Giselle', 'Jaeger', 'Sally', 'Quentin', 'Lara']
    
    def __init__(self, parent, index):
        super(PlayerInfoField, self).__init__(parent)
        self.index = index
        
        self.layout = QHBoxLayout()
        
        self.auto_button = Button(self, 'Auto')
        self.auto_button.setFixedWidth(60)
        self.auto_button.clicked.connect(self.generate_name)
        self.layout.addWidget(self.auto_button)
        
        self.name_field = QLineEdit()
        self.name_field.setPalette(QPalette(Qt.white))
        self.name_field.setPlaceholderText('Name')
        self.name_field.setClearButtonEnabled(True)
        self.name_field.setFixedWidth(250)
        self.layout.addWidget(self.name_field)
        
        self.AItoggle = QCheckBox()
        self.AItoggle.setText('Computer')
        self.AItoggle.setFixedWidth(100)
        self.layout.addWidget(self.AItoggle)
        self.AItoggle.stateChanged.connect(self.AIToggled)
        
        self.AIdifficulty = QComboBox()
        self.AIdifficulty.setPalette(QPalette(Qt.white))
        self.AIdifficulty.setFixedWidth(100)
        self.AIdifficulty.addItems(['Braindead', 'Easy', 'Normal', 'Hard', 'HAL-9000'])
        self.AIdifficulty.setCurrentIndex(2)
        self.AIdifficulty.setDisabled(True)
        self.layout.addWidget(self.AIdifficulty)
        
        self.spacer = QSpacerItem(40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum)
        self.layout.addItem(self.spacer)
        self.layout.setContentsMargins(0, 0, 0, 0)
        
        self.setLayout(self.layout)
        
        
    def generate_name(self):
        self.name_field.setText(PlayerInfoField.names[self.index])
     
    def AIToggled(self):
        if self.AItoggle.checkState() == Qt.Checked:
            self.AIdifficulty.setEnabled(True)
            
        else:
            self.AIdifficulty.setDisabled(True)
Beispiel #2
0
 def _updateModel(self, what=SkyModel.UpdateAll, origin=None):
     if origin is self or not what & (SkyModel.UpdateTags
                                      | SkyModel.UpdateGroupStyle):
         return
     model = self.model
     self._setting_model = True  # to ignore cellChanged() signals (in valueChanged())
     # _item_cb is a dict (with row,col keys) containing the widgets (CheckBoxes ComboBoxes) per each cell
     self._item_cb = {}
     # lists of "list" and "plot" checkboxes per each grouping (excepting the default grouping); each entry is an (row,col,item) tuple.
     # used as argument to self._showControls()
     self._list_controls = []
     self._plot_controls = []
     # list of selection callbacks (to which signals are connected)
     self._callbacks = []
     # set requisite number of rows,and start filling
     self.table.setRowCount(len(model.groupings))
     for irow, group in enumerate(model.groupings):
         self.table.setItem(irow, 0, QTableWidgetItem(group.name))
         if group is model.selgroup:
             self._irow_selgroup = irow
         # total # source in group: skip for "current"
         if group is not model.curgroup:
             self.table.setItem(irow, 1, QTableWidgetItem(str(group.total)))
         # selection controls: skip for current and selection
         if group not in (model.curgroup, model.selgroup):
             btns = QWidget()
             lo = QHBoxLayout(btns)
             lo.setContentsMargins(0, 0, 0, 0)
             lo.setSpacing(0)
             # make selector buttons (depending on which group we're in)
             if group is model.defgroup:
                 Buttons = (("+", lambda src, grp=group: True,
                             "select all sources"),
                            ("-", lambda src, grp=group: False,
                             "unselect all sources"))
             else:
                 Buttons = (
                     ("=", lambda src, grp=group: grp.func(src),
                      "select only this grouping"),
                     ("+",
                      lambda src, grp=group: src.selected or grp.func(src),
                      "add grouping to selection"),
                     ("-", lambda src, grp=group: src.selected and not grp.
                      func(src), "remove grouping from selection"),
                     ("&&",
                      lambda src, grp=group: src.selected and grp.func(src),
                      "intersect selection with grouping"))
             lo.addStretch(1)
             for label, predicate, tooltip in Buttons:
                 btn = QToolButton(btns)
                 btn.setText(label)
                 btn.setMinimumWidth(24)
                 btn.setMaximumWidth(24)
                 btn.setToolTip(tooltip)
                 lo.addWidget(btn)
                 # add callback
                 btn.clicked.connect(
                     self._currier.curry(self.selectSources, predicate))
             lo.addStretch(1)
             self.table.setCellWidget(irow, 2, btns)
         # "list" checkbox (not for current and selected groupings: these are always listed)
         if group not in (model.curgroup, model.selgroup):
             item = self._makeCheckItem("", group, "show_list")
             self.table.setItem(irow, self.ColList, item)
             item.setToolTip(
                 """<P>If checked, sources in this grouping will be listed in the source table. If un-checked, sources will be
         excluded from the table. If partially checked, then the default list/no list setting of "all sources" will be in effect.
         </P>""")
         # "plot" checkbox (not for the current grouping, since that's always plotted)
         if group is not model.curgroup:
             item = self._makeCheckItem("", group, "show_plot")
             self.table.setItem(irow, self.ColPlot, item)
             item.setToolTip(
                 """<P>If checked, sources in this grouping will be included in the plot. If un-checked, sources will be
         excluded from the plot. If partially checked, then the default plot/no plot setting of "all sources" will be in effect.
         </P>""")
         # custom style control
         # for default, current and selected, this is just a text label
         if group is model.defgroup:
             item = QTableWidgetItem("default:")
             item.setTextAlignment(Qt.AlignRight | Qt.AlignVCenter)
             item.setToolTip(
                 """<P>This is the default plot style used for all sources for which a custom grouping style is not selected.</P>"""
             )
             self.table.setItem(irow, self.ColApply, item)
         elif group is model.curgroup:
             item = QTableWidgetItem("")
             item.setTextAlignment(Qt.AlignRight | Qt.AlignVCenter)
             item.setToolTip(
                 """<P>This is the plot style used for the highlighted source, if any.</P>"""
             )
             self.table.setItem(irow, self.ColApply, item)
         elif group is model.selgroup:
             item = QTableWidgetItem("")
             item.setTextAlignment(Qt.AlignRight | Qt.AlignVCenter)
             item.setToolTip(
                 """<P>This is the plot style used for the currently selected sources.</P>"""
             )
             self.table.setItem(irow, self.ColApply, item)
         # for the rest, a combobox with custom priorities
         else:
             cb = QComboBox()
             cb.addItems(["default"] +
                         ["custom %d" % p for p in range(1, 10)])
             index = max(0, min(group.style.apply, 9))
             #        dprint(0,group.name,"apply",index)
             cb.setCurrentIndex(index)
             cb.activated[int].connect(
                 self._currier.xcurry(self._valueChanged,
                                      (irow, self.ColApply)))
             self.table.setCellWidget(irow, self.ColApply, cb)
             cb.setToolTip(
                 """<P>This controls whether sources within this group are plotted with a customized
         plot style. Customized styles have numeric priority; if a source belongs to multiple groups, then
         the style with the lowest priority takes precedence.<P>""")
         # attribute comboboxes
         for icol, attr in self.AttrByCol.items():
             # get list of options for this style attribute. If dealing with first grouping (i==0), which is
             # the "all sources" grouping, then remove the "default" option (which is always first in the list)
             options = PlotStyles.StyleAttributeOptions[attr]
             if irow == 0:
                 options = options[1:]
             # make combobox
             cb = QComboBox()
             cb.addItems(list(map(str, options)))
             # the "label" option is also editable
             if attr == "label":
                 cb.setEditable(True)
             try:
                 index = options.index(getattr(group.style, attr))
                 cb.setCurrentIndex(index)
             except ValueError:
                 cb.setEditText(str(getattr(group.style, attr)))
             slot = self._currier.xcurry(self._valueChanged, (irow, icol))
             cb.activated[int].connect(slot)
             cb.editTextChanged['QString'].connect(slot)
             cb.setEnabled(group is model.defgroup or group.style.apply)
             self.table.setCellWidget(irow, icol, cb)
             label = attr
             if irow:
                 cb.setToolTip(
                     """<P>This is the %s used to plot sources in this group, when a "custom" style for the group
       is enabled via the style control.<P>""" % label)
             else:
                 cb.setToolTip(
                     "<P>This is the default %s used for all sources for which a custom style is not specified below.<P>"
                     % label)
     self.table.resizeColumnsToContents()
     # re-enable processing of cellChanged() signals
     self._setting_model = False
Beispiel #3
0
class ConversionDialog(Dialog):
    def __init__(self, parent, force_entire_book=False):
        self.prefs = self.prefsPrep()
        self.parent = parent
        self.force_entire_book = force_entire_book
        self.criteria = None
        Dialog.__init__(self, _('Chinese Conversion'),
                        'chinese_conversion_dialog', parent)

    def setup_ui(self):
        self.quote_for_trad_target = _("Update quotes: "",'' -> 「」,『』")
        self.quote_for_simp_target = _("Update quotes: 「」,『』 -> "",''")

        # Create layout for entire dialog
        layout = QVBoxLayout(self)
        self.setLayout(layout)

        #Create a scroll area for the top part of the dialog
        self.scrollArea = QScrollArea(self)
        self.scrollArea.setWidgetResizable(True)

        # Create widget for all the contents of the dialog except the OK and Cancel buttons
        self.scrollContentWidget = QWidget(self.scrollArea)
        self.scrollArea.setWidget(self.scrollContentWidget)
        widgetLayout = QVBoxLayout(self.scrollContentWidget)

        # Add scrollArea to dialog
        layout.addWidget(self.scrollArea)

        self.operation_group_box = QGroupBox(_('Conversion Direction'))
        widgetLayout.addWidget(self.operation_group_box)
        operation_group_box_layout = QVBoxLayout()
        self.operation_group_box.setLayout(operation_group_box_layout)

        operation_group = QButtonGroup(self)
        self.no_conversion_button = QRadioButton(_('No Conversion'))
        operation_group.addButton(self.no_conversion_button)
        self.trad_to_simp_button = QRadioButton(_('Traditional to Simplified'))
        operation_group.addButton(self.trad_to_simp_button)
        self.simp_to_trad_button = QRadioButton(_('Simplified to Traditional'))
        operation_group.addButton(self.simp_to_trad_button)
        self.trad_to_trad_button = QRadioButton(
            _('Traditional to Traditional'))
        operation_group.addButton(self.trad_to_trad_button)
        operation_group_box_layout.addWidget(self.no_conversion_button)
        operation_group_box_layout.addWidget(self.trad_to_simp_button)
        operation_group_box_layout.addWidget(self.simp_to_trad_button)
        operation_group_box_layout.addWidget(self.trad_to_trad_button)
        self.no_conversion_button.toggled.connect(self.update_gui)
        self.trad_to_simp_button.toggled.connect(self.update_gui)
        self.simp_to_trad_button.toggled.connect(self.update_gui)
        self.trad_to_trad_button.toggled.connect(self.update_gui)

        self.style_group_box = QGroupBox(_('Language Styles'))
        widgetLayout.addWidget(self.style_group_box)
        style_group_box_layout = QVBoxLayout()
        self.style_group_box.setLayout(style_group_box_layout)

        input_layout = QHBoxLayout()
        style_group_box_layout.addLayout(input_layout)
        self.input_region_label = QLabel(_('Input:'))
        input_layout.addWidget(self.input_region_label)
        self.input_combo = QComboBox()
        input_layout.addWidget(self.input_combo)
        self.input_combo.addItems([_('Mainland'), _('Hong Kong'), _('Taiwan')])
        self.input_combo.setToolTip(_('Select the origin region of the input'))
        self.input_combo.currentIndexChanged.connect(self.update_gui)

        output_layout = QHBoxLayout()
        style_group_box_layout.addLayout(output_layout)
        self.output_region_label = QLabel(_('Output:'))
        output_layout.addWidget(self.output_region_label)
        self.output_combo = QComboBox()
        output_layout.addWidget(self.output_combo)
        self.output_combo.addItems(
            [_('Mainland'), _('Hong Kong'),
             _('Taiwan')])
        self.output_combo.setToolTip(
            _('Select the desired region of the output'))
        self.output_combo.currentIndexChanged.connect(self.update_gui)

        self.use_target_phrases = QCheckBox(
            _('Use output target phrases if possible'))
        self.use_target_phrases.setToolTip(
            _('Check to allow region specific word replacements if available'))
        style_group_box_layout.addWidget(self.use_target_phrases)
        self.use_target_phrases.stateChanged.connect(self.update_gui)

        self.quotation_group_box = QGroupBox(_('Quotation Marks'))
        widgetLayout.addWidget(self.quotation_group_box)
        quotation_group_box_layout = QVBoxLayout()
        self.quotation_group_box.setLayout(quotation_group_box_layout)

        quotation_group = QButtonGroup(self)
        self.quotation_no_conversion_button = QRadioButton(_('No Conversion'))
        quotation_group.addButton(self.quotation_no_conversion_button)
        self.quotation_trad_to_simp_button = QRadioButton(
            self.quote_for_simp_target)
        quotation_group.addButton(self.quotation_trad_to_simp_button)
        self.quotation_simp_to_trad_button = QRadioButton(
            self.quote_for_trad_target)
        quotation_group.addButton(self.quotation_simp_to_trad_button)
        quotation_group_box_layout.addWidget(
            self.quotation_no_conversion_button)
        quotation_group_box_layout.addWidget(
            self.quotation_simp_to_trad_button)
        quotation_group_box_layout.addWidget(
            self.quotation_trad_to_simp_button)
        self.quotation_no_conversion_button.toggled.connect(self.update_gui)
        self.quotation_trad_to_simp_button.toggled.connect(self.update_gui)
        self.quotation_simp_to_trad_button.toggled.connect(self.update_gui)
        self.use_smart_quotes = QCheckBox(
            """Use curved 'Smart" quotes if applicable""")
        self.use_smart_quotes.setToolTip(
            _('Use smart curved half-width quotes rather than straight full-width quotes'
              ))
        quotation_group_box_layout.addWidget(self.use_smart_quotes)
        self.use_smart_quotes.stateChanged.connect(self.update_gui)

        self.other_group_box = QGroupBox(_('Other Changes'))
        widgetLayout.addWidget(self.other_group_box)
        other_group_box_layout = QVBoxLayout()
        self.other_group_box.setLayout(other_group_box_layout)

        text_dir_layout = QHBoxLayout()
        other_group_box_layout.addLayout(text_dir_layout)
        direction_label = QLabel(_('Text Direction:'))
        text_dir_layout.addWidget(direction_label)
        self.text_dir_combo = QComboBox()
        text_dir_layout.addWidget(self.text_dir_combo)
        self.text_dir_combo.addItems(
            [_('No Conversion'),
             _('Horizontal'),
             _('Vertical')])
        self.text_dir_combo.setToolTip(
            _('Select the desired text orientation'))
        self.text_dir_combo.currentIndexChanged.connect(self.update_gui)

        self.optimization_group_box = QGroupBox(
            _('Reader Device Optimization'))
        other_group_box_layout.addWidget(self.optimization_group_box)
        optimization_group_box_layout = QVBoxLayout()
        self.optimization_group_box.setLayout(optimization_group_box_layout)

        punc_group = QButtonGroup(self)
        self.text_dir_punc_none_button = QRadioButton(
            """No presentation optimization""")
        optimization_group_box_layout.addWidget(self.text_dir_punc_none_button)
        self.text_dir_punc_button = QRadioButton(
            """Optimize presentation for Readium reader""")
        self.text_dir_punc_button.setToolTip(
            _('Use vert/horiz punctuation presentation forms for Chrome Readium Epub3 reader'
              ))
        optimization_group_box_layout.addWidget(self.text_dir_punc_button)
        self.text_dir_punc_kindle_button = QRadioButton(
            """Optimize presentation for Kindle reader""")
        self.text_dir_punc_kindle_button.setToolTip(
            _('Use vert/horiz puncuation presentation forms for Kindle reader')
        )
        optimization_group_box_layout.addWidget(
            self.text_dir_punc_kindle_button)
        self.text_dir_punc_none_button.toggled.connect(self.update_gui)
        self.text_dir_punc_button.toggled.connect(self.update_gui)
        self.text_dir_punc_kindle_button.toggled.connect(self.update_gui)

        source_group = QButtonGroup(self)
        self.file_source_button = QRadioButton(_('Selected File Only'))
        self.book_source_button = QRadioButton(_('Entire eBook'))
        source_group.addButton(self.file_source_button)
        source_group.addButton(self.book_source_button)
        self.source_group_box = QGroupBox(_('Source'))
        if not self.force_entire_book:
            widgetLayout.addWidget(self.source_group_box)
            source_group_box_layout = QVBoxLayout()
            self.source_group_box.setLayout(source_group_box_layout)
            source_group_box_layout.addWidget(self.file_source_button)
            source_group_box_layout.addWidget(self.book_source_button)

        layout.addSpacing(10)
        self.button_box = QDialogButtonBox(QDialogButtonBox.Ok
                                           | QDialogButtonBox.Cancel)

        self.button_box.accepted.connect(self._ok_clicked)
        self.button_box.rejected.connect(self.reject)
        layout.addWidget(self.button_box)

        self.input_combo.setCurrentIndex(self.prefs['input_format'])
        self.output_combo.setCurrentIndex(self.prefs['output_format'])
        self.no_conversion_button.setChecked(self.prefs['no_conversion'])
        self.trad_to_simp_button.setChecked(self.prefs['trad_to_simp'])
        self.simp_to_trad_button.setChecked(self.prefs['simp_to_trad'])
        self.trad_to_trad_button.setChecked(self.prefs['trad_to_trad'])
        if not self.force_entire_book:
            self.file_source_button.setChecked(self.prefs['use_html_file'])
            self.book_source_button.setChecked(self.prefs['use_entire_book'])
        else:
            self.file_source_button.setChecked(False)
            self.book_source_button.setChecked(True)

        self.quotation_no_conversion_button.setChecked(
            self.prefs['quote_no_conversion'])
        self.quotation_trad_to_simp_button.setChecked(
            self.prefs['quote_trad_to_simp'])
        self.quotation_simp_to_trad_button.setChecked(
            self.prefs['quote_simp_to_trad'])

        self.use_smart_quotes.setChecked(self.prefs['use_smart_quotes'])
        self.text_dir_combo.setCurrentIndex(self.prefs['orientation'])
        self.text_dir_punc_none_button.setChecked(
            self.prefs['no_optimization'])
        self.text_dir_punc_button.setChecked(
            self.prefs['readium_optimization'])
        self.text_dir_punc_kindle_button.setChecked(
            self.prefs['kindle_optimization'])
        self.update_gui()

    def update_gui(self):
        if (self.quotation_trad_to_simp_button.isChecked()):
            self.use_smart_quotes.setEnabled(True)
        else:
            self.use_smart_quotes.setEnabled(False)

        if self.text_dir_combo.currentIndex() == 0:
            self.optimization_group_box.setEnabled(False)
            self.text_dir_punc_none_button.setEnabled(False)
            self.text_dir_punc_button.setEnabled(False)
            self.text_dir_punc_kindle_button.setEnabled(False)
        else:
            self.optimization_group_box.setEnabled(True)
            self.text_dir_punc_none_button.setEnabled(True)
            self.text_dir_punc_button.setEnabled(True)
            self.text_dir_punc_kindle_button.setEnabled(True)

        if self.no_conversion_button.isChecked():
            self.input_combo.setEnabled(False)
            self.output_combo.setEnabled(False)
            self.use_target_phrases.setEnabled(False)
            self.output_region_label.setEnabled(False)
            self.input_region_label.setEnabled(False)
            self.style_group_box.setEnabled(False)

        elif self.trad_to_simp_button.isChecked():
            self.input_combo.setEnabled(True)
            #only mainland output locale for simplified output
            self.output_combo.setCurrentIndex(0)
            self.output_combo.setEnabled(False)
            self.use_target_phrases.setEnabled(True)
            self.output_region_label.setEnabled(False)
            self.input_region_label.setEnabled(True)
            self.style_group_box.setEnabled(True)

        elif self.simp_to_trad_button.isChecked():
            #only mainland input locale for simplified input
            self.input_combo.setCurrentIndex(0)
            self.input_combo.setEnabled(False)
            self.output_combo.setEnabled(True)
            self.use_target_phrases.setEnabled(True)
            self.output_region_label.setEnabled(True)
            self.input_region_label.setEnabled(False)
            self.style_group_box.setEnabled(True)

        elif self.trad_to_trad_button.isChecked():
            #Trad->Trad
            #currently only mainland input locale for Trad->Trad
            self.input_combo.setCurrentIndex(0)
            self.input_combo.setEnabled(False)
            self.output_combo.setEnabled(True)
            self.use_target_phrases.setEnabled(True)
            self.output_region_label.setEnabled(True)
            self.input_region_label.setEnabled(False)
            self.style_group_box.setEnabled(True)

        else:
            self.input_combo.setEnabled(True)
            self.output_combo.setEnabled(True)
            self.use_target_phrases.setEnabled(True)
            self.style_group_box.setEnabled(True)
            self.output_region_label.setEnabled(True)
            self.input_region_label.setEnabled(True)

    def _ok_clicked(self):
        output_mode = 0
        if self.trad_to_simp_button.isChecked():
            output_mode = 1  #trad -> simp
        if self.simp_to_trad_button.isChecked():
            output_mode = 2  #simp -> trad
        elif self.trad_to_trad_button.isChecked():
            output_mode = 3  #trad -> trad

        quote_mode = 0
        if self.quotation_trad_to_simp_button.isChecked():
            quote_mode = 1  #trad -> simp
        if self.quotation_simp_to_trad_button.isChecked():
            quote_mode = 2  #simp -> trad

        optimization_mode = 0
        if self.text_dir_punc_button.isChecked():
            optimization_mode = 1  #Readium
        if self.text_dir_punc_kindle_button.isChecked():
            optimization_mode = 2  #Kindle

        self.criteria = (self.file_source_button.isChecked(), output_mode,
                         self.input_combo.currentIndex(),
                         self.output_combo.currentIndex(),
                         self.use_target_phrases.isChecked(), quote_mode,
                         self.use_smart_quotes.isChecked(),
                         self.text_dir_combo.currentIndex(), optimization_mode)
        self.savePrefs()
        self.accept()

    def getCriteria(self):
        return self.criteria

    def prefsPrep(self):
        from calibre.utils.config import JSONConfig
        plugin_prefs = JSONConfig(
            'plugins/{0}_ChineseConversion_settings'.format(PLUGIN_SAFE_NAME))
        plugin_prefs.defaults['input_format'] = 0
        plugin_prefs.defaults['output_format'] = 0
        plugin_prefs.defaults['no_conversion'] = True
        plugin_prefs.defaults['trad_to_simp'] = False
        plugin_prefs.defaults['use_html_file'] = True
        plugin_prefs.defaults['simp_to_trad'] = False
        plugin_prefs.defaults['trad_to_trad'] = False
        plugin_prefs.defaults['use_entire_book'] = True
        plugin_prefs.defaults['use_target_phrases'] = True
        plugin_prefs.defaults['quote_no_conversion'] = True
        plugin_prefs.defaults['quote_trad_to_simp'] = False
        plugin_prefs.defaults['quote_simp_to_trad'] = False
        plugin_prefs.defaults['use_smart_quotes'] = False
        plugin_prefs.defaults['orientation'] = 0
        plugin_prefs.defaults['no_optimization'] = True
        plugin_prefs.defaults['readium_optimization'] = False
        plugin_prefs.defaults['kindle_optimization'] = False
        return plugin_prefs

    def savePrefs(self):
        self.prefs['input_format'] = self.input_combo.currentIndex()
        self.prefs['output_format'] = self.output_combo.currentIndex()
        self.prefs['no_conversion'] = self.no_conversion_button.isChecked()
        self.prefs['trad_to_simp'] = self.trad_to_simp_button.isChecked()
        self.prefs['use_html_file'] = self.file_source_button.isChecked()
        self.prefs['simp_to_trad'] = self.simp_to_trad_button.isChecked()
        self.prefs['trad_to_trad'] = self.trad_to_trad_button.isChecked()
        self.prefs['use_entire_book'] = self.book_source_button.isChecked()
        self.prefs['use_target_phrases'] = self.use_target_phrases.isChecked()
        self.prefs[
            'quote_no_conversion'] = self.quotation_no_conversion_button.isChecked(
            )
        self.prefs[
            'quote_trad_to_simp'] = self.quotation_trad_to_simp_button.isChecked(
            )
        self.prefs[
            'quote_simp_to_trad'] = self.quotation_simp_to_trad_button.isChecked(
            )
        self.prefs['use_smart_quotes'] = self.use_smart_quotes.isChecked()
        self.prefs['orientation'] = self.text_dir_combo.currentIndex()
        self.prefs[
            'no_optimization'] = self.text_dir_punc_none_button.isChecked()
        self.prefs[
            'readium_optimization'] = self.text_dir_punc_button.isChecked()
        self.prefs[
            'kindle_optimization'] = self.text_dir_punc_kindle_button.isChecked(
            )
Beispiel #4
0
class ImageDisplay(QWidget):

    video_infos     = ['vidéo : {}','nb frames : {}','taille : {}','FPS : {}','durée : {:.2f} sec']
    video_keys      = ['videoname','nframes','size','fps','duration']
    algo_traj       = ['barycentre','minmax']

    def __init__(self, mainWindow):

        # acall the base class constructor:
        super().__init__(mainWindow)

        self.mw = mainWindow

        # Attributs (objets persistants)
        self.img_lbl = QLabel(self)           # to display the current image
        self.img_lbl.installEventFilter(self) # filter to catch evenements
        self.selectTargetRect = None          # display a rectangle to show teh target color selection

        self.rubberBand  = QRubberBand(QRubberBand.Line, self)

        # Boutons pour avancer/reculer
        self.btn_prev  = QPushButton(QIcon("icones/go-prev.png"),  "", self)
        self.btn_next  = QPushButton(QIcon("icones/go-next.png"), "", self)
        self.btn_first = QPushButton(QIcon("icones/go-first.png"),  "", self)
        self.btn_last  = QPushButton(QIcon("icones/go-last.png"), "", self)
        self.btn_traj  = QPushButton(QIcon("icones/extract.png"), "Extraire...", self)
        self.btn_clear = QPushButton(QIcon("icones/clear.png"), "Effacer courbes...", self)
        self.btn_exportCSV = QPushButton(QIcon("icones/exportCSV.png"), "Export CSV", self)
        self.btn_algo      = QComboBox(self)
        self.image_index   = QLabel(self)
        
        # widget QSpinBox
        self.images_step      = QSpinBox(parent=self)
        self.images_firstRank = QSpinBox(parent=self) 
        self.images_lastRank  = QSpinBox(parent=self) 

        # QLabel to display the target color
        self.target_color_label = QLabel("target color",parent=self) 
        self.picked_color       = QLabel(self)
    
        self.video_path     = None  # Chemin de la dernière vidéo
        self.images_dir     = None  # Dossier contenant les images
        self.__img_idx      = None  # Rang de l'image affichée
        self.img_path       = None  # nom du chemin de l'image courante
        self.nb_img         = None  # nombre d'images

        self.video_name     = None  # nom de la video ("aaaaaa.mp4")
        self.video_nframes  = None  # nombre d'images dans la video
        self.video_size     = None  # taille (width, height) des images
        self.video_FPS      = None  # nombre d'images par seconde
        self.video_duration = None  # durée de la video en secondes
        self.videoLabels    = []    # liste de QLabel contenant les infos vidéo
        self.dico_video     = {}    # dictionnaire des méta-données

        self.dico_unit      = {}    # dictionary "pixels", "mm"
        self.scale_pixel    = None  # nombre de pixels pour conversion en mm
        self.scale_mm       = None  # nbre de mm pour scale_pixel
        self.valid_scale    = False # données de l'échelle valides ou pas
        self.pix_to_mm_coeff= 1.    # le coefficient de converion pixels -> mm
        self.dicoScale      = {}    # dictionnaire des QWidget d'info scale

        self.lbl_epsilon    = None  # label epsilon
        self.epsi_spin      = None  # boite de choix de epsilon    

        # créer l'onglet de visualisation image """
        self.__initUI()
        self.scaleInfoVisible(False)
        self.__epsilonVisible(False)

    def __initUI(self):

        # Onglet "Visualisation images"
        vbox = QVBoxLayout()

        # Ligne 1 : extraction trajec
        self.picked_color.setFrameStyle(QFrame.StyledPanel | QFrame.Plain);
        
        line1 = QHBoxLayout()
        line1.addStretch(1)
        line1.addWidget(self.btn_algo)
        line1.addWidget(self.btn_traj)
        line1.addWidget(self.target_color_label)
        line1.addWidget(self.picked_color)
        line1.addWidget(self.btn_clear)
        line1.addWidget(self.btn_exportCSV)
        line1.addStretch(1)

        # Ligne 2 : infos video + visu image
        line2 = QHBoxLayout()

        # boîte d'infos sur la vidéo
        infoVBox = QVBoxLayout()
        for _ in ImageDisplay.video_infos:
            label = QLabel(self)
            label.setFrameStyle(QFrame.StyledPanel | QFrame.Plain);
            infoVBox.addWidget(label)
            self.videoLabels.append(label)
        infoVBox.addStretch()

        widget = QLabel("Conversion pixels -> mm", self)
        self.dicoScale['Pixels-mm'] = widget
        infoVBox.addWidget(widget)

        grid = QGridLayout()
        infoVBox.addLayout(grid)

        widget = QLabel("pixels  ",self)
        self.dicoScale['pixels'] = widget
        grid.addWidget(widget,1,1)

        self.scale_pixel = QLineEdit(self)
        self.dicoScale['pixelsForMM'] = self.scale_pixel
        grid.addWidget(self.scale_pixel,1,2)

        widget = QLabel("millimètres ",self)
        self.dicoScale['millimeters'] = widget
        grid.addWidget(widget,2,1)

        self.scale_mm = QLineEdit(self)
        self.dicoScale['mmForPixels'] = self.scale_mm
        grid.addWidget(self.scale_mm,2,2)

        self.lbl_epsilon = QLabel("Epsilon ",self)
        grid.addWidget(self.lbl_epsilon,5,1)

        self.epsi_spin = QSpinBox(self)
        self.epsi_spin.setRange(1,50)
        self.epsi_spin.setSingleStep(1)
        self.epsi_spin.setValue(10)
        grid.addWidget(self.epsi_spin,5,2)
        
        infoVBox.addStretch()

        line2.addLayout(infoVBox)
        line2.addStretch(1)
        line2.addWidget(self.img_lbl) # le QLabel por afficher l'image
        line2.addStretch(1)

        # line 3 : navigation boutons
        self.image_index.setFrameStyle(QFrame.Panel | QFrame.Sunken)
        self.image_index.setText("       ")
        line3 = QHBoxLayout()
        line3.addStretch(1)
        line3.addWidget(self.btn_first)
        line3.addWidget(self.btn_prev)
        line3.addWidget(self.image_index)
        line3.addWidget(self.btn_next)
        line3.addWidget(self.btn_last)
        line3.addStretch(1)

        # line 4 : first , step, last image selection
        line4 = QHBoxLayout()
        line4.addStretch(1)
        line4.addWidget(self.images_firstRank)
        line4.addWidget(self.images_step)
        line4.addWidget(self.images_lastRank)
        line4.addStretch(1)

        vbox.addLayout(line1)
        vbox.addStretch(1)
        vbox.addLayout(line2)
        vbox.addStretch(1)
        vbox.addLayout(line3)
        vbox.addLayout(line4)

        self.setLayout(vbox)

        self.buttonsState()
        self.__buttonsConnect()
        self.__setVideoLabelVisible(False)

    def __setVideoLabelVisible(self, state):
        for label in self.videoLabels:
            label.setVisible(state)

    def __buttonsConnect(self):            
        self.btn_traj.clicked.connect(self.extract_trajectoire)
        self.btn_clear.clicked.connect(self.mw.clearPlots)
        self.btn_exportCSV.clicked.connect(self.mw.ExportCSV)
        self.btn_prev.clicked.connect(self.prev_image)
        self.btn_next.clicked.connect(self.next_image)
        self.btn_first.clicked.connect(self.first_image)
        self.btn_last.clicked.connect(self.last_image)
        self.images_step.valueChanged.connect(self.__step_changed)
        self.images_firstRank.valueChanged.connect(self.__first_rank_changed)
        self.images_lastRank.valueChanged.connect(self.__last_rank_changed)

    def buttonsState(self, importCSV=False):

        self.btn_traj.setEnabled(False)
        self.picked_color.setText("X")
        self.picked_color.setEnabled(False)
        
        self.btn_traj.setStatusTip('Extrait la trajectoire de la cible'+
            'dont la couleur a été choisie')

        self.target_color_label.setEnabled(False)
        self.picked_color.setStyleSheet('background-color : rgb(255, 255, 255)')
        
        self.btn_clear.setEnabled(False)
        self.btn_clear.setStatusTip('Nettoye tous les tracés des onglets'+
            '<trajectoire> et <X(t), Y(t)>')

        self.btn_exportCSV.setEnabled(False)
        texte = "Export des données dans un fichier CSV"
        self.btn_exportCSV.setStatusTip(texte)

        if not importCSV: self.btn_algo.addItems(ImageDisplay.algo_traj)
        self.btn_algo.setEnabled(False)

        self.btn_prev.setEnabled(False)
        self.btn_prev.setStatusTip("affiche l'image précédente")

        self.btn_next.setEnabled(False)
        self.btn_next.setStatusTip("affiche l'image suivante")

        self.btn_first.setEnabled(False)
        self.btn_first.setStatusTip("affiche la première image à traiter")

        self.btn_last.setEnabled(False)
        self.btn_last.setStatusTip("affiche la dernière image à traiter")

        # SpinBoxes parameters:
        self.images_step.setRange(1,1000)
        self.images_step.setSingleStep(1)
        self.images_step.setValue(1)
        self.images_step.setPrefix("step: ")
        self.images_step.setEnabled(False)
        self.images_step.setStatusTip("Fixe le pas pour passer d'une image à l'autre")
        
        self.images_firstRank.setRange(1,1000)
        self.images_firstRank.setSingleStep(1)
        self.images_firstRank.setValue(1)
        self.images_firstRank.setPrefix("first: ")
        self.images_firstRank.setEnabled(False)
        self.images_firstRank.setStatusTip("Fixe le rang de la première image à traiter")
        
        self.images_lastRank.setRange(1,10000)
        self.images_lastRank.setSingleStep(1)
        self.images_lastRank.setValue(1)
        self.images_lastRank.setPrefix("last: ")
        self.images_lastRank.setEnabled(False)
        self.images_lastRank.setStatusTip("Fixe le rang de la dernière image à traiter")

    def __first_rank_changed(self, val):
        if self.img_idx is None: return
        if self.img_idx < val:
            self.img_idx = val
            self.show_image()
            
    def __last_rank_changed(self, val):
        if self.img_idx is None: return
        if self.img_idx > val:
            self.img_idx = val
            self.show_image()

    def __step_changed(self, val):
        if self.img_idx is None: return

    def setTextInfoVideoGrid(self):
        
        for field, name, key in zip(self.videoLabels,
                                    ImageDisplay.video_infos,
                                    ImageDisplay.video_keys):
            mess = name.format(self.dico_video.get(key,'?'))
            field.setText(mess)
        self.__setVideoLabelVisible(True)            

    def scaleInfoVisible(self, state):
        for widget in self.dicoScale.values():
            widget.setVisible(state)

    def __epsilonVisible(self, state):
        self.lbl_epsilon.setVisible(state)
        self.epsi_spin.setVisible(state)

    def open_video(self):
        '''Lance un sélecteur de fichier pour choisir la vidéo à traiter.'''
        fname = QFileDialog.getOpenFileName(None,
                                            'Choisir une vidéo',
                                            self.mw.cur_dir,
                                            'Fichier vidéo (*.mp4)')
        if fname[0]  != '' :
            # un fichier vidéo a été chosi :
            vp = fname[0]
            if self.video_path == vp :
                name = os.path.basename(vp)
                rep = QMessageBox.question(self,        # widget parent de QMessageBox
                    'Question',                     # texte du bandeau de la fenêtre
                    'Voulez-vous recharger le fichier video {} ?'.format(name),
                    QMessageBox.Yes | QMessageBox.No,   # afficher les boutons Yes et No
                    QMessageBox.No)                     # bouton No sélectionné par défaut
                if rep == QMessageBox.No: return
            # fichier vidéo à traiter => faire le split des images :
            self.video_path = vp
            self.extract_images_from_video()


    def load_images_from_directory(self):
        '''Charge les images '*.png' contenue dans le répertoire
           des images choisi avec un sélecteur graphique.'''

        # Choix du répertoire avec un sélecteur de fichier :
        dname = QFileDialog.getExistingDirectory(None,
                                                 'Choisir un dossier images',
                                                 self.mw.image_dir)
        if dname != '' :
            # un répertoire valide a été choisi :
            self.video_path = None
            self.images_dir = dname + "/"

            try:
                # Lecture du fichier ascii des méta-données
                with open(self.images_dir + "metaData.txt", "r") as F:
                    data = F.read()
                exec('self.dico_video = '+data)
            except:
                rep = QMessageBox.critical(
                    None,             # widget parent de QMessageBox
                    'Erreur',    # bandeau de la fenêtre
                    'Pas de fichier de méta-données dans le répertoire'+\
                    ' <{}>'.format(os.path.basename(dname)),
                    QMessageBox.Ok)
                return



            print("méta données :", self.dico_video)

            self.parse_meta_data()
            self.setTextInfoVideoGrid()

            # Mettre à jour l'application avec les nouvelles images chargées :
            self.update_images()


    def extract_trajectoire(self):
        '''Méthode utilisée pour extraire la trajectoire du centre de la
           cible pour toutes les images de la vidéo.'''

        # Récupérer l'algorithme de calcul du centre de la cible :
        algo = self.btn_algo.currentText()

        # Définition de la liste dans laquelle on va récupérer les coordonnées
        # du centre cible pour toutes les images :
        target_pos = []

        # Création d'un objet ProgressBar qui va lancer le travail
        # d'extraction de la cible dans les images tout en affichant une
        # barre d'avancement :
        
        first = self.images_firstRank.value()
        last  = self.images_lastRank.value()
        step  = self.images_step.value()
        
        last = last - (last - first) % step
        first_last_step = (first, last, step)
        pg = ProgressBar(self.images_dir, self)
        pg.configure_for_target_extraction(self.mw.target_RGB,
                                           algo,
                                           self.epsi_spin.value(),
                                           target_pos,
                                           first_last_step)
        ret = pg.exec_() # lance la barre et le travail d'extraction...
        print("retour de pg.exec_() :",ret)

        if ret != 0:
            self.mw.target_pos = None
            return

        target_pos = np.array(target_pos)
        width, height = self.video_size
        # l'axe verticale est retourné et decalé:
        target_pos[1] = height - target_pos[1]
        self.scale_XY()

        self.mw.target_pos = target_pos
        self.display_plots()
        
        # remettre le bouton extraire_trajectoire disabled:
        self.btn_exportCSV.setEnabled(True)

    def display_plots(self):
        self.mw.clearPlots()
        
        # Plot trajectory (X(t), Y(t)) :
        self.mw.onePlot.setEnabled(True)
        self.mw.onePlot.Plot()

        # Plot curves X(t) and Y(t)
        self.mw.twoPlots_xy.setEnabled(True)
        self.mw.tabs.setCurrentWidget(self.mw.twoPlots_xy)
        self.mw.twoPlots_xy.Plot()

        # Plot curves VX(t) and VY(t)
        self.mw.twoPlots_VxVy.setEnabled(True)
        self.mw.tabs.setCurrentWidget(self.mw.twoPlots_xy)
        self.mw.twoPlots_VxVy.Plot()


    def extract_images_from_video(self) :
        # name of the video file without path and suffix:
        videoname = os.path.basename(self.video_path)[:-4]

        # directory where to put extracted iamges:
        self.images_dir = self.mw.image_dir + videoname + "/"

        if os.path.isdir(self.images_dir) :
            print("Effacement de tous les fichiers de '{}'"\
                  .format(self.images_dir))
            for fn in os.listdir(self.images_dir) :
                os.remove(self.images_dir+fn)
        else :
            os.mkdir(self.images_dir)

        video = cv2.VideoCapture(self.video_path)
        
        self.dico_video['nframes']   = int(video.get(cv2.CAP_PROP_FRAME_COUNT))
        self.dico_video['size']      = (int(video.get(cv2.CAP_PROP_FRAME_WIDTH)),
                                        int(video.get(cv2.CAP_PROP_FRAME_HEIGHT)))    
        self.dico_video['fps']       = int(video.get(cv2.CAP_PROP_FPS))
        self.dico_video['duration']  = video.get(cv2.CAP_PROP_FRAME_COUNT)/video.get(cv2.CAP_PROP_FPS)
        self.dico_video['videoname'] = os.path.basename(self.video_path)
                                            
        self.parse_meta_data()
        self.dico_video["videoname"] = videoname+".mp4"
        self.setTextInfoVideoGrid()

        # Création d'un objet ProgressBar qui va lancer le travail
        # d'extraction des images tout en affichant une barre d'avancement :
        pg = ProgressBar(self.images_dir, self)
        pg.configure_for_video_extraction(video, self.mw.image_fmt)
        ret = pg.exec_()
        print("retour de pg.exec_() :", ret)
        if ret != 0: return

        # MAJ de la liste des fichiers images :
        self.update_images()

        # écriture des méta-data dans le fichier 'nom_video'.info
        with open(self.mw.image_dir+videoname+"/metaData.txt", "w") as F:
            F.write(str(self.dico_video))

    def computeTargetColor(self, draw_selection=False):
        col_min,row_min,col_max,row_max = self.selection.getCoords()
        print("Pixels selectionnés : lignes [{},{}] colonnes [{},{}]".\
              format(row_min, row_max, col_min, col_max))

        tab = imread(self.img_path)
        self.target_pix = tab[row_min:row_max+1, col_min:col_max+1, :]
        R = round(self.target_pix[:,:,0].mean())
        G = round(self.target_pix[:,:,1].mean())
        B = round(self.target_pix[:,:,2].mean())
        self.mw.target_RGB = np.array([R, G, B], dtype=int)
        print("RGB sélection dans <{}> :".format(os.path.basename(self.img_path)),
              self.mw.target_RGB)

        draw_selection = self.mw.flags["drawTargetSelection"]
        if draw_selection:
            self.show_image()
            print("drawTargetSelection")
            #if self.selectTargetRect is not None : del self.selectTargetRect
            # create painter instance with pixmap
            self.selectTargetRect = QPainter(self.img_lbl.pixmap())

            # set rectangle color and thickness
            self.penRectangle = QPen(QColor(0,0,0))
            self.penRectangle.setWidth(2)

            # draw rectangle on painter
            self.selectTargetRect.begin(self)
            self.selectTargetRect.setPen(self.penRectangle)
            self.selectTargetRect.drawRect(col_min,row_min,
                                          col_max-col_min,row_max-row_min)
            self.selectTargetRect.setOpacity(0.1)
            self.selectTargetRect.end()
            #self.show_image()

        self.btn_traj.setEnabled(True)
        self.btn_algo.setEnabled(True)
        self.btn_clear.setEnabled(True)
        self.target_color_label.setEnabled(True)
        self.picked_color.setStyleSheet('background-color : rgb({},{},{})'.format(R, G, B))

    @property
    def img_idx(self): return self.__img_idx

    @img_idx.setter
    def img_idx(self, index):
        self.__img_idx = index
        self.image_index.setText(str(index))
                                 
    def update_images(self) :
        '''Méthode à exécuter quand de nouvelles images sont apparues
           après une extraction d'images depuis une vidéo par exemple.
           Cette méthode :
           - met à jour des attributs qui dépendant de la liste des images,
           - met à jour l'état de certains boutons
           - fait afficher la première image et un message d'information.'''

        if self.images_dir is None :
            self.__img_idx = None
            #self.btn_prev.setEnabled(False)
            self.btn_prev.setStatusTip("")
            #self.btn_next.setEnabled(False)
            self.btn_next.setStatusTip("")
            self.images_step.setEnabled(False)
            self.images_firstRank.setEnabled(False)
            self.images_lastRank.setEnabled(False)
            
        else :
            self.buttonsState()
            self.mw.clearPlots()
            self.mw.twoPlots_VxVy.reset()
            
            # liste des noms des fichiers image pour avoir leur nombre :
            file_names = [ f for f in os.listdir(self.images_dir) \
                           if f.endswith('.png')]
            file_names.sort()
            self.nb_img = len(file_names)

              # Update spinBox:
            self.images_step.setEnabled(True)
            self.images_firstRank.setEnabled(True)
            self.images_lastRank.setEnabled(True)

            self.images_firstRank.setValue(1)
            self.images_step.setValue(1)
            self.images_lastRank.setValue(self.nb_img)

            self.images_firstRank.setMaximum(self.nb_img)
            self.images_lastRank.setMaximum(self.nb_img)
            self.images_step.setMaximum(self.nb_img)

            # MAJ des boutons prev et next
            self.img_idx = self.images_firstRank.value()
            self.btn_prev.setEnabled(True)
            self.btn_first.setEnabled(True)

            self.btn_prev.setStatusTip("charge l'image précédente")

            self.btn_next.setEnabled(True)
            self.btn_last.setEnabled(True)
            self.btn_next.setStatusTip("afficher "+self.mw.image_fmt.format(\
                self.img_idx+self.images_step.value()))
          
            self.show_image()
            self.scaleInfoVisible(True)
            self.__epsilonVisible(True)
            self.mw.tabs.setCurrentWidget(self)

            self.scale_mm.clear()
            self.scale_mm.setText("???")
            self.scale_pixel.clear()
            try:
                text = str(self.video_size[1])
            except:
                text = ""
            self.scale_pixel.setText(text)

            self.mw.twoPlots_VxVy.reset()
            

            if self.mw.flags["displayInfo"]:
                rep = QMessageBox.information(
                    None,             # widget parent de QMessageBox
                    'Information',    # bandeau de la fenêtre
                    'Vous pouvez maintenant sélectionner une couleur de cible'+\
                    'avec la souris...',
                    QMessageBox.Ok)
                

    def show_image(self):
        '''Affiche l'image dont le numéro est donné par l'attribut 'img_idx'.'''
        if self.img_idx is None :
            self.img_path = ''
        else :
            self.img_path = self.images_dir+self.mw.image_fmt.format(self.img_idx)
        pixmap = QPixmap(self.img_path)
        self.img_lbl.setPixmap(pixmap)
        self.img_lbl.setStatusTip(os.path.basename(self.img_path))

    def first_image(self) :
        if self.img_idx == None : return
        self.img_idx = self.images_firstRank.value()
        self.mw.statusBar().showMessage("")
        self.show_image()

    def prev_image(self) :
        if self.img_idx == None : return
        if self.img_idx >= self.images_firstRank.value() + self.images_step.value():
            self.img_idx -= self.images_step.value()
        self.mw.statusBar().showMessage("")
        self.show_image()

    def last_image(self) :
        if self.img_idx == None : return
        self.img_idx = self.images_lastRank.value() # rank of last image to process
        self.mw.statusBar().showMessage("")
        self.show_image()

    def next_image(self) :
        if self.img_idx == None : return
        if self.img_idx <= self.images_lastRank.value()-self.images_step.value():
            self.img_idx += self.images_step.value()
        self.mw.statusBar().showMessage("")
        self.show_image()

    def parse_meta_data(self):
        self.video_nframes  = self.dico_video.get('nframes', None)
        self.video_size     = self.dico_video.get('size', None)
        self.video_FPS      = self.dico_video.get('fps', None)
        self.video_duration = self.dico_video.get('duration', None)
        self.video_name     = self.dico_video.get('videoname',"none.mp4")

        if self.mw.flags["debug"]:
            info= " nb images    : {},\n taille image : {},\n FPS : {} image/sec,\n durée : {.2f} sec."
            info = info.format(self.video_nframes,
                               self.video_size,
                               self.video_FPS,
                               self.video_duration)
            QMessageBox.about(None,     # widget parent de QMessageBox
                              'Informations video {}'.format(self.video_name),
                              info)


    def eventFilter(self, object, event):
        if object == self.img_lbl :
            if event.type() == QEvent.MouseButtonPress:
                self.mousePressInLabel(event)
                return True
            elif event.type() == QEvent.MouseButtonRelease:
                self.mouseReleaseInLabel(event)
                return True
            elif event.type() == QEvent.MouseMove:
                self.mouseMoveInLabel(event)
                return True
        return False

    def mousePressInLabel(self, event):
        if event.button() == Qt.LeftButton:
            self.pt1 = event.pos()
            self.pt1_rect = self.img_lbl.mapTo(self, self.pt1)
            print("\nCoord. pt1 image :",self.pt1)
            self.rubberBand.setGeometry(QRect(self.pt1_rect, QSize()))
            self.rubberBand.show()
            self.mw.statusBar().showMessage('sélection en cours....')

    def mouseMoveInLabel(self, event):
        if not self.pt1.isNull():
            pt = self.img_lbl.mapTo(self,event.pos())
            self.rubberBand.setGeometry(QRect(self.pt1_rect, pt).normalized())

    def mouseReleaseInLabel(self, event):
        if event.button() == Qt.LeftButton:
            self.pt2 = event.pos()
            print("Coord. pt2 image :", self.pt2)
            self.rubberBand.hide()
            self.selection = QRect(self.pt1, self.pt2).normalized()
            print(self.selection)
            self.computeTargetColor()

    def scale_XY(self):

        self.valid_scale = False
        self.pix_to_mm_coeff = 1.
        
        try :
            pixels = float(self.scale_pixel.text())
            mm     = float(self.scale_mm.text())
        except :
            if self.mw.flags["displayInfo"]:
                info = 'Les données de conversion Pixels -> mm n\'ont pas été '
                info += 'complétées.. les ordonnées des tracés seront en pixels.'
                rep = QMessageBox.information(None,  # parent de QMessageBox
                        'Info',               # bandeau de la fenêtre
                        info, QMessageBox.Ok)
            return
        self.valid_scale = True
        self.pix_to_mm_coeff = mm/pixels
        print("valid scale : ", self.pix_to_mm_coeff)
Beispiel #5
0
class GUI(QtWidgets.QMainWindow):
    def __init__(self):
        '''Asetetaan muuttujille alkuarvoja ohjelman suorittamiseksi'''
        super().__init__()
        self.title = "Lujuusanalysaattori"
        self.left = 200
        self.top = 200
        self.width = 1300
        self.height = 700
        self.palkin_default_pituus = 5
        self.square_size = 10
        self.ikkuna()
        self.button_height = 75
        self.button_width = 150
        self.button_separation = 25
        self.x = 0
        self.y = 0
        self.palkin_leveys = 700
        self.palkin_korkeus = 75
        self.palkin_keskipiste = 650
        self.palkin_paatypiste = 1000
        self.yksikko_arvo = 0
        self.voima = 20
        self.maks_jannitys = "-"
        self.asteikko_teksti = QGraphicsSimpleTextItem()
        '''Lisää QGraphicsScenen ruudukon piirtämistä varten'''
        self.scene = QtWidgets.QGraphicsScene()
        self.scene.setSceneRect(0, -20, self.width - 200, self.height - 100)
        '''Suoritetaan lukuisia metodeja, jolla ohjelma "alustetaan"'''
        self.aloita_simulaatio()
        self.simulaatioikkuna()
        self.simulaatio_nappi()
        self.materiaali_valikko()
        self.uusi_palkki_nappi()
        self.lisaa_tuki_nappi()
        self.lisaa_ulkoinen_voima_nappi()
        self.poista_ulkoinen_voima_nappi()
        self.vaihda_tuki_nappi()

        Ominaisuudet.alkuarvot(self)
        self.lisaa_palkki()
        self.palkin_pituus_valikko()
        self.yksikko_pituus()
        self.asteikko()
        self.lisaa_asteikko_arvo()
        self.asteikko_teksti.hide()
        self.tulos_teksti()
        self.lisaa_seina_tuki()
        self.lisaa_tuki_alhaalta()
        self.ulkoinen_voima_valikko()
        self.ulkoinen_voima_nuoli_alatuki()
        self.ulkoinen_voima_nuoli_seinatuki()
        Ominaisuudet.alkuarvot(self)
        '''Asetetaan tietyille napeille tietty näkyvyys'''
        self.lisaa_tuki.setEnabled(False)
        self.simuloi.setEnabled(False)
        self.show()

    def ikkuna(self):
        '''Tekee ohjelman pääikkunan'''
        self.setGeometry(self.left, self.top, self.width, self.height)
        self.setWindowTitle('Lujuusanalysaattori')
        self.horizontal = QtWidgets.QHBoxLayout()
        '''Luo menubarin'''
        self.uusiAction = QAction("Uusi simulaatio", self)
        self.uusiAction.setStatusTip("Luo uusi rakenne")
        self.uusiAction.triggered.connect(self.uusi_rakenne)
        self.uusiAction.setEnabled(True)
        self.uusiAction.setShortcut("Ctrl+N")

        self.tallennaAction = QAction("Tallenna simulaatio", self)
        self.tallennaAction.setStatusTip("Tallenna simulaatio")
        self.tallennaAction.triggered.connect(self.tallenna_rakenne)
        self.tallennaAction.setEnabled(False)
        self.tallennaAction.setShortcut("Ctrl+S")

        self.avaaAction = QAction("Lataa simulaatio", self)
        self.avaaAction.setStatusTip("Lataa simulaatio tiedostosta")
        self.avaaAction.triggered.connect(self.lataa_tallennettu_rakenne)
        self.avaaAction.setShortcut("Ctrl+O")

        self.exitAction = QAction("Exit", self)
        self.exitAction.setToolTip("Lopeta ohjelma")
        self.exitAction.triggered.connect(self.close_application)
        self.exitAction.setShortcut("Ctrl+E")
        self.statusBar()

        mainMenu = self.menuBar()
        fileMenu = mainMenu.addMenu('&File')
        aboutMenu = mainMenu.addMenu('&About')
        fileMenu.addAction(self.uusiAction)
        fileMenu.addAction(self.avaaAction)
        fileMenu.addAction(self.tallennaAction)
        fileMenu.addAction(self.exitAction)

    def tallenna_rakenne(self):
        '''Hoitaa rakenteen tallentamisen'''
        tallennus = Tallennin.tallenin(self)
        if tallennus == True:
            '''Kerrotaan käyttäjälle, että tallennus onnistui'''
            msgBox = QMessageBox()
            msgBox.setText("Tallennus onnistui!")
            msgBox.setWindowTitle("Onnistunut Tallennus")
            msgBox.setMinimumWidth(50)
            msgBox.addButton(QPushButton('OK'), QMessageBox.NoRole)
            msgBox.exec_()

    def lataa_tallennettu_rakenne(self):
        '''Metodi avaa QFileDialog ikkunan, josta käyttäjä valitsee tiedoston, jossa aiemmin tallennettu rakenne sijaitsee. Vain .txt -tiedostot 
        ovat ladattavissa '''
        options = QFileDialog.Options()
        options |= QFileDialog.DontUseNativeDialog
        tiedosto, _ = QFileDialog.getOpenFileName(self,
                                                  "Valitse tiedosto",
                                                  "",
                                                  "txt Files (*.txt)",
                                                  options=options)
        lataus = Lataaja.lataaja(self, tiedosto)
        if lataus == False:
            return

        if lataus == True:
            self.uusi_rakenne()
            Lataaja.lataaja(self, tiedosto)
            tuen_tyyppi = Ominaisuudet.palauta_tuen_tyyppi(self)
            '''Jos tuki on seinästä, piirretään sitä vastaava grafiikka'''
            if tuen_tyyppi == 0:
                self.nayta_seina_tuki()
                self.gradient_seina_tuki()
            '''Jos tuki on alhaalta, piirretään sitä vastaava grafiikka'''
            if tuen_tyyppi == 1:
                self.nayta_tuki_alhaalta()
                self.gradient_alatuki()

            if tuen_tyyppi != 2:
                self.vaihda_tuki.show()
                self.lisaa_tuki.hide()
            '''Jos ulkoinen voima on asetettu, piirretään se'''
            ulkoinen_voima = int(
                Ominaisuudet.onko_ulkoinen_voima_asetettu(self))
            if ulkoinen_voima == 1:
                self.nayta_ulkoinen_voima()

            self.nayta_palkki()
            Laskin.laskin(self)
            self.paivita_tulos_teksti()
            self.tulos.show()
            self.sp.setValue(float(Ominaisuudet.palauta_palkin_pituus(self)))
            self.uusiAction.setEnabled(True)
            self.simuloi.setEnabled(True)
            '''Kerrotaan käyttäjälle, että kaikki onnistui'''
            msgBox = QMessageBox()
            msgBox.setText("Lataus onnistui!")
            msgBox.setWindowTitle("Onnistunut lataus")
            msgBox.addButton(QPushButton('OK'), QMessageBox.NoRole)
            msgBox.exec_()

    def aloita_simulaatio(self):
        '''Aloittaa simulaation'''
        self.setCentralWidget(QtWidgets.QWidget())
        self.horizontal = QtWidgets.QHBoxLayout()
        self.centralWidget().setLayout(self.horizontal)

    def simulaatioikkuna(self):
        '''lisää view näyttämistä varten'''
        self.view = QtWidgets.QGraphicsView(self.scene, self)
        self.view.adjustSize()
        self.view.show()
        self.horizontal.addWidget(self.view)

    def uusi_palkki_nappi(self):
        '''Luo Uusi palkki -napin'''
        self.uusi_palkki = QPushButton('Uusi palkki')
        self.uusi_palkki.setToolTip("Lisää uusi palkki")
        self.uusi_palkki.move(0, 0)
        self.uusi_palkki.resize(self.button_width, self.button_height)
        self.uusi_palkki.font = QtGui.QFont()
        self.uusi_palkki.font.setPointSize(12)
        self.uusi_palkki.setFont(self.uusi_palkki.font)
        self.uusi_palkki.setEnabled(True)
        self.scene.addWidget(self.uusi_palkki)
        self.uusi_palkki.clicked.connect(self.nayta_palkki)

    def nayta_palkki(self):
        '''Näyttää kaikki palkkiin liittyvät komponentit sekä asettaa uusi palkki -napin toimimattomaksi'''
        self.rect.show()
        self.palkin_pituus.show()
        self.sp.show()
        self.yksikko.show()
        self.asteikko_teksti.show()
        self.line.show()
        self.nuoli_1.show()
        self.nuoli_2.show()
        self.uusi_palkki.setEnabled(False)
        self.lisaa_tuki.setEnabled(True)
        self.materiaali_valinta.setEnabled(True)

    def lisaa_palkki(self):
        '''lisää palkin'''
        self.rect = QGraphicsRectItem(300, 200, self.palkin_leveys,
                                      self.palkin_korkeus)
        self.rect.setBrush(QBrush(4))
        self.scene.addItem(self.rect)
        self.rect.hide()
        self.lisaa_tuki.setEnabled(True)
        '''Aina kun on uusi palkki luotu, voidaan aloittaa simulaatio alusta'''
        self.uusiAction.setEnabled(True)

    def lisaa_tuki_nappi(self):
        '''Luo Lisää tuki -napin'''
        self.lisaa_tuki = QPushButton("Lisää tuki")
        self.lisaa_tuki.setToolTip("Lisää tuki")
        self.lisaa_tuki.move(0, self.button_height + self.button_separation)
        self.lisaa_tuki.resize(self.button_width, self.button_height)
        self.lisaa_tuki.font = QtGui.QFont()
        self.lisaa_tuki.font.setPointSize(12)
        self.lisaa_tuki.setFont(self.lisaa_tuki.font)
        self.lisaa_tuki.setEnabled(False)
        self.lisaa_tuki.clicked.connect(self.valitse_tuki)
        self.scene.addWidget(self.lisaa_tuki)

    def vaihda_tuki_nappi(self):
        '''Luo vaihda tuki -napin'''
        self.vaihda_tuki = QPushButton("Vaihda tuki")
        self.vaihda_tuki.setToolTip("Vaihda tuki")
        self.vaihda_tuki.move(0, self.button_height + self.button_separation)
        self.vaihda_tuki.resize(self.button_width, self.button_height)
        self.vaihda_tuki.setFont(self.lisaa_tuki.font)
        self.vaihda_tuki.clicked.connect(self.valitse_tuki)
        self.scene.addWidget(self.vaihda_tuki)
        self.vaihda_tuki.hide()

    def valitse_tuki(self):
        '''Tuen valinta.
        Jos tuki on seinästä (tyyppi = 0), kysytään halutaanko vaihtaa.
        Jos haluaa muutetaan tuen grafiikka ja arvo'''

        if Ominaisuudet.palauta_tuen_tyyppi(self) == 0:
            msgBox = QMessageBox()
            msgBox.setText("Haluatko vaihtaa tuen tyyppiä?")
            msgBox.addButton(QPushButton('En'), QMessageBox.NoRole)
            msgBox.addButton(QPushButton('Kyllä'), QMessageBox.YesRole)
            vastaus = msgBox.exec_()
            self.rect.setBrush(QBrush(4))

            if vastaus == 1:
                self.viiva_1.hide()
                self.viiva_2.hide()
                self.viiva_3.hide()
                self.viiva_4.hide()
                self.nayta_tuki_alhaalta()

                if int(Ominaisuudet.onko_ulkoinen_voima_asetettu(self)) == 1:
                    self.viiva.hide()
                    self.nuoli_3.hide()
                    self.viiva_5.show()
                    self.nuoli_6.show()

                Ominaisuudet.tuki(self, 1)
            return
        '''Jos tuki on alhaalta (tyyppi = 1), kysytään halutaanko vaihtaa.
        Jos haluaa muutetaan tuen grafiikka ja arvo'''
        if Ominaisuudet.palauta_tuen_tyyppi(self) == 1:
            msgBox = QMessageBox()
            msgBox.setText("Haluatko vaihtaa tuen tyyppiä?")
            msgBox.addButton(QPushButton('Kyllä'), QMessageBox.YesRole)
            msgBox.addButton(QPushButton('En'), QMessageBox.NoRole)
            vastaus = msgBox.exec_()
            self.rect.setBrush(QBrush(4))

            if vastaus == 0:
                Ominaisuudet.tuki(self, 0)
                self.nuoli_4.hide()
                self.nuoli_5.hide()
                self.nayta_seina_tuki()

                if int(Ominaisuudet.onko_ulkoinen_voima_asetettu(self)) == 1:
                    self.viiva.show()
                    self.nuoli_3.show()
                    self.viiva_5.hide()
                    self.nuoli_6.hide()

            if vastaus == 1:
                pass
        '''Jos tukea ei ole (tyyppi = 2). Tuen tyypin valinta'''
        if Ominaisuudet.palauta_tuen_tyyppi(self) == 2:
            msgBox = QMessageBox()
            msgBox.setText("Valitse tuen tyyppi")
            msgBox.addButton(QPushButton('Seinätuki'), QMessageBox.YesRole)
            msgBox.addButton(QPushButton('Tuki alhaalta'), QMessageBox.NoRole)
            vastaus = msgBox.exec_()
            self.vaihda_tuki.show()
            self.lisaa_tuki.hide()

            if vastaus == 0:
                self.nayta_seina_tuki()
                Ominaisuudet.tuki(self, 0)

            if vastaus == 1:
                self.nayta_tuki_alhaalta()
                Ominaisuudet.tuki(self, 1)
        '''Joka tapauksessa asetetaan ulkoisen voiman lisääminen mahdolliseksi
        sekä maalataan palkki normaaliksi'''
        self.lisaa_ulkoinen_voima.setEnabled(True)
        self.simuloi.setEnabled(True)

    def nayta_seina_tuki(self):
        '''Näytetään seinätukea kuvaavat grafiikat'''
        self.viiva_1.show()
        self.viiva_2.show()
        self.viiva_3.show()
        self.viiva_4.show()

    def nayta_tuki_alhaalta(self):
        '''Näytetään alatukea kuvaavat grafiikat'''
        self.nuoli_4.show()
        self.nuoli_5.show()

    def paivita_tuen_tyyppi(self, tyyppi):
        '''Päivittää tuen tyypin arvon Ominaisuudet luokassa'''
        Ominaisuudet.tuki(self, tyyppi)

    def lisaa_seina_tuki(self):
        '''Piirtää seinätukea kuvaavat viivat sekä asettaa self.tuen_tyyppi arvoksi 
        Asettaa SIMULOI-napin painettavaksi'''
        viiva = QtGui.QPen(QtCore.Qt.black, 2)
        viiva.setStyle(QtCore.Qt.SolidLine)
        self.viiva_1 = QGraphicsLineItem(QtCore.QLineF(300, 202, 275, 225))
        self.viiva_2 = QGraphicsLineItem(QtCore.QLineF(300, 222, 275, 245))
        self.viiva_3 = QGraphicsLineItem(QtCore.QLineF(300, 242, 275, 265))
        self.viiva_4 = QGraphicsLineItem(QtCore.QLineF(300, 262, 275, 285))

        self.scene.addItem(self.viiva_1)
        self.scene.addItem(self.viiva_2)
        self.scene.addItem(self.viiva_3)
        self.scene.addItem(self.viiva_4)
        self.viiva_1.hide()
        self.viiva_2.hide()
        self.viiva_3.hide()
        self.viiva_4.hide()
        tyyppi = 0
        Ominaisuudet.tuki(self, tyyppi)
        self.simuloi.setEnabled(True)

    def lisaa_tuki_alhaalta(self):
        '''Piirtää alhaalta tukemista kuvaavat grafiikat
        sekä asettaa self.tuen_tyyppi arvoksi 1'''
        leveys = 15  #nuolen leveus pikseleissä
        korkeus = 30  #nuuolen korkeus pikseleissä
        '''Nuolen kärkien koordinaatit'''
        nuoli_piste_1 = QtCore.QPointF(305, 275)
        nuoli_piste_2 = QtCore.QPointF(305 - leveys, 275 + korkeus)
        nuoli_piste_3 = QtCore.QPointF(305 + leveys, 275 + korkeus)

        nuoli_piste_4 = QtCore.QPointF(995, 275)
        nuoli_piste_5 = QtCore.QPointF(995 - leveys, 275 + korkeus)
        nuoli_piste_6 = QtCore.QPointF(995 + leveys, 275 + korkeus)
        '''Luodaan nuolia kuvaavat QPolygonF oliot'''
        self.nuoli_4 = QGraphicsPolygonItem(
            QtGui.QPolygonF([nuoli_piste_1, nuoli_piste_2, nuoli_piste_3]))
        self.nuoli_5 = QGraphicsPolygonItem(
            QtGui.QPolygonF([nuoli_piste_4, nuoli_piste_5, nuoli_piste_6]))
        self.nuoli_brush = QtGui.QBrush(1)
        self.nuoli_pencil = QtGui.QPen(QtCore.Qt.black, 2)
        self.nuoli_pencil.setStyle(QtCore.Qt.SolidLine)
        '''Lisätään nuolet sceneen'''
        self.scene.addItem(self.nuoli_4)
        self.scene.addItem(self.nuoli_5)
        self.nuoli_4.hide()
        self.nuoli_5.hide()

        tyyppi = 1
        Ominaisuudet.tuki(self, tyyppi)
        self.simuloi.setEnabled(True)

    def lisaa_ulkoinen_voima_nappi(self):
        '''Luo Lisää ulkoinen voima -napin'''
        self.lisaa_ulkoinen_voima = QPushButton("Lisää ulkoinen voima")
        self.lisaa_ulkoinen_voima.setToolTip("Lisää ulkoinen voima")
        self.lisaa_ulkoinen_voima.move(
            0, 2 * self.button_height + 2 * self.button_separation)
        self.lisaa_ulkoinen_voima.resize(self.button_width, self.button_height)
        self.lisaa_ulkoinen_voima.font = QtGui.QFont()
        self.lisaa_ulkoinen_voima.font.setPointSize(8)
        self.lisaa_ulkoinen_voima.setFont(self.lisaa_ulkoinen_voima.font)
        self.lisaa_ulkoinen_voima.clicked.connect(self.nayta_ulkoinen_voima)
        self.lisaa_ulkoinen_voima.clicked.connect(self.nollaa_gradientti)
        self.lisaa_ulkoinen_voima.setEnabled(False)
        self.scene.addWidget(self.lisaa_ulkoinen_voima)

    def poista_ulkoinen_voima_nappi(self):
        '''Luo poista ulkoinen voima -napin'''
        self.poista_ulkoinen_voima = QPushButton("Poista ulkoinen voima")
        self.poista_ulkoinen_voima.setToolTip("Poista ulkoinen voima")
        self.poista_ulkoinen_voima.move(
            0, 2 * self.button_height + 2 * self.button_separation)
        self.poista_ulkoinen_voima.resize(self.button_width,
                                          self.button_height)
        self.poista_ulkoinen_voima.setFont(self.lisaa_ulkoinen_voima.font)
        self.poista_ulkoinen_voima.clicked.connect(self.piilota_ulkoinen_voima)
        self.poista_ulkoinen_voima.clicked.connect(self.nollaa_gradientti)
        self.scene.addWidget(self.poista_ulkoinen_voima)
        self.poista_ulkoinen_voima.hide()

    def piilota_ulkoinen_voima(self):
        '''Piilotaa kaiken ulkoiseen voimaan liittyvän'''
        self.sp_voima.hide()
        self.yksikko_voima.hide()
        self.ulkoinen_voima.hide()
        self.lisaa_ulkoinen_voima.show()
        self.lisaa_ulkoinen_voima.setEnabled(True)
        self.viiva.hide()
        self.nuoli_3.hide()
        self.viiva_5.hide()
        self.nuoli_6.hide()
        self.poista_ulkoinen_voima.hide()
        self.lisaa_ulkoinen_voima.show()
        self.tulos.hide()

        Ominaisuudet.ulkoinen_voima(self, 0)

    def nayta_ulkoinen_voima(self):
        '''Näytetään ulkoinen voima riippuen tuen tyypistä'''
        self.sp_voima.show()
        self.yksikko_voima.show()
        self.ulkoinen_voima.show()
        self.lisaa_ulkoinen_voima.hide()
        self.poista_ulkoinen_voima.show()

        if int(Ominaisuudet.palauta_tuen_tyyppi(self)) == 0:
            self.viiva.show()
            self.nuoli_3.show()

        if int(Ominaisuudet.palauta_tuen_tyyppi(self)) == 1:
            self.viiva_5.show()
            self.nuoli_6.show()

        Ominaisuudet.ulkoinen_voima(self, 1)

    def ulkoinen_voima_valikko(self):
        '''Luo voiman suuruus -tekstin'''
        self.ulkoinen_voima = QGraphicsSimpleTextItem("Voiman suuruus")
        self.ulkoinen_voima.setPos(600, 5)
        self.ulkoinen_voima.font = QtGui.QFont()
        self.ulkoinen_voima.font.setPointSize(12)
        self.ulkoinen_voima.setFont(self.ulkoinen_voima.font)
        self.lisaa_ulkoinen_voima.setEnabled(False)
        self.scene.addItem(self.ulkoinen_voima)
        self.ulkoinen_voima.hide()
        '''Luo voiman arvon QSpinBoxin'''
        self.sp_voima = QSpinBox()
        self.sp_voima.move(750, 5)
        self.sp_voima.setRange(0, 10000)
        self.sp_voima.setSingleStep(1)
        self.sp_voima.setMinimumHeight(30)
        self.sp_voima.setValue(int(Ominaisuudet.palauta_voima(self)))
        self.sp_voima.valueChanged.connect(self.paivita_voima)
        self.scene.addWidget(self.sp_voima)
        self.sp_voima.hide()
        '''Luo yksikönvalinta QComboBOxin'''
        self.yksikko_voima = QComboBox()
        self.yksikko_voima.addItem("kN", 0)
        self.yksikko_voima.addItem("N", 1)
        self.yksikko_voima.move(820, 5)
        self.yksikko_voima.setMinimumHeight(30)
        self.yksikko_voima.setCurrentIndex(
            int(Ominaisuudet.palauta_voiman_yksikko(self)))
        self.yksikko_voima.setEditable(True)
        self.yksikko_voima.lineEdit().setAlignment(QtCore.Qt.AlignCenter)
        self.scene.addWidget(self.yksikko_voima)
        self.yksikko_voima.currentIndexChanged.connect(
            self.paivita_yksikko_voima)
        self.yksikko_voima.hide()

    def ulkoinen_voima_nuoli_seinatuki(self):
        '''Luo nuolen osoittamaan ulkoisen voiman paikkaa'''
        voima_viiva = QtGui.QPen(QtCore.Qt.black, 2)
        voima_viiva.setStyle(QtCore.Qt.SolidLine)
        '''Nuolen kärkien koordinaatit seinätuelle'''
        nuoli_piste_1 = QtCore.QPointF(self.palkin_paatypiste - 7, 185)
        nuoli_piste_2 = QtCore.QPointF(self.palkin_paatypiste, 200)
        nuoli_piste_3 = QtCore.QPointF(self.palkin_paatypiste + 7, 185)
        viiva_x = self.palkin_paatypiste
        self.viiva = QGraphicsLineItem(
            QtCore.QLineF(viiva_x, 100, viiva_x, 200))
        '''Luodaan nuoli QPolygonItem olio'''
        self.nuoli_3 = QGraphicsPolygonItem(
            QtGui.QPolygonF([nuoli_piste_1, nuoli_piste_2, nuoli_piste_3]))
        self.nuoli_brush = QtGui.QBrush(1)
        self.nuoli_pencil = QtGui.QPen(QtCore.Qt.black, 2)
        self.nuoli_pencil.setStyle(QtCore.Qt.SolidLine)
        '''Lisätään viiva sekä päiden nuolet sceneen'''
        self.scene.addItem(self.viiva)
        self.scene.addItem(self.nuoli_3)
        self.viiva.hide()
        self.nuoli_3.hide()
        '''Lisätään tieto, että voima on asetettu'''
        Ominaisuudet.ulkoinen_voima(self, 1)

    def ulkoinen_voima_nuoli_alatuki(self):
        '''Nuolen kärkien koordinaatit alhaalta tuetulle palkille'''
        nuoli_piste_1 = QtCore.QPointF(self.palkin_keskipiste - 7, 185)
        nuoli_piste_2 = QtCore.QPointF(self.palkin_keskipiste, 200)
        nuoli_piste_3 = QtCore.QPointF(self.palkin_keskipiste + 7, 185)
        viiva_x = self.palkin_keskipiste
        '''Luodaan nuoli QPolygonItem olio'''
        self.nuoli_6 = QGraphicsPolygonItem(
            QtGui.QPolygonF([nuoli_piste_1, nuoli_piste_2, nuoli_piste_3]))
        self.nuoli_brush = QtGui.QBrush(1)
        self.nuoli_pencil = QtGui.QPen(QtCore.Qt.black, 2)
        self.nuoli_pencil.setStyle(QtCore.Qt.SolidLine)

        self.viiva_5 = QGraphicsLineItem(
            QtCore.QLineF(viiva_x, 100, viiva_x, 200))
        '''Lisätään viiva sekä päiden nuolet sceneen'''
        self.scene.addItem(self.viiva_5)
        self.scene.addItem(self.nuoli_6)
        self.viiva_5.hide()
        self.nuoli_6.hide()
        '''Lisätään tieto, että voima on asetettu'''
        Ominaisuudet.ulkoinen_voima(self, 1)

    def paivita_voima(self):
        '''Lukee voiman arvon 
        ja kutsuu Ominaisuudet luoka metodia voima'''
        voima = self.sp_voima.value()
        Ominaisuudet.voima(self, voima)

    def paivita_yksikko_voima(self):
        '''Lukee ykiskön arvon 
        ja kutsuu Ominaisuudet-luokan metodia yksikko_voima'''
        self.yksikko_voima_arvo = self.yksikko_voima.currentData()
        Ominaisuudet.yksikko_voima(self, self.yksikko_voima_arvo)

    def materiaali_valikko(self):
        ''' Luo Materiaali-otsikon'''
        self.materiaali = QGraphicsSimpleTextItem("Materiaali")
        self.materiaali.setPos(
            0, 3 * self.button_height + 3 * self.button_separation)
        self.materiaali.font = QtGui.QFont()
        self.materiaali.font.setPointSize(12)
        self.materiaali.setFont(self.materiaali.font)
        self.scene.addItem(self.materiaali)
        '''Luo drop down valikon materiaalivalinnalle'''
        self.materiaali_valinta = QComboBox()
        self.materiaali_valinta.addItem("Teräs", 0)
        self.materiaali_valinta.addItem("Alumiini", 1)
        self.materiaali_valinta.addItem("Muovi", 2)
        self.materiaali_valinta.move(
            0, 3 * self.button_height + 3 * self.button_separation + 25)
        self.materiaali_valinta.resize(self.button_width,
                                       self.button_height - 25)
        self.materiaali_valinta.setEditable(True)
        self.materiaali_valinta.lineEdit().setAlignment(QtCore.Qt.AlignCenter)
        self.materiaali_valinta.setCurrentIndex(0)
        self.scene.addWidget(self.materiaali_valinta)
        self.materiaali_valinta.setEnabled(False)
        self.materiaali_valinta.currentIndexChanged.connect(
            self.paivita_materiaali)

    def paivita_materiaali(self):
        '''Lukee materiaalin arvon 
        ja kutsuu Ominaisuudet-luokan metodia materiaali'''
        materiaali = self.materiaali_valinta.currentData()
        Ominaisuudet.materiaali(self, materiaali)

    def simulaatio_nappi(self):
        '''Luo SIMULOI-napin'''
        self.simuloi = QPushButton('SIMULOI')
        self.simuloi.setToolTip('Simuloi valittu rakenne')
        self.simuloi.move(0,
                          4 * self.button_height + 4 * self.button_separation)
        self.simuloi.setStyleSheet("background-color:rgb(122, 201, 255)")
        self.simuloi.resize(self.button_width, self.button_height)
        self.simuloi.font = QtGui.QFont()
        self.simuloi.font.setPointSize(12)
        self.simuloi.setFont(self.simuloi.font)
        self.simuloi.setEnabled(False)
        self.simuloi.clicked.connect(self.simulaatio)
        self.scene.addWidget(self.simuloi)

    def simulaatio(self):
        '''Kutsuu laskentaa suorittavaa metodia ja tallentaa tuloksen.
        Tämän jälkeen kutsuu lopputuloksen esittävän tekstin päivittävää metodia
        sekä palkin visualisoivaa gradient-metodia'''
        Laskin.laskin(self)
        Ominaisuudet.palauta_tulos(self)
        self.paivita_tulos_teksti()
        self.tallennaAction.setEnabled(True)

        if Ominaisuudet.palauta_tuen_tyyppi(self) == 0:

            if Ominaisuudet.onko_ulkoinen_voima_asetettu(self) == 1:
                self.gradient_seina_tuki()

            if Ominaisuudet.onko_ulkoinen_voima_asetettu(self) == 0:
                self.gradient_seina_tuki_ei_voimaa()

        if Ominaisuudet.palauta_tuen_tyyppi(self) == 1:
            self.gradient_alatuki()

    def tulos_teksti(self):
        '''Lisää tekstin, joka kertoo maksimijänintyksen arvon'''
        teksti = "Maksimijännitys " + str(self.maks_jannitys) + " MPa"
        self.tulos = QGraphicsSimpleTextItem(teksti)
        self.tulos.setPos(550, 500)
        self.tulos.font = QtGui.QFont()
        self.tulos.font.setPointSize(12)
        self.tulos.setFont(self.tulos.font)
        self.scene.addItem(self.tulos)
        self.tulos.hide()

    def paivita_tulos_teksti(self):
        '''Päivittää maksimijännityksen arvoa kuvaavan tekstin'''
        maks_jannitys = Ominaisuudet.palauta_tulos(self)
        self.tulos.setText("Maksimijännitys " + str(maks_jannitys) + " MPa")
        self.tulos.show()

    def palkin_pituus_valikko(self):
        '''Luo palkin pituus tekstin sekä spinbox-valitsimen pituuden asettamista varten
        Päivittää palkin pituuden Ominaisuudet luokan avulla'''
        self.palkin_pituus = QGraphicsSimpleTextItem("Palkin pituus")
        self.palkin_pituus.setPos(300, 5)
        self.palkin_pituus.font = QtGui.QFont()
        self.palkin_pituus.font.setPointSize(12)
        self.palkin_pituus.setFont(self.palkin_pituus.font)
        self.scene.addItem(self.palkin_pituus)
        self.palkin_pituus.hide()

        self.sp = QSpinBox()
        self.scene.addWidget(self.sp)
        self.sp.hide()
        self.sp.move(450, 5)
        self.sp.setRange(0, 100)
        self.sp.setSingleStep(1)
        self.sp.setMinimumHeight(30)
        self.sp.setValue(int(Ominaisuudet.palauta_palkin_pituus(self)))
        self.paivita_pituus()
        self.sp.valueChanged.connect(self.paivita_pituus)

    def paivita_pituus(self):
        '''Lukee palkin pituuden ja aktivoi Ominaisuudet luokan meodin palkin pituus'''
        self.palkin_pituus_arvo = self.sp.value()
        Ominaisuudet.palkin_pituus(self, self.palkin_pituus_arvo)
        self.paivita_asteikon_arvot()

    def yksikko_pituus(self):
        '''Luo yksikönvalinta dropdown-menun
        ja arvon muuttuessa päivittää yksikön Ominaisuudet-luokassa'''
        self.yksikko = QComboBox()
        self.yksikko.addItem("m", 0)
        self.yksikko.addItem("cm", 1)
        self.yksikko.addItem("mm", 2)
        self.yksikko.move(500, 5)
        self.yksikko.setMinimumHeight(30)
        self.yksikko.setEditable(True)
        self.yksikko.lineEdit().setAlignment(QtCore.Qt.AlignCenter)
        self.yksikko.setCurrentIndex(
            Ominaisuudet.palauta_pituuden_yksikko(self))
        self.scene.addWidget(self.yksikko)
        self.yksikko.hide()
        self.yksikko_arvo = self.yksikko.currentData()
        self.yksikko.currentIndexChanged.connect(self.paivita_yksikko)

    def paivita_yksikko(self):
        '''Lukee yksikön arvon 
        ja kutsuu Ominaisuudet-luokan metodia yksikko'''
        self.yksikko_arvo = self.yksikko.currentData()
        Ominaisuudet.yksikko(self, self.yksikko_arvo)
        self.paivita_asteikon_arvot()

    def asteikko(self):
        ''''Luodaan viivaa kuvaava olio'''
        viiva = QtGui.QPen(QtCore.Qt.black, 2)
        viiva.setStyle(QtCore.Qt.SolidLine)
        '''Oikean puoleisen nuolen kärkien koordinaatit'''
        nuoli_1_piste_1 = QtCore.QPointF(990, 390)
        nuoli_1_piste_2 = QtCore.QPointF(1000, 400)
        nuoli_1_piste_3 = QtCore.QPointF(990, 410)
        '''Vasemman puoleisen nuolen kärkien koordinaatit'''
        nuoli_2_piste_1 = QtCore.QPointF(310, 390)
        nuoli_2_piste_2 = QtCore.QPointF(300, 400)
        nuoli_2_piste_3 = QtCore.QPointF(310, 410)
        '''Luodaan nuoli QPolygonF oliot'''
        self.nuoli_1 = QGraphicsPolygonItem(
            QtGui.QPolygonF(
                [nuoli_1_piste_1, nuoli_1_piste_2, nuoli_1_piste_3]))
        self.nuoli_2 = QGraphicsPolygonItem(
            QtGui.QPolygonF(
                [nuoli_2_piste_1, nuoli_2_piste_2, nuoli_2_piste_3]))

        self.nuoli_brush = QtGui.QBrush(1)
        self.nuoli_pencil = QtGui.QPen(QtCore.Qt.black, 2)
        self.nuoli_pencil.setStyle(QtCore.Qt.SolidLine)

        self.line = QGraphicsLineItem(QtCore.QLineF(300, 400, 1000, 400))
        '''Lisätään viiva sekä päiden nuolet sceneen'''
        self.scene.addItem(self.line)
        self.scene.addItem(self.nuoli_1)
        self.scene.addItem(self.nuoli_2)
        self.line.hide()
        self.nuoli_1.hide()
        self.nuoli_2.hide()

    def lisaa_asteikko_arvo(self):
        '''Lisää tekstikentän pituuden arvolle sekä yksikölle'''
        teksti = (str(Ominaisuudet.palauta_palkin_pituus(self)) + " " + "m")
        self.asteikko_teksti = QGraphicsSimpleTextItem()
        self.asteikko_teksti.setText(teksti)
        self.asteikko_teksti.setPos(650, 425)
        self.asteikko_teksti.font = QtGui.QFont()
        self.asteikko_teksti.font.setPointSize(12)
        self.asteikko_teksti.setFont(self.asteikko_teksti.font)
        self.scene.addItem(self.asteikko_teksti)
        self.asteikko_teksti.hide()

    def paivita_asteikon_arvot(self):
        '''Päivittää palkin pituutta kuvaavan asteikon'''
        yksikko = Ominaisuudet.palauta_pituuden_yksikko(self)

        if yksikko == 0:
            self.yksikko_merkki = "m"
        if yksikko == 1:
            self.yksikko_merkki = "cm"
        if yksikko == 2:
            self.yksikko_merkki = "mm"

        pituus = float(Ominaisuudet.palauta_palkin_pituus(self))
        teksti = str(str(pituus) + " " + self.yksikko_merkki)
        self.asteikko_teksti.setText(teksti)
        self.asteikko_teksti.show()

    def gradient_seina_tuki(self):
        '''Luo seinästä tuetun palkin rasitusta kuvaavan gradientin'''
        gradient = QLinearGradient(300, 200, 300 + self.palkin_leveys, 200)
        gradient.setColorAt(0, QColor(244, 72, 66))
        gradient.setColorAt(1, QColor(65, 244, 83))
        self.rect.setBrush(gradient)

    def gradient_seina_tuki_ei_voimaa(self):
        '''Luo ilman ulkoista voimaa olevan gradientin'''
        gradient = QLinearGradient(300, 200, 300 + (self.palkin_leveys / 2),
                                   200)
        gradient.setColorAt(0, QColor(244, 72, 66))
        gradient.setColorAt(1, QColor(65, 244, 83))
        self.rect.setBrush(gradient)

    def gradient_alatuki(self):
        '''Luo kahdella alatuella olevan palkin rasitusta kuvaavan gradientin'''
        gradient = QLinearGradient(300, 200, 300 + self.palkin_leveys, 200)
        gradient.setColorAt(0, QColor(65, 244, 83))
        gradient.setColorAt(0.5, QColor(244, 72, 66))
        gradient.setColorAt(1, QColor(65, 244, 83))
        self.rect.setBrush(gradient)

    def nollaa_gradientti(self):
        '''Asettaa palkin "normaaliksi"'''
        self.rect.setBrush(QBrush(4))

    def uusi_rakenne(self):
        '''Muokkaa ikkunaa uuden simulaation luomista varten'''
        self.rect.hide()
        self.ulkoinen_voima.hide()
        self.sp_voima.hide()
        self.yksikko_voima.hide()
        self.nuoli_1.hide()
        self.nuoli_2.hide()
        self.nuoli_3.hide()
        self.nuoli_4.hide()
        self.nuoli_5.hide()
        self.nuoli_6.hide()
        self.viiva_1.hide()
        self.viiva_2.hide()
        self.viiva_3.hide()
        self.viiva_4.hide()
        self.viiva_5.hide()
        self.viiva.hide()
        self.palkin_pituus.hide()
        self.sp.hide()
        self.yksikko.hide()
        self.line.hide()
        self.asteikko_teksti.hide()
        self.tulos.hide()
        self.nollaa_gradientti()
        self.lisaa_tuki.show()
        self.vaihda_tuki.hide()
        self.poista_ulkoinen_voima.hide()
        self.lisaa_ulkoinen_voima.show()
        Ominaisuudet.alkuarvot(self)
        '''Asettaa napit'''
        self.uusi_palkki.setEnabled(True)
        self.lisaa_ulkoinen_voima.setEnabled(False)
        self.lisaa_tuki.setEnabled(False)
        self.simuloi.setEnabled(False)
        self.tallennaAction.setEnabled(False)
        '''Päivittää tuen tyypiksi arvon, joka vastaa, ettei tukea ole'''
        self.tuen_tyyppi = 2

    def close_application(self):
        '''sulkee ohjelman'''
        sys.exit()
Beispiel #6
0
class MainWidget(QWidget):
    precision_list = ["0.001", "0.0001", "0.00001"]

    def __init__(self, parent):
        super(MainWidget, self).__init__(parent)
        self.init_ui()

    def init_ui(self):

        main_widget_vbox_layout = QVBoxLayout()

        # File buttons
        file_box = QGroupBox()
        file_box.setTitle("File...")
        file_box_layout = QVBoxLayout()

        self.openFileBtn = QPushButton("Open file")
        self.saveFileBtn = QPushButton("Save file")
        self.openFileBtn.setToolTip("Open a GSI-16 file")
        self.saveFileBtn.setToolTip("Save as new GSI-16 file")
        self.openFileBtn.clicked.connect(self.parent()._choose_gsi_file)
        self.saveFileBtn.clicked.connect(self.parent().save_gsi_file)

        file_box_layout.addWidget(self.openFileBtn)
        file_box_layout.addWidget(self.saveFileBtn)
        file_box.setLayout(file_box_layout)

        # Tools box
        tools_box = QGroupBox()
        tools_box.setTitle("Tools")
        tools_box_layout = QGridLayout()

        label_validate = QLabel("Validate values")
        tools_box_layout.addWidget(label_validate, 0, 0)

        self.precisionCombo = QComboBox()
        self.precisionCombo.addItems(self.precision_list)
        self.precisionCombo.setEnabled(False)
        self.precisionCombo.activated[str].connect(self.set_precision)

        self.validate_values_btn = QPushButton("Validate")
        self.validate_values_btn.setToolTip(
            "Validate format of Measured data GSI words")
        self.validate_values_btn.clicked.connect(
            functools.partial(self.parent()._validate_gsi_objects, True))
        self.validate_values_btn.setEnabled(False)
        tools_box_layout.addWidget(self.validate_values_btn, 0, 1)

        label = QLabel("Change Precision")
        tools_box_layout.addWidget(label, 1, 0)
        tools_box_layout.addWidget(self.precisionCombo, 1, 1)
        tools_box.setLayout(tools_box_layout)

        control_box_hbox_layout = QHBoxLayout()
        control_box_hbox_layout.addWidget(file_box)
        control_box_hbox_layout.addSpacing(40)
        control_box_hbox_layout.addWidget(tools_box)
        control_box_hbox_layout.addStretch(1)
        main_widget_vbox_layout.addLayout(control_box_hbox_layout)

        # Table widget
        self.tableWidget = GsiTableWidget(self)
        # self.tableWidget.setRowCount(30)
        self.tableWidget.setColumnCount(8)

        # Header stylesheet
        stylesheet = "QHeaderView::section{Background-color:rgb(196,214,255); gridline-color: rgb(214, 214, 214)}"
        self.tableWidget.setStyleSheet(stylesheet)

        self.tableWidget.setHorizontalHeaderLabels([
            "Pointnumber", "Y-coordinate", "X-coordinate", "Elevation", "Code",
            "Attribute 1", "Attribute 2", "Attribute 3"
        ])
        font = QFont()
        font.setItalic(True)
        font.setPointSize(10)

        for idx in range(0, self.tableWidget.columnCount()):
            self.tableWidget.horizontalHeaderItem(idx).setFont(font)
            self.tableWidget.setColumnWidth(idx, 145)

        main_widget_vbox_layout.addWidget(self.tableWidget)
        self.setLayout(main_widget_vbox_layout)

        self.setGeometry(0, 0, 1240, 600)
        pal = self.palette()
        pal.setColor(self.backgroundRole(), QColor(255, 247, 204))
        self.setPalette(pal)

        self.setAutoFillBackground(True)
        self.setWindowTitle('Buttons')

    def clear_table(self):
        for i in reversed(range(self.tableWidget.rowCount())):
            self.tableWidget.removeRow(i)

    def fill_table(self, gsi_objects):
        self.tableWidget.setRowCount(len(gsi_objects))
        for idx, gsiObj in enumerate(gsi_objects):
            for posIdx, word in enumerate(gsiObj.gsi_words):
                # Add new Item (GSI Word) here
                self.tableWidget.setItem(idx, posIdx, word)

    def set_precision(self, precision):
        for row in range(self.tableWidget.rowCount()):
            for column in range(1, 4):
                self.tableWidget.item(row, column).set_precision(precision)
                self.parent().precision = len(precision.split(".")[1])