Mercurial > foo_out_sdl
comparison foosdk/sdk/libPPUI/InPlaceEdit.cpp @ 1:20d02a178406 default tip
*: check in everything else
yay
| author | Paper <paper@tflc.us> |
|---|---|
| date | Mon, 05 Jan 2026 02:15:46 -0500 |
| parents | |
| children |
comparison
equal
deleted
inserted
replaced
| 0:e9bb126753e7 | 1:20d02a178406 |
|---|---|
| 1 #include "stdafx.h" | |
| 2 | |
| 3 #include "InPlaceEdit.h" | |
| 4 #include "wtl-pp.h" | |
| 5 #include "win32_op.h" | |
| 6 | |
| 7 #include "AutoComplete.h" | |
| 8 #include "CWindowCreateAndDelete.h" | |
| 9 #include "win32_utility.h" | |
| 10 #include "listview_helper.h" // ListView_GetColumnCount | |
| 11 #include "clipboard.h" | |
| 12 | |
| 13 #include "DarkMode.h" | |
| 14 | |
| 15 #include <forward_list> | |
| 16 | |
| 17 using namespace InPlaceEdit; | |
| 18 | |
| 19 namespace { | |
| 20 | |
| 21 enum { | |
| 22 MSG_COMPLETION = WM_USER, | |
| 23 MSG_DISABLE_EDITING | |
| 24 }; | |
| 25 | |
| 26 | |
| 27 // Rationale: more than one HWND on the list is extremely uncommon, hence forward_list | |
| 28 static std::forward_list<HWND> g_editboxes; | |
| 29 static HHOOK g_hook = NULL /*, g_keyHook = NULL*/; | |
| 30 | |
| 31 static void GAbortEditing(HWND edit, t_uint32 code) { | |
| 32 CWindow parent = ::GetParent(edit); | |
| 33 parent.SendMessage(MSG_DISABLE_EDITING); | |
| 34 parent.PostMessage(MSG_COMPLETION, code, 0); | |
| 35 } | |
| 36 | |
| 37 #if 0 | |
| 38 static void GAbortEditing(t_uint32 code) { | |
| 39 for (auto walk = g_editboxes.begin(); walk != g_editboxes.end(); ++walk) { | |
| 40 GAbortEditing(*walk, code); | |
| 41 } | |
| 42 } | |
| 43 #endif | |
| 44 static bool IsSamePopup(CWindow wnd1, CWindow wnd2) { | |
| 45 return pfc::findOwningPopup(wnd1) == pfc::findOwningPopup(wnd2); | |
| 46 } | |
| 47 | |
| 48 static void MouseEventTest(HWND target, CPoint pt, bool isWheel) { | |
| 49 for (CWindow edit : g_editboxes) { | |
| 50 bool cancel = false; | |
| 51 if (target != edit && IsSamePopup(target, edit)) { | |
| 52 cancel = true; | |
| 53 } else if (isWheel) { | |
| 54 CWindow target2 = WindowFromPoint(pt); | |
| 55 if (target2 != edit && IsSamePopup(target2, edit)) { | |
| 56 cancel = true; | |
| 57 } | |
| 58 } | |
| 59 | |
| 60 if (cancel) GAbortEditing(edit, KEditLostFocus); | |
| 61 } | |
| 62 } | |
| 63 | |
| 64 static LRESULT CALLBACK GMouseProc(int nCode, WPARAM wParam, LPARAM lParam) { | |
| 65 if (nCode == HC_ACTION) { | |
| 66 const MOUSEHOOKSTRUCT * mhs = reinterpret_cast<const MOUSEHOOKSTRUCT *>(lParam); | |
| 67 switch (wParam) { | |
| 68 case WM_NCLBUTTONDOWN: | |
| 69 case WM_NCRBUTTONDOWN: | |
| 70 case WM_NCMBUTTONDOWN: | |
| 71 case WM_NCXBUTTONDOWN: | |
| 72 case WM_LBUTTONDOWN: | |
| 73 case WM_RBUTTONDOWN: | |
| 74 case WM_MBUTTONDOWN: | |
| 75 case WM_XBUTTONDOWN: | |
| 76 MouseEventTest(mhs->hwnd, mhs->pt, false); | |
| 77 break; | |
| 78 case WM_MOUSEWHEEL: | |
| 79 case WM_MOUSEHWHEEL: | |
| 80 MouseEventTest(mhs->hwnd, mhs->pt, true); | |
| 81 break; | |
| 82 } | |
| 83 } | |
| 84 return CallNextHookEx(g_hook, nCode, wParam, lParam); | |
| 85 } | |
| 86 | |
| 87 static void on_editbox_creation(HWND p_editbox) { | |
| 88 // PFC_ASSERT(core_api::is_main_thread()); | |
| 89 g_editboxes.push_front(p_editbox); | |
| 90 if (g_hook == NULL) { | |
| 91 g_hook = SetWindowsHookEx(WH_MOUSE, GMouseProc, NULL, GetCurrentThreadId()); | |
| 92 } | |
| 93 /*if (g_keyHook == NULL) { | |
| 94 g_keyHook = SetWindowsHookEx(WH_KEYBOARD, GKeyboardProc, NULL, GetCurrentThreadId()); | |
| 95 }*/ | |
| 96 } | |
| 97 static void UnhookHelper(HHOOK & hook) { | |
| 98 HHOOK v = pfc::replace_null_t(hook); | |
| 99 if (v != NULL) UnhookWindowsHookEx(v); | |
| 100 } | |
| 101 static void on_editbox_destruction(HWND p_editbox) { | |
| 102 // PFC_ASSERT(core_api::is_main_thread()); | |
| 103 g_editboxes.remove(p_editbox); | |
| 104 if (g_editboxes.empty()) { | |
| 105 UnhookHelper(g_hook); /*UnhookHelper(g_keyHook);*/ | |
| 106 } | |
| 107 } | |
| 108 | |
| 109 class CInPlaceEditBox : public CWindowImpl<CInPlaceEditBox, CEdit> { | |
| 110 public: | |
| 111 CInPlaceEditBox(uint32_t flags) : m_flags(flags) {} | |
| 112 BEGIN_MSG_MAP_EX(CInPlaceEditBox) | |
| 113 //MSG_WM_CREATE(OnCreate) | |
| 114 MSG_WM_DESTROY(OnDestroy) | |
| 115 MSG_WM_GETDLGCODE(OnGetDlgCode) | |
| 116 MSG_WM_KILLFOCUS(OnKillFocus) | |
| 117 MSG_WM_CHAR(OnChar) | |
| 118 MSG_WM_KEYDOWN(OnKeyDown) | |
| 119 MSG_WM_PASTE(OnPaste) | |
| 120 END_MSG_MAP() | |
| 121 | |
| 122 void OnCreation() { | |
| 123 on_editbox_creation(m_hWnd); | |
| 124 } | |
| 125 private: | |
| 126 void OnDestroy() { | |
| 127 m_selfDestruct = true; | |
| 128 on_editbox_destruction(m_hWnd); | |
| 129 SetMsgHandled(FALSE); | |
| 130 } | |
| 131 int OnCreate(LPCREATESTRUCT) { | |
| 132 OnCreation(); | |
| 133 SetMsgHandled(FALSE); | |
| 134 return 0; | |
| 135 } | |
| 136 UINT OnGetDlgCode(LPMSG lpMsg) { | |
| 137 if (lpMsg == NULL) { | |
| 138 SetMsgHandled(FALSE); return 0; | |
| 139 } else { | |
| 140 switch (lpMsg->message) { | |
| 141 case WM_KEYDOWN: | |
| 142 case WM_SYSKEYDOWN: | |
| 143 switch (lpMsg->wParam) { | |
| 144 case VK_TAB: | |
| 145 case VK_ESCAPE: | |
| 146 case VK_RETURN: | |
| 147 return DLGC_WANTMESSAGE; | |
| 148 default: | |
| 149 SetMsgHandled(FALSE); return 0; | |
| 150 } | |
| 151 default: | |
| 152 SetMsgHandled(FALSE); return 0; | |
| 153 | |
| 154 } | |
| 155 } | |
| 156 } | |
| 157 void OnKillFocus(CWindow wndFocus) { | |
| 158 if ( wndFocus != NULL ) ForwardCompletion(KEditLostFocus); | |
| 159 SetMsgHandled(FALSE); | |
| 160 } | |
| 161 | |
| 162 bool testPaste(const char* str) { | |
| 163 if (m_flags & InPlaceEdit::KFlagNumberSigned) { | |
| 164 if (pfc::string_is_numeric(str)) return true; | |
| 165 if (str[0] == '-' && pfc::string_is_numeric(str + 1) && GetWindowTextLength() == 0) return true; | |
| 166 return false; | |
| 167 } | |
| 168 if (m_flags & InPlaceEdit::KFlagNumber) { | |
| 169 return pfc::string_is_numeric(str); | |
| 170 } | |
| 171 return true; | |
| 172 } | |
| 173 | |
| 174 void OnPaste() { | |
| 175 if (m_flags & (InPlaceEdit::KFlagNumber | InPlaceEdit::KFlagNumberSigned)) { | |
| 176 pfc::string8 temp; | |
| 177 ClipboardHelper::OpenScope scope; scope.Open(m_hWnd); | |
| 178 if (ClipboardHelper::GetString(temp)) { | |
| 179 if (!testPaste(temp)) return; | |
| 180 } | |
| 181 } | |
| 182 // Let edit box handle it | |
| 183 SetMsgHandled(FALSE); | |
| 184 } | |
| 185 bool testChar(UINT nChar) { | |
| 186 // Allow various non text characters | |
| 187 if (nChar < ' ') return true; | |
| 188 | |
| 189 if (m_flags & InPlaceEdit::KFlagNumberSigned) { | |
| 190 if (pfc::char_is_numeric(nChar)) return true; | |
| 191 if (nChar == '-') { | |
| 192 return GetWindowTextLength() == 0; | |
| 193 } | |
| 194 return false; | |
| 195 } | |
| 196 if (m_flags & InPlaceEdit::KFlagNumber) { | |
| 197 return pfc::char_is_numeric(nChar); | |
| 198 } | |
| 199 return true; | |
| 200 } | |
| 201 void OnChar(UINT nChar, UINT nRepCnt, UINT nFlags) { | |
| 202 (void)nRepCnt; (void)nRepCnt; | |
| 203 if (m_suppressChar != 0) { | |
| 204 UINT code = nFlags & 0xFF; | |
| 205 if (code == m_suppressChar) return; | |
| 206 } | |
| 207 | |
| 208 if (!testChar(nChar)) { | |
| 209 MessageBeep(0); | |
| 210 return; | |
| 211 } | |
| 212 | |
| 213 SetMsgHandled(FALSE); | |
| 214 } | |
| 215 void OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags) { | |
| 216 (void)nRepCnt; | |
| 217 m_suppressChar = nFlags & 0xFF; | |
| 218 switch (nChar) { | |
| 219 case VK_BACK: | |
| 220 if (GetHotkeyModifierFlags() == MOD_CONTROL) { | |
| 221 CEditPPHooks::DeleteLastWord(*this); | |
| 222 return; | |
| 223 } | |
| 224 break; | |
| 225 case 'A': | |
| 226 if (GetHotkeyModifierFlags() == MOD_CONTROL) { | |
| 227 this->SetSelAll(); return; | |
| 228 } | |
| 229 break; | |
| 230 case VK_RETURN: | |
| 231 if (!IsKeyPressed(VK_LCONTROL) && !IsKeyPressed(VK_RCONTROL)) { | |
| 232 ForwardCompletion(KEditEnter); | |
| 233 return; | |
| 234 } | |
| 235 break; | |
| 236 case VK_TAB: | |
| 237 ForwardCompletion(IsKeyPressed(VK_SHIFT) ? KEditShiftTab : KEditTab); | |
| 238 return; | |
| 239 case VK_ESCAPE: | |
| 240 ForwardCompletion(KEditAborted); | |
| 241 return; | |
| 242 } | |
| 243 m_suppressChar = 0; | |
| 244 SetMsgHandled(FALSE); | |
| 245 } | |
| 246 | |
| 247 void ForwardCompletion(t_uint32 code) { | |
| 248 if (IsWindowEnabled()) { | |
| 249 CWindow owner = GetParent(); | |
| 250 owner.SendMessage(MSG_DISABLE_EDITING); | |
| 251 owner.PostMessage(MSG_COMPLETION, code, 0); | |
| 252 EnableWindow(FALSE); | |
| 253 } | |
| 254 } | |
| 255 | |
| 256 const uint32_t m_flags; | |
| 257 bool m_selfDestruct = false; | |
| 258 UINT m_suppressChar = 0; | |
| 259 }; | |
| 260 | |
| 261 class InPlaceEditContainer : public CWindowImpl<InPlaceEditContainer> { | |
| 262 public: | |
| 263 DECLARE_WND_CLASS_EX(_T("{54340C80-248C-4b8e-8CD4-D624A8E9377B}"), 0, -1); | |
| 264 | |
| 265 | |
| 266 HWND Create(CWindow parent) { | |
| 267 | |
| 268 RECT rect_cropped; | |
| 269 { | |
| 270 RECT client; | |
| 271 WIN32_OP_D(parent.GetClientRect(&client)); | |
| 272 IntersectRect(&rect_cropped, &client, &m_initRect); | |
| 273 } | |
| 274 const DWORD containerStyle = WS_BORDER | WS_CHILD; | |
| 275 AdjustWindowRect(&rect_cropped, containerStyle, FALSE); | |
| 276 | |
| 277 | |
| 278 | |
| 279 WIN32_OP(__super::Create(parent, rect_cropped, NULL, containerStyle) != NULL); | |
| 280 | |
| 281 try { | |
| 282 CRect rcClient; | |
| 283 WIN32_OP_D(GetClientRect(rcClient)); | |
| 284 | |
| 285 | |
| 286 DWORD style = WS_CHILD | WS_VISIBLE;//parent is invisible now | |
| 287 if (m_flags & KFlagMultiLine) style |= WS_VSCROLL | ES_MULTILINE; | |
| 288 else style |= ES_AUTOHSCROLL; | |
| 289 if (m_flags & KFlagReadOnly) style |= ES_READONLY; | |
| 290 if (m_flags & KFlagAlignCenter) style |= ES_CENTER; | |
| 291 else if (m_flags & KFlagAlignRight) style |= ES_RIGHT; | |
| 292 else style |= ES_LEFT; | |
| 293 | |
| 294 // ES_NUMBER is buggy in many ways (repaint glitches after balloon popup) and does not allow signed numbers. | |
| 295 // We implement number handling by filtering WM_CHAR instead. | |
| 296 // if (m_flags & KFlagNumber) style |= ES_NUMBER; | |
| 297 | |
| 298 | |
| 299 CEdit edit; | |
| 300 | |
| 301 WIN32_OP(edit.Create(*this, rcClient, NULL, style, 0, ID_MYEDIT) != NULL); | |
| 302 edit.SetFont(parent.GetFont()); | |
| 303 | |
| 304 if ((m_flags & KFlagDark) != 0) DarkMode::DarkenEditLite(edit); | |
| 305 | |
| 306 if (m_ACData.is_valid()) InitializeSimpleAC(edit, m_ACData.get_ptr(), m_ACOpts); | |
| 307 m_edit.SubclassWindow(edit); | |
| 308 m_edit.OnCreation(); | |
| 309 | |
| 310 pfc::setWindowText(m_edit, *m_content); | |
| 311 m_edit.SetSelAll(); | |
| 312 } catch (...) { | |
| 313 PostMessage(MSG_COMPLETION, InPlaceEdit::KEditAborted, 0); | |
| 314 return m_hWnd; | |
| 315 } | |
| 316 | |
| 317 ShowWindow(SW_SHOW); | |
| 318 m_edit.SetFocus(); | |
| 319 | |
| 320 m_initialized = true; | |
| 321 | |
| 322 PFC_ASSERT(m_hWnd != NULL); | |
| 323 | |
| 324 return m_hWnd; | |
| 325 } | |
| 326 | |
| 327 InPlaceEditContainer(const RECT & p_rect, t_uint32 p_flags, pfc::rcptr_t<pfc::string_base> p_content, reply_t p_notify, IUnknown * ACData, DWORD ACOpts) | |
| 328 : m_content(p_content), m_notify(p_notify), m_initRect(p_rect), | |
| 329 m_flags(p_flags), m_ACData(ACData), m_ACOpts(ACOpts), | |
| 330 m_edit(p_flags) | |
| 331 { | |
| 332 } | |
| 333 | |
| 334 enum { ID_MYEDIT = 666 }; | |
| 335 | |
| 336 BEGIN_MSG_MAP_EX(InPlaceEditContainer) | |
| 337 MESSAGE_HANDLER_EX(WM_CTLCOLOREDIT, MsgForwardToParent) | |
| 338 MESSAGE_HANDLER_EX(WM_CTLCOLORSTATIC, MsgForwardToParent) | |
| 339 MESSAGE_HANDLER_EX(WM_MOUSEWHEEL, MsgLostFocus) | |
| 340 MESSAGE_HANDLER_EX(WM_MOUSEHWHEEL, MsgLostFocus) | |
| 341 MESSAGE_HANDLER_SIMPLE(MSG_DISABLE_EDITING, OnMsgDisableEditing) | |
| 342 MESSAGE_HANDLER_EX(MSG_COMPLETION, OnMsgCompletion) | |
| 343 COMMAND_HANDLER_EX(ID_MYEDIT, EN_CHANGE, OnEditChange) | |
| 344 MSG_WM_DESTROY(OnDestroy) | |
| 345 END_MSG_MAP() | |
| 346 | |
| 347 HWND GetEditBox() const { return m_edit; } | |
| 348 | |
| 349 private: | |
| 350 void OnDestroy() { m_selfDestruct = true; } | |
| 351 | |
| 352 LRESULT MsgForwardToParent(UINT msg, WPARAM wParam, LPARAM lParam) { | |
| 353 return GetParent().SendMessage(msg, wParam, lParam); | |
| 354 } | |
| 355 LRESULT MsgLostFocus(UINT, WPARAM, LPARAM) { | |
| 356 PostMessage(MSG_COMPLETION, InPlaceEdit::KEditLostFocus, 0); | |
| 357 return 0; | |
| 358 } | |
| 359 void OnMsgDisableEditing() { | |
| 360 ShowWindow(SW_HIDE); | |
| 361 GetParent().UpdateWindow(); | |
| 362 m_disable_editing = true; | |
| 363 } | |
| 364 LRESULT OnMsgCompletion(UINT, WPARAM wParam, LPARAM) { | |
| 365 PFC_ASSERT(m_initialized); | |
| 366 if ((wParam & KEditMaskReason) != KEditLostFocus) { | |
| 367 GetParent().SetFocus(); | |
| 368 } | |
| 369 if ( m_changed && m_edit != NULL ) { | |
| 370 *m_content = pfc::getWindowText(m_edit); | |
| 371 } | |
| 372 OnCompletion((unsigned)wParam); | |
| 373 if (!m_selfDestruct) { | |
| 374 m_selfDestruct = true; | |
| 375 DestroyWindow(); | |
| 376 } | |
| 377 return 0; | |
| 378 } | |
| 379 void OnEditChange(UINT, int, CWindow source) { | |
| 380 if (m_initialized && !m_disable_editing) { | |
| 381 *m_content = pfc::getWindowText(source); | |
| 382 m_changed = true; | |
| 383 } | |
| 384 } | |
| 385 | |
| 386 private: | |
| 387 | |
| 388 void OnCompletion(unsigned p_status) { | |
| 389 if (!m_completed) { | |
| 390 m_completed = true; | |
| 391 p_status &= KEditMaskReason; | |
| 392 unsigned code = p_status; | |
| 393 if (m_changed && p_status != KEditAborted) code |= KEditFlagContentChanged; | |
| 394 if (m_notify) m_notify(code); | |
| 395 } | |
| 396 } | |
| 397 | |
| 398 const pfc::rcptr_t<pfc::string_base> m_content; | |
| 399 const reply_t m_notify; | |
| 400 bool m_completed = false; | |
| 401 bool m_initialized = false, m_changed = false; | |
| 402 bool m_disable_editing = false; | |
| 403 bool m_selfDestruct = false; | |
| 404 const CRect m_initRect; | |
| 405 const t_uint32 m_flags; | |
| 406 CInPlaceEditBox m_edit; | |
| 407 | |
| 408 const pfc::com_ptr_t<IUnknown> m_ACData; | |
| 409 const DWORD m_ACOpts; | |
| 410 }; | |
| 411 | |
| 412 } | |
| 413 | |
| 414 static void fail(reply_t p_notify) { | |
| 415 p_notify(KEditAborted); | |
| 416 // completion_notify::g_signal_completion_async(p_notify, KEditAborted); | |
| 417 } | |
| 418 | |
| 419 HWND InPlaceEdit::Start(HWND p_parentwnd, const RECT & p_rect, bool p_multiline, pfc::rcptr_t<pfc::string_base> p_content, reply_t p_notify) { | |
| 420 return StartEx(p_parentwnd, p_rect, p_multiline ? KFlagMultiLine : 0, p_content, p_notify); | |
| 421 } | |
| 422 | |
| 423 void InPlaceEdit::Start_FromListView(HWND p_listview, unsigned p_item, unsigned p_subitem, unsigned p_linecount, pfc::rcptr_t<pfc::string_base> p_content, reply_t p_notify) { | |
| 424 Start_FromListViewEx(p_listview, p_item, p_subitem, p_linecount, 0, p_content, p_notify); | |
| 425 } | |
| 426 | |
| 427 bool InPlaceEdit::TableEditAdvance_ListView(HWND p_listview, unsigned p_column_base, unsigned & p_item, unsigned & p_column, unsigned p_item_count, unsigned p_column_count, unsigned p_whathappened) { | |
| 428 if (p_column >= p_column_count) return false; | |
| 429 | |
| 430 | |
| 431 pfc::array_t<t_size> orderRev; | |
| 432 { | |
| 433 pfc::array_t<unsigned> order; | |
| 434 const unsigned orderExCount = /*p_column_base + p_column_count*/ ListView_GetColumnCount(p_listview); | |
| 435 PFC_ASSERT(orderExCount >= p_column_base + p_column_count); | |
| 436 pfc::array_t<int> orderEx; orderEx.set_size(orderExCount); | |
| 437 if (!ListView_GetColumnOrderArray(p_listview, orderExCount, orderEx.get_ptr())) { | |
| 438 PFC_ASSERT(!"Should not get here - probably mis-calculated column count"); | |
| 439 return false; | |
| 440 } | |
| 441 order.set_size(p_column_count); | |
| 442 for (unsigned walk = 0; walk < p_column_count; ++walk) order[walk] = orderEx[p_column_base + walk]; | |
| 443 | |
| 444 orderRev.set_size(p_column_count); order_helper::g_fill(orderRev); | |
| 445 pfc::sort_get_permutation_t(order, pfc::compare_t<unsigned, unsigned>, p_column_count, orderRev.get_ptr()); | |
| 446 } | |
| 447 | |
| 448 unsigned columnVisible = (unsigned)orderRev[p_column]; | |
| 449 | |
| 450 | |
| 451 if (!TableEditAdvance(p_item, columnVisible, p_item_count, p_column_count, p_whathappened)) return false; | |
| 452 | |
| 453 p_column = (unsigned)order_helper::g_find_reverse(orderRev.get_ptr(), columnVisible); | |
| 454 | |
| 455 return true; | |
| 456 } | |
| 457 | |
| 458 bool InPlaceEdit::TableEditAdvance(unsigned & p_item, unsigned & p_column, unsigned p_item_count, unsigned p_column_count, unsigned p_whathappened) { | |
| 459 if (p_item >= p_item_count || p_column >= p_column_count) return false; | |
| 460 int delta = 0; | |
| 461 | |
| 462 switch (p_whathappened & KEditMaskReason) { | |
| 463 case KEditEnter: | |
| 464 delta = (int)p_column_count; | |
| 465 break; | |
| 466 case KEditTab: | |
| 467 delta = 1; | |
| 468 break; | |
| 469 case KEditShiftTab: | |
| 470 delta = -1; | |
| 471 break; | |
| 472 default: | |
| 473 return false; | |
| 474 } | |
| 475 while (delta > 0) { | |
| 476 p_column++; | |
| 477 if (p_column >= p_column_count) { | |
| 478 p_column = 0; | |
| 479 p_item++; | |
| 480 if (p_item >= p_item_count) return false; | |
| 481 } | |
| 482 delta--; | |
| 483 } | |
| 484 while (delta < 0) { | |
| 485 if (p_column == 0) { | |
| 486 if (p_item == 0) return false; | |
| 487 p_item--; | |
| 488 p_column = p_column_count; | |
| 489 } | |
| 490 p_column--; | |
| 491 delta++; | |
| 492 } | |
| 493 return true; | |
| 494 } | |
| 495 | |
| 496 HWND InPlaceEdit::StartEx(HWND p_parentwnd, const RECT & p_rect, unsigned p_flags, pfc::rcptr_t<pfc::string_base> p_content, reply_t p_notify, IUnknown * ACData, DWORD ACOpts) { | |
| 497 try { | |
| 498 PFC_ASSERT((CWindow(p_parentwnd).GetWindowLong(GWL_STYLE) & WS_CLIPCHILDREN) != 0); | |
| 499 return (new CWindowCreateAndDelete<InPlaceEditContainer>(p_parentwnd, p_rect, p_flags, p_content, p_notify, ACData, ACOpts))->GetEditBox(); | |
| 500 } catch (...) { | |
| 501 fail(p_notify); | |
| 502 return NULL; | |
| 503 } | |
| 504 } | |
| 505 | |
| 506 void InPlaceEdit::Start_FromListViewEx(HWND p_listview, unsigned p_item, unsigned p_subitem, unsigned p_linecount, unsigned p_flags, pfc::rcptr_t<pfc::string_base> p_content, reply_t p_notify) { | |
| 507 try { | |
| 508 ListView_EnsureVisible(p_listview, p_item, FALSE); | |
| 509 RECT itemrect; | |
| 510 WIN32_OP_D(ListView_GetSubItemRect(p_listview, p_item, p_subitem, LVIR_LABEL, &itemrect)); | |
| 511 | |
| 512 const bool multiline = p_linecount > 1; | |
| 513 if (multiline) { | |
| 514 itemrect.bottom = itemrect.top + (itemrect.bottom - itemrect.top) * p_linecount; | |
| 515 } | |
| 516 | |
| 517 StartEx(p_listview, itemrect, p_flags | (multiline ? KFlagMultiLine : 0), p_content, p_notify); | |
| 518 } catch (...) { | |
| 519 fail(p_notify); | |
| 520 } | |
| 521 } |
