2 * \file GuiDelimiter.cpp
3 * This file is part of LyX, the document processor.
4 * Licence details can be found in the file COPYING.
8 * Full author contact details are available in file CREDITS.
13 #include "GuiDelimiter.h"
15 #include "GuiApplication.h"
16 #include "GuiFontLoader.h"
18 #include "qt_helpers.h"
20 #include "FontEnums.h"
22 #include "FuncRequest.h"
24 #include "support/debug.h"
25 #include "support/docstring.h"
26 #include "support/gettext.h"
27 #include "support/lstrings.h"
33 #include <QListWidgetItem>
46 static char const * latex_delimiters[] = {
47 "(", ")", "{", "}", "[", "]",
48 "lceil", "rceil", "lfloor", "rfloor", "langle", "rangle",
49 "llbracket", "rrbracket",
50 "uparrow", "updownarrow", "Uparrow", "Updownarrow", "downarrow", "Downarrow",
51 "|", "Vert", "/", "backslash", ""
55 static int const nr_latex_delimiters =
56 sizeof(latex_delimiters) / sizeof(char const *);
58 static string const bigleft[] = {"", "bigl", "Bigl", "biggl", "Biggl"};
60 static string const bigright[] = {"", "bigr", "Bigr", "biggr", "Biggr"};
62 static char const * const biggui[] = {
63 N_("big[[delimiter size]]"),
64 N_("Big[[delimiter size]]"),
65 N_("bigg[[delimiter size]]"),
66 N_("Bigg[[delimiter size]]"),
71 // FIXME: It might be better to fix the big delim LFUN to not require
72 // additional '\' prefix.
73 static docstring fix_name(string const & str, bool big)
76 return from_ascii(".");
77 if (!big || str == "(" || str == ")" || str == "[" || str == "]"
78 || str == "|" || str == "/")
79 return from_ascii(str);
81 return "\\" + from_ascii(str);
85 MathSymbol(char_type uc = '?', string icon = string())
86 : unicode(uc), icon(icon)
93 QPixmap getSelectedPixmap(QPixmap pixmap, QSize const icon_size)
95 QPalette palette = QPalette();
96 QColor text_color = (guiApp->isInDarkMode())
97 ? palette.color(QPalette::Active, QPalette::WindowText)
99 QColor highlight_color = palette.color(QPalette::Active, QPalette::HighlightedText);
100 QColor highlight_bg = palette.color(QPalette::Active, QPalette::Highlight);
102 // create a layer with black text turned to QPalette::HighlightedText
103 QPixmap hl_overlay(pixmap.size());
104 hl_overlay.fill(highlight_color);
105 hl_overlay.setMask(pixmap.createMaskFromColor(text_color, Qt::MaskOutColor));
107 // Create highlighted background
108 QPixmap hl_background(icon_size);
109 hl_background.fill(highlight_bg);
111 // put layers on top of existing pixmap
112 QPainter painter(&pixmap);
113 painter.drawPixmap(pixmap.rect(), hl_background);
114 painter.drawPixmap(pixmap.rect(), hl_overlay);
119 /// TeX-name / Math-symbol map.
120 static map<std::string, MathSymbol> math_symbols_;
121 /// Math-symbol / TeX-name map.
122 /// This one is for fast search, it contains the same data as
123 /// \c math_symbols_.
124 static map<char_type, string> tex_names_;
126 typedef map<char_type, QListWidgetItem *> ListItems;
127 ListItems left_list_items_;
128 ListItems right_list_items_;
130 void initMathSymbols()
132 // FIXME: Ideally, those unicode codepoints would be defined
133 // in "lib/symbols". Unfortunately, some of those are already
134 // defined with non-unicode ids for use within mathed.
135 // FIXME 2: We should fill-in this map with the parsed "symbols"
136 // file done in MathFactory.cpp.
137 math_symbols_["("] = MathSymbol('(', "lparen");
138 math_symbols_[")"] = MathSymbol(')', "rparen");
139 math_symbols_["{"] = MathSymbol('{', "lbrace");
140 math_symbols_["}"] = MathSymbol('}', "rbrace");
141 math_symbols_["["] = MathSymbol('[', "lbracket");
142 math_symbols_["]"] = MathSymbol(']', "rbracket");
143 math_symbols_["|"] = MathSymbol('|', "mid");
144 math_symbols_["/"] = MathSymbol('/', "slash");
145 math_symbols_["backslash"] = MathSymbol('\\', "backslash");
146 math_symbols_["lceil"] = MathSymbol(0x2308, "lceil");
147 math_symbols_["rceil"] = MathSymbol(0x2309, "rceil");
148 math_symbols_["lfloor"] = MathSymbol(0x230A, "lfloor");
149 math_symbols_["rfloor"] = MathSymbol(0x230B, "rfloor");
150 math_symbols_["langle"] = MathSymbol(0x2329, "langle");
151 math_symbols_["rangle"] = MathSymbol(0x232A, "rangle");
152 math_symbols_["llbracket"] = MathSymbol(0x27e6, "llbracket");
153 math_symbols_["rrbracket"] = MathSymbol(0x27e7, "rrbracket");
154 math_symbols_["uparrow"] = MathSymbol(0x2191, "uparrow");
155 math_symbols_["Uparrow"] = MathSymbol(0x21D1, "uparrow2");
156 math_symbols_["updownarrow"] = MathSymbol(0x2195, "updownarrow");
157 math_symbols_["Updownarrow"] = MathSymbol(0x21D5, "updownarrow2");
158 math_symbols_["downarrow"] = MathSymbol(0x2193, "downarrow");
159 math_symbols_["Downarrow"] = MathSymbol(0x21D3, "downarrow2");
160 math_symbols_["downdownarrows"] = MathSymbol(0x21CA, "downdownarrows");
161 math_symbols_["downharpoonleft"] = MathSymbol(0x21C3, "downharpoonleft");
162 math_symbols_["downharpoonright"] = MathSymbol(0x21C2, "downharpoonright");
163 math_symbols_["vert"] = MathSymbol(0x007C, "vert");
164 math_symbols_["Vert"] = MathSymbol(0x2016, "vert2");
166 map<string, MathSymbol>::const_iterator it = math_symbols_.begin();
167 map<string, MathSymbol>::const_iterator end = math_symbols_.end();
168 for (; it != end; ++it)
169 tex_names_[it->second.unicode] = it->first;
172 /// \return the math unicode symbol associated to a TeX name.
173 MathSymbol const & mathSymbol(string const & tex_name)
175 map<string, MathSymbol>::const_iterator it =
176 math_symbols_.find(tex_name);
178 static MathSymbol const unknown_symbol;
179 if (it == math_symbols_.end())
180 return unknown_symbol;
185 /// \return the TeX name associated to a math unicode symbol.
186 string const & texName(char_type math_symbol)
188 map<char_type, string>::const_iterator it =
189 tex_names_.find(math_symbol);
191 static string const empty_string;
192 if (it == tex_names_.end())
199 void setDelimiterName(QListWidgetItem * lwi, string const & name)
201 lwi->setData(Qt::UserRole, toqstr(name));
205 string getDelimiterName(QListWidgetItem const * lwi)
207 return fromqstr(lwi->data(Qt::UserRole).toString());
214 GuiDelimiter::GuiDelimiter(GuiView & lv)
215 : GuiDialog(lv, "mathdelimiter", qt_("Math Delimiter"))
219 connect(buttonBox, SIGNAL(rejected()), this, SLOT(accept()));
221 setFocusProxy(leftLW);
223 leftLW->setViewMode(QListView::IconMode);
224 rightLW->setViewMode(QListView::IconMode);
226 leftLW->setDragDropMode(QAbstractItemView::NoDragDrop);
227 rightLW->setDragDropMode(QAbstractItemView::NoDragDrop);
229 left_list_items_.clear();
230 right_list_items_.clear();
234 QSize icon_size(32, 32);
236 leftLW->setMinimumWidth(5 * icon_size.width());
237 rightLW->setMinimumWidth(5 * icon_size.width());
238 leftLW->setIconSize(icon_size);
239 rightLW->setIconSize(icon_size);
241 // The last element is the empty one.
242 int const end = nr_latex_delimiters - 1;
243 for (int i = 0; i < end; ++i) {
244 string const delim = latex_delimiters[i];
245 MathSymbol const & ms = mathSymbol(delim);
246 // get pixmap with bullets
247 QPixmap pixmap = getPixmap("images/math/", toqstr(ms.icon), "svgz,png");
249 icon.addPixmap(getSelectedPixmap(pixmap, icon_size), QIcon::Selected);
250 QListWidgetItem * lwi = new QListWidgetItem(icon, QString());
251 setDelimiterName(lwi, delim);
252 left_list_items_[ms.unicode] = lwi;
253 lwi->setToolTip(toqstr(delim));
254 lwi->setSizeHint(icon_size);
255 leftLW->addItem(lwi);
258 for (int i = 0; i != leftLW->count(); ++i) {
259 MathSymbol const & ms = mathSymbol(getDelimiterName(leftLW->item(i)));
260 QListWidgetItem * rwi = left_list_items_[doMatch(ms.unicode)]->clone();
261 right_list_items_[ms.unicode] = rwi;
262 rightLW->addItem(rwi);
265 // The last element is the empty one.
266 QListWidgetItem * lwi = new QListWidgetItem(qt_("(None)"));
267 lwi->setToolTip(qt_("No Delimiter"));
268 left_list_items_['?'] = lwi;
269 QListWidgetItem * rwi = new QListWidgetItem(qt_("(None)"));
270 rwi->setToolTip(qt_("No Delimiter"));
271 right_list_items_['?'] = rwi;
272 leftLW->addItem(lwi);
273 rightLW->addItem(rwi);
275 sizeCO->addItem(qt_("Variable"));
277 for (int i = 0; *biggui[i]; ++i)
278 sizeCO->addItem(qt_(biggui[i]));
280 on_leftLW_currentRowChanged(0);
281 // synchronise the scroll bars
282 on_matchCB_stateChanged(matchCB->checkState());
283 bc().setPolicy(ButtonPolicy::IgnorantPolicy);
287 char_type GuiDelimiter::doMatch(char_type const symbol)
289 string const & str = texName(symbol);
305 else if (str == "rceil")
307 else if (str == "lceil")
309 else if (str == "rfloor")
311 else if (str == "lfloor")
313 else if (str == "rangle")
315 else if (str == "langle")
317 else if (str == "llbracket")
319 else if (str == "rrbracket")
321 else if (str == "backslash")
328 return mathSymbol(match).unicode;
332 void GuiDelimiter::updateTeXCode(int size)
334 bool const bigsize = size != 0;
336 docstring left_str = fix_name(getDelimiterName(leftLW->currentItem()),
338 docstring right_str = fix_name(getDelimiterName(rightLW->currentItem()),
342 tex_code_ = left_str + ' ' + right_str;
344 tex_code_ = from_ascii(bigleft[size]) + ' '
346 + from_ascii(bigright[size]) + ' '
350 // Generate TeX-code for GUI display.
351 // FIXME: Instead of reconstructing the TeX code it would be nice to
352 // FIXME: retrieve the LateX code directly from mathed.
353 // In all cases, we want the '\' prefix if needed, so we pass 'true'
355 left_str = fix_name(getDelimiterName(leftLW->currentItem()),
357 right_str = fix_name(getDelimiterName(rightLW->currentItem()),
361 code_str = "\\left" + left_str + " \\right" + right_str;
363 // There should be nothing in the TeX-code when the delimiter is "None".
365 code_str = "\\" + from_ascii(bigleft[size]) + left_str + ' ';
366 if (right_str != ".")
367 code_str += "\\" + from_ascii(bigright[size]) + right_str;
370 texCodeL->setText(qt_("TeX Code: ") + toqstr(code_str));
372 // Enable the Swap button with non-matched pairs
373 bool const allow_swap =
374 (doMatch(mathSymbol(getDelimiterName(leftLW->currentItem())).unicode)
375 != mathSymbol(getDelimiterName(rightLW->currentItem())).unicode);
376 swapPB->setEnabled(allow_swap);
380 void GuiDelimiter::on_buttonBox_clicked(QAbstractButton * button)
382 switch (buttonBox->standardButton(button)) {
383 case QDialogButtonBox::Apply:
386 case QDialogButtonBox::Ok:
389 case QDialogButtonBox::Cancel:
398 void GuiDelimiter::insert()
400 if (sizeCO->currentIndex() == 0)
401 dispatch(FuncRequest(LFUN_MATH_DELIM, tex_code_));
403 docstring command = '"' + tex_code_ + '"';
404 command = support::subst(command, from_ascii(" "), from_ascii("\" \""));
405 dispatch(FuncRequest(LFUN_MATH_BIGDELIM, command));
407 buttonBox->button(QDialogButtonBox::Cancel)->setText(qt_("Close"));
411 void GuiDelimiter::on_sizeCO_activated(int index)
413 updateTeXCode(index);
417 void GuiDelimiter::on_leftLW_itemActivated(QListWidgetItem *)
419 // do not auto-apply if !matchCB->isChecked()
420 if (!matchCB->isChecked())
427 void GuiDelimiter::on_rightLW_itemActivated(QListWidgetItem *)
429 // do not auto-apply if !matchCB->isChecked()
430 if (!matchCB->isChecked())
437 void GuiDelimiter::on_leftLW_currentRowChanged(int item)
439 if (matchCB->isChecked())
440 rightLW->setCurrentRow(item);
442 updateTeXCode(sizeCO->currentIndex());
446 void GuiDelimiter::on_rightLW_currentRowChanged(int item)
448 if (matchCB->isChecked())
449 leftLW->setCurrentRow(item);
451 updateTeXCode(sizeCO->currentIndex());
455 void GuiDelimiter::on_matchCB_stateChanged(int state)
457 // Synchronise the vertical scroll bars when checked
458 QScrollBar * ls = leftLW->verticalScrollBar();
459 QScrollBar * rs = rightLW->verticalScrollBar();
461 if (state == Qt::Checked) {
462 on_leftLW_currentRowChanged(leftLW->currentRow());
464 connect(ls, SIGNAL(valueChanged(int)), rs, SLOT(setValue(int)),
465 Qt::UniqueConnection);
466 connect(rs, SIGNAL(valueChanged(int)), ls, SLOT(setValue(int)),
467 Qt::UniqueConnection);
468 rs->setValue(ls->value());
474 updateTeXCode(sizeCO->currentIndex());
477 void GuiDelimiter::on_swapPB_clicked()
479 // Get current math symbol for each side.
480 MathSymbol const & lms =
481 mathSymbol(getDelimiterName(leftLW->currentItem()));
482 MathSymbol const & rms =
483 mathSymbol(getDelimiterName(rightLW->currentItem()));
486 char_type const lc = doMatch(rms.unicode);
487 char_type const rc = doMatch(lms.unicode);
489 // Convert back to QString to locate them in the widget.
490 MathSymbol const & nlms = mathSymbol(texName(lc));
491 MathSymbol const & nrms = mathSymbol(texName(rc));
493 // Locate matching QListWidgetItem.
494 QListWidgetItem * lwi = left_list_items_[nlms.unicode];
495 QListWidgetItem * rwi = right_list_items_[nrms.unicode];
498 leftLW->setCurrentItem(lwi);
499 rightLW->setCurrentItem(rwi);
501 updateTeXCode(sizeCO->currentIndex());
505 } // namespace frontend
508 #include "moc_GuiDelimiter.cpp"