ui_win.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386
  1. #define HL_NAME(n) ui_##n
  2. #include <windows.h>
  3. #include <richedit.h>
  4. #include <hl.h>
  5. #define CLASS_NAME USTR("HLUIWindow")
  6. #define PTEXT USTR("_text")
  7. #define PREF USTR("_ref")
  8. typedef struct _wref wref;
  9. struct _wref {
  10. void (*finalize)( wref * );
  11. HWND h;
  12. vclosure *callb;
  13. int width;
  14. int height;
  15. };
  16. static void finalize_wref( wref *w ) {
  17. SetProp(w->h,PREF,NULL);
  18. }
  19. static wref *alloc_ref( HWND h ) {
  20. wref *ref = hl_gc_alloc_finalizer(sizeof(wref));
  21. memset(ref,0,sizeof(wref));
  22. ref->h = h;
  23. ref->finalize = finalize_wref;
  24. SetProp(h,PREF,ref);
  25. return ref;
  26. }
  27. static LRESULT CALLBACK WindowProc( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
  28. switch( msg ) {
  29. case WM_CLOSE:
  30. return 0;
  31. case WM_COMMAND:
  32. if( wparam == BN_CLICKED ) {
  33. wref *r = (wref*)GetProp((HWND)lparam,PREF);
  34. if( r && r->callb ) hl_dyn_call(r->callb,NULL,0);
  35. }
  36. break;
  37. }
  38. return DefWindowProc(hwnd,msg,wparam,lparam);
  39. }
  40. HL_PRIM void HL_NAME(ui_init)() {
  41. WNDCLASSEX wcl;
  42. HINSTANCE hinst = GetModuleHandle(NULL);
  43. memset(&wcl,0,sizeof(wcl));
  44. wcl.cbSize = sizeof(WNDCLASSEX);
  45. wcl.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
  46. wcl.lpfnWndProc = WindowProc;
  47. wcl.cbClsExtra = 0;
  48. wcl.cbWndExtra = 0;
  49. wcl.hInstance = hinst;
  50. wcl.hIcon = NULL;
  51. wcl.hCursor = LoadCursor(NULL, IDC_ARROW);
  52. wcl.hbrBackground = (HBRUSH)(COLOR_BTNFACE+1);
  53. wcl.lpszMenuName = USTR("");
  54. wcl.lpszClassName = CLASS_NAME;
  55. wcl.hIconSm = 0;
  56. RegisterClassEx(&wcl);
  57. LoadLibrary(USTR("RICHED32.DLL"));
  58. }
  59. HL_PRIM int HL_NAME(ui_dialog)( const uchar *title, const uchar *message, int flags ) {
  60. int ret;
  61. hl_blocking(true);
  62. ret = MessageBoxW(NULL,message,title,((flags & 1)?MB_YESNO:MB_OK) | ((flags & 2)?MB_ICONERROR:MB_ICONINFORMATION) ) == IDYES;
  63. hl_blocking(false);
  64. return ret;
  65. }
  66. static HFONT font = NULL;
  67. HL_PRIM wref *HL_NAME(ui_winlog_new)( const uchar *title, int width, int height ) {
  68. HWND wnd, text;
  69. RECT rc;
  70. RECT dtop;
  71. DWORD style = WS_SYSMENU | WS_OVERLAPPED | WS_CAPTION;
  72. DWORD exstyle = 0;
  73. wref *ref;
  74. // SIZE
  75. rc.left = 0;
  76. rc.right = width;
  77. rc.top = 0;
  78. rc.bottom = height;
  79. AdjustWindowRectEx(&rc, style, FALSE, exstyle);
  80. GetWindowRect(GetDesktopWindow(),&dtop);
  81. // WINDOW
  82. wnd = CreateWindowEx(
  83. exstyle,
  84. CLASS_NAME,
  85. title,
  86. style,
  87. (dtop.right - rc.right) / 2,
  88. (dtop.bottom - rc.bottom) / 2,
  89. rc.right - rc.left,
  90. rc.bottom - rc.top,
  91. GetActiveWindow(),
  92. NULL,
  93. GetModuleHandle(NULL),
  94. NULL
  95. );
  96. // FONT
  97. if( font == NULL ) {
  98. LOGFONT f;
  99. f.lfHeight = -8;
  100. f.lfWidth = 0;
  101. f.lfEscapement = 0;
  102. f.lfOrientation = 0;
  103. f.lfWeight = FW_NORMAL;
  104. f.lfItalic = FALSE;
  105. f.lfUnderline = FALSE;
  106. f.lfStrikeOut = FALSE;
  107. f.lfCharSet = DEFAULT_CHARSET;
  108. f.lfOutPrecision = OUT_DEFAULT_PRECIS;
  109. f.lfClipPrecision = 0;
  110. f.lfQuality = DEFAULT_QUALITY;
  111. f.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
  112. wcscpy(f.lfFaceName,USTR("MS Sans Serif"));
  113. font = CreateFontIndirect(&f);
  114. }
  115. // TEXT
  116. text = CreateWindowEx(WS_EX_CLIENTEDGE,USTR("RICHEDIT20A"),USTR(""),ES_MULTILINE | ES_DISABLENOSCROLL | ES_READONLY | WS_VSCROLL | WS_VISIBLE | WS_CHILD,5,5,width - 10,height - 50,wnd,NULL,NULL,NULL);
  117. SendMessage(text,WM_SETFONT,(WPARAM)font,TRUE);
  118. SetProp(wnd,PTEXT,text);
  119. SetTimer(wnd,0,1000,NULL); // prevent lock in ui_loop
  120. ShowWindow(wnd,SW_SHOW);
  121. ref = alloc_ref(wnd);
  122. ref->width = width;
  123. ref->height = height;
  124. return ref;
  125. }
  126. HL_PRIM wref *HL_NAME(ui_button_new)( wref *w, const uchar *txt, vclosure *callb ) {
  127. HWND but = CreateWindowEx(0,USTR("BUTTON"),USTR(""),WS_VISIBLE | WS_CHILD,w->width - 80,w->height - 30,75,25,w->h,NULL,NULL,NULL);
  128. wref *ref = alloc_ref(but);
  129. w->width -= 80;
  130. ref->callb = callb;
  131. SendMessage(but,WM_SETFONT,(WPARAM)font,TRUE);
  132. SetWindowText(but,txt);
  133. return ref;
  134. }
  135. HL_PRIM void HL_NAME(ui_winlog_set_text)( wref *w, const uchar *txt, bool autoScroll ) {
  136. HWND text = (HWND)GetProp(w->h,PTEXT);
  137. DWORD a,b;
  138. SCROLLINFO sinf;
  139. POINT pt;
  140. sinf.cbSize = sizeof(sinf);
  141. sinf.fMask = SIF_RANGE | SIF_POS | SIF_PAGE;
  142. GetScrollInfo(text,SB_VERT,&sinf);
  143. SendMessage(text,EM_GETSCROLLPOS,0,(LPARAM)&pt);
  144. SendMessage(text,EM_GETSEL,(WPARAM)&a,(LPARAM)&b);
  145. SetWindowText(text,txt);
  146. SendMessage(text,EM_SETSEL,a,b);
  147. if( autoScroll ) {
  148. if( sinf.nPos + sinf.nPage == sinf.nMax || sinf.nMax == 1 ) {
  149. GetScrollInfo(text,SB_VERT,&sinf);
  150. pt.y = sinf.nMax - sinf.nPage;
  151. }
  152. SendMessage(text,EM_SETSCROLLPOS,0,(LPARAM)&pt);
  153. }
  154. }
  155. HL_PRIM void HL_NAME(ui_win_set_text)( wref *w, const uchar *txt ) {
  156. SetWindowText(w->h,txt);
  157. }
  158. HL_PRIM void HL_NAME(ui_win_set_enable)( wref *w, bool enable ) {
  159. EnableWindow(w->h,enable);
  160. }
  161. HL_PRIM void HL_NAME(ui_win_destroy)( wref *w ) {
  162. DestroyWindow(w->h);
  163. }
  164. HL_PRIM int HL_NAME(ui_loop)( bool blocking ) {
  165. MSG msg;
  166. if( blocking )
  167. GetMessage(&msg,NULL,0,0);
  168. else if( !PeekMessage(&msg,NULL,0,0,PM_REMOVE) )
  169. return 0;
  170. TranslateMessage(&msg);
  171. DispatchMessage(&msg);
  172. if( msg.message == WM_QUIT )
  173. return 2;
  174. return 1;
  175. }
  176. HL_PRIM void HL_NAME(ui_stop_loop)() {
  177. PostQuitMessage(0);
  178. }
  179. typedef struct {
  180. hl_thread *thread;
  181. DWORD original;
  182. void *callback;
  183. double timeout;
  184. int ticks;
  185. bool pause;
  186. } vsentinel;
  187. static void sentinel_loop( vsentinel *s ) {
  188. int time_ms = (int)((s->timeout * 1000.) / 16.);
  189. HANDLE h = OpenThread(THREAD_ALL_ACCESS,FALSE,s->original);
  190. CONTEXT regs;
  191. regs.ContextFlags = CONTEXT_FULL;
  192. while( true ) {
  193. int k = 0;
  194. int tick = s->ticks;
  195. while( true ) {
  196. Sleep(time_ms);
  197. if( tick != s->ticks || s->pause ) break;
  198. if( hl_is_blocking() ) continue;
  199. k++;
  200. if( k == 16 ) {
  201. if( hl_detect_debugger() ) {
  202. k = 0;
  203. continue;
  204. }
  205. // pause
  206. SuspendThread(h);
  207. GetThreadContext(h,&regs);
  208. // simulate a call
  209. # ifdef HL_64
  210. *--(int_val*)regs.Rsp = regs.Rip;
  211. *--(int_val*)regs.Rsp = regs.Rsp;
  212. regs.Rip = (int_val)s->callback;
  213. # else
  214. *--(int_val*)regs.Esp = regs.Eip;
  215. *--(int_val*)regs.Esp = regs.Esp;
  216. regs.Eip = (int_val)s->callback;
  217. # endif
  218. // resume
  219. SetThreadContext(h,&regs);
  220. ResumeThread(h);
  221. break;
  222. }
  223. }
  224. }
  225. }
  226. HL_PRIM vsentinel *HL_NAME(ui_start_sentinel)( double timeout, vclosure *c ) {
  227. vsentinel *s = (vsentinel*)malloc(sizeof(vsentinel));
  228. if( c->hasValue ) hl_error("Cannot set sentinel on closure callback");
  229. # ifdef HL_DEBUG
  230. timeout *= 2;
  231. # endif
  232. s->timeout = timeout;
  233. s->ticks = 0;
  234. s->pause = false;
  235. s->original = GetCurrentThreadId();
  236. s->callback = c->fun;
  237. # ifdef HL_THREADS
  238. s->thread = hl_thread_start(sentinel_loop,s,false);
  239. # endif
  240. return s;
  241. }
  242. HL_PRIM void HL_NAME(ui_sentinel_tick)( vsentinel *s ) {
  243. s->ticks++;
  244. }
  245. HL_PRIM void HL_NAME(ui_sentinel_pause)( vsentinel *s, bool pause ) {
  246. s->pause = pause;
  247. }
  248. HL_PRIM bool HL_NAME(ui_sentinel_is_paused)( vsentinel *s ) {
  249. return s->pause;
  250. }
  251. HL_PRIM void HL_NAME(ui_close_console)() {
  252. FreeConsole();
  253. }
  254. HL_PRIM vbyte *HL_NAME(ui_choose_file)( bool forSave, vdynamic *options ) {
  255. wref *win = (wref*)hl_dyn_getp(options,hl_hash_utf8("window"), &hlt_abstract);
  256. varray *filters = (varray*)hl_dyn_getp(options,hl_hash_utf8("filters"),&hlt_array);
  257. wchar_t *fileName = (wchar_t*)hl_dyn_getp(options,hl_hash_utf8("fileName"),&hlt_bytes);
  258. OPENFILENAME op;
  259. wchar_t filterStr[1024];
  260. wchar_t outputFile[1024] = {0};
  261. ZeroMemory(&op, sizeof(op));
  262. op.lStructSize = sizeof(op);
  263. op.hwndOwner = win ? win->h : NULL;
  264. if( filters && filters->size > 0 ) {
  265. int i, pos = 0;
  266. for(i=0;i<filters->size;i++) {
  267. wchar_t *str = hl_aptr(filters,wchar_t*)[i];
  268. int len = (int)wcslen(str);
  269. if( pos + len > 1024 ) return false;
  270. memcpy(filterStr + pos, str, (len + 1) << 1);
  271. pos += len + 1;
  272. }
  273. filterStr[pos] = 0;
  274. op.lpstrFilter = filterStr;
  275. op.nFilterIndex = hl_dyn_geti(options,hl_hash_utf8("filterIndex"),&hlt_i32) + 1; // 1 based
  276. }
  277. if( fileName )
  278. memcpy(outputFile, fileName, (wcslen(fileName)+1) * 2 );
  279. op.lpstrFile = outputFile;
  280. op.nMaxFile = 1024;
  281. op.lpstrInitialDir = hl_dyn_getp(options,hl_hash_utf8("directory"),&hlt_bytes);
  282. op.lpstrTitle = hl_dyn_getp(options,hl_hash_utf8("title"),&hlt_bytes);
  283. op.Flags |= OFN_NOCHANGEDIR;
  284. if( forSave ) {
  285. op.Flags |= OFN_OVERWRITEPROMPT;
  286. if( !GetSaveFileName(&op) )
  287. return NULL;
  288. } else {
  289. op.Flags |= OFN_CREATEPROMPT;
  290. if( !GetOpenFileName(&op) )
  291. return NULL;
  292. }
  293. return hl_copy_bytes((vbyte*)outputFile, (int)(wcslen(outputFile)+1)*2);
  294. }
  295. HL_PRIM bool HL_NAME(ui_set_clipboard_text)(char* text) {
  296. if (!OpenClipboard(NULL))
  297. return false;
  298. if (!EmptyClipboard()) {
  299. CloseClipboard();
  300. return false;
  301. }
  302. int len = (int) strlen(text);
  303. HGLOBAL g = GlobalAlloc(0, (len + 1) * sizeof(TCHAR));
  304. if (g == NULL) {
  305. CloseClipboard();
  306. return false;
  307. }
  308. char* chr = GlobalLock(g);
  309. memcpy(chr, text, len);
  310. chr[len] = '\0';
  311. GlobalUnlock(g);
  312. HANDLE h = SetClipboardData(CF_TEXT, g);
  313. CloseClipboard();
  314. return h != NULL;
  315. }
  316. HL_PRIM byte* HL_NAME(ui_get_clipboard_text)() {
  317. if (!OpenClipboard(NULL))
  318. return NULL;
  319. HANDLE d = GetClipboardData(CF_TEXT);
  320. if (d == NULL) {
  321. CloseClipboard();
  322. return NULL;
  323. }
  324. char* chr = (char*) GlobalLock(d);
  325. if (chr == NULL) {
  326. CloseClipboard();
  327. return NULL;
  328. }
  329. vbyte* b = hl_copy_bytes(chr, (int) strlen(chr) + 1);
  330. GlobalUnlock(d);
  331. CloseClipboard();
  332. return b;
  333. }
  334. #define _WIN _ABSTRACT(ui_window)
  335. #define _SENTINEL _ABSTRACT(ui_sentinel)
  336. DEFINE_PRIM(_VOID, ui_init, _NO_ARG);
  337. DEFINE_PRIM(_I32, ui_dialog, _BYTES _BYTES _I32);
  338. DEFINE_PRIM(_WIN, ui_winlog_new, _BYTES _I32 _I32);
  339. DEFINE_PRIM(_WIN, ui_button_new, _WIN _BYTES _FUN(_VOID,_NO_ARG));
  340. DEFINE_PRIM(_VOID, ui_winlog_set_text, _WIN _BYTES _BOOL);
  341. DEFINE_PRIM(_VOID, ui_win_set_text, _WIN _BYTES);
  342. DEFINE_PRIM(_VOID, ui_win_set_enable, _WIN _BOOL);
  343. DEFINE_PRIM(_VOID, ui_win_destroy, _WIN);
  344. DEFINE_PRIM(_I32, ui_loop, _BOOL);
  345. DEFINE_PRIM(_VOID, ui_stop_loop, _NO_ARG);
  346. DEFINE_PRIM(_VOID, ui_close_console, _NO_ARG);
  347. DEFINE_PRIM(_SENTINEL, ui_start_sentinel, _F64 _FUN(_VOID,_NO_ARG));
  348. DEFINE_PRIM(_VOID, ui_sentinel_tick, _SENTINEL);
  349. DEFINE_PRIM(_VOID, ui_sentinel_pause, _SENTINEL _BOOL);
  350. DEFINE_PRIM(_BOOL, ui_sentinel_is_paused, _SENTINEL);
  351. DEFINE_PRIM(_BYTES, ui_choose_file, _BOOL _DYN);
  352. DEFINE_PRIM(_BOOL, ui_set_clipboard_text, _BYTES);
  353. DEFINE_PRIM(_BYTES, ui_get_clipboard_text, _NO_ARG);