示例#1
0
def askResetBind():
    """
    Dialogue qui demande quelle binding retrouver
    @return binding : <str> "defaut" -> cherche le binding par défaut
                            "custom" -> cherche l'ancien binding de l'utilisateur
                            "vide"   -> retire le binding ""
                      <None> -> annule l'opération
    """
    binding = None

    def onClose(btn):
        nonlocal binding
        if btn == "Annuler":
            pass
        elif btn == "Par défaut":
            binding = "defaut"
        elif btn == "Précédent":
            binding = "custom"
        elif btn == "Vide":
            binding = "vide"

        fen.destroy()

    fen = Dialog(title="Choix du raccourci",
                 buttons=("Précédent", "Par défaut", "Vide", "Annuler"),
                 command=onClose,
                 exitButton=("Précédent", "Par défaut", "Vide", "Annuler"))
    Label(fen,
          text="Quelle est le raccourci que vous voulez retrouver ?").pack(
              expand=YES, fill=BOTH, padx=2, pady=2)

    fen.activateandwait()
    return binding
示例#2
0
def askRestart():
    """
    Dialog qui demande si l'utilisateur veut redemarrer l'application
    """
    restart = None

    def Onclose(button):
        nonlocal restart
        if button == "Redémarrer":
            restart = True
        elif button == "Redémarrer plus tard" or button == 'WM_DELETE_WINDOW':
            restart = False
        else:
            restart = False

    f = Dialog(master=None,
               title="Redémarrage requis",
               buttons=("Redémarrer", "Redémarrer plus tard"),
               defaultbutton="Redémarrer",
               exitButton=("Redémarrer", "Redémarrer plus tard",
                           'WM_DELETE_WINDOW'),
               command=Onclose)

    l = Label(
        f,
        text=
        "Une ou plusieurs de vos modifications nécéssitent un redémarrage\nde l'applicationpour être correctement appliquées.\n\nVoulez-vous redémarrer l'application maintenant ?"
    )
    l.pack()

    f.activateandwait()
    return restart
示例#3
0
def askGroup(periode):
    """
    Permet de demander à l'utilisateur les informations nécessaires pour créer un groupe.
    @param periode: La période dans laquelle sera le groupe.
    """
    # Variables :
    groupe = None
    nom = None
    desc = None
    color = None

    # Callback :
    def onClose(button):
        nonlocal groupe, nom, desc, color
        nom = nomWidget.get()
        desc = descWidget.get("0.0", END)
        color = colorWidget.get()
        if button == "Ok":
            if not nom:
                showerror("Nom incorrect", "Vous devez nommer le groupe.")
            else:
                groupe = Groupe(nom, periode, desc, color)
                fen.destroy()

    # Dialogue :
    fen = Dialog(title="Ajouter un groupe",
                 buttons=("Ok", "Annuler"),
                 exitButton=("Annuler", "WM_DELETE_WINDOW"),
                 command=onClose)

    # Widgets :
    nomGroupe = LabelFrame(fen, text="Nom")
    descGroupe = LabelFrame(fen, text="Description")
    nomWidget = Entry(nomGroupe)
    colorWidget = ColorButton(nomGroupe)
    descWidget = Text(descGroupe, wrap="word")

    # Placements :
    descGroupe.pack(side=BOTTOM, expand=YES, fill=BOTH)
    nomGroupe.pack(side=TOP, expand=YES, fill=X)

    nomWidget.pack(side=LEFT, fill=X, expand=YES)
    colorWidget.pack(side=RIGHT)
    descWidget.pack(expand=YES, fill=BOTH)

    # Activation :
    fen.activateandwait()

    # Retour :
    return groupe
示例#4
0
def askDureeJours():
    duree = None
    def onClose(button):
        nonlocal duree
        if button == "Ok":
            duree = datetime.timedelta(**{{"Semaines":"weeks", "Jours": "days"}[unit.get()]:int(delta.get())})
        fen.destroy()
    
    fen = Dialog(title = "Décaler des périodes", buttons = ("Ok", "Annuler"), command = onClose)
    delta = Spinbox(fen, from_ = 0, to = 1000)
    delta.pack(side = LEFT, expand = YES, fill = X)
    delta.set(0)
    unit = Combobox(fen, values = ["Jours", "Semaines"])
    unit.set(unit.cget("values")[0])
    unit.pack(side = RIGHT, expand = YES, fill = X)
    
    fen.activateandwait()

    return duree
示例#5
0
def askEditGroupe(groupe):
    """
    Dialogue qui édite le groupe sur ses paramètres
    @param groupe : <Groupe> le groupe à modifier
    """
    def onClose(button):
        if button == "Ok":
            paramGroupe.onClose()
        elif button == "Supprimer":
            groupe.delete()
        # Pendant qu'on a encore le droit de l'utiliser
        groupe.getApplication().getDonneeCalendrier().updateAffichage(True)
        fen.destroy()

    fen = Dialog(title="Édition de \"%s\"" % groupe.getNom(),
                 buttons=("Ok", "Supprimer", "Annuler"),
                 exitButton=("Ok", "Supprimer", "Annuler"),
                 command=onClose)
    paramGroupe = GroupeParametre(fen, groupe)
    paramGroupe.pack(fill=BOTH, expand=YES)
    fen.activateandwait()
示例#6
0
def askAfficherMasquer(periodManager):
    """
    Dialogue qui permet de gérer la visibilitée des schedulables
    @param periodManager : <PeriodManager> celui de l'app
    @return masquage : <bool> True si au moins une tache n'est pas visible
    """
    masquage = False

    def onClose(b):
        nonlocal masquage
        if b == "Ok":
            masquage = gestion.onClose(b)
        fen.destroy()

    fen = Dialog(title="Afficher ou masquer des taches",
                 buttons=("Ok", "Annuler"),
                 command=onClose)
    gestion = AfficherMasquer(fen, periodManager)
    gestion.pack(fill=BOTH, expand=YES)

    fen.activateandwait()
    return masquage
示例#7
0
def askdate():
    """
    Permet d'ouvrir une boîte de dialogue usuelle pour demander
    la date (et pas l'heure) à l'utilisateur.
    @return datetime.date() choisie par l'utilisateur ou None
    """
    # Variable qui contient la valeur de retour :
    dateretour = None

    # Callback quand on ferme la fenêtre par l'un des boutons :
    def onClose(a):
        nonlocal dateretour

        # Si on annule :
        if a == 'Annuler' or a == 'WM_DELETE_WINDOW':
            fen.destroy()
            return

        # Si on accepte :
        if cal.selection is not None:
            dateretour = cal.selection.date()
        # on ferme la fenêtre.
        fen.destroy()

    # Construction du dialogue :
    fen = Dialog(title="Choix de la date",
                 buttons=("Ok", "Annuler"),
                 command=onClose)
    # création des widgets :
    cal = Calendar(master=fen, firstweekday=calendar.MONDAY)
    # placement des widgets :
    cal.pack(expand=1, fill='both')

    # et on active le dialogue.
    fen.activateandwait()
    return dateretour
示例#8
0
def askEditTask(task):
    """
    Dialogue qui édite la tache sur ses paramètres
    @param task : <Task> la tache à modifier
    """
    def onClose(button):
        if button == "Ok":
            taskUndo = task.saveByDict()
            parametrage.onClose()
            UndoRedoTaskEditing(taskUndo, task)
        elif button == "Supprimer":
            task.delete()

        # Pendant qu'on a encore le droit de l'utiliser
        task.getApplication().getDonneeCalendrier().updateAffichage(True)
        fen.destroy()

    fen = Dialog(title="Édition de \"%s\"" % task.getNom(),
                 buttons=("Ok", "Supprimer", "Annuler"),
                 exitButton=("Ok", "Supprimer", "Annuler"),
                 command=onClose)
    parametrage = TaskParametre(fen, task)
    parametrage.pack(fill=BOTH, expand=YES)
    fen.activateandwait()
示例#9
0
def askDupliquerPeriode(periodManager, taskEditor, from_=None):
    from affichages.periode.Periode import Periode
    from ..PeriodAdder import PeriodAdder

    per = from_

    def onClose(button):
        if button == "Ajouter":
            periode = p.createPeriode()

            ## Ajout des schedulables et autres :
            # Il faut en faire une copie,
            # Mais pour éviter tout les soucis de non copies en profondeur
            # (je pense notamment aux dépendances qui pourrait alors se trouver dans une autre période...)
            # on va faire une "sauvegarde-lecture" dans la RAM.
            data = per.saveByDict()
            newPeriode = Periode.load(data, periodManager)
            # Puis on remet les attributs :
            newPeriode.setNom(periode.getNom())
            newPeriode.setDebut(periode.getDebut())
            newPeriode.setFin(periode.getFin())
            newPeriode.setDescription(periode.getDescription())
            newPeriode.setColor(periode.getColor())
            newPeriode.setUniqueID()
            periodManager.ajouter(newPeriode)

    fen = Dialog(command=onClose,
                 buttons=("Ajouter", "Fermer"),
                 exitButton=("Fermer", "WM_DELETE_WINDOW"))

    fen.redessiner = taskEditor.redessiner
    fen.ajouter = taskEditor.ajouter
    fen.getApplication = taskEditor.getApplication

    p = PeriodAdder(periodManager, fen)
    p.pack(expand=YES, fill=BOTH)
    p.boutonValider.grid_forget()

    # Ajouter les champs déjà rempli si on a une période :
    if per is not None:
        p.debut = per.getDebut()
        p.fin = per.getFin()
        p.champNom.insert(END, per.nom)
        p.champDebut.config(text=p.debut)
        p.champFin.config(text=p.fin)
        p.champDescription.insert(END, per.desc)
        p.boutonColor.set(per.color)

    fen.activateandwait()
示例#10
0
def askModifierPeriode(periodManager, taskEditor, from_=None):
    from ..PeriodAdder import PeriodAdder

    per = from_

    def onClose(button):
        if button == "Modifier":
            # La création d'une période permettra de récupérer ses attributs.
            # Cependant, cette période est temporaire au calcul et n'est pas
            # ajoutée au PeriodManager.
            periode = p.createPeriode()

            # Puis on remet les attributs :
            per.setNom(periode.getNom())
            per.setDebut(periode.getDebut())
            per.setFin(periode.getFin())
            per.setDescription(periode.getDescription())
            per.setColor(periode.getColor())

    fen = Dialog(command=onClose,
                 buttons=("Modifier", "Annuler"),
                 exitButton=("Modifier", "Annuler", "Fermer",
                             "WM_DELETE_WINDOW"))

    # Pour faire croire au PeriodAdder que le Dialog est le TaskEditor.
    fen.redessiner = taskEditor.redessiner
    fen.ajouter = taskEditor.ajouter
    fen.getApplication = taskEditor.getApplication

    p = PeriodAdder(periodManager, fen)
    p.pack(expand=YES, fill=BOTH)
    p.boutonValider.grid_forget()

    # Ajouter les champs déjà rempli si on a une période :
    if per is not None:
        p.debut = per.getDebut()
        p.fin = per.getFin()
        p.champNom.insert(END, per.nom)
        p.champDebut.config(text=p.debut)
        p.champFin.config(text=p.fin)
        p.champDescription.insert(END, per.desc)
        p.boutonColor.config(bg=per.color)

    fen.activateandwait()
示例#11
0
def askComplicationjour(tache, periodeManager):
    choix = None
    periode = None

    def onClose(bouton):
        # Permet de modifier les valeurs des variables
        nonlocal choix, periode
        if bouton == 'Ok':
            choix = varRadio.get()
            if choix == "changer":
                for p in periodeManager.getPeriodes():
                    if p.nom == combo.get():
                        periode = p
        fen.destroy()

    def stateCombobox():
        if varRadio.get() == "changer":
            combo.config(state=ACTIVE)
        else:
            combo.config(state=DISABLED)

    fen = Dialog(title="%s n'est pas dans la période active" % tache.getNom(),
                 buttons=("Ok", "Annuler"),
                 command=onClose,
                 exitButton=('Ok', 'Annuler', "WM_DELETE_WINDOW"))

    # Binding des touches
    fen.bind_all("<Return>", lambda e: fen.execute("Ok"))
    fen.bind_all("<Escape>", lambda e: fen.execute("Annuler"))

    l = Label(
        fen,
        text=
        "La tache \"%s\" se trouve maintenant hors de la période. Que voulez-vous faire ?"
        % tache.getNom())

    frameRadio = LabelFrame(fen, text="Options")
    varRadio = StringVar()
    r1 = Radiobutton(frameRadio,
                     text="Agrandir la période",
                     value="agrandir",
                     variable=varRadio,
                     command=stateCombobox)
    r2 = Radiobutton(frameRadio,
                     text="Faire de %s une tache indépendante" %
                     tache.getNom(),
                     value="independante",
                     variable=varRadio,
                     command=stateCombobox)
    r3 = Radiobutton(frameRadio,
                     text="Supprimer %s." % tache.getNom(),
                     value="supprimer",
                     variable=varRadio,
                     command=stateCombobox)
    r4 = Radiobutton(frameRadio,
                     text="Changer la période de %s." % tache.getNom(),
                     value="changer",
                     variable=varRadio,
                     command=stateCombobox)
    # valeur par défaut :
    varRadio.set("agrandir")

    r1.grid(sticky="w")
    r2.grid(row=1, sticky="w")
    r3.grid(row=2, sticky="w")
    r4.grid(row=3, sticky="w")

    periodesExistantes = periodeManager.getPeriodes()
    pp = Periode(periodeManager, "",
                 tache.getDebut().date(),
                 tache.getFin().date(), "")
    periodesExistantes = [
        p.nom for p in periodesExistantes if p.intersectWith(pp)
    ]
    combo = Combobox(frameRadio, values=periodesExistantes)

    combo.grid(row=3, column=1, sticky="we")
    if periodesExistantes:
        combo.set(combo.cget("values")[0])
    else:
        combo.config(state=DISABLED)
        r4.config(state=DISABLED)

    l.pack()
    frameRadio.pack(expand=YES, fill=BOTH, pady=4, padx=4)

    # Active et attend (un peu comme une mainloop)
    fen.activateandwait()
    return choix, periode
示例#12
0
def askDecalJour(debut, fin, totBloque, tarBloque):
    """
    Dialog pour demander comment décaler les tâches
    @param debut     : (date) jour de début de la période
    @param fin       : (date) jour de fin de la période
    @param totBloque : (int) nombre de jours à partir duquel le blocage devient utile
    @param tarBloque : (int) nombre de jours à partir duquel le blocage devient utile
    """
    nbJour = None
    position = None
    param = None

    def onClose(bouton):
        # Permet de modifier les valeurs des variables
        nonlocal nbJour, position, param
        if bouton == 'Ok':
            position = varRadioGestion.get()
            param = varRadioParam.get()
            nbJour = int(sb.get())
            if varRadioGestion.get() == "tot":
                nbJour = nbJour * -1
        fen.destroy()

    # Pour adapter le nombre d'jour max du spinBoc
    def adapteSpinbox():
        newVar = 0
        if varRadioGestion.get() == "tot" and varRadioParam.get() == "bloquer":
            newVar = totBloque
        elif varRadioGestion.get() == "tard" and varRadioParam.get(
        ) == "bloquer":
            newVar = tarBloque
        elif varRadioGestion.get() == "tot" or varRadioGestion.get() == "tard":
            newVar = "+inf"

        # On config
        sb.config(to=newVar)
        # Si on dépasse, on reset au max
        if isinstance(newVar, str):
            return
        if int(sb.get()) > newVar:
            sb.set(int(newVar))

    fen = Dialog(title="Nombre de jours à déplacer",
                 buttons=("Ok", "Annuler"),
                 command=onClose,
                 exitButton=('Ok', 'Annuler', "WM_DELETE_WINDOW"))
    # Binding des touches
    fen.bind_all("<Return>", lambda e: fen.execute("Ok"))
    fen.bind_all("<Escape>", lambda e: fen.execute("Annuler"))

    # Mettre les widgets
    framePos = Frame(fen)
    varRadioGestion = StringVar()
    rG1 = Radiobutton(framePos,
                      text="Déplacer plus tot",
                      variable=varRadioGestion,
                      value="tot",
                      command=adapteSpinbox)
    rG2 = Radiobutton(framePos,
                      text="Déplacer plus tard",
                      variable=varRadioGestion,
                      value="tard",
                      command=adapteSpinbox)
    rG1.grid(row=0, sticky="w")
    rG2.grid(row=1, sticky="w")

    frameJour = Labelframe(fen, text="Déplacer de combien de jours ?")
    lb = Label(frameJour, text="Nombre de jours :")
    sb = Spinbox(frameJour, from_=0, to="+inf")
    sb.set(0)
    lb.pack(side=LEFT, fill=BOTH)
    sb.pack(side=LEFT, fill=X, expand=YES)

    frameParametre = Frame(fen)
    varRadioParam = StringVar()
    rP1 = Radiobutton(frameParametre,
                      text="Garder la même durée entre chaque tache",
                      variable=varRadioParam,
                      value="duree",
                      command=adapteSpinbox)
    rP2 = Radiobutton(
        frameParametre,
        text="Garder les tâches entre le %02i/%02i et le %02i/%02i" %
        (debut.day, debut.month, fin.day, fin.month),
        variable=varRadioParam,
        value="bloquer",
        command=adapteSpinbox)
    rP1.grid(row=0, sticky="w")
    rP2.grid(row=1, sticky="w")

    framePos.pack(side=TOP, expand=YES, fill=BOTH)
    frameJour.pack(side=TOP, expand=YES, fill=BOTH)
    frameParametre.pack(side=TOP, expand=YES, fill=BOTH)

    varRadioGestion.set("tard")
    varRadioParam.set("duree")

    # Active et attend (un peu comme une mainloop)
    fen.activateandwait()
    return nbJour, position, param
示例#13
0
def askDureeTache(master, longueurPeriode):
    """
    Permet de demander la durée de la tâche à l'utilisateur.
    @param longueurPeriode = longueur de la periode
    @return la durée choisie par l'utilisateur.
    """
    # Fonction quand on ferme le dialogue :
    duree = None

    def onClose(bouton):
        """Exécutée quand l'un des boutons du dialogue est pressé."""
        nonlocal duree
        if bouton == "Ok":
            duree = datetime.timedelta(days=int(d.get()),
                                       hours=int(h.get()),
                                       minutes=int(m.get()))
            if duree > datetime.timedelta():
                fen.quit()
                fen.destroy()
            else:
                showerror("Durée invalide",
                          "Veuillez mettre une durée plus grande que 0.")
        else:
            fen.destroy()

    def adapteHeureJour():
        """Adaptation des heures et des jours quand on augmente ou diminue trop les heures ou les minutes."""
        minutes = int(m.get())
        heures = int(h.get())
        jours = int(d.get())

        while minutes >= 60:
            minutes -= 60
            heures += 1
        while minutes < 0:
            minutes += 60
            heures -= 1
        while heures >= 24:
            heures -= 24
            jours += 1
        while heures < 0:
            heures += 24
            jours -= 1
        jours = max(0, min(jours, longueurPeriode.days))

        m.set(minutes)
        h.set(heures)
        d.set(jours)

    # Création du dialogue :
    fen = Dialog(master,
                 title="Choix de la durée de la tâche",
                 buttons=("Ok", "Annuler"),
                 command=onClose,
                 exitButton=('Annuler', ))
    # Widgets du dialogue :
    Label(fen, text="Choisissez la durée de la Tâche").pack(side=TOP, fill=X)
    d = Spinbox(fen, from_=0, to=longueurPeriode.days, increment=1, width=4)
    d.pack(side=LEFT)
    Label(fen, text="Jours").pack(side=LEFT)
    h = Spinbox(fen,
                from_=-1,
                to=24,
                increment=1,
                width=4,
                command=adapteHeureJour)
    h.pack(side=LEFT)
    Label(fen, text="Heures").pack(side=LEFT)
    m = Spinbox(fen,
                from_=-1,
                to=60,
                increment=1,
                width=4,
                command=adapteHeureJour)
    m.pack(side=LEFT)
    Label(fen, text="Minutes").pack(side=LEFT)
    d.set(0)
    h.set(1)
    m.set(0)
    # lancement du dialogue:
    fen.activateandwait()
    return duree
示例#14
0
def askScinderPeriode(periodManager, taskEditor, periode=None):
    """
    """
    # Vérifications :
    if periode.getDebut() == periode.getFin():
        showerror(
            "Longueur de période invalide",
            "Il est impossible de scinder une période qui dure un seul jour.")
        raise ValueError(
            "Impossible de scinder une période qui dure un seul jour")

    def getDebut():
        return periode.getDebut() + datetime.timedelta(days=1)

    # Une période de 2 jours ne peut être coupé qu'entre les 2 jours,
    # donc le début de la 2ème période dure à partir du 2ème jour,
    # soit la fin de cette période. (on notera que la fonction permet justement d'ignorer le début,
    # étant donné qu'il est impossible de scinder le même jour que ça commence).
    if getDebut() == periode.getFin():
        return periode.getFin()

    # Variables à retourner :
    dateScindage = None

    # Fonction quand on appuie sur un bouton :
    def onClose(button):
        """
        Fonction quand on appuie sur un bouton.
        @param button: le texte du bouton appuyé.
        """
        nonlocal dateScindage
        if button == "Aujourd'hui":
            date = datetime.datetime.now().date()
            jour.set(date.day)
            if mois is not None:
                mois.set(MOIS[date.month - 1])
            if annee is not None:
                annee.set(date.year)
            return
        if button == "Ok":
            dateScindage = datetime.date(getAnnee(), getMois(), getJour())
        fen.destroy()

    def setJourCalendrier():
        date = cal.selection
        if date is not None:
            date = date.date()
            if date < getDebut() or date > periode.getFin():
                showerror(
                    "Date invalide",
                    "La date choisie est en dehors des limites de la période à scinder."
                )
                return
            jour.set(date.day)
            if mois is not None:
                mois.set(MOIS[date.month - 1])
            if annee is not None:
                annee.set(date.year)

    def adapteJours():
        min = 1
        max = tailleMois(getMois(), getAnnee())

        if getMois() == getDebut().month and getAnnee() == getDebut().year:
            min = getDebut().day
        if getMois() == periode.getFin().month and getAnnee(
        ) == periode.getFin().year:
            max = periode.getFin().day

        jour.config(from_=min, to=max)
        if getJour() < min:
            jour.set(min)
        if getJour() > max:
            jour.set(max)

    def adapteMois():
        if mois is not None:
            lesMois = set()
            for m in rangeMois(getDebut(), periode.getFin()):
                lesMois.add(m)
            lesVraisMois = []
            for indice, m in enumerate(MOIS):
                if indice + 1 in lesMois:
                    lesVraisMois.append(m)
            mois.config(values=lesVraisMois)
            if mois.get() not in lesVraisMois:
                mois.set(lesVraisMois[0])

    def adapte():
        adapteMois()
        adapteJours()

    def getJour():
        if not jour.get():
            jour.set(1)
        return int(jour.get())

    def getMois():
        if mois is None:
            return datetime.datetime.now().month
        return MOIS.index(mois.get()) + 1

    def getAnnee():
        if annee is None:
            return datetime.datetime.now().year
        if not annee.get():
            jour.set(getDebut().year)
        return int(annee.get())

    # Dialogue :
    hasAujourdhui = datetime.datetime.now().date() >= getDebut(
    ) and datetime.datetime.now().date() < periode.getFin()
    fen = Dialog(title="Scinder une période",
                 buttons=("Ok", "Annuler", "Aujourd'hui") if hasAujourdhui else
                 ("Ok", "Annuler"),
                 command=onClose)

    # Widgets :
    cal = Calendar(master=fen)
    cal.pack(expand=YES, fill=BOTH, side=TOP)
    cal._calendar.bind("<Button-1>", lambda e: setJourCalendrier(), add=True)

    Label(fen, text="Le :").pack(side=LEFT, fill=X)
    jour = Spinbox(fen, from_=1, to=31, command=adapte, width=4)
    jour.pack(side=LEFT, fill=X)

    if getDebut().year != periode.getFin().year or getDebut(
    ).month != periode.getFin().month:
        mois = Combobox(fen, values=MOIS, state="readonly", width=11)
        mois.bind("<<ComboboxSelected>>", lambda e: adapte())
        mois.pack(side=LEFT, fill=X)
    else:
        mois = None
        Label(fen, text=MOIS[getMois() - 1]).pack(side=LEFT, fill=X)

    if getDebut().year != periode.getFin().year:
        annee = Spinbox(fen,
                        from_=getDebut().year,
                        to=periode.getFin().year,
                        command=adapte,
                        width=6)
        annee.pack(side=LEFT, fill=X)
    else:
        annee = None
        Label(fen, text=getAnnee()).pack(side=LEFT, fill=X)

    adapte()

    # Activation du dialogue :
    fen.activateandwait()

    # renvoie des valeurs
    return dateScindage
示例#15
0
def askHeureExacte(master, region):
    """
    Permet de faire un dialogue à l'utilisateur
    lui demandant de confirmer l'heure exacte à laquelle
    la tâche rajoutée via Drag&Drop doit-être rajoutée.
    @param region: L'heure auparavant calculée.
    @return la nouvelle heure calculée.
    """
    heure1 = region.hour
    minute1 = region.minute

    def onClose(bouton):
        nonlocal region
        if bouton == "Reset":
            h.set(heure1)
            m.set(minute1)
            return
        if bouton == "Ok":
            heure2 = int(h.get())
            minute2 = int(m.get())
            region += datetime.timedelta(minutes=heure2 * 60 - heure1 * 60 +
                                         minute2 - minute1)
        else:
            region = None
        fen.destroy()

    def minutePres():
        if var.get():
            m.config(increment=1)
        else:
            m.config(increment=5)

    def adapteHeure():
        """Adapte les heures quand on augmente (ou diminue) trop les minutes."""
        minutes = int(m.get())
        heures = int(h.get())
        while minutes < 0:
            minutes += 60
            heures -= 1
        while minutes >= 60:
            minutes -= 60
            heures += 1
        heures += 24
        heures %= 24
        m.set(minutes)
        h.set(heures)

    fen = Dialog(master,
                 "Confirmez l'heure exacte", ("Ok", "Annuler", "Reset"),
                 command=onClose)
    Label(fen, text="Veuillez entrer l'heure exacte").pack(side=TOP,
                                                           expand=YES,
                                                           fill=BOTH)
    var = BooleanVar(value=False)
    c = Checkbutton(fen,
                    text="Précision à la minute près ?",
                    command=minutePres,
                    variable=var)
    c.pack(side=TOP, fill=X)
    Label(fen, text="Heure :").pack(side=LEFT)
    h = Spinbox(fen, from_=-1, to=24, increment=1, command=adapteHeure)
    h.pack(side=LEFT, fill=X, expand=YES)
    m = Spinbox(fen, from_=-5, to=64, increment=5, command=adapteHeure)
    m.pack(side=RIGHT, fill=X, expand=YES)
    Label(fen, text="Minute :").pack(side=RIGHT)
    onClose("Reset")
    fen.activateandwait()
    return region
示例#16
0
def askSeparateRepetitiveTask(task):
    """
    Dialogue qui gère les taches à répétitions (les jours à ne pas afficher et autres
    @param task : <Task> tache dont on gère les répétition
    """
    from ..Task import Task  # Import circulaire...

    def makeListDissociated():
        """
        Fonction qui génère la liste des répétition avec un jolie texte
        @return <list> un truc parfait pour le StringVar de la listeDate
        """
        listTemp = []  # variable temporaire pour améliorer la visibilité
        for numero in range(task.getNbRep()):
            if numero in task.getDissociated():  # on rajoute * si dissocié
                listTemp.append("*" + adaptDatetime(numero * task.getRep() +
                                                    task.getDebut()))
            else:
                listTemp.append(
                    adaptDatetime(numero * task.getRep() + task.getDebut()))
        return listTemp

    def manageOption(e=None):
        """
        Fonction qui gère les options des boutons
        Active/désactive scinder (on ne peut pas scinder le 1 jour de la répétition)
        Dissocier/associer en fonction de si la répétition à été dissocié ou pas
        @param e : <tkinter.event> inutilisé
        """
        selected = listBoxRepet.curselection()
        # Scinder
        if 0 in selected:
            btnScinder.config(state=DISABLED)
        else:
            btnScinder.config(state=ACTIVE)

        # Dissocier
        # Permet d'avoir accès à l'index sinon c'est un tuple
        for index in selected:
            if index in task.getDissociated():
                # La tache est dissocié, on peut donc la rassocier
                btnSeparate.config(text="Associer",
                                   command=associate,
                                   state=ACTIVE)
            else:
                # La tache est dans la liste de répétition, on peut donc l'associer
                btnSeparate.config(text="Dissocier",
                                   command=dissociate,
                                   state=ACTIVE)

    def scinder():
        """
        Fonction qui scinde la répétition en une nouvelle répétition à partir
        de la répétition selectionné
        """
        selected = listBoxRepet.curselection()
        # On passe par une boucle pour avoir des int
        for iteration in selected:
            newTask = task.scinder(iteration)

            # On rajoute la tache
            task.getPeriode().addCopiedTask(newTask, task)

        # On met à jour la liste
        manageOption()
        listeDate.set(makeListDissociated())

    def associate():
        """
        Fonction qui remet la tache à répétition dans celles à faire
        En pratique, retire l'itération en question de la liste "setDissociated"
        """
        selected = listBoxRepet.curselection()
        for iteration in selected:
            task.removeDissociated(iteration)

        # On met à jour la liste
        manageOption()
        listeDate.set(makeListDissociated())

    def dissociate():
        """
        Fonction qui ajoute une répétition à ne pas faire
        + crée une autre tache à la date ou la précédante est annulé
        """
        selected = listBoxRepet.curselection()
        # Parcours du tuple pour avoir l'index de la ligne
        for iteration in selected:
            task.addDissociated(iteration)

        # On met à jour la liste
        manageOption()
        listeDate.set(makeListDissociated())

    # Variable
    listeDate = StringVar()

    # Affctation
    listeDate.set(makeListDissociated())

    fen = Dialog(title="Répétition de \"%s\"" % task.getNom(),
                 buttons=("Ok", "Annuler"),
                 exitButton=("Ok", "Annuler", "WM_DELETE_WINDOW"))

    # Liste de widget
    lbTop = Label(
        fen,
        text=
        "Gestion des répétitions :\n\t- (*)Dissocier : retire une tache des répétition\n\t- Scinder : crée une nouvelle tache à répétition",
        justify=LEFT)
    listBoxRepet = Listbox(fen, listvariable=listeDate, selectmode="single")
    listBoxRepet.bind("<<ListboxSelect>>", manageOption)  # Bind associé
    frameBtn = Frame(fen)
    btnSeparate = Button(
        frameBtn, text="Dissocier",
        state=DISABLED)  # Pour les commandes, voir manageOption
    btnScinder = Button(frameBtn,
                        text="Scinder",
                        command=scinder,
                        state=DISABLED)  # Pour l'état voir manageOption

    # Affichage
    lbTop.grid(row=0, column=0, columnspan=2)
    listBoxRepet.grid(row=1, column=0, sticky="we", padx=3)
    frameBtn.grid(row=1, column=1, sticky="nsew")
    btnSeparate.grid(row=0, column=0, sticky="we")
    btnScinder.grid(row=1, column=0, sticky="we")

    fen.activateandwait()
示例#17
0
def askProfil(obligatoire, app, listeProfil):
    """
    Dialogue qui demande a créer un profil
    @param obligatoire : <bool> True  = création d'un profil, pour un user si il en a 0
                                False = création d'un profil, facultatif
    @param app         : <Application> pour quitter en cas de Bool True et croix
    @param listeProfil : <dict> de tout les profils avec leurs paths, on dois la passer car la premiere fois on peut pas passer par l'app car le profil manager n'est pas encore crée
    """
    listeFolder = listeProfil.values(
    )  # <dict_values> contient tous les paths des profils
    nom = None
    folder = None

    def onClose(bouton):
        # Permet de modifier les valeurs des variables
        nonlocal nom, folder
        # Récupération des valeurs
        nom = entryNom.get()
        folder = varEntryPath.get()

        if bouton == "Ok":
            # On regarde si le dossier est vide
            testVide(folder)
            # Ne cherche que dans les "keys" qui sont les noms des profils ☺
            if nom in listeProfil:
                showerror(title="Erreur",
                          message="Ce nom est déjà pris pour un autre profil")
                return
            elif folder in listeFolder:
                showerror(
                    title="Erreur",
                    message="Ce dossier est déjà pris pour un autre profil")
                return

        # Dans tous les cas quand c'est annulé :
        else:
            if obligatoire:
                if not askyesnowarning(
                        title="Erreur",
                        message=
                        "Vous n'avez pas encore de profil, vous devez un créer un pour commencer.\nCliquez sur \"non\" pour fermer l'application"
                ):
                    # Si vraiment il est conscient et qu'il veut quitter...
                    app.destroy()
                    raise SystemExit(0)  # Pour finir le programme sans soucis
                return
            else:
                nom = folder = None

        fen.destroy()

    def parcourir():
        """
       fonction qui demande où stocker les fichier ET vérifie si le dossier est bien vide
       """
        path = askFolder(vide=True)
        # on set le nouveau path
        if path is not None:
            varEntryPath.set(path)

    fen = Dialog(master=app,
                 title="Création d'un profil",
                 buttons=("Ok", "Annuler"),
                 command=onClose,
                 exitButton=[])
    # Binding des touches
    fen.bind_all("<Return>", lambda e: fen.execute("Ok"))
    fen.bind_all("<Escape>", lambda e: fen.execute("Annuler"))

    # Widgets
    lbDebut = Label(fen, text="Créez un profil pour sauvegarder vos données")
    lbNom = Label(fen, text="Nom :")
    entryNom = Entry(fen)

    framePath = Frame(fen)
    lbPathCustomFile = Label(
        framePath,
        text="Chemin d'enregistrement de vos fichiers de préférences")
    varEntryPath = StringVar()
    entryPathCustomFile = Entry(framePath,
                                state="normal",
                                textvariable=varEntryPath)
    btnParcourir = Button(framePath, text="...", command=parcourir, width=3)

    # Affichage
    lbDebut.grid(column=0, row=0, columnspan=2, sticky="wens", pady=3)
    lbNom.grid(column=0, row=1, sticky="w")
    entryNom.grid(column=1, row=1, sticky="we")
    framePath.grid(column=0, row=2, columnspan=2, sticky="wens")
    lbPathCustomFile.grid(column=0, row=0, sticky="w")
    entryPathCustomFile.grid(column=0, row=1, sticky="we")
    btnParcourir.grid(column=1, row=1, sticky="w")

    # preset
    entryNom.insert(END, os.getlogin())
    varEntryPath.set((os.path.expanduser("~/.taskManager/")).replace(
        "/", os.sep).replace("\\", os.sep))

    fen.activateandwait()
    return nom, folder
示例#18
0
def askAjouterJour(totalJour):
    nbJour   = None
    position = None

    def onClose(bouton):
        # Permet de modifier les valeurs des variables
        nonlocal nbJour, position
        if bouton == 'Ok':
            position = varRadioBouton.get()
            nbJour = int(sb.get())
            if varRadioGestion.get() == "Retirer":
                nbJour = nbJour*-1
        fen.destroy()

    # Pour adapter le nombre de jour max du spinBox
    def adapteSpinbox():
        newVar = 0
        if   varRadioGestion.get() == "Retirer":
            newVar = totalJour
            # Si on dépasse, on reset au max
            if int(sb.get()) > newVar:
                sb.set(int(newVar))
        elif varRadioGestion.get() == "Ajouter":
            newVar = "+inf"
        # On config
        sb.config(to = newVar)

    fen = Dialog(title = "Nombre de jours à ajouter",
           buttons = ("Ok", "Annuler"), command = onClose, exitButton = ('Ok', 'Annuler', "WM_DELETE_WINDOW"))
    # Binding des touches
    fen.bind_all("<Return>", lambda e: fen.execute("Ok"))
    fen.bind_all("<Escape>", lambda e: fen.execute("Annuler"))

    # Mettre les widgets
    frameGestion = Frame(fen)
    varRadioGestion = StringVar()
    rG1= Radiobutton(frameGestion, text = "Ajouter les jours", variable = varRadioGestion, value = "Ajouter", command = adapteSpinbox)
    rG2= Radiobutton(frameGestion, text = "Retirer les jours", variable = varRadioGestion, value = "Retirer", command = adapteSpinbox)
    rG1.grid(row=0, sticky="w")
    rG2.grid(row=1, sticky="w")

    framejour = Labelframe(fen, text="Combien de jours ajouter ?")
    lb = Label(framejour,text="Nombre d'jour :")
    sb = Spinbox(framejour, from_ = 0, to="+inf")
    sb.set(0)
    lb.pack(side=LEFT, fill=BOTH)
    sb.pack(side=LEFT, fill=X, expand=YES)

    framePos = Labelframe(fen, text="Où rajouter les jours ?")
    varRadioBouton = StringVar()
    r1 = Radiobutton(framePos, text = "Au début de la période", variable = varRadioBouton, value = "Avant", command = adapteSpinbox)
    r2 = Radiobutton(framePos, text = "À la fin de la période", variable = varRadioBouton, value = "Apres", command = adapteSpinbox)
    r1.grid(row=0, sticky="w")
    r2.grid(row=1, sticky="w")

    frameGestion.pack(side = TOP, expand = YES, fill = BOTH)
    framejour.pack(  side = TOP, expand = YES, fill = BOTH)
    framePos.pack(    side = TOP, expand = YES, fill = BOTH)

    varRadioGestion.set("Ajouter")
    varRadioBouton.set("Apres")




    # Active et attend (un peu comme une mainloop)
    fen.activateandwait()
    return nbJour, position
示例#19
0
def askDecalHeure(heureRetirerMax, heureAjoutMax, debut, fin, totBloque,
                  tarBloque):
    """
    Dialog pour demander comment décaler les tâches
    @param heureRetirerMax : (int) nombre d'heure que l'on peut retirer maximum à la tache qui commence le plus tardivement
    @param heureAjoutMax   : (int) nombre d'heure que l'on peut ajouter maximum à la tache qui termine le plus tôt
    @param debut           : (time) heure de début d'affichage
    @param fin             : (time) heure de fin d'affichage
    @param totBloque       : (int) nombre d'heure à partir duquel le blocage devient utile
    @param tarBloque       : (int) nombre d'heure à partir duquel le blocage devient utile
    """
    nbHeure = None
    position = None
    param = None

    def onClose(bouton):
        # Permet de modifier les valeurs des variables
        nonlocal nbHeure, position, param
        if bouton == 'Ok':
            position = varRadioGestion.get()
            param = varRadioParam.get()
            nbHeure = int(sb.get())
            if varRadioGestion.get() == "tot":
                nbHeure = nbHeure * -1
        fen.destroy()

    # Pour adapter le nombre d'heure max du spinBoc
    def adapteSpinbox():
        newVar = 0
        if varRadioGestion.get() == "tot" and varRadioParam.get() == "bloquer":
            newVar = totBloque
        elif varRadioGestion.get() == "tot":
            newVar = heureRetirerMax
        elif varRadioGestion.get() == "tard" and varRadioParam.get(
        ) == "bloquer":
            newVar = tarBloque
        elif varRadioGestion.get() == "tard":
            newVar = heureAjoutMax

        # On config
        sb.config(to=newVar)
        # Si on dépasse, on reset au max
        if int(sb.get()) > newVar:
            sb.set(int(newVar))

    fen = Dialog(title="Nombre d'heure à déplacer",
                 buttons=("Ok", "Annuler"),
                 command=onClose,
                 exitButton=('Ok', 'Annuler', "WM_DELETE_WINDOW"))
    # Binding des touches
    fen.bind_all("<Return>", lambda e: fen.execute("Ok"))
    fen.bind_all("<Escape>", lambda e: fen.execute("Annuler"))

    # Mettre les widgets
    framePos = Frame(fen)
    varRadioGestion = StringVar()
    rG1 = Radiobutton(framePos,
                      text="Déplacer plus tot",
                      variable=varRadioGestion,
                      value="tot",
                      command=adapteSpinbox)
    rG2 = Radiobutton(framePos,
                      text="Déplacer plus tard",
                      variable=varRadioGestion,
                      value="tard",
                      command=adapteSpinbox)
    rG1.grid(row=0, sticky="w")
    rG2.grid(row=1, sticky="w")

    frameHeure = Labelframe(fen, text="Déplacer de combien d'heure ?")
    lb = Label(frameHeure, text="Nombre d'heure :")
    sb = Spinbox(frameHeure, from_=0, to=heureAjoutMax)
    sb.set(0)
    lb.pack(side=LEFT, fill=BOTH)
    sb.pack(side=LEFT, fill=X, expand=YES)

    frameParametre = Frame(fen)
    varRadioParam = StringVar()
    rP1 = Radiobutton(frameParametre,
                      text="Garder la même durée entre chaque tache",
                      variable=varRadioParam,
                      value="duree",
                      command=adapteSpinbox)
    rP2 = Radiobutton(frameParametre,
                      text="Garder les tâches entre %s:%02i et %s:%02i" %
                      (debut.hour, debut.minute, fin.hour, fin.minute),
                      variable=varRadioParam,
                      value="bloquer",
                      command=adapteSpinbox)
    rP1.grid(row=0, sticky="w")
    rP2.grid(row=1, sticky="w")

    framePos.pack(side=TOP, expand=YES, fill=BOTH)
    frameHeure.pack(side=TOP, expand=YES, fill=BOTH)
    frameParametre.pack(side=TOP, expand=YES, fill=BOTH)

    varRadioGestion.set("tard")
    varRadioParam.set("duree")

    # Active et attend (un peu comme une mainloop)
    fen.activateandwait()
    return nbHeure, position, param
示例#20
0
def askdatetime(style):
    """
    """
    # Callback quand on ferme la fenêtre par l'un des boutons :
    date = ""
    heure = ""
    dateheure = None
    EXIT = False
    prevHWas0 = prevMWas0 = False

    def onClose(a):
        nonlocal EXIT, date, heure, dateheure
        EXIT = True

        # Si on annule :
        if a == 'Annuler' or a == 'WM_DELETE_WINDOW':
            fen.destroy()
        elif a == 'Ok':  # Si on accepte :
            # on met en forme la date
            date = cal.selection
            if date == None:
                date = datetime.datetime.now().date()
            else:
                date = date.date()
            # et l'heure :
            dateheure = datetime.datetime.combine(
                date, datetime.time(hor.heure, hor.minute))
            # et on ferme la fenêtre.
            fen.destroy()

    def heureChange():
        try:
            hor.setAuto(False)
            hh = int(h.get() if h.get() else 0)
            mm = int(m.get() if m.get() else 0)
            while mm < 0:
                mm += 60
                hh -= 1
            while mm >= 60:
                mm -= 60
                hh += 1
            while hh < 0:
                hh += 24
                # cal.date -= 1
            while hh >= 24:
                hh -= 24
                # cal.date += 1
            m.set(mm)
            h.set(hh)
            hor.set(hh, mm)
        except TclError:  # Il peut y avoir une exception si on ferme la fenêtre : on s'en fiche.
            pass
        except Exception as e:
            showerror("Symbol Interdit", err(e))
            m.set(0)
            h.set(0)
            hor.set(0, 0)

    def heureChange2():
        try:
            print("I'm using it")
            if prevHWas0:
                h.delete(INSERT, END)
            if prevMWas0:
                m.delete(INSERT, END)

            hor.setAuto(False)
            hh = int(h.get() if h.get() else 0)
            mm = int(m.get() if m.get() else 0)

            while mm < 0:
                mm += 60
                hh -= 1
            while mm >= 60:
                mm -= 60
                hh += 1
            if hh < 0:
                hh = 0
                mm = 0
            if hh >= 24:
                hh = 23
                mm = 59
            m.set(mm)
            h.set(hh)
            hor.set(hh, mm)
        #except TclError: # Il peut y avoir une exception si on ferme la fenêtre : on s'en fiche.
        #    pass
        except Exception as e:
            showerror("Symbol Interdit", err(e))
            m.set(0)
            h.set(0)
            hor.set(0, 0)

    def prechange():
        nonlocal prevHWas0, prevMWas0
        prevHWas0 = int(h.get() if h.get() else 0) == 0
        prevMWas0 = int(m.get() if m.get() else 0) == 0
        print("pre", prevHWas0, prevMWas0)

    # Construction du dialogue :
    fen = Dialog(title="Choix de la date et l'heure",
                 buttons=("Ok", "Annuler"),
                 command=onClose)
    cadre = Frame(fen)
    cadre.pack(side=RIGHT)
    # création des widgets :
    cal = Calendar(master=fen, firstweekday=calendar.MONDAY)
    hor = Horloge(cadre, number=style)
    # placement des widgets :
    cal.pack(side=LEFT, expand=1, fill='both')
    hor.pack(side=TOP)

    # choix de l'heure :
    h = Spinbox(cadre,
                from_=-1,
                to=24,
                increment=1,
                width=4,
                command=heureChange)
    h.bind("<Key>", lambda e: prechange(), add=1)
    h.bind("<Key>", lambda e: h.after(10, heureChange2), add=1)
    h.pack(side=LEFT, expand=YES, fill=X)
    # choix de la minute : TODO : in-/décrémenter les minutes ou les heures au delà de leurs périodes de définition doit augmenter les heures/minutes
    m = Spinbox(cadre,
                from_=-1,
                to=60,
                increment=1,
                width=4,
                command=heureChange)
    m.bind("<Key>", lambda e: prechange(), add=1)
    m.bind("<Key>", lambda e: m.after(10, heureChange2), add=1)
    m.pack(side=LEFT, expand=YES, fill=X)
    # valeurs de bases :
    h.set(time.localtime().tm_hour)
    m.set(time.localtime().tm_min)

    prechange()
    # print(fen.master.master.slaves()[0].taskEditor.slaves()[1].slaves())
    # et on active le dialogue.
    fen.activateandwait()
    print(dateheure)
    return dateheure
示例#21
0
    def create(self, master=None):
        """
        Méthode pour demander à l'utilisateur les informations
        nécéssaires pour créer et instancier un objet quelquonque.
        @param master : Objet contenant l'objet créé. Si il est null,
        il ne sera pas passé au constructeur.
        @return l'objet tout juste créé.
        """
        # Créer l'espace du dialogue :
        dialogue = Dialog(None, "Ajouter %s" % self.__unNom, ("Ok", "Annuler"))

        # Mettre des composants dessus :
        # Pour commencer, on demmande le nom (obligatoire).
        cadreNom = LabelFrame(dialogue, text="Nom de %s" % self.__leNom)
        cadreNom.pack(side=TOP, expand=YES, fill=BOTH, padx=5, pady=5)
        etr = Entry(cadreNom)
        etr.pack(side=LEFT, expand=YES, fill=BOTH, padx=5, pady=5)

        # Mettre le choix de la visibilité: (facultatif)
        if len(self.__visibilitees):
            # Séparateur :
            Separator(dialogue, orient=HORIZONTAL).pack(side=TOP, fill=X)
            # On crée le cadre et les variable de calcul :
            cadreVisibilitee = LabelFrame(dialogue,
                                          text="Visibilité de %s" %
                                          self.__leNom)
            cadreVisibilitee.pack(side=TOP, fill=X, padx=5, pady=5)
            varV = StringVar(value=self.__defautVisibilitee)
            # Calcul du nombre de lignes et colonnes pour garder une grille à peu près carrée :
            rows = math.ceil(math.sqrt(len(self.__visibilitees)) / 2)
            cols = math.floor(math.sqrt(len(self.__visibilitees)) * 2)
            if cols * rows < len(self.__visibilitees):
                cols += 1
            while (cols - 1) * rows >= len(self.__visibilitees):
                cols -= 1

            # on crée/place les widgets :
            for i, v in enumerate(self.__visibilitees):
                Radiobutton(cadreVisibilitee, text=v, value=v,
                            variable=varV).grid(row=i // cols,
                                                column=i % cols,
                                                sticky="w")
            varV.set(self.__defautVisibilitee)

        # Mettre le choix des modifiers
        if len(self.__modifiers):
            # Séparateur :
            Separator(dialogue, orient=HORIZONTAL).pack(side=TOP, fill=X)
            # On crée le cadre et les variable de calcul :
            cadreModifiers = LabelFrame(dialogue,
                                        text="Modifiers de %s" % self.__leNom)
            cadreModifiers.pack(side=TOP, fill=X, padx=5, pady=5)
            varsM = {}
            # Calcul du nombre de lignes et colonnes pour garder une grille à peu près carrée :
            rows = math.ceil(math.sqrt(len(self.__modifiers)) / 2)
            cols = math.floor(math.sqrt(len(self.__modifiers)) * 2)
            if cols * rows < len(self.__modifiers):
                cols += 1
            while (cols - 1) * rows >= len(self.__modifiers):
                cols -= 1

            # on crée/place les widgets :
            for i, v in enumerate(self.__modifiers):
                var = BooleanVar(value=False)
                Checkbutton(cadreModifiers, text=v,
                            variable=var).grid(row=i // cols,
                                               column=i % cols,
                                               sticky="w")
                varsM[v] = var

        # Mettre le choix du type:
        if self.__typable:
            # Séparateur :
            Separator(dialogue, orient=HORIZONTAL).pack(side=TOP, fill=X)
            # On crée le cadre et les variable de calcul :
            cadreType = LabelFrame(dialogue, text="Type de %s" % self.__leNom)
            cadreType.pack(side=TOP, fill=X, padx=5, pady=5)
            cadreTypeNatifs = Frame(cadreType)
            cadreTypeNatifs.pack(expand=YES, fill=BOTH, side=TOP)
            varT = StringVar(value=self.__defautType)
            # Calcul du nombre de lignes et colonnes pour garder une grille à peu près carrée :
            rows = math.ceil(math.sqrt(len(self.__types)) / 2)
            cols = math.floor(math.sqrt(len(self.__types)) * 2)
            if cols * rows < len(self.__types):
                cols += 1
            while (cols - 1) * rows >= len(
                    list(inter(self.__types, DialogBuilder.__nativeTypes))):
                cols -= 1

            # on crée/place les widgets :
            for i, t in enumerate(
                    inter(self.__types, DialogBuilder.__nativeTypes)):
                Radiobutton(cadreTypeNatifs, text=t, value=t,
                            variable=varT).grid(row=i // cols,
                                                column=i % cols,
                                                sticky="w")

            # TODO : Mettre les types custom. Avec un combobox ?
            cbbTypes = Combobox(cadreType,
                                values=[
                                    i for i in self.__types
                                    if not i in DialogBuilder.__nativeTypes
                                ],
                                state="readonly",
                                textvariable=varT)
            Label(cadreType, text="Autre objet :").pack(side=LEFT)
            cbbTypes.pack(side=LEFT, fill=X)
            varT.set(self.__defautType)

        # Activer puis récupérer le résultat pour le renvoyer
        if dialogue.activateandwait() == "Ok":
            options = {"nom": etr.get(), "style": self.__style}
            if master is not None: options["master"] = master
            if len(self.__visibilitees): options["visibilitee"] = varV
            if len(self.__modifiers): options["modifiers"] = varsM
            if self.__typable: options["type"] = varT
            result = self.__cls(**options)
        else:
            result = None
        dialogue.destroy()
        return result