From 9242a80a84fa5c96dbadec9594177875aeeec1ac Mon Sep 17 00:00:00 2001 From: Kirill Volinsky Date: Tue, 10 Jul 2012 18:37:21 +0000 Subject: only added MyDetails and Skins. not adopted yet git-svn-id: http://svn.miranda-ng.org/main/trunk@892 1316c22d-e87f-b044-9b9b-93d7a3e3ba9c --- plugins/ExternalAPI/m_skins.h | 142 + plugins/ExternalAPI/m_skins_cpp.h | 210 ++ plugins/MyDetails/Docs/Skins/Default/MyDetails.msk | 399 +++ plugins/MyDetails/Docs/Skins/Pidgin/MyDetails.msk | 59 + plugins/MyDetails/Docs/langpack_MyDetails.txt | 85 + plugins/MyDetails/Docs/mydetails.gif | Bin 0 -> 80764 bytes plugins/MyDetails/Docs/mydetails_changelog.txt | 228 ++ plugins/MyDetails/Docs/mydetails_readme.txt | 41 + plugins/MyDetails/Docs/mydetails_version.txt | 1 + plugins/MyDetails/commons.h | 148 + plugins/MyDetails/data.cpp | 1063 ++++++ plugins/MyDetails/data.h | 183 + plugins/MyDetails/frame.cpp | 2428 +++++++++++++ plugins/MyDetails/frame.h | 38 + plugins/MyDetails/mydetails.cpp | 992 ++++++ plugins/MyDetails/mydetails.h | 42 + plugins/MyDetails/mydetails.vcproj | 642 ++++ plugins/MyDetails/options.cpp | 189 + plugins/MyDetails/options.h | 83 + plugins/MyDetails/res/leftarrow.ico | Bin 0 -> 2550 bytes plugins/MyDetails/res/listening_to.ico | Bin 0 -> 2038 bytes plugins/MyDetails/res/mail.ico | Bin 0 -> 2550 bytes plugins/MyDetails/res/rightarrow.ico | Bin 0 -> 2550 bytes plugins/MyDetails/resource.h | 72 + plugins/MyDetails/resource.rc | 326 ++ plugins/Skins/Docs/langpack_skins.txt | 2 + plugins/Skins/Docs/skins_changelog.txt | 25 + plugins/Skins/Docs/skins_readme.txt | 31 + plugins/Skins/Docs/skins_version.txt | 1 + plugins/Skins/MirandaField.h | 14 + plugins/Skins/MirandaFont.cpp | 87 + plugins/Skins/MirandaFont.h | 28 + plugins/Skins/MirandaIconField.cpp | 19 + plugins/Skins/MirandaIconField.h | 21 + plugins/Skins/MirandaImageField.cpp | 19 + plugins/Skins/MirandaImageField.h | 21 + plugins/Skins/MirandaSkinnedDialog.cpp | 252 ++ plugins/Skins/MirandaSkinnedDialog.h | 64 + plugins/Skins/MirandaTextField.cpp | 27 + plugins/Skins/MirandaTextField.h | 27 + plugins/Skins/SkinLib/BorderState.cpp | 61 + plugins/Skins/SkinLib/BorderState.h | 28 + plugins/Skins/SkinLib/BorderState_v8_wrapper.cpp | 160 + plugins/Skins/SkinLib/BorderState_v8_wrapper.h | 10 + plugins/Skins/SkinLib/ButtonField.cpp | 22 + plugins/Skins/SkinLib/ButtonField.h | 19 + plugins/Skins/SkinLib/ButtonFieldState.cpp | 30 + plugins/Skins/SkinLib/ButtonFieldState.h | 23 + .../Skins/SkinLib/ButtonFieldState_v8_wrapper.cpp | 20 + .../Skins/SkinLib/ButtonFieldState_v8_wrapper.h | 10 + plugins/Skins/SkinLib/ControlField.cpp | 123 + plugins/Skins/SkinLib/ControlField.h | 37 + plugins/Skins/SkinLib/ControlFieldState.cpp | 86 + plugins/Skins/SkinLib/ControlFieldState.h | 39 + .../Skins/SkinLib/ControlFieldState_v8_wrapper.cpp | 59 + .../Skins/SkinLib/ControlFieldState_v8_wrapper.h | 10 + plugins/Skins/SkinLib/Dialog.cpp | 100 + plugins/Skins/SkinLib/Dialog.h | 41 + plugins/Skins/SkinLib/DialogInfo.cpp | 190 + plugins/Skins/SkinLib/DialogInfo.h | 50 + plugins/Skins/SkinLib/DialogState.cpp | 132 + plugins/Skins/SkinLib/DialogState.h | 59 + plugins/Skins/SkinLib/DialogState_v8_wrapper.cpp | 233 ++ plugins/Skins/SkinLib/DialogState_v8_wrapper.h | 10 + plugins/Skins/SkinLib/EditField.cpp | 23 + plugins/Skins/SkinLib/EditField.h | 19 + plugins/Skins/SkinLib/EditFieldState.cpp | 58 + plugins/Skins/SkinLib/EditFieldState.h | 24 + .../Skins/SkinLib/EditFieldState_v8_wrapper.cpp | 20 + plugins/Skins/SkinLib/EditFieldState_v8_wrapper.h | 10 + plugins/Skins/SkinLib/Field.cpp | 56 + plugins/Skins/SkinLib/Field.h | 66 + plugins/Skins/SkinLib/FieldState.cpp | 303 ++ plugins/Skins/SkinLib/FieldState.h | 108 + plugins/Skins/SkinLib/FieldState.rec | 89 + plugins/Skins/SkinLib/FieldState_v8_wrapper.cpp | 539 +++ plugins/Skins/SkinLib/FieldState_v8_wrapper.h | 10 + plugins/Skins/SkinLib/FontState.cpp | 186 + plugins/Skins/SkinLib/FontState.h | 57 + plugins/Skins/SkinLib/FontState_v8_wrapper.cpp | 269 ++ plugins/Skins/SkinLib/FontState_v8_wrapper.h | 10 + plugins/Skins/SkinLib/IconField.cpp | 38 + plugins/Skins/SkinLib/IconField.h | 27 + plugins/Skins/SkinLib/IconFieldState.cpp | 37 + plugins/Skins/SkinLib/IconFieldState.h | 28 + .../Skins/SkinLib/IconFieldState_v8_wrapper.cpp | 20 + plugins/Skins/SkinLib/IconFieldState_v8_wrapper.h | 10 + plugins/Skins/SkinLib/ImageField.cpp | 38 + plugins/Skins/SkinLib/ImageField.h | 26 + plugins/Skins/SkinLib/ImageFieldState.cpp | 37 + plugins/Skins/SkinLib/ImageFieldState.h | 28 + .../Skins/SkinLib/ImageFieldState_v8_wrapper.cpp | 20 + plugins/Skins/SkinLib/ImageFieldState_v8_wrapper.h | 10 + plugins/Skins/SkinLib/LabelField.cpp | 23 + plugins/Skins/SkinLib/LabelField.h | 20 + plugins/Skins/SkinLib/LabelFieldState.cpp | 35 + plugins/Skins/SkinLib/LabelFieldState.h | 25 + .../Skins/SkinLib/LabelFieldState_v8_wrapper.cpp | 20 + plugins/Skins/SkinLib/LabelFieldState_v8_wrapper.h | 10 + plugins/Skins/SkinLib/Position.cpp | 9 + plugins/Skins/SkinLib/Position.h | 16 + plugins/Skins/SkinLib/Size.cpp | 84 + plugins/Skins/SkinLib/Size.h | 27 + plugins/Skins/SkinLib/SkinOption.h | 1 + plugins/Skins/SkinLib/SkinOption_v8_wrapper.cpp | 179 + plugins/Skins/SkinLib/SkinOption_v8_wrapper.h | 10 + plugins/Skins/SkinLib/SkinOptions.cpp | 216 ++ plugins/Skins/SkinLib/SkinOptions.h | 98 + plugins/Skins/SkinLib/SkinnedDialog.cpp | 235 ++ plugins/Skins/SkinLib/SkinnedDialog.h | 89 + plugins/Skins/SkinLib/TextField.cpp | 78 + plugins/Skins/SkinLib/TextField.h | 35 + plugins/Skins/SkinLib/TextFieldState.cpp | 65 + plugins/Skins/SkinLib/TextFieldState.h | 38 + .../Skins/SkinLib/TextFieldState_v8_wrapper.cpp | 59 + plugins/Skins/SkinLib/TextFieldState_v8_wrapper.h | 10 + plugins/Skins/SkinLib/V8Script.cpp | 236 ++ plugins/Skins/SkinLib/V8Script.h | 46 + plugins/Skins/SkinLib/V8Templates.cpp | 475 +++ plugins/Skins/SkinLib/V8Templates.h | 114 + plugins/Skins/SkinLib/V8Wrappers.cpp | 385 ++ plugins/Skins/SkinLib/V8Wrappers.h | 35 + plugins/Skins/SkinLib/globals.h | 20 + plugins/Skins/SkinLib/scope.h | 37 + plugins/Skins/SkinLib/tstring.h | 13 + plugins/Skins/commons.h | 119 + plugins/Skins/libs/v8-debug.h | 384 ++ plugins/Skins/libs/v8.h | 3686 ++++++++++++++++++++ plugins/Skins/libs/v8.lib | Bin 0 -> 34627500 bytes plugins/Skins/libs/v8_g.lib | Bin 0 -> 40003716 bytes plugins/Skins/options.cpp | 487 +++ plugins/Skins/options.h | 47 + plugins/Skins/resource.h | 22 + plugins/Skins/resource.rc | 111 + plugins/Skins/skins.cpp | 968 +++++ plugins/Skins/skins.vcproj | 1066 ++++++ 136 files changed, 21360 insertions(+) create mode 100644 plugins/ExternalAPI/m_skins.h create mode 100644 plugins/ExternalAPI/m_skins_cpp.h create mode 100644 plugins/MyDetails/Docs/Skins/Default/MyDetails.msk create mode 100644 plugins/MyDetails/Docs/Skins/Pidgin/MyDetails.msk create mode 100644 plugins/MyDetails/Docs/langpack_MyDetails.txt create mode 100644 plugins/MyDetails/Docs/mydetails.gif create mode 100644 plugins/MyDetails/Docs/mydetails_changelog.txt create mode 100644 plugins/MyDetails/Docs/mydetails_readme.txt create mode 100644 plugins/MyDetails/Docs/mydetails_version.txt create mode 100644 plugins/MyDetails/commons.h create mode 100644 plugins/MyDetails/data.cpp create mode 100644 plugins/MyDetails/data.h create mode 100644 plugins/MyDetails/frame.cpp create mode 100644 plugins/MyDetails/frame.h create mode 100644 plugins/MyDetails/mydetails.cpp create mode 100644 plugins/MyDetails/mydetails.h create mode 100644 plugins/MyDetails/mydetails.vcproj create mode 100644 plugins/MyDetails/options.cpp create mode 100644 plugins/MyDetails/options.h create mode 100644 plugins/MyDetails/res/leftarrow.ico create mode 100644 plugins/MyDetails/res/listening_to.ico create mode 100644 plugins/MyDetails/res/mail.ico create mode 100644 plugins/MyDetails/res/rightarrow.ico create mode 100644 plugins/MyDetails/resource.h create mode 100644 plugins/MyDetails/resource.rc create mode 100644 plugins/Skins/Docs/langpack_skins.txt create mode 100644 plugins/Skins/Docs/skins_changelog.txt create mode 100644 plugins/Skins/Docs/skins_readme.txt create mode 100644 plugins/Skins/Docs/skins_version.txt create mode 100644 plugins/Skins/MirandaField.h create mode 100644 plugins/Skins/MirandaFont.cpp create mode 100644 plugins/Skins/MirandaFont.h create mode 100644 plugins/Skins/MirandaIconField.cpp create mode 100644 plugins/Skins/MirandaIconField.h create mode 100644 plugins/Skins/MirandaImageField.cpp create mode 100644 plugins/Skins/MirandaImageField.h create mode 100644 plugins/Skins/MirandaSkinnedDialog.cpp create mode 100644 plugins/Skins/MirandaSkinnedDialog.h create mode 100644 plugins/Skins/MirandaTextField.cpp create mode 100644 plugins/Skins/MirandaTextField.h create mode 100644 plugins/Skins/SkinLib/BorderState.cpp create mode 100644 plugins/Skins/SkinLib/BorderState.h create mode 100644 plugins/Skins/SkinLib/BorderState_v8_wrapper.cpp create mode 100644 plugins/Skins/SkinLib/BorderState_v8_wrapper.h create mode 100644 plugins/Skins/SkinLib/ButtonField.cpp create mode 100644 plugins/Skins/SkinLib/ButtonField.h create mode 100644 plugins/Skins/SkinLib/ButtonFieldState.cpp create mode 100644 plugins/Skins/SkinLib/ButtonFieldState.h create mode 100644 plugins/Skins/SkinLib/ButtonFieldState_v8_wrapper.cpp create mode 100644 plugins/Skins/SkinLib/ButtonFieldState_v8_wrapper.h create mode 100644 plugins/Skins/SkinLib/ControlField.cpp create mode 100644 plugins/Skins/SkinLib/ControlField.h create mode 100644 plugins/Skins/SkinLib/ControlFieldState.cpp create mode 100644 plugins/Skins/SkinLib/ControlFieldState.h create mode 100644 plugins/Skins/SkinLib/ControlFieldState_v8_wrapper.cpp create mode 100644 plugins/Skins/SkinLib/ControlFieldState_v8_wrapper.h create mode 100644 plugins/Skins/SkinLib/Dialog.cpp create mode 100644 plugins/Skins/SkinLib/Dialog.h create mode 100644 plugins/Skins/SkinLib/DialogInfo.cpp create mode 100644 plugins/Skins/SkinLib/DialogInfo.h create mode 100644 plugins/Skins/SkinLib/DialogState.cpp create mode 100644 plugins/Skins/SkinLib/DialogState.h create mode 100644 plugins/Skins/SkinLib/DialogState_v8_wrapper.cpp create mode 100644 plugins/Skins/SkinLib/DialogState_v8_wrapper.h create mode 100644 plugins/Skins/SkinLib/EditField.cpp create mode 100644 plugins/Skins/SkinLib/EditField.h create mode 100644 plugins/Skins/SkinLib/EditFieldState.cpp create mode 100644 plugins/Skins/SkinLib/EditFieldState.h create mode 100644 plugins/Skins/SkinLib/EditFieldState_v8_wrapper.cpp create mode 100644 plugins/Skins/SkinLib/EditFieldState_v8_wrapper.h create mode 100644 plugins/Skins/SkinLib/Field.cpp create mode 100644 plugins/Skins/SkinLib/Field.h create mode 100644 plugins/Skins/SkinLib/FieldState.cpp create mode 100644 plugins/Skins/SkinLib/FieldState.h create mode 100644 plugins/Skins/SkinLib/FieldState.rec create mode 100644 plugins/Skins/SkinLib/FieldState_v8_wrapper.cpp create mode 100644 plugins/Skins/SkinLib/FieldState_v8_wrapper.h create mode 100644 plugins/Skins/SkinLib/FontState.cpp create mode 100644 plugins/Skins/SkinLib/FontState.h create mode 100644 plugins/Skins/SkinLib/FontState_v8_wrapper.cpp create mode 100644 plugins/Skins/SkinLib/FontState_v8_wrapper.h create mode 100644 plugins/Skins/SkinLib/IconField.cpp create mode 100644 plugins/Skins/SkinLib/IconField.h create mode 100644 plugins/Skins/SkinLib/IconFieldState.cpp create mode 100644 plugins/Skins/SkinLib/IconFieldState.h create mode 100644 plugins/Skins/SkinLib/IconFieldState_v8_wrapper.cpp create mode 100644 plugins/Skins/SkinLib/IconFieldState_v8_wrapper.h create mode 100644 plugins/Skins/SkinLib/ImageField.cpp create mode 100644 plugins/Skins/SkinLib/ImageField.h create mode 100644 plugins/Skins/SkinLib/ImageFieldState.cpp create mode 100644 plugins/Skins/SkinLib/ImageFieldState.h create mode 100644 plugins/Skins/SkinLib/ImageFieldState_v8_wrapper.cpp create mode 100644 plugins/Skins/SkinLib/ImageFieldState_v8_wrapper.h create mode 100644 plugins/Skins/SkinLib/LabelField.cpp create mode 100644 plugins/Skins/SkinLib/LabelField.h create mode 100644 plugins/Skins/SkinLib/LabelFieldState.cpp create mode 100644 plugins/Skins/SkinLib/LabelFieldState.h create mode 100644 plugins/Skins/SkinLib/LabelFieldState_v8_wrapper.cpp create mode 100644 plugins/Skins/SkinLib/LabelFieldState_v8_wrapper.h create mode 100644 plugins/Skins/SkinLib/Position.cpp create mode 100644 plugins/Skins/SkinLib/Position.h create mode 100644 plugins/Skins/SkinLib/Size.cpp create mode 100644 plugins/Skins/SkinLib/Size.h create mode 100644 plugins/Skins/SkinLib/SkinOption.h create mode 100644 plugins/Skins/SkinLib/SkinOption_v8_wrapper.cpp create mode 100644 plugins/Skins/SkinLib/SkinOption_v8_wrapper.h create mode 100644 plugins/Skins/SkinLib/SkinOptions.cpp create mode 100644 plugins/Skins/SkinLib/SkinOptions.h create mode 100644 plugins/Skins/SkinLib/SkinnedDialog.cpp create mode 100644 plugins/Skins/SkinLib/SkinnedDialog.h create mode 100644 plugins/Skins/SkinLib/TextField.cpp create mode 100644 plugins/Skins/SkinLib/TextField.h create mode 100644 plugins/Skins/SkinLib/TextFieldState.cpp create mode 100644 plugins/Skins/SkinLib/TextFieldState.h create mode 100644 plugins/Skins/SkinLib/TextFieldState_v8_wrapper.cpp create mode 100644 plugins/Skins/SkinLib/TextFieldState_v8_wrapper.h create mode 100644 plugins/Skins/SkinLib/V8Script.cpp create mode 100644 plugins/Skins/SkinLib/V8Script.h create mode 100644 plugins/Skins/SkinLib/V8Templates.cpp create mode 100644 plugins/Skins/SkinLib/V8Templates.h create mode 100644 plugins/Skins/SkinLib/V8Wrappers.cpp create mode 100644 plugins/Skins/SkinLib/V8Wrappers.h create mode 100644 plugins/Skins/SkinLib/globals.h create mode 100644 plugins/Skins/SkinLib/scope.h create mode 100644 plugins/Skins/SkinLib/tstring.h create mode 100644 plugins/Skins/commons.h create mode 100644 plugins/Skins/libs/v8-debug.h create mode 100644 plugins/Skins/libs/v8.h create mode 100644 plugins/Skins/libs/v8.lib create mode 100644 plugins/Skins/libs/v8_g.lib create mode 100644 plugins/Skins/options.cpp create mode 100644 plugins/Skins/options.h create mode 100644 plugins/Skins/resource.h create mode 100644 plugins/Skins/resource.rc create mode 100644 plugins/Skins/skins.cpp create mode 100644 plugins/Skins/skins.vcproj diff --git a/plugins/ExternalAPI/m_skins.h b/plugins/ExternalAPI/m_skins.h new file mode 100644 index 0000000000..da01064c64 --- /dev/null +++ b/plugins/ExternalAPI/m_skins.h @@ -0,0 +1,142 @@ +/* +Copyright (C) 2008 Ricardo Pescuma Domenecci + +This is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public +License as published by the Free Software Foundation; either +version 2 of the License, or (at your option) any later version. + +This 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 +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with this file; see the file license.txt. If +not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. +*/ + + +#ifndef __M_SKINS_H__ +# define __M_SKINS_H__ + +#include + +#define MIID_SKINS { 0x917db7a4, 0xd0fe, 0x4b1c, { 0x8c, 0xa3, 0x6d, 0xc1, 0x44, 0x80, 0xf5, 0xcc } } + + +typedef void * SKINNED_DIALOG; +typedef void * SKINNED_FIELD; +typedef void * SKINNED_DIALOG_STATE; +typedef void * SKINNED_FIELD_STATE; + +typedef void (*SkinOptionsChangedCallback)(void *param, SKINNED_DIALOG dlg); + + +#define SKN_HALIGN_LEFT 1 +#define SKN_HALIGN_CENTER 2 +#define SKN_HALIGN_RIGHT 3 + +#define SKN_VALIGN_TOP 1 +#define SKN_VALIGN_CENTER 2 +#define SKN_VALIGN_BOTTOM 3 + + +/// Some common parameters: +/// - name : internal name and name used inside skin file +/// - description : name shown to the user +/// - module : the module name where the settings will be stored +/// Do not translate any parameters. +struct SKIN_INTERFACE +{ + int cbSize; + + // Global methods + SKINNED_DIALOG (*RegisterDialog)(const char *name, const char *description, const char *module); + void (*DeleteDialog)(SKINNED_DIALOG dlg); + void (*SetSkinChangedCallback)(SKINNED_DIALOG dlg, SkinOptionsChangedCallback cb, void *param); + void (*FinishedConfiguring)(SKINNED_DIALOG dlg); + + // Dialog methods + SKINNED_FIELD (*AddTextField)(SKINNED_DIALOG dlg, const char *name, const char *description); + SKINNED_FIELD (*AddIconField)(SKINNED_DIALOG dlg, const char *name, const char *description); + SKINNED_FIELD (*AddImageField)(SKINNED_DIALOG dlg, const char *name, const char *description); + SKINNED_FIELD (*GetField)(SKINNED_DIALOG dlg, const char *name); + void (*SetDialogSize)(SKINNED_DIALOG dlg, int width, int height); + void (*SetInfoInt)(SKINNED_DIALOG dlg, const char *name, int value); + void (*SetInfoDouble)(SKINNED_DIALOG dlg, const char *name, double value); + void (*SetInfoBool)(SKINNED_DIALOG dlg, const char *name, BOOL value); + void (*SetInfoString)(SKINNED_DIALOG dlg, const char *name, const TCHAR *value); + void (*RemoveInfo)(SKINNED_DIALOG dlg, const char *name); + + // Field methods + void (*SetEnabled)(SKINNED_FIELD field, BOOL enabled); + void (*SetToolTipA)(SKINNED_FIELD field, const char *tooltip); + void (*SetToolTipW)(SKINNED_FIELD field, const WCHAR *tooltip); + + // TextField methods + void (*SetTextA)(SKINNED_FIELD field, const char *text); + void (*SetTextW)(SKINNED_FIELD field, const WCHAR *text); + + // IconField methods + void (*SetIcon)(SKINNED_FIELD field, HICON hIcon); + + // ImageField methods + void (*SetImage)(SKINNED_FIELD field, HBITMAP hBmp); + + // Run the skin and get an state from it + SKINNED_DIALOG_STATE (*Run)(SKINNED_DIALOG dialog); + + // Dialog State methods + SKINNED_FIELD_STATE (*GetFieldState)(SKINNED_DIALOG_STATE dlg, const char *name); + RECT (*GetDialogBorders)(SKINNED_DIALOG_STATE dlg); + + // Field State methods + RECT (*GetRect)(SKINNED_FIELD_STATE field); // With borders + RECT (*GetInsideRect)(SKINNED_FIELD_STATE field); // Without borders + RECT (*GetRawRect)(SKINNED_FIELD_STATE field); // With borders, without processing to assert inside window + RECT (*GetRawInsideRect)(SKINNED_FIELD_STATE field); // Without borders, without processing to assert inside window + RECT (*GetBorders)(SKINNED_FIELD_STATE field); + BOOL (*IsVisible)(SKINNED_FIELD_STATE field); + char * (*GetToolTipA)(SKINNED_FIELD field); // You have to free the result + WCHAR * (*GetToolTipW)(SKINNED_FIELD field); // You have to free the result + int (*GetHorizontalAlign)(SKINNED_FIELD_STATE field); // one of SKN_HALIGN_* + int (*GetVerticalAlign)(SKINNED_FIELD_STATE field); // one of SKN_VALIGN_* + + // TextField State methods + char * (*GetTextA)(SKINNED_FIELD_STATE field); // You have to free the result + WCHAR * (*GetTextW)(SKINNED_FIELD_STATE field); // You have to free the result + HFONT (*GetFont)(SKINNED_FIELD_STATE field); + COLORREF (*GetFontColor)(SKINNED_FIELD_STATE field); + + // IconField State methods + HICON (*GetIcon)(SKINNED_FIELD_STATE field); + + // ImageField State methods + HBITMAP (*GetImage)(SKINNED_FIELD_STATE field); +}; + + + +/* +Skins/GetInterface service +Fill the function pointers for a SKIN_INTERFACE struct + +wparam = 0 +lparam = (SKIN_INTERFACE *) struct to be filled +returns: 0 on success +*/ +#define MS_SKINS_GETINTERFACE "Skins/GetInterface" + + + + +static int mir_skins_getInterface(struct SKIN_INTERFACE *dest) +{ + dest->cbSize = sizeof(SKIN_INTERFACE); + return CallService(MS_SKINS_GETINTERFACE, 0, (LPARAM) dest); +} + + +#endif // __M_SKINS_H__ diff --git a/plugins/ExternalAPI/m_skins_cpp.h b/plugins/ExternalAPI/m_skins_cpp.h new file mode 100644 index 0000000000..bdc7337419 --- /dev/null +++ b/plugins/ExternalAPI/m_skins_cpp.h @@ -0,0 +1,210 @@ +/* +Copyright (C) 2008 Ricardo Pescuma Domenecci + +This is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public +License as published by the Free Software Foundation; either +version 2 of the License, or (at your option) any later version. + +This 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 +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with this file; see the file license.txt. If +not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. +*/ + + +#ifndef __M_SKINS_CPP_H__ +# define __M_SKINS_CPP_H__ + +#include "m_skins.h" + +extern struct SKIN_INTERFACE mski; + + +class SkinFieldState +{ +public: + SkinFieldState(SKINNED_FIELD_STATE field) : tooltip(NULL) { this->field = field; } + virtual ~SkinFieldState() { if (tooltip != NULL) mir_free(tooltip); } + + bool isValid() { return field != NULL; } + + RECT getRect(bool raw = false) { return raw ? mski.GetRawRect(field) : mski.GetRect(field); } + RECT getInsideRect(bool raw = false) { return raw ? mski.GetRawInsideRect(field) : mski.GetInsideRect(field); } + RECT getBorders() { return mski.GetBorders(field); } + bool isVisible() { return mski.IsVisible(field) != FALSE; } + int getHorizontalAlign() { return mski.GetHorizontalAlign(field); } // one of SKN_HALIGN_* + int getVerticalAlign() { return mski.GetVerticalAlign(field); } // one of SKN_VALIGN_* + + const TCHAR * getToolTip() { + if (tooltip != NULL) + mir_free(tooltip); + +#ifdef UNICODE + tooltip = mski.GetToolTipW(field); +#else + tooltip = mski.GetToolTipA(field); +#endif + return tooltip; + } + +protected: + SKINNED_FIELD_STATE field; + TCHAR *tooltip; +}; + +class SkinTextFieldState : public SkinFieldState +{ +public: + SkinTextFieldState(SKINNED_FIELD_STATE field) : SkinFieldState(field), text(NULL) {} + virtual ~SkinTextFieldState() { if (text != NULL) mir_free(text); } + + const TCHAR * getText() { + if (text != NULL) + mir_free(text); + +#ifdef UNICODE + text = mski.GetTextW(field); +#else + text = mski.GetTextA(field); +#endif + return text; + } + + HFONT getFont() { return mski.GetFont(field); } + COLORREF getFontColor() { return mski.GetFontColor(field); } + +private: + TCHAR *text; +}; + +class SkinIconFieldState : public SkinFieldState +{ +public: + SkinIconFieldState(SKINNED_FIELD_STATE field) : SkinFieldState(field) {} + + HICON getIcon() { return mski.GetIcon(field); } +}; + +class SkinImageFieldState : public SkinFieldState +{ +public: + SkinImageFieldState(SKINNED_FIELD_STATE field) : SkinFieldState(field) {} + + HBITMAP getImage() { return mski.GetImage(field); } +}; + + +class SkinDialogState +{ +public: + SkinDialogState(SKINNED_DIALOG_STATE dlg) { this->dlg = dlg; } + + bool isValid() { return dlg != NULL; } + + RECT getBorders() { return mski.GetDialogBorders(dlg); } + + SkinFieldState getField(const char *name) { return SkinFieldState( mski.GetFieldState(dlg, name) ); } + SkinTextFieldState getTextField(const char *name) { return SkinTextFieldState( mski.GetFieldState(dlg, name) ); } + SkinIconFieldState getIconField(const char *name) { return SkinIconFieldState( mski.GetFieldState(dlg, name) ); } + SkinImageFieldState getImageField(const char *name) { return SkinImageFieldState( mski.GetFieldState(dlg, name) ); } + +private: + SKINNED_DIALOG_STATE dlg; +}; + + +class SkinField +{ +public: + SkinField(SKINNED_FIELD field) { this->field = field; } + + bool isValid() { return field != NULL; } + + void setEnabled(bool enabled) { mski.SetEnabled(field, enabled); } + + void setToolTip(const TCHAR *tooltip) { +#ifdef UNICODE + mski.SetToolTipW(field, tooltip); +#else + mski.SetToolTipA(field, tooltip); +#endif + } + +protected: + SKINNED_FIELD field; +}; + +class SkinTextField : public SkinField +{ +public: + SkinTextField(SKINNED_FIELD field) : SkinField(field) {} + + void setText(const TCHAR *text) { +#ifdef UNICODE + mski.SetTextW(field, text); +#else + mski.SetTextA(field, text); +#endif + } +}; + +class SkinIconField : public SkinField +{ +public: + SkinIconField(SKINNED_FIELD field) : SkinField(field) {} + + void setIcon(HICON hIcon) { mski.SetIcon(field, hIcon); } +}; + +class SkinImageField : public SkinField +{ +public: + SkinImageField(SKINNED_FIELD field) : SkinField(field) {} + + void setImage(HBITMAP hBmp) { mski.SetImage(field, hBmp); } +}; + + +class SkinDialog +{ +public: + SkinDialog(const char *name, const char *description, const char *module) { dlg = mski.RegisterDialog(name, description, module); } + ~SkinDialog() { mski.DeleteDialog(dlg); dlg = NULL; } + + bool isValid() { return dlg != NULL; } + + void setSkinChangedCallback(SkinOptionsChangedCallback cb, void *param) { mski.SetSkinChangedCallback(dlg, cb, param); } + + void finishedConfiguring() { mski.FinishedConfiguring(dlg); } + + void setSize(int width, int height) { mski.SetDialogSize(dlg, width, height); } + + SkinTextField addTextField(const char *name, const char *description) { return SkinTextField( mski.AddTextField(dlg, name, description) ); } + SkinIconField addIconField(const char *name, const char *description) { return SkinIconField( mski.AddIconField(dlg, name, description) ); } + SkinImageField addImageField(const char *name, const char *description) { return SkinImageField( mski.AddImageField(dlg, name, description) ); } + + SkinField getField(const char *name) { return SkinField( mski.GetField(dlg, name) ); } + SkinTextField getTextField(const char *name) { return SkinTextField( mski.GetField(dlg, name) ); } + SkinIconField getIconField(const char *name) { return SkinIconField( mski.GetField(dlg, name) ); } + SkinImageField getImageField(const char *name) { return SkinImageField( mski.GetField(dlg, name) ); } + + void setInfoInt(const char *name, int value) { mski.SetInfoInt(dlg, name, value); } + void setInfoDouble(const char *name, double value) { mski.SetInfoDouble(dlg, name, value); } + void setInfoBool(const char *name, bool value) { mski.SetInfoBool(dlg, name, value); } + void setInfoString(const char *name, const TCHAR *value) { mski.SetInfoString(dlg, name, value); } + void removeInfo(const char *name) { mski.RemoveInfo(dlg, name); } + + SkinDialogState run() { return SkinDialogState( mski.Run(dlg) ); } + +private: + SKINNED_DIALOG dlg; +}; + + +#endif // __M_SKINS_CPP_H__ \ No newline at end of file diff --git a/plugins/MyDetails/Docs/Skins/Default/MyDetails.msk b/plugins/MyDetails/Docs/Skins/Default/MyDetails.msk new file mode 100644 index 0000000000..93c46b457a --- /dev/null +++ b/plugins/MyDetails/Docs/Skins/Default/MyDetails.msk @@ -0,0 +1,399 @@ +function configure() +{ + // Options for this skin + + opts.align_right.description = "Align to right" + opts.align_right.type = CHECKBOX + opts.align_right.value = false + + opts.show_avatar.description = "Show avatar" + opts.show_avatar.type = CHECKBOX + opts.show_avatar.value = true + + opts.avatar_allow_grow.description = "Allow avatar to grow (be bigger than original image)" + opts.avatar_allow_grow.type = CHECKBOX + opts.avatar_allow_grow.value = false + + opts.avatar_use_fixed_size.description = "Use fixed size avatar" + opts.avatar_use_fixed_size.type = CHECKBOX + opts.avatar_use_fixed_size.value = false + + opts.avatar_fixed_size.description = "Avatar fixed size (pixels)" + opts.avatar_fixed_size.type = NUMBER + opts.avatar_fixed_size.value = 30 + opts.avatar_fixed_size.min = 1 + opts.avatar_fixed_size.max = 255 + + opts.show_protocol.description = "Show protocol" + opts.show_protocol.type = CHECKBOX + opts.show_protocol.value = true + + opts.show_email.description = "Show unread mail count" + opts.show_email.type = CHECKBOX + opts.show_email.value = true + + opts.show_status.description = "Show status" + opts.show_status.type = CHECKBOX + opts.show_status.value = true + + opts.show_status_msg.description = "Show status message" + opts.show_status_msg.type = CHECKBOX + opts.show_status_msg.value = true + + opts.show_listening.description = "Show listening to" + opts.show_listening.type = CHECKBOX + opts.show_listening.value = true + + opts.show_protocol_cycle.description = "Show protocol cycle buttons" + opts.show_protocol_cycle.type = CHECKBOX + opts.show_protocol_cycle.value = false + + opts.use_under_avatar.description = "Use free space (under avatar) to other texts" + opts.use_under_avatar.type = CHECKBOX + opts.use_under_avatar.value = true + + opts.border_left.description = "Left border" + opts.border_left.type = NUMBER + opts.border_left.value = 8 + opts.border_left.min = 0 + opts.border_left.max = 100 + + opts.border_top.description = "Top border" + opts.border_top.type = NUMBER + opts.border_top.value = 8 + opts.border_top.min = 0 + opts.border_top.max = 100 + + opts.border_right.description = "Right border" + opts.border_right.type = NUMBER + opts.border_right.value = 8 + opts.border_right.min = 0 + opts.border_right.max = 100 + + opts.border_bottom.description = "Bottom border" + opts.border_bottom.type = NUMBER + opts.border_bottom.value = 8 + opts.border_bottom.min = 0 + opts.border_bottom.max = 100 + + // Default fonts + + nickname.font.face = "Tahoma" + nickname.font.size = 13 + nickname.font.bold = true + nickname.font.color = RGB(0,0,0) + + protocol.font.face = "Tahoma" + protocol.font.size = 8 + protocol.font.color = RGB(0,0,0) + + email.font.face = "Tahoma" + email.font.size = 8 + email.font.color = RGB(0,0,0) + + status_name.font.face = "Tahoma" + status_name.font.size = 8 + status_name.font.color = RGB(0,0,0) + + status_msg.font.face = "Tahoma" + status_msg.font.size = 8 + status_msg.font.italic = true + status_msg.font.color = RGB(150,150,150) + + listening.font.face = "Tahoma" + listening.font.size = 8 + listening.font.italic = true + listening.font.color = RGB(150,150,150) +} + +function valign_center(top) +{ + var height = 0 + for(var i = 1; i < arguments.length; i++) + height = Math.max(height, arguments[i].height) + for(var i = 1; i < arguments.length; i++) + arguments[i].top = top + (height - arguments[i].height)/2 + return top + height +} + +// Resize a field, keeping its aspect ratio +function resize(field, maxWidth, maxHeight, allowGrow) +{ + if (allowGrow == null) + allowGrow = true + + var factor = Math.min(maxWidth / field.width, maxHeight / field.height) + if (!allowGrow && factor >= 1) + return + + field.width *= factor + field.height *= factor +} + +function draw() +{ + // Default texts + if (nickname.enabled && nickname.text == "") + nickname.text = "" + if (status_msg.enabled && status_msg.text == "") + status_msg.text = "" + if (listening.enabled && listening.text == "") + listening.text = "" + + if (info.protocol.locked) + status_name.text += " (locked)" + + + // ToolTips + nickname.toolTip = nickname.text + protocol.toolTip = protocol.text + status_icon.toolTip = status_name.toolTip = status_name.text + status_msg.toolTip = status_msg.text + listening_icon.toolTip = listening.toolTip = listening.text + next_proto.toolTip = "Show next protocol" + prev_proto.toolTip = "Show previous protocol" + email_icon.toolTip = email.toolTip = "Unread Email Count: " + email.text + + + // Borders + window.borders.left = opts.border_left + window.borders.top = opts.border_top + window.borders.right = opts.border_right + window.borders.bottom = opts.border_bottom + + + // Visible + nickname.visible = true + prev_proto.visible = next_proto.visible = opts.show_protocol_cycle && !IsEmpty(next_proto, prev_proto) + avatar.visible = opts.show_avatar && avatar.enabled && !IsEmpty(avatar) + protocol.visible = opts.show_protocol && protocol.enabled + status_icon.visible = status_name.visible = opts.show_status && status_name.enabled + status_msg.visible = opts.show_status_msg && !IsEmpty(status_msg) + listening_icon.visible = listening.visible = opts.show_listening && !IsEmpty(listening_icon, listening) + email_icon.visible = email.visible = opts.show_email && email.enabled && !IsEmpty(email_icon, email) && email.text > 0 + + + // Space to draw the frame around + var BORDER_SPACE = 2 + nickname.borders = BORDER_SPACE + protocol.borders = BORDER_SPACE + status_icon.borders = BORDER_SPACE + status_name.borders = BORDER_SPACE + status_msg.borders = BORDER_SPACE + listening_icon.borders = BORDER_SPACE + listening.borders = BORDER_SPACE + email_icon.borders = BORDER_SPACE + email.borders = BORDER_SPACE + + + if (avatar.visible) + { + if (opts.avatar_use_fixed_size) + resize(avatar, opts.avatar_fixed_size, opts.avatar_fixed_size, opts.avatar_allow_grow) + else + resize(avatar, window.width/2.5, window.height - (!info.resize_frame && prev_proto.visible ? prev_proto.height : 0), opts.avatar_allow_grow) + } + + if (!info.resize_frame && prev_proto.visible) + { + prev_proto.left = 0 + prev_proto.bottom = window.height + + next_proto.right = window.width + next_proto.bottom = window.height + } + + var avatar_bottom = avatar.bottom + if (opts.show_avatar && opts.avatar_use_fixed_size) + avatar_bottom = opts.avatar_fixed_size + + var top = 0 + + if (opts.align_right) + { + // Align + nickname.hAlign = RIGHT + protocol.hAlign = RIGHT + status_name.hAlign = RIGHT + status_msg.hAlign = RIGHT + listening.hAlign = RIGHT + + + var right = window.right + + function updateTopRight(val) + { + top = val + if (opts.use_under_avatar && top > avatar_bottom) + right = window.right + } + + if (avatar.visible) + { + avatar.right = window.right + avatar.top = 0 + + right = avatar.left - 6 + } + + if (opts.show_avatar && opts.avatar_use_fixed_size) + right = window.right - opts.avatar_fixed_size - 6 + + nickname.right = right + nickname.top = top + + updateTopRight(nickname.bottom) + + if (protocol.visible) + { + protocol.right = right + protocol.top = top + + if (email.visible) + { + email_icon.right = protocol.left - 10 + email.right = email_icon.left + + var bottom = valign_center(top, protocol, email_icon, email) + updateTopRight(bottom) + } + else + updateTopRight(protocol.bottom) + } + else if (email.visible) + { + email_icon.borders.left = 0 + email_icon.right = right + + email.right = email_icon.left + + var bottom = valign_center(top, email_icon, email) + updateTopRight(bottom) + } + + if (status_name.visible) + { + status_icon.right = right + status_name.right = status_icon.left + + var bottom = valign_center(top, status_icon, status_name) + updateTopRight(bottom) + } + + if (status_msg.visible) + { + status_msg.right = right + status_msg.top = top + + updateTopRight(status_msg.bottom) + } + + if (listening.visible) + { + listening_icon.borders.left = 0 + listening_icon.right = right + + listening.right = listening_icon.left + + var bottom = valign_center(top, listening_icon, listening) + updateTopRight(bottom) + } + } + else + { + var left = 0 + + function updateTopLeft(val) + { + top = val + if (opts.use_under_avatar && top > avatar_bottom) + left = 0 + } + + if (avatar.visible) + { + avatar.left = 0 + avatar.top = 0 + + left = avatar.right + 6 + } + + if (opts.show_avatar && opts.avatar_use_fixed_size) + left = opts.avatar_fixed_size + 6 + + nickname.left = left + nickname.top = top + + updateTopLeft(nickname.bottom) + + if (protocol.visible) + { + protocol.left = left + protocol.top = top + + if (email.visible) + { + email_icon.left = protocol.right + 10 + email.left = email_icon.right + + var bottom = valign_center(top, protocol, email_icon, email) + updateTopLeft(bottom) + } + else + updateTopLeft(protocol.bottom) + } + else if (email.visible) + { + email_icon.borders.right = 0 + email_icon.left = left + + email.left = email_icon.right + + var bottom = valign_center(top, email_icon, email) + updateTopLeft(bottom) + } + + if (status_name.visible) + { + status_icon.left = left + status_name.left = status_icon.right + + var bottom = valign_center(top, status_icon, status_name) + updateTopLeft(bottom) + } + + if (status_msg.visible) + { + status_msg.left = left + status_msg.top = top + + updateTopLeft(status_msg.bottom) + } + + if (listening.visible) + { + listening_icon.borders.right = 0 + listening_icon.left = left + + listening.borders.left = 0 + listening.left = listening_icon.right + + var bottom = valign_center(top, listening_icon, listening) + updateTopLeft(bottom) + } + } + + if (info.resize_frame) + { + if (prev_proto.visible) + { + top = Math.max(avatar.bottom, top) + + prev_proto.left = 0 + prev_proto.top = top + + next_proto.right = window.width + next_proto.top = top + } + } +} \ No newline at end of file diff --git a/plugins/MyDetails/Docs/Skins/Pidgin/MyDetails.msk b/plugins/MyDetails/Docs/Skins/Pidgin/MyDetails.msk new file mode 100644 index 0000000000..89295899f8 --- /dev/null +++ b/plugins/MyDetails/Docs/Skins/Pidgin/MyDetails.msk @@ -0,0 +1,59 @@ +function configure() +{ + // Default fonts + + status_msg.font.face = "Tahoma" + status_msg.font.size = 8 + status_msg.font.color = RGB(0,0,0) +} + +function draw() +{ + if (status_msg.text == "") + status_msg.text = status_name.text + + // ToolTips + status_icon.toolTip = protocol.text + " : " + status_name.text + if (info.protocol.locked) + status_icon.toolTip += " (locked)" + if (email.text > 0) + status_icon.toolTip += " [" + email.text + " emails]" + + status_msg.toolTip = status_msg.text + + // Borders + window.borders = 10 + + // Visible + status_msg.visible = true + avatar.visible = true + status_icon.visible = true + + status_name.visible = false + protocol.visible = false + nickname.visible = false + prev_proto.visible = next_proto.visible = false + listening_icon.visible = listening.visible = false + email_icon.visible = email.visible = false + + // Space to draw the frame around + var BORDER_SPACE = 2 + status_icon.borders = BORDER_SPACE + status_msg.borders = BORDER_SPACE + status_name.borders = BORDER_SPACE + + // Positions + var HEIGHT = 45 + + avatar.right = window.right + avatar.top = 0 + avatar.width = HEIGHT + avatar.height = HEIGHT + + status_icon.left = 0 + status_icon.top = (HEIGHT - status_icon.height) / 2 + + status_msg.left = status_icon.right + 5 + status_msg.top = (HEIGHT - status_msg.height) / 2 + status_msg.right = avatar.left - 5 +} diff --git a/plugins/MyDetails/Docs/langpack_MyDetails.txt b/plugins/MyDetails/Docs/langpack_MyDetails.txt new file mode 100644 index 0000000000..01c61de1b4 --- /dev/null +++ b/plugins/MyDetails/Docs/langpack_MyDetails.txt @@ -0,0 +1,85 @@ +; My Details +; Author: Pescuma +; http://forums.miranda-im.org/showthread.php?t=5643 + +[My Details] + +; Group in options +[Customize] + +; Options + +[ General ] +[Cycle through protocols every:] +[seconds] +[RTL] +[Auto-resize frame] +[Replace Smileys] +[Align text to right] +[Use contact lest smileys] +[Resize Smileys] +[Global on avatar] +[Global on nickname] +[Global on status] +[Global on status message] + +[ Frame Options ] +[Top:] +[Bottom:] +[Left:] +[Right:] +[Background Color:] + +[ Avatar ] +[Custom size:] +[pixels] +[Allow it to grow] +[Draw border on avatar] +[Border Color:] +[Round corners of avatars] +[Custom corner size:] +[Use free space (under avatar) to other texts] + +[ Protocol ] +[Show protocol name] +[Show protocol cycle button] + + +; Default values +[] +[] + + +; Without multiwindows +[Show My Details] +[Hide My Details] + + +; Menus +[Set My Avatar...] +[Set My Nickname...] +[Set My Status Message...] +[Set My Avatar for %s...] +[Set My Nickname for %s...] +[Set My Status Message for %s...] +[Show next protocol] +[Show previous protocol] +[Cycle through protocols] +[Don't cycle through protocols] + + +; Dialogs +[Set My Nickname] +[Set My Nickname for %s] +[Nickname:] + +[Set My Status Message for All Status] +[Set My Status Message for %s] +[Status Message:] + +[OK] +[Cancel] + +; Clist Modern BAckground +[Main Window/Backgrnd] +[MyDetails/Backgrnd] diff --git a/plugins/MyDetails/Docs/mydetails.gif b/plugins/MyDetails/Docs/mydetails.gif new file mode 100644 index 0000000000..8e4d04e583 Binary files /dev/null and b/plugins/MyDetails/Docs/mydetails.gif differ diff --git a/plugins/MyDetails/Docs/mydetails_changelog.txt b/plugins/MyDetails/Docs/mydetails_changelog.txt new file mode 100644 index 0000000000..011a1c63b3 --- /dev/null +++ b/plugins/MyDetails/Docs/mydetails_changelog.txt @@ -0,0 +1,228 @@ +My Details + +Changelog: + +. 0.0.2.6 + + Added support for clist modern skin engine + + Added pidgin style skin + * Fix for last shown protocol + * Updated updater to use googlecode + +. 0.0.2.5 + + Use account name and ordering + * Better handling status messages + * Fix for jabber status names + * Bug fixes + +. 0.0.2.3 + * Moved background color to font service settings + + Better simple away support + +. 0.0.2.2 + * Fix for email count + * Better handling of hover + * Better handling of small sizes + * If fixed avatar size is set, use it even if no avatar present + + If windows uses RTL, it is selected by default + +. 0.0.2.1 + + Show lock icon over status + + Show unread mail count + * Resize frame is working again + * Still work in progress + +. 0.0.2.0 + + Now uses skins plugin to position elements (work in progress) + +. 0.0.1.11 + * Fix for arrows: always draw then at right side + +. 0.0.1.10 + + Added arrows to change protocols (Drugwash patch) + * Use icolib to show icons (uses listening to icon from contact list) + +. 0.0.1.9 + + Created 2 services: MyDetails/HideFrame and MyDetails/ShowFrame + * MyDetails/ShowHideMyDetails changed to work with frames too (it toggles the frame) + +. 0.0.1.8 + * Fix for crash when using main menu options + +. 0.0.1.7 + * Fix for crash when no protocol found + + Added 2 keys to allow themes to show/hide frame: MyDetails\ForceHideFrame and MyDetails\ForceShowFrame (BYTE). Both are deleted after use. + +. 0.0.1.6 + + Added uid for 0.8 + +. 0.0.1.5: + + Added option to set status message per protocol + +. 0.0.1.4 + * Fixed crash on protocol connection + + Support for new version of ersatz + +. 0.0.1.3 + + Support for ersatz plugin by TioDuke. When it is finished, status message will be shown correctly always :) + +. 0.0.1.2 + + Added listening to info + +. 0.0.1.1 + * Fix for crash on exit (thanks ghazan) + - Removed clist modern mod support + +. 0.0.1.0 + * Fix in call to NAS service + + Ready to FL + +. 0.0.0.42 + * Fixed code to open only one dialog + + CTRL-Enter on status message dialog + +. 0.0.0.41 + + Added support to new NAS services + + Open only one dialog (for dialogs that t handles - does not include NAS / avs) + * Bigger buffer for status messages + + First release build (dll is 200k smaller) + +. 0.0.0.40 + * Changed text [Top: ] to [Top:] + + Added langpack_MyDetails.txt + +. 0.0.0.39 + * Reverted to show menus on key up + + Using miranda lists now. This version only works with newer versions of miranda + * Fixed call to NAS with parsed variables + +. 0.0.0.38 + * Fix for international languages + + Translateble options dialog + + Show some menus on key down (but it still not work as desired, i'll have to figure it) + +. 0.0.0.37 + * Bugfix in status menu + + Better support for updater + +. 0.0.0.36 + + Change to better support NAS + + Change to know when info changed (may flick a little less the screen and the tooltip, but may be losing changes) + +. 0.0.0.35 + + Try to discover the default nick + + Global on avatar + * Fixed order of fields in options dialog + +. 0.0.0.34 + * Fixed issue with mTooltip + + Changed tooltip timeout to 10h (is it long enougth? :P ) + +. 0.0.0.33 + + Added timer to refresh status messages. It isnt in options dialog, but can be changed at DB, in key MyDetails\RefreshStatusMessageTimer (0 disables it, default to 12 s) + * Fixed input box in set my nickname + +. 0.0.0.32 + * Fix for crash on startup + * Fix for drawing function + +. 0.0.0.31 + * Fix for status message with NAS + +. 0.0.0.30 + * Try to fix bug when setting name (Again) + * Fix for multi line in status message and nickname + + Setting to call global functions on left click + + Calling service to get max nickname length from protocol (no proto support it right now) + +. 0.0.0.29 + * Fix in status message code + +. 0.0.0.28 + + Multiline popup + + More options in context menu + * Try to fix bug when setting name + +. 0.0.0.27 + + Better support for core away system (it set the message in the DB, inside SRAway module) + +. 0.0.0.26 + + Added tooltips + + Added background collor + + Added XStatus support + + Added in the zip: avatar service (unicode and non-unicode) and folder service + +. 0.0.0.25 + + Added support to set avatars (needs modified version of avatar service - is inside zip) + + Added in the zip: avatar service and folder service + +. 0.0.0.23 + * Bugfix in new status menu code + +. 0.0.0.22 + + Using clist status menus when possible (this should add support to all away system always) + + Show global status menu on right click + * Fixed space in status + +. 0.0.0.21 + * Bugfixes + +. 0.0.0.20 + + Compatibility with KeepStatus -> code is too ugly :'( + + Show status messages only for supported statuses + + Show SimpleAway dialog only to supported protocols + +. 0.0.0.19 + + Better support to SimpleAway + + Set what protocol to show by clicking in proto name + * Bug fixes + +. 0.0.0.18 + + Set status message after status change (should work with gadu-gadu, but it isn't the best solution at all) + +. 0.0.0.17 + + Popups with more actions + + Option to grow avatar + + An attempt to set status messages withou NAS + +. 0.0.0.16 + * Fixed leak of GDI objects + * Fixed resizing of avatar + +. 0.0.0.15 + * Bug fixes + +. 0.0.0.14 + + Resize frame + + Use space bellow avatar + +. 0.0.0.13 + - Change to try to get more updates from status message changes + * Fix in avatar refresh + +. 0.0.0.12 + * Updater works + * Fix drawing protocol name + +. 0.0.0.11 + * Fixed bug on drawing status name + + Added custom avatar size + + Will not cicle when changing status + +. 0.0.0.9 + * Fixed crash on Set My Nickname from status menu + + Added cache to data (should draw faster, but have to see if the data shown is correct) + + Added visual things + + Option to set status + - Changed to set things with left click of mouse + +. 0.0.0.7 + * Fix in NAS fetching code (again) + +. 0.0.0.6 + * Fix in NAS fetching code + + RTL + + Smileys + +. 0.0.0.5 + + Added option dialog + + Added option to not cicle throught protocols \ No newline at end of file diff --git a/plugins/MyDetails/Docs/mydetails_readme.txt b/plugins/MyDetails/Docs/mydetails_readme.txt new file mode 100644 index 0000000000..c9e58d0136 --- /dev/null +++ b/plugins/MyDetails/Docs/mydetails_readme.txt @@ -0,0 +1,41 @@ +My Details plugin +----------------- + +What it does: +- Show your current configuration, per protocol, for avatar, nickname, status and away message +- It shows each protocol at a time, cicling throught then +- Allows to set nickname (per protocol or for all protocols) and away messages (per protocol or for all protocols - need NewAwaySystem, SimpleAway or core module) + +Some comments: +1. SimpleAway does not show a dialog to set a message for all protocols. Someones it does not show the dialog (I requested it in the thread http://forums.miranda-im.org/showthread.php?p=47157). +2. For core away system, only some protocols works (probabily the same as SimpleAway). But for the ones that it works, the message in the frame is the old message. I know, it sucks... But if you use ersatz plugin this problem doesn't happen: http://pescuma.mirandaim.ru/miranda/ersatz.zip + +To request support to other away system: If someone wants to use another away system, please request in its thread to add support for 2 services: +1. Get current status message for a protocol, given its name +2. Set current status message for a protocol, given its name and the message + + +To use skin engine of clist modern: the following glyphs are used: +- MyDetails,ID=Background : background of frame +- MyDetails,ID=MouseOver : base mouse over background (for all fields) +- MyDetails,ID=MouseOverNick : base mouse over background for nick (drawn over the base one) +- MyDetails,ID=MouseOverProto : base mouse over background for protocol (drawn over the base one) +- MyDetails,ID=MouseOverStatus : base mouse over status name/icon for nick (drawn over the base one) +- MyDetails,ID=MouseOverStatusMsg : base mouse over background for status message (drawn over the base one) +- MyDetails,ID=MouseOverListening : base mouse over background for listening info (drawn over the base one) + +To report bugs/make suggestions, go to the forum thread: http://forums.miranda-im.org/showthread.php?t=5643 + +Dependencies: +- If you want integration with clist, an frame enabled clist, such as clist_modern or clist_nicer+ +- Away systens supported: Core, NewAwaySystem or SimpleAway + +Todo: +- Global page +- Add custom presets +- Resize on mouse hover +- clist_modern_layered integration -> try this: http://forums.miranda-im.org/showthread.php?t=6597 +- New drawing code (please, do not request things like order of items or spacing, it is in TODO list, but will take time to be made) +- Options to XStatus setup +- Icons instead of ... on mouse over +- Options to show/hide itens diff --git a/plugins/MyDetails/Docs/mydetails_version.txt b/plugins/MyDetails/Docs/mydetails_version.txt new file mode 100644 index 0000000000..e078af1e48 --- /dev/null +++ b/plugins/MyDetails/Docs/mydetails_version.txt @@ -0,0 +1 @@ +My Details 0.0.2.6 \ No newline at end of file diff --git a/plugins/MyDetails/commons.h b/plugins/MyDetails/commons.h new file mode 100644 index 0000000000..ca1849c826 --- /dev/null +++ b/plugins/MyDetails/commons.h @@ -0,0 +1,148 @@ +/* +Copyright (C) 2005 Ricardo Pescuma Domenecci + +This is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public +License as published by the Free Software Foundation; either +version 2 of the License, or (at your option) any later version. + +This 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 +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with this file; see the file license.txt. If +not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. +*/ + + +#ifndef __COMMONS_H__ +# define __COMMONS_H__ + + +#define _WIN32_WINNT 0x0501 +#include +#include +#include +#include +#include + +#define MIRANDA_VER 0x800 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "m_cluiframes.h" +#include "m_simpleaway.h" + +#include +#include + +#include + +#include "../skins/m_skins_cpp.h" + +#include "resource.h" + + +#define MODULE_NAME "MyDetails" + +#define SETTING_FRAME_VISIBLE "FrameVisible" +#define SETTING_DEFAULT_NICK "DefaultNick" + + +extern HINSTANCE hInst; +extern PLUGINLINK *pluginLink; + +extern long nickname_dialog_open; +extern long status_msg_dialog_open; + +extern SkinDialog *dialog; + + +#include "m_mydetails.h" +#include "data.h" +#include "options.h" +#include "frame.h" +#include "../utils/mir_smileys.h" +#include "../utils/mir_memory.h" +#include "../utils/mir_options.h" +#include "../utils/mir_icons.h" +#include "../utils/tstring.h" + + +#define PS_SETMYAVATAR "/SetMyAvatar" +#define PS_GETMYAVATAR "/GetMyAvatar" +#define PS_GETMYAVATARMAXSIZE "/GetMyAvatarMaxSize" +#define PS_GETUNREADEMAILCOUNT "/GetUnreadEmailCount" + +#define PS_SETMYNICKNAME "/SetNickname" + +#define PS_GETMYNICKNAMEMAXLENGTH "/GetMyNicknameMaxLength" + +#define WAYD_UNICODE 1 // return Unicode texts +#if defined( _UNICODE ) + #define WAYD_TCHAR WAYD_UNICODE +#else + #define WAYD_TCHAR 0 +#endif + +// Get the max length that a WAYD message can have +// wParam=(WPARAM)0 +// lParam=(LPARAM)0 +// Returns the max length +#define PS_GET_MY_WAYD_MAXLENGTH "/GetMyWAYDMaxLength" + +// Get the WAYD message for the user +// wParam=(WPARAM)WAYD_xxx +// lParam=(LPARAM)0 +// Returns the text or NULL if there is none. Remember to mir_free the return value. +#define PS_GET_MY_WAYD "/GetMyWAYD" + +// Sets the WAYD message for the user +// wParam=(WPARAM)WAYD_xxx +// lParam=(LPARAM)(WCHAR * or char *)The text to set +// Returns 0 on success, nonzero on failure +#define PS_SET_MY_WAYD "/SetMyWAYD" + +#define MAX_REGS(_A_) ( sizeof(_A_) / sizeof(_A_[0]) ) + + +// See if a protocol service exists +__inline static int ProtoServiceExists(const char *szModule,const char *szService) +{ + char str[MAXMODULELABELLENGTH]; + strcpy(str,szModule); + strcat(str,szService); + return ServiceExists(str); +} + + + + + +#endif // __COMMONS_H__ diff --git a/plugins/MyDetails/data.cpp b/plugins/MyDetails/data.cpp new file mode 100644 index 0000000000..eccd72e0e7 --- /dev/null +++ b/plugins/MyDetails/data.cpp @@ -0,0 +1,1063 @@ +/* +Copyright (C) 2005 Ricardo Pescuma Domenecci + +This is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public +License as published by the Free Software Foundation; either +version 2 of the License, or (at your option) any later version. + +This 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 +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with this file; see the file license.txt. If +not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. +*/ + + +#include "commons.h" +#include "data.h" +#include + + +static char *StatusModeToDbSetting(int status,const char *suffix); + + +static bool IsValid(const char *proto) +{ + if (proto == NULL || proto[0] == 0) + return false; + + int caps = CallProtoService(proto, PS_GETCAPS, PFLAGNUM_1, 0); + return (caps & PF1_IM) == PF1_IM && strcmp(proto, "MetaContacts") != 0; +} + +static bool AccOrderComp(PROTOACCOUNT *p1, PROTOACCOUNT *p2) +{ + return p1->iOrder < p2->iOrder; +} + +static void GetAccounts(std::vector *result) +{ + int count; + PROTOACCOUNT **protos; + ProtoEnumAccounts(&count, &protos); + + for (int i = 0; i < count; i++) + { + if (protos[i]->type != PROTOTYPE_PROTOCOL) + continue; + + if (!IsAccountEnabled(protos[i])) + continue; + + if (!IsValid(protos[i]->szModuleName)) + continue; + + result->push_back(protos[i]); + } + + std::sort(result->begin(), result->begin(), AccOrderComp); +} + + +void GetProtocols(std::vector *result) +{ + std::vector accs; + GetAccounts(&accs); + + unsigned int accsSize = accs.size(); + for (unsigned int i = 0; i < accsSize ; ++i) + result->push_back(Protocol(accs[i]->szModuleName)); +} + + +int GetProtocolIndexByName(const char *moduleName) +{ + std::vector protos; + GetAccounts(&protos); + + int protosSize = (int) protos.size(); + for(int i = 0; i < protosSize; ++i) + { + if (strcmp(protos[i]->szModuleName, moduleName) == 0) + return i; + } + + return -1; +} + + +int GetNumProtocols() +{ + std::vector protos; + GetAccounts(&protos); + return protos.size(); +} + + +struct ProtoCache +{ + Protocol *proto; + int index; + + void Free() + { + delete proto; + proto = NULL; + index = -1; + } +}; + +static ProtoCache current = { NULL, -1 }; + + +void SetCurrentProtocol(int index) +{ + current.Free(); + + int protosSize = GetNumProtocols(); + if (protosSize > 0) + current.index = (index % protosSize + protosSize) % protosSize; + + DBWriteContactSettingWord(NULL, "MyDetails", "ProtocolNumber", current.index); +} + +Protocol * GetCurrentProtocol(bool createIfDontExist) +{ + if (createIfDontExist && current.index >= 0 && current.proto == NULL) + { + std::vector protos; + GetAccounts(&protos); + + int protosSize = protos.size(); + if (current.index >= protosSize) + { + current.index = -1; + return NULL; + } + + current.proto = new Protocol(protos[current.index]->szModuleName); + } + + return current.proto; +} + +int GetCurrentProtocolIndex() +{ + return current.index; +} + + +Protocol GetProtocolByIndex(int index) +{ + std::vector protos; + GetAccounts(&protos); + int protosSize = protos.size(); + + if (protosSize < 1) + return Protocol(NULL); + + index = (index % protosSize + protosSize) % protosSize; + return Protocol(protos[index]->szModuleName); +} + + +Protocol GetProtocolByName(const char *moduleName) +{ + std::vector protos; + GetAccounts(&protos); + + int protosSize = (int) protos.size(); + for(int i = 0; i < protosSize; ++i) + { + if (strcmp(protos[i]->szModuleName, moduleName) == 0) + return Protocol(protos[i]->szModuleName); + } + + return Protocol(NULL); +} + + +ProtocolArray *protocols = NULL; + + +void InitProtocolData() +{ + protocols = new ProtocolArray(); +} + + +void DeInitProtocolData() +{ + current.Free(); + + delete protocols; + protocols = NULL; +} + + +// Protocol Class /////////////////////////////////////////////////////////////////////////////////////////// + + +Protocol::Protocol(const char *aName) +{ + if (aName) + name = aName; + + avatar_bmp = NULL; + status = 0; + custom_status = 0; + locked = false; + emails = 0; + + // Initial value + UpdateAll(); +} + +Protocol::~Protocol() +{ +} + + +bool Protocol::IsValid() +{ + return !name.empty(); +} + + +Protocol::operator bool () +{ + return IsValid(); +} + + +void Protocol::UpdateAll() +{ + status_initialized = false; + status_message_initialized = false; + nickname_initialized = false; + avatar_initialized = false; + locked_initialized = false; + emails_initialized = false; + listening_to_initialized = false; +} + + +int Protocol::Call(const char *service, WPARAM wParam, LPARAM lParam) +{ + return CallProtoService(name.c_str(), service, wParam, lParam); +} + + +bool Protocol::CanCall(const char *service) +{ + return ProtoServiceExists(name.c_str(), service) != 0; +} + + +std::string Protocol::GetDBSettingString(const char *key, const char *def) +{ + std::string result = def; + + DBVARIANT dbv; + if (!DBGetContactSettingTString(0, name.c_str(), key, &dbv)) + { + if (dbv.ptszVal != NULL && dbv.ptszVal[0] != 0) + result = dbv.ptszVal; + + DBFreeVariant(&dbv); + } + + return result; +} + + +const char * Protocol::GetName() +{ + return name.c_str(); +} + + +const char * Protocol::GetDescription() +{ + if (description.empty()) + { + PROTOACCOUNT *acc = ProtoGetAccount(name.c_str()); + + if (acc == NULL || acc->tszAccountName == NULL || acc->tszAccountName[0] == 0) + { + char tmp[1024]; + Call(PS_GETNAME, sizeof(tmp), (LPARAM) tmp); + description = tmp; + } + else + { + if (mir_is_unicode()) + { + char *tmp = mir_u2a((const wchar_t *) acc->tszAccountName); + description = tmp; + mir_free(tmp); + } + else + { + description = acc->tszAccountName; + } + } + } + + return description.c_str(); +} + +void Protocol::UpdateStatus() +{ + status_initialized = true; + + status = Call(PS_GETSTATUS); + + if (status > ID_STATUS_OFFLINE && CanCall(PS_ICQ_GETCUSTOMSTATUS)) + { + char *name_key = NULL; + char *message_key = NULL; + + custom_status = Call(PS_ICQ_GETCUSTOMSTATUS, (WPARAM) &name_key, (LPARAM) &message_key); + + // Fix fo jabber, that returns 0xbaadf00d here + if (custom_status < 0) + custom_status = 0; + + custom_status_name_key = (name_key ? name_key : ""); + custom_status_message_key = (message_key ? message_key : ""); + } + else + { + custom_status = 0; + custom_status_name_key = ""; + custom_status_message_key = ""; + } + + if (custom_status == 0) + { + status_name = (char *) CallService(MS_CLIST_GETSTATUSMODEDESCRIPTION, status, GCMDF_TCHAR); + } + else + { + status_name = ""; + + if (!custom_status_name_key.empty()) + status_name = GetDBSettingString(custom_status_name_key.c_str()); + + if (!custom_status_message_key.empty()) + { + std::string tmp = GetDBSettingString(custom_status_message_key.c_str()); + if (!tmp.empty()) + { + status_name += ": "; + status_name += tmp; + } + } + } + + if (status_name.empty()) + status_name = TranslateTS(""); +} + +const char * Protocol::GetStatusName() +{ + if (!status_initialized) + UpdateStatus(); + + return status_name.c_str(); +} + +const char * Protocol::GetCustomStatusNameKey() +{ + if (!status_initialized) + UpdateStatus(); + + return custom_status_name_key.c_str(); +} + +const char * Protocol::GetCustomStatusMessageKey() +{ + if (!status_initialized) + UpdateStatus(); + + return custom_status_message_key.c_str(); +} + +int Protocol::GetStatus() +{ + if (!status_initialized) + UpdateStatus(); + + return status; +} + +int Protocol::GetCustomStatus() +{ + if (!status_initialized) + UpdateStatus(); + + return custom_status; +} + + +void Protocol::SetStatus(int aStatus) +{ + char status_msg[256]; + + if (ServiceExists(MS_CS_SETSTATUSEX)) + { + // :'( + + // BEGIN From commomstatus.cpp (KeepStatus) + int i, count, pCount; + PROTOCOLDESCRIPTOR **protos; + + pCount = 0; + CallService(MS_PROTO_ENUMPROTOCOLS,(WPARAM)&count,(LPARAM)&protos); + for(i=0;itype!=PROTOTYPE_PROTOCOL || CallProtoService(protos[i]->szName,PS_GETCAPS,PFLAGNUM_2,0)==0) continue; + pCount += 1; + } + // END From commomstatus.cpp (KeepStatus) + + + PROTOCOLSETTINGEX **pse = (PROTOCOLSETTINGEX **) mir_alloc0(pCount * sizeof(PROTOCOLSETTINGEX *)); + + for(i = 0; i < pCount; i++) + { + pse[i] = (PROTOCOLSETTINGEX *) mir_alloc0(sizeof(PROTOCOLSETTINGEX)); + pse[i]->szName = ""; + } + + pse[0]->cbSize = sizeof(PROTOCOLSETTINGEX); + pse[0]->status = aStatus; + pse[0]->szName = (char *) name.c_str(); + + GetStatusMsg(aStatus, status_msg, sizeof(status_msg)); + pse[0]->szMsg = status_msg; + + CallService(MS_CS_SETSTATUSEX, (WPARAM) &pse, 0); + + for(i = 0; i < pCount; i++) + mir_free(pse[i]); + mir_free(pse); + } + else + { + Call(PS_SETSTATUS, aStatus); + + if (CanSetStatusMsg(aStatus)) + { + char status_msg[MS_MYDETAILS_GETMYSTATUSMESSAGE_BUFFER_SIZE]; + GetStatusMsg(aStatus, status_msg, sizeof(status_msg)); + SetStatusMsg(aStatus, status_msg); + } + } +} + + +bool Protocol::CanGetStatusMsg() +{ + return CanGetStatusMsg(GetStatus()); +} + +bool Protocol::CanGetStatusMsg(int aStatus) +{ + return (Call(PS_GETCAPS, PFLAGNUM_1) & PF1_MODEMSGSEND) != 0 + && (Call(PS_GETCAPS, (WPARAM)PFLAGNUM_3) & Proto_Status2Flag(aStatus)); +} + + +bool Protocol::CanSetStatusMsg() +{ + return CanSetStatusMsg(GetStatus()) // <- Simple away handled by this one + || ServiceExists(MS_NAS_INVOKESTATUSWINDOW); + +} + +bool Protocol::CanSetStatusMsg(int aStatus) +{ + return CanGetStatusMsg(aStatus); +} + +void Protocol::GetStatusMsg(int aStatus, char *msg, size_t msg_size) +{ + if (!CanGetStatusMsg()) + { + lstrcpyn(msg, "", msg_size); + return; + } + + bool isCurrentStatus = (aStatus == GetStatus()); + + if (isCurrentStatus && CanCall(PS_GETMYAWAYMSG)) + { + char *tmp = (char *) Call(PS_GETMYAWAYMSG); + lstrcpyn(msg, tmp == NULL ? "" : tmp, msg_size); + } + else if (isCurrentStatus && ServiceExists(MS_SA_ISSARUNNING) && CallService(MS_SA_ISSARUNNING, 0, 0)) + { + char *tmp = (char *) CallService(MS_AWAYMSG_GETSTATUSMSG, (WPARAM) ID_STATUS_CURRENT, (LPARAM) name.c_str()); + + if (tmp != NULL) + { + lstrcpyn(msg, tmp, msg_size); + mir_free(tmp); + } + else lstrcpyn(msg, "", msg_size); + + } + else if (ServiceExists(MS_NAS_GETSTATE)) + { + NAS_PROTOINFO pi; + + ZeroMemory(&pi, sizeof(pi)); + pi.cbSize = sizeof(NAS_PROTOINFO); + pi.szProto = (char *) name.c_str(); + pi.status = (isCurrentStatus ? 0 : aStatus); + pi.szMsg = NULL; + + if (CallService(MS_NAS_GETSTATE, (WPARAM) &pi, 1) == 0) + { + if (pi.szMsg == NULL) + { + pi.szProto = NULL; + + if (CallService(MS_NAS_GETSTATE, (WPARAM) &pi, 1) == 0) + { + if (pi.szMsg != NULL) + { + lstrcpyn(msg, pi.szMsg, msg_size); + mir_free(pi.szMsg); + } + else lstrcpyn(msg, "", msg_size); + } + else lstrcpyn(msg, "", msg_size); + } + else // if (pi.szMsg != NULL) + { + lstrcpyn(msg, pi.szMsg, msg_size); + mir_free(pi.szMsg); + } + } + else lstrcpyn(msg, "", msg_size); + + if (ServiceExists(MS_VARS_FORMATSTRING)) + { + char *tmp = variables_parse(msg, NULL, NULL); + lstrcpyn(msg, tmp, msg_size); + variables_free(tmp); + } + } + // TODO: Remove when removing old NAS services support + else if (ServiceExists("NewAwaySystem/GetState")) + { + NAS_PROTOINFO pi, *pii; + + ZeroMemory(&pi, sizeof(pi)); + pi.cbSize = sizeof(NAS_PROTOINFO); + pi.szProto = (char *) name.c_str(); + pi.status = (isCurrentStatus ? 0 : aStatus); + pi.szMsg = NULL; + + pii = π + + if (CallService("NewAwaySystem/GetState", (WPARAM) &pii, 1) == 0) + { + if (pi.szMsg == NULL) + { + pi.szProto = NULL; + + if (CallService("NewAwaySystem/GetState", (WPARAM) &pii, 1) == 0) + { + if (pi.szMsg != NULL) + { + lstrcpyn(msg, pi.szMsg, msg_size); + mir_free(pi.szMsg); + } + else lstrcpyn(msg, "", msg_size); + } + else lstrcpyn(msg, "", msg_size); + } + else // if (pi.szMsg != NULL) + { + lstrcpyn(msg, pi.szMsg, msg_size); + mir_free(pi.szMsg); + } + } + else lstrcpyn(msg, "", msg_size); + + if (ServiceExists(MS_VARS_FORMATSTRING)) + { + char *tmp = variables_parse(msg, NULL, NULL); + lstrcpyn(msg, tmp, msg_size); + variables_free(tmp); + } + } + else if (ServiceExists(MS_AWAYMSG_GETSTATUSMSG)) + { + char *tmp = (char *) CallService(MS_AWAYMSG_GETSTATUSMSG, (WPARAM)aStatus, 0); + + if (tmp != NULL) + { + lstrcpyn(msg, tmp, msg_size); + mir_free(tmp); + } + else lstrcpyn(msg, "", msg_size); + } +} + +void Protocol::UpdateStatusMsg() +{ + status_message_initialized = true; + + TCHAR tmp[1024]; + GetStatusMsg(GetStatus(), tmp, sizeof(tmp)); + + status_message = tmp; +} + +const char * Protocol::GetStatusMsg() +{ + if (!status_message_initialized) + UpdateStatusMsg(); + + return status_message.c_str(); +} + +void Protocol::SetStatusMsg(const char *message) +{ + SetStatusMsg(GetStatus(), message); +} + +void Protocol::SetStatusMsg(int aStatus, const char *message) +{ + if (!CanSetStatusMsg(aStatus)) + return; + + if (ServiceExists(MS_NAS_SETSTATE)) + { + NAS_PROTOINFO pi = {0}, *pii; + + pi.cbSize = sizeof(pi); + pi.szProto = (char *) name.c_str(); + pi.szMsg = mir_strdup(message); + pi.status = aStatus; + + pii = π + + CallService(MS_NAS_SETSTATE, (WPARAM) &pii, 1); + } + else + { + Call(PS_SETAWAYMSG, (WPARAM) aStatus, (LPARAM) message); + } +} + +bool Protocol::HasAvatar() +{ + if (!avatar_initialized) + UpdateAvatar(); + + return avatar_bmp != NULL; +} + +bool Protocol::CanGetAvatar() +{ + int caps = Call(PS_GETCAPS, PFLAGNUM_4); + + if ((caps & PF4_AVATARS) == 0) + return false; + + if (!ServiceExists(MS_AV_GETMYAVATAR)) + return false; + + return true; +} + +void Protocol::UpdateAvatar() +{ + avatar_initialized = true; + avatar_file = ""; + avatar_bmp = NULL; + + // See if can get one + if (!CanGetAvatar()) + return; + + // Get HBITMAP from cache + AVATARCACHEENTRY *ace = (avatarCacheEntry *) CallService(MS_AV_GETMYAVATAR, 0, (LPARAM) name.c_str()); + if (ace != NULL) + { + avatar_file = ace->szFilename; + avatar_bmp = ace->hbmPic; + } +} + +const char * Protocol::GetAvatarFile() +{ + if (!avatar_initialized) + UpdateAvatar(); + + return avatar_file.c_str(); +} + +HBITMAP Protocol::GetAvatarImage() +{ + if (!avatar_initialized) + UpdateAvatar(); + + return avatar_bmp; +} + + +bool Protocol::CanGetNick() +{ + return ServiceExists(MS_CONTACT_GETCONTACTINFO) != FALSE; +} + +int Protocol::GetNickMaxLength() +{ + if (CanCall(PS_GETMYNICKNAMEMAXLENGTH)) + { + int ret = Call(PS_GETMYNICKNAMEMAXLENGTH); + if (ret <= 0) + ret = MS_MYDETAILS_GETMYNICKNAME_BUFFER_SIZE; + return ret; + } + else + return MS_MYDETAILS_GETMYNICKNAME_BUFFER_SIZE; +} + +void Protocol::UpdateNick() +{ + nickname_initialized = true; + nickname = ""; + + // See if can get one + if (!CanGetNick()) + return; + + // Get it + CONTACTINFO ci; + ZeroMemory(&ci, sizeof(ci)); + ci.cbSize = sizeof(ci); + ci.hContact = NULL; + ci.szProto = (char *) name.c_str(); + ci.dwFlag = CNF_DISPLAY; + +#ifdef UNICODE + ci.dwFlag |= CNF_UNICODE; +#endif + + if (!CallService(MS_CONTACT_GETCONTACTINFO, 0, (LPARAM) & ci)) + { + // CNF_DISPLAY always returns a string type + nickname = ci.pszVal; + mir_free(ci.pszVal); + } +} + +const char * Protocol::GetNick() +{ + if (!nickname_initialized) + UpdateNick(); + + return nickname.c_str(); +} + + +bool Protocol::CanSetNick() +{ + return CanCall(PS_SETMYNICKNAME) != 0; +} + + +void Protocol::SetNick(const char *nick) +{ + // See if can get one + if (!CanSetNick()) + return; + + if (nick == NULL) + return; + + // Get it + Call(PS_SETMYNICKNAME, NULL, (LPARAM) nick); +} + + +bool Protocol::CanSetAvatar() +{ + return ServiceExists(MS_AV_SETMYAVATAR) != FALSE && ServiceExists(MS_AV_CANSETMYAVATAR) != FALSE && + CallService(MS_AV_CANSETMYAVATAR, (WPARAM) name.c_str(), 0); +} + +void Protocol::SetAvatar(const char *file_name) +{ + if (!CanSetAvatar()) + return; + + CallService(MS_AV_SETMYAVATAR, (WPARAM) name.c_str(), (LPARAM) file_name); +} + +bool Protocol::CanGetListeningTo() +{ + return CanCall(PS_SET_LISTENINGTO) != 0; +} + +bool Protocol::CanSetListeningTo() +{ + return CanGetListeningTo() && ServiceExists(MS_LISTENINGTO_ENABLE); +} + +bool Protocol::ListeningToEnabled() +{ + return CanSetListeningTo() && CallService(MS_LISTENINGTO_ENABLED, (WPARAM) name.c_str(), 0) != 0; +} + +void Protocol::UpdateListeningTo() +{ + listening_to_initialized = true; + listening_to = ""; + + if (!CanGetListeningTo()) + return; + + listening_to = GetDBSettingString("ListeningTo"); +} + +const char * Protocol::GetListeningTo() +{ + if (!listening_to_initialized) + UpdateListeningTo(); + + return listening_to.c_str(); +} + +void Protocol::UpdateLocked() +{ + locked_initialized = true; + + locked = (DBGetContactSettingByte(NULL, name.c_str(), "LockMainStatus", 0) != 0); +} + +bool Protocol::IsLocked() +{ + if (!locked_initialized) + UpdateLocked(); + + return locked; +} + +bool Protocol::CanGetEmailCount() +{ + return CanCall(PS_GETUNREADEMAILCOUNT) != 0 + && GetStatus() > ID_STATUS_OFFLINE; +} + +void Protocol::UpdateEmailCount() +{ + emails_initialized = true; + + if (!CanGetEmailCount()) + emails = 0; + else + emails = max(0, Call(PS_GETUNREADEMAILCOUNT)); +} + +int Protocol::GetEmailCount() +{ + if (!emails_initialized) + UpdateEmailCount(); + + return emails; +} + + +// ProtocolDataArray Class ///////////////////////////////////////////////////////////////////////////// + + +ProtocolArray::ProtocolArray() +{ + GetDefaultNick(); + GetDefaultAvatar(); +} + +int ProtocolArray::GetGlobalStatus() +{ + int status = CallService(MS_CLIST_GETSTATUSMODE, 0, 0); + if (status == ID_STATUS_CONNECTING) + status = ID_STATUS_OFFLINE; + + return status; +} + +bool ProtocolArray::CanSetAvatars() +{ + return ServiceExists(MS_AV_SETMYAVATAR) != FALSE; +} + +void ProtocolArray::SetAvatars(const char *file_name) +{ + if (!CanSetAvatars()) + return; + + CallService(MS_AV_SETMYAVATAR, NULL, (WPARAM) file_name); +} + + +void ProtocolArray::SetNicks(const char *nick) +{ + if (nick == NULL || nick[0] == '\0') + return; + + lstrcpyn(default_nick, nick, sizeof(default_nick)); + + DBWriteContactSettingString(0, MODULE_NAME, SETTING_DEFAULT_NICK, nick); + + std::vector protos; + GetProtocols(&protos); + + unsigned int protosSize = protos.size(); + for (int i = 0; i < protosSize; ++i) + protos[i].SetNick(default_nick); +} + + +void ProtocolArray::SetStatus(int aStatus) +{ + CallService(MS_CLIST_SETSTATUSMODE, aStatus, 0); +} + +void ProtocolArray::SetStatusMsgs(const char *message) +{ + for (int i = ID_STATUS_OFFLINE ; i <= ID_STATUS_IDLE; i++) + { + SetStatusMsgs(i, message); + } +} + +void ProtocolArray::SetStatusMsgs(int status, const char *message) +{ + DBWriteContactSettingString(NULL,"SRAway",StatusModeToDbSetting(status,"Msg"),message); + if (!DBGetContactSettingByte(NULL,"SRAway",StatusModeToDbSetting(status,"UsePrev"),0)) + { + // Save default also + DBWriteContactSettingString(NULL,"SRAway",StatusModeToDbSetting(status,"Default"),message); + } + + std::vector protos; + GetProtocols(&protos); + + unsigned int protosSize = protos.size(); + for (int i = 0; i < protosSize; ++i) + { + if (protos[i].GetStatus() == status) + protos[i].SetStatusMsg(status, message); + } +} + + +void ProtocolArray::GetDefaultNick() +{ + DBVARIANT dbv; + + if (!DBGetContactSettingTString(0, MODULE_NAME, SETTING_DEFAULT_NICK, &dbv)) + { + lstrcpyn(default_nick, dbv.pszVal, sizeof(default_nick)); + DBFreeVariant(&dbv); + } + else + { + default_nick[0] = '\0'; + } +} + +void ProtocolArray::GetDefaultAvatar() +{ + DBVARIANT dbv; + + if (!DBGetContactSettingTString(0, "ContactPhoto", "File", &dbv)) + { + lstrcpyn(default_avatar_file, dbv.pszVal, sizeof(default_avatar_file)); + DBFreeVariant(&dbv); + } + else + { + default_avatar_file[0] = '\0'; + } +} + +char * ProtocolArray::GetDefaultStatusMsg() +{ + return GetDefaultStatusMsg(CallService(MS_CLIST_GETSTATUSMODE, 0, 0)); +} + +char * ProtocolArray::GetDefaultStatusMsg(int status) +{ + default_status_message[0] = '\0'; + + if (ServiceExists(MS_AWAYMSG_GETSTATUSMSG)) + { + if (status == ID_STATUS_CONNECTING) + { + status = ID_STATUS_OFFLINE; + } + + char *tmp = (char *) CallService(MS_AWAYMSG_GETSTATUSMSG, (WPARAM)status, 0); + + if (tmp != NULL) + { + lstrcpyn(default_status_message, tmp, sizeof(default_status_message)); + mir_free(tmp); + } + } + + return default_status_message; +} + +bool ProtocolArray::CanSetListeningTo() +{ + return ServiceExists(MS_LISTENINGTO_ENABLE) != 0; +} + +bool ProtocolArray::ListeningToEnabled() +{ + return CanSetListeningTo() && CallService(MS_LISTENINGTO_ENABLED, 0, 0) != 0; +} + + +////////////////////////////////////////////////////////////////////////////////////////////////////// +// Helper functions + +static char *StatusModeToDbSetting(int status,const char *suffix) +{ + char *prefix; + static char str[64]; + + switch(status) { + case ID_STATUS_AWAY: prefix="Away"; break; + case ID_STATUS_NA: prefix="Na"; break; + case ID_STATUS_DND: prefix="Dnd"; break; + case ID_STATUS_OCCUPIED: prefix="Occupied"; break; + case ID_STATUS_FREECHAT: prefix="FreeChat"; break; + case ID_STATUS_ONLINE: prefix="On"; break; + case ID_STATUS_OFFLINE: prefix="Off"; break; + case ID_STATUS_INVISIBLE: prefix="Inv"; break; + case ID_STATUS_ONTHEPHONE: prefix="Otp"; break; + case ID_STATUS_OUTTOLUNCH: prefix="Otl"; break; + case ID_STATUS_IDLE: prefix="Idl"; break; + default: return NULL; + } + lstrcpyA(str,prefix); lstrcatA(str,suffix); + return str; +} + + diff --git a/plugins/MyDetails/data.h b/plugins/MyDetails/data.h new file mode 100644 index 0000000000..9c458b50dd --- /dev/null +++ b/plugins/MyDetails/data.h @@ -0,0 +1,183 @@ +/* +Copyright (C) 2005 Ricardo Pescuma Domenecci + +This is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public +License as published by the Free Software Foundation; either +version 2 of the License, or (at your option) any later version. + +This 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 +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with this file; see the file license.txt. If +not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. +*/ + + +#ifndef __DATA_H__ +# define __DATA_H__ + + +//#include "protocol_config.h" + +class Protocol +{ + // Attributes //////////// + std::string name; + + std::string description; + + bool avatar_initialized; + std::string avatar_file; + HBITMAP avatar_bmp; + + bool status_message_initialized; + std::string status_message; + + bool nickname_initialized; + std::string nickname; + + bool locked_initialized; + bool locked; + + bool emails_initialized; + int emails; + + bool listening_to_initialized; + std::string listening_to; + + bool status_initialized; + std::string status_name; + std::string custom_status_name_key; + std::string custom_status_message_key; + int status; + int custom_status; + +public: + Protocol(const char *name); + ~Protocol(); + + bool IsValid(); + operator bool (); + + void UpdateAll(); + + const char * GetName(); + const char * GetDescription(); + + const char * GetStatusName(); + const char * GetCustomStatusNameKey(); + const char * GetCustomStatusMessageKey(); + int GetStatus(); + int GetCustomStatus(); + void SetStatus(int aStatus); + + bool HasAvatar(); + bool CanGetAvatar(); + const char * GetAvatarFile(); + HBITMAP GetAvatarImage(); + + bool CanSetAvatar(); + void SetAvatar(const TCHAR *file_name); + + bool CanGetNick(); + const char * GetNick(); + int GetNickMaxLength(); + bool CanSetNick(); + void SetNick(const TCHAR *nick); + + bool CanGetListeningTo(); + bool CanSetListeningTo(); + bool ListeningToEnabled(); + const char * GetListeningTo(); + + bool CanGetStatusMsg(); + bool CanGetStatusMsg(int aStatus); + void GetStatusMsg(int aStatus, TCHAR *msg, size_t msg_size); + const char * GetStatusMsg(); + + bool CanSetStatusMsg(); + bool CanSetStatusMsg(int aStatus); + void SetStatusMsg(const TCHAR *message); + void SetStatusMsg(int aStatus, const TCHAR *message); + + bool IsLocked(); + + bool CanGetEmailCount(); + int GetEmailCount(); + + int Call(const char *service, WPARAM wParam = 0, LPARAM lParam = 0); + bool CanCall(const char *service); + + std::string GetDBSettingString(const char *key, const char *def = ""); + +private: + void UpdateStatus(); + void UpdateAvatar(); + void UpdateNick(); + void UpdateListeningTo(); + void UpdateStatusMsg(); + void UpdateLocked(); + void UpdateEmailCount(); +}; + + + +class ProtocolArray +{ +public: + TCHAR default_nick[256]; + TCHAR default_avatar_file[256]; + TCHAR default_status_message[256]; + + // Methods /////////////// + + ProtocolArray(); + + bool CanSetAvatars(); + void SetAvatars(const TCHAR *file); + + void SetNicks(const TCHAR *nick); + + void SetStatus(int aStatus); + + void SetStatusMsgs(const TCHAR *message); + void SetStatusMsgs(int status, const TCHAR *message); + + int GetGlobalStatus(); + + void GetDefaultNick(); // Copy to cache + void GetDefaultAvatar(); // Copy to cache + TCHAR * GetDefaultStatusMsg(); // Copy to cache + TCHAR * GetDefaultStatusMsg(int status); + + bool CanSetListeningTo(); + bool ListeningToEnabled(); +}; + +extern ProtocolArray *protocols; + + +void SetCurrentProtocol(int index); +Protocol * GetCurrentProtocol(bool createIfDontExist = true); +int GetCurrentProtocolIndex(); + +void GetProtocols(std::vector *result); +int GetProtocolIndexByName(const char *moduleName); +int GetNumProtocols(); +Protocol GetProtocolByIndex(int index); +Protocol GetProtocolByName(const char *proto); + +void InitProtocolData(); +void DeInitProtocolData(); + + + + + + +#endif // __DATA_H__ diff --git a/plugins/MyDetails/frame.cpp b/plugins/MyDetails/frame.cpp new file mode 100644 index 0000000000..d5b609a4e9 --- /dev/null +++ b/plugins/MyDetails/frame.cpp @@ -0,0 +1,2428 @@ +/* +Copyright (C) 2005 Ricardo Pescuma Domenecci + +This is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public +License as published by the Free Software Foundation; either +version 2 of the License, or (at your option) any later version. + +This 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 +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with this file; see the file license.txt. If +not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. +*/ + + +#include "commons.h" +#include "frame.h" +#include "wingdi.h" +#include "winuser.h" +#include + + +// Prototypes ///////////////////////////////////////////////////////////////////////////////////// + + +#define WINDOW_NAME_PREFIX "mydetails_window" +#define WINDOW_CLASS_NAME "MyDetailsFrame" +#define CONTAINER_CLASS_NAME "MyDetailsFrameContainer" + +#define ID_FRAME_TIMER 1011 +#define ID_RECALC_TIMER 1012 +#define ID_STATUSMESSAGE_TIMER 1013 + +#define RECALC_TIME 500 + +#define IDC_HAND MAKEINTRESOURCE(32649) + + +// Messages +#define MWM_REFRESH (WM_USER+10) +#define MWM_REFRESH_DATA (WM_USER+18) + + +HWND hwnd_frame = NULL; +HWND hwnd_container = NULL; + +int frame_id = -1; + +HANDLE hMenuShowHideFrame = 0; + +int CreateFrame(); +void FixMainMenu(); +void UpdateFrameData(); +void RedrawFrame(); + + +// used when no multiwindow functionality available +BOOL MyDetailsFrameVisible(); +void SetMyDetailsFrameVisible(BOOL visible); +int ShowHideMenuFunc(WPARAM wParam, LPARAM lParam); +int ShowFrameFunc(WPARAM wParam, LPARAM lParam); +int HideFrameFunc(WPARAM wParam, LPARAM lParam); +int ShowHideFrameFunc(WPARAM wParam, LPARAM lParam); + + + +LRESULT CALLBACK FrameContainerWindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam); +LRESULT CALLBACK FrameWindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam); +void SetCycleTime(); +void SetCycleTime(HWND hwnd); +void SetStatusMessageRefreshTime(); +void SetStatusMessageRefreshTime(HWND hwnd); +int SettingsChangedHook(WPARAM wParam, LPARAM lParam); +int AvatarChangedHook(WPARAM wParam, LPARAM lParam); +int ProtoAckHook(WPARAM wParam, LPARAM lParam); +int SmileyAddOptionsChangedHook(WPARAM wParam,LPARAM lParam); +int ListeningtoEnableStateChangedHook(WPARAM wParam,LPARAM lParam); +int AccListChanged(WPARAM wParam, LPARAM lParam); + + +void ExternalRect(RECT &ret, const RECT r1, const RECT r2); +bool InsideRect(const POINT &p, const RECT &r); + + +int operator==(const RECT& left, const RECT& right) +{ + return left.left == right.left && left.right == right.right + && left.top == right.top && left.bottom == right.bottom; +} + +class ToolTipArea +{ +public: + ToolTipArea() : hwndTT(0), hwndParent(0) { memset(&rc, 0, sizeof(rc)); } + ~ToolTipArea() { removeTooltip(); } + + void createTooltip(HWND hwnd, const RECT &rc, const TCHAR *text) + { + if (text == NULL || text[0] == 0) + { + removeTooltip(); + return; + } + + this->text = text; + + if (this->rc == rc && hwndParent == hwnd && hwndTT != NULL) + return; + + removeTooltip(); + + this->rc = rc; + this->hwndParent = hwnd; + this->hwndTT = CreateTooltip(this->hwndParent, this->rc); + } + + void removeTooltip() + { + if (hwndTT == NULL) + return; + + DestroyWindow(hwndTT); + hwndTT = NULL; + hwndParent = NULL; + } + + const TCHAR * getTextFor(HWND hwndFrom) + { + if (hwndTT == NULL || hwndTT != hwndFrom) + return NULL; + return text.c_str(); + } + + +private: + + HWND hwndTT; + RECT rc; + HWND hwndParent; + std::tstring text; + + HWND CreateTooltip(HWND hwnd, RECT &rect) + { + // struct specifying control classes to register + INITCOMMONCONTROLSEX iccex; + HWND hwndTT; // handle to the ToolTip control + // struct specifying info about tool in ToolTip control + TOOLINFO ti; + unsigned int uid = 0; // for ti initialization + + // Load the ToolTip class from the DLL. + iccex.dwSize = sizeof(iccex); + iccex.dwICC = ICC_BAR_CLASSES; + + if(!InitCommonControlsEx(&iccex)) + return NULL; + + /* CREATE A TOOLTIP WINDOW */ + hwndTT = CreateWindowEx(WS_EX_TOPMOST, + TOOLTIPS_CLASS, + NULL, + WS_POPUP | TTS_NOPREFIX | TTS_ALWAYSTIP, + CW_USEDEFAULT, + CW_USEDEFAULT, + CW_USEDEFAULT, + CW_USEDEFAULT, + hwnd, + NULL, + hInst, + NULL + ); + + /* Gives problem with mToolTip + SetWindowPos(hwndTT, + HWND_TOPMOST, + 0, + 0, + 0, + 0, + SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE); + */ + + /* INITIALIZE MEMBERS OF THE TOOLINFO STRUCTURE */ + ti.cbSize = sizeof(TOOLINFO); + ti.uFlags = TTF_SUBCLASS; + ti.hwnd = hwnd; + ti.hinst = hInst; + ti.uId = uid; + ti.lpszText = LPSTR_TEXTCALLBACK; + // ToolTip control will cover the whole window + ti.rect.left = rect.left; + ti.rect.top = rect.top; + ti.rect.right = rect.right; + ti.rect.bottom = rect.bottom; + + /* SEND AN ADDTOOL MESSAGE TO THE TOOLTIP CONTROL WINDOW */ + SendMessage(hwndTT, TTM_ADDTOOL, 0, (LPARAM) (LPTOOLINFO) &ti); + SendMessage(hwndTT, TTM_SETDELAYTIME, (WPARAM) (DWORD) TTDT_AUTOPOP, (LPARAM) MAKELONG(24 * 60 * 60 * 1000, 0)); + + return hwndTT; + } +}; + + +struct SimpleItem +{ + RECT rc; + bool draw; + bool mouseOver; + ToolTipArea tt; + bool alignRight; + + SimpleItem() : draw(FALSE), mouseOver(FALSE), alignRight(FALSE) + { + memset(&rc, 0, sizeof(rc)); + } + virtual ~SimpleItem() {} + + virtual void hide() + { + draw = false; + mouseOver = false; + tt.removeTooltip(); + } + + virtual void update(HWND hwnd, SkinFieldState *item) + { + draw = item->isVisible(); + alignRight = ( item->getHorizontalAlign() == SKN_HALIGN_RIGHT ); + + if (draw) + { + rc = item->getRect(); + tt.createTooltip(hwnd, rc, item->getToolTip()); + } + else + { + tt.removeTooltip(); + } + } + + virtual bool hitTest(const POINT &p) + { + return draw && InsideRect(p, rc); + } + + virtual const TCHAR * getToolTipFor(HWND hwndFrom) + { + return tt.getTextFor(hwndFrom); + } + + bool setMouseOver(POINT *mousePos) + { + bool over = (mousePos != NULL && hitTest(*mousePos)); + + if (mouseOver == over) + return FALSE; + + mouseOver = over; + return TRUE; + } + +}; + +struct IconAndItem : public SimpleItem +{ + RECT rcIcon; + RECT rcItem; + BOOL drawIcon; + BOOL drawItem; + ToolTipArea ttIcon; + + IconAndItem() : drawIcon(FALSE), drawItem(FALSE) + { + memset(&rcIcon, 0, sizeof(rcIcon)); + memset(&rcItem, 0, sizeof(rcItem)); + } + virtual ~IconAndItem() {} + + virtual void hide() + { + SimpleItem::hide(); + drawIcon = FALSE; + drawItem = FALSE; + } + + virtual void update(HWND hwnd, SkinIconFieldState *icon, SkinTextFieldState *item) + { + drawIcon = icon->isVisible(); + drawItem = item->isVisible(); + alignRight = ( item->getHorizontalAlign() == SKN_HALIGN_RIGHT ); + + draw = drawIcon || drawItem; + if (draw) + { + if (drawIcon) + rcIcon = icon->getRect(); + if (drawItem) + rcItem = item->getRect(); + + if (drawIcon && drawItem) + ExternalRect(rc, rcIcon, rcItem); + else if (drawIcon) + rc = rcIcon; + else // if (drawItem) + rc = rcItem; + } + + if (drawItem) + tt.createTooltip(hwnd, rcItem, item->getToolTip()); + else + tt.removeTooltip(); + + if (drawIcon) + ttIcon.createTooltip(hwnd, rcIcon, icon->getToolTip()); + else + ttIcon.removeTooltip(); + } + + virtual const TCHAR * getToolTipFor(HWND hwndFrom) + { + const TCHAR * ret = tt.getTextFor(hwndFrom); + + if (ret == NULL) + ret = ttIcon.getTextFor(hwndFrom); + + return ret; + } +}; + + +struct MyDetailsFrameData +{ + std::vector items; + SimpleItem proto; + SimpleItem proto_cycle_next; + SimpleItem proto_cycle_prev; + SimpleItem avatar; + SimpleItem nick; + IconAndItem status; + SimpleItem away_msg; + IconAndItem listening_to; + IconAndItem email; + + bool showing_menu; + + bool tracking_exit; + + MyDetailsFrameData() + : showing_menu(false) + , tracking_exit(false) + { + items.push_back(&proto); + items.push_back(&proto_cycle_next); + items.push_back(&proto_cycle_prev); + items.push_back(&avatar); + items.push_back(&nick); + items.push_back(&status); + items.push_back(&away_msg); + items.push_back(&listening_to); + items.push_back(&email); + } +}; + + + +// Functions ////////////////////////////////////////////////////////////////////////////////////// + +void InitFrames() +{ + InitContactListSmileys(); + + CreateFrame(); + + HookEvent(ME_DB_CONTACT_SETTINGCHANGED, SettingsChangedHook); + HookEvent(ME_AV_MYAVATARCHANGED, AvatarChangedHook); + HookEvent(ME_PROTO_ACK, ProtoAckHook); + HookEvent(ME_SMILEYADD_OPTIONSCHANGED,SmileyAddOptionsChangedHook); + HookEvent(ME_LISTENINGTO_ENABLE_STATE_CHANGED,ListeningtoEnableStateChangedHook); + HookEvent(ME_PROTO_ACCLISTCHANGED, AccListChanged); +} + + +void DeInitFrames() +{ + if(ServiceExists(MS_CLIST_FRAMES_REMOVEFRAME) && frame_id != -1) + { + CallService(MS_CLIST_FRAMES_REMOVEFRAME, (WPARAM)frame_id, 0); + } + + if (hwnd_frame != NULL) DestroyWindow(hwnd_frame); + if (hwnd_container != NULL) DestroyWindow(hwnd_container); +} + +int SmileyAddOptionsChangedHook(WPARAM wParam,LPARAM lParam) +{ + UpdateFrameData(); + return 0; +} + +int SkinEngineDrawCallback(HWND hWnd, HDC hDC, RECT * rcPaint, HRGN rgn, DWORD dFlags, void * CallBackData); + +int CreateFrame() +{ + WNDCLASS wndclass; + wndclass.style = CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW; //CS_PARENTDC | CS_HREDRAW | CS_VREDRAW; + wndclass.lpfnWndProc = FrameWindowProc; + wndclass.cbClsExtra = 0; + wndclass.cbWndExtra = 0; + wndclass.hInstance = hInst; + wndclass.hIcon = NULL; + wndclass.hCursor = LoadCursor (NULL, IDC_ARROW); + wndclass.hbrBackground = 0; //(HBRUSH)(COLOR_3DFACE+1); + wndclass.lpszMenuName = NULL; + wndclass.lpszClassName = WINDOW_CLASS_NAME; + RegisterClass(&wndclass); + + if (ServiceExists(MS_CLIST_FRAMES_ADDFRAME)) + { + hwnd_frame = CreateWindow(WINDOW_CLASS_NAME, Translate("My Details"), + WS_CHILD | WS_VISIBLE, + 0,0,10,10, (HWND)CallService(MS_CLUI_GETHWND, 0, 0), NULL, hInst, NULL); + + CLISTFrame Frame = {0}; + + Frame.cbSize = sizeof(Frame); + Frame.name = "My Details"; + Frame.TBname = Translate("My Details"); + Frame.hWnd = hwnd_frame; + Frame.align = alTop; + Frame.Flags = F_VISIBLE | F_SHOWTB | F_SHOWTBTIP | F_NOBORDER | F_NO_SUBCONTAINER; + Frame.height = 100; + + frame_id = CallService(MS_CLIST_FRAMES_ADDFRAME, (WPARAM)&Frame, 0); + + if (ServiceExists(MS_SKINENG_REGISTERPAINTSUB)) + { + CallService(MS_BACKGROUNDCONFIG_REGISTER,(WPARAM)"My Details Background/MyDetails", 0); + CallService(MS_SKINENG_REGISTERPAINTSUB, (WPARAM) Frame.hWnd, (LPARAM) SkinEngineDrawCallback); + } + + if (DBGetContactSettingByte(NULL, "MyDetails", "ForceHideFrame", 0)) + { + int flags = CallService(MS_CLIST_FRAMES_GETFRAMEOPTIONS, MAKEWPARAM(FO_FLAGS, frame_id), 0); + if(flags & F_VISIBLE) + CallService(MS_CLIST_FRAMES_SHFRAME, frame_id, 0); + + DBDeleteContactSetting(NULL, "MyDetails", "ForceHideFrame"); + } + + if (DBGetContactSettingByte(NULL, "MyDetails", "ForceShowFrame", 0)) + { + int flags = CallService(MS_CLIST_FRAMES_GETFRAMEOPTIONS, MAKEWPARAM(FO_FLAGS, frame_id), 0); + if(!(flags & F_VISIBLE)) + CallService(MS_CLIST_FRAMES_SHFRAME, frame_id, 0); + + DBDeleteContactSetting(NULL, "MyDetails", "ForceShowFrame"); + } + } + else + { + wndclass.style = CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW;//CS_HREDRAW | CS_VREDRAW; + wndclass.lpfnWndProc = FrameContainerWindowProc; + wndclass.cbClsExtra = 0; + wndclass.cbWndExtra = 0; + wndclass.hInstance = hInst; + wndclass.hIcon = NULL; + wndclass.hCursor = LoadCursor (NULL, IDC_ARROW); + wndclass.hbrBackground = 0; //(HBRUSH)(COLOR_3DFACE+1); + wndclass.lpszMenuName = NULL; + wndclass.lpszClassName = CONTAINER_CLASS_NAME; + RegisterClass(&wndclass); + + hwnd_container = CreateWindowEx(WS_EX_TOOLWINDOW, CONTAINER_CLASS_NAME, Translate("My Details"), + (WS_THICKFRAME | WS_CAPTION | WS_SYSMENU) & ~WS_VISIBLE, + 0,0,200,130, (HWND)CallService(MS_CLUI_GETHWND, 0, 0), NULL, hInst, NULL); + + hwnd_frame = CreateWindow(WINDOW_CLASS_NAME, Translate("My Details"), + WS_CHILD | WS_VISIBLE, + 0,0,10,10, hwnd_container, NULL, hInst, NULL); + + SetWindowLong(hwnd_container, GWL_USERDATA, (LONG)hwnd_frame); + SendMessage(hwnd_container, WM_SIZE, 0, 0); + + // Create menu item + + CLISTMENUITEM menu = {0}; + + menu.cbSize=sizeof(menu); + menu.flags = CMIM_ALL; + menu.popupPosition = -0x7FFFFFFF; + menu.pszPopupName = Translate("My Details"); + menu.position = 1; // 500010000 + menu.hIcon = LoadSkinnedIcon(SKINICON_OTHER_MIRANDA); + menu.pszName = Translate("Show My Details"); + menu.pszService= MODULE_NAME "/ShowHideMyDetails"; + hMenuShowHideFrame = (HANDLE)CallService(MS_CLIST_ADDMAINMENUITEM, 0, (LPARAM)&menu); + + if(DBGetContactSettingByte(0, MODULE_NAME, SETTING_FRAME_VISIBLE, 1) == 1) + { + ShowWindow(hwnd_container, SW_SHOW); + FixMainMenu(); + } + } + + CreateServiceFunction(MS_MYDETAILS_SHOWFRAME, ShowFrameFunc); + CreateServiceFunction(MS_MYDETAILS_HIDEFRAME, HideFrameFunc); + CreateServiceFunction(MS_MYDETAILS_SHOWHIDEFRAME, ShowHideFrameFunc); + + return 0; +} + + +BOOL FrameIsFloating() +{ + if (frame_id == -1) + { + return true; // no frames, always floating + } + + return (CallService(MS_CLIST_FRAMES_GETFRAMEOPTIONS, MAKEWPARAM(FO_FLOATING, frame_id), 0) != 0); +} + + +LRESULT CALLBACK FrameContainerWindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { + switch(msg) + { + case WM_SHOWWINDOW: + { + if ((BOOL)wParam) + Utils_RestoreWindowPosition(hwnd, 0, MODULE_NAME, WINDOW_NAME_PREFIX); + else + Utils_SaveWindowPosition(hwnd, 0, MODULE_NAME, WINDOW_NAME_PREFIX); + break; + } + + case WM_ERASEBKGND: + { + HWND child = (HWND)GetWindowLong(hwnd, GWL_USERDATA); + + SendMessage(child, WM_ERASEBKGND, wParam, lParam); + break; + } + + case WM_SIZE: + { + HWND child = (HWND)GetWindowLong(hwnd, GWL_USERDATA); + RECT r; + GetClientRect(hwnd, &r); + + SetWindowPos(child, 0, r.left, r.top, r.right - r.left, r.bottom - r.top, SWP_NOZORDER | SWP_NOACTIVATE); + InvalidateRect(child, NULL, TRUE); + + return TRUE; + } + + case WM_CLOSE: + { + DBWriteContactSettingByte(0, MODULE_NAME, SETTING_FRAME_VISIBLE, 0); + ShowWindow(hwnd, SW_HIDE); + FixMainMenu(); + return TRUE; + } + } + + return DefWindowProc(hwnd, msg, wParam, lParam); +} + + + +BOOL ScreenToClient(HWND hWnd, LPRECT lpRect) +{ + BOOL ret; + + POINT pt; + + pt.x = lpRect->left; + pt.y = lpRect->top; + + ret = ScreenToClient(hWnd, &pt); + + if (!ret) return ret; + + lpRect->left = pt.x; + lpRect->top = pt.y; + + + pt.x = lpRect->right; + pt.y = lpRect->bottom; + + ret = ScreenToClient(hWnd, &pt); + + lpRect->right = pt.x; + lpRect->bottom = pt.y; + + return ret; +} + + +BOOL MoveWindow(HWND hWnd, const RECT &rect, BOOL bRepaint) +{ + return MoveWindow(hWnd, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, bRepaint); +} + + +RECT GetInnerRect(const RECT &rc, const RECT &clipping) +{ + RECT rc_ret = rc; + + rc_ret.left = max(rc.left, clipping.left); + rc_ret.top = max(rc.top, clipping.top); + rc_ret.right = min(rc.right, clipping.right); + rc_ret.bottom = min(rc.bottom, clipping.bottom); + + return rc_ret; +} + + + + + +void ExternalRect(RECT &ret, const RECT r1, const RECT r2) +{ + ret.left = min(r1.left, r2.left); + ret.right = max(r1.right, r2.right); + ret.top = min(r1.top, r2.top); + ret.bottom = max(r1.bottom, r2.bottom); +} + + +HBITMAP CreateBitmap32(int cx, int cy) +{ + BITMAPINFO RGB32BitsBITMAPINFO; + UINT * ptPixels; + HBITMAP DirectBitmap; + + ZeroMemory(&RGB32BitsBITMAPINFO,sizeof(BITMAPINFO)); + RGB32BitsBITMAPINFO.bmiHeader.biSize=sizeof(BITMAPINFOHEADER); + RGB32BitsBITMAPINFO.bmiHeader.biWidth=cx;//bm.bmWidth; + RGB32BitsBITMAPINFO.bmiHeader.biHeight=cy;//bm.bmHeight; + RGB32BitsBITMAPINFO.bmiHeader.biPlanes=1; + RGB32BitsBITMAPINFO.bmiHeader.biBitCount=32; + + DirectBitmap = CreateDIBSection(NULL, + (BITMAPINFO *)&RGB32BitsBITMAPINFO, + DIB_RGB_COLORS, + (void **)&ptPixels, + NULL, 0); + return DirectBitmap; +} + + +BOOL UseLayeredMode() +{ + return isLayeredEnabled() && !FrameIsFloating(); +} + + +void EraseBackground(HWND hwnd, HDC hdc) +{ + RECT r; + GetClientRect(hwnd, &r); + + if (isSkinEngineEnabled()) + { + if (FrameIsFloating()) + { + HBRUSH hB = CreateSolidBrush(opts.bkg_color); + FillRect(hdc, &r, hB); + DeleteObject(hB); + } + else + { + SkinDrawWindowBack(hwnd, hdc, &r, "Main,ID=Background"); + } + + SkinDrawGlyph(hdc, &r, &r,"MyDetails,ID=Background"); + } + else + { + HBRUSH hB = CreateSolidBrush(opts.bkg_color); + FillRect(hdc, &r, hB); + DeleteObject(hB); + } +} + +static int Width(const RECT &rc) +{ + return rc.right - rc.left; +} + +static int Height(const RECT &rc) +{ + return rc.bottom - rc.top; +} + +static HICON CreateOverlayedIcon(HICON icon, HICON overlay) +{ + HIMAGELIST il = ImageList_Create( + GetSystemMetrics(SM_CXICON), + GetSystemMetrics(SM_CYICON), + ILC_COLOR32|ILC_MASK, 2, 2); + ImageList_AddIcon(il, icon); + ImageList_AddIcon(il, overlay); + HIMAGELIST newImage = ImageList_Merge(il,0,il,1,0,0); + ImageList_Destroy(il); + HICON hIcon = ImageList_GetIcon(newImage, 0, 0); + ImageList_Destroy(newImage); + return hIcon; // the result should be destroyed by DestroyIcon() +} + +void Draw(HDC hdc, SkinIconFieldState &state) +{ + if (!state.isVisible()) + return; + + RECT rc = state.getInsideRect(); + HRGN rgn = CreateRectRgnIndirect(&rc); + SelectClipRgn(hdc, rgn); + + rc = state.getInsideRect(true); + + skin_DrawIconEx(hdc, rc.left, rc.top, state.getIcon(), Width(rc), Height(rc), 0, NULL, DI_NORMAL); + + SelectClipRgn(hdc, NULL); + DeleteObject(rgn); +} + +void Draw(HDC hdc, SkinTextFieldState &state, BOOL replace_smileys = FALSE, const char *protocol = NULL) +{ + if (!state.isVisible()) + return; + + RECT rc = state.getInsideRect(); + HRGN rgn = CreateRectRgnIndirect(&rc); + SelectClipRgn(hdc, rgn); + + HGDIOBJ oldFont = SelectObject(hdc, state.getFont()); + COLORREF oldColor = SetTextColor(hdc, state.getFontColor()); + + UINT uFormat = DT_NOPREFIX | DT_END_ELLIPSIS | (opts.draw_text_rtl ? DT_RTLREADING : 0); + + switch(state.getHorizontalAlign()) + { + case SKN_HALIGN_RIGHT: + uFormat |= DT_RIGHT; + break; + case SKN_HALIGN_CENTER: + uFormat |= DT_CENTER; + break; + case SKN_HALIGN_LEFT: + uFormat |= DT_LEFT; + break; + } + + if (replace_smileys && opts.replace_smileys) + { + uFormat |= DT_SINGLELINE; + + // Draw only first line of text + char *tmp = strdup(state.getText()); + char *pos = strchr(tmp, '\r'); + if (pos != NULL) + pos[0] = '\0'; + pos = strchr(tmp, '\n'); + if (pos != NULL) + pos[0] = '\0'; + + Smileys_DrawText(hdc, tmp, -1, &rc, uFormat | (opts.resize_smileys ? DT_RESIZE_SMILEYS : 0), + opts.use_contact_list_smileys ? "clist" : protocol, NULL); + } + else + { + skin_DrawText(hdc, state.getText(), -1, &rc, uFormat); + } + + + SelectObject(hdc, oldFont); + SetTextColor(hdc, oldColor); + + SelectClipRgn(hdc, NULL); + DeleteObject(rgn); +} + + +void DrawMouseOver(HDC hdc, RECT *lprc, const char *place) +{ + if (isSkinEngineEnabled()) + { + SkinDrawGlyph(hdc, lprc, lprc, "MyDetails,ID=MouseOver"); + + char glyph[1024]; + mir_snprintf(glyph, MAX_REGS(glyph), "MyDetails,ID=MouseOver%s", place); + SkinDrawGlyph(hdc, lprc, lprc, glyph); + } + else + { + FrameRect(hdc, lprc, (HBRUSH) GetStockObject(GRAY_BRUSH)); + } +} + + +void Draw(HWND hwnd, HDC hdc_orig) +{ + MyDetailsFrameData *data = (MyDetailsFrameData *) GetWindowLong(hwnd, GWL_USERDATA); + + Protocol *proto = GetCurrentProtocol(); + if (proto == NULL) + { + EraseBackground(hwnd, hdc_orig); + return; + } + + if (ServiceExists(MS_CLIST_FRAMES_SETFRAMEOPTIONS) && frame_id != -1) + { + int flags = CallService(MS_CLIST_FRAMES_GETFRAMEOPTIONS, MAKEWPARAM(FO_FLAGS, frame_id), 0); + if(flags & F_UNCOLLAPSED) + { + RECT rf; + GetClientRect(hwnd, &rf); + + if (rf.bottom - rf.top != 0) + { + if (FrameIsFloating()) + { + HWND parent = GetParent(hwnd); + + if (parent != NULL) + { + RECT rp_client, rp_window, r_window; + GetClientRect(parent, &rp_client); + GetWindowRect(parent, &rp_window); + GetWindowRect(hwnd, &r_window); + int diff = (rp_window.bottom - rp_window.top) - (rp_client.bottom - rp_client.top); + if(ServiceExists(MS_CLIST_FRAMES_ADDFRAME)) + diff += (r_window.top - rp_window.top); + + SetWindowPos(parent, 0, 0, 0, rp_window.right - rp_window.left, diff, SWP_NOZORDER | SWP_NOMOVE | SWP_NOACTIVATE); + } + } + } + + for (size_t i = 0; i < data->items.size(); ++i) + data->items[i]->hide(); + + return; + } + } + + + RECT r_full; + GetClientRect(hwnd, &r_full); + + HDC hdc; + HBITMAP hBmp; + BOOL useLayeredMode = UseLayeredMode(); + if (useLayeredMode) + { + hdc = hdc_orig; + hBmp = NULL; + } + else + { + hdc = CreateCompatibleDC(hdc_orig); + hBmp = CreateBitmap32(Width(r_full), Height(r_full)); + SelectObject(hdc, hBmp); + } + + int old_bk_mode = SetBkMode(hdc, TRANSPARENT); + HFONT old_font = (HFONT) GetCurrentObject(hdc, OBJ_FONT); + COLORREF old_color = GetTextColor(hdc); + SetStretchBltMode(hdc, HALFTONE); + + + HICON hStatusIcon; + bool freeStatusIcon = false; + if (proto->GetCustomStatus() != 0 && proto->CanCall(PS_ICQ_GETCUSTOMSTATUSICON)) + hStatusIcon = (HICON) proto->Call(PS_ICQ_GETCUSTOMSTATUSICON, proto->GetCustomStatus(), LR_SHARED); + else + hStatusIcon = LoadSkinnedProtoIcon(proto->GetName(), proto->GetStatus()); + + if (proto->IsLocked()) + { + HICON hLockOverlay = LoadSkinnedIcon(SKINICON_OTHER_STATUS_LOCKED); + if (hLockOverlay != NULL) + { + freeStatusIcon = true; + hStatusIcon = CreateOverlayedIcon(hStatusIcon, hLockOverlay); + } + } + + + HICON hListeningIcon = IcoLib_LoadIcon("LISTENING_TO_ICON"); + HICON hEmailIcon = IcoLib_LoadIcon("MYDETAILS_EMAIL"); + HICON hNextIcon = IcoLib_LoadIcon("MYDETAILS_NEXT_PROTOCOL"); + HICON hPrevIcon = IcoLib_LoadIcon("MYDETAILS_PREV_PROTOCOL"); + + { + dialog->setInfoBool("resize_frame", opts.resize_frame); + dialog->setInfoBool("protocol.locked", proto->IsLocked()); + + + if (opts.resize_frame) + dialog->setSize(Width(r_full), 0x1FFFFFFF); + else + dialog->setSize(Width(r_full), Height(r_full)); + + + + SkinImageField avatar = dialog->getImageField("avatar"); + if (proto->CanGetAvatar() && proto->GetAvatarImage() != NULL) + { + avatar.setEnabled(TRUE); + avatar.setImage(proto->GetAvatarImage()); + } + else + { + avatar.setEnabled(FALSE); + avatar.setImage(NULL); + } + + SkinTextField nickname = dialog->getTextField("nickname"); + nickname.setText(proto->GetNick()); + + SkinTextField protocol = dialog->getTextField("protocol"); + protocol.setText(proto->GetDescription()); + + SkinIconField status_icon = dialog->getIconField("status_icon"); + status_icon.setIcon(hStatusIcon); + + SkinTextField status_name = dialog->getTextField("status_name"); + status_name.setText(proto->GetStatusName()); + + SkinTextField status_msg = dialog->getTextField("status_msg"); + if (proto->CanGetStatusMsg()) + { + status_msg.setEnabled(TRUE); + status_msg.setText(proto->GetStatusMsg()); + } + else + { + status_msg.setEnabled(FALSE); + status_msg.setText(_T("")); + } + + SkinIconField listening_icon = dialog->getIconField("listening_icon"); + SkinTextField listening = dialog->getTextField("listening"); + if (proto->ListeningToEnabled() && proto->GetStatus() > ID_STATUS_OFFLINE + && proto->GetListeningTo()[0] != 0) + { + listening_icon.setEnabled(TRUE); + listening.setEnabled(TRUE); + listening_icon.setIcon(hListeningIcon); + listening.setText(proto->GetListeningTo()); + } + else + { + listening_icon.setEnabled(FALSE); + listening.setEnabled(FALSE); + listening_icon.setIcon(NULL); + listening.setText(_T("")); + } + + SkinIconField email_icon = dialog->getIconField("email_icon"); + SkinTextField email = dialog->getTextField("email"); + if (proto->CanGetEmailCount()) + { + email_icon.setEnabled(TRUE); + email.setEnabled(TRUE); + email_icon.setIcon(hEmailIcon); + + TCHAR tmp[64]; + _sntprintf(tmp, MAX_REGS(tmp), _T("%d"), proto->GetEmailCount()); + email.setText(tmp); + } + else + { + email_icon.setEnabled(FALSE); + email.setEnabled(FALSE); + email_icon.setIcon(NULL); + email.setText(_T("")); + } + + SkinIconField next_proto = dialog->getIconField("next_proto"); + SkinIconField prev_proto = dialog->getIconField("prev_proto"); + prev_proto.setIcon(hPrevIcon); + next_proto.setIcon(hNextIcon); + } + + SkinDialogState state = dialog->run(); + SkinImageFieldState avatar = state.getImageField("avatar"); + SkinTextFieldState nickname = state.getTextField("nickname"); + SkinTextFieldState protocol = state.getTextField("protocol"); + SkinIconFieldState status_icon = state.getIconField("status_icon"); + SkinTextFieldState status_name = state.getTextField("status_name"); + SkinTextFieldState status_msg = state.getTextField("status_msg"); + SkinIconFieldState listening_icon = state.getIconField("listening_icon"); + SkinTextFieldState listening = state.getTextField("listening"); + SkinIconFieldState email_icon = state.getIconField("email_icon"); + SkinTextFieldState email = state.getTextField("email"); + SkinIconFieldState next_proto = state.getIconField("next_proto"); + SkinIconFieldState prev_proto = state.getIconField("prev_proto"); + + + { + data->proto.update(hwnd, &protocol); + data->proto_cycle_next.update(hwnd, &next_proto); + data->proto_cycle_prev.update(hwnd, &prev_proto); + data->avatar.update(hwnd, &avatar); + data->nick.update(hwnd, &nickname); + data->status.update(hwnd, &status_icon, &status_name); + data->away_msg.update(hwnd, &status_msg); + data->listening_to.update(hwnd, &listening_icon, &listening); + data->email.update(hwnd, &email_icon, &email); + + + POINT p = {0}; + GetCursorPos(&p); + ScreenToClient(hwnd, &p); + + for(size_t i = 0; i < data->items.size(); ++i) + data->items[i]->setMouseOver(&p); + } + + // Erase + EraseBackground(hwnd, hdc); + + // Draw items + + UINT uFormat = DT_SINGLELINE | DT_NOPREFIX | DT_END_ELLIPSIS + | (opts.draw_text_rtl ? DT_RTLREADING : 0); + + // Image + if (avatar.isVisible() && proto->CanGetAvatar() && proto->GetAvatarImage() != NULL) + { + RECT rc = avatar.getInsideRect(); + HRGN rgn = CreateRectRgnIndirect(&rc); + SelectClipRgn(hdc, rgn); + + rc = avatar.getInsideRect(true); + + int width = Width(rc); + int height = Height(rc); + + int round_radius; + if (opts.draw_avatar_round_corner) + { + if (opts.draw_avatar_use_custom_corner_size) + round_radius = opts.draw_avatar_custom_corner_size; + else + round_radius = min(width, height) / 6; + } + else + { + round_radius = 0; + } + + + AVATARDRAWREQUEST adr = {0}; + + adr.cbSize = sizeof(AVATARDRAWREQUEST); + adr.hTargetDC = hdc; + adr.rcDraw = rc; + + adr.dwFlags = AVDRQ_OWNPIC | AVDRQ_HIDEBORDERONTRANSPARENCY | + (opts.draw_avatar_border ? AVDRQ_DRAWBORDER : 0 ) | + (opts.draw_avatar_round_corner ? AVDRQ_ROUNDEDCORNER : 0 ); + + if (useLayeredMode) + adr.dwFlags |= AVDRQ_AERO; + + adr.clrBorder = opts.draw_avatar_border_color; + adr.radius = round_radius; + adr.alpha = 255; + adr.szProto = (char *) proto->GetName(); + + CallService(MS_AV_DRAWAVATAR, 0, (LPARAM) &adr); + + // Clipping rgn + SelectClipRgn(hdc, NULL); + DeleteObject(rgn); + } + + // Nick + if (data->nick.draw && data->nick.mouseOver && proto->CanSetNick()) + DrawMouseOver(hdc, &nickname.getRect(), "Nick"); + + Draw(hdc, nickname, TRUE, proto->GetName()); + + + // Protocol + if (data->proto.draw && data->proto.mouseOver) + DrawMouseOver(hdc, &data->proto.rc, "Proto"); + + Draw(hdc, protocol); + + + // Status + if (data->status.draw && data->status.mouseOver) + DrawMouseOver(hdc, &data->status.rc, "Status"); + + Draw(hdc, status_icon); + Draw(hdc, status_name); + + + // Away message + if (data->away_msg.draw && data->away_msg.mouseOver && proto->CanSetStatusMsg()) + DrawMouseOver(hdc, &data->away_msg.rc, "StatusMsg"); + + Draw(hdc, status_msg, TRUE, proto->GetName()); + + + // Listening to + Draw(hdc, listening_icon); + Draw(hdc, listening); + + if (data->listening_to.draw && data->listening_to.mouseOver && protocols->CanSetListeningTo()) + DrawMouseOver(hdc, &data->listening_to.rc, "Listening"); + + + // Unread email count + Draw(hdc, email_icon); + Draw(hdc, email); + + // Protocol cycle icon + Draw(hdc, next_proto); + Draw(hdc, prev_proto); + + + SelectObject(hdc, old_font); + SetTextColor(hdc, old_color); + SetBkMode(hdc, old_bk_mode); + + if (!useLayeredMode) + { + BitBlt(hdc_orig, r_full.left, r_full.top, r_full.right - r_full.left, + r_full.bottom - r_full.top, hdc, r_full.left, r_full.top, SRCCOPY); + DeleteDC(hdc); + DeleteObject(hBmp); + } + + if (freeStatusIcon) + DestroyIcon(hStatusIcon); + IcoLib_ReleaseIcon(hListeningIcon); + IcoLib_ReleaseIcon(hEmailIcon); + IcoLib_ReleaseIcon(hPrevIcon); + IcoLib_ReleaseIcon(hNextIcon); + + if (opts.resize_frame && ServiceExists(MS_CLIST_FRAMES_SETFRAMEOPTIONS) && frame_id != -1) + { + RECT rf; + GetClientRect(hwnd, &rf); + + int currentSize = Height(r_full); + + int expectedSize = 0; + for(size_t i = 0; i < data->items.size(); ++i) + { + SimpleItem *item = data->items[i]; + if (!item->draw) + continue; + + expectedSize = max(expectedSize, item->rc.bottom); + } + expectedSize += state.getBorders().bottom; + + if (expectedSize != currentSize) + { + if (FrameIsFloating()) + { + HWND parent = GetParent(hwnd); + + if (parent != NULL) + { + RECT rp_client, rp_window, r_window; + GetClientRect(parent, &rp_client); + GetWindowRect(parent, &rp_window); + GetWindowRect(hwnd, &r_window); + int diff = (rp_window.bottom - rp_window.top) - (rp_client.bottom - rp_client.top); + if(ServiceExists(MS_CLIST_FRAMES_ADDFRAME)) + diff += (r_window.top - rp_window.top); + + SetWindowPos(parent, 0, 0, 0, rp_window.right - rp_window.left, expectedSize + diff, SWP_NOZORDER | SWP_NOMOVE | SWP_NOACTIVATE); + } + } + else if (IsWindowVisible(hwnd) && ServiceExists(MS_CLIST_FRAMES_ADDFRAME)) + { + int flags = CallService(MS_CLIST_FRAMES_GETFRAMEOPTIONS, MAKEWPARAM(FO_FLAGS, frame_id), 0); + if(flags & F_VISIBLE) + { + CallService(MS_CLIST_FRAMES_SETFRAMEOPTIONS, MAKEWPARAM(FO_HEIGHT, frame_id), (LPARAM) expectedSize); + CallService(MS_CLIST_FRAMES_UPDATEFRAME, (WPARAM)frame_id, (LPARAM)(FU_TBREDRAW | FU_FMREDRAW | FU_FMPOS)); + } + } + } + } +} + +int SkinEngineDrawCallback(HWND hWnd, HDC hDC, RECT * rcPaint, HRGN rgn, DWORD dFlags, void * CallBackData) +{ + Draw(hWnd, hDC); + return 0; +} + +bool InsideRect(const POINT &p, const RECT &r) +{ + return p.x >= r.left && p.x < r.right && p.y >= r.top && p.y < r.bottom; +} + +int ShowPopupMenu(HWND hwnd, HMENU submenu, SimpleItem &item) +{ + POINT p; + if (item.alignRight) + p.x = item.rc.right; + else + p.x = item.rc.left; + p.y = item.rc.bottom+1; + ClientToScreen(hwnd, &p); + + return TrackPopupMenu(submenu, TPM_TOPALIGN|TPM_RIGHTBUTTON|TPM_RETURNCMD + | (item.alignRight ? TPM_RIGHTALIGN : TPM_LEFTALIGN), p.x, p.y, 0, hwnd, NULL); +} + + +void ShowGlobalStatusMenu(HWND hwnd, MyDetailsFrameData *data, Protocol *proto, POINT &p) +{ + HMENU submenu = (HMENU) CallService(MS_CLIST_MENUGETSTATUS,0,0); + + int ret = ShowPopupMenu(hwnd, submenu, data->status); + if(ret) + CallService(MS_CLIST_MENUPROCESSCOMMAND, MAKEWPARAM(LOWORD(ret),MPCF_MAINMENU),(LPARAM)NULL); +} + +void ShowProtocolStatusMenu(HWND hwnd, MyDetailsFrameData *data, Protocol *proto, POINT &p) +{ + HMENU menu = (HMENU) CallService(MS_CLIST_MENUGETSTATUS,0,0); + HMENU submenu = NULL; + + if (menu != NULL) + { + // Find the correct menu item + int count = GetMenuItemCount(menu); + for (int i = 0 ; i < count && submenu == NULL; i++) + { + MENUITEMINFO mii = {0}; + + mii.cbSize = sizeof(mii); + + if(!IsWinVer98Plus()) + { + mii.fMask = MIIM_TYPE; + } + else + { + mii.fMask = MIIM_STRING; + } + + GetMenuItemInfo(menu, i, TRUE, &mii); + + if (mii.cch != 0) + { + mii.cch++; + mii.dwTypeData = (char *)malloc(sizeof(char) * mii.cch); + GetMenuItemInfo(menu, i, TRUE, &mii); + + if (strcmp(mii.dwTypeData, proto->GetDescription()) == 0) + { + submenu = GetSubMenu(menu, i); + } + + free(mii.dwTypeData); + } + } + + if (submenu == NULL && GetNumProtocols() == 1) + { + submenu = menu; + } + } + + if (submenu != NULL) + { + int ret = ShowPopupMenu(hwnd, submenu, data->status); + if(ret) + CallService(MS_CLIST_MENUPROCESSCOMMAND, MAKEWPARAM(LOWORD(ret),MPCF_MAINMENU),(LPARAM)NULL); + } + else + { + // Well, lets do it by hand + static int statusModePf2List[]={0xFFFFFFFF,PF2_ONLINE,PF2_SHORTAWAY,PF2_LONGAWAY,PF2_LIGHTDND,PF2_HEAVYDND,PF2_FREECHAT,PF2_INVISIBLE,PF2_ONTHEPHONE,PF2_OUTTOLUNCH}; + + menu = LoadMenu(hInst, MAKEINTRESOURCE(IDR_MENU1)); + submenu = GetSubMenu(menu, 0); + CallService(MS_LANGPACK_TRANSLATEMENU,(WPARAM)submenu,0); + + DWORD flags = proto->Call(PS_GETCAPS, PFLAGNUM_2); + for ( int i = GetMenuItemCount(submenu) -1 ; i >= 0 ; i-- ) + { + if (!(flags & statusModePf2List[i])) + { + // Hide menu + RemoveMenu(submenu, i, MF_BYPOSITION); + } + } + + int ret = ShowPopupMenu(hwnd, submenu, data->status); + DestroyMenu(menu); + + if(ret) + proto->SetStatus(ret); + } +} + +void ShowListeningToMenu(HWND hwnd, MyDetailsFrameData *data, Protocol *proto, POINT &p) +{ + HMENU menu = LoadMenu(hInst, MAKEINTRESOURCE(IDR_MENU1)); + HMENU submenu = GetSubMenu(menu, 5); + CallService(MS_LANGPACK_TRANSLATEMENU,(WPARAM)submenu,0); + + // Add this proto to menu + char tmp[128]; + mir_snprintf(tmp, sizeof(tmp), Translate("Enable Listening To for %s"), proto->GetDescription()); + + MENUITEMINFO mii = {0}; + mii.cbSize = sizeof(mii); + mii.fMask = MIIM_ID | MIIM_TYPE | MIIM_STATE; + mii.fType = MFT_STRING; + mii.fState = proto->ListeningToEnabled() ? MFS_CHECKED : 0; + mii.dwTypeData = tmp; + mii.cch = strlen(tmp); + mii.wID = 1; + + if (!proto->CanSetListeningTo()) + { + mii.fState |= MFS_DISABLED; + } + + InsertMenuItem(submenu, 0, TRUE, &mii); + + ZeroMemory(&mii, sizeof(mii)); + mii.cbSize = sizeof(mii); + mii.fMask = MIIM_STATE; + mii.fState = protocols->ListeningToEnabled() ? MFS_CHECKED : 0; + + if (!protocols->CanSetListeningTo()) + { + mii.fState |= MFS_DISABLED; + } + + SetMenuItemInfo(submenu, ID_LISTENINGTOPOPUP_SENDLISTENINGTO, FALSE, &mii); + + int ret = ShowPopupMenu(hwnd, submenu, data->listening_to); + + DestroyMenu(menu); + + switch(ret) + { + case 1: + { + CallService(MS_LISTENINGTO_ENABLE, (LPARAM) proto->GetName(), !proto->ListeningToEnabled()); + break; + } + case ID_LISTENINGTOPOPUP_SENDLISTENINGTO: + { + CallService(MS_LISTENINGTO_ENABLE, 0, !protocols->ListeningToEnabled()); + break; + } + } + +} + + +LRESULT CALLBACK FrameWindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ + switch(msg) + { + case WM_CREATE: + { + MyDetailsFrameData *data = new MyDetailsFrameData(); + SetWindowLong(hwnd, GWL_USERDATA, (LONG) data); + + SetCurrentProtocol(DBGetContactSettingWord(NULL, "MyDetails", "ProtocolNumber", 0)); + + SetCycleTime(hwnd); + + SetStatusMessageRefreshTime(hwnd); + + return TRUE; + } + + + case WM_ERASEBKGND: + { + //EraseBackground(hwnd, (HDC)wParam); + //Draw(hwnd, (HDC)wParam); + return TRUE; + } + + /* + case WM_PRINTCLIENT: + { + Draw(hwnd, (HDC)wParam); + return TRUE; + } + */ + + case WM_PAINT: + { + if (UseLayeredMode()) + { + CallService(MS_SKINENG_INVALIDATEFRAMEIMAGE, (WPARAM) hwnd, 0); + ValidateRect(hwnd, NULL); + } + else + { + RECT r; + if(GetUpdateRect(hwnd, &r, FALSE)) + { + PAINTSTRUCT ps; + + HDC hdc = BeginPaint(hwnd, &ps); + Draw(hwnd, hdc); + EndPaint(hwnd, &ps); + } + } + + return TRUE; + } + + case WM_SIZE: + { + //InvalidateRect(hwnd, NULL, FALSE); + MyDetailsFrameData *data = (MyDetailsFrameData *)GetWindowLong(hwnd, GWL_USERDATA); + RedrawFrame(); + break; + } + + case WM_TIMER: + { + MyDetailsFrameData *data = (MyDetailsFrameData *)GetWindowLong(hwnd, GWL_USERDATA); + + if (wParam == ID_FRAME_TIMER) + { + if (!data->showing_menu) + CallService(MS_MYDETAILS_SHOWNEXTPROTOCOL, 0, 0); + } + else if (wParam == ID_RECALC_TIMER) + { + KillTimer(hwnd, ID_RECALC_TIMER); + + PostMessage(hwnd, MWM_REFRESH_DATA, 0, 0); + } + else if (wParam == ID_STATUSMESSAGE_TIMER) + { + SetStatusMessageRefreshTime(hwnd); + + PostMessage(hwnd, MWM_REFRESH_DATA, 0, 0); + } + + return TRUE; + } + + case WM_LBUTTONUP: + { + MyDetailsFrameData *data = (MyDetailsFrameData *)GetWindowLong(hwnd, GWL_USERDATA); + Protocol *proto = GetCurrentProtocol(); + if (proto == NULL) + break; + + POINT p; + p.x = LOWORD(lParam); + p.y = HIWORD(lParam); + + // In proto cycle button? + if (data->proto_cycle_next.hitTest(p)) + { + CallService(MS_MYDETAILS_SHOWNEXTPROTOCOL, 0, 0); + } + else if (data->proto_cycle_prev.hitTest(p)) + { + CallService(MS_MYDETAILS_SHOWPREVIOUSPROTOCOL, 0, 0); + } + // In image? + else if (data->avatar.hitTest(p) && proto->CanSetAvatar()) + { + if (opts.global_on_avatar) + CallService(MS_MYDETAILS_SETMYAVATARUI, 0, 0); + else + CallService(MS_MYDETAILS_SETMYAVATARUI, 0, (LPARAM) proto->GetName()); + } + // In nick? + else if (data->nick.hitTest(p) && proto->CanSetNick()) + { + if (opts.global_on_nickname) + CallService(MS_MYDETAILS_SETMYNICKNAMEUI, 0, 0); + else + CallService(MS_MYDETAILS_SETMYNICKNAMEUI, 0, (LPARAM) proto->GetName()); + } + // In status message? + else if (data->away_msg.hitTest(p) && proto->CanSetStatusMsg()) + { + if (opts.global_on_status_message) + CallService(MS_MYDETAILS_SETMYSTATUSMESSAGEUI, 0, 0); + else + CallService(MS_MYDETAILS_SETMYSTATUSMESSAGEUI, 0, (LPARAM) proto->GetName()); + } + // In status? + else if (data->status.hitTest(p)) + { + data->showing_menu = true; + + if (opts.global_on_status) + ShowGlobalStatusMenu(hwnd, data, proto, p); + else + ShowProtocolStatusMenu(hwnd, data, proto, p); + + data->showing_menu = false; + } + // In listening to? + else if (data->listening_to.hitTest(p) && protocols->CanSetListeningTo()) + { + ShowListeningToMenu(hwnd, data, proto, p); + } + // In protocol? + else if (data->proto.hitTest(p)) + { + data->showing_menu = true; + + HMENU menu = CreatePopupMenu(); + + std::vector protos; + GetProtocols(&protos); + + int current = GetCurrentProtocolIndex(); + + int protosSize = (int) protos.size(); + for (int i = protosSize - 1 ; i >= 0 ; i--) + { + Protocol &proto = protos[i]; + + MENUITEMINFO mii = {0}; + mii.cbSize = sizeof(mii); + mii.fMask = MIIM_ID | MIIM_TYPE; + mii.fType = MFT_STRING; + mii.dwTypeData = (char *) proto.GetDescription(); + mii.cch = strlen(mii.dwTypeData); + mii.wID = i + 1; + + if (i == current) + { + mii.fMask |= MIIM_STATE; + mii.fState = MFS_DISABLED; + } + + InsertMenuItem(menu, 0, TRUE, &mii); + } + + int ret = ShowPopupMenu(hwnd, menu, data->proto); + + DestroyMenu(menu); + + if (ret != 0) + PluginCommand_ShowProtocol(NULL, (WPARAM) GetProtocolByIndex(ret - 1).GetName()); + + data->showing_menu = false; + } + + break; + } + + case WM_MEASUREITEM: + { + return CallService(MS_CLIST_MENUMEASUREITEM,wParam,lParam); + } + case WM_DRAWITEM: + { + return CallService(MS_CLIST_MENUDRAWITEM,wParam,lParam); + } + + case WM_CONTEXTMENU: + { + MyDetailsFrameData *data = (MyDetailsFrameData *)GetWindowLong(hwnd, GWL_USERDATA); + Protocol *proto = GetCurrentProtocol(); + if (proto == NULL) + break; + + POINT p; + p.x = LOWORD(lParam); + p.y = HIWORD(lParam); + + ScreenToClient(hwnd, &p); + + data->showing_menu = true; + + // In proto cycle button? + if (data->proto_cycle_next.hitTest(p)) + { + CallService(MS_MYDETAILS_SHOWPREVIOUSPROTOCOL, 0, 0); + } + else if (data->proto_cycle_prev.hitTest(p)) + { + CallService(MS_MYDETAILS_SHOWNEXTPROTOCOL, 0, 0); + } + // In image? + else if (data->avatar.hitTest(p)) + { + HMENU menu = LoadMenu(hInst, MAKEINTRESOURCE(IDR_MENU1)); + HMENU submenu = GetSubMenu(menu, 4); + CallService(MS_LANGPACK_TRANSLATEMENU,(WPARAM)submenu,0); + + // Add this proto to menu + char tmp[128]; + mir_snprintf(tmp, sizeof(tmp), Translate("Set My Avatar for %s..."), proto->GetDescription()); + + MENUITEMINFO mii = {0}; + mii.cbSize = sizeof(mii); + mii.fMask = MIIM_ID | MIIM_TYPE; + mii.fType = MFT_STRING; + mii.dwTypeData = tmp; + mii.cch = strlen(tmp); + mii.wID = 1; + + if (!proto->CanSetAvatar()) + { + mii.fMask |= MIIM_STATE; + mii.fState = MFS_DISABLED; + } + + InsertMenuItem(submenu, 0, TRUE, &mii); + + ClientToScreen(hwnd, &p); + + int ret = TrackPopupMenu(submenu, TPM_TOPALIGN|TPM_LEFTALIGN|TPM_RIGHTBUTTON|TPM_RETURNCMD, p.x, p.y, 0, hwnd, NULL); + DestroyMenu(menu); + + switch(ret) + { + case 1: + { + CallService(MS_MYDETAILS_SETMYAVATARUI, 0, (LPARAM) proto->GetName()); + break; + } + case ID_AVATARPOPUP_SETMYAVATAR: + { + CallService(MS_MYDETAILS_SETMYAVATARUI, 0, 0); + break; + } + } + } + // In nick? + else if (data->nick.hitTest(p)) + { + HMENU menu = LoadMenu(hInst, MAKEINTRESOURCE(IDR_MENU1)); + HMENU submenu = GetSubMenu(menu, 2); + CallService(MS_LANGPACK_TRANSLATEMENU,(WPARAM)submenu,0); + + // Add this proto to menu + char tmp[128]; + mir_snprintf(tmp, sizeof(tmp), Translate("Set My Nickname for %s..."), proto->GetDescription()); + + MENUITEMINFO mii = {0}; + mii.cbSize = sizeof(mii); + mii.fMask = MIIM_ID | MIIM_TYPE; + mii.fType = MFT_STRING; + mii.dwTypeData = tmp; + mii.cch = strlen(tmp); + mii.wID = 1; + + if (!proto->CanSetNick()) + { + mii.fMask |= MIIM_STATE; + mii.fState = MFS_DISABLED; + } + + InsertMenuItem(submenu, 0, TRUE, &mii); + + ClientToScreen(hwnd, &p); + + int ret = TrackPopupMenu(submenu, TPM_TOPALIGN|TPM_LEFTALIGN|TPM_RIGHTBUTTON|TPM_RETURNCMD, p.x, p.y, 0, hwnd, NULL); + DestroyMenu(menu); + + switch(ret) + { + case 1: + { + CallService(MS_MYDETAILS_SETMYNICKNAMEUI, 0, (LPARAM) proto->GetName()); + break; + } + case ID_NICKPOPUP_SETMYNICKNAME: + { + CallService(MS_MYDETAILS_SETMYNICKNAMEUI, 0, 0); + break; + } + } + } + // In status message? + else if (data->away_msg.hitTest(p)) + { + char tmp[128]; + + HMENU menu = LoadMenu(hInst, MAKEINTRESOURCE(IDR_MENU1)); + HMENU submenu = GetSubMenu(menu, 3); + CallService(MS_LANGPACK_TRANSLATEMENU,(WPARAM)submenu,0); + + // Add this proto to menu + mir_snprintf(tmp, sizeof(tmp), Translate("Set My Status Message for %s..."), + proto->GetDescription()); + + MENUITEMINFO mii = {0}; + mii.cbSize = sizeof(mii); + mii.fMask = MIIM_ID | MIIM_TYPE; + mii.fType = MFT_STRING; + mii.dwTypeData = tmp; + mii.cch = strlen(tmp); + mii.wID = 1; + + if (!proto->CanSetStatusMsg()) + { + mii.fMask |= MIIM_STATE; + mii.fState = MFS_DISABLED; + } + + InsertMenuItem(submenu, 0, TRUE, &mii); + + { + // Add this to menu + mir_snprintf(tmp, sizeof(tmp), Translate("Set My Status Message for %s..."), + CallService(MS_CLIST_GETSTATUSMODEDESCRIPTION, proto->GetStatus(), 0)); + + MENUITEMINFO mii = {0}; + mii.cbSize = sizeof(mii); + mii.fMask = MIIM_ID | MIIM_TYPE; + mii.fType = MFT_STRING; + mii.dwTypeData = tmp; + mii.cch = strlen(tmp); + mii.wID = 2; + + if (proto->GetStatus() == ID_STATUS_OFFLINE) + { + mii.fMask |= MIIM_STATE; + mii.fState = MFS_DISABLED; + } + + InsertMenuItem(submenu, 0, TRUE, &mii); + } + + ClientToScreen(hwnd, &p); + + int ret = TrackPopupMenu(submenu, TPM_TOPALIGN|TPM_LEFTALIGN|TPM_RIGHTBUTTON|TPM_RETURNCMD, p.x, p.y, 0, hwnd, NULL); + DestroyMenu(menu); + + switch(ret) + { + case 1: + { + CallService(MS_MYDETAILS_SETMYSTATUSMESSAGEUI, 0, (LPARAM) proto->GetName()); + break; + } + case 2: + { + CallService(MS_MYDETAILS_SETMYSTATUSMESSAGEUI, (WPARAM) proto->GetStatus(), 0); + break; + } + case ID_STATUSMESSAGEPOPUP_SETMYSTATUSMESSAGE: + { + CallService(MS_MYDETAILS_SETMYSTATUSMESSAGEUI, 0, 0); + break; + } + } + } + // In status? + else if (data->status.hitTest(p)) + { + if (opts.global_on_status) + ShowProtocolStatusMenu(hwnd, data, proto, p); + else + ShowGlobalStatusMenu(hwnd, data, proto, p); + } + // In listening to? + else if (data->listening_to.hitTest(p) && protocols->CanSetListeningTo()) + { + ShowListeningToMenu(hwnd, data, proto, p); + } + // In protocol? + else if (data->proto.hitTest(p)) + { + } + // Default context menu + else + { + HMENU menu = LoadMenu(hInst, MAKEINTRESOURCE(IDR_MENU1)); + HMENU submenu = GetSubMenu(menu, 1); + CallService(MS_LANGPACK_TRANSLATEMENU,(WPARAM)submenu,0); + + if (opts.cycle_through_protocols) + RemoveMenu(submenu, ID_CYCLE_THROUGH_PROTOS, MF_BYCOMMAND); + else + RemoveMenu(submenu, ID_DONT_CYCLE_THROUGH_PROTOS, MF_BYCOMMAND); + + // Add this proto to menu + char tmp[128]; + MENUITEMINFO mii = {0}; + + mir_snprintf(tmp, sizeof(tmp), Translate("Enable Listening To for %s"), proto->GetDescription()); + + ZeroMemory(&mii, sizeof(mii)); + mii.cbSize = sizeof(mii); + mii.fMask = MIIM_ID | MIIM_TYPE | MIIM_STATE; + mii.fType = MFT_STRING; + mii.fState = proto->ListeningToEnabled() ? MFS_CHECKED : 0; + mii.dwTypeData = tmp; + mii.cch = strlen(tmp); + mii.wID = 5; + + if (!proto->CanSetListeningTo()) + { + mii.fState |= MFS_DISABLED; + } + + InsertMenuItem(submenu, 0, TRUE, &mii); + + // Add this to menu + mir_snprintf(tmp, sizeof(tmp), Translate("Set My Status Message for %s..."), + CallService(MS_CLIST_GETSTATUSMODEDESCRIPTION, proto->GetStatus(), 0)); + + ZeroMemory(&mii, sizeof(mii)); + mii.cbSize = sizeof(mii); + mii.fMask = MIIM_ID | MIIM_TYPE; + mii.fType = MFT_STRING; + mii.dwTypeData = tmp; + mii.cch = strlen(tmp); + mii.wID = 4; + + if (proto->GetStatus() == ID_STATUS_OFFLINE) + { + mii.fMask |= MIIM_STATE; + mii.fState = MFS_DISABLED; + } + + InsertMenuItem(submenu, 0, TRUE, &mii); + + // Add this proto to menu + mir_snprintf(tmp, sizeof(tmp), Translate("Set My Status Message for %s..."), proto->GetDescription()); + + ZeroMemory(&mii, sizeof(mii)); + mii.cbSize = sizeof(mii); + mii.fMask = MIIM_ID | MIIM_TYPE; + mii.fType = MFT_STRING; + mii.dwTypeData = tmp; + mii.cch = strlen(tmp); + mii.wID = 3; + + if (!proto->CanSetStatusMsg()) + { + mii.fMask |= MIIM_STATE; + mii.fState = MFS_DISABLED; + } + + InsertMenuItem(submenu, 0, TRUE, &mii); + + mir_snprintf(tmp, sizeof(tmp), Translate("Set My Nickname for %s..."), proto->GetDescription()); + + ZeroMemory(&mii, sizeof(mii)); + mii.cbSize = sizeof(mii); + mii.fMask = MIIM_ID | MIIM_TYPE; + mii.fType = MFT_STRING; + mii.dwTypeData = tmp; + mii.cch = strlen(tmp); + mii.wID = 2; + + if (!proto->CanSetNick()) + { + mii.fMask |= MIIM_STATE; + mii.fState = MFS_DISABLED; + } + + InsertMenuItem(submenu, 0, TRUE, &mii); + + mir_snprintf(tmp, sizeof(tmp), Translate("Set My Avatar for %s..."), proto->GetDescription()); + + ZeroMemory(&mii, sizeof(mii)); + mii.cbSize = sizeof(mii); + mii.fMask = MIIM_ID | MIIM_TYPE; + mii.fType = MFT_STRING; + mii.dwTypeData = tmp; + mii.cch = strlen(tmp); + mii.wID = 1; + + if (!proto->CanSetAvatar()) + { + mii.fMask |= MIIM_STATE; + mii.fState = MFS_DISABLED; + } + + InsertMenuItem(submenu, 0, TRUE, &mii); + + ZeroMemory(&mii, sizeof(mii)); + mii.cbSize = sizeof(mii); + mii.fMask = MIIM_STATE; + mii.fState = protocols->ListeningToEnabled() ? MFS_CHECKED : 0; + + if (!protocols->CanSetListeningTo()) + { + mii.fState |= MFS_DISABLED; + } + + SetMenuItemInfo(submenu, ID_CONTEXTPOPUP_ENABLELISTENINGTO, FALSE, &mii); + + ClientToScreen(hwnd, &p); + + int ret = TrackPopupMenu(submenu, TPM_TOPALIGN|TPM_LEFTALIGN|TPM_RIGHTBUTTON|TPM_RETURNCMD, p.x, p.y, 0, hwnd, NULL); + DestroyMenu(menu); + + switch(ret) + { + case 1: + { + CallService(MS_MYDETAILS_SETMYAVATARUI, 0, (LPARAM) proto->GetName()); + break; + } + case ID_AVATARPOPUP_SETMYAVATAR: + { + CallService(MS_MYDETAILS_SETMYAVATARUI, 0, 0); + break; + } + case 2: + { + CallService(MS_MYDETAILS_SETMYNICKNAMEUI, 0, (LPARAM) proto->GetName()); + break; + } + case ID_NICKPOPUP_SETMYNICKNAME: + { + CallService(MS_MYDETAILS_SETMYNICKNAMEUI, 0, 0); + break; + } + case 3: + { + CallService(MS_MYDETAILS_SETMYSTATUSMESSAGEUI, 0, (LPARAM) proto->GetName()); + break; + } + case 4: + { + CallService(MS_MYDETAILS_SETMYSTATUSMESSAGEUI, (WPARAM) proto->GetStatus(), 0); + break; + } + case ID_STATUSMESSAGEPOPUP_SETMYSTATUSMESSAGE: + { + CallService(MS_MYDETAILS_SETMYSTATUSMESSAGEUI, 0, 0); + break; + } + case 5: + { + CallService(MS_LISTENINGTO_ENABLE, (LPARAM) proto->GetName(), !proto->ListeningToEnabled()); + break; + } + case ID_CONTEXTPOPUP_ENABLELISTENINGTO: + { + CallService(MS_LISTENINGTO_ENABLE, 0, !protocols->ListeningToEnabled()); + break; + } + case ID_SHOW_NEXT_PROTO: + { + CallService(MS_MYDETAILS_SHOWNEXTPROTOCOL, 0, 0); + break; + } + case ID_SHOW_PREV_PROTO: + { + CallService(MS_MYDETAILS_SHOWPREVIOUSPROTOCOL, 0, 0); + break; + } + case ID_CYCLE_THROUGH_PROTOS: + { + CallService(MS_MYDETAILS_CYCLE_THROUGH_PROTOCOLS, TRUE, 0); + break; + } + case ID_DONT_CYCLE_THROUGH_PROTOS: + { + CallService(MS_MYDETAILS_CYCLE_THROUGH_PROTOCOLS, FALSE, 0); + break; + } + } + } + + data->showing_menu = false; + + + break; + } + + case WM_NCMOUSELEAVE: + case WM_MOUSELEAVE: + { + MyDetailsFrameData *data = (MyDetailsFrameData *)GetWindowLong(hwnd, GWL_USERDATA); + data->tracking_exit = false; + } + case WM_NCMOUSEMOVE: + { + MyDetailsFrameData *data = (MyDetailsFrameData *)GetWindowLong(hwnd, GWL_USERDATA); + + bool changed = false; + for(size_t i = 0; i < data->items.size(); ++i) + changed = changed || data->items[i]->setMouseOver(NULL); + + if (changed) + InvalidateRect(hwnd, NULL, FALSE); + + break; + } + + case WM_MOUSEMOVE: + { + MyDetailsFrameData *data = (MyDetailsFrameData *)GetWindowLong(hwnd, GWL_USERDATA); + Protocol *proto = GetCurrentProtocol(); + if (proto == NULL) + break; + + if (!data->tracking_exit) + { + TRACKMOUSEEVENT tme; + tme.cbSize = sizeof(TRACKMOUSEEVENT); + tme.dwFlags = TME_LEAVE; + tme.hwndTrack = hwnd; + tme.dwHoverTime = HOVER_DEFAULT; + TrackMouseEvent(&tme); + + data->tracking_exit = true; + } + + POINT p; + p.x = LOWORD(lParam); + p.y = HIWORD(lParam); + + bool changed = false; + for(size_t i = 0; i < data->items.size(); ++i) + changed = changed || data->items[i]->setMouseOver(&p); + + if (changed) + InvalidateRect(hwnd, NULL, FALSE); + + break; + } + + case WM_NOTIFY: + { + LPNMHDR lpnmhdr = (LPNMHDR) lParam; + + int i = (int) lpnmhdr->code; + + switch (lpnmhdr->code) { + case TTN_GETDISPINFO: + { + MyDetailsFrameData *data = (MyDetailsFrameData *)GetWindowLong(hwnd, GWL_USERDATA); + + LPNMTTDISPINFO lpttd = (LPNMTTDISPINFO) lpnmhdr; + SendMessage(lpnmhdr->hwndFrom, TTM_SETMAXTIPWIDTH, 0, 300); + + for(int i = 0; i < data->items.size(); i++) + { + lpttd->lpszText = (char *) data->items[i]->getToolTipFor(lpnmhdr->hwndFrom); + if (lpttd->lpszText != NULL) + break; + } + + return 0; + } + } + + break; + } + + case WM_DESTROY: + { + KillTimer(hwnd, ID_FRAME_TIMER); + + MyDetailsFrameData *tmp = (MyDetailsFrameData *)GetWindowLong(hwnd, GWL_USERDATA); + if (tmp != NULL) delete tmp; + + break; + } + + // Custom Messages ////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + case MWM_REFRESH: + { + KillTimer(hwnd, ID_RECALC_TIMER); + SetTimer(hwnd, ID_RECALC_TIMER, RECALC_TIME, NULL); + break; + } + + case MWM_REFRESH_DATA: + { + Protocol *proto = GetCurrentProtocol(false); + if (proto) + { + proto->UpdateAll(); + RedrawFrame(); + } + break; + } + } + + return DefWindowProc(hwnd, msg, wParam, lParam); +} + + +int ShowHideFrameFunc(WPARAM wParam, LPARAM lParam) +{ + if (ServiceExists(MS_CLIST_FRAMES_ADDFRAME)) + { + CallService(MS_CLIST_FRAMES_SHFRAME, frame_id, 0); + } + else + { + if (MyDetailsFrameVisible()) + { + SendMessage(hwnd_container, WM_CLOSE, 0, 0); + } + else + { + ShowWindow(hwnd_container, SW_SHOW); + DBWriteContactSettingByte(0, MODULE_NAME, SETTING_FRAME_VISIBLE, 1); + } + + FixMainMenu(); + } + return 0; +} + + +int ShowFrameFunc(WPARAM wParam, LPARAM lParam) +{ + if (ServiceExists(MS_CLIST_FRAMES_ADDFRAME)) + { + int flags = CallService(MS_CLIST_FRAMES_GETFRAMEOPTIONS, MAKEWPARAM(FO_FLAGS, frame_id), 0); + if(!(flags & F_VISIBLE)) + CallService(MS_CLIST_FRAMES_SHFRAME, frame_id, 0); + } + else + { + if (!MyDetailsFrameVisible()) + { + ShowWindow(hwnd_container, SW_SHOW); + DBWriteContactSettingByte(0, MODULE_NAME, SETTING_FRAME_VISIBLE, 1); + + FixMainMenu(); + } + + } + return 0; +} + + +int HideFrameFunc(WPARAM wParam, LPARAM lParam) +{ + if (ServiceExists(MS_CLIST_FRAMES_ADDFRAME)) + { + int flags = CallService(MS_CLIST_FRAMES_GETFRAMEOPTIONS, MAKEWPARAM(FO_FLAGS, frame_id), 0); + if (flags & F_VISIBLE) + CallService(MS_CLIST_FRAMES_SHFRAME, frame_id, 0); + } + else + { + if (MyDetailsFrameVisible()) + { + SendMessage(hwnd_container, WM_CLOSE, 0, 0); + + FixMainMenu(); + } + } + return 0; +} + + +void FixMainMenu() +{ + CLISTMENUITEM mi = {0}; + mi.cbSize = sizeof(CLISTMENUITEM); + mi.flags = CMIM_NAME; + + if(MyDetailsFrameVisible()) + mi.pszName = Translate("Hide My Details"); + else + mi.pszName = Translate("Show My Details"); + + CallService(MS_CLIST_MODIFYMENUITEM, (WPARAM)hMenuShowHideFrame, (LPARAM)&mi); +} + +#include + +void RedrawFrame() +{ + if (frame_id == -1) + { + InvalidateRect(hwnd_container, NULL, TRUE); + } + else + { + CallService(MS_CLIST_FRAMES_UPDATEFRAME, (WPARAM)frame_id, (LPARAM)FU_TBREDRAW | FU_FMREDRAW); + } +} + +void UpdateFrameData() +{ + if (hwnd_frame != NULL) + PostMessage(hwnd_frame, MWM_REFRESH, 0, 0); +} + +// only used when no multiwindow functionality is available +BOOL MyDetailsFrameVisible() +{ + return IsWindowVisible(hwnd_container) ? true : false; +} + +void SetMyDetailsFrameVisible(BOOL visible) +{ + if (frame_id == -1 && hwnd_container != 0) + { + ShowWindow(hwnd_container, visible ? SW_SHOW : SW_HIDE); + } +} + +void SetCycleTime() +{ + if (hwnd_frame != NULL) + SetCycleTime(hwnd_frame); +} + +void SetCycleTime(HWND hwnd) +{ + KillTimer(hwnd, ID_FRAME_TIMER); + + if (opts.cycle_through_protocols) + SetTimer(hwnd, ID_FRAME_TIMER, opts.seconds_to_show_protocol * 1000, 0); +} + +void SetStatusMessageRefreshTime() +{ + if (hwnd_frame != NULL) + SetStatusMessageRefreshTime(hwnd_frame); +} + +void SetStatusMessageRefreshTime(HWND hwnd) +{ + KillTimer(hwnd, ID_STATUSMESSAGE_TIMER); + + opts.refresh_status_message_timer = DBGetContactSettingWord(NULL, "MyDetails", "RefreshStatusMessageTimer",5); + if (opts.refresh_status_message_timer > 0) + { + SetTimer(hwnd, ID_STATUSMESSAGE_TIMER, opts.refresh_status_message_timer * 1000, NULL); + } +} + +int PluginCommand_ShowNextProtocol(WPARAM wParam,LPARAM lParam) +{ + if (hwnd_frame == NULL) + return -1; + + SetCurrentProtocol(GetCurrentProtocolIndex() + 1); + + SetCycleTime(); + + RedrawFrame(); + + return 0; +} + +int PluginCommand_ShowPreviousProtocol(WPARAM wParam,LPARAM lParam) +{ + if (hwnd_frame == NULL) + return -1; + + SetCurrentProtocol(GetCurrentProtocolIndex() - 1); + + SetCycleTime(); + + RedrawFrame(); + + return 0; +} + +int PluginCommand_ShowProtocol(WPARAM wParam,LPARAM lParam) +{ + char * proto = (char *)lParam; + + if (proto == NULL) + return -1; + + int proto_num = GetProtocolIndexByName(proto); + if (proto_num == -1) + return -2; + + if (hwnd_frame == NULL) + return -3; + + SetCurrentProtocol(proto_num); + + SetCycleTime(); + + RedrawFrame(); + + return 0; +} + +int SettingsChangedHook(WPARAM wParam, LPARAM lParam) +{ + if (hwnd_frame == NULL) + return 0; + + DBCONTACTWRITESETTING *cws = (DBCONTACTWRITESETTING*)lParam; + + if (wParam != NULL) + return 0; + + if (strstr(cws->szModule,"Away")) + { + // Status message changed + UpdateFrameData(); + return 0; + } + + Protocol *proto = GetCurrentProtocol(false); + if (proto == NULL || strcmp(proto->GetName(), cws->szModule) != 0) + return 0; + + if (!strcmp(cws->szSetting,"Status") + || !strcmp(cws->szSetting,"StatusMood") + || !strcmp(cws->szSetting,"XStatusName") + || !strcmp(cws->szSetting,"XStatusMsg") + || !strcmp(cws->szSetting,"XStatusId") + || ( proto->GetCustomStatus() != 0 && !strcmp(cws->szSetting, proto->GetCustomStatusNameKey()) ) + || ( proto->GetCustomStatus() != 0 && !strcmp(cws->szSetting, proto->GetCustomStatusMessageKey()) )) + { + // Status changed + UpdateFrameData(); + } + else if(!strcmp(cws->szSetting,"MyHandle") + || !strcmp(cws->szSetting,"UIN") + || !strcmp(cws->szSetting,"Nick") + || !strcmp(cws->szSetting,"FirstName") + || !strcmp(cws->szSetting,"e-mail") + || !strcmp(cws->szSetting,"LastName") + || !strcmp(cws->szSetting,"JID")) + { + // Name changed + UpdateFrameData(); + } + else if (strcmp(cws->szSetting,"ListeningTo") == 0) + { + UpdateFrameData(); + } + else if (strcmp(cws->szSetting,"LockMainStatus") == 0) + { + UpdateFrameData(); + } + + return 0; +} + +int AvatarChangedHook(WPARAM wParam, LPARAM lParam) +{ + if (hwnd_frame == NULL) + return 0; + + Protocol *proto = GetCurrentProtocol(false); + if (proto == NULL || strcmp(proto->GetName(), (const char *) wParam) != 0) + return 0; + + UpdateFrameData(); + + return 0; +} + +int ProtoAckHook(WPARAM wParam, LPARAM lParam) +{ + if (hwnd_frame == NULL) + return 0; + + ACKDATA *ack = (ACKDATA*) lParam; + if (ack->hContact != NULL) + return 0; + + Protocol *proto = GetCurrentProtocol(false); + if (proto == NULL || strcmp(proto->GetName(), ack->szModule) != 0) + return 0; + + if (ack->type == ACKTYPE_STATUS) + { + UpdateFrameData(); + } + else if (ack->type == ACKTYPE_AWAYMSG) + { + UpdateFrameData(); + } + else if (ack->type == ACKTYPE_EMAIL) + { + UpdateFrameData(); + } + + return 0; +} + +int ListeningtoEnableStateChangedHook(WPARAM wParam,LPARAM lParam) +{ + if (hwnd_frame == NULL) + return 0; + + Protocol *proto = GetCurrentProtocol(false); + if (proto == NULL || strcmp(proto->GetName(), (const char *) wParam) != 0) + return 0; + + UpdateFrameData(); + + return 0; +} + +int AccListChanged(WPARAM wParam, LPARAM lParam) +{ + SetCurrentProtocol(0); + + RedrawFrame(); + + return 0; +} diff --git a/plugins/MyDetails/frame.h b/plugins/MyDetails/frame.h new file mode 100644 index 0000000000..58aa800090 --- /dev/null +++ b/plugins/MyDetails/frame.h @@ -0,0 +1,38 @@ +/* +Copyright (C) 2005 Ricardo Pescuma Domenecci + +This is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public +License as published by the Free Software Foundation; either +version 2 of the License, or (at your option) any later version. + +This 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 +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with this file; see the file license.txt. If +not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. +*/ + + +#ifndef __FRAME_H__ +# define __FRAME_H__ + + +void InitFrames(); +void DeInitFrames(); + +void UpdateFrameData(); +void RedrawFrame(); + +void SetCycleTime(); + +int PluginCommand_ShowNextProtocol(WPARAM wParam,LPARAM lParam); +int PluginCommand_ShowPreviousProtocol(WPARAM wParam,LPARAM lParam); +int PluginCommand_ShowProtocol(WPARAM wParam,LPARAM lParam); + + +#endif // __FRAME_H__ \ No newline at end of file diff --git a/plugins/MyDetails/mydetails.cpp b/plugins/MyDetails/mydetails.cpp new file mode 100644 index 0000000000..9351765f6c --- /dev/null +++ b/plugins/MyDetails/mydetails.cpp @@ -0,0 +1,992 @@ +/* +Copyright (C) 2005 Ricardo Pescuma Domenecci + +This is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public +License as published by the Free Software Foundation; either +version 2 of the License, or (at your option) any later version. + +This 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 +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with this file; see the file license.txt. If +not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. +*/ + + +#include "commons.h" +#include "mydetails.h" + + +// Prototypes ///////////////////////////////////////////////////////////////////////////////////// + + +HINSTANCE hInst; +PLUGINLINK *pluginLink; + +PLUGININFOEX pluginInfo={ + sizeof(PLUGININFOEX), + "My Details", + PLUGIN_MAKE_VERSION(0,0,2,6), + "Show and allows you to edit your details for all protocols.", + "Ricardo Pescuma Domenecci, Drugwash", + "", + "© 2005-2010 Ricardo Pescuma Domenecci, Drugwash", + "http://pescuma.org/miranda/mydetails", + 0, //not transient + 0, //doesn't replace anything built-in + { 0xa82baeb3, 0xa33c, 0x4036, { 0xb8, 0x37, 0x78, 0x3, 0xa5, 0xb6, 0xc2, 0xab } } // {A82BAEB3-A33C-4036-B837-7803A5B6C2AB} +}; + + +struct MM_INTERFACE mmi; +struct UTF8_INTERFACE utfi; +struct SKIN_INTERFACE mski; + + +HANDLE hTTB = NULL; + +// Hooks +HANDLE hModulesLoadedHook = NULL; +HANDLE hPreShutdownHook = NULL; +HANDLE hColorChangedHook = NULL; + +long nickname_dialog_open; +HWND hwndSetNickname; + +long status_msg_dialog_open; +HWND hwndSetStatusMsg; + +SkinDialog *dialog; + + +// Hook called after init +static int MainInit(WPARAM wparam,LPARAM lparam); +static int MainUninit(WPARAM wParam, LPARAM lParam); + + +// Services +static int PluginCommand_SetMyNicknameUI(WPARAM wParam,LPARAM lParam); +static int PluginCommand_SetMyNickname(WPARAM wParam,LPARAM lParam); +static int PluginCommand_GetMyNickname(WPARAM wParam,LPARAM lParam); +static int PluginCommand_SetMyAvatarUI(WPARAM wParam,LPARAM lParam); +static int PluginCommand_SetMyAvatar(WPARAM wParam,LPARAM lParam); +static int PluginCommand_GetMyAvatar(WPARAM wParam,LPARAM lParam); +static int PluginCommand_SetMyStatusMessageUI(WPARAM wParam,LPARAM lParam); +static int PluginCommand_CicleThroughtProtocols(WPARAM wParam,LPARAM lParam); + + + + +// Functions ////////////////////////////////////////////////////////////////////////////////////// + + +BOOL WINAPI DllMain(HINSTANCE hinstDLL,DWORD fdwReason,LPVOID lpvReserved) +{ + hInst = hinstDLL; + return TRUE; +} + + +extern "C" __declspec(dllexport) PLUGININFO* MirandaPluginInfo(DWORD mirandaVersion) +{ + pluginInfo.cbSize = sizeof(PLUGININFO); + return (PLUGININFO*) &pluginInfo; +} + + +extern "C" __declspec(dllexport) PLUGININFOEX* MirandaPluginInfoEx(DWORD mirandaVersion) +{ + pluginInfo.cbSize = sizeof(PLUGININFOEX); + return &pluginInfo; +} + + +static const MUUID interfaces[] = { MIID_MDETAILS, MIID_LAST }; +extern "C" __declspec(dllexport) const MUUID* MirandaPluginInterfaces(void) +{ + return interfaces; +} + + +int __declspec(dllexport) Load(PLUGINLINK *link) +{ + // Copy data + pluginLink = link; + + // CHECK_VERSION("My Details") + + mir_getMMI(&mmi); + mir_getUTFI(&utfi); + + init_list_interface(); + + // Hook event to load messages and show first one + hModulesLoadedHook = HookEvent(ME_SYSTEM_MODULESLOADED, MainInit); + hPreShutdownHook = HookEvent(ME_SYSTEM_PRESHUTDOWN, MainUninit); + + nickname_dialog_open = 0; + status_msg_dialog_open = 0; + + // Options + InitOptions(); + + // Register services + CreateServiceFunction(MS_MYDETAILS_SETMYNICKNAME, PluginCommand_SetMyNickname); + CreateServiceFunction(MS_MYDETAILS_SETMYNICKNAMEUI, PluginCommand_SetMyNicknameUI); + CreateServiceFunction(MS_MYDETAILS_SETMYAVATAR, PluginCommand_SetMyAvatar); + CreateServiceFunction(MS_MYDETAILS_SETMYAVATARUI, PluginCommand_SetMyAvatarUI); + CreateServiceFunction(MS_MYDETAILS_GETMYNICKNAME, PluginCommand_GetMyNickname); + CreateServiceFunction(MS_MYDETAILS_GETMYAVATAR, PluginCommand_GetMyAvatar); + CreateServiceFunction(MS_MYDETAILS_SETMYSTATUSMESSAGEUI, PluginCommand_SetMyStatusMessageUI); + CreateServiceFunction(MS_MYDETAILS_SHOWNEXTPROTOCOL, PluginCommand_ShowNextProtocol); + CreateServiceFunction(MS_MYDETAILS_SHOWPREVIOUSPROTOCOL, PluginCommand_ShowPreviousProtocol); + CreateServiceFunction(MS_MYDETAILS_SHOWPROTOCOL, PluginCommand_ShowProtocol); + CreateServiceFunction(MS_MYDETAILS_CYCLE_THROUGH_PROTOCOLS, PluginCommand_CicleThroughtProtocols); + + return 0; +} + + +int __declspec(dllexport) Unload(void) +{ + DestroyServiceFunction(MS_MYDETAILS_SETMYNICKNAME); + DestroyServiceFunction(MS_MYDETAILS_SETMYNICKNAMEUI); + DestroyServiceFunction(MS_MYDETAILS_SETMYAVATAR); + DestroyServiceFunction(MS_MYDETAILS_SETMYAVATARUI); + DestroyServiceFunction(MS_MYDETAILS_GETMYNICKNAME); + DestroyServiceFunction(MS_MYDETAILS_GETMYAVATAR); + DestroyServiceFunction(MS_MYDETAILS_SETMYSTATUSMESSAGEUI); + DestroyServiceFunction(MS_MYDETAILS_SHOWNEXTPROTOCOL); + DestroyServiceFunction(MS_MYDETAILS_SHOWPREVIOUSPROTOCOL); + DestroyServiceFunction(MS_MYDETAILS_SHOWPROTOCOL); + DestroyServiceFunction(MS_MYDETAILS_CYCLE_THROUGH_PROTOCOLS); + + if (hModulesLoadedHook) UnhookEvent(hModulesLoadedHook); + + DeInitProtocolData(); + DeInitOptions(); + + return 0; +} + + +static int Menu_SetMyAvatarUI(WPARAM wParam,LPARAM lParam) +{ + return PluginCommand_SetMyAvatarUI(0, 0); +} +static int Menu_SetMyNicknameUI(WPARAM wParam,LPARAM lParam) +{ + return PluginCommand_SetMyNicknameUI(0, 0); +} +static int Menu_SetMyStatusMessageUI(WPARAM wParam,LPARAM lParam) +{ + return PluginCommand_SetMyStatusMessageUI(0, 0); +} + +static void SkinChanged(void *param, SKINNED_DIALOG dlg) +{ + RedrawFrame(); +} + + +static int ColorChanged(WPARAM wparam, LPARAM lparam) +{ + ColourID cid = {0}; + cid.cbSize = sizeof(ColourID); + lstrcpynA(cid.group, "My Details", sizeof(cid.group)); + lstrcpynA(cid.name, "Background", sizeof(cid.name)); + + opts.bkg_color = (COLORREF) CallService(MS_COLOUR_GET, (WPARAM) &cid, 0); + + RedrawFrame(); + + return 0; +} + + +// Hook called after init +static int MainInit(WPARAM wparam,LPARAM lparam) +{ + if ( mir_skins_getInterface(&mski) != 0 ) + { + MessageBox(NULL, _T("MyDetails needs Skins plugin in order to work"), _T("MyDetails"), MB_OK | MB_ICONERROR); + return 0; + } + + if (CallService(MS_SKIN2_GETICON, 0, (LPARAM) "LISTENING_TO_ICON") == NULL) + { + SKINICONDESC sid = {0}; + sid.cbSize = sizeof(SKINICONDESC); + sid.ptszSection = "Contact List"; + sid.ptszDescription = "Listening to"; + sid.pszName = "LISTENING_TO_ICON"; + sid.hDefaultIcon = LoadIcon(hInst, MAKEINTRESOURCE(IDI_LISTENINGTO)); + CallService(MS_SKIN2_ADDICON, 0, (LPARAM)&sid); + } + + { + SKINICONDESC sid = {0}; + sid.cbSize = sizeof(SKINICONDESC); + sid.ptszSection = "My Details"; + sid.ptszDescription = "Email"; + sid.pszName = "MYDETAILS_EMAIL"; + sid.hDefaultIcon = LoadIcon(hInst, MAKEINTRESOURCE(IDI_EMAIL)); + CallService(MS_SKIN2_ADDICON, 0, (LPARAM)&sid); + } + + { + SKINICONDESC sid = {0}; + sid.cbSize = sizeof(SKINICONDESC); + sid.ptszSection = "My Details"; + sid.ptszDescription = "Previous protocol"; + sid.pszName = "MYDETAILS_PREV_PROTOCOL"; + sid.hDefaultIcon = LoadIcon(hInst, MAKEINTRESOURCE(IDI_LEFT_ARROW)); + CallService(MS_SKIN2_ADDICON, 0, (LPARAM)&sid); + } + + { + SKINICONDESC sid = {0}; + sid.cbSize = sizeof(SKINICONDESC); + sid.ptszSection = "My Details"; + sid.ptszDescription = "Next protocol"; + sid.pszName = "MYDETAILS_NEXT_PROTOCOL"; + sid.hDefaultIcon = LoadIcon(hInst, MAKEINTRESOURCE(IDI_RIGHT_ARROW)); + CallService(MS_SKIN2_ADDICON, 0, (LPARAM)&sid); + } + + { + ColourID cid = {0}; + cid.cbSize = sizeof(ColourID); + lstrcpynA(cid.group, "My Details", sizeof(cid.group)); + lstrcpynA(cid.name, "Background", sizeof(cid.name)); + lstrcpynA(cid.dbSettingsGroup, MODULE_NAME, sizeof(cid.dbSettingsGroup)); + lstrcpynA(cid.setting, "BackgroundColor", sizeof(cid.setting)); + cid.defcolour = GetSysColor(COLOR_BTNFACE); + + CallService(MS_COLOUR_REGISTER, (WPARAM) &cid, 0); + + ColorChanged(0,0); + + hColorChangedHook = HookEvent(ME_COLOUR_RELOAD, ColorChanged); + } + + dialog = new SkinDialog("MyDetails", "My Details", MODULE_NAME); + if (!dialog->isValid()) + { + MessageBox(NULL, _T("MyDetails could not create dialog. Check if default skin is installed"), _T("MyDetails"), MB_OK | MB_ICONERROR); + return 0; + } + + dialog->addImageField("avatar", "Avatar"); + dialog->addTextField("nickname", "Nickname"); + dialog->addTextField("protocol", "Protocol"); + dialog->addIconField("email_icon", "Unread Email Count Icon"); + dialog->addTextField("email", "Unread Email Count"); + dialog->addIconField("status_icon", "Status Icon"); + dialog->addTextField("status_name", "Status"); + dialog->addTextField("status_msg", "Status Message"); + dialog->addIconField("listening_icon", "Listening To Icon"); + dialog->addTextField("listening", "Listening To"); + dialog->addIconField("next_proto", "Next Protocol"); + dialog->addIconField("prev_proto", "Previous Protocol"); + dialog->setSkinChangedCallback(SkinChanged, NULL); + dialog->finishedConfiguring(); + + + InitProtocolData(); + + // Add options to menu + CLISTMENUITEM mi; + + if (protocols->CanSetAvatars()) + { + ZeroMemory(&mi,sizeof(mi)); + mi.cbSize = sizeof(mi); + mi.flags = 0; + mi.popupPosition = 500050000; + mi.pszPopupName = Translate("My Details"); + mi.position = 100001; + mi.pszName = Translate("Set My Avatar..."); + CreateServiceFunction("MENU_" MS_MYDETAILS_SETMYAVATARUI, Menu_SetMyAvatarUI); + mi.pszService = "MENU_" MS_MYDETAILS_SETMYAVATARUI; + + CallService(MS_CLIST_ADDMAINMENUITEM,0,(LPARAM)&mi); + } + + ZeroMemory(&mi,sizeof(mi)); + mi.cbSize = sizeof(mi); + mi.flags = 0; + mi.popupPosition = 500050000; + mi.pszPopupName = Translate("My Details"); + mi.position = 100002; + mi.pszName = Translate("Set My Nickname..."); + CreateServiceFunction("MENU_" MS_MYDETAILS_SETMYNICKNAMEUI, Menu_SetMyNicknameUI); + mi.pszService = "MENU_" MS_MYDETAILS_SETMYNICKNAMEUI; + + CallService(MS_CLIST_ADDMAINMENUITEM,0,(LPARAM)&mi); + + ZeroMemory(&mi,sizeof(mi)); + mi.cbSize = sizeof(mi); + mi.flags = 0; + mi.popupPosition = 500050000; + mi.pszPopupName = Translate("My Details"); + mi.position = 100003; + mi.pszName = Translate("Set My Status Message..."); + CreateServiceFunction("MENU_" MS_MYDETAILS_SETMYSTATUSMESSAGEUI, Menu_SetMyStatusMessageUI); + mi.pszService = "MENU_" MS_MYDETAILS_SETMYSTATUSMESSAGEUI; + + CallService(MS_CLIST_ADDMAINMENUITEM,0,(LPARAM)&mi); + + // Set protocols to show frame + ZeroMemory(&mi,sizeof(mi)); + mi.cbSize = sizeof(mi); + mi.flags = 0; + mi.popupPosition = 500050000; + mi.pszPopupName = Translate("My Details"); + mi.position = 200001; + mi.pszName = Translate("Show next protocol"); + mi.pszService = MS_MYDETAILS_SHOWNEXTPROTOCOL; + + CallService(MS_CLIST_ADDMAINMENUITEM,0,(LPARAM)&mi); + + InitFrames(); + + // updater plugin support + if(ServiceExists(MS_UPDATE_REGISTER)) + { + Update upd = {0}; + char szCurrentVersion[30]; + + upd.cbSize = sizeof(upd); + upd.szComponentName = pluginInfo.shortName; + + upd.szUpdateURL = UPDATER_AUTOREGISTER; + + upd.szBetaVersionURL = "http://svn.berlios.de/svnroot/repos/mgoodies/trunk/mydetails/Docs/mydetails_version.txt"; + upd.szBetaChangelogURL = "http://svn.berlios.de/svnroot/repos/mgoodies/trunk/mydetails/Docs/mydetails_changelog.txt"; + upd.pbBetaVersionPrefix = (BYTE *)"My Details "; + upd.cpbBetaVersionPrefix = strlen((char *)upd.pbBetaVersionPrefix); + upd.szBetaUpdateURL = "http://pescuma.googlecode.com/files/mydetails.%VERSION%.zip"; + + upd.pbVersion = (BYTE *)CreateVersionStringPlugin((PLUGININFO*) &pluginInfo, szCurrentVersion); + upd.cpbVersion = strlen((char *)upd.pbVersion); + + CallService(MS_UPDATE_REGISTER, 0, (LPARAM)&upd); + } + + return 0; +} + +static int MainUninit(WPARAM wParam, LPARAM lParam) +{ + DeInitFrames(); + + delete dialog; + + return 0; +} + +// Set nickname /////////////////////////////////////////////////////////////////////////////////// + +#define WMU_SETDATA (WM_USER+1) + +static BOOL CALLBACK DlgProcSetNickname(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam) +{ + switch ( msg ) + { + case WM_INITDIALOG: + { + TranslateDialogDefault(hwndDlg); + SendMessage(GetDlgItem(hwndDlg, IDC_NICKNAME), EM_LIMITTEXT, + MS_MYDETAILS_GETMYNICKNAME_BUFFER_SIZE - 1, 0); + + return TRUE; + } + + case WMU_SETDATA: + { + int proto_num = (int)wParam; + + SetWindowLong(hwndDlg, GWL_USERDATA, proto_num); + + if (proto_num == -1) + { + SendMessage(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)LoadSkinnedIcon(SKINICON_OTHER_MIRANDA)); + + // All protos have the same nick? + + std::vector protos; + GetProtocols(&protos); + + int protosSize = protos.size(); + if (protosSize > 0) + { + std::string nick = protos[0].GetNick(); + + bool foundDefNick = true; + for(int i = 1; i < protosSize; i++) + { + if (stricmp(protos[i].GetNick(), nick.c_str()) != 0) + { + foundDefNick = false; + break; + } + } + + if (foundDefNick) + { + if (stricmp(protocols->default_nick, nick.c_str()) != 0) + lstrcpy(protocols->default_nick, nick.c_str()); + } + } + + SetDlgItemText(hwndDlg, IDC_NICKNAME, protocols->default_nick); + SendDlgItemMessage(hwndDlg, IDC_NICKNAME, EM_LIMITTEXT, MS_MYDETAILS_GETMYNICKNAME_BUFFER_SIZE, 0); + } + else + { + Protocol proto = GetProtocolByIndex(proto_num); + + char tmp[128]; + mir_snprintf(tmp, sizeof(tmp), Translate("Set My Nickname for %s"), proto.GetDescription()); + + SendMessage(hwndDlg, WM_SETTEXT, 0, (LPARAM)tmp); + + HICON hIcon = (HICON) proto.Call(PS_LOADICON, PLI_PROTOCOL); + if (hIcon != NULL) + { + SendMessage(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)hIcon); + DestroyIcon(hIcon); + } + + SetDlgItemText(hwndDlg, IDC_NICKNAME, proto.GetNick()); + SendDlgItemMessage(hwndDlg, IDC_NICKNAME, EM_LIMITTEXT, + min(MS_MYDETAILS_GETMYNICKNAME_BUFFER_SIZE, proto.GetNickMaxLength()), 0); + } + + return TRUE; + } + + case WM_COMMAND: + switch(wParam) + { + case IDOK: + { + char tmp[MS_MYDETAILS_GETMYNICKNAME_BUFFER_SIZE]; + GetDlgItemText(hwndDlg, IDC_NICKNAME, tmp, sizeof(tmp)); + + int proto_num = (int) GetWindowLong(hwndDlg, GWL_USERDATA); + if (proto_num == -1) + { + protocols->SetNicks(tmp); + } + else + { + GetProtocolByIndex(proto_num).SetNick(tmp); + } + + DestroyWindow(hwndDlg); + break; + } + case IDCANCEL: + { + DestroyWindow(hwndDlg); + break; + } + } + break; + + case WM_CLOSE: + DestroyWindow(hwndDlg); + break; + + case WM_DESTROY: + InterlockedExchange(&nickname_dialog_open, 0); + break; + } + + return FALSE; +} + +static int PluginCommand_SetMyNicknameUI(WPARAM wParam,LPARAM lParam) +{ + char * proto = (char *)lParam; + int proto_num = -1; + + if (proto != NULL) + { + proto_num = GetProtocolIndexByName(proto); + if (proto_num == -1) + return -1; + + if (!GetProtocolByIndex(proto_num).CanSetNick()) + return -2; + } + + if (!nickname_dialog_open) + { + InterlockedExchange(&nickname_dialog_open, 1); + + hwndSetNickname = CreateDialog(hInst, MAKEINTRESOURCE( IDD_SETNICKNAME ), NULL, DlgProcSetNickname ); + + SendMessage(hwndSetNickname, WMU_SETDATA, proto_num, 0); + } + + SetForegroundWindow( hwndSetNickname ); + SetFocus( hwndSetNickname ); + ShowWindow( hwndSetNickname, SW_SHOW ); + + return 0; +} + + +static int PluginCommand_SetMyNickname(WPARAM wParam,LPARAM lParam) +{ + char * proto = (char *)wParam; + + if (proto != NULL) + { + Protocol protocol = GetProtocolByName(proto); + if (!protocol) + return -1; + + if (!protocol.CanSetNick()) + return -2; + + protocol.SetNick((char *)lParam); + } + else + { + protocols->SetNicks((char *)lParam); + } + + return 0; +} + + +static int PluginCommand_GetMyNickname(WPARAM wParam,LPARAM lParam) +{ + char * ret = (char *)lParam; + char * proto = (char *)wParam; + + if (ret == NULL) + return -1; + + if (proto == NULL) + { + if (protocols->default_nick != NULL) + lstrcpyn(ret, protocols->default_nick, MS_MYDETAILS_GETMYNICKNAME_BUFFER_SIZE); + else + ret[0] = '\0'; + } + else + { + Protocol protocol = GetProtocolByName(proto); + if (!protocol) + return -1; + + lstrcpyn(ret, protocol.GetNick(), MS_MYDETAILS_GETMYNICKNAME_BUFFER_SIZE); + } + + return 0; +} + + +// Set avatar ///////////////////////////////////////////////////////////////////////////////////// + +static int PluginCommand_SetMyAvatarUI(WPARAM wParam,LPARAM lParam) +{ + char * proto = (char *)lParam; + int proto_num = -1; + + if (proto != NULL) + { + Protocol protocol = GetProtocolByName(proto); + if (!protocol) + return -1; + + if (!protocol.CanSetAvatar()) + return -2; + + protocol.SetAvatar(NULL); + } + else + { + protocols->SetAvatars(NULL); + } + + return 0; +} + + +static int PluginCommand_SetMyAvatar(WPARAM wParam,LPARAM lParam) +{ + char * proto = (char *)wParam; + + if (proto != NULL) + { + Protocol protocol = GetProtocolByName(proto); + if (!protocol) + return -1; + + if (!protocol.CanSetAvatar()) + return -2; + + protocol.SetAvatar((char *)lParam); + } + else + { + protocols->SetAvatars((char *)lParam); + } + + return 0; +} + + +int Status2SkinIcon(int status) +{ + switch(status) { + case ID_STATUS_AWAY: return SKINICON_STATUS_AWAY; + case ID_STATUS_NA: return SKINICON_STATUS_NA; + case ID_STATUS_DND: return SKINICON_STATUS_DND; + case ID_STATUS_OCCUPIED: return SKINICON_STATUS_OCCUPIED; + case ID_STATUS_FREECHAT: return SKINICON_STATUS_FREE4CHAT; + case ID_STATUS_ONLINE: return SKINICON_STATUS_ONLINE; + case ID_STATUS_OFFLINE: return SKINICON_STATUS_OFFLINE; + case ID_STATUS_INVISIBLE: return SKINICON_STATUS_INVISIBLE; + case ID_STATUS_ONTHEPHONE: return SKINICON_STATUS_ONTHEPHONE; + case ID_STATUS_OUTTOLUNCH: return SKINICON_STATUS_OUTTOLUNCH; + case ID_STATUS_IDLE: return SKINICON_STATUS_AWAY; + } + return SKINICON_STATUS_OFFLINE; +} + + + +static int PluginCommand_GetMyAvatar(WPARAM wParam,LPARAM lParam) +{ + char * ret = (char *)lParam; + char * proto = (char *)wParam; + + if (ret == NULL) + return -1; + + if (proto == NULL) + { + if (protocols->default_avatar_file != NULL) + lstrcpyn(ret, protocols->default_avatar_file, MS_MYDETAILS_GETMYAVATAR_BUFFER_SIZE); + else + ret[0] = '\0'; + } + else + { + Protocol protocol = GetProtocolByName(proto); + if (!protocol) + return -1; + + if (!protocol.CanGetAvatar()) + return -2; + + lstrcpyn(ret, protocol.GetAvatarFile(), MS_MYDETAILS_GETMYAVATAR_BUFFER_SIZE); + } + + return 0; +} + +static LRESULT CALLBACK StatusMsgEditSubclassProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ + switch (msg) { + case WM_CHAR: + { + if(wParam == 0x0a && (GetKeyState(VK_CONTROL) & 0x8000) != 0) { + PostMessage(GetParent(hwnd), WM_COMMAND, IDOK, 0); + return 0; + } + + break; + } + } + + return CallWindowProc((WNDPROC) GetWindowLong(hwnd, GWL_USERDATA), hwnd, msg, wParam, lParam); +} + +struct SetStatusMessageData { + int status; + int proto_num; +}; + +static BOOL CALLBACK DlgProcSetStatusMessage(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam) +{ + switch ( msg ) + { + case WM_INITDIALOG: + { + TranslateDialogDefault(hwndDlg); + SendMessage(GetDlgItem(hwndDlg, IDC_STATUSMESSAGE), EM_LIMITTEXT, + MS_MYDETAILS_GETMYSTATUSMESSAGE_BUFFER_SIZE - 1, 0); + + WNDPROC old_proc = (WNDPROC) SetWindowLong(GetDlgItem(hwndDlg, IDC_STATUSMESSAGE), + GWL_WNDPROC, (LONG) StatusMsgEditSubclassProc); + + SetWindowLong(GetDlgItem(hwndDlg, IDC_STATUSMESSAGE), GWL_USERDATA, (long) old_proc); + + return TRUE; + } + + case WMU_SETDATA: + { + SetStatusMessageData *data = (SetStatusMessageData *) malloc(sizeof(SetStatusMessageData)); + data->status = (int)wParam; + data->proto_num = (int)lParam; + + SetWindowLong(hwndDlg, GWL_USERDATA, (LONG) data); + + if (data->proto_num >= 0) + { + Protocol proto = GetProtocolByIndex(data->proto_num); + + HICON hIcon = (HICON) proto.Call(PS_LOADICON, PLI_PROTOCOL); + if (hIcon != NULL) + { + SendMessage(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)hIcon); + DestroyIcon(hIcon); + } + + char title[256]; + mir_snprintf(title, sizeof(title), Translate("Set My Status Message for %s"), + proto.GetDescription()); + SendMessage(hwndDlg, WM_SETTEXT, 0, (LPARAM)title); + + SetDlgItemText(hwndDlg, IDC_STATUSMESSAGE, proto.GetStatusMsg()); + } + else if (data->status != 0) + { + SendMessage(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)LoadSkinnedIcon(Status2SkinIcon(data->status))); + + char title[256]; + mir_snprintf(title, sizeof(title), Translate("Set My Status Message for %s"), + CallService(MS_CLIST_GETSTATUSMODEDESCRIPTION, data->status, 0)); + SendMessage(hwndDlg, WM_SETTEXT, 0, (LPARAM)title); + + SetDlgItemText(hwndDlg, IDC_STATUSMESSAGE, protocols->GetDefaultStatusMsg(data->status)); + } + else + { + SendMessage(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)LoadSkinnedIcon(SKINICON_OTHER_MIRANDA)); + + SetDlgItemText(hwndDlg, IDC_STATUSMESSAGE, protocols->GetDefaultStatusMsg()); + } + + return TRUE; + } + case WM_COMMAND: + switch(wParam) + { + case IDOK: + { + char tmp[MS_MYDETAILS_GETMYSTATUSMESSAGE_BUFFER_SIZE]; + GetDlgItemText(hwndDlg, IDC_STATUSMESSAGE, tmp, sizeof(tmp)); + + SetStatusMessageData *data = (SetStatusMessageData *) GetWindowLong(hwndDlg, GWL_USERDATA); + + if (data->proto_num >= 0) + GetProtocolByIndex(data->proto_num).SetStatusMsg(tmp); + else if (data->status == 0) + protocols->SetStatusMsgs(tmp); + else + protocols->SetStatusMsgs(data->status, tmp); + + // To force a refresh + UpdateFrameData(); + + DestroyWindow(hwndDlg); + break; + } + case IDCANCEL: + { + DestroyWindow(hwndDlg); + break; + } + } + break; + + case WM_CLOSE: + DestroyWindow(hwndDlg); + break; + + case WM_DESTROY: + SetWindowLong(GetDlgItem(hwndDlg, IDC_STATUSMESSAGE), GWL_WNDPROC, + GetWindowLong(GetDlgItem(hwndDlg, IDC_STATUSMESSAGE), GWL_USERDATA)); + free((SetStatusMessageData *) GetWindowLong(hwndDlg, GWL_USERDATA)); + InterlockedExchange(&status_msg_dialog_open, 0); + break; + } + + return FALSE; +} + +static int PluginCommand_SetMyStatusMessageUI(WPARAM wParam,LPARAM lParam) +{ + int status = (int)wParam; + char * proto_name = (char *)lParam; + int proto_num = -1; + Protocol proto(NULL); + TCHAR status_message[256]; + + if (status != 0 && (status < ID_STATUS_OFFLINE || status > ID_STATUS_OUTTOLUNCH)) + return -10; + + if (proto_name != NULL) + { + proto_num = GetProtocolIndexByName(proto_name); + if (proto_num == -1) + return -1; + + proto = GetProtocolByIndex(proto_num); + if (!proto.CanSetStatusMsg()) + return -2; + } + + if (ServiceExists(MS_NAS_INVOKESTATUSWINDOW)) + { + NAS_ISWINFO iswi; + + ZeroMemory(&iswi, sizeof(iswi)); + + iswi.cbSize = sizeof(NAS_ISWINFO); + + if (proto) + { + // Has to get the unparsed message + NAS_PROTOINFO pi; + + ZeroMemory(&pi, sizeof(pi)); + pi.cbSize = sizeof(NAS_PROTOINFO); + pi.szProto = (char *) proto.GetName(); + pi.status = status; + pi.szMsg = NULL; + + if (ServiceExists(MS_NAS_GETSTATE)) + { + if (CallService(MS_NAS_GETSTATE, (WPARAM) &pi, 1) == 0) + { + if (pi.szMsg == NULL) + { + pi.szProto = NULL; + + if (CallService(MS_NAS_GETSTATE, (WPARAM) &pi, 1) == 0) + { + if (pi.szMsg != NULL) + { + lstrcpyn(status_message, pi.szMsg, MAX_REGS(status_message)); + mir_free(pi.szMsg); + } + } + } + else // if (pi.szMsg != NULL) + { + lstrcpyn(status_message, pi.szMsg, MAX_REGS(status_message)); + mir_free(pi.szMsg); + } + } + } + // TODO: Remove when removing old NAS services support + else + { + NAS_PROTOINFO *pii = π + + // Old services + if (CallService("NewAwaySystem/GetState", (WPARAM) &pii, 1) == 0) + { + if (pi.szMsg == NULL) + { + pi.szProto = NULL; + + if (CallService("NewAwaySystem/GetState", (WPARAM) &pii, 1) == 0) + { + if (pi.szMsg != NULL) + { + lstrcpyn(status_message, pi.szMsg, MAX_REGS(status_message)); + mir_free(pi.szMsg); + } + } + } + else // if (pi.szMsg != NULL) + { + lstrcpyn(status_message, pi.szMsg, MAX_REGS(status_message)); + mir_free(pi.szMsg); + } + } + } + + iswi.szProto = (char *) proto.GetName(); + iswi.szMsg = status_message; + } + else + { + iswi.szMsg = protocols->GetDefaultStatusMsg(); + } + + iswi.Flags = ISWF_NOCOUNTDOWN; + + CallService(MS_NAS_INVOKESTATUSWINDOW, (WPARAM) &iswi, 0); + + return 0; + } + else if (ServiceExists(MS_SA_SHOWSTATUSMSGDIALOG)) + { + CallService(MS_SA_SHOWSTATUSMSGDIALOG, 0, (LPARAM) proto_name); + return 0; + } + else if (ServiceExists(MS_SA_CHANGESTATUSMSG)) + { + if (!proto && status == 0) + { + CallService(MS_SA_CHANGESTATUSMSG, protocols->GetGlobalStatus(), NULL); + } + else if (status == 0) + { + CallService(MS_SA_CHANGESTATUSMSG, proto.GetStatus(), (LPARAM) proto_name); + } + else + { + CallService(MS_SA_CHANGESTATUSMSG, status, (LPARAM) proto_name); + } + + return 0; + } + else if (!proto || proto.GetStatus() != ID_STATUS_OFFLINE) + { + if (!status_msg_dialog_open) + { + InterlockedExchange(&status_msg_dialog_open, 1); + + hwndSetStatusMsg = CreateDialog(hInst, MAKEINTRESOURCE( IDD_SETSTATUSMESSAGE ), NULL, DlgProcSetStatusMessage ); + + SendMessage(hwndSetStatusMsg, WMU_SETDATA, status, proto_num); + } + + SetForegroundWindow( hwndSetStatusMsg ); + SetFocus( hwndSetStatusMsg ); + ShowWindow( hwndSetStatusMsg, SW_SHOW ); + + return 0; + } + + return -3; +} + + +static int PluginCommand_CicleThroughtProtocols(WPARAM wParam,LPARAM lParam) +{ + DBWriteContactSettingByte(NULL,"MyDetails","CicleThroughtProtocols", (BYTE) wParam); + + LoadOptions(); + + return 0; +} \ No newline at end of file diff --git a/plugins/MyDetails/mydetails.h b/plugins/MyDetails/mydetails.h new file mode 100644 index 0000000000..0780f7335e --- /dev/null +++ b/plugins/MyDetails/mydetails.h @@ -0,0 +1,42 @@ +/* +Copyright (C) 2005 Ricardo Pescuma Domenecci + +This is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public +License as published by the Free Software Foundation; either +version 2 of the License, or (at your option) any later version. + +This 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 +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with this file; see the file license.txt. If +not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. +*/ + + +#ifndef __MYDETAILS_H__ +# define __MYDETAILS_H__ + + +extern "C" +{ + +// Dll init +BOOL WINAPI DllMain(HINSTANCE hinstDLL,DWORD fdwReason,LPVOID lpvReserved); + +// Exports: +__declspec(dllexport) PLUGININFO* MirandaPluginInfo(DWORD mirandaVersion); +int __declspec(dllexport) Load(PLUGINLINK *link); +int __declspec(dllexport) Unload(void); + + +} + + + + +#endif // __MYDETAILS_H__ \ No newline at end of file diff --git a/plugins/MyDetails/mydetails.vcproj b/plugins/MyDetails/mydetails.vcproj new file mode 100644 index 0000000000..db4b4631a3 --- /dev/null +++ b/plugins/MyDetails/mydetails.vcproj @@ -0,0 +1,642 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/MyDetails/options.cpp b/plugins/MyDetails/options.cpp new file mode 100644 index 0000000000..c5c298c798 --- /dev/null +++ b/plugins/MyDetails/options.cpp @@ -0,0 +1,189 @@ +/* +Copyright (C) 2005 Ricardo Pescuma Domenecci + +This is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public +License as published by the Free Software Foundation; either +version 2 of the License, or (at your option) any later version. + +This 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 +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with this file; see the file license.txt. If +not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. +*/ + + +#include "commons.h" +#include "options.h" + + + +// Prototypes ///////////////////////////////////////////////////////////////////////////////////// + +Options opts; + + +static BOOL CALLBACK DlgProcOpts(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam); + + +// Functions ////////////////////////////////////////////////////////////////////////////////////// + + + +static OptPageControl pageControls[] = { + { &opts.draw_text_rtl, CONTROL_CHECKBOX, IDC_TEXT_RTL, "TextRTL", (BYTE) 0 }, + { &opts.cycle_through_protocols, CONTROL_CHECKBOX, IDC_CYCLE_THROUGH_PROTOS, "CicleThroughtProtocols", (BYTE) 1 }, + { &opts.seconds_to_show_protocol, CONTROL_SPIN, IDC_CYCLE_TIME, "CicleTime", (WORD) 5, IDC_CYCLE_TIME_SPIN, (WORD) 1, (WORD) 255 }, + { &opts.replace_smileys, CONTROL_CHECKBOX, IDC_REPLACE_SMILEYS, "ReplaceSmileys", (BYTE) 1 }, + { &opts.resize_smileys, CONTROL_CHECKBOX, IDC_RESIZE_SMILEYS, "ResizeSmileys", (BYTE) 0 }, + { &opts.use_contact_list_smileys, CONTROL_CHECKBOX, IDC_USE_CONTACT_LIST_SMILEYS, "UseContactListSmileys", (BYTE) 0 }, + { &opts.global_on_avatar, CONTROL_CHECKBOX, IDC_GLOBAL_ON_AVATAR, "GlobalOnAvatar", (BYTE) 0 }, + { &opts.global_on_nickname, CONTROL_CHECKBOX, IDC_GLOBAL_ON_NICKNAME, "GlobalOnNickname", (BYTE) 0 }, + { &opts.global_on_status, CONTROL_CHECKBOX, IDC_GLOBAL_ON_STATUS, "GlobalOnStatus", (BYTE) 0 }, + { &opts.global_on_status_message, CONTROL_CHECKBOX, IDC_GLOBAL_ON_STATUS_MESSAGE, "GlobalOnStatusMessage", (BYTE) 0 }, + { &opts.draw_avatar_border, CONTROL_CHECKBOX, IDC_AVATAR_DRAW_BORDER, "AvatarDrawBorders", (BYTE) 0 }, + { &opts.draw_avatar_border_color, CONTROL_COLOR, IDC_AVATAR_BORDER_COLOR, "AvatarBorderColor", (DWORD) RGB(0,0,0) }, + { &opts.draw_avatar_round_corner, CONTROL_CHECKBOX, IDC_AVATAR_ROUND_CORNERS, "AvatarRoundCorners", (BYTE) 1 }, + { &opts.draw_avatar_use_custom_corner_size, CONTROL_CHECKBOX, IDC_AVATAR_CUSTOM_CORNER_SIZE_CHECK, "AvatarUseCustomCornerSize", (BYTE) 0 }, + { &opts.draw_avatar_custom_corner_size, CONTROL_SPIN, IDC_AVATAR_CUSTOM_CORNER_SIZE, "AvatarCustomCornerSize", (WORD) 4, IDC_AVATAR_CUSTOM_CORNER_SIZE_SPIN, (WORD) 1, (WORD) 255 }, + { &opts.resize_frame, CONTROL_CHECKBOX, IDC_RESIZE_FRAME, "ResizeFrame", (BYTE) 0 }, +}; + + +// Initializations needed by options +void LoadOptions() +{ + if (GetSystemMetrics(SM_MIDEASTENABLED)) + pageControls[0].dwDefValue = TRUE; + + LoadOpts(pageControls, MAX_REGS(pageControls), MODULE_NAME); + + // This is created here to assert that this key always exists + opts.refresh_status_message_timer = DBGetContactSettingWord(NULL,"MyDetails","RefreshStatusMessageTimer",12); + DBWriteContactSettingWord(NULL,"MyDetails","RefreshStatusMessageTimer", opts.refresh_status_message_timer); + + SetCycleTime(); + RedrawFrame(); +} + + +int InitOptionsCallback(WPARAM wParam,LPARAM lParam) +{ + OPTIONSDIALOGPAGE odp; + + ZeroMemory(&odp,sizeof(odp)); + odp.cbSize=sizeof(odp); + odp.position=-200000000; + odp.hInstance=hInst; + odp.pfnDlgProc=DlgProcOpts; + odp.pszTemplate=MAKEINTRESOURCE(IDD_OPTS); + odp.pszGroup=Translate("Customize"); + odp.pszTitle=Translate("My Details"); + odp.flags=ODPF_BOLDGROUPS; + CallService(MS_OPT_ADDPAGE,wParam,(LPARAM)&odp); + + return 0; +} + + +void InitOptions() +{ + LoadOptions(); + + HookEvent(ME_OPT_INITIALISE, InitOptionsCallback); +} + +// Deinitializations needed by options +void DeInitOptions() +{ +} + + +static BOOL CALLBACK DlgProcOpts(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam) +{ + BOOL ret = SaveOptsDlgProc(pageControls, MAX_REGS(pageControls), MODULE_NAME, hwndDlg, msg, wParam, lParam); + + switch (msg) + { + case WM_INITDIALOG: + { + if(!IsDlgButtonChecked(hwndDlg,IDC_AVATAR_DRAW_BORDER)) + { + EnableWindow(GetDlgItem(hwndDlg,IDC_AVATAR_BORDER_COLOR_L),FALSE); + EnableWindow(GetDlgItem(hwndDlg,IDC_AVATAR_BORDER_COLOR),FALSE); + } + if(!IsDlgButtonChecked(hwndDlg,IDC_AVATAR_ROUND_CORNERS)) + { + EnableWindow(GetDlgItem(hwndDlg,IDC_AVATAR_CUSTOM_CORNER_SIZE_CHECK),FALSE); + EnableWindow(GetDlgItem(hwndDlg,IDC_AVATAR_CUSTOM_CORNER_SIZE),FALSE); + EnableWindow(GetDlgItem(hwndDlg,IDC_AVATAR_CUSTOM_CORNER_SIZE_SPIN),FALSE); + } + if(!IsDlgButtonChecked(hwndDlg,IDC_SHOW_PROTO_NAME)) + { + EnableWindow(GetDlgItem(hwndDlg,IDC_SHOW_CYCLE_PROTO_BUTTON),FALSE); + } + if (!ServiceExists(MS_SMILEYADD_BATCHPARSE)) + { + EnableWindow(GetDlgItem(hwndDlg,IDC_REPLACE_SMILEYS),FALSE); + EnableWindow(GetDlgItem(hwndDlg,IDC_USE_CONTACT_LIST_SMILEYS),FALSE); + EnableWindow(GetDlgItem(hwndDlg,IDC_RESIZE_SMILEYS),FALSE); + } + if (!ServiceExists(MS_CLIST_FRAMES_SETFRAMEOPTIONS)) + { + EnableWindow(GetDlgItem(hwndDlg,IDC_RESIZE_FRAME),FALSE); + } + + break; + } + case WM_COMMAND: + { + if (LOWORD(wParam)==IDC_AVATAR_DRAW_BORDER) + { + BOOL enabled = IsDlgButtonChecked(hwndDlg,IDC_AVATAR_DRAW_BORDER); + EnableWindow(GetDlgItem(hwndDlg,IDC_AVATAR_BORDER_COLOR_L),enabled); + EnableWindow(GetDlgItem(hwndDlg,IDC_AVATAR_BORDER_COLOR),enabled); + } + else if (LOWORD(wParam)==IDC_AVATAR_ROUND_CORNERS) + { + BOOL enabled = IsDlgButtonChecked(hwndDlg,IDC_AVATAR_ROUND_CORNERS); + EnableWindow(GetDlgItem(hwndDlg,IDC_AVATAR_CUSTOM_CORNER_SIZE_CHECK),enabled); + EnableWindow(GetDlgItem(hwndDlg,IDC_AVATAR_CUSTOM_CORNER_SIZE),enabled); + EnableWindow(GetDlgItem(hwndDlg,IDC_AVATAR_CUSTOM_CORNER_SIZE_SPIN),enabled); + } + else if (LOWORD(wParam)==IDC_SHOW_PROTO_NAME) + { + BOOL enabled = IsDlgButtonChecked(hwndDlg,IDC_SHOW_PROTO_NAME); + EnableWindow(GetDlgItem(hwndDlg,IDC_SHOW_CYCLE_PROTO_BUTTON),enabled); + } + + break; + } + case WM_NOTIFY: + { + switch (((LPNMHDR)lParam)->idFrom) + { + case 0: + { + switch (((LPNMHDR)lParam)->code) + { + case PSN_APPLY: + { + LoadOptions(); + + return TRUE; + } + } + break; + } + } + break; + } + } + + return ret; +} diff --git a/plugins/MyDetails/options.h b/plugins/MyDetails/options.h new file mode 100644 index 0000000000..71d5f474c1 --- /dev/null +++ b/plugins/MyDetails/options.h @@ -0,0 +1,83 @@ +/* +Copyright (C) 2005 Ricardo Pescuma Domenecci + +This is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public +License as published by the Free Software Foundation; either +version 2 of the License, or (at your option) any later version. + +This 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 +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with this file; see the file license.txt. If +not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. +*/ + + +#ifndef __OPTIONS_H__ +# define __OPTIONS_H__ + + +#define TOP 0 +#define LEFT 1 +#define BOTTOM 2 +#define RIGHT 3 + +struct Options +{ + bool cycle_through_protocols; + int seconds_to_show_protocol; + bool replace_smileys; + bool resize_smileys; + bool use_contact_list_smileys; + + bool draw_text_rtl; +// bool draw_text_align_right; + +// bool draw_show_protocol_name; +// bool show_protocol_cycle_button; + + bool global_on_avatar; + bool global_on_nickname; + bool global_on_status; + bool global_on_status_message; + +// bool draw_avatar_custom_size; +// bool draw_avatar_allow_to_grow; +// int draw_avatar_custom_size_pixels; + bool draw_avatar_border; + COLORREF draw_avatar_border_color; + bool draw_avatar_round_corner; + bool draw_avatar_use_custom_corner_size; + int draw_avatar_custom_corner_size; + + COLORREF bkg_color; +// int borders[4]; + +// bool use_avatar_space_to_draw_text; + + bool resize_frame; + + int refresh_status_message_timer; +}; + +extern Options opts; + + +// Initializations needed by options +void InitOptions(); + +// Deinitializations needed by options +void DeInitOptions(); + + +// Loads the options from DB +// It don't need to be called, except in some rare cases +void LoadOptions(); + + +#endif // __OPTIONS_H__ diff --git a/plugins/MyDetails/res/leftarrow.ico b/plugins/MyDetails/res/leftarrow.ico new file mode 100644 index 0000000000..4953e83bb5 Binary files /dev/null and b/plugins/MyDetails/res/leftarrow.ico differ diff --git a/plugins/MyDetails/res/listening_to.ico b/plugins/MyDetails/res/listening_to.ico new file mode 100644 index 0000000000..d359ec1a11 Binary files /dev/null and b/plugins/MyDetails/res/listening_to.ico differ diff --git a/plugins/MyDetails/res/mail.ico b/plugins/MyDetails/res/mail.ico new file mode 100644 index 0000000000..ba0e7d35de Binary files /dev/null and b/plugins/MyDetails/res/mail.ico differ diff --git a/plugins/MyDetails/res/rightarrow.ico b/plugins/MyDetails/res/rightarrow.ico new file mode 100644 index 0000000000..2705830a79 Binary files /dev/null and b/plugins/MyDetails/res/rightarrow.ico differ diff --git a/plugins/MyDetails/resource.h b/plugins/MyDetails/resource.h new file mode 100644 index 0000000000..9bc277ea60 --- /dev/null +++ b/plugins/MyDetails/resource.h @@ -0,0 +1,72 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Developer Studio generated include file. +// Used by resource.rc +// +#define IDD_SETNICKNAME 101 +#define IDD_OPTS 102 +#define IDD_SETSTATUSMESSAGE 103 +#define IDR_MENU1 104 +#define IDI_LISTENINGTO 105 +#define IDI_RIGHT_ARROW 106 +#define IDI_LEFT_ARROW 107 +#define IDI_EMAIL 111 +#define IDC_NICKNAME 1000 +#define IDC_SHOW_PROTO_NAME 1001 +#define IDC_CYCLE_THROUGH_PROTOS 1002 +#define IDC_TEXT_RTL 1003 +#define IDC_TEXT_ALIGN_RIGHT 1004 +#define IDC_REPLACE_SMILEYS 1005 +#define IDC_RESIZE_SMILEYS 1006 +#define IDC_RESIZE_FRAME 1007 +#define IDC_RESIZE_SMILEYS2 1008 +#define IDC_USE_CONTACT_LIST_SMILEYS 1008 +#define IDC_STATUSMESSAGE 1009 +#define IDC_GLOBAL_ON_NICKNAME 1009 +#define IDC_AVATAR_ALLOW_TO_GROW 1010 +#define IDC_GLOBAL_ON_STATUS_MESSAGE 1011 +#define IDC_GLOBAL_ON_STATUS 1012 +#define IDC_GLOBAL_ON_AVATAR 1013 +#define IDC_SHOW_CYCLE_PROTO_BUTTON 1014 +#define IDC_AVATAR_CUSTOM_CORNER_SIZE 1622 +#define IDC_AVATAR_CUSTOM_CORNER_SIZE_SPIN 1623 +#define IDC_BORDER_TOP 1624 +#define IDC_BORDER_TOP_SPIN 1625 +#define IDC_BORDER_LEFT 1626 +#define IDC_BORDER_LEFT_SPIN 1627 +#define IDC_BORDER_BOTTOM 1628 +#define IDC_BORDER_BOTTOM_SPIN 1629 +#define IDC_BORDER_RIGHT 1630 +#define IDC_BORDER_RIGHT_SPIN 1631 +#define IDC_CYCLE_TIME 1632 +#define IDC_CYCLE_TIME_SPIN 1633 +#define IDC_AVATAR_CUSTOM_SIZE 1634 +#define IDC_AVATAR_CUSTOM_SIZE_SPIN 1635 +#define IDC_AVATAR_CUSTOM_CORNER_SIZE_CHECK 1761 +#define IDC_AVATAR_DRAW_BORDER 1764 +#define IDC_AVATAR_CUSTOM_SIZE_CHK 1765 +#define IDC_AVATAR_ROUND_CORNERS 1800 +#define IDC_AVATAR_USE_FREE_SPACE 1801 +#define IDC_AVATAR_BORDER_COLOR_L 1839 +#define IDC_AVATAR_BORDER_COLOR 1840 +#define IDC_AVATAR_BKG_COLOR_L 1841 +#define IDC_AVATAR_BKG_COLOR 1842 +#define ID_CYCLE_THROUGH_PROTOS 40004 +#define ID_DONT_CYCLE_THROUGH_PROTOS 40005 +#define ID_SHOW_NEXT_PROTO 40006 +#define ID_SHOW_PREV_PROTO 40007 +#define ID_NICKPOPUP_SETMYNICKNAME 40008 +#define ID_STATUSMESSAGEPOPUP_SETMYSTATUSMESSAGE 40009 +#define ID_AVATARPOPUP_SETMYAVATAR 40010 +#define ID_LISTENINGTOPOPUP_SENDLISTENINGTO 40011 +#define ID_CONTEXTPOPUP_ENABLELISTENINGTO 40012 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 112 +#define _APS_NEXT_COMMAND_VALUE 40013 +#define _APS_NEXT_CONTROL_VALUE 1011 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/plugins/MyDetails/resource.rc b/plugins/MyDetails/resource.rc new file mode 100644 index 0000000000..5706422e8e --- /dev/null +++ b/plugins/MyDetails/resource.rc @@ -0,0 +1,326 @@ +//Microsoft Developer Studio generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "afxres.h" +#include "../../include/statusmodes.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// Neutral resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_NEU) +#ifdef _WIN32 +LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL +#pragma code_page(1252) +#endif //_WIN32 + +///////////////////////////////////////////////////////////////////////////// +// +// Icon +// + +// Icon with lowest ID value placed first to ensure application icon +// remains consistent on all systems. +IDI_LISTENINGTO ICON DISCARDABLE "res\\listening_to.ico" +IDI_RIGHT_ARROW ICON DISCARDABLE "res\\rightarrow.ico" +IDI_LEFT_ARROW ICON DISCARDABLE "res\\leftarrow.ico" +IDI_EMAIL ICON DISCARDABLE "res\\mail.ico" +#endif // Neutral resources +///////////////////////////////////////////////////////////////////////////// + + +///////////////////////////////////////////////////////////////////////////// +// English (U.S.) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +#ifdef _WIN32 +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) +#endif //_WIN32 + +#ifndef _MAC +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 0,0,1,11 + PRODUCTVERSION 0,0,1,11 + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x40004L + FILETYPE 0x2L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "080004b0" + BEGIN + VALUE "Comments", "\0" + VALUE "CompanyName", " \0" + VALUE "FileDescription", "MyDetails Miranda Plugin\0" + VALUE "FileVersion", "0, 0, 1, 11\0" + VALUE "InternalName", "mydetails\0" + VALUE "LegalCopyright", "Copyright © 2005-2008 Ricardo Pescuma Domenecci, Drugwash\0" + VALUE "LegalTrademarks", "\0" + VALUE "OriginalFilename", "mydetails.dll\0" + VALUE "PrivateBuild", "\0" + VALUE "ProductName", "\0" + VALUE "ProductVersion", "0, 0, 1, 11\0" + VALUE "SpecialBuild", "\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x800, 1200 + END +END + +#endif // !_MAC + + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_SETNICKNAME DIALOG DISCARDABLE 0, 0, 283, 65 +STYLE DS_MODALFRAME | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_CAPTION | + WS_SYSMENU +CAPTION "Set My Nickname" +FONT 8, "MS Shell Dlg" +BEGIN + RTEXT "Nickname:",IDC_STATIC,7,8,51,12 + EDITTEXT IDC_NICKNAME,67,7,209,31,ES_MULTILINE | ES_AUTOVSCROLL | + WS_VSCROLL + DEFPUSHBUTTON "OK",IDOK,87,44,50,14 + PUSHBUTTON "Cancel",IDCANCEL,146,44,50,14 +END + +IDD_OPTS DIALOGEX 0, 0, 316, 246 +STYLE DS_FIXEDSYS | WS_CHILD | WS_VISIBLE +EXSTYLE WS_EX_CONTROLPARENT +FONT 8, "MS Shell Dlg" +BEGIN + GROUPBOX " General ",IDC_STATIC,7,7,302,70 + CONTROL "Cycle through protocols every:", + IDC_CYCLE_THROUGH_PROTOS,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,13,18,114,14 + EDITTEXT IDC_CYCLE_TIME,129,18,35,12,ES_NUMBER + CONTROL "",IDC_CYCLE_TIME_SPIN,"msctls_updown32",UDS_SETBUDDYINT | + UDS_ALIGNRIGHT | UDS_ARROWKEYS | UDS_NOTHOUSANDS | + UDS_HOTTRACK,156,18,11,12 + LTEXT "seconds",IDC_STATIC,171,21,32,11 + CONTROL "Global on avatar",IDC_GLOBAL_ON_AVATAR,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,207,18,96,14 + CONTROL "RTL",IDC_TEXT_RTL,"Button",BS_AUTOCHECKBOX | WS_TABSTOP, + 13,32,85,14 + CONTROL "Global on nickname",IDC_GLOBAL_ON_NICKNAME,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,207,32,96,14 + CONTROL "Auto-resize frame",IDC_RESIZE_FRAME,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,13,46,85,14 + CONTROL "Use contact list smileys",IDC_USE_CONTACT_LIST_SMILEYS, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,105,46,96,14 + CONTROL "Global on status",IDC_GLOBAL_ON_STATUS,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,207,46,96,14 + CONTROL "Replace Smileys",IDC_REPLACE_SMILEYS,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,13,60,85,14 + CONTROL "Resize Smileys",IDC_RESIZE_SMILEYS,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,105,60,96,14 + CONTROL "Global on status message",IDC_GLOBAL_ON_STATUS_MESSAGE, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,207,61,96,14 + GROUPBOX " Avatar ",IDC_STATIC,7,80,302,59 + CONTROL "Draw border on avatar",IDC_AVATAR_DRAW_BORDER,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,16,95,103,9 + LTEXT "Border Color:",IDC_AVATAR_BORDER_COLOR_L,123,95,53,10 + CONTROL "",IDC_AVATAR_BORDER_COLOR,"ColourPicker",WS_TABSTOP,180, + 92,17,13 + CONTROL "Round corners of avatars",IDC_AVATAR_ROUND_CORNERS, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,16,109,280,8 + CONTROL "Custom corner size:", + IDC_AVATAR_CUSTOM_CORNER_SIZE_CHECK,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,27,122,93,11 + EDITTEXT IDC_AVATAR_CUSTOM_CORNER_SIZE,127,121,35,12,ES_NUMBER + CONTROL "",IDC_AVATAR_CUSTOM_CORNER_SIZE_SPIN,"msctls_updown32", + UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_ARROWKEYS | + UDS_NOTHOUSANDS | UDS_HOTTRACK,165,121,11,12 + LTEXT "pixels",IDC_STATIC,179,124,41,11 +END + +IDD_SETSTATUSMESSAGE DIALOG DISCARDABLE 0, 0, 283, 68 +STYLE DS_MODALFRAME | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_CAPTION | + WS_SYSMENU +CAPTION "Set My Status Message for All Status" +FONT 8, "MS Shell Dlg" +BEGIN + RTEXT "Status Message:",IDC_STATIC,7,8,69,12 + EDITTEXT IDC_STATUSMESSAGE,81,7,195,35,ES_MULTILINE | + ES_AUTOVSCROLL | ES_WANTRETURN | WS_VSCROLL + DEFPUSHBUTTON "OK",IDOK,87,47,50,14 + PUSHBUTTON "Cancel",IDCANCEL,146,47,50,14 +END + + +///////////////////////////////////////////////////////////////////////////// +// +// DESIGNINFO +// + +#ifdef APSTUDIO_INVOKED +GUIDELINES DESIGNINFO DISCARDABLE +BEGIN + IDD_SETNICKNAME, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 276 + TOPMARGIN, 7 + BOTTOMMARGIN, 58 + END + + IDD_OPTS, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 309 + TOPMARGIN, 7 + BOTTOMMARGIN, 238 + END + + IDD_SETSTATUSMESSAGE, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 276 + TOPMARGIN, 7 + BOTTOMMARGIN, 61 + END +END +#endif // APSTUDIO_INVOKED + +#endif // English (U.S.) resources +///////////////////////////////////////////////////////////////////////////// + + +///////////////////////////////////////////////////////////////////////////// +// Portuguese (Brazil) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_PTB) +#ifdef _WIN32 +LANGUAGE LANG_PORTUGUESE, SUBLANG_PORTUGUESE_BRAZILIAN +#pragma code_page(1252) +#endif //_WIN32 + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE DISCARDABLE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE DISCARDABLE +BEGIN + "#include ""afxres.h""\r\n" + "#include ""../../include/statusmodes.h""\r\n" + "\0" +END + +3 TEXTINCLUDE DISCARDABLE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Menu +// + +IDR_MENU1 MENU DISCARDABLE +BEGIN + POPUP "Status popup" + BEGIN + MENUITEM "&Offline", ID_STATUS_OFFLINE + MENUITEM "On&line", ID_STATUS_ONLINE + MENUITEM "&Away", ID_STATUS_AWAY + MENUITEM "&NA", ID_STATUS_NA + MENUITEM "Occ&upied", ID_STATUS_OCCUPIED + MENUITEM "&DND", ID_STATUS_DND + MENUITEM "&Free for chat", ID_STATUS_FREECHAT + MENUITEM "&Invisible", ID_STATUS_INVISIBLE + MENUITEM "On the &Phone", ID_STATUS_ONTHEPHONE + MENUITEM "Out to &Lunch", ID_STATUS_OUTTOLUNCH + END + POPUP "Context popup" + BEGIN + MENUITEM SEPARATOR + MENUITEM "Set My Avatar...", ID_AVATARPOPUP_SETMYAVATAR + MENUITEM "Set My Nickname...", ID_NICKPOPUP_SETMYNICKNAME + MENUITEM "Set My Status Message...", ID_STATUSMESSAGEPOPUP_SETMYSTATUSMESSAGE + + MENUITEM "Enable Listening To", ID_CONTEXTPOPUP_ENABLELISTENINGTO + + MENUITEM SEPARATOR + MENUITEM "Show next protocol", ID_SHOW_NEXT_PROTO + MENUITEM "Show previous protocol", ID_SHOW_PREV_PROTO + MENUITEM SEPARATOR + MENUITEM "Cycle through protocols", ID_CYCLE_THROUGH_PROTOS + MENUITEM "Don't cycle through protocols", + ID_DONT_CYCLE_THROUGH_PROTOS + END + POPUP "Nick popup" + BEGIN + MENUITEM SEPARATOR + MENUITEM "Set My Nickname...", ID_NICKPOPUP_SETMYNICKNAME + END + POPUP "Status message popup" + BEGIN + MENUITEM SEPARATOR + MENUITEM "Set My Status Message...", ID_STATUSMESSAGEPOPUP_SETMYSTATUSMESSAGE + + END + POPUP "Avatar popup" + BEGIN + MENUITEM SEPARATOR + MENUITEM "Set My Avatar...", ID_AVATARPOPUP_SETMYAVATAR + END + POPUP "ListeningTo popup" + BEGIN + MENUITEM SEPARATOR + MENUITEM "Enable Listening To", ID_LISTENINGTOPOPUP_SENDLISTENINGTO + + END +END + +#endif // Portuguese (Brazil) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/plugins/Skins/Docs/langpack_skins.txt b/plugins/Skins/Docs/langpack_skins.txt new file mode 100644 index 0000000000..1819d74fce --- /dev/null +++ b/plugins/Skins/Docs/langpack_skins.txt @@ -0,0 +1,2 @@ +; Skins +; Author: Pescuma diff --git a/plugins/Skins/Docs/skins_changelog.txt b/plugins/Skins/Docs/skins_changelog.txt new file mode 100644 index 0000000000..fcaa8da44c --- /dev/null +++ b/plugins/Skins/Docs/skins_changelog.txt @@ -0,0 +1,25 @@ +Skins + +Changelog: + +. 0.0.0.5 + + Allow changing skins + * Updated v8 + * Updated updater to use googlecode + +. 0.0.0.4 + * Fixed font service iteration + * Fixed naming of skin options + +. 0.0.0.3 + * Better handling of small sizes + +. 0.0.0.2 + * Fix for float numbers + + Added valign (not used yet) + + Added dialog info (allow clients to set script variables starting with info) + + The zip will contain also the pdbs (at least until it is more stable) + * Fix for ASCII strings + +. 0.0.0.1 + + Initial version \ No newline at end of file diff --git a/plugins/Skins/Docs/skins_readme.txt b/plugins/Skins/Docs/skins_readme.txt new file mode 100644 index 0000000000..fd06309ad1 --- /dev/null +++ b/plugins/Skins/Docs/skins_readme.txt @@ -0,0 +1,31 @@ +Skins plugin +---------------- + +CAUTION: THIS IS AN ALPHA STAGE PLUGIN. IT CAN DO VERY BAD THINGS. USE AT YOUR OWN RISK. + +This is a service plugin to allow using different skins. It uses javascript as the language the skins are written, thus allowing a lot of flexibility. + +Keep in mind that this is an initial version of the plugin. It is intended to grow a loot (its to do list is bigger than its features list :P ). Currently it allows only calculating the position of elements. + +It works based in the consept of a skin beeing a group of small skins (one for each client). The skins are inside the dir \Skins\ , and inside that folder, each client skin has the name .msk + +Inside the zip there is also a version of MyDetails using this plugin. + +Many thanks to the v8 team for the javascript engine implementation. + +This needs Miranda 0.8 to work. + +To report bugs/make suggestions, go to the forum thread: http://forums.miranda-im.org/showthread.php?p=172392 + + +TODO: + - Allow changing skin without restart + - Add support for handling skin packs + - Add support for emoticons in text fields + - Add code to draw elements on screen + - Add service to create a new frame only based on the fields + - Allow setting variables by the users of the plugin + + +KNOWN PROBLEMS: + - It seems to have a memory leak (last time I debugged it, it was inside v8 - maybe I just don't understant its garbage collector?) diff --git a/plugins/Skins/Docs/skins_version.txt b/plugins/Skins/Docs/skins_version.txt new file mode 100644 index 0000000000..92fad2b10f --- /dev/null +++ b/plugins/Skins/Docs/skins_version.txt @@ -0,0 +1 @@ +Skins 0.0.0.5 \ No newline at end of file diff --git a/plugins/Skins/MirandaField.h b/plugins/Skins/MirandaField.h new file mode 100644 index 0000000000..d89901c77d --- /dev/null +++ b/plugins/Skins/MirandaField.h @@ -0,0 +1,14 @@ +#ifndef __MIRANDA_FIELD_H__ +# define __MIRANDA_FIELD_H__ + + +class MirandaField +{ +public: + virtual void configure() = 0; +}; + + + + +#endif // __MIRANDA_FIELD_H__ diff --git a/plugins/Skins/MirandaFont.cpp b/plugins/Skins/MirandaFont.cpp new file mode 100644 index 0000000000..51b0f34f9b --- /dev/null +++ b/plugins/Skins/MirandaFont.cpp @@ -0,0 +1,87 @@ +#include "MirandaFont.h" + +MirandaFont::MirandaFont(Field *aField, const char *description) + : field(aField), hFont(NULL) +{ + ZeroMemory(&fid, sizeof(fid)); + lstrcpyn(fid.name, CharToTchar(description), sizeof(fid.name)); +} + +MirandaFont::~MirandaFont() +{ + releaseFont(); +} + +void MirandaFont::registerFont(FontState *font) +{ + if (fid.cbSize != 0) + return; + + MirandaSkinnedDialog * dlg = (MirandaSkinnedDialog *) field->getDialog(); + + HDC hdc = GetDC(NULL); + + fid.cbSize = sizeof(fid); + lstrcpyn(fid.group, CharToTchar(dlg->getDescription()), sizeof(fid.group)); + strncpy(fid.dbSettingsGroup, dlg->getModule(), sizeof(fid.dbSettingsGroup)); + + char tmp[sizeof(fid.prefix)]; + mir_snprintf(tmp, sizeof(tmp), "%s%s%sFont", TcharToChar(dlg->getSkinName()), dlg->getName(), field->getName()); + strncpy(fid.prefix, tmp, sizeof(fid.prefix)); + + fid.deffontsettings.colour = font->getColor(); + fid.deffontsettings.size = -MulDiv(font->getSize(), GetDeviceCaps(hdc, LOGPIXELSY), 72); + fid.deffontsettings.style = (font->isBold() ? DBFONTF_BOLD : 0) + | (font->isItalic() ? DBFONTF_ITALIC : 0) + | (font->isUnderline() ? DBFONTF_UNDERLINE : 0) + | (font->isStrikeOut() ? DBFONTF_STRIKEOUT : 0); + fid.deffontsettings.charset = DEFAULT_CHARSET; + lstrcpyn(fid.deffontsettings.szFace, font->getFace(), sizeof(fid.deffontsettings.szFace)); + fid.order = dlg->getIndexOf(field); + fid.flags = FIDF_DEFAULTVALID | FIDF_ALLOWEFFECTS; + + CallService(MS_FONT_REGISTERT, (WPARAM)&fid, 0); + + ReleaseDC(NULL, hdc); + + HookEventObj(ME_FONT_RELOAD, staticReloadFont, this); + + reloadFont(); +} + +void MirandaFont::reloadFont() +{ + releaseFont(); + + LOGFONT log_font; + COLORREF color = (COLORREF) CallService(MS_FONT_GETT, (WPARAM) &fid, (LPARAM) &log_font); + hFont = CreateFontIndirect(&log_font); + + switch(field->getType()) + { + case SIMPLE_TEXT: + ((TextField *) field)->setFontColor(color); + ((TextField *) field)->setFont(hFont); + break; + case CONTROL_LABEL: + case CONTROL_BUTTON: + case CONTROL_EDIT: + ((ControlField *) field)->setFont(hFont); + break; + } +} + +int MirandaFont::staticReloadFont(void *obj, WPARAM wParam, LPARAM lParam) +{ + ((MirandaFont *) obj)->reloadFont(); + return 0; +} + +void MirandaFont::releaseFont() +{ + if (hFont != NULL) + { + DeleteObject(hFont); + hFont = NULL; + } +} \ No newline at end of file diff --git a/plugins/Skins/MirandaFont.h b/plugins/Skins/MirandaFont.h new file mode 100644 index 0000000000..da9a40a06e --- /dev/null +++ b/plugins/Skins/MirandaFont.h @@ -0,0 +1,28 @@ +#ifndef __MIRANDA_FONT_H__ +# define __MIRANDA_FONT_H__ + +#include "commons.h" + + +class MirandaFont +{ +public: + MirandaFont(Field *field, const char *description); + ~MirandaFont(); + + void registerFont(FontState *font); + void reloadFont(); + +private: + FontIDT fid; + HFONT hFont; + Field *field; + + void releaseFont(); + + static int staticReloadFont(void *obj, WPARAM wParam, LPARAM lParam); +}; + + + +#endif // __MIRANDA_FONT_H__ diff --git a/plugins/Skins/MirandaIconField.cpp b/plugins/Skins/MirandaIconField.cpp new file mode 100644 index 0000000000..7861e11091 --- /dev/null +++ b/plugins/Skins/MirandaIconField.cpp @@ -0,0 +1,19 @@ +#include "MirandaIconField.h" + +MirandaIconField::MirandaIconField(MirandaSkinnedDialog *dlg, const char *name, const char *description) + : IconField(dlg, name) +{ +} + +MirandaIconField::~MirandaIconField() +{ +} + +MirandaSkinnedDialog * MirandaIconField::getDialog() const +{ + return (MirandaSkinnedDialog *) IconField::getDialog(); +} + +void MirandaIconField::configure() +{ +} \ No newline at end of file diff --git a/plugins/Skins/MirandaIconField.h b/plugins/Skins/MirandaIconField.h new file mode 100644 index 0000000000..0f6f15af9e --- /dev/null +++ b/plugins/Skins/MirandaIconField.h @@ -0,0 +1,21 @@ +#ifndef __MIRANDA_ICON_FIELD_H__ +# define __MIRANDA_ICON_FIELD_H__ + +#include "commons.h" +#include "MirandaField.h" + + +class MirandaIconField : public IconField, public MirandaField +{ +public: + MirandaIconField(MirandaSkinnedDialog *dlg, const char *name, const char *description); + virtual ~MirandaIconField(); + + virtual MirandaSkinnedDialog * getDialog() const; + + virtual void configure(); +}; + + + +#endif // __MIRANDA_ICON_FIELD_H__ diff --git a/plugins/Skins/MirandaImageField.cpp b/plugins/Skins/MirandaImageField.cpp new file mode 100644 index 0000000000..2c9efe11f2 --- /dev/null +++ b/plugins/Skins/MirandaImageField.cpp @@ -0,0 +1,19 @@ +#include "MirandaImageField.h" + +MirandaImageField::MirandaImageField(MirandaSkinnedDialog *dlg, const char *name, const char *description) + : ImageField(dlg, name) +{ +} + +MirandaImageField::~MirandaImageField() +{ +} + +MirandaSkinnedDialog * MirandaImageField::getDialog() const +{ + return (MirandaSkinnedDialog *) ImageField::getDialog(); +} + +void MirandaImageField::configure() +{ +} \ No newline at end of file diff --git a/plugins/Skins/MirandaImageField.h b/plugins/Skins/MirandaImageField.h new file mode 100644 index 0000000000..70cd1ce873 --- /dev/null +++ b/plugins/Skins/MirandaImageField.h @@ -0,0 +1,21 @@ +#ifndef __MIRANDA_IMAGE_FIELD_H__ +# define __MIRANDA_IMAGE_FIELD_H__ + +#include "commons.h" +#include "MirandaField.h" + + +class MirandaImageField : public ImageField, public MirandaField +{ +public: + MirandaImageField(MirandaSkinnedDialog *dlg, const char *name, const char *description); + virtual ~MirandaImageField(); + + virtual MirandaSkinnedDialog * getDialog() const; + + virtual void configure(); +}; + + +#endif // __MIRANDA_IMAGE_FIELD_H__ + diff --git a/plugins/Skins/MirandaSkinnedDialog.cpp b/plugins/Skins/MirandaSkinnedDialog.cpp new file mode 100644 index 0000000000..97bf236a5a --- /dev/null +++ b/plugins/Skins/MirandaSkinnedDialog.cpp @@ -0,0 +1,252 @@ +#include "commons.h" +#include "MirandaSkinnedDialog.h" + +#define SETTING_NAME_SIZE 256 + + +MirandaSkinnedDialog::MirandaSkinnedDialog(const char *name, const char *aDescription, const char *aModule) + : SkinnedDialog(name), description(aDescription), module(aModule), + skinChangedCallback(NULL), skinChangedCallbackParam(NULL) +{ + getSettting("Skin", _T(DEFAULT_SKIN_NAME), skinName, true); +} + +MirandaSkinnedDialog::~MirandaSkinnedDialog() +{ +} + +const char * MirandaSkinnedDialog::getDescription() const +{ + return description.c_str(); +} + +const char * MirandaSkinnedDialog::getModule() const +{ + return module.c_str(); +} + +const TCHAR * MirandaSkinnedDialog::getSkinName() const +{ + return skinName.c_str(); +} + +void MirandaSkinnedDialog::setSkinName(const TCHAR *name) +{ + if (skinName == name) + return; + + skinName = name; + setSettting("Skin", skinName.c_str(), true); + updateFilename(); +} + +bool MirandaSkinnedDialog::finishedConfiguring() +{ + updateFilename(); + + if (getDefaultState() == NULL || getOpts() == NULL) + return false; + + return true; +} + +void MirandaSkinnedDialog::updateFilename() +{ + std::tstring filename; + getSkinnedDialogFilename(filename, getSkinName(), getName()); + setFilename(filename.c_str()); +} + +void MirandaSkinnedDialog::loadFromDB(SkinOption *opt) +{ + switch(opt->getType()) + { + case CHECKBOX: + { + opt->setValueCheckbox(getSettting(opt->getName(), opt->getValueCheckbox())); + break; + } + case NUMBER: + { + opt->setValueNumber(getSettting(opt->getName(), opt->getValueNumber())); + break; + } + case TEXT: + { + std::tstring tmp; + getSettting(opt->getName(), opt->getValueText(), tmp); + opt->setValueText(tmp.c_str()); + break; + } + } +} + +void MirandaSkinnedDialog::storeToDB(const SkinOptions *opts) +{ + for (unsigned int i = 0; i < opts->getNumOptions(); i++) + storeToDB(opts->getOption(i)); + + fireOnSkinChanged(); +} + +void MirandaSkinnedDialog::storeToDB(const SkinOption *opt) +{ + switch(opt->getType()) + { + case CHECKBOX: + { + setSettting(opt->getName(), opt->getValueCheckbox()); + break; + } + case NUMBER: + { + setSettting(opt->getName(), opt->getValueNumber()); + break; + } + case TEXT: + { + setSettting(opt->getName(), opt->getValueText()); + break; + } + } +} + +bool MirandaSkinnedDialog::getSettting(const char *name, bool defVal, bool global) +{ + char setting[SETTING_NAME_SIZE]; + getSettingName(setting, name, global); + + return DBGetContactSettingByte(NULL, getModule(), setting, defVal ? 1 : 0) != 0; +} + +void MirandaSkinnedDialog::setSettting(const char *name, bool val, bool global) +{ + char setting[SETTING_NAME_SIZE]; + getSettingName(setting, name, global); + + DBWriteContactSettingByte(NULL, getModule(), setting, val ? 1 : 0); +} + +int MirandaSkinnedDialog::getSettting(const char *name, int defVal, bool global) +{ + char setting[SETTING_NAME_SIZE]; + getSettingName(setting, name, global); + + return DBGetContactSettingDword(NULL, getModule(), setting, defVal); +} + +void MirandaSkinnedDialog::setSettting(const char *name, int val, bool global) +{ + char setting[SETTING_NAME_SIZE]; + getSettingName(setting, name, global); + + DBWriteContactSettingDword(NULL, getModule(), setting, val); +} + +void MirandaSkinnedDialog::getSettting(const char *name, const WCHAR *defVal, std::wstring &ret, bool global) +{ + char setting[SETTING_NAME_SIZE]; + getSettingName(setting, name, global); + + DBVARIANT dbv = {0}; + if (DBGetContactSettingWString(NULL, getModule(), setting, &dbv)) + { + ret = defVal; + return; + } + + ret = dbv.pwszVal; + DBFreeVariant(&dbv); +} + +void MirandaSkinnedDialog::setSettting(const char *name, const WCHAR *val, bool global) +{ + char setting[SETTING_NAME_SIZE]; + getSettingName(setting, name, global); + + DBWriteContactSettingWString(NULL, getModule(), setting, val); +} + +void MirandaSkinnedDialog::getSettting(const char *name, const char *defVal, std::string &ret, bool global) +{ + char setting[SETTING_NAME_SIZE]; + getSettingName(setting, name, global); + + DBVARIANT dbv = {0}; + if (DBGetContactSettingString(NULL, getModule(), setting, &dbv)) + { + ret = defVal; + return; + } + + ret = dbv.pszVal; + DBFreeVariant(&dbv); +} + +void MirandaSkinnedDialog::setSettting(const char *name, const char *val, bool global) +{ + char setting[SETTING_NAME_SIZE]; + getSettingName(setting, name, global); + + DBWriteContactSettingString(NULL, getModule(), setting, val); +} + +void MirandaSkinnedDialog::getSettingName(char *setting, const char * name, bool global) +{ + if (global) + mir_snprintf(setting, SETTING_NAME_SIZE, "%s%s", getName(), name); + else + mir_snprintf(setting, SETTING_NAME_SIZE, "%s%s%s", TcharToChar(getSkinName()), getName(), name); +} + +void MirandaSkinnedDialog::setOnSkinChangedCallback(MirandaSkinnedCallback cb, void *param) +{ + skinChangedCallback = cb; + skinChangedCallbackParam = param; +} + +void MirandaSkinnedDialog::fireOnSkinChanged() +{ + if (skinChangedCallback != NULL) + skinChangedCallback(skinChangedCallbackParam, this); +} + +int MirandaSkinnedDialog::compile() +{ + int ret = SkinnedDialog::compile(); + + if (ret == 2) + { + SkinOptions * opts = getOpts(); + _ASSERT(opts != NULL); + + for(unsigned int i = 0; i < opts->getNumOptions(); ++i) + { + SkinOption *opt = opts->getOption(i); + loadFromDB(opt); + opt->setOnChangeCallback(&staticOnOptionChange, this); + } + + for(unsigned int i = 0; i < getFieldCount(); ++i) + { + MirandaField *field = dynamic_cast(getField(i)); + field->configure(); + } + + fireOnSkinChanged(); + } + + return ret; +} + +void MirandaSkinnedDialog::onOptionChange(const SkinOption *opt) +{ + storeToDB(opt); +} + +void MirandaSkinnedDialog::staticOnOptionChange(void *param, const SkinOption *opt) +{ + _ASSERT(param != NULL); + + ((MirandaSkinnedDialog *) param)->onOptionChange(opt); +} diff --git a/plugins/Skins/MirandaSkinnedDialog.h b/plugins/Skins/MirandaSkinnedDialog.h new file mode 100644 index 0000000000..d556b9a495 --- /dev/null +++ b/plugins/Skins/MirandaSkinnedDialog.h @@ -0,0 +1,64 @@ +#ifndef __MIRANDA_SKINNED_DIALOG_H__ +# define __MIRANDA_SKINNED_DIALOG_H__ + +#include "SkinLib\SkinnedDialog.h" + +class SkinOption; +class MirandaSkinnedDialog; + +typedef void (*MirandaSkinnedCallback)(void *param, const MirandaSkinnedDialog *dlg); + + +class MirandaSkinnedDialog : public SkinnedDialog +{ +public: + MirandaSkinnedDialog(const char *name, const char *description, const char *module); + virtual ~MirandaSkinnedDialog(); + + virtual const char * getDescription() const; + virtual const char * getModule() const; + + virtual const TCHAR * getSkinName() const; + virtual void setSkinName(const TCHAR *name); + + virtual bool finishedConfiguring(); + + virtual void storeToDB(const SkinOptions *opts); + + virtual void setOnSkinChangedCallback(MirandaSkinnedCallback cb, void *param); + +protected: + virtual int compile(); + +private: + std::string description; + std::string module; + std::tstring skinName; + MirandaSkinnedCallback skinChangedCallback; + void *skinChangedCallbackParam; + + void updateFilename(); + + void loadFromDB(SkinOption *opt); + void storeToDB(const SkinOption *opt); + + bool getSettting(const char *name, bool defVal, bool global = false); + void setSettting(const char *name, bool val, bool global = false); + int getSettting(const char *name, int defVal, bool global = false); + void setSettting(const char *name, int val, bool global = false); + void getSettting(const char *name, const WCHAR *defVal, std::wstring &ret, bool global = false); + void setSettting(const char *name, const WCHAR *val, bool global = false); + void getSettting(const char *name, const char *defVal, std::string &ret, bool global = false); + void setSettting(const char *name, const char *val, bool global = false); + + inline void getSettingName(char *setting, const char * name, bool global); + + void fireOnSkinChanged(); + + void onOptionChange(const SkinOption *opt); + + static void staticOnOptionChange(void *param, const SkinOption *opt); +}; + + +#endif // __MIRANDA_SKINNED_DIALOG_H__ diff --git a/plugins/Skins/MirandaTextField.cpp b/plugins/Skins/MirandaTextField.cpp new file mode 100644 index 0000000000..4a3591a322 --- /dev/null +++ b/plugins/Skins/MirandaTextField.cpp @@ -0,0 +1,27 @@ +#include "MirandaTextField.h" +#include "MirandaFont.h" + + +MirandaTextField::MirandaTextField(MirandaSkinnedDialog *dlg, const char *name, const char *aDescription) + : TextField(dlg, name) +{ + font = new MirandaFont(this, aDescription); +} + +MirandaTextField::~MirandaTextField() +{ + delete font; +} + +MirandaSkinnedDialog * MirandaTextField::getDialog() const +{ + return (MirandaSkinnedDialog *) TextField::getDialog(); +} + +void MirandaTextField::configure() +{ + TextFieldState *field = (TextFieldState *) getDialog()->getDefaultState()->getField(getName()); + _ASSERT(field != NULL); + + font->registerFont(field->getFont()); +} diff --git a/plugins/Skins/MirandaTextField.h b/plugins/Skins/MirandaTextField.h new file mode 100644 index 0000000000..36b7ea7292 --- /dev/null +++ b/plugins/Skins/MirandaTextField.h @@ -0,0 +1,27 @@ +#ifndef __MIRANDA_TEXT_FIELD_H__ +# define __MIRANDA_TEXT_FIELD_H__ + +#include "commons.h" +#include "MirandaField.h" + +class MirandaFont; + + +class MirandaTextField : public TextField, public MirandaField +{ +public: + MirandaTextField(MirandaSkinnedDialog *dlg, const char *name, const char *description); + virtual ~MirandaTextField(); + + virtual MirandaSkinnedDialog * getDialog() const; + + virtual void configure(); + +private: + MirandaFont *font; + +}; + + + +#endif // __MIRANDA_TEXT_FIELD_H__ diff --git a/plugins/Skins/SkinLib/BorderState.cpp b/plugins/Skins/SkinLib/BorderState.cpp new file mode 100644 index 0000000000..83dcdbcf11 --- /dev/null +++ b/plugins/Skins/SkinLib/BorderState.cpp @@ -0,0 +1,61 @@ +#include "globals.h" +#include +#include "BorderState.h" + +BorderState::BorderState(int aLeft, int aRight, int aTop, int aBottom) + : left(aLeft), right(aRight), top(aTop), bottom(aBottom) +{ +} + +BorderState::~BorderState() +{ +} + +int BorderState::getLeft() const +{ + return left; +} + +void BorderState::setLeft(int left) +{ + this->left = max(0, left); +} + +int BorderState::getRight() const +{ + return right; +} + +void BorderState::setRight(int right) +{ + this->right = max(0, right); +} + +int BorderState::getTop() const +{ + return top; +} + +void BorderState::setTop(int top) +{ + this->top = max(0, top); +} + +int BorderState::getBottom() const +{ + return bottom; +} + +void BorderState::setBottom(int bottom) +{ + this->bottom = max(0, bottom); +} + +void BorderState::setAll(int border) +{ + border = max(0, border); + left = border; + right = border; + top = border; + bottom = border; +} diff --git a/plugins/Skins/SkinLib/BorderState.h b/plugins/Skins/SkinLib/BorderState.h new file mode 100644 index 0000000000..2cac3c1aa5 --- /dev/null +++ b/plugins/Skins/SkinLib/BorderState.h @@ -0,0 +1,28 @@ +#pragma once + +class BorderState +{ +public: + BorderState(int left, int right, int top, int bottom); + ~BorderState(); + + int getLeft() const; + void setLeft(int left); + + int getRight() const; + void setRight(int right); + + int getTop() const; + void setTop(int top); + + int getBottom() const; + void setBottom(int bottom); + + void setAll(int border); + +private: + int left; + int right; + int top; + int bottom; +}; diff --git a/plugins/Skins/SkinLib/BorderState_v8_wrapper.cpp b/plugins/Skins/SkinLib/BorderState_v8_wrapper.cpp new file mode 100644 index 0000000000..71cc057419 --- /dev/null +++ b/plugins/Skins/SkinLib/BorderState_v8_wrapper.cpp @@ -0,0 +1,160 @@ +#include "globals.h" +#include "BorderState_v8_wrapper.h" +#include +#include "BorderState.h" + +using namespace v8; + + +#ifdef UNICODE +# define V8_TCHAR uint16_t +#else +# define V8_TCHAR char +#endif + + +static Handle Get_BorderState_left(Local property, const AccessorInfo &info) +{ + HandleScope scope; + + Local self = info.Holder(); + Local wrap = Local::Cast(self->GetInternalField(0)); + if (wrap.IsEmpty()) + return scope.Close( Undefined() ); + + BorderState *tmp = (BorderState *) wrap->Value(); + if (tmp == NULL) + return scope.Close( Undefined() ); + + return scope.Close( Int32::New(tmp->getLeft()) ); +} + +static void Set_BorderState_left(Local property, Local value, const AccessorInfo& info) +{ + HandleScope scope; + + Local self = info.Holder(); + Local wrap = Local::Cast(self->GetInternalField(0)); + if (wrap.IsEmpty()) + return; + + BorderState *tmp = (BorderState *) wrap->Value(); + if (tmp == NULL) + return; + + if (!value.IsEmpty() && value->IsNumber()) + tmp->setLeft(value->Int32Value()); +} + + +static Handle Get_BorderState_right(Local property, const AccessorInfo &info) +{ + HandleScope scope; + + Local self = info.Holder(); + Local wrap = Local::Cast(self->GetInternalField(0)); + if (wrap.IsEmpty()) + return scope.Close( Undefined() ); + + BorderState *tmp = (BorderState *) wrap->Value(); + if (tmp == NULL) + return scope.Close( Undefined() ); + + return scope.Close( Int32::New(tmp->getRight()) ); +} + +static void Set_BorderState_right(Local property, Local value, const AccessorInfo& info) +{ + HandleScope scope; + + Local self = info.Holder(); + Local wrap = Local::Cast(self->GetInternalField(0)); + if (wrap.IsEmpty()) + return; + + BorderState *tmp = (BorderState *) wrap->Value(); + if (tmp == NULL) + return; + + if (!value.IsEmpty() && value->IsNumber()) + tmp->setRight(value->Int32Value()); +} + + +static Handle Get_BorderState_top(Local property, const AccessorInfo &info) +{ + HandleScope scope; + + Local self = info.Holder(); + Local wrap = Local::Cast(self->GetInternalField(0)); + if (wrap.IsEmpty()) + return scope.Close( Undefined() ); + + BorderState *tmp = (BorderState *) wrap->Value(); + if (tmp == NULL) + return scope.Close( Undefined() ); + + return scope.Close( Int32::New(tmp->getTop()) ); +} + +static void Set_BorderState_top(Local property, Local value, const AccessorInfo& info) +{ + HandleScope scope; + + Local self = info.Holder(); + Local wrap = Local::Cast(self->GetInternalField(0)); + if (wrap.IsEmpty()) + return; + + BorderState *tmp = (BorderState *) wrap->Value(); + if (tmp == NULL) + return; + + if (!value.IsEmpty() && value->IsNumber()) + tmp->setTop(value->Int32Value()); +} + + +static Handle Get_BorderState_bottom(Local property, const AccessorInfo &info) +{ + HandleScope scope; + + Local self = info.Holder(); + Local wrap = Local::Cast(self->GetInternalField(0)); + if (wrap.IsEmpty()) + return scope.Close( Undefined() ); + + BorderState *tmp = (BorderState *) wrap->Value(); + if (tmp == NULL) + return scope.Close( Undefined() ); + + return scope.Close( Int32::New(tmp->getBottom()) ); +} + +static void Set_BorderState_bottom(Local property, Local value, const AccessorInfo& info) +{ + HandleScope scope; + + Local self = info.Holder(); + Local wrap = Local::Cast(self->GetInternalField(0)); + if (wrap.IsEmpty()) + return; + + BorderState *tmp = (BorderState *) wrap->Value(); + if (tmp == NULL) + return; + + if (!value.IsEmpty() && value->IsNumber()) + tmp->setBottom(value->Int32Value()); +} + + +void AddBorderStateAcessors(Handle &templ) +{ + HandleScope scope; + + templ->SetAccessor(String::New("left"), Get_BorderState_left, Set_BorderState_left); + templ->SetAccessor(String::New("right"), Get_BorderState_right, Set_BorderState_right); + templ->SetAccessor(String::New("top"), Get_BorderState_top, Set_BorderState_top); + templ->SetAccessor(String::New("bottom"), Get_BorderState_bottom, Set_BorderState_bottom); +} diff --git a/plugins/Skins/SkinLib/BorderState_v8_wrapper.h b/plugins/Skins/SkinLib/BorderState_v8_wrapper.h new file mode 100644 index 0000000000..70af9e41dc --- /dev/null +++ b/plugins/Skins/SkinLib/BorderState_v8_wrapper.h @@ -0,0 +1,10 @@ +#ifndef __BORDER_STATE_V8_WRAPPER_H__ +# define __BORDER_STATE_V8_WRAPPER_H__ + +#include + +void AddBorderStateAcessors(v8::Handle &templ); + + + +#endif // __BORDER_STATE_V8_WRAPPER_H__ diff --git a/plugins/Skins/SkinLib/ButtonField.cpp b/plugins/Skins/SkinLib/ButtonField.cpp new file mode 100644 index 0000000000..e6c82ba5e3 --- /dev/null +++ b/plugins/Skins/SkinLib/ButtonField.cpp @@ -0,0 +1,22 @@ +#include "globals.h" +#include "ButtonField.h" +#include "ButtonFieldState.h" + + +ButtonField::ButtonField(Dialog *dlg, const char *name, HWND hwnd) : ControlField(dlg, name, hwnd) +{ +} + +ButtonField::~ButtonField() +{ +} + +FieldType ButtonField::getType() const +{ + return CONTROL_BUTTON; +} + +FieldState * ButtonField::createState(DialogState *dialogState) +{ + return new ButtonFieldState(dialogState, this); +} \ No newline at end of file diff --git a/plugins/Skins/SkinLib/ButtonField.h b/plugins/Skins/SkinLib/ButtonField.h new file mode 100644 index 0000000000..0d7a1555ca --- /dev/null +++ b/plugins/Skins/SkinLib/ButtonField.h @@ -0,0 +1,19 @@ +#ifndef __BUTTON_FIELD_H__ +# define __BUTTON_FIELD_H__ + +#include "ControlField.h" + +class ButtonField : public ControlField +{ +public: + ButtonField(Dialog *dlg, const char *name, HWND hwnd); + virtual ~ButtonField(); + + virtual FieldType getType() const; + + virtual FieldState * createState(DialogState *dialogState); +}; + + + +#endif // __BUTTON_FIELD_H__ diff --git a/plugins/Skins/SkinLib/ButtonFieldState.cpp b/plugins/Skins/SkinLib/ButtonFieldState.cpp new file mode 100644 index 0000000000..986484b20b --- /dev/null +++ b/plugins/Skins/SkinLib/ButtonFieldState.cpp @@ -0,0 +1,30 @@ +#include "globals.h" +#include "ButtonFieldState.h" + +ButtonFieldState::ButtonFieldState(DialogState *dialog, ControlField *field) + : ControlFieldState(dialog, field) +{ +} + +ButtonFieldState::~ButtonFieldState() +{ +} + +Size ButtonFieldState::getPreferedSize() const +{ + Size ret = getTextPreferedSize(DT_SINGLELINE); + + int border = getField()->getBorderSize(); + ret.x += 2 * border; + ret.y += 2 * border; + + ret.x += 12; + ret.y += 10; + + return ret; +} + +bool ButtonFieldState::isEmpty() const +{ + return false; +} \ No newline at end of file diff --git a/plugins/Skins/SkinLib/ButtonFieldState.h b/plugins/Skins/SkinLib/ButtonFieldState.h new file mode 100644 index 0000000000..12b701035a --- /dev/null +++ b/plugins/Skins/SkinLib/ButtonFieldState.h @@ -0,0 +1,23 @@ +#ifndef __BUTTON_FIELD_STATE_H__ +# define __BUTTON_FIELD_STATE_H__ + +#include "ControlFieldState.h" + + +class ButtonFieldState : public ControlFieldState +{ +public: + virtual ~ButtonFieldState(); + + virtual Size getPreferedSize() const; + + virtual bool isEmpty() const; + +private: + ButtonFieldState(DialogState *dialog, ControlField *field); + + friend class ButtonField; +}; + + +#endif // __BUTTON_FIELD_STATE_H__ diff --git a/plugins/Skins/SkinLib/ButtonFieldState_v8_wrapper.cpp b/plugins/Skins/SkinLib/ButtonFieldState_v8_wrapper.cpp new file mode 100644 index 0000000000..c5916b284c --- /dev/null +++ b/plugins/Skins/SkinLib/ButtonFieldState_v8_wrapper.cpp @@ -0,0 +1,20 @@ +#include "globals.h" +#include "ButtonFieldState_v8_wrapper.h" +#include +#include "ButtonFieldState.h" + +using namespace v8; + + +#ifdef UNICODE +# define V8_TCHAR uint16_t +#else +# define V8_TCHAR char +#endif + + +void AddButtonFieldStateAcessors(Handle &templ) +{ + HandleScope scope; + +} diff --git a/plugins/Skins/SkinLib/ButtonFieldState_v8_wrapper.h b/plugins/Skins/SkinLib/ButtonFieldState_v8_wrapper.h new file mode 100644 index 0000000000..c69fdc5c87 --- /dev/null +++ b/plugins/Skins/SkinLib/ButtonFieldState_v8_wrapper.h @@ -0,0 +1,10 @@ +#ifndef __BUTTON_FIELD_STATE_V8_WRAPPER_H__ +# define __BUTTON_FIELD_STATE_V8_WRAPPER_H__ + +#include + +void AddButtonFieldStateAcessors(v8::Handle &templ); + + + +#endif // __BUTTON_FIELD_STATE_V8_WRAPPER_H__ diff --git a/plugins/Skins/SkinLib/ControlField.cpp b/plugins/Skins/SkinLib/ControlField.cpp new file mode 100644 index 0000000000..dd9d7026d9 --- /dev/null +++ b/plugins/Skins/SkinLib/ControlField.cpp @@ -0,0 +1,123 @@ +#include "globals.h" +#include "ControlField.h" +#include "ControlFieldState.h" + + +ControlField::ControlField(Dialog *dlg, const char *name, HWND aHwnd) + : Field(dlg, name), hwnd(aHwnd), textSet(false), hFont(NULL) +{ +} + + +ControlField::~ControlField() +{ +} + + +HWND ControlField::getHWND() +{ + return hwnd; +} + + + +void ControlField::setText(const TCHAR *text) +{ + if (text == NULL) + { + if (!textSet) + return; + + textSet = false; + this->text.clear(); + fireOnChange(); + } + else + { + textSet = true; + if (this->text == text) + return; + + this->text = text; + // SetWindowText(hwnd, text); + fireOnChange(); + } +} + + +const TCHAR * ControlField::getText() +{ + if (textSet) + return text.c_str(); + + // Control text is the default value + int length = GetWindowTextLength(hwnd); + if (length <= 0) + { + text = _T(""); + } + else + { + TCHAR *tmp = new TCHAR[length+1]; + + if (GetWindowText(hwnd, tmp, length+1) == 0) + tmp[0] = 0; + + text = tmp; + + delete[] tmp; + } + + return text.c_str(); +} + + +void ControlField::setFont(HFONT hFont) +{ + if (this->hFont == hFont) + return; + + this->hFont = hFont; +// SendMessage(hwnd, WM_SETFONT, (WPARAM) hFont, FALSE); + fireOnChange(); +} + + +HFONT ControlField::getFont() const +{ + if (hFont != NULL) + return hFont; + + // Control font is the default value + return (HFONT) SendMessage(hwnd, WM_GETFONT, 0, 0); +} + + +COLORREF ControlField::getFontColor() const +{ + return GetSysColor(COLOR_WINDOWTEXT); +} + + +int ControlField::getBorderSize() const +{ + int exstyle = GetWindowLong(hwnd, GWL_EXSTYLE); + if (exstyle & WS_EX_CLIENTEDGE) + return GetSystemMetrics(SM_CXEDGE); + if (exstyle & WS_EX_STATICEDGE) + return GetSystemMetrics(SM_CXBORDER); + + int style = GetWindowLong(hwnd, GWL_STYLE); + if (style & WS_BORDER) + return GetSystemMetrics(SM_CXBORDER); + + return 0; +} + +bool ControlField::isScrollVisible(bool horizontal) const +{ + SCROLLBARINFO sbi = {0}; + sbi.cbSize = sizeof(SCROLLBARINFO); + GetScrollBarInfo(hwnd, horizontal ? OBJID_HSCROLL : OBJID_VSCROLL, &sbi); + return (sbi.rgstate[0] & STATE_SYSTEM_INVISIBLE) == 0; +} diff --git a/plugins/Skins/SkinLib/ControlField.h b/plugins/Skins/SkinLib/ControlField.h new file mode 100644 index 0000000000..014ee04b9b --- /dev/null +++ b/plugins/Skins/SkinLib/ControlField.h @@ -0,0 +1,37 @@ +#ifndef __LABEL_CONTROL_FIELD_H__ +# define __LABEL_CONTROL_FIELD_H__ + +#include "Field.h" + +class ControlField : public Field +{ +public: + ControlField(Dialog *dlg, const char *name, HWND hwnd); + virtual ~ControlField(); + + virtual HWND getHWND(); + + virtual void setText(const TCHAR *text); + virtual const TCHAR * getText(); + + virtual void setFont(HFONT hFont); + virtual HFONT getFont() const; + + virtual COLORREF getFontColor() const; + + virtual int getBorderSize() const; + + virtual bool isScrollVisible(bool horizontal) const; + +private: + HWND hwnd; + + bool textSet; + std::tstring text; + + HFONT hFont; +}; + + + +#endif // __LABEL_CONTROL_FIELD_H__ diff --git a/plugins/Skins/SkinLib/ControlFieldState.cpp b/plugins/Skins/SkinLib/ControlFieldState.cpp new file mode 100644 index 0000000000..37c412058a --- /dev/null +++ b/plugins/Skins/SkinLib/ControlFieldState.cpp @@ -0,0 +1,86 @@ +#include "globals.h" +#include "ControlFieldState.h" + + +ControlFieldState::ControlFieldState(DialogState *dialog, ControlField *field) + : FieldState(dialog, field), textSet(false), font(field->getFont(), field->getFontColor()) +{ +} + + +ControlFieldState::~ControlFieldState() +{ +} + + +ControlField * ControlFieldState::getField() const +{ + return (ControlField *) FieldState::getField(); +} + + +Size ControlFieldState::getTextPreferedSize(unsigned int format) const +{ + HDC hdc = CreateCompatibleDC(NULL); + + HFONT newFont = getFont()->getHFONT(); + HFONT oldFont = (HFONT) SelectObject(hdc, newFont); + + int width = 0; + int height = 0; + + const TCHAR *text = getText(); + int len = lstrlen(text); + if (len <= 0) + { + TEXTMETRIC tm = {0}; + GetTextMetrics(hdc, &tm); + height = tm.tmHeight; + } + else + { + RECT rc = {0}; + if ((format & DT_SINGLELINE) == 0 && size.x >= 0) + { + format |= DT_WORDBREAK; + rc.right = size.x; + } + DrawText(hdc, text, len, &rc, DT_CALCRECT | format); + width = rc.right - rc.left; + height = rc.bottom - rc.top; + } + + SelectObject(hdc, oldFont); + + DeleteDC(hdc); + + return Size(width, height); +} + + +const TCHAR * ControlFieldState::getText() const +{ + if (textSet) + return text.c_str(); + + return getField()->getText(); +} + + +void ControlFieldState::setText(const TCHAR *text) +{ + this->text = text; + textSet = true; +} + + +FontState * ControlFieldState::getFont() +{ + return &font; +} + + +const FontState * ControlFieldState::getFont() const +{ + return &font; +} \ No newline at end of file diff --git a/plugins/Skins/SkinLib/ControlFieldState.h b/plugins/Skins/SkinLib/ControlFieldState.h new file mode 100644 index 0000000000..85186c304a --- /dev/null +++ b/plugins/Skins/SkinLib/ControlFieldState.h @@ -0,0 +1,39 @@ +#ifndef __LABEL_CONTROL_FIELD_STATE_H__ +# define __LABEL_CONTROL_FIELD_STATE_H__ + +#include "ControlField.h" +#include "FieldState.h" +#include "FontState.h" + + +class ControlFieldState : public FieldState +{ +public: + virtual ~ControlFieldState(); + + virtual ControlField * getField() const; + + virtual Size getPreferedSize() const = 0; + + virtual const TCHAR * getText() const; + virtual void setText(const TCHAR *text); + + virtual FontState * getFont(); + virtual const FontState * getFont() const; + +protected: + ControlFieldState(DialogState *dialog, ControlField *field); + + virtual Size getTextPreferedSize(unsigned int format) const; + +private: + FontState font; + + bool textSet; + std::tstring text; + + friend class ControlField; +}; + + +#endif // __LABEL_CONTROL_FIELD_STATE_H__ \ No newline at end of file diff --git a/plugins/Skins/SkinLib/ControlFieldState_v8_wrapper.cpp b/plugins/Skins/SkinLib/ControlFieldState_v8_wrapper.cpp new file mode 100644 index 0000000000..70d3e06a45 --- /dev/null +++ b/plugins/Skins/SkinLib/ControlFieldState_v8_wrapper.cpp @@ -0,0 +1,59 @@ +#include "globals.h" +#include "ControlFieldState_v8_wrapper.h" +#include +#include "ControlFieldState.h" +#include + +using namespace v8; + + +#ifdef UNICODE +# define V8_TCHAR uint16_t +#else +# define V8_TCHAR char +#endif + + +static Handle Get_ControlFieldState_text(Local property, const AccessorInfo &info) +{ + HandleScope scope; + + Local self = info.Holder(); + Local wrap = Local::Cast(self->GetInternalField(0)); + if (wrap.IsEmpty()) + return scope.Close( Undefined() ); + + ControlFieldState *tmp = (ControlFieldState *) wrap->Value(); + if (tmp == NULL) + return scope.Close( Undefined() ); + + return scope.Close( String::New((const V8_TCHAR *) tmp->getText()) ); +} + +static void Set_ControlFieldState_text(Local property, Local value, const AccessorInfo& info) +{ + HandleScope scope; + + Local self = info.Holder(); + Local wrap = Local::Cast(self->GetInternalField(0)); + if (wrap.IsEmpty()) + return; + + ControlFieldState *tmp = (ControlFieldState *) wrap->Value(); + if (tmp == NULL) + return; + + if (!value.IsEmpty() && value->IsString()) + { + String::Utf8Value utf8_value(value); + tmp->setText(Utf8ToTchar(*utf8_value)); + } +} + + +void AddControlFieldStateAcessors(Handle &templ) +{ + HandleScope scope; + + templ->SetAccessor(String::New("text"), Get_ControlFieldState_text, Set_ControlFieldState_text); +} diff --git a/plugins/Skins/SkinLib/ControlFieldState_v8_wrapper.h b/plugins/Skins/SkinLib/ControlFieldState_v8_wrapper.h new file mode 100644 index 0000000000..c86964ce30 --- /dev/null +++ b/plugins/Skins/SkinLib/ControlFieldState_v8_wrapper.h @@ -0,0 +1,10 @@ +#ifndef __CONTROL_FIELD_STATE_V8_WRAPPER_H__ +# define __CONTROL_FIELD_STATE_V8_WRAPPER_H__ + +#include + +void AddControlFieldStateAcessors(v8::Handle &templ); + + + +#endif // __CONTROL_FIELD_STATE_V8_WRAPPER_H__ diff --git a/plugins/Skins/SkinLib/Dialog.cpp b/plugins/Skins/SkinLib/Dialog.cpp new file mode 100644 index 0000000000..edc8437817 --- /dev/null +++ b/plugins/Skins/SkinLib/Dialog.cpp @@ -0,0 +1,100 @@ +#include "globals.h" +#include "Dialog.h" +#include "DialogState.h" + + +Dialog::Dialog(const char *aName) : name(aName) +{ +} + + +Dialog::~Dialog() +{ + for(unsigned int i = 0; i < fields.size(); i++) + delete fields[i]; + + fields.clear(); +} + + +const char * Dialog::getName() const +{ + return name.c_str(); +} + + +bool Dialog::addField(Field *field) +{ + if (getField(field->getName()) != NULL) + return false; + + fields.push_back(field); + return true; +} + + +Field * Dialog::getField(const char *name) const +{ + if (name == NULL || name[0] == 0) + return NULL; + + for(unsigned int i = 0; i < fields.size(); i++) + { + Field *field = fields[i]; + if (strcmp(name, field->getName()) == 0) + return field; + } + + return NULL; +} + +Field * Dialog::getField(unsigned int pos) const +{ + if (pos >= fields.size()) + return NULL; + return fields[pos]; +} + +int Dialog::getIndexOf(Field *field) const +{ + for(unsigned int i = 0; i < fields.size(); i++) + { + Field *f = fields[i]; + if (field == f) + return i; + } + + return -1; +} + +unsigned int Dialog::getFieldCount() const +{ + return fields.size(); +} + +DialogInfo * Dialog::getInfo() +{ + return &info; +} + +const Size & Dialog::getSize() const +{ + return size; +} + + +void Dialog::setSize(const Size &size) +{ + this->size = size; +} + + +DialogState * Dialog::createState() +{ + DialogState *ret = new DialogState(this); + + for(unsigned int i = 0; i < fields.size(); i++) + ret->fields.push_back(fields[i]->createState(ret)); + + return ret; +} diff --git a/plugins/Skins/SkinLib/Dialog.h b/plugins/Skins/SkinLib/Dialog.h new file mode 100644 index 0000000000..0e85b8e340 --- /dev/null +++ b/plugins/Skins/SkinLib/Dialog.h @@ -0,0 +1,41 @@ +#ifndef __DIALOG_H__ +# define __DIALOG_H__ + +#include +#include "Field.h" +#include "DialogInfo.h" + +class DialogState; + + +/// It is responsible for freeing the Fields +class Dialog +{ +public: + Dialog(const char *name); + virtual ~Dialog(); + + virtual const char * getName() const; + + virtual bool addField(Field *field); + virtual Field * getField(const char *name) const; + virtual Field * getField(unsigned int pos) const; + virtual int getIndexOf(Field *field) const; + virtual unsigned int getFieldCount() const; + + virtual DialogInfo * getInfo(); + + virtual const Size & getSize() const; + virtual void setSize(const Size &size); + + virtual DialogState * createState(); + +private: + const std::string name; + std::vector fields; + DialogInfo info; + Size size; +}; + + +#endif // __DIALOG_H__ diff --git a/plugins/Skins/SkinLib/DialogInfo.cpp b/plugins/Skins/SkinLib/DialogInfo.cpp new file mode 100644 index 0000000000..fd29a37392 --- /dev/null +++ b/plugins/Skins/SkinLib/DialogInfo.cpp @@ -0,0 +1,190 @@ +#include "globals.h" +#include "DialogInfo.h" +#include "tstring.h" + +class DialogInfoValue +{ +public: + DialogInfoValue(const char *aName) : name(aName), type(UNKNOWN) {} + + const char * getName() { return name.c_str(); } + + void set(const TCHAR *value) { valueString = value; type = TYPE_STRING; } + void set(int value) { valueInt = value; type = TYPE_INT; } + void set(double value) { valueDouble = value; type = TYPE_DOUBLE; } + void set(bool value) { valueBool = value; type = TYPE_BOOL; } + + DialogInfoType getType() { return type; } + + const TCHAR * getAsString() { return valueString.c_str(); } + int getAsInt() { return valueInt; } + double getAsDouble() { return valueDouble; } + bool getAsBool() { return valueBool; } + +private: + std::string name; + + DialogInfoType type; + + std::tstring valueString; + int valueInt; + double valueDouble; + bool valueBool; +}; + +DialogInfo::DialogInfo() +{ +} + +DialogInfo::~DialogInfo() +{ + for(size_t i = 0; i < values.size(); ++i) + delete values[i]; +} + + +void DialogInfo::set(const char *name, const TCHAR *value) +{ + bool isVar; + DialogInfoValue * val = findValue(name, true, &isVar); + + if (isVar) + return; + + val->set(value); +} + +void DialogInfo::set(const char *name, int value) +{ + bool isVar; + DialogInfoValue * val = findValue(name, true, &isVar); + + if (isVar) + return; + + val->set(value); +} + +void DialogInfo::set(const char *name, double value) +{ + bool isVar; + DialogInfoValue * val = findValue(name, true, &isVar); + + if (isVar) + return; + + val->set(value); +} + +void DialogInfo::set(const char *name, bool value) +{ + bool isVar; + DialogInfoValue * val = findValue(name, true, &isVar); + + if (isVar) + return; + + val->set(value); +} + +void DialogInfo::remove(const char *name) +{ + size_t len = strlen(name); + + for(std::vector::iterator it = values.begin(); it != values.end(); ) + { + DialogInfoValue *val = *it; + + if (stricmp(name, val->getName()) == 0) + it = values.erase(it); + + else if (strnicmp(name, val->getName(), len) == 0 && val->getName()[len] == '.') + it = values.erase(it); + + else + it++; + } +} + +DialogInfoType DialogInfo::getType(const char *name) +{ + bool isVar; + DialogInfoValue * val = findValue(name, false, &isVar); + + if (isVar) + return TYPE_VARIABLE; + + else if (val == NULL) + return UNKNOWN; + + else + return val->getType(); +} + + +const TCHAR * DialogInfo::getAsString(const char *name) +{ + DialogInfoValue * val = findValue(name); + if (val == NULL) + return NULL; + + return val->getAsString(); +} + +int DialogInfo::getAsInt(const char *name) +{ + DialogInfoValue * val = findValue(name); + if (val == NULL) + return 0; + + return val->getAsInt(); +} + +double DialogInfo::getAsDouble(const char *name) +{ + DialogInfoValue * val = findValue(name); + if (val == NULL) + return 0; + + return val->getAsDouble(); +} + +bool DialogInfo::getAsBool(const char *name) +{ + DialogInfoValue * val = findValue(name); + if (val == NULL) + return false; + + return val->getAsBool(); +} + +DialogInfoValue * DialogInfo::findValue(const char *name, bool create, bool *isVar) +{ + size_t len = strlen(name); + + if (isVar != NULL) *isVar = false; + + for(size_t i = 0; i < values.size(); ++i) + { + DialogInfoValue *val = values[i]; + + if (stricmp(name, val->getName()) == 0) + { + return val; + } + else if (strnicmp(name, val->getName(), len) == 0 && val->getName()[len] == '.') + { + if (isVar != NULL) *isVar = true; + return val; + } + } + + if (create) + { + DialogInfoValue *ret = new DialogInfoValue(name); + values.push_back(ret); + return ret; + } + + return NULL; +} diff --git a/plugins/Skins/SkinLib/DialogInfo.h b/plugins/Skins/SkinLib/DialogInfo.h new file mode 100644 index 0000000000..02f07310d7 --- /dev/null +++ b/plugins/Skins/SkinLib/DialogInfo.h @@ -0,0 +1,50 @@ +#ifndef __DIALOG_INFO_H__ +# define __DIALOG_INFO_H__ + +#include +#include + + +enum DialogInfoType +{ + UNKNOWN = 0, + TYPE_VARIABLE, + TYPE_INT, + TYPE_DOUBLE, + TYPE_BOOL, + TYPE_STRING +}; + + +class DialogInfoValue; + +class DialogInfo +{ +public: + DialogInfo(); + ~DialogInfo(); + + void set(const char *name, const TCHAR *value); + void set(const char *name, int value); + void set(const char *name, double value); + void set(const char *name, bool value); + + void remove(const char *name); + + DialogInfoType getType(const char *name); + + const TCHAR * getAsString(const char *name); + int getAsInt(const char *name); + double getAsDouble(const char *name); + bool getAsBool(const char *name); + +private: + std::vector values; + + DialogInfoValue * findValue(const char *name, bool create = false, bool *isVar = NULL); + +}; + + + +#endif // __DIALOG_INFO_H__ \ No newline at end of file diff --git a/plugins/Skins/SkinLib/DialogState.cpp b/plugins/Skins/SkinLib/DialogState.cpp new file mode 100644 index 0000000000..e1e7654930 --- /dev/null +++ b/plugins/Skins/SkinLib/DialogState.cpp @@ -0,0 +1,132 @@ +#include "globals.h" +#include "DialogState.h" + + +DialogState::DialogState(Dialog *aDialog) : dialog(aDialog), size(-1,-1), borders(0,0,0,0) +{ +} + +DialogState::~DialogState() +{ + for(unsigned int i = 0; i < fields.size(); i++) + delete fields[i]; + + fields.clear(); +} + +Dialog * DialogState::getDialog() const +{ + return dialog; +} + +FieldState * DialogState::getField(const char *name) const +{ + if (name == NULL || name[0] == 0) + return NULL; + + for(unsigned int i = 0; i < fields.size(); i++) + { + FieldState *field = fields[i]; + if (strcmp(name, field->getField()->getName()) == 0) + return field; + } + + return NULL; +} + +int DialogState::getX() const +{ + return 0; +} + +int DialogState::getY() const +{ + return 0; +} + +int DialogState::getLeft() const +{ + return getX(); +} + +int DialogState::getTop() const +{ + return getY(); +} + +int DialogState::getRight() const +{ + return getX() + getWidth(); +} + +int DialogState::getBottom() const +{ + return getY() + getHeight(); +} + +int DialogState::getWidth() const +{ + if (size.x >= 0) + return size.x - getHorizontalBorders(); + + return dialog->getSize().x - getHorizontalBorders(); +} + +void DialogState::setWidth(int width) +{ + size.x = max(0, width) + getHorizontalBorders(); +} + +int DialogState::getHeight() const +{ + if (size.y >= 0) + return size.y - getVerticalBorders(); + + return dialog->getSize().y - getVerticalBorders(); +} + +void DialogState::setHeight(int height) +{ + size.y = max(0, height) + getVerticalBorders(); +} + +BorderState * DialogState::getBorders() +{ + return &borders; +} + +const BorderState * DialogState::getBorders() const +{ + return &borders; +} + +int DialogState::getHorizontalBorders() const +{ + return borders.getLeft() + borders.getRight(); +} + +int DialogState::getVerticalBorders() const +{ + return borders.getTop() + borders.getBottom(); +} + +RECT DialogState::getInsideRect() const +{ + RECT ret; + ret.left = borders.getLeft(); + ret.right = ret.left + getWidth(); + ret.top = borders.getTop(); + ret.bottom = ret.top + getHeight(); + return ret; +} + +RECT DialogState::getRect() const +{ + RECT ret; + ret.left = 0; + ret.right = borders.getLeft() + getWidth() + borders.getRight(); + ret.top = 0; + ret.bottom = borders.getTop() + getHeight() + borders.getBottom(); + return ret; +} + diff --git a/plugins/Skins/SkinLib/DialogState.h b/plugins/Skins/SkinLib/DialogState.h new file mode 100644 index 0000000000..e27fc929da --- /dev/null +++ b/plugins/Skins/SkinLib/DialogState.h @@ -0,0 +1,59 @@ +#ifndef __DIALOG_STATE_H__ +# define __DIALOG_STATE_H__ + +#include "Dialog.h" +#include "FieldState.h" +#include "BorderState.h" + + +/// This have to be deleted before the owning dialog +/// It is responsible for freeing the FieldStates +class DialogState +{ +public: + ~DialogState(); + + Dialog * getDialog() const; + + std::vector fields; + FieldState * getField(const char *name) const; + + // Used inside script + + virtual int getX() const; + virtual int getY() const; + virtual int getLeft() const; + virtual int getTop() const; + virtual int getRight() const; + virtual int getBottom() const; + + int getWidth() const; + void setWidth(int width); + + int getHeight() const; + void setHeight(int height); + + BorderState * getBorders(); + const BorderState * getBorders() const; + + // Results + + RECT getInsideRect() const; + RECT getRect() const; + +private: + DialogState(Dialog *dialog); + + Dialog *dialog; + + Size size; + BorderState borders; + + int getHorizontalBorders() const; + int getVerticalBorders() const; + + friend class Dialog; +}; + + +#endif // __DIALOG_STATE_H__ \ No newline at end of file diff --git a/plugins/Skins/SkinLib/DialogState_v8_wrapper.cpp b/plugins/Skins/SkinLib/DialogState_v8_wrapper.cpp new file mode 100644 index 0000000000..5739414d69 --- /dev/null +++ b/plugins/Skins/SkinLib/DialogState_v8_wrapper.cpp @@ -0,0 +1,233 @@ +#include "globals.h" +#include "DialogState_v8_wrapper.h" +#include +#include "DialogState.h" + +using namespace v8; + + +#ifdef UNICODE +# define V8_TCHAR uint16_t +#else +# define V8_TCHAR char +#endif + + +static Handle Get_DialogState_width(Local property, const AccessorInfo &info) +{ + HandleScope scope; + + Local self = info.Holder(); + Local wrap = Local::Cast(self->GetInternalField(0)); + if (wrap.IsEmpty()) + return scope.Close( Undefined() ); + + DialogState *tmp = (DialogState *) wrap->Value(); + if (tmp == NULL) + return scope.Close( Undefined() ); + + return scope.Close( Int32::New(tmp->getWidth()) ); +} + +static void Set_DialogState_width(Local property, Local value, const AccessorInfo& info) +{ + HandleScope scope; + + Local self = info.Holder(); + Local wrap = Local::Cast(self->GetInternalField(0)); + if (wrap.IsEmpty()) + return; + + DialogState *tmp = (DialogState *) wrap->Value(); + if (tmp == NULL) + return; + + if (!value.IsEmpty() && value->IsNumber()) + tmp->setWidth(value->Int32Value()); +} + + +static Handle Get_DialogState_height(Local property, const AccessorInfo &info) +{ + HandleScope scope; + + Local self = info.Holder(); + Local wrap = Local::Cast(self->GetInternalField(0)); + if (wrap.IsEmpty()) + return scope.Close( Undefined() ); + + DialogState *tmp = (DialogState *) wrap->Value(); + if (tmp == NULL) + return scope.Close( Undefined() ); + + return scope.Close( Int32::New(tmp->getHeight()) ); +} + +static void Set_DialogState_height(Local property, Local value, const AccessorInfo& info) +{ + HandleScope scope; + + Local self = info.Holder(); + Local wrap = Local::Cast(self->GetInternalField(0)); + if (wrap.IsEmpty()) + return; + + DialogState *tmp = (DialogState *) wrap->Value(); + if (tmp == NULL) + return; + + if (!value.IsEmpty() && value->IsNumber()) + tmp->setHeight(value->Int32Value()); +} + + +static Handle Get_DialogState_x(Local property, const AccessorInfo &info) +{ + HandleScope scope; + + Local self = info.Holder(); + Local wrap = Local::Cast(self->GetInternalField(0)); + if (wrap.IsEmpty()) + return scope.Close( Undefined() ); + + DialogState *tmp = (DialogState *) wrap->Value(); + if (tmp == NULL) + return scope.Close( Undefined() ); + + return scope.Close( Int32::New(tmp->getX()) ); +} + + +static Handle Get_DialogState_y(Local property, const AccessorInfo &info) +{ + HandleScope scope; + + Local self = info.Holder(); + Local wrap = Local::Cast(self->GetInternalField(0)); + if (wrap.IsEmpty()) + return scope.Close( Undefined() ); + + DialogState *tmp = (DialogState *) wrap->Value(); + if (tmp == NULL) + return scope.Close( Undefined() ); + + return scope.Close( Int32::New(tmp->getY()) ); +} + + +static Handle Get_DialogState_left(Local property, const AccessorInfo &info) +{ + HandleScope scope; + + Local self = info.Holder(); + Local wrap = Local::Cast(self->GetInternalField(0)); + if (wrap.IsEmpty()) + return scope.Close( Undefined() ); + + DialogState *tmp = (DialogState *) wrap->Value(); + if (tmp == NULL) + return scope.Close( Undefined() ); + + return scope.Close( Int32::New(tmp->getLeft()) ); +} + + +static Handle Get_DialogState_top(Local property, const AccessorInfo &info) +{ + HandleScope scope; + + Local self = info.Holder(); + Local wrap = Local::Cast(self->GetInternalField(0)); + if (wrap.IsEmpty()) + return scope.Close( Undefined() ); + + DialogState *tmp = (DialogState *) wrap->Value(); + if (tmp == NULL) + return scope.Close( Undefined() ); + + return scope.Close( Int32::New(tmp->getTop()) ); +} + + +static Handle Get_DialogState_right(Local property, const AccessorInfo &info) +{ + HandleScope scope; + + Local self = info.Holder(); + Local wrap = Local::Cast(self->GetInternalField(0)); + if (wrap.IsEmpty()) + return scope.Close( Undefined() ); + + DialogState *tmp = (DialogState *) wrap->Value(); + if (tmp == NULL) + return scope.Close( Undefined() ); + + return scope.Close( Int32::New(tmp->getRight()) ); +} + + +static Handle Get_DialogState_bottom(Local property, const AccessorInfo &info) +{ + HandleScope scope; + + Local self = info.Holder(); + Local wrap = Local::Cast(self->GetInternalField(0)); + if (wrap.IsEmpty()) + return scope.Close( Undefined() ); + + DialogState *tmp = (DialogState *) wrap->Value(); + if (tmp == NULL) + return scope.Close( Undefined() ); + + return scope.Close( Int32::New(tmp->getBottom()) ); +} + + +static Handle Get_DialogState_borders(Local property, const AccessorInfo &info) +{ + HandleScope scope; + + Local self = info.Holder(); + Local wrap = Local::Cast(self->GetInternalField(0)); + if (wrap.IsEmpty()) + return scope.Close( Undefined() ); + + DialogState *tmp = (DialogState *) wrap->Value(); + if (tmp == NULL) + return scope.Close( Undefined() ); + + return scope.Close( self->Get(String::New("bordersRaw")) ); +} + +static void Set_DialogState_borders(Local property, Local value, const AccessorInfo& info) +{ + HandleScope scope; + + Local self = info.Holder(); + Local wrap = Local::Cast(self->GetInternalField(0)); + if (wrap.IsEmpty()) + return; + + DialogState *tmp = (DialogState *) wrap->Value(); + if (tmp == NULL) + return; + + if (!value.IsEmpty() && value->IsInt32()) + tmp->getBorders()->setAll(value->Int32Value()); +} + + +void AddDialogStateAcessors(Handle &templ) +{ + HandleScope scope; + + templ->SetAccessor(String::New("width"), Get_DialogState_width, Set_DialogState_width); + templ->SetAccessor(String::New("height"), Get_DialogState_height, Set_DialogState_height); + templ->SetAccessor(String::New("x"), Get_DialogState_x, NULL, Handle(), DEFAULT, ReadOnly); + templ->SetAccessor(String::New("y"), Get_DialogState_y, NULL, Handle(), DEFAULT, ReadOnly); + templ->SetAccessor(String::New("left"), Get_DialogState_left, NULL, Handle(), DEFAULT, ReadOnly); + templ->SetAccessor(String::New("top"), Get_DialogState_top, NULL, Handle(), DEFAULT, ReadOnly); + templ->SetAccessor(String::New("right"), Get_DialogState_right, NULL, Handle(), DEFAULT, ReadOnly); + templ->SetAccessor(String::New("bottom"), Get_DialogState_bottom, NULL, Handle(), DEFAULT, ReadOnly); + templ->SetAccessor(String::New("borders"), Get_DialogState_borders, Set_DialogState_borders); +} diff --git a/plugins/Skins/SkinLib/DialogState_v8_wrapper.h b/plugins/Skins/SkinLib/DialogState_v8_wrapper.h new file mode 100644 index 0000000000..709ef2d738 --- /dev/null +++ b/plugins/Skins/SkinLib/DialogState_v8_wrapper.h @@ -0,0 +1,10 @@ +#ifndef __DIALOG_STATE_V8_WRAPPER_H__ +# define __DIALOG_STATE_V8_WRAPPER_H__ + +#include + +void AddDialogStateAcessors(v8::Handle &templ); + + + +#endif // __DIALOG_STATE_V8_WRAPPER_H__ diff --git a/plugins/Skins/SkinLib/EditField.cpp b/plugins/Skins/SkinLib/EditField.cpp new file mode 100644 index 0000000000..8eb0d5050f --- /dev/null +++ b/plugins/Skins/SkinLib/EditField.cpp @@ -0,0 +1,23 @@ +#include "globals.h" +#include "EditField.h" +#include "EditFieldState.h" + + +EditField::EditField(Dialog *dlg, const char *name, HWND hwnd) + : ControlField(dlg, name, hwnd) +{ +} + +EditField::~EditField() +{ +} + +FieldType EditField::getType() const +{ + return CONTROL_EDIT; +} + +FieldState * EditField::createState(DialogState *dialogState) +{ + return new EditFieldState(dialogState, this); +} \ No newline at end of file diff --git a/plugins/Skins/SkinLib/EditField.h b/plugins/Skins/SkinLib/EditField.h new file mode 100644 index 0000000000..f69f23576c --- /dev/null +++ b/plugins/Skins/SkinLib/EditField.h @@ -0,0 +1,19 @@ +#ifndef __EDIT_FIELD_H__ +# define __EDIT_FIELD_H__ + +#include "ControlField.h" + + +class EditField : public ControlField +{ +public: + EditField(Dialog *dlg, const char *name, HWND hwnd); + virtual ~EditField(); + + virtual FieldType getType() const; + + virtual FieldState * createState(DialogState *dialogState); +}; + + +#endif // __EDIT_FIELD_H__ diff --git a/plugins/Skins/SkinLib/EditFieldState.cpp b/plugins/Skins/SkinLib/EditFieldState.cpp new file mode 100644 index 0000000000..e634be7b55 --- /dev/null +++ b/plugins/Skins/SkinLib/EditFieldState.cpp @@ -0,0 +1,58 @@ +#include "globals.h" +#include "EditFieldState.h" + + +EditFieldState::EditFieldState(DialogState *dialog, EditField *field) + : ControlFieldState(dialog, field) +{ +} + +EditFieldState::~EditFieldState() +{ +} + +Size EditFieldState::getPreferedSize() const +{ + ControlField *field = getField(); + HWND hwnd = field->getHWND(); + + int style = GetWindowLong(hwnd, GWL_STYLE); + int exstyle = GetWindowLong(hwnd, GWL_EXSTYLE); + + int format = DT_NOPREFIX | DT_EDITCONTROL; + if (!(style & ES_MULTILINE)) + format |= DT_SINGLELINE; + Size ret = getTextPreferedSize(format); + + RECT rc = {0}; + SetRect(&rc, 0, 0, ret.x, ret.y); + AdjustWindowRectEx(&rc, style, false, exstyle); + + bool hasHorScroll = field->isScrollVisible(true); + if (hasHorScroll) + rc.bottom += GetSystemMetrics(SM_CYHSCROLL); + if (field->isScrollVisible(false)) + rc.right += GetSystemMetrics(SM_CXVSCROLL); + + int margins = SendMessage(hwnd, EM_GETMARGINS, 0, 0); + rc.left -= LOWORD(margins); + rc.right += HIWORD(margins); + if (hasHorScroll || (style & ES_AUTOHSCROLL)) + rc.right++; + + ret.x = rc.right - rc.left; + ret.y = rc.bottom - rc.top; + + if ((exstyle & WS_EX_CLIENTEDGE) || (exstyle & WS_EX_STATICEDGE) || (style & WS_BORDER)) + { + ret.x += 3; + ret.y += 3; + } + + return ret; +} + +bool EditFieldState::isEmpty() const +{ + return false; +} \ No newline at end of file diff --git a/plugins/Skins/SkinLib/EditFieldState.h b/plugins/Skins/SkinLib/EditFieldState.h new file mode 100644 index 0000000000..c2372d553d --- /dev/null +++ b/plugins/Skins/SkinLib/EditFieldState.h @@ -0,0 +1,24 @@ +#ifndef __EDIT_FIELD_STATE_H__ +# define __EDIT_FIELD_STATE_H__ + +#include "ControlFieldState.h" +#include "EditField.h" + + +class EditFieldState : public ControlFieldState +{ +public: + virtual ~EditFieldState(); + + virtual Size getPreferedSize() const; + + virtual bool isEmpty() const; + +private: + EditFieldState(DialogState *dialog, EditField *field); + + friend class EditField; +}; + + +#endif // __EDIT_FIELD_STATE_H__ diff --git a/plugins/Skins/SkinLib/EditFieldState_v8_wrapper.cpp b/plugins/Skins/SkinLib/EditFieldState_v8_wrapper.cpp new file mode 100644 index 0000000000..86522b87e3 --- /dev/null +++ b/plugins/Skins/SkinLib/EditFieldState_v8_wrapper.cpp @@ -0,0 +1,20 @@ +#include "globals.h" +#include "EditFieldState_v8_wrapper.h" +#include +#include "EditFieldState.h" + +using namespace v8; + + +#ifdef UNICODE +# define V8_TCHAR uint16_t +#else +# define V8_TCHAR char +#endif + + +void AddEditFieldStateAcessors(Handle &templ) +{ + HandleScope scope; + +} diff --git a/plugins/Skins/SkinLib/EditFieldState_v8_wrapper.h b/plugins/Skins/SkinLib/EditFieldState_v8_wrapper.h new file mode 100644 index 0000000000..a58972549f --- /dev/null +++ b/plugins/Skins/SkinLib/EditFieldState_v8_wrapper.h @@ -0,0 +1,10 @@ +#ifndef __EDIT_FIELD_STATE_V8_WRAPPER_H__ +# define __EDIT_FIELD_STATE_V8_WRAPPER_H__ + +#include + +void AddEditFieldStateAcessors(v8::Handle &templ); + + + +#endif // __EDIT_FIELD_STATE_V8_WRAPPER_H__ diff --git a/plugins/Skins/SkinLib/Field.cpp b/plugins/Skins/SkinLib/Field.cpp new file mode 100644 index 0000000000..24b823bde6 --- /dev/null +++ b/plugins/Skins/SkinLib/Field.cpp @@ -0,0 +1,56 @@ +#include "globals.h" +#include "Field.h" +#include "FieldState.h" + + +Field::Field(Dialog *aDlg, const char *aName) + : dlg(aDlg), name(aName), onChangeCallback(NULL), onChangeCallbackParam(NULL), enabled(true) +{ +} + +Field::~Field() +{ +} + +Dialog * Field::getDialog() const +{ + return dlg; +} + +const char * Field::getName() const +{ + return name.c_str(); +} + +bool Field::isEnabled() const +{ + return enabled; +} + +void Field::setEnabled(bool enabled) +{ + this->enabled = enabled; + fireOnChange(); +} + +const TCHAR * Field::getToolTip() const +{ + return tooltip.c_str(); +} + +void Field::setToolTip(const TCHAR *tooltip) +{ + this->tooltip = tooltip; +} + +void Field::setOnChangeCallback(FieldCallback cb, void *param /*= NULL*/) +{ + onChangeCallback = cb; + onChangeCallbackParam = param; +} + +void Field::fireOnChange() const +{ + if (onChangeCallback != NULL) + onChangeCallback(onChangeCallbackParam, this); +} diff --git a/plugins/Skins/SkinLib/Field.h b/plugins/Skins/SkinLib/Field.h new file mode 100644 index 0000000000..4cf7faaa51 --- /dev/null +++ b/plugins/Skins/SkinLib/Field.h @@ -0,0 +1,66 @@ +#ifndef __FIELD_H__ +# define __FIELD_H__ + +#include +#include +#include "tstring.h" +#include "Size.h" +#include "Position.h" + + +enum FieldType +{ + SIMPLE_TEXT = 1, + SIMPLE_IMAGE, + SIMPLE_ICON, + CONTROL_LABEL, + CONTROL_BUTTON, + CONTROL_EDIT, + USER_DEFINED = 0x100 +}; + +class Dialog; +class DialogState; +class Field; +class FieldState; + +typedef void (*FieldCallback)(void *param, const Field *field); + + +class Field +{ +public: + Field(Dialog *dlg, const char *name); + virtual ~Field(); + + virtual Dialog * getDialog() const; + virtual const char * getName() const; + virtual FieldType getType() const = 0; + + virtual bool isEnabled() const; + virtual void setEnabled(bool enabled); + + virtual const TCHAR * getToolTip() const; + virtual void setToolTip(const TCHAR *tooltip); + + virtual FieldState * createState(DialogState *dialogState) = 0; + + virtual void setOnChangeCallback(FieldCallback cb, void *param = NULL); + +protected: + void fireOnChange() const; + +private: + Dialog *dlg; + const std::string name; + bool enabled; + std::tstring tooltip; + + FieldCallback onChangeCallback; + void *onChangeCallbackParam; +}; + + + + +#endif // __FIELD_H__ \ No newline at end of file diff --git a/plugins/Skins/SkinLib/FieldState.cpp b/plugins/Skins/SkinLib/FieldState.cpp new file mode 100644 index 0000000000..68510051da --- /dev/null +++ b/plugins/Skins/SkinLib/FieldState.cpp @@ -0,0 +1,303 @@ +#include "globals.h" +#include "FieldState.h" +#include "DialogState.h" +#include "BorderState.h" + +#define START 1<<0 +#define LEN 1<<1 +#define END 1<<2 +#define USING_MASK 0xFF +#define LAST_SHIFT 8 +#define SET(_FIELD_, _ITEM_) _FIELD_ = (((_FIELD_ | _ITEM_) & USING_MASK) | (_ITEM_ << LAST_SHIFT)) +#define LAST_SET(_FIELD_) (_FIELD_ >> LAST_SHIFT) + + +FieldState::FieldState(DialogState *aDialog, Field *aField) + : field(aField), dialog(aDialog), size(-1, -1), pos(0, 0), + usingX(0), usingY(0), visible(aField->isEnabled()), borders(0,0,0,0), + tooltipSet(false), halign(HORIZONTAL_ALIGN_LEFT), valign(VERTICAL_ALIGN_TOP) +{ +} + +FieldState::~FieldState() +{ +} + +Field * FieldState::getField() const +{ + return field; +} + +DialogState * FieldState::getDialog() const +{ + return dialog; +} + +int FieldState::getX() const +{ + return pos.x; +} + +void FieldState::setX(int x) +{ + if (usingX & END) + { + int diff = x - getX(); + size.x = max(0, getWidth() - getHorizontalBorders() - diff); + } + + pos.x = x; + + SET(usingX, START); +} + +int FieldState::getY() const +{ + return pos.y; +} + +void FieldState::setY(int y) +{ + if (usingY & END) + { + int diff = y - getY(); + size.y = max(0, getHeight() - getVerticalBorders() - diff); + } + + pos.y = y; + + SET(usingY, START); +} + +int FieldState::getWidth() const +{ + if (size.x >= 0) + return size.x + getHorizontalBorders(); + + return getPreferedSize().x + getHorizontalBorders(); +} + +void FieldState::setWidth(int width) +{ + width = max(0, width - getHorizontalBorders()) + getHorizontalBorders(); + + if (LAST_SET(usingX) == END) + { + int diff = width - getWidth(); + pos.x = getX() - diff; + } + + size.x = width - getHorizontalBorders(); + + usingX |= LEN; +} + +int FieldState::getHeight() const +{ + if (size.y >= 0) + return size.y + getVerticalBorders(); + + return getPreferedSize().y + getVerticalBorders(); +} + +void FieldState::setHeight(int height) +{ + height = max(0, height - getVerticalBorders()) + getVerticalBorders(); + + if (LAST_SET(usingY) == END) + { + int diff = height - getHeight(); + pos.y = getY() - diff; + } + + size.y = height - getVerticalBorders(); + + usingY |= LEN; +} + +bool FieldState::isVisible() const +{ + if (!visible) + return false; + + RECT rc = getRect(); + if (rc.right <= rc.left || rc.bottom <= rc.top) + return false; + + return true; +} + +void FieldState::setVisible(bool visible) +{ + this->visible = visible; +} + +bool FieldState::isEnabled() const +{ + return field->isEnabled(); +} + +int FieldState::getLeft() const +{ + return getX(); +} + +void FieldState::setLeft(int left) +{ + setX(left); +} + +int FieldState::getTop() const +{ + return getY(); +} + +void FieldState::setTop(int top) +{ + setY(top); +} + +int FieldState::getRight() const +{ + return getX() + getWidth(); +} + +void FieldState::setRight(int right) +{ + if (usingX & START) + { + size.x = max(0, right - getX()); + } + else + { + pos.x = right - getWidth(); + } + + SET(usingX, END); +} + +int FieldState::getBottom() const +{ + return getY() + getHeight(); +} + +void FieldState::setBottom(int botom) +{ + if (usingY & START) + { + size.y = max(0, botom - getY()); + } + else + { + pos.y = botom - getHeight(); + } + + SET(usingY, END); +} + +const TCHAR * FieldState::getToolTip() const +{ + if (tooltipSet) + return tooltip.c_str(); + else + return field->getToolTip(); +} + +void FieldState::setToolTip(const TCHAR *tooltip) +{ + this->tooltip = tooltip; + tooltipSet = true; +} + +BorderState * FieldState::getBorders() +{ + return &borders; +} + +const BorderState * FieldState::getBorders() const +{ + return &borders; +} + +int FieldState::getHorizontalBorders() const +{ + return borders.getLeft() + borders.getRight(); +} + +int FieldState::getVerticalBorders() const +{ + return borders.getTop() + borders.getBottom(); +} + +static inline int beetween(int val, int minVal, int maxVal) +{ + return max(minVal, min(maxVal, val)); +} + +static inline void intersection(RECT &main, const RECT &other) +{ + main.left = beetween(main.left, other.left, other.right); + main.right = beetween(main.right, other.left, other.right); + main.top = beetween(main.top, other.top, other.bottom); + main.bottom = beetween(main.bottom, other.top, other.bottom); +} + +RECT FieldState::getRect(bool raw) const +{ + RECT ret = {0}; + + if (!visible) + return ret; + + RECT inside = dialog->getInsideRect(); + + ret.left = getLeft() + inside.left; + ret.right = getRight() + inside.left; + ret.top = getTop() + inside.top; + ret.bottom = getBottom() + inside.top; + + if (!raw) + intersection(ret, inside); + + return ret; +} + +RECT FieldState::getInsideRect(bool raw) const +{ + RECT ret = {0}; + + if (!visible) + return ret; + + RECT inside = dialog->getInsideRect(); + + ret.left = getLeft() + borders.getLeft() + inside.left; + ret.right = getRight() - borders.getRight() + inside.left; + ret.top = getTop() + borders.getTop() + inside.top; + ret.bottom = getBottom() - borders.getBottom() + inside.top; + + if (!raw) + intersection(ret, inside); + + return ret; +} + +HORIZONTAL_ALIGN FieldState::getHAlign() const +{ + return halign; +} + +void FieldState::setHAlign(HORIZONTAL_ALIGN halign) +{ + this->halign = halign; +} + +VERTICAL_ALIGN FieldState::getVAlign() const +{ + return valign; +} + +void FieldState::setVAlign(VERTICAL_ALIGN valign) +{ + this->valign = valign; +} diff --git a/plugins/Skins/SkinLib/FieldState.h b/plugins/Skins/SkinLib/FieldState.h new file mode 100644 index 0000000000..d7c552105f --- /dev/null +++ b/plugins/Skins/SkinLib/FieldState.h @@ -0,0 +1,108 @@ +#ifndef __FIELD_STATE_H__ +# define __FIELD_STATE_H__ + +#include "Field.h" +#include "BorderState.h" + +class DialogState; + +enum HORIZONTAL_ALIGN +{ + HORIZONTAL_ALIGN_LEFT = 1, + HORIZONTAL_ALIGN_CENTER, + HORIZONTAL_ALIGN_RIGHT +}; + +enum VERTICAL_ALIGN +{ + VERTICAL_ALIGN_TOP = 1, + VERTICAL_ALIGN_CENTER, + VERTICAL_ALIGN_BOTTOM +}; + + +class FieldState +{ +public: + virtual ~FieldState(); + + virtual Field * getField() const; + virtual DialogState * getDialog() const; + + virtual Size getPreferedSize() const = 0; + + // Used inside script + + virtual int getX() const; + virtual void setX(int x); + + virtual int getY() const; + virtual void setY(int y); + + virtual int getWidth() const; + virtual void setWidth(int width); + + virtual int getHeight() const; + virtual void setHeight(int height); + + virtual int getLeft() const; + virtual void setLeft(int left); + + virtual int getTop() const; + virtual void setTop(int top); + + virtual int getRight() const; + virtual void setRight(int right); + + virtual int getBottom() const; + virtual void setBottom(int bottom); + + virtual bool isVisible() const; + virtual void setVisible(bool visible); + + virtual bool isEnabled() const; + + virtual const TCHAR * getToolTip() const; + virtual void setToolTip(const TCHAR *tooltip); + + virtual BorderState * getBorders(); + virtual const BorderState * getBorders() const; + + virtual HORIZONTAL_ALIGN getHAlign() const; + virtual void setHAlign(HORIZONTAL_ALIGN halign); + + virtual VERTICAL_ALIGN getVAlign() const; + virtual void setVAlign(VERTICAL_ALIGN valign); + + virtual bool isEmpty() const = 0; + + // Results + + virtual RECT getInsideRect(bool raw = false) const; + virtual RECT getRect(bool raw = false) const; + +protected: + FieldState(DialogState *dialog, Field *field); + + Field *field; + DialogState *dialog; + + Size size; + Position pos; + int usingX; + int usingY; + bool visible; + BorderState borders; + bool tooltipSet; + std::tstring tooltip; + HORIZONTAL_ALIGN halign; + VERTICAL_ALIGN valign; + + int getHorizontalBorders() const; + int getVerticalBorders() const; + + friend class Field; +}; + + +#endif // __FIELD_STATE_H__ diff --git a/plugins/Skins/SkinLib/FieldState.rec b/plugins/Skins/SkinLib/FieldState.rec new file mode 100644 index 0000000000..7b9ffd890d --- /dev/null +++ b/plugins/Skins/SkinLib/FieldState.rec @@ -0,0 +1,89 @@ +struct DialogState +{ + Int32 width; + Int32 height; + const Int32 x; + const Int32 y; + const Int32 left; + const Int32 top; + const Int32 right; + const Int32 bottom; + BorderState borders [setter: if (!value.IsEmpty() && value->IsInt32())\n\ttmp->getBorders()->setAll(value->Int32Value()); ]; +}; + +struct FieldState +{ + Int32 x; + Int32 y; + Int32 width; + Int32 height; + Int32 left; + Int32 top; + Int32 right; + Int32 bottom; + Boolean visible; + const Boolean enabled; + Char toolTip[128]; + Int32 hAlign | HORIZONTAL_ALIGN_LEFT "LEFT" | HORIZONTAL_ALIGN_CENTER "CENTER" | HORIZONTAL_ALIGN_RIGHT "RIGHT"; + Int32 vAlign | VERTICAL_ALIGN_TOP "TOP" | VERTICAL_ALIGN_CENTER "CENTER" | VERTICAL_ALIGN_BOTTOM "BOTTOM"; + BorderState borders [setter: if (!value.IsEmpty() && value->IsInt32())\n\ttmp->getBorders()->setAll(value->Int32Value()); ]; +}; + +struct ControlFieldState : FieldState +{ + Char text[1024]; + FontState font; +}; + +struct LabelFieldState : ControlFieldState +{ +}; + +struct ButtonFieldState : ControlFieldState +{ +}; + +struct EditFieldState : ControlFieldState +{ +}; + +struct IconFieldState : FieldState +{ +}; + +struct ImageFieldState : FieldState +{ +}; + +struct TextFieldState : FieldState +{ + Char text[1024]; + FontState font; +}; + +struct FontState +{ + Char face[32]; + Int32 size; + Boolean italic; + Boolean bold; + Boolean underline; + Boolean strikeOut; + Int32 color; +}; + +struct BorderState +{ + Int32 left; + Int32 right; + Int32 top; + Int32 bottom; +}; + +struct SkinOption +{ + Char description[128]; + Int32 min; + Int32 max; + Int32 type | CHECKBOX | NUMBER | TEXT; +}; diff --git a/plugins/Skins/SkinLib/FieldState_v8_wrapper.cpp b/plugins/Skins/SkinLib/FieldState_v8_wrapper.cpp new file mode 100644 index 0000000000..937ad69a58 --- /dev/null +++ b/plugins/Skins/SkinLib/FieldState_v8_wrapper.cpp @@ -0,0 +1,539 @@ +#include "globals.h" +#include "FieldState_v8_wrapper.h" +#include +#include "FieldState.h" +#include + +using namespace v8; + + +#ifdef UNICODE +# define V8_TCHAR uint16_t +#else +# define V8_TCHAR char +#endif + + +static Handle Get_FieldState_x(Local property, const AccessorInfo &info) +{ + HandleScope scope; + + Local self = info.Holder(); + Local wrap = Local::Cast(self->GetInternalField(0)); + if (wrap.IsEmpty()) + return scope.Close( Undefined() ); + + FieldState *tmp = (FieldState *) wrap->Value(); + if (tmp == NULL) + return scope.Close( Undefined() ); + + return scope.Close( Int32::New(tmp->getX()) ); +} + +static void Set_FieldState_x(Local property, Local value, const AccessorInfo& info) +{ + HandleScope scope; + + Local self = info.Holder(); + Local wrap = Local::Cast(self->GetInternalField(0)); + if (wrap.IsEmpty()) + return; + + FieldState *tmp = (FieldState *) wrap->Value(); + if (tmp == NULL) + return; + + if (!value.IsEmpty() && value->IsNumber()) + tmp->setX(value->Int32Value()); +} + + +static Handle Get_FieldState_y(Local property, const AccessorInfo &info) +{ + HandleScope scope; + + Local self = info.Holder(); + Local wrap = Local::Cast(self->GetInternalField(0)); + if (wrap.IsEmpty()) + return scope.Close( Undefined() ); + + FieldState *tmp = (FieldState *) wrap->Value(); + if (tmp == NULL) + return scope.Close( Undefined() ); + + return scope.Close( Int32::New(tmp->getY()) ); +} + +static void Set_FieldState_y(Local property, Local value, const AccessorInfo& info) +{ + HandleScope scope; + + Local self = info.Holder(); + Local wrap = Local::Cast(self->GetInternalField(0)); + if (wrap.IsEmpty()) + return; + + FieldState *tmp = (FieldState *) wrap->Value(); + if (tmp == NULL) + return; + + if (!value.IsEmpty() && value->IsNumber()) + tmp->setY(value->Int32Value()); +} + + +static Handle Get_FieldState_width(Local property, const AccessorInfo &info) +{ + HandleScope scope; + + Local self = info.Holder(); + Local wrap = Local::Cast(self->GetInternalField(0)); + if (wrap.IsEmpty()) + return scope.Close( Undefined() ); + + FieldState *tmp = (FieldState *) wrap->Value(); + if (tmp == NULL) + return scope.Close( Undefined() ); + + return scope.Close( Int32::New(tmp->getWidth()) ); +} + +static void Set_FieldState_width(Local property, Local value, const AccessorInfo& info) +{ + HandleScope scope; + + Local self = info.Holder(); + Local wrap = Local::Cast(self->GetInternalField(0)); + if (wrap.IsEmpty()) + return; + + FieldState *tmp = (FieldState *) wrap->Value(); + if (tmp == NULL) + return; + + if (!value.IsEmpty() && value->IsNumber()) + tmp->setWidth(value->Int32Value()); +} + + +static Handle Get_FieldState_height(Local property, const AccessorInfo &info) +{ + HandleScope scope; + + Local self = info.Holder(); + Local wrap = Local::Cast(self->GetInternalField(0)); + if (wrap.IsEmpty()) + return scope.Close( Undefined() ); + + FieldState *tmp = (FieldState *) wrap->Value(); + if (tmp == NULL) + return scope.Close( Undefined() ); + + return scope.Close( Int32::New(tmp->getHeight()) ); +} + +static void Set_FieldState_height(Local property, Local value, const AccessorInfo& info) +{ + HandleScope scope; + + Local self = info.Holder(); + Local wrap = Local::Cast(self->GetInternalField(0)); + if (wrap.IsEmpty()) + return; + + FieldState *tmp = (FieldState *) wrap->Value(); + if (tmp == NULL) + return; + + if (!value.IsEmpty() && value->IsNumber()) + tmp->setHeight(value->Int32Value()); +} + + +static Handle Get_FieldState_left(Local property, const AccessorInfo &info) +{ + HandleScope scope; + + Local self = info.Holder(); + Local wrap = Local::Cast(self->GetInternalField(0)); + if (wrap.IsEmpty()) + return scope.Close( Undefined() ); + + FieldState *tmp = (FieldState *) wrap->Value(); + if (tmp == NULL) + return scope.Close( Undefined() ); + + return scope.Close( Int32::New(tmp->getLeft()) ); +} + +static void Set_FieldState_left(Local property, Local value, const AccessorInfo& info) +{ + HandleScope scope; + + Local self = info.Holder(); + Local wrap = Local::Cast(self->GetInternalField(0)); + if (wrap.IsEmpty()) + return; + + FieldState *tmp = (FieldState *) wrap->Value(); + if (tmp == NULL) + return; + + if (!value.IsEmpty() && value->IsNumber()) + tmp->setLeft(value->Int32Value()); +} + + +static Handle Get_FieldState_top(Local property, const AccessorInfo &info) +{ + HandleScope scope; + + Local self = info.Holder(); + Local wrap = Local::Cast(self->GetInternalField(0)); + if (wrap.IsEmpty()) + return scope.Close( Undefined() ); + + FieldState *tmp = (FieldState *) wrap->Value(); + if (tmp == NULL) + return scope.Close( Undefined() ); + + return scope.Close( Int32::New(tmp->getTop()) ); +} + +static void Set_FieldState_top(Local property, Local value, const AccessorInfo& info) +{ + HandleScope scope; + + Local self = info.Holder(); + Local wrap = Local::Cast(self->GetInternalField(0)); + if (wrap.IsEmpty()) + return; + + FieldState *tmp = (FieldState *) wrap->Value(); + if (tmp == NULL) + return; + + if (!value.IsEmpty() && value->IsNumber()) + tmp->setTop(value->Int32Value()); +} + + +static Handle Get_FieldState_right(Local property, const AccessorInfo &info) +{ + HandleScope scope; + + Local self = info.Holder(); + Local wrap = Local::Cast(self->GetInternalField(0)); + if (wrap.IsEmpty()) + return scope.Close( Undefined() ); + + FieldState *tmp = (FieldState *) wrap->Value(); + if (tmp == NULL) + return scope.Close( Undefined() ); + + return scope.Close( Int32::New(tmp->getRight()) ); +} + +static void Set_FieldState_right(Local property, Local value, const AccessorInfo& info) +{ + HandleScope scope; + + Local self = info.Holder(); + Local wrap = Local::Cast(self->GetInternalField(0)); + if (wrap.IsEmpty()) + return; + + FieldState *tmp = (FieldState *) wrap->Value(); + if (tmp == NULL) + return; + + if (!value.IsEmpty() && value->IsNumber()) + tmp->setRight(value->Int32Value()); +} + + +static Handle Get_FieldState_bottom(Local property, const AccessorInfo &info) +{ + HandleScope scope; + + Local self = info.Holder(); + Local wrap = Local::Cast(self->GetInternalField(0)); + if (wrap.IsEmpty()) + return scope.Close( Undefined() ); + + FieldState *tmp = (FieldState *) wrap->Value(); + if (tmp == NULL) + return scope.Close( Undefined() ); + + return scope.Close( Int32::New(tmp->getBottom()) ); +} + +static void Set_FieldState_bottom(Local property, Local value, const AccessorInfo& info) +{ + HandleScope scope; + + Local self = info.Holder(); + Local wrap = Local::Cast(self->GetInternalField(0)); + if (wrap.IsEmpty()) + return; + + FieldState *tmp = (FieldState *) wrap->Value(); + if (tmp == NULL) + return; + + if (!value.IsEmpty() && value->IsNumber()) + tmp->setBottom(value->Int32Value()); +} + + +static Handle Get_FieldState_visible(Local property, const AccessorInfo &info) +{ + HandleScope scope; + + Local self = info.Holder(); + Local wrap = Local::Cast(self->GetInternalField(0)); + if (wrap.IsEmpty()) + return scope.Close( Undefined() ); + + FieldState *tmp = (FieldState *) wrap->Value(); + if (tmp == NULL) + return scope.Close( Undefined() ); + + return scope.Close( Boolean::New(tmp->isVisible()) ); +} + +static void Set_FieldState_visible(Local property, Local value, const AccessorInfo& info) +{ + HandleScope scope; + + Local self = info.Holder(); + Local wrap = Local::Cast(self->GetInternalField(0)); + if (wrap.IsEmpty()) + return; + + FieldState *tmp = (FieldState *) wrap->Value(); + if (tmp == NULL) + return; + + if (!value.IsEmpty() && value->IsBoolean()) + tmp->setVisible(value->BooleanValue()); +} + + +static Handle Get_FieldState_enabled(Local property, const AccessorInfo &info) +{ + HandleScope scope; + + Local self = info.Holder(); + Local wrap = Local::Cast(self->GetInternalField(0)); + if (wrap.IsEmpty()) + return scope.Close( Undefined() ); + + FieldState *tmp = (FieldState *) wrap->Value(); + if (tmp == NULL) + return scope.Close( Undefined() ); + + return scope.Close( Boolean::New(tmp->isEnabled()) ); +} + + +static Handle Get_FieldState_toolTip(Local property, const AccessorInfo &info) +{ + HandleScope scope; + + Local self = info.Holder(); + Local wrap = Local::Cast(self->GetInternalField(0)); + if (wrap.IsEmpty()) + return scope.Close( Undefined() ); + + FieldState *tmp = (FieldState *) wrap->Value(); + if (tmp == NULL) + return scope.Close( Undefined() ); + + return scope.Close( String::New((const V8_TCHAR *) tmp->getToolTip()) ); +} + +static void Set_FieldState_toolTip(Local property, Local value, const AccessorInfo& info) +{ + HandleScope scope; + + Local self = info.Holder(); + Local wrap = Local::Cast(self->GetInternalField(0)); + if (wrap.IsEmpty()) + return; + + FieldState *tmp = (FieldState *) wrap->Value(); + if (tmp == NULL) + return; + + if (!value.IsEmpty() && value->IsString()) + { + String::Utf8Value utf8_value(value); + tmp->setToolTip(Utf8ToTchar(*utf8_value)); + } +} + + +static Handle Get_FieldState_hAlign(Local property, const AccessorInfo &info) +{ + HandleScope scope; + + Local self = info.Holder(); + Local wrap = Local::Cast(self->GetInternalField(0)); + if (wrap.IsEmpty()) + return scope.Close( Undefined() ); + + FieldState *tmp = (FieldState *) wrap->Value(); + if (tmp == NULL) + return scope.Close( Undefined() ); + + switch(tmp->getHAlign()) + { + case HORIZONTAL_ALIGN_LEFT: return scope.Close( String::New((const V8_TCHAR *) _T("LEFT")) ); + case HORIZONTAL_ALIGN_CENTER: return scope.Close( String::New((const V8_TCHAR *) _T("CENTER")) ); + case HORIZONTAL_ALIGN_RIGHT: return scope.Close( String::New((const V8_TCHAR *) _T("RIGHT")) ); + } + return scope.Close( Undefined() ); +} + +static void Set_FieldState_hAlign(Local property, Local value, const AccessorInfo& info) +{ + HandleScope scope; + + Local self = info.Holder(); + Local wrap = Local::Cast(self->GetInternalField(0)); + if (wrap.IsEmpty()) + return; + + FieldState *tmp = (FieldState *) wrap->Value(); + if (tmp == NULL) + return; + + if (!value.IsEmpty() && value->IsString()) + { + String::Utf8Value utf8_value(value); + Utf8ToTchar tval(*utf8_value); + if ( lstrcmpi(_T("HORIZONTAL_ALIGN_LEFT"), tval) == 0 ) + tmp->setHAlign(HORIZONTAL_ALIGN_LEFT); + else if ( lstrcmpi(_T("LEFT"), tval) == 0 ) + tmp->setHAlign(HORIZONTAL_ALIGN_LEFT); + else if ( lstrcmpi(_T("HORIZONTAL_ALIGN_CENTER"), tval) == 0 ) + tmp->setHAlign(HORIZONTAL_ALIGN_CENTER); + else if ( lstrcmpi(_T("CENTER"), tval) == 0 ) + tmp->setHAlign(HORIZONTAL_ALIGN_CENTER); + else if ( lstrcmpi(_T("HORIZONTAL_ALIGN_RIGHT"), tval) == 0 ) + tmp->setHAlign(HORIZONTAL_ALIGN_RIGHT); + else if ( lstrcmpi(_T("RIGHT"), tval) == 0 ) + tmp->setHAlign(HORIZONTAL_ALIGN_RIGHT); + } +} + + +static Handle Get_FieldState_vAlign(Local property, const AccessorInfo &info) +{ + HandleScope scope; + + Local self = info.Holder(); + Local wrap = Local::Cast(self->GetInternalField(0)); + if (wrap.IsEmpty()) + return scope.Close( Undefined() ); + + FieldState *tmp = (FieldState *) wrap->Value(); + if (tmp == NULL) + return scope.Close( Undefined() ); + + switch(tmp->getVAlign()) + { + case VERTICAL_ALIGN_TOP: return scope.Close( String::New((const V8_TCHAR *) _T("TOP")) ); + case VERTICAL_ALIGN_CENTER: return scope.Close( String::New((const V8_TCHAR *) _T("CENTER")) ); + case VERTICAL_ALIGN_BOTTOM: return scope.Close( String::New((const V8_TCHAR *) _T("BOTTOM")) ); + } + return scope.Close( Undefined() ); +} + +static void Set_FieldState_vAlign(Local property, Local value, const AccessorInfo& info) +{ + HandleScope scope; + + Local self = info.Holder(); + Local wrap = Local::Cast(self->GetInternalField(0)); + if (wrap.IsEmpty()) + return; + + FieldState *tmp = (FieldState *) wrap->Value(); + if (tmp == NULL) + return; + + if (!value.IsEmpty() && value->IsString()) + { + String::Utf8Value utf8_value(value); + Utf8ToTchar tval(*utf8_value); + if ( lstrcmpi(_T("VERTICAL_ALIGN_TOP"), tval) == 0 ) + tmp->setVAlign(VERTICAL_ALIGN_TOP); + else if ( lstrcmpi(_T("TOP"), tval) == 0 ) + tmp->setVAlign(VERTICAL_ALIGN_TOP); + else if ( lstrcmpi(_T("VERTICAL_ALIGN_CENTER"), tval) == 0 ) + tmp->setVAlign(VERTICAL_ALIGN_CENTER); + else if ( lstrcmpi(_T("CENTER"), tval) == 0 ) + tmp->setVAlign(VERTICAL_ALIGN_CENTER); + else if ( lstrcmpi(_T("VERTICAL_ALIGN_BOTTOM"), tval) == 0 ) + tmp->setVAlign(VERTICAL_ALIGN_BOTTOM); + else if ( lstrcmpi(_T("BOTTOM"), tval) == 0 ) + tmp->setVAlign(VERTICAL_ALIGN_BOTTOM); + } +} + + +static Handle Get_FieldState_borders(Local property, const AccessorInfo &info) +{ + HandleScope scope; + + Local self = info.Holder(); + Local wrap = Local::Cast(self->GetInternalField(0)); + if (wrap.IsEmpty()) + return scope.Close( Undefined() ); + + FieldState *tmp = (FieldState *) wrap->Value(); + if (tmp == NULL) + return scope.Close( Undefined() ); + + return scope.Close( self->Get(String::New("bordersRaw")) ); +} + +static void Set_FieldState_borders(Local property, Local value, const AccessorInfo& info) +{ + HandleScope scope; + + Local self = info.Holder(); + Local wrap = Local::Cast(self->GetInternalField(0)); + if (wrap.IsEmpty()) + return; + + FieldState *tmp = (FieldState *) wrap->Value(); + if (tmp == NULL) + return; + + if (!value.IsEmpty() && value->IsInt32()) + tmp->getBorders()->setAll(value->Int32Value()); +} + + +void AddFieldStateAcessors(Handle &templ) +{ + HandleScope scope; + + templ->SetAccessor(String::New("x"), Get_FieldState_x, Set_FieldState_x); + templ->SetAccessor(String::New("y"), Get_FieldState_y, Set_FieldState_y); + templ->SetAccessor(String::New("width"), Get_FieldState_width, Set_FieldState_width); + templ->SetAccessor(String::New("height"), Get_FieldState_height, Set_FieldState_height); + templ->SetAccessor(String::New("left"), Get_FieldState_left, Set_FieldState_left); + templ->SetAccessor(String::New("top"), Get_FieldState_top, Set_FieldState_top); + templ->SetAccessor(String::New("right"), Get_FieldState_right, Set_FieldState_right); + templ->SetAccessor(String::New("bottom"), Get_FieldState_bottom, Set_FieldState_bottom); + templ->SetAccessor(String::New("visible"), Get_FieldState_visible, Set_FieldState_visible); + templ->SetAccessor(String::New("enabled"), Get_FieldState_enabled, NULL, Handle(), DEFAULT, ReadOnly); + templ->SetAccessor(String::New("toolTip"), Get_FieldState_toolTip, Set_FieldState_toolTip); + templ->SetAccessor(String::New("hAlign"), Get_FieldState_hAlign, Set_FieldState_hAlign); + templ->SetAccessor(String::New("vAlign"), Get_FieldState_vAlign, Set_FieldState_vAlign); + templ->SetAccessor(String::New("borders"), Get_FieldState_borders, Set_FieldState_borders); +} diff --git a/plugins/Skins/SkinLib/FieldState_v8_wrapper.h b/plugins/Skins/SkinLib/FieldState_v8_wrapper.h new file mode 100644 index 0000000000..10c2a854b4 --- /dev/null +++ b/plugins/Skins/SkinLib/FieldState_v8_wrapper.h @@ -0,0 +1,10 @@ +#ifndef __FIELD_STATE_V8_WRAPPER_H__ +# define __FIELD_STATE_V8_WRAPPER_H__ + +#include + +void AddFieldStateAcessors(v8::Handle &templ); + + + +#endif // __FIELD_STATE_V8_WRAPPER_H__ diff --git a/plugins/Skins/SkinLib/FontState.cpp b/plugins/Skins/SkinLib/FontState.cpp new file mode 100644 index 0000000000..da9b4153d5 --- /dev/null +++ b/plugins/Skins/SkinLib/FontState.cpp @@ -0,0 +1,186 @@ +#include "globals.h" +#include "FontState.h" + + +FontState::FontState(HFONT hFont, COLORREF aColor) : hFont(NULL), externalFont(false), color(aColor) +{ + setHFONT(hFont); +} + +FontState::~FontState() +{ + releaseHFONT(); +} + +void FontState::rebuildHFONT() +{ + releaseHFONT(); + buildHFONT(); +} + +void FontState::buildAttribs() +{ + LOGFONT lf = {0}; + if (hFont == NULL || GetObject(hFont, sizeof(lf), &lf) == 0) + { + face = _T("Tahoma"); + size = 9; + italic = false; + bold = false; + underline = false; + strikeout = false; + + rebuildHFONT(); + + return; + } + + face = lf.lfFaceName; + italic = (lf.lfItalic != 0); + bold = (lf.lfWeight > FW_NORMAL); + underline = (lf.lfUnderline != 0); + strikeout = (lf.lfStrikeOut != 0); + + HDC hdc = GetDC(NULL); + size = -MulDiv(lf.lfHeight, 72, GetDeviceCaps(hdc, LOGPIXELSY)); + ReleaseDC(NULL, hdc); +} + +void FontState::buildHFONT() +{ + if (hFont != NULL) + return; + + LOGFONT lf; + + _tcscpy(lf.lfFaceName, getFace()); + + lf.lfWidth = lf.lfEscapement = lf.lfOrientation = 0; + lf.lfWeight = isBold() ? FW_BOLD : FW_NORMAL; + lf.lfItalic = isItalic() ? 1 : 0; + lf.lfUnderline = isUnderline() ? 1 : 0; + lf.lfStrikeOut = isStrikeOut() ? 1 : 0; + lf.lfCharSet = DEFAULT_CHARSET; + lf.lfOutPrecision = OUT_DEFAULT_PRECIS; + lf.lfClipPrecision = CLIP_DEFAULT_PRECIS; + lf.lfQuality = DEFAULT_QUALITY; + lf.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE; + + HDC hdc = GetDC(NULL); + lf.lfHeight = -MulDiv(getSize(), GetDeviceCaps(hdc, LOGPIXELSY), 72); + ReleaseDC(NULL, hdc); + + hFont = CreateFontIndirect(&lf); + externalFont = false; +} + +void FontState::releaseHFONT() +{ + if (hFont == NULL) + return; + + if (!externalFont) + DeleteObject(hFont); + + hFont = NULL; +} + + +HFONT FontState::getHFONT() const +{ + return hFont; +} + + +HFONT FontState::createHFONT() const +{ + LOGFONT lf; + if (hFont == NULL || GetObject(hFont, sizeof(lf), &lf) == 0) + return NULL; + else + return CreateFontIndirect(&lf); +} + +void FontState::setHFONT(HFONT hFont) +{ + releaseHFONT(); + this->hFont = hFont; + externalFont = true; + buildAttribs(); +} + +const TCHAR * FontState::getFace() const +{ + return face.c_str(); +} + +void FontState::setFace(const TCHAR * face) +{ + this->face = face; + rebuildHFONT(); +} + +int FontState::getSize() const +{ + return size; +} + +void FontState::setSize(int size) +{ + this->size = size; + rebuildHFONT(); +} + +COLORREF FontState::getColor() const +{ + return color; +} + +void FontState::setColor(COLORREF color) +{ + this->color = color; +} + +bool FontState::isItalic() const +{ + return italic; +} + +void FontState::setItalic(bool italic) +{ + this->italic = italic; + rebuildHFONT(); +} + +bool FontState::isBold() const +{ + return bold; +} + +void FontState::setBold(bool bold) +{ + this->bold = bold; + rebuildHFONT(); +} + +bool FontState::isUnderline() const +{ + return underline; +} + +void FontState::setUnderline(bool underline) +{ + this->underline = underline; + rebuildHFONT(); +} + +bool FontState::isStrikeOut() const +{ + return strikeout; +} + +void FontState::setStrikeOut(bool strikeout) +{ + this->strikeout = strikeout; + rebuildHFONT(); +} diff --git a/plugins/Skins/SkinLib/FontState.h b/plugins/Skins/SkinLib/FontState.h new file mode 100644 index 0000000000..de32bcdfb3 --- /dev/null +++ b/plugins/Skins/SkinLib/FontState.h @@ -0,0 +1,57 @@ +#ifndef __FONT_STATE_H__ +# define __FONT_STATE_H__ + +#include "Field.h" + + +class FontState +{ +public: + FontState(HFONT hFont, COLORREF aColor); + ~FontState(); + + HFONT getHFONT() const; + void setHFONT(HFONT hFont); + HFONT createHFONT() const; /// Return a copy of the internal HFONT. The caller must free it + + const TCHAR * getFace() const; + void setFace(const TCHAR * face); + + int getSize() const; + void setSize(int size); + + COLORREF getColor() const; + void setColor(COLORREF color); + + bool isItalic() const; + void setItalic(bool italic); + + bool isBold() const; + void setBold(bool bold); + + bool isUnderline() const; + void setUnderline(bool underline); + + bool isStrikeOut() const; + void setStrikeOut(bool strikeout); + +private: + COLORREF color; + HFONT hFont; + bool externalFont; + std::tstring face; + int size; + bool italic; + bool bold; + bool underline; + bool strikeout; + + void rebuildHFONT(); + void buildHFONT(); + void releaseHFONT(); + void buildAttribs(); +}; + + + +#endif // __FONT_STATE_H__ diff --git a/plugins/Skins/SkinLib/FontState_v8_wrapper.cpp b/plugins/Skins/SkinLib/FontState_v8_wrapper.cpp new file mode 100644 index 0000000000..5226736b24 --- /dev/null +++ b/plugins/Skins/SkinLib/FontState_v8_wrapper.cpp @@ -0,0 +1,269 @@ +#include "globals.h" +#include "FontState_v8_wrapper.h" +#include +#include "FontState.h" +#include + +using namespace v8; + + +#ifdef UNICODE +# define V8_TCHAR uint16_t +#else +# define V8_TCHAR char +#endif + + +static Handle Get_FontState_face(Local property, const AccessorInfo &info) +{ + HandleScope scope; + + Local self = info.Holder(); + Local wrap = Local::Cast(self->GetInternalField(0)); + if (wrap.IsEmpty()) + return scope.Close( Undefined() ); + + FontState *tmp = (FontState *) wrap->Value(); + if (tmp == NULL) + return scope.Close( Undefined() ); + + return scope.Close( String::New((const V8_TCHAR *) tmp->getFace()) ); +} + +static void Set_FontState_face(Local property, Local value, const AccessorInfo& info) +{ + HandleScope scope; + + Local self = info.Holder(); + Local wrap = Local::Cast(self->GetInternalField(0)); + if (wrap.IsEmpty()) + return; + + FontState *tmp = (FontState *) wrap->Value(); + if (tmp == NULL) + return; + + if (!value.IsEmpty() && value->IsString()) + { + String::Utf8Value utf8_value(value); + tmp->setFace(Utf8ToTchar(*utf8_value)); + } +} + + +static Handle Get_FontState_size(Local property, const AccessorInfo &info) +{ + HandleScope scope; + + Local self = info.Holder(); + Local wrap = Local::Cast(self->GetInternalField(0)); + if (wrap.IsEmpty()) + return scope.Close( Undefined() ); + + FontState *tmp = (FontState *) wrap->Value(); + if (tmp == NULL) + return scope.Close( Undefined() ); + + return scope.Close( Int32::New(tmp->getSize()) ); +} + +static void Set_FontState_size(Local property, Local value, const AccessorInfo& info) +{ + HandleScope scope; + + Local self = info.Holder(); + Local wrap = Local::Cast(self->GetInternalField(0)); + if (wrap.IsEmpty()) + return; + + FontState *tmp = (FontState *) wrap->Value(); + if (tmp == NULL) + return; + + if (!value.IsEmpty() && value->IsNumber()) + tmp->setSize(value->Int32Value()); +} + + +static Handle Get_FontState_italic(Local property, const AccessorInfo &info) +{ + HandleScope scope; + + Local self = info.Holder(); + Local wrap = Local::Cast(self->GetInternalField(0)); + if (wrap.IsEmpty()) + return scope.Close( Undefined() ); + + FontState *tmp = (FontState *) wrap->Value(); + if (tmp == NULL) + return scope.Close( Undefined() ); + + return scope.Close( Boolean::New(tmp->isItalic()) ); +} + +static void Set_FontState_italic(Local property, Local value, const AccessorInfo& info) +{ + HandleScope scope; + + Local self = info.Holder(); + Local wrap = Local::Cast(self->GetInternalField(0)); + if (wrap.IsEmpty()) + return; + + FontState *tmp = (FontState *) wrap->Value(); + if (tmp == NULL) + return; + + if (!value.IsEmpty() && value->IsBoolean()) + tmp->setItalic(value->BooleanValue()); +} + + +static Handle Get_FontState_bold(Local property, const AccessorInfo &info) +{ + HandleScope scope; + + Local self = info.Holder(); + Local wrap = Local::Cast(self->GetInternalField(0)); + if (wrap.IsEmpty()) + return scope.Close( Undefined() ); + + FontState *tmp = (FontState *) wrap->Value(); + if (tmp == NULL) + return scope.Close( Undefined() ); + + return scope.Close( Boolean::New(tmp->isBold()) ); +} + +static void Set_FontState_bold(Local property, Local value, const AccessorInfo& info) +{ + HandleScope scope; + + Local self = info.Holder(); + Local wrap = Local::Cast(self->GetInternalField(0)); + if (wrap.IsEmpty()) + return; + + FontState *tmp = (FontState *) wrap->Value(); + if (tmp == NULL) + return; + + if (!value.IsEmpty() && value->IsBoolean()) + tmp->setBold(value->BooleanValue()); +} + + +static Handle Get_FontState_underline(Local property, const AccessorInfo &info) +{ + HandleScope scope; + + Local self = info.Holder(); + Local wrap = Local::Cast(self->GetInternalField(0)); + if (wrap.IsEmpty()) + return scope.Close( Undefined() ); + + FontState *tmp = (FontState *) wrap->Value(); + if (tmp == NULL) + return scope.Close( Undefined() ); + + return scope.Close( Boolean::New(tmp->isUnderline()) ); +} + +static void Set_FontState_underline(Local property, Local value, const AccessorInfo& info) +{ + HandleScope scope; + + Local self = info.Holder(); + Local wrap = Local::Cast(self->GetInternalField(0)); + if (wrap.IsEmpty()) + return; + + FontState *tmp = (FontState *) wrap->Value(); + if (tmp == NULL) + return; + + if (!value.IsEmpty() && value->IsBoolean()) + tmp->setUnderline(value->BooleanValue()); +} + + +static Handle Get_FontState_strikeOut(Local property, const AccessorInfo &info) +{ + HandleScope scope; + + Local self = info.Holder(); + Local wrap = Local::Cast(self->GetInternalField(0)); + if (wrap.IsEmpty()) + return scope.Close( Undefined() ); + + FontState *tmp = (FontState *) wrap->Value(); + if (tmp == NULL) + return scope.Close( Undefined() ); + + return scope.Close( Boolean::New(tmp->isStrikeOut()) ); +} + +static void Set_FontState_strikeOut(Local property, Local value, const AccessorInfo& info) +{ + HandleScope scope; + + Local self = info.Holder(); + Local wrap = Local::Cast(self->GetInternalField(0)); + if (wrap.IsEmpty()) + return; + + FontState *tmp = (FontState *) wrap->Value(); + if (tmp == NULL) + return; + + if (!value.IsEmpty() && value->IsBoolean()) + tmp->setStrikeOut(value->BooleanValue()); +} + + +static Handle Get_FontState_color(Local property, const AccessorInfo &info) +{ + HandleScope scope; + + Local self = info.Holder(); + Local wrap = Local::Cast(self->GetInternalField(0)); + if (wrap.IsEmpty()) + return scope.Close( Undefined() ); + + FontState *tmp = (FontState *) wrap->Value(); + if (tmp == NULL) + return scope.Close( Undefined() ); + + return scope.Close( Int32::New(tmp->getColor()) ); +} + +static void Set_FontState_color(Local property, Local value, const AccessorInfo& info) +{ + HandleScope scope; + + Local self = info.Holder(); + Local wrap = Local::Cast(self->GetInternalField(0)); + if (wrap.IsEmpty()) + return; + + FontState *tmp = (FontState *) wrap->Value(); + if (tmp == NULL) + return; + + if (!value.IsEmpty() && value->IsNumber()) + tmp->setColor(value->Int32Value()); +} + + +void AddFontStateAcessors(Handle &templ) +{ + HandleScope scope; + + templ->SetAccessor(String::New("face"), Get_FontState_face, Set_FontState_face); + templ->SetAccessor(String::New("size"), Get_FontState_size, Set_FontState_size); + templ->SetAccessor(String::New("italic"), Get_FontState_italic, Set_FontState_italic); + templ->SetAccessor(String::New("bold"), Get_FontState_bold, Set_FontState_bold); + templ->SetAccessor(String::New("underline"), Get_FontState_underline, Set_FontState_underline); + templ->SetAccessor(String::New("strikeOut"), Get_FontState_strikeOut, Set_FontState_strikeOut); + templ->SetAccessor(String::New("color"), Get_FontState_color, Set_FontState_color); +} diff --git a/plugins/Skins/SkinLib/FontState_v8_wrapper.h b/plugins/Skins/SkinLib/FontState_v8_wrapper.h new file mode 100644 index 0000000000..4b0483ffd9 --- /dev/null +++ b/plugins/Skins/SkinLib/FontState_v8_wrapper.h @@ -0,0 +1,10 @@ +#ifndef __FONT_STATE_V8_WRAPPER_H__ +# define __FONT_STATE_V8_WRAPPER_H__ + +#include + +void AddFontStateAcessors(v8::Handle &templ); + + + +#endif // __FONT_STATE_V8_WRAPPER_H__ diff --git a/plugins/Skins/SkinLib/IconField.cpp b/plugins/Skins/SkinLib/IconField.cpp new file mode 100644 index 0000000000..4cf1aaf532 --- /dev/null +++ b/plugins/Skins/SkinLib/IconField.cpp @@ -0,0 +1,38 @@ +#include "globals.h" +#include "IconField.h" +#include "IconFieldState.h" + + +IconField::IconField(Dialog *dlg, const char *name) + : Field(dlg, name), hIcon(NULL) +{ + +} + +IconField::~IconField() +{ +} + +FieldType IconField::getType() const +{ + return SIMPLE_ICON; +} + +HICON IconField::getIcon() const +{ + return hIcon; +} + +void IconField::setIcon(HICON hIcon) +{ + if (this->hIcon == hIcon) + return; + + this->hIcon = hIcon; + fireOnChange(); +} + +FieldState * IconField::createState(DialogState *dialogState) +{ + return new IconFieldState(dialogState, this); +} \ No newline at end of file diff --git a/plugins/Skins/SkinLib/IconField.h b/plugins/Skins/SkinLib/IconField.h new file mode 100644 index 0000000000..984b36b984 --- /dev/null +++ b/plugins/Skins/SkinLib/IconField.h @@ -0,0 +1,27 @@ +#ifndef __ICON_FIELD_H__ +# define __ICON_FIELD_H__ + +#include "Field.h" + + +class IconField : public Field +{ +public: + IconField(Dialog *dlg, const char *name); + virtual ~IconField(); + + virtual FieldType getType() const; + + virtual HICON getIcon() const; + virtual void setIcon(HICON hIcon); + + virtual FieldState * createState(DialogState *dialogState); + +private: + HICON hIcon; + +}; + + + +#endif // __ICON_FIELD_H__ \ No newline at end of file diff --git a/plugins/Skins/SkinLib/IconFieldState.cpp b/plugins/Skins/SkinLib/IconFieldState.cpp new file mode 100644 index 0000000000..fad1d67084 --- /dev/null +++ b/plugins/Skins/SkinLib/IconFieldState.cpp @@ -0,0 +1,37 @@ +#include "globals.h" +#include "IconFieldState.h" + +#define ICON_SIZE 16 + + +IconFieldState::IconFieldState(DialogState *dialog, IconField *field) + : FieldState(dialog, field) +{ +} + +IconFieldState::~IconFieldState() +{ +} + +IconField * IconFieldState::getField() const +{ + return (IconField *) FieldState::getField(); +} + +Size IconFieldState::getPreferedSize() const +{ + if (getIcon() == NULL) + return Size(0, 0); + + return Size(ICON_SIZE, ICON_SIZE); +} + +HICON IconFieldState::getIcon() const +{ + return getField()->getIcon(); +} + +bool IconFieldState::isEmpty() const +{ + return getIcon() == NULL; +} \ No newline at end of file diff --git a/plugins/Skins/SkinLib/IconFieldState.h b/plugins/Skins/SkinLib/IconFieldState.h new file mode 100644 index 0000000000..b69e3fe01f --- /dev/null +++ b/plugins/Skins/SkinLib/IconFieldState.h @@ -0,0 +1,28 @@ +#ifndef __ICON_FIELD_STATE_H__ +# define __ICON_FIELD_STATE_H__ + +#include "IconField.h" +#include "FieldState.h" + + +class IconFieldState : public FieldState +{ +public: + virtual ~IconFieldState(); + + virtual IconField * getField() const; + + virtual Size getPreferedSize() const; + + virtual HICON getIcon() const; + + virtual bool isEmpty() const; + +private: + IconFieldState(DialogState *dialog, IconField *field); + + friend class IconField; +}; + + +#endif // __ICON_FIELD_STATE_H__ \ No newline at end of file diff --git a/plugins/Skins/SkinLib/IconFieldState_v8_wrapper.cpp b/plugins/Skins/SkinLib/IconFieldState_v8_wrapper.cpp new file mode 100644 index 0000000000..a955653652 --- /dev/null +++ b/plugins/Skins/SkinLib/IconFieldState_v8_wrapper.cpp @@ -0,0 +1,20 @@ +#include "globals.h" +#include "IconFieldState_v8_wrapper.h" +#include +#include "IconFieldState.h" + +using namespace v8; + + +#ifdef UNICODE +# define V8_TCHAR uint16_t +#else +# define V8_TCHAR char +#endif + + +void AddIconFieldStateAcessors(Handle &templ) +{ + HandleScope scope; + +} diff --git a/plugins/Skins/SkinLib/IconFieldState_v8_wrapper.h b/plugins/Skins/SkinLib/IconFieldState_v8_wrapper.h new file mode 100644 index 0000000000..7b63f801bc --- /dev/null +++ b/plugins/Skins/SkinLib/IconFieldState_v8_wrapper.h @@ -0,0 +1,10 @@ +#ifndef __ICON_FIELD_STATE_V8_WRAPPER_H__ +# define __ICON_FIELD_STATE_V8_WRAPPER_H__ + +#include + +void AddIconFieldStateAcessors(v8::Handle &templ); + + + +#endif // __ICON_FIELD_STATE_V8_WRAPPER_H__ diff --git a/plugins/Skins/SkinLib/ImageField.cpp b/plugins/Skins/SkinLib/ImageField.cpp new file mode 100644 index 0000000000..c65cf99a0f --- /dev/null +++ b/plugins/Skins/SkinLib/ImageField.cpp @@ -0,0 +1,38 @@ +#include "globals.h" +#include "ImageField.h" +#include "ImageFieldState.h" + + +ImageField::ImageField(Dialog *dlg, const char *name) + : Field(dlg, name), hBmp(NULL) +{ + +} + +ImageField::~ImageField() +{ +} + +FieldType ImageField::getType() const +{ + return SIMPLE_IMAGE; +} + +HBITMAP ImageField::getImage() const +{ + return hBmp; +} + +void ImageField::setImage(HBITMAP hBmp) +{ + if (this->hBmp == hBmp) + return; + + this->hBmp = hBmp; + fireOnChange(); +} + +FieldState * ImageField::createState(DialogState *dialogState) +{ + return new ImageFieldState(dialogState, this); +} \ No newline at end of file diff --git a/plugins/Skins/SkinLib/ImageField.h b/plugins/Skins/SkinLib/ImageField.h new file mode 100644 index 0000000000..e2f08665ca --- /dev/null +++ b/plugins/Skins/SkinLib/ImageField.h @@ -0,0 +1,26 @@ +#ifndef __IMAGE_FIELD_H__ +# define __IMAGE_FIELD_H__ + +#include "Field.h" + +class ImageField : public Field +{ +public: + ImageField(Dialog *dlg, const char *name); + virtual ~ImageField(); + + virtual FieldType getType() const; + + virtual HBITMAP getImage() const; + virtual void setImage(HBITMAP hBmp); + + virtual FieldState * createState(DialogState *dialogState); + +private: + HBITMAP hBmp; + +}; + + + +#endif // __IMAGE_FIELD_H__ \ No newline at end of file diff --git a/plugins/Skins/SkinLib/ImageFieldState.cpp b/plugins/Skins/SkinLib/ImageFieldState.cpp new file mode 100644 index 0000000000..f74d77e0f3 --- /dev/null +++ b/plugins/Skins/SkinLib/ImageFieldState.cpp @@ -0,0 +1,37 @@ +#include "globals.h" +#include "ImageFieldState.h" + + +ImageFieldState::ImageFieldState(DialogState *dialog, ImageField *field) + : FieldState(dialog, field) +{ +} + +ImageFieldState::~ImageFieldState() +{ +} + +ImageField * ImageFieldState::getField() const +{ + return (ImageField *) FieldState::getField(); +} + +Size ImageFieldState::getPreferedSize() const +{ + HBITMAP hBmp = getImage(); + BITMAP bmp; + if (hBmp == NULL || GetObject(hBmp, sizeof(bmp), &bmp) == 0) + return Size(0, 0); + + return Size(bmp.bmWidth, bmp.bmHeight); +} + +HBITMAP ImageFieldState::getImage() const +{ + return getField()->getImage(); +} + +bool ImageFieldState::isEmpty() const +{ + return getImage() == NULL; +} \ No newline at end of file diff --git a/plugins/Skins/SkinLib/ImageFieldState.h b/plugins/Skins/SkinLib/ImageFieldState.h new file mode 100644 index 0000000000..493c4db16d --- /dev/null +++ b/plugins/Skins/SkinLib/ImageFieldState.h @@ -0,0 +1,28 @@ +#ifndef __IMAGE_FIELD_STATE_H__ +# define __IMAGE_FIELD_STATE_H__ + +#include "ImageField.h" +#include "FieldState.h" + + +class ImageFieldState : public FieldState +{ +public: + virtual ~ImageFieldState(); + + virtual ImageField * getField() const; + + virtual Size getPreferedSize() const; + + virtual HBITMAP getImage() const; + + virtual bool isEmpty() const; + +private: + ImageFieldState(DialogState *dialog, ImageField *field); + + friend class ImageField; +}; + + +#endif // __IMAGE_FIELD_STATE_H__ \ No newline at end of file diff --git a/plugins/Skins/SkinLib/ImageFieldState_v8_wrapper.cpp b/plugins/Skins/SkinLib/ImageFieldState_v8_wrapper.cpp new file mode 100644 index 0000000000..1e4a9b6a54 --- /dev/null +++ b/plugins/Skins/SkinLib/ImageFieldState_v8_wrapper.cpp @@ -0,0 +1,20 @@ +#include "globals.h" +#include "ImageFieldState_v8_wrapper.h" +#include +#include "ImageFieldState.h" + +using namespace v8; + + +#ifdef UNICODE +# define V8_TCHAR uint16_t +#else +# define V8_TCHAR char +#endif + + +void AddImageFieldStateAcessors(Handle &templ) +{ + HandleScope scope; + +} diff --git a/plugins/Skins/SkinLib/ImageFieldState_v8_wrapper.h b/plugins/Skins/SkinLib/ImageFieldState_v8_wrapper.h new file mode 100644 index 0000000000..ea5f343e03 --- /dev/null +++ b/plugins/Skins/SkinLib/ImageFieldState_v8_wrapper.h @@ -0,0 +1,10 @@ +#ifndef __IMAGE_FIELD_STATE_V8_WRAPPER_H__ +# define __IMAGE_FIELD_STATE_V8_WRAPPER_H__ + +#include + +void AddImageFieldStateAcessors(v8::Handle &templ); + + + +#endif // __IMAGE_FIELD_STATE_V8_WRAPPER_H__ diff --git a/plugins/Skins/SkinLib/LabelField.cpp b/plugins/Skins/SkinLib/LabelField.cpp new file mode 100644 index 0000000000..154ae2fce5 --- /dev/null +++ b/plugins/Skins/SkinLib/LabelField.cpp @@ -0,0 +1,23 @@ +#include "globals.h" +#include "LabelField.h" +#include "LabelFieldState.h" + + +LabelField::LabelField(Dialog *dlg, const char *name, HWND hwnd) + : ControlField(dlg, name, hwnd) +{ +} + +LabelField::~LabelField() +{ +} + +FieldType LabelField::getType() const +{ + return CONTROL_LABEL; +} + +FieldState * LabelField::createState(DialogState *dialogState) +{ + return new LabelFieldState(dialogState, this); +} \ No newline at end of file diff --git a/plugins/Skins/SkinLib/LabelField.h b/plugins/Skins/SkinLib/LabelField.h new file mode 100644 index 0000000000..8c4cb04a03 --- /dev/null +++ b/plugins/Skins/SkinLib/LabelField.h @@ -0,0 +1,20 @@ +#ifndef __LABEL_FIELD_H__ +# define __LABEL_FIELD_H__ + +#include "ControlField.h" + + +class LabelField : public ControlField +{ +public: + LabelField(Dialog *dlg, const char *name, HWND hwnd); + virtual ~LabelField(); + + virtual FieldType getType() const; + + virtual FieldState * createState(DialogState *dialogState); +}; + + + +#endif // __LABEL_FIELD_H__ diff --git a/plugins/Skins/SkinLib/LabelFieldState.cpp b/plugins/Skins/SkinLib/LabelFieldState.cpp new file mode 100644 index 0000000000..364611fbf7 --- /dev/null +++ b/plugins/Skins/SkinLib/LabelFieldState.cpp @@ -0,0 +1,35 @@ +#include "globals.h" +#include "LabelFieldState.h" + + +LabelFieldState::LabelFieldState(DialogState *dialog, LabelField *field) + : ControlFieldState(dialog, field) +{ +} + +LabelFieldState::~LabelFieldState() +{ +} + +Size LabelFieldState::getPreferedSize() const +{ + int style = GetWindowLong(getField()->getHWND(), GWL_STYLE); + + int format = DT_EXPANDTABS | DT_EDITCONTROL; + if ((style & SS_LEFTNOWORDWRAP) || (style & SS_SIMPLE)) + format |= DT_SINGLELINE; + if (style & SS_NOPREFIX) + format |= DT_NOPREFIX; + Size ret = getTextPreferedSize(format); + + int border = getField()->getBorderSize(); + ret.x += 2 * border; + ret.y += 2 * border; + + return ret; +} + +bool LabelFieldState::isEmpty() const +{ + return lstrlen(getText()) <= 0; +} \ No newline at end of file diff --git a/plugins/Skins/SkinLib/LabelFieldState.h b/plugins/Skins/SkinLib/LabelFieldState.h new file mode 100644 index 0000000000..dbbb3b04d3 --- /dev/null +++ b/plugins/Skins/SkinLib/LabelFieldState.h @@ -0,0 +1,25 @@ +#ifndef __LABEL_FIELD_STATE_H__ +# define __LABEL_FIELD_STATE_H__ + +#include "ControlFieldState.h" +#include "LabelField.h" + + +class LabelFieldState : public ControlFieldState +{ +public: + virtual ~LabelFieldState(); + + virtual Size getPreferedSize() const; + + virtual bool isEmpty() const; + +private: + LabelFieldState(DialogState *dialog, LabelField *field); + + friend class LabelField; +}; + + + +#endif // __LABEL_FIELD_STATE_H__ diff --git a/plugins/Skins/SkinLib/LabelFieldState_v8_wrapper.cpp b/plugins/Skins/SkinLib/LabelFieldState_v8_wrapper.cpp new file mode 100644 index 0000000000..9105a7d878 --- /dev/null +++ b/plugins/Skins/SkinLib/LabelFieldState_v8_wrapper.cpp @@ -0,0 +1,20 @@ +#include "globals.h" +#include "LabelFieldState_v8_wrapper.h" +#include +#include "LabelFieldState.h" + +using namespace v8; + + +#ifdef UNICODE +# define V8_TCHAR uint16_t +#else +# define V8_TCHAR char +#endif + + +void AddLabelFieldStateAcessors(Handle &templ) +{ + HandleScope scope; + +} diff --git a/plugins/Skins/SkinLib/LabelFieldState_v8_wrapper.h b/plugins/Skins/SkinLib/LabelFieldState_v8_wrapper.h new file mode 100644 index 0000000000..7d40de5bc2 --- /dev/null +++ b/plugins/Skins/SkinLib/LabelFieldState_v8_wrapper.h @@ -0,0 +1,10 @@ +#ifndef __LABEL_FIELD_STATE_V8_WRAPPER_H__ +# define __LABEL_FIELD_STATE_V8_WRAPPER_H__ + +#include + +void AddLabelFieldStateAcessors(v8::Handle &templ); + + + +#endif // __LABEL_FIELD_STATE_V8_WRAPPER_H__ diff --git a/plugins/Skins/SkinLib/Position.cpp b/plugins/Skins/SkinLib/Position.cpp new file mode 100644 index 0000000000..6c68881fce --- /dev/null +++ b/plugins/Skins/SkinLib/Position.cpp @@ -0,0 +1,9 @@ +#include "Position.h" + +Position::Position() : x(0), y(0) +{ +} + +Position::Position(int aX, int aY) : x(aX), y(aY) +{ +} \ No newline at end of file diff --git a/plugins/Skins/SkinLib/Position.h b/plugins/Skins/SkinLib/Position.h new file mode 100644 index 0000000000..ed43a1ece3 --- /dev/null +++ b/plugins/Skins/SkinLib/Position.h @@ -0,0 +1,16 @@ +#ifndef __POSITION_H__ +# define __POSITION_H__ + + +struct Position +{ + int x; + int y; + + Position(); + Position(int x, int y); +}; + + + +#endif // __POSITION_H__ diff --git a/plugins/Skins/SkinLib/Size.cpp b/plugins/Skins/SkinLib/Size.cpp new file mode 100644 index 0000000000..9c2eef5d5d --- /dev/null +++ b/plugins/Skins/SkinLib/Size.cpp @@ -0,0 +1,84 @@ +#include "globals.h" +#include "Size.h" + +Size::Size() : x(0), y(0) +{ +} + +Size::Size(int aX, int aY) : x(aX), y(aY) +{ + +} + +int Size::resizeTo(int newX, int newY) +{ + if (newX < 0 && newY < 0) + return -1; + + if (newY < 0) + { + if (x < 0 || y < 0) + return -2; + + y = (int) (y * (newX / (float) x)); + x = newX; + } + else if (newX < 0) + { + if (x < 0 || y < 0) + return -2; + + x = (int) (x * (newY / (float) y)); + y = newY; + } + else + { + x = newX; + y = newY; + } + return 0; +} + +int Size::fitInside(int maxSize) +{ + if (x < 0 || y < 0) + return -2; + if (x <= maxSize && y <= maxSize) + return 0; + + if (x >= y) + { + y = (int) (y * (maxSize / (float) x)); + x = maxSize; + } + else + { + x = (int) (x * (maxSize / (float) y)); + y = maxSize; + } + return 0; +} + +int Size::scaleTo(int size) +{ + if (x < 0 || y < 0) + return -2; + + if (x >= y) + { + y = (int) (y * (size / (float) x)); + x = size; + } + else + { + x = (int) (x * (size / (float) y)); + y = size; + } + + return 0; +} + +bool Size::operator==(const Size &other) const +{ + return x == other.x && y == other.y; +} \ No newline at end of file diff --git a/plugins/Skins/SkinLib/Size.h b/plugins/Skins/SkinLib/Size.h new file mode 100644 index 0000000000..8c0a297aee --- /dev/null +++ b/plugins/Skins/SkinLib/Size.h @@ -0,0 +1,27 @@ +#ifndef __SIZE_H__ +# define __SIZE_H__ + + +struct Size +{ + int x; + int y; + + Size(); + Size(int aX, int aY); + + /// @return 0 on success + int resizeTo(int x, int y); + + /// @return 0 on success + int fitInside(int maxSize); + + /// @return 0 on success + int scaleTo(int size); + + bool operator==(const Size &other) const; +}; + + + +#endif // __SIZE_H__ diff --git a/plugins/Skins/SkinLib/SkinOption.h b/plugins/Skins/SkinLib/SkinOption.h new file mode 100644 index 0000000000..7812303327 --- /dev/null +++ b/plugins/Skins/SkinLib/SkinOption.h @@ -0,0 +1 @@ +#include "SkinOptions.h" \ No newline at end of file diff --git a/plugins/Skins/SkinLib/SkinOption_v8_wrapper.cpp b/plugins/Skins/SkinLib/SkinOption_v8_wrapper.cpp new file mode 100644 index 0000000000..11a401ad2e --- /dev/null +++ b/plugins/Skins/SkinLib/SkinOption_v8_wrapper.cpp @@ -0,0 +1,179 @@ +#include "globals.h" +#include "SkinOption_v8_wrapper.h" +#include +#include "SkinOption.h" +#include + +using namespace v8; + + +#ifdef UNICODE +# define V8_TCHAR uint16_t +#else +# define V8_TCHAR char +#endif + + +static Handle Get_SkinOption_description(Local property, const AccessorInfo &info) +{ + HandleScope scope; + + Local self = info.Holder(); + Local wrap = Local::Cast(self->GetInternalField(0)); + if (wrap.IsEmpty()) + return scope.Close( Undefined() ); + + SkinOption *tmp = (SkinOption *) wrap->Value(); + if (tmp == NULL) + return scope.Close( Undefined() ); + + return scope.Close( String::New((const V8_TCHAR *) tmp->getDescription()) ); +} + +static void Set_SkinOption_description(Local property, Local value, const AccessorInfo& info) +{ + HandleScope scope; + + Local self = info.Holder(); + Local wrap = Local::Cast(self->GetInternalField(0)); + if (wrap.IsEmpty()) + return; + + SkinOption *tmp = (SkinOption *) wrap->Value(); + if (tmp == NULL) + return; + + if (!value.IsEmpty() && value->IsString()) + { + String::Utf8Value utf8_value(value); + tmp->setDescription(Utf8ToTchar(*utf8_value)); + } +} + + +static Handle Get_SkinOption_min(Local property, const AccessorInfo &info) +{ + HandleScope scope; + + Local self = info.Holder(); + Local wrap = Local::Cast(self->GetInternalField(0)); + if (wrap.IsEmpty()) + return scope.Close( Undefined() ); + + SkinOption *tmp = (SkinOption *) wrap->Value(); + if (tmp == NULL) + return scope.Close( Undefined() ); + + return scope.Close( Int32::New(tmp->getMin()) ); +} + +static void Set_SkinOption_min(Local property, Local value, const AccessorInfo& info) +{ + HandleScope scope; + + Local self = info.Holder(); + Local wrap = Local::Cast(self->GetInternalField(0)); + if (wrap.IsEmpty()) + return; + + SkinOption *tmp = (SkinOption *) wrap->Value(); + if (tmp == NULL) + return; + + if (!value.IsEmpty() && value->IsNumber()) + tmp->setMin(value->Int32Value()); +} + + +static Handle Get_SkinOption_max(Local property, const AccessorInfo &info) +{ + HandleScope scope; + + Local self = info.Holder(); + Local wrap = Local::Cast(self->GetInternalField(0)); + if (wrap.IsEmpty()) + return scope.Close( Undefined() ); + + SkinOption *tmp = (SkinOption *) wrap->Value(); + if (tmp == NULL) + return scope.Close( Undefined() ); + + return scope.Close( Int32::New(tmp->getMax()) ); +} + +static void Set_SkinOption_max(Local property, Local value, const AccessorInfo& info) +{ + HandleScope scope; + + Local self = info.Holder(); + Local wrap = Local::Cast(self->GetInternalField(0)); + if (wrap.IsEmpty()) + return; + + SkinOption *tmp = (SkinOption *) wrap->Value(); + if (tmp == NULL) + return; + + if (!value.IsEmpty() && value->IsNumber()) + tmp->setMax(value->Int32Value()); +} + + +static Handle Get_SkinOption_type(Local property, const AccessorInfo &info) +{ + HandleScope scope; + + Local self = info.Holder(); + Local wrap = Local::Cast(self->GetInternalField(0)); + if (wrap.IsEmpty()) + return scope.Close( Undefined() ); + + SkinOption *tmp = (SkinOption *) wrap->Value(); + if (tmp == NULL) + return scope.Close( Undefined() ); + + switch(tmp->getType()) + { + case CHECKBOX: return scope.Close( String::New((const V8_TCHAR *) _T("CHECKBOX")) ); + case NUMBER: return scope.Close( String::New((const V8_TCHAR *) _T("NUMBER")) ); + case TEXT: return scope.Close( String::New((const V8_TCHAR *) _T("TEXT")) ); + } + return scope.Close( Undefined() ); +} + +static void Set_SkinOption_type(Local property, Local value, const AccessorInfo& info) +{ + HandleScope scope; + + Local self = info.Holder(); + Local wrap = Local::Cast(self->GetInternalField(0)); + if (wrap.IsEmpty()) + return; + + SkinOption *tmp = (SkinOption *) wrap->Value(); + if (tmp == NULL) + return; + + if (!value.IsEmpty() && value->IsString()) + { + String::Utf8Value utf8_value(value); + Utf8ToTchar tval(*utf8_value); + if ( lstrcmpi(_T("CHECKBOX"), tval) == 0 ) + tmp->setType(CHECKBOX); + else if ( lstrcmpi(_T("NUMBER"), tval) == 0 ) + tmp->setType(NUMBER); + else if ( lstrcmpi(_T("TEXT"), tval) == 0 ) + tmp->setType(TEXT); + } +} + + +void AddSkinOptionAcessors(Handle &templ) +{ + HandleScope scope; + + templ->SetAccessor(String::New("description"), Get_SkinOption_description, Set_SkinOption_description); + templ->SetAccessor(String::New("min"), Get_SkinOption_min, Set_SkinOption_min); + templ->SetAccessor(String::New("max"), Get_SkinOption_max, Set_SkinOption_max); + templ->SetAccessor(String::New("type"), Get_SkinOption_type, Set_SkinOption_type); +} diff --git a/plugins/Skins/SkinLib/SkinOption_v8_wrapper.h b/plugins/Skins/SkinLib/SkinOption_v8_wrapper.h new file mode 100644 index 0000000000..6aa05c2122 --- /dev/null +++ b/plugins/Skins/SkinLib/SkinOption_v8_wrapper.h @@ -0,0 +1,10 @@ +#ifndef __SKIN_OPTION_V8_WRAPPER_H__ +# define __SKIN_OPTION_V8_WRAPPER_H__ + +#include + +void AddSkinOptionAcessors(v8::Handle &templ); + + + +#endif // __SKIN_OPTION_V8_WRAPPER_H__ diff --git a/plugins/Skins/SkinLib/SkinOptions.cpp b/plugins/Skins/SkinLib/SkinOptions.cpp new file mode 100644 index 0000000000..51fb96cbdb --- /dev/null +++ b/plugins/Skins/SkinLib/SkinOptions.cpp @@ -0,0 +1,216 @@ +#include "globals.h" +#include "SkinOptions.h" +#include + + +SkinOption::SkinOption(const char *aName) + : name(aName), type(CHECKBOX), valueCheckbox(false), valueNumber(0), + onChangeCallback(NULL), onChangeCallbackParam(NULL), + minValue(MININT), maxValue(MAXINT) +{ + description = Utf8ToTchar(aName); +} + +SkinOption::~SkinOption() +{ +} + +const char * SkinOption::getName() const +{ + return name.c_str(); +} + +SkinOptionType SkinOption::getType() const +{ + return type; +} + +void SkinOption::setType(SkinOptionType type) +{ + if (this->type == type) + return; + + this->type = type; + fireOnChange(); +} + +const TCHAR * SkinOption::getDescription() const +{ + return description.c_str(); +} + +void SkinOption::setDescription(const TCHAR * description) +{ + if (this->description == description) + return; + + this->description = description; + fireOnChange(); +} + +int SkinOption::getMax() const +{ + return maxValue; +} + +void SkinOption::setMax(int max) +{ + this->maxValue = max; + setValueNumber(valueNumber); +} + +int SkinOption::getMin() const +{ + return minValue; +} + +void SkinOption::setMin(int min) +{ + this->minValue = min; + setValueNumber(valueNumber); +} + +bool SkinOption::getValueCheckbox() const +{ + return valueCheckbox; +} + +void SkinOption::setValueCheckbox(bool value) +{ + if (valueCheckbox == value) + return; + + valueCheckbox = value; + fireOnChange(); +} + +int SkinOption::getValueNumber() const +{ + return max(minValue, min(maxValue, valueNumber)); +} + +void SkinOption::setValueNumber(int value) +{ + value = max(minValue, min(maxValue, value)); + + if (value == valueNumber) + return; + + valueNumber = value; + fireOnChange(); +} + +const TCHAR * SkinOption::getValueText() const +{ + return valueText.c_str(); +} + +void SkinOption::setValueText(const TCHAR * value) +{ + if (valueText == value) + return; + + valueText = value; + fireOnChange(); +} + +void SkinOption::setOnChangeCallback(SkinOptionCallback cb, void *param /*= NULL*/) +{ + onChangeCallback = cb; + onChangeCallbackParam = param; +} + +void SkinOption::fireOnChange() +{ + if (onChangeCallback != NULL) + onChangeCallback(onChangeCallbackParam, this); +} + + + +SkinOptions::SkinOptions() + : onAddRemoveCallback(NULL), onAddRemoveCallbackParam(NULL), + onChangeCallback(NULL), onChangeCallbackParam(NULL) +{ +} + +SkinOptions::~SkinOptions() +{ + for(unsigned int i = 0; i < options.size(); i++) + delete options[i]; + options.clear(); +} + +bool SkinOptions::addOption(SkinOption *opt) +{ + _ASSERT(opt != NULL); + _ASSERT(opt->getName() != NULL); + + if (getOption(opt->getName()) != NULL) + return false; + + opt->setOnChangeCallback(onChangeCallback, onChangeCallbackParam); + options.push_back(opt); + + fireOnAddRemove(opt); + return true; +} + +SkinOption * SkinOptions::getOption(const char *name) const +{ + _ASSERT(name != NULL); + + for(unsigned int i = 0; i < options.size(); i++) + { + SkinOption *opt = options[i]; + if (strcmp(opt->getName(), name) == 0) + return opt; + } + return NULL; +} + +SkinOption * SkinOptions::getOption(unsigned int pos) const +{ + if (pos >= options.size()) + return NULL; + return options[pos]; +} + +unsigned int SkinOptions::getNumOptions() const +{ + return options.size(); +} + +void SkinOptions::clearOptions() +{ + if (options.size() <= 0) + return; + + for(unsigned int i = 0; i < options.size(); i++) + { + fireOnAddRemove(options[i]); + delete options[i]; + } + options.clear(); +} + +void SkinOptions::setOnOptionAddRemoveCallback(SkinOptionCallback cb, void *param /*= NULL*/) +{ + onAddRemoveCallback = cb; + onAddRemoveCallbackParam = param; +} + +void SkinOptions::setOnOptionChangeCallback(SkinOptionCallback cb, void *param /*= NULL*/) +{ + onChangeCallback = cb; + onChangeCallbackParam = param; + + for(unsigned int i = 0; i < options.size(); i++) + options[i]->setOnChangeCallback(cb, param); +} + +void SkinOptions::fireOnAddRemove(SkinOption *opt) +{ + if (onAddRemoveCallback != NULL) + onAddRemoveCallback(onAddRemoveCallbackParam, opt); +} diff --git a/plugins/Skins/SkinLib/SkinOptions.h b/plugins/Skins/SkinLib/SkinOptions.h new file mode 100644 index 0000000000..41d238a5a1 --- /dev/null +++ b/plugins/Skins/SkinLib/SkinOptions.h @@ -0,0 +1,98 @@ +#ifndef __SKINNED_DIALOG_OPTIONS_H__ +# define __SKINNED_DIALOG_OPTIONS_H__ + +#include +#include "tstring.h" +#include + + +enum SkinOptionType +{ + CHECKBOX, + NUMBER, + TEXT +}; + +class SkinOption; + +typedef void (*SkinOptionCallback)(void *param, const SkinOption *opt); + + +class SkinOption +{ +public: + SkinOption(const char *name); + ~SkinOption(); + + const char * getName() const; + + SkinOptionType getType() const; + void setType(SkinOptionType type); + + const TCHAR * getDescription() const; + void setDescription(const TCHAR * description); + + int getMax() const; + void setMax(int max); + + int getMin() const; + void setMin(int min); + + bool getValueCheckbox() const; + void setValueCheckbox(bool value); + + int getValueNumber() const; + void setValueNumber(int value); + + const TCHAR * getValueText() const; + void setValueText(const TCHAR * value); + + void setOnChangeCallback(SkinOptionCallback cb, void *param = NULL); + +private: + std::string name; + SkinOptionType type; + std::tstring description; + bool valueCheckbox; + int valueNumber; + int minValue; + int maxValue; + std::tstring valueText; + + SkinOptionCallback onChangeCallback; + void * onChangeCallbackParam; + + void fireOnChange(); +}; + + +class SkinOptions +{ +public: + SkinOptions(); + ~SkinOptions(); + + bool addOption(SkinOption *opt); + SkinOption * getOption(const char *name) const; + SkinOption * getOption(unsigned int pos) const; + unsigned int getNumOptions() const; + void clearOptions(); + + void setOnOptionAddRemoveCallback(SkinOptionCallback cb, void *param = NULL); + void setOnOptionChangeCallback(SkinOptionCallback cb, void *param = NULL); + +private: + std::vector options; + + SkinOptionCallback onAddRemoveCallback; + void * onAddRemoveCallbackParam; + + SkinOptionCallback onChangeCallback; + void * onChangeCallbackParam; + + void fireOnAddRemove(SkinOption *opt); +}; + + + +#endif // __SKINNED_DIALOG_OPTIONS_H__ diff --git a/plugins/Skins/SkinLib/SkinnedDialog.cpp b/plugins/Skins/SkinLib/SkinnedDialog.cpp new file mode 100644 index 0000000000..917193ad94 --- /dev/null +++ b/plugins/Skins/SkinLib/SkinnedDialog.cpp @@ -0,0 +1,235 @@ +#include "globals.h" +#include "SkinnedDialog.h" + +#include +#include "V8Script.h" +#include +#include "SkinOptions.h" + + +SkinnedDialog::SkinnedDialog(const char *name) + : Dialog(name), fileChangedTime(0), + script(NULL), state(NULL), opts(NULL), defaultState(NULL), + errorCallback(NULL), errorCallbackParam(NULL), + traceCallback(NULL), traceCallbackParam(NULL) +{ + V8Script::initializeEngine(); +} + +SkinnedDialog::~SkinnedDialog() +{ + releaseState(); + releaseCompiledScript(); +} + +const TCHAR * SkinnedDialog::getFilename() const +{ + return filename.c_str(); +} + +void SkinnedDialog::setFilename(const TCHAR *filename) +{ + if (this->filename == filename) + return; + + this->filename = filename; + releaseState(); + releaseCompiledScript(); +} + +bool SkinnedDialog::addField(Field *field) +{ + if (Dialog::addField(field)) + { + releaseCompiledScript(); + releaseState(); + field->setOnChangeCallback(SkinnedDialog::staticOnFieldChange, this); + return true; + } + else + return false; +} + +void SkinnedDialog::setSize(const Size &size) +{ + if (getSize() == size) + return; + + Dialog::setSize(size); + releaseState(); +} + +int SkinnedDialog::compile() +{ + if (!fileChanged()) + return 1; + + releaseCompiledScript(); + + struct _stat st = {0}; + if (_tstat(filename.c_str(), &st) != 0) + return 0; + + std::tstring text; + readFile(text); + if (text.size() <= 0) + return 0; + + script = new V8Script(); + script->setExceptionCallback(errorCallback, errorCallbackParam); + + if (!script->compile(text.c_str(), this)) + { + releaseCompiledScript(); + return 0; + } + + std::pair pair = script->configure(this); + opts = pair.first; + defaultState = pair.second; + if (opts == NULL) + { + releaseCompiledScript(); + return 0; + } + + fileChangedTime = st.st_mtime; + + return 2; +} + +DialogState * SkinnedDialog::getState() +{ + if (state != NULL && !fileChanged()) + return state; + + releaseState(); + + if (filename.size() <= 0) + return NULL; + + if (!compile()) + return NULL; + + state = Dialog::createState(); + if (!script->run(state, opts, getInfo())) + { + releaseState(); + return NULL; + } + + return state; +} + +void SkinnedDialog::releaseCompiledScript() +{ + delete script; + script = NULL; + fileChangedTime = 0; + + delete opts; + opts = NULL; + + delete defaultState; + defaultState = NULL; +} + +void SkinnedDialog::releaseState() +{ + delete state; + state = NULL; +} + +bool SkinnedDialog::fileChanged() +{ + if (filename.size() <= 0) + return false; + + struct _stat st = {0}; + if (_tstat(filename.c_str(), &st) != 0) + return false; + + return st.st_mtime > fileChangedTime; +} + +void SkinnedDialog::readFile(std::tstring &ret) +{ + FILE* file = _tfopen(filename.c_str(), _T("rb")); + if (file == NULL) + return; + + fseek(file, 0, SEEK_END); + int size = ftell(file); + rewind(file); + + char* chars = new char[size + 1]; + chars[size] = '\0'; + for (int i = 0; i < size;) + { + int read = fread(&chars[i], 1, size - i, file); + i += read; + } + fclose(file); + + ret = Utf8ToTchar(chars); + + delete[] chars; +} + +void SkinnedDialog::onFieldChange(const Field *field) +{ + releaseState(); +} + + +void SkinnedDialog::staticOnFieldChange(void *param, const Field *field) +{ + _ASSERT(param != NULL); + _ASSERT(field != NULL); + + SkinnedDialog *skdlg = (SkinnedDialog *) param; + skdlg->onFieldChange(field); +} + +void SkinnedDialog::setErrorCallback(MessageCallback cb, void *param /*= NULL*/) +{ + errorCallback = cb; + errorCallbackParam = param; +} + +void SkinnedDialog::setTraceCallback(MessageCallback cb, void *param /*= NULL*/) +{ + traceCallback = cb; + traceCallbackParam = param; +} + +void SkinnedDialog::trace(TCHAR *msg, ...) +{ + if (traceCallback == NULL) + return; + + TCHAR buff[1024]; + memset(buff, 0, sizeof(buff)); + + va_list args; + va_start(args, msg); + + _vsntprintf(buff, MAX_REGS(buff) - 1, msg, args); + buff[MAX_REGS(buff) - 1] = 0; + + va_end(args); + + traceCallback(traceCallbackParam, buff); +} + +SkinOptions * SkinnedDialog::getOpts() +{ + compile(); + return opts; +} + +DialogState * SkinnedDialog::getDefaultState() +{ + compile(); + return defaultState; +} \ No newline at end of file diff --git a/plugins/Skins/SkinLib/SkinnedDialog.h b/plugins/Skins/SkinLib/SkinnedDialog.h new file mode 100644 index 0000000000..1387082f44 --- /dev/null +++ b/plugins/Skins/SkinLib/SkinnedDialog.h @@ -0,0 +1,89 @@ +#ifndef __SKINNED_DIALOG_H__ +# define __SKINNED_DIALOG_H__ + +#include +#include +#include "tstring.h" + +#include "Dialog.h" +#include "ButtonField.h" +#include "EditField.h" +#include "IconField.h" +#include "ImageField.h" +#include "LabelField.h" +#include "TextField.h" + +#include "DialogState.h" +#include "BorderState.h" +#include "ButtonFieldState.h" +#include "EditFieldState.h" +#include "FontState.h" +#include "IconFieldState.h" +#include "ImageFieldState.h" +#include "LabelFieldState.h" +#include "TextFieldState.h" + +#include "SkinOptions.h" + +class V8Script; + + +typedef void (*MessageCallback)(void *param, const TCHAR *err); + + + +class SkinnedDialog : public Dialog +{ +public: + SkinnedDialog(const char *name); + virtual ~SkinnedDialog(); + + virtual const TCHAR * getFilename() const; + virtual void setFilename(const TCHAR *filename); + + virtual bool addField(Field *field); + + virtual void setSize(const Size &size); + + /// Return the cached state. Do not free the result. + /// Each call to this method can potentially create the state, so don't cache it. + virtual DialogState * getState(); + + virtual void setErrorCallback(MessageCallback cb, void *param = NULL); + virtual void setTraceCallback(MessageCallback cb, void *param = NULL); + + virtual SkinOptions * getOpts(); + virtual DialogState * getDefaultState(); + +protected: + virtual bool fileChanged(); + virtual int compile(); /// @return 0 error, 1 no change, 2 compiled + + virtual void trace(TCHAR *msg, ...); + + virtual void onFieldChange(const Field *field); + +private: + std::tstring filename; + __time64_t fileChangedTime; + V8Script *script; + DialogState *state; + SkinOptions *opts; + DialogState *defaultState; + + MessageCallback errorCallback; + void *errorCallbackParam; + MessageCallback traceCallback; + void *traceCallbackParam; + + void releaseCompiledScript(); + void releaseState(); + void readFile(std::tstring &ret); + + static void staticOnFieldChange(void *param, const Field *field); +}; + + + + +#endif // __SKINNED_DIALOG_H__ diff --git a/plugins/Skins/SkinLib/TextField.cpp b/plugins/Skins/SkinLib/TextField.cpp new file mode 100644 index 0000000000..d3841b98fd --- /dev/null +++ b/plugins/Skins/SkinLib/TextField.cpp @@ -0,0 +1,78 @@ +#include "globals.h" +#include "TextField.h" +#include "TextFieldState.h" + + +TextField::TextField(Dialog *dlg, const char *name) + : Field(dlg, name), hFont(NULL), fontColor(RGB(0,0,0)) +{ +} + + +TextField::~TextField() +{ +} + + +FieldType TextField::getType() const +{ + return SIMPLE_TEXT; +} + + +void TextField::setText(const TCHAR *text) +{ + if (this->text == text) + return; + + this->text = text; + fireOnChange(); +} + + +const TCHAR * TextField::getText() const +{ + return text.c_str(); +} + + +void TextField::setFont(HFONT hFont) +{ + if (this->hFont == hFont) + return; + + this->hFont = hFont; + fireOnChange(); +} + + +HFONT TextField::getFont() const +{ + if (hFont != NULL) + return hFont; + + // The default is the GUI font + return (HFONT) GetStockObject(DEFAULT_GUI_FONT); +} + + +COLORREF TextField::getFontColor() const +{ + return fontColor; +} + + +void TextField::setFontColor(COLORREF color) +{ + if (fontColor == color) + return; + + fontColor = color; + fireOnChange(); +} + + +FieldState * TextField::createState(DialogState *dialogState) +{ + return new TextFieldState(dialogState, this); +} diff --git a/plugins/Skins/SkinLib/TextField.h b/plugins/Skins/SkinLib/TextField.h new file mode 100644 index 0000000000..8d2291f876 --- /dev/null +++ b/plugins/Skins/SkinLib/TextField.h @@ -0,0 +1,35 @@ +#ifndef __TEXT_FIELD_H__ +# define __TEXT_FIELD_H__ + +#include "Field.h" + + +class TextField : public Field +{ +public: + TextField(Dialog *dlg, const char *name); + virtual ~TextField(); + + virtual FieldType getType() const; + + virtual const TCHAR * getText() const; + virtual void setText(const TCHAR *text); + + virtual HFONT getFont() const; + virtual void setFont(HFONT hFont); + + virtual COLORREF getFontColor() const; + virtual void setFontColor(COLORREF color); + + virtual FieldState * createState(DialogState *dialogState); + +private: + std::tstring text; + HFONT hFont; + COLORREF fontColor; + +}; + + + +#endif // __TEXT_FIELD_H__ diff --git a/plugins/Skins/SkinLib/TextFieldState.cpp b/plugins/Skins/SkinLib/TextFieldState.cpp new file mode 100644 index 0000000000..8e295d01ee --- /dev/null +++ b/plugins/Skins/SkinLib/TextFieldState.cpp @@ -0,0 +1,65 @@ +#include "globals.h" +#include "TextFieldState.h" + + +TextFieldState::TextFieldState(DialogState *dialog, TextField *field) + : FieldState(dialog, field), font(field->getFont(), field->getFontColor()), textSet(false) +{ +} + +TextFieldState::~TextFieldState() +{ +} + +TextField * TextFieldState::getField() const +{ + return (TextField *) FieldState::getField(); +} + + +Size TextFieldState::getPreferedSize() const +{ + HDC hdc = CreateCompatibleDC(NULL); + + HFONT newFont = getFont()->getHFONT(); + HFONT oldFont = (HFONT) SelectObject(hdc, newFont); + + RECT rc = {0}; + const TCHAR *text = getText(); + DrawText(hdc, text, -1, &rc, DT_CALCRECT | DT_NOPREFIX | DT_EXPANDTABS | DT_SINGLELINE); + + SelectObject(hdc, oldFont); + + DeleteDC(hdc); + + return Size(rc.right - rc.left, rc.bottom - rc.top); +} + +const TCHAR * TextFieldState::getText() const +{ + if (textSet) + return text.c_str(); + + return getField()->getText(); +} + +void TextFieldState::setText(const TCHAR *text) +{ + this->text = text; + textSet = true; +} + +FontState * TextFieldState::getFont() +{ + return &font; +} + +const FontState * TextFieldState::getFont() const +{ + return &font; +} + +bool TextFieldState::isEmpty() const +{ + return lstrlen(getText()) <= 0; +} diff --git a/plugins/Skins/SkinLib/TextFieldState.h b/plugins/Skins/SkinLib/TextFieldState.h new file mode 100644 index 0000000000..9779cfa569 --- /dev/null +++ b/plugins/Skins/SkinLib/TextFieldState.h @@ -0,0 +1,38 @@ +#ifndef __TEXT_FIELD_STATE_H__ +# define __TEXT_FIELD_STATE_H__ + +#include "TextField.h" +#include "FieldState.h" +#include "FontState.h" + + +class TextFieldState : public FieldState +{ +public: + virtual ~TextFieldState(); + + virtual TextField * getField() const; + + virtual Size getPreferedSize() const; + + virtual const TCHAR * getText() const; + virtual void setText(const TCHAR *text); + + virtual FontState * getFont(); + virtual const FontState * getFont() const; + + virtual bool isEmpty() const; + +private: + TextFieldState(DialogState *dialog, TextField *field); + + FontState font; + BOOL textSet; + std::tstring text; + + + friend class TextField; +}; + + +#endif // __TEXT_FIELD_STATE_H__ \ No newline at end of file diff --git a/plugins/Skins/SkinLib/TextFieldState_v8_wrapper.cpp b/plugins/Skins/SkinLib/TextFieldState_v8_wrapper.cpp new file mode 100644 index 0000000000..cf11fdb01f --- /dev/null +++ b/plugins/Skins/SkinLib/TextFieldState_v8_wrapper.cpp @@ -0,0 +1,59 @@ +#include "globals.h" +#include "TextFieldState_v8_wrapper.h" +#include +#include "TextFieldState.h" +#include + +using namespace v8; + + +#ifdef UNICODE +# define V8_TCHAR uint16_t +#else +# define V8_TCHAR char +#endif + + +static Handle Get_TextFieldState_text(Local property, const AccessorInfo &info) +{ + HandleScope scope; + + Local self = info.Holder(); + Local wrap = Local::Cast(self->GetInternalField(0)); + if (wrap.IsEmpty()) + return scope.Close( Undefined() ); + + TextFieldState *tmp = (TextFieldState *) wrap->Value(); + if (tmp == NULL) + return scope.Close( Undefined() ); + + return scope.Close( String::New((const V8_TCHAR *) tmp->getText()) ); +} + +static void Set_TextFieldState_text(Local property, Local value, const AccessorInfo& info) +{ + HandleScope scope; + + Local self = info.Holder(); + Local wrap = Local::Cast(self->GetInternalField(0)); + if (wrap.IsEmpty()) + return; + + TextFieldState *tmp = (TextFieldState *) wrap->Value(); + if (tmp == NULL) + return; + + if (!value.IsEmpty() && value->IsString()) + { + String::Utf8Value utf8_value(value); + tmp->setText(Utf8ToTchar(*utf8_value)); + } +} + + +void AddTextFieldStateAcessors(Handle &templ) +{ + HandleScope scope; + + templ->SetAccessor(String::New("text"), Get_TextFieldState_text, Set_TextFieldState_text); +} diff --git a/plugins/Skins/SkinLib/TextFieldState_v8_wrapper.h b/plugins/Skins/SkinLib/TextFieldState_v8_wrapper.h new file mode 100644 index 0000000000..c5d9e48a80 --- /dev/null +++ b/plugins/Skins/SkinLib/TextFieldState_v8_wrapper.h @@ -0,0 +1,10 @@ +#ifndef __TEXT_FIELD_STATE_V8_WRAPPER_H__ +# define __TEXT_FIELD_STATE_V8_WRAPPER_H__ + +#include + +void AddTextFieldStateAcessors(v8::Handle &templ); + + + +#endif // __TEXT_FIELD_STATE_V8_WRAPPER_H__ diff --git a/plugins/Skins/SkinLib/V8Script.cpp b/plugins/Skins/SkinLib/V8Script.cpp new file mode 100644 index 0000000000..c7619187a5 --- /dev/null +++ b/plugins/Skins/SkinLib/V8Script.cpp @@ -0,0 +1,236 @@ +#include "globals.h" +#include "V8Script.h" +#include "V8Wrappers.h" + +#include + +using namespace v8; + +#ifdef UNICODE +# define V8_TCHAR uint16_t +#else +# define V8_TCHAR char +#endif + + +V8Wrappers *wrappers = NULL; + + +void V8Script::initializeEngine() +{ + if (wrappers != NULL) + return; + + wrappers = new V8Wrappers(); +} + + +V8Script::V8Script() : exceptionCallback(NULL), exceptionCallbackParam(NULL) +{ +} + +V8Script::~V8Script() +{ + dispose(); +} + +bool V8Script::compile(const TCHAR *source, Dialog *dlg) +{ + dispose(); + + HandleScope handle_scope; + + context = Context::New(NULL, wrappers->getGlobalTemplate()); + + Context::Scope context_scope(context); + + context->Global()->Set(String::New("window"), wrappers->newDialogState(), ReadOnly); + context->Global()->Set(String::New("opts"), wrappers->newOptions(), ReadOnly); + context->Global()->Set(String::New("info"), wrappers->newDialogInfo(), ReadOnly); + for(unsigned int i = 0; i < dlg->getFieldCount(); i++) + { + Field *field = dlg->getField(i); + context->Global()->Set(String::New(field->getName()), wrappers->newState(field->getType()), ReadOnly); + } + + TryCatch try_catch; + Local