def __init__(self, base): Window.__init__(self, base, i18n.get('image_preview')) self.loader = BarLoadIndicator() self.view = QLabel() self.view.setSizePolicy(QSizePolicy.Ignored, QSizePolicy.Ignored) self.view.setScaledContents(True) scroll_area = QScrollArea() scroll_area.setBackgroundRole(QPalette.Dark) scroll_area.setWidget(self.view) scroll_area.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff) scroll_area.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.error_label = QLabel(i18n.get('error_loading_image')) self.error_label.setAlignment(Qt.AlignHCenter) self.error_label.setStyleSheet("QLabel {background-color: #ffecec;}") layout = QVBoxLayout() layout.setSpacing(0) layout.setContentsMargins(0, 0, 0, 0) layout.addWidget(self.loader) layout.addWidget(self.error_label) layout.addWidget(scroll_area) self.setLayout(layout) self.__clear()
def init_ui(self): self.setFrameShape(QFrame.Box) inner = QWidget() self.layout = QVBoxLayout() self.layout.setSpacing(1) self.layout.setMargin(1) self.layout.setAlignment(Qt.AlignTop) inner.setLayout(self.layout) scroll = QScrollArea() scroll.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOn) scroll.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) scroll.setWidgetResizable(True) scroll.setWidget(inner) layout = QVBoxLayout(self) layout.addWidget(scroll) self.setLayout(layout)
class UIWellPlotPG(QtCore.QObject): def setupUI(self): self.mainWidget = WellPlotWidget() vBox = QtGui.QVBoxLayout() self.splitter = QSplitter(QtCore.Qt.Vertical) self.headerScrollArea = QScrollArea() self.headerScrollArea.setVerticalScrollBarPolicy( QtCore.Qt.ScrollBarAlwaysOn) self.headerScrollArea.setHorizontalScrollBarPolicy( QtCore.Qt.ScrollBarAlwaysOff) self.headerScrollArea.setWidgetResizable(False) self.scrollArea = QScrollArea() self.scrollArea.setVerticalScrollBarPolicy( QtCore.Qt.ScrollBarAlwaysOff) self.scrollArea.setHorizontalScrollBarPolicy( QtCore.Qt.ScrollBarAlwaysOn) #Needs to be true to allow widget in scroll area size to change self.scrollArea.setWidgetResizable(True) #self.scrollArea.setWidget(self.dataWidget) #see http://stackoverflow.com/questions/29583927/pyqt-qscrollarea-within-qscrollarea/29584939#29584939 self.scrollArea.horizontalScrollBar().valueChanged.connect( self.headerScrollArea.horizontalScrollBar().setValue) self.splitter.addWidget(self.headerScrollArea) self.splitter.addWidget(self.scrollArea) #test hBox = QtGui.QHBoxLayout() #set parent so can access it for widget sizing self.scaleWidget = QWidget() self.scaleWidgetLayout = QtGui.QVBoxLayout() self.scaleWidget.setLayout(self.scaleWidgetLayout) self.scaleWidget.setMinimumWidth(30) hBox.addWidget(self.splitter, 1) hBox.addWidget(self.scaleWidget) self.mainWidget.setLayout(hBox) #end test '''
class SkillWidget(TraitWidget): """ @brief Das Widget, in welchem sämtliche Fertigkeiten angeordnet sind. Wird bei irgendeiner Fertigkeit der Spazialisierungen-Knopf gedrückt, werden alle anderen Spezialisierungs-Knöpfe ausgeschalten. """ specialtiesActivated = Signal(bool, object) def __init__(self, template, character, parent=None): super(SkillWidget, self).__init__(template, character, parent) self.__layout = QVBoxLayout() self.setLayout(self.__layout) self.__scrollArea = QScrollArea() ## Die Auflistung der Fertigkeiten soll auch unter Windows einen transparenten Hintergrund haben. self.__scrollArea.setObjectName("transparentWidget") ## \todo Sollte nicht vom Betriebssystem, sondern vom verwendeten Style abhängen. if os.name == "nt": self.__scrollArea.setStyleSheet( "QWidget#transparentWidget { background: transparent; }") self.__layout.addWidget(self.__scrollArea) self.__scrollLayout = QVBoxLayout() self.__scrollWidget = QWidget() ## Die Auflistung der Fertigkeiten soll auch unter Windows einen transparenten Hintergrund haben. Indem ich den selben Namen wie zuvor vergebe, wirkt auch das Stylsheet auf dieses Widget. self.__scrollWidget.setObjectName("transparentWidget") #self.__scrollWidget.setStyleSheet( "QWidget#transparentWidget { background-color:transparent; }" ) #scrollWidget.setMinimumSize(this.width(), 400); self.__scrollWidget.setLayout(self.__scrollLayout) typ = "Skill" ## Eine Liste, in der alle Eigenschafts-Widgets aufgelistet werden. self.__traitWidgets = [] for item in Config.CATEGORIES_MAIN: #Debug.debug(self._character.traits) # Für jede Kategorie wird ein eigener Abschnitt erzeugt. widgetSkillCategory = QGroupBox() widgetSkillCategory.setTitle(item) widgetSkillCategory.setFlat(True) layoutSkillCategory = QVBoxLayout() widgetSkillCategory.setLayout(layoutSkillCategory) self.__scrollLayout.addWidget(widgetSkillCategory) __list = list(self._character.traits[typ][item].items()) __list.sort() for skill in __list: # Anlegen des Widgets, das diese Eigenschaft repräsentiert. traitWidget = CharaTrait(skill[1], self) traitWidget.buttonText = 0 traitWidget.setDescriptionHidden(True) traitWidget.enableButton( 0 ) # Zu Beginn sollen die Spezailisierungen nicht enabled sein. # Dieses Widget auch an Liste anhängen, damit ich einfacher darauf zugreifen kann. traitListItem = traitWidget self.__traitWidgets.append(traitListItem) # Es werden nur Fertigkeiten der richtigen Alters- und Zeit-Kategorie angezeigt. self.hideReasonChanged.connect(traitWidget.hideOrShowTrait) # Fertigkeiten haben Spezialisierungen. traitWidget.specialtiesClicked.connect( self.uncheckOtherButtons) traitWidget.specialtiesClicked.connect( self.specialtiesActivated.emit) ## Wenn sich die Spezialisierungen ändern, sollen die veränderten Spezialisierungen auch angezeigt werden. Das wird so gelöst, als wäre der Knopf für die Spezialisierungen erneut gedrückt worden. #skill.specialtiesChanged.connect(self.emitSpecialtiesActivated) layoutSkillCategory.addWidget(traitWidget) self.maxTraitChanged.connect(traitWidget.setMaximum) # Stretch einfügen, damit die Eigenschaften besser angeordnet sind. self.__scrollLayout.addStretch() self.__scrollArea.setWidget(self.__scrollWidget) self.__scrollArea.setWidgetResizable(True) self.__scrollArea.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.__scrollArea.setMinimumWidth( self.__scrollArea.viewport().minimumWidth()) def uncheckOtherButtons(self, sw, trait): """ Über diese Funktion werden alle anderen Spezialisierungs-Knöpfe deaktiviert, sobald einer aktiviert wird. """ #Debug.debug("Drücke {}".format(skillName)) if sw: for item in self.__traitWidgets: if item.name != trait.name: item.setSpecialtyButtonChecked(False)
class ScrollArea(QFrame): def __init__(self, parent=None, horizontal=True, vertical=True, color=None): QFrame.__init__(self, parent) self.scrollarea = QScrollArea(self) self.scrollarea.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.scrollarea.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.v_pad = scrollbar.ScrollPad(self) self.v_pad.setOrientation(Qt.Vertical) self.v_pad.setMinimumWidth(30) if color: self.v_pad.set_color(color) self.h_pad = scrollbar.ScrollPad(self) self.h_pad.setOrientation(Qt.Horizontal) self.h_pad.setMinimumHeight(30) if color: self.h_pad.set_color(color) QObject.connect(self.v_pad, SIGNAL('valueChanged(int)'), self.v_scroll) QObject.connect(self.h_pad, SIGNAL('valueChanged(int)'), self.h_scroll) for name in ('setWidgetResizable',): setattr(self, name, getattr(self.scrollarea, name)) self.horizontal(horizontal) self.vertical(vertical) Layout1 = QVBoxLayout(self) Layout1.setSpacing(0) Layout1.setMargin(0) Layout2 = QHBoxLayout() Layout2.setSpacing(0) Layout2.setMargin(0) Layout2.addWidget(self.scrollarea) Layout2.addWidget(self.v_pad) Layout1.addLayout(Layout2) Layout1.addWidget(self.h_pad) def setWidget(self, widget): self.scrollarea.setWidget(widget) def horizontal(self, on): if on: self.h_pad.show() else: self.h_pad.hide() def vertical(self, on): if on: self.v_pad.show() else: self.v_pad.hide() def v_scroll(self, value): sb = self.v_pad target_sb = self.scrollarea.verticalScrollBar() percent = sb.value() / float(sb.maximum()) target_sb.setValue(int(percent * target_sb.maximum())) def h_scroll(self, value): sb = self.h_pad target_sb = self.scrollarea.horizontalScrollBar() percent = sb.value() / float(sb.maximum()) target_sb.setValue(int(percent * target_sb.maximum()))
def __init__(self, parent=0, dmd=None, *args, **kwargs): super(CheckListViewWidget, self).__init__( parent=parent, *args, **kwargs) self.parent = parent self.dmd = dmd self.check_list = self.dmd.check_list self.parentWidget().set_window_title("Check-list") row = 0 self.piecesGroupBox = QGroupBox("") # self.piecesGroupBox.setStyleSheet("color: gray; background:#fff") pieces_v_gribox = QGridLayout() css = "font-size:26px;border: 3px solid #000;background: black;color: white;" pieces_v_gribox.addWidget(FHeader( "I. Pièces à vérifier (au dépôt)", css), row, 0, 1, 6) row += 1 self.qualite_declarant_check = self.check_box(QCheckBox()) self.qualite_declarant_check.setChecked( self.check_list.qualite_declarant_check) pieces_v_gribox.addWidget(FRLabel( "Qualité du déclarant (Président, mandataire ou auxiliaire de Justice) "), row, 0) pieces_v_gribox.addWidget(self.qualite_declarant_check, row, 1) # row += 1 self.status_check = self.check_box(QCheckBox("(4)")) self.status_check.setChecked(self.check_list.status_check) pieces_v_gribox.addWidget(FRLabel("Statuts "), row, 2) pieces_v_gribox.addWidget(self.status_check, row, 3) self.pieces_check = self.check_box(QCheckBox("(4)")) self.pieces_check.setChecked(self.check_list.pieces_check) pieces_v_gribox.addWidget( FRLabel("Règlement Intérieur "), row, 4) pieces_v_gribox.addWidget(self.pieces_check, row, 5) row += 1 self.autorisation_pre_immt_check = self.check_box(QCheckBox()) self.autorisation_pre_immt_check.setChecked( self.check_list.autorisation_pre_immt_check) pieces_v_gribox.addWidget(FRLabel( "Autorisations préalables pour les activités réglementées "), row, 0) pieces_v_gribox.addWidget(self.autorisation_pre_immt_check, row, 1) self.demande_immt_check = self.check_box(QCheckBox("(2)")) self.demande_immt_check.setChecked(self.check_list.demande_immt_check) pieces_v_gribox.addWidget( FRLabel("Demande d’Immatriculation "), row, 2) pieces_v_gribox.addWidget(self.demande_immt_check, row, 3) self.pv_check = self.check_box(QCheckBox("(4)")) self.pv_check.setChecked(self.check_list.pv_check) pieces_v_gribox.addWidget(FRLabel("PV "), row, 4) pieces_v_gribox.addWidget(self.pv_check, row, 5) row = 0 pieces_gribox = QGridLayout() self.chronologique_check = self.check_box(QCheckBox()) self.chronologique_check.setChecked( self.check_list.chronologique_check) pieces_gribox.addWidget(FLabel( "Vérifier l’existence du registre des membres tenu par ordre chronologique "), row, 0) pieces_gribox.addWidget(self.chronologique_check, row, 1) pieces_gribox.addWidget(FHeader( "SCOOPS Art 235 et 236 COOP-CA Art 320, 321, 322 et 323", "font-size:15px"), row, 2) row += 1 self.compte_check = self.check_box(QCheckBox()) self.compte_check.setChecked(self.check_list.compte_check) pieces_gribox.addWidget(FLabel( "Vérifier l’existence d’un compte bancaire / Institution de Micro Finance"), row, 0) pieces_gribox.addWidget(self.compte_check, row, 1) pieces_gribox.addWidget(FHeader( "Art 213", "font-size:15px"), row, 2) row += 1 self.dispositions_check = self.check_box(QCheckBox()) self.dispositions_check.setChecked(self.check_list.dispositions_check) pieces_gribox.addWidget(FLabel( "Vérifier le respect des dispositions sur le non cumul des mandats"), row, 0) pieces_gribox.addWidget(self.dispositions_check, row, 1) pieces_gribox.addWidget(FHeader( "Art 300 et 326", "font-size:15px"), row, 2) row += 1 self.pv_delib_ca_check = self.check_box(QCheckBox()) self.pv_delib_ca_check.setChecked(self.check_list.pv_delib_ca_check) pieces_gribox.addWidget(FLabel( "Vérifier l’existence du registre des procès- verbaux de délibération du CA <br/> des COOP-CA coté et paraphé par le tribunal civil compétent"), row, 0) pieces_gribox.addWidget(self.pv_delib_ca_check, row, 1) pieces_gribox.addWidget(FHeader( "Art : 235, (d’ordre général) et COOP-CA 320", "font-size:15px"), row, 2) pieces_gribox.setColumnStretch(row, 2) row = 0 mentions_gribox = QGridLayout() mentions_gribox.addWidget(FHeader( " II. Mentions à vérifier dans les Statuts et le Règlement Intérieur", css), row, 0, 1, 4) row += 1 css = "color:blue;font-size:26px;border: 1px solid #000;background: black;color: white;" mentions_gribox.addWidget(FHeader("Mentions", css=css), row, 0) mentions_gribox.addWidget( FHeader("N° Art des Statuts", css=css), row, 1) mentions_gribox.addWidget(FHeader("N° Art du R.I", css=css), row, 2) mentions_gribox.addWidget( FHeader("Référence OHADA", css=css), row, 3) row += 1 self.forme_scoop_status_field = IntLineEdit(self.rest_d( self.check_list.forme_scoop_status)) self.forme_scoop_ri_field = IntLineEdit(self.rest_d( self.check_list.forme_scoop_ri)) self.add_element(mentions_gribox, row, "<b>01.</b> La forme de la société coopérative", self.forme_scoop_status_field, self.forme_scoop_ri_field, "Art 204 ,215 et 216 Pour la SCOOPS / Art 267 et de 271 à 290 Pour la COOP-CA") row += 1 self.denomination_status_field = IntLineEdit(self.rest_d( self.check_list.denomination_status)) self.denomination_ri_field = IntLineEdit(self.rest_d( self.check_list.denomination_ri)) self.add_element(mentions_gribox, row, "<b>02.</b> Sa dénomination suivie, le cas échéant, de son sigle", self.denomination_status_field, self.denomination_ri_field, "Art 19 et Art 205 Pour la SCOOPS<br/> Art 19 et 205 Pour COOP-CA") row += 1 self.nature_domaine_status_field = IntLineEdit(self.rest_d( self.check_list.nature_domaine_status)) self.nature_domaine_ri_field = IntLineEdit(self.rest_d( self.check_list.nature_domaine_ri)) self.add_element(mentions_gribox, row, "<b>03.</b> La nature et le domaine de son activité et qui forment son objet social", self.nature_domaine_status_field, self.nature_domaine_ri_field, "Art 5, Art 20 et 21 Pour toutes les formes<br/> de Sociétés Coopératives") row += 1 self.duree_status_field = IntLineEdit(self.rest_d( self.check_list.duree_status)) self.duree_ri_field = IntLineEdit(self.rest_d( self.check_list.duree_ri)) self.add_element(mentions_gribox, row, "<b>04.</b> Son siège et sa durée", self.duree_status_field, self.duree_ri_field, "Pour le Siège : Art 22 ,23 et 24 et Pour<br/> la Durée : Art 25, 26, 27et 28") row += 1 self.lien_commun_status_field = IntLineEdit(self.rest_d( self.check_list.lien_commun_status)) self.lien_commun_ri_field = IntLineEdit(self.rest_d( self.check_list.lien_commun_ri)) self.add_element(mentions_gribox, row, "<b>05.</b> Le lien commun qui réunit les membres,", self.lien_commun_status_field, self.lien_commun_ri_field, "Art 8") row += 1 self.coord_initiateur_status_field = IntLineEdit(self.rest_d( self.check_list.coord_initiateur_status)) self.coord_initiateur_ri_field = IntLineEdit(self.rest_d( self.check_list.coord_initiateur_ri)) self.add_element(mentions_gribox, row, "<b>06.</b> Les noms, prénoms et adresse résidentielle de chaque initiateur", self.coord_initiateur_status_field, self.coord_initiateur_ri_field, "Art 87") row += 1 self.max_min_admin_cg_status_field = IntLineEdit(self.rest_d( self.check_list.max_min_admin_cg_status)) self.max_min_admin_cg_ri_field = IntLineEdit(self.rest_d( self.check_list.max_min_admin_cg_ri)) self.add_element(mentions_gribox, row, "<b>07. a.</b> Le nombre précis ou les nombres minimal et maximal de ses administrateurs <br/> ou membres du comité de gestion</p>", self.max_min_admin_cg_status_field, self.max_min_admin_cg_ri_field, "Art 204 et Art 223 Pour la SCOOPS : <br/> (Effectif : 5 Pers au mini : CG=3 au plus si adh de 5 à 99 et CG = 5 si adh de 100 et +.") row += 1 self.max_min_admin_ca_status_field = IntLineEdit(self.rest_d( self.check_list.max_min_admin_ca_status)) self.max_min_admin_ca_ri_field = IntLineEdit(self.rest_d( self.check_list.max_min_admin_ca_ri)) self.add_element(mentions_gribox, row, "<b>07. b.</b> Le nombre précis ou les nombres minimal et maximal de ses <br/> administrateurs ou membres du Conseil d’Administration;", self.max_min_admin_ca_status_field, self.max_min_admin_ca_ri_field, "Art 207 et Art 223 Pour la COOP-CA: (Effectif : 15 Pers au mini : CA=3 au moins et 12 au plus.") row += 1 self.dispositions_cg_status_field = IntLineEdit(self.rest_d( self.check_list.dispositions_cg_status)) self.dispositions_cg_ri_field = IntLineEdit(self.rest_d( self.check_list.dispositions_cg_ri)) self.add_element(mentions_gribox, row, "<b>07. c.</b> Les dispositions portant limitation des pouvoirs des <br/> administrateurs ou membres du comité de gestion", self.dispositions_cg_status_field, self.dispositions_cg_ri_field, "Art 224 à Art 230 Pour la SCOOPS") row += 1 self.dispositions_ca_status_field = IntLineEdit(self.rest_d( self.check_list.dispositions_ca_status)) self.dispositions_ca_ri_field = IntLineEdit(self.rest_d( self.check_list.dispositions_ca_ri)) self.add_element(mentions_gribox, row, "<b>07. d.</b> Les dispositions portant limitation des pouvoirs des administrateurs ou <br/>membres du Conseil d’Administration", self.dispositions_ca_status_field, self.dispositions_ca_ri_field, "Art 296 à Art 307 Pour la COOP-CA et autres pouvoirs de l’Art 314 à l’Art 333") row += 1 self.max_min_cs_s_status_field = IntLineEdit(self.rest_d( self.check_list.max_min_cs_s_status)) self.max_min_cs_s_ri_field = IntLineEdit(self.rest_d( self.check_list.max_min_cs_s_ri)) self.add_element(mentions_gribox, row, "<b>08.</b> Le nombre précis ou les nombres minimal et maximal des membres de la <br/>Commission de Surveillance", self.max_min_cs_s_status_field, self.max_min_cs_s_ri_field, "Art 258 Pour la SCOOPS (de 3 à 5 Pers)") row += 1 self.max_min_cs_ca_status_field = IntLineEdit(self.rest_d( self.check_list.max_min_cs_ca_status)) self.max_min_cs_ca_ri_field = IntLineEdit(self.rest_d( self.check_list.max_min_cs_ca_ri)) self.add_element(mentions_gribox, row, "<b>08. a.</b> Le nombre précis ou les nombres minimal et maximal des membres du <br/>Conseil de Surveillance", self.max_min_cs_ca_status_field, self.max_min_cs_ca_ri_field, "Art 335 Pour la COOP-CA (de 3 à 5 Pers)") row += 1 self.dispositions_mo_status_field = IntLineEdit(self.rest_d( self.check_list.dispositions_mo_status)) self.dispositions_mo_ri_field = IntLineEdit(self.rest_d( self.check_list.dispositions_mo_ri)) self.add_element(mentions_gribox, row, "<b>08. b.</b> Les dispositions relatives à l’exercice efficace des missions de ces organes", self.dispositions_mo_status_field, self.dispositions_mo_ri_field, "Art 263 Pour la SCOOPS /Art 341 Pour la COOP-CA") row += 1 self.mandat_cs_status_field = IntLineEdit(self.rest_d( self.check_list.mandat_cs_status)) self.mandat_cs_ri_field = IntLineEdit(self.rest_d( self.check_list.mandat_cs_ri)) self.add_element(mentions_gribox, row, "<b>09.</b> La durée du mandat des membres du comité de gestion, du conseil d’administration, <br/> du comité de surveillance et du conseil de surveillance", self.mandat_cs_status_field, self.mandat_cs_ri_field, "Art 224 (Réf aux statuts) Pour la SCOOPS /Art 295 Pour la COOP-CA (Réf aux statuts)") row += 1 self.parts_sociales_status_field = IntLineEdit(self.rest_d( self.check_list.parts_sociales_status)) self.parts_sociales_ri_field = IntLineEdit(self.rest_d( self.check_list.parts_sociales_ri)) self.add_element(mentions_gribox, row, "<b>10.</b> Toute limite relative au pourcentage maximal de parts sociales que peut détenir <br/> un seul membre Pour la SCOOPS", self.parts_sociales_status_field, self.parts_sociales_ri_field, "Art 210 Réf aux statuts et ne peut excéder 5 fois <br/> le montant des parts sociales souscrites) Pour la COOP-CA Art 371") row += 1 self.declatation_status_field = IntLineEdit(self.rest_d( self.check_list.declatation_status)) self.declatation_ri_field = IntLineEdit(self.rest_d( self.check_list.declatation_ri)) self.add_element(mentions_gribox, row, "<b>11.</b> Une déclaration précisant que la société coopérative est organisée et exploitée <br/> et exerce ses activités selon les principes coopératifs et le rappel de ces principes", self.declatation_status_field, self.declatation_ri_field, "Art 6") row += 1 self.id_apport_numeraire_status_field = IntLineEdit(self.rest_d( self.check_list.id_apport_numeraire_status)) self.id_apport_numeraire_ri_field = IntLineEdit(self.rest_d( self.check_list.id_apport_numeraire_ri)) self.add_element(mentions_gribox, row, "<b>12.</b> L’identité des apporteurs en numéraires avec pour chacun d’eux le montant des <br/> apports, le nombre et la valeur des parts sociales remis en contrepartie de chaque apport", self.id_apport_numeraire_status_field, self.id_apport_numeraire_ri_field, "Art 30, 31, 32, 33,35, 36,") row += 1 self.id_apport_nature_status_field = IntLineEdit(self.rest_d( self.check_list.id_apport_nature_status)) self.id_apport_nature_ri_field = IntLineEdit(self.rest_d( self.check_list.id_apport_nature_ri)) self.add_element(mentions_gribox, row, "<b>13. a.</b> L’identité des apporteurs en nature", self.id_apport_nature_status_field, self.id_apport_nature_ri_field, "Point 12 de l’Art 18") row += 1 self.evaluation_apport_status_field = IntLineEdit(self.rest_d( self.check_list.evaluation_apport_status)) self.evaluation_apport_ri_field = IntLineEdit(self.rest_d( self.check_list.evaluation_apport_ri)) self.add_element(mentions_gribox, row, "<b>13. b.</b> La nature et l’évaluation de l’apport effectué par chacun d’eux, le nombre et la valeur <br/>des parts sociales remises en contrepartie de chaque apport, Le régime des biens ou valeurs apportés <br/>lorsque leur valeur excède celle des apports exigés ;", self.evaluation_apport_status_field, self.evaluation_apport_ri_field, "Point 13 de l’Art 18") row += 1 self.capital_social_status_field = IntLineEdit(self.rest_d( self.check_list.capital_social_status)) self.capital_social_ri_field = IntLineEdit(self.rest_d( self.check_list.capital_social_ri)) self.add_element(mentions_gribox, row, "<b>14. a.</b> Le montant du capital social, les limitations minimales et maximales y afférentes", self.capital_social_status_field, self.capital_social_ri_field, "Art 53, 57 et 58 en général. Art 207 Pour la SCOOPS et 269 Pour la COOP-CA") row += 1 self.valeur_nominale_status_field = IntLineEdit(self.rest_d( self.check_list.valeur_nominale_status)) self.valeur_nominale_ri_field = IntLineEdit(self.rest_d( self.check_list.valeur_nominale_ri)) self.add_element(mentions_gribox, row, "<b>14. b.</b> La valeur nominale des diverses catégories de parts, les conditions précises de leur émission<br/> ou souscription ;", self.valeur_nominale_status_field, self.valeur_nominale_ri_field, "Art 44 et 45 en général. Pour la COOP-CA Art 376 et 377") row += 1 self.stipulations_status_field = IntLineEdit(self.rest_d( self.check_list.stipulations_status)) self.stipulations_ri_field = IntLineEdit(self.rest_d( self.check_list.stipulations_ri)) self.add_element(mentions_gribox, row, "<b>15.</b> Les stipulations relatives à la répartition du résultat et notamment, des excédents<br/> et des réserves ;", self.stipulations_status_field, self.stipulations_ri_field, "Art 46 alinéa en général. Pour SCOOPS alinéa 2 de l’Art 209 Pour la COOP-CA Art 363 alinéa 4") row += 1 self.modalite_status_field = IntLineEdit(self.rest_d( self.check_list.modalite_status)) self.modalite_ri_field = IntLineEdit(self.rest_d( self.check_list.modalite_ri)) self.add_element(mentions_gribox, row, "<b>16.</b> Les modalités de fonctionnement de la société coopérative ;", self.modalite_status_field, self.modalite_ri_field, "Art 95 à 121 en général .Pour SCOOPS art 217 à 263 Pour la COOP-CA Art 291 à 368") row += 1 self.signature_int_status_field = IntLineEdit(self.rest_d( self.check_list.signature_int_status)) self.signature_int_ri_field = IntLineEdit(self.rest_d( self.check_list.signature_int_ri)) self.add_element(mentions_gribox, row, "<b>17.</b> La signature des initiateurs ou l’apposition de leur empreinte digitale", self.signature_int_status_field, self.signature_int_ri_field, "Point 17 de l’Art 18") row += 1 self.etendue_status_field = IntLineEdit(self.rest_d( self.check_list.etendue_status)) self.etendue_ri_field = IntLineEdit(self.rest_d( self.check_list.etendue_ri)) self.add_element(mentions_gribox, row, "<b>18.</b> L’étendue des transactions avec les usagers non coopérateurs, tout en ayant en vue<br/>la sauvegarde de l’autonomie de la société coopérative ;", self.etendue_status_field, self.etendue_ri_field, "Art 4 al. 2") row += 1 qss = "padding:5px;padding-left:25px;padding-right:25px;background: gray;font-size:30px;color:#fff" mentions_gribox.addWidget(FHeader( "Les mentions facultatives", qss), row, 0, 1, 4) row += 1 self.rendement_status_field = IntLineEdit(self.rest_d( self.check_list.rendement_status)) self.rendement_ri_field = IntLineEdit(self.rest_d( self.check_list.rendement_ri)) self.add_element(mentions_gribox, row, "<b>1. a.</b> Le taux de rendement maximal qui peut être appliqué aux prêts et aux épargnes des membres", self.rendement_status_field, self.rendement_ri_field, "Art 18. 1bis alinéa 1") row += 1 self.remuneration_status_field = IntLineEdit(self.rest_d( self.check_list.remuneration_status)) self.remuneration_ri_field = IntLineEdit(self.rest_d( self.check_list.remuneration_ri)) self.add_element(mentions_gribox, row, "<b>1. b.</b> Le taux de rémunération maximale qui peut être appliqué aux parts de membres ;", self.remuneration_status_field, self.remuneration_ri_field, "Art 239 ; 240 alinéa4 et 231(Art 18. 1bis alinéa 1)") row += 1 self.limite_imposee_status_field = IntLineEdit(self.rest_d( self.check_list.limite_imposee_status)) self.limite_imposee_ri_field = IntLineEdit(self.rest_d( self.check_list.limite_imposee_ri)) self.add_element(mentions_gribox, row, "<b>2.</b> Toute limite imposée aux activités commerciales de la société coopérative.", self.limite_imposee_status_field, self.limite_imposee_ri_field, "COOP–CA Art 313,SCOOPS Art 258 et 259") row += 1 mentions_gribox.addWidget(FHeader( "Règlement Intérieur, outre les mentions obligatoires des statuts, le règlement intérieur contient les prescriptions suivantes :", qss), row, 0, 1, 4) row += 1 self.indemnit_status_field = IntLineEdit(self.rest_d( self.check_list.indemnit_status)) self.indemnit_ri_field = IntLineEdit(self.rest_d( self.check_list.indemnit_ri)) self.add_element(mentions_gribox, row, "<b>1.</b> Les conditions de paiement d’indemnités aux membres du conseil d’administration ou du comité<br/> de gestion, du conseil ou du comité de surveillance, définies dans le respect des dispositions<br/> des articles 225 et 305 ;", self.indemnit_status_field, self.indemnit_ri_field, "Scoops : Art 225; Scoop-CA : Art 305") row += 1 self.souscription_status_field = IntLineEdit(self.rest_d( self.check_list.souscription_status)) self.souscription_ri_field = IntLineEdit(self.rest_d( self.check_list.souscription_ri)) self.add_element(mentions_gribox, row, "<b>2.</b> La souscription de parts sociales supplémentaires et leur nombre par coopérateur ;", self.souscription_status_field, self.souscription_ri_field, "Pour la SCOOPS Art 210 Réf aux statuts et ne peut excéder <br/>5 fois le montant des parts sociales souscrites) Pour la COOP-CA Art 371") row += 1 self.suspension_status_field = IntLineEdit(self.rest_d( self.check_list.suspension_status)) self.suspension_ri_field = IntLineEdit(self.rest_d( self.check_list.suspension_ri)) self.add_element(mentions_gribox, row, "<b>3.</b> Les critères et conditions de suspension des coopérateurs;", self.suspension_status_field, self.suspension_ri_field, "Statut (initiateurs)") row += 1 self.attribution_status_field = IntLineEdit(self.rest_d( self.check_list.attribution_status)) self.attribution_ri_field = IntLineEdit(self.rest_d( self.check_list.attribution_ri)) self.add_element(mentions_gribox, row, "<b>4.</b> La possibilité d’attribution d’un droit de vote plural dans le cas des unions, des fédérations et<br/>des confédérations ;", self.attribution_status_field, self.attribution_ri_field, "Art 138") row += 1 self.prescriptions_status_field = IntLineEdit(self.rest_d( self.check_list.prescriptions_status)) self.prescriptions_ri_field = IntLineEdit(self.rest_d( self.check_list.prescriptions_ri)) self.add_element(mentions_gribox, row, "<b>5.</b> Toutes autres prescriptions jugées nécessaires pour la réalisation de l’objet de la société <br/>coopérative et conformes aux principes coopératifs et aux dispositions impératives du présent<br/> Acte uniforme.", self.prescriptions_status_field, self.prescriptions_ri_field, "AUSCOOP") vbox = QVBoxLayout() vbox.addLayout(pieces_v_gribox) vbox.addLayout(pieces_gribox) vbox.addLayout(mentions_gribox) self.piecesGroupBox.setLayout(vbox) # Durée statutaire de la société coopérative duree_fbox = QFormLayout() self.butt_continous = Button_save(u"Continuer") self.butt_continous.clicked.connect(self.goto_immatriculation) self.butt_continous.setMaximumWidth(200) duree_fbox.addRow("", self.butt_continous) if not self.check_integrity_validation(): self.butt_continous.setEnabled(False) scroll = QScrollArea(self) scroll.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOn) scroll.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOn) scroll.setWidgetResizable(True) # scroll.setFixedHeight(200) vbox = QVBoxLayout() vbox.addWidget(FHeader( "<h2>Check-list de Contrôle de dossiers des sociétés coopératives avant l’immatriculation et l’enregistrement par le SLDS-ES</h2>", css="color:green")) vbox.addWidget(FHeader( "<h4>Société Coopérative : {} </h4>".format(self.dmd.scoop))) scroll.setWidget(self.piecesGroupBox) vbox.addWidget(scroll) vbox.addLayout(duree_fbox) self.setLayout(vbox)
class SectionsContainerWidget(QWidget): def __init__(self, parent=None, isLinacSection=True, sectionClass=None): QWidget.__init__(self, parent) self.isLinacSection = isLinacSection self.sectionClass = sectionClass self.setParent(parent) self.sectionWidgets = list() self.setMinimumWidth(460) self.setMinimumHeight(600) self.sumSize = 0 self.setupLayout() self.setupScrollArea() self.addSectionButton = QPushButton(self.containerWidget) self.addSectionButton.setText("Add new section") self.layout.addWidget(self.addSectionButton) self.connect(self.addSectionButton, QtCore.SIGNAL("clicked()"), self.addNewSection) def setupLayout(self): self.containerWidget = QWidget(self) self.widgetHeight = 120 self.containerWidget.setGeometry(QRect(0, 0, 460, self.widgetHeight)) self.layout = QVBoxLayout() self.containerWidget.setLayout(self.layout) def setupScrollArea(self): self.scrollArea = QScrollArea(self) self.scrollArea.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAsNeeded) self.scrollArea.setHorizontalScrollBarPolicy( QtCore.Qt.ScrollBarAlwaysOff) self.scrollArea.setMaximumWidth(460) self.scrollArea.setMinimumHeight(600) self.scrollArea.setWidgetResizable(False) self.scrollArea.setWidget(self.containerWidget) def addNewSection(self): newSection = self.sectionClass(self.containerWidget) widgetPosition = len(self.sectionWidgets) self.layout.insertWidget(widgetPosition, newSection) self.sectionWidgets.append(newSection) self.setDefaultValues(newSection) self.widgetHeight += 80 self.containerWidget.resize(460, self.widgetHeight) self.connect(newSection, QtCore.SIGNAL("remove()"), self.removeSection) self.connect(newSection, QtCore.SIGNAL("sizeValueChanged(QWidget*)"), self.updateSumOfSize) def setDefaultValues(self, section): pass # section.colorLabel.setColor(SettingsCloud.getParameter("subsectionColor")) # self.setSectionSize(section) def setSectionSize(self, section): pass # def setSubsectionSize(self, section): # if self.isLinacSection: # defaultSize = SettingsCloud.getParameter("linacSubsectionSize") # else: # defaultSize = SettingsCloud.getParameter("ringSubsectionSize") # section.sizeEdit.setValue(defaultSize) # self.updateSumOfSize(section) def updateSumOfSize(self, sectionWidget): self.sumSize = 0 for section in self.sectionWidgets: self.sumSize += section.getSize() if self.sumSize > 100: diff = self.sumSize - 100.0 actualSize = sectionWidget.getSize() sectionWidget.setSize(actualSize - diff) def removeSection(self): messageBox = QMessageBox(self) userReply = messageBox.question(self, "Are you sure?", "Do you want to remove this section?", QMessageBox.Yes | QMessageBox.No) if userReply == QMessageBox.Yes: sender = self.sender() self.layout.removeWidget(sender) self.sectionWidgets.remove(sender) sender.setVisible(False) self.widgetHeight -= 80 self.containerWidget.resize(460, self.widgetHeight) def getNumberOfSections(self): return len(self.sectionWidgets) def getSections(self): return self.sectionWidgets def getSectionsData(self): subsectionsData = list() for subsection in self.sectionWidgets: subsectionsData.append(subsection.getSectionData()) return subsectionsData
class SectionsContainerWidget(QWidget): def __init__(self, parent=None, isLinacSection=True, sectionClass=None): QWidget.__init__(self, parent) self.isLinacSection = isLinacSection self.sectionClass = sectionClass self.setParent(parent) self.sectionWidgets = list() self.setMinimumWidth(460) self.setMinimumHeight(600) self.sumSize = 0 self.setupLayout() self.setupScrollArea() self.addSectionButton = QPushButton(self.containerWidget) self.addSectionButton.setText("Add new section") self.layout.addWidget(self.addSectionButton) self.connect(self.addSectionButton, QtCore.SIGNAL("clicked()"), self.addNewSection) def setupLayout(self): self.containerWidget = QWidget(self) self.widgetHeight = 120 self.containerWidget.setGeometry(QRect(0,0,460,self.widgetHeight)) self.layout = QVBoxLayout() self.containerWidget.setLayout(self.layout) def setupScrollArea(self): self.scrollArea = QScrollArea(self) self.scrollArea.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAsNeeded) self.scrollArea.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff) self.scrollArea.setMaximumWidth(460) self.scrollArea.setMinimumHeight(600) self.scrollArea.setWidgetResizable(False) self.scrollArea.setWidget(self.containerWidget) def addNewSection(self): newSection = self.sectionClass(self.containerWidget) widgetPosition = len(self.sectionWidgets) self.layout.insertWidget(widgetPosition, newSection) self.sectionWidgets.append(newSection) self.setDefaultValues(newSection) self.widgetHeight += 80 self.containerWidget.resize(460,self.widgetHeight) self.connect(newSection, QtCore.SIGNAL("remove()"), self.removeSection) self.connect(newSection, QtCore.SIGNAL("sizeValueChanged(QWidget*)"), self.updateSumOfSize) def setDefaultValues(self, section): pass # section.colorLabel.setColor(SettingsCloud.getParameter("subsectionColor")) # self.setSectionSize(section) def setSectionSize(self, section): pass # def setSubsectionSize(self, section): # if self.isLinacSection: # defaultSize = SettingsCloud.getParameter("linacSubsectionSize") # else: # defaultSize = SettingsCloud.getParameter("ringSubsectionSize") # section.sizeEdit.setValue(defaultSize) # self.updateSumOfSize(section) def updateSumOfSize(self, sectionWidget): self.sumSize = 0 for section in self.sectionWidgets: self.sumSize += section.getSize() if self.sumSize > 100: diff = self.sumSize - 100.0 actualSize = sectionWidget.getSize() sectionWidget.setSize(actualSize - diff) def removeSection(self): messageBox = QMessageBox(self) userReply = messageBox.question(self, "Are you sure?", "Do you want to remove this section?", QMessageBox.Yes|QMessageBox.No) if userReply == QMessageBox.Yes: sender = self.sender() self.layout.removeWidget(sender) self.sectionWidgets.remove(sender) sender.setVisible(False) self.widgetHeight -= 80 self.containerWidget.resize(460,self.widgetHeight) def getNumberOfSections(self): return len(self.sectionWidgets) def getSections(self): return self.sectionWidgets def getSectionsData(self): subsectionsData = list() for subsection in self.sectionWidgets: subsectionsData.append(subsection.getSectionData()) return subsectionsData
class XPopupWidget(QWidget): """ """ Direction = enum('North', 'South', 'East', 'West') Mode = enum('Popup', 'Dialog', 'ToolTip') Anchor = enum('TopLeft', 'TopCenter', 'TopRight', 'LeftTop', 'LeftCenter', 'LeftBottom', 'RightTop', 'RightCenter', 'RightBottom', 'BottomLeft', 'BottomCenter', 'BottomRight') aboutToShow = qt.Signal() accepted = qt.Signal() closed = qt.Signal() rejected = qt.Signal() resetRequested = qt.Signal() shown = qt.Signal() buttonClicked = qt.Signal(QAbstractButton) def __init__(self, parent=None, buttons=None): super(XPopupWidget, self).__init__(parent) # define custom properties self._anchor = XPopupWidget.Anchor.TopCenter self._autoCalculateAnchor = False self._autoCloseOnAccept = True self._autoCloseOnReject = True self._autoCloseOnFocusOut = False self._autoDefault = True self._first = True self._animated = False self._currentMode = None self._positionLinkedTo = [] # define controls self._resizable = True self._popupPadding = 10 self._titleBarVisible = True self._buttonBoxVisible = True self._dialogButton = QToolButton(self) self._closeButton = QToolButton(self) self._scrollArea = QScrollArea(self) self._sizeGrip = QSizeGrip(self) self._sizeGrip.setFixedWidth(12) self._sizeGrip.setFixedHeight(12) self._leftSizeGrip = QSizeGrip(self) self._leftSizeGrip.setFixedWidth(12) self._leftSizeGrip.setFixedHeight(12) if buttons is None: buttons = QDialogButtonBox.NoButton self._buttonBox = QDialogButtonBox(buttons, Qt.Horizontal, self) self._buttonBox.setContentsMargins(3, 0, 3, 9) self._scrollArea.setWidgetResizable(True) self._scrollArea.setFrameShape(QScrollArea.NoFrame) self._scrollArea.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) palette = self.palette() self._scrollArea.setPalette(palette) self._dialogButton.setToolTip('Popout to Dialog') self._closeButton.setToolTip('Close Popup') for btn in (self._dialogButton, self._closeButton): btn.setAutoRaise(True) btn.setIconSize(QSize(14, 14)) btn.setMaximumSize(16, 16) # setup the icons icon = QIcon(projexui.resources.find('img/dialog.png')) self._dialogButton.setIcon(icon) icon = QIcon(projexui.resources.find('img/close.png')) self._closeButton.setIcon(icon) # define the ui hlayout = QHBoxLayout() hlayout.setSpacing(0) hlayout.addStretch(1) hlayout.addWidget(self._dialogButton) hlayout.addWidget(self._closeButton) hlayout.setContentsMargins(0, 0, 0, 0) hlayout2 = QHBoxLayout() hlayout2.addWidget(self._buttonBox) hlayout2.setContentsMargins(0, 0, 3, 0) vlayout = QVBoxLayout() vlayout.addLayout(hlayout) vlayout.addWidget(self._scrollArea) vlayout.addLayout(hlayout2) vlayout.setContentsMargins(3, 2, 3, 2) vlayout.setSpacing(0) self.setLayout(vlayout) self.setPositionLinkedTo(parent) # set default properties self.setAutoFillBackground(True) self.setBackgroundRole(QPalette.Button) self.setWindowTitle('Popup') self.setFocusPolicy(Qt.StrongFocus) self.setCurrentMode(XPopupWidget.Mode.Popup) # create connections self._dialogButton.clicked.connect(self.setDialogMode) self._closeButton.clicked.connect(self.reject) self._buttonBox.accepted.connect(self.accept) self._buttonBox.rejected.connect(self.reject) self._buttonBox.clicked.connect(self.handleButtonClick) def addButton(self, button, role=QDialogButtonBox.ActionRole): """ Adds a custom button to the button box for this popup widget. :param button | <QAbstractButton> || <str> :return <button> || None (based on if a button or string was given) """ return self._buttonBox.addButton(button, role) def adjustContentsMargins( self ): """ Adjusts the contents for this widget based on the anchor and \ mode. """ anchor = self.anchor() mode = self.currentMode() # margins for a dialog if ( mode == XPopupWidget.Mode.Dialog ): self.setContentsMargins(0, 0, 0, 0) # margins for a top anchor point elif ( anchor & (XPopupWidget.Anchor.TopLeft | XPopupWidget.Anchor.TopCenter | XPopupWidget.Anchor.TopRight) ): self.setContentsMargins(0, self.popupPadding() + 5, 0, 0) # margins for a bottom anchor point elif ( anchor & (XPopupWidget.Anchor.BottomLeft | XPopupWidget.Anchor.BottomCenter | XPopupWidget.Anchor.BottomRight) ): self.setContentsMargins(0, 0, 0, self.popupPadding()) # margins for a left anchor point elif ( anchor & (XPopupWidget.Anchor.LeftTop | XPopupWidget.Anchor.LeftCenter | XPopupWidget.Anchor.LeftBottom) ): self.setContentsMargins(self.popupPadding(), 0, 0, 0) # margins for a right anchor point else: self.setContentsMargins(0, 0, self.popupPadding(), 0) self.adjustMask() def adjustMask(self): """ Updates the alpha mask for this popup widget. """ if self.currentMode() == XPopupWidget.Mode.Dialog: self.clearMask() return path = self.borderPath() bitmap = QBitmap(self.width(), self.height()) bitmap.fill(QColor('white')) painter = QPainter() painter.begin(bitmap) painter.setRenderHint(QPainter.Antialiasing) pen = QPen(QColor('black')) pen.setWidthF(0.75) painter.setPen(pen) painter.setBrush(QColor('black')) painter.drawPath(path) painter.end() self.setMask(bitmap) def adjustSize(self): """ Adjusts the size of this popup to best fit the new widget size. """ widget = self.centralWidget() if widget is None: super(XPopupWidget, self).adjustSize() return widget.adjustSize() hint = widget.minimumSizeHint() size = widget.minimumSize() width = max(size.width(), hint.width()) height = max(size.height(), hint.height()) width += 20 height += 20 if self._buttonBoxVisible: height += self.buttonBox().height() + 10 if self._titleBarVisible: height += max(self._dialogButton.height(), self._closeButton.height()) + 10 curr_w = self.width() curr_h = self.height() # determine if we need to move based on our anchor anchor = self.anchor() if anchor & (self.Anchor.LeftBottom | self.Anchor.RightBottom | \ self.Anchor.BottomLeft | self.Anchor.BottomCenter | \ self.Anchor.BottomRight): delta_y = height - curr_h elif anchor & (self.Anchor.LeftCenter | self.Anchor.RightCenter): delta_y = (height - curr_h) / 2 else: delta_y = 0 if anchor & (self.Anchor.RightTop | self.Anchor.RightCenter | \ self.Anchor.RightTop | self.Anchor.TopRight): delta_x = width - curr_w elif anchor & (self.Anchor.TopCenter | self.Anchor.BottomCenter): delta_x = (width - curr_w) / 2 else: delta_x = 0 self.setMinimumSize(width, height) self.resize(width, height) pos = self.pos() pos.setX(pos.x() - delta_x) pos.setY(pos.y() - delta_y) self.move(pos) @qt.Slot() def accept(self): """ Emits the accepted signal and closes the popup. """ if not self.signalsBlocked(): self.accepted.emit() if self.autoCloseOnAccept(): self.close() def anchor( self ): """ Returns the anchor point for this popup widget. :return <XPopupWidget.Anchor> """ return self._anchor def autoCalculateAnchor( self ): """ Returns whether or not this popup should calculate the anchor point on popup based on the parent widget and the popup point. :return <bool> """ return self._autoCalculateAnchor def autoCloseOnAccept( self ): """ Returns whether or not this popup widget manages its own close on accept behavior. :return <bool> """ return self._autoCloseOnAccept def autoCloseOnReject( self ): """ Returns whether or not this popup widget manages its own close on reject behavior. :return <bool> """ return self._autoCloseOnReject def autoCloseOnFocusOut(self): """ Returns whether or not this popup widget should auto-close when the user clicks off the view. :return <bool> """ return self._autoCloseOnFocusOut def autoDefault(self): """ Returns whether or not clicking enter should default to the accept key. :return <bool> """ return self._autoDefault def borderPath(self): """ Returns the border path that will be drawn for this widget. :return <QPainterPath> """ path = QPainterPath() x = 1 y = 1 w = self.width() - 2 h = self.height() - 2 pad = self.popupPadding() anchor = self.anchor() # create a path for a top-center based popup if anchor == XPopupWidget.Anchor.TopCenter: path.moveTo(x, y + pad) path.lineTo(x + ((w/2) - pad), y + pad) path.lineTo(x + (w/2), y) path.lineTo(x + ((w/2) + pad), y + pad) path.lineTo(x + w, y + pad) path.lineTo(x + w, y + h) path.lineTo(x, y + h) path.lineTo(x, y + pad) # create a path for a top-left based popup elif anchor == XPopupWidget.Anchor.TopLeft: path.moveTo(x, y + pad) path.lineTo(x + pad, y) path.lineTo(x + 2 * pad, y + pad) path.lineTo(x + w, y + pad) path.lineTo(x + w, y + h) path.lineTo(x, y + h) path.lineTo(x, y + pad) # create a path for a top-right based popup elif anchor == XPopupWidget.Anchor.TopRight: path.moveTo(x, y + pad) path.lineTo(x + w - 2 * pad, y + pad) path.lineTo(x + w - pad, y) path.lineTo(x + w, y + pad) path.lineTo(x + w, y + h) path.lineTo(x, y + h) path.lineTo(x, y + pad) # create a path for a bottom-left based popup elif anchor == XPopupWidget.Anchor.BottomLeft: path.moveTo(x, y) path.lineTo(x + w, y) path.lineTo(x + w, y + h - pad) path.lineTo(x + 2 * pad, y + h - pad) path.lineTo(x + pad, y + h) path.lineTo(x, y + h - pad) path.lineTo(x, y) # create a path for a south based popup elif anchor == XPopupWidget.Anchor.BottomCenter: path.moveTo(x, y) path.lineTo(x + w, y) path.lineTo(x + w, y + h - pad) path.lineTo(x + ((w/2) + pad), y + h - pad) path.lineTo(x + (w/2), y + h) path.lineTo(x + ((w/2) - pad), y + h - pad) path.lineTo(x, y + h - pad) path.lineTo(x, y) # create a path for a bottom-right based popup elif anchor == XPopupWidget.Anchor.BottomRight: path.moveTo(x, y) path.lineTo(x + w, y) path.lineTo(x + w, y + h - pad) path.lineTo(x + w - pad, y + h) path.lineTo(x + w - 2 * pad, y + h - pad) path.lineTo(x, y + h - pad) path.lineTo(x, y) # create a path for a right-top based popup elif anchor == XPopupWidget.Anchor.RightTop: path.moveTo(x, y) path.lineTo(x + w - pad, y) path.lineTo(x + w, y + pad) path.lineTo(x + w - pad, y + 2 * pad) path.lineTo(x + w - pad, y + h) path.lineTo(x, y + h) path.lineTo(x, y) # create a path for a right-center based popup elif anchor == XPopupWidget.Anchor.RightCenter: path.moveTo(x, y) path.lineTo(x + w - pad, y) path.lineTo(x + w - pad, y + ((h/2) - pad)) path.lineTo(x + w, y + (h/2)) path.lineTo(x + w - pad, y + ((h/2) + pad)) path.lineTo(x + w - pad, y + h) path.lineTo(x, y + h) path.lineTo(x, y) # create a path for a right-bottom based popup elif anchor == XPopupWidget.Anchor.RightBottom: path.moveTo(x, y) path.lineTo(x + w - pad, y) path.lineTo(x + w - pad, y + h - 2 * pad) path.lineTo(x + w, y + h - pad) path.lineTo(x + w - pad, y + h) path.lineTo(x, y + h) path.lineTo(x, y) # create a path for a left-top based popup elif anchor == XPopupWidget.Anchor.LeftTop: path.moveTo(x + pad, y) path.lineTo(x + w, y) path.lineTo(x + w, y + h) path.lineTo(x + pad, y + h) path.lineTo(x + pad, y + 2 * pad) path.lineTo(x, y + pad) path.lineTo(x + pad, y) # create a path for an left-center based popup elif anchor == XPopupWidget.Anchor.LeftCenter: path.moveTo(x + pad, y) path.lineTo(x + w, y) path.lineTo(x + w, y + h) path.lineTo(x + pad, y + h) path.lineTo(x + pad, y + ((h/2) + pad)) path.lineTo(x, y + (h/2)) path.lineTo(x + pad, y + ((h/2) - pad)) path.lineTo(x + pad, y) # create a path for a left-bottom based popup elif anchor == XPopupWidget.Anchor.LeftBottom: path.moveTo(x + pad, y) path.lineTo(x + w, y) path.lineTo(x + w, y + h) path.lineTo(x + pad, y + h) path.lineTo(x, y + h - pad) path.lineTo(x + pad, y + h - 2 * pad) path.lineTo(x + pad, y) return path def buttonBox( self ): """ Returns the button box that is used to control this popup widget. :return <QDialogButtonBox> """ return self._buttonBox def centralWidget( self ): """ Returns the central widget that is being used by this popup. :return <QWidget> """ return self._scrollArea.widget() def close(self): """ Closes the popup widget and central widget. """ widget = self.centralWidget() if widget and not widget.close(): return super(XPopupWidget, self).close() def closeEvent(self, event): widget = self.centralWidget() if widget and not widget.close() and \ self.currentMode() != XPopupWidget.Mode.ToolTip: event.ignore() else: super(XPopupWidget, self).closeEvent(event) self.closed.emit() def currentMode( self ): """ Returns the current mode for this widget. :return <XPopupWidget.Mode> """ return self._currentMode @deprecatedmethod('XPopupWidget', 'Direction is no longer used, use anchor instead') def direction( self ): """ Returns the current direction parameter for this widget. :return <XPopupWidget.Direction> """ anchor = self.anchor() if ( anchor & (XPopupWidget.Anchor.TopLeft | XPopupWidget.Anchor.TopCenter | XPopupWidget.Anchor.TopRight) ): return XPopupWidget.Direction.North elif ( anchor & (XPopupWidget.Anchor.BottomLeft | XPopupWidget.Anchor.BottomCenter | XPopupWidget.Anchor.BottomRight) ): return XPopupWidget.Direction.South elif ( anchor & (XPopupWidget.Anchor.LeftTop | XPopupWidget.Anchor.LeftCenter | XPopupWidget.Anchor.LeftBottom) ): return XPopupWidget.Direction.East else: return XPopupWidget.Direction.West def eventFilter(self, object, event): """ Processes when the window is moving to update the position for the popup if in popup mode. :param object | <QObject> event | <QEvent> """ links = self.positionLinkedTo() is_dialog = self.currentMode() == self.Mode.Dialog if object not in links: return False if event.type() == event.Close: self.close() return False if event.type() == event.Hide and not is_dialog: self.hide() return False if event.type() == event.Move and not is_dialog: deltaPos = event.pos() - event.oldPos() self.move(self.pos() + deltaPos) return False if self.currentMode() != self.Mode.ToolTip: return False if event.type() == event.Leave: pos = object.mapFromGlobal(QCursor.pos()) if (not object.rect().contains(pos)): self.close() event.accept() return True if event.type() in (event.MouseButtonPress, event.MouseButtonDblClick): self.close() event.accept() return True return False @qt.Slot(QAbstractButton) def handleButtonClick(self, button): """ Handles the button click for this widget. If the Reset button was clicked, then the resetRequested signal will be emitted. All buttons will emit the buttonClicked signal. :param button | <QAbstractButton> """ if ( self.signalsBlocked() ): return if ( button == self._buttonBox.button(QDialogButtonBox.Reset) ): self.resetRequested.emit() self.buttonClicked.emit(button) def isAnimated(self): """ Returns whether or not the popup widget should animate its opacity when it is shown. :return <bool> """ return self._animated def isResizable(self): """ Returns if this popup is resizable or not. :return <bool> """ return self._resizable def keyPressEvent( self, event ): """ Looks for the Esc key to close the popup. :param event | <QKeyEvent> """ if ( event.key() == Qt.Key_Escape ): self.reject() event.accept() return elif ( event.key() in (Qt.Key_Return, Qt.Key_Enter) ): if self._autoDefault: self.accept() event.accept() return super(XPopupWidget, self).keyPressEvent(event) def mapAnchorFrom( self, widget, globalPos ): """ Returns the anchor point that best fits within the given widget from the inputed global position. :param widget | <QWidget> globalPos | <QPoint> :return <XPopupWidget.Anchor> """ localPos = widget.mapFromGlobal(globalPos) x = localPos.x() y = localPos.y() w = widget.width() h = widget.height() cw = self.width() / 2 ch = self.height() / 2 # by default, try to do a center point, so make sure the center point # is at least 1/2 the width longer from each edge if x < cw and h - y < ch: return XPopupWidget.Anchor.BottomLeft elif x < cw: return XPopupWidget.Anchor.TopLeft elif w - x < cw and h - y < ch: return XPopupWidget.Anchor.BottomRight elif w - x < cw: return XPopupWidget.Anchor.TopRight elif h - y < ch: return XPopupWidget.Anchor.BottomCenter else: return XPopupWidget.Anchor.TopCenter def popup(self, pos=None): """ Pops up this widget at the inputed position. The inputed point should \ be in global space. :param pos | <QPoint> :return <bool> success """ if self._first and self.centralWidget() is not None: self.adjustSize() self._first = False if not self.signalsBlocked(): self.aboutToShow.emit() if not pos: pos = QCursor.pos() if self.currentMode() == XPopupWidget.Mode.Dialog and \ self.isVisible(): return False elif self.currentMode() == XPopupWidget.Mode.Dialog: self.setPopupMode() # auto-calculate the point if self.autoCalculateAnchor(): self.setAnchor(self.mapAnchorFrom( self.parent(), pos )) pad = self.popupPadding() # determine where to move based on the anchor anchor = self.anchor() # MODIFY X POSITION # align x-left if ( anchor & (XPopupWidget.Anchor.TopLeft | XPopupWidget.Anchor.BottomLeft) ): pos.setX(pos.x() - pad) # align x-center elif ( anchor & (XPopupWidget.Anchor.TopCenter | XPopupWidget.Anchor.BottomCenter) ): pos.setX(pos.x() - self.width() / 2) # align x-right elif ( anchor & (XPopupWidget.Anchor.TopRight | XPopupWidget.Anchor.BottomRight) ): pos.setX(pos.x() - self.width() + pad) # align x-padded elif ( anchor & (XPopupWidget.Anchor.RightTop | XPopupWidget.Anchor.RightCenter | XPopupWidget.Anchor.RightBottom) ): pos.setX(pos.x() - self.width()) # MODIFY Y POSITION # align y-top if ( anchor & (XPopupWidget.Anchor.LeftTop | XPopupWidget.Anchor.RightTop) ): pos.setY(pos.y() - pad) # align y-center elif ( anchor & (XPopupWidget.Anchor.LeftCenter | XPopupWidget.Anchor.RightCenter) ): pos.setY(pos.y() - self.height() / 2) # align y-bottom elif ( anchor & (XPopupWidget.Anchor.LeftBottom | XPopupWidget.Anchor.RightBottom) ): pos.setY(pos.y() - self.height() + pad) # align y-padded elif ( anchor & (XPopupWidget.Anchor.BottomLeft | XPopupWidget.Anchor.BottomCenter | XPopupWidget.Anchor.BottomRight) ): pos.setY(pos.y() - self.height()) self.adjustMask() self.move(pos) self.update() self.setUpdatesEnabled(True) if self.isAnimated(): anim = QPropertyAnimation(self, 'windowOpacity') anim.setParent(self) anim.setStartValue(0.0) anim.setEndValue(self.windowOpacity()) anim.setDuration(500) anim.finished.connect(anim.deleteLater) self.setWindowOpacity(0.0) else: anim = None self.show() if self.currentMode() != XPopupWidget.Mode.ToolTip: self.activateWindow() widget = self.centralWidget() if widget: self.centralWidget().setFocus() if anim: anim.start() if not self.signalsBlocked(): self.shown.emit() return True def paintEvent(self, event): """ Overloads the paint event to handle painting pointers for the popup \ mode. :param event | <QPaintEvent> """ # use the base technique for the dialog mode if self.currentMode() == XPopupWidget.Mode.Dialog: super(XPopupWidget, self).paintEvent(event) return # setup the coloring options palette = self.palette() painter = QPainter() painter.begin(self) pen = QPen(palette.color(palette.Window).darker(130)) pen.setWidthF(1.75) painter.setPen(pen) painter.setRenderHint(painter.Antialiasing) painter.setBrush(palette.color(palette.Window)) painter.drawPath(self.borderPath()) painter.end() def popupPadding(self): """ Returns the amount of pixels to pad the popup arrow for this widget. :return <int> """ return self._popupPadding def positionLinkedTo(self): """ Returns the widget that this popup is linked to for positional changes. :return [<QWidget>, ..] """ return self._positionLinkedTo @qt.Slot() def reject(self): """ Emits the accepted signal and closes the popup. """ if not self.signalsBlocked(): self.rejected.emit() if self.autoCloseOnReject(): self.close() def resizeEvent(self, event): """ Resizes this widget and updates the mask. :param event | <QResizeEvent> """ self.setUpdatesEnabled(False) super(XPopupWidget, self).resizeEvent(event) self.adjustMask() self.setUpdatesEnabled(True) x = self.width() - self._sizeGrip.width() y = self.height() - self._sizeGrip.height() self._leftSizeGrip.move(0, y) self._sizeGrip.move(x, y) def scrollArea(self): """ Returns the scroll area widget for this popup. :return <QScrollArea> """ return self._scrollArea def setAnimated(self, state): """ Sets whether or not the popup widget should animate its opacity when it is shown. :param state | <bool> """ self._animated = state self.setAttribute(Qt.WA_TranslucentBackground, state) def setAutoCloseOnAccept( self, state ): """ Sets whether or not the popup handles closing for accepting states. :param state | <bool> """ self._autoCloseOnAccept = state def setAutoCloseOnReject( self, state ): """ Sets whether or not the popup handles closing for rejecting states. :param state | <bool> """ self._autoCloseOnReject = state def setAutoDefault(self, state): """ Sets whether or not the buttons should respond to defaulting options when the user is interacting with it. :param state | <bool> """ self._autoDefault = state for button in self.buttonBox().buttons(): button.setAutoDefault(state) button.setDefault(state) def setAnchor( self, anchor ): """ Sets the anchor position for this popup widget to the inputed point. :param anchor | <XPopupWidget.Anchor> """ self._anchor = anchor self.adjustContentsMargins() def setAutoCalculateAnchor( self, state ): """ Sets whether or not this widget should auto-calculate the anchor point based on the parent position when the popup is triggered. :param state | <bool> """ self._autoCalculateAnchor = state def setAutoCloseOnFocusOut(self, state): """ Sets whether or not this popup widget should auto-close when the user clicks off the view. :param state | <bool> """ self._autoCloseOnFocusOut = state self.updateModeSettings() def setCentralWidget( self, widget ): """ Sets the central widget that will be used by this popup. :param widget | <QWidget> || None """ self._scrollArea.takeWidget() self._scrollArea.setWidget(widget) self.adjustSize() def setCurrentMode( self, mode ): """ Sets the current mode for this dialog to the inputed mode. :param mode | <XPopupWidget.Mode> """ if ( self._currentMode == mode ): return self._currentMode = mode self.updateModeSettings() @qt.Slot() def setDialogMode(self): """ Sets the current mode value to Dialog. """ self.setCurrentMode(XPopupWidget.Mode.Dialog) @deprecatedmethod('XPopupWidget', 'Direction is no longer used, use setAnchor instead') def setDirection( self, direction ): """ Sets the direction for this widget to the inputed direction. :param direction | <XPopupWidget.Direction> """ if ( direction == XPopupWidget.Direction.North ): self.setAnchor(XPopupWidget.Anchor.TopCenter) elif ( direction == XPopupWidget.Direction.South ): self.setAnchor(XPopupWidget.Anchor.BottomCenter) elif ( direction == XPopupWidget.Direction.East ): self.setAnchor(XPopupWidget.Anchor.LeftCenter) else: self.setAnchor(XPopupWidget.Anchor.RightCenter) def setPalette(self, palette): """ Sets the palette for this widget and the scroll area. :param palette | <QPalette> """ super(XPopupWidget, self).setPalette(palette) self._scrollArea.setPalette(palette) def setPopupMode( self ): """ Sets the current mode value to Popup. """ self.setCurrentMode(XPopupWidget.Mode.Popup) def setPopupPadding( self, padding ): """ Sets the amount to pad the popup area when displaying this widget. :param padding | <int> """ self._popupPadding = padding self.adjustContentsMargins() def setPositionLinkedTo(self, widgets): """ Sets the widget that this popup will be linked to for positional changes. :param widgets | <QWidget> || [<QWidget>, ..] """ if type(widgets) in (list, set, tuple): new_widgets = list(widgets) else: new_widgets = [] widget = widgets while widget: widget.installEventFilter(self) new_widgets.append(widget) widget = widget.parent() self._positionLinkedTo = new_widgets def setResizable( self, state ): self._resizable = state self._sizeGrip.setVisible(state) self._leftSizeGrip.setVisible(state) def setShowButtonBox(self, state): self._buttonBoxVisible = state self.buttonBox().setVisible(state) def setShowTitleBar(self, state): self._titleBarVisible = state self._dialogButton.setVisible(state) self._closeButton.setVisible(state) def setToolTipMode(self): """ Sets the mode for this popup widget to ToolTip """ self.setCurrentMode(XPopupWidget.Mode.ToolTip) def setVisible(self, state): super(XPopupWidget, self).setVisible(state) widget = self.centralWidget() if widget: widget.setVisible(state) def timerEvent( self, event ): """ When the timer finishes, hide the tooltip popup widget. :param event | <QEvent> """ if self.currentMode() == XPopupWidget.Mode.ToolTip: self.killTimer(event.timerId()) event.accept() self.close() else: super(XPopupWidget, self).timerEvent(event) def updateModeSettings(self): mode = self.currentMode() is_visible = self.isVisible() # display as a floating dialog if mode == XPopupWidget.Mode.Dialog: self.setWindowFlags(Qt.Dialog | Qt.Tool) self.setAttribute(Qt.WA_TransparentForMouseEvents, False) self._closeButton.setVisible(False) self._dialogButton.setVisible(False) # display as a user tooltip elif mode == XPopupWidget.Mode.ToolTip: flags = Qt.Popup | Qt.FramelessWindowHint self.setWindowFlags(flags) self.setBackgroundRole(QPalette.Window) self.setAttribute(Qt.WA_TransparentForMouseEvents) self.setShowTitleBar(False) self.setShowButtonBox(False) self.setFocusPolicy(Qt.NoFocus) # hide the scrollbars policy = Qt.ScrollBarAlwaysOff self._scrollArea.setVerticalScrollBarPolicy(policy) self._scrollArea.setHorizontalScrollBarPolicy(policy) # display as a popup widget else: flags = Qt.Popup | Qt.FramelessWindowHint if not self.autoCloseOnFocusOut(): flags |= Qt.Tool self.setWindowFlags(flags) self._closeButton.setVisible(self._titleBarVisible) self._dialogButton.setVisible(self._titleBarVisible) self.setBackgroundRole(QPalette.Button) self.adjustContentsMargins() if ( is_visible ): self.show() @staticmethod @deprecatedmethod('XPopupWidget', 'This method no longer has an effect as we are not '\ 'storing references to the tooltip.') def hideToolTip(key = None): """ Hides any existing tooltip popup widgets. :warning This method is deprecated! """ pass @staticmethod def showToolTip( text, point = None, anchor = None, parent = None, background = None, foreground = None, key = None, seconds = 5 ): """ Displays a popup widget as a tooltip bubble. :param text | <str> point | <QPoint> || None anchor | <XPopupWidget.Mode.Anchor> || None parent | <QWidget> || None background | <QColor> || None foreground | <QColor> || None key | <str> || None seconds | <int> """ if point is None: point = QCursor.pos() if parent is None: parent = QApplication.activeWindow() if anchor is None and parent is None: anchor = XPopupWidget.Anchor.TopCenter # create a new tooltip widget widget = XPopupWidget(parent) widget.setToolTipMode() widget.setResizable(False) # create the tooltip label label = QLabel(text, widget) label.setOpenExternalLinks(True) label.setAlignment(Qt.AlignLeft | Qt.AlignVCenter) label.setMargin(3) label.setIndent(3) label.adjustSize() widget.setCentralWidget(label) # update the tip label.adjustSize() widget.adjustSize() palette = widget.palette() if not background: background = palette.color(palette.ToolTipBase) if not foreground: foreground = palette.color(palette.ToolTipText) palette.setColor(palette.Window, QColor(background)) palette.setColor(palette.WindowText, QColor(foreground)) widget.setPalette(palette) widget.centralWidget().setPalette(palette) if anchor is None: widget.setAutoCalculateAnchor(True) else: widget.setAnchor(anchor) widget.setAutoCloseOnFocusOut(True) widget.setAttribute(Qt.WA_DeleteOnClose) widget.popup(point) widget.startTimer(1000 * seconds) return widget
class SkillWidget(TraitWidget): """ @brief Das Widget, in welchem sämtliche Fertigkeiten angeordnet sind. Wird bei irgendeiner Fertigkeit der Spazialisierungen-Knopf gedrückt, werden alle anderen Spezialisierungs-Knöpfe ausgeschalten. """ specialtiesActivated = Signal(bool, object) def __init__(self, template, character, parent=None): super(SkillWidget, self).__init__(template, character, parent) self.__layout = QVBoxLayout() self.setLayout( self.__layout ) self.__scrollArea = QScrollArea() ## Die Auflistung der Fertigkeiten soll auch unter Windows einen transparenten Hintergrund haben. self.__scrollArea.setObjectName("transparentWidget") ## \todo Sollte nicht vom Betriebssystem, sondern vom verwendeten Style abhängen. if os.name == "nt": self.__scrollArea.setStyleSheet( "QWidget#transparentWidget { background: transparent; }" ) self.__layout.addWidget( self.__scrollArea) self.__scrollLayout = QVBoxLayout() self.__scrollWidget = QWidget() ## Die Auflistung der Fertigkeiten soll auch unter Windows einen transparenten Hintergrund haben. Indem ich den selben Namen wie zuvor vergebe, wirkt auch das Stylsheet auf dieses Widget. self.__scrollWidget.setObjectName("transparentWidget") #self.__scrollWidget.setStyleSheet( "QWidget#transparentWidget { background-color:transparent; }" ) #scrollWidget.setMinimumSize(this.width(), 400); self.__scrollWidget.setLayout(self.__scrollLayout) typ = "Skill" ## Eine Liste, in der alle Eigenschafts-Widgets aufgelistet werden. self.__traitWidgets = [] for item in Config.CATEGORIES_MAIN: #Debug.debug(self._character.traits) # Für jede Kategorie wird ein eigener Abschnitt erzeugt. widgetSkillCategory = QGroupBox() widgetSkillCategory.setTitle(item) widgetSkillCategory.setFlat(True) layoutSkillCategory = QVBoxLayout() widgetSkillCategory.setLayout( layoutSkillCategory ); self.__scrollLayout.addWidget( widgetSkillCategory ) __list = list( self._character.traits[typ][item].items() ) __list.sort() for skill in __list: # Anlegen des Widgets, das diese Eigenschaft repräsentiert. traitWidget = CharaTrait( skill[1], self ) traitWidget.buttonText = 0 traitWidget.setDescriptionHidden( True ) traitWidget.enableButton(0) # Zu Beginn sollen die Spezailisierungen nicht enabled sein. # Dieses Widget auch an Liste anhängen, damit ich einfacher darauf zugreifen kann. traitListItem = traitWidget self.__traitWidgets.append(traitListItem) # Es werden nur Fertigkeiten der richtigen Alters- und Zeit-Kategorie angezeigt. self.hideReasonChanged.connect(traitWidget.hideOrShowTrait) # Fertigkeiten haben Spezialisierungen. traitWidget.specialtiesClicked.connect(self.uncheckOtherButtons) traitWidget.specialtiesClicked.connect(self.specialtiesActivated.emit) ## Wenn sich die Spezialisierungen ändern, sollen die veränderten Spezialisierungen auch angezeigt werden. Das wird so gelöst, als wäre der Knopf für die Spezialisierungen erneut gedrückt worden. #skill.specialtiesChanged.connect(self.emitSpecialtiesActivated) layoutSkillCategory.addWidget( traitWidget ) self.maxTraitChanged.connect(traitWidget.setMaximum) # Stretch einfügen, damit die Eigenschaften besser angeordnet sind. self.__scrollLayout.addStretch() self.__scrollArea.setWidget(self.__scrollWidget) self.__scrollArea.setWidgetResizable(True) self.__scrollArea.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.__scrollArea.setMinimumWidth(self.__scrollArea.viewport().minimumWidth()) def uncheckOtherButtons( self, sw, trait ): """ Über diese Funktion werden alle anderen Spezialisierungs-Knöpfe deaktiviert, sobald einer aktiviert wird. """ #Debug.debug("Drücke {}".format(skillName)) if sw: for item in self.__traitWidgets: if item.name != trait.name: item.setSpecialtyButtonChecked(False)
class XNavigationEdit(XLineEdit): """ """ navigationChanged = Signal() __designer_icon__ = projexui.resources.find('img/ui/navigate.png') def __init__( self, parent = None ): super(XNavigationEdit, self).__init__( parent ) # define custom properties self._separator = '/' self._partsEditingEnabled = True self._originalText = '' self._scrollWidget = QScrollArea(self) self._partsWidget = QWidget(self._scrollWidget) self._buttonGroup = QButtonGroup(self) self._scrollAmount = 0 self._navigationModel = None # create the completer tree palette = self.palette() palette.setColor(palette.Base, palette.color(palette.Window)) palette.setColor(palette.Text, palette.color(palette.WindowText)) bg = palette.color(palette.Highlight) abg = bg.darker(115) fg = palette.color(palette.HighlightedText) sbg = 'rgb(%s, %s, %s)' % (bg.red(), bg.green(), bg.blue()) sabg = 'rgb(%s, %s, %s)' % (abg.red(), abg.green(), abg.blue()) sfg = 'rgb(%s, %s, %s)' % (fg.red(), fg.green(), fg.blue()) style = 'QTreeView::item:hover { '\ ' color: %s;'\ ' background: qlineargradient(x1:0,'\ ' y1:0,'\ ' x2:0,'\ ' y2:1,'\ ' stop: 0 %s,'\ ' stop: 1 %s);'\ '}' % (sfg, sbg, sabg) self._completerTree = QTreeView(self) self._completerTree.setStyleSheet(style) self._completerTree.header().hide() self._completerTree.setFrameShape(QTreeView.Box) self._completerTree.setFrameShadow(QTreeView.Plain) self._completerTree.setPalette(palette) self._completerTree.setEditTriggers(QTreeView.NoEditTriggers) self._completerTree.setWindowFlags(Qt.Popup) self._completerTree.installEventFilter(self) self._completerTree.setRootIsDecorated(False) self._completerTree.setItemsExpandable(False) # create the editing widget layout = QHBoxLayout() layout.setContentsMargins(0, 0, 0, 0) layout.setSpacing(0) layout.addStretch() self._scrollWidget.setFrameShape( QScrollArea.NoFrame ) self._scrollWidget.setFocusPolicy(Qt.NoFocus) self._scrollWidget.setWidget(self._partsWidget) self._scrollWidget.setWidgetResizable(True) self._scrollWidget.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self._scrollWidget.setAlignment(Qt.AlignTop | Qt.AlignRight) self._scrollWidget.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self._scrollWidget.setContentsMargins(0, 0, 0, 0) self._scrollWidget.setViewportMargins(0, 0, 0, 0) self._scrollWidget.move(2, 2) self._partsWidget.setLayout(layout) self._partsWidget.setCursor(Qt.ArrowCursor) self._partsWidget.setAutoFillBackground(True) self._partsWidget.setFixedHeight(self.height() - 12) palette = self._partsWidget.palette() palette.setColor(palette.Background, palette.color(palette.Base)) self._partsWidget.setPalette(palette) # create connections self._completerTree.clicked.connect( self.navigateToIndex ) self._buttonGroup.buttonClicked.connect( self.handleButtonClick ) self._scrollWidget.horizontalScrollBar().valueChanged.connect( self.scrollParts ) def acceptEdit( self ): """ Accepts the current text and rebuilds the parts widget. """ if ( self._partsWidget.isVisible() ): return False use_completion = self.completer().popup().isVisible() completion = self.completer().currentCompletion() self._completerTree.hide() self.completer().popup().hide() if ( use_completion ): self.setText(completion) else: self.rebuild() return True def cancelEdit( self ): """ Rejects the current edit and shows the parts widget. """ if ( self._partsWidget.isVisible() ): return False self._completerTree.hide() self.completer().popup().hide() self.setText(self._originalText) return True def currentItem( self ): """ Returns the current navigation item from the current path. :return <XNavigationItem> || None """ model = self.navigationModel() if ( not model ): return None return model.itemByPath(self.text()) def eventFilter( self, object, event ): """ Filters the events for the inputed object through this edit. :param object | <QObject> event | <QEvent> :return <bool> | consumed """ if ( event.type() == event.KeyPress ): if ( event.key() == Qt.Key_Escape ): self._completerTree.hide() self.completer().popup().hide() self.cancelEdit() elif ( event.key() in (Qt.Key_Return, Qt.Key_Enter) ): self.acceptEdit() return True elif ( event.key() == Qt.Key_Tab ): if ( self.completer().popup().isVisible() ): text = str(self.completer().currentCompletion()) super(XNavigationEdit, self).setText(text) return True else: self.acceptEdit() return False elif ( event.type() == event.MouseButtonPress ): if ( not self._completerTree.rect().contains(event.pos()) ): self._completerTree.hide() self.completer().popup().hide() self.cancelEdit() return False def focusOutEvent( self, event ): """ Overloads the focus out event to cancel editing when the widget loses focus. :param event | <QFocusEvent> """ super(XNavigationEdit, self).focusOutEvent(event) self.cancelEdit() def handleButtonClick( self, button ): """ Handle the event when a user clicks on one of the part buttons. :param button | <QToolButton> """ path = button.property('path') is_completer = button.property('is_completer') # popup a completion menu if ( unwrapVariant(is_completer) ): model = self.navigationModel() if ( not model ): return sep = self.separator() path = str(unwrapVariant(path)) item = model.itemByPath(path, includeRoot = True) if ( not item ): return curr_path = str(self.text()).strip(self.separator()) curr_path = curr_path.replace(path, '').strip(self.separator()) child_name = '' if ( curr_path ): child_name = curr_path.split(self.separator())[0] index = model.indexFromItem(item) self._completerTree.move(QCursor.pos()) self._completerTree.setRootIndex(index) self._completerTree.verticalScrollBar().setValue(0) if ( child_name ): child_item = None for i in range(item.rowCount()): child = item.child(i) if ( child.text() == child_name ): child_item = child break if ( child_item ): child_index = model.indexFromItem(child_item) self._completerTree.setCurrentIndex(child_index) self._completerTree.scrollTo(child_index) self._completerTree.show() self._completerTree.setUpdatesEnabled(True) else: self.setText(unwrapVariant(path)) def keyPressEvent( self, event ): """ Overloads the key press event to listen for escape calls to cancel the parts editing. :param event | <QKeyPressEvent> """ if ( self.scrollWidget().isHidden() ): if ( event.key() == Qt.Key_Escape ): self.cancelEdit() return elif ( event.key() in (Qt.Key_Return, Qt.Key_Enter) ): self.acceptEdit() return elif ( event.key() == Qt.Key_A and event.modifiers() == Qt.ControlModifier ): self.startEdit() super(XNavigationEdit, self).keyPressEvent(event) def mouseDoubleClickEvent( self, event ): """ Overloads the system to enable editing when a user double clicks. :param event | <QMouseEvent> """ super(XNavigationEdit, self).mouseDoubleClickEvent(event) self.startEdit() def navigationModel( self ): """ Returns the navigation model linked with this edit. :return <XNavigationModel> || None """ return self._navigationModel def navigateToIndex( self, index ): """ Navigates to the inputed action's path. :param action | <QAction> """ self._completerTree.hide() item = self._navigationModel.itemFromIndex(index) self.setText(self._navigationModel.itemPath(item)) def parts( self ): """ Returns the parts that are used for this system. :return [<str>, ..] """ path = str(self.text()).strip(self.separator()) if ( not path ): return [] return path.split(self.separator()) def partsWidget( self ): """ Returns the widget that contains the parts system. :return <QScrollArea> """ return self._partsWidget def startEdit( self ): """ Rebuilds the pathing based on the parts. """ self._originalText = self.text() self.scrollWidget().hide() self.setFocus() self.selectAll() def rebuild( self ): """ Rebuilds the parts widget with the latest text. """ navitem = self.currentItem() if ( navitem ): navitem.initialize() self.setUpdatesEnabled(False) self.scrollWidget().show() self._originalText = '' partsw = self.partsWidget() for button in self._buttonGroup.buttons(): self._buttonGroup.removeButton(button) button.close() button.setParent(None) button.deleteLater() # create the root button layout = partsw.layout() parts = self.parts() button = QToolButton(partsw) button.setAutoRaise(True) button.setMaximumWidth(12) button.setArrowType(Qt.RightArrow) button.setProperty('path', wrapVariant('')) button.setProperty('is_completer', wrapVariant(True)) last_button = button self._buttonGroup.addButton(button) layout.insertWidget(0, button) # check to see if we have a navigation model setup if ( self._navigationModel ): last_item = self._navigationModel.itemByPath(self.text()) show_last = last_item and last_item.rowCount() > 0 else: show_last = False # load the navigation system count = len(parts) for i, part in enumerate(parts): path = self.separator().join(parts[:i+1]) button = QToolButton(partsw) button.setAutoRaise(True) button.setText(part) if ( self._navigationModel ): item = self._navigationModel.itemByPath(path) if ( item ): button.setIcon(item.icon()) button.setToolButtonStyle(Qt.ToolButtonTextBesideIcon) button.setProperty('path', wrapVariant(path)) button.setProperty('is_completer', wrapVariant(False)) self._buttonGroup.addButton(button) layout.insertWidget((i * 2) + 1, button) # determine if we should show the final button if ( show_last or i < (count - 1) ): button = QToolButton(partsw) button.setAutoRaise(True) button.setMaximumWidth(12) button.setArrowType(Qt.RightArrow) button.setProperty('path', wrapVariant(path)) button.setProperty('is_completer', wrapVariant(True)) self._buttonGroup.addButton(button) layout.insertWidget((i * 2) + 2, button) last_button = button if ( self.scrollWidget().width() < partsw.width() ): self.scrollParts(partsw.width() - self.scrollWidget().width()) self.setUpdatesEnabled(True) self.navigationChanged.emit() def resizeEvent( self, event ): """ Resizes the current widget and its parts widget. :param event | <QResizeEvent> """ super(XNavigationEdit, self).resizeEvent(event) w = self.width() h = self.height() self._scrollWidget.resize(w - 4, h - 4) if ( self._scrollWidget.width() < self._partsWidget.width() ): self.scrollParts( self._partsWidget.width() - self._scrollWidget.width() ) def scrollParts( self, amount ): """ Scrolls the parts to offset the scrolling amount. :param amount | <int> """ change = self._scrollAmount - amount self._partsWidget.scroll(change, 0) self._scrollAmount = amount def scrollWidget( self ): """ Returns the scrolling widget. :return <QScrollArea> """ return self._scrollWidget def separator( self ): """ Returns the separation character that is used for this edit. :return <str> """ return self._separator def setTopLevelItems( self, items ): """ Initializes the navigation system to start with the inputed root \ item. :param item | <XNavigationItem> """ if ( not self._navigationModel ): self.setNavigationModel(XNavigationModel(self)) self._navigationModel.setTopLevelItems(items) def setNavigationModel( self, model ): """ Sets the navigation model for this edit. :param model | <XNavigationModel> """ self._navigationModel = model self._completerTree.setModel(model) if ( model ): model.setSeparator(self.separator()) completer = XNavigationCompleter(model, self) self.setCompleter(completer) completer.popup().installEventFilter(self) else: self.setCompleter(None) self.rebuild() def setParts( self, parts ): """ Sets the path for this edit widget by providing the parts to the path. :param parts | [<str>, ..] """ self.setText(self.separator().join(map(str, parts))) def setSeparator( self, separator ): """ Sets the separator to the inputed character. :param separator | <str> """ self._separator = separator if ( self._navigationModel ): self._navigationModel.setSeparator(separator) self.rebuild() def setText( self, text ): """ Sets the text for this edit to the inputed text. :param text | <str> """ super(XNavigationEdit, self).setText(text) self.scrollWidget().show() if ( text == '' or self._originalText != text ): self.rebuild()
class XPopupWidget(QWidget): """ """ Direction = enum('North', 'South', 'East', 'West') Mode = enum('Popup', 'Dialog', 'ToolTip') Anchor = enum('TopLeft', 'TopCenter', 'TopRight', 'LeftTop', 'LeftCenter', 'LeftBottom', 'RightTop', 'RightCenter', 'RightBottom', 'BottomLeft', 'BottomCenter', 'BottomRight') aboutToShow = qt.Signal() accepted = qt.Signal() closed = qt.Signal() rejected = qt.Signal() resetRequested = qt.Signal() shown = qt.Signal() buttonClicked = qt.Signal(QAbstractButton) def __init__(self, parent=None, buttons=None): super(XPopupWidget, self).__init__(parent) # define custom properties self._anchor = XPopupWidget.Anchor.TopCenter self._autoCalculateAnchor = False self._autoCloseOnAccept = True self._autoCloseOnReject = True self._autoCloseOnFocusOut = False self._autoDefault = True self._first = True self._animated = False self._currentMode = None self._positionLinkedTo = [] # define controls self._resizable = True self._popupPadding = 10 self._titleBarVisible = True self._buttonBoxVisible = True self._dialogButton = QToolButton(self) self._closeButton = QToolButton(self) self._scrollArea = QScrollArea(self) self._sizeGrip = QSizeGrip(self) self._sizeGrip.setFixedWidth(12) self._sizeGrip.setFixedHeight(12) self._leftSizeGrip = QSizeGrip(self) self._leftSizeGrip.setFixedWidth(12) self._leftSizeGrip.setFixedHeight(12) if buttons is None: buttons = QDialogButtonBox.NoButton self._buttonBox = QDialogButtonBox(buttons, Qt.Horizontal, self) self._buttonBox.setContentsMargins(3, 0, 3, 9) self._scrollArea.setWidgetResizable(True) self._scrollArea.setFrameShape(QScrollArea.NoFrame) self._scrollArea.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) palette = self.palette() self._scrollArea.setPalette(palette) self._dialogButton.setToolTip('Popout to Dialog') self._closeButton.setToolTip('Close Popup') for btn in (self._dialogButton, self._closeButton): btn.setAutoRaise(True) btn.setIconSize(QSize(14, 14)) btn.setMaximumSize(16, 16) # setup the icons icon = QIcon(projexui.resources.find('img/dialog.png')) self._dialogButton.setIcon(icon) icon = QIcon(projexui.resources.find('img/close.png')) self._closeButton.setIcon(icon) # define the ui hlayout = QHBoxLayout() hlayout.setSpacing(0) hlayout.addStretch(1) hlayout.addWidget(self._dialogButton) hlayout.addWidget(self._closeButton) hlayout.setContentsMargins(0, 0, 0, 0) hlayout2 = QHBoxLayout() hlayout2.addWidget(self._buttonBox) hlayout2.setContentsMargins(0, 0, 3, 0) vlayout = QVBoxLayout() vlayout.addLayout(hlayout) vlayout.addWidget(self._scrollArea) vlayout.addLayout(hlayout2) vlayout.setContentsMargins(3, 2, 3, 2) vlayout.setSpacing(0) self.setLayout(vlayout) self.setPositionLinkedTo(parent) # set default properties self.setAutoFillBackground(True) self.setBackgroundRole(QPalette.Button) self.setWindowTitle('Popup') self.setFocusPolicy(Qt.StrongFocus) self.setCurrentMode(XPopupWidget.Mode.Popup) # create connections self._dialogButton.clicked.connect(self.setDialogMode) self._closeButton.clicked.connect(self.reject) self._buttonBox.accepted.connect(self.accept) self._buttonBox.rejected.connect(self.reject) self._buttonBox.clicked.connect(self.handleButtonClick) def addButton(self, button, role=QDialogButtonBox.ActionRole): """ Adds a custom button to the button box for this popup widget. :param button | <QAbstractButton> || <str> :return <button> || None (based on if a button or string was given) """ return self._buttonBox.addButton(button, role) def adjustContentsMargins(self): """ Adjusts the contents for this widget based on the anchor and \ mode. """ anchor = self.anchor() mode = self.currentMode() # margins for a dialog if (mode == XPopupWidget.Mode.Dialog): self.setContentsMargins(0, 0, 0, 0) # margins for a top anchor point elif (anchor & (XPopupWidget.Anchor.TopLeft | XPopupWidget.Anchor.TopCenter | XPopupWidget.Anchor.TopRight)): self.setContentsMargins(0, self.popupPadding() + 5, 0, 0) # margins for a bottom anchor point elif ( anchor & (XPopupWidget.Anchor.BottomLeft | XPopupWidget.Anchor.BottomCenter | XPopupWidget.Anchor.BottomRight)): self.setContentsMargins(0, 0, 0, self.popupPadding()) # margins for a left anchor point elif (anchor & (XPopupWidget.Anchor.LeftTop | XPopupWidget.Anchor.LeftCenter | XPopupWidget.Anchor.LeftBottom)): self.setContentsMargins(self.popupPadding(), 0, 0, 0) # margins for a right anchor point else: self.setContentsMargins(0, 0, self.popupPadding(), 0) self.adjustMask() def adjustMask(self): """ Updates the alpha mask for this popup widget. """ if self.currentMode() == XPopupWidget.Mode.Dialog: self.clearMask() return path = self.borderPath() bitmap = QBitmap(self.width(), self.height()) bitmap.fill(QColor('white')) painter = QPainter() painter.begin(bitmap) painter.setRenderHint(QPainter.Antialiasing) pen = QPen(QColor('black')) pen.setWidthF(0.75) painter.setPen(pen) painter.setBrush(QColor('black')) painter.drawPath(path) painter.end() self.setMask(bitmap) def adjustSize(self): """ Adjusts the size of this popup to best fit the new widget size. """ widget = self.centralWidget() if widget is None: super(XPopupWidget, self).adjustSize() return widget.adjustSize() hint = widget.minimumSizeHint() size = widget.minimumSize() width = max(size.width(), hint.width()) height = max(size.height(), hint.height()) width += 20 height += 20 if self._buttonBoxVisible: height += self.buttonBox().height() + 10 if self._titleBarVisible: height += max(self._dialogButton.height(), self._closeButton.height()) + 10 curr_w = self.width() curr_h = self.height() # determine if we need to move based on our anchor anchor = self.anchor() if anchor & (self.Anchor.LeftBottom | self.Anchor.RightBottom | \ self.Anchor.BottomLeft | self.Anchor.BottomCenter | \ self.Anchor.BottomRight): delta_y = height - curr_h elif anchor & (self.Anchor.LeftCenter | self.Anchor.RightCenter): delta_y = (height - curr_h) / 2 else: delta_y = 0 if anchor & (self.Anchor.RightTop | self.Anchor.RightCenter | \ self.Anchor.RightTop | self.Anchor.TopRight): delta_x = width - curr_w elif anchor & (self.Anchor.TopCenter | self.Anchor.BottomCenter): delta_x = (width - curr_w) / 2 else: delta_x = 0 self.setMinimumSize(width, height) self.resize(width, height) pos = self.pos() pos.setX(pos.x() - delta_x) pos.setY(pos.y() - delta_y) self.move(pos) @qt.Slot() def accept(self): """ Emits the accepted signal and closes the popup. """ if not self.signalsBlocked(): self.accepted.emit() if self.autoCloseOnAccept(): self.close() def anchor(self): """ Returns the anchor point for this popup widget. :return <XPopupWidget.Anchor> """ return self._anchor def autoCalculateAnchor(self): """ Returns whether or not this popup should calculate the anchor point on popup based on the parent widget and the popup point. :return <bool> """ return self._autoCalculateAnchor def autoCloseOnAccept(self): """ Returns whether or not this popup widget manages its own close on accept behavior. :return <bool> """ return self._autoCloseOnAccept def autoCloseOnReject(self): """ Returns whether or not this popup widget manages its own close on reject behavior. :return <bool> """ return self._autoCloseOnReject def autoCloseOnFocusOut(self): """ Returns whether or not this popup widget should auto-close when the user clicks off the view. :return <bool> """ return self._autoCloseOnFocusOut def autoDefault(self): """ Returns whether or not clicking enter should default to the accept key. :return <bool> """ return self._autoDefault def borderPath(self): """ Returns the border path that will be drawn for this widget. :return <QPainterPath> """ path = QPainterPath() x = 1 y = 1 w = self.width() - 2 h = self.height() - 2 pad = self.popupPadding() anchor = self.anchor() # create a path for a top-center based popup if anchor == XPopupWidget.Anchor.TopCenter: path.moveTo(x, y + pad) path.lineTo(x + ((w / 2) - pad), y + pad) path.lineTo(x + (w / 2), y) path.lineTo(x + ((w / 2) + pad), y + pad) path.lineTo(x + w, y + pad) path.lineTo(x + w, y + h) path.lineTo(x, y + h) path.lineTo(x, y + pad) # create a path for a top-left based popup elif anchor == XPopupWidget.Anchor.TopLeft: path.moveTo(x, y + pad) path.lineTo(x + pad, y) path.lineTo(x + 2 * pad, y + pad) path.lineTo(x + w, y + pad) path.lineTo(x + w, y + h) path.lineTo(x, y + h) path.lineTo(x, y + pad) # create a path for a top-right based popup elif anchor == XPopupWidget.Anchor.TopRight: path.moveTo(x, y + pad) path.lineTo(x + w - 2 * pad, y + pad) path.lineTo(x + w - pad, y) path.lineTo(x + w, y + pad) path.lineTo(x + w, y + h) path.lineTo(x, y + h) path.lineTo(x, y + pad) # create a path for a bottom-left based popup elif anchor == XPopupWidget.Anchor.BottomLeft: path.moveTo(x, y) path.lineTo(x + w, y) path.lineTo(x + w, y + h - pad) path.lineTo(x + 2 * pad, y + h - pad) path.lineTo(x + pad, y + h) path.lineTo(x, y + h - pad) path.lineTo(x, y) # create a path for a south based popup elif anchor == XPopupWidget.Anchor.BottomCenter: path.moveTo(x, y) path.lineTo(x + w, y) path.lineTo(x + w, y + h - pad) path.lineTo(x + ((w / 2) + pad), y + h - pad) path.lineTo(x + (w / 2), y + h) path.lineTo(x + ((w / 2) - pad), y + h - pad) path.lineTo(x, y + h - pad) path.lineTo(x, y) # create a path for a bottom-right based popup elif anchor == XPopupWidget.Anchor.BottomRight: path.moveTo(x, y) path.lineTo(x + w, y) path.lineTo(x + w, y + h - pad) path.lineTo(x + w - pad, y + h) path.lineTo(x + w - 2 * pad, y + h - pad) path.lineTo(x, y + h - pad) path.lineTo(x, y) # create a path for a right-top based popup elif anchor == XPopupWidget.Anchor.RightTop: path.moveTo(x, y) path.lineTo(x + w - pad, y) path.lineTo(x + w, y + pad) path.lineTo(x + w - pad, y + 2 * pad) path.lineTo(x + w - pad, y + h) path.lineTo(x, y + h) path.lineTo(x, y) # create a path for a right-center based popup elif anchor == XPopupWidget.Anchor.RightCenter: path.moveTo(x, y) path.lineTo(x + w - pad, y) path.lineTo(x + w - pad, y + ((h / 2) - pad)) path.lineTo(x + w, y + (h / 2)) path.lineTo(x + w - pad, y + ((h / 2) + pad)) path.lineTo(x + w - pad, y + h) path.lineTo(x, y + h) path.lineTo(x, y) # create a path for a right-bottom based popup elif anchor == XPopupWidget.Anchor.RightBottom: path.moveTo(x, y) path.lineTo(x + w - pad, y) path.lineTo(x + w - pad, y + h - 2 * pad) path.lineTo(x + w, y + h - pad) path.lineTo(x + w - pad, y + h) path.lineTo(x, y + h) path.lineTo(x, y) # create a path for a left-top based popup elif anchor == XPopupWidget.Anchor.LeftTop: path.moveTo(x + pad, y) path.lineTo(x + w, y) path.lineTo(x + w, y + h) path.lineTo(x + pad, y + h) path.lineTo(x + pad, y + 2 * pad) path.lineTo(x, y + pad) path.lineTo(x + pad, y) # create a path for an left-center based popup elif anchor == XPopupWidget.Anchor.LeftCenter: path.moveTo(x + pad, y) path.lineTo(x + w, y) path.lineTo(x + w, y + h) path.lineTo(x + pad, y + h) path.lineTo(x + pad, y + ((h / 2) + pad)) path.lineTo(x, y + (h / 2)) path.lineTo(x + pad, y + ((h / 2) - pad)) path.lineTo(x + pad, y) # create a path for a left-bottom based popup elif anchor == XPopupWidget.Anchor.LeftBottom: path.moveTo(x + pad, y) path.lineTo(x + w, y) path.lineTo(x + w, y + h) path.lineTo(x + pad, y + h) path.lineTo(x, y + h - pad) path.lineTo(x + pad, y + h - 2 * pad) path.lineTo(x + pad, y) return path def buttonBox(self): """ Returns the button box that is used to control this popup widget. :return <QDialogButtonBox> """ return self._buttonBox def centralWidget(self): """ Returns the central widget that is being used by this popup. :return <QWidget> """ return self._scrollArea.widget() def close(self): """ Closes the popup widget and central widget. """ widget = self.centralWidget() if widget and not widget.close(): return super(XPopupWidget, self).close() def closeEvent(self, event): widget = self.centralWidget() if widget and not widget.close() and \ self.currentMode() != XPopupWidget.Mode.ToolTip: event.ignore() else: super(XPopupWidget, self).closeEvent(event) self.closed.emit() def currentMode(self): """ Returns the current mode for this widget. :return <XPopupWidget.Mode> """ return self._currentMode @deprecatedmethod('XPopupWidget', 'Direction is no longer used, use anchor instead') def direction(self): """ Returns the current direction parameter for this widget. :return <XPopupWidget.Direction> """ anchor = self.anchor() if (anchor & (XPopupWidget.Anchor.TopLeft | XPopupWidget.Anchor.TopCenter | XPopupWidget.Anchor.TopRight)): return XPopupWidget.Direction.North elif ( anchor & (XPopupWidget.Anchor.BottomLeft | XPopupWidget.Anchor.BottomCenter | XPopupWidget.Anchor.BottomRight)): return XPopupWidget.Direction.South elif (anchor & (XPopupWidget.Anchor.LeftTop | XPopupWidget.Anchor.LeftCenter | XPopupWidget.Anchor.LeftBottom)): return XPopupWidget.Direction.East else: return XPopupWidget.Direction.West def eventFilter(self, object, event): """ Processes when the window is moving to update the position for the popup if in popup mode. :param object | <QObject> event | <QEvent> """ links = self.positionLinkedTo() is_dialog = self.currentMode() == self.Mode.Dialog if object not in links: return False if event.type() == event.Close: self.close() return False if event.type() == event.Hide and not is_dialog: self.hide() return False if event.type() == event.Move and not is_dialog: deltaPos = event.pos() - event.oldPos() self.move(self.pos() + deltaPos) return False if self.currentMode() != self.Mode.ToolTip: return False if event.type() == event.Leave: pos = object.mapFromGlobal(QCursor.pos()) if (not object.rect().contains(pos)): self.close() event.accept() return True if event.type() in (event.MouseButtonPress, event.MouseButtonDblClick): self.close() event.accept() return True return False @qt.Slot(QAbstractButton) def handleButtonClick(self, button): """ Handles the button click for this widget. If the Reset button was clicked, then the resetRequested signal will be emitted. All buttons will emit the buttonClicked signal. :param button | <QAbstractButton> """ if (self.signalsBlocked()): return if (button == self._buttonBox.button(QDialogButtonBox.Reset)): self.resetRequested.emit() self.buttonClicked.emit(button) def isAnimated(self): """ Returns whether or not the popup widget should animate its opacity when it is shown. :return <bool> """ return self._animated def isResizable(self): """ Returns if this popup is resizable or not. :return <bool> """ return self._resizable def keyPressEvent(self, event): """ Looks for the Esc key to close the popup. :param event | <QKeyEvent> """ if (event.key() == Qt.Key_Escape): self.reject() event.accept() return elif (event.key() in (Qt.Key_Return, Qt.Key_Enter)): if self._autoDefault: self.accept() event.accept() return super(XPopupWidget, self).keyPressEvent(event) def mapAnchorFrom(self, widget, globalPos): """ Returns the anchor point that best fits within the given widget from the inputed global position. :param widget | <QWidget> globalPos | <QPoint> :return <XPopupWidget.Anchor> """ localPos = widget.mapFromGlobal(globalPos) x = localPos.x() y = localPos.y() w = widget.width() h = widget.height() cw = self.width() / 2 ch = self.height() / 2 # by default, try to do a center point, so make sure the center point # is at least 1/2 the width longer from each edge if x < cw and h - y < ch: return XPopupWidget.Anchor.BottomLeft elif x < cw: return XPopupWidget.Anchor.TopLeft elif w - x < cw and h - y < ch: return XPopupWidget.Anchor.BottomRight elif w - x < cw: return XPopupWidget.Anchor.TopRight elif h - y < ch: return XPopupWidget.Anchor.BottomCenter else: return XPopupWidget.Anchor.TopCenter def popup(self, pos=None): """ Pops up this widget at the inputed position. The inputed point should \ be in global space. :param pos | <QPoint> :return <bool> success """ if self._first and self.centralWidget() is not None: self.adjustSize() self._first = False if not self.signalsBlocked(): self.aboutToShow.emit() if not pos: pos = QCursor.pos() if self.currentMode() == XPopupWidget.Mode.Dialog and \ self.isVisible(): return False elif self.currentMode() == XPopupWidget.Mode.Dialog: self.setPopupMode() # auto-calculate the point if self.autoCalculateAnchor(): self.setAnchor(self.mapAnchorFrom(self.parent(), pos)) pad = self.popupPadding() # determine where to move based on the anchor anchor = self.anchor() # MODIFY X POSITION # align x-left if (anchor & (XPopupWidget.Anchor.TopLeft | XPopupWidget.Anchor.BottomLeft)): pos.setX(pos.x() - pad) # align x-center elif (anchor & (XPopupWidget.Anchor.TopCenter | XPopupWidget.Anchor.BottomCenter)): pos.setX(pos.x() - self.width() / 2) # align x-right elif ( anchor & (XPopupWidget.Anchor.TopRight | XPopupWidget.Anchor.BottomRight)): pos.setX(pos.x() - self.width() + pad) # align x-padded elif (anchor & (XPopupWidget.Anchor.RightTop | XPopupWidget.Anchor.RightCenter | XPopupWidget.Anchor.RightBottom)): pos.setX(pos.x() - self.width()) # MODIFY Y POSITION # align y-top if (anchor & (XPopupWidget.Anchor.LeftTop | XPopupWidget.Anchor.RightTop)): pos.setY(pos.y() - pad) # align y-center elif (anchor & (XPopupWidget.Anchor.LeftCenter | XPopupWidget.Anchor.RightCenter)): pos.setY(pos.y() - self.height() / 2) # align y-bottom elif (anchor & (XPopupWidget.Anchor.LeftBottom | XPopupWidget.Anchor.RightBottom)): pos.setY(pos.y() - self.height() + pad) # align y-padded elif ( anchor & (XPopupWidget.Anchor.BottomLeft | XPopupWidget.Anchor.BottomCenter | XPopupWidget.Anchor.BottomRight)): pos.setY(pos.y() - self.height()) self.adjustMask() self.move(pos) self.update() self.setUpdatesEnabled(True) if self.isAnimated(): anim = QPropertyAnimation(self, 'windowOpacity') anim.setParent(self) anim.setStartValue(0.0) anim.setEndValue(self.windowOpacity()) anim.setDuration(500) anim.finished.connect(anim.deleteLater) self.setWindowOpacity(0.0) else: anim = None self.show() if self.currentMode() != XPopupWidget.Mode.ToolTip: self.activateWindow() widget = self.centralWidget() if widget: self.centralWidget().setFocus() if anim: anim.start() if not self.signalsBlocked(): self.shown.emit() return True def paintEvent(self, event): """ Overloads the paint event to handle painting pointers for the popup \ mode. :param event | <QPaintEvent> """ # use the base technique for the dialog mode if self.currentMode() == XPopupWidget.Mode.Dialog: super(XPopupWidget, self).paintEvent(event) return # setup the coloring options palette = self.palette() painter = QPainter() painter.begin(self) pen = QPen(palette.color(palette.Window).darker(130)) pen.setWidthF(1.75) painter.setPen(pen) painter.setRenderHint(painter.Antialiasing) painter.setBrush(palette.color(palette.Window)) painter.drawPath(self.borderPath()) painter.end() def popupPadding(self): """ Returns the amount of pixels to pad the popup arrow for this widget. :return <int> """ return self._popupPadding def positionLinkedTo(self): """ Returns the widget that this popup is linked to for positional changes. :return [<QWidget>, ..] """ return self._positionLinkedTo @qt.Slot() def reject(self): """ Emits the accepted signal and closes the popup. """ if not self.signalsBlocked(): self.rejected.emit() if self.autoCloseOnReject(): self.close() def resizeEvent(self, event): """ Resizes this widget and updates the mask. :param event | <QResizeEvent> """ self.setUpdatesEnabled(False) super(XPopupWidget, self).resizeEvent(event) self.adjustMask() self.setUpdatesEnabled(True) x = self.width() - self._sizeGrip.width() y = self.height() - self._sizeGrip.height() self._leftSizeGrip.move(0, y) self._sizeGrip.move(x, y) def scrollArea(self): """ Returns the scroll area widget for this popup. :return <QScrollArea> """ return self._scrollArea def setAnimated(self, state): """ Sets whether or not the popup widget should animate its opacity when it is shown. :param state | <bool> """ self._animated = state self.setAttribute(Qt.WA_TranslucentBackground, state) def setAutoCloseOnAccept(self, state): """ Sets whether or not the popup handles closing for accepting states. :param state | <bool> """ self._autoCloseOnAccept = state def setAutoCloseOnReject(self, state): """ Sets whether or not the popup handles closing for rejecting states. :param state | <bool> """ self._autoCloseOnReject = state def setAutoDefault(self, state): """ Sets whether or not the buttons should respond to defaulting options when the user is interacting with it. :param state | <bool> """ self._autoDefault = state for button in self.buttonBox().buttons(): button.setAutoDefault(state) button.setDefault(state) def setAnchor(self, anchor): """ Sets the anchor position for this popup widget to the inputed point. :param anchor | <XPopupWidget.Anchor> """ self._anchor = anchor self.adjustContentsMargins() def setAutoCalculateAnchor(self, state): """ Sets whether or not this widget should auto-calculate the anchor point based on the parent position when the popup is triggered. :param state | <bool> """ self._autoCalculateAnchor = state def setAutoCloseOnFocusOut(self, state): """ Sets whether or not this popup widget should auto-close when the user clicks off the view. :param state | <bool> """ self._autoCloseOnFocusOut = state self.updateModeSettings() def setCentralWidget(self, widget): """ Sets the central widget that will be used by this popup. :param widget | <QWidget> || None """ self._scrollArea.takeWidget() self._scrollArea.setWidget(widget) self.adjustSize() def setCurrentMode(self, mode): """ Sets the current mode for this dialog to the inputed mode. :param mode | <XPopupWidget.Mode> """ if (self._currentMode == mode): return self._currentMode = mode self.updateModeSettings() @qt.Slot() def setDialogMode(self): """ Sets the current mode value to Dialog. """ self.setCurrentMode(XPopupWidget.Mode.Dialog) @deprecatedmethod('XPopupWidget', 'Direction is no longer used, use setAnchor instead') def setDirection(self, direction): """ Sets the direction for this widget to the inputed direction. :param direction | <XPopupWidget.Direction> """ if (direction == XPopupWidget.Direction.North): self.setAnchor(XPopupWidget.Anchor.TopCenter) elif (direction == XPopupWidget.Direction.South): self.setAnchor(XPopupWidget.Anchor.BottomCenter) elif (direction == XPopupWidget.Direction.East): self.setAnchor(XPopupWidget.Anchor.LeftCenter) else: self.setAnchor(XPopupWidget.Anchor.RightCenter) def setPalette(self, palette): """ Sets the palette for this widget and the scroll area. :param palette | <QPalette> """ super(XPopupWidget, self).setPalette(palette) self._scrollArea.setPalette(palette) def setPopupMode(self): """ Sets the current mode value to Popup. """ self.setCurrentMode(XPopupWidget.Mode.Popup) def setPopupPadding(self, padding): """ Sets the amount to pad the popup area when displaying this widget. :param padding | <int> """ self._popupPadding = padding self.adjustContentsMargins() def setPositionLinkedTo(self, widgets): """ Sets the widget that this popup will be linked to for positional changes. :param widgets | <QWidget> || [<QWidget>, ..] """ if type(widgets) in (list, set, tuple): new_widgets = list(widgets) else: new_widgets = [] widget = widgets while widget: widget.installEventFilter(self) new_widgets.append(widget) widget = widget.parent() self._positionLinkedTo = new_widgets def setResizable(self, state): self._resizable = state self._sizeGrip.setVisible(state) self._leftSizeGrip.setVisible(state) def setShowButtonBox(self, state): self._buttonBoxVisible = state self.buttonBox().setVisible(state) def setShowTitleBar(self, state): self._titleBarVisible = state self._dialogButton.setVisible(state) self._closeButton.setVisible(state) def setToolTipMode(self): """ Sets the mode for this popup widget to ToolTip """ self.setCurrentMode(XPopupWidget.Mode.ToolTip) def setVisible(self, state): super(XPopupWidget, self).setVisible(state) widget = self.centralWidget() if widget: widget.setVisible(state) def timerEvent(self, event): """ When the timer finishes, hide the tooltip popup widget. :param event | <QEvent> """ if self.currentMode() == XPopupWidget.Mode.ToolTip: self.killTimer(event.timerId()) event.accept() self.close() else: super(XPopupWidget, self).timerEvent(event) def updateModeSettings(self): mode = self.currentMode() is_visible = self.isVisible() # display as a floating dialog if mode == XPopupWidget.Mode.Dialog: self.setWindowFlags(Qt.Dialog | Qt.Tool) self.setAttribute(Qt.WA_TransparentForMouseEvents, False) self._closeButton.setVisible(False) self._dialogButton.setVisible(False) # display as a user tooltip elif mode == XPopupWidget.Mode.ToolTip: flags = Qt.Popup | Qt.FramelessWindowHint self.setWindowFlags(flags) self.setBackgroundRole(QPalette.Window) self.setAttribute(Qt.WA_TransparentForMouseEvents) self.setShowTitleBar(False) self.setShowButtonBox(False) self.setFocusPolicy(Qt.NoFocus) # hide the scrollbars policy = Qt.ScrollBarAlwaysOff self._scrollArea.setVerticalScrollBarPolicy(policy) self._scrollArea.setHorizontalScrollBarPolicy(policy) # display as a popup widget else: flags = Qt.Popup | Qt.FramelessWindowHint if not self.autoCloseOnFocusOut(): flags |= Qt.Tool self.setWindowFlags(flags) self._closeButton.setVisible(self._titleBarVisible) self._dialogButton.setVisible(self._titleBarVisible) self.setBackgroundRole(QPalette.Button) self.adjustContentsMargins() if (is_visible): self.show() @staticmethod @deprecatedmethod('XPopupWidget', 'This method no longer has an effect as we are not '\ 'storing references to the tooltip.') def hideToolTip(key=None): """ Hides any existing tooltip popup widgets. :warning This method is deprecated! """ pass @staticmethod def showToolTip(text, point=None, anchor=None, parent=None, background=None, foreground=None, key=None, seconds=5): """ Displays a popup widget as a tooltip bubble. :param text | <str> point | <QPoint> || None anchor | <XPopupWidget.Mode.Anchor> || None parent | <QWidget> || None background | <QColor> || None foreground | <QColor> || None key | <str> || None seconds | <int> """ if point is None: point = QCursor.pos() if parent is None: parent = QApplication.activeWindow() if anchor is None and parent is None: anchor = XPopupWidget.Anchor.TopCenter # create a new tooltip widget widget = XPopupWidget(parent) widget.setToolTipMode() widget.setResizable(False) # create the tooltip label label = QLabel(text, widget) label.setOpenExternalLinks(True) label.setAlignment(Qt.AlignLeft | Qt.AlignVCenter) label.setMargin(3) label.setIndent(3) label.adjustSize() widget.setCentralWidget(label) # update the tip label.adjustSize() widget.adjustSize() palette = widget.palette() if not background: background = palette.color(palette.ToolTipBase) if not foreground: foreground = palette.color(palette.ToolTipText) palette.setColor(palette.Window, QColor(background)) palette.setColor(palette.WindowText, QColor(foreground)) widget.setPalette(palette) widget.centralWidget().setPalette(palette) if anchor is None: widget.setAutoCalculateAnchor(True) else: widget.setAnchor(anchor) widget.setAutoCloseOnFocusOut(True) widget.setAttribute(Qt.WA_DeleteOnClose) widget.popup(point) widget.startTimer(1000 * seconds) return widget
class WellPlotMPL(QtCore.QObject): def __init__(self, logs, well, logSet=None, parent=None): super(WellPlotMPL, self).__init__(parent) self._well = well self._logSet = logSet self._logs = logs self.plots = [] self.canvas = None self.depthPlot = None self.headerPlot = None centralWidget = centraltabwidget.CentralTabWidget() #id(self) returns the 'hash' of this object self.uid = (centralWidget.count(), id(self)) self.wellPlotSignals = WellPlotSignals() self.setupUI() self.createTabView() self.connectSlots() self.plotMultiLogs() self.setSplitterStretch() self.createToolWidget() def setupUI(self): self.mainWidget = WellPlotWidget() vBox = QtGui.QVBoxLayout() self.mainWidget.setLayout(vBox) self.headerWidget = QWidget() self.headerLayout = QtGui.QHBoxLayout() self.headerWidget.setLayout(self.headerLayout) self.dataWidget = QWidget() self.dataLayout = QtGui.QHBoxLayout() self.dataWidget.setLayout(self.dataLayout) #if don't set a minimum, get matplotlib error when is very small self.dataWidget.setMinimumHeight(self.getMinimumVerticalHeight()) self.splitter = QSplitter(QtCore.Qt.Vertical) self.headerScrollArea = QScrollArea() self.headerScrollArea.setVerticalScrollBarPolicy( QtCore.Qt.ScrollBarAlwaysOn) self.headerScrollArea.setHorizontalScrollBarPolicy( QtCore.Qt.ScrollBarAlwaysOff) self.headerScrollArea.setWidgetResizable(False) self.headerScrollArea.setWidget(self.headerWidget) self.scrollArea = QScrollArea() self.scrollArea.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOn) self.scrollArea.setHorizontalScrollBarPolicy( QtCore.Qt.ScrollBarAlwaysOn) self.scrollArea.setWidgetResizable(False) self.scrollArea.setWidget(self.dataWidget) #see http://stackoverflow.com/questions/29583927/pyqt-qscrollarea-within-qscrollarea/29584939#29584939 self.scrollArea.horizontalScrollBar().valueChanged.connect( self.headerScrollArea.horizontalScrollBar().setValue) self.splitter.addWidget(self.headerScrollArea) self.splitter.addWidget(self.scrollArea) self.splitter.setStretchFactor(1, 10) vBox.addWidget(self.splitter) def getMinimumVerticalHeight(self): screenRect = QtGui.QDesktopWidget().screenGeometry() #need to set a minimum size otherwise get matplotlib error when rezizing to too small twentythOfScreen = int(round(screenRect.width() / 20)) return twentythOfScreen def plotMultiLogs(self): logPlotModelAccess = WellPlotModelAccess() logPlotData = logPlotModelAccess.createWellPlotData(self._logs) self.createCanvas(logPlotData) self.plotHeaderFields(logPlotData) def createCanvas(self, logPlotData): logger.debug(">>createCanvas()") #test for subPlotData in logPlotData.sub_plots: logger.debug( "--createCanvas() plot_index:{0} track_width:{1} track_gap:{2}" .format(subPlotData.plot_index, subPlotData.track_width, subPlotData.track_gap)) for log in subPlotData._logs: logger.debug("--createCanvas id:{0}, name:{1}".format( log.id, log.name)) #end test if len(logPlotData.sub_plots) > 0: WidgetUtils.removeWidgets(self.dataLayout) #test #time.sleep(1) # delays for 1 second #end test #There may be a better way to link plots with the toolbar self.mainWidget.setLogPlotData(logPlotData) self.depthPlot = DepthAxis(logPlotData, self.dataWidget) self.dataLayout.addWidget(self.depthPlot) self.canvas = MultiLogCanvas(logPlotData, self.dataWidget) self.canvas.setAutoFillBackground(True) self.dataLayout.addWidget(self.canvas) spacerItem = QtGui.QSpacerItem(40, 20, QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Minimum) self.dataLayout.addItem(spacerItem) else: logger.error("--plotMultiLogs() Error: no logs to plot") if AppSettings.isDebugMode: raise ValueError def plotHeaderFields(self, logPlotData): logger.debug(">>plotMultiLogs()") WidgetUtils.removeWidgets(self.headerLayout) self.headerPlot = HeaderPlotMPL(depthPlot=self.depthPlot, mainPlot=self.canvas, logPlotData=logPlotData) self.headerLayout.addWidget(self.headerPlot) def setSplitterStretch(self): #Minimum size is required for the QScrollArea.setWidgetResizable(False) setting''' headerW = self.headerPlot.width() headerH = self.headerPlot.height() self.headerWidget.setMinimumSize(headerW, headerH) #test (totalW, dataH) = MplUtils.calcFigCanvasWidthHeight(self.canvas.figure) #end test dWidth, dHeight = self.canvas.figure.canvas.get_width_height() self.dataWidget.setMinimumSize(dWidth, dHeight) def connectSlots(self): logger.debug(">>connectSlots") self.wellPlotSignals.logPlotSettingsModified.connect(self.replotLogs) @pyqtSlot(WellPlotData) def replotLogs(self, logPlotData): logger.debug(">>replotLogs len(logPlotData.sub_plots): " + str(len(logPlotData.sub_plots))) #check uid's before accessing them, where uid is a (number widgets in central widget, id) tuple logger.debug( "--replotLogs() len(self.uid):{0}, len(logPlotData.uid):{1}". format(len(self.uid), len(logPlotData.uid))) if (len(self.uid) == 2) and (len(logPlotData.uid) == 2): #ensure this object is associated with the plot object if self.uid[0] == logPlotData.uid[0] and self.uid[ 1] == logPlotData.uid[1]: logger.debug("--replotLogs() match found uid: " + str(self.uid[0])) self.createCanvas(logPlotData) self.plotHeaderFields(logPlotData) def spacePlots(self, bottomLayout): rightSpacer = QtGui.QWidget() rightSpacer.setSizePolicy(QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Expanding) #topLayout.addWidget(rightSpacer) bottomLayout.addWidget(rightSpacer) #self.topWidget.setLayout(topLayout) self.dataWidget.setLayout(bottomLayout) def createTabView(self): centralWidget = centraltabwidget.CentralTabWidget() self.mainWidget.setData(self.uid) #centralWidget.addTab(self.scrollArea, "Well plot "+str(self.uid[0])) centralWidget.addTab(self.mainWidget, "Well plot " + str(self.uid[0])) def createToolWidget(self): if len(self._logs) > 0: toolbar = logsettingstoolbar.LogSettingsToolbar() toolbar.setData(self._well, self._logSet, self.canvas, self.depthPlot, self.headerPlot) toolbar.emitShowToolbarSignal() logger.debug("<<createToolWidget() toolbar created")
if __name__ == '__main__': from PyQt4.QtCore import Qt from PyQt4.QtGui import QApplication, QSlider, QScrollArea from PyQt4.QtGui import QPushButton, QWidget, QVBoxLayout app = QApplication([]) widget = QWidget() Layout = QVBoxLayout(widget) for i in range(10): button = QPushButton('button %i' % i, widget) Layout.addWidget(button) widget.setFixedSize(600, 800) widget.show() scrollarea = QScrollArea() scrollarea.setWidget(widget) scrollarea.resize(300, 300) scrollarea.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOn) scrollarea.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOn) scrollarea.show() scroller = PreviewScroller(scrollarea) scroller.resize(400, 400) scroller.show() app.exec_()
class DeviceOrderWidget(QWidget): def __init__(self, parent=None): QWidget.__init__(self, parent) self.section = None self.deviceWidgets = list() self.setMinimumWidth(520) self.setMinimumHeight(600) self.iconAssigner = IconAssigner() self.setupLayout() self.setupScrollArea() # self.addNewDeviceWidget(device = Device("ABC", None, None)) # self.addNewDeviceWidget(device = Device("XD", None, None)) # self.addNewDeviceWidget(device = Device("1313XD", None, None)) # self.addNewDeviceWidget(device = Device(":-(", None, None)) def setupLayout(self): self.containerWidget = QWidget(self) self.widgetHeight = 0 self.containerWidget.setGeometry(QRect(0,0,451,self.widgetHeight)) self.layout = QVBoxLayout() self.containerWidget.setLayout(self.layout) def setupScrollArea(self): self.scrollArea = QScrollArea(self) self.scrollArea.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAsNeeded) self.scrollArea.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff) self.scrollArea.setMaximumWidth(530) self.scrollArea.setMinimumHeight(600) self.scrollArea.setWidgetResizable(False) self.scrollArea.setWidget(self.containerWidget) def setSection(self, section): self.section = section devices = section.devices devices = sorted(devices, key=lambda device: device.getShortName()) for device in devices: self.addNewDeviceWidget(device) def addNewDeviceWidget(self, device=None): newWidget = DeviceWidget(self, device = device) newWidget.position = len(self.deviceWidgets) iconPath = self.iconAssigner.getIconPath(device) newWidget.deviceIcon.setIcon(iconPath) self.deviceWidgets.append(newWidget) self.layout.addWidget(newWidget) self.widgetHeight += 70 self.containerWidget.resize(530, self.widgetHeight) self.connect(newWidget, QtCore.SIGNAL("up()"), self.upWidget) self.connect(newWidget, QtCore.SIGNAL("down()"), self.downWidget) def upWidget(self): widget = self.sender() if widget.position > 0: self.swap(widget.position, widget.position-1) def downWidget(self): widget = self.sender() if widget.position < len(self.deviceWidgets)-1: self.swap(widget.position, widget.position+1) def swap(self, first, second): firstWidget = self.deviceWidgets[first] secondWidget = self.deviceWidgets[second] firstWidget.position = second secondWidget.position = first self.layout.removeWidget(firstWidget) self.layout.removeWidget(secondWidget) self.deviceWidgets.remove(firstWidget) self.deviceWidgets.remove(secondWidget) if first > second: self.layout.insertWidget(second, firstWidget) self.layout.insertWidget(first, secondWidget) self.deviceWidgets.insert(second, firstWidget) self.deviceWidgets.insert(first, secondWidget) else: self.layout.insertWidget(first, secondWidget) self.layout.insertWidget(second, firstWidget) self.deviceWidgets.insert(first, secondWidget) self.deviceWidgets.insert(second, firstWidget) def getSortedDevices(self): devices = list() for deviceWidget in self.deviceWidgets: devices.append(deviceWidget.device) return devices