~ubuntu-branches/ubuntu/precise/ipe/precise

« back to all changes in this revision

Viewing changes to src/ipeui/ipeui.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Steve M. Robbins
  • Date: 2009-12-11 21:22:35 UTC
  • mfrom: (4.1.6 sid)
  • Revision ID: james.westby@ubuntu.com-20091211212235-5iio4nzpra64snab
Tags: 7.0.10-1
* New upstream.  Closes: #551192.
  - New build-depends: libcairo2-dev, liblua5.1-0-dev, gsfonts
  - patches/config.diff: Remove.  Upstream build system replaced.
  - Runtime lib package changed to libipe7.0.10 from libipe1c2a
  - Devel package renamed to libipe-dev (from libipe1-dev)
  - Package ipe depends on lua5.1 due to ipe-update-master.

* rules: Re-write to use dh.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
// --------------------------------------------------------------------
 
2
// Lua bindings for Qt dialogs
 
3
// --------------------------------------------------------------------
 
4
/*
 
5
 
 
6
    This file is part of the extensible drawing editor Ipe.
 
7
    Copyright (C) 1993-2009  Otfried Cheong
 
8
 
 
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.
 
13
 
 
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.
 
18
 
 
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.
 
23
 
 
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.
 
28
 
 
29
*/
 
30
 
 
31
extern "C" {
 
32
#include <lua.h>
 
33
#include <lualib.h>
 
34
#include <lauxlib.h>
 
35
}
 
36
 
 
37
#include "ipeui.h"
 
38
 
 
39
#include <cstdio>
 
40
#include <cstdlib>
 
41
 
 
42
#include <QApplication>
 
43
#include <QCheckBox>
 
44
#include <QClipboard>
 
45
#include <QCloseEvent>
 
46
#include <QColorDialog>
 
47
#include <QComboBox>
 
48
#include <QDateTime>
 
49
#include <QDialog>
 
50
#include <QFileDialog>
 
51
#include <QGridLayout>
 
52
#include <QInputDialog>
 
53
#include <QLabel>
 
54
#include <QLineEdit>
 
55
#include <QListWidget>
 
56
#include <QMenu>
 
57
#include <QMessageBox>
 
58
#include <QPushButton>
 
59
#include <QShortcut>
 
60
#include <QSyntaxHighlighter>
 
61
#include <QTextEdit>
 
62
#include <QThread>
 
63
#include <QTimer>
 
64
 
 
65
#if defined(WIN32)
 
66
#include <windows.h>
 
67
#endif
 
68
 
 
69
using namespace ipeui;
 
70
 
 
71
// --------------------------------------------------------------------
 
72
 
 
73
inline Dialog **check_dialog(lua_State *L, int i)
 
74
{
 
75
  return (Dialog **) luaL_checkudata(L, i, "Ipe.dialog");
 
76
}
 
77
 
 
78
inline QMenu **check_menu(lua_State *L, int i)
 
79
{
 
80
  return (QMenu **) luaL_checkudata(L, i, "Ipe.menu");
 
81
}
 
82
 
 
83
inline Timer **check_timer(lua_State *L, int i)
 
84
{
 
85
  return (Timer **) luaL_checkudata(L, i, "Ipe.timer");
 
86
}
 
87
 
 
88
// --------------------------------------------------------------------
 
89
 
 
90
static void push_string(lua_State *L, const QString &str)
 
91
{
 
92
  lua_pushstring(L, str.toUtf8());
 
93
}
 
94
 
 
95
inline QString tostring(lua_State *L, int i)
 
96
{
 
97
  return QString::fromUtf8(lua_tostring(L, i));
 
98
}
 
99
 
 
100
inline QString checkstring(lua_State *L, int i)
 
101
{
 
102
  return QString::fromUtf8(luaL_checkstring(L, i));
 
103
}
 
104
 
 
105
static QWidget *check_parent(lua_State *L, int i)
 
106
{
 
107
  if (lua_isnil(L, i))
 
108
    return 0;
 
109
  QWidget **p = (QWidget **) luaL_checkudata(L, i, "Ipe.appui");
 
110
  return *p;
 
111
}
 
112
 
 
113
// --------------------------------------------------------------------
 
114
 
 
115
class XmlHighlighter : public QSyntaxHighlighter
 
116
{
 
117
public:
 
118
  XmlHighlighter(QTextEdit *textEdit);
 
119
protected:
 
120
  void applyFormat(const QString &text, QRegExp &exp,
 
121
                   const QTextCharFormat &format);
 
122
  virtual void highlightBlock(const QString &text);
 
123
};
 
124
 
 
125
void XmlHighlighter::applyFormat(const QString &text, QRegExp &exp,
 
126
                                 const QTextCharFormat &format)
 
127
{
 
128
  int index = text.indexOf(exp);
 
129
  while (index >= 0) {
 
130
    int length = exp.matchedLength();
 
131
    setFormat(index, length, format);
 
132
    index = text.indexOf(exp, index + length);
 
133
  }
 
134
}
 
135
 
 
136
void XmlHighlighter::highlightBlock(const QString &text)
 
137
{
 
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);
 
143
 
 
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);
 
150
}
 
151
 
 
152
XmlHighlighter::XmlHighlighter(QTextEdit *textEdit)
 
153
  : QSyntaxHighlighter(textEdit)
 
154
{
 
155
  // nothing
 
156
}
 
157
 
 
158
// --------------------------------------------------------------------
 
159
 
 
160
class LatexHighlighter : public QSyntaxHighlighter
 
161
{
 
162
public:
 
163
  LatexHighlighter(QTextEdit *textEdit);
 
164
protected:
 
165
  void applyFormat(const QString &text, QRegExp &exp,
 
166
                   const QTextCharFormat &format);
 
167
  virtual void highlightBlock(const QString &text);
 
168
};
 
169
 
 
170
void LatexHighlighter::applyFormat(const QString &text, QRegExp &exp,
 
171
                                   const QTextCharFormat &format)
 
172
{
 
173
  int index = text.indexOf(exp);
 
174
  while (index >= 0) {
 
175
    int length = exp.matchedLength();
 
176
    setFormat(index, length, format);
 
177
    index = text.indexOf(exp, index + length);
 
178
  }
 
179
}
 
180
 
 
181
void LatexHighlighter::highlightBlock(const QString &text)
 
182
{
 
183
  QTextCharFormat mathFormat, tagFormat;
 
184
  mathFormat.setForeground(Qt::red);
 
185
  tagFormat.setFontWeight(QFont::Bold);
 
186
  tagFormat.setForeground(Qt::blue);
 
187
 
 
188
  QRegExp mathExp( "\\$[^$]+\\$" );
 
189
  QRegExp tagExp( "\\\\[a-zA-Z]+" );
 
190
  applyFormat(text, mathExp, mathFormat);
 
191
  applyFormat(text, tagExp, tagFormat);
 
192
}
 
193
 
 
194
LatexHighlighter::LatexHighlighter(QTextEdit *textEdit)
 
195
  : QSyntaxHighlighter(textEdit)
 
196
{
 
197
  // nothing
 
198
}
 
199
 
 
200
// --------------------------------------------------------------------
 
201
 
 
202
Dialog::Dialog(lua_State *L0, QWidget *parent) :QDialog(parent)
 
203
{
 
204
  L = L0;
 
205
  iLuaDialog = LUA_NOREF;
 
206
  QGridLayout *lo = new QGridLayout;
 
207
  setLayout(lo);
 
208
  QShortcut *shortcut = new QShortcut(QKeySequence("Ctrl+Return"), this);
 
209
  connect(shortcut, SIGNAL(activated()), SLOT(accept()));
 
210
}
 
211
 
 
212
Dialog::~Dialog()
 
213
{
 
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);
 
218
}
 
219
 
 
220
void Dialog::callLua()
 
221
{
 
222
  // only call back to Lua during execute()
 
223
  if (iLuaDialog == LUA_NOREF)
 
224
    return;
 
225
 
 
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);
 
231
      lua_call(L, 1, 0);
 
232
      return;
 
233
    }
 
234
  }
 
235
}
 
236
 
 
237
QGridLayout *Dialog::gridlayout()
 
238
{
 
239
  return qobject_cast<QGridLayout *>(layout());
 
240
}
 
241
 
 
242
int Dialog::add(lua_State *L)
 
243
{
 
244
  static const char * const typenames[] =
 
245
    { "button", "text", "list", "label", "combo", "checkbox", "input", 0 };
 
246
 
 
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;
 
252
  int rowstretch = 1;
 
253
  int colstretch = 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);
 
258
 
 
259
  SElement m;
 
260
  m.name = name;
 
261
  m.widget = 0;
 
262
  m.lua_method = LUA_NOREF;
 
263
  m.flags = 0;
 
264
 
 
265
  switch (type) {
 
266
  case 0:
 
267
    addButton(L, m);
 
268
    break;
 
269
  case 1:
 
270
    addTextEdit(L, m);
 
271
    break;
 
272
  case 2:
 
273
    addList(L, m);
 
274
    break;
 
275
  case 3:
 
276
    addLabel(L, m);
 
277
    break;
 
278
  case 4:
 
279
    addCombo(L, m);
 
280
    break;
 
281
  case 5:
 
282
    addCheckbox(L, m);
 
283
    break;
 
284
  case 6:
 
285
    addInput(L, m);
 
286
    break;
 
287
  default:
 
288
    break;
 
289
  }
 
290
 
 
291
  QGridLayout *lo = gridlayout();
 
292
  lo->addWidget(m.widget, row, col, rowstretch, colstretch);
 
293
  iElements.push_back(m);
 
294
  return 0;
 
295
}
 
296
 
 
297
void Dialog::addButton(lua_State *L, SElement &m)
 
298
{
 
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);
 
303
  m.widget = b;
 
304
  lua_getfield(L, 4, "action");
 
305
  if (lua_isstring(L, -1)) {
 
306
    QString s = tostring(L, -1);
 
307
    if (s == "accept")
 
308
      connect(b, SIGNAL(clicked()), SLOT(accept()));
 
309
    else if (s == "reject")
 
310
      connect(b, SIGNAL(clicked()), SLOT(reject()));
 
311
    else
 
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
 
320
}
 
321
 
 
322
void Dialog::addTextEdit(lua_State *L, SElement &m)
 
323
{
 
324
  QTextEdit *t = new QTextEdit(this);
 
325
  t->setAcceptRichText(false);
 
326
  m.widget = t;
 
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") {
 
334
      m.flags |= ELogFile;
 
335
    } else if (s == "xml") {
 
336
      m.flags |= EXml;
 
337
      (void) new XmlHighlighter(t);
 
338
    } else if (s == "latex") {
 
339
      (void) new LatexHighlighter(t);
 
340
    } else
 
341
      luaL_argerror(L, 4, "unknown syntax");
 
342
  }
 
343
  lua_pop(L, 2); // syntax, read_only
 
344
}
 
345
 
 
346
static void setListItems(lua_State *L, int index, QListWidget *l = 0,
 
347
                         QComboBox *b = 0)
 
348
{
 
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
 
357
  }
 
358
}
 
359
 
 
360
void Dialog::addList(lua_State *L, SElement &m)
 
361
{
 
362
  QListWidget *l = new QListWidget(this);
 
363
  m.widget = l;
 
364
  setListItems(L, 4, l, 0);
 
365
}
 
366
 
 
367
void Dialog::addLabel(lua_State *L, SElement &m)
 
368
{
 
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);
 
373
  m.widget = l;
 
374
  lua_pop(L, 1); // label
 
375
}
 
376
 
 
377
void Dialog::addCombo(lua_State *L, SElement &m)
 
378
{
 
379
  QComboBox *b = new QComboBox(this);
 
380
  m.widget = b;
 
381
  setListItems(L, 4, 0, b);
 
382
}
 
383
 
 
384
void Dialog::addCheckbox(lua_State *L, SElement &m)
 
385
{
 
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);
 
390
  m.widget = b;
 
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()));
 
397
  }
 
398
  lua_pop(L, 2); // action, label
 
399
}
 
400
 
 
401
void Dialog::addInput(lua_State *L, SElement &m)
 
402
{
 
403
  QLineEdit *e = new QLineEdit(this);
 
404
  m.widget = e;
 
405
}
 
406
 
 
407
int Dialog::findElement(lua_State *L, int index)
 
408
{
 
409
  QString name = checkstring(L, index);
 
410
  for (uint i = 0; i < iElements.size(); ++i) {
 
411
    if (iElements[i].name == name)
 
412
      return i;
 
413
  }
 
414
  return luaL_argerror(L, index, "no such element in dialog");
 
415
}
 
416
 
 
417
static void markupLog(QTextEdit *t, const QString &text)
 
418
{
 
419
  QTextDocument *doc = new QTextDocument(t);
 
420
  doc->setPlainText(text);
 
421
  QTextCursor cursor(doc);
 
422
  int curPos = 0;
 
423
  int errNo = 0;
 
424
  for (;;) {
 
425
    int nextErr = text.indexOf(QLatin1String("\n!"), curPos);
 
426
    if (nextErr < 0)
 
427
      break;
 
428
 
 
429
    int lines = 0;
 
430
    while (curPos < nextErr + 1) {
 
431
      if (text[curPos++] == QLatin1Char('\n'))
 
432
        ++lines;
 
433
    }
 
434
    cursor.movePosition(QTextCursor::Down, QTextCursor::MoveAnchor, lines);
 
435
    int pos = cursor.position();
 
436
    cursor.movePosition(QTextCursor::Down);
 
437
    cursor.setPosition(pos, QTextCursor::KeepAnchor);
 
438
    ++errNo;
 
439
    QString s;
 
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);
 
446
  }
 
447
  t->setDocument(doc);
 
448
  t->scrollToAnchor(QLatin1String("err1"));
 
449
}
 
450
 
 
451
#if 0
 
452
static void xmlIndent(QString &text)
 
453
{
 
454
  QStringList l = text.split('\n');
 
455
 
 
456
  QRegExp begExp( "<(?!/).*>" );
 
457
  QRegExp endExp( "</.*>" );
 
458
  int tabLevel = 0;
 
459
 
 
460
  for (QStringList::Iterator it = l.begin(); it != l.end(); ++it) {
 
461
    if (it->contains(endExp))
 
462
      tabLevel--;
 
463
    for (int i = 0; i < tabLevel; i++)
 
464
      it->insert(0, "  ");
 
465
    if (it->contains(begExp))
 
466
      tabLevel++;
 
467
  }
 
468
  text = l.join("\n");
 
469
}
 
470
#endif
 
471
 
 
472
int Dialog::set(lua_State *L)
 
473
{
 
474
  int idx = findElement(L, 2);
 
475
 
 
476
  QLabel *l = qobject_cast<QLabel *>(iElements[idx].widget);
 
477
  if (l) {
 
478
    l->setText(checkstring(L, 3));
 
479
    return 0;
 
480
  }
 
481
  QTextEdit *t = qobject_cast<QTextEdit *>(iElements[idx].widget);
 
482
  if (t) {
 
483
    QString text = checkstring(L, 3);
 
484
    if (iElements[idx].flags & ELogFile) {
 
485
      markupLog(t, text);
 
486
    } else
 
487
      t->setPlainText(text);
 
488
    return 0;
 
489
  }
 
490
  QListWidget *list = qobject_cast<QListWidget *>(iElements[idx].widget);
 
491
  if (list) {
 
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);
 
497
    } else {
 
498
      luaL_checktype(L, 3, LUA_TTABLE);
 
499
      list->clear();
 
500
      setListItems(L, 3, list, 0);
 
501
    }
 
502
    return 0;
 
503
  }
 
504
 
 
505
  QComboBox *b = qobject_cast<QComboBox *>(iElements[idx].widget);
 
506
  if (b) {
 
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);
 
512
    } else {
 
513
      luaL_checktype(L, 3, LUA_TTABLE);
 
514
      b->clear();
 
515
      setListItems(L, 3, 0, b);
 
516
    }
 
517
    return 0;
 
518
  }
 
519
 
 
520
  QCheckBox *ch = qobject_cast<QCheckBox *>(iElements[idx].widget);
 
521
  if (ch) {
 
522
    bool value = lua_toboolean(L, 3);
 
523
    ch->setChecked(value);
 
524
    return 0;
 
525
  }
 
526
 
 
527
  QLineEdit *le = qobject_cast<QLineEdit *>(iElements[idx].widget);
 
528
  if (le) {
 
529
    QString text = checkstring(L, 3);
 
530
    le->setText(text);
 
531
    return 0;
 
532
  }
 
533
 
 
534
  return luaL_argerror(L, 2, "no suitable element");
 
535
}
 
536
 
 
537
int Dialog::get(lua_State *L)
 
538
{
 
539
  int idx = findElement(L, 2);
 
540
 
 
541
  QTextEdit *t = qobject_cast<QTextEdit *>(iElements[idx].widget);
 
542
  if (t) {
 
543
    QString s = t->toPlainText();
 
544
    push_string(L, s);
 
545
    return 1;
 
546
  }
 
547
 
 
548
  QListWidget *list = qobject_cast<QListWidget *>(iElements[idx].widget);
 
549
  if (list) {
 
550
    if (list->currentRow() >= 0)
 
551
      lua_pushnumber(L, list->currentRow() + 1);
 
552
    else
 
553
      lua_pushnil(L);
 
554
    return 1;
 
555
  }
 
556
 
 
557
  QComboBox *b = qobject_cast<QComboBox *>(iElements[idx].widget);
 
558
  if (b) {
 
559
    lua_pushnumber(L, b->currentIndex() + 1);
 
560
    return 1;
 
561
  }
 
562
 
 
563
  QCheckBox *ch = qobject_cast<QCheckBox *>(iElements[idx].widget);
 
564
  if (ch) {
 
565
    lua_pushboolean(L, ch->isChecked());
 
566
    return 1;
 
567
  }
 
568
 
 
569
  QLineEdit *le = qobject_cast<QLineEdit *>(iElements[idx].widget);
 
570
  if (le) {
 
571
    push_string(L, le->text());
 
572
    return 1;
 
573
  }
 
574
 
 
575
  return luaL_argerror(L, 2, "no suitable element");
 
576
}
 
577
 
 
578
int Dialog::execute(lua_State *L)
 
579
{
 
580
  // remember Lua object for dialog for callbacks
 
581
  lua_pushvalue(L, 1);
 
582
  iLuaDialog = luaL_ref(L, LUA_REGISTRYINDEX);
 
583
  int result = exec();
 
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;
 
588
  return result;
 
589
}
 
590
 
 
591
int Dialog::setEnabled(lua_State *L)
 
592
{
 
593
  int idx = findElement(L, 2);
 
594
  bool value = lua_toboolean(L, 3);
 
595
  iElements[idx].widget->setEnabled(value);
 
596
  return 0;
 
597
}
 
598
 
 
599
// --------------------------------------------------------------------
 
600
 
 
601
static int dialog_constructor(lua_State *L)
 
602
{
 
603
  QWidget *parent = check_parent(L, 1);
 
604
  QString s = checkstring(L, 2);
 
605
 
 
606
  Dialog **dlg = (Dialog **) lua_newuserdata(L, sizeof(Dialog *));
 
607
  *dlg = 0;
 
608
  luaL_getmetatable(L, "Ipe.dialog");
 
609
  lua_setmetatable(L, -2);
 
610
  *dlg = new Dialog(L, parent);
 
611
  (*dlg)->setWindowTitle(s);
 
612
  return 1;
 
613
}
 
614
 
 
615
static int dialog_tostring(lua_State *L)
 
616
{
 
617
  check_dialog(L, 1);
 
618
  lua_pushfstring(L, "Dialog@%p", lua_topointer(L, 1));
 
619
  return 1;
 
620
}
 
621
 
 
622
static int dialog_destructor(lua_State *L)
 
623
{
 
624
  // fprintf(stderr, "Dialog destructor\n");
 
625
  Dialog **dlg = check_dialog(L, 1);
 
626
  delete (*dlg);
 
627
  *dlg = 0;
 
628
  return 0;
 
629
}
 
630
 
 
631
static int dialog_execute(lua_State *L)
 
632
{
 
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);
 
644
  }
 
645
  lua_pushboolean(L, (*dlg)->execute(L));
 
646
  return 1;
 
647
}
 
648
 
 
649
static int dialog_setStretch(lua_State *L)
 
650
{
 
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);
 
656
 
 
657
  QGridLayout *lo = (*dlg)->gridlayout();
 
658
 
 
659
  if (type == 0)
 
660
    lo->setRowStretch(rowcol, stretch);
 
661
  else
 
662
    lo->setColumnStretch(rowcol, stretch);
 
663
  return 0;
 
664
}
 
665
 
 
666
static int dialog_add(lua_State *L)
 
667
{
 
668
  Dialog **dlg = check_dialog(L, 1);
 
669
  return (*dlg)->add(L);
 
670
}
 
671
 
 
672
static int dialog_set(lua_State *L)
 
673
{
 
674
  Dialog **dlg = check_dialog(L, 1);
 
675
  return (*dlg)->set(L);
 
676
}
 
677
 
 
678
static int dialog_get(lua_State *L)
 
679
{
 
680
  Dialog **dlg = check_dialog(L, 1);
 
681
  return (*dlg)->get(L);
 
682
}
 
683
 
 
684
static int dialog_setEnabled(lua_State *L)
 
685
{
 
686
  Dialog **dlg = check_dialog(L, 1);
 
687
  return (*dlg)->setEnabled(L);
 
688
}
 
689
 
 
690
// --------------------------------------------------------------------
 
691
 
 
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 },
 
701
  { 0, 0 }
 
702
};
 
703
 
 
704
// --------------------------------------------------------------------
 
705
 
 
706
MenuAction::MenuAction(const QString &name, int number,
 
707
                       const QString &item, const QString &text,
 
708
                       QWidget *parent)
 
709
  : QAction(text, parent)
 
710
{
 
711
  iName = name;
 
712
  iItemName = item;
 
713
  iNumber = number;
 
714
}
 
715
 
 
716
static int menu_constructor(lua_State *L)
 
717
{
 
718
  QMenu **m = (QMenu **) lua_newuserdata(L, sizeof(QMenu *));
 
719
  *m = 0;
 
720
  luaL_getmetatable(L, "Ipe.menu");
 
721
  lua_setmetatable(L, -2);
 
722
 
 
723
  *m = new QMenu();
 
724
  return 1;
 
725
}
 
726
 
 
727
static int menu_tostring(lua_State *L)
 
728
{
 
729
  check_menu(L, 1);
 
730
  lua_pushfstring(L, "Menu@%p", lua_topointer(L, 1));
 
731
  return 1;
 
732
}
 
733
 
 
734
static int menu_destructor(lua_State *L)
 
735
{
 
736
  QMenu **m = check_menu(L, 1);
 
737
  delete *m;
 
738
  *m = 0;
 
739
  return 0;
 
740
}
 
741
 
 
742
static int menu_execute(lua_State *L)
 
743
{
 
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);
 
749
  if (ma) {
 
750
    push_string(L, ma->name());
 
751
    lua_pushnumber(L, ma->number());
 
752
    push_string(L, ma->itemName());
 
753
    return 3;
 
754
  }
 
755
  return 0;
 
756
}
 
757
 
 
758
#define SIZE 16
 
759
 
 
760
static QIcon colorIcon(double red, double green, double blue)
 
761
{
 
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);
 
767
}
 
768
 
 
769
static int menu_add(lua_State *L)
 
770
{
 
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));
 
776
  } else {
 
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);
 
782
    if (hastable)
 
783
      luaL_argcheck(L, lua_istable(L, 5), 5,
 
784
                    "argument is not a function or table");
 
785
    QString current;
 
786
    if (hascheck) {
 
787
      luaL_argcheck(L, lua_isstring(L, 6), 6,
 
788
                    "argument is not a function or string");
 
789
      current = checkstring(L, 6);
 
790
    }
 
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);
 
797
      QString text = item;
 
798
      if (hastable) {
 
799
        lua_rawgeti(L, 5, i);
 
800
        luaL_argcheck(L, lua_isstring(L, -1), 5, "labels must be strings");
 
801
        text = tostring(L, -1);
 
802
        lua_pop(L, 1);
 
803
      }
 
804
      if (hasmap) {
 
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
 
813
      }
 
814
      MenuAction *ma = new MenuAction(name, i, item, text, sm);
 
815
      if (hascolor) {
 
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));
 
825
      }
 
826
      if (hascheck) {
 
827
        ma->setCheckable(true);
 
828
        ma->setChecked(item == current);
 
829
      }
 
830
      lua_pop(L, 1); // item
 
831
      sm->addAction(ma);
 
832
    }
 
833
    (*m)->addMenu(sm);
 
834
  }
 
835
  return 0;
 
836
}
 
837
 
 
838
// --------------------------------------------------------------------
 
839
 
 
840
static const struct luaL_Reg menu_methods[] = {
 
841
  { "__tostring", menu_tostring },
 
842
  { "__gc", menu_destructor },
 
843
  { "execute", menu_execute },
 
844
  { "add", menu_add },
 
845
  { 0, 0 }
 
846
};
 
847
 
 
848
// --------------------------------------------------------------------
 
849
 
 
850
static int ipeui_getString(lua_State *L)
 
851
{
 
852
  QWidget *parent = check_parent(L, 1);
 
853
  QString s = checkstring(L, 2);
 
854
  bool ok;
 
855
  QString str = QInputDialog::getText(parent, QString("Ipe"), s,
 
856
                                      QLineEdit::Normal,
 
857
                                      QString(),
 
858
                                      &ok);
 
859
  if (ok && !str.isEmpty()) {
 
860
    push_string(L, str);
 
861
    return 1;
 
862
  } else
 
863
    return 0;
 
864
}
 
865
 
 
866
static int ipeui_getDouble(lua_State *L)
 
867
{
 
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);
 
875
  bool ok;
 
876
  double d = QInputDialog::getDouble(parent, title, detail,
 
877
                                     value, minv, maxv, decimals, &ok);
 
878
  if (ok) {
 
879
    lua_pushnumber(L, d);
 
880
    return 1;
 
881
  } else
 
882
    return 0;
 
883
}
 
884
 
 
885
static int ipeui_getInt(lua_State *L)
 
886
{
 
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);
 
894
  bool ok;
 
895
#if QT_VERSION >= 0x040500
 
896
  int d = QInputDialog::getInt(parent, title, detail,
 
897
                               value, minv, maxv, step, &ok);
 
898
#else
 
899
  (void) step;
 
900
  int d = int(QInputDialog::getDouble(parent, title, detail,
 
901
                                      value, minv, maxv, 0, &ok));
 
902
#endif
 
903
  if (ok) {
 
904
    lua_pushnumber(L, d);
 
905
    return 1;
 
906
  } else
 
907
    return 0;
 
908
}
 
909
 
 
910
static int ipeui_getColor(lua_State *L)
 
911
{
 
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);
 
919
#else
 
920
  QColor changed = QColorDialog::getColor(initial, parent);
 
921
#endif
 
922
  if (changed.isValid()) {
 
923
    lua_pushnumber(L, changed.redF());
 
924
    lua_pushnumber(L, changed.greenF());
 
925
    lua_pushnumber(L, changed.blueF());
 
926
    return 3;
 
927
  } else
 
928
    return 0;
 
929
}
 
930
 
 
931
// --------------------------------------------------------------------
 
932
 
 
933
static int ipeui_fileDialog(lua_State *L)
 
934
{
 
935
  static const char * const typenames[] = { "open", "save", 0 };
 
936
 
 
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);
 
941
 
 
942
  QString dir;
 
943
  if (!lua_isnoneornil(L, 5))
 
944
    dir = checkstring(L, 5);
 
945
  QString selected;
 
946
  if (!lua_isnoneornil(L, 6))
 
947
    selected = checkstring(L, 6);
 
948
 
 
949
  QFileDialog dialog(parent);
 
950
  dialog.setWindowTitle(caption);
 
951
  dialog.setNameFilter(filter);
 
952
  dialog.setConfirmOverwrite(false);
 
953
 
 
954
  if (type == 0) {
 
955
    dialog.setFileMode(QFileDialog::ExistingFile);
 
956
    dialog.setAcceptMode(QFileDialog::AcceptOpen);
 
957
  } else {
 
958
    dialog.setFileMode(QFileDialog::AnyFile);
 
959
    dialog.setAcceptMode(QFileDialog::AcceptSave);
 
960
  }
 
961
 
 
962
  if (!selected.isNull())
 
963
    dialog.selectFilter(selected);
 
964
  if (!dir.isNull())
 
965
    dialog.setDirectory(dir);
 
966
 
 
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());
 
972
      return 2;
 
973
    }
 
974
  }
 
975
  return 0;
 
976
}
 
977
 
 
978
// --------------------------------------------------------------------
 
979
 
 
980
static int ipeui_messageBox(lua_State *L)
 
981
{
 
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 };
 
987
 
 
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);
 
994
  int buttons = 0;
 
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);
 
999
 
 
1000
  QMessageBox msgBox(parent);
 
1001
  msgBox.setText(text);
 
1002
  if (details)
 
1003
    msgBox.setInformativeText(QString::fromUtf8(details));
 
1004
 
 
1005
  switch (type) {
 
1006
  case 0:
 
1007
  default:
 
1008
    msgBox.setIcon(QMessageBox::NoIcon);
 
1009
    break;
 
1010
  case 1:
 
1011
    msgBox.setIcon(QMessageBox::Warning);
 
1012
    break;
 
1013
  case 2:
 
1014
    msgBox.setIcon(QMessageBox::Information);
 
1015
    break;
 
1016
  case 3:
 
1017
    msgBox.setIcon(QMessageBox::Question);
 
1018
    break;
 
1019
  case 4:
 
1020
    msgBox.setIcon(QMessageBox::Critical);
 
1021
    break;
 
1022
  }
 
1023
 
 
1024
  switch (buttons) {
 
1025
  case 0:
 
1026
  default:
 
1027
    msgBox.setStandardButtons(QMessageBox::Ok);
 
1028
    break;
 
1029
  case 1:
 
1030
    msgBox.setStandardButtons(QMessageBox::Ok|QMessageBox::Cancel);
 
1031
    break;
 
1032
  case 2:
 
1033
    msgBox.setStandardButtons(QMessageBox::Yes|QMessageBox::No|
 
1034
                              QMessageBox::Cancel);
 
1035
    break;
 
1036
  case 3:
 
1037
    msgBox.setStandardButtons(QMessageBox::Discard|QMessageBox::Cancel);
 
1038
    break;
 
1039
  case 4:
 
1040
    msgBox.setStandardButtons(QMessageBox::Save|QMessageBox::Discard|
 
1041
                              QMessageBox::Cancel);
 
1042
    break;
 
1043
  }
 
1044
 
 
1045
  int ret = msgBox.exec();
 
1046
 
 
1047
  switch (ret) {
 
1048
  case QMessageBox::Ok:
 
1049
  case QMessageBox::Yes:
 
1050
  case QMessageBox::Save:
 
1051
    lua_pushnumber(L, 1);
 
1052
    break;
 
1053
  case QMessageBox::No:
 
1054
  case QMessageBox::Discard:
 
1055
    lua_pushnumber(L, 0);
 
1056
    break;
 
1057
  case QMessageBox::Cancel:
 
1058
  default:
 
1059
    lua_pushnumber(L, -1);
 
1060
    break;
 
1061
  }
 
1062
  return 1;
 
1063
}
 
1064
 
 
1065
// --------------------------------------------------------------------
 
1066
 
 
1067
class EditorThread : public QThread
 
1068
{
 
1069
public:
 
1070
  EditorThread(const QString &cmd);
 
1071
 
 
1072
protected:
 
1073
  virtual void run();
 
1074
private:
 
1075
  QString iCommand;
 
1076
};
 
1077
 
 
1078
EditorThread::EditorThread(const QString &cmd) : QThread()
 
1079
{
 
1080
  iCommand = cmd;
 
1081
}
 
1082
 
 
1083
void EditorThread::run()
 
1084
{
 
1085
  int result = std::system(iCommand.toUtf8());
 
1086
  (void) result;
 
1087
}
 
1088
 
 
1089
class EditorDialog : public QDialog
 
1090
{
 
1091
public:
 
1092
  EditorDialog(QWidget *parent = 0);
 
1093
protected:
 
1094
  void closeEvent(QCloseEvent *ev);
 
1095
};
 
1096
 
 
1097
EditorDialog::EditorDialog(QWidget *parent)
 
1098
  : QDialog(parent)
 
1099
{
 
1100
  QGridLayout *lo = new QGridLayout;
 
1101
  setLayout(lo);
 
1102
  setWindowTitle("Ipe: waiting");
 
1103
  QLabel *l = new QLabel("Waiting for external editor", this);
 
1104
  lo->addWidget(l, 0, 0);
 
1105
}
 
1106
 
 
1107
void EditorDialog::closeEvent(QCloseEvent *ev)
 
1108
{
 
1109
  ev->ignore();
 
1110
}
 
1111
 
 
1112
static int ipeui_wait(lua_State *L)
 
1113
{
 
1114
  QString cmd = checkstring(L, 1);
 
1115
 
 
1116
  EditorDialog *dialog = new EditorDialog();
 
1117
 
 
1118
  EditorThread *thread = new EditorThread(cmd);
 
1119
  dialog->connect(thread, SIGNAL(finished()), SLOT(accept()));
 
1120
 
 
1121
  thread->start();
 
1122
  dialog->exec();
 
1123
  delete dialog;
 
1124
  delete thread;
 
1125
  return 0;
 
1126
}
 
1127
 
 
1128
// --------------------------------------------------------------------
 
1129
 
 
1130
Timer::Timer(lua_State *L0, int lua_object,
 
1131
             const QString &method)
 
1132
{
 
1133
  L = L0;
 
1134
  iLuaObject = lua_object;
 
1135
  iMethod = method;
 
1136
  iTimer = new QTimer();
 
1137
  connect(iTimer, SIGNAL(timeout()), SLOT(callLua()));
 
1138
}
 
1139
 
 
1140
Timer::~Timer()
 
1141
{
 
1142
  luaL_unref(L, LUA_REGISTRYINDEX, iLuaObject);
 
1143
  delete iTimer;
 
1144
}
 
1145
 
 
1146
void Timer::callLua()
 
1147
{
 
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
 
1152
    return;
 
1153
  }
 
1154
  lua_getfield(L, -1, iMethod.toUtf8());
 
1155
  if (lua_isnil(L, -1)) {
 
1156
    lua_pop(L, 3); // pop weak table, table, nil
 
1157
    return;
 
1158
  }
 
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
 
1162
}
 
1163
 
 
1164
int Timer::setSingleShot(lua_State *L)
 
1165
{
 
1166
  bool t = lua_toboolean(L, 2);
 
1167
  iTimer->setSingleShot(t);
 
1168
  return 0;
 
1169
}
 
1170
 
 
1171
int Timer::setInterval(lua_State *L)
 
1172
{
 
1173
  int t = luaL_checkint(L, 2);
 
1174
  iTimer->setInterval(t);
 
1175
  return 0;
 
1176
}
 
1177
 
 
1178
int Timer::active(lua_State *L)
 
1179
{
 
1180
  lua_pushboolean(L, iTimer->isActive());
 
1181
  return 1;
 
1182
}
 
1183
 
 
1184
int Timer::start(lua_State *L)
 
1185
{
 
1186
  iTimer->start();
 
1187
  return 0;
 
1188
}
 
1189
 
 
1190
int Timer::stop(lua_State *L)
 
1191
{
 
1192
  iTimer->stop();
 
1193
  return 0;
 
1194
}
 
1195
 
 
1196
// --------------------------------------------------------------------
 
1197
 
 
1198
static int timer_constructor(lua_State *L)
 
1199
{
 
1200
  luaL_argcheck(L, lua_istable(L, 1), 1, "argument is not a table");
 
1201
  QString method = luaL_checkstring(L, 2);
 
1202
 
 
1203
  Timer **t = (Timer **) lua_newuserdata(L, sizeof(Timer *));
 
1204
  *t = 0;
 
1205
  luaL_getmetatable(L, "Ipe.timer");
 
1206
  lua_setmetatable(L, -2);
 
1207
 
 
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);
 
1218
  return 1;
 
1219
}
 
1220
 
 
1221
static int timer_tostring(lua_State *L)
 
1222
{
 
1223
  check_timer(L, 1);
 
1224
  lua_pushfstring(L, "Timer@%p", lua_topointer(L, 1));
 
1225
  return 1;
 
1226
}
 
1227
 
 
1228
static int timer_destructor(lua_State *L)
 
1229
{
 
1230
  Timer **t = check_timer(L, 1);
 
1231
  // fprintf(stderr, "Timer destructor\n");
 
1232
  delete *t;
 
1233
  *t = 0;
 
1234
  return 0;
 
1235
}
 
1236
 
 
1237
// --------------------------------------------------------------------
 
1238
 
 
1239
static int timer_start(lua_State *L)
 
1240
{
 
1241
  Timer **t = check_timer(L, 1);
 
1242
  return (*t)->start(L);
 
1243
}
 
1244
 
 
1245
static int timer_stop(lua_State *L)
 
1246
{
 
1247
  Timer **t = check_timer(L, 1);
 
1248
  return (*t)->stop(L);
 
1249
}
 
1250
 
 
1251
static int timer_active(lua_State *L)
 
1252
{
 
1253
  Timer **t = check_timer(L, 1);
 
1254
  return (*t)->active(L);
 
1255
}
 
1256
 
 
1257
static int timer_setinterval(lua_State *L)
 
1258
{
 
1259
  Timer **t = check_timer(L, 1);
 
1260
  return (*t)->setInterval(L);
 
1261
}
 
1262
 
 
1263
static int timer_setsingleshot(lua_State *L)
 
1264
{
 
1265
  Timer **t = check_timer(L, 1);
 
1266
  return (*t)->setSingleShot(L);
 
1267
}
 
1268
 
 
1269
// --------------------------------------------------------------------
 
1270
 
 
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 },
 
1279
  { 0, 0 }
 
1280
};
 
1281
 
 
1282
// --------------------------------------------------------------------
 
1283
 
 
1284
static int ipeui_mainloop(lua_State *L)
 
1285
{
 
1286
  QApplication::exec();
 
1287
  return 0;
 
1288
}
 
1289
 
 
1290
static int ipeui_closeAllWindows(lua_State *L)
 
1291
{
 
1292
  QApplication::closeAllWindows();
 
1293
  return 0;
 
1294
}
 
1295
 
 
1296
static int ipeui_setClipboard(lua_State *L)
 
1297
{
 
1298
  QString data = checkstring(L, 1);
 
1299
  QClipboard *cb = QApplication::clipboard();
 
1300
  cb->setText(data);
 
1301
  return 0;
 
1302
}
 
1303
 
 
1304
static int ipeui_clipboard(lua_State *L)
 
1305
{
 
1306
  QClipboard *cb = QApplication::clipboard();
 
1307
  QString data = cb->text();
 
1308
  push_string(L, data);
 
1309
  return 1;
 
1310
}
 
1311
 
 
1312
static int ipeui_local8bit(lua_State *L)
 
1313
{
 
1314
  QString data = checkstring(L, 1);
 
1315
  QByteArray l8 = data.toLocal8Bit();
 
1316
  lua_pushstring(L, l8.data());
 
1317
  return 1;
 
1318
}
 
1319
 
 
1320
static int ipeui_currentDateTime(lua_State *L)
 
1321
{
 
1322
  QDateTime dt = QDateTime::currentDateTime();
 
1323
  QString mod;
 
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);
 
1328
  return 1;
 
1329
}
 
1330
 
 
1331
#if defined(WIN32)
 
1332
static int ipeui_startBrowser(lua_State *L)
 
1333
{
 
1334
  const char *url = luaL_checkstring(L, 1);
 
1335
  ShellExecuteA(0, "open", url, 0, 0, 0);
 
1336
  return 0;
 
1337
}
 
1338
#endif
 
1339
 
 
1340
// --------------------------------------------------------------------
 
1341
 
 
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 },
 
1359
#ifdef WIN32
 
1360
  { "startBrowser", ipeui_startBrowser },
 
1361
#endif
 
1362
  { 0, 0},
 
1363
};
 
1364
 
 
1365
// --------------------------------------------------------------------
 
1366
 
 
1367
static void make_metatable(lua_State *L, const char *name,
 
1368
                           const struct luaL_Reg *methods)
 
1369
{
 
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);
 
1375
  lua_pop(L, 1);
 
1376
}
 
1377
 
 
1378
int luaopen_ipeui(lua_State *L)
 
1379
{
 
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);
 
1384
  return 0;
 
1385
}
 
1386
 
 
1387
// --------------------------------------------------------------------