diff --git a/win-linux/extras/online-installer/OnlineInstaller.pro b/win-linux/extras/online-installer/OnlineInstaller.pro index 15a81d34c..999e4d325 100644 --- a/win-linux/extras/online-installer/OnlineInstaller.pro +++ b/win-linux/extras/online-installer/OnlineInstaller.pro @@ -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\\\") diff --git a/win-linux/extras/online-installer/common.pri b/win-linux/extras/online-installer/common.pri index 61773b3fd..bc52abd47 100644 --- a/win-linux/extras/online-installer/common.pri +++ b/win-linux/extras/online-installer/common.pri @@ -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 - -OTHER_FILES += $$PWD/res/dialog.rc \ + $$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/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,19 @@ build_xp { DEFINES += __OS_WIN_XP } +DEFINES -= NOMINMAX + LIBS += -luser32 \ -lshell32 \ + -lshlwapi \ -lwinhttp \ -lwintrust \ + -lgdi32 \ + -lgdiplus \ + -ladvapi32 \ + -lrpcrt4 \ + -lole32 \ + -lmsi \ -lcomctl32 OBJECTS_DIR = $$DESTDIR/obj diff --git a/win-linux/extras/online-installer/res/dialog.rc b/win-linux/extras/online-installer/res/dialog.rc deleted file mode 100644 index 14c403f34..000000000 --- a/win-linux/extras/online-installer/res/dialog.rc +++ /dev/null @@ -1,68 +0,0 @@ -#pragma code_page(65001) -#include -#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 diff --git a/win-linux/extras/online-installer/res/icons/welcome.png b/win-linux/extras/online-installer/res/icons/welcome.png new file mode 100644 index 000000000..d3fabc3a4 Binary files /dev/null and b/win-linux/extras/online-installer/res/icons/welcome.png differ diff --git a/win-linux/extras/online-installer/res/langs/langs.iss b/win-linux/extras/online-installer/res/langs/langs.iss index c9f96ba47..643cf2b29 100644 --- a/win-linux/extras/online-installer/res/langs/langs.iss +++ b/win-linux/extras/online-installer/res/langs/langs.iss @@ -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.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.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.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.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.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.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.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.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.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.MSG_REMOVE =This will remove %1 and its components. +ru.MSG_REMOVE =Это приведет к удалению %1 и его компонентов. + +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 =Очистить пользовательские настройки и кэшированные данные diff --git a/win-linux/extras/online-installer/res/version.rc b/win-linux/extras/online-installer/res/version.rc new file mode 100644 index 000000000..e880f1f6c --- /dev/null +++ b/win-linux/extras/online-installer/res/version.rc @@ -0,0 +1,37 @@ +#pragma code_page(65001) +#include +#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 diff --git a/win-linux/extras/online-installer/src/cdownloader.cpp b/win-linux/extras/online-installer/src/cdownloader.cpp index f3440d02c..b1c9aa221 100644 --- a/win-linux/extras/online-installer/src/cdownloader.cpp +++ b/win-linux/extras/online-installer/src/cdownloader.cpp @@ -33,17 +33,19 @@ #include "cdownloader.h" #include #include +#include -#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 +struct Connection { + ~Connection() { + if (hRequest) WinHttpCloseHandle(hRequest); + if (hConnect) WinHttpCloseHandle(hConnect); + if (hSession) WinHttpCloseHandle(hSession); + } + HINTERNET hSession = NULL, hConnect = NULL, hRequest = NULL; +}; -int downloadToFile(const wstring &url, const wstring &filePath, std::atomic_bool &run, FnVoidInt &progress_callback) +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; + return ERROR_SUCCESS; +} + +class CDownloaderPrivate +{ +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; - 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((100.0 * dwProgress) / dwProgressMax); - if (percent != prev_percent) { - progress_callback(percent); - prev_percent = percent; + 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((100.0 * dwProgress) / dwProgressMax); + if (percent != prev_percent) { + m_progress_callback(percent); + prev_percent = percent; + } } - } - } while (dwSize > 0); + } while (dwSize > 0); -cleanup : - if (hFile != INVALID_HANDLE_VALUE) { CloseHandle(hFile); - if (result == DNL_ABORT) - DeleteFile(filePath.c_str()); + if (result == ERROR_CANCELLED) + DeleteFile(m_filePath.c_str()); + return result; } - WinHttpCloseHandle(hRequest); - WinHttpCloseHandle(hConnect); - WinHttpCloseHandle(hSession); - return result; + FnVoidUlUl m_query_callback = nullptr; + FnVoidUl m_complete_callback = nullptr; + FnVoidInt m_progress_callback = nullptr; + wstring m_url, + m_filePath; + std::future m_future; + std::atomic_bool m_run, + m_lock; +}; + +CDownloader::CDownloader() : + pimpl(new CDownloaderPrivate) +{ + pimpl->m_run = true; + pimpl->m_lock = false; } -CDownloader::CDownloader() +CDownloader::~CDownloader() { - m_run = true; - m_lock = false; + pimpl->m_run = false; + if (pimpl->m_future.valid()) + pimpl->m_future.wait(); + delete pimpl, pimpl = nullptr; } -CDownloader::~CDownloader() +void CDownloader::queryContentLenght(const wstring &url) { - m_run = false; - if (m_future.valid()) - m_future.wait(); + 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::onQueryResponse(FnVoidUlUl callback) +{ + pimpl->m_query_callback = callback; } -void CDownloader::onComplete(FnVoidInt callback) +void CDownloader::onComplete(FnVoidUl callback) { - m_complete_callback = callback; + pimpl->m_complete_callback = callback; } void CDownloader::onProgress(FnVoidInt callback) { - m_progress_callback = callback; + pimpl->m_progress_callback = callback; } diff --git a/win-linux/extras/online-installer/src/cdownloader.h b/win-linux/extras/online-installer/src/cdownloader.h index cb93b5dfb..c0e3f38e6 100644 --- a/win-linux/extras/online-installer/src/cdownloader.h +++ b/win-linux/extras/online-installer/src/cdownloader.h @@ -35,35 +35,36 @@ #include #include -#include +typedef unsigned long ulong; typedef std::function FnVoidInt; +typedef std::function FnVoidUl; +typedef std::function 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 m_future; - std::atomic_bool m_run, - m_lock; + CDownloaderPrivate *pimpl = nullptr; }; #endif // CDOWNLOADER_H diff --git a/win-linux/extras/online-installer/src/main.cpp b/win-linux/extras/online-installer/src/main.cpp index 50c306e57..1f85c2fe7 100644 --- a/win-linux/extras/online-installer/src/main.cpp +++ b/win-linux/extras/online-installer/src/main.cpp @@ -1,10 +1,10 @@ -#include -#include +#include "application.h" +#include "mainwindow.h" #include #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,56 @@ 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)); - 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 (!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; + 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; } - 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()); + 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; } - 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)); + wstring url_or_path, arch; + bool app_installed = NS_Utils::IsAppInstalled(url_or_path, &arch); + if (!app_installed) { + SYSTEM_INFO info; + GetSystemInfo(&info); + if (info.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64) { + url_or_path = (Utils::getWinVersion() <= Utils::WinVer::WinVista) ? _T(URL_INSTALL_X64_XP) : _T(URL_INSTALL_X64); } else - if (error == -2) { - if (IsWindow(hLabelMsg)) - SetWindowText(hLabelMsg, _TR(LABEL_MESSAGE_TEXT_ERR3)); + if (info.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_INTEL) { + url_or_path = (Utils::getWinVersion() <= Utils::WinVer::WinVista) ? _T(URL_INSTALL_X86_XP) : _T(URL_INSTALL_X86); } else { - if (IsWindow(hLabelMsg)) - SetWindowText(hLabelMsg, _TR(LABEL_MESSAGE_TEXT_ERR4)); + NS_Utils::ShowMessage(_TR(MSG_ERR_ARCH)); + return 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; + 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); + }); + if (!app_installed) + w.initInstallationMode(url_or_path); + else + w.initControlMode(arch); + w.showAll(); + int exit_code = app.exec(); + CloseHandle(hMutex); + return exit_code; } diff --git a/win-linux/extras/online-installer/src/mainwindow.cpp b/win-linux/extras/online-installer/src/mainwindow.cpp new file mode 100644 index 000000000..afa246251 --- /dev/null +++ b/win-linux/extras/online-installer/src/mainwindow.cpp @@ -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 +#include +#include +#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 +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 *func = (std::function*)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 &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 +void MainWindow::invokeMethod(Fn&& fn, Args&&... args) +{ + std::function *func = new std::function(std::bind(std::forward(fn), std::forward(args)...)); + PostMessage(m_hWnd, WM_INVOKEMETHOD, (WPARAM)func, 0); +} // NOLINT diff --git a/win-linux/extras/online-installer/src/mainwindow.h b/win-linux/extras/online-installer/src/mainwindow.h new file mode 100644 index 000000000..75961f8bc --- /dev/null +++ b/win-linux/extras/online-installer/src/mainwindow.h @@ -0,0 +1,67 @@ +#ifndef MAINWINDOW_H +#define MAINWINDOW_H + +#include "window.h" +#include + + +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 &onComplete); + template + 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 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 diff --git a/win-linux/extras/online-installer/src/resource.h b/win-linux/extras/online-installer/src/resource.h index 4a2488eca..1dbed03dc 100644 --- a/win-linux/extras/online-installer/src/resource.h +++ b/win-linux/extras/online-installer/src/resource.h @@ -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" diff --git a/win-linux/extras/online-installer/src/translator.h b/win-linux/extras/online-installer/src/translator.h index 5715d90b8..2828d4cbe 100644 --- a/win-linux/extras/online-installer/src/translator.h +++ b/win-linux/extras/online-installer/src/translator.h @@ -29,7 +29,7 @@ class Translator 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, diff --git a/win-linux/extras/online-installer/src/uiclasses/abstractbutton.cpp b/win-linux/extras/online-installer/src/uiclasses/abstractbutton.cpp new file mode 100644 index 000000000..f0fe8c2fc --- /dev/null +++ b/win-linux/extras/online-installer/src/uiclasses/abstractbutton.cpp @@ -0,0 +1,87 @@ +#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; + if (IsWindowVisible(m_hWnd)) + 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)(); + } + } +} diff --git a/win-linux/extras/online-installer/src/uiclasses/abstractbutton.h b/win-linux/extras/online-installer/src/uiclasses/abstractbutton.h new file mode 100644 index 000000000..4673fbc69 --- /dev/null +++ b/win-linux/extras/online-installer/src/uiclasses/abstractbutton.h @@ -0,0 +1,30 @@ +#ifndef ABSTRACTBUTTON_H +#define ABSTRACTBUTTON_H + +#include "widget.h" +#include + + +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 m_click_callbacks; +}; + +#endif // ABSTRACTBUTTON_H diff --git a/win-linux/extras/online-installer/src/uiclasses/application.cpp b/win-linux/extras/online-installer/src/uiclasses/application.cpp new file mode 100644 index 000000000..f826f5ec7 --- /dev/null +++ b/win-linux/extras/online-installer/src/uiclasses/application.cpp @@ -0,0 +1,180 @@ +#include "application.h" +#include "widget.h" +#include "src/resource.h" +#include + + +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); + // } +} + + diff --git a/win-linux/extras/online-installer/src/uiclasses/application.h b/win-linux/extras/online-installer/src/uiclasses/application.h new file mode 100644 index 000000000..6d8d6c69f --- /dev/null +++ b/win-linux/extras/online-installer/src/uiclasses/application.h @@ -0,0 +1,34 @@ +#ifndef APPLICATION_H +#define APPLICATION_H + +#include "object.h" +#include "common.h" +#include + + +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 diff --git a/win-linux/extras/online-installer/src/uiclasses/baseutils.cpp b/win-linux/extras/online-installer/src/uiclasses/baseutils.cpp new file mode 100644 index 000000000..c0e6189b1 --- /dev/null +++ b/win-linux/extras/online-installer/src/uiclasses/baseutils.cpp @@ -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; +} diff --git a/win-linux/extras/online-installer/src/uiclasses/baseutils.h b/win-linux/extras/online-installer/src/uiclasses/baseutils.h new file mode 100644 index 000000000..da68271a4 --- /dev/null +++ b/win-linux/extras/online-installer/src/uiclasses/baseutils.h @@ -0,0 +1,17 @@ +#ifndef BASEUTILS_H +#define BASEUTILS_H + +#include + + +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 diff --git a/win-linux/extras/online-installer/src/uiclasses/boxlayout.cpp b/win-linux/extras/online-installer/src/uiclasses/boxlayout.cpp new file mode 100644 index 000000000..d882d3627 --- /dev/null +++ b/win-linux/extras/online-installer/src/uiclasses/boxlayout.cpp @@ -0,0 +1,211 @@ +#include "boxlayout.h" +#include "widget.h" +#include + + +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; + } + } + } + } +} + diff --git a/win-linux/extras/online-installer/src/uiclasses/boxlayout.h b/win-linux/extras/online-installer/src/uiclasses/boxlayout.h new file mode 100644 index 000000000..49f971fb9 --- /dev/null +++ b/win-linux/extras/online-installer/src/uiclasses/boxlayout.h @@ -0,0 +1,33 @@ +#ifndef BOXLAYOUT_H +#define BOXLAYOUT_H + +#include "layout.h" +#include + + +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 m_destroy_conn; + std::vector m_widgets; + Direction m_direction; + int m_spacing; + int m_total_fixed_size; +}; + +#endif // BOXLAYOUT_H diff --git a/win-linux/extras/online-installer/src/uiclasses/button.cpp b/win-linux/extras/online-installer/src/uiclasses/button.cpp new file mode 100644 index 000000000..1cdd22cd4 --- /dev/null +++ b/win-linux/extras/online-installer/src/uiclasses/button.cpp @@ -0,0 +1,203 @@ +#include "button.h" +#include "baseutils.h" +#include "drawningengine.h" +#include "metrics.h" +#include "palette.h" +#include + + +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); + if (IsWindowVisible(m_hWnd)) + 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); + if (IsWindowVisible(m_hWnd)) + 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()); + if (IsWindowVisible(m_hWnd)) + 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); + } + } + if (IsWindowVisible(m_hWnd)) + update(); +} + +void Button::setIconSize(int w, int h) +{ + metrics()->setMetrics(Metrics::IconWidth, w); + metrics()->setMetrics(Metrics::IconHeight, h); + if (IsWindowVisible(m_hWnd)) + update(); +} + +void Button::setSupportSnapLayouts() +{ + if (Utils::getWinVersion() > Utils::WinVer::Win10) { + snapLayoutAllowed = isArrangingAllowed(); + supportSnapLayouts = true; + } +} + +void Button::setStockIcon(StockIcon stockIcon) +{ + m_stockIcon = stockIcon; + if (IsWindowVisible(m_hWnd)) + 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); +} diff --git a/win-linux/extras/online-installer/src/uiclasses/button.h b/win-linux/extras/online-installer/src/uiclasses/button.h new file mode 100644 index 000000000..2c1eaffce --- /dev/null +++ b/win-linux/extras/online-installer/src/uiclasses/button.h @@ -0,0 +1,45 @@ +#ifndef BUTTON_H +#define BUTTON_H + +#include "abstractbutton.h" +#include + + +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 diff --git a/win-linux/extras/online-installer/src/uiclasses/caption.cpp b/win-linux/extras/online-installer/src/uiclasses/caption.cpp new file mode 100644 index 000000000..ee2d7a3a0 --- /dev/null +++ b/win-linux/extras/online-installer/src/uiclasses/caption.cpp @@ -0,0 +1,117 @@ +#include "caption.h" +#include "baseutils.h" +#include "metrics.h" +#include "drawningengine.h" +#include + +#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; +} diff --git a/win-linux/extras/online-installer/src/uiclasses/caption.h b/win-linux/extras/online-installer/src/uiclasses/caption.h new file mode 100644 index 000000000..cf56e4985 --- /dev/null +++ b/win-linux/extras/online-installer/src/uiclasses/caption.h @@ -0,0 +1,30 @@ +#ifndef CAPTION_H +#define CAPTION_H + +#include "label.h" +#include + + +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 diff --git a/win-linux/extras/online-installer/src/uiclasses/checkbox.cpp b/win-linux/extras/online-installer/src/uiclasses/checkbox.cpp new file mode 100644 index 000000000..00a067963 --- /dev/null +++ b/win-linux/extras/online-installer/src/uiclasses/checkbox.cpp @@ -0,0 +1,60 @@ +#include "checkbox.h" +#include "drawningengine.h" +#include "metrics.h" +#include + + +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; + if (IsWindowVisible(m_hWnd)) + 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(); +} diff --git a/win-linux/extras/online-installer/src/uiclasses/checkbox.h b/win-linux/extras/online-installer/src/uiclasses/checkbox.h new file mode 100644 index 000000000..eb7c3f7c8 --- /dev/null +++ b/win-linux/extras/online-installer/src/uiclasses/checkbox.h @@ -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 diff --git a/win-linux/extras/online-installer/src/uiclasses/common.cpp b/win-linux/extras/online-installer/src/uiclasses/common.cpp new file mode 100644 index 000000000..ba0660b86 --- /dev/null +++ b/win-linux/extras/online-installer/src/uiclasses/common.cpp @@ -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; +} diff --git a/win-linux/extras/online-installer/src/uiclasses/common.h b/win-linux/extras/online-installer/src/uiclasses/common.h new file mode 100644 index 000000000..089a15702 --- /dev/null +++ b/win-linux/extras/online-installer/src/uiclasses/common.h @@ -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 diff --git a/win-linux/extras/online-installer/src/uiclasses/commondefines.h b/win-linux/extras/online-installer/src/uiclasses/commondefines.h new file mode 100644 index 000000000..7ccd81d0a --- /dev/null +++ b/win-linux/extras/online-installer/src/uiclasses/commondefines.h @@ -0,0 +1,17 @@ +#ifndef COMMONDEFINES_H +#define COMMONDEFINES_H + +#include + +#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 FnVoidVoid; +typedef std::function FnVoidInt; +typedef std::function FnVoidIntInt; +typedef std::function FnVoidBoolPtr; + +#endif // COMMONDEFINES_H diff --git a/win-linux/extras/online-installer/src/uiclasses/dialog.cpp b/win-linux/extras/online-installer/src/uiclasses/dialog.cpp new file mode 100644 index 000000000..cb7b2cd12 --- /dev/null +++ b/win-linux/extras/online-installer/src/uiclasses/dialog.cpp @@ -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); +} diff --git a/win-linux/extras/online-installer/src/uiclasses/dialog.h b/win-linux/extras/online-installer/src/uiclasses/dialog.h new file mode 100644 index 000000000..beab8a4b1 --- /dev/null +++ b/win-linux/extras/online-installer/src/uiclasses/dialog.h @@ -0,0 +1,25 @@ +#ifndef DIALOG_H +#define DIALOG_H + +#include "widget.h" +#include + +#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 diff --git a/win-linux/extras/online-installer/src/uiclasses/drawingsurface.cpp b/win-linux/extras/online-installer/src/uiclasses/drawingsurface.cpp new file mode 100644 index 000000000..b307ce8a8 --- /dev/null +++ b/win-linux/extras/online-installer/src/uiclasses/drawingsurface.cpp @@ -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; +} diff --git a/win-linux/extras/online-installer/src/uiclasses/drawingsurface.h b/win-linux/extras/online-installer/src/uiclasses/drawingsurface.h new file mode 100644 index 000000000..1dcd8c9ca --- /dev/null +++ b/win-linux/extras/online-installer/src/uiclasses/drawingsurface.h @@ -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 diff --git a/win-linux/extras/online-installer/src/uiclasses/drawningengine.cpp b/win-linux/extras/online-installer/src/uiclasses/drawningengine.cpp new file mode 100644 index 000000000..d226fdcc0 --- /dev/null +++ b/win-linux/extras/online-installer/src/uiclasses/drawningengine.cpp @@ -0,0 +1,570 @@ +#include "drawningengine.h" +#include "drawingsurface.h" +#include "palette.h" +#include "metrics.h" +#include + + +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; +// } diff --git a/win-linux/extras/online-installer/src/uiclasses/drawningengine.h b/win-linux/extras/online-installer/src/uiclasses/drawningengine.h new file mode 100644 index 000000000..6333d216b --- /dev/null +++ b/win-linux/extras/online-installer/src/uiclasses/drawningengine.h @@ -0,0 +1,59 @@ +#ifndef DRAWNINGENGINE_H +#define DRAWNINGENGINE_H + +#include +#include +#include + + +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 diff --git a/win-linux/extras/online-installer/src/uiclasses/label.cpp b/win-linux/extras/online-installer/src/uiclasses/label.cpp new file mode 100644 index 000000000..5d47c20ea --- /dev/null +++ b/win-linux/extras/online-installer/src/uiclasses/label.cpp @@ -0,0 +1,192 @@ +#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; + if (IsWindowVisible(m_hWnd)) + 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); + if (IsWindowVisible(m_hWnd)) + 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); + if (IsWindowVisible(m_hWnd)) + 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()); + if (IsWindowVisible(m_hWnd)) + 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); + } + } + if (IsWindowVisible(m_hWnd)) + 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); + } + } + if (IsWindowVisible(m_hWnd)) + update(); +} + +void Label::setIconSize(int w, int h) +{ + metrics()->setMetrics(Metrics::IconWidth, w); + metrics()->setMetrics(Metrics::IconHeight, h); + if (IsWindowVisible(m_hWnd)) + 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); +} diff --git a/win-linux/extras/online-installer/src/uiclasses/label.h b/win-linux/extras/online-installer/src/uiclasses/label.h new file mode 100644 index 000000000..39b00d8cf --- /dev/null +++ b/win-linux/extras/online-installer/src/uiclasses/label.h @@ -0,0 +1,35 @@ +#ifndef LABEL_H +#define LABEL_H + +#include "widget.h" +#include +#include + + +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 diff --git a/win-linux/extras/online-installer/src/uiclasses/layout.cpp b/win-linux/extras/online-installer/src/uiclasses/layout.cpp new file mode 100644 index 000000000..c427e35ab --- /dev/null +++ b/win-linux/extras/online-installer/src/uiclasses/layout.cpp @@ -0,0 +1,12 @@ +#include "layout.h" + + +Layout::Layout(Object *parent) +{ + +} + +Layout::~Layout() +{ + +} diff --git a/win-linux/extras/online-installer/src/uiclasses/layout.h b/win-linux/extras/online-installer/src/uiclasses/layout.h new file mode 100644 index 000000000..bc62360b4 --- /dev/null +++ b/win-linux/extras/online-installer/src/uiclasses/layout.h @@ -0,0 +1,27 @@ +#ifndef LAYOUT_H +#define LAYOUT_H + +#include "object.h" +#include "layoutitem.h" +#include "common.h" +// #include + + + +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 diff --git a/win-linux/extras/online-installer/src/uiclasses/layoutitem.cpp b/win-linux/extras/online-installer/src/uiclasses/layoutitem.cpp new file mode 100644 index 000000000..eaa60ee2e --- /dev/null +++ b/win-linux/extras/online-installer/src/uiclasses/layoutitem.cpp @@ -0,0 +1,22 @@ +#include "layoutitem.h" + + +LayoutItem::LayoutItem() +{ + +} + +LayoutItem::~LayoutItem() +{ + +} + +Widget *LayoutItem::widget() +{ + return nullptr; +} + +Layout *LayoutItem::layout() +{ + return nullptr; +} diff --git a/win-linux/extras/online-installer/src/uiclasses/layoutitem.h b/win-linux/extras/online-installer/src/uiclasses/layoutitem.h new file mode 100644 index 000000000..10ef87afc --- /dev/null +++ b/win-linux/extras/online-installer/src/uiclasses/layoutitem.h @@ -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 diff --git a/win-linux/extras/online-installer/src/uiclasses/metrics.cpp b/win-linux/extras/online-installer/src/uiclasses/metrics.cpp new file mode 100644 index 000000000..e6ecc36b4 --- /dev/null +++ b/win-linux/extras/online-installer/src/uiclasses/metrics.cpp @@ -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; +} diff --git a/win-linux/extras/online-installer/src/uiclasses/metrics.h b/win-linux/extras/online-installer/src/uiclasses/metrics.h new file mode 100644 index 000000000..09f6dc7de --- /dev/null +++ b/win-linux/extras/online-installer/src/uiclasses/metrics.h @@ -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 diff --git a/win-linux/extras/online-installer/src/uiclasses/object.cpp b/win-linux/extras/online-installer/src/uiclasses/object.cpp new file mode 100644 index 000000000..0fb88274c --- /dev/null +++ b/win-linux/extras/online-installer/src/uiclasses/object.cpp @@ -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) +{ + +} diff --git a/win-linux/extras/online-installer/src/uiclasses/object.h b/win-linux/extras/online-installer/src/uiclasses/object.h new file mode 100644 index 000000000..02b50fe6a --- /dev/null +++ b/win-linux/extras/online-installer/src/uiclasses/object.h @@ -0,0 +1,35 @@ +#ifndef OBJECT_H +#define OBJECT_H + +#include + + +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 diff --git a/win-linux/extras/online-installer/src/uiclasses/palette.cpp b/win-linux/extras/online-installer/src/uiclasses/palette.cpp new file mode 100644 index 000000000..bfc68c003 --- /dev/null +++ b/win-linux/extras/online-installer/src/uiclasses/palette.cpp @@ -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; +} diff --git a/win-linux/extras/online-installer/src/uiclasses/palette.h b/win-linux/extras/online-installer/src/uiclasses/palette.h new file mode 100644 index 000000000..710e53142 --- /dev/null +++ b/win-linux/extras/online-installer/src/uiclasses/palette.h @@ -0,0 +1,41 @@ +#ifndef PALETTE_H +#define PALETTE_H + +#include + + +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 diff --git a/win-linux/extras/online-installer/src/uiclasses/progressbar.cpp b/win-linux/extras/online-installer/src/uiclasses/progressbar.cpp new file mode 100644 index 000000000..ae144e9a5 --- /dev/null +++ b/win-linux/extras/online-installer/src/uiclasses/progressbar.cpp @@ -0,0 +1,109 @@ +#include "progressbar.h" +#include "drawningengine.h" + +#define DEFAULT_PULSE_STEP 2 + + +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; + if (IsWindowVisible(m_hWnd)) + update(); +} + +void ProgressBar::pulse(bool enable) +{ + m_pulse_pos = enable ? 0 : -1; + m_pulse_direction = 1; + if (enable) + SetTimer(m_hWnd, PROGRESS_PULSE_TIMER_ID, 50, NULL); + else + KillTimer(m_hWnd, PROGRESS_PULSE_TIMER_ID); +} + +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; + } + if (IsWindowVisible(m_hWnd)) + update(); + } + break; + } + + default: + break; + } + return Widget::event(msg, wParam, lParam, result); +} diff --git a/win-linux/extras/online-installer/src/uiclasses/progressbar.h b/win-linux/extras/online-installer/src/uiclasses/progressbar.h new file mode 100644 index 000000000..31ca56e47 --- /dev/null +++ b/win-linux/extras/online-installer/src/uiclasses/progressbar.h @@ -0,0 +1,30 @@ +#ifndef PROGRESSBAR_H +#define PROGRESSBAR_H + +#include "widget.h" +//#include + + +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 diff --git a/win-linux/extras/online-installer/src/uiclasses/radiobutton.cpp b/win-linux/extras/online-installer/src/uiclasses/radiobutton.cpp new file mode 100644 index 000000000..16ef81402 --- /dev/null +++ b/win-linux/extras/online-installer/src/uiclasses/radiobutton.cpp @@ -0,0 +1,60 @@ +#include "radiobutton.h" +#include "drawningengine.h" +#include "metrics.h" +#include + + +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; + if (IsWindowVisible(m_hWnd)) + 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(); +} diff --git a/win-linux/extras/online-installer/src/uiclasses/radiobutton.h b/win-linux/extras/online-installer/src/uiclasses/radiobutton.h new file mode 100644 index 000000000..ad76d07b6 --- /dev/null +++ b/win-linux/extras/online-installer/src/uiclasses/radiobutton.h @@ -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 diff --git a/win-linux/extras/online-installer/src/uiclasses/widget.cpp b/win-linux/extras/online-installer/src/uiclasses/widget.cpp new file mode 100644 index 000000000..2300bd24d --- /dev/null +++ b/win-linux/extras/online-installer/src/uiclasses/widget.cpp @@ -0,0 +1,413 @@ +#include "widget.h" +#include "application.h" +#include "metrics.h" +#include "palette.h" +#include "drawningengine.h" +#include + + +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); + if (IsWindowVisible(m_hWnd)) + 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(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() +{ + RedrawWindow(m_hWnd, NULL, NULL, RDW_INVALIDATE | RDW_NOERASE | RDW_INTERNALPAINT | RDW_UPDATENOW); +} + +void Widget::update() +{ + 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; +} diff --git a/win-linux/extras/online-installer/src/uiclasses/widget.h b/win-linux/extras/online-installer/src/uiclasses/widget.h new file mode 100644 index 000000000..f8664459c --- /dev/null +++ b/win-linux/extras/online-installer/src/uiclasses/widget.h @@ -0,0 +1,89 @@ +#ifndef WIDGET_H +#define WIDGET_H + +#include "object.h" +#include "drawingsurface.h" +#include "layout.h" +#include "commondefines.h" +#include +#include + + +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 m_resize_callbacks, + m_move_callbacks; + std::unordered_map m_create_callbacks, + m_destroy_callbacks; + std::unordered_map m_close_callbacks; + + bool m_is_created, + m_is_destroyed, + m_is_class_destroyed, + m_mouse_entered; +}; + +#endif // WIDGET_H diff --git a/win-linux/extras/online-installer/src/uiclasses/window.cpp b/win-linux/extras/online-installer/src/uiclasses/window.cpp new file mode 100644 index 000000000..4e9e8c8a3 --- /dev/null +++ b/win-linux/extras/online-installer/src/uiclasses/window.cpp @@ -0,0 +1,544 @@ +#include "window.h" +#include "baseutils.h" +#include "palette.h" +#include "metrics.h" +#include "drawningengine.h" +#include + +#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); +} diff --git a/win-linux/extras/online-installer/src/uiclasses/window.h b/win-linux/extras/online-installer/src/uiclasses/window.h new file mode 100644 index 000000000..13d6ae10d --- /dev/null +++ b/win-linux/extras/online-installer/src/uiclasses/window.h @@ -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 m_state_callbacks; +}; + +#endif // WINDOW_H diff --git a/win-linux/extras/online-installer/src/utils.cpp b/win-linux/extras/online-installer/src/utils.cpp index 262fda9d9..98e9e7426 100644 --- a/win-linux/extras/online-installer/src/utils.cpp +++ b/win-linux/extras/online-installer/src/utils.cpp @@ -31,34 +31,57 @@ */ #include "utils.h" +#include "baseutils.h" #include "resource.h" #include "translator.h" -#include +#include #include -#include +#include #include #include -#include +#include +#include +// #include +#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, LPCWSTR value, wstring &result) +{ + HKEY hKey; + if (RegOpenKeyEx(rootKey, subkey, 0, KEY_READ, &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,11 +108,98 @@ namespace NS_Utils } return false; } + + bool IsWin64() + { +#ifdef _WIN64 + return true; +#else + SYSTEM_INFO info; + GetSystemInfo(&info); + return (info.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64); +#endif + } + + bool IsAppInstalled(wstring &path, wstring *arch) + { + std::vector subkeys{L"Software"}; + if (NS_Utils::IsWin64()) + subkeys.push_back(L"Software\\WOW6432Node"); + for (auto &subkey : subkeys) { + subkey += _T(APP_REG_PATH); + RegQueryStringValue(HKEY_LOCAL_MACHINE, subkey.c_str(), L"AppPath", path); + if (!path.empty() /*&& NS_File::fileExists(path + _T(APP_LAUNCH_NAME))*/) { + if (arch) + *arch = (!NS_Utils::IsWin64() || subkey.find(L"WOW6432Node") != std::wstring::npos) ? L"x86" : L"x64"; + return true; + } + } + return false; + } + + void InstalledVerInfo(LPCWSTR value, wstring &name, wstring &arch) + { + if (!name.empty()) + name.clear(); + std::vector subkeys{L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\"}; + if (NS_Utils::IsWin64()) + subkeys.push_back(L"SOFTWARE\\WOW6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\"); + for (auto &subkey : subkeys) { + subkey += _T(WINDOW_NAME); + for (int i = 0; i < 2; i++) { + RegQueryStringValue(HKEY_LOCAL_MACHINE, subkey.c_str(), value, name); + if (!name.empty()) { + if (arch.empty()) + arch = (!NS_Utils::IsWin64() || subkey.find(L"WOW6432Node") != std::wstring::npos) ? L"x86" : L"x64"; + 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); @@ -102,7 +212,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 +255,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 +292,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 +306,56 @@ namespace NS_File return (res != 0) ? fromNativeSeparators(parentPath(buff)) : _T(""); } - WinVer 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); - 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 generateTmpFileName(const wstring &ext) + { + 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; - -// 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; -// } + 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 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 diff --git a/win-linux/extras/online-installer/src/utils.h b/win-linux/extras/online-installer/src/utils.h index 78d7b9dc1..8ab459510 100644 --- a/win-linux/extras/online-installer/src/utils.h +++ b/win-linux/extras/online-installer/src/utils.h @@ -33,14 +33,12 @@ #ifndef UTILS_H #define UTILS_H +#include #include -#include -#include 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