]> git.lyx.org Git - features.git/blob - src/frontends/qt/BulletsModule.cpp
Guard against possible referencing null.
[features.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(currentItemChanged(QListWidgetItem*, QListWidgetItem*)),
178                 this, SLOT(bulletSelected(QListWidgetItem *, 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());
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, QListWidgetItem *)
254 {
255         // unselect previous item
256         selectItem(current_font_, current_char_, false);
257
258         int const level = levelLW->currentRow();
259         bullets_[level].setCharacter(item->type());
260         bullets_[level].setFont(bulletpaneCO->currentIndex());
261         current_font_ = bulletpaneCO->currentIndex();
262         current_char_ = item->type();
263         changed();
264 }
265
266
267 void BulletsModule::on_customCB_clicked(bool custom)
268 {
269         bulletsizeCO->setEnabled(!custom);
270         sizeL->setEnabled(!custom);
271
272         if (!custom) {
273                 if (current_font_ < 0)
274                         current_font_ = bulletpaneCO->currentIndex();
275                 return;
276         }
277
278         // unselect previous item
279         selectItem(current_font_, current_char_, false);
280         current_font_ = -1;
281         changed();
282 }
283
284
285 void BulletsModule::selectItem(int font, int character, bool select)
286 {
287         if (font < 0)
288                 return;
289
290         QListWidget * lw = static_cast<QListWidget *>(bulletpaneSW->widget(font));
291         if (lw->item(character))
292                 lw->item(character)->setSelected(select);
293 }
294
295
296 void BulletsModule::on_customLE_textEdited(const QString & text)
297 {
298         if (customCB->checkState() == Qt::Unchecked)
299                 return;
300
301         bullets_[levelLW->currentRow()].setFont(current_font_);
302         bullets_[levelLW->currentRow()].setText(qstring_to_ucs4(text));
303         changed();
304 }
305
306
307 void BulletsModule::on_bulletsizeCO_activated(int size)
308 {
309         // -1 apparently means default...
310         bullets_[levelLW->currentRow()].setSize(size - 1);
311         changed();
312 }
313
314
315 void BulletsModule::setBullet(int level, Bullet const & bullet)
316 {
317         bullets_[level] = bullet;
318 }
319
320
321 Bullet const & BulletsModule::bullet(int level) const
322 {
323         return bullets_[level];
324 }
325
326 } // namespace frontend
327
328 } // namespace lyx
329
330
331 #include "moc_BulletsModule.cpp"