1
// --------------------------------------------------------------------
2
// Lua bindings for Qt dialogs
3
// --------------------------------------------------------------------
6
This file is part of the extensible drawing editor Ipe.
7
Copyright (C) 1993-2009 Otfried Cheong
9
Ipe is free software; you can redistribute it and/or modify it
10
under the terms of the GNU General Public License as published by
11
the Free Software Foundation; either version 3 of the License, or
12
(at your option) any later version.
14
As a special exception, you have permission to link Ipe with the
15
CGAL library and distribute executables, as long as you follow the
16
requirements of the Gnu General Public License in regard to all of
17
the software in the executable aside from CGAL.
19
Ipe is distributed in the hope that it will be useful, but WITHOUT
20
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
21
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
22
License for more details.
24
You should have received a copy of the GNU General Public License
25
along with Ipe; if not, you can find it at
26
"http://www.gnu.org/copyleft/gpl.html", or write to the Free
27
Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
42
#include <QApplication>
45
#include <QCloseEvent>
46
#include <QColorDialog>
50
#include <QFileDialog>
51
#include <QGridLayout>
52
#include <QInputDialog>
55
#include <QListWidget>
57
#include <QMessageBox>
58
#include <QPushButton>
60
#include <QSyntaxHighlighter>
69
using namespace ipeui;
71
// --------------------------------------------------------------------
73
inline Dialog **check_dialog(lua_State *L, int i)
75
return (Dialog **) luaL_checkudata(L, i, "Ipe.dialog");
78
inline QMenu **check_menu(lua_State *L, int i)
80
return (QMenu **) luaL_checkudata(L, i, "Ipe.menu");
83
inline Timer **check_timer(lua_State *L, int i)
85
return (Timer **) luaL_checkudata(L, i, "Ipe.timer");
88
// --------------------------------------------------------------------
90
static void push_string(lua_State *L, const QString &str)
92
lua_pushstring(L, str.toUtf8());
95
inline QString tostring(lua_State *L, int i)
97
return QString::fromUtf8(lua_tostring(L, i));
100
inline QString checkstring(lua_State *L, int i)
102
return QString::fromUtf8(luaL_checkstring(L, i));
105
static QWidget *check_parent(lua_State *L, int i)
109
QWidget **p = (QWidget **) luaL_checkudata(L, i, "Ipe.appui");
113
// --------------------------------------------------------------------
115
class XmlHighlighter : public QSyntaxHighlighter
118
XmlHighlighter(QTextEdit *textEdit);
120
void applyFormat(const QString &text, QRegExp &exp,
121
const QTextCharFormat &format);
122
virtual void highlightBlock(const QString &text);
125
void XmlHighlighter::applyFormat(const QString &text, QRegExp &exp,
126
const QTextCharFormat &format)
128
int index = text.indexOf(exp);
130
int length = exp.matchedLength();
131
setFormat(index, length, format);
132
index = text.indexOf(exp, index + length);
136
void XmlHighlighter::highlightBlock(const QString &text)
138
QTextCharFormat tagFormat, stringFormat, numberFormat;
139
tagFormat.setFontWeight(QFont::Bold);
140
tagFormat.setForeground(Qt::blue);
141
stringFormat.setForeground(Qt::darkMagenta);
142
numberFormat.setForeground(Qt::red);
144
QRegExp tagExp( "<.*>" );
145
QRegExp stringExp( "\"[a-zA-Z]*\"" );
146
QRegExp numberExp( "[+|-]*[0-9]*.[0-9][0-9]*" );
147
applyFormat(text, tagExp, tagFormat);
148
applyFormat(text, stringExp, stringFormat);
149
applyFormat(text, numberExp, numberFormat);
152
XmlHighlighter::XmlHighlighter(QTextEdit *textEdit)
153
: QSyntaxHighlighter(textEdit)
158
// --------------------------------------------------------------------
160
class LatexHighlighter : public QSyntaxHighlighter
163
LatexHighlighter(QTextEdit *textEdit);
165
void applyFormat(const QString &text, QRegExp &exp,
166
const QTextCharFormat &format);
167
virtual void highlightBlock(const QString &text);
170
void LatexHighlighter::applyFormat(const QString &text, QRegExp &exp,
171
const QTextCharFormat &format)
173
int index = text.indexOf(exp);
175
int length = exp.matchedLength();
176
setFormat(index, length, format);
177
index = text.indexOf(exp, index + length);
181
void LatexHighlighter::highlightBlock(const QString &text)
183
QTextCharFormat mathFormat, tagFormat;
184
mathFormat.setForeground(Qt::red);
185
tagFormat.setFontWeight(QFont::Bold);
186
tagFormat.setForeground(Qt::blue);
188
QRegExp mathExp( "\\$[^$]+\\$" );
189
QRegExp tagExp( "\\\\[a-zA-Z]+" );
190
applyFormat(text, mathExp, mathFormat);
191
applyFormat(text, tagExp, tagFormat);
194
LatexHighlighter::LatexHighlighter(QTextEdit *textEdit)
195
: QSyntaxHighlighter(textEdit)
200
// --------------------------------------------------------------------
202
Dialog::Dialog(lua_State *L0, QWidget *parent) :QDialog(parent)
205
iLuaDialog = LUA_NOREF;
206
QGridLayout *lo = new QGridLayout;
208
QShortcut *shortcut = new QShortcut(QKeySequence("Ctrl+Return"), this);
209
connect(shortcut, SIGNAL(activated()), SLOT(accept()));
214
// dereference lua methods
215
for (uint i = 0; i < iElements.size(); ++i)
216
luaL_unref(L, LUA_REGISTRYINDEX, iElements[i].lua_method);
217
luaL_unref(L, LUA_REGISTRYINDEX, iLuaDialog);
220
void Dialog::callLua()
222
// only call back to Lua during execute()
223
if (iLuaDialog == LUA_NOREF)
226
QObject *s = sender();
227
for (uint i = 0; i < iElements.size(); ++i) {
228
if (s == iElements[i].widget) {
229
lua_rawgeti(L, LUA_REGISTRYINDEX, iElements[i].lua_method);
230
lua_rawgeti(L, LUA_REGISTRYINDEX, iLuaDialog);
237
QGridLayout *Dialog::gridlayout()
239
return qobject_cast<QGridLayout *>(layout());
242
int Dialog::add(lua_State *L)
244
static const char * const typenames[] =
245
{ "button", "text", "list", "label", "combo", "checkbox", "input", 0 };
247
QString name = checkstring(L, 2);
248
int type = luaL_checkoption(L, 3, 0, typenames);
249
luaL_checktype(L, 4, LUA_TTABLE);
250
int row = luaL_checkint(L, 5) - 1;
251
int col = luaL_checkint(L, 6) - 1;
254
if (!lua_isnoneornil(L, 7))
255
rowstretch = luaL_checkint(L, 7);
256
if (!lua_isnoneornil(L, 8))
257
colstretch = luaL_checkint(L, 8);
262
m.lua_method = LUA_NOREF;
291
QGridLayout *lo = gridlayout();
292
lo->addWidget(m.widget, row, col, rowstretch, colstretch);
293
iElements.push_back(m);
297
void Dialog::addButton(lua_State *L, SElement &m)
299
lua_getfield(L, 4, "label");
300
luaL_argcheck(L, lua_isstring(L, -1), 4, "no button label");
301
QString label = tostring(L, -1);
302
QPushButton *b = new QPushButton(label, this);
304
lua_getfield(L, 4, "action");
305
if (lua_isstring(L, -1)) {
306
QString s = tostring(L, -1);
308
connect(b, SIGNAL(clicked()), SLOT(accept()));
309
else if (s == "reject")
310
connect(b, SIGNAL(clicked()), SLOT(reject()));
312
luaL_argerror(L, 4, "unknown action");
313
} else if (lua_isfunction(L, -1)) {
314
lua_pushvalue(L, -1);
315
m.lua_method = luaL_ref(L, LUA_REGISTRYINDEX);
316
connect(b, SIGNAL(clicked()), SLOT(callLua()));
317
} else if (!lua_isnil(L, -1))
318
luaL_argerror(L, 4, "unknown action type");
319
lua_pop(L, 2); // action, label
322
void Dialog::addTextEdit(lua_State *L, SElement &m)
324
QTextEdit *t = new QTextEdit(this);
325
t->setAcceptRichText(false);
327
lua_getfield(L, 4, "read_only");
328
if (lua_toboolean(L, -1))
329
t->setReadOnly(true);
330
lua_getfield(L, 4, "syntax");
331
if (!lua_isnil(L, -1)) {
332
QString s = tostring(L, -1);
333
if (s == "logfile") {
335
} else if (s == "xml") {
337
(void) new XmlHighlighter(t);
338
} else if (s == "latex") {
339
(void) new LatexHighlighter(t);
341
luaL_argerror(L, 4, "unknown syntax");
343
lua_pop(L, 2); // syntax, read_only
346
static void setListItems(lua_State *L, int index, QListWidget *l = 0,
349
int no = lua_objlen(L, index);
350
for (int i = 1; i <= no; ++i) {
351
lua_rawgeti(L, index, i);
352
luaL_argcheck(L, lua_isstring(L, -1), index, "items must be strings");
353
QString item = tostring(L, -1);
354
if (l) l->addItem(item);
355
if (b) b->addItem(item);
356
lua_pop(L, 1); // item
360
void Dialog::addList(lua_State *L, SElement &m)
362
QListWidget *l = new QListWidget(this);
364
setListItems(L, 4, l, 0);
367
void Dialog::addLabel(lua_State *L, SElement &m)
369
lua_getfield(L, 4, "label");
370
luaL_argcheck(L, lua_isstring(L, -1), 4, "no label");
371
QString label = tostring(L, -1);
372
QLabel *l = new QLabel(label, this);
374
lua_pop(L, 1); // label
377
void Dialog::addCombo(lua_State *L, SElement &m)
379
QComboBox *b = new QComboBox(this);
381
setListItems(L, 4, 0, b);
384
void Dialog::addCheckbox(lua_State *L, SElement &m)
386
lua_getfield(L, 4, "label");
387
luaL_argcheck(L, lua_isstring(L, -1), 4, "no label");
388
QString label = tostring(L, -1);
389
QCheckBox *b = new QCheckBox(label, this);
391
lua_getfield(L, 4, "action");
392
if (!lua_isnil(L, -1)) {
393
luaL_argcheck(L, lua_isfunction(L, -1), 4, "unknown action type");
394
lua_pushvalue(L, -1);
395
m.lua_method = luaL_ref(L, LUA_REGISTRYINDEX);
396
connect(b, SIGNAL(stateChanged(int)), SLOT(callLua()));
398
lua_pop(L, 2); // action, label
401
void Dialog::addInput(lua_State *L, SElement &m)
403
QLineEdit *e = new QLineEdit(this);
407
int Dialog::findElement(lua_State *L, int index)
409
QString name = checkstring(L, index);
410
for (uint i = 0; i < iElements.size(); ++i) {
411
if (iElements[i].name == name)
414
return luaL_argerror(L, index, "no such element in dialog");
417
static void markupLog(QTextEdit *t, const QString &text)
419
QTextDocument *doc = new QTextDocument(t);
420
doc->setPlainText(text);
421
QTextCursor cursor(doc);
425
int nextErr = text.indexOf(QLatin1String("\n!"), curPos);
430
while (curPos < nextErr + 1) {
431
if (text[curPos++] == QLatin1Char('\n'))
434
cursor.movePosition(QTextCursor::Down, QTextCursor::MoveAnchor, lines);
435
int pos = cursor.position();
436
cursor.movePosition(QTextCursor::Down);
437
cursor.setPosition(pos, QTextCursor::KeepAnchor);
440
s.sprintf("err%d", errNo);
441
QTextCharFormat format;
442
format.setBackground(Qt::yellow);
443
format.setAnchorName(s);
444
format.setAnchor(true);
445
cursor.setCharFormat(format);
448
t->scrollToAnchor(QLatin1String("err1"));
452
static void xmlIndent(QString &text)
454
QStringList l = text.split('\n');
456
QRegExp begExp( "<(?!/).*>" );
457
QRegExp endExp( "</.*>" );
460
for (QStringList::Iterator it = l.begin(); it != l.end(); ++it) {
461
if (it->contains(endExp))
463
for (int i = 0; i < tabLevel; i++)
465
if (it->contains(begExp))
472
int Dialog::set(lua_State *L)
474
int idx = findElement(L, 2);
476
QLabel *l = qobject_cast<QLabel *>(iElements[idx].widget);
478
l->setText(checkstring(L, 3));
481
QTextEdit *t = qobject_cast<QTextEdit *>(iElements[idx].widget);
483
QString text = checkstring(L, 3);
484
if (iElements[idx].flags & ELogFile) {
487
t->setPlainText(text);
490
QListWidget *list = qobject_cast<QListWidget *>(iElements[idx].widget);
492
if (lua_isnumber(L, 3)) {
493
int m = luaL_checkint(L, 3);
494
luaL_argcheck(L, 1 <= m && m <= list->count(), 3,
495
"list index out of bounds");
496
list->setCurrentRow(m - 1);
498
luaL_checktype(L, 3, LUA_TTABLE);
500
setListItems(L, 3, list, 0);
505
QComboBox *b = qobject_cast<QComboBox *>(iElements[idx].widget);
507
if (lua_isnumber(L, 3)) {
508
int m = luaL_checkint(L, 3);
509
luaL_argcheck(L, 1 <= m && m <= b->count(), 3,
510
"list index out of bounds");
511
b->setCurrentIndex(m - 1);
513
luaL_checktype(L, 3, LUA_TTABLE);
515
setListItems(L, 3, 0, b);
520
QCheckBox *ch = qobject_cast<QCheckBox *>(iElements[idx].widget);
522
bool value = lua_toboolean(L, 3);
523
ch->setChecked(value);
527
QLineEdit *le = qobject_cast<QLineEdit *>(iElements[idx].widget);
529
QString text = checkstring(L, 3);
534
return luaL_argerror(L, 2, "no suitable element");
537
int Dialog::get(lua_State *L)
539
int idx = findElement(L, 2);
541
QTextEdit *t = qobject_cast<QTextEdit *>(iElements[idx].widget);
543
QString s = t->toPlainText();
548
QListWidget *list = qobject_cast<QListWidget *>(iElements[idx].widget);
550
if (list->currentRow() >= 0)
551
lua_pushnumber(L, list->currentRow() + 1);
557
QComboBox *b = qobject_cast<QComboBox *>(iElements[idx].widget);
559
lua_pushnumber(L, b->currentIndex() + 1);
563
QCheckBox *ch = qobject_cast<QCheckBox *>(iElements[idx].widget);
565
lua_pushboolean(L, ch->isChecked());
569
QLineEdit *le = qobject_cast<QLineEdit *>(iElements[idx].widget);
571
push_string(L, le->text());
575
return luaL_argerror(L, 2, "no suitable element");
578
int Dialog::execute(lua_State *L)
580
// remember Lua object for dialog for callbacks
582
iLuaDialog = luaL_ref(L, LUA_REGISTRYINDEX);
584
// discard reference to dialog object
585
// (otherwise the circular reference will stop Lua gc)
586
luaL_unref(L, LUA_REGISTRYINDEX, iLuaDialog);
587
iLuaDialog = LUA_NOREF;
591
int Dialog::setEnabled(lua_State *L)
593
int idx = findElement(L, 2);
594
bool value = lua_toboolean(L, 3);
595
iElements[idx].widget->setEnabled(value);
599
// --------------------------------------------------------------------
601
static int dialog_constructor(lua_State *L)
603
QWidget *parent = check_parent(L, 1);
604
QString s = checkstring(L, 2);
606
Dialog **dlg = (Dialog **) lua_newuserdata(L, sizeof(Dialog *));
608
luaL_getmetatable(L, "Ipe.dialog");
609
lua_setmetatable(L, -2);
610
*dlg = new Dialog(L, parent);
611
(*dlg)->setWindowTitle(s);
615
static int dialog_tostring(lua_State *L)
618
lua_pushfstring(L, "Dialog@%p", lua_topointer(L, 1));
622
static int dialog_destructor(lua_State *L)
624
// fprintf(stderr, "Dialog destructor\n");
625
Dialog **dlg = check_dialog(L, 1);
631
static int dialog_execute(lua_State *L)
633
Dialog **dlg = check_dialog(L, 1);
634
if (!lua_isnoneornil(L, 2)) {
635
luaL_argcheck(L, lua_istable(L, 2), 2, "argument is not a table");
636
lua_rawgeti(L, 2, 1);
637
luaL_argcheck(L, lua_isnumber(L, -1), 2, "width is not a number");
638
lua_rawgeti(L, 2, 2);
639
luaL_argcheck(L, lua_isnumber(L, -1), 2, "height is not a number");
640
int w = lua_tointeger(L, -2);
641
int h = lua_tointeger(L, -1);
642
lua_pop(L, 2); // w & h
643
(*dlg)->resize(w, h);
645
lua_pushboolean(L, (*dlg)->execute(L));
649
static int dialog_setStretch(lua_State *L)
651
static const char * const typenames[] = { "row", "column", 0 };
652
Dialog **dlg = check_dialog(L, 1);
653
int type = luaL_checkoption(L, 2, 0, typenames);
654
int rowcol = luaL_checkint(L, 3) - 1;
655
int stretch = luaL_checkint(L, 4);
657
QGridLayout *lo = (*dlg)->gridlayout();
660
lo->setRowStretch(rowcol, stretch);
662
lo->setColumnStretch(rowcol, stretch);
666
static int dialog_add(lua_State *L)
668
Dialog **dlg = check_dialog(L, 1);
669
return (*dlg)->add(L);
672
static int dialog_set(lua_State *L)
674
Dialog **dlg = check_dialog(L, 1);
675
return (*dlg)->set(L);
678
static int dialog_get(lua_State *L)
680
Dialog **dlg = check_dialog(L, 1);
681
return (*dlg)->get(L);
684
static int dialog_setEnabled(lua_State *L)
686
Dialog **dlg = check_dialog(L, 1);
687
return (*dlg)->setEnabled(L);
690
// --------------------------------------------------------------------
692
static const struct luaL_Reg dialog_methods[] = {
693
{ "__tostring", dialog_tostring },
694
{ "__gc", dialog_destructor },
695
{ "execute", dialog_execute },
696
{ "setStretch", dialog_setStretch },
697
{ "add", dialog_add },
698
{ "set", dialog_set },
699
{ "get", dialog_get },
700
{ "setEnabled", dialog_setEnabled },
704
// --------------------------------------------------------------------
706
MenuAction::MenuAction(const QString &name, int number,
707
const QString &item, const QString &text,
709
: QAction(text, parent)
716
static int menu_constructor(lua_State *L)
718
QMenu **m = (QMenu **) lua_newuserdata(L, sizeof(QMenu *));
720
luaL_getmetatable(L, "Ipe.menu");
721
lua_setmetatable(L, -2);
727
static int menu_tostring(lua_State *L)
730
lua_pushfstring(L, "Menu@%p", lua_topointer(L, 1));
734
static int menu_destructor(lua_State *L)
736
QMenu **m = check_menu(L, 1);
742
static int menu_execute(lua_State *L)
744
QMenu **m = check_menu(L, 1);
745
int vx = luaL_checkint(L, 2);
746
int vy = luaL_checkint(L, 3);
747
QAction *a = (*m)->exec(QPoint(vx, vy));
748
MenuAction *ma = qobject_cast<MenuAction *>(a);
750
push_string(L, ma->name());
751
lua_pushnumber(L, ma->number());
752
push_string(L, ma->itemName());
760
static QIcon colorIcon(double red, double green, double blue)
762
QPixmap pixmap(SIZE, SIZE);
763
pixmap.fill(QColor(int(red * 255.0 + 0.5),
764
int(green * 255.0 + 0.5),
765
int(blue * 255.0 + 0.5)));
766
return QIcon(pixmap);
769
static int menu_add(lua_State *L)
771
QMenu **m = check_menu(L, 1);
772
QString name = checkstring(L, 2);
773
QString title = checkstring(L, 3);
774
if (lua_gettop(L) == 3) {
775
(*m)->addAction(new MenuAction(name, 0, QString(), title, *m));
777
luaL_argcheck(L, lua_istable(L, 4), 4, "argument is not a table");
778
bool hasmap = !lua_isnoneornil(L, 5) && lua_isfunction(L, 5);
779
bool hastable = !hasmap && !lua_isnoneornil(L, 5);
780
bool hascolor = !lua_isnoneornil(L, 6) && lua_isfunction(L, 6);
781
bool hascheck = !hascolor && !lua_isnoneornil(L, 6);
783
luaL_argcheck(L, lua_istable(L, 5), 5,
784
"argument is not a function or table");
787
luaL_argcheck(L, lua_isstring(L, 6), 6,
788
"argument is not a function or string");
789
current = checkstring(L, 6);
791
int no = lua_objlen(L, 4);
792
QMenu *sm = new QMenu(title, *m);
793
for (int i = 1; i <= no; ++i) {
794
lua_rawgeti(L, 4, i);
795
luaL_argcheck(L, lua_isstring(L, -1), 4, "items must be strings");
796
QString item = tostring(L, -1);
799
lua_rawgeti(L, 5, i);
800
luaL_argcheck(L, lua_isstring(L, -1), 5, "labels must be strings");
801
text = tostring(L, -1);
805
lua_pushvalue(L, 5); // function
806
lua_pushnumber(L, i); // index
807
lua_pushvalue(L, -3); // name
808
lua_call(L, 2, 1); // function returns label
809
luaL_argcheck(L, lua_isstring(L, -1), 5,
810
"function does not return string");
811
text = tostring(L, -1);
812
lua_pop(L, 1); // pop result
814
MenuAction *ma = new MenuAction(name, i, item, text, sm);
816
lua_pushvalue(L, 6); // function
817
lua_pushnumber(L, i); // index
818
lua_pushvalue(L, -3); // name
819
lua_call(L, 2, 3); // function returns red, green, blue
820
double red = luaL_checknumber(L, -3);
821
double green = luaL_checknumber(L, -2);
822
double blue = luaL_checknumber(L, -1);
823
lua_pop(L, 3); // pop result
824
ma->setIcon(colorIcon(red, green, blue));
827
ma->setCheckable(true);
828
ma->setChecked(item == current);
830
lua_pop(L, 1); // item
838
// --------------------------------------------------------------------
840
static const struct luaL_Reg menu_methods[] = {
841
{ "__tostring", menu_tostring },
842
{ "__gc", menu_destructor },
843
{ "execute", menu_execute },
848
// --------------------------------------------------------------------
850
static int ipeui_getString(lua_State *L)
852
QWidget *parent = check_parent(L, 1);
853
QString s = checkstring(L, 2);
855
QString str = QInputDialog::getText(parent, QString("Ipe"), s,
859
if (ok && !str.isEmpty()) {
866
static int ipeui_getDouble(lua_State *L)
868
QWidget *parent = check_parent(L, 1);
869
QString title = checkstring(L, 2);
870
QString detail = checkstring(L, 3);
871
double value = luaL_checknumber(L, 4);
872
double minv = luaL_checknumber(L, 5);
873
double maxv = luaL_checknumber(L, 6);
874
int decimals = luaL_checkint(L, 7);
876
double d = QInputDialog::getDouble(parent, title, detail,
877
value, minv, maxv, decimals, &ok);
879
lua_pushnumber(L, d);
885
static int ipeui_getInt(lua_State *L)
887
QWidget *parent = check_parent(L, 1);
888
QString title = checkstring(L, 2);
889
QString detail = checkstring(L, 3);
890
int value = luaL_checkint(L, 4);
891
int minv = luaL_checkint(L, 5);
892
int maxv = luaL_checkint(L, 6);
893
int step = luaL_checkint(L, 7);
895
#if QT_VERSION >= 0x040500
896
int d = QInputDialog::getInt(parent, title, detail,
897
value, minv, maxv, step, &ok);
900
int d = int(QInputDialog::getDouble(parent, title, detail,
901
value, minv, maxv, 0, &ok));
904
lua_pushnumber(L, d);
910
static int ipeui_getColor(lua_State *L)
912
QWidget *parent = check_parent(L, 1);
913
QString title = checkstring(L, 2);
914
QColor initial = QColor::fromRgbF(luaL_checknumber(L, 3),
915
luaL_checknumber(L, 4),
916
luaL_checknumber(L, 5));
917
#if QT_VERSION >= 0x040500
918
QColor changed = QColorDialog::getColor(initial, parent, title);
920
QColor changed = QColorDialog::getColor(initial, parent);
922
if (changed.isValid()) {
923
lua_pushnumber(L, changed.redF());
924
lua_pushnumber(L, changed.greenF());
925
lua_pushnumber(L, changed.blueF());
931
// --------------------------------------------------------------------
933
static int ipeui_fileDialog(lua_State *L)
935
static const char * const typenames[] = { "open", "save", 0 };
937
QWidget *parent = check_parent(L, 1);
938
int type = luaL_checkoption(L, 2, 0, typenames);
939
QString caption = checkstring(L, 3);
940
QString filter = checkstring(L, 4);
943
if (!lua_isnoneornil(L, 5))
944
dir = checkstring(L, 5);
946
if (!lua_isnoneornil(L, 6))
947
selected = checkstring(L, 6);
949
QFileDialog dialog(parent);
950
dialog.setWindowTitle(caption);
951
dialog.setNameFilter(filter);
952
dialog.setConfirmOverwrite(false);
955
dialog.setFileMode(QFileDialog::ExistingFile);
956
dialog.setAcceptMode(QFileDialog::AcceptOpen);
958
dialog.setFileMode(QFileDialog::AnyFile);
959
dialog.setAcceptMode(QFileDialog::AcceptSave);
962
if (!selected.isNull())
963
dialog.selectFilter(selected);
965
dialog.setDirectory(dir);
967
if (dialog.exec() == QDialog::Accepted) {
968
QStringList fns = dialog.selectedFiles();
969
if (!fns.isEmpty()) {
970
push_string(L, fns[0]);
971
push_string(L, dialog.selectedNameFilter());
978
// --------------------------------------------------------------------
980
static int ipeui_messageBox(lua_State *L)
982
static const char * const options[] = {
983
"none", "warning", "information", "question", "critical", 0 };
984
static const char * const buttontype[] = {
985
"ok", "okcancel", "yesnocancel", "discardcancel",
986
"savediscardcancel", 0 };
988
QWidget *parent = check_parent(L, 1);
989
int type = luaL_checkoption(L, 2, "none", options);
990
QString text = checkstring(L, 3);
991
const char *details = 0;
992
if (!lua_isnoneornil(L, 4))
993
details = luaL_checkstring(L, 4);
995
if (lua_isnumber(L, 5))
996
buttons = luaL_checkint(L, 5);
997
else if (!lua_isnoneornil(L, 5))
998
buttons = luaL_checkoption(L, 5, 0, buttontype);
1000
QMessageBox msgBox(parent);
1001
msgBox.setText(text);
1003
msgBox.setInformativeText(QString::fromUtf8(details));
1008
msgBox.setIcon(QMessageBox::NoIcon);
1011
msgBox.setIcon(QMessageBox::Warning);
1014
msgBox.setIcon(QMessageBox::Information);
1017
msgBox.setIcon(QMessageBox::Question);
1020
msgBox.setIcon(QMessageBox::Critical);
1027
msgBox.setStandardButtons(QMessageBox::Ok);
1030
msgBox.setStandardButtons(QMessageBox::Ok|QMessageBox::Cancel);
1033
msgBox.setStandardButtons(QMessageBox::Yes|QMessageBox::No|
1034
QMessageBox::Cancel);
1037
msgBox.setStandardButtons(QMessageBox::Discard|QMessageBox::Cancel);
1040
msgBox.setStandardButtons(QMessageBox::Save|QMessageBox::Discard|
1041
QMessageBox::Cancel);
1045
int ret = msgBox.exec();
1048
case QMessageBox::Ok:
1049
case QMessageBox::Yes:
1050
case QMessageBox::Save:
1051
lua_pushnumber(L, 1);
1053
case QMessageBox::No:
1054
case QMessageBox::Discard:
1055
lua_pushnumber(L, 0);
1057
case QMessageBox::Cancel:
1059
lua_pushnumber(L, -1);
1065
// --------------------------------------------------------------------
1067
class EditorThread : public QThread
1070
EditorThread(const QString &cmd);
1078
EditorThread::EditorThread(const QString &cmd) : QThread()
1083
void EditorThread::run()
1085
int result = std::system(iCommand.toUtf8());
1089
class EditorDialog : public QDialog
1092
EditorDialog(QWidget *parent = 0);
1094
void closeEvent(QCloseEvent *ev);
1097
EditorDialog::EditorDialog(QWidget *parent)
1100
QGridLayout *lo = new QGridLayout;
1102
setWindowTitle("Ipe: waiting");
1103
QLabel *l = new QLabel("Waiting for external editor", this);
1104
lo->addWidget(l, 0, 0);
1107
void EditorDialog::closeEvent(QCloseEvent *ev)
1112
static int ipeui_wait(lua_State *L)
1114
QString cmd = checkstring(L, 1);
1116
EditorDialog *dialog = new EditorDialog();
1118
EditorThread *thread = new EditorThread(cmd);
1119
dialog->connect(thread, SIGNAL(finished()), SLOT(accept()));
1128
// --------------------------------------------------------------------
1130
Timer::Timer(lua_State *L0, int lua_object,
1131
const QString &method)
1134
iLuaObject = lua_object;
1136
iTimer = new QTimer();
1137
connect(iTimer, SIGNAL(timeout()), SLOT(callLua()));
1142
luaL_unref(L, LUA_REGISTRYINDEX, iLuaObject);
1146
void Timer::callLua()
1148
lua_rawgeti(L, LUA_REGISTRYINDEX, iLuaObject);
1149
lua_rawgeti(L, -1, 1); // get Lua object
1150
if (lua_isnil(L, -1)) {
1151
lua_pop(L, 2); // pop weak table, nil
1154
lua_getfield(L, -1, iMethod.toUtf8());
1155
if (lua_isnil(L, -1)) {
1156
lua_pop(L, 3); // pop weak table, table, nil
1159
lua_remove(L, -3); // remove weak table
1160
lua_insert(L, -2); // stack is now: method, table
1161
lua_call(L, 1, 0); // call method
1164
int Timer::setSingleShot(lua_State *L)
1166
bool t = lua_toboolean(L, 2);
1167
iTimer->setSingleShot(t);
1171
int Timer::setInterval(lua_State *L)
1173
int t = luaL_checkint(L, 2);
1174
iTimer->setInterval(t);
1178
int Timer::active(lua_State *L)
1180
lua_pushboolean(L, iTimer->isActive());
1184
int Timer::start(lua_State *L)
1190
int Timer::stop(lua_State *L)
1196
// --------------------------------------------------------------------
1198
static int timer_constructor(lua_State *L)
1200
luaL_argcheck(L, lua_istable(L, 1), 1, "argument is not a table");
1201
QString method = luaL_checkstring(L, 2);
1203
Timer **t = (Timer **) lua_newuserdata(L, sizeof(Timer *));
1205
luaL_getmetatable(L, "Ipe.timer");
1206
lua_setmetatable(L, -2);
1208
// create a table with weak reference to Lua object
1209
lua_createtable(L, 1, 1);
1210
lua_pushliteral(L, "v");
1211
lua_setfield(L, -2, "__mode");
1212
lua_pushvalue(L, -1);
1213
lua_setmetatable(L, -2);
1214
lua_pushvalue(L, 1);
1215
lua_rawseti(L, -2, 1);
1216
int lua_object = luaL_ref(L, LUA_REGISTRYINDEX);
1217
*t = new Timer(L, lua_object, method);
1221
static int timer_tostring(lua_State *L)
1224
lua_pushfstring(L, "Timer@%p", lua_topointer(L, 1));
1228
static int timer_destructor(lua_State *L)
1230
Timer **t = check_timer(L, 1);
1231
// fprintf(stderr, "Timer destructor\n");
1237
// --------------------------------------------------------------------
1239
static int timer_start(lua_State *L)
1241
Timer **t = check_timer(L, 1);
1242
return (*t)->start(L);
1245
static int timer_stop(lua_State *L)
1247
Timer **t = check_timer(L, 1);
1248
return (*t)->stop(L);
1251
static int timer_active(lua_State *L)
1253
Timer **t = check_timer(L, 1);
1254
return (*t)->active(L);
1257
static int timer_setinterval(lua_State *L)
1259
Timer **t = check_timer(L, 1);
1260
return (*t)->setInterval(L);
1263
static int timer_setsingleshot(lua_State *L)
1265
Timer **t = check_timer(L, 1);
1266
return (*t)->setSingleShot(L);
1269
// --------------------------------------------------------------------
1271
static const struct luaL_Reg timer_methods[] = {
1272
{ "__tostring", timer_tostring },
1273
{ "__gc", timer_destructor },
1274
{ "start", timer_start },
1275
{ "stop", timer_stop },
1276
{ "active", timer_active },
1277
{ "setInterval", timer_setinterval },
1278
{ "setSingleShot", timer_setsingleshot },
1282
// --------------------------------------------------------------------
1284
static int ipeui_mainloop(lua_State *L)
1286
QApplication::exec();
1290
static int ipeui_closeAllWindows(lua_State *L)
1292
QApplication::closeAllWindows();
1296
static int ipeui_setClipboard(lua_State *L)
1298
QString data = checkstring(L, 1);
1299
QClipboard *cb = QApplication::clipboard();
1304
static int ipeui_clipboard(lua_State *L)
1306
QClipboard *cb = QApplication::clipboard();
1307
QString data = cb->text();
1308
push_string(L, data);
1312
static int ipeui_local8bit(lua_State *L)
1314
QString data = checkstring(L, 1);
1315
QByteArray l8 = data.toLocal8Bit();
1316
lua_pushstring(L, l8.data());
1320
static int ipeui_currentDateTime(lua_State *L)
1322
QDateTime dt = QDateTime::currentDateTime();
1324
mod.sprintf("%04d%02d%02d%02d%02d%02d",
1325
dt.date().year(), dt.date().month(), dt.date().day(),
1326
dt.time().hour(), dt.time().minute(), dt.time().second());
1327
push_string(L, mod);
1332
static int ipeui_startBrowser(lua_State *L)
1334
const char *url = luaL_checkstring(L, 1);
1335
ShellExecuteA(0, "open", url, 0, 0, 0);
1340
// --------------------------------------------------------------------
1342
static const struct luaL_Reg ipeui_functions[] = {
1343
{ "Dialog", dialog_constructor },
1344
{ "Menu", menu_constructor },
1345
{ "Timer", timer_constructor },
1346
{ "getString", ipeui_getString },
1347
{ "getDouble", ipeui_getDouble },
1348
{ "getInt", ipeui_getInt },
1349
{ "getColor", ipeui_getColor },
1350
{ "fileDialog", ipeui_fileDialog },
1351
{ "messageBox", ipeui_messageBox },
1352
{ "WaitDialog", ipeui_wait },
1353
{ "mainLoop", ipeui_mainloop },
1354
{ "closeAllWindows", ipeui_closeAllWindows },
1355
{ "currentDateTime", ipeui_currentDateTime },
1356
{ "setClipboard", ipeui_setClipboard },
1357
{ "clipboard", ipeui_clipboard },
1358
{ "local8bit", ipeui_local8bit },
1360
{ "startBrowser", ipeui_startBrowser },
1365
// --------------------------------------------------------------------
1367
static void make_metatable(lua_State *L, const char *name,
1368
const struct luaL_Reg *methods)
1370
luaL_newmetatable(L, name);
1371
lua_pushstring(L, "__index");
1372
lua_pushvalue(L, -2); /* pushes the metatable */
1373
lua_settable(L, -3); /* metatable.__index = metatable */
1374
luaL_register(L, 0, methods);
1378
int luaopen_ipeui(lua_State *L)
1380
luaL_register(L, "ipeui", ipeui_functions);
1381
make_metatable(L, "Ipe.dialog", dialog_methods);
1382
make_metatable(L, "Ipe.menu", menu_methods);
1383
make_metatable(L, "Ipe.timer", timer_methods);
1387
// --------------------------------------------------------------------