diff options
-rw-r--r-- | tipper/common.h | 82 | ||||
-rw-r--r-- | tipper/docs/autoexec_Tipper(Omniwolf).ini | 339 | ||||
-rw-r--r-- | tipper/docs/autoexec_Tipper(Tweety).ini | 377 | ||||
-rw-r--r-- | tipper/docs/licence_Tipper.txt | 6 | ||||
-rw-r--r-- | tipper/docs/m_tipper.h | 23 | ||||
-rw-r--r-- | tipper/docs/readme_tipper.txt | 143 | ||||
-rw-r--r-- | tipper/m_tipper.h | 19 | ||||
-rw-r--r-- | tipper/message_pump.cpp | 201 | ||||
-rw-r--r-- | tipper/message_pump.h | 41 | ||||
-rw-r--r-- | tipper/options.cpp | 1126 | ||||
-rw-r--r-- | tipper/options.h | 74 | ||||
-rw-r--r-- | tipper/popwin.cpp | 837 | ||||
-rw-r--r-- | tipper/popwin.h | 17 | ||||
-rw-r--r-- | tipper/resource.h | 85 | ||||
-rw-r--r-- | tipper/resource.rc | 6 | ||||
-rw-r--r-- | tipper/subst.cpp | 468 | ||||
-rw-r--r-- | tipper/subst.h | 14 | ||||
-rw-r--r-- | tipper/tipper.cpp | 295 | ||||
-rw-r--r-- | tipper/tipper.h | 12 | ||||
-rw-r--r-- | tipper/tipper.mdsp | 107 | ||||
-rw-r--r-- | tipper/tipper.rc | 239 | ||||
-rw-r--r-- | tipper/tipper.sln | 20 | ||||
-rw-r--r-- | tipper/tipper.vcproj | 376 | ||||
-rw-r--r-- | tipper/translations.cpp | 654 | ||||
-rw-r--r-- | tipper/translations.h | 14 | ||||
-rw-r--r-- | tipper/version.h | 23 | ||||
-rw-r--r-- | tipper/version.rc | 33 |
27 files changed, 5631 insertions, 0 deletions
diff --git a/tipper/common.h b/tipper/common.h new file mode 100644 index 0000000..9b9e0e4 --- /dev/null +++ b/tipper/common.h @@ -0,0 +1,82 @@ +// stdafx.h : include file for standard system include files,
+// or project specific include files that are used frequently, but
+// are changed infrequently
+//
+
+#pragma once
+
+// Modify the following defines if you have to target a platform prior to the ones specified below.
+// Refer to MSDN for the latest info on corresponding values for different platforms.
+#ifndef WINVER // Allow use of features specific to Windows XP or later.
+#define WINVER 0x0501 // Change this to the appropriate value to target other versions of Windows.
+#endif
+
+#ifndef _WIN32_WINNT // Allow use of features specific to Windows XP or later.
+#define _WIN32_WINNT 0x0501 // Change this to the appropriate value to target other versions of Windows.
+#endif
+
+#ifndef _WIN32_WINDOWS // Allow use of features specific to Windows 98 or later.
+#define _WIN32_WINDOWS 0x0410 // Change this to the appropriate value to target Windows Me or later.
+#endif
+
+#ifndef _WIN32_IE // Allow use of features specific to IE 6.0 or later.
+#define _WIN32_IE 0x0600 // Change this to the appropriate value to target other versions of IE.
+#endif
+
+#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
+// Windows Header Files:
+#include <windows.h>
+#include <process.h>
+#include <commctrl.h>
+#include <malloc.h>
+#include <stdlib.h>
+
+#define MIRANDA_VER 0x0600 // for tabbed options
+
+#include <newpluginapi.h>
+#include <statusmodes.h>
+#include <m_database.h>
+#include <m_langpack.h>
+#include <m_options.h>
+#include <m_system.h>
+#include <m_idle.h>
+#include <m_skin.h>
+#include <m_clui.h>
+#include <m_clist.h>
+#include <m_clc.h>
+#include <m_cluiframes.h>
+#include <m_awaymsg.h>
+#include <stdio.h>
+#include <m_utils.h>
+#include <m_protocols.h>
+#include <m_protosvc.h>
+#include <m_protomod.h>
+#include <m_contacts.h>
+
+#include <m_popup.h>
+
+#include <m_updater.h>
+#include <m_fontservicew.h>
+#include <m_avatars.h>
+#include <m_variables.h>
+
+#include <m_notify.h>
+
+#include <m_smr.h>
+
+#include <m_metacontacts.h>
+
+#include <m_icq.h>
+
+#define MODULE "Tipper"
+
+extern HMODULE hInst;
+extern PLUGINLINK *pluginLink;
+extern HANDLE mainThread;
+
+extern HFONT hFontTitle, hFontLabels, hFontValues;
+extern COLORREF colTitle, colLabels, colBg, colValues;
+
+extern int code_page;
+
+extern struct MM_INTERFACE memoryManagerInterface;
diff --git a/tipper/docs/autoexec_Tipper(Omniwolf).ini b/tipper/docs/autoexec_Tipper(Omniwolf).ini new file mode 100644 index 0000000..b68bdc8 --- /dev/null +++ b/tipper/docs/autoexec_Tipper(Omniwolf).ini @@ -0,0 +1,339 @@ +SETTINGS:
+
+[Tipper]
+WinWidth=d400
+WinMaxHeight=d400
+Transparency=b19
+Border=b0
+RoundCorners=b1
+Animate=b0
+TransparentBg=b0
+RightIcon=b0
+AVLayout=b2
+AVSize=d86
+TextIndent=d22
+ShowNoFocus=b1
+DSNumValues=w19
+DINumValues=w22
+ShowStatusMsg=b1
+Type0=b1
+TransFunc0=w7
+DIValue0=u%Status%
+DILineAbove0=b0
+DIValNewline0=b0
+Type1=b1
+TransFunc1=w7
+DILineAbove1=b0
+DIValNewline1=b0
+Type2=b1
+TransFunc2=w2
+DILineAbove2=b0
+DIValNewline2=b0
+Type3=b1
+TransFunc3=w3
+Type4=b1
+TransFunc4=w1
+DILineAbove3=b0
+DIValNewline3=b0
+Type5=b1
+TransFunc5=w1
+DILineAbove4=b1
+DIValNewline4=b0
+Type6=b1
+TransFunc6=w1
+DILineAbove5=b0
+DIValNewline5=b0
+DILabel0=uStatus:
+Type7=b1
+TransFunc7=w1
+DILineAbove6=b0
+DIValNewline6=b0
+Name8=umetaS0
+Type8=b1
+TransFunc8=w1
+Name9=umetaS1
+Type9=b1
+TransFunc9=w1
+Name10=umetaS2
+Type10=b1
+TransFunc10=w1
+Name11=umetaS3
+Type11=b1
+TransFunc11=w1
+Name12=umetaS4
+Type12=b1
+TransFunc12=w1
+Name13=umetaS5
+Type13=b1
+TransFunc13=w1
+Type14=b1
+TransFunc14=w1
+Type15=b1
+TransFunc15=w1
+Type16=b1
+TransFunc16=w1
+DILineAbove7=b0
+DIValNewline7=b0
+DILineAbove8=b1
+DIValNewline8=b0
+DILineAbove9=b1
+DIValNewline9=b0
+DILineAbove10=b1
+DIValNewline10=b1
+Name14=umetaS6
+Name16=umetaS8
+Type17=b1
+TransFunc17=w1
+Name15=umetaS7
+Name17=umetaS9
+Type18=b1
+TransFunc18=w1
+Type19=b1
+TransFunc19=w0
+Type20=b1
+TransFunc20=w0
+FontFirstSize=b241
+FontFirstSty=b1
+FontFirstSet=b0
+FontFirstCol=d255
+FontLabelsSize=b243
+FontLabelsSty=b0
+FontLabelsSet=b0
+FontLabelsCol=d4210752
+FontValuesSize=b243
+FontValuesSty=b0
+FontValuesSet=b0
+FontValuesCol=d0
+ColourBg=d14476004
+Name0=uicqIP
+Name18=uStatus
+Type21=b1
+TransFunc21=w1
+DILineAbove11=b1
+DIValNewline11=b1
+Name1=uicqIPreal
+Name19=uMirVer
+Name20=usametimeID
+Name21=uStatus
+Name22=uUIN
+Type22=b1
+TransFunc22=w0
+DILineAbove12=b1
+DIValNewline12=b0
+RightLabels=b0
+TimeIn=w500
+DILineAbove17=b0
+DIValNewline17=b0
+DILineAbove18=b0
+DIValNewline18=b0
+DILineAbove19=b0
+DIValNewline19=b0
+DILineAbove20=b0
+DIValNewline20=b0
+DILineAbove21=b0
+DIValNewline21=b0
+DILineAbove13=b0
+DIValNewline13=b0
+DILineAbove14=b0
+DIValNewline14=b0
+DILineAbove15=b0
+DIValNewline15=b0
+DILineAbove16=b0
+DIValNewline16=b0
+DILineAbove22=b1
+DIValNewline22=b0
+Module0=s
+Setting0=sIP
+Module1=s
+Setting1=sRealIP
+Module2=s
+Setting2=sIdleTS
+Module3=s
+Setting3=sIdleTS
+Module4=s
+Module5=s
+Module6=s
+Module7=s
+Module8=s
+Module9=s
+Module10=s
+Module11=s
+Module12=s
+Module13=s
+Module14=s
+Module15=s
+Module16=s
+Setting16=sStatus8
+Module17=s
+Setting17=sStatus9
+Module18=s
+Module19=s
+Setting19=sMirVer
+Module20=s
+Setting20=sstid
+Module21=s
+Setting21=sStatus
+Module22=s
+Setting22=sUIN
+BorderCol=d0
+Name3=uIdleTS-diff
+Setting7=sLogonTS
+Setting8=sStatus0
+Setting9=sStatus1
+Setting10=sStatus2
+Setting11=sStatus3
+Setting12=sStatus4
+Setting13=sStatus5
+DILineAbove23=b0
+DIValNewline23=b0
+DILineAbove24=b0
+DIValNewline24=b0
+DILineAbove25=b0
+DIValNewline25=b0
+DILineAbove26=b0
+DIValNewline26=b0
+DILineAbove27=b0
+DIValNewline27=b0
+DILineAbove28=b0
+DIValNewline28=b0
+TitleLayout=b0
+Padding=w4
+Position=b1
+MinWidth=d0
+MinHeight=d0
+WORD to status description=d1
+NextFuncId=d17
+DWORD timestamp to time=d2
+DWORD timestamp to time difference=d3
+BYTE to Yes/No=d4
+BYTE to Male/Female (ICQ)=d5
+WORD to country name=d6
+DWORD to ip address=d7
+<prefix>Day|Month|Year to date=d8
+<prefix>Day|Month|Year to age=d9
+<prefix>Hours|Minutes|Seconds to time=d10
+<prefix>Day|Month|Year|Hours|Minutes|Seconds to time difference=d11
+DWORD timestamp to time (no seconds)=d12
+<prefix>Hours|Minutes to time=d13
+DWORD timestamp to date (short)=d14
+DWORD timestamp to date (long)=d15
+MaxWidth=d350
+MaxHeight=d400
+Opacity=b85
+TransFuncId0=d7
+TransFuncId1=d7
+TransFuncId2=d14
+TransFuncId3=d3
+TransFuncId4=d12
+TransFuncId5=d14
+TransFuncId6=d3
+TransFuncId7=d12
+TransFuncId8=d1
+TransFuncId9=d1
+TransFuncId10=d1
+TransFuncId11=d1
+TransFuncId12=d1
+TransFuncId13=d1
+TransFuncId14=d1
+MouseTollerance=b16
+DropShadow=b1
+DILineAbove29=b0
+DIValNewline29=b0
+RightValues=b0
+SBarTips=b1
+xStatus: empty xStatus name to default name=d16
+DILineAbove30=b0
+DIValNewline30=b0
+DividerCol=d8421440
+SidebarCol=d9741995
+AvatarRoundCorners=b0
+AvatarPadding=w7
+TextPadding=w4
+SidebarWidth=d22
+Name2=uIdleTS-date
+Name4=uIdleTS-time
+Setting4=sIdleTS
+Setting14=sStatus6
+TransFuncId15=d1
+Name5=uLogonTS-date
+Name6=uLogonTS-diff
+Name7=uLogonTS-time
+Setting15=sStatus7
+TransFuncId16=d1
+TransFuncId17=d1
+Setting18=sStatus
+TransFuncId18=d1
+Setting5=sLogonTS
+Setting6=sLogonTS
+FontValues=uTahoma
+FontLabels=uTahoma
+FontFirst=uTahoma
+DILabel26=uHigh/Low:
+DILabel27=uPressure:
+DILabel1=uName:
+DIValue1=u%raw:/FirstName|% %raw:/LastName%
+DIValue3=u%raw:/MirVer%
+DILabel6=uExternal IP:
+DILabel23=uVisibility:
+DILabel28=uHumidity:
+DILabel7=uInternal IP:
+DILabel8=uActive subcontact:
+DIValue8=u%sys:meta_subproto% - %sys:meta_subname%
+DILabel22=uObservation time:
+DIValue22=u%raw:Current/Update%
+DIValue23=u%raw:Current/Visibility%
+DILabel24=uFeels like:
+DIValue24=u%raw:Current/Feel%
+DILabel25=uWind:
+DIValue25=u%raw:Current/Wind Direction% (%raw:Current/Wind Direction DEG%)/%raw:Current/Wind Speed%
+DIValue26=u%raw:Current/High%/%raw:Current/Low%
+DIValue27=u%raw:Current/Pressure% (%raw:Current/Pressure Tendency%)
+DIValue28=u%raw:Current/Humidity%
+DILabel29=uUV Index:
+DIValue29=u%raw:Current/UV% - %raw:Current/UVI%
+DILabel30=uSunrise/Sunset:
+DIValue30=u%raw:Current/Sunrise%/%raw:Current/Sunset%
+DILabel31=uMoonphase
+DIValue31=u%raw:Current/Moon%
+DILineAbove31=b0
+DIValNewline31=b0
+DIValue6=u%icqIP%
+DIValue7=u%icqIPreal%
+DILabel2=u%sys:uidname^!MetaContacts%:
+DIValue2=u%sys:uid%
+DILabel3=uClient:
+DILabel4=uLogged on:
+DIValue4=u%LogonTS-diff%
+DILabel5=uIdle:
+DIValue5=u%IdleTS-diff%
+FontFirstFlags=d288
+FontLabelsFlags=d288
+FontValuesFlags=d288
+DILabel9=uListening To:
+DIValue9=u%raw:/ListeningTo%
+DILabel10=uLast message: (%sys:last_msg_reltime% ago)
+DIValue10=u%sys:last_msg%
+DILabel11=uStatus Message:
+DIValue11=u%sys:status_msg%
+DILabel12=uObservation time:
+DIValue12=u%raw:Current/Update%
+DILabel13=uVisibility:
+DIValue13=u%raw:Current/Visibility%
+DILabel14=uFeels like:
+DIValue14=u%raw:Current/Feel%
+DILabel15=uWind:
+DIValue15=u%raw:Current/Wind Direction% (%raw:Current/Wind Direction DEG%)/%raw:Current/Wind Speed%
+DILabel16=uHigh/Low:
+DIValue16=u%raw:Current/High%/%raw:Current/Low%
+DILabel17=uPressure:
+DIValue17=u%raw:Current/Pressure% (%raw:Current/Pressure Tendency%)
+DILabel18=uHumidity:
+DIValue18=u%raw:Current/Humidity%
+DILabel19=uUV Index:
+DIValue19=u%raw:Current/UV% - %raw:Current/UVI%
+DILabel20=uSunrise/Sunset:
+DIValue20=u%raw:Current/Sunrise%/%raw:Current/Sunset%
+DILabel21=uMoonphase
+DIValue21=u%raw:Current/Moon%
+
+
diff --git a/tipper/docs/autoexec_Tipper(Tweety).ini b/tipper/docs/autoexec_Tipper(Tweety).ini new file mode 100644 index 0000000..9f555f5 --- /dev/null +++ b/tipper/docs/autoexec_Tipper(Tweety).ini @@ -0,0 +1,377 @@ +SETTINGS:
+
+[Tipper]
+WORD to status description=d1
+NextFuncId=d17
+DWORD timestamp to time=d2
+DWORD timestamp to time difference=d3
+BYTE to Yes/No=d4
+BYTE to Male/Female (ICQ)=d5
+WORD to country name=d6
+DWORD to ip address=d7
+<prefix>Day|Month|Year to date=d8
+<prefix>Day|Month|Year to age=d9
+<prefix>Hours|Minutes|Seconds to time=d10
+<prefix>Day|Month|Year|Hours|Minutes|Seconds to time difference=d11
+DWORD timestamp to time (no seconds)=d12
+<prefix>Hours|Minutes to time=d13
+DWORD timestamp to date (short)=d14
+DWORD timestamp to date (long)=d15
+WinWidth=d400
+WinMaxHeight=d400
+Transparency=b19
+Border=b0
+RoundCorners=b1
+Animate=b1
+TransparentBg=b0
+RightIcon=b0
+AVLayout=b2
+AVSize=d80
+TextIndent=d23
+ShowNoFocus=b1
+NumValues=w3
+FontFirstSize=b247
+FontFirstSty=b1
+FontFirstSet=b0
+FontFirstCol=d6572572
+FontLabelsSize=b247
+FontLabelsSty=b1
+FontLabelsSet=b0
+FontLabelsCol=d6572572
+FontValuesSize=b247
+FontValuesSty=b0
+FontValuesSet=b0
+FontValuesCol=d6049571
+ColourBg=d15987699
+Label0=uEtat
+Type0=b0
+TransFunc0=w7
+Label1=uMessage d'état
+Type1=b1
+TransFunc1=w7
+Label2=uDernier Message
+Type2=b1
+TransFunc2=w2
+ShowStatusMsg=b1
+DSNumValues=w21
+DILineAbove0=b0
+DIValNewline0=b0
+DINumValues=w38
+DILineAbove1=b0
+DIValNewline1=b0
+DILineAbove2=b0
+DIValNewline2=b0
+DILineAbove3=b0
+DIValNewline3=b0
+DILineAbove4=b0
+DIValNewline4=b0
+Type3=b1
+TransFunc3=w3
+Type4=b1
+TransFunc4=w1
+Type5=b1
+TransFunc5=w1
+Type6=b0
+TransFunc6=w1
+DILineAbove5=b0
+DIValNewline5=b0
+Type7=b1
+TransFunc7=w1
+DILineAbove6=b0
+DIValNewline6=b0
+Type8=b1
+TransFunc8=w1
+Type9=b1
+TransFunc9=w1
+Name10=umetaS0
+Type10=b1
+TransFunc10=w1
+Name11=umetaS1
+Type11=b1
+TransFunc11=w1
+Name12=umetaS2
+Type12=b1
+TransFunc12=w1
+Name13=umetaS3
+Type13=b1
+TransFunc13=w1
+Type14=b1
+TransFunc14=w1
+Type15=b1
+TransFunc15=w1
+Type16=b1
+TransFunc16=w1
+DILineAbove7=b0
+DIValNewline7=b0
+DILineAbove8=b1
+DIValNewline8=b0
+DILineAbove9=b0
+DIValNewline9=b0
+DILineAbove10=b0
+DIValNewline10=b0
+Name14=umetaS4
+Name16=umetaS6
+Type17=b1
+TransFunc17=w1
+Name15=umetaS5
+Name17=umetaS7
+Type18=b1
+TransFunc18=w1
+Type19=b1
+TransFunc19=w0
+Type20=b1
+TransFunc20=w0
+Name18=umetaS8
+Type21=b1
+TransFunc21=w1
+DILineAbove11=b0
+DIValNewline11=b0
+Name19=umetaS9
+Name21=uStatus
+Name22=uUIN
+Type22=b1
+TransFunc22=w0
+DILineAbove12=b0
+DIValNewline12=b0
+RightLabels=b0
+TimeIn=w300
+DILineAbove17=b0
+DIValNewline17=b0
+DILineAbove18=b0
+DIValNewline18=b0
+DILineAbove19=b0
+DIValNewline19=b0
+DILineAbove20=b0
+DIValNewline20=b0
+DILineAbove21=b0
+DIValNewline21=b0
+DILineAbove13=b1
+DIValNewline13=b1
+DILineAbove14=b0
+DIValNewline14=b1
+DILineAbove15=b1
+DIValNewline15=b0
+DILineAbove16=b0
+DIValNewline16=b0
+DILineAbove22=b0
+DIValNewline22=b0
+Module1=s
+Module2=s
+Setting2=sRealIP
+Module3=s
+Setting3=sIdleTS
+Module7=s
+Module8=s
+Module9=s
+Module10=s
+Module11=s
+Module12=s
+Module13=s
+Module14=s
+Module15=s
+Module16=s
+Module17=s
+Module18=s
+Module19=s
+Module20=s
+Module21=s
+Setting21=sStatus
+Module22=s
+Setting22=sUIN
+BorderCol=d6567708
+Setting7=sLogonTS
+Setting8=sLogonTS
+Setting9=sLogonTS
+Setting10=sStatus0
+Setting11=sStatus1
+Setting12=sStatus2
+Setting13=sStatus3
+DILineAbove23=b0
+DIValNewline23=b0
+DILineAbove24=b0
+DIValNewline24=b0
+DILineAbove25=b1
+DIValNewline25=b1
+DILineAbove26=b1
+DIValNewline26=b1
+DILineAbove27=b1
+DIValNewline27=b1
+DILineAbove28=b1
+DIValNewline28=b0
+Setting14=sStatus4
+DILineAbove29=b0
+DIValNewline29=b0
+DILineAbove30=b0
+DIValNewline30=b0
+DILineAbove31=b0
+DIValNewline31=b0
+TitleLayout=b0
+Padding=w3
+Position=b1
+MinWidth=d300
+MinHeight=d0
+TransFuncId0=d5
+TransFuncId1=d7
+TransFuncId2=d7
+TransFuncId3=d3
+TransFuncId4=d14
+TransFuncId5=d12
+TransFuncId6=d1
+TransFuncId7=d3
+TransFuncId8=d14
+TransFuncId9=d12
+TransFuncId10=d1
+TransFuncId11=d1
+TransFuncId12=d1
+TransFuncId13=d1
+TransFuncId14=d1
+TransFuncId15=d1
+DILineAbove32=b0
+DIValNewline32=b0
+DILineAbove33=b0
+DIValNewline33=b0
+MaxWidth=d350
+MaxHeight=d400
+Opacity=b75
+DILabel21=uHumidity:
+DILineAbove34=b0
+DIValNewline34=b0
+Module4=s
+Setting15=sStatus5
+TransFuncId16=d1
+DILineAbove35=b0
+DIValNewline35=b0
+DILineAbove36=b0
+DIValNewline36=b0
+MouseTollerance=b16
+DILineAbove37=b0
+DIValNewline37=b0
+DILineAbove38=b0
+DIValNewline38=b0
+FontValues=uTahoma
+FontLabels=uTahoma
+FontFirst=uTahoma
+xStatus: empty xStatus name to default name=d16
+DropShadow=b1
+RightValues=b0
+SBarTips=b1
+DividerCol=d10304821
+SidebarCol=d15391189
+AvatarRoundCorners=b0
+AvatarPadding=w6
+TextPadding=w4
+SidebarWidth=d22
+TransFuncId17=d1
+TransFuncId18=d1
+Name0=uGender
+Module0=sUserInfo
+Setting0=sGender
+Name1=uicqIP
+Setting1=sIP
+Name2=uicqIPreal
+DILabel20=uPressure:
+DILabel39=uLast message: (%sys:last_msg_reltime% ago)
+DIValue39=u%sys:last_msg%
+DILineAbove39=b1
+DIValNewline39=b1
+DILabel0=uStatus:
+DIValue0=u%Status%
+DILabel4=uID:
+DILabel1=uNick:
+DIValue1=u%raw:/Nick%
+DIValue29=u%raw:/CListName1% (%metaS1%) %raw:/Login1%
+DILabel29=u%raw:/Protocol1%:
+DILabel30=u%raw:/Protocol2%:
+DILabel31=u%raw:/Protocol3%:
+DILabel32=u%raw:/Protocol4%:
+DIValue30=u%raw:/CListName2% (%metaS2%) %raw:/Login2%
+DIValue31=u%raw:/CListName3% (%metaS3%) %raw:/Login3%
+DIValue32=u%raw:/CListName4% (%metaS4%) %raw:/Login4%
+DILabel38=u%raw:/Protocol9%:
+DIValue38=u%raw:/CListName9% (%metaS9%) %raw:/Login9%
+DILabel37=u%raw:/Protocol9%:
+DIValue37=u%raw:/CListName9% (%metaS9%) %raw:/Login9%
+DILabel35=u%raw:/Protocol7%:
+DIValue35=u%raw:/CListName7% (%metaS7%) %raw:/Login7%
+DILabel36=u%raw:/Protocol8%:
+DIValue36=u%raw:/CListName8% (%metaS8%) %raw:/Login8%
+DILabel33=u%raw:/Protocol5%:
+DIValue33=u%raw:/CListName5% (%metaS5%) %raw:/Login5%
+DILabel34=u%raw:/Protocol6%:
+DIValue34=u%raw:/CListName6% (%metaS6%) %raw:/Login6%
+FontFirstFlags=d288
+FontLabelsFlags=d288
+FontValuesFlags=d288
+DILabel16=uVisibility:
+DILabel19=uHigh/Low:
+DILabel28=u%raw:/Protocol0%:
+DIValue28=u%raw:/CListName0% (%metaS0%) %raw:/Login0%
+Name3=uidle_ago
+Name4=uidle_date
+Name5=uidle_time
+Module5=s
+Name6=ulastseen_status
+Module6=sSeenModule
+Setting6=sStatus
+Setting16=sStatus6
+Setting4=sIdleTS
+Setting5=sIdleTS
+Name8=ulogon_date
+Setting17=sStatus7
+Setting18=sStatus8
+TransFuncId19=d1
+DILabel13=uExtra status title:
+DIValue13=u%raw:/XStatusName%
+DILabel14=uExtra status message:
+DIValue14=u%raw:/XStatusMsg%
+DILabel15=uObservation time:
+DIValue15=u%raw:Current/Update%
+DIValue16=u%raw:Current/Visibility%
+DILabel17=uFeels like:
+DIValue17=u%raw:Current/Feel%
+DILabel18=uWind:
+DIValue18=u%raw:Current/Wind Direction% (%raw:Current/Wind Direction DEG%)/%raw:Current/Wind Speed%
+DIValue19=u%raw:Current/High%/%raw:Current/Low%
+DIValue20=u%raw:Current/Pressure% (%raw:Current/Pressure Tendency%)
+DIValue21=u%raw:Current/Humidity%
+DILabel22=uUV Index:
+DIValue22=u%raw:Current/UV% - %raw:Current/UVI%
+DILabel23=uSunrise/Sunset:
+DIValue23=u%raw:Current/Sunrise%/%raw:Current/Sunset%
+DILabel24=uMoonphase
+DIValue24=u%raw:Current/Moon%
+DILabel25=uTopic :
+DIValue25=u%raw:/Topic%
+DILabel26=uLast message: (%sys:last_msg_reltime% ago)
+DIValue26=u%sys:last_msg%
+DILabel27=uStatus message :
+DIValue27=u%sys:status_msg%
+Name9=ulogon_time
+Setting19=sStatus9
+Name20=uStatus
+Setting20=sStatus
+TransFuncId20=d1
+DIValue8=u%raw:/MirVer%
+DILabel11=uIdle:
+DIValue11=u%idle_date% @ %idle_time% (%idle_ago%)
+DILabel12=uLogon:
+DIValue12=u%logon_date% @ %logon_time% (%logon_ago%)
+Name7=ulogon_ago
+DILabel8=uClient:
+DILabel9=uIP:
+DIValue9=u%icqIP% (%icqIPreal%)
+DILabel10=uLast seen:
+DIValue10=u%raw:SeenModule/Day%.%raw:SeenModule/Month%.%raw:SeenModule/Year% @ %raw:SeenModule/Hours%:%raw:SeenModule/Minutes%:%raw:SeenModule/Seconds% (%lastseen_status%)
+DILabel2=uEmail:
+DIValue2=u%raw:/e-mail%
+DILabel3=uUIN:
+DIValue3=u%raw:/UIN%
+DIValue4=u%raw:/stid%
+DILabel5=uID:
+DIValue5=u%raw:/jid%
+DILabel6=uGender:
+DIValue6=u%Gender%
+DILabel7=uBirthday:
+DIValue7=u%raw:mBirthday/BirthDay%-%raw:mBirthday/BirthMonth%-%raw:mBirthday/BirthYear% ( %raw:UserInfo/Age% )
+
+
diff --git a/tipper/docs/licence_Tipper.txt b/tipper/docs/licence_Tipper.txt new file mode 100644 index 0000000..082744b --- /dev/null +++ b/tipper/docs/licence_Tipper.txt @@ -0,0 +1,6 @@ +The Tipper plugin for Miranda-IM is Copyright (c) 2006 Scott Ellis (mail@scottellis.com.au)
+
+http://www.scottellis.com.au
+
+It is released under the General Public Licence, available here:
+http://www.gnu.org/copyleft/gpl.html
\ No newline at end of file diff --git a/tipper/docs/m_tipper.h b/tipper/docs/m_tipper.h new file mode 100644 index 0000000..031d490 --- /dev/null +++ b/tipper/docs/m_tipper.h @@ -0,0 +1,23 @@ +// Tipper API
+// note: Tipper is internally unicode and requires unicows.dll to function correctly on 95/98/ME
+// so you'll find a lot of wchar_t stuff in here
+
+// use hContact, module and setting to read your db value(s) and put the resulting string into buff
+// return buff if the translation was successful, or return 0 for failure
+typedef wchar_t *(TranslateFunc)(HANDLE hContact, const char *module, const char *setting_or_prefix, wchar_t *buff, int bufflen);
+
+typedef struct {
+ TranslateFunc *tfunc; // address of your translation function (see typedef above)
+ const wchar_t *name; // make sure this is unique, and DO NOT translate it
+ DWORD id; // will be overwritten by Tipper - do not use
+} DBVTranslation;
+
+// add a translation to tipper
+// wParam not used
+// lParam = (DBVTranslation *)translation
+#define MS_TIPPER_ADDTRANSLATION "Tipper/AddTranslation"
+
+// unicode extension to the basic functionality
+// wParam - optional (wchar_t *)text for text-only tips
+// lParam - (CLCINFOTIP *)infoTip
+#define MS_TIPPER_SHOWTIPW "mToolTip/ShowTipW"
diff --git a/tipper/docs/readme_tipper.txt b/tipper/docs/readme_tipper.txt new file mode 100644 index 0000000..2ab3603 --- /dev/null +++ b/tipper/docs/readme_tipper.txt @@ -0,0 +1,143 @@ +Document updated: 28/9/06
+
+******
+Tipper - shows a tooltip when you hover the mouse over a contact in your contact list
+******
+
+Most options are self explanitory...except for 'items' and 'substitutions'.
+
+If you want to set this up yourself, you need a moderate understanding of the miranda database (profile) and the Database Editor++ plugin.
+
+The easiest way is to copy the autoexec_tipper.ini file (in the same folder as this document) to the miranda program folder and restart -
+it will (normally) ask you if you wish to import the settings. If you click yes, you will find several examples in your Tipper options that
+will get you started. You can also ask your nerdier miranda-using buddies to create such a file for you, if they have a good setup.
+
+To get an idea of how tipper works, try playing with items. Items are simply a label and some text (the value). Try adding some items. Once
+you've played around a bit you'll get the idea, and then you'll understand the need for substitutions.
+
+Substitutions allow you to put useful, contact related, information into the label or value of an item. To create a substitution you need
+to have a relatively good understanding of the miranda database - a few hours browsing with dbeditor++ will give you a clue. You create a
+substitution by specifying a name and the database module and setting names for the data it will contain. You can then put this data into
+any item (label or value) by enclosing the substitution name in '%' symbols. Many database values are not terribly friendly to humans, so
+when creating a substitution, you can also choose a translation which will convert the value into a more readable format.
+
+To get technical:
+
+A 'Substitution' is a name for a database value, represented according to a particular translation. When creating new substitutions, you
+specify its name, the database module (or the contact's protocol module) and the setting name. Then you select a translation from the drop
+down list. This transformation will convert the database value into a string.
+
+An 'Item' is just a label and a value. However, any substitution names (surrounded by % symbols) occuring in either a label or a value will
+be substituted as described above. If you want to put a % symbol in a value or label, use '%%' instead.
+
+A good example is representing a contacts status (as 'Online' etc) in the tooltip.
+
+First, create a substitution called 'status' (without quotes) - the module will be the contact's protocol module, the setting name will be
+'Status' (without quotes - note the capital 'S') and the translation will be 'WORD to status description' (since this value is a WORD value
+in the database). Then, create an item and specify 'Status:' for the label and '%status%' for the value. Done.
+
+There is also a built in substitution, called a 'raw' substitution. It is not listed in the substitution list, but it is available in all
+labels and values. It's format is:
+
+%raw:<db module>/<db setting>%
+
+No translation is performed on 'raw' values. For example, to display a contact's contact list group in the tooltip, add an item with the
+label 'Group:' and the value '%raw:CList/Group%'. If you do not specify a module name (you must still include the '/'), the contact's
+protocol module will be used. This is ultimately just a shortcut for the 'null translation'.
+
+There are also 'system' substitutions (thanks to y_b), also not listed but available in all item labels and values, with the following
+format:
+
+%sys:<name>%
+
+Were name can be any of the following (as at 28/9/06):
+
+uid - contact's unique identifier
+uidname - name of unique identifier
+proto - contact's protocol
+status_msg - contact's status message
+last_msg - last message received from contact
+last_msg_time - time of last received message
+last_msg_date - date of last received message
+last_msg_reltime - relative time of last message (i.e. time between then and now)
+meta_subname - nickname of active subcontact (for metacontacts)
+meta_subuid - unique id of active subcontact
+meta_subproto - active subcontact protocol (also for metacontacts)
+
+If a substitution's value results in no text (or nothing but spaces, tabs, newlines, and carriage returns), the whole item containing that
+substitution will not be displayed. If there is an error during the substitution process (e.g. a substitution name that does not exist, an odd
+number of % symbols, etc) then the value of that substitution will be "*". Note that you can use double-percent ("%%") in plain text (not in
+substitutions) if you want an actual percent symbol.
+
+ADVANCED
+--------
+
+Alternative Text:
+In any substitution you can have 'alternate text' to use if the substitution fails (missing db value, etc). The format is:
+
+%x|y%
+
+where x is the original substitution and y is the alternative text. Note that you can use '|' in the alternative text, since it uses the
+*first* occurence to determine where the alternative text begins. Normally if any substitution results in no value, the entire item will not
+be displayed - but if you omit the 'y' value above (i.e. have nothing for the 'alternate' text) then the substitution process will continue.
+As an example, consider the following item value:
+
+%raw:/FirstName|% %raw:/LastName%
+
+The above value will display the contact's first name if it's available, and then their last name - but if the last name is not available, the
+entire item will not be displayed.
+
+Specific protocol:
+If you end a substitution with '^' and a protocol name, then that substitution will only be displayed if the contact belongs to the given
+protocol:
+
+%x^y%
+
+where y is the protocol name. If you want to display an item for every protocol *except* one, use
+
+%x^!y%
+
+If you use alternative text and specific protocol together, specify the alternative text first:
+
+%x|y^z%
+
+In such substitutions you can use a '^' symbol in the alternative text, as Tipper will take the *last* '^' symbol as the start of the protocol
+specifier. If you want to use a '^' symbol in alternative text without a specific protocol, just append a '^' to the end of the descriptor,
+e.g.:
+
+%x|y^%
+
+
+'HIDDEN' DB SETTINGS
+--------------------
+
+Due to space constraints in the options page and my own laziness, the following settings are only accessible via the database (i.e. using dbeditor++):
+
+DWORD Tipper/MinHeight
+DWORD Tipper/MinWidth
+WORD Tipper/AvatarPadding
+WORD Tipper/TextPadding (space between lines of text)
+DWORD Tipper/SidebarWidth
+BYTE Tipper/MouseTollerance (distance mouse can move while tip is shown, before it is automatically closed, in pixels)
+BYTE Tipper/AvatarRoundCorners
+
+
+********************
+'Variables' support:
+********************
+
+This plugin supports the variables plugin by UnregistereD (http://www.cs.vu.nl/~pboon/variables.zip)
+
+Be sure to use the unicode version!
+
+All text in 'Items' - that is, labels and values, will be processed by variables BEFORE Tipper substitutions are applied.
+
+
+Good luck and have fun.
+
+
+Scott
+mail@scottellis.com.au
+www.scottellis.com.au
+
+p.s. Thanks to Omniwolf and Tweety for compiling autoexec_Tipper(*).ini files
diff --git a/tipper/m_tipper.h b/tipper/m_tipper.h new file mode 100644 index 0000000..81dcb59 --- /dev/null +++ b/tipper/m_tipper.h @@ -0,0 +1,19 @@ +// Tipper API
+// note: Tipper is internally unicode and requires unicows.dll to function correctly on 95/98/ME
+// so you'll find a lot of wchar_t stuff in here
+
+// translation function type
+// use hContact, module and setting to read your db value(s) and put the resulting string into buff
+// return buff if the translation was successful, or return 0 for failure
+typedef wchar_t *(TranslateFunc)(HANDLE hContact, const char *module, const char *setting_or_prefix, wchar_t *buff, int bufflen);
+
+typedef struct {
+ TranslateFunc *tfunc; // address of your translation function (see typedef above)
+ const wchar_t *name; // make sure this is unique, and DO NOT translate it
+ DWORD id; // will be overwritten by Tipper - do not use
+} DBVTranslation;
+
+// add a translation to tipper
+// wParam not used
+// lParam = (DBVTranslation *)translation
+#define MS_TIPPER_ADDTRANSLATION "Tipper/AddTranslation"
diff --git a/tipper/message_pump.cpp b/tipper/message_pump.cpp new file mode 100644 index 0000000..d891a33 --- /dev/null +++ b/tipper/message_pump.cpp @@ -0,0 +1,201 @@ +#include "common.h"
+#include "message_pump.h"
+#include "popwin.h"
+#include "options.h"
+
+HMODULE hUserDll;
+BOOL (WINAPI *MySetLayeredWindowAttributes)(HWND,COLORREF,BYTE,DWORD) = 0;
+BOOL (WINAPI *MyAnimateWindow)(HWND hWnd,DWORD dwTime,DWORD dwFlags) = 0;
+
+//DWORD message_pump_thread_id = 0;
+unsigned int message_pump_thread_id = 0;
+HANDLE hMPEvent;
+
+//DWORD CALLBACK MessagePumpThread(LPVOID param) {
+unsigned int CALLBACK MessagePumpThread(void *param) {
+ if(param) SetEvent((HANDLE)param);
+
+ CallService(MS_SYSTEM_THREAD_PUSH, 0, 0);
+
+ HWND hwndTip = 0;
+
+ MSG hwndMsg = {0};
+ while(GetMessage(&hwndMsg, 0, 0, 0) > 0 && !Miranda_Terminated()) {
+ if(!IsDialogMessage(hwndMsg.hwnd, &hwndMsg)) {
+ switch(hwndMsg.message) {
+ case MUM_CREATEPOPUP:
+ {
+ if(hwndTip) DestroyWindow(hwndTip);
+ // if child of clist, zorder is right, but it steals the first click on a contact :(
+
+ // copy topmost exstyle from clist, since we'll put clist under tip in WM_CREATE message
+ //LONG clist_exstyle = GetWindowLong((HWND)CallService(MS_CLUI_GETHWND, 0, 0), GWL_EXSTYLE);
+ //hwndTip = CreateWindowEx((clist_exstyle & WS_EX_TOPMOST), POP_WIN_CLASS, _T("TipperPopup"), WS_POPUP, 0, 0, 0, 0, 0/*(HWND)CallService(MS_CLUI_GETHWND, 0, 0)*/, 0, hInst, (LPVOID)hwndMsg.lParam);
+
+ hwndTip = CreateWindowEx(WS_EX_TOOLWINDOW | WS_EX_TOPMOST, POP_WIN_CLASS, _T("TipperPopup"), WS_POPUP, 0, 0, 0, 0, 0/*(HWND)CallService(MS_CLUI_GETHWND, 0, 0)*/, 0, hInst, (LPVOID)hwndMsg.lParam);
+ if(hwndMsg.lParam) free((LPVOID)hwndMsg.lParam);
+ }
+ break;
+
+ case MUM_DELETEPOPUP:
+ {
+ if(hwndTip) {
+ DestroyWindow(hwndTip);
+ hwndTip = 0;
+ }
+ }
+ break;
+ case MUM_GOTSTATUS:
+ {
+ if(hwndTip) SendMessage(hwndTip, PUM_SETSTATUSTEXT, hwndMsg.wParam, hwndMsg.lParam);
+ else if(hwndMsg.lParam) free((void *)hwndMsg.lParam);
+ }
+ break;
+ case MUM_GOTAVATAR:
+ {
+ if(hwndTip) SendMessage(hwndTip, PUM_SETAVATAR, hwndMsg.wParam, hwndMsg.lParam);
+ }
+ break;
+ default:
+ {
+ TranslateMessage(&hwndMsg);
+ DispatchMessage(&hwndMsg);
+ }
+ break;
+ }
+ }
+ }
+
+ CallService(MS_SYSTEM_THREAD_POP, 0, 0);
+
+ return 0;
+}
+
+void PostMPMessage(UINT msg, WPARAM wParam, LPARAM lParam) {
+ PostThreadMessage(message_pump_thread_id, msg, wParam, lParam);
+}
+
+// given a popup data pointer, and a handle to an event, this function
+// will post a message to the message queue which will set the hwnd value
+// and then set the event...so create an event, call this function and then wait on the event
+// when the event is signalled, the hwnd will be valid
+void FindWindow(POPUPDATAW *pd, HANDLE hEvent, HWND *hwnd);
+
+void InitMessagePump() {
+ WNDCLASS popup_win_class = {0};
+ popup_win_class.style = 0;
+ popup_win_class.lpfnWndProc = PopupWindowProc;
+ popup_win_class.hInstance = hInst;
+ popup_win_class.lpszClassName = POP_WIN_CLASS;
+ popup_win_class.hCursor = LoadCursor(NULL, IDC_ARROW);
+ RegisterClass(&popup_win_class);
+
+ hUserDll = LoadLibrary(_T("user32.dll"));
+ if (hUserDll) {
+ MySetLayeredWindowAttributes = (BOOL (WINAPI *)(HWND,COLORREF,BYTE,DWORD))GetProcAddress(hUserDll, "SetLayeredWindowAttributes");
+ MyAnimateWindow=(BOOL (WINAPI*)(HWND,DWORD,DWORD))GetProcAddress(hUserDll,"AnimateWindow");
+ }
+
+ hMPEvent = CreateEvent(0, TRUE, 0, 0);
+ CloseHandle((HANDLE)_beginthreadex(0, 0, MessagePumpThread, hMPEvent, 0, &message_pump_thread_id));
+ WaitForSingleObject(hMPEvent, INFINITE);
+ CloseHandle(hMPEvent);
+}
+
+void DeinitMessagePump() {
+ PostMPMessage(WM_QUIT, 0, 0);
+
+ FreeLibrary(hUserDll);
+
+ UnregisterClass(POP_WIN_CLASS, hInst);
+}
+
+int ShowTip(WPARAM wParam, LPARAM lParam) {
+ CLCINFOTIP *clcit = (CLCINFOTIP *)lParam;
+ if(clcit->isGroup) return 0; // no group tips (since they're pretty useless)
+ if(clcit->isTreeFocused == 0 && options.show_no_focus == false) return 0;
+
+ CLCINFOTIPEX *clcit2 = (CLCINFOTIPEX *)malloc(sizeof(CLCINFOTIPEX));
+ memcpy(clcit2, clcit, sizeof(CLCINFOTIP));
+ clcit2->cbSize = sizeof(CLCINFOTIPEX);
+ clcit2->proto = 0;
+ clcit2->text = 0;
+
+ if(wParam) { // wParam is char pointer containing text - e.g. status bar tooltip
+ int size = MultiByteToWideChar(code_page, 0, (char *)wParam, -1, 0, 0); + if(size) { + clcit2->text = (wchar_t *)malloc(size * sizeof(wchar_t)); + MultiByteToWideChar(code_page, 0, (char *)wParam, -1, clcit2->text, size); + GetCursorPos(&clcit2->ptCursor); // cursor pos broken?
+ } + }
+
+ PostMPMessage(MUM_CREATEPOPUP, 0, (LPARAM)clcit2);
+ return 1;
+}
+
+int ShowTipW(WPARAM wParam, LPARAM lParam) {
+ CLCINFOTIP *clcit = (CLCINFOTIP *)lParam;
+ if(clcit->isGroup) return 0; // no group tips (since they're pretty useless)
+ if(clcit->isTreeFocused == 0 && options.show_no_focus == false) return 0;
+
+ CLCINFOTIPEX *clcit2 = (CLCINFOTIPEX *)malloc(sizeof(CLCINFOTIPEX));
+ memcpy(clcit2, clcit, sizeof(CLCINFOTIP));
+ clcit2->cbSize = sizeof(CLCINFOTIPEX);
+ clcit2->proto = 0;
+ clcit2->text = 0;
+
+ if(wParam) { // wParam is char pointer containing text - e.g. status bar tooltip
+ clcit2->text = _tcsdup((TCHAR *)wParam); + GetCursorPos(&clcit2->ptCursor); // cursor pos broken?
+ }
+
+ PostMPMessage(MUM_CREATEPOPUP, 0, (LPARAM)clcit2);
+ return 1;
+}
+
+int HideTip(WPARAM wParam, LPARAM lParam) {
+ //CLCINFOTIP *clcit = (CLCINFOTIP *)lParam;
+ PostMPMessage(MUM_DELETEPOPUP, 0, 0);
+ return 1;
+}
+
+int ProtoAck(WPARAM wParam, LPARAM lParam) {
+ ACKDATA *ack = (ACKDATA *)lParam;
+ char *szMsg = (char *)ack->lParam;
+ if(ack->type == ACKTYPE_AWAYMSG && ack->result == ACKRESULT_SUCCESS && szMsg) {
+ int size = MultiByteToWideChar(code_page, 0, szMsg, -1, 0, 0);
+ if(size > 1) {
+ wchar_t *msg = (wchar_t *)malloc(size * sizeof(wchar_t));
+ MultiByteToWideChar(code_page, 0, (char *) szMsg, -1, msg, size);
+ PostMPMessage(MUM_GOTSTATUS, (WPARAM)ack->hContact, (LPARAM)msg);
+ }
+ }
+ return 0;
+}
+
+int FramesShowSBTip(WPARAM wParam, LPARAM lParam) {
+ if(options.status_bar_tips) {
+ char *proto = (char *)wParam;
+
+ CLCINFOTIPEX *clcit2 = (CLCINFOTIPEX *)malloc(sizeof(CLCINFOTIPEX));
+ memset(clcit2, 0, sizeof(CLCINFOTIPEX));
+ clcit2->cbSize = sizeof(CLCINFOTIPEX);
+ clcit2->proto = proto; // assume static string
+ GetCursorPos(&clcit2->ptCursor);
+
+ PostMPMessage(MUM_CREATEPOPUP, 0, (LPARAM)clcit2);
+
+ return 1;
+ }
+ return 0;
+}
+
+int FramesHideSBTip(WPARAM wParam, LPARAM lParam) {
+ if(options.status_bar_tips) {
+ PostMPMessage(MUM_DELETEPOPUP, 0, 0);
+ return 1;
+ }
+ return 0;
+}
+
diff --git a/tipper/message_pump.h b/tipper/message_pump.h new file mode 100644 index 0000000..4ed5eed --- /dev/null +++ b/tipper/message_pump.h @@ -0,0 +1,41 @@ +#ifndef _MESSAGE_PUMP_INC
+#define _MESSAGE_PUMP_INC
+
+//extern DWORD message_pump_thread_id;
+extern unsigned int message_pump_thread_id;
+void PostMPMessage(UINT msg, WPARAM, LPARAM);
+
+#define MUM_CREATEPOPUP (WM_USER + 0x011)
+#define MUM_DELETEPOPUP (WM_USER + 0x012)
+#define MUM_GOTSTATUS (WM_USER + 0x013)
+#define MUM_GOTAVATAR (WM_USER + 0x014)
+
+extern HMODULE hUserDll;
+extern BOOL (WINAPI *MySetLayeredWindowAttributes)(HWND,COLORREF,BYTE,DWORD);
+extern BOOL (WINAPI *MyAnimateWindow)(HWND hWnd,DWORD dwTime,DWORD dwFlags);
+
+void InitMessagePump();
+void DeinitMessagePump();
+
+int ShowTip(WPARAM wParam, LPARAM lParam);
+int ShowTipW(WPARAM wParam, LPARAM lParam);
+int HideTip(WPARAM wParam, LPARAM lParam);
+
+int FramesShowSBTip(WPARAM wParam, LPARAM lParam);
+int FramesHideSBTip(WPARAM wParam, LPARAM lParam);
+
+int ProtoAck(WPARAM wParam, LPARAM lParam);
+
+typedef struct {
+ int cbSize;
+ int isTreeFocused; //so the plugin can provide an option
+ int isGroup; //0 if it's a contact, 1 if it's a group
+ HANDLE hItem; //handle to group or contact
+ POINT ptCursor;
+ RECT rcItem;
+ TCHAR *text; // for tips with specific text
+ char *proto; // for proto tips
+} CLCINFOTIPEX;
+
+
+#endif
diff --git a/tipper/options.cpp b/tipper/options.cpp new file mode 100644 index 0000000..260ccbb --- /dev/null +++ b/tipper/options.cpp @@ -0,0 +1,1126 @@ +#include "common.h" +#include "options.h" +#include "resource.h" +#include "popwin.h" +#include <commctrl.h> + +Options options; + +#define WMU_ENABLE_LIST_BUTTONS (WM_USER + 0x030) +#define WMU_ENABLE_MODULE_ENTRY (WM_USER + 0x031) + +void CreateDefaultItems() { + DSListNode *ds_node; + DIListNode *di_node; + + // last message item + di_node = (DIListNode *)malloc(sizeof(DIListNode)); + _tcsncpy(di_node->di.label, _T("Last message: (%sys:last_msg_reltime% ago)"), LABEL_LEN); + _tcsncpy(di_node->di.value, _T("%sys:last_msg%"), VALUE_LEN); + di_node->di.line_above = di_node->di.value_newline = true; + di_node->next = options.di_list; + options.di_list = di_node; + options.di_count++; + + // status message item + di_node = (DIListNode *)malloc(sizeof(DIListNode)); + _tcsncpy(di_node->di.label, _T("Status message:"), LABEL_LEN); + _tcsncpy(di_node->di.value, _T("%sys:status_msg%"), VALUE_LEN); + di_node->di.line_above = di_node->di.value_newline = true; + di_node->next = options.di_list; + options.di_list = di_node; + options.di_count++; +
+ // status substitution + ds_node = (DSListNode *)malloc(sizeof(DSListNode)); + _tcsncpy(ds_node->ds.name, _T("status"), LABEL_LEN); + ds_node->ds.type = DVT_PROTODB; + strncpy(ds_node->ds.setting_name, "Status", SETTING_NAME_LEN); + ds_node->ds.translate_func_id = 1; + ds_node->next = options.ds_list; + options.ds_list = ds_node; + options.ds_count++; + + // status item + di_node = (DIListNode *)malloc(sizeof(DIListNode)); + _tcsncpy(di_node->di.label, _T("Status:"), LABEL_LEN); + _tcsncpy(di_node->di.value, _T("%status%"), VALUE_LEN); + di_node->di.line_above = di_node->di.value_newline = false; + di_node->next = options.di_list; + options.di_list = di_node; + options.di_count++; + + // client substitution + ds_node = (DSListNode *)malloc(sizeof(DSListNode)); + _tcsncpy(ds_node->ds.name, _T("client"), LABEL_LEN); + ds_node->ds.type = DVT_PROTODB; + strncpy(ds_node->ds.setting_name, "MirVer", SETTING_NAME_LEN); + ds_node->ds.translate_func_id = 0; + ds_node->next = options.ds_list; + options.ds_list = ds_node; + options.ds_count++; + + // client item + di_node = (DIListNode *)malloc(sizeof(DIListNode)); + _tcsncpy(di_node->di.label, _T("Client:"), LABEL_LEN); + _tcsncpy(di_node->di.value, _T("%client%"), VALUE_LEN); + di_node->di.line_above = di_node->di.value_newline = false; + di_node->next = options.di_list; + options.di_list = di_node; + options.di_count++; + + // idle time substitution (long date) + ds_node = (DSListNode *)malloc(sizeof(DSListNode)); + _tcsncpy(ds_node->ds.name, _T("idle"), LABEL_LEN); + ds_node->ds.type = DVT_PROTODB; + strncpy(ds_node->ds.setting_name, "IdleTS", SETTING_NAME_LEN); + ds_node->ds.translate_func_id = 15; + ds_node->next = options.ds_list; + options.ds_list = ds_node; + options.ds_count++; + + // idle time substitution (time difference) + ds_node = (DSListNode *)malloc(sizeof(DSListNode)); + _tcsncpy(ds_node->ds.name, _T("idle_diff"), LABEL_LEN); + ds_node->ds.type = DVT_PROTODB; + strncpy(ds_node->ds.setting_name, "IdleTS", SETTING_NAME_LEN); + ds_node->ds.translate_func_id = 3; + ds_node->next = options.ds_list; + options.ds_list = ds_node; + options.ds_count++; + + + // idle item + di_node = (DIListNode *)malloc(sizeof(DIListNode)); + _tcsncpy(di_node->di.label, _T("Idle:"), LABEL_LEN); + _tcsncpy(di_node->di.value, _T("%idle% (%idle_diff% ago)"), VALUE_LEN); + di_node->di.line_above = di_node->di.value_newline = false; + di_node->next = options.di_list; + options.di_list = di_node; + options.di_count++; + + // first name substitution + ds_node = (DSListNode *)malloc(sizeof(DSListNode)); + _tcsncpy(ds_node->ds.name, _T("first_name"), LABEL_LEN); + ds_node->ds.type = DVT_PROTODB; + strncpy(ds_node->ds.setting_name, "FirstName", SETTING_NAME_LEN); + ds_node->ds.translate_func_id = 0; + ds_node->next = options.ds_list; + options.ds_list = ds_node; + options.ds_count++; + + // last name substitution + ds_node = (DSListNode *)malloc(sizeof(DSListNode)); + _tcsncpy(ds_node->ds.name, _T("last_name"), LABEL_LEN); + ds_node->ds.type = DVT_PROTODB; + strncpy(ds_node->ds.setting_name, "LastName", SETTING_NAME_LEN); + ds_node->ds.translate_func_id = 0; + ds_node->next = options.ds_list; + options.ds_list = ds_node; + options.ds_count++; + + // name item + di_node = (DIListNode *)malloc(sizeof(DIListNode)); + _tcsncpy(di_node->di.label, _T("Name:"), LABEL_LEN); + _tcsncpy(di_node->di.value, _T("%first_name% %last_name%"), VALUE_LEN); + di_node->di.line_above = di_node->di.value_newline = false; + di_node->next = options.di_list; + options.di_list = di_node; + options.di_count++; + +} + +bool LoadDS(DisplaySubst *ds, int index) { + char setting[512]; + DBVARIANT dbv; + mir_snprintf(setting, 512, "Name%d", index); + ds->name[0] = 0; + if(!DBGetContactSettingWString(0, MODULE, setting, &dbv)) { + _tcsncpy(ds->name, dbv.pwszVal, LABEL_LEN); + DBFreeVariant(&dbv); + } else if(!DBGetContactSettingStringUtf(0, MODULE, setting, &dbv)) { + MultiByteToWideChar(CP_UTF8, 0, dbv.pszVal, -1, ds->name, LABEL_LEN); + DBFreeVariant(&dbv); + } else if(!DBGetContactSetting(0, MODULE, setting, &dbv)) { + if(dbv.type == DBVT_ASCIIZ) MultiByteToWideChar(code_page, 0, dbv.pszVal, -1, ds->name, LABEL_LEN); + DBFreeVariant(&dbv); + } else + return false; + ds->name[LABEL_LEN - 1] = 0; + + mir_snprintf(setting, 512, "Type%d", index); + ds->type = (DisplaySubstType)DBGetContactSettingByte(0, MODULE, setting, DVT_PROTODB); + + mir_snprintf(setting, 512, "Module%d", index); + ds->module_name[0] = 0; + if(!DBGetContactSetting(0, MODULE, setting, &dbv)) { + strncpy(ds->module_name, dbv.pszVal, MODULE_NAME_LEN); + ds->module_name[MODULE_NAME_LEN - 1] = 0; + DBFreeVariant(&dbv); + } + + mir_snprintf(setting, 512, "Setting%d", index); + ds->setting_name[0] = 0; + if(!DBGetContactSetting(0, MODULE, setting, &dbv)) { + strncpy(ds->setting_name, dbv.pszVal, SETTING_NAME_LEN); + ds->setting_name[SETTING_NAME_LEN - 1] = 0; + DBFreeVariant(&dbv); + } + + mir_snprintf(setting, 512, "TransFuncId%d", index); + ds->translate_func_id = DBGetContactSettingDword(0, MODULE, setting, (DWORD)-1); + + // a little backward compatibility + if((DWORD)ds->translate_func_id == (DWORD)-1) { + mir_snprintf(setting, 512, "TransFunc%d", index); + ds->translate_func_id = (DWORD)DBGetContactSettingWord(0, MODULE, setting, 0); + } + return true; +} + +void SaveDS(DisplaySubst *ds, int index) { + char setting[512]; + mir_snprintf(setting, 512, "Name%d", index); + if(DBWriteContactSettingWString(0, MODULE, setting, ds->name)) { + char buff[LABEL_LEN]; + WideCharToMultiByte(code_page, 0, ds->name, -1, buff, LABEL_LEN, 0, 0); + buff[LABEL_LEN] = 0; + DBWriteContactSettingString(0, MODULE, setting, buff); + } + mir_snprintf(setting, 512, "Type%d", index); + DBWriteContactSettingByte(0, MODULE, setting, (BYTE)ds->type); + mir_snprintf(setting, 512, "Module%d", index); + DBWriteContactSettingString(0, MODULE, setting, ds->module_name); + mir_snprintf(setting, 512, "Setting%d", index); + DBWriteContactSettingString(0, MODULE, setting, ds->setting_name); + mir_snprintf(setting, 512, "TransFuncId%d", index); + DBWriteContactSettingDword(0, MODULE, setting, (WORD)ds->translate_func_id); +} + +bool LoadDI(DisplayItem *di, int index) { + char setting[512]; + DBVARIANT dbv; + mir_snprintf(setting, 512, "DILabel%d", index); + di->label[0] = 0; + if(!DBGetContactSettingWString(0, MODULE, setting, &dbv)) { + _tcsncpy(di->label, dbv.pwszVal, LABEL_LEN); + DBFreeVariant(&dbv); + } else if(!DBGetContactSettingStringUtf(0, MODULE, setting, &dbv)) { + MultiByteToWideChar(CP_UTF8, 0, dbv.pszVal, -1, di->label, LABEL_LEN); + DBFreeVariant(&dbv); + } else if(!DBGetContactSetting(0, MODULE, setting, &dbv)) { + if(dbv.type == DBVT_ASCIIZ) MultiByteToWideChar(code_page, 0, dbv.pszVal, -1, di->label, LABEL_LEN); + DBFreeVariant(&dbv); + } else + return false; + di->label[LABEL_LEN - 1] = 0; + + mir_snprintf(setting, 512, "DIValue%d", index); + di->value[0] = 0; + if(!DBGetContactSettingWString(0, MODULE, setting, &dbv)) { + _tcsncpy(di->value, dbv.pwszVal, VALUE_LEN); + DBFreeVariant(&dbv); + } else if(!DBGetContactSettingStringUtf(0, MODULE, setting, &dbv)) { + MultiByteToWideChar(CP_UTF8, 0, dbv.pszVal, -1, di->value, VALUE_LEN); + DBFreeVariant(&dbv); + } else if(!DBGetContactSetting(0, MODULE, setting, &dbv)) { + MultiByteToWideChar(code_page, 0, dbv.pszVal, -1, di->value, VALUE_LEN); + DBFreeVariant(&dbv); + } + + di->value[VALUE_LEN - 1] = 0; + + mir_snprintf(setting, 512, "DILineAbove%d", index); + di->line_above = (DBGetContactSettingByte(0, MODULE, setting, 0) == 1); + mir_snprintf(setting, 512, "DIValNewline%d", index); + di->value_newline = (DBGetContactSettingByte(0, MODULE, setting, 0) == 1); + + return true; +} + +void SaveDI(DisplayItem *di, int index) { + char setting[512]; + mir_snprintf(setting, 512, "DILabel%d", index); + if(DBWriteContactSettingWString(0, MODULE, setting, di->label)) { + char buff[LABEL_LEN]; + WideCharToMultiByte(code_page, 0, di->label, -1, buff, LABEL_LEN, 0, 0); + DBWriteContactSettingString(0, MODULE, setting, buff); + } + mir_snprintf(setting, 512, "DIValue%d", index); + if(DBWriteContactSettingWString(0, MODULE, setting, di->value)) { + char buff[VALUE_LEN]; + WideCharToMultiByte(code_page, 0, di->value, -1, buff, VALUE_LEN, 0, 0); + DBWriteContactSettingString(0, MODULE, setting, buff); + } + mir_snprintf(setting, 512, "DILineAbove%d", index); + DBWriteContactSettingByte(0, MODULE, setting, di->line_above ? 1 : 0); + mir_snprintf(setting, 512, "DIValNewline%d", index); + DBWriteContactSettingByte(0, MODULE, setting, di->value_newline ? 1 : 0); +} + +void SaveOptions() { + DBWriteContactSettingDword(0, MODULE, "MaxWidth", options.win_width); + DBWriteContactSettingDword(0, MODULE, "MaxHeight", options.win_max_height); + DBWriteContactSettingByte(0, MODULE, "Opacity", (BYTE)options.opacity); + DBWriteContactSettingByte(0, MODULE, "Border", (options.border ? 1 : 0)); + DBWriteContactSettingByte(0, MODULE, "DropShadow", (options.drop_shadow ? 1 : 0)); + DBWriteContactSettingByte(0, MODULE, "RoundCorners", (options.round ? 1 : 0)); + DBWriteContactSettingByte(0, MODULE, "AvatarRoundCorners", (options.av_round ? 1 : 0)); + DBWriteContactSettingByte(0, MODULE, "Animate", (options.animate ? 1 : 0)); + DBWriteContactSettingByte(0, MODULE, "TransparentBg", (options.trans_bg ? 1 : 0)); + DBWriteContactSettingByte(0, MODULE, "TitleLayout", (BYTE)options.title_layout); + if(ServiceExists(MS_AV_DRAWAVATAR)) + DBWriteContactSettingByte(0, MODULE, "AVLayout", (BYTE)options.av_layout); + DBWriteContactSettingDword(0, MODULE, "AVSize", options.av_size); + DBWriteContactSettingDword(0, MODULE, "TextIndent", options.text_indent); + DBWriteContactSettingByte(0, MODULE, "ShowNoFocus", (options.show_no_focus ? 1 : 0)); + + int index = 0; + DSListNode *ds_node = options.ds_list; + while(ds_node) { + SaveDS(&ds_node->ds, index); + ds_node = ds_node->next; + index++; + } + DBWriteContactSettingWord(0, MODULE, "DSNumValues", index); + + index = 0; + DIListNode *di_node = options.di_list; + while(di_node) { + SaveDI(&di_node->di, index); + di_node = di_node->next; + index++; + } + DBWriteContactSettingWord(0, MODULE, "DINumValues", index); + + DBWriteContactSettingWord(0, MODULE, "TimeIn", options.time_in); + CallService(MS_CLC_SETINFOTIPHOVERTIME, options.time_in, 0); + + DBWriteContactSettingWord(0, MODULE, "Padding", options.padding); + DBWriteContactSettingWord(0, MODULE, "AvatarPadding", options.av_padding); + DBWriteContactSettingWord(0, MODULE, "TextPadding", options.text_padding); + DBWriteContactSettingByte(0, MODULE, "Position", (BYTE)options.pos); + DBWriteContactSettingDword(0, MODULE, "MinWidth", (DWORD)options.min_width); + DBWriteContactSettingDword(0, MODULE, "MinHeight", (DWORD)options.min_height); + DBWriteContactSettingDword(0, MODULE, "SidebarWidth", (DWORD)options.sidebar_width); + DBWriteContactSettingByte(0, MODULE, "MouseTollerance", (BYTE)options.mouse_tollerance); + DBWriteContactSettingByte(0, MODULE, "SBarTips", (options.status_bar_tips ? 1 : 0)); + + DBWriteContactSettingWord(0, MODULE, "LabelVAlign", options.label_valign); + DBWriteContactSettingWord(0, MODULE, "LabelHAlign", options.label_halign); + DBWriteContactSettingWord(0, MODULE, "ValueVAlign", options.value_valign); + DBWriteContactSettingWord(0, MODULE, "ValueHAlign", options.value_halign); +} + +void LoadOptions() { + options.win_width = DBGetContactSettingDword(0, MODULE, "MaxWidth", 420); + options.win_max_height = DBGetContactSettingDword(0, MODULE, "MaxHeight", 400); + options.opacity = DBGetContactSettingByte(0, MODULE, "Opacity", 75); + options.border = (DBGetContactSettingByte(0, MODULE, "Border", 1) == 1); + options.drop_shadow = (DBGetContactSettingByte(0, MODULE, "DropShadow", 1) == 1); + options.round = (DBGetContactSettingByte(0, MODULE, "RoundCorners", 1) == 1); + options.av_round = (DBGetContactSettingByte(0, MODULE, "AvatarRoundCorners", options.round ? 1 : 0) == 1); + options.animate = (DBGetContactSettingByte(0, MODULE, "Animate", 0) == 1); + options.trans_bg = (DBGetContactSettingByte(0, MODULE, "TransparentBg", 0) == 1); + options.title_layout = (PopupTitleLayout)DBGetContactSettingByte(0, MODULE, "TitleLayout", (BYTE)PTL_LEFTICON); + if(ServiceExists(MS_AV_DRAWAVATAR)) + options.av_layout = (PopupAvLayout)DBGetContactSettingByte(0, MODULE, "AVLayout", PAV_RIGHT); + else + options.av_layout = PAV_NONE; + options.av_size = DBGetContactSettingDword(0, MODULE, "AVSize", 60); //tweety + options.text_indent = DBGetContactSettingDword(0, MODULE, "TextIndent", 22); + options.sidebar_width = DBGetContactSettingDword(0, MODULE, "SidebarWidth", 22); + options.show_no_focus = (DBGetContactSettingByte(0, MODULE, "ShowNoFocus", 1) == 1); + + int real_count = 0; + options.ds_list = 0; + DSListNode *ds_node; + options.ds_count = DBGetContactSettingWord(0, MODULE, "DSNumValues", 0); + for(int i = options.ds_count - 1; i >= 0; i--) { + ds_node = (DSListNode *)malloc(sizeof(DSListNode)); + if(LoadDS(&ds_node->ds, i)) { + ds_node->next = options.ds_list; + options.ds_list = ds_node; + real_count++; + } else free(ds_node); + } + options.ds_count = real_count; + + real_count = 0; + options.di_list = 0; + DIListNode *di_node; + options.di_count = DBGetContactSettingWord(0, MODULE, "DINumValues", 0); + for(int i = options.di_count - 1; i >= 0; i--) { + di_node = (DIListNode *)malloc(sizeof(DIListNode)); + if(LoadDI(&di_node->di, i)) { + di_node->next = options.di_list; + options.di_list = di_node; + real_count++; + } else free(di_node); + } + options.di_count = real_count; + + options.time_in = DBGetContactSettingWord(0, MODULE, "TimeIn", 750); + options.padding = DBGetContactSettingWord(0, MODULE, "Padding", 4); + options.av_padding = DBGetContactSettingWord(0, MODULE, "AvatarPadding", 6); + options.text_padding = DBGetContactSettingWord(0, MODULE, "TextPadding", 4); + options.pos = (PopupPosition)DBGetContactSettingByte(0, MODULE, "Position", (BYTE)PP_BOTTOMRIGHT); + options.min_width = DBGetContactSettingDword(0, MODULE, "MinWidth", 0); + options.min_height = DBGetContactSettingDword(0, MODULE, "MinHeight", 0); + + options.mouse_tollerance = DBGetContactSettingByte(0, MODULE, "MouseTollerance", (BYTE)GetSystemMetrics(SM_CXSMICON)); + options.status_bar_tips = (DBGetContactSettingByte(0, MODULE, "SBarTips", 1) == 1); + + // convert defunct last message and status message options to new 'sys' items, and remove the old settings + if(DBGetContactSettingByte(0, MODULE, "ShowLastMessage", 0)) { + DBDeleteContactSetting(0, MODULE, "ShowLastMessage"); + + // find end of list + di_node = options.di_list;
+ while(di_node && di_node->next) di_node = di_node->next;
+ + // last message item + if(di_node) { + di_node->next = (DIListNode *)malloc(sizeof(DIListNode)); + di_node = di_node->next;
+ } else {
+ options.di_list = (DIListNode *)malloc(sizeof(DIListNode));
+ di_node = options.di_list;
+ }
+ + _tcsncpy(di_node->di.label, _T("Last message: (%sys:last_msg_reltime% ago)"), LABEL_LEN); + _tcsncpy(di_node->di.value, _T("%sys:last_msg%"), VALUE_LEN); + di_node->di.line_above = di_node->di.value_newline = true; + di_node->next = 0; + options.di_count++;
+ } + + if(DBGetContactSettingByte(0, MODULE, "ShowStatusMessage", 0)) { + DBDeleteContactSetting(0, MODULE, "ShowStatusMessage"); +
+ // find end of list
+ di_node = options.di_list;
+ while(di_node && di_node->next) di_node = di_node->next;
+ + // status message item
+ if(di_node) { + di_node->next = (DIListNode *)malloc(sizeof(DIListNode));
+ di_node = di_node->next;
+ } else {
+ options.di_list = (DIListNode *)malloc(sizeof(DIListNode));
+ di_node = options.di_list;
+ }
+ + _tcsncpy(di_node->di.label, _T("Status message:"), LABEL_LEN); + _tcsncpy(di_node->di.value, _T("%sys:status_msg%"), VALUE_LEN); + di_node->di.line_above = di_node->di.value_newline = true; + di_node->next = 0; + options.di_count++;
+ } + + options.label_valign = DBGetContactSettingWord(0, MODULE, "LabelVAlign", DT_TOP /*DT_VCENTER*/); + options.label_halign = DBGetContactSettingWord(0, MODULE, "LabelHAlign", DT_LEFT); + options.value_valign = DBGetContactSettingWord(0, MODULE, "ValueVAlign", DT_TOP /*DT_VCENTER*/); + options.value_halign = DBGetContactSettingWord(0, MODULE, "ValueHAlign", DT_LEFT); + + if(options.ds_count == 0 && options.di_count == 0 && DBGetContactSettingByte(0, MODULE, "DefaultsCreated", 0) == 0) { + // set up some reasonable defaults - but only 'once' + CreateDefaultItems(); + DBWriteContactSettingByte(0, MODULE, "DefaultsCreated", 1); + SaveOptions(); + } + +} + +static BOOL CALLBACK DlgProcAddItem(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam) { + DisplayItem *di = (DisplayItem *)GetWindowLong(hwndDlg, GWL_USERDATA); + + switch ( msg ) { + case WM_INITDIALOG: + TranslateDialogDefault( hwndDlg ); + di = (DisplayItem *)lParam; + SetWindowLong(hwndDlg, GWL_USERDATA, (LONG)di); + + SetDlgItemText(hwndDlg, IDC_ED_LABEL, di->label); + SetDlgItemText(hwndDlg, IDC_ED_VALUE, di->value); + + CheckDlgButton(hwndDlg, IDC_CHK_LINEABOVE, di->line_above ? TRUE : FALSE); + CheckDlgButton(hwndDlg, IDC_CHK_VALNEWLINE, di->value_newline ? TRUE : FALSE); + SetFocus(GetDlgItem(hwndDlg, IDC_ED_LABEL)); + return TRUE; + case WM_COMMAND: + if(HIWORD(wParam) == BN_CLICKED) { + switch(LOWORD(wParam)) { + case IDOK: + GetDlgItemText(hwndDlg, IDC_ED_LABEL, di->label, LABEL_LEN); + GetDlgItemText(hwndDlg, IDC_ED_VALUE, di->value, VALUE_LEN); + + di->line_above = (IsDlgButtonChecked(hwndDlg, IDC_CHK_LINEABOVE) ? true : false); + di->value_newline = (IsDlgButtonChecked(hwndDlg, IDC_CHK_VALNEWLINE) ? true : false); + + EndDialog(hwndDlg, IDOK); + return TRUE; + case IDCANCEL: + EndDialog(hwndDlg, IDCANCEL); + return TRUE; + } + } + break; + } + + return 0; +} + +static BOOL CALLBACK DlgProcAddSubst(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam) { + DisplaySubst *ds = (DisplaySubst *)GetWindowLong(hwndDlg, GWL_USERDATA); + + switch ( msg ) { + case WM_INITDIALOG: + TranslateDialogDefault( hwndDlg ); + ds = (DisplaySubst *)lParam; + SetWindowLong(hwndDlg, GWL_USERDATA, (LONG)ds); + + SetDlgItemText(hwndDlg, IDC_ED_LABEL, ds->name); + + switch(ds->type) { + case DVT_PROTODB: + CheckDlgButton(hwndDlg, IDC_CHK_PROTOMOD, TRUE); + SetDlgItemTextA(hwndDlg, IDC_ED_SETTING, ds->setting_name); + break; + case DVT_DB: + SetDlgItemTextA(hwndDlg, IDC_ED_MODULE, ds->module_name); + SetDlgItemTextA(hwndDlg, IDC_ED_SETTING, ds->setting_name); + break; + } + + { + int index, id; + for(int i = 0; i < num_tfuncs; i++) { + index = SendDlgItemMessage(hwndDlg, IDC_CMB_TRANSLATE, CB_ADDSTRING, (WPARAM)-1, (LPARAM)TranslateTS(translations[i].name)); + SendDlgItemMessage(hwndDlg, IDC_CMB_TRANSLATE, CB_SETITEMDATA, index, (LPARAM)translations[i].id); + } + for(int i = 0; i < num_tfuncs; i++) { + id = SendDlgItemMessage(hwndDlg, IDC_CMB_TRANSLATE, CB_GETITEMDATA, i, 0); + if(id == ds->translate_func_id) + SendDlgItemMessage(hwndDlg, IDC_CMB_TRANSLATE, CB_SETCURSEL, i, 0); + } + + } + + SendMessage(hwndDlg, WMU_ENABLE_MODULE_ENTRY, 0, 0); + SetFocus(GetDlgItem(hwndDlg, IDC_ED_LABEL)); + return TRUE; + case WMU_ENABLE_MODULE_ENTRY: + { + HWND hw = GetDlgItem(hwndDlg, IDC_CHK_PROTOMOD); + EnableWindow(hw, TRUE); + hw = GetDlgItem(hwndDlg, IDC_ED_MODULE); + EnableWindow(hw, !IsDlgButtonChecked(hwndDlg, IDC_CHK_PROTOMOD)); + hw = GetDlgItem(hwndDlg, IDC_ED_SETTING); + EnableWindow(hw, TRUE); + } + return TRUE; + case WM_COMMAND: + if ( HIWORD( wParam ) == CBN_SELCHANGE) { + return TRUE; + } else if(HIWORD(wParam) == BN_CLICKED) { + switch(LOWORD(wParam)) { + case IDC_CHK_PROTOMOD: + SendMessage(hwndDlg, WMU_ENABLE_MODULE_ENTRY, 0, 0); + break; + case IDOK: + GetDlgItemText(hwndDlg, IDC_ED_LABEL, ds->name, LABEL_LEN); + if(ds->name[0] == 0) { + MessageBox(hwndDlg, TranslateT("You must enter a label"), TranslateT("Invalid Substitution"), MB_OK | MB_ICONWARNING); + return TRUE; + } + + if(IsDlgButtonChecked(hwndDlg, IDC_CHK_PROTOMOD)) + ds->type = DVT_PROTODB; + else { + ds->type = DVT_DB; + GetDlgItemTextA(hwndDlg, IDC_ED_MODULE, ds->module_name, MODULE_NAME_LEN); + } + GetDlgItemTextA(hwndDlg, IDC_ED_SETTING, ds->setting_name, SETTING_NAME_LEN); + + { + int sel = SendDlgItemMessage(hwndDlg, IDC_CMB_TRANSLATE, CB_GETCURSEL, 0, 0); + ds->translate_func_id = SendDlgItemMessage(hwndDlg, IDC_CMB_TRANSLATE, CB_GETITEMDATA, sel, 0); + } + + EndDialog(hwndDlg, IDOK); + return TRUE; + case IDCANCEL: + EndDialog(hwndDlg, IDCANCEL); + return TRUE; + } + } + break; + } + + return 0; +} + +static BOOL CALLBACK DlgProcOpts2(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam) { + + switch ( msg ) { + case WM_INITDIALOG: + TranslateDialogDefault( hwndDlg ); + { + int index; + DIListNode *di_node = options.di_list, *di_value; + while(di_node) { + di_value = (DIListNode *)malloc(sizeof(DIListNode)); + *di_value = *di_node; + if(di_value->di.label[0] == 0) + index = SendDlgItemMessage(hwndDlg, IDC_LST_ITEMS, LB_ADDSTRING, 0, (LPARAM)TranslateT("<No Label>")); + else + index = SendDlgItemMessage(hwndDlg, IDC_LST_ITEMS, LB_ADDSTRING, 0, (LPARAM)di_value->di.label); + SendDlgItemMessage(hwndDlg, IDC_LST_ITEMS, LB_SETITEMDATA, index, (LPARAM)di_value); + + di_node = di_node->next; + } + + DSListNode *ds_node = options.ds_list, *ds_value; + while(ds_node) { + ds_value = (DSListNode *)malloc(sizeof(DSListNode)); + *ds_value = *ds_node; + index = SendDlgItemMessage(hwndDlg, IDC_LST_SUBST, LB_ADDSTRING, 0, (LPARAM)ds_value->ds.name); + SendDlgItemMessage(hwndDlg, IDC_LST_SUBST, LB_SETITEMDATA, index, (LPARAM)ds_value); + + ds_node = ds_node->next; + } + } + + SendMessage(hwndDlg, WMU_ENABLE_LIST_BUTTONS, 0, 0); + return FALSE; + case WMU_ENABLE_LIST_BUTTONS: + { + int sel = SendDlgItemMessage(hwndDlg, IDC_LST_ITEMS, LB_GETCURSEL, 0, 0); + if(sel == -1) { + HWND hw = GetDlgItem(hwndDlg, IDC_BTN_REMOVE); + EnableWindow(hw, FALSE); + hw = GetDlgItem(hwndDlg, IDC_BTN_UP); + EnableWindow(hw, FALSE); + hw = GetDlgItem(hwndDlg, IDC_BTN_DOWN); + EnableWindow(hw, FALSE); + hw = GetDlgItem(hwndDlg, IDC_BTN_EDIT); + EnableWindow(hw, FALSE); + } else { + int count = SendDlgItemMessage(hwndDlg, IDC_LST_ITEMS, LB_GETCOUNT, 0, 0); + HWND hw = GetDlgItem(hwndDlg, IDC_BTN_REMOVE); + EnableWindow(hw, TRUE); + hw = GetDlgItem(hwndDlg, IDC_BTN_UP); + EnableWindow(hw, sel > 0); + hw = GetDlgItem(hwndDlg, IDC_BTN_DOWN); + EnableWindow(hw, sel < count - 1); + hw = GetDlgItem(hwndDlg, IDC_BTN_EDIT); + EnableWindow(hw, TRUE); + } + + sel = SendDlgItemMessage(hwndDlg, IDC_LST_SUBST, LB_GETCURSEL, 0, 0); + if(sel == -1) { + HWND hw = GetDlgItem(hwndDlg, IDC_BTN_REMOVE2); + EnableWindow(hw, FALSE); + hw = GetDlgItem(hwndDlg, IDC_BTN_EDIT2); + EnableWindow(hw, FALSE); + } else { + HWND hw = GetDlgItem(hwndDlg, IDC_BTN_REMOVE2); + EnableWindow(hw, TRUE); + hw = GetDlgItem(hwndDlg, IDC_BTN_EDIT2); + EnableWindow(hw, TRUE); + } + } + return TRUE; + case WM_COMMAND: + if ( HIWORD( wParam ) == LBN_SELCHANGE && LOWORD(wParam) == IDC_LST_ITEMS) { + SendMessage(hwndDlg, WMU_ENABLE_LIST_BUTTONS, 0, 0); + } else if ( HIWORD( wParam ) == LBN_SELCHANGE && LOWORD(wParam) == IDC_LST_SUBST) { + SendMessage(hwndDlg, WMU_ENABLE_LIST_BUTTONS, 0, 0); + } else if ( HIWORD( wParam ) == CBN_SELCHANGE) { + SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0); + } else if ( HIWORD( wParam ) == EN_CHANGE && ( HWND )lParam == GetFocus()) { + SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0); + } else if ( HIWORD( wParam) == LBN_DBLCLK && LOWORD(wParam) == IDC_LST_ITEMS) { + { + DIListNode *value; + int sel = SendDlgItemMessage(hwndDlg, IDC_LST_ITEMS, LB_GETCURSEL, 0, 0); + if(sel != -1) { + value = (DIListNode *)SendDlgItemMessage(hwndDlg, IDC_LST_ITEMS, LB_GETITEMDATA, sel, 0); + if(DialogBoxParam(hInst, MAKEINTRESOURCE(IDD_ITEM), hwndDlg, DlgProcAddItem, (LPARAM)&value->di) == IDOK) { + SendDlgItemMessage(hwndDlg, IDC_LST_ITEMS, LB_DELETESTRING, (WPARAM)sel, 0); + + SendDlgItemMessage(hwndDlg, IDC_LST_ITEMS, LB_INSERTSTRING, sel, (LPARAM)value->di.label); + SendDlgItemMessage(hwndDlg, IDC_LST_ITEMS, LB_SETITEMDATA, sel, (LPARAM)value); + + SendDlgItemMessage(hwndDlg, IDC_LST_ITEMS, LB_SETCURSEL, sel, 0); + + SendMessage(hwndDlg, WMU_ENABLE_LIST_BUTTONS, 0, 0); + SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0); + } + } + } + } else if ( HIWORD( wParam) == LBN_DBLCLK && LOWORD(wParam) == IDC_LST_SUBST) { + { + DSListNode *value; + int sel = SendDlgItemMessage(hwndDlg, IDC_LST_SUBST, LB_GETCURSEL, 0, 0); + if(sel != -1) { + value = (DSListNode *)SendDlgItemMessage(hwndDlg, IDC_LST_SUBST, LB_GETITEMDATA, sel, 0); + if(DialogBoxParam(hInst, MAKEINTRESOURCE(IDD_SUBST), hwndDlg, DlgProcAddSubst, (LPARAM)&value->ds) == IDOK) { + SendDlgItemMessage(hwndDlg, IDC_LST_SUBST, LB_DELETESTRING, (WPARAM)sel, 0); + + sel = SendDlgItemMessage(hwndDlg, IDC_LST_SUBST, LB_ADDSTRING, 0, (LPARAM)value->ds.name); + SendDlgItemMessage(hwndDlg, IDC_LST_SUBST, LB_SETITEMDATA, sel, (LPARAM)value); + + SendDlgItemMessage(hwndDlg, IDC_LST_SUBST, LB_SETCURSEL, sel, 0); + + SendMessage(hwndDlg, WMU_ENABLE_LIST_BUTTONS, 0, 0); + SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0); + } + } + } + } else if ( HIWORD( wParam ) == BN_CLICKED ) { + switch(LOWORD(wParam)) { + case IDC_BTN_ADD: + { + DIListNode *value = (DIListNode *)malloc(sizeof(DIListNode)); + memset(value, 0, sizeof(DIListNode)); + if(DialogBoxParam(hInst, MAKEINTRESOURCE(IDD_ITEM), hwndDlg, DlgProcAddItem, (LPARAM)&value->di) == IDOK) { + int sel = SendDlgItemMessage(hwndDlg, IDC_LST_ITEMS, LB_GETCURSEL, 0, 0), index = sel + 1; + if(value->di.label[0] == 0) + SendDlgItemMessage(hwndDlg, IDC_LST_ITEMS, LB_INSERTSTRING, index, (LPARAM)TranslateT("<No Label>")); + else + SendDlgItemMessage(hwndDlg, IDC_LST_ITEMS, LB_INSERTSTRING, index, (LPARAM)value->di.label); + SendDlgItemMessage(hwndDlg, IDC_LST_ITEMS, LB_SETITEMDATA, index, (LPARAM)value); + SendDlgItemMessage(hwndDlg, IDC_LST_ITEMS, LB_SETCURSEL, index, 0); + SendMessage(hwndDlg, WMU_ENABLE_LIST_BUTTONS, 0, 0); + SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0); + } + + } + return TRUE; + case IDC_BTN_REMOVE: + { + int sel = SendDlgItemMessage(hwndDlg, IDC_LST_ITEMS, LB_GETCURSEL, 0, 0); + if(sel != -1) { + DIListNode *value = (DIListNode *)SendDlgItemMessage(hwndDlg, IDC_LST_ITEMS, LB_GETITEMDATA, sel, 0); + SendDlgItemMessage(hwndDlg, IDC_LST_ITEMS, LB_DELETESTRING, (WPARAM)sel, 0); + free(value); + SendMessage(hwndDlg, WMU_ENABLE_LIST_BUTTONS, 0, 0); + SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0); + } + } + return TRUE; + case IDC_BTN_UP: + { + DIListNode *value_up; + int sel = SendDlgItemMessage(hwndDlg, IDC_LST_ITEMS, LB_GETCURSEL, 0, 0); + if(sel > 0) { + value_up = (DIListNode *)SendDlgItemMessage(hwndDlg, IDC_LST_ITEMS, LB_GETITEMDATA, sel - 1, 0); + SendDlgItemMessage(hwndDlg, IDC_LST_ITEMS, LB_DELETESTRING, (WPARAM)sel - 1, 0); + + SendDlgItemMessage(hwndDlg, IDC_LST_ITEMS, LB_INSERTSTRING, sel, (LPARAM)value_up->di.label); + SendDlgItemMessage(hwndDlg, IDC_LST_ITEMS, LB_SETITEMDATA, sel, (LPARAM)value_up); + + SendDlgItemMessage(hwndDlg, IDC_LST_ITEMS, LB_SETCURSEL, sel - 1, 0); + } + } + SendMessage(hwndDlg, WMU_ENABLE_LIST_BUTTONS, 0, 0); + SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0); + return TRUE; + case IDC_BTN_DOWN: + { + DIListNode *value_down; + int sel = SendDlgItemMessage(hwndDlg, IDC_LST_ITEMS, LB_GETCURSEL, 0, 0); + int count = SendDlgItemMessage(hwndDlg, IDC_LST_ITEMS, LB_GETCOUNT, 0, 0); + if(sel < count - 1) { + value_down = (DIListNode *)SendDlgItemMessage(hwndDlg, IDC_LST_ITEMS, LB_GETITEMDATA, sel + 1, 0); + SendDlgItemMessage(hwndDlg, IDC_LST_ITEMS, LB_DELETESTRING, (WPARAM)sel + 1, 0); + + SendDlgItemMessage(hwndDlg, IDC_LST_ITEMS, LB_INSERTSTRING, sel, (LPARAM)value_down->di.label); + SendDlgItemMessage(hwndDlg, IDC_LST_ITEMS, LB_SETITEMDATA, sel, (LPARAM)value_down); + + SendDlgItemMessage(hwndDlg, IDC_LST_ITEMS, LB_SETCURSEL, sel + 1, 0); + } + } + SendMessage(hwndDlg, WMU_ENABLE_LIST_BUTTONS, 0, 0); + SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0); + return TRUE; + case IDC_BTN_EDIT: + { + DIListNode *value; + int sel = SendDlgItemMessage(hwndDlg, IDC_LST_ITEMS, LB_GETCURSEL, 0, 0); + if(sel != -1) { + value = (DIListNode *)SendDlgItemMessage(hwndDlg, IDC_LST_ITEMS, LB_GETITEMDATA, sel, 0); + if(DialogBoxParam(hInst, MAKEINTRESOURCE(IDD_ITEM), hwndDlg, DlgProcAddItem, (LPARAM)&value->di) == IDOK) { + SendDlgItemMessage(hwndDlg, IDC_LST_ITEMS, LB_DELETESTRING, (WPARAM)sel, 0); + + if(value->di.label[0] == 0) + SendDlgItemMessage(hwndDlg, IDC_LST_ITEMS, LB_INSERTSTRING, sel, (LPARAM)TranslateT("<No Label>")); + else + SendDlgItemMessage(hwndDlg, IDC_LST_ITEMS, LB_INSERTSTRING, sel, (LPARAM)value->di.label); + SendDlgItemMessage(hwndDlg, IDC_LST_ITEMS, LB_SETITEMDATA, sel, (LPARAM)value); + + SendDlgItemMessage(hwndDlg, IDC_LST_ITEMS, LB_SETCURSEL, sel, 0); + + SendMessage(hwndDlg, WMU_ENABLE_LIST_BUTTONS, 0, 0); + SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0); + } + } + } + return TRUE; + + case IDC_BTN_ADD2: + { + DSListNode *value = (DSListNode *)malloc(sizeof(DSListNode)); + memset(value, 0, sizeof(DSListNode)); + if(DialogBoxParam(hInst, MAKEINTRESOURCE(IDD_SUBST), hwndDlg, DlgProcAddSubst, (LPARAM)&value->ds) == IDOK) { + int index = SendDlgItemMessage(hwndDlg, IDC_LST_SUBST, LB_ADDSTRING, 0, (LPARAM)value->ds.name); + SendDlgItemMessage(hwndDlg, IDC_LST_SUBST, LB_SETITEMDATA, index, (LPARAM)value); + SendDlgItemMessage(hwndDlg, IDC_LST_SUBST, LB_SETCURSEL, index, 0); + SendMessage(hwndDlg, WMU_ENABLE_LIST_BUTTONS, 0, 0); + SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0); + } + + } + return TRUE; + case IDC_BTN_REMOVE2: + { + int sel = SendDlgItemMessage(hwndDlg, IDC_LST_SUBST, LB_GETCURSEL, 0, 0); + if(sel != -1) { + DSListNode *value = (DSListNode *)SendDlgItemMessage(hwndDlg, IDC_LST_SUBST, LB_GETITEMDATA, sel, 0); + SendDlgItemMessage(hwndDlg, IDC_LST_SUBST, LB_DELETESTRING, (WPARAM)sel, 0); + free(value); + SendMessage(hwndDlg, WMU_ENABLE_LIST_BUTTONS, 0, 0); + SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0); + } + } + return TRUE; + case IDC_BTN_EDIT2: + { + DSListNode *value; + int sel = SendDlgItemMessage(hwndDlg, IDC_LST_SUBST, LB_GETCURSEL, 0, 0); + if(sel != -1) { + value = (DSListNode *)SendDlgItemMessage(hwndDlg, IDC_LST_SUBST, LB_GETITEMDATA, sel, 0); + if(DialogBoxParam(hInst, MAKEINTRESOURCE(IDD_SUBST), hwndDlg, DlgProcAddSubst, (LPARAM)&value->ds) == IDOK) { + SendDlgItemMessage(hwndDlg, IDC_LST_SUBST, LB_DELETESTRING, (WPARAM)sel, 0); + + sel = SendDlgItemMessage(hwndDlg, IDC_LST_SUBST, LB_ADDSTRING, 0, (LPARAM)value->ds.name); + SendDlgItemMessage(hwndDlg, IDC_LST_SUBST, LB_SETITEMDATA, sel, (LPARAM)value); + + SendDlgItemMessage(hwndDlg, IDC_LST_SUBST, LB_SETCURSEL, sel, 0); + + SendMessage(hwndDlg, WMU_ENABLE_LIST_BUTTONS, 0, 0); + SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0); + } + } + } + return TRUE; + default: + SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0); + return TRUE; + } + } + break; + case WM_NOTIFY: + if (((LPNMHDR)lParam)->code == (unsigned)PSN_APPLY ) { + DIListNode *di_node; + while(options.di_list) { + di_node = options.di_list; + options.di_list = options.di_list->next; + free(di_node); + } + + DIListNode *di_value; + options.di_count = SendDlgItemMessage(hwndDlg, IDC_LST_ITEMS, LB_GETCOUNT, 0, 0); + for(int i = options.di_count - 1; i >= 0; i--) { + di_node = (DIListNode *)SendDlgItemMessage(hwndDlg, IDC_LST_ITEMS, LB_GETITEMDATA, i, 0); + di_value = (DIListNode *)malloc(sizeof(DIListNode)); + *di_value = *di_node; + + di_value->next = options.di_list; + options.di_list = di_value; + } + + DSListNode *ds_node; + while(options.ds_list) { + ds_node = options.ds_list; + options.ds_list = options.ds_list->next; + free(ds_node); + } + + DSListNode *ds_value; + options.ds_count = SendDlgItemMessage(hwndDlg, IDC_LST_SUBST, LB_GETCOUNT, 0, 0); + for(int i = options.ds_count - 1; i >= 0; i--) { + ds_node = (DSListNode *)SendDlgItemMessage(hwndDlg, IDC_LST_SUBST, LB_GETITEMDATA, i, 0); + ds_value = (DSListNode *)malloc(sizeof(DSListNode)); + *ds_value = *ds_node; + + ds_value->next = options.ds_list; + options.ds_list = ds_value; + } + + SaveOptions(); + return TRUE; + } + break; + case WM_DESTROY: + { + DIListNode *di_value; + int count = SendDlgItemMessage(hwndDlg, IDC_LST_ITEMS, LB_GETCOUNT, 0, 0); + for(int i = 0; i < count; i++) { + di_value = (DIListNode *)SendDlgItemMessage(hwndDlg, IDC_LST_ITEMS, LB_GETITEMDATA, i, 0); + free(di_value); + } + DSListNode *ds_value; + count = SendDlgItemMessage(hwndDlg, IDC_LST_SUBST, LB_GETCOUNT, 0, 0); + for(int i = 0; i < count; i++) { + ds_value = (DSListNode *)SendDlgItemMessage(hwndDlg, IDC_LST_SUBST, LB_GETITEMDATA, i, 0); + free(ds_value); + } + } + break; + } + + return 0; +} + + +static BOOL CALLBACK DlgProcOpts1(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam) { + + switch ( msg ) { + case WM_INITDIALOG: + TranslateDialogDefault( hwndDlg ); + + CheckDlgButton(hwndDlg, IDC_CHK_NOFOCUS, options.show_no_focus ? TRUE : FALSE); + CheckDlgButton(hwndDlg, IDC_CHK_SBAR, options.status_bar_tips ? TRUE : FALSE); + + SendDlgItemMessage(hwndDlg, IDC_CMB_ICON, CB_ADDSTRING, 0, (LPARAM)TranslateT("Icon on left")); + SendDlgItemMessage(hwndDlg, IDC_CMB_ICON, CB_ADDSTRING, 0, (LPARAM)TranslateT("Icon on right")); + SendDlgItemMessage(hwndDlg, IDC_CMB_ICON, CB_ADDSTRING, 0, (LPARAM)TranslateT("No icon")); + SendDlgItemMessage(hwndDlg, IDC_CMB_ICON, CB_ADDSTRING, 0, (LPARAM)TranslateT("No title")); + SendDlgItemMessage(hwndDlg, IDC_CMB_ICON, CB_SETCURSEL, (int)options.title_layout, 0); + + SendDlgItemMessage(hwndDlg, IDC_CMB_POS, CB_ADDSTRING, 0, (LPARAM)TranslateT("Bottom right")); + SendDlgItemMessage(hwndDlg, IDC_CMB_POS, CB_ADDSTRING, 0, (LPARAM)TranslateT("Bottom left")); + SendDlgItemMessage(hwndDlg, IDC_CMB_POS, CB_ADDSTRING, 0, (LPARAM)TranslateT("Top right")); + SendDlgItemMessage(hwndDlg, IDC_CMB_POS, CB_ADDSTRING, 0, (LPARAM)TranslateT("Top left")); + SendDlgItemMessage(hwndDlg, IDC_CMB_POS, CB_SETCURSEL, (int)options.pos, 0); + + SendDlgItemMessage(hwndDlg, IDC_CMB_LV, CB_ADDSTRING, 0, (LPARAM)TranslateT("Top")); + SendDlgItemMessage(hwndDlg, IDC_CMB_LV, CB_ADDSTRING, 0, (LPARAM)TranslateT("Centre")); + SendDlgItemMessage(hwndDlg, IDC_CMB_LV, CB_ADDSTRING, 0, (LPARAM)TranslateT("Bottom"));
+ switch(options.label_valign) {
+ case DT_TOP: SendDlgItemMessage(hwndDlg, IDC_CMB_LV, CB_SETCURSEL, 0, 0); break; + case DT_VCENTER: SendDlgItemMessage(hwndDlg, IDC_CMB_LV, CB_SETCURSEL, 1, 0); break; + case DT_BOTTOM: SendDlgItemMessage(hwndDlg, IDC_CMB_LV, CB_SETCURSEL, 2, 0); break;
+ }
+ + SendDlgItemMessage(hwndDlg, IDC_CMB_VV, CB_ADDSTRING, 0, (LPARAM)TranslateT("Top")); + SendDlgItemMessage(hwndDlg, IDC_CMB_VV, CB_ADDSTRING, 0, (LPARAM)TranslateT("Centre")); + SendDlgItemMessage(hwndDlg, IDC_CMB_VV, CB_ADDSTRING, 0, (LPARAM)TranslateT("Bottom")); + switch(options.value_valign) {
+ case DT_TOP: SendDlgItemMessage(hwndDlg, IDC_CMB_VV, CB_SETCURSEL, 0, 0); break; + case DT_VCENTER: SendDlgItemMessage(hwndDlg, IDC_CMB_VV, CB_SETCURSEL, 1, 0); break; + case DT_BOTTOM: SendDlgItemMessage(hwndDlg, IDC_CMB_VV, CB_SETCURSEL, 2, 0); break;
+ }
+
+ SendDlgItemMessage(hwndDlg, IDC_CMB_LH, CB_ADDSTRING, 0, (LPARAM)TranslateT("Left")); + SendDlgItemMessage(hwndDlg, IDC_CMB_LH, CB_ADDSTRING, 0, (LPARAM)TranslateT("Right")); + switch(options.label_halign) {
+ case DT_LEFT: SendDlgItemMessage(hwndDlg, IDC_CMB_LH, CB_SETCURSEL, 0, 0); break; + case DT_RIGHT: SendDlgItemMessage(hwndDlg, IDC_CMB_LH, CB_SETCURSEL, 1, 0); break;
+ }
+ + SendDlgItemMessage(hwndDlg, IDC_CMB_VH, CB_ADDSTRING, 0, (LPARAM)TranslateT("Left")); + SendDlgItemMessage(hwndDlg, IDC_CMB_VH, CB_ADDSTRING, 0, (LPARAM)TranslateT("Right")); + switch(options.value_halign) {
+ case DT_LEFT: SendDlgItemMessage(hwndDlg, IDC_CMB_VH, CB_SETCURSEL, 0, 0); break; + case DT_RIGHT: SendDlgItemMessage(hwndDlg, IDC_CMB_VH, CB_SETCURSEL, 1, 0); break;
+ }
+ + SendDlgItemMessage(hwndDlg, IDC_CMB_AV, CB_ADDSTRING, 0, (LPARAM)TranslateT("No avatar")); + if(ServiceExists(MS_AV_DRAWAVATAR)) { + SendDlgItemMessage(hwndDlg, IDC_CMB_AV, CB_ADDSTRING, 0, (LPARAM)TranslateT("Left avatar")); + SendDlgItemMessage(hwndDlg, IDC_CMB_AV, CB_ADDSTRING, 0, (LPARAM)TranslateT("Right avatar")); + } else { + HWND hw = GetDlgItem(hwndDlg, IDC_CMB_AV); + EnableWindow(hw, FALSE); + hw = GetDlgItem(hwndDlg, IDC_SPIN_AVSIZE); + EnableWindow(hw, FALSE); + hw = GetDlgItem(hwndDlg, IDC_ED_AVSIZE); + EnableWindow(hw, FALSE); + } + SendDlgItemMessage(hwndDlg, IDC_CMB_AV, CB_SETCURSEL, (int)options.av_layout, 0); + + SendDlgItemMessage(hwndDlg, IDC_SPIN_WIDTH, UDM_SETRANGE, 0, (LPARAM)MAKELONG(2048, 16)); + SendDlgItemMessage(hwndDlg, IDC_SPIN_MINWIDTH, UDM_SETRANGE, 0, (LPARAM)MAKELONG(2048, 16)); + SendDlgItemMessage(hwndDlg, IDC_SPIN_MAXHEIGHT, UDM_SETRANGE, 0, (LPARAM)MAKELONG(2048, 16)); + SendDlgItemMessage(hwndDlg, IDC_SPIN_MINHEIGHT, UDM_SETRANGE, 0, (LPARAM)MAKELONG(2048, 16)); + SendDlgItemMessage(hwndDlg, IDC_SPIN_TRANS, UDM_SETRANGE, 0, (LPARAM)MAKELONG(99, 0)); + SendDlgItemMessage(hwndDlg, IDC_SPIN_AVSIZE, UDM_SETRANGE, 0, (LPARAM)MAKELONG(100, 16)); + SendDlgItemMessage(hwndDlg, IDC_SPIN_INDENT, UDM_SETRANGE, 0, (LPARAM)MAKELONG(400, 0)); + SendDlgItemMessage(hwndDlg, IDC_SPIN_PADDING, UDM_SETRANGE, 0, (LPARAM)MAKELONG(128, 0)); + SendDlgItemMessage(hwndDlg, IDC_SPIN_TEXTPADDING, UDM_SETRANGE, 0, (LPARAM)MAKELONG(128, 0)); + SendDlgItemMessage(hwndDlg, IDC_SPIN_AVPADDING, UDM_SETRANGE, 0, (LPARAM)MAKELONG(128, 0)); + SendDlgItemMessage(hwndDlg, IDC_SPIN_HOVER, UDM_SETRANGE, 0, (LPARAM)MAKELONG(5000, 5)); + SendDlgItemMessage(hwndDlg, IDC_SPIN_SBWIDTH, UDM_SETRANGE, 0, (LPARAM)MAKELONG(2048, 0)); + + SetDlgItemInt(hwndDlg, IDC_ED_WIDTH, options.win_width, FALSE); + SetDlgItemInt(hwndDlg, IDC_ED_MAXHEIGHT, options.win_max_height, FALSE); + SetDlgItemInt(hwndDlg, IDC_ED_MINWIDTH, options.min_width, FALSE); + SetDlgItemInt(hwndDlg, IDC_ED_MINHEIGHT, options.min_height, FALSE); + SetDlgItemInt(hwndDlg, IDC_ED_AVSIZE, options.av_size, FALSE); + SetDlgItemInt(hwndDlg, IDC_ED_INDENT, options.text_indent, FALSE); + SetDlgItemInt(hwndDlg, IDC_ED_PADDING, options.padding, FALSE); + SetDlgItemInt(hwndDlg, IDC_ED_TEXTPADDING, options.text_padding, FALSE); + SetDlgItemInt(hwndDlg, IDC_ED_AVPADDING, options.av_padding, FALSE); + SetDlgItemInt(hwndDlg, IDC_ED_HOVER, options.time_in, FALSE); + SetDlgItemInt(hwndDlg, IDC_ED_SBWIDTH, options.sidebar_width, FALSE); + + SetDlgItemInt(hwndDlg, IDC_ED_TRANS, options.opacity, FALSE); + CheckDlgButton(hwndDlg, IDC_CHK_BORDER, options.border); + CheckDlgButton(hwndDlg, IDC_CHK_ROUNDCORNERS, options.round); + CheckDlgButton(hwndDlg, IDC_CHK_ROUNDCORNERSAV, options.av_round); + + CheckDlgButton(hwndDlg, IDC_CHK_ANIMATE, options.animate); + CheckDlgButton(hwndDlg, IDC_CHK_SHADOW, options.drop_shadow); + CheckDlgButton(hwndDlg, IDC_CHK_TRANSBG, options.trans_bg); + + return FALSE; + case WM_COMMAND: + if ( HIWORD( wParam ) == CBN_SELCHANGE) { + SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0); + } else if ( HIWORD( wParam ) == EN_CHANGE && ( HWND )lParam == GetFocus()) { + SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0); + } else if ( HIWORD( wParam ) == BN_CLICKED ) { + SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0); + } + break; + case WM_NOTIFY: + if (((LPNMHDR)lParam)->code == (unsigned)PSN_APPLY ) { + BOOL trans; + int new_val; + new_val = GetDlgItemInt(hwndDlg, IDC_ED_WIDTH, &trans, FALSE); + if(trans) options.win_width = new_val; + new_val = GetDlgItemInt(hwndDlg, IDC_ED_MINWIDTH, &trans, FALSE); + if(trans) options.min_width = new_val; + new_val = GetDlgItemInt(hwndDlg, IDC_ED_MAXHEIGHT, &trans, FALSE); + if(trans) options.win_max_height = new_val; + new_val = GetDlgItemInt(hwndDlg, IDC_ED_MINHEIGHT, &trans, FALSE); + if(trans) options.min_height = new_val; + new_val = GetDlgItemInt(hwndDlg, IDC_ED_AVSIZE, &trans, FALSE); + if(trans) options.av_size = new_val; + new_val = GetDlgItemInt(hwndDlg, IDC_ED_INDENT, &trans, FALSE); + if(trans) options.text_indent = new_val; + new_val = GetDlgItemInt(hwndDlg, IDC_ED_PADDING, &trans, FALSE); + if(trans) options.padding = new_val; + new_val = GetDlgItemInt(hwndDlg, IDC_ED_TEXTPADDING, &trans, FALSE); + if(trans) options.text_padding = new_val; + new_val = GetDlgItemInt(hwndDlg, IDC_ED_AVPADDING, &trans, FALSE); + if(trans) options.av_padding = new_val; + new_val = GetDlgItemInt(hwndDlg, IDC_ED_HOVER, &trans, FALSE); + if(trans) options.time_in = new_val; + new_val = GetDlgItemInt(hwndDlg, IDC_ED_SBWIDTH, &trans, FALSE); + if(trans) options.sidebar_width = new_val; + + options.title_layout = (PopupTitleLayout)SendDlgItemMessage(hwndDlg, IDC_CMB_ICON, CB_GETCURSEL, 0, 0); + options.av_layout = (PopupAvLayout)SendDlgItemMessage(hwndDlg, IDC_CMB_AV, CB_GETCURSEL, 0, 0); + options.pos = (PopupPosition)SendDlgItemMessage(hwndDlg, IDC_CMB_POS, CB_GETCURSEL, 0, 0); + + new_val = GetDlgItemInt(hwndDlg, IDC_ED_TRANS, &trans, FALSE); + if(trans) options.opacity = new_val; + options.border = IsDlgButtonChecked(hwndDlg, IDC_CHK_BORDER) && IsWindowEnabled(GetDlgItem(hwndDlg, IDC_CHK_BORDER)) ? true : false; + options.round = IsDlgButtonChecked(hwndDlg, IDC_CHK_ROUNDCORNERS) && IsWindowEnabled(GetDlgItem(hwndDlg, IDC_CHK_ROUNDCORNERS)) ? true : false; + options.av_round = IsDlgButtonChecked(hwndDlg, IDC_CHK_ROUNDCORNERSAV) && IsWindowEnabled(GetDlgItem(hwndDlg, IDC_CHK_ROUNDCORNERSAV)) ? true : false; + options.animate = IsDlgButtonChecked(hwndDlg, IDC_CHK_ANIMATE) ? true : false; + options.drop_shadow = IsDlgButtonChecked(hwndDlg, IDC_CHK_SHADOW) ? true : false; + options.trans_bg = IsDlgButtonChecked(hwndDlg, IDC_CHK_TRANSBG) ? true : false; + + options.show_no_focus = IsDlgButtonChecked(hwndDlg, IDC_CHK_NOFOCUS) ? true : false; + options.status_bar_tips = IsDlgButtonChecked(hwndDlg, IDC_CHK_SBAR) ? true : false; + + switch(SendDlgItemMessage(hwndDlg, IDC_CMB_LV, CB_GETCURSEL, 0, 0)) { + case 0: options.label_valign = DT_TOP; break; + case 1: options.label_valign = DT_VCENTER; break; + case 2: options.label_valign = DT_BOTTOM; break; + } + switch(SendDlgItemMessage(hwndDlg, IDC_CMB_VV, CB_GETCURSEL, 0, 0)) { + case 0: options.value_valign = DT_TOP; break; + case 1: options.value_valign = DT_VCENTER; break; + case 2: options.value_valign = DT_BOTTOM; break; + } + + switch(SendDlgItemMessage(hwndDlg, IDC_CMB_LH, CB_GETCURSEL, 0, 0)) { + case 0: options.label_halign = DT_LEFT; break; + case 1: options.label_halign = DT_RIGHT; break; + } + switch(SendDlgItemMessage(hwndDlg, IDC_CMB_VH, CB_GETCURSEL, 0, 0)) { + case 0: options.value_halign = DT_LEFT; break; + case 1: options.value_halign = DT_RIGHT; break; + } + + SaveOptions(); + return TRUE; + } + break; + } + + return 0; +} + +int OptInit(WPARAM wParam, LPARAM lParam) { + OPTIONSDIALOGPAGE odp = { 0 }; +#define OPTIONPAGE_OLD_SIZE2 60
+ DWORD mirVir = (DWORD)CallService(MS_SYSTEM_GETVERSION, 0, 0);
+ odp.cbSize = (mirVir >= 0x00060000 ? sizeof(odp) : OPTIONPAGE_OLD_SIZE2);
+ //odp.cbSize = sizeof(odp);
+
+ odp.flags = ODPF_BOLDGROUPS; + //odp.flags |= ODPF_UNICODE; + odp.position = -790000000; + odp.hInstance = hInst; + + + odp.pszTemplate = MAKEINTRESOURCEA(IDD_OPT1); + odp.pszTab = Translate("Appearance"); + odp.pszTitle = (mirVir >= 0x00060000 ? Translate("Tooltips") : Translate("Tooltips View"));; + odp.pszGroup = Translate("Customize"); + odp.nIDBottomSimpleControl = 0; + odp.pfnDlgProc = DlgProcOpts1; + CallService( MS_OPT_ADDPAGE, wParam,( LPARAM )&odp ); + + odp.pszTemplate = MAKEINTRESOURCEA(IDD_OPT2); + odp.pszTab = Translate("Content"); + odp.pszTitle = (mirVir >= 0x00060000 ? Translate("Tooltips") : Translate("Tooltips Content"));; + odp.pszGroup = Translate("Customize"); + odp.nIDBottomSimpleControl = 0; + odp.pfnDlgProc = DlgProcOpts2; + CallService( MS_OPT_ADDPAGE, wParam,( LPARAM )&odp ); + + return 0; +} + +HANDLE hEventOptInit; + +void InitOptions() { + hEventOptInit = HookEvent(ME_OPT_INITIALISE, OptInit); +} + +void DeinitOptions() { + UnhookEvent(hEventOptInit); + + DIListNode *di_node = options.di_list; + while(options.di_list) { + di_node = options.di_list; + options.di_list = options.di_list->next; + free(di_node); + } + + DSListNode *ds_node = options.ds_list; + while(options.ds_list) { + ds_node = options.ds_list; + options.ds_list = options.ds_list->next; + free(ds_node); + } +} diff --git a/tipper/options.h b/tipper/options.h new file mode 100644 index 0000000..6fff79b --- /dev/null +++ b/tipper/options.h @@ -0,0 +1,74 @@ +#ifndef _OPTIONS_INC +#define _OPTIONS_INC + +#include "translations.h" + +#define LABEL_LEN 1024 +#define VALUE_LEN 8192 + +#define MODULE_NAME_LEN 512 +#define SETTING_NAME_LEN 512 + +typedef struct { + TCHAR label[LABEL_LEN]; + TCHAR value[VALUE_LEN]; + bool line_above, value_newline; +} DisplayItem; + +typedef enum {DVT_DB = 0, DVT_PROTODB = 1} DisplaySubstType; +typedef struct { + TCHAR name[LABEL_LEN]; + DisplaySubstType type; + char module_name[MODULE_NAME_LEN]; + char setting_name[SETTING_NAME_LEN]; + int translate_func_id; +} DisplaySubst; + +struct DSListNode { + DisplaySubst ds; + DSListNode *next; +}; + +struct DIListNode { + DisplayItem di; + DIListNode *next; +}; + +typedef enum {PAV_NONE=0, PAV_LEFT=1, PAV_RIGHT=2} PopupAvLayout; +typedef enum {PTL_LEFTICON=0, PTL_RIGHTICON=1, PTL_NOICON=2, PTL_NOTITLE=3} PopupTitleLayout; +typedef enum {PP_BOTTOMRIGHT=0, PP_BOTTOMLEFT=1, PP_TOPRIGHT=2, PP_TOPLEFT=3} PopupPosition; + +typedef struct { + int win_width, win_max_height, av_size; //tweety + int opacity; + bool border; + bool round, av_round; + bool animate; + bool drop_shadow; + bool trans_bg; + PopupTitleLayout title_layout; + PopupAvLayout av_layout; + int text_indent; + bool show_no_focus; + DSListNode *ds_list; + int ds_count; + DIListNode *di_list; + int di_count; + int time_in; + int padding, av_padding, text_padding; + PopupPosition pos; + int min_width, min_height; // no UI for these + int mouse_tollerance; + bool status_bar_tips; + int sidebar_width; + COLORREF bg_col, border_col, div_col, bar_col, title_col, label_col, value_col, sidebar_col; + int label_valign, label_halign, value_valign, value_halign; +} Options; + +extern Options options; + +void InitOptions(); +void LoadOptions(); +void DeinitOptions(); + +#endif diff --git a/tipper/popwin.cpp b/tipper/popwin.cpp new file mode 100644 index 0000000..c42467b --- /dev/null +++ b/tipper/popwin.cpp @@ -0,0 +1,837 @@ +#include "common.h" +#include "subst.h" +#include "popwin.h" +#include "message_pump.h" + +#define TITLE_TEXT_LEN 512 + +#define ANIM_STEPS 20 +#define ANIM_ELAPSE 10 + +#define CHECKMOUSE_ELAPSE 250 + +#define ID_TIMER_ANIMATE 0x0100 +#define ID_TIMER_CHECKMOUSE 0x0101 + +typedef struct { + TCHAR *swzLabel, *swzValue; + bool value_newline; + bool line_above; + int label_height, value_height, total_height; +} RowData; + +struct PopupWindowData { + HBRUSH bkBrush, barBrush; + HPEN bPen, dPen; + int tb_height, av_height, text_height, sm_height, lm_height, label_width; + int real_av_width, real_av_height; + //TCHAR *lm_text, *sm_text; + HANDLE hContact; + int iconIndex; + CLCINFOTIPEX clcit; + TCHAR swzTitle[TITLE_TEXT_LEN]; + RowData *rows; + int row_count; + int anim_step; + bool text_tip; + int indent, sb_width; + POINT start_cursor_pos; // work around bugs with hiding tips (timer check mouse position) +}; + +LRESULT CALLBACK PopupWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { + PopupWindowData *pwd = (PopupWindowData *)GetWindowLong(hwnd, GWL_USERDATA); + + switch(uMsg) { + case WM_CREATE: + { + + CREATESTRUCT *cs = (CREATESTRUCT *)lParam; + pwd = (PopupWindowData *)malloc(sizeof(PopupWindowData)); + memset(pwd, 0, sizeof(PopupWindowData)); + pwd->clcit = *(CLCINFOTIPEX *)cs->lpCreateParams; + pwd->iconIndex = -1; + pwd->bkBrush = CreateSolidBrush(options.bg_col); + pwd->barBrush = CreateSolidBrush(options.sidebar_col); + pwd->bPen = options.border ? (HPEN)CreatePen(PS_SOLID, 1, options.border_col) : (HPEN)CreatePen(PS_SOLID, 1, options.bg_col); + pwd->dPen = (HPEN)CreatePen(PS_SOLID, 1, options.div_col); + + SetWindowLong(hwnd, GWL_USERDATA, (LONG)pwd); + + // work around bug hiding tips + GetCursorPos(&pwd->start_cursor_pos); + SetTimer(hwnd, ID_TIMER_CHECKMOUSE, CHECKMOUSE_ELAPSE, 0); + + if(pwd->clcit.proto) { + pwd->text_tip = false; + pwd->indent = options.text_indent; + pwd->sb_width = options.sidebar_width; + + MultiByteToWideChar(code_page, 0, pwd->clcit.proto, -1, pwd->swzTitle, 512); + + WORD status = CallProtoService(pwd->clcit.proto, PS_GETSTATUS, 0, 0); + char *strptr = (char *)CallService(MS_CLIST_GETSTATUSMODEDESCRIPTION, (WPARAM)status, (LPARAM)0);
+ int size = MultiByteToWideChar(code_page, 0, strptr, -1, 0, 0);
+ if(size) { + wchar_t *swzText = (wchar_t *)malloc(size * sizeof(wchar_t)); + MultiByteToWideChar(code_page, 0, strptr, -1, swzText, size); + pwd->rows = (RowData *) realloc(pwd->rows, sizeof(RowData) * (pwd->row_count + 1)); + + pwd->rows[pwd->row_count].swzLabel = wcsdup(TranslateT("Status:")); + pwd->rows[pwd->row_count].swzValue = swzText; + pwd->rows[pwd->row_count].value_newline = false; + pwd->rows[pwd->row_count].line_above = false; + pwd->row_count++; + } + + if(status >= ID_STATUS_OFFLINE && status <= ID_STATUS_IDLE) { + char *status_msg = (char *)CallService(MS_AWAYMSG_GETSTATUSMSG, status, 0); + if(status_msg) { + int size = MultiByteToWideChar(code_page, 0, status_msg, -1, 0, 0); + if(size) { + wchar_t *swzText = (wchar_t *)malloc(size * sizeof(wchar_t)); + MultiByteToWideChar(code_page, 0, status_msg, -1, swzText, size); + StripBBCodesInPlace(swzText); + pwd->rows = (RowData *) realloc(pwd->rows, sizeof(RowData) * (pwd->row_count + 1)); + + pwd->rows[pwd->row_count].swzLabel = wcsdup(TranslateT("Status message:")); + pwd->rows[pwd->row_count].swzValue = swzText; + pwd->rows[pwd->row_count].value_newline = true; + pwd->rows[pwd->row_count].line_above = true; + pwd->row_count++; + } + mir_free(status_msg); + } + } + } else if(pwd->clcit.text) { + pwd->text_tip = true; + pwd->indent = 0; + pwd->sb_width = 0; + +
+ //MessageBox(0, swzText, _T("tip"), MB_OK);
+ + wchar_t buff[2048], *swzText = pwd->clcit.text; + int buff_pos, i = 0, size = _tcslen(pwd->clcit.text); + bool top_message = false; + + if(swzText[0] != _T('<')) { + while(swzText[i] != _T('\n') && swzText[i] != _T('\r') && i < size && i < 2048) {
+ buff[i] = swzText[i];
+ i++;
+ } + buff[i] = 0; + + if(_tcslen(buff)) { + pwd->rows = (RowData *)realloc(pwd->rows, sizeof(RowData) * (pwd->row_count + 1)); + pwd->rows[pwd->row_count].line_above = false; + pwd->rows[pwd->row_count].value_newline = true; + pwd->rows[pwd->row_count].swzLabel = _T(""); + pwd->rows[pwd->row_count].swzValue = wcsdup(buff);
+ pwd->row_count++; + top_message = true; + } + } + + // parse bold bits into labels and the rest into items + while(i < size) { + while(i + 2 < size + && (swzText[i] != L'<' + || swzText[i + 1] != L'b' + || swzText[i + 2] != L'>')) + { + i++; + } + + i += 3; + + buff_pos = 0; + while(i + 3 < size + && buff_pos < 2048 + && (swzText[i] != L'<' + || swzText[i + 1] != L'/' + || swzText[i + 2] != L'b' + || swzText[i + 3] != L'>')) + { + if(swzText[i] != L'\t') + buff[buff_pos++] = swzText[i]; + i++; + } + + i += 4; + + buff[buff_pos] = 0; + + if(buff_pos) { + pwd->rows = (RowData *)realloc(pwd->rows, sizeof(RowData) * (pwd->row_count + 1)); + pwd->rows[pwd->row_count].value_newline = false; + pwd->rows[pwd->row_count].swzLabel = wcsdup(buff); + if(pwd->row_count == 1 && top_message) + pwd->rows[pwd->row_count].line_above = true; + else + pwd->rows[pwd->row_count].line_above = false; + + buff_pos = 0; + while(i < size + && buff_pos < 2048 + && swzText[i] != L'\n') + { + if(swzText[i] != L'\t' && swzText[i] != L'\r') + buff[buff_pos++] = swzText[i]; + i++; + } + buff[buff_pos] = 0; + + pwd->rows[pwd->row_count].swzValue = wcsdup(buff); + + pwd->row_count++; + } + + i++; + } + + if(pwd->row_count == 0) { + // single item + pwd->row_count = 1; + pwd->rows = (RowData *)malloc(sizeof(RowData)); + pwd->rows[0].line_above = pwd->rows[0].value_newline = false; + pwd->rows[0].swzLabel = 0; + pwd->rows[0].swzValue = swzText; + } + + free(pwd->clcit.text); + pwd->clcit.text = 0; + } else { + pwd->text_tip = false; + pwd->indent = options.text_indent; + pwd->sb_width = options.sidebar_width; + pwd->hContact = pwd->clcit.hItem; + pwd->iconIndex = (int)CallService(MS_CLIST_GETCONTACTICON, (WPARAM)pwd->hContact, 0); + + // don't use stored status message + DBDeleteContactSetting(pwd->hContact, MODULE, "TempStatusMsg"); + + { // get unicode name if possible, else ascii + wchar_t *swzCDN = (wchar_t *) CallService(MS_CLIST_GETCONTACTDISPLAYNAME, (WPARAM)pwd->hContact, GCDNF_UNICODE); + char *szCDN = (char *)CallService(MS_CLIST_GETCONTACTDISPLAYNAME, (WPARAM)pwd->hContact, 0); + + if(szCDN) { + // detect if the clist provided unicode display name by comparing with non-unicode + if(swzCDN && strncmp(szCDN, (char *)swzCDN, strlen(szCDN)) != 0) { + wcsncpy(pwd->swzTitle, swzCDN, TITLE_TEXT_LEN); + } else { + // convert to unicode + //swzContactDisplayName = (wchar_t *) _alloca(sizeof(wchar_t) * (strlen(szCDN) + 1)); + int size = MultiByteToWideChar(code_page, 0, (char *) szCDN, -1, 0, 0); + if(size > 0) { + MultiByteToWideChar(code_page, 0, (char *) szCDN, -1, pwd->swzTitle, TITLE_TEXT_LEN); + } else { + wcsncpy(pwd->swzTitle, TranslateT("(Unknown)"), TITLE_TEXT_LEN); + } + } + pwd->swzTitle[TITLE_TEXT_LEN - 1] = 0; + } else { + wcscpy(pwd->swzTitle, TranslateT("(Unknown)")); + } + } + + SendMessage(hwnd, PUM_REFRESH_VALUES, 0, 0); + } + } + + // transparency +#ifdef WS_EX_LAYERED + SetWindowLong(hwnd, GWL_EXSTYLE, GetWindowLong(hwnd, GWL_EXSTYLE) | WS_EX_LAYERED); +#endif + +// not defined in my mingw winuser.h +#ifdef __GNUC__ +#define CS_DROPSHADOW 0x00020000 +#endif +#ifdef CS_DROPSHADOW + if (options.drop_shadow) SetClassLong(hwnd, GCL_STYLE, CS_DROPSHADOW); + else SetClassLong(hwnd, GCL_STYLE, 0); +#endif + +#ifdef LWA_ALPHA + if(MySetLayeredWindowAttributes) { + MySetLayeredWindowAttributes(hwnd, RGB(0,0,0), (int)(options.opacity / 100.0 * 255), LWA_ALPHA); + if(options.trans_bg) { + MySetLayeredWindowAttributes(hwnd, options.bg_col, 0, LWA_COLORKEY); + } + } +#endif + SendMessage(hwnd, PUM_GETHEIGHT, 0, 0); // calculate window height + SendMessage(hwnd, PUM_CALCPOS, 0, 0); + + if(options.animate) + SetTimer(hwnd, ID_TIMER_ANIMATE, ANIM_ELAPSE, 0); + + ShowWindow(hwnd, SW_SHOWNOACTIVATE); + UpdateWindow(hwnd); + /* + // move clist under? + { + HWND hwndClist = (HWND)CallService(MS_CLUI_GETHWND, 0, 0); + if(GetWindowLong(hwndClist, GWL_EXSTYLE) & WS_EX_TOPMOST) + SetWindowPos(hwndClist, hwnd, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE); + } + */ + // since tipper win is topmost, this should put it at top of topmost windows + SetWindowPos(hwnd, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE); + return 0; + case WM_ERASEBKGND: + { + HDC hdc = (HDC) wParam; + RECT r, r_bar; + GetClientRect(hwnd, &r); + + // bg + FillRect(hdc, &r, pwd->bkBrush); + // sidebar + r_bar = r; + r_bar.right = r.left + pwd->sb_width; + FillRect(hdc, &r_bar, pwd->barBrush); + // border + if(options.border) { + + HBRUSH hOldBrush = (HBRUSH)SelectObject(hdc, GetStockObject(NULL_BRUSH)); + HPEN hOldPen = (HPEN)SelectObject(hdc, pwd->bPen); + + int h = 0; + if(options.round) { + int v; + int w=14; + h=(r.right-r.left)>(w*2)?w:(r.right-r.left); + v=(r.bottom-r.top)>(w*2)?w:(r.bottom-r.top); + h=(h<v)?h:v; + //} else { + // Rectangle(hdc, r.left, r.top, (r.right - r.left), (r.bottom - r.top)); + } + RoundRect(hdc, 0, 0, (r.right - r.left), (r.bottom - r.top), h, h); + + SelectObject(hdc, hOldBrush); + SelectObject(hdc, hOldPen); + } + } + return TRUE; + case WM_PAINT: + { + RECT r, r2; + //if(GetUpdateRect(hwnd, &r, TRUE)) { + PAINTSTRUCT ps; + BeginPaint(hwnd, &ps); + HDC hdc = ps.hdc; + GetClientRect(hwnd, &r); + r2 = r; + + // text background + //SetBkColor(ps.hdc, options.bg_col); + SetBkMode(hdc, TRANSPARENT);
+ + // avatar + if(!pwd->text_tip && options.av_layout != PAV_NONE && pwd->av_height) { + RECT avr; + avr.top = options.av_padding; + + if(options.av_layout == PAV_LEFT) { + avr.left = r.left + options.av_padding; + avr.right = avr.left + pwd->real_av_width; + r2.left += pwd->real_av_width + (2 * options.av_padding - options.padding); // padding re-added for text + } else if(options.av_layout == PAV_RIGHT) { + avr.right = r.right - options.av_padding; + avr.left = avr.right - pwd->real_av_width; + r2.right -= pwd->real_av_width + (2 * options.av_padding - options.padding); + } + + avr.bottom = avr.top + pwd->real_av_height; + + AVATARDRAWREQUEST adr = {0}; + adr.cbSize = sizeof(adr); + adr.hContact = pwd->hContact; + adr.hTargetDC = ps.hdc; + adr.rcDraw = avr; + adr.dwFlags = (options.av_round ? AVDRQ_ROUNDEDCORNER : 0); + if(!pwd->hContact) { // status bar tip? + adr.dwFlags |= AVDRQ_OWNPIC; + adr.szProto = pwd->clcit.proto; + } + adr.radius = (options.av_round ? 5 : 0); + + CallService(MS_AV_DRAWAVATAR, 0, (LPARAM)&adr); + } + + RECT tr; + tr.left = r2.left + options.padding; tr.right = r2.right - options.padding; tr.top = tr.bottom = 0; + if(!pwd->text_tip && options.title_layout != PTL_NOTITLE) { + // title icon + if(options.title_layout != PTL_NOICON) { + HICON hIcon = 0; + bool destroy_icon = true; + if(pwd->iconIndex != -1) hIcon = ImageList_GetIcon((HIMAGELIST)CallService(MS_CLIST_GETICONSIMAGELIST, 0, 0), pwd->iconIndex, 0); + else if(!pwd->hContact) { + WORD status = CallProtoService(pwd->clcit.proto, PS_GETSTATUS, 0, 0); + hIcon = LoadSkinnedProtoIcon(pwd->clcit.proto, status); + destroy_icon = false; + } + if(hIcon) { + int iconx; + if(options.title_layout == PTL_RIGHTICON) { + iconx = r2.right - 16 - options.padding; + tr.right -= 16 + options.padding; + } else { + iconx = r2.left + options.padding; + tr.left += 16 + options.padding; + } + DrawIconEx(ps.hdc, iconx, options.padding + (pwd->tb_height - options.padding - 16) / 2, hIcon, 16, 16, 0, NULL, DI_NORMAL); + if(destroy_icon) DestroyIcon(hIcon); + } + } + + // title text + if(hFontTitle) SelectObject(ps.hdc, (HGDIOBJ)hFontTitle); + + SetTextColor(ps.hdc, options.title_col); + + tr.top = r.top + options.padding; tr.bottom = tr.top + pwd->tb_height - options.padding; + DrawText(ps.hdc, pwd->swzTitle, wcslen(pwd->swzTitle), &tr, DT_VCENTER | DT_LEFT | DT_END_ELLIPSIS | DT_SINGLELINE | DT_NOPREFIX);
+ } + + // values + pwd->text_height = 0; + bool use_r = true; + int row_height; + for(int i = 0; i < pwd->row_count; i++) { + tr.top = tr.bottom; + use_r = (tr.top + options.text_padding >= pwd->av_height); + + if(use_r) { + if(pwd->rows[i].line_above) { + HPEN hOldPen = (HPEN)SelectObject(hdc, pwd->dPen); + tr.top += options.text_padding; + Rectangle(hdc, r.left + options.padding + pwd->indent, tr.top, r.right - options.padding, tr.top + 1); + SelectObject(hdc, hOldPen); + } + tr.left = r.left + options.padding + pwd->indent; + if(pwd->rows[i].value_newline) + tr.right = r.right - options.padding; + else + tr.right = r.left + options.padding + pwd->indent + pwd->label_width; + } else { + if(pwd->rows[i].line_above) { + HPEN hOldPen = (HPEN)SelectObject(hdc, pwd->dPen); + tr.top += options.text_padding; + Rectangle(hdc, r2.left + options.padding + pwd->indent, tr.top, r2.right - options.padding, tr.top + 1); + SelectObject(hdc, hOldPen); + } + tr.left = r2.left + options.padding + pwd->indent; + if(pwd->rows[i].value_newline) + tr.right = r2.right - options.padding; + else + tr.right = r2.left + options.padding + pwd->indent + pwd->label_width; + } + + if(pwd->rows[i].value_newline) + row_height = pwd->rows[i].label_height; + else + row_height = max(pwd->rows[i].label_height, pwd->rows[i].value_height); + + if(hFontLabels) SelectObject(hdc, (HGDIOBJ)hFontLabels); + if(pwd->rows[i].label_height) { + tr.top += options.text_padding; + tr.bottom = tr.top + row_height; + SetTextColor(ps.hdc, options.label_col); + DrawText(ps.hdc, pwd->rows[i].swzLabel, wcslen(pwd->rows[i].swzLabel), &tr, options.label_valign | ((options.label_halign == DT_RIGHT && !pwd->rows[i].value_newline) ? DT_RIGHT : DT_LEFT) | DT_END_ELLIPSIS | DT_SINGLELINE | DT_NOPREFIX); + if(pwd->rows[i].value_newline) + tr.top = tr.bottom; + } else + tr.bottom = tr.top; + + if(pwd->rows[i].value_newline) + row_height = pwd->rows[i].value_height; + + if(hFontValues) SelectObject(hdc, (HGDIOBJ)hFontValues); + SetTextColor(ps.hdc, options.value_col); + if(use_r) { + if(pwd->rows[i].value_newline) + tr.left = r.left + options.padding + pwd->indent; + else + tr.left = r.left + options.padding + pwd->indent + pwd->label_width + options.padding; + tr.right = r.right - options.padding; + } else { + if(pwd->rows[i].value_newline) + tr.left = r2.left + options.padding + pwd->indent; + else + tr.left = r2.left + options.padding + pwd->indent + pwd->label_width + options.padding; + tr.right = r2.right - options.padding; + } + if(pwd->rows[i].value_height) { + if(pwd->rows[i].value_newline || !pwd->rows[i].label_height) tr.top += options.text_padding; + tr.bottom = tr.top + row_height; + DrawText(ps.hdc, pwd->rows[i].swzValue, wcslen(pwd->rows[i].swzValue), &tr, options.value_valign | options.value_halign | DT_WORDBREAK | DT_WORD_ELLIPSIS | DT_END_ELLIPSIS | DT_NOPREFIX); + } + } + + EndPaint(hwnd, &ps); + //} + } + return 0; + case WM_DESTROY: + KillTimer(hwnd, ID_TIMER_CHECKMOUSE); + KillTimer(hwnd, ID_TIMER_ANIMATE); + ShowWindow(hwnd, SW_HIDE); + + DeleteObject(pwd->bkBrush); + DeleteObject(pwd->barBrush); + DeleteObject(pwd->bPen); + DeleteObject(pwd->dPen); + + for(int i = 0; i < pwd->row_count; i++) { + free(pwd->rows[i].swzLabel); + free(pwd->rows[i].swzValue); + } + free(pwd->rows); + + free(pwd); pwd = 0; + SetWindowLong(hwnd, GWL_USERDATA, 0); + + break; + case WM_TIMER: + if(wParam == ID_TIMER_ANIMATE) { + pwd->anim_step++; + if(pwd->anim_step == ANIM_STEPS) + KillTimer(hwnd, ID_TIMER_ANIMATE); + SendMessage(hwnd, PUM_UPDATERGN, 0, 0); + InvalidateRect(hwnd, 0, TRUE); + UpdateWindow(hwnd); + } else if(wParam == ID_TIMER_CHECKMOUSE) { + // workaround for tips that just won't go away + + POINT pt; + GetCursorPos(&pt); + + /* + // works well, except in e.g. options->events->ignore :( + bool hide = false; + if(pwd->text_tip) { + // tip may be off clist (e.g. systray) + if(pt.x != pwd->start_cursor_pos.x || pt.y != pwd->start_cursor_pos.y) // mouse has moved + hide = false; + } else { + // check window under cursor - hide if not clist + HWND hwnd_clist = (HWND)CallService(MS_CLUI_GETHWND, 0, 0), + hwnd_under = WindowFromPoint(pt); + if(hwnd_under != hwnd_clist && !IsChild(hwnd_clist, hwnd_under)) + hide = true; + } + if(hide) PostMPMessage(MUM_DELETEPOPUP, 0, 0); + */ + + if(abs(pt.x - pwd->start_cursor_pos.x) > options.mouse_tollerance + || abs(pt.y - pwd->start_cursor_pos.y) > options.mouse_tollerance) // mouse has moved beyond tollerance + { + PostMPMessage(MUM_DELETEPOPUP, 0, 0); + } + } + break; + + case PUM_SETSTATUSTEXT: + { + if(pwd && (HANDLE)wParam == pwd->hContact) { + // in case we have the status message in a row + DBWriteContactSettingTString(pwd->hContact, MODULE, "TempStatusMsg", (TCHAR*)lParam); + SendMessage(hwnd, PUM_REFRESH_VALUES, 0, 0); + } + } + return TRUE; + case PUM_SETAVATAR: + { + if(pwd && (HANDLE)wParam == pwd->hContact) { + SendMessage(hwnd, PUM_GETHEIGHT, 0, 0); // calculate window height + SendMessage(hwnd, PUM_CALCPOS, 0, 0); + InvalidateRect(hwnd, 0, TRUE); + } + } + return TRUE; + case PUM_REFRESH_VALUES: + if(pwd && pwd->clcit.proto == 0 && pwd->text_tip == false) { + for(int i = 0; i < pwd->row_count; i++) { + free(pwd->rows[i].swzLabel); + free(pwd->rows[i].swzValue); + } + if(pwd->rows) { + free(pwd->rows); + pwd->rows = 0; + } + pwd->row_count = 0; + + DIListNode *node = options.di_list; + TCHAR buff_label[LABEL_LEN], buff[VALUE_LEN]; + while(node) { + if(GetLabelText(pwd->hContact, node->di, buff_label, LABEL_LEN) && GetValueText(pwd->hContact, node->di, buff, VALUE_LEN)) { + if(node->di.line_above // we have a line above + && pwd->row_count > 0 // and we're not the first row + && pwd->rows[pwd->row_count - 1].line_above // and above us there's a line above + && pwd->rows[pwd->row_count - 1].swzLabel[0] == 0 // with no label + && pwd->rows[pwd->row_count - 1].swzValue[0] == 0) // and no value + { + // overwrite item above + pwd->row_count--; + free(pwd->rows[pwd->row_count].swzLabel); + free(pwd->rows[pwd->row_count].swzValue); + } else + pwd->rows = (RowData *) realloc(pwd->rows, sizeof(RowData) * (pwd->row_count + 1)); + + pwd->rows[pwd->row_count].swzLabel = wcsdup(buff_label); + pwd->rows[pwd->row_count].swzValue = wcsdup(buff); + pwd->rows[pwd->row_count].value_newline = node->di.value_newline; + pwd->rows[pwd->row_count].line_above = node->di.line_above; + pwd->row_count++; + } + node = node->next; + } + + // if the last item is just a divider, remove it + if(pwd->row_count > 0 + && pwd->rows[pwd->row_count - 1].line_above // and above us there's a line above + && pwd->rows[pwd->row_count - 1].swzLabel[0] == 0 // with no label + && pwd->rows[pwd->row_count - 1].swzValue[0] == 0) // and no value + { + pwd->row_count--; + free(pwd->rows[pwd->row_count].swzLabel); + free(pwd->rows[pwd->row_count].swzValue); + + if(pwd->row_count == 0) + free(pwd->rows); + } + + SendMessage(hwnd, PUM_GETHEIGHT, 0, 0); // calculate window height + SendMessage(hwnd, PUM_CALCPOS, 0, 0); + InvalidateRect(hwnd, 0, TRUE); + } + return TRUE; + case PUM_GETHEIGHT: + { + int *pHeight = (int *)wParam; + HDC hdc = GetDC(hwnd); + SIZE size; + RECT r; + r.top = r.left = 0; + r.right = options.win_width; + int width = options.padding; + + // titlebar height + if(!pwd->text_tip && pwd->swzTitle && options.title_layout != PTL_NOTITLE) { + if(hFontTitle) SelectObject(hdc, (HGDIOBJ)hFontTitle); + GetTextExtentPoint32(hdc, pwd->swzTitle, wcslen(pwd->swzTitle), &size); + width += options.padding + size.cx; + if(options.title_layout != PTL_NOICON) { + pwd->tb_height = options.padding + max(size.cy, 16); + width += 16 + options.padding; + } else + pwd->tb_height = options.padding + size.cy; + } else + pwd->tb_height = 0; + + // avatar height + pwd->av_height = 0; + if(!pwd->text_tip && options.av_layout != PAV_NONE && ServiceExists(MS_AV_DRAWAVATAR)) { + AVATARCACHEENTRY *ace = 0; + if(pwd->hContact) ace = (AVATARCACHEENTRY *)CallService(MS_AV_GETAVATARBITMAP, (WPARAM)pwd->hContact, 0); + else ace = (AVATARCACHEENTRY *)CallService(MS_AV_GETMYAVATAR, 0, (LPARAM)pwd->clcit.proto); + if(ace && (ace->dwFlags & AVS_BITMAP_VALID) && !(ace->dwFlags & AVS_HIDEONCLIST)) { + if(ace->bmHeight >= ace->bmWidth) { + pwd->real_av_height = options.av_size; + pwd->real_av_width = (int)(options.av_size * (ace->bmWidth / (double)ace->bmHeight)); + } else { + pwd->real_av_height = (int)(options.av_size * (ace->bmHeight / (double)ace->bmWidth)); + pwd->real_av_width = options.av_size; + } + pwd->av_height = options.av_padding * 2 + pwd->real_av_height; + width += pwd->real_av_width + (2 * options.av_padding - options.padding); + } + } + + int i; + // text height + pwd->text_height = pwd->label_width = 0; + // iterate once to find max label width for items with label and value on same line, but don't consider width of labels on a new line + for(i = 0; i < pwd->row_count; i++) { + if(pwd->rows[i].swzLabel && pwd->rows[i].value_newline == false) { + if(hFontLabels) SelectObject(hdc, (HGDIOBJ)hFontLabels); + GetTextExtentPoint32(hdc, pwd->rows[i].swzLabel, wcslen(pwd->rows[i].swzLabel), &size); + if(size.cx > pwd->label_width) + pwd->label_width = size.cx; + } + } + + for(i = 0; i < pwd->row_count; i++) { + if(hFontLabels) SelectObject(hdc, (HGDIOBJ)hFontLabels); + if(pwd->rows[i].swzLabel) + GetTextExtentPoint32(hdc, pwd->rows[i].swzLabel, wcslen(pwd->rows[i].swzLabel), &size); + else + size.cy = size.cx = 0; + + // save so we don't have to recalculate + pwd->rows[i].label_height = size.cy; + + if(hFontValues) SelectObject(hdc, (HGDIOBJ)hFontValues); + RECT smr; + smr.top = smr.bottom = 0; + smr.left = r.left + options.padding + pwd->indent; + smr.right = r.right; + if(pwd->tb_height + pwd->text_height + options.text_padding < pwd->av_height) + smr.right -= pwd->real_av_width + 2 * options.av_padding;
+ else + smr.right -= options.padding; + if(!pwd->rows[i].value_newline) smr.right -= pwd->label_width + options.padding; + if(pwd->rows[i].swzValue) + DrawText(hdc, pwd->rows[i].swzValue, wcslen(pwd->rows[i].swzValue), &smr, DT_CALCRECT | DT_VCENTER | DT_LEFT | DT_WORDBREAK | DT_WORD_ELLIPSIS | DT_END_ELLIPSIS | DT_NOPREFIX); + + // save so we don't have to recalculate + pwd->rows[i].value_height = smr.bottom; + + pwd->rows[i].total_height = (pwd->rows[i].line_above ? options.text_padding : 0); + if(pwd->rows[i].value_newline) { + if(size.cy) pwd->rows[i].total_height += size.cy + options.text_padding; + if(smr.bottom) pwd->rows[i].total_height += smr.bottom + options.text_padding; + } else { + int maxheight = max(size.cy, smr.bottom); + if(maxheight) pwd->rows[i].total_height += maxheight + options.text_padding; + } + + // only consider this item's width, and include it's height, if it doesn't make the window too big + if(max(pwd->tb_height + pwd->text_height + options.padding + pwd->rows[i].total_height, pwd->av_height) <= options.win_max_height) { + if(width < options.win_width) { + int wid = options.padding + pwd->indent + (pwd->rows[i].value_newline ? max(size.cx, smr.right - smr.left) : pwd->label_width + options.padding + (smr.right - smr.left)); + if(pwd->tb_height + pwd->text_height + options.text_padding < pwd->av_height) + width = max(width, wid + options.av_size + 2 * options.av_padding); + else + width = max(width, wid + options.padding); + } +
+ pwd->text_height += pwd->rows[i].total_height; + } + } + + ReleaseDC(hwnd, hdc); + + int height = max(pwd->tb_height + pwd->text_height + options.padding, pwd->av_height); + + if(height < options.min_height) height = options.min_height; + // ignore minwidth for text tips + if((!pwd->text_tip) && width < options.min_width) width = options.min_width; + + if(height > options.win_max_height) height = options.win_max_height; + if(width > options.win_width) width = options.win_width; + + GetWindowRect(hwnd, &r); + if(r.right - r.left != width || r.bottom - r.top != height) { + + SetWindowPos(hwnd, 0, 0, 0, width, height, SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE); + SendMessage(hwnd, PUM_UPDATERGN, 0, 0); + + InvalidateRect(hwnd, 0, TRUE); + } + + if(pHeight) *pHeight = height; + } + return TRUE; + case PUM_UPDATERGN: + { + HRGN hRgn1; + RECT r; + + int v,h; + int w=11; + GetWindowRect(hwnd,&r); + r.right -= r.left; + r.left = 0; + r.bottom -= r.top; + r.top = 0; + + if(options.animate && pwd->anim_step < ANIM_STEPS) { + float frac = 1.0f - pwd->anim_step / (float)ANIM_STEPS; + int wi = r.right, hi = r.bottom; + + r.left += (int)(wi / 2.0f * frac + 0.5f); + r.right -= (int)(wi / 2.0f * frac + 0.5f); + r.top += (int)(hi / 2.0f * frac + 0.5f); + r.bottom -= (int)(hi / 2.0f * frac + 0.5f); + } + + // round corners + if(options.round) { + h=(r.right-r.left)>(w*2)?w:(r.right-r.left); + v=(r.bottom-r.top)>(w*2)?w:(r.bottom-r.top); + h=(h<v)?h:v; + } else + h = 0; + hRgn1=CreateRoundRectRgn(r.left,r.top,r.right + 1,r.bottom + 1,h,h); + SetWindowRgn(hwnd,hRgn1,FALSE); + } + return TRUE; + case PUM_CALCPOS: + { + RECT wa_rect, r; + + HMONITOR hMonitor; + hMonitor = MonitorFromPoint(pwd->clcit.ptCursor, MONITOR_DEFAULTTONEAREST); + + MONITORINFO mi; + mi.cbSize = sizeof(mi); + GetMonitorInfo(hMonitor, &mi); + + wa_rect = mi.rcWork; + + GetWindowRect(hwnd, &r); + + CURSORINFO ci = {sizeof(CURSORINFO)}; + GetCursorInfo(&ci); + + + + int x = 0, y = 0, width = (r.right - r.left), height = (r.bottom - r.top); + + switch(options.pos) { + case PP_BOTTOMRIGHT: + x = pwd->clcit.ptCursor.x + GetSystemMetrics(SM_CXSMICON); // cursor size is too large - use small icon size + y = pwd->clcit.ptCursor.y + GetSystemMetrics(SM_CYSMICON); + break; + case PP_BOTTOMLEFT: + x = pwd->clcit.ptCursor.x - width - GetSystemMetrics(SM_CXSMICON); + y = pwd->clcit.ptCursor.y + GetSystemMetrics(SM_CYSMICON); + break; + case PP_TOPRIGHT: + x = pwd->clcit.ptCursor.x + GetSystemMetrics(SM_CXSMICON); + y = pwd->clcit.ptCursor.y - height - GetSystemMetrics(SM_CYSMICON); + break; + case PP_TOPLEFT: + x = pwd->clcit.ptCursor.x - width - GetSystemMetrics(SM_CXSMICON); + y = pwd->clcit.ptCursor.y - height - GetSystemMetrics(SM_CYSMICON); + break; + } + + if(x + width + 8 > wa_rect.right) + x = wa_rect.right - width - 8; + if(y + height > wa_rect.bottom) + y = pwd->clcit.ptCursor.y - height - 8; + if(x - 8 < wa_rect.left) + x = wa_rect.left + 8; + if(y - 8 < wa_rect.top) + y = pwd->clcit.ptCursor.y + GetSystemMetrics(SM_CYSMICON); + + SetWindowPos(hwnd, 0, x, y, 0, 0, SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER); + } + return TRUE; + } + + + return DefWindowProc(hwnd, uMsg, wParam, lParam); +} + +int AvatarChanged(WPARAM wParam, LPARAM lParam) { + HANDLE hContact = (HANDLE)wParam; + PostMPMessage(MUM_GOTAVATAR, (WPARAM)hContact, 0); + return 0; +} + diff --git a/tipper/popwin.h b/tipper/popwin.h new file mode 100644 index 0000000..f354d63 --- /dev/null +++ b/tipper/popwin.h @@ -0,0 +1,17 @@ +#ifndef _POPWIN_INC
+#define _POPWIN_INC
+
+#define POP_WIN_CLASS _T(MODULE) _T("MimTTClass")
+
+#define PUM_GETHEIGHT (WM_USER + 0x020)
+#define PUM_CALCPOS (WM_USER + 0x021)
+#define PUM_SETSTATUSTEXT (WM_USER + 0x022)
+#define PUM_UPDATERGN (WM_USER + 0x023)
+#define PUM_SETAVATAR (WM_USER + 0x024)
+#define PUM_REFRESH_VALUES (WM_USER + 0x025)
+
+LRESULT CALLBACK PopupWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
+
+int AvatarChanged(WPARAM wParam, LPARAM lParam); // exposed so hook/unhook is in main thread
+
+#endif
diff --git a/tipper/resource.h b/tipper/resource.h new file mode 100644 index 0000000..dad8e31 --- /dev/null +++ b/tipper/resource.h @@ -0,0 +1,85 @@ +//{{NO_DEPENDENCIES}}
+// Microsoft Visual C++ generated include file.
+// Used by tipper.rc
+//
+#define IDD_OPT1 101
+#define IDD_SUBST 103
+#define IDD_ITEM 104
+#define IDD_OPT2 105
+#define IDC_ED_WIDTH 1005
+#define IDC_ED_MAXHEIGHT 1006
+#define IDC_SPIN_WIDTH 1007
+#define IDC_SPIN_MAXHEIGHT 1008
+#define IDC_ED_INDENT 1009
+#define IDC_SPIN_INDENT 1010
+#define IDC_ED_PADDING 1011
+#define IDC_SPIN_PADDING 1012
+#define IDC_ED_TRANS 1013
+#define IDC_SPIN_TRANS 1014
+#define IDC_CHK_BORDER 1015
+#define IDC_CHK_ROUNDCORNERS 1016
+#define IDC_ED_MINWIDTH 1017
+#define IDC_CHK_ANIMATE 1018
+#define IDC_CHK_TRANSBG 1019
+#define IDC_CHK_SHADOW 1020
+#define IDC_SPIN_MINWIDTH 1021
+#define IDC_ED_MINHEIGHT 1022
+#define IDC_SPIN_MINHEIGHT 1023
+#define IDC_ED_SBWIDTH 1024
+#define IDC_SPIN_SBWIDTH 1025
+#define IDC_ED_TEXTPADDING 1026
+#define IDC_ED_AVSIZE 1027
+#define IDC_SPIN_AVSIZE 1028
+#define IDC_ED_HOVER 1029
+#define IDC_SPIN_HOVER 1030
+#define IDC_SPIN_TEXTPADDING 1031
+#define IDC_CMB_ICON 1032
+#define IDC_CMB_AV 1033
+#define IDC_CMB_AV2 1034
+#define IDC_CMB_ICON2 1034
+#define IDC_CMB_POS 1034
+#define IDC_LST_ITEMS 1035
+#define IDC_ED_AVPADDING 1035
+#define IDC_BTN_ADD 1036
+#define IDC_SPIN_AVPADDING 1036
+#define IDC_BTN_REMOVE 1037
+#define IDC_CHK_ROUNDCORNERS2 1037
+#define IDC_CHK_ROUNDCORNERSAV 1037
+#define IDC_BTN_UP 1038
+#define IDC_BTN_DOWN 1039
+#define IDC_CHK_NOFOCUS 1040
+#define IDC_BTN_EDIT 1041
+#define IDC_LST_SUBST 1042
+#define IDC_BTN_ADD2 1043
+#define IDC_ED_MODULE 1044
+#define IDC_BTN_REMOVE2 1044
+#define IDC_CHK_PROTOMOD 1045
+#define IDC_BTN_UP2 1045
+#define IDC_CHK_RIGHTLABEL 1045
+#define IDC_ED_SETTING 1046
+#define IDC_CMB_TRANSLATE 1047
+#define IDC_BTN_EDIT2 1047
+#define IDC_ED_LABEL 1048
+#define IDC_CHK_STATUSMSG 1048
+#define IDC_CHK_SBAR 1048
+#define IDC_CHK_LASTMSG 1049
+#define IDC_ED_VALUE 1050
+#define IDC_CHK_LINEABOVE 1051
+#define IDC_CHK_VALNEWLINE 1052
+#define IDC_CUSTOM1 1052
+#define IDC_BORDERCOLOUR 1052
+#define IDC_CMB_LV 1053
+#define IDC_CMB_VV 1054
+#define IDC_CMB_LH 1055
+#define IDC_CMB_VH 1056
+
+// Next default values for new objects
+//
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NEXT_RESOURCE_VALUE 106
+#define _APS_NEXT_COMMAND_VALUE 40001
+#define _APS_NEXT_CONTROL_VALUE 1054
+#define _APS_NEXT_SYMED_VALUE 101
+#endif
+#endif
diff --git a/tipper/resource.rc b/tipper/resource.rc new file mode 100644 index 0000000..41f2ce9 --- /dev/null +++ b/tipper/resource.rc @@ -0,0 +1,6 @@ +
+// this makes our dependencies work better
+#include "version.h"
+
+#include "tipper.rc"
+#include "version.rc"
diff --git a/tipper/subst.cpp b/tipper/subst.cpp new file mode 100644 index 0000000..5eb6e49 --- /dev/null +++ b/tipper/subst.cpp @@ -0,0 +1,468 @@ +#include "common.h"
+#include "subst.h"
+#include <time.h>
+
+void StripBBCodesInPlace(wchar_t *text) { + if(!DBGetContactSettingByte(0, MODULE, "StripBBCodes", 1)) + return; + + int read = 0, write = 0; + int len = wcslen(text); + + while(read <= len) { // copy terminating null too + while(read <= len && text[read] != L'[') { + if(text[read] != text[write]) text[write] = text[read]; + read++; write++; + } + if(read == len) break; + + if(len - read >= 3 && (wcsnicmp(text + read, L"[b]", 3) == 0 || wcsnicmp(text + read, L"[i]", 3) == 0)) + read += 3; + else if(len - read >= 4 && (wcsnicmp(text + read, L"[/b]", 4) == 0 || wcsnicmp(text + read, L"[/i]", 4) == 0)) + read += 4; + else if(len - read >= 6 && (wcsnicmp(text + read, L"[color", 6) == 0)) { + while(read < len && text[read] != L']') read++; + read++;// skip the ']' + } else if(len - read >= 8 && (wcsnicmp(text + read, L"[/color]", 8) == 0)) + read += 8; + else { + if(text[read] != text[write]) text[write] = text[read]; + read++; write++; + } + } +} +
+DWORD last_message_timestamp(HANDLE hContact) {
+ DBEVENTINFO dbei = {0}; + dbei.cbSize = sizeof(dbei); + HANDLE hDbEvent = (HANDLE)CallService(MS_DB_EVENT_FINDLAST, (WPARAM)hContact, 0); + while(hDbEvent) { + dbei.cbBlob = 0; + CallService(MS_DB_EVENT_GET, (WPARAM)hDbEvent, (LPARAM)&dbei); + if(dbei.eventType == EVENTTYPE_MESSAGE && !(dbei.flags & DBEF_SENT)) { + break; + } + hDbEvent = (HANDLE)CallService(MS_DB_EVENT_FINDPREV, (WPARAM)hDbEvent, 0); + } + + if(hDbEvent) return dbei.timestamp; + + return 0; +}
+
+void format_timestamp(DWORD ts, char *format, TCHAR *buff, int bufflen) {
+ if(unicode_system) {
+ TCHAR form[16];
+ DBTIMETOSTRINGT dbt = {0};
+ dbt.cbDest = bufflen;
+ dbt.szDest = buff;
+ MultiByteToWideChar(code_page, 0, format, -1, form, 16);
+ dbt.szFormat = form;
+ CallService(MS_DB_TIME_TIMESTAMPTOSTRINGT, (WPARAM)ts, (LPARAM)&dbt);
+ } else {
+ char buffA[512];
+ DBTIMETOSTRING dbt = {0};
+ dbt.cbDest = sizeof(buffA);
+ dbt.szDest = buffA;
+ dbt.szFormat = format;
+ CallService(MS_DB_TIME_TIMESTAMPTOSTRING, (WPARAM)ts, (LPARAM)&dbt);
+ MultiByteToWideChar(code_page, 0, buffA, -1, buff, bufflen);
+ }
+}
+
+bool uid(HANDLE hContact, TCHAR *buff, int bufflen) {
+ CONTACTINFO ci;
+ ci.cbSize = sizeof(CONTACTINFO);
+ ci.hContact = hContact;
+ ci.szProto = 0;//(char *)CallService(MS_PROTO_GETCONTACTBASEPROTO,(WPARAM)hcontact,0);
+ ci.dwFlag = CNF_UNIQUEID | (unicode_system ? CNF_UNICODE : 0);
+ if(!CallService(MS_CONTACT_GETCONTACTINFO, 0, (LPARAM)&ci)) {
+ switch(ci.type) {
+ case CNFT_BYTE:
+ _ltot(ci.bVal, buff, 10);
+ break;
+ case CNFT_WORD:
+ _ltot(ci.wVal, buff, 10);
+ break;
+ case CNFT_DWORD:
+ _ltot(ci.dVal, buff, 10);
+ break;
+ case CNFT_ASCIIZ:
+ if(unicode_system) _tcsncpy(buff, ci.pszVal, bufflen);
+ else MultiByteToWideChar(code_page, 0, (char *)ci.pszVal, -1, buff, bufflen);
+ break;
+ default:
+ return false;
+ }
+ return true;
+ }
+ return false;
+}
+
+TCHAR *GetLastMessageText(HANDLE hContact) { + DBEVENTINFO dbei = {0}; + dbei.cbSize = sizeof(dbei); + + HANDLE hDbEvent = (HANDLE)CallService(MS_DB_EVENT_FINDLAST, (WPARAM)hContact, 0); + while(hDbEvent) { + dbei.cbBlob = 0; + CallService(MS_DB_EVENT_GET, (WPARAM)hDbEvent, (LPARAM)&dbei); + if(dbei.eventType == EVENTTYPE_MESSAGE && !(dbei.flags & DBEF_SENT)) { + break; + } + hDbEvent = (HANDLE)CallService(MS_DB_EVENT_FINDPREV, (WPARAM)hDbEvent, 0); + } + + if(hDbEvent) { + dbei.pBlob = (BYTE *)malloc(dbei.cbBlob); + CallService(MS_DB_EVENT_GET, (WPARAM)hDbEvent, (LPARAM)&dbei); + + if(dbei.cbBlob == 0 || dbei.pBlob == 0) return 0; + + wchar_t *msg; + unsigned int msglen = strlen((char *)dbei.pBlob) + 1; + + // here we detect the double-zero wide char zero terminator - in case of messages that are not unicode but have + // other data after the message (e.g. metacontact copied messages with source identifier) + bool dz = false; + for(unsigned int i = msglen; i < dbei.cbBlob; i++) { + if(dbei.pBlob[i] == 0 && dbei.pBlob[i - 1] == 0) { // safe since msglen + 1 above + dz = true; + break; + } + } + + // does blob contain unicode message? + if(msglen < dbei.cbBlob && dz && wcslen((wchar_t *)(&dbei.pBlob[msglen]))) { + // yes + msg = (wchar_t *)(&dbei.pBlob[msglen]); + wchar_t *ret = wcsdup(msg); + StripBBCodesInPlace(ret); + return ret; + } else { + // no, convert to unciode (allocate stack memory); + int size = MultiByteToWideChar(code_page, 0, (char *) dbei.pBlob, -1, 0, 0); + if(size > 0) { + msg = (wchar_t *) malloc(sizeof(wchar_t) * size); + MultiByteToWideChar(code_page, 0, (char *) dbei.pBlob, -1, msg, size); + } else { + msg = (wchar_t *) malloc(sizeof(wchar_t) * (wcslen(TranslateT("Empty message")) + 1)); + wcscpy(msg, TranslateT("Empty message")); + } + StripBBCodesInPlace(msg); + return msg; + } + + } + + return 0; +} + +TCHAR *GetStatusMessageText(HANDLE hContact) { + TCHAR *ret = 0; + DBVARIANT dbv; + if(!DBGetContactSettingTString(hContact, MODULE, "TempStatusMsg", &dbv)) { + if(_tcslen(dbv.ptszVal)) { + ret = _tcsdup(dbv.ptszVal); + StripBBCodesInPlace(ret); // todo - fix for ansi build + } else CallContactService(hContact, PSS_GETAWAYMSG, 0, 0); + DBFreeVariant(&dbv);
+ /*
+ // removed - people can use e.g. %raw:CList/StatusMsg% for SMR + } else if(!DBGetContactSettingTString(hContact, "CList", "StatusMsg", &dbv)) { + if(_tcslen(dbv.ptszVal)) ret = _tcsdup(dbv.ptszVal); + else CallContactService(hContact, PSS_GETAWAYMSG, 0, 0); + DBFreeVariant(&dbv);
+ */ + } else + CallContactService(hContact, PSS_GETAWAYMSG, 0, 0); + + return ret; +} + +bool GetSysSubstText(HANDLE hContact, TCHAR *raw_spec, TCHAR *buff, int bufflen) {
+ if (!_tcscmp(raw_spec, _T("uid"))) {
+ return uid(hContact, buff, bufflen);
+ } else if (!_tcscmp(raw_spec, _T("proto"))) {
+ char *szProto = (char*)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)hContact, 0);
+ if (szProto){
+ MultiByteToWideChar(code_page, 0, szProto, -1, buff, bufflen);
+ return true;
+ }
+ } else if (!_tcscmp(raw_spec, _T("uidname"))) {
+ char *szProto = (char*)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)hContact, 0);
+ if (szProto){
+ char *szUniqueId = (char*)CallProtoService(szProto, PS_GETCAPS, PFLAG_UNIQUEIDTEXT, 0);
+ if(szUniqueId) {
+ MultiByteToWideChar(code_page, 0, szUniqueId, -1, buff, bufflen);
+ return true;
+ }
+ }
+ } else if (!_tcscmp(raw_spec, _T("status_msg"))) {
+ TCHAR *msg = GetStatusMessageText(hContact);
+ if(msg) {
+ _tcsncpy(buff, msg, bufflen);
+ free(msg);
+ return true;
+ }
+ } else if (!_tcscmp(raw_spec, _T("last_msg"))) {
+ TCHAR *msg = GetLastMessageText(hContact);
+ if(msg) {
+ _tcsncpy(buff, msg, bufflen);
+ return true;
+ }
+ } else if (!_tcscmp(raw_spec, _T("meta_subname"))) {
+ // get contact list name of active subcontact
+ HANDLE hSubContact = (HANDLE)CallService(MS_MC_GETMOSTONLINECONTACT, (WPARAM)hContact, 0);
+ if(!hSubContact) return false;
+
+ if(unicode_system) { // get unicode name if possible, else get ascii and convert + wchar_t *swzCDN = (wchar_t *) CallService(MS_CLIST_GETCONTACTDISPLAYNAME, (WPARAM)hSubContact, GCDNF_UNICODE); + if(swzCDN) { + wcsncpy(buff, swzCDN, bufflen); + return true; + } + } else { + char *szCDN = (char *)CallService(MS_CLIST_GETCONTACTDISPLAYNAME, (WPARAM)hSubContact, 0); + if(szCDN) { + int size = MultiByteToWideChar(code_page, 0, (char *) szCDN, -1, 0, 0); + if(size > 0) { + MultiByteToWideChar(code_page, 0, (char *) szCDN, -1, buff, bufflen); + return true; + } + } + } + return false; +
+ } else if (!_tcscmp(raw_spec, _T("meta_subuid"))){
+ HANDLE hSubContact = (HANDLE)CallService(MS_MC_GETMOSTONLINECONTACT, (WPARAM)hContact, 0);
+ if(!hSubContact) return false;
+ return uid(hSubContact, buff, bufflen);
+ } else if (!_tcscmp(raw_spec, _T("meta_subproto"))) {
+ // get protocol of active subcontact
+ HANDLE hSubContact = (HANDLE)CallService(MS_MC_GETMOSTONLINECONTACT, (WPARAM)hContact, 0);
+ if(!hSubContact) return false;
+
+ char *szProto = (char*)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)hSubContact, 0);
+ if (szProto){
+ MultiByteToWideChar(code_page, 0, szProto, -1, buff, bufflen);
+ return true;
+ }
+ } else if (!_tcscmp(raw_spec, _T("last_msg_time"))) {
+ DWORD ts = last_message_timestamp(hContact); + if(ts == 0) return false; + + format_timestamp(ts, "t", buff, bufflen);
+ return true;
+ } else if (!_tcscmp(raw_spec, _T("last_msg_date"))) {
+ DWORD ts = last_message_timestamp(hContact); + if(ts == 0) return false; + + format_timestamp(ts, "d", buff, bufflen);
+ return true;
+ } else if (!_tcscmp(raw_spec, _T("last_msg_reltime"))) {
+ DWORD ts = last_message_timestamp(hContact); + if(ts == 0) return false; + + DWORD t = (DWORD)time(0);
+ DWORD diff = (t - ts);
+ int d = (diff / 60 / 60 / 24);
+ int h = (diff - d * 60 * 60 * 24) / 60 / 60;
+ int m = (diff - d * 60 * 60 * 24 - h * 60 * 60) / 60;
+ if(d > 0) mir_sntprintf(buff, bufflen, TranslateT("%dd %dh %dm"), d, h, m);
+ else if(h > 0) mir_sntprintf(buff, bufflen, TranslateT("%dh %dm"), h, m);
+ else mir_sntprintf(buff, bufflen, TranslateT("%dm"), m);
+
+ return true;
+ }
+ return false;
+}
+
+bool GetSubstText(HANDLE hContact, const DisplaySubst &ds, TCHAR *buff, int bufflen) { + TranslateFunc *tfunc = 0; + for(int i = 0; i < num_tfuncs; i++) { + if(translations[i].id == (DWORD)ds.translate_func_id) { + tfunc = translations[i].tfunc; + break; + } + } + if(!tfunc) return false; + + switch(ds.type) { + case DVT_DB: + return tfunc(hContact, ds.module_name, ds.setting_name, buff, bufflen) != 0; + case DVT_PROTODB: + { + char *proto = (char *)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)hContact, 0); + if(proto) { + return tfunc(hContact, proto, ds.setting_name, buff, bufflen) != 0; + } + } + break; + } + return false; +} + +bool GetRawSubstText(HANDLE hContact, char *raw_spec, TCHAR *buff, int bufflen) { + int len = strlen(raw_spec); + for(int i = 0; i < len; i++) { + if(raw_spec[i] == '/') { + raw_spec[i] = 0; + if(strlen(raw_spec) == 0) { + char *proto = (char *)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)hContact, 0); + if(proto) + return translations[0].tfunc(hContact, proto, &raw_spec[i + 1], buff, bufflen) != 0; + else + return false; + } else + return translations[0].tfunc(hContact, raw_spec, &raw_spec[i + 1], buff, bufflen) != 0; + } + } + return false; +} + +bool ApplySubst(HANDLE hContact, const TCHAR *source, TCHAR *dest, int dest_len) { + // hack - allow empty strings before passing to variables (note - zero length strings return false after this) + if(dest && source &&_tcslen(source) == 0) { + dest[0] = 0; + return true; + } + + // pass to variables plugin if available + TCHAR *var_src = variables_parsedup((TCHAR *)source, 0, hContact); + //TCHAR *var_src = wcsdup(source); // disable variables + int source_len = _tcslen(var_src); + + int si = 0, di = 0, v = 0; + TCHAR vname[LABEL_LEN]; + TCHAR rep[VALUE_LEN], alt[VALUE_LEN]; + while(si < source_len && di < dest_len - 1) { + if(var_src[si] == _T('%')) { + si++; + v = 0; + while(si < source_len && v < LABEL_LEN) { + if(var_src[si] == _T('%')) { + // two %'s in a row in variable name disabled: e.g. %a%%b% - this is ambiguous] + //if(si + 1 < source_len && var_src[si + 1] == _T('%')) { + // si++; // skip first %, allow following code to add the second one to the variable name + //} else + break; + } + vname[v] = var_src[si]; + v++; si++; + } + if(v == 0) { // subst len is 0 - just a % symbol + dest[di] = _T('%'); + } else if(si < source_len) { // we found end % + vname[v] = 0; + + bool alt_subst = false; + bool subst = false; + + // apply only to specific protocol + TCHAR *p = _tcsrchr(vname, _T('^')); // use last '^', so if you want a ^ in alt text, you can just put a '^' on the end + if(p) { + *p = 0; + p++; + if(*p) { + bool negate = false; + if(*p == _T('!')) { + p++; + if(*p == 0) goto error; + negate = true; + } + + char sproto[256], *cp; + WideCharToMultiByte(code_page, 0, p, -1, sproto, 256, 0, 0); + cp = (char *)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)hContact, 0); + if(cp == 0 || (negate ? stricmp(cp, sproto) == 0 : stricmp(cp, sproto) != 0)) + goto empty; + } + } + + // get alternate text, if subst fails + alt[0] = 0; + p = _tcschr(vname, _T('|')); // use first '|' - so you can use the '|' symbol in alt text + if(p) { + *p = 0; // clip alt from vname + alt_subst = true; + + p++; + _tcsncpy(alt, p, VALUE_LEN); + alt[VALUE_LEN - 1] = 0; + } + + // get subst text + if(v > 4 && _tcsncmp(vname, _T("raw:"), 4) == 0) { // raw db substitution + char raw_spec[LABEL_LEN]; + WideCharToMultiByte(code_page, 0, &vname[4], -1, raw_spec, LABEL_LEN, 0, 0); + subst = GetRawSubstText(hContact, raw_spec, rep, VALUE_LEN); + } else if(v > 4 && _tcsncmp(vname, _T("sys:"), 4) == 0) { // 'system' substitution + subst = GetSysSubstText(hContact, &vname[4], rep, VALUE_LEN); + } else { + // see if we can find the subst + DSListNode *ds_node = options.ds_list; + while(ds_node) { + if(_tcscmp(ds_node->ds.name, vname) == 0) + break; + + ds_node = ds_node->next; + } + if(!ds_node) goto error; // no such subst + + subst = GetSubstText(hContact, ds_node->ds, rep, VALUE_LEN); + } + + if(subst) { + int rep_len = _tcslen(rep); + wcsncpy(&dest[di], rep, min(rep_len, dest_len - di)); + di += rep_len - 1; // -1 because we inc at bottom of loop + } else if(alt_subst) { + int alt_len = _tcslen(alt); + wcsncpy(&dest[di], alt, min(alt_len, dest_len - di)); + di += alt_len - 1; // -1 because we inc at bottom of loop + } else + goto empty; // empty value + + } else // no end % - error + goto error; + + } else { + dest[di] = var_src[si]; + } + + si++; + di++; + } + + free(var_src); + dest[di] = 0; + + // check for a 'blank' string - just spaces etc + for(si = 0; si <= di; si++) { + if(dest[si] != 0 && dest[si] != _T(' ') && dest[si] != _T('\t') && dest[si] != _T('\r') && dest[si] != _T('\n')) + return true; + } + + return false; + +empty: + free(var_src); + return false; + +error: + dest[0] = _T('*'); + dest[1] = 0; + free(var_src); + return true; +} + +bool GetLabelText(HANDLE hContact, const DisplayItem &di, TCHAR *buff, int bufflen) { + return ApplySubst(hContact, di.label, buff, bufflen); + +} + +bool GetValueText(HANDLE hContact, const DisplayItem &di, TCHAR *buff, int bufflen) { + return ApplySubst(hContact, di.value, buff, bufflen); +} + diff --git a/tipper/subst.h b/tipper/subst.h new file mode 100644 index 0000000..7fbf5f1 --- /dev/null +++ b/tipper/subst.h @@ -0,0 +1,14 @@ +#ifndef _SUBST_INC
+#define _SUBST_INC
+
+#include "options.h"
+#include "translations.h"
+
+//TCHAR *GetLastMessageText(HANDLE hContact); +//TCHAR *GetStatusMessageText(HANDLE hContact); +bool GetLabelText(HANDLE hContact, const DisplayItem &di, TCHAR *buff, int bufflen);
+bool GetValueText(HANDLE hContact, const DisplayItem &di, TCHAR *buff, int bufflen);
+
+void StripBBCodesInPlace(wchar_t *text);
+
+#endif
diff --git a/tipper/tipper.cpp b/tipper/tipper.cpp new file mode 100644 index 0000000..cd8085b --- /dev/null +++ b/tipper/tipper.cpp @@ -0,0 +1,295 @@ +// popups2.cpp : Defines the entry point for the DLL application.
+//
+
+#include "common.h"
+#include "tipper.h"
+#include "version.h"
+#include "message_pump.h"
+#include "options.h"
+#include "popwin.h"
+
+HMODULE hInst = 0;
+HANDLE mainThread = 0;
+
+int code_page = CP_ACP;
+
+
+FontIDW font_id_title = {0}, font_id_labels = {0}, font_id_values = {0};
+ColourIDW colour_id_bg = {0}, colour_id_border = {0}, colour_id_divider = {0}, colour_id_sidebar = {0};
+HFONT hFontTitle = 0, hFontLabels = 0, hFontValues = 0;
+
+// hooked here so it's in the main thread
+HANDLE hAvChangeEvent = 0, hShowTipEvent = 0, hHideTipEvent = 0, hAckEvent = 0, hFramesSBShow = 0, hFramesSBHide;
+
+HANDLE hShowTipService = 0, hShowTipWService = 0, hHideTipService = 0;
+
+struct MM_INTERFACE memoryManagerInterface = {0};
+
+PLUGININFO pluginInfo={
+ sizeof(PLUGININFO),
+ __PLUGIN_NAME,
+ PLUGIN_MAKE_VERSION(__MAJOR_VERSION, __MINOR_VERSION, __RELEASE_NUM, __BUILD_NUM),
+ __DESC,
+ __AUTHOR,
+ __AUTHOREMAIL,
+ __COPYRIGHT,
+ __AUTHORWEB,
+ 0, //not transient
+ 0 //doesn't replace anything built-in
+};
+
+PLUGINLINK *pluginLink = 0;
+
+extern "C" BOOL APIENTRY DllMain( HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
+{
+ hInst = hModule;
+ DisableThreadLibraryCalls(hInst);
+ return TRUE;
+}
+
+extern "C" __declspec(dllexport) PLUGININFO* MirandaPluginInfo(DWORD mirandaVersion)
+{
+ return &pluginInfo;
+}
+
+int ReloadFont(WPARAM wParam, LPARAM lParam) {
+ LOGFONT log_font;
+
+ if(hFontTitle) DeleteObject(hFontTitle);
+ options.title_col = CallService(MS_FONT_GETW, (WPARAM)&font_id_title, (LPARAM)&log_font);
+ hFontTitle = CreateFontIndirect(&log_font);
+ if(hFontLabels) DeleteObject(hFontLabels);
+ options.label_col = CallService(MS_FONT_GETW, (WPARAM)&font_id_labels, (LPARAM)&log_font);
+ hFontLabels = CreateFontIndirect(&log_font);
+ if(hFontValues) DeleteObject(hFontValues);
+ options.value_col = CallService(MS_FONT_GETW, (WPARAM)&font_id_values, (LPARAM)&log_font);
+ hFontValues = CreateFontIndirect(&log_font);
+
+ options.bg_col = CallService(MS_COLOUR_GETW, (WPARAM)&colour_id_bg, 0);
+ options.border_col = CallService(MS_COLOUR_GETW, (WPARAM)&colour_id_border, 0);
+ options.sidebar_col = CallService(MS_COLOUR_GETW, (WPARAM)&colour_id_sidebar, 0);
+ options.div_col = CallService(MS_COLOUR_GETW, (WPARAM)&colour_id_divider, 0);
+
+ return 0;
+}
+
+int ModulesLoaded(WPARAM wParam, LPARAM lParam) {
+ if(ServiceExists(MS_UPDATE_REGISTER)) {
+ // register with updater
+ Update update = {0};
+ char szVersion[16];
+
+ update.cbSize = sizeof(Update);
+
+ update.szComponentName = pluginInfo.shortName;
+ update.pbVersion = (BYTE *)CreateVersionString(pluginInfo.version, szVersion);
+ update.cpbVersion = strlen((char *)update.pbVersion);
+
+ update.szUpdateURL = UPDATER_AUTOREGISTER;
+
+ // these are the three lines that matter - the archive, the page containing the version string, and the text (or data)
+ // before the version that we use to locate it on the page
+ // (note that if the update URL and the version URL point to standard file listing entries, the backend xml
+ // data will be used to check for updates rather than the actual web page - this is not true for beta urls)
+ update.szBetaUpdateURL = "http://www.scottellis.com.au/miranda_plugins/tipper.zip";
+ update.szBetaVersionURL = "http://www.scottellis.com.au/miranda_plugins/ver_tipper.html";
+ update.pbBetaVersionPrefix = (BYTE *)"Tipper version ";
+
+ update.cpbBetaVersionPrefix = strlen((char *)update.pbBetaVersionPrefix);
+
+ CallService(MS_UPDATE_REGISTER, 0, (WPARAM)&update);
+ }
+
+ if(ServiceExists(MS_FONT_REGISTERW)) {
+ font_id_title.cbSize = sizeof(FontIDW);
+ font_id_title.flags = FIDF_ALLOWEFFECTS;
+ wcscpy(font_id_title.group, TranslateT("Tooltips"));
+ wcscpy(font_id_title.name, TranslateT("Title"));
+ strcpy(font_id_title.dbSettingsGroup, MODULE);
+ strcpy(font_id_title.prefix, "FontFirst");
+ font_id_title.order = 0;
+
+ font_id_title.deffontsettings.charset = DEFAULT_CHARSET;
+ font_id_title.deffontsettings.size = -14;
+ font_id_title.deffontsettings.style = DBFONTF_BOLD;
+ font_id_title.deffontsettings.colour = RGB(255, 0, 0);
+ font_id_title.flags |= FIDF_DEFAULTVALID;
+
+ font_id_labels.cbSize = sizeof(FontIDW);
+ font_id_labels.flags = FIDF_ALLOWEFFECTS;
+ wcscpy(font_id_labels.group, TranslateT("Tooltips"));
+ wcscpy(font_id_labels.name, TranslateT("Labels"));
+ strcpy(font_id_labels.dbSettingsGroup, MODULE);
+ strcpy(font_id_labels.prefix, "FontLabels");
+ font_id_labels.order = 1;
+
+ font_id_labels.deffontsettings.charset = DEFAULT_CHARSET;
+ font_id_labels.deffontsettings.size = -12;
+ font_id_labels.deffontsettings.style = DBFONTF_ITALIC;
+ font_id_labels.deffontsettings.colour = RGB(128, 128, 128);
+ font_id_labels.flags |= FIDF_DEFAULTVALID;
+
+ font_id_values.cbSize = sizeof(FontIDW);
+ font_id_values.flags = FIDF_ALLOWEFFECTS;
+ wcscpy(font_id_values.group, TranslateT("Tooltips"));
+ wcscpy(font_id_values.name, TranslateT("Values"));
+ strcpy(font_id_values.dbSettingsGroup, MODULE);
+ strcpy(font_id_values.prefix, "FontValues");
+ font_id_values.order = 2;
+
+ font_id_values.deffontsettings.charset = DEFAULT_CHARSET;
+ font_id_values.deffontsettings.size = -12;
+ font_id_values.deffontsettings.style = 0;
+ font_id_values.deffontsettings.colour = RGB(0, 0, 0);
+ font_id_values.flags |= FIDF_DEFAULTVALID;
+
+ CallService(MS_FONT_REGISTERW, (WPARAM)&font_id_title, 0);
+ CallService(MS_FONT_REGISTERW, (WPARAM)&font_id_labels, 0);
+ CallService(MS_FONT_REGISTERW, (WPARAM)&font_id_values, 0);
+
+ colour_id_bg.cbSize = sizeof(ColourIDW);
+ wcscpy(colour_id_bg.group, TranslateT("Tooltips"));
+ wcscpy(colour_id_bg.name, TranslateT("Background"));
+ strcpy(colour_id_bg.dbSettingsGroup, MODULE);
+ strcpy(colour_id_bg.setting, "ColourBg");
+ colour_id_bg.defcolour = RGB(219, 219, 219);
+ colour_id_bg.order = 0;
+
+ colour_id_border.cbSize = sizeof(ColourIDW);
+ wcscpy(colour_id_border.group, TranslateT("Tooltips"));
+ wcscpy(colour_id_border.name, TranslateT("Border"));
+ strcpy(colour_id_border.dbSettingsGroup, MODULE);
+ strcpy(colour_id_border.setting, "BorderCol");
+ colour_id_border.defcolour = 0;
+ colour_id_border.order = 0;
+
+ colour_id_divider.cbSize = sizeof(ColourIDW);
+ wcscpy(colour_id_divider.group, TranslateT("Tooltips"));
+ wcscpy(colour_id_divider.name, TranslateT("Dividers"));
+ strcpy(colour_id_divider.dbSettingsGroup, MODULE);
+ strcpy(colour_id_divider.setting, "DividerCol");
+ colour_id_divider.defcolour = 0;
+ colour_id_divider.order = 0;
+
+ colour_id_sidebar.cbSize = sizeof(ColourIDW);
+ wcscpy(colour_id_sidebar.group, TranslateT("Tooltips"));
+ wcscpy(colour_id_sidebar.name, TranslateT("Sidebar"));
+ strcpy(colour_id_sidebar.dbSettingsGroup, MODULE);
+ strcpy(colour_id_sidebar.setting, "SidebarCol");
+ colour_id_sidebar.defcolour = RGB(192, 192, 192);
+ colour_id_sidebar.order = 0;
+
+ CallService(MS_COLOUR_REGISTERW, (WPARAM)&colour_id_bg, 0);
+ CallService(MS_COLOUR_REGISTERW, (WPARAM)&colour_id_border, 0);
+ CallService(MS_COLOUR_REGISTERW, (WPARAM)&colour_id_divider, 0);
+ CallService(MS_COLOUR_REGISTERW, (WPARAM)&colour_id_sidebar, 0);
+
+ ReloadFont(0, 0);
+
+ HookEvent(ME_FONT_RELOAD, ReloadFont);
+ } else {
+ options.title_col = RGB(255, 0, 0); options.label_col = RGB(128, 128, 128), options.value_col = 0;
+ options.bg_col = RGB(219, 219, 219);
+ options.border_col = options.div_col = 0;
+ options.sidebar_col = RGB(192, 192, 192);
+
+ LOGFONT lf = {0};
+ lf.lfCharSet = DEFAULT_CHARSET;
+ lf.lfHeight = -14;
+ lf.lfWeight = FW_BOLD;
+ hFontTitle = CreateFontIndirect(&lf);
+
+ lf.lfHeight = -12;
+ lf.lfWeight = 0;
+ lf.lfItalic = TRUE;
+ hFontLabels = CreateFontIndirect(&lf);
+
+ lf.lfHeight = -12;
+ lf.lfWeight = 0;
+ lf.lfItalic = FALSE;
+ hFontValues = CreateFontIndirect(&lf);
+ }
+
+ hAvChangeEvent = HookEvent(ME_AV_AVATARCHANGED, AvatarChanged);
+ hShowTipEvent = HookEvent(ME_CLC_SHOWINFOTIP, ShowTip);
+ hHideTipEvent = HookEvent(ME_CLC_HIDEINFOTIP, HideTip);
+ hAckEvent = HookEvent(ME_PROTO_ACK, ProtoAck);
+
+ hFramesSBShow = HookEvent(ME_CLIST_FRAMES_SB_SHOW_TOOLTIP, FramesShowSBTip);
+ hFramesSBHide = HookEvent(ME_CLIST_FRAMES_SB_HIDE_TOOLTIP, FramesHideSBTip);
+
+ LoadOptions();
+
+ // set 'time-in'
+ CallService(MS_CLC_SETINFOTIPHOVERTIME, options.time_in, 0);
+
+ return 0;
+}
+
+int Shutdown(WPARAM wParam, LPARAM lParam) {
+ if(hFramesSBShow) UnhookEvent(hFramesSBShow);
+ if(hFramesSBHide) UnhookEvent(hFramesSBHide);
+ if(hAvChangeEvent) UnhookEvent(hAvChangeEvent);
+ if(hShowTipEvent) UnhookEvent(hShowTipEvent);
+ if(hHideTipEvent) UnhookEvent(hHideTipEvent);
+ if(hAckEvent) UnhookEvent(hAckEvent);
+
+ if(hShowTipService) DestroyServiceFunction(hShowTipService);
+ if(hShowTipWService) DestroyServiceFunction(hShowTipWService);
+ if(hHideTipService) DestroyServiceFunction(hHideTipService);
+
+ DeinitMessagePump();
+
+ return 0;
+}
+
+HANDLE hEventPreShutdown, hEventModulesLoaded;
+
+extern "C" int TIPPER_API Load(PLUGINLINK *link) {
+ pluginLink = link;
+ DuplicateHandle(GetCurrentProcess(), GetCurrentThread(), GetCurrentProcess(), &mainThread, THREAD_SET_CONTEXT, FALSE, 0);
+
+ // get the internal malloc/free()
+ memoryManagerInterface.cbSize = sizeof(memoryManagerInterface);
+ CallService(MS_SYSTEM_GET_MMI, 0, (LPARAM)&memoryManagerInterface);
+
+ // don't save status messages
+ CallService(MS_DB_SETSETTINGRESIDENT, (WPARAM)TRUE, (LPARAM)MODULE "/TempStatusMsg");
+
+ // Ensure that the common control DLL is loaded (for listview)
+ INITCOMMONCONTROLSEX icex;
+ icex.dwSize = sizeof(INITCOMMONCONTROLSEX);
+ icex.dwICC = ICC_LISTVIEW_CLASSES;
+ InitCommonControlsEx(&icex);
+
+ if(ServiceExists(MS_LANGPACK_GETCODEPAGE))
+ code_page = CallService(MS_LANGPACK_GETCODEPAGE, 0, 0);
+
+ InitTranslations();
+ InitMessagePump();
+ InitOptions();
+
+ // for compatibility with mToolTip status tooltips
+ hShowTipService = CreateServiceFunction("mToolTip/ShowTip", ShowTip);
+ hShowTipWService = CreateServiceFunction("mToolTip/ShowTipW", ShowTipW);
+ hHideTipService = CreateServiceFunction("mToolTip/HideTip", HideTip);
+
+ hEventPreShutdown = HookEvent(ME_SYSTEM_PRESHUTDOWN, Shutdown);
+ hEventModulesLoaded = HookEvent(ME_SYSTEM_MODULESLOADED, ModulesLoaded);
+
+ return 0;
+}
+
+extern "C" int TIPPER_API Unload() {
+ UnhookEvent(hEventPreShutdown);
+ UnhookEvent(hEventModulesLoaded);
+
+ DeinitOptions();
+ if(ServiceExists(MS_FONT_REGISTERW)) {
+ DeleteObject(hFontTitle);
+ DeleteObject(hFontLabels);
+ DeleteObject(hFontValues);
+ } // otherwise, no need to delete the handle
+ DeinitTranslations();
+ return 0;
+}
diff --git a/tipper/tipper.h b/tipper/tipper.h new file mode 100644 index 0000000..94e4778 --- /dev/null +++ b/tipper/tipper.h @@ -0,0 +1,12 @@ +// The following ifdef block is the standard way of creating macros which make exporting
+// from a DLL simpler. All files within this DLL are compiled with the POPUPS2_EXPORTS
+// symbol defined on the command line. this symbol should not be defined on any project
+// that uses this DLL. This way any other project whose source files include this file see
+// POPUPS2_API functions as being imported from a DLL, whereas this DLL sees symbols
+// defined with this macro as being exported.
+#ifdef TIPPER_EXPORTS
+#define TIPPER_API __declspec(dllexport)
+#else
+#define TIPPER_API __declspec(dllimport)
+#endif
+
diff --git a/tipper/tipper.mdsp b/tipper/tipper.mdsp new file mode 100644 index 0000000..7d09545 --- /dev/null +++ b/tipper/tipper.mdsp @@ -0,0 +1,107 @@ +[Project]
+name=tipper
+type=2
+defaultConfig=0
+
+
+[Debug]
+// compiler
+workingDirectory=
+arguments=
+intermediateFilesDirectory=Debug
+outputFilesDirectory=Debug
+compilerPreprocessor=UNICODE,_UNICODE,TIPPER_EXPORTS
+extraCompilerOptions=
+compilerIncludeDirectory=..\..\include
+noWarning=0
+defaultWarning=0
+allWarning=1
+extraWarning=0
+isoWarning=0
+warningsAsErrors=0
+debugType=1
+debugLevel=2
+exceptionEnabled=1
+runtimeTypeEnabled=1
+optimizeLevel=0
+
+// linker
+libraryPath=
+outputFilename=Debug\tipper.dll
+libraries=unicows,gdi32,comctl32,ws2_32
+extraLinkerOptions=
+ignoreStartupFile=0
+ignoreDefaultLibs=0
+stripExecutableFile=0
+
+// archive
+extraArchiveOptions=
+
+//resource
+resourcePreprocessor=
+resourceIncludeDirectory=
+extraResourceOptions=
+
+[Release]
+// compiler
+workingDirectory=
+arguments=
+intermediateFilesDirectory=Release
+outputFilesDirectory=Release
+compilerPreprocessor=UNICODE,_UNICODE,TIPPER_EXPORTS
+extraCompilerOptions=
+compilerIncludeDirectory=..\..\include
+noWarning=0
+defaultWarning=0
+allWarning=1
+extraWarning=0
+isoWarning=0
+warningAsErrors=0
+debugType=1
+debugLevel=2
+exceptionEnabled=0
+runtimeTypeEnabled=0
+optimizeLevel=4
+
+// linker
+libraryPath=
+outputFilename=Release\tipper.dll
+libraries=unicows,gdi32,comctl32,ws2_32
+extraLinkerOptions=
+ignoreStartupFile=0
+ignoreDefaultLibs=0
+stripExecutableFile=1
+
+// archive
+extraArchiveOptions=
+
+//resource
+resourcePreprocessor=
+resourceIncludeDirectory=
+extraResourceOptions=
+
+[Source]
+1=message_pump.cpp
+2=options.cpp
+3=popwin.cpp
+4=tipper.cpp
+5=translations.cpp
+6=subst.cpp
+[Header]
+1=m_tipper.h
+2=message_pump.h
+3=options.h
+4=popwin.h
+5=resource.h
+6=stdafx.h
+7=tipper.h
+8=translations.h
+9=version.h
+10=subst.h
+[Resource]
+1=resource.rc
+[Other]
+[History]
+tipper.cpp,3326
+message_pump.cpp,1325
+version.h,175
diff --git a/tipper/tipper.rc b/tipper/tipper.rc new file mode 100644 index 0000000..4cd63ae --- /dev/null +++ b/tipper/tipper.rc @@ -0,0 +1,239 @@ +// Microsoft Visual C++ generated resource script.
+//
+#include "resource.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#include "afxres.h"
+
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+// 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
+
+#ifdef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+1 TEXTINCLUDE
+BEGIN
+ "resource.h\0"
+END
+
+2 TEXTINCLUDE
+BEGIN
+ "#include ""afxres.h""\r\n"
+ "\0"
+END
+
+3 TEXTINCLUDE
+BEGIN
+ "\r\n"
+ "\0"
+END
+
+#endif // APSTUDIO_INVOKED
+
+#endif // English (U.S.) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+/////////////////////////////////////////////////////////////////////////////
+// English (Australia) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENA)
+#ifdef _WIN32
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_AUS
+#pragma code_page(1252)
+#endif //_WIN32
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Dialog
+//
+
+IDD_OPT1 DIALOGEX 0, 0, 265, 221
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD
+FONT 8, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+ EDITTEXT IDC_ED_WIDTH,210,11,31,12,ES_RIGHT | ES_AUTOHSCROLL | ES_NUMBER,WS_EX_RIGHT
+ CONTROL "",IDC_SPIN_WIDTH,"msctls_updown32",UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_AUTOBUDDY | UDS_ARROWKEYS,239,11,12,12
+ EDITTEXT IDC_ED_MAXHEIGHT,210,39,31,12,ES_RIGHT | ES_AUTOHSCROLL | ES_NUMBER,WS_EX_RIGHT
+ CONTROL "",IDC_SPIN_MAXHEIGHT,"msctls_updown32",UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_AUTOBUDDY | UDS_ARROWKEYS,239,39,12,12
+ GROUPBOX "Options",IDC_STATIC,147,115,111,99
+ EDITTEXT IDC_ED_TRANS,87,189,33,12,ES_RIGHT | ES_AUTOHSCROLL | ES_NUMBER,WS_EX_RIGHT
+ CONTROL "",IDC_SPIN_TRANS,"msctls_updown32",UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_AUTOBUDDY | UDS_ARROWKEYS | UDS_NOTHOUSANDS,118,189,13,12
+ RTEXT "Opacity(%):",IDC_STATIC,13,192,69,8,0,WS_EX_RIGHT
+ CONTROL "Border",IDC_CHK_BORDER,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,156,156,84,9
+ CONTROL "Round corners (window)",IDC_CHK_ROUNDCORNERS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,156,171,100,9
+ CONTROL "Animate",IDC_CHK_ANIMATE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,156,201,84,9
+ CONTROL "Transparent background",IDC_CHK_TRANSBG,"Button",BS_AUTOCHECKBOX | BS_LEFTTEXT | WS_TABSTOP,18,203,116,10,WS_EX_RIGHT
+ GROUPBOX "Layout",IDC_STATIC,7,3,116,130
+ EDITTEXT IDC_ED_AVSIZE,210,67,31,12,ES_RIGHT | ES_AUTOHSCROLL | ES_NUMBER,WS_EX_RIGHT
+ CONTROL "",IDC_SPIN_AVSIZE,"msctls_updown32",UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_AUTOBUDDY | UDS_ARROWKEYS,239,67,12,12
+ COMBOBOX IDC_CMB_ICON,12,26,107,69,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
+ COMBOBOX IDC_CMB_AV,12,40,107,76,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
+ EDITTEXT IDC_ED_INDENT,78,56,35,12,ES_RIGHT | ES_AUTOHSCROLL | ES_NUMBER,WS_EX_RIGHT
+ CONTROL "",IDC_SPIN_INDENT,"msctls_updown32",UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_AUTOBUDDY | UDS_ARROWKEYS,109,56,12,12
+ RTEXT "Text indent:",IDC_STATIC,26,59,46,8
+ GROUPBOX "Window",IDC_STATIC,128,3,130,110
+ RTEXT "Max width:",IDC_STATIC,152,14,52,8,0,WS_EX_RIGHT
+ RTEXT "Max height:",IDC_STATIC,147,41,57,8,0,WS_EX_RIGHT
+ RTEXT "Avatar size:",IDC_STATIC,147,69,57,8,0,WS_EX_RIGHT
+ CONTROL "Show if list not focused",IDC_CHK_NOFOCUS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,136,98,117,11
+ EDITTEXT IDC_ED_PADDING,78,70,35,12,ES_RIGHT | ES_AUTOHSCROLL | ES_NUMBER,WS_EX_RIGHT
+ CONTROL "",IDC_SPIN_PADDING,"msctls_updown32",UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_AUTOBUDDY | UDS_ARROWKEYS,109,70,12,12
+ RTEXT "General padding:",IDC_STATIC,11,72,60,8
+ EDITTEXT IDC_ED_HOVER,210,81,31,12,ES_RIGHT | ES_AUTOHSCROLL | ES_NUMBER,WS_EX_RIGHT
+ CONTROL "",IDC_SPIN_HOVER,"msctls_updown32",UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_AUTOBUDDY | UDS_ARROWKEYS,239,81,12,12
+ RTEXT "Hover time:",IDC_STATIC,147,83,57,8,0,WS_EX_RIGHT
+ GROUPBOX "XP+",IDC_STATIC,6,182,137,32
+ COMBOBOX IDC_CMB_POS,12,12,107,69,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
+ CONTROL "Shadow",IDC_CHK_SHADOW,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,156,141,84,9
+ CONTROL "Status bar tips",IDC_CHK_SBAR,"Button",BS_AUTOCHECKBOX | BS_MULTILINE | WS_TABSTOP,156,126,85,9
+ GROUPBOX "Alignment",IDC_STATIC,7,135,136,45
+ COMBOBOX IDC_CMB_LV,49,146,43,30,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
+ COMBOBOX IDC_CMB_VV,49,162,43,30,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
+ COMBOBOX IDC_CMB_LH,96,146,43,30,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
+ COMBOBOX IDC_CMB_VH,96,162,43,30,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
+ RTEXT "Labels:",IDC_STATIC,11,148,34,8
+ RTEXT "Values:",IDC_STATIC,11,164,34,8
+ EDITTEXT IDC_ED_MINWIDTH,210,25,31,12,ES_RIGHT | ES_AUTOHSCROLL | ES_NUMBER,WS_EX_RIGHT
+ CONTROL "",IDC_SPIN_MINWIDTH,"msctls_updown32",UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_AUTOBUDDY | UDS_ARROWKEYS,239,25,12,12
+ RTEXT "Min width:",IDC_STATIC,152,27,52,8,0,WS_EX_RIGHT
+ EDITTEXT IDC_ED_MINHEIGHT,210,53,31,12,ES_RIGHT | ES_AUTOHSCROLL | ES_NUMBER,WS_EX_RIGHT
+ CONTROL "",IDC_SPIN_MINHEIGHT,"msctls_updown32",UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_AUTOBUDDY | UDS_ARROWKEYS,239,52,12,12
+ RTEXT "Min height:",IDC_STATIC,146,55,57,8,0,WS_EX_RIGHT
+ EDITTEXT IDC_ED_SBWIDTH,78,112,35,12,ES_RIGHT | ES_AUTOHSCROLL | ES_NUMBER,WS_EX_RIGHT
+ CONTROL "",IDC_SPIN_SBWIDTH,"msctls_updown32",UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_AUTOBUDDY | UDS_ARROWKEYS,110,112,11,12
+ RTEXT "Sidebar width:",IDC_STATIC,14,114,60,8
+ EDITTEXT IDC_ED_TEXTPADDING,78,84,35,12,ES_RIGHT | ES_AUTOHSCROLL | ES_NUMBER,WS_EX_RIGHT
+ CONTROL "",IDC_SPIN_TEXTPADDING,"msctls_updown32",UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_AUTOBUDDY | UDS_ARROWKEYS,110,84,12,12
+ RTEXT "Text padding:",IDC_STATIC,12,85,59,8
+ EDITTEXT IDC_ED_AVPADDING,78,98,35,12,ES_RIGHT | ES_AUTOHSCROLL | ES_NUMBER,WS_EX_RIGHT
+ CONTROL "",IDC_SPIN_AVPADDING,"msctls_updown32",UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_AUTOBUDDY | UDS_ARROWKEYS,110,98,12,12
+ RTEXT "Avatar padding:",IDC_STATIC,12,99,59,8
+ CONTROL "Round corners (avatar)",IDC_CHK_ROUNDCORNERSAV,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,156,186,100,9
+END
+
+IDD_SUBST DIALOGEX 0, 0, 253, 182
+STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Substitution"
+FONT 8, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+ RTEXT "Label:",IDC_STATIC,31,21,48,8,0,WS_EX_RIGHT
+ EDITTEXT IDC_ED_LABEL,84,19,115,14,ES_AUTOHSCROLL
+ CONTROL "Contact protocol module",IDC_CHK_PROTOMOD,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,61,52,141,10
+ RTEXT "Module:",IDC_STATIC,21,74,69,8,0,WS_EX_RIGHT
+ EDITTEXT IDC_ED_MODULE,95,71,115,14,ES_AUTOHSCROLL
+ RTEXT "Setting or prefix:",IDC_STATIC,21,92,69,8,0,WS_EX_RIGHT
+ EDITTEXT IDC_ED_SETTING,95,89,115,14,ES_AUTOHSCROLL
+ LTEXT "Translation:",IDC_STATIC,46,118,139,8
+ COMBOBOX IDC_CMB_TRANSLATE,7,134,239,104,CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP
+ DEFPUSHBUTTON "OK",IDOK,72,161,50,14
+ PUSHBUTTON "Cancel",IDCANCEL,130,161,50,14
+END
+
+IDD_ITEM DIALOGEX 0, 0, 207, 178
+STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Item"
+FONT 8, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+ LTEXT "Label:",IDC_STATIC,32,17,52,8
+ LTEXT "Value:",IDC_STATIC,32,49,52,8
+ EDITTEXT IDC_ED_LABEL,36,30,136,13,ES_AUTOHSCROLL
+ EDITTEXT IDC_ED_VALUE,36,61,136,45,ES_MULTILINE | ES_AUTOVSCROLL | ES_AUTOHSCROLL | ES_WANTRETURN
+ CONTROL "Draw a line above",IDC_CHK_LINEABOVE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,53,112,101,10
+ CONTROL "Value on a new line",IDC_CHK_VALNEWLINE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,53,127,101,10
+ DEFPUSHBUTTON "OK",IDOK,51,157,50,14
+ PUSHBUTTON "Cancel",IDCANCEL,107,157,50,14
+END
+
+IDD_OPT2 DIALOGEX 0, 0, 289, 179
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_VISIBLE | WS_SYSMENU
+FONT 8, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+ GROUPBOX "Items",IDC_STATIC,7,3,135,169
+ LISTBOX IDC_LST_ITEMS,12,13,78,153,LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP
+ PUSHBUTTON "Add...",IDC_BTN_ADD,92,13,48,15
+ PUSHBUTTON "Delete",IDC_BTN_REMOVE,92,30,48,15
+ PUSHBUTTON "Up",IDC_BTN_UP,92,47,48,15
+ PUSHBUTTON "Down",IDC_BTN_DOWN,92,64,48,15
+ GROUPBOX "Substitutions",IDC_STATIC,147,3,135,169
+ PUSHBUTTON "Edit...",IDC_BTN_EDIT,92,81,48,15
+ LISTBOX IDC_LST_SUBST,152,13,78,153,LBS_SORT | LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP
+ PUSHBUTTON "Add...",IDC_BTN_ADD2,232,13,48,15
+ PUSHBUTTON "Delete",IDC_BTN_REMOVE2,232,30,48,15
+ PUSHBUTTON "Edit...",IDC_BTN_EDIT2,232,81,48,15
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// DESIGNINFO
+//
+
+#ifdef APSTUDIO_INVOKED
+GUIDELINES DESIGNINFO
+BEGIN
+ IDD_OPT1, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 258
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 214
+ END
+
+ IDD_SUBST, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 246
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 175
+ END
+
+ IDD_ITEM, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 200
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 171
+ END
+
+ IDD_OPT2, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 282
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 172
+ END
+END
+#endif // APSTUDIO_INVOKED
+
+#endif // English (Australia) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+
+
+/////////////////////////////////////////////////////////////////////////////
+#endif // not APSTUDIO_INVOKED
+
diff --git a/tipper/tipper.sln b/tipper/tipper.sln new file mode 100644 index 0000000..a63a865 --- /dev/null +++ b/tipper/tipper.sln @@ -0,0 +1,20 @@ +
+Microsoft Visual Studio Solution File, Format Version 9.00
+# Visual Studio 2005
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "tipper", "tipper.vcproj", "{2C818919-A38F-44FF-BD91-A6A204AC592A}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Win32 = Debug|Win32
+ Release|Win32 = Release|Win32
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {2C818919-A38F-44FF-BD91-A6A204AC592A}.Debug|Win32.ActiveCfg = Debug|Win32
+ {2C818919-A38F-44FF-BD91-A6A204AC592A}.Debug|Win32.Build.0 = Debug|Win32
+ {2C818919-A38F-44FF-BD91-A6A204AC592A}.Release|Win32.ActiveCfg = Release|Win32
+ {2C818919-A38F-44FF-BD91-A6A204AC592A}.Release|Win32.Build.0 = Release|Win32
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
diff --git a/tipper/tipper.vcproj b/tipper/tipper.vcproj new file mode 100644 index 0000000..9c3c48a --- /dev/null +++ b/tipper/tipper.vcproj @@ -0,0 +1,376 @@ +<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="tipper"
+ ProjectGUID="{2C818919-A38F-44FF-BD91-A6A204AC592A}"
+ RootNamespace="tipper"
+ Keyword="Win32Proj"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="2"
+ CharacterSet="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="../../include"
+ PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;TIPPER_EXPORTS;_UNICODE;UNICODE;MICROSOFT_LAYER_FOR_UNICODE=1"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="1"
+ UsePrecompiledHeader="2"
+ PrecompiledHeaderThrough="common.h"
+ WarningLevel="3"
+ DebugInformationFormat="4"
+ DisableSpecificWarnings="4996"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="unicows.lib comctl32.lib ws2_32.lib"
+ OutputFile="..\..\bin\$(ConfigurationName)\plugins\$(ProjectName).dll"
+ LinkIncremental="2"
+ GenerateManifest="false"
+ GenerateDebugInformation="true"
+ SubSystem="2"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="2"
+ CharacterSet="1"
+ WholeProgramOptimization="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="1"
+ FavorSizeOrSpeed="2"
+ AdditionalIncludeDirectories="../../include"
+ PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;TIPPER_EXPORTS;_UNICODE;UNICODE;MICROSOFT_LAYER_FOR_UNICODE=1"
+ RuntimeLibrary="0"
+ UsePrecompiledHeader="2"
+ PrecompiledHeaderThrough="common.h"
+ WarningLevel="3"
+ DebugInformationFormat="3"
+ DisableSpecificWarnings="4996"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="unicows.lib comctl32.lib ws2_32.lib"
+ OutputFile="..\..\bin\$(ConfigurationName)\plugins\$(ProjectName).dll"
+ LinkIncremental="1"
+ GenerateManifest="false"
+ IgnoreDefaultLibraryNames="Kernel32.lib Advapi32.lib User32.lib Gdi32.lib Shell32.lib Comdlg32.lib Version.lib Mpr.lib Rasapi32.lib Winmm.lib Winspool.lib Vfw32.lib Secur32.lib Oleacc.lib Oledlg.lib Sensapi.lib"
+ GenerateDebugInformation="true"
+ SubSystem="2"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ ImportLibrary="$(IntDir)/$(TargetName).lib"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ EmbedManifest="false"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+ UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+ >
+ <File
+ RelativePath=".\message_pump.cpp"
+ >
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ UsePrecompiledHeader="2"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ UsePrecompiledHeader="2"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\options.cpp"
+ >
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ UsePrecompiledHeader="2"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ UsePrecompiledHeader="2"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\popwin.cpp"
+ >
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ UsePrecompiledHeader="2"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ UsePrecompiledHeader="2"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\subst.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\tipper.cpp"
+ >
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ UsePrecompiledHeader="1"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ UsePrecompiledHeader="1"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\translations.cpp"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl;inc;xsd"
+ UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+ >
+ <File
+ RelativePath=".\common.h"
+ >
+ </File>
+ <File
+ RelativePath=".\message_pump.h"
+ >
+ </File>
+ <File
+ RelativePath=".\options.h"
+ >
+ </File>
+ <File
+ RelativePath=".\popwin.h"
+ >
+ </File>
+ <File
+ RelativePath=".\resource.h"
+ >
+ </File>
+ <File
+ RelativePath=".\subst.h"
+ >
+ </File>
+ <File
+ RelativePath=".\tipper.h"
+ >
+ </File>
+ <File
+ RelativePath=".\translations.h"
+ >
+ </File>
+ <File
+ RelativePath=".\version.h"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Resource Files"
+ Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
+ UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
+ >
+ <File
+ RelativePath=".\resource.rc"
+ >
+ </File>
+ <File
+ RelativePath=".\tipper.rc"
+ >
+ <FileConfiguration
+ Name="Debug|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\version.rc"
+ >
+ <FileConfiguration
+ Name="Debug|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ </FileConfiguration>
+ </File>
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/tipper/translations.cpp b/tipper/translations.cpp new file mode 100644 index 0000000..f22e726 --- /dev/null +++ b/tipper/translations.cpp @@ -0,0 +1,654 @@ +#include "common.h" +#include "translations.h" +#include <winsock.h> +#include <time.h> + +int num_tfuncs = 0; +DBVTranslation *translations = 0; + +DWORD next_func_id; + +bool unicode_system; +HANDLE hServiceAdd; + +void AddTranslation(DBVTranslation *new_trans) { + num_tfuncs++; + + translations = (DBVTranslation *)realloc(translations, sizeof(DBVTranslation) * num_tfuncs); + translations[num_tfuncs - 1] = *new_trans; + + char setting[256]; +#ifdef _UNICODE + WideCharToMultiByte(code_page, 0, new_trans->name, -1, setting, 256, 0, 0); +#else + strncpy(setting, new_trans.name, 256); +#endif + + if(_tcscmp(new_trans->name, _T("[No translation]")) == 0) + translations[num_tfuncs - 1].id = 0; + else { + DWORD id = DBGetContactSettingDword(0, MODULE, setting, 0); + if(id != 0) { + translations[num_tfuncs - 1].id = id; + if(next_func_id <= id) next_func_id = id + 1; + } else { + translations[num_tfuncs - 1].id = next_func_id++; + DBWriteContactSettingDword(0, MODULE, setting, translations[num_tfuncs - 1].id); + } + + DBWriteContactSettingDword(0, MODULE, "NextFuncId", next_func_id); + } +} + +TCHAR *null_translation(HANDLE hContact, const char *module_name, const char *setting_name, TCHAR *buff, int bufflen) { + DBVARIANT dbv; + buff[0] = 0; + if(ServiceExists(MS_DB_CONTACT_GETSETTING_STR)) { + if(DBGetContactSettingStringUtf(hContact, module_name, setting_name, &dbv)) + return 0; + } else { + if(DBGetContactSetting(hContact, module_name, setting_name, &dbv)) + return 0; + } + + switch(dbv.type) { + case DBVT_DELETED: + DBFreeVariant(&dbv); + return 0; + case DBVT_BYTE: + _itow(dbv.bVal, buff, 10); + break; + case DBVT_WORD: + _ltow(dbv.wVal, buff, 10); + break; + case DBVT_DWORD: + _ltow(dbv.dVal, buff, 10); + break; + case DBVT_ASCIIZ: + MultiByteToWideChar(code_page, 0, dbv.pszVal, -1, buff, bufflen); + buff[bufflen - 1] = 0; + break; + case DBVT_UTF8: + MultiByteToWideChar(CP_UTF8, 0, dbv.pszVal, -1, buff, bufflen); + buff[bufflen - 1] = 0; + break; + //case DBVT_WCHAR: + //wcsncpy(buff, dbv.pwszVal, 1024); + //buff[bufflen - 1] = 0; + //break; + case DBVT_BLOB: + default: + DBFreeVariant(&dbv); + return 0; + + + } + DBFreeVariant(&dbv); + + if(wcslen(buff) == 0) + return 0; + return buff; +} + +TCHAR *timestamp_to_short_date(HANDLE hContact, const char *module_name, const char *setting_name, TCHAR *buff, int bufflen) { + DWORD ts = DBGetContactSettingDword(hContact, module_name, setting_name, 0); + if(ts == 0) return 0; + + if(unicode_system) { + DBTIMETOSTRINGT dbt = {0}; + dbt.cbDest = bufflen; + dbt.szDest = buff; + dbt.szFormat = _T("d"); + CallService(MS_DB_TIME_TIMESTAMPTOSTRINGT, (WPARAM)ts, (LPARAM)&dbt); + } else { + char buffA[1024]; + DBTIMETOSTRING dbt = {0}; + dbt.cbDest = sizeof(buffA); + dbt.szDest = buffA; + dbt.szFormat = "d"; + CallService(MS_DB_TIME_TIMESTAMPTOSTRING, (WPARAM)ts, (LPARAM)&dbt); + MultiByteToWideChar(code_page, 0, buffA, -1, buff, bufflen); + } + + buff[bufflen - 1] = 0; + return buff; +} + +TCHAR *timestamp_to_long_date(HANDLE hContact, const char *module_name, const char *setting_name, TCHAR *buff, int bufflen) { + DWORD ts = DBGetContactSettingDword(hContact, module_name, setting_name, 0); + if(ts == 0) return 0; + + if(unicode_system) { + DBTIMETOSTRINGT dbt = {0}; + dbt.cbDest = bufflen; + dbt.szDest = buff; + dbt.szFormat = _T("D"); + CallService(MS_DB_TIME_TIMESTAMPTOSTRINGT, (WPARAM)ts, (LPARAM)&dbt); + } else { + char buffA[1024]; + DBTIMETOSTRING dbt = {0}; + dbt.cbDest = sizeof(buffA); + dbt.szDest = buffA; + dbt.szFormat = "D"; + CallService(MS_DB_TIME_TIMESTAMPTOSTRING, (WPARAM)ts, (LPARAM)&dbt); + MultiByteToWideChar(code_page, 0, buffA, -1, buff, bufflen); + } + + buff[bufflen - 1] = 0; + return buff; +} + +TCHAR *timestamp_to_time(HANDLE hContact, const char *module_name, const char *setting_name, TCHAR *buff, int bufflen) { + DWORD ts = DBGetContactSettingDword(hContact, module_name, setting_name, 0); + if(ts == 0) return 0; + + if(unicode_system) { + DBTIMETOSTRINGT dbt = {0}; + dbt.cbDest = bufflen; + dbt.szDest = buff; + dbt.szFormat = _T("s"); + CallService(MS_DB_TIME_TIMESTAMPTOSTRINGT, (WPARAM)ts, (LPARAM)&dbt); + } else { + char buffA[1024]; + DBTIMETOSTRING dbt = {0}; + dbt.cbDest = sizeof(buffA); + dbt.szDest = buffA; + dbt.szFormat = "s"; + CallService(MS_DB_TIME_TIMESTAMPTOSTRING, (WPARAM)ts, (LPARAM)&dbt); + MultiByteToWideChar(code_page, 0, buffA, -1, buff, bufflen); + } + + buff[bufflen - 1] = 0; + return buff; +} + +TCHAR *timestamp_to_time_no_secs(HANDLE hContact, const char *module_name, const char *setting_name, TCHAR *buff, int bufflen) { + DWORD ts = DBGetContactSettingDword(hContact, module_name, setting_name, 0); + if(ts == 0) return 0; + + if(unicode_system) { + DBTIMETOSTRINGT dbt = {0}; + dbt.cbDest = bufflen; + dbt.szDest = buff; + dbt.szFormat = _T("t"); + CallService(MS_DB_TIME_TIMESTAMPTOSTRINGT, (WPARAM)ts, (LPARAM)&dbt); + } else { + char buffA[1024]; + DBTIMETOSTRING dbt = {0}; + dbt.cbDest = sizeof(buffA); + dbt.szDest = buffA; + dbt.szFormat = "t"; + CallService(MS_DB_TIME_TIMESTAMPTOSTRING, (WPARAM)ts, (LPARAM)&dbt); + MultiByteToWideChar(code_page, 0, buffA, -1, buff, bufflen); + } + + return buff; +} + +TCHAR *timestamp_to_time_difference(HANDLE hContact, const char *module_name, const char *setting_name, TCHAR *buff, int bufflen) { + DWORD ts = DBGetContactSettingDword(hContact, module_name, setting_name, 0); + DWORD t = (DWORD)time(0); + if(ts == 0) return 0; + + DWORD diff = (t - ts); + int d = (diff / 60 / 60 / 24); + int h = (diff - d * 60 * 60 * 24) / 60 / 60; + int m = (diff - d * 60 * 60 * 24 - h * 60 * 60) / 60; + if(d > 0) + mir_sntprintf(buff, bufflen, TranslateT("%dd %dh %dm"), d, h, m); + else if(h > 0) + mir_sntprintf(buff, bufflen, TranslateT("%dh %dm"), h, m); + else + mir_sntprintf(buff, bufflen, TranslateT("%dm"), m); + + return buff; +} + +TCHAR *seconds_to_time_difference(HANDLE hContact, const char *module_name, const char *setting_name, TCHAR *buff, int bufflen) { + + DWORD diff = DBGetContactSettingDword(hContact, module_name, setting_name, 0); + int d = (diff / 60 / 60 / 24); + int h = (diff - d * 60 * 60 * 24) / 60 / 60; + int m = (diff - d * 60 * 60 * 24 - h * 60 * 60) / 60; + if(d > 0) + mir_sntprintf(buff, bufflen, TranslateT("%dd %dh %dm"), d, h, m); + else if(h > 0) + mir_sntprintf(buff, bufflen, TranslateT("%dh %dm"), h, m); + else + mir_sntprintf(buff, bufflen, TranslateT("%dm"), m); + + return buff; +} + +TCHAR *word_to_status_desc(HANDLE hContact, const char *module_name, const char *setting_name, TCHAR *buff, int bufflen) { + int status = DBGetContactSettingWord(hContact, module_name, setting_name, ID_STATUS_OFFLINE); + char *strptr = (char *)CallService(MS_CLIST_GETSTATUSMODEDESCRIPTION, (WPARAM)status, (LPARAM)0); + MultiByteToWideChar(code_page, 0, strptr, -1, buff, bufflen); + buff[bufflen - 1] = 0; + return buff; +} + +TCHAR *byte_to_yesno(HANDLE hContact, const char *module_name, const char *setting_name, TCHAR *buff, int bufflen) { + DBVARIANT dbv; + if(!DBGetContactSetting(hContact, module_name, setting_name, &dbv)) { + if(dbv.type == DBVT_BYTE) { + if(dbv.bVal != 0) + _tcsncpy(buff, _T("Yes"), bufflen); + else + _tcsncpy(buff, _T("No"), bufflen); + buff[bufflen - 1] = 0; + DBFreeVariant(&dbv); + return buff; + } + DBFreeVariant(&dbv); + } + return 0; +} + +TCHAR *byte_to_mf(HANDLE hContact, const char *module_name, const char *setting_name, TCHAR *buff, int bufflen) { + BYTE val = DBGetContactSettingByte(hContact, module_name, setting_name, 0); + if(val == 'F') + _tcsncpy(buff, TranslateT("Female"), bufflen); + else if(val == 'M') + _tcsncpy(buff, TranslateT("Male"), bufflen); + else + return 0; + + buff[bufflen - 1] = 0; + return buff; +} + +TCHAR *word_to_country(HANDLE hContact, const char *module_name, const char *setting_name, TCHAR *buff, int bufflen) { + char *cname = 0; + WORD cid = DBGetContactSettingWord(hContact, module_name, setting_name, (WORD)-1); + if(cid != (WORD)-1 && ServiceExists(MS_UTILS_GETCOUNTRYBYNUMBER) && (cname = (char *)CallService(MS_UTILS_GETCOUNTRYBYNUMBER, cid, 0)) != 0) { + if(strcmp(cname, "Unknown") == 0) + return 0; + MultiByteToWideChar(code_page, 0, Translate(cname), -1, buff, bufflen); + buff[bufflen - 1] = 0; + return buff; + } + return 0; +} + +TCHAR *dword_to_ip(HANDLE hContact, const char *module_name, const char *setting_name, TCHAR *buff, int bufflen) { + DWORD ip = DBGetContactSettingDword(hContact, module_name, setting_name, (WORD)0); + if(ip) { + in_addr in; + in.S_un.S_addr = htonl(ip); + MultiByteToWideChar(code_page, 0, inet_ntoa(in), -1, buff, bufflen); + buff[bufflen - 1] = 0; + return buff; + } + return 0; +} + +bool GetInt(const DBVARIANT &dbv, int *val) { + if(!val) return false; + + switch(dbv.type) { + case DBVT_BYTE: + if(val) *val = (int)dbv.bVal; + return true; + case DBVT_WORD: + if(val) *val = (int)dbv.wVal; + return true; + case DBVT_DWORD: + if(val) *val = (int)dbv.dVal; + return true; + } + return false; +} + +TCHAR *day_month_year_to_date(HANDLE hContact, const char *module_name, const char *prefix, TCHAR *buff, int bufflen) { + DBVARIANT dbv; + char setting_name[256]; + mir_snprintf(setting_name, 256, "%sDay", prefix); + if(!DBGetContactSetting(hContact, module_name, setting_name, &dbv)) { + int day = 0; + if(GetInt(dbv, &day)) { + DBFreeVariant(&dbv); + mir_snprintf(setting_name, 256, "%sMonth", prefix); + int month = 0; + if(!DBGetContactSetting(hContact, module_name, setting_name, &dbv)) { + if(GetInt(dbv, &month)) { + DBFreeVariant(&dbv); + mir_snprintf(setting_name, 256, "%sYear", prefix); + int year = 0; + if(!DBGetContactSetting(hContact, module_name, setting_name, &dbv)) { + if(GetInt(dbv, &year)) { + DBFreeVariant(&dbv); + + SYSTEMTIME st = {0}; + st.wDay = day; + st.wMonth = month; + st.wYear = year; + + GetDateFormat(LOCALE_USER_DEFAULT, 0, &st, 0, buff, bufflen); + return buff; + } else + DBFreeVariant(&dbv); + } + } else + DBFreeVariant(&dbv); + } + } else + DBFreeVariant(&dbv); + } + return 0; +} + +TCHAR *day_month_year_to_age(HANDLE hContact, const char *module_name, const char *prefix, TCHAR *buff, int bufflen) { + DBVARIANT dbv; + char setting_name[256]; + mir_snprintf(setting_name, 256, "%sDay", prefix); + if(!DBGetContactSetting(hContact, module_name, setting_name, &dbv)) { + int day = 0; + if(GetInt(dbv, &day)) { + DBFreeVariant(&dbv); + mir_snprintf(setting_name, 256, "%sMonth", prefix); + int month = 0; + if(!DBGetContactSetting(hContact, module_name, setting_name, &dbv)) { + if(GetInt(dbv, &month)) { + DBFreeVariant(&dbv); + mir_snprintf(setting_name, 256, "%sYear", prefix); + int year = 0; + if(!DBGetContactSetting(hContact, module_name, setting_name, &dbv)) { + if(GetInt(dbv, &year)) { + DBFreeVariant(&dbv); + + SYSTEMTIME now; + GetLocalTime(&now); + + int age = now.wYear - year; + if(now.wMonth < month || (now.wMonth == month && now.wDay < day)) + age--; + mir_sntprintf(buff, bufflen, _T("%d"), age); + return buff; + } else + DBFreeVariant(&dbv); + } + } else + DBFreeVariant(&dbv); + } + } else + DBFreeVariant(&dbv); + } + return 0; +} + +TCHAR *hours_minutes_seconds_to_time(HANDLE hContact, const char *module_name, const char *prefix, TCHAR *buff, int bufflen) { + DBVARIANT dbv; + char setting_name[256]; + mir_snprintf(setting_name, 256, "%sHours", prefix); + if(!DBGetContactSetting(hContact, module_name, setting_name, &dbv)) { + int hours = 0; + if(GetInt(dbv, &hours)) { + DBFreeVariant(&dbv); + mir_snprintf(setting_name, 256, "%sMinutes", prefix); + int minutes = 0; + if(!DBGetContactSetting(hContact, module_name, setting_name, &dbv)) { + if(GetInt(dbv, &minutes)) { + DBFreeVariant(&dbv); + mir_snprintf(setting_name, 256, "%sSeconds", prefix); + int seconds = 0; + if(!DBGetContactSetting(hContact, module_name, setting_name, &dbv)) { + GetInt(dbv, &seconds); + DBFreeVariant(&dbv); + } + + SYSTEMTIME st = {0}; + st.wHour = hours; + st.wMinute = minutes; + st.wSecond = seconds; + + GetTimeFormat(LOCALE_USER_DEFAULT, 0, &st, 0, buff, bufflen); + return buff; + } else + DBFreeVariant(&dbv); + } + } else + DBFreeVariant(&dbv); + } + return 0; +} + +TCHAR *hours_minutes_to_time(HANDLE hContact, const char *module_name, const char *prefix, TCHAR *buff, int bufflen) { + DBVARIANT dbv; + char setting_name[256]; + mir_snprintf(setting_name, 256, "%sHours", prefix); + if(!DBGetContactSetting(hContact, module_name, setting_name, &dbv)) { + int hours = 0; + if(GetInt(dbv, &hours)) { + DBFreeVariant(&dbv); + mir_snprintf(setting_name, 256, "%sMinutes", prefix); + int minutes = 0; + if(!DBGetContactSetting(hContact, module_name, setting_name, &dbv)) { + if(GetInt(dbv, &minutes)) { + DBFreeVariant(&dbv); + + SYSTEMTIME st = {0}; + st.wHour = hours; + st.wMinute = minutes; + + GetTimeFormat(LOCALE_USER_DEFAULT, TIME_NOSECONDS, &st, 0, buff, bufflen); + return buff; + } else + DBFreeVariant(&dbv); + } + } else + DBFreeVariant(&dbv); + } + return 0; +} + +TCHAR *day_month_year_hours_minutes_seconds_to_time_difference(HANDLE hContact, const char *module_name, const char *prefix, TCHAR *buff, int bufflen) { + DBVARIANT dbv; + char setting_name[256]; + mir_snprintf(setting_name, 256, "%sDay", prefix); + if(!DBGetContactSetting(hContact, module_name, setting_name, &dbv)) { + int day = 0; + if(GetInt(dbv, &day)) { + DBFreeVariant(&dbv); + mir_snprintf(setting_name, 256, "%sMonth", prefix); + int month = 0; + if(!DBGetContactSetting(hContact, module_name, setting_name, &dbv)) { + if(GetInt(dbv, &month)) { + DBFreeVariant(&dbv); + mir_snprintf(setting_name, 256, "%sYear", prefix); + int year = 0; + if(!DBGetContactSetting(hContact, module_name, setting_name, &dbv)) { + if(GetInt(dbv, &year)) { + DBFreeVariant(&dbv); + mir_snprintf(setting_name, 256, "%sHours", prefix); + if(!DBGetContactSetting(hContact, module_name, setting_name, &dbv)) { + int hours = 0; + if(GetInt(dbv, &hours)) { + DBFreeVariant(&dbv); + mir_snprintf(setting_name, 256, "%sMinutes", prefix); + int minutes = 0; + if(!DBGetContactSetting(hContact, module_name, setting_name, &dbv)) { + if(GetInt(dbv, &minutes)) { + DBFreeVariant(&dbv); + mir_snprintf(setting_name, 256, "%sSeconds", prefix); + int seconds = 0; + if(!DBGetContactSetting(hContact, module_name, setting_name, &dbv)) { + GetInt(dbv, &seconds); + DBFreeVariant(&dbv); + } + + SYSTEMTIME st = {0}, st_now; + st.wDay = day; + st.wMonth = month; + st.wYear = year; + st.wHour = hours; + st.wMinute = minutes; + st.wSecond = seconds; + GetLocalTime(&st_now); + + FILETIME ft, ft_now; + SystemTimeToFileTime(&st, &ft); + SystemTimeToFileTime(&st_now, &ft_now); + + LARGE_INTEGER li, li_now; + li.HighPart = ft.dwHighDateTime; li.LowPart = ft.dwLowDateTime; + li_now.HighPart = ft_now.dwHighDateTime; li_now.LowPart = ft_now.dwLowDateTime; + + long diff = (long)((li_now.QuadPart - li.QuadPart) / (LONGLONG)10000000LL); + int y = diff / 60 / 60 / 24 / 365; + int d = (diff - y * 60 * 60 * 24 * 365) / 60 / 60 / 24; + int h = (diff - y * 60 * 60 * 24 * 365 - d * 60 * 60 * 24) / 60 / 60; + int m = (diff - y * 60 * 60 * 24 * 365 - d * 60 * 60 * 24 - h * 60 * 60) / 60; + if(y != 0) + mir_sntprintf(buff, bufflen, TranslateT("%dy %dd %dh %dm"), y, d, h, m); + else if(d != 0) + mir_sntprintf(buff, bufflen, TranslateT("%dd %dh %dm"), d, h, m); + else if(h != 0) + mir_sntprintf(buff, bufflen, TranslateT("%dh %dm"), h, m); + else + mir_sntprintf(buff, bufflen, TranslateT("%dm"), m); + + return buff; + } else + DBFreeVariant(&dbv); + } + } else + DBFreeVariant(&dbv); + } + } else + DBFreeVariant(&dbv); + } + } else + DBFreeVariant(&dbv); + } + } else + DBFreeVariant(&dbv); + } + return 0; +} + +TCHAR *empty_xStatus_name_to_default_name(HANDLE hContact, const char *module_name, const char *setting_name, TCHAR *buff, int bufflen) { + TCHAR szDefaultName[1024];
+ ICQ_CUSTOM_STATUS xstatus={0};
+
+ if(null_translation(hContact, module_name, setting_name, buff, bufflen))
+ return buff;
+
+ int status = (int)DBGetContactSettingByte(hContact, module_name, "XStatusId", 0);
+ if(!status) return 0;
+
+ xstatus.cbSize = sizeof(ICQ_CUSTOM_STATUS);
+ xstatus.flags = CSSF_MASK_NAME|CSSF_DEFAULT_NAME|CSSF_TCHAR;
+ xstatus.ptszName = szDefaultName;
+ xstatus.wParam = (WPARAM *)&status;
+ if(CallProtoService(module_name, PS_ICQ_GETCUSTOMSTATUSEX, 0, (LPARAM)&xstatus))
+ return 0;
+
+ _tcsncpy(buff, szDefaultName, bufflen);
+ buff[bufflen - 1] = 0;
+
+ return buff;
+} + +int ServiceAddTranslation(WPARAM wParam, LPARAM lParam) { + if(!lParam) return 1; + + DBVTranslation *trans = (DBVTranslation *)lParam; + AddTranslation(trans); + + return 0; +} + +void InitTranslations() { + + char szVer[128]; + unicode_system = (CallService(MS_SYSTEM_GETVERSIONTEXT, (WPARAM)sizeof(szVer), (LPARAM)szVer) == 0 && strstr(szVer, "Unicode")); + + next_func_id = DBGetContactSettingDword(0, MODULE, "NextFuncId", 1); + +#define INT_TRANS_COUNT 18 + DBVTranslation internal_translations[INT_TRANS_COUNT] = { + { + (TranslateFunc*)null_translation, + _T("[No translation]"), + }, + { + (TranslateFunc*)word_to_status_desc, + _T("WORD to status description") + }, + { + (TranslateFunc*)timestamp_to_time, + _T("DWORD timestamp to time") + }, + { + (TranslateFunc*)timestamp_to_time_difference, + _T("DWORD timestamp to time difference") + }, + { + (TranslateFunc*)byte_to_yesno, + _T("BYTE to Yes/No") + }, + { + (TranslateFunc*)byte_to_mf, + _T("BYTE to Male/Female (ICQ)") + }, + { + (TranslateFunc*)word_to_country, + _T("WORD to country name") + }, + { + (TranslateFunc*)dword_to_ip, + _T("DWORD to ip address") + }, + { + (TranslateFunc*)day_month_year_to_date, + _T("<prefix>Day|Month|Year to date") + }, + { + (TranslateFunc*)day_month_year_to_age, + _T("<prefix>Day|Month|Year to age") + }, + { + (TranslateFunc*)hours_minutes_seconds_to_time, + _T("<prefix>Hours|Minutes|Seconds to time") + }, + { + (TranslateFunc*)day_month_year_hours_minutes_seconds_to_time_difference, + _T("<prefix>Day|Month|Year|Hours|Minutes|Seconds to time difference") + }, + { + (TranslateFunc*)timestamp_to_time_no_secs, + _T("DWORD timestamp to time (no seconds)") + }, + { + (TranslateFunc*)hours_minutes_to_time, + _T("<prefix>Hours|Minutes to time") + }, + { + (TranslateFunc*)timestamp_to_short_date, + _T("DWORD timestamp to date (short)") + }, + { + (TranslateFunc*)timestamp_to_long_date, + _T("DWORD timestamp to date (long)") + }, + { + (TranslateFunc*)empty_xStatus_name_to_default_name, + _T("xStatus: empty xStatus name to default name") + }, + { + (TranslateFunc*)seconds_to_time_difference, + _T("DWORD seconds to time difference") + } + }; + + for(int i = 0; i < INT_TRANS_COUNT; i++) AddTranslation(&internal_translations[i]); + + hServiceAdd = CreateServiceFunction(MS_TIPPER_ADDTRANSLATION, ServiceAddTranslation); +} + +void DeinitTranslations() { + DestroyServiceFunction(hServiceAdd); + free(translations); +} + diff --git a/tipper/translations.h b/tipper/translations.h new file mode 100644 index 0000000..66dc137 --- /dev/null +++ b/tipper/translations.h @@ -0,0 +1,14 @@ +#ifndef _TRANSLATIONS_INC
+#define _TRANSLATIONS_INC
+
+#include "m_tipper.h"
+
+extern bool unicode_system;
+
+extern int num_tfuncs;
+extern DBVTranslation *translations;
+
+void InitTranslations();
+void DeinitTranslations();
+
+#endif
diff --git a/tipper/version.h b/tipper/version.h new file mode 100644 index 0000000..a3a11e4 --- /dev/null +++ b/tipper/version.h @@ -0,0 +1,23 @@ +#ifndef __VERSION_H_INCLUDED
+#define __VERSION_H_INCLUDED
+
+#define __MAJOR_VERSION 0
+#define __MINOR_VERSION 2
+#define __RELEASE_NUM 4
+#define __BUILD_NUM 1
+
+#define __FILEVERSION_STRING __MAJOR_VERSION,__MINOR_VERSION,__RELEASE_NUM,__BUILD_NUM
+#define __FILEVERSION_STRING_DOTS __MAJOR_VERSION.__MINOR_VERSION.__RELEASE_NUM.__BUILD_NUM
+#define __STRINGIFY(x) #x
+#define __VERSION_STRING __STRINGIFY(__FILEVERSION_STRING_DOTS)
+
+#define __DESC "Tool Tip notification windows"
+#define __AUTHOR "Scott Ellis"
+#define __AUTHOREMAIL "mail@scottellis.com.au"
+#define __COPYRIGHT "© 2005,2006 Scott Ellis"
+#define __AUTHORWEB "http://www.scottellis.com.au"
+
+#define __PLUGIN_NAME "Tipper"
+#define __FILENAME "tipper.dll"
+
+#endif //__VERSION_H_INCLUDED
diff --git a/tipper/version.rc b/tipper/version.rc new file mode 100644 index 0000000..f8bed6d --- /dev/null +++ b/tipper/version.rc @@ -0,0 +1,33 @@ +
+#include <windows.h>
+#include "version.h"
+
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION __FILEVERSION_STRING
+ PRODUCTVERSION __FILEVERSION_STRING
+ FILEFLAGSMASK 0x3fL
+#ifdef _DEBUG
+ FILEFLAGS 0x1L
+#else
+ FILEFLAGS 0x0L
+#endif
+ FILEOS 0x40004L
+ FILETYPE 0x1L
+ FILESUBTYPE 0x0L
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "000004b0"
+ BEGIN
+ VALUE "Author", __AUTHOR
+ VALUE "FileDescription", __DESC
+ VALUE "InternalName", __PLUGIN_NAME
+ VALUE "LegalCopyright", __COPYRIGHT
+ VALUE "OriginalFilename", __FILENAME
+ END
+ END
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x0, 1200
+ END
+END
|