mirror of https://github.com/roytam1/kmeleon.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1847 lines
48 KiB
1847 lines
48 KiB
/* |
|
* Copyright (C) 2001 Jeff Doozan |
|
* |
|
* This program is free software; you can redistribute it and/or modify |
|
* it under the terms of the GNU General Public License as published by |
|
* the Free Software Foundation; either version 2, or (at your option) |
|
* any later version. |
|
* |
|
* This program is distributed in the hope that it will be useful, |
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
* GNU General Public License for more details. |
|
* |
|
* You should have received a copy of the GNU General Public License |
|
* along with this program; if not, write to the Free Software |
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
|
*/ |
|
|
|
#define WINVER 0x0500 |
|
#define _WIN32_WINNT 0x0500 |
|
#define WIN32_LEAN_AND_MEAN |
|
#include <windows.h> |
|
#include <shellapi.h> |
|
#include <commctrl.h> |
|
#include <stdlib.h> |
|
#include <shlwapi.h> |
|
#include "utf.h" |
|
|
|
#define PLUGIN_NAME "Toolbar Control Plugin" |
|
|
|
#define _Tr(x) kPlugin.kFuncs->Translate(x) |
|
|
|
#define KMELEON_PLUGIN_EXPORTS |
|
#include "kmeleon_plugin.h" |
|
#include "utils.h" |
|
#include "../../app/KMeleonConst.h" |
|
|
|
|
|
#include <afxres.h> |
|
#include "../../app/resource.h" |
|
|
|
/* Begin K-Meleon Plugin Header */ |
|
|
|
int Setup(); |
|
void Create(HWND parent); |
|
void Config(HWND parent); |
|
void Destroy(HWND hWnd); |
|
void Quit(); |
|
void DoRebar(HWND rebarWnd); |
|
int GetToolbarID(char *sName); |
|
void SetButtonImage(char *sParams); |
|
void EnableButton(char *sParams); |
|
int IsButtonEnabled(char *sParams); |
|
void CheckButton(char *sParams); |
|
int IsButtonChecked(char *sParams); |
|
int AddToolbarMsg(char* sParam); |
|
int AddButtonMsg(char* sParam); |
|
|
|
int GetConfigFiles(configFileType **configFiles); |
|
|
|
long DoMessage(const char *to, const char *from, const char *subject, long data1, long data2); |
|
|
|
kmeleonPlugin kPlugin = { |
|
KMEL_PLUGIN_VER_UTF8, |
|
PLUGIN_NAME, |
|
DoMessage |
|
}; |
|
|
|
|
|
/* End K-Meleon Plugin Header */ |
|
|
|
long DoMessage(const char *to, const char *from, const char *subject, long data1, long data2) |
|
{ |
|
if (to[0] == '*' || stricmp(to, kPlugin.dllname) == 0) { |
|
if (stricmp(subject, "Init") == 0) { |
|
Setup(); |
|
} |
|
else if (strcmp(subject, "Create") == 0) { |
|
Create((HWND)data1); |
|
} |
|
else if (strcmp(subject, "Config") == 0) { |
|
Config((HWND)data1); |
|
} |
|
else if (strcmp(subject, "Destroy") == 0) { |
|
Destroy((HWND)data1); |
|
} |
|
else if (strcmp(subject, "Quit") == 0) { |
|
Quit(); |
|
} |
|
else if (strcmp(subject, "DoRebar") == 0) { |
|
DoRebar((HWND)data1); |
|
} |
|
else if (strcmp(subject, "GetConfigFiles") == 0) { |
|
*(int *)data2 = GetConfigFiles((configFileType**)data1); |
|
} |
|
else if (strcmp(subject, "SetButtonImage") == 0) { |
|
SetButtonImage((char *)data1); |
|
} |
|
else if (strcmp(subject, "EnableButton") == 0) { |
|
EnableButton((char *)data1); |
|
} |
|
else if (strcmp(subject, "IsButtonEnabled") == 0) { |
|
*(int *)data2 = IsButtonEnabled((char *)data1); |
|
} |
|
else if (strcmp(subject, "CheckButton") == 0) { |
|
CheckButton((char *)data1); |
|
} |
|
else if (strcmp(subject, "IsButtonChecked") == 0) { |
|
*(int *)data2 = IsButtonChecked((char *)data1); |
|
} |
|
else if (strcmp(subject, "AddToolbar") == 0) { |
|
*(int *)data2 = AddToolbarMsg((char *)data1); |
|
} |
|
else if (strcmp(subject, "AddButton") == 0) { |
|
*(int *)data2 = AddButtonMsg((char *)data1); |
|
} |
|
else return 0; |
|
|
|
return 1; |
|
} |
|
return 0; |
|
} |
|
|
|
struct s_button { |
|
TCHAR *sName; |
|
char *sToolTip; |
|
char *sImagePath; |
|
char *hotImage; |
|
char *coldImage; |
|
char *deadImage; |
|
char *menu; |
|
char *lmenu; |
|
TCHAR *label; |
|
//HMENU menu; |
|
int iID; |
|
int width, height; |
|
s_button *next, *prev; |
|
}; |
|
|
|
struct s_toolbar { |
|
|
|
HWND hWnd; |
|
WORD iID; |
|
|
|
char *sTitle; |
|
|
|
HIMAGELIST hot; |
|
HIMAGELIST cold; |
|
HIMAGELIST dead; |
|
|
|
int iButtonCount; |
|
int width, height; |
|
|
|
s_button *pButtonHead; |
|
s_button *pButtonTail; |
|
s_toolbar *next; |
|
|
|
s_toolbar *nextWindow; |
|
HWND hwndWindow; |
|
}; |
|
s_toolbar *toolbar_head = NULL; |
|
int giToolbarCount = 0; |
|
BOOL gbIsComCtl6 = FALSE; |
|
BOOL gbLegacy = FALSE; |
|
|
|
bool LoadToolbars(TCHAR *filename); |
|
void AddImageToList(s_toolbar *pToolbar, s_button *pButton, int list, char *file); |
|
s_toolbar *AddToolbar(char *name, int width, int height); |
|
s_button *AddButton(s_toolbar *toolbar, char *name, int width, int height); |
|
void EndButton(s_toolbar *toolbar, s_button *button, int state); |
|
|
|
BOOL APIENTRY DllMain(HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved ) { |
|
return TRUE; |
|
} |
|
|
|
int Setup() |
|
{ |
|
HMODULE hComCtlDll = LoadLibrary(_T("comctl32.dll")); |
|
if (hComCtlDll) |
|
{ |
|
typedef HRESULT (CALLBACK *PFNDLLGETVERSION)(DLLVERSIONINFO*); |
|
|
|
PFNDLLGETVERSION pfnDllGetVersion = (PFNDLLGETVERSION)GetProcAddress(hComCtlDll, "DllGetVersion"); |
|
|
|
if (pfnDllGetVersion) |
|
{ |
|
DLLVERSIONINFO dvi = {0}; |
|
dvi.cbSize = sizeof(dvi); |
|
|
|
HRESULT hRes = (*pfnDllGetVersion)(&dvi); |
|
if (SUCCEEDED(hRes) && dvi.dwMajorVersion >= 6) |
|
gbIsComCtl6 = TRUE; |
|
} |
|
|
|
FreeLibrary(hComCtlDll); |
|
} |
|
|
|
gbLegacy = kPlugin.kFuncs->GetPreference(PREF_BOOL, "kmeleon.plugins.toolbars.legacy", &gbLegacy, &gbLegacy); |
|
|
|
char file[MAX_PATH]; |
|
kPlugin.kFuncs->GetFolder(FolderType::UserSettingsFolder, file, sizeof(file)); |
|
strcat_s(file, "\\toolbars.cfg"); |
|
bool loaded = LoadToolbars(utf8_to_t(file)); |
|
|
|
if (!loaded) { |
|
TCHAR szConfigFile[MAX_PATH]; |
|
kPlugin.kFuncs->FindSkinFile(L"toolbars.cfg", szConfigFile, MAX_PATH); |
|
loaded = LoadToolbars(szConfigFile); |
|
} |
|
|
|
if (!loaded) { |
|
kPlugin.kFuncs->GetFolder(FolderType::DefSettingsFolder, file, sizeof(file)); |
|
strcat_s(file, "\\toolbars.cfg"); |
|
loaded = LoadToolbars(utf8_to_t(file)); |
|
} |
|
|
|
if (!loaded) { |
|
MessageBox(NULL, utf8_to_t(_Tr("K-Meleon was not able to find your toolbar settings. Your selected skin may be missing or corrupt. Please, check your skin settings in the GUI appearance section of k-meleon preferences.")), utf8_to_t(_Tr(PLUGIN_NAME)), MB_OK); |
|
return 0; |
|
} |
|
|
|
return 1; |
|
} |
|
|
|
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam); |
|
|
|
WNDPROC KMeleonWndProc; |
|
s_button *FindButton(s_toolbar *pToolbar, int iButton); |
|
|
|
void Create(HWND parent){ |
|
KMeleonWndProc = (WNDPROC) GetWindowLong(parent, GWL_WNDPROC); |
|
SetWindowLong(parent, GWL_WNDPROC, (LONG)WndProc); |
|
|
|
s_toolbar *firstToolbar = NULL; |
|
s_toolbar *prevToolbar = NULL; |
|
s_toolbar *toolbar = toolbar_head; |
|
while (toolbar) { |
|
s_toolbar *newToolbar = new s_toolbar; |
|
*newToolbar = *toolbar; |
|
newToolbar->hwndWindow = parent; |
|
newToolbar->nextWindow = toolbar; |
|
newToolbar->next = NULL; |
|
if (prevToolbar != NULL) |
|
prevToolbar->next = newToolbar; |
|
prevToolbar = newToolbar; |
|
if (firstToolbar == NULL) |
|
firstToolbar = newToolbar; |
|
toolbar = toolbar->next; |
|
} |
|
toolbar_head = firstToolbar; |
|
} |
|
|
|
void Config(HWND hWndParent) { |
|
TCHAR cfgPath[MAX_PATH]; |
|
kPlugin.kFuncs->FindSkinFile(_T("toolbars.cfg"), cfgPath, MAX_PATH); |
|
ShellExecute(NULL, NULL, _T("notepad.exe"), cfgPath, NULL, SW_SHOW); |
|
} |
|
|
|
configFileType g_configFiles[1]; |
|
int GetConfigFiles(configFileType **configFiles) |
|
{ |
|
#ifdef _UNICODE |
|
TCHAR file[MAX_PATH]; |
|
kPlugin.kFuncs->FindSkinFile(_T("toolbars.cfg"), file, MAX_PATH ); |
|
utf16_to_utf8(file, g_configFiles[0].file, MAX_PATH); |
|
#else |
|
FindSkinFile(g_configFiles[0].file, _T("toolbars.cfg")); |
|
#endif |
|
|
|
strcpy(g_configFiles[0].label, "Toolbars"); |
|
|
|
strcpy(g_configFiles[0].helpUrl, "http://www.kmeleon.org"); |
|
|
|
*configFiles = g_configFiles; |
|
|
|
return 1; |
|
} |
|
|
|
void Destroy(HWND hWnd) { |
|
s_toolbar *toolbar = toolbar_head; |
|
s_toolbar *prevToolbar = NULL; |
|
while (toolbar) { |
|
if (toolbar->hwndWindow == hWnd) { |
|
s_toolbar *tempbar = toolbar; |
|
if (prevToolbar) { |
|
while (toolbar) { |
|
prevToolbar->nextWindow = toolbar->nextWindow; |
|
prevToolbar = prevToolbar->next; |
|
toolbar = toolbar->next; |
|
} |
|
} |
|
else { |
|
toolbar_head = toolbar->nextWindow; |
|
} |
|
|
|
s_toolbar *bar; |
|
while (tempbar) |
|
{ |
|
bar = tempbar; |
|
tempbar = tempbar->next; |
|
delete bar; |
|
} |
|
break; |
|
} |
|
else { |
|
prevToolbar = toolbar; |
|
toolbar = toolbar->nextWindow; |
|
} |
|
} |
|
} |
|
|
|
void Quit() { |
|
s_toolbar *tempbar, *toolbar = toolbar_head; |
|
s_button *tempbtn, *button; |
|
|
|
while (toolbar) { |
|
if (toolbar->sTitle) |
|
delete toolbar->sTitle; |
|
|
|
if (toolbar->hot) |
|
ImageList_Destroy(toolbar->hot); |
|
if (toolbar->cold) |
|
ImageList_Destroy(toolbar->cold); |
|
if (toolbar->dead) |
|
ImageList_Destroy(toolbar->dead); |
|
|
|
button = toolbar->pButtonHead; |
|
while (button) { |
|
if (button->sName) |
|
delete button->sName; |
|
if (button->label) |
|
delete button->label; |
|
if (button->menu) |
|
delete button->menu; |
|
if (button->lmenu) |
|
delete button->lmenu; |
|
if (button->sToolTip) |
|
delete button->sToolTip; |
|
if (button->sImagePath) |
|
delete button->sImagePath; |
|
if (button->hotImage) |
|
delete button->hotImage; |
|
if (button->coldImage) |
|
delete button->coldImage; |
|
if (button->deadImage) |
|
delete button->deadImage; |
|
|
|
tempbtn = button; |
|
button = button->next; |
|
delete tempbtn; |
|
} |
|
|
|
tempbar = toolbar; |
|
toolbar = toolbar->next; |
|
delete tempbar; |
|
} |
|
} |
|
|
|
void DoRebar(HWND rebarWnd) { |
|
if (!gbLegacy) return; |
|
s_toolbar *toolbar = toolbar_head; |
|
s_button *button; |
|
TBBUTTON *buttons = NULL; |
|
int sep; |
|
|
|
while (toolbar) { |
|
sep = 0; |
|
if (toolbar->iButtonCount == 0) { |
|
toolbar = toolbar->next; |
|
continue; |
|
} |
|
|
|
// Create the toolbar control to be added. |
|
toolbar->hWnd = kPlugin.kFuncs->CreateToolbar(GetParent(rebarWnd), CCS_NODIVIDER | CCS_NOPARENTALIGN | CCS_NORESIZE | TBSTYLE_FLAT | TBSTYLE_TRANSPARENT | TBSTYLE_TOOLTIPS); |
|
if (!toolbar->hWnd){ |
|
MessageBox(NULL, utf8_to_t(_Tr("Failed to create toolbar")), _T(PLUGIN_NAME), MB_OK); |
|
return; |
|
} |
|
|
|
buttons = new TBBUTTON[toolbar->iButtonCount]; |
|
button = toolbar->pButtonHead; |
|
int i = 0; |
|
int j = 0; |
|
while (button) { |
|
if (button->sName!=NULL || button->width!=0 || button->height!=0) { |
|
buttons[i].iBitmap = j; |
|
buttons[i].idCommand = button->iID; |
|
buttons[i].iString = j; |
|
j++; |
|
|
|
buttons[i].dwData = 0; |
|
buttons[i].fsState = TBSTATE_ENABLED; |
|
buttons[i].fsStyle = TBSTYLE_BUTTON; // | (button->menu?TBSTYLE_DROPDOWN:0); |
|
buttons[i].bReserved[0] = 0; |
|
} |
|
else { |
|
buttons[i].iBitmap = 0; |
|
buttons[i].idCommand = 0; |
|
buttons[i].iString = 0; |
|
sep++; |
|
|
|
buttons[i].dwData = 0; |
|
buttons[i].fsState = TBSTATE_ENABLED; |
|
buttons[i].fsStyle = TBSTYLE_SEP; |
|
buttons[i].bReserved[0] = 0; |
|
} |
|
|
|
i++; |
|
button = button->next; |
|
} |
|
SendMessage(toolbar->hWnd, TB_BUTTONSTRUCTSIZE, (WPARAM) sizeof(TBBUTTON), 0); |
|
SendMessage(toolbar->hWnd, TB_ADDBUTTONS, i, (LPARAM) buttons); |
|
|
|
// if no images were specified, then we'll be using text buttons |
|
if (!toolbar->hot) { |
|
TCHAR buf[4096]; // you'd have to be crazy to use more than 1K worth of toolbar text on a single toolbar |
|
int buflen = 0; |
|
button = toolbar->pButtonHead; |
|
while (button) { |
|
if (button->sName != NULL) { |
|
int len = _tcslen(button->sName); |
|
if (buflen + len > 4096) break; |
|
_tcscpy(buf+buflen, button->sName); |
|
buflen += len; |
|
buf[buflen] = 0; |
|
buflen++; |
|
} |
|
button = button->next; |
|
} |
|
buf[buflen] = 0; |
|
SendMessage(toolbar->hWnd, TB_ADDSTRING, 0, (LPARAM) buf); |
|
SendMessage(toolbar->hWnd, TB_SETIMAGELIST, 0, (LPARAM) NULL); |
|
} |
|
else { |
|
// if only one image was specified, set that as the default image |
|
// instead of making it the "hot" image |
|
if (!toolbar->cold) |
|
SendMessage(toolbar->hWnd, TB_SETIMAGELIST, 0, (LPARAM) toolbar->hot); |
|
else { |
|
SendMessage(toolbar->hWnd, TB_SETHOTIMAGELIST, 0, (LPARAM) toolbar->hot); |
|
SendMessage(toolbar->hWnd, TB_SETIMAGELIST, 0, (LPARAM) toolbar->cold); |
|
if (toolbar->dead) |
|
SendMessage(toolbar->hWnd, TB_SETDISABLEDIMAGELIST, 0, (LPARAM) toolbar->dead); |
|
} |
|
} |
|
|
|
SetWindowPos(toolbar->hWnd, NULL, 0, 0, 0, 0, SWP_FRAMECHANGED); |
|
|
|
|
|
// Register the band name and child hwnd |
|
kPlugin.kFuncs->RegisterBand(toolbar->hWnd, toolbar->sTitle, true); |
|
|
|
REBARBANDINFO rbBand; |
|
rbBand.cbSize = sizeof(REBARBANDINFO); // Required |
|
rbBand.fMask = RBBIM_STYLE | RBBIM_CHILD | RBBIM_CHILDSIZE | |
|
RBBIM_SIZE | RBBIM_IDEALSIZE; |
|
|
|
DWORD dwBtnSize = SendMessage(toolbar->hWnd, TB_GETBUTTONSIZE, 0,0); |
|
rbBand.fStyle = RBBS_FIXEDBMP; |
|
rbBand.lpText = NULL; |
|
rbBand.hwndChild = toolbar->hWnd; |
|
rbBand.cxMinChild = LOWORD(dwBtnSize) * (toolbar->iButtonCount-sep) + 8*sep; |
|
rbBand.cyMinChild = HIWORD(dwBtnSize); |
|
rbBand.cyIntegral = 1; |
|
rbBand.cyMaxChild = rbBand.cyMinChild; |
|
rbBand.cxIdeal = LOWORD(dwBtnSize) * (toolbar->iButtonCount-sep) + 8*sep; |
|
rbBand.cx = rbBand.cxIdeal; |
|
|
|
// Add the band that has the toolbar. |
|
SendMessage(rebarWnd, RB_INSERTBAND, (WPARAM)-1, (LPARAM)&rbBand); |
|
|
|
if (toolbar && toolbar->nextWindow) { |
|
s_toolbar *oldToolbar = toolbar->nextWindow; |
|
int i = 1; |
|
s_button *pButton = FindButton(oldToolbar, i); |
|
while (pButton) { |
|
if (SendMessage(oldToolbar->hWnd, TB_ISBUTTONENABLED, pButton->iID, 0) != 0) |
|
SendMessage(toolbar->hWnd, TB_ENABLEBUTTON, pButton->iID, MAKELONG(1, 0)); |
|
if (SendMessage(oldToolbar->hWnd, TB_ISBUTTONCHECKED, pButton->iID, 0) != 0) |
|
SendMessage(toolbar->hWnd, TB_CHECKBUTTON, pButton->iID, MAKELONG(1, 0)); |
|
|
|
i++; |
|
pButton = FindButton(oldToolbar, i); |
|
} |
|
} |
|
|
|
toolbar = toolbar->next; |
|
if (buttons) { |
|
delete [] buttons; |
|
buttons = NULL; |
|
} |
|
} |
|
} |
|
|
|
enum state { |
|
TOOLBAR = 0,// waiting for toolbar to be added |
|
BUTTON, // expecting a button to be added |
|
ID, // expecting a button id |
|
DESC, // expecting a tooltip/description |
|
HOT, // expecting theh hot image |
|
COLD, // expecting the cold image |
|
DEAD // expecting the disabled image |
|
}; |
|
|
|
|
|
/* Sample config |
|
|
|
Sample ToolBar(16,16) { # (width, height) is optional, defaults to 16, 16 |
|
Button1(16, 16) { # the (width, height) is optional, defaults to toolbar dimensions |
|
ID_NAV_STOP | MenuName # command / Menu |
|
Tooltip Text # Tooltip popup text |
|
c:\tool1.bmp[0] # hot image |
|
c:\tool2.bmp[0] # cold image (optional) |
|
c:\tool3.bmp[0] # dead image (optional) |
|
} |
|
} |
|
|
|
*/ |
|
|
|
|
|
int ifplugin(char *p) |
|
{ |
|
char *q; |
|
|
|
if (!p || !*p) |
|
return 0; |
|
|
|
q = strchr(p, '&'); |
|
if (q) { |
|
*q = 0; |
|
q++; |
|
while (*q && (*q=='&' || isspace(*q))) |
|
q++; |
|
return ifplugin(p) && ifplugin(q); |
|
} |
|
else { |
|
q = strchr(p, '|'); |
|
if (q) { |
|
*q = 0; |
|
q++; |
|
while (*q && (*q=='|' || isspace(*q))) |
|
q++; |
|
return ifplugin(p) || ifplugin(q); |
|
} |
|
else { |
|
while ( *p && isspace(*p) ) |
|
p++; |
|
int loaded = 1; |
|
if (*p=='!') |
|
loaded = 0; |
|
while ( *p && !isalpha(*p) ) |
|
p++; |
|
char *plugin = p; |
|
while ( *p && isalpha(*p) ) |
|
p++; |
|
*p = 0; |
|
if (strcmp(plugin, "tabs") == 0) |
|
{ |
|
int notab = 0; |
|
kPlugin.kFuncs->GetPreference(PREF_BOOL, "kmeleon.notab", ¬ab, ¬ab); |
|
return !notab; |
|
} |
|
kmeleonPlugin * plug = kPlugin.kFuncs->Load(plugin); |
|
if (!plug || !plug->loaded) |
|
return !loaded; |
|
else |
|
return loaded; |
|
} |
|
} |
|
return 0; |
|
} |
|
|
|
bool LoadToolbars(TCHAR *filename) { |
|
|
|
FILE* configFile = _tfopen(filename, _T("r")); |
|
if (!configFile) return false; |
|
|
|
s_toolbar *curToolbar = NULL; |
|
s_button *curButton = NULL; |
|
int iBuildState = TOOLBAR; |
|
|
|
int pauseParsing = 0; |
|
char buf[512]; |
|
while (fgets(buf, 512, configFile)) { |
|
|
|
char* p = SkipWhiteSpace(buf); |
|
TrimWhiteSpace(buf); |
|
|
|
if (p[0] == '#') {} |
|
|
|
// empty line |
|
else if (p[0] == 0) {} |
|
|
|
else if (pauseParsing > 0){ |
|
if (p[0] == '%'){ |
|
if (strnicmp(p+1, "ifplugin", 8) == 0) { |
|
pauseParsing++; |
|
} |
|
else if (strnicmp(p+1, "else", 4) == 0) { |
|
if (pauseParsing == 1) { |
|
pauseParsing = 0; |
|
} |
|
} |
|
else if (strnicmp(p+1, "endif", 5) == 0) { |
|
pauseParsing--; |
|
} |
|
} |
|
} |
|
else if (p[0] == '%'){ |
|
if (strnicmp(p+1, "ifplugin", 8) == 0) { |
|
pauseParsing = !ifplugin(p+9); |
|
} |
|
else if (strnicmp(p+1, "else", 4) == 0) { |
|
pauseParsing = 1; |
|
} |
|
else if (strnicmp(p+1, "endif", 5) == 0) { |
|
} |
|
} |
|
|
|
// end block |
|
else if (p[0] == '}') { |
|
if (iBuildState > BUTTON) { |
|
EndButton(curToolbar, curButton, iBuildState); |
|
iBuildState = BUTTON; |
|
} |
|
else |
|
iBuildState = TOOLBAR; |
|
|
|
} |
|
|
|
// "ToolBar Name(width, height) {" |
|
// "ToolButton(width, height) {" |
|
else if (iBuildState <= BUTTON) { |
|
// There can only be 2 things outside a toolbar definition |
|
// comments, and the beginning of a toolbar block |
|
char *cb = strchr(p, '{'); |
|
if (cb) { |
|
*cb = 0; |
|
p = SkipWhiteSpace(p); |
|
TrimWhiteSpace(p); |
|
|
|
|
|
int width, height; |
|
if (iBuildState == TOOLBAR || !curToolbar) { |
|
width=16; |
|
height=16; |
|
} |
|
else { |
|
width = curToolbar->width; |
|
height = curToolbar->height; |
|
} |
|
char *pp, *val; |
|
if ((pp = strchr(p, '('))) { |
|
*pp = 0; |
|
pp++; |
|
// get width from parameters |
|
while(*pp && (*pp==' ' || *pp=='\t')) pp++; |
|
if (*pp) { |
|
val = pp; |
|
if ( (pp = strchr(pp, ',')) ) { |
|
*pp = 0; |
|
pp++; |
|
width = atoi(val); |
|
} |
|
} |
|
// get height from parameters |
|
if (pp) { |
|
while(*pp && (*pp==' ' || *pp=='\t')) pp++; |
|
if (*pp) { |
|
val = pp; |
|
height = atoi(val); |
|
} |
|
} |
|
}; |
|
|
|
if (iBuildState == TOOLBAR) { |
|
// add new toolbar |
|
if (curToolbar) { |
|
curToolbar->next = AddToolbar(p, width, height); |
|
curToolbar = curToolbar->next; |
|
curButton = NULL; |
|
} |
|
else |
|
toolbar_head = curToolbar = AddToolbar(p, width, height); |
|
iBuildState++; |
|
} |
|
else if (iBuildState == BUTTON) { |
|
// add new button |
|
if (curButton) { |
|
curButton->next = AddButton(curToolbar, p, width, height); |
|
curButton = curButton->next; |
|
} |
|
else |
|
curButton = AddButton(curToolbar, p, width, height); |
|
iBuildState++; |
|
} |
|
else { |
|
MessageBox(NULL, utf8_to_t(_Tr("Extra { found")), NULL, MB_OK); |
|
} |
|
} |
|
cb = strchr(p, '-'); |
|
if (cb && iBuildState == BUTTON) { |
|
p = SkipWhiteSpace(p); |
|
TrimWhiteSpace(p); |
|
if (strcmp(p, "-") == 0) { |
|
// add new separator |
|
if (curButton) { |
|
curButton->next = AddButton(curToolbar, NULL, 0, 0); |
|
curButton = curButton->next; |
|
} |
|
else |
|
curButton = AddButton(curToolbar, NULL, 0, 0); |
|
EndButton(curToolbar, curButton, iBuildState); |
|
} |
|
} |
|
} |
|
|
|
// button data |
|
else { |
|
|
|
switch (iBuildState) { |
|
case ID: |
|
|
|
|
|
// ID_NAME|MENU |
|
|
|
// get the menu associated with the button |
|
curButton->menu = NULL; |
|
curButton->lmenu = NULL; |
|
char *pipe; |
|
pipe = strchr(p, '|'); |
|
if (pipe) { |
|
*pipe = 0; |
|
TrimWhiteSpace(p); |
|
|
|
TrimWhiteSpace(pipe+1); |
|
curButton->menu = new char[strlen(pipe+1) + 1]; |
|
strcpy(curButton->menu, pipe+1); |
|
} |
|
|
|
curButton->iID = kPlugin.kFuncs->GetID(p); |
|
if (!curButton->iID) |
|
if (kPlugin.kFuncs->GetMenu(p)) { |
|
curButton->iID = kPlugin.kFuncs->GetCommandIDs(1); |
|
curButton->lmenu = strdup(p); |
|
} |
|
|
|
if (!curButton->menu && curButton->iID == ID_NAV_BACK) |
|
curButton->menu = strdup("SHistoryBack"); |
|
else if (!curButton->menu && curButton->iID == ID_NAV_FORWARD) |
|
curButton->menu = strdup("SHistoryForward"); |
|
|
|
/* |
|
// if a menu wasn't explicitly set, see if the command id has a registered menu |
|
if (!pipe) |
|
curButton->menu = kPlugin.kFuncs->GetMenu(curButton->iID); |
|
*/ |
|
|
|
iBuildState++; |
|
|
|
break; |
|
case DESC: |
|
if (strcmp(p, "\"\"") != 0) { |
|
char* tooltip = p; |
|
if (strlen(p)>1 && p[0] == '\"' && p[strlen(p)-1] == '\"') { |
|
tooltip++; |
|
tooltip[strlen(tooltip)-1] = 0; |
|
} |
|
|
|
TrimWhiteSpace(tooltip); |
|
curButton->sToolTip = strdup(tooltip); |
|
} |
|
iBuildState++; |
|
break; |
|
case HOT: |
|
case COLD: |
|
case DEAD: |
|
{ |
|
switch (iBuildState) |
|
{ |
|
case HOT: curButton->hotImage = strdup(p); break; |
|
case COLD: curButton->coldImage = strdup(p); break; |
|
default: curButton->deadImage = strdup(p); break; |
|
} |
|
|
|
AddImageToList(curToolbar, curButton, iBuildState, p); |
|
} |
|
|
|
|
|
iBuildState++; |
|
break; |
|
} |
|
} |
|
} // while |
|
fclose(configFile); |
|
return true; |
|
} |
|
|
|
s_toolbar *AddToolbar(char *name, int width, int height) { |
|
|
|
if (!gbLegacy) { |
|
kPlugin.kFuncs->AddToolbar(name, width, height); |
|
//return nullptr; |
|
} |
|
|
|
s_toolbar *newToolbar = new s_toolbar; |
|
if (name) { |
|
newToolbar->sTitle = new char[strlen(name) + 1]; |
|
strcpy (newToolbar->sTitle, name); |
|
} |
|
else |
|
newToolbar->sTitle = NULL; |
|
|
|
|
|
newToolbar->width = width; |
|
newToolbar->height = height; |
|
newToolbar->iButtonCount = 0; |
|
newToolbar->next = NULL; |
|
|
|
newToolbar->hot = NULL; |
|
newToolbar->cold = NULL; |
|
newToolbar->dead = NULL; |
|
newToolbar->nextWindow = NULL; |
|
|
|
newToolbar->iID = ++giToolbarCount; |
|
newToolbar->pButtonHead = NULL; |
|
newToolbar->pButtonTail = NULL; |
|
newToolbar->hWnd = NULL; |
|
|
|
return newToolbar; |
|
} |
|
|
|
s_button *AddButton(s_toolbar *toolbar, char *name, int width, int height) { |
|
|
|
s_button *newButton = new s_button; |
|
|
|
if (name) { |
|
if (name[0] == '!') { |
|
name++; |
|
newButton->label = t_from_utf8(name); |
|
} else { |
|
newButton->label = NULL; |
|
} |
|
newButton->sName = t_from_utf8(name); |
|
} |
|
else { |
|
newButton->sName = NULL; |
|
newButton->label = NULL; |
|
} |
|
|
|
|
|
newButton->width = width; |
|
newButton->height = height; |
|
newButton->sToolTip = NULL; |
|
newButton->iID = 0; |
|
newButton->menu = NULL; |
|
newButton->lmenu = NULL; |
|
newButton->next = NULL; |
|
newButton->sImagePath = NULL; |
|
newButton->hotImage = NULL; |
|
newButton->coldImage = NULL; |
|
newButton->deadImage = NULL; |
|
|
|
if (!toolbar) return newButton; // !gbLegacy |
|
newButton->prev = toolbar->pButtonTail; |
|
|
|
if (toolbar->pButtonHead == NULL) |
|
toolbar->pButtonHead = newButton; |
|
if (toolbar->pButtonTail != NULL) |
|
toolbar->pButtonTail->next = newButton; |
|
toolbar->pButtonTail = newButton; |
|
toolbar->iButtonCount++; |
|
|
|
return newButton; |
|
} |
|
|
|
|
|
// if no cold or disabled button images have been defined, |
|
// we'll just have to create some |
|
void EndButton(s_toolbar *toolbar, s_button *button, int state) { |
|
if (!gbLegacy) { |
|
char* name = button->sName ? utf8_from_utf16(button->sName) : 0; |
|
char* label = button->label ? utf8_from_utf16(button->label) : 0; |
|
char* cmd = nullptr; |
|
if (button->lmenu) { |
|
cmd = (char*)malloc(sizeof(char) * strlen(button->lmenu)+2); |
|
cmd[0] = '@'; |
|
cmd[1] = 0; |
|
strcat(cmd, button->lmenu); |
|
} |
|
|
|
kmeleonButton kbutton = { |
|
name, |
|
label, |
|
button->sToolTip, |
|
cmd ? cmd : "", |
|
button->menu, |
|
button->hotImage, |
|
button->coldImage, |
|
button->deadImage, |
|
true, |
|
false, |
|
button->iID, |
|
0, |
|
button->width, |
|
button->height |
|
}; |
|
|
|
if (kbutton.hotimage && !kbutton.coldimage) { |
|
kbutton.coldimage = kbutton.hotimage; |
|
kbutton.hotimage = nullptr; |
|
} |
|
|
|
|
|
kPlugin.kFuncs->AddButtonEx(toolbar->sTitle, &kbutton); |
|
if (label) free(label); |
|
if (name) free(name); |
|
if (cmd) free(cmd); |
|
//delete button; |
|
return; |
|
} |
|
|
|
if (state == COLD) { |
|
// the following is a very messed up way of creating a new |
|
// bitmap that is compatible with the image we want it the imagelist |
|
// and then copying the image into our new bitmap |
|
|
|
int index = ImageList_GetImageCount(toolbar->hot)-1; |
|
|
|
// get a handle to the bitmap in the imagelist |
|
IMAGEINFO ii; |
|
ImageList_GetImageInfo(toolbar->hot, index, &ii); |
|
|
|
// create a 1x1 compatbile bitmap from the image |
|
HBITMAP hbmpTemp = (HBITMAP) CopyImage(ii.hbmImage, IMAGE_BITMAP, 1, 1, LR_COPYRETURNORG); |
|
|
|
// select the 1x1 bitmap into a new DC |
|
HDC hdcTemp = CreateCompatibleDC(NULL); |
|
SelectObject(hdcTemp, hbmpTemp); |
|
|
|
// create a new bitmap and DC based on the one we just created |
|
HDC hdcNew = CreateCompatibleDC(hdcTemp); |
|
HBITMAP hbmpNew = CreateCompatibleBitmap(hdcTemp, ii.rcImage.right - ii.rcImage.left, ii.rcImage.bottom - ii.rcImage.top); |
|
SelectObject(hdcNew, hbmpNew); |
|
|
|
// we don't need the 1x1 bitmap DC anymore |
|
DeleteDC(hdcTemp); |
|
DeleteObject(hbmpTemp); |
|
|
|
// draw the image into our compatible bitmap |
|
ImageList_DrawEx(toolbar->hot, index, hdcNew, 0, 0, 0, 0, RGB(255, 0, 255), NULL, ILD_NORMAL); |
|
|
|
DeleteDC(hdcNew); |
|
|
|
ImageList_AddMasked(toolbar->cold, hbmpNew, RGB(255, 0, 255)); |
|
|
|
DeleteObject(hbmpNew); |
|
} |
|
} |
|
|
|
HBITMAP LoadButtonImage(s_toolbar *pToolbar, s_button *pButton, char *sFile, COLORREF* bgColor) { |
|
|
|
if (!sFile || !*sFile) |
|
return 0; |
|
|
|
if (bgColor) *bgColor =-1; |
|
|
|
int index; |
|
TCHAR* _sFile = t_from_utf8(sFile); |
|
TCHAR *p = _tcschr(_sFile, _T('[')); |
|
if (p) { |
|
*p = 0; |
|
p = SkipWhiteSpace(p+1); |
|
index = _ttoi(p); |
|
} |
|
else |
|
index = 0; // set default image index |
|
|
|
int xstart, ystart; |
|
int height = pButton->height; |
|
int width = pButton->width; |
|
|
|
// center the bitmap if smaller, and crop it if it's too big |
|
if (height > pToolbar->height) height = pToolbar->height; |
|
if (width > pToolbar->width) width = pToolbar->width; |
|
|
|
xstart = (pToolbar->width - width)/2; |
|
ystart = (pToolbar->height - height)/2; |
|
|
|
HDC hdcButton, hdcBitmap; |
|
HBITMAP hButton, hBitmap; |
|
HBRUSH hBrush; |
|
|
|
UINT flag = LR_LOADFROMFILE | LR_CREATEDIBSECTION; |
|
|
|
if (strchr(sFile, '\\')) { |
|
hBitmap = (HBITMAP)LoadImage(NULL, _sFile, IMAGE_BITMAP, 0, 0, flag); |
|
} |
|
else { |
|
TCHAR fullpath[MAX_PATH]; |
|
kPlugin.kFuncs->FindSkinFile(_sFile, fullpath, MAX_PATH); |
|
hBitmap = (HBITMAP)LoadImage(NULL, fullpath, IMAGE_BITMAP, 0, 0, flag); |
|
} |
|
free(_sFile); |
|
|
|
if (!hBitmap) return NULL; |
|
hdcBitmap = CreateCompatibleDC(NULL); |
|
|
|
struct { |
|
BITMAPINFOHEADER header; |
|
COLORREF col[256]; |
|
} bmpi = {0}; |
|
|
|
bmpi.header.biSize = sizeof(BITMAPINFOHEADER); |
|
|
|
GetDIBits(hdcBitmap, hBitmap, 0, 0, NULL, (BITMAPINFO*)&bmpi, DIB_RGB_COLORS); |
|
int nCol = ((width*index) % bmpi.header.biWidth) / width; |
|
int nLine = bmpi.header.biHeight / height + (width*index) / bmpi.header.biWidth - 1; |
|
if (nLine<0) return NULL; |
|
if (bmpi.header.biBitCount == 32) { |
|
|
|
|
|
int srcWidth = bmpi.header.biWidth * 4; |
|
int srcHeight = bmpi.header.biHeight; |
|
|
|
int dstWidth = width * 4; |
|
int offset = nCol * dstWidth + nLine * srcWidth * height; |
|
|
|
if (offset + (height-1) * srcWidth + dstWidth > srcWidth * srcHeight) |
|
return NULL; |
|
|
|
BYTE* srcBits = new BYTE[srcWidth * srcHeight]; |
|
GetDIBits(hdcBitmap, hBitmap, 0, srcHeight, srcBits, (BITMAPINFO*)&bmpi, DIB_RGB_COLORS); |
|
|
|
bmpi.header.biWidth = width; |
|
bmpi.header.biHeight = height; |
|
|
|
BYTE* dstBits = NULL; |
|
HBITMAP hBmp = CreateDIBSection(hdcBitmap, (BITMAPINFO*)&bmpi, DIB_RGB_COLORS, (void**)&dstBits, NULL, 0); |
|
|
|
if (!hBmp) { |
|
DeleteObject(hBitmap); |
|
DeleteDC(hdcBitmap); |
|
delete[] srcBits; |
|
return NULL; |
|
} |
|
|
|
for (int i = 0; i< height-1; i++) |
|
memcpy(&dstBits[dstWidth*i], &srcBits[i * srcWidth + offset], dstWidth); |
|
|
|
DeleteObject(hBitmap); |
|
|
|
/*if (!gbIsComCtl6) { |
|
bmpi.header.biBitCount = 24; |
|
bmpi.header.biCompression = 0; |
|
|
|
pDest = NULL; |
|
HBITMAP hBmp2 = CreateDIBSection(hdcBitmap, (BITMAPINFO*)&bmpi, DIB_RGB_COLORS, (void**)&pDest, NULL, 0); |
|
|
|
if (!hBmp2) { |
|
DeleteObject(hBmp); |
|
DeleteDC(hdcBitmap); |
|
delete[] pData; |
|
return NULL; |
|
} |
|
|
|
GetDIBits(hdcBitmap, hBmp, 0, nLineCnt, pData, (BITMAPINFO*)&bmpi, DIB_RGB_COLORS); |
|
|
|
memcpy(pDest, pData, width * height * 4); |
|
DeleteObject(hBmp); |
|
hBmp = hBmp2; |
|
}*/ |
|
|
|
if (!gbIsComCtl6 && bgColor) { |
|
// Pseudo background color check |
|
*bgColor = RGB(255, 0, 255); |
|
for (int i=0;i<width*height*4;i+=4) |
|
if (dstBits[i] == 0) { |
|
*bgColor = RGB(dstBits[i+1], dstBits[i+2], dstBits[i+3]); |
|
break; |
|
} |
|
} |
|
|
|
delete[] srcBits; |
|
DeleteDC(hdcBitmap); |
|
return hBmp; |
|
} |
|
|
|
HGDIOBJ oldBmp = SelectObject(hdcBitmap, hBitmap); |
|
|
|
hdcButton = CreateCompatibleDC(hdcBitmap); |
|
hButton = CreateCompatibleBitmap(hdcBitmap, pToolbar->width, pToolbar->height); |
|
HGDIOBJ oldBmp2 = SelectObject(hdcButton, hButton); |
|
|
|
// fill the button with the transparency |
|
hBrush = CreateSolidBrush(RGB(255,0,255)); |
|
HGDIOBJ oldBrush = SelectObject(hdcButton, hBrush); |
|
PatBlt(hdcButton, 0, 0, pToolbar->width, pToolbar->height, PATCOPY); |
|
|
|
// copy the button from the full bitmap |
|
BitBlt(hdcButton, xstart, ystart, width, height, hdcBitmap, width*nCol + height*nLine, 0, SRCCOPY); |
|
SelectObject(hdcButton, oldBrush); |
|
SelectObject(hdcButton, oldBmp2); |
|
SelectObject(hdcBitmap, oldBmp); |
|
DeleteDC(hdcBitmap); |
|
DeleteDC(hdcButton); |
|
|
|
DeleteObject(hBrush); |
|
DeleteObject(hBitmap); |
|
|
|
if (bgColor) *bgColor = RGB(255,0,255); |
|
return hButton; |
|
|
|
} |
|
|
|
void AddImageToList(s_toolbar *pToolbar, s_button *pButton, int list, char *sFile) { |
|
|
|
if (!pToolbar) return; //!gbLegacy |
|
|
|
HIMAGELIST* pImgList = NULL; |
|
switch (list) |
|
{ |
|
case HOT: pImgList = &pToolbar->hot; break; |
|
case COLD: pImgList = &pToolbar->cold; break; |
|
default: pImgList = &pToolbar->dead; break; |
|
} |
|
|
|
if (!*pImgList) |
|
*pImgList = ImageList_Create(pToolbar->width, pToolbar->height, ILC_MASK | (gbIsComCtl6 ? ILC_COLOR32 : ILC_COLORDDB), 10, 10); |
|
|
|
COLORREF bgColor; |
|
HBITMAP hButton = LoadButtonImage(pToolbar, pButton, sFile, &bgColor); |
|
|
|
if (bgColor != -1) |
|
ImageList_AddMasked(*pImgList, hButton, bgColor); |
|
else |
|
ImageList_Add(*pImgList, hButton, 0); |
|
|
|
DeleteObject(hButton); |
|
|
|
free(pButton->sImagePath); |
|
pButton->sImagePath = strdup(sFile); |
|
} |
|
|
|
|
|
/* |
|
We use the toolbar name to ID conversion scheme because it lets us later squeeze both the |
|
toolbar ID the button ID into the same LONG paramater in SendMessage calls. Since we |
|
need one of the two SendMessage paramaters for a return value data pointer, the |
|
alternative to using numeric ids would be have to be passing a pointer to a structure |
|
containing the toolbar string name and the button ID. |
|
*/ |
|
|
|
int GetToolbarID(char *sToolbar) { |
|
|
|
s_toolbar *pToolbar = toolbar_head; |
|
while (pToolbar) { |
|
if (pToolbar->sTitle && *pToolbar->sTitle && !strcmpi(sToolbar, pToolbar->sTitle)) |
|
return pToolbar->iID; |
|
pToolbar = pToolbar->next; |
|
} |
|
|
|
return 0; // return 0 if the toolbar does not exist, the first toolbar number is 1 |
|
} |
|
|
|
int AddToolbarMsg(char *sParams) { |
|
// sParams = ToolbarName, width, height |
|
char *p = SkipWhiteSpace(sParams); |
|
char *c = strchr(sParams, ','); |
|
if (!c) return 0; |
|
*c = 0; |
|
|
|
p = SkipWhiteSpace(c+1); |
|
c = strchr(p, ','); |
|
if (!c) return 0; |
|
*c = 0; |
|
int width = atoi(p); |
|
int height = atoi(SkipWhiteSpace(c+1)); |
|
|
|
if (toolbar_head) { |
|
s_toolbar *t = toolbar_head; |
|
while (t->next) t = t->next; |
|
t->next = AddToolbar(sParams, width, height); |
|
} |
|
else |
|
toolbar_head = AddToolbar(sParams, width, height); |
|
|
|
return 1; |
|
} |
|
|
|
int AddButtonMsg(char *sParams) { |
|
// sParams toolbarname, buttonname, command, menu, tooltip, width, height, hot, cold, head |
|
char *p = SkipWhiteSpace(sParams); |
|
char *c = strchr(sParams, ','); |
|
if (!c) return 0; |
|
*c = 0; |
|
|
|
s_toolbar *pToolbar = toolbar_head; |
|
while (pToolbar) { |
|
if (strcmp(pToolbar->sTitle, sParams) == 0) |
|
break; |
|
pToolbar = pToolbar->next; |
|
} |
|
|
|
if (!pToolbar) return 0; |
|
|
|
p = SkipWhiteSpace(c+1); |
|
c = strchr(p, ','); |
|
if (!c) return 0; |
|
*c = 0; |
|
char *buttonname = p; |
|
|
|
p = SkipWhiteSpace(c+1); |
|
c = strchr(p, ','); |
|
if (!c) return 0; |
|
*c = 0; |
|
int command = kPlugin.kFuncs->GetID(p); |
|
if (!command) return 0; |
|
|
|
p = SkipWhiteSpace(c+1); |
|
c = strchr(p, ','); |
|
if (!c) return 0; |
|
*c = 0; |
|
char* menu = p; |
|
|
|
p = SkipWhiteSpace(c+1); |
|
c = strchr(p, ','); |
|
if (!c) return 0; |
|
*c = 0; |
|
char* tooltip = p; |
|
|
|
p = SkipWhiteSpace(c+1); |
|
c = strchr(p, ','); |
|
if (!c) return 0; |
|
*c = 0; |
|
int width = atoi(p); |
|
|
|
p = SkipWhiteSpace(c+1); |
|
c = strchr(p, ','); |
|
if (!c) return 0; |
|
*c = 0; |
|
int height = atoi(p); |
|
|
|
char* hot = 0, *cold = 0, *dead = 0; |
|
p = SkipWhiteSpace(c+1); |
|
c = strchr(p, ','); |
|
if (!c) { |
|
hot = p; |
|
} |
|
else { |
|
*c = 0; |
|
hot = p; |
|
p = SkipWhiteSpace(c+1); |
|
c = strchr(p, ','); |
|
if (!c) { |
|
cold = p; |
|
} |
|
else { |
|
*c = 0; |
|
cold = p; |
|
p = SkipWhiteSpace(c+1); |
|
dead = p; |
|
} |
|
} |
|
|
|
s_button* pButton = pToolbar->pButtonHead; |
|
while (pButton) { |
|
if (pButton->iID == command) |
|
return 0; |
|
pButton = pButton->next; |
|
} |
|
|
|
pButton = AddButton(pToolbar, buttonname, width, height); |
|
pButton->sToolTip = strdup(tooltip); |
|
pButton->menu = new char[strlen(menu) + 1]; |
|
strcpy(pButton->menu, menu); |
|
pButton->iID = command; |
|
|
|
if (hot) { |
|
AddImageToList(pToolbar, pButton, HOT, hot); |
|
pButton->hotImage = strdup(hot); |
|
} |
|
|
|
if (cold) { |
|
AddImageToList(pToolbar, pButton, COLD, cold); |
|
pButton->coldImage = strdup(cold); |
|
} |
|
|
|
if (dead) { |
|
AddImageToList(pToolbar, pButton, DEAD, dead); |
|
pButton->deadImage = strdup(dead); |
|
} |
|
|
|
EndButton(pToolbar, pButton, !cold? COLD : DEAD); |
|
return 1; |
|
} |
|
|
|
s_toolbar *FindToolbar(WORD iToolbar) { |
|
// make sure the toolbar id is valid |
|
if (iToolbar == 0 || iToolbar > giToolbarCount) |
|
return NULL; |
|
|
|
s_toolbar *pToolbar = toolbar_head; |
|
while (pToolbar) { |
|
if (pToolbar->iID == iToolbar) |
|
return pToolbar; |
|
pToolbar = pToolbar->next; |
|
} |
|
|
|
return NULL; |
|
} |
|
|
|
s_button *FindButton(s_toolbar *pToolbar, int iButton) { |
|
|
|
if (!pToolbar) |
|
return NULL; |
|
|
|
s_button *pButton = pToolbar->pButtonHead; |
|
while (pButton) { |
|
if (pButton->iID == iButton) |
|
return pButton; |
|
pButton = pButton->next; |
|
} |
|
|
|
int i = 1; |
|
pButton = pToolbar->pButtonHead; |
|
while (pButton) { |
|
if (i++ == iButton) |
|
return pButton; |
|
pButton = pButton->next; |
|
} |
|
|
|
return NULL; |
|
} |
|
|
|
|
|
enum list { IMAGELIST_HOT = 1, IMAGELIST_COLD, IMAGELIST_DEAD }; |
|
|
|
|
|
void SetButtonImage(char *sParams) {//WORD iToolbar, WORD iButton, char *sImage) { |
|
|
|
// sParams = "ToolbarID, BUTTON_ID, [HOT|COLD|DEAD], Path\to\new\image.bmp[0]" |
|
|
|
// parse paramaters |
|
|
|
// Get ToolbarID param |
|
char *p = SkipWhiteSpace(sParams); |
|
char *name = p; |
|
char *d = strchr(sParams, ','); |
|
if (!d) return; |
|
*d = 0; // terminate string |
|
int iToolbar = atoi(p); |
|
if (!iToolbar) |
|
iToolbar = GetToolbarID(p); |
|
|
|
|
|
// Get BUTTON_ID param |
|
p = SkipWhiteSpace(d+1); |
|
char *c = strchr(p, ','); |
|
if (!c) return; |
|
*c = 0; // terminate string |
|
int iButton = atoi(p); |
|
if (!iButton) |
|
iButton = kPlugin.kFuncs->GetID(p); |
|
*c = ','; // replace comma |
|
|
|
|
|
// Get imagelist param (hot, cold, dead) |
|
p = SkipWhiteSpace(c+1); |
|
c = strchr(p, ','); |
|
if (!c) return; |
|
*c = 0; // terminate string |
|
int iImagelist; |
|
if (!strcmpi(p, "hot")) |
|
iImagelist = IMAGELIST_HOT; |
|
else if (!strcmpi(p, "cold")) |
|
iImagelist = IMAGELIST_COLD; |
|
else if (!strcmpi(p, "dead")) |
|
iImagelist = IMAGELIST_DEAD; |
|
else |
|
iImagelist = IMAGELIST_HOT; |
|
*c = ','; // replace comma |
|
|
|
|
|
// get image param |
|
char *sImage = SkipWhiteSpace(c+1); |
|
|
|
if (!gbLegacy) { |
|
char* hotimage = nullptr, *deadimage = nullptr, *coldimage = nullptr; |
|
switch(iImagelist) { |
|
case IMAGELIST_HOT:hotimage = sImage; break; |
|
case IMAGELIST_COLD:coldimage = sImage; break; |
|
case IMAGELIST_DEAD:deadimage = sImage; break; |
|
} |
|
|
|
kPlugin.kFuncs->SetButtonIcon(name, iButton, coldimage, nullptr, hotimage, nullptr, deadimage, nullptr); |
|
} |
|
|
|
*d = ','; // replace comma |
|
|
|
s_toolbar *pToolbar = FindToolbar(iToolbar); |
|
if (!pToolbar) |
|
return; |
|
|
|
s_button *pButton = FindButton(pToolbar, iButton); |
|
if (!pButton) |
|
return; |
|
|
|
if (pButton->sImagePath && *pButton->sImagePath && !strcmpi(pButton->sImagePath, sImage)) |
|
return; |
|
|
|
int index = SendMessage(pToolbar->hWnd, TB_COMMANDTOINDEX, pButton->iID, 0); |
|
|
|
COLORREF bgColor; |
|
HBITMAP hButton = LoadButtonImage(pToolbar, pButton, sImage, &bgColor); |
|
|
|
HDC hdcButton = CreateCompatibleDC(NULL); |
|
SelectObject(hdcButton, hButton); |
|
|
|
HIMAGELIST hImgList = NULL; |
|
if (iImagelist == IMAGELIST_HOT) |
|
hImgList = pToolbar->hot; |
|
else if (iImagelist == IMAGELIST_COLD) |
|
hImgList = pToolbar->cold; |
|
else if (iImagelist == IMAGELIST_DEAD) |
|
hImgList = pToolbar->dead; |
|
|
|
if (bgColor != -1) { |
|
// Create the transparency mask |
|
HDC hdcMask = CreateCompatibleDC(hdcButton); |
|
HBITMAP hMask = CreateBitmap(pButton->width, pButton->height, 1, 1, NULL); |
|
SelectObject(hdcMask, hMask); |
|
SetBkColor(hdcButton, bgColor); |
|
BitBlt(hdcMask, 0, 0, pButton->width, pButton->height, hdcButton, 0, 0, SRCCOPY); |
|
DeleteObject(hdcMask); |
|
ImageList_Replace(hImgList, index, hButton, hMask); |
|
DeleteObject(hMask); |
|
} |
|
else |
|
ImageList_Replace(hImgList, index, hButton, 0); |
|
|
|
DeleteObject(hdcButton); |
|
DeleteObject(hButton); |
|
|
|
// force the toolbar to reload the image from the imagelist |
|
while (pToolbar) { |
|
SendMessage(pToolbar->hWnd, TB_CHANGEBITMAP, iButton, MAKELPARAM(index, 0)); |
|
pToolbar = pToolbar->nextWindow; |
|
} |
|
|
|
delete pButton->sImagePath; |
|
pButton->sImagePath = strdup(sImage); |
|
} |
|
|
|
|
|
void EnableButton(char *sParams) { |
|
|
|
// sParams = "ToolbarID, BUTTON_ID, STATE" |
|
|
|
// Get ToolbarID param |
|
char *p = SkipWhiteSpace(sParams); |
|
char *c = strchr(sParams, ','); |
|
if (!c) return; |
|
*c = 0; // terminate string |
|
int iToolbar = atoi(p); |
|
if (!iToolbar) |
|
iToolbar = GetToolbarID(p); |
|
|
|
|
|
// Get BUTTON_ID param |
|
char* q = SkipWhiteSpace(c+1); |
|
char* d = strchr(p, ','); |
|
if (!d) return; |
|
*d = 0; // terminate string |
|
int iButton = atoi(q); |
|
if (!iButton) |
|
iButton = kPlugin.kFuncs->GetID(q); |
|
*d = ','; // replace comma |
|
|
|
// Get STATE param |
|
p = SkipWhiteSpace(d+1); |
|
int iState = atoi(p); |
|
|
|
if (!gbLegacy) { |
|
kmeleonButton b; |
|
b.enabled = iState; |
|
b.checked = -1; |
|
kPlugin.kFuncs->SetButton(p, iButton, &b); |
|
} |
|
*c = ','; // replace comma |
|
|
|
s_toolbar *pToolbar = FindToolbar(iToolbar); |
|
if (!pToolbar) |
|
return; |
|
|
|
while (pToolbar) { |
|
if (pToolbar->hWnd == NULL || pToolbar->nextWindow == NULL) |
|
return; |
|
s_button *pButton = FindButton(pToolbar, iButton); |
|
if (!pButton) |
|
return; |
|
|
|
SendMessage(pToolbar->hWnd, TB_ENABLEBUTTON, pButton->iID, MAKELONG(iState != 0, 0)); |
|
pToolbar = pToolbar->nextWindow; |
|
} |
|
} |
|
|
|
int IsButtonEnabled(char *sParams) { |
|
|
|
// sParams = "ToolbarID, BUTTON_ID" |
|
|
|
// Get ToolbarID param |
|
char *p = SkipWhiteSpace(sParams); |
|
char *c = strchr(sParams, ','); |
|
if (!c) return NULL; |
|
*c = 0; // terminate string |
|
int iToolbar = atoi(p); |
|
if (!iToolbar) |
|
iToolbar = GetToolbarID(p); |
|
|
|
// Get BUTTON_ID param |
|
char* q = SkipWhiteSpace(c+1); |
|
int iButton = atoi(q); |
|
if (!iButton) |
|
iButton = kPlugin.kFuncs->GetID(q); |
|
|
|
if (!gbLegacy) { |
|
kmeleonButton b; |
|
kPlugin.kFuncs->GetButton(p, iButton, &b); |
|
*c = ','; // replace comma |
|
return b.enabled; |
|
} |
|
*c = ','; // replace comma |
|
|
|
|
|
s_toolbar *pToolbar = FindToolbar(iToolbar); |
|
if (!pToolbar) |
|
return NULL; |
|
|
|
s_button *pButton = FindButton(pToolbar, iButton); |
|
if (!pButton) |
|
return NULL; |
|
|
|
while (pToolbar) { |
|
if (pToolbar->hwndWindow == GetActiveWindow()) |
|
return SendMessage(pToolbar->hWnd, TB_ISBUTTONENABLED, pButton->iID, 0) != 0; |
|
pToolbar = pToolbar->nextWindow; |
|
} |
|
return NULL; |
|
} |
|
|
|
|
|
void CheckButton(char *sParams) { |
|
|
|
// sParams = "ToolbarID, BUTTON_ID, STATE" |
|
|
|
// Get ToolbarID param |
|
char *p = SkipWhiteSpace(sParams); |
|
char *c = strchr(sParams, ','); |
|
if (!c) return; |
|
*c = 0; // terminate string |
|
int iToolbar = atoi(p); |
|
if (!iToolbar) |
|
iToolbar = GetToolbarID(p); |
|
|
|
|
|
// Get BUTTON_ID param |
|
char* q = SkipWhiteSpace(c+1); |
|
char *d = strchr(q, ','); |
|
if (!c) return; |
|
*d = 0; // terminate string |
|
int iButton = atoi(q); |
|
if (!iButton) |
|
iButton = kPlugin.kFuncs->GetID(q); |
|
*d = ','; // replace comma |
|
|
|
// Get STATE param |
|
q = SkipWhiteSpace(d+1); |
|
int iState = atoi(q); |
|
|
|
if (!gbLegacy) { |
|
kmeleonButton b = {0}; |
|
b.checked = iState; |
|
b.enabled = -1; |
|
kPlugin.kFuncs->SetButton(p, iButton, &b); |
|
} |
|
*c = ','; // replace comma |
|
s_toolbar *pToolbar = FindToolbar(iToolbar); |
|
if (!pToolbar) |
|
return; |
|
|
|
while (pToolbar) { |
|
if (pToolbar->hWnd == NULL || pToolbar->nextWindow == NULL) |
|
return; |
|
s_button *pButton = FindButton(pToolbar, iButton); |
|
if (!pButton) |
|
return; |
|
|
|
SendMessage(pToolbar->hWnd, TB_CHECKBUTTON, pButton->iID, MAKELONG(iState != 0, 0)); |
|
|
|
pToolbar = pToolbar->nextWindow; |
|
} |
|
} |
|
|
|
int IsButtonChecked(char *sParams) { |
|
|
|
// sParams = "ToolbarID, BUTTON_ID" |
|
|
|
// Get ToolbarID param |
|
char *p = SkipWhiteSpace(sParams); |
|
char *c = strchr(sParams, ','); |
|
if (!c) return NULL; |
|
*c = 0; // terminate string |
|
int iToolbar = atoi(p); |
|
if (!iToolbar) |
|
iToolbar = GetToolbarID(p); |
|
|
|
|
|
// Get BUTTON_ID param |
|
char* q = SkipWhiteSpace(c+1); |
|
int iButton = atoi(q); |
|
if (!iButton) |
|
iButton = kPlugin.kFuncs->GetID(q); |
|
|
|
if (!gbLegacy) { |
|
kmeleonButton b; |
|
kPlugin.kFuncs->GetButton(p, iButton, &b); |
|
*c = ','; // replace comma |
|
return b.checked; |
|
} |
|
*c = ','; // replace comma |
|
|
|
s_toolbar *pToolbar = FindToolbar(iToolbar); |
|
if (!pToolbar) |
|
return NULL; |
|
|
|
s_button *pButton = FindButton(pToolbar, iButton); |
|
if (!pButton) |
|
return NULL; |
|
|
|
while (pToolbar) { |
|
if (pToolbar->hwndWindow == GetActiveWindow()) |
|
return SendMessage(pToolbar->hWnd, TB_ISBUTTONCHECKED, pButton->iID, 0) != 0; |
|
pToolbar = pToolbar->nextWindow; |
|
} |
|
return NULL; |
|
} |
|
|
|
|
|
|
|
int ShowMenuUnderButton(HWND hWndParent, UINT uMouseButton, int iID, HWND hToolbar) { |
|
|
|
s_toolbar *pToolbar = toolbar_head; |
|
s_button *pButton; |
|
HMENU hMenu = NULL; |
|
|
|
// Find the window |
|
while (pToolbar) { |
|
if (pToolbar->hwndWindow == hWndParent) break; |
|
pToolbar = pToolbar->nextWindow; |
|
} |
|
if (!pToolbar) return 0; |
|
|
|
// Find the toolbar |
|
bool stop = false; |
|
if (hToolbar) { |
|
while (pToolbar) { |
|
if (pToolbar->hWnd == hToolbar) break; |
|
pToolbar = pToolbar->next; |
|
} |
|
if (!pToolbar) return 0; |
|
|
|
pButton = pToolbar->pButtonTail; |
|
while (pButton) { |
|
char* menu = (uMouseButton == TPM_LEFTBUTTON ? pButton->lmenu : pButton->menu); |
|
if (pButton->iID == iID) { |
|
if (menu) hMenu = kPlugin.kFuncs->GetMenu(menu); |
|
stop = true; |
|
break; |
|
} |
|
pButton = pButton->prev; |
|
} |
|
|
|
} else { |
|
while (pToolbar) { |
|
pButton = pToolbar->pButtonTail; |
|
while (pButton) { |
|
if (pButton->iID == iID && pButton->menu) { |
|
hMenu = kPlugin.kFuncs->GetMenu(pButton->menu); |
|
stop = true; |
|
break; |
|
} |
|
pButton = pButton->prev; |
|
} |
|
if (stop) break; |
|
pToolbar = pToolbar->next; |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
if (!pButton) { |
|
if (uMouseButton == TPM_RIGHTBUTTON) |
|
hMenu = kPlugin.kFuncs->GetMenu("Toolbars"); |
|
else if (uMouseButton == TPM_LEFTBUTTON) { |
|
POINT p; |
|
::GetCursorPos(&p); |
|
::SendMessage(hWndParent, WM_SYSCOMMAND, SC_MOVE+1, MAKELPARAM(p.x,p.y)); |
|
return 1; |
|
} |
|
else return 0; |
|
} |
|
|
|
// Show the menu if any |
|
if (hMenu) { |
|
|
|
RECT rc; |
|
int ButtonID = SendMessage(pToolbar->hWnd, TB_COMMANDTOINDEX, iID, 0); |
|
POINT pt; |
|
if (ButtonID >= 0) { |
|
SendMessage(pToolbar->hWnd, TB_GETITEMRECT, ButtonID, (LPARAM) &rc); |
|
pt.x = rc.left; |
|
pt.y = rc.bottom; |
|
ClientToScreen(pToolbar->hWnd, &pt); |
|
} |
|
else { |
|
GetCursorPos(&pt); |
|
} |
|
//if (pt.x<0) pt.x = 0; |
|
//if (pt.y<0) pt.y = 0; |
|
DWORD SelectionMade = TrackPopupMenu(hMenu, TPM_LEFTALIGN | uMouseButton | TPM_RETURNCMD, pt.x, pt.y, 0, hWndParent, &rc); |
|
|
|
if (SelectionMade > 0) { |
|
SendMessage(pToolbar->hWnd, TB_SETSTATE, (WPARAM) iID, (LPARAM) MAKELONG (TBSTATE_ENABLED , 0)); |
|
PostMessage(hWndParent, WM_COMMAND, (WPARAM) SelectionMade, 0); |
|
} |
|
|
|
return 1; |
|
} |
|
return 0; |
|
} |
|
|
|
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam){ |
|
|
|
static char* tip = NULL; |
|
static wchar_t* wtip = NULL; |
|
|
|
if (message == TB_LBUTTONDOWN) { |
|
int command = LOWORD(wParam); |
|
if (ShowMenuUnderButton(hWnd, TPM_LEFTBUTTON, command, (HWND)lParam)) |
|
return 0; |
|
} |
|
else if (message == TB_RBUTTONDOWN || message == TB_LBUTTONHOLD) { |
|
|
|
UINT button = (message == TB_RBUTTONDOWN) ? TPM_RIGHTBUTTON : TPM_LEFTBUTTON; |
|
if (ID_NAV_BACK == wParam) |
|
;//CreateHistoryBackMenu(hWnd, button); |
|
else if (ID_NAV_FORWARD == wParam) |
|
;//CreateHistoryForwardMenu(hWnd, button); |
|
else { |
|
int command = LOWORD(wParam); |
|
|
|
if (ShowMenuUnderButton(hWnd, button, command, (HWND)lParam)) |
|
return 0; |
|
} |
|
|
|
} |
|
|
|
else if (message == WM_NOTIFY){ |
|
|
|
LPNMHDR lpNmhdr = (LPNMHDR) lParam; |
|
if (lpNmhdr->code == TTN_NEEDTEXTA || lpNmhdr->code == TTN_NEEDTEXTW) { |
|
|
|
s_toolbar *toolbar = toolbar_head; |
|
s_button *button; |
|
|
|
while (toolbar) { |
|
if (toolbar->iButtonCount == 0) { |
|
toolbar = toolbar->next; |
|
continue; |
|
} |
|
|
|
button = toolbar->pButtonTail; |
|
while (button) { |
|
if (button->iID == (int) wParam) { |
|
if (lpNmhdr->code == TTN_NEEDTEXTA) |
|
{ |
|
LPTOOLTIPTEXTA lpTiptext = (LPTOOLTIPTEXTA) lParam; |
|
#ifdef _UNICODE |
|
if (button->sToolTip) { |
|
if (tip) free(tip); |
|
tip = ansi_from_utf8(_Tr(button->sToolTip)); |
|
lpTiptext->lpszText = tip; |
|
} |
|
#else |
|
lpTiptext->lpszText = button->sToolTip; |
|
#endif |
|
} |
|
else |
|
{ |
|
LPTOOLTIPTEXTW lpTiptext = (LPTOOLTIPTEXTW) lParam; |
|
#ifdef _UNICODE |
|
if (wtip) free(wtip); |
|
lpTiptext->lpszText = wtip = utf16_from_utf8(_Tr(button->sToolTip)); |
|
#else |
|
if (button->sToolTip) { |
|
if (tip) free(tip); |
|
const TCHAR* lpText = kPlugin.kFuncs->Translate(button->sToolTip); |
|
unsigned lengthDst = strlen(lpText) + 1; |
|
tip = (WCHAR*)malloc(sizeof(WCHAR) * lengthDst); |
|
MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, lpText, -1, tip, lengthDst); |
|
lpTiptext->lpszText = tip; |
|
} |
|
#endif |
|
} |
|
return 0; |
|
} |
|
button = button->prev; |
|
} |
|
toolbar = toolbar->next; |
|
} |
|
|
|
} |
|
} |
|
else if (message == WM_CLOSE){ |
|
if (tip) { |
|
free(tip); |
|
tip = NULL; |
|
} |
|
} |
|
|
|
return CallWindowProc(KMeleonWndProc, hWnd, message, wParam, lParam); |
|
} |
|
|
|
|
|
|
|
// function mutilation protection |
|
extern "C" { |
|
|
|
KMELEON_PLUGIN kmeleonPlugin *GetKmeleonPlugin() { |
|
return &kPlugin; |
|
} |
|
|
|
}
|
|
|