]> git.lyx.org Git - lyx.git/blob - src/frontends/qt/BulletsModule.cpp
Properly scale some icons for HiDPI (#12695)
[lyx.git] / src / frontends / qt / BulletsModule.cpp
1 /**
2  * \file BulletsModule.cpp
3  * This file is part of LyX, the document processor.
4  * Licence details can be found in the file COPYING.
5  *
6  * \author Edwin Leuven
7  *
8  * Full author contact details are available in file CREDITS.
9  */
10
11 #include <config.h>
12
13 #include "Bullet.h"
14
15 #include "BulletsModule.h"
16 #include "GuiApplication.h"
17 #include "qt_helpers.h"
18
19 #include <QBitmap>
20 #include <QPixmap>
21 #include <QPainter>
22 #include <QScrollBar>
23
24 using namespace std;
25
26 namespace lyx {
27
28 namespace frontend {
29
30 int const CHARMAX = 36;
31 int const FONTMAX = 6;
32
33 BulletsModule::BulletsModule(QWidget * parent)
34     : QWidget(parent)
35 {
36         setupUi(this);
37
38         for (int iter = 0; iter < 4; ++iter)
39                 bullets_[iter] = ITEMIZE_DEFAULTS[iter];
40
41         current_font_ = -1;
42         current_char_ = 0;
43
44         // add levels
45         levelLW->addItem("1");
46         levelLW->addItem("2");
47         levelLW->addItem("3");
48         levelLW->addItem("4");
49
50         // insert pixmaps
51         setupPanel(new QListWidget(bulletpaneSW), qt_("Standard[[Bullets]]"), 0);
52         setupPanel(new QListWidget(bulletpaneSW), qt_("Maths"), 1, "math");
53         setupPanel(new QListWidget(bulletpaneSW), qt_("Dings 1"), 2);
54         setupPanel(new QListWidget(bulletpaneSW), qt_("Dings 2"), 3);
55         setupPanel(new QListWidget(bulletpaneSW), qt_("Dings 3"), 4);
56         setupPanel(new QListWidget(bulletpaneSW), qt_("Dings 4"), 5);
57
58         connect(levelLW, SIGNAL(currentRowChanged(int)),
59                 this, SLOT(showLevel(int)));
60         connect(bulletpaneCO, SIGNAL(activated(int)), bulletpaneSW,
61                 SLOT(setCurrentIndex(int)));
62 }
63
64
65 string const bulletIcon(int f, int c)
66 {
67         static char const * BulletPanelIcons0[CHARMAX] = {
68                 /* standard */
69                 "bfendash", "vdash", "dashv", "flat", "natural",
70                 "sharp", "ast", "star", "bullet", "circ", "cdot",
71                 "dagger", "bigtriangleup", "bigtriangledown", "triangleleft",
72                 "triangleright", "lhd", "rhd", "oplus", "ominus", "otimes",
73                 "oslash", "odot", "spadesuit", "diamond", "diamond2", "box",
74                 "diamondsuit", "heartsuit",  "clubsuit", "rightarrow", "leadsto",
75                 "rightharpoonup", "rightharpoondown", "rightarrow2", "succ"
76         };
77         static char const * BulletPanelIcons1[CHARMAX] = {
78                 /* amssymb */
79                 "Rrightarrow", "rightarrowtail", "twoheadrightarrow", "rightsquigarrow",
80                 "looparrowright", "multimap", "boxtimes", "boxplus", "boxminus",
81                 "boxdot", "divideontimes", "Vvdash", "lessdot", "gtrdot", "maltese",
82                 "bigstar", "checkmark", "vdash2", "backsim", "thicksim",
83                 "centerdot", "circleddash", "circledast", "circledcirc",
84                 "vartriangleleft", "vartriangleright", "vartriangle", "triangledown",
85                 "lozenge", "square", "blacktriangleleft", "blacktriangleright", "blacktriangle",
86                 "blacktriangledown", "blacklozenge", "blacksquare"
87         };
88         static char const * BulletPanelIcons2[CHARMAX] = {
89                 /* psnfss1 */
90                 "ding108", "ding109", "ding119", "pisymbol_psy197",
91                 "pisymbol_psy196", "pisymbol_psy183", "ding71", "ding70",
92                 "ding118", "ding117", "pisymbol_psy224", "pisymbol_psy215",
93                 "ding111", "ding112", "ding113", "ding114",
94                 "pisymbol_psy68", "pisymbol_psy209", "ding120", "ding121",
95                 "ding122", "ding110", "ding115", "ding116",
96                 "pisymbol_psy42", "ding67", "ding66", "ding82",
97                 "ding81", "ding228", "ding162", "ding163",
98                 "ding166", "ding167", "ding226", "ding227"
99         };
100         static char const * BulletPanelIcons3[CHARMAX] = {
101                 /* psnfss2 */
102                 "ding37", "ding38", "ding34", "ding36",
103                 "ding39", "ding40", "ding41", "ding42",
104                 "ding43", "ding44", "ding45", "ding47",
105                 "ding53", "ding54", "ding59", "ding57",
106                 "ding62", "ding61", "ding55", "ding56",
107                 "ding58", "ding60", "ding63", "ding64",
108                 "ding51", "ding52", "pisymbol_psy170", "pisymbol_psy167",
109                 "pisymbol_psy168", "pisymbol_psy169",  "ding164", "ding165",
110                 "ding171", "ding168", "ding169", "ding170"
111         };
112         static char const * BulletPanelIcons4[CHARMAX] = {
113                 /* psnfss3 */
114                 "ding65", "ding76", "ding75", "ding72",
115                 "ding80", "ding74", "ding78", "ding77",
116                 "ding79", "ding85", "ding90", "ding98",
117                 "ding83", "ding84", "ding86", "ding87",
118                 "ding88", "ding89", "ding92", "ding91",
119                 "ding93", "ding105", "ding94", "ding99",
120                 "ding103", "ding104", "ding106", "ding107",
121                 "ding68", "ding69", "ding100", "ding101",
122                 "ding102", "ding96", "ding95", "ding97"
123         };
124         static char const * BulletPanelIcons5[CHARMAX] = {
125                 /* psnfss4 */
126                 "ding223", "ding224", "ding225", "ding232",
127                 "ding229", "ding230", "ding238", "ding237",
128                 "ding236", "ding235", "ding234", "ding233",
129                 "ding239", "ding241", "ding250", "ding251",
130                 "ding49", "ding50", "ding217", "ding245",
131                 "ding243", "ding248", "ding252", "ding253",
132                 "ding219", "ding213", "ding221", "ding222",
133                 "ding220", "ding212", "pisymbol_psy174", "pisymbol_psy222",
134                 "ding254", "ding242", "ding231", "pisymbol_psy45"
135         };
136
137         static char const ** BulletPanelIcons[FONTMAX] = {
138                 BulletPanelIcons0, BulletPanelIcons1,
139                 BulletPanelIcons2, BulletPanelIcons3,
140                 BulletPanelIcons4, BulletPanelIcons5
141         };
142
143         return BulletPanelIcons[f][c];
144 }
145
146
147 QPixmap getSelectedPixmap(QPixmap pixmap, QSize const icon_size)
148 {
149         QPalette palette = QPalette();
150         QColor text_color = (guiApp->isInDarkMode())
151                         ? palette.color(QPalette::Active, QPalette::WindowText)
152                         : Qt::black;
153         QColor highlight_color = palette.color(QPalette::Active, QPalette::HighlightedText);
154         QColor highlight_bg = palette.color(QPalette::Active, QPalette::Highlight);
155
156         // create a layer with black text turned to QPalette::HighlightedText
157         QPixmap hl_overlay(pixmap.size());
158         hl_overlay.fill(highlight_color);
159         hl_overlay.setMask(pixmap.createMaskFromColor(text_color, Qt::MaskOutColor));
160
161         // Create highlighted background
162         QPixmap hl_background(icon_size);
163         hl_background.fill(highlight_bg);
164
165         // put layers on top of existing pixmap
166         QPainter painter(&pixmap);
167         painter.drawPixmap(pixmap.rect(), hl_background);
168         painter.drawPixmap(pixmap.rect(), hl_overlay);
169
170         return pixmap;
171 }
172
173
174 void BulletsModule::setupPanel(QListWidget * lw, QString const & panelname,
175         int const font, string const folder)
176 {
177         connect(lw, SIGNAL(itemClicked(QListWidgetItem *)),
178                 this, SLOT(bulletSelected(QListWidgetItem *)));
179
180         // add panelname to combox
181         bulletpaneCO->addItem(panelname);
182
183         lw->setViewMode(QListView::IconMode);
184         lw->setDragDropMode(QAbstractItemView::NoDragDrop);
185         lw->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
186         lw->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
187         lw->setFlow(QListView::LeftToRight);
188         lw->setSpacing(12);
189         lw->setUniformItemSizes(true);
190
191         QSize icon_size(26, 26);
192         lw->setIconSize(icon_size);
193
194         // we calculate the appropriate width to fit 6 icons in a row
195         lw->setFixedWidth((6 * (icon_size.width() + lw->spacing()))
196                                 + (lw->frameWidth() * 2)
197                                 + lw->verticalScrollBar()->height());
198         // and six rows
199         lw->setFixedHeight((6 * (icon_size.height() + lw->spacing()))
200                                 + (lw->frameWidth() * 2)
201                                 + lw->horizontalScrollBar()->height());
202
203         for (int i = 0; i < CHARMAX; ++i) {
204                 string const iconname = bulletIcon(font, i);
205                 // get pixmap with bullets
206                 QPixmap pixmap = getPixmap("images/" + toqstr(folder) + "/", toqstr(iconname), "svgz");
207                 QIcon icon(pixmap);
208                 icon.addPixmap(getSelectedPixmap(pixmap, icon_size), QIcon::Selected);
209                 QListWidgetItem * lwi = new QListWidgetItem(icon, QString(), 0, i);
210                 lwi->setToolTip(toqstr(Bullet::bulletEntry(font, i)));
211                 lwi->setSizeHint(icon_size);
212                 lw->addItem(lwi);
213         }
214
215         // add bulletpanel to stackedwidget
216         bulletpaneSW->addWidget(lw);
217 }
218
219
220 void BulletsModule::showLevel(int level)
221 {
222         // unselect previous item
223         selectItem(current_font_, current_char_, false);
224
225         current_font_ = bullets_[level].getFont();
226
227         if (bullets_[level].getFont() < 0) {
228                 customCB->setCheckState(Qt::Checked);
229                 customLE->setText(toqstr(bullets_[level].getText()));
230                 bulletsizeCO->setEnabled(false);
231                 sizeL->setEnabled(false);
232         } else {
233                 customCB->setCheckState(Qt::Unchecked);
234                 customLE->clear();
235                 current_char_ = bullets_[level].getCharacter();
236                 selectItem(current_font_, current_char_, true);
237                 bulletpaneCO->setCurrentIndex(current_font_);
238                 bulletpaneSW->setCurrentIndex(current_font_);
239                 bulletsizeCO->setEnabled(true);
240                 sizeL->setEnabled(true);
241         }
242         bulletsizeCO->setCurrentIndex(bullets_[level].getSize() + 1);
243 }
244
245
246 void BulletsModule::init()
247 {
248         levelLW->setCurrentRow(0);
249         showLevel(0);
250 }
251
252
253 void BulletsModule::bulletSelected(QListWidgetItem * item)
254 {
255         int const level = levelLW->currentRow();
256
257         // no change
258         if (bullets_[level].getFont() == bulletpaneCO->currentIndex()
259                 && bullets_[level].getCharacter() == item->type())
260                 return;
261
262         // unselect previous item
263         selectItem(current_font_, current_char_, false);
264
265         bullets_[level].setCharacter(item->type());
266         bullets_[level].setFont(bulletpaneCO->currentIndex());
267         current_font_ = bulletpaneCO->currentIndex();
268         current_char_ = item->type();
269         changed();
270 }
271
272
273 void BulletsModule::on_customCB_clicked(bool custom)
274 {
275         bulletsizeCO->setEnabled(!custom);
276         sizeL->setEnabled(!custom);
277
278         if (!custom) {
279                 if (current_font_ < 0)
280                         current_font_ = bulletpaneCO->currentIndex();
281                 return;
282         }
283
284         // unselect previous item
285         selectItem(current_font_, current_char_, false);
286         current_font_ = -1;
287         changed();
288 }
289
290
291 void BulletsModule::selectItem(int font, int character, bool select)
292 {
293         if (font < 0)
294                 return;
295
296         QListWidget * lw = static_cast<QListWidget *>(bulletpaneSW->widget(font));
297         if (lw->item(character))
298                 lw->item(character)->setSelected(select);
299 }
300
301
302 void BulletsModule::on_customLE_textEdited(const QString & text)
303 {
304         if (customCB->checkState() == Qt::Unchecked)
305                 return;
306
307         bullets_[levelLW->currentRow()].setFont(current_font_);
308         bullets_[levelLW->currentRow()].setText(qstring_to_ucs4(text));
309         changed();
310 }
311
312
313 void BulletsModule::on_bulletsizeCO_activated(int size)
314 {
315         // -1 apparently means default...
316         bullets_[levelLW->currentRow()].setSize(size - 1);
317         changed();
318 }
319
320
321 void BulletsModule::setBullet(int level, Bullet const & bullet)
322 {
323         bullets_[level] = bullet;
324 }
325
326
327 Bullet const & BulletsModule::bullet(int level) const
328 {
329         return bullets_[level];
330 }
331
332 } // namespace frontend
333
334 } // namespace lyx
335
336
337 #include "moc_BulletsModule.cpp"