1 /*
2
3 Minimum Profit - A Text Editor
4 Qt4 (and Qt5) driver.
5
6 ttcdt <dev@triptico.com> et al.
7
8 This software is released into the public domain.
9 NO WARRANTY. See file LICENSE for details.
10
11 */
12
13 /* override auto-generated definition in config.h */
14 extern "C" int qt4_drv_detect(int *argc, char ***argv);
15 extern "C" int qt5_drv_detect(int *argc, char ***argv);
16
17 #include "config.h"
18
19 #include <stdio.h>
20 #include <wchar.h>
21 #include <unistd.h>
22
23 //#define MPDM_OLD_COMPAT
24
25 #include "mpdm.h"
26 #include "mpsl.h"
27 #include "mp.h"
28 #include "mp.xpm"
29
30 #ifdef CONFOPT_QT5
31 #include <QtWidgets>
32 #else
33 #include <QtGui>
34 #endif
35
36 /** data **/
37
38 #define MENU_CLASS QMenu
39 #define MENUBAR_CLASS QMenuBar
40
41 #include "mpv_qk_common.cpp"
42
43 class MPWindow : public QMainWindow
44 {
45 public:
46 MPWindow(QWidget * parent = 0);
47 ~MPWindow(void);
48 bool queryExit(void);
49 void closeEvent(QCloseEvent *event);
50 bool event(QEvent * event);
51 void save_settings(void);
52 MPArea *area;
53 };
54
55 QApplication *app;
56 MPWindow *window;
57
58
59 /** MPWindow methods **/
60
MPWindow(QWidget * parent)61 MPWindow::MPWindow(QWidget * parent) : QMainWindow(parent)
62 {
63 QVBoxLayout *vb;
64 QHBoxLayout *hb;
65
66 setWindowTitle("mp " VERSION);
67
68 // menubar = this->menuBar();
69 qk_build_menu(this->menuBar());
70
71 /* pick an optimal height for the menu & tabs */
72 // int height = menubar->sizeHint().height();
73
74 /* main area */
75 hb = new QHBoxLayout();
76 hb->setContentsMargins(0, 0, 0, 0);
77
78 area = new MPArea();
79
80 hb->addWidget(area);
81 hb->addWidget(area->scrollbar);
82 QWidget *cc = new QWidget();
83 cc->setLayout(hb);
84
85 /* the full container */
86 vb = new QVBoxLayout();
87 vb->setContentsMargins(0, 0, 0, 0);
88
89 vb->addWidget(area->file_tabs);
90 vb->addWidget(cc);
91
92 QWidget *mc = new QWidget();
93 mc->setLayout(vb);
94
95 this->statusBar()->addWidget(area->statusbar);
96
97 setCentralWidget(mc);
98
99 connect(area->scrollbar, SIGNAL(valueChanged(int)),
100 area, SLOT(from_scrollbar(int)));
101
102 connect(area->file_tabs, SIGNAL(currentChanged(int)),
103 area, SLOT(from_filetabs(int)));
104
105 connect(this->menuBar(), SIGNAL(triggered(QAction *)),
106 area, SLOT(from_menu(QAction *)));
107
108 this->setWindowIcon(QIcon(QPixmap(mp_xpm)));
109
110 mpdm_t v = mpdm_get_wcs(MP, L"state");
111 if ((v = mpdm_get_wcs(v, L"window")) == NULL) {
112 v = mpdm_set_wcs(mpdm_get_wcs(MP, L"state"), MPDM_O(), L"window");
113 mpdm_set_wcs(v, MPDM_I(20), L"x");
114 mpdm_set_wcs(v, MPDM_I(20), L"y");
115 mpdm_set_wcs(v, MPDM_I(600), L"w");
116 mpdm_set_wcs(v, MPDM_I(400), L"h");
117 }
118
119 move(QPoint(mpdm_ival(mpdm_get_wcs(v, L"x")), mpdm_ival(mpdm_get_wcs(v, L"y"))));
120 resize(QSize(mpdm_ival(mpdm_get_wcs(v, L"w")), mpdm_ival(mpdm_get_wcs(v, L"h"))));
121 }
122
123
~MPWindow(void)124 MPWindow::~MPWindow(void)
125 {
126 }
127
128
save_settings(void)129 void MPWindow::save_settings(void)
130 {
131 mpdm_t v;
132
133 v = mpdm_get_wcs(MP, L"state");
134 v = mpdm_set_wcs(v, MPDM_O(), L"window");
135 mpdm_set_wcs(v, MPDM_I(pos().x()), L"x");
136 mpdm_set_wcs(v, MPDM_I(pos().y()), L"y");
137 mpdm_set_wcs(v, MPDM_I(size().width()), L"w");
138 mpdm_set_wcs(v, MPDM_I(size().height()), L"h");
139 }
140
141
queryExit(void)142 bool MPWindow::queryExit(void)
143 {
144 mp_process_event(MPDM_S(L"close-window"));
145
146 return mp_exit_requested ? true : false;
147 }
148
149
closeEvent(QCloseEvent * event)150 void MPWindow::closeEvent(QCloseEvent *event)
151 {
152 mp_process_event(MPDM_S(L"close-window"));
153
154 if (!mp_exit_requested)
155 event->ignore();
156 }
157
158
159 static mpdm_t qt4_drv_shutdown(mpdm_t a, mpdm_t ctxt);
160
event(QEvent * event)161 bool MPWindow::event(QEvent *event)
162 {
163 /* do the processing */
164 bool r = QWidget::event(event);
165
166 if (mp_exit_requested) {
167 save_settings();
168 QApplication::exit(0);
169 }
170
171 return r;
172 }
173
174
175 /** driver functions **/
176
qt4_drv_alert(mpdm_t a,mpdm_t ctxt)177 static mpdm_t qt4_drv_alert(mpdm_t a, mpdm_t ctxt)
178 {
179 /* 1# arg: prompt */
180 QMessageBox::information(window, "mp " VERSION,
181 v_to_qstring(mpdm_get_i(a, 0)));
182
183 return NULL;
184 }
185
186
qt4_drv_confirm(mpdm_t a,mpdm_t ctxt)187 static mpdm_t qt4_drv_confirm(mpdm_t a, mpdm_t ctxt)
188 {
189 int r;
190
191 /* 1# arg: prompt */
192 r = QMessageBox::question(window, "mp" VERSION,
193 v_to_qstring(mpdm_get_i(a, 0)),
194 QMessageBox::Yes | QMessageBox::
195 No | QMessageBox::Cancel);
196
197 switch (r) {
198 case QMessageBox::Yes:
199 r = 1;
200 break;
201
202 case QMessageBox::No:
203 r = 2;
204 break;
205
206 case QMessageBox::Cancel:
207 r = 0;
208 break;
209 }
210
211 return MPDM_I(r);
212 }
213
214
qt4_drv_openfile(mpdm_t a,mpdm_t ctxt)215 static mpdm_t qt4_drv_openfile(mpdm_t a, mpdm_t ctxt)
216 {
217 QString r;
218 char tmp[128];
219
220 getcwd(tmp, sizeof(tmp));
221
222 /* 1# arg: prompt */
223 r = QFileDialog::getOpenFileName(window,
224 v_to_qstring(mpdm_get_i(a, 0)), tmp);
225
226 return qstring_to_v(r);
227 }
228
229
qt4_drv_savefile(mpdm_t a,mpdm_t ctxt)230 static mpdm_t qt4_drv_savefile(mpdm_t a, mpdm_t ctxt)
231 {
232 QString r;
233 char tmp[128];
234
235 getcwd(tmp, sizeof(tmp));
236
237 /* 1# arg: prompt */
238 r = QFileDialog::getSaveFileName(window,
239 v_to_qstring(mpdm_get_i(a, 0)), tmp);
240
241 return qstring_to_v(r);
242 }
243
244
qt4_drv_openfolder(mpdm_t a,mpdm_t ctxt)245 static mpdm_t qt4_drv_openfolder(mpdm_t a, mpdm_t ctxt)
246 {
247 QString r;
248 char tmp[128];
249
250 getcwd(tmp, sizeof(tmp));
251
252 /* 1# arg: prompt */
253 r = QFileDialog::getExistingDirectory(window,
254 v_to_qstring(mpdm_get_i(a, 0)),
255 tmp,
256 QFileDialog::ShowDirsOnly);
257
258 return qstring_to_v(r);
259 }
260
261
262 class MPForm : public QDialog
263 {
264 public:
265 QDialogButtonBox *button_box;
266
MPForm(QWidget * parent=0)267 MPForm(QWidget * parent = 0) : QDialog(parent)
268 {
269 button_box = new QDialogButtonBox(QDialogButtonBox::Ok |
270 QDialogButtonBox::Cancel);
271
272 connect(button_box, SIGNAL(accepted()), this, SLOT(accept()));
273 connect(button_box, SIGNAL(rejected()), this, SLOT(reject()));
274 }
275 };
276
277
qt4_drv_form(mpdm_t a,mpdm_t ctxt)278 static mpdm_t qt4_drv_form(mpdm_t a, mpdm_t ctxt)
279 {
280 int n;
281 mpdm_t widget_list;
282 QWidget *qlist[100];
283 mpdm_t r = NULL;
284
285 MPForm *dialog = new MPForm(window);
286 dialog->setWindowTitle("mp " VERSION);
287
288 dialog->setModal(true);
289
290 widget_list = mpdm_get_i(a, 0);
291
292 QWidget *form = new QWidget();
293 QFormLayout *fl = new QFormLayout();
294
295 for (n = 0; n < (int) mpdm_size(widget_list); n++) {
296 mpdm_t w = mpdm_get_i(widget_list, n);
297 wchar_t *type;
298 mpdm_t t;
299 QLabel *ql = new QLabel("");
300 QWidget *qw = NULL;
301
302 type = mpdm_string(mpdm_get_wcs(w, L"type"));
303
304 if ((t = mpdm_get_wcs(w, L"label")) != NULL) {
305 ql->setText(v_to_qstring(mpdm_gettext(t)));
306 }
307
308 t = mpdm_get_wcs(w, L"value");
309
310 if (wcscmp(type, L"text") == 0) {
311 mpdm_t h;
312 QComboBox *qc = new QComboBox();
313
314 qc->setEditable(true);
315 qc->setMinimumContentsLength(30);
316 qc->setMaxVisibleItems(8);
317
318 if (t != NULL)
319 qc->setEditText(v_to_qstring(t));
320
321 if ((h = mpdm_get_wcs(w, L"history")) != NULL) {
322 int i;
323
324 /* has history; fill it */
325 h = mp_get_history(h);
326
327 for (i = 0; i < (int) mpdm_size(h); i++)
328 qc->addItem(v_to_qstring(mpdm_get_i(h, i)));
329
330 qc->setCurrentIndex(mpdm_size(h) - 1);
331 }
332
333 /* select all the editable field */
334 qc->lineEdit()->selectAll();
335
336 qw = qc;
337 }
338 else
339 if (wcscmp(type, L"password") == 0) {
340 QLineEdit *qe = new QLineEdit();
341
342 qe->setEchoMode(QLineEdit::Password);
343
344 qw = qe;
345 }
346 else
347 if (wcscmp(type, L"checkbox") == 0) {
348 QCheckBox *qc = new QCheckBox();
349
350 if (mpdm_ival(t))
351 qc->setCheckState(Qt::Checked);
352
353 qw = qc;
354 }
355 else
356 if (wcscmp(type, L"list") == 0) {
357 int i;
358 QTableWidget *qtw = new QTableWidget();
359 qtw->setSelectionBehavior(QAbstractItemView::SelectRows);
360 qtw->setShowGrid(false);
361
362 qtw->setMinimumWidth(600);
363
364 /* if it's the only widget, make it tall */
365 if (mpdm_size(widget_list) == 1)
366 qtw->setMinimumHeight(400);
367
368 qtw->horizontalHeader()->hide();
369 qtw->horizontalHeader()->setStretchLastSection(true);
370 qtw->verticalHeader()->hide();
371
372 mpdm_t l = mpdm_get_wcs(w, L"list");
373
374 qtw->setColumnCount(2);
375 qtw->setRowCount(mpdm_size(l));
376
377 for (i = 0; i < (int) mpdm_size(l); i++) {
378 QTableWidgetItem *qtwi;
379 wchar_t *ptr1, *ptr2;
380
381 ptr1 = wcsdup(mpdm_string(mpdm_get_i(l, i)));
382 if ((ptr2 = wcschr(ptr1, L'\t'))) {
383 *ptr2 = L'\0';
384 ptr2++;
385 }
386 else
387 ptr2 = (wchar_t *)L"";
388
389 qtwi = new QTableWidgetItem(QString::fromWCharArray(ptr1));
390 qtw->setItem(i, 0, qtwi);
391
392 qtwi = new QTableWidgetItem(QString::fromWCharArray(ptr2));
393 qtwi->setTextAlignment(Qt::AlignRight);
394 qtw->setItem(i, 1, qtwi);
395
396 qtw->setRowHeight(i, 24);
397
398 free(ptr1);
399 }
400
401 qtw->selectRow(mpdm_ival(t));
402
403 qtw->resizeColumnsToContents();
404
405 qw = qtw;
406 }
407
408 qlist[n] = qw;
409
410 if (mpdm_size(widget_list) == 1) {
411 fl->addRow(ql);
412 fl->addRow(qw);
413 }
414 else
415 fl->addRow(ql, qw);
416
417 if (n == 0)
418 qlist[n]->setFocus(Qt::OtherFocusReason);
419 }
420
421 form->setLayout(fl);
422
423 QVBoxLayout *ml = new QVBoxLayout();
424 ml->addWidget(form);
425 ml->addWidget(dialog->button_box);
426
427 dialog->setLayout(ml);
428
429 if (dialog->exec()) {
430 r = MPDM_A(mpdm_size(widget_list));
431
432 /* fill the return values */
433 for (n = 0; n < (int) mpdm_size(widget_list); n++) {
434 mpdm_t w = mpdm_get_i(widget_list, n);
435 mpdm_t v = NULL;
436 wchar_t *type;
437
438 type = mpdm_string(mpdm_get_wcs(w, L"type"));
439
440 if (wcscmp(type, L"text") == 0) {
441 mpdm_t h;
442 QComboBox *ql = (QComboBox *) qlist[n];
443
444 v = mpdm_ref(qstring_to_v(ql->currentText()));
445
446 /* if it has history, add to it */
447 if (v && (h = mpdm_get_wcs(w, L"history")) && mpdm_cmp_wcs(v, L"")) {
448 h = mp_get_history(h);
449
450 if (mpdm_cmp(v, mpdm_get_i(h, -1)) != 0)
451 mpdm_push(h, v);
452 }
453
454 mpdm_unrefnd(v);
455 }
456 else
457 if (wcscmp(type, L"password") == 0) {
458 QLineEdit *ql = (QLineEdit *) qlist[n];
459
460 v = qstring_to_v(ql->text());
461 }
462 else
463 if (wcscmp(type, L"checkbox") == 0) {
464 QCheckBox *qb = (QCheckBox *) qlist[n];
465
466 v = MPDM_I(qb->checkState() == Qt::Checked);
467 }
468 else
469 if (wcscmp(type, L"list") == 0) {
470 QListWidget *ql = (QListWidget *) qlist[n];
471
472 v = MPDM_I(ql->currentRow());
473 }
474
475 mpdm_set_i(r, v, n);
476 }
477 }
478
479 return r;
480 }
481
482
qt4_drv_update_ui(mpdm_t a,mpdm_t ctxt)483 static mpdm_t qt4_drv_update_ui(mpdm_t a, mpdm_t ctxt)
484 {
485 window->area->font = qk_build_font();
486 qk_build_colors();
487 qk_build_menu(window->menuBar());
488
489 window->area->ls_width = -1;
490 window->area->ls_height = -1;
491 window->area->update();
492
493 return NULL;
494 }
495
496
qt4_drv_busy(mpdm_t a,mpdm_t ctxt)497 static mpdm_t qt4_drv_busy(mpdm_t a, mpdm_t ctxt)
498 {
499 int onoff = mpdm_ival(mpdm_get_i(a, 0));
500
501 window->setCursor(onoff ? Qt::WaitCursor : Qt::ArrowCursor);
502
503 return NULL;
504 }
505
506
qt4_drv_main_loop(mpdm_t a,mpdm_t ctxt)507 static mpdm_t qt4_drv_main_loop(mpdm_t a, mpdm_t ctxt)
508 {
509 app->exec();
510
511 return NULL;
512 }
513
514
qt4_drv_idle(mpdm_t a,mpdm_t ctxt)515 static mpdm_t qt4_drv_idle(mpdm_t a, mpdm_t ctxt)
516 {
517 int idle_msecs = (int) (mpdm_rval(mpdm_get_i(a, 0)) * 1000);
518
519 window->area->timer->stop();
520
521 if (idle_msecs)
522 window->area->timer->start(idle_msecs);
523
524 return NULL;
525 }
526
527
qt4_register_functions(void)528 static void qt4_register_functions(void)
529 {
530 mpdm_t drv;
531
532 drv = mpdm_get_wcs(mpdm_root(), L"mp_drv");
533 mpdm_set_wcs(drv, MPDM_X(qt4_drv_main_loop), L"main_loop");
534 mpdm_set_wcs(drv, MPDM_X(qt4_drv_shutdown), L"shutdown");
535 mpdm_set_wcs(drv, MPDM_X(qt4_drv_clip_to_sys), L"clip_to_sys");
536 mpdm_set_wcs(drv, MPDM_X(qt4_drv_sys_to_clip), L"sys_to_clip");
537 mpdm_set_wcs(drv, MPDM_X(qt4_drv_update_ui), L"update_ui");
538 mpdm_set_wcs(drv, MPDM_X(qt4_drv_idle), L"idle");
539 mpdm_set_wcs(drv, MPDM_X(qt4_drv_busy), L"busy");
540 mpdm_set_wcs(drv, MPDM_X(qt4_drv_alert), L"alert");
541 mpdm_set_wcs(drv, MPDM_X(qt4_drv_confirm), L"confirm");
542 mpdm_set_wcs(drv, MPDM_X(qt4_drv_openfile), L"openfile");
543 mpdm_set_wcs(drv, MPDM_X(qt4_drv_savefile), L"savefile");
544 mpdm_set_wcs(drv, MPDM_X(qt4_drv_form), L"form");
545 mpdm_set_wcs(drv, MPDM_X(qt4_drv_openfolder), L"openfolder");
546 }
547
548
qt4_drv_startup(mpdm_t a,mpdm_t ctxt)549 static mpdm_t qt4_drv_startup(mpdm_t a, mpdm_t ctxt)
550 /* driver initialization */
551 {
552 qt4_register_functions();
553
554 qk_build_colors();
555
556 window = new MPWindow();
557 window->show();
558
559 return NULL;
560 }
561
562
563 #ifdef CONFOPT_QT4
564 extern "C" Display *XOpenDisplay(char *);
565
qt4_drv_detect(int * argc,char *** argv)566 extern "C" int qt4_drv_detect(int *argc, char ***argv)
567 {
568 int n, ret = 1;
569
570 for (n = 0; n < *argc; n++) {
571 if (strcmp(argv[0][n], "-txt") == 0)
572 ret = 0;
573 }
574
575 if (ret) {
576 Display *x11_display;
577
578 /* try connecting directly to the Xserver */
579 if ((x11_display = XOpenDisplay((char *) NULL))) {
580 mpdm_t drv;
581
582 /* this is where it crashes if no X server */
583 app = new QApplication(x11_display);
584
585 drv = mpdm_set_wcs(mpdm_root(), MPDM_O(), L"mp_drv");
586 mpdm_set_wcs(drv, MPDM_S(L"qt4"), L"id");
587 mpdm_set_wcs(drv, MPDM_X(qt4_drv_startup), L"startup");
588 }
589 else
590 ret = 0;
591 }
592
593 return ret;
594 }
595
596 #endif
597
598
qt5_drv_detect(int * argc,char *** argv)599 extern "C" int qt5_drv_detect(int *argc, char ***argv)
600 {
601 int n, ret = 1;
602
603 for (n = 0; n < *argc; n++) {
604 if (strcmp(argv[0][n], "-txt") == 0)
605 ret = 0;
606 }
607
608 if (ret) {
609 char *display;
610
611 if ((display = getenv("DISPLAY")) && *display) {
612 mpdm_t drv;
613
614 /* _argc cannot disappear */
615 static int _argc = 0;
616 app = new QApplication(_argc, NULL);
617
618 drv = mpdm_set_wcs(mpdm_root(), MPDM_O(), L"mp_drv");
619 mpdm_set_wcs(drv, MPDM_S(L"qt5"), L"id");
620 mpdm_set_wcs(drv, MPDM_X(qt4_drv_startup), L"startup");
621 }
622 else
623 ret = 0;
624 }
625
626 return ret;
627 }
628
629