4 #include "../swell/swell.h"
6 #define CURSES_INSTANCE ___ERRROR_____
8 #include "../wdltypes.h"
9 #include "../wdlutf8.h"
16 #define CURSOR_BLINK_TIMER_MS 400
17 #define CURSOR_BLINK_TIMER 2
18 #define CURSOR_BLINK_TIMER_ZEROEVERY 3
20 #define WIN32CURSES_CLASS_NAME "WDLCursesWindow"
22 static void doFontCalc(win32CursesCtx
*, HDC
);
23 static void reInitializeContext(win32CursesCtx
*ctx
);
25 static void m_InvalidateArea(win32CursesCtx
*ctx
, int sx
, int sy
, int ex
, int ey
)
31 if (!ctx
->m_hwnd
|| (ctx
->need_redraw
&4)) return;
34 r
.left
=sx
*ctx
->m_font_w
;
35 r
.top
=sy
*ctx
->m_font_h
;
36 r
.right
=ex
*ctx
->m_font_w
;
37 r
.bottom
=ey
*ctx
->m_font_h
;
38 InvalidateRect(ctx
->m_hwnd
,&r
,FALSE
);
41 void __curses_invalidatefull(win32CursesCtx
*inst
, bool finish
)
43 if (inst
&& inst
->m_hwnd
)
47 if (inst
->need_redraw
&4)
49 inst
->need_redraw
&=~4;
50 InvalidateRect(inst
->m_hwnd
,NULL
,FALSE
);
58 void __addnstr(win32CursesCtx
*ctx
, const char *str
,int n
)
60 if (!ctx
||n
==0) return;
62 const int sx
=ctx
->m_cursor_x
, sy
=ctx
->m_cursor_y
, cols
=ctx
->cols
;
63 if (!ctx
->m_framebuffer
|| sy
< 0 || sy
>= ctx
->lines
|| sx
< 0 || sx
>= cols
) return;
64 win32CursesFB
*p
=ctx
->m_framebuffer
+ (sx
+ sy
*cols
);
66 const unsigned char attr
= ctx
->m_cur_attr
;
69 int c
,sz
=wdl_utf8_parsechar(str
,&c
);
74 if (n
> 0 && (n
-=sz
)<0) n
= 0;
76 if (++ctx
->m_cursor_x
>= cols
) break;
78 m_InvalidateArea(ctx
,sx
,sy
,sy
< ctx
->m_cursor_y
? cols
: ctx
->m_cursor_x
+1,ctx
->m_cursor_y
+1);
81 void __addnstr_w(win32CursesCtx
*ctx
, const wchar_t *str
,int n
)
83 if (!ctx
||n
==0) return;
85 const int sx
=ctx
->m_cursor_x
, sy
=ctx
->m_cursor_y
, cols
=ctx
->cols
;
86 if (!ctx
->m_framebuffer
|| sy
< 0 || sy
>= ctx
->lines
|| sx
< 0 || sx
>= cols
) return;
87 win32CursesFB
*p
=ctx
->m_framebuffer
+ (sx
+ sy
*cols
);
89 const unsigned char attr
= ctx
->m_cur_attr
;
95 if (++ctx
->m_cursor_x
>= cols
) break;
97 m_InvalidateArea(ctx
,sx
,sy
,sy
< ctx
->m_cursor_y
? cols
: ctx
->m_cursor_x
+1,ctx
->m_cursor_y
+1);
100 void __clrtoeol(win32CursesCtx
*ctx
)
104 if (ctx
->m_cursor_x
<0)ctx
->m_cursor_x
=0;
105 int n
= ctx
->cols
- ctx
->m_cursor_x
;
106 if (!ctx
->m_framebuffer
|| ctx
->m_cursor_y
< 0 || ctx
->m_cursor_y
>= ctx
->lines
|| n
< 1) return;
107 win32CursesFB
*p
=ctx
->m_framebuffer
+ (ctx
->m_cursor_x
+ ctx
->m_cursor_y
*ctx
->cols
);
108 int sx
=ctx
->m_cursor_x
;
112 p
->attr
=ctx
->m_cur_erase_attr
;
115 m_InvalidateArea(ctx
,sx
,ctx
->m_cursor_y
,ctx
->cols
,ctx
->m_cursor_y
+1);
118 void __curses_erase(win32CursesCtx
*ctx
)
123 ctx
->m_cur_erase_attr
=0;
124 if (ctx
->m_framebuffer
) memset(ctx
->m_framebuffer
,0,ctx
->cols
*ctx
->lines
*sizeof(*ctx
->m_framebuffer
));
127 m_InvalidateArea(ctx
,0,0,ctx
->cols
,ctx
->lines
);
130 void __move(win32CursesCtx
*ctx
, int y
, int x
, int noupdest
)
134 m_InvalidateArea(ctx
,ctx
->m_cursor_x
,ctx
->m_cursor_y
,ctx
->m_cursor_x
+1,ctx
->m_cursor_y
+1);
135 ctx
->m_cursor_x
=wdl_max(x
,0);
136 ctx
->m_cursor_y
=wdl_max(y
,0);
137 if (!noupdest
) m_InvalidateArea(ctx
,ctx
->m_cursor_x
,ctx
->m_cursor_y
,ctx
->m_cursor_x
+1,ctx
->m_cursor_y
+1);
141 void __init_pair(win32CursesCtx
*ctx
, int pair
, int fcolor
, int bcolor
)
143 if (!ctx
|| pair
< 0 || pair
>= COLOR_PAIRS
) return;
145 pair
=COLOR_PAIR(pair
);
146 fcolor
&= RGB(255,255,255);
147 bcolor
&= RGB(255,255,255);
149 ctx
->colortab
[pair
][0]=fcolor
;
150 ctx
->colortab
[pair
][1]=bcolor
;
152 if (fcolor
& 0xff) fcolor
|=0xff;
153 if (fcolor
& 0xff00) fcolor
|=0xff00;
154 if (fcolor
& 0xff0000) fcolor
|=0xff0000;
155 ctx
->colortab
[pair
|A_BOLD
][0]=fcolor
;
156 ctx
->colortab
[pair
|A_BOLD
][1]=bcolor
;
159 int *curses_win32_global_user_colortab
;
161 static LRESULT
xlateKey(int msg
, WPARAM wParam
, LPARAM lParam
)
163 if (msg
== WM_KEYDOWN
)
166 if (lParam
& FVIRTKEY
)
170 case VK_HOME
: return KEY_HOME
;
171 case VK_UP
: return KEY_UP
;
172 case VK_PRIOR
: return KEY_PPAGE
;
173 case VK_LEFT
: return KEY_LEFT
;
174 case VK_RIGHT
: return KEY_RIGHT
;
175 case VK_END
: return KEY_END
;
176 case VK_DOWN
: return KEY_DOWN
;
177 case VK_NEXT
: return KEY_NPAGE
;
178 case VK_INSERT
: return KEY_IC
;
179 case VK_DELETE
: return KEY_DC
;
180 case VK_F1
: return KEY_F1
;
181 case VK_F2
: return KEY_F2
;
182 case VK_F3
: return KEY_F3
;
183 case VK_F4
: return KEY_F4
;
184 case VK_F5
: return KEY_F5
;
185 case VK_F6
: return KEY_F6
;
186 case VK_F7
: return KEY_F7
;
187 case VK_F8
: return KEY_F8
;
188 case VK_F9
: return KEY_F9
;
189 case VK_F10
: return KEY_F10
;
190 case VK_F11
: return KEY_F11
;
191 case VK_F12
: return KEY_F12
;
193 case VK_SUBTRACT
: return '-'; // numpad -
194 case VK_ADD
: return '+';
195 case VK_MULTIPLY
: return '*';
196 case VK_DIVIDE
: return '/';
197 case VK_DECIMAL
: return '.';
198 case VK_NUMPAD0
: return '0';
199 case VK_NUMPAD1
: return '1';
200 case VK_NUMPAD2
: return '2';
201 case VK_NUMPAD3
: return '3';
202 case VK_NUMPAD4
: return '4';
203 case VK_NUMPAD5
: return '5';
204 case VK_NUMPAD6
: return '6';
205 case VK_NUMPAD7
: return '7';
206 case VK_NUMPAD8
: return '8';
207 case VK_NUMPAD9
: return '9';
208 case (32768|VK_RETURN
): return VK_RETURN
;
214 case VK_RETURN
: case VK_BACK
: case VK_TAB
: case VK_ESCAPE
: return wParam
;
215 case VK_CONTROL
: break;
218 if(GetAsyncKeyState(VK_CONTROL
)&0x8000)
220 if (wParam
>='a' && wParam
<='z')
225 if (wParam
>='A' && wParam
<='Z')
230 if ((wParam
&~0x80) == '[') return 27;
231 if ((wParam
&~0x80) == ']') return 29;
236 #ifdef _WIN32 // todo : fix for nonwin32
239 if(wParam
>=32) return wParam
;
245 if (!(GetAsyncKeyState(VK_SHIFT
)&0x8000))
247 if (wParam
>='A' && wParam
<='Z')
249 if ((GetAsyncKeyState(VK_LWIN
)&0x8000)) wParam
-= 'A'-1;
262 static void m_reinit_framebuffer(win32CursesCtx
*ctx
)
266 doFontCalc(ctx
,NULL
);
269 GetClientRect(ctx
->m_hwnd
,&r
);
271 ctx
->lines
=r
.bottom
/ ctx
->m_font_h
;
272 ctx
->cols
=r
.right
/ ctx
->m_font_w
;
273 if (ctx
->lines
<1) ctx
->lines
=1;
274 if (ctx
->cols
<1) ctx
->cols
=1;
277 free(ctx
->m_framebuffer
);
278 ctx
->m_framebuffer
=(win32CursesFB
*)malloc(sizeof(win32CursesFB
)*ctx
->lines
*ctx
->cols
);
279 if (ctx
->m_framebuffer
) memset(ctx
->m_framebuffer
, 0,sizeof(win32CursesFB
)*ctx
->lines
*ctx
->cols
);
281 const int *tab
= ctx
->user_colortab
? ctx
->user_colortab
: curses_win32_global_user_colortab
;
284 ctx
->user_colortab_lastfirstval
=tab
[0];
285 for (int x
=0;x
<COLOR_PAIRS
;x
++) __init_pair(ctx
,x
,tab
[x
*2],tab
[x
*2+1]);
288 #ifndef WM_MOUSEWHEEL
289 #define WM_MOUSEWHEEL 0x20A
292 LRESULT CALLBACK
cursesWindowProc(HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
294 win32CursesCtx
*ctx
= (win32CursesCtx
*)GetWindowLongPtr(hwnd
,GWLP_USERDATA
);
298 static int Scroll_Message
;
301 Scroll_Message
= (int)RegisterWindowMessage("MSWHEEL_ROLLMSG");
302 if (!Scroll_Message
) Scroll_Message
=-1;
304 if (Scroll_Message
> 0 && uMsg
== (UINT
)Scroll_Message
)
311 if (ctx
) switch (uMsg
)
316 case WM_CHAR
: case WM_KEYDOWN
:
321 wParam
= SWELL_MacKeyToWindowsKeyEx(NULL
,&f
,1);
327 const int a
=(int)xlateKey(uMsg
,wParam
,lParam
);
330 const int qsize
= sizeof(ctx
->m_kb_queue
)/sizeof(ctx
->m_kb_queue
[0]);
331 if (ctx
->m_kb_queue_valid
>=qsize
) // queue full, dump an old event!
333 ctx
->m_kb_queue_valid
--;
334 ctx
->m_kb_queue_pos
++;
337 ctx
->m_kb_queue
[(ctx
->m_kb_queue_pos
+ ctx
->m_kb_queue_valid
++) & (qsize
-1)] = a
;
342 case WM_GETMINMAXINFO
:
344 LPMINMAXINFO p
=(LPMINMAXINFO
)lParam
;
345 p
->ptMinTrackSize
.x
= 160;
346 p
->ptMinTrackSize
.y
= 120;
350 if (wParam
!= SIZE_MINIMIZED
)
352 m_reinit_framebuffer(ctx
);
353 if (ctx
->do_update
) ctx
->do_update(ctx
);
354 else ctx
->need_redraw
|=1;
362 case WM_CAPTURECHANGED
:
365 case WM_LBUTTONDBLCLK
:
366 case WM_RBUTTONDBLCLK
:
367 case WM_MBUTTONDBLCLK
:
368 if (ctx
&& ctx
->fontsize_ptr
&& uMsg
== WM_MOUSEWHEEL
&& (GetAsyncKeyState(VK_CONTROL
)&0x8000))
370 int a
= (int)(short)HIWORD(wParam
);
371 if (a
<0 && *ctx
->fontsize_ptr
> 4) (*ctx
->fontsize_ptr
)--;
372 else if (a
>=0 && *ctx
->fontsize_ptr
< 64) (*ctx
->fontsize_ptr
)++;
377 DeleteObject(ctx
->mOurFont
);
380 reInitializeContext(ctx
);
381 m_reinit_framebuffer(ctx
);
382 if (ctx
->do_update
) ctx
->do_update(ctx
);
383 else ctx
->need_redraw
|=1;
387 if (ctx
&& ctx
->onMouseMessage
) return ctx
->onMouseMessage(ctx
->user_data
,hwnd
,uMsg
,wParam
,lParam
);
391 if (ctx
->m_font_w
&& ctx
->m_font_h
)
395 ScreenToClient(hwnd
, &p
);
396 p
.x
/= ctx
->m_font_w
;
397 p
.y
/= ctx
->m_font_h
;
399 const int topmarg
=ctx
->scrollbar_topmargin
;
400 const int bottmarg
=ctx
->scrollbar_botmargin
;
401 int paney
[2] = { topmarg
, ctx
->div_y
+topmarg
+1 };
402 int paneh
[2] = { ctx
->div_y
, ctx
->lines
-ctx
->div_y
-topmarg
-bottmarg
-1 };
403 bool has_panes
=(ctx
->div_y
< ctx
->lines
-topmarg
-bottmarg
-1);
404 int scrollw
[2] = { ctx
->cols
-ctx
->drew_scrollbar
[0], ctx
->cols
-ctx
->drew_scrollbar
[1] };
406 if (has_panes
&& p
.y
>= ctx
->div_y
+1 && p
.y
< ctx
->div_y
+2) SetCursor(LoadCursor(NULL
, IDC_SIZENS
));
407 else if (p
.y
< 1 || p
.y
>= ctx
->lines
-1) SetCursor(LoadCursor(NULL
, IDC_ARROW
));
408 else if (p
.y
>= paney
[0] && p
.y
< paney
[0]+paneh
[0] && p
.x
>= scrollw
[0]) SetCursor(LoadCursor(NULL
, IDC_ARROW
));
409 else if (p
.y
>= paney
[1] && p
.y
< paney
[1]+paneh
[1] && p
.x
>= scrollw
[1]) SetCursor(LoadCursor(NULL
, IDC_ARROW
));
410 else SetCursor(LoadCursor(NULL
, IDC_IBEAM
));
418 return DLGC_WANTALLKEYS
;
423 if (wParam
==CURSOR_BLINK_TIMER
&& ctx
)
425 const char la
= ctx
->cursor_state
;
426 ctx
->cursor_state
= (ctx
->cursor_state
+1)%CURSOR_BLINK_TIMER_ZEROEVERY
;
428 const int *tab
= ctx
->user_colortab
? ctx
->user_colortab
: curses_win32_global_user_colortab
;
429 if (tab
&& tab
[0] != ctx
->user_colortab_lastfirstval
)
431 m_reinit_framebuffer(ctx
);
432 if (ctx
->do_update
) ctx
->do_update(ctx
);
433 else ctx
->need_redraw
|=1;
435 else if (!!ctx
->cursor_state
!= !!la
)
437 __move(ctx
,ctx
->m_cursor_y
,ctx
->m_cursor_x
,1);// refresh cursor
443 // this only is called on osx or from standalone, it seems, since on win32 ctx isnt set up yet
446 m_reinit_framebuffer(ctx
);
449 SetTimer(hwnd
,CURSOR_BLINK_TIMER
,CURSOR_BLINK_TIMER_MS
,NULL
);
457 HDC hdc
=BeginPaint(hwnd
,&ps
);
460 const int topmarg
=ctx
->scrollbar_topmargin
;
461 const int bottmarg
=ctx
->scrollbar_botmargin
;
462 int paney
[2] = { topmarg
, ctx
->div_y
+topmarg
+1 };
463 int paneh
[2] = { ctx
->div_y
, ctx
->lines
-ctx
->div_y
-topmarg
-bottmarg
-1 };
464 bool has_panes
=(ctx
->div_y
< ctx
->lines
-topmarg
-bottmarg
-1);
465 if (!has_panes
) paneh
[0]++;
467 ctx
->drew_scrollbar
[0]=ctx
->drew_scrollbar
[1]=0;
468 if (ctx
->want_scrollbar
> 0)
471 GetClientRect(hwnd
, &cr
);
472 double cf
=(double)cr
.right
/(double)ctx
->m_font_w
-(double)ctx
->cols
;
473 int ws
=ctx
->want_scrollbar
;
477 for (i
=0; i
< 2; ++i
)
479 ctx
->scroll_y
[i
]=ctx
->scroll_h
[i
]=0;
480 if (paneh
[i
] > 0 && ctx
->tot_y
> paneh
[i
])
482 ctx
->drew_scrollbar
[i
]=ws
;
483 int ey
=paneh
[i
]*ctx
->m_font_h
;
484 ctx
->scroll_h
[i
]=ey
*paneh
[i
]/ctx
->tot_y
;
485 if (ctx
->scroll_h
[i
] < ctx
->m_font_h
) ctx
->scroll_h
[i
]=ctx
->m_font_h
;
486 ctx
->scroll_y
[i
]=(ey
-ctx
->scroll_h
[i
])*ctx
->offs_y
[i
]/(ctx
->tot_y
-paneh
[i
]);
487 if (ctx
->scroll_y
[i
] < 0) ctx
->scroll_y
[i
]=0;
488 if (ctx
->scroll_y
[i
] > ey
-ctx
->scroll_h
[i
]) ctx
->scroll_y
[i
]=ey
-ctx
->scroll_h
[i
];
494 doFontCalc(ctx
,ps
.hdc
);
496 HGDIOBJ oldf
=SelectObject(hdc
,ctx
->mOurFont
);
500 SetTextAlign(hdc
,TA_TOP
|TA_LEFT
);
502 const win32CursesFB
*ptr
=(const win32CursesFB
*)ctx
->m_framebuffer
;
505 r
.left
/= ctx
->m_font_w
;
506 r
.top
/= ctx
->m_font_h
;
507 r
.bottom
+= ctx
->m_font_h
-1;
508 r
.bottom
/= ctx
->m_font_h
;
509 r
.right
+= ctx
->m_font_w
-1;
510 r
.right
/= ctx
->m_font_w
;
512 if (r
.top
< 0) r
.top
=0;
513 if (r
.bottom
> ctx
->lines
) r
.bottom
=ctx
->lines
;
514 if (r
.left
< 0) r
.left
=0;
515 if (r
.right
> ctx
->cols
) r
.right
=ctx
->cols
;
517 ypos
= r
.top
* ctx
->m_font_h
;
518 ptr
+= (r
.top
* ctx
->cols
);
521 HBRUSH bgbrushes
[COLOR_PAIRS
<< NUM_ATTRBITS
];
522 for(y
=0;y
<sizeof(bgbrushes
)/sizeof(bgbrushes
[0]);y
++) bgbrushes
[y
] = CreateSolidBrush(ctx
->colortab
[y
][1]);
524 char cstate
=ctx
->cursor_state
;
525 if (ctx
->m_cursor_y
!= ctx
->cursor_state_ly
|| ctx
->m_cursor_x
!= ctx
->cursor_state_lx
)
527 ctx
->cursor_state_lx
=ctx
->m_cursor_x
;
528 ctx
->cursor_state_ly
=ctx
->m_cursor_y
;
533 if (ctx
->m_framebuffer
) for (y
= r
.top
; y
< r
.bottom
; y
++, ypos
+=ctx
->m_font_h
, ptr
+= ctx
->cols
)
535 int x
= r
.left
,xpos
= r
.left
* ctx
->m_font_w
;
537 const win32CursesFB
*p
= ptr
+ r
.left
;
542 if (y
>= paney
[0] && y
< paney
[0]+paneh
[0])
544 right
=wdl_min(right
, ctx
->cols
-ctx
->drew_scrollbar
[0]);
546 else if (y
>= paney
[1] && y
< paney
[1]+paneh
[1])
548 right
=wdl_min(right
, ctx
->cols
-ctx
->drew_scrollbar
[1]);
551 for (;; x
++, xpos
+=ctx
->m_font_w
, p
++)
562 const bool isCursor
= cstate
&& y
== ctx
->m_cursor_y
&& x
== ctx
->m_cursor_x
;
563 const bool isNotBlank
= c
>=128 || (isprint(c
) && !isspace(c
));
565 if (defer_blanks
> 0 && (isNotBlank
|| isCursor
|| attr
!= lattr
|| x
>=right
))
567 RECT tr
={xpos
- defer_blanks
*ctx
->m_font_w
,ypos
,xpos
,ypos
+ctx
->m_font_h
};
568 FillRect(hdc
,&tr
,bgbrushes
[lattr
&((COLOR_PAIRS
<< NUM_ATTRBITS
)-1)]);
574 if (isCursor
&& ctx
->cursor_type
== WIN32_CURSES_CURSOR_TYPE_BLOCK
)
576 SetTextColor(hdc
,ctx
->colortab
[attr
&((COLOR_PAIRS
<< NUM_ATTRBITS
)-1)][1]);
577 SetBkColor(hdc
,ctx
->colortab
[attr
&((COLOR_PAIRS
<< NUM_ATTRBITS
)-1)][0]);
583 SetTextColor(hdc
,ctx
->colortab
[attr
&((COLOR_PAIRS
<< NUM_ATTRBITS
)-1)][0]);
584 SetBkColor(hdc
,ctx
->colortab
[attr
&((COLOR_PAIRS
<< NUM_ATTRBITS
)-1)][1]);
588 if (isNotBlank
||isCursor
)
592 TextOutW(hdc
,txpos
,ypos
,isNotBlank
? &c
: L
" ",1);
594 const int max_charw
= ctx
->m_font_w
, max_charh
= ctx
->m_font_h
;
595 RECT tr
={xpos
,ypos
,xpos
+max_charw
, ypos
+max_charh
};
596 HBRUSH br
=bgbrushes
[attr
&((COLOR_PAIRS
<< NUM_ATTRBITS
)-1)];
597 if (isCursor
&& ctx
->cursor_type
== WIN32_CURSES_CURSOR_TYPE_BLOCK
)
599 br
= CreateSolidBrush(ctx
->colortab
[attr
&((COLOR_PAIRS
<< NUM_ATTRBITS
)-1)][0]);
600 FillRect(hdc
,&tr
,br
);
605 FillRect(hdc
,&tr
,br
);
610 WDL_MakeUTFChar(tmp
,c
,sizeof(tmp
));
614 tmp
[0]=isNotBlank
? (char)c
: ' ';
617 DrawText(hdc
,tmp
,-1,&tr
,DT_LEFT
|DT_TOP
|DT_NOPREFIX
|DT_NOCLIP
);
620 if (isCursor
&& ctx
->cursor_type
!= WIN32_CURSES_CURSOR_TYPE_BLOCK
)
622 RECT r
={xpos
,ypos
,xpos
+2,ypos
+ctx
->m_font_h
};
623 if (ctx
->cursor_type
== WIN32_CURSES_CURSOR_TYPE_HORZBAR
)
625 RECT tr
={xpos
,ypos
+ctx
->m_font_h
-2,xpos
+ctx
->m_font_w
,ypos
+ctx
->m_font_h
};
628 HBRUSH br
=CreateSolidBrush(ctx
->colortab
[attr
&((COLOR_PAIRS
<< NUM_ATTRBITS
)-1)][0]);
640 int ex
=ctx
->cols
*ctx
->m_font_w
;
641 int ey
=ctx
->lines
*ctx
->m_font_h
;
643 int anyscrollw
=wdl_max(ctx
->drew_scrollbar
[0], ctx
->drew_scrollbar
[1]);
644 if (anyscrollw
&& updr
.right
>= ex
-anyscrollw
*ctx
->m_font_w
)
646 HBRUSH sb1
=CreateSolidBrush(RGB(128,128,128));
647 HBRUSH sb2
=CreateSolidBrush(RGB(96, 96, 96));
649 for (i
=0; i
< 2; ++i
)
651 if (ctx
->drew_scrollbar
[i
])
653 int scrolly
=paney
[i
]*ctx
->m_font_h
+ctx
->scroll_y
[i
];
654 int scrollh
=ctx
->scroll_h
[i
];
655 RECT tr
= { ex
-ctx
->drew_scrollbar
[i
]*ctx
->m_font_w
, paney
[i
]*ctx
->m_font_h
, updr
.right
, wdl_min(scrolly
, updr
.bottom
) };
656 if (tr
.bottom
> tr
.top
) FillRect(hdc
, &tr
, sb1
);
657 tr
.top
=wdl_max(updr
.top
, scrolly
);
658 tr
.bottom
=wdl_min(updr
.bottom
, scrolly
+scrollh
);
659 if (tr
.bottom
> tr
.top
) FillRect(hdc
, &tr
, sb2
);
660 tr
.top
=wdl_max(updr
.top
,scrolly
+scrollh
);
661 tr
.bottom
=(paney
[i
]+paneh
[i
])*ctx
->m_font_h
;
662 if (tr
.bottom
> tr
.top
) FillRect(hdc
, &tr
, sb1
);
670 if (updr
.right
>= ex
)
672 // draw the scrollbars if they haven't been already drawn
673 if (!ctx
->drew_scrollbar
[0] && updr
.bottom
> paney
[0]*ctx
->m_font_h
&& updr
.top
< (paney
[0]+paneh
[0])*ctx
->m_font_h
)
675 RECT tr
= { ex
, paney
[0]*ctx
->m_font_h
, updr
.right
, (paney
[0]+paneh
[0])*ctx
->m_font_h
};
676 FillRect(hdc
, &tr
, bgbrushes
[0]);
678 if (!ctx
->drew_scrollbar
[1] && updr
.bottom
> paney
[1]*ctx
->m_font_h
&& updr
.top
< (paney
[1]+paneh
[1])*ctx
->m_font_h
)
680 RECT tr
= { ex
, paney
[1]*ctx
->m_font_h
, updr
.right
, (paney
[1]+paneh
[1])*ctx
->m_font_h
};
681 FillRect(hdc
, &tr
, bgbrushes
[0]);
684 // draw line endings of special areas
686 const int div1a
= has_panes
? (paney
[0]+paneh
[0]) : 0;
687 const int div1b
= has_panes
? paney
[1] : 0;
690 const int bm1
= ctx
->lines
-bottmarg
;
691 const int fonth
= ctx
->m_font_h
;
692 for (y
= r
.top
; y
< r
.bottom
; y
++)
694 if (y
< topmarg
|| y
>=bm1
|| (y
<div1b
&& y
>= div1a
))
696 const int attr
= ctx
->m_framebuffer
? ctx
->m_framebuffer
[(y
+1) * ctx
->cols
- 1].attr
: 0; // last attribute of line
698 const int yp
= y
* fonth
;
699 RECT tr
= { wdl_max(ex
,updr
.left
), wdl_max(yp
,updr
.top
), updr
.right
, wdl_min(yp
+fonth
,updr
.bottom
) };
700 FillRect(hdc
, &tr
, bgbrushes
[attr
&((COLOR_PAIRS
<< NUM_ATTRBITS
)-1)]);
705 if (updr
.bottom
> ey
)
707 RECT tr
= { updr
.left
, wdl_max(ey
,updr
.top
), updr
.right
, updr
.bottom
};
708 FillRect(hdc
, &tr
, bgbrushes
[2]);
711 for(y
=0;y
<sizeof(bgbrushes
)/sizeof(bgbrushes
[0]);y
++) DeleteObject(bgbrushes
[y
]);
712 SelectObject(hdc
,oldf
);
720 return DefWindowProc(hwnd
,uMsg
,wParam
,lParam
);
723 static void doFontCalc(win32CursesCtx
*ctx
, HDC hdcIn
)
725 if (!ctx
|| !ctx
->m_hwnd
|| !(ctx
->need_redraw
&2)) return;
728 if (!hdc
) hdc
= GetDC(ctx
->m_hwnd
);
732 ctx
->need_redraw
&=~2;
734 HGDIOBJ oldf
=SelectObject(hdc
,ctx
->mOurFont
);
736 GetTextMetrics(hdc
,&tm
);
737 ctx
->m_font_h
=tm
.tmHeight
;
738 ctx
->m_font_w
=tm
.tmAveCharWidth
;
739 SelectObject(hdc
,oldf
);
741 if (hdc
!= hdcIn
) ReleaseDC(ctx
->m_hwnd
,hdc
);
745 void reInitializeContext(win32CursesCtx
*ctx
)
749 if (!ctx
->mOurFont
) ctx
->mOurFont
= CreateFont(
750 ctx
->fontsize_ptr
? *ctx
->fontsize_ptr
:
770 ANTIALIASED_QUALITY
, //NONANTIALIASED_QUALITY,//DEFAULT_QUALITY,
781 doFontCalc(ctx
,NULL
);
787 void __initscr(win32CursesCtx
*ctx
)
789 #ifdef WDL_IS_FAKE_CURSES
790 if (!curses_win32_global_user_colortab
&& (!ctx
|| !ctx
->user_colortab
))
793 __init_pair(ctx
,0,RGB(192,192,192),RGB(0,0,0));
797 void __endwin(win32CursesCtx
*ctx
)
802 curses_setWindowContext(ctx
->m_hwnd
,0);
803 ctx
->m_kb_queue_valid
=0;
805 free(ctx
->m_framebuffer
);
806 ctx
->m_framebuffer
=0;
807 if (ctx
->mOurFont
) DeleteObject(ctx
->mOurFont
);
813 int curses_getch(win32CursesCtx
*ctx
)
815 if (!ctx
|| !ctx
->m_hwnd
) return ERR
;
818 if (ctx
->want_getch_runmsgpump
>0)
821 if (ctx
->want_getch_runmsgpump
>1)
823 while(!ctx
->m_kb_queue_valid
&& GetMessage(&msg
,NULL
,0,0))
825 TranslateMessage(&msg
);
826 DispatchMessage(&msg
);
829 else while(PeekMessage(&msg
,NULL
,0,0,PM_REMOVE
))
831 TranslateMessage(&msg
);
832 DispatchMessage(&msg
);
837 if (ctx
->m_kb_queue_valid
)
839 const int qsize
= sizeof(ctx
->m_kb_queue
)/sizeof(ctx
->m_kb_queue
[0]);
840 const int a
= ctx
->m_kb_queue
[ctx
->m_kb_queue_pos
& (qsize
-1)];
841 ctx
->m_kb_queue_pos
++;
842 ctx
->m_kb_queue_valid
--;
846 if (ctx
->need_redraw
&1)
848 ctx
->need_redraw
&=~1;
849 InvalidateRect(ctx
->m_hwnd
,NULL
,FALSE
);
856 void curses_setWindowContext(HWND hwnd
, win32CursesCtx
*ctx
)
858 SetWindowLongPtr(hwnd
,GWLP_USERDATA
,(INT_PTR
)ctx
);
862 ctx
->m_kb_queue_valid
=0;
864 free(ctx
->m_framebuffer
);
865 ctx
->m_framebuffer
=0;
867 SetTimer(hwnd
,CURSOR_BLINK_TIMER
,CURSOR_BLINK_TIMER_MS
,NULL
);
868 reInitializeContext(ctx
);
869 m_reinit_framebuffer(ctx
);
870 InvalidateRect(hwnd
,NULL
,FALSE
);
878 void curses_unregisterChildClass(HINSTANCE hInstance
)
882 UnregisterClass(WIN32CURSES_CLASS_NAME
,hInstance
);
886 void curses_registerChildClass(HINSTANCE hInstance
)
891 WNDCLASS wc
={CS_DBLCLKS
,};
892 wc
.lpfnWndProc
= cursesWindowProc
;
893 wc
.hInstance
= hInstance
;
894 wc
.hCursor
= LoadCursor(NULL
,IDC_ARROW
);
895 wc
.lpszClassName
= WIN32CURSES_CLASS_NAME
;
903 HWND
curses_ControlCreator(HWND parent
, const char *cname
, int idx
, const char *classname
, int style
, int x
, int y
, int w
, int h
)
906 if (!strcmp(classname
,WIN32CURSES_CLASS_NAME
))
908 hw
=CreateDialog(NULL
,0,parent
,(DLGPROC
)cursesWindowProc
);
913 SetWindowLong(hw
,GWL_ID
,idx
);
914 SetWindowPos(hw
,HWND_TOP
,x
,y
,w
,h
,SWP_NOZORDER
|SWP_NOACTIVATE
);
915 ShowWindow(hw
,SW_SHOWNA
);
924 HWND
curses_CreateWindow(HINSTANCE hInstance
, win32CursesCtx
*ctx
, const char *title
)
926 if (!ctx
) return NULL
;
928 ctx
->m_hwnd
= CreateWindowEx(0,WIN32CURSES_CLASS_NAME
, title
,WS_CAPTION
|WS_MAXIMIZEBOX
|WS_MINIMIZEBOX
|WS_SIZEBOX
|WS_SYSMENU
,
929 CW_USEDEFAULT
,CW_USEDEFAULT
,640,480,
930 NULL
, NULL
,hInstance
,NULL
);
932 ctx
->m_hwnd
= CreateDialog(NULL
,0,NULL
,(DLGPROC
)cursesWindowProc
);
937 curses_setWindowContext(ctx
->m_hwnd
,ctx
);
938 ShowWindow(ctx
->m_hwnd
,SW_SHOW
);