summaryrefslogtreecommitdiff
path: root/plugins/NotesAndReminders
diff options
context:
space:
mode:
authorRozhuk Ivan <rozhuk.im@gmail.com>2014-11-27 19:10:05 +0000
committerRozhuk Ivan <rozhuk.im@gmail.com>2014-11-27 19:10:05 +0000
commitea9f7e71bf6d6938bd99795ae6ec8e80028d17a5 (patch)
treebe086e1794bc34ad02afb26615cbb7efafcdec78 /plugins/NotesAndReminders
parent9c2117c10e0d9eb7eb5b704c0177ee1553d3f198 (diff)
NotesReminders: code cleanup
git-svn-id: http://svn.miranda-ng.org/main/trunk@11122 1316c22d-e87f-b044-9b9b-93d7a3e3ba9c
Diffstat (limited to 'plugins/NotesAndReminders')
-rw-r--r--plugins/NotesAndReminders/src/notes.cpp4316
1 files changed, 2156 insertions, 2160 deletions
diff --git a/plugins/NotesAndReminders/src/notes.cpp b/plugins/NotesAndReminders/src/notes.cpp
index 847deb95c0..5d634e24f9 100644
--- a/plugins/NotesAndReminders/src/notes.cpp
+++ b/plugins/NotesAndReminders/src/notes.cpp
@@ -1,2160 +1,2156 @@
-#include "globals.h"
-
-#ifndef MONITOR_DEFAULTTONULL
-#define MONITOR_DEFAULTTONULL 0x00000000
-#endif
-
-
-// NotesData DB data params
-#define DATATAG_TEXT 1 // %s
-#define DATATAG_SCROLLPOS 2 // %u (specifies rich edit controls scroll post as first visible line)
-#define DATATAG_BGCOL 3 // %x (custom background color)
-#define DATATAG_FGCOL 4 // %x (custom text/fg colors)
-#define DATATAG_TITLE 5 // %s (custom note title)
-#define DATATAG_FONT 6 // %d:%u:%u:%s (custom font)
-
-
-#define MAX_TITLE_LEN 63
-#define MAX_NOTE_LEN 16384
-
-// delay before saving note changes (ms)
-#define NOTE_CHANGE_COMMIT_DELAY 1000
-
-
-#ifndef WS_EX_NOACTIVATE
-#define WS_EX_NOACTIVATE 0x08000000
-#endif
-#define IDM_REMOVENOTE 40001
-#define IDM_HIDENOTE 40002
-#define IDM_TOGGLEONTOP 40003
-#define IDM_UNDO 40004
-#define IDM_COPY 40005
-#define IDM_PASTE 40006
-#define IDM_CUT 40007
-#define IDM_CLEAR 40008
-#define WS_EX_LAYERED 0x00080000
-#define LWA_ALPHA 0x00000002
-
-#define IDC_LISTREMINDERS 1000
-#define IDC_LISTREMINDERS_HEADER 2000
-#define IDC_REMINDERDATA 1001
-#define IDC_ADDNEWREMINDER 1002
-#define IDC_CLOSE 1003
-#define WM_RELOAD (WM_USER + 100)
-
-#define NOTIFY_LIST() if (ListNotesVisible) PostMessage(LV,WM_RELOAD,0,0)
-
-#define PENLINK ENLINK *
-
-#define NOTE_WND_CLASS _T("MIM_StickyNote")
-
-
-#define IDM_COLORPRESET_BG 41000
-#define IDM_COLORPRESET_FG 41100
-
-
-static BOOL ListNotesVisible = FALSE;
-static HWND LV;
-
-
-struct ColorPreset
-{
- TCHAR *szName;
- COLORREF color;
-};
-
-static struct ColorPreset clrPresets[] =
-{
- {LPGENT("Black"), RGB(0,0,0)},
- {LPGENT("Maroon"), RGB(128,0,0)},
- {LPGENT("Green"), RGB(0,128,0)},
- {LPGENT("Olive"), RGB(128,128,0)},
- {LPGENT("Navy"), RGB(0,0,128)},
- {LPGENT("Purple"), RGB(128,0,128)},
- {LPGENT("Teal"), RGB(0,128,128)},
- {LPGENT("Gray"), RGB(128,128,128)},
- {LPGENT("Silver"), RGB(192,192,192)},
- {LPGENT("Red"), RGB(255,0,0)},
- {LPGENT("Orange"), RGB(255,155,0)},
- {LPGENT("Lime"), RGB(0,255,0)},
- {LPGENT("Yellow"), RGB(255,255,0)},
- {LPGENT("Blue"), RGB(0,0,255)},
- {LPGENT("Fuchsia"), RGB(255,0,255)},
- {LPGENT("Aqua"), RGB(0,255,255)},
- {LPGENT("White"), RGB(255,255,255)}
-};
-
-
-TREEELEMENT *g_Stickies = NULL;
-
-
-INT_PTR CALLBACK StickyNoteWndProc(HWND hdlg,UINT message,
- WPARAM wParam,LPARAM lParam);
-INT_PTR CALLBACK DlgProcViewNotes(HWND Dialog,UINT Message,WPARAM wParam,
- LPARAM lParam);
-void JustSaveNotes(void);
-INT_PTR PluginMenuCommandAddNew(WPARAM w,LPARAM l);
-INT_PTR PluginMenuCommandDeleteAll(WPARAM w,LPARAM l);
-void GetTriggerTimeString(const ULARGE_INTEGER *When, char *s, UINT strSize, BOOL bUtc);
-void OnListResize(HWND Dialog);
-void UpdateGeomFromWnd(HWND Dialog, int *geom, int *colgeom, int nCols);
-void FileTimeToTzLocalST(const FILETIME *lpUtc, SYSTEMTIME *tmLocal);
-
-
-COLORREF GetCaptionColor(COLORREF bodyClr)
-{
- const DWORD r = ((bodyClr & 0xff) * 4) / 5;
- const DWORD g = (((bodyClr & 0xff00) * 4) / 5) & 0xff00;
- const DWORD b = (((bodyClr & 0xff0000) * 4) / 5) & 0xff0000;
-
- return (COLORREF)(r|g|b);
-}
-
-
-static void EnsureUniqueID(STICKYNOTE *TSN)
-{
- TREEELEMENT *TTE;
-
- if (!g_Stickies)
- return;
-
-try_next:
-
- // check existing notes if id is in use
- TTE = g_Stickies;
- while (TTE)
- {
- if (((STICKYNOTE*)TTE->ptrdata)->ID.QuadPart == TSN->ID.QuadPart)
- {
- // id in use, try new (increases the ID/time stamp by 100 nanosecond steps until an unused time is found,
- // allthough it's very unlikely that there will be duplicated id's it's better to make 100% sure)
- TSN->ID.QuadPart++;
- goto try_next;
- }
-
- TTE = (TREEELEMENT*)TTE->next;
- }
-}
-
-
-static void InitNoteTitle(STICKYNOTE *TSN)
-{
- if (g_NoteTitleDate)
- {
- char TempStr[MAX_PATH];
- SYSTEMTIME tm;
- LCID lc = GetUserDefaultLCID();
-
- TempStr[0] = 0;
-
- memset(&tm, 0, sizeof(tm));
- FileTimeToTzLocalST((FILETIME*)&TSN->ID, &tm);
-
- if ( GetDateFormat(lc, 0, &tm, GetDateFormatStr(), TempStr, MAX_PATH) )
- {
- // append time if requested
- if (g_NoteTitleTime)
- {
- int n = (int)strlen(TempStr);
- TempStr[n++] = ' ';
- TempStr[n] = 0;
-
- GetTimeFormat(MAKELCID(MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),0), 0, &tm, GetTimeFormatStr(), TempStr+n, MAX_PATH-n);
- }
-
- TSN->title = _strdup(TempStr);
- }
- }
-
- TSN->CustomTitle = FALSE;
-}
-
-
-static void InitStickyNoteLogFont(STICKYNOTEFONT *pCustomFont, LOGFONT *lf)
-{
- if (!pCustomFont->size)
- {
- SystemParametersInfo(SPI_GETICONTITLELOGFONT, sizeof(LOGFONT), &lf, FALSE);
- lf->lfHeight = 10;
- HDC hdc = GetDC(0);
- lf->lfHeight = -MulDiv(lf->lfHeight,GetDeviceCaps(hdc, LOGPIXELSY), 72);
- ReleaseDC(0, hdc);
- }
- else
- {
- lf->lfHeight = pCustomFont->size;
- }
-
- _tcscpy(lf->lfFaceName, pCustomFont->szFace);
-
- lf->lfWidth = lf->lfEscapement = lf->lfOrientation = 0;
- lf->lfWeight = pCustomFont->style & DBFONTF_BOLD ? FW_BOLD : FW_NORMAL;
- lf->lfItalic = (pCustomFont->style & DBFONTF_ITALIC) != 0;
- lf->lfUnderline = (pCustomFont->style & DBFONTF_UNDERLINE) != 0;
- lf->lfStrikeOut = (pCustomFont->style & DBFONTF_STRIKEOUT) != 0;
- lf->lfCharSet = pCustomFont->charset;
- lf->lfOutPrecision = OUT_DEFAULT_PRECIS;
- lf->lfClipPrecision = CLIP_DEFAULT_PRECIS;
- lf->lfQuality = DEFAULT_QUALITY;
- lf->lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
-}
-
-static BOOL CreateStickyNoteFont(STICKYNOTEFONT *pCustomFont, LOGFONT *plf)
-{
- LOGFONT lf = {0};
-
- if (!plf)
- {
- InitStickyNoteLogFont(pCustomFont, &lf);
- plf = &lf;
- }
-
- if (pCustomFont->hFont)
- DeleteObject(pCustomFont->hFont);
-
- pCustomFont->hFont = CreateFontIndirect(plf);
-
- return pCustomFont->hFont != NULL;
-}
-
-
-STICKYNOTE* NewNoteEx(int Ax,int Ay,int Aw,int Ah,char *Data,ULARGE_INTEGER *ID,BOOL Visible,BOOL OnTop,int scrollV,COLORREF bgClr,COLORREF fgClr,char *Title,STICKYNOTEFONT *pCustomFont,BOOL bLoading)
-{
- STICKYNOTE* TSN;
- WNDCLASSEX TWC = {0};
- WINDOWPLACEMENT TWP;
- DWORD L1,L2;
- SYSTEMTIME tm;
- char TempStr[MAX_PATH] = {0};
- char *TData;
-
- const BOOL bIsStartup = Visible & 0x10000;
- Visible &= ~0x10000;
-
- if (Data) TData = Data; else TData = NULL;
-
- if (!GetClassInfoEx(hmiranda, NOTE_WND_CLASS, &TWC))
- {
- TWC.style = CS_HREDRAW | CS_VREDRAW | CS_NOCLOSE;
- TWC.cbClsExtra = 0;
- TWC.cbWndExtra = 0;
- TWC.hInstance = hmiranda;
- TWC.hIcon = LoadIcon(0,IDI_APPLICATION);
- TWC.hCursor = LoadCursor(0,IDC_ARROW);
- TWC.hbrBackground = 0;
- TWC.lpszMenuName = 0;
- TWC.lpszClassName = NOTE_WND_CLASS;
- TWC.cbSize = sizeof(WNDCLASSEX);
- TWC.lpfnWndProc = (WNDPROC)StickyNoteWndProc;
- if (!RegisterClassEx(&TWC)) return NULL;
- }
-
- if (!TData || Aw < 0 || Ah < 0)
- {
- TWP.length = sizeof(WINDOWPLACEMENT);
- GetWindowPlacement(GetDesktopWindow(),&TWP);
- Aw = g_NoteWidth; Ah = g_NoteHeight;
- Ax = ((TWP.rcNormalPosition.right - TWP.rcNormalPosition.left) / 2) - (Aw / 2);
- Ay = ((TWP.rcNormalPosition.bottom - TWP.rcNormalPosition.top) / 2) - (Ah / 2);
- }
-
- TSN = (STICKYNOTE*)malloc(sizeof(STICKYNOTE));
-
- if (ID)
- {
- TSN->ID = *ID;
- }
- else
- {
- GetSystemTime(&tm);
- SYSTEMTIMEtoFILETIME(&tm, (FILETIME*)&TSN->ID);
- }
-
- EnsureUniqueID(TSN);
-
- TreeAdd(&g_Stickies,TSN);
-
- if (!TData)
- {
- TData = _strdup("");
- TSN->data = TData;
- }
- else
- TSN->data = TData;
-
- // init note title (time-stamp)
- if (Title)
- {
- TSN->title = Title;
- TSN->CustomTitle = TRUE;
- }
- else
- {
- TSN->title = NULL;
- InitNoteTitle(TSN);
- }
-
- TSN->Visible = Visible;
- TSN->OnTop = OnTop;
-
- TSN->BgColor = bgClr;
- TSN->FgColor = fgClr;
-
- TSN->pCustomFont = pCustomFont;
-
- L1 = WS_EX_TOOLWINDOW;
- if (g_Transparency < 255) L1 |= WS_EX_LAYERED;
- if (OnTop) L1 |= WS_EX_TOPMOST;
-
- L2 = WS_POPUP | WS_THICKFRAME | WS_CAPTION;
-
- // NOTE: loaded note positions stem from GetWindowPlacement, which normally have a different coord space than
- // CreateWindow/SetWindowPos, BUT since we now use WS_EX_TOOLWINDOW they use the same coord space so
- // we don't have to worry about notes "drifting" between sessions
- TSN->SNHwnd = CreateWindowEx(L1, NOTE_WND_CLASS, _T("StickyNote"), L2, Ax,Ay,Aw,Ah, NULL, 0, hmiranda, TSN);
-
- if (g_Transparency < 255)
- SetLayeredWindowAttributes(TSN->SNHwnd,0,(BYTE)g_Transparency,LWA_ALPHA);
-
- // ensure that window is not placed off-screen (if previous session had different monitor count or resolution)
- // NOTE: SetWindowPlacement should do this, but it's extremly flakey
- if (Data)
- {
- if (!MonitorFromWindow(TSN->SNHwnd, MONITOR_DEFAULTTONULL) )
- {
- TWP.length = sizeof(WINDOWPLACEMENT);
- GetWindowPlacement(GetDesktopWindow(), &TWP);
-
- if (Aw > 500) Aw = 500;
- if (Ay < TWP.rcNormalPosition.left+10 || Ax > TWP.rcNormalPosition.right-120)
- Ax = ((TWP.rcNormalPosition.right - TWP.rcNormalPosition.left) / 2) - (Aw / 2) + (rand() & 0x3f);
- if (Ay < TWP.rcNormalPosition.top+50 || Ay > TWP.rcNormalPosition.bottom-50)
- Ay = ((TWP.rcNormalPosition.bottom - TWP.rcNormalPosition.top) / 4) + (rand() & 0x1f);
-
- SetWindowPos(TSN->SNHwnd, NULL, Ax, Ay, Aw, Ah, SWP_NOZORDER|SWP_NOACTIVATE);
- }
- }
-
- if (Visible)
- {
- ShowWindow(TSN->SNHwnd, SW_SHOWNA);
-
- // when loading notes (only at startup), place all non-top notes at the bottom so they don't cover other windows
- if (Data && !OnTop && bIsStartup)
- SetWindowPos(TSN->SNHwnd, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE|SWP_NOACTIVATE|SWP_ASYNCWINDOWPOS);
- }
-
- if (scrollV)
- {
- SendMessage(TSN->REHwnd, EM_LINESCROLL, 0, scrollV);
- }
-
- // make sure that any event triggered by init doesn't cause a meaningless save
- KillTimer(TSN->SNHwnd, 1025);
-
- if (!bLoading)
- {
- NOTIFY_LIST();
- }
-
- return TSN;
-}
-
-STICKYNOTE* NewNote(int Ax,int Ay,int Aw,int Ah,char *Data,ULARGE_INTEGER *ID,BOOL Visible,BOOL OnTop,int scrollV)
-{
- return NewNoteEx(Ax,Ay,Aw,Ah,Data,ID,Visible,OnTop,scrollV,0,0,NULL,NULL,FALSE);
-}
-
-void LoadNotes(BOOL bIsStartup)
-{
- int I;
- int NotesCount;
- WORD Size;
- char *Value = NULL, *TVal = NULL;
- char ValueName[32];
-
- g_Stickies = NULL;
-
- NotesCount = db_get_dw(0,MODULENAME,"NotesData",0);
-
- for (I = 0; I < NotesCount; I++)
- {
- char *DelPos;
-
- mir_snprintf(ValueName, SIZEOF(ValueName), "NotesData%d", I);
-
- if (Value)
- {
- FreeSettingBlob(Size, Value);
- Value = NULL;
- }
-
- Size = 65535; // does not get used
-
- ReadSettingBlob(0, MODULENAME, ValueName, &Size, (void**)&Value);
-
- if (!Size || !Value)
- continue; // the setting could not be read from DB -> skip
-
- if (Value[0] == 'X')
- {
- // new eXtended/fleXible data format
-
- STICKYNOTE note = {0};
- int i, rect[4];
- int scrollV = 0;
- STICKYNOTEFONT *pCustomFont = NULL;
- DWORD flags;
-
- DelPos = strchr(Value+1,0x1B);
- if (DelPos)
- *DelPos = 0;
-
- // id:x:y:w:h:flags
-
- TVal = strchr(Value+1, ':');
- if (!TVal || (DelPos && TVal > DelPos))
- continue;
- *TVal++ = 0;
-
- note.ID.QuadPart = _strtoui64(Value+1, NULL, 16);
-
- for (i=0; i<4; i++)
- {
- char *sep = strchr(TVal, ':');
- if (!sep || (DelPos && sep > DelPos))
- goto skip;
- *sep++ = 0;
-
- rect[i] = strtol(TVal, NULL, 10);
-
- TVal = sep;
- }
-
- flags = strtoul(TVal, NULL, 16);
-
- if (flags & 1)
- note.Visible = TRUE;
- if (flags & 2)
- note.OnTop = TRUE;
-
- // optional \033 separated params
- while (DelPos)
- {
- char *sep;
- UINT tag;
-
- TVal = DelPos + 1;
- // find param end and make sure it's null-terminated (if end of data then it's already null-terminated)
- DelPos = strchr(TVal, 0x1B);
- if (DelPos)
- *DelPos = 0;
-
- // tag:<data>
-
- sep = strchr(TVal, ':');
- if (!sep || (DelPos && sep > DelPos))
- goto skip;
-
- tag = strtoul(TVal, NULL, 10);
- TVal = sep + 1;
-
- switch (tag)
- {
- case DATATAG_TEXT:
- note.data = _strdup(TVal);
- break;
-
- case DATATAG_SCROLLPOS:
- scrollV = (int)strtoul(TVal, NULL, 10);
- break;
-
- case DATATAG_BGCOL:
- note.BgColor = strtoul(TVal, NULL, 16) | 0xff000000;
- break;
-
- case DATATAG_FGCOL:
- note.FgColor = strtoul(TVal, NULL, 16) | 0xff000000;
- break;
-
- case DATATAG_TITLE:
- if (strlen(TVal) > MAX_TITLE_LEN)
- TVal[MAX_TITLE_LEN] = 0;
- note.title = _strdup(TVal);
- note.CustomTitle = TRUE;
- break;
-
- case DATATAG_FONT:
- {
- int fsize;
- UINT fstyle, fcharset;
-
- char *TVal2 = TVal;
- sep = strchr(TVal2, ':');
- if (!sep || (DelPos && sep > DelPos))
- goto skip;
- *sep++ = 0;
- fsize = strtol(TVal2, NULL, 10);
- TVal2 = sep;
-
- sep = strchr(TVal2, ':');
- if (!sep || (DelPos && sep > DelPos))
- goto skip;
- *sep++ = 0;
- fstyle = strtoul(TVal2, NULL, 10);
- TVal2 = sep;
-
- sep = strchr(TVal2, ':');
- if (!sep || (DelPos && sep > DelPos))
- goto skip;
- *sep++ = 0;
- fcharset = strtoul(TVal2, NULL, 10);
- TVal2 = sep;
-
- if (TVal2 >= DelPos)
- goto skip;
-
- pCustomFont = (STICKYNOTEFONT*)malloc(sizeof(STICKYNOTEFONT));
- pCustomFont->size = (char)fsize;
- pCustomFont->style = (BYTE)fstyle;
- pCustomFont->charset = (BYTE)fcharset;
- _tcscpy(pCustomFont->szFace, TVal2);
- pCustomFont->hFont = NULL;
-
- if ( !CreateStickyNoteFont(pCustomFont, NULL) )
- {
- free(pCustomFont);
- pCustomFont = NULL;
- }
- }
- break;
- }
- }
-
- if (!note.data)
- note.data = _strdup("");
-
- note.Visible = note.Visible && (!bIsStartup || g_ShowNotesAtStart);
- if (bIsStartup)
- note.Visible |= 0x10000;
-
- NewNoteEx(rect[0],rect[1],rect[2],rect[3],note.data,&note.ID,note.Visible,note.OnTop,scrollV,note.BgColor,note.FgColor,note.title,pCustomFont,TRUE);
- }
- else
- {
- // old format (for DB backward compatibility)
-
- int Tx,Ty,Tw,Th,TV,OT;
- BOOL V;
- char *Data,*ID;
- ULARGE_INTEGER newid;
-
- OT = 1; TV = 1;
- Tx = 100; Ty = 100;
- Tw = 179; Th = 35;
- Data = NULL; ID = NULL;
-
- if (DelPos = strchr(Value,0x1B))
- { // get first delimiter
- int PartLen = DelPos - TVal;
-
- Data = NULL;
- ID = NULL;
- TVal = Value;
- DelPos[0] = 0x0;
- Tx = strtol(TVal, NULL, 10);
-
- TVal = DelPos + 1;
- DelPos = strchr(TVal, 0x1B);
- if (!DelPos) continue; // setting is broken, do not crash
- DelPos[0] = 0x0;
- Ty = strtol(TVal, NULL, 10);
-
- TVal = DelPos + 1;
- DelPos = strchr(TVal, 0x1B);
- if (!DelPos) continue; // setting is broken, do not crash
- DelPos[0] = 0x0;
- Tw = strtol(TVal, NULL, 10);
-
- TVal = DelPos + 1;
- DelPos = strchr(TVal, 0x1B);
- if (!DelPos) continue; // setting is broken, do not crash
- DelPos[0] = 0x0;
- Th = strtol(TVal, NULL, 10);
-
- TVal = DelPos + 1;
- DelPos = strchr(TVal, 0x1B);
- if (!DelPos) continue; // setting is broken, do not crash
- DelPos[0] = 0x0;
- TV = strtol(TVal, NULL, 10);
-
- TVal = DelPos + 1;
- DelPos = strchr(TVal, 0x1B);
- if (!DelPos) continue; // setting is broken, do not crash
- DelPos[0] = 0x0;
- OT = strtol(TVal, NULL, 10);
-
- TVal = DelPos + 1;
- DelPos = strchr(TVal, 0x1B);
- if (!DelPos) continue; // setting is broken, do not crash
- DelPos[0] = 0x0;
- Data = _strdup(TVal);
-
- TVal = DelPos + 1;
- ID = TVal;
-
- V = (BOOL)TV && (!bIsStartup || g_ShowNotesAtStart);
-
- if (bIsStartup)
- V |= 0x10000;
-
- // convert old ID format to new
- if ( strchr(ID, '-') )
- {
- // validate format (otherwise create new)
- if (strlen(ID) < 19 || ID[2] != '-' || ID[5] != '-' || ID[10] != ' ' || ID[13] != ':' || ID[16] != ':')
- {
- ID = NULL;
- }
- else
- {
- SYSTEMTIME tm;
-
- ID[2] = ID[5] = ID[10] = ID[13] = ID[16] = 0;
-
- memset(&tm, 0, sizeof(tm));
- tm.wDay = (WORD)strtoul(ID, NULL, 10);
- tm.wMonth = (WORD)strtoul(ID+3, NULL, 10);
- tm.wYear = (WORD)strtoul(ID+6, NULL, 10);
- tm.wHour = (WORD)strtoul(ID+11, NULL, 10);
- tm.wMinute = (WORD)strtoul(ID+14, NULL, 10);
- tm.wSecond = (WORD)strtoul(ID+17, NULL, 10);
-
- SYSTEMTIMEtoFILETIME(&tm, (FILETIME*)&newid);
- }
- }
- else
- {
- ID = NULL;
- }
-
- NewNoteEx(Tx,Ty,Tw,Th,Data,ID?&newid:NULL,V,(BOOL)OT,0,0,0,NULL,NULL,TRUE);
- }
- }
-skip:;
- }
-
- if (Value)
- FreeSettingBlob(Size, Value); // we do not leak on bad setting
-
- NOTIFY_LIST();
-}
-
-void CloseNotesList()
-{
- if (ListNotesVisible)
- {
- DestroyWindow(LV);
- ListNotesVisible = FALSE;
- }
-}
-
-static void PurgeNotesTree()
-{
- STICKYNOTE *pt;
-
- while (g_Stickies) // empty whole tree
- {
- pt = (STICKYNOTE*)g_Stickies->ptrdata;
- if (pt->SNHwnd) DestroyWindow(pt->SNHwnd);
- SAFE_FREE((void**)&pt->title);
- SAFE_FREE((void**)&pt->data);
- if (pt->pCustomFont)
- {
- DeleteObject(pt->pCustomFont->hFont);
- free(pt->pCustomFont);
- }
- TreeDelete(&g_Stickies,pt);
- SAFE_FREE((void**)&pt);
- }
- g_Stickies = NULL;
-}
-
-void SaveNotes(void)
-{
- JustSaveNotes();
- PurgeNotesTree();
-}
-
-void PurgeNotes(void)
-{
- int NotesCount, I;
- char ValueName[16];
-
- NotesCount = db_get_dw(0,MODULENAME,"NotesData",0);
- for(I = 0; I < NotesCount; I++)
- {
- mir_snprintf(ValueName, SIZEOF(ValueName), "NotesData%d", I);
- db_unset(0,MODULENAME,ValueName);
- }
-}
-
-void OnDeleteNote(HWND hdlg, STICKYNOTE *SN)
-{
- if (MessageBox(hdlg, TranslateT("Are you sure you want to delete this note?"), TranslateT(SECTIONNAME), MB_OKCANCEL) == IDOK)
- {
- if (SN->SNHwnd)
- DestroyWindow(SN->SNHwnd);
- TreeDelete(&g_Stickies,SN);
- SAFE_FREE((void**)&SN->data);
- if (SN->pCustomFont)
- {
- DeleteObject(SN->pCustomFont->hFont);
- free(SN->pCustomFont);
- }
- SAFE_FREE((void**)&SN);
- JustSaveNotes();
- NOTIFY_LIST();
- }
-}
-
-void DeleteNotes(void)
-{
- PurgeNotes();
- db_set_dw(0, MODULENAME, "NotesData", 0);
- PurgeNotesTree();
- NOTIFY_LIST();
-}
-
-void ShowHideNotes(void)
-{
- BOOL Visible;
-
- if (!g_Stickies)
- return;
-
- // if some notes are hidden but others visible then first make all visible
- // only toggle vis state if all are hidden or all are visible
-
- UINT nHideCount = 0, nVisCount = 0;
- TREEELEMENT *TTE = g_Stickies;
- while (TTE)
- {
- if (((STICKYNOTE*)TTE->ptrdata)->Visible)
- nVisCount++;
- else
- nHideCount++;
-
- TTE = (TREEELEMENT*)TTE->next;
- }
-
- if (!nVisCount)
- Visible = TRUE;
- else if (!nHideCount)
- Visible = FALSE;
- else
- Visible = TRUE;
-
- int bShow = Visible ? SW_SHOWNA : SW_HIDE;
-
- TTE = g_Stickies;
- while (TTE)
- {
- STICKYNOTE *SN = (STICKYNOTE*)TTE->ptrdata;
-
- if ((!Visible) != (!SN->Visible))
- {
- ShowWindow(SN->SNHwnd, bShow);
- SN->Visible = Visible;
- }
-
- TTE = (TREEELEMENT*)TTE->next;
- }
-
- JustSaveNotes();
-}
-
-void BringAllNotesToFront(STICKYNOTE *pActive)
-{
- TREEELEMENT *TTE;
-
- if (!g_Stickies)
- return;
-
- // NOTE: for some reason there are issues when bringing to top through hotkey while another app (like Explorer)
- // is active, it refuses to move notes to top like it should with HWND_TOP. as a workaround still doesn't
- // work 100% of the time, but at least more often, we first move not to top-most then for non-always-on-top
- // notes we demote them back as a non top-most window
-
- TTE = g_Stickies;
- while (TTE)
- {
- STICKYNOTE *SN = (STICKYNOTE*)TTE->ptrdata;
-
- if (SN->Visible && pActive != SN)
- {
- SetWindowPos(SN->SNHwnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
- if (!SN->OnTop)
- SetWindowPos(SN->SNHwnd, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
- }
-
- TTE = (TREEELEMENT*)TTE->next;
- }
-
- if (pActive)
- {
- SetWindowPos(pActive->SNHwnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
- if (!pActive->OnTop)
- SetWindowPos(pActive->SNHwnd, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
- }
-}
-
-static void JustSaveNotesEx(STICKYNOTE *pModified)
-{
- // pModified optionally points to the modified note that invoked the JustSaveNotesEx call
-
- TREEELEMENT *TTE;
- int I, NotesCount = TreeGetCount(g_Stickies);
- int n, l;
- char ValueName[32];
- WINDOWPLACEMENT wp;
- int TX,TY,TW,TH;
- DWORD flags;
- int SzT;
- int scrollV;
- char *tData, *Value;
-
- const int OldNotesCount = db_get_dw(0, MODULENAME, "NotesData", 0);
-
- db_set_dw(0, MODULENAME, "NotesData", NotesCount);
-
- for (TTE = g_Stickies, I = 0; TTE; TTE = (TREEELEMENT*)TTE->next, I++)
- {
- STICKYNOTE *pNote = (STICKYNOTE*)TTE->ptrdata;
- BOOL bDeleteTData = TRUE;
- scrollV = 0;
- tData = NULL;
-
- // window pos and size
- wp.length = sizeof(WINDOWPLACEMENT);
- GetWindowPlacement(pNote->SNHwnd, &wp);
- TX = wp.rcNormalPosition.left;
- TY = wp.rcNormalPosition.top;
- TW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
- TH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
-
- // set flags
- flags = 0;
- if (pNote->Visible) flags |= 1;
- if (pNote->OnTop) flags |= 2;
-
- // get note text
- SzT = SendMessage(pNote->REHwnd, WM_GETTEXTLENGTH, 0, 0);
- if (SzT) // TODO: change to support unicode and rtf, use EM_STREAMOUT
- {
- if (SzT > MAX_NOTE_LEN) SzT = MAX_NOTE_LEN; // we want to be far below the 64k limit
- tData = (char*)malloc(SzT+1);
- if (tData)
- SendMessage(pNote->REHwnd, WM_GETTEXT, SzT+1, (LPARAM)tData);
- }
-
- if (pNote == pModified)
- {
- // update the data of the modified note
- if (pNote->data)
- free(pNote->data);
- pNote->data = tData ? tData : _strdup("");
- bDeleteTData = FALSE;
- }
-
- if (!tData)
- // empty note
- SzT = 0;
- else
- // get current scroll position
- scrollV = SendMessage(pNote->REHwnd, EM_GETFIRSTVISIBLELINE, 0, 0);
-
- //
-
- Value = (char*)malloc(SzT + 512);
- if (!Value) {
- if (bDeleteTData)
- SAFE_FREE((void**)&tData);
- continue;
- }
-
- n = 0;
-
- // data header
- l = sprintf(Value, "X%I64x:%d:%d:%d:%d:%x", pNote->ID.QuadPart, TX, TY, TW, TH, flags); //!!!!!!!!!!!!
- if (l > 0) n += l;
-
- // scroll pos
- if (scrollV > 0)
- {
- l = sprintf(Value+n, "\033""%u:%u", DATATAG_SCROLLPOS, (UINT)scrollV); //!!!!!!!!!!
- if (l > 0) n += l;
- }
-
- // custom bg color
- if (pNote->BgColor)
- {
- l = sprintf(Value+n, "\033""%u:%x", DATATAG_BGCOL, (UINT)(pNote->BgColor&0xffffff)); //!!!!!!!!!!!!!
- if (l > 0) n += l;
- }
-
- // custom fg color
- if (pNote->FgColor)
- {
- l = sprintf(Value+n, "\033""%u:%x", DATATAG_FGCOL, (UINT)(pNote->FgColor&0xffffff)); //!!!!!!!!!!!!!
- if (l > 0) n += l;
- }
-
- if (pNote->pCustomFont)
- {
- l = sprintf(Value+n, "\033""%u:%d:%u:%u:%s", DATATAG_FONT,
- (int)pNote->pCustomFont->size, (UINT)pNote->pCustomFont->style, (UINT)pNote->pCustomFont->charset,
- pNote->pCustomFont->szFace); //!!!!!!!!!!!!!!!
- if (l > 0) n += l;
- }
-
- // custom title
- if (pNote->CustomTitle && pNote->title)
- {
- l = sprintf(Value+n, "\033""%u:%s", DATATAG_TITLE, pNote->title); //!!!!!!!!!!!!!
- if (l > 0) n += l;
- }
-
- // note text (ALWAYS PUT THIS PARAM LAST)
- if (tData)
- {
- l = sprintf(Value+n, "\033""%u:%s", DATATAG_TEXT, tData); //!!!!!!!!!!!!
- if (l > 0) n += l;
- }
-
- // clamp data size to WORD (including null terminator)
- if (n >= 0xffff)
- {
- // huston, we have a problem, strip some reminder text
- n = 0xfffe;
- Value[0xffff] = 0;
- }
-
- mir_snprintf(ValueName, SIZEOF(ValueName), "NotesData%d", NotesCount - I - 1); // we do not reverse notes in DB
-
- db_set_blob(0, MODULENAME, ValueName, Value, n+1);
-
- SAFE_FREE((void**)&Value);
- if (bDeleteTData)
- SAFE_FREE((void**)&tData);
-
- // make no save is queued for the note
- if (pNote->SNHwnd)
- KillTimer(pNote->SNHwnd, 1025);
- }
-
- // delete any left over DB note entries
- for(; I < OldNotesCount; I++)
- {
- mir_snprintf(ValueName, SIZEOF(ValueName), "NotesData%d", I);
- db_unset(0,MODULENAME,ValueName);
- }
-
- NOTIFY_LIST();
-}
-
-__inline void JustSaveNotes(void)
-{
- JustSaveNotesEx(NULL);
-}
-
-
-/////////////////////////////////////////////////////////////////////
-// Note Window
-
-static int FindMenuItem(HMENU h, LPTSTR lpszName)
-{
- UINT i;
- TCHAR s[128];
-
- int n = GetMenuItemCount(h);
-
- if (n <= 0)
- {
- return -1;
- }
-
- // searches for a menu item based on name (used to avoid hardcoding item indices for sub-menus)
- for (i=0; i<(UINT)n; i++)
- {
- if ( GetMenuString(h, i, s, 128, MF_BYPOSITION) )
- {
- if ( !_tcscmp(s, lpszName) )
- {
- return (int)i;
- }
- }
- }
-
- return -1;
-}
-
-static BOOL DoContextMenu(HWND AhWnd,WPARAM wParam,LPARAM lParam)
-{
- int n, i;
- STICKYNOTE *SN = (STICKYNOTE*)GetProp(AhWnd, _T("ctrldata"));
-
- HMENU hMenuLoad, FhMenu, hSub;
- hMenuLoad = LoadMenu(hinstance, _T("MNU_NOTEPOPUP"));
- FhMenu = GetSubMenu(hMenuLoad,0);
-
- if (SN->OnTop)
- CheckMenuItem(FhMenu, IDM_TOGGLEONTOP, MF_CHECKED|MF_BYCOMMAND);
-
- EnableMenuItem(FhMenu, ID_CONTEXTMENUNOTEPOPUP_PASTETITLE, MF_BYCOMMAND | (IsClipboardFormatAvailable(CF_TEXT) ? MF_ENABLED : MF_GRAYED));
-
- if (!SN->CustomTitle)
- EnableMenuItem(FhMenu, ID_CONTEXTMENUNOTEPOPUP_RESETTITLE, MF_BYCOMMAND | MF_GRAYED);
-
- // NOTE: names used for FindMenuItem would need to include & chars if such shortcuts are added to the menus
-
- n = FindMenuItem(FhMenu, _T("Appearance"));
- if (n >= 0 && (hSub = GetSubMenu(FhMenu, n)))
- {
- HMENU hBg = GetSubMenu(hSub, FindMenuItem(hSub, _T("Background Color")));
- HMENU hFg = GetSubMenu(hSub, FindMenuItem(hSub, _T("Text Color")));
-
- for (i=0; i<SIZEOF(clrPresets); i++)
- InsertMenu(hBg, i, MF_BYPOSITION|MF_OWNERDRAW, IDM_COLORPRESET_BG+i, TranslateTS(clrPresets[i].szName));
-
- for (i=0; i<SIZEOF(clrPresets); i++)
- InsertMenu(hFg, i, MF_BYPOSITION|MF_OWNERDRAW, IDM_COLORPRESET_FG+i, TranslateTS(clrPresets[i].szName));
- }
-
- CallService(MS_LANGPACK_TRANSLATEMENU,(DWORD)FhMenu,0);
- TrackPopupMenu(FhMenu,TPM_LEFTALIGN | TPM_RIGHTBUTTON,LOWORD(lParam),HIWORD(lParam),0,AhWnd,0);
- DestroyMenu(hMenuLoad);
-
- return TRUE;
-}
-
-static void MeasureColorPresetMenuItem(HWND hdlg, LPMEASUREITEMSTRUCT lpMeasureItem, struct ColorPreset *clrPresets)
-{
- HDC hdc = GetDC(hdlg);
- LPTSTR lpsz = TranslateTS(clrPresets->szName);
- SIZE sz;
- GetTextExtentPoint32(hdc, lpsz, (int)_tcslen(lpsz), &sz);
- ReleaseDC(hdlg, hdc);
-
- lpMeasureItem->itemWidth = 50 + sz.cx;
- lpMeasureItem->itemHeight = (sz.cy+2)>18 ? sz.cy+2 : 18;
-}
-
-static void PaintColorPresetMenuItem(LPDRAWITEMSTRUCT lpDrawItem, struct ColorPreset *clrPresets)
-{
- UINT n = lpDrawItem->itemID - IDM_COLORPRESET_BG;
- RECT rect;
- rect.left = lpDrawItem->rcItem.left + 50;
- rect.top = lpDrawItem->rcItem.top;
- rect.right = lpDrawItem->rcItem.right;
- rect.bottom = lpDrawItem->rcItem.bottom;
-
- if (lpDrawItem->itemState & ODS_SELECTED)
- {
- SetDCBrushColor(lpDrawItem->hDC, GetSysColor(COLOR_MENUHILIGHT));
- FillRect(lpDrawItem->hDC, &lpDrawItem->rcItem, (HBRUSH)GetStockObject(DC_BRUSH));
-
- SetTextColor(lpDrawItem->hDC, GetSysColor(COLOR_HIGHLIGHTTEXT));
- }
- else
- {
- SetDCBrushColor(lpDrawItem->hDC, GetSysColor(COLOR_MENU));
- FillRect(lpDrawItem->hDC, &lpDrawItem->rcItem, (HBRUSH)GetStockObject(DC_BRUSH));
-
- SetTextColor(lpDrawItem->hDC, GetSysColor(COLOR_MENUTEXT));
- }
-
- SetBkMode(lpDrawItem->hDC, TRANSPARENT);
- DrawText(lpDrawItem->hDC,clrPresets->szName,-1,&rect,DT_LEFT | DT_SINGLELINE | DT_END_ELLIPSIS | DT_VCENTER);
-
- {
- int h = lpDrawItem->rcItem.bottom - lpDrawItem->rcItem.top;
- rect.left = lpDrawItem->rcItem.left + 5;
- rect.top = lpDrawItem->rcItem.top + ((h-14)>>1);
- rect.right = rect.left + 40;
- rect.bottom = rect.top + 14;
-
- FrameRect(lpDrawItem->hDC, &rect, (HBRUSH)GetStockObject(BLACK_BRUSH));
- rect.left++; rect.top++;
- rect.right--; rect.bottom--;
- SetDCBrushColor(lpDrawItem->hDC, clrPresets->color);
- FillRect(lpDrawItem->hDC, &rect, (HBRUSH)GetStockObject(DC_BRUSH));
- }
-}
-
-static BOOL GetClipboardText_Title(char *pOut, int size)
-{
- BOOL bResult = FALSE;
-
- if ( OpenClipboard(NULL) )
- {
- HANDLE hData = GetClipboardData(CF_TEXT);
- LPCSTR buffer;
-
- if (hData && (buffer = (LPCSTR)GlobalLock(hData)))
- {
- // trim initial white spaces
- while (*buffer && isspace(*buffer))
- buffer++;
-
- if (buffer)
- {
- char *p;
-
- int n = (int)strlen(buffer);
- if (n >= size)
- n = size-1;
- memcpy(pOut, buffer, n);
- pOut[n] = 0;
-
- // end string on line break and convert tabs to spaces
- p = pOut;
- while (*p)
- {
- if (*p == '\r' || *p == '\n')
- {
- *p = 0;
- n = (int)strlen(pOut);
- break;
- }
- else if (*p == '\t')
- {
- *p = ' ';
- }
- p++;
- }
-
- // trim trailing white spaces
- while (n && isspace(pOut[n-1]))
- pOut[--n] = 0;
-
- if (n)
- bResult = TRUE;
- }
-
- GlobalUnlock(hData);
- }
-
- CloseClipboard();
- }
-
- return bResult;
-}
-
-static void SetNoteTextControl(STICKYNOTE *SN)
-{
- CHARFORMAT CF = {0};
- CF.cbSize = sizeof(CHARFORMAT);
- CF.dwMask = CFM_COLOR;
- CF.crTextColor = SN->FgColor ? (SN->FgColor&0xffffff) : BodyFontColor;
- SendMessage(SN->REHwnd, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&CF);
-
- if (SN->data) // TODO: use EM_STREAMIN
- SendMessage(SN->REHwnd, WM_SETTEXT, 0, (LPARAM)(SN->data));
-}
-
-
-static UINT_PTR CALLBACK CFHookProc(HWND hdlg, UINT msg, WPARAM wParam, LPARAM lParam)
-{
- if (msg == WM_INITDIALOG)
- {
- // hide color selector
- ShowWindow(GetDlgItem(hdlg,0x443), SW_HIDE);
- ShowWindow(GetDlgItem(hdlg,0x473), SW_HIDE);
- TranslateDialogDefault(hdlg);
- }
-
- return 0;
-}
-
-
-INT_PTR CALLBACK StickyNoteWndProc(HWND hdlg,UINT message,WPARAM wParam,LPARAM lParam)
-{
- switch (message)
- {
- case WM_CLOSE:
- return TRUE;
-
- case WM_SIZE:
- {
- RECT SZ;
-
- GetClientRect(hdlg,&SZ);
- HWND H = GetDlgItem(hdlg,1);
- MoveWindow(H, 0, 0, SZ.right,SZ.bottom, TRUE);
-
- KillTimer(hdlg, 1025);
- SetTimer(hdlg, 1025, NOTE_CHANGE_COMMIT_DELAY, 0);
-
- return TRUE;
- }
- case WM_TIMER:
- if (wParam == 1025)
- {
- STICKYNOTE *SN = (STICKYNOTE*)GetProp(hdlg,_T("ctrldata"));
-
- KillTimer(hdlg, 1025);
- JustSaveNotesEx(SN);
- }
- break;
- case WM_MOVE:
- {
- KillTimer(hdlg, 1025);
- SetTimer(hdlg, 1025, NOTE_CHANGE_COMMIT_DELAY, 0);
- return TRUE;
- }
- case WM_CREATE:
- {
- STICKYNOTE *SN = (STICKYNOTE*)GetProp(hdlg,_T("ctrldata"));
-
- CREATESTRUCT *CS = (CREATESTRUCT *)lParam;
- HWND H;
- DWORD mystyle;
-
- SN = (STICKYNOTE*)CS->lpCreateParams;
- SetProp(hdlg,_T("ctrldata"),(HANDLE)SN);
- BringWindowToTop(hdlg);
- mystyle = WS_CHILD | WS_VISIBLE | ES_LEFT | ES_MULTILINE | ES_AUTOVSCROLL | ES_WANTRETURN;
- if (g_ShowScrollbar) mystyle |= WS_VSCROLL;
- H = CreateWindow(RICHEDIT_CLASS, 0, mystyle, 0, 0, CS->cx-3-3, CS->cy-3-(3+14), hdlg, (HMENU)1, hmiranda, 0);
- SN->REHwnd = H;
- SendMessage(H, EM_SETTEXTMODE, TM_PLAINTEXT, 0);
- SendMessage(H, EM_LIMITTEXT, MAX_NOTE_LEN, 0);
- SendMessage(H, WM_SETFONT, (WPARAM)(SN->pCustomFont ? SN->pCustomFont->hFont : hBodyFont), 1);
- SendMessage(H, EM_SETEVENTMASK, 0, ENM_CHANGE | ENM_LINK);
- SendMessage(H, EM_SETBKGNDCOLOR, 0, SN->BgColor ? (SN->BgColor&0xffffff) : BodyColor);
- SendMessage(H, EM_AUTOURLDETECT, 1, 0);
- SetNoteTextControl(SN);
- return TRUE;
- }
- case WM_GETMINMAXINFO:
- {
- MINMAXINFO *mm = (MINMAXINFO*)lParam;
- // min width accomodates frame, buttons and some extra space for sanity
- mm->ptMinTrackSize.x = 48+3+3+8 + 40;
- // min height allows collapsing entire client area, only leaving frame and caption
- mm->ptMinTrackSize.y = 3+3+14;
- }
- return 0;
- case WM_ERASEBKGND:
- // no BG needed as edit control takes up entire client area
- return TRUE;
- case WM_NCPAINT:
- // make window borders have the same color as caption
- {
- STICKYNOTE *SN = (STICKYNOTE*)GetProp(hdlg,"ctrldata");
-
- HBRUSH hBkBrush;
- RECT rect, wr, r;
- //HDC hdc = GetDCEx(hdlg, (HRGN)wParam, DCX_WINDOW|DCX_INTERSECTRGN);
- HDC hdc = GetWindowDC(hdlg);
-
- GetWindowRect(hdlg, &wr);
- if (wParam && wParam != 1)
- {
- SelectClipRgn(hdc, (HRGN)wParam);
- OffsetClipRgn(hdc, -wr.left, -wr.top);
- }
-
- rect = wr;
- OffsetRect(&rect, -wr.left, -wr.top);
-
- hBkBrush = (HBRUSH)GetStockObject(DC_BRUSH);
- SetDCBrushColor(hdc, GetCaptionColor((SN && SN->BgColor) ? SN->BgColor : BodyColor));
-
- // draw all frame sides separately to avoid filling client area (which flickers)
- {
- // top
- r.left = rect.left; r.right = rect.right;
- r.top = rect.top; r.bottom = r.top + 3+14;
- FillRect(hdc, &r, hBkBrush);
- // bottom
- r.top = rect.bottom - 3; r.bottom = rect.bottom;
- FillRect(hdc, &r, hBkBrush);
- // left
- r.left = rect.left; r.right = r.left + 3;
- r.top = rect.top + 3+14; r.bottom = rect.bottom - 3;
- FillRect(hdc, &r, hBkBrush);
- // right
- r.left = rect.right - 3; r.right = rect.right;
- FillRect(hdc, &r, hBkBrush);
- }
-
- // paint title bar contents (time stamp and buttons)
-
- if (SN && SN->title)
- {
- RECT R;
- SelectObject(hdc,hCaptionFont);
- R.top = 3+1; R.bottom = 3+11; R.left = 3+2; R.right = rect.right-3-1;
- if (g_ShowNoteButtons)
- R.right -= 48;
-
- SetTextColor(hdc,SN->FgColor ? (SN->FgColor&0xffffff) : CaptionFontColor);
- SetBkMode(hdc, TRANSPARENT);
- DrawText(hdc,SN->title,-1,&R,DT_LEFT | DT_SINGLELINE | DT_END_ELLIPSIS | DT_VCENTER);
- }
-
- if (g_ShowNoteButtons)
- {
- HICON hcIcon;
- if (SN->OnTop)
- hcIcon = Skin_GetIconByHandle(iconList[4].hIcolib);
- else
- hcIcon = Skin_GetIconByHandle(iconList[7].hIcolib);
- DrawIcon(hdc, wr.right - wr.left - 16, 0 + 3, hcIcon);
- Skin_ReleaseIcon(hcIcon);
-
- hcIcon = Skin_GetIconByHandle(iconList[9].hIcolib);
- DrawIcon(hdc, wr.right - wr.left - 32, 1 + 3, hcIcon);
- Skin_ReleaseIcon(hcIcon);
-
- hcIcon = Skin_GetIconByHandle(iconList[8].hIcolib);
- DrawIcon(hdc, wr.right - wr.left - 48, 1 + 3, hcIcon);
- Skin_ReleaseIcon(hcIcon);
- }
-
- if (wParam && wParam != 1)
- {
- SelectClipRgn(hdc, NULL);
- }
-
- ReleaseDC(hdlg, hdc);
- return TRUE;
- }
- case WM_NCCALCSIZE:
- {
- RECT *pRect = wParam ? &((NCCALCSIZE_PARAMS*)lParam)->rgrc[0] : (RECT*)lParam;
- pRect->bottom -= 3;
- pRect->right -= 3;
- pRect->left += 3;
- pRect->top += 3+14;
- return WVR_REDRAW;
- }
- case WM_NCACTIVATE:
- // update window (so that parts that potentially became visible through activation get redrawn immediately)
- RedrawWindow(hdlg, NULL, NULL, RDW_UPDATENOW);
- return TRUE;
- case WM_NOTIFY:
- if (LOWORD(wParam) == 1)
- {
- char *Buff;
- PENLINK PEnLnk = (PENLINK)lParam;
-
- if (PEnLnk->msg == WM_LBUTTONDOWN)
- {
- SendDlgItemMessage(hdlg,1,EM_EXSETSEL,0,(LPARAM)&(PEnLnk->chrg));
- Buff = (char*)malloc(PEnLnk->chrg.cpMax - PEnLnk->chrg.cpMin + 1);
- SendDlgItemMessage(hdlg,1,EM_GETSELTEXT,0,(LPARAM)Buff);
- if ((GetAsyncKeyState(VK_CONTROL) >> 15) != 0)
- ShellExecute(hdlg, _T("open"), _T("iexplore"), Buff, _T("") ,SW_SHOWNORMAL);
- else if (g_lpszAltBrowser && *g_lpszAltBrowser)
- ShellExecute(hdlg,_T("open"), g_lpszAltBrowser, Buff, _T("") ,SW_SHOWNORMAL);
- else
- ShellExecute(hdlg, _T("open"), Buff, _T(""), _T(""), SW_SHOWNORMAL);
- SAFE_FREE((void**)&Buff);
- return TRUE;
- }
- return FALSE;
- }
- break;
- case WM_NCHITTEST:
- {
- int r = DefWindowProc(hdlg,message,wParam,lParam);
- // filter out potential hits on windows default title bar buttons
- switch (r)
- {
- case HTSYSMENU:
- case HTCLOSE:
- case HTMINBUTTON:
- case HTMAXBUTTON:
- return HTCAPTION;
- }
- return r;
- }
- case WM_NCLBUTTONDOWN:
- if (wParam == HTCAPTION && g_ShowNoteButtons)
- {
- long X,Y;
- RECT rect;
- int Tw;
-
- GetWindowRect(hdlg, &rect);
- Tw = rect.right - rect.left;
-
- X = LOWORD(lParam) - rect.left;
- Y = HIWORD(lParam) - rect.top;
-
- if (X > Tw - 16)
- {
- SendMessage(hdlg,WM_COMMAND,IDM_TOGGLEONTOP,0);
- return TRUE;
- }
- else if (X > Tw - 31 && X < Tw - 16)
- {
- SendMessage(hdlg,WM_COMMAND,IDM_REMOVENOTE,0);
- return TRUE;
- }
- else if (X > Tw - 48 && X < Tw - 32)
- {
- SendMessage(hdlg,WM_COMMAND,IDM_HIDENOTE,0);
- return TRUE;
- }
- }
- return DefWindowProc(hdlg,message,wParam,lParam);
- case WM_MEASUREITEM:
- {
- LPMEASUREITEMSTRUCT lpMeasureItem = (LPMEASUREITEMSTRUCT)lParam;
-
- if (lpMeasureItem->CtlType != ODT_MENU)
- break;
-
- if (lpMeasureItem->itemID >= IDM_COLORPRESET_BG && lpMeasureItem->itemID <= IDM_COLORPRESET_BG+SIZEOF(clrPresets))
- {
- MeasureColorPresetMenuItem(hdlg, lpMeasureItem, clrPresets + (lpMeasureItem->itemID - IDM_COLORPRESET_BG));
- return TRUE;
- }
- else if (lpMeasureItem->itemID >= IDM_COLORPRESET_FG && lpMeasureItem->itemID <= IDM_COLORPRESET_FG+SIZEOF(clrPresets))
- {
- MeasureColorPresetMenuItem(hdlg, lpMeasureItem, clrPresets + (lpMeasureItem->itemID - IDM_COLORPRESET_FG));
- return TRUE;
- }
- }
- break;
- case WM_DRAWITEM:
- if (!wParam)
- {
- LPDRAWITEMSTRUCT lpDrawItem = (LPDRAWITEMSTRUCT)lParam;
-
- if (lpDrawItem->CtlType != ODT_MENU)
- break;
-
- if (lpDrawItem->itemID >= IDM_COLORPRESET_BG && lpDrawItem->itemID <= IDM_COLORPRESET_BG+SIZEOF(clrPresets))
- {
- PaintColorPresetMenuItem(lpDrawItem, clrPresets + (lpDrawItem->itemID - IDM_COLORPRESET_BG));
- return TRUE;
- }
- else if (lpDrawItem->itemID >= IDM_COLORPRESET_FG && lpDrawItem->itemID <= IDM_COLORPRESET_FG+SIZEOF(clrPresets))
- {
- PaintColorPresetMenuItem(lpDrawItem, clrPresets + (lpDrawItem->itemID - IDM_COLORPRESET_FG));
- return TRUE;
- }
- }
- break;
- case WM_COMMAND:
- {
- STICKYNOTE *SN = (STICKYNOTE*)GetProp(hdlg, _T("ctrldata"));
-
- HWND H;
- UINT id;
-
- switch ( HIWORD(wParam) )
- {
- case EN_CHANGE:
- case EN_VSCROLL:
- case EN_HSCROLL:
- {
- KillTimer(hdlg,1025);
- SetTimer(hdlg, 1025, NOTE_CHANGE_COMMIT_DELAY, 0);
- }
- break;
- }
-
- id = (UINT) LOWORD(wParam);
-
- H = SN->REHwnd;
-
- if (id >= IDM_COLORPRESET_BG && id <= IDM_COLORPRESET_BG+SIZEOF(clrPresets))
- {
- SN->BgColor = clrPresets[id-IDM_COLORPRESET_BG].color | 0xff000000;
- SendMessage(H, EM_SETBKGNDCOLOR, 0, (LPARAM)(SN->BgColor&0xffffff));
- RedrawWindow(SN->SNHwnd, NULL, NULL, RDW_INVALIDATE|RDW_FRAME|RDW_UPDATENOW);
- JustSaveNotes();
- return FALSE;
- }
- else if (id >= IDM_COLORPRESET_FG && id <= IDM_COLORPRESET_FG+SIZEOF(clrPresets))
- {
- CHARFORMAT CF = {0};
- SN->FgColor = clrPresets[id-IDM_COLORPRESET_FG].color | 0xff000000;
- CF.cbSize = sizeof(CHARFORMAT);
- CF.dwMask = CFM_COLOR;
- CF.crTextColor = SN->FgColor & 0xffffff;
- SendMessage(H, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&CF);
- RedrawWindow(SN->SNHwnd, NULL, NULL, RDW_INVALIDATE|RDW_FRAME|RDW_UPDATENOW);
- JustSaveNotes();
- return FALSE;
- }
-
- switch (id)
- {
- case ID_CONTEXTMENUNOTEPOPUP_NEWNOTE:
- {
- PluginMenuCommandAddNew(0,0);
- }
- break;
- case ID_APPEARANCE_CUSTOMBG:
- {
- COLORREF custclr[16] = {0};
- CHOOSECOLOR cc = {0};
- COLORREF orgclr = SN->BgColor ? (COLORREF)(SN->BgColor&0xffffff) : (COLORREF)(BodyColor&0xffffff);
- cc.lStructSize = sizeof(cc);
- cc.hwndOwner = SN->SNHwnd;
- cc.rgbResult = orgclr;
- cc.Flags = CC_ANYCOLOR | CC_FULLOPEN | CC_RGBINIT | CC_SOLIDCOLOR;
- cc.lpCustColors = custclr;
-
- if (ChooseColor(&cc) && cc.rgbResult != orgclr)
- {
- SN->BgColor = cc.rgbResult | 0xff000000;
- SendMessage(H, EM_SETBKGNDCOLOR, 0, (LPARAM)(SN->BgColor&0xffffff));
- RedrawWindow(SN->SNHwnd, NULL, NULL, RDW_INVALIDATE|RDW_FRAME|RDW_UPDATENOW);
- JustSaveNotes();
- }
- }
- break;
- case ID_APPEARANCE_CUSTOMTEXT:
- {
- COLORREF custclr[16] = {0};
- CHOOSECOLOR cc = {0};
- COLORREF orgclr = SN->FgColor ? (COLORREF)(SN->FgColor&0xffffff) : (COLORREF)(BodyFontColor&0xffffff);
- cc.lStructSize = sizeof(cc);
- cc.hwndOwner = SN->SNHwnd;
- cc.rgbResult = orgclr;
- cc.Flags = CC_ANYCOLOR | CC_FULLOPEN | CC_RGBINIT | CC_SOLIDCOLOR;
- cc.lpCustColors = custclr;
-
- if (ChooseColor(&cc) && cc.rgbResult != orgclr)
- {
- CHARFORMAT CF = {0};
- SN->FgColor = cc.rgbResult | 0xff000000;
- CF.cbSize = sizeof(CHARFORMAT);
- CF.dwMask = CFM_COLOR;
- CF.crTextColor = SN->FgColor & 0xffffff;
- SendMessage(H, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&CF);
- RedrawWindow(SN->SNHwnd, NULL, NULL, RDW_INVALIDATE|RDW_FRAME|RDW_UPDATENOW);
- JustSaveNotes();
- }
- }
- break;
- case ID_APPEARANCE_CUSTOMFONT:
- {
- CHOOSEFONT cf = {0};
- LOGFONT lf = {0};
-
- if (SN->pCustomFont)
- InitStickyNoteLogFont(SN->pCustomFont, &lf);
- else
- LoadNRFont(NR_FONTID_BODY, &lf, NULL);
-
- cf.lStructSize = sizeof(cf);
- cf.hwndOwner = SN->SNHwnd;
- cf.lpLogFont = &lf;
- cf.Flags = CF_EFFECTS | CF_FORCEFONTEXIST | CF_INITTOLOGFONTSTRUCT | CF_SCREENFONTS | CF_ENABLEHOOK;
- cf.lpfnHook = CFHookProc;
-
- if ( ChooseFont(&cf) )
- {
- if (!SN->pCustomFont)
- {
- SN->pCustomFont = (STICKYNOTEFONT*)malloc(sizeof(STICKYNOTEFONT));
- SN->pCustomFont->hFont = NULL;
- }
-
- SN->pCustomFont->size = (char)lf.lfHeight;
- SN->pCustomFont->style = (lf.lfWeight >= FW_BOLD ? DBFONTF_BOLD : 0) | (lf.lfItalic ? DBFONTF_ITALIC : 0) | (lf.lfUnderline ? DBFONTF_UNDERLINE : 0) | (lf.lfStrikeOut ? DBFONTF_STRIKEOUT : 0);
- SN->pCustomFont->charset = lf.lfCharSet;
- _tcscpy(SN->pCustomFont->szFace, lf.lfFaceName);
-
- if ( !CreateStickyNoteFont(SN->pCustomFont, &lf) )
- {
- // failed
- free(SN->pCustomFont);
- SN->pCustomFont = NULL;
- }
-
- // clear text first to force a reformatting w.r.t scrollbar
- SendMessage(H, WM_SETTEXT, 0, (LPARAM)"");
- SendMessage(H, WM_SETFONT, (WPARAM)(SN->pCustomFont ? SN->pCustomFont->hFont : hBodyFont), FALSE);
- SetNoteTextControl(SN);
- RedrawWindow(SN->SNHwnd, NULL, NULL, RDW_INVALIDATE|RDW_FRAME|RDW_UPDATENOW);
- JustSaveNotes();
- }
- }
- break;
- case ID_BACKGROUNDCOLOR_RESET:
- {
- SN->BgColor = 0;
- SendMessage(H, EM_SETBKGNDCOLOR, 0, (LPARAM)BodyColor);
- RedrawWindow(SN->SNHwnd, NULL, NULL, RDW_INVALIDATE|RDW_FRAME|RDW_UPDATENOW);
- JustSaveNotes();
- }
- break;
- case ID_TEXTCOLOR_RESET:
- {
- CHARFORMAT CF = {0};
- SN->FgColor = 0;
- CF.cbSize = sizeof(CHARFORMAT);
- CF.dwMask = CFM_COLOR;
- CF.crTextColor = BodyFontColor;
- SendMessage(H, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&CF);
- RedrawWindow(SN->SNHwnd, NULL, NULL, RDW_INVALIDATE|RDW_FRAME|RDW_UPDATENOW);
- JustSaveNotes();
- }
- break;
- case ID_FONT_RESET:
- {
- if (SN->pCustomFont)
- {
- DeleteObject(SN->pCustomFont->hFont);
- free(SN->pCustomFont);
- SN->pCustomFont = NULL;
-
- // clear text first to force a reformatting w.r.t scrollbar
- SendMessage(H, WM_SETTEXT, 0, (LPARAM)"");
- SendMessage(H, WM_SETFONT, (WPARAM)hBodyFont, FALSE);
- SetNoteTextControl(SN);
- RedrawWindow(SN->SNHwnd, NULL, NULL, RDW_INVALIDATE|RDW_FRAME|RDW_UPDATENOW);
- JustSaveNotes();
- }
- }
- break;
- case ID_CONTEXTMENUNOTEPOPUP_PASTETITLE:
- {
- char s[MAX_TITLE_LEN+1];
- if ( GetClipboardText_Title(s, sizeof(s)) )
- {
- if (SN->title)
- free(SN->title);
- SN->title = _strdup(s);
- SN->CustomTitle = TRUE;
- RedrawWindow(SN->SNHwnd, NULL, NULL, RDW_INVALIDATE|RDW_FRAME|RDW_UPDATENOW);
- JustSaveNotes();
- }
- }
- break;
- case ID_CONTEXTMENUNOTEPOPUP_RESETTITLE:
- if (SN->CustomTitle)
- {
- if (SN->title)
- {
- free(SN->title);
- SN->title = NULL;
- }
- InitNoteTitle(SN);
- RedrawWindow(SN->SNHwnd, NULL, NULL, RDW_INVALIDATE|RDW_FRAME|RDW_UPDATENOW);
- JustSaveNotes();
- }
- break;
- case IDM_REMOVENOTE:
- OnDeleteNote(hdlg, SN);
- break;
- case IDM_HIDENOTE:
- {
- SN->Visible = FALSE;
- ShowWindow(hdlg,SW_HIDE);
- JustSaveNotes();
- }
- break;
- case IDM_COPY: SendMessage(H,WM_COPY,0,0); break;
- case IDM_PASTE: SendMessage(H,WM_PASTE,0,0); break;
- case IDM_CUT: SendMessage(H,WM_CUT,0,0); break;
- case IDM_CLEAR: SendMessage(H,WM_CLEAR,0,0); break;
- case IDM_UNDO: SendMessage(H,WM_UNDO,0,0); break;
- case IDM_TOGGLEONTOP:
- {
- SN->OnTop = !SN->OnTop;
- SetWindowPos(hdlg, SN->OnTop ? HWND_TOPMOST : HWND_NOTOPMOST, 0,0,0,0, SWP_SHOWWINDOW|SWP_NOMOVE|SWP_NOSIZE);
- RedrawWindow(hdlg, NULL, NULL, RDW_FRAME|RDW_INVALIDATE|RDW_UPDATENOW);
- JustSaveNotes();
- }
- break;
- case ID_CONTEXTMENUNOTEPOPUP_VIEWNOTES:
- ListNotes();
- break;
- case ID_CONTEXTMENUNOTEPOPUP_BRINGALLTOTOP:
- BringAllNotesToFront(SN);
- break;
- }
- return TRUE;
- }
- case WM_NCDESTROY:
- {
- RemoveProp(hdlg, _T("ctrldata"));
- }
- break;
- case WM_CONTEXTMENU:
- if (DoContextMenu(hdlg,wParam,lParam)) return FALSE;
-
- default:
- return DefWindowProc(hdlg,message,wParam,lParam);
- }
- return FALSE;
-}
-
-
-/////////////////////////////////////////////////////////////////////
-// Notes List Dialog (uses same dialog template as reminder list)
-
-void ListNotes(void)
-{
- if (!ListNotesVisible)
- {
- CreateDialog(hinstance, MAKEINTRESOURCE(IDD_LISTREMINDERS), 0, DlgProcViewNotes);
- ListNotesVisible = TRUE;
- }
- else
- {
- BringWindowToTop(LV);
- }
-}
-
-static void EditNote(STICKYNOTE *SN)
-{
- if (!SN)
- return;
-
- if (!SN->Visible)
- {
- SN->Visible = TRUE;
- JustSaveNotes();
- }
-
- SetWindowPos(SN->SNHwnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
- if (!SN->OnTop)
- SetWindowPos(SN->SNHwnd, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
-
- SetFocus(SN->REHwnd);
-}
-
-char* GetPreviewString(const char *lpsz)
-{
- int l;
- char *p;
- const int MaxLen = 80;
- static char s[80+8];
-
- if (!lpsz)
- return "";
-
- // trim leading spaces
- while ( iswspace(*lpsz) )
- lpsz++;
-
- l = (int)strlen(lpsz);
-
- if (!l)
- return "";
-
- if (l <= MaxLen)
- {
- strcpy(s, lpsz);
- }
- else
- {
- memcpy(s, lpsz, MaxLen);
- s[MaxLen] = '.';
- s[MaxLen+1] = '.';
- s[MaxLen+2] = '.';
- s[MaxLen+3] = 0;
- }
-
- if (!s)
- return NULL;
-
- // convert line breaks and tabs to spaces
-
- p = s;
-
- while (*p)
- {
- if ( iswspace(*p) )
- *p = ' ';
- p++;
- }
-
- return s;
-}
-
-static void InitListView(HWND AHLV)
-{
- LV_ITEM lvTIt;
- int I;
- char *S;
- char S1[128];
- STICKYNOTE *pNote;
- TREEELEMENT *TTE;
-
- char *V = Translate("Visible");
- char *T = Translate("Top");
-
- ListView_SetHoverTime(AHLV,700);
- ListView_SetExtendedListViewStyle(AHLV,LVS_EX_FULLROWSELECT | LVS_EX_GRIDLINES | LVS_EX_TRACKSELECT);
- ListView_DeleteAllItems(AHLV);
-
- I = 0;
- TTE = g_Stickies;
- while (TTE)
- {
- pNote = (STICKYNOTE*)TTE->ptrdata;
-
- lvTIt.mask = LVIF_TEXT;
-
- if (!pNote->CustomTitle || !pNote->title)
- GetTriggerTimeString(&pNote->ID, S1, sizeof(S1), TRUE);
-
- lvTIt.iItem = I;
- lvTIt.iSubItem = 0;
- lvTIt.pszText = (pNote->CustomTitle && pNote->title) ? pNote->title : S1;
- lvTIt.cchTextMax = (int)strlen(S1);
- ListView_InsertItem(AHLV,&lvTIt);
-
- if (pNote->Visible)
- {
- lvTIt.iItem = I;
- lvTIt.iSubItem = 1;
- lvTIt.pszText = V;
- lvTIt.cchTextMax = (int)strlen(lvTIt.pszText);
- ListView_SetItem(AHLV,&lvTIt);
- }
-
- if (pNote->OnTop)
- {
- lvTIt.iItem = I;
- lvTIt.iSubItem = 2;
- lvTIt.pszText = T;
- lvTIt.cchTextMax = (int)strlen(lvTIt.pszText);
- ListView_SetItem(AHLV,&lvTIt);
- }
-
- S = GetPreviewString(pNote->data);
- lvTIt.iItem = I;
- lvTIt.iSubItem = 3;
- lvTIt.pszText = S;
- lvTIt.cchTextMax = (int)strlen(S);
- ListView_SetItem(AHLV,&lvTIt);
-
- I++;
- TTE = (TREEELEMENT*)TTE->next;
- }
-
- ListView_SetItemState(AHLV,0,LVIS_SELECTED,LVIS_SELECTED);
-}
-
-static BOOL DoListContextMenu(HWND AhWnd,WPARAM wParam,LPARAM lParam,STICKYNOTE *pNote)
-{
- HWND hwndListView;
- HMENU hMenuLoad,FhMenu;
- MENUITEMINFO mii;
-
- hwndListView = (HWND)wParam;
- if (hwndListView != GetDlgItem(AhWnd,IDC_LISTREMINDERS)) return FALSE;
- hMenuLoad = LoadMenu(hinstance,"MNU_NOTELISTPOPUP");
- FhMenu = GetSubMenu(hMenuLoad,0);
-
- mii.cbSize = sizeof(mii);
- mii.fMask = MIIM_STATE;
- mii.fState = MFS_DEFAULT;
- if (!pNote)
- mii.fState |= MFS_GRAYED;
- SetMenuItemInfo(FhMenu, ID_CONTEXTMENUNOTELISTVIEW_EDITNOTE, FALSE, &mii);
-
- if (!pNote)
- {
- EnableMenuItem(FhMenu, IDM_REMOVENOTE, MF_GRAYED|MF_BYCOMMAND);
- EnableMenuItem(FhMenu, ID_CONTEXTMENUNOTELISTVIEW_TOGGLEVISIBILITY, MF_GRAYED|MF_BYCOMMAND);
- EnableMenuItem(FhMenu, IDM_TOGGLEONTOP, MF_GRAYED|MF_BYCOMMAND);
- }
- else
- {
- if (pNote->Visible)
- CheckMenuItem(FhMenu, ID_CONTEXTMENUNOTELISTVIEW_TOGGLEVISIBILITY, MF_CHECKED|MF_BYCOMMAND);
- if (pNote->OnTop)
- CheckMenuItem(FhMenu, IDM_TOGGLEONTOP, MF_CHECKED|MF_BYCOMMAND);
- }
-
- CallService(MS_LANGPACK_TRANSLATEMENU,(DWORD)FhMenu,0);
- TrackPopupMenu(FhMenu,TPM_LEFTALIGN | TPM_RIGHTBUTTON,LOWORD(lParam),HIWORD(lParam),0,AhWnd,0);
- DestroyMenu(hMenuLoad);
-
- return TRUE;
-}
-
-
-INT_PTR CALLBACK DlgProcViewNotes(HWND Dialog,UINT Message,WPARAM wParam,LPARAM lParam)
-{
- LV_COLUMN lvCol;
- NMLISTVIEW *NM;
- TCHAR *S;
- int I;
-
- switch (Message)
- {
- case WM_SIZE:
- {
- OnListResize(Dialog);
- UpdateGeomFromWnd(Dialog, g_notesListGeom, NULL, 0);
- break;
- }
- case WM_MOVE:
- UpdateGeomFromWnd(Dialog, g_notesListGeom, NULL, 0);
- break;
- case WM_GETMINMAXINFO:
- {
- MINMAXINFO *mm = (MINMAXINFO*)lParam;
- mm->ptMinTrackSize.x = 394;
- mm->ptMinTrackSize.y = 300;
- }
- return 0;
- case WM_RELOAD:
- {
- SetDlgItemText(Dialog,IDC_REMINDERDATA,"");
- InitListView(GetDlgItem(Dialog,IDC_LISTREMINDERS));
- return TRUE;
- }
- case WM_CONTEXTMENU:
- {
- HWND H;
- STICKYNOTE *pNote = NULL;
-
- H = GetDlgItem(Dialog,IDC_LISTREMINDERS);
- if ( ListView_GetSelectedCount(H) )
- {
- I = ListView_GetSelectionMark(H);
- if (I != -1)
- {
- pNote = (STICKYNOTE*)TreeGetAt(g_Stickies, I);
- }
- }
-
- if (DoListContextMenu(Dialog, wParam, lParam, pNote))
- return TRUE;
- }
- break;
- case WM_INITDIALOG:
- {
- HWND H;
-
- HICON hIcon = Skin_GetIconByHandle(iconList[13].hIcolib, ICON_SMALL);
- SendMessage(Dialog, WM_SETICON, (WPARAM)ICON_SMALL, (LPARAM)hIcon);
- hIcon = Skin_GetIconByHandle(iconList[13].hIcolib, ICON_BIG);
- SendMessage(Dialog, WM_SETICON, (WPARAM)ICON_BIG, (LPARAM)hIcon);
-
- SetWindowText(Dialog, LPGENT("Notes"));
-
- TranslateDialogDefault(Dialog);
-
- SetDlgItemText(Dialog,IDC_REMINDERDATA, _T(""));
-
- H = GetDlgItem(Dialog,IDC_LISTREMINDERS);
- lvCol.mask = LVCF_TEXT | LVCF_WIDTH;
-
- S = TranslateT("Note text");
- lvCol.pszText = S;
- lvCol.cchTextMax = (int)_tcslen(S);
- lvCol.cx = g_notesListColGeom[3];
- ListView_InsertColumn(H,0,&lvCol);
- lvCol.mask = LVCF_TEXT | LVCF_WIDTH;
-
- S = TranslateT("Top");
- lvCol.pszText = S;
- lvCol.cchTextMax = (int)_tcslen(S);
- lvCol.cx = g_notesListColGeom[2];
- ListView_InsertColumn(H,0,&lvCol);
- lvCol.mask = LVCF_TEXT | LVCF_WIDTH;
-
- S = TranslateT("Visible");
- lvCol.pszText = S;
- lvCol.cchTextMax = (int)strlen(S);
- lvCol.cx = g_notesListColGeom[1];
- ListView_InsertColumn(H,0,&lvCol);
- lvCol.mask = LVCF_TEXT | LVCF_WIDTH;
-
- S = TranslateT("Date/Title");
- lvCol.pszText = S;
- lvCol.cchTextMax = (int)_tcslen(S);
- lvCol.cx = g_notesListColGeom[0];
- ListView_InsertColumn(H,0,&lvCol);
-
- InitListView(H);
- SetWindowLongPtr(GetDlgItem(H, 0), GWL_ID, IDC_LISTREMINDERS_HEADER);
- LV = Dialog;
-
- if (g_notesListGeom[1] && g_notesListGeom[2])
- {
- WINDOWPLACEMENT wp;
- wp.length = sizeof(WINDOWPLACEMENT);
- GetWindowPlacement(Dialog, &wp);
- wp.rcNormalPosition.left = g_notesListGeom[0];
- wp.rcNormalPosition.top = g_notesListGeom[1];
- wp.rcNormalPosition.right = g_notesListGeom[2] + g_notesListGeom[0];
- wp.rcNormalPosition.bottom = g_notesListGeom[3] + g_notesListGeom[1];
- SetWindowPlacement(Dialog, &wp);
- }
- return TRUE;
- }
- case WM_CLOSE:
- DestroyWindow(Dialog);
- ListNotesVisible = FALSE;
- return TRUE;
-
- case WM_DESTROY:
- ListNotesVisible = FALSE;
- Skin_ReleaseIcon((HICON)SendMessage(Dialog, WM_SETICON, ICON_BIG, 0));
- Skin_ReleaseIcon((HICON)SendMessage(Dialog, WM_SETICON, ICON_SMALL, 0));
- return TRUE;
-
- case WM_NOTIFY:
- {
- if (wParam == IDC_LISTREMINDERS)
- {
- NM = (NMLISTVIEW *)lParam;
- switch (NM->hdr.code)
- {
- case LVN_ITEMCHANGED:
- {
- S = ((STICKYNOTE*)TreeGetAt(g_Stickies,NM->iItem))->data;
- SetDlgItemText(Dialog,IDC_REMINDERDATA,S);
- }
- break;
- case NM_DBLCLK:
- {
- HWND H;
-
- H = GetDlgItem(Dialog,IDC_LISTREMINDERS);
- if ( ListView_GetSelectedCount(H) )
- {
- I = ListView_GetSelectionMark(H);
- if (I != -1)
- {
- EditNote((STICKYNOTE *)TreeGetAt(g_Stickies, I));
- }
- }
- }
- break;
- }
- }
- else if (wParam == IDC_LISTREMINDERS_HEADER)
- {
- NMHEADER *NM = (NMHEADER*)lParam;
- switch (NM->hdr.code)
- {
- case HDN_ENDTRACK:
- UpdateGeomFromWnd(Dialog, NULL, g_notesListColGeom, SIZEOF(g_notesListColGeom));
- break;
- }
- }
- }
- break;
- case WM_COMMAND:
- {
- switch(LOWORD(wParam))
- {
- case ID_CONTEXTMENUNOTELISTVIEW_EDITNOTE:
- {
- HWND H;
-
- H = GetDlgItem(Dialog,IDC_LISTREMINDERS);
- if ( ListView_GetSelectedCount(H) )
- {
- I = ListView_GetSelectionMark(H);
- if (I != -1)
- {
- EditNote((STICKYNOTE*)TreeGetAt(g_Stickies, I));
- }
- }
- }
- return TRUE;
- case ID_CONTEXTMENUNOTELISTVIEW_TOGGLEVISIBILITY:
- {
- HWND H;
-
- H = GetDlgItem(Dialog,IDC_LISTREMINDERS);
- if ( ListView_GetSelectedCount(H) )
- {
- I = ListView_GetSelectionMark(H);
- if (I != -1)
- {
- STICKYNOTE *SN = (STICKYNOTE*)TreeGetAt(g_Stickies, I);
- SN->Visible = !SN->Visible;
- ShowWindow(SN->SNHwnd,SN->Visible?SW_SHOWNA:SW_HIDE);
- JustSaveNotes();
- }
- }
- }
- return TRUE;
- case IDM_TOGGLEONTOP:
- {
- HWND H;
-
- H = GetDlgItem(Dialog,IDC_LISTREMINDERS);
- if ( ListView_GetSelectedCount(H) )
- {
- I = ListView_GetSelectionMark(H);
- if (I != -1)
- {
- STICKYNOTE *SN = (STICKYNOTE*)TreeGetAt(g_Stickies,I);
- SN->OnTop = !SN->OnTop;
- SetWindowPos(SN->SNHwnd, SN->OnTop ? HWND_TOPMOST : HWND_NOTOPMOST, 0,0,0,0, SWP_SHOWWINDOW|SWP_NOMOVE|SWP_NOSIZE);
- RedrawWindow(SN->SNHwnd, NULL, NULL, RDW_FRAME|RDW_INVALIDATE|RDW_UPDATENOW);
- JustSaveNotes();
- }
- }
- }
- return TRUE;
- case IDC_CLOSE:
- {
- DestroyWindow(Dialog);
- ListNotesVisible = FALSE;
- return TRUE;
- }
- case ID_CONTEXTMENUNOTEPOPUP_NEWNOTE:
- case IDC_ADDNEWREMINDER:
- {
- PluginMenuCommandAddNew(0,0);
- return TRUE;
- }
- case ID_CONTEXTMENUNOTELISTVIEW_DELETEALLNOTES:
- {
- PluginMenuCommandDeleteAll(0,0);
- return TRUE;
- }
- case IDM_REMOVENOTE:
- {
- HWND H;
-
- H = GetDlgItem(Dialog,IDC_LISTREMINDERS);
- if ( ListView_GetSelectedCount(H) )
- {
- I = ListView_GetSelectionMark(H);
- if (I != -1)
- {
- OnDeleteNote(Dialog, (STICKYNOTE*)TreeGetAt(g_Stickies, I));
- }
- }
- }
- return TRUE;
- case ID_CONTEXTMENUNOTELISTVIEW_SHOW:
- {
- ShowHideNotes();
- return TRUE;
- }
- case ID_CONTEXTMENUNOTEPOPUP_BRINGALLTOTOP:
- {
- BringAllNotesToFront(NULL);
- return TRUE;
- }
- }
- }
- }
- return FALSE;
-}
+#include "globals.h"
+
+#ifndef MONITOR_DEFAULTTONULL
+#define MONITOR_DEFAULTTONULL 0x00000000
+#endif
+
+
+// NotesData DB data params
+#define DATATAG_TEXT 1 // %s
+#define DATATAG_SCROLLPOS 2 // %u (specifies rich edit controls scroll post as first visible line)
+#define DATATAG_BGCOL 3 // %x (custom background color)
+#define DATATAG_FGCOL 4 // %x (custom text/fg colors)
+#define DATATAG_TITLE 5 // %s (custom note title)
+#define DATATAG_FONT 6 // %d:%u:%u:%s (custom font)
+
+
+#define MAX_TITLE_LEN 63
+#define MAX_NOTE_LEN 16384
+
+// delay before saving note changes (ms)
+#define NOTE_CHANGE_COMMIT_DELAY 1000
+
+
+#ifndef WS_EX_NOACTIVATE
+#define WS_EX_NOACTIVATE 0x08000000
+#endif
+#define IDM_REMOVENOTE 40001
+#define IDM_HIDENOTE 40002
+#define IDM_TOGGLEONTOP 40003
+#define IDM_UNDO 40004
+#define IDM_COPY 40005
+#define IDM_PASTE 40006
+#define IDM_CUT 40007
+#define IDM_CLEAR 40008
+#define WS_EX_LAYERED 0x00080000
+#define LWA_ALPHA 0x00000002
+
+#define IDC_LISTREMINDERS 1000
+#define IDC_LISTREMINDERS_HEADER 2000
+#define IDC_REMINDERDATA 1001
+#define IDC_ADDNEWREMINDER 1002
+#define IDC_CLOSE 1003
+#define WM_RELOAD (WM_USER + 100)
+
+#define NOTIFY_LIST() if (ListNotesVisible) PostMessage(LV,WM_RELOAD,0,0)
+
+#define PENLINK ENLINK *
+
+#define NOTE_WND_CLASS _T("MIM_StickyNote")
+
+
+#define IDM_COLORPRESET_BG 41000
+#define IDM_COLORPRESET_FG 41100
+
+
+static BOOL ListNotesVisible = FALSE;
+static HWND LV;
+
+
+struct ColorPreset
+{
+ TCHAR *szName;
+ COLORREF color;
+};
+
+static struct ColorPreset clrPresets[] =
+{
+ {LPGENT("Black"), RGB(0,0,0)},
+ {LPGENT("Maroon"), RGB(128,0,0)},
+ {LPGENT("Green"), RGB(0,128,0)},
+ {LPGENT("Olive"), RGB(128,128,0)},
+ {LPGENT("Navy"), RGB(0,0,128)},
+ {LPGENT("Purple"), RGB(128,0,128)},
+ {LPGENT("Teal"), RGB(0,128,128)},
+ {LPGENT("Gray"), RGB(128,128,128)},
+ {LPGENT("Silver"), RGB(192,192,192)},
+ {LPGENT("Red"), RGB(255,0,0)},
+ {LPGENT("Orange"), RGB(255,155,0)},
+ {LPGENT("Lime"), RGB(0,255,0)},
+ {LPGENT("Yellow"), RGB(255,255,0)},
+ {LPGENT("Blue"), RGB(0,0,255)},
+ {LPGENT("Fuchsia"), RGB(255,0,255)},
+ {LPGENT("Aqua"), RGB(0,255,255)},
+ {LPGENT("White"), RGB(255,255,255)}
+};
+
+
+TREEELEMENT *g_Stickies = NULL;
+
+
+INT_PTR CALLBACK StickyNoteWndProc(HWND hdlg,UINT message,
+ WPARAM wParam,LPARAM lParam);
+INT_PTR CALLBACK DlgProcViewNotes(HWND Dialog,UINT Message,WPARAM wParam,
+ LPARAM lParam);
+void JustSaveNotes(void);
+INT_PTR PluginMenuCommandAddNew(WPARAM w,LPARAM l);
+INT_PTR PluginMenuCommandDeleteAll(WPARAM w,LPARAM l);
+void GetTriggerTimeString(const ULARGE_INTEGER *When, char *s, UINT strSize, BOOL bUtc);
+void OnListResize(HWND Dialog);
+void UpdateGeomFromWnd(HWND Dialog, int *geom, int *colgeom, int nCols);
+void FileTimeToTzLocalST(const FILETIME *lpUtc, SYSTEMTIME *tmLocal);
+
+
+COLORREF GetCaptionColor(COLORREF bodyClr)
+{
+ const DWORD r = ((bodyClr & 0xff) * 4) / 5;
+ const DWORD g = (((bodyClr & 0xff00) * 4) / 5) & 0xff00;
+ const DWORD b = (((bodyClr & 0xff0000) * 4) / 5) & 0xff0000;
+
+ return (COLORREF)(r|g|b);
+}
+
+
+static void EnsureUniqueID(STICKYNOTE *TSN)
+{
+ TREEELEMENT *TTE;
+
+ if (!g_Stickies)
+ return;
+
+try_next:
+
+ // check existing notes if id is in use
+ TTE = g_Stickies;
+ while (TTE)
+ {
+ if (((STICKYNOTE*)TTE->ptrdata)->ID.QuadPart == TSN->ID.QuadPart)
+ {
+ // id in use, try new (increases the ID/time stamp by 100 nanosecond steps until an unused time is found,
+ // allthough it's very unlikely that there will be duplicated id's it's better to make 100% sure)
+ TSN->ID.QuadPart++;
+ goto try_next;
+ }
+
+ TTE = (TREEELEMENT*)TTE->next;
+ }
+}
+
+
+static void InitNoteTitle(STICKYNOTE *TSN)
+{
+ if (g_NoteTitleDate)
+ {
+ char TempStr[MAX_PATH];
+ SYSTEMTIME tm;
+ LCID lc = GetUserDefaultLCID();
+
+ TempStr[0] = 0;
+
+ memset(&tm, 0, sizeof(tm));
+ FileTimeToTzLocalST((FILETIME*)&TSN->ID, &tm);
+
+ if ( GetDateFormat(lc, 0, &tm, GetDateFormatStr(), TempStr, MAX_PATH) )
+ {
+ // append time if requested
+ if (g_NoteTitleTime)
+ {
+ int n = (int)strlen(TempStr);
+ TempStr[n++] = ' ';
+ TempStr[n] = 0;
+
+ GetTimeFormat(MAKELCID(MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),0), 0, &tm, GetTimeFormatStr(), TempStr+n, MAX_PATH-n);
+ }
+
+ TSN->title = _strdup(TempStr);
+ }
+ }
+
+ TSN->CustomTitle = FALSE;
+}
+
+
+static void InitStickyNoteLogFont(STICKYNOTEFONT *pCustomFont, LOGFONT *lf)
+{
+ if (!pCustomFont->size)
+ {
+ SystemParametersInfo(SPI_GETICONTITLELOGFONT, sizeof(LOGFONT), &lf, FALSE);
+ lf->lfHeight = 10;
+ HDC hdc = GetDC(0);
+ lf->lfHeight = -MulDiv(lf->lfHeight,GetDeviceCaps(hdc, LOGPIXELSY), 72);
+ ReleaseDC(0, hdc);
+ }
+ else
+ {
+ lf->lfHeight = pCustomFont->size;
+ }
+
+ _tcscpy(lf->lfFaceName, pCustomFont->szFace);
+
+ lf->lfWidth = lf->lfEscapement = lf->lfOrientation = 0;
+ lf->lfWeight = pCustomFont->style & DBFONTF_BOLD ? FW_BOLD : FW_NORMAL;
+ lf->lfItalic = (pCustomFont->style & DBFONTF_ITALIC) != 0;
+ lf->lfUnderline = (pCustomFont->style & DBFONTF_UNDERLINE) != 0;
+ lf->lfStrikeOut = (pCustomFont->style & DBFONTF_STRIKEOUT) != 0;
+ lf->lfCharSet = pCustomFont->charset;
+ lf->lfOutPrecision = OUT_DEFAULT_PRECIS;
+ lf->lfClipPrecision = CLIP_DEFAULT_PRECIS;
+ lf->lfQuality = DEFAULT_QUALITY;
+ lf->lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
+}
+
+static BOOL CreateStickyNoteFont(STICKYNOTEFONT *pCustomFont, LOGFONT *plf)
+{
+ LOGFONT lf = {0};
+
+ if (!plf)
+ {
+ InitStickyNoteLogFont(pCustomFont, &lf);
+ plf = &lf;
+ }
+
+ if (pCustomFont->hFont)
+ DeleteObject(pCustomFont->hFont);
+
+ pCustomFont->hFont = CreateFontIndirect(plf);
+
+ return pCustomFont->hFont != NULL;
+}
+
+
+STICKYNOTE* NewNoteEx(int Ax,int Ay,int Aw,int Ah,char *Data,ULARGE_INTEGER *ID,BOOL Visible,BOOL OnTop,int scrollV,COLORREF bgClr,COLORREF fgClr,char *Title,STICKYNOTEFONT *pCustomFont,BOOL bLoading)
+{
+ STICKYNOTE* TSN;
+ WNDCLASSEX TWC = {0};
+ WINDOWPLACEMENT TWP;
+ DWORD L1,L2;
+ SYSTEMTIME tm;
+ char TempStr[MAX_PATH] = {0};
+ char *TData;
+
+ const BOOL bIsStartup = Visible & 0x10000;
+ Visible &= ~0x10000;
+
+ if (Data) TData = Data; else TData = NULL;
+
+ if (!GetClassInfoEx(hmiranda, NOTE_WND_CLASS, &TWC))
+ {
+ TWC.style = CS_HREDRAW | CS_VREDRAW | CS_NOCLOSE;
+ TWC.cbClsExtra = 0;
+ TWC.cbWndExtra = 0;
+ TWC.hInstance = hmiranda;
+ TWC.hIcon = LoadIcon(0,IDI_APPLICATION);
+ TWC.hCursor = LoadCursor(0,IDC_ARROW);
+ TWC.hbrBackground = 0;
+ TWC.lpszMenuName = 0;
+ TWC.lpszClassName = NOTE_WND_CLASS;
+ TWC.cbSize = sizeof(WNDCLASSEX);
+ TWC.lpfnWndProc = (WNDPROC)StickyNoteWndProc;
+ if (!RegisterClassEx(&TWC)) return NULL;
+ }
+
+ if (!TData || Aw < 0 || Ah < 0)
+ {
+ TWP.length = sizeof(WINDOWPLACEMENT);
+ GetWindowPlacement(GetDesktopWindow(),&TWP);
+ Aw = g_NoteWidth; Ah = g_NoteHeight;
+ Ax = ((TWP.rcNormalPosition.right - TWP.rcNormalPosition.left) / 2) - (Aw / 2);
+ Ay = ((TWP.rcNormalPosition.bottom - TWP.rcNormalPosition.top) / 2) - (Ah / 2);
+ }
+
+ TSN = (STICKYNOTE*)malloc(sizeof(STICKYNOTE));
+
+ if (ID)
+ {
+ TSN->ID = *ID;
+ }
+ else
+ {
+ GetSystemTime(&tm);
+ SYSTEMTIMEtoFILETIME(&tm, (FILETIME*)&TSN->ID);
+ }
+
+ EnsureUniqueID(TSN);
+
+ TreeAdd(&g_Stickies,TSN);
+
+ if (!TData)
+ {
+ TData = _strdup("");
+ TSN->data = TData;
+ }
+ else
+ TSN->data = TData;
+
+ // init note title (time-stamp)
+ if (Title)
+ {
+ TSN->title = Title;
+ TSN->CustomTitle = TRUE;
+ }
+ else
+ {
+ TSN->title = NULL;
+ InitNoteTitle(TSN);
+ }
+
+ TSN->Visible = Visible;
+ TSN->OnTop = OnTop;
+
+ TSN->BgColor = bgClr;
+ TSN->FgColor = fgClr;
+
+ TSN->pCustomFont = pCustomFont;
+
+ L1 = WS_EX_TOOLWINDOW;
+ if (g_Transparency < 255) L1 |= WS_EX_LAYERED;
+ if (OnTop) L1 |= WS_EX_TOPMOST;
+
+ L2 = WS_POPUP | WS_THICKFRAME | WS_CAPTION;
+
+ // NOTE: loaded note positions stem from GetWindowPlacement, which normally have a different coord space than
+ // CreateWindow/SetWindowPos, BUT since we now use WS_EX_TOOLWINDOW they use the same coord space so
+ // we don't have to worry about notes "drifting" between sessions
+ TSN->SNHwnd = CreateWindowEx(L1, NOTE_WND_CLASS, _T("StickyNote"), L2, Ax,Ay,Aw,Ah, NULL, 0, hmiranda, TSN);
+
+ if (g_Transparency < 255)
+ SetLayeredWindowAttributes(TSN->SNHwnd,0,(BYTE)g_Transparency,LWA_ALPHA);
+
+ // ensure that window is not placed off-screen (if previous session had different monitor count or resolution)
+ // NOTE: SetWindowPlacement should do this, but it's extremly flakey
+ if (Data)
+ {
+ if (!MonitorFromWindow(TSN->SNHwnd, MONITOR_DEFAULTTONULL) )
+ {
+ TWP.length = sizeof(WINDOWPLACEMENT);
+ GetWindowPlacement(GetDesktopWindow(), &TWP);
+
+ if (Aw > 500) Aw = 500;
+ if (Ay < TWP.rcNormalPosition.left+10 || Ax > TWP.rcNormalPosition.right-120)
+ Ax = ((TWP.rcNormalPosition.right - TWP.rcNormalPosition.left) / 2) - (Aw / 2) + (rand() & 0x3f);
+ if (Ay < TWP.rcNormalPosition.top+50 || Ay > TWP.rcNormalPosition.bottom-50)
+ Ay = ((TWP.rcNormalPosition.bottom - TWP.rcNormalPosition.top) / 4) + (rand() & 0x1f);
+
+ SetWindowPos(TSN->SNHwnd, NULL, Ax, Ay, Aw, Ah, SWP_NOZORDER|SWP_NOACTIVATE);
+ }
+ }
+
+ if (Visible)
+ {
+ ShowWindow(TSN->SNHwnd, SW_SHOWNA);
+
+ // when loading notes (only at startup), place all non-top notes at the bottom so they don't cover other windows
+ if (Data && !OnTop && bIsStartup)
+ SetWindowPos(TSN->SNHwnd, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE|SWP_NOACTIVATE|SWP_ASYNCWINDOWPOS);
+ }
+
+ if (scrollV)
+ {
+ SendMessage(TSN->REHwnd, EM_LINESCROLL, 0, scrollV);
+ }
+
+ // make sure that any event triggered by init doesn't cause a meaningless save
+ KillTimer(TSN->SNHwnd, 1025);
+
+ if (!bLoading)
+ {
+ NOTIFY_LIST();
+ }
+
+ return TSN;
+}
+
+STICKYNOTE* NewNote(int Ax,int Ay,int Aw,int Ah,char *Data,ULARGE_INTEGER *ID,BOOL Visible,BOOL OnTop,int scrollV)
+{
+ return NewNoteEx(Ax,Ay,Aw,Ah,Data,ID,Visible,OnTop,scrollV,0,0,NULL,NULL,FALSE);
+}
+
+void LoadNotes(BOOL bIsStartup)
+{
+ int I;
+ int NotesCount;
+ WORD Size;
+ char *Value = NULL, *TVal = NULL;
+ char ValueName[32];
+
+ g_Stickies = NULL;
+
+ NotesCount = db_get_dw(0,MODULENAME,"NotesData",0);
+
+ for (I = 0; I < NotesCount; I++)
+ {
+ char *DelPos;
+
+ mir_snprintf(ValueName, SIZEOF(ValueName), "NotesData%d", I);
+
+ if (Value)
+ {
+ FreeSettingBlob(Size, Value);
+ Value = NULL;
+ }
+
+ Size = 65535; // does not get used
+
+ ReadSettingBlob(0, MODULENAME, ValueName, &Size, (void**)&Value);
+
+ if (!Size || !Value)
+ continue; // the setting could not be read from DB -> skip
+
+ if (Value[0] == 'X')
+ {
+ // new eXtended/fleXible data format
+
+ STICKYNOTE note = {0};
+ int i, rect[4];
+ int scrollV = 0;
+ STICKYNOTEFONT *pCustomFont = NULL;
+ DWORD flags;
+
+ DelPos = strchr(Value+1,0x1B);
+ if (DelPos)
+ *DelPos = 0;
+
+ // id:x:y:w:h:flags
+
+ TVal = strchr(Value+1, ':');
+ if (!TVal || (DelPos && TVal > DelPos))
+ continue;
+ *TVal++ = 0;
+
+ note.ID.QuadPart = _strtoui64(Value+1, NULL, 16);
+
+ for (i=0; i<4; i++)
+ {
+ char *sep = strchr(TVal, ':');
+ if (!sep || (DelPos && sep > DelPos))
+ goto skip;
+ *sep++ = 0;
+
+ rect[i] = strtol(TVal, NULL, 10);
+
+ TVal = sep;
+ }
+
+ flags = strtoul(TVal, NULL, 16);
+
+ if (flags & 1)
+ note.Visible = TRUE;
+ if (flags & 2)
+ note.OnTop = TRUE;
+
+ // optional \033 separated params
+ while (DelPos)
+ {
+ char *sep;
+ UINT tag;
+
+ TVal = DelPos + 1;
+ // find param end and make sure it's null-terminated (if end of data then it's already null-terminated)
+ DelPos = strchr(TVal, 0x1B);
+ if (DelPos)
+ *DelPos = 0;
+
+ // tag:<data>
+
+ sep = strchr(TVal, ':');
+ if (!sep || (DelPos && sep > DelPos))
+ goto skip;
+
+ tag = strtoul(TVal, NULL, 10);
+ TVal = sep + 1;
+
+ switch (tag)
+ {
+ case DATATAG_TEXT:
+ note.data = _strdup(TVal);
+ break;
+
+ case DATATAG_SCROLLPOS:
+ scrollV = (int)strtoul(TVal, NULL, 10);
+ break;
+
+ case DATATAG_BGCOL:
+ note.BgColor = strtoul(TVal, NULL, 16) | 0xff000000;
+ break;
+
+ case DATATAG_FGCOL:
+ note.FgColor = strtoul(TVal, NULL, 16) | 0xff000000;
+ break;
+
+ case DATATAG_TITLE:
+ if (strlen(TVal) > MAX_TITLE_LEN)
+ TVal[MAX_TITLE_LEN] = 0;
+ note.title = _strdup(TVal);
+ note.CustomTitle = TRUE;
+ break;
+
+ case DATATAG_FONT:
+ {
+ int fsize;
+ UINT fstyle, fcharset;
+
+ char *TVal2 = TVal;
+ sep = strchr(TVal2, ':');
+ if (!sep || (DelPos && sep > DelPos))
+ goto skip;
+ *sep++ = 0;
+ fsize = strtol(TVal2, NULL, 10);
+ TVal2 = sep;
+
+ sep = strchr(TVal2, ':');
+ if (!sep || (DelPos && sep > DelPos))
+ goto skip;
+ *sep++ = 0;
+ fstyle = strtoul(TVal2, NULL, 10);
+ TVal2 = sep;
+
+ sep = strchr(TVal2, ':');
+ if (!sep || (DelPos && sep > DelPos))
+ goto skip;
+ *sep++ = 0;
+ fcharset = strtoul(TVal2, NULL, 10);
+ TVal2 = sep;
+
+ if (TVal2 >= DelPos)
+ goto skip;
+
+ pCustomFont = (STICKYNOTEFONT*)malloc(sizeof(STICKYNOTEFONT));
+ pCustomFont->size = (char)fsize;
+ pCustomFont->style = (BYTE)fstyle;
+ pCustomFont->charset = (BYTE)fcharset;
+ _tcscpy(pCustomFont->szFace, TVal2);
+ pCustomFont->hFont = NULL;
+
+ if ( !CreateStickyNoteFont(pCustomFont, NULL) )
+ {
+ free(pCustomFont);
+ pCustomFont = NULL;
+ }
+ }
+ break;
+ }
+ }
+
+ if (!note.data)
+ note.data = _strdup("");
+
+ note.Visible = note.Visible && (!bIsStartup || g_ShowNotesAtStart);
+ if (bIsStartup)
+ note.Visible |= 0x10000;
+
+ NewNoteEx(rect[0],rect[1],rect[2],rect[3],note.data,&note.ID,note.Visible,note.OnTop,scrollV,note.BgColor,note.FgColor,note.title,pCustomFont,TRUE);
+ }
+ else
+ {
+ // old format (for DB backward compatibility)
+
+ int Tx,Ty,Tw,Th,TV,OT;
+ BOOL V;
+ char *Data,*ID;
+ ULARGE_INTEGER newid;
+
+ OT = 1; TV = 1;
+ Tx = 100; Ty = 100;
+ Tw = 179; Th = 35;
+ Data = NULL; ID = NULL;
+
+ if (DelPos = strchr(Value,0x1B))
+ { // get first delimiter
+ int PartLen = DelPos - TVal;
+
+ Data = NULL;
+ ID = NULL;
+ TVal = Value;
+ DelPos[0] = 0x0;
+ Tx = strtol(TVal, NULL, 10);
+
+ TVal = DelPos + 1;
+ DelPos = strchr(TVal, 0x1B);
+ if (!DelPos) continue; // setting is broken, do not crash
+ DelPos[0] = 0x0;
+ Ty = strtol(TVal, NULL, 10);
+
+ TVal = DelPos + 1;
+ DelPos = strchr(TVal, 0x1B);
+ if (!DelPos) continue; // setting is broken, do not crash
+ DelPos[0] = 0x0;
+ Tw = strtol(TVal, NULL, 10);
+
+ TVal = DelPos + 1;
+ DelPos = strchr(TVal, 0x1B);
+ if (!DelPos) continue; // setting is broken, do not crash
+ DelPos[0] = 0x0;
+ Th = strtol(TVal, NULL, 10);
+
+ TVal = DelPos + 1;
+ DelPos = strchr(TVal, 0x1B);
+ if (!DelPos) continue; // setting is broken, do not crash
+ DelPos[0] = 0x0;
+ TV = strtol(TVal, NULL, 10);
+
+ TVal = DelPos + 1;
+ DelPos = strchr(TVal, 0x1B);
+ if (!DelPos) continue; // setting is broken, do not crash
+ DelPos[0] = 0x0;
+ OT = strtol(TVal, NULL, 10);
+
+ TVal = DelPos + 1;
+ DelPos = strchr(TVal, 0x1B);
+ if (!DelPos) continue; // setting is broken, do not crash
+ DelPos[0] = 0x0;
+ Data = _strdup(TVal);
+
+ TVal = DelPos + 1;
+ ID = TVal;
+
+ V = (BOOL)TV && (!bIsStartup || g_ShowNotesAtStart);
+
+ if (bIsStartup)
+ V |= 0x10000;
+
+ // convert old ID format to new
+ if ( strchr(ID, '-') )
+ {
+ // validate format (otherwise create new)
+ if (strlen(ID) < 19 || ID[2] != '-' || ID[5] != '-' || ID[10] != ' ' || ID[13] != ':' || ID[16] != ':')
+ {
+ ID = NULL;
+ }
+ else
+ {
+ SYSTEMTIME tm;
+
+ ID[2] = ID[5] = ID[10] = ID[13] = ID[16] = 0;
+
+ memset(&tm, 0, sizeof(tm));
+ tm.wDay = (WORD)strtoul(ID, NULL, 10);
+ tm.wMonth = (WORD)strtoul(ID+3, NULL, 10);
+ tm.wYear = (WORD)strtoul(ID+6, NULL, 10);
+ tm.wHour = (WORD)strtoul(ID+11, NULL, 10);
+ tm.wMinute = (WORD)strtoul(ID+14, NULL, 10);
+ tm.wSecond = (WORD)strtoul(ID+17, NULL, 10);
+
+ SYSTEMTIMEtoFILETIME(&tm, (FILETIME*)&newid);
+ }
+ }
+ else
+ {
+ ID = NULL;
+ }
+
+ NewNoteEx(Tx,Ty,Tw,Th,Data,ID?&newid:NULL,V,(BOOL)OT,0,0,0,NULL,NULL,TRUE);
+ }
+ }
+skip:;
+ }
+
+ if (Value)
+ FreeSettingBlob(Size, Value); // we do not leak on bad setting
+
+ NOTIFY_LIST();
+}
+
+void CloseNotesList()
+{
+ if (ListNotesVisible)
+ {
+ DestroyWindow(LV);
+ ListNotesVisible = FALSE;
+ }
+}
+
+static void PurgeNotesTree()
+{
+ STICKYNOTE *pt;
+
+ while (g_Stickies) // empty whole tree
+ {
+ pt = (STICKYNOTE*)g_Stickies->ptrdata;
+ if (pt->SNHwnd) DestroyWindow(pt->SNHwnd);
+ SAFE_FREE((void**)&pt->title);
+ SAFE_FREE((void**)&pt->data);
+ if (pt->pCustomFont)
+ {
+ DeleteObject(pt->pCustomFont->hFont);
+ free(pt->pCustomFont);
+ }
+ TreeDelete(&g_Stickies,pt);
+ SAFE_FREE((void**)&pt);
+ }
+ g_Stickies = NULL;
+}
+
+void SaveNotes(void)
+{
+ JustSaveNotes();
+ PurgeNotesTree();
+}
+
+void PurgeNotes(void)
+{
+ int NotesCount, I;
+ char ValueName[16];
+
+ NotesCount = db_get_dw(0,MODULENAME,"NotesData",0);
+ for(I = 0; I < NotesCount; I++)
+ {
+ mir_snprintf(ValueName, SIZEOF(ValueName), "NotesData%d", I);
+ db_unset(0,MODULENAME,ValueName);
+ }
+}
+
+void OnDeleteNote(HWND hdlg, STICKYNOTE *SN)
+{
+ if (MessageBox(hdlg, TranslateT("Are you sure you want to delete this note?"), TranslateT(SECTIONNAME), MB_OKCANCEL) == IDOK)
+ {
+ if (SN->SNHwnd)
+ DestroyWindow(SN->SNHwnd);
+ TreeDelete(&g_Stickies,SN);
+ SAFE_FREE((void**)&SN->data);
+ if (SN->pCustomFont)
+ {
+ DeleteObject(SN->pCustomFont->hFont);
+ free(SN->pCustomFont);
+ }
+ SAFE_FREE((void**)&SN);
+ JustSaveNotes();
+ NOTIFY_LIST();
+ }
+}
+
+void DeleteNotes(void)
+{
+ PurgeNotes();
+ db_set_dw(0, MODULENAME, "NotesData", 0);
+ PurgeNotesTree();
+ NOTIFY_LIST();
+}
+
+void ShowHideNotes(void)
+{
+ BOOL Visible;
+
+ if (!g_Stickies)
+ return;
+
+ // if some notes are hidden but others visible then first make all visible
+ // only toggle vis state if all are hidden or all are visible
+
+ UINT nHideCount = 0, nVisCount = 0;
+ TREEELEMENT *TTE = g_Stickies;
+ while (TTE)
+ {
+ if (((STICKYNOTE*)TTE->ptrdata)->Visible)
+ nVisCount++;
+ else
+ nHideCount++;
+
+ TTE = (TREEELEMENT*)TTE->next;
+ }
+
+ if (!nVisCount)
+ Visible = TRUE;
+ else if (!nHideCount)
+ Visible = FALSE;
+ else
+ Visible = TRUE;
+
+ int bShow = Visible ? SW_SHOWNA : SW_HIDE;
+
+ TTE = g_Stickies;
+ while (TTE)
+ {
+ STICKYNOTE *SN = (STICKYNOTE*)TTE->ptrdata;
+
+ if ((!Visible) != (!SN->Visible))
+ {
+ ShowWindow(SN->SNHwnd, bShow);
+ SN->Visible = Visible;
+ }
+
+ TTE = (TREEELEMENT*)TTE->next;
+ }
+
+ JustSaveNotes();
+}
+
+void BringAllNotesToFront(STICKYNOTE *pActive)
+{
+ TREEELEMENT *TTE;
+
+ if (!g_Stickies)
+ return;
+
+ // NOTE: for some reason there are issues when bringing to top through hotkey while another app (like Explorer)
+ // is active, it refuses to move notes to top like it should with HWND_TOP. as a workaround still doesn't
+ // work 100% of the time, but at least more often, we first move not to top-most then for non-always-on-top
+ // notes we demote them back as a non top-most window
+
+ TTE = g_Stickies;
+ while (TTE)
+ {
+ STICKYNOTE *SN = (STICKYNOTE*)TTE->ptrdata;
+
+ if (SN->Visible && pActive != SN)
+ {
+ SetWindowPos(SN->SNHwnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
+ if (!SN->OnTop)
+ SetWindowPos(SN->SNHwnd, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
+ }
+
+ TTE = (TREEELEMENT*)TTE->next;
+ }
+
+ if (pActive)
+ {
+ SetWindowPos(pActive->SNHwnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
+ if (!pActive->OnTop)
+ SetWindowPos(pActive->SNHwnd, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
+ }
+}
+
+static void JustSaveNotesEx(STICKYNOTE *pModified)
+{
+ // pModified optionally points to the modified note that invoked the JustSaveNotesEx call
+
+ TREEELEMENT *TTE;
+ int I, NotesCount = TreeGetCount(g_Stickies);
+ int n, l;
+ char ValueName[32];
+ WINDOWPLACEMENT wp;
+ int TX,TY,TW,TH;
+ DWORD flags;
+ int SzT;
+ int scrollV;
+ char *tData, *Value;
+
+ const int OldNotesCount = db_get_dw(0, MODULENAME, "NotesData", 0);
+
+ db_set_dw(0, MODULENAME, "NotesData", NotesCount);
+
+ for (TTE = g_Stickies, I = 0; TTE; TTE = (TREEELEMENT*)TTE->next, I++)
+ {
+ STICKYNOTE *pNote = (STICKYNOTE*)TTE->ptrdata;
+ BOOL bDeleteTData = TRUE;
+ scrollV = 0;
+ tData = NULL;
+
+ // window pos and size
+ wp.length = sizeof(WINDOWPLACEMENT);
+ GetWindowPlacement(pNote->SNHwnd, &wp);
+ TX = wp.rcNormalPosition.left;
+ TY = wp.rcNormalPosition.top;
+ TW = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
+ TH = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
+
+ // set flags
+ flags = 0;
+ if (pNote->Visible) flags |= 1;
+ if (pNote->OnTop) flags |= 2;
+
+ // get note text
+ SzT = SendMessage(pNote->REHwnd, WM_GETTEXTLENGTH, 0, 0);
+ if (SzT) // TODO: change to support unicode and rtf, use EM_STREAMOUT
+ {
+ if (SzT > MAX_NOTE_LEN) SzT = MAX_NOTE_LEN; // we want to be far below the 64k limit
+ tData = (char*)malloc(SzT+1);
+ if (tData)
+ SendMessage(pNote->REHwnd, WM_GETTEXT, SzT+1, (LPARAM)tData);
+ }
+
+ if (pNote == pModified)
+ {
+ // update the data of the modified note
+ if (pNote->data)
+ free(pNote->data);
+ pNote->data = tData ? tData : _strdup("");
+ bDeleteTData = FALSE;
+ }
+
+ if (!tData)
+ // empty note
+ SzT = 0;
+ else
+ // get current scroll position
+ scrollV = SendMessage(pNote->REHwnd, EM_GETFIRSTVISIBLELINE, 0, 0);
+
+ //
+
+ Value = (char*)malloc(SzT + 512);
+ if (!Value) {
+ if (bDeleteTData)
+ SAFE_FREE((void**)&tData);
+ continue;
+ }
+
+ n = 0;
+
+ // data header
+ l = sprintf(Value, "X%I64x:%d:%d:%d:%d:%x", pNote->ID.QuadPart, TX, TY, TW, TH, flags); //!!!!!!!!!!!!
+ if (l > 0) n += l;
+
+ // scroll pos
+ if (scrollV > 0)
+ {
+ l = sprintf(Value+n, "\033""%u:%u", DATATAG_SCROLLPOS, (UINT)scrollV); //!!!!!!!!!!
+ if (l > 0) n += l;
+ }
+
+ // custom bg color
+ if (pNote->BgColor)
+ {
+ l = sprintf(Value+n, "\033""%u:%x", DATATAG_BGCOL, (UINT)(pNote->BgColor&0xffffff)); //!!!!!!!!!!!!!
+ if (l > 0) n += l;
+ }
+
+ // custom fg color
+ if (pNote->FgColor)
+ {
+ l = sprintf(Value+n, "\033""%u:%x", DATATAG_FGCOL, (UINT)(pNote->FgColor&0xffffff)); //!!!!!!!!!!!!!
+ if (l > 0) n += l;
+ }
+
+ if (pNote->pCustomFont)
+ {
+ l = sprintf(Value+n, "\033""%u:%d:%u:%u:%s", DATATAG_FONT,
+ (int)pNote->pCustomFont->size, (UINT)pNote->pCustomFont->style, (UINT)pNote->pCustomFont->charset,
+ pNote->pCustomFont->szFace); //!!!!!!!!!!!!!!!
+ if (l > 0) n += l;
+ }
+
+ // custom title
+ if (pNote->CustomTitle && pNote->title)
+ {
+ l = sprintf(Value+n, "\033""%u:%s", DATATAG_TITLE, pNote->title); //!!!!!!!!!!!!!
+ if (l > 0) n += l;
+ }
+
+ // note text (ALWAYS PUT THIS PARAM LAST)
+ if (tData)
+ {
+ l = sprintf(Value+n, "\033""%u:%s", DATATAG_TEXT, tData); //!!!!!!!!!!!!
+ if (l > 0) n += l;
+ }
+
+ // clamp data size to WORD (including null terminator)
+ if (n >= 0xffff)
+ {
+ // huston, we have a problem, strip some reminder text
+ n = 0xfffe;
+ Value[0xffff] = 0;
+ }
+
+ mir_snprintf(ValueName, SIZEOF(ValueName), "NotesData%d", NotesCount - I - 1); // we do not reverse notes in DB
+
+ db_set_blob(0, MODULENAME, ValueName, Value, n+1);
+
+ SAFE_FREE((void**)&Value);
+ if (bDeleteTData)
+ SAFE_FREE((void**)&tData);
+
+ // make no save is queued for the note
+ if (pNote->SNHwnd)
+ KillTimer(pNote->SNHwnd, 1025);
+ }
+
+ // delete any left over DB note entries
+ for(; I < OldNotesCount; I++)
+ {
+ mir_snprintf(ValueName, SIZEOF(ValueName), "NotesData%d", I);
+ db_unset(0,MODULENAME,ValueName);
+ }
+
+ NOTIFY_LIST();
+}
+
+__inline void JustSaveNotes(void)
+{
+ JustSaveNotesEx(NULL);
+}
+
+
+/////////////////////////////////////////////////////////////////////
+// Note Window
+
+static int FindMenuItem(HMENU h, LPTSTR lpszName)
+{
+ UINT i;
+ TCHAR s[128];
+
+ int n = GetMenuItemCount(h);
+
+ if (n <= 0)
+ {
+ return -1;
+ }
+
+ // searches for a menu item based on name (used to avoid hardcoding item indices for sub-menus)
+ for (i=0; i<(UINT)n; i++)
+ {
+ if ( GetMenuString(h, i, s, 128, MF_BYPOSITION) )
+ {
+ if ( !_tcscmp(s, lpszName) )
+ {
+ return (int)i;
+ }
+ }
+ }
+
+ return -1;
+}
+
+static BOOL DoContextMenu(HWND AhWnd,WPARAM wParam,LPARAM lParam)
+{
+ int n, i;
+ STICKYNOTE *SN = (STICKYNOTE*)GetProp(AhWnd, _T("ctrldata"));
+
+ HMENU hMenuLoad, FhMenu, hSub;
+ hMenuLoad = LoadMenu(hinstance, _T("MNU_NOTEPOPUP"));
+ FhMenu = GetSubMenu(hMenuLoad,0);
+
+ if (SN->OnTop)
+ CheckMenuItem(FhMenu, IDM_TOGGLEONTOP, MF_CHECKED|MF_BYCOMMAND);
+
+ EnableMenuItem(FhMenu, ID_CONTEXTMENUNOTEPOPUP_PASTETITLE, MF_BYCOMMAND | (IsClipboardFormatAvailable(CF_TEXT) ? MF_ENABLED : MF_GRAYED));
+
+ if (!SN->CustomTitle)
+ EnableMenuItem(FhMenu, ID_CONTEXTMENUNOTEPOPUP_RESETTITLE, MF_BYCOMMAND | MF_GRAYED);
+
+ // NOTE: names used for FindMenuItem would need to include & chars if such shortcuts are added to the menus
+
+ n = FindMenuItem(FhMenu, _T("Appearance"));
+ if (n >= 0 && (hSub = GetSubMenu(FhMenu, n)))
+ {
+ HMENU hBg = GetSubMenu(hSub, FindMenuItem(hSub, _T("Background Color")));
+ HMENU hFg = GetSubMenu(hSub, FindMenuItem(hSub, _T("Text Color")));
+
+ for (i=0; i<SIZEOF(clrPresets); i++)
+ InsertMenu(hBg, i, MF_BYPOSITION|MF_OWNERDRAW, IDM_COLORPRESET_BG+i, TranslateTS(clrPresets[i].szName));
+
+ for (i=0; i<SIZEOF(clrPresets); i++)
+ InsertMenu(hFg, i, MF_BYPOSITION|MF_OWNERDRAW, IDM_COLORPRESET_FG+i, TranslateTS(clrPresets[i].szName));
+ }
+
+ CallService(MS_LANGPACK_TRANSLATEMENU,(DWORD)FhMenu,0);
+ TrackPopupMenu(FhMenu,TPM_LEFTALIGN | TPM_RIGHTBUTTON,LOWORD(lParam),HIWORD(lParam),0,AhWnd,0);
+ DestroyMenu(hMenuLoad);
+
+ return TRUE;
+}
+
+static void MeasureColorPresetMenuItem(HWND hdlg, LPMEASUREITEMSTRUCT lpMeasureItem, struct ColorPreset *clrPresets)
+{
+ HDC hdc = GetDC(hdlg);
+ LPTSTR lpsz = TranslateTS(clrPresets->szName);
+ SIZE sz;
+ GetTextExtentPoint32(hdc, lpsz, (int)_tcslen(lpsz), &sz);
+ ReleaseDC(hdlg, hdc);
+
+ lpMeasureItem->itemWidth = 50 + sz.cx;
+ lpMeasureItem->itemHeight = (sz.cy+2)>18 ? sz.cy+2 : 18;
+}
+
+static void PaintColorPresetMenuItem(LPDRAWITEMSTRUCT lpDrawItem, struct ColorPreset *clrPresets)
+{
+ UINT n = lpDrawItem->itemID - IDM_COLORPRESET_BG;
+ RECT rect;
+ rect.left = lpDrawItem->rcItem.left + 50;
+ rect.top = lpDrawItem->rcItem.top;
+ rect.right = lpDrawItem->rcItem.right;
+ rect.bottom = lpDrawItem->rcItem.bottom;
+
+ if (lpDrawItem->itemState & ODS_SELECTED)
+ {
+ SetDCBrushColor(lpDrawItem->hDC, GetSysColor(COLOR_MENUHILIGHT));
+ FillRect(lpDrawItem->hDC, &lpDrawItem->rcItem, (HBRUSH)GetStockObject(DC_BRUSH));
+
+ SetTextColor(lpDrawItem->hDC, GetSysColor(COLOR_HIGHLIGHTTEXT));
+ }
+ else
+ {
+ SetDCBrushColor(lpDrawItem->hDC, GetSysColor(COLOR_MENU));
+ FillRect(lpDrawItem->hDC, &lpDrawItem->rcItem, (HBRUSH)GetStockObject(DC_BRUSH));
+
+ SetTextColor(lpDrawItem->hDC, GetSysColor(COLOR_MENUTEXT));
+ }
+
+ SetBkMode(lpDrawItem->hDC, TRANSPARENT);
+ DrawText(lpDrawItem->hDC,clrPresets->szName,-1,&rect,DT_LEFT | DT_SINGLELINE | DT_END_ELLIPSIS | DT_VCENTER);
+
+ {
+ int h = lpDrawItem->rcItem.bottom - lpDrawItem->rcItem.top;
+ rect.left = lpDrawItem->rcItem.left + 5;
+ rect.top = lpDrawItem->rcItem.top + ((h-14)>>1);
+ rect.right = rect.left + 40;
+ rect.bottom = rect.top + 14;
+
+ FrameRect(lpDrawItem->hDC, &rect, (HBRUSH)GetStockObject(BLACK_BRUSH));
+ rect.left++; rect.top++;
+ rect.right--; rect.bottom--;
+ SetDCBrushColor(lpDrawItem->hDC, clrPresets->color);
+ FillRect(lpDrawItem->hDC, &rect, (HBRUSH)GetStockObject(DC_BRUSH));
+ }
+}
+
+static BOOL GetClipboardText_Title(char *pOut, int size)
+{
+ BOOL bResult = FALSE;
+
+ if ( OpenClipboard(NULL) )
+ {
+ HANDLE hData = GetClipboardData(CF_TEXT);
+ LPCSTR buffer;
+
+ if (hData && (buffer = (LPCSTR)GlobalLock(hData)))
+ {
+ // trim initial white spaces
+ while (*buffer && isspace(*buffer))
+ buffer++;
+
+ char *p;
+ int n = strlen(buffer);
+ if (n >= size)
+ n = size-1;
+ memcpy(pOut, buffer, n);
+ pOut[n] = 0;
+
+ // end string on line break and convert tabs to spaces
+ p = pOut;
+ while (*p)
+ {
+ if (*p == '\r' || *p == '\n')
+ {
+ *p = 0;
+ n = strlen(pOut);
+ break;
+ }
+ else if (*p == '\t')
+ {
+ *p = ' ';
+ }
+ p++;
+ }
+
+ // trim trailing white spaces
+ while (n && isspace(pOut[n-1]))
+ pOut[--n] = 0;
+
+ if (n)
+ bResult = TRUE;
+
+ GlobalUnlock(hData);
+ }
+
+ CloseClipboard();
+ }
+
+ return bResult;
+}
+
+static void SetNoteTextControl(STICKYNOTE *SN)
+{
+ CHARFORMAT CF = {0};
+ CF.cbSize = sizeof(CHARFORMAT);
+ CF.dwMask = CFM_COLOR;
+ CF.crTextColor = SN->FgColor ? (SN->FgColor&0xffffff) : BodyFontColor;
+ SendMessage(SN->REHwnd, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&CF);
+
+ if (SN->data) // TODO: use EM_STREAMIN
+ SendMessage(SN->REHwnd, WM_SETTEXT, 0, (LPARAM)(SN->data));
+}
+
+
+static UINT_PTR CALLBACK CFHookProc(HWND hdlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ if (msg == WM_INITDIALOG)
+ {
+ // hide color selector
+ ShowWindow(GetDlgItem(hdlg,0x443), SW_HIDE);
+ ShowWindow(GetDlgItem(hdlg,0x473), SW_HIDE);
+ TranslateDialogDefault(hdlg);
+ }
+
+ return 0;
+}
+
+
+INT_PTR CALLBACK StickyNoteWndProc(HWND hdlg,UINT message,WPARAM wParam,LPARAM lParam)
+{
+ switch (message)
+ {
+ case WM_CLOSE:
+ return TRUE;
+
+ case WM_SIZE:
+ {
+ RECT SZ;
+
+ GetClientRect(hdlg,&SZ);
+ HWND H = GetDlgItem(hdlg,1);
+ MoveWindow(H, 0, 0, SZ.right,SZ.bottom, TRUE);
+
+ KillTimer(hdlg, 1025);
+ SetTimer(hdlg, 1025, NOTE_CHANGE_COMMIT_DELAY, 0);
+
+ return TRUE;
+ }
+ case WM_TIMER:
+ if (wParam == 1025)
+ {
+ STICKYNOTE *SN = (STICKYNOTE*)GetProp(hdlg,_T("ctrldata"));
+
+ KillTimer(hdlg, 1025);
+ JustSaveNotesEx(SN);
+ }
+ break;
+ case WM_MOVE:
+ {
+ KillTimer(hdlg, 1025);
+ SetTimer(hdlg, 1025, NOTE_CHANGE_COMMIT_DELAY, 0);
+ return TRUE;
+ }
+ case WM_CREATE:
+ {
+ STICKYNOTE *SN = (STICKYNOTE*)GetProp(hdlg,_T("ctrldata"));
+
+ CREATESTRUCT *CS = (CREATESTRUCT *)lParam;
+ HWND H;
+ DWORD mystyle;
+
+ SN = (STICKYNOTE*)CS->lpCreateParams;
+ SetProp(hdlg,_T("ctrldata"),(HANDLE)SN);
+ BringWindowToTop(hdlg);
+ mystyle = WS_CHILD | WS_VISIBLE | ES_LEFT | ES_MULTILINE | ES_AUTOVSCROLL | ES_WANTRETURN;
+ if (g_ShowScrollbar) mystyle |= WS_VSCROLL;
+ H = CreateWindow(RICHEDIT_CLASS, 0, mystyle, 0, 0, CS->cx-3-3, CS->cy-3-(3+14), hdlg, (HMENU)1, hmiranda, 0);
+ SN->REHwnd = H;
+ SendMessage(H, EM_SETTEXTMODE, TM_PLAINTEXT, 0);
+ SendMessage(H, EM_LIMITTEXT, MAX_NOTE_LEN, 0);
+ SendMessage(H, WM_SETFONT, (WPARAM)(SN->pCustomFont ? SN->pCustomFont->hFont : hBodyFont), 1);
+ SendMessage(H, EM_SETEVENTMASK, 0, ENM_CHANGE | ENM_LINK);
+ SendMessage(H, EM_SETBKGNDCOLOR, 0, SN->BgColor ? (SN->BgColor&0xffffff) : BodyColor);
+ SendMessage(H, EM_AUTOURLDETECT, 1, 0);
+ SetNoteTextControl(SN);
+ return TRUE;
+ }
+ case WM_GETMINMAXINFO:
+ {
+ MINMAXINFO *mm = (MINMAXINFO*)lParam;
+ // min width accomodates frame, buttons and some extra space for sanity
+ mm->ptMinTrackSize.x = 48+3+3+8 + 40;
+ // min height allows collapsing entire client area, only leaving frame and caption
+ mm->ptMinTrackSize.y = 3+3+14;
+ }
+ return 0;
+ case WM_ERASEBKGND:
+ // no BG needed as edit control takes up entire client area
+ return TRUE;
+ case WM_NCPAINT:
+ // make window borders have the same color as caption
+ {
+ STICKYNOTE *SN = (STICKYNOTE*)GetProp(hdlg,"ctrldata");
+
+ HBRUSH hBkBrush;
+ RECT rect, wr, r;
+ //HDC hdc = GetDCEx(hdlg, (HRGN)wParam, DCX_WINDOW|DCX_INTERSECTRGN);
+ HDC hdc = GetWindowDC(hdlg);
+
+ GetWindowRect(hdlg, &wr);
+ if (wParam && wParam != 1)
+ {
+ SelectClipRgn(hdc, (HRGN)wParam);
+ OffsetClipRgn(hdc, -wr.left, -wr.top);
+ }
+
+ rect = wr;
+ OffsetRect(&rect, -wr.left, -wr.top);
+
+ hBkBrush = (HBRUSH)GetStockObject(DC_BRUSH);
+ SetDCBrushColor(hdc, GetCaptionColor((SN && SN->BgColor) ? SN->BgColor : BodyColor));
+
+ // draw all frame sides separately to avoid filling client area (which flickers)
+ {
+ // top
+ r.left = rect.left; r.right = rect.right;
+ r.top = rect.top; r.bottom = r.top + 3+14;
+ FillRect(hdc, &r, hBkBrush);
+ // bottom
+ r.top = rect.bottom - 3; r.bottom = rect.bottom;
+ FillRect(hdc, &r, hBkBrush);
+ // left
+ r.left = rect.left; r.right = r.left + 3;
+ r.top = rect.top + 3+14; r.bottom = rect.bottom - 3;
+ FillRect(hdc, &r, hBkBrush);
+ // right
+ r.left = rect.right - 3; r.right = rect.right;
+ FillRect(hdc, &r, hBkBrush);
+ }
+
+ // paint title bar contents (time stamp and buttons)
+
+ if (SN && SN->title)
+ {
+ RECT R;
+ SelectObject(hdc,hCaptionFont);
+ R.top = 3+1; R.bottom = 3+11; R.left = 3+2; R.right = rect.right-3-1;
+ if (g_ShowNoteButtons)
+ R.right -= 48;
+
+ SetTextColor(hdc,SN->FgColor ? (SN->FgColor&0xffffff) : CaptionFontColor);
+ SetBkMode(hdc, TRANSPARENT);
+ DrawText(hdc,SN->title,-1,&R,DT_LEFT | DT_SINGLELINE | DT_END_ELLIPSIS | DT_VCENTER);
+ }
+
+ if (g_ShowNoteButtons)
+ {
+ HICON hcIcon;
+ if (SN->OnTop)
+ hcIcon = Skin_GetIconByHandle(iconList[4].hIcolib);
+ else
+ hcIcon = Skin_GetIconByHandle(iconList[7].hIcolib);
+ DrawIcon(hdc, wr.right - wr.left - 16, 0 + 3, hcIcon);
+ Skin_ReleaseIcon(hcIcon);
+
+ hcIcon = Skin_GetIconByHandle(iconList[9].hIcolib);
+ DrawIcon(hdc, wr.right - wr.left - 32, 1 + 3, hcIcon);
+ Skin_ReleaseIcon(hcIcon);
+
+ hcIcon = Skin_GetIconByHandle(iconList[8].hIcolib);
+ DrawIcon(hdc, wr.right - wr.left - 48, 1 + 3, hcIcon);
+ Skin_ReleaseIcon(hcIcon);
+ }
+
+ if (wParam && wParam != 1)
+ {
+ SelectClipRgn(hdc, NULL);
+ }
+
+ ReleaseDC(hdlg, hdc);
+ return TRUE;
+ }
+ case WM_NCCALCSIZE:
+ {
+ RECT *pRect = wParam ? &((NCCALCSIZE_PARAMS*)lParam)->rgrc[0] : (RECT*)lParam;
+ pRect->bottom -= 3;
+ pRect->right -= 3;
+ pRect->left += 3;
+ pRect->top += 3+14;
+ return WVR_REDRAW;
+ }
+ case WM_NCACTIVATE:
+ // update window (so that parts that potentially became visible through activation get redrawn immediately)
+ RedrawWindow(hdlg, NULL, NULL, RDW_UPDATENOW);
+ return TRUE;
+ case WM_NOTIFY:
+ if (LOWORD(wParam) == 1)
+ {
+ char *Buff;
+ PENLINK PEnLnk = (PENLINK)lParam;
+
+ if (PEnLnk->msg == WM_LBUTTONDOWN)
+ {
+ SendDlgItemMessage(hdlg,1,EM_EXSETSEL,0,(LPARAM)&(PEnLnk->chrg));
+ Buff = (char*)malloc(PEnLnk->chrg.cpMax - PEnLnk->chrg.cpMin + 1);
+ SendDlgItemMessage(hdlg,1,EM_GETSELTEXT,0,(LPARAM)Buff);
+ if ((GetAsyncKeyState(VK_CONTROL) >> 15) != 0)
+ ShellExecute(hdlg, _T("open"), _T("iexplore"), Buff, _T("") ,SW_SHOWNORMAL);
+ else if (g_lpszAltBrowser && *g_lpszAltBrowser)
+ ShellExecute(hdlg,_T("open"), g_lpszAltBrowser, Buff, _T("") ,SW_SHOWNORMAL);
+ else
+ ShellExecute(hdlg, _T("open"), Buff, _T(""), _T(""), SW_SHOWNORMAL);
+ SAFE_FREE((void**)&Buff);
+ return TRUE;
+ }
+ return FALSE;
+ }
+ break;
+ case WM_NCHITTEST:
+ {
+ int r = DefWindowProc(hdlg,message,wParam,lParam);
+ // filter out potential hits on windows default title bar buttons
+ switch (r)
+ {
+ case HTSYSMENU:
+ case HTCLOSE:
+ case HTMINBUTTON:
+ case HTMAXBUTTON:
+ return HTCAPTION;
+ }
+ return r;
+ }
+ case WM_NCLBUTTONDOWN:
+ if (wParam == HTCAPTION && g_ShowNoteButtons)
+ {
+ long X,Y;
+ RECT rect;
+ int Tw;
+
+ GetWindowRect(hdlg, &rect);
+ Tw = rect.right - rect.left;
+
+ X = LOWORD(lParam) - rect.left;
+ Y = HIWORD(lParam) - rect.top;
+
+ if (X > Tw - 16)
+ {
+ SendMessage(hdlg,WM_COMMAND,IDM_TOGGLEONTOP,0);
+ return TRUE;
+ }
+ else if (X > Tw - 31 && X < Tw - 16)
+ {
+ SendMessage(hdlg,WM_COMMAND,IDM_REMOVENOTE,0);
+ return TRUE;
+ }
+ else if (X > Tw - 48 && X < Tw - 32)
+ {
+ SendMessage(hdlg,WM_COMMAND,IDM_HIDENOTE,0);
+ return TRUE;
+ }
+ }
+ return DefWindowProc(hdlg,message,wParam,lParam);
+ case WM_MEASUREITEM:
+ {
+ LPMEASUREITEMSTRUCT lpMeasureItem = (LPMEASUREITEMSTRUCT)lParam;
+
+ if (lpMeasureItem->CtlType != ODT_MENU)
+ break;
+
+ if (lpMeasureItem->itemID >= IDM_COLORPRESET_BG && lpMeasureItem->itemID <= IDM_COLORPRESET_BG+SIZEOF(clrPresets))
+ {
+ MeasureColorPresetMenuItem(hdlg, lpMeasureItem, clrPresets + (lpMeasureItem->itemID - IDM_COLORPRESET_BG));
+ return TRUE;
+ }
+ else if (lpMeasureItem->itemID >= IDM_COLORPRESET_FG && lpMeasureItem->itemID <= IDM_COLORPRESET_FG+SIZEOF(clrPresets))
+ {
+ MeasureColorPresetMenuItem(hdlg, lpMeasureItem, clrPresets + (lpMeasureItem->itemID - IDM_COLORPRESET_FG));
+ return TRUE;
+ }
+ }
+ break;
+ case WM_DRAWITEM:
+ if (!wParam)
+ {
+ LPDRAWITEMSTRUCT lpDrawItem = (LPDRAWITEMSTRUCT)lParam;
+
+ if (lpDrawItem->CtlType != ODT_MENU)
+ break;
+
+ if (lpDrawItem->itemID >= IDM_COLORPRESET_BG && lpDrawItem->itemID <= IDM_COLORPRESET_BG+SIZEOF(clrPresets))
+ {
+ PaintColorPresetMenuItem(lpDrawItem, clrPresets + (lpDrawItem->itemID - IDM_COLORPRESET_BG));
+ return TRUE;
+ }
+ else if (lpDrawItem->itemID >= IDM_COLORPRESET_FG && lpDrawItem->itemID <= IDM_COLORPRESET_FG+SIZEOF(clrPresets))
+ {
+ PaintColorPresetMenuItem(lpDrawItem, clrPresets + (lpDrawItem->itemID - IDM_COLORPRESET_FG));
+ return TRUE;
+ }
+ }
+ break;
+ case WM_COMMAND:
+ {
+ STICKYNOTE *SN = (STICKYNOTE*)GetProp(hdlg, _T("ctrldata"));
+
+ HWND H;
+ UINT id;
+
+ switch ( HIWORD(wParam) )
+ {
+ case EN_CHANGE:
+ case EN_VSCROLL:
+ case EN_HSCROLL:
+ {
+ KillTimer(hdlg,1025);
+ SetTimer(hdlg, 1025, NOTE_CHANGE_COMMIT_DELAY, 0);
+ }
+ break;
+ }
+
+ id = (UINT) LOWORD(wParam);
+
+ H = SN->REHwnd;
+
+ if (id >= IDM_COLORPRESET_BG && id <= IDM_COLORPRESET_BG+SIZEOF(clrPresets))
+ {
+ SN->BgColor = clrPresets[id-IDM_COLORPRESET_BG].color | 0xff000000;
+ SendMessage(H, EM_SETBKGNDCOLOR, 0, (LPARAM)(SN->BgColor&0xffffff));
+ RedrawWindow(SN->SNHwnd, NULL, NULL, RDW_INVALIDATE|RDW_FRAME|RDW_UPDATENOW);
+ JustSaveNotes();
+ return FALSE;
+ }
+ else if (id >= IDM_COLORPRESET_FG && id <= IDM_COLORPRESET_FG+SIZEOF(clrPresets))
+ {
+ CHARFORMAT CF = {0};
+ SN->FgColor = clrPresets[id-IDM_COLORPRESET_FG].color | 0xff000000;
+ CF.cbSize = sizeof(CHARFORMAT);
+ CF.dwMask = CFM_COLOR;
+ CF.crTextColor = SN->FgColor & 0xffffff;
+ SendMessage(H, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&CF);
+ RedrawWindow(SN->SNHwnd, NULL, NULL, RDW_INVALIDATE|RDW_FRAME|RDW_UPDATENOW);
+ JustSaveNotes();
+ return FALSE;
+ }
+
+ switch (id)
+ {
+ case ID_CONTEXTMENUNOTEPOPUP_NEWNOTE:
+ {
+ PluginMenuCommandAddNew(0,0);
+ }
+ break;
+ case ID_APPEARANCE_CUSTOMBG:
+ {
+ COLORREF custclr[16] = {0};
+ CHOOSECOLOR cc = {0};
+ COLORREF orgclr = SN->BgColor ? (COLORREF)(SN->BgColor&0xffffff) : (COLORREF)(BodyColor&0xffffff);
+ cc.lStructSize = sizeof(cc);
+ cc.hwndOwner = SN->SNHwnd;
+ cc.rgbResult = orgclr;
+ cc.Flags = CC_ANYCOLOR | CC_FULLOPEN | CC_RGBINIT | CC_SOLIDCOLOR;
+ cc.lpCustColors = custclr;
+
+ if (ChooseColor(&cc) && cc.rgbResult != orgclr)
+ {
+ SN->BgColor = cc.rgbResult | 0xff000000;
+ SendMessage(H, EM_SETBKGNDCOLOR, 0, (LPARAM)(SN->BgColor&0xffffff));
+ RedrawWindow(SN->SNHwnd, NULL, NULL, RDW_INVALIDATE|RDW_FRAME|RDW_UPDATENOW);
+ JustSaveNotes();
+ }
+ }
+ break;
+ case ID_APPEARANCE_CUSTOMTEXT:
+ {
+ COLORREF custclr[16] = {0};
+ CHOOSECOLOR cc = {0};
+ COLORREF orgclr = SN->FgColor ? (COLORREF)(SN->FgColor&0xffffff) : (COLORREF)(BodyFontColor&0xffffff);
+ cc.lStructSize = sizeof(cc);
+ cc.hwndOwner = SN->SNHwnd;
+ cc.rgbResult = orgclr;
+ cc.Flags = CC_ANYCOLOR | CC_FULLOPEN | CC_RGBINIT | CC_SOLIDCOLOR;
+ cc.lpCustColors = custclr;
+
+ if (ChooseColor(&cc) && cc.rgbResult != orgclr)
+ {
+ CHARFORMAT CF = {0};
+ SN->FgColor = cc.rgbResult | 0xff000000;
+ CF.cbSize = sizeof(CHARFORMAT);
+ CF.dwMask = CFM_COLOR;
+ CF.crTextColor = SN->FgColor & 0xffffff;
+ SendMessage(H, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&CF);
+ RedrawWindow(SN->SNHwnd, NULL, NULL, RDW_INVALIDATE|RDW_FRAME|RDW_UPDATENOW);
+ JustSaveNotes();
+ }
+ }
+ break;
+ case ID_APPEARANCE_CUSTOMFONT:
+ {
+ CHOOSEFONT cf = {0};
+ LOGFONT lf = {0};
+
+ if (SN->pCustomFont)
+ InitStickyNoteLogFont(SN->pCustomFont, &lf);
+ else
+ LoadNRFont(NR_FONTID_BODY, &lf, NULL);
+
+ cf.lStructSize = sizeof(cf);
+ cf.hwndOwner = SN->SNHwnd;
+ cf.lpLogFont = &lf;
+ cf.Flags = CF_EFFECTS | CF_FORCEFONTEXIST | CF_INITTOLOGFONTSTRUCT | CF_SCREENFONTS | CF_ENABLEHOOK;
+ cf.lpfnHook = CFHookProc;
+
+ if ( ChooseFont(&cf) )
+ {
+ if (!SN->pCustomFont)
+ {
+ SN->pCustomFont = (STICKYNOTEFONT*)malloc(sizeof(STICKYNOTEFONT));
+ SN->pCustomFont->hFont = NULL;
+ }
+
+ SN->pCustomFont->size = (char)lf.lfHeight;
+ SN->pCustomFont->style = (lf.lfWeight >= FW_BOLD ? DBFONTF_BOLD : 0) | (lf.lfItalic ? DBFONTF_ITALIC : 0) | (lf.lfUnderline ? DBFONTF_UNDERLINE : 0) | (lf.lfStrikeOut ? DBFONTF_STRIKEOUT : 0);
+ SN->pCustomFont->charset = lf.lfCharSet;
+ _tcscpy(SN->pCustomFont->szFace, lf.lfFaceName);
+
+ if ( !CreateStickyNoteFont(SN->pCustomFont, &lf) )
+ {
+ // failed
+ free(SN->pCustomFont);
+ SN->pCustomFont = NULL;
+ }
+
+ // clear text first to force a reformatting w.r.t scrollbar
+ SendMessage(H, WM_SETTEXT, 0, (LPARAM)"");
+ SendMessage(H, WM_SETFONT, (WPARAM)(SN->pCustomFont ? SN->pCustomFont->hFont : hBodyFont), FALSE);
+ SetNoteTextControl(SN);
+ RedrawWindow(SN->SNHwnd, NULL, NULL, RDW_INVALIDATE|RDW_FRAME|RDW_UPDATENOW);
+ JustSaveNotes();
+ }
+ }
+ break;
+ case ID_BACKGROUNDCOLOR_RESET:
+ {
+ SN->BgColor = 0;
+ SendMessage(H, EM_SETBKGNDCOLOR, 0, (LPARAM)BodyColor);
+ RedrawWindow(SN->SNHwnd, NULL, NULL, RDW_INVALIDATE|RDW_FRAME|RDW_UPDATENOW);
+ JustSaveNotes();
+ }
+ break;
+ case ID_TEXTCOLOR_RESET:
+ {
+ CHARFORMAT CF = {0};
+ SN->FgColor = 0;
+ CF.cbSize = sizeof(CHARFORMAT);
+ CF.dwMask = CFM_COLOR;
+ CF.crTextColor = BodyFontColor;
+ SendMessage(H, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&CF);
+ RedrawWindow(SN->SNHwnd, NULL, NULL, RDW_INVALIDATE|RDW_FRAME|RDW_UPDATENOW);
+ JustSaveNotes();
+ }
+ break;
+ case ID_FONT_RESET:
+ {
+ if (SN->pCustomFont)
+ {
+ DeleteObject(SN->pCustomFont->hFont);
+ free(SN->pCustomFont);
+ SN->pCustomFont = NULL;
+
+ // clear text first to force a reformatting w.r.t scrollbar
+ SendMessage(H, WM_SETTEXT, 0, (LPARAM)"");
+ SendMessage(H, WM_SETFONT, (WPARAM)hBodyFont, FALSE);
+ SetNoteTextControl(SN);
+ RedrawWindow(SN->SNHwnd, NULL, NULL, RDW_INVALIDATE|RDW_FRAME|RDW_UPDATENOW);
+ JustSaveNotes();
+ }
+ }
+ break;
+ case ID_CONTEXTMENUNOTEPOPUP_PASTETITLE:
+ {
+ char s[MAX_TITLE_LEN+1];
+ if ( GetClipboardText_Title(s, sizeof(s)) )
+ {
+ if (SN->title)
+ free(SN->title);
+ SN->title = _strdup(s);
+ SN->CustomTitle = TRUE;
+ RedrawWindow(SN->SNHwnd, NULL, NULL, RDW_INVALIDATE|RDW_FRAME|RDW_UPDATENOW);
+ JustSaveNotes();
+ }
+ }
+ break;
+ case ID_CONTEXTMENUNOTEPOPUP_RESETTITLE:
+ if (SN->CustomTitle)
+ {
+ if (SN->title)
+ {
+ free(SN->title);
+ SN->title = NULL;
+ }
+ InitNoteTitle(SN);
+ RedrawWindow(SN->SNHwnd, NULL, NULL, RDW_INVALIDATE|RDW_FRAME|RDW_UPDATENOW);
+ JustSaveNotes();
+ }
+ break;
+ case IDM_REMOVENOTE:
+ OnDeleteNote(hdlg, SN);
+ break;
+ case IDM_HIDENOTE:
+ {
+ SN->Visible = FALSE;
+ ShowWindow(hdlg,SW_HIDE);
+ JustSaveNotes();
+ }
+ break;
+ case IDM_COPY: SendMessage(H,WM_COPY,0,0); break;
+ case IDM_PASTE: SendMessage(H,WM_PASTE,0,0); break;
+ case IDM_CUT: SendMessage(H,WM_CUT,0,0); break;
+ case IDM_CLEAR: SendMessage(H,WM_CLEAR,0,0); break;
+ case IDM_UNDO: SendMessage(H,WM_UNDO,0,0); break;
+ case IDM_TOGGLEONTOP:
+ {
+ SN->OnTop = !SN->OnTop;
+ SetWindowPos(hdlg, SN->OnTop ? HWND_TOPMOST : HWND_NOTOPMOST, 0,0,0,0, SWP_SHOWWINDOW|SWP_NOMOVE|SWP_NOSIZE);
+ RedrawWindow(hdlg, NULL, NULL, RDW_FRAME|RDW_INVALIDATE|RDW_UPDATENOW);
+ JustSaveNotes();
+ }
+ break;
+ case ID_CONTEXTMENUNOTEPOPUP_VIEWNOTES:
+ ListNotes();
+ break;
+ case ID_CONTEXTMENUNOTEPOPUP_BRINGALLTOTOP:
+ BringAllNotesToFront(SN);
+ break;
+ }
+ return TRUE;
+ }
+ case WM_NCDESTROY:
+ {
+ RemoveProp(hdlg, _T("ctrldata"));
+ }
+ break;
+ case WM_CONTEXTMENU:
+ if (DoContextMenu(hdlg,wParam,lParam)) return FALSE;
+
+ default:
+ return DefWindowProc(hdlg,message,wParam,lParam);
+ }
+ return FALSE;
+}
+
+
+/////////////////////////////////////////////////////////////////////
+// Notes List Dialog (uses same dialog template as reminder list)
+
+void ListNotes(void)
+{
+ if (!ListNotesVisible)
+ {
+ CreateDialog(hinstance, MAKEINTRESOURCE(IDD_LISTREMINDERS), 0, DlgProcViewNotes);
+ ListNotesVisible = TRUE;
+ }
+ else
+ {
+ BringWindowToTop(LV);
+ }
+}
+
+static void EditNote(STICKYNOTE *SN)
+{
+ if (!SN)
+ return;
+
+ if (!SN->Visible)
+ {
+ SN->Visible = TRUE;
+ JustSaveNotes();
+ }
+
+ SetWindowPos(SN->SNHwnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
+ if (!SN->OnTop)
+ SetWindowPos(SN->SNHwnd, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
+
+ SetFocus(SN->REHwnd);
+}
+
+char* GetPreviewString(const char *lpsz)
+{
+ int l;
+ char *p;
+ const int MaxLen = 80;
+ static char s[80+8];
+
+ if (!lpsz)
+ return "";
+
+ // trim leading spaces
+ while ( iswspace(*lpsz) )
+ lpsz++;
+
+ l = (int)strlen(lpsz);
+
+ if (!l)
+ return "";
+
+ if (l <= MaxLen)
+ {
+ strcpy(s, lpsz);
+ }
+ else
+ {
+ memcpy(s, lpsz, MaxLen);
+ s[MaxLen] = '.';
+ s[MaxLen+1] = '.';
+ s[MaxLen+2] = '.';
+ s[MaxLen+3] = 0;
+ }
+
+ if (!s)
+ return NULL;
+
+ // convert line breaks and tabs to spaces
+
+ p = s;
+
+ while (*p)
+ {
+ if ( iswspace(*p) )
+ *p = ' ';
+ p++;
+ }
+
+ return s;
+}
+
+static void InitListView(HWND AHLV)
+{
+ LV_ITEM lvTIt;
+ int I;
+ char *S;
+ char S1[128];
+ STICKYNOTE *pNote;
+ TREEELEMENT *TTE;
+
+ char *V = Translate("Visible");
+ char *T = Translate("Top");
+
+ ListView_SetHoverTime(AHLV,700);
+ ListView_SetExtendedListViewStyle(AHLV,LVS_EX_FULLROWSELECT | LVS_EX_GRIDLINES | LVS_EX_TRACKSELECT);
+ ListView_DeleteAllItems(AHLV);
+
+ I = 0;
+ TTE = g_Stickies;
+ while (TTE)
+ {
+ pNote = (STICKYNOTE*)TTE->ptrdata;
+
+ lvTIt.mask = LVIF_TEXT;
+
+ if (!pNote->CustomTitle || !pNote->title)
+ GetTriggerTimeString(&pNote->ID, S1, sizeof(S1), TRUE);
+
+ lvTIt.iItem = I;
+ lvTIt.iSubItem = 0;
+ lvTIt.pszText = (pNote->CustomTitle && pNote->title) ? pNote->title : S1;
+ lvTIt.cchTextMax = (int)strlen(S1);
+ ListView_InsertItem(AHLV,&lvTIt);
+
+ if (pNote->Visible)
+ {
+ lvTIt.iItem = I;
+ lvTIt.iSubItem = 1;
+ lvTIt.pszText = V;
+ lvTIt.cchTextMax = (int)strlen(lvTIt.pszText);
+ ListView_SetItem(AHLV,&lvTIt);
+ }
+
+ if (pNote->OnTop)
+ {
+ lvTIt.iItem = I;
+ lvTIt.iSubItem = 2;
+ lvTIt.pszText = T;
+ lvTIt.cchTextMax = (int)strlen(lvTIt.pszText);
+ ListView_SetItem(AHLV,&lvTIt);
+ }
+
+ S = GetPreviewString(pNote->data);
+ lvTIt.iItem = I;
+ lvTIt.iSubItem = 3;
+ lvTIt.pszText = S;
+ lvTIt.cchTextMax = (int)strlen(S);
+ ListView_SetItem(AHLV,&lvTIt);
+
+ I++;
+ TTE = (TREEELEMENT*)TTE->next;
+ }
+
+ ListView_SetItemState(AHLV,0,LVIS_SELECTED,LVIS_SELECTED);
+}
+
+static BOOL DoListContextMenu(HWND AhWnd,WPARAM wParam,LPARAM lParam,STICKYNOTE *pNote)
+{
+ HWND hwndListView;
+ HMENU hMenuLoad,FhMenu;
+ MENUITEMINFO mii;
+
+ hwndListView = (HWND)wParam;
+ if (hwndListView != GetDlgItem(AhWnd,IDC_LISTREMINDERS)) return FALSE;
+ hMenuLoad = LoadMenu(hinstance,"MNU_NOTELISTPOPUP");
+ FhMenu = GetSubMenu(hMenuLoad,0);
+
+ mii.cbSize = sizeof(mii);
+ mii.fMask = MIIM_STATE;
+ mii.fState = MFS_DEFAULT;
+ if (!pNote)
+ mii.fState |= MFS_GRAYED;
+ SetMenuItemInfo(FhMenu, ID_CONTEXTMENUNOTELISTVIEW_EDITNOTE, FALSE, &mii);
+
+ if (!pNote)
+ {
+ EnableMenuItem(FhMenu, IDM_REMOVENOTE, MF_GRAYED|MF_BYCOMMAND);
+ EnableMenuItem(FhMenu, ID_CONTEXTMENUNOTELISTVIEW_TOGGLEVISIBILITY, MF_GRAYED|MF_BYCOMMAND);
+ EnableMenuItem(FhMenu, IDM_TOGGLEONTOP, MF_GRAYED|MF_BYCOMMAND);
+ }
+ else
+ {
+ if (pNote->Visible)
+ CheckMenuItem(FhMenu, ID_CONTEXTMENUNOTELISTVIEW_TOGGLEVISIBILITY, MF_CHECKED|MF_BYCOMMAND);
+ if (pNote->OnTop)
+ CheckMenuItem(FhMenu, IDM_TOGGLEONTOP, MF_CHECKED|MF_BYCOMMAND);
+ }
+
+ CallService(MS_LANGPACK_TRANSLATEMENU,(DWORD)FhMenu,0);
+ TrackPopupMenu(FhMenu,TPM_LEFTALIGN | TPM_RIGHTBUTTON,LOWORD(lParam),HIWORD(lParam),0,AhWnd,0);
+ DestroyMenu(hMenuLoad);
+
+ return TRUE;
+}
+
+
+INT_PTR CALLBACK DlgProcViewNotes(HWND Dialog,UINT Message,WPARAM wParam,LPARAM lParam)
+{
+ LV_COLUMN lvCol;
+ NMLISTVIEW *NM;
+ TCHAR *S;
+ int I;
+
+ switch (Message)
+ {
+ case WM_SIZE:
+ {
+ OnListResize(Dialog);
+ UpdateGeomFromWnd(Dialog, g_notesListGeom, NULL, 0);
+ break;
+ }
+ case WM_MOVE:
+ UpdateGeomFromWnd(Dialog, g_notesListGeom, NULL, 0);
+ break;
+ case WM_GETMINMAXINFO:
+ {
+ MINMAXINFO *mm = (MINMAXINFO*)lParam;
+ mm->ptMinTrackSize.x = 394;
+ mm->ptMinTrackSize.y = 300;
+ }
+ return 0;
+ case WM_RELOAD:
+ {
+ SetDlgItemText(Dialog,IDC_REMINDERDATA,"");
+ InitListView(GetDlgItem(Dialog,IDC_LISTREMINDERS));
+ return TRUE;
+ }
+ case WM_CONTEXTMENU:
+ {
+ HWND H;
+ STICKYNOTE *pNote = NULL;
+
+ H = GetDlgItem(Dialog,IDC_LISTREMINDERS);
+ if ( ListView_GetSelectedCount(H) )
+ {
+ I = ListView_GetSelectionMark(H);
+ if (I != -1)
+ {
+ pNote = (STICKYNOTE*)TreeGetAt(g_Stickies, I);
+ }
+ }
+
+ if (DoListContextMenu(Dialog, wParam, lParam, pNote))
+ return TRUE;
+ }
+ break;
+ case WM_INITDIALOG:
+ {
+ HWND H;
+
+ HICON hIcon = Skin_GetIconByHandle(iconList[13].hIcolib, ICON_SMALL);
+ SendMessage(Dialog, WM_SETICON, (WPARAM)ICON_SMALL, (LPARAM)hIcon);
+ hIcon = Skin_GetIconByHandle(iconList[13].hIcolib, ICON_BIG);
+ SendMessage(Dialog, WM_SETICON, (WPARAM)ICON_BIG, (LPARAM)hIcon);
+
+ SetWindowText(Dialog, LPGENT("Notes"));
+
+ TranslateDialogDefault(Dialog);
+
+ SetDlgItemText(Dialog,IDC_REMINDERDATA, _T(""));
+
+ H = GetDlgItem(Dialog,IDC_LISTREMINDERS);
+ lvCol.mask = LVCF_TEXT | LVCF_WIDTH;
+
+ S = TranslateT("Note text");
+ lvCol.pszText = S;
+ lvCol.cchTextMax = (int)_tcslen(S);
+ lvCol.cx = g_notesListColGeom[3];
+ ListView_InsertColumn(H,0,&lvCol);
+ lvCol.mask = LVCF_TEXT | LVCF_WIDTH;
+
+ S = TranslateT("Top");
+ lvCol.pszText = S;
+ lvCol.cchTextMax = (int)_tcslen(S);
+ lvCol.cx = g_notesListColGeom[2];
+ ListView_InsertColumn(H,0,&lvCol);
+ lvCol.mask = LVCF_TEXT | LVCF_WIDTH;
+
+ S = TranslateT("Visible");
+ lvCol.pszText = S;
+ lvCol.cchTextMax = (int)strlen(S);
+ lvCol.cx = g_notesListColGeom[1];
+ ListView_InsertColumn(H,0,&lvCol);
+ lvCol.mask = LVCF_TEXT | LVCF_WIDTH;
+
+ S = TranslateT("Date/Title");
+ lvCol.pszText = S;
+ lvCol.cchTextMax = (int)_tcslen(S);
+ lvCol.cx = g_notesListColGeom[0];
+ ListView_InsertColumn(H,0,&lvCol);
+
+ InitListView(H);
+ SetWindowLongPtr(GetDlgItem(H, 0), GWL_ID, IDC_LISTREMINDERS_HEADER);
+ LV = Dialog;
+
+ if (g_notesListGeom[1] && g_notesListGeom[2])
+ {
+ WINDOWPLACEMENT wp;
+ wp.length = sizeof(WINDOWPLACEMENT);
+ GetWindowPlacement(Dialog, &wp);
+ wp.rcNormalPosition.left = g_notesListGeom[0];
+ wp.rcNormalPosition.top = g_notesListGeom[1];
+ wp.rcNormalPosition.right = g_notesListGeom[2] + g_notesListGeom[0];
+ wp.rcNormalPosition.bottom = g_notesListGeom[3] + g_notesListGeom[1];
+ SetWindowPlacement(Dialog, &wp);
+ }
+ return TRUE;
+ }
+ case WM_CLOSE:
+ DestroyWindow(Dialog);
+ ListNotesVisible = FALSE;
+ return TRUE;
+
+ case WM_DESTROY:
+ ListNotesVisible = FALSE;
+ Skin_ReleaseIcon((HICON)SendMessage(Dialog, WM_SETICON, ICON_BIG, 0));
+ Skin_ReleaseIcon((HICON)SendMessage(Dialog, WM_SETICON, ICON_SMALL, 0));
+ return TRUE;
+
+ case WM_NOTIFY:
+ {
+ if (wParam == IDC_LISTREMINDERS)
+ {
+ NM = (NMLISTVIEW *)lParam;
+ switch (NM->hdr.code)
+ {
+ case LVN_ITEMCHANGED:
+ {
+ S = ((STICKYNOTE*)TreeGetAt(g_Stickies,NM->iItem))->data;
+ SetDlgItemText(Dialog,IDC_REMINDERDATA,S);
+ }
+ break;
+ case NM_DBLCLK:
+ {
+ HWND H;
+
+ H = GetDlgItem(Dialog,IDC_LISTREMINDERS);
+ if ( ListView_GetSelectedCount(H) )
+ {
+ I = ListView_GetSelectionMark(H);
+ if (I != -1)
+ {
+ EditNote((STICKYNOTE *)TreeGetAt(g_Stickies, I));
+ }
+ }
+ }
+ break;
+ }
+ }
+ else if (wParam == IDC_LISTREMINDERS_HEADER)
+ {
+ NMHEADER *NM = (NMHEADER*)lParam;
+ switch (NM->hdr.code)
+ {
+ case HDN_ENDTRACK:
+ UpdateGeomFromWnd(Dialog, NULL, g_notesListColGeom, SIZEOF(g_notesListColGeom));
+ break;
+ }
+ }
+ }
+ break;
+ case WM_COMMAND:
+ {
+ switch(LOWORD(wParam))
+ {
+ case ID_CONTEXTMENUNOTELISTVIEW_EDITNOTE:
+ {
+ HWND H;
+
+ H = GetDlgItem(Dialog,IDC_LISTREMINDERS);
+ if ( ListView_GetSelectedCount(H) )
+ {
+ I = ListView_GetSelectionMark(H);
+ if (I != -1)
+ {
+ EditNote((STICKYNOTE*)TreeGetAt(g_Stickies, I));
+ }
+ }
+ }
+ return TRUE;
+ case ID_CONTEXTMENUNOTELISTVIEW_TOGGLEVISIBILITY:
+ {
+ HWND H;
+
+ H = GetDlgItem(Dialog,IDC_LISTREMINDERS);
+ if ( ListView_GetSelectedCount(H) )
+ {
+ I = ListView_GetSelectionMark(H);
+ if (I != -1)
+ {
+ STICKYNOTE *SN = (STICKYNOTE*)TreeGetAt(g_Stickies, I);
+ SN->Visible = !SN->Visible;
+ ShowWindow(SN->SNHwnd,SN->Visible?SW_SHOWNA:SW_HIDE);
+ JustSaveNotes();
+ }
+ }
+ }
+ return TRUE;
+ case IDM_TOGGLEONTOP:
+ {
+ HWND H;
+
+ H = GetDlgItem(Dialog,IDC_LISTREMINDERS);
+ if ( ListView_GetSelectedCount(H) )
+ {
+ I = ListView_GetSelectionMark(H);
+ if (I != -1)
+ {
+ STICKYNOTE *SN = (STICKYNOTE*)TreeGetAt(g_Stickies,I);
+ SN->OnTop = !SN->OnTop;
+ SetWindowPos(SN->SNHwnd, SN->OnTop ? HWND_TOPMOST : HWND_NOTOPMOST, 0,0,0,0, SWP_SHOWWINDOW|SWP_NOMOVE|SWP_NOSIZE);
+ RedrawWindow(SN->SNHwnd, NULL, NULL, RDW_FRAME|RDW_INVALIDATE|RDW_UPDATENOW);
+ JustSaveNotes();
+ }
+ }
+ }
+ return TRUE;
+ case IDC_CLOSE:
+ {
+ DestroyWindow(Dialog);
+ ListNotesVisible = FALSE;
+ return TRUE;
+ }
+ case ID_CONTEXTMENUNOTEPOPUP_NEWNOTE:
+ case IDC_ADDNEWREMINDER:
+ {
+ PluginMenuCommandAddNew(0,0);
+ return TRUE;
+ }
+ case ID_CONTEXTMENUNOTELISTVIEW_DELETEALLNOTES:
+ {
+ PluginMenuCommandDeleteAll(0,0);
+ return TRUE;
+ }
+ case IDM_REMOVENOTE:
+ {
+ HWND H;
+
+ H = GetDlgItem(Dialog,IDC_LISTREMINDERS);
+ if ( ListView_GetSelectedCount(H) )
+ {
+ I = ListView_GetSelectionMark(H);
+ if (I != -1)
+ {
+ OnDeleteNote(Dialog, (STICKYNOTE*)TreeGetAt(g_Stickies, I));
+ }
+ }
+ }
+ return TRUE;
+ case ID_CONTEXTMENUNOTELISTVIEW_SHOW:
+ {
+ ShowHideNotes();
+ return TRUE;
+ }
+ case ID_CONTEXTMENUNOTEPOPUP_BRINGALLTOTOP:
+ {
+ BringAllNotesToFront(NULL);
+ return TRUE;
+ }
+ }
+ }
+ }
+ return FALSE;
+}