summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGeorge Hazan <ghazan@miranda.im>2022-05-10 16:08:57 +0300
committerGeorge Hazan <ghazan@miranda.im>2022-05-10 16:09:14 +0300
commit2e21c98da8ddec95194a1a65b3a9f04fe86dfaa1 (patch)
treebe3127c3e0d4b51332ddcd1bcc26b4c987fe61de
parentff66933b6399d8cd5636622d678c66960ae87fc5 (diff)
добавляем начатки UI classes для Linux
-rw-r--r--src/mir_core/mir_core.mk152
-rw-r--r--src/mir_core/mir_core.project11
-rw-r--r--src/mir_core/src/Linux/CCtrlBase.cpp224
-rw-r--r--src/mir_core/src/Linux/CCtrlButton.cpp54
-rw-r--r--src/mir_core/src/Linux/CCtrlCheck.cpp68
-rw-r--r--src/mir_core/src/Linux/CCtrlClc.cpp207
-rw-r--r--src/mir_core/src/Linux/CCtrlColor.cpp61
-rw-r--r--src/mir_core/src/Linux/CCtrlCombo.cpp185
-rw-r--r--src/mir_core/src/Linux/CCtrlData.cpp52
-rw-r--r--src/mir_core/src/Linux/CCtrlEdit.cpp68
-rw-r--r--src/mir_core/src/Linux/CCtrlHyperlink.cpp54
-rw-r--r--src/mir_core/src/Linux/CCtrlLabel.cpp31
-rw-r--r--src/mir_core/src/Linux/CCtrlListBox.cpp160
-rw-r--r--src/mir_core/src/Linux/CCtrlListView.cpp551
-rw-r--r--src/mir_core/src/Linux/CCtrlMButton.cpp62
-rw-r--r--src/mir_core/src/Linux/CCtrlPages.cpp411
-rw-r--r--src/mir_core/src/Linux/CCtrlSlider.cpp70
-rw-r--r--src/mir_core/src/Linux/CCtrlSpin.cpp81
-rw-r--r--src/mir_core/src/Linux/CCtrlTreeOpts.cpp216
-rw-r--r--src/mir_core/src/Linux/CCtrlTreeView.cpp817
-rw-r--r--src/mir_core/src/Linux/CDbLink.cpp92
-rw-r--r--src/mir_core/src/Linux/CDlgBase.cpp506
-rw-r--r--src/mir_core/src/Linux/CProgress.cpp53
-rw-r--r--src/mir_core/src/Linux/CSplitter.cpp83
-rw-r--r--src/mir_core/src/Linux/CTimer.cpp90
-rw-r--r--src/mir_core/src/Linux/cctrldate.cpp49
26 files changed, 4338 insertions, 70 deletions
diff --git a/src/mir_core/mir_core.mk b/src/mir_core/mir_core.mk
index 1b9f3e372d..875f47a2da 100644
--- a/src/mir_core/mir_core.mk
+++ b/src/mir_core/mir_core.mk
@@ -38,7 +38,7 @@ PreprocessOnlySwitch :=-E
ObjectsFileList :=$(IntermediateDirectory)/ObjectsList.txt
PCHCompileFlags :=
LinkOptions := $(shell wx-config --libs --unicode=yes)
-IncludePath := $(IncludeSwitch). $(IncludeSwitch). $(IncludeSwitch)../../include
+IncludePath := $(IncludeSwitch). $(IncludeSwitch). $(IncludeSwitch)../../include $(IncludeSwitch)"`pkg-config --cflags --libs elementary`"
IncludePCH :=
RcIncludePath :=
Libs :=
@@ -62,8 +62,9 @@ AS := as
## User defined environment variables
##
CodeLiteDir:=/usr/share/codelite
-Objects0=$(IntermediateDirectory)/src_binbuffer.cpp$(ObjectSuffix) $(IntermediateDirectory)/src_bitmaps.cpp$(ObjectSuffix) $(IntermediateDirectory)/src_lists.cpp$(ObjectSuffix) $(IntermediateDirectory)/src_Linux_fileutil.cpp$(ObjectSuffix) $(IntermediateDirectory)/src_memory.cpp$(ObjectSuffix) $(IntermediateDirectory)/src_utils.cpp$(ObjectSuffix) $(IntermediateDirectory)/src_Linux_strutil.cpp$(ObjectSuffix) $(IntermediateDirectory)/src_tinyxml2_utils.cpp$(ObjectSuffix) $(IntermediateDirectory)/src_utf.cpp$(ObjectSuffix) $(IntermediateDirectory)/src_tinyxml2.cpp$(ObjectSuffix) \
- $(IntermediateDirectory)/src_http.cpp$(ObjectSuffix) $(IntermediateDirectory)/src_stdafx.cxx$(ObjectSuffix) $(IntermediateDirectory)/src_sha256.cpp$(ObjectSuffix) $(IntermediateDirectory)/src_db.cpp$(ObjectSuffix) $(IntermediateDirectory)/src_sha1.cpp$(ObjectSuffix) $(IntermediateDirectory)/src_mstring.cpp$(ObjectSuffix) $(IntermediateDirectory)/src_md5.cpp$(ObjectSuffix) $(IntermediateDirectory)/src_logger.cpp$(ObjectSuffix)
+Objects0=$(IntermediateDirectory)/src_logger.cpp$(ObjectSuffix) $(IntermediateDirectory)/src_md5.cpp$(ObjectSuffix) $(IntermediateDirectory)/src_mstring.cpp$(ObjectSuffix) $(IntermediateDirectory)/src_db.cpp$(ObjectSuffix) $(IntermediateDirectory)/src_Linux_CDlgBase.cpp$(ObjectSuffix) $(IntermediateDirectory)/src_stdafx.cxx$(ObjectSuffix) $(IntermediateDirectory)/src_http.cpp$(ObjectSuffix) $(IntermediateDirectory)/src_tinyxml2.cpp$(ObjectSuffix) $(IntermediateDirectory)/src_sha256.cpp$(ObjectSuffix) $(IntermediateDirectory)/src_utf.cpp$(ObjectSuffix) \
+ $(IntermediateDirectory)/src_Linux_strutil.cpp$(ObjectSuffix) $(IntermediateDirectory)/src_utils.cpp$(ObjectSuffix) $(IntermediateDirectory)/src_memory.cpp$(ObjectSuffix) $(IntermediateDirectory)/src_Linux_CDbLink.cpp$(ObjectSuffix) $(IntermediateDirectory)/src_Linux_CCtrlBase.cpp$(ObjectSuffix) $(IntermediateDirectory)/src_tinyxml2_utils.cpp$(ObjectSuffix) $(IntermediateDirectory)/src_Linux_fileutil.cpp$(ObjectSuffix) $(IntermediateDirectory)/src_lists.cpp$(ObjectSuffix) $(IntermediateDirectory)/src_bitmaps.cpp$(ObjectSuffix) $(IntermediateDirectory)/src_binbuffer.cpp$(ObjectSuffix) \
+ $(IntermediateDirectory)/src_sha1.cpp$(ObjectSuffix)
@@ -95,96 +96,111 @@ PreBuild:
##
## Objects
##
-$(IntermediateDirectory)/src_binbuffer.cpp$(ObjectSuffix): src/binbuffer.cpp
- $(CXX) $(IncludePCH) $(SourceSwitch) "/home/ghazan/miranda-ng/src/mir_core/src/binbuffer.cpp" $(CXXFLAGS) $(ObjectSwitch)$(IntermediateDirectory)/src_binbuffer.cpp$(ObjectSuffix) $(IncludePath)
-$(IntermediateDirectory)/src_binbuffer.cpp$(PreprocessSuffix): src/binbuffer.cpp
- $(CXX) $(CXXFLAGS) $(IncludePCH) $(IncludePath) $(PreprocessOnlySwitch) $(OutputSwitch) $(IntermediateDirectory)/src_binbuffer.cpp$(PreprocessSuffix) src/binbuffer.cpp
+$(IntermediateDirectory)/src_logger.cpp$(ObjectSuffix): src/logger.cpp
+ $(CXX) $(IncludePCH) $(SourceSwitch) "/home/ghazan/miranda-ng/src/mir_core/src/logger.cpp" $(CXXFLAGS) $(ObjectSwitch)$(IntermediateDirectory)/src_logger.cpp$(ObjectSuffix) $(IncludePath)
+$(IntermediateDirectory)/src_logger.cpp$(PreprocessSuffix): src/logger.cpp
+ $(CXX) $(CXXFLAGS) $(IncludePCH) $(IncludePath) $(PreprocessOnlySwitch) $(OutputSwitch) $(IntermediateDirectory)/src_logger.cpp$(PreprocessSuffix) src/logger.cpp
-$(IntermediateDirectory)/src_bitmaps.cpp$(ObjectSuffix): src/bitmaps.cpp
- $(CXX) $(IncludePCH) $(SourceSwitch) "/home/ghazan/miranda-ng/src/mir_core/src/bitmaps.cpp" $(CXXFLAGS) $(ObjectSwitch)$(IntermediateDirectory)/src_bitmaps.cpp$(ObjectSuffix) $(IncludePath)
-$(IntermediateDirectory)/src_bitmaps.cpp$(PreprocessSuffix): src/bitmaps.cpp
- $(CXX) $(CXXFLAGS) $(IncludePCH) $(IncludePath) $(PreprocessOnlySwitch) $(OutputSwitch) $(IntermediateDirectory)/src_bitmaps.cpp$(PreprocessSuffix) src/bitmaps.cpp
+$(IntermediateDirectory)/src_md5.cpp$(ObjectSuffix): src/md5.cpp
+ $(CXX) $(IncludePCH) $(SourceSwitch) "/home/ghazan/miranda-ng/src/mir_core/src/md5.cpp" $(CXXFLAGS) $(ObjectSwitch)$(IntermediateDirectory)/src_md5.cpp$(ObjectSuffix) $(IncludePath)
+$(IntermediateDirectory)/src_md5.cpp$(PreprocessSuffix): src/md5.cpp
+ $(CXX) $(CXXFLAGS) $(IncludePCH) $(IncludePath) $(PreprocessOnlySwitch) $(OutputSwitch) $(IntermediateDirectory)/src_md5.cpp$(PreprocessSuffix) src/md5.cpp
-$(IntermediateDirectory)/src_lists.cpp$(ObjectSuffix): src/lists.cpp
- $(CXX) $(IncludePCH) $(SourceSwitch) "/home/ghazan/miranda-ng/src/mir_core/src/lists.cpp" $(CXXFLAGS) $(ObjectSwitch)$(IntermediateDirectory)/src_lists.cpp$(ObjectSuffix) $(IncludePath)
-$(IntermediateDirectory)/src_lists.cpp$(PreprocessSuffix): src/lists.cpp
- $(CXX) $(CXXFLAGS) $(IncludePCH) $(IncludePath) $(PreprocessOnlySwitch) $(OutputSwitch) $(IntermediateDirectory)/src_lists.cpp$(PreprocessSuffix) src/lists.cpp
+$(IntermediateDirectory)/src_mstring.cpp$(ObjectSuffix): src/mstring.cpp
+ $(CXX) $(IncludePCH) $(SourceSwitch) "/home/ghazan/miranda-ng/src/mir_core/src/mstring.cpp" $(CXXFLAGS) $(ObjectSwitch)$(IntermediateDirectory)/src_mstring.cpp$(ObjectSuffix) $(IncludePath)
+$(IntermediateDirectory)/src_mstring.cpp$(PreprocessSuffix): src/mstring.cpp
+ $(CXX) $(CXXFLAGS) $(IncludePCH) $(IncludePath) $(PreprocessOnlySwitch) $(OutputSwitch) $(IntermediateDirectory)/src_mstring.cpp$(PreprocessSuffix) src/mstring.cpp
-$(IntermediateDirectory)/src_Linux_fileutil.cpp$(ObjectSuffix): src/Linux/fileutil.cpp
- $(CXX) $(IncludePCH) $(SourceSwitch) "/home/ghazan/miranda-ng/src/mir_core/src/Linux/fileutil.cpp" $(CXXFLAGS) $(ObjectSwitch)$(IntermediateDirectory)/src_Linux_fileutil.cpp$(ObjectSuffix) $(IncludePath)
-$(IntermediateDirectory)/src_Linux_fileutil.cpp$(PreprocessSuffix): src/Linux/fileutil.cpp
- $(CXX) $(CXXFLAGS) $(IncludePCH) $(IncludePath) $(PreprocessOnlySwitch) $(OutputSwitch) $(IntermediateDirectory)/src_Linux_fileutil.cpp$(PreprocessSuffix) src/Linux/fileutil.cpp
+$(IntermediateDirectory)/src_db.cpp$(ObjectSuffix): src/db.cpp
+ $(CXX) $(IncludePCH) $(SourceSwitch) "/home/ghazan/miranda-ng/src/mir_core/src/db.cpp" $(CXXFLAGS) $(ObjectSwitch)$(IntermediateDirectory)/src_db.cpp$(ObjectSuffix) $(IncludePath)
+$(IntermediateDirectory)/src_db.cpp$(PreprocessSuffix): src/db.cpp
+ $(CXX) $(CXXFLAGS) $(IncludePCH) $(IncludePath) $(PreprocessOnlySwitch) $(OutputSwitch) $(IntermediateDirectory)/src_db.cpp$(PreprocessSuffix) src/db.cpp
-$(IntermediateDirectory)/src_memory.cpp$(ObjectSuffix): src/memory.cpp
- $(CXX) $(IncludePCH) $(SourceSwitch) "/home/ghazan/miranda-ng/src/mir_core/src/memory.cpp" $(CXXFLAGS) $(ObjectSwitch)$(IntermediateDirectory)/src_memory.cpp$(ObjectSuffix) $(IncludePath)
-$(IntermediateDirectory)/src_memory.cpp$(PreprocessSuffix): src/memory.cpp
- $(CXX) $(CXXFLAGS) $(IncludePCH) $(IncludePath) $(PreprocessOnlySwitch) $(OutputSwitch) $(IntermediateDirectory)/src_memory.cpp$(PreprocessSuffix) src/memory.cpp
+$(IntermediateDirectory)/src_Linux_CDlgBase.cpp$(ObjectSuffix): src/Linux/CDlgBase.cpp
+ $(CXX) $(IncludePCH) $(SourceSwitch) "/home/ghazan/miranda-ng/src/mir_core/src/Linux/CDlgBase.cpp" $(CXXFLAGS) $(ObjectSwitch)$(IntermediateDirectory)/src_Linux_CDlgBase.cpp$(ObjectSuffix) $(IncludePath)
+$(IntermediateDirectory)/src_Linux_CDlgBase.cpp$(PreprocessSuffix): src/Linux/CDlgBase.cpp
+ $(CXX) $(CXXFLAGS) $(IncludePCH) $(IncludePath) $(PreprocessOnlySwitch) $(OutputSwitch) $(IntermediateDirectory)/src_Linux_CDlgBase.cpp$(PreprocessSuffix) src/Linux/CDlgBase.cpp
-$(IntermediateDirectory)/src_utils.cpp$(ObjectSuffix): src/utils.cpp
- $(CXX) $(IncludePCH) $(SourceSwitch) "/home/ghazan/miranda-ng/src/mir_core/src/utils.cpp" $(CXXFLAGS) $(ObjectSwitch)$(IntermediateDirectory)/src_utils.cpp$(ObjectSuffix) $(IncludePath)
-$(IntermediateDirectory)/src_utils.cpp$(PreprocessSuffix): src/utils.cpp
- $(CXX) $(CXXFLAGS) $(IncludePCH) $(IncludePath) $(PreprocessOnlySwitch) $(OutputSwitch) $(IntermediateDirectory)/src_utils.cpp$(PreprocessSuffix) src/utils.cpp
+$(IntermediateDirectory)/src_stdafx.cxx$(ObjectSuffix): src/stdafx.cxx
+ $(CXX) $(IncludePCH) $(SourceSwitch) "/home/ghazan/miranda-ng/src/mir_core/src/stdafx.cxx" $(CXXFLAGS) $(ObjectSwitch)$(IntermediateDirectory)/src_stdafx.cxx$(ObjectSuffix) $(IncludePath)
+$(IntermediateDirectory)/src_stdafx.cxx$(PreprocessSuffix): src/stdafx.cxx
+ $(CXX) $(CXXFLAGS) $(IncludePCH) $(IncludePath) $(PreprocessOnlySwitch) $(OutputSwitch) $(IntermediateDirectory)/src_stdafx.cxx$(PreprocessSuffix) src/stdafx.cxx
+
+$(IntermediateDirectory)/src_http.cpp$(ObjectSuffix): src/http.cpp
+ $(CXX) $(IncludePCH) $(SourceSwitch) "/home/ghazan/miranda-ng/src/mir_core/src/http.cpp" $(CXXFLAGS) $(ObjectSwitch)$(IntermediateDirectory)/src_http.cpp$(ObjectSuffix) $(IncludePath)
+$(IntermediateDirectory)/src_http.cpp$(PreprocessSuffix): src/http.cpp
+ $(CXX) $(CXXFLAGS) $(IncludePCH) $(IncludePath) $(PreprocessOnlySwitch) $(OutputSwitch) $(IntermediateDirectory)/src_http.cpp$(PreprocessSuffix) src/http.cpp
+
+$(IntermediateDirectory)/src_tinyxml2.cpp$(ObjectSuffix): src/tinyxml2.cpp
+ $(CXX) $(IncludePCH) $(SourceSwitch) "/home/ghazan/miranda-ng/src/mir_core/src/tinyxml2.cpp" $(CXXFLAGS) $(ObjectSwitch)$(IntermediateDirectory)/src_tinyxml2.cpp$(ObjectSuffix) $(IncludePath)
+$(IntermediateDirectory)/src_tinyxml2.cpp$(PreprocessSuffix): src/tinyxml2.cpp
+ $(CXX) $(CXXFLAGS) $(IncludePCH) $(IncludePath) $(PreprocessOnlySwitch) $(OutputSwitch) $(IntermediateDirectory)/src_tinyxml2.cpp$(PreprocessSuffix) src/tinyxml2.cpp
+
+$(IntermediateDirectory)/src_sha256.cpp$(ObjectSuffix): src/sha256.cpp
+ $(CXX) $(IncludePCH) $(SourceSwitch) "/home/ghazan/miranda-ng/src/mir_core/src/sha256.cpp" $(CXXFLAGS) $(ObjectSwitch)$(IntermediateDirectory)/src_sha256.cpp$(ObjectSuffix) $(IncludePath)
+$(IntermediateDirectory)/src_sha256.cpp$(PreprocessSuffix): src/sha256.cpp
+ $(CXX) $(CXXFLAGS) $(IncludePCH) $(IncludePath) $(PreprocessOnlySwitch) $(OutputSwitch) $(IntermediateDirectory)/src_sha256.cpp$(PreprocessSuffix) src/sha256.cpp
+
+$(IntermediateDirectory)/src_utf.cpp$(ObjectSuffix): src/utf.cpp
+ $(CXX) $(IncludePCH) $(SourceSwitch) "/home/ghazan/miranda-ng/src/mir_core/src/utf.cpp" $(CXXFLAGS) $(ObjectSwitch)$(IntermediateDirectory)/src_utf.cpp$(ObjectSuffix) $(IncludePath)
+$(IntermediateDirectory)/src_utf.cpp$(PreprocessSuffix): src/utf.cpp
+ $(CXX) $(CXXFLAGS) $(IncludePCH) $(IncludePath) $(PreprocessOnlySwitch) $(OutputSwitch) $(IntermediateDirectory)/src_utf.cpp$(PreprocessSuffix) src/utf.cpp
$(IntermediateDirectory)/src_Linux_strutil.cpp$(ObjectSuffix): src/Linux/strutil.cpp
$(CXX) $(IncludePCH) $(SourceSwitch) "/home/ghazan/miranda-ng/src/mir_core/src/Linux/strutil.cpp" $(CXXFLAGS) $(ObjectSwitch)$(IntermediateDirectory)/src_Linux_strutil.cpp$(ObjectSuffix) $(IncludePath)
$(IntermediateDirectory)/src_Linux_strutil.cpp$(PreprocessSuffix): src/Linux/strutil.cpp
$(CXX) $(CXXFLAGS) $(IncludePCH) $(IncludePath) $(PreprocessOnlySwitch) $(OutputSwitch) $(IntermediateDirectory)/src_Linux_strutil.cpp$(PreprocessSuffix) src/Linux/strutil.cpp
+$(IntermediateDirectory)/src_utils.cpp$(ObjectSuffix): src/utils.cpp
+ $(CXX) $(IncludePCH) $(SourceSwitch) "/home/ghazan/miranda-ng/src/mir_core/src/utils.cpp" $(CXXFLAGS) $(ObjectSwitch)$(IntermediateDirectory)/src_utils.cpp$(ObjectSuffix) $(IncludePath)
+$(IntermediateDirectory)/src_utils.cpp$(PreprocessSuffix): src/utils.cpp
+ $(CXX) $(CXXFLAGS) $(IncludePCH) $(IncludePath) $(PreprocessOnlySwitch) $(OutputSwitch) $(IntermediateDirectory)/src_utils.cpp$(PreprocessSuffix) src/utils.cpp
+
+$(IntermediateDirectory)/src_memory.cpp$(ObjectSuffix): src/memory.cpp
+ $(CXX) $(IncludePCH) $(SourceSwitch) "/home/ghazan/miranda-ng/src/mir_core/src/memory.cpp" $(CXXFLAGS) $(ObjectSwitch)$(IntermediateDirectory)/src_memory.cpp$(ObjectSuffix) $(IncludePath)
+$(IntermediateDirectory)/src_memory.cpp$(PreprocessSuffix): src/memory.cpp
+ $(CXX) $(CXXFLAGS) $(IncludePCH) $(IncludePath) $(PreprocessOnlySwitch) $(OutputSwitch) $(IntermediateDirectory)/src_memory.cpp$(PreprocessSuffix) src/memory.cpp
+
+$(IntermediateDirectory)/src_Linux_CDbLink.cpp$(ObjectSuffix): src/Linux/CDbLink.cpp
+ $(CXX) $(IncludePCH) $(SourceSwitch) "/home/ghazan/miranda-ng/src/mir_core/src/Linux/CDbLink.cpp" $(CXXFLAGS) $(ObjectSwitch)$(IntermediateDirectory)/src_Linux_CDbLink.cpp$(ObjectSuffix) $(IncludePath)
+$(IntermediateDirectory)/src_Linux_CDbLink.cpp$(PreprocessSuffix): src/Linux/CDbLink.cpp
+ $(CXX) $(CXXFLAGS) $(IncludePCH) $(IncludePath) $(PreprocessOnlySwitch) $(OutputSwitch) $(IntermediateDirectory)/src_Linux_CDbLink.cpp$(PreprocessSuffix) src/Linux/CDbLink.cpp
+
+$(IntermediateDirectory)/src_Linux_CCtrlBase.cpp$(ObjectSuffix): src/Linux/CCtrlBase.cpp
+ $(CXX) $(IncludePCH) $(SourceSwitch) "/home/ghazan/miranda-ng/src/mir_core/src/Linux/CCtrlBase.cpp" $(CXXFLAGS) $(ObjectSwitch)$(IntermediateDirectory)/src_Linux_CCtrlBase.cpp$(ObjectSuffix) $(IncludePath)
+$(IntermediateDirectory)/src_Linux_CCtrlBase.cpp$(PreprocessSuffix): src/Linux/CCtrlBase.cpp
+ $(CXX) $(CXXFLAGS) $(IncludePCH) $(IncludePath) $(PreprocessOnlySwitch) $(OutputSwitch) $(IntermediateDirectory)/src_Linux_CCtrlBase.cpp$(PreprocessSuffix) src/Linux/CCtrlBase.cpp
+
$(IntermediateDirectory)/src_tinyxml2_utils.cpp$(ObjectSuffix): src/tinyxml2_utils.cpp
$(CXX) $(IncludePCH) $(SourceSwitch) "/home/ghazan/miranda-ng/src/mir_core/src/tinyxml2_utils.cpp" $(CXXFLAGS) $(ObjectSwitch)$(IntermediateDirectory)/src_tinyxml2_utils.cpp$(ObjectSuffix) $(IncludePath)
$(IntermediateDirectory)/src_tinyxml2_utils.cpp$(PreprocessSuffix): src/tinyxml2_utils.cpp
$(CXX) $(CXXFLAGS) $(IncludePCH) $(IncludePath) $(PreprocessOnlySwitch) $(OutputSwitch) $(IntermediateDirectory)/src_tinyxml2_utils.cpp$(PreprocessSuffix) src/tinyxml2_utils.cpp
-$(IntermediateDirectory)/src_utf.cpp$(ObjectSuffix): src/utf.cpp
- $(CXX) $(IncludePCH) $(SourceSwitch) "/home/ghazan/miranda-ng/src/mir_core/src/utf.cpp" $(CXXFLAGS) $(ObjectSwitch)$(IntermediateDirectory)/src_utf.cpp$(ObjectSuffix) $(IncludePath)
-$(IntermediateDirectory)/src_utf.cpp$(PreprocessSuffix): src/utf.cpp
- $(CXX) $(CXXFLAGS) $(IncludePCH) $(IncludePath) $(PreprocessOnlySwitch) $(OutputSwitch) $(IntermediateDirectory)/src_utf.cpp$(PreprocessSuffix) src/utf.cpp
-
-$(IntermediateDirectory)/src_tinyxml2.cpp$(ObjectSuffix): src/tinyxml2.cpp
- $(CXX) $(IncludePCH) $(SourceSwitch) "/home/ghazan/miranda-ng/src/mir_core/src/tinyxml2.cpp" $(CXXFLAGS) $(ObjectSwitch)$(IntermediateDirectory)/src_tinyxml2.cpp$(ObjectSuffix) $(IncludePath)
-$(IntermediateDirectory)/src_tinyxml2.cpp$(PreprocessSuffix): src/tinyxml2.cpp
- $(CXX) $(CXXFLAGS) $(IncludePCH) $(IncludePath) $(PreprocessOnlySwitch) $(OutputSwitch) $(IntermediateDirectory)/src_tinyxml2.cpp$(PreprocessSuffix) src/tinyxml2.cpp
-
-$(IntermediateDirectory)/src_http.cpp$(ObjectSuffix): src/http.cpp
- $(CXX) $(IncludePCH) $(SourceSwitch) "/home/ghazan/miranda-ng/src/mir_core/src/http.cpp" $(CXXFLAGS) $(ObjectSwitch)$(IntermediateDirectory)/src_http.cpp$(ObjectSuffix) $(IncludePath)
-$(IntermediateDirectory)/src_http.cpp$(PreprocessSuffix): src/http.cpp
- $(CXX) $(CXXFLAGS) $(IncludePCH) $(IncludePath) $(PreprocessOnlySwitch) $(OutputSwitch) $(IntermediateDirectory)/src_http.cpp$(PreprocessSuffix) src/http.cpp
+$(IntermediateDirectory)/src_Linux_fileutil.cpp$(ObjectSuffix): src/Linux/fileutil.cpp
+ $(CXX) $(IncludePCH) $(SourceSwitch) "/home/ghazan/miranda-ng/src/mir_core/src/Linux/fileutil.cpp" $(CXXFLAGS) $(ObjectSwitch)$(IntermediateDirectory)/src_Linux_fileutil.cpp$(ObjectSuffix) $(IncludePath)
+$(IntermediateDirectory)/src_Linux_fileutil.cpp$(PreprocessSuffix): src/Linux/fileutil.cpp
+ $(CXX) $(CXXFLAGS) $(IncludePCH) $(IncludePath) $(PreprocessOnlySwitch) $(OutputSwitch) $(IntermediateDirectory)/src_Linux_fileutil.cpp$(PreprocessSuffix) src/Linux/fileutil.cpp
-$(IntermediateDirectory)/src_stdafx.cxx$(ObjectSuffix): src/stdafx.cxx
- $(CXX) $(IncludePCH) $(SourceSwitch) "/home/ghazan/miranda-ng/src/mir_core/src/stdafx.cxx" $(CXXFLAGS) $(ObjectSwitch)$(IntermediateDirectory)/src_stdafx.cxx$(ObjectSuffix) $(IncludePath)
-$(IntermediateDirectory)/src_stdafx.cxx$(PreprocessSuffix): src/stdafx.cxx
- $(CXX) $(CXXFLAGS) $(IncludePCH) $(IncludePath) $(PreprocessOnlySwitch) $(OutputSwitch) $(IntermediateDirectory)/src_stdafx.cxx$(PreprocessSuffix) src/stdafx.cxx
+$(IntermediateDirectory)/src_lists.cpp$(ObjectSuffix): src/lists.cpp
+ $(CXX) $(IncludePCH) $(SourceSwitch) "/home/ghazan/miranda-ng/src/mir_core/src/lists.cpp" $(CXXFLAGS) $(ObjectSwitch)$(IntermediateDirectory)/src_lists.cpp$(ObjectSuffix) $(IncludePath)
+$(IntermediateDirectory)/src_lists.cpp$(PreprocessSuffix): src/lists.cpp
+ $(CXX) $(CXXFLAGS) $(IncludePCH) $(IncludePath) $(PreprocessOnlySwitch) $(OutputSwitch) $(IntermediateDirectory)/src_lists.cpp$(PreprocessSuffix) src/lists.cpp
-$(IntermediateDirectory)/src_sha256.cpp$(ObjectSuffix): src/sha256.cpp
- $(CXX) $(IncludePCH) $(SourceSwitch) "/home/ghazan/miranda-ng/src/mir_core/src/sha256.cpp" $(CXXFLAGS) $(ObjectSwitch)$(IntermediateDirectory)/src_sha256.cpp$(ObjectSuffix) $(IncludePath)
-$(IntermediateDirectory)/src_sha256.cpp$(PreprocessSuffix): src/sha256.cpp
- $(CXX) $(CXXFLAGS) $(IncludePCH) $(IncludePath) $(PreprocessOnlySwitch) $(OutputSwitch) $(IntermediateDirectory)/src_sha256.cpp$(PreprocessSuffix) src/sha256.cpp
+$(IntermediateDirectory)/src_bitmaps.cpp$(ObjectSuffix): src/bitmaps.cpp
+ $(CXX) $(IncludePCH) $(SourceSwitch) "/home/ghazan/miranda-ng/src/mir_core/src/bitmaps.cpp" $(CXXFLAGS) $(ObjectSwitch)$(IntermediateDirectory)/src_bitmaps.cpp$(ObjectSuffix) $(IncludePath)
+$(IntermediateDirectory)/src_bitmaps.cpp$(PreprocessSuffix): src/bitmaps.cpp
+ $(CXX) $(CXXFLAGS) $(IncludePCH) $(IncludePath) $(PreprocessOnlySwitch) $(OutputSwitch) $(IntermediateDirectory)/src_bitmaps.cpp$(PreprocessSuffix) src/bitmaps.cpp
-$(IntermediateDirectory)/src_db.cpp$(ObjectSuffix): src/db.cpp
- $(CXX) $(IncludePCH) $(SourceSwitch) "/home/ghazan/miranda-ng/src/mir_core/src/db.cpp" $(CXXFLAGS) $(ObjectSwitch)$(IntermediateDirectory)/src_db.cpp$(ObjectSuffix) $(IncludePath)
-$(IntermediateDirectory)/src_db.cpp$(PreprocessSuffix): src/db.cpp
- $(CXX) $(CXXFLAGS) $(IncludePCH) $(IncludePath) $(PreprocessOnlySwitch) $(OutputSwitch) $(IntermediateDirectory)/src_db.cpp$(PreprocessSuffix) src/db.cpp
+$(IntermediateDirectory)/src_binbuffer.cpp$(ObjectSuffix): src/binbuffer.cpp
+ $(CXX) $(IncludePCH) $(SourceSwitch) "/home/ghazan/miranda-ng/src/mir_core/src/binbuffer.cpp" $(CXXFLAGS) $(ObjectSwitch)$(IntermediateDirectory)/src_binbuffer.cpp$(ObjectSuffix) $(IncludePath)
+$(IntermediateDirectory)/src_binbuffer.cpp$(PreprocessSuffix): src/binbuffer.cpp
+ $(CXX) $(CXXFLAGS) $(IncludePCH) $(IncludePath) $(PreprocessOnlySwitch) $(OutputSwitch) $(IntermediateDirectory)/src_binbuffer.cpp$(PreprocessSuffix) src/binbuffer.cpp
$(IntermediateDirectory)/src_sha1.cpp$(ObjectSuffix): src/sha1.cpp
$(CXX) $(IncludePCH) $(SourceSwitch) "/home/ghazan/miranda-ng/src/mir_core/src/sha1.cpp" $(CXXFLAGS) $(ObjectSwitch)$(IntermediateDirectory)/src_sha1.cpp$(ObjectSuffix) $(IncludePath)
$(IntermediateDirectory)/src_sha1.cpp$(PreprocessSuffix): src/sha1.cpp
$(CXX) $(CXXFLAGS) $(IncludePCH) $(IncludePath) $(PreprocessOnlySwitch) $(OutputSwitch) $(IntermediateDirectory)/src_sha1.cpp$(PreprocessSuffix) src/sha1.cpp
-$(IntermediateDirectory)/src_mstring.cpp$(ObjectSuffix): src/mstring.cpp
- $(CXX) $(IncludePCH) $(SourceSwitch) "/home/ghazan/miranda-ng/src/mir_core/src/mstring.cpp" $(CXXFLAGS) $(ObjectSwitch)$(IntermediateDirectory)/src_mstring.cpp$(ObjectSuffix) $(IncludePath)
-$(IntermediateDirectory)/src_mstring.cpp$(PreprocessSuffix): src/mstring.cpp
- $(CXX) $(CXXFLAGS) $(IncludePCH) $(IncludePath) $(PreprocessOnlySwitch) $(OutputSwitch) $(IntermediateDirectory)/src_mstring.cpp$(PreprocessSuffix) src/mstring.cpp
-
-$(IntermediateDirectory)/src_md5.cpp$(ObjectSuffix): src/md5.cpp
- $(CXX) $(IncludePCH) $(SourceSwitch) "/home/ghazan/miranda-ng/src/mir_core/src/md5.cpp" $(CXXFLAGS) $(ObjectSwitch)$(IntermediateDirectory)/src_md5.cpp$(ObjectSuffix) $(IncludePath)
-$(IntermediateDirectory)/src_md5.cpp$(PreprocessSuffix): src/md5.cpp
- $(CXX) $(CXXFLAGS) $(IncludePCH) $(IncludePath) $(PreprocessOnlySwitch) $(OutputSwitch) $(IntermediateDirectory)/src_md5.cpp$(PreprocessSuffix) src/md5.cpp
-
-$(IntermediateDirectory)/src_logger.cpp$(ObjectSuffix): src/logger.cpp
- $(CXX) $(IncludePCH) $(SourceSwitch) "/home/ghazan/miranda-ng/src/mir_core/src/logger.cpp" $(CXXFLAGS) $(ObjectSwitch)$(IntermediateDirectory)/src_logger.cpp$(ObjectSuffix) $(IncludePath)
-$(IntermediateDirectory)/src_logger.cpp$(PreprocessSuffix): src/logger.cpp
- $(CXX) $(CXXFLAGS) $(IncludePCH) $(IncludePath) $(PreprocessOnlySwitch) $(OutputSwitch) $(IntermediateDirectory)/src_logger.cpp$(PreprocessSuffix) src/logger.cpp
-
##
## Clean
##
diff --git a/src/mir_core/mir_core.project b/src/mir_core/mir_core.project
index cc337c96f0..70005786ae 100644
--- a/src/mir_core/mir_core.project
+++ b/src/mir_core/mir_core.project
@@ -3,6 +3,11 @@
<Description/>
<Dependencies/>
<VirtualDirectory Name="src">
+ <VirtualDirectory Name="UI">
+ <File Name="src/Linux/CDlgBase.cpp"/>
+ <File Name="src/Linux/CDbLink.cpp"/>
+ <File Name="src/Linux/CCtrlBase.cpp"/>
+ </VirtualDirectory>
<File Name="src/Linux/strutil.cpp"/>
<File Name="src/Linux/fileutil.cpp"/>
<File Name="src/utils.cpp"/>
@@ -41,11 +46,12 @@
<Compiler Options="-g;$(shell wx-config --cxxflags --unicode=yes) -fPIC" C_Options="-g;$(shell wx-config --cxxflags --unicode=yes) -fPIC" Assembler="" Required="yes" PreCompiledHeader="" PCHInCommandLine="no" PCHFlags="" PCHFlagsPolicy="0">
<IncludePath Value="."/>
<IncludePath Value="../../include"/>
+ <IncludePath Value="`pkg-config --cflags --libs elementary`"/>
</Compiler>
<Linker Options="$(shell wx-config --libs --unicode=yes)" Required="yes"/>
<ResourceCompiler Options="" Required="no"/>
<General OutputFile="$(ProjectName)" IntermediateDirectory="$(WorkspacePath)/obj/debug/$(ProjectName)" Command="$(WorkspacePath)/build-$(WorkspaceConfiguration)/bin/$(OutputFile)" CommandArguments="" UseSeparateDebugArgs="no" DebugArguments="" WorkingDirectory="$(WorkspacePath)/build-$(WorkspaceConfiguration)/lib" PauseExecWhenProcTerminates="yes" IsGUIProgram="no" IsEnabled="yes"/>
- <BuildSystem Name="CodeLite Make Generator"/>
+ <BuildSystem Name="CodeLite Makefile Generator"/>
<Environment EnvVarSetName="&lt;Use Defaults&gt;" DbgSetName="&lt;Use Defaults&gt;">
<![CDATA[]]>
</Environment>
@@ -81,11 +87,12 @@
<Compiler Options="-O2;$(shell wx-config --cxxflags --debug=no --unicode=yes) -fPIC" C_Options="-O2;$(shell wx-config --cxxflags --debug=no --unicode=yes) -fPIC" Assembler="" Required="yes" PreCompiledHeader="" PCHInCommandLine="no" PCHFlags="" PCHFlagsPolicy="0">
<IncludePath Value="."/>
<IncludePath Value="../../include"/>
+ <IncludePath Value="`pkg-config --cflags --libs elementary`"/>
</Compiler>
<Linker Options="$(shell wx-config --debug=no --libs --unicode=yes);" Required="yes"/>
<ResourceCompiler Options="" Required="no"/>
<General OutputFile="$(ProjectName)" IntermediateDirectory="$(WorkspacePath)/obj/debug/$(ProjectName)" Command="$(WorkspacePath)/build-$(WorkspaceConfiguration)/bin/$(OutputFile)" CommandArguments="" UseSeparateDebugArgs="no" DebugArguments="" WorkingDirectory="$(WorkspacePath)/build-$(WorkspaceConfiguration)/lib" PauseExecWhenProcTerminates="yes" IsGUIProgram="no" IsEnabled="yes"/>
- <BuildSystem Name="CodeLite Make Generator"/>
+ <BuildSystem Name="CodeLite Makefile Generator"/>
<Environment EnvVarSetName="&lt;Use Defaults&gt;" DbgSetName="&lt;Use Defaults&gt;">
<![CDATA[]]>
</Environment>
diff --git a/src/mir_core/src/Linux/CCtrlBase.cpp b/src/mir_core/src/Linux/CCtrlBase.cpp
new file mode 100644
index 0000000000..58787b02db
--- /dev/null
+++ b/src/mir_core/src/Linux/CCtrlBase.cpp
@@ -0,0 +1,224 @@
+/*
+
+Object UI extensions
+Copyright (c) 2008 Victor Pavlychko, George Hazan
+Copyright (C) 2012-22 Miranda NG team
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+*/
+
+#include "../stdafx.h"
+
+static mir_cs csCtrl;
+
+static int CompareControls(const CCtrlBase *p1, const CCtrlBase *p2)
+{
+ return (INT_PTR)p1->GetHwnd() - (INT_PTR)p2->GetHwnd();
+}
+static LIST<CCtrlBase> arControls(10, CompareControls);
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// CCtrlBase
+
+CCtrlBase::CCtrlBase(CDlgBase *wnd, int idCtrl) :
+ m_parentWnd(wnd),
+ m_idCtrl(idCtrl)
+{
+ if (wnd)
+ wnd->AddControl(this);
+}
+
+CCtrlBase::~CCtrlBase()
+{
+}
+
+void CCtrlBase::OnInit()
+{
+ m_hwnd = (m_idCtrl && m_parentWnd && m_parentWnd->GetHwnd()) ? GetDlgItem(m_parentWnd->GetHwnd(), m_idCtrl) : nullptr;
+}
+
+void CCtrlBase::OnDestroy()
+{
+ PVOID bullshit[2]; // vfptr + hwnd
+ bullshit[1] = m_hwnd;
+ CCtrlBase *pCtrl = arControls.find((CCtrlBase*)&bullshit);
+ if (pCtrl) {
+ pCtrl->Unsubclass();
+ arControls.remove(pCtrl);
+ }
+
+ m_hwnd = nullptr;
+}
+
+bool CCtrlBase::OnApply()
+{
+ m_bChanged = false;
+ return true;
+}
+
+void CCtrlBase::OnReset()
+{}
+
+void CCtrlBase::Show(bool bShow)
+{
+ ::ShowWindow(m_hwnd, bShow ? SW_SHOW : SW_HIDE);
+}
+
+void CCtrlBase::Enable(bool bIsEnable)
+{
+ ::EnableWindow(m_hwnd, bIsEnable);
+}
+
+bool CCtrlBase::Enabled() const
+{
+ return (m_hwnd) ? IsWindowEnabled(m_hwnd) != 0 : false;
+}
+
+void CCtrlBase::NotifyChange()
+{
+ if (!m_parentWnd)
+ return;
+
+ if (m_parentWnd->IsInitialized()) {
+ m_bChanged = true;
+ if (!m_bSilent)
+ m_parentWnd->NotifyChange();
+ }
+
+ OnChange(this);
+}
+
+LRESULT CCtrlBase::SendMsg(UINT Msg, WPARAM wParam, LPARAM lParam) const
+{
+ return ::SendMessage(m_hwnd, Msg, wParam, lParam);
+}
+
+void CCtrlBase::SetText(const wchar_t *text)
+{
+ ::SetWindowText(m_hwnd, text);
+}
+
+void CCtrlBase::SetTextA(const char *text)
+{
+ ::SetWindowTextA(m_hwnd, text);
+}
+
+void CCtrlBase::SetDraw(bool bEnable)
+{
+ ::SendMessage(m_hwnd, WM_SETREDRAW, bEnable, 0);
+}
+
+void CCtrlBase::SetInt(int value)
+{
+ wchar_t buf[32] = { 0 };
+ mir_snwprintf(buf, L"%d", value);
+ SetWindowText(m_hwnd, buf);
+}
+
+wchar_t* CCtrlBase::GetText() const
+{
+ int length = GetWindowTextLengthW(m_hwnd);
+ wchar_t *result = (wchar_t *)mir_alloc((length+1) * sizeof(wchar_t));
+ if (length)
+ GetWindowTextW(m_hwnd, result, length+1);
+ result[length] = 0;
+ return result;
+}
+
+char* CCtrlBase::GetTextA() const
+{
+ int length = GetWindowTextLengthA(m_hwnd);
+ char *result = (char *)mir_alloc((length+1) * sizeof(char));
+ if (length)
+ GetWindowTextA(m_hwnd, result, length+1);
+ result[length] = 0;
+ return result;
+}
+
+char* CCtrlBase::GetTextU() const
+{
+ return mir_utf8encodeW(ptrW(GetText()));
+}
+
+wchar_t* CCtrlBase::GetText(wchar_t *buf, size_t size) const
+{
+ GetWindowTextW(m_hwnd, buf, (int)size);
+ buf[size - 1] = 0;
+ return buf;
+}
+
+char* CCtrlBase::GetTextA(char *buf, size_t size) const
+{
+ GetWindowTextA(m_hwnd, buf, (int)size);
+ buf[size - 1] = 0;
+ return buf;
+}
+
+char* CCtrlBase::GetTextU(char *buf, size_t size) const
+{
+ ptrW wszText(GetText());
+ strncpy_s(buf, size, T2Utf(wszText), _TRUNCATE);
+ return buf;
+}
+
+int CCtrlBase::GetInt() const
+{
+ int length = GetWindowTextLengthW(m_hwnd) + 1;
+ wchar_t *result = (wchar_t *)_alloca(length * sizeof(wchar_t));
+ GetWindowTextW(m_hwnd, result, length);
+ return _wtoi(result);
+}
+
+void CCtrlBase::GetCaretPos(CContextMenuPos &pos) const
+{
+ pos.pCtrl = this;
+ pos.iCurr = -1;
+
+ if (pos.pt.x == 0 && pos.pt.y == 0)
+ GetCursorPos(&pos.pt);
+}
+
+LRESULT CCtrlBase::CustomWndProc(UINT, WPARAM, LPARAM)
+{
+ return FALSE;
+}
+
+LRESULT CALLBACK CCtrlBase::GlobalSubclassWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ PVOID bullshit[2]; // vfptr + hwnd
+ bullshit[1] = hwnd;
+ CCtrlBase *pCtrl = arControls.find((CCtrlBase*)&bullshit);
+ if (pCtrl) {
+ LRESULT res = pCtrl->CustomWndProc(msg, wParam, lParam);
+ if (res != 0)
+ return res;
+ }
+
+ return mir_callNextSubclass(hwnd, GlobalSubclassWndProc, msg, wParam, lParam);
+}
+
+void CCtrlBase::Subclass()
+{
+ mir_subclassWindow(m_hwnd, GlobalSubclassWndProc);
+
+ mir_cslock lck(csCtrl);
+ arControls.insert(this);
+}
+
+void CCtrlBase::Unsubclass()
+{
+ mir_unsubclassWindow(m_hwnd, GlobalSubclassWndProc);
+}
diff --git a/src/mir_core/src/Linux/CCtrlButton.cpp b/src/mir_core/src/Linux/CCtrlButton.cpp
new file mode 100644
index 0000000000..bf84cad74f
--- /dev/null
+++ b/src/mir_core/src/Linux/CCtrlButton.cpp
@@ -0,0 +1,54 @@
+/*
+
+Object UI extensions
+Copyright (c) 2008 Victor Pavlychko, George Hazan
+Copyright (C) 2012-22 Miranda NG team
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+*/
+
+#include "../stdafx.h"
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// CCtrlButton
+
+CCtrlButton::CCtrlButton(CDlgBase* wnd, int idCtrl)
+ : CCtrlBase(wnd, idCtrl)
+{}
+
+BOOL CCtrlButton::OnCommand(HWND, uint16_t, uint16_t idCode)
+{
+ if (idCode == BN_CLICKED)
+ OnClick(this);
+ return FALSE;
+}
+
+void CCtrlButton::Click()
+{
+ if (Enabled())
+ ::SendMessage(m_parentWnd->GetHwnd(), WM_COMMAND, MAKELONG(m_idCtrl, BN_CLICKED), 0);
+}
+
+bool CCtrlButton::IsPushed() const
+{
+ return ::SendMessage(m_hwnd, BM_GETCHECK, 0, 0) == BST_CHECKED;
+}
+
+void CCtrlButton::Push(bool bPushed)
+{
+ if (Enabled())
+ ::SendMessage(m_hwnd, BM_SETCHECK, (bPushed) ? BST_CHECKED : BST_UNCHECKED, 0);
+}
diff --git a/src/mir_core/src/Linux/CCtrlCheck.cpp b/src/mir_core/src/Linux/CCtrlCheck.cpp
new file mode 100644
index 0000000000..9c1281e8b8
--- /dev/null
+++ b/src/mir_core/src/Linux/CCtrlCheck.cpp
@@ -0,0 +1,68 @@
+/*
+
+Object UI extensions
+Copyright (c) 2008 Victor Pavlychko, George Hazan
+Copyright (C) 2012-22 Miranda NG team
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+*/
+
+#include "../stdafx.h"
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// CCtrlCheck class
+
+CCtrlCheck::CCtrlCheck(CDlgBase *dlg, int ctrlId)
+ : CCtrlData(dlg, ctrlId)
+{
+ m_bNotifiable = true;
+}
+
+BOOL CCtrlCheck::OnCommand(HWND, uint16_t, uint16_t)
+{
+ NotifyChange();
+ return TRUE;
+}
+
+bool CCtrlCheck::OnApply()
+{
+ CSuper::OnApply();
+
+ if (m_dbLink != nullptr)
+ SaveInt(GetState());
+ return true;
+}
+
+void CCtrlCheck::OnReset()
+{
+ if (m_dbLink != nullptr)
+ SetState(LoadInt());
+}
+
+int CCtrlCheck::GetState() const
+{
+ return ::SendMessage(m_hwnd, BM_GETCHECK, 0, 0);
+}
+
+void CCtrlCheck::SetState(int state)
+{
+ ::SendMessage(m_hwnd, BM_SETCHECK, state, 0);
+}
+
+bool CCtrlCheck::IsChecked()
+{
+ return GetState() == BST_CHECKED;
+}
diff --git a/src/mir_core/src/Linux/CCtrlClc.cpp b/src/mir_core/src/Linux/CCtrlClc.cpp
new file mode 100644
index 0000000000..cf4f05cda6
--- /dev/null
+++ b/src/mir_core/src/Linux/CCtrlClc.cpp
@@ -0,0 +1,207 @@
+/*
+
+Object UI extensions
+Copyright (c) 2008 Victor Pavlychko, George Hazan
+Copyright (C) 2012-22 Miranda NG team
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+*/
+
+#include "../stdafx.h"
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// CCtrlClc
+
+CCtrlClc::CCtrlClc(CDlgBase *dlg, int ctrlId)
+ : CCtrlBase(dlg, ctrlId)
+{}
+
+BOOL CCtrlClc::OnNotify(int, NMHDR *pnmh)
+{
+ TEventInfo evt = { this, (NMCLISTCONTROL *)pnmh };
+ switch (pnmh->code) {
+ case CLN_EXPANDED: OnExpanded(&evt); break;
+ case CLN_LISTREBUILT: OnListRebuilt(&evt); break;
+ case CLN_ITEMCHECKED: OnItemChecked(&evt); break;
+ case CLN_DRAGGING: OnDragging(&evt); break;
+ case CLN_DROPPED: OnDropped(&evt); break;
+ case CLN_LISTSIZECHANGE: OnListSizeChange(&evt); break;
+ case CLN_OPTIONSCHANGED: OnOptionsChanged(&evt); break;
+ case CLN_DRAGSTOP: OnDragStop(&evt); break;
+ case CLN_NEWCONTACT: OnNewContact(&evt); break;
+ case CLN_CONTACTMOVED: OnContactMoved(&evt); break;
+ case CLN_CHECKCHANGED: OnCheckChanged(&evt); break;
+ case NM_CLICK: OnClick(&evt); break;
+ }
+ return FALSE;
+}
+
+void CCtrlClc::AddContact(MCONTACT hContact)
+{ SendMessage(m_hwnd, CLM_ADDCONTACT, hContact, 0);
+}
+
+void CCtrlClc::AddGroup(HANDLE hGroup)
+{ SendMessage(m_hwnd, CLM_ADDGROUP, (WPARAM)hGroup, 0);
+}
+
+void CCtrlClc::AutoRebuild()
+{ SendMessage(m_hwnd, CLM_AUTOREBUILD, 0, 0);
+}
+
+void CCtrlClc::DeleteItem(HANDLE hItem)
+{ SendMessage(m_hwnd, CLM_DELETEITEM, (WPARAM)hItem, 0);
+}
+
+void CCtrlClc::EditLabel(HANDLE hItem)
+{ SendMessage(m_hwnd, CLM_EDITLABEL, (WPARAM)hItem, 0);
+}
+
+void CCtrlClc::EndEditLabel(bool save)
+{ SendMessage(m_hwnd, CLM_ENDEDITLABELNOW, save ? 0 : 1, 0);
+}
+
+void CCtrlClc::EnsureVisible(HANDLE hItem, bool partialOk)
+{ SendMessage(m_hwnd, CLM_ENSUREVISIBLE, (WPARAM)hItem, partialOk ? TRUE : FALSE);
+}
+
+void CCtrlClc::Expand(HANDLE hItem, uint32_t flags)
+{ SendMessage(m_hwnd, CLM_EXPAND, (WPARAM)hItem, flags);
+}
+
+HANDLE CCtrlClc::FindContact(MCONTACT hContact)
+{ return (HANDLE)SendMessage(m_hwnd, CLM_FINDCONTACT, hContact, 0);
+}
+
+HANDLE CCtrlClc::FindGroup(MGROUP hGroup)
+{ return (HANDLE)SendMessage(m_hwnd, CLM_FINDGROUP, hGroup, 0);
+}
+
+COLORREF CCtrlClc::GetBkColor() const
+{ return (COLORREF)SendMessage(m_hwnd, CLM_GETBKCOLOR, 0, 0);
+}
+
+bool CCtrlClc::GetCheck(HANDLE hItem) const
+{ return SendMessage(m_hwnd, CLM_GETCHECKMARK, (WPARAM)hItem, 0) ? true : false;
+}
+
+int CCtrlClc::GetCount() const
+{ return SendMessage(m_hwnd, CLM_GETCOUNT, 0, 0);
+}
+
+HWND CCtrlClc::GetEditControl() const
+{ return (HWND)SendMessage(m_hwnd, CLM_GETEDITCONTROL, 0, 0);
+}
+
+uint32_t CCtrlClc::GetExpand(HANDLE hItem) const
+{ return SendMessage(m_hwnd, CLM_GETEXPAND, (WPARAM)hItem, 0);
+}
+
+int CCtrlClc::GetExtraColumns() const
+{ return SendMessage(m_hwnd, CLM_GETEXTRACOLUMNS, 0, 0);
+}
+
+uint8_t CCtrlClc::GetExtraImage(HANDLE hItem, int iColumn) const
+{
+ return (uint8_t)(SendMessage(m_hwnd, CLM_GETEXTRAIMAGE, (WPARAM)hItem, MAKELPARAM(iColumn, 0)) & 0xFFFF);
+}
+
+HIMAGELIST CCtrlClc::GetExtraImageList() const
+{ return (HIMAGELIST)SendMessage(m_hwnd, CLM_GETEXTRAIMAGELIST, 0, 0);
+}
+
+HFONT CCtrlClc::GetFont(int iFontId) const
+{ return (HFONT)SendMessage(m_hwnd, CLM_GETFONT, (WPARAM)iFontId, 0);
+}
+
+HANDLE CCtrlClc::GetSelection() const
+{ return (HANDLE)SendMessage(m_hwnd, CLM_GETSELECTION, 0, 0);
+}
+
+HANDLE CCtrlClc::HitTest(int x, int y, uint32_t *hitTest) const
+{ return (HANDLE)SendMessage(m_hwnd, CLM_HITTEST, (WPARAM)hitTest, MAKELPARAM(x,y));
+}
+
+void CCtrlClc::SelectItem(HANDLE hItem)
+{ SendMessage(m_hwnd, CLM_SELECTITEM, (WPARAM)hItem, 0);
+}
+
+void CCtrlClc::SetBkColor(COLORREF clBack)
+{ SendMessage(m_hwnd, CLM_SETBKCOLOR, (WPARAM)clBack, 0);
+}
+
+void CCtrlClc::SetCheck(HANDLE hItem, bool check)
+{ SendMessage(m_hwnd, CLM_SETCHECKMARK, (WPARAM)hItem, check ? 1 : 0);
+}
+
+void CCtrlClc::SetExtraColumns(int iColumns)
+{ SendMessage(m_hwnd, CLM_SETEXTRACOLUMNS, (WPARAM)iColumns, 0);
+}
+
+void CCtrlClc::SetExtraImage(HANDLE hItem, int iColumn, int iImage)
+{ SendMessage(m_hwnd, CLM_SETEXTRAIMAGE, (WPARAM)hItem, MAKELPARAM(iColumn, iImage));
+}
+
+void CCtrlClc::SetExtraImageList(HIMAGELIST hImgList)
+{ SendMessage(m_hwnd, CLM_SETEXTRAIMAGELIST, 0, (LPARAM)hImgList);
+}
+
+void CCtrlClc::SetFont(int iFontId, HANDLE hFont, bool bRedraw)
+{ SendMessage(m_hwnd, CLM_SETFONT, (WPARAM)hFont, MAKELPARAM(bRedraw ? 1 : 0, iFontId));
+}
+
+void CCtrlClc::SetItemText(HANDLE hItem, char *szText)
+{ SendMessage(m_hwnd, CLM_SETITEMTEXT, (WPARAM)hItem, (LPARAM)szText);
+}
+
+void CCtrlClc::SetHideEmptyGroups(bool state)
+{ SendMessage(m_hwnd, CLM_SETHIDEEMPTYGROUPS, state ? 1 : 0, 0);
+}
+
+bool CCtrlClc::GetHideOfflineRoot() const
+{ return SendMessage(m_hwnd, CLM_GETHIDEOFFLINEROOT, 0, 0) ? true : false;
+}
+
+void CCtrlClc::SetHideOfflineRoot(bool state)
+{ SendMessage(m_hwnd, CLM_SETHIDEOFFLINEROOT, state ? 1 : 0, 9);
+}
+
+void CCtrlClc::SetUseGroups(bool state)
+{ SendMessage(m_hwnd, CLM_SETUSEGROUPS, state ? 1 : 0, 0);
+}
+
+void CCtrlClc::SetOfflineModes(uint32_t modes)
+{ SendMessage(m_hwnd, CLM_SETOFFLINEMODES, modes, 0);
+}
+
+uint32_t CCtrlClc::GetExStyle() const
+{ return SendMessage(m_hwnd, CLM_GETEXSTYLE, 0, 0);
+}
+
+void CCtrlClc::SetExStyle(uint32_t exStyle)
+{ SendMessage(m_hwnd, CLM_SETEXSTYLE, (WPARAM)exStyle, 0);
+}
+
+HANDLE CCtrlClc::AddInfoItem(CLCINFOITEM *cii)
+{ return (HANDLE)SendMessage(m_hwnd, CLM_ADDINFOITEM, 0, (LPARAM)cii);
+}
+
+int CCtrlClc::GetItemType(HANDLE hItem) const
+{ return SendMessage(m_hwnd, CLM_GETITEMTYPE, (WPARAM)hItem, 0);
+}
+
+HANDLE CCtrlClc::GetNextItem(HANDLE hItem, uint32_t flags) const
+{ return (HANDLE)SendMessage(m_hwnd, CLM_GETNEXTITEM, (WPARAM)flags, (LPARAM)hItem);
+}
diff --git a/src/mir_core/src/Linux/CCtrlColor.cpp b/src/mir_core/src/Linux/CCtrlColor.cpp
new file mode 100644
index 0000000000..97f5e48e02
--- /dev/null
+++ b/src/mir_core/src/Linux/CCtrlColor.cpp
@@ -0,0 +1,61 @@
+/*
+
+Object UI extensions
+Copyright (c) 2008 Victor Pavlychko, George Hazan
+Copyright (C) 2012-22 Miranda NG team
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+*/
+
+#include "../stdafx.h"
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// CCtrlColor class
+
+CCtrlColor::CCtrlColor(CDlgBase *dlg, int ctrlId) :
+ CCtrlData(dlg, ctrlId)
+{}
+
+BOOL CCtrlColor::OnCommand(HWND, uint16_t, uint16_t)
+{
+ NotifyChange();
+ return TRUE;
+}
+
+bool CCtrlColor::OnApply()
+{
+ CSuper::OnApply();
+
+ if (m_dbLink != nullptr)
+ SaveInt(GetColor());
+ return true;
+}
+
+void CCtrlColor::OnReset()
+{
+ if (m_dbLink != nullptr)
+ SetColor(LoadInt());
+}
+
+uint32_t CCtrlColor::GetColor()
+{
+ return ::SendMessage(m_hwnd, CPM_GETCOLOUR, 0, 0);
+}
+
+void CCtrlColor::SetColor(uint32_t dwValue)
+{
+ ::SendMessage(m_hwnd, CPM_SETCOLOUR, 0, dwValue);
+}
diff --git a/src/mir_core/src/Linux/CCtrlCombo.cpp b/src/mir_core/src/Linux/CCtrlCombo.cpp
new file mode 100644
index 0000000000..83cd721494
--- /dev/null
+++ b/src/mir_core/src/Linux/CCtrlCombo.cpp
@@ -0,0 +1,185 @@
+/*
+
+Object UI extensions
+Copyright (c) 2008 Victor Pavlychko, George Hazan
+Copyright (C) 2012-22 Miranda NG team
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+*/
+
+#include "../stdafx.h"
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// CCtrlCombo class
+
+CCtrlCombo::CCtrlCombo(CDlgBase *dlg, int ctrlId)
+ : CCtrlData(dlg, ctrlId)
+{}
+
+BOOL CCtrlCombo::OnCommand(HWND, uint16_t, uint16_t idCode)
+{
+ switch (idCode) {
+ case CBN_CLOSEUP: OnCloseup(this); break;
+ case CBN_DROPDOWN: OnDropdown(this); break;
+ case CBN_SELCHANGE: OnSelChanged(this); break;
+ case CBN_KILLFOCUS: OnKillFocus(this); break;
+
+ case CBN_EDITCHANGE:
+ case CBN_EDITUPDATE:
+ case CBN_SELENDOK:
+ NotifyChange();
+ break;
+ }
+ return TRUE;
+}
+
+void CCtrlCombo::OnInit()
+{
+ CSuper::OnInit();
+ OnReset();
+}
+
+bool CCtrlCombo::OnApply()
+{
+ CSuper::OnApply();
+
+ if (GetDataType() == DBVT_WCHAR) {
+ int len = GetWindowTextLength(m_hwnd) + 1;
+ wchar_t *buf = (wchar_t *)_alloca(sizeof(wchar_t) * len);
+ GetWindowText(m_hwnd, buf, len);
+ SaveText(buf);
+ }
+ else if (GetDataType() != DBVT_DELETED) {
+ SaveInt(GetInt());
+ }
+ return true;
+}
+
+void CCtrlCombo::OnReset()
+{
+ if (GetDataType() == DBVT_WCHAR)
+ SetText(LoadText());
+ else if (GetDataType() != DBVT_DELETED)
+ SetInt(LoadInt());
+}
+
+LPARAM CCtrlCombo::GetCurData() const
+{
+ return GetItemData(GetCurSel());
+}
+
+// selects line with userdata passed
+int CCtrlCombo::SelectData(LPARAM data)
+{
+ int ret = -1, nCount = GetCount();
+
+ for (int i = 0; i < nCount; i++)
+ if (GetItemData(i) == data) {
+ ret = i;
+ break;
+ }
+
+ return SetCurSel(ret);
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// Windows API
+
+int CCtrlCombo::AddString(const wchar_t *text, LPARAM data)
+{
+ int iItem = SendMessage(m_hwnd, CB_ADDSTRING, 0, (LPARAM)text);
+ if (data)
+ SendMessage(m_hwnd, CB_SETITEMDATA, iItem, data);
+ return iItem;
+}
+
+int CCtrlCombo::AddStringA(const char *text, LPARAM data)
+{
+ int iItem = SendMessageA(m_hwnd, CB_ADDSTRING, 0, (LPARAM)text);
+ if (data)
+ SendMessage(m_hwnd, CB_SETITEMDATA, iItem, data);
+ return iItem;
+}
+
+void CCtrlCombo::DeleteString(int index)
+{ SendMessage(m_hwnd, CB_DELETESTRING, index, 0);
+}
+
+int CCtrlCombo::FindString(const wchar_t *str, int index, bool exact)
+{ return SendMessage(m_hwnd, exact?CB_FINDSTRINGEXACT:CB_FINDSTRING, index, (LPARAM)str);
+}
+
+int CCtrlCombo::FindStringA(const char *str, int index, bool exact)
+{ return SendMessageA(m_hwnd, exact?CB_FINDSTRINGEXACT:CB_FINDSTRING, index, (LPARAM)str);
+}
+
+int CCtrlCombo::GetCount() const
+{ return SendMessage(m_hwnd, CB_GETCOUNT, 0, 0);
+}
+
+int CCtrlCombo::GetCurSel() const
+{ return SendMessage(m_hwnd, CB_GETCURSEL, 0, 0);
+}
+
+bool CCtrlCombo::GetDroppedState() const
+{ return SendMessage(m_hwnd, CB_GETDROPPEDSTATE, 0, 0) ? true : false;
+}
+
+LPARAM CCtrlCombo::GetItemData(int index) const
+{ return SendMessage(m_hwnd, CB_GETITEMDATA, index, 0);
+}
+
+wchar_t* CCtrlCombo::GetItemText(int index) const
+{
+ wchar_t *result = (wchar_t *)mir_alloc(sizeof(wchar_t) * (SendMessage(m_hwnd, CB_GETLBTEXTLEN, index, 0) + 1));
+ SendMessage(m_hwnd, CB_GETLBTEXT, index, (LPARAM)result);
+ return result;
+}
+
+wchar_t* CCtrlCombo::GetItemText(int index, wchar_t *buf, int size) const
+{
+ wchar_t *result = (wchar_t *)_alloca(sizeof(wchar_t) * (SendMessage(m_hwnd, CB_GETLBTEXTLEN, index, 0) + 1));
+ SendMessage(m_hwnd, CB_GETLBTEXT, index, (LPARAM)result);
+ mir_wstrncpy(buf, result, size);
+ return buf;
+}
+
+int CCtrlCombo::InsertString(const wchar_t *text, int pos, LPARAM data)
+{
+ int iItem = SendMessage(m_hwnd, CB_INSERTSTRING, pos, (LPARAM)text);
+ SendMessage(m_hwnd, CB_SETITEMDATA, iItem, data);
+ return iItem;
+}
+
+void CCtrlCombo::ResetContent()
+{ SendMessage(m_hwnd, CB_RESETCONTENT, 0, 0);
+}
+
+int CCtrlCombo::SelectString(const wchar_t *str)
+{ return SendMessage(m_hwnd, CB_SELECTSTRING, 0, (LPARAM)str);
+}
+
+int CCtrlCombo::SetCurSel(int index)
+{ return SendMessage(m_hwnd, CB_SETCURSEL, index, 0);
+}
+
+void CCtrlCombo::SetItemData(int index, LPARAM data)
+{ SendMessage(m_hwnd, CB_SETITEMDATA, index, data);
+}
+
+void CCtrlCombo::ShowDropdown(bool show)
+{ SendMessage(m_hwnd, CB_SHOWDROPDOWN, show ? TRUE : FALSE, 0);
+}
diff --git a/src/mir_core/src/Linux/CCtrlData.cpp b/src/mir_core/src/Linux/CCtrlData.cpp
new file mode 100644
index 0000000000..fab5ca0409
--- /dev/null
+++ b/src/mir_core/src/Linux/CCtrlData.cpp
@@ -0,0 +1,52 @@
+/*
+
+Object UI extensions
+Copyright (c) 2008 Victor Pavlychko, George Hazan
+Copyright (C) 2012-22 Miranda NG team
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+*/
+
+#include "../stdafx.h"
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// CCtrlData class
+
+CCtrlData::CCtrlData(CDlgBase *wnd, int idCtrl)
+ : CCtrlBase(wnd, idCtrl),
+ m_dbLink(nullptr)
+{}
+
+CCtrlData::~CCtrlData()
+{
+ delete m_dbLink;
+}
+
+void CCtrlData::OnInit()
+{
+ CCtrlBase::OnInit();
+ OnReset();
+}
+
+void CCtrlData::CreateDbLink(const char* szModuleName, const char* szSetting, uint8_t type, uint32_t iValue)
+{
+ m_dbLink = new CDbLink(szModuleName, szSetting, type, iValue);
+}
+
+void CCtrlData::CreateDbLink(const char* szModuleName, const char* szSetting, wchar_t* szValue)
+{
+ m_dbLink = new CDbLink(szModuleName, szSetting, DBVT_WCHAR, szValue);
+}
diff --git a/src/mir_core/src/Linux/CCtrlEdit.cpp b/src/mir_core/src/Linux/CCtrlEdit.cpp
new file mode 100644
index 0000000000..f035b5b14a
--- /dev/null
+++ b/src/mir_core/src/Linux/CCtrlEdit.cpp
@@ -0,0 +1,68 @@
+/*
+
+Object UI extensions
+Copyright (c) 2008 Victor Pavlychko, George Hazan
+Copyright (C) 2012-22 Miranda NG team
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+*/
+
+#include "../stdafx.h"
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// CCtrlEdit class
+
+CCtrlEdit::CCtrlEdit(CDlgBase *dlg, int ctrlId)
+ : CCtrlData(dlg, ctrlId)
+{}
+
+BOOL CCtrlEdit::OnCommand(HWND, uint16_t, uint16_t idCode)
+{
+ if (idCode == EN_CHANGE)
+ NotifyChange();
+ return TRUE;
+}
+
+bool CCtrlEdit::OnApply()
+{
+ CSuper::OnApply();
+
+ if (GetDataType() == DBVT_WCHAR) {
+ int len = GetWindowTextLength(m_hwnd) + 1;
+ wchar_t *buf = (wchar_t *)_alloca(sizeof(wchar_t) * len);
+ GetWindowText(m_hwnd, buf, len);
+ SaveText(buf);
+ }
+ else if (GetDataType() != DBVT_DELETED) {
+ SaveInt(GetInt());
+ }
+ return true;
+}
+
+void CCtrlEdit::OnReset()
+{
+ m_bSilent = (GetWindowLong(m_hwnd, GWL_STYLE) & ES_READONLY) != 0;
+
+ if (GetDataType() == DBVT_WCHAR)
+ SetText(LoadText());
+ else if (GetDataType() != DBVT_DELETED)
+ SetInt(LoadInt());
+}
+
+void CCtrlEdit::SetMaxLength(unsigned int len)
+{
+ SendMsg(EM_SETLIMITTEXT, len, 0);
+}
diff --git a/src/mir_core/src/Linux/CCtrlHyperlink.cpp b/src/mir_core/src/Linux/CCtrlHyperlink.cpp
new file mode 100644
index 0000000000..ca92d19dbc
--- /dev/null
+++ b/src/mir_core/src/Linux/CCtrlHyperlink.cpp
@@ -0,0 +1,54 @@
+/*
+
+Object UI extensions
+Copyright (c) 2008 Victor Pavlychko, George Hazan
+Copyright (C) 2012-22 Miranda NG team
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+*/
+
+#include "../stdafx.h"
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// CCtrlHyperlink
+
+CCtrlHyperlink::CCtrlHyperlink(CDlgBase* wnd, int idCtrl, const char* url)
+ : CCtrlBase(wnd, idCtrl),
+ m_url(url)
+{
+ OnClick = Callback(this, &CCtrlHyperlink::Default_OnClick);
+}
+
+BOOL CCtrlHyperlink::OnCommand(HWND, uint16_t, uint16_t)
+{
+ OnClick(this);
+ return FALSE;
+}
+
+void CCtrlHyperlink::Default_OnClick(CCtrlHyperlink*)
+{
+ ShellExecuteA(m_hwnd, "open", m_url, "", "", SW_SHOW);
+}
+
+void CCtrlHyperlink::SetUrl(const char *url)
+{
+ m_url = url;
+}
+
+const char* CCtrlHyperlink::GetUrl()
+{
+ return m_url;
+}
diff --git a/src/mir_core/src/Linux/CCtrlLabel.cpp b/src/mir_core/src/Linux/CCtrlLabel.cpp
new file mode 100644
index 0000000000..fd460fdf8b
--- /dev/null
+++ b/src/mir_core/src/Linux/CCtrlLabel.cpp
@@ -0,0 +1,31 @@
+/*
+
+Object UI extensions
+Copyright (c) 2008 Victor Pavlychko, George Hazan
+Copyright (C) 2012-22 Miranda NG team
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+*/
+
+#include "../stdafx.h"
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// CCtrlLabel
+
+CCtrlLabel::CCtrlLabel(CDlgBase* wnd, int idCtrl)
+ : CCtrlBase(wnd, idCtrl)
+{}
+
diff --git a/src/mir_core/src/Linux/CCtrlListBox.cpp b/src/mir_core/src/Linux/CCtrlListBox.cpp
new file mode 100644
index 0000000000..abaa31a786
--- /dev/null
+++ b/src/mir_core/src/Linux/CCtrlListBox.cpp
@@ -0,0 +1,160 @@
+/*
+
+Object UI extensions
+Copyright (c) 2008 Victor Pavlychko, George Hazan
+Copyright (C) 2012-22 Miranda NG team
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+*/
+
+#include "../stdafx.h"
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// CCtrlListBox class
+
+CCtrlListBox::CCtrlListBox(CDlgBase *dlg, int ctrlId)
+ : CCtrlBase(dlg, ctrlId)
+{}
+
+BOOL CCtrlListBox::OnCommand(HWND, uint16_t, uint16_t idCode)
+{
+ switch (idCode) {
+ case LBN_DBLCLK: OnDblClick(this); break;
+ case LBN_SELCANCEL: OnSelCancel(this); break;
+ case LBN_SELCHANGE: OnSelChange(this); break;
+ }
+ return TRUE;
+}
+
+void CCtrlListBox::GetCaretPos(CContextMenuPos &pos) const
+{
+ pos.pCtrl = this;
+ if (pos.pt.x == 0 && pos.pt.y == 0) {
+ pos.iCurr = GetCurSel();
+ if (pos.iCurr != -1) {
+ RECT rc;
+ GetItemRect(pos.iCurr, &rc);
+ pos.pt.x = rc.left + 8;
+ pos.pt.y = rc.top + 8;
+ ClientToScreen(m_hwnd, &pos.pt);
+ return;
+ }
+ }
+
+ CSuper::GetCaretPos(pos);
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+int CCtrlListBox::AddString(const wchar_t *text, LPARAM data)
+{
+ int iItem = ListBox_AddString(m_hwnd, text);
+ ListBox_SetItemData(m_hwnd, iItem, data);
+ return iItem;
+}
+
+void CCtrlListBox::DeleteString(int index)
+{ ListBox_DeleteString(m_hwnd, index);
+}
+
+int CCtrlListBox::FindString(const wchar_t *str, int index, bool exact)
+{ return SendMessage(m_hwnd, exact?LB_FINDSTRINGEXACT:LB_FINDSTRING, index, (LPARAM)str);
+}
+
+int CCtrlListBox::GetCount() const
+{ return ListBox_GetCount(m_hwnd);
+}
+
+int CCtrlListBox::GetCurSel() const
+{ return ListBox_GetCurSel(m_hwnd);
+}
+
+LPARAM CCtrlListBox::GetItemData(int index) const
+{ return ListBox_GetItemData(m_hwnd, index);
+}
+
+int CCtrlListBox::GetItemRect(int index, RECT *pResult) const
+{ return ListBox_GetItemRect(m_hwnd, index, pResult);
+}
+
+wchar_t* CCtrlListBox::GetItemText(int index) const
+{
+ wchar_t *result = (wchar_t *)mir_alloc(sizeof(wchar_t) * (SendMessage(m_hwnd, LB_GETTEXTLEN, index, 0) + 1));
+ SendMessage(m_hwnd, LB_GETTEXT, index, (LPARAM)result);
+ return result;
+}
+
+wchar_t* CCtrlListBox::GetItemText(int index, wchar_t *buf, int size) const
+{
+ wchar_t *result = (wchar_t *)_alloca(sizeof(wchar_t) * (SendMessage(m_hwnd, LB_GETTEXTLEN, index, 0) + 1));
+ SendMessage(m_hwnd, LB_GETTEXT, index, (LPARAM)result);
+ mir_wstrncpy(buf, result, size);
+ return buf;
+}
+
+bool CCtrlListBox::GetSel(int index) const
+{ return ListBox_GetSel(m_hwnd, index) ? true : false;
+}
+
+int CCtrlListBox::GetSelCount() const
+{ return ListBox_GetSelCount(m_hwnd);
+}
+
+int* CCtrlListBox::GetSelItems(int *items, int count) const
+{
+ ListBox_GetSelItems(m_hwnd, count, items);
+ return items;
+}
+
+int* CCtrlListBox::GetSelItems() const
+{
+ int count = GetSelCount() + 1;
+ int *result = (int *)mir_alloc(sizeof(int) * count);
+ ListBox_GetSelItems(m_hwnd, count, result);
+ result[count-1] = -1;
+ return result;
+}
+
+int CCtrlListBox::InsertString(const wchar_t *text, int pos, LPARAM data)
+{
+ int iItem = ListBox_InsertString(m_hwnd, pos, text);
+ ListBox_SetItemData(m_hwnd, iItem, data);
+ return iItem;
+}
+
+void CCtrlListBox::ResetContent()
+{ ListBox_ResetContent(m_hwnd);
+}
+
+int CCtrlListBox::SelectString(const wchar_t *str)
+{ return ListBox_SelectString(m_hwnd, 0, str);
+}
+
+int CCtrlListBox::SetCurSel(int index)
+{ return ListBox_SetCurSel(m_hwnd, index);
+}
+
+void CCtrlListBox::SetItemData(int index, LPARAM data)
+{ ListBox_SetItemData(m_hwnd, index, data);
+}
+
+void CCtrlListBox::SetItemHeight(int index, int iHeight)
+{ ListBox_SetItemHeight(m_hwnd, index, iHeight);
+}
+
+void CCtrlListBox::SetSel(int index, bool sel)
+{ ListBox_SetSel(m_hwnd, sel ? TRUE : FALSE, index);
+}
diff --git a/src/mir_core/src/Linux/CCtrlListView.cpp b/src/mir_core/src/Linux/CCtrlListView.cpp
new file mode 100644
index 0000000000..eb57951a3c
--- /dev/null
+++ b/src/mir_core/src/Linux/CCtrlListView.cpp
@@ -0,0 +1,551 @@
+/*
+
+Object UI extensions
+Copyright (c) 2008 Victor Pavlychko, George Hazan
+Copyright (C) 2012-22 Miranda NG team
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+*/
+
+#include "../stdafx.h"
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// CCtrlListView
+
+CCtrlListView::CCtrlListView(CDlgBase *dlg, int ctrlId)
+ : CCtrlBase(dlg, ctrlId)
+{}
+
+BOOL CCtrlListView::OnNotify(int, NMHDR *pnmh)
+{
+ TEventInfo evt = { this, pnmh };
+
+ switch (pnmh->code) {
+ case NM_CLICK: OnClick(&evt); return TRUE;
+ case NM_DBLCLK: OnDoubleClick(&evt); return TRUE;
+ case NM_CUSTOMDRAW: OnCustomDraw(&evt); return TRUE;
+ case LVN_BEGINDRAG: OnBeginDrag(&evt); return TRUE;
+ case LVN_BEGINLABELEDIT: OnBeginLabelEdit(&evt); return TRUE;
+ case LVN_BEGINRDRAG: OnBeginRDrag(&evt); return TRUE;
+ case LVN_BEGINSCROLL: OnBeginScroll(&evt); return TRUE;
+ case LVN_COLUMNCLICK: OnColumnClick(&evt); return TRUE;
+ case LVN_DELETEALLITEMS: OnDeleteAllItems(&evt); return TRUE;
+ case LVN_DELETEITEM: OnDeleteItem(&evt); return TRUE;
+ case LVN_ENDLABELEDIT: OnEndLabelEdit(&evt); return TRUE;
+ case LVN_ENDSCROLL: OnEndScroll(&evt); return TRUE;
+ case LVN_GETDISPINFO: OnGetDispInfo(&evt); return TRUE;
+ case LVN_GETINFOTIP: OnGetInfoTip(&evt); return TRUE;
+ case LVN_HOTTRACK: OnHotTrack(&evt); return TRUE;
+ case LVN_INSERTITEM: OnInsertItem(&evt); return TRUE;
+ case LVN_ITEMACTIVATE: OnItemActivate(&evt); return TRUE;
+ case LVN_ITEMCHANGING: OnItemChanging(&evt); return TRUE;
+ case LVN_KEYDOWN: OnKeyDown(&evt); return TRUE;
+ case LVN_MARQUEEBEGIN: OnMarqueeBegin(&evt); return TRUE;
+ case LVN_SETDISPINFO: OnSetDispInfo(&evt); return TRUE;
+
+ case LVN_ITEMCHANGED:
+ if (!m_parentWnd || !m_parentWnd->IsInitialized())
+ return FALSE;
+
+ OnItemChanged(&evt);
+
+ // item's state is calculated as 1/2 << 12, so we check it to filter out all non-state changes
+ if (evt.nmlv->uChanged & LVIF_STATE)
+ if ((evt.nmlv->uOldState >> 12) != 0 && (evt.nmlv->uNewState >> 12) != 0)
+ NotifyChange();
+ return TRUE;
+
+ case LVN_ODSTATECHANGED:
+ NotifyChange();
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+static int CALLBACK LVMoveSortProc(LPARAM l1, LPARAM l2, LPARAM param)
+{
+ int result = l1 - l2;
+ int newItem = HIWORD(param);
+ int oldItem = LOWORD(param);
+ if (newItem > oldItem)
+ return (l1 == oldItem && l2 <= newItem) ? 1 : result;
+
+ return (l2 == oldItem && l1 >= newItem) ? 1 : result;
+}
+
+int CCtrlListView::MoveItem(int idx, int direction)
+{
+ if ((direction > 0 && idx >= GetItemCount() - 1) || (direction < 0 && idx <= 0))
+ return idx;
+
+ if (idx < 0)
+ idx = GetNextItem(-1, LVNI_FOCUSED);
+ SortItemsEx(&LVMoveSortProc, MAKELONG(idx, idx + direction));
+ return idx + direction;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+void CCtrlListView::SetCurSel(int idx)
+{
+ SetItemState(idx, LVIS_FOCUSED | LVIS_SELECTED, LVIS_FOCUSED | LVIS_SELECTED);
+}
+
+// additional api
+HIMAGELIST CCtrlListView::CreateImageList(int iImageList)
+{
+ HIMAGELIST hIml = GetImageList(iImageList);
+ if (hIml)
+ return hIml;
+
+ hIml = ImageList_Create(16, 16, ILC_COLOR32 | ILC_MASK, 0, 1);
+ SetImageList(hIml, iImageList);
+ return hIml;
+}
+
+void CCtrlListView::AddColumn(int iSubItem, const wchar_t *name, int cx)
+{
+ LVCOLUMN lvc;
+ lvc.mask = LVCF_TEXT | LVCF_WIDTH | LVCF_SUBITEM;
+ lvc.iImage = 0;
+ lvc.pszText = (LPWSTR)name;
+ lvc.cx = cx;
+ lvc.iSubItem = iSubItem;
+ InsertColumn(iSubItem, &lvc);
+}
+
+void CCtrlListView::AddGroup(int iGroupId, const wchar_t *name)
+{
+ LVGROUP lvg = { 0 };
+ lvg.cbSize = sizeof(lvg);
+ lvg.mask = LVGF_HEADER | LVGF_GROUPID;
+ lvg.pszHeader = (LPWSTR)name;
+ lvg.cchHeader = (int)mir_wstrlen(lvg.pszHeader);
+ lvg.iGroupId = iGroupId;
+ InsertGroup(-1, &lvg);
+}
+
+int CCtrlListView::AddItem(const wchar_t *text, int iIcon, LPARAM lParam, int iGroupId)
+{
+ LVITEM lvi = { 0 };
+ lvi.mask = LVIF_PARAM | LVIF_TEXT | LVIF_IMAGE;
+ lvi.iSubItem = 0;
+ lvi.pszText = (LPWSTR)text;
+ lvi.iImage = iIcon;
+ lvi.lParam = lParam;
+ if (iGroupId >= 0) {
+ lvi.mask |= LVIF_GROUPID;
+ lvi.iGroupId = iGroupId;
+ }
+
+ return InsertItem(&lvi);
+}
+
+void CCtrlListView::SetItem(int iItem, int iSubItem, const wchar_t *text, int iIcon)
+{
+ LVITEM lvi = { 0 };
+ lvi.mask = LVIF_TEXT;
+ lvi.iItem = iItem;
+ lvi.iSubItem = iSubItem;
+ lvi.pszText = (LPWSTR)text;
+ if (iIcon >= 0) {
+ lvi.mask |= LVIF_IMAGE;
+ lvi.iImage = iIcon;
+ }
+
+ SetItem(&lvi);
+}
+
+LPARAM CCtrlListView::GetItemData(int iItem) const
+{
+ LVITEM lvi = { 0 };
+ lvi.mask = LVIF_PARAM;
+ lvi.iItem = iItem;
+ return GetItem(&lvi) ? lvi.lParam : -1;
+}
+
+void CCtrlListView::GetCaretPos(CContextMenuPos &pos) const
+{
+ pos.pCtrl = this;
+
+ // position is empty, let's fill it using selection
+ if (pos.pt.x == 0 && pos.pt.y == 0) {
+ pos.iCurr = GetSelectionMark();
+ if (pos.iCurr != -1) {
+ RECT rc;
+ GetItemRect(pos.iCurr, &rc, TRUE);
+ pos.pt.x = rc.left + 8;
+ pos.pt.y = rc.top + 8;
+ ClientToScreen(m_hwnd, &pos.pt);
+ return;
+ }
+ }
+ // position is present, let's calculate current item
+ else {
+ LVHITTESTINFO hti;
+ hti.pt = pos.pt;
+ ScreenToClient(m_hwnd, &hti.pt);
+ if (SubItemHitTest(&hti) != -1) {
+ pos.iCurr = hti.iItem;
+ return;
+ }
+ }
+ CSuper::GetCaretPos(pos);
+}
+
+// classic api
+uint32_t CCtrlListView::ApproximateViewRect(int cx, int cy, int iCount)
+{ return ListView_ApproximateViewRect(m_hwnd, cx, cy, iCount);
+}
+void CCtrlListView::Arrange(UINT code)
+{ ListView_Arrange(m_hwnd, code);
+}
+void CCtrlListView::CancelEditLabel()
+{ ListView_CancelEditLabel(m_hwnd);
+}
+HIMAGELIST CCtrlListView::CreateDragImage(int iItem, LPPOINT lpptUpLeft)
+{ return ListView_CreateDragImage(m_hwnd, iItem, lpptUpLeft);
+}
+void CCtrlListView::DeleteAllItems()
+{ ListView_DeleteAllItems(m_hwnd);
+}
+void CCtrlListView::DeleteColumn(int iCol)
+{ ListView_DeleteColumn(m_hwnd, iCol);
+}
+void CCtrlListView::DeleteItem(int iItem)
+{ ListView_DeleteItem(m_hwnd, iItem);
+}
+HWND CCtrlListView::EditLabel(int iItem)
+{ return ListView_EditLabel(m_hwnd, iItem);
+}
+int CCtrlListView::EnableGroupView(BOOL fEnable)
+{ return ListView_EnableGroupView(m_hwnd, fEnable);
+}
+BOOL CCtrlListView::EnsureVisible(int i, BOOL fPartialOK)
+{ return ListView_EnsureVisible(m_hwnd, i, fPartialOK);
+}
+int CCtrlListView::FindItem(int iStart, const LVFINDINFO *plvfi)
+{ return ListView_FindItem(m_hwnd, iStart, plvfi);
+}
+COLORREF CCtrlListView::GetBkColor() const
+{ return ListView_GetBkColor(m_hwnd);
+}
+void CCtrlListView::GetBkImage(LPLVBKIMAGE plvbki) const
+{ ListView_GetBkImage(m_hwnd, plvbki);
+}
+UINT CCtrlListView::GetCallbackMask() const
+{ return ListView_GetCallbackMask(m_hwnd);
+}
+BOOL CCtrlListView::GetCheckState(UINT iIndex) const
+{ return ListView_GetCheckState(m_hwnd, iIndex);
+}
+void CCtrlListView::GetColumn(int iCol, LPLVCOLUMN pcol) const
+{ ListView_GetColumn(m_hwnd, iCol, pcol);
+}
+void CCtrlListView::GetColumnOrderArray(int iCount, int *lpiArray) const
+{ ListView_GetColumnOrderArray(m_hwnd, iCount, lpiArray);
+}
+int CCtrlListView::GetColumnWidth(int iCol) const
+{ return ListView_GetColumnWidth(m_hwnd, iCol);
+}
+int CCtrlListView::GetCountPerPage() const
+{ return ListView_GetCountPerPage(m_hwnd);
+}
+HWND CCtrlListView::GetEditControl() const
+{ return ListView_GetEditControl(m_hwnd);
+}
+uint32_t CCtrlListView::GetExtendedListViewStyle() const
+{ return ListView_GetExtendedListViewStyle(m_hwnd);
+}
+void CCtrlListView::GetGroupMetrics(LVGROUPMETRICS *pGroupMetrics) const
+{ ListView_GetGroupMetrics(m_hwnd, pGroupMetrics);
+}
+HWND CCtrlListView::GetHeader() const
+{ return ListView_GetHeader(m_hwnd);
+}
+HCURSOR CCtrlListView::GetHotCursor() const
+{ return ListView_GetHotCursor(m_hwnd);
+}
+INT CCtrlListView::GetHotItem() const
+{ return ListView_GetHotItem(m_hwnd);
+}
+uint32_t CCtrlListView::GetHoverTime() const
+{ return ListView_GetHoverTime(m_hwnd);
+}
+HIMAGELIST CCtrlListView::GetImageList(int iImageList) const
+{ return ListView_GetImageList(m_hwnd, iImageList);
+}
+BOOL CCtrlListView::GetInsertMark(LVINSERTMARK *plvim) const
+{ return ListView_GetInsertMark(m_hwnd, plvim);
+}
+COLORREF CCtrlListView::GetInsertMarkColor() const
+{ return ListView_GetInsertMarkColor(m_hwnd);
+}
+int CCtrlListView::GetInsertMarkRect(LPRECT prc) const
+{ return ListView_GetInsertMarkRect(m_hwnd, prc);
+}
+BOOL CCtrlListView::GetISearchString(LPSTR lpsz) const
+{ return ListView_GetISearchString(m_hwnd, lpsz);
+}
+bool CCtrlListView::GetItem(LPLVITEM pitem) const
+{ return ListView_GetItem(m_hwnd, pitem) == TRUE;
+}
+int CCtrlListView::GetItemCount() const
+{ return ListView_GetItemCount(m_hwnd);
+}
+void CCtrlListView::GetItemPosition(int i, POINT *ppt) const
+{ ListView_GetItemPosition(m_hwnd, i, ppt);
+}
+void CCtrlListView::GetItemRect(int i, RECT *prc, int code) const
+{ ListView_GetItemRect(m_hwnd, i, prc, code);
+}
+uint32_t CCtrlListView::GetItemSpacing(BOOL fSmall) const
+{ return ListView_GetItemSpacing(m_hwnd, fSmall);
+}
+UINT CCtrlListView::GetItemState(int i, UINT mask) const
+{ return ListView_GetItemState(m_hwnd, i, mask);
+}
+void CCtrlListView::GetItemText(int iItem, int iSubItem, LPTSTR pszText, int cchTextMax) const
+{ ListView_GetItemText(m_hwnd, iItem, iSubItem, pszText, cchTextMax);
+}
+int CCtrlListView::GetNextItem(int iStart, UINT flags) const
+{ return ListView_GetNextItem(m_hwnd, iStart, flags);
+}
+BOOL CCtrlListView::GetNumberOfWorkAreas(LPUINT lpuWorkAreas) const
+{ return ListView_GetNumberOfWorkAreas(m_hwnd, lpuWorkAreas);
+}
+BOOL CCtrlListView::GetOrigin(LPPOINT lpptOrg) const
+{ return ListView_GetOrigin(m_hwnd, lpptOrg);
+}
+COLORREF CCtrlListView::GetOutlineColor() const
+{ return ListView_GetOutlineColor(m_hwnd);
+}
+UINT CCtrlListView::GetSelectedColumn() const
+{ return ListView_GetSelectedColumn(m_hwnd);
+}
+UINT CCtrlListView::GetSelectedCount() const
+{ return ListView_GetSelectedCount(m_hwnd);
+}
+INT CCtrlListView::GetSelectionMark() const
+{ return ListView_GetSelectionMark(m_hwnd);
+}
+int CCtrlListView::GetStringWidth(LPCSTR psz) const
+{ return ListView_GetStringWidth(m_hwnd, psz);
+}
+BOOL CCtrlListView::GetSubItemRect(int iItem, int iSubItem, int code, LPRECT lpRect) const
+{ return ListView_GetSubItemRect(m_hwnd, iItem, iSubItem, code, lpRect);
+}
+COLORREF CCtrlListView::GetTextBkColor() const
+{ return ListView_GetTextBkColor(m_hwnd);
+}
+COLORREF CCtrlListView::GetTextColor() const
+{ return ListView_GetTextColor(m_hwnd);
+}
+void CCtrlListView::GetTileInfo(PLVTILEINFO plvtinfo) const
+{ ListView_GetTileInfo(m_hwnd, plvtinfo);
+}
+void CCtrlListView::GetTileViewInfo(PLVTILEVIEWINFO plvtvinfo) const
+{ ListView_GetTileViewInfo(m_hwnd, plvtvinfo);
+}
+HWND CCtrlListView::GetToolTips() const
+{ return ListView_GetToolTips(m_hwnd);
+}
+int CCtrlListView::GetTopIndex() const
+{ return ListView_GetTopIndex(m_hwnd);
+}
+BOOL CCtrlListView::GetUnicodeFormat() const
+{ return ListView_GetUnicodeFormat(m_hwnd);
+}
+uint32_t CCtrlListView::GetView() const
+{ return ListView_GetView(m_hwnd);
+}
+BOOL CCtrlListView::GetViewRect(RECT *prc) const
+{ return ListView_GetViewRect(m_hwnd, prc);
+}
+void CCtrlListView::GetWorkAreas(INT nWorkAreas, LPRECT lprc) const
+{ ListView_GetWorkAreas(m_hwnd, nWorkAreas, lprc);
+}
+BOOL CCtrlListView::HasGroup(int dwGroupId)
+{ return ListView_HasGroup(m_hwnd, dwGroupId);
+}
+int CCtrlListView::HitTest(LPLVHITTESTINFO pinfo) const
+{ return ListView_HitTest(m_hwnd, pinfo);
+}
+int CCtrlListView::InsertColumn(int iCol, const LVCOLUMN *pcol)
+{ return ListView_InsertColumn(m_hwnd, iCol, pcol);
+}
+int CCtrlListView::InsertGroup(int index, PLVGROUP pgrp)
+{ return ListView_InsertGroup(m_hwnd, index, pgrp);
+}
+void CCtrlListView::InsertGroupSorted(PLVINSERTGROUPSORTED structInsert)
+{ ListView_InsertGroupSorted(m_hwnd, structInsert);
+}
+int CCtrlListView::InsertItem(const LVITEM *pitem)
+{ return ListView_InsertItem(m_hwnd, pitem);
+}
+BOOL CCtrlListView::InsertMarkHitTest(LPPOINT point, LVINSERTMARK *plvim)
+{ return ListView_InsertMarkHitTest(m_hwnd, point, plvim);
+}
+BOOL CCtrlListView::IsGroupViewEnabled()
+{ return ListView_IsGroupViewEnabled(m_hwnd);
+}
+UINT CCtrlListView::MapIDToIndex(UINT id)
+{ return ListView_MapIDToIndex(m_hwnd, id);
+}
+UINT CCtrlListView::MapIndexToID(UINT index)
+{ return ListView_MapIndexToID(m_hwnd, index);
+}
+BOOL CCtrlListView::RedrawItems(int iFirst, int iLast)
+{ return ListView_RedrawItems(m_hwnd, iFirst, iLast);
+}
+void CCtrlListView::RemoveAllGroups()
+{ ListView_RemoveAllGroups(m_hwnd);
+}
+int CCtrlListView::RemoveGroup(int iGroupId)
+{ return ListView_RemoveGroup(m_hwnd, iGroupId);
+}
+BOOL CCtrlListView::Scroll(int dx, int dy)
+{ return ListView_Scroll(m_hwnd, dx, dy);
+}
+BOOL CCtrlListView::SetBkColor(COLORREF clrBk)
+{ return ListView_SetBkColor(m_hwnd, clrBk);
+}
+BOOL CCtrlListView::SetBkImage(LPLVBKIMAGE plvbki)
+{ return ListView_SetBkImage(m_hwnd, plvbki);
+}
+BOOL CCtrlListView::SetCallbackMask(UINT mask)
+{ return ListView_SetCallbackMask(m_hwnd, mask);
+}
+void CCtrlListView::SetCheckState(UINT iIndex, BOOL fCheck)
+{ ListView_SetCheckState(m_hwnd, iIndex, fCheck);
+}
+BOOL CCtrlListView::SetColumn(int iCol, LPLVCOLUMN pcol)
+{ return ListView_SetColumn(m_hwnd, iCol, pcol);
+}
+BOOL CCtrlListView::SetColumnOrderArray(int iCount, int *lpiArray)
+{ return ListView_SetColumnOrderArray(m_hwnd, iCount, lpiArray);
+}
+BOOL CCtrlListView::SetColumnWidth(int iCol, int cx)
+{ return ListView_SetColumnWidth(m_hwnd, iCol, cx);
+}
+void CCtrlListView::SetExtendedListViewStyle(uint32_t dwExStyle)
+{ ListView_SetExtendedListViewStyle(m_hwnd, dwExStyle);
+}
+void CCtrlListView::SetExtendedListViewStyleEx(uint32_t dwExMask, uint32_t dwExStyle)
+{ ListView_SetExtendedListViewStyleEx(m_hwnd, dwExMask, dwExStyle);
+}
+int CCtrlListView::SetGroupInfo(int iGroupId, PLVGROUP pgrp)
+{ return ListView_SetGroupInfo(m_hwnd, iGroupId, pgrp);
+}
+void CCtrlListView::SetGroupMetrics(PLVGROUPMETRICS pGroupMetrics)
+{ ListView_SetGroupMetrics(m_hwnd, pGroupMetrics);
+}
+HCURSOR CCtrlListView::SetHotCursor(HCURSOR hCursor)
+{ return ListView_SetHotCursor(m_hwnd, hCursor);
+}
+INT CCtrlListView::SetHotItem(INT iIndex)
+{ return ListView_SetHotItem(m_hwnd, iIndex);
+}
+void CCtrlListView::SetHoverTime(uint32_t dwHoverTime)
+{ ListView_SetHoverTime(m_hwnd, dwHoverTime);
+}
+uint32_t CCtrlListView::SetIconSpacing(int cx, int cy)
+{ return ListView_SetIconSpacing(m_hwnd, cx, cy);
+}
+HIMAGELIST CCtrlListView::SetImageList(HIMAGELIST himl, int iImageList)
+{ return ListView_SetImageList(m_hwnd, himl, iImageList);
+}
+BOOL CCtrlListView::SetInfoTip(PLVSETINFOTIP plvSetInfoTip)
+{ return ListView_SetInfoTip(m_hwnd, plvSetInfoTip);
+}
+BOOL CCtrlListView::SetInsertMark(LVINSERTMARK *plvim)
+{ return ListView_SetInsertMark(m_hwnd, plvim);
+}
+COLORREF CCtrlListView::SetInsertMarkColor(COLORREF color)
+{ return ListView_SetInsertMarkColor(m_hwnd, color);
+}
+BOOL CCtrlListView::SetItem(const LVITEM *pitem)
+{ return ListView_SetItem(m_hwnd, pitem);
+}
+void CCtrlListView::SetItemCount(int cItems)
+{ ListView_SetItemCount(m_hwnd, cItems);
+}
+void CCtrlListView::SetItemCountEx(int cItems, uint32_t dwFlags)
+{ ListView_SetItemCountEx(m_hwnd, cItems, dwFlags);
+}
+BOOL CCtrlListView::SetItemPosition(int i, int x, int y)
+{ return ListView_SetItemPosition(m_hwnd, i, x, y);
+}
+void CCtrlListView::SetItemPosition32(int iItem, int x, int y)
+{ ListView_SetItemPosition32(m_hwnd, iItem, x, y);
+}
+void CCtrlListView::SetItemState(int i, UINT state, UINT mask)
+{ ListView_SetItemState(m_hwnd, i, state, mask);
+}
+void CCtrlListView::SetItemText(int i, int iSubItem, const wchar_t *pszText)
+{ ListView_SetItemText(m_hwnd, i, iSubItem, (LPWSTR)pszText);
+}
+COLORREF CCtrlListView::SetOutlineColor(COLORREF color)
+{ return ListView_SetOutlineColor(m_hwnd, color);
+}
+void CCtrlListView::SetSelectedColumn(int iCol)
+{ ListView_SetSelectedColumn(m_hwnd, iCol);
+}
+INT CCtrlListView::SetSelectionMark(INT iIndex)
+{ return ListView_SetSelectionMark(m_hwnd, iIndex);
+}
+BOOL CCtrlListView::SetTextBkColor(COLORREF clrText)
+{ return ListView_SetTextBkColor(m_hwnd, clrText);
+}
+BOOL CCtrlListView::SetTextColor(COLORREF clrText)
+{ return ListView_SetTextColor(m_hwnd, clrText);
+}
+BOOL CCtrlListView::SetTileInfo(PLVTILEINFO plvtinfo)
+{ return ListView_SetTileInfo(m_hwnd, plvtinfo);
+}
+BOOL CCtrlListView::SetTileViewInfo(PLVTILEVIEWINFO plvtvinfo)
+{ return ListView_SetTileViewInfo(m_hwnd, plvtvinfo);
+}
+HWND CCtrlListView::SetToolTips(HWND ToolTip)
+{ return ListView_SetToolTips(m_hwnd, ToolTip);
+}
+BOOL CCtrlListView::SetUnicodeFormat(BOOL fUnicode)
+{ return ListView_SetUnicodeFormat(m_hwnd, fUnicode);
+}
+int CCtrlListView::SetView(uint32_t iView)
+{ return ListView_SetView(m_hwnd, iView);
+}
+void CCtrlListView::SetWorkAreas(INT nWorkAreas, LPRECT lprc)
+{ ListView_SetWorkAreas(m_hwnd, nWorkAreas, lprc);
+}
+int CCtrlListView::SortGroups(PFNLVGROUPCOMPARE pfnGroupCompare, LPVOID plv)
+{ return ListView_SortGroups(m_hwnd, pfnGroupCompare, plv);
+}
+BOOL CCtrlListView::SortItems(PFNLVCOMPARE pfnCompare, LPARAM lParamSort)
+{ return ListView_SortItems(m_hwnd, pfnCompare, lParamSort);
+}
+BOOL CCtrlListView::SortItemsEx(PFNLVCOMPARE pfnCompare, LPARAM lParamSort)
+{ return ListView_SortItemsEx(m_hwnd, pfnCompare, lParamSort);
+}
+INT CCtrlListView::SubItemHitTest(LPLVHITTESTINFO pInfo) const
+{ return ListView_SubItemHitTest(m_hwnd, pInfo);
+}
+BOOL CCtrlListView::Update(int iItem)
+{ return ListView_Update(m_hwnd, iItem);
+}
diff --git a/src/mir_core/src/Linux/CCtrlMButton.cpp b/src/mir_core/src/Linux/CCtrlMButton.cpp
new file mode 100644
index 0000000000..8d9198e144
--- /dev/null
+++ b/src/mir_core/src/Linux/CCtrlMButton.cpp
@@ -0,0 +1,62 @@
+/*
+
+Object UI extensions
+Copyright (c) 2008 Victor Pavlychko, George Hazan
+Copyright (C) 2012-22 Miranda NG team
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+*/
+
+#include "../stdafx.h"
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// CCtrlMButton
+
+CCtrlMButton::CCtrlMButton(CDlgBase *dlg, int ctrlId, HICON hIcon, const char* tooltip)
+ : CCtrlButton(dlg, ctrlId),
+ m_hIcon(hIcon),
+ m_toolTip(tooltip)
+{}
+
+CCtrlMButton::CCtrlMButton(CDlgBase *dlg, int ctrlId, int iCoreIcon, const char* tooltip)
+ : CCtrlButton(dlg, ctrlId),
+ m_hIcon(::Skin_LoadIcon(iCoreIcon)),
+ m_toolTip(tooltip)
+{}
+
+CCtrlMButton::~CCtrlMButton()
+{
+ ::IcoLib_ReleaseIcon(m_hIcon);
+}
+
+void CCtrlMButton::OnInit()
+{
+ CCtrlButton::OnInit();
+
+ SendMessage(m_hwnd, BM_SETIMAGE, IMAGE_ICON, (LPARAM)m_hIcon);
+ SendMessage(m_hwnd, BUTTONADDTOOLTIP, (WPARAM)m_toolTip, 0);
+ SendMessage(m_hwnd, BUTTONSETASFLATBTN, (WPARAM)m_toolTip, 0);
+}
+
+void CCtrlMButton::MakeFlat()
+{
+ SendMessage(m_hwnd, BUTTONSETASFLATBTN, TRUE, 0);
+}
+
+void CCtrlMButton::MakePush()
+{
+ SendMessage(m_hwnd, BUTTONSETASPUSHBTN, TRUE, 0);
+}
diff --git a/src/mir_core/src/Linux/CCtrlPages.cpp b/src/mir_core/src/Linux/CCtrlPages.cpp
new file mode 100644
index 0000000000..512c32e142
--- /dev/null
+++ b/src/mir_core/src/Linux/CCtrlPages.cpp
@@ -0,0 +1,411 @@
+/*
+
+Object UI extensions
+Copyright (c) 2008 Victor Pavlychko, George Hazan
+Copyright (C) 2012-22 Miranda NG team
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+*/
+
+#include "../stdafx.h"
+
+static volatile long g_order = 1;
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// CCtrlPages
+
+struct CCtrlPages::TPageInfo : public MZeroedObject
+{
+ TPageInfo()
+ {
+ m_iOrder = InterlockedIncrement(&g_order);
+ }
+
+ ~TPageInfo()
+ {
+ if (m_hIcon)
+ DestroyIcon(m_hIcon);
+ }
+
+ int m_iOrder;
+ ptrW m_ptszHeader;
+ HICON m_hIcon;
+ bool m_bChanged, m_bScheduledResize;
+ CDlgBase *m_pDlg;
+};
+
+CCtrlPages::CCtrlPages(CDlgBase *dlg, int ctrlId)
+ : CCtrlBase(dlg, ctrlId),
+ m_hIml(nullptr),
+ m_pActivePage(nullptr),
+ m_pages(4, NumericKeySortT)
+{}
+
+void CCtrlPages::OnInit()
+{
+ CSuper::OnInit();
+ Subclass();
+
+ for (auto &it : m_pages)
+ InsertPage(it);
+ m_pages.destroy();
+
+ ::SetWindowLongPtr(m_hwnd, GWL_EXSTYLE, ::GetWindowLongPtr(m_hwnd, GWL_EXSTYLE) | WS_EX_CONTROLPARENT);
+
+ TPageInfo *info = GetCurrPage();
+ if (info) {
+ m_pActivePage = info->m_pDlg;
+ ShowPage(m_pActivePage);
+
+ PSHNOTIFY pshn;
+ pshn.hdr.code = PSN_INFOCHANGED;
+ pshn.hdr.hwndFrom = m_pActivePage->GetHwnd();
+ pshn.hdr.idFrom = 0;
+ pshn.lParam = 0;
+ SendMessage(pshn.hdr.hwndFrom, WM_NOTIFY, 0, (LPARAM)&pshn);
+ }
+}
+
+LRESULT CCtrlPages::CustomWndProc(UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ int tabCount;
+
+ switch (msg) {
+ case WM_SIZE:
+ if (TPageInfo *pCurrInfo = GetCurrPage()) {
+ tabCount = GetCount();
+ for (int i = 0; i < tabCount; i++) {
+ TPageInfo *p = GetItemPage(i);
+ if (p == nullptr)
+ continue;
+ if (p == pCurrInfo) {
+ RECT rc;
+ GetClientRect(m_hwnd, &rc);
+ TabCtrl_AdjustRect(m_hwnd, FALSE, &rc);
+ SetWindowPos(p->m_pDlg->GetHwnd(), nullptr, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, SWP_NOACTIVATE | SWP_NOZORDER);
+ }
+ else p->m_bScheduledResize = true;
+ }
+ }
+ break;
+
+ case PSM_CHANGED:
+ if (TPageInfo *info = GetCurrPage())
+ info->m_bChanged = TRUE;
+ return TRUE;
+
+ case PSM_FORCECHANGED:
+ tabCount = GetCount();
+
+ PSHNOTIFY pshn;
+ pshn.hdr.code = PSN_INFOCHANGED;
+ pshn.hdr.idFrom = 0;
+ pshn.lParam = 0;
+ for (int i = 0; i < tabCount; i++) {
+ TPageInfo *p = GetItemPage(i);
+ if (p) {
+ pshn.hdr.hwndFrom = p->m_pDlg->GetHwnd();
+ if (pshn.hdr.hwndFrom != nullptr)
+ SendMessage(pshn.hdr.hwndFrom, WM_NOTIFY, 0, (LPARAM)&pshn);
+ }
+ }
+ break;
+ }
+
+ return CSuper::CustomWndProc(msg, wParam, lParam);
+}
+
+void CCtrlPages::AddPage(const wchar_t *ptszName, HICON hIcon, CDlgBase *pDlg)
+{
+ TPageInfo *info = new TPageInfo;
+ info->m_pDlg = pDlg;
+ info->m_hIcon = hIcon;
+ info->m_ptszHeader = mir_wstrdup(ptszName);
+
+ if (m_hwnd != nullptr) {
+ InsertPage(info);
+
+ if (GetCount() == 1) {
+ m_pActivePage = info->m_pDlg;
+ ShowPage(m_pActivePage);
+ }
+ }
+ m_pages.insert(info);
+}
+
+void CCtrlPages::ActivatePage(int iPage)
+{
+ TPageInfo *info = GetItemPage(iPage);
+ if (info == nullptr || info->m_pDlg == nullptr)
+ return;
+
+ if (m_pActivePage != nullptr)
+ ShowWindow(m_pActivePage->GetHwnd(), SW_HIDE);
+
+ m_pActivePage = info->m_pDlg;
+ if (m_pActivePage->GetHwnd() && info->m_bScheduledResize) {
+ RECT rc;
+ GetClientRect(m_hwnd, &rc);
+ TabCtrl_AdjustRect(m_hwnd, FALSE, &rc);
+ SetWindowPos(m_pActivePage->GetHwnd(), nullptr, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, SWP_NOACTIVATE | SWP_NOZORDER);
+ }
+
+ TabCtrl_SetCurSel(m_hwnd, iPage);
+ ShowPage(m_pActivePage);
+ ::SendMessage(m_pActivePage->GetHwnd(), WM_MOUSEACTIVATE, 0, 0);
+}
+
+void CCtrlPages::CheckRowCount()
+{
+ int iRowCount = TabCtrl_GetRowCount(m_hwnd);
+ if (m_numRows != iRowCount) {
+ m_numRows = iRowCount;
+ for (auto &p : m_pages)
+ p->m_bScheduledResize = true;
+ }
+}
+
+int CCtrlPages::GetCount()
+{
+ return TabCtrl_GetItemCount(m_hwnd);
+}
+
+CDlgBase* CCtrlPages::GetNthPage(int iPage)
+{
+ TPageInfo *info = GetItemPage(iPage);
+ return (info == nullptr) ? nullptr : info->m_pDlg;
+}
+
+CCtrlPages::TPageInfo* CCtrlPages::GetCurrPage()
+{
+ TCITEM tci = { 0 };
+ tci.mask = TCIF_PARAM;
+ if (!TabCtrl_GetItem(m_hwnd, TabCtrl_GetCurSel(m_hwnd), &tci))
+ return nullptr;
+
+ return (TPageInfo*)tci.lParam;
+}
+
+CCtrlPages::TPageInfo* CCtrlPages::GetItemPage(int iPage)
+{
+ TCITEM tci = { 0 };
+ tci.mask = TCIF_PARAM;
+ if (!TabCtrl_GetItem(m_hwnd, iPage, &tci))
+ return nullptr;
+
+ return (TPageInfo*)tci.lParam;
+}
+
+int CCtrlPages::GetDlgIndex(CDlgBase *pDlg)
+{
+ int tabCount = TabCtrl_GetItemCount(m_hwnd);
+ for (int i = 0; i < tabCount; i++) {
+ TCITEM tci;
+ tci.mask = TCIF_PARAM | TCIF_IMAGE;
+ TabCtrl_GetItem(m_hwnd, i, &tci);
+ TPageInfo *pPage = (TPageInfo *)tci.lParam;
+ if (pPage == nullptr)
+ continue;
+
+ if (pPage->m_pDlg == pDlg)
+ return i;
+ }
+
+ return -1;
+}
+
+void CCtrlPages::InsertPage(TPageInfo *pPage)
+{
+ TCITEM tci = { 0 };
+ tci.mask = TCIF_PARAM | TCIF_TEXT;
+ tci.lParam = (LPARAM)pPage;
+ tci.pszText = TranslateW_LP(pPage->m_ptszHeader);
+ if (pPage->m_hIcon) {
+ if (!m_hIml) {
+ m_hIml = ImageList_Create(16, 16, ILC_COLOR32 | ILC_MASK, 0, 1);
+ TabCtrl_SetImageList(m_hwnd, m_hIml);
+ }
+
+ tci.mask |= TCIF_IMAGE;
+ tci.iImage = ImageList_AddIcon(m_hIml, pPage->m_hIcon);
+ }
+
+ TabCtrl_InsertItem(m_hwnd, TabCtrl_GetItemCount(m_hwnd), &tci);
+
+ CheckRowCount();
+}
+
+void CCtrlPages::RemovePage(int iPage)
+{
+ TPageInfo *p = GetItemPage(iPage);
+ if (p == nullptr)
+ return;
+
+ TabCtrl_DeleteItem(m_hwnd, iPage);
+ m_pages.remove(p);
+ delete p;
+
+ CheckRowCount();
+}
+
+void CCtrlPages::ShowPage(CDlgBase *pDlg)
+{
+ if (pDlg->GetHwnd() == nullptr) {
+ pDlg->SetParent(m_hwnd);
+ pDlg->Create();
+
+ RECT rc;
+ GetClientRect(m_hwnd, &rc);
+ TabCtrl_AdjustRect(m_hwnd, FALSE, &rc);
+ SetWindowPos(pDlg->GetHwnd(), HWND_TOP, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, SWP_NOACTIVATE);
+
+ EnableThemeDialogTexture(pDlg->GetHwnd(), ETDT_ENABLETAB);
+
+ PSHNOTIFY pshn;
+ pshn.hdr.code = PSN_INFOCHANGED;
+ pshn.hdr.hwndFrom = pDlg->GetHwnd();
+ pshn.hdr.idFrom = 0;
+ pshn.lParam = 0;
+ SendMessage(pshn.hdr.hwndFrom, WM_NOTIFY, 0, (LPARAM)&pshn);
+ }
+ ShowWindow(pDlg->GetHwnd(), SW_SHOW);
+}
+
+void CCtrlPages::SwapPages(int idx1, int idx2)
+{
+ TPageInfo *p1 = GetItemPage(idx1), *p2 = GetItemPage(idx2);
+ if (p1 == nullptr || p2 == nullptr)
+ return;
+
+ TabCtrl_DeleteItem(m_hwnd, idx1);
+
+ TCITEM tci = { 0 };
+ tci.mask = TCIF_PARAM | TCIF_TEXT;
+ tci.lParam = (LPARAM)p1;
+ tci.pszText = TranslateW_LP(p1->m_ptszHeader);
+ TabCtrl_InsertItem(m_hwnd, idx2, &tci);
+}
+
+BOOL CCtrlPages::OnNotify(int /*idCtrl*/, NMHDR *pnmh)
+{
+ TPageInfo *info;
+ PSHNOTIFY pshn;
+
+ switch (pnmh->code) {
+ case TCN_SELCHANGING:
+ if (info = GetCurrPage()) {
+ pshn.hdr.code = PSN_KILLACTIVE;
+ pshn.hdr.hwndFrom = info->m_pDlg->GetHwnd();
+ pshn.hdr.idFrom = 0;
+ pshn.lParam = 0;
+ if (SendMessage(pshn.hdr.hwndFrom, WM_NOTIFY, 0, (LPARAM)&pshn)) {
+ SetWindowLongPtr(GetParent()->GetHwnd(), DWLP_MSGRESULT, TRUE);
+ return TRUE;
+ }
+ }
+ return TRUE;
+
+ case TCN_SELCHANGE:
+ if (m_pActivePage != nullptr)
+ m_pActivePage->Hide();
+
+ if (info = GetCurrPage()) {
+ m_pActivePage = info->m_pDlg;
+ ShowPage(m_pActivePage);
+ }
+ else m_pActivePage = nullptr;
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+void CCtrlPages::OnReset()
+{
+ CSuper::OnReset();
+
+ PSHNOTIFY pshn;
+ pshn.hdr.code = PSN_INFOCHANGED;
+ pshn.hdr.idFrom = 0;
+ pshn.lParam = 0;
+
+ int tabCount = GetCount();
+ for (int i = 0; i < tabCount; i++) {
+ TPageInfo *p = GetItemPage(i);
+ if (p->m_pDlg->GetHwnd() == nullptr || !p->m_bChanged)
+ continue;
+
+ pshn.hdr.hwndFrom = p->m_pDlg->GetHwnd();
+ SendMessage(pshn.hdr.hwndFrom, WM_NOTIFY, 0, (LPARAM)&pshn);
+ }
+}
+
+bool CCtrlPages::OnApply()
+{
+ PSHNOTIFY pshn;
+ pshn.hdr.idFrom = 0;
+ pshn.lParam = 0;
+
+ if (m_pActivePage != nullptr) {
+ pshn.hdr.code = PSN_KILLACTIVE;
+ pshn.hdr.hwndFrom = m_pActivePage->GetHwnd();
+ if (SendMessage(pshn.hdr.hwndFrom, WM_NOTIFY, 0, (LPARAM)&pshn))
+ return false;
+ }
+
+ pshn.hdr.code = PSN_APPLY;
+ int tabCount = GetCount();
+ for (int i = 0; i < tabCount; i++) {
+ TPageInfo *p = GetItemPage(i);
+ if (p->m_pDlg->GetHwnd() == nullptr || !p->m_bChanged)
+ continue;
+
+ pshn.hdr.hwndFrom = p->m_pDlg->GetHwnd();
+ SendMessage(pshn.hdr.hwndFrom, WM_NOTIFY, 0, (LPARAM)&pshn);
+ if (GetWindowLongPtr(pshn.hdr.hwndFrom, DWLP_MSGRESULT) == PSNRET_INVALID_NOCHANGEPAGE) {
+ TabCtrl_SetCurSel(m_hwnd, i);
+ if (m_pActivePage != nullptr)
+ m_pActivePage->Hide();
+ m_pActivePage = p->m_pDlg;
+ m_pActivePage->Show();
+ return false;
+ }
+ }
+
+ CSuper::OnApply();
+ return true;
+}
+
+void CCtrlPages::OnDestroy()
+{
+ int tabCount = GetCount();
+ for (int i = 0; i < tabCount; i++) {
+ TPageInfo *p = GetItemPage(i);
+ CDlgBase *pDlg = p->m_pDlg; p->m_pDlg = nullptr;
+ if (pDlg->GetHwnd())
+ pDlg->Close();
+ delete p;
+ }
+
+ TabCtrl_DeleteAllItems(m_hwnd);
+
+ if (m_hIml) {
+ TabCtrl_SetImageList(m_hwnd, nullptr);
+ ImageList_Destroy(m_hIml);
+ }
+
+ CSuper::OnDestroy();
+}
diff --git a/src/mir_core/src/Linux/CCtrlSlider.cpp b/src/mir_core/src/Linux/CCtrlSlider.cpp
new file mode 100644
index 0000000000..69aeb24796
--- /dev/null
+++ b/src/mir_core/src/Linux/CCtrlSlider.cpp
@@ -0,0 +1,70 @@
+/*
+
+Object UI extensions
+Copyright (c) 2008 Victor Pavlychko, George Hazan
+Copyright (C) 2012-22 Miranda NG team
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+*/
+
+#include "../stdafx.h"
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// CCtrlSlider class
+
+CCtrlSlider::CCtrlSlider(CDlgBase *dlg, int ctrlId, int wMax, int wMin) :
+ CCtrlData(dlg, ctrlId),
+ m_wMin(wMin),
+ m_wMax(wMax)
+{
+ m_bNotifiable = true;
+}
+
+BOOL CCtrlSlider::OnCommand(HWND, uint16_t, uint16_t idCode)
+{
+ if (idCode == WM_HSCROLL) {
+ NotifyChange();
+ return TRUE;
+ }
+ return FALSE;
+}
+
+bool CCtrlSlider::OnApply()
+{
+ CSuper::OnApply();
+
+ if (m_dbLink != nullptr)
+ SaveInt(GetPosition());
+ return true;
+}
+
+void CCtrlSlider::OnReset()
+{
+ SendMsg(TBM_SETRANGE, 0, MAKELONG(m_wMin, m_wMax));
+
+ if (m_dbLink != nullptr)
+ SetPosition(LoadInt());
+}
+
+int CCtrlSlider::GetPosition() const
+{
+ return SendMsg(TBM_GETPOS, 0, 0);
+}
+
+void CCtrlSlider::SetPosition(int wPos)
+{
+ SendMsg(TBM_SETPOS, TRUE, wPos);
+}
diff --git a/src/mir_core/src/Linux/CCtrlSpin.cpp b/src/mir_core/src/Linux/CCtrlSpin.cpp
new file mode 100644
index 0000000000..54d43e933a
--- /dev/null
+++ b/src/mir_core/src/Linux/CCtrlSpin.cpp
@@ -0,0 +1,81 @@
+/*
+
+Object UI extensions
+Copyright (c) 2008 Victor Pavlychko, George Hazan
+Copyright (C) 2012-22 Miranda NG team
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+*/
+
+#include "../stdafx.h"
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// CCtrlSpin class
+
+CCtrlSpin::CCtrlSpin(CDlgBase *dlg, int ctrlId, int16_t wMax, int16_t wMin) :
+ CCtrlData(dlg, ctrlId),
+ m_wMin(wMin),
+ m_wMax(wMax),
+ m_wCurr(0)
+{}
+
+BOOL CCtrlSpin::OnNotify(int, NMHDR *pnmh)
+{
+ if (pnmh->code == UDN_DELTAPOS) {
+ auto *pEvent = (NMUPDOWN *)pnmh;
+ m_wCurr = pEvent->iPos + pEvent->iDelta;
+
+ NotifyChange();
+ return TRUE;
+ }
+ return FALSE;
+}
+
+bool CCtrlSpin::OnApply()
+{
+ CSuper::OnApply();
+
+ m_wCurr = SendMsg(UDM_GETPOS, 0, 0);
+ if (m_dbLink != nullptr)
+ SaveInt(m_wCurr);
+
+ HWND hwndBuddy = (HWND)SendMsg(UDM_GETBUDDY, 0, 0);
+ if (hwndBuddy) {
+ wchar_t buf[100];
+ _itow(m_wCurr, buf, 10);
+ ::SendMessage(hwndBuddy, WM_SETTEXT, 0, LPARAM(buf));
+ }
+
+ return true;
+}
+
+void CCtrlSpin::OnReset()
+{
+ SendMsg(UDM_SETRANGE, 0, MAKELPARAM(m_wMax, m_wMin));
+
+ if (m_dbLink != nullptr)
+ SetPosition(LoadInt());
+}
+
+int16_t CCtrlSpin::GetPosition()
+{
+ return m_wCurr;
+}
+
+void CCtrlSpin::SetPosition(int16_t wPos)
+{
+ SendMsg(UDM_SETPOS, 0, m_wCurr = wPos);
+}
diff --git a/src/mir_core/src/Linux/CCtrlTreeOpts.cpp b/src/mir_core/src/Linux/CCtrlTreeOpts.cpp
new file mode 100644
index 0000000000..13a6b79bd3
--- /dev/null
+++ b/src/mir_core/src/Linux/CCtrlTreeOpts.cpp
@@ -0,0 +1,216 @@
+/*
+
+Object UI extensions
+Copyright (c) 2008 Victor Pavlychko, George Hazan
+Copyright (C) 2012-22 Miranda NG team
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+*/
+
+#include "../stdafx.h"
+
+enum { IMG_GROUP, IMG_CHECK, IMG_NOCHECK, IMG_GRPOPEN, IMG_GRPCLOSED };
+
+CCtrlTreeOpts::CCtrlTreeOpts(CDlgBase* dlg, int ctrlId):
+ CCtrlTreeView(dlg, ctrlId),
+ m_options(5)
+{
+}
+
+CCtrlTreeOpts::~CCtrlTreeOpts()
+{
+}
+
+void CCtrlTreeOpts::AddOption(const wchar_t *pwszSection, const wchar_t *pwszName, CMOption<bool> &option)
+{
+ auto *p = new COptionsItem(pwszSection, pwszName, COptionsItem::CMOPTION);
+ p->m_option = &option;
+ m_options.insert(p, m_options.getCount());
+}
+
+void CCtrlTreeOpts::AddOption(const wchar_t *pwszSection, const wchar_t *pwszName, bool &option)
+{
+ auto *p = new COptionsItem(pwszSection, pwszName, COptionsItem::BOOL);
+ p->m_pBool = &option;
+ m_options.insert(p, m_options.getCount());
+}
+
+void CCtrlTreeOpts::AddOption(const wchar_t *pwszSection, const wchar_t *pwszName, uint32_t &option, uint32_t mask)
+{
+ auto *p = new COptionsItem(pwszSection, pwszName, COptionsItem::MASK);
+ p->m_pDword = &option;
+ p->m_mask = mask;
+ m_options.insert(p, m_options.getCount());
+}
+
+BOOL CCtrlTreeOpts::OnNotify(int idCtrl, NMHDR *pnmh)
+{
+ switch (pnmh->code) {
+ case TVN_KEYDOWN:
+ {
+ LPNMTVKEYDOWN lpnmtvkd = (LPNMTVKEYDOWN)pnmh;
+ HTREEITEM hti;
+ if ((lpnmtvkd->wVKey == VK_SPACE) && (hti = GetSelection()))
+ ProcessItemClick(hti);
+ }
+ break;
+
+ case NM_CLICK:
+ TVHITTESTINFO htti;
+ htti.pt.x = (short)LOWORD(GetMessagePos());
+ htti.pt.y = (short)HIWORD(GetMessagePos());
+ ScreenToClient(pnmh->hwndFrom, &htti.pt);
+ if (HitTest(&htti))
+ if (htti.flags & TVHT_ONITEMICON)
+ ProcessItemClick(htti.hItem);
+ break;
+
+ case TVN_ITEMEXPANDED:
+ LPNMTREEVIEW lpnmtv = (LPNMTREEVIEW)pnmh;
+ TVITEM tvi;
+ tvi.mask = TVIF_HANDLE | TVIF_IMAGE | TVIF_SELECTEDIMAGE;
+ tvi.hItem = lpnmtv->itemNew.hItem;
+ tvi.iImage = tvi.iSelectedImage = (lpnmtv->itemNew.state & TVIS_EXPANDED) ? IMG_GRPOPEN : IMG_GRPCLOSED;
+ SendMessage(pnmh->hwndFrom, TVM_SETITEM, 0, (LPARAM)&tvi);
+ break;
+ }
+
+ return CSuper::OnNotify(idCtrl, pnmh);
+}
+
+void CCtrlTreeOpts::OnInit()
+{
+ CSuper::OnInit();
+
+ SelectItem(nullptr);
+ DeleteAllItems();
+
+ HIMAGELIST hImgLst = ImageList_Create(GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), ILC_COLOR | ILC_COLOR32 | ILC_MASK, 5, 1);
+ ImageList_AddSkinIcon(hImgLst, SKINICON_OTHER_MIRANDA);
+ ImageList_AddSkinIcon(hImgLst, SKINICON_OTHER_TICK);
+ ImageList_AddSkinIcon(hImgLst, SKINICON_OTHER_NOTICK);
+ ImageList_AddSkinIcon(hImgLst, SKINICON_OTHER_GROUPOPEN);
+ ImageList_AddSkinIcon(hImgLst, SKINICON_OTHER_GROUPSHUT);
+ SetImageList(hImgLst, TVSIL_NORMAL);
+
+ /* build options tree. based on code from IcoLib */
+ for (auto &it : m_options) {
+ if (it->m_pwszSection) {
+ HTREEITEM hSection = FindNamedItem(nullptr, it->m_pwszSection);
+ if (!hSection) {
+ TVINSERTSTRUCT tvis = {};
+ tvis.hParent = hSection;
+ tvis.hInsertAfter = TVI_LAST;
+ tvis.item.mask = TVIF_TEXT | TVIF_PARAM | TVIF_STATE | TVIF_IMAGE | TVIF_SELECTEDIMAGE;
+ tvis.item.pszText = (LPWSTR)it->m_pwszSection;
+ tvis.item.state = tvis.item.stateMask = TVIS_EXPANDED | TVIS_BOLD;
+ tvis.item.iImage = tvis.item.iSelectedImage = IMG_GRPOPEN;
+ hSection = InsertItem(&tvis);
+ }
+
+ bool bValue;
+ switch (it->m_type) {
+ case COptionsItem::CMOPTION:
+ bValue = *it->m_option;
+ break;
+ case COptionsItem::BOOL:
+ bValue = *it->m_pBool;
+ break;
+ case COptionsItem::MASK:
+ bValue = (*it->m_pDword & it->m_mask) != 0;
+ break;
+ default:
+ continue;
+ }
+
+ TVINSERTSTRUCT tvis = {};
+ tvis.hParent = hSection;
+ tvis.hInsertAfter = TVI_LAST;
+ tvis.item.mask = TVIF_TEXT | TVIF_PARAM | TVIF_STATE | TVIF_IMAGE | TVIF_SELECTEDIMAGE;
+ tvis.item.pszText = (LPWSTR)it->m_pwszName;
+ tvis.item.state = tvis.item.stateMask = TVIS_EXPANDED;
+ tvis.item.lParam = m_options.indexOf(&it);
+ tvis.item.iImage = tvis.item.iSelectedImage = (bValue) ? IMG_CHECK : IMG_NOCHECK;
+
+ it->m_hItem = InsertItem(&tvis);
+ }
+ }
+
+ TranslateTree();
+ ShowWindow(m_hwnd, SW_SHOW);
+ SelectItem(FindNamedItem(nullptr, nullptr));
+}
+
+void CCtrlTreeOpts::OnDestroy()
+{
+ ImageList_Destroy(GetImageList(TVSIL_NORMAL));
+}
+
+bool CCtrlTreeOpts::OnApply()
+{
+ CSuper::OnApply();
+
+ for (auto &it : m_options) {
+ TVITEMEX tvi;
+ GetItem(it->m_hItem, &tvi);
+
+ bool bValue = (tvi.iImage == IMG_CHECK);
+ switch (it->m_type) {
+ case COptionsItem::CMOPTION:
+ *it->m_option = bValue;
+ break;
+ case COptionsItem::BOOL:
+ *it->m_pBool = bValue;
+ break;
+ case COptionsItem::MASK:
+ if (bValue)
+ *it->m_pDword |= it->m_mask;
+ else
+ *it->m_pDword &= ~it->m_mask;
+ break;
+ }
+ }
+ return true;
+}
+
+void CCtrlTreeOpts::ProcessItemClick(HTREEITEM hti)
+{
+ TVITEMEX tvi;
+ GetItem(hti, &tvi);
+ switch (tvi.iImage) {
+ case IMG_GRPOPEN:
+ tvi.iImage = tvi.iSelectedImage = IMG_GRPCLOSED;
+ Expand(tvi.hItem, TVE_COLLAPSE);
+ break;
+
+ case IMG_GRPCLOSED:
+ tvi.iImage = tvi.iSelectedImage = IMG_GRPOPEN;
+ Expand(tvi.hItem, TVE_EXPAND);
+ break;
+
+ case IMG_CHECK:
+ tvi.iImage = tvi.iSelectedImage = IMG_NOCHECK;
+ NotifyChange();
+ break;
+
+ case IMG_NOCHECK:
+ tvi.iImage = tvi.iSelectedImage = IMG_CHECK;
+ NotifyChange();
+ break;
+ }
+
+ SetItem(&tvi);
+}
diff --git a/src/mir_core/src/Linux/CCtrlTreeView.cpp b/src/mir_core/src/Linux/CCtrlTreeView.cpp
new file mode 100644
index 0000000000..390f1618fc
--- /dev/null
+++ b/src/mir_core/src/Linux/CCtrlTreeView.cpp
@@ -0,0 +1,817 @@
+/*
+
+Object UI extensions
+Copyright (c) 2008 Victor Pavlychko, George Hazan
+Copyright (C) 2012-22 Miranda NG team
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+*/
+
+#include "../stdafx.h"
+
+int ImageList_AddIcon_IconLibLoaded(HIMAGELIST hIml, int iconId)
+{
+ HICON hIcon = Skin_LoadIcon(iconId);
+ int res = ImageList_AddIcon(hIml, hIcon);
+ IcoLib_ReleaseIcon(hIcon);
+ return res;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// CCtrlTreeView
+
+CCtrlTreeView::CCtrlTreeView(CDlgBase *dlg, int ctrlId) :
+ CCtrlBase(dlg, ctrlId),
+ m_dwFlags(0),
+ m_hDragItem(nullptr)
+{}
+
+void CCtrlTreeView::SetFlags(uint32_t dwFlags)
+{
+ if (dwFlags & MTREE_CHECKBOX)
+ m_bCheckBox = true;
+
+ if (dwFlags & MTREE_MULTISELECT)
+ m_bMultiSelect = true;
+
+ if (dwFlags & MTREE_DND) {
+ m_bDndEnabled = true;
+ m_bDragging = false;
+ m_hDragItem = nullptr;
+ }
+}
+
+void CCtrlTreeView::OnInit()
+{
+ CSuper::OnInit();
+
+ Subclass();
+
+ if (m_bCheckBox) {
+ HIMAGELIST himlCheckBoxes = ::ImageList_Create(16, 16, ILC_COLOR32 | ILC_MASK, 2, 2);
+ ::ImageList_AddIcon_IconLibLoaded(himlCheckBoxes, SKINICON_OTHER_NOTICK);
+ ::ImageList_AddIcon_IconLibLoaded(himlCheckBoxes, SKINICON_OTHER_TICK);
+ SetImageList(himlCheckBoxes, TVSIL_NORMAL);
+ }
+}
+
+void CCtrlTreeView::OnDestroy()
+{
+ if (m_bCheckBox)
+ ::ImageList_Destroy(GetImageList(TVSIL_NORMAL));
+
+ CSuper::OnDestroy();
+}
+
+HTREEITEM CCtrlTreeView::MoveItemAbove(HTREEITEM hItem, HTREEITEM hInsertAfter, HTREEITEM hParent)
+{
+ if (hItem == nullptr || hInsertAfter == nullptr)
+ return nullptr;
+
+ if (hItem == hInsertAfter)
+ return hItem;
+
+ wchar_t name[128];
+ TVINSERTSTRUCT tvis = {};
+ tvis.itemex.mask = (UINT)-1;
+ tvis.itemex.pszText = name;
+ tvis.itemex.cchTextMax = _countof(name);
+ tvis.itemex.hItem = hItem;
+ if (!GetItem(&tvis.itemex))
+ return nullptr;
+
+ OBJLIST<TVINSERTSTRUCT> arChildren(1);
+ for (HTREEITEM p = GetChild(hItem); p; p = GetNextSibling(p)) {
+ wchar_t buf[128];
+ TVINSERTSTRUCT tvis2 = {};
+ tvis2.itemex.mask = (UINT)-1;
+ tvis2.itemex.pszText = buf;
+ tvis2.itemex.cchTextMax = _countof(buf);
+ tvis2.itemex.hItem = p;
+ if (GetItem(&tvis2.itemex)) {
+ tvis2.itemex.pszText = mir_wstrdup(tvis2.itemex.pszText);
+ arChildren.insert(new TVINSERTSTRUCT(tvis2));
+
+ tvis2.itemex.lParam = 0;
+ SetItem(&tvis2.itemex);
+ }
+ }
+
+ // the pointed lParam will be freed inside TVN_DELETEITEM
+ // so lets substitute it with 0
+ LPARAM saveOldData = tvis.itemex.lParam;
+ tvis.itemex.lParam = 0;
+ SetItem(&tvis.itemex);
+
+ // now current item contain lParam = 0 we can delete it. the memory will be kept.
+ DeleteItem(hItem);
+
+ for (auto &it : arChildren)
+ DeleteItem(it->itemex.hItem);
+
+ tvis.itemex.stateMask = tvis.itemex.state;
+ tvis.itemex.lParam = saveOldData;
+ tvis.hParent = hParent;
+ tvis.hInsertAfter = hInsertAfter;
+ auto hNewItem = InsertItem(&tvis);
+
+ hInsertAfter = nullptr;
+ for (auto &it : arChildren) {
+ it->hParent = hNewItem;
+ it->hInsertAfter = hInsertAfter;
+ hInsertAfter = InsertItem(it);
+
+ mir_free(it->itemex.pszText);
+ }
+
+ return hNewItem;
+}
+
+LRESULT CCtrlTreeView::CustomWndProc(UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ TVHITTESTINFO hti;
+
+ switch (msg) {
+ case WM_MOUSEMOVE:
+ if (m_bDragging) {
+ hti.pt.x = (short)LOWORD(lParam);
+ hti.pt.y = (short)HIWORD(lParam);
+ HitTest(&hti);
+ if (hti.flags & (TVHT_ONITEM | TVHT_ONITEMRIGHT)) {
+ HTREEITEM it = hti.hItem;
+ hti.pt.y -= GetItemHeight() / 2;
+ HitTest(&hti);
+ if (!(hti.flags & TVHT_ABOVE))
+ SetInsertMark(hti.hItem, 1);
+ else
+ SetInsertMark(it, 0);
+ }
+ else {
+ if (hti.flags & TVHT_ABOVE) SendMsg(WM_VSCROLL, MAKEWPARAM(SB_LINEUP, 0), 0);
+ if (hti.flags & TVHT_BELOW) SendMsg(WM_VSCROLL, MAKEWPARAM(SB_LINEDOWN, 0), 0);
+ SetInsertMark(nullptr, 0);
+ }
+ }
+ break;
+
+ case WM_LBUTTONUP:
+ if (m_bDragging) {
+ SetInsertMark(nullptr, 0);
+ m_bDragging = false;
+ ReleaseCapture();
+
+ hti.pt.x = (short)LOWORD(lParam);
+ hti.pt.y = (short)HIWORD(lParam) - GetItemHeight() / 2;
+ HitTest(&hti);
+ if (m_hDragItem == hti.hItem)
+ break;
+
+ if (hti.flags & TVHT_ABOVE)
+ hti.hItem = TVI_FIRST;
+ else if (hti.flags & TVHT_BELOW)
+ hti.hItem = TVI_LAST;
+
+ HTREEITEM insertAfter = hti.hItem, hParent;
+ if (insertAfter != TVI_FIRST) {
+ hParent = GetParent(insertAfter);
+ if (GetChild(insertAfter) != nullptr) {
+ hParent = insertAfter;
+ insertAfter = TVI_FIRST;
+ }
+ }
+ else hParent = nullptr;
+
+ HTREEITEM FirstItem = nullptr;
+ if (m_bMultiSelect) {
+ LIST<_TREEITEM> arItems(10);
+ GetSelected(arItems);
+
+ // Proceed moving
+ for (auto &it : arItems) {
+ if (!insertAfter)
+ break;
+ if (GetParent(it) != hParent) // prevent subitems from being inserted at the same level
+ continue;
+
+ insertAfter = MoveItemAbove(it, insertAfter, hParent);
+ if (it == arItems[0])
+ FirstItem = insertAfter;
+ }
+ }
+ else FirstItem = MoveItemAbove(m_hDragItem, insertAfter, hParent);
+ if (FirstItem)
+ SelectItem(FirstItem);
+
+ NotifyChange();
+ }
+ break;
+
+ case WM_LBUTTONDOWN:
+ if (!m_bMultiSelect)
+ break;
+
+ hti.pt.x = (short)LOWORD(lParam);
+ hti.pt.y = (short)HIWORD(lParam);
+ if (!TreeView_HitTest(m_hwnd, &hti)) {
+ UnselectAll();
+ break;
+ }
+
+ if (!m_bDndEnabled)
+ if (!(wParam & (MK_CONTROL | MK_SHIFT)) || !(hti.flags & (TVHT_ONITEMICON | TVHT_ONITEMLABEL | TVHT_ONITEMRIGHT))) {
+ UnselectAll();
+ TreeView_SelectItem(m_hwnd, hti.hItem);
+ break;
+ }
+
+ if (wParam & MK_CONTROL) {
+ LIST<_TREEITEM> selected(1);
+ GetSelected(selected);
+
+ // Check if have to deselect it
+ for (int i = 0; i < selected.getCount(); i++) {
+ if (selected[i] == hti.hItem) {
+ // Deselect it
+ UnselectAll();
+ selected.remove(i);
+
+ if (i > 0)
+ hti.hItem = selected[0];
+ else if (i < selected.getCount())
+ hti.hItem = selected[i];
+ else
+ hti.hItem = nullptr;
+ break;
+ }
+ }
+
+ TreeView_SelectItem(m_hwnd, hti.hItem);
+ Select(selected);
+ }
+ else if (wParam & MK_SHIFT) {
+ HTREEITEM hItem = TreeView_GetSelection(m_hwnd);
+ if (hItem == nullptr)
+ break;
+
+ LIST<_TREEITEM> selected(1);
+ GetSelected(selected);
+
+ TreeView_SelectItem(m_hwnd, hti.hItem);
+ Select(selected);
+ SelectRange(hItem, hti.hItem);
+ }
+ break;
+ }
+
+ return CSuper::CustomWndProc(msg, wParam, lParam);
+}
+
+BOOL CCtrlTreeView::OnNotify(int, NMHDR *pnmh)
+{
+ TEventInfo evt = { this, pnmh };
+
+ switch (pnmh->code) {
+ case NM_RCLICK: OnRightClick(&evt); return TRUE;
+ case NM_CUSTOMDRAW: OnCustomDraw(&evt); return TRUE;
+ case TVN_BEGINLABELEDIT: OnBeginLabelEdit(&evt); return TRUE;
+ case TVN_BEGINRDRAG: OnBeginRDrag(&evt); return TRUE;
+ case TVN_DELETEITEM: OnDeleteItem(&evt); return TRUE;
+ case TVN_ENDLABELEDIT: OnEndLabelEdit(&evt); return TRUE;
+ case TVN_GETDISPINFO: OnGetDispInfo(&evt); return TRUE;
+ case TVN_GETINFOTIP: OnGetInfoTip(&evt); return TRUE;
+ case TVN_ITEMEXPANDED: OnItemExpanded(&evt); return TRUE;
+ case TVN_ITEMEXPANDING: OnItemExpanding(&evt); return TRUE;
+ case TVN_SELCHANGED: OnSelChanged(&evt); return TRUE;
+ case TVN_SELCHANGING: OnSelChanging(&evt); return TRUE;
+ case TVN_SETDISPINFO: OnSetDispInfo(&evt); return TRUE;
+ case TVN_SINGLEEXPAND: OnSingleExpand(&evt); return TRUE;
+
+ case TVN_BEGINDRAG:
+ OnBeginDrag(&evt);
+
+ // user-defined can clear the event code to disable dragging
+ if (m_bDndEnabled && pnmh->code) {
+ ::SetCapture(m_hwnd);
+ m_bDragging = true;
+ m_hDragItem = evt.nmtv->itemNew.hItem;
+ SelectItem(m_hDragItem);
+ }
+ return TRUE;
+
+ case TVN_KEYDOWN:
+ if (evt.nmtvkey->wVKey == VK_SPACE) {
+ evt.hItem = GetSelection();
+ if (m_bCheckBox)
+ InvertCheck(evt.hItem);
+ OnItemChanged(&evt);
+ NotifyChange();
+ }
+
+ OnKeyDown(&evt);
+ return TRUE;
+ }
+
+ if (pnmh->code == NM_CLICK) {
+ TVHITTESTINFO hti;
+ hti.pt.x = (short)LOWORD(GetMessagePos());
+ hti.pt.y = (short)HIWORD(GetMessagePos());
+ ScreenToClient(pnmh->hwndFrom, &hti.pt);
+ if (HitTest(&hti)) {
+ if (m_bCheckBox && (hti.flags & TVHT_ONITEMICON) || !m_bCheckBox && (hti.flags & TVHT_ONITEMSTATEICON)) {
+ if (m_bCheckBox)
+ InvertCheck(hti.hItem);
+ else
+ SelectItem(hti.hItem);
+
+ evt.hItem = hti.hItem;
+ OnItemChanged(&evt);
+ NotifyChange();
+ }
+ }
+ }
+
+ return FALSE;
+}
+
+void CCtrlTreeView::InvertCheck(HTREEITEM hItem)
+{
+ TVITEMEX tvi;
+ tvi.mask = TVIF_HANDLE | TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIF_PARAM | TVIF_STATEEX;
+ tvi.hItem = hItem;
+ if (!GetItem(&tvi))
+ return;
+
+ if (IsWinVerVistaPlus() && (tvi.uStateEx & TVIS_EX_DISABLED))
+ return;
+
+ tvi.iImage = tvi.iSelectedImage = !tvi.iImage;
+ SetItem(&tvi);
+
+ SelectItem(hItem);
+}
+
+void CCtrlTreeView::TranslateItem(HTREEITEM hItem)
+{
+ TVITEMEX tvi;
+ wchar_t buf[128];
+ GetItem(hItem, &tvi, buf, _countof(buf));
+ tvi.pszText = TranslateW_LP(tvi.pszText);
+ SetItem(&tvi);
+}
+
+void CCtrlTreeView::TranslateTree()
+{
+ HTREEITEM hItem = GetRoot();
+ while (hItem) {
+ TranslateItem(hItem);
+
+ HTREEITEM hItemTmp = nullptr;
+ if (hItemTmp = GetChild(hItem))
+ hItem = hItemTmp;
+ else if (hItemTmp = GetNextSibling(hItem))
+ hItem = hItemTmp;
+ else {
+ while (true) {
+ if (!(hItem = GetParent(hItem)))
+ break;
+ if (hItemTmp = GetNextSibling(hItem)) {
+ hItem = hItemTmp;
+ break;
+ }
+ }
+ }
+ }
+}
+
+HTREEITEM CCtrlTreeView::FindNamedItem(HTREEITEM hItem, const wchar_t *name)
+{
+ TVITEMEX tvi = { 0 };
+ wchar_t str[MAX_PATH];
+
+ if (hItem)
+ tvi.hItem = GetChild(hItem);
+ else
+ tvi.hItem = GetRoot();
+
+ if (!name)
+ return tvi.hItem;
+
+ tvi.mask = TVIF_TEXT;
+ tvi.pszText = str;
+ tvi.cchTextMax = _countof(str);
+
+ while (tvi.hItem) {
+ GetItem(&tvi);
+
+ if (!mir_wstrcmp(tvi.pszText, name))
+ return tvi.hItem;
+
+ tvi.hItem = GetNextSibling(tvi.hItem);
+ }
+ return nullptr;
+}
+
+void CCtrlTreeView::GetItem(HTREEITEM hItem, TVITEMEX *tvi) const
+{
+ memset(tvi, 0, sizeof(*tvi));
+ tvi->mask = TVIF_CHILDREN | TVIF_HANDLE | TVIF_IMAGE | TVIF_INTEGRAL | TVIF_PARAM | TVIF_SELECTEDIMAGE | TVIF_STATE;
+ tvi->hItem = hItem;
+ GetItem(tvi);
+}
+
+void CCtrlTreeView::GetItem(HTREEITEM hItem, TVITEMEX *tvi, wchar_t *szText, int iTextLength) const
+{
+ memset(tvi, 0, sizeof(*tvi));
+ tvi->mask = TVIF_CHILDREN | TVIF_HANDLE | TVIF_IMAGE | TVIF_INTEGRAL | TVIF_PARAM | TVIF_SELECTEDIMAGE | TVIF_STATE | TVIF_TEXT;
+ tvi->hItem = hItem;
+ tvi->pszText = szText;
+ tvi->cchTextMax = iTextLength;
+ GetItem(tvi);
+}
+
+bool CCtrlTreeView::IsSelected(HTREEITEM hItem)
+{
+ return (TVIS_SELECTED & TreeView_GetItemState(m_hwnd, hItem, TVIS_SELECTED)) == TVIS_SELECTED;
+}
+
+void CCtrlTreeView::Select(HTREEITEM hItem)
+{
+ TreeView_SetItemState(m_hwnd, hItem, TVIS_SELECTED, TVIS_SELECTED);
+}
+
+void CCtrlTreeView::Unselect(HTREEITEM hItem)
+{
+ TreeView_SetItemState(m_hwnd, hItem, 0, TVIS_SELECTED);
+}
+
+void CCtrlTreeView::DropHilite(HTREEITEM hItem)
+{
+ TreeView_SetItemState(m_hwnd, hItem, TVIS_DROPHILITED, TVIS_DROPHILITED);
+}
+
+void CCtrlTreeView::DropUnhilite(HTREEITEM hItem)
+{
+ TreeView_SetItemState(m_hwnd, hItem, 0, TVIS_DROPHILITED);
+}
+
+void CCtrlTreeView::SelectAll()
+{
+ TreeView_SelectItem(m_hwnd, nullptr);
+
+ HTREEITEM hItem = TreeView_GetRoot(m_hwnd);
+ while (hItem) {
+ Select(hItem);
+ hItem = TreeView_GetNextSibling(m_hwnd, hItem);
+ }
+}
+
+void CCtrlTreeView::UnselectAll()
+{
+ TreeView_SelectItem(m_hwnd, nullptr);
+
+ HTREEITEM hItem = TreeView_GetRoot(m_hwnd);
+ while (hItem) {
+ Unselect(hItem);
+ hItem = TreeView_GetNextSibling(m_hwnd, hItem);
+ }
+}
+
+void CCtrlTreeView::SelectRange(HTREEITEM hStart, HTREEITEM hEnd)
+{
+ int start = 0, end = 0, i = 0;
+ HTREEITEM hItem = TreeView_GetRoot(m_hwnd);
+ while (hItem) {
+ if (hItem == hStart)
+ start = i;
+ if (hItem == hEnd)
+ end = i;
+
+ i++;
+ hItem = TreeView_GetNextSibling(m_hwnd, hItem);
+ }
+
+ if (end < start) {
+ int tmp = start;
+ start = end;
+ end = tmp;
+ }
+
+ i = 0;
+ hItem = TreeView_GetRoot(m_hwnd);
+ while (hItem) {
+ if (i >= start)
+ Select(hItem);
+ if (i == end)
+ break;
+
+ i++;
+ hItem = TreeView_GetNextSibling(m_hwnd, hItem);
+ }
+}
+
+int CCtrlTreeView::GetNumSelected()
+{
+ int ret = 0;
+ for (HTREEITEM hItem = TreeView_GetRoot(m_hwnd); hItem; hItem = TreeView_GetNextSibling(m_hwnd, hItem))
+ if (IsSelected(hItem))
+ ret++;
+
+ return ret;
+}
+
+void CCtrlTreeView::GetSelected(LIST<_TREEITEM> &selected)
+{
+ HTREEITEM hItem = TreeView_GetRoot(m_hwnd);
+ while (hItem) {
+ if (IsSelected(hItem))
+ selected.insert(hItem);
+ hItem = TreeView_GetNextSibling(m_hwnd, hItem);
+ }
+}
+
+void CCtrlTreeView::Select(LIST<_TREEITEM> &selected)
+{
+ for (auto &it : selected)
+ if (it != nullptr)
+ Select(it);
+}
+
+void CCtrlTreeView::GetCaretPos(CContextMenuPos &pos) const
+{
+ pos.pCtrl = this;
+
+ // position is empty, let's fill it using selection
+ if (pos.pt.x == 0 && pos.pt.y == 0) {
+ HTREEITEM hItem = GetSelection();
+ if (hItem != nullptr) {
+ pos.pCtrl = this;
+ pos.hItem = hItem;
+
+ RECT rc;
+ GetItemRect(hItem, &rc, TRUE);
+ pos.pt.x = rc.left + 8;
+ pos.pt.y = rc.top + 8;
+ ClientToScreen(m_hwnd, &pos.pt);
+ return;
+ }
+ }
+ // position is present, let's calculate current item
+ else {
+ TVHITTESTINFO hti;
+ hti.pt = pos.pt;
+ ScreenToClient(m_hwnd, &hti.pt);
+ if (HitTest(&hti) && (hti.flags & TVHT_ONITEM)) {
+ pos.hItem = hti.hItem;
+ return;
+ }
+ }
+
+ CSuper::GetCaretPos(pos);
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+HIMAGELIST CCtrlTreeView::CreateDragImage(HTREEITEM hItem)
+{ return TreeView_CreateDragImage(m_hwnd, hItem);
+}
+
+void CCtrlTreeView::DeleteAllItems()
+{ TreeView_DeleteAllItems(m_hwnd);
+}
+
+void CCtrlTreeView::DeleteItem(HTREEITEM hItem)
+{ TreeView_DeleteItem(m_hwnd, hItem);
+}
+
+HWND CCtrlTreeView::EditLabel(HTREEITEM hItem)
+{ return TreeView_EditLabel(m_hwnd, hItem);
+}
+
+void CCtrlTreeView::EndEditLabelNow(BOOL cancel)
+{ TreeView_EndEditLabelNow(m_hwnd, cancel);
+}
+
+void CCtrlTreeView::EnsureVisible(HTREEITEM hItem)
+{ TreeView_EnsureVisible(m_hwnd, hItem);
+}
+
+void CCtrlTreeView::Expand(HTREEITEM hItem, uint32_t flag)
+{ TreeView_Expand(m_hwnd, hItem, flag);
+}
+
+COLORREF CCtrlTreeView::GetBkColor() const
+{ return TreeView_GetBkColor(m_hwnd);
+}
+
+uint32_t CCtrlTreeView::GetCheckState(HTREEITEM hItem) const
+{ return TreeView_GetCheckState(m_hwnd, hItem);
+}
+
+HTREEITEM CCtrlTreeView::GetChild(HTREEITEM hItem) const
+{ return TreeView_GetChild(m_hwnd, hItem);
+}
+
+int CCtrlTreeView::GetCount() const
+{ return TreeView_GetCount(m_hwnd);
+}
+
+HTREEITEM CCtrlTreeView::GetDropHilight() const
+{ return TreeView_GetDropHilight(m_hwnd);
+}
+
+HWND CCtrlTreeView::GetEditControl() const
+{ return TreeView_GetEditControl(m_hwnd);
+}
+
+HTREEITEM CCtrlTreeView::GetFirstVisible() const
+{ return TreeView_GetFirstVisible(m_hwnd);
+}
+
+HIMAGELIST CCtrlTreeView::GetImageList(int iImage) const
+{ return TreeView_GetImageList(m_hwnd, iImage);
+}
+
+int CCtrlTreeView::GetIndent() const
+{ return TreeView_GetIndent(m_hwnd);
+}
+
+COLORREF CCtrlTreeView::GetInsertMarkColor() const
+{ return TreeView_GetInsertMarkColor(m_hwnd);
+}
+
+bool CCtrlTreeView::GetItem(TVITEMEX *tvi) const
+{ return TreeView_GetItem(m_hwnd, tvi) == TRUE;
+}
+
+int CCtrlTreeView::GetItemHeight() const
+{ return TreeView_GetItemHeight(m_hwnd);
+}
+
+void CCtrlTreeView::GetItemRect(HTREEITEM hItem, RECT *rcItem, BOOL fItemRect) const
+{ TreeView_GetItemRect(m_hwnd, hItem, rcItem, fItemRect);
+}
+
+uint32_t CCtrlTreeView::GetItemState(HTREEITEM hItem, uint32_t stateMask) const
+{ return TreeView_GetItemState(m_hwnd, hItem, stateMask);
+}
+
+HTREEITEM CCtrlTreeView::GetLastVisible() const
+{ return TreeView_GetLastVisible(m_hwnd);
+}
+
+COLORREF CCtrlTreeView::GetLineColor() const
+{ return TreeView_GetLineColor(m_hwnd);
+}
+
+HTREEITEM CCtrlTreeView::GetNextItem(HTREEITEM hItem, uint32_t flag) const
+{ return TreeView_GetNextItem(m_hwnd, hItem, flag);
+}
+
+HTREEITEM CCtrlTreeView::GetNextSibling(HTREEITEM hItem) const
+{ return TreeView_GetNextSibling(m_hwnd, hItem);
+}
+
+HTREEITEM CCtrlTreeView::GetNextVisible(HTREEITEM hItem) const
+{ return TreeView_GetNextVisible(m_hwnd, hItem);
+}
+
+HTREEITEM CCtrlTreeView::GetParent(HTREEITEM hItem) const
+{ return TreeView_GetParent(m_hwnd, hItem);
+}
+
+HTREEITEM CCtrlTreeView::GetPrevSibling(HTREEITEM hItem) const
+{ return TreeView_GetPrevSibling(m_hwnd, hItem);
+}
+
+HTREEITEM CCtrlTreeView::GetPrevVisible(HTREEITEM hItem) const
+{ return TreeView_GetPrevVisible(m_hwnd, hItem);
+}
+
+HTREEITEM CCtrlTreeView::GetRoot() const
+{ return TreeView_GetRoot(m_hwnd);
+}
+
+uint32_t CCtrlTreeView::GetScrollTime() const
+{ return TreeView_GetScrollTime(m_hwnd);
+}
+
+HTREEITEM CCtrlTreeView::GetSelection() const
+{ return TreeView_GetSelection(m_hwnd);
+}
+
+COLORREF CCtrlTreeView::GetTextColor() const
+{ return TreeView_GetTextColor(m_hwnd);
+}
+
+HWND CCtrlTreeView::GetToolTips() const
+{ return TreeView_GetToolTips(m_hwnd);
+}
+
+BOOL CCtrlTreeView::GetUnicodeFormat() const
+{ return TreeView_GetUnicodeFormat(m_hwnd);
+}
+
+unsigned CCtrlTreeView::GetVisibleCount() const
+{ return TreeView_GetVisibleCount(m_hwnd);
+}
+
+HTREEITEM CCtrlTreeView::HitTest(TVHITTESTINFO *hti) const
+{ return TreeView_HitTest(m_hwnd, hti);
+}
+
+HTREEITEM CCtrlTreeView::InsertItem(TVINSERTSTRUCT *tvis)
+{ return TreeView_InsertItem(m_hwnd, tvis);
+}
+
+void CCtrlTreeView::Select(HTREEITEM hItem, uint32_t flag)
+{ TreeView_Select(m_hwnd, hItem, flag);
+}
+
+void CCtrlTreeView::SelectDropTarget(HTREEITEM hItem)
+{ TreeView_SelectDropTarget(m_hwnd, hItem);
+}
+
+void CCtrlTreeView::SelectItem(HTREEITEM hItem)
+{ TreeView_SelectItem(m_hwnd, hItem);
+}
+
+void CCtrlTreeView::SelectSetFirstVisible(HTREEITEM hItem)
+{ TreeView_SelectSetFirstVisible(m_hwnd, hItem);
+}
+
+COLORREF CCtrlTreeView::SetBkColor(COLORREF clBack)
+{ return TreeView_SetBkColor(m_hwnd, clBack);
+}
+
+void CCtrlTreeView::SetCheckState(HTREEITEM hItem, uint32_t state)
+{ TreeView_SetCheckState(m_hwnd, hItem, state);
+}
+
+void CCtrlTreeView::SetImageList(HIMAGELIST hIml, int iImage)
+{ TreeView_SetImageList(m_hwnd, hIml, iImage);
+}
+
+void CCtrlTreeView::SetIndent(int iIndent)
+{ TreeView_SetIndent(m_hwnd, iIndent);
+}
+
+void CCtrlTreeView::SetInsertMark(HTREEITEM hItem, BOOL fAfter)
+{ TreeView_SetInsertMark(m_hwnd, hItem, fAfter);
+}
+
+COLORREF CCtrlTreeView::SetInsertMarkColor(COLORREF clMark)
+{ return TreeView_SetInsertMarkColor(m_hwnd, clMark);
+}
+
+void CCtrlTreeView::SetItem(TVITEMEX *tvi)
+{ TreeView_SetItem(m_hwnd, tvi);
+}
+
+void CCtrlTreeView::SetItemHeight(short cyItem)
+{ TreeView_SetItemHeight(m_hwnd, cyItem);
+}
+
+void CCtrlTreeView::SetItemState(HTREEITEM hItem, uint32_t state, uint32_t stateMask)
+{ TreeView_SetItemState(m_hwnd, hItem, state, stateMask);
+}
+
+COLORREF CCtrlTreeView::SetLineColor(COLORREF clLine)
+{ return TreeView_SetLineColor(m_hwnd, clLine);
+}
+
+void CCtrlTreeView::SetScrollTime(UINT uMaxScrollTime)
+{ TreeView_SetScrollTime(m_hwnd, uMaxScrollTime);
+}
+
+COLORREF CCtrlTreeView::SetTextColor(COLORREF clText)
+{ return TreeView_SetTextColor(m_hwnd, clText);
+}
+
+HWND CCtrlTreeView::SetToolTips(HWND hwndToolTips)
+{ return TreeView_SetToolTips(m_hwnd, hwndToolTips);
+}
+
+BOOL CCtrlTreeView::SetUnicodeFormat(BOOL fUnicode)
+{ return TreeView_SetUnicodeFormat(m_hwnd, fUnicode);
+}
+
+void CCtrlTreeView::SortChildren(HTREEITEM hItem, BOOL fRecurse)
+{ TreeView_SortChildren(m_hwnd, hItem, fRecurse);
+}
+
+void CCtrlTreeView::SortChildrenCB(TVSORTCB *cb, BOOL fRecurse)
+{ TreeView_SortChildrenCB(m_hwnd, cb, fRecurse);
+}
diff --git a/src/mir_core/src/Linux/CDbLink.cpp b/src/mir_core/src/Linux/CDbLink.cpp
new file mode 100644
index 0000000000..2a0734cd3b
--- /dev/null
+++ b/src/mir_core/src/Linux/CDbLink.cpp
@@ -0,0 +1,92 @@
+/*
+
+Object UI extensions
+Copyright (c) 2008 Victor Pavlychko, George Hazan
+Copyright (C) 2012-22 Miranda NG team
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+*/
+
+#include "../stdafx.h"
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// CDbLink class
+
+CDbLink::CDbLink(const char *szModule, const char *szSetting, uint8_t type, uint32_t iValue)
+ : CDataLink(type)
+{
+ m_szModule = mir_strdup(szModule);
+ m_szSetting = mir_strdup(szSetting);
+ m_iDefault = iValue;
+ m_szDefault = nullptr;
+ dbv.type = DBVT_DELETED;
+}
+
+CDbLink::CDbLink(const char *szModule, const char *szSetting, uint8_t type, wchar_t *szValue)
+ : CDataLink(type),
+ m_iDefault(0)
+{
+ m_szModule = mir_strdup(szModule);
+ m_szSetting = mir_strdup(szSetting);
+ m_szDefault = mir_wstrdup(szValue);
+ dbv.type = DBVT_DELETED;
+}
+
+CDbLink::~CDbLink()
+{
+ mir_free(m_szModule);
+ mir_free(m_szSetting);
+ mir_free(m_szDefault);
+ if (dbv.type != DBVT_DELETED)
+ db_free(&dbv);
+}
+
+uint32_t CDbLink::LoadInt()
+{
+ switch (m_type) {
+ case DBVT_BYTE: return db_get_b(0, m_szModule, m_szSetting, m_iDefault);
+ case DBVT_WORD: return db_get_w(0, m_szModule, m_szSetting, m_iDefault);
+ case DBVT_DWORD: return db_get_dw(0, m_szModule, m_szSetting, m_iDefault);
+ default: return m_iDefault;
+ }
+}
+
+void CDbLink::SaveInt(uint32_t value)
+{
+ switch (m_type) {
+ case DBVT_BYTE: db_set_b(0, m_szModule, m_szSetting, (uint8_t)value); break;
+ case DBVT_WORD: db_set_w(0, m_szModule, m_szSetting, (uint16_t)value); break;
+ case DBVT_DWORD: db_set_dw(0, m_szModule, m_szSetting, value); break;
+ }
+}
+
+wchar_t* CDbLink::LoadText()
+{
+ if (dbv.type != DBVT_DELETED) db_free(&dbv);
+ if (!db_get_ws(0, m_szModule, m_szSetting, &dbv)) {
+ if (dbv.type == DBVT_WCHAR)
+ return dbv.pwszVal;
+ return m_szDefault;
+ }
+
+ dbv.type = DBVT_DELETED;
+ return m_szDefault;
+}
+
+void CDbLink::SaveText(wchar_t *value)
+{
+ db_set_ws(0, m_szModule, m_szSetting, value);
+}
diff --git a/src/mir_core/src/Linux/CDlgBase.cpp b/src/mir_core/src/Linux/CDlgBase.cpp
new file mode 100644
index 0000000000..d6c798eb41
--- /dev/null
+++ b/src/mir_core/src/Linux/CDlgBase.cpp
@@ -0,0 +1,506 @@
+/*
+
+Object UI extensions
+Copyright (c) 2008 Victor Pavlychko, George Hazan
+Copyright (C) 2012-22 Miranda NG team
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+*/
+
+#include "../stdafx.h"
+
+static mir_cs csDialogs;
+
+static int CompareDialogs(const CDlgBase *p1, const CDlgBase *p2)
+{
+ return (INT_PTR)p1->GetHwnd() - (INT_PTR)p2->GetHwnd();
+}
+static LIST<CDlgBase> arDialogs(10, CompareDialogs);
+
+#pragma comment(lib, "uxtheme")
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// CDlgBase
+
+static int CompareControlId(const CCtrlBase *c1, const CCtrlBase *c2)
+{
+ return c1->GetCtrlId() - c2->GetCtrlId();
+}
+
+static int CompareTimerId(const CTimer *t1, const CTimer *t2)
+{
+ return t1->GetEventId() - t2->GetEventId();
+}
+
+CDlgBase::CDlgBase(CMPluginBase &pPlug, int idDialog)
+ : m_controls(1, CompareControlId),
+ m_timers(1, CompareTimerId),
+ m_pPlugin(pPlug)
+{
+ m_idDialog = idDialog;
+ m_autoClose = CLOSE_ON_OK | CLOSE_ON_CANCEL;
+}
+
+CDlgBase::~CDlgBase()
+{
+ m_bInitialized = false; // prevent double call of destructor
+ if (m_hwnd)
+ DestroyWindow(m_hwnd);
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// events
+
+bool CDlgBase::OnInitDialog()
+{
+ return true;
+}
+
+bool CDlgBase::OnClose()
+{
+ return true;
+}
+
+bool CDlgBase::OnApply()
+{
+ return true;
+}
+
+void CDlgBase::OnChange()
+{}
+
+void CDlgBase::OnDestroy()
+{}
+
+void CDlgBase::OnReset()
+{}
+
+void CDlgBase::OnTimer(CTimer*)
+{}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// methods
+
+void CDlgBase::Close()
+{
+ ::SendMessage(m_hwnd, WM_CLOSE, 0, 0);
+}
+
+void CDlgBase::Create()
+{
+ CreateDialogParam(GetInst(), MAKEINTRESOURCE(m_idDialog), m_hwndParent, GlobalDlgProc, (LPARAM)this);
+}
+
+int CDlgBase::DoModal()
+{
+ m_isModal = true;
+ return DialogBoxParam(GetInst(), MAKEINTRESOURCE(m_idDialog), m_hwndParent, GlobalDlgProc, (LPARAM)this);
+}
+
+void CDlgBase::EndModal(INT_PTR nResult)
+{
+ ::EndDialog(m_hwnd, nResult);
+}
+
+HINSTANCE CDlgBase::GetInst() const
+{
+ return m_pPlugin.getInst();
+}
+
+void CDlgBase::NotifyChange(void)
+{
+ if (!m_bInitialized)
+ return;
+
+ OnChange();
+
+ if (m_hwndParent)
+ SendMessage(m_hwndParent, PSM_CHANGED, (WPARAM)m_hwnd, 0);
+}
+
+void CDlgBase::Resize()
+{
+ SendMessage(m_hwnd, WM_SIZE, 0, 0);
+}
+
+void CDlgBase::SetCaption(const wchar_t *ptszCaption)
+{
+ if (m_hwnd && ptszCaption)
+ SetWindowText(m_hwnd, ptszCaption);
+}
+
+void CDlgBase::SetDraw(bool bEnable)
+{
+ ::SendMessage(m_hwnd, WM_SETREDRAW, bEnable, 0);
+}
+
+void CDlgBase::Show(int nCmdShow)
+{
+ if (m_hwnd == nullptr)
+ Create();
+ ShowWindow(m_hwnd, nCmdShow);
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+void CDlgBase::CreateLink(CCtrlData& ctrl, const char *szSetting, uint8_t type, uint32_t iValue)
+{
+ ctrl.CreateDbLink(m_pPlugin.getModule(), szSetting, type, iValue);
+}
+
+void CDlgBase::CreateLink(CCtrlData& ctrl, const char *szSetting, wchar_t *szValue)
+{
+ ctrl.CreateDbLink(m_pPlugin.getModule(), szSetting, szValue);
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// virtual methods
+
+int CDlgBase::Resizer(UTILRESIZECONTROL*)
+{
+ return RD_ANCHORX_LEFT | RD_ANCHORY_TOP;
+}
+
+BOOL CALLBACK CDlgBase::GlobalFieldEnum(HWND hwnd, LPARAM lParam)
+{
+ CDlgBase *pDlg = (CDlgBase*)lParam;
+ int id = GetWindowLongPtrW(hwnd, GWLP_ID);
+ if (id <= 0)
+ return TRUE;
+
+ // already declared inside the class? skipping
+ CCtrlBase *ctrl = pDlg->FindControl(id);
+ if (ctrl != nullptr)
+ return TRUE;
+
+ wchar_t wszClass[100];
+ GetClassNameW(hwnd, wszClass, _countof(wszClass));
+ if (!wcsicmp(wszClass, L"Static"))
+ new CCtrlLabel(pDlg, id);
+ if (!wcsicmp(wszClass, L"Edit"))
+ new CCtrlEdit(pDlg, id);
+ else if (!wcsicmp(wszClass, L"ComboBox"))
+ new CCtrlCombo(pDlg, id);
+ else if (!wcsicmp(wszClass, L"Button")) {
+ switch (GetWindowLongW(hwnd, GWL_STYLE) & (BS_CHECKBOX | BS_RADIOBUTTON | BS_AUTOCHECKBOX | BS_AUTORADIOBUTTON)) {
+ case BS_CHECKBOX:
+ case BS_AUTOCHECKBOX:
+ case BS_RADIOBUTTON:
+ case BS_AUTORADIOBUTTON:
+ new CCtrlCheck(pDlg, id);
+ break;
+
+ default:
+ new CCtrlButton(pDlg, id);
+ }
+ }
+ else if (!wcsicmp(wszClass, L"RichEdit50W"))
+ new CCtrlRichEdit(pDlg, id);
+ else if (!wcsicmp(wszClass, L"msctls_updown32"))
+ new CCtrlSpin(pDlg, id);
+
+ return TRUE;
+}
+
+INT_PTR CDlgBase::DlgProc(UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ switch (msg) {
+ case WM_INITDIALOG:
+ m_bInitialized = m_bSucceeded = false;
+ TranslateDialog_LP(m_hwnd, &m_pPlugin);
+
+ ::EnumChildWindows(m_hwnd, &GlobalFieldEnum, LPARAM(this));
+
+ NotifyControls(&CCtrlBase::OnInit);
+ if (!OnInitDialog())
+ return FALSE;
+
+ for (auto &it : m_controls)
+ if (it->m_bNotifiable)
+ it->OnChange(it);
+
+ m_bInitialized = true;
+ return TRUE;
+
+ case WM_CTLCOLOREDIT:
+ case WM_CTLCOLORSTATIC:
+ if (CCtrlBase *ctrl = FindControl(HWND(lParam))) {
+ if (ctrl->m_bUseSystemColors) {
+ SetBkColor((HDC)wParam, GetSysColor(COLOR_WINDOW));
+ return (INT_PTR)GetSysColorBrush(COLOR_WINDOW);
+ }
+ }
+ break;
+
+ case WM_GETMINMAXINFO:
+ if (m_iMinHeight != -1 && m_iMinWidth != -1) {
+ MINMAXINFO *lpmmi = (MINMAXINFO*)lParam;
+ lpmmi->ptMinTrackSize.y = m_iMinHeight;
+ lpmmi->ptMinTrackSize.x = m_iMinWidth;
+ return 0;
+ }
+ break;
+
+ case WM_MEASUREITEM:
+ if (!Menu_MeasureItem(lParam)) {
+ MEASUREITEMSTRUCT *param = (MEASUREITEMSTRUCT *)lParam;
+ if (param && param->CtlID)
+ if (CCtrlBase *ctrl = FindControl(param->CtlID))
+ return ctrl->OnMeasureItem(param);
+ }
+ return FALSE;
+
+ case WM_DRAWITEM:
+ if (!Menu_DrawItem(lParam)) {
+ DRAWITEMSTRUCT *param = (DRAWITEMSTRUCT *)lParam;
+ if (param && param->CtlID)
+ if (CCtrlBase *ctrl = FindControl(param->CtlID))
+ return ctrl->OnDrawItem(param);
+ }
+ return FALSE;
+
+ case WM_DELETEITEM:
+ {
+ DELETEITEMSTRUCT *param = (DELETEITEMSTRUCT *)lParam;
+ if (param && param->CtlID)
+ if (CCtrlBase *ctrl = FindControl(param->CtlID))
+ return ctrl->OnDeleteItem(param);
+ }
+ return FALSE;
+
+ case WM_COMMAND:
+ {
+ HWND hwndCtrl = (HWND)lParam;
+ uint16_t idCtrl = LOWORD(wParam);
+ uint16_t idCode = HIWORD(wParam);
+ if (CCtrlBase *ctrl = FindControl(idCtrl)) {
+ BOOL result = ctrl->OnCommand(hwndCtrl, idCtrl, idCode);
+ if (result != FALSE)
+ return result;
+ }
+
+ if (idCode == BN_CLICKED) {
+ // close dialog automatically if 'Cancel' button is pressed
+ if (idCtrl == IDCANCEL && (m_autoClose & CLOSE_ON_CANCEL)) {
+ m_bExiting = true;
+ PostMessage(m_hwnd, WM_CLOSE, 0, 0);
+ }
+
+ // close dialog automatically if 'OK' button is pressed
+ if (idCtrl == IDOK && (m_autoClose & CLOSE_ON_OK)) {
+ // validate dialog data first
+ if (VerifyControls(&CCtrlBase::OnApply)) {
+ m_bExiting = true;
+
+ // everything ok? good, let's close it
+ if (OnApply()) {
+ m_bSucceeded = true;
+ PostMessage(m_hwnd, WM_CLOSE, 0, 0);
+ }
+ else m_bExiting = false;
+ }
+ }
+ }
+ }
+ return FALSE;
+
+ case WM_NOTIFY:
+ {
+ int idCtrl = wParam;
+ NMHDR *pnmh = (NMHDR *)lParam;
+ if (pnmh->idFrom == 0) {
+ switch (pnmh->code) {
+ case PSN_APPLY:
+ if (LPPSHNOTIFY(lParam)->lParam != 3) // IDC_APPLY
+ m_bExiting = true;
+
+ if (!VerifyControls(&CCtrlBase::OnApply))
+ m_bExiting = false;
+ else if (!OnApply())
+ m_bExiting = false;
+ break;
+
+ case PSN_RESET:
+ NotifyControls(&CCtrlBase::OnReset);
+ OnReset();
+ break;
+
+ case PSN_WIZFINISH:
+ m_OnFinishWizard(this);
+ break;
+ }
+ }
+
+ if (CCtrlBase *ctrl = FindControl(pnmh->idFrom))
+ return ctrl->OnNotify(idCtrl, pnmh);
+ }
+ return FALSE;
+
+ case WM_HSCROLL:
+ if (auto *pCtrl = FindControl(HWND(lParam)))
+ pCtrl->OnCommand(HWND(lParam), pCtrl->m_idCtrl, WM_HSCROLL);
+ break;
+
+ case PSM_CHANGED:
+ if (m_bInitialized)
+ OnChange();
+ break;
+
+ case WM_CONTEXTMENU:
+ if (CCtrlBase *ctrl = FindControl(HWND(wParam))) {
+ CContextMenuPos pos = {};
+ if (lParam != -1) {
+ pos.pt.x = GET_X_LPARAM(lParam);
+ pos.pt.y = GET_Y_LPARAM(lParam);
+ }
+ ctrl->GetCaretPos(pos);
+ ctrl->OnBuildMenu(&pos);
+ }
+ break;
+
+ case WM_SIZE:
+ if (m_forceResizable || (GetWindowLongPtr(m_hwnd, GWL_STYLE) & WS_THICKFRAME))
+ Utils_ResizeDialog(m_hwnd, m_pPlugin.getInst(), MAKEINTRESOURCEA(m_idDialog), GlobalDlgResizer);
+ return TRUE;
+
+ case WM_TIMER:
+ if (CTimer *timer = FindTimer(wParam))
+ return timer->OnTimer();
+ return FALSE;
+
+ case WM_CLOSE:
+ if (OnClose()) {
+ m_bExiting = true;
+ if (m_isModal)
+ EndModal(m_bSucceeded ? IDOK : FALSE);
+ else
+ DestroyWindow(m_hwnd);
+ }
+ return TRUE;
+
+ case WM_DESTROY:
+ m_bExiting = true;
+ OnDestroy();
+ NotifyControls(&CCtrlBase::OnDestroy);
+ {
+ mir_cslock lck(csDialogs);
+ int idx = arDialogs.getIndex(this);
+ if (idx != -1)
+ arDialogs.remove(idx);
+ }
+ m_hwnd = nullptr;
+ if (m_bInitialized) {
+ if (m_isModal)
+ m_isModal = false;
+ else // modeless dialogs MUST be allocated with 'new'
+ delete this;
+ }
+
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+INT_PTR CALLBACK CDlgBase::GlobalDlgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ CDlgBase *wnd;
+ if (msg == WM_INITDIALOG) {
+ wnd = (CDlgBase*)lParam;
+ wnd->m_hwnd = hwnd;
+
+ mir_cslock lck(csDialogs);
+ arDialogs.insert(wnd);
+ }
+ else wnd = CDlgBase::Find(hwnd);
+
+ return (wnd == nullptr) ? FALSE : wnd->DlgProc(msg, wParam, lParam);
+}
+
+int CDlgBase::GlobalDlgResizer(HWND hwnd, LPARAM, UTILRESIZECONTROL *urc)
+{
+ CDlgBase *wnd = CDlgBase::Find(hwnd);
+ return (wnd == nullptr) ? 0 : wnd->Resizer(urc);
+}
+
+void CDlgBase::ThemeDialogBackground(BOOL tabbed)
+{
+ EnableThemeDialogTexture(m_hwnd, (tabbed ? ETDT_ENABLE : ETDT_DISABLE) | ETDT_USETABTEXTURE);
+}
+
+void CDlgBase::AddControl(CCtrlBase *ctrl)
+{
+ m_controls.insert(ctrl);
+}
+
+void CDlgBase::RemoveControl(CCtrlBase *ctrl)
+{
+ m_controls.remove(ctrl);
+}
+
+void CDlgBase::NotifyControls(void (CCtrlBase::*fn)())
+{
+ for (auto &it : m_controls)
+ (it->*fn)();
+}
+
+bool CDlgBase::VerifyControls(bool (CCtrlBase::*fn)())
+{
+ for (auto &it : m_controls)
+ if (!(it->*fn)())
+ return false;
+
+ return true;
+}
+
+CCtrlBase* CDlgBase::FindControl(int idCtrl)
+{
+ CCtrlBase search(nullptr, idCtrl);
+ return m_controls.find(&search);
+}
+
+CCtrlBase* CDlgBase::FindControl(HWND hwnd)
+{
+ for (auto &it : m_controls)
+ if (it->GetHwnd() == hwnd)
+ return it;
+
+ return nullptr;
+}
+
+void CDlgBase::AddTimer(CTimer *timer)
+{
+ m_timers.insert(timer);
+}
+
+void CDlgBase::RemoveTimer(UINT_PTR idEvent)
+{
+ CTimer search(nullptr, idEvent);
+ m_timers.remove(&search);
+}
+
+CTimer* CDlgBase::FindTimer(int idEvent)
+{
+ CTimer search(nullptr, idEvent);
+ return m_timers.find(&search);
+}
+
+CDlgBase* CDlgBase::Find(HWND hwnd)
+{
+ PVOID bullshit[2]; // vfptr + hwnd
+ bullshit[1] = hwnd;
+ return arDialogs.find((CDlgBase*)&bullshit);
+}
diff --git a/src/mir_core/src/Linux/CProgress.cpp b/src/mir_core/src/Linux/CProgress.cpp
new file mode 100644
index 0000000000..991c6f239d
--- /dev/null
+++ b/src/mir_core/src/Linux/CProgress.cpp
@@ -0,0 +1,53 @@
+/*
+
+Object UI extensions
+Copyright (c) 2008 Victor Pavlychko, George Hazan
+Copyright (C) 2012-22 Miranda NG team
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+*/
+
+#include "../stdafx.h"
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// CCtrlProgress
+
+CCtrlProgress::CCtrlProgress(CDlgBase *wnd, int idCtrl)
+ : CCtrlBase(wnd, idCtrl)
+{
+}
+
+void CCtrlProgress::SetRange(uint16_t max, uint16_t min)
+{
+ SendMsg(PBM_SETRANGE, 0, MAKELPARAM(min, max));
+}
+
+void CCtrlProgress::SetPosition(uint16_t value)
+{
+ SendMsg(PBM_SETPOS, value, 0);
+}
+
+void CCtrlProgress::SetStep(uint16_t value)
+{
+ SendMsg(PBM_SETSTEP, value, 0);
+}
+
+uint16_t CCtrlProgress::Move(uint16_t delta)
+{
+ return delta == 0
+ ? SendMsg(PBM_STEPIT, 0, 0)
+ : SendMsg(PBM_DELTAPOS, delta, 0);
+}
diff --git a/src/mir_core/src/Linux/CSplitter.cpp b/src/mir_core/src/Linux/CSplitter.cpp
new file mode 100644
index 0000000000..e2ee6b6fc8
--- /dev/null
+++ b/src/mir_core/src/Linux/CSplitter.cpp
@@ -0,0 +1,83 @@
+/*
+
+Object UI extensions
+Copyright (c) 2008 Victor Pavlychko, George Hazan
+Copyright (C) 2012-22 Miranda NG team
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+*/
+
+#include "../stdafx.h"
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// CSplitter
+
+CSplitter::CSplitter(CDlgBase *wnd, int idCtrl)
+ : CCtrlBase(wnd, idCtrl),
+ m_iPosition(0)
+{
+}
+
+void CSplitter::OnInit()
+{
+ CSuper::OnInit();
+ Subclass();
+}
+
+LRESULT CSplitter::CustomWndProc(UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ switch (msg) {
+ case WM_NCHITTEST:
+ return HTCLIENT;
+
+ case WM_SETCURSOR:
+ RECT rc;
+ GetClientRect(m_hwnd, &rc);
+ SetCursor(rc.right > rc.bottom ? g_hCursorNS : g_hCursorWE);
+ return TRUE;
+
+ case WM_LBUTTONDOWN:
+ SetCapture(m_hwnd);
+ return 0;
+
+ case WM_MOUSEMOVE:
+ if (GetCapture() == m_hwnd) {
+ POINT pt = { 0, 0 };
+ GetClientRect(m_hwnd, &rc);
+ if (rc.right > rc.bottom) {
+ pt.y = HIWORD(GetMessagePos()) + rc.bottom / 2;
+ ScreenToClient(m_parentWnd->GetHwnd(), &pt);
+ m_iPosition = pt.y;
+ }
+ else {
+ pt.x = LOWORD(GetMessagePos()) + rc.right / 2;
+ ScreenToClient(m_parentWnd->GetHwnd(), &pt);
+ m_iPosition = pt.x;
+ }
+
+ OnChange(this);
+ PostMessage(m_parentWnd->GetHwnd(), WM_SIZE, 0, 0);
+ }
+ return 0;
+
+ case WM_LBUTTONUP:
+ ReleaseCapture();
+ PostMessage(m_parentWnd->GetHwnd(), WM_SIZE, 0, 0);
+ return 0;
+ }
+
+ return CSuper::CustomWndProc(msg, wParam, lParam);
+}
diff --git a/src/mir_core/src/Linux/CTimer.cpp b/src/mir_core/src/Linux/CTimer.cpp
new file mode 100644
index 0000000000..b346138707
--- /dev/null
+++ b/src/mir_core/src/Linux/CTimer.cpp
@@ -0,0 +1,90 @@
+/*
+
+Object UI extensions
+Copyright (c) 2008 Victor Pavlychko, George Hazan
+Copyright (C) 2012-22 Miranda NG team
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+*/
+
+#include "../stdafx.h"
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// CTimer
+
+CTimer::CTimer(CDlgBase *wnd, UINT_PTR idEvent)
+ : m_wnd(wnd), m_idEvent(idEvent)
+{
+ if (wnd)
+ wnd->AddTimer(this);
+}
+
+CTimer::~CTimer()
+{
+ if (m_wnd)
+ m_wnd->RemoveTimer(m_idEvent);
+}
+
+BOOL CTimer::OnTimer()
+{
+ OnEvent(this);
+ return FALSE;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+void CTimer::Start(int elapse)
+{
+ ::SetTimer(m_wnd->GetHwnd(), m_idEvent, elapse, nullptr);
+}
+
+bool CTimer::Stop()
+{
+ return 0 != ::KillTimer(m_wnd->GetHwnd(), m_idEvent);
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+struct TStartParam
+{
+ CTimer *pTimer;
+ int period;
+};
+
+static INT_PTR CALLBACK stubStart(void *param)
+{
+ auto *p = (TStartParam *)param;
+ return ::SetTimer(p->pTimer->GetHwnd(), p->pTimer->GetEventId(), p->period, nullptr);
+}
+
+void CTimer::StartSafe(int elapse)
+{
+ TStartParam param = { this, elapse };
+ CallFunctionSync(stubStart, &param);
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+static INT_PTR CALLBACK stubStop(void *param)
+{
+ auto *p = (CTimer*)param;
+ return ::KillTimer(p->GetHwnd(), p->GetEventId());
+}
+
+void CTimer::StopSafe()
+{
+ CallFunctionSync(stubStop, this);
+}
diff --git a/src/mir_core/src/Linux/cctrldate.cpp b/src/mir_core/src/Linux/cctrldate.cpp
new file mode 100644
index 0000000000..1967cb5678
--- /dev/null
+++ b/src/mir_core/src/Linux/cctrldate.cpp
@@ -0,0 +1,49 @@
+/*
+
+Object UI extensions
+Copyright (c) 2008 Victor Pavlychko, George Hazan
+Copyright (C) 2012-22 Miranda NG team
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+*/
+
+#include "../stdafx.h"
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// CCtrlDate class
+
+CCtrlDate::CCtrlDate(CDlgBase *dlg, int ctrlId) :
+ CCtrlData(dlg, ctrlId)
+{}
+
+BOOL CCtrlDate::OnNotify(int, NMHDR *pnmh)
+{
+ if (pnmh->code == DTN_DATETIMECHANGE) {
+ NotifyChange();
+ return TRUE;
+ }
+ return FALSE;
+}
+
+void CCtrlDate::GetTime(SYSTEMTIME *pDate)
+{
+ ::SendMessage(m_hwnd, DTM_GETSYSTEMTIME, 0, (LPARAM)pDate);
+}
+
+void CCtrlDate::SetTime(SYSTEMTIME *pDate)
+{
+ ::SendMessage(m_hwnd, DTM_SETSYSTEMTIME, 0, (LPARAM)pDate);
+}