[win] online-installer: enhancement

This commit is contained in:
SimplestStudio
2024-09-05 15:29:42 +03:00
parent 504d34effd
commit 3e39cfca85
58 changed files with 5801 additions and 754 deletions

View File

@ -27,7 +27,19 @@ ENV_URL_INSTALL_X86_XP = $$(DESKTOP_URL_INSTALL_CHANNEL_X86_XP)
DEFINES += URL_INSTALL_X86_XP=\\\"$${ENV_URL_INSTALL_X86_XP}\\\"
}
ENV_URL_INSTALL_X64_MSI = $$(DESKTOP_URL_INSTALL_CHANNEL_X64_MSI)
!isEmpty(ENV_URL_INSTALL_X64_MSI) {
DEFINES += URL_INSTALL_X64_MSI=\\\"$${ENV_URL_INSTALL_X64_MSI}\\\"
}
ENV_URL_INSTALL_X86_MSI = $$(DESKTOP_URL_INSTALL_CHANNEL_X86_MSI)
!isEmpty(ENV_URL_INSTALL_X86_MSI) {
DEFINES += URL_INSTALL_X86_MSI=\\\"$${ENV_URL_INSTALL_X86_MSI}\\\"
}
message(install x64 url: \\\"$$ENV_URL_INSTALL_X64\\\")
message(install x86 url: \\\"$$ENV_URL_INSTALL_X86\\\")
message(install x64 xp url: \\\"$$ENV_URL_INSTALL_X64_XP\\\")
message(install x86 xp url: \\\"$$ENV_URL_INSTALL_X86_XP\\\")
message(install x64 msi url: \\\"$$ENV_URL_INSTALL_X64_MSI\\\")
message(install x86 msi url: \\\"$$ENV_URL_INSTALL_X86_MSI\\\")

View File

@ -8,25 +8,70 @@ CONFIG -= debug_and_release debug_and_release_target
TEMPLATE = app
CORE_ROOT_DIR = $$PWD/../../../../core
UICLASSES = $$PWD/src/uiclasses
CONFIG += core_no_dst
include($$CORE_ROOT_DIR/Common/base.pri)
INCLUDEPATH += $$PWD/src
INCLUDEPATH += $$PWD/src \
$$UICLASSES
INCLUDEPATH += $$PWD/../../src/prop
HEADERS += $$PWD/src/version.h \
$$PWD/src/resource.h \
$$PWD/src/mainwindow.h \
$$PWD/src/cdownloader.h \
$$PWD/src/translator.h \
$$PWD/src/utils.h
$$PWD/src/utils.h \
$$UICLASSES/commondefines.h \
$$UICLASSES/baseutils.h \
$$UICLASSES/common.h \
$$UICLASSES/metrics.h \
$$UICLASSES/palette.h \
$$UICLASSES/drawningengine.h \
$$UICLASSES/drawingsurface.h \
$$UICLASSES/object.h \
$$UICLASSES/application.h \
$$UICLASSES/window.h \
$$UICLASSES/widget.h \
$$UICLASSES/label.h \
$$UICLASSES/caption.h \
$$UICLASSES/abstractbutton.h \
$$UICLASSES/button.h \
$$UICLASSES/checkbox.h \
$$UICLASSES/radiobutton.h \
$$UICLASSES/progressbar.h \
$$UICLASSES/layoutitem.h \
$$UICLASSES/layout.h \
$$UICLASSES/boxlayout.h
SOURCES += $$PWD/src/main.cpp \
$$PWD/src/mainwindow.cpp \
$$PWD/src/cdownloader.cpp \
$$PWD/src/translator.cpp \
$$PWD/src/utils.cpp
$$PWD/src/utils.cpp \
$$UICLASSES/baseutils.cpp \
$$UICLASSES/common.cpp \
$$UICLASSES/metrics.cpp \
$$UICLASSES/palette.cpp \
$$UICLASSES/drawningengine.cpp \
$$UICLASSES/drawingsurface.cpp \
$$UICLASSES/object.cpp \
$$UICLASSES/application.cpp \
$$UICLASSES/window.cpp \
$$UICLASSES/widget.cpp \
$$UICLASSES/label.cpp \
$$UICLASSES/caption.cpp \
$$UICLASSES/abstractbutton.cpp \
$$UICLASSES/button.cpp \
$$UICLASSES/checkbox.cpp \
$$UICLASSES/radiobutton.cpp \
$$UICLASSES/progressbar.cpp \
$$UICLASSES/layoutitem.cpp \
$$UICLASSES/layout.cpp \
$$UICLASSES/boxlayout.cpp
OTHER_FILES += $$PWD/res/dialog.rc \
OTHER_FILES += $$PWD/res/version.rc \
$$PWD/res/manifest/online-installer.exe.manifest
ENV_PRODUCT_VERSION = $$(PRODUCT_VERSION)
@ -37,7 +82,8 @@ ENV_PRODUCT_VERSION = $$(PRODUCT_VERSION)
}
CONFIG -= embed_manifest_exe
RC_FILE = $$PWD/res/dialog.rc
RC_FILE = $$PWD/res/version.rc
QMAKE_CXXFLAGS += -D_UNICODE
contains(QMAKE_TARGET.arch, x86_64):{
QMAKE_LFLAGS_WINDOWS = /SUBSYSTEM:WINDOWS,5.02
@ -59,10 +105,20 @@ build_xp {
DEFINES += __OS_WIN_XP
}
DEFINES -= NOMINMAX
LIBS += -luser32 \
-lshell32 \
-lshlwapi \
-lwinhttp \
-lwintrust \
-lgdi32 \
-lgdiplus \
-ladvapi32 \
-lrpcrt4 \
-lole32 \
-lmsi \
-lwinmm \
-lcomctl32
OBJECTS_DIR = $$DESTDIR/obj

View File

@ -1,68 +0,0 @@
#pragma code_page(65001)
#include <Windows.h>
#include "../src/version.h"
#include "../src/resource.h"
IDI_MAINICON ICON DISCARDABLE APP_ICON_PATH
IDT_TRANSLATIONS RCDATA APP_LANG_PATH
CREATEPROCESS_MANIFEST_RESOURCE_ID RT_MANIFEST "./manifest/online-installer.exe.manifest"
VS_VERSION_INFO VERSIONINFO
FILEVERSION VER_FILEVERSION
PRODUCTVERSION VER_PRODUCTVERSION
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK VER_LANG_AND_CHARSET_STR
BEGIN
VALUE "CompanyName", VER_COMPANYNAME_STR
VALUE "FileDescription", VER_FILEDESCRIPTION_STR
VALUE "FileVersion", VER_FILEVERSION_STR
VALUE "InternalName", VER_INTERNALNAME_STR
VALUE "LegalCopyright", VER_LEGALCOPYRIGHT_STR
VALUE "LegalTrademarks1", VER_LEGALTRADEMARKS1_STR
VALUE "LegalTrademarks2", VER_LEGALTRADEMARKS2_STR
VALUE "OriginalFilename", VER_ORIGINALFILENAME_STR
VALUE "ProductName", VER_PRODUCTNAME_STR
VALUE "ProductVersion", VER_PRODUCTVERSION_STR
END
END
BLOCK "VarFileInfo"
BEGIN
VALUE "Translation", VER_LANG_ID, VER_CHARSET_ID
END
END
//
// Dialog
//
IDD_DIALOG DIALOGEX 0, 0, 320, 100
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CENTER | WS_CAPTION | WS_SYSMENU
EXSTYLE WS_EX_STATICEDGE
CAPTION ""
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
CONTROL "Progress", IDC_PROGRESS, "msctls_progress32", WS_BORDER, 15, 56, 290, 6
CONTROL "Icon", IDC_MAIN_ICON, "Static", SS_ICON | SS_CENTER | WS_CHILD | WS_VISIBLE, 15, 10, 32, 32
LTEXT "", IDC_LABEL_TITLE, 75, 15, 220, 14, SS_LEFT | WS_CHILD | WS_VISIBLE
LTEXT "", IDC_LABEL_MESSAGE, 75, 28, 220, 24, SS_LEFT | WS_CHILD | WS_VISIBLE
PUSHBUTTON "", IDC_BUTTON_CANCEL, 225, 72, 80, 18
CONTROL "", IDC_SILENT_CHECK, "BUTTON", BS_AUTOCHECKBOX | WS_TABSTOP, 30, 70, 100, 20
END
IDD_DIALOG_RTL DIALOGEX 0, 0, 320, 100
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CENTER | WS_CAPTION | WS_SYSMENU
EXSTYLE WS_EX_STATICEDGE | WS_EX_LAYOUTRTL
CAPTION ""
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
CONTROL "Progress", IDC_PROGRESS, "msctls_progress32", WS_BORDER, 15, 56, 290, 6
CONTROL "Icon", IDC_MAIN_ICON, "Static", SS_ICON | SS_CENTER | WS_CHILD | WS_VISIBLE, 15, 10, 32, 32
LTEXT "", IDC_LABEL_TITLE, 75, 15, 220, 14, SS_LEFT | WS_CHILD | WS_VISIBLE
LTEXT "", IDC_LABEL_MESSAGE, 75, 28, 220, 24, SS_LEFT | WS_CHILD | WS_VISIBLE
PUSHBUTTON "", IDC_BUTTON_CANCEL, 225, 72, 80, 18
CONTROL "", IDC_SILENT_CHECK, "BUTTON", BS_AUTOCHECKBOX | WS_TABSTOP, 30, 70, 100, 20
END

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

View File

@ -1,246 +1,357 @@
en.CAPTION_TEXT =ONLYOFFICE Online Installer
ru.CAPTION_TEXT =ONLYOFFICE Онлайн Установщик
de.CAPTION_TEXT =ONLYOFFICE Online-Installationsprogramm
fr.CAPTION_TEXT =Programme d'installation ONLYOFFICE en ligne
es.CAPTION_TEXT = Instalador online ONLYOFFICE
it.CAPTION_TEXT =Programma di installazione online di ONLYOFFICE
ja.CAPTION_TEXT =ONLYOFFICE オンラインインストーラー
zh_CN.CAPTION_TEXT =ONLYOFFICE 在线安装程序
ro.CAPTION_TEXT =Asistent de Instalare Online ONLYOFFICE
ar_SA.CAPTION_TEXT =ONLYOFFICE المثبت عبر الإنترنت
bg.CAPTION_TEXT =Онлайн инсталатор на ONLYOFFICE
cs.CAPTION_TEXT =Online instalátor ONLYOFFICE
el.CAPTION_TEXT =Διαδικτυακό πρόγραμμα εγκατάστασης ONLYOFFICE
fi.CAPTION_TEXT =ONLYOFFICE verkkoasennus
hy.CAPTION_TEXT =ONLYOFFICE առցանց տեղադրող
ko.CAPTION_TEXT =ONLYOFFICE 온라인 설치 프로그램
lv.CAPTION_TEXT =ONLYOFFICE tiešsaistes instalētājs
nl.CAPTION_TEXT =ONLYOFFICE Online Installatieprogramma
pl.CAPTION_TEXT =Instalator ONLYOFFICE online
pt_PT.CAPTION_TEXT =Instalador on-line do ONLYOFFICE
sk.CAPTION_TEXT =Online inštalátor ONLYOFFICE
sl.CAPTION_TEXT =ONLYOFFICE Spletni namestitveni program
tr.CAPTION_TEXT =ONLYOFFICE Çevrimiçi Yükleyici
uk.CAPTION_TEXT =Онлайн-інсталятор ONLYOFFICE
vi.CAPTION_TEXT =Trình cài đặt trực tuyến ONLYOFFICE
sr_latn_RS.CAPTION_TEXT =ONLYOFFICE Onlajn Instalater
si.CAPTION_TEXT =ඔන්ලිඔෆිස් මාර්ගගත ස්ථාපකය
be.CAPTION_TEXT =Анлайн усталёўшчык ONLYOFFICE
ca.CAPTION_TEXT =Instal·lador online ONLYOFFICE
da.CAPTION_TEXT =ONLYOFFICE Onlineinstallatør
gl.CAPTION_TEXT =Instalador en liña de ONLYOFFICE
hu.CAPTION_TEXT =ONLYOFFICE Online Telepítő
id.CAPTION_TEXT =Installer Online ONLYOFFICE
no.CAPTION_TEXT =ONLYOFFICE nettbasert installasjonsprogram
et.CAPTION_TEXT =ONLYOFFICE veebipaigaldus
lt.CAPTION_TEXT =ONLYOFFICE diegimas internetu
hr.CAPTION_TEXT =Mrežni instalacijski program ONLYOFFICE
hi.CAPTION_TEXT =ओनलीऑफिस ऑनलाइन इंस्टॉलर
sv.CAPTION_TEXT =ONLYOFFICE onlineinstallationsprogram
sr_Cyrl_RS.CAPTION_TEXT =ONLYOFFICE Онлајн Инсталатер
en.CAPTION =ONLYOFFICE Online Installer
ru.CAPTION =ONLYOFFICE Онлайн Установщик
de.CAPTION =ONLYOFFICE Online-Installationsprogramm
fr.CAPTION =Programme d'installation ONLYOFFICE en ligne
es.CAPTION = Instalador online ONLYOFFICE
it.CAPTION =Programma di installazione online di ONLYOFFICE
ja.CAPTION =ONLYOFFICE オンラインインストーラー
zh_CN.CAPTION =ONLYOFFICE 在线安装程序
ro.CAPTION =Asistent de Instalare Online ONLYOFFICE
ar_SA.CAPTION =ONLYOFFICE المثبت عبر الإنترنت
bg.CAPTION =Онлайн инсталатор на ONLYOFFICE
cs.CAPTION =Online instalátor ONLYOFFICE
el.CAPTION =Διαδικτυακό πρόγραμμα εγκατάστασης ONLYOFFICE
fi.CAPTION =ONLYOFFICE verkkoasennus
hy.CAPTION =ONLYOFFICE առցանց տեղադրող
ko.CAPTION =ONLYOFFICE 온라인 설치 프로그램
lv.CAPTION =ONLYOFFICE tiešsaistes instalētājs
nl.CAPTION =ONLYOFFICE Online Installatieprogramma
pl.CAPTION =Instalator ONLYOFFICE online
pt_PT.CAPTION =Instalador on-line do ONLYOFFICE
sk.CAPTION =Online inštalátor ONLYOFFICE
sl.CAPTION =ONLYOFFICE Spletni namestitveni program
tr.CAPTION =ONLYOFFICE Çevrimiçi Yükleyici
uk.CAPTION =Онлайн-інсталятор ONLYOFFICE
vi.CAPTION =Trình cài đặt trực tuyến ONLYOFFICE
sr_latn_RS.CAPTION =ONLYOFFICE Onlajn Instalater
si.CAPTION =ඔන්ලිඔෆිස් මාර්ගගත ස්ථාපකය
be.CAPTION =Анлайн усталёўшчык ONLYOFFICE
ca.CAPTION =Instal·lador online ONLYOFFICE
da.CAPTION =ONLYOFFICE Onlineinstallatør
gl.CAPTION =Instalador en liña de ONLYOFFICE
hu.CAPTION =ONLYOFFICE Online Telepítő
id.CAPTION =Installer Online ONLYOFFICE
no.CAPTION =ONLYOFFICE nettbasert installasjonsprogram
et.CAPTION =ONLYOFFICE veebipaigaldus
lt.CAPTION =ONLYOFFICE diegimas internetu
hr.CAPTION =Mrežni instalacijski program ONLYOFFICE
hi.CAPTION =ओनलीऑफिस ऑनलाइन इंस्टॉलर
sv.CAPTION =ONLYOFFICE onlineinstallationsprogram
sr_Cyrl_RS.CAPTION =ONLYOFFICE Онлајн Инсталатер
en.MESSAGE_TEXT_ERR1 =The application cannot continue because this architecture is not supported.
ru.MESSAGE_TEXT_ERR1 =Приложение не может продолжить работу, так как эта архитектура не поддерживается.
de.MESSAGE_TEXT_ERR1 =Die Anwendung kann nicht fortgesetzt werden, da diese Architektur nicht unterstützt wird.
fr.MESSAGE_TEXT_ERR1 =L'application ne peut pas continuer car cette architecture n'est pas prise en charge.
es.MESSAGE_TEXT_ERR1 =La aplicación no puede continuar porque esta arquitectura no es compatible.
it.MESSAGE_TEXT_ERR1 =L'applicazione non può continuare perché questa architettura non è supportata.
ja.MESSAGE_TEXT_ERR1 =このアーキテクチャがサポートされていないため、アプリケーションを続行できません。
zh_CN.MESSAGE_TEXT_ERR1 =应用程序无法继续,因为此架构不受支持。
ro.MESSAGE_TEXT_ERR1 =Procesul aplicației nu poate continua deoarece această arhitectură nu este acceptată.
ar_SA.MESSAGE_TEXT_ERR1 =لا يمكن متابعة التطبيق لأن هذه البنية غير معتمدة.
bg.MESSAGE_TEXT_ERR1 =Приложението не може да продължи, защото тази архитектура не се поддържа.
cs.MESSAGE_TEXT_ERR1 =Aplikace nemůže pokračovat, protože tato architektura není podporována.
el.MESSAGE_TEXT_ERR1 =Η εφαρμογή δεν μπορεί να συνεχιστεί επειδή αυτή η αρχιτεκτονική δεν υποστηρίζεται.
fi.MESSAGE_TEXT_ERR1 =Sovellus ei toimi, koska tätä arkkitehtuuria ei tueta.
hy.MESSAGE_TEXT_ERR1 =Հավելվածը չի կարող շարունակվել, քանի որ այս ճարտարապետությունը չի աջակցվում:
ko.MESSAGE_TEXT_ERR1 =이 아키텍처는 지원되지 않으므로 애플리케이션을 계속할 수 없습니다.
lv.MESSAGE_TEXT_ERR1 =Lietojumprogrammu nevar turpināt, jo šī arhitektūra netiek atbalstīta.
nl.MESSAGE_TEXT_ERR1 =De toepassing kan niet doorgaan omdat deze architectuur niet wordt ondersteund.
pl.MESSAGE_TEXT_ERR1 =Aplikacja nie może zostać uruchomiona, ponieważ dana architektura nie jest obsługiwana.
pt_PT.MESSAGE_TEXT_ERR1 =O aplicativo não pode continuar porque esta arquitetura não é suportada.
sk.MESSAGE_TEXT_ERR1 =Aplikácia nemôže pokračovať, pretože táto architektúra nie je podporovaná.
sl.MESSAGE_TEXT_ERR1 =Aplikacija ne more nadaljevati, ker ta arhitektura ni podprta.
tr.MESSAGE_TEXT_ERR1 =Bu mimari desteklenmediği için uygulama devam edemiyor.
uk.MESSAGE_TEXT_ERR1 =Застосунок не може продовжити роботу, оскільки ця архітектура не підтримується.
vi.MESSAGE_TEXT_ERR1 =Ứng dụng không thể tiếp tục vì cấu trúc này không được hỗ trợ.
sr_Latn_RS.MESSAGE_TEXT_ERR1 =Aplikacija ne može nastaviti jer ova arhitektura nije podržana.
si.MESSAGE_TEXT_ERR1 =මෙම නිර්මාණ ශිල්පයට සහාය නොදක්වන නිසා මෘදුකාංගයට ඉදිරියට යාමට නොහැකිය.
be.MESSAGE_TEXT_ERR1 =Прыкладанне не можа далей працаваць, бо гэтая архітэктура не падтрымліваецца.
ca.MESSAGE_TEXT_ERR1 =L'aplicació no pot continuar perquè aquesta arquitectura no és compatible.
da.MESSAGE_TEXT_ERR1 =Applikationen kan ikke fortsætte, da denne arkitektur ikke er understøttet.
gl.MESSAGE_TEXT_ERR1 =A aplicación non pode continuar porque esta arquitectura non é compatible.
hu.MESSAGE_TEXT_ERR1 =Az alkalmazás nem folytatódhat, mert ez az architektúra nem támogatott.
id.MESSAGE_TEXT_ERR1 =Aplikasi tidak bisa dilanjutkan karena arsitektur tidak mendukung.
no.MESSAGE_TEXT_ERR1 =Applikasjonen kan ikke fortsette fordi denne arkitekturen støttes ikke.
et.MESSAGE_TEXT_ERR1 =Rakendusega ei saa jätkata, sest seda arhitektuuri ei toetata.
lt.MESSAGE_TEXT_ERR1 =Programa negali būti tęsiama, nes ši architektūra nepalaikoma.
hr.MESSAGE_TEXT_ERR1 =Aplikacija ne može nastaviti jer ova arhitektura nije podržana.
hi.MESSAGE_TEXT_ERR1 =यह एप्लिकेशन जारी नहीं रह सकती क्योंकि यह आर्किटेक्चर समर्थित नहीं है।
sv.MESSAGE_TEXT_ERR1 =Applikationen kan inte fortsätta eftersom denna arkitektur inte stöds.
sr_Cyrl_RS.MESSAGE_TEXT_ERR1 =Апликација не може наставити јер ова архитектура није подржана.
en.MSG_ERR_ARCH =The application cannot continue because this architecture is not supported.
ru.MSG_ERR_ARCH =Приложение не может продолжить работу, так как эта архитектура не поддерживается.
de.MSG_ERR_ARCH =Die Anwendung kann nicht fortgesetzt werden, da diese Architektur nicht unterstützt wird.
fr.MSG_ERR_ARCH =L'application ne peut pas continuer car cette architecture n'est pas prise en charge.
es.MSG_ERR_ARCH =La aplicación no puede continuar porque esta arquitectura no es compatible.
it.MSG_ERR_ARCH =L'applicazione non può continuare perché questa architettura non è supportata.
ja.MSG_ERR_ARCH =このアーキテクチャがサポートされていないため、アプリケーションを続行できません。
zh_CN.MSG_ERR_ARCH =应用程序无法继续,因为此架构不受支持。
ro.MSG_ERR_ARCH =Procesul aplicației nu poate continua deoarece această arhitectură nu este acceptată.
ar_SA.MSG_ERR_ARCH =لا يمكن متابعة التطبيق لأن هذه البنية غير معتمدة.
bg.MSG_ERR_ARCH =Приложението не може да продължи, защото тази архитектура не се поддържа.
cs.MSG_ERR_ARCH =Aplikace nemůže pokračovat, protože tato architektura není podporována.
el.MSG_ERR_ARCH =Η εφαρμογή δεν μπορεί να συνεχιστεί επειδή αυτή η αρχιτεκτονική δεν υποστηρίζεται.
fi.MSG_ERR_ARCH =Sovellus ei toimi, koska tätä arkkitehtuuria ei tueta.
hy.MSG_ERR_ARCH =Հավելվածը չի կարող շարունակվել, քանի որ այս ճարտարապետությունը չի աջակցվում:
ko.MSG_ERR_ARCH =이 아키텍처는 지원되지 않으므로 애플리케이션을 계속할 수 없습니다.
lv.MSG_ERR_ARCH =Lietojumprogrammu nevar turpināt, jo šī arhitektūra netiek atbalstīta.
nl.MSG_ERR_ARCH =De toepassing kan niet doorgaan omdat deze architectuur niet wordt ondersteund.
pl.MSG_ERR_ARCH =Aplikacja nie może zostać uruchomiona, ponieważ dana architektura nie jest obsługiwana.
pt_PT.MSG_ERR_ARCH =O aplicativo não pode continuar porque esta arquitetura não é suportada.
sk.MSG_ERR_ARCH =Aplikácia nemôže pokračovať, pretože táto architektúra nie je podporovaná.
sl.MSG_ERR_ARCH =Aplikacija ne more nadaljevati, ker ta arhitektura ni podprta.
tr.MSG_ERR_ARCH =Bu mimari desteklenmediği için uygulama devam edemiyor.
uk.MSG_ERR_ARCH =Застосунок не може продовжити роботу, оскільки ця архітектура не підтримується.
vi.MSG_ERR_ARCH =Ứng dụng không thể tiếp tục vì cấu trúc này không được hỗ trợ.
sr_Latn_RS.MSG_ERR_ARCH =Aplikacija ne može nastaviti jer ova arhitektura nije podržana.
si.MSG_ERR_ARCH =මෙම නිර්මාණ ශිල්පයට සහාය නොදක්වන නිසා මෘදුකාංගයට ඉදිරියට යාමට නොහැකිය.
be.MSG_ERR_ARCH =Прыкладанне не можа далей працаваць, бо гэтая архітэктура не падтрымліваецца.
ca.MSG_ERR_ARCH =L'aplicació no pot continuar perquè aquesta arquitectura no és compatible.
da.MSG_ERR_ARCH =Applikationen kan ikke fortsætte, da denne arkitektur ikke er understøttet.
gl.MSG_ERR_ARCH =A aplicación non pode continuar porque esta arquitectura non é compatible.
hu.MSG_ERR_ARCH =Az alkalmazás nem folytatódhat, mert ez az architektúra nem támogatott.
id.MSG_ERR_ARCH =Aplikasi tidak bisa dilanjutkan karena arsitektur tidak mendukung.
no.MSG_ERR_ARCH =Applikasjonen kan ikke fortsette fordi denne arkitekturen støttes ikke.
et.MSG_ERR_ARCH =Rakendusega ei saa jätkata, sest seda arhitektuuri ei toetata.
lt.MSG_ERR_ARCH =Programa negali būti tęsiama, nes ši architektūra nepalaikoma.
hr.MSG_ERR_ARCH =Aplikacija ne može nastaviti jer ova arhitektura nije podržana.
hi.MSG_ERR_ARCH =यह एप्लिकेशन जारी नहीं रह सकती क्योंकि यह आर्किटेक्चर समर्थित नहीं है।
sv.MSG_ERR_ARCH =Applikationen kan inte fortsätta eftersom denna arkitektur inte stöds.
sr_Cyrl_RS.MSG_ERR_ARCH =Апликација не може наставити јер ова архитектура није подржана.
en.MESSAGE_TEXT_ERR2 =The application is already running.
ru.MESSAGE_TEXT_ERR2 =Приложение уже запущено.
de.MESSAGE_TEXT_ERR2 =Die Anwendung läuft bereits.
fr.MESSAGE_TEXT_ERR2 =Cette application est déjà en cours d'exécution.
es.MESSAGE_TEXT_ERR2 =La aplicación ya se está ejecutando.
it.MESSAGE_TEXT_ERR2 =L'applicazione sta già funzionando.
ja.MESSAGE_TEXT_ERR2 =アプリケーションはすでに実行されています。
zh_CN.MESSAGE_TEXT_ERR2 =应用程序已在运行。
ro.MESSAGE_TEXT_ERR2 =Aplicația este deja în desfășurare.
ar_SA.MESSAGE_TEXT_ERR2 =التطبيق قيد التشغيل بالفعل.
bg.MESSAGE_TEXT_ERR2 =Приложението вече работи.
cs.MESSAGE_TEXT_ERR2 =Aplikace již běží.
el.MESSAGE_TEXT_ERR2 =Η εφαρμογή εκτελείται ήδη.
fi.MESSAGE_TEXT_ERR2 =Sovellus on jo käynnissä.
hy.MESSAGE_TEXT_ERR2 =Հավելվածն արդեն աշխատում է։
ko.MESSAGE_TEXT_ERR2 =애플리케이션이 이미 실행 중입니다.
lv.MESSAGE_TEXT_ERR2 =Lietojumprogramma jau darbojas.
nl.MESSAGE_TEXT_ERR2 =De toepassing draait al.
pl.MESSAGE_TEXT_ERR2 =Aplikacja jest już uruchomiona.
pt_PT.MESSAGE_TEXT_ERR2 =O aplicativo já está em execução.
sk.MESSAGE_TEXT_ERR2 =Aplikácia je už spustená.
sl.MESSAGE_TEXT_ERR2 =Aplikacija se že izvaja.
tr.MESSAGE_TEXT_ERR2 =Uygulama zaten çalışıyor.
uk.MESSAGE_TEXT_ERR2 =Застосунок вже запущений.
vi.MESSAGE_TEXT_ERR2 =Ứng dụng đang chạy.
sr_Latn_RS.MESSAGE_TEXT_ERR2 =Aplikacija već radi.
si.MESSAGE_TEXT_ERR2 =මෘදුකාංගය දැනටමත් ධාවනය වේ.
be.MESSAGE_TEXT_ERR2 =Прыкладанне ўжо запушчана.
ca.MESSAGE_TEXT_ERR2 =L'aplicació ja s'està executant.
da.MESSAGE_TEXT_ERR2 =Applikationen kører allerede.
gl.MESSAGE_TEXT_ERR2 =A aplicación xa se está executando.
hu.MESSAGE_TEXT_ERR2 =Az alkalmazás már fut.
id.MESSAGE_TEXT_ERR2 =Aplikasi sedang berjalan.
no.MESSAGE_TEXT_ERR2 =Applikasjonen kjører allerede.
et.MESSAGE_TEXT_ERR2 =Rakendus juba töötab.
lt.MESSAGE_TEXT_ERR2 =Programa jau paleista.
hr.MESSAGE_TEXT_ERR2 =Aplikacija je već pokrenuta.
hi.MESSAGE_TEXT_ERR2 =एप्लीकेशन पहले से ही चल रही है।
sv.MESSAGE_TEXT_ERR2 =Applikationen körs redan.
sr_Cyrl_RS.MESSAGE_TEXT_ERR2 =Апликација већ ради.
en.MSG_ERR_ALREADY_RUNNING =The application is already running.
ru.MSG_ERR_ALREADY_RUNNING =Приложение уже запущено.
de.MSG_ERR_ALREADY_RUNNING =Die Anwendung läuft bereits.
fr.MSG_ERR_ALREADY_RUNNING =Cette application est déjà en cours d'exécution.
es.MSG_ERR_ALREADY_RUNNING =La aplicación ya se está ejecutando.
it.MSG_ERR_ALREADY_RUNNING =L'applicazione sta già funzionando.
ja.MSG_ERR_ALREADY_RUNNING =アプリケーションはすでに実行されています。
zh_CN.MSG_ERR_ALREADY_RUNNING =应用程序已在运行。
ro.MSG_ERR_ALREADY_RUNNING =Aplicația este deja în desfășurare.
ar_SA.MSG_ERR_ALREADY_RUNNING =التطبيق قيد التشغيل بالفعل.
bg.MSG_ERR_ALREADY_RUNNING =Приложението вече работи.
cs.MSG_ERR_ALREADY_RUNNING =Aplikace již běží.
el.MSG_ERR_ALREADY_RUNNING =Η εφαρμογή εκτελείται ήδη.
fi.MSG_ERR_ALREADY_RUNNING =Sovellus on jo käynnissä.
hy.MSG_ERR_ALREADY_RUNNING =Հավելվածն արդեն աշխատում է։
ko.MSG_ERR_ALREADY_RUNNING =애플리케이션이 이미 실행 중입니다.
lv.MSG_ERR_ALREADY_RUNNING =Lietojumprogramma jau darbojas.
nl.MSG_ERR_ALREADY_RUNNING =De toepassing draait al.
pl.MSG_ERR_ALREADY_RUNNING =Aplikacja jest już uruchomiona.
pt_PT.MSG_ERR_ALREADY_RUNNING =O aplicativo já está em execução.
sk.MSG_ERR_ALREADY_RUNNING =Aplikácia je už spustená.
sl.MSG_ERR_ALREADY_RUNNING =Aplikacija se že izvaja.
tr.MSG_ERR_ALREADY_RUNNING =Uygulama zaten çalışıyor.
uk.MSG_ERR_ALREADY_RUNNING =Застосунок вже запущений.
vi.MSG_ERR_ALREADY_RUNNING =Ứng dụng đang chạy.
sr_Latn_RS.MSG_ERR_ALREADY_RUNNING =Aplikacija već radi.
si.MSG_ERR_ALREADY_RUNNING =මෘදුකාංගය දැනටමත් ධාවනය වේ.
be.MSG_ERR_ALREADY_RUNNING =Прыкладанне ўжо запушчана.
ca.MSG_ERR_ALREADY_RUNNING =L'aplicació ja s'està executant.
da.MSG_ERR_ALREADY_RUNNING =Applikationen kører allerede.
gl.MSG_ERR_ALREADY_RUNNING =A aplicación xa se está executando.
hu.MSG_ERR_ALREADY_RUNNING =Az alkalmazás már fut.
id.MSG_ERR_ALREADY_RUNNING =Aplikasi sedang berjalan.
no.MSG_ERR_ALREADY_RUNNING =Applikasjonen kjører allerede.
et.MSG_ERR_ALREADY_RUNNING =Rakendus juba töötab.
lt.MSG_ERR_ALREADY_RUNNING =Programa jau paleista.
hr.MSG_ERR_ALREADY_RUNNING =Aplikacija je već pokrenuta.
hi.MSG_ERR_ALREADY_RUNNING =एप्लीकेशन पहले से ही चल रही है।
sv.MSG_ERR_ALREADY_RUNNING =Applikationen körs redan.
sr_Cyrl_RS.MSG_ERR_ALREADY_RUNNING =Апликација већ ради.
en.LABEL_MESSAGE_TEXT_ERR5 =An error occurred while running the package.\nPlease try restarting the app later.
ru.LABEL_MESSAGE_TEXT_ERR5 =Произошла ошибка при запуске установщика.\nПопробуйте перезапустить приложение позже.
de.LABEL_MESSAGE_TEXT_ERR5 =Beim Ausführen des Pakets ist ein Fehler aufgetreten.\nBitte versuchen Sie, die App später neu zu starten.
fr.LABEL_MESSAGE_TEXT_ERR5 =Une erreur s'est produit lors de l'exécution du paquet.\nVeuillez réessayer de redémarrer l'application plus tard.
es.LABEL_MESSAGE_TEXT_ERR5 =Se ha producido un error al ejecutar el paquete.\nIntente reiniciar la aplicación más tarde.
it.LABEL_MESSAGE_TEXT_ERR5 =Si è verificato un errore durante l'esecuzione del pacchetto.\nProva a riavviare l'app più tardi.
ja.LABEL_MESSAGE_TEXT_ERR5 =パッケージの実行中にエラーが発生しました。\nアプリを後で再起動してみてください。
zh_CN.LABEL_MESSAGE_TEXT_ERR5 =运行软件包时发生错误。\n请稍后尝试重新启动应用程序。
ro.LABEL_MESSAGE_TEXT_ERR5 =A intervenit o eroare în timpul executării pachetului.\nÎncercaţi să reporniți aplicația mai târziu.
ar_SA.LABEL_MESSAGE_TEXT_ERR5 =حدث خطأ أثناء تشغيل الحزمة.\nالرجاء محاولة إعادة تشغيل التطبيق لاحقا.
bg.LABEL_MESSAGE_TEXT_ERR5 =Възникна грешка при стартиране на пакета.\nМоля, опитайте да рестартирате приложението по-късно.
cs.LABEL_MESSAGE_TEXT_ERR5 =Při spouštění balíčku došlo k chybě.\nProsím, zkuste aplikaci restartovat později.
el.LABEL_MESSAGE_TEXT_ERR5 =Προέκυψε σφάλμα κατά την εκτέλεση του πακέτου.\nΔοκιμάστε να επανεκκινήσετε την εφαρμογή αργότερα.
fi.LABEL_MESSAGE_TEXT_ERR5 =Paketin suorittamisen aikana tapahtui virhe. \nOle hyvä ja yritä käynnistää sovellus myöhemmin uudelleen.
hy.LABEL_MESSAGE_TEXT_ERR5 =Փաթեթը գործարկելիս սխալ է տեղի ունեցել.\nՓորձեք ավելի ուշ վերագործարկել հավելվածը:
ko.LABEL_MESSAGE_TEXT_ERR5 =패키지를 실행하는 동안 오류가 발생했습니다.\n나중에 앱을 다시 시작하세요.
lv.LABEL_MESSAGE_TEXT_ERR5 =Palaižot pakotni, radās kļūda.\nMēģiniet restartēt lietotni vēlāk.
nl.LABEL_MESSAGE_TEXT_ERR5 =Er is een fout opgetreden tijdens het uitvoeren van het pakket.\Probeer de app later opnieuw te starten.
pl.LABEL_MESSAGE_TEXT_ERR5 =Wystąpił błąd podczas uruchamiania pakietu.\nSpróbuj ponownie uruchomić aplikację później.
pt_PT.LABEL_MESSAGE_TEXT_ERR5 =Ocorreu um erro ao executar o pacote.\nTente reiniciar o aplicativo mais tarde.
sk.LABEL_MESSAGE_TEXT_ERR5 =Počas spúšťania balíka došlo k chybe.\nProsím, skúste reštartovať aplikáciu neskôr.
sl.LABEL_MESSAGE_TEXT_ERR5 =Med izvajanjem paketa je prišlo do napake.\nPoskusite znova zagnati aplikacijo pozneje.
tr.LABEL_MESSAGE_TEXT_ERR5 =Paket çalıştırılırken bir hata oluştu.\nLütfen uygulamayı daha sonra yeniden başlatmayı deneyin.
uk.LABEL_MESSAGE_TEXT_ERR5 =Під час запуску пакету сталася помилка. \nСпробуйте перезапустити застосунок пізніше.
vi.LABEL_MESSAGE_TEXT_ERR5 =Đã xảy ra lỗi khi chạy gói.\nVui lòng thử khởi động lại ứng dụng sau.
sr_Latn_RS.LABEL_MESSAGE_TEXT_ERR5 =Došlo je do greške prilikom pokretanja paketa.\nMolimo pokušajte da restartujete aplikaciju kasnije.
si.LABEL_MESSAGE_TEXT_ERR5 =ඇසුරුම ධාවනයේ දී දෝෂයක් සිදු විය.\nකරුණාකර මෘදුකාංගය නැවත ආරම්භ කර බලන්න.
be.LABEL_MESSAGE_TEXT_ERR5 =Падчас запуску пакета адбылася памылка.\nПаспрабуйце перазапусціць прыкладанне пазней.
ca.LABEL_MESSAGE_TEXT_ERR5 =S'ha produït un error en executar el paquet.\nProveu de reiniciar l'aplicació més tard.
da.LABEL_MESSAGE_TEXT_ERR5 =Der opstod en fejl under drift af pakken.\nPrøv venligst at genstarte appen senere.
gl.LABEL_MESSAGE_TEXT_ERR5 =Produciuse un erro ao executar o paquete.\nPor favor, tente reiniciar a aplicación máis tarde.
hu.LABEL_MESSAGE_TEXT_ERR5 =Hiba történt a csomag futtatása közben.\nKérjük, próbálja meg később újraindítani az alkalmazást.
id.LABEL_MESSAGE_TEXT_ERR5 =Ada kesalahan saat menjalankan paket.\nMohon restart app lagi nanti.
no.LABEL_MESSAGE_TEXT_ERR5 =Det oppstod en feil under kjøring av pakken.\nVennligst prøv å starte appen på nytt senere.
et.LABEL_MESSAGE_TEXT_ERR5 =Paketi käivitamisel tekkis viga.\nPalun proovige rakenduse taaskäivitamist hiljem.
lt.LABEL_MESSAGE_TEXT_ERR5 =Paleidus paketą, įvyko klaida.\nPabandykite kiek vėliau iš naujo paleisti programą.
hr.LABEL_MESSAGE_TEXT_ERR5 =Došlo je do pogreške prilikom pokretanja paketa.\nPokušajte ponovno pokrenuti aplikaciju kasnije.
hi.LABEL_MESSAGE_TEXT_ERR5 =पैकेज चलाने के दौरान एक त्रुटि उत्पन्न हुई।\nकृपया बाद में ऐप को रीस्टार्ट करने का प्रयास करें।
sv.LABEL_MESSAGE_TEXT_ERR5 =Ett fel inträffade vid körning av paketet.\nFörsök starta om appen senare.
sr_Cyrl_RS.LABEL_MESSAGE_TEXT_ERR5 =Дошло је до грешке приликом покретања пакета.\nМолимо покушајте да рестартујете апликацију касније.
en.MSG_ERR_CLOSE_APP =Setup has detected that %1 is currently running. Please close all instances of it.
ru.MSG_ERR_CLOSE_APP =Обнаружен запущенный экземпляр %1. Пожалуйста, закройте все экземпляры приложения.
en.BUTTON_CANCEL_TEXT =Cancel
ru.BUTTON_CANCEL_TEXT =Отмена
de.BUTTON_CANCEL_TEXT =Abbrechen
fr.BUTTON_CANCEL_TEXT =Annuler
es.BUTTON_CANCEL_TEXT =Cancelar
it.BUTTON_CANCEL_TEXT =Annulla
ja.BUTTON_CANCEL_TEXT =キャンセル
zh_CN.BUTTON_CANCEL_TEXT =取消
ro.BUTTON_CANCEL_TEXT =Anulare
ar_SA.BUTTON_CANCEL_TEXT =إلغاء
bg.BUTTON_CANCEL_TEXT =Отказ
cs.BUTTON_CANCEL_TEXT =Zrušit
el.BUTTON_CANCEL_TEXT =Ακύρωση
fi.BUTTON_CANCEL_TEXT =Peruuta
hy.BUTTON_CANCEL_TEXT =Չեղարկել
ko.BUTTON_CANCEL_TEXT =취소
lv.BUTTON_CANCEL_TEXT =Atcelt
nl.BUTTON_CANCEL_TEXT =Annuleren
pl.BUTTON_CANCEL_TEXT =Anuluj
pt_PT.BUTTON_CANCEL_TEXT =Cancelar
sk.BUTTON_CANCEL_TEXT =Zrušiť
sl.BUTTON_CANCEL_TEXT =Prekliči
tr.BUTTON_CANCEL_TEXT =İptal
uk.BUTTON_CANCEL_TEXT =Скасувати
vi.BUTTON_CANCEL_TEXT =Hủy
sr_Latn_RS.BUTTON_CANCEL_TEXT =Otkaži
si.BUTTON_CANCEL_TEXT =අවලංගු
be.BUTTON_CANCEL_TEXT =Адмяніць
ca.BUTTON_CANCEL_TEXT =Cancel·lar
da.BUTTON_CANCEL_TEXT =Annuller
gl.BUTTON_CANCEL_TEXT =Cancelar
hu.BUTTON_CANCEL_TEXT =Törlés
id.BUTTON_CANCEL_TEXT =Batal
no.BUTTON_CANCEL_TEXT =Avbryt
et.BUTTON_CANCEL_TEXT =Tühista
lt.BUTTON_CANCEL_TEXT =Atšaukti
hr.BUTTON_CANCEL_TEXT =Otkaži
hi.BUTTON_CANCEL_TEXT =रद्द करें
sv.BUTTON_CANCEL_TEXT =Avbryt
sr_Cyrl_RS.BUTTON_CANCEL_TEXT =Откажи
en.MSG_REMOVE =This will remove %1 and its components.
ru.MSG_REMOVE =Это приведет к удалению %1 и его компонентов.
en.SILENT_CHECK_TEXT =Silent Installation
ru.SILENT_CHECK_TEXT =Тихая установка
de.SILENT_CHECK_TEXT =Silent Installation
fr.SILENT_CHECK_TEXT =Installation sans assistance
es.SILENT_CHECK_TEXT =Instalación silenciosa
it.SILENT_CHECK_TEXT =Installazione silenziosa
ja.SILENT_CHECK_TEXT =サイレントインストール
zh_CN.SILENT_CHECK_TEXT =静默安装
ro.SILENT_CHECK_TEXT =Instalare nesupravegheată
ar_SA.SILENT_CHECK_TEXT =التثبيت الصامت
bg.SILENT_CHECK_TEXT =Тихо инсталиране
cs.SILENT_CHECK_TEXT =Tichá instalace
el.SILENT_CHECK_TEXT =Αθόρυβη εγκατάσταση
fi.SILENT_CHECK_TEXT =Äänetön asennus
hy.SILENT_CHECK_TEXT =Լուռ տեղադրում
ko.SILENT_CHECK_TEXT =비대화형 방식 설치
lv.SILENT_CHECK_TEXT =Klusā instalēšana
nl.SILENT_CHECK_TEXT =Stille installatie
pl.SILENT_CHECK_TEXT =Instalacja dyskretna
pt_PT.SILENT_CHECK_TEXT =Instalação silenciosa
sk.SILENT_CHECK_TEXT =Tichá inštalácia
sl.SILENT_CHECK_TEXT =Tiha namestitev
tr.SILENT_CHECK_TEXT =Sessiz Kurulum
uk.SILENT_CHECK_TEXT =Автоматичне інсталювання
vi.SILENT_CHECK_TEXT =Cài đặt im lặng
sr_Latn_RS.SILENT_CHECK_TEXT =Tiha instalacija
si.SILENT_CHECK_TEXT =නිහඬ ස්ථාපනය
be.SILENT_CHECK_TEXT =Ціхая ўстаноўка
ca.SILENT_CHECK_TEXT =Instal·lació silenciosa
da.SILENT_CHECK_TEXT =Lydløs installation
gl.SILENT_CHECK_TEXT =Instalación silenciosa
hu.SILENT_CHECK_TEXT =Beavatkozás nélküli telepítés
id.SILENT_CHECK_TEXT =Instalasi senyap
no.SILENT_CHECK_TEXT =Stille installering
et.SILENT_CHECK_TEXT =Vaikne paigaldus
lt.SILENT_CHECK_TEXT =Tylus diegimas
hr.SILENT_CHECK_TEXT =Tiha instalacija
hi.SILENT_CHECK_TEXT =मौन इंस्टॉलेशन
sv.SILENT_CHECK_TEXT =Obevakad installation
sr_Cyrl_RS.SILENT_CHECK_TEXT =Тиха инсталација
en.MSG_REPAIR =This will repair the current version of %1.
ru.MSG_REPAIR =Это восстановит текущую версию %1.
en.MSG_UPDATE =This will update %1 to the latest version available.
ru.MSG_UPDATE =Это обновит %1 до последней доступной версии.
en.LABEL_DOWNLOAD =Downloading
ru.LABEL_DOWNLOAD =Загрузка
en.LABEL_INSTALL =Installing
ru.LABEL_INSTALL =Установка
en.LABEL_UPDATING =Updating
ru.LABEL_UPDATING =Обновление
en.LABEL_REPAIRING =Repairing
ru.LABEL_REPAIRING =Восстановление
en.LABEL_UNINSTLING =Uninstalling
ru.LABEL_UNINSTLING =Удаление
en.LABEL_UPDATE_COMPL =Update complete!
ru.LABEL_UPDATE_COMPL =Обновление завершено!
en.LABEL_REPAIR_COMPL =Repairing completed!
ru.LABEL_REPAIR_COMPL =Восстановление завершено!
en.LABEL_UNINST_COMPL =Uninstalling completed!
ru.LABEL_UNINST_COMPL =Удаление завершено!
en.LABEL_VERSION =%1 %2 (%3 %4) is installed
ru.LABEL_VERSION =%1 %2 (%3 %4) установлен
en.LABEL_UNKN_VER =unknown version
ru.LABEL_UNKN_VER =неизвестная версия
en.LABEL_UNKN_PACK =unknown package
ru.LABEL_UNKN_PACK =неизвестный пакет
en.LABEL_NO_OPTIONS =No additional options available.
ru.LABEL_NO_OPTIONS =Дополнительные опции недоступны.
en.LABEL_NO_VER_AVAIL =No version available
ru.LABEL_NO_VER_AVAIL =Нет доступной версии
en.LABEL_WARN_CLOSE =This will install ONLYOFFICE Desktop Editors on your computer.\nIt is reccomended that you close all other applications before continuing.
ru.LABEL_WARN_CLOSE =Программа установит ONLYOFFICE Desktop Editors на ваш компьютер.\nРекомендуется закрыть все прочие приложения перед тем, как продолжить.
en.LABEL_ALMOST_DONE =Just a bit more and we're done
ru.LABEL_ALMOST_DONE =Еще немного и мы закончим
en.LABEL_INSTALL_COMPL =%1 has been successfully installed on your computer.\nTo run the application after closing this installer, select the check box.
ru.LABEL_INSTALL_COMPL =%1 успешно установлен на вашем компьютере.\nЧтобы запустить приложение после закрытия этого установщика, установите флажок.
en.LABEL_ERR_PROD_CODE =Error while retrieving product code.
ru.LABEL_ERR_PROD_CODE =Ошибка при получении кода продукта.
en.LABEL_ERR_PACK_NAME =Error while retrieving package name.
ru.LABEL_ERR_PACK_NAME =Ошибка при получении имени пакета.
en.LABEL_ERR_INSTALL =An error occurred during installation.
ru.LABEL_ERR_INSTALL =Во время установки произошла ошибка.
en.LABEL_ERR_UNINST =An error occurred during uninstalling.
ru.LABEL_ERR_UNINST =Во время удаления произошла ошибка.
en.LABEL_ERR_COMMON =An error occurred:
ru.LABEL_ERR_COMMON =Произошла ошибка:
en.LABEL_ERR_RUNNING =An error occurred while running the package.\nPlease try restarting the app later.
ru.LABEL_ERR_RUNNING =Произошла ошибка при запуске установщика.\nПопробуйте перезапустить приложение позже.
de.LABEL_ERR_RUNNING =Beim Ausführen des Pakets ist ein Fehler aufgetreten.\nBitte versuchen Sie, die App später neu zu starten.
fr.LABEL_ERR_RUNNING =Une erreur s'est produit lors de l'exécution du paquet.\nVeuillez réessayer de redémarrer l'application plus tard.
es.LABEL_ERR_RUNNING =Se ha producido un error al ejecutar el paquete.\nIntente reiniciar la aplicación más tarde.
it.LABEL_ERR_RUNNING =Si è verificato un errore durante l'esecuzione del pacchetto.\nProva a riavviare l'app più tardi.
ja.LABEL_ERR_RUNNING =パッケージの実行中にエラーが発生しました。\nアプリを後で再起動してみてください。
zh_CN.LABEL_ERR_RUNNING =运行软件包时发生错误。\n请稍后尝试重新启动应用程序。
ro.LABEL_ERR_RUNNING =A intervenit o eroare în timpul executării pachetului.\nÎncercaţi să reporniți aplicația mai târziu.
ar_SA.LABEL_ERR_RUNNING =حدث خطأ أثناء تشغيل الحزمة.\nالرجاء محاولة إعادة تشغيل التطبيق لاحقا.
bg.LABEL_ERR_RUNNING =Възникна грешка при стартиране на пакета.\nМоля, опитайте да рестартирате приложението по-късно.
cs.LABEL_ERR_RUNNING =Při spouštění balíčku došlo k chybě.\nProsím, zkuste aplikaci restartovat později.
el.LABEL_ERR_RUNNING =Προέκυψε σφάλμα κατά την εκτέλεση του πακέτου.\nΔοκιμάστε να επανεκκινήσετε την εφαρμογή αργότερα.
fi.LABEL_ERR_RUNNING =Paketin suorittamisen aikana tapahtui virhe. \nOle hyvä ja yritä käynnistää sovellus myöhemmin uudelleen.
hy.LABEL_ERR_RUNNING =Փաթեթը գործարկելիս սխալ է տեղի ունեցել.\nՓորձեք ավելի ուշ վերագործարկել հավելվածը:
ko.LABEL_ERR_RUNNING =패키지를 실행하는 동안 오류가 발생했습니다.\n나중에 앱을 다시 시작하세요.
lv.LABEL_ERR_RUNNING =Palaižot pakotni, radās kļūda.\nMēģiniet restartēt lietotni vēlāk.
nl.LABEL_ERR_RUNNING =Er is een fout opgetreden tijdens het uitvoeren van het pakket.\Probeer de app later opnieuw te starten.
pl.LABEL_ERR_RUNNING =Wystąpił błąd podczas uruchamiania pakietu.\nSpróbuj ponownie uruchomić aplikację później.
pt_PT.LABEL_ERR_RUNNING =Ocorreu um erro ao executar o pacote.\nTente reiniciar o aplicativo mais tarde.
sk.LABEL_ERR_RUNNING =Počas spúšťania balíka došlo k chybe.\nProsím, skúste reštartovať aplikáciu neskôr.
sl.LABEL_ERR_RUNNING =Med izvajanjem paketa je prišlo do napake.\nPoskusite znova zagnati aplikacijo pozneje.
tr.LABEL_ERR_RUNNING =Paket çalıştırılırken bir hata oluştu.\nLütfen uygulamayı daha sonra yeniden başlatmayı deneyin.
uk.LABEL_ERR_RUNNING =Під час запуску пакету сталася помилка. \nСпробуйте перезапустити застосунок пізніше.
vi.LABEL_ERR_RUNNING =Đã xảy ra lỗi khi chạy gói.\nVui lòng thử khởi động lại ứng dụng sau.
sr_Latn_RS.LABEL_ERR_RUNNING =Došlo je do greške prilikom pokretanja paketa.\nMolimo pokušajte da restartujete aplikaciju kasnije.
si.LABEL_ERR_RUNNING =ඇසුරුම ධාවනයේ දී දෝෂයක් සිදු විය.\nකරුණාකර මෘදුකාංගය නැවත ආරම්භ කර බලන්න.
be.LABEL_ERR_RUNNING =Падчас запуску пакета адбылася памылка.\nПаспрабуйце перазапусціць прыкладанне пазней.
ca.LABEL_ERR_RUNNING =S'ha produït un error en executar el paquet.\nProveu de reiniciar l'aplicació més tard.
da.LABEL_ERR_RUNNING =Der opstod en fejl under drift af pakken.\nPrøv venligst at genstarte appen senere.
gl.LABEL_ERR_RUNNING =Produciuse un erro ao executar o paquete.\nPor favor, tente reiniciar a aplicación máis tarde.
hu.LABEL_ERR_RUNNING =Hiba történt a csomag futtatása közben.\nKérjük, próbálja meg később újraindítani az alkalmazást.
id.LABEL_ERR_RUNNING =Ada kesalahan saat menjalankan paket.\nMohon restart app lagi nanti.
no.LABEL_ERR_RUNNING =Det oppstod en feil under kjøring av pakken.\nVennligst prøv å starte appen på nytt senere.
et.LABEL_ERR_RUNNING =Paketi käivitamisel tekkis viga.\nPalun proovige rakenduse taaskäivitamist hiljem.
lt.LABEL_ERR_RUNNING =Paleidus paketą, įvyko klaida.\nPabandykite kiek vėliau iš naujo paleisti programą.
hr.LABEL_ERR_RUNNING =Došlo je do pogreške prilikom pokretanja paketa.\nPokušajte ponovno pokrenuti aplikaciju kasnije.
hi.LABEL_ERR_RUNNING =पैकेज चलाने के दौरान एक त्रुटि उत्पन्न हुई।\nकृपया बाद में ऐप को रीस्टार्ट करने का प्रयास करें।
sv.LABEL_ERR_RUNNING =Ett fel inträffade vid körning av paketet.\nFörsök starta om appen senare.
sr_Cyrl_RS.LABEL_ERR_RUNNING =Дошло је до грешке приликом покретања пакета.\nМолимо покушајте да рестартујете апликацију касније.
en.LABEL_ERR_CANCELLED =Cancelled!
ru.LABEL_ERR_CANCELLED =Отменено!
en.BUTTON_INSTALL =Install
ru.BUTTON_INSTALL =Установить
en.BUTTON_CANCEL =Cancel
ru.BUTTON_CANCEL =Отмена
de.BUTTON_CANCEL =Abbrechen
fr.BUTTON_CANCEL =Annuler
es.BUTTON_CANCEL =Cancelar
it.BUTTON_CANCEL =Annulla
ja.BUTTON_CANCEL =キャンセル
zh_CN.BUTTON_CANCEL =取消
ro.BUTTON_CANCEL =Anulare
ar_SA.BUTTON_CANCEL =إلغاء
bg.BUTTON_CANCEL =Отказ
cs.BUTTON_CANCEL =Zrušit
el.BUTTON_CANCEL =Ακύρωση
fi.BUTTON_CANCEL =Peruuta
hy.BUTTON_CANCEL =Չեղարկել
ko.BUTTON_CANCEL =취소
lv.BUTTON_CANCEL =Atcelt
nl.BUTTON_CANCEL =Annuleren
pl.BUTTON_CANCEL =Anuluj
pt_PT.BUTTON_CANCEL =Cancelar
sk.BUTTON_CANCEL =Zrušiť
sl.BUTTON_CANCEL =Prekliči
tr.BUTTON_CANCEL =İptal
uk.BUTTON_CANCEL =Скасувати
vi.BUTTON_CANCEL =Hủy
sr_Latn_RS.BUTTON_CANCEL =Otkaži
si.BUTTON_CANCEL =අවලංගු
be.BUTTON_CANCEL =Адмяніць
ca.BUTTON_CANCEL =Cancel·lar
da.BUTTON_CANCEL =Annuller
gl.BUTTON_CANCEL =Cancelar
hu.BUTTON_CANCEL =Törlés
id.BUTTON_CANCEL =Batal
no.BUTTON_CANCEL =Avbryt
et.BUTTON_CANCEL =Tühista
lt.BUTTON_CANCEL =Atšaukti
hr.BUTTON_CANCEL =Otkaži
hi.BUTTON_CANCEL =रद्द करें
sv.BUTTON_CANCEL =Avbryt
sr_Cyrl_RS.BUTTON_CANCEL =Откажи
en.BUTTON_APPLY =Apply
ru.BUTTON_APPLY =Применить
en.BUTTON_CLOSE =Close
ru.BUTTON_CLOSE =Закрыть
en.BUTTON_BACK =Back
ru.BUTTON_BACK =Назад
en.RADIO_UPDATE =Update
ru.RADIO_UPDATE =Обновить
en.RADIO_REPAIR =Repair
ru.RADIO_REPAIR =Восстановить
en.RADIO_UNINST =Uninstall
ru.RADIO_UNINST =Удалить
en.CHECK_SILENT =Silent Installation
ru.CHECK_SILENT =Тихая установка
de.CHECK_SILENT =Silent Installation
fr.CHECK_SILENT =Installation sans assistance
es.CHECK_SILENT =Instalación silenciosa
it.CHECK_SILENT =Installazione silenziosa
ja.CHECK_SILENT =サイレントインストール
zh_CN.CHECK_SILENT =静默安装
ro.CHECK_SILENT =Instalare nesupravegheată
ar_SA.CHECK_SILENT =التثبيت الصامت
bg.CHECK_SILENT =Тихо инсталиране
cs.CHECK_SILENT =Tichá instalace
el.CHECK_SILENT =Αθόρυβη εγκατάσταση
fi.CHECK_SILENT =Äänetön asennus
hy.CHECK_SILENT =Լուռ տեղադրում
ko.CHECK_SILENT =비대화형 방식 설치
lv.CHECK_SILENT =Klusā instalēšana
nl.CHECK_SILENT =Stille installatie
pl.CHECK_SILENT =Instalacja dyskretna
pt_PT.CHECK_SILENT =Instalação silenciosa
sk.CHECK_SILENT =Tichá inštalácia
sl.CHECK_SILENT =Tiha namestitev
tr.CHECK_SILENT =Sessiz Kurulum
uk.CHECK_SILENT =Автоматичне інсталювання
vi.CHECK_SILENT =Cài đặt im lặng
sr_Latn_RS.CHECK_SILENT =Tiha instalacija
si.CHECK_SILENT =නිහඬ ස්ථාපනය
be.CHECK_SILENT =Ціхая ўстаноўка
ca.CHECK_SILENT =Instal·lació silenciosa
da.CHECK_SILENT =Lydløs installation
gl.CHECK_SILENT =Instalación silenciosa
hu.CHECK_SILENT =Beavatkozás nélküli telepítés
id.CHECK_SILENT =Instalasi senyap
no.CHECK_SILENT =Stille installering
et.CHECK_SILENT =Vaikne paigaldus
lt.CHECK_SILENT =Tylus diegimas
hr.CHECK_SILENT =Tiha instalacija
hi.CHECK_SILENT =मौन इंस्टॉलेशन
sv.CHECK_SILENT =Obevakad installation
sr_Cyrl_RS.CHECK_SILENT =Тиха инсталација
en.CHECK_LAUNCH =Launch
ru.CHECK_LAUNCH =Запустить
en.CHECK_CLR_DATA =Clear cached data
ru.CHECK_CLR_DATA =Очистить кэшированные данные
en.CHECK_CLR_STNGS =Clear user settings
ru.CHECK_CLR_STNGS =Очистить пользовательские настройки
en.CHECK_CLR_ALL =Clear user settings and cached data
ru.CHECK_CLR_ALL =Очистить пользовательские настройки и кэшированные данные

View File

@ -0,0 +1,37 @@
#pragma code_page(65001)
#include <Windows.h>
#include "../src/version.h"
#include "../src/resource.h"
IDI_MAINICON ICON DISCARDABLE APP_ICON_PATH
IDI_WELCOME PNG "./icons/welcome.png"
IDT_TRANSLATIONS RCDATA APP_LANG_PATH
CREATEPROCESS_MANIFEST_RESOURCE_ID RT_MANIFEST "./manifest/online-installer.exe.manifest"
VS_VERSION_INFO VERSIONINFO
FILEVERSION VER_FILEVERSION
PRODUCTVERSION VER_PRODUCTVERSION
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK VER_LANG_AND_CHARSET_STR
BEGIN
VALUE "CompanyName", VER_COMPANYNAME_STR
VALUE "FileDescription", VER_FILEDESCRIPTION_STR
VALUE "FileVersion", VER_FILEVERSION_STR
VALUE "InternalName", VER_INTERNALNAME_STR
VALUE "LegalCopyright", VER_LEGALCOPYRIGHT_STR
VALUE "LegalTrademarks1", VER_LEGALTRADEMARKS1_STR
VALUE "LegalTrademarks2", VER_LEGALTRADEMARKS2_STR
VALUE "OriginalFilename", VER_ORIGINALFILENAME_STR
VALUE "ProductName", VER_PRODUCTNAME_STR
VALUE "ProductVersion", VER_PRODUCTVERSION_STR
END
END
BLOCK "VarFileInfo"
BEGIN
VALUE "Translation", VER_LANG_ID, VER_CHARSET_ID
END
END

View File

@ -33,17 +33,19 @@
#include "cdownloader.h"
#include <Windows.h>
#include <Winhttp.h>
#define DNL_OK 0
#define DNL_ABORT 1
#define DNL_URL_ERR 2
#define DNL_CONN_ERR 3
#define DNL_OUT_MEM 4
#define DNL_CREAT_ERR 5
#define DNL_OTHER_ERR 6
#include <future>
int downloadToFile(const wstring &url, const wstring &filePath, std::atomic_bool &run, FnVoidInt &progress_callback)
struct Connection {
~Connection() {
if (hRequest) WinHttpCloseHandle(hRequest);
if (hConnect) WinHttpCloseHandle(hConnect);
if (hSession) WinHttpCloseHandle(hSession);
}
HINTERNET hSession = NULL, hConnect = NULL, hRequest = NULL;
};
static DWORD initConnection(const wstring &url, DWORD &dwFileSize, Connection &conn)
{
URL_COMPONENTS urlComp;
ZeroMemory(&urlComp, sizeof(urlComp));
@ -51,176 +53,208 @@ int downloadToFile(const wstring &url, const wstring &filePath, std::atomic_bool
urlComp.dwHostNameLength = 1;
urlComp.dwUrlPathLength = 1;
if (!WinHttpCrackUrl(url.c_str(), (DWORD)url.length(), 0, &urlComp))
return DNL_URL_ERR;
return GetLastError();
wstring url_host(urlComp.lpszHostName, urlComp.dwHostNameLength);
wstring url_path(urlComp.lpszUrlPath, urlComp.dwUrlPathLength);
int prev_percent = -1;
DWORD dwProgress = 0;
DWORD dwProgressMax = 0;
DWORD dwSize = sizeof(DWORD);
HANDLE hFile = INVALID_HANDLE_VALUE;
conn.hSession = WinHttpOpen(L"WinHTTP Example/1.0", WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, WINHTTP_NO_PROXY_NAME, WINHTTP_NO_PROXY_BYPASS, 0);
if (!conn.hSession)
return GetLastError();
HINTERNET hSession = WinHttpOpen(L"WinHTTP Example/1.0", WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, WINHTTP_NO_PROXY_NAME, WINHTTP_NO_PROXY_BYPASS, 0);
if (!hSession)
return DNL_OTHER_ERR;
//WinHttpSetStatusCallback(hSession, WinHttpCallback, WINHTTP_CALLBACK_FLAG_ALL_NOTIFICATIONS, 0);
DWORD dwEnabledProtocols = WINHTTP_FLAG_SECURE_PROTOCOL_TLS1 | WINHTTP_FLAG_SECURE_PROTOCOL_TLS1_1 | WINHTTP_FLAG_SECURE_PROTOCOL_TLS1_2;
WinHttpSetOption(hSession, WINHTTP_OPTION_SECURE_PROTOCOLS, &dwEnabledProtocols, sizeof(DWORD));
WinHttpSetOption(conn.hSession, WINHTTP_OPTION_SECURE_PROTOCOLS, &dwEnabledProtocols, sizeof(DWORD));
HINTERNET hConnect = WinHttpConnect(hSession, url_host.c_str(), INTERNET_DEFAULT_HTTPS_PORT, 0);
if (!hConnect) {
WinHttpCloseHandle(hSession);
return DNL_CONN_ERR;
}
#ifdef IGNORE_CERTIFICATE_REQUIREMENTS
DWORD dwSecurity = SECURITY_FLAG_IGNORE_UNKNOWN_CA | SECURITY_FLAG_IGNORE_CERT_CN_INVALID | SECURITY_FLAG_IGNORE_CERT_DATE_INVALID;
WinHttpSetOption(conn.hSession, WINHTTP_OPTION_SECURITY_FLAGS, &dwSecurity, sizeof(DWORD));
#endif
HINTERNET hRequest = WinHttpOpenRequest(hConnect, L"GET", url_path.c_str(), NULL, WINHTTP_NO_REFERER, WINHTTP_DEFAULT_ACCEPT_TYPES, WINHTTP_FLAG_SECURE);
if (!hRequest) {
WinHttpCloseHandle(hConnect);
WinHttpCloseHandle(hSession);
return DNL_CONN_ERR;
}
conn.hConnect = WinHttpConnect(conn.hSession, url_host.c_str(), INTERNET_DEFAULT_HTTPS_PORT, 0);
if (!conn.hConnect)
return GetLastError();
int result = DNL_OK;
if (!WinHttpSendRequest(hRequest, WINHTTP_NO_ADDITIONAL_HEADERS, 0, WINHTTP_NO_REQUEST_DATA, 0, 0, 0)) {
result = DNL_OTHER_ERR;
goto cleanup;
}
conn.hRequest = WinHttpOpenRequest(conn.hConnect, L"GET", url_path.c_str(), NULL, WINHTTP_NO_REFERER, WINHTTP_DEFAULT_ACCEPT_TYPES, WINHTTP_FLAG_SECURE);
if (!conn.hRequest)
return GetLastError();
if (!WinHttpReceiveResponse(hRequest, NULL)) {
result = DNL_CONN_ERR;
goto cleanup;
}
if (!WinHttpSendRequest(conn.hRequest, WINHTTP_NO_ADDITIONAL_HEADERS, 0, WINHTTP_NO_REQUEST_DATA, 0, 0, 0))
return GetLastError();
if (!WinHttpQueryHeaders(hRequest, WINHTTP_QUERY_CONTENT_LENGTH | WINHTTP_QUERY_FLAG_NUMBER, NULL, &dwProgressMax, &dwSize, WINHTTP_NO_HEADER_INDEX)) {
result = DNL_CONN_ERR;
goto cleanup;
}
if (!WinHttpReceiveResponse(conn.hRequest, NULL))
return GetLastError();
hFile = CreateFile(filePath.c_str(), GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (hFile == INVALID_HANDLE_VALUE) {
result = DNL_CREAT_ERR;
goto cleanup;
}
DWORD dwSize = sizeof(DWORD);
if (!WinHttpQueryHeaders(conn.hRequest, WINHTTP_QUERY_CONTENT_LENGTH | WINHTTP_QUERY_FLAG_NUMBER, NULL, &dwFileSize, &dwSize, WINHTTP_NO_HEADER_INDEX))
return GetLastError();
do {
if (!run) {
result = DNL_ABORT;
break;
}
dwSize = 0;
if (!WinHttpQueryDataAvailable(hRequest, &dwSize)) {
result = DNL_CONN_ERR;
break;
}
LPSTR lpBuffer = new char[dwSize];
if (!lpBuffer) {
result = DNL_OUT_MEM;
break;
}
DWORD dwDownloaded = 0;
if (!WinHttpReadData(hRequest, (LPVOID)lpBuffer, dwSize, &dwDownloaded)) {
result = DNL_CONN_ERR;
delete[] lpBuffer;
break;
}
DWORD dwBytesWritten = 0;
BOOL write_res = WriteFile(hFile, lpBuffer, dwDownloaded, &dwBytesWritten, NULL);
delete[] lpBuffer;
if (!write_res || dwBytesWritten != dwDownloaded) {
result = DNL_OUT_MEM;
break;
}
if (dwProgressMax != 0 && progress_callback) {
dwProgress += dwDownloaded;
int percent = static_cast<int>((100.0 * dwProgress) / dwProgressMax);
if (percent != prev_percent) {
progress_callback(percent);
prev_percent = percent;
}
}
} while (dwSize > 0);
cleanup :
if (hFile != INVALID_HANDLE_VALUE) {
CloseHandle(hFile);
if (result == DNL_ABORT)
DeleteFile(filePath.c_str());
}
WinHttpCloseHandle(hRequest);
WinHttpCloseHandle(hConnect);
WinHttpCloseHandle(hSession);
return result;
return ERROR_SUCCESS;
}
CDownloader::CDownloader()
class CDownloaderPrivate
{
m_run = true;
m_lock = false;
public:
CDownloaderPrivate()
{}
~CDownloaderPrivate()
{}
DWORD downloadToFile()
{
DWORD dwSize = 0, dwProgress = 0, dwProgressMax = 0;
Connection conn;
DWORD result = initConnection(m_url, dwProgressMax, conn);
if (result != ERROR_SUCCESS)
return result;
HANDLE hFile = CreateFile(m_filePath.c_str(), GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (hFile == INVALID_HANDLE_VALUE)
return GetLastError();
int prev_percent = -1;
do {
if (!m_run) {
result = ERROR_CANCELLED;
break;
}
dwSize = 0;
if (!WinHttpQueryDataAvailable(conn.hRequest, &dwSize)) {
result = GetLastError();
break;
}
LPSTR lpBuffer = new char[dwSize];
if (!lpBuffer) {
result = ERROR_NOT_ENOUGH_MEMORY;
break;
}
DWORD dwDownloaded = 0;
if (!WinHttpReadData(conn.hRequest, (LPVOID)lpBuffer, dwSize, &dwDownloaded)) {
result = GetLastError();
delete[] lpBuffer;
break;
}
DWORD dwBytesWritten = 0;
BOOL write_res = WriteFile(hFile, lpBuffer, dwDownloaded, &dwBytesWritten, NULL);
delete[] lpBuffer;
if (!write_res) {
result = GetLastError();
break;
}
if (dwBytesWritten != dwDownloaded) {
result = ERROR_OUTOFMEMORY;
break;
}
if (dwProgressMax != 0 && m_progress_callback) {
dwProgress += dwDownloaded;
int percent = static_cast<int>((100.0 * dwProgress) / dwProgressMax);
if (percent != prev_percent) {
m_progress_callback(percent);
prev_percent = percent;
}
}
} while (dwSize > 0);
CloseHandle(hFile);
if (result == ERROR_CANCELLED)
DeleteFile(m_filePath.c_str());
return result;
}
FnVoidUlUl m_query_callback = nullptr;
FnVoidUl m_complete_callback = nullptr;
FnVoidInt m_progress_callback = nullptr;
wstring m_url,
m_filePath;
std::future<void> m_future;
std::atomic_bool m_run,
m_lock;
};
CDownloader::CDownloader() :
pimpl(new CDownloaderPrivate)
{
pimpl->m_run = true;
pimpl->m_lock = false;
}
CDownloader::~CDownloader()
{
m_run = false;
if (m_future.valid())
m_future.wait();
pimpl->m_run = false;
if (pimpl->m_future.valid())
pimpl->m_future.wait();
delete pimpl, pimpl = nullptr;
}
void CDownloader::queryContentLenght(const wstring &url)
{
if (url.empty() || pimpl->m_lock)
return;
pimpl->m_lock = true;
pimpl->m_future = std::async(std::launch::async, [=]() {
DWORD dwFileSize = 0;
Connection conn;
DWORD error = initConnection(url, dwFileSize, conn);
if (pimpl->m_query_callback)
pimpl->m_query_callback(error, dwFileSize);
pimpl->m_lock = false;
});
}
void CDownloader::downloadFile(const std::wstring &url, const std::wstring &filePath)
{
m_url.clear();
m_filePath.clear();
if (url.empty() || filePath.empty() || m_lock)
pimpl->m_url.clear();
pimpl->m_filePath.clear();
if (url.empty() || filePath.empty() || pimpl->m_lock)
return;
m_url = url;
m_filePath = filePath;
pimpl->m_url = url;
pimpl->m_filePath = filePath;
start();
}
void CDownloader::start()
{
if (m_url.empty() || m_filePath.empty() || m_lock)
if (pimpl->m_url.empty() || pimpl->m_filePath.empty() || pimpl->m_lock)
return;
m_run = true;
m_lock = true;
m_future = std::async(std::launch::async, [=]() {
int hr = downloadToFile(m_url, m_filePath, m_run, m_progress_callback);
int error = (hr == DNL_OK) ? 0 :
(hr == DNL_ABORT) ? 1 :
(hr == DNL_OUT_MEM) ? -1 :
(hr == DNL_CONN_ERR) ? -2 : -3;
if (m_complete_callback)
m_complete_callback(error);
m_lock = false;
pimpl->m_run = true;
pimpl->m_lock = true;
pimpl->m_future = std::async(std::launch::async, [=]() {
DWORD error = pimpl->downloadToFile();
if (pimpl->m_complete_callback)
pimpl->m_complete_callback(error);
pimpl->m_lock = false;
});
}
void CDownloader::stop()
{
m_run = false;
pimpl->m_run = false;
}
wstring CDownloader::GetFilePath()
{
return m_filePath;
return pimpl->m_filePath;
}
void CDownloader::onComplete(FnVoidInt callback)
void CDownloader::onQueryResponse(FnVoidUlUl callback)
{
m_complete_callback = callback;
pimpl->m_query_callback = callback;
}
void CDownloader::onComplete(FnVoidUl callback)
{
pimpl->m_complete_callback = callback;
}
void CDownloader::onProgress(FnVoidInt callback)
{
m_progress_callback = callback;
pimpl->m_progress_callback = callback;
}

View File

@ -35,35 +35,36 @@
#include <string>
#include <functional>
#include <future>
typedef unsigned long ulong;
typedef std::function<void(int)> FnVoidInt;
typedef std::function<void(ulong)> FnVoidUl;
typedef std::function<void(ulong,ulong)> FnVoidUlUl;
using std::wstring;
class CDownloaderPrivate;
class CDownloader
{
public:
CDownloader();
~CDownloader();
void queryContentLenght(const wstring &url);
void downloadFile(const wstring &url, const wstring &filePath);
void start();
void stop();
wstring GetFilePath();
/* callback */
void onComplete(FnVoidInt callback);
void onQueryResponse(FnVoidUlUl callback);
void onComplete(FnVoidUl callback);
void onProgress(FnVoidInt callback);
private:
FnVoidInt m_complete_callback = nullptr,
m_progress_callback = nullptr;
wstring m_url,
m_filePath;
std::future<void> m_future;
std::atomic_bool m_run,
m_lock;
CDownloaderPrivate *pimpl = nullptr;
};
#endif // CDOWNLOADER_H

View File

@ -1,10 +1,10 @@
#include <Windows.h>
#include <CommCtrl.h>
#include "application.h"
#include "mainwindow.h"
#include <locale>
#include "resource.h"
#include "utils.h"
#include "baseutils.h"
#include "translator.h"
#include "cdownloader.h"
#include "../../src/defines.h"
#include "../../src/prop/defines_p.h"
@ -20,33 +20,19 @@
#ifndef URL_INSTALL_X86_XP
# define URL_INSTALL_X86_XP ""
#endif
#ifndef URL_INSTALL_X64_MSI
# define URL_INSTALL_X64_MSI ""
#endif
#ifndef URL_INSTALL_X86_MSI
# define URL_INSTALL_X86_MSI ""
#endif
#define _TR(str) Translator::tr(str).c_str()
#define WINDOW_SIZE Size(768, 480)
HANDLE hIcon = NULL;
struct UserData
{
CDownloader *dnl = nullptr;
wstring *url = nullptr;
wstring *file_name = nullptr;
};
void startDownloadAndInstall(HWND hDlg, UserData *data);
INT_PTR CALLBACK DialogProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
int WINAPI _tWinMain(_In_ HINSTANCE hInst, _In_opt_ HINSTANCE hPrevInstance, _In_ LPTSTR lpCmdLine, _In_ int nCmdShow)
{
UNREFERENCED_PARAMETER(hPrevInstance);
std::locale::global(std::locale(""));
LCID lcid = MAKELCID(GetUserDefaultUILanguage(), SORT_DEFAULT);
Translator lang(lcid, IDT_TRANSLATIONS);
HANDLE hMutex = CreateMutex(NULL, FALSE, _T(VER_PRODUCTNAME_STR));
if (GetLastError() == ERROR_ALREADY_EXISTS) {
NS_Utils::ShowMessage(_TR(MESSAGE_TEXT_ERR2));
return 0;
}
int num_args = 0;
if (LPTSTR *args = CommandLineToArgvW(lpCmdLine, &num_args)) {
for (int i = 0; i < num_args; i++) {
@ -56,185 +42,50 @@ int WINAPI _tWinMain(_In_ HINSTANCE hInst, _In_opt_ HINSTANCE hPrevInstance, _In
}
}
LocalFree(args);
}
SYSTEM_INFO info;
GetSystemInfo(&info);
wstring url, fileName(_T(REG_APP_NAME));
WinVer ver = NS_File::getWinVersion();
if (info.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64) {
url = (ver == WinVer::WinXP) ? _T(URL_INSTALL_X64_XP) : _T(URL_INSTALL_X64);
fileName += (ver == WinVer::WinXP) ? _T("_x64_xp.exe") : _T("_x64.exe");
} else
if (info.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_INTEL) {
url = (ver == WinVer::WinXP) ? _T(URL_INSTALL_X86_XP) : _T(URL_INSTALL_X86);
fileName += (ver == WinVer::WinXP) ? _T("_x86_xp.exe") : _T("_x86.exe");
} else {
NS_Utils::ShowMessage(_TR(MESSAGE_TEXT_ERR1));
}
std::locale::global(std::locale(""));
LCID lcid = MAKELCID(GetUserDefaultUILanguage(), SORT_DEFAULT);
Translator lang(lcid, IDT_TRANSLATIONS);
HANDLE hMutex = CreateMutex(NULL, FALSE, _T(VER_PRODUCTNAME_STR));
if (GetLastError() == ERROR_ALREADY_EXISTS) {
NS_Utils::ShowMessage(_TR(MSG_ERR_ALREADY_RUNNING));
return 0;
}
CDownloader dnl;
UserData data;
data.dnl = &dnl;
data.url = &url;
data.file_name = &fileName;
InitCommonControls();
HWND hDlg = CreateDialogParam(hInst, MAKEINTRESOURCE(NS_Utils::IsRtlLanguage(lcid) ? IDD_DIALOG_RTL : IDD_DIALOG), NULL, DialogProc, (LPARAM)&data);
ShowWindow(hDlg, nCmdShow);
BOOL ret;
MSG msg = {0};
while ((ret = GetMessage(&msg, hDlg, 0, 0)) != 0) {
if (ret == -1)
break;
if (IsDialogMessage(hDlg, &msg)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
CloseHandle(hMutex);
return (int)msg.wParam;
}
void startDownloadAndInstall(HWND hDlg, UserData *data)
{
HWND hLabelMsg = GetDlgItem(hDlg, IDC_LABEL_MESSAGE);
if (hLabelMsg)
SetWindowText(hLabelMsg, _TR(LABEL_MESSAGE_TEXT));
HWND hCheckSilent = GetDlgItem(hDlg, IDC_SILENT_CHECK);
if (hCheckSilent) {
wstring text(_T(" "));
text.append(_TR(SILENT_CHECK_TEXT));
SetWindowText(hCheckSilent, text.c_str());
if (HWND hWnd = FindWindow(WINDOW_CLASS_NAME, NULL)) {
wstring msg(_TR(MSG_ERR_CLOSE_APP));
NS_Utils::Replace(msg, L"%1", _T(WINDOW_NAME));
NS_Utils::ShowMessage(msg);
return 0;
}
if (!data) {
if (hLabelMsg)
SetWindowText(hLabelMsg, _TR(LABEL_MESSAGE_TEXT_ERR1));
return;
}
if (data->url->empty()) {
if (hLabelMsg)
SetWindowText(hLabelMsg, _TR(LABEL_MESSAGE_TEXT_ERR6));
return;
}
if (data->file_name->empty()) {
if (hLabelMsg)
SetWindowText(hLabelMsg, _TR(LABEL_MESSAGE_TEXT_ERR7));
return;
}
wstring msgText;
if (hLabelMsg) {
int len = GetWindowTextLength(hLabelMsg);
if (len > 0) {
LPTSTR buff = (LPTSTR)malloc((len + 1) * sizeof(TCHAR));
if (buff) {
GetWindowText(hLabelMsg, buff, len + 1);
msgText = buff;
free(buff);
}
}
msgText += _T(" ") + (*data->file_name);
SetWindowText(hLabelMsg, msgText.c_str());
}
wstring path = NS_File::appPath() + _T("/") + (*data->file_name);
HWND hProgress = GetDlgItem(hDlg, IDC_PROGRESS);
data->dnl->onProgress([=](int percent) {
if (IsWindow(hProgress))
PostMessage(hProgress, PBM_SETPOS, percent, 0);
});
data->dnl->onComplete([=](int error) {
if (error == 0) {
if (IsWindow(hDlg))
ShowWindow(hDlg, SW_HIDE);
wstring args;
if (IsWindow(hCheckSilent)) {
LRESULT isChecked = SendMessage(hCheckSilent, BM_GETCHECK, 0, 0);
if (isChecked == BST_CHECKED)
args = _T("/SILENT");
}
if (!NS_File::runProcess(path, args)) {
if (IsWindow(hDlg))
ShowWindow(hDlg, SW_SHOW);
if (IsWindow(hLabelMsg))
SetWindowText(hLabelMsg, _TR(LABEL_MESSAGE_TEXT_ERR5));
} else {
if (IsWindow(hDlg))
PostMessage(hDlg, WM_CLOSE, 0, 0);
}
if (NS_File::fileExists(path))
NS_File::removeFile(path);
} else
if (error == -1) {
if (IsWindow(hLabelMsg))
SetWindowText(hLabelMsg, _TR(LABEL_MESSAGE_TEXT_ERR2));
} else
if (error == -2) {
if (IsWindow(hLabelMsg))
SetWindowText(hLabelMsg, _TR(LABEL_MESSAGE_TEXT_ERR3));
wstring url_or_path, arch;
bool app_installed = NS_Utils::IsAppInstalled(url_or_path, &arch);
if (!app_installed) {
if (NS_Utils::IsWin64()) {
url_or_path = (Utils::getWinVersion() <= Utils::WinVer::WinVista) ? _T(URL_INSTALL_X64_XP) : _T(URL_INSTALL_X64);
} else {
if (IsWindow(hLabelMsg))
SetWindowText(hLabelMsg, _TR(LABEL_MESSAGE_TEXT_ERR4));
url_or_path = (Utils::getWinVersion() <= Utils::WinVer::WinVista) ? _T(URL_INSTALL_X86_XP) : _T(URL_INSTALL_X86);
}
}
Application app(hInst, lpCmdLine, nCmdShow);
if (NS_Utils::IsRtlLanguage(lcid))
app.setLayoutDirection(LayoutDirection::RightToLeft);
int scrWidth = GetSystemMetrics(SM_CXSCREEN);
int scrHeight = GetSystemMetrics(SM_CYSCREEN);
int x = (scrWidth - WINDOW_SIZE.width) / 2;
int y = (scrHeight - WINDOW_SIZE.height) / 2;
MainWindow w(nullptr, Rect(x, y, WINDOW_SIZE.width, WINDOW_SIZE.height));
w.onAboutToDestroy([&app]() {
app.exit(0);
});
data->dnl->downloadFile(*data->url, path);
}
INT_PTR CALLBACK DialogProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_INITDIALOG: {
wstring text(_T(" "));
text.append(_TR(CAPTION_TEXT));
SetWindowText(hDlg, text.c_str());
HWND hwndIcon = GetDlgItem(hDlg, IDC_MAIN_ICON);
hIcon = LoadImage(GetModuleHandle(NULL), MAKEINTRESOURCE(IDI_MAINICON), IMAGE_ICON, 64, 64, LR_DEFAULTCOLOR | LR_LOADTRANSPARENT);
if (hIcon && hwndIcon)
PostMessage(hwndIcon, STM_SETIMAGE, IMAGE_ICON, (LPARAM)hIcon);
HWND hLabelTitle = GetDlgItem(hDlg, IDC_LABEL_TITLE);
if (hLabelTitle)
SetWindowText(hLabelTitle, _TR(LABEL_TITLE_TEXT));
HWND hBtnCancel = GetDlgItem(hDlg, IDC_BUTTON_CANCEL);
if (hBtnCancel)
SetWindowText(hBtnCancel, _TR(BUTTON_CANCEL_TEXT));
startDownloadAndInstall(hDlg, (UserData*)lParam);
return TRUE;
}
case WM_COMMAND:
switch (LOWORD(wParam)) {
case IDC_BUTTON_CANCEL:
PostMessage(hDlg, WM_CLOSE, 0, 0);
return TRUE;
}
break;
case WM_CLOSE:
if (hIcon)
DestroyIcon((HICON)hIcon);
DestroyWindow(hDlg);
return TRUE;
case WM_ACTIVATE:
break;
case WM_DESTROY:
PostQuitMessage(0);
return TRUE;
default:
break;
}
return FALSE;
if (!app_installed)
w.initInstallationMode(url_or_path);
else
w.initControlMode(arch);
w.showAll();
int exit_code = app.exec();
CloseHandle(hMutex);
return exit_code;
}

View File

@ -0,0 +1,793 @@
#include "mainwindow.h"
#include "application.h"
#include "utils.h"
#include "checkbox.h"
#include "button.h"
#include "label.h"
#include "boxlayout.h"
#include "radiobutton.h"
#include "progressbar.h"
#include "metrics.h"
#include "palette.h"
#include "caption.h"
#include "resource.h"
#include "translator.h"
#include "cdownloader.h"
#include "baseutils.h"
#include <Msi.h>
#include <ShlObj.h>
#include <Shlwapi.h>
#include "../../src/defines.h"
#include "../../src/prop/defines_p.h"
#ifndef URL_INSTALL_X64
# define URL_INSTALL_X64 ""
#endif
#ifndef URL_INSTALL_X86
# define URL_INSTALL_X86 ""
#endif
#ifndef URL_INSTALL_X64_XP
# define URL_INSTALL_X64_XP ""
#endif
#ifndef URL_INSTALL_X86_XP
# define URL_INSTALL_X86_XP ""
#endif
#ifndef URL_INSTALL_X64_MSI
# define URL_INSTALL_X64_MSI ""
#endif
#ifndef URL_INSTALL_X86_MSI
# define URL_INSTALL_X86_MSI ""
#endif
#define _TR(str) Translator::tr(str).c_str()
template <class T>
static void setSelectorStyle(T *sel) // style for CheckBox and RadioButton
{
sel->metrics()->setMetrics(Metrics::TextMarginLeft, 6);
sel->palette()->setColor(Palette::Text, Palette::Disabled, 0x888888);
sel->palette()->setColor(Palette::Text, Palette::Normal, 0x333333);
sel->palette()->setColor(Palette::Text, Palette::Hover, 0x333333);
sel->palette()->setColor(Palette::Text, Palette::Pressed, 0x333333);
sel->palette()->setColor(Palette::Background, Palette::Disabled, 0xfefefe);
sel->palette()->setColor(Palette::Background, Palette::Normal, 0xfefefe);
sel->palette()->setColor(Palette::Background, Palette::Hover, 0xfefefe);
sel->palette()->setColor(Palette::Background, Palette::Pressed, 0xfefefe);
sel->palette()->setColor(Palette::Primitive, Palette::Disabled, 0x888888);
sel->palette()->setColor(Palette::Primitive, Palette::Normal, 0x333333);
sel->palette()->setColor(Palette::Primitive, Palette::Hover, 0x0055ff);
sel->palette()->setColor(Palette::Primitive, Palette::Pressed, 0x0055ff);
}
static void setButtonStyle(Button *btn)
{
btn->palette()->setColor(Palette::Text, Palette::Disabled, 0x888888);
btn->palette()->setColor(Palette::Text, Palette::Normal, 0x333333);
btn->palette()->setColor(Palette::Text, Palette::Hover, 0x333333);
btn->palette()->setColor(Palette::Text, Palette::Pressed, 0x333333);
btn->palette()->setColor(Palette::Background, Palette::Disabled, 0xeeeeee);
btn->palette()->setColor(Palette::Background, Palette::Normal, 0xeeeeee);
btn->palette()->setColor(Palette::Background, Palette::Hover, 0xe0e0e0);
btn->palette()->setColor(Palette::Background, Palette::Pressed, 0xd0d0d0);
btn->palette()->setColor(Palette::Border, Palette::Disabled, 0xbebebe);
btn->palette()->setColor(Palette::Border, Palette::Normal, 0xbebebe);
btn->palette()->setColor(Palette::Border, Palette::Hover, 0xbebebe);
btn->palette()->setColor(Palette::Border, Palette::Pressed, 0xbebebe);
btn->metrics()->setMetrics(Metrics::BorderWidth, 1);
}
static void setProgressStyle(ProgressBar *bar)
{
bar->palette()->setColor(Palette::Background, Palette::Normal, 0xfefefe);
bar->palette()->setColor(Palette::Base, Palette::Normal, 0xcccccc);
bar->palette()->setColor(Palette::AlternateBase, Palette::Normal, 0x1e7aaa);
}
static void setLabelStyle(Label *lb)
{
lb->palette()->setColor(Palette::Background, Palette::Normal, 0xfefefe);
lb->palette()->setColor(Palette::Text, Palette::Normal, 0x888888);
}
static void setControlLabelStyle(Label *lb)
{
lb->resize(50, 36);
lb->palette()->setColor(Palette::Background, Palette::Normal, 0xfefefe);
lb->palette()->setColor(Palette::Text, Palette::Normal, 0x333333);
lb->metrics()->setMetrics(Metrics::TextAlignment, Metrics::AlignHLeft | Metrics::AlignVTop);
}
MainWindow::MainWindow(Widget *parent, const Rect &rc) :
Window(parent, rc),
m_comntLbl(nullptr),
m_versionLbl(nullptr),
m_comntInfoLbl(nullptr),
m_bar(nullptr),
m_updRadio(nullptr),
m_repRadio(nullptr),
m_uninsRadio(nullptr),
m_cancelBtn(nullptr),
m_mode(Mode::Install),
m_resize_conn(0),
m_checkState(UpdateRadio),
m_is_clear_checked(false),
m_is_sttgs_checked(false),
m_is_checked(false)
{
setWindowTitle(_TR(CAPTION));
setResizable(false);
// setIcon(IDI_MAINICON);
palette()->setColor(Palette::Background, Palette::Normal, 0xfefefe);
palette()->setColor(Palette::Border, Palette::Normal, 0x888888);
if (Utils::getWinVersion() > Utils::WinXP && Utils::getWinVersion() < Utils::Win10)
metrics()->setMetrics(Metrics::BorderWidth, 1);
Widget *cw = new Widget(this);
cw->palette()->setColor(Palette::Background, Palette::Normal, 0xfefefe);
setCentralWidget(cw);
setContentsMargins(0,0,0,0);
BoxLayout *cenVlut = new BoxLayout(BoxLayout::Vertical);
cenVlut->setContentMargins(0, 0, 0, 0);
cenVlut->setSpacing(0);
cw->setLayout(cenVlut);
/* Caption section*/
Widget *topPanel = new Widget(cw);
topPanel->resize(50,28);
topPanel->palette()->setColor(Palette::Background, Palette::Normal, 0xfefefe);
topPanel->setProperty(Widget::HSizeBehavior, Widget::Expanding);
topPanel->setProperty(Widget::VSizeBehavior, Widget::Fixed);
cenVlut->addWidget(topPanel);
BoxLayout *topHlut = new BoxLayout(BoxLayout::Horizontal);
topHlut->setContentMargins(0, 0, 0, 0);
topHlut->setSpacing(0);
topPanel->setLayout(topHlut);
Caption *cap = new Caption(topPanel);
cap->setResizingAvailable(false);
cap->palette()->setColor(Palette::Background, Palette::Normal, 0xfefefe);
cap->metrics()->setMetrics(Metrics::TextMarginLeft, 12);
cap->metrics()->setMetrics(Metrics::TextAlignment, Metrics::AlignHLeft| Metrics::AlignVCenter);
cap->resize(50,28);
cap->setProperty(Widget::HSizeBehavior, Widget::Expanding);
cap->setProperty(Widget::VSizeBehavior, Widget::Fixed);
Button *closeBtn = new Button(topPanel);
closeBtn->resize(40,28);
closeBtn->setProperty(Widget::HSizeBehavior, Widget::Fixed);
closeBtn->setProperty(Widget::VSizeBehavior, Widget::Fixed);
closeBtn->palette()->setColor(Palette::Background, Palette::Normal, 0xfefefe);
closeBtn->palette()->setColor(Palette::Background, Palette::Hover, 0xe81123);
closeBtn->palette()->setColor(Palette::Background, Palette::Pressed, 0x8b0a14);
closeBtn->palette()->setColor(Palette::Background, Palette::Disabled, 0x2b2b2b);
closeBtn->palette()->setColor(Palette::Primitive, Palette::Normal, 0x000000);
closeBtn->metrics()->setMetrics(Metrics::PrimitiveWidth, 1);
closeBtn->setStockIcon(Button::CloseIcon);
closeBtn->setIconSize(10, 10);
closeBtn->onClick([this]() {
close();
});
topHlut->addWidget(cap);
topHlut->addWidget(closeBtn);
/* Central section */
m_cenPanel = new Widget(cw);
m_cenPanel->palette()->setColor(Palette::Background, Palette::Normal, 0xfefefe);
m_cenPanel->setProperty(Widget::HSizeBehavior, Widget::Expanding);
m_cenPanel->setProperty(Widget::VSizeBehavior, Widget::Expanding);
cenVlut->addWidget(m_cenPanel);
m_cenPanelVlut = new BoxLayout(BoxLayout::Vertical);
m_cenPanelVlut->setContentMargins(6, 12, 6, 48);
m_cenPanelVlut->setSpacing(6);
m_cenPanel->setLayout(m_cenPanelVlut);
}
MainWindow::~MainWindow()
{
if (m_future.valid())
m_future.wait();
}
void MainWindow::initInstallationMode(const std::wstring &url)
{
m_mode = Mode::Install;
/* Image section*/
Label *wlcLbl = new Label(m_cenPanel);
wlcLbl->resize(282, 200);
wlcLbl->setImage(IDI_WELCOME, 282, 200);
wlcLbl->palette()->setColor(Palette::Background, Palette::Normal, 0xfefefe);
wlcLbl->setProperty(Widget::HSizeBehavior, Widget::Expanding);
wlcLbl->setProperty(Widget::VSizeBehavior, Widget::Fixed);
m_cenPanelVlut->addWidget(wlcLbl);
/* Check box section*/
CheckBox *chkBox = new CheckBox(m_cenPanel, _TR(CHECK_SILENT));
chkBox->setGeometry(m_cenPanel->size().width/2 - 43, 254, 180, 16);
setSelectorStyle(chkBox);
chkBox->onClick([chkBox, this]() {
m_is_checked = chkBox->isChecked();
});
/* Comment section */
Label *comntLbl = new Label(m_cenPanel);
comntLbl->setText(_TR(LABEL_WARN_CLOSE), true);
comntLbl->setGeometry(0, m_cenPanel->size().height - 130, m_cenPanel->size().width, 48);
setLabelStyle(comntLbl);
/* Install button section */
Button *instlBtn = new Button(m_cenPanel);
instlBtn->setText(_TR(BUTTON_INSTALL));
instlBtn->setGeometry(m_cenPanel->size().width/2 - 50, m_cenPanel->size().height - 76, 100, 28);
setButtonStyle(instlBtn);
instlBtn->onClick([=]() {
m_cenPanel->disconnect(m_resize_conn);
chkBox->close();
comntLbl->close();
instlBtn->close();
startInstall(url);
});
m_resize_conn = m_cenPanel->onResize([chkBox, comntLbl, instlBtn](int w, int h) {
chkBox->setGeometry(w/2 - 43, 254, 180, 16);
comntLbl->setGeometry(0, h - 130, w, 48);
instlBtn->setGeometry(w/2 - 50, h - 76, 100, 28);
});
}
void MainWindow::initControlMode(const std::wstring &_arch)
{
m_mode = Mode::Control;
/* Comment section */
m_versionLbl = new Label(m_cenPanel);
setControlLabelStyle(m_versionLbl);
m_versionLbl->setText(fillInstalledVerInfo());
m_versionLbl->setProperty(Widget::HSizeBehavior, Widget::Expanding);
m_versionLbl->setProperty(Widget::VSizeBehavior, Widget::Fixed);
m_versionLbl->metrics()->setMetrics(Metrics::TextMarginLeft, 12);
m_cenPanelVlut->setContentMargins(18, 6, 6, 6);
m_cenPanelVlut->addWidget(m_versionLbl);
if (m_package == _TR(LABEL_UNKN_PACK) || m_ver == _TR(LABEL_UNKN_VER) || _arch.empty() || m_arch != _arch) {
Label *errLbl = new Label(m_cenPanel);
setControlLabelStyle(errLbl);
errLbl->setText(_TR(LABEL_NO_OPTIONS));
errLbl->setProperty(Widget::HSizeBehavior, Widget::Expanding);
errLbl->setProperty(Widget::VSizeBehavior, Widget::Expanding);
errLbl->metrics()->setMetrics(Metrics::TextMarginLeft, 24);
m_cenPanelVlut->addWidget(errLbl);
return;
}
createSelectionPage();
}
bool MainWindow::event(UINT msg, WPARAM wParam, LPARAM lParam, LRESULT *result)
{
switch (msg) {
case WM_INVOKEMETHOD: {
if (std::function<void()> *func = (std::function<void()>*)wParam) {
if (*func)
(*func)();
delete func;
}
break;
}
}
return Window::event(msg, wParam, lParam, result);
}
void MainWindow::startInstall(const std::wstring &url)
{
/* Comment section */
m_comntLbl = new Label(m_cenPanel);
m_comntLbl->setText(_TR(LABEL_DOWNLOAD), true);
m_comntLbl->setGeometry(0, m_cenPanel->size().height - 156, m_cenPanel->size().width, 24);
m_comntLbl->metrics()->setMetrics(Metrics::FontHeight, 20);
setLabelStyle(m_comntLbl);
m_comntInfoLbl = new Label(m_cenPanel);
m_comntInfoLbl->setText(_TR(LABEL_ALMOST_DONE), true);
m_comntInfoLbl->setGeometry(0, m_cenPanel->size().height - 112, m_cenPanel->size().width, 40);
setLabelStyle(m_comntInfoLbl);
/* Progress section */
m_bar = new ProgressBar(m_cenPanel);
m_bar->setGeometry(0, m_cenPanel->size().height - 126, m_cenPanel->size().width, 5);
setProgressStyle(m_bar);
m_bar->metrics()->setMetrics(Metrics::IconMarginLeft, 108);
m_bar->metrics()->setMetrics(Metrics::IconMarginRight, 108);
m_resize_conn = m_cenPanel->onResize([this](int w, int h) {
m_comntLbl->setGeometry(0, h - 156, w, 24);
m_comntInfoLbl->setGeometry(0, h - 112, w, 40);
m_bar->setGeometry(0, m_cenPanel->size().height - 126, m_cenPanel->size().width, 5);
});
m_comntLbl->show();
m_comntInfoLbl->show();
m_bar->show();
wstring path = NS_File::generateTmpFileName(L".exe");
startDownload(url, path, [=]() {
wstring args;
if (m_is_checked) {
args = _T("/VERYSILENT");
m_comntLbl->setText(_TR(LABEL_INSTALL), true);
m_bar->pulse(true);
} else {
hide();
}
if (!NS_File::runProcess(path, args)) {
if (!m_is_checked)
show();
m_bar->pulse(false);
m_bar->setProgress(0);
m_comntInfoLbl->setText(_TR(LABEL_ERR_RUNNING), true);
} else {
if (m_is_checked) {
wstring app_path;
if (NS_Utils::IsAppInstalled(app_path)) {
m_cenPanel->disconnect(m_resize_conn);
m_comntLbl->close();
m_comntInfoLbl->close();
m_bar->close();
invokeMethod(&MainWindow::finishInstall, this, app_path);
} else {
m_bar->pulse(false);
m_bar->setProgress(0);
m_comntLbl->setText(_TR(LABEL_ERR_INSTALL), true);
}
} else {
close();
}
}
});
}
void MainWindow::finishInstall(const std::wstring &app_path)
{
/* Check box section*/
m_is_checked = false;
CheckBox *chkBox = new CheckBox(m_cenPanel, _TR(CHECK_LAUNCH));
chkBox->setGeometry(m_cenPanel->size().width/2 - 43, 254, 180, 16);
setSelectorStyle(chkBox);
chkBox->onClick([chkBox, this]() {
m_is_checked = chkBox->isChecked();
});
/* Comment section */
wstring compl_text = _TR(LABEL_INSTALL_COMPL);
NS_Utils::Replace(compl_text, L"%1", _T(WINDOW_NAME));
Label *comntLbl = new Label(m_cenPanel);
comntLbl->setText(compl_text, true);
comntLbl->setGeometry(0, m_cenPanel->size().height - 130, m_cenPanel->size().width, 48);
setLabelStyle(comntLbl);
/* Install button section */
Button *closeBtn = new Button(m_cenPanel);
closeBtn->setText(_TR(BUTTON_CLOSE));
closeBtn->setGeometry(m_cenPanel->size().width/2 - 50, m_cenPanel->size().height - 76, 100, 28);
setButtonStyle(closeBtn);
closeBtn->onClick([=]() {
if (m_is_checked)
NS_File::runProcess(app_path + _T(APP_LAUNCH_NAME), L"", false);
close();
});
m_resize_conn = m_cenPanel->onResize([chkBox, comntLbl, closeBtn](int w, int h) {
chkBox->setGeometry(w/2 - 43, 254, 180, 16);
comntLbl->setGeometry(0, h - 130, w, 48);
closeBtn->setGeometry(w/2 - 50, h - 76, 100, 28);
});
chkBox->show();
comntLbl->show();
closeBtn->show();
}
void MainWindow::startUpdate()
{
wstring tmp_path = NS_File::toNativeSeparators(NS_File::generateTmpFileName(L"." + m_package));
wstring url;
if (m_package == L"msi") {
url = (m_arch == L"x64") ? _T(URL_INSTALL_X64_MSI) : _T(URL_INSTALL_X86_MSI);
} else {
if (Utils::getWinVersion() <= Utils::WinVer::WinVista) {
url = (m_arch == L"x64") ? _T(URL_INSTALL_X64_XP) : _T(URL_INSTALL_X86_XP);
} else {
url = (m_arch == L"x64") ? _T(URL_INSTALL_X64) : _T(URL_INSTALL_X86);
}
}
CDownloader *dnl = startDownload(url, tmp_path, [=]() {
m_bar->pulse(true);
wstring args = L"/c \"" + tmp_path;
args += (m_package == L"msi") ? L" /qn\"" : L" /UPDATE /VERYSILENT\"";
if (!NS_File::runProcess(L"cmd", args, true)) {
m_bar->pulse(false);
m_bar->setProgress(0);
m_comntInfoLbl->setText(_TR(LABEL_ERR_RUNNING), true);
} else {
m_bar->pulse(false);
m_bar->setProgress(100);
m_comntLbl->setText(_TR(LABEL_UPDATE_COMPL));
m_versionLbl->setText(fillInstalledVerInfo());
}
});
m_cancelBtn->onClick([=]() {
dnl->stop();
});
}
void MainWindow::startRepair()
{
wstring tmp_path;
if (m_package == L"msi") {
wstring prodCode = NS_Utils::MsiProductCode(_T(WINDOW_NAME));
if (prodCode.empty()) {
m_comntInfoLbl->setText(_TR(LABEL_ERR_PROD_CODE), true);
return;
}
wstring packageName = NS_Utils::MsiGetProperty(prodCode.c_str(), INSTALLPROPERTY_PACKAGENAME);
if (packageName.empty()) {
m_comntInfoLbl->setText(_TR(LABEL_ERR_PACK_NAME), true);
return;
}
tmp_path = NS_File::toNativeSeparators(NS_File::tempPath() + _T("/") + packageName);
} else {
tmp_path = NS_File::toNativeSeparators(NS_File::generateTmpFileName(L"." + m_package));
}
wstring url = L"https://github.com/%1/%2/releases/download/%3/%4";
{
wstring url_filename = L"DesktopEditors_" + m_arch;
if (Utils::getWinVersion() <= Utils::WinVer::WinVista)
url_filename.append(L"_xp");
url_filename.append(L"." + m_package);
wstring url_ver = L"v" + m_ver;
size_t pos = url_ver.find_last_of(L'.');
if (pos != std::wstring::npos)
url_ver = url_ver.substr(0, pos);
NS_Utils::Replace(url, L"%1", _T(REG_GROUP_KEY));
NS_Utils::Replace(url, L"%2", _T(APP_NAME));
NS_Utils::Replace(url, L"%3", url_ver);
NS_Utils::Replace(url, L"%4", url_filename);
}
CDownloader *dnl = startDownload(url, tmp_path, [=]() {
m_bar->pulse(true);
wstring cmd = (m_package == L"msi") ? L"msiexec" : L"cmd",
args = (m_package == L"msi") ? L"/fvamus \"" : L"/c \"";
args += tmp_path;
args += (m_package == L"msi") ? L"\" /qn" : L" /VERYSILENT\"";
if (!NS_File::runProcess(cmd, args, true)) {
m_bar->pulse(false);
m_bar->setProgress(0);
m_comntInfoLbl->setText(_TR(LABEL_ERR_RUNNING), true);
} else {
if (m_is_clear_checked) {
wstring dataPath = NS_File::appDataPath();
if (!dataPath.empty())
NS_File::removeDirRecursively(dataPath);
}
if (m_is_sttgs_checked) {
wstring key(L"SOFTWARE\\");
key.append(_T(REG_GROUP_KEY));
SHDeleteKey(HKEY_CURRENT_USER, key.c_str());
}
m_bar->pulse(false);
m_bar->setProgress(100);
m_comntLbl->setText(_TR(LABEL_REPAIR_COMPL));
}
});
m_cancelBtn->onClick([=]() {
dnl->stop();
});
}
void MainWindow::startUninstall()
{
m_cancelBtn->setDisabled(true);
m_bar->pulse(true);
wstring args = L"/c \"" + m_uninst_cmd;
args += (m_package == L"msi") ? L" /qn\"" : L" /VERYSILENT\"";
m_future = std::async(std::launch::async, [=]() {
if (!NS_File::runProcess(L"cmd", args, true)) {
m_bar->pulse(false);
m_bar->setProgress(0);
m_comntInfoLbl->setText(_TR(LABEL_ERR_UNINST));
createCloseAndBackButtons();
} else {
if (m_is_checked) {
wstring dataPath = NS_File::appDataPath();
if (!dataPath.empty())
NS_File::removeDirRecursively(dataPath);
wstring key(L"SOFTWARE\\");
key.append(_T(REG_GROUP_KEY));
SHDeleteKey(HKEY_CURRENT_USER, key.c_str());
}
m_bar->pulse(false);
m_bar->setProgress(100);
m_comntLbl->setText(_TR(LABEL_UNINST_COMPL));
createCloseButton();
}
});
}
void MainWindow::createSelectionPage()
{
/* Check box section*/
m_is_clear_checked = false;
CheckBox *clrChkBox = new CheckBox(m_cenPanel, _TR(CHECK_CLR_DATA));
clrChkBox->setDisabled(!(m_checkState & RepairRadio));
clrChkBox->setChecked(m_checkState & ClrDataCheck);
clrChkBox->setGeometry(79, 114, 450, 18);
setSelectorStyle(clrChkBox);
clrChkBox->onClick([=]() {
m_is_clear_checked = clrChkBox->isChecked();
m_checkState = (m_checkState & ~ClrDataCheck) | (m_is_clear_checked * ClrDataCheck);
});
m_is_sttgs_checked = false;
CheckBox *stnChkBox = new CheckBox(m_cenPanel, _TR(CHECK_CLR_STNGS));
stnChkBox->setDisabled(!(m_checkState & RepairRadio));
stnChkBox->setChecked(m_checkState & ClrStnCheck);
stnChkBox->setGeometry(79, 146, 450, 18);
setSelectorStyle(stnChkBox);
stnChkBox->onClick([stnChkBox, this]() {
m_is_sttgs_checked = stnChkBox->isChecked();
m_checkState = (m_checkState & ~ClrStnCheck) | (m_is_sttgs_checked * ClrStnCheck);
});
m_is_checked = false;
CheckBox *clrAllChkBox = new CheckBox(m_cenPanel, _TR(CHECK_CLR_ALL));
clrAllChkBox->setDisabled(!(m_checkState & UninstRadio));
clrAllChkBox->setChecked(m_checkState & ClrAllCheck);
clrAllChkBox->setGeometry(79, 216, 450, 18);
setSelectorStyle(clrAllChkBox);
clrAllChkBox->onClick([clrAllChkBox, this]() {
m_is_checked = clrAllChkBox->isChecked();
m_checkState = (m_checkState & ~ClrAllCheck) | (m_is_checked * ClrAllCheck);
});
/* Update radio button section*/
m_updRadio = new RadioButton(m_cenPanel, _TR(RADIO_UPDATE));
m_updRadio->setChecked(m_checkState & UpdateRadio);
m_updRadio->setGeometry(50, 48, 128, 18);
setSelectorStyle(m_updRadio);
m_updRadio->onClick([=]() {
clrChkBox->setDisabled(true);
stnChkBox->setDisabled(true);
clrAllChkBox->setDisabled(true);
if (m_repRadio->isChecked())
m_repRadio->setChecked(false);
if (m_uninsRadio->isChecked())
m_uninsRadio->setChecked(false);
m_checkState = (m_checkState | UpdateRadio) & ~(RepairRadio | UninstRadio);
});
/* Repair radio button section*/
m_repRadio = new RadioButton(m_cenPanel, _TR(RADIO_REPAIR));
m_repRadio->setChecked(m_checkState & RepairRadio);
m_repRadio->setGeometry(50, 82, 128, 18);
setSelectorStyle(m_repRadio);
m_repRadio->onClick([=]() {
clrChkBox->setDisabled(false);
stnChkBox->setDisabled(false);
clrAllChkBox->setDisabled(true);
if (m_updRadio->isChecked())
m_updRadio->setChecked(false);
if (m_uninsRadio->isChecked())
m_uninsRadio->setChecked(false);
m_checkState = (m_checkState | RepairRadio) & ~(UninstRadio | UpdateRadio);
});
/* Uninstall radio button section*/
m_uninsRadio = new RadioButton(m_cenPanel, _TR(RADIO_UNINST));
m_uninsRadio->setChecked(m_checkState & UninstRadio);
m_uninsRadio->setGeometry(50, 184, 128, 18);
setSelectorStyle(m_uninsRadio);
m_uninsRadio->onClick([=]() {
clrChkBox->setDisabled(true);
stnChkBox->setDisabled(true);
clrAllChkBox->setDisabled(false);
if (m_repRadio->isChecked())
m_repRadio->setChecked(false);
if (m_updRadio->isChecked())
m_updRadio->setChecked(false);
m_checkState = (m_checkState | UninstRadio) & ~(UpdateRadio | RepairRadio);
});
/* Apply button section */
Button *applyBtn = new Button(m_cenPanel);
applyBtn->setText(_TR(BUTTON_APPLY));
applyBtn->setGeometry(m_cenPanel->size().width - 100 - 12, m_cenPanel->size().height - 28 - 12, 100, 28);
setButtonStyle(applyBtn);
applyBtn->onClick([=]() {
wstring msg = m_uninsRadio->isChecked() ? _TR(MSG_REMOVE) : m_repRadio->isChecked() ? _TR(MSG_REPAIR) : _TR(MSG_UPDATE);
NS_Utils::Replace(msg, L"%1", _T(WINDOW_NAME));
if (IDOK == MessageBox(nativeWindowHandle(), msg.c_str(), _TR(CAPTION), MB_ICONWARNING | MB_OKCANCEL | MB_DEFBUTTON2)) {
m_cenPanel->disconnect(m_resize_conn);
m_updRadio->close();
m_repRadio->close();
clrChkBox->close();
stnChkBox->close();
m_uninsRadio->close();
clrAllChkBox->close();
applyBtn->close();
msg = m_uninsRadio->isChecked() ? _TR(LABEL_UNINSTLING) : m_repRadio->isChecked() ? _TR(LABEL_REPAIRING) : _TR(LABEL_UPDATING);
createProgressPage(msg);
if (m_uninsRadio->isChecked())
startUninstall();
else
if (m_repRadio->isChecked())
startRepair();
else
startUpdate();
}
});
m_resize_conn = m_cenPanel->onResize([applyBtn](int w, int h) {
applyBtn->setGeometry(w - 100 - 12, h - 28 - 12, 100, 28);
});
m_updRadio->show();
m_repRadio->show();
clrChkBox->show();
stnChkBox->show();
m_uninsRadio->show();
clrAllChkBox->show();
applyBtn->show();
}
void MainWindow::createProgressPage(const std::wstring &text)
{
m_comntLbl = new Label(m_cenPanel);
setControlLabelStyle(m_comntLbl);
m_comntLbl->setText(text);
m_comntLbl->metrics()->setMetrics(Metrics::TextMarginLeft, 12);
m_comntLbl->setGeometry(30, 50, size().width - 30, 24);
m_comntInfoLbl = new Label(m_cenPanel);
setControlLabelStyle(m_comntInfoLbl);
m_comntInfoLbl->metrics()->setMetrics(Metrics::TextMarginLeft, 12);
m_comntInfoLbl->setGeometry(30, 92, m_cenPanel->size().width - 30, 40);
/* Progress section */
m_bar = new ProgressBar(m_cenPanel);
m_bar->setGeometry(42, 80, 250, 5);
setProgressStyle(m_bar);
m_cancelBtn = new Button(m_cenPanel);
m_cancelBtn->setText(_TR(BUTTON_CANCEL));
m_cancelBtn->setGeometry(m_cenPanel->size().width - 100 - 12, m_cenPanel->size().height - 28 - 12, 100, 28);
setButtonStyle(m_cancelBtn);
m_resize_conn = m_cenPanel->onResize([this](int w, int h) {
m_cancelBtn->setGeometry(w - 100 - 12, h - 28 - 12, 100, 28);
});
m_comntLbl->show();
m_comntInfoLbl->show();
m_bar->show();
m_cancelBtn->show();
}
void MainWindow::createCloseButton()
{
invokeMethod([=]() {
m_cenPanel->disconnect(m_resize_conn);
m_cancelBtn->close();
Button *closeBtn = new Button(m_cenPanel);
closeBtn->setText(_TR(BUTTON_CLOSE));
closeBtn->setGeometry(m_cenPanel->size().width - 100 - 12, m_cenPanel->size().height - 28 - 12, 100, 28);
setButtonStyle(closeBtn);
closeBtn->onClick([=]() {
m_cenPanel->disconnect(m_resize_conn);
close();
});
m_resize_conn = m_cenPanel->onResize([closeBtn](int w, int h) {
closeBtn->setGeometry(w - 100 - 12, h - 28 - 12, 100, 28);
});
closeBtn->show();
});
}
void MainWindow::createCloseAndBackButtons()
{
invokeMethod([=]() {
m_cenPanel->disconnect(m_resize_conn);
m_cancelBtn->close();
Button *closeBtn = new Button(m_cenPanel);
closeBtn->setText(_TR(BUTTON_CLOSE));
closeBtn->setGeometry(m_cenPanel->size().width - 100 - 12, m_cenPanel->size().height - 28 - 12, 100, 28);
setButtonStyle(closeBtn);
closeBtn->onClick([=]() {
m_cenPanel->disconnect(m_resize_conn);
close();
});
Button *backBtn = new Button(m_cenPanel);
backBtn->setText(_TR(BUTTON_BACK));
backBtn->setGeometry(m_cenPanel->size().width - 100 - 12 - 106, m_cenPanel->size().height - 28 - 12, 100, 28);
setButtonStyle(backBtn);
backBtn->onClick([=]() {
m_cenPanel->disconnect(m_resize_conn);
m_comntLbl->close();
m_comntInfoLbl->close();
m_bar->close();
closeBtn->close();
backBtn->close();
createSelectionPage();
});
m_resize_conn = m_cenPanel->onResize([closeBtn, backBtn](int w, int h) {
closeBtn->setGeometry(w - 100 - 12, h - 28 - 12, 100, 28);
backBtn->setGeometry(w - 100 - 12 - 106, h - 28 - 12, 100, 28);
});
closeBtn->show();
backBtn->show();
});
}
wstring MainWindow::fillInstalledVerInfo()
{
wstring text = _TR(LABEL_VERSION);
NS_Utils::InstalledVerInfo(L"DisplayVersion", m_ver, m_arch);
if (m_ver.empty())
m_ver = _TR(LABEL_UNKN_VER);
NS_Utils::InstalledVerInfo(L"UninstallString", m_uninst_cmd, m_arch);
m_package = (m_uninst_cmd.find(L"msiexec") != std::wstring::npos) ? L"msi" : (m_uninst_cmd.find(L".exe") != std::wstring::npos) ? L"exe" : _TR(LABEL_UNKN_PACK);
NS_Utils::Replace(text, L"%1", _T(WINDOW_NAME));
NS_Utils::Replace(text, L"%2", m_ver);
NS_Utils::Replace(text, L"%3", m_arch);
NS_Utils::Replace(text, L"%4", m_package);
return text;
}
CDownloader* MainWindow::startDownload(const std::wstring &url, const std::wstring &path, const std::function<void()> &onComplete)
{
CDownloader *dnl = new CDownloader();
dnl->onProgress([=](int percent) {
m_bar->setProgress(percent);
});
dnl->onComplete([=](ulong error) {
if (m_mode == Mode::Control)
m_cancelBtn->setDisabled(true);
if (error == ERROR_SUCCESS) {
if (NS_File::verifyEmbeddedSignature(path)) {
onComplete();
} else {
m_bar->setProgress(0);
m_comntInfoLbl->setText(_TR(LABEL_NO_VER_AVAIL), true);
}
if (NS_File::fileExists(path))
NS_File::removeFile(path);
} else
if (error == ERROR_CANCELLED) {
m_comntInfoLbl->setText(_TR(LABEL_ERR_CANCELLED), true);
} else {
m_comntInfoLbl->setText(NS_Utils::GetLastErrorAsString(error), true);
}
if (m_mode == Mode::Control)
createCloseAndBackButtons();
});
dnl->downloadFile(url, path);
onAboutToDestroy([=]() {
delete dnl;
});
return dnl;
}
template<typename Fn, typename... Args>
void MainWindow::invokeMethod(Fn&& fn, Args&&... args)
{
std::function<void()> *func = new std::function<void()>(std::bind(std::forward<Fn>(fn), std::forward<Args>(args)...));
PostMessage(m_hWnd, WM_INVOKEMETHOD, (WPARAM)func, 0);
} // NOLINT

View File

@ -0,0 +1,67 @@
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include "window.h"
#include <future>
class Label;
class ProgressBar;
class Widget;
class BoxLayout;
class RadioButton;
class Button;
class CDownloader;
class MainWindow : public Window
{
public:
MainWindow(Widget *parent, const Rect &rc);
~MainWindow();
void initInstallationMode(const std::wstring &url);
void initControlMode(const std::wstring &arch);
protected:
virtual bool event(UINT, WPARAM, LPARAM, LRESULT*) override;
private:
void startInstall(const std::wstring &url);
void finishInstall(const std::wstring &app_path);
void startUpdate();
void startRepair();
void startUninstall();
void createSelectionPage();
void createProgressPage(const std::wstring &text);
void createCloseButton();
void createCloseAndBackButtons();
std::wstring fillInstalledVerInfo();
CDownloader* startDownload(const std::wstring &url, const std::wstring &path, const std::function<void()> &onComplete);
template<typename Fn, typename... Args>
void invokeMethod(Fn&& fn, Args&&... args);
enum class Mode : BYTE {Install, Control};
enum Selectors : BYTE {UpdateRadio = 1, RepairRadio = 2, UninstRadio = 4, ClrDataCheck = 8, ClrStnCheck = 16, ClrAllCheck = 32};
std::future<void> m_future;
std::wstring m_uninst_cmd,
m_ver,
m_arch,
m_package;
Label *m_comntLbl,
*m_versionLbl,
*m_comntInfoLbl;
ProgressBar *m_bar;
Widget *m_cenPanel;
BoxLayout *m_cenPanelVlut;
RadioButton *m_updRadio,
*m_repRadio,
*m_uninsRadio;
Button *m_cancelBtn;
Mode m_mode;
int m_resize_conn;
BYTE m_checkState;
bool m_is_clear_checked,
m_is_sttgs_checked,
m_is_checked;
};
#endif // MAINWINDOW_H

View File

@ -1,29 +1,52 @@
#include "version.h"
#define IDI_MAINICON 101
#define IDD_DIALOG 102
#define IDD_DIALOG_RTL 103
#define IDC_MAIN_ICON 1001
#define IDC_LABEL_TITLE 1002
#define IDC_LABEL_MESSAGE 1003
#define IDC_PROGRESS 1004
#define IDC_BUTTON_CANCEL 1005
#define IDC_SILENT_CHECK 1006
#define IDI_WELCOME 102
#define IDT_TRANSLATIONS 10001
#define CAPTION_TEXT VER_PRODUCTNAME_STR
#define MESSAGE_TEXT_ERR1 "The application cannot continue because this architecture is not supported.\0"
#define MESSAGE_TEXT_ERR2 "The application is already running.\0"
#define LABEL_TITLE_TEXT "Preparing for installation\0"
#define LABEL_MESSAGE_TEXT "Downloading a package\0"
#define LABEL_MESSAGE_TEXT_ERR1 "An error occurred during initialization.\nPlease try restarting the app later.\0"
#define LABEL_MESSAGE_TEXT_ERR2 "Package download failed: Not enough memory!\nPlease try restarting the app later.\0"
#define LABEL_MESSAGE_TEXT_ERR3 "Package download failed: Server connection error!\nPlease try restarting the app later.\0"
#define LABEL_MESSAGE_TEXT_ERR4 "Package download failed: Network error!\nPlease try restarting the app later.\0"
#define LABEL_MESSAGE_TEXT_ERR5 "An error occurred while running the package.\nPlease try restarting the app later.\0"
#define LABEL_MESSAGE_TEXT_ERR6 "An error occurred during initialization: Url not set.\0"
#define LABEL_MESSAGE_TEXT_ERR7 "An error occurred during initialization: File name not specified.\0"
#define BUTTON_CANCEL_TEXT "Cancel\0"
#define SILENT_CHECK_TEXT "Silent Installation\0"
#define APP_LAUNCH_NAME "\\DesktopEditors.exe"
#define CAPTION VER_PRODUCTNAME_STR
#define MSG_ERR_ARCH "The application cannot continue because this architecture is not supported."
#define MSG_ERR_ALREADY_RUNNING "The application is already running."
#define MSG_ERR_CLOSE_APP "Setup has detected that %1 is currently running. Please close all instances of it."
#define MSG_REMOVE "This will remove %1 and its components."
#define MSG_REPAIR "This will repair the current version of %1."
#define MSG_UPDATE "This will update %1 to the latest version available."
#define LABEL_DOWNLOAD "Downloading"
#define LABEL_INSTALL "Installing"
#define LABEL_UPDATING "Updating"
#define LABEL_REPAIRING "Repairing"
#define LABEL_UNINSTLING "Uninstalling"
#define LABEL_UPDATE_COMPL "Update complete!"
#define LABEL_REPAIR_COMPL "Repairing completed!"
#define LABEL_UNINST_COMPL "Uninstalling completed!"
#define LABEL_VERSION "%1 %2 (%3 %4) is installed"
#define LABEL_UNKN_VER "unknown version"
#define LABEL_UNKN_PACK "unknown package"
#define LABEL_NO_OPTIONS "No additional options available."
#define LABEL_NO_VER_AVAIL "No version available"
#define LABEL_WARN_CLOSE "This will install ONLYOFFICE Desktop Editors on your computer.\nIt is reccomended that you close all other applications before continuing."
#define LABEL_ALMOST_DONE "Just a bit more and we're done"
#define LABEL_INSTALL_COMPL "%1 has been successfully installed on your computer.\nTo run the application after closing this installer, select the check box."
#define LABEL_ERR_PROD_CODE "Error while retrieving product code."
#define LABEL_ERR_PACK_NAME "Error while retrieving package name."
#define LABEL_ERR_INSTALL "An error occurred during installation."
#define LABEL_ERR_UNINST "An error occurred during uninstalling."
#define LABEL_ERR_COMMON "An error occurred:"
#define LABEL_ERR_RUNNING "An error occurred while running the package.\nPlease try restarting the app later."
#define LABEL_ERR_CANCELLED "Cancelled!"
#define BUTTON_INSTALL "Install"
#define BUTTON_CANCEL "Cancel"
#define BUTTON_APPLY "Apply"
#define BUTTON_CLOSE "Close"
#define BUTTON_BACK "Back"
#define RADIO_UPDATE "Update"
#define RADIO_REPAIR "Repair"
#define RADIO_UNINST "Uninstall"
#define CHECK_SILENT "Silent Installation"
#define CHECK_LAUNCH "Launch"
#define CHECK_CLR_DATA "Clear cached data"
#define CHECK_CLR_STNGS "Clear user settings"
#define CHECK_CLR_ALL "Clear user settings and cached data"

View File

@ -29,7 +29,7 @@ private:
static wstring langName;
static bool is_translations_valid;
enum TokenType {
enum TokenType : unsigned char {
TOKEN_BEGIN_DOCUMENT = 0,
TOKEN_END_DOCUMENT,
TOKEN_BEGIN_STRING_ID,

View File

@ -0,0 +1,86 @@
#include "abstractbutton.h"
#include "palette.h"
AbstractButton::AbstractButton(Widget *parent, const std::wstring &text) :
Widget(parent, ObjectType::WidgetType),
m_text(text)
{
}
AbstractButton::~AbstractButton()
{
}
void AbstractButton::setText(const std::wstring &text)
{
m_text = text;
update();
}
int AbstractButton::onClick(const FnVoidVoid &callback)
{
m_click_callbacks[++m_connectionId] = callback;
return m_connectionId;
}
void AbstractButton::disconnect(int connectionId)
{
auto it = m_click_callbacks.find(connectionId);
if (it != m_click_callbacks.end())
m_click_callbacks.erase(it);
}
bool AbstractButton::event(UINT msg, WPARAM wParam, LPARAM lParam, LRESULT *result)
{
switch (msg) {
case WM_LBUTTONDOWN: {
if (!m_disabled) {
palette()->setCurrentState(Palette::Pressed);
repaint();
}
return false;
}
case WM_LBUTTONUP: {
if (!m_disabled) {
palette()->setCurrentState(Palette::Hover);
repaint();
click();
}
break;
}
case WM_MOUSEENTER: {
if (!m_disabled) {
palette()->setCurrentState(Palette::Hover);
repaint();
}
break;
}
case WM_MOUSELEAVE: {
if (!m_disabled) {
palette()->setCurrentState(Palette::Normal);
repaint();
}
break;
}
default:
break;
}
return Widget::event(msg, wParam, lParam, result);
}
void AbstractButton::click()
{
if (underMouse()) {
for (auto it = m_click_callbacks.begin(); it != m_click_callbacks.end(); it++) {
if (it->second)
(it->second)();
}
}
}

View File

@ -0,0 +1,30 @@
#ifndef ABSTRACTBUTTON_H
#define ABSTRACTBUTTON_H
#include "widget.h"
#include <unordered_map>
class AbstractButton : public Widget
{
public:
AbstractButton(Widget *parent = nullptr, const std::wstring &text = L"");
virtual ~AbstractButton();
void setText(const std::wstring &text);
/* callback */
int onClick(const FnVoidVoid &callback);
virtual void disconnect(int) override;
protected:
virtual bool event(UINT, WPARAM, LPARAM, LRESULT*) override;
virtual void click();
std::wstring m_text;
private:
std::unordered_map<int, FnVoidVoid> m_click_callbacks;
};
#endif // ABSTRACTBUTTON_H

View File

@ -0,0 +1,180 @@
#include "application.h"
#include "widget.h"
#include "src/resource.h"
#include <gdiplus.h>
class Application::ApplicationPrivate
{
public:
ApplicationPrivate();
~ApplicationPrivate();
ULONG_PTR gdi_token;
HINSTANCE hInstance;
LayoutDirection layoutDirection;
int windowId;
ATOM registerClass(LPCWSTR className, HINSTANCE hInstance);
static LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
};
Application::ApplicationPrivate::ApplicationPrivate() :
gdi_token(0),
hInstance(nullptr),
layoutDirection(LayoutDirection::LeftToRight),
windowId(0)
{
Gdiplus::GdiplusStartupInput gdiplusStartupInput;
Gdiplus::GdiplusStartup(&gdi_token, &gdiplusStartupInput, nullptr);
}
Application::ApplicationPrivate::~ApplicationPrivate()
{
Gdiplus::GdiplusShutdown(gdi_token);
}
ATOM Application::ApplicationPrivate::registerClass(LPCWSTR className, HINSTANCE hInstance)
{
WNDCLASSEX wcx;
memset(&wcx, 0, sizeof(wcx));
wcx.cbSize = sizeof(WNDCLASSEX);
wcx.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS;
wcx.hInstance = hInstance;
wcx.lpfnWndProc = WndProc;
wcx.cbClsExtra = 0;
wcx.cbWndExtra = 0;
// wcx.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_MAINICON));
// wcx.hIconSm = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_MAINICON));
wcx.lpszClassName = className;
wcx.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
wcx.hCursor = LoadCursor(NULL, IDC_ARROW);
return RegisterClassEx(&wcx);
}
LRESULT CALLBACK Application::ApplicationPrivate::WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
if (msg == WM_CREATE) {
if (CREATESTRUCT *cs = (CREATESTRUCT*)lParam) {
if (Widget *wgt = (Widget*)cs->lpCreateParams) {
wgt->setNativeWindowHandle(hWnd);
SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR)wgt);
LRESULT result = 0;
if (wgt->event(msg, wParam, lParam, &result))
return result;
}
}
} else
if (Widget *wgt = (Widget*)GetWindowLongPtr(hWnd, GWLP_USERDATA)) {
LRESULT result = 0;
if (wgt->event(msg, wParam, lParam, &result))
return result;
}
return DefWindowProc(hWnd, msg, wParam, lParam);
}
Application *Application::inst = nullptr;
Application::Application(HINSTANCE hInstance, PWSTR cmdline, int cmdshow) :
Application()
{
d_ptr->hInstance = hInstance;
if (!d_ptr->hInstance)
d_ptr->hInstance = GetModuleHandle(NULL);
inst = this;
}
Application::Application() :
Object(nullptr),
d_ptr(new ApplicationPrivate)
{
}
Application *Application::instance()
{
return inst;
}
HINSTANCE Application::moduleHandle()
{
return d_ptr->hInstance;
}
void Application::setLayoutDirection(LayoutDirection layoutDirection)
{
d_ptr->layoutDirection = layoutDirection;
}
Application::~Application()
{
delete d_ptr, d_ptr = nullptr;
}
int Application::exec()
{
MSG msg;
BOOL res;
while ((res = GetMessage(&msg, NULL, 0, 0)) != 0 && res != -1) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return (int)msg.wParam;
}
void Application::exit(int code)
{
PostQuitMessage(code);
}
void Application::registerWidget(Widget *wgt, ObjectType objType, const Rect &rc)
{
std::wstring className;
DWORD style = WS_CLIPCHILDREN;
DWORD exStyle = d_ptr->layoutDirection == LayoutDirection::RightToLeft ? WS_EX_LAYOUTRTL : 0;
HWND hWndParent = wgt->parentWidget() ? wgt->parentWidget()->nativeWindowHandle() : HWND_DESKTOP;
switch (objType) {
case ObjectType::WindowType:
className = L"MainWindow " + std::to_wstring(++d_ptr->windowId);
style |= WS_OVERLAPPEDWINDOW;
exStyle |= WS_EX_APPWINDOW;
break;
case ObjectType::DialogType:
className = L"Dialog " + std::to_wstring(++d_ptr->windowId);
style |= WS_CAPTION | WS_SYSMENU /*| DS_MODALFRAME*/;
exStyle |= WS_EX_DLGMODALFRAME;
break;
case ObjectType::PopupType:
className = L"Popup " + std::to_wstring(++d_ptr->windowId);
style |= WS_POPUP;
exStyle |= WS_EX_TOOLWINDOW | WS_EX_LAYERED;
break;
case ObjectType::WidgetType:
default:
className = L"Widget " + std::to_wstring(++d_ptr->windowId);
style |= WS_CHILD;
break;
}
// if (wgt->parent()) {
// if (wgt->parentWidget()->isCreated()) {
// d_ptr->registerClass(className.c_str(), hInstance);
// wgt->m_hWnd = CreateWindowEx(exStyle, className.c_str(), wgt->title().c_str(), style, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, hWndParent, NULL, hInstance, NULL);
// SetWindowLongPtr(wgt->m_hWnd, GWLP_USERDATA, (LONG_PTR)wgt);
// } else {
// wgt->connectOnCreate([=]() {
// wgt->m_hWnd = CreateWindowEx(exStyle, className.c_str(), wgt->title().c_str(), style, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, hWndParent, NULL, hInstance, NULL);
// SetWindowLongPtr(wgt->m_hWnd, GWLP_USERDATA, (LONG_PTR)wgt);
// });
// }
// } else {
d_ptr->registerClass(className.c_str(), d_ptr->hInstance);
CreateWindowEx(exStyle, className.c_str(), wgt->title().c_str(), style, rc.x, rc.y, rc.width, rc.height,
hWndParent, NULL, d_ptr->hInstance, (LPVOID)wgt);
// }
}

View File

@ -0,0 +1,34 @@
#ifndef APPLICATION_H
#define APPLICATION_H
#include "object.h"
#include "common.h"
#include <Windows.h>
class Widget;
class Application : public Object
{
public:
Application(HINSTANCE hInstance, PWSTR cmdline, int cmdshow);
Application(const Application&) = delete;
~Application();
Application& operator=(const Application&) = delete;
static Application *instance();
HINSTANCE moduleHandle();
void setLayoutDirection(LayoutDirection);
int exec();
void exit(int);
private:
Application();
friend class Widget;
void registerWidget(Widget*, ObjectType, const Rect &rc);
class ApplicationPrivate;
ApplicationPrivate *d_ptr;
static Application *inst;
};
#endif // APPLICATION_H

View File

@ -0,0 +1,79 @@
#include "baseutils.h"
static int getLuma(COLORREF color)
{
return int(0.299 * GetRValue(color) + 0.587 * GetGValue(color) + 0.114 * GetBValue(color));
}
Utils::WinVer Utils::getWinVersion()
{
static WinVer winVer = WinVer::Undef;
if (winVer == WinVer::Undef) {
if (HMODULE module = GetModuleHandleA("ntdll")) {
NTSTATUS(WINAPI *RtlGetVersion)(LPOSVERSIONINFOEXW);
*(FARPROC*)&RtlGetVersion = GetProcAddress(module, "RtlGetVersion");
if (RtlGetVersion) {
OSVERSIONINFOEXW os = {0};
os.dwOSVersionInfoSize = sizeof(os);
RtlGetVersion(&os);
#define MjrVer os.dwMajorVersion
#define MinVer os.dwMinorVersion
#define BldVer os.dwBuildNumber
winVer = MjrVer == 5L && (MinVer == 1L || MinVer == 2L) ? WinVer::WinXP :
MjrVer == 6L && MinVer == 0L ? WinVer::WinVista :
MjrVer == 6L && MinVer == 1L ? WinVer::Win7 :
MjrVer == 6L && MinVer == 2L ? WinVer::Win8 :
MjrVer == 6L && MinVer == 3L ? WinVer::Win8_1 :
MjrVer == 10L && MinVer == 0L && BldVer < 22000 ? WinVer::Win10 :
MjrVer == 10L && MinVer == 0L && BldVer >= 22000 ? WinVer::Win11 :
MjrVer == 10L && MinVer > 0L ? WinVer::Win11 :
MjrVer > 10L ? WinVer::Win11 : WinVer::Undef;
}
}
}
return winVer;
}
COLORREF Utils::getColorizationColor(bool isActive, COLORREF topColor)
{
HKEY hKey;
DWORD dwValue = 0;
if (RegOpenKeyEx(HKEY_CURRENT_USER, L"SOFTWARE\\Microsoft\\Windows\\DWM", 0, KEY_READ, &hKey) == ERROR_SUCCESS) {
DWORD dwType = REG_DWORD;
DWORD dwSize = sizeof(DWORD);
if (RegQueryValueEx(hKey, L"ColorPrevalence", nullptr, &dwType, (LPBYTE)&dwValue, &dwSize) == ERROR_SUCCESS) {
}
RegCloseKey(hKey);
}
if (isActive && dwValue != 0) {
DWORD dwcolor = 0;
BOOL opaque = TRUE;
HRESULT(WINAPI *DwmGetColorizationColor)(DWORD*, BOOL*) = NULL;
if (HMODULE module = LoadLibrary(L"dwmapi")) {
*(FARPROC*)&DwmGetColorizationColor = GetProcAddress(module, "DwmGetColorizationColor");
if (DwmGetColorizationColor && !SUCCEEDED(DwmGetColorizationColor(&dwcolor, &opaque))) {
dwcolor = 0;
}
FreeLibrary(module);
if (dwcolor)
return RGB((dwcolor & 0xff0000) >> 16, (dwcolor & 0xff00) >> 8, dwcolor & 0xff);
}
}
#define BORDER_ACTIVE_DARK RGB(0x2a, 0x2a, 0x2a) // Dark theme
#define BORDER_INACTIVE_DARK RGB(0x3a, 0x3a, 0x3a)
#define BORDER_ACTIVE_LIGHT_V1 RGB(0x58, 0x58, 0x58) // Light theme and colored background
#define BORDER_ACTIVE_LIGHT_V2 RGB(0x77, 0x77, 0x77) // Light theme and white background
#define BORDER_INACTIVE_LIGHT_V1 RGB(0x60, 0x60, 0x60)
#define BORDER_INACTIVE_LIGHT_V2 RGB(0xaa, 0xaa, 0xaa)
int luma = getLuma(topColor);
COLORREF color = luma < 85 ? (isActive ? BORDER_ACTIVE_DARK : BORDER_INACTIVE_DARK) :
luma < 170 ? (isActive ? BORDER_ACTIVE_LIGHT_V1 : BORDER_INACTIVE_LIGHT_V1) :
(isActive ? BORDER_ACTIVE_LIGHT_V2 : BORDER_INACTIVE_LIGHT_V2);
return color;
}
bool Utils::isColorDark(COLORREF color)
{
return int(0.299 * GetRValue(color) + 0.587 * GetGValue(color) + 0.114 * GetBValue(color)) < 128;
}

View File

@ -0,0 +1,17 @@
#ifndef BASEUTILS_H
#define BASEUTILS_H
#include <Windows.h>
namespace Utils
{
enum WinVer : BYTE {
Undef, WinXP, WinVista, Win7, Win8, Win8_1, Win10, Win11
};
WinVer getWinVersion();
bool isColorDark(COLORREF color);
COLORREF getColorizationColor(bool isActive = true, COLORREF topColor = 0x00ffffff);
};
#endif // BASEUTILS_H

View File

@ -0,0 +1,211 @@
#include "boxlayout.h"
#include "widget.h"
#include <cmath>
BoxLayout::BoxLayout(Direction direction) :
m_direction(direction)
{
m_margins = Margins(6,6,6,6);
m_spacing = 6;
}
BoxLayout::~BoxLayout()
{
for (auto it = m_destroy_conn.begin(); it != m_destroy_conn.end(); it++)
it->first->disconnect(it->second);
}
void BoxLayout::addWidget(Widget *wgt)
{
m_widgets.push_back(wgt);
// int destroy_conn = wgt->onAboutToDestroy([=]() {
// auto it = std::find(m_widgets.begin(), m_widgets.end(), wgt);
// if (it != m_widgets.end())
// m_widgets.erase(it);
// auto it_conn = m_destroy_conn.find(wgt);
// if (it_conn != m_destroy_conn.end())
// m_destroy_conn.erase(it_conn);
// });
// m_destroy_conn[wgt] = destroy_conn;
}
void BoxLayout::setContentMargins(int left, int top, int right, int bottom)
{
m_margins = Margins(left, top, right, bottom);
}
void BoxLayout::setSpacing(int spacing)
{
m_spacing = spacing;
}
void BoxLayout::onResize(int w, int h)
{
int amount = m_widgets.size();
if (amount > 0) {
int x = m_margins.left;
int y = m_margins.top;
int sum_width = w - (m_margins.right + m_margins.left);
int sum_height = h - (m_margins.bottom + m_margins.top);
int num_fixed = 0;
int sum_fixed_width_or_height = 0;
int last_expanding = -1;
if (m_direction == Horizontal) {
sum_width -= (amount - 1) * m_spacing;
for (int i = 0; i < amount; i++) {
Widget::SizeBehavior sb = (Widget::SizeBehavior)m_widgets[i]->property(Widget::HSizeBehavior);
if (sb == Widget::SizeBehavior::Fixed) {
int _w = 0, _h = 0;
m_widgets[i]->size(&_w, &_h);
sum_fixed_width_or_height += _w;
++num_fixed;
} else
if (sb == Widget::SizeBehavior::Expanding) {
last_expanding = i;
}
}
if (num_fixed != 0 && last_expanding != -1) {
int sep_width = (int)std::round((float)(sum_width - sum_fixed_width_or_height)/(amount - num_fixed));
for (int i = 0; i < amount; i++) {
if (i == last_expanding)
sep_width = (sum_width - sum_fixed_width_or_height) - (amount - num_fixed - 1)*sep_width;
int _w = 0, _h = 0;
m_widgets[i]->size(&_w, &_h);
Widget::SizeBehavior hsb = (Widget::SizeBehavior)m_widgets[i]->property(Widget::HSizeBehavior);
Widget::SizeBehavior vsb = (Widget::SizeBehavior)m_widgets[i]->property(Widget::VSizeBehavior);
if (hsb == Widget::SizeBehavior::Fixed) {
if (vsb == Widget::SizeBehavior::Fixed) {
m_widgets[i]->move(x, y);
} else
if (vsb == Widget::SizeBehavior::Expanding) {
m_widgets[i]->setGeometry(x, y, _w, sum_height);
}
x += _w + m_spacing;
} else
if (hsb == Widget::SizeBehavior::Expanding) {
if (vsb == Widget::SizeBehavior::Fixed) {
m_widgets[i]->setGeometry(x, y, sep_width, _h);
} else
if (vsb == Widget::SizeBehavior::Expanding) {
m_widgets[i]->setGeometry(x, y, sep_width, sum_height);
}
x += sep_width + m_spacing;
}
}
} else {
int sep_width = (int)std::round((float)sum_width/amount);
for (int i = 0; i < amount; i++) {
if (i == amount - 1)
sep_width = sum_width - i*sep_width;
Widget::SizeBehavior hsb = (Widget::SizeBehavior)m_widgets[i]->property(Widget::HSizeBehavior);
Widget::SizeBehavior vsb = (Widget::SizeBehavior)m_widgets[i]->property(Widget::VSizeBehavior);
if (hsb == Widget::SizeBehavior::Fixed) {
if (vsb == Widget::SizeBehavior::Fixed) {
m_widgets[i]->move(x, y);
} else
if (vsb == Widget::SizeBehavior::Expanding) {
int _w = 0, _h = 0;
m_widgets[i]->size(&_w, &_h);
m_widgets[i]->setGeometry(x, y, _w, sum_height);
}
} else
if (hsb == Widget::SizeBehavior::Expanding) {
if (vsb == Widget::SizeBehavior::Fixed) {
int _w = 0, _h = 0;
m_widgets[i]->size(&_w, &_h);
m_widgets[i]->setGeometry(x, y, sep_width, _h);
} else
if (vsb == Widget::SizeBehavior::Expanding) {
m_widgets[i]->setGeometry(x, y, sep_width, sum_height);
}
}
x += sep_width + m_spacing;
}
}
} else {
sum_height -= (amount - 1) * m_spacing;
for (int i = 0; i < amount; i++) {
Widget::SizeBehavior sb = (Widget::SizeBehavior)m_widgets[i]->property(Widget::VSizeBehavior);
if (sb == Widget::SizeBehavior::Fixed) {
int _w = 0, _h = 0;
m_widgets[i]->size(&_w, &_h);
sum_fixed_width_or_height += _h;
++num_fixed;
} else
if (sb == Widget::SizeBehavior::Expanding) {
last_expanding = i;
}
}
if (num_fixed != 0 && last_expanding != -1) {
int sep_height = (int)std::round((float)(sum_height - sum_fixed_width_or_height)/(amount - num_fixed));
for (int i = 0; i < amount; i++) {
if (i == last_expanding)
sep_height = (sum_height - sum_fixed_width_or_height) - (amount - num_fixed - 1)*sep_height;
int _w = 0, _h = 0;
m_widgets[i]->size(&_w, &_h);
Widget::SizeBehavior hsb = (Widget::SizeBehavior)m_widgets[i]->property(Widget::HSizeBehavior);
Widget::SizeBehavior vsb = (Widget::SizeBehavior)m_widgets[i]->property(Widget::VSizeBehavior);
if (vsb == Widget::SizeBehavior::Fixed) {
if (hsb == Widget::SizeBehavior::Fixed) {
m_widgets[i]->move(x, y);
} else
if (hsb == Widget::SizeBehavior::Expanding) {
m_widgets[i]->setGeometry(x, y, sum_width, _h);
}
y += _h + m_spacing;
} else
if (vsb == Widget::SizeBehavior::Expanding) {
if (hsb == Widget::SizeBehavior::Fixed) {
m_widgets[i]->setGeometry(x, y, _w, sep_height);
} else
if (hsb == Widget::SizeBehavior::Expanding) {
m_widgets[i]->setGeometry(x, y, sum_width, sep_height);
}
y += sep_height + m_spacing;
}
}
} else {
int sep_height = (int)std::round((float)sum_height/amount);
for (int i = 0; i < amount; i++) {
if (i == amount - 1)
sep_height = sum_height - i*sep_height;
Widget::SizeBehavior hsb = (Widget::SizeBehavior)m_widgets[i]->property(Widget::HSizeBehavior);
Widget::SizeBehavior vsb = (Widget::SizeBehavior)m_widgets[i]->property(Widget::VSizeBehavior);
if (vsb == Widget::SizeBehavior::Fixed) {
if (hsb == Widget::SizeBehavior::Fixed) {
m_widgets[i]->move(x, y);
} else
if (hsb == Widget::SizeBehavior::Expanding) {
int _w = 0, _h = 0;
m_widgets[i]->size(&_w, &_h);
m_widgets[i]->setGeometry(x, y, sum_width, _h);
}
} else
if (vsb == Widget::SizeBehavior::Expanding) {
if (hsb == Widget::SizeBehavior::Fixed) {
int _w = 0, _h = 0;
m_widgets[i]->size(&_w, &_h);
m_widgets[i]->setGeometry(x, y, _w, sep_height);
} else
if (hsb == Widget::SizeBehavior::Expanding) {
m_widgets[i]->setGeometry(x, y, sum_width, sep_height);
}
}
y += sep_height + m_spacing;
}
}
}
}
}

View File

@ -0,0 +1,33 @@
#ifndef BOXLAYOUT_H
#define BOXLAYOUT_H
#include "layout.h"
#include <unordered_map>
class BoxLayout : public Layout
{
public:
enum Direction : unsigned char {
Horizontal,
Vertical
};
BoxLayout(Direction);
~BoxLayout();
virtual void addWidget(Widget *wgt) override;
virtual void setContentMargins(int, int, int, int);
virtual void setSpacing(int);
protected:
private:
virtual void onResize(int w, int h) override;
std::unordered_map<Widget*, int> m_destroy_conn;
std::vector<Widget*> m_widgets;
Direction m_direction;
int m_spacing;
int m_total_fixed_size;
};
#endif // BOXLAYOUT_H

View File

@ -0,0 +1,197 @@
#include "button.h"
#include "baseutils.h"
#include "drawningengine.h"
#include "metrics.h"
#include "palette.h"
#include <windowsx.h>
static bool isArrangingAllowed() {
BOOL arranging = FALSE;
SystemParametersInfoA(SPI_GETWINARRANGING, 0, &arranging, 0);
return (arranging == TRUE);
}
Button::Button(Widget *parent, const std::wstring &text) :
AbstractButton(parent, text),
m_hIcon(nullptr),
m_hMetaFile(nullptr),
m_stockIcon(StockIcon::None),
supportSnapLayouts(false),
snapLayoutAllowed(false),
snapLayoutTimerIsSet(false)
{
}
Button::~Button()
{
if (m_hIcon) {
DestroyIcon(m_hIcon);
m_hIcon = nullptr;
}
if (m_hMetaFile) {
//delete m_hMetaFile;
DeleteEnhMetaFile(m_hMetaFile);
m_hMetaFile = nullptr;
}
}
void Button::setIcon(const std::wstring &path, int w, int h)
{
if (m_hIcon) {
DestroyIcon(m_hIcon);
m_hIcon = nullptr;
}
metrics()->setMetrics(Metrics::IconWidth, w);
metrics()->setMetrics(Metrics::IconHeight, h);
m_hIcon = (HICON)LoadImage(NULL, path.c_str(), IMAGE_ICON, w, h, LR_LOADFROMFILE | LR_DEFAULTCOLOR | LR_SHARED);
update();
}
void Button::setIcon(int id, int w, int h)
{
if (m_hIcon) {
DestroyIcon(m_hIcon);
m_hIcon = nullptr;
}
metrics()->setMetrics(Metrics::IconWidth, w);
metrics()->setMetrics(Metrics::IconHeight, h);
HMODULE hInst = GetModuleHandle(NULL);
m_hIcon = (HICON)LoadImage(hInst, MAKEINTRESOURCE(id), IMAGE_ICON, w, h, LR_COPYFROMRESOURCE | LR_DEFAULTCOLOR | LR_SHARED);
update();
}
void Button::setEMFIcon(const std::wstring &path, int w, int h)
{
if (m_hMetaFile) {
//delete m_hMetaFile;
DeleteEnhMetaFile(m_hMetaFile);
m_hMetaFile = nullptr;
}
metrics()->setMetrics(Metrics::IconWidth, w);
metrics()->setMetrics(Metrics::IconHeight, h);
m_hMetaFile = GetEnhMetaFile(path.c_str());
//m_hMetaFile = new Metafile(path.c_str());
update();
}
void Button::setEMFIcon(int id, int w, int h)
{
if (m_hMetaFile) {
//delete m_hMetaFile;
DeleteEnhMetaFile(m_hMetaFile);
m_hMetaFile = nullptr;
}
metrics()->setMetrics(Metrics::IconWidth, w);
metrics()->setMetrics(Metrics::IconHeight, h);
HMODULE hInst = GetModuleHandle(NULL);
if (HRSRC hRes = FindResource(hInst, MAKEINTRESOURCE(id), RT_RCDATA)) {
if (HGLOBAL hResData = LoadResource(hInst, hRes)) {
if (LPVOID pData = LockResource(hResData)) {
DWORD dataSize = SizeofResource(hInst, hRes);
if (dataSize > 0)
m_hMetaFile = SetEnhMetaFileBits(dataSize, (BYTE*)pData);
}
FreeResource(hResData);
}
}
update();
}
void Button::setIconSize(int w, int h)
{
metrics()->setMetrics(Metrics::IconWidth, w);
metrics()->setMetrics(Metrics::IconHeight, h);
update();
}
void Button::setSupportSnapLayouts()
{
if (Utils::getWinVersion() > Utils::WinVer::Win10) {
snapLayoutAllowed = isArrangingAllowed();
supportSnapLayouts = true;
}
}
void Button::setStockIcon(StockIcon stockIcon)
{
m_stockIcon = stockIcon;
update();
}
bool Button::event(UINT msg, WPARAM wParam, LPARAM lParam, LRESULT *result)
{
switch (msg) {
case WM_PAINT: {
RECT rc;
GetClientRect(m_hWnd, &rc);
engine()->Begin(this, m_hWnd, &rc);
engine()->FillBackground();
// engine()->DrawRoundedRect();
if (metrics()->value(Metrics::BorderWidth) != 0)
engine()->DrawBorder();
if (m_hIcon)
engine()->DrawIcon(m_hIcon);
if (m_hMetaFile)
engine()->DrawEmfIcon(m_hMetaFile);
if (!m_text.empty())
engine()->DrawText(rc, m_text);
if (m_stockIcon == StockIcon::CloseIcon)
engine()->DrawStockCloseIcon();
else
if (m_stockIcon == StockIcon::RestoreIcon)
engine()->DrawStockRestoreIcon();
else
if (m_stockIcon == StockIcon::MinimizeIcon)
engine()->DrawStockMinimizeIcon();
else
if (m_stockIcon == StockIcon::MaximizeIcon)
engine()->DrawStockMaximizeIcon();
engine()->End();
*result = FALSE;
return true;
}
case WM_NCHITTEST: {
if (supportSnapLayouts && snapLayoutAllowed) {
if (!snapLayoutTimerIsSet) {
snapLayoutTimerIsSet = true;
palette()->setCurrentState(Palette::Hover);
SetTimer(m_hWnd, SNAP_LAYOUTS_TIMER_ID, 100, NULL);
repaint();
}
*result = HTMAXBUTTON;
return true;
}
return false;
}
case WM_TIMER: {
if (wParam == SNAP_LAYOUTS_TIMER_ID) {
if (!underMouse()) {
KillTimer(m_hWnd, wParam);
snapLayoutTimerIsSet = false;
palette()->setCurrentState(Palette::Normal);
repaint();
}
}
break;
}
case WM_CAPTURECHANGED: {
if (Utils::getWinVersion() > Utils::WinVer::Win10) {
click();
}
break;
}
default:
break;
}
return AbstractButton::event(msg, wParam, lParam, result);
}

View File

@ -0,0 +1,45 @@
#ifndef BUTTON_H
#define BUTTON_H
#include "abstractbutton.h"
#include <gdiplus.h>
class Button : public AbstractButton
{
public:
Button(Widget *parent = nullptr, const std::wstring &text = L"");
virtual ~Button();
enum StockIcon : BYTE {
None,
MinimizeIcon,
MaximizeIcon,
RestoreIcon,
CloseIcon
};
void setIcon(const std::wstring &path, int w, int h);
void setIcon(int id, int w, int h);
void setEMFIcon(const std::wstring &path, int w, int h);
void setEMFIcon(int id, int w, int h);
void setIconSize(int w, int h);
void setSupportSnapLayouts();
void setStockIcon(StockIcon stockIcon);
/* callback */
protected:
virtual bool event(UINT, WPARAM, LPARAM, LRESULT*) override;
private:
HICON m_hIcon;
HENHMETAFILE m_hMetaFile;
//Gdiplus::Metafile *m_hMetaFile;
int m_stockIcon;
bool supportSnapLayouts,
snapLayoutAllowed;
bool snapLayoutTimerIsSet;
};
#endif // BUTTON_H

View File

@ -0,0 +1,117 @@
#include "caption.h"
#include "baseutils.h"
#include "metrics.h"
#include "drawningengine.h"
#include <windowsx.h>
#define RESIZE_AREA_PART 0.14
Caption::Caption(Widget *parent) :
Label(parent),
m_isResizingAvailable(true)
{
m_hwndRoot = GetAncestor(m_hWnd, GA_ROOT);
}
Caption::~Caption()
{
}
void Caption::setResizingAvailable(bool isResizingAvailable)
{
m_isResizingAvailable = isResizingAvailable;
}
bool Caption::event(UINT msg, WPARAM wParam, LPARAM lParam, LRESULT *result)
{
switch (msg) {
case WM_PAINT: {
RECT rc;
GetClientRect(m_hWnd, &rc);
engine()->Begin(this, m_hWnd, &rc);
engine()->FillBackground();
// DrawRoundedRect();
if (metrics()->value(Metrics::BorderWidth) != 0)
engine()->DrawBorder();
if (!m_title.empty())
engine()->DrawText(rc, m_title);
engine()->End();
*result = FALSE;
return true;
}
case WM_LBUTTONDOWN:
case WM_NCLBUTTONDOWN: {
if (isResizingAvailable()) {
int y = GET_Y_LPARAM(lParam);
if (HCURSOR hCursor = LoadCursor(NULL, isPointInResizeArea(y) ? IDC_SIZENS : IDC_ARROW))
SetCursor(hCursor);
}
if (postMsg(WM_NCLBUTTONDOWN)) {
*result = TRUE;
return true;
}
return false;
}
case WM_LBUTTONDBLCLK: {
if (postMsg(WM_NCLBUTTONDBLCLK)) {
*result = TRUE;
return true;
}
return false;
}
case WM_MOUSEMOVE:
case WM_NCMOUSEMOVE: {
if (isResizingAvailable()) {
int y = GET_Y_LPARAM(lParam);
if (HCURSOR hCursor = LoadCursor(NULL, isPointInResizeArea(y) ? IDC_SIZENS : IDC_ARROW))
SetCursor(hCursor);
}
break;
}
case WM_MOUSEENTER: {
//palette()->setCurrentState(Palette::Hover);
repaint();
break;
}
case WM_MOUSELEAVE: {
//palette()->setCurrentState(Palette::Normal);
repaint();
break;
}
default:
break;
}
return Widget::event(msg, wParam, lParam, result);
}
bool Caption::isResizingAvailable()
{
return m_isResizingAvailable && Utils::getWinVersion() >= Utils::WinVer::Win10 && !IsZoomed(m_hwndRoot);
}
bool Caption::isPointInResizeArea(int posY)
{
int w = 0, h = 0;
size(&w, &h);
return posY <= RESIZE_AREA_PART * h;
}
bool Caption::postMsg(DWORD cmd) {
POINT pt;
::GetCursorPos(&pt);
ScreenToClient(m_hWnd, &pt);
::ReleaseCapture();
::PostMessage(m_hwndRoot, cmd, isResizingAvailable() && isPointInResizeArea(pt.y) ? HTTOP : HTCAPTION, POINTTOPOINTS(pt));
return true;
}

View File

@ -0,0 +1,30 @@
#ifndef CAPTION_H
#define CAPTION_H
#include "label.h"
#include <Windows.h>
class Caption : public Label
{
public:
Caption(Widget *parent = nullptr);
~Caption();
void setResizingAvailable(bool);
/* callback */
protected:
virtual bool event(UINT, WPARAM, LPARAM, LRESULT*) override;
private:
bool isResizingAvailable();
bool isPointInResizeArea(int posY);
bool postMsg(DWORD cmd);
HWND m_hwndRoot;
bool m_isResizingAvailable;
};
#endif // CAPTION_H

View File

@ -0,0 +1,59 @@
#include "checkbox.h"
#include "drawningengine.h"
#include "metrics.h"
#include <windowsx.h>
CheckBox::CheckBox(Widget *parent, const std::wstring &text) :
AbstractButton(parent, text),
m_checked(false)
{
metrics()->setMetrics(Metrics::TextAlignment, Metrics::AlignHLeft | Metrics::AlignVCenter);
}
CheckBox::~CheckBox()
{
}
void CheckBox::setChecked(bool checked)
{
m_checked = checked;
update();
}
bool CheckBox::isChecked()
{
return m_checked;
}
bool CheckBox::event(UINT msg, WPARAM wParam, LPARAM lParam, LRESULT *result)
{
switch (msg) {
case WM_PAINT: {
RECT rc;
GetClientRect(m_hWnd, &rc);
engine()->Begin(this, m_hWnd, &rc);
engine()->DrawCheckBox(m_text, m_checked);
if (metrics()->value(Metrics::BorderWidth) != 0)
engine()->DrawBorder();
engine()->End();
*result = FALSE;
return true;
}
default:
break;
}
return AbstractButton::event(msg, wParam, lParam, result);
}
void CheckBox::click()
{
m_checked = !m_checked;
update();
AbstractButton::click();
}

View File

@ -0,0 +1,26 @@
#ifndef CHECKBOX_H
#define CHECKBOX_H
#include "abstractbutton.h"
class CheckBox : public AbstractButton
{
public:
CheckBox(Widget *parent = nullptr, const std::wstring &text = L"");
virtual ~CheckBox();
void setChecked(bool checked);
bool isChecked();
/* callback */
protected:
virtual bool event(UINT, WPARAM, LPARAM, LRESULT*) override;
virtual void click() override;
private:
bool m_checked;
};
#endif // CHECKBOX_H

View File

@ -0,0 +1,81 @@
#include "common.h"
Margins::Margins() :
left(0), top(0), right(0), bottom(0)
{}
Margins::Margins(int l, int t, int r, int b) :
left(l), top(t), right(r), bottom(b)
{}
Margins::Margins(const Margins &mrg)
{
left = mrg.left;
top = mrg.top;
right = mrg.right;
bottom = mrg.bottom;
}
Margins& Margins::operator=(const Margins &mrg)
{
if (this == &mrg)
return *this;
left = mrg.left;
top = mrg.top;
right = mrg.right;
bottom = mrg.bottom;
return *this;
}
Rect::Rect() :
x(0), y(0), width(0), height(0)
{}
Rect::Rect(int x, int y, int w, int h) :
x(x), y(y), width(w), height(h)
{}
Rect::Rect(const Rect &rc)
{
x = rc.x;
y = rc.y;
width = rc.width;
height = rc.height;
}
Rect& Rect::operator=(const Rect &rc)
{
if (this == &rc)
return *this;
x = rc.x;
y = rc.y;
width = rc.width;
height = rc.height;
return *this;
}
Size::Size() :
width(0), height(0)
{}
Size::Size(int w, int h) :
width(w), height(h)
{}
Size::Size(const Size &sz)
{
width = sz.width;
height = sz.height;
}
Size& Size::operator=(const Size &sz)
{
if (this == &sz)
return *this;
width = sz.width;
height = sz.height;
return *this;
}

View File

@ -0,0 +1,37 @@
#ifndef COMMON_H
#define COMMON_H
struct Margins {
Margins();
Margins(int, int, int, int);
Margins(const Margins&);
Margins& operator=(const Margins&);
int left, top, right, bottom;
};
struct Rect {
Rect();
Rect(int, int, int, int);
Rect(const Rect &rc);
Rect& operator=(const Rect &rc);
int x, y, width, height;
};
struct Size {
Size();
Size(int, int);
Size(const Size&);
Size& operator=(const Size&);
int width, height;
};
enum LayoutDirection : unsigned char {
LeftToRight = 0,
RightToLeft
};
#endif // COMMON_H

View File

@ -0,0 +1,17 @@
#ifndef COMMONDEFINES_H
#define COMMONDEFINES_H
#include <functional>
#define SNAP_LAYOUTS_TIMER_ID 0x1f000000
#define PROGRESS_PULSE_TIMER_ID 0x2f000000
#define WM_MOUSEENTER (WM_APP + 1)
#define WM_INVOKEMETHOD (WM_APP + 2)
typedef std::function<void(void)> FnVoidVoid;
typedef std::function<void(int)> FnVoidInt;
typedef std::function<void(int, int)> FnVoidIntInt;
typedef std::function<void(bool*)> FnVoidBoolPtr;
#endif // COMMONDEFINES_H

View File

@ -0,0 +1,76 @@
#include "dialog.h"
#include "metrics.h"
#include "palette.h"
#include "drawningengine.h"
Dialog::Dialog(Widget *parent, const Rect &rc) :
Widget(parent, ObjectType::DialogType, rc)
{
}
Dialog::~Dialog()
{
}
bool Dialog::event(UINT msg, WPARAM wParam, LPARAM lParam, LRESULT *result)
{
switch (msg) {
case WM_SHOWWINDOW: {
if (wParam) {
if (Widget *parent = parentWidget())
EnableWindow(parent->nativeWindowHandle(), FALSE);
}
break;
}
case WM_PAINT: {
RECT rc;
GetClientRect(m_hWnd, &rc);
engine()->Begin(this, m_hWnd);
engine()->FillBackground(rc);
//engine()->DrawRoundedRect(rc);
if (metrics()->value(Metrics::BorderWidth) != 0)
engine()->DrawBorder(rc);
// if (!m_title.empty())
// engine()->DrawText(rc, m_title);
engine()->End();
*result = FALSE;
return true;
}
case WM_MOUSEENTER: {
palette()->setCurrentState(Palette::Hover);
repaint();
break;
}
case WM_NCMOUSELEAVE:
case WM_MOUSELEAVE: {
palette()->setCurrentState(Palette::Normal);
repaint();
break;
}
/*case WM_NCHITTEST: {
*result = HTCAPTION;
return true;
}*/
case WM_CLOSE: {
if (Widget *parent = parentWidget())
EnableWindow(parent->nativeWindowHandle(), TRUE);
break;
}
default:
break;
}
return Widget::event(msg, wParam, lParam, result);
}

View File

@ -0,0 +1,25 @@
#ifndef DIALOG_H
#define DIALOG_H
#include "widget.h"
#include <Windows.h>
#define DEFAULT_DLG_RECT Rect(100,100,800,600)
class Dialog : public Widget
{
public:
Dialog(Widget *parent = nullptr, const Rect &rc = DEFAULT_DLG_RECT);
virtual ~Dialog();
/* callback */
protected:
virtual bool event(UINT, WPARAM, LPARAM, LRESULT*) override;
private:
};
#endif // DIALOG_H

View File

@ -0,0 +1,33 @@
#include "drawingsurface.h"
#include "drawningengine.h"
#include "metrics.h"
#include "palette.h"
DrawningSurface::DrawningSurface() :
m_metrics(new Metrics),
m_palette(new Palette)
{
m_engine = DrawingEngine::instance();
}
DrawningSurface::~DrawningSurface()
{
delete m_palette, m_palette = nullptr;
delete m_metrics, m_metrics = nullptr;
}
Metrics *DrawningSurface::metrics()
{
return m_metrics;
}
Palette *DrawningSurface::palette()
{
return m_palette;
}
DrawingEngine *DrawningSurface::engine()
{
return m_engine;
}

View File

@ -0,0 +1,26 @@
#ifndef DRAWNINGSURFACE_H
#define DRAWNINGSURFACE_H
class Metrics;
class Palette;
class DrawingEngine;
class DrawningSurface
{
public:
DrawningSurface();
virtual ~DrawningSurface();
Metrics *metrics();
Palette *palette();
protected:
DrawingEngine *engine();
private:
Metrics *m_metrics;
Palette *m_palette;
DrawingEngine *m_engine;
};
#endif // DRAWNINGSURFACE_H

View File

@ -0,0 +1,570 @@
#include "drawningengine.h"
#include "drawingsurface.h"
#include "palette.h"
#include "metrics.h"
#include <gdiplusheaders.h>
static Gdiplus::Color ColorFromColorRef(COLORREF rgb)
{
Gdiplus::Color color;
color.SetFromCOLORREF(rgb);
return color;
}
static void RoundedPath(Gdiplus::GraphicsPath &ph, int x, int y, int width, int height, int rad)
{
ph.AddArc(x, y, rad * 2, rad * 2, 180, 90);
ph.AddLine(x + rad, y, x + width - rad, y);
ph.AddArc(x + width - rad * 2, y, rad * 2, rad * 2, 270, 90);
ph.AddLine(x + width, y + rad, x + width, y + height - rad);
ph.AddArc(x + width - rad * 2, y + height - rad * 2, rad * 2, rad * 2, 0, 90);
ph.AddLine(x + width - rad, y + height, x + rad, y + height);
ph.AddArc(x, y + height - rad * 2, rad * 2, rad * 2, 90, 90);
ph.AddLine(x, y + height - rad, x, y + rad);
ph.CloseFigure();
}
DrawingEngine::DrawingEngine() :
m_ds(nullptr),
m_ps(nullptr),
m_hwnd(nullptr),
m_hdc(nullptr),
m_memDC(nullptr),
m_memBmp(nullptr),
m_oldBmp(nullptr),
m_graphics(nullptr)
{
}
DrawingEngine* DrawingEngine::instance()
{
static DrawingEngine inst;
return &inst;
}
DrawingEngine::~DrawingEngine()
{
}
DrawningSurface *DrawingEngine::surface()
{
return m_ds;
}
void DrawingEngine::Begin(DrawningSurface *ds, HWND hwnd, RECT *rc)
{
if (m_ds) {
printf("Engine is buisy...\n");
fflush(stdout);
return;
}
m_ds = ds;
m_rc = rc;
m_hwnd = hwnd;
m_ps = new PAINTSTRUCT;
m_hdc = BeginPaint(hwnd, m_ps);
}
void DrawingEngine::FillBackground() const
{
HBRUSH bkgBrush = CreateSolidBrush(m_ds->palette()->color(Palette::Background));
HBRUSH oldBkgBrush = (HBRUSH)SelectObject(m_hdc, bkgBrush);
FillRect(m_hdc, m_rc, bkgBrush);
SelectObject(m_hdc, oldBkgBrush);
DeleteObject(bkgBrush);
}
// void DrawingEngine::DrawRoundedRect()
// {
// int x = m_rc->left + m_ds->metrics()->value(Metrics::BorderWidth) - 1;
// int y = m_rc->top + m_ds->metrics()->value(Metrics::BorderWidth) - 1;
// int width = m_rc->right - m_rc->left - m_ds->metrics()->value(Metrics::BorderWidth) * 2 + 1;
// int height = m_rc->bottom - m_rc->top - m_ds->metrics()->value(Metrics::BorderWidth) * 2 + 1;
// int rad = m_ds->metrics()->value(Metrics::BorderRadius);
// m_memDC = CreateCompatibleDC(m_hdc);
// m_memBmp = CreateCompatibleBitmap(m_hdc, m_rc->right - m_rc->left, m_rc->bottom - m_rc->top);
// m_oldBmp = (HBITMAP)SelectObject(m_memDC, m_memBmp);
// m_graphics = new Gdiplus::Graphics(m_memDC);
// m_graphics->SetSmoothingMode(Gdiplus::SmoothingModeAntiAlias);
// m_graphics->Clear(ColorFromColorRef(m_ds->palette()->color(Palette::Background)));
// Gdiplus::GraphicsPath ph;
// RoundedPath(ph, x, y, width, height, rad);
// Gdiplus::SolidBrush brush(ColorFromColorRef(m_ds->palette()->color(Palette::Base)));
// m_graphics->FillPath(&brush, &ph);
// if (m_ds->metrics()->value(Metrics::BorderWidth) != 0) {
// Gdiplus::Pen pen(ColorFromColorRef(m_ds->palette()->color(Palette::Border)), m_ds->metrics()->value(Metrics::BorderWidth));
// m_graphics->DrawPath(&pen, &ph);
// }
// BitBlt(m_hdc, m_rc->left, m_rc->top, m_rc->right - m_rc->left, m_rc->bottom - m_rc->top, m_memDC, 0, 0, SRCCOPY);
// delete m_graphics;
// m_graphics = nullptr;
// SelectObject(m_memDC, m_oldBmp);
// m_oldBmp = nullptr;
// DeleteObject(m_memBmp);
// m_memBmp = nullptr;
// DeleteDC(m_memDC);
// m_memDC = nullptr;
// }
void DrawingEngine::DrawBorder() const
{
HPEN hPen = CreatePen(PS_SOLID, m_ds->metrics()->value(Metrics::BorderWidth), m_ds->palette()->color(Palette::Border));
HPEN oldPen = (HPEN)SelectObject(m_hdc, hPen);
MoveToEx(m_hdc, m_rc->left, m_rc->top, NULL);
LineTo(m_hdc, m_rc->right - 1, m_rc->top);
LineTo(m_hdc, m_rc->right - 1, m_rc->bottom - 1);
LineTo(m_hdc, m_rc->left, m_rc->bottom - 1);
LineTo(m_hdc, m_rc->left, m_rc->top);
SelectObject(m_hdc, oldPen);
DeleteObject(hPen);
}
void DrawingEngine::DrawTopBorder(int brdWidth, COLORREF brdColor) const
{
HPEN pen = CreatePen(PS_SOLID, brdWidth, brdColor);
HPEN oldPen = (HPEN)SelectObject(m_hdc, pen);
MoveToEx(m_hdc, m_rc->left, m_rc->top, NULL);
LineTo(m_hdc, m_rc->right, m_rc->top);
SelectObject(m_hdc, oldPen);
DeleteObject(pen);
}
void DrawingEngine::DrawIcon(HICON hIcon) const
{
int x = m_rc->left + (m_rc->right - m_rc->left - m_ds->metrics()->value(Metrics::IconWidth)) / 2;
int y = m_rc->top + (m_rc->bottom - m_rc->top - m_ds->metrics()->value(Metrics::IconHeight)) / 2;
DrawIconEx(m_hdc, x, y, hIcon, m_ds->metrics()->value(Metrics::IconWidth), m_ds->metrics()->value(Metrics::IconHeight), 0, NULL, DI_NORMAL);
}
void DrawingEngine::DrawEmfIcon(HENHMETAFILE hIcon) const
{
int x = m_rc->left + (m_rc->right - m_rc->left - m_ds->metrics()->value(Metrics::IconWidth)) / 2;
int y = m_rc->top + (m_rc->bottom - m_rc->top - m_ds->metrics()->value(Metrics::IconHeight)) / 2;
RECT _rc{x, y, x + m_ds->metrics()->value(Metrics::IconWidth), y + m_ds->metrics()->value(Metrics::IconHeight)};
SetGraphicsMode(m_hdc, GM_ADVANCED);
SetPolyFillMode(m_hdc, WINDING);
SetStretchBltMode(m_hdc, HALFTONE);
SetBrushOrgEx(m_hdc, 0, 0, nullptr);
PlayEnhMetaFile(m_hdc, hIcon, &_rc);
// Gdiplus::Graphics gr(m_hdc);
// gr.SetInterpolationMode(Gdiplus::InterpolationModeBilinear);
// gr.SetPixelOffsetMode(Gdiplus::PixelOffsetModeHighQuality);
// gr.SetSmoothingMode(Gdiplus::SmoothingMode::SmoothingModeAntiAlias);
// int x = m_rc->left + (m_rc->right - m_rc->left - m_ds->metrics()->value(Metrics::IconWidth)) / 2;
// int y = m_rc->top + (m_rc->bottom - m_rc->top - m_ds->metrics()->value(Metrics::IconHeight)) / 2;
// Gdiplus::Metafile mf(hIcon);
// mf.ConvertToEmfPlus(&gr, NULL , Gdiplus::EmfTypeEmfPlusOnly, NULL);
// gr.DrawImage(&mf, x, y, m_ds->metrics()->value(Metrics::IconWidth), m_ds->metrics()->value(Metrics::IconHeight));
}
void DrawingEngine::DrawImage(Gdiplus::Bitmap *hBmp) const
{
int x = m_rc->left + (m_rc->right - m_rc->left - m_ds->metrics()->value(Metrics::IconWidth)) / 2;
int y = m_rc->top + (m_rc->bottom - m_rc->top - m_ds->metrics()->value(Metrics::IconHeight)) / 2;
Gdiplus::Graphics gr(m_hdc);
gr.SetInterpolationMode(Gdiplus::InterpolationModeBilinear);
gr.SetPixelOffsetMode(Gdiplus::PixelOffsetModeHighQuality);
gr.SetSmoothingMode(Gdiplus::SmoothingModeAntiAlias);
gr.DrawImage(hBmp, x, y, m_ds->metrics()->value(Metrics::IconWidth), m_ds->metrics()->value(Metrics::IconHeight));
}
void DrawingEngine::DrawStockCloseIcon()
{
HPEN hPen = CreatePen(PS_SOLID, m_ds->metrics()->value(Metrics::PrimitiveWidth), m_ds->palette()->color(Palette::Primitive));
HPEN oldPen = (HPEN)SelectObject(m_hdc, hPen);
int x = m_rc->left + (m_rc->right - m_rc->left)/2;
int y = m_rc->top + (m_rc->bottom - m_rc->top)/2;
MoveToEx(m_hdc, x, y, NULL);
LineTo(m_hdc, x + m_ds->metrics()->value(Metrics::IconWidth)/2, y + m_ds->metrics()->value(Metrics::IconHeight)/2);
MoveToEx(m_hdc, x, y, NULL);
LineTo(m_hdc, x + m_ds->metrics()->value(Metrics::IconWidth)/2, y - m_ds->metrics()->value(Metrics::IconHeight)/2);
MoveToEx(m_hdc, x, y, NULL);
LineTo(m_hdc, x - m_ds->metrics()->value(Metrics::IconWidth)/2, y + m_ds->metrics()->value(Metrics::IconHeight)/2);
MoveToEx(m_hdc, x, y, NULL);
LineTo(m_hdc, x - m_ds->metrics()->value(Metrics::IconWidth)/2, y - m_ds->metrics()->value(Metrics::IconHeight)/2);
SelectObject(m_hdc, oldPen);
DeleteObject(hPen);
}
void DrawingEngine::DrawStockMinimizeIcon()
{
HPEN hPen = CreatePen(PS_SOLID, m_ds->metrics()->value(Metrics::PrimitiveWidth), m_ds->palette()->color(Palette::Primitive));
HPEN oldPen = (HPEN)SelectObject(m_hdc, hPen);
int x = m_rc->left + (m_rc->right - m_rc->left - m_ds->metrics()->value(Metrics::IconWidth)) / 2;
int y = m_rc->top + (m_rc->bottom - m_rc->top - m_ds->metrics()->value(Metrics::IconHeight)) / 2;
MoveToEx(m_hdc, x, y + m_ds->metrics()->value(Metrics::IconHeight)/2, NULL);
LineTo(m_hdc, x + m_ds->metrics()->value(Metrics::IconWidth), y + m_ds->metrics()->value(Metrics::IconHeight)/2);
SelectObject(m_hdc, oldPen);
DeleteObject(hPen);
}
void DrawingEngine::DrawStockMaximizeIcon()
{
HPEN hPen = CreatePen(PS_SOLID, m_ds->metrics()->value(Metrics::PrimitiveWidth), m_ds->palette()->color(Palette::Primitive));
HPEN oldPen = (HPEN)SelectObject(m_hdc, hPen);
int x = m_rc->left + (m_rc->right - m_rc->left - m_ds->metrics()->value(Metrics::IconWidth)) / 2;
int y = m_rc->top + (m_rc->bottom - m_rc->top - m_ds->metrics()->value(Metrics::IconHeight)) / 2;
int quarterw = m_ds->metrics()->value(Metrics::IconWidth)/4;
int restw = m_ds->metrics()->value(Metrics::IconWidth) - quarterw;
int quarterh = m_ds->metrics()->value(Metrics::IconHeight)/4;
int resth = m_ds->metrics()->value(Metrics::IconHeight) - quarterh;
MoveToEx(m_hdc, x, y + quarterh, NULL);
LineTo(m_hdc, x + restw - 1, y + quarterh);
LineTo(m_hdc, x + restw - 1, y + m_ds->metrics()->value(Metrics::IconHeight) - 1);
LineTo(m_hdc, x, y + m_ds->metrics()->value(Metrics::IconHeight) - 1);
LineTo(m_hdc, x, y + quarterh + m_ds->metrics()->value(Metrics::PrimitiveWidth) - 1);
MoveToEx(m_hdc, x + quarterw, y + quarterh, NULL);
LineTo(m_hdc, x + quarterw, y);
LineTo(m_hdc, x + m_ds->metrics()->value(Metrics::IconWidth) - 1, y);
LineTo(m_hdc, x + m_ds->metrics()->value(Metrics::IconWidth) - 1, y + resth - 1);
LineTo(m_hdc, x + restw - 1, y + resth - 1);
SelectObject(m_hdc, oldPen);
DeleteObject(hPen);
}
void DrawingEngine::DrawStockRestoreIcon()
{
HPEN hPen = CreatePen(PS_SOLID, m_ds->metrics()->value(Metrics::PrimitiveWidth), m_ds->palette()->color(Palette::Primitive));
HPEN oldPen = (HPEN)SelectObject(m_hdc, hPen);
int x = m_rc->left + (m_rc->right - m_rc->left - m_ds->metrics()->value(Metrics::IconWidth)) / 2;
int y = m_rc->top + (m_rc->bottom - m_rc->top - m_ds->metrics()->value(Metrics::IconHeight)) / 2;
MoveToEx(m_hdc, x, y, NULL);
LineTo(m_hdc, x + m_ds->metrics()->value(Metrics::IconWidth) - 1, y);
LineTo(m_hdc, x + m_ds->metrics()->value(Metrics::IconWidth) - 1, y + m_ds->metrics()->value(Metrics::IconHeight) - 1);
LineTo(m_hdc, x, y + m_ds->metrics()->value(Metrics::IconHeight) - 1);
LineTo(m_hdc, x, y + m_ds->metrics()->value(Metrics::PrimitiveWidth) - 1);
SelectObject(m_hdc, oldPen);
DeleteObject(hPen);
}
void DrawingEngine::DrawCheckBox(const std::wstring &text, bool checked)
{
int x = m_rc->left;
int y = m_rc->top + (m_rc->bottom - m_rc->top - m_ds->metrics()->value(Metrics::IconHeight)) / 2;
m_memDC = CreateCompatibleDC(m_hdc);
m_memBmp = CreateCompatibleBitmap(m_hdc, m_rc->right - m_rc->left, m_rc->bottom - m_rc->top);
m_oldBmp = (HBITMAP)SelectObject(m_memDC, m_memBmp);
SetLayout(m_memDC, LAYOUT_BITMAPORIENTATIONPRESERVED);
m_graphics = new Gdiplus::Graphics(m_memDC);
m_graphics->SetSmoothingMode(Gdiplus::SmoothingModeDefault);
m_graphics->Clear(ColorFromColorRef(m_ds->palette()->color(Palette::Background)));
Gdiplus::Pen pen(ColorFromColorRef(m_ds->palette()->color(Palette::Primitive)), m_ds->metrics()->value(Metrics::PrimitiveWidth));
Gdiplus::Rect rc(x, y, m_ds->metrics()->value(Metrics::IconWidth) - 1, m_ds->metrics()->value(Metrics::IconHeight) - 1);
m_graphics->DrawRectangle(&pen, rc);
if (checked) {
Gdiplus::PointF pts[3] = {
Gdiplus::PointF(float(x + 2), float(y + m_ds->metrics()->value(Metrics::IconHeight)/2 - 1)),
Gdiplus::PointF(float(x + m_ds->metrics()->value(Metrics::IconWidth)/2 - 2), float(y + m_ds->metrics()->value(Metrics::IconHeight) - 5)),
Gdiplus::PointF(float(x + m_ds->metrics()->value(Metrics::IconWidth) - 3), float(y + 4))
};
m_graphics->DrawLines(&pen, pts, 3);
}
if (!text.empty()) {
RECT rc;
SetRect(&rc, m_rc->left + m_ds->metrics()->value(Metrics::IconWidth), m_rc->top, m_rc->right, m_rc->bottom);
m_graphics->SetSmoothingMode(Gdiplus::SmoothingModeAntiAlias);
LayeredDrawText(rc, text);
}
BitBlt(m_hdc, m_rc->left, m_rc->top, m_rc->right - m_rc->left, m_rc->bottom - m_rc->top, m_memDC, 0, 0, SRCCOPY);
delete m_graphics;
m_graphics = nullptr;
SelectObject(m_memDC, m_oldBmp);
m_oldBmp = nullptr;
DeleteObject(m_memBmp);
m_memBmp = nullptr;
DeleteDC(m_memDC);
m_memDC = nullptr;
// HPEN hPen = CreatePen(PS_SOLID, m_ds->metrics()->value(Metrics::PrimitiveWidth), m_ds->palette()->color(Palette::Primitive));
// HPEN oldPen = (HPEN)SelectObject(m_hdc, hPen);
// int x = m_rc->left;
// int y = m_rc->top + (m_rc->bottom - m_rc->top - m_ds->metrics()->value(Metrics::IconHeight)) / 2;
// MoveToEx(m_hdc, x, y, NULL);
// LineTo(m_hdc, x + m_ds->metrics()->value(Metrics::IconWidth) - 1, y);
// LineTo(m_hdc, x + m_ds->metrics()->value(Metrics::IconWidth) - 1, y + m_ds->metrics()->value(Metrics::IconHeight) - 1);
// LineTo(m_hdc, x, y + m_ds->metrics()->value(Metrics::IconHeight) - 1);
// LineTo(m_hdc, x, y + m_ds->metrics()->value(Metrics::PrimitiveWidth) - 1);
// if (checked) {
// MoveToEx(m_hdc, x + 2, y + m_ds->metrics()->value(Metrics::IconHeight)/2 - 1, NULL);
// LineTo(m_hdc, x + m_ds->metrics()->value(Metrics::IconWidth)/2 - 2, y + m_ds->metrics()->value(Metrics::IconHeight) - 5);
// LineTo(m_hdc, x + m_ds->metrics()->value(Metrics::IconWidth) - 2, y + 3);
// }
// SelectObject(m_hdc, oldPen);
// DeleteObject(hPen);
}
void DrawingEngine::DrawRadioButton(const std::wstring &text, bool checked)
{
int x = m_rc->left;
int y = m_rc->top + (m_rc->bottom - m_rc->top - m_ds->metrics()->value(Metrics::IconHeight)) / 2;
m_memDC = CreateCompatibleDC(m_hdc);
m_memBmp = CreateCompatibleBitmap(m_hdc, m_rc->right - m_rc->left, m_rc->bottom - m_rc->top);
m_oldBmp = (HBITMAP)SelectObject(m_memDC, m_memBmp);
SetLayout(m_memDC, LAYOUT_BITMAPORIENTATIONPRESERVED);
m_graphics = new Gdiplus::Graphics(m_memDC);
m_graphics->SetSmoothingMode(Gdiplus::SmoothingModeAntiAlias);
m_graphics->Clear(ColorFromColorRef(m_ds->palette()->color(Palette::Background)));
Gdiplus::Pen pen(ColorFromColorRef(m_ds->palette()->color(Palette::Primitive)), m_ds->metrics()->value(Metrics::PrimitiveWidth));
m_graphics->DrawEllipse(&pen, x, y, m_ds->metrics()->value(Metrics::IconHeight) - 1, m_ds->metrics()->value(Metrics::IconHeight) - 1);
if (checked) {
Gdiplus::SolidBrush chunkBrush(ColorFromColorRef(m_ds->palette()->color(Palette::Primitive)));
m_graphics->FillEllipse(&chunkBrush, x + 2, y + 2, m_ds->metrics()->value(Metrics::IconHeight) - 4 - 1, m_ds->metrics()->value(Metrics::IconHeight) - 4 - 1);
}
if (!text.empty()) {
RECT rc;
SetRect(&rc, m_rc->left + m_ds->metrics()->value(Metrics::IconWidth), m_rc->top, m_rc->right, m_rc->bottom);
LayeredDrawText(rc, text);
}
BitBlt(m_hdc, m_rc->left, m_rc->top, m_rc->right - m_rc->left, m_rc->bottom - m_rc->top, m_memDC, 0, 0, SRCCOPY);
delete m_graphics;
m_graphics = nullptr;
SelectObject(m_memDC, m_oldBmp);
m_oldBmp = nullptr;
DeleteObject(m_memBmp);
m_memBmp = nullptr;
DeleteDC(m_memDC);
m_memDC = nullptr;
}
void DrawingEngine::DrawProgressBar(int progress, int pulse_pos)
{
int x = m_rc->left + m_ds->metrics()->value(Metrics::BorderWidth) + m_ds->metrics()->value(Metrics::IconMarginLeft);
int y = m_rc->top + m_ds->metrics()->value(Metrics::BorderWidth) + m_ds->metrics()->value(Metrics::IconMarginTop);
int width = m_rc->right - m_rc->left - m_ds->metrics()->value(Metrics::BorderWidth) * 2 -
m_ds->metrics()->value(Metrics::IconMarginRight) - m_ds->metrics()->value(Metrics::IconMarginLeft) - 1;
int height = m_rc->bottom - m_rc->top - m_ds->metrics()->value(Metrics::BorderWidth) * 2 -
m_ds->metrics()->value(Metrics::IconMarginBottom) - m_ds->metrics()->value(Metrics::IconMarginTop) - 1;
int rad = m_ds->metrics()->value(Metrics::BorderRadius);
m_memDC = CreateCompatibleDC(m_hdc);
m_memBmp = CreateCompatibleBitmap(m_hdc, m_rc->right - m_rc->left, m_rc->bottom - m_rc->top);
m_oldBmp = (HBITMAP)SelectObject(m_memDC, m_memBmp);
m_graphics = new Gdiplus::Graphics(m_memDC);
m_graphics->SetSmoothingMode(Gdiplus::SmoothingModeHighSpeed);
m_graphics->Clear(ColorFromColorRef(m_ds->palette()->color(Palette::Background)));
Gdiplus::GraphicsPath ph;
RoundedPath(ph, x, y, width, height, rad);
Gdiplus::SolidBrush prgBrush(ColorFromColorRef(m_ds->palette()->color(Palette::Base)));
m_graphics->FillPath(&prgBrush, &ph);
{
int _x = x, _width;
if (pulse_pos != -1) {
_width = width/5;
_x = x + (int)round(double((width - _width) * pulse_pos)/100);
} else {
if (progress < 0)
progress = 0;
else
if (progress > 100)
progress = 100;
_width = (int)round(double(width * progress)/100);
}
Gdiplus::GraphicsPath _ph;
RoundedPath(_ph, _x, y, _width, height, rad);
Gdiplus::SolidBrush chunkBrush(ColorFromColorRef(m_ds->palette()->color(Palette::AlternateBase)));
m_graphics->FillPath(&chunkBrush, &_ph);
}
if (m_ds->metrics()->value(Metrics::BorderWidth) != 0) {
Gdiplus::Pen pen(ColorFromColorRef(m_ds->palette()->color(Palette::Border)), m_ds->metrics()->value(Metrics::BorderWidth));
m_graphics->DrawPath(&pen, &ph);
}
BitBlt(m_hdc, m_rc->left, m_rc->top, m_rc->right - m_rc->left, m_rc->bottom - m_rc->top, m_memDC, 0, 0, SRCCOPY);
delete m_graphics;
m_graphics = nullptr;
SelectObject(m_memDC, m_oldBmp);
m_oldBmp = nullptr;
DeleteObject(m_memBmp);
m_memBmp = nullptr;
DeleteDC(m_memDC);
m_memDC = nullptr;
}
void DrawingEngine::DrawText(const RECT &rc, const std::wstring &text, bool multiline) const
{
HFONT hFont = CreateFontW(m_ds->metrics()->value(Metrics::FontHeight), m_ds->metrics()->value(Metrics::FontWidth), 0, 0, FW_NORMAL,
0, 0, 0, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, CLEARTYPE_QUALITY, DEFAULT_PITCH, TEXT("Segoe UI"));
HFONT hOldFont = (HFONT) SelectObject(m_hdc, hFont);
SetBkMode(m_hdc, TRANSPARENT);
SetTextColor(m_hdc, m_ds->palette()->color(Palette::Text));
RECT _rc{rc.left + m_ds->metrics()->value(Metrics::TextMarginLeft), rc.top + m_ds->metrics()->value(Metrics::TextMarginTop),
rc.right + m_ds->metrics()->value(Metrics::TextMarginRight), rc.bottom + m_ds->metrics()->value(Metrics::TextMarginBottom)};
UINT fmt = multiline ? 0 : DT_SINGLELINE;
UINT algn = m_ds->metrics()->value(Metrics::TextAlignment);
if (algn & Metrics::AlignHLeft)
fmt |= DT_LEFT;
if (algn & Metrics::AlignHCenter)
fmt |= DT_CENTER;
if (algn & Metrics::AlignHRight)
fmt |= DT_RIGHT;
if (algn & Metrics::AlignVTop)
fmt |= DT_TOP;
if (algn & Metrics::AlignVCenter)
fmt |= DT_VCENTER;
if (algn & Metrics::AlignVBottom)
fmt |= DT_BOTTOM;
::DrawText(m_hdc, text.c_str(), text.length(), &_rc, fmt);
SelectObject(m_hdc, hOldFont);
SetBkMode(m_hdc, OPAQUE);
DeleteObject(hFont);
}
void DrawingEngine::End()
{
EndPaint(m_hwnd, m_ps);
delete m_ps;
m_ps = nullptr;
m_hdc = nullptr;
m_hwnd = nullptr;
m_rc = nullptr;
m_ds = nullptr;
}
// void DrawingEngine::LayeredBegin(DrawningSurface *ds, HWND hwnd, RECT *rc)
// {
// if (m_ds) {
// printf("Engine is buisy....\n");
// fflush(stdout);
// return;
// }
// m_ds = ds;
// m_rc = rc;
// m_hwnd = hwnd;
// m_hdc = GetDC(m_hwnd);
// m_memDC = CreateCompatibleDC(m_hdc);
// m_memBmp = CreateCompatibleBitmap(m_hdc, rc->right - rc->left, rc->bottom - rc->top);
// m_oldBmp = (HBITMAP)SelectObject(m_memDC, m_memBmp);
// m_graphics = new Gdiplus::Graphics(m_memDC);
// m_graphics->SetSmoothingMode(Gdiplus::SmoothingMode::SmoothingModeAntiAlias);
// // gr->SetCompositingMode(Gdiplus::CompositingMode::CompositingModeSourceOver);
// // gr->SetInterpolationMode(Gdiplus::InterpolationModeHighQuality);
// }
// void DrawingEngine::LayeredDrawRoundedRect() const
// {
// int x = m_rc->left + m_ds->metrics()->value(Metrics::ShadowWidth) + m_ds->metrics()->value(Metrics::BorderWidth) - 1;
// int y = m_rc->top + m_ds->metrics()->value(Metrics::ShadowWidth) + m_ds->metrics()->value(Metrics::BorderWidth) - 1;
// int width = m_rc->right - m_rc->left - (m_ds->metrics()->value(Metrics::ShadowWidth) + m_ds->metrics()->value(Metrics::BorderWidth)) * 2 + 1;
// int height = m_rc->bottom - m_rc->top - (m_ds->metrics()->value(Metrics::ShadowWidth) + m_ds->metrics()->value(Metrics::BorderWidth)) * 2 + 1;
// int rad = m_ds->metrics()->value(Metrics::BorderRadius);
// Gdiplus::GraphicsPath ph;
// RoundedPath(ph, x, y, width, height, rad);
// if (m_ds->metrics()->value(Metrics::BorderWidth) != 0) {
// Gdiplus::Pen pen(ColorFromColorRef(m_ds->palette()->color(Palette::Border)), m_ds->metrics()->value(Metrics::BorderWidth));
// m_graphics->DrawPath(&pen, &ph);
// }
// Gdiplus::SolidBrush brush(ColorFromColorRef(m_ds->palette()->color(Palette::Background)));
// m_graphics->FillPath(&brush, &ph);
// }
void DrawingEngine::LayeredDrawText(RECT &rc, const std::wstring &text) const
{
// Gdiplus::FontFamily fntFam(L"Segoe UI");
// Gdiplus::Font font(&fntFam, m_ds->metrics()->value(Metrics::FontHeight), Gdiplus::FontStyleRegular, Gdiplus::Unit::UnitPixel);
HFONT hFont = CreateFontW(m_ds->metrics()->value(Metrics::FontHeight), m_ds->metrics()->value(Metrics::FontWidth), 0, 0, FW_NORMAL,
0, 0, 0, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, CLEARTYPE_QUALITY, DEFAULT_PITCH, TEXT("Segoe UI"));
LOGFONTW logFont = {0};
GetObject(hFont, sizeof(LOGFONTW), &logFont);
Gdiplus::Font font(m_memDC, &logFont);
DeleteObject(hFont);
Gdiplus::RectF rcF(rc.left + m_ds->metrics()->value(Metrics::TextMarginLeft), rc.top + m_ds->metrics()->value(Metrics::TextMarginTop),
rc.right + m_ds->metrics()->value(Metrics::TextMarginRight) - rc.left - m_ds->metrics()->value(Metrics::TextMarginLeft),
rc.bottom + m_ds->metrics()->value(Metrics::TextMarginBottom) - rc.top - m_ds->metrics()->value(Metrics::TextMarginTop));
Gdiplus::StringAlignment h_algn, v_algn;
UINT algn = m_ds->metrics()->value(Metrics::TextAlignment);
if (algn & Metrics::AlignHLeft)
h_algn = Gdiplus::StringAlignmentNear;
if (algn & Metrics::AlignHCenter)
h_algn = Gdiplus::StringAlignmentCenter;
if (algn & Metrics::AlignHRight)
h_algn = Gdiplus::StringAlignmentFar;
if (algn & Metrics::AlignVTop)
v_algn = Gdiplus::StringAlignmentNear;
if (algn & Metrics::AlignVCenter)
v_algn = Gdiplus::StringAlignmentCenter;
if (algn & Metrics::AlignVBottom)
v_algn = Gdiplus::StringAlignmentFar;
Gdiplus::StringFormat strFmt;
strFmt.SetAlignment(h_algn);
strFmt.SetLineAlignment(v_algn);
Gdiplus::SolidBrush brush(ColorFromColorRef(m_ds->palette()->color(Palette::Text)));
m_graphics->DrawString(text.c_str(), -1, &font, rcF, &strFmt, &brush);
}
// void DrawingEngine::LayeredDrawShadow(int shadowWidth, int rad)
// {
// #define SHADOW_TRANSPATENCY 0x26
// for (int i = 0; i < shadowWidth; i++) {
// int x = m_rc->left + i;
// int y = m_rc->top + i;
// int width = m_rc->right - m_rc->left - i * 2 - 1;
// int height = m_rc->bottom - m_rc->top - i * 2 - 1;
// Gdiplus::GraphicsPath ph;
// RoundedPath(ph, x, y, width, height, rad);
// int alpha = shadowWidth > 1 ? SHADOW_TRANSPATENCY * (i * i) / ((shadowWidth - 1) * (shadowWidth - 1)) : SHADOW_TRANSPATENCY;
// Gdiplus::Pen pen(Gdiplus::Color(alpha, 0, 0, 0), 1);
// m_graphics->DrawPath(&pen, &ph);
// }
// }
// void DrawingEngine::LayeredUpdate(BYTE alpha)
// {
// RECT wrc;
// GetWindowRect(m_hwnd, &wrc);
// HDC scrDC = GetDC(NULL);
// POINT ptSrc = {0, 0};
// POINT ptDst = {wrc.left, wrc.top};
// SIZE szDst = {wrc.right - wrc.left, wrc.bottom - wrc.top};
// BLENDFUNCTION bf;
// bf.AlphaFormat = AC_SRC_ALPHA;
// bf.BlendFlags = 0;
// bf.BlendOp = AC_SRC_OVER;
// bf.SourceConstantAlpha = alpha;
// UpdateLayeredWindow(m_hwnd, scrDC, &ptDst, &szDst, m_memDC, &ptSrc, 0, &bf, ULW_ALPHA);
// ReleaseDC(NULL, scrDC);
// }
// void DrawingEngine::LayeredEnd()
// {
// delete m_graphics;
// m_graphics = nullptr;
// SelectObject(m_memDC, m_oldBmp);
// m_oldBmp = nullptr;
// DeleteObject(m_memBmp);
// m_memBmp = nullptr;
// DeleteDC(m_memDC);
// m_memDC = nullptr;
// ReleaseDC(m_hwnd, m_hdc);
// m_hdc = nullptr;
// m_hwnd = nullptr;
// m_rc = nullptr;
// m_ds = nullptr;
// }

View File

@ -0,0 +1,59 @@
#ifndef DRAWNINGENGINE_H
#define DRAWNINGENGINE_H
#include <Windows.h>
#include <gdiplus.h>
#include <string>
class DrawningSurface;
class DrawingEngine
{
public:
DrawingEngine(const DrawingEngine&) = delete;
DrawingEngine& operator=(const DrawingEngine&) = delete;
static DrawingEngine *instance();
DrawningSurface *surface();
void Begin(DrawningSurface*, HWND, RECT *rc);
void FillBackground() const;
// void DrawRoundedRect();
void DrawBorder() const;
void DrawTopBorder(int, COLORREF) const;
void DrawIcon(HICON hIcon) const;
void DrawEmfIcon(HENHMETAFILE hIconc) const;
void DrawImage(Gdiplus::Bitmap *hBmp) const;
void DrawStockCloseIcon();
void DrawStockMinimizeIcon();
void DrawStockMaximizeIcon();
void DrawStockRestoreIcon();
void DrawCheckBox(const std::wstring &text, bool checked = false);
void DrawRadioButton(const std::wstring &text, bool checked = false);
void DrawProgressBar(int progress, int pulse_pos);
void DrawText(const RECT &rc, const std::wstring &text, bool multiline = false) const;
void End();
// void LayeredBegin(DrawningSurface*, HWND, RECT *rc);
// void LayeredDrawRoundedRect() const;
void LayeredDrawText(RECT &rc, const std::wstring &text) const;
// void LayeredDrawShadow(int shadowWidth, int rad);
// void LayeredUpdate(BYTE alpha);
// void LayeredEnd();
private:
DrawingEngine();
~DrawingEngine();
DrawningSurface *m_ds;
RECT *m_rc;
PAINTSTRUCT *m_ps;
HWND m_hwnd;
HDC m_hdc;
HDC m_memDC;
HBITMAP m_memBmp;
HBITMAP m_oldBmp;
Gdiplus::Graphics *m_graphics;
};
#endif // DRAWNINGENGINE_H

View File

@ -0,0 +1,185 @@
#include "label.h"
#include "metrics.h"
#include "drawningengine.h"
Label::Label(Widget *parent) :
Widget(parent, ObjectType::WidgetType),
m_hIcon(nullptr),
m_hMetaFile(nullptr),
m_hBmp(nullptr),
m_multiline(false)
{
}
Label::~Label()
{
if (m_hIcon) {
DestroyIcon(m_hIcon);
m_hIcon = nullptr;
}
if (m_hMetaFile) {
//delete m_hMetaFile;
DeleteEnhMetaFile(m_hMetaFile);
m_hMetaFile = nullptr;
}
if (m_hBmp) {
delete m_hBmp, m_hBmp = nullptr;
}
}
void Label::setText(const std::wstring &text, bool multiline)
{
m_text = text;
m_multiline = multiline;
update();
}
void Label::setIcon(const std::wstring &path, int w, int h)
{
if (m_hIcon) {
DestroyIcon(m_hIcon);
m_hIcon = nullptr;
}
metrics()->setMetrics(Metrics::IconWidth, w);
metrics()->setMetrics(Metrics::IconHeight, h);
m_hIcon = (HICON)LoadImage(NULL, path.c_str(), IMAGE_ICON, w, h, LR_LOADFROMFILE | LR_DEFAULTCOLOR | LR_SHARED);
update();
}
void Label::setIcon(int id, int w, int h)
{
if (m_hIcon) {
DestroyIcon(m_hIcon);
m_hIcon = nullptr;
}
metrics()->setMetrics(Metrics::IconWidth, w);
metrics()->setMetrics(Metrics::IconHeight, h);
HMODULE hInst = GetModuleHandle(NULL);
m_hIcon = (HICON)LoadImage(hInst, MAKEINTRESOURCE(id), IMAGE_ICON, w, h, LR_COPYFROMRESOURCE | LR_DEFAULTCOLOR | LR_SHARED);
update();
}
void Label::setEMFIcon(const std::wstring &path, int w, int h)
{
if (m_hMetaFile) {
//delete m_hMetaFile;
DeleteEnhMetaFile(m_hMetaFile);
m_hMetaFile = nullptr;
}
metrics()->setMetrics(Metrics::IconWidth, w);
metrics()->setMetrics(Metrics::IconHeight, h);
m_hMetaFile = GetEnhMetaFile(path.c_str());
//m_hMetaFile = new Metafile(path.c_str());
update();
}
void Label::setEMFIcon(int id, int w, int h)
{
if (m_hMetaFile) {
//delete m_hMetaFile;
DeleteEnhMetaFile(m_hMetaFile);
m_hMetaFile = nullptr;
}
metrics()->setMetrics(Metrics::IconWidth, w);
metrics()->setMetrics(Metrics::IconHeight, h);
HMODULE hInst = GetModuleHandle(NULL);
if (HRSRC hRes = FindResource(hInst, MAKEINTRESOURCE(id), RT_RCDATA)) {
if (HGLOBAL hResData = LoadResource(hInst, hRes)) {
if (LPVOID pData = LockResource(hResData)) {
DWORD dataSize = SizeofResource(hInst, hRes);
if (dataSize > 0)
m_hMetaFile = SetEnhMetaFileBits(dataSize, (BYTE*)pData);
}
FreeResource(hResData);
}
}
update();
}
void Label::setImage(int id, int w, int h)
{
if (m_hBmp) {
delete m_hBmp, m_hBmp = nullptr;
}
metrics()->setMetrics(Metrics::IconWidth, w);
metrics()->setMetrics(Metrics::IconHeight, h);
HMODULE hInst = GetModuleHandle(NULL);
if (HRSRC hRes = FindResource(hInst, MAKEINTRESOURCE(id), L"PNG")) {
if (HGLOBAL hResData = LoadResource(hInst, hRes)) {
if (LPVOID pData = LockResource(hResData)) {
DWORD dataSize = SizeofResource(hInst, hRes);
if (dataSize > 0) {
if (HGLOBAL hGlobal = GlobalAlloc(GHND, dataSize)) {
if (LPVOID pBuffer = GlobalLock(hGlobal)) {
memcpy(pBuffer, pData, dataSize);
IStream *pStream = nullptr;
HRESULT hr = CreateStreamOnHGlobal(hGlobal, TRUE, &pStream);
if (SUCCEEDED(hr)) {
m_hBmp = new Gdiplus::Bitmap(pStream);
pStream->Release();
}
GlobalUnlock(hGlobal);
}
GlobalFree(hGlobal);
}
}
}
FreeResource(hResData);
}
}
update();
}
void Label::setIconSize(int w, int h)
{
metrics()->setMetrics(Metrics::IconWidth, w);
metrics()->setMetrics(Metrics::IconHeight, h);
update();
}
bool Label::event(UINT msg, WPARAM wParam, LPARAM lParam, LRESULT *result)
{
switch (msg) {
case WM_PAINT: {
RECT rc;
GetClientRect(m_hWnd, &rc);
engine()->Begin(this, m_hWnd, &rc);
engine()->FillBackground();
// DrawRoundedRect();
if (metrics()->value(Metrics::BorderWidth) != 0)
engine()->DrawBorder();
if (m_hBmp)
engine()->DrawImage(m_hBmp);
if (m_hIcon)
engine()->DrawIcon(m_hIcon);
if (m_hMetaFile)
engine()->DrawEmfIcon(m_hMetaFile);
if (!m_text.empty())
engine()->DrawText(rc, m_text, m_multiline);
engine()->End();
*result = FALSE;
return true;
}
// case WM_MOUSEENTER: {
// palette()->setCurrentState(Palette::Hover);
// repaint();
// break;
// }
// case WM_MOUSELEAVE: {
// palette()->setCurrentState(Palette::Normal);
// repaint();
// break;
// }
default:
break;
}
return Widget::event(msg, wParam, lParam, result);
}

View File

@ -0,0 +1,35 @@
#ifndef LABEL_H
#define LABEL_H
#include "widget.h"
#include <Windows.h>
#include <gdiplus.h>
class Label : public Widget
{
public:
Label(Widget *parent = nullptr);
virtual ~Label();
void setText(const std::wstring &text, bool multiline = false);
void setIcon(const std::wstring &path, int w, int h);
void setIcon(int id, int w, int h);
void setEMFIcon(const std::wstring &path, int w, int h);
void setEMFIcon(int id, int w, int h);
void setImage(int id, int w, int h);
void setIconSize(int w, int h);
/* callback */
protected:
virtual bool event(UINT, WPARAM, LPARAM, LRESULT*) override;
private:
std::wstring m_text;
HICON m_hIcon;
HENHMETAFILE m_hMetaFile;
Gdiplus::Bitmap *m_hBmp;
bool m_multiline;
};
#endif // LABEL_H

View File

@ -0,0 +1,12 @@
#include "layout.h"
Layout::Layout(Object *parent)
{
}
Layout::~Layout()
{
}

View File

@ -0,0 +1,27 @@
#ifndef LAYOUT_H
#define LAYOUT_H
#include "object.h"
#include "layoutitem.h"
#include "common.h"
// #include <vector>
class Layout : public LayoutItem
{
public:
Layout(Object *parent = nullptr);
virtual ~Layout();
virtual void addWidget(Widget *wgt) = 0;
protected:
Margins m_margins;
private:
friend class Widget;
virtual void onResize(int w, int h) = 0;
};
#endif // LAYOUT_H

View File

@ -0,0 +1,22 @@
#include "layoutitem.h"
LayoutItem::LayoutItem()
{
}
LayoutItem::~LayoutItem()
{
}
Widget *LayoutItem::widget()
{
return nullptr;
}
Layout *LayoutItem::layout()
{
return nullptr;
}

View File

@ -0,0 +1,20 @@
#ifndef LAYOUTITEM_H
#define LAYOUTITEM_H
class Widget;
class Layout;
class LayoutItem
{
public:
LayoutItem();
~LayoutItem();
virtual Widget *widget();
virtual Layout *layout();
protected:
};
#endif // LAYOUTITEM_H

View File

@ -0,0 +1,40 @@
#include "metrics.h"
Metrics::Metrics()
{
metrics[BorderWidth] = 0;
metrics[BorderRadius] = 0;
metrics[IconWidth] = 16;
metrics[IconHeight] = 16;
metrics[IconMarginLeft] = 0;
metrics[IconMarginRight] = 0;
metrics[IconMarginTop] = 0;
metrics[IconMarginBottom] = 0;
metrics[IconAlignment] = Alignment::AlignCenter;
metrics[FontWidth] = 0;
metrics[FontHeight] = 18;
metrics[PrimitiveWidth] = 1;
metrics[ShadowWidth] = 10;
metrics[ShadowRadius] = 10;
metrics[TextMarginLeft] = 0;
metrics[TextMarginTop] = 0;
metrics[TextMarginRight] = 0;
metrics[TextMarginBottom] = 0;
metrics[TextAlignment] = Alignment::AlignCenter;
}
Metrics::~Metrics()
{
}
int Metrics::value(Role role)
{
return metrics[role];
}
void Metrics::setMetrics(Role role, int value)
{
metrics[role] = value;
}

View File

@ -0,0 +1,53 @@
#ifndef METRICS_H
#define METRICS_H
class Metrics
{
public:
Metrics();
~Metrics();
enum Alignment : unsigned char {
AlignHLeft = 1,
AlignHCenter = 2,
AlignHRight = 4,
AlignVTop = 8,
AlignVCenter = 16,
AlignVBottom = 32,
AlignCenter = AlignHCenter | AlignVCenter
};
enum Role : unsigned char {
BorderWidth,
BorderRadius,
IconWidth,
IconHeight,
IconMarginLeft,
IconMarginTop,
IconMarginRight,
IconMarginBottom,
IconAlignment,
FontWidth,
FontHeight,
PrimitiveWidth,
ShadowWidth,
ShadowRadius,
TextMarginLeft,
TextMarginTop,
TextMarginRight,
TextMarginBottom,
TextAlignment,
METRICS_COUNT
};
void setMetrics(Role, int);
int value(Role);
protected:
private:
int metrics[METRICS_COUNT];
};
#endif // METRICS_H

View File

@ -0,0 +1,40 @@
#include "object.h"
int Object::m_connectionId = 0;
Object::Object(Object *parent) :
m_parent(parent)
{
}
Object::~Object()
{
}
Object *Object::parent()
{
return m_parent;
}
void Object::setParent(Object *parent)
{
m_parent = parent;
}
void Object::setObjectName(const std::wstring &object_name)
{
m_object_name = object_name;
}
std::wstring Object::objectName()
{
return m_object_name;
}
void Object::disconnect(int connectionId)
{
}

View File

@ -0,0 +1,35 @@
#ifndef OBJECT_H
#define OBJECT_H
#include <string>
class Object
{
public:
Object(Object *parent = nullptr);
virtual ~Object();
enum ObjectType : unsigned char {
ApplicationType,
WindowType,
DialogType,
WidgetType,
PopupType
};
Object *parent();
void setParent(Object*);
void setObjectName(const std::wstring&);
std::wstring objectName();
virtual void disconnect(int);
protected:
static int m_connectionId;
private:
Object *m_parent;
std::wstring m_object_name;
};
#endif // OBJECT_H

View File

@ -0,0 +1,59 @@
#include "palette.h"
Palette::Palette()
{
palette[Background][Disabled] = 0x21252b;
palette[Background][Normal] = 0x21252b;
palette[Background][Hover] = 0x34383f;
palette[Background][Pressed] = 0x30343c;
palette[Border][Disabled] = 0x21252b;
palette[Border][Normal] = 0x21252b;
palette[Border][Hover] = 0x34383f;
palette[Border][Pressed] = 0x30343c;
palette[Base][Disabled] = 0x0000ff;
palette[Base][Normal] = 0x0000ff;
palette[Base][Hover] = 0x0000ff;
palette[Base][Pressed] = 0x0000ff;
palette[AlternateBase][Disabled] = 0xff0000;
palette[AlternateBase][Normal] = 0xff0000;
palette[AlternateBase][Hover] = 0xff0000;
palette[AlternateBase][Pressed] = 0xff0000;
palette[Text][Disabled] = 0xeeeeee;
palette[Text][Normal] = 0xeeeeee;
palette[Text][Hover] = 0xaaaaaa;
palette[Text][Pressed] = 0xaaaaaa;
palette[Primitive][Disabled] = 0xeeeeee;
palette[Primitive][Normal] = 0xeeeeee;
palette[Primitive][Hover] = 0xeeeeee;
palette[Primitive][Pressed] = 0xeeeeee;
setCurrentState(Normal);
}
Palette::~Palette()
{
}
COLORREF Palette::color(Role role)
{
return RGB((currentColors[role] & 0xff0000) >> 16, (currentColors[role] & 0xff00) >> 8, currentColors[role] & 0xff);
}
void Palette::setColor(Role role, State state, DWORD color)
{
palette[role][state] = color;
currentColors[role] = palette[role][currentState];
}
void Palette::setCurrentState(State state)
{
currentColors[Background] = palette[Background][state];
currentColors[Border] = palette[Border][state];
currentColors[Base] = palette[Base][state];
currentColors[AlternateBase] = palette[AlternateBase][state];
currentColors[Text] = palette[Text][state];
currentColors[Primitive] = palette[Primitive][state];
currentState = state;
}

View File

@ -0,0 +1,41 @@
#ifndef PALETTE_H
#define PALETTE_H
#include <Windows.h>
class Palette
{
public:
Palette();
~Palette();
enum Role : BYTE {
Background = 0,
Border,
Base,
AlternateBase,
Text,
Primitive,
PALETTE_ROLE_COUNT
};
enum State : BYTE {
Disabled = 0,
Normal,
Hover,
Pressed,
PALETTE_STATE_COUNT
};
COLORREF color(Role);
void setColor(Role, State, DWORD);
void setCurrentState(State);
private:
DWORD palette[PALETTE_ROLE_COUNT][PALETTE_STATE_COUNT];
DWORD currentColors[PALETTE_ROLE_COUNT];
State currentState;
};
#endif // PALETTE_H

View File

@ -0,0 +1,110 @@
#include "progressbar.h"
#include "drawningengine.h"
#define DEFAULT_PULSE_STEP 1
ProgressBar::ProgressBar(Widget *parent) :
Widget(parent, ObjectType::WidgetType),
m_progress(0),
m_pulse_pos(-1),
m_pulse_direction(1),
m_pulse_step(DEFAULT_PULSE_STEP)
{
}
ProgressBar::~ProgressBar()
{
}
void ProgressBar::setProgress(int progress)
{
m_progress = progress;
update();
}
void ProgressBar::pulse(bool enable)
{
m_pulse_pos = enable ? 0 : -1;
m_pulse_direction = 1;
if (enable) {
timeBeginPeriod(1);
SetTimer(m_hWnd, PROGRESS_PULSE_TIMER_ID, 17, NULL);
} else {
KillTimer(m_hWnd, PROGRESS_PULSE_TIMER_ID);
timeEndPeriod(1);
}
}
void ProgressBar::setPulseStep(int step)
{
if (step < 1)
step = 1;
else
if (step > 50)
step = 50;
m_pulse_step = step;
}
bool ProgressBar::event(UINT msg, WPARAM wParam, LPARAM lParam, LRESULT *result)
{
switch (msg) {
// case WM_LBUTTONDOWN: {
// palette()->setCurrentState(Palette::Pressed);
// repaint();
// return false;
// }
// case WM_LBUTTONUP: {
// palette()->setCurrentState(Palette::Hover);
// repaint();
// break;
// }
// case WM_MOUSEENTER: {
// palette()->setCurrentState(Palette::Hover);
// repaint();
// break;
// }
// case WM_MOUSELEAVE:
// case WM_NCMOUSELEAVE: {
// palette()->setCurrentState(Palette::Normal);
// repaint();
// break;
// }
case WM_PAINT: {
RECT rc;
GetClientRect(m_hWnd, &rc);
engine()->Begin(this, m_hWnd, &rc);
engine()->DrawProgressBar(m_progress, m_pulse_pos);
engine()->End();
*result = FALSE;
return true;
}
case WM_TIMER: {
if (wParam == PROGRESS_PULSE_TIMER_ID) {
m_pulse_pos += m_pulse_direction * m_pulse_step;
if (m_pulse_pos >= 100) {
m_pulse_pos = 100;
m_pulse_direction = -1;
} else
if (m_pulse_pos <= 0) {
m_pulse_pos = 0;
m_pulse_direction = 1;
}
update();
}
break;
}
default:
break;
}
return Widget::event(msg, wParam, lParam, result);
}

View File

@ -0,0 +1,30 @@
#ifndef PROGRESSBAR_H
#define PROGRESSBAR_H
#include "widget.h"
//#include <gdiplus.h>
class ProgressBar : public Widget
{
public:
ProgressBar(Widget *parent = nullptr);
virtual ~ProgressBar();
void setProgress(int progress);
void pulse(bool);
void setPulseStep(int);
/* callback */
protected:
virtual bool event(UINT, WPARAM, LPARAM, LRESULT*) override;
private:
int m_progress,
m_pulse_pos,
m_pulse_direction,
m_pulse_step;
};
#endif // PROGRESSBAR_H

View File

@ -0,0 +1,59 @@
#include "radiobutton.h"
#include "drawningengine.h"
#include "metrics.h"
#include <windowsx.h>
RadioButton::RadioButton(Widget *parent, const std::wstring &text) :
AbstractButton(parent, text),
m_checked(false)
{
metrics()->setMetrics(Metrics::TextAlignment, Metrics::AlignHLeft | Metrics::AlignVCenter);
}
RadioButton::~RadioButton()
{
}
void RadioButton::setChecked(bool checked)
{
m_checked = checked;
update();
}
bool RadioButton::isChecked()
{
return m_checked;
}
bool RadioButton::event(UINT msg, WPARAM wParam, LPARAM lParam, LRESULT *result)
{
switch (msg) {
case WM_PAINT: {
RECT rc;
GetClientRect(m_hWnd, &rc);
engine()->Begin(this, m_hWnd, &rc);
engine()->DrawRadioButton(m_text, m_checked);
if (metrics()->value(Metrics::BorderWidth) != 0)
engine()->DrawBorder();
engine()->End();
*result = FALSE;
return true;
}
default:
break;
}
return AbstractButton::event(msg, wParam, lParam, result);
}
void RadioButton::click()
{
m_checked = true;
update();
AbstractButton::click();
}

View File

@ -0,0 +1,26 @@
#ifndef RADIOBUTTON_H
#define RADIOBUTTON_H
#include "abstractbutton.h"
class RadioButton : public AbstractButton
{
public:
RadioButton(Widget *parent = nullptr, const std::wstring &text = L"");
virtual ~RadioButton();
void setChecked(bool checked);
bool isChecked();
/* callback */
protected:
virtual bool event(UINT, WPARAM, LPARAM, LRESULT*) override;
virtual void click() override;
private:
bool m_checked;
};
#endif // RADIOBUTTON_H

View File

@ -0,0 +1,414 @@
#include "widget.h"
#include "application.h"
#include "metrics.h"
#include "palette.h"
#include "drawningengine.h"
#include <CommCtrl.h>
static bool isAllocOnHeap(void *addr) {
if (HANDLE procHeap = GetProcessHeap()) {
if (HeapLock(procHeap)) {
bool res = false;
PROCESS_HEAP_ENTRY entry = {0};
while (HeapWalk(procHeap, &entry)) {
if ((entry.wFlags & PROCESS_HEAP_REGION) && addr >= (void*)entry.Region.lpFirstBlock && addr <= (void*)entry.Region.lpLastBlock) {
res = true;
break;
}
}
if (!HeapUnlock(procHeap))
res = false;
return res;
}
}
return false;
}
Widget::Widget(Widget *parent) :
Widget(parent, ObjectType::WidgetType)
{}
Widget::Widget(Widget *parent, HWND hwnd) :
Object(parent),
DrawningSurface(),
m_hWnd(hwnd),
m_layout(nullptr),
m_disabled(false),
m_is_created(false),
m_is_destroyed(false),
m_is_class_destroyed(false),
m_mouse_entered(false)
{
LONG style = ::GetWindowLong(m_hWnd, GWL_STYLE) | WS_CHILD;
::SetWindowLong(m_hWnd, GWL_STYLE, style);
m_properties[Properties::HSizeBehavior] = SizeBehavior::Expanding;
m_properties[Properties::VSizeBehavior] = SizeBehavior::Expanding;
SetParent(hwnd, parent->nativeWindowHandle());
}
Widget::Widget(Widget *parent, ObjectType type, const Rect &rc) :
Object(parent),
DrawningSurface(),
m_hWnd(nullptr),
m_layout(nullptr),
m_disabled(false),
m_is_created(false),
m_is_destroyed(false),
m_is_class_destroyed(false),
m_mouse_entered(false)
{
m_properties[Properties::HSizeBehavior] = SizeBehavior::Expanding;
m_properties[Properties::VSizeBehavior] = SizeBehavior::Expanding;
Application::instance()->registerWidget(this, type, rc);
}
Widget::~Widget()
{
m_is_class_destroyed = true;
if (m_layout) {
if (isAllocOnHeap(m_layout))
delete m_layout;
m_layout = nullptr;
}
if (!m_is_destroyed)
DestroyWindow(m_hWnd);
}
void Widget::setGeometry(int x, int y, int width, int height)
{
SetWindowPos(m_hWnd, NULL, x, y, width, height, SWP_FRAMECHANGED | SWP_NOZORDER | SWP_NOOWNERZORDER /*| SWP_NOSENDCHANGING*/);
}
void Widget::setDisabled(bool disable)
{
m_disabled = disable;
palette()->setCurrentState(disable ? Palette::Disabled : Palette::Normal);
update();
}
void Widget::close()
{
PostMessage(m_hWnd, WM_CLOSE, 0, 0);
}
void Widget::move(int x, int y)
{
SetWindowPos(m_hWnd, NULL, x, y, 0, 0, SWP_NOSIZE | SWP_FRAMECHANGED | SWP_NOZORDER | SWP_NOOWNERZORDER /*| SWP_NOSENDCHANGING*/);
}
void Widget::resize(int w, int h)
{
SetWindowPos(m_hWnd, NULL, 0, 0, w, h, SWP_NOMOVE | SWP_FRAMECHANGED | SWP_NOZORDER | SWP_NOOWNERZORDER /*| SWP_NOSENDCHANGING*/);
}
Widget *Widget::parentWidget()
{
return dynamic_cast<Widget*>(parent());
}
std::wstring Widget::title()
{
return m_title;
}
Size Widget::size()
{
RECT rc;
GetClientRect(m_hWnd, &rc);
return Size(rc.right - rc.left, rc.bottom - rc.top);
}
void Widget::size(int *width, int *height)
{
RECT rc;
GetClientRect(m_hWnd, &rc);
*width = rc.right - rc.left;
*height = rc.bottom - rc.top;
}
void Widget::setWindowTitle(const std::wstring &title)
{
m_title = title;
SetWindowText(m_hWnd, title.c_str());
}
void Widget::setProperty(Properties property, int val)
{
m_properties[property] = val;
}
void Widget::show()
{
ShowWindow(m_hWnd, SW_SHOW);
UpdateWindow(m_hWnd);
}
void Widget::hide()
{
ShowWindow(m_hWnd, SW_HIDE);
}
void Widget::repaint()
{
if (IsWindowVisible(m_hWnd))
RedrawWindow(m_hWnd, NULL, NULL, RDW_INVALIDATE | RDW_NOERASE | RDW_INTERNALPAINT | RDW_UPDATENOW);
}
void Widget::update()
{
if (IsWindowVisible(m_hWnd))
RedrawWindow(m_hWnd, NULL, NULL, RDW_INVALIDATE | RDW_NOERASE | RDW_INTERNALPAINT);
}
void Widget::setLayout(Layout *layout)
{
if (m_layout) {
// TODO: error: trying to add a layout when the widget contains a layout
} else {
m_layout = layout;
}
}
bool Widget::isCreated()
{
return m_is_created;
}
bool Widget::underMouse()
{
POINT pt;
GetCursorPos(&pt);
return WindowFromPoint(pt) == m_hWnd;
}
int Widget::property(Properties property)
{
return m_properties[property];
}
Layout *Widget::layout()
{
return m_layout;
}
HWND Widget::nativeWindowHandle()
{
return m_hWnd;
}
Widget *Widget::widgetFromHwnd(Widget *parent, HWND hwnd)
{
return new Widget(parent, hwnd);
}
int Widget::onResize(const FnVoidIntInt &callback)
{
m_resize_callbacks[++m_connectionId] = callback;
return m_connectionId;
}
int Widget::onMove(const FnVoidIntInt &callback)
{
m_move_callbacks[++m_connectionId] = callback;
return m_connectionId;
}
int Widget::onAboutToDestroy(const FnVoidVoid &callback)
{
m_destroy_callbacks[++m_connectionId] = callback;
return m_connectionId;
}
int Widget::onCreate(const FnVoidVoid &callback)
{
m_create_callbacks[++m_connectionId] = callback;
return m_connectionId;
}
int Widget::onClose(const FnVoidBoolPtr &callback)
{
m_close_callbacks[++m_connectionId] = callback;
return m_connectionId;
}
void Widget::disconnect(int connectionId)
{
{
auto it = m_resize_callbacks.find(connectionId);
if (it != m_resize_callbacks.end()) {
m_resize_callbacks.erase(it);
return;
}
}
{
auto it = m_move_callbacks.find(connectionId);
if (it != m_move_callbacks.end()) {
m_move_callbacks.erase(it);
return;
}
}
{
auto it = m_destroy_callbacks.find(connectionId);
if (it != m_destroy_callbacks.end()) {
m_destroy_callbacks.erase(it);
return;
}
}
{
auto it = m_create_callbacks.find(connectionId);
if (it != m_create_callbacks.end()) {
m_create_callbacks.erase(it);
return;
}
}
{
auto it = m_close_callbacks.find(connectionId);
if (it != m_close_callbacks.end()) {
m_close_callbacks.erase(it);
return;
}
}
}
bool Widget::event(UINT msg, WPARAM wParam, LPARAM lParam, LRESULT *result)
{
switch (msg) {
case WM_ACTIVATE:
break;
case WM_CREATE: {
m_is_created = true;
for (auto it = m_create_callbacks.begin(); it != m_create_callbacks.end(); it++)
if (it->second)
(it->second)();
break;
}
case WM_SIZE:
if (m_layout)
m_layout->onResize(LOWORD(lParam), HIWORD(lParam));
for (auto it = m_resize_callbacks.begin(); it != m_resize_callbacks.end(); it++)
if (it->second)
(it->second)(LOWORD(lParam), HIWORD(lParam));
break;
case WM_MOVE:
for (auto it = m_move_callbacks.begin(); it != m_move_callbacks.end(); it++)
if (it->second)
(it->second)(LOWORD(lParam), HIWORD(lParam));
break;
case WM_PAINT: {
RECT rc;
GetClientRect(m_hWnd, &rc);
engine()->Begin(this, m_hWnd, &rc);
engine()->FillBackground();
if (metrics()->value(Metrics::BorderWidth) != 0)
engine()->DrawBorder();
//DrawRoundedRect();
engine()->End();
*result = FALSE;
return true;
}
case WM_LBUTTONDOWN:
case WM_NCLBUTTONDOWN: {
break;
}
case WM_ERASEBKGND: {
*result = FALSE;
return true;
}
case WM_LBUTTONDBLCLK: {
break;
}
case WM_LBUTTONUP: {
break;
}
case WM_MOUSEMOVE: {
if (!m_mouse_entered) {
m_mouse_entered = true;
PostMessage(m_hWnd, WM_MOUSEENTER, 0, 0);
}
// add here impl onMouseMove
TRACKMOUSEEVENT tme;
tme.cbSize = sizeof(tme);
tme.hwndTrack = m_hWnd;
tme.dwFlags = TME_LEAVE /*| TME_HOVER*/;
tme.dwHoverTime = HOVER_DEFAULT;
_TrackMouseEvent(&tme);
break;
}
case WM_NCMOUSEMOVE: {
if (!m_mouse_entered) {
m_mouse_entered = true;
PostMessage(m_hWnd, WM_MOUSEENTER, 0, 0);
}
// add here impl onMouseMove
break;
}
case WM_MOUSEHOVER:
case WM_NCMOUSEHOVER: {
break;
}
case WM_MOUSEENTER: {
// palette()->setCurrentState(Palette::Hover);
// repaint();
break;
}
case WM_MOUSELEAVE:
case WM_NCMOUSELEAVE: {
if (m_mouse_entered) {
m_mouse_entered = false;
}
// palette()->setCurrentState(Palette::Normal);
// repaint();
break;
}
case WM_CLOSE: {
bool accept = true;
for (auto it = m_close_callbacks.begin(); it != m_close_callbacks.end(); it++)
if (it->second)
(it->second)(&accept);
if (accept)
DestroyWindow(m_hWnd);
*result = TRUE;
return true;
}
case WM_DESTROY: {
m_is_destroyed = true;
for (auto it = m_destroy_callbacks.begin(); it != m_destroy_callbacks.end(); it++)
if (it->second)
(it->second)();
if (!m_is_class_destroyed) {
if (isAllocOnHeap(this)) {
SetWindowLongPtr(m_hWnd, GWLP_USERDATA, 0);
delete this;
}
}
break;
}
default:
break;
}
return false;
}
void Widget::setNativeWindowHandle(HWND hWnd)
{
m_hWnd = hWnd;
}

View File

@ -0,0 +1,89 @@
#ifndef WIDGET_H
#define WIDGET_H
#include "object.h"
#include "drawingsurface.h"
#include "layout.h"
#include "commondefines.h"
#include <unordered_map>
#include <Windows.h>
class Widget : public Object, public DrawningSurface
{
public:
Widget(Widget *parent = nullptr);
virtual ~Widget();
enum Properties : BYTE {
HSizeBehavior,
VSizeBehavior,
PROPERTIES_COUNT
};
enum SizeBehavior : BYTE {
Fixed,
Expanding,
//Preferred
};
virtual void setGeometry(int, int, int, int);
void setDisabled(bool);
void close();
void move(int, int);
void resize(int, int);
Widget* parentWidget();
std::wstring title();
Size size();
void size(int*, int*);
void setWindowTitle(const std::wstring &title);
void setProperty(Properties, int);
void show();
void hide();
void repaint();
void update();
void setLayout(Layout *lut);
bool isCreated();
bool underMouse();
int property(Properties);
Layout* layout();
HWND nativeWindowHandle();
static Widget* widgetFromHwnd(Widget *parent, HWND);
/* callback */
int onResize(const FnVoidIntInt &callback);
int onMove(const FnVoidIntInt &callback);
int onAboutToDestroy(const FnVoidVoid &callback);
int onCreate(const FnVoidVoid &callback);
int onClose(const FnVoidBoolPtr &callback);
virtual void disconnect(int) override;
protected:
friend class Application;
Widget(Widget *parent, HWND);
Widget(Widget *parent, ObjectType type, const Rect &rc = Rect(CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT));
virtual bool event(UINT, WPARAM, LPARAM, LRESULT*);
HWND m_hWnd;
Layout *m_layout;
std::wstring m_title;
bool m_disabled;
private:
void setNativeWindowHandle(HWND);
int m_properties[PROPERTIES_COUNT];
std::unordered_map<int, FnVoidIntInt> m_resize_callbacks,
m_move_callbacks;
std::unordered_map<int, FnVoidVoid> m_create_callbacks,
m_destroy_callbacks;
std::unordered_map<int, FnVoidBoolPtr> m_close_callbacks;
bool m_is_created,
m_is_destroyed,
m_is_class_destroyed,
m_mouse_entered;
};
#endif // WIDGET_H

View File

@ -0,0 +1,544 @@
#include "window.h"
#include "baseutils.h"
#include "palette.h"
#include "metrics.h"
#include "drawningengine.h"
#include <windowsx.h>
#define DCX_USESTYLE 0x00010000
#define NC_AREA_WIDTH 3
#define MAIN_WINDOW_BORDER_WIDTH 1
using WinVer = Utils::WinVer;
static BOOL CALLBACK EnumChildProc(_In_ HWND hwnd, _In_ LPARAM lParam)
{
ShowWindow(hwnd, SW_SHOW);
UpdateWindow(hwnd);
return TRUE;
}
static double GetLogicalDpi(HWND hWnd)
{
if (HMODULE module = GetModuleHandleA("user32")) {
UINT(WINAPI *_GetDpiForWindow)(HWND) = NULL;
*(FARPROC*)&_GetDpiForWindow = GetProcAddress(module, "GetDpiForWindow");
if (_GetDpiForWindow)
return _GetDpiForWindow(hWnd)/96;
}
HDC hdc = GetDC(NULL);
double dpi = (double)GetDeviceCaps(hdc, LOGPIXELSX)/96;
ReleaseDC(NULL, hdc);
return dpi;
}
static Rect availableGeometry(HWND hwnd)
{
Rect rc;
if (HMONITOR monitor = MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST)) {
MONITORINFOEX monInfo;
ZeroMemory(&monInfo, sizeof(monInfo));
monInfo.cbSize = sizeof(MONITORINFOEX);
if (GetMonitorInfo(monitor, &monInfo))
rc = Rect(monInfo.rcWork.left, monInfo.rcWork.top, monInfo.rcWork.right - monInfo.rcWork.left, monInfo.rcWork.bottom - monInfo.rcWork.top);
}
return rc;
}
static void GetFrameMetricsForDpi(FRAME &frame, double dpi, bool maximized = false)
{
WinVer ver = Utils::getWinVersion();
int row = ver == WinVer::WinXP ? 0 :
ver <= WinVer::Win7 ? 1 :
ver <= WinVer::Win8_1 ? 2 :
ver <= WinVer::Win10 ? 3 : 4;
int column = dpi <= 1.0 ? 0 :
dpi <= 1.25 ? 1 :
dpi <= 1.5 ? 2 :
dpi <= 1.75 ? 3 :
dpi <= 2.0 ? 4 :
dpi <= 2.25 ? 5 :
dpi <= 2.5 ? 6 :
dpi <= 3.0 ? 7 :
dpi <= 3.5 ? 8 :
dpi <= 4.0 ? 9 :
dpi <= 4.5 ? 10 :
dpi <= 5.0 ? 11 : 12;
const int left[5][13] = { // Left margin for scales 100-500%
{0, 0, 0, 0, 0, 1, 1, 1, 2, 2, 2, 2, 2}, // WinXp: for NC width 3px
{7, 8, 10, 11, 12, 13, 15, 17, 20, 22, 25, 27, 32}, // WinVista - Win7
{7, 8, 10, 11, 12, 13, 15, 17, 20, 22, 25, 27, 32}, // Win8 - Win8.1
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // Win10
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} // Win11
};
frame.left = left[row][column];
const int top[5][13] = { // Top margin for scales 100-500%
{0, 0, 0, 0, 0, 1, 1, 1, 2, 2, 2, 2, 2}, // WinXp: for NC width 3px
{7, 8, 10, 11, 12, 13, 15, 17, 20, 22, 25, 27, 32}, // WinVista - Win7
{7, 8, 10, 11, 12, 13, 15, 17, 20, 22, 25, 27, 32}, // Win8 - Win8.1
{31, 38, 45, 52, 58, 65, 72, 85, 99, 112, 126, 139, 167}, // Win10
{30, 37, 43, 50, 56, 63, 69, 82, 95, 108, 121, 134, 161} // Win11
};
frame.top = top[row][column];
if (!maximized)
return;
const int left_ofs[5][13] = { // Left offset for scales 100-500%
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // WinXp
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // WinVista - Win7
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // Win8 - Win8.1
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // Win10
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} // Win11
};
frame.left -= left_ofs[row][column];
const int top_ofs[5][13] = { // Top offset for scales 100-500%
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // WinXp
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // WinVista - Win7
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // Win8 - Win8.1
{8, 9, 11, 12, 13, 14, 16, 18, 21, 24, 27, 30, 36}, // Win10
{7, 8, 9, 10, 11, 12, 13, 15, 17, 19, 21, 23, 28} // Win11
};
frame.top -= top_ofs[row][column];
}
static bool isTaskbarAutoHideOn()
{
APPBARDATA ABData;
ABData.cbSize = sizeof(ABData);
return (SHAppBarMessage(ABM_GETSTATE, &ABData) & ABS_AUTOHIDE) != 0;
}
static bool isThemeActive()
{
static BOOL(WINAPI *IsThemeActive)() = NULL;
if (!IsThemeActive) {
if (HMODULE module = GetModuleHandleA("uxtheme"))
*(FARPROC*)&IsThemeActive = GetProcAddress(module, "IsThemeActive");
}
return IsThemeActive ? (bool)IsThemeActive() : true;
}
Window::Window(Widget *parent, const Rect &rc) :
Widget(parent, ObjectType::WindowType, rc),
m_centralWidget(nullptr),
m_contentMargins(0,0,0,0),
m_resAreaWidth(0),
m_state(-1),
m_borderless(true),
m_isResizable(true),
m_scaleChanged(false),
m_init_size(rc.width, rc.height)
{
//setLayout(new BoxLayout(BoxLayout::Vertical));
m_isThemeActive = isThemeActive();
m_isTaskbarAutoHideOn = isTaskbarAutoHideOn();
m_borderless = true;//isCustomWindowStyle();
if (m_borderless && Utils::getWinVersion() < WinVer::Win10) {
LONG style = ::GetWindowLong(m_hWnd, GWL_STYLE) | WS_OVERLAPPEDWINDOW;
::SetWindowLong(m_hWnd, GWL_STYLE, style & ~WS_CAPTION);
}
m_isMaximized = IsZoomed(m_hWnd);
m_dpi = GetLogicalDpi(m_hWnd);
GetFrameMetricsForDpi(m_frame, m_dpi, m_isMaximized);
if (m_borderless && Utils::getWinVersion() == WinVer::Win10) {
SystemParametersInfo(SPI_GETBORDER, 0, &m_brdWidth, 0);
m_brdColor = Utils::getColorizationColor(true, RGB(0xfe, 0xfe, 0xfe));
}
SetWindowPos(m_hWnd, NULL, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_FRAMECHANGED);
}
Window::~Window()
{
//if (m_layout)
// delete m_layout, m_layout = nullptr;
}
void Window::setCentralWidget(Widget *wgt)
{
m_centralWidget = wgt;
}
void Window::setContentsMargins(int left, int top, int right, int bottom)
{
m_contentMargins = Margins(left, top, right, bottom);
if (IsWindowVisible(m_hWnd))
SetWindowPos(m_hWnd, NULL, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_FRAMECHANGED);
}
void Window::setResizable(bool isResizable)
{
if (m_isResizable != isResizable) {
m_isResizable = isResizable;
LONG style = ::GetWindowLong(m_hWnd, GWL_STYLE);
::SetWindowLong(m_hWnd, GWL_STYLE, m_isResizable ? style | WS_MAXIMIZEBOX : style & ~WS_MAXIMIZEBOX);
}
}
void Window::showAll()
{
ShowWindow(m_hWnd, SW_SHOW);
UpdateWindow(m_hWnd);
EnumChildWindows(m_hWnd, EnumChildProc, 0);
}
void Window::showNormal()
{
ShowWindow(m_hWnd, SW_RESTORE);
}
void Window::showMinimized()
{
ShowWindow(m_hWnd, SW_SHOWMINIMIZED);
}
void Window::showMaximized()
{
ShowWindow(m_hWnd, SW_SHOWMAXIMIZED);
}
void Window::setIcon(int id)
{
HMODULE hInstance = GetModuleHandle(NULL);
HICON hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(id));
SendMessage(m_hWnd, WM_SETICON, ICON_SMALL, (LPARAM)hIcon);
SendMessage(m_hWnd, WM_SETICON, ICON_BIG, (LPARAM)hIcon);
}
bool Window::isMinimized()
{
WINDOWPLACEMENT wpl;
wpl.length = sizeof(wpl);
if (GetWindowPlacement(m_hWnd, &wpl))
return wpl.showCmd == SW_SHOWMINIMIZED;
return false;
}
bool Window::isMaximized()
{
WINDOWPLACEMENT wpl;
wpl.length = sizeof(wpl);
if (GetWindowPlacement(m_hWnd, &wpl))
return wpl.showCmd == SW_SHOWMAXIMIZED;
return false;
}
Widget *Window::centralWidget()
{
return m_centralWidget;
}
int Window::onStateChanged(const FnVoidInt &callback)
{
m_state_callbacks[++m_connectionId] = callback;
return m_connectionId;
}
void Window::disconnect(int connectionId)
{
auto it = m_state_callbacks.find(connectionId);
if (it != m_state_callbacks.end())
m_state_callbacks.erase(it);
}
bool Window::event(UINT msg, WPARAM wParam, LPARAM lParam, LRESULT *result)
{
switch (msg) {
case WM_DPICHANGED: {
m_dpi = (double)HIWORD(wParam)/96;
RECT *prc = (RECT*)lParam;
GetFrameMetricsForDpi(m_frame, m_dpi, m_isMaximized);
SetWindowPos(m_hWnd, NULL, prc->left, prc->top, prc->right - prc->left, prc->bottom - prc->top, SWP_NOZORDER | SWP_NOACTIVATE);
break;
}
case WM_NCMOUSEMOVE:
case WM_MOUSEMOVE: {
//int x = GET_X_LPARAM(lParam);
//int y = GET_Y_LPARAM(lParam);
//printf("Window Move Event: %d x %d \t %lld\n", x, y, (long long)this);
//fflush(stdout);
break;
}
case WM_MOUSEHOVER:
case WM_NCMOUSEHOVER: {
//int x = GET_X_LPARAM(lParam);
//int y = GET_Y_LPARAM(lParam);
//printf("Window Hover Event: %d x %d \t %lld\n", x, y, (long long)this);
//fflush(stdout);
break;
}
case WM_PAINT: {
RECT rc;
GetClientRect(m_hWnd, &rc);
engine()->Begin(this, m_hWnd, &rc);
engine()->FillBackground();
if (metrics()->value(Metrics::BorderWidth) != 0)
engine()->DrawBorder();
if (m_brdWidth != 0)
engine()->DrawTopBorder(m_brdWidth, m_brdColor);
engine()->End();
*result = FALSE;
return true;
}
case WM_NCPAINT: {
if (Utils::getWinVersion() > WinVer::Win7 || !m_borderless)
return false;
if (HDC hdc = ::GetDCEx(m_hWnd, 0, DCX_WINDOW | DCX_USESTYLE)) {
RECT rcc, rcw;
::GetClientRect(m_hWnd, &rcc);
::GetWindowRect(m_hWnd, &rcw);
POINT pt;
pt.x = rcw.left;
pt.y = rcw.top;
::MapWindowPoints(0, m_hWnd, (LPPOINT)&rcw, (sizeof(RECT)/sizeof(POINT)));
::OffsetRect(&rcc, -rcw.left, -rcw.top);
::OffsetRect(&rcw, -rcw.left, -rcw.top);
HRGN rgntemp = NULL;
if (wParam == NULLREGION || wParam == ERROR) {
::ExcludeClipRect(hdc, rcc.left, rcc.top, rcc.right, rcc.bottom);
} else {
rgntemp = ::CreateRectRgn(rcc.left + pt.x, rcc.top + pt.y, rcc.right + pt.x, rcc.bottom + pt.y);
if (::CombineRgn(rgntemp, (HRGN)wParam, rgntemp, RGN_DIFF) == NULLREGION) {
// nothing to paint
}
::OffsetRgn(rgntemp, -pt.x, -pt.y);
::ExtSelectClipRgn(hdc, rgntemp, RGN_AND);
}
HBRUSH hbrushBkg = ::CreateSolidBrush(palette()->color(Palette::Background));
::FillRect(hdc, &rcw, hbrushBkg);
::DeleteObject(hbrushBkg);
// HRGN hrgn = CreateRectRgn(0, 0, 0, 0);
// GetWindowRgn(msg->hwnd, hrgn);
HBRUSH hbrushBrd = ::CreateSolidBrush(palette()->color(Palette::Border));
::FrameRect(hdc, &rcw, hbrushBrd); // Drawing NC border when using ~WS_CAPTION
// ::FrameRgn(hdc, hrgn, hbrushBrd, 1, 1); // Drawing NC border when using WS_CAPTION
::DeleteObject(hbrushBrd);
// ::DeleteObject(hrgn);
::ReleaseDC(m_hWnd, hdc);
if (rgntemp != 0)
::DeleteObject(rgntemp);
return true;
}
return false;
}
case WM_NCCALCSIZE: {
if (!m_borderless || !wParam)
return false;
NCCALCSIZE_PARAMS *params = (NCCALCSIZE_PARAMS*)lParam;
if (!m_isThemeActive) {
*result = m_isMaximized ? 0 : DefWindowProc(m_hWnd, WM_NCCALCSIZE, wParam, lParam);
return true;
}
LRESULT res = DefWindowProc(m_hWnd, WM_NCCALCSIZE, wParam, lParam);
params->rgrc[0].left -= m_frame.left;
params->rgrc[0].top -= m_frame.top;
params->rgrc[0].right += m_frame.left;
params->rgrc[0].bottom += m_frame.left;
if (m_isMaximized && m_isTaskbarAutoHideOn && (Utils::getWinVersion() >= WinVer::Win10))
params->rgrc[0].bottom -= 2;
*result = res;
return true;
}
case WM_NCHITTEST: {
if (m_isResizable) {
if (m_borderless) {
RECT rect;
GetWindowRect(m_hWnd, &rect);
long x = GET_X_LPARAM(lParam);
long y = GET_Y_LPARAM(lParam);
if (x <= rect.left + m_resAreaWidth) {
if (y <= rect.top + m_resAreaWidth)
*result = HTTOPLEFT;
else
if (y > rect.top + m_resAreaWidth && y < rect.bottom - m_resAreaWidth)
*result = HTLEFT;
else
if (y >= rect.bottom - m_resAreaWidth)
*result = HTBOTTOMLEFT;
} else
if (x > rect.left + m_resAreaWidth && x < rect.right - m_resAreaWidth) {
if (y <= rect.top + m_resAreaWidth)
*result = HTTOP;
else
if (y >= rect.bottom - m_resAreaWidth)
*result = HTBOTTOM;
} else
if (x >= rect.right - m_resAreaWidth) {
if (y <= rect.top + m_resAreaWidth)
*result = HTTOPRIGHT;
else
if (y > rect.top + m_resAreaWidth && y < rect.bottom - m_resAreaWidth)
*result = HTRIGHT;
else
if (y >= rect.bottom - m_resAreaWidth)
*result = HTBOTTOMRIGHT;
}
return *result != 0;
}
} else {
LRESULT hit = DefWindowProc(m_hWnd, msg, wParam, lParam);
if (hit == HTBOTTOM || hit == HTLEFT || hit == HTRIGHT || hit == HTTOP ||
hit == HTBOTTOMLEFT || hit == HTBOTTOMRIGHT || hit == HTTOPLEFT || hit == HTTOPRIGHT) {
*result = HTCLIENT;
return true;
}
}
return false;
}
case WM_NCACTIVATE: {
if (m_borderless) {
if (Utils::getWinVersion() > WinVer::WinXP && Utils::getWinVersion() < WinVer::Win10) {
// Prevent drawing of inactive system frame (needs ~WS_CAPTION or temporary ~WS_VISIBLE to work)
*result = DefWindowProc(m_hWnd, WM_NCACTIVATE, wParam, -1);
return true;
} else
if (Utils::getWinVersion() == WinVer::Win10) {
m_brdColor = Utils::getColorizationColor(LOWORD(wParam), RGB(0xfe, 0xfe, 0xfe));
// POINT pt = {2,2};
// ClientToScreen(m_hWnd, &pt);
// HWND chld = WindowFromPoint(pt);
// if (chld) {
// HDC dc = GetDC(chld);
// int x = pt.x, y = pt.y;
// COLORREF color = GetPixel(dc, x, y);
// ReleaseDC(chld, dc);
// int _red = GetRValue(color);
// int _green = GetGValue(color);
// int _blue = GetBValue(color);
// printf("Red: 0x%02x\n", _red);
// printf("Green: 0x%02x\n", _green);
// printf("Blue: 0x%02x\n", _blue);
// fflush(stdout);
// }
repaint();
}
}
return false;
}
case WM_GETMINMAXINFO: {
bool isMaximized = (bool)IsZoomed(m_hWnd);
if (m_isMaximized != isMaximized) {
m_isMaximized = isMaximized;
GetFrameMetricsForDpi(m_frame, m_dpi, isMaximized);
if (m_borderless && Utils::getWinVersion() == WinVer::Win10) {
if (isMaximized) {
m_brdWidth = 0;
} else {
SystemParametersInfo(SPI_GETBORDER, 0, &m_brdWidth, 0);
}
}
}
if (!m_isResizable) {
MINMAXINFO* minMaxInfo = (MINMAXINFO*)lParam;
minMaxInfo->ptMinTrackSize.x = m_init_size.width;
minMaxInfo->ptMinTrackSize.y = m_init_size.height;
minMaxInfo->ptMaxTrackSize.x = m_init_size.width;
minMaxInfo->ptMaxTrackSize.y = m_init_size.height;
}
break;
}
case WM_THEMECHANGED: {
bool _isThemeActive = isThemeActive();
if (m_isThemeActive != _isThemeActive)
m_isThemeActive = _isThemeActive;
break;
}
case WM_SETTINGCHANGE: {
// if (wParam == SPI_SETWINARRANGING) {
// if (Utils::getWinVersion() > Utils::WinVer::Win10)
// SendMessage((HWND)m_boxTitleBtns->winId(), WM_SETTINGCHANGE, 0, 0);
// }
// printf(" Settings...\n");
// fflush(stdout);
// snapLayoutAllowed = isArrangingAllowed();
break;
}
case WM_SIZING: {
// if (m_borderless)
// RedrawWindow(m_hWnd, NULL, NULL, RDW_INVALIDATE | RDW_NOERASE | RDW_INTERNALPAINT);
break;
}
case WM_SIZE: {
switch (wParam) {
case SIZE_MAXIMIZED:
case SIZE_MINIMIZED:
case SIZE_RESTORED: {
if (m_state != (int)wParam) {
m_state = (int)wParam;
for (auto it = m_state_callbacks.begin(); it != m_state_callbacks.end(); it++)
if (it->second)
(it->second)(m_state);
if (m_borderless) {
if (m_isMaximized) {
if (Utils::getWinVersion() < WinVer::Win10) {
m_resAreaWidth = 0;
Rect rc = availableGeometry(m_hWnd);
int offset = 0;
if (Utils::getWinVersion() == WinVer::WinXP) {
if (isTaskbarAutoHideOn())
offset += NC_AREA_WIDTH + 1;
if (m_isThemeActive) {
rc.x += -NC_AREA_WIDTH;
rc.y += -NC_AREA_WIDTH;
rc.width += 2*NC_AREA_WIDTH;
rc.height += 2*NC_AREA_WIDTH;
}
} else
if (Utils::getWinVersion() > WinVer::WinXP && isTaskbarAutoHideOn())
offset += 2;
SetWindowPos(m_hWnd, NULL, rc.x, rc.y, rc.width, rc.height - offset, SWP_NOZORDER | SWP_NOOWNERZORDER | SWP_NOSENDCHANGING);
}
} else {
if (Utils::getWinVersion() < WinVer::Win10) {
m_resAreaWidth = (int)round(MAIN_WINDOW_BORDER_WIDTH * m_dpi);
if (Utils::getWinVersion() == WinVer::WinXP)
m_resAreaWidth -= NC_AREA_WIDTH;
}
}
}
}
if (m_centralWidget) {
int top_offset = 0;
if (m_borderless && !m_isMaximized && Utils::getWinVersion() == Utils::WinVer::Win10)
top_offset = m_brdWidth;
m_centralWidget->setGeometry(m_contentMargins.left + m_resAreaWidth, m_contentMargins.top + top_offset + m_resAreaWidth,
LOWORD(lParam) - m_contentMargins.right - m_contentMargins.left - 2*m_resAreaWidth,
HIWORD(lParam) - m_contentMargins.bottom - m_contentMargins.top - top_offset - 2*m_resAreaWidth);
}
break;
}
default:
break;
}
break;
}
default:
break;
}
return Widget::event(msg, wParam, lParam, result);
}

View File

@ -0,0 +1,67 @@
#ifndef WINDOW_H
#define WINDOW_H
#include "widget.h"
#define DEFAULT_WINDOW_RECT Rect(100,100,1368,768)
struct FRAME {
FRAME() : left(0), top(0)
{}
FRAME(FRAME &frame) {
left = frame.left;
top = frame.top;
}
int left, top;
};
class Window : public Widget
{
public:
Window(Widget *parent = nullptr, const Rect &rc = DEFAULT_WINDOW_RECT);
virtual ~Window();
void setCentralWidget(Widget*);
void setContentsMargins(int, int, int, int);
void setResizable(bool);
void showAll();
void showNormal();
void showMinimized();
void showMaximized();
void setIcon(int);
void setLayout(Layout*) = delete;
bool isMinimized();
bool isMaximized();
Widget *centralWidget();
Layout *layout() = delete;
/* callback */
int onStateChanged(const FnVoidInt &callback);
virtual void disconnect(int) override;
protected:
virtual bool event(UINT, WPARAM, LPARAM, LRESULT*) override;
private:
Widget *m_centralWidget;
Margins m_contentMargins;
COLORREF m_brdColor;
int m_brdWidth,
m_resAreaWidth,
m_state;
double m_dpi;
FRAME m_frame;
bool m_borderless,
m_isResizable,
m_isMaximized,
m_isThemeActive,
m_isTaskbarAutoHideOn,
m_scaleChanged;
Size m_init_size;
std::unordered_map<int, FnVoidInt> m_state_callbacks;
};
#endif // WINDOW_H

View File

@ -31,34 +31,57 @@
*/
#include "utils.h"
#include "baseutils.h"
#include "resource.h"
#include "translator.h"
#include <Windows.h>
#include <shlwapi.h>
#include <fstream>
#include <regex>
#include <algorithm>
#include <Softpub.h>
#include <TlHelp32.h>
#include <sstream>
#include <Msi.h>
#include <ShlObj.h>
// #include <sstream>
#include "../../src/defines.h"
#include "../../src/prop/defines_p.h"
#define _TR(str) Translator::tr(str).c_str()
#define APP_REG_PATH "\\" REG_GROUP_KEY "\\" REG_APP_NAME
#define BIT123_LAYOUTRTL 0x08000000
#ifndef LOCALE_IREADINGLAYOUT
# define LOCALE_IREADINGLAYOUT 0x70
#endif
static void RegQueryStringValue(HKEY rootKey, LPCWSTR subkey, REGSAM advFlags, LPCWSTR value, wstring &result)
{
HKEY hKey;
if (RegOpenKeyExW(rootKey, subkey, 0, KEY_READ | advFlags, &hKey) == ERROR_SUCCESS) {
DWORD type = REG_SZ, cbData = 0;
if (SHGetValue(hKey, L"", value, &type, NULL, &cbData) == ERROR_SUCCESS) {
wchar_t *pvData = (wchar_t*)malloc(cbData);
if (SHGetValue(hKey, L"", value, &type, (void*)pvData, &cbData) == ERROR_SUCCESS)
result = pvData;
free(pvData);
}
RegCloseKey(hKey);
}
}
namespace NS_Utils
{
wstring GetLastErrorAsString()
wstring GetLastErrorAsString(DWORD _errID)
{
DWORD errID = ::GetLastError();
DWORD errID = _errID != 0 ? _errID : ::GetLastError();
if (errID == 0)
return _T("");
LPTSTR msgBuff = NULL;
size_t size = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
NULL, errID, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)&msgBuff, 0, NULL);
wstring msg(msgBuff, (int)size);
wstring msg = _TR(LABEL_ERR_COMMON) + wstring(L" ") + std::to_wstring(errID);
if (size > 0)
msg.append(L"\n" + wstring(msgBuff, (int)size));
LocalFree(msgBuff);
return msg;
}
@ -68,13 +91,13 @@ namespace NS_Utils
if (showError)
str += _T(" ") + GetLastErrorAsString();
wstring caption(_T(" "));
caption.append(_TR(CAPTION_TEXT));
caption.append(_TR(CAPTION));
MessageBox(NULL, str.c_str(), caption.c_str(), MB_ICONERROR | MB_SERVICE_NOTIFICATION_NT3X | MB_SETFOREGROUND);
}
bool IsRtlLanguage(unsigned long lcid)
{
if (NS_File::getWinVersion() >= WinVer::Win7) {
if (Utils::getWinVersion() >= Utils::WinVer::Win7) {
DWORD layout = 0;
if (GetLocaleInfo(lcid, LOCALE_IREADINGLAYOUT | LOCALE_RETURN_NUMBER, (LPWSTR)&layout, sizeof(layout)/sizeof(WCHAR)) > 0)
return layout == 1;
@ -85,15 +108,123 @@ namespace NS_Utils
}
return false;
}
bool IsWin64()
{
#ifdef _WIN64
return true;
#else
BOOL wow64 = FALSE;
return IsWow64Process(GetCurrentProcess(), &wow64) && wow64;
#endif
}
bool IsAppInstalled(wstring &path, wstring *arch)
{
std::vector<REGSAM> flags{0};
if (NS_Utils::IsWin64()) {
#ifdef _WIN64
flags.push_back(KEY_WOW64_32KEY);
#else
flags.push_back(KEY_WOW64_64KEY);
#endif
}
wstring subkey(L"Software");
subkey += _T(APP_REG_PATH);
for (auto &flag : flags) {
RegQueryStringValue(HKEY_LOCAL_MACHINE, subkey.c_str(), flag, L"AppPath", path);
if (!path.empty() /*&& NS_File::fileExists(path + _T(APP_LAUNCH_NAME))*/) {
if (arch) {
#ifdef _WIN64
*arch = (flag == 0) ? L"x64" : L"x86";
#else
*arch = (flag == 0) ? L"x86" : L"x64";
#endif
}
return true;
}
}
return false;
}
void InstalledVerInfo(LPCWSTR value, wstring &name, wstring &arch)
{
if (!name.empty())
name.clear();
std::vector<REGSAM> flags{0};
if (NS_Utils::IsWin64()) {
#ifdef _WIN64
flags.push_back(KEY_WOW64_32KEY);
#else
flags.push_back(KEY_WOW64_64KEY);
#endif
}
for (auto &flag : flags) {
wstring subkey(L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\");
subkey += _T(WINDOW_NAME);
for (int i = 0; i < 2; i++) {
RegQueryStringValue(HKEY_LOCAL_MACHINE, subkey.c_str(), flag, value, name);
if (!name.empty()) {
if (arch.empty()) {
#ifdef _WIN64
arch = (flag == 0) ? L"x64" : L"x86";
#else
arch = (flag == 0) ? L"x86" : L"x64";
#endif
}
return;
}
subkey += L"_is1";
}
}
}
void Replace(wstring &str, const wstring &from, const wstring &to) {
if (from.empty())
return;
size_t start_pos = 0;
while((start_pos = str.find(from, start_pos)) != std::wstring::npos) {
str.replace(start_pos, from.length(), to);
start_pos += to.length();
}
}
wstring MsiGetProperty(LPCWSTR prodCode, LPCWSTR propName)
{
DWORD buffSize = 0;
UINT res = MsiGetProductInfoW(prodCode, propName, NULL, &buffSize);
if ((res == ERROR_MORE_DATA || res == ERROR_SUCCESS) && buffSize > 0) {
++buffSize;
wchar_t *value = new wchar_t[buffSize];
if (MsiGetProductInfoW(prodCode, propName, value, &buffSize) == ERROR_SUCCESS) {
wstring propValue = value;
delete[] value;
return propValue;
}
delete[] value;
}
return wstring();
}
wstring MsiProductCode(const wstring &prodName)
{
DWORD ind = 0;
WCHAR prodCode[39];
while (MsiEnumProductsEx(NULL, NULL, MSIINSTALLCONTEXT_MACHINE, ind++, prodCode, NULL, NULL, NULL) == ERROR_SUCCESS) {
if (MsiGetProperty(prodCode, INSTALLPROPERTY_PRODUCTNAME) == prodName)
return prodCode;
}
return wstring();
}
}
namespace NS_File
{
bool runProcess(const wstring &fileName, const wstring &args, bool runAsAdmin)
bool runProcess(const wstring &fileName, const wstring &args, bool runAsAdmin, bool wait)
{
SHELLEXECUTEINFO shExInfo = {0};
shExInfo.cbSize = sizeof(shExInfo);
shExInfo.fMask = SEE_MASK_NOCLOSEPROCESS | SEE_MASK_NO_CONSOLE | SEE_MASK_FLAG_NO_UI;
shExInfo.fMask = SEE_MASK_NOCLOSEPROCESS | SEE_MASK_NO_CONSOLE /*| SEE_MASK_FLAG_NO_UI*/;
shExInfo.hwnd = NULL;
shExInfo.lpVerb = runAsAdmin ? _T("runas") : _T("open");
shExInfo.lpFile = fileName.c_str();
@ -102,7 +233,8 @@ namespace NS_File
shExInfo.nShow = SW_HIDE;
shExInfo.hInstApp = NULL;
if (ShellExecuteEx(&shExInfo)) {
WaitForSingleObject(shExInfo.hProcess, INFINITE);
if (wait)
WaitForSingleObject(shExInfo.hProcess, INFINITE);
CloseHandle(shExInfo.hProcess);
return true;
}
@ -144,14 +276,35 @@ namespace NS_File
return DeleteFile(filePath.c_str()) != 0;
}
bool removeDirRecursively(const wstring &dir)
{
WCHAR pFrom[_MAX_PATH + 1] = {0};
swprintf_s(pFrom, sizeof(pFrom)/sizeof(WCHAR), L"%s%c", dir.c_str(), L'\0');
SHFILEOPSTRUCT fop = {
NULL,
FO_DELETE,
pFrom,
NULL,
FOF_NOCONFIRMATION | FOF_NOERRORUI | FOF_SILENT,
FALSE,
0,
NULL
};
return SHFileOperation(&fop) == 0;
}
wstring fromNativeSeparators(const wstring &path)
{
return std::regex_replace(path, std::wregex(_T("\\\\")), _T("/"));
wstring _path(path);
std::replace(_path.begin(), _path.end(), L'\\', L'/');
return _path;
}
wstring toNativeSeparators(const wstring &path)
{
return std::regex_replace(path, std::wregex(_T("\\/")), _T("\\"));
wstring _path(path);
std::replace(_path.begin(), _path.end(), L'/', L'\\');
return _path;
}
wstring parentPath(const wstring &path)
@ -160,12 +313,12 @@ namespace NS_File
return (delim == wstring::npos) ? _T("") : path.substr(0, delim);
}
// wstring tempPath()
// {
// TCHAR buff[MAX_PATH] = {0};
// DWORD res = ::GetTempPath(MAX_PATH, buff);
// return (res != 0) ? fromNativeSeparators(parentPath(buff)) : _T("");
// }
wstring tempPath()
{
TCHAR buff[MAX_PATH] = {0};
DWORD res = ::GetTempPath(MAX_PATH, buff);
return (res != 0) ? fromNativeSeparators(parentPath(buff)) : _T("");
}
wstring appPath()
{
@ -174,57 +327,56 @@ namespace NS_File
return (res != 0) ? fromNativeSeparators(parentPath(buff)) : _T("");
}
WinVer getWinVersion()
wstring generateTmpFileName(const wstring &ext)
{
static WinVer winVer = WinVer::Undef;
if (winVer == WinVer::Undef) {
if (HMODULE module = GetModuleHandleA("ntdll")) {
NTSTATUS(WINAPI *RtlGetVersion)(LPOSVERSIONINFOEXW);
*(FARPROC*)&RtlGetVersion = GetProcAddress(module, "RtlGetVersion");
if (RtlGetVersion) {
OSVERSIONINFOEXW os = {0};
os.dwOSVersionInfoSize = sizeof(os);
RtlGetVersion(&os);
winVer = os.dwMajorVersion == 5L && (os.dwMinorVersion == 1L || os.dwMinorVersion == 2L) ? WinVer::WinXP :
os.dwMajorVersion == 6L && os.dwMinorVersion == 0L ? WinVer::WinVista :
os.dwMajorVersion == 6L && os.dwMinorVersion == 1L ? WinVer::Win7 :
os.dwMajorVersion == 6L && os.dwMinorVersion == 2L ? WinVer::Win8 :
os.dwMajorVersion == 6L && os.dwMinorVersion == 3L ? WinVer::Win8_1 :
os.dwMajorVersion == 10L && os.dwMinorVersion == 0L && os.dwBuildNumber < 22000 ? WinVer::Win10 :
os.dwMajorVersion == 10L && os.dwMinorVersion == 0L && os.dwBuildNumber >= 22000 ? WinVer::Win11 :
os.dwMajorVersion == 10L && os.dwMinorVersion > 0L ? WinVer::Win11 :
os.dwMajorVersion > 10L ? WinVer::Win11 : WinVer::Undef;
}
}
}
return winVer;
wstring uuid_tstr;
UUID uuid = {0};
RPC_WSTR wszUuid = NULL;
if (UuidCreate(&uuid) == RPC_S_OK && UuidToStringW(&uuid, &wszUuid) == RPC_S_OK) {
uuid_tstr = ((wchar_t*)wszUuid);
RpcStringFreeW(&wszUuid);
} else
uuid_tstr = L"00000000-0000-0000-0000-000000000000";
return NS_File::tempPath() + _T("/") + _T(FILE_PREFIX) + uuid_tstr + ext;
}
// bool verifyEmbeddedSignature(const wstring &fileName)
// {
// WINTRUST_FILE_INFO fileInfo;
// ZeroMemory(&fileInfo, sizeof(fileInfo));
// fileInfo.cbStruct = sizeof(WINTRUST_FILE_INFO);
// fileInfo.pcwszFilePath = fileName.c_str();
// fileInfo.hFile = NULL;
// fileInfo.pgKnownSubject = NULL;
bool verifyEmbeddedSignature(const wstring &fileName)
{
WINTRUST_FILE_INFO wfi;
ZeroMemory(&wfi, sizeof(wfi));
wfi.cbStruct = sizeof(WINTRUST_FILE_INFO);
wfi.pcwszFilePath = fileName.c_str();
wfi.hFile = NULL;
wfi.pgKnownSubject = NULL;
// GUID guidAction = WINTRUST_ACTION_GENERIC_VERIFY_V2;
// WINTRUST_DATA winTrustData;
// ZeroMemory(&winTrustData, sizeof(winTrustData));
// winTrustData.cbStruct = sizeof(WINTRUST_DATA);
// winTrustData.pPolicyCallbackData = NULL;
// winTrustData.pSIPClientData = NULL;
// winTrustData.dwUIChoice = WTD_UI_NONE;
// winTrustData.fdwRevocationChecks = WTD_REVOKE_NONE;
// winTrustData.dwUnionChoice = WTD_CHOICE_FILE;
// winTrustData.dwStateAction = WTD_STATEACTION_VERIFY;
// winTrustData.hWVTStateData = NULL;
// winTrustData.pwszURLReference = NULL;
// winTrustData.dwUIContext = 0;
// winTrustData.pFile = &fileInfo;
// return WinVerifyTrust(NULL, &guidAction, &winTrustData) == ERROR_SUCCESS;
// }
GUID guidAction = WINTRUST_ACTION_GENERIC_VERIFY_V2;
WINTRUST_DATA wtd;
ZeroMemory(&wtd, sizeof(wtd));
wtd.cbStruct = sizeof(WINTRUST_DATA);
wtd.pPolicyCallbackData = NULL;
wtd.pSIPClientData = NULL;
wtd.dwUIChoice = WTD_UI_NONE;
wtd.fdwRevocationChecks = WTD_REVOKE_NONE;
wtd.dwUnionChoice = WTD_CHOICE_FILE;
wtd.dwStateAction = WTD_STATEACTION_VERIFY;
wtd.hWVTStateData = NULL;
wtd.pwszURLReference = NULL;
wtd.dwUIContext = 0;
wtd.pFile = &wfi;
return WinVerifyTrust(NULL, &guidAction, &wtd) == ERROR_SUCCESS;
}
wstring appDataPath()
{
TCHAR buff[MAX_PATH] = {0};
if (SUCCEEDED(SHGetFolderPathW(NULL, CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, buff))) {
wstring path(buff);
path.append(_T(APP_REG_PATH));
path.append(_T("\\data"));
return path;
}
return _T("");
}
}
namespace NS_Logger

View File

@ -33,14 +33,12 @@
#ifndef UTILS_H
#define UTILS_H
#include <Windows.h>
#include <string>
#include <list>
#include <tchar.h>
using std::string;
using std::wstring;
using std::to_wstring;
using std::list;
#define DEFAULT_ERROR_MESSAGE _T("An error occurred: ") + \
wstring(_T(__FUNCTION__)) + _T(" Line: ") + to_wstring(__LINE__)
@ -48,30 +46,34 @@ using std::list;
_T(" ") + NS_Utils::GetLastErrorAsString()
enum class WinVer : unsigned char {
Undef, WinXP, WinVista, Win7, Win8, Win8_1, Win10, Win11
};
namespace NS_Utils
{
wstring GetLastErrorAsString();
wstring GetLastErrorAsString(DWORD errID = 0);
void ShowMessage(wstring str, bool showError = false);
bool IsRtlLanguage(unsigned long lcid);
bool IsWin64();
bool IsAppInstalled(wstring &path, wstring *arch = nullptr);
void InstalledVerInfo(LPCWSTR value, wstring &name, wstring &arch);
void Replace(wstring &str, const wstring &from, const wstring &to);
wstring MsiGetProperty(LPCWSTR prodCode, LPCWSTR propName);
wstring MsiProductCode(const wstring &prodName);
}
namespace NS_File
{
bool runProcess(const wstring &fileName, const wstring &args, bool runAsAdmin = false);
//bool isProcessRunning(const wstring &fileName);
bool runProcess(const wstring &fileName, const wstring &args, bool runAsAdmin = false, bool wait = true);
// bool isProcessRunning(const wstring &fileName);
bool fileExists(const wstring &filePath);
bool removeFile(const wstring &filePath);
bool removeDirRecursively(const wstring &dir);
wstring fromNativeSeparators(const wstring &path);
wstring toNativeSeparators(const wstring &path);
wstring parentPath(const wstring &path);
//wstring tempPath();
wstring tempPath();
wstring appPath();
WinVer getWinVersion();
//bool verifyEmbeddedSignature(const wstring &fileName);
wstring appDataPath();
wstring generateTmpFileName(const wstring &ext);
bool verifyEmbeddedSignature(const wstring &fileName);
}
namespace NS_Logger