summaryrefslogtreecommitdiff
path: root/plugins/NewStory
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/NewStory')
-rw-r--r--plugins/NewStory/NewStory.vcxproj1
-rw-r--r--plugins/NewStory/NewStory.vcxproj.filters3
-rw-r--r--plugins/NewStory/res/resource.rc14
-rw-r--r--plugins/NewStory/src/history_control.cpp645
-rw-r--r--plugins/NewStory/src/history_control.h45
-rw-r--r--plugins/NewStory/src/history_menus.cpp138
-rw-r--r--plugins/NewStory/src/main.cpp3
-rw-r--r--plugins/NewStory/src/resource.h5
-rw-r--r--plugins/NewStory/src/stdafx.h1
-rw-r--r--plugins/NewStory/src/utils.h3
10 files changed, 479 insertions, 379 deletions
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);