1#
2# configuration_wdgt_card_appearance.py <Peter.Bienstman@UGent.be>
3#
4
5from copy import deepcopy
6
7from PyQt5 import QtCore, QtGui, QtWidgets
8
9from mnemosyne.libmnemosyne.fact import Fact
10from mnemosyne.libmnemosyne.gui_translator import _
11from mnemosyne.libmnemosyne.component import Component
12from mnemosyne.pyqt_ui.preview_cards_dlg import PreviewCardsDlg
13from mnemosyne.libmnemosyne.ui_components.configuration_widget import \
14    ConfigurationWidget
15from mnemosyne.pyqt_ui.ui_configuration_wdgt_card_appearance import \
16     Ui_ConfigurationWdgtCardAppearance
17
18
19class ConfigurationWdgtCardAppearance(QtWidgets.QWidget, ConfigurationWidget,
20    Ui_ConfigurationWdgtCardAppearance):
21
22    name = _("Card appearance")
23
24    def __init__(self, **kwds):
25        super().__init__(**kwds)
26        self.setupUi(self)
27        self.dynamic_widgets = []
28        self.affected_card_types = []
29        self.fact_key_names = []
30        self.non_latin_font_size_increase.setValue\
31            (self.config()['non_latin_font_size_increase'])
32        # We calculate card_type_by_name here because these names can change
33        # if the user chooses another translation.
34        self.card_types_widget.addItem(_("<all card types>"))
35        self.card_type_by_name = {}
36        for card_type in self.database().sorted_card_types():
37            if card_type.hidden_from_UI:
38                continue
39            self.card_type_by_name[_(card_type.name)] = card_type
40            self.card_types_widget.addItem(_(card_type.name))
41        # Store backups in order to be able to revert our changes.
42        self.old_font = deepcopy(self.config()["font"])
43        self.old_background_colour = \
44            deepcopy(self.config()["background_colour"])
45        self.old_font_colour = deepcopy(self.config()["font_colour"])
46        self.old_alignment = deepcopy(self.config()["alignment"])
47
48    def card_type_changed(self, new_card_type_name):
49        non_latin_widgets = [self.label_non_latin_1, self.label_non_latin_2,
50                self.label_non_latin_3, self.line_non_latin,
51                self.non_latin_font_size_increase]
52        background_align_widgets = [self.background_label,
53            self.background_button, self.align_label, self.alignment]
54        if new_card_type_name == _("<all card types>"):
55            self.affected_card_types = self.card_types()
56            self.fact_key_names = [_("Text")]
57            for widget in non_latin_widgets + background_align_widgets:
58                widget.show()
59        else:
60            new_card_type_name = new_card_type_name
61            new_card_type = self.card_type_by_name[new_card_type_name]
62            self.affected_card_types = [new_card_type]
63            self.fact_key_names = new_card_type.fact_key_names()
64            for widget in background_align_widgets:
65                if new_card_type.id.startswith("7::"):
66                    widget.hide()
67                else:
68                    widget.show()
69            for widget in non_latin_widgets:
70                widget.hide()
71        for widget in self.dynamic_widgets:
72            self.gridLayout.removeWidget(widget)
73            widget.close()
74        self.dynamic_widgets = []
75
76        row = 0
77        self.font_buttons = QtWidgets.QButtonGroup()
78        self.colour_buttons = QtWidgets.QButtonGroup()
79        self.align_buttons = QtWidgets.QButtonGroup()
80        self.align_buttons.setExclusive(False)
81        for key_name in self.fact_key_names:
82            label = QtWidgets.QLabel(_(key_name) + ":", self)
83            self.gridLayout.addWidget(label, row, 0, 1, 1)
84            self.dynamic_widgets.append(label)
85
86            font = QtWidgets.QPushButton(_("Select font"), self)
87            self.font_buttons.addButton(font, row)
88            self.gridLayout.addWidget(font, row, 1, 1, 1)
89            self.dynamic_widgets.append(font)
90
91            colour = QtWidgets.QPushButton(_("Select colour"),self)
92            self.colour_buttons.addButton(colour, row)
93            self.gridLayout.addWidget(colour, row, 2, 1, 1)
94            self.dynamic_widgets.append(colour)
95
96            row += 1
97        self.gridLayout.setColumnStretch(1, 10)
98        self.gridLayout.setColumnStretch(2, 10)
99        self.font_buttons.buttonClicked[int].connect(self.update_font)
100        self.colour_buttons.buttonClicked[int].\
101            connect(self.update_font_colour)
102
103        current_alignment = self.config().card_type_property(\
104            "alignment", self.affected_card_types[0], default="center")
105        if current_alignment == "left":
106            self.alignment.setCurrentIndex(0)
107        elif current_alignment == "center":
108            self.alignment.setCurrentIndex(1)
109        elif current_alignment == "right":
110            self.alignment.setCurrentIndex(2)
111        # Make font light if different alignments are active.
112        self.alignment.setFont(self.font())
113        values = set()
114        for card_type in self.affected_card_types:
115            if not card_type.id in self.config()["alignment"]:
116                values.add("center")
117            else:
118                values.add(self.config()["alignment"][card_type.id])
119        if len(values) > 1:
120            self.alignment.font().setWeight(25)
121        else:
122            self.alignment.font().setWeight(50)
123        self.adjustSize()
124
125    def update_background_colour(self):
126        # Determine current colour.
127        current_rgb = self.config().card_type_property("background_colour",
128            self.affected_card_types[0])
129        if current_rgb:
130            current_colour = QtGui.QColor(current_rgb)
131        else:
132            current_colour = self.palette().color(QtGui.QPalette.Base)
133        # Set new colour.
134        colour = QtWidgets.QColorDialog.getColor(current_colour, self)
135        if colour.isValid():
136            for card_type in self.affected_card_types:
137                self.config().set_card_type_property("background_colour",
138                    colour.rgb(), card_type)
139
140    def update_font(self, index):
141        # Determine keys affected.
142        if len(self.affected_card_types) > 1:
143            affected_fact_key = None # Actually means all the keys.
144        else:
145            affected_fact_key = \
146                self.affected_card_types[0].fact_keys_and_names[index][0]
147        # Determine current font.
148        if len(self.affected_card_types) > 1:
149            font_strings = set()
150            for card_type in self.affected_card_types:
151                if card_type.hidden_from_UI:
152                    continue
153                font_strings.add(self.config().card_type_property(\
154                    "font", card_type, card_type.fact_keys_and_names[0][0]))
155            if len(font_strings) > 1:
156                font_string = None
157            else:
158                font_string = font_strings.pop()
159        else:
160            font_string = self.config().card_type_property(\
161                "font", self.affected_card_types[0], affected_fact_key)
162        current_font = QtGui.QFont(self.font())
163        if font_string:
164            current_font.fromString(font_string)
165        # Set new font.
166        font, ok = QtWidgets.QFontDialog.getFont(current_font, self)
167        if ok:
168            font_string = font.toString()
169            for card_type in self.affected_card_types:
170                self.config().set_card_type_property("font", font_string,
171                    card_type, affected_fact_key)
172
173    def update_font_colour(self, index):
174        # Determine keys affected.
175        if len(self.affected_card_types) > 1:
176            affected_fact_key = None # Actually means all the keys.
177        else:
178            affected_fact_key = \
179                self.affected_card_types[0].fact_keys_and_names[index][0]
180        # Determine current colour.
181        if len(self.affected_card_types) > 1:
182            current_rgb = self.config().card_type_property(\
183                "font_colour", self.card_type_with_id("1"), "f")
184        else:
185            current_rgb = self.config().card_type_property(\
186                "font_colour", self.affected_card_types[0], affected_fact_key)
187        if current_rgb:
188            current_colour = QtGui.QColor(current_rgb)
189        else:
190            current_colour = QtGui.QColor(QtCore.Qt.black)
191        # Set new colour.
192        colour = QtWidgets.QColorDialog.getColor(current_colour, self)
193        if colour.isValid():
194            for card_type in self.affected_card_types:
195                self.config().set_card_type_property("font_colour",
196                    colour.rgb(), card_type, affected_fact_key)
197
198    def update_alignment(self, index):
199        if index == 0:
200            new_alignment = "left"
201        elif index == 1:
202            new_alignment = "center"
203        elif index == 2:
204            new_alignment = "right"
205        for card_type in self.affected_card_types:
206            self.config().set_card_type_property("alignment", new_alignment,
207                card_type)
208        self.alignment.font().setWeight(50)
209
210    def apply(self):
211        self.config()["non_latin_font_size_increase"] = \
212            self.non_latin_font_size_increase.value()
213        for card_type in self.card_types():
214            for render_chain in self.component_manager.all("render_chain"):
215                render_chain.renderer_for_card_type(card_type).\
216                    update(card_type)
217
218    def preview(self):
219        card_type = self.affected_card_types[0]
220        for render_chain in self.component_manager.all("render_chain"):
221            render_chain.renderer_for_card_type(card_type).update(card_type)
222        fact_data = {}
223        for fact_key, fact_key_name in card_type.fact_keys_and_names:
224            fact_data[fact_key] = _(fact_key_name)
225            # Tmp hack for cloze.
226            if fact_key == "text":
227                fact_data[fact_key] = "[" + _(fact_key_name) + "]"
228        fact = Fact(fact_data)
229        cards = card_type.create_sister_cards(fact)
230        # Tmp hack for Anki
231        for card in cards:
232            card.extra_data["ord"] = 1
233        tag_text = ""
234        dlg = PreviewCardsDlg(cards, tag_text,
235            component_manager=self.component_manager, parent=self)
236        dlg.exec_()
237
238    def reset_to_defaults(self):
239        if len(self.affected_card_types) > 1:
240            message = _("Reset all card types to default system font?")
241        else:
242            message = _("Reset '%s' to default system font?") \
243                % (_(self.affected_card_types[0].name))
244        result = self.main_widget().show_question(\
245            message, _("&Yes"), _("&No"), "")
246        if result == 1:
247            return
248        self.non_latin_font_size_increase.setValue(0)
249        if len(self.affected_card_types) > 1:
250            self.config()["font"] = {}
251            self.config()["background_colour"] = {}
252            self.config()["font_colour"] = {}
253            self.config()["alignment"] = {}
254        else:
255            card_type_id = self.affected_card_types[0].id
256            self.config()["font"].pop(card_type_id, None)
257            self.config()["background_colour"].pop(card_type_id, None)
258            self.config()["font_colour"].pop(card_type_id, None)
259            self.config()["alignment"].pop(card_type_id, None)
260        self.alignment.setCurrentIndex(1)
261
262    def reject(self):
263        self.config()["font"] = self.old_font
264        self.config()["background_colour"] = self.old_background_colour
265        self.config()["font_colour"] = self.old_font_colour
266        self.config()["alignment"] = self.old_alignment
267        for card_type in self.card_types():
268            for render_chain in self.component_manager.all("render_chain"):
269                render_chain.renderer_for_card_type(card_type).\
270                    update(card_type)
271
272