Windows candidate list support.
Candidate list should now be drawn and function normally.
Tested in XP and 7.
1.1 --- a/src/video/SDL_video.c Tue Nov 23 17:44:10 2010 -0500
1.2 +++ b/src/video/SDL_video.c Tue Nov 23 17:46:47 2010 -0500
1.3 @@ -34,6 +34,11 @@
1.4 #include "../events/SDL_sysevents.h"
1.5 #include "../events/SDL_events_c.h"
1.6
1.7 +#if SDL_VIDEO_DRIVER_WIN32
1.8 +#include "win32/SDL_win32video.h"
1.9 +extern void IME_Present(SDL_VideoData *videodata);
1.10 +#endif
1.11 +
1.12 #if SDL_VIDEO_OPENGL_ES
1.13 #include "SDL_opengles.h"
1.14 #endif /* SDL_VIDEO_OPENGL_ES */
1.15 @@ -2687,6 +2692,9 @@
1.16 if (!renderer || !renderer->RenderPresent) {
1.17 return;
1.18 }
1.19 +#if SDL_VIDEO_DRIVER_WIN32
1.20 + IME_Present((SDL_VideoData *)_this->driverdata);
1.21 +#endif
1.22 renderer->RenderPresent(renderer);
1.23 }
1.24
2.1 --- a/src/video/win32/SDL_win32keyboard.c Tue Nov 23 17:44:10 2010 -0500
2.2 +++ b/src/video/win32/SDL_win32keyboard.c Tue Nov 23 17:46:47 2010 -0500
2.3 @@ -100,6 +100,23 @@
2.4 data->ime_composition[0] = 0;
2.5 data->ime_readingstring[0] = 0;
2.6 data->ime_cursor = 0;
2.7 +
2.8 + data->ime_candlist = SDL_FALSE;
2.9 + SDL_memset(data->ime_candidates, 0, sizeof(data->ime_candidates));
2.10 + data->ime_candcount = 0;
2.11 + data->ime_candref = 0;
2.12 + data->ime_candsel = 0;
2.13 + data->ime_candpgsize = 0;
2.14 + data->ime_candlistindexbase = 0;
2.15 + data->ime_candvertical = SDL_TRUE;
2.16 +
2.17 + data->ime_candtex = NULL;
2.18 + data->ime_dirty = SDL_FALSE;
2.19 + SDL_memset(&data->ime_rect, 0, sizeof(data->ime_rect));
2.20 + SDL_memset(&data->ime_candlistrect, 0, sizeof(data->ime_candlistrect));
2.21 + data->ime_winwidth = 0;
2.22 + data->ime_winheight = 0;
2.23 +
2.24 data->ime_hkl = 0;
2.25 data->ime_himm32 = 0;
2.26 data->GetReadingString = 0;
2.27 @@ -165,6 +182,7 @@
2.28 if (window) {
2.29 HWND hwnd = ((SDL_WindowData *) window->driverdata)->hwnd;
2.30 SDL_VideoData *videodata = (SDL_VideoData *)_this->driverdata;
2.31 + SDL_GetWindowSize(window, &videodata->ime_winwidth, &videodata->ime_winheight);
2.32 IME_Init(videodata, hwnd);
2.33 IME_Enable(videodata, hwnd);
2.34 }
2.35 @@ -185,7 +203,8 @@
2.36 void
2.37 WIN_SetTextInputRect(_THIS, SDL_Rect *rect)
2.38 {
2.39 -
2.40 + SDL_VideoData *videodata = (SDL_VideoData *)_this->driverdata;
2.41 + videodata->ime_rect = *rect;
2.42 }
2.43
2.44 #ifdef __GNUC__
2.45 @@ -196,6 +215,7 @@
2.46 DEFINE_GUID(GUID_TFCAT_TIP_KEYBOARD, 0x34745C63,0xB2F0,0x4784,0x8B,0x67,0x5E,0x12,0xC8,0x70,0x1A,0x31);
2.47 DEFINE_GUID(IID_ITfSource, 0x4EA48A35,0x60AE,0x446F,0x8F,0xD6,0xE6,0xA8,0xD8,0x24,0x59,0xF7);
2.48 DEFINE_GUID(IID_ITfUIElementMgr, 0xEA1EA135,0x19DF,0x11D7,0xA6,0xD2,0x00,0x06,0x5B,0x84,0x43,0x5C);
2.49 +DEFINE_GUID(IID_ITfCandidateListUIElement, 0xEA1EA138,0x19DF,0x11D7,0xA6,0xD2,0x00,0x06,0x5B,0x84,0x43,0x5C);
2.50 DEFINE_GUID(IID_ITfReadingInformationUIElement, 0xEA1EA139,0x19DF,0x11D7,0xA6,0xD2,0x00,0x06,0x5B,0x84,0x43,0x5C);
2.51 DEFINE_GUID(IID_ITfThreadMgr, 0xAA80E801,0x2021,0x11D2,0x93,0xE0,0x00,0x60,0xB0,0x67,0xB8,0x6E);
2.52 DEFINE_GUID(CLSID_TF_ThreadMgr, 0x529A9E6B,0x6587,0x4F23,0xAB,0x9E,0x9C,0x7D,0x68,0x3E,0x3C,0x50);
2.53 @@ -243,6 +263,8 @@
2.54 static void IME_SetupAPI(SDL_VideoData *videodata);
2.55 static DWORD IME_GetId(SDL_VideoData *videodata, UINT uIndex);
2.56 static void IME_SendEditingEvent(SDL_VideoData *videodata);
2.57 +static void IME_DestroyTextures(SDL_VideoData *videodata);
2.58 +
2.59 #define SDL_IsEqualIID(riid1, riid2) SDL_IsEqualGUID(riid1, riid2)
2.60 #define SDL_IsEqualGUID(rguid1, rguid2) (!SDL_memcmp(rguid1, rguid2, sizeof(GUID)))
2.61
2.62 @@ -345,6 +367,7 @@
2.63 CoUninitialize();
2.64 videodata->ime_com_initialized = SDL_FALSE;
2.65 }
2.66 + IME_DestroyTextures(videodata);
2.67 videodata->ime_initialized = SDL_FALSE;
2.68 }
2.69
2.70 @@ -453,17 +476,14 @@
2.71 IME_InputLangChanged(SDL_VideoData *videodata)
2.72 {
2.73 UINT lang = PRIMLANG();
2.74 - HWND hwndime = 0;
2.75 IME_UpdateInputLocale(videodata);
2.76 + if (!videodata->ime_uiless)
2.77 + videodata->ime_candlistindexbase = (videodata->ime_hkl == CHT_HKL_DAYI) ? 0 : 1;
2.78 +
2.79 IME_SetupAPI(videodata);
2.80 if (lang != PRIMLANG()) {
2.81 IME_ClearComposition(videodata);
2.82 }
2.83 - hwndime = ImmGetDefaultIMEWnd(videodata->ime_hwnd_current);
2.84 - if (hwndime) {
2.85 - SendMessageA(hwndime, WM_IME_CONTROL, IMC_OPENSTATUSWINDOW, 0);
2.86 - SendMessageA(hwndime, WM_IME_CONTROL, IMC_CLOSESTATUSWINDOW, 0);
2.87 - }
2.88 }
2.89
2.90 static DWORD
2.91 @@ -610,6 +630,21 @@
2.92 return;
2.93
2.94 hklprev = videodata->ime_hkl;
2.95 + switch (PRIMLANG())
2.96 + {
2.97 + case LANG_CHINESE:
2.98 + videodata->ime_candvertical = SDL_TRUE;
2.99 + if (SUBLANG() == SUBLANG_CHINESE_SIMPLIFIED)
2.100 + videodata->ime_candvertical = SDL_FALSE;
2.101 +
2.102 + break;
2.103 + case LANG_JAPANESE:
2.104 + videodata->ime_candvertical = SDL_TRUE;
2.105 + break;
2.106 + case LANG_KOREAN:
2.107 + videodata->ime_candvertical = SDL_FALSE;
2.108 + break;
2.109 + }
2.110 }
2.111
2.112 static void
2.113 @@ -633,12 +668,6 @@
2.114 }
2.115
2.116 static void
2.117 -IME_ClearEditing(SDL_VideoData *videodata)
2.118 -{
2.119 -
2.120 -}
2.121 -
2.122 -static void
2.123 IME_GetCompositionString(SDL_VideoData *videodata, HIMC himc, DWORD string)
2.124 {
2.125 LONG length = ImmGetCompositionStringW(himc, string, videodata->ime_composition, sizeof(videodata->ime_composition));
2.126 @@ -690,6 +719,101 @@
2.127 SDL_free(s);
2.128 }
2.129
2.130 +static void
2.131 +IME_AddCandidate(SDL_VideoData *videodata, UINT i, LPCWSTR candidate)
2.132 +{
2.133 + LPWSTR dst = videodata->ime_candidates[i];
2.134 + *dst++ = (WCHAR)(TEXT('0') + ((i + videodata->ime_candlistindexbase) % 10));
2.135 + if (videodata->ime_candvertical)
2.136 + *dst++ = TEXT(' ');
2.137 +
2.138 + while (*candidate && (SDL_arraysize(videodata->ime_candidates[i]) > (dst - videodata->ime_candidates[i])))
2.139 + *dst++ = *candidate++;
2.140 +
2.141 + *dst = (WCHAR)'\0';
2.142 +}
2.143 +
2.144 +static void
2.145 +IME_GetCandidateList(HIMC himc, SDL_VideoData *videodata)
2.146 +{
2.147 + LPCANDIDATELIST cand_list = 0;
2.148 + DWORD size = ImmGetCandidateListW(himc, 0, 0, 0);
2.149 + if (size)
2.150 + {
2.151 + cand_list = (LPCANDIDATELIST)SDL_malloc(size);
2.152 + if (cand_list)
2.153 + {
2.154 + size = ImmGetCandidateListW(himc, 0, cand_list, size);
2.155 + if (size)
2.156 + {
2.157 + int i = 0;
2.158 + int j = 0;
2.159 + int page_start = 0;
2.160 + videodata->ime_candsel = cand_list->dwSelection;
2.161 + videodata->ime_candcount = cand_list->dwCount;
2.162 +
2.163 + if (LANG() == LANG_CHS && IME_GetId(videodata, 0))
2.164 + {
2.165 + const UINT maxcandchar = 18;
2.166 + UINT i = 0;
2.167 + UINT cchars = 0;
2.168 +
2.169 + for (; i < videodata->ime_candcount; ++i)
2.170 + {
2.171 + UINT len = SDL_wcslen((LPWSTR)((DWORD)cand_list + cand_list->dwOffset[i])) + 1;
2.172 + if (len + cchars > maxcandchar)
2.173 + {
2.174 + if (i > cand_list->dwSelection)
2.175 + break;
2.176 +
2.177 + page_start = i;
2.178 + cchars = len;
2.179 + }
2.180 + else
2.181 + {
2.182 + cchars += len;
2.183 + }
2.184 + }
2.185 + videodata->ime_candpgsize = i - page_start;
2.186 + }
2.187 + else
2.188 + {
2.189 + videodata->ime_candpgsize = SDL_min(cand_list->dwPageSize, MAX_CANDLIST);
2.190 + page_start = (cand_list->dwSelection / videodata->ime_candpgsize) * videodata->ime_candpgsize;
2.191 + }
2.192 + SDL_memset(&videodata->ime_candidates, 0, sizeof(videodata->ime_candidates));
2.193 + for (i = page_start, j = 0; (DWORD)i < cand_list->dwCount && j < (int)videodata->ime_candpgsize; i++, j++)
2.194 + {
2.195 + LPCWSTR candidate = (LPCWSTR)((DWORD)cand_list + cand_list->dwOffset[i]);
2.196 + IME_AddCandidate(videodata, j, candidate);
2.197 + }
2.198 + if (PRIMLANG() == LANG_KOREAN || (PRIMLANG() == LANG_CHT && !IME_GetId(videodata, 0)))
2.199 + videodata->ime_candsel = -1;
2.200 +
2.201 + }
2.202 + SDL_free(cand_list);
2.203 + }
2.204 + }
2.205 +}
2.206 +
2.207 +static void
2.208 +IME_ShowCandidateList(SDL_VideoData *videodata)
2.209 +{
2.210 + videodata->ime_dirty = SDL_TRUE;
2.211 + videodata->ime_candlist = SDL_TRUE;
2.212 + IME_DestroyTextures(videodata);
2.213 + IME_SendEditingEvent(videodata);
2.214 +}
2.215 +
2.216 +static void
2.217 +IME_HideCandidateList(SDL_VideoData *videodata)
2.218 +{
2.219 + videodata->ime_dirty = SDL_FALSE;
2.220 + videodata->ime_candlist = SDL_FALSE;
2.221 + IME_DestroyTextures(videodata);
2.222 + IME_SendEditingEvent(videodata);
2.223 +}
2.224 +
2.225 SDL_bool
2.226 IME_HandleMessage(HWND hwnd, UINT msg, WPARAM wParam, LPARAM *lParam, SDL_VideoData *videodata)
2.227 {
2.228 @@ -701,7 +825,7 @@
2.229 switch (msg)
2.230 {
2.231 case WM_INPUTLANGCHANGE:
2.232 - //IME_InputLangChanged(videodata);
2.233 + IME_InputLangChanged(videodata);
2.234 break;
2.235 case WM_IME_SETCONTEXT:
2.236 *lParam = 0;
2.237 @@ -740,10 +864,21 @@
2.238 break;
2.239 case IMN_OPENCANDIDATE:
2.240 case IMN_CHANGECANDIDATE:
2.241 + if (videodata->ime_uiless)
2.242 + break;
2.243 +
2.244 trap = SDL_TRUE;
2.245 + IME_ShowCandidateList(videodata);
2.246 + himc = ImmGetContext(hwnd);
2.247 + if (!himc)
2.248 + break;
2.249 +
2.250 + IME_GetCandidateList(himc, videodata);
2.251 + ImmReleaseContext(hwnd, himc);
2.252 break;
2.253 case IMN_CLOSECANDIDATE:
2.254 trap = SDL_TRUE;
2.255 + IME_HideCandidateList(videodata);
2.256 break;
2.257 case IMN_PRIVATE:
2.258 {
2.259 @@ -784,6 +919,68 @@
2.260 return trap;
2.261 }
2.262
2.263 +static void
2.264 +IME_CloseCandidateList(SDL_VideoData *videodata)
2.265 +{
2.266 + IME_HideCandidateList(videodata);
2.267 + videodata->ime_candcount = 0;
2.268 + SDL_memset(videodata->ime_candidates, 0, sizeof(videodata->ime_candidates));
2.269 +}
2.270 +
2.271 +static void
2.272 +UILess_GetCandidateList(SDL_VideoData *videodata, ITfCandidateListUIElement *pcandlist)
2.273 +{
2.274 + UINT selection = 0;
2.275 + UINT count = 0;
2.276 + UINT page = 0;
2.277 + UINT pgcount = 0;
2.278 + DWORD pgstart = 0;
2.279 + DWORD pgsize = 0;
2.280 + UINT i, j;
2.281 + pcandlist->lpVtbl->GetSelection(pcandlist, &selection);
2.282 + pcandlist->lpVtbl->GetCount(pcandlist, &count);
2.283 + pcandlist->lpVtbl->GetCurrentPage(pcandlist, &page);
2.284 +
2.285 + videodata->ime_candsel = selection;
2.286 + videodata->ime_candcount = count;
2.287 + IME_ShowCandidateList(videodata);
2.288 +
2.289 + pcandlist->lpVtbl->GetPageIndex(pcandlist, 0, 0, &pgcount);
2.290 + if (pgcount > 0)
2.291 + {
2.292 + UINT *idxlist = SDL_malloc(sizeof(UINT) * pgcount);
2.293 + if (idxlist)
2.294 + {
2.295 + pcandlist->lpVtbl->GetPageIndex(pcandlist, idxlist, pgcount, &pgcount);
2.296 + pgstart = idxlist[page];
2.297 + if (page < pgcount - 1)
2.298 + pgsize = SDL_min(count, idxlist[page + 1]) - pgstart;
2.299 + else
2.300 + pgsize = count - pgstart;
2.301 +
2.302 + SDL_free(idxlist);
2.303 + }
2.304 + }
2.305 + videodata->ime_candpgsize = SDL_min(pgsize, MAX_CANDLIST);
2.306 + videodata->ime_candsel = videodata->ime_candsel - pgstart;
2.307 +
2.308 + SDL_memset(videodata->ime_candidates, 0, sizeof(videodata->ime_candidates));
2.309 + for (i = pgstart, j = 0; (DWORD)i < count && j < videodata->ime_candpgsize; i++, j++)
2.310 + {
2.311 + BSTR bstr;
2.312 + if (SUCCEEDED(pcandlist->lpVtbl->GetString(pcandlist, i, &bstr)))
2.313 + {
2.314 + if (bstr)
2.315 + {
2.316 + IME_AddCandidate(videodata, j, bstr);
2.317 + SysFreeString(bstr);
2.318 + }
2.319 + }
2.320 + }
2.321 + if (PRIMLANG() == LANG_KOREAN)
2.322 + videodata->ime_candsel = -1;
2.323 +}
2.324 +
2.325 STDMETHODIMP_(ULONG) TSFSink_AddRef(TSFSink *sink)
2.326 {
2.327 return ++sink->refcount;
2.328 @@ -835,6 +1032,7 @@
2.329 {
2.330 ITfUIElement *element = UILess_GetUIElement((SDL_VideoData *)sink->data, dwUIElementId);
2.331 ITfReadingInformationUIElement *preading = 0;
2.332 + ITfCandidateListUIElement *pcandlist = 0;
2.333 SDL_VideoData *videodata = (SDL_VideoData *)sink->data;
2.334 if (!element)
2.335 return E_INVALIDARG;
2.336 @@ -848,6 +1046,11 @@
2.337 }
2.338 preading->lpVtbl->Release(preading);
2.339 }
2.340 + else if (SUCCEEDED(element->lpVtbl->QueryInterface(element, &IID_ITfCandidateListUIElement, (LPVOID *)&pcandlist))) {
2.341 + videodata->ime_candref++;
2.342 + UILess_GetCandidateList(videodata, pcandlist);
2.343 + pcandlist->lpVtbl->Release(pcandlist);
2.344 + }
2.345 return S_OK;
2.346 }
2.347
2.348 @@ -855,6 +1058,7 @@
2.349 {
2.350 ITfUIElement *element = UILess_GetUIElement((SDL_VideoData *)sink->data, dwUIElementId);
2.351 ITfReadingInformationUIElement *preading = 0;
2.352 + ITfCandidateListUIElement *pcandlist = 0;
2.353 SDL_VideoData *videodata = (SDL_VideoData *)sink->data;
2.354 if (!element)
2.355 return E_INVALIDARG;
2.356 @@ -869,6 +1073,10 @@
2.357 }
2.358 preading->lpVtbl->Release(preading);
2.359 }
2.360 + else if (SUCCEEDED(element->lpVtbl->QueryInterface(element, &IID_ITfCandidateListUIElement, (LPVOID *)&pcandlist))) {
2.361 + UILess_GetCandidateList(videodata, pcandlist);
2.362 + pcandlist->lpVtbl->Release(pcandlist);
2.363 + }
2.364 return S_OK;
2.365 }
2.366
2.367 @@ -876,6 +1084,7 @@
2.368 {
2.369 ITfUIElement *element = UILess_GetUIElement((SDL_VideoData *)sink->data, dwUIElementId);
2.370 ITfReadingInformationUIElement *preading = 0;
2.371 + ITfCandidateListUIElement *pcandlist = 0;
2.372 SDL_VideoData *videodata = (SDL_VideoData *)sink->data;
2.373 if (!element)
2.374 return E_INVALIDARG;
2.375 @@ -885,6 +1094,13 @@
2.376 IME_SendEditingEvent(videodata);
2.377 preading->lpVtbl->Release(preading);
2.378 }
2.379 + if (SUCCEEDED(element->lpVtbl->QueryInterface(element, &IID_ITfCandidateListUIElement, (LPVOID *)&pcandlist))) {
2.380 + videodata->ime_candref--;
2.381 + if (videodata->ime_candref == 0)
2.382 + IME_CloseCandidateList(videodata);
2.383 +
2.384 + pcandlist->lpVtbl->Release(pcandlist);
2.385 + }
2.386 return S_OK;
2.387 }
2.388
2.389 @@ -908,9 +1124,13 @@
2.390
2.391 STDMETHODIMP IPPASink_OnActivated(TSFSink *sink, DWORD dwProfileType, LANGID langid, REFCLSID clsid, REFGUID catid, REFGUID guidProfile, HKL hkl, DWORD dwFlags)
2.392 {
2.393 + static GUID TF_PROFILE_DAYI = {0x037B2C25, 0x480C, 0x4D7F, 0xB0, 0x27, 0xD6, 0xCA, 0x6B, 0x69, 0x78, 0x8A};
2.394 + SDL_VideoData *videodata = (SDL_VideoData *)sink->data;
2.395 + videodata->ime_candlistindexbase = SDL_IsEqualGUID(&TF_PROFILE_DAYI, guidProfile) ? 0 : 1;
2.396 if (SDL_IsEqualIID(catid, &GUID_TFCAT_TIP_KEYBOARD) && (dwFlags & TF_IPSINK_FLAG_ACTIVE))
2.397 IME_InputLangChanged((SDL_VideoData *)sink->data);
2.398
2.399 + IME_HideCandidateList(videodata);
2.400 return S_OK;
2.401 }
2.402
2.403 @@ -1016,4 +1236,332 @@
2.404 }
2.405 }
2.406
2.407 +static void *
2.408 +StartDrawToBitmap(HDC hdc, HBITMAP *hhbm, int width, int height)
2.409 +{
2.410 + BITMAPINFO info = {0};
2.411 + BITMAPINFOHEADER *infoHeader = &info.bmiHeader;
2.412 + BYTE *bits = NULL;
2.413 + if (hhbm)
2.414 + {
2.415 + infoHeader->biSize = sizeof(BITMAPINFOHEADER);
2.416 + infoHeader->biWidth = width;
2.417 + infoHeader->biHeight = -1 * SDL_abs(height);
2.418 + infoHeader->biPlanes = 1;
2.419 + infoHeader->biBitCount = 32;
2.420 + infoHeader->biCompression = BI_RGB;
2.421 + *hhbm = CreateDIBSection(hdc, &info, DIB_RGB_COLORS, (void **)&bits, 0, 0);
2.422 + if (*hhbm)
2.423 + SelectObject(hdc, *hhbm);
2.424 + }
2.425 + return bits;
2.426 +}
2.427 +
2.428 +static void
2.429 +StopDrawToBitmap(HDC hdc, HBITMAP *hhbm)
2.430 +{
2.431 + if (hhbm && *hhbm)
2.432 + {
2.433 + DeleteObject(*hhbm);
2.434 + *hhbm = NULL;
2.435 + }
2.436 +}
2.437 +
2.438 +static void
2.439 +BitmapToTexture(HBITMAP hbm, BYTE *bits, int width, int height, SDL_Texture **texture)
2.440 +{
2.441 + SDL_Surface *surface = NULL;
2.442 + BITMAP bm = {0};
2.443 +
2.444 + if (GetObject(hbm, sizeof(bm), &bm) == 0)
2.445 + return;
2.446 +
2.447 + if (bits && texture)
2.448 + {
2.449 + /*
2.450 + For transparency:
2.451 +
2.452 + const Uint8 alpha = 130;
2.453 + unsigned long *p = (unsigned long *)bits;
2.454 + unsigned long *end = (unsigned long *)(bits + (bm.bmWidthBytes * bm.bmHeight));
2.455 + while (p < end)
2.456 + {
2.457 + *p = RGB(GetRValue(*p), GetGValue(*p), GetBValue(*p)) | (alpha << 24);
2.458 + ++p;
2.459 + }
2.460 + surface = SDL_CreateRGBSurfaceFrom(bits, width, height, bm.bmBitsPixel, bm.bmWidthBytes, 0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000);
2.461 + */
2.462 + surface = SDL_CreateRGBSurfaceFrom(bits, width, height, bm.bmBitsPixel, bm.bmWidthBytes, 0x00ff0000, 0x0000ff00, 0x000000ff, 0);
2.463 + if (surface)
2.464 + {
2.465 + *texture = SDL_CreateTextureFromSurface(0, surface);
2.466 + SDL_FreeSurface(surface);
2.467 + }
2.468 + }
2.469 +}
2.470 +
2.471 +/* This draws only within the specified area and fills the entire region. */
2.472 +static void
2.473 +DrawRect(HDC hdc, int left, int top, int right, int bottom, int pensize)
2.474 +{
2.475 + /* The case of no pen (PenSize = 0) is automatically taken care of. */
2.476 + const int penadjust = (int)SDL_floor(pensize / 2.0f - 0.5f);
2.477 + left += pensize / 2;
2.478 + top += pensize / 2;
2.479 + right -= penadjust;
2.480 + bottom -= penadjust;
2.481 + Rectangle(hdc, left, top, right, bottom);
2.482 +}
2.483 +
2.484 +static void
2.485 +DestroyTexture(SDL_Texture **texture)
2.486 +{
2.487 + if (texture && *texture)
2.488 + {
2.489 + SDL_DestroyTexture(*texture);
2.490 + *texture = NULL;
2.491 + }
2.492 +}
2.493 +
2.494 +static void
2.495 +IME_DestroyTextures(SDL_VideoData *videodata)
2.496 +{
2.497 + DestroyTexture(&videodata->ime_candtex);
2.498 +}
2.499 +
2.500 +#define SDL_swap(a,b) { \
2.501 + int c = (a); \
2.502 + (a) = (b); \
2.503 + (b) = c; \
2.504 + }
2.505 +
2.506 +static void
2.507 +IME_PositionCandidateList(SDL_VideoData *videodata, SIZE size)
2.508 +{
2.509 + int left, top, right, bottom;
2.510 + SDL_bool ok = SDL_FALSE;
2.511 + int winw = videodata->ime_winwidth;
2.512 + int winh = videodata->ime_winheight;
2.513 +
2.514 + /* Bottom */
2.515 + left = videodata->ime_rect.x;
2.516 + top = videodata->ime_rect.y + videodata->ime_rect.h;
2.517 + right = left + size.cx;
2.518 + bottom = top + size.cy;
2.519 + if (right >= winw)
2.520 + {
2.521 + left -= right - winw;
2.522 + right = winw;
2.523 + }
2.524 + if (bottom < winh)
2.525 + ok = SDL_TRUE;
2.526 +
2.527 + /* Top */
2.528 + if (!ok)
2.529 + {
2.530 + left = videodata->ime_rect.x;
2.531 + top = videodata->ime_rect.y - size.cy;
2.532 + right = left + size.cx;
2.533 + bottom = videodata->ime_rect.y;
2.534 + if (right >= winw)
2.535 + {
2.536 + left -= right - winw;
2.537 + right = winw;
2.538 + }
2.539 + if (top >= 0)
2.540 + ok = SDL_TRUE;
2.541 + }
2.542 +
2.543 + /* Right */
2.544 + if (!ok)
2.545 + {
2.546 + left = videodata->ime_rect.x + size.cx;
2.547 + top = 0;
2.548 + right = left + size.cx;
2.549 + bottom = size.cy;
2.550 + if (right < winw)
2.551 + ok = SDL_TRUE;
2.552 + }
2.553 +
2.554 + /* Left */
2.555 + if (!ok)
2.556 + {
2.557 + left = videodata->ime_rect.x - size.cx;
2.558 + top = 0;
2.559 + right = videodata->ime_rect.x;
2.560 + bottom = size.cy;
2.561 + if (right >= 0)
2.562 + ok = SDL_TRUE;
2.563 + }
2.564 +
2.565 + /* Window too small, show at (0,0) */
2.566 + if (!ok)
2.567 + {
2.568 + left = 0;
2.569 + top = 0;
2.570 + right = size.cx;
2.571 + bottom = size.cy;
2.572 + }
2.573 +
2.574 + videodata->ime_candlistrect.x = left;
2.575 + videodata->ime_candlistrect.y = top;
2.576 + videodata->ime_candlistrect.w = right - left;
2.577 + videodata->ime_candlistrect.h = bottom - top;
2.578 +}
2.579 +
2.580 +static void
2.581 +IME_RenderCandidateList(SDL_VideoData *videodata, HDC hdc)
2.582 +{
2.583 + int i = 0;
2.584 + SIZE size = {0};
2.585 + SIZE maxcandsize = {0};
2.586 + HBITMAP hbm = NULL;
2.587 + BYTE *bits = NULL;
2.588 + const int candcount = SDL_min(SDL_min(MAX_CANDLIST, videodata->ime_candcount), videodata->ime_candpgsize);
2.589 + SDL_bool vertical = videodata->ime_candvertical;
2.590 +
2.591 + const int listborder = 1;
2.592 + const int listpadding = 0;
2.593 + const int listbordercolor = RGB(0xB4, 0xC7, 0xAA);
2.594 + const int listfillcolor = RGB(255, 255, 255);
2.595 +
2.596 + const int candborder = 1;
2.597 + const int candpadding = 0;
2.598 + const int candmargin = 1;
2.599 + const COLORREF candbordercolor = RGB(255, 255, 255);
2.600 + const COLORREF candfillcolor = RGB(255, 255, 255);
2.601 + const COLORREF candtextcolor = RGB(0, 0, 0);
2.602 + const COLORREF selbordercolor = RGB(0x84, 0xAC, 0xDD);
2.603 + const COLORREF selfillcolor = RGB(0xD2, 0xE6, 0xFF);
2.604 + const COLORREF seltextcolor = RGB(0, 0, 0);
2.605 +
2.606 + HPEN listpen = listborder != 0 ? CreatePen(PS_SOLID, listborder, listbordercolor) : (HPEN)GetStockObject(NULL_PEN);
2.607 + HBRUSH listbrush = CreateSolidBrush(listfillcolor);
2.608 + HPEN candpen = candborder != 0 ? CreatePen(PS_SOLID, candborder, candbordercolor) : (HPEN)GetStockObject(NULL_PEN);
2.609 + HBRUSH candbrush = CreateSolidBrush(candfillcolor);
2.610 + HPEN selpen = candborder != 0 ? CreatePen(PS_DOT, candborder, selbordercolor) : (HPEN)GetStockObject(NULL_PEN);
2.611 + HBRUSH selbrush = CreateSolidBrush(selfillcolor);
2.612 + HFONT font = CreateFont((int)(1 + videodata->ime_rect.h * 0.75f), 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, DEFAULT_CHARSET, OUT_CHARACTER_PRECIS, CLIP_DEFAULT_PRECIS, PROOF_QUALITY, VARIABLE_PITCH | FF_SWISS, TEXT("Microsoft Sans Serif"));
2.613 +
2.614 + SetBkMode(hdc, TRANSPARENT);
2.615 + SelectObject(hdc, font);
2.616 +
2.617 + for (i = 0; i < candcount; ++i)
2.618 + {
2.619 + const WCHAR *s = videodata->ime_candidates[i];
2.620 + if (!*s)
2.621 + break;
2.622 +
2.623 + GetTextExtentPoint32W(hdc, s, SDL_wcslen(s), &size);
2.624 + maxcandsize.cx = SDL_max(maxcandsize.cx, size.cx);
2.625 + maxcandsize.cy = SDL_max(maxcandsize.cy, size.cy);
2.626 +
2.627 + }
2.628 + if (!vertical)
2.629 + SDL_swap(maxcandsize.cx, maxcandsize.cy);
2.630 +
2.631 + size.cx =
2.632 + (listborder * 2) +
2.633 + (listpadding * 2) +
2.634 + (candmargin * 2) +
2.635 + (candborder * 2) +
2.636 + (candpadding * 2) +
2.637 + (maxcandsize.cx)
2.638 + ;
2.639 + size.cy =
2.640 + (listborder * 2) +
2.641 + (listpadding * 2) +
2.642 + ((candcount + 1) * candmargin) +
2.643 + (candcount * candborder * 2) +
2.644 + (candcount * candpadding * 2) +
2.645 + (candcount * maxcandsize.cy)
2.646 + ;
2.647 + if (!vertical)
2.648 + SDL_swap(size.cx, size.cy);
2.649 +
2.650 + bits = StartDrawToBitmap(hdc, &hbm, size.cx, size.cy);
2.651 +
2.652 + SelectObject(hdc, listpen);
2.653 + SelectObject(hdc, listbrush);
2.654 + DrawRect(hdc, 0, 0, size.cx, size.cy, listborder);
2.655 +
2.656 + SelectObject(hdc, candpen);
2.657 + SelectObject(hdc, candbrush);
2.658 + SetTextColor(hdc, candtextcolor);
2.659 + SetBkMode(hdc, TRANSPARENT);
2.660 +
2.661 + for (i = 0; i < candcount; ++i)
2.662 + {
2.663 + const WCHAR *s = videodata->ime_candidates[i];
2.664 + int left, top, right, bottom;
2.665 + if (!*s)
2.666 + break;
2.667 +
2.668 + left = listborder + listpadding + candmargin;
2.669 + top = listborder + listpadding + (i * candborder * 2) + (i * candpadding * 2) + ((i + 1) * candmargin) + (i * maxcandsize.cy);
2.670 + if (!vertical)
2.671 + SDL_swap(size.cx, size.cy);
2.672 +
2.673 + right = size.cx - listborder - listpadding - candmargin;
2.674 + if (!vertical)
2.675 + SDL_swap(size.cx, size.cy);
2.676 +
2.677 + bottom = top + maxcandsize.cy + (candpadding * 2) + (candborder * 2);
2.678 + if (!vertical)
2.679 + {
2.680 + SDL_swap(left, top);
2.681 + SDL_swap(right, bottom);
2.682 + }
2.683 +
2.684 + if (i == videodata->ime_candsel)
2.685 + {
2.686 + SelectObject(hdc, selpen);
2.687 + SelectObject(hdc, selbrush);
2.688 + SetTextColor(hdc, seltextcolor);
2.689 + }
2.690 + else
2.691 + {
2.692 + SelectObject(hdc, candpen);
2.693 + SelectObject(hdc, candbrush);
2.694 + SetTextColor(hdc, candtextcolor);
2.695 + }
2.696 +
2.697 + DrawRect(hdc, left, top, right, bottom, candborder);
2.698 + ExtTextOutW(hdc, left + candborder + candpadding, top + candborder + candpadding, 0, NULL, s, SDL_wcslen(s), NULL);
2.699 + }
2.700 + BitmapToTexture(hbm, bits, size.cx, size.cy, &videodata->ime_candtex);
2.701 + StopDrawToBitmap(hdc, &hbm);
2.702 +
2.703 + DeleteObject(listpen);
2.704 + DeleteObject(listbrush);
2.705 + DeleteObject(candpen);
2.706 + DeleteObject(candbrush);
2.707 + DeleteObject(selpen);
2.708 + DeleteObject(selbrush);
2.709 + DeleteObject(font);
2.710 +
2.711 + IME_PositionCandidateList(videodata, size);
2.712 +}
2.713 +
2.714 +static void
2.715 +IME_Render(SDL_VideoData *videodata)
2.716 +{
2.717 + HDC hdc = CreateCompatibleDC(NULL);
2.718 +
2.719 + if (videodata->ime_candlist)
2.720 + IME_RenderCandidateList(videodata, hdc);
2.721 +
2.722 + DeleteDC(hdc);
2.723 +
2.724 + videodata->ime_dirty = SDL_FALSE;
2.725 +}
2.726 +
2.727 +void IME_Present(SDL_VideoData *videodata)
2.728 +{
2.729 + if (videodata->ime_dirty)
2.730 + IME_Render(videodata);
2.731 +
2.732 + SDL_RenderCopy(videodata->ime_candtex, NULL, &videodata->ime_candlistrect);
2.733 +}
2.734 +
2.735 /* vi: set ts=4 sw=4 expandtab: */