3 Minimum Profit - Programmer Text Editor
7 Copyright (C) 1991-2009 Angel Ortega <angel@triptico.com>
9 This program is free software; you can redistribute it and/or
10 modify it under the terms of the GNU General Public License
11 as published by the Free Software Foundation; either version 2
12 of the License, or (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
23 http://www.triptico.com
54 /* font handlers and metrics */
55 HFONT font_normal
= NULL
;
56 HFONT font_underline
= NULL
;
60 /* height of the tab set */
63 /* height of the status bar */
64 int status_height
= 16;
66 int is_wm_keydown
= 0;
69 static COLORREF
*inks
= NULL
;
70 static COLORREF
*papers
= NULL
;
71 int *underlines
= NULL
;
74 /* code for the 'normal' attribute */
75 static int normal_attr
= 0;
78 static HMENU menu
= NULL
;
80 /* mp.drv.form() controls */
82 static mpdm_t form_args
= NULL
;
83 static mpdm_t form_values
= NULL
;
86 static int mouse_down
= 0;
89 static mpdm_t timer_func
= NULL
;
93 static void update_window_size(void)
94 /* updates the viewport size in characters */
100 /* no font information? go */
101 if (font_width
== 0 || font_height
== 0)
104 GetClientRect(hwnd
, &rect
);
106 /* calculate the size in chars */
107 tx
= ((rect
.right
- rect
.left
) / font_width
) + 1;
108 ty
= (rect
.bottom
- rect
.top
- tab_height
) / font_height
;
110 /* store the 'window' size */
111 v
= mpdm_hget_s(mp
, L
"window");
112 mpdm_hset_s(v
, L
"tx", MPDM_I(tx
));
113 mpdm_hset_s(v
, L
"ty", MPDM_I(ty
));
117 static void build_fonts(HDC hdc
)
118 /* build the fonts */
123 char * font_face
= "Lucida Console";
126 if (font_normal
!= NULL
) {
127 SelectObject(hdc
, GetStockObject(SYSTEM_FONT
));
128 DeleteObject(font_normal
);
131 /* get current configuration */
132 if ((c
= mpdm_hget_s(mp
, L
"config")) != NULL
) {
135 if ((v
= mpdm_hget_s(c
, L
"font_size")) != NULL
)
136 font_size
= mpdm_ival(v
);
138 mpdm_hset_s(c
, L
"font_size", MPDM_I(font_size
));
140 if ((v
= mpdm_hget_s(c
, L
"font_face")) != NULL
) {
141 v
= MPDM_2MBS(v
->data
);
142 font_face
= (char *)v
->data
;
145 mpdm_hset_s(c
, L
"font_face", MPDM_MBS(font_face
));
149 n
= -MulDiv(font_size
, GetDeviceCaps(hdc
, LOGPIXELSY
), 72);
151 font_normal
= CreateFont(n
, 0, 0, 0, 0, 0, 0,
152 0, 0, 0, 0, 0, 0, font_face
);
154 font_underline
= CreateFont(n
, 0, 0, 0, 0, 0, 1,
155 0, 0, 0, 0, 0, 0, font_face
);
157 SelectObject(hdc
, font_normal
);
158 GetTextMetrics(hdc
, &tm
);
161 font_height
= tm
.tmHeight
;
162 font_width
= tm
.tmAveCharWidth
;
164 update_window_size();
168 static void build_colors(void)
169 /* builds the colors */
176 /* gets the color definitions and attribute names */
177 colors
= mpdm_hget_s(mp
, L
"colors");
178 l
= mpdm_keys(colors
);
181 /* redim the structures */
182 inks
= realloc(inks
, sizeof(COLORREF
) * s
);
183 papers
= realloc(papers
, sizeof(COLORREF
) * s
);
184 underlines
= realloc(underlines
, sizeof(int) * s
);
186 /* loop the colors */
187 for (n
= 0; n
< s
&& (c
= mpdm_aget(l
, n
)) != NULL
; n
++) {
188 mpdm_t d
= mpdm_hget(colors
, c
);
189 mpdm_t v
= mpdm_hget_s(d
, L
"gui");
192 /* store the 'normal' attribute */
193 if (wcscmp(mpdm_string(c
), L
"normal") == 0)
197 mpdm_hset_s(d
, L
"attr", MPDM_I(n
));
199 m
= mpdm_ival(mpdm_aget(v
, 0));
200 inks
[n
] = ((m
& 0x000000ff) << 16)|
202 ((m
& 0x00ff0000) >> 16);
203 m
= mpdm_ival(mpdm_aget(v
, 1));
204 papers
[n
] = ((m
& 0x000000ff) << 16)|
206 ((m
& 0x00ff0000) >> 16);
209 v
= mpdm_hget_s(d
, L
"flags");
211 underlines
[n
] = mpdm_seek_s(v
, L
"underline", 1) != -1 ? 1 : 0;
213 if (mpdm_seek_s(v
, L
"reverse", 1) != -1) {
222 /* create the background brush */
223 bgbrush
= CreateSolidBrush(papers
[normal_attr
]);
227 static void build_menu(void)
228 /* builds the menu */
232 int win32_menu_id
= 1000;
234 /* gets the current menu */
235 if ((m
= mpdm_hget_s(mp
, L
"menu")) == NULL
)
243 for (n
= 0; n
< mpdm_size(m
); n
++) {
247 HMENU submenu
= CreatePopupMenu();
249 /* get the label and the items */
250 mi
= mpdm_aget(m
, n
);
251 v
= mpdm_gettext(mpdm_aget(mi
, 0));
252 l
= mpdm_aget(mi
, 1);
254 /* create the submenus */
255 for (i
= 0; i
< mpdm_size(l
); i
++) {
257 mpdm_t v
= mpdm_aget(l
, i
);
259 /* if the action is a separator... */
260 if (*((wchar_t *)v
->data
) == L
'-')
261 AppendMenu(submenu
, MF_SEPARATOR
, 0, NULL
);
264 mpdm_t d
= mp_menu_label(v
);
267 ptr
= mpdm_wcstombs(mpdm_string(d
), NULL
);
268 AppendMenu(submenu
, MF_STRING
, win32_menu_id
, ptr
);
271 /* store the action inside the menu */
272 memset(&mi
, '\0', sizeof(mi
));
273 mi
.cbSize
= sizeof(mi
);
274 mi
.fMask
= MIIM_DATA
;
275 mi
.dwItemData
= (unsigned long)v
;
277 SetMenuItemInfo(submenu
, win32_menu_id
, FALSE
, &mi
);
283 /* now store the popup inside the menu */
284 ptr
= mpdm_wcstombs(mpdm_string(v
), NULL
);
285 AppendMenu(menu
, MF_STRING
|MF_POPUP
, (UINT
)submenu
, ptr
);
293 static void draw_filetabs(void)
294 /* draws the filetabs */
296 static mpdm_t last
= NULL
;
303 names
= mp_get_doc_names();
305 /* is the list different from the previous one? */
306 if (mpdm_cmp(names
, last
) != 0) {
307 TabCtrl_DeleteAllItems(hwtabs
);
309 for (n
= 0; n
< mpdm_size(names
); n
++) {
312 mpdm_t v
= mpdm_aget(names
, n
);
315 ptr
= mpdm_wcstombs(v
->data
, NULL
);
321 TabCtrl_InsertItem(hwtabs
, n
, &ti
);
326 /* store for the next time */
327 mpdm_unref(last
); last
= mpdm_ref(names
);
330 /* set the active one */
331 TabCtrl_SetCurSel(hwtabs
, mpdm_ival(mpdm_hget_s(mp
, L
"active_i")));
335 static void draw_scrollbar(void)
336 /* updates the scrollbar */
343 /* gets the active document */
344 if ((d
= mp_active()) == NULL
)
347 /* get the coordinates */
348 v
= mpdm_hget_s(d
, L
"txt");
349 pos
= mpdm_ival(mpdm_hget_s(v
, L
"vy"));
350 max
= mpdm_size(mpdm_hget_s(v
, L
"lines"));
352 v
= mpdm_hget_s(mp
, L
"window");
353 size
= mpdm_ival(mpdm_hget_s(v
, L
"ty"));
355 si
.cbSize
= sizeof(si
);
362 SetScrollInfo(hwnd
, SB_VERT
, &si
, TRUE
);
366 void draw_status(void)
367 /* draws the status line */
371 if (hwstatus
!= NULL
&& (t
= mp_build_status_line()) != NULL
) {
372 t
= MPDM_2MBS(t
->data
);
375 SetWindowText(hwstatus
, t
->data
);
380 static void win32_draw(HWND hwnd
, mpdm_t doc
)
381 /* win32 document draw function */
391 hdc
= BeginPaint(hwnd
, &ps
);
393 /* no font? construct it */
394 if (font_normal
== NULL
) {
399 /* no document? end */
400 if ((d
= mp_draw(doc
, 0)) == NULL
) {
405 /* select defaults to start painting */
406 SelectObject(hdc
, font_normal
);
408 GetClientRect(hwnd
, &rect
);
411 r2
.top
+= tab_height
;
412 r2
.bottom
= r2
.top
+ font_height
;
414 for (n
= 0; n
< mpdm_size(d
); n
++) {
415 mpdm_t l
= mpdm_aget(d
, n
);
419 for (m
= 0; m
< mpdm_size(l
); m
++) {
423 /* get the attribute and the string */
424 attr
= mpdm_ival(mpdm_aget(l
, m
++));
427 SetTextColor(hdc
, inks
[attr
]);
428 SetBkColor(hdc
, papers
[attr
]);
430 SelectObject(hdc
, underlines
[attr
] ?
431 font_underline
: font_normal
);
433 TextOutW(hdc
, r2
.left
, r2
.top
, s
->data
, mpdm_size(s
));
434 r2
.left
+= mpdm_size(s
) * font_width
;
437 /* fills the rest of the line */
438 FillRect(hdc
, &r2
, bgbrush
);
440 r2
.top
+= font_height
;
441 r2
.bottom
+= font_height
;
452 static void redraw(void)
454 InvalidateRect(hwnd
, NULL
, TRUE
);
458 static void win32_vkey(int c
)
459 /* win32 virtual key processing */
461 wchar_t * ptr
= NULL
;
462 static int maxed
= 0;
464 /* set mp.shift_pressed */
465 if (GetKeyState(VK_SHIFT
) & 0x8000)
466 mpdm_hset_s(mp
, L
"shift_pressed", MPDM_I(1));
468 if (GetKeyState(VK_CONTROL
) & 0x8000 ||
469 GetKeyState(VK_MENU
) & 0x8000) {
471 case VK_UP
: ptr
= L
"ctrl-cursor-up"; break;
472 case VK_DOWN
: ptr
= L
"ctrl-cursor-down"; break;
473 case VK_LEFT
: ptr
= L
"ctrl-cursor-left"; break;
474 case VK_RIGHT
: ptr
= L
"ctrl-cursor-right"; break;
475 case VK_PRIOR
: ptr
= L
"ctrl-page-up"; break;
476 case VK_NEXT
: ptr
= L
"ctrl-page-down"; break;
477 case VK_HOME
: ptr
= L
"ctrl-home"; break;
478 case VK_END
: ptr
= L
"ctrl-end"; break;
479 case VK_SPACE
: ptr
= L
"ctrl-space"; break;
480 case VK_DIVIDE
: ptr
= L
"ctrl-kp-divide"; break;
481 case VK_MULTIPLY
: ptr
= L
"ctrl-kp-multiply"; break;
482 case VK_SUBTRACT
: ptr
= L
"ctrl-kp-minus"; break;
483 case VK_ADD
: ptr
= L
"ctrl-kp-plus"; break;
484 case VK_RETURN
: ptr
= L
"ctrl-enter"; break;
485 case VK_F1
: ptr
= L
"ctrl-f1"; break;
486 case VK_F2
: ptr
= L
"ctrl-f2"; break;
487 case VK_F3
: ptr
= L
"ctrl-f3"; break;
488 case VK_F4
: ptr
= L
"ctrl-f4"; break;
489 case VK_F5
: ptr
= L
"ctrl-f5"; break;
490 case VK_F6
: ptr
= L
"ctrl-f6"; break;
491 case VK_F7
: ptr
= L
"ctrl-f7"; break;
492 case VK_F8
: ptr
= L
"ctrl-f8"; break;
493 case VK_F9
: ptr
= L
"ctrl-f9"; break;
494 case VK_F10
: ptr
= L
"ctrl-f10"; break;
495 case VK_F11
: ptr
= L
"ctrl-f11"; break;
497 SendMessage(hwnd
, WM_SYSCOMMAND
,
498 maxed
? SC_RESTORE
: SC_MAXIMIZE
, 0);
507 case VK_UP
: ptr
= L
"cursor-up"; break;
508 case VK_DOWN
: ptr
= L
"cursor-down"; break;
509 case VK_LEFT
: ptr
= L
"cursor-left"; break;
510 case VK_RIGHT
: ptr
= L
"cursor-right"; break;
511 case VK_PRIOR
: ptr
= L
"page-up"; break;
512 case VK_NEXT
: ptr
= L
"page-down"; break;
513 case VK_HOME
: ptr
= L
"home"; break;
514 case VK_END
: ptr
= L
"end"; break;
515 case VK_TAB
: ptr
= L
"tab"; break;
516 case VK_RETURN
: ptr
= L
"enter"; break;
517 case VK_BACK
: ptr
= L
"backspace"; break;
518 case VK_DELETE
: ptr
= L
"delete"; break;
519 case VK_INSERT
: ptr
= L
"insert"; break;
520 case VK_DIVIDE
: ptr
= L
"kp-divide"; break;
521 case VK_MULTIPLY
: ptr
= L
"kp-multiply"; break;
522 case VK_SUBTRACT
: ptr
= L
"kp-minus"; break;
523 case VK_ADD
: ptr
= L
"kp-plus"; break;
524 case VK_F1
: ptr
= L
"f1"; break;
525 case VK_F2
: ptr
= L
"f2"; break;
526 case VK_F3
: ptr
= L
"f3"; break;
527 case VK_F4
: ptr
= L
"f4"; break;
528 case VK_F5
: ptr
= L
"f5"; break;
529 case VK_F6
: ptr
= L
"f6"; break;
530 case VK_F7
: ptr
= L
"f7"; break;
531 case VK_F8
: ptr
= L
"f8"; break;
532 case VK_F9
: ptr
= L
"f9"; break;
533 case VK_F10
: ptr
= L
"f10"; break;
534 case VK_F11
: ptr
= L
"f11"; break;
535 case VK_F12
: ptr
= L
"f12"; break;
540 mp_process_event(MPDM_S(ptr
));
544 if (mp_keypress_throttle(1))
550 #define ctrl(c) ((c) & 31)
552 static void win32_akey(int k
)
553 /* win32 alphanumeric key processing */
556 wchar_t * ptr
= NULL
;
558 /* set mp.shift_pressed */
559 if (GetKeyState(VK_SHIFT
) & 0x8000)
560 mpdm_hset_s(mp
, L
"shift_pressed", MPDM_I(1));
563 case ctrl(' '): ptr
= L
"ctrl-space"; break;
564 case ctrl('a'): ptr
= L
"ctrl-a"; break;
565 case ctrl('b'): ptr
= L
"ctrl-b"; break;
566 case ctrl('c'): ptr
= L
"ctrl-c"; break;
567 case ctrl('d'): ptr
= L
"ctrl-d"; break;
568 case ctrl('e'): ptr
= L
"ctrl-e"; break;
569 case ctrl('f'): ptr
= L
"ctrl-f"; break;
570 case ctrl('g'): ptr
= L
"ctrl-g"; break;
571 case ctrl('h'): /* same as backspace */ break;
572 case ctrl('i'): ptr
= L
"ctrl-i"; break;
573 case ctrl('j'): ptr
= L
"ctrl-j"; break;
574 case ctrl('k'): ptr
= L
"ctrl-k"; break;
575 case ctrl('l'): ptr
= L
"ctrl-l"; break;
576 case ctrl('m'): /* same as ENTER */ break;
577 case ctrl('n'): ptr
= L
"ctrl-n"; break;
578 case ctrl('o'): ptr
= L
"ctrl-o"; break;
579 case ctrl('p'): ptr
= L
"ctrl-p"; break;
580 case ctrl('q'): ptr
= L
"ctrl-q"; break;
581 case ctrl('r'): ptr
= L
"ctrl-r"; break;
582 case ctrl('s'): ptr
= L
"ctrl-s"; break;
583 case ctrl('t'): ptr
= L
"ctrl-t"; break;
584 case ctrl('u'): ptr
= L
"ctrl-u"; break;
585 case ctrl('v'): ptr
= L
"ctrl-v"; break;
586 case ctrl('w'): ptr
= L
"ctrl-w"; break;
587 case ctrl('x'): ptr
= L
"ctrl-x"; break;
588 case ctrl('y'): ptr
= L
"ctrl-y"; break;
589 case ctrl('z'): ptr
= L
"ctrl-z"; break;
590 case ' ': ptr
= L
"space"; break;
591 case 27: ptr
= L
"escape"; break;
594 /* this is probably very bad */
603 mp_process_event(MPDM_S(ptr
));
610 static void win32_vscroll(UINT wparam
)
611 /* scrollbar messages handler */
613 wchar_t * ptr
= NULL
;
616 switch (LOWORD(wparam
)) {
617 case SB_PAGEUP
: ptr
= L
"page-up"; break;
618 case SB_PAGEDOWN
: ptr
= L
"page-down"; break;
619 case SB_LINEUP
: ptr
= L
"cursor-up"; break;
620 case SB_LINEDOWN
: ptr
= L
"cursor-down"; break;
621 case SB_THUMBPOSITION
:
623 /* set both y and vy */
624 txt
= mpdm_hget_s(mp_active(), L
"txt");
625 mp_set_y(mp_active(), HIWORD(wparam
));
626 mpdm_hset_s(txt
, L
"vy", MPDM_I(HIWORD(wparam
)));
632 mp_process_event(MPDM_S(ptr
));
638 static void action_by_menu(int item
)
639 /* execute an action triggered by the menu */
643 memset(&mi
, '\0', sizeof(mi
));
644 mi
.cbSize
= sizeof(mi
);
645 mi
.fMask
= MIIM_DATA
;
647 if (GetMenuItemInfo(menu
, item
, FALSE
, &mi
)) {
648 if (mi
.dwItemData
!= 0) {
649 mp_process_action((mpdm_t
)mi
.dwItemData
);
656 static void dropped_files(HDROP hDrop
)
657 /* fill the mp.dropped_files array with the dropped files */
659 mpdm_t a
= MPDM_A(0);
663 n
= DragQueryFile(hDrop
, 0xffffffff, NULL
, sizeof(tmp
) - 1);
666 DragQueryFile(hDrop
, n
, tmp
, sizeof(tmp
) - 1);
667 mpdm_push(a
, MPDM_MBS(tmp
));
672 mpdm_hset_s(mp
, L
"dropped_files", a
);
673 mp_process_event(MPDM_LS(L
"dropped-files"));
678 #ifndef WM_MOUSEWHEEL
679 #define WM_MOUSEWHEEL 0x020A
682 long STDCALL
WndProc(HWND hwnd
, UINT msg
, UINT wparam
, LONG lparam
)
683 /* main window Proc */
687 wchar_t * ptr
= NULL
;
693 DragAcceptFiles(hwnd
, TRUE
);
698 dropped_files((HDROP
) wparam
);
705 if (mp_keypress_throttle(0))
722 win32_vscroll(wparam
);
727 if (mpdm_size(mpdm_hget_s(mp
, L
"docs")))
728 win32_draw(hwnd
, mp_active());
734 if (!IsIconic(hwnd
)) {
735 update_window_size();
737 MoveWindow(hwtabs
, 0, 0, LOWORD(lparam
), tab_height
, FALSE
);
739 MoveWindow(hwstatus
, 0, HIWORD(lparam
) - status_height
,
740 LOWORD(lparam
), status_height
, FALSE
);
755 x
= (LOWORD(lparam
)) / font_width
;
756 y
= (HIWORD(lparam
) - tab_height
) / font_height
;
758 mpdm_hset_s(mp
, L
"mouse_x", MPDM_I(x
));
759 mpdm_hset_s(mp
, L
"mouse_y", MPDM_I(y
));
762 case WM_LBUTTONDOWN
: ptr
= L
"mouse-left-button"; break;
763 case WM_RBUTTONDOWN
: ptr
= L
"mouse-right-button"; break;
764 case WM_MBUTTONDOWN
: ptr
= L
"mouse-middle-button"; break;
768 mp_process_event(MPDM_S(ptr
));
782 x
= (LOWORD(lparam
)) / font_width
;
783 y
= (HIWORD(lparam
) - tab_height
) / font_height
;
785 mpdm_hset_s(mp
, L
"mouse_to_x", MPDM_I(x
));
786 mpdm_hset_s(mp
, L
"mouse_to_y", MPDM_I(y
));
788 mp_process_event(MPDM_LS(L
"mouse-drag"));
796 if ((int) wparam
> 0)
797 ptr
= L
"mouse-wheel-up";
799 ptr
= L
"mouse-wheel-down";
802 mp_process_event(MPDM_S(ptr
));
810 action_by_menu(LOWORD(wparam
));
817 if (!mp_exit_requested
)
818 mp_process_event(MPDM_LS(L
"close-window"));
820 if (mp_exit_requested
)
832 if (p
->code
== TCN_SELCHANGE
) {
833 /* tab selected by clicking on it */
834 int n
= TabCtrl_GetCurSel(hwtabs
);
836 /* set mp.active_i to this */
837 mpdm_hset_s(mp
, L
"active_i", MPDM_I(n
));
845 mpdm_exec(timer_func
, NULL
);
850 if (mp_exit_requested
)
851 PostMessage(hwnd
, WM_CLOSE
, 0, 0);
853 return DefWindowProcW(hwnd
, msg
, wparam
, lparam
);
857 static mpdm_t
win32_drv_clip_to_sys(mpdm_t a
)
858 /* driver-dependent mp to system clipboard */
866 /* convert the clipboard to DOS text */
867 d
= mpdm_hget_s(mp
, L
"clipboard");
869 if (mpdm_size(d
) == 0)
872 d
= mpdm_join(MPDM_LS(L
"\r\n"), d
);
873 ptr
= mpdm_wcstombs(d
->data
, &s
);
875 /* allocates a handle and copies */
876 hclp
= GlobalAlloc(GHND
, s
+ 1);
877 clpptr
= (char *)GlobalLock(hclp
);
878 memcpy(clpptr
, ptr
, s
);
886 SetClipboardData(CF_TEXT
, hclp
);
893 static mpdm_t
win32_drv_sys_to_clip(mpdm_t a
)
894 /* driver-dependent system to mp clipboard */
900 hclp
= GetClipboardData(CF_TEXT
);
903 if (hclp
&& (ptr
= GlobalLock(hclp
)) != NULL
) {
906 /* create a value and split */
908 d
= mpdm_split(MPDM_LS(L
"\r\n"), d
);
910 /* and set as the clipboard */
911 mpdm_hset_s(mp
, L
"clipboard", d
);
912 mpdm_hset_s(mp
, L
"clipboard_vertical", MPDM_I(0));
921 static mpdm_t
win32_drv_main_loop(mpdm_t a
)
925 if (!mp_exit_requested
) {
928 while (GetMessage(&msg
, NULL
, 0, 0)) {
929 TranslateMessage(&msg
);
930 DispatchMessage(&msg
);
938 static mpdm_t
win32_drv_shutdown(mpdm_t a
)
942 SendMessage(hwnd
, WM_CLOSE
, 0, 0);
944 if ((v
= mpdm_hget_s(mp
, L
"exit_message")) != NULL
) {
945 char * ptr
= mpdm_wcstombs(mpdm_string(v
), NULL
);
946 MessageBox(NULL
, ptr
, "mp " VERSION
, MB_ICONWARNING
|MB_OK
);
954 static mpdm_t
win32_drv_alert(mpdm_t a
)
955 /* alert driver function */
961 wptr
= mpdm_string(mpdm_aget(a
, 0));
963 if ((ptr
= mpdm_wcstombs(wptr
, NULL
)) != NULL
) {
964 MessageBox(hwnd
, ptr
, "mp " VERSION
, MB_ICONWARNING
|MB_OK
);
972 static mpdm_t
win32_drv_confirm(mpdm_t a
)
973 /* confirm driver function */
980 wptr
= mpdm_string(mpdm_aget(a
, 0));
982 if ((ptr
= mpdm_wcstombs(wptr
, NULL
)) != NULL
) {
983 ret
= MessageBox(hwnd
, ptr
, "mp " VERSION
, MB_ICONQUESTION
|MB_YESNOCANCEL
);
999 static LPWORD
lpwAlign(LPWORD lpIn
)
1000 /* aligns a pointer to DWORD boundary (for dialog templates) */
1012 #define LABEL_ID 1000
1013 #define CTRL_ID 2000
1015 BOOL CALLBACK
formDlgProc(HWND hwnd
, UINT msg
, WPARAM wparam
, LPARAM lparam
)
1016 /* mp.drv.form() dialog proc */
1024 SetWindowText(hwnd
, "mp " VERSION
);
1026 hf
= GetStockObject(DEFAULT_GUI_FONT
);
1028 /* fill controls with its initial data */
1029 for (n
= 0; n
< mpdm_size(form_args
); n
++) {
1030 mpdm_t w
= mpdm_aget(form_args
, n
);
1033 int ctrl
= CTRL_ID
+ n
;
1037 if ((t
= mpdm_hget_s(w
, L
"label")) != NULL
) {
1038 if ((ptr
= mpdm_wcstombs(mpdm_string(t
), NULL
)) != NULL
) {
1039 SetDlgItemText(hwnd
, LABEL_ID
+ n
, ptr
);
1042 SendDlgItemMessage(hwnd
, LABEL_ID
+ n
, WM_SETFONT
,
1043 (WPARAM
) hf
, MAKELPARAM(FALSE
, 0));
1047 SendDlgItemMessage(hwnd
, ctrl
, WM_SETFONT
,
1048 (WPARAM
) hf
, MAKELPARAM(FALSE
, 0));
1050 type
= mpdm_string(mpdm_hget_s(w
, L
"type"));
1052 if (wcscmp(type
, L
"text") == 0) {
1053 if ((t
= mpdm_hget_s(w
, L
"value")) != NULL
&&
1054 (ptr
= mpdm_wcstombs(mpdm_string(t
), NULL
)) != NULL
) {
1055 SetDlgItemText(hwnd
, ctrl
, ptr
);
1059 /* store the history into combo_items */
1060 if ((t
= mpdm_hget_s(w
, L
"history")) != NULL
) {
1061 t
= mp_get_history(t
);
1064 for (i
= 0; i
< mpdm_size(t
); i
++) {
1065 mpdm_t v
= mpdm_aget(t
, i
);
1067 if ((ptr
= mpdm_wcstombs(v
->data
,
1069 SendDlgItemMessage(hwnd
,
1079 if (wcscmp(type
, L
"password") == 0) {
1080 SendDlgItemMessage(hwnd
, ctrl
,
1081 EM_SETPASSWORDCHAR
, (WPARAM
)'*', (LPARAM
)0);
1084 if (wcscmp(type
, L
"checkbox") == 0) {
1085 if ((t
= mpdm_hget_s(w
, L
"value")) != NULL
)
1086 SendDlgItemMessage(hwnd
, ctrl
,
1087 BM_SETCHECK
, mpdm_ival(t
) ?
1088 BST_CHECKED
: BST_UNCHECKED
,
1092 if (wcscmp(type
, L
"list") == 0) {
1095 t
= mpdm_hget_s(w
, L
"list");
1098 for (i
= 0; i
< mpdm_size(t
); i
++) {
1099 wptr
= mpdm_string(mpdm_aget(t
, i
));
1100 if ((ptr
= mpdm_wcstombs(wptr
, NULL
)) != NULL
) {
1101 SendDlgItemMessage(hwnd
, ctrl
,
1102 LB_ADDSTRING
, 0, (LPARAM
) ptr
);
1108 SendDlgItemMessage(hwnd
, ctrl
, LB_SETCURSEL
,
1109 mpdm_ival(mpdm_hget_s(w
, L
"value")), 0);
1113 /* FIXME: untranslated strings */
1115 SetDlgItemText(hwnd
, IDOK
, "OK");
1116 SendDlgItemMessage(hwnd
, IDOK
, WM_SETFONT
,
1117 (WPARAM
) hf
, MAKELPARAM(FALSE
, 0));
1119 SetDlgItemText(hwnd
, IDCANCEL
, "Cancel");
1120 SendDlgItemMessage(hwnd
, IDCANCEL
, WM_SETFONT
,
1121 (WPARAM
) hf
, MAKELPARAM(FALSE
, 0));
1127 if (LOWORD(wparam
) == IDCANCEL
) {
1132 if (LOWORD(wparam
) != IDOK
)
1135 /* fill all return values */
1136 for (n
= 0; n
< mpdm_size(form_args
); n
++) {
1137 mpdm_t w
= mpdm_aget(form_args
, n
);
1138 wchar_t * type
= mpdm_string(mpdm_hget_s(w
, L
"type"));
1139 int ctrl
= CTRL_ID
+ n
;
1141 if (wcscmp(type
, L
"text") == 0) {
1146 GetDlgItemText(hwnd
, ctrl
, tmp
, sizeof(tmp
) - 1);
1149 mpdm_aset(form_values
, v
, n
);
1151 /* if it has history, fill it */
1152 if ((h
= mpdm_hget_s(w
, L
"history")) != NULL
&&
1153 v
!= NULL
&& mpdm_cmp(v
, MPDM_LS(L
"")) != 0) {
1154 h
= mp_get_history(h
);
1156 if (mpdm_cmp(v
, mpdm_aget(h
, -1)) != 0)
1160 if (wcscmp(type
, L
"password") == 0) {
1163 GetDlgItemText(hwnd
, ctrl
, tmp
, sizeof(tmp
) - 1);
1164 mpdm_aset(form_values
, MPDM_MBS(tmp
), n
);
1167 if (wcscmp(type
, L
"checkbox") == 0) {
1168 mpdm_aset(form_values
,
1169 MPDM_I(SendDlgItemMessage(hwnd
, ctrl
,
1170 BM_GETCHECK
, 0, 0)), n
);
1173 if (wcscmp(type
, L
"list") == 0) {
1174 mpdm_aset(form_values
,
1175 MPDM_I(SendDlgItemMessage(hwnd
, ctrl
,
1176 LB_GETCURSEL
, 0, 0)), n
);
1188 static void build_form_data(mpdm_t widget_list
)
1189 /* builds the necessary information for a list of widgets */
1191 mpdm_unref(form_args
);
1192 form_args
= mpdm_ref(widget_list
);
1194 mpdm_unref(form_values
);
1195 form_values
= widget_list
== NULL
? NULL
:
1196 mpdm_ref(MPDM_A(mpdm_size(form_args
)));
1200 LPWORD
static build_control(LPWORD lpw
, int x
, int y
,
1201 int cx
, int cy
, int id
, int class, int style
)
1202 /* fills a control structure in a hand-made dialog template */
1204 LPDLGITEMTEMPLATE lpdit
;
1206 lpw
= lpwAlign(lpw
);
1207 lpdit
= (LPDLGITEMTEMPLATE
)lpw
;
1208 lpdit
->x
= x
; lpdit
->y
= y
;
1209 lpdit
->cx
= cx
; lpdit
->cy
= cy
;
1211 lpdit
->style
= style
;
1213 lpw
= (LPWORD
)(lpdit
+ 1);
1217 /* no text (will be set on dialog setup) */
1221 /* Align creation data on DWORD boundary */
1222 lpw
= lpwAlign(lpw
);
1223 /* No creation data */
1230 static mpdm_t
win32_drv_form(mpdm_t a
)
1231 /* mp.drv.form() function */
1240 /* first argument: list of widgets */
1241 build_form_data(mpdm_aget(a
, 0));
1243 /* On-the-fly dialog template creation */
1244 /* Note: all this crap is taken from MSDN, no less */
1246 /* magic size; looking for problems */
1247 hgbl
= GlobalAlloc(GMEM_ZEROINIT
, 4096);
1248 lpdt
= (LPDLGTEMPLATE
)GlobalLock(hgbl
);
1250 lpdt
->style
= WS_POPUP
| WS_BORDER
| WS_SYSMENU
| DS_MODALFRAME
| WS_CAPTION
;
1251 lpdt
->cdit
= (2 * mpdm_size(form_args
)) + 2;
1252 lpdt
->x
= 20; lpdt
->y
= 20;
1255 lpw
= (LPWORD
)(lpdt
+ 1);
1256 *lpw
++ = 0; /* No menu */
1257 *lpw
++ = 0; /* Predefined dialog box class (by default) */
1258 *lpw
++ = 0; /* No title */
1260 /* first pass: calculate maximum size of labels */
1261 for (n
= 0; n
< mpdm_size(form_args
); n
++) {
1262 mpdm_t w
= mpdm_aget(form_args
, n
);
1263 int l
= mpdm_size(mpdm_hget_s(w
, L
"label"));
1269 /* second pass: create the dialog controls */
1270 for (n
= p
= 0; n
< mpdm_size(form_args
); n
++) {
1271 mpdm_t w
= mpdm_aget(form_args
, n
);
1279 lpw
= build_control(lpw
, 0, 5 + p
* il
,
1280 lbl
* 3, 20, LABEL_ID
+ n
, 0x0082,
1281 WS_CHILD
| WS_VISIBLE
| SS_RIGHT
);
1283 type
= mpdm_string(mpdm_hget_s(w
, L
"type"));
1285 if (wcscmp(type
, L
"text") == 0) {
1287 style
= WS_CHILD
| WS_VISIBLE
| WS_TABSTOP
|
1288 CBS_DROPDOWN
| CBS_AUTOHSCROLL
| WS_VSCROLL
;
1294 if (wcscmp(type
, L
"password") == 0) {
1296 style
= WS_CHILD
| WS_VISIBLE
| WS_BORDER
| WS_TABSTOP
;
1299 if (wcscmp(type
, L
"checkbox") == 0) {
1301 style
= WS_CHILD
| WS_VISIBLE
| BS_AUTOCHECKBOX
| WS_TABSTOP
;
1304 if (wcscmp(type
, L
"list") == 0) {
1306 style
= WS_CHILD
| WS_VISIBLE
| WS_TABSTOP
| WS_BORDER
|
1307 LBS_NOINTEGRALHEIGHT
| WS_VSCROLL
|
1308 LBS_NOTIFY
| LBS_USETABSTOPS
;
1315 lpw
= build_control(lpw
, 10 + lbl
* 3, 5 + p
* il
,
1316 245 - lbl
* 3, inc
* il
* sz
, CTRL_ID
+ n
,
1323 /* set total height */
1324 lpdt
->cy
= 30 + p
* il
;
1327 lpw
= build_control(lpw
, 170, 10 + p
* il
, 40, 15, IDOK
,
1328 0x0080, WS_CHILD
| WS_VISIBLE
| BS_DEFPUSHBUTTON
| WS_TABSTOP
);
1331 lpw
= build_control(lpw
, 215, 10 + p
* il
, 40, 15, IDCANCEL
,
1332 0x0080, WS_CHILD
| WS_VISIBLE
| BS_PUSHBUTTON
| WS_TABSTOP
);
1335 n
= DialogBoxIndirect(hinst
, (LPDLGTEMPLATE
)hgbl
,
1336 hwnd
, (DLGPROC
)formDlgProc
);
1340 return n
? form_values
: NULL
;
1344 static mpdm_t
open_or_save(int o
, mpdm_t a
)
1345 /* manages an open or save file dialog */
1350 char buf
[1024] = "";
1354 /* 1# arg: prompt */
1355 wptr
= mpdm_string(mpdm_aget(a
, 0));
1356 ptr
= mpdm_wcstombs(wptr
, NULL
);
1358 memset(&ofn
, '\0', sizeof(OPENFILENAME
));
1359 ofn
.lStructSize
= sizeof(OPENFILENAME
);
1360 ofn
.hwndOwner
= hwnd
;
1361 ofn
.lpstrFilter
= "*.*\0*.*\0";
1362 ofn
.nFilterIndex
= 1;
1363 ofn
.lpstrFile
= buf
;
1364 ofn
.nMaxFile
= sizeof(buf
);
1365 ofn
.lpstrTitle
= ptr
;
1366 ofn
.lpstrDefExt
= "";
1368 GetCurrentDirectory(sizeof(buf2
), buf2
);
1369 ofn
.lpstrInitialDir
= buf2
;
1371 /* ofn.lpstrDefExt=(def==NULL ? "" : def);*/
1374 ofn
.Flags
= OFN_PATHMUSTEXIST
|OFN_HIDEREADONLY
|
1375 OFN_NOCHANGEDIR
|OFN_FILEMUSTEXIST
;
1377 r
= GetOpenFileName(&ofn
);
1380 ofn
.Flags
= OFN_HIDEREADONLY
;
1382 r
= GetSaveFileName(&ofn
);
1388 return MPDM_MBS(buf
);
1394 static mpdm_t
win32_drv_openfile(mpdm_t a
)
1395 /* openfile driver function */
1397 return open_or_save(1, a
);
1401 static mpdm_t
win32_drv_savefile(mpdm_t a
)
1402 /* savefile driver function */
1404 return open_or_save(0, a
);
1408 static mpdm_t
win32_drv_update_ui(mpdm_t a
)
1410 build_fonts(GetDC(hwnd
));
1418 static mpdm_t
win32_drv_timer(mpdm_t a
)
1420 int msecs
= mpdm_ival(mpdm_aget(a
, 0));
1421 mpdm_t func
= mpdm_aget(a
, 1);
1424 /* previously defined one? remove */
1425 if (timer_func
!= NULL
)
1428 /* if msecs and func are set, program timer */
1429 if (msecs
> 0 && func
!= NULL
)
1430 SetTimer(hwnd
, 1, msecs
, NULL
);
1432 r
= mpdm_unref(timer_func
);
1433 timer_func
= mpdm_ref(func
);
1439 static mpdm_t
win32_drv_busy(mpdm_t a
)
1441 int onoff
= mpdm_ival(mpdm_aget(a
, 0));
1443 SetCursor(LoadCursor(NULL
, onoff
? IDC_WAIT
: IDC_ARROW
));
1449 static void register_functions(void)
1453 drv
= mpdm_hget_s(mp
, L
"drv");
1454 mpdm_hset_s(drv
, L
"main_loop", MPDM_X(win32_drv_main_loop
));
1455 mpdm_hset_s(drv
, L
"shutdown", MPDM_X(win32_drv_shutdown
));
1457 mpdm_hset_s(drv
, L
"clip_to_sys", MPDM_X(win32_drv_clip_to_sys
));
1458 mpdm_hset_s(drv
, L
"sys_to_clip", MPDM_X(win32_drv_sys_to_clip
));
1459 mpdm_hset_s(drv
, L
"update_ui", MPDM_X(win32_drv_update_ui
));
1460 mpdm_hset_s(drv
, L
"timer", MPDM_X(win32_drv_timer
));
1461 mpdm_hset_s(drv
, L
"busy", MPDM_X(win32_drv_busy
));
1463 mpdm_hset_s(drv
, L
"alert", MPDM_X(win32_drv_alert
));
1464 mpdm_hset_s(drv
, L
"confirm", MPDM_X(win32_drv_confirm
));
1465 mpdm_hset_s(drv
, L
"openfile", MPDM_X(win32_drv_openfile
));
1466 mpdm_hset_s(drv
, L
"savefile", MPDM_X(win32_drv_savefile
));
1467 mpdm_hset_s(drv
, L
"form", MPDM_X(win32_drv_form
));
1471 static mpdm_t
win32_drv_startup(mpdm_t a
)
1477 register_functions();
1479 InitCommonControls();
1481 /* register the window */
1482 wc
.style
= CS_HREDRAW
|CS_VREDRAW
;
1483 wc
.lpfnWndProc
= WndProc
;
1486 wc
.hInstance
= hinst
;
1487 wc
.hIcon
= LoadIcon(hinst
,"MP_ICON");
1488 wc
.hCursor
= LoadCursor(NULL
, IDC_ARROW
);
1489 wc
.hbrBackground
= NULL
;
1490 wc
.lpszMenuName
= NULL
;
1491 wc
.lpszClassName
= L
"minimumprofit5.x";
1493 RegisterClassW(&wc
);
1495 /* create the window */
1496 hwnd
= CreateWindowW(L
"minimumprofit5.x", L
"mp " VERSION
,
1497 WS_OVERLAPPEDWINDOW
| WS_CLIPCHILDREN
| WS_VSCROLL
,
1498 CW_USEDEFAULT
, CW_USEDEFAULT
,
1499 CW_USEDEFAULT
, CW_USEDEFAULT
,
1500 NULL
, NULL
, hinst
, NULL
);
1502 ShowWindow(hwnd
, SW_SHOW
);
1505 GetClientRect(hwnd
, &r
);
1507 hwtabs
= CreateWindow(WC_TABCONTROL
, "tab",
1508 WS_CHILD
| TCS_TABS
| TCS_SINGLELINE
| TCS_FOCUSNEVER
,
1509 0, 0, r
.right
- r
.left
, tab_height
, hwnd
, NULL
, hinst
, NULL
);
1511 SendMessage(hwtabs
, WM_SETFONT
,
1512 (WPARAM
) GetStockObject(DEFAULT_GUI_FONT
), 0);
1514 ShowWindow(hwtabs
, SW_SHOW
);
1515 UpdateWindow(hwtabs
);
1517 hwstatus
= CreateWindow(WC_STATIC
, "status",
1519 0, r
.bottom
- r
.top
- status_height
,
1520 r
.right
- r
.left
, status_height
, hwnd
, NULL
, hinst
, NULL
);
1522 win32_drv_update_ui(NULL
);
1524 SendMessage(hwstatus
, WM_SETFONT
,
1525 (WPARAM
) GetStockObject(DEFAULT_GUI_FONT
), 0);
1527 ShowWindow(hwstatus
, SW_SHOW
);
1528 UpdateWindow(hwstatus
);
1530 if ((v
= mpdm_hget_s(mp
, L
"config")) != NULL
&&
1531 mpdm_ival(mpdm_hget_s(v
, L
"maximize")) > 0)
1532 SendMessage(hwnd
, WM_SYSCOMMAND
, SC_MAXIMIZE
, 0);
1538 int win32_drv_detect(int * argc
, char *** argv
)
1542 drv
= mpdm_hget_s(mp
, L
"drv");
1543 mpdm_hset_s(drv
, L
"id", MPDM_LS(L
"win32"));
1544 mpdm_hset_s(drv
, L
"startup", MPDM_X(win32_drv_startup
));
1549 #endif /* CONFOPT_WIN32 */