diff options
-rw-r--r-- | plugins/ExternalAPI/m_NewStory.h | 17 | ||||
-rw-r--r-- | plugins/NewStory/NewStory.vcxproj | 1 | ||||
-rw-r--r-- | plugins/NewStory/NewStory.vcxproj.filters | 3 | ||||
-rw-r--r-- | plugins/NewStory/res/resource.rc | 14 | ||||
-rw-r--r-- | plugins/NewStory/src/history_control.cpp | 645 | ||||
-rw-r--r-- | plugins/NewStory/src/history_control.h | 45 | ||||
-rw-r--r-- | plugins/NewStory/src/history_menus.cpp | 138 | ||||
-rw-r--r-- | plugins/NewStory/src/main.cpp | 3 | ||||
-rw-r--r-- | plugins/NewStory/src/resource.h | 5 | ||||
-rw-r--r-- | plugins/NewStory/src/stdafx.h | 1 | ||||
-rw-r--r-- | plugins/NewStory/src/utils.h | 3 |
11 files changed, 496 insertions, 379 deletions
diff --git a/plugins/ExternalAPI/m_NewStory.h b/plugins/ExternalAPI/m_NewStory.h new file mode 100644 index 0000000000..8f8baff12c --- /dev/null +++ b/plugins/ExternalAPI/m_NewStory.h @@ -0,0 +1,17 @@ +#pragma once + +struct NSMenuExecParam +{ + char *szServiceName; + int iParam; +}; + +__forceinline HGENMENU Menu_AddNewStoryMenuItem(TMO_MenuItem *pmi, int param) +{ + return (HGENMENU)CallService("NSMenu/AddService", (WPARAM)pmi, param); +} + +// event for changing NewStory menu items +// wparam = (MCONTACT)hContact - contact id +// lparam = (DB::EventInfo*)dbei - event +#define ME_NS_PREBUILDMENU "NewStory/PreBuildMenu" diff --git a/plugins/NewStory/NewStory.vcxproj b/plugins/NewStory/NewStory.vcxproj index 9ca4c37199..d7c64a5402 100644 --- a/plugins/NewStory/NewStory.vcxproj +++ b/plugins/NewStory/NewStory.vcxproj @@ -45,6 +45,7 @@ </ClCompile> <ClCompile Include="src\templates.cpp" /> <ClCompile Include="src\utils.cpp" /> + <ClInclude Include="..\ExternalAPI\m_NewStory.h" /> <ClInclude Include="src\calendartool.h" /> <ClInclude Include="src\fonts.h" /> <ClInclude Include="src\history.h" /> diff --git a/plugins/NewStory/NewStory.vcxproj.filters b/plugins/NewStory/NewStory.vcxproj.filters index 1d8ce04786..45b40c8e4b 100644 --- a/plugins/NewStory/NewStory.vcxproj.filters +++ b/plugins/NewStory/NewStory.vcxproj.filters @@ -73,6 +73,9 @@ <ClInclude Include="src\version.h"> <Filter>Header Files</Filter> </ClInclude> + <ClInclude Include="..\ExternalAPI\m_NewStory.h"> + <Filter>Header Files</Filter> + </ClInclude> </ItemGroup> <ItemGroup> <ResourceCompile Include="res\resource.rc"> diff --git a/plugins/NewStory/res/resource.rc b/plugins/NewStory/res/resource.rc index cbae402065..069771bfb7 100644 --- a/plugins/NewStory/res/resource.rc +++ b/plugins/NewStory/res/resource.rc @@ -241,20 +241,6 @@ BEGIN END END -IDR_CONTEXTMENU MENU -BEGIN - POPUP "" - BEGIN - MENUITEM "Copy", ID_CONTEXT_COPY - MENUITEM SEPARATOR - MENUITEM "Edit", ID_CONTEXT_EDIT - MENUITEM "Delete", ID_CONTEXT_DELETE - MENUITEM SEPARATOR - MENUITEM "Select all", ID_CONTEXT_SELECTALL - END -END - - #ifdef APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// // diff --git a/plugins/NewStory/src/history_control.cpp b/plugins/NewStory/src/history_control.cpp index e57b8ac52a..99e7c3e3bf 100644 --- a/plugins/NewStory/src/history_control.cpp +++ b/plugins/NewStory/src/history_control.cpp @@ -10,425 +10,367 @@ static LRESULT CALLBACK HistoryEditWndProc(HWND, UINT, WPARAM, LPARAM); ///////////////////////////////////////////////////////////////////////// // Control utilities, types and constants -struct NewstoryListData : public MZeroedObject +void NewstoryListData::OnContextMenu(int index, POINT pt) { - NewstoryListData(HWND _1) : - hwnd(_1), - redrawTimer(Miranda_GetSystemWindow(), (LPARAM)this) - { - redrawTimer.OnEvent = Callback(this, &NewstoryListData::OnTimer); - } - - HistoryArray items; - - int scrollTopItem; // topmost item - int scrollTopPixel; // y coord of topmost item, this should be negative or zero - int caret; - int selStart = -1; - int cachedWindowHeight; - int cachedMaxTopItem; // the largest ID of top item to avoid empty space - int cachedMaxTopPixel; + ItemData *item = items[index]; + if (item == nullptr) + return; + + HMENU hMenu = NSMenu_Build(item); - RECT rcLastPaint; - - bool bWasShift; + if (pMsgDlg != nullptr && pMsgDlg->isChat()) { + EnableMenuItem(hMenu, 2, MF_BYPOSITION | MF_GRAYED); + Chat_CreateMenu(hMenu, pMsgDlg->getChat(), nullptr); + } + + TrackPopupMenu(hMenu, TPM_TOPALIGN | TPM_LEFTALIGN | TPM_LEFTBUTTON, pt.x, pt.y, 0, hwnd, nullptr); + Menu_DestroyNestedMenu(hMenu); +} - HWND hwnd; - HWND hwndEditBox; +void NewstoryListData::OnTimer(CTimer *pTimer) +{ + pTimer->Stop(); - CTimer redrawTimer; - CSrmmBaseDialog *pMsgDlg = nullptr; + scrollTopItem = items.getCount(); + FixScrollPosition(); + InvalidateRect(hwnd, 0, FALSE); +} - void OnContextMenu(int index, POINT pt) - { - ItemData* item = items[index]; - if (item == nullptr) - return; - - HMENU hMenu = LoadMenu(g_plugin.getInst(), MAKEINTRESOURCE(IDR_CONTEXTMENU)); - TranslateMenu(hMenu); +void NewstoryListData::BeginEditItem(int index, bool bReadOnly) +{ + if (hwndEditBox) + EndEditItem(false); - HMENU hSubMenu = GetSubMenu(hMenu, 0); - UINT ret; - if (pMsgDlg != nullptr && pMsgDlg->isChat()) { - EnableMenuItem(hSubMenu, 2, MF_BYPOSITION | MF_GRAYED); + if (scrollTopItem > index) + return; - pMsgDlg->m_bInMenu = true; - ret = Chat_CreateMenu(hwnd, hSubMenu, pt, pMsgDlg->getChat(), nullptr); - pMsgDlg->m_bInMenu = false; - } - else ret = TrackPopupMenu(hSubMenu, TPM_RETURNCMD, pt.x, pt.y, 0, hwnd, nullptr); + RECT rc; GetClientRect(hwnd, &rc); + int height = rc.bottom - rc.top; - switch(ret) { - case ID_CONTEXT_COPY: - SendMessage(hwnd, NSM_COPY, 0, 0); + int top = scrollTopPixel; + int idx = scrollTopItem; + int itemHeight = LayoutItem(idx); + while (top < height) { + if (idx == index) break; - case ID_CONTEXT_EDIT: - BeginEditItem(index, false); - break; + top += itemHeight; + idx++; + itemHeight = LayoutItem(idx); + } - case ID_CONTEXT_DELETE: - DeleteItems(); - break; + ItemData *item = items[index]; + if (item->dbe.eventType != EVENTTYPE_MESSAGE) + return; + + int fontid, colorid; + item->getFontColor(fontid, colorid); + + uint32_t dwStyle = WS_CHILD | WS_BORDER | ES_MULTILINE | ES_AUTOVSCROLL; + if (bReadOnly) + dwStyle |= ES_READONLY; + + hwndEditBox = CreateWindow(L"EDIT", item->getWBuf(), dwStyle, 0, top, rc.right - rc.left, itemHeight, hwnd, NULL, g_plugin.getInst(), NULL); + SetWindowLongPtrW(hwndEditBox, GWLP_USERDATA, (LPARAM)item); + OldEditWndProc = (WNDPROC)SetWindowLongPtr(hwndEditBox, GWLP_WNDPROC, (LONG_PTR)HistoryEditWndProc); + SendMessage(hwndEditBox, WM_SETFONT, (WPARAM)g_fontTable[fontid].hfnt, 0); + SendMessage(hwndEditBox, EM_SETMARGINS, EC_RIGHTMARGIN, 100); + SendMessage(hwndEditBox, EM_SETSEL, 0, (LPARAM)(-1)); + ShowWindow(hwndEditBox, SW_SHOW); + SetFocus(hwndEditBox); +} - case ID_CONTEXT_SELECTALL: - SendMessage(hwnd, NSM_SELECTITEMS, 0, items.getCount() - 1); - break; +void NewstoryListData::DeleteItems(void) +{ + if (IDYES != MessageBoxW(hwnd, TranslateT("Are you sure to remove selected event(s)?"), _T(MODULETITLE), MB_YESNOCANCEL | MB_ICONQUESTION)) + return; - default: - if (pMsgDlg != nullptr) { - PostMessage(pMsgDlg->GetHwnd(), WM_MOUSEACTIVATE, 0, 0); - Chat_DoEventHook(pMsgDlg->getChat(), GC_USER_LOGMENU, nullptr, nullptr, ret); - } + db_set_safety_mode(false); + + int firstSel = -1; + int eventCount = items.getCount(); + for (int i = eventCount - 1; i >= 0; i--) { + auto *p = items.get(i, false); + if (p->hEvent && p->bSelected) { + db_event_delete(p->hEvent); + items.remove(i); + firstSel = i; } + } + db_set_safety_mode(true); - DestroyMenu(hMenu); + if (firstSel != -1) { + SendMessage(hwnd, NSM_SETCARET, firstSel, 0); + SendMessage(hwnd, NSM_SELECTITEMS, firstSel, firstSel); } +} - void OnTimer(CTimer *pTimer) - { - pTimer->Stop(); +void NewstoryListData::EndEditItem(bool bAccept) +{ + if (hwndEditBox == nullptr) + return; + + if (bAccept) { + if ((GetWindowLong(hwndEditBox, GWL_STYLE) & ES_READONLY) == 0) { + auto *pItem = (ItemData *)GetWindowLongPtrW(hwndEditBox, GWLP_USERDATA); + + int iTextLen = GetWindowTextLengthW(hwndEditBox); + replaceStrW(pItem->wtext, (wchar_t *)mir_alloc((iTextLen + 1) * sizeof(wchar_t))); + GetWindowTextW(hwndEditBox, pItem->wtext, iTextLen); + pItem->wtext[iTextLen] = 0; + + if (pItem->hContact && pItem->hEvent) { + ptrA szUtf(mir_utf8encodeW(pItem->wtext)); + pItem->dbe.cbBlob = (int)mir_strlen(szUtf) + 1; + pItem->dbe.pBlob = (uint8_t *)szUtf.get(); + db_event_edit(pItem->hEvent, &pItem->dbe); + + if (auto *ppro = Proto_GetInstance(pItem->hContact)) + ppro->OnEventEdited(pItem->hContact, pItem->hEvent); + } - scrollTopItem = items.getCount(); - FixScrollPosition(); - InvalidateRect(hwnd, 0, FALSE); + MTextDestroy(pItem->data); pItem->data = 0; + pItem->checkCreate(hwnd); + } } - void BeginEditItem(int index, bool bReadOnly) - { - if (hwndEditBox) - EndEditItem(false); - - if (scrollTopItem > index) - return; + DestroyWindow(hwndEditBox); + hwndEditBox = 0; +} - RECT rc; GetClientRect(hwnd, &rc); +void NewstoryListData::EnsureVisible(int item) +{ + if (scrollTopItem >= item) { + scrollTopItem = item; + scrollTopPixel = 0; + } + else { + RECT rc; + GetClientRect(hwnd, &rc); int height = rc.bottom - rc.top; - int top = scrollTopPixel; int idx = scrollTopItem; int itemHeight = LayoutItem(idx); + bool found = false; while (top < height) { - if (idx == index) + if (idx == item) { + itemHeight = LayoutItem(idx); + if (top + itemHeight > height) + ScrollListBy(0, height - top - itemHeight); + found = true; break; - + } top += itemHeight; idx++; itemHeight = LayoutItem(idx); } - - ItemData *item = items[index]; - if (item->dbe.eventType != EVENTTYPE_MESSAGE) - return; - - int fontid, colorid; - item->getFontColor(fontid, colorid); - - uint32_t dwStyle = WS_CHILD | WS_BORDER | ES_MULTILINE | ES_AUTOVSCROLL; - if (bReadOnly) - dwStyle |= ES_READONLY; - - hwndEditBox = CreateWindow(L"EDIT", item->getWBuf(), dwStyle, 0, top, rc.right - rc.left, itemHeight, hwnd, NULL, g_plugin.getInst(), NULL); - SetWindowLongPtrW(hwndEditBox, GWLP_USERDATA, (LPARAM)item); - OldEditWndProc = (WNDPROC)SetWindowLongPtr(hwndEditBox, GWLP_WNDPROC, (LONG_PTR)HistoryEditWndProc); - SendMessage(hwndEditBox, WM_SETFONT, (WPARAM)g_fontTable[fontid].hfnt, 0); - SendMessage(hwndEditBox, EM_SETMARGINS, EC_RIGHTMARGIN, 100); - SendMessage(hwndEditBox, EM_SETSEL, 0, (LPARAM)(-1)); - ShowWindow(hwndEditBox, SW_SHOW); - SetFocus(hwndEditBox); - } - - void DeleteItems(void) - { - if (IDYES != MessageBoxW(hwnd, TranslateT("Are you sure to remove selected event(s)?"), _T(MODULETITLE), MB_YESNOCANCEL | MB_ICONQUESTION)) - return; - - db_set_safety_mode(false); - - int firstSel = -1; - int eventCount = items.getCount(); - for (int i = eventCount - 1; i >= 0; i--) { - auto *p = items.get(i, false); - if (p->hEvent && p->bSelected) { - db_event_delete(p->hEvent); - items.remove(i); - firstSel = i; - } - } - db_set_safety_mode(true); - - if (firstSel != -1) { - SendMessage(hwnd, NSM_SETCARET, firstSel, 0); - SendMessage(hwnd, NSM_SELECTITEMS, firstSel, firstSel); - } - } - - void EndEditItem(bool bAccept) - { - if (hwndEditBox == nullptr) - return; - - if (bAccept) { - if ((GetWindowLong(hwndEditBox, GWL_STYLE) & ES_READONLY) == 0) { - auto *pItem = (ItemData *)GetWindowLongPtrW(hwndEditBox, GWLP_USERDATA); - - int iTextLen = GetWindowTextLengthW(hwndEditBox); - replaceStrW(pItem->wtext, (wchar_t *)mir_alloc((iTextLen + 1) * sizeof(wchar_t))); - GetWindowTextW(hwndEditBox, pItem->wtext, iTextLen); - pItem->wtext[iTextLen] = 0; - - if (pItem->hContact && pItem->hEvent) { - ptrA szUtf(mir_utf8encodeW(pItem->wtext)); - pItem->dbe.cbBlob = (int)mir_strlen(szUtf) + 1; - pItem->dbe.pBlob = (uint8_t *)szUtf.get(); - db_event_edit(pItem->hEvent, &pItem->dbe); - - if (auto *ppro = Proto_GetInstance(pItem->hContact)) - ppro->OnEventEdited(pItem->hContact, pItem->hEvent); - } - - MTextDestroy(pItem->data); pItem->data = 0; - pItem->checkCreate(hwnd); - } - } - - DestroyWindow(hwndEditBox); - hwndEditBox = 0; - } - - void EnsureVisible(int item) - { - if (scrollTopItem >= item) { + if (!found) { scrollTopItem = item; scrollTopPixel = 0; } - else { - RECT rc; - GetClientRect(hwnd, &rc); - int height = rc.bottom - rc.top; - int top = scrollTopPixel; - int idx = scrollTopItem; - int itemHeight = LayoutItem(idx); - bool found = false; - while (top < height) { - if (idx == item) { - itemHeight = LayoutItem(idx); - if (top + itemHeight > height) - ScrollListBy(0, height - top - itemHeight); - found = true; - break; - } - top += itemHeight; - idx++; - itemHeight = LayoutItem(idx); - } - if (!found) { - scrollTopItem = item; - scrollTopPixel = 0; - } - } - FixScrollPosition(); } + FixScrollPosition(); +} - void FixScrollPosition() - { - EndEditItem(false); +void NewstoryListData::FixScrollPosition() +{ + EndEditItem(false); + + RECT rc; + GetWindowRect(hwnd, &rc); + int windowHeight = rc.bottom - rc.top; + + if (windowHeight != cachedWindowHeight || cachedMaxTopItem != scrollTopItem) { + int maxTopItem = 0; + int tmp = 0; + for (maxTopItem = items.getCount(); (maxTopItem > 0) && (tmp < windowHeight); maxTopItem--) + tmp += LayoutItem(maxTopItem - 1); + cachedMaxTopItem = maxTopItem; + cachedWindowHeight = windowHeight; + cachedMaxTopPixel = (windowHeight < tmp) ? windowHeight - tmp : 0; + } - RECT rc; - GetWindowRect(hwnd, &rc); - int windowHeight = rc.bottom - rc.top; - - if (windowHeight != cachedWindowHeight || cachedMaxTopItem != scrollTopItem) { - int maxTopItem = 0; - int tmp = 0; - for (maxTopItem = items.getCount(); (maxTopItem > 0) && (tmp < windowHeight); maxTopItem--) - tmp += LayoutItem(maxTopItem - 1); - cachedMaxTopItem = maxTopItem; - cachedWindowHeight = windowHeight; - cachedMaxTopPixel = (windowHeight < tmp) ? windowHeight - tmp : 0; - } + if (scrollTopItem < 0) + scrollTopItem = 0; - if (scrollTopItem < 0) - scrollTopItem = 0; + if ((scrollTopItem > cachedMaxTopItem) || + ((scrollTopItem == cachedMaxTopItem) && (scrollTopPixel < cachedMaxTopPixel))) { + scrollTopItem = cachedMaxTopItem; + scrollTopPixel = cachedMaxTopPixel; + } - if ((scrollTopItem > cachedMaxTopItem) || - ((scrollTopItem == cachedMaxTopItem) && (scrollTopPixel < cachedMaxTopPixel))) { - scrollTopItem = cachedMaxTopItem; - scrollTopPixel = cachedMaxTopPixel; - } + if (g_plugin.bOptVScroll) + RecalcScrollBar(); +} - if (g_plugin.bOptVScroll) - RecalcScrollBar(); +int NewstoryListData::GetItemFromPixel(int yPos) +{ + int count = items.getCount(); + if (!count) + return -1; + + RECT rc; + GetClientRect(hwnd, &rc); + + int height = rc.bottom - rc.top; + int current = scrollTopItem; + int top = scrollTopPixel; + int bottom = top + LayoutItem(current); + while (top <= height) { + if (yPos >= top && yPos <= bottom) + return current; + if (++current >= count) + break; + top = bottom; + bottom = top + LayoutItem(current); } - int GetItemFromPixel(int yPos) - { - int count = items.getCount(); - if (!count) - return -1; - - RECT rc; - GetClientRect(hwnd, &rc); + return -1; +} - int height = rc.bottom - rc.top; - int current = scrollTopItem; - int top = scrollTopPixel; - int bottom = top + LayoutItem(current); - while (top <= height) { - if (yPos >= top && yPos <= bottom) - return current; - if (++current >= count) - break; - top = bottom; - bottom = top + LayoutItem(current); - } +int NewstoryListData::LayoutItem(int index) +{ + HDC hdc = GetDC(hwnd); + RECT rc; GetClientRect(hwnd, &rc); + int width = rc.right - rc.left; - return -1; + ItemData *item = items[index]; + if (!item) { + DeleteDC(hdc); + return 0; } - int LayoutItem(int index) - { - HDC hdc = GetDC(hwnd); - RECT rc; GetClientRect(hwnd, &rc); - int width = rc.right - rc.left; + int fontid, colorid; + item->getFontColor(fontid, colorid); + item->checkCreate(hwnd); - ItemData *item = items[index]; - if (!item) { - DeleteDC(hdc); - return 0; - } + HFONT hfnt = (HFONT)SelectObject(hdc, g_fontTable[fontid].hfnt); - int fontid, colorid; - item->getFontColor(fontid, colorid); - item->checkCreate(hwnd); + SIZE sz; + sz.cx = width - 6; + MTextMeasure(hdc, &sz, (HANDLE)item->data); - HFONT hfnt = (HFONT)SelectObject(hdc, g_fontTable[fontid].hfnt); + SelectObject(hdc, hfnt); - SIZE sz; - sz.cx = width - 6; - MTextMeasure(hdc, &sz, (HANDLE)item->data); - - SelectObject(hdc, hfnt); + ReleaseDC(hwnd, hdc); + return sz.cy + 5; +} - ReleaseDC(hwnd, hdc); - return sz.cy + 5; +int NewstoryListData::PaintItem(HDC hdc, int index, int top, int width) +{ + auto *item = items[index]; + item->savedTop = top; + + // LOGFONT lfText; + COLORREF clText, clBack, clLine; + int fontid, colorid; + item->getFontColor(fontid, colorid); + + clText = g_fontTable[fontid].cl; + if (item->bSelected) { + MTextSendMessage(0, item->data, EM_SETSEL, 0, -1); + clText = g_colorTable[COLOR_SELTEXT].cl; + clBack = g_colorTable[COLOR_SELBACK].cl; + clLine = g_colorTable[COLOR_SELFRAME].cl; + } + else { + MTextSendMessage(0, item->data, EM_SETSEL, 0, 0); + clLine = g_colorTable[COLOR_FRAME].cl; + clBack = g_colorTable[colorid].cl; } - int PaintItem(HDC hdc, int index, int top, int width) - { - auto *item = items[index]; - item->savedTop = top; - - // LOGFONT lfText; - COLORREF clText, clBack, clLine; - int fontid, colorid; - item->getFontColor(fontid, colorid); - - clText = g_fontTable[fontid].cl; - if (item->bSelected) { - MTextSendMessage(0, item->data, EM_SETSEL, 0, -1); - clText = g_colorTable[COLOR_SELTEXT].cl; - clBack = g_colorTable[COLOR_SELBACK].cl; - clLine = g_colorTable[COLOR_SELFRAME].cl; - } - else { - MTextSendMessage(0, item->data, EM_SETSEL, 0, 0); - clLine = g_colorTable[COLOR_FRAME].cl; - clBack = g_colorTable[colorid].cl; - } + item->checkCreate(hwnd); - item->checkCreate(hwnd); + SIZE sz; + sz.cx = width - 6; + HFONT hfnt = (HFONT)SelectObject(hdc, g_fontTable[fontid].hfnt); + MTextMeasure(hdc, &sz, item->data); + SelectObject(hdc, hfnt); + int height = sz.cy + 5; - SIZE sz; - sz.cx = width - 6; - HFONT hfnt = (HFONT)SelectObject(hdc, g_fontTable[fontid].hfnt); - MTextMeasure(hdc, &sz, item->data); - SelectObject(hdc, hfnt); - int height = sz.cy + 5; + RECT rc; + SetRect(&rc, 0, top, width, top + height); - RECT rc; - SetRect(&rc, 0, top, width, top + height); + HBRUSH hbr; + hbr = CreateSolidBrush(clBack); + FillRect(hdc, &rc, hbr); - HBRUSH hbr; - hbr = CreateSolidBrush(clBack); - FillRect(hdc, &rc, hbr); + SetTextColor(hdc, clText); + SetBkMode(hdc, TRANSPARENT); - SetTextColor(hdc, clText); - SetBkMode(hdc, TRANSPARENT); + POINT pos; + pos.x = 3; + pos.y = top + 2; + hfnt = (HFONT)SelectObject(hdc, g_fontTable[fontid].hfnt); + MTextDisplay(hdc, pos, sz, item->data); + SelectObject(hdc, hfnt); - POINT pos; - pos.x = 3; - pos.y = top + 2; - hfnt = (HFONT)SelectObject(hdc, g_fontTable[fontid].hfnt); - MTextDisplay(hdc, pos, sz, item->data); - SelectObject(hdc, hfnt); + DeleteObject(hbr); - DeleteObject(hbr); + HPEN hpn = (HPEN)SelectObject(hdc, CreatePen(PS_SOLID, 1, clLine)); + MoveToEx(hdc, rc.left, rc.bottom - 1, 0); + LineTo(hdc, rc.right, rc.bottom - 1); + DeleteObject(SelectObject(hdc, hpn)); + return height; +} - HPEN hpn = (HPEN)SelectObject(hdc, CreatePen(PS_SOLID, 1, clLine)); - MoveToEx(hdc, rc.left, rc.bottom - 1, 0); - LineTo(hdc, rc.right, rc.bottom - 1); - DeleteObject(SelectObject(hdc, hpn)); - return height; - } +void NewstoryListData::RecalcScrollBar() +{ + SCROLLINFO si = { 0 }; + RECT clRect; + GetClientRect(hwnd, &clRect); + si.cbSize = sizeof(si); + si.fMask = SIF_ALL; + si.nMin = 0; + si.nMax = items.getCount() * AVERAGE_ITEM_HEIGHT; + si.nPage = clRect.bottom; + si.nPos = scrollTopItem * AVERAGE_ITEM_HEIGHT; + SetScrollInfo(hwnd, SB_VERT, &si, TRUE); +} - void RecalcScrollBar() - { - SCROLLINFO si = { 0 }; - RECT clRect; - GetClientRect(hwnd, &clRect); - si.cbSize = sizeof(si); - si.fMask = SIF_ALL; - si.nMin = 0; - si.nMax = items.getCount() * AVERAGE_ITEM_HEIGHT; - si.nPage = clRect.bottom; - si.nPos = scrollTopItem * AVERAGE_ITEM_HEIGHT; - SetScrollInfo(hwnd, SB_VERT, &si, TRUE); +void NewstoryListData::ScrollListBy(int scrollItems, int scrollPixels) +{ + if (scrollItems) { + scrollTopItem += scrollItems; + scrollTopPixel = 0; } + else if (scrollPixels) { + scrollTopPixel += scrollPixels; + if (scrollTopPixel > 0) { + while ((scrollTopPixel > 0) && scrollTopItem) { + scrollTopItem--; + int itemHeight = LayoutItem(scrollTopItem); + scrollTopPixel -= itemHeight; + } - void ScrollListBy(int scrollItems, int scrollPixels) - { - if (scrollItems) { - scrollTopItem += scrollItems; - scrollTopPixel = 0; - } - else if (scrollPixels) { - scrollTopPixel += scrollPixels; if (scrollTopPixel > 0) { - while ((scrollTopPixel > 0) && scrollTopItem) { - scrollTopItem--; - int itemHeight = LayoutItem(scrollTopItem); - scrollTopPixel -= itemHeight; - } - - if (scrollTopPixel > 0) { - scrollTopPixel = 0; - } + scrollTopPixel = 0; } - else if (scrollTopPixel < 0) { - int maxItem = items.getCount(); - int itemHeight = LayoutItem(scrollTopItem); - while ((-scrollTopPixel > itemHeight) && (scrollTopItem < maxItem)) { - scrollTopPixel += itemHeight; - scrollTopItem++; - itemHeight = LayoutItem(scrollTopItem); - } + } + else if (scrollTopPixel < 0) { + int maxItem = items.getCount(); + int itemHeight = LayoutItem(scrollTopItem); + while ((-scrollTopPixel > itemHeight) && (scrollTopItem < maxItem)) { + scrollTopPixel += itemHeight; + scrollTopItem++; + itemHeight = LayoutItem(scrollTopItem); } } - - FixScrollPosition(); } - void SetPos(int pos) - { - caret = pos; - SendMessage(hwnd, NSM_SELECTITEMS2, (selStart == -1) ? pos : selStart, pos); - SendMessage(hwnd, NSM_SETCARET, pos, TRUE); - } -}; + FixScrollPosition(); +} + +void NewstoryListData::SetPos(int pos) +{ + caret = pos; + SendMessage(hwnd, NSM_SELECTITEMS2, (selStart == -1) ? pos : selStart, pos); + SendMessage(hwnd, NSM_SETCARET, pos, TRUE); +} + +///////////////////////////////////////////////////////////////////////// +// Edit box window procedure -// Edit box static LRESULT CALLBACK HistoryEditWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { auto *pData = (NewstoryListData *)GetWindowLongPtr(GetParent(hwnd), 0); @@ -464,7 +406,7 @@ static LRESULT CALLBACK HistoryEditWndProc(HWND hwnd, UINT msg, WPARAM wParam, L } ///////////////////////////////////////////////////////////////////////// -// WndProc +// NewStory history control window procedure LRESULT CALLBACK NewstoryListWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { @@ -660,6 +602,11 @@ LRESULT CALLBACK NewstoryListWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM InvalidateRect(hwnd, 0, FALSE); break; + case WM_COMMAND: + if (NSMenu_Process(LOWORD(wParam), data)) + return 1; + break; + case WM_ERASEBKGND: return 1; diff --git a/plugins/NewStory/src/history_control.h b/plugins/NewStory/src/history_control.h index 9d61c02e35..3d9784b8c1 100644 --- a/plugins/NewStory/src/history_control.h +++ b/plugins/NewStory/src/history_control.h @@ -82,7 +82,50 @@ enum NSM_LAST }; +struct NewstoryListData : public MZeroedObject +{ + NewstoryListData(HWND _1) : + hwnd(_1), + redrawTimer(Miranda_GetSystemWindow(), (LPARAM)this) + { + redrawTimer.OnEvent = Callback(this, &NewstoryListData::OnTimer); + } + + HistoryArray items; + + int scrollTopItem; // topmost item + int scrollTopPixel; // y coord of topmost item, this should be negative or zero + int caret; + int selStart = -1; + int cachedWindowHeight; + int cachedMaxTopItem; // the largest ID of top item to avoid empty space + int cachedMaxTopPixel; + + RECT rcLastPaint; + + bool bWasShift; + + HWND hwnd; + HWND hwndEditBox; + + CTimer redrawTimer; + CSrmmBaseDialog *pMsgDlg = nullptr; + + void OnContextMenu(int index, POINT pt); + void OnTimer(CTimer *pTimer); + void BeginEditItem(int index, bool bReadOnly); + void DeleteItems(void); + void EndEditItem(bool bAccept); + void EnsureVisible(int item); + void FixScrollPosition(); + int GetItemFromPixel(int yPos); + int LayoutItem(int index); + int PaintItem(HDC hdc, int index, int top, int width); + void RecalcScrollBar(); + void ScrollListBy(int scrollItems, int scrollPixels); + void SetPos(int pos); +}; + void InitNewstoryControl(); -//void DestroyNewstoryControl(); #endif // __history_control_h__ diff --git a/plugins/NewStory/src/history_menus.cpp b/plugins/NewStory/src/history_menus.cpp index f7275a3016..8f06a0b5ec 100644 --- a/plugins/NewStory/src/history_menus.cpp +++ b/plugins/NewStory/src/history_menus.cpp @@ -1,7 +1,93 @@ #include "stdafx.h" +static int hMenuObject; +static HANDLE hEventPreBuildMenu; static HGENMENU hmiHistory; +HMENU NSMenu_Build(ItemData *item) +{ + NotifyEventHooks(hEventPreBuildMenu, item->hContact, (LPARAM)&item->dbe); + + HMENU hMenu = CreatePopupMenu(); + Menu_Build(hMenu, hMenuObject); + return hMenu; +} + +bool NSMenu_Process(int iCommand, NewstoryListData *data) +{ + return Menu_ProcessCommandById(iCommand, LPARAM(data)) != 0; +} + +static INT_PTR NSMenuHelper(WPARAM wParam, LPARAM lParam) +{ + auto *pData = (NewstoryListData *)lParam; + + switch (wParam) { + case 1: + SendMessage(pData->hwnd, NSM_COPY, 0, 0); + break; + + case 2: + pData->BeginEditItem(pData->caret, false); + break; + + case 3: + pData->DeleteItems(); + break; + + case 4: + SendMessage(pData->hwnd, NSM_SELECTITEMS, 0, pData->items.getCount() - 1); + break; + + default: + if (auto *pDlg = pData->pMsgDlg) { + PostMessage(pDlg->GetHwnd(), WM_MOUSEACTIVATE, 0, 0); + Chat_DoEventHook(pDlg->getChat(), GC_USER_LOGMENU, nullptr, nullptr, wParam); + } + } + + return 0; +} + +static INT_PTR NSMenuAddService(WPARAM wParam, LPARAM lParam) +{ + auto *pmi = (TMO_MenuItem *)wParam; + if (pmi == nullptr) + return 0; + + auto *mmep = (NSMenuExecParam *)mir_calloc(sizeof(NSMenuExecParam)); + if (mmep == nullptr) + return 0; + + // we need just one parametr. + mmep->szServiceName = mir_strdup(pmi->pszService); + mmep->iParam = lParam; + + HGENMENU hNewItem = Menu_AddItem(hMenuObject, pmi, mmep); + + char buf[1024]; + mir_snprintf(buf, "%s/%s", pmi->pszService, pmi->name.a); + Menu_ConfigureItem(hNewItem, MCI_OPT_UNIQUENAME, buf); + return (INT_PTR)hNewItem; +} + +static INT_PTR NSMenuExecService(WPARAM wParam, LPARAM lParam) +{ + if (auto *pParam = (NSMenuExecParam *)wParam) + CallService(pParam->szServiceName, pParam->iParam, lParam); + + return 0; +} + +static INT_PTR NSMenuFreeOwnerData(WPARAM, LPARAM lParam) +{ + if (auto *param = (NSMenuExecParam *)lParam) { + mir_free(param->szServiceName); + mir_free(param); + } + return 0; +} + static int OnPrebuildContactMenu(WPARAM hContact, LPARAM) { Menu_ShowItem(hmiHistory, db_event_first(hContact) != 0); @@ -11,14 +97,48 @@ static int OnPrebuildContactMenu(WPARAM hContact, LPARAM) void InitMenus() { // Contact menu items + { + CMenuItem mi(&g_plugin); + SET_UID(mi, 0xc20d7a69, 0x7607, 0x4aad, 0xa7, 0x42, 0x10, 0x86, 0xfb, 0x32, 0x49, 0x21); + mi.pszService = MS_HISTORY_SHOWCONTACTHISTORY; + mi.name.a = LPGEN("User history"); + mi.position = 1000090000; + mi.hIcon = g_plugin.getIcon(ICO_NEWSTORY); + hmiHistory = Menu_AddContactMenuItem(&mi); + CreateServiceFunction(mi.pszService, svcShowNewstory); + + HookEvent(ME_CLIST_PREBUILDCONTACTMENU, OnPrebuildContactMenu); + } + + // Init history item's menu + CreateServiceFunction("NSMenu/Helper", NSMenuHelper); + CreateServiceFunction("NSMenu/AddService", NSMenuAddService); + CreateServiceFunction("NSMenu/ExecService", NSMenuExecService); + CreateServiceFunction("NSMenu/FreeOwnerData", NSMenuFreeOwnerData); + + hEventPreBuildMenu = CreateHookableEvent(ME_NS_PREBUILDMENU); + + hMenuObject = Menu_AddObject("NSMenu", LPGEN("NewStory item menu"), nullptr, "NSMenu/ExecService"); + Menu_ConfigureObject(hMenuObject, MCO_OPT_USERDEFINEDITEMS, INT_PTR(FALSE)); + Menu_ConfigureObject(hMenuObject, MCO_OPT_FREE_SERVICE, INT_PTR("NSMenu/FreeOwnerData")); + Menu_ConfigureObject(hMenuObject, MCO_OPT_ONADD_SERVICE, INT_PTR("NSMenu/OnAddService")); + CMenuItem mi(&g_plugin); - SET_UID(mi, 0xc20d7a69, 0x7607, 0x4aad, 0xa7, 0x42, 0x10, 0x86, 0xfb, 0x32, 0x49, 0x21); - mi.pszService = MS_HISTORY_SHOWCONTACTHISTORY; - mi.name.a = LPGEN("User history"); - mi.position = 1000090000; - mi.hIcon = g_plugin.getIcon(ICO_NEWSTORY); - hmiHistory = Menu_AddContactMenuItem(&mi); - CreateServiceFunction(mi.pszService, svcShowNewstory); - - HookEvent(ME_CLIST_PREBUILDCONTACTMENU, OnPrebuildContactMenu); + mi.pszService = "NSMenu/Helper"; + + mi.position = 100000; + mi.name.a = LPGEN("Copy"); + Menu_AddNewStoryMenuItem(&mi, 1); + + mi.position = 200000; + mi.name.a = LPGEN("Edit"); + Menu_AddNewStoryMenuItem(&mi, 2); + + mi.position = 200001; + mi.name.a = LPGEN("Delete"); + Menu_AddNewStoryMenuItem(&mi, 3); + + mi.position = 300000; + mi.name.a = LPGEN("Select all"); + Menu_AddNewStoryMenuItem(&mi, 4); } diff --git a/plugins/NewStory/src/main.cpp b/plugins/NewStory/src/main.cpp index cfde3a75d8..a1db102c88 100644 --- a/plugins/NewStory/src/main.cpp +++ b/plugins/NewStory/src/main.cpp @@ -77,7 +77,6 @@ static int evtModulesLoaded(WPARAM, LPARAM) InitFonts(); InitNewstoryControl(); InitHistory(); - InitMenus(); LoadTemplates(); return 0; @@ -101,6 +100,8 @@ int CMPlugin::Load() HookEvent(ME_OPT_INITIALISE, OptionsInitialize); HookEvent(ME_SYSTEM_MODULESLOADED, evtModulesLoaded); HookEvent(ME_SYSTEM_PRESHUTDOWN, evtPreShutdown); + + InitMenus(); return 0; } diff --git a/plugins/NewStory/src/resource.h b/plugins/NewStory/src/resource.h index 160a52f51d..fc1bb6966a 100644 --- a/plugins/NewStory/src/resource.h +++ b/plugins/NewStory/src/resource.h @@ -7,7 +7,6 @@ #define IDD_OPT_ADVANCED 103 #define IDD_CALENDARTOOL 104 #define IDR_POPUPS 105 -#define IDR_CONTEXTMENU 106 #define ICO_NEWSTORY 107 #define ICO_USERINFO 108 #define ICO_USERMENU 109 @@ -101,10 +100,6 @@ #define ID_FILTER_AUTO 40012 #define ID_LOGOPTIONS_OPTIONS 40013 #define ID_LOGOPTIONS_TEMPLATES 40014 -#define ID_CONTEXT_COPY 40015 -#define ID_CONTEXT_EDIT 40016 -#define ID_CONTEXT_DELETE 40017 -#define ID_CONTEXT_SELECTALL 40018 // Next default values for new objects // diff --git a/plugins/NewStory/src/stdafx.h b/plugins/NewStory/src/stdafx.h index 265607be0b..151d95e5a3 100644 --- a/plugins/NewStory/src/stdafx.h +++ b/plugins/NewStory/src/stdafx.h @@ -55,6 +55,7 @@ Boston, MA 02111-1307, USA. #include <m_metacontacts.h> #include <m_timezones.h> +#include "m_NewStory.h" #include "m_smileyadd.h" #ifndef MTEXT_NOHELPERS #define MTEXT_NOHELPERS diff --git a/plugins/NewStory/src/utils.h b/plugins/NewStory/src/utils.h index 0b69a5d0e6..07dd85da44 100644 --- a/plugins/NewStory/src/utils.h +++ b/plugins/NewStory/src/utils.h @@ -1,2 +1,5 @@ uint32_t toggleBit(uint32_t dw, uint32_t bit); bool CheckFilter(wchar_t *buf, wchar_t *filter); + +HMENU NSMenu_Build(struct ItemData *item); +bool NSMenu_Process(int iCommand, struct NewstoryListData *data); |