1 /*
2
3 Minimum Profit - A Text Editor
4 Win32 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 #include "config.h"
14
15 #ifdef CONFOPT_WIN32
16
17 #include <stdio.h>
18 #include <string.h>
19 #include <stdlib.h>
20 #include <wchar.h>
21
22 #include <windows.h>
23 #include <commctrl.h>
24 #include <shlobj.h>
25
26 #include "mpdm.h"
27 #include "mpsl.h"
28
29 #include "mp.h"
30
31 /** data **/
32
33 /* the instance */
34 HINSTANCE hinst;
35
36 /* the windows */
37 HWND hwnd = NULL;
38 HWND hwtabs = NULL;
39 HWND hwstatus = NULL;
40
41 /* font handlers and metrics */
42 HFONT font_normal = NULL;
43 HFONT font_underline = NULL;
44 int font_width = 0;
45 int font_height = 0;
46
47 /* height of the tab set */
48 int tab_height = 28;
49
50 /* height of the status bar */
51 int status_height = 16;
52
53 int is_wm_keydown = 0;
54
55 /* colors */
56 #define MAX_COLORS 100
57 static COLORREF inks[MAX_COLORS];
58 static COLORREF papers[MAX_COLORS];
59 int underlines[MAX_COLORS];
60 HBRUSH bgbrush;
61
62 /* code for the 'normal' attribute */
63 static int normal_attr = 0;
64
65 /* the menu */
66 static HMENU menu = NULL;
67
68 /* mp.drv.form() controls */
69
70 static mpdm_t form_args = NULL;
71 static mpdm_t form_values = NULL;
72
73 /* mouse down flag */
74 static int mouse_down = 0;
75
76 /** code **/
77
update_window_size(void)78 static void update_window_size(void)
79 /* updates the viewport size in characters */
80 {
81 RECT rect;
82 int tx, ty;
83 mpdm_t v;
84
85 if (font_width && font_height) {
86 GetClientRect(hwnd, &rect);
87
88 /* calculate the size in chars */
89 tx = ((rect.right - rect.left) / font_width) + 1;
90 ty = (rect.bottom - rect.top - tab_height) / font_height;
91
92 /* store the 'window' size */
93 v = mpdm_get_wcs(MP, L"window");
94 mpdm_set_wcs(v, MPDM_I(tx), L"tx");
95 mpdm_set_wcs(v, MPDM_I(ty), L"ty");
96 }
97 }
98
99
build_fonts(HDC hdc)100 static void build_fonts(HDC hdc)
101 /* build the fonts */
102 {
103 TEXTMETRIC tm;
104 int n;
105 mpdm_t v = NULL;
106 mpdm_t c;
107 int font_size = 10;
108 char *font_face = "Lucida Console";
109 double font_weight = 0.0;
110
111 if (font_normal != NULL) {
112 SelectObject(hdc, GetStockObject(SYSTEM_FONT));
113 DeleteObject(font_normal);
114 }
115
116 /* get current configuration */
117 if ((c = mpdm_get_wcs(MP, L"config")) != NULL) {
118 if ((v = mpdm_get_wcs(c, L"font_size")) != NULL)
119 font_size = mpdm_ival(v);
120 else
121 mpdm_set_wcs(c, MPDM_I(font_size), L"font_size");
122
123 if ((v = mpdm_get_wcs(c, L"font_weight")) != NULL)
124 font_weight = mpdm_rval(v) * 1000.0;
125 else
126 mpdm_set_wcs(c, MPDM_R(font_weight / 1000.0), L"font_weight");
127
128 if ((v = mpdm_get_wcs(c, L"font_face")) != NULL) {
129 v = mpdm_ref(MPDM_2MBS(v->data));
130 font_face = (char *) v->data;
131 }
132 else
133 mpdm_set_wcs(c, MPDM_MBS(font_face), L"font_face");
134 }
135
136 /* create fonts */
137 n = -MulDiv(font_size, GetDeviceCaps(hdc, LOGPIXELSY), 72);
138
139 if ((font_normal = CreateFont(n, 0, 0, 0, (int) font_weight, 0, 0,
140 0, 0, 0, 0, 0, 0, font_face)) == NULL)
141 font_normal = CreateFont(n, 0, 0, 0, 0, 0, 0,
142 0, 0, 0, 0, 0, 0, font_face);
143
144 if ((font_underline = CreateFont(n, 0, 0, 0, (int) font_weight, 0, 1,
145 0, 0, 0, 0, 0, 0, font_face)) == NULL)
146 font_underline = CreateFont(n, 0, 0, 0, 0, 0, 1,
147 0, 0, 0, 0, 0, 0, font_face);
148
149 SelectObject(hdc, font_normal);
150 GetTextMetrics(hdc, &tm);
151
152 /* store sizes */
153 font_height = tm.tmHeight;
154 font_width = tm.tmAveCharWidth;
155
156 update_window_size();
157
158 mpdm_unref(v);
159 }
160
161
build_colors(void)162 static void build_colors(void)
163 /* builds the colors */
164 {
165 mpdm_t colors;
166 mpdm_t v, i;
167 int n, c;
168
169 /* gets the color definitions and attribute names */
170 colors = mpdm_get_wcs(MP, L"colors");
171
172 /* loop the colors */
173 n = c = 0;
174 while (mpdm_iterator(colors, &c, &v, &i)) {
175 int m;
176 mpdm_t w = mpdm_get_wcs(v, L"gui");
177
178 /* store the 'normal' attribute */
179 if (wcscmp(mpdm_string(i), L"normal") == 0)
180 normal_attr = n;
181
182 /* store the attr */
183 mpdm_set_wcs(v, MPDM_I(n), L"attr");
184
185 m = mpdm_ival(mpdm_get_i(w, 0));
186 inks[n] = ((m & 0x000000ff) << 16) | ((m & 0x0000ff00)) | ((m & 0x00ff0000) >> 16);
187 m = mpdm_ival(mpdm_get_i(w, 1));
188 papers[n] = ((m & 0x000000ff) << 16) | ((m & 0x0000ff00)) | ((m & 0x00ff0000) >> 16);
189
190 /* flags */
191 w = mpdm_get_wcs(v, L"flags");
192
193 underlines[n] = mpdm_seek_wcs(w, L"underline", 1) != -1 ? 1 : 0;
194
195 if (mpdm_seek_wcs(w, L"reverse", 1) != -1) {
196 COLORREF t;
197
198 t = inks[n];
199 inks[n] = papers[n];
200 papers[n] = t;
201 }
202
203 n++;
204 }
205
206 /* create the background brush */
207 bgbrush = CreateSolidBrush(papers[normal_attr]);
208 }
209
210
build_menu(void)211 static void build_menu(void)
212 /* builds the menu */
213 {
214 int n;
215 mpdm_t m;
216 int win32_menu_id = 1000;
217
218 /* gets the current menu */
219 m = mpdm_get_wcs(MP, L"menu");
220
221 if (menu != NULL)
222 DestroyMenu(menu);
223
224 menu = CreateMenu();
225
226 for (n = 0; n < mpdm_size(m); n++) {
227 mpdm_t mi, v, l;
228 int i;
229 HMENU submenu = CreatePopupMenu();
230
231 /* get the label and the items */
232 mi = mpdm_get_i(m, n);
233 v = mpdm_gettext(mpdm_get_i(mi, 0));
234 l = mpdm_get_i(mi, 1);
235
236 /* create the submenus */
237 for (i = 0; i < mpdm_size(l); i++) {
238 /* get the action */
239 mpdm_t v = mpdm_get_i(l, i);
240
241 /* if the action is a separator... */
242 if (*((wchar_t *) v->data) == L'-')
243 AppendMenu(submenu, MF_SEPARATOR, 0, NULL);
244 else {
245 MENUITEMINFO mi;
246 mpdm_t d = mpdm_ref(mp_menu_label(v));
247
248 /* set the string */
249 AppendMenuW(submenu, MF_STRING, win32_menu_id, mpdm_string(d));
250
251 mpdm_unref(d);
252
253 /* store the action inside the menu */
254 memset(&mi, '\0', sizeof(mi));
255 mi.cbSize = sizeof(mi);
256 mi.fMask = MIIM_DATA;
257 mi.dwItemData = (unsigned long) v;
258
259 SetMenuItemInfo(submenu, win32_menu_id, FALSE, &mi);
260
261 win32_menu_id++;
262 }
263 }
264
265 /* now store the popup inside the menu */
266 AppendMenuW(menu, MF_STRING | MF_POPUP, (UINT) submenu, mpdm_string(v));
267 }
268
269 SetMenu(hwnd, menu);
270 }
271
272
draw_filetabs(void)273 static void draw_filetabs(void)
274 /* draws the filetabs */
275 {
276 static mpdm_t prev = NULL;
277 mpdm_t names;
278 int n;
279
280 names = mpdm_ref(mp_get_doc_names());
281
282 /* is the list different from the previous one? */
283 if (mpdm_cmp(names, prev) != 0) {
284 TabCtrl_DeleteAllItems(hwtabs);
285
286 for (n = 0; n < mpdm_size(names); n++) {
287 TCITEM ti;
288 char *ptr;
289 mpdm_t v = mpdm_get_i(names, n);
290
291 /* convert to mbs */
292 ptr = mpdm_wcstombs(v->data, NULL);
293
294 ti.mask = TCIF_TEXT;
295 ti.pszText = ptr;
296
297 /* create it */
298 TabCtrl_InsertItem(hwtabs, n, &ti);
299
300 free(ptr);
301 }
302
303 /* store for the next time */
304 mpdm_store(&prev, names);
305 }
306
307 mpdm_unref(names);
308
309 /* set the active one */
310 TabCtrl_SetCurSel(hwtabs, mpdm_ival(mpdm_get_wcs(MP, L"active_i")));
311 }
312
313
draw_scrollbar(void)314 static void draw_scrollbar(void)
315 /* updates the scrollbar */
316 {
317 mpdm_t d;
318 mpdm_t v;
319 int pos, size, max;
320 SCROLLINFO si;
321
322 d = mp_active();
323
324 /* get the coordinates */
325 v = mpdm_get_wcs(d, L"txt");
326 pos = mpdm_ival(mpdm_get_wcs(v, L"vy"));
327 max = mpdm_size(mpdm_get_wcs(v, L"lines"));
328
329 v = mpdm_get_wcs(MP, L"window");
330 size = mpdm_ival(mpdm_get_wcs(v, L"ty"));
331
332 si.cbSize = sizeof(si);
333 si.fMask = SIF_ALL;
334 si.nMin = 0;
335 si.nMax = max;
336 si.nPage = size;
337 si.nPos = pos;
338
339 SetScrollInfo(hwnd, SB_VERT, &si, TRUE);
340 }
341
342
draw_status(void)343 void draw_status(void)
344 /* draws the status line */
345 {
346 mpdm_t t;
347
348 if (hwstatus != NULL && (t = mpdm_ref(mp_build_status_line())) != NULL) {
349 mpdm_t v = mpdm_ref(MPDM_2MBS(t->data));
350
351 if (v->data != NULL)
352 SetWindowText(hwstatus, v->data);
353
354 mpdm_unref(v);
355 mpdm_unref(t);
356 }
357 }
358
359
win32_draw(HWND hwnd)360 static void win32_draw(HWND hwnd)
361 /* win32 document draw function */
362 {
363 HDC hdc;
364 PAINTSTRUCT ps;
365 RECT rect;
366 RECT r2;
367 mpdm_t d = NULL;
368 int n, m;
369
370 /* start painting */
371 hdc = BeginPaint(hwnd, &ps);
372
373 /* no font? construct it */
374 if (font_normal == NULL) {
375 build_fonts(hdc);
376 build_colors();
377 }
378
379 d = mp_draw(mp_active(), 0);
380
381 mpdm_ref(d);
382
383 /* select defaults to start painting */
384 SelectObject(hdc, font_normal);
385
386 GetClientRect(hwnd, &rect);
387 r2 = rect;
388
389 r2.top += tab_height;
390 r2.bottom = r2.top + font_height;
391
392 for (n = 0; n < mpdm_size(d); n++) {
393 mpdm_t l = mpdm_get_i(d, n);
394
395 r2.left = rect.left;
396
397 for (m = 0; m < mpdm_size(l); m++) {
398 int attr;
399 mpdm_t s;
400
401 /* get the attribute and the string */
402 attr = mpdm_ival(mpdm_get_i(l, m++));
403 s = mpdm_get_i(l, m);
404
405 SetTextColor(hdc, inks[attr]);
406 SetBkColor(hdc, papers[attr]);
407
408 SelectObject(hdc, underlines[attr] ?
409 font_underline : font_normal);
410
411 TextOutW(hdc, r2.left, r2.top, s->data, mpdm_size(s));
412 r2.left += mpdm_size(s) * font_width;
413 }
414
415 /* fills the rest of the line */
416 FillRect(hdc, &r2, bgbrush);
417
418 r2.top += font_height;
419 r2.bottom += font_height;
420 }
421
422 EndPaint(hwnd, &ps);
423
424 mpdm_unref(d);
425
426 draw_filetabs();
427 draw_scrollbar();
428 draw_status();
429 }
430
431
redraw(void)432 static void redraw(void)
433 {
434 InvalidateRect(hwnd, NULL, TRUE);
435 }
436
437
win32_vkey(int c)438 static void win32_vkey(int c)
439 /* win32 virtual key processing */
440 {
441 wchar_t *ptr = NULL;
442 static int maxed = 0;
443
444 /* set mp.shift_pressed */
445 if (GetKeyState(VK_SHIFT) & 0x8000)
446 mpdm_set_wcs(MP, MPDM_I(1), L"shift_pressed");
447
448 if (GetKeyState(VK_SHIFT) & 0x8000) {
449 switch (c) {
450 case VK_F1:
451 ptr = L"shift-f1";
452 break;
453 case VK_F2:
454 ptr = L"shift-f2";
455 break;
456 case VK_F3:
457 ptr = L"shift-f3";
458 break;
459 case VK_F4:
460 ptr = L"shift-f4";
461 break;
462 case VK_F5:
463 ptr = L"shift-f5";
464 break;
465 case VK_F6:
466 ptr = L"shift-f6";
467 break;
468 case VK_F7:
469 ptr = L"shift-f7";
470 break;
471 case VK_F8:
472 ptr = L"shift-f8";
473 break;
474 case VK_F9:
475 ptr = L"shift-f9";
476 break;
477 case VK_F10:
478 ptr = L"shift-f10";
479 break;
480 case VK_F11:
481 ptr = L"shift-f11";
482 break;
483 case VK_F12:
484 ptr = L"shift-f12";
485 break;
486 }
487 }
488
489 if (ptr == NULL && (GetKeyState(VK_CONTROL) & 0x8000)) {
490 switch (c) {
491 case VK_UP:
492 ptr = L"ctrl-cursor-up";
493 break;
494 case VK_DOWN:
495 ptr = L"ctrl-cursor-down";
496 break;
497 case VK_LEFT:
498 ptr = L"ctrl-cursor-left";
499 break;
500 case VK_RIGHT:
501 ptr = L"ctrl-cursor-right";
502 break;
503 case VK_PRIOR:
504 ptr = L"ctrl-page-up";
505 break;
506 case VK_NEXT:
507 ptr = L"ctrl-page-down";
508 break;
509 case VK_HOME:
510 ptr = L"ctrl-home";
511 break;
512 case VK_END:
513 ptr = L"ctrl-end";
514 break;
515 case VK_SPACE:
516 ptr = L"ctrl-space";
517 break;
518 case VK_DIVIDE:
519 ptr = L"ctrl-kp-divide";
520 break;
521 case VK_MULTIPLY:
522 ptr = L"ctrl-kp-multiply";
523 break;
524 case VK_SUBTRACT:
525 ptr = L"ctrl-kp-minus";
526 break;
527 case VK_ADD:
528 ptr = L"ctrl-kp-plus";
529 break;
530 case VK_RETURN:
531 ptr = L"ctrl-enter";
532 break;
533 case VK_F1:
534 ptr = L"ctrl-f1";
535 break;
536 case VK_F2:
537 ptr = L"ctrl-f2";
538 break;
539 case VK_F3:
540 ptr = L"ctrl-f3";
541 break;
542 case VK_F4:
543 ptr = L"ctrl-f4";
544 break;
545 case VK_F5:
546 ptr = L"ctrl-f5";
547 break;
548 case VK_F6:
549 ptr = L"ctrl-f6";
550 break;
551 case VK_F7:
552 ptr = L"ctrl-f7";
553 break;
554 case VK_F8:
555 ptr = L"ctrl-f8";
556 break;
557 case VK_F9:
558 ptr = L"ctrl-f9";
559 break;
560 case VK_F10:
561 ptr = L"ctrl-f10";
562 break;
563 case VK_F11:
564 ptr = L"ctrl-f11";
565 break;
566 case VK_F12:
567 SendMessage(hwnd, WM_SYSCOMMAND,
568 maxed ? SC_RESTORE : SC_MAXIMIZE, 0);
569
570 maxed ^= 1;
571
572 break;
573 }
574 }
575 else
576 if (ptr == NULL && (GetKeyState(VK_LMENU) & 0x8000)) {
577 switch (c) {
578 case VK_UP:
579 ptr = L"alt-cursor-up";
580 break;
581 case VK_DOWN:
582 ptr = L"alt-cursor-down";
583 break;
584 case VK_LEFT:
585 ptr = L"alt-cursor-left";
586 break;
587 case VK_RIGHT:
588 ptr = L"alt-cursor-right";
589 break;
590 case VK_PRIOR:
591 ptr = L"alt-page-up";
592 break;
593 case VK_NEXT:
594 ptr = L"alt-page-down";
595 break;
596 case VK_HOME:
597 ptr = L"alt-home";
598 break;
599 case VK_END:
600 ptr = L"alt-end";
601 break;
602 case VK_SPACE:
603 ptr = L"alt-space";
604 break;
605 case VK_DIVIDE:
606 ptr = L"alt-kp-divide";
607 break;
608 case VK_MULTIPLY:
609 ptr = L"alt-kp-multiply";
610 break;
611 case VK_SUBTRACT:
612 ptr = L"alt-kp-minus";
613 break;
614 case VK_ADD:
615 ptr = L"alt-kp-plus";
616 break;
617 case VK_RETURN:
618 ptr = L"alt-enter";
619 break;
620 case VK_F1:
621 ptr = L"alt-f1";
622 break;
623 case VK_F2:
624 ptr = L"alt-f2";
625 break;
626 case VK_F3:
627 ptr = L"alt-f3";
628 break;
629 case VK_F4:
630 ptr = L"alt-f4";
631 break;
632 case VK_F5:
633 ptr = L"alt-f5";
634 break;
635 case VK_F6:
636 ptr = L"alt-f6";
637 break;
638 case VK_F7:
639 ptr = L"alt-f7";
640 break;
641 case VK_F8:
642 ptr = L"alt-f8";
643 break;
644 case VK_F9:
645 ptr = L"alt-f9";
646 break;
647 case VK_F10:
648 ptr = L"alt-f10";
649 break;
650 case VK_F11:
651 ptr = L"alt-f11";
652 break;
653 case VK_F12:
654 ptr = L"alt-f12";
655 break;
656 case 0xbd: /* VK_OEM_MINUS */
657 ptr = L"alt-minus";
658 break;
659 }
660 }
661 else
662 if (ptr == NULL) {
663 switch (c) {
664 case VK_UP:
665 ptr = L"cursor-up";
666 break;
667 case VK_DOWN:
668 ptr = L"cursor-down";
669 break;
670 case VK_LEFT:
671 ptr = L"cursor-left";
672 break;
673 case VK_RIGHT:
674 ptr = L"cursor-right";
675 break;
676 case VK_PRIOR:
677 ptr = L"page-up";
678 break;
679 case VK_NEXT:
680 ptr = L"page-down";
681 break;
682 case VK_HOME:
683 ptr = L"home";
684 break;
685 case VK_END:
686 ptr = L"end";
687 break;
688 case VK_RETURN:
689 ptr = L"enter";
690 break;
691 case VK_BACK:
692 ptr = L"backspace";
693 break;
694 case VK_DELETE:
695 ptr = L"delete";
696 break;
697 case VK_INSERT:
698 ptr = L"insert";
699 break;
700 case VK_DIVIDE:
701 ptr = L"kp-divide";
702 break;
703 case VK_MULTIPLY:
704 ptr = L"kp-multiply";
705 break;
706 case VK_SUBTRACT:
707 ptr = L"kp-minus";
708 break;
709 case VK_ADD:
710 ptr = L"kp-plus";
711 break;
712 case VK_F1:
713 ptr = L"f1";
714 break;
715 case VK_F2:
716 ptr = L"f2";
717 break;
718 case VK_F3:
719 ptr = L"f3";
720 break;
721 case VK_F4:
722 ptr = L"f4";
723 break;
724 case VK_F5:
725 ptr = L"f5";
726 break;
727 case VK_F6:
728 ptr = L"f6";
729 break;
730 case VK_F7:
731 ptr = L"f7";
732 break;
733 case VK_F8:
734 ptr = L"f8";
735 break;
736 case VK_F9:
737 ptr = L"f9";
738 break;
739 case VK_F10:
740 ptr = L"f10";
741 break;
742 case VK_F11:
743 ptr = L"f11";
744 break;
745 case VK_F12:
746 ptr = L"f12";
747 break;
748 }
749 }
750
751 if (ptr != NULL) {
752 mp_process_event(MPDM_S(ptr));
753
754 is_wm_keydown = 1;
755 mp_active();
756
757 if (mp_keypress_throttle(1))
758 redraw();
759 }
760 }
761
762
763 #define ctrl(c) ((c) & 31)
764
win32_akey(int k)765 static void win32_akey(int k)
766 /* win32 alphanumeric key processing */
767 {
768 wchar_t c[2];
769 wchar_t *ptr = NULL;
770
771 /* set mp.shift_pressed */
772 if (GetKeyState(VK_SHIFT) & 0x8000)
773 mpdm_set_wcs(MP, MPDM_I(1), L"shift_pressed");
774
775 switch (k) {
776 case ctrl(' '):
777 ptr = L"ctrl-space";
778 break;
779 case ctrl('a'):
780 ptr = L"ctrl-a";
781 break;
782 case ctrl('b'):
783 ptr = L"ctrl-b";
784 break;
785 case ctrl('c'):
786 ptr = L"ctrl-c";
787 break;
788 case ctrl('d'):
789 ptr = L"ctrl-d";
790 break;
791 case ctrl('e'):
792 ptr = L"ctrl-e";
793 break;
794 case ctrl('f'):
795 ptr = L"ctrl-f";
796 break;
797 case ctrl('g'):
798 ptr = L"ctrl-g";
799 break;
800 case ctrl('h'): /* same as backspace */
801 break;
802 case ctrl('i'): /* same as tab */
803 ptr = (GetKeyState(VK_SHIFT) & 0x8000) ? L"shift-tab" : L"tab";
804 break;
805 case ctrl('j'):
806 ptr = L"ctrl-j";
807 break;
808 case ctrl('k'):
809 ptr = L"ctrl-k";
810 break;
811 case ctrl('l'):
812 ptr = L"ctrl-l";
813 break;
814 case ctrl('m'): /* same as ENTER */
815 break;
816 case ctrl('n'):
817 ptr = L"ctrl-n";
818 break;
819 case ctrl('o'):
820 ptr = L"ctrl-o";
821 break;
822 case ctrl('p'):
823 ptr = L"ctrl-p";
824 break;
825 case ctrl('q'):
826 ptr = L"ctrl-q";
827 break;
828 case ctrl('r'):
829 ptr = L"ctrl-r";
830 break;
831 case ctrl('s'):
832 ptr = L"ctrl-s";
833 break;
834 case ctrl('t'):
835 ptr = L"ctrl-t";
836 break;
837 case ctrl('u'):
838 ptr = L"ctrl-u";
839 break;
840 case ctrl('v'):
841 ptr = L"ctrl-v";
842 break;
843 case ctrl('w'):
844 ptr = L"ctrl-w";
845 break;
846 case ctrl('x'):
847 ptr = L"ctrl-x";
848 break;
849 case ctrl('y'):
850 ptr = L"ctrl-y";
851 break;
852 case ctrl('z'):
853 ptr = L"ctrl-z";
854 break;
855 case ' ':
856 ptr = L"space";
857 break;
858 case 27:
859 ptr = L"escape";
860 break;
861 case '-':
862 ptr = (GetKeyState(VK_LMENU) & 0x8000) ? L"alt-minus" : L"-";
863 break;
864
865 default:
866 /* this is probably very bad */
867 c[0] = (wchar_t) k;
868 c[1] = L'\0';
869 ptr = c;
870
871 break;
872 }
873
874 if (ptr != NULL) {
875 mp_process_event(MPDM_S(ptr));
876
877 mp_active();
878 redraw();
879 }
880 }
881
882
win32_vscroll(UINT wparam)883 static void win32_vscroll(UINT wparam)
884 /* scrollbar messages handler */
885 {
886 wchar_t *ptr = NULL;
887 mpdm_t txt;
888
889 switch (LOWORD(wparam)) {
890 case SB_PAGEUP:
891 ptr = L"page-up";
892 break;
893 case SB_PAGEDOWN:
894 ptr = L"page-down";
895 break;
896 case SB_LINEUP:
897 ptr = L"cursor-up";
898 break;
899 case SB_LINEDOWN:
900 ptr = L"cursor-down";
901 break;
902 case SB_THUMBPOSITION:
903 case SB_THUMBTRACK:
904 /* set both y and vy */
905 txt = mpdm_get_wcs(mp_active(), L"txt");
906 mp_set_y(mp_active(), HIWORD(wparam));
907 mpdm_set_wcs(txt, MPDM_I(HIWORD(wparam)), L"vy");
908 redraw();
909 break;
910 }
911
912 if (ptr != NULL) {
913 mp_process_event(MPDM_S(ptr));
914
915 redraw();
916 }
917 }
918
919
action_by_menu(int item)920 static void action_by_menu(int item)
921 /* execute an action triggered by the menu */
922 {
923 MENUITEMINFO mi;
924
925 memset(&mi, '\0', sizeof(mi));
926 mi.cbSize = sizeof(mi);
927 mi.fMask = MIIM_DATA;
928
929 if (GetMenuItemInfo(menu, item, FALSE, &mi)) {
930 if (mi.dwItemData != 0) {
931 mp_process_action((mpdm_t) mi.dwItemData);
932 mp_active();
933 }
934 }
935 }
936
937
dropped_files(HDROP hDrop)938 static void dropped_files(HDROP hDrop)
939 /* fill the mp.dropped_files array with the dropped files */
940 {
941 mpdm_t a = MPDM_A(0);
942 char tmp[1024];
943 int n;
944
945 mpdm_ref(a);
946
947 n = DragQueryFile(hDrop, 0xffffffff, NULL, sizeof(tmp) - 1);
948
949 while (--n >= 0) {
950 DragQueryFile(hDrop, n, tmp, sizeof(tmp) - 1);
951 mpdm_push(a, MPDM_MBS(tmp));
952 }
953
954 DragFinish(hDrop);
955
956 mpdm_set_wcs(MP, a, L"dropped_files");
957
958 mpdm_unref(a);
959
960 mp_process_event(MPDM_S(L"dropped-files"));
961
962 redraw();
963 }
964
965
966 #ifndef WM_MOUSEWHEEL
967 #define WM_MOUSEWHEEL 0x020A
968 #endif
969
WndProc(HWND hwnd,UINT msg,UINT wparam,LONG lparam)970 long CALLBACK WndProc(HWND hwnd, UINT msg, UINT wparam, LONG lparam)
971 /* main window Proc */
972 {
973 int x, y;
974 LPNMHDR p;
975 wchar_t *ptr = NULL;
976
977 switch (msg) {
978 case WM_CREATE:
979
980 is_wm_keydown = 0;
981 DragAcceptFiles(hwnd, TRUE);
982 return 0;
983
984 case WM_DROPFILES:
985
986 dropped_files((HDROP) wparam);
987 return 0;
988
989 case WM_SYSKEYUP:
990 case WM_KEYUP:
991
992 is_wm_keydown = 0;
993
994 if (mp_keypress_throttle(0))
995 redraw();
996
997 return 0;
998
999 case WM_SYSKEYDOWN:
1000 case WM_KEYDOWN:
1001
1002 win32_vkey(wparam);
1003 return 0;
1004
1005 case WM_CHAR:
1006
1007 win32_akey(wparam);
1008 return 0;
1009
1010 case WM_VSCROLL:
1011
1012 win32_vscroll(wparam);
1013 return 0;
1014
1015 case WM_PAINT:
1016
1017 if (mpdm_size(mpdm_get_wcs(MP, L"docs")))
1018 win32_draw(hwnd);
1019
1020 return 0;
1021
1022 case WM_SIZE:
1023
1024 if (!IsIconic(hwnd)) {
1025 update_window_size();
1026
1027 MoveWindow(hwtabs, 0, 0, LOWORD(lparam), tab_height, FALSE);
1028
1029 MoveWindow(hwstatus, 0, HIWORD(lparam) - status_height,
1030 LOWORD(lparam), status_height, FALSE);
1031
1032 redraw();
1033 }
1034
1035 return 0;
1036
1037 case WM_LBUTTONDOWN:
1038 case WM_LBUTTONDBLCLK:
1039
1040 mouse_down = 1;
1041 /* fallthrough */
1042
1043 case WM_RBUTTONDOWN:
1044 case WM_MBUTTONDOWN:
1045
1046 x = (LOWORD(lparam)) / font_width;
1047 y = (HIWORD(lparam) - tab_height) / font_height;
1048
1049 mpdm_set_wcs(MP, MPDM_I(x), L"mouse_x");
1050 mpdm_set_wcs(MP, MPDM_I(y), L"mouse_y");
1051
1052 switch (msg) {
1053 case WM_LBUTTONDOWN:
1054 ptr = L"mouse-left-button";
1055 break;
1056 case WM_RBUTTONDOWN:
1057 ptr = L"mouse-right-button";
1058 break;
1059 case WM_MBUTTONDOWN:
1060 ptr = L"mouse-middle-button";
1061 break;
1062 case WM_LBUTTONDBLCLK:
1063 ptr = L"mouse-left-dblclick";
1064 break;
1065 }
1066
1067 if (ptr != NULL) {
1068 mp_process_event(MPDM_S(ptr));
1069
1070 redraw();
1071 }
1072
1073 return 0;
1074
1075 case WM_LBUTTONUP:
1076
1077 mouse_down = 0;
1078 return 0;
1079
1080 case WM_MOUSEMOVE:
1081
1082 if (mouse_down) {
1083 x = (LOWORD(lparam)) / font_width;
1084 y = (HIWORD(lparam) - tab_height) / font_height;
1085
1086 mpdm_set_wcs(MP, MPDM_I(x), L"mouse_to_x");
1087 mpdm_set_wcs(MP, MPDM_I(y), L"mouse_to_y");
1088
1089 mp_process_event(MPDM_S(L"mouse-drag"));
1090
1091 redraw();
1092 }
1093
1094 return 0;
1095
1096 case WM_MOUSEWHEEL:
1097
1098 if ((int) wparam > 0)
1099 ptr = L"mouse-wheel-up";
1100 else
1101 ptr = L"mouse-wheel-down";
1102
1103 if (ptr != NULL) {
1104 mp_process_event(MPDM_S(ptr));
1105
1106 redraw();
1107 }
1108
1109 return 0;
1110
1111 case WM_COMMAND:
1112
1113 action_by_menu(LOWORD(wparam));
1114 redraw();
1115
1116 return 0;
1117
1118 case WM_CLOSE:
1119
1120 {
1121 RECT r;
1122 mpdm_t v;
1123
1124 GetWindowRect(hwnd, &r);
1125
1126 v = mpdm_get_wcs(MP, L"state");
1127 v = mpdm_set_wcs(v, MPDM_O(), L"window");
1128 mpdm_set_wcs(v, MPDM_I(r.left), L"x");
1129 mpdm_set_wcs(v, MPDM_I(r.top), L"y");
1130 mpdm_set_wcs(v, MPDM_I(r.right - r.left), L"w");
1131 mpdm_set_wcs(v, MPDM_I(r.bottom - r.top), L"h");
1132 }
1133
1134 if (!mp_exit_requested)
1135 mp_process_event(MPDM_S(L"close-window"));
1136
1137 if (mp_exit_requested)
1138 DestroyWindow(hwnd);
1139
1140 return 0;
1141
1142 case WM_DESTROY:
1143 PostQuitMessage(0);
1144 return 0;
1145
1146 case WM_NOTIFY:
1147 p = (LPNMHDR) lparam;
1148
1149 if (p->code == TCN_SELCHANGE) {
1150 /* tab selected by clicking on it */
1151 int n = TabCtrl_GetCurSel(hwtabs);
1152
1153 /* set mp.active_i to this */
1154 mpdm_set_wcs(MP, MPDM_I(n), L"active_i");
1155
1156 redraw();
1157 }
1158
1159 return 0;
1160
1161 case WM_TIMER:
1162 mp_process_event(MPDM_S(L"idle"));
1163 redraw();
1164
1165 return 0;
1166 }
1167
1168 if (mp_exit_requested)
1169 PostMessage(hwnd, WM_CLOSE, 0, 0);
1170
1171 return DefWindowProcW(hwnd, msg, wparam, lparam);
1172 }
1173
1174
win32_drv_clip_to_sys(mpdm_t a,mpdm_t ctxt)1175 static mpdm_t win32_drv_clip_to_sys(mpdm_t a, mpdm_t ctxt)
1176 /* driver-dependent mp to system clipboard */
1177 {
1178 HGLOBAL hclp;
1179 mpdm_t d, v;
1180 char *ptr;
1181 char *clpptr;
1182 int s;
1183
1184 /* convert the clipboard to DOS text */
1185 d = mpdm_get_wcs(MP, L"clipboard");
1186
1187 if (mpdm_size(d)) {
1188 v = mpdm_ref(mpdm_join_wcs(d, L"\r\n"));
1189 ptr = mpdm_wcstombs(v->data, &s);
1190
1191 /* allocates a handle and copies */
1192 hclp = GlobalAlloc(GHND, s + 1);
1193 clpptr = (char *) GlobalLock(hclp);
1194 memcpy(clpptr, ptr, s);
1195 clpptr[s] = '\0';
1196 GlobalUnlock(hclp);
1197
1198 free(ptr);
1199
1200 OpenClipboard(NULL);
1201 EmptyClipboard();
1202 SetClipboardData(CF_TEXT, hclp);
1203 CloseClipboard();
1204
1205 mpdm_unref(v);
1206 }
1207
1208 return NULL;
1209 }
1210
1211
win32_drv_sys_to_clip(mpdm_t a,mpdm_t ctxt)1212 static mpdm_t win32_drv_sys_to_clip(mpdm_t a, mpdm_t ctxt)
1213 /* driver-dependent system to mp clipboard */
1214 {
1215 HGLOBAL hclp;
1216 char *ptr;
1217
1218 OpenClipboard(NULL);
1219 hclp = GetClipboardData(CF_TEXT);
1220 CloseClipboard();
1221
1222 if (hclp && (ptr = GlobalLock(hclp)) != NULL) {
1223 mpdm_t d, v;
1224
1225 /* create a value and split */
1226 v = mpdm_ref(MPDM_MBS(ptr));
1227 d = mpdm_ref(mpdm_split_wcs(v, L"\r\n"));
1228
1229 /* and set as the clipboard */
1230 mpdm_set_wcs(MP, d, L"clipboard");
1231
1232 GlobalUnlock(hclp);
1233
1234 mpdm_unref(d);
1235 mpdm_unref(v);
1236 }
1237
1238 return NULL;
1239 }
1240
1241
win32_drv_main_loop(mpdm_t a,mpdm_t ctxt)1242 static mpdm_t win32_drv_main_loop(mpdm_t a, mpdm_t ctxt)
1243 {
1244 MSG msg;
1245
1246 if (!mp_exit_requested) {
1247 mp_active();
1248
1249 while (GetMessage(&msg, NULL, 0, 0)) {
1250 TranslateMessage(&msg);
1251 DispatchMessage(&msg);
1252 }
1253 }
1254
1255 return NULL;
1256 }
1257
1258
win32_drv_shutdown(mpdm_t a,mpdm_t ctxt)1259 static mpdm_t win32_drv_shutdown(mpdm_t a, mpdm_t ctxt)
1260 {
1261 mpdm_t v;
1262
1263 SendMessage(hwnd, WM_CLOSE, 0, 0);
1264
1265 if ((v = mpdm_get_wcs(MP, L"exit_message")) != NULL)
1266 MessageBoxW(NULL, mpdm_string(v), L"mp " VERSION, MB_ICONWARNING | MB_OK);
1267
1268 return NULL;
1269 }
1270
1271
win32_drv_alert(mpdm_t a,mpdm_t ctxt)1272 static mpdm_t win32_drv_alert(mpdm_t a, mpdm_t ctxt)
1273 /* alert driver function */
1274 {
1275 /* 1# arg: prompt */
1276 MessageBoxW(hwnd, mpdm_string(mpdm_get_i(a, 0)), L"mp " VERSION, MB_ICONWARNING | MB_OK);
1277
1278 return NULL;
1279 }
1280
1281
win32_drv_confirm(mpdm_t a,mpdm_t ctxt)1282 static mpdm_t win32_drv_confirm(mpdm_t a, mpdm_t ctxt)
1283 /* confirm driver function */
1284 {
1285 int ret = 0;
1286
1287 /* 1# arg: prompt */
1288 ret = MessageBoxW(hwnd, mpdm_string(mpdm_get_i(a, 0)), L"mp " VERSION,
1289 MB_ICONQUESTION | MB_YESNOCANCEL);
1290
1291 if (ret == IDYES)
1292 ret = 1;
1293 else
1294 if (ret == IDNO)
1295 ret = 2;
1296 else
1297 ret = 0;
1298
1299 return MPDM_I(ret);
1300 }
1301
1302
lpwAlign(LPWORD lpIn)1303 static LPWORD lpwAlign(LPWORD lpIn)
1304 /* aligns a pointer to DWORD boundary (for dialog templates) */
1305 {
1306 ULONG ul;
1307
1308 ul = (ULONG) lpIn;
1309 ul++;
1310 ul >>= 1;
1311 ul <<= 1;
1312 return (LPWORD) ul;
1313 }
1314
1315
1316 #define LABEL_ID 1000
1317 #define CTRL_ID 2000
1318
formDlgProc(HWND hwnd,UINT msg,WPARAM wparam,LPARAM lparam)1319 BOOL CALLBACK formDlgProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
1320 /* mp.drv.form() dialog proc */
1321 {
1322 int n;
1323 HFONT hf;
1324
1325 switch (msg) {
1326 case WM_INITDIALOG:
1327
1328 SetWindowText(hwnd, "mp " VERSION);
1329
1330 hf = GetStockObject(DEFAULT_GUI_FONT);
1331
1332 /* fill controls with its initial data */
1333 for (n = 0; n < mpdm_size(form_args); n++) {
1334 mpdm_t w = mpdm_get_i(form_args, n);
1335 wchar_t *type;
1336 mpdm_t t;
1337 int ctrl = CTRL_ID + n;
1338 wchar_t *wptr;
1339 char *ptr;
1340
1341 if ((t = mpdm_get_wcs(w, L"label")) != NULL) {
1342 SetDlgItemTextW(hwnd, LABEL_ID + n, mpdm_string(t));
1343
1344 SendDlgItemMessage(hwnd, LABEL_ID + n, WM_SETFONT,
1345 (WPARAM) hf, MAKELPARAM(FALSE, 0));
1346 }
1347
1348 SendDlgItemMessage(hwnd, ctrl, WM_SETFONT,
1349 (WPARAM) hf, MAKELPARAM(FALSE, 0));
1350
1351 type = mpdm_string(mpdm_get_wcs(w, L"type"));
1352
1353 if (wcscmp(type, L"text") == 0) {
1354 if ((t = mpdm_get_wcs(w, L"value")) != NULL) {
1355 SetDlgItemTextW(hwnd, ctrl, mpdm_string(t));
1356 }
1357
1358 /* store the history into combo_items */
1359 if ((t = mpdm_get_wcs(w, L"history")) != NULL) {
1360 t = mp_get_history(t);
1361 int i;
1362
1363 for (i = 0; i < mpdm_size(t); i++) {
1364 mpdm_t v = mpdm_get_i(t, i);
1365
1366 if ((ptr = mpdm_wcstombs(v->data, NULL)) != NULL) {
1367 SendDlgItemMessage(hwnd,
1368 ctrl,
1369 CB_INSERTSTRING, 0,
1370 (LPARAM) ptr);
1371 free(ptr);
1372 }
1373 }
1374 }
1375 }
1376 else
1377 if (wcscmp(type, L"password") == 0) {
1378 SendDlgItemMessage(hwnd, ctrl,
1379 EM_SETPASSWORDCHAR, (WPARAM) '*',
1380 (LPARAM) 0);
1381 }
1382 else
1383 if (wcscmp(type, L"checkbox") == 0) {
1384 if ((t = mpdm_get_wcs(w, L"value")) != NULL)
1385 SendDlgItemMessage(hwnd, ctrl,
1386 BM_SETCHECK, mpdm_ival(t) ?
1387 BST_CHECKED : BST_UNCHECKED, 0);
1388 }
1389 else
1390 if (wcscmp(type, L"list") == 0) {
1391 int i;
1392 int ts[] = { 250, 20 };
1393
1394 t = mpdm_get_wcs(w, L"list");
1395
1396 /* fill the list */
1397 for (i = 0; i < mpdm_size(t); i++) {
1398 wptr = mpdm_string(mpdm_get_i(t, i));
1399 if ((ptr = mpdm_wcstombs(wptr, NULL)) != NULL) {
1400 SendDlgItemMessage(hwnd, ctrl,
1401 LB_ADDSTRING, 0, (LPARAM) ptr);
1402 free(ptr);
1403 }
1404 }
1405
1406 SendDlgItemMessage(hwnd, ctrl, LB_SETTABSTOPS, 2, (LPARAM) ts);
1407
1408 /* set position */
1409 SendDlgItemMessage(hwnd, ctrl, LB_SETCURSEL,
1410 mpdm_ival(mpdm_get_wcs(w, L"value")), 0);
1411 }
1412 }
1413
1414 /* FIXME: untranslated strings */
1415
1416 SetDlgItemText(hwnd, IDOK, "OK");
1417 SendDlgItemMessage(hwnd, IDOK, WM_SETFONT,
1418 (WPARAM) hf, MAKELPARAM(FALSE, 0));
1419
1420 SetDlgItemText(hwnd, IDCANCEL, "Cancel");
1421 SendDlgItemMessage(hwnd, IDCANCEL, WM_SETFONT,
1422 (WPARAM) hf, MAKELPARAM(FALSE, 0));
1423
1424 return TRUE;
1425
1426 case WM_COMMAND:
1427
1428 if (LOWORD(wparam) == IDCANCEL) {
1429 EndDialog(hwnd, 0);
1430 return TRUE;
1431 }
1432
1433 if (LOWORD(wparam) != IDOK)
1434 break;
1435
1436 /* fill all return values */
1437 for (n = 0; n < mpdm_size(form_args); n++) {
1438 mpdm_t w = mpdm_get_i(form_args, n);
1439 wchar_t *type = mpdm_string(mpdm_get_wcs(w, L"type"));
1440 int ctrl = CTRL_ID + n;
1441
1442 if (wcscmp(type, L"text") == 0) {
1443 char tmp[2048];
1444 mpdm_t v;
1445 mpdm_t h;
1446
1447 GetDlgItemText(hwnd, ctrl, tmp, sizeof(tmp) - 1);
1448 v = MPDM_MBS(tmp);
1449
1450 mpdm_set_i(form_values, v, n);
1451
1452 /* if it has history, fill it */
1453 if (v && (h = mpdm_get_wcs(w, L"history")) && mpdm_cmp_wcs(v, L"")) {
1454 h = mp_get_history(h);
1455
1456 if (mpdm_cmp(v, mpdm_get_i(h, -1)) != 0)
1457 mpdm_push(h, v);
1458 }
1459 }
1460 if (wcscmp(type, L"password") == 0) {
1461 char tmp[2048];
1462
1463 GetDlgItemText(hwnd, ctrl, tmp, sizeof(tmp) - 1);
1464 mpdm_set_i(form_values, MPDM_MBS(tmp), n);
1465 }
1466 else
1467 if (wcscmp(type, L"checkbox") == 0) {
1468 mpdm_set_i(form_values,
1469 MPDM_I(SendDlgItemMessage(hwnd, ctrl,
1470 BM_GETCHECK, 0, 0)),
1471 n);
1472 }
1473 else
1474 if (wcscmp(type, L"list") == 0) {
1475 mpdm_set_i(form_values,
1476 MPDM_I(SendDlgItemMessage(hwnd, ctrl,
1477 LB_GETCURSEL, 0, 0)),
1478 n);
1479 }
1480 }
1481
1482 EndDialog(hwnd, 1);
1483 return TRUE;
1484 }
1485
1486 return FALSE;
1487 }
1488
1489
build_form_data(mpdm_t widget_list)1490 static void build_form_data(mpdm_t widget_list)
1491 /* builds the necessary information for a list of widgets */
1492 {
1493 mpdm_unref(form_args);
1494 form_args = mpdm_ref(widget_list);
1495
1496 mpdm_unref(form_values);
1497 form_values = widget_list == NULL ? NULL :
1498 mpdm_ref(MPDM_A(mpdm_size(form_args)));
1499 }
1500
1501
build_control(LPWORD lpw,int x,int y,int cx,int cy,int id,int w_class,int style)1502 LPWORD static build_control(LPWORD lpw, int x, int y,
1503 int cx, int cy, int id, int w_class, int style)
1504 /* fills a control structure in a hand-made dialog template */
1505 {
1506 LPDLGITEMTEMPLATE lpdit;
1507
1508 lpw = lpwAlign(lpw);
1509 lpdit = (LPDLGITEMTEMPLATE) lpw;
1510 lpdit->x = x;
1511 lpdit->y = y;
1512 lpdit->cx = cx;
1513 lpdit->cy = cy;
1514 lpdit->id = id;
1515 lpdit->style = style;
1516
1517 lpw = (LPWORD) (lpdit + 1);
1518 *lpw++ = 0xFFFF;
1519 *lpw++ = w_class;
1520
1521 /* no text (will be set on dialog setup) */
1522 *lpw++ = 0;
1523 *lpw++ = 0;
1524
1525 /* Align creation data on DWORD boundary */
1526 lpw = lpwAlign(lpw);
1527 /* No creation data */
1528 *lpw++ = 0;
1529
1530 return lpw;
1531 }
1532
1533
win32_drv_form(mpdm_t a,mpdm_t ctxt)1534 static mpdm_t win32_drv_form(mpdm_t a, mpdm_t ctxt)
1535 /* mp.drv.form() function */
1536 {
1537 HGLOBAL hgbl;
1538 LPDLGTEMPLATE lpdt;
1539 LPWORD lpw;
1540 int n, y;
1541 int line_height = 12;
1542 int label_width = 0;
1543 int dialog_width = 260;
1544 int button_width = 40;
1545 int spacing = 5;
1546
1547 /* first argument: list of widgets */
1548 build_form_data(mpdm_get_i(a, 0));
1549
1550 /* On-the-fly dialog template creation */
1551 /* Note: all this crap is taken from MSDN, no less */
1552
1553 /* magic size; looking for problems */
1554 hgbl = GlobalAlloc(GMEM_ZEROINIT, 4096);
1555 lpdt = (LPDLGTEMPLATE) GlobalLock(hgbl);
1556
1557 lpdt->style = WS_POPUP | WS_BORDER | WS_SYSMENU | DS_MODALFRAME | WS_CAPTION;
1558 lpdt->cdit = (2 * mpdm_size(form_args)) + 2;
1559 lpdt->x = 20;
1560 lpdt->y = 20;
1561 lpdt->cx = dialog_width;
1562
1563 lpw = (LPWORD) (lpdt + 1);
1564 *lpw++ = 0; /* No menu */
1565 *lpw++ = 0; /* Predefined dialog box class (by default) */
1566 *lpw++ = 0; /* No title */
1567
1568 /* first pass: calculate maximum size of labels */
1569 for (n = 0; n < mpdm_size(form_args); n++) {
1570 mpdm_t w = mpdm_get_i(form_args, n);
1571 int l = mpdm_size(mpdm_get_wcs(w, L"label"));
1572
1573 if (label_width < l)
1574 label_width = l;
1575 }
1576
1577 y = line_height / 2;
1578 label_width *= 3;
1579
1580 /* second pass: create the dialog controls */
1581 for (n = 0; n < mpdm_size(form_args); n++) {
1582 mpdm_t w = mpdm_get_i(form_args, n);
1583 wchar_t *type;
1584 int w_class;
1585 int style;
1586 int inc = 1;
1587 int sz = 1;
1588
1589 type = mpdm_string(mpdm_get_wcs(w, L"type"));
1590
1591 if (wcscmp(type, L"text") == 0) {
1592 w_class = 0x0085;
1593 style = WS_CHILD | WS_VISIBLE | WS_TABSTOP |
1594 CBS_DROPDOWN | CBS_AUTOHSCROLL | WS_VSCROLL;
1595
1596 /* size */
1597 sz = 5;
1598 }
1599 else
1600 if (wcscmp(type, L"password") == 0) {
1601 w_class = 0x0081;
1602 style = WS_CHILD | WS_VISIBLE | WS_BORDER | WS_TABSTOP;
1603 }
1604 else
1605 if (wcscmp(type, L"checkbox") == 0) {
1606 w_class = 0x0080;
1607 style = WS_CHILD | WS_VISIBLE | BS_AUTOCHECKBOX | WS_TABSTOP;
1608 }
1609 else
1610 if (wcscmp(type, L"list") == 0) {
1611 w_class = 0x0083;
1612 style = WS_CHILD | WS_VISIBLE | WS_TABSTOP | WS_BORDER |
1613 LBS_NOINTEGRALHEIGHT | WS_VSCROLL |
1614 LBS_NOTIFY | LBS_USETABSTOPS;
1615
1616 /* height */
1617 inc = 14;
1618 }
1619
1620 if (mpdm_size(form_args) == 1) {
1621 /* label control */
1622 lpw = build_control(lpw, spacing, y,
1623 dialog_width - spacing * 2,
1624 line_height,
1625 LABEL_ID + n, 0x0082,
1626 WS_CHILD | WS_VISIBLE | SS_LEFT);
1627
1628 /* the control */
1629 lpw = build_control(lpw, spacing, y + line_height,
1630 dialog_width - spacing * 2,
1631 inc * line_height * sz,
1632 CTRL_ID + n, w_class,
1633 style);
1634
1635 inc++;
1636 }
1637 else {
1638 /* label control */
1639 lpw = build_control(lpw, spacing, y,
1640 label_width,
1641 line_height,
1642 LABEL_ID + n, 0x0082,
1643 WS_CHILD | WS_VISIBLE | SS_LEFT);
1644
1645 /* the control */
1646 lpw = build_control(lpw, spacing + label_width, y,
1647 dialog_width - label_width - spacing * 2,
1648 inc * line_height * sz,
1649 CTRL_ID + n, w_class,
1650 style);
1651 }
1652
1653 /* next position */
1654 y += inc * line_height;
1655 }
1656
1657 /* set total height */
1658 lpdt->cy = line_height * 2 + y;
1659
1660 y += line_height / 2;
1661
1662 /* OK */
1663 lpw = build_control(lpw, dialog_width - button_width * 2 - spacing * 2, y,
1664 button_width, line_height,
1665 IDOK, 0x0080,
1666 WS_CHILD | WS_VISIBLE | BS_DEFPUSHBUTTON | WS_TABSTOP);
1667
1668 /* Cancel */
1669 lpw = build_control(lpw, dialog_width - button_width - spacing, y,
1670 button_width, line_height,
1671 IDCANCEL, 0x0080,
1672 WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON | WS_TABSTOP);
1673
1674 GlobalUnlock(hgbl);
1675 n = DialogBoxIndirect(hinst, (LPDLGTEMPLATE) hgbl,
1676 hwnd, (DLGPROC) formDlgProc);
1677
1678 GlobalFree(hgbl);
1679
1680 return n ? form_values : NULL;
1681 }
1682
1683
open_or_save(int o,mpdm_t a)1684 static mpdm_t open_or_save(int o, mpdm_t a)
1685 /* manages an open or save file dialog */
1686 {
1687 OPENFILENAME ofn;
1688 wchar_t *wptr;
1689 char *ptr;
1690 char buf[1024] = "";
1691 char buf2[1024];
1692 int r;
1693
1694 /* 1# arg: prompt */
1695 wptr = mpdm_string(mpdm_get_i(a, 0));
1696 ptr = mpdm_wcstombs(wptr, NULL);
1697
1698 memset(&ofn, '\0', sizeof(OPENFILENAME));
1699 ofn.lStructSize = sizeof(OPENFILENAME);
1700 ofn.hwndOwner = hwnd;
1701 ofn.lpstrFilter = "*.*\0*.*\0";
1702 ofn.nFilterIndex = 1;
1703 ofn.lpstrFile = buf;
1704 ofn.nMaxFile = sizeof(buf);
1705 ofn.lpstrTitle = ptr;
1706 ofn.lpstrDefExt = "";
1707
1708 GetCurrentDirectory(sizeof(buf2), buf2);
1709 ofn.lpstrInitialDir = buf2;
1710
1711 if (o) {
1712 ofn.Flags = OFN_PATHMUSTEXIST | OFN_HIDEREADONLY |
1713 OFN_NOCHANGEDIR | OFN_FILEMUSTEXIST;
1714
1715 r = GetOpenFileName(&ofn);
1716 }
1717 else {
1718 ofn.Flags = OFN_HIDEREADONLY;
1719
1720 r = GetSaveFileName(&ofn);
1721 }
1722
1723 free(ptr);
1724
1725 return r ? MPDM_MBS(buf) : NULL;
1726 }
1727
1728
win32_drv_openfile(mpdm_t a,mpdm_t ctxt)1729 static mpdm_t win32_drv_openfile(mpdm_t a, mpdm_t ctxt)
1730 /* openfile driver function */
1731 {
1732 return open_or_save(1, a);
1733 }
1734
1735
win32_drv_savefile(mpdm_t a,mpdm_t ctxt)1736 static mpdm_t win32_drv_savefile(mpdm_t a, mpdm_t ctxt)
1737 /* savefile driver function */
1738 {
1739 return open_or_save(0, a);
1740 }
1741
1742
win32_drv_openfolder(mpdm_t a,mpdm_t ctxt)1743 static mpdm_t win32_drv_openfolder(mpdm_t a, mpdm_t ctxt)
1744 /* openfolder driver function */
1745 {
1746 mpdm_t r = NULL;
1747 BROWSEINFO bi;
1748 char tmp[16384];
1749 char *ptr;
1750 LPITEMIDLIST i;
1751
1752 /* 1# arg: prompt */
1753 ptr = mpdm_wcstombs(mpdm_string(mpdm_get_i(a, 0)), NULL);
1754
1755 memset(&bi, '\0', sizeof(bi));
1756 bi.hwndOwner = hwnd;
1757 bi.pidlRoot = NULL;
1758 bi.pszDisplayName = tmp;
1759 bi.lpszTitle = ptr;
1760 bi.ulFlags = BIF_RETURNONLYFSDIRS;
1761
1762 if ((i = SHBrowseForFolder(&bi)) != NULL) {
1763 if (SHGetPathFromIDList(i, tmp) != 0)
1764 r = MPDM_MBS(tmp);
1765 }
1766
1767 free(ptr);
1768
1769 return r;
1770 }
1771
1772
win32_drv_update_ui(mpdm_t a,mpdm_t ctxt)1773 static mpdm_t win32_drv_update_ui(mpdm_t a, mpdm_t ctxt)
1774 {
1775 build_fonts(GetDC(hwnd));
1776 build_colors();
1777 build_menu();
1778
1779 return NULL;
1780 }
1781
1782
win32_drv_idle(mpdm_t a,mpdm_t ctxt)1783 static mpdm_t win32_drv_idle(mpdm_t a, mpdm_t ctxt)
1784 {
1785 int idle_msecs = (int) (mpdm_rval(mpdm_get_i(a, 0)) * 1000);
1786
1787 KillTimer(hwnd, 1);
1788
1789 if (idle_msecs > 0)
1790 SetTimer(hwnd, 1, idle_msecs, NULL);
1791 }
1792
1793
win32_drv_busy(mpdm_t a,mpdm_t ctxt)1794 static mpdm_t win32_drv_busy(mpdm_t a, mpdm_t ctxt)
1795 {
1796 int onoff = mpdm_ival(mpdm_get_i(a, 0));
1797
1798 SetCursor(LoadCursor(NULL, onoff ? IDC_WAIT : IDC_ARROW));
1799
1800 return NULL;
1801 }
1802
1803
register_functions(void)1804 static void register_functions(void)
1805 {
1806 mpdm_t drv;
1807
1808 drv = mpdm_get_wcs(mpdm_root(), L"mp_drv");
1809 mpdm_set_wcs(drv, MPDM_X(win32_drv_main_loop), L"main_loop");
1810 mpdm_set_wcs(drv, MPDM_X(win32_drv_shutdown), L"shutdown");
1811 mpdm_set_wcs(drv, MPDM_X(win32_drv_clip_to_sys), L"clip_to_sys");
1812 mpdm_set_wcs(drv, MPDM_X(win32_drv_sys_to_clip), L"sys_to_clip");
1813 mpdm_set_wcs(drv, MPDM_X(win32_drv_update_ui), L"update_ui");
1814 mpdm_set_wcs(drv, MPDM_X(win32_drv_idle), L"idle");
1815 mpdm_set_wcs(drv, MPDM_X(win32_drv_busy), L"busy");
1816 mpdm_set_wcs(drv, MPDM_X(win32_drv_alert), L"alert");
1817 mpdm_set_wcs(drv, MPDM_X(win32_drv_confirm), L"confirm");
1818 mpdm_set_wcs(drv, MPDM_X(win32_drv_openfile), L"openfile");
1819 mpdm_set_wcs(drv, MPDM_X(win32_drv_savefile), L"savefile");
1820 mpdm_set_wcs(drv, MPDM_X(win32_drv_form), L"form");
1821 mpdm_set_wcs(drv, MPDM_X(win32_drv_openfolder), L"openfolder");
1822 }
1823
1824
win32_drv_startup(mpdm_t a,mpdm_t ctxt)1825 static mpdm_t win32_drv_startup(mpdm_t a, mpdm_t ctxt)
1826 {
1827 WNDCLASSW wc;
1828 RECT r;
1829 mpdm_t v;
1830
1831 register_functions();
1832
1833 InitCommonControls();
1834
1835 hinst = GetModuleHandle(NULL);
1836
1837 /* register the window */
1838 wc.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS;
1839 wc.lpfnWndProc = WndProc;
1840 wc.cbClsExtra = 0;
1841 wc.cbWndExtra = 0;
1842 wc.hInstance = hinst;
1843 wc.hIcon = LoadIcon(hinst, "MP_ICON");
1844 wc.hCursor = LoadCursor(NULL, IDC_ARROW);
1845 wc.hbrBackground = NULL;
1846 wc.lpszMenuName = NULL;
1847 wc.lpszClassName = L"minimumprofit5.x";
1848
1849 RegisterClassW(&wc);
1850
1851 v = mpdm_get_wcs(MP, L"state");
1852 if ((v = mpdm_get_wcs(v, L"window")) == NULL) {
1853 v = mpdm_set_wcs(mpdm_get_wcs(MP, L"state"), MPDM_O(), L"window");
1854 mpdm_set_wcs(v, MPDM_I(10), L"x");
1855 mpdm_set_wcs(v, MPDM_I(10), L"y");
1856 mpdm_set_wcs(v, MPDM_I(600), L"w");
1857 mpdm_set_wcs(v, MPDM_I(400), L"h");
1858 }
1859
1860 /* create the window */
1861 hwnd = CreateWindowW(L"minimumprofit5.x", L"mp " VERSION,
1862 WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN | WS_VSCROLL,
1863 mpdm_ival(mpdm_get_wcs(v, L"x")),
1864 mpdm_ival(mpdm_get_wcs(v, L"y")),
1865 mpdm_ival(mpdm_get_wcs(v, L"w")),
1866 mpdm_ival(mpdm_get_wcs(v, L"h")),
1867 NULL, NULL, hinst, NULL);
1868
1869 ShowWindow(hwnd, SW_SHOW);
1870 UpdateWindow(hwnd);
1871
1872 GetClientRect(hwnd, &r);
1873
1874 hwtabs = CreateWindow(WC_TABCONTROL, "tab",
1875 WS_CHILD | TCS_TABS | TCS_SINGLELINE |
1876 TCS_FOCUSNEVER, 0, 0, r.right - r.left,
1877 tab_height, hwnd, NULL, hinst, NULL);
1878
1879 SendMessage(hwtabs, WM_SETFONT,
1880 (WPARAM) GetStockObject(DEFAULT_GUI_FONT), 0);
1881
1882 ShowWindow(hwtabs, SW_SHOW);
1883 UpdateWindow(hwtabs);
1884
1885 hwstatus = CreateWindow(WC_STATIC, "status",
1886 WS_CHILD,
1887 0, r.bottom - r.top - status_height,
1888 r.right - r.left, status_height, hwnd, NULL,
1889 hinst, NULL);
1890
1891 win32_drv_update_ui(NULL, NULL);
1892
1893 SendMessage(hwstatus, WM_SETFONT,
1894 (WPARAM) GetStockObject(DEFAULT_GUI_FONT), 0);
1895
1896 ShowWindow(hwstatus, SW_SHOW);
1897 UpdateWindow(hwstatus);
1898
1899 if ((v = mpdm_get_wcs(MP, L"config")) != NULL &&
1900 mpdm_ival(mpdm_get_wcs(v, L"maximize")) > 0)
1901 SendMessage(hwnd, WM_SYSCOMMAND, SC_MAXIMIZE, 0);
1902
1903 return NULL;
1904 }
1905
1906
win32_drv_detect(int * argc,char *** argv)1907 int win32_drv_detect(int *argc, char ***argv)
1908 {
1909 int n, ret = 1;
1910
1911 for (n = 0; n < *argc; n++) {
1912 if (strcmp(argv[0][n], "-txt") == 0)
1913 ret = 0;
1914 }
1915
1916 if (ret) {
1917 mpdm_t drv;
1918
1919 drv = mpdm_set_wcs(mpdm_root(), MPDM_O(), L"mp_drv");
1920
1921 mpdm_set_wcs(drv, MPDM_S(sizeof(char *) == 8 ? L"win64" : L"win32"), L"id");
1922 mpdm_set_wcs(drv, MPDM_X(win32_drv_startup), L"startup");
1923 }
1924
1925 return ret;
1926 }
1927
1928 #endif /* CONFOPT_WIN32 */
1929