libkysdk-applications/0000775000175000017500000000000015155674255014017 5ustar fengfenglibkysdk-applications/kysdk-qtwidgets/0000775000175000017500000000000015147772510017147 5ustar fengfenglibkysdk-applications/kysdk-qtwidgets/translations/0000775000175000017500000000000015104543305021657 5ustar fengfenglibkysdk-applications/kysdk-qtwidgets/translations/gui_ug.ts0000664000175000017500000002674315104543305023522 0ustar fengfeng CloseButton Close Tab بەتكۈچ ياپ KCustomTabBar Scroll Left سولغا سىيرىل Scroll Right ئوڭغا سىيرىلىش kdk::KAboutDialog Your system does not have any email application installed or the default mail application is not set up Unable to open mail application ئېلخەت خېرىدارلار تېرمىنالىنى ئاچقىلى بولمىدى Service & Support: 服务与支持团队: مۇلازىمەت ۋە قوللاش ئەترىتى Privacy statement مەخپىيەتلىكنى ساقلاش باياناتى kdk::KAboutDialogPrivate version : نۇسخا Version number not found ماس كېلىدىغان نۇسخا نومۇرىنى تاپالمىدى kdk::KAddFileButtonPrivate Please select file ھۆججەتنى تاللاڭ kdk::KDragWidget Select or drag and drop the folder identification path ھۆججەت قىسقۇچنىڭ كۆرسەتمە يولىنى تاللاڭ ياكى سۆرەپ ئەكىلىڭ kdk::KDragWidgetPrivate Please select file ھۆججەتنى تاللاڭ kdk::KInputDialog Enter a value: سانلىق قىممەتنى كىرگۈزۈڭ kdk::KInputDialogPrivate ok جەزملەشتۈرۈش cancel ئەمەلدىن قالدۇرۇش kdk::KMenuButton Options كۆپنى تاللاش Setting 设置 بەلگىلەش Theme سىرتقى كۆرۈنۈشى Help ياردەم About ئالاقىدارلار Feedback ئىنكاس قايتۇرۇش Quit چېكىنىش Auto سىستېمىغا ئەگىشىش Light سۇس رەڭ Dark قېنىق رەڭ kdk::KProgressDialog cancel ئەمەلدىن قالدۇرۇش kdk::KSearchLineEditPrivate Search ئىزدەش kdk::KSecurityLevelBar Low تۆۋەن Medium ئوتتۇرا High يۇقىرى kdk::KSecurityLevelBarPrivate Low تۆۋەن kdk::KSecurityQuestionDialog Security question%1 Answer Required زۆرۈر kdk::KSecurityQuestionDialogPrivate Security Question Setting security questions to reset password when forget it, please remember answer. Cancel ئەمەلدىن قالدۇرۇش Save ساقلاش kdk::KUninstallDialog uninstall 立即卸载 دەرھال يۇيۇۋېتىش deb name: نامى: deb version: نۇسخىسى: kdk::KUninstallDialogPrivate deb name: نامى: deb version: نۇسخىسى: kdk::KWindowButtonBar Maximize ئەڭ چوڭ ھالەت Restore ئەسلىگە قايتۇرۇش kdk::KWindowButtonBarPrivate Minimize ئەڭ كىچىك ھالەتكە ئەكىلىش Close ئېتىش Maximize ئەڭ چوڭ ھالەتكە ئەكىلىش Restore ئەسلىگە قايتۇرۇش libkysdk-applications/kysdk-qtwidgets/translations/gui_ky.ts0000664000175000017500000002661615104543305023531 0ustar fengfeng CloseButton Close Tab بەتكۈچ ياپ KCustomTabBar Scroll Left سولعو سىيرىل Scroll Right وڭ جاقا تايعىلۇۇ kdk::KAboutDialog Your system does not have any email application installed or the default mail application is not set up Unable to open mail application پوچتو جولدونموسۇ تەرمىنالدى اچقالى بولبودۇ Service & Support: 服务与支持团队: تەيلۅۅ جانا قولدوش ، دەم بەرىش : Privacy statement سىرىن ساقتوو باياناتى kdk::KAboutDialogPrivate version : نۇسقا Version number not found شاي گەلەتۇرعان نۇسقا نومۇرۇن تابالبادى kdk::KAddFileButtonPrivate Please select file ۅجۅتۉن تانداڭ kdk::KDragWidget Select or drag and drop the folder identification path ۅجۅت قىسقىچتىن جولجورۇق جولۇن تانداڭ كۅرۉنۉشتۅرۉ سۉيرۅپ كېلىڭ kdk::KDragWidgetPrivate Please select file ۅجۅتۉن تانداڭ kdk::KInputDialog Enter a value: بىر نارقتۇۇنۇ كىرگىزىڭ: kdk::KInputDialogPrivate ok بەكىتۉۉ cancel بەكەر جاسوو ،اتقارۇۇ kdk::KMenuButton Options تاندالما Setting 设置 تەڭشەك Theme ۇسلۇپ Help جەرلىك About جۅنۉندۅ Feedback ىنكاس كەتىرىش Quit جانىش ، قايتىش Auto اپتوماتىك Light كۉڭۉرت تۉس Dark قانىق تۉس kdk::KProgressDialog cancel بەكەر جاسوو ،اتقارۇۇ kdk::KSearchLineEditPrivate Search ىزدۅۅ kdk::KSecurityLevelBar Low تۅمۅن Medium ورتوسۇ High جوعورۇ kdk::KSecurityLevelBarPrivate Low تۅمۅن kdk::KSecurityQuestionDialog Security question%1 Answer Required زارىل kdk::KSecurityQuestionDialogPrivate Security Question Setting security questions to reset password when forget it, please remember answer. Cancel ارعادان قالتىرىش Save ساقتوو kdk::KUninstallDialog uninstall 立即卸载 داروو جۇۇپ جىبەر deb name: تاڭىق ناامى : deb version: باسماسى : kdk::KUninstallDialogPrivate deb name: تاڭىق ناامى : deb version: باسماسى : kdk::KWindowButtonBar Maximize چوڭويتۇش Restore العاچىنا كەلتىرۉۉ kdk::KWindowButtonBarPrivate Minimize ەڭ كىچىك ابالى Close بەكىتىش Maximize چوڭويتۇش Restore العاچىنا كەلتىرۉۉ libkysdk-applications/kysdk-qtwidgets/translations/gui_es.ts0000664000175000017500000002574215104543305023514 0ustar fengfeng CloseButton Close Tab Cerrar pestaña KCustomTabBar Scroll Left Scroll Right kdk::KAboutDialog Your system does not have any email application installed or the default mail application is not set up No tiene ninguna aplicación de correo electrónico instalada en el sistema o no tiene una aplicación de correo predeterminada configurada Unable to open mail application No se puede abrir la aplicación de correo Service & Support: 服务与支持团队: Servicio y soporte: Privacy statement Declaración de privacidad kdk::KAboutDialogPrivate version : Versión: Version number not found No se encontró el número de versión kdk::KAddFileButtonPrivate Please select file Por favor, seleccione un archivo kdk::KDragWidget Select or drag and drop the folder identification path Seleccione o arrastre y suelte la ruta de identificación de la carpeta kdk::KDragWidgetPrivate Please select file Por favor, seleccione un archivo kdk::KInputDialog Enter a value: Introduzca un valor: kdk::KInputDialogPrivate ok De acuerdo cancel Cancelar kdk::KMenuButton Options Opciones Setting 设置 Ajuste Theme Tema Help Ayuda About Acerca de Feedback Retroalimentación Quit Renunciar Auto Automático Light Luz Dark Oscuro kdk::KProgressDialog cancel Cancelar kdk::KSearchLineEditPrivate Search Buscar kdk::KSecurityLevelBar Low Bajo Medium Medio High Alto kdk::KSecurityLevelBarPrivate Low Bajo kdk::KSecurityQuestionDialog Security question%1 Answer Required Obligatorio kdk::KSecurityQuestionDialogPrivate Security Question Setting security questions to reset password when forget it, please remember answer. Cancel Cancel Save Salvar kdk::KUninstallDialog uninstall 立即卸载 desinstalar deb name: Nombre deb: deb version: Versión deb: kdk::KUninstallDialogPrivate deb name: Nombre deb: deb version: Versión deb: kdk::KWindowButtonBar Maximize Maximizar Restore Restaurar kdk::KWindowButtonBarPrivate Minimize Minimizar Close Cerrar Maximize Maximizar Restore Restaurar libkysdk-applications/kysdk-qtwidgets/translations/gui_fr.ts0000664000175000017500000002604515104543305023511 0ustar fengfeng CloseButton Close Tab Fermer l'onglet KCustomTabBar Scroll Left Scroll Right kdk::KAboutDialog Your system does not have any email application installed or the default mail application is not set up Aucune application de messagerie n’est installée sur votre système ou vous n’avez pas d’application de messagerie par défaut Unable to open mail application Impossible d’ouvrir l’application de messagerie Service & Support: 服务与支持团队: Service après-vente et assistance : Privacy statement Déclaration de confidentialité kdk::KAboutDialogPrivate version : Version: Version number not found Numéro de version introuvable kdk::KAddFileButtonPrivate Please select file S’il vous plaît sélectionner un fichier kdk::KDragWidget Select or drag and drop the folder identification path Sélectionnez ou glissez-déposez le chemin d’identification du dossier kdk::KDragWidgetPrivate Please select file S’il vous plaît sélectionner un fichier kdk::KInputDialog Enter a value: Entrez une valeur : kdk::KInputDialogPrivate ok D’accord cancel Annuler kdk::KMenuButton Options Options Setting 设置 Réglage Theme Thème Help Aide About Environ Feedback Rétroaction Quit Démissionner Auto Auto Light Lumière Dark Sombre kdk::KProgressDialog cancel Annuler kdk::KSearchLineEditPrivate Search Rechercher kdk::KSecurityLevelBar Low Bas Medium Douleur moyenne High Haut kdk::KSecurityLevelBarPrivate Low Bas kdk::KSecurityQuestionDialog Security question%1 Answer Required Obligatoire kdk::KSecurityQuestionDialogPrivate Security Question Setting security questions to reset password when forget it, please remember answer. Cancel Annuler Save Sauvegarder kdk::KUninstallDialog uninstall 立即卸载 Désinstaller deb name: Nom de Deb : deb version: Version de Deb : kdk::KUninstallDialogPrivate deb name: Nom de Deb : deb version: Version de Deb : kdk::KWindowButtonBar Maximize Maximiser Restore Restaurer kdk::KWindowButtonBarPrivate Minimize Minimiser Close Fermer Maximize Maximiser Restore Restaurer libkysdk-applications/kysdk-qtwidgets/translations/gui_ug.qm0000664000175000017500000000761415104543305023505 0ustar fengfeng ) [ kf 4X4d@i ܕR Close Tab CloseButtonT]nR Scroll Left KCustomTabBarTSnR Scroll Right KCustomTabBar 0 yrf0 Privacy statementkdk::KAboutDialogg Rقe/cW Service & Support: kdk::KAboutDialogq!lbSNu(b6zUnable to open mail applicationkdk::KAboutDialog2`v|}qg*[NOU[PNau(bg*-n-Nau(gYour system does not have any email application installed or the default mail application is not set upkdk::KAboutDialogg*b~R0\ arHg,_Version number not foundkdk::KAboutDialogPrivaterHg, version :kdk::KAboutDialogPrivate ːxdjhHPlease select filekdk::KAddFileButtonPrivatexdbbe>eY>XR%_6Select or drag and drop the folder identification pathkdk::KDragWidget ːxdjhHPlease select filekdk::KDragWidgetPrivate ˏ8QeexP<Enter a value:kdk::KInputDialogSmcancelkdk::KInputDialogPrivatexokkdk::KInputDialogPrivateeAboutkdk::KMenuButtonߖ|}qAutokdk::KMenuButtonmrDarkkdk::KMenuButtonSS͙KFeedbackkdk::KMenuButton^kRHelpkdk::KMenuButtonmrLightkdk::KMenuButtonxOptionskdk::KMenuButtonQQuitkdk::KMenuButton-nSettingkdk::KMenuButtonYThemekdk::KMenuButtonSmcancelkdk::KProgressDialogd}"Searchkdk::KSearchLineEditPrivateHighkdk::KSecurityLevelBarONLowkdk::KSecurityLevelBarN-Mediumkdk::KSecurityLevelBarONLowkdk::KSecurityLevelBarPrivate{ThHAnswerkdk::KSecurityQuestionDialoglBRequiredkdk::KSecurityQuestionDialog [QhUOL%1Security question%1kdk::KSecurityQuestionDialogSmCancel#kdk::KSecurityQuestionDialogPrivateO[XSave#kdk::KSecurityQuestionDialogPrivate[QhUOLSecurity Question#kdk::KSecurityQuestionDialogPrivate@-n[QhUOLSN^kRO`Q_؊[xfBn[x xON[OO{ThH0TSetting security questions to reset password when forget it, please remember answer.#kdk::KSecurityQuestionDialogPrivateST  deb name:kdk::KUninstallDialogrHg, deb version:kdk::KUninstallDialogzSsSx  uninstallkdk::KUninstallDialogST  deb name:kdk::KUninstallDialogPrivaterHg, deb version:kdk::KUninstallDialogPrivategY'SMaximizekdk::KWindowButtonBarSRestorekdk::KWindowButtonBarܕClosekdk::KWindowButtonBarPrivategY'SMaximizekdk::KWindowButtonBarPrivateg\SMinimizekdk::KWindowButtonBarPrivateSRestorekdk::KWindowButtonBarPrivatelibkysdk-applications/kysdk-qtwidgets/translations/gui_zh_CN.qm0000664000175000017500000000706715104543305024075 0ustar fengfeng + [ kh 4X4d@i  Qs ySa Close Tab CloseButtonT]nR Scroll Left KCustomTabBarTSnR Scroll Right KCustomTabBar 0 yXf0 Privacy statementkdk::KAboutDialogg RNe/cVService & Support: kdk::KAboutDialogelbS_N[b7zUnable to open mail applicationkdk::KAboutDialog2`v|~g*[NOUu5[PN^u(bg*n؋N^u(gYour system does not have any email application installed or the default mail application is not set upkdk::KAboutDialogg*b~R0[^rHg,SVersion number not foundkdk::KAboutDialogPrivaterHg, version :kdk::KAboutDialogPrivate beNPlease select filekdk::KAddFileButtonPrivate bbbe>eNY9hƍ_6Select or drag and drop the folder identification pathkdk::KDragWidget beNPlease select filekdk::KDragWidgetPrivate QeepP<Enter a value:kdk::KInputDialogSmcancelkdk::KInputDialogPrivatexnokkdk::KInputDialogPrivateQsNAboutkdk::KMenuButtonߖ|~Autokdk::KMenuButtonmrDarkkdk::KMenuButtonaS͙Feedbackkdk::KMenuButton^.RHelpkdk::KMenuButtonmErLightkdk::KMenuButton yOptionskdk::KMenuButtonQQuitkdk::KMenuButtonnSettingkdk::KMenuButtonYThemekdk::KMenuButtonSmcancelkdk::KProgressDialogd}"Searchkdk::KSearchLineEditPrivateHighkdk::KSecurityLevelBarONLowkdk::KSecurityLevelBarN-Mediumkdk::KSecurityLevelBarONLowkdk::KSecurityLevelBarPrivate{ThHAnswerkdk::KSecurityQuestionDialog_XkRequiredkdk::KSecurityQuestionDialog [Qh%1Security question%1kdk::KSecurityQuestionDialogSmCancel#kdk::KSecurityQuestionDialogPrivateO[XSave#kdk::KSecurityQuestionDialogPrivate[QhSecurity Question#kdk::KSecurityQuestionDialogPrivate@n[QhSN^.RO`W(_؋[xen[x xnON[OO{ThH0TSetting security questions to reset password when forget it, please remember answer.#kdk::KSecurityQuestionDialogPrivateST  deb name:kdk::KUninstallDialogrHg, deb version:kdk::KUninstallDialogzSsSx} uninstallkdk::KUninstallDialogST  deb name:kdk::KUninstallDialogPrivaterHg, deb version:kdk::KUninstallDialogPrivategY'SMaximizekdk::KWindowButtonBarSRestorekdk::KWindowButtonBarQsClosekdk::KWindowButtonBarPrivategY'SMaximizekdk::KWindowButtonBarPrivateg\SMinimizekdk::KWindowButtonBarPrivateSRestorekdk::KWindowButtonBarPrivatelibkysdk-applications/kysdk-qtwidgets/translations/gui_bo_CN.qm0000664000175000017500000001107115104543305024042 0ustar fengfeng CloseButton Close Tab 關閉分頁 KCustomTabBar Scroll Left 向左滾動 Scroll Right 向右滾動 kdk::KAboutDialog Your system does not have any email application installed or the default mail application is not set up 您的系統未安裝任何電子郵件應用或未設置預設郵件應用 Unable to open mail application 無法打開郵件用戶端 Service & Support: 服务与支持团队: 服務與支持團隊: Privacy statement 《隱私聲明》 kdk::KAboutDialogPrivate version : 版本: Version number not found 未找到對應版本號 kdk::KAddFileButtonPrivate Please select file 請選擇檔案 kdk::KDragWidget Select or drag and drop the folder identification path 選擇或拖放資料夾識別路徑 kdk::KDragWidgetPrivate Please select file 請選擇檔案 kdk::KInputDialog Enter a value: 請輸入數值: kdk::KInputDialogPrivate ok 確認 cancel 取消 kdk::KMenuButton Options 選項 Setting 设置 設置 Theme 外觀 Help 幫助 About 關於 Feedback 去反饋 Quit 退出 Auto 跟隨系統 Light 淺色 Dark 深色 kdk::KProgressDialog cancel 取消 kdk::KSearchLineEditPrivate Search 搜索 kdk::KSecurityLevelBar Low Medium High kdk::KSecurityLevelBarPrivate Low kdk::KSecurityQuestionDialog Security question%1 安全問題%1 Answer 答案 Required 要求 kdk::KSecurityQuestionDialogPrivate Security Question 安全問題 Setting security questions to reset password when forget it, please remember answer. 設置安全問題可以幫助你再忘記密碼時重置密碼,請確保一定記住答案。 Cancel 取消 Save 保存 kdk::KUninstallDialog uninstall 立即卸载 立即卸載 deb name: 包名: deb version: 版本: kdk::KUninstallDialogPrivate deb name: 包名: deb version: 版本: kdk::KWindowButtonBar Maximize 最大化 Restore 還原 kdk::KWindowButtonBarPrivate Minimize 最小化 Close 關閉 Maximize 最大化 Restore 還原 libkysdk-applications/kysdk-qtwidgets/translations/gui_es.qm0000664000175000017500000001002215104543305023464 0ustar fengfeng CloseButton Close Tab 关闭选项卡 KCustomTabBar Scroll Left 向左滚动 Scroll Right 向右滚动 kdk::KAboutDialog Your system does not have any email application installed or the default mail application is not set up 您的系统未安装任何电子邮件应用或未设置默认邮件应用 Unable to open mail application 无法打开邮件客户端 Service & Support: 服务与支持团队: 服务与支持团队: Privacy statement 《隐私声明》 kdk::KAboutDialogPrivate version : 版本: Version number not found 未找到对应版本号 kdk::KAddFileButtonPrivate Please select file 请选择文件 kdk::KDragWidget Select or drag and drop the folder identification path 选择或拖放文件夹标识路径 kdk::KDragWidgetPrivate Please select file 请选择文件 kdk::KInputDialog Enter a value: 请输入数值: kdk::KInputDialogPrivate ok 确认 cancel 取消 kdk::KMenuButton Options 选项 Setting 设置 设置 Theme 外观 Help 帮助 About 关于 Feedback 意见反馈 Quit 退出 Auto 跟随系统 Light 浅色 Dark 深色 kdk::KProgressDialog cancel 取消 kdk::KSearchLineEditPrivate Search 搜索 kdk::KSecurityLevelBar Low Medium High kdk::KSecurityLevelBarPrivate Low kdk::KSecurityQuestionDialog Security question%1 安全问题%1 Answer 答案 Required 必填 kdk::KSecurityQuestionDialogPrivate Security Question 安全问题 Setting security questions to reset password when forget it, please remember answer. 设置安全问题可以帮助你在忘记密码时重置密码,请确保一定记住答案。 Cancel 取消 Save 保存 kdk::KUninstallDialog uninstall 立即卸载 立即卸载 deb name: 包名: deb version: 版本: kdk::KUninstallDialogPrivate deb name: 包名: deb version: 版本: kdk::KWindowButtonBar Maximize 最大化 Restore 还原 kdk::KWindowButtonBarPrivate Minimize 最小化 Close 关闭 Maximize 最大化 Restore 还原 libkysdk-applications/kysdk-qtwidgets/translations/gui_fr.qm0000664000175000017500000001014215104543305023467 0ustar fengfeng CloseButton Close Tab Đóng tab KCustomTabBar Scroll Left Cuộn sang trái Scroll Right Cuộn sang phải kdk::KAboutDialog Your system does not have any email application installed or the default mail application is not set up 您的系统没有安装任何电子邮件应用程序,或者没有设置默认的邮件应用程序 Unable to open mail application Không thể mở ứng dụng thư Service & Support: 服务与支持团队: Đội vũ phục vụ và hỗ trợ: Privacy statement Tuyên bố về quyền riêng tư kdk::KAboutDialogPrivate version : Phiên bản: Version number not found Không tìm thấy số phiên bản kdk::KAddFileButtonPrivate Please select file Vui lòng chọn tệp kdk::KDragWidget Select or drag and drop the folder identification path Chọn hoặc kéo và thả đường dẫn nhận dạng thư mục kdk::KDragWidgetPrivate Please select file Vui lòng chọn tệp kdk::KInputDialog Enter a value: Giá trị nhập vào: kdk::KInputDialogPrivate ok Ok cancel hủy kdk::KMenuButton Options Tùy chọn Setting 设置 Khung cảnh Theme Chủ đề Help Trợ giúp About Về Feedback Phản hồi Quit Bỏ Auto Theo hệ thống Light Sáng Dark Tối kdk::KProgressDialog cancel hủy kdk::KSearchLineEditPrivate Search Tìm kiếm ứng dụng kdk::KSecurityLevelBar Low Thấp Medium Đau vừa High Tốc độ cao kdk::KSecurityLevelBarPrivate Low Thấp kdk::KSecurityQuestionDialog Security question%1 Câu hỏi bảo mật%1 Answer Câu trả lời Required Bắt buộc điền kdk::KSecurityQuestionDialogPrivate Security Question Vấn đề an toàn Setting security questions to reset password when forget it, please remember answer. Đặt câu hỏi bảo mật để đặt lại mật khẩu khi quên, hãy nhớ câu trả lời. Cancel Hủy Save Cứu kdk::KUninstallDialog uninstall 立即卸载 Gỡ ngay deb name: Tên deb: deb version: Phiên bản deb: kdk::KUninstallDialogPrivate deb name: Tên gói: deb version: Phiên bản deb: kdk::KWindowButtonBar Maximize Phóng lớn Restore Khôi phục kdk::KWindowButtonBarPrivate Minimize Giảm thiểu Close Đóng Maximize Phóng lớn Restore Mở libkysdk-applications/kysdk-qtwidgets/translations/gui_mn.ts0000664000175000017500000003074315104543305023514 0ustar fengfeng CloseButton Close Tab ᠱᠤᠰᠢᠭ᠎ᠠ ᠵᠢᠨ ᠨᠢᠭᠤᠷ ᠢ᠋ ᠬᠠᠭᠠᠬᠤ KCustomTabBar Scroll Left ᠵᠡᠭᠦᠨᠰᠢ ᠦᠩᠬᠦᠷᠢᠬᠦ Scroll Right ᠪᠠᠷᠠᠭᠤᠨᠰᠢ ᠦᠩᠬᠦᠷᠢᠬᠦ kdk::KAboutDialog Your system does not have any email application installed or the default mail application is not set up ᠲᠠᠨ ᠤ ᠰᠢᠰᠲ᠋ᠧᠮ ᠳᠦ ᠶᠠᠮᠠᠷ ᠴᠤ ᠡᠯᠧᠺᠲ᠋ᠷᠣᠨ ᠰᠢᠤᠳᠠᠨ ᠤ ᠵᠦᠢᠯ ᠢ ᠬᠡᠷᠡᠭᠯᠡᠬᠦ ᠪᠤᠶᠤ ᠳᠤᠪ ᠳᠤᠭᠤᠢ ᠲᠠᠨᠢᠬᠤ ᠰᠢᠤᠳᠠᠨ ᠤ ᠵᠦᠢᠯ ᠦᠨ ᠬᠡᠷᠡᠭᠯᠡᠯᠲᠡ ᠬᠢᠭᠰᠡᠨ ᠦᠭᠡᠢ ᠃ Unable to open mail application ᠰᠢᠤᠳᠠᠨ ᠤ ᠵᠦᠢᠯ ᠦᠨ ᠵᠣᠴᠢᠨ ᠡᠷᠦᠬᠡ ᠶᠢ ᠨᠡᠭᠡᠭᠡᠵᠦ ᠳᠡᠶᠢᠯᠬᠦ ᠦᠭᠡᠢ ᠃ Service & Support: ᠦᠢᠯᠡᠴᠢᠯᠡᠬᠦ ᠪᠠ ᠳᠡᠮᠵᠢᠬᠦ ᠪᠦᠯᠬᠦᠮ: Privacy statement 《ᠨᠢᠭᠤᠴᠠ ᠶᠢᠨ ᠢᠯᠡᠷᠬᠡᠶᠢᠯᠡᠯᠲᠡ》 kdk::KAboutDialogPrivate version : ᠬᠡᠪᠯᠡᠯ Version number not found ᠵᠣᠬᠢᠴᠠᠩᠭᠤᠢ ᠬᠡᠪᠯᠡᠯ ᠦᠨ ᠨᠣᠮᠧᠷ ᠢ ᠡᠷᠢᠵᠦ ᠣᠯᠣᠭᠰᠠᠨ ᠦᠭᠡᠢ ᠃ kdk::KAddFileButtonPrivate Please select file ᠪᠢᠴᠢᠭ᠌ ᠮᠠᠲ᠋ᠧᠷᠢᠶᠠᠯ ᠢ ᠰᠣᠩᠭᠣᠭᠠᠷᠠᠢ ᠃ kdk::KDragWidget Select or drag and drop the folder identification path ᠪᠢᠴᠢᠭ ᠮᠠᠲ᠋ᠧᠷᠢᠶᠠᠯ ᠤᠨ ᠬᠠᠪᠤᠳᠠᠷ ᠢ ᠰᠣᠩᠭᠣᠬᠤ ᠪᠤᠶᠤ ᠲᠠᠯᠪᠢᠬᠤ ᠬᠡᠷᠡᠭᠲᠡᠶ᠃ kdk::KDragWidgetPrivate Please select file ᠪᠢᠴᠢᠭ᠌ ᠮᠠᠲ᠋ᠧᠷᠢᠶᠠᠯ ᠢ ᠰᠣᠩᠭᠣᠭᠠᠷᠠᠢ ᠃ kdk::KInputDialog Enter a value: ᠲᠤᠭ᠎ᠠ ᠬᠡᠮᠵᠢᠭᠳᠡᠯ ᠢ ᠤᠷᠤᠭᠤᠯᠤᠭᠠᠷᠠᠢ: kdk::KInputDialogPrivate ok ᠪᠠᠳᠤᠯᠠᠬᠤ cancel ᠦᠬᠡᠢᠰᠬᠡᠬᠦ kdk::KMenuButton Options ᠰᠣᠩᠭᠣᠯᠲᠠ ᠃ Setting ᠳᠤᠬᠢᠷᠠᠭᠤᠯᠬᠤ Theme ᠭᠤᠤᠯ ᠰᠡᠳᠦᠪ Help ᠬᠠᠪᠰᠤᠷᠬᠤ About ᠲᠤᠬᠠᠢ Feedback ᠬᠠᠷᠢᠭᠤ ᠲᠤᠰᠬᠠᠯ ᠃ Quit ᠪᠤᠴᠠᠵᠤ ᠭᠠᠷᠬᠤ Auto ᠭᠤᠤᠯ ᠰᠡᠳᠦᠪ ᠢ ᠳᠠᠭᠠᠬᠤ Light ᠬᠦᠶᠦᠬᠡᠨ ᠦᠩᠭᠡ ᠲᠠᠢ ᠭᠤᠤᠯ ᠰᠡᠳᠦᠪ Dark ᠬᠦᠨ ᠦᠩᠭᠡ ᠲᠠᠢ ᠭᠤᠤᠯ ᠰᠡᠳᠦᠪ kdk::KProgressDialog cancel ᠦᠬᠡᠢᠰᠬᠡᠬᠦ kdk::KSearchLineEditPrivate Search ᠬᠠᠢᠯᠳᠠ kdk::KSecurityLevelBar Low ᠳᠤᠤᠷ᠎ᠠ Medium ᠳᠤᠮᠳᠠ High ᠦᠨᠳᠦᠷ kdk::KSecurityLevelBarPrivate Low ᠳᠤᠤᠷ᠎ᠠ kdk::KSecurityQuestionDialog Security question%1 Answer Required ᠡᠷᠬᠡᠪᠰᠢ ᠳᠠᠭᠯᠠᠬᠤ kdk::KSecurityQuestionDialogPrivate Security Question Setting security questions to reset password when forget it, please remember answer. Cancel ᠦᠬᠡᠢᠰᠭᠡᠬᠦ᠌ Save ᠬᠠᠳᠠᠭᠠᠯᠠᠬᠤ kdk::KUninstallDialog uninstall ᠲᠡᠷᠡ ᠳᠠᠷᠤᠢ ᠪᠠᠭᠤᠯᠭᠠᠬᠤ deb name: ᠪᠠᠭᠳᠠᠬᠤ ᠨᠡᠷ᠎ᠡ : deb version: ᠬᠡᠪᠯᠡᠯ: kdk::KUninstallDialogPrivate deb name: ᠪᠠᠭᠳᠠᠬᠤ ᠨᠡᠷ᠎ᠡ: deb version: ᠬᠡᠪᠯᠡᠯ: kdk::KWindowButtonBar Maximize ᠬᠠᠮᠤᠭ ᠤᠨ ᠶᠡᠬᠡᠴᠢᠯᠡᠯ Restore ᠤᠭ ᠢᠶᠠᠨ ᠪᠤᠴᠠᠭᠠᠬᠤ kdk::KWindowButtonBarPrivate Minimize ᠬᠠᠮᠤᠭ ᠤᠨ ᠪᠠᠭᠠᠴᠢᠯᠠᠯ Close ᠬᠠᠭᠠᠬᠤ Maximize ᠬᠠᠮᠤᠭ ᠤᠨ ᠶᠡᠬᠡᠴᠢᠯᠡᠯ Restore ᠤᠭ ᠢᠶᠠᠨ ᠪᠤᠴᠠᠭᠠᠬᠤ libkysdk-applications/kysdk-qtwidgets/translations/gui_de.ts0000664000175000017500000002571615104543305023476 0ustar fengfeng CloseButton Close Tab Reiter schließen KCustomTabBar Scroll Left Scroll Right kdk::KAboutDialog Your system does not have any email application installed or the default mail application is not set up Sie haben keine E-Mail-Apps auf Ihrem System installiert oder keine Standard-Mail-App festgelegt Unable to open mail application E-Mail-Anwendung kann nicht geöffnet werden Service & Support: 服务与支持团队: Service & Support: Privacy statement Datenschutzerklärung kdk::KAboutDialogPrivate version : Version: Version number not found Versionsnummer nicht gefunden kdk::KAddFileButtonPrivate Please select file Bitte wählen Sie eine Datei aus kdk::KDragWidget Select or drag and drop the folder identification path Wählen Sie den Ordneridentifikationspfad aus oder ziehen Sie ihn per Drag & Drop kdk::KDragWidgetPrivate Please select file Bitte wählen Sie eine Datei aus kdk::KInputDialog Enter a value: Geben Sie einen Wert ein: kdk::KInputDialogPrivate ok Okay cancel Abbrechen kdk::KMenuButton Options Optionen Setting 设置 Einstellung Theme Thema Help Hilfe About Über Feedback Feedback Quit Verlassen Auto Auto Light Licht Dark Dunkel kdk::KProgressDialog cancel Abbrechen kdk::KSearchLineEditPrivate Search Suchen kdk::KSecurityLevelBar Low Niedrig Medium Mittel High Hoch kdk::KSecurityLevelBarPrivate Low Niedrig kdk::KSecurityQuestionDialog Security question%1 Answer Required Erforderlich kdk::KSecurityQuestionDialogPrivate Security Question Setting security questions to reset password when forget it, please remember answer. Cancel Abbrechen Save Retten kdk::KUninstallDialog uninstall 立即卸载 Deinstallieren deb name: Deb Name: deb version: Deb-Version: kdk::KUninstallDialogPrivate deb name: Deb Name: deb version: Deb-Version: kdk::KWindowButtonBar Maximize Maximieren Restore Wiederherstellen kdk::KWindowButtonBarPrivate Minimize Minimieren Close Schließen Maximize Maximieren Restore Wiederherstellen libkysdk-applications/kysdk-qtwidgets/translations/gui_kk.qm0000664000175000017500000000734415104543305023477 0ustar fengfeng CloseButton Close Tab སྒོ་རྒྱག་པའི་རེའུ་མིག KCustomTabBar Scroll Left གཡོན་ཕྱོགས་སུ་ཤོག་ལྷེ་གཅིག Scroll Right གཡས་ཕྱོགས་སུ་དཀྱ kdk::KAboutDialog Your system does not have any email application installed or the default mail application is not set up ཁྱེད་རང་གི་མ་ལག་ལ་གློག་རྡུལ་སྦྲག་རྫས་གང་རུང་ཞིག་སྒྲིག་སྦྱོར་བྱས་མེད་པའམ་ཡང་ན་སྦྲག་རྫས་བཀོལ་སྤྱོད་བྱས་མེད།། Unable to open mail application སྦྲག་རྫས་ཉེར་སྤྱོད་བྱ་རིམ་ཁ་ཕྱེ་མི་ཐུབ་། Service & Support: ཞབས་ཞུ་དང་རྒྱབ་སྐྱོར་ཚོགས་པ་ Privacy statement 《གསང་བའི་གསལ་བསྒྲགས། 》 kdk::KAboutDialogPrivate version : པར་གཞི། Version number not found པར་གཞིའི་ཨང་གྲངས་རྙེད་མ་བྱུང་། kdk::KAddFileButtonPrivate Please select file ཡིག་ཆ་འདེམས་རོགས་གནང་། kdk::KDragWidget Select or drag and drop the folder identification path ཡིག་ཆའི་རྟགས་མཚན་འགོད་པའི་ཐབས་ལམ་འདེམས་པའམ་ཡང་ན་འདྲུད་གཏོང་བྱས་པ། kdk::KDragWidgetPrivate Please select file ཡིག་ཆ་འདེམས་རོགས་གནང་། kdk::KInputDialog Enter a value: ཁྱོད་ཀྱིས་གྲངས་ཀ་ནང་འཇུག་གནང་རོགས། kdk::KInputDialogPrivate ok དངོས་སུ་ཁས་ལེན་པ། cancel མེད་པར་བཟོ་དགོས། kdk::KMenuButton Options འདེམས་ཚན་ Setting བཀོད་སྒྲིག་བཅས་བྱ་དགོས། Theme ཕྱི་ཚུལ། Help རོགས་རམ་བྱེད་དགོས། About དེའི་སྐོར། Feedback ལྡོག་འདྲེན་ Quit ཕྱིར་འཐེན་བྱ་དགོས། Auto མ་ལག་གི་རྗེས་སུ་འབྲང་བ Light མདོག་སྨུག་པོ། Dark ཚོས་གཞི་ཟབ་པ། kdk::KProgressDialog cancel མེད་པར་བཟོ་དགོས། kdk::KSearchLineEditPrivate Search འཚོལ་ཞིབ་བྱེད་པ། kdk::KSecurityLevelBar Low དམའ་བ། Medium ཀྲུང་གོའི་གུང་ཀྲུང་ High མཐོན་པོ། kdk::KSecurityLevelBarPrivate Low དམའ་བ། kdk::KSecurityQuestionDialog Security question%1 Answer Required ངེས་པར་དུ་སྐོང་དགོས། kdk::KSecurityQuestionDialogPrivate Security Question Setting security questions to reset password when forget it, please remember answer. Cancel ཕྱིར་འཐེན། Save ཉར་ཚགས་བྱེད་དགོས། kdk::KUninstallDialog uninstall འཕྲལ་མར་ཕབ་ལེན་བྱེད་དགོས། deb name: འགན་གཙང་ལེན་པའི་མིང་འདི deb version: པར་གཞི། kdk::KUninstallDialogPrivate deb name: འགན་གཙང་ལེན་པའི་མིང་འདི deb version: པར་གཞི། kdk::KWindowButtonBar Maximize ཆེ་ཤོས་སུ་སྒྱུར་བ་ Restore སླར་གསོ་བྱེད་དགོས། kdk::KWindowButtonBarPrivate Minimize ཆེས་ཆུང་ཅན་ Close སྒོ་རྒྱག་པ་ Maximize ཆེ་ཤོས་སུ་སྒྱུར་བ་ Restore སླར་གསོ་བྱེད་དགོས། libkysdk-applications/kysdk-qtwidgets/translations/gui_mn.qm0000664000175000017500000001101515104543305023472 0ustar fengfeng2$- ,!.5"-3!/ " $7$-$/$- 7 "Enter a value:kdk::KInputDialog&,!"0,!,&cancelkdk::KInputDialogPrivate* 3$/ ,$okkdk::KInputDialogPrivate 2$, "Aboutkdk::KMenuButton&-$$/ 0!3&* " 3 - ,$Autokdk::KMenuButton.,&( &)-! 2 " -$$/ 0!3&*Darkkdk::KMenuButton, 7"-$ 2$0, / Feedbackkdk::KMenuButton, *0$7,$Helpkdk::KMenuButton6,&6&,!( &)-! 2 " -$$/ 0!3&*Lightkdk::KMenuButton0#)-#/2 Optionskdk::KMenuButton*$4 5$ - 7,$Quitkdk::KMenuButton3$,"7 -$/,$Settingkdk::KMenuButton-$$/ 0!3&*Themekdk::KMenuButton&,!"0,!,&cancelkdk::KProgressDialog , "/3 Searchkdk::KSearchLineEditPrivate &(3&7Highkdk::KSecurityLevelBar 3$$7 Lowkdk::KSecurityLevelBar 3$.3 Mediumkdk::KSecurityLevelBar 3$$7 Lowkdk::KSecurityLevelBarPrivate!7,!*0" 3 -/ ,$Requiredkdk::KSecurityQuestionDialog&,!"0-!,& Cancel#kdk::KSecurityQuestionDialogPrivate, 3 - / ,$Save#kdk::KSecurityQuestionDialogPrivate* -3 ,$ (!7!  deb name:kdk::KUninstallDialog,!*/!/ deb version:kdk::KUninstallDialog(2!7! 3 7$" * -$/- ,$ uninstallkdk::KUninstallDialog* -3 ,$ (!7! deb name:kdk::KUninstallDialogPrivate,!*/!/ deb version:kdk::KUninstallDialogPrivate$, .$- $( 6!,!4"/!/Maximizekdk::KWindowButtonBar $- "6 ( *$4 - ,$Restorekdk::KWindowButtonBar , - ,$Closekdk::KWindowButtonBarPrivate$, .$- $( 6!,!4"/!/Maximizekdk::KWindowButtonBarPrivate$, .$- $( * - 4"/ /Minimizekdk::KWindowButtonBarPrivate $- "6 ( *$4 - ,$Restorekdk::KWindowButtonBarPrivatelibkysdk-applications/kysdk-qtwidgets/translations/gui_de.qm0000664000175000017500000000775015104543305023463 0ustar fengfengBitte whlen Sie eine Datei ausPlease select filekdk::KAddFileButtonPrivateWhlen Sie den Ordneridentifikationspfad aus oder ziehen Sie ihn per Drag & Drop6Select or drag and drop the folder identification pathkdk::KDragWidget>Bitte whlen Sie eine Datei ausPlease select filekdk::KDragWidgetPrivate2Geben Sie einen Wert ein:Enter a value:kdk::KInputDialogAbbrechencancelkdk::KInputDialogPrivateOkayokkdk::KInputDialogPrivateberAboutkdk::KMenuButtonAutoAutokdk::KMenuButton DunkelDarkkdk::KMenuButtonFeedbackFeedbackkdk::KMenuButton HilfeHelpkdk::KMenuButton LichtLightkdk::KMenuButtonOptionenOptionskdk::KMenuButtonVerlassenQuitkdk::KMenuButtonEinstellungSettingkdk::KMenuButton ThemaThemekdk::KMenuButtonAbbrechencancelkdk::KProgressDialog SuchenSearchkdk::KSearchLineEditPrivateHochHighkdk::KSecurityLevelBarNiedrigLowkdk::KSecurityLevelBar MittelMediumkdk::KSecurityLevelBarNiedrigLowkdk::KSecurityLevelBarPrivateErforderlichRequiredkdk::KSecurityQuestionDialogAbbrechenCancel#kdk::KSecurityQuestionDialogPrivate RettenSave#kdk::KSecurityQuestionDialogPrivateDeb Name: deb name:kdk::KUninstallDialogDeb-Version: deb version:kdk::KUninstallDialogDeinstallieren uninstallkdk::KUninstallDialogDeb Name: deb name:kdk::KUninstallDialogPrivateDeb-Version: deb version:kdk::KUninstallDialogPrivateMaximierenMaximizekdk::KWindowButtonBar WiederherstellenRestorekdk::KWindowButtonBarSchlieenClosekdk::KWindowButtonBarPrivateMaximierenMaximizekdk::KWindowButtonBarPrivateMinimierenMinimizekdk::KWindowButtonBarPrivate WiederherstellenRestorekdk::KWindowButtonBarPrivatelibkysdk-applications/kysdk-qtwidgets/translations/gui_kk.ts0000664000175000017500000002645515104543305023514 0ustar fengfeng CloseButton Close Tab بەتكۇش ياپ KCustomTabBar Scroll Left سولعا سىيرىل Scroll Right وڭعا سيىرىلۋ kdk::KAboutDialog Your system does not have any email application installed or the default mail application is not set up Unable to open mail application پوچتا جولدانباسى ورتاسنىڭ اشۋئاجرىتىششىن بولمادى Service & Support: 服务与支持团队: قىزىمەت ۋا قولداۋ: Privacy statement قۇپيالىعىن ساقتاۋ مالىمەتى kdk::KAboutDialogPrivate version : نۇسخا Version number not found بۇرشاق كەلەتىن نۇسخا نۇمىردى تاباالمادٸ kdk::KAddFileButtonPrivate Please select file حۇجاتتى تالدا kdk::KDragWidget Select or drag and drop the folder identification path حۇجات قىسۋاسپابىنىڭ كورسەتپە جولىن تالدا ياكي سۇيرەپ كەلىڭ kdk::KDragWidgetPrivate Please select file حۇجاتتى تالدا kdk::KInputDialog Enter a value: بٸر مانىن كىرگىزىڭىز: kdk::KInputDialogPrivate ok تۇراقتاندىرۋ cancel بوس ەتۋ kdk::KMenuButton Options تالدانبا Setting 设置 تەڭشە Theme سلوب Help جاردەم About جونٸندە Feedback جاۋاپ قايتارۋ Quit شەگىنۋ Auto اۆتوماتىك Light السىرەۋ رەڭ Dark قانىق رەڭ kdk::KProgressDialog cancel بوس ەتۋ kdk::KSearchLineEditPrivate Search ٸزدەۋ kdk::KSecurityLevelBar Low تومەن Medium ورتا High جوعارعى kdk::KSecurityLevelBarPrivate Low تومەن kdk::KSecurityQuestionDialog Security question%1 Answer Required ٴسوزسىز kdk::KSecurityQuestionDialogPrivate Security Question Setting security questions to reset password when forget it, please remember answer. Cancel كۇشىنەن قالدىرۋ Save ساقتاۋ kdk::KUninstallDialog uninstall 立即卸载 دەرەۋ جۋىپ جىبەرۋ deb name: بۇلاق مى: deb version: باسىلىمى: kdk::KUninstallDialogPrivate deb name: بۇلاق مى: deb version: باسىلىمى: kdk::KWindowButtonBar Maximize ۇلكەيتۋ Restore قالپىنا كەلتىرىلگەن kdk::KWindowButtonBarPrivate Minimize ەڭ كشكەنە بەينە Close تاقاۋ Maximize ۇلكەيتۋ Restore قالپىنا كەلتىرىلگەن libkysdk-applications/kysdk-qtwidgets/sdk_res.qrc0000664000175000017500000000123015104543305021273 0ustar fengfeng translations/gui_zh_CN.qm translations/gui_bo_CN.qm translations/gui_mn.qm translations/gui_zh_HK.qm translations/gui_de.qm translations/gui_es.qm translations/gui_fr.qm translations/gui_kk.qm translations/gui_ug.qm translations/gui_ky.qm image/ukui-switchbutton-symbolic.svg image/starred-symbolic.svg image/non-starred-symbolic.svg libkysdk-applications/kysdk-qtwidgets/image/0000775000175000017500000000000015104543305020220 5ustar fengfenglibkysdk-applications/kysdk-qtwidgets/image/starred-symbolic.svg0000664000175000017500000000140415104543305024223 0ustar fengfeng libkysdk-applications/kysdk-qtwidgets/image/ukui-semantics-symbolic.svg0000664000175000017500000000333615104543305025526 0ustar fengfeng libkysdk-applications/kysdk-qtwidgets/image/non-starred-symbolic.svg0000664000175000017500000000122715104543305025016 0ustar fengfenglibkysdk-applications/kysdk-qtwidgets/image/ukui-switchbutton-symbolic.svg0000664000175000017500000000036515104543305026274 0ustar fengfenglibkysdk-applications/kysdk-qtwidgets/test/0000775000175000017500000000000015104543305020115 5ustar fengfenglibkysdk-applications/kysdk-qtwidgets/test/testLunarDateEdit/0000775000175000017500000000000015104543305023502 5ustar fengfenglibkysdk-applications/kysdk-qtwidgets/test/testLunarDateEdit/widget.h0000664000175000017500000000061515104543305025140 0ustar fengfeng#ifndef WIDGET_H #define WIDGET_H #include "klunardateedit.h" #include #include using namespace kdk; class Widget : public QWidget { Q_OBJECT public: Widget(QWidget *parent = nullptr); ~Widget(); private slots: void on_checkBox_clicked(bool checked); private: QCheckBox *m_pLunarCheckBox; KLunarDateEdit *m_pLunarDateEdit; }; #endif // WIDGET_H libkysdk-applications/kysdk-qtwidgets/test/testLunarDateEdit/testLunarDateEdit.pro0000664000175000017500000000200115104543305027602 0ustar fengfengQT += core gui greaterThan(QT_MAJOR_VERSION, 4): QT += widgets CONFIG += c++17 CONFIG += link_pkgconfig PKGCONFIG += kysdk-widgetutils kysdk-qtwidgets # The following define makes your compiler emit warnings if you use # any Qt feature that has been marked deprecated (the exact warnings # depend on your compiler). Please consult the documentation of the # deprecated API in order to know how to port your code away from it. DEFINES += QT_DEPRECATED_WARNINGS # You can also make your code fail to compile if it uses deprecated APIs. # In order to do so, uncomment the following line. # You can also select to disable deprecated APIs only up to a certain version of Qt. #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 SOURCES += \ main.cpp \ widget.cpp HEADERS += \ widget.h # Default rules for deployment. qnx: target.path = /tmp/$${TARGET}/bin else: unix:!android: target.path = /opt/$${TARGET}/bin !isEmpty(target.path): INSTALLS += target libkysdk-applications/kysdk-qtwidgets/test/testLunarDateEdit/widget.cpp0000664000175000017500000000172315104543305025474 0ustar fengfeng#include "widget.h" #include "klunardateedit.h" #include Widget::Widget(QWidget *parent) : QWidget(parent) { this->setFixedSize(300, 150); QVBoxLayout *layout = new QVBoxLayout(this); m_pLunarCheckBox = new QCheckBox(this); m_pLunarCheckBox->setObjectName(QString::fromUtf8("checkBox")); m_pLunarCheckBox->setGeometry(QRect(120, 80, 82, 21)); m_pLunarCheckBox->setChecked(false); m_pLunarCheckBox->setText("Lunar"); m_pLunarDateEdit = new KLunarDateEdit(this); m_pLunarDateEdit->setFixedSize(140, 36); layout->addWidget(m_pLunarCheckBox); layout->addWidget(m_pLunarDateEdit); // 用法,拿到DateEdit指针,然后像正常DateEdit控件一样用,农历会跟随刷新 m_pLunarDateEdit->getDateEdit()->setDate(QDate::currentDate()); QMetaObject::connectSlotsByName(this); } Widget::~Widget() { } void Widget::on_checkBox_clicked(bool checked) { m_pLunarDateEdit->setShowLunar(checked); } libkysdk-applications/kysdk-qtwidgets/test/testLunarDateEdit/main.cpp0000664000175000017500000000024415104543305025132 0ustar fengfeng#include "widget.h" #include int main(int argc, char *argv[]) { QApplication a(argc, argv); Widget w; w.show(); return a.exec(); } libkysdk-applications/kysdk-qtwidgets/test/testListView/0000775000175000017500000000000015104543305022563 5ustar fengfenglibkysdk-applications/kysdk-qtwidgets/test/testListView/widget.h0000664000175000017500000000170015104543305024215 0ustar fengfeng/* * * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhenyu Wang * */ #ifndef WIDGET_H #define WIDGET_H #include class Widget : public QWidget { Q_OBJECT public: Widget(QWidget *parent = nullptr); ~Widget(); }; #endif // WIDGET_H libkysdk-applications/kysdk-qtwidgets/test/testListView/testListView.pro0000664000175000017500000000200215104543305025745 0ustar fengfengQT += core gui greaterThan(QT_MAJOR_VERSION, 4): QT += widgets CONFIG += link_pkgconfig PKGCONFIG += kysdk-qtwidgets kysdk-widgetutils CONFIG += c++17 # The following define makes your compiler emit warnings if you use # any Qt feature that has been marked deprecated (the exact warnings # depend on your compiler). Please consult the documentation of the # deprecated API in order to know how to port your code away from it. DEFINES += QT_DEPRECATED_WARNINGS # You can also make your code fail to compile if it uses deprecated APIs. # In order to do so, uncomment the following line. # You can also select to disable deprecated APIs only up to a certain version of Qt. #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 SOURCES += \ main.cpp \ widget.cpp HEADERS += \ widget.h # Default rules for deployment. qnx: target.path = /tmp/$${TARGET}/bin else: unix:!android: target.path = /opt/$${TARGET}/bin !isEmpty(target.path): INSTALLS += target libkysdk-applications/kysdk-qtwidgets/test/testListView/widget.cpp0000664000175000017500000000701415104543305024554 0ustar fengfeng/* * * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhenyu Wang * */ #include "widget.h" #include "klistview.h" #include "klistviewdelegate.h" #include #include #include #include #include #include using namespace kdk; Widget::Widget(QWidget *parent) : QWidget(parent) { QHBoxLayout *hlayout = new QHBoxLayout(this); QListView *view = new QListView(this); view->setIconSize(QSize(32, 32)); // 设置图片大小 QStandardItemModel *model = new QStandardItemModel(this); KListViewDelegate *delegate = new KListViewDelegate(view); view->setModel(model); QStandardItem *item = new QStandardItem(); item->setIcon(QIcon::fromTheme("kylin-music")); item->setData(QVariant("Test"), Qt::DisplayRole); item->setData(QVariant("subTEST"), Qt::UserRole); QStandardItem *item1 = new QStandardItem(); item1->setIcon(QIcon::fromTheme("kylin-music")); item1->setData(QVariant("Test"), Qt::DisplayRole); item1->setData(QVariant("supTEST"), Qt::UserRole); QStandardItem *item2 = new QStandardItem(); item2->setIcon(QIcon::fromTheme("kylin-music")); item2->setData(QVariant("Test"), Qt::DisplayRole); item2->setData(QVariant("supTEST"), Qt::UserRole); model->appendRow(item); model->appendRow(item1); model->appendRow(item2); view->setItemDelegate(delegate); view->setViewMode(QListView::ListMode); // view->setGridSize(QSize(60,120));//IconMode下用 view->setFixedSize(300, 480); hlayout->addWidget(view); QListView *view1 = new QListView(this); view1->setIconSize(QSize(32, 32)); QStandardItemModel *model1 = new QStandardItemModel(this); KListViewDelegate *delegate1 = new KListViewDelegate(view1); view1->setModel(model1); QStandardItem *item3 = new QStandardItem(); item3->setIcon(QIcon::fromTheme("kylin-music")); item3->setData(QVariant("Test"), Qt::DisplayRole); QStandardItem *item4 = new QStandardItem(); item4->setIcon(QIcon::fromTheme("kylin-music")); item4->setData(QVariant("Test"), Qt::DisplayRole); QStandardItem *item5 = new QStandardItem(); item5->setIcon(QIcon::fromTheme("kylin-music")); item5->setData(QVariant("Test"), Qt::DisplayRole); model1->appendRow(item3); model1->appendRow(item4); model1->appendRow(item5); view1->setItemDelegate(delegate1); view1->setViewMode(QListView::ListMode); // view->setGridSize(QSize(60,120));//IconMode下用 hlayout->addWidget(view1); // view->setSelectionMode(QAbstractItemView::ContiguousSelection); // view->setSelectionMode(QAbstractItemView::MultiSelection); // view->setSelectionMode(QAbstractItemView::ExtendedSelection); view1->setFixedSize(300, 480); // setFixedSize(800,600); } Widget::~Widget() { } libkysdk-applications/kysdk-qtwidgets/test/testListView/main.cpp0000664000175000017500000000255115104543305024216 0ustar fengfeng/* * * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhenyu Wang * */ #include "widget.h" #include "kwidgetutils.h" #include #include int main(int argc, char *argv[]) { kdk::KWidgetUtils::highDpiScaling(); QApplication a(argc, argv); QTranslator trans; QString locale = QLocale::system().name(); if (locale == "zh_CN") { if (trans.load(":/translations/gui_zh_CN.qm")) { a.installTranslator(&trans); } } if (locale == "bo_CN") { if (trans.load(":/translations/gui_bo_CN.qm")) { a.installTranslator(&trans); } } Widget w; w.show(); return a.exec(); } libkysdk-applications/kysdk-qtwidgets/test/testcomboboxwidget/0000775000175000017500000000000015104543305024031 5ustar fengfenglibkysdk-applications/kysdk-qtwidgets/test/testcomboboxwidget/widget.h0000664000175000017500000000167515104543305025476 0ustar fengfeng/* * * Copyright (C) 2024, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhenyu Wang * */ #ifndef WIDGET_H #define WIDGET_H #include class Widget : public QWidget { Q_OBJECT public: Widget(QWidget *parent = nullptr); ~Widget(); }; #endif // WIDGET_H libkysdk-applications/kysdk-qtwidgets/test/testcomboboxwidget/testcomboboxwidget.pro0000664000175000017500000000203615104543305030470 0ustar fengfengQT += core gui greaterThan(QT_MAJOR_VERSION, 4): QT += widgets CONFIG += c++17 CONFIG += link_pkgconfig PKGCONFIG += gsettings-qt6 PKGCONFIG += kysdk-widgetutils kysdk-qtwidgets # The following define makes your compiler emit warnings if you use # any Qt feature that has been marked deprecated (the exact warnings # depend on your compiler). Please consult the documentation of the # deprecated API in order to know how to port your code away from it. DEFINES += QT_DEPRECATED_WARNINGS # You can also make your code fail to compile if it uses deprecated APIs. # In order to do so, uncomment the following line. # You can also select to disable deprecated APIs only up to a certain version of Qt. #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 SOURCES += \ main.cpp \ widget.cpp HEADERS += \ widget.h # Default rules for deployment. qnx: target.path = /tmp/$${TARGET}/bin else: unix:!android: target.path = /opt/$${TARGET}/bin !isEmpty(target.path): INSTALLS += target libkysdk-applications/kysdk-qtwidgets/test/testcomboboxwidget/widget.cpp0000664000175000017500000000360215104543305026021 0ustar fengfeng/* * * Copyright (C) 2024, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhenyu Wang * */ #include "widget.h" #include "kcomboboxwidget.h" #include #include #include #include using namespace kdk; Widget::Widget(QWidget *parent) : QWidget(parent) { KComboBoxWidget *widget = new KComboBoxWidget(this); // widget->setLabelWeekSelect("111"); QStringList list; list.append("111"); list.append("222"); list.append("333"); list.append("444444444"); list.append("55555555555"); list.append("66666"); list.append("7777"); list.append("888"); widget->setStringList(list); widget->setMainText("abnfaowifoawf"); widget->menu()->setFixedWidth(200); connect(widget, &KComboBoxWidget::comBoxWidgetClicked, this, [=] { qDebug() << "xxx" << widget->getChosenList() << widget->width() << widget->menu()->size(); }); QPushButton *btn = new QPushButton(this); QMenu *menu = new QMenu(this); menu->addAction("1"); menu->addAction("2"); menu->addAction("3"); menu->addAction("4"); menu->show(); btn->move(0, 200); btn->setMenu(menu); setFixedSize(600, 500); } Widget::~Widget() { } libkysdk-applications/kysdk-qtwidgets/test/testcomboboxwidget/main.cpp0000664000175000017500000000165015104543305025463 0ustar fengfeng/* * * Copyright (C) 2024, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhenyu Wang * */ #include "widget.h" #include int main(int argc, char *argv[]) { QApplication a(argc, argv); Widget w; w.show(); return a.exec(); } libkysdk-applications/kysdk-qtwidgets/test/testcrumb/0000775000175000017500000000000015104543305022125 5ustar fengfenglibkysdk-applications/kysdk-qtwidgets/test/testcrumb/testcrumb.pro0000664000175000017500000000200115104543305024650 0ustar fengfengQT += core gui greaterThan(QT_MAJOR_VERSION, 4): QT += widgets CONFIG += c++17 CONFIG += link_pkgconfig PKGCONFIG += kysdk-widgetutils kysdk-qtwidgets # The following define makes your compiler emit warnings if you use # any Qt feature that has been marked deprecated (the exact warnings # depend on your compiler). Please consult the documentation of the # deprecated API in order to know how to port your code away from it. DEFINES += QT_DEPRECATED_WARNINGS # You can also make your code fail to compile if it uses deprecated APIs. # In order to do so, uncomment the following line. # You can also select to disable deprecated APIs only up to a certain version of Qt. #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 SOURCES += \ main.cpp \ widget.cpp HEADERS += \ widget.h # Default rules for deployment. qnx: target.path = /tmp/$${TARGET}/bin else: unix:!android: target.path = /opt/$${TARGET}/bin !isEmpty(target.path): INSTALLS += target libkysdk-applications/kysdk-qtwidgets/test/testcrumb/widget.h0000664000175000017500000000167515104543305023572 0ustar fengfeng/* * * Copyright (C) 2024, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhenyu Wang * */ #ifndef WIDGET_H #define WIDGET_H #include class Widget : public QWidget { Q_OBJECT public: Widget(QWidget *parent = nullptr); ~Widget(); }; #endif // WIDGET_H libkysdk-applications/kysdk-qtwidgets/test/testcrumb/widget.cpp0000664000175000017500000001045515104543305024121 0ustar fengfeng/* * * Copyright (C) 2024, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhenyu Wang * */ #include "widget.h" #include "kborderlessbutton.h" #include "kcrumb.h" #include #include #include using namespace kdk; Widget::Widget(QWidget *parent) : QWidget(parent) { QVBoxLayout *mainLayout = new QVBoxLayout; QHBoxLayout *hLayout = new QHBoxLayout; KCrumb *crumb = new KCrumb(this); // QTabBar*crumb = new QTabBar(this); crumb->setUsesScrollButtons(false); // 默认是true crumb->setFlat(false); crumb->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); crumb->addTab("页面目录一,页面目录一"); crumb->addTab("页面目录二,页面目录二"); crumb->addTab("页面目录三,页面目录三"); crumb->addTab("页面目录四,页面目录四"); crumb->addTab("页面目录五,页面目录五"); // crumb->setFixedWidth(1200); // crumb->setIcon(QIcon::fromTheme("dialog-info")); //设置KBreadCrumb的图标 crumb->setUsesScrollButtons(false); ; // crumb->addTab("长的长的长的长的长的长的"); // crumb->addTab("长的长的长的长的长的长的"); // crumb->setIcon(QIcon::fromTheme("dialog-info")); //设置KBreadCrumb的图标 // KBorderlessButton *btn1 = new KBorderlessButton(); // KBorderlessButton *btn2 = new KBorderlessButton(); // btn1->setIcon(QIcon::fromTheme("go-previous.symbolic")); // btn2->setIcon(QIcon::fromTheme("go-next.symbolic")); // btn1->setFixedSize(24,24); // btn2->setFixedSize(24,24); // hLayout->addWidget(btn1); // hLayout->addWidget(btn2); hLayout->addWidget(crumb); mainLayout->addLayout(hLayout); hLayout = new QHBoxLayout; // KCrumb*crumb2 = new KCrumb(this); QTabBar *crumb2 = new QTabBar(this); // //默认是true // crumb->setFlat(false); //设置KBreadCrumb是否为flat类型 // crumb2->setSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); crumb2->addTab("页面目录一,页面目录一"); crumb2->addTab("页面目录二,页面目录二"); crumb2->addTab("页面目录三,页面目录三"); crumb2->addTab("短的"); crumb2->addTab("长的长的长的长的长的长的"); //// crumb2->setIcon(QIcon::fromTheme("dialog-warning")); hLayout->addWidget(crumb2); mainLayout->addLayout(hLayout); // crumb2->setFixedWidth(200); //// crumb2->setShape(QTabBar::RoundedWest); mainLayout->addLayout(hLayout); setLayout(mainLayout); // if(crumb->currentIndex() == 0) // { // btn1->setEnabled(false); // } // else if(crumb->currentIndex() == crumb->count() - 1) // { // btn2->setEnabled(false); // } // connect(btn1,&KBorderlessButton::clicked,this,[=]{ // crumb->leftScrollTabs(); // }); // connect(btn2,&KBorderlessButton::clicked,this,[=]{ // crumb->rightScrollTabs(); // }); setMinimumSize(600, 500); crumb2->setElideMode(Qt::ElideMiddle); connect(crumb, &KCrumb::tabBarClicked, this, [=](int index) { if (index == 1) crumb->setMaximumWidth(1300); }); // connect(crumb2,&QTabBar::tabBarClicked,this,[=](int index){ // if(index == 0) // { // crumb2->setTabText(1,"..."); // crumb2->adjustSize(); // } // if(index == 1) // { // crumb2->setTabText(1,"页面目录二,页面目录二"); // crumb2->adjustSize(); // } // }); } Widget::~Widget() { } libkysdk-applications/kysdk-qtwidgets/test/testcrumb/main.cpp0000664000175000017500000000240415104543305023555 0ustar fengfeng/* * * Copyright (C) 2024, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhenyu Wang * */ #include "widget.h" #include #include #include #include #include int main(int argc, char *argv[]) { QApplication a(argc, argv); QString qtTransPath = QLibraryInfo::location(QLibraryInfo::TranslationsPath); QTranslator *trans_qt = new QTranslator(); qDebug() << qtTransPath; if (trans_qt->load(QLocale(), "qt", "_", qtTransPath)) qApp->installTranslator(trans_qt); Widget w; w.show(); return a.exec(); } libkysdk-applications/kysdk-qtwidgets/test/testsecurityquestiondialog/0000775000175000017500000000000015104543305025634 5ustar fengfenglibkysdk-applications/kysdk-qtwidgets/test/testsecurityquestiondialog/dialog.h0000664000175000017500000000165615104543305027254 0ustar fengfeng/* * * Copyright (C) 2024, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhenyu Wang * */ #ifndef DIALOG_H #define DIALOG_H #include class Dialog : public QWidget { Q_OBJECT public: Dialog(QWidget *parent = nullptr); }; #endif // DIALOG_H libkysdk-applications/kysdk-qtwidgets/test/testsecurityquestiondialog/testsecurityquestiondialog.pro0000664000175000017500000000176115104543305034102 0ustar fengfengQT += core gui greaterThan(QT_MAJOR_VERSION, 4): QT += widgets CONFIG += c++17 CONFIG += link_pkgconfig PKGCONFIG += kysdk-qtwidgets # The following define makes your compiler emit warnings if you use # any Qt feature that has been marked deprecated (the exact warnings # depend on your compiler). Please consult the documentation of the # deprecated API in order to know how to port your code away from it. DEFINES += QT_DEPRECATED_WARNINGS # You can also make your code fail to compile if it uses deprecated APIs. # In order to do so, uncomment the following line. # You can also select to disable deprecated APIs only up to a certain version of Qt. #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 SOURCES += \ dialog.cpp \ main.cpp \ HEADERS += \ dialog.h # Default rules for deployment. qnx: target.path = /tmp/$${TARGET}/bin else: unix:!android: target.path = /opt/$${TARGET}/bin !isEmpty(target.path): INSTALLS += target libkysdk-applications/kysdk-qtwidgets/test/testsecurityquestiondialog/dialog.cpp0000664000175000017500000000447215104543305027606 0ustar fengfeng/* * * Copyright (C) 2024, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhenyu Wang * */ #include "dialog.h" #include #include "ksecurityquestiondialog.h" using namespace kdk; Dialog::Dialog(QWidget *parent) : QWidget(parent) { KSecurityQuestionDialog *questionDialog = new KSecurityQuestionDialog(); questionDialog->setWindowIcon("ukui-control-center"); questionDialog->setWindowTitle("Security Question"); questionDialog->setTitleText(tr("Answer the security questions and reset your password")); questionDialog->addSecurityQuestionItem(3, true); QStringList AA; AA << "111" << "222" << "333" << "444"; questionDialog->initQustionCombox(AA); if (questionDialog->answerLabel(1) != nullptr) { questionDialog->answerLabel(1)->setText("answerLabel1"); qDebug() << questionDialog->answerLabel(1)->text(); } if (questionDialog->questionLabel(1) != nullptr) { questionDialog->questionLabel(1)->setText("test111"); qDebug() << questionDialog->questionLabel(1)->text(); } if (questionDialog->answerLineedit(1) != nullptr) { qDebug() << questionDialog->answerLineedit(1)->text(); } if (questionDialog->questionCombox(1) != nullptr) { qDebug() << questionDialog->questionCombox(1)->currentText(); } if (questionDialog->tipsLabel(1) != nullptr) { questionDialog->tipsLabel(1)->setText("Incorrect answer"); qDebug() << questionDialog->tipsLabel(1)->text(); } connect(questionDialog->cancelButton(), &KPushButton::clicked, this, [=]() { questionDialog->close(); }); questionDialog->show(); } libkysdk-applications/kysdk-qtwidgets/test/testsecurityquestiondialog/main.cpp0000664000175000017500000000214515104543305027266 0ustar fengfeng/* * * Copyright (C) 2024, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhenyu Wang * */ #include "dialog.h" #include #include int main(int argc, char *argv[]) { QApplication a(argc, argv); // sdk翻译加载 QTranslator trans; if (trans.load(":/translations/gui_" + QLocale::system().name() + ".qm")) { a.installTranslator(&trans); } Dialog testDailog; return a.exec(); } libkysdk-applications/kysdk-qtwidgets/test/testpasswordedit/0000775000175000017500000000000015104543305023525 5ustar fengfenglibkysdk-applications/kysdk-qtwidgets/test/testpasswordedit/testpasswordedit.pro0000664000175000017500000000200215104543305027651 0ustar fengfengQT += core gui greaterThan(QT_MAJOR_VERSION, 4): QT += widgets CONFIG += link_pkgconfig PKGCONFIG += kysdk-qtwidgets kysdk-widgetutils CONFIG += c++17 # The following define makes your compiler emit warnings if you use # any Qt feature that has been marked deprecated (the exact warnings # depend on your compiler). Please consult the documentation of the # deprecated API in order to know how to port your code away from it. DEFINES += QT_DEPRECATED_WARNINGS # You can also make your code fail to compile if it uses deprecated APIs. # In order to do so, uncomment the following line. # You can also select to disable deprecated APIs only up to a certain version of Qt. #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 SOURCES += \ main.cpp \ widget.cpp HEADERS += \ widget.h # Default rules for deployment. qnx: target.path = /tmp/$${TARGET}/bin else: unix:!android: target.path = /opt/$${TARGET}/bin !isEmpty(target.path): INSTALLS += target libkysdk-applications/kysdk-qtwidgets/test/testpasswordedit/widget.h0000664000175000017500000000214615104543305025164 0ustar fengfeng/* * * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #ifndef WIDGET_H #define WIDGET_H #include "kpasswordedit.h" #include "kwidget.h" using namespace kdk; class Widget : public KWidget { Q_OBJECT public: Widget(QWidget *parent = nullptr); ~Widget(); private: KPasswordEdit *m_pPasswordEdit; KPasswordEdit *m_pPasswordEdit1; KPasswordEdit *m_pPasswordEdit2; }; #endif // WIDGET_H libkysdk-applications/kysdk-qtwidgets/test/testpasswordedit/widget.cpp0000664000175000017500000000736215104543305025524 0ustar fengfeng/* * * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #include "widget.h" #include #include #include static const QString password = "kylin"; Widget::Widget(QWidget *parent) : KWidget(parent) { QVBoxLayout *vLayout = new QVBoxLayout(this); QHBoxLayout *hLayout = new QHBoxLayout(this); m_pPasswordEdit = new KPasswordEdit(this); hLayout->addWidget(m_pPasswordEdit); m_pPasswordEdit1 = new KPasswordEdit(this); m_pPasswordEdit2 = new KPasswordEdit(this); QPushButton *confirmBtn = new QPushButton("confirm", this); hLayout->addWidget(confirmBtn); vLayout->addLayout(hLayout); vLayout->addWidget(m_pPasswordEdit1); vLayout->addWidget(m_pPasswordEdit2); hLayout = new QHBoxLayout(this); QPushButton *enableBtn = new QPushButton("enable", this); hLayout->addWidget(enableBtn); QPushButton *loadingBtn = new QPushButton("isLoading:false", this); hLayout->addWidget(loadingBtn); vLayout->addLayout(hLayout); this->baseBar()->setLayout(vLayout); QString str("dwadwa"); m_pPasswordEdit1->setPlaceholderText(str); // 设置背景文字 m_pPasswordEdit1->setClearButtonEnabled(false); // 禁用ClearBtn按钮 m_pPasswordEdit2->setEchoModeBtnVisible(false); // 隐藏EchoMode按钮 bool flag = m_pPasswordEdit2->echoModeBtnVisible(); // 返回EchoMode按钮是否隐藏 m_pPasswordEdit2->setEchoMode(QLineEdit::EchoMode::Normal); // 明文输入 m_pPasswordEdit->setClearBtnVisible(false); // 隐藏ClearBtn按钮(启用但隐藏) bool flag1 = m_pPasswordEdit->clearBtnVisible(); // 返回ClearBtn按钮是否隐藏 connect(confirmBtn, &QPushButton::clicked, this, [=]() { if (m_pPasswordEdit->text() == password) m_pPasswordEdit->setState(LoginState::LoginSuccess); // 设置登录状态 else m_pPasswordEdit->setState(LoginState::LoginFailed); m_pPasswordEdit->setFocus(); }); connect(m_pPasswordEdit, &KPasswordEdit::returnPressed, this, [=]() { if (m_pPasswordEdit->text() == password) m_pPasswordEdit->setState(LoginState::LoginSuccess); else m_pPasswordEdit->setState(LoginState::LoginFailed); m_pPasswordEdit->setFocus(); }); connect(enableBtn, &QPushButton::clicked, this, [=]() { if (m_pPasswordEdit->isEnabled()) { m_pPasswordEdit->setEnabled(false); // 设置KLineEdit不可用 enableBtn->setText("disable"); } else { m_pPasswordEdit->setEnabled(true); enableBtn->setText("enable"); } }); connect(loadingBtn, &QPushButton::clicked, this, [=]() { if (!m_pPasswordEdit->isLoading()) { qDebug() << "is loading"; m_pPasswordEdit->setLoading(true); // 设置启用加载状态 loadingBtn->setText("isLoading:true"); } else { qDebug() << "is not loading"; m_pPasswordEdit->setLoading(false); loadingBtn->setText("isLoading:false"); } }); } Widget::~Widget() { } libkysdk-applications/kysdk-qtwidgets/test/testpasswordedit/main.cpp0000664000175000017500000000254415104543305025162 0ustar fengfeng/* * * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #include "widget.h" #include "kwidgetutils.h" #include #include int main(int argc, char *argv[]) { kdk::KWidgetUtils::highDpiScaling(); QApplication a(argc, argv); QTranslator trans; QString locale = QLocale::system().name(); if (locale == "zh_CN") { if (trans.load(":/translations/gui_zh_CN.qm")) { a.installTranslator(&trans); } } if (locale == "bo_CN") { if (trans.load(":/translations/gui_bo_CN.qm")) { a.installTranslator(&trans); } } Widget w; w.show(); return a.exec(); } libkysdk-applications/kysdk-qtwidgets/test/testclocktimer/0000775000175000017500000000000015104543305023151 5ustar fengfenglibkysdk-applications/kysdk-qtwidgets/test/testclocktimer/testclocktimer.pro0000664000175000017500000000200115104543305026720 0ustar fengfengQT += core gui greaterThan(QT_MAJOR_VERSION, 4): QT += widgets CONFIG += c++17 CONFIG += link_pkgconfig PKGCONFIG += kysdk-widgetutils kysdk-qtwidgets # The following define makes your compiler emit warnings if you use # any Qt feature that has been marked deprecated (the exact warnings # depend on your compiler). Please consult the documentation of the # deprecated API in order to know how to port your code away from it. DEFINES += QT_DEPRECATED_WARNINGS # You can also make your code fail to compile if it uses deprecated APIs. # In order to do so, uncomment the following line. # You can also select to disable deprecated APIs only up to a certain version of Qt. #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 SOURCES += \ main.cpp \ widget.cpp HEADERS += \ widget.h # Default rules for deployment. qnx: target.path = /tmp/$${TARGET}/bin else: unix:!android: target.path = /opt/$${TARGET}/bin !isEmpty(target.path): INSTALLS += target libkysdk-applications/kysdk-qtwidgets/test/testclocktimer/widget.h0000664000175000017500000000167515104543305024616 0ustar fengfeng/* * * Copyright (C) 2024, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhenyu Wang * */ #ifndef WIDGET_H #define WIDGET_H #include class Widget : public QWidget { Q_OBJECT public: Widget(QWidget *parent = nullptr); ~Widget(); }; #endif // WIDGET_H libkysdk-applications/kysdk-qtwidgets/test/testclocktimer/widget.cpp0000664000175000017500000000476415104543305025153 0ustar fengfeng/* * * Copyright (C) 2024, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhenyu Wang * */ #include "widget.h" #include "kclocktimer.h" #include #include #include using namespace kdk; Widget::Widget(QWidget *parent) : QWidget(parent) { QVBoxLayout *vlayout = new QVBoxLayout(this); KClockTimer *clock = new KClockTimer(this); QHBoxLayout *hlayout = new QHBoxLayout(); QPushButton *btn1 = new QPushButton("开始"); QPushButton *btn2 = new QPushButton("停止"); QPushButton *btn3 = new QPushButton("复位"); QPushButton *btn4 = new QPushButton("继续"); QPushButton *btn5 = new QPushButton("计次"); hlayout->addWidget(btn1); hlayout->addWidget(btn2); vlayout->addWidget(clock); vlayout->addLayout(hlayout); hlayout = new QHBoxLayout(); hlayout->addWidget(btn3); hlayout->addWidget(btn4); vlayout->addLayout(hlayout); hlayout = new QHBoxLayout(); hlayout->addWidget(btn5); vlayout->addLayout(hlayout); connect(btn1, &QPushButton::clicked, clock, &KClockTimer::startStopwatch); connect(btn2, &QPushButton::clicked, clock, &KClockTimer::stopStopwatch); connect(btn3, &QPushButton::clicked, clock, &KClockTimer::resetStopwatch); connect(btn4, &QPushButton::clicked, clock, &KClockTimer::startStopwatch); connect(btn5, &QPushButton::clicked, this, [=] { qDebug() << clock->time(); }); // qint64 otherMilliseconds = stringToMilliseconds(otherTimeString); // 转换为毫秒数 // // 比较两个时间 // if (compareMilliseconds(currentMilliseconds, otherMilliseconds)) { // // currentMilliseconds小于otherMilliseconds // } else { // // currentMilliseconds大于或等于otherMilliseconds // } // setFixedSize(300,200); } Widget::~Widget() { } libkysdk-applications/kysdk-qtwidgets/test/testclocktimer/main.cpp0000664000175000017500000000165015104543305024603 0ustar fengfeng/* * * Copyright (C) 2024, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhenyu Wang * */ #include "widget.h" #include int main(int argc, char *argv[]) { QApplication a(argc, argv); Widget w; w.show(); return a.exec(); } libkysdk-applications/kysdk-qtwidgets/test/testKTextedit/0000775000175000017500000000000015104543305022722 5ustar fengfenglibkysdk-applications/kysdk-qtwidgets/test/testKTextedit/widget.h0000664000175000017500000000167515104543305024367 0ustar fengfeng/* * * Copyright (C) 2024, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhenyu Wang * */ #ifndef WIDGET_H #define WIDGET_H #include class Widget : public QWidget { Q_OBJECT public: Widget(QWidget *parent = nullptr); ~Widget(); }; #endif // WIDGET_H libkysdk-applications/kysdk-qtwidgets/test/testKTextedit/widget.cpp0000664000175000017500000001166715104543305024724 0ustar fengfeng/* * * Copyright (C) 2024, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhenyu Wang * */ #include "widget.h" #include "kbubblewidget.h" #include "ktextedit.h" #include using namespace kdk; Widget::Widget(QWidget *parent) : QWidget(parent) { QVBoxLayout *mainLayout = new QVBoxLayout(this); QPushButton *btn1 = new QPushButton(); btn1->setText("无tag-正常背景"); QPushButton *btn2 = new QPushButton(); btn2->setText("无tag-高亮背景"); QPushButton *btn3 = new QPushButton(); btn3->setText("有tag-正常背景"); QPushButton *btn4 = new QPushButton(); btn4->setText("有tag-高亮背景"); KBubbleWidget *bubbleWidget1 = new KBubbleWidget(); bubbleWidget1->setTailPosition(TopDirection); QVBoxLayout *layout1 = new QVBoxLayout(bubbleWidget1); KTextEdit *edit1 = new KTextEdit(); QPushButton *button1 = new QPushButton(); button1->setText("关闭"); layout1->addWidget(edit1); layout1->addWidget(button1); connect(btn1, &QPushButton::clicked, this, [=] { bubbleWidget1->show(); }); connect(button1, &QPushButton::clicked, this, [=] { bubbleWidget1->hide(); }); KBubbleWidget *bubbleWidget2 = new KBubbleWidget(); bubbleWidget2->setTailPosition(RightDirection, TailLocation::LeftLocation); bubbleWidget2->setHighlightBackground(true); QVBoxLayout *layout2 = new QVBoxLayout(bubbleWidget2); KTextEdit *edit2 = new KTextEdit(); edit2->setReadOnly(true); edit2->setText("这是一段测试性文字,用来测试ktextedit在只读状态(不可编辑状态)下的背景色。"); QPushButton *button2 = new QPushButton(); button2->setText("关闭"); layout2->addWidget(edit2); layout2->addWidget(button2); connect(btn2, &QPushButton::clicked, this, [=] { bubbleWidget2->show(); }); connect(button2, &QPushButton::clicked, this, [=] { bubbleWidget2->hide(); }); KBubbleWidget *bubbleWidget3 = new KBubbleWidget(); bubbleWidget3->setTailPosition(BottomDirection, TailLocation::RightLocation); QVBoxLayout *layout3 = new QVBoxLayout(bubbleWidget3); KTextEdit *edit3 = new KTextEdit(); edit3->setLabelVisible(true); edit3->setPixmap(QIcon("system-computer-symbolic").pixmap(16, 16)); edit3->setLabelText("翻译"); QPushButton *button3 = new QPushButton(); button3->setText("关闭"); layout3->addWidget(edit3); layout3->addWidget(button3); connect(btn3, &QPushButton::clicked, this, [=] { bubbleWidget3->show(); }); connect(button3, &QPushButton::clicked, this, [=] { bubbleWidget3->hide(); }); KBubbleWidget *bubbleWidget4 = new KBubbleWidget(); bubbleWidget4->setTailPosition(LeftDirection, TailLocation::RightLocation); bubbleWidget4->setHighlightBackground(true); QVBoxLayout *layout4 = new QVBoxLayout(bubbleWidget4); KTextEdit *edit4 = new KTextEdit(); edit4->setLabelVisible(true); edit4->setPixmap(QIcon("system-computer-symbolic").pixmap(16, 16)); edit4->setLabelText("翻译"); edit4->setText("这是一段测试性文字,用来测试ktextedit在只读状态(不可编辑状态)下的背景色。"); edit4->setReadOnly(true); QPushButton *button4 = new QPushButton(); button4->setText("关闭"); QPushButton *button5 = new QPushButton(); button5->setText("切换是否可编辑状态"); layout4->addWidget(edit4); layout4->addWidget(button4); layout4->addWidget(button5); connect(btn4, &QPushButton::clicked, this, [=] { bubbleWidget4->show(); }); connect(button4, &QPushButton::clicked, this, [=] { bubbleWidget4->hide(); }); connect(button5, &QPushButton::clicked, this, [=] { if (edit4->isReadOnly()) { edit4->setReadOnly(false); bubbleWidget4->setHighlightBackground(false); } else { edit4->setReadOnly(true); bubbleWidget4->setHighlightBackground(true); } }); QHBoxLayout *hlayout1 = new QHBoxLayout(); QHBoxLayout *hlayout2 = new QHBoxLayout(); hlayout1->addWidget(btn1); hlayout1->addWidget(btn2); hlayout2->addWidget(btn3); hlayout2->addWidget(btn4); mainLayout->addLayout(hlayout1); mainLayout->addLayout(hlayout2); } Widget::~Widget() { } libkysdk-applications/kysdk-qtwidgets/test/testKTextedit/main.cpp0000664000175000017500000000165015104543305024354 0ustar fengfeng/* * * Copyright (C) 2024, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhenyu Wang * */ #include "widget.h" #include int main(int argc, char *argv[]) { QApplication a(argc, argv); Widget w; w.show(); return a.exec(); } libkysdk-applications/kysdk-qtwidgets/test/testKTextedit/testKTextedit.pro0000664000175000017500000000200115104543305026242 0ustar fengfengQT += core gui greaterThan(QT_MAJOR_VERSION, 4): QT += widgets CONFIG += c++17 CONFIG += link_pkgconfig PKGCONFIG += kysdk-widgetutils kysdk-qtwidgets # The following define makes your compiler emit warnings if you use # any Qt feature that has been marked deprecated (the exact warnings # depend on your compiler). Please consult the documentation of the # deprecated API in order to know how to port your code away from it. DEFINES += QT_DEPRECATED_WARNINGS # You can also make your code fail to compile if it uses deprecated APIs. # In order to do so, uncomment the following line. # You can also select to disable deprecated APIs only up to a certain version of Qt. #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 SOURCES += \ main.cpp \ widget.cpp HEADERS += \ widget.h # Default rules for deployment. qnx: target.path = /tmp/$${TARGET}/bin else: unix:!android: target.path = /opt/$${TARGET}/bin !isEmpty(target.path): INSTALLS += target libkysdk-applications/kysdk-qtwidgets/test/testListWidget/0000775000175000017500000000000015104543305023074 5ustar fengfenglibkysdk-applications/kysdk-qtwidgets/test/testListWidget/testListWidget.pro0000664000175000017500000000200115104543305026566 0ustar fengfengQT += core gui greaterThan(QT_MAJOR_VERSION, 4): QT += widgets CONFIG += c++17 CONFIG += link_pkgconfig PKGCONFIG += kysdk-qtwidgets kysdk-widgetutils # The following define makes your compiler emit warnings if you use # any Qt feature that has been marked deprecated (the exact warnings # depend on your compiler). Please consult the documentation of the # deprecated API in order to know how to port your code away from it. DEFINES += QT_DEPRECATED_WARNINGS # You can also make your code fail to compile if it uses deprecated APIs. # In order to do so, uncomment the following line. # You can also select to disable deprecated APIs only up to a certain version of Qt. #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 SOURCES += \ main.cpp \ widget.cpp HEADERS += \ widget.h # Default rules for deployment. qnx: target.path = /tmp/$${TARGET}/bin else: unix:!android: target.path = /opt/$${TARGET}/bin !isEmpty(target.path): INSTALLS += target libkysdk-applications/kysdk-qtwidgets/test/testListWidget/widget.h0000664000175000017500000000221415104543305024527 0ustar fengfeng/* * * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhenyu Wang * */ #ifndef WIDGET_H #define WIDGET_H #include "gui_g.h" #include "kitemwidget.h" #include "klistwidget.h" #include "kwidget.h" #include using namespace kdk; class Widget : public QWidget { Q_OBJECT public: Widget(QWidget *parent = nullptr); ~Widget(); private: KItemWidget *m_item; KItemWidget *m_item1; KListWidget *m_listwidget; }; #endif // WIDGET_H libkysdk-applications/kysdk-qtwidgets/test/testListWidget/widget.cpp0000664000175000017500000000360115104543305025063 0ustar fengfeng/* * * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhenyu Wang * */ #include "widget.h" #include using namespace kdk; Widget::Widget(QWidget *parent) : QWidget(parent) { QVBoxLayout *vlayout = new QVBoxLayout(this); m_listwidget = new KListWidget(this); this->setWindowTitle("test"); this->setWindowIcon(QIcon::fromTheme("kylin-music")); this->resize(800, 500); // KItemWidget 构造函数 KItemWidget(const QIcon &Myicon,QString MmainText,QString MsecText,QWidget *parent); // Myicon 需要显示的图片 MmainText 需要写入的miantext MsecText 需要写入的sectext m_item = new KItemWidget(QIcon::fromTheme("kylin-music"), QString("IMG202202121544.JPG"), QString("1.6MB"), m_listwidget); m_item1 = new KItemWidget(QIcon::fromTheme("kylin-music"), QString("IMG202202121544.JPG"), QString("1.5MB"), m_listwidget); KItemWidget *m_item2 = new KItemWidget(QIcon::fromTheme("kylin-music"), QString("IMG202202121544.JPG"), QString("1.5MB"), m_listwidget); m_listwidget->AddItemWidget(m_item); m_listwidget->AddItemWidget(m_item1); m_listwidget->AddItemWidget(m_item2); vlayout->addWidget(m_listwidget); } Widget::~Widget() { } libkysdk-applications/kysdk-qtwidgets/test/testListWidget/main.cpp0000664000175000017500000000255115104543305024527 0ustar fengfeng/* * * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhenyu Wang * */ #include "widget.h" #include "kwidgetutils.h" #include #include int main(int argc, char *argv[]) { kdk::KWidgetUtils::highDpiScaling(); QApplication a(argc, argv); QTranslator trans; QString locale = QLocale::system().name(); if (locale == "zh_CN") { if (trans.load(":/translations/gui_zh_CN.qm")) { a.installTranslator(&trans); } } if (locale == "bo_CN") { if (trans.load(":/translations/gui_bo_CN.qm")) { a.installTranslator(&trans); } } Widget w; w.show(); return a.exec(); } libkysdk-applications/kysdk-qtwidgets/test/testKButtonBox/0000775000175000017500000000000015104543305023054 5ustar fengfenglibkysdk-applications/kysdk-qtwidgets/test/testKButtonBox/widget.h0000664000175000017500000000167315104515306024517 0ustar fengfeng/* * * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #ifndef WIDGET_H #define WIDGET_H #include class Widget : public QWidget { Q_OBJECT public: Widget(QWidget *parent = nullptr); ~Widget(); }; #endif // WIDGET_H libkysdk-applications/kysdk-qtwidgets/test/testKButtonBox/testKButtonBox.pro0000664000175000017500000000175715104543305026547 0ustar fengfengQT += core gui greaterThan(QT_MAJOR_VERSION, 4): QT += widgets CONFIG += c++17 # The following define makes your compiler emit warnings if you use # any Qt feature that has been marked deprecated (the exact warnings # depend on your compiler). Please consult the documentation of the # deprecated API in order to know how to port your code away from it. DEFINES += QT_DEPRECATED_WARNINGS CONFIG += link_pkgconfig PKGCONFIG += kysdk-qtwidgets # You can also make your code fail to compile if it uses deprecated APIs. # In order to do so, uncomment the following line. # You can also select to disable deprecated APIs only up to a certain version of Qt. #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 SOURCES += \ main.cpp \ widget.cpp HEADERS += \ widget.h # Default rules for deployment. qnx: target.path = /tmp/$${TARGET}/bin else: unix:!android: target.path = /opt/$${TARGET}/bin !isEmpty(target.path): INSTALLS += target libkysdk-applications/kysdk-qtwidgets/test/testKButtonBox/widget.cpp0000664000175000017500000000641715104543305025053 0ustar fengfeng/* * * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #include "widget.h" #include "kbuttonbox.h" #include "kpushbutton.h" #include #include #include #include #include using namespace kdk; Widget::Widget(QWidget *parent) : QWidget(parent) { QVBoxLayout *layout = new QVBoxLayout(this); QHBoxLayout *layout1 = new QHBoxLayout; KButtonBox *box1 = new KButtonBox(this); KPushButton *btn1 = new KPushButton; btn1->setIcon(QIcon::fromTheme("list-add-symbolic")); btn1->setFixedSize(48, 48); btn1->setIconSize(QSize(32, 32)); KPushButton *btn2 = new KPushButton; btn2->setIcon(QIcon::fromTheme("list-remove-symbolic")); btn2->setFixedSize(48, 48); btn2->setIconSize(QSize(32, 32)); box1->addButton(btn1); box1->addButton(btn2); KButtonBox *box2 = new KButtonBox(this); KPushButton *btn3 = new KPushButton; btn3->setIcon(QIcon::fromTheme("list-add-symbolic")); btn3->setFixedSize(48, 48); btn3->setIconSize(QSize(32, 32)); KPushButton *btn4 = new KPushButton; btn4->setIcon(QIcon::fromTheme("list-remove-symbolic")); btn4->setFixedSize(48, 48); btn4->setIconSize(QSize(32, 32)); btn4->setEnabled(false); box2->addButton(btn3); box2->addButton(btn4); QHBoxLayout *layout2 = new QHBoxLayout; KButtonBox *box3 = new KButtonBox(this); KPushButton *btn5 = new KPushButton(this); btn5->setIcon(QIcon::fromTheme("system-computer-symbolic")); KPushButton *btn6 = new KPushButton(this); btn6->setIcon(QIcon::fromTheme("format-text-italic-symbolic")); KPushButton *btn7 = new KPushButton(this); btn7->setIcon(QIcon::fromTheme("format-text-underline-symbolic")); KPushButton *btn8 = new KPushButton(this); btn8->setIcon(QIcon::fromTheme("format-text-strikethrough-symbolic")); QList list; list.insert(0, btn5); list.insert(1, btn6); list.insert(2, btn7); list.insert(3, btn8); box3->setButtonList(list); box3->setCheckable(true); box3->setExclusive(false); KPushButton *btn = new KPushButton; btn->setText("New Button"); connect(box1, &KButtonBox::buttonClicked, this, [=](QAbstractButton *button) { if (btn1 == button) box3->addButton(btn); if (btn2 == button) box3->removeButton(btn); }); layout1->addWidget(box1); layout1->addWidget(box2); layout2->addWidget(box3); layout->addLayout(layout1); layout->addLayout(layout2); this->setLayout(layout); this->setFixedSize(500, 400); } Widget::~Widget() { } libkysdk-applications/kysdk-qtwidgets/test/testKButtonBox/main.cpp0000664000175000017500000000164615104515306024513 0ustar fengfeng/* * * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #include "widget.h" #include int main(int argc, char *argv[]) { QApplication a(argc, argv); Widget w; w.show(); return a.exec(); } libkysdk-applications/kysdk-qtwidgets/test/test.pro0000664000175000017500000000222015104543305021612 0ustar fengfengTEMPLATE = subdirs SUBDIRS += \ testAddFileButton \ testarrowtabbar \ testbadge \ testballontip \ testbreadcrumb \ testclocktimer \ testcolorbutton \ testcomboboxwidget \ testcrumb \ testDialog \ testFileWidget \ testinputdialog \ testintrowidget \ testkbackground \ testKBubbleWidget \ testKButtonBox \ testkcolorcombobox \ testKDirTabBar \ testKDragWidget \ testKLabel \ testKMessageBox \ testkpressbutton \ testKPushButton \ testksettinggroup \ testKTextedit \ testKTranslucentFloor \ testlineedit \ testListView \ testListWidget \ testloopplaypage \ testLunarDateEdit \ testnativetabbar \ testnavigationbar \ testnavigationtrail \ testpasswordedit \ testprogressbar \ testProgressCircle \ testprogressdialog \ testprogresslabel \ testPushbutton \ testsearchlinedit \ testsecuritylevelbar \ testsecurityquestiondialog \ testslider \ testSwitchButton \ testtabbar \ testtableview \ testTag \ testtitlewindow \ testtoolbutton \ testTranslucent \ testWidget libkysdk-applications/kysdk-qtwidgets/test/testbadge/0000775000175000017500000000000015104543305022057 5ustar fengfenglibkysdk-applications/kysdk-qtwidgets/test/testbadge/widget.h0000664000175000017500000000237715104543305023524 0ustar fengfeng/* * * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #ifndef WIDGET_H #define WIDGET_H #include "kbadge.h" #include "kpixmapcontainer.h" #include "kwidget.h" using namespace kdk; class Widget : public KWidget { Q_OBJECT public: Widget(QWidget *parent = nullptr); ~Widget(); private: KPixmapContainer *m_pContainer1; KPixmapContainer *m_pContainer2; KPixmapContainer *m_pContainer3; KPixmapContainer *m_pContainer4; KBadge *m_pBadge1; KBadge *m_pBadge2; KBadge *m_pBadge3; KBadge *m_pBadge4; }; #endif // WIDGET_H libkysdk-applications/kysdk-qtwidgets/test/testbadge/testbadge.pro0000664000175000017500000000200215104543305024535 0ustar fengfengQT += core gui greaterThan(QT_MAJOR_VERSION, 4): QT += widgets CONFIG += c++17 CONFIG += link_pkgconfig PKGCONFIG += kysdk-qtwidgets kysdk-widgetutils # The following define makes your compiler emit warnings if you use # any Qt feature that has been marked deprecated (the exact warnings # depend on your compiler). Please consult the documentation of the # deprecated API in order to know how to port your code away from it. DEFINES += QT_DEPRECATED_WARNINGS # You can also make your code fail to compile if it uses deprecated APIs. # In order to do so, uncomment the following line. # You can also select to disable deprecated APIs only up to a certain version of Qt. #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 SOURCES += \ main.cpp \ widget.cpp HEADERS += \ widget.h # Default rules for deployment. qnx: target.path = /tmp/$${TARGET}/bin else: unix:!android: target.path = /opt/$${TARGET}/bin !isEmpty(target.path): INSTALLS += target libkysdk-applications/kysdk-qtwidgets/test/testbadge/widget.cpp0000664000175000017500000000631715104543305024055 0ustar fengfeng/* * * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #include "widget.h" #include #include #include Widget::Widget(QWidget *parent) : KWidget(parent) { QVBoxLayout *vLayout = new QVBoxLayout(this); QHBoxLayout *hLayout = new QHBoxLayout(); m_pContainer1 = new KPixmapContainer(this); m_pContainer1->setPixmap(QIcon::fromTheme("edit-find-symbolic").pixmap(16, 16)); m_pContainer1->setFontSize(8); m_pContainer1->setColor(QColor(255, 0, 0)); // 设置背景色 m_pContainer2 = new KPixmapContainer(this); m_pContainer2->setPixmap(QIcon::fromTheme("edit-find-symbolic").pixmap(24, 24)); m_pContainer2->setFontSize(10); m_pContainer2->setValue(99); // 设置值 m_pContainer2->setValueVisiable(false); // 设置值不可见 m_pContainer3 = new KPixmapContainer(this); m_pContainer3->setPixmap(QIcon::fromTheme("edit-find-symbolic").pixmap(36, 36)); m_pContainer3->setFontSize(10); m_pContainer3->setValue(999); m_pContainer4 = new KPixmapContainer(this); m_pContainer4->setPixmap(QIcon::fromTheme("edit-find-symbolic").pixmap(48, 48)); m_pContainer4->setFontSize(12); // 设置字体大小 m_pContainer4->setValue(1000); hLayout->addWidget(m_pContainer1); hLayout->addWidget(m_pContainer2); hLayout->addWidget(m_pContainer3); hLayout->addWidget(m_pContainer4); vLayout->addStretch(); vLayout->addLayout(hLayout); QLabel *label = new QLabel("调整badge3大小:", this); QSpinBox *spinBox = new QSpinBox(this); spinBox->setValue(m_pContainer3->fontSize()); connect(spinBox, static_cast(&QSpinBox::valueChanged), this, [=](int i) { m_pContainer3->setFontSize(spinBox->value()); }); hLayout = new QHBoxLayout(); hLayout->addStretch(); hLayout->addWidget(label); hLayout->addWidget(spinBox); hLayout->addStretch(); vLayout->addLayout(hLayout); m_pBadge1 = new KBadge(this); m_pBadge1->setValue(0); m_pBadge2 = new KBadge(this); m_pBadge2->setValue(99); // m_pBadge2->setValueVisiable(false); m_pBadge3 = new KBadge(this); m_pBadge3->setValue(999); m_pBadge4 = new KBadge(this); m_pBadge4->setValue(1000); hLayout = new QHBoxLayout(this); hLayout->addWidget(m_pBadge1); hLayout->addWidget(m_pBadge2); hLayout->addWidget(m_pBadge3); hLayout->addWidget(m_pBadge4); vLayout->addLayout(hLayout); vLayout->addStretch(); baseBar()->setLayout(vLayout); } Widget::~Widget() { } libkysdk-applications/kysdk-qtwidgets/test/testbadge/main.cpp0000664000175000017500000000254315104543305023513 0ustar fengfeng/* * * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #include "kwidgetutils.h" #include "widget.h" #include #include int main(int argc, char *argv[]) { kdk::KWidgetUtils::highDpiScaling(); QApplication a(argc, argv); QTranslator trans; QString locale = QLocale::system().name(); if (locale == "zh_CN") { if (trans.load(":/translations/gui_zh_CN.qm")) { a.installTranslator(&trans); } } if (locale == "bo_CN") { if (trans.load(":/translations/gui_bo_CN.qm")) { a.installTranslator(&trans); } } Widget w; w.show(); return a.exec(); } libkysdk-applications/kysdk-qtwidgets/test/testcolorbutton/0000775000175000017500000000000015104543305023367 5ustar fengfenglibkysdk-applications/kysdk-qtwidgets/test/testcolorbutton/widget.h0000664000175000017500000000174315104515306025030 0ustar fengfeng/* * * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #ifndef WIDGET_H #define WIDGET_H #include "kwidget.h" #include using namespace kdk; class Widget : public QWidget { Q_OBJECT public: Widget(QWidget *parent = nullptr); ~Widget(); }; #endif // WIDGET_H libkysdk-applications/kysdk-qtwidgets/test/testcolorbutton/testcolorbutton.pro0000664000175000017500000000175715104543305027375 0ustar fengfengQT += core gui greaterThan(QT_MAJOR_VERSION, 4): QT += widgets CONFIG += c++17 # The following define makes your compiler emit warnings if you use # any Qt feature that has been marked deprecated (the exact warnings # depend on your compiler). Please consult the documentation of the # deprecated API in order to know how to port your code away from it. DEFINES += QT_DEPRECATED_WARNINGS CONFIG += link_pkgconfig PKGCONFIG += kysdk-qtwidgets # You can also make your code fail to compile if it uses deprecated APIs. # In order to do so, uncomment the following line. # You can also select to disable deprecated APIs only up to a certain version of Qt. #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 SOURCES += \ main.cpp \ widget.cpp HEADERS += \ widget.h # Default rules for deployment. qnx: target.path = /tmp/$${TARGET}/bin else: unix:!android: target.path = /opt/$${TARGET}/bin !isEmpty(target.path): INSTALLS += target libkysdk-applications/kysdk-qtwidgets/test/testcolorbutton/widget.cpp0000664000175000017500000000776215104543305025372 0ustar fengfeng/* * * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #include "widget.h" #include "kcolorbutton.h" #include #include #include using namespace kdk; Widget::Widget(QWidget *parent) : QWidget(parent) { QVBoxLayout *vlayout = new QVBoxLayout(this); QHBoxLayout *hlayout = new QHBoxLayout(); QHBoxLayout *hlayout1 = new QHBoxLayout(); KColorButton *btn1 = new KColorButton(); KColorButton *btn2 = new KColorButton(); btn2->setBackgroundColor(Qt::cyan); KColorButton *btn3 = new KColorButton(); btn3->setBackgroundColor(Qt::darkYellow); KColorButton *btn4 = new KColorButton(); btn4->setBackgroundColor(Qt::red); KColorButton *btn5 = new KColorButton(); btn5->setBackgroundColor(Qt::gray); btn5->setButtonType(KColorButton::CheckedRect); KColorButton *btn6 = new KColorButton(); btn6->setBackgroundColor(Qt::green); btn6->setButtonType(KColorButton::CheckedRect); KColorButton *btn7 = new KColorButton(); btn7->setBackgroundColor(Qt::darkCyan); btn7->setButtonType(KColorButton::CheckedRect); KColorButton *btn8 = new KColorButton(); btn8->setBackgroundColor(Qt::darkRed); btn8->setButtonType(KColorButton::CheckedRect); QButtonGroup *group = new QButtonGroup(this); group->addButton(btn1); group->addButton(btn2); group->addButton(btn3); group->addButton(btn4); group->addButton(btn5); group->addButton(btn6); group->addButton(btn7); group->addButton(btn8); group->setExclusive(false); // 方形按钮是否可以多选 false为可以多选 // 方形第一行 hlayout->addStretch(); hlayout->setSpacing(10); hlayout->addWidget(btn1); hlayout->addWidget(btn2); hlayout->addWidget(btn3); hlayout->addWidget(btn4); hlayout->addStretch(); // 方形第二行 hlayout1->addStretch(); hlayout1->setSpacing(10); hlayout1->addWidget(btn5); hlayout1->addWidget(btn6); hlayout1->addWidget(btn7); hlayout1->addWidget(btn8); hlayout1->addStretch(); // 圆形 KColorButton *btn9 = new KColorButton(); btn9->setBackgroundColor(Qt::gray); btn9->setButtonType(KColorButton::Circle); KColorButton *btn10 = new KColorButton(); btn10->setBackgroundColor(Qt::green); btn10->setButtonType(KColorButton::Circle); KColorButton *btn11 = new KColorButton(); btn11->setBackgroundColor(Qt::darkCyan); btn11->setButtonType(KColorButton::Circle); KColorButton *btn12 = new KColorButton(); btn12->setBackgroundColor(Qt::darkRed); btn12->setButtonType(KColorButton::Circle); QButtonGroup *group1 = new QButtonGroup(this); group1->addButton(btn9); group1->addButton(btn10); group1->addButton(btn11); group1->addButton(btn12); group1->setExclusive(false); // 圆形形按钮是否可以多选 false为可以多选 QHBoxLayout *hlayout2 = new QHBoxLayout(); hlayout2->addStretch(); hlayout2->addWidget(btn9); hlayout2->addWidget(btn10); hlayout2->addWidget(btn11); hlayout2->addWidget(btn12); hlayout2->addStretch(); vlayout->addLayout(hlayout); vlayout->addLayout(hlayout1); vlayout->addLayout(hlayout2); // vlayout->setSizeConstraint(QLayout::SizeConstraint::SetFixedSize); this->setFixedSize(300, 240); } Widget::~Widget() { } libkysdk-applications/kysdk-qtwidgets/test/testcolorbutton/main.cpp0000664000175000017500000000164615104515306025026 0ustar fengfeng/* * * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #include "widget.h" #include int main(int argc, char *argv[]) { QApplication a(argc, argv); Widget w; w.show(); return a.exec(); } libkysdk-applications/kysdk-qtwidgets/test/testnativetabbar/0000775000175000017500000000000015104543305023457 5ustar fengfenglibkysdk-applications/kysdk-qtwidgets/test/testnativetabbar/widget.h0000664000175000017500000000167515104543305025124 0ustar fengfeng/* * * Copyright (C) 2024, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhenyu Wang * */ #ifndef WIDGET_H #define WIDGET_H #include class Widget : public QWidget { Q_OBJECT public: Widget(QWidget *parent = nullptr); ~Widget(); }; #endif // WIDGET_H libkysdk-applications/kysdk-qtwidgets/test/testnativetabbar/testnativetabbar.pro0000664000175000017500000000200015104543305027533 0ustar fengfengQT += core gui greaterThan(QT_MAJOR_VERSION, 4): QT += widgets CONFIG += c++17 CONFIG += link_pkgconfig PKGCONFIG += kysdk-qtwidgets kysdk-widgetutils # The following define makes your compiler emit warnings if you use # any Qt feature that has been marked deprecated (the exact warnings # depend on your compiler). Please consult the documentation of the # deprecated API in order to know how to port your code away from it. DEFINES += QT_DEPRECATED_WARNINGS # You can also make your code fail to compile if it uses deprecated APIs. # In order to do so, uncomment the following line. # You can also select to disable deprecated APIs only up to a certain version of Qt. #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 SOURCES += \ main.cpp \ widget.cpp HEADERS += \ widget.h # Default rules for deployment. qnx: target.path = /tmp/$${TARGET}/bin else: unix:!android: target.path = /opt/$${TARGET}/bin !isEmpty(target.path): INSTALLS += target libkysdk-applications/kysdk-qtwidgets/test/testnativetabbar/widget.cpp0000664000175000017500000001020015104543305025437 0ustar fengfeng/* * * Copyright (C) 2024, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhenyu Wang * */ #include "widget.h" #include "knativetabbar.h" #include #include #include using namespace kdk; Widget::Widget(QWidget *parent) : QWidget(parent) { QWidget *w = new QWidget(); KNativeTabbar *tabBar1 = new KNativeTabbar(KNativeTabbarStyle::SegmentLight, w); tabBar1->addTab(QIcon::fromTheme("kylin-music"), "Segment1"); tabBar1->addTab("Segment2"); tabBar1->addTab(QIcon::fromTheme("kylin-music"), ""); tabBar1->addTab("Segment4"); tabBar1->addTab("Segment5"); tabBar1->addTab("Segment6"); KNativeTabbar *tabBar2 = new KNativeTabbar(KNativeTabbarStyle::SegmentDark, w); tabBar2->addTab("SegmentDark1"); tabBar2->addTab("SegmentDark2"); tabBar2->addTab(QIcon::fromTheme("kylin-music"), "SegmentDark3"); tabBar2->addTab("SegmentDark4"); tabBar2->addTab("SegmentDark5"); tabBar2->addTab(QIcon::fromTheme("kylin-music"), ""); KNativeTabbar *tabBar3 = new KNativeTabbar(KNativeTabbarStyle::Sliding, w); tabBar3->addTab(QIcon::fromTheme("ukui-dialog-success"), "正常"); tabBar3->addTab(QIcon::fromTheme("dialog-warning"), "错误"); tabBar3->addTab(QIcon::fromTheme("dialog-info"), "注意"); tabBar3->addTab(QIcon::fromTheme("kylin-music"), "Sliding4"); tabBar3->addTab("Sliding5"); tabBar3->addTab(QIcon::fromTheme("kylin-music"), "Sliding6"); // tabBar3->setIconSize(QSize(24,24)); KNativeTabbar *tabBar4 = new KNativeTabbar(KNativeTabbarStyle::Sliding, w); tabBar4->addTab("Segment1"); tabBar4->addTab("Segment2"); tabBar4->addTab("Segment3"); tabBar4->addTab("Segment4"); tabBar4->setTabbarStyle(KNativeTabbarStyle::SegmentDark); // 设置style tabBar4->setBorderRadius(10); // 设置圆角半径,只对SegmentDark,SegmentLight样式生效 tabBar4->setBackgroundColor(QColor(0, 255, 0)); // 设置背景色 QLabel *pLabel = new QLabel(w); pLabel->setAlignment(Qt::AlignCenter); QMenu *menu = new QMenu(); QAction *action1 = new QAction("action1", menu); QAction *action2 = new QAction("action2", menu); QAction *action3 = new QAction("action3", menu); menu->addAction(action1); menu->addAction(action2); menu->addAction(action3); connect(tabBar1, &KNativeTabbar::tabBarClicked, this, [=](int index) { pLabel->setText(tabBar1->tabText(index)); }); connect(tabBar2, &KNativeTabbar::tabBarClicked, this, [=](int index) { pLabel->setText(tabBar2->tabText(index)); }); connect(tabBar3, &KNativeTabbar::tabBarClicked, this, [=](int index) { pLabel->setText(tabBar3->tabText(index)); }); connect(tabBar4, &KNativeTabbar::tabBarClicked, this, [=](int index) { pLabel->setText(tabBar4->tabText(index)); }); connect(tabBar4, &KNativeTabbar::rightlicked, this, [=](QPoint point) { menu->move(point); menu->show(); }); QHBoxLayout *hlayout = new QHBoxLayout(); QLabel *label = new QLabel(); label->setText("just a test label"); hlayout->addWidget(label); QVBoxLayout *vLayout = new QVBoxLayout; vLayout->addStretch(); vLayout->addWidget(tabBar1); vLayout->addWidget(tabBar2); vLayout->addWidget(tabBar3); vLayout->addWidget(tabBar4); vLayout->addStretch(); vLayout->addWidget(pLabel); vLayout->addStretch(); vLayout->addLayout(hlayout); vLayout->addStretch(); setLayout(vLayout); } Widget::~Widget() { } libkysdk-applications/kysdk-qtwidgets/test/testnativetabbar/main.cpp0000664000175000017500000000165015104543305025111 0ustar fengfeng/* * * Copyright (C) 2024, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhenyu Wang * */ #include "widget.h" #include int main(int argc, char *argv[]) { QApplication a(argc, argv); Widget w; w.show(); return a.exec(); } libkysdk-applications/kysdk-qtwidgets/test/testIcon/0000775000175000017500000000000015104543305021705 5ustar fengfenglibkysdk-applications/kysdk-qtwidgets/test/testIcon/widget.h0000664000175000017500000000027115104543305023341 0ustar fengfeng#ifndef WIDGET_H #define WIDGET_H #include class Widget : public QWidget { Q_OBJECT public: Widget(QWidget *parent = nullptr); ~Widget(); }; #endif // WIDGET_H libkysdk-applications/kysdk-qtwidgets/test/testIcon/testIcon.pro0000664000175000017500000000113715104543305024221 0ustar fengfengQT += core gui greaterThan(QT_MAJOR_VERSION, 4): QT += widgets CONFIG += c++17 CONFIG += link_pkgconfig PKGCONFIG += kysdk-qtwidgets # You can make your code fail to compile if it uses deprecated APIs. # In order to do so, uncomment the following line. #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 SOURCES += \ main.cpp \ widget.cpp HEADERS += \ widget.h # Default rules for deployment. qnx: target.path = /tmp/$${TARGET}/bin else: unix:!android: target.path = /opt/$${TARGET}/bin !isEmpty(target.path): INSTALLS += target libkysdk-applications/kysdk-qtwidgets/test/testIcon/widget.cpp0000664000175000017500000000130415104543305023672 0ustar fengfeng#include "widget.h" #include "kwidget.h" #include "themeController.h" #include #include #include // using namespace kdk; Widget::Widget(QWidget *parent) : QWidget(parent) { QHBoxLayout *layout = new QHBoxLayout(this); QPushButton *btn = new QPushButton(); QIcon icon1 = QIcon::fromTheme("kylin-music"); QIcon icon2 = QIcon::fromTheme("kylin-video"); btn->setIcon(ThemeController::overlayIcons(icon1, icon2, 16, 16, 8, 8)); QLabel *label = new QLabel(); label->setPixmap(ThemeController::overlayPixmaps(icon2.pixmap(24, 24), icon1.pixmap(16, 16), 8, 8)); layout->addWidget(btn); layout->addWidget(label); } Widget::~Widget() { } libkysdk-applications/kysdk-qtwidgets/test/testIcon/main.cpp0000664000175000017500000000024415104543305023335 0ustar fengfeng#include "widget.h" #include int main(int argc, char *argv[]) { QApplication a(argc, argv); Widget w; w.show(); return a.exec(); } libkysdk-applications/kysdk-qtwidgets/test/testKDirTabBar/0000775000175000017500000000000015104543305022722 5ustar fengfenglibkysdk-applications/kysdk-qtwidgets/test/testKDirTabBar/testKDirTabBar.pro0000664000175000017500000000200115104543305026242 0ustar fengfengQT += core gui greaterThan(QT_MAJOR_VERSION, 4): QT += widgets CONFIG += c++17 CONFIG += link_pkgconfig PKGCONFIG += kysdk-widgetutils kysdk-qtwidgets # The following define makes your compiler emit warnings if you use # any Qt feature that has been marked deprecated (the exact warnings # depend on your compiler). Please consult the documentation of the # deprecated API in order to know how to port your code away from it. DEFINES += QT_DEPRECATED_WARNINGS # You can also make your code fail to compile if it uses deprecated APIs. # In order to do so, uncomment the following line. # You can also select to disable deprecated APIs only up to a certain version of Qt. #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 SOURCES += \ main.cpp \ widget.cpp HEADERS += \ widget.h # Default rules for deployment. qnx: target.path = /tmp/$${TARGET}/bin else: unix:!android: target.path = /opt/$${TARGET}/bin !isEmpty(target.path): INSTALLS += target libkysdk-applications/kysdk-qtwidgets/test/testKDirTabBar/widget.h0000664000175000017500000000050315104543305024354 0ustar fengfeng#ifndef WIDGET_H #define WIDGET_H #include "kdirtabbar.h" #include "widget.h" #include class Widget : public QWidget { Q_OBJECT public: Widget(QWidget *parent = nullptr); ~Widget(); void getchildFolds(const QString &foldPath, QStringList &folds, QStringList &foldsName); }; #endif // WIDGET_H libkysdk-applications/kysdk-qtwidgets/test/testKDirTabBar/widget.cpp0000664000175000017500000000356315104543305024720 0ustar fengfeng#include "widget.h" #include "kdirtabbar.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace kdk; Widget::Widget(QWidget *parent) : QWidget(parent) { KDirTabBar *bar = new KDirTabBar(this); QVBoxLayout *myLayout = new QVBoxLayout(); QFileDialog *fileDialog = new QFileDialog(this); ; QPushButton *button1 = new QPushButton("open files", this); QLabel *label = new QLabel(); QString path = QDir::currentPath(); QFileInfo fileInfo(path); QList btns; KDirTabBar *bar2 = new KDirTabBar(this); bar->setCurrentPath(fileInfo.absoluteFilePath()); label->setText(bar->currentPath()); btns = bar->buttons(); btns[btns.count() - 1]->setIcon(QIcon()); // 设置按钮的图标 btns[btns.count() - 2]->setEnabled(false); // 设置按钮是否可用 bar->setIcon(btns.count() - 2, QIcon::fromTheme("folder-pictures")); // 设置按钮的图标 connect(bar, &KDirTabBar::tabBarClicked, [=]() { label->setText(bar->currentPath()); }); connect(button1, &QPushButton::clicked, [=] { fileDialog->setDirectory(QStandardPaths::writableLocation(QStandardPaths::HomeLocation)); fileDialog->setFileMode(QFileDialog::ExistingFiles); bar2->setCurrentPath(fileDialog->getExistingDirectory()); }); setLayout(myLayout); myLayout->addWidget(bar); myLayout->addStretch(); myLayout->addWidget(label); myLayout->addStretch(); myLayout->addWidget(button1); myLayout->addStretch(); myLayout->addWidget(bar2); myLayout->addStretch(); } Widget::~Widget() { } libkysdk-applications/kysdk-qtwidgets/test/testKDirTabBar/main.cpp0000664000175000017500000000024415104543305024352 0ustar fengfeng#include "widget.h" #include int main(int argc, char *argv[]) { QApplication a(argc, argv); Widget w; w.show(); return a.exec(); } libkysdk-applications/kysdk-qtwidgets/test/testKMessageBox/0000775000175000017500000000000015104543305023165 5ustar fengfenglibkysdk-applications/kysdk-qtwidgets/test/testKMessageBox/widget.h0000664000175000017500000000167315104515306024630 0ustar fengfeng/* * * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #ifndef WIDGET_H #define WIDGET_H #include class Widget : public QWidget { Q_OBJECT public: Widget(QWidget *parent = nullptr); ~Widget(); }; #endif // WIDGET_H libkysdk-applications/kysdk-qtwidgets/test/testKMessageBox/testKMessageBox.pro0000664000175000017500000000200115104543305026750 0ustar fengfengQT += core gui greaterThan(QT_MAJOR_VERSION, 4): QT += widgets CONFIG += c++17 # The following define makes your compiler emit warnings if you use # any Qt feature that has been marked deprecated (the exact warnings # depend on your compiler). Please consult the documentation of the # deprecated API in order to know how to port your code away from it. DEFINES += QT_DEPRECATED_WARNINGS CONFIG += link_pkgconfig PKGCONFIG += kysdk-widgetutils kysdk-qtwidgets # You can also make your code fail to compile if it uses deprecated APIs. # In order to do so, uncomment the following line. # You can also select to disable deprecated APIs only up to a certain version of Qt. #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 SOURCES += \ main.cpp \ widget.cpp HEADERS += \ widget.h # Default rules for deployment. qnx: target.path = /tmp/$${TARGET}/bin else: unix:!android: target.path = /opt/$${TARGET}/bin !isEmpty(target.path): INSTALLS += target libkysdk-applications/kysdk-qtwidgets/test/testKMessageBox/widget.cpp0000664000175000017500000000426215104543305025160 0ustar fengfeng/* * * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #include "widget.h" #include "kmessagebox.h" #include #include using namespace kdk; Widget::Widget(QWidget *parent) : QWidget(parent) { QVBoxLayout *layout = new QVBoxLayout; QPushButton *btn_1 = new QPushButton(this); btn_1->setText("TestDemoOne"); QObject::connect(btn_1, &QPushButton::clicked, this, [=]() { KMessageBox w; w.setCustomIcon(QIcon::fromTheme("dialog-error")); w.setText("打印测试失败,建议修改驱动后重试"); QPushButton *btn1 = new QPushButton("修改驱动"); QPushButton *btn2 = new QPushButton("取消"); w.addButton(btn1, KMessageBox::YesRole); w.addButton(btn2, KMessageBox::NoRole); w.exec(); }); QPushButton *btn_2 = new QPushButton(this); btn_2->setText("TestDemoTwo"); QObject::connect(btn_2, &QPushButton::clicked, this, [=]() { KMessageBox w; w.setCustomIcon(QIcon::fromTheme("ukui-dialog-success")); w.setText("添加成功,是否打印测试页?"); QPushButton *btn1 = new QPushButton("打印测试页"); QPushButton *btn2 = new QPushButton("查看设备"); w.addButton(btn1, KMessageBox::YesRole); w.addButton(btn2, KMessageBox::NoRole); w.exec(); }); layout->addWidget(btn_1); layout->addWidget(btn_2); this->setLayout(layout); this->setFixedSize(300, 200); } Widget::~Widget() { } libkysdk-applications/kysdk-qtwidgets/test/testKMessageBox/main.cpp0000664000175000017500000000254315104543305024621 0ustar fengfeng/* * * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #include "kwidgetutils.h" #include "widget.h" #include #include int main(int argc, char *argv[]) { kdk::KWidgetUtils::highDpiScaling(); QApplication a(argc, argv); QTranslator trans; QString locale = QLocale::system().name(); if (locale == "zh_CN") { if (trans.load(":/translations/gui_zh_CN.qm")) { a.installTranslator(&trans); } } if (locale == "bo_CN") { if (trans.load(":/translations/gui_bo_CN.qm")) { a.installTranslator(&trans); } } Widget w; w.show(); return a.exec(); } libkysdk-applications/kysdk-qtwidgets/test/testintrowidget/0000775000175000017500000000000015104543305023354 5ustar fengfenglibkysdk-applications/kysdk-qtwidgets/test/testintrowidget/widget.h0000664000175000017500000000167515104543305025021 0ustar fengfeng/* * * Copyright (C) 2024, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhenyu Wang * */ #ifndef WIDGET_H #define WIDGET_H #include class Widget : public QWidget { Q_OBJECT public: Widget(QWidget *parent = nullptr); ~Widget(); }; #endif // WIDGET_H libkysdk-applications/kysdk-qtwidgets/test/testintrowidget/widget.cpp0000664000175000017500000000504715104543305025351 0ustar fengfeng/* * * Copyright (C) 2024, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhenyu Wang * */ #include "widget.h" #include "kintrowidget.h" #include #include using namespace kdk; Widget::Widget(QWidget *parent) : QWidget(parent) { QVBoxLayout *layout = new QVBoxLayout(this); KIntroWidget *widget1 = new KIntroWidget(this); widget1->setMainLabel("我是一段测试文本,测试显示不全是否可以换行(单行测试文本)"); widget1->setSubLabel("2024216161"); widget1->setFixedHeight(76); widget1->setBorderRadius(15); KIntroWidget *widget2 = new KIntroWidget(this); widget2->setMainLabel("我是一段测试文本,测试换行符号\n('\\n'不显示只换行)是否可以正常换行以及显示不全是否可以换行"); widget2->setSubLabel("2024216161"); widget2->setViewType(ViewType::IconView); widget2->setFixedSize(218, 200); widget2->setTitleColor(Qt::red); widget2->setBorderRadius(0, 20, 20, 30); layout->addWidget(widget1); layout->addWidget(widget2); QMenu *menu = new QMenu(); QAction *action1 = new QAction("action1", menu); QAction *action2 = new QAction("action2", menu); QAction *action3 = new QAction("action3", menu); menu->addAction(action1); menu->addAction(action2); menu->addAction(action3); connect(widget1, &KIntroWidget::rightClick, this, [=](QPoint point) { menu->move(point); menu->show(); }); QMenu *menu1 = new QMenu(); QAction *action4 = new QAction("action4", menu); QAction *action5 = new QAction("action5", menu); QAction *action6 = new QAction("action6", menu); menu1->addAction(action4); menu1->addAction(action5); menu1->addAction(action6); connect(widget2, &KIntroWidget::rightClick, this, [=](QPoint point) { menu1->move(point); menu1->show(); }); } Widget::~Widget() { } libkysdk-applications/kysdk-qtwidgets/test/testintrowidget/main.cpp0000664000175000017500000000165015104543305025006 0ustar fengfeng/* * * Copyright (C) 2024, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhenyu Wang * */ #include "widget.h" #include int main(int argc, char *argv[]) { QApplication a(argc, argv); Widget w; w.show(); return a.exec(); } libkysdk-applications/kysdk-qtwidgets/test/testintrowidget/testintrowidget.pro0000664000175000017500000000200115104543305027326 0ustar fengfengQT += core gui greaterThan(QT_MAJOR_VERSION, 4): QT += widgets CONFIG += c++17 CONFIG += link_pkgconfig PKGCONFIG += kysdk-widgetutils kysdk-qtwidgets # The following define makes your compiler emit warnings if you use # any Qt feature that has been marked deprecated (the exact warnings # depend on your compiler). Please consult the documentation of the # deprecated API in order to know how to port your code away from it. DEFINES += QT_DEPRECATED_WARNINGS # You can also make your code fail to compile if it uses deprecated APIs. # In order to do so, uncomment the following line. # You can also select to disable deprecated APIs only up to a certain version of Qt. #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 SOURCES += \ main.cpp \ widget.cpp HEADERS += \ widget.h # Default rules for deployment. qnx: target.path = /tmp/$${TARGET}/bin else: unix:!android: target.path = /opt/$${TARGET}/bin !isEmpty(target.path): INSTALLS += target libkysdk-applications/kysdk-qtwidgets/test/testballontip/0000775000175000017500000000000015104543305023001 5ustar fengfenglibkysdk-applications/kysdk-qtwidgets/test/testballontip/widget.h0000664000175000017500000000234215104543305024436 0ustar fengfeng/* * * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #ifndef WIDGET_H #define WIDGET_H #include "kballontip.h" #include "kwidget.h" #include using namespace kdk; class Widget : public KWidget { Q_OBJECT public: Widget(QWidget *parent = nullptr); ~Widget(); private: // Nothing KBallonTip *m_pNothingTip; // Normal KBallonTip *m_pNormalTip; // Info KBallonTip *m_pInfoTip; // Warning KBallonTip *m_pWarningTip; // Error KBallonTip *m_pErrorTip; }; #endif // WIDGET_H libkysdk-applications/kysdk-qtwidgets/test/testballontip/testballontip.pro0000664000175000017500000000200115104543305026400 0ustar fengfengQT += core gui greaterThan(QT_MAJOR_VERSION, 4): QT += widgets CONFIG += c++17 CONFIG += link_pkgconfig PKGCONFIG += kysdk-qtwidgets kysdk-widgetutils # The following define makes your compiler emit warnings if you use # any Qt feature that has been marked deprecated (the exact warnings # depend on your compiler). Please consult the documentation of the # deprecated API in order to know how to port your code away from it. DEFINES += QT_DEPRECATED_WARNINGS # You can also make your code fail to compile if it uses deprecated APIs. # In order to do so, uncomment the following line. # You can also select to disable deprecated APIs only up to a certain version of Qt. #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 SOURCES += \ main.cpp \ widget.cpp HEADERS += \ widget.h # Default rules for deployment. qnx: target.path = /tmp/$${TARGET}/bin else: unix:!android: target.path = /opt/$${TARGET}/bin !isEmpty(target.path): INSTALLS += target libkysdk-applications/kysdk-qtwidgets/test/testballontip/widget.cpp0000664000175000017500000001104315104543305024767 0ustar fengfeng/* * * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #include "widget.h" #include #include Widget::Widget(QWidget *parent) : KWidget(parent) { QVBoxLayout *vLayout = new QVBoxLayout(); QPushButton *button = new QPushButton(this); button->setText("NothingTip"); QPushButton *button1 = new QPushButton(this); button1->setText("NormalTip"); QPushButton *button2 = new QPushButton(this); button2->setText("InfoTip"); QPushButton *button3 = new QPushButton(this); button3->setText("WarningTip"); QPushButton *button4 = new QPushButton(this); button4->setText("ErrorTip"); vLayout->addWidget(button); vLayout->addWidget(button1); vLayout->addWidget(button2); vLayout->addWidget(button3); vLayout->addWidget(button4); // 提供了两种构造函数 m_pNothingTip 和 m_pInfoTip 分别为两种构造函数 m_pNothingTip = new KBallonTip(); m_pNothingTip->setWindowFlag(Qt::FramelessWindowHint); m_pNothingTip->setAttribute(Qt::WA_TranslucentBackground); m_pNothingTip->setTipType(TipType::Nothing); // 设置KBallonTip类型 m_pNothingTip->setText("这是一段操作信息描述的文字,这是一段操作信息描述的文字,这是一段操作信息描述的文字,这是一段操作信息描述的文字"); // 设置文本内容 m_pNormalTip = new KBallonTip(); m_pNormalTip->setWindowFlag(Qt::FramelessWindowHint); m_pNormalTip->setAttribute(Qt::WA_TranslucentBackground); m_pNormalTip->setTipType(TipType::Normal); m_pNormalTip->setText("setContentsMargins调整边距"); // 两种setmargins都支持 // m_pWarningTip->setContentsMargins(QMargins(0,0,0,0)); m_pNormalTip->setContentsMargins(20, 20, 20, 20); // 设置内容边距 m_pInfoTip = new KBallonTip("提供两种构造函数", TipType::Info); m_pInfoTip->setWindowFlag(Qt::FramelessWindowHint); m_pInfoTip->setAttribute(Qt::WA_TranslucentBackground); m_pWarningTip = new KBallonTip(); m_pWarningTip->setWindowFlag(Qt::FramelessWindowHint); m_pWarningTip->setAttribute(Qt::WA_TranslucentBackground); m_pWarningTip->setTipType(TipType::Warning); m_pWarningTip->setText("这是一段操作信息描述的文字,这是一段操作信息描述的文字,这是一段操作信息描述的文字,这是一段操作信息描述的文字"); QMargins marge(20, 20, 20, 20); m_pErrorTip = new KBallonTip(); m_pErrorTip->setWindowFlag(Qt::FramelessWindowHint); m_pErrorTip->setAttribute(Qt::WA_TranslucentBackground); m_pErrorTip->setTipType(TipType::Error); m_pErrorTip->setContentsMargins(marge); // 通过 QMargins 设置内容边距 m_pErrorTip->setText("这是一段操作信息描述的文字,这是一段操作信息描述的文字,这是一段操作信息描述的文字,这是一段操作信息描述的文字"); connect(button, &QPushButton::clicked, this, [=]() { m_pNothingTip->setTipTime(4000); // 设置显示时间 m_pNothingTip->showInfo(); // 定时显示KBallonTip,随后隐退 默认为1s }); connect(button1, &QPushButton::clicked, this, [=]() { m_pNormalTip->setTipTime(3000); m_pNormalTip->showInfo(); }); connect(button2, &QPushButton::clicked, this, [=]() { m_pInfoTip->setTipTime(2000); m_pInfoTip->showInfo(); }); connect(button3, &QPushButton::clicked, this, [=]() { m_pWarningTip->setTipTime(1000); m_pWarningTip->showInfo(); }); connect(button4, &QPushButton::clicked, this, [=]() { m_pErrorTip->showInfo(); }); // //vLayout->addWidget(m_pNothingTip); // vLayout->addWidget(m_pNormalTip); // vLayout->addWidget(m_pInfoTip); // vLayout->addWidget(m_pWarningTip); // vLayout->addWidget(m_pErrorTip); this->baseBar()->setLayout(vLayout); } Widget::~Widget() { } libkysdk-applications/kysdk-qtwidgets/test/testballontip/main.cpp0000664000175000017500000000254315104543305024435 0ustar fengfeng/* * * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #include "kwidgetutils.h" #include "widget.h" #include #include int main(int argc, char *argv[]) { kdk::KWidgetUtils::highDpiScaling(); QApplication a(argc, argv); QTranslator trans; QString locale = QLocale::system().name(); if (locale == "zh_CN") { if (trans.load(":/translations/gui_zh_CN.qm")) { a.installTranslator(&trans); } } if (locale == "bo_CN") { if (trans.load(":/translations/gui_bo_CN.qm")) { a.installTranslator(&trans); } } Widget w; w.show(); return a.exec(); } libkysdk-applications/kysdk-qtwidgets/test/testtoolbutton/0000775000175000017500000000000015104543305023226 5ustar fengfenglibkysdk-applications/kysdk-qtwidgets/test/testtoolbutton/widget.h0000664000175000017500000000175415104543305024671 0ustar fengfeng/* * * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #ifndef WIDGET_H #define WIDGET_H #include "ktoolbutton.h" #include "kwidget.h" using namespace kdk; class Widget : public KWidget { Q_OBJECT public: Widget(QWidget *parent = nullptr); ~Widget(); }; #endif // WIDGET_H libkysdk-applications/kysdk-qtwidgets/test/testtoolbutton/widget.cpp0000664000175000017500000000645715104543305025231 0ustar fengfeng/* * * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #include "widget.h" #include Widget::Widget(QWidget *parent) : KWidget(parent) { QVBoxLayout *mainLayout = new QVBoxLayout; KToolButton *toolbtn1 = new KToolButton(this); // 构建一个toolbutton,默认类型为Flat toolbtn1->setEnabled(false); // 设置是否可用 KToolButton *toolbtn2 = new KToolButton(this); // 默认图标为"open-menu-symbolic" // toolbtn2->setIcon(QIcon::fromTheme("camera-switch-symbolic")); //设置toolbutton的图标 KToolButton *toolbtn3 = new KToolButton(this); toolbtn3->setLoading(true); // 设置正在加载状态,仅不带箭头的toolbuttuon支持该状态 QHBoxLayout *hLayout = new QHBoxLayout(); hLayout->addWidget(toolbtn1); hLayout->addWidget(toolbtn2); hLayout->addWidget(toolbtn3); mainLayout->addLayout(hLayout); hLayout = new QHBoxLayout(); KToolButton *toolbtn4 = new KToolButton(this); toolbtn4->setEnabled(false); toolbtn4->setArrow(true); // 设置是否显示向下箭头,默认不显示 KToolButton *toolbtn5 = new KToolButton(this); toolbtn5->setArrow(true); KToolButton *toolbtn6 = new KToolButton(this); toolbtn6->setLoading(true); toolbtn6->setArrow(true); hLayout->addWidget(toolbtn4); hLayout->addWidget(toolbtn5); hLayout->addWidget(toolbtn6); mainLayout->addLayout(hLayout); hLayout = new QHBoxLayout(); KToolButton *toolbtn7 = new KToolButton(this); toolbtn7->setEnabled(false); toolbtn7->setType(KToolButtonType::SemiFlat); // 设置toolbutton类型为SemiFlat KToolButton *toolbtn8 = new KToolButton(this); toolbtn8->setType(KToolButtonType::SemiFlat); KToolButton *toolbtn9 = new KToolButton(this); toolbtn9->setLoading(true); toolbtn9->setType(KToolButtonType::SemiFlat); hLayout->addWidget(toolbtn7); hLayout->addWidget(toolbtn8); hLayout->addWidget(toolbtn9); mainLayout->addLayout(hLayout); hLayout = new QHBoxLayout(); KToolButton *toolbtn10 = new KToolButton(this); toolbtn10->setEnabled(false); toolbtn10->setType(KToolButtonType::Background); // 设置toolbutton类型为Background KToolButton *toolbtn11 = new KToolButton(this); toolbtn11->setType(KToolButtonType::Background); KToolButton *toolbtn12 = new KToolButton(this); toolbtn12->setLoading(true); toolbtn12->setType(KToolButtonType::Background); hLayout->addWidget(toolbtn10); hLayout->addWidget(toolbtn11); hLayout->addWidget(toolbtn12); mainLayout->addLayout(hLayout); baseBar()->setLayout(mainLayout); } Widget::~Widget() { } libkysdk-applications/kysdk-qtwidgets/test/testtoolbutton/main.cpp0000664000175000017500000000254415104543305024663 0ustar fengfeng/* * * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #include "widget.h" #include "kwidgetutils.h" #include #include int main(int argc, char *argv[]) { kdk::KWidgetUtils::highDpiScaling(); QApplication a(argc, argv); QTranslator trans; QString locale = QLocale::system().name(); if (locale == "zh_CN") { if (trans.load(":/translations/gui_zh_CN.qm")) { a.installTranslator(&trans); } } if (locale == "bo_CN") { if (trans.load(":/translations/gui_bo_CN.qm")) { a.installTranslator(&trans); } } Widget w; w.show(); return a.exec(); } libkysdk-applications/kysdk-qtwidgets/test/testtoolbutton/testtoolbutton.pro0000664000175000017500000000200115104543305027052 0ustar fengfengQT += core gui greaterThan(QT_MAJOR_VERSION, 4): QT += widgets CONFIG += c++17 CONFIG += link_pkgconfig PKGCONFIG += kysdk-qtwidgets kysdk-widgetutils # The following define makes your compiler emit warnings if you use # any Qt feature that has been marked deprecated (the exact warnings # depend on your compiler). Please consult the documentation of the # deprecated API in order to know how to port your code away from it. DEFINES += QT_DEPRECATED_WARNINGS # You can also make your code fail to compile if it uses deprecated APIs. # In order to do so, uncomment the following line. # You can also select to disable deprecated APIs only up to a certain version of Qt. #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 SOURCES += \ main.cpp \ widget.cpp HEADERS += \ widget.h # Default rules for deployment. qnx: target.path = /tmp/$${TARGET}/bin else: unix:!android: target.path = /opt/$${TARGET}/bin !isEmpty(target.path): INSTALLS += target libkysdk-applications/kysdk-qtwidgets/test/testKBubbleWidget/0000775000175000017500000000000015104543305023467 5ustar fengfenglibkysdk-applications/kysdk-qtwidgets/test/testKBubbleWidget/widget.h0000664000175000017500000000167315104515306025132 0ustar fengfeng/* * * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #ifndef WIDGET_H #define WIDGET_H #include class Widget : public QWidget { Q_OBJECT public: Widget(QWidget *parent = nullptr); ~Widget(); }; #endif // WIDGET_H libkysdk-applications/kysdk-qtwidgets/test/testKBubbleWidget/testKBubbleWidget.pro0000664000175000017500000000175715104543305027575 0ustar fengfengQT += core gui greaterThan(QT_MAJOR_VERSION, 4): QT += widgets CONFIG += c++17 CONFIG += link_pkgconfig PKGCONFIG += kysdk-qtwidgets # The following define makes your compiler emit warnings if you use # any Qt feature that has been marked deprecated (the exact warnings # depend on your compiler). Please consult the documentation of the # deprecated API in order to know how to port your code away from it. DEFINES += QT_DEPRECATED_WARNINGS # You can also make your code fail to compile if it uses deprecated APIs. # In order to do so, uncomment the following line. # You can also select to disable deprecated APIs only up to a certain version of Qt. #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 SOURCES += \ main.cpp \ widget.cpp HEADERS += \ widget.h # Default rules for deployment. qnx: target.path = /tmp/$${TARGET}/bin else: unix:!android: target.path = /opt/$${TARGET}/bin !isEmpty(target.path): INSTALLS += target libkysdk-applications/kysdk-qtwidgets/test/testKBubbleWidget/widget.cpp0000664000175000017500000000452515104543305025464 0ustar fengfeng/* * * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #include "widget.h" #include "kbubblewidget.h" #include "kwidget.h" #include #include #include #include #include using namespace kdk; Widget::Widget(QWidget *parent) : QWidget(parent) { QPushButton *btn1 = new QPushButton(this); btn1->setText("常规"); QPushButton *btn2 = new QPushButton(this); btn2->setText("毛玻璃"); btn2->move(100, 0); KBubbleWidget *w = new KBubbleWidget(); w->setTailPosition(TailDirection::TopDirection); w->setTailSize(QSize(16, 8)); w->setBorderRadius(12); w->setOpacity(0.4); w->setEnableBlur(false); w->setFixedSize(320, 320); QHBoxLayout *layout = new QHBoxLayout(w); QPushButton *button = new QPushButton(w); button->setText("关闭"); layout->addWidget(button); connect(button, &QPushButton::clicked, this, [=]() { w->hide(); }); KBubbleWidget *w2 = new KBubbleWidget(); w2->setTailPosition(TailDirection::TopDirection); w2->setTailSize(QSize(16, 8)); w2->setBorderRadius(12); w2->setOpacity(0.4); w2->setEnableBlur(true); w2->setFixedSize(320, 320); QPushButton *button2 = new QPushButton(w2); button2->setText("关闭"); QHBoxLayout *layout2 = new QHBoxLayout(w2); layout2->addWidget(button2); connect(button2, &QPushButton::clicked, this, [=]() { w2->hide(); }); connect(btn1, &QPushButton::clicked, this, [=]() { w->show(); }); connect(btn2, &QPushButton::clicked, this, [=]() { w2->show(); }); } Widget::~Widget() { } libkysdk-applications/kysdk-qtwidgets/test/testKBubbleWidget/main.cpp0000664000175000017500000000164615104515306025126 0ustar fengfeng/* * * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #include "widget.h" #include int main(int argc, char *argv[]) { QApplication a(argc, argv); Widget w; w.show(); return a.exec(); } libkysdk-applications/kysdk-qtwidgets/test/testPushbutton/0000775000175000017500000000000015104543305023170 5ustar fengfenglibkysdk-applications/kysdk-qtwidgets/test/testPushbutton/widget.h0000664000175000017500000000231315104543305024623 0ustar fengfeng/* * * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #ifndef WIDGET_H #define WIDGET_H #include "kborderbutton.h" #include "kborderlessbutton.h" #include "kwidget.h" using namespace kdk; class Widget : public KWidget { Q_OBJECT public: Widget(QWidget *parent = nullptr); ~Widget(); private: KBorderButton *m_pBtn1; KBorderButton *m_pBtn2; KBorderButton *m_pBtn3; KBorderlessButton *m_pBtn4; KBorderlessButton *m_pBtn5; KBorderlessButton *m_pBtn6; }; #endif // WIDGET_H libkysdk-applications/kysdk-qtwidgets/test/testPushbutton/testPushbutton.pro0000664000175000017500000000200115104543305026756 0ustar fengfengQT += core gui greaterThan(QT_MAJOR_VERSION, 4): QT += widgets CONFIG += c++17 CONFIG += link_pkgconfig PKGCONFIG += kysdk-qtwidgets kysdk-widgetutils # The following define makes your compiler emit warnings if you use # any Qt feature that has been marked deprecated (the exact warnings # depend on your compiler). Please consult the documentation of the # deprecated API in order to know how to port your code away from it. DEFINES += QT_DEPRECATED_WARNINGS # You can also make your code fail to compile if it uses deprecated APIs. # In order to do so, uncomment the following line. # You can also select to disable deprecated APIs only up to a certain version of Qt. #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 SOURCES += \ main.cpp \ widget.cpp HEADERS += \ widget.h # Default rules for deployment. qnx: target.path = /tmp/$${TARGET}/bin else: unix:!android: target.path = /opt/$${TARGET}/bin !isEmpty(target.path): INSTALLS += target libkysdk-applications/kysdk-qtwidgets/test/testPushbutton/widget.cpp0000664000175000017500000000607015104543305025162 0ustar fengfeng/* * * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #include "widget.h" #include #include #include #include Widget::Widget(QWidget *parent) : KWidget(parent) { QVBoxLayout *vLayout = new QVBoxLayout; QGroupBox *groupBox1 = new QGroupBox("border", this); QGroupBox *groupBox2 = new QGroupBox("borderless", this); QGroupBox *groupBox3 = new QGroupBox("borderless tooltip", this); QHBoxLayout *hLayout = new QHBoxLayout; m_pBtn1 = new KBorderButton("border", this); // 构造一个带边框按钮 m_pBtn2 = new KBorderButton("border", this); m_pBtn2->setIcon(QIcon::fromTheme("browser-download-symbolic")); // 设置按钮图标 m_pBtn3 = new KBorderButton("border", this); m_pBtn3->setIcon(QIcon::fromTheme("browser-download-symbolic")); m_pBtn3->setEnabled(false); // 设置不可点击 hLayout->addWidget(m_pBtn1); hLayout->addWidget(m_pBtn2); hLayout->addWidget(m_pBtn3); groupBox1->setLayout(hLayout); m_pBtn4 = new KBorderlessButton("borderless", this); // 构造一个无边框按钮 m_pBtn5 = new KBorderlessButton("borderless", this); m_pBtn5->setIcon(QIcon::fromTheme("document-send-symbolic")); // 设置按钮图标 m_pBtn6 = new KBorderlessButton("borderless", this); m_pBtn6->setIcon(QIcon::fromTheme("browser-download-symbolic")); m_pBtn6->setEnabled(false); // 设置不可点击 hLayout = new QHBoxLayout; hLayout->addWidget(m_pBtn4); hLayout->addWidget(m_pBtn5); hLayout->addWidget(m_pBtn6); groupBox2->setLayout(hLayout); KBorderlessButton *m_pBtn7 = new KBorderlessButton("borderless test", this); // 构造一个无边框按钮 m_pBtn7->setFixedWidth(80); KBorderlessButton *m_pBtn8 = new KBorderlessButton("borderless", this); m_pBtn8->setIcon(QIcon::fromTheme("document-send-symbolic")); // 设置按钮图标 KBorderlessButton *m_pBtn9 = new KBorderlessButton("borderless", this); m_pBtn9->setFixedWidth(80); m_pBtn9->setIcon(QIcon::fromTheme("browser-download-symbolic")); hLayout = new QHBoxLayout; hLayout->addWidget(m_pBtn7); hLayout->addWidget(m_pBtn8); hLayout->addWidget(m_pBtn9); groupBox3->setLayout(hLayout); vLayout->addWidget(groupBox1); vLayout->addWidget(groupBox2); vLayout->addWidget(groupBox3); baseBar()->setLayout(vLayout); } Widget::~Widget() { } libkysdk-applications/kysdk-qtwidgets/test/testPushbutton/main.cpp0000664000175000017500000000254415104543305024625 0ustar fengfeng/* * * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #include "widget.h" #include "kwidgetutils.h" #include #include int main(int argc, char *argv[]) { kdk::KWidgetUtils::highDpiScaling(); QApplication a(argc, argv); QTranslator trans; QString locale = QLocale::system().name(); if (locale == "zh_CN") { if (trans.load(":/translations/gui_zh_CN.qm")) { a.installTranslator(&trans); } } if (locale == "bo_CN") { if (trans.load(":/translations/gui_bo_CN.qm")) { a.installTranslator(&trans); } } Widget w; w.show(); return a.exec(); } libkysdk-applications/kysdk-qtwidgets/test/testloopplaypage/0000775000175000017500000000000015104543305023511 5ustar fengfenglibkysdk-applications/kysdk-qtwidgets/test/testloopplaypage/4.jpg0000664000175000017500000367665115104543305024406 0ustar fengfengJFIFC    $.' ",#(7),01444'9=82<.342C  2!!22222222222222222222222222222222222222222222222222 " }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?ŠzD3Fs#09sҀڕ01H@^ A<p4 NiWi8{PO@fP PA;< iLO=ri;ubJMz$ќy搐xh>ڔ r)=1jsV_*m;0>a 뗇#8 ]8Mw>$h<8*囓MJu?&ZI q(u*!̏™rdl9ykҰ|Z0&~̷ ssHzV--"ص֌axqJ`1!,s@TԬΓJ\_+ҝ%X<םiR(w M) q)ۀy-ixYU8V&pS qNkc`)QX_8i qYـv2h-t~HRy=B QQ35G5i0}jeqYGJd?t&឴*M{T6,iAB$8SRD֝( c4I=;QÓ@ h횭qcuh8 Hemdhv < ^K.Z Y4̬!vե|$g5rpjO7NGMvd;VrA cڞI۹\ϥ=d>b# \,㎴ BR2Rg /Ҭ`Fscu5oҳ,p+HarMYQSr)H\w5ښr&.u.{PE$$1։>\Vul;IRcBL5)P94iҜئqH(TX3@D*(8 8R18 6NS *).=j$R(`Gz Q+AZV*2i;4f .y4PfHO4 Hi I&qAC)њLiO^}S4{vq@&'S֟)1HcFzSE7'=)Tg4)JgH4ӚOjL`hRڔfsJ#;`?9M\R!x84b9Sh3Aȥb:}Y1ڵUy-؃ϥ1o2HV5]e3f"S ?N8Sɻ ܾu $!1@5TeI5FI& OjI АZ VeƼeR=7Ts4̻W $DB['Sby%$-5lҚnϥE{Cfm<S#1MHcYT=Agf#ZHC#"Gj c|he ,"{ֽ$FZqPJ\o*D$vq*37jnc<ўqNHi>O#M#*LRI=fUo+VaCsc1XcF մF+sig/[_O3qbd4\8ȧ"S NN5\$ޤcKg)v1C/NAE%xE+ԡUڻUN285<X`i,ӯhPpumBDrҭj$<ý$;nku#x@eV0ڤW]A5k|(rO^hn,qR1جzՕWJ2]Қ̣ d~XqN[b@Tu%GL{m+E+[KsH9틐k5o4jX}5K2Dѐsw]U,F;Ywt@џRhDc^ې)VD.w]  N1VEŠIKݳRvBI[$Cs#SjB^%Ē9V#N1Mx$S%2sp*IY=*Cm"+.ڂ3uqow"1.ٍ[>jh\ѮJ[-*u:jH@1jdhm5F7 :O&903)+"Ê8 ~( &| (&xJxy$b3 @M3P\-Z.%b3LF\x担f ^:gQFBwgW)Dx=}i';Fi>nҍрi\vbA4y4x(nۚx*~)g֗稥qXx99.ri{8.iRѷv@ JN d۲9N"Q"H+@DG5?V~X<]rz lظ.E#j{ҚO8 D\Z?'2e0,sI~8j6PA;#31ށ<@ `EJ iu-ǽ0/i9DGv6H 1K ``$Ґu'LFy*0Fz{ GAH zPp:r(cix'ҀM'P2(x)ACiKL"cKH(`8SQg Mn8(u03@wn EFhcctM8֐@ &{@=Iњ`( f*ED)M1piˌP!zRHcyiq-0*Q2P"Q`j3Z 4Tz)1P3(qlq<: LP&(c Kz"q NozJoniS!8a4s=x9 s֞9phÃOJF3FE34@}j28OcQhJii84M) zSN(ysA<)/4sJFi8'ޔP!{bx\qS$4w#HzP1Ό 84@sڂbq@3(ڬLW f1V g( *@A\pA ȨٕN: /ˎ 4tlF(BO;7)9aqkiax,0*,…±4w*\aY!8ȦK+4֫XOiari:Ӕ ZA=+?{g$̀sf:4д0N& Vcfc4ӉRgcNrsօyzcƁN<⌎HC \tiQys-4ڀlPN[4 yQޘr(J4gإیQqJ 5B`8l7gH(n đ FcrW FFEzΧ>N@QҌfvee=V.KC H )[03i̾[` nJw9,9 9'V.R%.7EVg]bR8UfTrX)q#wg⹭L!ޣkUd75\j ܍)n=jKIBV ju,ɸ9e5H|[yT6v#v_ۄ^L:W/p9\bsʹ/מ\VQҺQDސJy +Ǔ[㹡ffzk40A⼾zv,+)|G Up= sҩʊ{b'Vj冐lf04F/r ` 194G70Ar(I(HD;)=L(/5V[:.ATf%{w~X uHI ց$9PXIA9Z̑ #7"ܐoq7Nǘ=qi\V\WJIRr:wHMVV݆!.icёh' AEi;1[ɩv"=c֯ŦJҴ`H#&Y.Imlnކ2aj*)TN1s(⤘V'h!4g j+R_Є,()AS*X3Fin))K S(NJ!&M78H%*;#Fi, ͔r "PgjsƆT^sNQ#O.ęHl`]O'(dځrEF[ic݆V2 Ed84b`[˖b*vlq@4q qJ{8V㰍HA ;Hr+Ӥ-W"aGNI68*p*5SYi#}j6+LSY>lԑk>P7HQILb\MN:FhQւ4(%Hf3:P2旽5OPHf(9Xbl"%aҔl Pr(|SӚ DA,Y2TfNyLHMj\7UHVF([N+H($>l}QJ7)qL YrXgEk4 ;c<=A-1Ry1N:\Bpiq.x'dib84)?.h"4g>Ct=iiL7iҀ3ց 84gs9gՖGǖ?a6p֚$~54ծB~Zbk,&zG C1  ٣V=Z`۝H8n6UjlƸۛ4p!{Ss Cq ZFZڂX0o$ lF< S/Pְv̞R拐Fo>'e]7ՈE b(=ڕ܅Jk79'($:h8gLi 34uRq'jL&x1F8`44O+֑V*3olE>ۅYګʨ`IڝHy8Vj[j 14IQp8qy1n#'<<;X`=+hk0:wU޴w^#3҂$oAS1`8aPHag#8lSEv~i*@yR'7NO|>rݫ=HIɡgGQ47y8^jsR)f[+[ɍASY:mmwy$=:'4n*ɇCֻa*ȥ_=3TgѡeiX~0qw;RLWq7$)ET6m?'JMI.@9f]&5NiSAԮs#ӲqL9؊E .cJjsTa9# Hcaz"O+2ríU)6kr IgFř0&!EF.N> 鎅$OfP;${9Ҩv n_Jt#<{sҵ-mH{w42v&t":U=LjW< (qVnlE,h/5XAȭ9Dg0E7Grzsɇzp&׊df ⦈aFED>i0>`p}s14p1#12uCLӉۭ(@ aBsN#"z{r4 r0iOD?ZP)֤LCXd=NHZ`HzOSzI]bzJ\Myxw3Q;pjhi *i %uGMC-G̐[ذd']j+gjhk 莈R3ۥ2Cw(DO>P֡-54`F=| H$zӷ-Q"Қ]GJ8͓Q104ܓ$)` ; Ҏw(Q J2jb\qGz) fhbQH1O)@ibͰL HK֩#6LCOL{|vo^du:O%zIrzKNCRjRzh({sL(=('J38=O4ӆDN@KGR@NTmSq@F*\q5 (9 sOa0f׊t4hs҃F($`)(dz n 3zҐi83A⛏4 ^ W ȩje=v,QS}k|VQT_xM唯;1*mljQQ1kekH޽*\DO4ηqcxijhFXrhC* ;U ccHˎ !|^[DazU',JѲJ44pij\-@d58SVfƁN#Z^ !SIn)s N &iei0$;sKna4d7P=j_C*9 !n@hB@PGzHeaYS[cJQ>`M(լVRd駪0A*F JdBUh]G}2/< _I1Ѿ+u;⹚jG| 'B,@ Y1 ];V0oE=Ĩ]Ee$R][BRɌb[$5F\N@2q[֖R5gv٢$RH<Zٴx槕yKA99⹝jX\vWki3ncgSrїl3Ќk&rL< P>kZӭp@FVVNkmd+f,n=*3N1#1)S6G$@T#"P U~RA,2\BRaR2Jhɠ~\m1J~8+I 86)?ˎ P##A1ڬ& ZփXFJeĜ #&9@Bn}) q>fX1TQ0{Rbq O:QXsP4A>a9AjfڝyګREq(`p+`F Q@_֋ Bj+*C rHfs'7>zdUH(+׽E,n2›<̈$dj "2U H$*E,c`WW;IqQsDʷ eE;֜0֭p|J)i˼[vzƃv W@m UoN$6Co\g*a0iIPsr7KcFJرcqȔl"jI'h u40#kDs0&?)SgbNIH7D`Ҍg\RI UXJSBťSLV❚f#M&M)4hv T.ޫ Hl'5#)<)>s1zl̈\FsVb{i!.=Ϙx@9d RgDGZc֗8Eay` i7z`bDh a9I׊rO3)L=(ߊiscZa3'W-/W[>ɔMU+09+d"PH'OƂFhiqF(=E1M=iAR iM&M(<ԈzH h㚥bf2Mmȧb7"0ZY68 RqcL'4Bh(~h$ |MTPI' INɥWa6qv$ 3ۭ8OZh<杕#@ 'sN!94LR{1`i HH@?Zb0H~SVQL9UrZ5wdc#J3Ӕs1ҘNܚQ&ݜPJFނX [8UI&cvGqVmuxnfd t7C{Hp##Y7$J2:5 {w@;F OBً5 pycWK$y,*d'J͆m$ҦFBT摓/:(2 ͠$*_zҎ陶UhnZP90v s?즖]+R ]d9m>i]ȫxb(&kxBAMmtNNI4kH@*yiapS׭!(!ɱƋ-s DW\RM +pbCZld3Sy#)r4 6RRzڲ۫RLjnі+'=piDQcXՒ9e{`si"K1G a$: RLҷ˃*[.o4l8qVȗ |#nIB7;sJMKSG cJlFqɫf<|eX~UY _E R1O&E[vVp MOtNEi;6Mi$0 [ȫ T${qdH}E0= NB*IH7*zRBA*sޑ &OҬƠrf1j`1H qh'3ƛWHVH`i[qu9up) %Zp<*][2q SpIS@2D<ƝS`~4b Ҕy fJF2_E(@RI4ryQv1:qU%Q֬JH"sJK\e@VKrM2@ diJDaJsy>pzr #:#̙OͶ dgj\=126pi@/s.ARn擜;To2 ZIp8 YF9$Թƙ+<񊍛yM~! $ æyь1bq^iC cůrA\g5]yh9Gd0r]wlݝM?6Z#~I`0ȦbPqM=sKޙ#{H`qMP;Iga5\$K'o)6t) -Zޠ`'I5)ئNAB|r~"v\I3p.,gݘf å<-O֡'=%" eDOOZw!JR9-nY09VtRؒ$!q7/AW<Ԉu&vT|6..q:e#uI8Q< C^H! +RA;J;ڜy4.3Zn-ҝ0BTrebַ^W'T ޝ#$^cM ,,g -[xbyE"ejcʯ% ~P2rk&{ppڸ /&FR9*Ҷ؆EI;`VDτ*rzEFiN!Fm;Eebf~j Q<#vڔbu9Yq9q͊(xO%"X;Ue.Kj;9Fǝ8^kJ B֚|>L{Οcnbz*g=4"N^6+$H<}+ ( ,Wv,IgFqIY& H&lPǹxcR8U`[*DVJ/=*?iG0#@cN\)8THF= )֟1.3G1Jۆ\\E5ps$oPIZ*$j-\*nFiܤc#fSؕ <ԫʓZ˔)pVԊ=kVEœsҙ=JWWr)0JpweCeˊӴhė(>(o Tj)n%J_L ve-VGz_-J 2M|3sl--R-$_J%~jM]ցs2d#]p6i|{ѐAf+Z (bROZ}Tz)X93LnOjv;O ֤g5*\_ QA{U<|,I튙[G9mw3h7(jM塒 1Qޥz"=ʼcH cN*eQRclS24LfCQ3Mgɞ:GJ=i qɨ֕x()Gҁ횞&c`i8C8Bs֐zӷ M9Q6ހЬ@Ѵ(8hȣ"P)7Ҩ0rN=4(Š8N}hMqNQȣp@Gx4r !9U^=( 2sA N|ZW RcST9ӹHw .R ;O4 \('3$6(=y@ cij:@KfY`iC`ri-!h4@ 43H3ր#e!*\Sw%'Ac`hmsMFGҀx敎yQM@R@ϥ4sc8>si1gs*LM{W<ᎠwXdYhWiXn TIQͣ"O.0 gҷ"eaQ+[c݈CHv5ɎcXƕ9RַY'ֽ̧,EOincA%9NA<⍬F}){P2{f9*m-ךLcaӎ.0MRs50Hir(^ 9k/n44 G/-^YFY2[kNo-Z3#j<,%g@vhX+AN;f̮ˀ;;)i |qG2^z(U,iL[k($گQQN?xpi%YٕJޞUPiUrwHiqG'n0=jT!S<@rsHNKLN3!e'+08m;sϥ9zRwqy 6*(0K9V 7=xr&B3@?$d݃P84 cg{ץ)ڌڐ%G@іrO*8j9UpznN<#Ґcm sIhG͓ s ;rNis1֡WO˜L2CI0st^$*IY]\i6\i] 6C߽V,r>9 Vm[ Svr;ҫ0U<3De UbN !g%ړe:PvWy\$Ar;ә$ QbcdEMt%Ԯ#K aaٞs}47}*m3ںQԫrtgj*J0MWY3TG=öOJ<ʸ*`;Tm0^d9a{Nx*TH㊅gަq⛜d tčT d5~GT`qI;KNEWRp1eҜ9)"⌟ZNh zfi4 E8 GjQ#J\R S$Aœxn0JO HPqRR()U%/q@n*ɩ8Y&͠bDBqC68i=Fb&F-=jKkb6EtEܮ˪J8v>-EzHl8(hү xL˛S.EÚV&\Hj1H qE ₉QtQj7:lvZ0?P0͕Y6Sh섋=땽TFfgpB6d$MCK@݃ڰ4R'nécTfXK1!c;USf%@2e_cn{e@?*Syެ-%S'7^ ["gy^Iô ^{ EI5rZ䮺%1xoP{U+!PeV-AIŸ]*y'Hc,?1܁2(1'W4=h4aN()" iBݓJb 0Rmjvǵ8D[NzS[jfL΁#r BqpSf͙q^O\hCsWTpiNͧd `H^ RGlIn'X/b61|IAM|d$ UXz%O<Ն{Pv OZtA:\Nn9\[AMWFFGX4vFZ>b|5v%hpx5@IUYU5"WPp3%V8#ެF+})fS|jpS;esNr(fm#H~a!w jvۻt3j4Ii;E.j$RHyniwfځ44V#4KF)A 3=*"{2 y+ǎHN"hmpGҤT,jt=6ʹ)cpz."޴ÎqA@i(E恇zqRwR *X#dfqVsp:M'5I"҄iǭG4y<"L|v5m]Ee搙ov޽)}FIJO^ Q#'KVbϱ{yoo^eI4; Yw6J"8dQ4z)c2@ 9mFӡvh~dP1K2Mh88>vA)FР` Te&=i #)>ÎiB}3M$ J=jʞ*5(K95 \STwf!n)m0)Ԃb<)< wfCtSu}f .xqH̓&܏zys!>E jr1*qhQphZKF0xqR)>) Txy9* ;1PFr4]͓Қ~X-*`ϱG$j(g7SI8/ZM0sRG͖0Pojhg4/O'#oLP3@v=8֎3GM=ҟM9,&h ibPғ/)F1@ ֕ 7-AO$4<2:;u3!pJFO= .CAq4c4#-D˞jR0FDqiy4>Hϵ?;zU!4R1M#M1TMlSS t18UmF;3* G3 ֑qG?xZi|ިx_Z7a6a#튌v^8AR:G-93DKRE =3A9>LsHs8[ۊ5cOifzR## ~L5Hq+7g @\cR܁∉SIophVk/1y$۾|'&+ɞy*dZ'փ\SZ:Ч9d{R*jAK5ϵ7=(ϥ?9T`N4KDO LC9ʕ1 Q4:RW3H1?bP9wHlisQ'$wcԛj)EfѢc-Ѥ^= Qm*t+jIUla*ݲUsޮB6WI-h2(~!Ug_|֭W#"^rx" g0iPUUO F]MOU@9&944q@ 8 *TOQ@_/ڰOOj,KXD;#)EPHQ5cUISkti)ryb:R,zr8bI=8R`c38OcX`U: D6B#4EGV搡.D p9<ь LPXMP1 =)GJLڐgxzng"~F:&@HzsH9LfJIQLVO0&L1q)Gbi.;P_8玔?7֓i>Jb5 Իl:19W]daKMm>?*3)<m UݏlUbHS`S6BSd Nz HwZ z`Pi_,2ig#hȸq֙GvU%"6ISC7LgcbT ޞ6E _jyҫ.f 隹0F-V 3SF3.H@ .jTCeiJ$[qțOΤ+íjwZBA@ /lTREHc4tҘ##C1֐qM9'sH;s${Jn.Q:T=(Z]ނ'Z`B6G5!`y4޴=(wpxݨ=sڗ9WGr)"zӮX5]H둊xǮ{ L6j{0)]1A#8s֥$x׃#99(F U⥓G5ZIV!wI JV~El>FCFy̡|W(Bl;ss;>KP J/ L1Wl2 T-R1d b[C(0^T*FGIJX IM!6 _18i% !*p;X; GZ6ֱa}]Hd1#RQ e=* rieAǥ5XJZTޤTT12ҫ EqyJz1`[֔8<OXĶ@IGڦTqApM+T)NIϥVݳ#֜>тALQ\E*!YX@8RN{dr3+Җ!Y_"et`WRW+>VbAq+Nv͊ԜtL$(֩]M&_FRI?KTbOn#7B T$ÓO`$sKm$D/m i1F3RR iHrG o`*i/`D°A[O/AMcE)4̲( 5P3$ش3N@2/zI3ES6.(S\žmSu{WE ,< f5S'Ir'= iKNj3dq* n0Vḱc155.rH=cP˓ֱv20JDr}&Ln%_L2e@fIZFcST>QW'c+t/~3Z"tAL֞)OCi-)L5cx恦fJ7?Sʼd^VץR5qOH[KE$b H`i(4QH1H) lBȜH]+F+=OR43T2iFA⑎39]*@`f֕qMS\Հx+;`޶"psTr&#"TԃPE32.7ݥ#C!gJ95ϭHÜgր# sO~M1ځ'=8;A$R1#M@-G&1;Rhv8{{T< "QNې ڥ9G"s,ri8Hނ\T#('')M#Rco6穠Iyug-Ҙ$ =*'O7s02L| N s3hZS֍d8Ph?/Bi;9a9˹92Y'"EW3Bݥe,Ҁ@ mvTOcZNtxRti(URIk!hj113`V֕/#b|\.F 쐷' 6n^e!&H</zםЩKB)-8f&.G~;-t xkA=8]XO= )٫/%5%D89+;:}V {kʆ n+#=YL I8 n5E }e :#SHrym$N+L[+qO- ,/#=ء !m8D AM#9TL ֒]*ޱ*l'sN F 䖬aϕbJO˜SҤ9L>􍞦8<)^(61ڹXfdTӗU:TJLl]GB38#Vc&#EL9)(9vGAH; /V"늁, 3| P+ \UCNfɦv47(8r3L:p4⌒( 4N:c9@8/2'슌n]5iC6I7L!Lќ 7cvv7 5GJG.GZ7ҀNȤ{vTq(ցKGlQjO8^sG^ ޗAךZd J)zC@QE 1J)q C֖8zZ=@%(ӻbL5080@{nޤV8TCKADќtw{ѿ5b B9O'@1r}*4GV4SJoSJ3 2 1ޒ=p @0+ETH0IZa4Qq7N(x\}ē2*MPm~iN)sRE1e>AC@Sc8qA.($QN ;{S6'S2[36@$cڜ 8#zԀI/tL.dRpqE ֢iƞq54\#뚧q"t Գng8=n୻[?3.vjNxSWR1Zm6v+E"1aM+\(~I&v!AVdZ` 7;w$5sެ"`vV ªUCI2)fSҜ1*YKqp~UdRU+F$.. XʢZcf' TbS$Y86MہEHU a/̣Q7( &(@254[rV*DHr!=~"0 ԄɃ2iysG׽W`=pM&Õ4D<V9[ZrFaJv95GzV-M"_,aUkUM 4X,JԃK$Gw qQli{6rZ$}*2iN8iB_1JM$A`;SdbT%"O8r0aFH1 S*w8jcα3HIFx/.8>-N{ $i"~rjr_D@g=Xȫ0GzKDb#OcO$q)rZ@ .*.zp6sO\f82UIszb@pSYTBHa=IufBD׻^ F_Sڧ==$:OHtCo5y:W@@qd$UXesJPNJ AW\~Rj6L`1Ojku+aPU"-R^SJ0jW$\t3dr&ip*!S*SwU*#ڵfRwGJe|WUp+# 2!0j|HTS!RP83)٨ۚar:Z_zLS摢E~*0Fj0I✣EDv3TWQhEZhKTf-C ⥨RW4AAEwaIii5*Ŷrրv;$ lPךePrkQ#*Ơfbs4l5 3q. 4R6B f Ԍԗq8lIb8Ҵ'"3"^6"cHڥ"F˚uWw0`ӊк1TH&FENM4'jN)y1 'z1Hh `4h'=)3HO9 4ޔ) h3zcM!<曍h7^)b)+Z5nSl''UaI);E8R9V)悐1hR1Kq78I8d(榖$tc=(=#BHS/1 9H2=(hQ3@-SXv@`=)Ųe!&fs֨q~aү88ى-T4Mm ǭN^97I5dEiC9hrB˱}zi&!g)BS`O-JԎd >Vy7zji "V/Se T3zR m*F\dd2š˽Hbm7|Ec<9v0Rs\՞پ\CЧ;NXzs밤t8L$(vg",msV[5Zx٣>o+1Zoj&<9k~rխ<:NURЊSCjҳH qmR}ӻdsJJLp9bP'棌y` Tb=O MToZy^Ur= oS F:1@SGsҥہQW: w֤XtQcE1\00VpUy"ri}f@ d񀃵O F&Dk)Ux@IƙՈB2VbzP]֙IHP*֠pFEZQ(2$^ޔzSA wzf,3 KHxC.Adt `P1@s*( 4:PPIE8 @&3֎*MMe(0H⃒1J)M P1íH8P LC\Aү8J=h@85F,l UWT2Fs\٧,4a.EuF?8RbsO  ""`g4HlSC)1ll p=ѷiJh &sҝ#B1nM&[=yƐn04{G(j2qHg8>fiP sO&S"c2;ў'JN%-!y4)qR}hs; (<J@X┚1\4H=)s(`jS֣q'4ަ@#aP"㨥} L`Rɦ)@\iaz(t}4]C$DdJPsLÀ楖M'18V7O';M9o3w;R4,bw SFP*4Cӊ0l m%Zõ)Ƌ4$ɉTX5(UҫF1VV%2 ͑TDXV >"sG|6 z1$PdJ<ҁIҚ̸8G9FP3|CQ3< ]H s/nW )5 YNsL-g F7УՁzSC^<4@6N6hV'=@3&SօS&cޞY7>FhƏa1N .=v`L. []BF\+%pKrd d FPI'1,UQjV##S6)z "wnb5ZQqVg9g) m_sҞ{SA"& |P;USe\R`SSw0PpjyȤe8㡤jۺsW H@'8|=ͻLsbsiL;W*Mz zqp&fa^[[F Z؀Hڛ8K)SIM F*[6P.mUW˨i#o/ W94I HN~\S@3֍0s)\(8'YN`BR">GМ~yeȗi UM+\Lǿz_*䖪$aq*" j*Vz wƙ2I/ӱZA,uX0n^6^J ,^zMJ: @= LG$yf1` SIP+HRSRSjvNk7L`g$՛PmOޯFLGB(AJc 9Ukk"u[bGL|*:kHJM7)2pjp*%У&EZ|m, ՒKgqX{'sڦU@=iiakx&k(=j^0aKE%!Zu TMVqUH@+x 0i::k)^ :՘Tg:*xi- N3ԧA!`HbQژƚniX&0i $gT֕j&;4Hk7 ?i1N98U[rFxUls˚䑟#81֘pgf./r: K,јhJ6=+Y@lXҭ!ȬvՈ NwF;=(<2ARH/~)y S&xTcOjdT^MJNU<(KbN )h%vpZPqh+Rm"\ҵ)´L8sVH2:Sf|Jbf%YD6 #$Qr2{TM85;7r*?/Ihu=1SӕI'+C7!H0Gz81*6;*CN:UԋE =*'pDTqP=PHSP)PbaHih4L"i1'85#uy4!95FcթOZϝ UrNܜ0s6lҌm4E $Pkdy^ZtXs:5 WEL)x吔-ң#f<'95Q 0Ң NSFU#g,pA$Up1Ox+۵6XG͸n<.r* %(^$h D-1lc4"xn\>`zq:1:R)D sH V[\6 f ˫ kRnSڹ{7)=kdhs\TՍf@YW֛^OZّ#U&(J`$l({ՄBZ4( O)ڮBX .w(iәBOsTFGUȭț⢑8#ިS7bp3|g)OD9=*.xH iA隢*LUb"ߐ8C#TɤTP@l@0.K)9'8(P[4`=*pA 4 2wMr{\@x+H-8L:Y]ǃNaS&P]PGot! B KS0kXX(KV2, <3D@-R0:$ĸZV$ .@HĚiy A0484=1ajeH`xn8Ⲯi3Nb3I4PM("T(+F,i"1R&>7qCN44w 隰Sx 9\ž0*{LOAP$kqS@8L\R)KiwZSs!4қ ^3ɠҙs{m!41@s@S`ͼ恌d~)6+sPc֧Lc&G ph=}H@ J9{HaIhzъqw`c)9昅snzIQsM<g M x&1N:qPhv4 C=X.5v敊0G"8#𮘅e A+9 wTj}ډ#<(2)op84 }r>i~5U+ V%MqCmuǭZRb 'Y`$`h"gl[?.+P95g' r]6@R}*wߺԓ.>-a(&%:NE h$ȌN2*-F ji r.1s07#-w!ȪaACOL&x4@`(4pӣS(#ޢo5nHwĀ*+3Lh"akf*r{$]gN`ltIHA*AP[#&*SMސڙ#F P44c't`hqHKcޚ~n` E`Kutl8Š ӷH1 ${)G4'"ME(ց qCE+q҂xC Ozaޓ8  p3pǥ1aNnPh5=[h# hh1 8;o;sH@0xLAٻ}v~rǭKH;RL)zh#!#<I|wi#>TP1{qNhoP(nj)&c•<Ӊ]4y+Jɜ9;O#. GZ7{duu 5EYXHCaV$][ lQ$y`]a@=NO<T9+]ao9F_8lڳ/.T?,𽪓ۺ ړ. lB%qG0a5xA24cQ F-ҫ w6qwƴM71 ֚b,F)&2l֤Wvqڕ:|ǚfRc2994( c֧,"u\ҥN\`՘G|1!\{{Pr=*P>S3+!ޥr7ɻh|OJ9c=9Rt GDnQV&ܪ`W8V>Ҵ+*i8{P4h3DE7.Xd›HN$Mf惌_pW =$." 8I99y1)vNiOg81sMy/UY\i6]֠7dTsHB'5<ƟrƳ3$(v3ϕG!ث-PNQr*[l)" 6V#h\ )ƑW 8sڀXJwaI;phJb 81RH?8쉈.x,k%Y3$vNKrd"ONx  .]|׼t)= Ʉ$Xn=q[𗔓tB]eR̶.UE[p݀L#BmaeAQF[tsI+37tH˒[)U}iK!eE :_^+pj0WBDtl/ZFWDѮ{0 u>gx.Ts-gp \go' k Z3JښUUF*M+3ĸ[w2jOj2RRhVe&TYFRI4IJ֦QT5NbŠ(E!8FWՙNjK=yIlFߖ+J28^1Lm@x'ȱ/Nj)FU%ʍ ISHО„RR; i0qM 2XH MX1O 9gn➑=(+;uV;qOE@9 ԁE\ӱ  )#ցQ@E-1VdP$`E l;M[u] EG55VVA,u&(&*7N:qRFx k}zVRV5&7jEBE4ԅ~S74uӎ)1HaiRъC=/Z1p(sh*zSuQTC>)JcH8PHR)qLAHiP1HElf<%JO E!Z3bAڝqJ'<NU9P稤#'4:ޛEJq$s֗{ S58#iM!^ o<ݓJ@:ڬүt5SuTY8Py*2?:QnARg\ܘ4G ͻPERW 뚿Hŀۏzț{>M]/zTdp1zb~jnݍ t>LcބPis+q@WRF[|6ɬ3&JKTj6H#"A.N4xr9xyaPq&E=`(6H2;ԙSTm1P⑀95QtpV!%b(+H375X\^7>8(L.3ҚY ;u@mF%FJf201_5"oJ@H)K)1)M!'+@h)`h^sV6e&EFIqTł#)VexҊVF@sY΁OcSB$3IEr$Up:.j2zT#$^8*eR5qW=)iX1(XEJ:P fTnjܭ5Eq=E'J yEdpk8zV˂)8+Ywk-R晜w3ۯNifޤ:G4S2hh#+N%:UXn ]^FjN2mƨA[BP4U\VnykbVeY,Q0>0'ViS>o WCl)Î:DCSÒ;Œ;S=)i )ɰi[4vHԢE7i;p.ǽ6:Rѐhڀ/@ƕc>nQ=qK@iBE@LRQE'4S)s@'[kA<{44rSTӿ@ f'J5mw'ܫVA9FG{ɸpk%BM^muWH,{>he pjHWN3B$$HB'8!aAQI9(9yNP?7O죞AbA@40&}M!=z!$zia@X9i44o0NqHrq֓hZBl*)n Ziҫ%i/Km4g`l)F\0!dpր*xPpMX4x$Sv]X 爂zvcdSP9HV^M5@ufGVbYVJ؉s#9"pp(hoQNڙ9u!N!wN)A@:.n) Lf###W1!Hc*# 4kivpiAsH)'b:A,13NSdrx䊋<@;V`FGSCl!b2cb&r!UUIRG7lh3P, E,1/2[L1zc`3)j3Ud8 {fem;xcRi\Ng~p,=1Y#Q FKeaLTdsB6I$U^pd4m>I!$MlGɷj#]'>HU^ \hq BO1Dh#-ަl7Q0i>LqQGM92IA ` F _ʓq| \NExN +kZ W2g(zn)5q ױsɚ'uOsRDi޶{ݏFܙOT5`9-:wC/oFFy=c3Gj09Qi9hLR֦AFh9qJGzVy"D574{Op[*s[%mZI;LNI!v6|ڲTtdDMJRS"PTj" BPf%4jLҰF1RT$U4"H1Er]v]4nG8t1Ӫ]֠~em-\* 3e8r}ڟ20blU?*z*Q 1WRqɬ$H'ltr͖P:In5E$gNsG0;ޡf88KgڳDֽ`Mgȋ.Cep/qSەhdqZXe$v9Kyd'͂!bFi̜dezӈE4\+um&BUQFk)BHl[!0KGm&ґcUUJmjj 銙[ `S1 4Md⛜@|4 Wzk4('֣Nyp zԵsH˕$JP gEUhj taMckӕθ֋EFW^~\UL`3[%d.dbf}iul뚢BU؊jnU UtjpO?qmԘm ::;V]ik*p\(Rhf]™[XKZFҙ`.hoj;R4L#oȠCNdC)q@ ϥsGc1x"n  fV,B[7g2:0Vmvt-w6#|֟ykrĠ-9Gu >lR3^|>};-'lzM*w4Wp Z`c>֎heq&Egm?\xGPr+¸aO^hp8 u&774 8(aҨґ~ւyY`-QcC"#1Ni~і83Cns@XBrsҚώA#2> PEw [Ql!Oj79; Ǿ>ۻUO Kb8})ƓgK8\3tV`I9m3Y!Vϛ[jASV A9;h' #3ybq2 Lu&c *`pݨLW~0*Cd㊉tMaȦxޑ9{f\8/4zsE4@Sp}BTRn֬Tc#'ܔ5mzXx48@@7lL͡sInTjaJ3@JL zh+@\0{Ԭ09 {t`EY y㠤 H89p8@ >nRaN@ ֶ'[=rjNp@AO-,WeV8`4[:ւn5l8jNEB 2J9f 8jbK2 tu'M/*B PE+g jG&\]EnFE9iWv9CGlS/qgiSO8␄}iXPXgsրw'7N)I$Vn}]Ɔinxa?abPãT3p~f9@{ c1S5wgJ*N1{Աp@apIuRn3R[d_0HV Bᗥ>1TA t.B3ڣ%%L*KrSmme=@4ІyOTfU@ 't#`.T1VKVj ĜdV# R#EePWnTGJv',dDJ'7(ڐX֠N{qU`E$ҭW#{ =g&N -P3 ǾK됇p)D!c!&͹1\usGZY޵QRXQ"iGㅢ2wbx#8IJӂp3NA8q GT v L`ҫ6Pȧ| W5r .1PDpnjd'9$PzS`zbjV}p dLFpM!O/&  @*0p:itgզja AjHjXc֟b$䝣aS v ;Rade3Rsz":1##n֯ AVKt% iM2|ECEsG9\v%)) !/]ӣx:=Msք&NEsՃUn̎?DlFpiaqҽ95TjbmJQ- xWUܣzTA#*XCa`Ǧiwpx=V2"#=d;GbzTŘbu1R3UmBIg 1sZHhR3@GzYB! deSRc3׭Xr*TD̿7F ]U[)̃4?5(PP Qmʧ= $Rg<LUQD#iZZ\߳P{0={fԷY%Gr+]ȲzU˙BKeQcZVt☃1SS${VP|.@ ^f\Q<đ+>U"}*Wg$ҹb]iSJzz!XU*M"A9OfFEcI)Bs+cоU"zR(l0kNSByd4!SR?Jb+*dr*d5=dɍqF)lr+e~魖Y6H;3…Q٧3LcM#$J# =rzcnsOA h9|t, PHl$%dr+TlkfMMf")=4mIخ<`n9jkpBz1Ғ5 5&9$Vd3 TU)Zhb8)N6sp@E(GPsLLpm0i̹Jo= = xC11ڥ=pIX\E}*fR@SH+ӜPRdR#(\(^8$v8&H9SA!chF x 2$q[:T[q5YS21ZvJvdWV7`MJFG ڊ*-vVeYfj)檶p~CZqFx₅JN4$f"UxF1W1K5# W1"$.y(sNN0S(n⯎Ee۾ iF~^i&E) Ҍi(&zscqI}yZC1HSJr k&sCDc*N ָ8B *MH5T+hepEm J5Ey-`k$J:60e *m+E{o d1hKθ;9BC6vlRZ=X}NQLMp&2RQڶ(G )Eltt˸8EN<:r)qUģ{:zIzi<*?1r0٥gsMAɦS\T2\L٩k8eVsj[>H8=)qJzޙqI8<f=i)Ɛ4P0(r($Ls\c(9(&oJp<ўi3;()h <Ԋj4cR/"iqLQZcqH>qL'bz+X F{RvLS$9)5 N*,45!mmJγ~qZIќ 2S3"AjT EF+n>HQAZ$*GZ \!fw$m ITHpQLH4pzӆ1 A)-4sL"yL u L ӾNҀs֎0Jb% 5xz3mMʌcrȮps+֭r pː[V`268Gcth[[BɍFzfYiX2ktt9-b#jqZZ Ax]FX[-~Tc֎XȣFI8f50vOo'JDp6\Sd'&Ei!JPKlcH1C̠*1ڐ7;v7֫Igpˆni\3@BҘ<505;z\T$䜟-ҽIl2د-񇅞Sul3 dRfidvO19a0U Tn<l68ԱՉ-@Q%{B%_rk;#mkҟـt*4%Gy-'۷k׈W^voe8lw}ǥ4R,rѝ=GH+^u?ȓA1k*P93&bzN)S6rN84 6xO&)js|GAKB4 2iT >@TAx38=y &'qSpD\}dEJB`qMA`3@\^gV5~qF!؋;e$|&k.x; ~#cǣ~+#WV͓'AKt`*OZ \zZ+8"[;$J) ԡ1#v"^E'=iRcMfj(aE-m4iwb˷cޮBI'VwdH£e/5Q5H}a5$N:QtO,-ǥ;Jp&朡YEߩ,[Uʆ,xV߀3_M K 砩7oAGC%‚ǩI~`Zh y.؞(sBUBڲkdg* ~doyԳbNqk MNrHwh쥶>Am!ǽ2c9Ry5/ےMڰFq)"ҹ6n 2h2͖>F7FAv5 8qީ2Zۅ=oQ4ٜ OoCe n^a |q[7Zmì{O9_ZqShSi2$ʎ$ J>FI r+RSTHUt@ *P(-R6"(p`tDL m"BH* Z@^3N'ZS5RD"[0┐1@3޴HɶlU@y3QT'dKZDe {U{%@5z0>8O KVrtE(XiңEy/?J+#]ɑ0*(I{V25jd`TH ՚v!sTfG< SHɻ)QtrsJsW0j6zC˚,$nOU$Vk>P]*r@odsEGjf i:ÿ4&H9|'P ѴM=+fdِ6؄qTܷ 60HL O9A"F( x4R:JZ((()i-!PEPHE-µZ*3@B$8d4+KMCQEg(E- $.&f#O;3N37ڄw0sQ9JzXzGԣLa[h9$MPTJRŅ< M3aH+BN}MВ""rCn5jIVc;Unw*TW}Rj *sS4XŢp'JqG=zӇ|݌SxQ2F~cN3S89 ScSrH uJ9?JԹ9(51қZRZSe .kIv MWB d>1x%"J#jY-dcF -BTTiOZr7vWpjv$U ȠSW 槓֠&z)F:A5y뚙TҬ)VQI+9N;aBc"}i*fi9MH0 rXVykN?(DLRz3TdPi3Ҁ㚉3Oҁ~qZP? #[(FV[uno!\4e5r8{TM1Jũ;TXXsd+u;e#\"YY1n 1zi(c@wWY *ݝWO0*WF M$;hċ&O֐NsQ̅2vԊf \g1/֑5Y#jrBT&Xb[')SFϰn`U'kڌGB\Itg .W*D"([^isO\,Z4G #֚9H}hCyGj) bsI@sIgQQJ@ 1K Rg4ܚ?)P4=( "sڔ!R8ڔ PN=h fJy< t USץ Pxaɠ 7b-M4@&sҜE34 ٤l?yzT$`%WqP_[sG@ C\;@qڵgF0iM)EFOd>8fhLE9݂"m+֭ !tRf1mW"mAű<"(^sOs9c֬)ER*Kz G3A+WڣQQ%BIViU` UI4۸$$M*F˱ŕ#$zӤbp*GUd4KĪtsɥW#AꉄYSH5,mkEK[fGR>&t8it[p@Q R="7~)I H$d)b,#90曃C;RN#ʰbFg8hZHw椉c)RlhqJXP=)cH#)UE'/ަnCl*0 R"zԄf$h'֟ЄwCGqHPdSR8sR}("ri!EH@8Jj; x^ f8ggߚC'hfY'8(pí %=,L'g֐79=(p1FpNqL_T~ =Ɣ 6@4>cd0qi49cJUW קJ.Gp)ML;SK 9֫=IǵVmCk徴sDW?D쐩byƼC)Wi'֑i4!GFBs{Wc)m$\(I 'PFŔ.{TAY %ӥ?3fX W\e{*DMKW*\UcdBԒAQ]9ejeZހTvR krOYbSCfm&'aBkBH PV])W#5*vUBsX5 IMڙ&8d4aYz ,:bvAɒs11wjŹ{>~cAЎ3P7|9e ɳ$iԾI-Fj)zR)y@Qާb|7لVtS0yPYE&\>aڡӊ$qA e'oHaSB.~^* 0IRq5fݸj&&]HH8({Sy$SBISS>9 HW<> d.9zP&=M(RG;!xII\TIy=%ڢҩmX|\r=j'7 iI7ڠqprzU"Cn j` sQY@gޕ 8>Hl5+2n1Ua9ZW. }*d֢ۆG ELgj{>i `OC`g(Qmq|B҇{1@95_Mڶq'֮lNS Rʥ= T>y,WZiHXb}K1<,I.Z3]jh-]F{,_l$2<`6sZ]L7+Qn*ipӷ\!@` D2T6=i[4XIǙx1lWF7 %S)VqI"SZ ==1U!٦J Q[/eN .N?EU"TR^ hXX#W p+CMɓ{dThp6srJA$jpHlJ9Z,,?Jd8v4 w,C8/ZB6(jmÚ@&1!\ԇCҜ@=)Z3HqJ8=i\~t>gKd8 R:`9XV'rqX)GzEIY2qwGuj`F"R:5kzڿ68X"d>YÊzlz+]l_=_BqE0XIԪcұQRؤ @ RNJvONhl ~ BG\ I#C !A7B 51NG 7 h) ;\O&n؅=Ŷp A\2fZm%Nz֟wN*wNR B#/1!.ǡ=i'1mc֑Iؤ 3HJȿw&F>'t<'jM; E"M;'v?PK?Ed'&SP6184=p杸YCR4X,Hǵ&9!  'L9`sQd@yAR)mSqU%GPm(ϥ;_A H+1cIx PzFbx֪ď"BN="} 9-5MX  ``,f.O=Ea5 &A G.3Qg5$D3A%T>mҪ[ V#hHlIa_,;V @p9Xvz5Ƀw1B.psL]8(N fFk\D8QEup%QHjR7JuWqU'i:cVتi)ҤJO 5m"ӞuW R TqLzS&Gr!cfVZBޚFӟZ\P1@Ȥ8 Wty[INko_3sBvEf;!.eHp sH 実plyf*L[ŻQ,hUO_jJHA$(w҆Gy cɖ@>C&ܭj(å?b>QNWzPQ 1+8ɐ;SP ̔#[* í2Q5r $! 00+d$}kt>&8ryqV9)9Q!֐1Җ R2(&I@@#[cьg.>R{sEf+'jFR^8,8Z@3lM)AgPid.j r3SVɘyk$'m# zV)RF0iJsZPBXѶOhZ2z HȝdL+fƢ*TQJ$e)~ r3j@OzL @03HRKh{f:R)1#e b/^q@=iWHiJzb'T bwzbfc9bj&` ToJVh2#ң%Ojl&s Œ-MIoxf+Ͳu+ko%1MdHwj^Y|V9x*kߤ"c4+\{[\frsc;ZΒœ׫ZZŲ"YPt=u*r!tnHyd{(vPɫ@ҵ!{7͌rMiG&Ҭ\EQRt݃IkP>uӗ i HSٹA摔]oVd/FAP7.N1D+ cooZ2fK69V-WBP$[RhFR,ԈH\.UϥQ))00:Ҷ zQNhc8)sҀp)3ϵ.E((n(َ4 ,s79⽇A#Qȯ ][՟N՗̐c&RYwGӊ )##!nS-Y،TȨNwfRM1c?wsi1L|wM r;P>8;{Qi0GjSAli^Hpq4#)7@pH5 175dMq 1A94bd㜁@ *}h֗(ҀG)hSҗќ4-/SH)GJv'=J(! ݊x]zUkO/y5h)D֌dg&B ۨi0>QQre|ucN$*r3Ggl ⭭6sަ0rr[<3$)8jf{VV2ud!ݥF )wfs6:`x'4(]iXn֬ @-Y Sc)u*ьqJOQTHlS7Xw@ @4SADF+[c+PKEV1 Y5-ҾE8x1H ];撜ڙfmH8/Y3Iؐt֝3T_M"ju\NR3bu4TcJEКoFTcS5r5AqfzњEL?<HZdjlS)LbxHZ*"E!K4@jL(.*"-j;PRd\tQPP5*bNUf9Ji!HM撁nM5sS @)qUDCDr*?4JC8Q&NJz4pKZ)m"RQNfmVIE1 E4QFhQEQEQEQ3@ EPJ)(@%-%i(&P5;qPlV=ͼVg5< b#T82|W Rѐ_NqҙҚHsH[ZFqU&miqQ3d ('R!X0!(/ )@̓Q;AhG`RGNM>WU%H5&D .q͡7`R2IlSzc x @FOZmnwm椂 vbU$sԨazVJE r*ʨ9=EJ*E? ( JZ(1F)qE(((((() i8c569fL@9qL|w\zM'Y385trRw+cEM89t5zF[7qӚ!Xp95*V(@Q@IiqhRw>n!恊H-N#wSQbjޥwK??#H798HOJ$fv$݃ȦJf4g+M )hn iciN[BeSzE(=+6ABYT'%:g4vcy0jxVu#;zwХpcOwP5 !Oz< 2T*16<;V'˜+_ѹ>2#@K#1җF Fsބ[>zP˞qN]ӵ=791*[.ӰjЈ֡#qW )$rȧ P1"AQ HԒZo2)RpE!e-gL'''8-b5*8*ˌ]Ġb7=G$l!M>6!H͏JCZG&67r{Ӕ3L*a[NRT{DC{!+$j<|T"J~@=%bEUB* y`o[0*z՘/=LS7w`ל0!O^}1y60:I6)ULW^i6T)[Q8n5#Sӭ4o*HAi2ynGWajV5;5szEaE")ZcUV#S|i v^4}3Pґ(!)1TfR Z(*"\̞0Xnzՙ#Q9Y:R5Zղ]BC:ͅƖ)17#˕STӣpyt4SG/uuIA+`[@O͏ZHpҧ(D=VҰb#A-rX7oJ>emj: #lGJܶHw'Wl 0\ S n Up~N>PZVN^ؔ|k7*HeH3 vr0Gj9Z[o˹G ֢NޠaX'Fo>jhG= 攒*Qǥ7^hi@04g.(";4i sM'ڗM=hA3cpj'je"oz ӧ5Yyy54le4]ViȦ&ҩzMq@9S4u{J*Ln<) j=ja2zL֣\i2&8j7' fdE[Y#9fЭ4HS_vxE7b}i @n`_0"v㒼(X! F?f=*BsURPLXmX֛1 'zD0*`c'LOAn*[skƄ/w ק#͢Lp;W w][ݞp)|+k3C+`)L{3Э&/8aIާf[02bs}2Ck?.eNE1(N $cMT' TCYmֆT SXŔ4x3M݄; ]V9)CZr!EsgGYܲț[4l?#o"4 HQI@N8Bm?< iqJ :Ctg R P!Җr(9\"1=OJEP9ZJb(|ż|s]W]afAK ϩR42]E2(My3G+Y7B@sUd{2p[?.juuFe^m̜^i6LWpªm }I5̧*=3#(n#(k9Eĸ3sͶ009qWnUwL` CB([zG:"#7Ε(rԜM/G;&{RP$)a JJ㚮i'4j؜- QI#dsHŰ "dsvlP[m`i!^#83qSžBF\" J:1S^K,qL<HrLbCq@,+yB1 &Z7=#oaJjKCٽ j3g9pIX8#4NN .IpH޵a&IS L1ݦiyLP1HF0t *SRBR)\ ^1 eQHHe4r@j=B yjrι=g#4 FU.qJݐ9)mbꌶG$#-: #pJ@ydl̹.sOVށTu8⪲a;d5LFALޮB{@)8C+'Ӕ`GZr2#ҍ S2*<i8;(ڿޞ9BHp:Յ 嬑5\&m2x{ q xIu# Q(Uў{eۅ&{R񮭖'XcD"'Zkb]D68PhvLVNI+K?%lNƘ%P==JPzU*ij[s]"M7Aޡ3 7Vl4>qK#⦛w)NTx.=MtvzSr #<`420tI\q֧I{9oT0gV;ZxvwJ@(@UM.;]FALzc"9Vl2sUE&)ï4sIi_8i\, Iqxv5QJ3\d%5dkmc񫎂\=^*ApAϵ8hBڃKa)O4ri3ҀysKqH* `:ғsr?p:S9tޘLG' C #5YSGjxM4F rIQT3T\ㅩar̓@-E8r*="l<7p3A݁ց02:QHTeXvS4aO-AM8ϭA<vW3Y's KHj4emfnju6DhQI0Q9+HӢ4*˅}ix&@=sL3 :UWpyɍ9Rg~i(<Wes|( gNޘ3zFa:s\Zqu@˻~}(-1$[4hkn"<*~Uڴcbc FsCfdU{6$z=[P&&!PMyέ^LKHv<U>^HS]%L&pqҼr<]}12wsEʌar2~Xsg |4qob [vQ~VV. PTAf~;Qځ@昅3ڔ4^3֌.##b wu4y ֚j9f*w"q iݨcjΏctcTnsL}vFQ䚰WGҙWddDȍ~ƉqIMJzD b|Ԯ =(P9j]*O.s,QP/!d9)7x'35.9Ӳ3H( 4A ҂H⁊=(4bw<Lnp:Qw$p)q.A!${1M#44q3T6 5FnsxOM>iz[&2K9+;񒒺)ݎj8JۙOҔ TiLC(RNUnx([!!޹⢓k9E@N- ! Oz\'r{zS XvPFvY]zSCQx=24iH,k6dT!ҮAql1hH"'.j9$1 Fe#h95;:%"o.Y[&o0o#~gcV7!݃Ji 袸_5Jr[=k%9*kF̺P}*GYU[ۑ_/ 9AZrܯ)w dš"J21W %qb6dx%_,p* 4e$(@koRAf1^S*t;\lvo΋—e5?-z$j>VPy䶒Oit H`3X:⛦lk0*s5]㜎+Wem٦9'83O;e5QҥB6j,^iZMO4 i*Wq^؛=ibxAhp9aU xa85" z  4z@3ۚ;sGj@sSf)ER''|R ^s@J);҃@NQMNfUYVp0jd hi)1N Cڗ;u$RGJ'zvp)9ddhY"NZ0 gn?*i4JRtGҟZ#'Tr.EIH˚biJ_1 >7#/MQ ,u^j@rSF(/eoțM:k yWMg⬇ _ZɣlޮFuyHiyK)!Tݪ&hb*+;\T,ԊOSZZ`d+OqHpiO^aT$r3HJ3OV@$sV39@b[Swmn9NZHi8YDyi ndb1T+֦taӥF3ґI }ކ)V XpW0CbhC.X $9NxZ&^CdLs|"Z $W3 F@@]0q?%kfU=ibq0q%#h=9Um5HH6UWTeNj u4ĝ jT)5,˂ 1ҙW$(uK ,}h yǥ05\c-C7jU,X̌U4s)j'S TA4Aw N_9 Q+ELT&3I@P@FlU3T%MN[SLP!WA>]aSrQl!R& 3tA= U8;YtWw~f!piɕ :U6O ګu.$رĬ֤ ~`zRE!\8is#=94u8&2bJ|1h9:%_M,ZmIbm[U&g()]yUV}EUY*iϖń{Ո')ɻichN=/J'-2.13 ILaށ֔S#4or83R}"5!- )ѠԼSHR& .qLc"9c'^k<)#^} .*ݒ][p`^fO'CɪZ$ýnZ^p9J #Zvr8E_>'Kۊ*M()i)h(>ԴPYUY7VT+Yhg8$/z84qizS7"1I!ZN3ɥȤMv 3wMRAQIvS$·QI<Ӕ*ĬB i Egd}+II$ 8W찫,\!6g!W=k,K¼ȁ5+׎3t'wdsN`j(+;6q.MZ10`NCb,WhQ; yȷڒ)Vnt6'q2ATrJ:w(%XG|2 aVkMH;ZrOa5Z`˓#mB稡 FndC5E8M^"@>鬒^N֘Xgv*Q/jJi<4(F3ޘ\h49$bX/Eڟv$>kʤ T1N@p1Avqj jYd-UІ=h)!|5PD 3.Zq*<&5 ֐rxH"^P@lVSȦL @)х<)H=h$Lg_tuS&# sXzm(^.)7j2ӿ$P7 ֔/0XpW5Lr;-#$æ:S)ug]eFd!m+ڬp`|jxѶM AI})y@>|x'UdC@AÒjN 9Oep]wֱl`Rr=rIˊIo{S{#oSRdm8<oJʴK{TrHGJ.%##JVPsNqJkNA3ޙȪ$B}ړqaցl=(g4Hi1=TD(/(`xfG4ܑLM$Ҟ׭4JFA]R? m$jHf qQY) M(+ȨToը;qBqhXFA c r)2s P'=)@9xRq4I߃QZbp9H42<(<4sO=9 "'֑֔zR֎ri1^b upO39î(GSir:w3p 4x9 Pyz8 qUqP˾kKqj(!sт!*GuтۓspaV:\ϕ̑x^A/f;EUP\pcgq؆O`S =#`)$1:4 I4#/`*!*FAAFIU!ǵNً0zPUU\IJqVk TfVcKi <qN  :  U'nsRF2OEBQ42,~*1GZS^1L\^ H'֚H2=Io,+GJBd+[K/$MdVj "Z ITE)3 0,Gz\ 6iSU8ދQe4 ,a(Z)HN9l1``W7[1v-z‘Ӝ-j-vZMhM)mLm-##1[ Ȱh[qgrxQUb;dQ 5Ў.I)$8i Vmƫ! N?YDe%呉?(rosBM}+ eS]rqfcQ>!ӵ.flC`꠮r8+YI(䓊\=NCj79(C:s^/5s= 9t4୭a TV8g11ڄ[vV0[\u97v\F1nTd4\ mQV!xJL7؎GtQ{ѩV'4 $*X9HŝednzHX qR`iV,<H#5P(0ЙR=)1j8i(R 3IMfތ( wi)GJoz:{eWA#x8<ьRgf)G#P8 8'i[@!ḩSvE9[ɠ/*7lzQS"?o&j L8KR CrzӼژNX H aKS2ңaFZ's.(]Ң5b4"ɣbj|HsRq36)#֓v*&8wh)udDSPKy_ޟUE|p|S3q-nHdV'/FNS@O3Q8S3NQEPQKI@QEQE4R@(()(-%-PQKI@Q@Q@Q@v)Q1P"&i0jZM ҅\R⁉ѶE7P1Iz@Rmm#ǵ(Z~61i@b 8QZ((-%QEQERQ@(i)pi((((ZJ(E0jB9@QN@HWtFV 82Ojo9ɤ;9OwȫaJT ;5+IJP#84DVlR*⁸Xؒ:Pp)`iFqX){Ӱ*7 P4G#.B@, )AwZv!`AQiASsFR1q: ) X+x.FFr*&J/sB^H8nۀzSƐ dTRaCNLvaLvF $i )s>`)KqցTUl}pe1$Xczc0pp*mp*bTmޕږ59\!pG,]E2xĥOSҤ 8Dj}&:TDp9#f'&GJKH9 &TThl('Eb'bBUI%NI8Hdi<R9Yn9ՇzRb%߃f*,sLgۊI,u?ɦێsMLxv l EZ3; 5Li8JDH8O Q(H3񅟙l:IzB)78cD;Il, Prsֺh|/qNFoѳg sTNGM1onҮCcq5wɉ&8o[AsZBLՊެ8;z4RֵV"VR+fp#Q'@Oyo'ݕIG-W(U\棧OdHmδz0}+P GhCn:lYPkp5u/pw!ŢvPk6د;Vx 8鳔F'ZB ='ILvF:SZ(Ft٧ :63aTѱ2AE5idcpaTC&HQzr)ey+VbjJG+B<`Y ߂a"qMVeӔjK*Ir=YvȢX2>R+d1\<\Tc1އXQN@;^ 3ԀKM~i i$&lSsq4vLtx Ť \{]=*)4'kTcHRy$rjaUd }Z j#"m&s=iTcOv~k''PÆbzP4IE~lS+&Qݞ=*^\g&\ݞiX|5,#(42r{ԑ'QU qnxؒp:fZ @!D'$P[l`$Qk z OQAP(ŷc7]k>) b@=jH2I%K#d;"UA9 U]<*@RF;2F [@Cg|TЪ9c! 2bBJ SK".c sҀp$rP4RҤV '҂Xއڧ@)5]:frW!%P۰p;Ru{SqJr"c+ A Hq]#h)OƂ!c -))2yLwI؜柧t~a,FFF*"եBҹ3C"[j("KI*IL"NibXپMAhr֩*݇F9@Tr8湽Euav" N% օcz5㯥_D ҡQ!y]l97>@%FZ6L&i *,0:R/O^A]eR8 \F;qUU0GZ8A5Idj֣g$ rlJ7 qQFbڅpqQqXQw=N35Hި1da?#SqO1֚6P0sH @MqPRBu[]YՄniwr{SF<:[l0xe \Xi,<~C5:5xە8ӾېysPhrFHiwcBuy$9iȦ1K攜vQRҐΝi~jRF3@4)3*Mݞ[pqT`98=3HOJji$P[ ^:gz9鶗i1{ 6})FwzpU񚁀r17zRRnvy5r `wZYx8 $b`&f9GBA n G*JɄ8窐L;:DhN늱pR$7sMx)"v6t 8ެbށX#(9>7o#W* ֒Y.@9 8ah C4e)A9PIL0zA@im9#Ox#uAݚrN}鱠V摛sj0,BRJQ<)QLɆ+v1Rp1PIS$h h-Ҏ3( #ۃȪT8@&$3ނt8YT1U.MҺ['EY75?| 3m5f"?sPyHGALdepAҐ#HF֞W"#$Nv65c9jV 0LE#@1` E<"BDkքB8TqK ;8ZVݴ㹧`֑hzF*UPwL =GAP1He{cҳQAI9fM!XM#h#Ujԁm`u*<94ȱ#j4Mf84UP r-<-37`p\Ԋl p(Z]q )ES0S((PtQJ(sFi((C@\IK@&)hb((((J1KE7m(((((((((( 1J(EQEQEQE.i( ( ( ( ( ()iTE!L#LE7ER0(q~𴢔 qP^D{US$ȘP gX*0b]R#4A!xbl @* [|*6 HEOjUxDM!6<-O0t4e}x4`1֖Aq9@*\ MNOFxe`{U;"gZ( ҫqUI.iS1=)X{e Kj.yӂ_)AZ*/`A1WW6HDF_nF1֫|ޕ?rÆ' ށ8qRޠo<{nE5T*MTm#ӽJ֣f,vhty+509[,{TĐ E-BR,`ph =ެŖ85(UgD,TT}N栆InJqA,a[`19HrMFA$Ռ c֚ ~RCrz.T`/J6$₉d z;"rH Gm1l@\F@QOC*#0n9bNTycW'5m%D_#&o85au*=jZ)f㊴u^,0""Ev(>L R/Ml0Jc5F|eq8>5u `YrL7'W5Ue|qEJP鈺$$R[Vߐ9i2qڀ$\#g*&ϭ"UbO4̐Չ> j.MEqS9L*4H@x fC&c=h4x◵1FZ^hA &4'C4g'CZ;vpjTp>><`Bh҆]XuEnpjhTg()`29K jaQIs?zW^zW"GLf}BF>XOFN\ƶlcջ F#\eێJa(I!J쒸Hizp($F7/xҞ#sGSS B#W@'!R ɥ 3NQ֚wOQ4"hڿZ)ֆd{WWTs`̄e;jQGj k sZ喖,\~%H8~x橖 H^4\$K%Ē\e4 xlQsEcBpxQ+ Uc"3ކa#A╭$ gl0JƂd.ZڣMC5rS9vO-›q\ԗ))H9t8&R+: <3qUbcAVUdSփ[)M݅> F9v=J 6Q2ҙbf'M%@XqUpyX .R1g^[,eQq@Y b{MA4XNB9!M3-DXx 1_ZC1)y;0[(:c2]H>rY,`qPܲiӍƩ~v\Wjav@d1^()1n1f\ۗD/ jU:(ozUV a%. M ɒy*FrwX4/(8HBA4S(d9 "wdb<-*KmZh 3PsJ҅?1UZB6 3qE4˸ޕ=-҂ %j[XF ΢p7>,^ղǞjK?jׇ"u3" .TK.!eH;iJm4=&;ݹ䑟镧c7RLbAd(؄ݩXdP84ljR҃[sAq@Uc/bnirQTf{hFqV\)9U%r)F Y9Qe 3UΒS7'ޕSD0E0$iZ.ciXOgv;p+XI1<h p㊢?{v -Y3ұo(&ʿthjD8w֎4>?9*( I"lQ{ž*$t>èA?cex<׈* lDaK3H[gh&TW=pk4F;ddB5{ ^ Q0*$Fy j jL9NIMeuy9+%x-Hi)EU'җB` ffRҟ3o|v t(teOTC,qOJhS.: jzaebHEJ›E@qG4 ^0Ȣ]=# qM1R2; 6Un!*R(PHzh/ZޡLVcLU'zAƠ-8 )s@())iq@86@&)i\IK@Q@Q@(1F( QE%()sIE-QEQEfJ(qF( Q(R⒖ (IJi(J( R(%- њJ(-%-%(QECE-%QEQEQJ(%-%bZLQKI@.)-Q@ EPf)(4A41 %)4bIE-8SE-(S;H7j iaWT.*X=2yHr=j?3#iNIԷ"YwFc #XDъub oŸ-|)6ce^sɕVhvQV m\rrXW[GQ@J:cN PU4,zR9ԫy{ќƖsp̘Eh]nn*>s`c4i$:+R6pثk\oZjpT \92H·Q9 1RbdA:tL9c꾕d hPrz.b@ҠhM_#j&u]ES1w!2 xgPNyejw#u h F2.uz2 U}Itbs:%spa=yQjC.+J"PdAݑndjVʹۻSjy,L@gҪA44Lۻ\)]rV,YA'Ҳ8;|բLc#hʢ,*H};TJĀTԃ'Zg<v)j޵"F Zf2F ѩNvk<IۜS<]꛳;sޝ2i W)"wW 6=*hfglU_iHWE\t4*3֪/=@E;d\֢ Iw&!b~ԍݞhMM| ֤V ǎ)^BTsL=i 1qH4@sސ@;9NP RqZaliˊ2})HuޘqGg4c#)t}1MnhPqQ)ޔ(oz_3IS859yiI=M)$L(^O9`c&yHG=i'4=1@ #4sB3ny@M.I4q@xH)<#rzvrzP2:ў b&& <M>6'4G+V7;X zs\sqζ-D T1JʮXpiAirFE3#ַ6+tI( -i& jZ7S25v|Z"[1DԛBOk`nvFuq@s%yrp}#'rm5M񜊄@Qi zBަ(:sRmڣց9 #<9@1HA P7u 8`ǵ7;fb%YQT&hDUR?-&0@ nCȢܬ6 te32qڨy&g' aU@>$ Ď.c[b.%I°@rI&J~.fXo''NH=*sE-jBC 3MK *!pµ&T5HMZBB3DpۊfFޙ1y543 1]HpQOIZq.YN{tFV0=w֗ A# Ob{w]JЮ5sl֪K#m恊imwc  3L]ǥZI @ry _TĜza/'@늍2@'BRdfp W`-I+ <= "CzQ;VެM|;P',P±Y< #Ʀy|kU R1PF*pK`h ;p;ҙb֗niZv(u9Jaqgҟ^;ژ*ځ\re=Jp:ѻc#+zV^3cYI,e T]Hv[NќSH(\`ڞ'VH`֞ b)k,4E2f䟻ցs, (BrN*#x$zvr#ZjB{PK)E;ƬG s mTc {T$.@` zք#+tkR2ʏ=)֕G,@#\)1E$IsQdeQZ܉,ݧPJBxM sDL'8,j TyenE"n7((Uܤc1a`0iیGZVpx" *ǑPۉ`R;Gȫ*`R7{SVi844avpi횕`w`OҀQ1.@<5FmpJ&_I4bV\ڢ9S׊*'iCВx40*$ W*jT'2M96F'O# pj*~njv>v9))E<ԟxTQڬ3sPH&6HWmIc m)'%M+ 2zvzP}h$Abn#9E 8@QG9-4p=N3֘v_}6:rY Gn ̤ɧb׎d( xHH8DR})1}{9Jg84g (Z ;h\ *hҨ 4ih^O+HZcކ4pzR!xsA`J(T0I4v듑P*֕{@ܙ= -I@V`)HPL9*>Oz*9"8)44TTDӆb84Ґ()Z(Rެ9U5,lj^*w]p0qYtLLU*@h)*%n)[f;蛥djrya}6Vtj@ 4GvEUsD$C#(hf#j%>KLk(d$qZWmݫ-Iۜ4␐:Qh4!TnIH,3$J JV88 SjK*eOJr)C=i3HO4רH4 ( U&0(zbyN&HCIRyR RS!\R*Tc(84*#5**qQ9^WUfuf8jᵴJ\zq\r[ KmEEݣ3Zn8j`pos {]EiC.'5Mҷf(&WJb*#hGʙNBӀ4 Ou86&.=iJh{t$P">sC&d jU wT3)z̛#dɬLH6f<3 KG]9\ [iqP~e9]vMA.A ܲEPF|끎eP.ܪQ0;isރF=RJ Ti<I!V`r0'_Hn:ФS$ux43g.Q"Àj".iҸ9L9SҞ4 yCxrj]8P2)9AQ"Trrx>ʌ0&rIéNTqLj`Xgn^ H?Ԩ&24!JIPq>O*ECdrU0=TP{sEl8x.6M< v;4C9:wPicqFF)|{S) `pj\/SIq`C㡩@a}@ ڤi?vmA@dlp*FE!R@~Rj@IQkI̶Hdv6O.dhON%rg*l؊\}ّ!O7Y 'yvB2)0S٣Y SoT0bFգQ,3R k |.ړF,pdq Q$d:Qǭ='A,Ԋ*M"n*G"{g< w)YGZ" ׵#5oƦR0xй$1VR9Nzd*N4fid:%ުZ?Z;pFzR3a}iG4@rgb)X^3;ڮ9)8L@gڬ({ֈ``XA1F2ICW?18n|?٥tc}EVկ<9Av::%^.}x7ҘIlSI=;PE4+n9b<(L!S@G5N(`Sd Qrh:c"pj 8=ipsL.U &ʊFs !AMK2c\3<# dAje;{R'$1㞢F!s4bCqh` sc&!Yr)IlwSִCd5]p>Ck oB3AQY8> 5(sFf-& 35~[GJ}!x4@h\4r8 |k֚F-O~&'YeX<IQgs1a*GZVPF)M?/jЍp)ێ(iWQEY( ( MHp(ipiƘZ()3@ HM&qL$RRˊ=EDˎ@O6r{ f@<7) )ljټG*0]\1Mj#aGҳ` 0یւp0k֢x$,8P)2x4[m[MPr21MhcIsA@ԅxw)\`FXt=)8R84pDUQHnMNŋL~E"298kFPePc#zT%U'MbDI@Nd Cmk@zVQcoˀE:L*RKpxUcT₹U F5Z+$R?Ê曜V9P@Jwn ^wڸźC #zjᄅYaV. ȤRyu5m yxT"a ݃z *4L<昤}($LĔڗ$hqN>{P@^h?'h8S 8O;捸iw4$1aү44p:Rnu@#)8 ci@M4czSBt`R Kj:R)=金ALQCtzJ>" @#r *8B*njѷ MZHGIVc q!V`WbɌlް 7c׽D鑳ƕP)ҜpIyJ3(ޗ#9@4gh;5ƌ7͚22N*.酋Q\8}مe OcLt P*r2ֹ/^PG .ʑک3ڣV6F8Tq.WW䶨vDtp<ю)qQ#uj64 c.[^iSr%vRl֜.Ksp !,$Hrj)d隆θFP X `|zT0廎ǽA| Ӄ+6UչJmR݈c@/h +~}\n 6;v 1Q⚭Fy5+3u[ac]T\# ^Fyǰ ڭlwHԎfKdo| Ͻ^[3IzP6Ѡ(F:Tx/Tx<;BHO8$Hrh$2Jj=Q@lfqR۱R`g&4󞂝e|ӎ3zPAFϛ8"c?Jq TCP6"PP;S€O=zqހ]NXmz$`$ "F~GJ~ˌ!; *i9RG_JiEkdBLrHA9jp@O)a@mQμn+ILf(,ޫiywS#/y\0>Ӏ}&P4w#c;#54 -P3Xw @*7ӥ]o͢7*R2?zΤ_e$6Fi8*+.W;z#;jǭ(6E5-ȧL>Rr :œw; rAQ 㩡I 5j5T s><j, ŖA&wڭ%2J7#?-JIcp*% ` @ )8iNzPI)`15 {qLBɠkqMiSJB:j@jTl=j5Qi4 E O^dxHqehEyiGW! l qny;ӏ s'Xr L 3ɦK=ii1hِ(:RHHGSp: `G⟱1XP{SY!=iH iF;zP e&@h 瞔1(V*{zR!q@w.`u3C0$@#Mkj%,Yp@ [A*QJ26*\d ֙`SJEZ^G٧L`!0)[֐`6(5A'4"x4;'IP8ҔUt?Q3dR#(Pi@v=)Lӳ*ҞQI) OHvT(xcW*d-[zDH)iŸVE3LȠ;PbZ9EDNJTnapy#w4J4OCRLn NY5Ȗ!SO.=B7"^XN9SA]8($?vx皈s`(#9;63?C)=6RbsH~~vQJ q, a 'c'=j)[ #OFq֘R`X,8U_*X"EɡYJ)UAA=ぷ!o=THxp=(bBq&JjA8=i1@8')HgCr2i1ic曖TRHQ5 @==";I#!۽!Nh#8 {҂;4*v>AHM A"rN:Ү x(g'511 Fj#F;T9Қsߥ!'ksP1ݹ*gE3z C/zU<J`z`6ysQ6qK7ph$ LRqH82pWW) /X [Bȥ%=w\ȅ>1J d,]~D}p21`gUY=jXc(Pr09.sJE0*FM @1"he`F9&gH5UU2M,O@j3:/=ZD^cx˶ KTD\ ~%mY-Fwq23.۴NV` U;4qF @M;($_ {RLx=?-[RT(!*ɠcqݓ?3LDSl7BUyv7Y99Re#>< OLXP@4MP挜 CSZa`zf[Ő!8I\tJdy dfPSSSTHu2-ėϜ*sџK.G,kGٌEmp*8?/J@H i3MAHNLPzUYS[PFA"T  Rڠ zJJE@O2Cl[>*GVd:qA-@?Hh$f~a9+qOEq0w+wZqsqR b c@~]ǷjM!ި^ye ֹvUGmc=qYv7E-`86qR9$W+['-ov1lQUxrU8Gp?S2GJr樁ÒiNx)sLC3HI` bi9&=(@I< 4P=(ւx 1ҙ!$t!e44`SM/9iO_z`NPiM\өJzBZpW 84!7d3Y(M[[Rfn%.*OQ/zfLS$c94\9K=jJ:*ǚ۵ԙqf!c7 G )$Rԕ r9dBOI=(MߎzT*N{S2K9= Ph"ęɧd*-s1Pi3JzP!Jf)͞)1CCO#48ₐiAPE&E4MM4;4 BiGJu(pN\rjuTH8VTcLNQOmgvD-<5UQ@4X4jALh.h(!4  a4 4.iQz$ZxA#JZ(((((E()q@ E.( Fh4QEQERQEQEQEQEQEQEQE.(( Q@&iM4 A4An))-IBZCbe7W).iA5L 8T@h3hSA )hiS6#4Ʃ^j75)/ҚLczRi0yAjz&>^:3zRKҀr(c(dQ H&1҃sH9(o9IzR4h:)'@'Ҁi=ԠG;OfsKPHM=ES( ELaPLhlӸCT8ڞH+Қ0L>2gғ4 h҃)c;0wqHzF;S8Fz"6Njc9,9TFtQqVc GN)IZ3($x=*ݿ,sUTr*{4!3R3+0l0j kC ]d f3K,EXi4v$ӿ(Ni(>ZCpP$rIPRF)nx4cL槢 i.5Ti0F=H6LTf? 8){|ب5cbHV336W!Owqj6o*H*y22@)xNEf(x#s j6\Luu ~1o::Uttgc˧$.@oƱm2ŇvAGcAuDyMz 3mOiZ%Rps[w3 ~cHMڜ>ט=꼞!nK+ҋ6th8>Sd\ # 3P+y9wX=:pC|*rvBoǹ1O.ō" GS,WgdgDS0ÜrU얐: Y1۽{Rcv%V-Nb(xʞhH4RswSZb(۷0.rG^iy4 N .hhj/A$!RBJF$8NFfs7VXO58'f8r"*A<  *.NzR 798z %??9`qKѺҒs#}T`ds{5y4kc"40Os@.FpLBcPȸT^1L` 82piEC88nح!e*Oqb ~M"eYC "f c8LV,)8yNED wLY{f,y73y`ɪ0FЎfL)in ֪~ՕqsL62~oZvќR\bTP@)y<(8cP9S@' c8/2G#Bw6;f"֑mvCIf Ej7$aq[*9$MNj5YGC"4N=HJ*%uI*#q1Hr1jUgL |Vy.2iy0Ӕ{3cSU"@zC(il1L8is0bMi݁pjU /Js+x(4^F9@ .3@i ɧǥ ӌP)M N1@\@ ir}iZ?'֌iM<uˌ{ը{PL.>ZVH1Hƴ2# E ,sK;|g>%WBSR)<)h%@9F ڪ][BI-utSWNqS#hk&3 T"B8敍.F@R=SvxU4 HiUS$B=*[i|'GQ94R9Sd*>ZJTdF'=Ԑ\aE[ ;fHfM܌ZY3ڢPbɤm30Ru44~430h&54nhRaWk!X[=i$59*NшFG@BLFE&\Ku0 Sϵ3PҒqL< ޥI3U zrNqҦD8ViV&ǭ(q@ 31í;7Ҋ-6i(R>P44ӥKL"IMSM'4cS|J';G5/9PF)3b'QK\`8SqC:͐1I1r'W`tRv*)_/鈫,#I* +z͝E|Z 5]J8zdRNy4ɃdL22`>cހ$=y4)y1x4)[9$kAh#jJhcИk*4ѸtEL A<4YYsMb SqKd@9&Gu2gZnE2SV$?jxP3ɩ)cv{UHOIf5#@gM qql A= C Gҍҁiv4qO$n0MmЊls@#<h=ȹ8jf &>rE]i(pHb`WF`,85UkiQ\GcS;K.$[1=i4 Kr3+-޳0mg :Й(siFC)-SL N'=)^IP1B!`Oѐ@LW5'ZcKPb@H444cBiOCIK@ SiN?<ӰiRSHDn~\U_5n@ y@3DL*Bz bSr31jxk RإzOrHk6YI4הPwUq$!lLL#PӊF1FAƛQ@ÐO4)# FpEw֎ M=NisN'1Җ3LlHU@svs4 pԀ=< P!8dsLAOzWQ-&呋R=;ף_rHaOEVI"qka@lgxh&:L֤/'08_dT[SkKBmX'3Z(e#q\>a5S16Y(T>3U|RO4NZpRI=i~4~hyk3ہڙ([Wq'ʋ RwDQ{S'yP'nݕ < CӆLvnPq]o[_\[QZ@pvfV=rTI(iD'nD1*,*8fg4 IiAP]JOQA֑u9?xt?E G$\LFI+ԛ[wA/f 5I4g0%r8.L2 8 FiBIN7z:1^ʌI֮Η`c}k7NHkKw\*nD(ؾz$ͶMm* GR11U\Mg@%)ґ%4$#8X:<oX$2h$aWy7cg$[! H+tbG+6>觅cT-00M0<})s/^A>\28Th$IaN=i0*ri]9Qŵ13SE*) @HG=x47,nɨTv(ʞ&q527l&㩥$V>uo\ˊb qIޔ}iS&8)GJF' Rd!X3Aӥ@ .ss#3#Zz14Q;玔$сk<;Ec8=Yr$ۏ|׺XB"l b1C7X-M%jsaIOn9JGvcNRzIi6nHI J4(2Y <sJB6iO֘ʤs@`P`zfnx`B)sH[\1tFiGf˻~)9=ڕNUpUph .A<1Ȫ S@N;rFs\f%(޴7TLs@abOZXbJIE%͕X0Zf H!Ȩ_C4SLBozi "V@æ}pIb38^h7$p8IHqmmÚ`|R7ʹBAR- bT+R2>QO=h.(ҚWpRrF}(JBGzI;L&%@¥lQ<\g"ДUeGT^bIHi~i~^2*P枻 E" Nǡ(]OF21@}=h8=i֤ہi4 67MT;x8R>' 4ϭF8'ցRElG%81HfT8|㊮@&pTV]؊&jYerObUSHݱH72J&غܵ9\TRjùCѫ(H@OqJdjF3TG94䙤Sãܙ|6mQڨdϥ/E2^G4l)(F w3Eܠ\QʹT#&[R1E+r)SM-56GzOZC&r)9*G5v dC?pS:L&nՉ48jn/p I4摲E#vm$ԎNxޫ8vjQɤ; P8(4@HrH)oh+֤=#wM"JC8'9qARܕFޤ17M8ӭE ˌS E!_֐3=@_?5=S8٦!ey4;6O4wCn47,9\ZB9hătHJAJ8&I Cs@}4e`R K@0 uc"1F控4'J*)|3@t(nI0fvN(p3PqPs@ @nzS0;@01柵GZB2`GMc0CƼɭ]EeuVV;P&.{ui"Ǘ#׾*YJy0Zʊ7/ZB4U#Xpj iȜjLqL"Τh2"(6)\0AGV 0[1L1W#&yR*mmT֧*3Q)rNnr(J4ӌRf9ݓqH=iï47!`S3N3@ ) #)#i8qZLH&Hn ~I'LPw L(ڤ (2 n*E鞴qH4KHFiwdSx#(ujpqiF";5;v֐oL ddsڙtݎYFz3e?/;V#'p%MmJ1HV4mYuܠ=M1L cwgNPқaU۵V>[JVleYfM4pVE+sҥMª)+{1aLĉ:Rw0`;Mg F9i(0=i&>G4=K5m$Yqk^wkFpq^qX>yrїMjifr)xe+H~\ƙ\p(TFrȬsm-VTN RO4R):ѸOPR⁈:Rb @NzPN8J֐p)B - 4GJBFiugzG4FWMbaCPL/TAoJx  $2`ߍH(I&q4y .*eEgQIЌ0A%Tl&iD)ݑ橍vUZe2 ȥ&#zRc*rE7ȤPy4 9'^=j6aiz44qO^W4bzPQUiK1@ 3~0)O-8▀ \ 2hs>4HzPEiBQYVHG4$E;BM8=j۾QTJDq94tsTQf$U yXB>eēJ2q*6Ư Z}\1.k3 >Qp/ R@3PuI'#R/s =JĒ&Sǽ+F–4PFzRg=(L NiPM&i 78n ZuD8VPǟJZ3cs^ 1JU W,Po$ `Xԍn6S3-Jjym^k:ՔG.2THFi`*MHÂ8I,h sNڮGbX@) 5bK_⪟ց^ZBr:7 pM1ʤ**E.2qEU爓P4DҕDV, N*c)ݘqJ󢳌N*(bҴ S>#4!l8Xa֯T$#0\V&;J:i)O"(c4tiO4Rd=ehiԀR8z*<42*`TA4|d^plw'Jq,nsKPKD 8P!@@( VXnZNRe"MV>?'$Q4#~OvF*CiLhoNxAG5&qA-K84(&Kfis@f3@&I&3M>AK@ IERJQ@%-%bZJZ(RJ)i((Z((ZJ(()h()i(;Q@ E%RRaaQWY 洜rEP"X+{PWd֘mJXHI*ɷ xJwjsnwf4/HRG MH.f3VEQB}*m fl"Z*tS2c;4R($p.i:ҁ \68,8a48)sMRiԪqyp2)W:;9+ђ?7AU%Zk q})8挍ԇccK) 4yRr7L~4)@Zf=HF40T"Yoh/8^j@45҂6;. qKp)Ör)\.C#ciԀ8; ^h;8҃qHԤzC);P`*qҒ QiP@50RHh<*!FsFchҌzNQf'tJq!=( 9񎧚bO=*@G&F9g< bc8ɥ99B L)H*7o=zUsLh@A2ҨJ~e db>|1J|ҥY.)ϔd(O5VBHd.FЫaqH#H F:pEc4'2DWoi%Y$dqҟ0]O&f*{Uyt\צxRpEhz\Cs_SEFG=.~E4= v6Im4_fqDaW<2*wc1Yu>k"Y^NLR,JT~5vBmU,Q{Twu6G>'#p>pyƍu,klpһK@84w-89O֟Tq azR03OnF)@GJId(f@ҧvOJp!7ӥeiqg)|V)Ho"T-ɫJ+b;k #9 猚TW4`H=8evS1jġsOP)#~x!nK3QnN^ԛs85P%y#aj4djp1A9AMCHr)sLl񎔻hȠy iw~T &ҧp#n f!Ƞ :zS5 rn!֚=OJJ2z@QQe`{Ulʚz:SntȠycCpܝ4wA8Mog. 􅹥ݓu14n#5(ŰZS0f,ySM/R@JӊU'POJpH 3IF(IsK@ GEQ(I@ ~!Qph I9$LSa8491y6yVAΛHbN(-σڟJXy xeC6OҚXHp84F:qRC.HC1TBN9,I)3Q:04Ŏ5*3'Zi`'āqҥV*b9c}f&N .TUF2$QNȤ^ڨ`qڮY/L2<4TNE`M~cFI77ciUVmVPf$PT3(~rqW-pk3ݼN $6ӈA``0wJͻM:֑jr4 izP(أ~(4.q*IR+1X{(=Q*@ri{4L<H"X\Q` `,~6) v%ȍcmQMƁN)Zk3M&xM 4/RҎhi3Fir:2j^h)2"1ڊtp)y=h: 1Iր$ ޞqځJXU. ;R^ "O=).=o4L.0 $lӶ)SM@ q" VʷZbqK}M8sNa\:INxDli7cKS1}i1¨:.OJ`.jc$OU!i_S>/jX!_~qv¬OjtW2+7+G5]-ݹhkQ2r@L̟;qNjN皴b  j\@d1M>):(O<).ss@e#4yjLҐ㊛`1SNSqqIi ҧ"c6*#VLjdp9S2[h,N)0g5 u+dS3L `R4B Vc^I90HHF8QԄj&rN6% -4惜R,@{c^ x\ w"\Bp!N(i:T23Aց LS֝h^M/A<@ Ow>iGLM8旿4IҞ4tc[4)1H&\LZv9CS\n694Iޘ1%zTf@/ztBpp:RDO'ԫ whFiAhҔ7lPqJ9":8 =h89`hun ;@zSGC@ Q);A"ucGJ;qIE($h< F)zjg㚖ޔqK΅9=h!J 9!2Ɯ09L<bcsG I$TQJAif]%zdd$tBPgH5fUlfgzlx#KMK̍cܠ|0)wX\ViTnma)dp5Eu"BN=M[[||.1Q?nQ[e}&hD[Sea Q*XLqVl\1G0o -ڧM|0OjÊ0+j ݰ9)PI~*T.7U5pzR+\Ks'Kx絏2IweSH%*0;mcscwn$Lcu)@MRMI]xrN{mJ#X2k4X$[6[d X}:l!Pۖƀua^ m¢i=pAU&)b9)ASO=F)pCcېh$$0jUf8.6*U8wa/*)K5eA`*Yip$go'!8H)fjtG$t#o2s`7;Rv-|!x؜az^Bz//ҁ;v8L'hl Xhr79*#4i+Gֹ{ĩmjVCNƱ>#{k"cץ0|dq悋"&}h<)Ӂi0qS.1Ҁ) |78Fi=€h$SPzi$dN WSQ4i0zLnGQQjb:( H٫,yaȤZcăiDsU< 1N,t]Aޝ֪yUIj@TR 94X7xUycң OFNeLFӈ)L!$R1GQJzS6'dc,)LbD~F0=_oӚ;QڂpqAHXdShf- J0FJ/*2+T9)j۵X$}t1Y F0*-pӝ-H0΁s~dZ)lI ~r95e#!cќo`J?X:mͳd.jR^EiY%E$t0{SZU*>B +a]ʮi.AORnQt{;d`ڤ-Ur鑷0gh3RdbNN*ti~ٸV}9a4LޑzSҨn2;VdS7?JJɝwY|iU;ȇܪI;G4}M;vzԚ"bȤ!Z*9H杴R)WbUx-T hM48V(*jǼ'J| @r1cg jM##;R$RJ975mRLjK;Ӂ sOӹ8b)P@ӹ&@4N@<{R\AQҤF9a4 ӁJ@0i1DpsJmⓁ֥FNsJ@(A49W9ҍå Jb OHFsK3LLFrj6x1'q"Ih `uaqW11G~Vv)̓L4 y "=jT}}+#>_,槂%da,pUWq=}(ӧS*hFV5,pßZ;9ULE P75b0ZϹi/ H >b84H WdeRrsڬ:uCs @g5rrZm3q4y\0~2j` lfhzSqHZCB =)`r&L[NYn-VcW zWTV65iB}H%9`Ҷ-mv\% N81ZԂ=&'YX7nƥ5i:Ť'bcJbdUs˫EiZaqfi4 Q9"&44n8"lgx A 1^`qP7#p1@LkYDQ\CX<׮zjNץyNfw8&wW6Zd5d WxR@ur>Zq xZLS|cbG&i;Ff@Z1@) p\8Hk`>e=j WORJ:xY*bV# m*8)I=ւXQ1R+|40gg>'ӧ]*XNE8 P)aK9V%9<ަd$@Àxm;ҏ0ԡwJo&28N\V)ǑI24H)¬1HȌ0SW+BMWItʋS/qP?#?n3Qҗ*)Us Uyt8 ߞF4'']mpjU@POZ E6 U*yMY.\v5He1 5Mi:y +Q[sM<-G"LS@lSUhd9= m4i Ì ?a *Z5LHiz`&Ҧ?TxSni .:T1`QE! `T55# Li Va@q]dR}TeN}lu*0):FŁF)jwd%m!&FNsLVE)ej)qsEqE0֍UvqrGy8⓭BɤRHKETg9Q.Fx3@S)f҆ z恏&h@LR .)J( )i4c4bZbb8L.'S@\ 8GKhUț)ҷ:E!NSPqs&*2RoaǞ*0AJW"\ԡF1A`pRN6fEDdSJԄSMDV4)TqHb8 P)P!H8 bJ(-1(RR))i( ( ( ( ( (PERRPEPEPEPEPE&i 4)3Fh斛\IK@ E RPISI@ M"IC#5 S`s@28{TF: /4 yȨcUY#PRa֚~9]d8sN)BӂzP+jF qMFX3U,pTQ:C p֢4z%ᒘph ER%.zV84h 5.2!@\bӲU=XM4pE 2zP欦 ->.vq:Qw|=*۩Q֦7(k ~u亴{#kcD'fCt:dqGm&il vA޺I&֯CH`4'zR;F'Rg"QQҎ0h<19nDHdTQ`N3<@ f4t+՟\miOdgqNTR50b$(OݒIP3#"Eb@Vfk|,i{cHFRyStr1P|)'5fR ^h)]LkC*_5rGOJi!*ֲ.]ehqYUjY? B\#Ff-9rָ]_;)'+;"<➁8{ r)'XFa !z¼(Rك#JdR ' ɩgڀ*<SS y.)vp|bp)8 Th~LӃqH 6İ% ZaȪ6SI"9;c uhiC6E[FɬhkJ)3L"J)b*ŽRgùsZmjMK*,31M1[0晳HH#hsVvJ6P>bÞi|S捔1_j6Mo4 {yzTq@@55`i4S=*DR2R CL TTKiz7֌IIwz7R!@sLM(L) 8Bm4`bƗS < ||"ԅʬZqWqŌ=iғL>D'(3$Ԩ**ub92L*T(2lRasS ֜%< @()bQLAE-%QE- %Q@Q@-%-QE (((((( ( ( nih&M!8PHZ/ǭMތ"@iwњ5;uK\[Cq@Fj0sO4ѓKQh*30I$;E7xOSN  pJvPm01f £3֕Y,*9J֢i:E(A\r*8H'=Ej'Tk)#KgBVȩ7hxyJ4,k3c`޴;i1ӑ=EDNjQ aqs :ӃDqqA9f 9bhmӥ)8M\i f)4 ]4&b(=jhrDZd;\}*HdR3Un#<'(6IDY^H%{SKws(1珥21S`:ӹ%Mj5sTDXv)h(ϨBHT Җ=bG4284sڎ:vgh݁ҁ x搚BI!y(zRR)8< c)!h%aKp28 0(l() 1ӥ1##&~I qMi cKש3Hj>:ӤltKL (U'L*灃;3"* <.6=r9d;KS֥+W,RnbJ=p(ңYUpT*MG>j?QVLhϽR+i35bFq! -`Ui E%78+7(INKVre@X@A^VBMZeKyZщA&qN6dvj9 nԄr8CnFEr X:f+}.@n*- ⦙9Yex3qimoM: 2 uݞ԰޻Tez՝TvZ|V-@i⹍&p zW@$&HZU4YLT83Q!cڌRt31E!$JO1H֘zUIlك<`VdcrH$\zRgM=0EzRi#ċާp-#-֤ZeP &vfuH2j%Hמ*yHWAm"C`o&mZu#JbQ)j(O'ҳ'RJg5$ϖ"uMP2sX3%sfoo/L/<_9 +*0 a s*$[ ^a^23YG?-a^:'bf `5bȲCP5agZ))z H@HM4^)<psS$?#Hfzұp84!ʹ5b$DQ &9VUzT8b S8PC RE RRj6< 0&sR1íf6@8 (lђ8)(QPUI9sp2iJ4ހ'5~^8Z2&u+iv?ʓظnd.i$4u7 0 ".XOz[}^ kͭs|ɞ,D!G}BLw&I9CIaTudXq5ԧR3+I^#䄻7-e|FȩU"vU8b`:e8c' 7JҔ}nnPk,*QUZխztbkMkڎ>*lp icwjBsӥ0!bS7㩦9tM,7SLS!sc@@z ~AIcsP |v@i7S/^mRC@ 4 a8sIriOޱ/8Ԙ֓57&7T yJ^f 4W|:W*vR{_.Ak8(ldc0B9[1'MFn4F@TsXir={У8+IҤ z5T(1lg;yҍPTyPj5.4`R`ӻ׊pM140vZ $i080@J P2kd*@2Ը}h 1JN8@\3ɤ+sM9Q۵N) ǥ8@\3z9Qz徔lx=qT=i㞴c1KS7sJ7sb'|`S7~:4AF)W=i)\ I @ONqIsA} Z7rF)8b98B0Jx4ȠdnGB8ݩnFс1֓`30F[4m,xfJ D2u4M+҆zM w#֗xcJw␱)u'֐SA4=XpBvH_"FSr5OF~fԁ cR$ sHwFf"*E*ȧwKa -+sP tLu496HAPe!)rz4&H#Pw b܌fM8Sll*֚ҢoxV`XWh9VJHڳlS.3#9\ѩKVę"!g+8ٳʐy{sMQ sJO5AF})zc9`jeg =*Ftɦ*v1GVO\T+Ͻh 11ԦM҇DJ5{'W-KQlEj[{WSe`.0)4qT f=xyHPĂj.w%JK4ۆhدq@u8۫/< PEGKڠYnO8UsF݉659MLrփ6p8Cq88"I2OJp=iSH@0”)@Jrhf(Ԡ(=iB /h ?qu`@sMN/0t,Q #%a@ɪ\|֙blӀQ48L))N}í ږq@ϭ H4QΊ(h--%0 d枹-D*09-X<6US!=+"G=qȆ3ׯQf(T}iV]kFkES\cG:)[?@NZNdcvJyN1 B`gN)z\qց%`x1`sUbsrdzU` iM8 ZPjLz\MjAiXÌiLݑwކE#sZ%  *ݟAVV=O:5L8Z*MA=.;B3ց Pbia@Mja4!٣nj c'QOnEF})9<8dGAHI4ƓMMHG0'R?jCG8zՕ^).z lqqO?w)qI&;` 3J9A'!@)wh_zP4 rysO!gr)u c ȦM3`TlRIր"`Zu 1sn5E*ކ;<7 *Mv״6+p[b7vIjyl2lFSjk7F#]]ׅP+$xc,5jѤT <, rsZds#\`SäNҷ,Fԛ)GD]fޔ;WEl^*°m ҶRsڢLgMJ9S"0i!.01$S82) 8"94 r*ÃddN=j0 /R* dPր1`ynsPOfX('HqJɤ& @j~:RS@Xz2ϰgnGA$ȻlګKr|]\0l~c ¸eurʜ)T<֤M$T p =yh^\q|NhA dtzJ"kjFnJ[Znp4U@[8Qobp3%^)a|ǵHF9V$#秈1-S)P҂X1s&(4)4v5CJy'R ޓ UvqN1❅r-` @b9`+.; gbȥRdfG'#+@Q=aOUҏޔpxJ@)zEyh%u44~\S!?16zTeZwfʎBKӵN"@TJa@*A~jR1A$A>F)PZ$\Qo 4AZE#=(F`!MDVU i888hZpNiQ悉 `SsN94\)2*7 ZNH!Ri@Ҝ784h&wtR+8 r'y%In4.Iظ#-1@*ix4 vNqќxHCqȠ Uu=hFN*N;*75&4 1Jnji< PPM=sJsⓎ@ '")6i9QiL#\{ρBNC@3p|fv*q3&MAґنܦe|s#޹*鼳dHvFĠq@ W `_q=YJm;T72$D#[#lU{vVu EgF mH؅`qT'&]Dh4覍!?Jl̴GUQnN61WL3JÌR(CpsVx3|$]~< @V6~ez+""3ֱw 5m2E#s'$Ҭ: 2*L<'wz\1 4Сgi aA=sA DZ2+Xcp}X[VLnSU y$a 5nH6";F:TM:>[SZJ֔g\ń)Gs}+P89jG%X\`5`CY-+쑹A=И ƧMsֹ [t+id<(VuεYݱְ7}z\0EN^]3]Ig$n׍,u 'úͥ5mjX>rqoW'\߈R]85-ŒI'}fբV$f%M4# v|:S OҮeJZEG`" ǂi`8&6zk͞źWUhgwBe-퍧0SzgWޯ/'e]G9+'.s5|yƭbK ٳ%Q-Ivp6l"O֥itm- sP8/F 4jw)'Oo}67@83Sn2M(98} 0Y ɫ! fՃ8r)s)1iw R(8@ );ҎHx4riu3 >\f N0E;zQ(iG֓IҎ1IѓҘ H\S&jA2mbn~yu g;In y> eX4-㱇hdpv;!Oj%tsI8O“x\aQQh4 n)isi?`ub NV&s@f钨,VҩͻN5SFp!YU;I4tJ*P]f\p٪ɓH"jFOXց4:Ph"nj6${ o3kDz.F_z\\O(S 6)Jl]恤[Vȥjr[(%qUx櫵4"#֓570)日!Fh? CӥiL4 \斣4 \S4⻇4vS W֡d'4ƩRs֡كO\Jx1U8% bqI `E HE!\8S}E/z 'jJGJ)@= b5"b>f"`qU\V\UƃHwjpvC LސZqQɧf xT&hFiu!8IC:sKӭ)G13HIϵ%5y9 b*JFOZXPAG6N{ӇݤY98rxN"`)͂u C# S!cަf$2<95,:"DPWUP@|Uhq@pgVXnWBsAih‘ԁPNx%6*ܨQqܙ`8㊆8p =i#s"qW"\C"Gzmih`1Yp)yt( \LHQL9cInM3#dR N:2{PT@ZpSqp` =(ZBqKqH&qI!ws8rir4 bsx 1QJ RGɤKe8;敇gKj$Zd#,=Mo4GҙI6E+>*X@ 'j4[ pҕdA%~^G"ƣEqSAjax52 :CiK3@*6@KiniU)U@)\d~lJp"z6zSŒM -;j$ARĜ1H:Z.8^1A8)Ȧ.2 #6* |` jznhk4P'd^F(f^3ij# i4oNL 3SRS ㆩˈf l>QiMxp)- gpe8MX`]_q Ui&,#j5wOD3.~5C:J G1U@Ųj6OQF0J5!USҒ1H}n 0i_*rí;9tEsOf[')@#=F9=)HpX>NzA)7s! i68@Gj\j`1NaHcɥ'柏ΘR@` !?7ɤ4 N#4}iq٤Ҝ@aR: 4㑊(i RPL瑟J s@$)T#$g89_AVNjD8j2;ԋNRr)f $''=*VgF>"((`4)=)ӊoO4I|zJya / @FsD<Kޣ+ހCGLP8<6J &y9HS5H!9HRA#R< h R})ziJ\z!Ww R(JOcMbGNi2pZq9!zSzү'0zvs`u䚇 ԧqHS>)=S$#P299l t5ݳ%G/M@e01҆u3]wRFz dZsȥI#((75I%ī#F:Ϻ|H^a1}+47BUpivlә9;I'qNsZGۍ'j 626%-$~, ,n=T yd4EKQmUÏ0jrȪJm= ӷuX"qV#%8/gʐث#.HMhjӜE ~w ՍmtgO,IoҚ9hINz6ITF 5N;U&+cz&`XyA*{Dm6d>#Vh)=5j뛴OE6kɼ\2 (zbOSWp-(GR@j @䅘IS#e|}8l`RHKBGZ1$즢6Rx CdkX~$U{VW4f\Fށ̲!Abܲ\0l4gn_u9Bl49R&jXv 7! _L|ȍ"AwnN"2&:uf,PJ$VHu48L$XLxj%Xek*'Xjؗ#`d&mRMոpip-%~g#5^QGN)ڃ8Zf"Q @1HbqIϯ$bӽ1z si ;AFK#8~ZRܟ|UF)YpW Q$ W ?.E* gdzр9 8A19UnXd]zh C 9A ة3L(挌(f3֛O4fր!xj?5=)˂qLzc@ ֚yc1GF1?I1@ `G1ڜ@$(@ӚsX qAH0F"qR) Q@#ZM<FGn f6d 2:ӡH,25!:܇\1*3XX YhܗGvM8sUT4b@}iA3Kh P}0iC8ǽh;Mes֗@ʌ0ryew gE `RȆzzSҍ9)(݁֐).$u!׳a)=EKj,_L}A⤢U Bq2G4ҘzzPX&sN<wsҘiArsҜ~){ZF5'SeƲ5 zb[~mo4UР2YAzzԎUR,ǥ% ʃAQϭ;Y0!.p!==٣`RPAQސ2(KCvh>[$>RxL@jB38p%)F' cץD0RA vy)ց#Q:up4jQIJ(?/SH>4`g4s0)/=sGZ;p ⓷PAڀ"qU/"t"r=zUbG!zUgW&e&5ɫ4&H7M47?fƚm8Lu Z(G"(: k v94 JE)!ЌS˞?jc(W+4(9Zh@\T (Uؘ4p{v4ţ"i)ր&NR/ 7Cyߥ+ҫ_YqBG=(5B1S)H K( 9OsN QpcR⛎(?44vNmihJn0jV@ x4J %(5jp43QI3LCFiwPFi4Qnh0\3K@4PJ((PEPIEQERQ@Q@Q@Q@Q@&)h48SPXUIfۚFl+:Y E7$jӭ7qLۊ$SpkWqVa(2tCc^;ĐzT)i48F[ M!4'a斛`FgFRւ#1HE<4La&p)NJi4}ڑ{P2&*6<(7J[V^Wr>zIt0=S@}Մ5 hV%RYcojrcFzR@"lBzT.8{Ӥ8֠FGJLG,ӣyG#;R-ijڛH4"h@W i 85#d0)8$WVc!<^lQԚ2skF8V yV2 AJ rqZ\qJ)`xHJ4"A=iF=֤”p:h( =#.x@\hZv w~iH=9B4ql&Vܿ)!i+ 4dpk vi4L:v5UŞg b;VݸD1R3I7fcrR[ %8"~QXj:{d$ex<5(|nE@*L84Hq@829=(Qe]sNO;)4pFy46OC0)`u 4'CN<ɥց.=i\pi)Ls@ɠRq@u ďJi`;]=P1'MT41 irsM2Ep @F:rpȩ[JdJ?w=)H$;#r '/=}r_FY΃;] ٜUgCdi6և>Nc2^ vUF~$[Z2 sPe(v5F1Ґ̫J;ݴrs.=!~>՗qs3vHXѢad\9o^) [FZ&ay <&GH: $JAWЩ- r"ZzgE ҹHz9LA(NJSʕ4\G9L&#hh-@HZadkpEY}جp$- SdR:fҲ񑊴$WSNn cB=j<ދb@T Ӂ;b]Եb):QqXC(&#874Bi xM8(sR⎜恙74yoz)Ղ޵g4lz?^c׽T@j¿4#[TA)٧bG7u C6M<1LbcړOj'bځIhmÃp$u4 T Ҏ4ՓfTEr? eO+S7j~LnVzA+Ҝ)9dun &rԣp)[<@A+2G"?!qUi>ve2Yǥ;T 0$ ycXPsN=@\L8R3R+1JhLi@Ns:ԁtIn*cNTR7p)11b3MrPpF("}*`A##oYU{bY I#&9(jtԝ)<qc?`ޘTrj2#Lne!>\h4 z,n5JviĠӁsR@&ii)Z( (4PEP3EQEQEQER⒖ZJ((((iE#P VzYi٘#&9Pd#IԶy88/~)9\y K@ pk34lS7Âj'㚫i6Si9L(؋u-2Hi٦i)ddRwPRcasH~Oғvi` b$^AL8҂hxOp{RzP}(Fj`.[iI$SIRy d@4($g>;#I:9*\pPwB&+kN'dleީFbSօXٓ8'#o=U1ڬoSnmAJRsR6IBq'S@PM/XbiҘO4\cE?h,\~4@ =>NRj.p)Nni;E. tM)=ZQ; h.йɤ ( q914fsb ہK#78HSI a`qkA+Wi3D$'ʌsM"` A _Jq3ޓaڜpM2 R^)H☇:SCfLva@@ pE.yOZ0b823)Xd,U qESɦ9L܌rNE+@铚}@8)l) @恋)@`Aȧ3B%\fy8 wwzD*6Hp{6sޘ$*ZTv9eTc=z)qϵI֝1ܽ{/91`(ޥJO4n\g@0&I惌:b*in2;yQ0r1Dc]?kxM1X[h\s^q{I}'M5*+ۊ%K) >\><9<Z&bϜ{cu6,(Z#jimVC.d8֏My$T>0¢"2ơ鎈N=bHMh.;@U84glzu.= /NQށo`)clo^T#Jozb,7&j0DF#@Xs 1a'9ϥ#H =j (AրnM!HFhdu&AMؤ.xQ:Rs@(4P2 sQ_Ya֢mJ{W_gckAgGkK2:p9@w1L}*6RyDtA$)[40MmP4!&> a'<zG1H{Ҁ)qF &M܁Ҫ,‘IVb:zR8b9 bڼw 0ME&T[#yJҤ*A 8Wv !YIzzͣI0 qCn,HCtqH2K)jh-~5 n)gRsXk)=i8GLM+ H.RÎR2c8\dOL6#JsMAҎ8]!֙$c:g99E9P?͜c-Il{TGTH($֤~4\t8g4暼Ӈ@c P3ޖ4 bJMq@'RQښ 4sH 2;3ȣ (8R80J3!U;xyEE m$ [N1Q:7: &q`W[+R;J@Jc Znٶ@aSz7*:E`"SY\V6եrs]I-2u$J)(<&Çz7ёCZ1z恊 ⛚)`4tp2)H9hҀIѓPMq@GSB8f)P)hRqҖ3w@ JHt7= u.j̞ dҬڠAV#4ɁZzfLpvhM8P4f!4RP1LjFFqސ82Ko{L,LXzKɥq W,zRZb-UI-Jg1.%5*N%QjŴi'I C INfOhif3L*6`GjfqLhAȇr)EE;Li;ALA>A*GjK9:P ހKbN{q֗hݩ2@c@ZS !`1AKZfyh ݃qHNHg 1 zzTEIJOnԄ b+1L1*m<̀ &0qޘrMc<+$*!CjKSP18lReC;sV\rzНȜ%i3M88"L ^8irrzRAȧO @.;E jp Q4cF)#ހi9*u ;SP R( 3R`@.08R69B N@擵($)&ri%Hi j1g`{w=*bN# æq e?(i\"K1P =:STdq@]uq"(gӀP!*K#+gQڀ8⑑G@sQ9~Ӄs 9Ү8m8jvNb.x4HP!Y♻js @u4HH:i8 izSޙ,14(^qH@hA׍-Yģ;M{ 9euc6Aӆݔ!m\޴-C,0 h=js} Zp̸_dE%=\Z Mt1p+I0]+7p]-ed X櫠^ҹ˦FčZg4c̟B"<1qM,9f'q!"NE+嫨(7uN1N޹Vc 4A}L֧om{p@9cDH87g H47攷˒jrn$7Z~OLUqb:AQq`,P㱨d!iBc<|O'1,s|@K;f9Pm'4SfP1rjY@`Zy6 e81FdjGB#~SK,mk23.w8tZ}s0;\yPNfU6[e#3ԑG*ԫ@P'{3kP\l wQ(U84F-@aaYXxǽw qξ2[51@ VoWaU,}GʸcNnNIAjg(`rzTm.@5P)\qd5 ȀezwQC!=Uޞ GE)p~V֋Ĭp#j5/A*93]q$b棕QXM&G4'0ó78H,x>"150>HF&lo}j2SVgqܚU.3sҚϷ$$x*OƏ17D2Œ*7}i-01[:j6qzO *a@1ACw]; zӓvLO;rOZC!*@PtgfHot eUN=}˗\qAHjʶpOSNb3>I(- M0{iV~v]T#ܤݷ* rC! F6rI<"i 4KɎ*熴S5W6{m ܪvAmE^hFuܐWsGRzu⁀c9➧OB1!(&wJpjCLBZia(dc56sNrBhA{PPJiAԀHW ֓ $y^LBRPiRʓ3ڗ r?y晻#=9u E08^ϧJ}74ɤڛҞF}):`)8;FMD&2s'\jsGsQKsf#ӭ R(W*<Xڪ\ZHn!}+[ҖUY E٘vzT=y8qO`ZIi{nSYcb@TvȤ4̧qT`FM\IC N0梖7Bc>a,_R'c1sd($kVӬw1|sXא5)*6ynn1REv D Ӛ 4v!2bzՂKFzV-2/\m þiH$@2O|ޔ!Qɤ(Zx45rU=)˝bP!OG R2ǚs`r*2 uqW )TAp?wSAGzR€HvGG?Z1=(^\utytri@s!Q 8@$)8'4@*ǭPQkwac#7X5)'-ڹq^B6ͨmR CJG kF"uAӚ%1gڸ! m3J0Z-ͥ A\WR]I,@4%&1ެ;3\yFnU:D1%F u6ba)ue=k6 UtmRn5im猓@lm☉ĜP !F`>Ê`E;hޚAއzԄg P 8?LѲ;w֎}j2)Fhړ4@ RjL4iP1Aڀ'4Ni9CPs4=:h5nIt5 #h@УOYav}Z3Qފ)j˹pk.hOӊըnb#&4g4#H#iW=jv_$@C&j8QzbdAB\GJV]me9HQS][D1Q=NV)Jg9[y fViɏTMl1=h@qFݼ1@.sM`(4is@;4SO1h)!lҐҀ3A{֧I 8rh%LeȨ]P ^[wmĞ@5V;G8ےzwxAR}jݜ=Xi8"ᗦi Ijy8#y>MrhAFqw\RM##; \91'8H=)>9(5&hPO^aڣ\F @9/0P5̖V$V#b&ܒRֲnHqVdYd|WVH#4yҶIn*⪫1V5g;D(i98g?1@cPF)szo%[^zPSFIҝU4p*]$ Bb(.3L>1sB׽1܋kv+Z nWi怹5R;NSN@,Z#tɵF1O2ґ6ϊD28T`sUnd^q4co8=j?AjF2z_/͓6ַ- toZU=h:9A͕x=jߓP$6րdf zՈPF㞽j sUs>8NJ<2-]99 lt_0pZnf*Ț7+#0T Tf_uLt⁎6T/ dlvG8BA#(ŲqH-* UbGpBb$%,zmڥϗF5֥DJ۫pLU6,@䎦7l~uGVnLiI M#i!"\mFq~MF:TqPj*aki:   fyӚiNNBB,itcV֢Q1HA4w@sL4Zw 3֓ny)p4t)Nl)vʟPx#)sM(8z+T)*Bǎin(2 jX `.B7\U[<X-FYd sVF`k YRTW0_z,H=n* *,W)V|jAiNkd)A)R7+h(J:sU ycӁ)~SXm⁑v-rEsFCW^1$lxasW[DLތ@zmA=jx tFw&*MM&zY2Wjo)=qAЈW )(!8Pvp:Uc^U!t3/Iš.&`pA< p'wt(f12'&&) m#ޜ#d:Ҡ; E\hچ;Hf У4qx:pBM QR84^q9Ww`Nx"B qړ b0hP;C)i=t @<ڎ(v<@iHx`qIh9zRnɧCPI4h &}hȣ@5v4q8#4{j&C o9\TפJ7+YӒ"ی¦PM4jyVIy_Jg; tb2xbz֞]&~U1U 6VWq4-Wd<T&#RIA z҆-۾$lRx5v85HJ4sP,5W1hy)ҡ$LE_!abEIIJqi8QژNM+ R C$QIڔSQEA4cJ~)hmGU8jFp!#Qi) !@:f&\ `(h R(% =)yKӺwC RmB=鈁PCDe4&iïJhN\tdEҦnj&RҞj0~lSAC9=EFHDK(IM84 cg4Nji>N'c+"#8H#օFUԋ@ -8TE18R+'v} WH.mfYCpN %|ݽs҄i} _y< *(,h;0kC[vH^qO LҀ{Za` ;&s9&`goni @ qH97 v0>c:uΗ=R &%4Fbj1F1E NjF7{S0D٦L<>Py$aX9'離U9 [hK;T\rVۂc4jF=jڵӥ ܚ˷9TsRy@w0pezѸbT0'hd>h%3M@Ґ>cpsEÕyF #/.>Rup\ARlj >`H2j6*=KjyTl5N[SwFc\K*hY2WCsR}N( qYRiF_sXeCkE3Uۚr>Tiby>l|̠+R؍= I5uG=MX3<ֈb QB~jShz\st2vuFh'&@(S硠ny^2)'ig@63֟H=W" ɧm#3A0i9Tg y朤M)>Ԁyqj\g9#!sMJ=y@')qڝiɦB9B$ҙ˶xT:2*e@I!1%8-W0MYX Q951ݷ'ҳRBwWJ+֫*W6)Thn=J˓A0^l'n2zSe26[#APRdkbpJ+zTmӓx* 0vr*bQ*cL:nf\C%zEo*؍+"3iqmQz@9X*)YqACs]T$2ݚ%vvA[qB@5,4;waoڣs;:cL!X.0i" :P6 Le įJh E8t>P>cAaѱX``p) vsQcP'$@-p89 (UpiJUY 7b@H.GӃO\+R[3SbCL9?18rIiX>cT"'v@|΁'Vm樖@Ak8 <>q~d v{QeWާ2@~lU"Y*H]C( ڠJ0 m "&k8Č7j"*4J) 194&ghTlSF@yܖU2LL! I~[ߵW')؀A  [!Wcr𛙐sZAl`޹{ bT{qT} ÀFOYpT٪0HTn1QVqj+>R& $dtÞqA$'=98,YIE+{W=xQɻԲ0Ɏ& . AU}A܇9pW9AH$)yV-m/5?<ɧb" +49¹k5r=!8)X`$CBc)#N1LcҞpNM5H61`<i @4+֤i‚8@$1M` ?hq]vq5?njH׌h$xR*cҥRp8❁Uc'"Jj6g֋ dMYXh1dQa\ ۃJO Z7jwx Ry.(N6<" 1Ky;iu8bԤnk(#TI zղr8ٛoҀ8X}`F ;hjs+Ym$qJy95} ZԌjJ"#@5X1vy{T{XvW5F|ʏ L@*톑|fN=뱵6X;0qQ˄8,[Nl'`7pzຄCȮr;'vsxoH+3[ҩήcV)K"FjT@?;V9609=(+b''n}Ni8&=fq0u(9i=XcF)9MXb1ґ(sր❓`P0:whip *C \&qۚ)t╇q٤I41Ҕsra8%Wңq@GAi0n:xLњ`-f)$`3BWҵHA$y )34 1RITtPsF(84'9 4$AR)2S4SZ bKQKA"`Rq4y@"5ZAdU1ɠ)F(@GjJ^c c HLsJ=i H)hHiRzMah)Fƥndq C1(F9#4y`JArq޴呅UdT('eYyNhY\ԫ)عzQԪh%N5Gz )@n))1@0㊉ՂZ L"UUOjHʭ֚G59Z: EiQ@G1֪'5n:j00 Nc2b:R-#@S'wZ꬛l xq9g촩| Vq=JBj GɜӝrQȭڜj& Sl~Y#`Gޫ,~bjE+h)P;?fǘ(\H7}sL4 7p7{VUr\L F̷+XҌ~ԆTf簬L 7Nu"#N{WI`EPflڢi$PtcXEH!TD<ۊ1`c֮Lgp℉ #B>jFO>_<S1ȫ`M;;O4JRE 94J9T+lSSH=NXS,Ċ+bk2COJ؄U#и]ޥ'_%pՅ$.{ֈ☄◁AtN:@:RB9HIq@33E("Xt$ N=h9`RԚMͻ8P?q0)200i xbzu^E2DeSL3ACA !֎$dE!$@IWqJ[fvPOSҙ,^qҕGi^楱4u9.RiOTP; ?h(#ҙ"p 1'AL W#h׽Ki恕% t6pj܏Jc/4*EJj bS3@IQ?4x@>xC @;lG'VDj%Vg|J$tRh=(-"BH\FN1K!g'RC(MDMxlZr kp峪rH/SY H&uS8w>pq<1].#=*,df%+se*x#hy #MZ!jĂ8l;C'9늰l j@cZvuUFeu%Yv܍S%s x I)Id8ni~b3H7+٠DM i݀|t$ m彩V9v/i>`eid%BqV(Hw{K3!3J[1Y5j̷e%ٴc\b;C-ڹyG%5[,Il:W>Bl2p9kB;*0u{janeW%>J$k;OްnhgFjZ4ܞEv#uXGÜS2c@N,C^` TΡpD̓yPFx@G$8x=[;PM3ڀ%J*0x$kmery]=뱈#sRw$iN',9,pq\ݹl+&H=t)V,@U89*IAb('ҚXI1H&>^v36г(iSݔg C(2z,C $l21NY6Ă$AR6=g$֓u*ڲU5fV;U«(yNr†EeޘNU@L)yŮۥWSW l%x(1M̭)һn>W&7N`?⺵6(dVzݩHSi@)TRU8ǵUȤRi3rEzNH)2 㸠Cu14pXSUF1bX歀@ӭ81#92Q1QI-3; 7QX RL,H=-uX#yU/3!Z !8noưo:3`S\L,c#V|e{SJbrZ`S"uwz0]6A+5csr4 .yM=s[!惜Yq@#+7.p1'IN g'7h)\Si2s@gq9FM/\)ʡM!c4=~TR3G2(9njw|Hj)Nݞx sGni dP}(88⌓A N^GzwҎHȰE0MFJ&G186XȕgS=_Z2v:Ufs{T;Ufq#4RREɽ5$\0ZӎrQ^B7r)AFVqRD>ؐ`Ԉ9z-+B<5n Nxm*+jz|{iNE7 NTKUh$嚥Kw* ɫ'q8irI."a)I8H;bdOzMݚpm 0 00;H1PxL.3;wv(,S RHb*Rygi։>cǸ >$jQ9H[Ni~x\*Dwzu 6sf|܀() *cޤ0yk5qmk1ZsB0{UQl䓏JeX̎ɣx$ib h%8J[`Rfl~;gtVB`UWv#PȖ0 nU&]GJՒ (]Uc'V 7::+ N2iF̟tw%@T[*jfUKc~hu4Η  qNzRdr" '"ŏ"N<hѓڌF#&1G_ҁ/Nh03HlqCaGZqH:g4dMipvrI>ZP( =;R;u⌎1H &94Q`zScIڈjFжI#Ywj RZLM `B825MO$?*>' p\ZI uhR4RIhmnOR)f~j0Č`vzcj7/zQ a&wg(U]՘i0$`sM&Cvi p1S1 6Ĝգ>bBf_%r>lsQ);AKd!"m@VUS tx5 DM0=jn٪ZC 58扉8;98 0摛g4h2)V'$PgiÏƔ }(=YI,iT1 `Pҗ<J #p:P~4rp)vI aȥ>i'5&&9*]g4Sx_SC%}GjCw敓q銞%[,K;4K-@WV[ʹxF2AdiXm2*L*?rHT⭩jcR1pG0d4>FzT Ow)//aS.JԌBYGw PPp;F>d>>oT]>|ڣ{?!ܾ]>S@x&f1089cxBM*vݺT;|k\>tɬ9 9zY 0TCNxF[UwpvY21ҘŲFjUʚnWwSRgF!㨨9<@ I )0A ء#1 ,6Jfl |Ђw WұA< ~`B=h#|JTA$IT#2rEK3[y')XәHjdb1Y/r:%O,Yp¥q 쁊wZOAx4 BHƗj9{FOf s9BK`q]XиbFz _0\2K aa)ozWxfq{$_Zn]\(feb:T Hfcϥ8'wZU)˱v_%wA&n$aR[HSޠXe\ԋ.MLT 'Jdsժʿ;G w$$]Wb:uEH qЯ^'$?@OJ|oo*x* ^j\&0)1<(*#o5\? [;> *H88)b^A& p]84\Jós 1?T<$}= II7I OʵZ$IwFr*c\4| 3]o~&yI%QDHtm#]xBM$sE)#9桶sJ{CmUQ RyK #Ҙ "QHE?ݩ@#C ޜA,pq(yw;)3wU xP8h:}kP.ޔ63s<9g3VcJrhwNir2%V13ڍxJA,:v@0O XI$U5`E;jAoh&“d0dFj#JszMҀ(qwUf'%@^ţpi U#4s@N{TC*d=JvpHe9G;GQVP@5Qj@<0 @${DmO`@;RcR{RM7;$ i]>co)"۞)sq5 sMc{ԥAQ!tM$ gJ9.p@jc+ҘN0P08'ٷⲜ<х<Zv=Gz aj#R1zvx#q@|n{ӟQa4z8j5AiCg #`?b#4%m/P= !nxMhך$d]l1@㍎x4'ci~r9īHaҹӠkzVdTjM ^*P6 pY'c96HXć*p1DM҃)jh)f'#֨d4()`Qi']` >nD RHF CYjY"iP=)"2^:dIښW'9!M!~c9IUBy #1H2z?$R+f(p)',RsւM03ZGLBpjF;R/AHO"|MTcL UqRZ TAL4G=iPH r)gQE%-@KMgH91 g4ÀjhqPSE#FKJiCg֙8SG'8zP8SGCi@E8RA8@nFsUjd3LRQ@N);&8M`sR$SJT 捽"> QH v8SRbsib5 ب\桑l ޝ+d ixoZp@w9^M4 G&HU،p L9qLZFV@s*Tozfm*@h!SsKLRqKLjFxp2jP4L;TdaQ0>Tң隕E'Nj֙%SOK)hSQER@Q@ E-QEQEJL#Es aU 3HެȤ1esP>iѸ+ys@IRC{TMf$!ؤ$$`T&-QlƽZk5X婸*hڐRb2*r"ѿ(ԜUJaPyr ׊YcaUʃۚc-"Hǥ9MBၧFib`y H(X;PJ,(k) 8v`kWI71 TDJBi;.F[MT=vKWF"#5g'$yh;V R[,٠B6BNaaEqGxipr(C#PA)Tc4#&B*`0SA@&V1gv Sقlm1/e>FCzWw=+]@ت3)r:R:##SM5Rs59Ԝp+f1E4rՇRz◎_ғ'PMqFY6kB=jBxTyɩF,VSC^3HqfsҒ; h<рJøRpyV*2L''#FFNi2 w44QpcKKW5MA v(`33=(UTl3JP[h܎9&>)~P(=(Y@' uiQAWMQ*~,A؜()*<KϥG'ʜhEiHʌ@~HfE Fc9XKs BF+Li1=i(POtKd'5 ۺZh'y dfM=Ql4\nmpC|_ZϔyEMžjhFPx8f.GhqFraU%8i H,o/vGJɱK74H`]*8\5`\b6p(-qS(3 jqx0}Uc+C.Uvݜ|U%-Ґ.6%g;H ӭB|}(r8>H$"ʱɧz⅍7f4GVeprS'TS FORD&$9lSv!aQ=j85^}n`*˸^"52t>F,]R11h$oE"aFh8 )gJAI٥#(7Jh>m`hp6sJpE46$Ɛ)H!'B~Z*8fHJ~E5P0?w"Mr*l(2@=h)@8ޡ ޜ08 )jD*I1ޚsۭ*'cLjwXRS ,>]2F"5+WLBx[F FzqR(cLsG܌~?x%W{O9s D$X`TJJ޸X`H $D'ڜ^)qRshI˓1)1@H㟭CX+ҫl_0D@"lkE,9CxₑhGZUUj@˳Hv.,TY;n-_B6A6%;9z\ sҫHVc+]xT^Tmq 1Q"⻺bi,V⨠޶JG վΏ fy1f?)\w9 HP;i谏ci23ޖ W!="9~JsҬɱ(Rcipz- W/a/j1ӆ EL  Ԅ9C!BzN#R*jʜL1zHm(8)1f3)p 攜P!u44MqOE$bUBOJ^ Gz%=AHL\楦K 41$[I= l+ ՛{ɒHD3{Tdh% f-Ҏ ux4 S@0I┯*ҁ)xҭ\sU.NI-Ft^ & 8Ċr k>JQr2j~ذz3Ґchpy6sLd,I4f B EG@8&mOjHt,jFёL8"IW`@SNbK(qAoSN F O#l[~gicG,՘AJEBJodXOP3֞@/)9z@'AKLs(^сR.3LJR03r94I^8zT6׆I E)|cڵQ ]5(rrzD#"&YPId 3֘\HW MQ `>Rya% =)d|\c"M" !$z2q* APWE\L(f9Ns@`i g516iA uڣTyT&ȡrNiASxj+Lۓ9GE|A 5Q#|#$XG*' 6Ȧ: g5s{T낸2`g9VHjpJ a@$O ֓n1@9qZ3@'׊BFy4n>lgCHX㉛ҨZFxcM85v1oU48qEF}irsVb8cZdx5g#lyJUE&( ^1WFa$caA9ֵ"%c-k)+= *0*O3P_\c< 洭PDȮkЁg9yiv͞μoL-I=2d(L}!Ӈ)ÅeVUdcg1c֘Bvj̐Ð* M!ڑђF)z1Fq}'%H1@KR$;GJsDipOzz`8$| Ԁ3QN1҂X֘ {170cqڜ4€z#H F81vP֦(d(adit̄ҁgUK6rxhMu<:$^i'A2qLC99@#uA4J1րqHzԀg0)VH #[]&:ֱ穱k,8nWI:Nlf; [v/r1R"VH503qӚPI4m*\U7`I=:Ug$8Ύ1ތ qq@\1APQhE&=r)2hV89p GizQd^ь07?6)̓B.|Kt fNNx#L\8SkRQiةFr){D7AR1ךy qէsiޛ)zS$:)N(9#J0I$M)9ޙt李3H4 Ғhji!ycBm'*rIUd岧&a&ѹ'ҫY>?ˌ扣IЫ>wgeٔϾjzfQriŢƪ71\YO qX:.* L@V݃sY YWR1LK@Ƞ4 IS Ciӊ\I NcqLnE$ ~ii+ך,(0H"IO4Ra]muҰ.AyL$` RۀrE/7}i=)iSJ,PY'6RhWVqE!?&v@:y⛻8mˁ#V~O8 BBՈ]0ҡW+EGCbRv;q}*̷A5=IepCVn곶ۛ}jyZP6+Cjf)AFBvL"$ L?J$IԖ RBA*BUF*UX2P/"00)XuJrUzҰiڬawmT@|4C*CQ3$݄c['IۑR$eqCxjYU1H)*e6J6ڑ׶O|d\ L %M_ YP E@B KJ2p4Kr{P]]Gc:RE\j c$NJ^:Qz Aoza@>i#4F(HP!dm5!Mnc>jFBHCPۚqS%cH4`졎)Ƞ lv-H24'#=)ʸ<zR*]3q@d␃ˊfxnӨi -y@5=MDnhaե$玴hR`uDI._ZA旑B4#i?S@}(sHRj;:R7Jq4,mӆAQTO\PۗWlRs/sKJN1Gc@8R"hb i eN69ƐoiʦS"-qJH-/ ڲ!wqִQH5v坎1DQy{,R4Ni d @<Э@H ;䌎*pZr9|ŷBΌ̃!4K_O\),Ae]݊Qn ݑ@A ="a@P˂sd9 <=Q,U`fr1G!Us֟gȕտ*ޔir fL:V,! U݌+ICNJPgi7vhJLf8DcgwbC;bYu\bV,O#$P,3[z=. ۞"i"K9FѬxA1jQu#c"m-L򛾠'ڎgsHi |sSs NJx#Ԫw7(7{ 4bH1dSM,6`EңT@Q} H5b(͓LKۯ4xAczUp# dXLU1PD2vԆ~ sUܓҥHzcF*}ycҐW JWڬF`=+JPt*r)>1@) ց`::Px4)@ AIPR)ȠLR)4f:D4y ff5D& 0j]j]ZI4d; BqAjo! &8(c@m Zb8EF*AA x`A#8`4i>@iiP:Q@Q@h%vgbqR^EKAl'J0"j1ҝޓgDi\@d< .*x`tsT]#=QzQWdDI4q֌c3S/ݦ81ڀqZCqK$@dRp{R@=h<$f`S:Rb HF9HqA=Inv ~x▘)YPq@bN;S LP$vJqg'#tr20"p͋mD*~;p¹MKepCM3 SLgqJE1U4^ Ul+HzϹohyzӠTֶaȖ^œAC -֛3FqLsNQHH.Erwm'qA#$8bԅF98@ yZλKVI5P\E娖7NZvUde9l k6M62|O5i6#~㎵0@5ҝ1ǵG٦!R=i s@4Ǟ(hg+7w; Xg0M'vj&fcj[.1aTYf'<QVCr*P rC=rGҦ '{_FW8!@@0>aeh4N 嗗j9 8h1U'`aja%r8G+TbZS)$T*à"RKw)n1 ǒ9)a9LXDd4l`RGZ X˚-w" Qx9M!J@1)#R; 9Kn9FLY"eS4rO-mhsK*9{3#*@S 'y8 R<(+!ȎRNߑH_S̾*$l<8#k6I@J0jTRp9'H֩qӄś.pq.j@jKEUq9_Eh[9#M9XC梘i'xdi2'i)ӵ"ץ7 ({\<( ⡱0JxA1NR1Huȧp &&JR~Zi8 u1܁F@Dž4ZCf?LE3`P2r H"d=A(㚳6)HC;9b:6S|ýJUJDQ7YX E2EB0IbKHU4+'R< + Ւ%q֘ 4@ZHՓv&F1Տ, 5nCW+ >9BIids9 Ydc c4 n\VA5$In+9_p#Fp)JUrVV3sr'yf<SEqT8QL24YF2*0|әՎfXnXSZ [#L=jL1H|Pxj`$<)9'4w@R! t֤FE0bK| ͖2 PyɨzG&$g(:H (W iJ0fcҪdvu1LSgMl`3mT>S2 9 YWL#x&:_285yLQdjf"fS̷ M"ZC<>EnUn0*PQMC~u'@I\)i9&Ih#=)4(O K8hY6H Ҍ@zr:?N)ڜ@Ԫj<d`}AQdgvi2i7 i~8V^FgB4BHv5! '{TP jdLiSF0i.1J;R_jybd-7<Aާ< i uA`ӐA,t UdT18P{ N="''qJoZ\BdڞzRHIJ{S ¬u(LʞkiɨNhHÊf99-(4gqҙh zP& K E.@J5lSZ}R$ғhFx4ȣ{:P1LdIpM!<=i۰8=)wdSABK0@ǭ $)zTE49,<hT[fĻQ5dJրq֙ߚ7Qi1#9恌d(4fǚ9u+Coip w 0Ăq(4o)"<><'Ҁcӵ)W iIgR.ҜAuZAr21O 4#6H9S0L.iTdNvN \u1H0&G1f&i1P 1" R@A"Nh\O7╊1+>An<,0sZ/84dc^m (SOwz 51}iX璻*IPsH1ւJ(lҦ򠃌^墹Қ1NsR r>2S(c1 A`cy&EDFc@ Ni3VS׽;kL6c֨;Wޯ1"vSL.ђIkW$)zEWАLc ~5:$Kkz`1݀i{ԃ҂%ǧj*9ӔA6{ 41=i&ц=(484q@ A! 8^i *ni|9 -ylH+FwALʩ悐:",3R3.2:k(4EsQq{ v9J۱<'jLUbV9m |.whؖfɪ1GNTY=E[ OCgZ~'g+SnNOQyɺ1J-no&᎕] =9xK=jcIl *[uځݫ>9ó&KQG5mgTZZ#Cq H;3{rh0 7R@\sBxO8@ 01A9ȠHtBc 4i}M!@ȏ ֦N9N85$0rh&N:ӹa֚2Ga48(y49('Td RC1C8'x C@ɣik*9`3lBBcnadTR "jTsYS9 =H#l:9?ZrH7 ➌Zh6if>׏AֽLm-u)ad})C:SZ"-/JPuz+m6x% W]E㵅ZuL^A3o?qUt@9+dlV.2l'Ҵoj]qI[&Wh${YkZ(a9vȦ$U#UE P2eUe+9PIbzftuRp*3+SJrBZ:Lm.QGSYMKctz,ai QG @):E!njNI3 2(ݶ1F`:SMS{R7z}i.R o@#5 u#:NPD9'E= G#S4P{UfZ\Fkj"z j;Dzڤ@ %*qڜq!aLwlvx\T{F=!zhqҔP!h&@<.8nj iFYiHޔc.N4`c(ӑ@ݑFx1K":iyaQNiCq@+ Ui<գ5&4|4أĊHjDSb<@t5`1ҡzqLaA4qJ211 xg46s@Z)tؠ A¿2H"$Xұ1=+Ӈܔ=FHiaxNAMOTձJɷy!I?7wݕrBҀLc.NMInpyNJ(0SҡzPZcz0567:F§L`@ɆV9'iK;1K)"1ɥ$)@<Ҕ~S@5 8֘‘Yw/.2V*sX2ܘ;*dmH$O~zT~)Id/57.Ͳv-؀q&cݼ*Pk]>-2GsY^W7/Rر8 79&>S]'*$2cQ1ɞydqڂ󧝲t"H^ CZ.";j 9k'֧9vm~pIž1H%%cLp1Rg'k NRMd ݐipqdPI#ڑJ f`Ns@l61N䃊0 Ҭ)h8U@F޴lQޘ 8qoJb R@x6&?J0)8ip:ѐLB ag 37;H^sc!)׭9皫)&&,+.3J8`,c'1A?!H֡T2Yz@>Q>Զc4|B~ 8iS&NirLLL`i!\dxUc VfMŘ dPNiȦ"MESs9AZ?Zvێ:ӣGWcNg3w1 )4^㩨:Rbv'Ҍ aPU* ReM> @(#4Pduj+6wҘ@H(-ih4IJi L8x<Ӄt;w58OsN @j0qޔh&i33u4~i2U5"z {S8BZdANOh!:I@QOdӁL@ii(!ii)h((IEWYcv$m guPn.ei2'r@  z{DwF8,6qSc3R i3ޚEwo994RgЮqfb=r=)IS5j]:vΝ;c"H+ 3Pؚ|)>Uu,ژMgt'h-J%)vNA}ڲ--.%P56i*tY} M>w˒bܟ3ޡ'=hL٦sH(=ٓ^)wzR(N)O8P c=$hn)9=fH+֘q@Lm҄z@{qO.> z~@A^4 ֜0;xȠH1M2sLS nϥe OBfTO **͢Ґڲ-( p)Ñx7(zLDI Jc0Tr(env⣐ (R<V9 BPA7#S.{Qbiz.2h/h'q+Li␰4 a bn&Fប#m=1׌)+i 0!drzGASpzWLw"<4׊P=( t#N*DAޤ[8DhA'M $y_7=N+v72ʂYjE$jʸ zF2GZC(5$#*"cҴ8;/'p2@ L vRY[y5Zs=i]=[f"7̨9P6G1%R) qF^uEm'jkXz=FZ)գ/"8gqެӊ`*L!Ϩ=)3hE.4Ru@B=;ӛyhR1K!sM (Lkp)G'R0r9'uRA⎧L`Ti7wA=8)8j  Uqj#:S*CSqLX%q*r*ւF판1JK~kQnj Pt-cJ tF1-ւ,XHV,VAxRH˵pyyoxCp-SNTdp+=oo&B3 reg?w"Zf6*@j3ɩqsғfNŬBA:Ai ΣocZl#1`dYD RGVDqd<(#ޡIVTZP6뚳_d;RJJ|i;3,?½x`1=)5cҽ~oܪ7=0Fè[VUU' LUyC&[7rGDe0摊n,N})ߓ9=x!44ՆCSFr4l0:RO]82h% JH,!:@HEqS=*,T kc8M8#=)9T%V(床#uRq #mмdb<#DnlP:'1 MI7b@R{ ¨zi&6!V9XNI+5+ڐLG#߻{zW($܉4݌W]i2[\4aGJۇјopn.C-yD3֡9RI;5Uc5(^u]d6}kp6Lǫa G9 KpF9#4H8@KZO&*aRIic)A=6s)*aic y2"_ӷ*1LxQzVqpn;TCi 8+(Xr*ꢔE,I\L QHG;Ӹԉ鞴p*PA'֣n ⁎LRA f[q@8=i\,8g4$ ;9Os)) i=< n8Hb1HcQc~LR&cp$W3\H0ruJ8=+QkfV-Ͼ*@=j5^99sE&9H妓Sj>[>h$Y=3(u#4cKZGIR hg3nOwFrz~\b1RchŁbwb^A--u1{.2~joEJ+5@'wZsH&x H.r`zN)$'=)P ĞRgywclsJWgt#ʬM3Fc$r$sH3`(^|HӚ7S$y*8x=Gj` ( !1H hl(,FM5qy&.h&iaA4ja_pP UպTiL 5:JV#Ui-#Z7c4Tf١Lz_j*ҩM)2 4<ir:uiqM'OCA9"4O yQKP;XaڝcH2Hvs`BsL i۰3ށ AЁMfqPG֚:SGzrMDZ5*(ƀ9.3K8`.:MO{c#H\J_cBHq,*EC,TqtLqR44zmQVHL5@>$g'v*N4Ӊ82F*2@v34P*|lz*Á*sLD^iSJ(&n}Xpi8ڂK i7 Q!ך'J:ќbmZBqFxF Nǘ.3G7f)v4I d)6`u1қbL 3R.Fiq-Ҁw)2(i8 +s;90̀h9#m9AR@\dEl;ӶȨޓvX`թw"PX.*;T\0j3ج UZ&0y@ 2*C Tcjd T2汓D<l0r 414|qeXq#=j20dSkHH ƒ+WTF'#NN1Tu+-VWN1֓7Q"kQٽW, +*=*$VƢ\*]Fܝi.݌:cwV# Gjd&.IG5,cB $r FW$`IeH@@(-2\|էgXʃ9&>V۞ԍbWan4,nvpi[U(VERC: `s%B)ݝ}x22Uޥ\hAPr\`=1OBY(,[9:!8,SQpOjsҁ4nXͽ ʞ"+o*92Bc4qb"X it4B+TpȗRulQbx2҄ҔzSLW#BB l@!4/;8>$(bjM`7˃ xU/4 1#=)\j7,<3ɪ:UnF Tt‹jMJf-˓(pzSR3Ej *:TM!ݕ֔ˎOJ;S#8Q4ޘ 9?JMF| Q wIȡ[9BĢF)z 0*Ga$PN{R+J}ir sӃ1ӌSs(ِ);v4 A*vrjp g4$ R)Ǒңir@ⓐ4`('"m_jhOǎD7`JXdqښRطR3ڬ:Lj$8< iMZ2ci{ pV@r!@J\SA杊CPO $f`8<g'nq8[FP(V+8 ȩDFM.1A'?wxB6{PG(8I55&}?*EF@?Zi8&FJo ʐ=( dSBc)QMbrcNENW0E2N&}r#r1Eb b@˃*@ldBHr5,mg(!bUsګDK3[R#}i3">MYچ$(Ŏ\ڜV"ņh|w5 G Nց# 1R(bF43, M;EO  0H5]$n*N)Gl҆=H(nY0nrlgpi$dRHH}):Ct`)>\Mߎ4ù_嵷 Bi~ŝډ=?*iúhםExMB1Vu{^f Kvurj& 8mV}dZxV(S3]<Ҷ!@֑PY>d^)iB^ A C)҂ZvF( A]@QJLUiIFl'r׶8$]^L}V2· +U#й-RF@[c`] :>==uѸ=MY.4SisLk+6OK[Eij&`cW.-:DΧ$1gqɯHNvz%;W`1l(˙#n7s]8qD7H@֠¾ p9(/za(#w5#7q#q|xqޡNJU|ć҆ʁj!&I(zP+'KӃQ+|4`E0\Ԋ)xZlCNTbTA[Rqy;qA$f!@4`3Hu 0FwTQ1F9ޝiuۛH`7tezPx;T]T0dui LFAI* s@iE0HFNj9'X&%q.g#1MMy~Hr8dO8+c=vCThM績 =HD`X8ӷӬKxVw\)¶'D@>I#p4ƎL ~ޣ"93[vx)\z֦?3HH)vojoT*rsj\~)&52F[֤(4.~{W8E$*9?:uR2=iI 9U;fCl#<:EJ4v>vp &ZJS’x;y=:Հ1jp}yLP9h$vǵ#HZ5*}M -þ"mXkU稉ߑޭVu4gxL#SSv39424幹GJk&U.<у֭Lbv5zHT҂Uo[lX5B;ׅnp1OQRj()Ȅ~ `dՄZfTzS%dM<h/jkSx"j٫gjXXdM)ISsHujPs@s֝j ,3ǡҞ=icVݸ\^՟nU9c1K֘҂ `H"eaQ0)Tӥ37Rtۚ=*WzX'[4HPF)PLӲq@1Mϥ7w> Zp4%iSS(8A,a2*b)@TP1N~JhZ(<3Ԡ恓+ԋ 4 ű o1ށXM5xH*249<Á=3S NiyMEaZҹ@=qHsHr 08&1A9g&?p8p$4fNzRzS(iT!4)@\isOݽEȧfwREQ̨3Jh&۳HMF ;!I֌Z3S*tg"e5 ԫTfR2)nH&ɥNM4J@238c4FH  9ϚB2yJGCN*OC3@n9= KzQؤ#9:P!C)eqL xjq0FFcW7A?JChy2J҂/^_ƄE&isOv5|ձĂO^CI1%5x4!ihC)g :S\S0SPdJNzu;v9&JNzMjE$4=N1(<*A4`ysS~haӷG8玔ĎM''cpG9_)v=E!A84ߘ{  vqL4% $LGR>B,1LZb ҂OjbߊBN:PM!xx) sNL1"=0ƞy'4aq)Wq>d1Xfi1FE 8)@4*C FWcBcHIi~lIDGJLȡ*= 6T2*?&LznA~E! oGFeY?qW b5k 䎠5;b2O8iIΘ"I#@: dlc&XnȤdalpP0_WkxrI% 1D&{#b1փ~46I;K%F8sPƧHa;Z*2LH\(* ̿(Z'igRێ'FύwDbRYa!'z2q(s ;72=;֙aqkr~bs{x,~3ZmFr jZEwXc1T"ޜ2A\d=N)l^a$CnulkqW%,$K1tI8N1B31T3x!FLPsڶG2@sڟӚh/'N81bt(A9.S$ޔm9e4 nsJRl%ƿEF$ysϵ6iy#ԯ+9JU݆YϨ)(c\7w7hV<~p+ ;EE082`OzzF\(RS8SQ֜@9|P!8Gȧgދā \/MWuӖRG"Pi_JqcۊCS@ EfBǵN AZFzwj@bO@ ˼BѪTUR|VXjڰ%XzգAYۉ"Tl BZS "`--'^u80 rhS$pEgXqcW֐Fy;0\ޒ+Ψ@aԞ t)Ñ9N!qYH.70w`vub,֮XrzUf#KaYV2Ej?X %iC3EZ5H<%;J 08W w mszYkf42 bErS$𵽧y5Iam7Sb;U`gg#b8nZvFxbFp2&.zR09 );V@ iqLr9&J28 3/zI($jHi*M@ Pr)ҎPQ2GZt?tHf|e8*kǽY!s)s8r;P84R<`Ai 6JsQRJ *Ł1h|UT@X+Pާ]֠ a^vfh$]jMTZ0ï4J$vI(r{ty' gH傝52j&I,pi\BĒ>1A&_JTW H)FC:1F1AW vJW׮RkU8l*I ;sQɧQsTcB-NLzMƬxQ.Ʊ  B=H|ךH 7I)lk`>r-3LX}ir6Z4]:v[_'[)Кcx`S;HӴ-֚IXXhV-,䳓acIxnTF@`pLs sG9!px !P㐪4ܼYւ84 -P-3V:4;![16҉ !ɰɤ'isI}(VcEX:U)XJe\sSGNqzzԥp;R),FQM}/JdPE z҇iҀҪV#QA=wҙ,x5bɓh,q5s&;U˫:h.zL!îjX9Azz74.%I*HKd+`TEiL&(k7r];Ni["2!aHMi0qG0r7 җ튦Xn{=1G0 JùCV.)]!XM,pqkm=j1Q1`t$xaZ"\GU('DҒWO $Vrˌ,8tRU qp*&`㩨lDqsȦL# 'sg;Q¤10ϼn +dI9nVpQ ܤm]VE2Ye@: 9@bfgK TGuPyBb]wVN9U<5e2v٩h3rzhPN PἌ`kMƸ#Rs8>T2i*wy ' * k"S!V9U0 ,'2$Rp)CȫLM] ;QTXtTS$:Zѕr T#;j QZ.=EN{2-W# Njqm'QbUWKn^ n4E$T^GP*?-\Zliېb1֬MgIolɸϩj} =zT@aVɩ;8fJA 3 8Sǽ_23l: AYgQ`Ģ)HvSKګHX{(\w9O.rl<>KzU9NO$vm5*H8r!s)*+?Vر 83tjǽ4B[ #L+=t&T 8o p ȭ Adž`zpiJiN)74Y$cSqPD>Ʀ ph!I*`1Lu$c#R<ŏYf[md(iG*֞$#[g{fJdb?qV;fWB@u_(\F]ރjG:ޠ|ɪ¡V\4~\@9&n9A#jIv*O(![G>^6 4cW;yc128fi[;In uFvI jčFvi?x[x1RЎT7=kj cJC3W&Urj %9>ca uHT >( ւY1vV@K9%T4,1Eg],"?742D7?;V2rHj(J.W7>A2͕lfeSVP(HV2cϭBC:b2.3j4Ӧ7_JidQxE)[у@yc{+VtOUgZF'5JŊ8#x *aXi{8{ޢTMSLB7ғh Mf1Գ;ӑH ,(=yC8!$ 1RH*&n 9ךLHE$;naSmP~^ )ꦚ vrj@FR})ǽZNf۞) 98(V tf5 I4\V.AaS@ʃG6w YV2 Y9<`RLQ8q9&tqӯ4H\FRq7Z{xZ2>J ,-XWf8 9ަd*Z#fH9B3֐Ğ #>yJv&]ަ8?04bL502 "8\NN HF=P95w9;\u:ph&ÈJO0ޔc(hiؤX={O"Fi q4qNVcJq֐ưe0 &y0ip=n?'~iv֚@IN hlPWh /^=)vh H84SsH2֌RpبJ(&(# '( . Hy"jԎEp9ϽRg$鸲y$?Zfb=8 N4җ1@ pzQۭ R=#'zS@ ӚU$y@R9)5x0+wތ#ԱRT4Y1J:RrqMlg@D[hRÜTM9(AUB$R4GOZgZ.Hڄ69E\iFsz8t$@ۜ ڪ0Č{R)y [ OJۊA*/6+B bfU#s[_E4 ZL4އ4sIց ␓L,h*Qң&*'bO4a'بNF1Hv'"JJxL@{kRiDFr{Ү{ҰG iEfFLE.mA=sL[;"F0qQ$r=TQi/&`sژ5Wjb O ޞOb"cިD_ԊcxYp)' fF7 Pm![h82e]2RdnL/WQm=i@Q* r$*ZB 3ަI0,6Vpr3Uerڃ0:uOZ9,Oj\zS33\ni84HSc!ۃOUҪd›sP! N1R27qLqHh@$Տz\n*1bځʖJSN:P!;ɧssK<5NGqM8ǵ1 Kfq@>и9ǎ2zү֕NH^BjuSdۻhhidP cjƒ92ǓU0f͢%U d*PAPHD2>\CHܲxڢY0&AZdK4ZNhZ\6Ìs(5 J4 :SAZ]Meh31ɧ9n8iGJwco'?<^,g9d@TTVVfLdT O5"5ceQU]TJv>¡ʾ)CC|=NgL ue`Z%ȣbZ$\F$H>y3=O")82);I7\kJ v3=mX`hesN˦U"Pۊҳ2 pVY9fd!M$5;S%5RzĹ`V ީ@}T.ӎ:zSK ~ &#2Db#sނ^OikSC 0##Kl wx>wnr1Mȧ]wh{1>}7SM()'V% &Wu<">r1;ֈeĨ$;HpnC$aHn<mH37P2 x1-pKsVRTlC9T ɑ[4*FzT.K9qP0ɠC ]b:b[< ?tڭ f5" t=X~UJxF 'j$תT=OI)WD pb8)a15ayL5,mh(bHi?x>ҤW''nӊ9f H&R'K23ԁCA0 oXӮ# ՗p$RɈs@ Sj.U *- 0u$\ i9:faWAEUGN+DIhnsTd/PHќ?3J]Jk9hf"߸#4)$Qɥ,@@\2sɦɥM1J a'sM.6M+/ +85Y؜)i]H6[804qC8lq(Eɤ@db3y)sN I'֚XۃQZ3ڑ@ZP*d\eq@`b؝Lx)RuZ媑%ZEMeHZe)XG$朧e]Q56S-I1(8QsC!֫gcAPy  'K2=sHӔ@jXlCU(As!# hc K*˺+]pKcRwо>\=`_zTiȪ˯D'* QV:WQ,@%J…cayg $Z+8xK2JrFp3RM2naίk6@,{_K{і\ԑ,fDS/C.=Ҙ.ёRi"_6hROCQ>Xd R;)&qD66*pHZqcE+Hc@eKI1,֠2^U nz-@AIfh$:_,/I dtLkL'98_s֑IOLho!>$B}p*€&S;PJ4o#84ݘj`Uz`8fh7F}ؤNl3#J{6GCMB55iƚCKB:S;PF1"*6&ʐbnCjM)tRM4%&((@ޜ:P C(4iÚ@8u&DqNRO֫,SGZA!UGrMBg9n=(jeM2H;Vp|'rrMMU#Y GZBn{2i%ʆ1ETMgU@3Q5&$U&ԋ) dҎb,H1MZkm2Ojm{#,8qqXMe=xNk{xEQ5'Ad.d]9*9.'@Jrͻ>-_`X4\T^"pGSF WQsA.&AIx::VJ9=*i9P_ZySW4mufozrJw1U 4q܍U&sU(*+[68z16J6JZQ@ 0k?0.:dllނm27[w =_LdC~/sX\@Qo"bs?ZB?7z`Ș( z~jY{PZ+'ҙڞ?iu{R.E:oyMRHӣR79e+׊PpqZuM"pj5WF@a6'f),NGhHJ3L{`!)ZFA#r{TU}Χj`)$)bW...[?hXIJ|i /h?[vnnYhZ%K(ͷ<=s(8\p*\)R$9Iv( zOsTu܋Q; ޕ4?!UX4ܫ3qMsǽ֠[c2{S(UEϥ*V ZTDr{R?# ؽْ$i̠g2\SL|X9KZG<rиh=um2G Xksڭn$\7/`muT3 Un9WWyQdm5!4A@=h`njz:ߝVUciȪNMzR=꺷͊yl%*g?Jn06ݻ9qXqe9Ƞ895CEqҽcIZ;sMhϯJu)5zT⚺ZvZQ{Քn2*623El mS^*TFCKڀƌsDX{H$R.ǥ?1Ȼqc@e9UءvHLGqЊO-N'f9taGc1\BT5b o:0'5!ȫʨ sTg:1@Qڮ$edST`qS Ih)\w'9i#@@FLQځ niS@ڎM!r:q@;W֙NVsp(IP4 `KUy1$kqD)"uh:M1N9Kn$_gXݰ7`S: G9r@! G rIcF@M;q֐ xQ9&;ҁs@ @Um(8zF$1~8'44L\5 Ը*Ol8݃Yw69ֈ993HT9hñt;Vd~VdGJϞ$LdO 587fv[h Ӻvyۚ\0JxwҚG<  4 \g&n)Iv 'B"(OjnIޔ V qHgfh 1R܃ӊ٫̙UiVJcQF |7VLq@yIJ:l =4XM\)X#ba]uv5ľy0]})!{!v=- ~_NwXy1=JzGqqV==h"\Čn·k4 99*̝zO4)STKiCJZb;Z FSf:uE2ad1ʞ[HaJSkx1\#9cC=znNC$&- kG_?*i?5).%a*Teyj2 oₓJ,9#Vj9V(kpFΪm4Nf "$|SLQYPG9F{T(!qfz$Z},mbYHͩH¯$ZQ餌AcIb|Hґ$z! c8nإ)R8 #'8 sNÜpVhEX=)zL$) :Hq"nk̷+#dT2TZڱWE7iڕqi͒6Tg j5\#.,1hKb* #n=)žj0Tq@g"BHQF:ӗ PK&SN (*9RGUgobiv}EJ#ެA#ci&WwG֤XFq)b@*e 7bdZsSW TlNLfܧ#4ܜjT$Sz A1\h)Ō#tQޖG'd֢wP  4whc5wf3]^Ƨ?7y0;Qx z.;[+Ի`bZi +\Jq赋X>\͛+XMLѲmIR@#u""t^<a&Q DaP7 B*y5Te,IzPhY9vsP$jܸ {##vsMp1Jqҙ)a*9SLTR1R# sWb0*1Bjҙ4,"Ú#4iIdvP(Tg֛) Pܜv/9)K|'^A)ьgB?2tni90h iAɦ?8>pF)ҧVμy.r}Mn8ߵ0 1rW+% ;dRށRN{Ҟ7# 6)8gh g-֍NI#(Ni(>ZB6'֬I\YO=Lzs}*4#!5*qHlDv?Zz1$w1J$h1ޤ JB9dL0N)l 8ɧ`2{W:pxJ P0wghOaNCzu8r Rz3nzb~R\$֑K 8 zP,!$1Uw14v#.x֜BQ+~aO'b(;`v&2n8'U>a *,,TMgE+8f!>mz̹B9j͝tд2!FMf[JV}pr֑:}n,ҵ R{T[r*Q|+9JJȬzӼOJT)꛹$sG,yF6o3RM}@K0@JhB=# JT1l4bE\ y9UZte"̓{P163ӭ2V(Ȍ) }i@aIn N$PET?2 Thh0U4"lwP#dH(^O4q Fh.7HJUU/,D|?Z!mDžsޫ`c#֝ Aϵ!9nOBXE\Z{o)֦E\tJ7`7CԊbe*NOcQ=Am H۹t \Ɍbh5V1dr{UqNUS׭M!ȧsd@ՙul/q[#Jɽ[R?J,\%rP):?O/aPӇf!1(0@⬒F$ɜNJ@b- 䓌zf TsQ+ŌmÇ䞴,PF=I ګ:Һ76*H{1_f[AaVȹlf#HkmȤom(<-.op[>&Y޹53B{$'M8k>P~jPPY1OGLMmb4d~o3OJ޲rN:|rM"'{(ځwojTߚ,5Å*!~/"ͮPcuexG|Ν)I#3{vjμsM?k\oj(o$$}EE3Xw:ۍxH `@/.\|Ӛ <3qQLMT`R-Z2%vHXs#z61esDT_2=^'ݖ ) evqJilZ\)sԋ$H:Rf=cf#p: <ұ 1ޓSsCqN>ԇ ZJ6MzG4z,pNw9H|s@3idu2A)".>^0:fsNcQ84Fjǽl}bзcҾx }t#-VAJ*(8vzfp횐+H˴Av9 yf: \L8Hhr"7zbRLTst=vH~Hjr9b͎¸xcK]Sc*o^hkI M6dQ=u8ir3Zc.sVnu(e’sHG+nyMRf!dr1==B獸d횆>i.ǡCJ玴{Vۊd#j7&aT+1?*ҥYGTV'=*khacϛ/GJ! Tdϳ1rv G**I$7T5y<^:vqv=ɕ?wL]Ӡzg^V2#ҖF .vbЪ1ǖ2@$yV࿘;Wҩ3+a"Y*2j^X*mwb$&n=%3ҝpeZ] N<.O)6xI`\V$ɣTj'w,89Jac4n#f;4怤 Af=F88pqF_qJeq3H,Ky7V 5)Rm@Wv>*ġϡ/Cbm!W^ũ HK=ESX$U]tl֧k੊LTtVV:jKVnnAڄ.y$^$jVhlחR; ȢHgʿfr&H|@NCuTGM.p0=+< \,Wũ:m$1]\JcƦ?8`bKձ~`4Q+Jvxfo4yd$ۭ6G=jHRb͹ Fg'ئR(NI!` <ni1udnW;lwSLڋ9p}n@sx+m\-"(['VLRDc ;Uv_!b%&8Ri+>?qE*"c#V}А#4˘kQ Deb#rE!4= s޵-n ?S[ϝ;iP JGVwHÕ9**ۥ 0Q%1\'z"mnA6ԭĜ]#G{֙4I$R AlTweXҙquI=uBCu,브S:mhqǻ|=jG {P+XϐH #AJi:R'J!8 3M3qNh -O7ڐS#h$sQsR+!^eRS T*ǡ* U9WdQ#Zo+r)떨Q4含aG~F^0MX9`qPn\g[g`EO 5@'4SW@4[})(8)sEAG4Rd^u␞Ԇ4a4r!)JiAh^KC@!)AL@02I &^;TUuuB!Jx3֨1_<8l`¨D}{Uh&HՋjG3 -I ♚RšHj]i4 RAT4RDcFH9U\@Q^)恆(ygў:P0ϥ<4p8G&+sS#sW֞  MY8Z%2qJy^#zp2qI{9ZzջT$桝Rr{S֓jE iAڹTmH;⑻zx.Y~LxcˑV fУ➣-d H"HLk(9ب FsM z'+Q҂փ1:`f>n晹#t|ăڗ'vh0y0#exn)$1RnMZCL`[s/6@ 恃 ɤX*DWqP˂1@\eۜZ\6̞1C+~m#hzsppz0JL=igJUlI5t⏔7h#+0*0{T6r G0OSP:]ޟ -GcY9j9hmS6+g=뵕-A=SH & eGX_̖@=](reW*D(,}LdXTn -Gr!M9Wk(:u<țjyNAhdJjF;X:CO1I&#);$wOjo&FGZF8#d Q@=H6z vRgҰ^h`Hg&8Si:4 D}iɀW&1K4VUblZҳ'eTw2и0)%xFzs/֧͜3$#I:SG&#W9ɧp[9/ 2ǃHG7(F4V}W6&+Q҃6E5``4 D!n*'lhFn(F\ʬHc/XEGZ湖TRޕˊMC zQ4bW;ز\Skk{=qڏsoۤ=+Sw"KAZrEOnfjZ 흺/8XFf510,4&GZ-8B8n;QT1Wr}JkSo~i#9ZX␂;JC(}ixx;R 9ǭ4(Q@J=jpM9qsErPsRy  N#Ƥ1 be=k\?^8U5}hev8j/MDs7{P^"NI*6;#ːe"T V,GpIHV\ u\}2t+(S+"=yBfUhnxZz}R"vJ,DfҬm[⫋8ւȅV`>*eY6Z3 l@X$m);p:zMo&W?+ԦkVGeP:zȅ['zStƺ?0sU-8-Ls%&+`{T, )'UvdͲqTr,D{UmMk =3UQ(b0MgrGփt:Gֹ5[Nȶ$[֬`5G<ظEqOj'PAFn^o lLe}+IAc޵@qH|n\Wk*IV.X1L{[$=jRTj) VEP JW!x=p@i85׸b rQ֑x)yϵ!)G҃@ *E4)9cnI(sYʰw!GK6ؕ6ymuH`1eA t4A9iR zsP,1W=j'-AIsN;RmE\g48bS?t8e&\A ri㞔+#8Gu<Ӻq&F8Nޛ1\[K6=i $PG')?.(O:R40;u4;TjKbHǎ: !9xT~\tP(KtQ!Bņ: nG^:r\Rr w[.=lGUfb)sR:E"^B9dOV zFqR"cxLS0)3fi})R&vɦGrO=(;x4)d^iÃh9;qҚ8LCMiA(i)S`fގ3GzZLKO@ihi(=!4"M OiI B1فyڣ,() zfXҗMOqG;LdGcbz Oix 1r9=*$5214n(H#&1=!Րg+mWۜUQbl aR4hb֩ LӄL\rjEjS$z'9dR1A65ZA֥fsAH/\K)qQ`M,zѴS2hXM(i2h@݅MF@q4$YWFAVcL͓/JZ*<Ն<;a)29WsS750!*HN &zxq^qpFbS+iSՐc&:%?L1y⃤g QHŹam$j'˜TiiV`ҵc; rs@GRf4aO֘yF T*T@J~36Ȃv01Mn N!=k`؞+"2BaT;ge XՂl6@R3=jN P|RΣo.F9s[&X26J3HR1ɨw2r1L.J.>RcnICz檳pO4F>hr"v<>[UFI9 !/ n= a"zӋ -)*H{RTMB6x) H9Ip\S yS;Ih!ڙ3֧ ͥs I 9>j+'+nM-ef~ 7ǵ4*U:js$5+++pciUqʻ9[1bS:Uo ^kViNhlq(O gGN$dȠJa =*Ͷ˄p*%< Cip 9ۚgc4b5 LOE݌rx!29>LUCn\Rb )2JB?72H:qҀUO=iP 8J#qQvqLTpz}U^>nÊ桎TggJ]ؚ.CD8 f=$)Ѱ7 Ҹ\O^9#pxi6('( 9V>q OAHF98>),yLX$>cڐ5&RA: F.@nI@cQѩJ2v䏡IOӃJrFqLCA@"FH)Ë5=rs@zFQZ@~s@XN+bn: Aئ|gTM^)) MrqH})/ׁ֬G|x"#!٧a]Mp~lqUUf/zUA29 `ZP|3JȮbAu"/ޢb䞵ñlW<%s asjNͽ7RE岻qUYL"Eޟ).ijxPHGv/p;.B+UmPz[䵘dk'mihW^!VE!x,>!*g(!y@]T 9ȨYnpAGpdqjBT(VFE8)^h$fppåC*Ҧ (H ۑ@+l*nejPFFR\m4Q2!TB  _u%HH"2s֑JFgD~td.bW5";UD@KfeƗ*jRiy7ddO͞1!RO4;{{8A=9ns\rˌfdQְw{P:B9R\'>rGZB=)xZM8sIRہ֑ )E2Fy5n)7 _R) 4h=O&V;_JVM&~fR*v35ehc~Vdyj۽9TK $cIdmbQ_VxsyKc` ڙ7+2l4FIݑVҤYHh\n+ևXٶenԀyUFgz` cJGTU+g%@p~ZuUٝ~sP>$٭AqfVl zʞ2gڣhP@UTZ S2n" MPx} P3 KapĞ{L"56Kq{\s*yU;ba%~V@X.d8Q$)PO 1ҶaqJ[iȥqڋ81=)r; sdSÌ`p=iQ[;RXp H,i )INaI&㨦ӭ!4[4uniX1N*2LTsޑDXPsLTd( ^STԠgi r(+Qphֳ. [.T"=1L.SQ~ӕ72BD4\(#G'X4\)#MJj4b e161FHl?FOoKKNv.5i1DʹE($GJ'c8F)1/Cy$a^x)摹dCҎZݽMǽɤ2 ! zS= BHmd#$ҩ)ydR֐V*8y"az*KL)H̃R:N8\wwtt0xJҶ ʎO纝4Xń RlO |Z ,21P@<RMoJi@Bpud u`;-?P0?UJL2W1.H?(Y~Ѽ8aHGsc,`(wHIVOmhIVnv` 8{(rRF kZQZ>n%KX ;%aeg$ML#geڻPvmBdcn3r"0Oz@eY1zD*Bb#9OR[/ +8,OJi_8_.>O'2OAJ93RqL`*HJf)ɝxGlGTMnaGjV~SRPm)"XaN;aQI2A܀cJ~)E/lR(o9>"eHF3MFP)& ֕b9p84ili Ҍ3@ >REFp  棐P43>[gT1ϑޥz*sH;3S%ڇEs܈6{ޥBýWd16s#' YUY8'JNsŐ;vxBsf[4sJs3`O Ԙ S dzФ7Z\ǚ f|y@i(M8 5 h1CCHB19i=84!'ÜHwEXFn'I9I݌P;(H4&LY?1&3Hja75$q&)xx<'5BrcT?=f; .)E&9(ڗoɸڃ= &9LW}i63֑ v6QqKӔz.1ڔ ~4BKGz\P8i) C@,/34F_;dN'w4`$@N y4;! 79Hja)>`1H1p8 >uLnwqYzޜ2 8ИC,9جXU ǁԊK_'ZqM#?*玴H:T!GsJҰgmԥ4 ? 9VUɧG9h Ɵ)|ҌHl80 f\sqVH @nsޝpO1\`Q.\-HT R:96Z@ FOlLLkDpM]$+ae÷j߉cHJ'1r+CS-MeQNH [#v^r ;SɧrΒ1]°$`drzHd&i |Ɯ&pxnR4~3Tp;)"CG:7LNV\F_iPrZFi)7di0˺ @c=?(=3ޕ=}3ުK$U6(?"R IXeB&yz-(6'֩i]aQr~SM.Ġ(NEu "`'HMIcsDT%sVԊ>!:8֟ `t֐S8LE) %)g4Zѹ ;S\tN2ǎԇqP c HZ=@㑀)g4q9Rn(rx `)`9i28fxcT⁒3vy P!GZ])Rt"If)T Td"W`wSjgJEXʅ"@A9SBOTaG=yRnE$&H-)v gM4(Ppj`M)Pi1Ҕ( ɦov|()" Sӂe Dٲ#J pČb`{R1f9V\ !~@!!x5Ҟr26 Q[RGZz)(mP֘ ڿ=1l皔pɦ!tD=2*589cJg 8횏i9sg9曖 pH:UIt|@jBy֥@45`z$!Tcz?8E$qSL@EL28時_;H'D]JB@)} =*.HG50@QFAdd9#=  S0NZ@ Jù1v02Y!]qJs*l$Ȧ7$UȊI=v2;Q`+NEUr!9OƛfrhJvCHۇdrsHZSXB1~:$3/9ҧV!: Jٻ SQ;9c8$?˼n< !8[:uH5"m˖59LhV.*Hrk&P-Zt޺"pN%۔)A5[v@6ֈ;5p;҆ dP52)} 6q L\V ew(fO𣨩7u#e]v8$SUUؔ m1I9@ S0r*w0G=!p0})!<i\f=)c f}*e\ǜ v$ 3)S8Qv&vq=kݝdʥtDI?(Y7XZ-, ex;@:ZS Cn9:#LnPc Un ,ZRG'Sv`r#DU& 9L50/S;mH˟AM|߻XOzEL2y`m[TZF[v)ĊIH^3ց%pK2zbhWM#ʙ\=ר5M]iw4ϕֲ/8my!z 3ްUG`YB 7twֺi$+zֆ'FmV+t,\Ơ~bF7n)bze($k\jWjV!q7wȍtcS5n( RXOQ>õ+Ԭi[Ċ6 h%TqF@8N(8E#Rop^Լ:}3^( S#֚ri'\S#4N"~ؠҔ5MHM9'1 H@#;Q9qQqR*c.N)S"EiŻTLFh3y(TuĐ]8$qɭ z2Lɞ5+[#F[wnM8)#PPF3ڤ<-TetcR,S@z 4sڨRx4g4 di;pSt"qݤ45d(jt|53!9 :Jzc4Qޠsz桐֓EZe'LT޵lFYc[ `t5|Qk7~b@fSIR((!00 - U!:Te~EȬa|J=vEAI*(B7N0)7э5X=kBJyPHfcme!r\;Nkrh^BmۥHvS X7 F'*{-K3n !.)Z\.;S>ޚI`@^gUpsԱƓgwZ;pʁmjE:dIX[)-V,cjr>n 3RíHNS#M\rwTɄڦR 2J#*kOCDܑ޴PƶQ1AsUjEsE3RjG\hj"9QqûHʼn怼 0O;$zqɪK4F\A 4֘LS&) 0WrqQKA/$ 586z@9MyJ$HaiL 3JO8h2jHGa\UIJIN:4Q$ȥ2q5:u-7;8쌭*HR,x&Jvy)%Hm%sLEU''#ڔڅ_ .84r })`(PԂ-xb\Bp1DPƵ0)SV^f?Jdip; o#+qР8ø֘C$W'P1B=j\J7M!Fؖ 9Nx4*8 zSDI|Ԩ'ҔuRc6ޕ@m N\LbJm4<}i*7Al(@ϹM2iW .¨rh=yCphܞiGZ@pxSqP2i23Kv{wdnF{XAaQ)vTIUH(hSJz,qR)) F.AP0bx4<Ѐ~0=i1@sNV|S)qHsB sAVroպ_z䴿4~ou*'3Irw7ܥiEaZV99ɤ90ZUttEHms"L\%q$89nWԩl57HlmSH1)rFH> Byu{c;SSJwS3Pn5" Thx`=h ɦ &n:P Ȥ9iFO4'RidZp8&sZ,1Ip);Tnű KE"T )'1I$ސ?ˌsLm)+ }znlRpOZFXޜ2iRڣ=h 1M#h$RN3Q4qE9&@\)!M6Q0JN(>^ 6>X ߅&\F$0ڬ{U[wP4sV ;A!J>Ɯ8ne$ҐO($A;G^ S$O8gf#=h S@ ڍ5IpۉSqJG83cHwPGR32VPs(瞴?=2 CnP&49`zP( Z`F"~4::72vښ~cEr"CIvi6c!O1Y@lW#1\!9;C VzҜ׵K4~&&.ԡ N: Tg~M2$L >ui9n;(ZSHXEP=8S'WqQ`"ڡ#@Ry~AXw(LT G4X\{ %FspFIc4>b^Ԗ^dJ.uSH#NVԫMq#+;ԸRu5n9C*STSS @ҝ(ni#MjqqϭDSEz4֔4{ 1S>4И8?-'A֗f9c&{vHӀ9f*cjRҫbr1N"/\qztW8^渝Bs%ԁAT1[dB3Fy&~*.}NٓLjD~ moigSL/gƔDY#QؿMVp!ȒF\~U_yRn;Ճf~SUN@vnF@J?:0p*Q854ߘu犤rJmbIӍ!z2ې-WKmIA\fF2W7'tk7kQĮ GAҼjv]G+,psK<3JJUFJG~ũA/Hd|}i sކ$YPdsQu1&@X=hULi:x%34`Y%V Z#J P1I\@$\+6T*C5FЇ-Wtat)ȻdrzRqBS:;oW3( Xz>i3R`&\Sο2+>BXdRrQ16h#5y=*bIoQv2}Q z!ȡݤqYpăPL#e{ Ei\V@Ezň04*nw+3S17Qh"Go T`\R֕S"j:oaGZ! W@KR[i,8Б>2 hB VFBw dv=+-)rʠ`w@1T}ނ ֙mA;P*z a>E< ~p$R0̪ V2)RncP ҕܳt4qb_ǥj$ĨN;sk#SzՅێ[wc*B\f2QQzfdQrrh(TW-֚1 " J)$z ShuCHa4 `lFi 3Mp ЍrJ[Ta>{R~b ``-g(LҹA5kpm9Sڹ:F 'Bkt}sī*ak* M`l> +J lZȘnh!@zITVvNW%߾=` h 26RgQ'媬 +,ђCA<*7(ތjg$,#50d;HPA".ZBfFEraVNw&vr%cЎ*! Z~xrJMX\TF&櫻4ɵfq:/&5,hdu AUSZЍ 1jDrw,֗b֡)H1A@uE*H d1ޝʩ=4 9Xmd=4ĵeYe/p1R$v[MZ\Tѫp4i9L6B Vzc+cRICMStEa&F)ʻWɤ1.~Z *zFdwR gHce^hBAjj+cŽi 9ֈE2p`oO1r00y99=) U E9TSb'PM*JedsL*::C4EcS#d.qL[桑>lR C0JTp)J: \s ރ^ҎQsd _?-FbܵYp7)WsERj66sJӑNLX&AS1Q"jfmx?y4\,<4 P}zP;)L8ךLjePFrxb F_+W0t02j$bՑ44R8ӆwAWNRg“LfU;PzqOޠn BBn "Ȝs ޤ<>xh)YzNJt@.fB1RfݙKOXiPV6auԓ לHҢ@VBQǻ faޙdm9FıV힘=)르53,>i̦7df'>!hYOijzI ɪ8YYJҡc@ Nu$bhULT*xdɥ(fQN&3R*@*EҘU NRXiE7"4vi h FzԙXsDgFP9+HS){qjd4 R)Z3HH4Lel['5 ,3־bpI)ڶWă槗OHԐ*he Iq>*:Pg)35- gUdlP=e9KHQ˦p5wu3Ibe 1ژYwUāԳDg'j1* OE~J R9i TKcH;x#sd|#w`FsRGS@ r:rx]gEX$qjěN;iI'1mrÞN֭SiJR0)v'̪ygqT搎J8i/JyuF=IdS Cq)w6311M&@&ߛq#ڥAJ$ҁ܉x p*`T֐27.GjB>)1rwqGJL9i8#5(SP)6JGy&7@~`Tgց^2aJ^\ Wp T^zDV'JBÅ6M8FHTbؠ~.9[v*e9B!aG#;Rd^iD9lOЅ$y(ȊH(*ka4DHRhMtxNcN'Ͷl3XđA\]_CYSt(zjY*o;R^|2Ӯ0~j^լ FAR]r׆c*!V|:IN9<%1:X5} 퀸_ZVBZS+,d)D&QFWw0P~QQJeO6Qnjlh*"&^H." [9"3āҕCgf' <@n-1Q:0+lse08✮bȧU_.N@'o1#NFT,SBhQ< FӂAK,d<%*XЋx?a*qjp<2"Gq?jhe[yF`sT|ۅ;rvEXV>`8.CL%ϭ6 ʌi#U˃jé&$qzTťx*1((P[MyLG{VPz֪h4`i$0ǨZ?vGSq8#Uї+]“UmCPWͽ=iZD}+u֝W%T$rl Y* %[TܾӚL^ scD 惌d @y994\ 84cN*F8~O4rdPH 4X ֝'/Jb#|Th[*rB7uPɖb 1.We>ϴu Һ;mOjû].t6"HLFSqVm#V}$!E?sOZ-! i;YʼnzubV`S78i!`PV#6$x^iP7@׆4Б׭VQ6®AN1)9=jFH1a8rwRW'nޠDZV)ɨZN7P3;<╣5;] GZ%GQ@![ .p)%MdP$uD#(E'&ݸ*Ltť8$H֐TMV,q҃~vz9zSa Ҥ j4ƈPͶ5!֭TOjBWa ֆLbTRĄM#8$9w/HvxsF~N4ܰviM)zROցgC '$w|Ss@Ҋou(u R~\QRg@q@j6bEQpn)@ = 0k—h##" uĜt y 1ށBSG\UityGe5)9yf[y$4>wL *j:Nv#ς5ȏa95ERn Mum#1N-IBXAӜVEھ8-R8឴=i4 "8+(=HBRLp)˞pi1FHZCҕ})>n4;NswP  !NR+gCE jN zl5X]\Poj[?tiN#5Bg"隂D*Su FGz^Gz L* ON!Q-RsaM)|-4Jk " Spq@$)c#R*w ώ_QZz!ٸ>[͜c ]%tY0 +I Vqd,) N3VHm'$ԍ.A왢sz Ȟ4 ('kbEP/Hn@=s 9HV2կ*8aҵͤm#1Pf 1|i.ST2`7ִ!zń֣DL$9+Z7֑E= I$JS7&B7j7GU]BQzT0rF}E;m>[°;OLTelVE`Nzmᇵ"`-LNy=X (z #BAJ@zӕ@4> 'J=:T-CIsڜ$ 8R&̀c[Qgҩw#Rb$?(54]hn7zMN=KQ <@JmsH? QGzf❒^=(+IK0Hv$9ipM&2{ rE;n ڔ(җ P& z`S~1‚iE_0Tv`,P; #*d `Z sLL 8⿍D R3֙,cTnjH8 B)F\b@ޙ֐1NfCTpjP'1OQ})zu=( 8!;1@#4GJOƔn= ip4a@␏^6 xZ-қڧ6|FD,y84h:H{" f )85"zL9HTozwZ?t{-w&Rjޱol" @E`]WrjlB\.GL0dZv!LTlI&V'ENI4tJ8qW1PcjeQ&&Ni4g9"5Nw20 <* S2UibåAn'9,ֱ-$fSG<\v9Mf# l~sڙ:pj1R@ZvXr1J~sց bz iR8);}ib"zԫg=WJ֤ jP(2n49M@8J3JS@)zSzR\ iZ83H)q`!L$nM41z)Ԫ4`:S1KS"{9mh@Co֬0|u czS"ޝ"FO֐PyF:ԋ@Q'A@Fi3\RJ3@ ӱp_z`)SJ6O(DDSJRziҁm7O< ܭ#ޕc':8Iy]|.BiCT3P|{4Qv5zX@q]CIk:H-6PE=V T|8M3~03TvƔwDszc:9p׭9 cJ`PzBv4M eQL8=H= 0&hict46#-׏J F-.nL>@kBfR\FZj <)ޱ5ڕzmLU9HaA zmLaҸh!x>YekV7*Y'p8%hp\9n3PLb3ҠӝnSH8 RM@y朕zӐY?E "qހD]'ւ$2h@3%t0q:>1袗QTrƲ!Sһ%8s &4C Rh鞕Oƶ#27llwJnriJ -Mz ;B8qVS)L0qU*܋*&Tx1GSHc}#`gab7/ٺ$]dIRXD$S("˚|N[sPnURAwҵ-nQ@u&\vQҐIܞv524T*p"dJ H(ϽIH͒ \^9Vf49ҫ|h*&(&=)2Uz VG$Q .R*N]@g<բ^K]d3xTʇ:JExެElTsցJHtj@B6&ư] (<(f!$8ShSrgR)!Oj3!HyXSGgrj7MrnJ785V&cҩOqʼc4L83!y8MWq4C40dt_Ҁ)2E֌Xii.zD'o?Nh (ME4f`Z< E!Z9O`Rnڸ=IOZPK^3 g^TN1O‚I1AH0Hpj؇ܠfPj#U-PSD͊XH6ԃ򪱃bH2 8g=x(&ґ8A4@(sԨAmF*`ަFj&S`x*'8 ! 9nzb3إsJPAҀ+ܝm'X p;L7!RjOWBr0i[OP;m$# J dӇNF(ނz1O˸6~\u)loZn17'8z&<1 U)[%j`=)ng|e#&}{dW^Is"]6rxQrԯjEyd݆zs%8/iԍ0P1OّNzҎ>Z ӵqޞBiTڙ-GN69 @V&1,H.܁ sڀQJTO 3r)O#)1R m9R$QU]W=.$w&p|dY,QX ;S.F1&EY5Z1f&lJJsPŒnxٿT g* nF0sY8*w"CH()vavu50TIY@ (Hw9*Ra$X0AU>2mmzz u,8;1T۲n5 IGh@[vD<.%;#D[RAJ$l6Hxr i[,c#38RXes@: G=DO$L{S߼9T r q*Q¡ro>(Xbwn< 0*9XnC#N}* G Kw ;ijy_Ƙ2A,j@В,lǀV01ޥV #P\{\۷1E xHdٟR+JrUXsS]_'dd7Vr j/L} i5 {=VFrk^Hg 3!ݚ4QvH|]\i+h\HPrk[[u@P1|7 y%#-<@dgvOS aHrrM*Ɏ8Khdxh%z 擂:QئHDG<. 9<)4ɪe{I&%j % ;r`U{=ҳd~$x1b{$3@pMT0>V:Lv mc ud}byp\uR_ -g]o#*|ҧ[PM];vv@E8;ePnʌW)eC.Y @ 4Nq3*m{C42Ӎ(zJD~bxO,#ӑ̄ ԛ4++c{Q*ۀ£ASRh8n>W529ShPH)LŒ"FItl1ڝ0҆Iy,j^;iExibsI6JPR(5yOQP9zqӕFbc'ROJ@3@X@MP}i͍riǽ3srsUۻҹ/ۼ4~Xqr{VV*F ҖƔY0XO}qÐb)݌R >@j(TXT_SV$*>aӟM9q@{GQQ4Fݒx UɧŰ-@'SoI$\ X"шsN ,|1N@G9>LD_>I>`as28jS$ jĥi@\AGCFqL.2iRfB3@ .(\g"^)-.:JFj7H@4F,jV[UdDe i9jXE#*n07+?(݌W+{c= =몵ԣPT}M6CW&frB{F,k+3EF&;Wl)!F;TD<çJn8EI܂Fz-J6mbs88#\֨l&ݻB/k7(qZFBgRNj qQTroAZȤ1SF$*2ҫ5ޣUfϘi_s@Qm``U<5z7yV-}7$dNM$`c=DCg# S#7SNsHfp]kfFW֓EEٜBGj'PƮb٪fwAWـyՂ21nkvDToԦEy9֤T rh5CM64Z Frhg&`F~s8Rhi(Hp3s#T&2 bNr",x^dTk'/9HJ]Xt4BqӒLsg=ne"$n'LVRVPzյ;FRhb{L}ŐN:r8PO ?20e7$0$zTA/dx *6 r6N \G#;4*R]Z`5JL! 0J.yzґܮ~@烚Je9E" Z6a7t_5`r 涃t);n)Ff9@H:gLĔ0\REsO۸qJpX:P;':F3@( 63A;[i\.yP,P1\`{ր$ g~4Ƞc9Kj=42E5Rip0lU'5U$F)\6#^;PvTv3Vf2.$l4QWG^Fc)=hq-e_9(8?T123cڵ=ǃȤpЊK`vf$1@WE!w}4)Rfw ҕWP&$&WP1*ckG9 XBwa\m'S\e=}*FAܣ43\S)J_p5fF0YX>qҥTe%Jm9 &ITERp)ѱ-֙c*Fp+ #L"9941\C*\)ʼ8Udslcimbz2X:PԬfKrזÞ@kI@ j%?>FGvf$ m5gEno lxDuiV7kVz#9ɭY${-8sV]y \躺HϴA̸N9*7oMZh! * F67qTfe 3Pp9ec:zRO= p)x Ӝ>jQ=)\`Vg\yNgW#qfbc9YLF'hmQV`Q‹W  v )֥3ޤvh+FE;@w'=B"'Ӛzgt`^r3R`Ґ @Qʡ?uC&8# Tc 4+;sʊbSwm==i|8j@9  a;A$7@$ FLS"YF7Pj-҂,"*6Č4́X$V WMl/R761RJX\7]^W'ZXrI-%Xpy>O,jg_4`r(%WԺ!WB)nN W5y Uu2 wRMBbh|ֈN#46*&TTKЌx4c;)w&YvyQmOPScI<`^($FN)d 1[㊄#瓚m% "H>bQYmhG-Xf67^9TVR㚖Ϊpr q(pX#F 8HKO=( f2i 3Kȹ=ir})rhyq94h4g5qOG( H+40Hb(RYSs;NLMK*'~>3=ˉOZW S-9s#جdʃst-fFqCZS\cܠ~sڤU)p{#=iI#4C*G3ҽ'MV@W9!xdLq]u7%|~Zte ITVء֦ܞVL*5OzqK1HA<לR(yHN "ؕ"95EK}*jpqRbnEUej%|# ^#+}1|\TzDfT!+C8"(>͐3ڥu1PQ>'޴Grd֋w3ެ4,7ǎl#hbg"8ʸrqHV.$aZt+fD#q"P&J F)\$R9Av$ *yk nZdNp!~(gfe qx٦!_zܞ KI@ɫ[#/̹!r*X&VxK*[4!b ZVk5m]<Ҭ$qHeWf J53[!s@.$SӵԒq^ r!{5/d2fƫ R0C Ee3J2{ ӎ%A+Av,YckۦMh^8ZF b]iY\^*8#XT (H t{ BvI}1+VN NZI-lf,2ֵmqo€@+idOZN 7RzPQ߭@sIڌf)KsQyeO|F-H>t3*/Hu%zUwq9\╊LGˎ;)줃4D\6GJbHIP x=i 88$[d zh)8" Jp(b&9gAҝLDs@)3@z0(:P"):g] ?6kFSg&ҥRh#Ҡ݀J)TmNHԡWH)ɆM|rEYE-T1uZdl85:c4Q^H,:S$k'q6fM0g5-B"QURTcڛQЮ|sPzXVyg+RbR(Uح3AsS5L#ؽ3Ar*w+d;UY;UVEUtc",O];`櫢0psUt e)й>Ƭ(C'L9HE:m2F.( LqA<:(;\h4Kh=i( dS4)vMƁO8杞1@Q7/2ixaf#3@*@RԪ!>Qȧ&ûS[x DNxIaE@“-i@fWT6QGzc#" FV-JR2pZb }*[:R|uC `4׸D +jEs뚀;' @G5$`H&H68Ho3qneV=^BaG1^ jsQM^-NBo=)ҡgqI.j/lwBzf @M 6G>F9+SOkWEfOJq|::RO sֹ<u0!k'P1юyg-)Yٙl IR9OGvsa2AԀHZi X J҂.3Q, Kɭ{ h`>ln3NS:C;2D'2J|AhbTiŨ[ RW"8^z:mb2"cFZ5(d Mzt35dJ"%V}2aWi⹢ɕӁVҫ7RОMd횎%8Ƞcqf;LPr9( g;ƒxH܅\s@ہE 4; Sq LN gRDp>VevܜQ6[i Fn:VslN)̟wlS,e**{*v$PTc"wocҥHGh(Frjc.۳V%; =1H ޑIFk(7rV$e T%M'SI=?JL4Sҙ.#æ1TЮUtW&LJÂHc"sր; vWkrqҜ85=) N!v{AɤP(zO ֣^9)U4ciN6㡦P6nFqo#"tʒ6"L)(*I)ۉ) ^'+ҚRdQɰdR"wm0*Î57I#DZQҦTHL Tf<`qހn(皣+ҎҐva@GTGZazhiN0QPT bcNh.v=i14)EƯ+K19F1׭$AȩT⢑rjT Иeɩ8US~ JIfGzsNw`#n"HG4L`MDfJX1֪ceıGRݰ}+I݈\U{@751}ӊG pv#P84qLjy84@h+LҀ:Ҟ0 ;j㎴ ?RR*r+goR1I@2N($ !pU9 Ԯ>^$`uCV=1U^G8F(˟̊?0&E9Վܮ5y251 sg+:Gy{Iq%a_ ɬ- oB VwG uiȣH2HsV`Pt=Qyg~q_t,* !aIHȮQ=JQC#GdҮ)XpL )O-׊M4L8G"F !vu)ɞݪ%1n1Q`f[ڕBٓ#-$1&EKE &%~jFI9²,>b ! JqR6s@\cF&)%uy<`@B3H(PW8(1GF;OJb R+Hڬӥ&nȣ qqv u# 0=( J]أ#pW:K *ܐF[@$ Wr*#ޢeNIeޮUH|OnijH(@P1I➊s f36G8ȣ'=K|BIԃG4Ȥt )gp S]03idP`micT4ݍ.4 jo)6@weګ<Ҳ1d1VH-+q4+ZeaE!vHwv?)̠w+FpA8@3!ɫKblc@>Z{ j9QHCؒ܎)Hqq9 u&[icy9#2܏JR\VbJs֩JrhF0YǮk_LAF*9a+\T#$=)@ Ju4+ޤ;*>ϔqi ܊cJrۘOfI0A!N1 E(fAۧS'zD<6O:/PX{+L?hKnvT'qMgb VrF.ɓ=kfى%GIC u5'l$0[D{*e sJH#LF*]ye  d|30sE .vg(&vQJdeEsVa"Y1 G,iw{R0ǽD$CR=i ۃp@@F 1)8Uʊy<@G#T҂ZN&I#FiJ84 `hr=* 2+T 4HMHxsV]0hŒkTpycILPӸ ּiW,r;bAخ&O \sKD64T)W_ O>R֪;/YXbquɸ֎pa#S8bSh$Gp*eV{u&ɭ*?z26kI7}kNh֧fXj py@ɠ" 48i>S"pw ǥ@A;qRn 7'fFnH|G̤|X xC}* aGz)gMZ#wϹV66nETsN7ƬFc;GUkT 淐޴wM9yVQ#J4JT_A, 0>5r(XCK(t%-*YHp2s] _-1=mNi9ȴiA铚mj.$M}+r` Ui U3v#bvy;͎µIFGJzGNhF+`g<{U#\0ը(N]x=zt(puuQ+` %,嵷|KzT7`¯:$Z-D ՍhæGk\a՗5'*Gj&ˏ-R'R-cw8C=qǦ*^Sj pgrrՌZxbCv,7\sb{Vvc+:y4$7H2Z9~aں*GJ^+EIbxf`Î+#ҮrUV& lQn*86$tnz Ʈ&"ԉdڰouyn$*WJm&54y \K)' aRZk6QdSӞ{G=Jm,%y;8Ec"VW$ӽ,0j3jjowJ?b48iٕLgsZZ5 pk-rlͦA"7A*fNki"Η#I "kY[aHe%`~IӍg4wt3+D~c%]~@ EƘ*CMaIҎ".j2٫9zfMZi'4zR҃@ zpzQ8c%sXDgAb1ȿr 'PzW=ǩT0;ZH1[1VӰ *XrsR9.=)HYI4m̀ "9,j5HjE!&Q!]NTKcTj1j^+Dbj=Xj\x=ia#x)446TRhp=G Ę;dXⴶjeQ4(psޗpGs\g`.1҆_z\Mlh M*J1s A} psJ aȤP6M?d|sڟyCg0:RahtFGZs `=i pԚa t`ӂ`s֜Ƚ@|)Xy"*pҭ'Me╃<)r:R.+q'ҕT b怸nzTf ~Uv>^F 1\TMc֕T(Q@611P>o+udҋd-p2 @۔h1rpjYi50e9jFDj ^6m_ڲZw: @i`7?uA{@jYqt ۽g}&1ք59.^bRMQ 15=M=IfIRSLCzR` !ߨ>nہUgʊԪ>ypqVUHUE~M^trHHrPzĂ;S>fQ!9ڭc(!ґ~ &_Jp@d7J@pӸXV|t4IU#4@8lN$:{SU<%O<䞴s95!~aNT't{娜lӝœҘ;eOjVf¥2S_XE99R&'*AO"l4RpbA@+HXi,O#*OJ1J4`82i,cCS i ,\3_ޭN8|&Tw9I-~*휸UmR4VY00 KOҳl ըbP#9S¸9)n'oZMH8֮6& )9~+$"7RT#MX(⠑I'=M"ȜΝqD.AfR%CA$`29gU-RDlCUd'xɄJZ$vsfx-&VLc#:Xf2֤x 7T^#r$lKv!CUH-@Z1طdʿJ%[ YZ9OcV\z4NV5,\~FFAA(4^&m$CMWdz? 7Zv "Z@4ʚ76q][PXd`SgSBd$ɤ ycҠRO'$&\ $#=Q pI; 3MT`@.ƣ#OmpF1Ȩ~ Y}S23ƤXa`9%[/ȀҫͭJLG'ҧL dmc5YMR`E –*{`wm/Ͻ5-.ce1T'܃T7nn9Z|SlVciӔU]#;m6Nr)6{ 3>NkQN+\ޗ&# B%}]\J#^@w$ipweé8w7耢ϻԳif'5W3PO$sA>(.TKiw`bP{9R Ãx7hx @2r*@zddS(=(LRJjVbv*ɎvQ^^*Yb*@bH?-M!T5"/cߥH&v!DN0jEjO8f9$Aj ӌc5JRܳ9Lb^'DU?(߼ryjݛ"G ;eWQcڤ5XT z>PpjmqIt@&\P#n=)+h 88M<z *e5"A,Jx5 9 o^cNM JwJc4(Cq\Rcҁ8qGZBOZLYN?<ӳLLB*C!%Q#%;iS2sJ:RS E ޗQG^ "* jQ3.jPqE8qHߑӚsRW* /ƧM$Ei1xZP)"Ԫj%"BcRIJzS$(Hh4<Ӎ1DܵVzPz #eqֶ8\pAUߺU>m{U7S* ԫ#p)@ 9 4DfC0 K Î਍h[W9J{SNA*:iDwq5rq*Ojf\O>*p1SdFQzƵ{ (58բqZzmp:t1Ʈǖ*5NOUғz>dbNu!HO5bDK I2ɪ߼ ʹg3V#&Fn.k#bTEOp͸@N/=Pne2zW;rV=E/~#<|FFFiCP.B0vj_=n²2 IṄJ2eJW" |/o-AW^AzᠽK$aEwZ?n8ǽm&y8;2L[[خH ѩG{jqt#_sU&Y#=(UێhfWi괪"Jd N)BS8K:PM6O"+HV)PDb ScM B9iq3iKԘ Ar0< fzT3]qa%?\zKI$4(:\sVvlI#,QԘ.00;aU" ۵x*?Ҝr'B aާJ3R0W r)\ܓNs֘26sǥNeS}($rj֪!Ѷ9HNE мF}j%@NjQ9g?:dz (40y$u.{Ҟh) NGMQN1]G^RmsO`@t昉ph`hLJyS^M#ǁ=*1vԁCҝ`qLcB)z#lH c-H/OZՓUվ>R+Rq*S5lHS۽WBqԿwj(4Mh$~֐1I54ө#iRCf?wӥfN.@<Ԍj/'ңf@08 uI!o5 ,/W'&.1pZl{T,wd͔K .Kw(_=x8~1QڕQ$,OSE?σi|޽iHո+ʀWɁfG&Aj*J@6ȧ#uJ2Q+28X|ڔh1OYÓi|RqQZi0<Q\r`qBlڤ2\⤤69ZnKSZBdSA\Wn+HO\t"Oz guBUfig+ 21Jxg9. X14;Si˴zh@Gm'Kd](G7~ZI#ޣ]4F3dǜsH#H8yB$Tethh;lSTRyL$U*f24bX<ٷ߽]I$[&o3v>SVIsR%!rOʸl㰩1@TKC=(#,RG4 ƙ"T@A5:҈b 7EbRT 17`)rm4ppǥ2H;Sq4 jL'Qp/0qqR't44ݑED5 MHNNsTr\bAPuz '*sMc.0ұpjkd0 ng&dŽMh7*h)Sԛ7c1 9EiqRs˜S>\1Ɩ5)T:ae*h qX0elASQo^A#b>U4ѓ؝H+zRH௵06AoZX8R*$s)N[=`%yUNg%{Rp Q4-9Mh剦+F{vIiC2d䱩rMdy [~W#5'}R)' Al7־#WiMvzGTMN-+ST?Hj}LkpJpsO4zb#e0$tTdR) f]@XSd8T1썇q恤u5^Xyl`@ېĚ) ǀyRЉNS#֮0TD'JLHU<">H 3WҤ1D[8qO^%*Y{U&L}XYsY aWZ&r%zR D)3i9yqXws*F8B-Lޟ.M4x4&.㷏Ƣ`~SN')C8~aXv-.H@B}kfC`njuG2ҡ6w%^vRjyL01qRtŔeY!`|ki d"HU4(]y ǡ1Kp$qk"̬Zq؈\` şAtiPGE?q  T]yg,i=KHȥRX<8 LFj@TX֐ 79RVXL9p3JT,K#<˹)!IOJqeUrqSi)H7?ZDҜR.EYe9 (ź@75m9Qh9il^ [ Dz"oԒqXaZ #YGCTG]b [0* e ɍ#"DLSG$f(}rsVb$ܿx^測}:Tjf?-@"CsO=2\==☋CJ*4js@(ҁ N:gZ8 OJgS@ǓTվ^CKAAsRn;oF84"pIrsL$ r:y#"D!Gzvs֣$sRS)҂S#2XR5V {PC(PqO`JJw8Dg@# C-"2y@\rҎ%n= s<ii S)L@ {R;f1ffٞE!#RWSf AG4PMGJޤ7qHu2MhD\ l1F1(1)iiR?&) n)RR &Șn4#"Χ8sRmi*LX hB)֡RNIޙ&nx@j3M֐1Xq4sHώ*<Ci˓Qd\צ)ݱH8bjCҎh)q&8S4kqFyC֗4@ IizS;R\QJZLRS&b\br(1@NIRi20Sך1K@bQhE=i4J/58JS$hjLٲ)Iɠl,jF'֣n4FFw.sX,D6q.HvY#ee< HKێNpYB*A$dְ=(Jvyqұ qO21ҐVG-'j<̙;MM䍿ZI@=jM7vID^p2@TP8Ň`,㊶t ka>g=bywr3j|hVtQe\$dt?[r}HP%=k>m")ky#*Y3xjU cjY D϶G.Sn}6&*ɑY) LI'f|ʠ!sU$r|Z+1-LΨI-]J`< Rdˎ3RJyUo.b96k۵YQ|zUV%.=jHq)WH]P?Hc?"g'(d369>Ll2rݳOD1 Ri(+3u% B\5xt?ƁF."6ƂVH5GFTf8™j)jyvday>(4q1֓qbCv%6sN!@O8zRi1@c) I( <E]p^A LuizA.?JW:NRP:3NsNoDY*UskHUO53j9|!ypӜjכ>ԮZ٪kr75/̀n9gid^4\(Y!ÓWb㶑0z+9za#ɧ(\O",Q9'ar U^$ƋLHVAsqrE#kX

Ɓs=gh8 Z|i"<&1Q7ִ6^h֥@9*)j_[>£udMRfi;?FcT0j\#vZXݸ*xܬytʾQ253IJ $Jͣ2t y@)Qڪç9CpބHךVQI)#4p]FAepE`j}`nFM.1JĶ4z/4@TM"y4Tk$p}jo v+bNIFQ\#h_niZc~e!{*ljY܂ִW;*y *kKOG[F]UY;PHQjr)@#=21ހ sU@ (PȠ⥕=:r()WN39h_zqsLDd)x#;#HeyF{WE"5,\i!n86H ڐqLC`}iSx|Ԅo9fRSyg# 9&Ƅ Fڊ2I?KFњ+O9Y9nrmg )#VfDUy=jtj!cb 51CT#g6A,qV 0q-<2$p&x9'd8R)ӊ\L(ҁџALvN0O"[auhB 9^s-A5Sv];N85wR,-cXT:ǩ(V26jdEsT+0+JD5ԥ٩y6 n+` Jd⹍OO{k0})#GúAk5Jюq=D@xұfCVaclBAPs:,NqAڟ7\# :b:-f, "@3V/RG7axDhE&*̎]ϥZBɑ[&f\0=iITԤ~Fv3oߺ9aڐgNu<ӄ*p=d')Kp0z,W9^/]\V1VQ_AUI&s<eXT A&l܄ U( <5TO4dB;V*i i(L0jZ3ʀE=6>Z6 u9JCp*,EŏqX`gWE3Nhs$CgXWWhN%EǩhjrbxDq0^*Xt ~%H! Q4.B"2*=*9Tb:9F)RMr +FO沣6 r$ja9$HQ5HjDmGY82LxfUvBX] ַɊiA#\Bcp ]7v7b4ii qN#iRqI҃kuE<({RzR f3Ҟ=)$t&\d0 c׏Ob;> 4ciN(RӱIڛt22p8ڜHbf"&E9S%ݸf/QfN0|& g%8$ҔE,V .pKH`E!~|85P.wؿݭ  W vxUdi|՜;@TA395Ge#Z`.j,B;V 6)9ƒDmCHU 'zkdI~Q>R ޞHžlbrɂ0*)nH +ɓ43ƣTr\@$0#V~|FU~GP@=M)} L℘>X\ZbL:zpw.+IwDo*/60xF`U4֑JaҲ~ብvv!._41R[h玕ȴFOJv! bqE$Hv2ќ_,݂+@EgkQ٭FAȨeF V@ fvi# _BƓ$j2ER % CJ' DZITJI`|@;yF rQ gjɣFJRZEX!H iB<ƐN(06I=0Ii3PVҔOjG0)ڤg96sHHc/RM;Lo]z_͎Ό K JbF1tF^6]bF-+~.5؝vW}keeB3nm"G?of%Իz,Krd5evb`}isSʺ*jrQ87p<4g'vJ#pLE#g#HH0yi Q$@擒s֍ vB2xQH9&0L*=$hquoZjxaޫdS!X(ld_yҳ8,X4viPG^>ZdT =QPskuq+_2Y 2~eҴDCYԍIbK,F2JcDUmU'N1$mFM$r UVN{*_ZrYXna'bIo)kbD` 4%T SqfJœno3c'E䚡<Ú%[&fCBY@Km rʡKch͓,~Vאx5:Lw@N7`g5&R+`5d \Γ#-V&bl?ZfS$8+S;z* bޝ鎛16 C"m'GҭHr J"ުOqd!ӚQQ 9HRIۚ 0!G4'Q 4҇'54R E4!%R..̇ SzR~CҬj`Ɲ̎F H 9 G1L8GJhIHOH#"PiJas PҤ¸ N1S' doJ0*2Np:ԣ 9MS l&94cv6qKZr ,)p‸"1b)ڙ,41. zXG#ydա Ê`X t[Hciz&ab2'N$brzP43FRfjE^ 9V8odCUۑTKlbB4ѣT^&ZflJFiuDgL<ڣ'BR \03K :)@@FH4S)DbEWhH<}))XjV3%=*5LV1ҠhaJƪemS{sO*wp)a('LjAHJbb ($SҘKEFށ5KdN~)i GZ^G| zAIHM7-Qi(1MZPM7PPbz 6@K(l4 iS9 6)^)rkusWUCN*fWJ~1H*x6;RӏҐ@ #izSȤ0KzS`9er=N953HˊoLS*IJ LXU3l: ZCɣ P!h4FzRSK)@ Nq@ Jp@Hs}jNq9`sA)2TI֥S%1M)åқO\ Ct:S@ <dO&0M"X JJRl Z_g-Ed gaai@}Ebɦʪpym:/+@9攰*pz҆!vM4jeK heS! A_^T=V8\s_`7yYMmC54g:j 5JUp2@'ҭ3n^sިqi:ї+;KI]y +UwuqGu)IFÙtNzӔmOG&FD\ R2)4OspXOO@)?4v3P;{[4z8< e&p,NuWJȳ Kݒg/r۩nQZWsZܻ2sT (*7+=3Rcp6S;NXԌ ;U8w, xSu[XnzfzGEA]6k*鼑fR^jMm8In(p/RL$rS*G&od4Xc`ֺ ˖X [#;#r9]6\Riakӕ 2ۯ^2}!v0GJC3B75iT92d+iҞX]#AQn-(EvrڢR{5f&\2)*e'+9nz5ɛ#9cQ!I䚮(II4p*gxF{2mQ$V~c9R'(֐W ʬ;q |>5 ,zd^sT`Ӑwzv4Aۂ*e=yTt4 ܎ A#q'O 1@ϴ ؒԄȜ3Ҝ)B/v@1&'ݗ?.iۉfR[J(02E2JPJLg#<6ۊRed FCܒ@Eg<qN@sӥEs6#_/VFPXO)!g|bK?ZCa|MQ%ǟ@px".%"S sR<o@ cj71ͅNZ[GYB+f~U@_i^[$ v4ޛa7c$295z'1q/J: 3֑g&Q7`Uey4y#=y1l4vѨ o4Z 0 24ݳ@$mS/I+wݸ9aփFKFE4I)wl9 O4HkCaKw4[k/LazR4Hi`#ɨ$q҇QK&AD,zzӶ6Vt`R:_5na]SzَNGn;R$xkS>u8(4恉Lw=) 'CG4sH@LIG&j{Osǚ7&jd  T[> sk%B^{D@PO4*< Q^R⻋2q,r1w{fC`u4Z"\6Fiy&XzU"%{IcQ}ެ!]=)2N1V(3w5Wc fQ+x>J`E=Q3ޚ_jmk3DGx) 3T*\;Q㚊b *YCzxAH`@ &VElzw"Eґ+g ֲ/.pY FpWcnz+Mb 8ꧽmm3^o{qg.(ø5h^Ք\ɺI^ׇKyX,XYb .AXsx,Þơ;3QSse:bʸۚ^&!Q^ueooJ;Μy];8\R+bX>^VOaݤ1:\[ˀ9jz8UzKln8$tF灳$gGBH^99k&*zUݔXt9E%bYAH#*p*éL`AZ9aϮiaunUx$..1Tfi-]mj,G$~ ]/lVܚI$ts'G] s唕ڪ !p14Vl=C|FAa#`#l0zZfsHa~jt A:H :TOs@"-S֭ƣrj$Vc\/.I ㎴Jh9EWN n0}y+' ; 4pc89a1J¹[q*6 >lbAWLp8Q*N z4-ޜ wMṦ zSq@*9C)4Jv!"6lܽZuUm䊲O5HͭF940i !SH9< ӺL" AZ$Aϥt/@ m՝ ۥQ>3C Q.33 qPÊZd})} 1ÞM<0ǩqhNdb$4)2 .( L|SxZeRi:CґBw u@lSH)!ADf4yR) ќR&a$ާݭ叭SmM.{VւI$G#5uC4# ؃f=zRFײ~ta"M*&EREO'֦:[MVkr$5Zks7Wx~7u b v&FF+<7pG nRui ?@a39D񀢛$EE*jι(.0|ңQHZ̒cȸxKgD(Wzy5gbva31摉'ҹãuuZ0Q\v=*ͬHs;΂Zދ*byo@NA}tFBSΩ]ɼ͹w8#`Ҡbq+$gY1-ޡ*K6$Ub^1vޑRvC%PlH!T;sp*9h]Փ{y5ܽ%򢕌[BұݓZ5EnҫmԷlV}@8jv5՝ 9K&9d=M[rIM qWh֜n '4BiKE*Z(ڼR%j}[Cesm{Rt$bm 2@ԊeXp殈XC0"Ԉrr@5AjرH$X$➠5cpqԌ UM 1Ҝ3n?9go) VS-ނFq@(H1`{y)oR0~jb#l 0 V{U$sHRe,T-6jU6q.q6Sc~my!HTO]IH#y|<'jބLJcず1 jsX":P#! INSh.DkV'8|.2ӰgI eR7\RfP U8dA;PGM3S(0M?h(\@޴r1L pir{)#=G$(fFMG!ni ԖϽQQ-8V͑t4ez)NM~*|j2]kwfް5Ne1ӭcOqY6k (T}*!Fz*M<ѴnQ.m pi{TPF{U$KR UbnFSҔy.EHsRX.GZqSgCRAcO"O9PR(8=i^`UYp;S#Og\jOy'gSt18r (H`viXGҔĊPErGl6]OAD#dL."OR\҆u^G;h9ǥ68ZRf25MuN_"qih?/ S jsgܰ׵pZѸ#WqC 13^{9ievckM b~%>h(kѠ/?qU:jF}tտHMQH&$O}+ɝ+$:ՙ ?Z,@n4>ch/,XenW5;E MS͟jǷe8%qSKa&@+E4s2FdcR*jQ08:O>d/e"ېqQzy=JvI4E'j!wltKے0 ދad 9n8%i>ֹE-jyY&w/sQ.)8aֱBsƞIxcR7+S嬋kDE?iEqrxCDR,s5,Z3tn{Rʊzӹk.;#'n9îKRZ,zb: ĀEU-ך.+)Gh-wW @һ+^Fa2=1Zgs p{Oy5Ϊr})űڻ tW(G՛:ȣi{5\FZeg>Hl9.sZd[izdV&>hnumHt4ܧK pTcVʑLeiiN:R8⁢#2Oݬ]PM \})gc)utkoen>F;n`vc5f 168Ƨ5yJ q\elv&1@dH >hbna4 !^B7gzU85zH9St#sL,`) 1 T> n4 F[&oca6ka[j'I jIp ` ]ĐA22)]h.Ksx@Hb$ rP+"Q5\fGk:@'#~1UX\$%*28MU!*\d`QFOHNqbey?օ'd'ktkd04Cs:g ]C) [HդVk5AKlt4$o:}QMI`Y˹x4)XčzPX[<3H>XdEF9SAa܍84ƌe[^iTFTgB[,[S'"Lc Ի/5Wbay-QXs̨LH^\ Yw1h%4RKr"UY6~t[HBr1FҬ+\! QTHޢF O=h3c'FxPc rSJ>SzT[CPR!֮FwƅAP1ǵʻ\dV$@3?(9uITV1Ҧf{+Oֹ.K(ڻ^EsnÒ+)L飊lD%F$_QƞX\V_}j77}+ǷN:Ы4[߅Wt 1F=EZ2Oj:-H2 ܇O1C1k\>uukVWގXy%Ml<-r*B!tB㊨I<}a1MlkgKq3m56 ]fĀz֤uVoTR**ؔp8}*Q\ܚ$Ƭdn!FFVfOqR;N{fʮv)2.2|zjdNbsTXܭMt&l;cxY,2oMr|,zܴKӤGW8ƩBsĨ'˧jlcv^-eX$؞C+[ST0 7(xcCf#prQWBLڻ[¶BF\tDmNX̩V^EO pT S!g2q]3@֬csҭWOb\a~j{$~ t"-cm݀9}*2 Sױ58bsz6@6֌Q=N:P t49;&YThIF$H#H`;ZX aE`@$n+ڇoª 5#"lqނЁS$as}iTsR6fD(BIF)rHy9NG6 K41dl`TIR3LB* Ywrl 4և1&riMF)@aZOlB<ՔE0aS/9~P)SvQl4qքGO ĚGe.1CdIP"T{.:S]}Tq89WRnq;xcq`@c9iH:Jf E8@$MaY()ȑ,Ojk,۸S٘ԖLjN01ۇP*܊BE.yҎF H=wsR1$L9i[֟1P@Q@iZC*6,h8U wuVLJz#4 QN쾄Tbrv쎴>g==ivlH7cm#a6sW E@5'ljzϗ) io)f3x޵xwRY+_$FJɦ܇4Zr~=9<(a*6r*°`1֚9Q׽.<ўyJGhǵ&qڐOJ.94 hnHM!cZfh[ @I=*t9AIIR-*SC c\4sޕN[=ry G 7< B޸#sM9\Ga `ZU±6 9ds􇁁LPƫIL/zx]v('a 6;SahHU_CL\sX4tAU Oj# #X@A@5y0f#=MLk0'$VVfon5FlJc-tUҬbLrZʬ+s;-Gkk0R~ 9cN̖_ގP klNj*pri̪Bb9S&pEFRޤ:^ǰ删DhҢKϕ=*@rFJB:2VEcT"u JLeCl1sx#ݺ*]UFri$X1'8Zb;\'JҴe~9/%"ֱ0dG8>mĎZVEOZ,ϥgU:$g1=j1X3g5,a&`ΌK?J2Yל{Ucl皖4,dc< NxW,ANwasIw8Mry#flPWLg? UFM67zFWU!nc|WopӠ+IV9Em`pV:Dy@E9c4FQWo\sS*3 DT2FK*ڃ$TOa,?57m-5;iјɳQ=F+P3ɪ=kECitznF赅-̓gb=i`֪*;Rj^uʡ=MPS}ޔݢkWZ]*ZpWZډgB bf *kb b{sF̻3R\5{pbsJyxG4bgۏJc Tk&{t[wND\ޡ 7Fi)+z`L~C;P Cҕ$R3[ޘ\LrdHU^`݃ֆx rjU1oN  Cs4ybn8[2l?FCVnҫpO֝,cS0ǕCJr lTzfBseīv AyJ/0\NZkF;本T1;1;H OGe88 W'4$HDuyPn'5R-#]յxfc*p W ͨk>|n@zjWj:N6vۈESG[r y%݁ұeżl*3=FjQRUF:R$ sTcaPަGVSOVC >:T S` d\`6޹xYmR֬~dE"͋E#5HhJ6gAxU!']O5[ЬX yTQ0gqDiH'upxZeN̊p"Mi,Ԣu[գ<\Wgg[ޕ}2:A:Rܤ`ԅOJJ~2 #0%'2zRɠ2 O(@2p)rh,HbME]< cII⁍!s֘sOgE"Iǵ}`2s0D߂p=GQ {XG(+u2c hanXȟ~M1d IReGBV&PHZ̛});d 1H&R8Q&!*W9ԥZG]I"K0A湍FUrҹ>!V3'k>䷄JĖn’mkM&]S!yݳ*q / ;T#C疤r!N02L,fjȠ8+T:Ըh PG+2)=i):SOZHsysQZE0PɩUw` IB i5n*Wp~is2D8=i>dсh9)2 ';Ɛq>Әs# $OnKv,AQ=7>sõ[rJ+jxd|J݂̒ziXN-1k"+Ny߹&euxGME\|4֐=)ImJiBPҸPlƮZj[8V`2:T'P;Fzߞ R:1. 9ML^>^ynbg=* KOZ% iMFInSL@;bջ̘9?4durFzfZIpAQ1ȬoŭM,Z28lZwMb!P3wZ7tqWG` {DėZ3y ]6PB"N@[B%x5"ƚHVMٔ~lӥgjFsIPf@0Q SU?{mPxR0M56+0i `;VJh6;j7$eqRw3 XYtۀʼn"d1N4r8b(Ʋ81Q$OӂȠ.@ U']"F~n23&p$giX%$Em$1}kF-"VΝf*V8gmv$cǵ8/G_aRڂ% @_ZnO4ࢴ1Ӱ1RGJn3րikc֘I)m7 ۽6@??4Q;&a] @w Uni ĽTrIԌ9B[rhH =.7`K"֤dQ1g `p)a[

D/*9A?NʻyF~TD!pqVl@c#m69R>SAEpjLw';#w"Eg?@ʞ " p S0)yp}8{voC\B.sX"x\|}}F ~aK9lk9i(Fu}˜ɃGxjkIEJӔއQHWec^W@TW5v#KRx*uԥctoM.yS $ r̬8ڎ w29 ۺ@nzipr1@n;JF 1s ֘%ّ@l i;dSYԎ)>#; uE犪wJw /&na#1LƬQSX` T28 iBm^`vnjG;= P>jRh)GphƒVws\ݞ^o:7wtY.^0HnQ[mLz6wG84Bjrm5Oy]gj)PFUMbUA8K[/:D}*ge J֎%Va-j~Q⑗$ʘ45r^w1R$bcqF9i rR;#59RJp^asv*z͚"@q[Qx7]튾VWqEB֡1F kqhUe}tRcm+T4t1dgN8IVBK*ԎgʾٙJEvNYwrmZPCuأ;Uݔri6H= n:> jîsRmf‚+Dd#43G#y91X9CqJlt!ldRz bP=_ <ݩ)7''j|4MbMi?.WLoF?e'CH\Np15]P#$__-(d*ͣ K'vvMqZ$9oz_|cwA9$kjt?v;]rۤbMW'ֺNN;QE}% E4{ik #HVƉ*8?⣰yHN[`TdƐƹ  )6hߴz%qXb\V0 Fi9 j+Vb0V\iHt"UR}۝MV <{S #o5ֱǀI=1HI4jX+aV]y`2`8aDKWH^Y ,Z}$qǷ I${7!C*Sj JY{fY /d8J@$blKBT{VĜzVb;s4ЖI79G1'@m擐jhx&VE1M]=wN X#zNH%#_#5`HOҹ[* KcգtepG9H@ TŲjq.F:S2d!0j6 YSѫ3PդZFzU9#f9=9v3!=:S"u1h:MDjr98riK"dg&ξP E_IkP5.0; Sp Y{E_Tid(l: bm4TebLd҅8ch^`$R"Җܫn )6uV^ڑ&1ۊ ϕn U=$(2{Q 59B/cX!Mj Cv.X@mk6ǠsTea@g$KGZ!$)`T3qh{Q*sX(r);8G48 =hGzkM :($`A:S[hHI|R]Sr+#dx>K]y57-+g^sN8R[ǖ$UGz)lL['8 8=xjri 41n3A@N94ͳhP[hyMlHc53D r:U4br(LV3Uzսi\u=iUwsҟvfcx;wsPgrXf }šXցX&aH͓L##"sS)>*ց+=a/T< U &ņnxMTa֗ހ.r)Jhjvh*7銛 R)㊭+VdɪbzTh qԪj NF:TlxFr)g9. B)3ۚ\&p=i.!cjH0R&xeSLTSJfLSM84#NsKړ4 CI)i(I֔ {RJ^-!fZiiZ ¦jAHIR!1M~Jhp.@Ѹ d1soJ\RP (`i1Z)GZ)M8 \dN)REQR G"NEH!1H@)PDzPI\P1sN1NqW# (\S&*6QRA dZh.9U5ˆ`7j/%4OV^\Ѝd@v(dfI"wKP+p*L晋CH1Hq@IګhOi3l%KS*eF`Qr&u͕>]橳4m+FAli*NFj2#Osk#ɠm16v95nOLF.ΚUb@?VVGO>TqrddM'\w4@#*z=6RR,|ݸ+FXsjǂsZ!))AHCLa<7ZE3攃4:Pn MԃU2C3o09#Q 1#|GqI2@sTDA#[dFG=)FZ|W}ڍBhrp>#gsH-C- V3TJ9Fm0 i1ɩRJ.(4RB 4Q1Qj Epe(l=h@ӳi \r)Kqb~h/2iZF0'94 8NeQL9_@Ր9$ iE'$K!O*[ϡr0;TJ岠qR7J pb` ݚC5 ;FVfNqO[^`'4 Fn;QҝejBvX(9F $;<ԥ+@FAv /(HҢfDPFmςࡁ:SI)3qƧX ='E`A1r<A}7lT0(Qҧ T4؛3ךv:t=)Os4jS!8=5!"ɠF):P"iurzcV 4ݘ#)r!qh,G柞(&v+L~V(@81EjV;֣D [ud#i~ f]\nId}bJȵLKJ,˰f<@ ;sۂp;æܰS.KjE8ZAI ^C*9\HGhWW-ovɉ:(8F_X/mV72 Zh$5u‹\'+t5QB#OCR,D|jP;צ!q/#R?JPSwrNnJ\i ;S_ Ȧ2FLp=h(*\9+P"&*:#ۓ5iV@P1ځN> P!~U\M3p?~ \r)!8UN1 8(Pq4K`[=0րFN4 16IHASJ@ 4δsM!x }t^F,1V1Op@)1aiU ّ,]ZI HkKSЍOt `ig!*X+{զ3r_x`XDI23VBB;/zlrGq:R bAۊx!fa19)<xab)sMu '>TI%W259dS4(O4@#XWF>SPBqh! qӭ\UٜdZDITTNn<kt ;FqQ'ҜM!H㎕d5QcDewv{TJ14ӷ3 TE&x8B1!N5V豵rOjͷ֫͑G#,Qف@SUȨ r*EP\m1mN:V֙6#+ +Z6`̀0)sՍѾHߚzS~E2ic#3h4FxU!iX)8c4 j8\zT.52e76 3?1N3ANsRZvҸ4W#*q@SJwnJ!F@8HE;M 3O!-T ݕى5$7FB;U .0Oqڡ2 kIj8Ծh4Q$ݓޮ[#V<joA2$ێ;l ! soIK8Ph 4 $jF=( >=r:P&QJ))im{Ya@Itۊt$R,:u= RJM!~xD|ӒI)$i权FuMzQ&=M2"A5֜eUI5"UNjZ5#RNF*BFA'zLьPrғJS@4 ('z^pQI)GN:zSNq/^DL 9~MԲj|`b! b\ P1@ILO8 L#(`I) 1iĞÊwAҞ g.  bv4ކ1Ҝ  fXԪ$C6d`BgbǓrz2ϴqWc`Pjɸl̫рcڨЛi!<izM(Vf2_W΄ғWEӕALn1W/mLoUBOVW(IYWnCuoJM/EDxݪ̸ulFJqt& ULkNI´cȫLg hln Avb RE>qψMQ˩s*;\]i[VND_poekj qޢ:}gHcڐ0 ۀ(3peL'[Gw8&l. oRqhڞ#s]$Zر3" iv QV8B.sBI$Lw[j59cLYe[Cc}+!&"gesj'vs֚F5j_BQPpr+6e\5QR^qe$MFvM"C1l@T>~jW4Q'fН5k We;j,# @[+py1 v8RVv@=Fxj5̥@(yqd1rIO?6kfЈ;*nCQq6r*펣< R!)МsM0ۙ9IMG= ᇥjxbw}AVbJh 7Jrͷ*5F$p4Ҍ#< E+JqnJB7#Jpn.;YL@JX}Hwb9ӀRMVҜv4 P7  E#qLGHyi bsQF$P4$ѝHxбb*@pvۚ4R }+B2])本U 3)A3q\zPsP۸`S`‘r94(}׽TLմq$JU!=fZgn"EZV<vH6:du 7PQ54g5\_aHlv̀=jzA ,yv;b̾^3޵r9bJDk.L0x# Q*c4凁ݎpaH!#i#kb8A$i4?ZD6Tc J@*pVI**sI!@< P>^zAZ >ԥ@^)1'SҏKqBc#B p!q5 Wi6ܞf *-6&ЀzR`Э x8bzSKdP+sGZ]ކXw*yivĞ\yTFpFCa70#N,Ce@pSG2niSu "Lz'0dtS0{F֌i, #(ihǥ׭sR@4m$׊SրCAr:SK"O4SJ{ӸPCJxLW#j21z9`S\ޭ$~6M7GZQd3S*;8EBOe梇wÑ3K3浴mWQSՍvvMLň==k" ^*e.iWЊq$rƺbp=:TQ=qa:[Z-ޗxhYH8t␂W"AGZq9)Fy =ZB4( !%Vi$$c"E0qX8AM()sIǚ 1'Mܤbcr=)2Ksҟztp iJ7HXzђp(<CG9r?2IwAb`iAž$viN \h^2&ލSJ*sKGڔ!rE'QTErN[䞙xWij!\\ZWEbA:c\3:a9(CsU8zF͒+;0#͖|f6$$Y=*9Q..EBY{PmUir)@3;PA5&Xwց TT#irKtWa(piv޴ 'pI^}jCS\R*}i$"`  ru$q6@XT3\p*u4aHq86;ϭY`TpKFei`+5ͩ] bqEc$uSF$n`ϸOtVŶZH Ҳgl'yLӌr3f)eF~2+>@zkqY.2{xyW%1VF O63񟗨]L]_wۅk0R*RϑԎvו"P׸O)ޟLMt J @c$? KzXB4JO(K|/cH37L֭m(¢mhF eآ;4<|I**enh1{ U[31ڄ7B4Dd\ǒM9K$ݤ1W r ַW|nY?"\<+O?;݄2y4 ^iOLVM/ndrEQLxiޙA,^9<(M-6HC*]!O.H爼+kGa䳜 [U#ie1,NjȦiVq"m"1-YZݐF5"';D=&[Ҳsgd)+.Bkq{ |=񿛜ǛNR gKnz쯦 5L@*5ٖEzV*ޫJwԨ/n>p=jctfftis&srR}ۋ52g۵eGT=XR΃~z qc˒#nX@3ԑHe >aޑc1Uf5ᝤwҡvddj (ùhV=v=q՜t_JԒ!IǭE5*+-;'O,LOzkM9Gnoʣ,pɌ޹vF*mi y-mdT=F4+U!Lz(5NGZL6EBR 9<Ԫ+qQmA"#梏FTzK!T\Bܧ.Mx P8d~nE\{O B,rMYh#Ui1:%Jj̧"I Um 0F恹jeF*8+:PfSNfS3N )}s3KJ>JsڀpyI;84sQiL,?`֞ jr_uNX 2WRsRǜ!ʓzS ?JC{ޔLs@ ҒK^ED)(:U5iUi@""isRx+ R JVTr7?N+qڣ<"%8!^(z(8g<ғt9!i)9h9gP3/^3@t5$|R4 T)Zp(!nS):SF=iԙ ڀ/J;^tCy.(ǭ&iz㠠>t*#Jp*dc~)YBq* s&N2{S'9i~8iAE)Rvfeއ|TY>bpx"[VJ!"\J)&fi('ހ 8>Jj Ɲ4-QHbFxH"D1 wrL&s޻"7)_Z587L1i3j[!&SuH*sAq9 *n1ҳ\LhN5Rm ӘUIDnXU˜sQwgqM=cHn*vL )2[RjJ$+) m#a6e H"h=iByeez.T7AlWSn*5\$}dLNWC' {PKZ6"L@+"d\eOFx 1hF Rs")A!'wJ\ 1mV[vk1zW#3vjѰ ܋qz78B 2I4vj4 p5o|.;9eMļQ ͢\G^Jf) P+g_P)K]5Xc#9WaCVP0ݳfڤW]eBۍu6 xa\#֕w(N)c^7 VjvA9rĴTmQDI<6E.vd܃ؐ{VeʜfHޣ'EGƑsHAZVFId֣e`ϵJx4'=-/9Qޟ7sTlA=Ri,i5)f/ jiۻ9dtԐ8ȵ,vI!zyP+&iB`5c)hTV s7S\#F>wJmsSPE+L5 9 zS[uVRN+!H3qUX,` Y#>9..U،烊RFMRL0׊U0;1''gXWQ t +*&(`A)b_އnw 6T@jź,B7 yj֬tG"1i3Qiʧ85F"Aa>O;*nT(fQ0:5$Zs*'::P }%psIo*3ڡ)h-I26rzqH2:6(CBHgv}jprAC^\C$Ze(A J>pZ۪/5J:P;TE2_JO6]7Yi"< pug1S3$&.QTf2Ek.GGMqixCw0W_C}dbM^ҵ,rjaSW׎N9Zv:6FHlS8\\]gF`nեrp:&O\hq#f#i\1ۭ6ZZsQJ) Lf)g<.GZC =)1Na_Zb"P=*YNMF܊ ct v D88twʠ3 mɜԇqn;) (2n^0:Wn,#sLmMIɩo-%sCdR.;sk4G14〼IEHy59z0;@2Br5,I*|j g=haK RH 1Sj~Jz9Ķ!U^f'1 nF`iH$ucp qNݖ>&;4NqrC塔NF6H26\uM#pt E\wN;ԇ8%T6qCw9` 49'zSJsCdRp&)V6 IQ#/]0ݩlTU8#T0҄ X*9l uR&6$sMlGMxWgiv_ZnJd{9UFS2@*E_CQa֤)M;MdI4d4N<ҞqF8!*b "'19hݑPig8{1^i6J#>c4<qptFh=;Q)A Ң'8..9j=i) Q/'ɾxeTpaHn׌?7C;(t=*s!9,Π=* n),I{԰aI'5".x, +NqHWCdϼKX;EUkf]['$g-% f5 _g;GZ_[p¯sEF)MUǭUR0;Ӽ94WPNZ`}I"YWnq0xQ{(=*tN&&̜8r )P!zAk`3ӚhQjP2=aҬ`lxi \JhLuӐxJB^=8ph cyc;HN J 41Sڐr1,"hPmp* TM{ԴZ7vz.j29;HRѢKP:`Vj>ϯJ;U`_vN3Qn#JB8/pi!0ڥڞX!\|ЫU)cWc&PHo$)UEgkfvSUaH85 FmdF^ f^i+]TeecN(mVycLJk<ÌF+JEeTOBHՉ^jrbB2P)Ͻ9vcR9ʾXɦGZqرĐi)y:=_Dzgue.0qָ*`|ԭAw mNu:C5p*%R#5,Q6\k>~$??Þ婹=j@N  -Z\25fRD+7 *͜rCS:'/ )?+/POS'\xB/PE)EᗓJzR$3n93,i2W5*&FFqm2|ƭF V|'"VP29±Xڥ̙w6ҟ7sPFT%7|(bVg Vue_O).Ǩ\P[5b$Lpe0j$mEC/!bIr2y0dE$`3M<杁)=nc/Jp)[`v lȨKң_NNh*DE1!VE,Z\S*m(94ћdʙoZBcp#=)^/͒hqQiޙ2xFhV4I)&QbR3KNԘњ;ގs@ RRfOz;/Ҁ 3HN)Oj*U+h{ 5* ku85@ 1?7j.. ya?m14>negBpzVACmOk­^r$R4rkgXb(mb>jARBZGvnScxr`pqHFEGh&૞MJF3t;0sJ1HphP!v5(l 搰ZCW*ow5ZGVwUC+I#l?-z-8#RkO z hB㸢漌v5p@1ߊisqNK泡\`y  G,/JP9H~^EElgQF7|E2FbHABo,M4"^8m!JsGMáesH(f48N%BHڑhqAT)=|6IN~Hx9S`F9e8"JI`[Ġ.7 R#!y'E,&GEYVOxDC~7/#֞V%pwqU+dU!bE1cQ/&FP&q(Dܓd6;R [AY;ٮc\+Zٶ#f޻KbBD;ֹIcґ[8'nsʫ2jE, ji#Z1ZG)g*lu7X4q{U]GJ A/j߰jlV\zllNcd@|klJ TA sK]tܢ˧̇%+DNqxGTkITRʄ;F>013 C s‰R<ґX .>Qn.14FIwH9 2 NۇJJD+*zb2'byEHG!NhSҚ+@L:C$)ԹߝTEeW&cn6h̄y-⫴6Ww5͹K!ySި]#6XGw8 qL+W.OSdnlޑֵGA=du=k6<ձv99M8.}jbj.Fs F`6L{"4!FT-S#2UWiնw3!OaEI#3p3cA ,RrV-mOL0=qLgΗKIU@׶Y AZ$_ZV+(VRI]`ɜǭQߔv$`ZPOT[dsA,Y26KA5fW3wE`A !21UmF}h-HΑ0NEUJxVO 5U z\zK0Tq2##oRBSbN}t“hۿ Fdl(=V=CA֚Al4 rWdژ4ۆvԨy2uyrBw4r\#ւ(907 ;lȃfAl.@W<ԁFH$gmCOL l0e`A8.ќRI#җGqK3Sjv9D\5'sM#4q#625,BNkoܫ}W;b%g} VefH'&"|ޫRyJbjd}*NlW"]QxfJcFTlQsj6{ g(zP Ai Oցq֙8#4P4 v攜%E" v4ğJ d⁒dIݎz1YFTEUOȩ4C'N8I);OQF}N &8{Qڛz b ;s&4RnM3vsI4\MM8\b4Ґց a5˜ ywc/|QSҚzR(x4| 9֚d1͜QpH2 ce3j6CS֑CLUL@Km7R1.y) ) N='d@xmt4PJ$`ph(͹cb*d8>ydV`)$2ȁ ɪHFES +o oHJCHT @$[ ™#y-NyFiAz)4,B1Rz@0Ćr,j)'Pj)`@+Y85]js0am;Rypz$¶*jǰ5;cښ&NRos:צ[ V1 qLFl 3֥w}N`eIRGc>1$((1b҆I2Ɣ }õpE9 bXiP.9QE ;Nir Rdd  u'WG}yY9P0{P6@d_JOSl6Kn[jHVL`^ ϗ:QgVjBS٭ K!%Ƙ#"0(沯s{V<@宯EW;n25ƒȧ;[֛p,ܸ0xAg70;kj4۰k!HYJx~b.[zwMMЩ'c XM[8<Ilp Fښocp}$# T F)O"5B'iPzqBM1\S0܃NXӌ昈/_đv6*&q IˠP&0j1T P8Riv I{z4֤ٞ(@gց4g;Ep'<3bOzx9sp=}J.;סĂ q4]0wG1w">tcpZA0'rMMނS%17⵴TV*`7n1Yv8^"ҜȄ-ɁFhqsBG81AU vSkV;漕7 X~U8[kEbV/+*2>:Tq́ڨ.+1攂y($=8ȩG&&8sSIȣU9ȫTd}٨-OL'&1P 4$nibF1J9dR'sG""1晜䞴=9ayQӵ&ssIsG~ii K$FRgq )NL' GzQϥ%_j}FڥcqIҟI@zSqRSjf#'E!"\yJW84T=)l4d4'$vj: 9{ @S SdS:sHI8H[ 7 x99恋J T@p<Ҍ8J!njDṠ[8jjQҙ/9Kހc4GjqMj iZPE! P )?$c@2tnqV0ة|S!ÌXv FE;'֨JdU"M!=(Mi)e\ޫW gu"ʄ8ɮ~Ldm}qRuSՙ_w*+U~GuH3K`޸zr@XisfO< >Ԥ@!=GG!Tc=s@A$P =33Ji\ (UQȠ5*XN, -cRRvdKp1diֱ޴>ƶSdr*ն!K δq l5sX7[yzi.;V-~SӚ׵IZ+ý;VokӱHBG\UKb(s]  b:$N"!,J`Nƒ!]M.Ş;F1\(:a]5c&RwUYbwuHY 9-Tj)#Z1##g%JpFBxJLΦ ݞyqHHTҺ+*>`AR:7Aw Ʊ%2nkWGLsUIRAKPf9V@\EcZk%+PVV:j=jQj2*h\>mkN=F\0FP$eTw oG"Z3 (< DwCy'qsA``T;t zST[<5G CԃLҙG4uu:[xRj͒he%fxOrj&l$bG'oJuroB˴a"~LMpwUMBVFk ⥳ѧN6fޫ.&ȷ_vLNU 8Q>n;UVnp1B*QQUsm &Ha cޣ*w|cG-EU`4| TVd@S-vw4\آytq'S\>Jl #".F 5V`rk5#<>Q`ep]skmH qP B|Ayy* $+#L3\vmC/BjkX٥a'ifh"6ֶt-?J#-`o,WM]vjW`tPNEv#Ɛ^I'LN96Ii98i2H&A:SIx qɠ4PiQ曙[,;@SK,Fb_Nb31YWmb7uʄ.YZRO"IC8fh$ݪ@ynzC B_j̮UqRApN2j, Խ Z!1ɂ{y1U SlY3i4qUYLqG1\kMUp`0*bs'ֳeЕرqv+u5RV_׽liv8үD$KkW4Ąr8TXc7<q3qH#+`5|)׊kh%*;Z*AGZlq =U%)aެd#berʹCDB 帧q'-W{ejޕ&E6@eato~ƣ ҁ_bhfaFGF {8;#.4w.3@p;а34\!ec,YUc5t4XdP \n<nҨ"L GL"*ܺrsUIy(MSZ~Cf%h%Wd[L̒P0;WKN,f3!!Aɨt?y,| e%U})9;GSJ>aȦ7f@ O9943K'[&UƜ(曐=*F*1e&',7vTsM|R7va?zq3lE $ێ)Ng r0i z3f*1P) 7JFH GjEj_510iD0jeQj@>7p9̛rQ\ҍ]+^}J5V WjOv kDeny29{tNRѯ mج{Imb  xt`bⴅFE~FA擠2M@溏%ŧf06u0x=)I{$=>ܹ JZl EcV|Q3cLUpU݅boqQJʬX3>3Q;(zsMvrBI= CX)֋ɽi{4=*&V -(ec;˗'•5( Tydy0D3gya6iIqH!+QCo2MHd99=jv[#4c<滍;+Sޱ|?f.Ԣ0*sV#gS=#lԅlT9LO֨c1Ɣj$bX*a8K[$qC1JҖ9zdؗ AS!fҁQKTY(rjS7xiKQ@ ӆS43rqK/92(`L傟Jr76~!Tgާ*YM4( Hw`=iU@RqN8A'4})GC@4Z1 ?'ҀCs ytwm߆ka%Ί9⡳zPV|ՠ~P"" @51Ҧ׻ A'=*Y&2zjmVGZW'|GZrTgV)IIqž1P"3 O ͼCaՅ#XDNllLS֤d#naSmV=xϭ8}*c69 c+Ӛq'44eLܑғ8v  lqJolSzv Ӱ\kɐ;U"CbwHn-ɧYϸVPji98*i&IWfSFഭqX$yYt OiPgYml H<Җ(<)C`7Z J}ڐ׊c DyݷhGIg~E9 4 um١b n'R*Mϵ=:Nrri*p)zqLFJ#H Ҁԙ963K{K#+ү?!JFȠšA݌Jr!ZPӆ H"u (8 )OSi@◍2Qt>{TE!s֑h'6:b[ls[dd2 53Sۙ*oIiB^eqVu&򖅵;{I*%RV8>ƙ!rPH3D$ϺiN~6T!vTe7F+I&}H ռZFWLK;UqT!7NzҺ ۵d1Np*D#qG-Z >0qHu)lևw"v"r3Vc ҁ'=$1"SzT@|j@qҁ1I{G^i9!dԜg4Rj` h9(ɩ`ObzS"zs($A::Z818xb%\ԀO5*d٢A"F2U AP?JE"z֘qEx&?=xtcB9r& LahnN3MejLgƓ&sIJA4gE(3ց.)14\IIސ㡠8ϵ));ps!ӊn0z2)#Sr6cUyD Y0.?ƥMJb)J24|0tVi4e3Nj5+Q3VnҩOBw t:Yk7B-M!x,Hr 6k1H*GoѸ<FNsH- qxltAw#=22A2Z$ǥ4py:sA#Nw SK&hL2)3@H)9@ӶtjzGJW:.@ i 2)wFGzei&3@P9ʷUQQ2>$x:R/b7!I<䓚iqZUm]Ma3AE]ξoq *JC4+'LW9]`rŭQ$RwF˚lڝs \A5١3=)\ϲ ֢*Ru4pX@R-؇ح1sz}y!09IPyaۚ 4fRBs/qq>i{8$ig֧Z<R0=h=iw7sMA!U)Ze :+@bW;k9yReME[3D ?+EfRj7n ;+2q繬zZHT ׸mj7cIYxAQʋi=E$񓊪BcdXHBX|D wbB_q m',N(5#qmY$,NsR7?{s!e$CgBVQ]pghYY*1E@Ԗ=fZGL梬}Wc5aa*( sPrvTr6F'#GJΆV՝Ŏ۽OQ|$ 7 VύPփMh0i꩸1T y)LH)95cZA iG lU*UW!C+y>-7,Ah"^](r2xZ1ַly_ABN@a"U\\5&Wn[jq67Bˌ4=`89 chp3F_[Aj$0<9R1EMAذҨ9"ުCGMeOzλCKfsBRDMg7#2M#$c$t5d.]K6*(@cs=jPFKd]yN+ELfFHI.^@uś{zgܠjg&tSQ_3< S&'՝ss_i7HqtS+&{0#D,%朶%#zU$)y0ڕ|2f"u>a([ĉWh}"rǚ`1 csQK f7/_CMܬ *z2A4Hh$cҚic#b 90SajA-Uqt ALbNJ-5T#7'viFw|NJ<`i1 >ԻQ@@<хTN:ficnh88 ^@qi@ kr3YMo,rq[,zV}*Ia41ӑ]CAL*R>޵5FDa}[jwH@'4P0z djzёN:rjn3HGcғ4ԬwHLjDz^)&C[&8upiN!7'>Ԡv")xIFiKCZ>~5W&ý! (9q@e Vq5|U&+u䏥)!3L\@ƕ=sJ& dt<h@epi"(x=AH@iӚ9)H9zRPsA$x恊HYvuqh7iZejuq#`۸H NAO 2=YMdnJJwTA\Sl;H6"vҕF IU 1*Ŵ0X$% k{Q,\m p-O \ꌯdH犅H#s!ZӁ]zmh5+rOjaTFNGެA@I(9ڵt`mRW TIދG'.8\dVa+X}\2SǕ Sd})@/79{ $5Rvg c$XK1 @ΤNj衉cӵU7HFX뚑+C1L=HC1ȩ'k˂3ԚBX:ц,r OQ9KIgp)va}¶e]twL iqo썻[R4aK(ǎb@niq2Rj\(QK N)Xc9&?8rLS*?*Q&H:P'Tc+oI1 v01HlN(BT41Hw֕sQ]˚\*C/x)A#bIXLri.MQҐ bNO.Fx.4:H]6iRS:Ib2)$v}CPX-rc5+7ۊOC9=T VT;L\/Z-9;_mfgc\|ݪ6*GXgq̻!,X%DZfN1.U {S>7T[pXHҤ- 3 GJr˜rwU)+%EGW\ǽ> \SA\bE$N_V#qGg"^9U#*Y\J"(#$qH׊xEE+ޜ ݞ<yS09CLrG]FqO@F*aHF ݚ7!!ALԒ/z҈b&g_ʻAJ/Z/%_<8IlZ見{nz:R8V{U d5"+SWqĪVRČ zWE6؀6?c"_8m $S\(1ԍUw! ~jJ>Gy'-nW-$R„=j@Ut"R-rjD 2aJdBި&bb *Y'FX: VtsVa<`p3X3ЃСr,n rGxx:i;zfM FYHζnR@BbqQ̽jx֑Ⱥ 㚔ƮH#/%I1\dhz)r$RDa? }E5.2AJI#`u{Sr& •ʖiJHPƔ+8攪y:P@F:G58=) BFsK;<֋FːjWjF"Opz4LF9ӃP RpI\9I`8_^*6bx~Pܐvu!|0 M"mL!N޵*˭kQ4oAE\C ҷ8r+Z9dⱯ3rXVR>ZLJuQJ19@浴sq bZDeIqBFekA͕< ,IE3SG'+7qMF;U4rzT;Q( ӊRp)Iiާ4ǽ.9◁iKL s@һq1f99X(b>f=M47IL+ ]=M0H҂c zv$QiNpjBGZp|gbTrXԫ!< v৑A-UqRgO^*E~q hg8T@NxҘ&iv3(K($8:NH#q> (0ӎh&MvO[ڦ^jS!Ki;H+t `-Uj*HH0i8)i&8qNIPJduGcRM4BA 󚱌E"r1M?H=F Rb˴pWn~ m<9 Tip*5 Ո',% Qҙn$C$<ыW*36MJ8ZG?<{e"jӿ/ϊlӃH2.rGjL )(>(KIޗڐ(Qz^"8JE!E&  GjFA#ҘHKԘ G=:6jvZR*0O@)8/;Fr84ʬ3B$E4zS9Z1ځ&0QM)ҁ B3,2*V+4JDI_\f_/bjQT(Z#Li$%WPq=)2$a0OxP 6;4Lɩ^@GNMvBJP3WE bwfe @ G(#AW r$ϵC,v*Pfidj7rMD*Y= Tbc0l C;}9NI:J/E+r$Ldv ǏƒrIܦZIZpW3&&AzӬm<7~EH)][+"y60)* cP:S,nn$rh3q ~1><Ԋ&>Py.UBqLb.~jٌRlaR 8Lfub֨ 3F2$LQL$*⤴"]ʿQMBPۇxPs먿}{Rw3J ;n,OU !ڶ;y*T4uJj*ac֥CC VJgj׾â-ji|P3Zrm"&֣dsE*piÎp;擌 %xƐrilT|3j>STO= Q}kӯUu/YFy ߼lN?_2C֠A۾$j`*˂zTnAٺEf)j b>aYAF02(F$&_)G#bR1G߼!Vn+&ˌFbޡo:h`ަ[1_ִ7PͯcK ={g'& 230`FbXHk(TEv>+n I f*zr'`*BrN1C|ko9@}``ЮA)u~Ei `1>z|BMU>TH3R(>83 7hϭ(<7#Qڧ!P5f;!85Y+Jb0yqځ ;B5/4˂ZcF3H07qs tj-Ԇ %NqN,f)(!zRJ>CUvȧɤoq{p'4NqJ@ h8ǰ3ԛW*99*+V TrG2s N;he]_<&zz]$ ɂ٨,jf 1AdlۭhnqS S(94ҤqAjO1ӊ;#4sH@OSN51J3КC뻚z)4ޔcC9^)cQ:P1 izSr:!W859R*R94 +L?)砩0j6Sh-2' rx Ҡ~ӸTƠJz`)ؤGi v-+" F :V- $phDF~x=j'R,gZʸ$XW%EQoR׷Pa=}kT ڪC{P#Դ9=;&06(tیt *~C3:i=JEg'?Ja.`{5H|X׭2yN6Ƽt#gEqi t1ۡ)9┞:Stn/4;Pxič)ڀpj2i6v*W`x, [ C4#b!9$n6b dːwsMI+"HT F flt0A+ `sBi@߈LdlqH"O 2]⚨$~:Rm9A#gFNdY:vtAPT?A!;H첂_.8*ڐ3"HU*H}6v`f=91OҚ)FsAҌ眊;yE y p=iGԬd犋4? @Nyڀy4zP u`Xb ցw4d2*O`ELiuCҦ#Qn+9#8 ۥPݥ֯\|kԵqy:%eF7C-lj ۉٌM=j:*|.Xi'cC9,dcϒzVyx_ fLR٭#;Η20`ӀkBًp:S,eFq䚮eBM]Ӧdw隗eWF@W֬i<7)$)ZӶ҄j|~ƞ@îk7Ql;w6/9Q"}QBF=ȫ*Y;qw0Rس K88 r:0lf z Jrcϥ @✸'A U#8V۞x4֏8"aS@F~5cHj c4)F/2@sޗqa֚TJ^G'Ҁ:Q 2zQ0& i˷iR8E1) 4 `(';!H񠌎)A+1Hl™6=iFGY"iJ$<1[vi!_r ̓F+@$>\2cKv5'#GVb"iZOi1f.#SvHv&nt)ry/ʺ,*O zVvH<+HjwJ91`W!KShX1x'֥nsQ+205ae_±.,dOg! <.0(6 8@.89j1qSDrdjFcvhv:mhGJ2 ҵV'. u!EV<f0 PQq7Cy)v3t@#1”)ɀ=Ma@dsJcKghS@m:Tc!z  ݠh6Ajev fB4rŤd'VAe=*vjiܰJsD\$"B8^0kDg^+Gw70!}k^̰' mhUΊڑZ89$#xS6 hMSdo.Q*FUҐ㨤2X2d}Jk1d:#b;C6)`&@3ڠed95,&u>tlqBɭC\V|2:|BM"J̕T@<ѰOdJ n8 P6f2i0:qڐP3ڦQSzd1O{ t9#`GzM`nRxbsl*C<6=+>8a. p(=1WCSr9pXqAHi1zi#"xR OD+£y1qZ2@rivd"TMyQ]X]*Su,:`-٣\)I# 5EQ^Ba"+HKur$q֢p0iX25xL#OǖF2+*>xX dkj?kՆ2:ԠAoR*H֨{1ޒ1' 1 x*)cO=M.r( Jm$+0}+T",䜓M݅Dca^OdS7>mSjeҬg$x 1nƀ͸lOA,[`#50LIEzR(&v@*&nƜ['-@ǁNҕpN)iA70)GLP"E<Յ5Y>X^d`ui 2Dғ<Ӹ4Z`1T(PsL/94XN(F@(r17=i 0)0:P1QJ P4@x<ܮ㊝O|҂qKO<ou84={fBdUPC&A*uY@ȫh!c@#8S3c8h2JQaS[4 K.$ 1RQFg8`Gn(/^iF:ёwc=(@zQw94fh S)0(6 T4Ry#w40()2'$ sCL!ґHLaI= 1zRC(pܞ) P;F GhP;P8Dď_j]ˍ?JbPrGVlΔ}=j1UAv4dw7=x?]--gLA4`r(eдg1\޳nTopfRQdgUUcG5bF)GQRϡ+ōdUQ%e9%En8 YBJ#q%lX2z-K;0i-"{L2 H-r}*wLx6x&<ƚ#N( jBCqڛs|(Nh RHr p*NE80 :zьu4)F;s@J?P%4T;UxwWPLhl M w>zUwޡy~~iy#9s5s6rj&u/ҟ ר0ҖjFVWYB34P Yx⁷rð? X6ۭY2GI75&س h椙v0* ֦9׽;㮂]í40CRzUv T8$JjĠs:ӕFzSDe p΂ Ȫ? QlJB R E2)T,)zk:M"h_n[6ry$XJ>kpҐGM k5"ƥa*X*.<֪M %ٞETsUzT:ct\ĭe'8i, <u |+L9⒚LњK")PsVDиv\yqkK5 4Ǔ+xOq TL7(9рۏ_J6|խnzwl4 84X.5"88I8^+;\|62yKP\I3#a>՛rdi6vB ^_5JA$RlrA|`Jh8NGj|\q!vFۺ.bIpMdA,Nњ9Hu:~n*g=-E=QȁWmk}Lz 8UGkj(|R:`Օ(B8Vf!TSİ}Vv4^u8UR2#"A_iaiiY@i#F7*r}*imdxHʡgW&1ć+ޏRMX.S?|t(4)\7\TRzβ=R2]G4a7gE;Z>Ph4Pg6ǘ@h2rhLsj)"GLj]h[y5>7rqQ@Zd=;ShrN W4*1ZC"FMIsJS c9 z]TRҁ6',iA} NSҚN&UG-H G1]>U2Z5ڡsa2Oj\a RAj $`(2xԳ7#DJcH"<眊&riRm41|GQ7 ;p(ngPXиvF)ҌM";Уi2ip6\w,iAi)OLd,U-8j.:bi݁\vp5UR@Z0;>b_FwTwwf `\/sGD)^Jت |nnՒn 4@vMrUF%iA :Rl7UXHAW;@Vs9C.%i*d Aّ⩰Ew&Ȑ;*ի%p$4lFR#L+KOuod`jm<3sLAR8G'MݩqȤ88L@Hiғ)Iiu4v4P3/4qI.)v֗uWR)W4Hb\ sM"9AsH[A#j'n#)J^Ot☄whwg)H4Rs q) 92zP)ixւh`hIy-&y@)@ HZ#U%9#ԍ!.rqEaSsKlc5`AJW)).Tu|zTkt&|O\Ik2{I'ڲV}bSqTÞ^{ӕS5-Iā̽̒X$*=xGG.j]}R84nU{(zmiǑy: t&P{LYGizn+ޘTi`~D&Wh2n\)f.wgvqQchvUhC6c5d!ȖT,xD'h\Z``A83Oz qJD]ѫ_,c tؤ¨Z]5n3]=ʰu'G-x5c`WH]88^JW8 /C($6lRY,>cPnt4d%ʂ>Cָ6ȸV[w0#lLˌԀ £F9iabw^{HɠAJ@IUyF$DM?Jp`‘j!\yޥAP1"o=)OOĀE!y;nR֢#PƆ|(8Pʞg*@4HYt `1!,Ho/يɦ+y\u2.sTg9@րˌmAM 'S!=i@kJb(pSzRmA ?6,H=2)<ҏ1yvqnnn 0 9D:`RMn\m'_E24-NȰͲ y ̅r9`fqvw3 a6:9sG(uR;1宥nE,g3s,eqA֝֐Ҝ0i1K{RE4F4y 3u#;RDwy = 6B SKw~JL'gO…nǏAD۶hhj9zzTYM +0rO8jSNi8W$u`Ҩ~JtNoQrM9H(%.1Ӕ*%=je1ɒjp1LH) i'4@F}3ހ#v9n)9HpjxZNJphN=O5:@S'JdQ $LNnE*T#8ZH7R4;R`pH]@QUqӭ#D$瞔sH8RZ2( ݥ4@B[56HEDBܷڜnTP zSS_VUxF⬅ͱ`Tўb@pZ`tfgPi4$+"\oM8s %$*u"@$^4#x%sK" *{'dۜR2FуR@qHqǭ"n1[ibF 6Ws֤rITɻ12`+7ZuFr4%8^6CtF l`gZDPFB&i ;w}Ҭ:UT*rJ*Ј `x'J{4S֙vvTlAOy<i8Pr -H £%gT+~C9cQΤ`p2ʎ9`qUJG,-!ݕr vUrO"/|>S*R}#zBR5yUV.,$2WHUJ6y$Rzll^,So5+9z8X&B TrwgeW uݚ]o)Y)zD[W*|@A\q6ѢsҜn>̻A=OfpTp٪W2rfѪfON\jN~_zY=Jsf,{"5, ", Vi~^@dUfYOg* jaWqCd@ϭ*Ozh iQR<@ïGFVJ V#95.I\M=#Dl7n $ J'đHLo;ڞ vĶ1EQzR%4 !)Oˏz@ŀaysKrxAmǎԊ.6A܎<)7NJ1#9? %E$F GVt(U6 7<$uҥՎ{NZ)U9|ߘҙh,1IԕP8+JRA7q]^fQ0AI4JC=(.tSZi 'J 3sOjʁړ. *\*;B#xR0X5Zv jN({VΏYe'vyEvˎEnhHT@gY)F@i$)׭Q&{=)s1HGVBv@x9aLd;pp*R\QK5e'g Q>vM& A >\`S#*!Ŀ;|Z%O@+RE9j#$kT聜ⵒ`c;ӣ '}p9+ve:tv' Ki=騘:#$m19 R*E ;%DQ8<{Ԣ^ U9Jy &=ipW=a$qڂves.AOLV5C+ ޲mY+IM6~D(Z4 ?ٰX l\( QnvتMy48$&]w0pq]V9_ݮ;s>X`rY#tpR[ˌV9":+XWDD+'8+`Z CϵcO5]F&RPzTش3 hH{-[ݓJư0Gִ'`13ϩ2nTנ?{ڗv3f"gSOާsM+Z@!)#.K(w\QNh)~ĜSya\Yr0EnZ%ā{UGsJ{. 3޵ GY6X8a[[Nu˳m]j웡6I#GzRw U|N8Ж0ł?ėhU<6^x0|_CG;4` YvQ#ejIi#Ԯ7rg!#9#*81$gpࢶ0je`3G0rYajb$##`IK)\ri\#1u}E<`7 +ԮS35c,+!1{ʧ%Im2åa)jtBVF3(FsV gm˷ڵ̥u,O"QHekkHbdIjpY0_yQHNvn|$%zUc0IKp8`)8Hҳ|\M=*6EF0Ai KmMVAFN ;a<dڀrJe#)pI(3s#H=*mSq.(!ج֋$ JAhS11q*=+h-LO7t4#LaܪL)₮@j2U ZdHjAZN &Ύn! 3@KNF8m9f_ZzTKҥ\( 8fzQւ WL TxK$'L@?JxZx 8aVr8@5~0J e{/6>>`MDXq]i^+'V|ZVdctN>gsJNN:SInӸaցLPO90g!Q"6z՛pH*azs@6YH_z)Z'&4H'.Bp*U"%\U剉,ںa$82r3r1VU0F+9$hPK:)Vr{ $OrOjS0/Ÿz aǮ ^ȱ/Bi`܌NsKyÀlƒ׭9`B#O4] U+.*R͢UN_5"# c񦲤y; ϩ7X{K"Q{S8S2bŸv?F5 w'9@ P+bydl88⧲ԮLRg=ZI3\yO#%yz 0k{N953QȦ;ep99_m3G$g;zulBH.Agp+s\2ztYSUwD}`"d%6$[@()J<^t5sעjvcRXb4-t]uW9 kȑpA]2)bc}9~WnT-ֵ" E@GLD }ɴ;˒) viA2U|jMο\-t.|BEDv0>~ʢA?gx6Iz{HncG;0&Ѯ ż3!xEn22A=8V)*A ¿9 { /X$ &¹YmvJHUCQI)RT)[,{XPN~RyC*ӸHGLTG4̈HWWےzRgL6+IGlo,cjQ䇍OQRBsM 8Ys֑10zf偑Nbx:s %QCiR`E \D3OAF>Qa[9'5. $bH+?[Xg5Y8XQ4ȑUw歒H`js4Y2(ldռc' a2# E$88` T8w=!P0֞=qH_\dĹ'&OjCJơ!~NR3qʃ&8/`⣑?=) Z?/֐Хza=;K@Z =h&HF,hn)Y#41,.I_Anl#>-N8ix8aPV8'@$Og/rj S2i}bb))ש8K'@JsTT,x8rI曼MҮ3IHg qޡyc'˼P8i\u|ȪR1қ {W/,$7SS LI~%Z|WD#Sfh$A8sY%E2z u]֗Dkk누P9ug)nŇ!bzJ$ߍw5mW#=1!1MBg7X:W-}y qP5WL,g l'9V[!WXc&7ǰAQz2;ǹ~`:U˅HWsd'TYL2w]#lVWo脼*4MN 8Rd3NIS~Zq@ '9dQ(R ӎqM xPWZZLP))R!BP&;早;H8ɧɦ4X.&)3:S3HbSӚ\*2=)ӓ@=(^8&4GAEdKMixir ga_z\r)Fy~Am( #9hM'O"iHqJ)4x(Z< nisHKf$L@'i( ,HN 4%ԘLQ;hmTc@ݚR8'4c 1@ riaQw/~1"8 ֘ m%-s!A>^C>-Xge!5iEީ0/oR;)QӚE >Qv ۦzWyi!iwi<LAb9WÒǟzW&FNU)4/Lnݧ4.HTbq;dQ@ سS6;hCX a?.jpsQ#MUnNIRn9csXGT!a+7,9 XzRWОϞ2҅GOzc#ڟ%ۈ:$教NΌ$PN+ӯM**@\=G/V,<_ip9CRyL"EtcVvaHN4q 3763IJg4iJHU4;q0Jn} R'"@n1A#! <5&)9@y09x#hrh1=j6U*C1#qҕi"46<NܻN>YIZw棓p#*WyC.牏g&mr%1Ef͚ V|Sp^"/fWD`F@V )1.ґ. 2Kt4Ie+H7g,j&&]2@ RBeG"|c~T)i5j!U 3~MT ֮jG"\t@B苻D?@: VF[mRE*~W5,| 2i?5?&kJ*iJVDJL3k^ev9W}*JxV)7RA'8^jBAS(jyNFOjR3 Zvz]׭UlcFx4NGi؛& It zj:c&;M#s 8ݜ+M#4@D{R JJ0I('Fژ[tp;Ӹ @dS49'9P&) k EF>X1lUݙ )28ǽC! R9#jdd(HTxfJW(\RPET%30oAI`22Msio$S hI͜+X2;$mMܱ ŋc lij;Q yUA:"<PhVͳr= F 0;ޯ/*r 3LߚqfBX=>b'qZ£ZT _ ̐ %AwCR<:e=[9jhGDX[))wKJ$5SP7d0\(h" 埥Wcp_'yOUU*{4oB&=McQ`o*({bcesUO0I)Qzh=kV78?*R['jnl( E1|cFRLɷ84k9g2C=T|b`EQARvDUDNJ0}i6=Դ煜bIػ +R#86O}sTSbn#: "@<[ ow3S+E:kпRA?18Y@9W&R UW ԳH2aajTv`*dR~l;Q4"Նe}M(j3̥0n\%uU.Λ,F}k]&0`AkXל.Tv 1;Z+eHl\Җj9\<{pMVi=h.Nj46㷚W-D\|U;M,Jc9⋕bŭ 69&K&o޸ *HdP kMrMk,CnV?[nOeRS1m]+~c*8lL¤nOUH皰gE&ZdM#4CH[4 @뜑IW:1\7Q]6'(XWκ3!gr5mûq"$X۷׽Zf A-v+ܕUL7#TR,y!_9Қ BIzp)Y2xZC)UdN33@tsJ\V$ԪXPW"iM 늎EWF@ҪO4\V#vb1TLB62OAV_fJܠ9K5+̆InƜd1 5n;;>bےiUN=M^mphH\:Nxf`ޔ 2dE[$!t:gnnyxP֦kge}Y3}sZF7ᭊ{AZYa%;կɬIu.>*|޵G RV # w~$i<z)bJuoI-4A,~7sКїZaR$Vk8%@':aΖB"O({%Rq tuP .gs_T_qc՚vcct /ٞ9 ; v6Nz &\7!G\bəWA69ve҂reI+z}⩻ )=+@X.f>KU6 W&CN@Ӝ H:PU\w(˹ihN*5ɄQ5:A!_M T `2ipH-:{ʐ߭Qi$q$ҠD2JYoPբU`I C*BLc ڱ|-xAt`;fՋ 8Tn٥oDe,'Y#wS{[[AwLB?M\jFy1ð_B*6&S[9eSߚB R4܁Fǻ,84.B HIVSϥ;rʲ!V<՟.'3ECfAj7za5B([ֵ$_0玵l)@I[r5!˩Dy_Zbw`1#ުγQ]D*4 Ip>U 953j%H(ުL !XF8 `r\ qRΣw*)U1TWlT@UX{ta!M8%rT35fGd)crgE44nGJ| McYnciӶ$%[$TeԱHg$]79ZdO3f8Rkկ%&X7Ct9ϥiHQVTe83S;U6:li!pX{8 O|sOn$8S^p> ߌ+<9êFm#ޒvg6"8=o 88&MYMq֐0$1&N)\ Ӆ4ygzRu'!ɣҁ*QiprOjCM2H2b`\5oQڌZ&{̘i;2 1mP~n ';CaaRJlxS&]O*?.zW{ih9/ i% 0ʊQ3.HGJZ:1g TG+NO`P)\UsRzRyUvqhnN94y_Mi6$ґM |9(8m# #)X. \$R=i=BI8(N9@e\$ `C\L,L{⥱TȤU2E<|+QRB 7&g`W-hI caqZv'f2ƞ#%9)p0=jF`*Y =~ZTW a_kt6af)$nc~Uוʧ^#[KrvטVN*1ⵍ)=Y=dWU2XPb\pCН2pjY-a22; @CM<|dփ9Rđ5MQfXZoFjo|Ლ8Joa|t,m"4#AN1V\1PzHv9ܮ/4u3OdE 4桜gm&JN4tnL}ČcץF#R*}G=2zqHFVFZi:Pԧړ3@0~8Jc599;C)862 ;2j$n\ qtհ0'3- 뎕$&2@J/(FW*&EkaZ)cکj0Y.nա(Fݫ5mLj8ZMޅ/i+o"dL3l"W ]tj^y8G_-+w4, >Jd\WsX.dc<ⱙQj6 GCZQ~S\]Ii:^qY^u _nT*@w2*(R*9։Jo6P0=j!wqMG7`hs:l O P0%\5b[ִL8m/D4i%>j\-n\nj8%lcߊW+fXK,.0MtN,sT=fŠQB(P81>PyRJ;]bp~ӾqSy5鎈"!94/4S3n㗭X^Y5izPirFE4GP<ŭ`;C6zbf9%{a%\sN_ љwdՁ94CF$*9Anģr {UYr^X2ȵNKiZe{V`;=+hĺw{9b{LmJk*]HXeH*tH#r;M+C_GVSzX֯K;28U֣BGn6j6m+Cr]w°fvI6Oǵx_ʓ-Wk/[rFq\2*Rκ2od`lQ 5*3bXZhPȦ2TS~XϠ-'bbL8&?|[h,}nKSՙUSl)p:VMH'ҳu#~=ʸT v-${ 1:Gi"H\Nf*zW˦'IF6(HkR`+Eg[ NRiP}*ѭ d6Uc2r;ͦRkESZwx^U)~k9իo#ȬĜ'kJ!ƨ e$e<Ӥ}Fvb⦄y46L7(U-Z2Dx5M ƎKRy" }U̜n:YIb3ڪ4._'Ҙ|TDRHqRih[Ech$cDq'=i./a a}}`[:wbt(FRCL֟f0W' v]B?S3]Y4K%P鞵F3N̯m{ K^ O%1뻫I2Y'<拍S;[ ԊƗIg3U.XMy=wvc\[3FqRrT֧?]v}j mHp޵>I7(PQq%A]2jJuCJ-('ZnmE(# ^}jPn$c!0MJDta I `ҡGsG{,@@jut.95I Zd(&!#Pg{j}Ьz+ H*2sH8TUG67Tv)qɦM-K18:Pxiyd2e8Pl{n'E$փH1k)1Zd8+:ϚM⦒|14lH4sZ.Q[bQ׵9m NJYXR Ra CE"T 1Q֜HʩlvݎzS'TbBڋpqCFzu04p!0,N{TFMDA֋Ōwzh? S!$2h.#^1 |+FzWC&FpFWA9Yު^i ?*8 rg! v}Zg4!ՏTZdd{R-aG9ўev8ChBTb*`8MW9}i=f5ҎZ8l8 "7y {ju`z(7ctY'Aj)iXQ25@BFS}#]ҍv46` ɫIV]GCPDPFr_9^EVl.Pވzz6{ $~]4j4jG"J79$Pv 7TlYs4 311+ e#%*8ckEPV/iOJꎡڦF\a>F2ڕ*ij̜Zd0hݹ8#!n!yj3I浧ݐ65Qi\8T%c'E(wEu Gsr@Ph%O<5 3i _{mi\P=\{!F:PsH:қ/=OJ`Ȧgp9tf 0B`qOxq*;tvSg+hor3 BծMJ'c]KD =3m庁jd8&z]۬C)Gj~q p>Ѯ~3Nva]r*yȮNkt3< Җ4ܨzuiÁM]tv>M*4 t$b:RgiI7</ޣ)2ipyLd8nJqҙq#8" u<ѓ曖@j&l*㴟Zs[ڒ&4%-;`r@U}d\FTTkwXqR3ؕG*O8zJ9ɡ=y+;d Ornrk~_& $' A^uxUO^Bԅ0͞)#B 8¯4/ 3l'՝ζ=@k>d*T6`꺃 i_sB6gvbf\?'U?.q&*(gުI!XeEQ8`-zU %qު2ǕU8.qZ-pҲ.#=ۉU@H$) WDcd9TŸJ R}j{aY6+mU*g.2Vt<(pkAbD2w1@v)(Nhd9]F$cS8D!FqF93& qv1ӥ)l}BIn9qUC7GAE$޻~^OzLSPrJOj]@8LrG5&7p8ݱUSdRO;]#*".k"A}*\*_1U5׭j42I Z"(H#j:#3|(kwSVDZ rqT2.)D Zmmkqy'Jl_Ɂcsboc@+`vjFM #ksga N1Uer|f ުi7(6Ἲ1E,+udlN6qR73DJUdKXFw h 1Y[{0?unfV<(4LWVE{U$O1M^Rw9\%,+Դ(KBMKQ85sR5/N=l[WH nMXٓ8gi؇2(Ni|f89)#ph9FKxǔ4@0Iw m84pjEㅫ12hDQ[=ja1A<~T M2.;q@8l v APhd 5Nh#4@>niy 8m @\QgpzӋUzPr)SqG O4 (8 qvK1ŀL(|E8=K9-֮֠Pd&MfvOS00?J[Αvۣo&5p悠JդC < QUu2$*rk>w%rw.,_P$ !MEhlԿ(AҲV/mߵ<Ӕ,JNDy&o,˭]Rè-KDR6uPj¸9O0F9cUk*WGCos_5.$ Z^\>#j1M P;yMc ށvqjAPRxP A#9.=iC0P rjhv{`Y OSP#nTh%tJqlL.iiN CdџJNMbA=; fc5"GHô`*@;&)(j'5?>Zɺ Yꮿ)5<{Xs1IQۊ4=j- `w_$P[-[޹P2 'hF04ȝNjuP*e3c3GA"tb2O4;\˻ 4r\up)N6~5^LIǥt֑ nȎ jQRLKI TMT54T{E+MTqMu"`4Z|v^ee?3uP i.яכÂ+_k2" D~6JWL nczD9Nj$n 2M>V'1M+MqԓCbJC*@ۂg5.v) PJJ݁T%Uu=6t'ttqw02ᶯr{Vn@n8,Ld|`s@! CM9V.WZ&c(R}qZv7myV8K`tYmgERf2tw*yȬc&/?oJ؁UFW=ꖧ FƱMJQ⑟V6Kڡ҂ D c#Jz̿YUWT.}5ti dY F,r>~lMzx~dfC2d'5:=QQƴ e`ǚ2I˽._@U kX8ztoC׆]¨_ AMke~FER|1zRcGwkBp>33H`5ah<9_J3bcMg7sqtW3U.f)OK1/=}/c A unR9!w\\ri9f,ɐ)=Pð*HA'=i(|l M#VWQ.YJ~aV$9HP{I392Jr9S^"䪾GpjH92>jm4O(Kg9S`ګپLc5fYv\0,43O!dÏryWޢW*@9jc#Ҡc BU= yw[męls>ZgS <ѸV<:u=݃mD&ҰB6+JBeĚkM4! dV33ҤrAlفR8gDtfc QH7[ުg8MG` `) <lt5CNx<hRpN9摬P0 TE ǕP~5.9Ri) @9эz%Pԧ|/CZ$rT=M+ .))ӷe1`[ڜIFPnj*Uu8-1BɲAH5nL c@%\&$] @4ХZ6Y\B8}=Ĥ"CҙqT.܇xb5&\L'AMAWkfNJ˝㚆wљRdxƦ#fEl5&> >svg_#HҺw})u3NZD&rJ$98_ZuшNE2O~U79^Y!.VyN=EF73 u\*I`D [0g}dæ9Cڵ4}Hn)BUe2u%_ø,bP[<%GU!EV>,I%ף*8 1O.1Wq{D0,VysY¦QEz[\+SdڣhVOsԢ2NM FcG[f2pE&MnZf%TpMg"C^'Ww1ȋkoz^8*sSaqNȆ5tBFq.5;i&U$ziTdS ST e T2HbMǚg7j|R:wQzspx95,$ppV`%j+&dD#V$a(lVWRj&z GHS2p)GXgsIQpIa)%8$JN3Č}*\#%ڌ="tUzw*!?ZUWҥ;0I 2؍.B*c|5-~.\+݈O;wjw XP)bT3bQsI\]N!cY\HC&r{TG_QH6{KVF%.ckN쮍ys~\ԊRY7FBu":3~]R˵w⹹o\FXn\;}_CZm4N*kI 9\ҶwCg,J /`}~VΞD#kq^%rΡWYЖ0dG+t|eIWUr9XC|cMhJnd;+ӍD16LۖF8Uԕ#TgpL3=]DÂܩQ)g3JrîjрJhg;R' qҽ#ƱڗҚurFsH,2ilS)!8r p6UFZzIр%P+ޛNlllx>A F{S$6k^fu\aY[r-1\ݞ%IAd>7_28e(KӞHW֖*Z@ 2lŀN>ZvNǖvV`VϞrJLl3޳# Qι\cyF*xكg3IȵEzIWlWr*";Y $PRK8a׎Ʃ5[fmH_6X]#*Q{ьKRPf0ɣpE!hJwAM=qJ1:"Zy8c _k.Fjh97A뚃R҅^I3` diH2G i9 A/Z^ғsL8v䁚CHr9)<@4sJn}(>t⁆r1BR(#HGqG~: @iHcA46Vd$cQւSdt3ץ.xL49jKړ46zSɥ()s@TnUȨ]2NhLriMbiIx>0 !pM38|׊E,3S`zS%n5Rg 1li]UWGzu~QX+ 1^]r' ٭m'CҢ s'Ͷ̟ xF Cܞ@=cI!@2%7- f18&zv3fmU9捠xu۞ 3UsO1ך@)IbSw00 t&[A'qL9("0*āV2L"bǵ) Mfl!Llm<ӂHFX H /9D),J9ykų-\oFUjkM4 Z؊Li{aA'9%cIM]ڠ#ҕT$bHJ#q zXtǑ 5\rφmRx'M@!*ѴMJqNN*j 1u2)wMDw8淲U]դ`N ǵA3ɭrCZ30q48Z0374g֘-˜͓A 7րq4,P+>^T~9.4EucH5OfHc=kWu맂;Kjy \sɕEoVƊ1!z槊 үSҲu_C(- ZNk8BKp m :aY"ݴFHQ2GF 昶jJ4<ȳSɖ9SJBS8NnkT͒OןfSmo&}+\v׭LRWr;p(X~=F, Hv5֏'Vnj&GoֺxPu=T ug`De`¡Dqm\P]jDRu59leyV}1UE,iv ̙ri؅$Lz8inM0 $ c< @'ӌUԫ>win=׫&81L; yVhop+ݭt-aqHJ\ȳR?L*;#.b zT1V(qRՓn@0qU=z\q]jy*Bx$piym=+K\g"Lq!) J18|Zc>(qַ֩BjsjWyƑܤjdc8`S,ri5rƠFRl $_LF R.GZd\{H`fS&>ң50R("\c`)8'4EzyU8iLU3R} PTcsTܖ)S>Տj^qih@ }xN LylPIɥhg "i@9?>:R*qVcC"LJqKA{TpiQ.ZFfHiL=)Xi9 #fOiMÃ[T 'c2;{Uă8jŃ&~(&V2;T1N=(+N*11H悛9OX=j6 UPsYh"ǵ@GS@3&/j(vaf8X :W&H8} <5麪gWn9ⲭ4= 6=bji"/*ÄD<"PGURNF: wJW^U &VxdU)bu#0`֭DQ)dj|/"߼?w0d5^bG^qZE 测(ـ4lO$yYݼ +jS9ɡ6y"2Z!FlutطamB03ky4jȩ@&8/8P֘h ǹ0[ 5"z4hTT+ҙ,u%-Jj&4H1=y8ғqIqG5R$rp~1X]s] r>0R*Iu {qqx3 Z}v!b,3]@j =$) m)Eۚm-ݜ1(KvG+  jO/mjX5iD酏&w&@@\ 8hrdҜ0( O-@Wq9uc҂n"KҐ h`pR[ڀZж_ޏZkJu4zPOj)nIi] M g|kMX8k|}JI8xD{Zq˜jCI=1@ћwf\.ftfUW26+Ⅲh5Zzqv%Im]Ɲa q3hlʐWailc)FmR^W9;ԥŒ1e9 7&qz\0; 35(H4aUhT$ol 2S$L[Zj_RAf&S`"SM%m >$#.>fqɞuC]I!'?zlwn9Qs}:*[5Hs9,@R }`ܟNȡ;T\QҨ@rw:I[`=11g3Q6?1R6!fck˩] fkӴ;%MkQ$Rtyma]PG"R#aӤc銁uؠ)9WU@*GzI1$[ 19MGA m&Q!ű2̬ *}LK-U)/iY6_Y|c%kdVِu%9'f 0ͷEjd'ҔzYCy,&(ӟ\VZ  .g|kJ' tŽ[J#MӌuM.+BRGJ$7NwgH]ɿ寧ZKGRBߥCѪg 8\f.i8]ˋ:g=#惜RGCM ҁ{ q8Ҁ~l*۰9=*u8U184biʝ0kB8%KpGC j4Rb+9X tT ޔҹ 1Iӹǵ&:R JrN}(9@HO4zP b6I7CF1C4bU޹тOZXp!A>Ƈ C9Қ 폿lnԶv}ķHӅgzq3.ѷޓP!cxJFzL=h4⁊GLtiii6VFJc.hČLSP *TEf'ўiE.3@i{P!3F2ix"LB)7Py!9@@c8)94F(Kӥ9GZv2)6`f\QJB< ONΜb`iO3ց]T!SSs;Lc/zh4Ox )wh.F9U ]Ɓ''#QwhcUu㊂yfDՅDS'Wce EƩf|{榴W!>@i)鴮mO~05Z2JLf,s+<޵-jrNM\gYQ2&zbyz@J@aB";n&ӊM,+8m ~ь QF89=h;zSXK&hh c44N9dRz N>/S4qy5ZE;Ւ2Ҫ܎Q!8\FFisLj SR#015@7JV1WnW'hq'a8қqr1N%]lb}+eF 5 ٝTV᠛k 1,TVjDO=p+fZ ]GtTbɮ;tdrC c} ]cI홺9d=e[ Zath =1 &RBv'ґ&5վ( }<x݊ؑ#_tAq*e}SZ=:Mt1_ʈRA=k x]`GLWr!;h uv9a#:,Lt[JƲ0 [ }*9%boJ~ݜWMPNQI "V1<4ʞƴ ^ٲı$ rܤV̤[*hk֋M;#5.=JZ7+p3FՌ-j%eX9-Rۆ Y7rF;! kܞf;YdS-XU;E䶈(FSO%-=Yp=("~Tޢo2wO0.8JvϔAq;՘cR18sWm`'+hD*j vըsY)V0 5NHkP1<'hXu-'8q[n v'ͳRI6~Dhc$CL=ꤒb@ r;ɅǞ`="tqvX0 U;)2aTsh$^FpzR9|NJErcdxqMcf𤌟xE-rWZڴ~ ;} =/ϭ0S""5:^Tk[?h8p -[\]mS]g9g-4:SB)9)G9TG>rIn^ >4!>nizJ (6ބ]Ăvc?ZH=xhIR ,p:Pbp@bTHM ](^2(8Bց'i)e*iʧ8H=@ J9SJ¸Fw1 ֚W+CHځ7ztg5 -P@F4LӱE.@^NjC"OZtʌ I6˟h~GQ:aiǰs(v+F\\ҀTlkri#ԅAϨw\=O(j";[f߫JAKr.j;0$`T6X(:Te$SV(ث*v eı*;`L&~Dn I ]xO'֐L0U/D3QyCsw^c͡i.c $I";aR(PwxW&=-tvF$\]l*l3Q4FPt-׭Kd[@~b$"I!IՃ?! =dژ=M2X)'MIQ=4 ě`{Sܚi XB>*hI998*YE}3V2v8O >m¥A k03sFXŸz SeNJ`4 sR*Ԁb(X~5r3 JECx3*f8F1rJasabM"C 94n9&GhtI1I@0J94$~:⫯*kSEL*STt.h8)RL8)sMt!⌌SsM-É8ߊh%$? ]MHb0h AS-@\zBc)33L5 q4i ێJv&('5[}Lf[,dlᒳ>-iMl9U&3Ҥ)[FH56:Y2{H<%8Ȥwq޶쯢ȬfFRk=/[͐tYDNG{EjYS=pu ͚謵9xPpe0 !x56DI'M:w]O,s\xi+YYyVnV,cNrIȰ89#L|RFsNٵpip4D([=)$qH9qT$ǫ wE$1~abR0sYiPǥ*{R*q>bs( h]ր6O5&r)@֦Sa qTpGZԳMfF[jU#)]V sR+ ҒQ@ւpҩז1q1Aۃ_#>[ *:#14n;[#K5D.I#Q5HێIZcש$P*YiFY{sR eO'6 9{WZƥ4D0źL5o,OQ`[NӶ:E*nn+еc+#8ƻT`SاɻLp1~@QX+IjĠ`.=FG6IK;;f 1M8c\$9+bn+HRQYxH!1׽b!w̔Ƕj(1޼f5$n%Q&Ir&95+F`bjYIlB6dR("43cOLzBA~1Y27_.1Z_E:T6NGjTl)ܗ" maakQ[+ZJR2Y8@mEK, :T[⇱v1*8e`wnnc<'p\v=PQh1;A5y d'25Q X _>B{V&.ҙspxAXgG&-]j*!D;JN|N56 eр*\Q5*G  {F(g/ L'5{71=A=1ċhYAZ>V;SI6h;jιc)P^3nCR?:9U"B(oT֣nrHbO1]\:Ѥ:n' V"3Sx(ʬfex65JՍUFAv՝ 9V` 1cFT 7 #5'԰;zU h=:"Ni`;Ӏ(3AoZBsJ1#499 E2·N8qROQHBIKGZ^Jviqր 0A LiPGҲ5@6+xȹ(T-^;_L4]oK)jݞ^9$գ ɴՄ~)YU`#&<`)ވ%hKn$pk`pI^ W" i5 WRk9< 7RobH&NqqFxzRU CڍcM8)8 #/i 7q@8u*'׊@=({c4dӞxͷaZQ1; F;iNviYWޤIGSXVzʪSmRZ@2@'&TH.BbN+},ÎսzV6R<ɝĴa#k jM6EE\*[ԫ} yLN՝lc;Zr+žWA8!~B S.{vR 8HM7kKZa g_$m驥9r-E*@n# JOWZӱ V:Mhh3!Ork8}YEc j"U)f1VW-(gyULCX52 գ6*c5CꭖQֽ *kաIv. ӄ~). qт! ֠WO%/"U>#=H:)h H ApNXD1ުۭ^[A:w=d7`Ӿj5ȒP%pVہ|UbD VnxSqy8)8$LcM=)\v1Hl}y*iqhvC#e (4F9>הBR)&zRryNx`Sn9a\F*TgQXbg |ɩWyŠ Ȩ`1MS*+sҤ_qJVXP? T.GZo8&nqM 6$!SRTOH͞(#UV ANA- ~EB~ln6b}4'꿙MW8'8,X,)V3g&4,$0^j孲y 㱬V0J8b6T,OjS7GRϏ-sS=L׳Bls0 t}ipK,~ꖨSH⸕ݦW%jJtUի=^Mdt:>n7f`J`p=մ6@=HDeB#sjniskyP8kݦa<j= $rƌˌt qYZ}ek3K%Yw?[8Av&b@؀}iUIP)Z33ofڋF懞 1Y1*y;ZPfbedۆD6G9-&Mb$ob(nPp4X`S18)2f.p1S E9܌uN696NbP 8dU$e& v&`s҂GԪr8?<:uئ" rh i 8HjE4ixxl)z" h##85Yf28ݴzT^)18LX" ZݾlKۏE= U;{%GZ7q4%@;P2xGTr}*[cn?:#&F\EE&u1 qVQ8,Ij\` vpqMA%;QX<7cʻLOʶ>^ޤю5r8FOasCu.@/ҦU*UQPCc@Ґ-.((4qK@nJ 0Ҕ~i ;3R0q@') N  zP:(=EE!"@84w.'^U`*?"/+ \"L 6i?4l;4=iA+uk5!4jLAvjOzi8:29X Fuq]D6{*[#0&nYhyFsȣrʤ!ֶd!6(L2. w54q Yn\_ީJAin@7d ӐW>[ z2(DUQ 0yrhZ76%,Cm56'եF^$vyJ39+!{ v6ZHGJѫ%x+F:ѹUAS*䑜nWBj#ښ"KBGq(9RǭY4'J/NӒALOҩd~4pFiXx<')bO<ziPG4qI6vg3|ҙԶfPUGy$ \&3UĞ8xIDfFY4jYFE;y.O5 ւXcfrFMH։O@*xږ5Yh䎾[2F?5Zw4zķmn@WKiD=MQ j[ː֔ijq8;&qiQ޲VVws@$Ix8MtOWVdH$Cxq5u[}K) 8U&cKPD/ڻO׭H#E@q Sq*MHKd=)GdSҚyHq(ʎ4'Bg5g"{Q# n4jMrX(rIjC"6U8'#ޣgA#=*?2.Zj[HzZƪWw~F,dMܥshm;2ŘA 'Hir }U9Un;E6m\`\4kK@ nkn2WD,իam[I=MCi'8%O85>iNP-";hO˺< snSOzg>E8*v;#d@aQHjSSGMh5֛iݻ&9|!lTZNwty*"Nۤ*L)r&E .{Zgd*\aJ$m2 o.p:I[wZsFɦKa;zb&r)}qT ڒ;XcU"Y8d̪:bG.ӊۋxRF[x#R3hi`9"0N) :3* u7uHA#bpD1{ /8@1FwFzZ8 k3ގHO('+ =SSNRKPI7viYqM9@m(`ҁZ6ub{T9HERw̡Zq@NO4p?q.I4'Nu旃Ҍd! 0Z\dހt?/9Ln \F@SKNi( RvzR4(9ӁT<0ZOqZn3'9\Q$lAv9VG˜{✩&wWVC!`1Z/CdLv3uvUA)滟+Ϧ^ z8H+SFK({6^܄Hsӕ I ҀpNӊiQڌq@ wR{IvE!'׽ g+JRÿZk1A9ސ,3N 15Zq>ߔ c`i k{P18`Kqzdg `vq[8;&`T`;bj&9pai2F|#G# ,>Szkdj ް} Md SD"Uqֵ-++ĸRAJ07&8Jk cXVV*3Z DkU 7n)D G [8*@*XMJ*EBT0犊[eh>j Ȥ S\1ުܢ#)EGuAe#Z}ޡo3:W?]'`nz|ea٠*ۆ1ҡT_ Au+5% yT/H1Y"s"7r1Bλ b/YiՆ3 ]CduqW2N=1U-=xEB:W+qԑGޣ*0Q#Q h$Hez 38M+sȦgpnSy]sQE[rYrc`<';4 cv21U<WAOI"N&R*(EeA7E cҺ Ҳ,k`Ss*U8'K9r>ΘP_֬{t?0!O=sTQ\~֡KM I '|V˱Fl⮟Ċ9?Xn&+S\k> ZV=yf*NNC/PзX_kz:ӾT&0N99$qT@gifH-vA7#i`qքQO >ưSYޥh*Iϭ e g)߻SSP> ZraY5fԷgL;w_mI>*'8Q:HnjQP=-}*xbQnF~]̉n$u=iNFd%d/lEZB15@ӘH,);lp4E#LB3c,(*[OR1@MCC.NU`xR9+S< SJͱS'8T6޹Kb *xLuN`J})7q.0)Ԗj ҥ@i|ڑlp)I<QSҔQS})2jp4nir3 \QHڤw%TҤI擌Ӕ5%1p1p>@ ㌂*)b1'bWae$RU=\$k@}5NCgRbr#9+ԫ"923PpGVFHsҬENsE Ra KPTȼiҼuD|ޜ=82`(lSRإ(bh.i\(OҜzyGޓ97aړ9t@ FVl 3İZW?JN>yITΦYW8LQ\⩑dCDԠ7 X~qHZXR3 ap*&zF|sQ3w1xn*%` !}ĬW$lJۛg6TEYOjq9X"rr݂ې,1ŹY~pH56Bkiњe g>ѮK`U7*ګ),+P.峷=h{phIrUKdRL]Q9$wdvGZ9m٨f,O= )w `э8<A2v(Dw_ZrH-[Mac=ƚ"NFYVF XČC&Bg ޅq1*MmtiFQvG\ըXprj[’Gj : 3лMҹ8UO(W,ջ{"+V"1ϬaI^dϬHT>OjGje4n9]Iyn[O5X@Z31nwA]TSDbNȣH+=HJѾCǥSj8*Ӂt.ݣ4 e2sl(zar{QԆJQU h$cUP\AP3dlqHN)lm5oЈn\כߛxPK{S8$q^qkykCF2Si{n*HsQ(vs\*'hTJ@3|I fP 5DҐ@jśd|iѱE8+bDdKd8YI{s*),'"FM>%b3!]T]N#gLKdTP9)k+#ŜQE C74B)7,A+zYVsPΈ)[8JsjF8ϭL$?G=)3HC9QRuS8 TJ [EI4>aPGMqp,jz-j)cҦYV8X%qҁsM|Z}XPZ uETPw`tyIGjb֤As!|tUHr8Vq3oC5rf-7j} *dftWKKgIHM#9;\AyB$uwS,MkUF~GJ6) u5YYiค g%r2|O*48!ZNv(+r9)8T+•JᙺRHDnNpgP QgU4X8'&(rOHB,{tf/N܆B85VV]PSڜqU]P5J,N+.@csQhTHu&llbH̅`P9jv y<Ѭ{pvs7+$O, 'vWY4OlcwwB9xB8[f5Ҥb ک>嫄|UhT.'C*ޠ5*{M"UjiIҠz7 G2&}ʼnid cFLj81pZl<ޕ6A(lJ`b+ Bc9ڥ;7bPZ:0PF#Pa V j„@ T# .0zԊwbyS4KX/r*_ۑڛ>ӣSǭ2/w}JsiS ҁ\#edT)Ҫ[2*ҩ݃ҀcrpGjJkgzTyb{n%5ӹycbOeSVgM*77wFڪI`dw?ɵՈ̒zsXZcu<渙ď&pVŒAU:aw=FƟ@k^DeU8h3jk$;hmU"6 :TZ}vlH´P w3[DJ R/ӊx銳 wKM`1Fi9H4jE&08i9 pN)7'1ɥ91z" }iёRԙM qҀ\4 JUP1X;P4L(18w|T`MC'4:S*3>,=j)Ij<*Ya ֝ o08dT$9I'QS2($BXJ:?w{X+r5BwdԪ$EUQƪs/sQ{s`۫6eE ֹWũ)e2MsJH PɚPPҺj 7WnxKn[PhH UW!En[Hʱf5Ƭ9-}*ʩnMW5mH${IA5 E cmiZw|ǒ7,Fx'?I#B8Ԥbتc&''=TLCImp)p@>m2:RV tRT!1~F9;)7$ҽaBzSFOaR{ gڑ u%IiבLCK_zrAi:.H84&7k q)ÓR0!27JB4W##Qa 0i[ {St,hF\`fPfo`*Yh *BN@S8'4]5#28MٞD@ E/Q@-THdf9ۈ8X"Kw'nJ]nP :Mݝ\%*d*,q)'g*18'"!E )^R#| ֭#6XlS0G?iqq1Б9VAC:SFAܤw(u#)B:S6vauXk[cӵyv[N?:WQA>K}ZݮQ;Kϟ u>0s ^Gٮ,Kn9'+KkĐS' yJ_$.Tf+wk $ڔ:kB.ޤSԒz)?:U 0iHL瞔 !nQҡpK q5 _)2n2|2 w)H|Z=*LtjL`ӎ2F3&B$q@Ss[ Қe([5Fsj0JNUA*-RFah!.e@6✻ҕDmbl# )-wm4i40>T' x9iPTy ;5>&MƐJ=*ö֕XGI 19y 'n59'6VhB-kEԵme =jC'nE \vB*7qcM8jLژ7ֆf;yCcSV KGLQ/N74K(EҤ<)f94U`y恡ҫEl<=i,a*z**.,NK :UV\ S>#piD} ~"Kt'AA< *0:SNsJv Bi=*Anv} Ht#m5qpSUH-QOx['JLX8G9jF# L R{Ԁu"(@c'n(`9(){`9 >ޚX昅f# Sd~GM!=jT=81RxZ%bE֙`iSgzԀ!94R*yP(%ElvK$"v>ԄDMuEJ㊉PRHiN) 5]I"4$?Jin&Ìs80b 5jw1VGrY6;֣(2T ִj϶ګD9)5(zT|\\)nM]M!9hh3"AN+!cGPcpY|,zJ.NA⩴Q#HQfG yjʢ,{aJyQ87QK@]O'>{w38$ *3+Zų7tVh xSB 2'sW֥+'k28Si[u66cҹ0ՙykdpVm dn3Y2))qԛAapڄqA+5"\UU=飚[2+z+qI9f'Tg$4!_&Έo3i 󚯸XRibBq[3lwpZͶя4"Q@V[k&TJ8=֩?u0c}P`5VWgRm;=)x[ziv$k&ݼmocLI9u8sF9j0# F8AbVALBF3HF3Hb:oc n(@T%$F$S 恤1OjajEBfh" Tn`0[pNsC8UQ6 H; [=AcPSڥQ) 6h;jr>B[Wrj2{7JS1_4jFEFjҰwW5mݑm#N !'ҩDG=ƮTHH$Uz%e>i-cRrTI<2?Z`>}j3pVLɥr *9*PgڧmGi$}j#7*xDQ 6SH?tXPɓڀ4o*̀&BRW5R\֑Qp$>֬ZZ ҤqVBʌE%Il?).WsͲ0W=K}pNOTbمI+ݮ_H;FMJ6: d #ƝNy6[ȏGY{yC12tFx.rn8,IE(8 {{9#L Ii(816g&@)n#$0A҅ڬ8F4i \s֜4uH4kOxR;6p:TR4+`Z+[_li~)@|V3Z <vpzQbzR 4Iҗi"hzH>SqM ˱$&[Zk.I g'Ҟ* @GJBw[G4tw+$rxU^' |7 TuUF0z%+v"O`tK%I cUxۃKB`ci-N@##sN^W;,yA>DlS`/sSb!w)id,qҔ)/F'g8R3c(ZBHFx '7cB~ZLt)$r(F~jQ€0W/ZCsRh5 8{~ 3Q@ǵDT9v7>َqH\94$ 6mǭAg.^JyM6Wcf8O5S/X.:>#@I E"ی AK (h O$di#ASK)qրnEIS #r1brGriIҕn1#N,v3J Q`қ4 a{lbn iUqMOZiw9/ 1T.6R^6$bCk!f7RWbƻFH=}.)BR+Q)X|M:(bT881qZ(913(*IzoL&\@m!Qޓ mJvI uOW&#H6y4v41ZN5a,@*O##zVݼ +wUCL\ ֺDK"eV޵ c`Ž{pg9dlSx4(&;HHh9(@ÁAQҘ7qH@;ѰynÌC)5OS-bi$Toc5CO + ,av犬[TfB+{T Ia ڸ7p&'™1V5=) $MsRv&uvjYF֨pc;[4Kd{TU * MÑQ 9j *@#'ҭĤ)ɠ 34M34ɰnz3rEG 'ذ1O*(Hn gڑqBǸ5e 1O$=iPc<M4 "(8#c P <:V9(()'S8C4cf-cc>A$ wJcc{S'D1"zK&Sdu2Y5 V[V~>b3:3P稩 E $Ҟ[RuZ{>sP bXo#CM-Q&'Oj`SiM;;a)R D qc Rv2 nSހ PHH9gHdSJ4 4f& U$O=*g$Tm}3LpZ^>luA7ӚjǵHv,?F yPA 5.#,5B`cf.r9ԩۖ`@0FsYo *Ebުrmǩ̤gZʙ$\t'b9]FA1: b*sJ+ QpOR`TiSh񤋇Pk6MeyLei6=kvgj»MϔH ~ ֳy(W) Z7#P8n4y&7&7+u4r' u6ifs?cxORJܐ 2j{/-"mZT{ kxpjU[P8EQ#֮H0 }Lg.vilTi|ș F61*Ƒet1$XϥþP̵W,rF Cpvǃce2jno!vXG X:RiZ16bbA/"0~ 尹#]d,AR4r,r:ΕP?D*7洋λL$ +qgy:pR+VALesQkS &L2sDSOcև V!^O\ջy'#K*x8 $- T@''.I vaq@?Z+i?$V2)!E;$q@9x ֚8=h sFx&w ԊF^ȥ48$2)Ԇ9Q)8⁁94nRt=(n)8(!TNr1ڀLX8Z|i>nHx;q\F/ `z\R})@@ɧsL`6hҌB穠g4ҜXuh)Hu1qHNGؒqM'Dϴt9(6{Ӌ|J`[v84 'Kby$sQKiy8+cR2x.M0fɸqRHs#XXr7JH$T*orGOF2'Fejgrzdo瑚кrqT13\OBaF3֭#Z íFKUd],3o92L_p.p;Sݤ\ڃDTd{rޮGn $KӨ@`0I;nUG"*(";)&♕M0U֙#ME=5s]^;wr69Q[clm!NiU qޡ0v1[ϲ O _C9-X;''BM6`ުhZt #ZM9=뮜9Ql@e$v;@=#L$tr!'vz֢"1/95^@prp=i{;.@ ~ZhЌ ץqMOˌp*d#$S5؏fߙGZi'SBW#@ph'Z4`1!u&Zpӥ6sORWJ%!EkÚ9W]j^xlq/Pv!3/=i(B8-@ iz @$1ҧ48搰4cby@c;(lwb! H)4 M{ 8II')q@ *5 lOZ84 N _=F1ڑe9`nҲ.doC[r0XV]Avғ7ȣ\!!5J.OPB: *AR>cQ2PsVYyw(Q+1,e&Om94.޽5RQ!F0~j/v܂ǽIhv8cLE24%I/O0{AQ>Y)AGSA$CDpvFzP5+x_'4b'ǥ7c'~iXiVlq@f@oQӔn A\zPE8r1ޡ<jQ"Q gzCnr:hNI*EJ0F R!$b 7!9DZ仲z̓58#$`O'0 rH⟂NqMRvS b@bmzzLXр8$u:ƈdRm"#E ˰Z=CRZi.9E9X(  n^3S#9951wsOj/sNT%8NW"sh:B8#RC6?5ٕAkrOniYTĩ$%r%+ 3ՅAK{boC+JWh44ȥA6Hݹ(#a+pZv)Y+#W)37=7 B={Đ 灚&Fk(_c`lZ}ձit'khK x rUM1{iREqo0.)漷XOy/Ks6d[hs)UӚs^;,#j[[YoJpDjvBs׭WȭJYCȭC8N ̊K0@Ut+ jX?a$p9N t=hg#jݢ¸I杜*3٧oj`) IH$48\Q`"h:a|g< z QyMfl(6ӗȨnE8zy^)W;D#9/9AuiJq41 H 9J<,F:-TnGx,yq385q.% g&mcpِRnQDC)GɇO.ppip)uZx#0qApGLRd@n:PX)RHc84nyb=xuؖ\^xqؓ`tăh21Qtc 'oi|Vf+ aZA 9Hh"V<F=v`Q NJIVFx=S4:~arS֩^xLң?j^^:BG8~U<1$ Vj?ZҤl-i3jU>Ӛ4rx%ubǥ(ՖcHبq! 5FV4P-5&qGT!>Zl9CzS*D-ns;ј^iƙG4 I 8Md =Fg!@cPRLqU AfzgPT4'cEfM/sҡ*|ʹin$r94gW[;*>3TJ r*Xzh$VzcMx5TmFʓV!ڑ#%6;2ħAKdF*lW$dmd=16@]@⦃ IHrٔZvlkF 1O^#,*8rJ8nF d5BVg9SIY$g#5g- ҹXu<&jܢĻN=zyLO&8+&k^[>+Ȩ[v;4 WGSX>I*7(唧8j ajȜlFDX0&F7A Rw^3;RR~/4(R8)HR"dgE=!vljXWȧH.~9y QphގAP#`Rn"^h {P 9Ji S&{ӱy4R;-bɦ9H C%%bu5*̓Z Yie<-z]a ޵^[ՊH0k|],f;\YvhHIY(l}Қ|L#*g}9&yCv\,69h[x V%ctq3ᴝARAܚ,Iܬ t'sŭKxJj8族Z lWAnQ^SsO~(]UeRˊc 9=2k>E> /ԥJ9Hl!^>maFMAJ#$8HqWg%2K75uX+M$z*ۯ5=zzV!U#^1Z"\ T`)_L,"b%ا{뒄,oKWc./K|ڨL J-,!aPK SVo!:q8H,>lS7!ԍ*\5%a%AL F932HҤgh@Nh XHNN{U#nIrL{x3l\26g@2:TcϽ!2#)tBp'&Xū J! w>k㚂Xw@gzPRV#)[]9<☳$AVDb{VCQ06IϥRfu+Fՙ%з,,k|? g&I%niEzզfbI]0x،[[{iqx\sFA{Ԍ9J ƶ݇ pÓU?n~QLtE)PrOJ1Q䑖A"z"x8r:P!Nl#iR%PjU+ځA@`[榀qOW 3(o@$tNNh 8қ UgWH[*BHǵK4t9RZ`uXe^Iv6`/CT#qԞi@Pq5C*C3jX=6@Yڞ {dB8Y7 mbҤV UN xlpP)!@P6x}sLri_)}RBFXOJT9x#V{zP'ÁMa*a)$Tn3;lgଭҲ9S29 HMIsN9Vh$B96E;^jǽFǥB#ck60_zk!tÑBa(-dwOWp84JC1OHb5 U?r̿) KTVVew0fV|A2;@+9Hޕ$c" ǟSsDcq/k,ciP~ءe# /85pm Y@0=.zR "_'_¬$͂*+'852 #maԻi58q#&19R̡⟂2OD%hW%!襏#e RF<{t)]@c(S:R(9J8cqA$ @E7 (NFy(J i!4!ψ)R䁾jU{VS "YefcI'.[*QH>ytѸ硅ܑW ֌YhZf vꚌ0Y115Y[;S@!<ݪQ_~4 GJy5RU.< {i#v"+yHIP!1J(SI'8.K '1e 3cÊw t9⑥ dqNM2u*E(ۃB ӹ?-5m8M!~GI)1ӗEaF>ny,xO\c(Is" )^q)nzNeitY nqQM*D$MpbCӊidUA9#X݌ N9@#Dbzr)]Mu4yP})UC 0bGv*->6](@vrzVpOM K>GĕA_B&lZY|.qM sߵ,їw#l@TFV&q.#sKV''R ,=q5i3E[QN4ɓкq{x5aHU|#L6L,3O' ҡd=i">xRR+zL[,p'iR:)䟻"MF;CbA?z#]M }Z.FjnqTl)<0;g-Pm"eU:*H`2=bɰ8g+AGk^H4@ |eW*s^8/RZP $icrd sXYZ9!:ZqG1sO1y~4X9he?wB/O[:\L ǛNXNO~h.Omq#53SvADZ YsT`]YC&OfǸ5ln Hǐ8nj;{}mFyZSi'y"9(29#ōo֑Aɩ61'p }*u1"?z)R$@1MU4(4;'4QPH4+M9(qiڀ$SҘ(AS]/TiaM!ixGh;GAMUHy88O iKiڔ@$A$uKm"^N " 3H*jq=.O4Ϙ1E.xpsJph &sKҐ;PA%ITqL 1߭<94x<Qi JWw7V©Zp>,1<) dfO }+3l)yMHd=)ѝyI~Z@}G pcB$D%2)O枈Ðx)-A#0t`|u< nj=r'(Cڎ;)褁(T4j<Ҡ3lLnџ)0'O#d =(4S 1sZQj3=Y{J=hA"cE4.P*f qU`7Zk}Hd(HZʷ].9WscJIq C",g˗k[h=x=jZ5e:f vUbm#ґYtj;:SRw0iIz⩛6p9=lh,Pp* EnMPWA Tȡz)#E@^:I#V89j91ڢE.0'5"f ր ڐ4)2X9ϵq֘ {Qr3HdruF*C)9J\k}PIJi0W`?J!< b4d)59i"|Κ0Rbį$qXV*2 r\rj03@:qQlu1ZҋrZ7!㚟&PqҳFu56UcIcC0;W}[jDviW*rJ5$aI9^j{ 0߅JW;AUl)ڙ̑DCTS>N1HevdiXH⤓ W''֓q c)1LQ;{UFG"]$gq\#⥭ )ٲ˰\ZѲ$@q{QaۼZ:yE,tEuqYv1|*eb3I5,>˙B\,7Zf6w^W.UA'9=i7shQ,^;ZX:mOoh .mhqV֧cF.*Y|1.@ t1$MAOC y8 Y Mo` zwIj*aS3|4 @r%W@>?N@=+{\v,ЖdTl}n=>6\֒x I+)=b\3~"g#ؚNr{nʇٽA5[H-h?v'NsFHxD-3M 5ֱUk!dkuOJ4yDB=jwO֍2ySLc$aXvX'⑐oǧ<h9~^R] ,5Ȋ~fSU&֎f`,!GުR1rj%3Rtg/o&ݟZIqJ(`7$9渗=VI P1E_1)UB{sHx+)jKms֘sғ 1@/mbp3R($P&`T` vqM 5}sQ# W"(/^ ޢ >J`g\\jO-/u-aJ[ 8F-HJ08'=H0Z&9U'9HT3Nz.FJi)(]玀ҬiLBSTd`AJIM2Xsy-Ҥ+h9>"nOJr8HXq3LS؃NsBwH^xɦB{ '+r)b皯#ot"N{Ҙ$Om֭FYi@*?CT2D)9v A9qֲ']߇Jر-Hz"c"%B1欢59$aChdߜF{G@{SRcJ)A9E&04O4Xw%qyqLUL?λ-Y=!1cё0ItPٓE"c|!8R@I`[S* d[\xQ 9ExN6^r8QLţ^w(5)l VxUꆿvlvGKxfQfvByM%]D?w! Ikl #ƼUm-Xb]֕I]h">уm/Zl >|*d0qc'KrÚ'sSF[hNrՙ4J|Y^"Ox>(%U`ELҍe,Fh˳la(Eq184 )n@ցXI9=*sR9ǛޙKX })niRc #JF ҀG@(ȼy4͛[=r {RdkN)Hzd#@h҃^>ݚw=)P' qznHn~ޛ@ixs֐䌯ZQ@擅940hV3I2YTS) uGsFܪGaC58Tm-RV2F)zZ`%ĭ,S52j[Gb:3ڥХEF7'v7ڬ]V<R(''49DO@v.EDlrO>gJH-dޛ=(QhHēIvxtS/bۂ=dJCm ;j@ޑFœ+QKzUvdcj楥სȭ.U<(|zgw&sU$FSް`[1L("H2"ce**ek&|#&lDڍR1.7\w0+ T7cjPS/kW89϶;97]f! !dt%+:J Y|9[ZpH708\岳#ݎy[Rl⥔XԌa"V Lje9㚨ښtq7!50>GmnF#3;ҽ˘b&=)hqP=ҼZt4'$4s @'#5]Bֹ\m%!X?,eV2=&&dX&{&OU3H֗ ˰kzT-O&0o%26ÆuiW{#f@1P* zWRV< 򸸢ԴRi() '=&a<үZNwjbO@ws`Z#\g2RqL54ӵIs *dEfJO&`pDdiqO?*7 m^jNfN(QZlK"Ld dԀ%'ނ;uE;NxgˑR[Zqz0SqM#""ƀ(40sXRyg"$8lfKs)UrpzP1۸aVӰ6v1Q)f9$piwmh0~iwlJH$!֓v  kp3%Cp)?55i1!s<)yWSMT| »/ķi.]jֵ ֹ{ Y Qy+9jvPƴz#V`nFQֻ[C|6н*S9|^;]VI62 mH#n}kEJ2)cV"G>U}Ŏ{G5Q,dI1#8CwZydWRF9})C.u6ڴi|VRzK Tw09: :b{ -@J0+@#+ҙ(88I( N=1T̜=N-Ԡ|I҇ j㚐jfH  JNJ zV EN0CEW n8TqHFqS)`Au\|PF3[RD Un ;H2xVw=~8 I Yҧj[=O2dO\[ \*,At~Y UOcOP7Zv `;E_0sQ QlG&rzzɠ4DJYQO\/qޜ0I6Onj@ =0ǦqI*fҍdc֘L3p W94yKDёҜ y'ʃ h~:ޱ6ZX3(7O-f(P!=V-ߊdcP9zj΅{ԶtSmYwsz֍ze#Ea*ݤ0QP\ȉZ|,|$?JNF 2xNFj0 E*V뚣2Bdy y4Y)Ǐ4cs>( R&wsL:<#) Z<٦HҜ~ZU P[#`sMqeL9D`A\x4qC; @`Vӥ Pdy$(-Z De *7qnOaD8!@PyX~i2љۍD=+,"PxbקW=-e7oIht$p=kbI,sVQ&_`UNjJvбn`Z0Rv&ڼ*H*>ͷN *3+RFHu1bG\ A@ 2Ns֛NFAS$&!$RI 'BPsڣ',98H%\sheVX^H)qi/˕L7q>jO+ ׊Eg ocJPI !c% rZ=*p wwx5sd0ǭnJI|ʼphYKUB5SN1ҳ)+]yy#5 JLGJ W jYy'R3Cq Iu.LjHIZG%j)ҭэ9=k5_1T7[\3ʩMT[(ȪZr(fPќ˜=jY3}*NoY͓"b8ezFvсָ+-K+OC Jr3V,yr0R8Wl1յamT{IFccJrWv>Yg#dW)8sBhCȭ)j;?t Sm9)Y^R1JP h L.@AfH<՟/i#=h9Q֥Gzwx`-F<=(+r ݪL#յ#ZD4.2)9܁H4@N)w`td R#0#9r0E!#g%9۞xAߊ HcI8Ň'TQf<1ȣ%h)Mf86c4|S) T 8@e&bÊN:S;HWҚ8=h?Zn dbB 40hl2P0N;Rl9jS#?!,1@M 0bFOZ_@9"9/JH@Ҁy})&2{SYL, q}(r2pNzW} äh.FNkWKѭ؃$`}kFN@3BlK~qG:{ԀsAE;qՁ]Gpu{rAjKG}*Yr6|㊚P5RfPyt8 qNYUc5YI.b *6ðRgd-C޳oV0JM2K.힤T0& c0r=iPMjuPݤT\wĨ7GP+ZXFW;ŽF,l#Qfc9F2:VDCKlSWe/*$i<)aQxZHi#Z;VN=e 1FxfԁBALo[b} Ӏb[A"槉Rz~Ҡ& k&\Ij92żqY0pXAp dv`eEo&栍d m`SHH杜)[5a#2{5Qߵd"nn{"NƑ)ՆK T`^q{l#H%Mli2bRՊtCl0QQph >ps֕m@Yڤ>(b LWFFHG")0;Nx;qM'Ҁ MގsJF(. Pǜ9)=JqNH$X?(jBN6%>"MHq*6*l`g<'F9$c8.";EF6+OzeG78Nd ㊥ ?u$L-H1Uێ1R;Tr1e楚D+bCp՝x5AcMt+'LmU8wPYV[ ݼ涃9++YI`M8}گIwZh+ |3xmn{|pwJ8ށݑIc z>Ul|Փ89ʊhQT. Rĵ>=ŇleӆwI9*GM'x=R80n=IIhxRsHFFE+wIҀF)wP1ӵ+bNc46H)X3((#*E`Ӕb&.84tHx?2:UC(IGfH< Q9AQJ0AR#BqR38 K҆z)4`b= kuShr)4R1@M Kgڀp)AzP913J)Bilf4.x8 08Ӕyr9ry#aSӓRzYy`klw|/B+1`תHyω͎o7;:3bѣ%h ޭ3[=s%Ƨis[іF*uZ-MwSMGEf3jN9[ sO֢+!sOȆ#ҥ|TOu+IeztȰd6cj 5J*{P3֎y)6\ r+zXr{8"[$SW,o*`>:F7Da֡12q&7JsAl`7&&,~4IʒzcUyZiJ3Mm.: Q|Ł=HHvsҤ'-d#K+(8N ^Rn 95aWI݁UPz@-O9Rt Қy=ؤ  @R#iN$i??h+; VBG<_(dս\JR3U_ǥGϓ\!zHSqNہұ^Kۨ؛[Ջ35m"dl NDEjՈԶ.haq⻒QTt=&]D}yCE^t`/!fciՉu[p qSI>No 4R2/&Rf ³fq>j~YrV,0u-A$7ZzHU Ҽ4/|mPVyid.&i=IR8Umcnୡ:i% RUlEjFD똲r~P Ms:iʁW`+cW?oy*=n GXxvzՔQJ{U)HWAZhH[9D *8'9(8'# sUc6F: pbUvrE xiˌҨUF)@Ž94i$|)h2E;*La@&a4-Nq-6PSX)$dӌ8 dLi싑GqS  ɩ۞£+ӚЈ0&I'/9*4 >F=ډ@yS], 1X7!dtS/[qm#QFbXSm' Ll5ʞ}*br` Mb{퐞::W-4jL|V q*p ہMVPLvoZtq(<ܩ2>>J|p;bC;JbXNRHˍ'p aȧP*K+=!zD0#>0]ǯ7❑.L( A@@*"ytq~yJk ۀR&{P6?yt;ёWhU.5,rLr&i/GZݺ.2LLT}ڡU"3gA>QRRE)ȍ^9`*d!X未xjq"#s+R*\`Q^:#);q:UJ<8qȭ1[ )ӥ (&O4ǥ(C9@'ޑ['1*%dR;pd51$u9[9JGF3S&X7i tjVhqmrqA=:iE|kt]ڽxȢY<=8^`D]ݪ N9晍ɍy>ԦPj8aaN,>9U,cgVȧ=jyHf5XsHMv{qS'҇(BQzKۍ0 u)$0rcn Ep:Lhv3ֺѶL;Wah/Fq\w·c@5z.'/Ž˦pA<&*yF儹ec;r@ T]X:<јҵ1ִthON831vhP81Җ؛@$Z !p?T1w?j՜@wuH.F?M4Pj~BGbnr1A&8+֭6EE i}qVFzLs FHCHGMvN7%J X;R3"ڑYN.P$Rſx;WU&@K%Bk6"HjQV4SU2|:ڵ^ouy;\IX+gA<)ةMnG2psڨg89gjJOJO9*9S1j+FH^E< pt?qsVdTR$>XQ"5V@Ƞ$'bNʧqL'm&p)nS|P$+HBQPBq@Xx,HҔ0T_xn 1[bʸΡwRZKjzL5@*&pzHc'65Zfw! EJgJ #( R3Ԡ1#K1N 8nsOZpOrhG~p8ݾezSI;^ E%A g^ -zVUh=G"/IQCG*yjT P^Gzsh91LR$7=?xۀ)\\nR:UQV &~Z!L"#i ߅;`)F)܌ȩJ4\\'w&MT峊% 8J'Qgt$oz~6V_F}FV8ٙr{VZM %ktZƜqDЩYy|Jm qVM‘'#޶ͯyqSYPz;E,8I8&KqT`Rޮ2)A,+mAG)]~ n`9=i) TdU<*F'U&wsMHv9fވn9[ڤ3PO vQ&kV97 fϘmhl9:kcB)!=gCԳ&9#;4HƼ9-G* u5R A%z.`T6ךKr֗Og*c]iOC; ` YuHS$ֶ A$ܤIٜ(G4őM^Ȭajmc2R{`hXM5J>Ԇnv?A]6yq>nFjմHF*;h#v*khHoʃɮO:VI|$֖CK\aU6h>"X' zeQ l!Ix?xWBárGM UmʆpdcUa^jO,@\1#.4SipJ@ U &vԸ#4%|kCBLksZ+v; ,wSZl %@W̍Njr3TqsAH t3+:DʱaZW5ARΈ= +&ȑȕcϖW&VcՍ{h/5'U9f)⫱rI^*Ѯp gJ>N3:;V08'dR]LV19^*܉yd؄=zUy̱kRPKq.m<9p7UvHʎ ir@=T"i!еcw2jW cfx5b+[*,LR$@ÜJەKRK3LniNs0O,L`PffԇpzҫvA 0mӯ#hu#9B!ʞ:^1P7.QW +w3#wR@~/-$rc9V0 ޔMhlaH522>)R<i˵PҜ@F ?h#iCznԅyL,G 3-"s6 BS8&]B F2IFGf[LԶ4S U`Nhv4,thZ^;RHC摛"[ldjyYm.YpҥH6m(?7Pҭ^Y湷r@'^%5k ,#Vj:! {4MUuO:WB5 k5thp½E,ёnk7:n,`*aLT A4^^&Hx4H Jr $pi ,8< 9yGN) tC2 %[ހ))o7fxH iTӊBWXEArFy9G6ҹ ͸qzbtCq\_q FT1FlqS[9zh!%8 FX p)Uم!Ĉ3yǵvGh:,( -r{ VYMU6RQZM)]Q!m7R")>N>\YS60(j@yۀhvPzbf(=iT 4bqB42JC*][Xqb*cHI%O#F x=q\d0sSyMޣln9r)Uc)OzL|w֛un: q ($y{8 7UxˎNqRZف*U0G12c{T@mQTTy-jP9*e-AT`XQ`+6GiqKx=l+ܳҡv*MEkB0Z=ʤ2) >sHrC=* 3%vrBe+2IY`/ 4=tH.:cOE=;\S9xqjNqYI n&y"RLŊ)sH9)p~F,SO)lWNR<յׯJkXBϹ6[`c'#Oqg$RUXƼueg!֘QzdϜ$Saz3ѸbǸI#ڜIT'8 7.PٍsZ:m̃)3]JӤN2xk-ɫ+Lu%ĀxQ&(`ӹK[BAaR ׊ :m844 zc/=i1ҭۯ 1lہ!F@kjb.̴2GOʺvE<[ǐ)##RckkP6w!'Iֳh˞A Ό\7= b˴gJU=iTBO5\x7|i b(sH"vr=*rFjcvݨy?{?R٬cqN3&9U#~w⟹CW4^[Q;JPˀo8Z VCrAϵ.' zQ8Am9'Q9UHzմU#)ع)2|8jԁ~B=qU"xM4a) yB908 ~K}A;$8s6$%2+Եm=/ae*2GRK7Ks\`ӹ`)EE\@7W#)DrpANxʾHO5zdN&stap6TeHD,1Loݓ(Wrš)O[R! z clR *eP1tUwNB*ёQ ?vLm?XnZOqc5)݁VWTC-@54Nxe>V YBGFҭ4[ކX$ ܰ]JՎPfmMzSk E!t&Fv''4ڷU)Xuir7̿Ӌ!jɲͼ`8m@$.2{^peHf4prxO&} hQշ$\2F8ugskVrj~6ы0jޛk$,@ #hZP0d&􋤊*11z]I-j l DizVNvU[5 #Μ\YGQk';u N_<9`=zUjcC+ FQ(\ބaGz3'QM)Pbgf{qGzqH#ln5N7dS6>4!"=$TYb )6r}i ֚`9l`= dbFw'>UɩWj u.0 rӶ94 [poҀ q^!vc0) uWIw8=sc>EnM&Q[_xd خ܊Sqq("41pkW16ް2"j4`SzS1!7dtkk*D&mcw5I"̪tl ILǾqs-^>["<RκSrR7ɖ2q#v8`ҫ\['.*W]x2.0)6cS_n2M&Yi ـ~aֺkYtrW&GX8Ir\ު&5ڴ" LQ֬㛸0)Bɳ֕3oΙX&sJAm;q1\>Q($kuw~SOjPR `#e_[zTc0.=cp00}j1EN7#*WzdJv6JXz@q҃qoSwD834ɤ,3ɠB9WsJq,E#2jor'v;e4`=ƜT9T< .!r>~u|kRILj$ p2jb>)XF9 fLblWG.AdܙP\.'52\nEirR8f'UX0Y3uPdlME.0pHO_/] xI>SRhUr4udfGڦP#I!} qc4W9dO<zz*/*uXbRqJIfrr})=i] {1/!'H>,JJiMX,\t4}1N_z&/':RhQMO=)y=h&y$旆4}h#\nxRu(>&S$bNOZ LBKFM&3( uBrђiA46O4@iŇJvq4 ֚g֞yJ07\sR,PTh^Eq4c8) x!PzR=h<)HKEHc[ J OJF\@c@POH04dp)TLaS z\!R3Alh.}'AqR1 zR'R8ʟ)Ҁ#`A8`vՇPqNS݈⺉Hj/\`zd1Ջ+u&0DZ~FY4e"pOQV$Yf?5Im wKvVd+sY̤Qa6(P6M*Ggݝ®"\IXDA\W;+ ?*{,A^>sH7$e,摇AڪE7dznwˎ=jsj{ͷI>ӡBD1r*dϕjE9U"$ZC3&G9_Hb7\S)H'@L*f1ɥw#p)x)9Z.%ϠPϴ)~Kg҂R#1R ,{UeiXƐH ӚB`cq1G#A+d!Q8p"+ݹTҕMFW(2;7JWC(ұjV1me,{U]OöCr,ouwqQ@_ZgBѧ,fpֽ[{mBݡeH?eӤ74=@|ϩ9jʓWc Cz}ψ85kp"e On6%5jђ .3NHΪ٦|L0VdPֹY0j҂P :WYN̎;UdE z\Xї-tө͹v!ULd85M ކ?>qڤy +(Qӵ#VA);W0!f&%nZ/T"ߑWodH|u?RZ jc{3^+ )9R6ع8*@wE9eSr6A$ty|͛p^%dLmG!F M1n vF)' 2EHN,i@@ ۡQ ǽZU%HuOF{ʥ&3. X1Ơ*7oD>\ ZLI r:3&O:ҏF0A"q\̳npvjXϖQb3n>n? ڱ1UOҴ8dhEJ'vjcpb$ӕFj x ʐ)cT@֤sؙ:rAyjH^ezUhV9/SGz!""iY^MHqb{:jC5RIؚ #׊{sYG7"f9ZdJT8C.NO\[ƚ7V`Yz) =B1Cܣo9h!ʡs#OL6`Z#Utu9*Xܖ`9qܴ0;i6+o4ocđOqzdž洙brgER:2G.-䌐sk'hjqR*)aW޹ha5-P~Tǭ4HP0 >䌳ޚP% N0C0$ T7@ 61UC!;y:?xc JleHnH'y\nDSeOo^r:T24e_r+>]P'R/]sJ̧a#QYc}⫞$`*D;ٔ7֢gw*M:F*rx!4}E8A_tPOP)VM٣+$T䳽ird+8 IN7v2jp+5K7O 9?JI$V!'_Hm˼R*27WD8{iEr9-: 8sn|f}>ZrIxraк͜Z1)#mO~76{V uo|W|)+) ;b1"EiKd׵.;p)eQ{W=MY5+{T_h'~4 aiu 9ۣsLM95FN)$$ќ)1֚Ī4 #&F6Җ|)Fb?J8\qLxf뷁Ґ qHb1bs I:PAn=hQpq9{ʿLH׮"R=hCʠn-R%(fRmsd=sSI^8KbEg1:wgޜxF2 M+Tsh"8⥷9ڏ7?51oP M%q!jFCIgwBeT$!tAG*nkDP9n~5SނG #m##50%q@P89[27V*A\ŌVqc^70*݊1#C:dE09[S$8+1a HfWgjA>l"RT$ւ)ꢮ*ZEMJ Ҍ:Y➣ wՎNRMljd8jĞ'GvB[ ZE׊OA O48ơc zsJrxXJNsWbl*lCj}d8"ט*E9֩ Þa\>c)@`F<`jp94M;b6F2*ݸ;VQ=;'nEMZÁ=)ĐGӃs@ )Ss)`x4oJ9&iA ւNi@ 'Hs:ӸOZ@xC[>z@ Wn4K89A4ւx(ڎOzp(z1i )9ɠ8 @$M S9"'DRpN4<ǑUqjxj`SZfy<݅Qy;qLB)3߽)3n40)0 @ QR\! J@aćb) xȤ1 01 Ҟ A*c `4b 2E.@7QD.)ci0ړiß ^w KA#cdà9t\n; ÿZӐOZasH^8=9{ PێqL@ H2z)p@sgڀL)Ȥ R2x(" uRPrMWv bp}|뺡DlMNڧrZG|1=5ͮ+dޡ`^" כkl}'4U.64m@˹&X tA"c^m`P$qWw ǞF+CKeTQvNHS<jM&hJNYnӽ8)4M8G8c")#&1sL/\rsڡJ-;q4L$ڦ 6gWT#Mv@B4'ҝE2DQ)@9P'JR}i3{P :g4ͧ4}h1)U=)֚ùM)PҀ";0䜊yM"]ߍK,$Gx,*Kt,`.}IE Ab{P9Q'I߭0mf*9N# q ґ>) lbyT2J\Ԣg+\t 3aҦFަϟk6GzVDbGu+lcW;G<W@z7O.y 7RiqeҾA{SA;4wcQp(8Ƞ*&fڞX #94ŤPwVmJZC|KidYVv45Ae֣tkZ[eֻ+y9#QYj~kztII/GM-:R i=A8WݮX21\tל] ZV&/a[yPmTF7ci`3EuL偭|eW2k҃9fʙ {ԆD0éF5Duȩ6hH8|$ !lU9g4KWS\u@^[:l1$tPB$J7.G R)1t ҘI$2)C($ ;`N=ݑjDpaHGQd;V@ɢ\F )@(oC-)bCJ2F=*pyd>Ө玔  $zSJf})$pPsN PsN)G\ O^($:q!!x'bYC( !+3\H_r5є25+52=:ۼhtIq *c w `fxΦQuUZڂX]5E$)F{֍r)}2ON*nMs֚Þ:fa$㚵$YR4$ !;y'4ĸW䞴Ờ JVr3NMDY۷b8R*tvqֲ<Մ4oC.xa5s)J%1{VPRkM;:Uj֦E,sU~b89@cC S3L,(3dS"m5{e^|WU#V]FM!i4tQ9 SKrp;Tۘ.w'>#$Ob:y#ʑ,dn@H-FVO1VZ=āfTR"*¹#BӷwZ|;aޮ:o+ƨVVL\7-V@2)v"\ne( "c$ZNdx ﴷH+18}keH3YTن8|A 9.~}+kY/-⤷uJו9{/ \O6[o9#Y?zC#*RKs.l .,y(OҧtlxGZah*n%v >3>{|0qA8ʉU$f;xOJvF Q}%v ֶF:҂1rhEẓ,+=+P*AWsN=ѕRF/sɯ,'Lq]0d Ǵ?cjb!xtxgq*5=c*Wgdtji:02H6iB0K=¨sڤWtFEg->YsZ >r1Xk\p+Nٰܿ_zi&u4y;(4kB"ہCd*ZWW}2Vg%+8:2^J5L slԭӒe7wcZjɳ`.I'MvQ(a5VG b);e&GCjAKd$\y c3E$N򂴊I$qO EaZӁDQ{8XfDRnȆW Fk!ۭ M*|zןZJkJ 9f)ܡW"2BbGQܹGB¥ȨKnO^&sȎ( )ZC`t^h<BNI!c3\Zx푊GN/j#sKr)zTeHݟuEW+ݭٕ3M`1Rgd~ ^9nH@ "Xc#9:Q@0)*B@pM+68a L~Gjxs b2|tO~PQH',h8WLRI 8\*A4;b]q4`3O  =i`<@9Ͻ(ϭ4s@'1Ȭ(i|kSSPȎ6?=fh][ȭp%o*qc]IZ;UwPˁW@+[EGvKMtXmsNݑLȮMdM< LzAަe#Lo~`6)vqM۵zPch4le0s@+#$epցGC.[*G~~^{oZْhKMBF( 1?oACVzm:tXVwZ 췦A{#?7NtEUr95[E||[1nHvEІ럭BFzb." Yw6A"qLBjz2'!NiO [H@qRM0!H4[<9#qZ #(zR8z\ P+*;iR`i1@\'"cp怹ލ=)xPy@\Um6{DQyY͙Vǵ.)H`7"(bw 0y9悛9'S " H%͍+pjLfsOA,0JR PbNȠry42n\AJh|c1TRP9:PNO@ ;sQnsI)c )Awt@ 1Rthn 3Lb{Rb:Qv'{p@۱+b`jUsjP1A"pO#0'*&n€^(R=((8 &)( pXtBqO#+P\P4L2x]4Jya8a֌QϭD@#9 -" >QImzdQQ۶p̀i\~4zh㎴UzQFs@!2H9">cdc4փ`fm.h;8斔(g()Jq֐1Sw8zw#\y7}i;jy 4rب\c#֞Ȧ@ /Mځ\VC皵5mOz{BhwF=)+1䒾A'8V# C~Uڹ PsN)Y~@OZE,sQp)UN)@qK!ޔy4;AGM A4zUg  [ j1n.-Iqȸ8zb4$qEvCX(=ju$ 5>06OTϧjBshwILGlJU=in4x46ӷ4Ói%G4qj#=&F0)X0`dwv;WiGN:*`LQʝi1AIzp; aGLB8ү&H|4pIy?5.sM+=)fѻEsKӃ@!k%[?fMzWy`P$jL\ZU4F3Fў)ns)⥻=rAֳlJلԁíGnLce@?sB~qy銀V cj;)P0l.r)IXgsֳ|Ev:sI38[5m@23\5ΝrZUZ괽n&`%#-*ナLpўog yM')*$NFCx^0&s¨KJC1Rk NAl#W.QX1ih՛=3Zyu 9ڃ9(ػ%ߒjʿj gơ=a jF޷rjsijo0(&DFU#n]ɤl]^3n\.}W|4ogrkmұݞh[b]bl^軘To4`r+~#NzĴ#r` 0<޸jnv4,OCQ܂pW!D\yV/bظ<&sk_C H UL9LRpgw)6VYȯZVڴQ W&Xסp8\馺4 Lw3[@n 4؝V85:i#)w3Θ-ٜsH 0yP9 [%bTz9[UIhYǀ?3G/CN*p*$;{xsX(݁AlD6AR:?[;pb[Xfmv f{w*&#%0}1jQPvSH873sA-YSҘ˻# ձyqO1]c>#U8皁W,*ȓ# hD sdjd6'B*t~so8k$ FjgtsvrA!=m \[4gkʘҥzu.3)Ӕ1b{ E6DO4-֜␓b6/j@ M 0շHSt&<bAMZ2ҡvج%¨RϚtQn(M-c< E/4Km>+Ƞlٮ_Jn2zJ ƴlI0#4bz~b2RGSЋ45Z?G]Oko"?3{;]YOvf'9ib]͛9.ʍ~^wh;H"Ȁޱ*[P3==F)#dZvY\w9꾕B$q^ތtz%TBICoQֶ*}+ӥ>h|!`Z2<ՕZǙ0dg}+Ygp89_HЬrqV`BE6hCFަuKYD(~l[gֹ}I]Im %yWdINϹT4^J6kn0FfJW9M$%! eQovFWجѕ\ЌQ'$X8TP=<pB#f+hY I#VbkP|FV;0*xN<~rN6:B?83N.@XӔVƗ z` i'p"D@$W7=*9ju`yc Ŝ7wA vj>iŜ=DOJ82g8נK J8uMX:)UiP8Bjw \R:$I#ҚwHwu(UO dG`>e9F( irM2Xt:0hg(b:>b1Spiv@A sLevrM7wjpc8=ifOuh(,,{jʐUv6 9 $ƅz5lrH+/LcH88"WRA9JW 48@,xjP1# GOJ~F 5y8hi[ #Mt]qHfl14Ƈ!@Rb#p Ҟ4ov ҬG^(ZRIL1*Lq c\ $xf uQ9 +#OD٨s*E 悬X6xPyI$b8 (iJ^pHHNA%~1iNL^[P sKL ӥavi@ \Hy8udn7#UMeRƝ 8Cur'i#zQ \nẔ(c@ y% AČ4pxFS*# Y;2 /"!b~cڜvbH mٰ[QgrpihANFh LVH<Ses8H|95 u9L~NE 9 ؝@ݟZ<*9>c ɧ.vi;5DP0iF OW ޤc'ޜ ׊b.FъdWqHO )wavpLD2˵"fg,:oP4ʰs)7+;S ۜ*pz}|-A4M(6S s֚@41iq4HʶFy/2}j܌+ wI#U\[8\9@ݍHX\2Gn".X&eI tu]b"\V&Mr*ɳ빏Fȿ'uVgL1C椻hJ~›GΡ; $)i@Yl Ct_H+05!zf{2@\zv289FJbw{7rGJK UčDAG0zԛ)%<cԩx#y9 {SܣD 9P3)a%']oDF3W-q#͉Ջ69U *r*FW!y]RfQ8iQ(W^3֫h %Q[J*ەg':m`YvWC2x)m,UȕZCVԨj9J5 7B SA&]FkK,mti{WG"9S]QR܉!NswDTvk@ =x4[yStJuJZ0'ZcȦRv}*rI+ ZhKnL ֥ 6Ulb53&rJoڬMrn]Ԅi)PzCJBA8# c$M彪O$xL\[=(sqPF.8@RGq,HL ;RE8>nh6O@ETm"1֤Cm-A-P@ +O<ՇZ%B lghT8pz ަ O42G4 !9OJ0EB0ԈP =985HGNMQN1RLRrhcBz i2vNhme`@) Ig洵k{5#C=JQ=9"Ev!8\2rRGXgdLk! wҫ9Ā犣r6Ror[W}cW#pHE2#uZ]8-ѨVĸE8gFNsLnB3-v xUR ܄0;3ҿ=i2rue$#L"?b¤ojxۄ}&Wh֥¯%3>q֬Gzei=yzr%]Bl8d`ARFW;i23ip(.AMSlQ;a4Y>`01Nc,-ۥFE+Q9TF>]c߁Ȧ)ņyx-V?Q!g /,pHOS|ʣ8&>dUn# wa~ VpGDRQ㞔1\. 9;U,2GN0`PڮGzaJ<sj&T:сmf~qJRD9qWJ@kU#t | _j'nU`k"+d9lzURTUsJF:qDy&cU$TdmcZĨ8ϭfYsۊx2FJLV_EVz 85RSßJ,LdA0ɡCU|dh'vZBHɠ#Mc=MCy~Zf@i/F)>d/B;Q8PKxJ,iG֠0,X`QqjNTB+v,LY Blc+Ρu!f)3\%#zTJ:}N5 trsH;ֱzN@CdU$v0Bv;hr99JVe P{tKVo^z3g+7-NI] DRXd4ڃ@!l%Y%B@<`qGQ(5t( gkգA,|¸ɬM/ݶ$ciEV52kX:HÒٓ+2k3XJfϜzTpʞfPzv,7tP[0X=Q@ZDhnc-Lǥ7*0 E-H2\Xj- QWK;T4=#ZpiIYԱڶTW=jǚ݁F1Mgyt6 :`Ӈ_3 7m0 =++zV?5k9YI"':8 CHG"Ni؃8"<X=KjÀ:RQNaCwgE/aB{P:3 94 Ĝv41`>/ٌҹvHI1iide-ޮizTE!.9lqSn"G1,fFHN:сv@XX S ;Z)2nCH*(OݠS5+&G4e @#(ێ悈E"ILznrF@˝p$fTcLA20z"dNp} as˸nm$OJGV1}/"pjXKomJ]^WEќK`BG\Vz zoN }hG) !sMLgE PҌ|܎(#=(v1MsԌ=1FN:RG4dS\s L7pSLirhfE#n'*7VT?xa\H!eUJXT'^YZ |R;ĺ?dw=k F^$ê,+ִ]M5<1lVvM?y&zJˀA+TcN>84U<ҁnp&y4P)H! PdO Z]ؠh&sږg8 杁M#@8cR-)4 a84dVmpiGSQO9 :ci{ӏQ5&Ìv< eU}(GF+w v*O$*~ >Vx:'#ڱme̋mgCPn*Ln0 QI l>SIn?Zgp0)Q khWЎ>={){WE&:Re(ː;TtFdv a"2#:\[O,`U;jmܕY ja%j%çʧz:m$JdYґgP9M5CszSRk TL!ԭM")ʬIA gl H~^:BQzQO;o|c I#41Q9{t8ۚLdM0 ?Hϥ\c&A9Jq@ 8v3ғqc QS}ӎ)E ٠(q֛⟞ƣ&L+nƐb]08iv4៵H$RW 뚭ZV Ͻfr@&/Uئfg'\`\o2Dh~]WքSh}:C=1RqZlnpޅmujL]p*zżةibX"nڳrLΫOn) zԚ8S߻Q+ mˌS `d F))q"M43aL,OzL/z[02vjQj- PW3n9QgO#ڜZ.4jk0錓H䞕 +6OϽE]D̼皠0ۈ9r,׽VppT3֦ 9`y)d)p{T! pګIqZlUJiji2ahi_(;Vԑ9~+>K@J=R+ 'Wm'k=#=O R<Š:ոFbtjM6aiJ&3f%$"].hѓ#[n8zAHQ ` v'Zϰ4,cyV84y8@ޡE;\eG+&JtbƤf^$)jYKh6f䶻,kDd5lSWdu5nՙY+;=+I$ǥhRaa*T[oZ8$ԪIQ9Q$T#O{}Å;Rӱɺbù<PzfWCa^Q_JV^k╋kӤP̅te*ge-:5t麛JϲQUA|rƖUBXl{֫ }Ezb:oS4yLOunpj,W(cX kA0+J#16$qTmQgіtuĊ kTJ^M; "12w8Jѳ}] fUΆ1)O"08cٯA;\װX%Ekg#7+1oI#a}+g#M7- EEq#Ks$ 찅 ~cڲ^ic4 eH";݂c)+H>6͐b#Zuҡ IֵG&duuh+ dxQlm励/u6_wjZͻ) 9Z2$(Z!c^5vInTu?Kj5kMm;s5'pp*Lk˪=+V[7;fiI*7b?`G}c.nA?Zw3-~5^BBQ*̹ =hlщ aڵNwX`3Zv72K6 m6P հA{785Q.Yy]6acV9vWw=R R9~ORG4g;T'rZYRqLP6zr~7aJo`- pE1 i8 g P!0E(8R46; LFn3gɣiiqޑhGC@sJ:{PF1@F{#0:ng8s&<ך,4``d}h)!%t4XQU'<IhX,q|rH9R3nnMb񎔤94 =y6F1@$0IydER1H}( QZ]MT PKxMqSS34 h91gӊp> zQISԀ99Dc@4>3()IQvrrhx "(iM6(g5!qHG^)VN;UfPTڮȹSUHf_Ydq!iOXǙjv+~@0`PdZzVn:P!O_`-׊@dciށ-r:C}G=qXvF)*AECb20x+}i@9n刖4` p:RHZ4_#P\ݹ\`խ9Iv4 ẊoɐkkNOoJdcRk`X3փxuj2w5:3Hen1X7pY …#F!A}luyۂ𒫞G^%PgXyR1 I2MlzV+;EǚHjiNf_MV$p}+<=TEx,{e8_JP0q.sސG= G\LN+sHXS7JFq@UeSi# sJ)'9 O*s@/ʸwzfi`rΠf18c?7qTTnNJ5;v֟++-iVԆFazt|ÃՆœp޵ZGQo֕i+JCDD.Z}ʹ4rMk9vOLB7I8jkGq5cPzυϓ~»"2yeaIA'JJ:d){ uXz C0s@8d`XTZ-𝸮u=G pRǒC^:uC+~)p"K w\ٞmj 7ګ'M OҰ88f )Q49h)攅'< Plz,+ QF2h;"-YUT!@Ht*8HBD2h||3BQɯ ?+k6mBeNlUpPlmJc'"3UD8lO[՗VR}ȃs jjWrzU<dӥNYsVEna$ރڦ# dHh\9PrӦQOڅ1 3dGwg>TRC̗P9${rj _Zg99NV||\qeChNGlxloim4r-17~5v?\+#+ȑҼBpL$LVW `fܛI}1HM=tћo0:u@rqɮep`k7'rO=( )Sޑ,zf 3MI(rriC@ e 0)iZI"ZTOz`3)v_zs$ s*t{TNlFnMX89nB3:PFiFFK~ c@,M!P@g4Gw*H԰,i ()ӵ!YG(#UHRIi%i F=)2h##4rpqQ2`Z Q%Re&aj1,F.euET$]ާ#MrWvHɮynzT]lZ0'ط@X5jBF=kb݌u:ŴALe`楌>9[#DE"H liN6iӱ`t@@R)Q4q@4sҝE,/ Qހ# 2󨤖;h3oJyDc1q',͞ K7'k"jA 4dت ;=+;u)l+yknlzcE/1}iQԨ`1ӜP]#ns.-Š -cԺ] Ӵc4Ф:( jPI9>$JΙ-jR2FK4)vxM'4p Z@4vE(TdR|*Sң 8I5HOQ6RGҌsJp ƚo|Իw >\w+R7fS<曰ցs@7R=i4E)I׏J]0dr B1@Fp8InS#jmCd,## iZ\W6M쪶%j|fZ_-++CxnBDW 楌pwi 'n_;Ac֜N[n#''Pd!pnxF[c>2Q0A Z~ў D cNSfL>RJ phZp)94@ !H3Zi) zvp 3=*ց'#M)L5Nk7W|Ci0:苾}(5"r"UZ9 ZO늖z1#m\s"Hy5ks44_9PrG M_X3LT&$QdQ9iZFN*>gi8ܥR:hyB [<qӊNOjSuUn`H]sNlcӥ+d#y*Iȫ1HKHqQv!ecLM2ͳ:bs`gU$B qS` ̚'%`!ZYS#?Dy^9m#yiUGoZF5iU&^)V]KއQG 6?z{U{ݮɭFnra%Skqjh!W ,ZXLݹ0NMg15ue rᕺWvAj8} XX)p L&@ɃXiI!,9iKgRͩEՏ&5OZE6)p@ i ('RFJό5/(-'ֆm:MJ9=rzpEHsI ܱrjPq*{wsᰴI✦$㊙X z'4L HZdiL [hD$FAށ&щw>HjĹ슭]sކHr@cZQ<Qdt!H05Y$@5>lC'isIϐrqQ-R;/? WAws.X-1]rҪLsk1!ǥy${LPLG%>ΨWgj^// AR;u-Biŗjw2 9$Q>8tSl@ӅY{rbjY2d? 3*wR7H7@i2 |Ҵ >>R;IrH-a<wsTnUd;qWMoh#-+>\jBEp6585wHu H.NkjkvaMa5Pֺ{]<[ 9+sU Vilc5mr2Ij0Nԃ޽Udysa*MJ1qTs)l%.+5ړi-{i-*Qvo]\ϹҐ˓l,LVAI;{ 9|?ere&Hca\^jLc"[eI/'=AE:5w:iQ̈́#k;z$5ȧ9'B;jbDnx:(S%nCǽF;y$0aQEΛ|\PS/V2HܫLRFrئ'0H'Z\@; W'e$IQQe+h;@5xKk;&=⻦I!01ڲ[HSnښR4{V`zWcc|kgFzVx3*^c,,Ho6sKٜ`/R)IrcGCVM$IC A˾ReB^H,sMjTb 3J1k";`%Xz]f6kHDˌZaQ&+;CXm[\w{ 66k&2[d"gjvWGM\.'GBkZ)pn޹{LɦhCˮR5eځ{`}FR(jNؑr\➯֙Q=)ÜA{nLj3ކ=i)iQ4R2;P -ڜ0Mc@^ .A)#jLs8 'GT"RrO4S+ \ &N9"IiCzqA"? y0Fsh) {Swن2WbA52r{ b<Ԃ<&I枊Tn'40 rE=֌1@PG4 pxMy#<^h13e߅NTZ"Ce`.QR# +4HF)UӚdRvqEĶl/<ZUF~cxFrDFszԤ.@6\RR~aϭQ68`ӂ`i  s g4`bAC\ @r܏(,1AM|C1I2i7;"2x`ɤ]Anp'֦s&=iXK`t.3 {f88U3\!✧g4@)9;g4VxL5+Tey@Rsqpj<ށ j&h6!X^i@qFpqjJPI4H#oL@SIoJF|ԟ1NRZF()Hیf7}=듌ReeNFWz$ܚN 1b*grsɛg.xmfܑJ"횐F:>P9AˌNƷdmȠi!^j  O+KtcP{p K:iBuIftcViLBUy&=VdR $Y!wy549RHrZ7ы6F_Kθs皉zƝ6Df󞕱'<4-}--.Ě04ْ]ۊhhVgDlap"k|-ɹfxI+๊ !ЎZwEFr(!(zTюG;DFix`qO9ɰҝ)riP!sǽ'=SSG{ў(8iJFOZ= 13r)O#BIMՓ/I9cޣ&Zdw(?6ִX/љټ0)YF'3Nl+1M@95+06*sEܖQv*柪Oi"zySkpc`: +3TjI0¶kK<+]dRG,(XXyE8}i͹W4g4Xy&b/ 8 P@=F82iq1@ qNHiAcÕ|w@ iß0*N:R@ @rjQNGI_ZP d 5zRb& yzS2:ʰэӵ4 hI;х" 474\M!T秵'ӧ.bM7w!id&]ǨC"$~`gi8rl4GHbv PFpȯ/r7-Nmqq%nUiZy6H"(N(NdRdf xS?yaJȜv1|̈́wLeaֳ$ @џ\Xrz dhu9*ʐ0qTpaR*xʨ9|۸izSÜSrxgr->IHb0Tʑ T;؀8z @sO/Jd'a8N ҁ c/<m9@3Hr㞴Jӥ(-sAO֣bc`EH" xS&n2)J[JBHlk֤iǭJc֥Tdjkep8PsMnބ3Dpd J.u笛Fx\Cfb˚ez!OZt1ڜVv9T`.F)(Lf/P,$p) c2NW]ϖW4ŖqvF* cab;>|GOۆbk9%_SGR*ҔlSϥ#kM2;ێ=)rI<)E928+46?Ji6 Ky\(RQI=h  3#qM%Tz02q˨Y=HÓZ"윚3"pj$blZfL14I3lЌP#$nB#qBI'C%8w3![ )''& g4+ Hws@o_1c=+<9eKcsc5,L+Rz1D] NIK.o Լ,h*ă\KnaK+eSfϙ)ZoRs81  =ќeV"I r,0ʑvNxZE<9c!G45W O`Cg64@; A9O@dHiz=鼂Eu4J)\A'L4/" Rlw@Rj|S1vZmܰR0;T֨͒i@ɦc&d#mܚim[ &l:oڂBT5w3/LO]Rk,<f #hMzLg#q?Z&.\(O9X*j5]engUn  }TFLt`ǁXf@răjv|XbSB@O=)=GpO/ܤQ1;O'8;$" +NgڑBzi!h8((A%ڡUlP&JO;sڌ=($cp)xIH[qP18xԪ\vlj̛@h\XÒhPLeS/OY8V]z:ŠE&W @# $НjYl!؄!ҢQ# 1p*<ȉI'5,RE@uBx?J4EUdAՈ`qJjZ&ڣZQNP=~JCDhޥC%qaF: (ѝΛEyW#8V#v\r*r+h6"$p =URdf -֜xLQqւE'4)C {qJ2Fos I2yu08权nh;'ifI9)/J8$桕(,q@,rU5.}զ&&:D;OkZA:uǙ\- X?QPCڎcWA#uoEJrT2:b#1L!U.5 g#S).cFqq޲=I#=2mlOfZe<3Dv\@;Tኞ}k1u{fW)ΗTdmSFő&؎n1Vcg}DG\֑"vL}]'vuF @ Cwj5\3Bf0|c 3OnIMZ+٭(X~sTq;.f9$mJ3hzR7u8 ☇c/C ҂ߕ'hIRFh ԆS4 i5=i;$R+Ahew4KXX#C޹DBQ-PjO]ySU`Hwe=JycõcocZ; jloSڄmdsWA12&JG#=롼dhdʌs&E#qGN>E"awVRVf `qڴ-e&hcΎI91*w\zŶWjw5mvЙR6-*T iAjx#$1#8 3X#D9j=@Vl fd2vEŒQ VG[ˤsU`zS F5ж5"EFYyb@c4yoP;$ M J(ԳViь/lTkj!2HCzT 'J)B$`|y5aB|?#+S2 >B؍@,R{/ 3bpsCdf(4XSpOz 9dbn5P9ޑ :T1 %di2l`֕#\@o+(f)*s09LwVVD s"s/i2R ws r"UciUsՏ+u#" (h^NFh +0'm5ySn)SH\k8`qQ0+g3JʽK)TfIp9 kZD#*S:Vm6S}crc %F3ҎW=%*%vShqȤ_41Hxœ *S7ny\O'<F9 4{A!x%I> hZvF3L@IRP+84` {naq]0:)ESsEb\)KJ0zN?PIcjxDN9PiU3؁s׵FOOl9 ސ7A֛S=ΟmTA2fU?Z8=_,(^jv#gZgإ3ךI+~JUëF7[{v*d 4'kke8@zzӭTUHӖƅgu;dJo!V8eۖG ^~)yTg#n% z#s!#FOcU1XZ*K.8"}Y+ #0&vP~TZʼ6}KX8h裌E/{ DB d 9KeGjzb$qֳ/.&J}į)GOQ9H ,p}FAtp|i)Z W2*RƬFޘpD5C6- me[)d"U!ryjF_)3 қ4"^HP 34p"l~\K6ҧ[xx{ұ~_*?Zl5փqr WhD? NU#89<Ԁ| yHmc#6r=$#£ p 5b4  9jeNOd082"kF>,ജ{P6N0*BW`ɠLULR8}}) S!v!p: U2y4.@Ӕq҂$ۀsޑBnzS<PKbG4R: 8`nt(48Ib_z!RgI11@'`K hKPx=(=届)b Y,{ .Ccm ȤEVj'=Jl!u\`]*qX 5bUc:pwlhIw0AFҒ[5ӺM_]b>i)̫͠Tcbgg4&G4"R+=7v"SIyr;mr*Eت$aКv(h[i9*’әe#p=I jԥ%1ԢӐw iV)ٔu;1DocؚهO &Br܉U+כdqN[}"Lmؘ"*yhcMi^iA1+ wk>ýML"Jqr Nŗby)zW#ػ$a#P1>^YLב &k*0q]Te1l0)}Yz{v܀)UD#vk]Aݜii[,TY.M:0 |v<ʋhpHܵ>4UOKC-*(;h֩\ɱ5yvn"94ԁCh=yѵO19'U$5?½]гcI;@kVMVLr_|iyBD$?C`: dPC^4~ipϐ:UvKzSx.jO+߾RO*gNu^6r85K3\$1W4Qk{XaKAlc8F+ɼ9Ieȹy8yXe`1ҠKg2dxg0 s˳8][LxuK uSU{bhhSK22,O9G,nP =ބh'inȤVÓ)a]wiʬPwcJp@4ɱ/=qJQiN8玼Z71$݊b9 bGJq p{b7QO 3Q@ lmJG Jn zP8A`ܚ+ v$TJNqRM=@wpiOw) {< 8'Z" A⼶XXI'2coGZ$P#hc~ZC֜ ݩda8jRwO59 @16yajPF *6L0$OD*3RoV͡XqH(40b(lS y4 柵zr4;ǵ;@4H!R6Ҽ6vfRWd$PN\NrA-+Svpۏp;V,;p6ڃ[%_<gMXP7LFô}n#hDRǡ=ڒ ҉7kuŖFW9ٙ6z(E`J1ݝ`(ݲHVf(`wZV?y*09Cdo5P+Z,I RMXhσ&Rs*bc'2r;Tm5.5hx"X#-Q ۅ$PvsD9>`b&99ӶRr801ALAU,h9[1@ *ȧ'fvbhH4,67p `Q9B>1JWZcg4?ZyYBpGsWH< YѸcst+ʌ3V 8=8+1IٻRdqM#w 9`Z)FzS *^0sڣ;sN@2‘֗q.SM9)ŠaדB4`)[ڂ'"@#1C IZyL})8R!i{S p4Ctu@ BqܟJ)03nǵUfܫ0 -XSa&@3Yha9N0L^R"N\h #41O Prg.EluV%ݞM&~o2cL',LXM3֠$Ӕ gaɦHKL ғ-!7JK"EQ"{OȵT I#IR,Ơ 皗d2fF,VL$ti@"sHuN~)p!osL()ʐMaѿ85(%x'RftpGJu(LMB$U;}ZbFN*A kGa2 Ȍn`vcRF\;SSoB34dN⟟Ƌ;P&HOʑ RlP}# 1́ȦL*njC"+CcҦ*N~R*(Je*ʢE؞vc. K-I]JfSqL* 5x}UZ"yn7};R)Iƨ#. :}E\ ^LhHsHB3"wBc!8JX(NIlG+YLְ `p tP̲^;WV DdFtw^"nH閫Sm'(Њh%m^C\m .XJ=JpʇTٲN[̇* s.CGNF;A K.>j֗"bK jw'\z׶s)pJ&C(VpH9pe[kyOZ6yvt#|0XVQL-|k=9`Vݗa~cǑe s0n_zv0#)"\{) x W^rlY)<ϡ“֍Ǹ5ͦ`ǜ)Km4XFH7|FqVzjHFOHpOz,ft0A5ejȭOtJB[Y/z(Z:nqLxp>ҹ2ԣ%0] wj++q 1pq޴PrNޅ(,mˬ*S*R'8n1ckm 늉#qX=)6yZ,.bA@_?ʭ1Lc$E1Eu(E]h3f4J4W8O岂r|zlC暪J4r32MHFwU]J>w5c9Ašvhu?\Z[m?XRH?Wq*{ռ7i۰P"z{cHOF`CXi,!)^pyWͣBu {WzjjHySN̊Ѻ|󒻪֥58$M(\M9S%┮qL8 $RzSOn)3q9;!sKq@>S(?vK@)2sJx1h# N eGc.r(sbm\枀CNҪp;HM޼u1{ץƤ68Q^cq9~A҅f2Sҷ='" +ݫBadkT&8ʚtNj%;+PzV6֜cnӊ49gR" PlԀ:P] f}=iH}^zByE |6q֘gi1`qN-A b߼W1=i GW'|LZN84RFnd|U{b!\OB+C^TgvTӦ>ooz0QiN[9$SDQˏ4\E㊑؝\j=Jh7xjŎcƠq]LsPgSb 8 Կ+n}*0q3̩lҗm3ekknKOeWvlmiky2oxޣo0wc31*41n5=Dr:U{Q% IZ"쨤#n>,Y+ 0ij/5z&yRGIlf0** UmjHj;ʑ-ʚl4P~;JԐk*:V 1/Κ[qR;;r#J6 FVE23ɨT#i*9&I̊YO5,pJp>SPJ9;sq";EhR(.7OϴmFk/$n2DÞ~# *Ha<֔,o @;(9qWCAɆpsҥb܁ҙ8RJ^s50a fM 2)@12v]$m!HQ}\XU9jD 2Z-ߕk>h YryN8vQ?/\*˿Zs۲eUR0S֑w)vQ{ I]|Yf!UNH<qִ"`TVhoZy|3ҋ\{ *\fv`Qf\IF@ )^*9-qXLIJ\tv=(BwPsvCVSׯ5l8 h)CZ}–4iqwj+,C/fbʥ%_/HѷԎ,c9ani0 sS%2eNH`P'8G*@_a,A`枹n1FdR;4ت@*`)xDj$fKiAE)0m\Ҝɨ98jef `] TkP@GzvpxA (`nB@Pz^ԪwR14JsF>jCK֌(r!U2F:[R[$ -wZĈEHYTe*96ނ矻F>VmoT7>s); ii6t:%$t-ƫ0H5 %Ö'O]Cifh5ti.[!j-ڲ[>܀zsLq0 .6wsҗ#R}# Nت]T\;/1FFi pϸ+sO]IQ.?(<`\ip:UW?7j"vRݾƳ?ciy<jѵNGLpZ 5IAUe"J Eecir40Q`"ag5x~ LN{b%#dWx"o( )ltabcIq7 tP@-TtO)K:2=bŖyL)*Չ#20p=)LӸX6Ct;̀TNE%-8cc3V6ݍh6wq~@\cYۛ UKC{q& Z2CV!$jHV:sIc9[Vũ,6 fB959V"7zhwnPGqPuz83lH8ڹUy,I-dڠOFIyy>|$Hw+ !|eUfdub /Veثg+DKQ;Xigp8(1YJ=iZĢ)7\ :3Ed(,t߳ۏWW@<@ؠpOdHn95*m##=kN=F9 GpXvkF29(S,7_4>jxȖ=D0M?9s?dI.&[V>!U@C8"1Hة|P̹SZ/c0Td.LգZ2k/4 |3jq!lO#<-# .gZ3ȣo/Q~axlzH$V Ҝ'9U8!8c= )tu@ n n0}i1M`y}Sɦ2{SH$x9)0u)18uCTұVjW9ɠ04'P1p)Np*`ÿmjّ*Y sWlhEM*` z͛{Ҁ *\sJ~SI#j6WjSqi1M.JErqQqڀ9 I,i8[hC6C=)6d {;PP^1JF9ƞ 9#c*9eHbi(ϽbRsy g',F殙 CVbg<Ȃ(bu";TE ӊhgZ@à4̉8N)N mvL@vȣ f8 LnR$2#tD 2 |{Te|b\)RI9j32EiL"-z{֪VE,N*P0@jAqEF˂=sRw#Icy2&'ҏ\LT11JpAfOaV^iLhT+MS WB) 9Uhtb)H*! Bq750'4PsRSH+*)R5#wt/SHH`t$yNN~zR2T!-h)2ɸ1٧-q!p}ȷ`}*]H\`TTinP嗹54lH+xʆ;VUëwz.[,\ډ!swVdfީ8rJmw ;} ]kpO;TRLZ\n54r]ۘp:[ Vɥv ]!igsZ) TY/k$kegQRɝ1&B{Ԓ w @{33dky^效Z-l2 w0ޅAVԮa^:%,߭]2,Q@b=b`y&׷<EZkT(0MGw4\;*WKyQ{d|#Ь%)4#pS0 Qi`)G1Q>n0>3g" C)CrIN<&VIJԔ8ȥ?()84 ʹRx=Bd[I7*g!:T\hdd S9,0)Zmq. SRphd`z$=M,ګ6da BkPB5jm>] 37&<.]yw?^xIF:St^AF8^&nwk DޥEV,wzWHP(Y Dyӛ$SJBO X$fͱAZa1@tNګN܄&iHR;q`]T P Mݤ* rCҜ"Lڔ;EVxx#)nqVB'.Tm+r*i{܀(lojqSHo(j\1րR{xnh_#5o`%þ?r݇j$ <$|044KhȭnACy&N\ݽՌl`8[Hn"ƅ+n9S6C#U|0㱩~=UsOG* "1lJIۚdf4` OJQy/Z^Ґu7Zh8qHqS[j9/Z!^M<8`Gi@#jJ"Ql\a`A)>uwmk*v)lc֋ Yt= ȣlJ k- F szqkX1V7hϊU(X K 7ݪaIP3ڙ*FF iŀ&m2@pyj|}j~PqA!'TnXI>cRg`qJ]ڭcUuRKSb.ic+NH8BwghܖL@XxI=גrzг{]>8US ^j8j֜:ú|*^YDBǡRx?cqXLI#oznTQCnmsYD$sQWEf;Vt[9WjO)8\PiVEEu赩G>#]:w5W%$s46UnHv.v+KLjuQ>;v{VS=:45sf(rBiJ:jJõVΐ97/Œ@i#'%1qLero3<F9PXTyaw 4GO= ,ԨDs dj_6]峚@Gm"lyaw 0"v'w7MK-Փz2mU¬6*a8e6[qJĹXyIV5ov@wucQ#ī|(E_'ˑ0Tztn+R-24_޶OZ:żrk5y䜼8#@ғC\h,ab.1v*V&r&a1V FƺnIQ=Qx81 gytX3ڜq=j.fam$J3ך.瞔ǔHC%VGxzYXDOw9<JR*ARRąq\0Vq',x]v,$LжyZǖh&$W,(^2,]ME|RePPtqƫx޻4,Xr;V31eǒy=&QELS%ZrpN =륷m~5_OXw;F8։Μ^%E[2KgWIYOk-86NIr\z -Ծy,]{[X1Ja8.TsK6F%%|8+rO Au=*4`VM3(dÈD * cxaf ZwHW9M2,U%D"%\i`G< `O86n⪦~oAR[>Mh;SKˢ`|аIukfK:s,yq^5Թ@Qc8+)ߘ p{P8@ABzzÎj> :S+ҁ2\r' rZ)A9ݑSr׊ 5|$fނǯm, 9NiŒ"3&lǁSH88aLoph,;v֤b@?Lߎ=)TLd\MI67mvɯ y#K"1ۡ~x5ӽhFjJWv8|%|+jZU ^:tO6YҺ8#ǥ5&Qy-Xs&D5s mM#29=Ϟ'#бb qp6ֽÖwAI2 )ɄKMtqQgHݐz I00+Ky!Ibv3Hjm]AVIa!ʲ\fe; j8ـB#Ɩ.FPT5H\6sY^"vr霊iٕK{Z rk/*\hU̡H9~HKsW-%N6 vGZ6݁9#'%MzF3Ҏs f}zQڑJ R0bx)1PX#N@K{P<VP08BevԻGQQnAhryh /$R4z 8Ec4m{5K, &ܝE6: cpi\$1Kw.3#4&wcTUn}*NF0=O͎Won+ZksTM#R0N9L5>gi8cR͒zW̬qT1U'*s҃)lNA&b@g T1f 本BgQ8 }j7GsQ'""QRBt=WvG^-" N4{`TMi3*9f;nf=*Inۖ-UH4J%D$Pw m@͌JC*K`zT9v8?-Aw9jnt(_r"jDF۹+=atUA>ޔFImv48NTevCg=DĞxUƐQnX8t.VH[jm`_w c) QpQbTe{R #ZW-DRiӚ3&gĀ1n0Y)\&gZ+eܜ6W=jMbG8>`cC$O>Z=G"4Q&@ib15AVI XgW*`b076nGz{6B3ѐ@LT+0$e"nm>y8LҬ(sMwO"Eu!vɊ$ڥsU3&qRBŕ׊Bhv@;(ڽ, _;ՔfAއV9.J5?ኆB ¬$| >`*YL{ѾF 򂼊h 9Vz}+1a~]Q5%$5єRDJt18,zLinZq @Gb7̑S$ ySQҜcsʟ[riDdrǹRAްdR+2 (Xc*J<g{⣽X7ߴwvi oc>e2BR5eUPtـQ"˶x;܃y@{5kADVOz"+JE&4>'֧Rp@?JY Φ)!P6{QTH*ݺRnKiؗq*~UcVW F5ߟJVf&= $乓x^[Fj{&X-1UΣp"K!޽[]׬:7֍$jʴ$HRDėFf-:UWiE1W0\eAG&6YYU&e%bhF3<xUe)qā\| tK ;f gw#.猊U} I)N$fϵ5X֟xH@;Ӳ Ps3.s8iIRF{@iO)hA\)@=G41q@ /'֤o% :C q!9$b(uf=xl8SRѭ96Xk)P:0` ՟ k-z:[Rk-C"5pEE7j-EKg=ph_֨Zn1Zsqa}:MŇ#MQc!R1@MR :S2zT+{T[ g<$JU 8r\3=*U{T84neeXda\ͤ`8Lں襎tW֘NUIgP K&Ѵ:F'#L,xGUISL_`%=kְwlۂf"_ȃA)XJb@?7wPZ֑R;dVԫWҭF.S2 ֑7,bi;[/ʢcW >~vdB徤~qEÃh@iIIH=E?]jl7X86 xhmf]˙n6HN)6a! (If J7SZ:+sLx0.ƖK 'l "}";F֘!iN㚱d՘txu+65 zՆ.g(#KlClkuc欉Ю;uN&qc7uStqJU}3N1T#[@5{ỘѺԋr1FrQ%5,y@QX>e N6UAD1Vl6I>i*Y\8Gݿ#]OLұAE[YGN*hTH71"eOZQ)zNP"" kĤ'Qc F;R&6'Ou=2L8'5#֘O|GCsޚrih&G qV8$*S9oX\+Z 7m! ֩[R2Qsu3aW?pw˦J4OjrxC@"18h1ip 8Izdr)TsL Htd7\b`qҍ31-dP:M(<P g[AI c$(6qMc@'͕ڣI;h AV%3Mߐp97p*9Q yrT*̊x^j114l敾a0PȦ;sO8(}-˷RT ̊y9aA!ا=;PhD5$:ƣ1V+ )\ĥ <gMwrh[*.|I) Bk3FjZ]\+SHT#f͢4|ic;ZF}BzYoQ0 <';$e;naRs j.S^8gPNBE;;x1h<RlP#`g}(ϕsW<(&om elx|v)ǙQDAiq\ρ&\yRiQݤbE*偪!B u4%'9qi|6) ڙojdMl`qIJa 4#h& <۳?i_U#L}+XEowåXbǽx {&;U&1s @$ 1Yd|s֐W'=jV 9Ң#UHwT@Z4}H1FuS0E.OD,=F R@?x! 45ҁ A81ёө4 ڔlm!>N Nlcy58XހHl@]L!Y 1Y'1WasV;@sK)j" _kWRy%!P٪g`p͒ERGD%aÜmEeeҖ U-v` ZB :UC 8{kRx#~cJ .R= P!&V[.k9 +eѤer TوHlg]f##\`6tVx\K3Ke[Bi uaFKrI=M=|̃m&5b™2qVXG=*Y6ҿO0cҐńy$L}$@j3vU,>D͖s1Q0=j%tfM:bhhLSR0*EbAUlLHv_ޡmL%*\Nj)3)L1'ie d7n5ӔI+f8MáQU$r3?5d@fDe/v6fyfL lMDZZڋ d$v/a+jH*=i&`1 2w#6`C) TS8==jTA})͒mqR*T8C.v|Ԍ``R_s\\nya_vGaO=E7 >rl[2w=OjiWX\bFq)1F'Lܒh#;F@>QЧx9uc3F)IUޑqȨ$?4#ۀ ι..:$k>p }shD)X9*a֤E9z.TmVrG7Ү_ʣ56 OdԂ3!JW:W K anw3&)ׯ4STBsIcw: fABzTȡЬIݢVxc3 feoJ%nG|uHU TqG/IvY@ZBqEr:UOkr੅9TdNVRSM~D&ZH2@S5<CM߻91xA)E{V`+3T9=*ݦC砨2M".ޜ1R75`+ H4*b qKOa9)8rj-Wt41@7|ݩA"! hN7M:yPfj!ҷJejN42<-K7+o`z m,1(c_!p7Jf L~aJ@?{%L^­0mwS!DK$柌< ,dgHYrb"2)MQ=h q3OFbx´mנԲ*=)X.F$%{ԜlRsR0 ؜m&@=)99X "p)l^;ONiG|y^)70M(`<!]ۆ3ҍ@ CZ\(!69!^8q0UO*/I&p42NiD=)u$)h^ą UO5nGɾ[*B`NV7L(X7QD!#ɫH~U\PփWEP8 VXe*ģIwҡb9㰤'ҨsF ~U:#iV噀n2^k 3oV<ԅP[ç֞U.q^;FѬ|;{qӧ{<UWŅXon`Fvd>U]`@)S\Cz|?nI`xqL]%cfnLGԝPާSƣ"Жm.V$ܧ9NVb= wqaU `jUm>c"f'(2hn#mƦ@ Ӣ\۹xF.4lz/y' 56)$Dj{,[!8ǥbIt& k n>e=]oSR33]d8<҆iu"f95sVM3M ܞveMs-MM1҂cj$c"H+drblbsiæNjoiR:Rx))#!R(¯l^H#.O烚8;ƪ=Oڗ !ɦ9FQI&ڽh 3"y# ;by@ ֣3*1,aBR hH4Oj`4Cbb1Pyl8RLfRyn &4`Aծ;d^xsEƕ4pJŢM,[${C+biڒgmpqyr3QK,08oR혁Wku1Vc882QcW䌃ȨXJD砤?53ŁI*~ZF988IfdِZ􈬘EU%v6Ptaݵ"XxD7t,A9\m4˔Zl'#%%Qrz<\ZyݎDǖ4'K l2&ERw)*#q+ߺ8&K6&8v&̳D{gr܈\av#vH=)kY<^*a%|7zrR)__J )ޒUˊٱIE-gyxWtKэtq ؀m86' T8qRaxSHS늻 QS橹ڌ[5/呴sR^A=#)\ɽHBsU*؎NBARS9;T%.1FzQ~4c#$4A8@iVAL<zy0xEb03>B7zHcfsķ 9QL;{խPw ҫP;i[]LC!ȦŐ30&GhՋ4WlZE&H`֮[;2G]ռha֢i$Okycpb0wa5DqԮpjd"wF84^*Kg\44H3 ђ~8Lt4tN+@ `0;EA xAH\IJҘ$inC)a&Ih`9';Җi 2MVi1Lٳ1ހP88cKT+@*ǓNfBUZUfW✡N qA>0 oޤAPCzP.@犓zS̅"%50090hyCX+zT3AV*((3HQ#15ZiNFq5Q@=jaqރKXr)" ޗ$ RrQ@Ջ9$ W8`@2ji,.D*k $Ujs?8P2MIЖ%8E1WӐ(%43vp)2@WU(s]|혨Iʎ܇7c Od&_d{pG$aq)c ]ګH_1p&6l2o8o#'bqz5A}CvVjsn1 ZGpUxUWdOuS)O<Q\Qq$__)CA6<ٌ@4 +`NDfH>!`gtmR2[!܌4XR }**NjEF%# l gM(< 6FIj(v=LܞV/"ֶm#Z\igygRxٷ9 ֫GlzuC uZsIe+}v}"h:"5&iI,{N; p!a$` tgDv=MTOB0OAJi3rIn%/{ҭ_&hNbBqNyÒ0zSZI期zF>k.2p1M )Mj O(fp)ia'=*r\O1Cqج.T!R37 VƲF 8Rj,M=JEТ>ީ[u9P{ֿR'h"5I#(ZB7՞~#E51A)rjGל᭏:!y4֗AA (' r8j]җ9@] t<@^)TcQt/J*1sP09lP4fǥJ7rvՑ}N Z:i82sED$c,38c5:\1>MuqAIGAzS9y :4-e_K5e*bbj8b+G',3iM6̥!Ж)ivmOPv>!Qj`99)0)qPHȤ*:^M(hF0?*lm!]G5yG2y5.(3kf4NHY7~. 1Kud# f6Z >3k?-u#yDgpeyLIdg}Kqr>U۞~R늚وb8Qȍ*V 4xt|4Aj }ÊE-rՕv7)zkVU_35"<у8 M0p<4&rå5yTFjQNܰ淃.î+H{ uhG +CJ$U;yz5{erdU`/Iߞ'!Y>I5[)0P bNvEyeTye3|%U8[(UT8HP{6X9O\ғwScQ0OW;*S\)P@2qIXt!㱢Q;XF[ggA$B R)&.I*֓ғ#h֜pN1N:!ڜ}i;Pَph?s(F}j';KQ'84ÂM&# Qg&ih#!R'QO5r4ޥHz*֌ ܊`#9()iu\!KHFW"HV!9HH uc{ueKzь'*+ᰵy8fTbވɤZ9pp>zV`qPjzڍѐn–+svǥ#EB7:h1O'֟w}]m<Kr{Rg:]X?'zJFJJ9R;ԍf,yYJɨ7 ݞL\H*,Vi8Y.HvqlLsZ&2v(Sv$ko #KøJɛ!6@$숄yr4҆:q@HF&C1SֵT* >JVrGjI'*g08^M&jrzw! >sV$r:(Py,%G M?ZҬL5h!T2HٌhFd|1;:$*@9隺! 桗kJܬW iu4ב*ymp]A7V>l%U@PdDNEkUܠ*38hMٔX-Χ"175aHSQBJ9⤫\3j9[p> U?YBV UPnSwj 44 0&_i2#)SiA@[,GI&3U xIXĈ9*{k,KM5 ΠBaw#9D՛ I50@{b>T*2ݽ)INcJz0qNڐ9) @ } 4ʢNCv)r& 09"NIHΜ⁌ qM8sޛ#=(7Phqhl Rrܛ dA jT0ƒdֳB7P=vZp=*ShhdK1P'CkvMfy*@9tӚ{u9n*EK(ϯ }kSk%mAٷOItV B ZK $ ^iXjiZL11y5Ƙ2l>ATNWgȥcUX}Jv?w硪1! =2uL =ңlSEZ0dxڙ YڔJq;Ԩ>_zy\`TL .UA0ŸBޜB0:QwSuw$qB`Rҡ-*F vj$vlDL (BĞ;S @=j9OTW XYiؓ-Ow8 4684㿥GL,8(799Mg%}y^i1Q*>^I3;HS=ךn[1$=h\')DmXt@QQ2ߊ3cF6>N`֫iNCUٚW1rZΫ~/QC:)Ϳ EE*\&&i.$.oo.\󪜂5QbvQc!1ҭE[RZ~ee "yA<PȮt[3 vuW%4LHjC Ż銔GSs䷯j-3w` M7>S9"e* 6n3JHmґw X``Q2Fc2@:T.Pc4UOV1orO0Xlq*[*0zP,d`D|zSQZ) ՠ)¸p?K T$.yJ7۟E,[ni 0 LUO_Zh¼{RX2*r#& Aʢ#dTF&PkyAh٘ZɌpkByM'$fŒ6SvR7U'zZ8b~1ҭ˷#4db\p)r15Xg$FsJHU#zcQ$:`Ke$8ǥ5 OqFNeR)!S_/idbd>bҹI("Z ʄ=i7EӸ;iB r):& ⌒P2xXԻ~~H1 O񏔂=kHQYbG@#rSkK hZ<=)ۏ4ȱ'EiX[i# L,Hgj=N1MʶO$:cF3y?+/Ǩ[Ɲ$R:"YЀ˴!F44BlHjdf r*6G O&SeɁ=*k{ %@Zrn:AT on܂i[&91( =jp. sIjLlP)!z u<~4 dQpGZQx"RfrxޘI3Aq:R3hg;@܊k/rsAIgR7); ɩaP4!_I nUo4Hqċs+󎵜3TwSWh/' bȏTwQEbH "Z3pP4%6 dAW_# 6 "(͗ Hpz $WVܿ|W9X#LO|ZR~HKfB.T7JRh'ii0l6H=3M %8oZ3ڑ0l=9ٺbϴ9QמE+\Gss*CVݪa~KN$^v@oVP"WeȪ@hܽAjSbDFF \GJw1hb M4sMb,>!Uc&mݼTHwP#K䝘 ]-ޠio3J}RI"Tʑx\:PeɩB"')L;E"4#)A#aB݁sӜ)\p8p|UmHCJ(e]Y@6R1[<;ʷPM"ϵ=G$IKQL];jKڿ7LV RrWٜYn$e1⫐w,k8!P5 ~/TX=+ ! -m+(+yRS~qdrh֠a9'Ȫ\*E)\3m]W%=*ă᨞1Z]we}Mz}Uf TKc( 6sުg!٧$YOOh#;֫C7r{B[9H,Wp++AݑVU%:JV25#=ju CdF)1=xuv/Z)5(5ZGe1Ro6Fj̪rw`*H܇9jwɑOqґ1`T-ړBUm+3Y=*p^j弶֪IXwC:SX&マj"`cL8{b"vh-is=l4+e q (=(1dŁhQKHrxdb$˜Eepx~bJKsGT:EMܨ-+Rbu SGUgX@X.W t1b<}iHc$U mgض㚸!QI2>o=O\5N6IwMK=(=%p9iޞtH9̈jSʝ"`((xED" ʺd)IZQx B<̬?JUT7m\w4+֚ ߛ槃`,aS9)(fo|v1} Coɩ5CérPs7=I434c7w[w)ڽZ=I0<=dx[vb0&aW7wVK v$%/ DM,I *H,!ϭ1 w+;081;ځXx?/N#icee'88iHGS s2faSM14;3㷽8'fzւ/}j9\ U 9%*H Pc&z#d"8(f ZvN9,p98HH`ԀyۜJ` L߽!ڃexژWr@zy$)CP=*2$ p@'4)aP4n c1i@keyanZs##F(- ]|F|v$t YmrzӲpii,\.%PB˓ڶbQY.BzVX1/˃[@Ìg4i)xǥjr\',~ZU'_q}* PkVH]@v5ouݞ41`HکČ6;7#0Isd$jZQw5I؇!ڥ. D2 Kr+^@RPk94 +! w{> f' \,p+zAޠV#=1T8F\SY*6eG4Z#̣^xHX7E!g)'GަZ//bzK]Bɐ9L9blqE$$.I5Lrq;i6Lo*|>zlHqwҝ@NR9TlR4rDFϠKntohGkin?w("X#Lzb)H+]ʬ =* ʀ){VIms.8S n=Fj_&0+J1LcUUGQZ8<:|Q`A楲%}He#dMm& RV ],ŲAnIi9_0S)"#'hۺW=k5v)M2 W"qѱ zpyPckͶԂG~6c&_&Y6({j$ IԵ6 XvrMC InuVִ^Y\0d|.=*I(n)e8o#J)UA,ѧI$Y9*WU^Xq֚`R2W'ޑi FXiQ 1J-\_9-%av؂& `? ?." edT jrh\.) )`yG59'П{Ԡ`dPG@튏'9J q GA<41816sI9#'"CH Tm `A>1O-3)zS(C; ;R@ aHt;a2K'k(aȬN)W et.8 SUC~&G tjY؀}jJto(]8+$?jk[ /nx{4zޕ)/ǡd)޼KJ$^[򣹩xx}^В";ڣ]H;`֨e}MXH#M_S :S A X3 C*԰uMJe\bc7ܴTS֞6 Ҩ]G$JR5PDXYi%gSC"SwSQ]ZI' TlgZ.G>wQVbG%IkqdJNj.9]K`#G-ԙ9b۫$|Pcl׭KN-ܚiɋr{Մ1C7 9߂qHͱ`tD`pŎzvGv"#_|mvxY^i94X6HŸ(b#!bP2#',bXbzS MO@ɤۏҀIR%ؐ7ϑNn SQCa3)6)x sI$Ԟ,l?QVI36A Ҭ/ZpHTg۳4?.V=sP0Xx;IҔ4rw3[djMj hF`W"\uI j@R}j$aApq֘/=iF h`8Ojvy9sb$^Fip@99 R5nˊS™ @x<D>{Sd C*Vkui"#^k]7U(;k1޼fW)1qgM katk٣HSS `wnrIm+`5isReb)_S0 hWPLY2IҤ+{ևՙx0FZ㕋cn7kKR@cvv;gA{3=ibV6WB1I銲&X,bLLGTv~daxH01fh%OG$rGP n)$#[Q@Jqrq(1ldGڹH4V_60N⢋ds1O))mq eP8Lu̵P'֥12c+h6IK,2uKD wz jyzP b1MR6҂H@ (n4 `ʜ{C ^:RCe i}Ȧ(n)_Z(P60TcoBkv R>{45U<7 G"}kBI$򧩮} D*9;3jq/NBjY:}0MkXu̪˙ıqNN3(ґvGZ@O ylM.sڕ() @H843NЊwj?v2 dNIJF]iԎIbI<ip1Qvqi3@;OWq5'l@I(^5] sǽ50/[wjw3Ĺfʁj<ݻMOdJ8,=e͓{ԛp8S0:@NHZpME@M(\R@␅RwFqbP)@:Kz,3HQa@DFy2:欐vl\&Re)ŸLdk͵)tg*Mp a'fd897 VaQI8``"ZLZ rBVyRN0V=yu}:Bfն*1zP$jA٠d 'Ի=*V{SE`[h#7G2dz  b&snV8q,N1A%sHzi"HCp6$$5 O$ApOZnii]vzW=_*1# ;{Nр HҲf'V_fI_a.º޵'Y20}L*vj+g#{}RO$yp3r営"0wt6FұpL2'Lc {=5ɗkk/6GV2TG,98;+ftRJUCi0XJPoct6\)2(&UL=d9i –;GC6i L y3q a@ș3&tɶEf Z ŋ M`sN#.ӍhCrAwocX*#sOEֵʹte:F:RΪoS>OJeC S;Jep:͝Aw)]5銳kznHgi核v!qQ-v&CgSj\c7""ѾGà5"9Vn u-HspZv:]s,Xȭhh5 dŢHdh5m4{V$OTn<7&I>hZGܞ0(=iļqX Oj94dI"m;'jnXL9pUTu,M⬄;g(Jc)b#يlgi jmT%QiG8і2pjzh09x\f݉r?6Ӄ 1BԞ`iԷ"6 359qHBEFj9$ *xAH#Jmqj6' {tJn,XҀ%6{jM7ޚ`ƘKf-#hi2a)Z9xk:Bgo4{ܷҩ2'X Z'j`E(  ✐7c[A`(arHy |xs04"(0)iyM)"#dMhN2JqN<,;d8I1N)-W92EFH@@m\V&ޝW@#&npfx Srmnd8_eϨ%Υ!1CT!=6z5Vm* sZ(S-$XlAC)̵*yxZ|VA簫fWA-Cr+=w![(#h.qҥKUq842mUv(jAlH˕ 99G\U(LIjy,XSjzoA O)"ʚ#vSYsdfyU$\gT:QhlIҒ+l`s\JjJزW7zSt2 tY)*~jK(@SVOLS`7lc+Ԛ͕YeVM?}iKC ;ʍ-5ajHz1aw CPƣՕR 9p`oiѧ#͐$UrIR8#No#0-vv5m'i$ HdT}iXFIUBp %i+6iPٴJ2Hk=B坏=kTc'Kh'gie*Pl4ݙM ^ 皾K"tF(SJn[ 9ġrxsRs6 38ޓn;F=is@>t< w^M'U$i'P8札 c4 TqC}){pj2?J#cf (>ڑCmޔN04ߚ a<"zӘdQ rY4<'0.ր9J"h=(nA*p)P17)@YJ1iA$Ԍ>o)K9+?09]ʳSq\Ә4Κ#8/涭#T戀 f(zS %v*Q}z2H qfoB*aG&6V\p3NJF,~r:R n!aGJN{F$iIc2H>af<P1J;=G&NJl ɡJY`^x V{A>\g4((wgڂ=1L8 piF7JөhU[ *ݝҞ|5VI* +<ӷ5&֥/~=kr4cl4k峁ҁGZ5 -s*zSmmqU$s՚ r MiQ$KSA=F1MfCJVliLܖhBH5!rA6IBGH$d}M${zwrzR/b-ǽpxP j\ :PszG\R'JpQ)FqւGsJI#6M<r63֥W>i7dMjS :UfaNV'O/Q#J@WO6T#sbkk\c9=D%^Wf`[,0Fi mp ?)i\d`r-@,O&#h>F;@'4Ѩ';-+h>@ͤUHJ*i9 (K u]d ,x1lʥHjf[X"89LE)Ya:e ~R1]G[)`OAM,TcRn+OZNR=iJ8p(&zU#Ӂ=(v$&7xI(~\dIfhg-B2H1,!A\zW=4g EE4AN$`bABcAHF:tq@S݃AP♓w |ăjk) hnp"WJidS *3O(%R# '9߹(Br s% ,͌P5m&5^ko&v}*Yi2j-Z6֦ۖ4E̒8Slc$QB@1F jU^z՘S 1iy; :SHRhi0D]VQѴ\?ـQImb{<ӱ;1$=j^1ںd1Tnm0)N4A SysJ|; $ޡ-J>\ջvtd?0#^5`IQ}Kn59mTSЎ?/Z)R i篵17 L3 w[b 1Hs,Yyn+Djo\ޣc8Ss?pȍ#ҭBpj 5b,qL33g9NܛcLreB)].蜞jRޜ!'z|5p4tZsH!Q+dbS!H^*$h;rFdTHHÌgF#uWZbw#enJzS1@*@wҮ4`o-j (|ׄ^5 <k!3֬hN t#Ȩ{+=+|0e%vjֶqM=:+y Z0 P#׮jțc?1f}1ՄQBsd1#9vgڭ2sUTt_h.3R#-y( ϒI_%SQ.I˼F7A dxJA x7O v À\mݽ+bE-|ֽo d(Ѯtm"yK1K/oz\ ՜h X&i!dܚ|ı\V<9Jwg@WV?NjxRIҴZۀ̹?Zy9 ;V j}x! mnLgg! qܷ"b9N@lUSaᶜsު;FEQA;1PU٨;ڠhd@dqhX]vJy4sS/xUeP̿/h%Êzd|IXyLb4sڡɞ`2UXb@Y`0#~n Vh$/9ޒed[B*퍈\ӮR1ެ3M=H ׮Z֔z$$BIAk>AʸMVRaFY$%J*qN5ZTI3H1`Ry P7*Udc 3$Q1Ԏ̚wZm][:Xq/Ek{ݯ!*=k @tE39Y)9ʜdmws}饎xi%FFU޺@`F5=Pvc5n̖VzijԡzO#h.=85vSuZ~lvTB.7-2@9w d玔I&p:.Bd$D4XcԸ)g8, <Ā1F) Z7$jYD^?`i" |`3yzZf,6 S*@!rÚ JyyHPH֐PPizRP`74) TQ^/zP"$ќ7+Q㑎V xaQKb'02$yq ^,{!w4kY`Cب|ۓ X'ȥqe 9 ,8Z2Cz"HOz M M7~TNxVvrG5,_1]j8mq5liA7)#[1|0fIlK@c*[,G 7q:l9P 7  j@-:UBrzUhJ 3pR'k賫Fц-X jBaH} F@'3q'z_Iܶ+6dN kBr<Ѕ T T6#|-c(P2 2v*#gyRHjg #lc\+; <(N;dV0oLWCtuov54jYS1Uܠ ~ZJ_jnfu 4zp@IR9Pl (E.❅<R6\c,;a;#|{ 4@<ڑD15F;P43PvpqȤui($N Aɦ6y"sɦCFF1c*yKjBjE+3RvTKPXc4aRnH%|+}j==i0f=izAibV֘01LsO(0r)x4ҤG88 =2!iM9'vSJ6LB37LqLrـjۜd'q1VmH[m7CC:xǑIQ@AO8:#dSϡGj;SA4/^ib)cu5؆⤤<rVW)#4 pz cOe!ry1T^q.E!ٻ5FMYGz#?t``ZN)0"X [1, ִ֡MMjr7뙱J/*,uy]|(#d8^_t:e^_*_rtX=H":ӆPs[RX,|^$p;sO)~ϏN!e\zbkTivS$q PzkhoRU\Ӕv&N;PQ@)JP3JE1:sM}اM9'&"9)$& <{sHÂjfHcLM ebBPҤs09o<?hD@Jhe$sLYWa:S( +gi!S.9YS"DNET{T%lož/<դb RBfFPg&cFjUQF97RtQ4`E5qbI!H^E '4 y(F005@f94(&n84ڢ߆4Q$L-x; y$qH 9Mg$Fli!HqU3*dҜ 5GvEFF*3<䯛 Aye5+ӇdO:P1jo+S Ǚ;yɭ[ Klү & $zUtIX"u#""iMXTZ]4Xp$V*r!Zs D(JȆ 9mi SuLύ*/ycMidV8Hj892E&ƒ# SOC@9#w5D&:R HX2De939źFWE""qRN|T.OjJ-_ =2'4Hdd`b;Q8Q4# Y87G]ƚNQdq;(L\uJx1d4ғ9 Bz{Ui!` ԫ =pJPUi czLJ8QP(+U5d *7 8A]'Գkr=2OZ^I.r0j1õp#wpFjf7S標3rNzPeG Uw3QKfR<Kn\)XD`HcTcڊ:Bd@ѯ̽i$_-*\UH3vVcP_44[P]SF\>UsɩpNjY" M?2q eY#IɪWBU7sn1ڑnsp+ʩ|uie9,>x4uF:;ɩCӯek_dִ` x$U#q-i yS#?/ZHy322@2XSq&D|NZx8jk.8={P1JmqR `y1–73s@{ѓjr 1 fgғ(G'IBc#:hgO214f(Dג@#M[9#k2Pxxr!!9*Qsqh Bٌ15y аʜFkDʂ fIfk<23)5y\cFёtsxLMP@-w枲Lc)"'֧?%1֩)91jl`~JЇ^]=ጟ6CDz}j5˘aI ݍs!}Ww4QVF1L$cӃڥkx'Qõ|y<' YⱊokjljBH+ Z4T(O&^VRiuq+*jO j͏ʱVI(=_Hv9 =ijw͌Utm%\ +cA.v< zbwEV\P&e(`CsB6~Oj!JS*;dnoTJ$~Q,nګ;]bjV-і"LVhk5$ϙ֊]}9L71)<] I#R]0Sue{,֩46ܱ ][ϨHzSL/9R+#dJIlS|ʼ L:ՅP963*@ؤ&2Q)ӊSF O3^ dh#4'wtoJ+1si$e 8q$p;FG,#I!gV0 qAMbFn(PFCw9ŠcUbnBFNE )=; HۑBf=[J|YnB4lr8 k2ʥOY+1qy(1G,b8S8`(sOQӊjRH!ovÌlWX‚0ߵ)*P`r:Ӕጊs:SnNqIʮ F0F p*67biw?#U͚IYUAzau~皈bؙ sޘX sj1EZmp☛ _{r=+V-ǹPt0HK1;zRn /юt8MHX6 uU|fG)Ex& y)'Ni7 @4ޚg n{Tg"y>pi%+g=()HI'#.NԀrʥ 1J$ ™Uǭ:2y)+ʸLrvvIp0S(e#*qg}wlܰh.vz:]O 5`G7͑;&vi$zj*iڴ+z/eմ,sax_m,i4c*vޅ3֕U構ȼ̵ >m䌨#֋7m p85&x?d.S\S6dP&<xb&Gڂ@OE,0  ݿA]lDo ^Qڂ[H4Kc#/^WZO;,}QgIUș1Tin:xI%O&EX{T Bd@CgkppE'Q8m6QGb |\Nf3$Q{)S;*Vw.DbFnc0@U\֮Oo*KzUŝg6q̣PzԐRiGFR9R9@5,w2FwlpVvԊCF#u562Z0G|UQZ#Cю~)bOJQ̇Q<IO8 v9'GCH3(# M ޠqRp2hqz>9'ҩ2)\c4LnFE #4OP1ȦOyRz m&I gF3Q lEH >jW* A֦RS b,S'@4}E4C=@d$M)Û yvqPLyZ`w, AJ~cF>: j{@7GZpqG֥N㠠U)JnqڝZ. `j3z# (HPFR 1SKasHvw- #>yyY Ѹ0␝H,+H#0|0["(9=iiԧd=D kaOMXeԘʆ#w,aVwՕ7[UcT.i O ֨h7H8F֩[J8,q"9=*ߥB ԡaV&LJ'4;ӷ6Mgb#[ 7jWjB1WE\EPLJޮ"5V9}z 4eLną^& ޛV'ҽipoǵVf_ `Tb6R8\iȝ0ive@Aj/pdUnMeR7= %eu,"_1kuzr'%jEثs1@83!]V) 9PP呴zҰ|BA)#Ywڭ,LrX\R\e1`ZhU9nG@(K SxF;6 QT9nU[IUR$ݷ.;(3'Z6У <+F!䎴ṝNnW |2éccRMS[K"94ʌսU #ΫT-W5P6:T:b#RmAqo|QCoJv[S8I]J~HcYLcB'qT.L'N-q!rMV*a ~k2k=j;&i\#Pd⩋a#(YJ(үi4iI{ Ğkm'usG9VE (j7g@ƒ7+臤0[dbsRم<\[dݚsG%>ԍq)aDr L2}h"5*_rAK`%mÚЎ29pHBwgwQH Ւr5bCqR8(ax ݓUM=1Uw+e(-A2Jzۚr5-x"u)\4[53p=f>'ڳrĝ-W z )%ffRQ!g-"AIUVP9U؛H$S4na`NZ(Ni7sGQSyc_8ޛ暤1ߚ T3BE>&34f|u5\N4Zw#N:JFy@%fcX̯;,Gc=8=>mpPk"v#/z+)>bP08^ ЋbdђF)K fIBݣ0d⮼!F1We&\N"1^*yOJ5erⱪC-lg!՘5srj9Jl.|nk.2~zd 7msLϟ +K T kF99vIՆ\qp۹4[Ҵ $wUtƪS"U{4I.ryVf;A<6Tpisva,.g%ܾ|- I˜znVadV6ImјU:n#э-y%*`~Wp uOk !=lvBF;QaCR|gMM3b0\b)>i2E{˩OEX&3޴dwb3ֳ/>ITN:&YlSz`0OdkJW.0eiA FuS NNkBXeFnx8Jq~^9]֣sXhuv7 h J"%Z;ke 1^14?۶״!sJڗ^Nj1&`ٳ֙s\VXU3 4{}}+;V\5X{dr8cyjcy~zcq|V]2F֘S9aJDd(oZW8v*(<1s81[n'&,S9r5s޹`bh5MawJJj.bߐ?acS%a֨y2۷[B ̤-jNY8i : @H/?P֡gV\f3vpDPeoV@lY%UIL\d)ہʆ4ȷ4O2#`R1;X*8YDބ3 9YO'=#4W{;bŕ͒k.yIu^Em݀S8\ 9Hږuw3ЊĚy .8Q5kM>%xf+LgRE$+5Ԅ$T`qJ23CO”:P:N !xQ1s@E;0c)ց)NqLjD@-.Glןj];<=w_ỳNn9JNC'͆5n`rYA*zm`cS3w;tKƲ/$d,I<&'*OAXRܨ$/ZC"0T𽨇FwyZ?ZM)|= ֙-(UPތ638w4I871\ZĮIfaT+ᑉc"(Z;>` \rڅ Zz $1͇Eoޤ'֖6'զa(XSßJMGulT^eTEdQީGpDC;R٤iHrsґIb*e Ʈ*VoBDsD5`lhqP1֬;x0C7|4wALK)bWjE  ^ łӎ @5q6^8ܲ/͜֊;7A_JIS7zlU\QDlHcpr:~Gj>Ihnc/EI v% j@%[5أtj)rv529'iz209T*sO1n0 zՀBnILS*&2pSArуN`ppǓJӜ4HnJLsjRN([i4H4T ʁBA0Kt C WڑX s@R1LH'z|o/#6)p=)0#NI☀FM& `@ NlJ=IMs>ԀB8E0}%9&f#jEb:!ARHG(*@`x$fj TinOZu%OJkMٙ$>j4w9fvX3fمisڳwns[vʨsFsGV6@7dT9kSD9sj@á'$qAgȠsP &lg_cs1"z}i5H OvC 61C0ɦ+\Ҁ~)J2#\6` ǤJgݺGsTuW A%CnG8501 # qKH}{ѳ: rwڦTSXNҦ \krLg,r01RCzP ? 5m^PFdInvNduSj3z92%+|֌+,9ڈ2m!lc`#hiN=h(sy: T)4d tz(2 j5bNHoܧKm4r djcj]GL R dCD݊Iqҟ0ST7\P \ îr8MwȪH8"vQ@9"zzS 1.{v4>^qbfFr3OH>@zMUQXN*U1] P`d2%} krﭴKT `Z1 +jQ[kvrGJ1HԜs+hUaֹ##Rܾxn BnM&vPu>r[kv2[g]#x%EV0`zՕe2٠<`5 FǹlGv5`i76ɓ/L%ێz]`⭤ A(4,b9>s֫Ф7<|hlW'{F`\H9Vv;}(f io5j9֟&T.k?0Sұ+F:Tq:H:GJg۱ڜBya;H.O5!U cRAxp9iktI:M#9E]a; a+B"0# rIZ$y*9{6ba0Tzli|Ƨ`h1zT4ޔ c=ES;S$JL(C Jzǖ3Kme#:W:D#u84˙ ;fj_~ldh|2UYb܎Ka2fqϥ,hfPvL6EOnWnI4 JenvOKE-y\@43{U\nQ!;(#V}kz9OrjiLi՛q&U{SQ!BYF{VeTPyĨ {V})]tqs,,)V{derVP}!1/Z\E,J}j-aޓ#}9Z5!Uy`HB0*cݚ|(NPI@HH,}jF69hRP2)s٢̗ǰ*JlszR(Dm`Rr<&p,q\z9kmNXbogbLU{UEw΍>`;I$HsڰU%@2Xւ,xՎE8 |%aV:|凔LRc"r>W2=+mD2nȾT[?~)ʓlpAՔ(}协qP˒Xkh$L{\D**(D{G5#JU6=i2gA1ƪNnUN*/*ӡb\:o۵ωbhPIJ\5l<;b:uI0v#sgkv:l{d]v,1l;p:| V<XF(-(EJ > $eQ*#KXhOg5Vh%(}\FtRzSQ%@~USay#*-P'cLW,Ȼ@ҸRH'͝dA-~;1查AҬG뫛y OJ,t8h6Dj 66}@p F̌E$bI"lUt, ┠+8 ;xGwE8`I6Ф>b@CAri RqҔG恛 :((t1g4g rs+jgz41TS@.Ҥ₣0zTs~p1sgTq֛I%>Ь1Z>`eT15d7Ɍ` &K/8jXuN #JG-ƒ 3XRиG6ZIҍCLu)̀*Vk!CSseNyr-2 {EWmȤ*KRetQKrݽXN*&nBZnƐI8iFBsңq'EA31lRAJp7MZpA,)lP F)|)xcbDH%hEn!1#*z<#S72 46= Q@ ]} ;Ai >yaL- R 2E.1K`@= doJC^(lh*R˴sOo݆l)y|2'5vY8ix#\SrOrx4g4nJg;J˞L+@ޗ ( #$8^3IlƘל[svu!rNҜcң74>å1{SXZsCNIspqLwe'jF5-"~oƄjHEl ]icE&-TKqP}a9Cϔ#/.SUTg0AZZmn^Ln@i "UtCﱄG#*ED*yM^v(_**ŗE5 UFǚ] )s\[$k6j 8TbSKE tpZ'ԝ戍˶籼SFBJ c`nfTy23G;GDZz3_䏘qNP#hnj>\\Ɠ}g3 b,jib8ʝҖ,7F{R[oSS+KlDjGPBi ¦;{T6S)-p>l " O8,@5NwXa(Cd֝ 6kܙUSmZX(VBUzb.XʚHa#Zd YԓdH4 3n泛v*IJ9bZlEnYpܚjg8 "4ٝɠM|з\SUm0r3Z^[pe3lM !qZZ~\WHIt8+7#nCP6lXUYC ='mǭ),v}T2\,o_U&`PO x{k4۸!xQ-X*>^I{ڨ84\|D 5p)i!XiVĜ;|Þ)$tQ#5$i%lt1VdAh1$؊JBK+(5-R,bYTC$ˎ@mhEKBEAҤx~WM,Q$ZFl(Z@Jɪ0b'$06:AZHÃҴZ0NՓ3ϴ*%ɷ*-qUC,9[f:ԩ 8j # R8ȨLe)dqE|}P*BZ${)یO#y5ieinWØ`.?J` =*M=i[``#' MvS2)qG!P`:g5T y?! Q!}*V,Lj5ci*w >j 5QHSѪ.{Ul` Qu%uG]3h7tXY =a3֘[֛*` $ BIn pAB(8JU\0 A4Ը  $SjPb7*8@ 4)1q6'5;?YJp9 Zf#V3OnaRT9J r+X5 ZShȢÌ(d$/S`iL9O5 =j@()ce\l}i#49';j>IPgq/,ոb' s@Dǿ qMQzxS9dTE!ہPsJK4 ERX=Ap8 aPNy"!s(ÁށR*B@Jw09w61֥hS2EJJcH%#9U> 9Vtn['̋Kipj h7jlWS9%V S>(ޤv'l jhGeU@ej.4浚T8:fl2=UƤnvj8C@wo "0o d Fq=!F^sڨݒp$ҵ!`yL >\4hO5J} 刧 َeFJ1PN Č_+^͆7AՃVw8Iŭ!R,ϕ<폭,v@rd3 UM樾E z Q ۴ds*O1XdGa#4RmHĀS؛I$;(Ufb0F1Vs m23n[]WTWʧfG@ME]֡z/Pm8kmĞRE˂0Ngr7W";̘# OHHwHasH0>eT,_U樚0F6EQ1\EWFRVSBiQm,X(< [;fm *E^$XRvSU"[T8:4y2m8R+]ʵDՇgq+arq]mݒw8 n=T,v1NSsJ, {Tjv<Z Ve\09IFlV]޵.Nؐ#50V**֚7Z f5~4yPU#VS"auƺb%!۩VBDF8(ىAޞ#qB]Ve`85>p -+\X=j96g WiۓҪjKfW(.(5!qۊџϵhx\b#Ld[Zd6zѻ! U!I0!y䚂QTN UQR/YTvOe\Y ;.*\ ;@M#Uf$V[tqFҰ-:;8$*"ZʮOrqn Hv{Ұ6ңYtpަmH.ց"dV$1E9{-r5e>S1jT8a2,dk@ dKSN.Ƙ)v?1>!M36֜-ш6 Ӗڙc<*ny&csQzn@˞iS4}XnǢxR~er:g5/h0+ukCwଏ&& )5FCO֘>)ݲj34 37fP; G43IqHc8drrjLuA|խhz l;JͤH J"8il;ґCT9XnAi]C7 昛6Fn:zi8€?Z^d t*î+]e#P1Wz`THR4 |zOW#gJq !A6UOSR[:F`X I;oDU=iّCބi=JTik\ڤ%@s (BjKxU8'R԰TAlnv!̇a8N܊wRn;H⨎bU i$G87 b#]aȩd]aP;4mIJQpqG9*U&Y ⥚ =GR)t7f* vq}b u@-ˍ®1ԊULT.]@۟J̓:s5,s76'k'Vز+[p@HYbpjy c8uxy㚒;26]Yޠ ~^ .AA,RypEj5lXbkU!\¥U4𑻜70(8&S85-ơ`+л}버nW ֺKeG1cjqZgt^Hǭ;+U=\kCF$b0$TI uJQX#ޞx"c͵a I,0yj ٠1dca;sUiFqL)\˹?)TVP;W(zj//![9d Y $V4P~쫜83JmOc敆戋mXu".g"!VU$1;ҥir*'\ xxʤ{Fs 8&Ҁ R_(Q0ij%-J{)3P@XiZOI5X\9n37iK=y,?aO@ isMGbsv%\w;r"ipq*#;I$"bD$ !9⟌u׮hAsґ Rb$n?tTm!:Xr G$3܌F8'ґr\f!fHjl$rLj<֌LOCR͎A+]\vMYQU$⮖ܣV)-iv`QSuFwԑfXp*n*py19>pc@ n⁐zS &3R,Ojr#"Q{ v9aJ⣌P8S2*PpIHǜӁ4my=|EMXtғEV0-2zSnܒ=֡*U*9VY pyɪ8vz2:@:ip@80r9;IiZT oܞ:RHvsA*I;FIjRpyI1܊˟JEb(D AȤh2m)' ^☬#"~t3F, 8Cen{ Q$ATҧ@}ZQ`X!^xSD8'?ZX9j3ұJD^ 8d `Lx@ÚMR3y fy=$ '=j{blJͩALuSl714q%TXӘ˹*rzc3/d c`Pi4>~ 6:QF'Cy7cR.,=+X妙F7`[֘HI;('sLФ;J隲(D *c¿(Q\j>̮-=̲p1P0W ]$&rĹaWDݖymA'm=bllInC 9e 1z TɚB7->qq#H =jgg?)ұl$-^{҂-J[hmOݫD) G )xgֹKDsWS b[$T˹a6IS3trWmioF4[@Rީ>8(/d Wg ,$e`WIc5i2a2\1uh;ShxyNm;zS$z,$QzU zU(&>i4RRAXX@v2HdWOQ8kg> jZ-"N\}*w, =@KjF>V'RRI$0Nr\K,v}i@ L+>[b kzܶrwc`PuE92T#h)m ݃Ґiq`c@$FAX}+.ady2kB,Ԏqk鄲yZE]3)QU#t5hpT=G8NGa;֙6Ii>jPl C3ssMOarhwLAL>c׊pҔ;PAPyMڽ"[٭Qݖ I`zxnsd6yvCs7zҒLIG 7PQik"TIZȘV 1oԼs֍IZG9#fS eЂZ[Kȉlt>3](L'xXF`;.5nlY!4Q֮Gyܞ=j}/B2ȳN߁m;GE;~U ;|Zb I109ɪ(LސA!OO=恱1ZgmQV,]2qց"ޕ} - RޕxIk)F+qB&V\+hlߚcI(OAZ7ک3hKU%UՎ}(S:F#iOaqZvlFnA9\ W.(Lm^inA#V4KW6Yf&5+v‚x6! @Fs ni &rvnش=& #bTVn:(5rHPT0.x>v@JG J n[&FzdJ,FE5 P@4jQC)rFM&@Wp&qeJAcK´D7ySQ~R;)m= z8iPMLppE:Zf}W5ѩ(Ih<&\;PWV.jeXo/Xݝde7#%&8 c׊,.X*DEk[^ ${f# .I[ͅBJ7"$"l ~c 58fFqZqxD #A:2\4sⲬE"n$=w imU`sЊw2pGb) p9?J$FqP ;F* )!sj,j>}OsvZl{0z@?9Ae7)LNiG5( 2ہbfڧ|GmTw !g#8I5w#f >GLT6L@<֤Jx+cvebV. x`qd  93\C33)emFQ,ni++|~qT+1884uP ͬOjU;a&$x'Dn 9,*Y1U9f\  PmeR,X {zxUbf< yevbTsOX>^~jyu$" p(s@gS zҒpsIGZ=J`wOAM_IN[JaےE* ( FEٰ= vI+HXM;i^qšL%Os)jlXޫ ۍ'ӻhxѕa0:~9=* sH8 (9*EAvD!po8)xdp S֢T>XjL_ '7v|Aڹibٞ&V5lǨT/[ŀߏJ&c5#Rӫ*R#jc=++a>`zV%r08U(.AJI'RGCҷJ4miѦY"2qO72s"%߅`r V6yci}xHؕǠ'#ՠNXXt&@ (9X'J1$sKݕUbk$(RfF$pOS@s3`x :`i̹c\`#>ĉAc$S9(%,jևio\g9A53d_X쐒)1&·Aԣb?}F>fҼB[j`G9=Z5u_<{ѱU'&8 M9'o<}h#mp<`ns;Ըe8&e##CrGV]ʙ"ݞ1sC/#n"6f˂ 3HdN6\=*9$>ܰPu5Wj NFISdI}u ްD7+}ZZlkjӲ6;Wict+A˞t JV,`*0MIlHQ1tAc=)Ly/)~iL <YoR_y7j.fߜ:iRlkCRGy*_%*0@r@#Ҩدs'9DCLbF($*6\JQsV*3Ҵo+ ^i'Ӄ.-zS04 \R ܊˴pMZsL,ڜjfʵH0&En¤ubaϨTyfە npy$tJ2CLg|rÌ2^\Qi2 'qdVJ҄8-d8^H+ԒR0Y#݀jŌO$ jӋShfš*tCqpG$n>lHk;2=EY*!0|杌Zx;haFY9qLA&wt!Nӊ`7I9\{R ڠ'`\1mZ}qUw+3UȐ94$OsjVOB.&Y%"OUejA8n4ԩ"\֖1xsU$n кfz "ިB1`zu)(sIaU|e6̚)J ?.2sҙ\a*;yjP{c [U Uhn?1.xr$GMDHWh9fb`50asU6ҘeNÔTH50! (-]$` N%MuP;p"e&])`1FI>cSᒹ# Ru\*dX&y\<=i9Y@@8VR|jC81h>qR R:Rhp\G|vsH[z /hH"G=h9)dSA M OZV`6AQW/y!%YsRڙZ\i9*H@r789UwM/q@KjxUU}G$T.<=YЅbܭ8Hܐ{иI1W7R. ƪƒI T c $r~ԨBu>f9 ̡9curhYo: j[z%i>VŽyrN7,k9B*Ĉ)9}*uz^SҬjQ1ǝt7,S'֫#ɱXA=[E* C)m+ TUn}&\sS+ޑw-j&ͦ1L 9'6)j6E by9$ԌGJ AhkIӽD jv~X(DE#'4$im5 8z3*e횢\6%9'_ΡF Sf9jfRw-}&aۂNIn1Gu HRN&B69Bm ֮)yQH$R;Ṯl& m^ݛv 믚(E*w1YZzqSSYHgj ՙ#X.$.1ǭDQ}.[F,[N ]mP-J"qv858JE$+!`jbR*&P7"`l60iȀy;):Ӹc5\@jU;))U;Lmz" e@4F @t9'c8(U(M \fmO"uɤPI;4C2L2UE*IN*0¢62 d Ң2"ceOcb@Yb#vNkYɩ~E~eV3[U+LN[&HnV|>*u(zH'l)#pH,y4A#I0,ÁW-b_C3y5(f+nR6=92*̮8CnݏmugNF)Iw7a搁LTnaC뚒5@ P(#i&ԣ [5_ߙJ ZQF@Z㉱zCe^)gr)2,A|s5TҐ*^2;U/4bGASZa2{RХr]W=C(PO=ԁ%8."6Z2oG%U$]bs6n1Wv8 ΀4(tY{WO !m#DgPzqKk$+NdB`i#ϵkCrI 5D<Q"CjF =zTr:aր3{rz}*0j0ᐫ*bHZvDJʱ\۰cm])@AJby:3 UGzb$TqɄkmC)!+>_' ԓU!Yyzԝ ZNooF,kWleqV'4 3&,N:\159ar1Qgi9>L9sTǀ:y&~YdPn2"mS]"ĆHK5bF+(cM@dԨ jvҦe,M#<.Ί;U) )޵]FOugZP-Ċe=*AFv#K(1ڋˑ^C񶤻 "+ FaBkH6,P%YsH9]D&4Uܑ!~<.A\5}H0&A=jT6Z9*L!BnҠIv< G_:d]qLjFq 3AVⴈl{i3$œR-J}U[s0^UI5lY|o\RIvՉaҠ!* ֚'7cb3\K&pwJxʦcC9`sQ:HR* <jk\ZG4U+.@a`LvL݋\m$rj-n+5 eYTťMVdJJt-yO.XkP g:aݭ]WƺPI]ئd(#Eg=jEiO+3@ S YxAu\ bܚn 48rW, ,N:R_J] PI+rԚYK*xwX0r:Զ}aMyXjRy6KUHl^ >jʅQ,qH>&tUyNȌH U(3ޞ8GT~Ai2ER~"mF qMb|0 s#GlT*i*(vmf]|QWj³M+=VFR[9< vYЇ\p=+B?=xViI+F8I#*FqR#M3;/9#Oc#%p(JM5XO0)bXvD qK3NQ@kpx.! ަVQ.A>0I R^:ASSLC6vMU+QVbΨLO()A/Hcj^&#A+y 2n%y fenЬ9)DisWpYHp!َ1QҬ ;c< ɔX3P^ub ~u~}@.$Zo "ֺ譢?% Ic"Tua.K7҈TH8"IM䊎I>`*:{QbTf\^l2m(dϰ\g櫤ؔFW;6jAsQdž8#WFDG J"k1i!Q@t䎔p9+AC&chv>c)R#8K^84AP+gsH20EH 287;i}) E%LP; ܎TL>_Zs_%B䌚 HF.;O* |j B;JhJcV i") TeVHd$qښQ2ygZz  TɥUO3#րsȢq~Wd.ҁ1\k.N ~j\`ރ nOLSySrQP nzP'ݩ26RJbSLc@!A"0:RqHXրirی>`?pb3hf@bH0#R3; 1HhcÇSӶ=)Un1CT!FG5$*M\w &K]@IJ^*n?: 2͐jsB4N)Yu- Pn*@/'8ӵF*\EJ&0[4"+Q7+./H[ k7W^%ğ/U5e8ͶN =k|h ęF&EY tŚ3VӅSgilϠљ^F >EiLQ ֲHG5f2O0gޤ3ڔ~324,A,8h+OgolSX) hSz8R1 R\8c;c9"d P)vSRSfud悫ԇ 9 oSR(^)qI`3J敔1I)=yN%MA?ʵl!Ukc93$!,{V>CA3~aH8^L7ԵޠZ.}PumP(QyTB"8i34 MrqϵZFE+6{TEaZR$;ɒ3eNR v91LsJC82x5gE+ t ԌT Ͻ;%LLN$ f=j x)Jb S=O1G.4#`r5;a9v`R>F8;F㩫'qP.21CD)8f0ƭN9Pa-ϵgcN 8XaOjrUy+ &ӆtv_j3;TL{bo0q!31֦!B-rPu4govj=ʔlb[ ڽ etFI\dfc^6˅J' R5*#c#+eAJyzTp;6F@`b"1#4q@5``z;dғz94{S^!H^I&gp1AJ7'3#>}wUηKwzbߥ4O˓uڲN3jXM9Pf5GTȭ eF+>;/c7P9_-wPmVLz՟Xp dUO_j *HVv~jэQU qEH666l#c W!pxy C-9&8$OJw(¥=4lsV݂R8h3h >sR }N( Ě`RFy=%I}:(_n$2*,w:LǍƶaRms2# wi_*ARVB /' 9=]Ъ1Kmq4KFVir/Ue%Aksn-e- d7zU!h@ -N62 ܠI3zV0s%crV>E2)d1f=Wh!"ݾVq*ݭR*b3߰ƃ *9VbxtT?a|>49G#&PMߢwa`ty}NCHVD6rBf2 QRGJq.zR:ɞO1z$&M*JI\4+"ԑ4VgܥW8Ai\юB'[dV?WոA#8_ƄȔ T`*@U^q\ 翥QV%\U-vqV, :P$Ƅԛ2g\}qҤYqoZ 3CH$@Lѫ DؕqL=1Cl-w1LN dJ;w9o~*e; D4g`ȠaA"RqOTn('i81P0Al.}*N3⣒EwR@9AǑRa HP`IOJC.iI:lfQ*ݪCf=sYٍZOCDosgH*+u;"ʥeJng1Ԩ@]OVXʀ0 gmHQdf+TU1ڬKDÊMǭ07c@X~G~۳4Wրゼjr:Uf N$G&`8I) z0w9XfG LCSCr)uG .[%+pB#MqګeP(Ǚ33zҠU\::6c+Sd %Q E&W1d}*9d.2zTSGzL/S zƎݮb8,7 y&>-yg|*ާxC[F򢎟JDQXIӏj8jH(e=)@,9P1=Tg @" qLL (848'h+l@18 P2S$AN 941nQqmi'8J恦D@> Z۞*xն 2H8lEd0Ҭ u^*FT`Ph2`t5Zm)VY9++X%FW5f#sEVIm"vT{3lnDF>Ok>dp޵-]Ü&OAi_cNǐ0GLw^Gjc,[AVdiMJ$aܑPٸb2𠴱H"y<ӝtW>qixwbFe?)QA u;@asA-(PIaӥGW'֜dۊM 7 &4c Ӊ0{@l(c9N}L-*c֤gw@fen_&XB'z0 ԛXtª2XI<뼪ኮc'T6oNiMh"\yo_)29+f=G~]^ *^,N-؏W1K(7r ڟJ5dm+nK} @>F|#QsEMv$7M?N A6LPy٨HҘ׫+6@sUN XZibʼnprɦK8HitD.K0fW m4|"{kUMHźs&P@#;GfrxnȊ!gtv0p R"uVFlcĎQH#,E0C=i#|օ+)3dp~^֗r9<^c#5um6FjIr->vE-)Cۓ,Ca#֨HV1rM8@\`#B]N$ags|w&3:RCW0C\Odb2]<CnGY2\zk,gϵKFf͙PkFn |P(lz͛řaf6z<`;ƛuOZ| F3),YOap Ti^۫Ȯ#{) 5Bے*;;x jlҁל >zUpsސKyy\M3v Efv'4rMDLBԙSrsHSbFsҕ@-$Pw tfP$ԧyUy,ǥ CZcw#MǁULefg'5 $u^K(Y0[(ݎW>`jKBo_$9& XT *?(XAB-26V䊂+6 DT$f j Uر⣋;885e,z,0h)"ƒYN+BɪFAvA#ڂdqNDr$t@P1@9"#h=*,o̙g+.[ f-幐6}9X;rUv>C4.A),67c(y۷ +|j&.@n'O[v;Qa<)暷.WȕqS10q@QrS@ /YW7\D6ilSޛ mFƨy*5%;'K yqn})DW& xޞ%ve840c[0RfO@*`'ggf![ڦ4+%eC)Uk *IY%ۈ Jb;HV%zF3m )OhԫW!)0E( K2./ n\q P++֫4Ci sOE"rInRv+#4g&WޒH ?-WbуHgVFeۚqLHz$sdfgqny3I@ߙRA v9"a܆T !S8Ԫn*30z҅wHari+/4( .rOҀf%E1^|╰6qADUT"3*Lv5V%p@QҠ}VZyel=i1hж7b,TzP#Y#4 GrZ}YܞiюsWH9~ )͢ʲ+d"%s= q3El#RD*_8/Ҫ`qF.ޢɱmUҕQN29Qւ(PK8)0;R`ѝzi~)tP8H;Q2y4\ēJv{)wp;P |tۓ!@Cw"i KFIi N94_zo+",SҔ/-M0) P}9^3)(<1H\TzVRæhr6'jC @iPi@f#gI6T;RSX. BOJ\9 i3d}iRB` vHh!<) $gwp{@&U' 2k9SfUUϒc$ tbRbqn;Ԋ~*Ib/ZfN$AS dbe|Q.XWßJǦ)<6)q~%ѧ蔹"$I]J0+݂ I<5o XjѴkoFvURsďpG>px]#|+e `錔:r<I r#s {3_:#E*k|}MOޯsՏ+:OtvPiT◪: uL%ϭ5I7Әd `Sʍ%x;98+oo\Vև M LrVPnGK2P ʞ[=jv}`1 pT+;O\$szYJƞfd㩫5^Jp@^ђF꣊RrwBSId #ܸ ֢?+p(@X'vPr2u9\9'ۏjFIrNH"O[=MR{9ǘIF(FK7:ΡaQu5Gi,`"FԮܓWyQ?(RUu9ϵY7$X-[(0 A*[rn i-?uw>}9LʍjW3u_C,=*K.9$O.H<{Ա S!fD$V{V rw)Q1ҁ3ԌhN #aXg}$sTp6)c/ 0AK3"~‚9C#<~5(w4ւؐj&ݻdv5a6Ao0҃h߱K9*XrOJ@UP- -|Zp湋/\ɮiM4qUZiyhŊy}s]9YQ%SfPm3-Pk SYjiZA 5ZjtABh$8= (٦qJ3'wN)P2GZxRL$S#&@ERM-ցCl֛cX9F`1X3i9 VN6': Ëb{Wȩ}"ʙ'Sup:Wm&2p8لzq W[}T3u-$NŢTBr dDd1@JA +j*DM>INXiX,l2d=*vY6X)LTZ Nx\~o=E88 ւu1O)6l@ fMvcl˺%lt'a_(NOcLv%s sJ* W";LUF2րLvӼ1-B8!R @cݻJtj6)E"{ jf)һu5QFG<͐9rQZiV.sZAhVcN#]ΛBKո*|,v9mZ& N:Ui5Kxfڰi&mǸ4+fnŽI3UIu6p=*5ڕB;bF$U2{Sr$2U!Pf7yہ"JPA[`iZy[j !R5 B>dSK#RjrA(ؕ=)cqd|U\9'<Ru6_Xr1\;\{ Mmr!sԣmQwVx/z!u@9/6YT(9@nLB ia,˂9rfpxST8^sAV 8M V!azV:v(칽1*,ᶇ$ 5" qX:e۞ ݕ_8Gʸ+*WMgA<Y]PӀwv>IrjoOb8 *yҾǭѫN W׫cnɏm4*79Xq|xSjޕCy2$V'5y# ccd{ ֚le|ðA\>v՟MCS26rjaMW1٩h-Ҏ: c5 +gc.0O-C;;]"1 ؊j62Z+H"L Iq2&7*\aR@+S0KQ?>=rB{A]A$t\_b':TCHĆȤ&lR;#GƸ}) ޑuj)ZH@c=˺)!3VHe}~QԶRd;UɩO{`W}?ăֳ-2鰇#3ɭJۅHTbYPƁX\'**F,c94H/]IG9,nsQ2lN}*YFF`N Se皒蠓 U]­M91P fuqӚ0Xn`*ޙl[>jXe8s9Tw9 &0ǵ1TW[껉aI}R: [F`ʁ2V++TXLżPE EIhʜU`[4lz ,n+1M>6n tncrA4 < jc_blnJB!#㚒E00iێނ[=*PWc˦OzM= ;h#4-ٱJNFnK6;҂>e@P n$ӻ*Vj{2ønv ϥZξbH=+_K&\sޑ3r%0*[8jDQ51P>Eq$tN\qKwa<pEq@?v4ьٞ,1Ҝ@dRր=ƅJjL*sLbE&ʮGJ||w\;h.+#4qTnN X\拋Rp3ьQ)x!қ8v8ȠhCxϿ4犎6$vPVSi2)Ǒ9݌q1*U,y1~iQGCA@\1\ޛ!6T-'HMlR76IC3֧gօqKoe TrsTeapj5̆ v7qUb^Fq=[)h^XiSA䊓h8l n1֧<)r)^8妅}s@\1;'(?1 {\|x.: F^Mzќdi 3 FS|Ɂ*11 RҠ9"I&2SUnh&Qj sfJ)7f 0n)r3K@ ;؁)p438Fx=nKiߚ6#:3K41odF^AI(E]`IV071jtjF)&w0N|´b+#k~%FETbrzk(AcfR5g=sHT$Yz9cvr^#֯5I<68Mo!AUqt1?^H=k+N1G-W8MRF@! 59|¾~ 6ӮeҭJbQx`H&؂*{ضUSs*yvdJhÄ\2N~q*5ۅ4䄢դфet,118"UɢrI q,@$==*1"clGs[6T cz5QkXwc[bV!60{VB@sELhȎafE`"(T*+D8#w`JO QK6S3RY(IќZq qުn iUauEÔ|ژVxzR+ cwIrAz`'RMƂ#RLr*,cRL*=dd拔JCmM( :)u9Wp!Ӣ,cT-2uyj2C|b۸*B@lf2UN.2P+x#%` Pj4aciU(@b0W0 s[ܚ%>x>tN˜dEط _SLT8nP2#=:6ppF,ΪO^qX-!aZV*adOJ WVcPE AT+:p{h`BH%Mj@76Н)rdAp[0HnQ (KTW5V9!#0c{O5B=+H*Ы.iBV1S֩ V~k^ksUvD0As7Ҵ- )ȫ Wa?; ubE.6ʼA^1ڄ\iYKic^A#xKn➀l9#R83@PXMx7 zEǥFXSJU"4D9.;Tv:Tl[To8-;e ZkۖH"sU[@hwe^8f_<ޣ~Jzuj@I'F(q֣>U< nOR DMH2Z +Ґ}h PILw A0,IiLr1ȥ1(#s"@QR2ci\US# Ԩ %Vycirթbդ"5#jg'xY½8.G741ڹMojġ͓2|7qڑ{# qwgKMOJ ÆHLgW gQэ0 :s"Q&#Hy@Yiҥ[8iu 'Px榄2P1AV&jlE,X'5d<+AQP("3m@0ͻ2MSJj6 $zPhrͯ.E1t1PނdW=r^C0$"tc-Q1,fZM) sZAri8r!)o$ާ$U ofߌD:ݑ 6GZjBUyM_+hGc'5I l@&X(<*Vn~u0;!] 吽ksS\\I%i@|&dI@zᙊ:I4̓4lC!! r1Al|`%Toݷ2D9."LsR eWd NK d.\̓Jy0xYMݞ 1bI n649pOh˥ɳ/)hV…fWfR7w\H|c֮i@ijMi!6޽n~v$4Ҿ/RؖF8#v^?E7/ݱ;4WV6 FCWc:H e0M^8VɅU<ꛃ́Hxv,Kp88(sfZU O;I]0Im$r) tYl f P`!IPm⚧# @Z R8`5#.W;8gyn1W-ʲB=i0Y`Ni%2pOAإK( Rʪ:S!bpڙ?2;Sg9d8i0 4r:R\)p6R) ҇(͚GTl8 qޥ)xx'SpC?%*;SI@ùҚܐ3ISƂs\6p*G#M1`hHn(C>5B7QҖC.naLE#z֮I$,1T/7Jr@$A<ҫME]CFI"fD"XSwc9܃R,]Ro#l4Uʺ+! StĬ94:@RK+yPTzSmHbUU9NgH@Rnf,qҚ,[Jr3+Zv\ǻDI;0⚊G> =ӭD;y/aKWl &H$f*G;cJz/w㊮C$5&G&EW@K>+ t=jˉ$;ɦɽbyX ,qVA< dZmՙX <գm*;`:UŒǼm =bdvf`L2_CT!+7GNvTGLJ)=怱[ywG`ڵ5DB-wj%ΡٙPgJA9Z#R2N* agJՕ?)ǵ!-vTꤎبK9 @fgnW8QS8$8yvD_emŝǰ5}M<ȋw"[R.)ZPH "aSCQK 6)\&ŏq#F1CHaޠi8JSqRwS w5JXd{.*౪Tu5 1eA:+J@j{4RIJr( 2Y19[[Q&|5FLejޮz$jNcUmN95;G*cDTed4~M eISRXBSE!R Y WL{U.=V07nSЩ.EF"="yJIH.b*Uٔc*(H8A.CTmU1v3z wd-Q@GJHކg8nÄnI)>!p MMEO7HHg#}VPa@9qQޡkQQH";uODifvXtDpjWڪ0F}餏/LW2Ĉ H̄EWOsJSXzU# 7֦<(!^֢!uM! p*muZ'U("q#Dz,+cR1K:Ӹ@#s1n4\\n`U"W@{SԠݏJ(6pi"iZ+1_VhJK/5 w(ȅܯ$*u[|֮y~Pbí5DRD7hEuc{hn0k?Ozΰp̶czV߂ȸ\`J8%FQYF("eEUOq#)\|ۙ隕 D!9@/ih *'3ǁR N{)\rś 5 C|搸Ixv@jRc;DP;҆ !'JdvHR-HO9 m"''+(\⮴̨i=ME?ʣ ;T'i,:/YWAvn-$w:hRVb2:fG0w{\yI&~ HByoAhKfrj"[ ^wz7RĚQ# lqIUq KةFFx4ѷBqS1M))H)iǽ!'ϭ0=!qZ9PjR r2(v9۽<'1}+0 +}ppIJMOJY ~g43XzA7"5ҺxEEӚ!,Nqf/!{g=FJA5&x) "Uz昫Tq11zzO$m)@hXSP88cn3B8DwF),1I>1AW# Rcp2)~l*1@\=:$ Zܸ4ǎ,jlhRMR+U s*E$UsIY@afI#׭G hqnw!cR0p zw+u##&&jtp #X`KbIykF˯PаWϥ92e?r1ib:2nko%ÑM7ey.uIfRߧj R>^++N{kD<0[G!TvV-sڥV OHh8qHē8+ӑIM7i'1@Xqv:P$8Ѵ42@wH*ip,79ǵ91OmF)9«J6r:R`A,Nes;`o;JsM]"HIG4/rz&=##9G|sJޚ2S` )Әm`GjnFE0*2r+EDFѻK) 4>b3)F N>(QHcw6*`#'HU[ 3F,r8X4)0FO1ߔ5SBW%8ۀ( ȦMChFx*P=ih+)I8L0K`ܙ J;gC8T20xD6'4gi)nɹjvzB2u)2<8-@8^ּܣID3~ yęnzVVg5hzM!W+^w;՛kU*qBpvb7# =H63渝/[[]Tr8zqMı` HAJ3[MܒsI œ"Lguh89OH*OӥFі3Ǡ4 YFs0Xj;c֝tM` S=*w!\IQ@5hH{!<=jEHvpw ''РrxRh 6XzԑiYpiqa9| u b9Q3y- P+gyNh6Ei-a##ܚL(G %NK5@"sVŹ\SO(/zݣ!#Y32.,rK[T+&WⵤELӣYxf㩲H;l9D=jG0=*LB1'\ tezb7*(Yՙ#0Lw? SGZO4&@<}hhZqr) Q[/PA)cIq@F`N)7H'Xx8vmӕ]X娸X@_֔qj%bU IHG5v 87_Zw&0^Úi8r3M`TdSzhڈ 8sޭ VmZ06<Vղv8B F+]Tbi]3248=6Y ʌ]>T[R1z沮,mf0~aV4%$^ GldT2>Z< j@a0Je:o[Ʌp=M;;3vCUA5F.w8b\;\*O E#qVɌ%saE<eP{ldލS &I]J͚b 3HI V% @$@J7)U#&'+Jc8L@9+kDH 1zTsrJA`J&g(y Tv*#ޞN=jf7pCqh-)q`i<"*،ƭBơqqAhv2zPd*ݚvH#8Onpb ;j@6M7tj{ ;К}XToO5 VIH6GqU{iܸ_'MIkj&BO5^ U d+E(&TI'ymOZG㞵:l=j7%B HXDla/q2XmLЊCP!@sڤޗhxߥ*T9( X|ӌ֜P϶`CU#$ c>*!Un>I:Y_֚cA,3Y TFsSqHlj4R`88Q~F*N8.{@+)`+)O$JyaF1ҭA^6P j1bRlE8**q>􌡇 ֢+:UP@H3H;u#IB兙*XݜsVrjռ8+@YE2hH8銓Upj73 nDW7=jQDcPUƁk'v P5g|5b*`ީv Gfso吡0:2'ߗÓ*|?2CƋ2h>LM>ҜmZK-C1qU$ ѕ?LұfR8"r9UIu-bKi$!)|P>*3d&hE( $ϧ"UbB% 8t06(MZP R+&sp۝YW֭kU!JvqJ&)JE j76WwNb#j#6dwi#`:Xm] .voO]z.EΨG y#@8ֹrR|l޻;K KBL;Vr  ؍/M|j<[ipQ'јUT\2)`qtpxSQlaynw9[ 2y>ض-FYN⢻W=ţC"3e~Q^?Wcg xk|4)zsE&q|U3T,Jr{tzUl$TNH$Sۂ884 ( <&,XSƙRFO4C2#l2AOn8$r{dpt0i&a DEejʞqaZ3a1/VY[xd_>kK˚{ʡ~jyV"f&# >Lii_SU9J#Ҭy&&.;){"VAԲFN~aLhq1nE(;e,?fbRۈW jCNEB Բ.&WmqQ\9SS}M֐ F#Ve#A[mlt &: f/bn0W_UFG^_jЩ\çzu {BTS1KBa_n tт:՗qF\ՙ^AV`{,eH#N=1֫G"+֜d+׊.gJ$CDg㚬y6(ď4_%"%MZ`i6 qޗi3RƨR%0E7#怬 =E *l|.͑ڴpBET@뚉?sڡx$$H9" &ЋJ2}M&]:析{Syuh#@4;kix_E*=Il ۊT;Vrx@]ÓdY>frpi`w֬0㌊'aR3v60i4MH){SQ@ ֑1P:%y>N6OK(wQTք1b6ϽM" T6Zq-Xp9I+.Yd8.J2Qy=j_qy P:ypI&|| i\FOQO"g~jDG&r!N挕V+ޜvnqQKp.w|1Q]^ %_T)4!MX6R>}ѰUL3M>2-\XJSnPu0q-BbXg6$o2' 3׵#Ɏ֢'; @2(ҹ;"I n(90Z0+ʋ&toZExBb}jҜ>.EOn(ֵq+'88$eW)i_Qq#) evu T9c֐ČVa9"mP{*#gH-r+>Enf1Y>Q{[h9 JւU`hڥbVX[ rդzTC FS&=p)'fCs{RqN8+RǸ$zR+(bLLII)"8^sQ;c+i~p1R?J!oJVヸ*.RW/#߅ n=*]D=iq9KsHpK&F3J4w 4\gid#ҵIH1Bx԰)^IL.3efr9-V{}y-m7\6Y旜Տu !\]._ٔEc y\ ts1@SbG$vGQcL12YvW$1+`pik#xLV&Y;sG&'4bO0q@j5 p{P;Q \&Օo %Ep+ٝ!@p`״ۍ^CZAa8&:RXQ4`1QIk1ecxZNwt̫8*89ՈE8#E§=jic:u2'^A$b2gֻed_W3=1VⳚ:jj(ԊUoN+%5 AaҤI&|ecnF[uj)HGݸ>)\qҁ/JV s&7|kI2=j,.a}jUdv8lbWo@i71 dU{H*`z6 ,STf1=CrxC#(UI4$ȼ"& NHJD{${0{Չ2#2Efj0=z1݋,:␰iBܯSELOZPͻJ/~in֟t<sM٠V-yq@U-T9RdpZy9cVo(p?+y0@r1Lg&|ô墺[0C$kFH隤jlώ*sL$xUy!ӹ žzľsb0Փwi ǚͩRRNI]rzf%pɩWP1*NČs)gFhyEl|ݠ| ݱN^XP?7&klnN+n~5hY|Ƀ[J͝1*3\)jW\@)um0Bj-u |Dv3"0H|^1"|Wo[jqǸ(*cV/r`%qEh$ObPYSoV"x 7j)b9ZQqQ\삲$V#$ -N= Z''=9Xv"2 hϙқ`SGb(,R9'{:%dRQÓP'Fםi2#ΚG 42J-j'<\s؎%1S5o`L y5 (:Z.'-H0 S\5>`=3PZkdfR6@5x6UVXCkF3kAՐvczUu{.AYɁ=jr=*<ڑԙ ϥW306Ozfqܭ#*Q.IܹL҉2jB&V% ~1Yb\{beSQ+};@ r- 8ҐƐP `2 ]zʳfֵ.#['n#xtpwrsR(M5ޮӑާڡg<-$F8o;4Ł^f4A\b!s #nl 7b^[#Di׎ZHoH{+Ae;6TqLbV<&/Aԧj5@A[hxߌNٓ:c9 5rjIKsr rjF>UA$$ vp'֭2o );{Q$RmgDqRH:0t~1ڣ0&J :p}L]oXPhb e +IX@&*ʌ&!jiH,$ݎئp`޵"x唫-P,ټؗ9*%H7f+Kq(ipeGvi-rdٺܿ5mӊBX :Dv{*ʺ'4|2 SH% !]>{d_ZkS)i4.椳iZBz>ͰnעiZ|`cm|#X]UwШpWLːGSJ= kdyWϜM*M"Kr)I-t^kټe-Nʐ+,#1HXԅ=-IrKsռ%vW 5 x5Bأ `V#BHlvo!_,«F-Q}5<6n,r{ h%PȎ@ȇ6;#r1Tf0gQ)ϩ,F# GV|ݒJ`qT$ niL}VIH[M 3^6ףdc3g+<"`ֽrx f8(If`B}jbv9C1|׳}~l]29Vna=G+$2ޝR4>F-M$a52RjD\;dmbMlY) GkOj66l*3I-OnWv"kM *Vw"Th";laV (<]ʊJ{ӶѲj"pvBP`#բH,HX0fRSK8,犕@2*~[4) 3+dkB,7}jyِeT& 9v [ޣ}Ri>Rdm8#V )v˅ޕE\cBa}EI)#-ҕWl7_JE!{Ո+9뚩@&E h.(`>F9F7Кs҃6Q <pjqVT,7u9OZR7Gzd<hJE ByR8i@2yU@aF2qK8iUIi xd64nE(۞(oŠ\iziSq p KHqӭ4HOɠcN8 ;4tS z5,t1͒Oj2RխcolLҔYV̈́15r56"P;qZ=sԚDriR31#G)Zqc$S m㚎>J嘔5{ o z2TRA$JXRcփ:R( bh٠cIɡv0)In:Pp)ț$` UCJk1Iq\mQU9%h+dKk6-+qO#N@~cyLS yLɛAZ-m"YqFsp3lD cJ )1q99囥)4 qMpqH@< b v (曆DJuҎ~`FNŴЧY9j|-dHp\r)]cnfy*#6kXlAcxn*޼V䴑HҝNa\0>9NA]7<֚.YݘXnעkU͔#;JHf@Vs:=ױ+jF$Nkɲ wv>4wcE+7\{ rǓK$sQeZnOZnM8sVGsM4XeN>emJȏ.hwƬ=L /"Yv']MH>Sx$*TԍP]bGq nOqRڼImR:962FO]ՃTjF :ȣwm_VlZ7Rw?'yxG9oQSrYw7ПCUHܑP}8[''J9 T/?,oL5 [.=XMTϗ? .4﹪"@!Uj; ! K*1\r^kx\ft6G?gEi{U8%jQۉc0ig.LIvq~5f6D. CȨʸ,y5&(MG"2IEIkcqbG|f&cɫBO{KJ csa7z, b;ԛ9[vRЁ@@ 銏= dqPRH>`@91R1ET0f;I0}h"d P0Q֤Ziv2c+B5\b߂HMvlE* s+ :oi-;Pk 0F¨: ͒{Q?ŷN [2@+ڀ'UH<0|Zb#JѶPgڴ"c$ V^u[3TYH]hiӥ2T'NVVB%4L<cc]0Mr f"EFҝ^, !h3dpy5.:C6*8DH 8 2c5ṧgrTf4:R/QG+# 5QJJ`]8N3#h"(WqcʯZX581hA q֜~IZfc~'qڡg╟;@H9Q#$ǎ֑BIBh1p%F~ (:uelML_qbHKd(-S|*q5.y‚Y4rq bL4\Ua)Ð3#ԊT=꼇g +1~(<Wcm&V^ N*ykAmM1.t=.y IbMXUSZ}ԛY!BI4ح cqPI*PpFWQh r&>#ޑR2y*xLށ\rF8>0Q`^mq_jQ=)x)IPbLeR=2@")jd)P)Xu TcYڃ7vylvcɥf F<pO@j"yNQ4O 9$xlH} ;/&WqAq`tM<.T܂RC8=RqS p݈( r`uZ T^㚭NM LKr[FA4&g XhsNY]%ZݤgP4Cdҋ tmy X #(N{R2 C&?)ymKFL{XCrdHf5edJwK"嵪. mK$sHI-;R&F#Yn_:Hʕ8m.6q֨BsM Rwc.KfCwzbMѝzyRMp;VSڝɻTlV} CN)+K#X12E .b1uWUS}ETYLҳV.Gli&uǔCzU,%aOc$rwzոY'޴p5攳,01UH֖6&AMI$)$ZiV56ũl~_z7ʓ.l08 Fꨳh3.lehnszec5ӃY9I؎IɩC`Heӊ@F458P ϥM+a5 "`h-!6IJmRRH=( $"4U|XvQSFR|sHy0F#Xzbsv>!ДudǕ`%$Rw=JU6Tl99 20jҒӽI#;@HӨʒE=k6 >Jb.cWVo—P! ǾzSJv=R0h$@GZqoJFSZ&ހ!gqғ;~w<{Ӑp*%;XVXúv 9lT?2>;PUD,i~6#*{U`S!96aJSI8.b%ܠO*ɩUR1MBE!\Ļz 2r1ڭ2Jx̩P]w;q*C3#_[OĨ<J*/"vPƁbUxWIsb&2P'9 WluQ΋J $ ޒFapz +(EJ@&czVGJBt]Y/߫TѾ]-!ғZdSB'^} 2 z&qӾi"ʸqzM\#'t|i,EH8U#E-)(=k5o [_LaҼYޞ[x̑z|zg'82xzU)7 HN h#5FKgEtݝ=8I]6uW Ғka+=KaT+SSrv[ViJz}$7AZR`&B;U\EgnUcHJ)\{Kwrώܙc?h du2|jPέRo&\j9./ބ'JC62ŹfH\b'5r>[$pOaPg=TfL(e "ڢVSmFɓGjEspzGql+TEW| 88\FI'͐nvQү]K k5ZyރezJdD "M,pA*ʧ8G9g *Rny9R'BiZk@&7=jq5 E Nv⥖ Ro}#"#w5y*GǡQ=:}Z.X?Г X?=6TQ9qUd g)6tN$ĆV j{)#E;26Z=qIbhr"TXQPWzTp*Q‹eҕ^TeHl ̰BwܠbdI),si[zSɦRW ӜhѴlb++bm$vW-Ґ*ը O/984B|SpGNV(&)ܣҀ4.7aҗo0s/HΪB$T20¥ +48Zp*PQл[Zg|5=w.rsJ&ӌ"y7haK*j :s֬rz.-COvqN+i֚!0O\┰.O.)c0s/^~cҔb;攆,AH{ qf4vu4ҸnR1$ L81G0AHW 6ǵGZzF}%ޱ|8$'l5o=?=6-ںRF'֣dqzFv<^Nx'ǖ2i]1E H5l$aӛؚٜ ≓|yfx"rEms-I,9+bIOZFIM yrsIz6!J);!J3&hb R(CM ]^@#dwt65qV5ǁJy8xb*CfzD^'xVI%b}1ҝ/-2@9F)UX5v:ۿ]g%=L澝&Ԙ)zD(fNs[L xe;((H d-o+:XҒv՗;Aأjwb6Q Ҭ;qҮYC"GNh BPi6BNHeۊnw?RY8Q!<17dqRyh/J@W 6#<Ѱm[CHJ[ji1QӚL]LgNY>l 3;z V9M1rZ#w^犀32RHjћ@Fs{S1FztDNe &ϛb'.qM3ҔåR4u)K`,x4ӒK(,1I5wsҞW#)81 'iI OAڢd4Q8P*p)@5 -0{U\Abfl!⪜䟘 ,ք ig cjұܤnlZ;ҡP&H;H4dPj c<g߰!?Zp#֧+̌YGhJWbRH;f3)yvTL^).T,zt"61>ɂR͘\Ho!W yb#kaj૜Ԩ+) o\W.\)B #rf̱pHPmDv)9J4dtWL/dϑqJ Yj9N-UQ&p#9+4\ l q`(SQq?xHX(:ԃo#ubynhY9yPi0E-$b!bND_2&|@Êݑ>fF`g9a]ƪ|Ì{UpyV`5Sd#Z"h99W{Qr [F6Xd8< w1.@.v3<}JkHA0 ךFeV׌fgl#oqiyd@U 45XNI$lleI 5=Clҁ\X8Y'*F2iJv FhT+qfIm^⮭pz V\^Ό]ܯJpMݺԋj Җ8V'ڀ+}b ұd VA5Rj`A:A w?K3ZBv1M8?ył=*GdyWr(-f$8UT!H[A4%sZv|jR ?SɹX>@K7 PLh]ܴ4ՒRR*\Փ8eU4 2X$ PJi8h!G皏98b[*Z9=YN3Mb<)Ê *;IJ3V>vn0G_tuRD~jr)Ż#6f>Sj̀|Y%5U/Wb,n8sr8OJW ̷j\lf7w*|c }jZQt;;`": n*lI7h79fx<*IWV UK9珰C(b{P#$N@J+?p(etePu2Nܯzb 6K jb.ҪI ֮IO4IEؾ r@OR`XQʆ•NE6Jd* ).dbAM@Ś2H?CI$g, FYrhnYkrWp 1S,j+hcR?qj]N94߼9q3caGN֔_қSʃ94fٻS㡬iFVy3G'T_ZA?QۧJo7uk6RomXrF2qXءƱgj ֬K\̄~|-u${ǵ5a>nK]f9DłdhK\[ɴżw8Nw;`mM#-q9#Gk29Gk 98ZG,(rƒ.iHbQ(Pv@jXaWqV\s#oP1#QL!N6@\$P% cǭ+F-#b՜);'ٲ0w 5*.y%Er{TYp60ME΋෈FC/AzQڑZtQc؊l5kk2ajҋ%nIW?ܘa?>n>)g=9R5ZW"\n{ԊzP'N5c͑*&<";!N{iG^FcH HSjVt4dcnqM#i٤1TʤsUnAۓR~2Aʣy8S[+S [F*)0Òjm@9L ;=Lk<W∛a"N䢣vZeȖ ƥnm/_GQ՝qd RF˷Z #"SҘcA" 1JNXI'%qQ鞵iK9-2>rE9RŘs'AHˀ<0jNW`SO QoH I< #!b'HKR0* YYvb}PI H# ٔXI$n>VUl>L3aA]'&N]N b!uh3ВzQsvfA9Maz r4bk!MےN0j+Xuc5cF$0$o̫ ]޴{Pc@xA0< fjpAm()H$R]Ѱ4V2/0)I=3LP%By1P|SEDX1h<`8K8҅\N,cԊ$F 8)$#֥`=h%@089 Tܹ ҭ+ S3`#"h)m<Ӿjkd:S@$dSN0zSqN'3/z_z394!SѴqn9@M\u}i0TgJg@ jpTb(Ri%sCBFh08ԙ m#`5Ј>7nKҁ6On)XN)Gc~zsMTd>1oҙ=zTA^P,49R% 8݊s:@2i9 `1IP{H8+֞䤌r ,1晼c4s(=F:lw暼7\(z f,I*ȦcwaSj@~A4.H5 %둜B3`!'4yQ<xwqҗ4)sJPp(ia\ 1ӌf+43Hw*WޜJ$ܿ?Zs!/˜ɞE$gғiqQ34C _T7TM]C&#)H"x˫<{D;ƐqG88ъm9z\nשjkLh 2Fڤ1jrĒi)*\4)<{Ԕ0MwZ@A9Dl.ri92z Bӱ -L "q5:wg(b$UH㜊^ S'jK#͒*UE&9V*x\>ȧi19'&րĶ3Nӎqڞ#g}0TҚ٭޹Y nb:W!@^sP .IJZj&dIG#vS\ytPyyLj%,9n%a ruDgv3֋ ݻF3L jy[{gªƺJɈǚhbiJSITH{ҏJ aE-4(ivN4 ;zSYۥ\Oaj\-SlH 9Uua!kr@& 4qF=+'Sikewi &WLJށk,ٻҺ+ɶ◾N>`sAQއRA92HS+cp1J͏U&DrGsNV5oSBwuR@9nh:-x8xqӊnSӊy ܓҚ2ricZ_⁁c 4?V4pϭ.:dY GaCSC.ig`VE9LnSg(zRD*Ur: *Bq?=(Y"[ӳq(Yjƃx ֥mۆp Z9.eGsVcS(OA(sV Ϝ:Lm_"ݫ[` (0]m^BPOX*\N٬~mRYܭFy)0`AUaOz0*>j[>2EzԞC$f=)]xiEj8*Uf9F03֬hRLG,~TȘg_bXĠt{#J<TtJQ6F ɩlNqXāIQZ!}II, p)9e6'Hű,$4`~ex"s3ک"\[I>a⠆JLEP8)Lr<|huUg5#1LMIJHg9cLIc vC`ޠFq`נ8?.Ԉr3kaSVT|4"$Im&452I61MqM\q}å0iwMɦ;m^h,#Wn)x@Imp9~)7yjb5s$>^>cjP=)c@Sv/1d1\hf8hN\5\e 8Qҁ4! < rE"8VtFQހ91/jzǓҐh(x@o,aҙ+^)[;O#4(3RQgM}֜Cnқ#9Q( p5B sɩH8 T =Ihى֚Qќ@GrNxU Zx`zDIHLoXm S4!6Sv6|F4"J[J* Նe3kQ0 QrmCNl)ǠE|ہR٬b;+p6`xW =q7նzoVh0iq֥LTTHJ9& 1N ㊗*%ʡ$‚͜S1bϽ#>۶U. SC!:jFM &F]$: O3N>oJF pYp|̜TRNCbzRR9ZL+ȱJHү>jVMpԹE*!a0:`USjȪG;dKnAU#hǭKiprE2lx0jQ VGf!xCD1)'Sw`6+2Ja9Ղ44BOJZPx<"6NiH1Y8A4`n>OLGJ$s@. Dq[j\ܚO&gG¥Bfg SBrkHьvFr&U8;[1YҡU*ĪnzHUʊ^~*F&NsԪ_ SA X{` vIⴭxU,9$ I3s\S M19&1`hWxAb\(*0h* M픰"q! *J4S341PjFC85LzbԆ#Ԋ˸1ZNF@Ɇ8*0@8H 2n)UW$\֕[ ւFG844)  :Qd`Nj2p~T{C99b)Üak6LI);^q~x">YC²8n=IXn]| t{%9ڤ(4m\iw3֥S!pFEFʆec`vցhjݚ]i@wPMDNwKkG>BsS{ںXխEݤ6˅,kZ@܆❉4>n~aR!*U%!VYr ŭOVrhPF?`۳\m}=;J0(~ZІe|nyd \{,FbVd] L ]z5q7}| #{u*$sQOWXwd,6O֬`@&[|@6XgD~jRij;8bCi&Hz:g+RgĀcސ` rjDRTxawsMcb@ ֚[nz+-3ONpF+5;Cj/lA+yGǾT- Ү2k>VyRn\Uh75؜FdnMO!vYP}@.ؕ-zSTTcg6(=8ߛ=Ac݄rL|o 6>Y&{:$^n9>sko$Rf GE.BuT|$VX b(jqQ)$qQtМfR(%A%z.ܙ-nA \ L c9M;R**`38 M 7KA*nǑWoJA!sւT$nKf]ypx^>r@4e HiUh,B5e+nRP& 8HZxQ` G!z 1U8ݹ#($̀ Y1ښ%J9OEz{7l+"Iҗ1OH.4U8FwԈJP+U4H 4 pPǞ U7Cݨ3 J9Ns@0) ȧ)+Wp@i44 ȣN~@EZ$ƾZ@FQĸ%!9T* ړ`vH6݌:JN-t\ X,1=*eч讔ynIW[{vb2٪w7oJԂv&wh&ܪBo+H^f,IQ dSF\o> t[*b\KK9e~)Nbb UX[ `L˅KCeWfv:b#QDQ]\2u>++2kc 5i#{&MukAqRAӨ,6$F Nd{iXΨ:kOjyߺw;'dIq$o|̋P s si7z NW4P$wiTا"BM)yQch0L`RTQ+(7h**)%Tk I֣a3ڀ3d;G+D 0R)X4e1A] x\Fa khb70>svG$V|v6JYqZAFNK㞕UE.0 rAW:Pd7bH~NR)sץLB}QHT@L3M N2h)2 b6=ġ Uy&h Ov1IAS[Y*KcH$BHQ%iѣvUޙi2S aK;T)`8 drKR`Q KT/+s44$4C=*$ye:K}Q+ ;bGeD; g wzUV<9WDm+* $wlRk֡0{q%UXpXtFZ-{?IjEj,zLZEkd+?Qe^9q޵nIT5_"IeS/$ jM-$Dy[JO-5 2wҬsRJ!r1j_3$)3oe z*/5##f]ڃ6l plR fH& ڥ 8'{sM:Ł>`p9\ʾYz%6:{Ǵ};k9H:3{{S-F 9% 5k69DԴ0”isRq"Ni6HMV*914sҙJ;‰qL=sKڐwMw4fr4 vpsJ838R@' h8+L% S(H4IA\a"!QVaR7y Rʉ.Nqڜ>jiJ֫5bCRTޓnRԊ x&"P^ݩÃQ# bGisiyhݹN,rE0)0Ü(}hx=i$(-֣ f7$Rm$O\qH:q5 0r[CL敊LR R 1sJø̈́f&sr1Q@'") l.HǥFY7 LsM##9i1 1)Y1P1Gެy 2i`? *`iŁ>O@x46U4QsG] _t5>f*ztdV!W=+u.YQnC{T"|Db.z*fRDR1jE `N:&)NqJo44yIL' l`(m̀8tn)ց66B7AHҫ ) P>4ҭSzcj"UBI3yjCs"R#kR:zEB&F$TdD@ '#wҀyLSKcӻG=ipʁM=F)H\g4wO)9A-(qW8sŪDQ`Y6H*YFVgI,Rxdjt.7=0kt)E$ѝrK&)g"0k2;6MU0F@IxH%-bIliR8kt C `.sA)hi)ݩRzӔ =y@UU_?E#&b*r8*J.$W}xT2=v~QVV0orV#A# +F-5P"1F[*i9U[t^c=*\cF뚫"n*JU~ZKɢ__KNTn f̢DYOzu#JbEndn1\Q݆Y iǻ<(zRV'A$.9ϧ^izdV ɤ88m`A@ PH},y"M!v-j7ف^*qҚ, 8iZso :sHcH Ӣk!dP*wtd8;M48FZdLc+6@Vni^4|q,WSCSi4 Rs9\c;zajq֮DڠṊ }nL&~ϒ>) rb8TpNjHv5_H#ҀWLW1puk+H/" Bc}$ZHyH[/i|*PSjf,k8' ;TDo)SP}hRi7/3;HQU#WDlU; K`MRcyjLFS8'V0_wMv>E`IF2zc4ca;ӝq rH+&Hϩ+9fJr1QHTuF@\P.kc MeޭX@xTOa6Qq+eHyaVD̀[iZg,yoV2 @aS%Bd.٩ $9)3K?7cdx$.1ڳ%eljTaG,&qiDjRQ>Q 1|1\W8:SU ?d9ޠ#҂zރP*:g!GaT LNX pvl1AIӃKF@`I`s@\@p);OJvݽzy0vEv?JNCCc R@XN hHdjW,B:zQ3Z24 cҜXCŞJE:Ug1Vl⪼ "̩1LQW^V1n[j$pOxGk[FN*r]Tϗ"23SG$@aX2+ʸ(fDٸ(7ilޣ3+,Jj9;"Qi楊6WOZ] %ӖLaO$wEFrEԶK:+d+>_J.W9>IA D2Str5R>3] ϥRg;ϒ#Hc>R\'OzPJq DTrjgiaFd'$Er9CF'> Z#B U tuNA*jue<5gI@G&H^*l`^P!a"&8nFxzZ6-m! %`ڄk=pk p*f'`=}陦FUN2ii#9g$.X zPRd;d.G$q+o mjXHjXUElݘI!Fj aDtM TdAǵ@ ܣɶyFҲO=Oz!Lt瞸B‡;!pUzRHu%[ӘAڜQdUq)ʞҬ 未v + JVMR#,&1;a+tk%1y!.I?CnbF\Q~ƥM|ңt P4@sHdeTk.@4CXN Q9|j@BXU)^<jr|#}(9} xl`s@ " #'N6ȦH41݈Hح(\ӊn-xcBY砩qb~FOnԄ \s4biX[Q>I4Cs:R+ cFXQy0@v#Hk N&<@8:T"g$y(Xp)⠂O2 R6<( yi9;Fq(9RH~B1Hccjv0'N.+ڽ9 SH#p;uG_Fp 9c&Ӈހ88#E<)<ګj@ul*)ٲdR*;cRbpS2984rMPO34⎣ NqR 4٤֙,Lh9dqך@8v4ny*dW\ Ӱ@ ksJ@ ](j,r}*V!x L`}h޵&1֣cȦ+l44cU)}qxw{Q2N($Zk zRe!rs$9B`1$`T2ЈSsN*0Y= H⤦Hq;~Z_ 9"D$cqSI4ky~+` mJ ԌD)'$o hLqHQO4 Ӷ$@K1'({SX4b~Pwx;q8#ȧsMSRgf2JvGMiZnpzq@l`Tn `SOғ UrEa̟ӵs㙾a観:(lOLwYXbBbFň>9Aso>{o1r-3Z)zёJa O> l=I(uE52Tڏqb9SDxSّ&i ج>cҳ䴊NtyڵIVHl+z4:+!@^+2IA ˈ$*Һ˙|艜0SGjIӍ4U\HM'Zq69%Z=xjPH4- k>cLxZtDDZ렝]*єLp)Q؃UQr򫹙4r1wK$M#V%\KR٤ ٧kg~{+-˔2تrM$ sUF+73ХV,MH8`:һdUg5s{VRw:4ѫnS#Ysy2W22bLSsRGI&64'N)<{1 )ɠ"uZa#n/R i&l^1F6:SxqACIbE5[ *Rw0򦲝c.F(bیo85*)J53fop,$R 䚡":0`x4ֻdn}sGztNR&r}i;UK'$ڌTK/#&cS&ˀPM8>1  BSFӒM BA 2VD\Lh$$%c"qL|3Brpw H~a!*F.bWGZ|Ƭ[mLV`v| TN?R9d>0|LU@sKr['xxf֑cX+</KngT+&z4ZLDwc\PHe?=2w`HTc"oI)RX:T(g eUOn,Șܹ{R"oefҧi`Uֲ/u_( Ȭ &yOjne:\k#qP-9eo,' ƞ/K ` >;A5~l+ mGipLZE5#!@>Sޱ-/1W"x$TRFp)RT0@ۗwBe붩4M*Tu.n;ѓ&gm9a^Rq$Ȱ [)$xt=O4zq@,:AU~WMQ~NЧ,Ve 0}j^G 384LXL bz欣hy"T\n R0Ƞ.Wpb6@?W>n] " &LC#7'iO\ y NcPKClazRcړkyj649H82OJn3ؕSNL"0U2yR*(# ӕ@+J;)vhP2V))C TP;\bP2Ui3#|Ky|E@Ġ޾ HgڢFhOO1Q`E*B48iG=)fg ƅaSEn<cR IIqՅQ_j U1rw wz xM6✈͒Jւ/iB Mh HF&=vπ2j?S}@I<@Ȧ-' YH sO#52GCJT8cR}T\1eQ5)0ޤ+279N7ݦ9xv94rx421@W!IY^qP&vJdj *rJpzPG<3Wq4pi7>4o3U[ƤSr3@5*G5{p)k g!AJd^(3U2p9\j"Ďin3LgDI:rM؟ȤZU y3O!lvXQ`c1Ebmsk&WTȤjzR TGF.>FhHP=3jn}sc拉" u r:F$nԛxb@څ/JKۇJU#q`j$VlSISD6nEBJRARal$y(R(I6J6WPϜJV}\M 9<5&nDbA;kVO\_K+Xc$S9Nvޛ5XH1wr@CXa~Z#D\P09c` АKBJT9IWr+qbA#Үӈ=R7Գ.j"#qYwzQ&f=AV` O6X*qUa\bE8mҴb2^*$*#EjE^NE4gRELv@TMQJ ~4f8u'~ #ȞZ7^zzrkY =*doFdfutrlkFN :Ds׵.,Fꦛ[E.ڌNc*q)y 9XvmE4*b63/Z}̛Wb^2rhRb2ZtIk0v*%9wAM$sj%AUy#eTmێI޴ bT{NŰne=VV[G}_nJ/ 8 iyJLLHܳA[Rz<4M5ieejvQc՞*+c|'}zUdؿh58ձLbm@:f*8*לABjQT6!j.kC*&j`</hu`El5KV ӚLޛjA99w1$h@RvTZܔ80p2h`2N Hon \'4g8 qB&YQT_ƫfHsүz$xRvמơ) t#] HsTC.1Zŝq4,G5;.r8oZ,ʞ[& AZpyo`8Rj']'P#Io У 7;eH0I SAشa+drj%e#c ‹f2b&xsPK(L1J& ;'ҋ,0cS9`%n}Wk:ָ󂫓+ش2AnľTߑ[wrJch\v{ ,GEvbX0}Z8ʇνvڐh&mb潢/ijrTwdiiÞ'#(F t9 o55'PʜfnཨIr)pxP2<|ޟ#FJy4HS$qI‚@PM**gz,gsY;GfEd2!'tɟ'w eM$Qzj "yv,7qQz ͵O4қc8flNE_BHdعOեd5G$֥9Ag<ӳ4Ni n㌚CB~FPRRi4˚Bv֐ ׯ_Zv2 ݥ`y @AH$II1RsHYQyC-;4+`[Kn9AC`t>Z9&1a/4$8 39 61I mؠWr8$Q 7(LzjۑSK8Up4@1*/Π恈A\R)rY5rɴt8m hcȠ  0" Ӄbc !w7' PsLC_8t8FOQQ3<s2ڹ;"rq]#!u7ЭݝŻ(;4)ZF>p1#8+ӯƋf$.q]s}МSk]K2-RrMTlެ+.3g3'tH 3"SNUr n:Hh|{ F\x`9 yƅG8"+zviY&ݠcq4p4U'AC4c8uBH2*Fϖ1L4)$h4tN:S4 y^:'ZG&NUg§H [2DQ y}++kUJf"ĨޕMpYұS^&&9tV&䲏^@%8kue H+ǞGqL'|90<&!t4 ( N\SzPysJ IS$gQH j\.4-J q1\MG$.Wvek:=qP晬iIkcOD6=+Śe*=+핅c51جV0Vre*Qo$jGBlI lCſ߸'r2*ȸG'I6Ez=-i-nwž٬'Yjs+iOZF 2w6!B1e/ zTvhGucWr=*Jd)HJŋI9 r*:FN{ _Mkxuf8{P3cbH洫ۈ@wGqPsElsL9I;yf9!IJee܈z|hL~+ a})$cUKLAHNqk *\o4tkI9gZH|ЇG-CB ڥ#;T1pEY܃U.(99>^3 s(cY[ ⮫4ՉkC7Ε=zz+;dwr-y̘VmRnV؄Ƃمc,B@zԸy"rQ\ޢw'i\̹]ULNHG:T.sҴ<겖č@gT9@x[YBNz 0𨱸߃DEoGo λH 1o(B7π"eS2ʛIy4M1]z C7m}i% qJJG$Pg)RSmaT+!p JP岃.!qEvRrG&#U[@L0,Q߻.HނwV>a dn~cޡMwz4~է0;NID4-4}gV++P~jViَkӣ *h(F*O?2R|JzyDk7SZZƛ$t6g֥nld1$2B#msOH̉C֑ NI*Ј0ISKxzTe#ajFnW#\ɧr0c@ɖ4C (9m*Bp)aq0:T#4(ATg2P4,\!X`w9WҀh$n2FjL~r?'L(TSw4Wbq^F*3BNO^jpy&Lm+ͱ< ?E?J ƨ^ FcRKzC(j;VuviP N`5Y8♢؛sڍ̴+ Xe ^K`wS9T`͎j@I A@\=GJʪ)3$gҥ` A- .J5hg޶~\7Zd͵fϥ>2@uh/۷R2ky;>rKIf=+泙ׇ\l1$^i|#g暊0NJ$ ޣAUid>b 9 5 rK䩧rlM.C0z* T+9x(;B qK?M*jszRN>dnKy&lMMi:<ּ=wIu.i_22iaRTl n9WaݞҤ[pX<[`zW40 P FAZD>$+U\V-Zjo~A{? Nkp ҶC[L;kt-$8k?< w ,ਮ˨sqSDCP<V`TzUsNRN UmW$i/ʸ?/z.dnH U`N =:U5M&˄;/-t5:LTbj07C:O2#1nXQ+ʐ,X#O3n:nFh2pS8Tb*L1֭T 6Ul} K(a"`:L'#lFq$v"CKU(ޢwe ׃@HU++aT35=UVRgj*֪>pXdR* NAJqңx#7):oG 7͜qU';Ee#GH̥nI d,zԖ֤H"̇8l~uW©P޺R&EQZ(Ujr8k.{V MAqlU$ѝ+q)Y2mԪ2J ٩2v`՘2J9tSF9&l<ʫsU+:^MT,$0lڛU2*pj~h-»fR92b+|ڂlLx:wg}"W,Xx-t0NG4zH"(Urj4¶Pgix9ڄG=M 81RGNX1(籧`H3('ҘUcpfTR('(n<+umLhIÎNkgG+71& WL2MXUB(= 4qӃezS0)w&dɠB M O-tZ@݆.[O/%O5`Ed*Jv'$Ln NH6c&3r1TGxܐGZ3Iȋf`9z6\A>@XdR,m䪰^"$c756jsfaÊ UX4\?1Ԙ!A*%d+AH*V!cY2qW{ɒ6ZpO^*}BzHޔ4cbRN) )yH >Zlif^ CV(9\ dA)y 1XLTa]Ɠ03 CgZxrgL"h~YQ=@Z5[\FJǠDafޠBHڴpFP$m ]?\svhGͫ;eS |NKBAvIHÆ:bftFƤH~؋#eqJ4l<5_b dg|P s>Ltqm# (ǔV.'+#:=bH~@JI1 ꥰQ:U?y8cw4SE=|67cںYs\c9d' Wl%xT5sͷ)zU9 g7]33CՊ1OG+tޣ$zҰbqR0Ǹ6z18@E8#`'qnO#ibFg bmF=!Cʒ h"~y>Ԙ Gɔ~4CJ HN`bŹ ` hZr1Ugg;UUّU&cƖ7Yr~bOJR cKpc'n *vu!U'hrB]%+$1˛4ϖ\̷w .G{%X CJ4Pt]|h<41ކBvBR1ǮjH[kc/Z7ЀǞD Mjd1)fr]w }jyK?J5G=yt iz_ts`ڿZf\'<ӦS$q#oݑ*ʕK.=e[sXb!ۗAiQoq@ &Z$+~=u>WT`+U234 TzU`U:& kتҤ96-#G+VXSrc 00XF\!*n!@beQrgJ+qҮƯ4Q`V6^j$ɥO 6.iA S2l2M[XtCS6#0r>Vp^r1SHG4 2‹[aTH o84nn/Jar\]'jG"@B\t%㠦 . ~V+4*:I#8"@֦`#98K"2XJ@3ʨ*cF0]d*ST|Gz X`1O 0 us֐1塺Fێc-()"FHB=icNq@_Bc `SN ۉQ15K'ڧ14k@^IzՅM`76)܎Fz!?b% IiM7"2h69PP9G$ EɡmO4й_4$Jy9Zr G+Wڹl+pe<ړ*uF;5c#}t`ئmٚb@ X6vhnA®qJT޴nw w6HzA>$*&D EU[zeS&@ *JC>m(*qPy1ą+R~qbjͩZ(Yqg^ڹN:s!iAZ*mbh55Ф&,#cIJhȹXn~aXD31p;51͖F<R)AA#j[nﭱSTYV&fa)v:FlXT05JU*3j]ρԙUwmc Z7!vF*X⤍PdSȑ8 ^JjFia@`z.fԑ1 +6IN“҈&a̍֋ɡ-IH8?-U|qO2n@(&`R$ Woy< BhSX0j1 -*}1(X#q ٬TD{Q[xl;j^FĖN)S,=+$x.5f$PzW%ӑULߝc̄≮kFOebߞ68LETQTp8byCJK`T){T,1S"GN* &oFq]n=a)^zIDq͞H<=^7,c^n*xFI|NhdhHL'XZ6i0p8,H\$ 8F[xČBYM05DW=5jbGo:楄h=k=C%4'!if\ǭ[a(qLrO t42H tSv$98Eql ei2Q<>YX iJ6:iUIj]'P.nb Ȧd{Uc!:ԃ9SQnlMCʓlW^=k=X:h Lf̕]ɑ8 rN)yP5URU"ՔePCCi Ӂ#4Dj|HˑfdPjsMv3J@AP!c&81F7cƝÎ}jP;j] qԛ׹|ʬ;ҫlGf7A1\/"c4G_#i!, ~ٙ5R} ҍpc\u2 RKqVf7# 4\py=)2'^}(ɥ4bpXS$K7MؤG$ZIw\ΫK/BXF^jW2oϱ`-SƖ#'ҹVQEAWV?Uc1PΈʜv9mfVa .} .V'V,31!\rFj67cL}, @^XsRԪCa@ a:T֥EM2H[8V WךkIsM) UWjIJHݚdX8HW =) r)!SOIQ2:͞, p9yL2J̹)ZƄk` |0%$LlB0R( Tzj9#ґVlbN( JqU4^i`LciztS⃟ʝ+ syj|隫%xlPCz!pZv*&Ch .ir Yk;)=#VZa #Ҧ8" }LRK7PXVy`+3)OaO')c*$`A'w>*LA sE13 Bt qjCs #RC,dtwҒ%NX'զ!b1N9zqK3H 9grO1@ Q|ҞF3HN3AB`G Q4Sp3Y0~QNf%;KGiqWKe Gg{gTͩ_| NF*@52"(XqQa%?L7@LQcb?15_{u |: ͆Y!xQ4s:Pkg " q*҄w qnڌr̝j1N&vy5y,m8-IgpyajhAR5⦶Bq|n?M@Bz hmt"O W}6m}=ɷdz#KJ1!==dsh1ށ&;V9+KҲ5Jgք*'[䚶ebݷͷR;F*ޫI5rHk[D^H@J.F Lހ>|0w+(9PxRw{UT`EpF[֞~Hnq|Ɲ++v« tUqQ%jV4!nJ(88us۸ :Fek;,qZշrmX76A1=*tF Y'N 㿭D =0PEXGi A|*FA6F1QEXpGP#z-"I b";UebWsgmX 0qLhب%ԒǗ02St.’,!P'5FV*1֭L*Tj8-ȩwxCL&)ad]b1Z3[k ;C2t{Ih,,sLEH.V6 -TqKrɔhʊÆ]:F#H=A5K=ų8emv❰d)u8$+Lk&ԱrXWMT2sWǒ!FݏZ׉p=> ts166L0qەSwI7jN[9la+ޥDޛ"X@$2̖Wʌ⻳, ` :hidghj2ţo`U{B]QPMOyizbY&B jxx\.%p(HX;NA*WzՙD$s'&XoMD-80ۻJgo"2!JZT$'T+* p{SH8)aLW;S*ȠzRy 6U*l)Er] [p?[,p2zb%Z,>c=% z%Z)e3JV-HTهZx"ʼnUll^ԬW1 P +~qN $ `?/sR\6Xҗ`!1H@$ĸ= lEjh֭upE4.X7 ]?8{Hp1Z#nESTo 5tRQMJKQmtexZs0ye k:Kife*1Ys$E;F~jnJl⥋MyaۻޭguަD]si,T֪@F# ڑEV!r*HZ-.ef؉0h4UvPXK%Ң ./gܚjt?9mр(ʄBX< f8??$P{#`uV8]J{ x#<^:更uB bR7g/.4c4րhMك֥ pE4F95"6 )(O2҂ WSA2bi@'*3PJNb`6p`q͖a0ެABq{,UzzRCUN`۳Jrx4#w21p252"|⬡SHg[Sju2AW!*d bXT+:z[ǹkLT{漶_, vn.PtM`fPvV̇#7 eDIɤ`Ep(b[ @ GfvK+b4A\hō:aJl"&}`Hr1zTɭEU$Y ݏ§E wsQi u3ws$k֧[a^UM\MC4@67-e*f_yV,ʹZԭ臖*nt1t]9Glⰴg(Sz-W ީĄWVnfUk143 [HxRkZͺ2`q޹I.(]ryZ%'[A6LeGhqWNԚ FyVÏ,`~5xCka$@y\|.du Zsҩ*ljE(% ~^\`7{S չ=M\;3::Ӣh€g*pEU/ZA8k>F[tā9BjG\;A+U ER%@ NV!aǭ8KcOiT6-UsJm@Is3lCj e(clv-LH` TU#Tb>(!V0 ʹv B5;|""<ӳ *Xz7U[8Iw3hJ8j\u$v43'Y 98*\3ȫ {Կf$04M$2u"CMrǮ].qkh=*2ViKi$J܊!%QIVNA<]p-qYڵܨ<UšI;GACU?[;@rWMʁ޵k6hkqk8'hmCejfXaEJ!gvT;bO59+O6H^;d,rީ !Y>])[=i"dW֛ͅߎnjTңFyU )e9=qAI C.YwTcj,gjbd Y2A]3Y8̐])$K (^ PesWV_-rZkXX4̖ͱ 6[V7%&5f2bm%B9]'5I /M $C :w˂{f"$ X7j:|7U "}P" gVHɧtyspD~j&{UH rvm~H SzTFƍ$ #<&. se=sTsvzbΥ=.O0 Tg"22sVK#H* E f$T21QvvZ&AVMQ2{mkr+amO,˼'WG%q=kVlHϻp=)--XUr͖Ȼ6\ YT& CG ]4+/BCLaw+\RhRf3[=m(YFr#ݼ|2늙Քgi1pNm VT_\kO*jnIь0wUmq=jlu4S!QI!'zR;bFvSNSc@[jhg=)01֜2hf)#>2o"@@HQ ) s I4ǥ/%( sp=`sC 1ڀm{N@-62YM Ly2CZ{"S5$+zR)#CC@84sM94 V^ӺF;zY .m68Ž+@w \fy5Oz]b[R95 rN/@#jvt2qJ;J' $Iah` qQ+FAJ-2N)c|K>\ԱHJ9EK<'G}c$2|JsEG#*LLyy]?CXFhk grOOmC9v0L$c, +W8YhcҳZҪ=Ö1'i]"F5 uznvyJI SW[';FL Kt&s3DMajWcW. s+L֔.łUmď8 |*sT-0dpO"YՇJPr1K ;g<@Da'8 i erĐ 7ːWi `.sޤ`"Ҁ" Os@4ŗ $`Vb Xr[\) =[J-ә ؑT򊴬׵Q='NsK v=i{yeB|󃜃K dXPB;{TOjk I 7) HrNA 桒O0$nGj܃(A/`P31<;T~sY~S@vbQG" %STranڀ[329iFдTpzPh[@SZ97"[S;գ bHxZx6O50vFpR\\\;2gwzǨX9jL0c6 zۋkDl# )jr.`v a`9;` U.st41B&9a3ƽ FCY9ڂFu65=2= # 2zPT|0gaLrO4ܺ L"1Fpw!p}ʤ2zrDLB)Xҥg ꠔnM)ra %NH(U ǚSv ,4\qjBV.dK;iͻwQ9n` cʆRݪSD$aSLq4ARD]Z #SJ"$dTMb ['E R0E/4=(1M[ke 461yJ2g a.3?0ڼzԊ xO09ȣ#;6 R2H680Jv:F`BĶhU#p9X9 D*ni( "J@f^q֛'9׊9N`T=sL!``t9F8pFye'`02T,7En}h'ќXS"p2j9hRjC TEK>mL6Tu]mpEr3>x >IU VQ\[Wc͏icγuj$}Q`L1ħ,+o|d@H=괓28QI!IvBtQ)˴/A؞QqӐr=( ȘN oz{'MWMt;փ*1jQM=cE[ba*Ơ rjަDŽ8$\˝NY@'4N5&6,1ҫqk$dsJPZII5!܏j.сSȎ cNqUHH\j SscYm56َMWV_: ~NUbh'xS Yp*(w;TF)b Tp*qZel*unyg&5+/5m+4ATBHkMYp#PtT)S HctPzVD>MknO#9H!yLں{Dm;e2E)rMjxU4a6d[.(<6Tu.A摬/cg TW=lV*V6fv0ɓ^oZi34^_֋cڳ *PƔk=v<ŝ|1␿ĶYLw D*J0+*t A 5V=8II]][3m5uhnUKn@d*awLUD1v2$=*֤4U,jUTF"n;R2sjHz$7HaD*u;i76Sc5jVգ'AA%F@h]6Zή]ָeos\I.1IjDGKy,RDD##뚦]=b\0BHS+&EvbNT42ʹ/eq•$QQ2*ɻ'H--rTYaF}) Sjɤƕvj?SY7*N+O !9lr쥣_TsO1 y XJ턋nhGZf7QY2EUfDUcgzEF`IMm*z*1giq{N1Yؠ%A[Vh<0e6qkzP A3 1R,͂`zW7+үq~Zw9Dގ`Rp͆y;ZY{ hĊ̒=*w )8a-=i/Xw8331K(*V[RB+[3W98 EUl#\N*d)\ӛHE3m!k:V U'wf_&i'd'ny)bSI♘d=j3'~nwTI/BAagҘ1 Hڧ0}$LЫ.<ja?.>qA2ܺ*J|f63ޥCRfdd@28D*0GsRc* K%pN۸piʸ=sH@q86o tSJ;4uPEz3M!~zk%Ge 5@`RC\<S?5#>Hˁȭg95x31k9rAj3Ͻ@yKaH'AD7)1JZEhFI4@+H$9MdL )pbGuJ#,aكE %uSjnipLRA>\5P*EƩЙ"qQcXsj^؏yJrM;%A48 M[,>ƘU ަ ڪ8k8'dR9Oz ~#iXEo"]h3 W7 Aڐ|q+zyF;RsWa[ֶn6v9 .:rc;}qU$b[S8>h>4тƛZ?\S#8P({|kmR#КTpkxd>IxT*ZrM+3u8K}iI.2FN=?N^‘\cJR}tҎVr(9VxftXXc=Zّb2k&m4Y pOV$dQ 늓pd#&( x}Tsʚd`?x֡L!֥Wf bm'9ϱN&98HC2ݧ'(8 Ͻ TEyҧ^qPM!b.5 .@E]GC($A8cU3&Y^"sKe[o#B5Lr efjORskHh*w2ş4XB-a#b{HX=GdLq n~~lEڽL¶Xbv;"3*7TGq 9răRrP)bSH ^ǽhBEg# Uq9 [KTKi 0=9`kҸ}_PkH9 3WqRܗ-Q"gQ;P Й[.0JdL|zbBp(<1I ϰ \4@|Pq@ 1ZG2E?.5ŻlKߤs;3>4g5t#GLTr Un:*`I2 8aRҒ[!S?Ziq1QmjO2*W8"2Ns^sbu"%Xc>k:[[`:sUoss]T:sS5sxnzREZ$;)ӌvg sM[nXprxut8oڵt+’:z\xf1UC":paP\Kv\ 00k'e6]jH]$~()s $o==)wSkU'!,G`e`zR&*pI ֫M0K;}M3v㞤Fs D230R&8*)ϘLc#4DkL1YUNE(FNadB',¢7! {ҬCco#$$nr")2,O;W H1.1ز%1h}jEbPJ#yA"X&gb:sKE2:f;; FX 6MY,,v(F?"s"4N0z椂rPhElSn$>hAi09*D`HOP \׶.L+E]1Yo:BvOSV1dtf\Kn|'Gx({`aA] ;BǒgX 7#;xɎ*TZ ʲ#*&\N>)ޥOn";oLϖFiU3}*+eMWInb~YtKCSFjey1$*ڼYcͻ-Z"F܃Ҹ8L"ZYPsQjlSvfJfxXaqTl^@#]'#R:~8ϥmrA\7ZҊ1 TO( &hɐk6iPb_Q@5jYRЎ usMVmyT=j$vPn,⦹kI*X%p0O ֥ ?I&%!VvE3D)@5Z0_5fm1*e839b #!\I PJnẕ,cv*@=;e$+b9CQRW ީMP?0?0! ۰g$*1ڱ'xmqGZLVϨnnJ3я_JbDeYI΄l8Di 2)>F-e|I4{X2ĞMFG0P5hTAS>]bef q9,h," 8Ske? rn3uDgxd5Urj `V.1=Y aoetԗBTVܰ/ \nE|jb (wo*zў6+DyMsUbnX.VQ菩 ccFH& ZYE$eT٣039.Xjߌ{Ԏ `߅Ko:z &EaSD8Q ݍq8T"2hGep3ҁYI~uifAȩ,dw6L2S99+Y&l]eAsc%Y_ۅ=+;BAU$c^nȬ4u*|ˌV;tڣ40TVYXxb]梸:w $jw6ֲoh"3fwc[dFXSP,Kza )+6F*ntJv}Q#Cf4Pw"XIsKaqO,aEQ?W%Trp*rNJd (ey֣%d\cijE$ҙJV2^'^7$[od6%p1AJf^(1'u 7jв!pHp (wLc iC $he\ 母cG ҁ2"3Sli*0W3'w4P(ǥ\+2zOED'{]8}[v3A ics$e!o@6l,ʘV6`ڂ\TUj)WR8|ҵbj8X5%w,zV E@*`+D37ē~6sȧbQGFs@\y6[ktM t<+ FNivXcҺIQQ6j'-|O39v1fL95xk!H2(*(e=.w`* *K$c+ʭXe"ީ 9Zp^-Q@Q@Q@.*Ea #4<ƼQ'nA56HX.x5=+U1Cޅ''vGu<Oj̸ga R_>q$ ?J45#i=#Ԍl{KNvAĸr~N*+3|Rc-6V]Ԍ8KךcMqHiM& L旚EizP (uz sdKF52@IP\$㱇%Ir[*H`Dm@>v]8Y\+ m6pFZv2I^z<RvyK2b=sV3+n8JGTTr=i`0SJU])*:Ph5U#+R,}H|S>`i$5b`iт~2)dcz>o$zSar;P!vcIeVy{9V HQ)@UjQ&)C2j n@OcrG Icb.sQHH3j0X)ǐBI@xrz(,';8sMf+ۊTy(W`L1*hr1⥊Ղ*p9$UCQOҴ# HmP/LUf(>.Hҥh {P8LItYaT9$fELqΓԶj"E+(`FNyܚKE&D[#&V*g~QM;#JXѤ1!!U2|(B4jp^SwR֨c4qzpZy˓@èۅ|dE<&# R'w81"\w=)^E=ped?~t|x4 ̐> 9lHFj&ԑh9YwiIdPg^YTgz.ܔ74J:Ӹ }iր*swp$nA4ͱj¿w=4.L1VrACrHJ /Uce⚚FO>( [Үo,qm9~WKk%jj6)F3qOVyfڷo0g]ʧoM zcڣOQ˦Fapz2zԾXch12;MFR1*xm=[#Q۱(<ڐ@3I:UsM!)K17@OGոXu1RGޠfp;̀=$GQ3l+1yH剮vWo*u=j+"!#O\63Ү5hA`>M\P1eN%* Aԡ1ڮvB.jMv|ۅ-CA1֘U 9PM" /*1隯qH#%;k#QGiƼqȪ7JYN "e8܋qaޢk1=١N@G'7 xݪ,A< *!Swem>CQS2Y!S9P:֝$b0>憆[xdS"zdfSǡd 4I$$-+exTRvzCd@E\;Z}' Z褴'Ɩ"~9UmhIKXQuʟ$M29f M[Kɓ]:s44Tg(t^$_cEe<j!|)J͒!etwaYp`LqY񐳑pUXdO ŷҔǓ4HlcO '6Jn:x$4R988:PfA9sE!\&aK)7n #`wS 99r7ۊ+ ~^FZʤؚj>z` # p4֤ӱxmO+23r9|G~7ﰒ[,JS[Ehl@-mM5UHBO'Ҙ@# X6zP#vj[t`Z`IQ H8}MA܇1<1Ĥc LeEVi0k(V,:Bp@h4=0GBOcNOsʻ >zf0)#%\}jt!~lv4!;JnMT.pO#QMĒp0ږ)w[sSV%slj0q"avINHXQ ԪO `@*qC@V%Tyq\Sp i!fJ.FbsJ():CM7{yVLRyD٪.U7Je"Q#yOLBwR_ޕ'-1p;6\;0! N|(-ĭ8FPE)`\4G`:vհi\ԛ0H0v=7 , y#lJrNEl" )AӃrwdh&d*$ִRE8 U{SiOJfw7s6xRC66L'2.OZĎnwp)ʑў{?wk=d9"͞\9+q!Ojo5F< % ^wR:+." N߹4+"L낥dr#+O4 rr݅1[q -EJW4̖$@\k*zS+HT +exsMHTɩp3@`0h1g zzU c=1M)}ݛQ%LS}`7B&~blzW#vqvvg_qu5GVGMҤSY1Pt,䁊h8=(7i UpO3\ڀZqP~Z '"yc>\$xl4 "lb5Fx}i9NqK4ڔxJiC8f܅c26QM&Im8)0[HL1xrǥJqKYP]yf2TIqڟnAւg4y8 3&u8)xc'$\2j9 r1H(#4BT#VXmHխ.hB'4ؔN=h0cph@h=i5HK7e=+fL'ҹY\Hڊ,`" @,&1K@ 1ϭ7c +=p(ku1NPSֻ\HzrP4b\T:x.Vn2GJO%vѻ)cu=dٞwvs*LJ x6e(_RASZzL" x1RLN{SS<.PFTЪTv)Ae]xz2NJ`V``ՙa8I+1nHeIu:ȼfN7v8 f^vl3ڱʒ6WBl%s;ܢ#.UbHc$Jid%yofg*'v1* sHAPsVmQ8ן4MSY^ߡf솯iv֖7 0\s]J.9ɓdy6؇p ,P@yc;Hh$ |Oҝ|f9 g6n@ fTϔNjRc1ֆaMuڏ)8y"ܧ/4FU`|I!"/kGzå+{֧{Yǒ9jRԶ>hD#U 4b6@85ReܭybAPHTdՍs 3(S Vc3d*i Y:>d8=\t ںf\i"kHĹ'bLqW'CrjH7yJ瞵|JwN5Ob"i51(:m[*'A6- qVήv :0*z֧H)i- ( (4Qz*Y@XPuB+8[kQRLj]OUyGse]ݍiQswyv$te;J7;sUgx;FWp9۹š,YޙiAPjHIJw*ϒpx@Asj1Ap23Z9l" ќc&aM=iy !8 nxQN"3)|}"8rWb4AٕP' ||v&fnt]\>NQ }S 80j#.+R:vҤPȧޙҜI  ԀdP"n)PFlPKU OBH=L`ih!}+(b dVqբ5G!8ysYfa5/$=8?8Tz JR0j`ricҘ 3t l=FG EDpzP1H$7QH.1A;W#u-.O$hɠuDhHHiMiڢ :u4*El@N2 i =)9sqMRך1'!4{MoaDE&ͅ;үZ+gkuR;4a,1hQJH @L,R˫'^jXR^SFT1ۑ^D"$F߇wGlG 8Rү{4|?Jr3H+1#mf8-s@!c!, `(ڦ&^ [9*1L'/IIx’N <+ysu{h3qZ+ m0Ņ_fmdT{탚p3̛Gщ4iN6zʸ=z؋ Rc-V1QVV@g4:'R.6NgCc@9LN) czv@W1*3Of,{Ҫ֋_'/*01ޚ`\#` xb}3֜FG+K|"RyJ19'n@=)WlO%{T3ԋM; qi;:Q41gޞ:R`Fr 9O&MFAQ8ӭ"2O4 ~3@%iSNo`@3$61H8I'HHa>=i0PJp O\L`SWL`@Fq ;o(:d⁡T,+,k} AX$YwW#,:TLȲj8bW84'rrA:R8p'Sei WEǟkB+U|?^H$QU&(ڽv5bOzx6%1i.Ji{bo[e+TkЃ۠P!F?Jd`AB*MhdӴO;45ҖNO(IlrNNZ1w4LqIG&w3'9>J89Z FG944sMf4֐(,+sQ479aRڵ&ӵG-%#5:0)d jEb|Q+܊4j#*p ɪx!pHLhy/Zni#\zwR>DqKrOZc椴G#dWH U::UYmY>DJ$RFC!\[;yR$QQ-̉"e\H"VP*n l8#UF`M9# '4V1)*=UQBJLh7*|¬XUmbNv]K)Pƶ%]py'XXOJGHePWrn@lTK)ܧOO.Ns;U&UްՒ9T]WS3.6czV\'. H`ÖW[`Zd@fbIRnYUxVˇi F&94݆4\¢LQ9} 7``9^Ru"$@\i'*,UeD~ϵ7kW‱i88}8*r5av4Ƥw;9Mt܎Ք'E)o`:-K]k=2oG85vS9ʑSVM)؄Jhbv*_(H]Ƥ[R[+hȦ@=i:Fҗ*@ FTpj[~3s@\NYBq2@Tr*i\cpLBlri̊qEB ,푞)9lB \bSԞ)q48'(ԏIQ$y`XGT@ͽ2i/cM'Q0y`M[woi26dk4XRO$d1I sONgF#ݝƬJ|n#ҴQb2R1lo56Ԩ+>;Ѱ7HFpia(2RUs*^Nq37NȥFZ@EC0zf?kJMnhVp0~1֘`Cq֥‘ɠ=$E#Oۖ)E me9Ь9WFx&K *C݊ 0M /E!1ZXZ tQr9uQm3ބV,)IX У9O>\xT'4ᎀ+'OrpJ$q@Z.*,75#ڐt)IP-JFi& )3NK(ڌPӏΚx yM<d6ie9=NJB3P;4H8S'4QLb&U:</A"9 ⣙njhWe}pp͛uo|Ul+z߆e42zb1Tg֩#[VbF74urxR ǥ6;XDq*_l֑:gRW&pÊ5"YN+qr~=hd2Tml:AnRҙ4eWښx=k]N=8)HU ~nE/APS.%یp=iӟzCu$] !Ϙ[JPA n p\. Mی &v>@qӊ gHq߯&v/'*piE9sHA#)A<8&TixN*dRiɍB Tx(]xIp \?@N2i0`2q@0 >\ w)@JAqqAarN(RA9W(ZMq=8q:PPcE&rx@ED}qHx8HcVځD}Lxv.pAec3p8H;hjhkQ#֠{SlŒRTPs YӶA楝4+}M8ʖ֘jr ؂0fHQ3ށ(nlX|YfJbp)2Hs(}Tsޣd 8HHKYqj}=C=ZUV8aҪD,: L#k+b>Nx5YQUเy(:W*4R8y ^+)`wM!I9/^iV7#WOLlhذ|j FgZyVRCiGq<$c$V攏+IX1Yh* ~]܂p{TDĎ;6̆6Cvz廑D+5IzH7v9!`fn:rG,ZqƲd;TJt1%X+;WDWqͷ#,mr`l!15NzեvsT),nP)JX$9 9\sTe}KQ#l;OgÖnfwaĄV=kv-R٤K*n99kf 5oF9!$lZ/Orʐ]Ga]N{ղV}VhY X |c+~]OJo]q C&wX/Tby`5<1,_(iB+< c';u{LN֫Kv"xo0\-/X_A2ȍh d7{/>θB0<'Ң*E5G9(v(QEQ(bK1\N4GJwY{#+pEix[2şXZ,q8Rȧ+>c#:ܴjC```V\i;. Ow=hSHt14.TEVFvQ}vj~L ;A!9Ҁ)qL QIJAIoOקZcpOh)̤F=jL{V 7CYjQI4RBeiHsQ'-GjS ,O$ H AHO2ऀ8C *D<3O rǠ9pR^:SrA:R z ݩs4匜 cސH3{uyn #k Pb/,n4Fњj@1)VU+)K$8ZNT&h+yG Q®dufCz F?k;EH#8*9bڻiͷ0>\X ;?gLg5`E'T9sPlTQ_Ϧj-'x .22`6 :biv}x2.sޫIW\I+3Ԓ[8?Υy=Mqe85Ѵ[<7j*Y3ILTLp=(+b,JˆBZe'%AuNyJU ЛxPvF*)&>^TH#^uI sIy2yr}W@d +X HVSTH'-J(^F3PQcҤO23x/+P `ҡo1@-k Zvڣ#yҝ簩u*9].L(;~jV!URcsJBO#4XͱcO5d4 P NmO݁a` !B:{>$RM4s;FE"&rƀHӇҐF1Kx4Ѕ\c@4d sLBtQKP 9ry%Pޙ7aESei2.nۃT֡{ rX␚&/ug@$w{b@ ~ݼ҂){b6r1$jBN1M 1I*z҆DA()qޕxp) 9╘q!ɦ(;)(␞i/LL@ M7c)⽈V9(sO4rɥ#Jxbˎ#4dj`q;\/ˉ%[ w) Tnfͭ5?eC+M!ϭRR߲HˀS%duAXѲfLI]Mh2媺uiކF?6FԨ:(fTQ<.;bQ9>Qv̎i1Iޝ=)$Ž0/#FK De[\Sa#dL!jEFɫL9HHsӰŔ%dtۃ0XGjٞ='\Q膣o?-d|;{?nMVnJ Vg%ʯJ1,j  Ԍ$S2ubZ'Yl En;BԓBp1'GZ|,d)E% pqK ̮UT=ya1F6W3M2zg=HIHΫ1 bNNk1.9}x&G݄\68qQnd2G Rt:vhߏÍQV5?U9GqM ҽP"~3 =I4Кd#z_>QzկW2'U>{uH@z֔EQ5*ia(F1X5.^V2AFwcƽVw/)|kᾡ[FIO"@a]\.d s~egv!iRG#5Z4"޽7sW *!4c\sMPb`րn<йEN 9#21`sL0j5f<#r3 PUȠ`/Iw@S:x9i}:R frԡ;P2S;1q[s@ x$R/z~@)4܊N"$Gu02Q|+5|@Ư+#pVH%GZ7rܚX7Zc+$2N#'r 1I ,v#P+ K Fn w6(2޹7d|aAOW݌ǭ68呃ʣhZeC? ܆1Pl>s(",™ßԊCGIwMqHX\RG \@@;) @@m-9.(?.;|.Z&+ѩ1Z$دwC U`frl՛xcM#~?(3\4,U4SZ)e0W\ޭ#rI`B#f->ҦUh\zդsh2qR*-*ldmpU0NiF4:cbi#?2n sRn$t*9<ЪA,#T'*>cgoHޅAgc8L^= /uurrSce7B$Y ߒS1M}:qIHrj<ݓA!l7Jӂp9 ljdojYQT1HSuX\&]@I7Dh\s)Z@8:d$cP qCc6vE&R{@rCzTo.r>h|ds!nT~df Vl `oc5Z}Œ2})ȗ J[ EԻʌr)\ 6¸ԑZJW!gWp#Kh󽷚@YHc7ό~HNzSc\r{M9 la\(NS#6NE369wc Sg7'n<@'Jqdn~\R ޕX:搓8 +FsQTs@Xyni=JSԅa4qҗvAri;)8|(I*PcjkVC@JKBzʞ{lBX S&ڍyT~ E1"B3P*!&qɜKV|NK9qvIaJA5G+9|.s֑>bM)'/K7hz)@ÓPb)bV++x'؅#G$hA-kշU hF gSӭV06*ϭWhG9H2( [QOz%a9P4K,w6Vfʷ10j9!j p㹫Ӯ쁐=M̻ќshH&ѷ5-,@'U{Y#E ʒ&i5 5yqUF~sYl͋YJp*)@v85 8)0W6TyySZ>_h]UHHй(2jy0'r$^f޹ҚZdjYg0̹+=nFx|"<^Qq+i$V἖ 0zܶZS͈L82T@qK4B-ok>F rI42T.^<2&azZ R)J2I)TN<;tm`;A$mɹzǚQ# Q-JI^M6tSwا;E ,k=$zנʼ/TJ֨r sHȦmo9v۵TJwde+,+hX15zfTl݃WMtVr@S#eM `6bM|ѳ6b0O""nT! > ) S1e˭RkuL{v񝃜*\7SC~Tĕ.H&ܞ8E `sV7 䚑T;oܴL18>b ksց&F&ʾTY?s?36й?jBYaI]IF$V5*IȤUbAUU[tE$4p29(A9"btJdi'czA0=j>"N"̭׆*|mMxUU~z© D{doJUi3`B\՗,;oI#W+QDI-Τ}ˌfFvI&t""6K]Z[f@Iw1F>~䐧b ؛:մ p0W!~rA*~aR,*ZE@)3=G҆z&OHn=T2yZ\$cJ_9EcJ! k4&GY gJ& ,56bL)jŴK˶ 5f@11ZMIY5Aw9heXגPʹ8~ H3OݭSG[ $v))¹;OBJ }~l zv8w5Uܬ1N ΁\=9FKZ.p _Z?*&MMϵp-5ĎvO غtG8c&wgc\廑V9"hŶH5w=jTbœQ+;BjVlT^T`b$<`hITcqnf AKH U&X`.XzW +~okSWXzUd@ hys0~sHsC1Ii8@ixv4 E?ZiЊQ34p)ܞcӽW`Jjǵ[ @0Afvf[|Q1GZq&'jdIt40 RJ`Bp$N\T{J"O} O)V'= Kfy{C[ݝw!Z0iQǂ֊Cp v0d166dJn9WW'Eb@Hc倩 p H䞴cjy21U8R#PrN8ͳH _h'P]"+u0ȨQv6I%o+R)-£n@L bli1899GrđH0IRsHFI @4)'hE!w`zisN''Y2*ɭx']fM͊F5/$*;圛KꌱdcҥSzTF ?&Xq\k;f_4vi8JNi*$Vc*ہ\6ϙEV #<ʊifߑVPW*5u5^Z*84ydG.ȏa$V>`%\rKr3]D*ByM#Ӷg" M&jA ȥIӁ@Pvӷg1OlҞhg$ҶYiOZCM9=2hF=)ӎE0x nyS#`栾f8'Fb~fps,vdS#Dž Ҭ\]|MP6;ۊь^2;iVʊ;4cI FyDI ;U6@-/ԓ;1޶Rď'sKL 88ҹsn巼$F1arQL櫝WҐ/=-7"7fYfSgC;P=^4uUHaҧܥq6ȇҺbpHVzIF*'3Xu!`vS50銴 QhxWϭ v24̪? dg֩,˴4p Gҋž߻d3}(3>b0FL rH4NO4vᜊMئU^ү&IlJN ]ƁP0N)F JQ +QF">%A =WntExRF2Cjc% UsLA@v80A(Uz҃{}sS iXIǵCvI_0r "HG'U]"!`ϷdVmܐ#R4J2T0e,[~>B[IdH*ʁdZ8$@d뻑Vm{y>aڣ x4͓ lTTSG4"GSSeE8&6~c@Ƙ\+㊉}3IִvTv9qC %̙;֍YQS}bc1!ԥ9mzS ` &Ϊ}i؇+1ԥ<|ԛ< {FH) iim@yd }( 8&@xw= x}) )<]lw ei6FLma`= 2+jxNj ;U.mr+F*#q5FX؅*6Mgj?2֕ͱ)ۚTz}6 RMnF{JYCsR(oL( + HVJړ<NKcLySQ(+4ߛw~Tv2}28TvM\663L#p9iq-q+GopkG@*֩q$vUH\Sރ |ckFlW o=qW4y!@vg\ri7wr*F:^V٘mmbETVFt拳U8X1~ ې9ҝk H9ʘ~TGgt=FrB?R6g+kT?+ c'q%zq^P~)$/Aʲ('J3[+ 6)@ƃg+*A)T7etxW13'5%/dwh5H˩[Y t+sکA_<8ԖY&FD;grs!;{Va= ] F4f1V7[WE5IܼE4K5G22#I s}) 4 plxEߩ4 i Pw>#EBfaR/OXqҁ e`B ~)_3rڼ֘|vWb˸ Xʒp}2 mc=M1 k"&k~"sRY#,SkIq*Bh\TUm28QJ`V%@2)ђn~A#lLy@bgp8Q5$a@ߜP)+qp*#(P?ZdhyؽX]ĻUeһmV`=($Pjum@!9ܔa"?} >b#w;b(Ҫj97BPu+Hn=YH6lzJ(,jhl\.ݣJެ`m-ګ4SKr &(sZy%>aٓ*'X$ 7*$d0A5Ԋ+EI֝\̩ {=(͜j]:l=$~bERVô6*q {r:$!zfAZGL.qӕ{ѷvg4F6)ÊD5w$N Fxi%bn wM3l*99TD$O :Ү\})cadRشPG%Ћon qrTBcڕ3ǜcJ#Vj⁌V}ey%4D0'h h9ɮQoj܊ٌIl>RimQ⫗&,qNB28)<=)H, !^,pU%VZ@RX5X|ӥ&#&efwSzFW-|6TI+!v7bl8=Mc.cgpp7/63|We# +g#ڸ]L[{jv.E:9|nHo0T:w4Hލ+ni+ fA3_SH|dTQo\G{JvS`5C"[N 5 uϡsa TdƬ#J 29W3 KB>_K$AEMC,16J0+ś:ⳓ;iF㤍.H9y gI<YiCc}F, sڭ!/Q u٣dNshqU挂`JC*sUyT܃Uڄ$ϥYO/̏'\RaqSbYsdTnb)I>~h}$dT=(LMX+cF]/j™J,$6.}(Ccf+*ktj Rd8] $[3n#j͛S+cDX_nߕHhuVV;Uz֚ߴ}j@|y{*Fj7vFz{ 3sQF\c@ ]S#%{ w` jy:ʰsPW?K ,ޣ֖%,29#),JceF<A #;P94M$xT?4fm̯xQNݚƒZ# 5Ut5,줹j1*E"emA%NiCԍI rÊLpwLYp搕L~_JbY@N eۡ =/Li?}!(K! K!y{):Ozf)HԆhRV#6\L7Աxpw^ b;CԚs*TY`6w>+Ubk?V?JBIqsI7`OYD@G9л<^O8Bj6p@ao 2:biB;zԹ\%dWw 30<P2HO429)r S犌[RsCiH3@E9>^@O PEYR '֢A75yH9Wۇ(-=_bE*`<(732k߆xoZ̎oJ !,YNYNIIX#V|DрZԹQ j=LˇPvT% +FXufMt=\үfo)n0cր .jq3@ 4t✼ nqژ@e5#yrRdbWD%MW?qE#` 楝4BD eږW&vG֑bpP*qS!0oH#^98%x6dwD:Ka"iI`R*['4H͓2)j1Onأ1H47dg=)"#RYR 21Z@&NJi!BmzbLJHj`&IrzRHC|4dvjo)89^zsT!cw)WI9E09uʋ90ei!h,IP9GQQ#f#=$^*v:! ~W;O1WnEr aNtNpZ#N&V$V<-cXuXvI4=]FįEQy|ǵg%lP,rfHL2 ӷ8ڄ)|d 7 NF`Sg=eB>dAJFTZbTMRF2c#5iN6ҞsUYJk6 SUgޮzLjS>~h1J۴NVPsiar8g ΠS&ą< {'"{|eH d8lQʃ$Ơ˾h*0—޳v Qt>cK~̼dy9c-[U3i''#gF*_4+XYʟJT@NXjE@14laE݊*RA ; !'>Z#z sPIJt "=i 7#~Ӱ$G3lI\G֓vsHOzRANQ2 32㎔\e C c KߵF8i2 ϊE[>YRB>1TnѬS)GvD6GyL QeGDV4v.&f@V>ɧ/$cHbbb?1z #^6NzaUHJy9 Xw7U}>mRˏz1,f`n:M@}+β[G,br\> 8m<)ERM?`@ NJ&Qvr3K*iG6@$ ԏ3fNW3g=*w}͇aW5FI`kj-b h7(JWyq : Q(}oxwHTD |䎴J(vϩ4R.[ DXb_XȉqČG=8jUma:Sގ1LHP0)x 6֗4ȊgqNB/>^G4.C)i /MX\҈.@c HLaݒ9U( 2ǭG%wYwU AJT0h[(ls6b^Ǝ~RѭuHDY:i\襈kFyg5Mf,Ս_@GmyGL À~VF8P0٠E`Lr6$cycFnGjd1†Q*4~X-C1/s($O]Y"ٹ}IϽ2[CN@ݧeqM&;ݕ|- }j,n1bښ*|B/kӬ6a9m(' q]mM!V2c YÄ5 . P08v8$*z2[)z(9q;Wh@ H"3~H\gG0GJ0s)`)ax4zeRښ_*\egLρrpkr4A@j } 8Qjkg4ޝy& S$楳XĵjUֳh 4\SIjڣIQ=iv5>Ԁ4&qL}hRJCBV\@ ObfJiYf,jnž& 3UP}*6o^IhqkjJYRCݏJh[c8'_iCn`V;9SsD<.2IXUyF(s֪7#hܜ 8_,R,]lZF# n Ami vA4D@LԙUL`tvqAD4jif10z㞠K zŐ챩dH, eOj; /RcIwɝ|ʮ26T SpK!X'}L$ Tj+=sɠiqPxֹV3[EAA5/' Դ3z5n#`'bzgU.Ð=)f;VVP3e[ ^+džc4mIt`ZZ4L !e>+Sp"b vV촎 T6~AjEIY 7G%Ozef䪕=&XܶIlcs\17&9Bn+deղOs\6n\lTn|H:\7I&Eč>QLJ;֔koH"v`QUh\z_,gpQP̻X|B-RYFCܼ,vUMޒv8ey+3`0Qҷ5ȾW ϊ⍼Ņ=kBCmmIIsM" Zmώ!\r=sTr1c9Dwgڗ jD%O$C!=CҘV >cj[TqIt#!:{ո Eq`nimgւ^m;9jX]8dƙb=85fYX]1oIvC+gt~VrsBJ~uq۵0r d]Z:o,Ukp3Vt槉c#?u,TRs+aiȯ4bG?$844ġ#FPۜ`w< >b("SsgKEp,DnRZBN~҂%ɏn hgoN,NG$1c>f߻ Ҟ$Q3T΀ȫ&.qNX"?<8'6X+kF0Gc^}{Y[nmc­Uԕ<$KWP+&vQErWΥ3mU þMU<{UY[Pm5:䮍&<4Zer3TcbQ1@85f4ݎ2&\TxjíDG4H3ӻSIh#?ZwzC@FGZF q@ ! sQ TZa4 VF$b`94vJЍ:Kr@ǵ! }bviώ7c4E3$"=0xZ[9 R` 7#(4HB71I-@ve *V#8*?HNMRx4HR989j@qOE;s`^3S)p( z F)n)×jdQ49 N7?zTp1Z@(6ihe8UȂcЌԛ vu<GH2n;@0=% cgvH5#\1gdߞU:NJ b:֜! 1Yqe%4eP4Dn>Q٭qEPzPʦ3 jiFpk/ʏK(lP/;EL>D4qC9N9H'4IAC7JB:JOp< .i>=;Sw(JAҏ94;!0(SA1@>ԍ)ii Csں2+3R,ړ9TrZH/=:UI؊(nXCJWOzH|1ZD$AcUJ*] 09ƥ, R{^_FU36 jVF3)$r4z s(o>(1Q*D]8!'#NN c4m4#x<id$(1sMC#;w=iF .p*23i7uL4@RLC- TLcAScf9I}2_CKqށlTsLNx4~@HT8@i+044VOM4N980@J 9VH=hdVDжnZ1[' cv:889sB ':25vɂ:҅ "sO 2)qN)RidRHSHzEnª;s\|EG$a㚆'vA>RB1S##(óleTQ$҉ٌv4-3pѸ18Խ؂zQLlo֦_b(s ARLTf8x\p)F)aRE9I9OF*Vftqn vAV!&({ dZ1HUt!9Ё< q a桐) a J2s'VLr(@v&&f85IHe ןJJΔ/jdw_PcWNxL#*<"u0+ӭiʯT\X)r9VӎRD E"' OEXv77UgM4nc]pT4x ޕI Zȟ) 0i\dB1)"DXOcޤ`)'ҶZ௚{R9$U줹m}oi[AaК i4R8<6=IR8sJshq&q׽9!Gh QIN1 `4`! d(Rui~(vLbxPFM&N)3ғڀ?.sJ30GJ4cqG O)@7pjLbz(V ּSUҮ4mA9]WX-kZax~wѐCY4.!<zׅw>UU^eyu qB}q8F1ޞpjt3v8c=(8 Aځ q.95$bZd1RAiON(.:Ui~cs` A◁iBuJddS0 1N!($2rN= 'y__Kq2$95xY]iS}k-mTqښ;iG]:--)N-0㹪:6n5 i֩9>0^84.{Sv9M7=)4z!Fy)җi@H1@ K#iF7:J3 @ 0ip)xrp)0828悼k>wUy5zm;PtmlgiБdWfrdm;9vK`WC}d26x;yYR}H~V%A69Kh9ؤ6-ya*N;+%u=('qc҃.Aӝ#!;H*\2i3&9n$$helrWSg$cwWwZ(wձ@"E-1p+6DsQ*rCҟ  1붕ĊMDRb\qLC.٩Cj8mG,tɂڈC0^٦ HDT8_@ o%5}8*S/+j!@-(WZ"G3=+BFrv,['(Ҩrp㰧n򁆦`ڻK3`Y6*@<[pqIE{̻kλ[cwj͜#u%ʍ2܈bk] 9Uy%]QH+`3 QsP>)_7ѴNir di'vi8 P g\A4U nnSdBp$*6qt$SJ5@FR<0$d6*d*&C*F@ QBX+ sV#,[v⮦3"T)杜Pd7uW_!1FH"r[9IspR'!+ޔKg4LbaOJzR6`F e⟌ lcGz~:ۑ֑Wp@d{PNXsHqӑr2E?49)5s@49/z`si h"ZFu+:YΧ1M <V;zhM%;{l&˸sQA UY\xjFWI5ƥ|͹!\) PqQ=# -44q@" ֘πGzvܑN(' Z5a֜'VRxiXqUU+֝=IHO#c8mnZ$ AoQDLN⋃M=NWn8VÎB#{N(fZ.G'sS1ȑ:kp~g_҈}?;hA!td=fQ f)ß΋"/i @ƢK)`3Uqr&G<^E< ͋]@]84ɠH5Q́{Uzfɮr?;j$Sm$ TptE"!¶TLp{9-ơurB"#ueV>GzvaR-9;WP;ɍe8f$T,;$f pF9!szc Mc4ZFp !\jDdɪ-Lc$+zqBn=@2)\0LDhX8}RBSTRh ةtU9ąCFvҎЂY=9Ri]H+=`]HkcRSrks;p(|&ʈHYXx:HĞg8Ob πX lV!ͣp{Fykg#YKsXzNi6s]0S?!M3tyucUEOVX;R =jq4pȰTl3kvHBɒ1I샌S FRqQ@Zq)@ђ5^H# I-K's6}J[;_ݒ\tQy$nӚVxG  IQ4t\edV*2ASEv 8h8"m1qX#(6OkdsT +<hZEP@rXMf\sUdIXBP0i[TM?2B6֎@P'Ni[4ڃq=i[dD;rH͹9ϯJ+ 5F]&BFyr@>ՙ1gmZ]I^&y:ֈooRXǕ}*D"+W8J*1!>RbzTh TrOJ);h"#Ip"k{46 X~i,yr+1JCG ReSVW2Q/Wv(#/QY{. #k(ZU/8sVv\yGG7UK!T0zb  "W.()P0Qql0",9/Bh#FP;S]]g.*`aLIArs0G Zj7 PAY A,R~j$Ol1l`̭&@#Tp<J#~j_݀qփUj4XS`75=@IJ XkSi@氧x$0w5 K*Մ7 Jn dcrKO ֠'#4օ,VE#B $İ0r@$$؎yn6=M"+ bFNH1 RqOGWrsHdأ` D)zsMeUe a$e㚴E f8т kY ;O@)t}iǸ,)HU{RD04dV%8*ɤwqҚ\rzSF(:tW4|͊v:tq)XHE\NzfJwϥqNa'9@S)d@ UZU)1 =)c<9h nJ`FED8ϡA"jV`:m <&M! qZpQ aG4 ɧ 7Z Gś#OIp:~PUA &SQ@<9 x9h(RI\bvF1HcJ39.6j@Mq2h*vwM< cH[IW ͜rsMu E֤M+dPL^1PP14#!VN|D$w 9WsxW ӊJ ČAaVi$g/&50}Y98\Yw&B8e ɞ{ 6(4xW"4JBʮng(q{p'iČUw.4eRi"h$q `uiEJ[qNB0#ޤRTx2l#wm pW H}( RTP ȥHG");"['L0GJx{U֠-+&#hc~Ч柸60)9sS8dt;.[*qO3wpE"OjH3݅4o)ց(iWJv(sYZyV̐9 Fq:Uӂm;sIgcj+`N{4فM֣CS]1"8r1O qP=sSrMۓzNI40HBg( HcRvcT+y1X.Qv=+Z+uo9v3Tõ8J2:ҫ;m"j0G`{Ԓwn䎕wW9Zve)ՋnPݑޥ bzsX oJE ­fdKm>+YN~bNhܬVIqⵔ `.H J~ p #)J ONJhN'n( 2s8q0 4K gJPKu(Q 94t^1֓uZoQO`m{) c\h֓J Ȧq֜y=xw`#i#(ۜcsj\JS2p(=(1R H/Vϔ#ٔ y%WʕQ FZyv};GJ FϘ0~X`OzSc sO U$;`RqQ8>Gz5 ph".G5 )`t)n($EvGzipҶzpÚcHL)rpWYr~~ FƣҨ$N !'^g4<sfYTp*a/ b_L$rj%y4Wh@tg$惀=BzPQ~l >V&b8]#Hd?eͨ,quoJGL}t_⩰pw|S>|L2"YlR@$jS݇vp*q4iOZPR`U0{V5 6$MiXiFrT{?ugJԿfPTw,@=M+~T ՗Xdd?Tf Z8;ͭMнșe@~Nј~Gcxty:gn+X:4vKq^E+N}*221)Fe z9y&ꚡ[qf=iQXd;u4ӂ0 DM;QqUTX;VG*b5TC4< JqjH72xMi1ձmI$eL37͚٢Ǽtl9ę@zRgg8 ~C6TiP֌J!FEvI,XZj傟P'gSՓͅeOY1`ҨqSlR1x欲8b*peTzъqV%`ϥMܰ$O()g= *q/EtJG*g]s LTx +$t4Bl6J T~gb ќCh%٘\5%faEˑq&"9ԋ!Bޤ-:Ux-0ccsAB`9㎵Rm"c{TJQ߽ $Ez>@,گD=rb0=*j>ń=Q#Kpw<©AT#2RξXUc$@4(X J%#eO҈HKfǎg峊vfD 䏥7IS`dP)L ,I!3Vi"ycWCT ǩV Dh9J݃4ҭ#r;w$ c Y6,o\*LR+OrXiA719Qj,\duBi$ 74F[vOO`y=jx#huFiLOƯ[gqTO+Z\,kHϽ5ѐiAʜ sLBA pKOV%sӵ3nWTGR7ZaژsOSwgu8sKނ(99Hz҃ @4)9S[@6"VbK(^m"ejPyT0 TLpqL.@T Se jA l#A* nieMj%7 eU1\YHOMq"UYNd8O@'!%GJY> 9Xmķ$`3u-ЈsK`TyPBNG5=*V`8DÊCD2'$yj5b=h4[Fxb>6 sA2,㰤@?89H S 9j0XJR)랙BO7qҔS !@jC94Z:R&G /441 (F8~S@IAiy5!(Zaf f?JJ5aUM@/4"H;AV2#S$J 5tmL'D+ۦjX l;0j]!O|4ĞsV7MB$籦;c8dnU sނ +I>ԡ9:Pg:+sҁAyݑҔr(=6`/=)#<ҞN(}G$#RFpZZyTh)ހpGszRv7ˆ8V+?Q* pZklA@Q[#lMO I肩9\Ɍ) W͍i+0=JL2‚q֔@)8曒q2)ł.ZB0)M*'?k3Ҟ@FOL4$(P:`S6=9#SXqHc4i9I4Ê`&00){Ґ P O*4S8z Hu"0 p8-up-o>0(pHcx'4>3N&Cm9`wh<jFtdS2:! Kj\408Hgޗi$@Hj&= ߯JF}=qHh42mFId# wA'|N܃ȩge_ReyF]\r1t.Nvn2Mejڃ+^BGi~+^P :֭JI]e$lzWUlZX=ðtP{TnPvzF"ffx=[;VŴՋRsQ"]AA,qpĞkUsĂ O8 XpqR Yb*qZzɣ,XQ-#\FDWYs8U%)ŗnH5ڷ~IU21peGQ5{{T(;\挐GjbRO+ЊT)#cii$b4Oz\N=N WMolD6_g$ m̧#,jZq}qLn*V\ѷ?nяZI\!%4w)ך\f%';n4p sL)ҌU`Ss@HN(ݸbqG͊~y=)4 < ❁Aǥ0}))J>R(8dԤWz О)H4I a-Vw<Ě~tF#|= ztU^_><b;G]KDU9mw֜YhEP޴S֞J꣙yP׭/=#ցNF)sSFp 3 idH:sP6r01S:b:֦HGҹ sڒ,v\5XNiT7bgc^ :Πu^8nxKKcj) O_GD/5r{WM# p;$b2G$()ȧҥ z0iʘ9 z=10+ҁy9 `➣<M4:S:R9Hx)h@Ʒi8ǩONtq';BfR?';sF0sR?*M}xh$挞7#Zq "(u x4hn=OifŴI 3ΒS'5IYb[;n"գ>hCp2KGE;b8E !\tƒR%f.WS{検bq!aR J'`Tԍ#cK4 'i>:O/'˴HA3w! t\0}va$Ȭ9=弨9뚆@qOQ 84,ay < 1D{ԫPwz62n?0Ҥ uxцj}G RLtQጱnsҺx bt>L[cBFOzsV"mHv5$eG x0ҨbbPt'QHmEWN|G@SAIƿt'u*9z*SVOZ3`I$`e VN D\HkymQiאJ)#hb95/8e@SK ܊K2h0NaN04`faP"]u<}-z.CVb PTqNNEL3PF@8(9帄:jF#w:qSq41'`Fn9 @ hbzi 0/;rhNy)ɏHP9G1@ 0GOƔ1H9'i2m;u9lҎ{PG4)'"4`p9~r(-N> Npz w$gYW$9\ffㅠ!O"hUȆNppyҁ&@zHY88i]oPK GzE$I98'M(py=DxYΪێveri"*vSp3LN;i8cY+w^_Rj88h9$敗ФPȣq#(\ޝ0Ҍ7O QiKE :Rg&4#cTNkE#"Ml2h*-+j\~I>Rx5=\6 9p+Mع ֺU’x^)mEXFȊ5gqk}8GA]DLD!U; hy@OpF>=kdeiB[L&wsLf$wfIZ9I|$sޢ.[ )!)bR Tc?nE,,œj QD!2zRQӹ)T ?*F p\N(jdF/`s( h6cSҐrE#dpÕи=)Q38a g_&@SW=F)8 J:R!vz2ܚ@$i8xPNzU{J`ŕ@C4vQsJ͇ H7$ +d0IX1PK'b2O ֣0f,ES6eh& `9"qM`^+GJ^*|c]cEYP ; dMيn:%Q,oZ lͿP STwPFpO&(MZD4f@V'ߥiIl7?BMA[qA֘i* fvr =*8wd!¥ Bzq̹=kJkh'4qMf2jFZh¥֨AMW,j٦ORK)+YW)%#,d00 pۜ LRE.SXG?+2 6޴n4ہϖ*xnsjlo:507c#52Fpj8O;H/Zi_ώRe6ڋ:Ӄ#$ =E9[&4m(&wR\|p*47JeϘѤJji}B"%rjDYTKa=$aJd7&gHdVJ_"_OjLsWݙ6ZÖlp3槻򓚡C`v"cri3 {0L Ҳ1[rkRC)PsSyXйQlOHeWG6kY"H0@͓!H}jM\Ǔ+15Xvuل v:dWsB]&4y>[(f^AiIaR7c%1fB7v{yٕBmJWD0Rh)ݱ҈A7Yv56[a>p9 P˪q&|%awO,;Ak,yu5/8K=8`,:2 wApGQN$YY"_qTR u( {LMdƣV H SB"H #jb2X?ݸGzӶt$ V1Ls=3Op0UF_8gfvsVs\O1d )=+`˅J(&D~DTfU{ԭ6&ڋFQy?x5$Vl=@X4`V" ` H.Wj#T2r}&l{"pOSOJ)QRAC,ePZh(HUf@Bxv8 ޡդ0F*[K$_ҹҖ VrbB^F( ڵF'g=HؒG*pu`OcXsdTAs!@5FV]sU"$Y͑5^ 7*9RzpG7E9.609~fi)=w# EH<` qQ;NwJ \m; Ʌ*{KHco֋krɐ8=!W]xr8FqW $a9^|a5Fr:/-n ˓ j.$LŴck1w+d;Tmljϻ 䖤ٴ"$@*@ҩ8bwjc3૮3JX@^ ⰓR51J4\p7b_Z'΍x7d y 4i0)2" [b)cڙ_j ̞H2үJ܃A$)Ҟ}ҚGzwn)ҁ׭('Ҁ9E#ry.NC-cN Ljx|f\i+<ֵAc(99 Ji`xtWY@Y*1ԜqJyZ1/ҨM4r9ztB);fy''q8#5?4 ޗg ~qҀݩ:NҘc1Nk?Q(،#^}Ƽs$?|t7[>V>^xcXoWP&HOip1Nfl@A=*T^I*qh0`C^yl(Ojab@wҕxS' җHx`8:M !9J G4OJGSYAA@=T׊^oh'*9 @J@isҀ8GGA< bNbRs})3&Gg|R r|ƻ #T𽳂7F6¼<' a~V=hZa+hՏLn9*y+tw ڛQGHH{R.8mmHp~*";PHHI *qG(]+j! ~5$Ϸp8&#j˨|܊͝4VLRc,=i$b"<HP21̍ !;4Wqf}R / qpT#t^r^IyVkQTnmh\]888<ӛl06`dZy38O^"8#6<9٘cm=)B_ @=)sP.3O^g *0WxY(C7,.XŶ@ea'=p: bt=&xxqJ8# K >֘( )8q@#&R+ ҇(phIii8.{@g(Z3M$✸imsAR)Py)A`i:qF28;w;'wJqI8j3(CY=H<]hExa纗Þ.rr#tC<9<R\n=j4Mo Yw~u,`֭;Vx(8ju=s֒C(=iРMQ${{БN'J63 g ^))(8&8{RSy=S[K1չ`+M ƌhn{PzmWz Un2# ;;MM]j#oڟҦT˃xǨwx0$l;TY0@X1azhg *Cjd\`f=|Ɍӡ8;JU-R4 Y\+v'zPCqeN?Z{wlP+B݊OTXҡY6qFr6b=vazTyjCS6z yJoys+tM2ϥQO)x]QWe+1*:U)CyaAW/1y46O<*ރEtR밎m" g0R@Zv0Fők:VU2 9Wj]et4 0HaU+MI mƩDz1 榌;dHTO49Up{$ivT uL,, nHp;Х09]((@V=*D%@cJ7lA Y$~Zc( eBazPd0C!9;JF6'Uʎh(Tl R?=iP!!@J w PNi\&ífOPhGeK=^U _)w-##OiBG}*V/>`n"-ǑܚL|R@h$Q?j<րzPxϠBr.qHH@r(4pI#^ؤ9݃ӽ("qRTy挜f91@ K3ր8qM)pHp@>$dgC)T Q/&zs֔8aУpfA#>%3]N!z4 9 ; G\ $M]p v!նHt#6v'>4?߉IS hT~X=9`˜R~Gf7gҳ+#A"}jI;R5RD yOE.9nҙJ*pbo&8 :Wi6߰HTG= ;XYqOs 7HCؗlDZȀ( mrPbܯĦ4& znG R ThmK|z )s2[#*^&9ӈbT8,9Ɵ7v`ԭ48@F@#Zi8zԥ?7CM C ʠ?Zڦo) `pT&Rƀf(1F}阶)'^i[9uP ǧ4ݸ44 1'!`4 @'<J7g4zc`.枥09ؓ3f 0)̟09Bn0|89-UӉlޭ F>niO5JMy(ҢGJ0] <0HHwA)1cߚ02h!X vֽ@ {g͊CǵZG=I*( R◷ Ucz0hKa84A\ьPpfmv.1 8=! '+qխǙ$g ] ]ېrQUapCwsZ+íf[rh:"$epfS1sȪFqW"`T():0_KRBXzLFNP7`toޕ)9\f۹m!So^j[E%i{ŘV Jl9->Tcab/9zR!E7'4QH;#4s2E(tiGW^  ]#<^gxA0dbF+tk4t~eQ=|ѰuV' SX]{gqY6ofj+Ra4fX$HvsV#f/,sǰ h yZмѣpRCaKYuRR(lN*0;-ҨD0Rܗ]>^Ա@5ZFʑ) F@+e9zS C P_4 ALHH2j<JS*#iJFQ"}K±35 ~u1#0aAS8P5+Ii:d$ScǡX `W j^A*$ ]T%"R'N<`*ȒULMXt8ն稨U 0=iO($,t[eXcm$Oz[E|+kƓ!1؉MEjgz=ַ…W2rNIE$^UE r*+zHHST:cSMFDa3&pMrW;N+Dg'}H*\TȪ\b1a>;h%1Sz.AɧUvꑢXZAr8~j"oZq$ ӽ-c(i`~MvH>xH0n{b7d.*`w&:5mҦ$ QUJ)N AIi8QTne{J,!'idj҆mJ7f.{Q/ܫK+&(f}5m;Rwd<32ǷOo@ٲ~sA)(2q[c yMVزp>\r&¤.WUgbÑPZ̒<7t푤i%BU6~^Ȯ6y=$-,q+䏛jWҗW,zm4 ]I(;yiNv*Kbከ/4T _$ @գU=Ra 3|m ĬAו@SPw˓Ҭmɑ#Js sɳi;3hLv.bXׂO5-SW"@mJs2 Ҭo;,(Q `u 'A V1Gj]phS)@|֭C=WH6 48rf:0:uvL+sȖynK9OF "o(l5 4f'7ZLҒ3Mݎ1Hb7^)0G&#=(7xsIO$t%uģ+8$ I溻X dD4v ijKtKө"ʙfJО,dV+f) 7Zw/+5e#,Y$P6EeڱoW( QΚegRh)B,걾k-qOJm9T8CR;)ӰKyPFSU͐"4<؄K.kBg?Z9"tH+摐Xfq*Cӭ2Lc0FTdcJrښ@qi+o4[&7ddg'mbPJvfl䎝*T`'`e` F)jIIX })=:V~xvkHˑZz2$jPsS:Y0sҁFHɤdS9NY~n:SBbzcvȠLKdJ9&0@4;)jb9T6R2sjcր(>ԞS3!!c4AHh{*nOJķ.ZBy9sV˱b?0)̜-vAZ$^)dH~2@-g@ 7 j$7Jqf8 3O1سr*+?PVvہ@NVE- *M$IdoϚc|Prj=-OwS๋H@<+umS0yADYV# cn㎴WҎhHbg8րiKv ) <Q=iĂqM&4FF cRe%vcx40tW_6~AZ>!5]pt4In AR*M)8>:PۇrAv]UA@4gFrpN"lq֒[ggr7I4 wPXuf1Kx7# gCpGP>j1( (&ANԝ8ϭ#hҐ t\4 Ewg*)0w0Xg5]eHNBɮe!X@CGe$@R_ 0Gkaok&{R;R7P:KEoǮkivIf͇|wԖV_܈-jb.hlq^D# sڳt':F+V! ƌӭ; h89&8ґnsr׵!~ҕطךC X~-4T=+hip}O79ӗ,yl(֑#,Vo#Ն8T_{S=hn~Cj$$wRpZFO00sLdCj@HQ*o2 g#UJ2޴٤V<Sd^v {Ba$ O##$3&X\߻Ue+8)$$Ԍan'454Vddw5.Tt ZZ' G !⑕Yt+G;!@HXW~˩8ۚʼ) $۹@ #agVZF\ ~Q̙T |(^d,+E '# sN,Ćښo'?2QuV@F;}Ngs'>Sm#ҧiBdlv`bnF*($ O rw$piцMH0*)s(CPO50GҤ\cP2I#iN{KRV\^&8wcL!zR9Vm9u'ցLBiќ1ry9NY  6F*ҝ'p4V@*:R;<q$n-K3wWDo3&UFiE.z-U_v*M89V8B}O6@ nH(('*y"Bf(ܽiAqM#xu6n:zҀ8KE&s1Jf8Me4sF: q"\.G'Ҝ~&`t1ߚ9#rx\SOҎ0@;ҚFihUa)FIf>yZ+HcV,05dܕ K掜fh[B74dVFy8u75N2)܇{TGpΡps~(j-*R$qJ0VU -ſ|54z ? JHtGd @5+tlʿї!ұљ֥ce2JCpEj[6xA-KxZfc$,*hBljmX5"hg8ץ O4Ɛw͑ڐi2zqޔzmԂ0 ~4/8TzQS.3QH $0H8-F5nc+Pi*r E4]lye}IL7(mINOdd"e&UEHI@܆cFO" wӻ҂Fޤxri8#+ Ȧ,HSH*X y)iRi7_Ju=j @TQޝ\@Zm 1HD`SC)wg@zG<␶G\ c41')&HGQ!XW`WicpWdE Ԏ(y`f:$);bh5e$SZFvȠ7J<֥ ڹeS,8ݏZi b\tj z,{٫_8TtՒ2@'w!FARuqԅ܋1IA4#9=%UI&Kp &ˌ.RV=jГ=saԆ A8!`NipwD6DC&@U\~*nGozf|eIjE#viֈ!-A-ېmjg<1Kw)eQ޴FnG,+4RCf L qUeB{Բ`A5H6idlJ8:2Z^3kY!&c$*uS)i!4wfh8]ƛE=q]=\Y$}kP;Օ)Q%tmB.cKW5;d3$9sTDԫ9ɒAki:eȑX3O(Sdw,)@r+๖DOlWQ+r09c5-]6hU$5vð\Z9"Jvw@szDM8Jh'rof1䒀c7l72WhSi]PnұVE8"CyAS;cm{]++zV}吽8Yvi1!NSt⡎! uSp` ME%)29\CFb+i2֪Iڛ)EiԥP2OrYiweX=8-1s8IںDlyWUwX=*yn4l|#c̱c5#pH9 u5\CW݊WzY̘S3zsnMU2yvG"u BUFOjXh{T4уE PQ|XҬ(iS6ޒO1U@ae\{ӃQ@n@Y y2.x怹xҬTب3cp\@63c)px5&3Qǹ#ðS Wi:E:44"u=!jE":FYlE3{T'{P>fa[*1O52A`rs܅Oivdj+etIF"fk"ڻS+[ĺf=v%yRЧevZAٚ u agQmFWFu#ӥFCp1ڱ7V-$LnѬ)<@+O$e9k\D|$BXm=`;3k uCqT1]6œT7I&,.| oZB)C\de/02{"nȽlו ՕRt&S2["R%fa"8%́`T'vu݇\eԦ9Jǒi](P)CQp•y3펔`=+3K B i6XW2ID\@JAc5?F);fmSՍ#SOĹj3ˡدwj<P8k[>2 9NIP)j1C}HiѸciC'ѓPqHN<7h&)gڐx K#֜=;P4٦|~+ sL {T`CAF)ڑqKҲ=+I% 3*faej{V۽Pq|(dd6G8DlL qe]ϘjK0ķg[%ΨS$W@IRW'ڨne$P`H)7b#G#8XA 䞕XÑWϝ>p] cHqŏZYڱ&q0>b94)qH#0 )5"بLه1V1}݆'1Ȉ[!kBH'"B5doR{ЈJaL՝m8ߴkDH2 R904RQ8C1GQL1ڞ(6wy>ia4NIӚ\ ٱ~MH oFZD$*b&~jH hPHobYLHS5f,FA>M+d'FjB @P~"iI`Qpy4ʹ_J s@$( H/JL0 R4`✠t=hU>8Cu:iW9pWGNGAHF\čOinXzb8ʤo#FI=|Mkk!ڟcws/kF`|y rM6<Fzfo~'z i&6*r1^ݡjqZD7F@}GZ%b9~-l/<RԊԢz0>+:| @Lb8&9x1x#L|u/NTPHb{ {,W_ ]r1S0YsɌ--nVpHu&ii0Қ[rHH`XLTI1mԃGj#iT$EѪ@'=1o, # #2iUidv@@c@|I| 3{w8AR٭8 ۊx޼qުH1Pr*eݖb~hɢs/Ai 3tzTEUpZqP0=hE3I\n^gPNs4)@78`Lhۃ@KR ޘfҩzIh<Ӹ^i01N=iqI##I5+ Uw#}ZcF\~A 豔樴!B*cgIl\HMT׭G\TR8L#[tT3#$6IH8$V/0}iAX$ckǜ/JlxVlZos~"ˀhBp 8tS" gڙ!.HL9NXTlEa+&ڣ.0 uNeo`H95!@{925L*Ǟ2(Ǧ)Î1A7b .;Jh s8x(/,->sҤ8ِy@2dc&p{|4qRM)pzP w1I9vO=(BF օ#ޗ9 qN$1Mn(849GS=3m$Sf@Wѧq时ph(g/@^{P+ANEcvj6¯5'eSSTe Hi<8f<#O8]܀qS'nւ[3W#b0( ]n*d0 3Mٸi zT<4 ȍc 1V9ȩ$c| uxԊ(NkAzcOw@{k HYhޢeitCPRNԸgA8PHsq *Y%ֳyhFLyzH?1ɦn'i31NV9Q G8M58 0i9ShUNM 8Hvo  #@ؙR-H L*JQ*x)Xg5*1HEF>RzxϘ2GN~eߗAYJV5&2¥_=ErÓLLN{St&G_ҥAozPfȦY?ty8,A `Ub9oZrM䃵yvwi ڢ3L CYFj0@cM6y5*͸dU8ܨOYw)^Ӕ?M(SYbNN)KfE׻v5HH^IF@J.9}ޔTCȅq[&%;3=E x< Xõ@LNR=; b[*nnN13вY[ga.#C&Yc1L(X^.znF3M @qL|92P cjerQڟ/)֫cx,pcRohJcm11906IN,ilppZ2#\dC&v!Hցs \N$b8[m48'1B@6%k {S6l0[9r8 m0j%ʰ#q7U7jc#MG(v R zGLH=]5bE@9A]϶)\Q"Z["PxLwsIzS zQ6Rt9sڑw&HS4”c )};SIpUoԞSFEfB1qZdXrǒ*YV:"= "d֚W99c Tֳnh7K2 #DkP37Jǿ26N g }0&)#ڱޤSHo51,rE&vҧ{JY1ңi66Xz\{梖PrJ$#phG͓P@FX4[L O_͓j#*X)@P*j:rw3/SU9ۊv3@&\v('_qLi#͑F͎sN sړa<pқ@S~=twHԛӆ=(xa!3>|í F 1MvZWO3}K'Hli.̣q.@CJd8p n7u~9R4v+b$HaOzǻ ܶzӦ;zU J[{.TtzF \{Vrֳ."YJdg%Tv4\4mZ% P[e1Y) zS0j³"n1֚Un*,Ґ. csi \j-iŒ@$KNvNlO\gVK8v3HO84O5 p EOP1c]YGuE3 pi&J#<(l)X.")㎔wt"Ҙp1Z9欸x@ RNQq@? VFMFķNƅa l|Yy̌r}=*dˌz&+3jSJR v$t3<'B jSEGz+0,;SM t,/TLۘM#fmڎZ_~sZQwSp) B)[9iۥ8hBFXdP 84d7=)zҘ|ԠO& zP=hI~  bc^(y$\n b)v?"&U\kڸSn8^SiQ;[ޫ,l/+Ь۔gF N:5/J n_*M)iFN݉޵.`|]Ia)Z,xuKp%Q1=kt1LZk dl+POnV"52yVm̠ /U؄Jђ2j5}JBSqs)U)#,AiqWC"R0hݩ1d S3l`T昹qFK8`)'i|D*P!*˚  ̸( ,=zR.$ 8)Z  Lxr5o^j@!nV˵LNݩx;DϥĨEfni!FP$|v*;VBB.[`9$;n'Jcӵ<8f@g;$Qr0;p\k6P( ۃқO>0Yc%:sSgҢ ɱi`ӑ?8p36q:zFW  Ni܁҅=3N F3A#Q9O#ҝǥ{]48".8iLҎ9h4F iQR@&8SykVO]'c%R(;ZvI"wMr4CsPt4r)Mc5 I=p*zf(aq 3֜xnf07/^*=rJ@!#349 P1YCbi0G$ hM$1CM:hwߙԎy,{ 8P (<t.]b1|QlJHceTVU88+@@I}(1܌QIG9Hb9$qN #(! w,sQ XPB㌚n1X&)vMҞp2xq֣.ұ]qC24D[d⢒UT E4o&ڍKgL)ܼ! jn<*O\3s՛T\&`zR5-U ƖDi 5_/i;x HPp(Įqit欤i H.zUt橩 E3&S8P+|Sik cQҬm#@\#9^PTe9d 9F;zSU_V7i;_4ޕ #"mrJ@ԨHDzV7Ҝw08zU'iMjՒeNge<-u3BfN+kSOz54ը׍٨VTVP69qPKiҍsS1K̉>CXۮۨvP9KcwKRPc5 WdqT(Xnr4# io$A2wwK)rH7#q )D?C@,9CmC\W {RFy9HIN1V8>'ӿJ TL.d6 VlQqR^BKĆPX\ 5hEϭ=AT)̩ϥ wdbqOX,z2 Eir)n*4P*GO4(PB>]ڭ1*.}ią` 3:UyO9+̄/nOjhAIج@Nr Y'zeieEB7;FqPf˕;}ܙ\dLmaWK,KjҋKt3Ʉq6V#39gLGO VjuްfmY+cy;.àyp<֭If8(:S>(Vjs&*+1rN;!k>PS3sW7Y^5I6u4QkOԡH8\DariJyz.=E8+F)NIJ3$5d!)R3@e N gFm@˅ gRPnS3Hɷi!3 [ՕsXo$CZ9czPZ@N 4'3F˅PEX:ST24ۙG< qnd 5($9TƅރH<g[_c&G6ZY+qz`uR;\iQN݅7@9 ֐>}[i'ᷥAM5c˕KL`ҦR@!׎x'Œh׉ Mg{ i<606vgKIe(940h,BGҐ9樑ozj ri".܄`W)tNZAʡf8Qްn.>j1&14> LVqO$x!S9*h$R Rhq@`УuФLBRt@np{Ӹ @ ##֌s.N('4#(n,qNh杞ݨ#y:jRA `8Qt s֚@ H7q֛ԏzLzҺL@ƺ {ӗ y4"ӆh?/+ L1z%n=y;KjL/SjRwGq9ۊF(h(劄LZ \XJ6vV`8lGčĻ[v׽!tO!3jjfXֹo !CR_IsHu9rUrW4xKO"Mػ 8q$gisޡ_0Ն$;T*;n$~ֺ+g=Ѯ3"q h,uf5!/?evݐJp̀~abÓRT wiqTq$!ȇ,~\ӌ~@8c!6{ԗ2\Da($nq֚`bǭFP%!Ilʟy 2\aA$Ex@}Ihj+ǸH1ߊ*@˻=QZy̅r ݐrsֆg3)³rjjr@\ KuZ_iɂMH(=qO '9F8wq<cޗ23@U9ȥ9$Р1jL9Ji ɨ;4g'>{gp9$-JR0x C4@# BNsǥ(mԡ9I4ϵL)r B/=y<6GJ\dTyOiARb #h1h/511 Қ` 1N#yl䚐{t'AJ'4ݹ2Oqtu(]46ҌJVzJJ1@09<RJ.SHBGr~\ʱGuRN$t5 mor{PhՑqʪ/ 9t()Ie3R8Y|S$rjL7`TbxD&yOcQy1[ qNI}j$vրxHA5@XdrjXfYK0nh4jrB`zV-4bzE7Tb)`si-LI=iysHm9i@EeN9'LX,G!qXMup\g*+ҦFvNPH8!t+DތXtW; "kZw61Nw&֪y(1HvkW|n(sKC[\۱y$hKtVgב cR5حq$:L4DA$dE$aLbg5Fw%gA5*a{R|O]qig,̤m$Up 8AS$c9#91$SGd^<1 @&U`0.E,$Tc4f3@5Q P7m2PE#zҌn(&('8(:7͞Օ@ Vm Cl4TAqXp#H0H$|1nr2nKo JD$ iX#X/@OJm6ЊH;q 3OF7A[xHOJɧ08"!SgQ) Jh85k 6بycL0Znr*sJ®EfX[IiOEⲒfI]fuY cȸQ9{}>{6E1Yعֻ +;M7VӑB)zBs ji*84bchLP;Y* y*WLw9azP"2HIر_HQQ1.Zoh)+ؐPZj6gQ\J-x+FeiJ7 VzM#<֩wb82{v@IN SrGn!dP $Ȧ Ӌ.n oM L(zFQq#TcPYRQFj)~fR)aЇJ(Gjp$*+pZDŲ"QcMs[Hnpzű%HNT!5~LH9aZ;m) 6iFҥaɫAqޱ\h< \s.9Q}9G'cX~%:|Ԉ j2y)jx  lfϔ߽~n}Lғ7`=hۅƤ?J ` 'sq NN*tR[VJa ɠͭrMdv(}n !+ ޔʣ%rIS $t .ywHhz=sPvnj/Ȩwo$[[8*+JLcBJ@vqR1})8c#p:g@TM"Z F3@MHqHT`)#9Q@#iaN%viv=IN!x!Hi)511nM;qϵV$)c˳,r)r'%foݱ>ӧ\(kj(9* o(݌ht,_M.p$U2sQW*3ud a~j[ZNXfS}OBNiFm5w&A'4rؕ 3O;QR7<1Hn_E4+܍m=E(o7./⠻"̸T}y5~!\+GzNiS)^[ij&s\חbkr*-T9fMNfCGkM$H<⩜ȮK0H< ZEمXs#U>0xH,)W` [9=yO |5&Fց\j O?Ja9J9bTz8O A" ҃ڀ6 8)i uAHOҰ`SbH[k>Y=VLRhkˎ[8M[vR #ެZ[oz56"SN*ʮsQ皐ry2n㽨8P 89.9'!hqGCJ3A18IvKN77F~^P8Fi zsMa@ ezy8TÍ )IsޚsJOȠbJzhU^4~4+hc$#w,h7UxT1v-r1LZP:S=M )Iŏ1J3ގdCm\bGP_.q@8& d B@ o4ɗ"'4jq#1dSsR*)BqA7#ن UF9GzN94GQHTh+.QIzRN=0I&f6i7n8 SKyS^zSvހ4:R(Ҁ+H=MF1VQR8IPV4MJ;W N 8)=h))  >"8lVVuFՒie;gNٖRsTeқr„xc *1J0GO˚hR b c4穤< }aIy'ߊC0# QژNMXM("  9U ݿ1$K͊EHk6Pci&AHć+ڂB}}FzWP:G "4c$ '/'h*tN2EL"0y!sIiQ74r0iHiI"&+2~H-hv(N߁LdriNx!Xx94N)b@\P9)I ϵ)b%$)0\#P! ‘Nnyڡrh<)< 4) P1H1I)b|F&l:`Ŷ'jDՁn2+)`=u;a`iM#1{Ӿ1E2u+H$OW5#*x\h)1w1BsL(NzQv0jɖRX ;F8泄y*Dg!)_,f!yUN2E)9yn,p{fT# nlRd4d2!Q[J{ jTPSع4x`x"R1J ZۊJHE;-A"N#F$@ =xf4 *GM$O qLbiN1PaO"nu2G4gyfEMZ~>cQϙ" ;Xgޫ޳QtRӽWcPt j1xUYp>54"]l'}vc^v qjP~T,] o([yQZؚ;(y7,vk[3[n}cI򤃎HUko4~ש"]楷YIVibH<ƌd`ҵƙz}>[gK )x&LM1)qJ PsG$gg8&˕9S%Y_LŔ`cFķn+1ۂr3h ֈ̀SiFϥ7 Ҕgn9H8P>9e-6$@)#Zai}jvnJx27»EIJDG*\Ny&$#X3,2m'DYVrň2 [1S7TKsr*X|E4U >h֣#Q;MiTKbE)&Ǖ$z,,zĀ*Jc`Hq޶e|\Wqؚ/5zDwdcoɲݷu~D+*H Eq`A ўBէXph y_&y3jff.=ꬬO+,NӁQ;ɪ!?٥$`ҹ|v}ŻnqրhiYdU\<6JX>pj0qN߭.Nq) p)z ֌RP4`0ދRluq&pZMpi UWc/l,pm/}Q.5sNBP}Ӕ(RP)B "sBSi1Ҥ!%G#I6XR8) hzPsO¸ӗxNE+ɠ98|$rh9K@#dG$B6c4րFcC@ڛzPr )=ӃzT{+)NէLzoiH8mbm}2*s'0[{P[PqR2iAqң sLہ9#TJ{U=b۟ J.3if8 XY\ַ0q._^h Ҫ_48X=jPUw6p*U/HN*7 Ma@өdb]ۙ\n^5"֨Πdұ%cXZ%oa]5?r+WX&ٕW=ARN;[Ҷzg$n1TBsF.q@̍LLT)v @&!gZT 3fl9#{R&9^iwdzRtc(sB8'q `;9Mj/A@J1HH'NEu.y Rrh?1R%Hgfj#ҴXtqnÌ[vFnQ'r^&D0!-o:![[6  Y9sP C{ 347$ڨm,v*B]FKeQQf;G1,(h1ڦDjCLBuRޤju;G5w3a qޱOz816h* |c-Vs!}5bHj"(Ci*yF+{O93l| & W.Spꎬ=wgzgc* 9luivy͵UW$gX3ҍ(OEC7zbAmxwEʷesFx ?z*ҹ5d dTH`m8}kD>LjyLsO1'@s֤/s,d稨ԕ4{isMS thR4Ώ:POHTi0}1#ǑHWmaO<GLLhzA9HziiHb7OaJ@nIsOS6N8 N^! x8B!rKSG_J&$ēʹPo )2)+׵3}'Hv2{3n$‘V426y4ai*Cb0H9QsD,KC'5v0#˷#@@L]bR ]s3ۉ)rp-bKAsY+ɕ&;X Iy1TVDvk,dհ88 ӀIIĥҐi@Hۥ/җؠ78kWԆ!$nN 4 RjZ HT\b@=O]J7Pծ>@DqY+Wngm*d2r2ܻ=* lث, j"| fl,aZdi*i%YPzQ bySDa"9G\硪,n+Յ\B#'\(1ur'o׃R=yyMjD9@ &@\ϵ9vxӰJb`ǩ$N@3H 8Z@sޜ4 i6GN1@0)CF@0bRuϽ!`җO{ W`$S ҅0yR$P@n0aj]Ͷ[($gu=hbPsAAɠɥ zh9iTbM`w⤊< „XԟIj|h'4@l4hsz29G6XGQɦ'{P0zwuJp1v1A< 3 Yq(Bf8'1u)|PԱMƠ)0y&ZdAcG=~vE Pt֚Qך\ҝ4s@ FOLђhp (44 fr9hF3M;4B4c :2h22j6NsTFqڐ1@):S4РCG1r)ڕ5~h+sO\*nr:Tr3HDA.q@*@N`6*NqL~9MHݱLbq: 7PE;2)ɠaHԸ(ix~BC2M(#4 tc#4!H7< C03cy:I@ 8$S^4ܱ=(#<GJiq!e5dc#AhaR>upπiȥrIU<ڝj1"0OjW#ҫG4KpqF;p)4E7## gUx5\ })3H3pȠd6Nt;p)~Sྴ4&!XGjyzhW4dQ8Lqb{! ڣ;{p(2x3Gj{2qF\82{ԫr]pGFE\e}]R0+<^FNTd|3>mWIfor7~4se3jUQT䑁Ca&\m QC7Z.Id̅ssQW/It#>kǚd bʑ&$5l"lX:SF:blBL>h˞)Jz Lźh+tId*v֩O??QIF-ދņ8cz~Gyؒ쌗=}v2ܮ{U$2y:p9)\@m;O% + qaLeS3I}iPM sN $8,d9( PQ)ToJGaBXڒHBOjx4zP(lgrP~3CfS3ǘNXhA) 2(2c7'o`:f*f2PS,#rLYR29JaF޴ Ļ (C7DcUQ/̧Uq.>R6 M=MMYK{p2VAQ뒵 4 ]fUd*Ynq5ԪWp=\1;^;U0 <,.|I]'J7V5ٸv db@}3riJ8 &E VF"P0ntE UKc8%s˞XOJ}p1t~ c^wppWn2p5+}@Č3vn_ ޕts$J6֊*ұqW!ɭgϦ˦fq42*w; 5b 'AȦ n'k#nQAF"Fb[q*_XwG) D_LUR[ł׸&,zđ9$#OQJ\Bg,aLkx cJBA&M5ݝűs.G "su qXN[W]UJt\=) *ygQ. WscfZc튧=۝Mu6)gp.wAF Q[e5Za[vWPzL/ATcysGd944g4A%F+0۫HQNue%b$"y 5X-~cLYONvIڀQhP89P·"`u YĠzE^l}]rTm\bLJù8KRp ߥ"Ɂو$KRXa?tUӆrs҂E J[nO@(% (@R`}(ZV @Q@Ӓ9m^Nyw!\8Z˵wpZ,g=K(%Ӑ(楳UD*&7S]˞qɤ4Q*YݜUt\|٪dGqVKM=o>S5n). 8]ѝEj#d F0>qtZVBG֮+mLQ5bCGLqb$$AFA-SۺIaT\cn= LI< $)tZaq:qI1/592pz`x@ pMNriG8 ;Q4h$P=($s@=)ppCs@ = OOƌ[=+`LiI恛Z9 U=-=H# tƍj#a5fpo79횰 ˯Գe?:hR1&1p)7J4qRR29 nIJ>r( "9: œ5*( ;H[i11cڣ'{})I%wR!!FqL A$iDe}E{2T(\Z0["jE!eR 82r`^L_Jy}1Q<`PHa#`T!Qң bCA6&3)s(pi)׵DH˂y˳#5~GRS)?-D/(73a@Zb 4)8pGJѴӬ0>4JKrؠ1ێzA.x4iz*9@偨pǥ"Ry2ǥ\ACS"y@`zP!֛sS/LN'CR1Ra=)x)b gir &M!Qi$T1 R N-B8`  nxȥM8( $E)`qPz1+0 ]WRD_zCbSB&64RKCn݃J6pyݶ58.O@Ȏ O\ZE='J)ini<G#j n*Vl i1HN(L N@)[ Ƒq{۴}) &ݑ|-,G.F?] Ni'1ҡ*XK0J_#2&k]-㌳b]^0k8pI>Qw9\Xw;+ޥ$7M'P$3ֺW3)R.~Z`hg#M(hͱ 'iߟR#]])t[t )@y*m=[#%?K9w) (wDnۉ8$tG1֤j@aaҦhߥSRI4R5%et9ßڷo9ï8\ճ1<y(lɬi3/\ebbxC&jП`ڑAҷtȹ< >v|kjo8lr3[6pkc4! JE#TA(r@\*Q ZdUr|&џi(VW$"mvUذ=uK3vgNAi'#S5 bNOb w{PJz4qA7a#4 ڂX OsAVހԄq@ "iZ' ӭ0֝H4h0 VYjE#9MEtaTfDZ&tNA($C<^5ެtFWq.WH"J@^9.F d a4z)&F[ FR)Y@ONi#ݑ@I[3G:*.л >_Ҙebi~:] H>$x R ,w#&yE̓=*BS<bA+ JVک`hM(jlڄ 0c& Gi_{JaU:#i*0M݌-hK-WH#^ҖS^5n:ުFѝY+drƜҙ>_JB:3`Ojc,bDrk_N.؎6*Q敆cPxjh?0얠DW,;T؞ش 952ʭ6$he|打1>@t*u s@Ձ.'g9"ĸNr}]BIe1A#ե W**GnELY>[{Uŕ-g';C"c+\tf@mx ZQ)H=ДyFnV]H8[\WZxsH`lU j`#¥lP]8{_ ʲ6P^))r:zR 1Yt:KD@! Gbi{[@ R%c7RH{ҪN"n⍄*gDTu&2YIm.:ŒjEN=*61/ԗ48!Iڒ[ĎۻsA<>QH-׵!:Rpiۉ\)n!H lT|w(')#b3׌U.&;ON)36IqH?IP ']=1ړ $8;G Ê$(A֬yB7J)GOZ_4Hg攍Lު7w7zS Tzj;08l$M@{ D!vUu FyYz %ݐ˸#3\Cq7%Ü+Unu;^˜Dj[;iܴ*Od 05 ׽gugTqV"<ۨ8+HF"]2})P7FA%zPQP*݃ҩȹ|msTI7zSL` u=h)S,OCR!2 bHunؤ+Ƚ8"Ŋ݈%G'^3!zv=+3&0YI-޻}'ZKR:~ƌrzUCDI! MգІF>wW/ek:P8jMurz$;*5i5{"MM."1Ӟ<7\ΤV;B3Q3`bXiI9H0h6G525G~'^h&i#OOZx&$2h& $@ee 3@R㱤T bJޓ >j\b9 ;P=?ތo.qFORE /x wi0i9'f YjELml(EF]&`0x.S+ kۀ 9ԓemzk;l@V6#GR >p@j,rORjm֪+ n3ҚGdU;m>V(S/-QКm;P>⧂]^T sfqj׊O-ctݻ79LDNVy7}jɠM0`Ҏz$OLUrbj6hYPcGZs9"bSi[I=j &7=h8[b] bR)QЖO)wR< h*+!VFCzd \ `w~˅L=( gnҶYyc7ZE^91(j!XBrUerzIF WzU B63 *-I^HviT7xJp@pXuҁ6L0s+oc}O#/AAn¥ R.qց0]Sx,G40a?FdiHVց`߭=qHH` "Pxr}(wRj6]TqK 3@dCT184}BTSm T-Fjer$91$`sFg2H`(_!Q%yd ڑwjUGaTg8h"!SFjcUJH R!ȏi7oJr > s@Ybc;S:Wpɠ..3ڐ &¸s1W'Ҧ hoEl8!)vAs@\Ap@8Mۅ8  7mhI=NȤ,qF~Zd;40E( H<?w=sֆ$t!jq5#H9 TML1,bsLP܏jpuUbFjv${R-#;V%uѧ I}vs+ }-4%cYAIY[K!>@q  (`,3J^ ;q- \U #p+yf)HFK4imljfU@*K e拝-"FH8bdFҫ#JeE9Y"e +֭#ˀ# ؚpt4s(C }+:;I niy;`2l`cg\*AހUm$c5RaҋF$a2s]VUޘHǵgk?l6Pb]49溭f\e`؛ʸlעb lNS60|&1i3'{ҙl-$>q$ uqPYzֳK~x5?J_haT.[[q;W)B\ LbCtǷ>') >FGJqhPcM<<($0KLe,r⑲(_fPű߽Y'$ 7i2RAU' Pw bIG*t@nP?0R?JB!ڭLw k6lupy<#tk޲o'{D"U9BNri.n"ᘌmRH)6c$qVWgV3X%3-+jN 0AmSTٗ*qԝaT30ܚ{L|1Tpf+⁤-Ԟ\+Yj$vrۗU ZX\^i(Ey53szqDE6#tyymY++œ+Σ&dexڻ}kQFDXpFq+i'%Moxn.E.o']*fU۷#vҺ;\┃5|TH8PIs@3ܖ gS0sHhU^:w_nqVQ֓.%YS!*EH@6 9(4CrE!WQJ @( 3=Qh*9'G=)=OO&)@/_jpMnzt)P!( M @oi=F(d"U s*#*71R)B) H=qU0Bz7:Q:ÏݞƄц.Iݙ*N=j4ry']EmDoAA2iA+ֈ pSjl(O{`I.NFhI.CX-qN@rNI7˸Ӻu6?%WY?)憛nA9UyCfڴK_ݥ-u&g.#qX׺gkm\z 3f^3>lǦ5mBUK$@S֟)+nsR{␙euHYS<ҡKc8dgV"'aϦix,FOzPVTfn0j?)H>BQ~Bzb˽N"8~[(x]xns5Iem$,ZR8.];T.\ұq^rCVdF]¸'ҹ) [y NsQԓ#nLzͮkwmZ2XuA(\Y?1]~% `9P9gAt:Քuɱ(`ZjI!aFlp@3@b,[=)zڗ8 wj1h$r^'S&h1s@.9 LIҍvKir1MNS[nr0i9Qp@J=_P]+Ly'y.VBnjuRUOcf!# {*19^Njhue;sZxrGb$]~z{vAs:[LVZ_4-5]|`/_,H6Wp;Pv6E7/֣{h'o*{^)\Lӡ"tdIȬ_I$]kPynmp4f M8ɣ=h?8⁉M) ;ҽJe*x+'\[ ޹IFV;i˘ᄃQ;TV:pzfD2푻֋8٫xk^d6-Cq3r?ްWcv[LkV8=Mw d4;95f5d4m-(WUxE#jeA@ 'KZϯ4zZ^ e$UȥR&O9reNEhR1UE9 bR:.8T^Q p mY9'9<03qڨ:Uf:2^)@9/J U>f-!( p v*MY?/Ud99o£2M=iA#B :Mcy-#L“iX ϥ<>vÌ sҘ`AqqFߗCQFeFzt,A4# - $$)CF?//4#H3(4 $B.q)71rzY{PH2Hl 8ޙ-R[mL>U ECYiJǴS2wЎvUp֪"TqK4Fj%@Dlȧ ⦊6c3_< c݈&Ux! ,gX\Ԕݴ#֜8e)L1 A7&(yF: z{"g) g)SւOUQOj;FziFNh^!n@.rJQ{R cie;^09n3N)q0J=1L;҃ cXE6DfPhZRrr 1&@C4I܆HpUi6A1ٓך}fv-dW8GJ_C;K0q(V䴖RD<{UR!NU,fSqRơs)܈mlP>u` *Vth::ɮynzIE")cwNF~p⑊ 5O!6x3PQ!ctmtnԾ ˵8$@NX .{5&A+ZV?imf qxZضYqw"?UeF*1@CuNY7|b01?5!bE u42Ó$0)|82A֕&ͷ<2G暧nHy$f7˷(VmϒSbҐ;oX<{P Fi M$FW%@!RvӋ8շiH$Cۏҗɠ\u4304%IG"`$@!6z&dQCH˂Jz֡O"$X; IsV9 lOWSk($҄ຝ1'DLIN+mBn $QqA`]ߠP z\i\28=eWp1h)DkwV-q$FnGp1q&0ܿM+Ci`P# ^_`6)k$vzVS3ƥ7v2bJYKdP,8d'WZTE12(i%-$,#rpypFiCq= `SxsLx֜BF#RojLԆ8BW vʉ]O p>nQX` E(&OWhBH¬uP)/N7:T'L'L$Nb0e bӇE(#=( PM `/ zCwzBhA@ 3@=M*;^A$HcZ=*Z>ƓbRv) 6Sa1+r*4+ԚyPK"GqZz0hp^w/[iQ$qI:i>)Zbp)8ch9 TQ#4x_Oj  x1 /PHHy{FsL)H'E"H==hT;M@~X7j܀sfpOQ#ht%GSV^9;1LI(LtcM' Qi $ځBp'嬝ZI )5}Z8ɍ~ϙ%|!UCFd 4g#5(\6j(@,jB`H#9#kƗg=DEjhB ^xxЖvJrQ=>r0SȁqjƃgGQZf%ʠl04-K3y˂2g_݆rrw"Vx@B:whȤ̑Vy3IkBU e eB`TW#e]kB RX[eKkGn9Fb%zvVUdʷz 8>SfwS9Y4,{HEۚSe\ cH'ҘE;UG~eGT^,33 sL­Hcw'X.E 2ˊeX9O ϸƪS&Bpgc''tl*I==h B,8ZFlz+zS4 2 ((J+9C9QsHLAi>QH:ߥ*H4Ui@曜 KCҘ| GN恊B=iy=i# g+LGnrM?px4:ӳaz L 8)|?1GJS1Zv'8㹤S׎iGZ`9zRfˌ֘0 4n-EVk#m⁤HSp!EdiQ΄*V¯֝$T*EFn;[ 4eU &Fm#ݔg#ҫ hWؠcvRHX+iۨ(0Ouv*.OZ#XL+TSS4zP#Ҟ CH=qQy1* 28`G bR28[6ҲET,ڴoOz"KyS|Uy ڃ)Wc*b q"p\;I AP]i/qV u5 EԜj1+JES`wAg\1z.qI)p7t?:qNjA(8@9Sx$y6rv!?7zV 0'!oJܮx1?t%OJE$7qQ3n~(oS@#TE*`Fk:Swnx8iÜ<'=vR3̣ցB( Xnwc*jB$xTԒ/JO }":t;zޣ@ TM6S՘Q25FPCg_ao‒,ܠQ tw|U\#յfW\j #4)}xP+8Rq@\g!yTpzR ;NE +o;'+Rl\RG= >8gZ` MxL.0iT8AZqn3O\F^@49rwI'ځg;#x M]E؁9W.FT`2= KA,%Q;Av~FL@+2hHW h r )Q96/~qli1Oeja SN sM1ݨAoPϽ<~QF̒zPeE(;Fq֤eq3s.Hi&HBLޤ{P2.3N+e1H+F͓@ qy:"ZU$UU~^PM968oX^é"K,or;WE=R5̿|o.wg 5<9a$J֒=_ &}Ei||U1jc߮)"6kET('u1VBX*rL'bs֬%/`TwVL*SRCϵLh#JӮ<" ֺ)+3M:b`6EPM4m&UGPI@<.;R6@bi`sRGzch)*)ݫ̿FUb|}֡AfH 9^-z~s1zVLjo^  ~Fa(||GJ:\ L}XʼqUL榊6@۹4k"[rn߱]"Up̽+*v-[Ӝ%2qJEʌnS~g %Aɫ "K<~ZY슡EU.q8n˕f˔ :Ӱ)*iw¢IB.i'̸Wˉ2ME SW\VccE%cT[YWzSe{v/'"`$q(Y9y ZHW12=a8P[1M- 2@Y09~G5P{SݦTsQ[*d;P+aiVBJ71ڝQe|sBj%ʮ"=:Pq)2Ja4_b0h?3qNT!5A 8g8< E589twr)_R$ H'+)8Ȧ nP96=jFn:T AlcDR8`]az/Z|%+oKBy+)rD P J1Ozȥ@xapFOZHcWӜNj3&GNҘn&ʮ@S=@DqӎOwNwt5lKR"^1GSs@>;R@PNJ1i#QgijqޘW#)px-W9JqXw>HÌtNqTJR'<H H O$)`9(mum712Vdr2FqHҢ sYH磻NgQI\V4$Nq]<Oq\\I8 ]:HNO3#.Nj}}jgQgn{ Tpt~".}産t];EnA` _5阣lDʮt>leXӘv( oARH*M6m=i w95F@9^hj zix8GqFriF<iC=i9Hw`@ O)N*BvZ<CCTI4:N E X8aSdl/1]@^棐RUv$JkH]YANWzSn)4M?gHݳJrLNWL87^sT3GPi_-8NjԌ ^#5کrJzԫpcjH8Nee1LVF`z Q*l DmAej%M4*Q\iv7HbpMI-rW_s@ODkg#r҉ h1Ǡ : l/cZ'K bY7~8acԵX-lz+.UE\YvT}j wm۹)W1) TW+E$o> V[i Wv U@gp ңl}܎I؇_5r?k9KgzT`OATCjҞzV#N\ȏfEAɧ$eEeͮe +6.>XF 拍 3y!weBW0Ð=kmBbd踫`PQ՗y9枧-ɦD lc8*q_"Fda)"MnHcV4"Y ڵF!!ݞբŃJt7 #&*PJ5rPsTS*10;QrA|`J86Y'Q!1&`}jQ6,h2V ӄ.URDA9?Z$d940D$TI ȧW882d&1B0hӭFS`Զ0j:̥ޥR,})^MFHW-$\Tr\8 -$Nø%$`C(R91DAɦ-S4q#*E`;Ԋ#2@z朑pހq֡t ;_w`*P}e%ߚ,5+(v(\O&ffh#%@:P &&l˹1ҟ21D>]Tak6[i\rW,io72s&ݵJV,)=JB#.;W+Y#5˻IڸEAc5=N,%%s]ʤdt8?)lh+{ԑD%V5V庹 o'w? #Y@e?)N6t2(=K XIVJI| hgV.VY)^AN+&( +1`6b4Hܮs9f 3:zZ nT  qM&KFXYa!նdjjIu *HVU/8idZȕjMH49Om8"`-8'8E8%LQ9<;GZp=dtRg֬]ʅJ*pzTQNzә@boҨ6RB>Q֜`YJ쿭(~2G)i[vvN#NiǮj$l f=yؐpizHc.gڡpbz bQM2DF8S' 2"dZì@@Th":*&b R8~'f#:+pۉ]jvKY UPT.ޝ`W:b\cpsS6()8< ,O0`Rm-qg,r 0|PI"\51̸83r@QC.=@@=: ڞ1HJ 5=W'4 g5"1N})@9LqJ=iFiȠ*CqHPL܊{b  98f1@91l\曏iq(\OҐhF:JH=)4\Pѐ `8})@DOn |is+򎦛$g3\G|g#'t )sfySo8WlL[Rm&u'@{WJ3HGE%E t1Ay=)ȧgi^(dsQNT p4#4 xr(#!#/9!taң*@%FM!PUEJNe8ɠ(',5G?SRϥ^@2 p=*]*1Va5eNTHRiqUsH\]=+7yY%E&C5S4si_JEJirit84Ƞ w5.J1p"YF h8Rf{] ba^h Gԇ8+<YO]ԛ7)@r)U(? =  E%ګmUjv(\`36j0TOff^rY@Y2E?(\h JcXjbQިgrhfW(o)٘=*">91 zAC$ҎO_S8A-xJz[h9A@)x&&"٣E;ˁަS$}ÚZMxLh;H9QnpVkTĴgy&wWy=+1)GE; 9#oSZ}Coc/5X&1}j$Va 9`Ӳ|Uޤ3YIN KXt=},T  J.\^*8(v7g_i' }&$#UK>*kx4u U:1SUؕ_!+jF.~\㚏$" @uU`TR b=ˉ Æ^EAn"bD1Rd10 N'\qAxn '8p~йim<@SFqH@sI@Nzހ Ըi9cH5M)`")-RH?y5*A>^ixd' # k~hIgN0qFБĶር};SFFF%8S܊oi,r ReIţ_Z_/sR?AHcxS2:R+bƐ*:4-֘ !`۠~TS ;bϽ/昄JIG94JN5#q7,r)-`a^)nRЛLB^= tL( d6kQ)HVe+@>oUL9(HHpUK(}+լmӴح!m9gOfڍ;WS$͚L;h ڗ&2S^Bp+&zԼ.q$ 6֝K?tӹ6%'o$H=iLA 4f?v7׊.;HXSG J! >#sc+!\|riŸ@\M#*TNlF9 <Ϩʒp(dB#AlS2;MD[oyJŦ ;N6H3< cB9fy$~P}i,MBn6 A8h䐰` X``ݵԬQ:@?%".2 +LLn> Is#bCp EC& X5*ڠ})l*ޢ\d6&@Ci 54Qr>4@ դ`F K*pGJAIoS<̩$>c(_֧q@=V4ݖ4R2+w29]`V H=G9v~IScXRG *]Aj I3jdm ҆ P"Ulf  sUZ揕,W*FN{_M`Z+y5 ڪ)mT w+I|á5TTm"K8*,mss]A0ÌH6R2k6ztVHA$ۻFѩ95dflJGd`Lվ"|W5m3MK%R╎5Э 1i"àrs,@xӂr:qFp 0+NK#fӋƱwXJim#c *i7s@)X.2qSoݾ*OAm5q,`o"]99Z{/:1+@(++NPRem)NWHq\m1E.SIt+gk2#){y%>Yx[c Ug'4e@{E*Hsu3?(YӢ+٘k E?ZI _$7$\GLqI0V˞ri<f,O1%Hgd#S{P 0#Qȕ'i(p9]ۀ5P\\n=H NHT2ːP!b+{bNG4gv7B1~BH|w<?x{]b$8 ?9BȦU$VfEL>N.)ֶ]W,V ڤkBHNN;TBf&|Uc)' : )x? vx3`!;qMq>'@ay8 )@KHBR>aMc+1I2BaeHR =*I"yIfg$` JҨ!p[&J$V#;˴z@dҀNJ1n L=VIr}&x>ᇮE >aJc i9MC`}*n7Mq3 71E]#)#b!ZV.LS2:$T.ъjE?y LF$lM+9.p1Dʥ0E@AaS3Ґ*mPHɀZC%irs3y2Y"IK#L*IZ)<\m9=jˮ{%ISL {})LRB性i9R q9)`ѻ S8K G/4n,ۜ]*ֺT-5́OaX~#񍦄mjDx!k EB>:)QKuݘ"n:ѿ52Uid` zFsPxDTK'N3QƻjuT- *zTF>Sp{Pfݷ8sޛbŒuG4 i$M f9 zS A柜pQV# ZhKjG"MoȘ=2ԣ{P TҶXzSGZ. \곑EYP05JH]Z3SѶ6ہ Xma5܏NՕi 82DzM92;G# ȧg4#ХT)qP0*zv/SHaR7;A'i1yw q'Cҙ'D#ref]ځG~&6Rb|'0J#dhP`*X QWL|1u;؋kq#!Ġ\tK^ț#ylX#>W0Jr S`E8sғyn1@ l>cN'bf*zCHkO*=;I9>\dc{L(~j6i9]Fyښ1N%$h낤n4P(棌v.:h$E^i&ɔ9Ȣ"# fxOaDq6zl$fX`)Ő*u#2c)m ?,f8!‚EOQOل3<䎴8#  ?ɨY Sba@M7vA C 3&9(Kӭ)y'<M''{K*)&⑓x#݌wavPI^z@ K7SJ;a`:V1qcH%Q T{%rπ=*"܍uɓACgJWg@\4 cw"ȥ8 DDnq.pOLT7S4kwbIEgޫn\`dn ¿ ҫX7pT%?*C*b Z$Q0ҮHAmdž1=M#x DU4@rڒPVp/ت<BXJR9z eS!*4w*20^=iǁs(cjN (4Fz A1JAc VC$$ڪ2:fv\UXT<Њ:L[vpy ݵ}Ges+jjcO @9ޭ3c$Q+VsIQ*Aj)#[ ;t GOJH]0p1M}j@@8b(du87h^3F9`f*đ*'';pܹ&9-P\p9UgH" p;湛lEyrſ:$V2RIP$eui ݏJ B@LS卆C](z}Vt"·^Տ5m٘5q.DlJ7;*fG>Թp*##RGdzUQrl n gL2~cdf23K$QHQrlē/$U]R=zy1T9s\#*+[ՍC`RꚐӭ]8=n"t.5NdMc" nJgg73ǠeKȡJ+\2sQ\\>]ADV4`ˌ&fQV(Zyf B=:SgAM;;u1Li6oj >c nZ=Ok]I!,8qrb+_Bpw1H)#-vt[ 081oӨH[eTvx S|À9.[0"TQbpԁ]9AA tk#-RݳLUnЬX/."vt'_j\ZFgTvm'4k8PgEB '3Hsɪ7bBLy)E.p}M L"09 Қp4OLRg;dPaK mkY5 {8µ.p@4/SQwAUI$U_0 [})=f3Qd1 q֔G9y#Eb?A`mS؎h(wMXUF|⬀ FrrqAh'ӥ/T< irZ\H4B cnHc4ئKqJGFGQ;s(:`ҩ4uqB G͜v zrivn3'9Ƞ JdnH:Sg!\E*V# M)q(`N hRALrXhH`e:s/H*lSfUԍ=L˲`gQ.G_mXjʏN{os pj"aL6{]qNbƑDH U9$#Z`I`Ҟ5Ga{R4X|#5$dYVHi`Q9$R`V9C|Mg4q/7k8P2sHXi]`>_J" c<䐿5?h_3Mu?ZV*]Lݖ#wXNi7l@+j :ҍ1&Qzd<J Lo1UIjBȪ3'^:Tg ~}jx4H:5*;h/JPp*RH#i;,&ŏL _W0c,qC*<s*ѾofnH 6+Dʜ{Fyf#sWT# x[LSK5чh`K[uX9t9#XqaTܹn,@uSl`]QUn3Sc 22}q@"U%&"Q(hRe39%`ɢEt3Rp*-}Bd?+Uf9vvSqi\5r;-F1H"A®sR#|HJh n@\t7 ?J nуOjqB!%Xn]rqڋH{PcEpOҐ" :^&4) +Tr<QրCCI1r=)&HIRKhyEV2҂-;q4D$D@pOyZ{.wc#8i3Kub kѮZ+c^ԠF;`WҴNXrx09"i0n#5 X~4'B2jDV,Px$y ڙIS҂IsR5 ݌ eN*'U3U=) )if{A_23Ueځ=1QM'5pMA`:slFid{W>ȦiK(R3ژ|J*h)+PB3>&gnbk[&:޼AOe'{ʔRFVrvStrzԏWv%V_[y!, {d,LfRmVIt_ J` 1>l r>SOv,㚴 8"GYs10}QQfIE W&W8J2? gޤzҜQ(;4i3i q@rx4f^٦dSNF4 ځ=injsTmV%UzT*Fw$pQMm]  U.6SsFiyRY8$T̑n;U\řrBe\mɂ>alj76G?$\TX9 7stw$҆P;i?8iQM/nZqPs8ɴ쵡it|ٗhMeVvpGzŖ`` 4*8֫`Sc 418Sw 5/A"'5vwp)IA2J뷓Tn$3ERJqP:HHmoDdhMNI5axKsC ҀYEvދ/;3tMUl sQCq :ҹj3TAoiЖ<**>ɩf*P'4pdڏT' A=qAN)U#g;Iarf`[J4f;f>& Sņ23C1?Z>ȠI+"7Z¨+dV)sO*,s@h 92;So`R7>U o `sOL33ґX=i`u&zST)b7~LBAl?JyYBy8UQ2EF 9䊆@UU)sVA*`FN]VЙO_ ?J?5[,p-(,xf'$7`3LE*;R^) \n1ڈ֥FW\hULIdSbs@XRm/'QaFI'}@J0A:clQ%YO {Py؜0F`?*ܹA.RgUy pY@AnM1Hy)صM{ ]\XR2!V"ETc A,hw S@64Jq黹A-PFT*UZz/"[tFeW$Tjw!"EW ҡl>E~j#mM&R t&\g31QhW- ,gpң'6╛i&0NM Erˑt&<߂ !riE:G<ӛ&qS9Л@s\4ؠ`嘑VLFpH N*9d fc<1L8T.94r[{ Rp D J_'v MbBcdg IN(ȓjvL61җ`ґ<41{gwXW","}ZǭR)[H J?70 +H&ᖾ#Bz6k1od!HN@\`S5ܕgA4ڃ)7LrS c"$gG;I4&OyI)T7"`ze)F`ܧ j%<*nɨAIJqHߗ94̚Fsޟ(4.E2Xdyd'upᛀ%YΆA^H~a5(f 0W+|l֢[4IHG'1W^I(tV$r2gzEҙ=.rL]N۪9ly1) ٓ=hRrcPöEXb_[85JT(,*nj h3!8=h4i7gvA5Xb)0Z0`ڒ+)98($`jՙHB9l{F{ӯŊЭN1R7NѹFc1ء k$_z͖bK(憇HcQ#g:|(`1A-z杍aH 8d 6g\ &M!4sF(4SF8c0hN{fG~phxIL@.{POjP61 J`jc65!bR٦犌6s&4\qJ;SFAQCu@(8btO@(ڣV!iFjj}搀{s@R3TeJ "l=09SS uiS4$?)̉*8"F#ޚ\(+BHN#lVϽgH8CC_^=3JLAIfu!).P;QrQ.+JrȬ2}+(@µ*ep9EÑt5AAfvQqWdi-ʃ;qIqN#)1S<5 E1"t0D-4I#4< v@po4rh P^HFz;ӆ=0)Tրӽ&yN)@ $g0qN=x޹ڜi?#m1ANosH7JV4w@nyh|[I(j؎TOoSWG5ʹ*T]5y̙^sށFM\碋vp2j2 [[wJE2:>n aZ4*EeN"hFMС/@F2(H<"fn;}5npe\6r՟4A(@J=*L"-zJA b8W@=jU*@OʣxhL{*#Jx/zP$#"zPLPx!qJSҀw(9#4Ҙ/i*=SE2F24 9* UN;ԁ OxiV7N#ʏq<Li-G"/4RM--Ik8\Iwݷ^r)ʹp܂)銰cb(D 1G)\H钣4Ln1Or-j$RyAx.(#&ػQx?0SBdcҤ d0^G9[>6zuB4#$yeϥHIU$džI""eU9Hs ESj䍠qQ  $jd4JFKSqI")Q z:)܎1ADjx*qL#zq FAd 8N3Ҁ0wH&T FTdӃ@Rp(1Nۇޜp Z4X,3V1g\g.Q G"Y,U֩K˴LH$ 6CNiQ)hrO^8ASSUI53oHGTJ1iRt3QK$"/`- rzd,lջ(XPAlf*4R5!0ݓ*US!fVFD;UX)̱QOx EHnTQ*VaI隻lvAHMNY bEMBvsS9є|JQ/ {FR(O-W9jsNpУ;S,ITNIS*#:0iK"h{(Tmj#G 9کVa=*[%mr;ԛDx;>j}i(r r*nE*GQ@s"R )#/ҝعPIr˓G#H&s<-i,0cZ=|{t(:ye &Af*P[x%P` Qas\/c#P׭t涤;c'ҤlHT(JvE1c5Q"P~nsH6Må1I(i&@M2(;*:a`,HO  3dTcޭ"[B\yV"$'n NyrM @L '$6 !Zr[{.aAPsT+G;)W!ڤFws֤Z8G{(\mG9c^p&Ɓ:S^0HKl HϙdPJŜI¬q4m3"+})9fA)<H"xr`o )sJF\6r7SĪ񍣚2dl̘<q%Ssj0@9 8!sx %#t$Ww& W k `Q dIT̿,5 92l./X]E\q+K\f`LC1#3Hq֤DjӖ3#3p:4PYr3,0N)ZU9t x$sUcǵCr^Ai#4Ʋ6JEPP ]lc.rj2 XTsQcyb0q@9r%yq0+גA \Ȇ;pⲑI 0T56TvC>YYqPh ¶M-‚sX\8a9G?N\tl#)[q$N+E+}JN%JVr3g;TҪ $6H@A^5(tJbePUq)N #U$|Uށ 95 i>l  $ސ}h-(#\0Pzo =)^Hl-(4j-MkU@ǭq7)ME";"Sx\uPVO \M"\+6ܶ:cjoTwva:j-i0….9";9h;pm;q4nTbW't L>XMsvŝ[קLᄜTYZ%#wcd288$8jaLMaFGJ  7&qOnFc恊FGZF94RBܚy=*!"/rݱЅ؎]ɡ 猎c*ҵѳUnDkQ ERm,nzETkz怰>NyYAnbT|9Km%R7VC944AjʒH'$ x52@h:o<!Db* I>\qqg.s8͟,m̆"ۋ[}i(r(ǟz| qs*5cK=ԇ]EkdbøSX}?η ; mǵL͑vR~g&f]IR:ƦcO~v34Bjwx=kS\V1`(u?vi:})=bU OTLͅb{T[7LjF/ۉRQҢQ 3AQn.K/<D, j9 g mj>n0\{TL"9K22Ǒޤ!I^£ɍ0 Jvs^[ !X5Q1a2TZ3GiڭAc=-āJQFXqҋ*u=NQ0g`Ҝ)]S~*0:T"XF=>RE6Vež[) xCc!= !g,M n Ѕ#xԷn]SN84HRC/5% U@#JcUFih$JCQ<HWl郚l~댜ӰK(,Kr(5w!G^jd9Pүp1a=3NQE!ȩS,Z# $ܰ+R 0sV)sQ4j|.k#*њi< b 4䐟L/?ӵJTduԌ#$s]GޤK#wlP^)$bi=N=JFs40IFq%%Xt싞h=T$B10Φ|ɁU+V=Ln^ԝbJ!,y!GJevi~tf_G}5/pMCHN/s6 荅U]JA_bYKrjG59Ch"J~`:Q95i&9'bHwAN01yjH)`QѣЯ#!7FK6! v"c^-h8A4ҽDː=-9}V;r'`}*f3V]ypdjzU |TD2L+O4fVN7>o},׬0jGsqJIsK,deB *.2y:sL*aT9yyȧ_1o|I$,VIbsD j;i\\&lƣo ,oNϥEa┮dݜLgaOZ]^|,\p+hn7 .\s[vȤlb%4mdRpN <09[i>U@!(b=fh9 zr4m&-F3Py=ijbB␞x({ѻ܀ph&XU})DJu52¤ hK]9X[PqYUԲ-y#%maBaQb<&iu=i2{S6<5`1 $SSUhl3@ʾPg181֑b"\5*0{$8Q'p; p2yi/rsV &X=MW)<{ O4IZ"wU&G#v$ިIm2CKo4rcUdc(92A0MVMn[ۑVO5엞"ZiQYN:UmbZxl@M2 8:~qd;o^hނ☈v=iiYqҚp=i Rޔri3҆0:T 4=4P2iwi$Pi<ӈ$piqMm=).9,3PyPn>GRV @"MҰIi5MMw| 6xnՄvѥerAڐN P$DV.psft1 tF*ɴޚ6u4U{P2iBKӭe]ۋR>RsYcY7pr*U!`0M>w/&j@qJ4)u(" 6u4o1C5*)vgu)c֐PA14˵$pH3ʅb=" yPi &ޑ9QX$$Yp]J8"=h*L.A ,="?f1)r3hqOuf(0㱦iJv&F Xw!,*#際;ښѮr8';ap( c@&BlnA~0b[ڞ"SN8Jf9ycۥ! NzF9tj2Se N#$ VFb84b C$`gަ$Y^0sWk}?‚Ԕ=*¿σTT '14XގI9R9;~)mƂh 12P\{R+nRzw$!f jpب$\V3R71f|zRD!qH*f!{aWR9WJ@wxTc*1ӣ -[ERAJd"21f9$* X*h' L\H(^;BR>H͌"!b0:E0dQvD*g}*Aí5r@A y394t<ӏ@/jr*%# 8L QlsH yaMu)RC)t( 8PJn9&54x5 uɧHz\՘H57A@Ѐ}GPU|S})1n`#:Vf67bD4}*6#)͝SI!)XtքU; NiS!1,dz6!%6XW]AђE9$fmgm֒H>*J,b۽}kX#P1X 5o& 4sT:RUx_rޕHh3Yr ֱ/C*IZ:ڳbԷA"gn*dl/~LfŽ5(롻!ta;K# bɕ,tQPgY:$ 6ؽqAVr6G4ܱܛi"iX2)3ct|w9PKv84?zH_L s9>1ךvP8Uw9mhqQa]ӕC9+*)@\pۻAD{TN1A;ȥc(;Z5Scy^-{PAiIA]XLI7\tsRh1\󀙤 |',XaT۸̊|ԙH ~d9&FXc=3RlyQvy 7jc@<>ޜ}x+TFzS@T?̧>a 3rN=H~4L֪,R@9P,RIɭ ː276M XL6nޣe#I Rn  e1@0J.U3MsN*1|/~\,?p$OzRlynڕf=i^pzR A֝Co Α伛 ÊhaWc }š4K\tP*U{T\F)=q)؀ MP6 @R`=iȜ&)p2z!!*2] !sR`oɀ'H4qI8yH !f!8懗1/):]$tl1+(m*"N1T<@S,}HE_1 4Fg1(w #IJH ҂84G%44+JR3LLE0qJ8I${Ңqdn94SP)SGt>4 :*k>t+$Q8A<_md&o< LƎp[>Tu&Y%٪^&1PB<ֻ2Xy8z-QxR $v#mR]i\#qq!P>i [tQ#8vF M y< MB#IcOhBLΟ)>7EP$u6 "1XU䶕)XBQ )6RE7h `;2I^tU,27_jMܫ#:K!9##޳ٕ`sJ4:հMYiߖPc7sʝq:L֥q`n(}QoFkU+t{uhH8Jw堼k:CJS4Ug_:+VKfsAޢ d M\Jky .3G4C0RJؚ߆p/a'ip *ҳt8rucwVb8ɮ/ Ѝŏ5kUPq,N!FڧTfO ۅq\m=,ҝe&vB\ݐNMf^kF &P$ZYeJɝ[;NK;R J:*} TDZƻ]楶SO 5<{:+p*A^~.v+9]~&+VRt~k< I:[} m5iirB7˂9ad%NTئڻG]ud r4э=^VK`nx0.* !S{q6CYS92G&E# ֤@<(oZsr*5{EfnKYBsV2` ^jM:I@ QђcrrSidR"\n486I}AI0iW FR YzwTL+n㱤'ˉw@hV-Gն}铡\bXM>[5l*/'w}5%;$i_kS| $q!gcAQ;!NU -Q ݟB;R۠<{b9T&4&ú *3.ՁdT1nXWE)b#*V0,sOM>!.4Xt gTUuѡǰd]i Ix4XDuJpnq)!r֙m<^6:L+pEJG|l92[+,r3]e|"E qdN+[Ex>-ȩti:a!R-ީHd:*3!XF5pyj[4L%+y4I?:A䌺j(;QAjſ/wzA.H[!@SR">rGJȝ)'0G5`1rypwQ˜ )ӱfяz@ nl8@4p4Ac!0SY4&v%Ҙ:R@A➇QT);\㚼BЃִ7)_-d)-SN A-R"nSp$읻V,-hoY});rjy,. jn2i4RLCxhIqۊCjJ!\:k f Ab0*hL;jD#8Rbi3Qr(ɤbˑިu$.Ʀ7qyNI d=23GD!rph$NTj `{b]FB)`i\262)2kisic5SOFZD 79.e4QMJvݫJ̩R"Q6ՃLR,xJ*Y2)6edo*PEV*ō>)(LRdM;*DcVdՃO;cyXjRL#h ҔnnRSpdRoZh$ݷ=A&isR s`u'0IaIM) )0S"$DiY3>92R_0 {Jн$\.sS#z0Ȯy9O2NJY#2ЎC1R)I7zReqyJ$5%)p; NT!'i+b @XY.zА- g5 u}ض5#x+֜p +H%'&Fcw si=)vҝ )1\=M#7ӐbDw2ރ!XcEGlP#f@ }iz0'u;fzB7c2NOjxE4 (杍)X2RHrNGJb 7ҌwzAv'H@=(c7wcC#s)0G4MXmŒrx8 CJJf3iI?6*L(`6r)>[Jkolv!AOmÃLnS§ZQ)' v{PϥWwb杸sHpN3C`3jSQ5*! by4Sҗ;[C8;SqiP{R ? 9(<M46E8{sN /Nhpzg2BN;SrH!U -{(m4`iJȥWj!Zxz òJH̴ 9y8nGHJR5ۍW`,Oh vƑCN^jR3C⁑q5^f~֘㡦E1''.67&IߞzVi>\MpMe-κKQG, z֍<VPYz{+J;A 8Lc3 0*H)aŽ0OJ%y!(tJrڵ"WqTR0kAc6LT*RG P uw4I eA 8&葍{aYm6-ޕc${ԏdl=q֤Lŏljf |ҮnI5i`8 S]#~cS33jY8)+Iq5P9>v\*vXb(H#;8<Ԙ\8^?s giq}sS`)E2ϥK!ɦX)H)KbiW#9=h p#֚Cnby @q) ӈr(t|Hpa&\t5FLLQh'v@"ҍyj EoK ϔϨ K|G8My=* NSS J^) +R;sc @@=)0ph=i_gb}1ڢR c׻zRp8d'? ! Rni)@'pt3R` iO4t@&7ք\ T=(bp LqSvnf$9KcީQ)dH]WfPmj >P9rOzbɻ*GJKf,$p*$N@#[iʫ$2֓+"X:t0F:|6Ӑy=($W$p]\dɭ7^6>5UctGP73ن:z֩ff{fE8@N$1#q84z RC: bq ͩ ly7e$$B~z7Q+$1Pwjkc!x]o$ڪKq,4H*M-ZOH7]^;y㷈C< / -N+Յ]E jv4\ܩHPGg8QqQo3!۩ ;]VV9"Z\րU$1rz sH$@iM;jvHS[P.&O  P8FH&HF+sR+?-5`A Gzu0U$ 3lOETKҘR#'HXjiɦrO8o@ȟ>NANjA d9?xb2@@|ƃ)}i$݇n*eȪHNyTEHp $"q:qQjohw;@AN/EPOjxE^jNerDDgo J*sq6繪 OHƝy<|j2\R@+Y 3Md)9e.R$#j"˃,ZyIڀcN dϭG &7f6T&Hq=yʑ;=1z ;GR$+H@8ḯ? 5ux)(y i:RlyXz4wB5AgHu5KC:%b"05N ]d.wt5VR3T=栉^4gh#5H-Gs#(=)OCK~ ݌)q89;v# s.pGZbX)˕rGz@&I<3S2~03 b_h9&jMxy}efӷP[3<-Қ4^nj&xA >`B2j66֭2"!6b>v0LUޝisNW@&ܟ! >SLD\=J 7le蚒xȷ1T­n ؎OU&'mڡE7 NI⡸4dr+;J: vNҢ^.z֜ >w>숤a&T8f&a5jg=K|^*ݞ5VKpHA"}^L3Z &&=~c8Y7c^R2DYHd|>qЯ?x5ͷz⋍" (AF(݆85$J|zw *'(E)qƤHWz֓tPd7k/Ȅ#ս3SR%f 49WGß," k)XJ]Đkbr3ڼĚguS>Jɜ2jT8h*@ SHsVLM]sXgKY#I > nCvH-t5*ۇ7.үN%Wj>68y΀SֳҶnQ"V\|IV89nN4$c6P avS;"r_TuHoAWT$Wڼq z|ش.i̸QI$oGƪcpuc?ٕbSR um8[Jb!8isVt_|о.=đ&V*3 [A"Io%enƺ ?@d,9 W oޘAbNfR}QB8Sq8cS%B u-ėYg89j]j2&@ uK4Fic. rrKWꏻsSL뚪7q#(T/mD5t³ٔ/&Oֈ_4nY>jelbfudcMMcv#*$+ J ?v8ZƔQR[;+eȷW=AHh{T̷ ;Ha-cNdA$\A&S"m95l2TI̪7}j͹*qu2Yw\H)\0cnn%Vg6cMI,Zθ N -LmE/.Q`hHSke ;Kϳ}zj;"HЏMc ߊ9I4qKQbA(kԡNZ5sBOyPIBO\voȣ88@ST&SqG'믱DIo?J-Wc`֏-͸(9KyYrwTZd$o荇zچxc'rw ?ZC4sީJ3ͱ1dc1 5kѪgRYx&z^բg<5{tl2{]őh4`YCN ~pXG[֚{U/Ȱ 8kb^I3Py'VM-`O0YȒdAgDmbT6;ON[iVqHBWEW]Imj6oybVJY " &X*fOV&Eɪ$%Ks$MZFmKu$/TY>5hz B o}ǨS ՈEmۉ#g\K9-)8>sP=V)L1FhjJŦUaO\rG#:wh#Y8^X:R=1J_w9cԐy5" iE2lNjE U` _GB˸GhToWi`.=CDr()J5 ִ-g!v;n5FHwD+TQ>65/ 31ƙ: (%.%9 xn+l8&YcȫMQa[p($LmrHJcr<~-2[64I".[) s MMB,,z D Gziv;$pSz@ivFq(5+ci8 NqGZ፹#8`йi P5@w(1b$q۵.#"1'8 qN܌!QҘTθ\>ڥ08n6䞔l҄.+ It;qL?j2\-I`涅\#pN(ɰ Q0'=IJ 3 (WFKzV{=(ڤҀJ0܅u+`HE| c+cC)8@M6m%9pX($3U(gH`ڤbDypj f̟+dTܦsR"U cK9($!vЛ#8!TݜOt DXK6*Zެ"5Q3c֚+N qZyW~38qL; PZ@O@N G$0JpQ;qҁUٴ?N)0W4ȣS4yL=XVԅIW+J iv \ cr%Li jGCoLf2rOJ$pyIށG?=j" @}ו(&tT&(B"Anh6>xSɂֳ9c@!R7J7:RpPPC:S-I! WLj˯>]Ym#HnQ6s$mp`yd.O95"WO/|jx6*֧Vb'[Dr' Բ]yih2{ӕ- GH&Qӱ`P/AF0F?Z˟za<g4;.T*ZW#B^ 1܄TRٴ`=I`đzԫFFߘ(i0EBb@&+|Sn#ݻ>74 Ӓ9VUBQ۽fs(tg4bT]Aǵ4:v=i*2Fsڅpy95Cg:T/"Oj6U=3Hrw=*'BJ5;CQCv-s4 ҟ.'BGCQ᷀vάWviTܮK_i Z16+65I٩I$;GZ.Ku3|͊&R 3LLm,p8rmV}oCYi2Zooܨ#ү]Kd5YEkn$q 9Q%0YY{h¨)pNP# ڔz՜mBTOZR 6֬6KUy9 ED[qҬDI5UƒMJvj*qд$ y QFHRzrUXz \<7ٰ۰lJNHӽ) U5o:Ob V;hu;6=B' T pxg%CmZce3MΘ\4/SUnB8?u[Dd= ۈULrE҉oZ棾ee螵f+T9?1ObBM`CY ;!{q1J/D-|ǡq&no@rõ^+FB' ,Z=3!%Ak6Tگk"Eivd#71T$({QqжqIj\kD.shZ1GJM-PU ' V$u42x4 5<Ք/ZId\ g4wyo^ac@6us!̟\\)$$0*+nu@5BC]䚨NzY NR?1ǵ"\*)9sUU#kO^)"V0Zh9ROZ$v;yR<)րW>sLc'b2@*]-GCJ)MrVS֯]og*}ԠfV9 N|ϵU'Y6|S.-`b38V8H1Yb/S#ftF1@S \4[Ki ^LSW=+gU9pF2+ VgL{`T9BTMqiF gsLd9ǭ>6uZ 5LЭ7RFAxnv ئ4K/*d#Yu~ .KjJpk d*3p)܇lM;5V)ߚ85W1qc&Yw ֜Jϸ!)2Q`9 M!犏h#5&茌z/S)6iCz1C '9sQ84(>Q)9 Ҕp4 իnҵ4ь c< UZCLCPm$lxII16Y{njW␈^&iACwem}jw`)|ioG$xL0^7heD9Z+&6W~i̬0v)`ᕊ F6kWN'zh´nH9r)Y@$c49Ch-K؆ <7wl#1Ü 2=X\SwZE\H#& >㠧r( : B90\( :p)!;z !$(`?4Inh SJ֞zS4YeOJlRl`h}Ct-3S&,mu1&ls֓P[hw3s: ɶ- fa$֪4G W5[_C\Tz yşFrtC[֌V&+b^:V"`=E]EIeO-z *隖drzVLN Dޣ "}wferO-QM:QzbHvAqh%= M2|UuM+-Ddi;֑w 3d|9/VF@[֨"I 빊Ҩ{X d+ `Oz'-8R!h"Ȅ4wRT@zS7#fRsLxmws]i s&[͍V-Gx_tb, X8<}Z* n 2O`jh?j9ṇ#Hjf#eS"\@]U1|.;!,)f2YÙqV-I"I֗p1M_r;2|ſ fVUfsH۲#Cmdz nHTn&8 ݀&9>P$#*Ԁ?Jւ=h}ýHEOIy@l3144 SZq e 0BX#$ʸs3mk(1ֱFrxLEƒPRKR8<++ǷZkcC`zUș Zwg-+ ?-"YtJdo*qZA<;93z \C,Ҁ9>vkd);^t\N󣎸.mbLdgBtϧˑUOqjɍї =1V^$GZmd–cA#?F=*lȔ fTeqCl%3PRdϥ2"|wWVpx硭{1! )ӊx#b-4#q`Y9^Q-O2LQ@RFsFAMbE"s"{{ŻV\}+V⠿ol%tkF|1fNFjgcRM^ԭHg)!XO$W G )+{i\ҩ:$d;j+Z'Aup0OZ!.1ڣy,B2ǑOX5 9見ʉe9h#->dwL`pib+;G\V2/4d\s}]m8l=*[VI7q"by0_I2s[$ `55%>RLϒQwE%VM1{տ@Ÿz9s=3W+N.6!Q9;b$dt,hT)* ] bAT-8-tqfDb6`iwO.Kd*J:G fi0Z$X:qIC)l)yY1VRj7\f9GjԯHJ7Ee&uSG1:[h+֘|ß*(84̤ȫ'PYnf0PHZNUFPkb÷w3I"ef+EzMƕGѹB0M;WB,q/pE(e)77$bͲ6TӲB䎴m<pqIܓ1qMO8 gS H Xسa3O(ČqH  K.9@-UA9,je&{07=pb(2|C[ZpT7΅.}=P剫a;Jg]rL ڡ-5i. ,PlOFP7zفI= 2L$&[@?DU< ֧ĈX)?#)7ڂ⯨ear |P`t&P7cv9'5Nw˞zMM'Ҡ'Q2driI ҕSmvkz=5\3 rT(,TgS$63 ҍt!1H?54Ɂ447ߎ@jdfo8}U0E&#O %ܡA­#KdPA#(aTyA<<9c4RdghB PI*ra-H2z\d(j)$'ZvYAZb"cVSRcɦbJk?T~-m9_&ΈA1;:|ABqIsSsfXl'NsJW )&XSeL.FJiQ8('ob!"4i)L*TԐHPc=y:Cn'l"2a7 ;V7M(%pirzWjpyȤMqLzո/w4CF꜒dڠI4N(}41)I# Êq\Twg5GOR ;nW4FWRQ49'*@R#4t\f [vAL 4SOYZx5x Req􍂊3I@($R})gaNM&R!\w(&wu'82oR12{F1>#1EapnCREJ1q֙jv9 1XEWSylbVՍt. +Y3emHړ[LhY#>)qAC(2qZV,&n1Ғe=Q*\rVnJ3')בM8BpTqN8 Ibe \I0tM8cQV29)6M&FIĩ3#TNnKgig/n*8rJI&w$#i>(>B+`eë#R,,MfMrPP{P\UvIp *RXsMi6㸃TX2I$y@|Zṿbm p;28ʡϥy6 ޤgc*$Ffc;yIo͝jŘ`X qj?t$[0sRS7 ,r@Hͳ8)x&Ų>XbN!XzMVv-f8HU=د!TfWa= Pc"e7ѝfbAZAyfˤj[k-vK97#5Qg"#HҜ0Nznx88RcaFiP \4ɥ"QLx2AJW&1iNs!PH)XZ8#ja`:;ңcWŠ޶֡l-دr;םE1YCIj7ԧ[{0H3B*ڟ۵r>aٛ/M;2*b([H]wY<+,|íf4e޵ۻ^+:"[z?IC4rJ$1ڠԷcLnٻtM{o97\t55c3}L¥+k&W# /Aɵ"b wXΛLw9(# :QҨ@0R`sqt@ 'J7`FRt~~:PS, ;!xB,#ݭ׫ #4n_\#xܚyPWh0s+ Nm:sNT*8OX.Eң"qjpG'VncԚfuFH9a_1&%WKtJ氵CAc+ɨtAs x 4y[Z_tۆ÷! q:,FRNk >Rke3))jt26ߔ׉ZkwrV {Gc}MFJz9"іǠJ Oa8ve939sUʦ H2y4pƴ9S$`Q88qI&IALu(jTMSt)r8VR)!57nI4=&*P>SQ2>JOqҁZB*N8Jk(H3i10M'@sRj658n;G @ O"6{pUP%rYrVe@5zu jʍIRBIb'*pXd"3QD pyr8BƖ0GGJ;!ݜVqpH(4F_ >R 2 r=&%[i婬wԒ8'uegQ-~\sWmyl&pI?7z#&ʔP 9rƻUu)Rh;3%zt`Լa 8 .\VВh'k2ܰ~NzdHQbFEeQZqcS<ݚeD#${S;ӓzW;MuDz7[<ѵLıs\s ۂhز|u&7wF)3IP*PY=AYp*"Bj4X>@WqiJx)ijV"/Qҩ.iq튒gWb>pI QC**aj&H[dz<@WbrZdMndz;8gw\P2 J I zAtءqz392āW˅j7E>CR#\*sW{ ,{>U)^Hnw`p*00sC1fDRz6I\+ *+ZEň^5 H*ɰ K*0|X Zmǵ8`qS0%A494!QJUfU#n3%qLe Ǟ)8 ),>ZJ߻1bG"*$'ƗqڐXz wljt(piAV9qTdh)^m2ÃYgg.~~@z pLlH☡rv8ٴjO,ԜUUS8/cU@S&NB_Q@`7I(VuRJRYˊB`Bp եR6!>P~yWk/Hs*Gn0w=jdc5!g'h&Tl`*MS6~Vuyb!rjwHDcTȀE;&@cQDmOZq\0EIjZY2,cvrGcAk&ԯ)xj>x)1O)uc&E[@@a5xF6!OByrA3BX֓Msۺ([DcS#(li3{$c+ҠH𭚅ݙ:r%:ւn 'jkk_6q h-tYTӠaUf ]N;UAB);duʜT+%{"ʨc}kxl ZʹEneuUUQ;yLPU 롲,ujI\ =ь+$RXu'{"Լ0EkF R=!Sq#~IT5ho=iI"r՘\PT1KߎI zS `g)l!O MA҅?/4B ␍ ֛[ZHI(l( PĂNh֜W<\#3r=sҗP!I7r*̃M69ۻ ̌K<}i H"RAKdMH& !$7NS9.TҖ*ߡ,zRDRZ;jV|qQ0*Yb&Sf8&*U{zֲ۬+ƒTrQUsT`V& \nr2qNEsLSy|r(6 NiPCԀc'S)q{\90gd8=isMN$qSzPp: NJ@9&Hs4S6SGޤ2B)rX`2 bhzfSSﶺRF$E3ju &q 5N2D c#vL_CztC`8 6vdxMZ59s"7T2X&:+2ؒ UV*:fNW.~^Ԓw\#BQ$ܩ7Fk1 !Td%I\Q+vZ'G =j̨ NP#cR#-,Dc0T"UlwH~8PxT\dR6V( SG"hd<maKp&4QUNfUb3ƚ8,f{%Py[R3YӳpC!=Oc)soִkK"'vTguA7)dݳl EuL՗uG#oJQi\'W\#]gpk KylGZ]`U.}Q6..vu>̹yWpcu5M޹5$fozI;xl[6N `OEG@lh#3. |dN1ej][Bsn})>"ZP,KHrڲü浅S:uWIKwl0WIJ\zMiK\&c[EE];[GV9Z>oWVPȫ~:Tqmn`}k%/qݚ- 7/Lh|f7*9d*AΥ̊PʯAEl@%yYbhVSTsՌXY3cqUUJ@W3o|P|Ejg'Q;?095%^*9. (W#|}z}D#GQޛ4= j (]_P+Jn*LPvm`ԅSr}4P ( x8## L™V8 ւAl EUfCJT &hxY#|չ;YZε ESQ IA 'AMf\7gюh'$P]S0pyA'Q)黷1@ǻ`x)4jy<ЏL,?ɦ̓ :Pj%9H۰0:ҸHϵs;9)ycF'RcEi|͌O+X< ST<ֲЪ RkkKKiMuo{0%0oz{FGGT,J 93ww*[{-Y{ ru@ "c jz͢yV*\ة m稨b`/C #M27y<sҗfi ԧ8✸N(\R;hyM&m9Cc84 8d.>sJsMr357JZ|"v@1΁ E!\R*rDiڜnTǭ5J3ܟ,-F=Jg^[΍4ɓ Y5f5;s`Ҡ[}?koHu$vz 1͌W cfe +bzArPiF8#+۟Z+1$8,g4hVnin#!R#m2rFl7j4d Es,'7tv `WɌ4m3FyU+CZef(A͈bE]H87Ԝ[3"8R lWiO ,kK+5|ؕ?{[ zPRArF)ؐw ! .C3m㠫i]8ne#vNҢ^$)0w %Z4g!.ҫ+9ܹe'2,,(A=*ڠ1'm̲6WT`p$UuUgGR9$0Eee~PA"3Ҫ_05&JsVfdɠi A&n:L hJFiʬI:Uufݷ<փDHܡv/z!: sRw sZh|sXSlB%Cp=kZ,rI^H媵%c0ri;Fi3֙jM=RB.DYM&yF\uR$摢'?&jҩ;]/N(2?E tsԅIzP!y*|Hvr)Uj@#1LpM 0s'\ 8vy)1>4҆<`trY1@S֞"XAjĐب}Hw61RDp%ApW3o&S)OCP/&IpiJGZl}1RĬ ާ*1n{TLbNR2gp#!1z,x<`u$dTjxb8;1g ;q@~H4p)h1ڥH5aւ(HI%qsSqAq" W{eFqڪ\fcEU_aX9ϭLPL3SPփf)``: 㡠6Uef`0jY on,U[kD`CV3m }\ی$`(sK pKJf^ǚ9vUI4{Hɑٝ+ٻ򂾵XcEkciȫWHȾ|<)\\[o,J''}*jZ|%DZ[r|4hK5%f<#0@_/nC)>zVVxW Z:Liɹr2gVKq#,#޺+qSWFdsJwQw9f7p85%mG%#\4H{։\ݭ_ȟK\d_`@ v5qxـܬW-Zg?)K،H;S$csI3RX) LKBjEcH{ M<ց[d# HU91 GˏZ-{Rd`qNp@0qڛʯZ t[v!NZa4 #<1H$݂9昈nvSl*2M0 (cR5ezP1W'hr 8ʎ)1R$'{Kr+k%Eڶ[i2@qr[۶C<3 kj|W"vgvTV/Xpvkr@zH+L^,c^G@$yܬ>`sN@fvnHbj:E;X6i ^Ye([[Ca+ڭEsZos+S<Ш5O*Dq^nW=]:;-XLK0& {ە/"kKʾY5HMzHUU6Kt f^ƪ2(A=54qo~R,{Ӯ"FgBPdŨ:KLķuk-SUebqד j2eRpr*h.[S y-8Khb]JJ c5N6*; N7mUT4f@wo$>T\t¡2n~\tqzr: jGFP sKC~;$6ӣ1IgְVEURzS|7q=WGF>1SCYCfId,6ڐms:uQ":'\[7OVK5iO$ZRhjHy0hKhA!F*༑P4mRdԌ.MQ{I_m Eqo+&^@1NJY*G]G$aRy8Ei: m7s>yuLCpNRVoN=s7>K(\c5aWqPw|w%Q= 8 ygER4%c[k#+U-䒿Zl F?imK(yiv Fe!OZ6 >qTcCN9J-֟yo%䐲䃀)ֶSJN2i &݋C%mҤ.g`i΋(#wB:WCg{6&b_#RG1<6)~qҷm<2|Z-"@憹$f4m6ue$Tԯ‚v;X9&`߂jLx%Ni)*օ^ 5&IuC;) A)FqR$CN=+X҂܈w|AaO M#9*3ƕ0IPKDj@A5'i2hH?Lf$lTM^< TSig̊ =jj$\sԩܷk8ղkS^WqHc3Fd@~l櫴FFzZṔ!NRzfĀpM?`yhR 6[$>ݓڝfI& ӕب'fk#:r9WMXq+^2HSdN|K`M8*ĩ8 48uӏZHe@[y=V,C R369Zj 285W9ԭs;]m '24qMZ~)xX081O қO*@sM#4&xъ Q<Pьt0<q81cABt8"sҔmS曒I{Ғ6 cq瞴NP,y4e:fnF ֠ĀHgalsPD:BdqO&U$rh\E kqQBhK|r#wQYEJ;sSBnZ3dm9&˃\"4NgA4 `9AP~Sji]FI>@f]ݳQцO2{$ރHGDbi[ I7ziqVVq(!#[X h0d4vnX1  4;4d[`Sς䊑ܪ7zG).{Od1 TxuT.XTc$S ($vdBTsSGƚїÅ";2̬vBIo%9=jۢeGAYF RrYsոVs1Rm &cP6["E"{($>QJ皴䄻 :-f6'ʆ1TTA^fFO|ݽD_ݞȹ]Bi{6ʴbUw c)#g 3֐2ͪ:'/֯Z֐C=,p; sr)q3A>ӰՙZj0_Ĥ`ddT܃s^j eGUJtV;H@u浌yhrNHJ$R,l;9wvU,e8b9un OjʽHR2̸Nvgr=iY o~j7h?]?ZI#{Q2rĵu ۾f=!*asנx;I<3:[F hqۦ1ZF*:Do" .VV[6+ĊGn+NDY}ؒ0>i%knPi;Z5aOqo>|%">w* ST=(Dfr/]8PzM宩~W>eP95Velު%>{O]ns7iG*#š̈́#{xkR~E:b"G=J:vpƌu K+6vב2);J'ˆ l X(dU&Um٪Ӫ>uAhֳ|e6VU$jp~:1HJ0GZYozQx(@r#}ַJYQmdf9Qwtޭʎš"jӌ3Tޕ]2υu="[` cQK JsJ  Zf>1ݷP6z-2HzwdD;P(@`=3&wq=&JA$9mNXڃ8d%z9>=M!U'i*zH3`GR9&9w6w2E9'#36=XA,yYG-ߵ03{؝5 c8$օĂerqZRl J#49* ̊]}iQ_)@=*y%H7'C2*;X[9N3q$V.tk=apXdev-t2[I *rbH!@}jM)9Pc8,x4ȑJw͞f6"yK3pE=aͻ~ZC 0(LnRa`C@*A8>#gq(Q֫;OبMVfcn*9h%'U1.z--t\pHEmӏb3zPk+xBj,iڪ/(9#)I<n 6Xg"U]NN)YĎIHv5'DQ a7N@$xga҂.KaOjl&FIV@JƎJ(w(ZR6iFa\ z8IJJLO>4JyՁJi; 02*ʂ!\9)FAh>Ri@\ ,wƻX#iYAhbf/4U_ʦ( s)+}a`mxc^=+ @ӝpz昧hRsQ[zJ#7M<?v1`]tsLg'dJ@\LB6N^8bi 8ނ&a*Aَc0$AC*F#HXC\>S0 Mo\Rva\63K+Kyg[Sf9 r5xjz4'PdڑFEBn G"C\ ߺMp7v^Fk/͎w!4R{KqF=YnIk]/4ȿ$Z+X / 4gIas|Ն-Xи#U<*M%bIAV5>[( f4+)Y`gk[E;x$\6;Nk_-c&|]ɨ[w敖.GpkItk8G؜+Lį ֺZ B _޵np2#zJʖ*n"|Ƥ6рzQPŇ4Z^"~jNP;UbYW9']>4?del֝llA#\v^3x3xvb2@Izx8`qf:#qnZc4zu84ĀHLsQ:҅N^T94]À(\UM2y'8), ɖSZCG3)fzPc#@k2@YJlXA4[$P,bBMD2_;vc֨A]"af r46p[Huof!U͚W¸=ihdg zU>‹=Mg^4L&_Ve";Tst&3Ur"s(Դ;ipsҸM/Jʶdש*gl4hcٸҀ֘_c53d T2*SQpe*8FR+"`RqMD<Ҵy%dvYI"8 !V9IWđo"35";. j[hNIҨǩh6PBw[ S+Bĸ%r*/@Z5ehm;ҴJzU0,#XlTk>jpبE UY^mq\u5b >rhK22HWxnJ҆8cy1RZ Q-t}kFO{O=o4 İso< nsL͢OyK׭)L( Zϖ!+Mۚs0H֛ԣ`q@{RxBPRΔ8皍rd?-KsҔ`r_>lT1҄ jr>n[Sp} <@xaq@\i\;n M?hٞL`gtV6yG Gj`ډH"Mz TzUȨ'‚IVs&c].ҩwV-׊9T4NM=)ґW!JOe%"Q^f.\#Qa9TrPmI*3>E+{) N 7n>2)aF(Oc0ӱM1sS׽֐\ " h䌃Hp@H1ZgSNґ# gQ$w4P9HcvfSsӊL1Pdmj n8 zgiѺ cn)70zQAb{O;k%[[px㩠)ne#Ar1cG^k"h6ڵep:&pҡnOK>dϷM>Oˎj!^#(*:uYɅ=*ubp<P6%hʱ=Tw7!"WE &ι 4d<Ճ hUeKxg҃: ۨ> 䊡t6a)fiZ0{;:#vIJl tFTjB9jhRo,8RQqM75K61Pyhʭ"|p)cQU=yji4 j[ `7Ua "C࿼׍ƤRebWbL?v2K'S_Z*$\rNn1Xki]籦222(2" 3LxնnHݚwi ;GBfb?:Y#[sH*9TF6ֆ;Č}갋n]ixb^h58ɪ5VD >?ZK2^kXDv t#;ZTSzwFa.#[xeM3I9)wD }* 2.WրPd쯍ݪ%xD& N:U) jFdI\_JPP:wD%>zΚYړ4r}IaMU%V,Y̛<9ȣi#;O|6PD_\ʼq<Ա2'E,krIl[L`i32֓**娙|8@$G[ncҀc*uQH7)،}*2?(Fgq@9Dww6)qH'9Xm4 0O a˞R[isLw:RX*rzYIM3ձ.exty1Mߗc rA5 6PtZq $m0O phsfՊHDb(ݓQ'tkMZH ܋-QA9la,@r>Y <eBNȸ$\3{3s](GҸۣnR{7J_5 3,h2Z؜wPEn9+#YY"yCcK%=jQ'iҦP gWtӖ(fAޔbyٝl;i#Y7hMiL@ޘA`Go"Dրh p:ҵ¢EL sSWg^>Ab6Hw1== m#^j;I.ݹ\RVCdu$Pn(r)!,cRC6QmÚ Շ\,O(lRHNsP4OGҸIKU"c1@Q 0M+ٖYf ʷj4jH9N#$S@ؖmjO+ Tv3g{)(r{~2.X2棑>@TQa2ܟ%A5n"WֳDV;zVٝD[ R TkCjN8ɥ2)إAJ9bqO^8IQ<搆N8Jo=J)5La1yǵ.8 x )F* 4]R/ݧ8ia18)|y<˜=z[EX8ǸcJVr92eDN A;u|jV 3 7W-t\j4Һ;LңiZj&_!kۭ /p\`dSH|LjޅdsJMy=)va Gqޝ3ҀRӸ80v)iG(8On*@m(lwUshMzQp *OZs*R9@TÌmqgf\qPiܧ֬S dҸșT!o¹OHU;WJ@#.Ѱ׭Ɛ.$r85k:.0$L2*&8gJ3!RAri>c֮ݠݑPUP z˟3"c ɰ`P+b6(-հ?<¨n;IVdPڴ7ғsQ[^33O `> w[QAz}iVm6݅Rf3Dh/̼w*fR[ppn*@BàI"_1i j'VByALǝ}܅wE g\-FҮ\/͋V:]vٝ69?{&:W1,`皓RPq;dnѢAgޓ7MB&,Mn$eVHJ2dAzUؠBGPSЅ#,c9ٛl̀*ʇRA\ eG&ͼ51^͐ ZˁkOJA :4X Zg=E˜g c6Bգcz-ڻ۲')Mn]=:(%kDOlםho@Y]L˂s+]Eͩ$M7 ͞G棈;Xh!ndߐݪfRN =*H_z{I@3\ı$č}-* LI|(H2uRv`\h I"bO XcPɐ՝sbw e_Pm/F9SIUvG׳p+*9ؐw3V57ISɩdFE2VXۿ#2pwvQ11iՎ~J R#@ Y^W LyG~kR4֋J c&l|]k8< ֫w<.&Z8m@P#) uR2.}j.>6:~\ dvB0کk:*n=Xji1ݭQ1ӚŌ4d"Ҋa~s wR)8"9\޴܀<963j)r)sTR6yTJ7DjI*ZI[lFj@_A7PA 3E \x7duchZ׭=0 1֤USt4N1֐Ss@ }6 ;Z\@Zy68gXWV}]DdJMSkӚMp 1'Α +@Xڍ1f8ıGTjRZcD(wNHz)f{`,V TCp:9C3eO%1H96q9`@ݧcXsKޘ qJ) @&9>zS$Fs t=)9O+)aQ`Rl!Ըؠb!UjE9$*ݝGN.AOtl=)q+8a'jRH}WE}ei XN 2 iHN-AH`}kG3YHݎ88SOIcu`2䱨k[FQ{+y#ʧiX֚!2)nė@j 3(V*,@Ƞ{cynIL`P.zRAu}ei .:MUՔu1~^CHdۢs]#&9.;^zփFf,Wpk6%UJ5jTg1iOm*OD/!;}3!^mplha-4{m8cF-N̮بG RiϥXR㚳u]*.w~Ԇ$sLqpe(_5bX#TUBND v@{NT5E6q 6MEMc{qfCq]wm)Yc_8tМb9X9AZXcv0ɣȻXUҢF&- cis{%M?}b7(]F+_MtQ#@AyZO/vF0j(hUosZ`Yv/?0[ 'Zغo-mݣHS<QwgҋhgLۓ?)^}8UsJfIY UQާ,FUHntGlԳhH#`KA_/2HӼHTDٗqD dh\?/Qۤ`nj[5[_"0=5%(T6=rHYӁc$4e4VKvZDy LFyO-Ċm:ղ2pi P~Zx a>q֦)gs#W*FٰA;d$ Š#AI' yp\,6I!Ee\S$I?)D$ƣ(Cϥ $ m>?+Uܩ$gV̕0cTqV.db:I[س&8Z۫fk1"we-;V5j-q6|ASzeH aj3lP9زIs{*1򩨤ۙsB%Tp3rb( ˖ZQrqYa߭jD7Tw5)1y<LetцvOCQl`Ůy2=Z+ lNTs!QWXe/1|qVm\֥U;|R# $JgzU8lɱt)#~0Md~SJrz$AXi<Q~6 p,,zd@U8M!nR1q9HF o^7ӻ1HF 6OJN:w'%(RܓL+E+mi\H7t8 8fʑO#~^i|P"(\)"`U0KA LDpjS$IUr(tfTЀ7}jHJw0Vo!v Dv`R: OȪϖmf'< UV>PE2#eH-GSV.>:Ҝ+9ʷFs#A2 O# :q8RYcޣ}ɖ Ōp8SYm i2hI#֑c_,ڕ`cދ܆H;J rj=ݸTy9䑖@bMHvMD_i8h~Buz sªH"Z_]A7Q#IlorrEdo:;QYR00 jֳ9ֳ"tF qJ]Ja16#8MYL>aLDyexGzS\ w(SJg1IVEOTP+2*9ܩ#r:P+ mScb59t#>+$dLԻ)R~i'8 v& %AH&dc#3ndu.>J"HPH)$t.ZnNIL#`PxXJW$⤏,+HnD.5/9jQlfaHt19R}izYxW#֤}#<9"1z2kk@y]N$B #ZsgJ{VeF^W]^Kg8,ɬ93AABjJf6=kvSg*Ǖn9#8!ȶ!+ڑvWf#9Hw}ɵ֥jsF!ڌEnT`\OJ\ۖ۸cP@bī)V*PbnN6;tbNW?t'=i"nɰ򞆬[/jrq֐c9$Umn*Pۇ҂lAmsUٜΤch<lj|UZc(ݎ 0OJS$ƶJsI|9T/e.+R8>sS2V*y$Z9I rE"H-`y\K>a>kͩ',$2oZж IxsH-EGۂ=*Ed",H3ڥ|Np=(SD,jZ0Qvrb:/jv!flzDkP^LtcZ3D֟+ BE;ܩ T3C $+X0FN:G;;0$HTr+V)p{fm|؜*''>wÌ 8&r/϶GoZ ˴ a+x$WonDW'4cMΛ\ c4h>\TiED֕&xѾiڬnT9Tif p)lZ9sZ7v_>xː{滋YCە qT5kQj̢giw8yDد O6^lNT9 R 163LVrUXhȲwѣ>[y-)U$ l)TEo S-EptXeHyeWR z\{3gH۩#n&Z준I?f[ȓ+;W`iLWұ#-y~MUmp+B8ZH>`X z\ `9zr3VnԌmҺxv{hv:ڹt)V {VVFz35_:8M֜%L9|BzZrTk ;.@_06OLU;w>z t "dAiJʬK)gDK+S qIIb83)̒n'pr )֋RޝjD\Baǽcjn#֟׭~S<QӑII1Pnsr*BwHFӽ- sb9w3 LGTyef3qT6.)K)PO`cd*Bގlv4֐"OSR=i( b')8qIؠB9 Pҏz3ǯ!y )1Zn2N*3n3:SKcIX쀹3QU:$L \x s]ˑ|VMX֝eLa+NfEl0ikXnWޚsfjzih@f&*M]2ۡRv_ZG$1N;3@Sk5]I75gў5HJ^pzUwas\,TTrqLlp3Z4h)rW5$䷥:ha\TL92zw ry9XR9qUF9vɦ }vZy7I{fդAOB+!™yW^jzyUvW4'I|o[Տ{+;Ɍ wC7 XG ch34XPhQ`Ȼ&_$ \v_n퍲Fc$ J-ʞ55 1r]bz枨ƭ)KC.t?PLM rfs}wd թI?Mեg+:wF X|'ƂI"-Q\ ~9 %ev$|1"M$^ԮtAJjjs#)#)U'>h< m [J?EktHcrL9B^iXNhQҭDdžBA]|{`suuok `UlVptJ}2=jn]:HcjO,S!b1jXn\2#ɀs>v ^̲+M ×fI .Hqo>%rYpbQߝJ֮1=ؕd&5+Kp2y @ZݹiRA:M:ĨҠP{}.W֞wzu2JJ$X- q Ұ$<&9/_U̝Glu{UYcp´W-cpBkA[' # "JT}Né=DnS(E221r=jM6c`X˛9@IY p>E؋2ý+V>zy$ktH皅cU\˰GZV&N*I'905Zݣr{c94Uxl@ghqZnJE; 28PRwF"#F2q*{lSWPPH:M!~UaSbi k&21ELc<~P9SŒ qR=zPCЪ`ڠD8aPHќW~632QzsҫhK銭wt6ޓ4BghXٮ=ĊT JbLyy])!T} cpexYΦIv"xSm{JB>ӑU.-TF5*Hͷ&LJ^-8ⲝKqzWWsn%B52 8G)f ې2sҮ鬪[zZW6FnkI!LrDB#ՙU' FB*1Ysv(RN3Vfb^} əhٙSڻ׳%w隈m(lm#"@c9\ܱ$1e3Т)B(s1#rCd8=a"Wb<̻&Q+GI܀KSAYrۘfH侶ڄn8CD* ZS*V-DL2EtEhq~yky , /*OJ=Av$^:W>||mIΛr#O§`X+H%.l5gQ,k Žzn '=#dSG*[ZI>+N)F>ֳHUUqO,ہlΛp#V4S}ǽ^[&w1pe4piNCvUpS"6ӂu4цb8'H /Jŗo'2HLzPp/TۉDHP04)NsG ,FqiьevQ ,sb6 nqMe@A9j`Frk2ý ;l=GzGFz!`b9L$`Wvr} %vo&PH@!8JUwE(\⁥U`TisTmI%UWs~ZF&r3"l`I9zyh~yI#ޝMc*sk ;6Bxҷ,kO]VD(i5J cbF5t*3MqhcQCŽpsAN:]p-Fxt5v7$MensT!BRiYGJvlfbͷƜy4@ f]`iUs=U@i΁Ar%?JcFKgiTFNi/&ȤSDE7ze5mʿ8h)k-Pg,=kK%xZ4&N֭ۀ{RlQF&[-W4ˋt9ޘƤlt}I15'N:R"iö:yl!vG;3/J蔑qV"D- >OgEFV 'ؚ些Z_[*kt{Bv5Oᛘ;#蚄]p}le8)jw페pKʃ]i,#UA\]F&/@MbxU\M֡& '-^7"*˜r))" \WU$d]Z{2KI#R4ם\95pfu /[9ŵ*O$Ϧ5$goOݤ%JSf&4_8$\ֹp58t4BD{xP;ךVye3]rG5|7%6!OJ8S5etؠkX I=+ZQrV*, &#y/#q^[bytkǥQ7z|+\V Ti:Jг%N.:ҞѬ5Y$ҥ~Rq\sٝAsp< iwzmў8[*s@XV$1ғh3Q4\.aԙHǽ)$jBkR; 1SN$})omDքQcZv9J  &K5q%`W ؃ϥ1p`䞵DQA"ɍvmgTR;w3HBhpqH.qSlÚ_Ƞ5psҔ1e;J#lˆBJI=)7M暄CA%Lx+ R2@pMF6]O>fI@\9BsJpcҜs*( .^sޔ sq' "ZijCB@g t?HI4IqB8hhFFxvPLP4O#*)qW)K֧ws!a-0<)Y8(''HZYp4FdvBZҊ48ܧRDT{XXBU!Nb,Y}qO3ߵ9Fp)ï1TNL”iMLz &(*zx&&7?=) 084$m>ƘshI&ILʮ=@)r)#(zSM 3ҝsJx:S@ H=i@\98c9=)8qzrusz @?8v19@ 8K(RE&6qPV22MU^G5yP'$qM2)?L 1cvfiH|zU\c*LN)N ޥ +a;dSϭ $.VF~pxNh<4)sғǗ*6qTTm:b4UPkepwpjM0v=GJc" Z.|4A34S4,=2Mfy]Y6 {VW!ŲN"WvJrTqVf= !h[F@4.;P";U@s^:Cd_+̾"žf_)5x#f8&|[Zd1sx8\ddWU)" (;E6xZ.FmĦB#lkɪ1ǹC&$*tEis aMdy49r;ldB![+xU,T'O Vu|݄ 0 g#}D_0ոnbD' Dg`J9w [B[D*51=C) T"˲!"io`PL|1pGߩ3Nj:eލv$mv"B]AAMz֫ej"^_io&7ϕЕfm9DiQ[^C*͚XZ\ӔEܨsڝ;9Qd )Bh`|[F)GCTLrnMheU()"xcEWo4#L8eUCL_ZHKb|14IiȮ6>=j a.X1oh$I{j0@c}1.-bZ<\ T"}r[,5 Ku]b&;TҹVt+f/彩S7}+J{Pp *؈$BqFR:KM=u 0}r )U8־*T2RJ0K&*rT~ۂi/۽+av՛dlTOK']qV"L N2| 눖`oE? y-Ź` ȭ2x[\cW+w2&1SR':u&jV2QT*dD]sSI1LJ+c`}W[1i:ZRn ;Zl"SYT78PxjŽr+F?wޜ ʪh*ɖ:\/i,_8t=ꅫ~H)`&hV* 2Ê*JB4 w9BlvP8]z Գ\wcjdL˄Sp|>NM#+#1cmwcJU,A93#EN&H11ךc ᶞ*>`t_f^bfeDq,3 tId[6F*\,SʘkP/ lJ–2;UWB=+Z+:d H@RV *l\GM=̑}Ҫͨyrlޔ-}QyNv{7s)(uYGRkKԠ3ȮNǵF*EX]htJLg,_5885Ex3uq4mU 20@Oڤ#Ҕ(Ɓ#.F1LvMxp /zzRMLb-Me!r}k`&A3Apn662ےp+v;VHH~7ScM#d'jw+%V'J'Sj0fctT "C1Ot.nJО@Д$p*}:ЭǞÝ*.Z (X9ڟP#'֞>E;j [ԮP tAjTqźmMӹO&Ā1V#$.ÃI0Q}֭Q #VdGֶd\9Y0vv$cJИ$/v5E_ ?k:Ẏe Josp \Kcf5=7ωE^3ڹ?[jf~BPV\#zq'̾o['֭r{9ޣjəg ]\W1ʀ{4PYVúa֧vơTzS1$sH}1Uc6ܩtN֬!#ع-d &i#UɬY` rXLi| Yyy8L.&BቦM!2=qC !@C5)o&~UL}Bنѐ+$eZvP[v:`=TB4=jj;@!x:q(p+0My,C nzbGyg횓(pDc8i(p U|*85m-0@jVPGD "&j-TSBȦZ.C/M2jc$ Jзr0O4C5&rsڠFg $}jĘRVJS@9`)ѓ9~ݥAhi<`S2 ORRsҗ984dph&yڣ*3HLy1J0x)@h o !4d~\ϵ"ZF>}nBUrqC[$h`iFzV5GX--L{c}}H74%1UM>ħo{ #&LAրNqIqFHz@͢Й.JqPC'0H[eJ9 i\9]kr%TV-m:U5Zv)ղ3=)̲ʁU[29p2%Arrib" >"<Þ&=҇FV܍UA!V,7cm<:n$搲XtdR `p (E$Q&PWF yc1Sؖ|Z[IFv9ˎ&bQFCݾp I n;йJЅZXRVDmb ѷs҄ȜXULF1{Ի(aȣ0 m0OZڸPv+)NQLB3 }\Y5deRA ^tV?V*g܍-{Omjđ¼զy ,rsצQM߆r_[ c<29HKH[)c֗v8 'ON))"4dÌf9#փjF%i S\K&0 S:BM;1 8FMq2`޴aS jc6:P$߹:Ui&֢$A#!ңKo7vUE):P[$+jiG9/s+1zrS79q=iT>|@٦+ ,rkF@oZ΃0#T߽c8 ֨N,k{.N9=*lyRQEGs,aPI1YjW$!NI0~Q؃n=lvbێsY*rPcݝ/,B>goBD5^L-տalֻ1\gd,lYwQPuL5!R[k ެڨWlna2GX(@(8Z2q#6 ;Ғ3iT|iLdwG[vcqi"Y[VE8S3#ct1dR3Ed[%#js;+@m?ZM;jKRHS/.ݤ+A6faG }J үR$52ah5HWDno&}YGAV-ayϥFY:1L.U7$t , . dpFl$hCc6-ݦ`j6wYZb>#SK -TRVŎ $`  Ky&U4F\8sҎvV cekH2krQs/8xVhPPv5"\u*ܫ@*$%€bcrw(:V'U̦HXَ$,'5YX 1R ;F,92:Y10 3 :j zx+ȥ;[m>/ێ®YV3$]<FkBf"YJLF`GZk'"斦ea&9g̹V^h-eN8똷jj#aVFfswF(0܅Հ w,ǜw`ؔ!"lדR 3҄)pԱtuUQ;m0zN1)ݜaȼkMXJgDRFΪFFvuަD@ힵdJzQ0瑞+&ܮnƿ7P@]&r$1 +tZ2b5+-:oQTv1eϽJ9ɪђTt^v8$$>Hx4E#n9@>1.1ɨ::r;W`H$rr:u8]*gȦ 6+HsEH9ₐ8=8ni9ZQM .RrX€9&dOh9'5OX${S\ ՕSLd;\.{O !G5p48D^ɕXduΛ%@]|N MM2@O)zՋa2zN׈aW!SUcә-2T* $c]W JC  "Sh[gxsmplIdHX(4S2L`+JWTʿbeg R(Rk"|m\`IfUa\x9LyܙFHw`Y C6Gr(yNpjQzXbqY~_zhR`eRYJāU*i!L!ԮĪp:ݾF]ߧNZh#^xQaۭYKd/Z +ơR4x\`QpqH 40#sY1Mڵ\,qxg ޵=.FU=;b"шn-&DR&% r9<Z  Q%gTjʆlem ׅAIHkwUui[90,r?:ll;y9׽DX^wνM,jcz&"!A?Iy F&aR)Crs I4bN:Rl9"\**aC@;x9Mg}i 4dLB6ǽFl'4S gCCHXiqOց# j&7< BNA$@?yzfc O =`SӂqA8S%R '>eTz wJo,)Sgm1M('^sM'Jp@LFqU 9bYaR"{ <0n!&<ϱp>$);RBB^H WU@M 8ʋ-ܯ_Z*YprVC䌷;+Mb|3W@ ^dH$ʰм ֱPWFqȸu9<wC.{/jgM62Iigiڅ̒\1ZÂGEbfV\\:KAD{U;׵M-3)u" x>[;1ވ]Mns֝eAdwlt&5c@nx\~p"1ʹEJ mꚺj 6Xem@sֲ啌]o"iN둎*g%YF{OLܢe_JUV]przW82K1B(&D~U)R*;d:,01>gkz{V#<{aa䏗Ґ##̧ܨ,Mȁ%sGZp$}i$q@W07$R!w)uBښ#cݨ ;K@bXc͖eҐö152ĻN*)f[}vB R^F#'ya+t35%3:W+DxƲ*V!f!5VBGuV^12?JwhҾqJA"a%H( zWNnG M4C$XB˂NLTL9vd gO)8"6#FFzwԒǭ@d(ŷ LZƷn^jZ@o\w^aiv0XFFh:о$ Tp=j aQ9 ~4у7y$dq}#7xU;Ӹ^dw8 sdpդ<31Jp@=MpjWQ `8@|Zܐ7-Ҁs12DR@A>(cJ0F3zԈ0) b1G( $#)5'4ɠ@n p@"1RqHCd %Bjv"BDG=5-蜃v<0[xsM8␜RB= L5=Ib(A:KbsA֝@3‼ri@\y3~IR8dub 4({dq@zPxR){SMq fpri=&4cE4 ,3I9F0{w1wȨؒ8O8QW$1sMPM2ɜ}j7pzP2@0R3 ֩*HiC/jjzO53W~JJt>$$V,`2Rrn:ń@$ݪeglP}M,J8cR2(#aǥؘ긫e*/beNG&ʨ|hh:T!ƫ$x.H j1)fM,r~eK)|ݬ@=}j < o%DBrCz_9z$m[Q`>f#$:2.'vǵ[ }*53hg%wso 8K*bM3syƖ` 2`IN0+6N:يw⤐jUMHY^+sęc$;S 3vzu!. 4 0FrXO cTՏ4DD14qRPSr(%T4#F+(P䚉uz 2[4ߗhȦR9.jԂI=Enj1[y+F u}))"ԲnU?ک `%AQ2odn:lV@q+6h+ `*-n\ҹ'HJvҲϴz iSa9L͑)1ߴ A+K,qxf%#;XsIvg'Ե64V/2^cɦ˓-oqĔ#QpiE.6^򎪠Ƙ=d16R%q΄zSbVOLP,[a5$ ?\.fJ1 {(~yѰ#!B84] ̧-t's0ޥN{֯@3ޱbIn#*OمOǪ F#N;W6ޢ#Wdt++HtI8N陰U=+[\ַlb7W1+W=DQ9w k^ϽJ`cM<i &f\-@4\ZS}:Y~n {Ch LS1*2Z":Ԁn'"$ls)''BR @:c9n@@&902j0[iZj&&5l`HvC+}jPOU]ꭜ n5<洣]9!*8晔Pֵb"5s4̚Rw-'XLɿ0(.dՒ9S=!֭͑GyHa"e! M-a TLʠI+CvƠd欀$f2MbI *u ҅dc^3#*xM`֑IB/=4 *ӕG~M2)iN7S 4?$sB=M1$){Pn:Rg&J/C׭4rڐhv= ;? bCg qڑW{ yܤ1ԊDalsRM$)&۞1Q‘ړ.xB`94dg( r$RwsU6pZ8(-HhѱڭL42zR$HImܺw46m?& E4&J0LsmfJʻV)$][籪wlcUʏN(YΫIв[HcpF:Fvg,ѭ(9UCK3k3+?bI;ҵJ1lpk6R6:=W2޴ؤK}xMb@bw'8ɬ<=Ei͠Ip;֦(UA{T3;Vn9SK E1 *H=HnҸ9\JDjE$*r;_5cI$Xu5 u O4y_jKsVC3@9Jr/c\,Tq$f_r][-=8F4Ј! jWecH"fC*eeWuaP}i=Ma.XzT[dI *ͬo;|·LX#brAJ1b9arqR Oz2eIՑ%ðEI R]G$A%yܧ9LXᵏd:jab`qu8jL%GT3DPw+ \dfw*8lsUtSys#!$b*65]鑿weneIE"w :%W f+#=ku2+]efgV7W:.psN8c7qx$NC0='o&xn> )ؠL8R u5Ng%3!25@&` uj8] W&+[و\TɭTGb5zSS#.A0:YpS'$>0Wo&L)N֒K)cX7z"sO=aRv66.Kp70YHa$ey fbҦs9+Xs\ͶmVɧY8rǦ0ib цԫ,PTR#$TؼJmd~ V{I5eOj޴`C#M]'qME阐Rkh#*܃! 0=b/5iXN$sUd\2q[0qfFi֙[ E&`\ ҎZw#8Za< ^@SǹM 4yGz\ўhTdcLpi01@#$T} 4+8M*dqV T,P2mROz@;$砦(ȁ8bi =)]vF)B(\t ^{HN))E8& P3P!ȼUUb{Ԡ !HHˀ9x"zR.W*F/0Jd vFb ZG⨨^zLqS[vfcVQ 2*lV+?8ԎH#X]&G\% eRN"Rhf+;9j"y(a [ƪ880ǸԮvU@ /sZyVA~^  [OGb9@mK 70Jg*VS4rcJTwe=sO`-*<(H-ɥA 7 dbqIgdҀqOTyX0a`~9RH€&7sNeJFh1 .yjD^"Q Hw+jg>k>I G0z܏ UFN9k ރMRf*ˌzv(15ƷRHϕҵB+C$=*۴ŔHݣc*ѳ*3nI,`1$_ɽtO~Ց-JZxq]"$o}#Atc9O!09^˩TZ٣f"1Kcd*}i.$WeF*`UPoQΡp=j';d#r2ΫhIFRKlҌdګjk?vev+.] Qrr}3ڬ/UVB 'yXw.kѴ_"6dW3 ܴq]q*#;o].9D.zT )ABVv2AS$ \fr#zqڋUAS~anw^E;AzR)1QB>S֣Qyc=HҐ/P1v V79PHy4=qHFB;0#BQ݃GqS4AT0uF~y9aw#qwG 2Es^+4 \#aMZ8h֗^6ENvK8wݒڲ/4rW+ٜhv qOL!RZQx]TٰrVIa; ӱU _z2ϙ_Z߆q j,Dc٦J?qv5CdO4FϽhUkFtoʪ-!FڵG{4%Y̚$9EasɻP9<|c{4_ec2RyRĜvlNJ;S`EZ0UZZ1R>OJĹpSPѴ'jdAe5D; HOn.~o^*nlh5ĶoU-֭]ak Sq<ɠ25&jwKLl:g&Y>=낲յgȄE+Vѩsq+))"dd@ )ܜ`և+Mn }yQGjzqhu Ӿj48u  ht+CJLqҍJktɤ\Wmˊ;HYJpjbNҁ C nZ!xc҂@n~nQ5| eN؉@(`"7g'44i .2p:R'nRAcIsL# 48m4`f M֛[4z#4 ɚUR ❞1  8@ ۸1K 'x)ؚiLJC 9⁏nxr7J@+L2`/4UJYElSvy0$fCb.zTDNv-ґ`n8ܩ_Oj7|LQU56WQ<֘x}NN*|nV|srOfA4HTФu_q:҄|aO^*mU$ zqdc5b˝rB|d I'ASsj r:'A'B*5a+gH!g9)26c#@&ңc< &1lvC'syn)+OTŹ˕ިrͽ {B3޹PDĒq^$oAY*R/2Gop/R qvpGjiӝTn;U@]X~; 2BIm{71n1H*2ZqJ B;u0.F/p^=ʯ['ҙc%~cޚ zPa3LH@g:*4qn󷀕_وopxc]+ Bp>n2WFefbı"砫,UeY)1Nig ">;K9n'(Y +< 0$Ԓ$K뚆k4 g,,nW=_dWێ֋0ZB@"=c.jG]F}&,2ƣhZoBtٵ"*B\z<<'_sjwS.GH-<Y08$uCcTI\mq;l$M,,MO#f.`oI+,ps;dQҘԡu5_@ VHс8zP)$(jf{kt-ʁ(U9oZO) V/9p˙<xtWw35#ۅ#yXM۴;T$݂tГljMY̫)$j|V3;T Kv1 \FuHar s>1*#>Q=#l.la.1k-i5`d F=r&%IَdsҬjpjr^*aZɈQXӊ\ {ҌAis!s@➥@t9RM4=*C=i@"cRRj@9 PCJFNE27`n8(@`ݧCS/ G@,"#gTrZ DJG'g'%CcP+rieiy#>NOJ8("YpOC?7)$mx] ]\p*øU[9T)} E1FÚpe f3N먭ۉ3RƆxvA-kզ}e$q^JG$kKz yLx֥nsb"ddiѩ$SC) v8LHx)yAsf,l8.b| WY3Wp/Z{$|1ުGM`1QcOJCHl0wTw(j 4`:"44 zQrұQeZ݂VL80E!cQC9D1ޠ$iϐgI]/SX"aʄڷmf Ed\¾iSZr)!mҲȌ7*"u^A5RX|S4&,nj! x=)D-{qDrIWުY&}ޓ5E'%;)ck 砮7JH+뵹"fU b BpzRzOVR̉N Ҁ- p:RiGL@?jI4FU@sUOJ4+JҕOzqH 0NJc!:Zا@8ɥ)wabd b~MҰBA vf0Jy ue Q5v1BQMtk@LR-):֟+)IP9(`$IJԳ5ܨZE99+R"Rh`˓iҔ.( @ȁ/*EF (bo%ގq8gKʉ>kڼjs޼oj{+ir#iT;t=h@\j'r vM^]Ԛwf8;I4ث$x8QUvPv[ +j2ITiif؇!8\XG暍uZFR{A(^1J"FlN(َ)J2F9-;⋌fic=jZp"ɤMMh G4rNsP;H\iaw;V-{o#<#88Ñ!Έb%P\0##O(e벾ږUh \.mwycz{5W-W%\Ed8lS¯ʹ&Po,dƂB#MɖFFU@Zr+zI)ЌYhW\=01^Ca_i\+c?5[ާ@CEVV\})pJrheJG4SYڶr2wU[CVr2Jieʩ9jO"I`[ѕRf]lӹ̬giP5"z-Y1_¤1.w=1sl%Z'4lUێ9̛ MtPrF8%[i5d{bdVPR , |˖å,)$qH8\I뚍²(Eڂ{ R`0((qš{*) `ӣ2dPClc5ܜӌ! 6HhºF(6fR3ZrG.LSc5c&iw xȫq݌lo~ZwmX*={RbIk0Ufܗ,dlU#qˍ4zdIVE{O-1s .;F6أF/"kd̄HXl &%?`vCՓovȺI #ޝr7OZ2dvLJ@LT@-! :D1uO:0 FYXB3 );Z$fsPj Ѱ҂e++M{:-eN^H9eWKg# g<2I@o!09#inQޜe+1qҔұ[i#֡MS^I2y<rn5!wn+5~$;FAP +6zn@+I:ֺG<۵mL78ĐӜƽVHqnYWq|2'bfL$*0j` 80ߝH֐=S6H 8j`9HH ֤᳚R6g94 Fz@NqK4RzJT*P9iJp1@˷f0Nzd]&Tl2P qJn7F?)HqF=:R?ԛn&D% #m HޙnNI,: .4<oҦ dvaRŠ,FbP3@|0扏_Jԧ>N)թr9CrItc,liBCg4t>BnY+2 AVFP;Sq1bl<.ޜQ8ԭ,FLHr{ӤQ<탎#v1UHH{+aDB (5F)n `sVn @HPe'vV=gxzU R$ ޞ椑ƔOP0y)\Sۭ #'"svS8(BsJ8%7 KE5(&i )v1P zR8 wϘ4ĠRN*+Z¶{3S(qA!zf854P22'⤁K!lsQɐ8GSK).r@yp34aȧdc95 F)d# $r3GuP[nBAG gB+y1lUmF%W#$PO(GID"ۈvX?iB]"Q1Ad@$v*fl4J;\?PvuEQְ)7l ֛]@x@ Mƭ"6q7qkt!w([tEe(v%QQehN2 :I_vry6Gc HM"]/5<$2{կ(hï7b~[\Qr2Q.ZVD%G+2rI}uW .` mTu_:]J[ʑt&@/ B%$U7qJ!v5D96iA#Jҳ[6 $*Q$f/67( ̅.*:H{Se؀sVboݰj6TMzXӘ˒}{ =jбoWWUP "}n񊰻 5NjD6NS@Q[6%垳fBaSd9LœȠ8sD+0Ҵx6˰cVEڠ$ei>>[ǭkc$8х4rSP#S։#1Ҙqs#zEv>\Hυ]$JE]`]HIsPRr5EU.łɧ,,`*i)֕ݎNqPhg\c#G%/2TH*K@qKחBm!|n-=kB5hOdV1Ҩ?9(=0)|O "(\QpԝXʕl/E 'hjc$f2LNҗKOIyW<{U.v@w){Йr 6i3=k.+Qie7bKћW5APz /ĜpkHBY1W}YᒌntW9c ?u݅k[j>t9 10k^XI^']#UW.~Qֵ"ek-M]QHT$»[΂:0IcR]q]%l*M26B+MC\]7ϥd޳yeˑԃa}N+Y;Gt6>+[7I4R(N3֑DI'FN {J@?0(7 b˸U$N}A ڬ`u3 jI"\'<)MܴQE5QUiB|铁5r}i,IwӴ/sMf@ex ǰ9<0' +FHj"ŵ2H-v AK6M:8J.'ЗwԮ)+Q 8Bs՘-H_ZRF.v*)2>)3>}űQ\+ygT5E^8T H+J?@=j\D N.AiUy4s $N1r8F_jOJC>H2 ({*5cA98hfup$p :q\Hi9sޥ[ܥKr:GCi"'+mUi~R΀JjߣLYHժۆ(' .EIȫL\t⁌Ti LӅ=)Z<@,f.vbxVly")\u* 0~1Q"8>aԊUQPc=*AzTLB^Ns"S=j'- *`Wf@#ޢq少2z4L'jX%+L 1뚊X0eZ~ThRդp>d|z 76Vc>^@-EtѼ*q, rX1?jXErQ(2tѲCzU% ֧K8ظ #4՘q1TS$,BVa6dV=Z{\mcWa2Cc&#qXO7Xn4EnqeqT2B!d]@u\+uPŎh7[ uVwBWt?Ucix5io5iQZ7j KD(Qj{⬫dӰAI.sߊsCc'@J20E8~% <(Tq?k(ܣY'O@f;H0=HǜR9ȤV4O=)wd8Kt401@@QHSI\5;p)0H"FO[M9psp8@ $PX`v82n; [sI(ҮCqު8RF^L^V/wq"(bjQ5cۆ=*X8j^ S8OL%恠~x=;T2'o8SN 8qm,T)\m4]z; -[L/YrI0 +^oE#@N*'ʮgVkrxd;sR;lU"G'qRHwFzqS؞Ge1+ڼ%<:.>qdS]ui49 x5;hE wam*h늍&pn+pQ9SV {T>eunԁ*%$bG N9BO,_;(>si4\V:g;<`TJ$S֝a OjnB#.Jwz`r@i\,8֗9]zw?E@F9M-w—w~ƕ`ʓHQ@;B8qk}0kҵ ?|Se<:‘&LJfЭ(ylc)ʰZV< kwHΝu()*]B)(ZG#/#HR<T^`N kBJUg#;fO!pGJ)}h[j^ B0\`#R3.G؊P&zRd#b)IS@Cb f$0(/#`@ZNs@aK-@63G9#4yg"=黈,pi;zT"3@7@8J#5Ҙq JnpXӎ8)b~ Ȩs>0Q銆YJpPu5+aȉ< (@ Q^0øpTTjWt:=EJu)Uno0\J:( 5'*ˌ"Tӥ' U$rryN0:[~s֤Ul`sR[GER֬c ;)jPHiLt4u^4G4 1HON/0sPbzRtL}J5 !e,c H5$rb)p$:S@liKf.) 9$RrsҍcNJAq@ 0i9@ &}@NqM4B҃ȠmJiA ԭښp:"Ul(`&yȦ%FHA C8W OHF T9晆/e&A#BGɸ:T1Bb>H4dg RSCqL'wjLd҃)Lm 03O8 P&.s) i6x#.S@IRN)<rH89:CS h=p)Ǖ7$ C֜Ǡ1@, iSsNPŸFb{bf`h7C7jI*3HV;ޚ(A dsցqJ TwOɲ9cI!R͒дȩ[#mlaNG!qHG˚SR2FzЯ# Hqސ7cd 9N5y !E0/H4#&4s?~ʌK8TA4޴ċl7IZnuL@O͎j5rĊsnpp"q)9H#E"#x:Tu6=p) NGJӨdFM1Ai\A aR k<|ё؃Uswй떓ND7mY dF*)oҹ7Ж{T^[!$C}ELVca%zU"( w5M*ȧt{W[`ثl Dل!ME{Tm(a:SabŎ\QЙB,sA0  ((bFMck:ser"4FW cֺ˝qXzj rOQQ67 Vv8N)$(b~NVv-8 MFѤ=^X>]'aJT}V9a2 <ֿN u32ұJf ,`mOr0߰jr+P}rGP$LҼijw }gvKFu=xy!7rBf\3H̓I$S9irFqL7&'(!EB35j5F%2s4+2]TvGN7w:;O@&m@YoabM]a5ʎyFHؒFGFf%WBA U,'xsFn cNe>Ԯ _Ԍfu ioR}w"H[hy2JNi[bIP+JJdp<;;b1l-" :\ך]ܛL95߽B5J6915/'z" ^hl+n d4Wol[(+k Sj7eK$Tf95u0>oV1Tv؞ HAM=N)Kn"󶹭6ɉbG ,0lg3X8"8Nw}`2 i>\ȩyK/58`2MARM4c!2P U?=jw'yEC$4D$C~ e{*PK#+FH`^oRFHTjҟ;5Z%ަX8@7r:fm 4)1-OEW`s@L)ǭD+\iasL+4Fi[PnR%u88#^y#]JL3| j7M+Ob6{XSd }jYW}KIbFc5͛{f9`y6SٮXhIo#)QVv`ĩQʡ >yIt&F&ROVH U dcH֞@U!QM.1A$|]'=͸B_79jngBv:TecZӴA rzj8JϕyA+M֙ Fby zdFÂe;pǂ=koL]b#dn9><֑WdNVFaNZB ϥBqڶN@YdcҝpHvADgo_t5 pVYA+]-u?26OҶU/1lk4?Ra?:F\M])qFzR) FDȤO`H4D$d P {Re_&Ry5+T{N7|qInR*!&\mXܱH3Lsr\+!8kܠud˭܇ݔc*MJS%/ViA5d$?krD@^\I9Z8@Uz!u7ݦ$I=y#-R$cp:&覻! .IjHj<ASH|@sIԪW3"J8 3zA)b{SOΞr=*6`"x>Y@ÓR!R,(;4Q(J1¤P FB h$z4áiT)ԬIojaztR9# v8 }iG#4u 9HG8h.p8QSBzzmbQH0˒0F)ǹi&=VҘ9a9|wS؎3M9 P17c'*e$bMz p 1pGZvt4\#c4m$u#֘Gn=R8v8̼b nJq(!'jq߅3i9*)sS&ܹ1ґQܯxY,]8WhZbY: )6!UuN34HF qPn ԎipA$Ai SZJz/oZt"\ւC$hQ0iӊKV.Y\IXWPKt6?)9泮$CմM:,R(n+C 48?v\iLtBH\+Fʥ{qRɠL~bk<n*a^rRHzX.r籜o b Ӏ9" PJRxA"ɥ\?L?/JQ9@Ǯy84mڽri-8(Ð2M&xf-gPD60i =nyi-c99_1$1iV^a%U ,frsRRU5fJ $lUPh Ԕ\K 69SRIR,:f9+2z ͈FWR|GcUdtv&IH. * * Authors: Zhenyu Wang * */ #ifndef WIDGET_H #define WIDGET_H #include class Widget : public QWidget { Q_OBJECT public: Widget(QWidget *parent = nullptr); ~Widget(); }; #endif // WIDGET_H libkysdk-applications/kysdk-qtwidgets/test/testloopplaypage/3.jpg0000664000175000017500000077220315104543305024370 0ustar fengfengJFIF XICC_PROFILE HLinomntrRGB XYZ  1acspMSFTIEC sRGB-HP cprtP3desclwtptbkptrXYZgXYZ,bXYZ@dmndTpdmddvuedLview$lumimeas $tech0 rTRC< gTRC< bTRC< textCopyright (c) 1998 Hewlett-Packard CompanydescsRGB IEC61966-2.1sRGB IEC61966-2.1XYZ QXYZ XYZ o8XYZ bXYZ $descIEC http://www.iec.chIEC http://www.iec.chdesc.IEC 61966-2.1 Default RGB colour space - sRGB.IEC 61966-2.1 Default RGB colour space - sRGBdesc,Reference Viewing Condition in IEC61966-2.1,Reference Viewing Condition in IEC61966-2.1view_. \XYZ L VPWmeassig CRT curv #(-27;@EJOTY^chmrw| %+28>ELRY`gnu| &/8AKT]gqz !-8COZfr~ -;HUcq~ +:IXgw'7HYj{+=Oat 2FZn  % : O d y  ' = T j " 9 Q i  * C \ u & @ Z t .Id %A^z &Ca~1Om&Ed#Cc'Ij4Vx&IlAe@e Ek*Qw;c*R{Gp@j>i  A l !!H!u!!!"'"U"""# #8#f###$$M$|$$% %8%h%%%&'&W&&&''I'z''( (?(q(())8)k))**5*h**++6+i++,,9,n,,- -A-v--..L.../$/Z///050l0011J1112*2c223 3F3334+4e4455M555676r667$7`7788P8899B999:6:t::;-;k;;<' >`>>?!?a??@#@d@@A)AjAAB0BrBBC:C}CDDGDDEEUEEF"FgFFG5G{GHHKHHIIcIIJ7J}JK KSKKL*LrLMMJMMN%NnNOOIOOP'PqPQQPQQR1R|RSS_SSTBTTU(UuUVV\VVWDWWX/X}XYYiYZZVZZ[E[[\5\\]']x]^^l^__a_``W``aOaabIbbcCccd@dde=eef=ffg=ggh?hhiCiijHjjkOkklWlmm`mnnknooxop+ppq:qqrKrss]sttptu(uuv>vvwVwxxnxy*yyzFz{{c{|!||}A}~~b~#G k͂0WGrׇ;iΉ3dʋ0cʍ1fΏ6n֑?zM _ɖ4 uL$h՛BdҞ@iءG&vVǥ8nRĩ7u\ЭD-u`ֲK³8%yhYѹJº;.! zpg_XQKFAǿ=ȼ:ɹ8ʷ6˶5̵5͵6ζ7ϸ9к<Ѿ?DINU\dlvۀ܊ݖޢ)߯6DScs 2F[p(@Xr4Pm8Ww)KmC    $.' ",#(7),01444'9=82<.342C  2!!22222222222222222222222222222222222222222222222222+@" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?SHCJO+(s*#0\$)q*[dYs#'Lt%d%Q\;O¢;Ƒ܊8ෞxy!#K3wME~  IiO^E@:(^g lH1tl ?\y[nV ё@siH# Lz 1ҝIE'E(IUEcQOGIb4~OOaGHqxP`@ d)nX  :w E$'bn9֡'$sހG>s)(Bu'qqh 6T9ӥ a`K ϛR: U<NoZk\֪Nm}9ϭ'րF)IP*X@-X}EH aO ]dlc?Zo4sZ Q Ms*6 D O{gyIXbc@>o[x2.[ #QtKg9 1ۮyN5qs2{Rc.9AA38(e14GS%'Nc94wP@~qޛjip:8K2%(f\H&mx>D 8AUN=jť֟pwSNvX%h~`/l.-- dΫUBon.|nyZGltbMWm} YZẺ`sۺӥsM9E&(? 6mv@? {2 )xӍ!0:E/>ki/[m>v6g;y!ZN%ous(9s'S֧\]M2"GgD0a 1GZ(\R@K^IwJCҗ-'SRbh4ҝI@ Kҕ#JXڛAa -K1~L;Ei)RPF=裚)}1֏jȔ[(w0O7|;|3߷8ݎ3PNbI)1ANh1K_KI,1Rʀ*sǽ.U+Rѵ(5 >EIx#`$/l'ܚ:hi`ъZN/RqP!,**p9Lis@ -/|UE,<DB?3wcx+lu.i}H Lq O4 F# Ո,I ALS p dٵyX@apeil犀A$u B8"RcP"Kk9ԋ(@;'qH8#R| zsWt{hݷ k/'L隦Fs@Ɣ$S8*q*eV;6cǠ=9:cDH ZS"3ތ..-ϧI||b9PO==)a~4 )q4 k}jk{۩fl,s$<E&n2pzSNΪ*zUNq9P?ZJz4&I@JJ  |aS N(( ;ȥԀEJbhcKE-JOOڵY%Ka 8=APH9@4kw5w9"4Q? N~yGt,cf]˵>J9;KyhpJ^AQv8短7*W"$ f Byf8 7B@v0>qsJ0`sqL`]A_IAF$I 0AoJLu+wl~`gJF1ڎ@(>ށL ^T-bL6Q oLt1)߅7ڀҊ^gR=@ tׁRIhTE.T۵9e2)SA{L.Kqo'_:?31%H*t j q=AǾ3C.x+RWk 3:^g8Kͫ4 !g#:PhJy9n!71 x ` vhb[ +]s#'wc8dG`BunhjYXhUkܙ=FyQ`ғ4pNytZ@sV,n O˸ISQHf U3{PfN2O'/4ޗ<ӊ˵Ά3f@%mf?OBܓ N]vQ@g *:Z@I8cgzPz +[/Z}F+Y H?g(RSHe_|-<3ӹX8zlvR4Y"I`;>VT9 ۇcfpG==C0pG.:RPQB™f$"g`4Mːv2"{ i>Pv=EOwjl42 сpA@W.V :]C!L |[[6F90O)XȾZ(r9oN?,Skxyx-g%#F { F`Y<@:bxG N,O_Ji=6>BsL"<.Y?6p=hbIXe24vKC+x2y]!GU*y  FQ0U.تqI;OUl?!ӰS9љX2{GJ=1֐\_\wwl5Pc<-Itlő+'ϙ֋*Q5p INv#8=EW6f2HYDrހ&(yD9AϨ=;[5hhHi9'=;R1O8]Gv# 6ϵ2+H$Z2%,6CkGGĆ۶қ q4pǰ;P]$$c[-Ctï7qI)wE/?vD'+שR)!&P>R4gRq@“Qn(4n) =(Io\Ex#\ ֘ )$}) ZĺV勘yOpFFYt}C`QL -H1qDكgZZS4)vs@9$[P1x `gF5f+'Dl@^SҠ䌊b@.(J.~\bz(`#G5"Fd/8S1JOZqHPM6 #Ν2<䎜SKz})1\4c&(hQL{QNzLNQJqF>`S=(n(WvV-myo-1̅ddp}F* ]in1搌P11Y*%n/*ܦ܎vA=0xT xva];B8nP~^s8J:*VPw nQGh@2 .);PS{ztַ1@kYp!*FA(+J3q˪n#3'899CH}E&) 8 x&xn8;X0q@ $5 4aGcB60A7ixzxq4c6JL<[984 }; ###>秵6(|̂61O,wtǿI&JI8.fp37@A4,JȽ#$T\ ! T}4Ì8;bJ)r6zt8A IsEolM*9vy),0H\b眮: n8@.}Xԯe͸H@}N3b*,VOUDFFxb @Ac郑%k Px ޕUl) %>߯Jqv)4>_j{[̑G3܎7<Oz\ `Իa1bn\ ysL wW/=#JR5 }g߽2XF)w۱9cq3:橎)Nhvdkz|Bp*UzJjl@K|ĨZZ-vLRkȐIQ!8B3U#yQOb6qݪ<+#b ׯv@u(}6(\듞)g8d#=ǧ,vI݇zt9 J].'OΣր.EmX~Ƴ 3&ggv1ʨw=+횚(?Kp%IHqq SkCmEm?Z=Riq0ԐBى$ʐg0z)TQBjU޳e.ti(f!IN EJ)$㜏8P zVRTG^q;+T;FyH I1q*`4$܄3֥LcQ6/˷6|~Rs@QNE% ci$d71N0`Zg[)c<Ұ *G(i14ڣ> zRB=(Ѫ5'#85BKǯ4z@ iۜ))H :N@ EG@ i J)s%)'izbO-')tO$eVA*{Z=)iAjn=R (f4o쳫 ef;c>uir,2{Q`=k{>oIۭ/!476 ::dBiꁫhĤ;H'E)Q@()d9c`"1VR:G QO6y0dr,@N'撗bF1IHAz`%/Q@J~UʐNF(9R8 hbY3n-''1M0YTV4g^hw= d^5`74ma;ޓt:̯yh3#Aʓyz9_hCv%{dd1cRP6ԘڗPb%-zQ &_ά_%w%5lE,zګPQ4Z\=h(]0*`<^8"uf9{gCQ.~}s5pLw(b]Ł== 6y(d(2.|N83}Ǩ1ފrhzF2E0F֗izPq߷jX"6lp?*K.fXY0[ˍP €2qI=Ǽvw? {RC@ _)=웶rg#3;brXI>43K4m ) Qژ 5gOkDm%{1")B* LRcP6\JF0,?(lwU){R$ zR~(ri$ؑ#t LC+A*ȁ 0?PF 0yl`zg!`}֏\Sr(`(rqKu%DY|l@ugژq"Y\.8(^Nٶ 3~֜ Ls*Ņեu9ޖ8kY)2m1FP.O y<[kI.TM2H"q=#<8 %CrOjQ ݔ6A y9#vȣyrŃXmB9 6qT)?8"FzqHbGBGX Dc2evb9#kd{ZOpVQM.M4Nby`0=:񞂙kwqarHcz AaW炠ķ=`ۜv)ATH6Fs,a,ǧl_9b Lѐ PvOaL'A) Bqך6Iw"+pz,N }hPq i BN$t'A,OJꑢ 8\"eHUb1Jɹ6nrr=T}ޗ}-PI  R~sP< !&F1@bڔ#8֏)}(sJ4v"XAGj1K;-ia450HYW?# \qjՍWo*mf2߇?{SҒ!dy(^4+pی6|ڳ@Rs qL)G^Z-[;P,^f[c>OzSue+cғ/^v'zN1ǯZ)(G<Qۭ#a֒O  7Ը9֛ʁzш>U >>5!F!-В=u4G> An`ѽG39'>GHO9(R(kd# |8bȦ㰧q)TC3IC$c#Ҝ{SAG$c4JP GPoZoNRTIړN:L`n7sXb;+ wLE$ "4nnSր(v/z9&Lt)^E89 *ʓqڔP t!A8.,1<$Q3QŒp>nQSٖ- 6a1@ @W(tMO:O<~1oLJdvE Һ!"1ea>wI"e*Jd sތiܙ<6q=21_ƆqOjQ@43$Q[/C>wFs˂9G=)x\nP}A>ԮȨW灞~I[JF9XsCF{1x;Q9*8$nCR`zSyqӽ;aMX{gPop=A}zg=ۄ;m~'ʦI2X~' n"Fy![W+`F J rA#TZ<3MHYgqFQDZ aW x:c !#r1Eu9ǃOb.D6Ww=5\+TR[j (™KR2qӭOi-7*VhkHc<pz#Ը-+H߯@c:q 2b-אy<.U s҉$qo,DrHp MEiWSuo]lcp ZͻqK@1B$K׽JPPe +Jf ӰF''Kw ))ݖ<}id]dqAECpI!g5$kpOE4d=ZXLܯǟf62 v;xV[$ҐΨs81\z`*2fj1\BַQ {5s$LdS!cDgf8 IjgE['c($܂ǂ~@ Iݞs\Ax**İtL CSJlB$ ש䞵X)'4;Ӹ$'JVzsAb=)HRP0H }(fSH);i;Hfg='ޛpi[ 1PjG}Tu.8vN(h=([n1uKN+>·J^9ǵhs2M'i*ޝv&7E*e#UH ;+&GE*8((ih@ KI.(ޝjEon-&*PScޜ'aa-'N/|W?Zh`AE!Hi{w)h 8g( SE g0* -vȠN٤.9⊺E4aܼHFBz{bsMNiZg(ӃHjͥΡtpI<ĥ3@XaTeKQڀEYKI̲DquM>r;R`1d`[}GzoQӚR Pq?CI&kSKqL&QQU>"0(6$n.^U(wq}5OXV`Np=1)1ڝRR&;ӾڀLS'\R\P0 q?JB]ÓiW msmyS$#>b+ahWu)<DWH LAQ@&)F1҂1QEծD2l2;z>>jK2ELT^~tޮRܷo061=(ڊZ@3ڀ+KEo{6 B3 f*UH-Em ɂvF2N?AL~-[7Q$?ı8V ~]j>}*X =>;sz;'k Bby4w8W5&եt clxa9KҀcj_€(8P oyݷv8ϦZolmа6y>e;]ۻ+ӊJwғK1KzP=.9 uݠc\H2#~GxqhB$R4wFAVw ||qsO*A#&y=:,hQ1@^3җ𣷽Miyu-ŝ(!dB3sP{rHcp~np?QM 4X'@q{J> KO_04<"!ǝ2N38?7bظf3w~bFiCa=ahKR!ssRЪ Dy q@=F 8u*JpA PViՏ`! lA MS + &:v'#?Ҏ@.wsր8qAR''S@zp)HҀ 0s@H)`ʜ? @41W0}9ȰJ!;uHLS42+GcdNGC:$x\[yRLx?0CHTݼc zP28>J@JYZHգ`# 8HLC*DJHd<=xH2?MbYz(u3(iR.w4j`0g#8G5#pg>@$qN/On%8# c꒣2E`YsøIZIYy)I]ǓiDo#DEn R8H#r$dcglu#sV!xf{ƆEF1v #<0rI)D%2D*20^M-M4m|8Y4p9cF۱y$Y #Xwg `i}xBA ĊGOQm$K27" NOȧhgi1$RۀGQUsF+SHmͤ(:N WÅG# 4!u>~Ti'叕s>  fR@jz:,R~4+2n^|ng*r 2Kڅ̛IS85[DxE/+DR2zzS>t (8`;{SCzsPA#kkЎkk"SHlc+>S~.#M=cKgi#[ԡ1Y_} |%* .#=T$qKJeF`v9ڄbHѰtbR<2H,ۋrzҴjF*6w )$cjf9EKoZX̙ g?FF=r+0E11{`M-0A ;e+NNHS (hhxngdYd9^8Ȩ;o MF˜_ImA F%fƎ  8iyI. {iHjq?O"ݐ%N RiHilQE//4s4E.8$=wm8:NsZwkwcq%gl0yh3‹1mOWHGqJûoj)H1@ )RwNp3IܾѬaѭ =r*h4LG8R~p:di'q'JipropG۽0(RǥOo{sf iOPb}iH4tJOƜGzRzҞz@ ގ)yE*,;FܾRc4R Rbb(z^OJ1@ ށwq@_]X.7R-N,nI#b5(.K<\IG=(#ޗbTTd Ю@e49Q@Sя/=;RJ8|ɠ L D(VU=89zA{s)ybtbG(0$ɥ#b A^2:SOJeyM2GIz NԌ9A({ B9,RKJT#):ҳ+;2ځv'4δKG9޴{>Mi~`.2Z6;B# C(`QqGzojbzґ$W2#0D9ߥGn(簠 $8]=@M"*2ܟ06sn'{H &K0kh`F>pS*viғ K |{Q`gm 1@X"@9PFOi|30c!¬\9onMIЭː:+qIcIOʧg1!|AUOޙR~PGszRF#X1;;W=y[re7ΦE.B:'5YWTi&.`\upѸpȢ;7c9T7H8B#yxpђ{} ):H䈀|p Hm$ S╃);R 8ېO9"FiRHW-96k,92G?%n+ӠzUHM<2Bz(Ipy#Tqӥ\B1Vaa8?1Im: rEjU'$Tq3)j2>sMa#C9sc{):6~Z 'Y`6k'#8 g ʊbBܟR *L[bAiܛGAti8?jzSB-OxӼ@2BTjcU;2qS3G  Ntp+)ʕ8 TC#vRc dCg>[xbh2M m9_~ޜ# 8en?UΜouZ.42{[TmW݀t&4ip@OQan[5 ]a&1cNX @Z7ta]. MT.1ۧQ<>`/^TZA27>d $DmYO#-JѾ*2@/sz8S$Ӊf%ܖby'>!"#Iu wc0O{ PFO>8 _s:~4ũ$^J'LAQBO84c8@ȨDr,JmwnVlƟcٳc"Y'~ZQ ~KPy a}-3Ҭ[o-1Arcp_|cW1I3J{ Gkx.&7܊m.MR`C$H]zqք;SO4t XsvH &"ls$΁ϧ j:\hF){Ojhn&v.7wy⠣fK[{+g[[tvQFTJ!9)c]BSC 5ػ'< S3֬^z+BXF9S@{敮;7p@ĥJ  G$䞴F@hR;Q@ ۭAKE˜pG#3L#kSǭ'<ӊ+dpE Rc})1I'ҝH= #==ނs">4vP1N!ƛRsMF=ޓ@8qс >R⒀ y۵Z^`J\tOJ1JE-F))'d C?:r; tfGR ~H,K;43/PJJAOZCJ}P!:,fݕaیp}~Խ9aqGRo%1) vzs85(bSzS(g'j)F1F(Nͫ0nwgzSqV]-~,jD2 ?ڿjKzS_Γޘ ր)̠ShpH)}:YId $`JCq郎i.AD V" 8'ڢ0 v$GS[5ӘW+8@}xϠLEZ)G Q@:Omp-L $e L=v# ÎjI#x$,E[2?4 =(ҦyɌ#X/Оq=i\ y2qN)_ҔryTF)|b,?Χi(Qs{Q4`u4?L RJqс~zQߧ;?JDCR**X 7e|u\g.`)G) u#۔ 8_f`sJp'ҝҁܐ2%]eyB?s<N+F hY>BA'ҥC9hPXTXhǽ<$shW*Y0>%dxB|Ksrj0;ջ JK洗w~+ e9 (e`?ZfzSۀ{Rs֘øJw?x#++I TȢ?)Q?P@h)c4FA$Hb2K8K8PԜv4`rsS=3Ls<,`#p2[kvׯҁҍڝV7ZC{cm*B@$}$7č܁>Ԋax BVG 9{+>ڲNQOm JVyD#PN|OJu6+.8eiVFlrcST*S1aΔ!#GL~5?Q֮_Z+ηn?yo&`FrV 81P1Τ'Aj#*czi9ǥRʅ"I37<(Gwp۷ s?6!psiBg̓C#,gr:>ئК d-gu{fVX# ;z.=qeYjdqiI8=([{I]8\mYY@ r* Dgg>m?7*>\,uo$+"Da9嗯^44ĐcLw+),}NJBQ_u8d9Sa3OG1"Inť{pN; y<`-$]!e 2=AM{r]2a"mC 60Aڪ$GWnpALwnbrO=j%Ŧ5!H-2,A$@uOJIɮ$im_~7,%v$9?ZfһKcދ\]Eqci[4(T.76.Ѱrr2yjSzՕXeL@6~9z~mǧ|ТEy5]6qk;mr|9~㞤cgY8@?9&=`y gv=zw4*f-H?PVI%XԒg$ǹ46:Ԫ`# {Ұ3E^ӭm]_FD-?A㊤E=# 5+#g/{M;ARvz`!*\Rg9"(;H ز\E ]>XHӐ>aު*0Le'ԖknL̨L&?FG=趁r8\C2Hc@d*=Sjb[miE8Mq$(ńqgjg'RiCb{rO@ĖY!'XCoZ+K[1|U'qJ=(4;8tmp[վS֣H;!N3yZzv-cdn_9}ߠ) ;Kmeg6UBV<@Nj})1;Ҍ֒ p(٢GJ@wԔvQ@^Ԝӏ'=QKQX |w@g;3oF(#zJ)~)4{RPEQ@Ws̐-(i=>: O& c)9IrFiGjQyAaǽsQ3ըKkEqByf MF /Tyx*̲N1$(NiHjv4;u[D8=s-)i3)Hj1ϵ1 =zKF=1QG'y9 "q/70qG9Hǹt(4biwZKfpq%ܾ\y- 4dQFq7SiZ\DX+cI [,~@YTV?09;Pb+*CJ>ItΒJΐ*zFBI?~QE@8'#/SKzJLxV*)!y'>*7PZ\4sOzRMq=ijM$&szOzRQ``S,16M;gw>98PwҌ \4@! $ d[:=)@i5v֐vG'֘Á*]szd@st$O'=hn2( /Lc'h ƫ,*D?'ۥXӾ.@򼢭4pFqFj0G42U/ ௮wڌxnS؃ji+f$ ڹ3t~ #CN _.Td}{FFʕà`A#sLe wO֛*[yZuC7+1Hu5f}MI-KmBe@CJ 8d\TC$ >?-%XHU}~ @Irm!- 88=\ DTpʰ``r=FglZf Hɰ38${SӐ*+2pq+84j% ;rG1oq@R22pcR#=>t9C%bN3$7cBGCqLb9䍊3)**Nz縠gҎ2JP*N?@r`)x<ǵNJ(L&gӦ*v,m r1NRUhPӞ=ҲK#?!OFKyFc]RFG_ Rr2:E2ݻ;F>I[M#2b!7~8<238V(FO2<w=:g8Ko#$(2!$gO3Ku=ԯ ڤ̱+ '? hm&I%Qv'hb3w}\cqqHXHU ;an<%#sg=9>/<qް|Ӎc }8L,eyCJnyJٴ>1n.c:csϠR>[! SJ G2Ą~>ezTk3]yK)<ț`eO-T" ێbDEZ Pv[B8SjH **is:(Fol^Ў{t$ 4[yJ3'8}QaZD\G/̊Yۜ|dg\[6>l;N%[r{@R AA՛VK|RB%`8b.zޠ@,ܘݿ@U=HyI42}= tt=o>|YI0pv0pEBbO+Y9 ht{x@Hُ89>بB(d>~Iy ,b]FvvSowgy$1YTshY$?@b2WJf7wެZ,p^Azqh[x|߼Q#84۩v52@ƿ8bi>t2sP#nvCd~@ijc2~KGaÍÃ0`"Ė?u8d`'jlr8ܝMEY}?h$5_5qcK(B טxl%#Fl F{H?#Wl%Y/1`A0ybTѤ&VgcSː@NGLd}*R&b%=Vnen6J16Gq 5)⸚ v1q׌j#*EQ)$#4;ؿe"ΡYa ==*ŽQ4Jwc*<@%+,UQǧG+4rw49GjyRB0[ӭ@ 4I2QRr} & {ҖҀʁ°6z ;[c+єm69cUv!YO)'vHX}ifPGE4/ Gn)R%G$'yR {(F1QprgMyS`Q uVhfX9:A23zbnH$AJp>cTx$Գ=y`f?H0}ԑ@A()%q=i0(sO4]N. ϧ tgN)@MY0.A`zяʀeej Y>y>~>]qU1(ߥ-*(gjZf} 8")䁃PqqH})\Ɠ'`(})hz;@%-Go,^DNdɏNx{IEw¯jxnR{iw$̵Agi?QOj1KF)<&UpQRIQEy@2(K@15/s4~YDX"2 PsF:gZ !p?FG*R3MvGw=)zcP!Zvy >Iż-VQI{h-s9<׽Vh4c۟Jn*N;o0(Z7 cV8\bBtP2:t Z@JLc=T 㩦 HN⁚k9`%1Oi"f6 0'?:w\L`t)x4z*Q@2sS)N3@李H.ӌ:4zR1c.NԤq,pqQSGP1W<2AҀ4Tg(F@_]_yj!X"s5&K1ƒV ONJ/Ɖ2<+wg=X9%+$HfR>Z惎09Kܚ[}yxy330 N\Fb 2rT S<~7~g*3@ COx^<  2;&:S˹c.OPtsx =u?AH3H> Ԋu͕ZN::_:z(v,,7|{z|zxUDRqc֔psOCym-CpJzUReE,̱) zN1q NjZTsr(apFJqRP7 p("O7}ۉ\@\Hc 7cpHEЊzEVOϷ| xv`ϭ=|o(c PT恊P@`]ǡz~# aj^:!`3zzmg5a(VERTu''P`6#'?*^~Xb=~TM>+i0 ]`>Ͻ:#H!!#s9sMI vH{Si#I58npt~Ŏ(IY'D܊?㎵D+##eeR;zTi"wUc8#Z̪JxR`" I)?ֆDE,>$=rW(ʶ;jk jjAj҅u.KI2# 0A H\mS~c*OAD7 |)?Ei(7wH瑐qUAjե@R}gޫǭ8R3إ#Wh*s>yDrW#֘\ݼȩ XH#h6eu* 0G`#$H;_4q~҄!΍uXLU@L'p1W uy_,I擿Nh*{֘Hѿy ?ehf%$W { ˒'(k9i'8 v5?Cҭ])Cm<3vc.0P<ͨx GZu]^{:8Kmnâbw^jhdg*wIt~n^\o'? t2Ң[gH s2`b?p$9U/: t=?dg tD3{U$WVTF9I [ kYvԀ u :Gv\gt#ڋvnrF%:3{ymIՄTOS.y؆F;dokzh/oR%?X*F?;haXM%HaA+52<=Mb8e*\2=c#dT yND20U[o)Dp(ᇡ ćJ+xob.ݣ9#8$xQx%Ѹars=;slEpų1r7FqA`j76Km= I א8%N:FjRe;U|-E;JK=9Y6z8<0=F;DڬFs>KI~aZhEʌ4c386T܎b/"(o$#~p@ G&Am0io\tϽFd xc/4|!f☮FSNF1<h%rA^=*y~H$30Gl S"A?*c܁o.UUXWP~ʳ3;\0 $Ko$M){vdcWsmn$7=c'ғMbx~n̲Vi8#'Lrq3^z()#XaM:`B -bjy{5ؒXGךf2%HHW84Cj^UTL[P1-wN=HQ䄷YDw6ңr;OVM k"#a31bv(3I?L,EF)RQnDq}F=[}nce*Osq9;cu$x{4haHe+܃Lةq9ˏ_jɭ/ :s#`ʞO/ `@ڍǰ!:4S~x09ǐ1Q?8npq׿Jk\/$(q(YDWDvȪ22%Q-MuX|}&xkX$΃$g k"fxb9Ug=ajW̭ y۞3ҟ,dXHl}n>oXxOi5h(J=B܋%3=1$Lׂr #qX-N@l#=G D1n n88>mZVIsvppYAjsOiv+.N'D}RG]y SI$䓓i{f!\;is@ J ? B4>l'A4f8GJΫu5xvm'5Ryo.%<^G=X!E*Ni m(ZH=('އuMa;{n8S;FOCҌ★M SFN1Buc b MaUO|z*R04ҽ0yMzbTFRvLPO\Sv$ H)g<Ъ2㠠V!LۑɥiwD T{74sA"n)4~?JhzSԲO,#o0qSҗQWVk{bmr30oCyANú?91VrTm3QZrGmh v>EP)CâR1?7Cj=͘mfO2/1J{qU!ޏ—1G42?02)v'Td(ff`zo֬麍ޓAc1-AH x<); :hҟ#XM`9鴀scp Կ+Osimk+n0PNH32s>ieyp_%d2}@5x)<Ef`m$ ӁZ kKHt(589\ W@RG^Z*"GC.ztME}Xmm܄==MG$rFpa;XeI=*bp2qzT0\_$WffMpvqҢ 9 8iq̪ P38?483O^ g#֝1]%eWrz /e-1)%Y ~ۓNBQi#1*zdZ7.r sp3"h 1ջdգau6*?Dιl;`׸O,Z‰Ygrx#'K+\ܼWUFda 1!!vmVcZvU>.,|+u GP{zsP[8r,q1Jv+2oϷo0 {z{w2sv5s̴򡹍a2DW}K㑌<´׭=Kpv< 䜓Iɔ%{ )FUyGj2Ke0Ns8$qJYg{I4mN3P LRi7du ʪBt8$F}*0c@H.\ϝ͸98ZtR$L!i` ӨY; \.$MOc 8`Sܑ<>ŗc3ڬs={ncJH9ONurX|pr8z z|&. ̆EpVom!9)}Г H\:>WxyR3֖j=܈<%vsߏOP=pi9's߭T&(!';p O>[=c}66BTeS]Zd ,MNVO22Bg } C.,7&+䄆990q냏L].B¥Y~iJs`v :96)Ma!}I*f$6$%xk#9#:+{ny&5Ds\py`Pa;ܞuI&:m2 yV<,spzcZ#2 럙nQMt.&tU*,o늈n8#? g:Z+C)K,c#֭jGuy%v[A;D~>L8 >89}*mgr\ G\!4p|+x~IH'?wib-Ŵ)*$`q,Fr1ӷ4=*U$*M*nʂ@VE|봜cȦ$@fV$=G4N1( +lÂ?1.f YdPB0ޣߊFPp#iqĐ%2zV-(#e\H`08s0~?- ހ,b7).qȨJ`q299fu9;6 ubxz-LyQdlm 8Aq\I,G uXlp$x< c8釥Mor`U1)_lnv ͅQqr@:i" :F!6Tbv+A N;gtx$pQbd:L—'ޓ=){TAi m#D/l{H*=mUIǩRr QbAzisڍZCF`sQ4!AG9c֐1L擊v)HGsKKs@w=)~TR` zR$Q9'HiON?v"\1J().އvz})J8zCI=Ni)@`TnO-!Q@ c48(zcdsOÚZ %*!v 1i(>)V ^(ڊ9:sҚAzԻFi36E8JBԌr:RL3ӭ4B 4 .+pry jN܃HAz&`cFC?:vΐހ4hu/~@QUsShDWq3ʐ=JHA5aF3TD}iaA%0sPcԜJiBs@ v})8NA@ _+)Ҍuژ8yR"ڀ)3O&;b c֛02{S:JLdPF RьS~iBN RF/1C1Уmaϵ!RbixR&vhPNv銚fY"sm}I>ЌE/L}sL >Ua/<(_+o1z8&@ѷ i$p8M>hR3#lA=76}sKk)@|{P `NHdRէۣXKǩ PGj>&P)Q<NhǠI-b"$#P<# SQy\ I.=zQLb[c֜:oa#sGJL \ s +#R[E,RAaN9!#&821q2@(n |fCmMn>]>5 I \v~֖Go&v$HU징gVu܏FOb$F ;NzZuO<<,]یrMGkoff{L.#6XIUO18d>`?8';r{(\1M4dnl&@p#9["XaT"w#.=R"2d{w1f(Utg27L(232w*EiX<7^Aӌ$G!_2'N4'ޥy[f 69m8x?bN)<\#\Ԏi^>Z c$l~-by[a<9UN@~b-Ma"R7==A=cKDqQB踬BAu8HpđgзgK1CW "u~U7i^8)jBO!2F"l3ӯNĹV"Pf9`PN~Su V(yJ$`,6z9R0Fqؑ?HBTYl Z|U I\s8K1L1\HR F]H8;.+s@TG}A<0miy~\m*N (O}@ "6XRU*pGN ާ ?D*{-խĊocG~G8Wn%biPSvIA=ZxlZ^xX>KŒO]Vc =R$5hg|aXr0sׂ}QI (D27S^zT=OZ7 zqV崖?Lk!J$q #Rl= I,!Kk'>_=q][ݦX A9;ڢ8$c+gz_L(y00rIsKFedgm84$ Ȩ}?]̛͍#{@\FqqPZى>qx?䙖rPdvs?ҭ"%| U<=Eήo!\hXrsZ+R2܂}Е~n.'Ec'݂6NrA>^hmL2;x}*['"5dBʳ9SEޝ,S$Nġ0v eIGe^YIvfcG=k[D5HRIR=:$ފ?B$ H/_R9`v&AVb$gMvRH}v҃;1BV2ij*@+ ]Yb˴fdxϵ"ZV3aGomxB8 7|Nx#ӏ_PI=eU$2o0*ہ/i3?֔og-@9ҙPc0[v1q>;>0@@#S/` ҜUUr)'>@icaꍜȃYDFaPJY>v֠x) ;Ƞ3 zfK*Tb `,q<,q;UQIJѰb627>Z[`4i}sJ01M!ֿco}fʠ?mG^ C'ai|Tmӟx~fy4m68t֓]%O$p%Y;cs4QXy做=@ ȡRrzvwn9LC'(4KWH cm ͌ g'޳3<~;3aY })'hǽ'ZP~lڔ>ӎ '-~tXFcl|o֗(f;5a,'T۟[=T)y~tCE۽KW<ԲFWU,,RQhsI4Iu'-(PN< H))E;YX`#.^-2ڔ8C PDqcY4 $%N@؊CV.dyHa\D\>Z`  }i4N3ҊwJJNأRzP zSy R*GYQvDO i)i)tQaQ@7 u!8''2=W%ґPIu2h# (id‣+2O##,"f06P)q۵>Y$G;8E=t 0 `8i8?Z1hsGii:%B%kxZA "~{ҪENT.Q>H9c`ozNLCPA,H#֛ڔ&) mE!r@9j>[HpF#?X<;[wY]Ees<9õ$p:{ԶDJcsS <Nt ~91-ƬnF>\4cP ?;=^Ist IwHwcry6io!7r 'q=<=+W.y4-BّO]ノFH`OdQˎ9|h F1EHl^ z~c$\fKI$LBz3]h kwd~2e_*)L(;uxL!C?0b8#Q-sāw}HAu[K$LrRA]pX棙Y̲iBl C?_ʠemq&ef9ogñH~a㿯@ l_%,>221S[NӬsIU qAzCye+|e8(N#&v"s"0zϊ%u &#cUHӏNqAuG8LQN>u!vjH}oh%_sU/UBrFrCϥiMUn8Ϸ%.2Dp'+3ɻyU`{sӯDZD֩kI#gRr+p %m-eidJ9`s#4zߥN@&"YpAg EjsZ"Q&JI0IR0yYj]3aA!+Z?)[mzQQJH* #7$g=:SV E@o$P0q:tFM3>@VMAu?s9>+K%kn!Y'¹s g2 eJB:c`o["<뀻fMH`8=88ZO$r1kHfx ;0#<0G=o^6slgpdH؀Nr+\{峑G#߸>YsL3K)3G~Ztr6%yԑ\sKgsscxᘠl) i8 ;Մ[1WyAҬK,yskkڑ9 z ,tSݲl!4O4 ydW# 9'YU,0OTLZb*\FvB>el `nbH|%͕@ 鈁V|s088-靧>$&O.tۢ6N@9>29| F@Rs=8AM}A30sn x}3yɿc>dG{޳;ɰ+y 9"m Q*Xz~`bAZWQb7/FPܾdl~g G42pN=Op$BkdbI1퓞@PtVelg#"4z3$o8r1!{yfaGYר?:@G.֟(#a w8rPx>(9nwNZ4bKH E~P\@K-5ȖDd碂y94HMnJ {LwBƸ~Caڑ/pdt].0>;II^7 7nè拋y-n$M&9e$4=Q<0);Djv&oʫnFy]]D]bSb1Dh>MV7Ksk<.q"AQX,gfs=(.# +CJ})&cA{4;N߲ʪCv`r?TxffnF8Öl BL`y+yZ6*8lZ(֦FgI H#C#ڣҡ4 rH4ȈOʽ:PB`⛎pzPdF0Hb@ fXAFH%CDF5ti#.p8?CLGP42J-m̶1̙nKAٔ.ͺHId= AF=)q@Ƞ qlgR1J ˷n6c$m>Qv;8ǭ'Iʘ ҂GB::vc: J){E%O8`6pf|" :h▤&H8IOrp̬ ؎KbI$y'RM#(eC$\ǨD` OZvH<&?{zp vʁs9z1@V-K!pev;A?4Xg59H@8@ȿ()Î23S؛U7+ X~`RczrlE27LUbcҌPQGҖ PF(iJP#?wg.KE.҇1Uo8j֚iTknm>PЖyU@[VZ%kh Ԏ3Kri!qpH =(jBv܁}{S-׮)qTԁ 8*B`H>a(N*2)ց #* gJPqM#ߥ%rqL{c;*F@rsNG 6XDl\QJOz_|Zn8O I^@)r0z$d>q*2yn{@XhMh݁N1'<4o#=OMɭ/x,CKwCU 0hБ <j?9n7@DR6#G$,Z)2T*$"Ԇ$]$P>p)Iۊ\riv&0s_Z\vNqczb V ќ kjܺڬЋktDWp_nyo~)kqg43%OQ=)9iv@ >11ӱnV{P8!$҅R:A3&Yrz5PȩEDV2[*L\US(ł\~*hr(oE Da21f\B NcثШA׿^Kaq W&f$G'PH8G  \q9iL\ |ճXdX38>Ks4RF0Fyoz ++K 9<$$kHKTf,&iٶy s׌zTe'aXv!a+ФɌ}1R_?1*Ka]z c߭:2c#j8pF(fI:,#e8a觿~=.RFC.A)Bb"@N_csQ'}i_}M03m_%=x'朗Z=mdfwQ*IgL'@H mZ<9ϸGP-漊QAĝs}Ol1r[rwn#nlsBYTscCДY`nhl-WBqZ=g2~w1׾0`ƌȮ)8u#px]"[$Xij7˿#py߽Jmt]\ UPM%qc^*ƮN}ǵ;kq6 .,wmZJ)T=GJmQT[95&XgEېzG.촏lR%Tڢ̒ (&s<H=H=zsZ\iEqm#Fvz4] Gi"wKmQԅ#p]rscw\ukP2Ýv5{;Q4<~p}x^}Rkx3 F8brq{:/>XM0LX7^y9_|PKu%l-$@JTdr>qveƷt4`4K&=LA qqqkm*YUÿ5Wr1cyk _, $#ޠ` = ?ßRd%M$x?LVww?fy#,)F }8 Ɔ\FK#LqI\c~55+I#&X9EYon-͉SK }ϭWf8;e`= *[I4rS*~q㓈   I_hL Br!,?*H$,@x$F=i5T tXNtIAV;dEpJJ Tc?֝ |  q>9o6dr|͑J3#ըGW '.>R8:*)h@Ia8a28sP|nJn@i̤|W{c(@`ݨ@>U݃~lOJiDڧSO,B<7>n 19לkHif&le=3|_M023iN}:1)u p }3YlP̑: eF?| qN!v1ߜGo@Io}uk3 SOL:xw*=#q?pG SyHT,I T?\QڞJ$zyJN֞D^RlI;`AY[Xkm72ƭw\g8I=J8FBdP=0GֈJŹc0 0lv֖̈l;4 cxܜ*qSۭ 6INi~`q3Q6s4=sK$riJFѓz `F8'<3NqҐg4!F* ,`?"4^sԞUOn #zV*ڽd:tFְ1hRrOq'`:fAps21Vӂ1 Y'\y&:obqF@N6>siъ\uq 8_Jjbe︖ ^c)t4RPoҎz◚(=CaH⁂y8\Jײ%喍q,62"kDwF#n|n C*tgo -.{H{ fR۰m$œGziH}H(q,B@R>IZF;Jc(;LҶ9#L7?abV3uИWJ-t/Ӡi"h`OƳ ')w٣1FrۄZ^S>v7|ޞԒnϘr1:)ۊb#rW >M ,1JdGYRF9zV8Lɓ m#s@; 1^XF*B2֣We`52bH3cj_0z`'Os@\g0zj#G8,M D~̈?8Ȧ! z;k4Ф|g֡gS&H@1Q${]@r2zTWtry gJUr9|^W*0wy ?zVǀ 9H8qߧ^'MԳo qp*wmuܧ랴O-J:ՉC$@Xy$NjrO\4ȖN}}e$ xij٤Lq^PcOwF)"w <3_ZEۜ8nVtp1cޙyw-լ!A-N9#;?:6.RPi_/RL%!b>awXzq~_ZIնOl dA"B7*FziFΨyRv E@h| QqJrʋd&Bp9 q[wݛ$m9qs&I17.ztƟHcY~UrWp\~v0iW *?~)0[ܯo«d6@PJ^Ub(P;I] UNG2[t ;%LcB=j<(#pB;zץnYJwQ}Xd4|IHaeyX@#;wuA~6",Ƃ@rIzdz4ŵr=B #-4`\S{Oӧė t@I e=pvT@8, td|@ s8N^D ݾBOt0-IaWhg:szXKcE!zvy~ Y"Oqmv,Pp11*庋HŽ[pwg'vH#/Chͽ ѼИC_pVB`0s}{byY]6'31Ha:i6㯥(Ǧh $f6^T0<{,0,Q p@YyD`ERs ~ ixӰ1L# \ G v4@i1SsN@pe1U!A'BH 3 ]ǰio4u94" $s U&y dFy!yI@ ޓQ@ɠq@ KK(s552w,Bމ~eI9 :]Y`Ws qލI#sA;h皑SajC_Zq߾i1z4ך8iq&go m08JLpyC9<r)9AE4 bH+;$u(g4I1LzЎ)<g?ҟIFH"0{ӆ@Gc!$tHT⟁J@2;S xxޞHs:uJL8ihnsHTbc<9O{"ILij[j'0@\1!`{VakG,s2 }{b8PRzx `4(dRyd%\!v°e0s}r \D"dY P@s'8?J`#p>0F; R;=r}iҧ'?_Qyj\#.ƍpTӏG=& <\ԁ+ #8v*]8L?@}\ܞ>=֍ ۊ4~8杌^ǭ hrE??r8t،2?Z =9[mlt;E3<h>pݪ GO 0iv4 { cL*E@9oz^{׊LMdno;c#ZXm' $&Ol2{'Z)HN HY~\n ڦny ?ARzʆ<~85r!!H#o-$gWǽ4a?w|zӈ8z#0bNgS G22w7yA!R"uu- ӟC2[L0IiD`y=:c{c8G7@vSm#C֥ @1^Zh qS@҆o8\s?J}Z+f UG9$n1?"Y$2p 8Ѩa$pG=)ӱQSʟCIIv@!_)o7"I=r'*zfdG@CŎxQ0?J)VD;Ye9jR3IPrrOzj8g`QSݏ! UpgH~~ifR<;GiPLxC'"PHebhløtF6 W $v1RG4ƙ ?-gp}*y7vy#4UXm=H܅ wj `Azն4I4{c ~YCe+|y?Qd:i핔  IflcP= pex.::|fDCFVb@۰9Qy튆'P:,n3ױԢDcYKd>GRh4bSywmݤq.fY%{8vL<|##=N0i _k6}3ǧ>iH qBEoʣ~}#ػF0RJ5m$0MPW9֢yY$( l|}sj9WRYc6G":yy8@J3p:P(nL64msvRE U!.W d?U( KwV ࿡*3Ƅ&# yylÐ9=kTŦ[j 6LBaX$qЎk;dWy+c>Ln(f*#=\Dh1U<$r:ȃ͘C3I8yLNypU;KD6~ЏOkxd/k),18>rM r2a ( F@F:wR{Ri ۋgIn'W.L<\ DKjcrB}3ZwX[ygOЫ&2gQ&䍤.?.o|IZ;O;`< 9ֻix<6ĪEW s;}b@8809JgX3[XyrI?Q~emZ{uզ~T >\gj쏵z/jZ2Fdv38Fo=.'k[iQeCJԁ9dj. &VEW&ĊA``IjK]+GpĹxpvA=8 +~XiJ,,G T;?\KXch ۂ@ lr 1mjb @$N }K+cP8Sq=OZQYn);GsGsxk C`yӸ"HAǒA}+jEH#V"8HEisnJ;U0O`m~`0jK+w .bgFC>5{Kbؽ<|J1֣I&fbhp3dٗGmqÃ<zUhisͻ=ѺO|#G8VCr5yfhbPFH2FOAk6x'VARKO%w2AlTk+9=*y6I>:d%`Fu`6=>ߖx!p䷿ҥK/68 `#SIm8 QyqQ##5%;FvuTwmv #Atဍ<<ȧPOԆn"01S$#=ULT F>}鞞?1]E Q36?ORʑ(VάgFaUe+n ul_õ3wx" bXAƫ֫m6q ys? 皋z╖;2ҐcsNRCduwW^+L-#("#s8>qy=ȥ#9A@ +}"m>cu}qo~2aO#|R p zn*B1qHrh@Ⱦ7N!Qz`jd؏oLsڟ?Pi;jb2zPy*F98==i_҂28iq:u!aeb1(m]X61SvҀ2I{ g[%n줜8´7S!Њ8+NJ7 Xax`IrMNI(.mh\`<hUzÌާvFXjT?PhiXg$bZ)t_vO,ۺzVk)Bwl$GNN*u' ?*b,K$2!ʼlT%x䍧{33 ~?ҡ8'^Y]Q ʍFx?Ly{>frޛv攓Jpݜ{2sҜA#IN898'=@?? Ӂ*r=XI9,E Z^99#`Kgn^cyL2O`;ӯm~{=)Ram=T zUAm9:.yc(5!Gv<Ԓ->eb>ɢbt? SeTR9yAsIg@ Pc,-cUIsN21L=hxVm.O@\dc8)=A۲Gp\q$+`$mǮyl zi ϽF,NS;XFQVazqRf)f3jq B o7}ͼmzu )=@ )EQ: h+7x_qm?NwKԑ[,YYt7qAqgs$2_4M|Ƈb'sKw|,]ĩGII,p"`]}ϧN~1G?,j$rۂA>m[i[i#mJ<ԍmB혘Irϧ"\] Hb?ڪÀ㞜H/糷;gd!hnWRy\``9=8vRHjZJ'eweG vGT;Bo7l`Ҭi>܌oZ>m*+^/5D)um)ی{skA=wyc/L I=xGQ:$b!e`'9@r*s,MpN99=+F+"7$pDdub}OaChmCk wYT>OS3҈yoűS 1^p~KVzl 4Hf1sǿ5,3Y$,*c-GK3ȵ]YRybؠ; d>9$ Ngw.wUʜy?L(dZFJH[KUyC`q l/PuWNH AYӼ=9fh|$*682pk-崷xR/)G 885-h]`i Jp@9r~c4QRr6gwFxsڅ~1ˡIʛe[(ZE펖63G)\(cc_V)BdcgnT.$zc 1Mef@n\fݺ`M2G dSs6@p8#sX:ȫnĺG'=H֍RsrLij8 Ўxx5.)L 9,3.d`$ԱQoIPTc&67Nl8z$6Csщ'q&^FPr(`mNzEՈ#b͕Ne;psb;: "ֳO۔!݂8$9Vֱ7\3 U@qr8ֲ^-oR\:d~|s[3|A3mN9  uxHWTZA>023\:zr#*ܩ p~ $L&y<6[8G6?{Gs5RKrˉ >q~bHoI!P~n6^gPnBq~vcIeu5F B9HGCsT( bB%Ist~y2E IA!F1犬 $;+܉^+:d0^>^H(n8*F:9yfq-F$9 s9wJ/H< kRWi6TF?R\,7 gxRpHJ$eqԖnɘN{>K--qpGI,2Ei x' Gr^x?ni@#|9=aܒ+s(RƁaq}zӰN֥[L+R@tN23@A~Ӎ9NARm0A8ShH13]`aR1A$q嬣2lYI@=qT<@nYl̾V} Uyȧ+(nzg㰠 a ^_Ǚ AːUzp*2='L`cۊ\ rmc n9A5$ш($I3bs4$-8T$)Lʲn{SHbm:|ĚfS鴅R? "cP2I34bN`#z x┃߭w_#";>Q⛃us֚A1I$1, %b=Ո% Td /Oj=݂.Ԅ09Rm8F=*y Cf:aa]dVRr*}<+0ƠG8! w㰠,51'Umi ? >HDlU]]Tr}R㩤\:&chQ,.goӈ(VV "y[0Cr19@#`2+H ^@8}3'WzG,rr#)`4nNeC*(҇=}"+[0oHiT8!PɌr(<(ڦTzUfwFŷ4Q3QzRlj$NETn9CLEޥ|fr9֙{0:``0jv z>&cI!d-aݼ(,Ď9#qǮI.$"#e89Ss6GJ#P ;@b B~hF;g{P; dXiAs@RuI$ʥघyF)P9xq:qfK,Q @H'?q؊X獶$Rm 'v6f$6֮eƱ{ ghbx.X Hzq~E÷QbRq?7[4s4~^H@# =.y"0ܮwuQX|$zcH6 qZiǚU3@.ͬ ;sNH:Se?+qN%i*"%8 r}?΢VX\sSݵnf|iԖ96[qPʹK3LTaCOAB A $3}*Y`ح@cjGS`sQ-Vv%єv#\YMB #8r@] 󞣌 Ҥ{V8$zT[ f`>*hf7n?2@ϡ%ƢW8s K#;rcmDi7 0$@2=CJXd[ʧc#۹}y|ӹ<ʫ}ztt&5١`>b Fr {u4׋5ĎYlcV̪;\N1mAGN*]mo^@8V_.T;Xr͆8/Mah̲əT0?x }}i!HdHǛ@ Ko}q <1Ct=R<-$bAE%c I r;֓]3NTdX1rl~Tļ1OO&&M(xz?0"2!lpvy~A#{}^{zqY\.0 U-eY]$;v$H|@Ȩ`I.Ojp$208dDQrH"L>NIUy}:Tf #FK^#q۟l|9/mZZGl9N{qң@Dpsfsz~Zvdl[^3 v,?)|fФnpx}23D>r]X„|d)#Mcq|L=5{aX[<:=~8Y[P w'c:ۜ;{CJVʯ޿>.T6`.;ƝbppǧӶJĸ#:s< @J 32G SA$X jxS$YWr}u_Nqr~-GR8Byv#=JjLXCضџG=Zi'qg4`)4;-3t'fdLp l~ opXĪ7%wi%LPH >NH<}*VVB4nHS;S1rMMR`cn?7I2*v3Qސ 41@Ġ)p0LPrx"\iJ9Hp@9}wLm$M,n נs,(V*$L|wSA# IœyҔ9{Ӻ'AzzS  .ܰ `An= hړO?ZW mƔddTc grٙ рp2bz+m2My=A$QEKvViMǞxi91# =jR>ae#>`f ~?ԔwPgHہ> @Xg2;֜!n#4N%xRxj0̌9樒tUVW$e׭WE]Vyߏޥ`WYd%bK7RI΁1w8'ҘbÜt'קAmD)ۅߗUi?]chmQI#ArHxz|R=XQc'v8#(rw2ɏ 81׹[68ZN gTCzǧ8*d[9@9P6 -RedQw6ztpİ;w1t8cg:Ďp3p=pKj%Я9/!\m-(~==bS !xrYU.,A 9*┛L((!r#7 @ލH2E,IF##<2}ESݔ#"(H6ӫ ˵mb{d{㯡#qӈý"[YAvpq|5kB^IdcdrF{g^9I8ӉH+#ʬeOnݻRH[r@ncToͻsl~Hsľa]1>zHD(y82r HYAyE%niMjP+I̤86NOoZ-ZWͼg}wjō#+sr:&1bŔ,Q>ږ4өJHsȘSW ~Z0jцX![oσ`ih#8fU24;堑00z {9`zd{Ҡ@1?÷帚9HdPϯ82Ja[s;!;8J] H`#i:@ ޥ 2вM1Ǿq8`)m:w!Tp?O](#jSAZd9NiO?Zw9%BF ghg iy.3z}z^`C?@ 56|-W, Cbxw<Imm B`?bA#ۏ%+6i#e0P*y dɪyRhD@=9! OˑSyQ}?nqC 3Ȧ<* e9#80= f1҃돭8` HS<q@D!0]$#LϽ6wxјM۶LqQ1 68$ugϻ!!f2rC/1dBaT\S#=  (?=N(6UPI`3;€3SzH}BINr3֚sq!4PK.Yu,֤1?1" W<?a rp tRA`u_j%ؒo[),xی\w`r3IniXwFiqޏ&2p֤!wPܨKS}ҘWi3E4`0֭[XwG-bVkz b7aQJcg&(!襷flsSpO&I@ ۭJ? NI~㞔)4P22X221I]]OQOq4»bWA蠞ҠۊCqQW-tˋ~]fU[=*qE.=)qҀnr cIb sI!@M/zrg WMl3Ҥ* stSh2:PTpOj9In v\⛴q)NpM X)Nds[;[A:)8`F3ǧ!F>7kp{fqJdS=="gqy0 DKmc%rL%"1nڠHJFaE/@@IHӽ5tr2E8Wxbi?Ҙ vHԪ#?/pzQ]h Ӊ$ޔlf@hP$lw61QTiXHp(&,pXgd $qWn߅'2?FBZaNz`R'P)# +s.F{*1ҁAbG\e}uܥ͜ r/Pqr0zy/.`IsE@O@-n;< FRqBOԎSQcG.nO'g4i꧞",!!M@XEE,^ln7<Mn 3.O֜[jd֟1IDrrIvЄ^)6`XǵIDe NWMo@XF I*Z:c=F:T'MQ6fHcVݗ{dTr&ӌ~Ҥl@DbSzӧ4Ɖy#1A O؜JqB_A6"ǿB8P~ڗi*BND˄c# c;*o(MPg- *9W 'vSG,p831W^[8uGiAĎۂqq>KpmX`[9?zzuzڰsЪQc@ypNN{z~XcF|9${!w(9!:x W<[<afa N㝾3Ld8ڤ1&IH14WvL2pU:.|1'МD;fF';N8Snը€y~TD Uc@8@>\y7;_~ uنq4iUq׏_J,[ *`#@>:|+YS?1a ~Q鷮qg>:Y<ӉvU@ZsD9 'cP"G;wW؜ 4)Fb(dwGVc׏b``=:LG:B(S"H9R9@Tڠ=ǡ효ҳ$a;\}*^E s[b{A4s)l#/O1"J"Q$a2Txp?^986?|rwOyQpz5kTg幂c&۲FXy6O|q'SduS[#`0o(yeS .EbWOhfBG'%P8#L5 y:?CJ8?J_($f$et>Jǃ'W;F{5F.rH珧S7O˓bOHTfa|YXG8Q2q׎MI,oo3aEzqdըܱ`[i\rG8Y3"f)'v'6&HPm8  Cl,"E v[{d9~fOcMFqK{47R}%HVR7zGo俔7mw¢uX+1L5#EÓQK ]vv3"$h&WfP3۔:d>?ϽHmI"x C1ۭ WUa9U{ *6qn}ŸsF3gQ͆@:O1RW2Dd2n }* >byN=+2;0bēǯd{)cHt*NG9M3P%q=( ;Tȗ/lG, ^=B!1X^TxVݒ 8r7͹T($AMM& UQ"5?6@9Vm-^h-mO=PdQ\U1BI8*2{{#^3J]={]vd>j]ZZ-լpI7I\qֳ0hM=c',qR#P, zdt#)cU 󄥁7q8&(R'Վ>Ef%p[nu㏭1S,@?JH or Kı#,rђ>b#T*/?>HL.HScv-(2 =3Hc! nƐx<[T Xw&Kp'}G 2gnsޓq߰鑞( *HzҜuQN ~TݬANs@,EN*$isSE*$P$a,~434ƭ}Wz~㍼~TʐN ƆwR$HsOLӑ£6r=:[;FGXg*-I-A)`Aj]A9NnjH-y@ Mc'HL(pᚒaPGRMOG@9ر })%8e|Lc-qP4{T\)Iw,*? VHhةF9 RcږhEA$ ܇.~2OZr?œ ԗv2 7}"(@a-7庇a"`On*9_X" |bM N p*_|&C;C;sZ|djI`xXے\7M "c{zH4G+?9i w#=~޼` jκk٘-YYT >8ҫuE;Zs*!rQ'nP#=:Rm%X=`A41I$㷵" h<((}Q'4~U 0p{Vꗑm[i谬f+ucsVs)S0A=X4GAJ1F9c1i}PZ} ul27qګ63s֎;R,n,.%T0LvC!*QY)q(z9JflXzS{Chk푋 } ^~)`4$==-7*idcd0|ҵ2oad)9B$B{rOI #eq搡2䁓G&cH(i4gimE&H3y<4NA#Ҷt6 GG$s黢T.melG<x?Cޒzv+"*Ar>[L%7 Ͼ) i~c1 ڸʾ}F) < @ 㷧ZioS@HM#P[yXJ`~At4x?œ[=c\!{aҜG'P6)QKʹ׭9n@GQM @<( ȪJx8zRr@P9h=>WR 0F#V@[f?x-dcu &1eT ЊbK*g'#?+(A%s@X~Rc'UJ@4\@Xo\P2p@=)@<OTAp<= FǷʡmaa  zHHzHO8Un)st`c?qXgyVY*6Os4 pӦ)<aJܐϿ8Ó׽ =yqL,76Ӱ ǭ?aɠ.8?㰙@s!=r1?EP@I`OzA4ţkn,t>4!r p۱ldV|={})iLjȽ>4a^pҬWǑh,؊OC9ZlDexYU2 ry,E(6ZtJ:g!brsRƮVш=}Ȫ.0#:3ZO'˶ _a;_'^HPN`0)a,eRPQ=iї@2)"x܇ |q@(;hg`c5 X ٍI)RG_dlǼ`x=8e&UMmp׬SaW۹r7)GɸqS&HpOn<@rp:ǵ#00~[.Gn) X dv]0y \bZ@Ux<~?lf#p>)'n<#Laz}9LM H]˝9`zաRIƸU32}x2s>A㒧b=Y, ߿C4B6vPsL%f1RO^߀~:qZrDL1m]\+%GB[Lq!G^OצOL[ Pi$|ï׏vjѣ Jī*F6G5b9J]~m𶬫m$ 0d OLGtQ w ,n1y'};57o3 [$ qkjeK /̲,s{ȥ#24u^[E#JĀG8B{U+^/!Њ%+v8X700zs`{b_ˍC?`;csOB}s 7ROB+9V!x#I_̜"Bɐ 0OztPaH|rO^>iub&G  *c=$;d .عhx~nԺ|g(V3 .s>1U1:v?tt\զjS!JPe:O˖h7jKtq_8aמOQ5uކu"V@#qxR0G'XiV٥ĄGgҦZ{\]y #9 `VR~lc2ʣepp6Aq؇#r[yF";a\-ךn=)1,ўv %=:F U9jڌ|*[Ā(%NOLvlr85ɋ%̲ÖOSC;Yf(qΙ;H s;cϒE2/!H{  tmkc$eT]sHp*F;ғ)\ţ̱6@AoR8=qH.Bݐ98u<ɓkQ#erxl[7l{t'}!$?!IOB?O~Sqw!GRxp6|=A;؍`Fpdy'p+0^\E>ih m`<$[R͆s׎zE%ȒHfHm<0*:*ss=t/k,v૲}R$8SnUkpm墈D3ӯ%1%\˜c=xMm*?qzqϡ+9`֭,蟽"0t#rP+MJ%Wqؘ֤.ȣ@09I 3=F\z ܀0@A=aMj--4@(}y? T"WycVݷ<Q:Զ`fUQ"A'NLޣr_`; *)FHCӧ={fIDa\39翽@xe_zt(>DZaR@ۑ}qױ%7_0nVfLqvЫ( #o8A:n##mbބtg4NVyc, }NG ATV1Q~#+,$Q7@uw0l`֚!)FIG'}yڮ;cpg֝,pyx7IQ:Ewy~q=3bhⵄdol\wçx%m#0VvrKt}ki#$LGpκRBcf)GPqڮ۴n+4g^1 ?Us7JAFT03A#?/=}~rY. JʥXq;Yot|nNGhl>eCC 9:=2j *RF@Ƿ o+Vldz{؆Fn$qU*eO<sw*i$@~VPց 5'$t',C d${~F{y#rU䌩\h% ]YA g<8tL &d|omFۆ]^@P{wb9$iȠ>Ř@?^=Yel͵Mm&,syA@ߋ?Ig~zɌwCb3zBTRX+R>G Lp?iu41aTvмLc wfM#{S[3ZP7pOb0<`~t:d{[q*.;:e8Ш\}NKJ ..V8Hj?0T_Jr0sF1Jӿ4Z+ ?*"UAڋvc ws@ =*K;Tet=!!A99'嶖 9dt;Yv}up33JǞȻ:c&XkFFr=8@(H+E8zN#z(瞦( ^2yJ/(?皴d=~!81?#Ff!@9=8rsDђ#>{īr85,:P1@=;tԞRyf{S[mI#*e`v!'s_Ipq񃞞'[eKx`1eO뚤cA#r:n0x2OOԏ  nyKMr DɅ Z4$r@inqql$וj8sL9FE1rp:1PyoCij!S3sHe HA>  B5?f $72}?Ɛˌg|.ޞ=t qJE;x=spr^3 DlFqԐ`8_dv݁j[r~^eְ_,Hs~?U/9Vx 7mc?ӎp{y,Ix8֚[C[9YU 0VBd2+p8p۷zlf;couoNKҍi"۫HKmp AhoBbf=sr wz r0qǿ跳G r} 9I! a۞8=qwYEEe\vO֓H1}cr==p9 sqv3tҿHQ`93Gc+].tm;؄FHt\>5]RvhN34)rOqǮsӚoqI(+,s`8@8*F=@uۑrFȑ  #nrrBn.&X :pOZ۵r99@fC| #Ҝh2JCy#_|tѭW'1઒L/ p>an^KpC"4O˳c g1׎W9=ȿ?);#^[04Z(dLq ot.Aƣ]C쎹9 3U4ER6<|G1#O_sWLRj|#v\ݕ%Ha0ZR"CmUJGLgɐX,2&$Mn@GԲ(e9s[Ms8?Ue d98{UGDCW2'A/03$r=r;b5IOVR_ߛ+,oO&I$z.U!?9#b*ɅQ{s})~rTpvvؚiԐ8ޔ!Ҩ я';Ʋ0T-zti07(_1F`pCt? fvA3@3A~?lIS ?O9mhm >Ivd,Ԕwס<e\ 3_\T;BRLB~V? 5 dDr"z4g "b1H\0}P"ø73w !O-QRUYSc}8pÌyo_WL(OGsx4Jb9 _~ք4@Y]6|n9I#vF@7rH w%orl3d d iܲn5`F1ЎsZ{*[ϩa5Dn~…8ݸz~*(n't1hkߟ/4KZUqG!+ǖq˭>Y KN3 V?2)?QTNbU-لc e$gj)1u ^:cw[$8zgҘ&B3We`5C!R2;u5v~>ӑH@ 2iz]AT 2^=ƘG{QzS8=}I'Ʉ8w~L1"68?Q֐Ď5pH©+'q=p9i; 4`ҕ/@\c6$(jPm8xe`$dx 'w; c[@9@//od4.@8 N }šz@awgx>XgFA14!P2֑UJkg(8ǭM*JAOz@B 3@E);q֥+3RsJg"ƪFwȧJFAah ?))?)8>X'(3*684irpA#*X-n.y52?m:@=iu $w?6x2vc($v8:CC!a$hcAɍocI$I s9> m@08kcSǨy4ON)1<сҁIH?(.ҐtV\o խo%kY6C8e!zc$=hѴ@Lx`ъ`OTf8Q=)\hTc(ցM#Q=Lڊ95!F*C)2K}1@ǿ֊pBz VV^ 1܎)x9tI@ ϵ4i SV(`) U:+)5 K#*E1ʫcZO$qx>#OJ\c^3b=(`g79'LTln=9'& .OJ=3RER{PMeq9g9AR29鞴_84ޔcNiUNgE)_Q@˖zCku4qHeV98YcJP@Қ3Ӷza #$y`r8SFM8Fqސ2@ϽX::T_kɰ7'P+݌\GZ#&̜a`i^W#ݝp A/[݆dz9GôHHjVX\I?#'`*2㚌8N=Ð})FP#,>43!2+y]]# rfIʻ?L,+.CϠ S6xU8ltqPAnT6X :?:g ;wG9qsU"S6y)ha?8?R=JY B*qA =PcEI80~QJcQPqST#YpNt+b{Pҗ*!7dg~}="=c(?ȩxT19푐pxF3Sq68>ܜx "hY J?֮^4΍q8B. :ץ= 3>Tg#^^"Gqׯj5mҡhPǧLqsVaOu B;/(3?秾@.0S%8).ۜ?3O_ޞB%a|~<t`Cc=A>D؁It"꼒_UJnvnT;yn?6$*'9>I\J(G !db%HRjA.@`8#dg5$67 EH@F}'8v cZI$j#x=}xE^X/bIw$m Oc#JVјZIuЈ69#w A}ORᡈ rt G%ܬ>]p~s3JW 0 (ܭ#\~_Q>T5 +k:q&5uxl÷O=*S=~]f"A 2Gk3'F@dBȪՈuq6\xa,H@-u'L@#2J$E.q0=A<ڹ}gG-)e,Crx'rG~^+xOj&x2K߸ˀA^K讠|"T@Bi&ٙ%sve}ȋGc(cFv?_~B$1Tܲ ?0:zMU5++g039' x/0l *3NryJe;̮!UBXaܣdӿʚ!2Ȇԩ| x~Xn}2& 0n;z$PI!8^3Kw*"e?)#xj8`mǰ5,l&1qRH챸_>LdS &9a]d\u`b"o8銶 !8e# l('3 n 9 r #p<0jE€s;"^򫸬UڻTۀжZ;N'?/On*3A ,qA!(?JSgO%ˏKq?>ޔ@OX(V }ҁh2#FᏧQ;jH,} "ŒVMUp?(bivA D=pN֣HBe1OcڡyvvVR)9N;`VUvzpKE &tI?$= KJK 0܌zGvĠc}7S]3TcfW?[ҖچFsqp!IQ%uzi]C8/fY"Am18}j}C*4|#?b:zՠu1A XGp>nK͎M\2F3G Pg4ii܆$DmϾiZ ]ҙ9$STꦁ"2#(P09v|~fHcYC5IOoSИ2 I$ A (_<6`B К}(V4`Iy~HKf$rMJVoH]p9d"X+0ݷ :ZLrO=7qm<Ԓ|lfg99Whe%Xt P3Ψ8\d0:qQKJQᔂ1ڀ94IKcM %Y2#I֨R)}H@Jr[[%o|&efqy< [h_Oʂ20MKs;\fhጶ2] dшds5@Zm6`bnM*`G=)}!zH{H$䷚)9"t>+ 3G;擠Hb:Rb\_?NjKKgt`!"0pȨ; :懨đTN={Uk[Ylg]J+yWnHQzsӊMAM)S[*QHm,Nbq"f~D`ޓJF2HY'S9cqҁK( iyE<xN',HA I|pArv8{TmJրG~Hp3(I=1Zvo†5@c=EK6L01T?w 1@VL rݷc w`w{`b؏Js[&⋎Fyϭ xP8}Gx"Dᕾp&3opאG_ϦGZ| d$tH03+b䑂8 s}x|Sv@b3dޝp#=An]99*ݜ?6 HP0}8#5nIAoe (;sK*e*r{) @ڧ=XӢ-˜APWWsO ~֋ 5gh#890sSAoK:0eu-2 BTHL?GjkT,d)b0p3Aӧ0!D{U9H$8}:YC ,EI P[u =h/'B0>Ϯzj$$iĹf$;F{Xhbrb]i#?xtUafUgH'NX>ní= eQF2rЎ''/?Uf}&S z5<1a5@b[|\n^@xg' :`ǿҩKedI`2럧J;C8@HcvrpM:9B23#$S%,Jw{t>Y °p@l9@I hŨ@# ˏLps2qSPLAv)M,^'~s+KAHO ƑQb=N",Kn]DrSs{DhFF7 LB-*$]Ǩ:Ӿ23r.*bXwqLL.ܓIj!g$A~}!ܖh݃+цЁz~908cW g {h^I=r}"fUr=xzFqٶT(8vy{{byEQ2WhʟN8.78KBfI NvNK,rU-~3}KVZ"H"{i<\eOL`p=jv#mW}=oPM'7{w?fD6oOiƝ/ |U?pZ΀#1{ N?ϩy7jv}x*$v3oSuDIݗ$TTp j`PQ{,ǧsWSqƱmSЏNOjERljSӠ7 Qo3 w"6=qϩn+Az'{槆~ز9g+$#Utl|{LglTU,ojKn>qn}: eqRze " qqi2Em2 ~T0zy ~& /O8?qoaS%h\"d2_ Nx?4Lc.Gq=}z8V7du7FąE\1E\7aN=>[^e QI#:vkR/nvD0(p{8chYOL;G1tBR0YK*@c: UI Kp`: Nߵ%յ&a+$̀x nP7 _cZu 4J n9suVb$+ ҸAێG=E5Ӳm<Ob:cG^5@Iʝ~f>{U2[py*[J1eʱ$u =X$(GX==1xs9#֩y9Ъ$h6=Бǭ$N#;~~)P҆ {R|ߎqޝ2P0@M9{WQv; ~" BĞ~0>["BG OOƖ±%c\}۟á:msEH2.]RC#L>S'ϰ)jVfey#T'&BW$n=_{s:5 Eѣ%F0{_h]pr@=ZA3#$b+#AߧP![N(Z&w51!WzzZ$fCf3:k̛ QM\.x]A] +1#qu$h#vbYA9<;9ϕ*B%PBztL̤ch~4&c A0(_#dF1:zRky"14l|tGU %>fJpsq**6-ޟ؂ʬ[nԊҸ9o'cUt,9UY#w ~Nh-?2)> TUgWL;cwn:ds֐DZO)LY'#}INخb2;wiN:9BSӽ.ͤ:SV]pUsx4T'<6!Ese6w@GYZ7)܎d{Й c8Q1X6ی~9tU,9 ? ض wJ:9!Y$(>j/RAl?άA&IZd, 2ppq:qǮ1Q=t694ڹ `#x9[G/M ȿYI9<ZB E5?#oO{MuCg&]*HRTzȭM[KIxmXzY±CIhG-BrnyO|cڙ%]n}uqzR uLg]Nl:X)bXcϷM@=.2)Uu2",maQׯB~Fjk #$0|j +abXnJJ0̇?BAǨ'ޙ b X4qާ 1<2֣bq@2h H:N#94me A<榔p9>&ȹppiY"*2toc՚{m#p#ytD OZ:BM$NM&YHpG)?JzH r2 Ӹ$e gC#7$M`yށ }i00;S>|h gԱBJHN @B!ۅep0HT.F2}HdLI\ GC7#vXd8+8=ZCƒ >@4v?>8R3z(VDREbL͖FqDg':nܶ$R=99{I=} ;3ʬԀO{..,q#,'VHКi\敇q{p{sKϯmr?tb1!ys@:k7udA qj;x}$mKϭMI-Wc*/;@yB@CFz 18.7֛Nj˛gDە<րWRzbJs۲BdRǭ =i=0c4`]nZh={F8~4Lڏ;(44 1XDL6vƚddf/hl|s7``1wUlwZ i=өW4$IOj~xǭLQ`Հ''Nj݋2}0nK9pYr;Rc֔2:R=iqm>{ LjnЬA^ic>*6Yp*]2qBʡm= A+)b^H z>*=Af!8hޔ#Wcjw 2Nh߼Xs(ZaB8"D8$4vO=)629T `y<ҒxS68^Bq1C(vu(MM;n㩧*$a@XAsrX+u G%_Z F%O@yqL<ӮZ|<[ 4a2Wp=g>2c"!A0$?P1@\})遒sZf-_8(*)Án=G9,:A2A eF2o?)S#m*|gSNhu !bJdw'߈#֧Y41m]ۧ}T%qFd.vj(w6>Sa$q5jB81Ш9+ 8#jhlW`d< };qO\vI$BU1A\<}֓uWi#p =r]Gz xs*YI(rV#|;NC+pB~-t8ɏ v@s*4TewEʱ &0~Oۏ?R)P$+OGGIQ7xҀ]cK*8tRUce%KccWe~^;2C=*Aps#}Z`Xc=>dT1@Vi Ք2zi Jb!#h 87 zu?Zlk睳dB 3K@lǷEXB9&A;Lh@̲1–pN23Ԗv+ef̈rBy`}j"[3vpPcFs5mw* ȭ"WIwtl-:]b !򜞄c9r8(B\̪#O?N̅&u# fK70¢H#<^'H[\H=sJ2x) G ^9\ CMy9\xRP8JJNeU܃~U `G9sF|F~i<9?1Y-n2Y ޙɢ",1L忻ד8cB&cY bgpso9$vzԳQO>`$1[qס[f8 s~̕@葟Pw|~=)k #4'1 ~?JKL<{zuMZBf]W%H:sެBmi 2l^o|{ .+~T$`:$d?_zmWT dB;s=+"|B3|O''܎ݮIͪ&Хu9烁3Ax܂ $S.ϧSt.YYO΃i;OӞ4 {ˎwq8;Zm;!ʶчrv0n;IZgeK(Vh=Õc a2H^8ypl/q%fvv.J郞dOZH?7908=?AngΩ"L2޼*r@8#9O_,S%̆B#|$9`{皞{f%RJqzA{M\j!D3\=D/ I (f|qw qp7S'>*xЂa~r=iEXQVԉܩT(H8pZQuLY\rAǿf}̋$0;眏ץgʹ,cXHpr?霊b8v\x-G9ݜ錟bbA,6`Tc"bp>Q#Hc3PKn |r?0X` fJnGaʁ^4Rܗ_#BQJAXdB2Zn;UW'a;*YaʌF~b~4@X:H|38#9Kb{J-dPw&TФҔgu;IRILČRē;Eɱ Rg)$c=R(OU lM;})1=wc,9ySSofO9J<⬦u5#B*88G1ܠ {F4p\a3wVԧ!fߒ0~o0 n2#,p<ԗ6sYME42wI#(b m\d{g$Js8I08}jx,I-q**}8IRԩ Ҕ!7cnHϘ4ɚסWHFiQ H9FNǵ!x)!_ݓwlc?2yӓj1z(Vbhbei FuuܿB)J7q4FyI)=0\ty4)Ӷvzv.EqO#jnސ 4=iF:S%̶O X%T%S=2qzA46C+:w2+Eߑw.~Pwh R#z^xcjyL" ޓր ?ǽLZ\HJXYWg c:J>cڞF)v=o`89i[*H%?Θ˜}kʹ#e',[9E@<s9?Zi r@rኒ9eCwQN33ҟCXNԮKi$xS qPÞ)(} 6L{_=p#~%$C?U vǧ3=Dx=8#RRNO>nG9@(jU6pzbuA}e"DVPqUXRdO<$ۉBz)X$Mg#Ԍ~xq.I UBp.sRgM(x=iv"*@9s^ٷ^S:f? j\).%I9W~jgB1b 3a-sLV"@9`vJc$GzpR `90x#9#sOm*@x}( \w4W=Ӵ |bEV!J>}㿧Un Bݻڽwrv^?Dddg3FQ,`۞?.XPAˇ#=*PƿC798TʃS#I޴ q7! 2u4R  s:n_*/rO>Qw9jF%$bYI`烻$1eWSh2Fl9={U}BIqs#/i rp7u;qY+ɸ[N-AHdy$F=kzmv;A"|Ϊ[;H8ṁj!`He]q9#nX#1F0QG^{f Αѹ.pF=F i)6J94n~M|2A=Z̑i:I<z_$!a*GV<_Z餖شdcBG~Gwe+yq%%OrWz`p{7;}b ֐p(:AOХ1g;tV4q0q@Ǹ۳dzrHr!u8=; FVu?ޘ̱Ʊ͜«Kp3Vx?^Ngd9ggN#t/ډfQ)\c>oCy8P52̪AGWSClČ‘q8#"䉡7$T|&HbW@?)=}o]Aw{<RI9m#v1;̧$c~zIwN2~lHuqӨ.vfHXe+ V@r;s c={{qQw/',s׶ecnçSw v*IcTfU#s mD39Tn,Ġ\rRM#HTܩdlǽE韘GMD$FZD!T\N7 UbuX dw;`Ƹ) pPrE21ПOqT8?09${{Y@PZAfx9PdG;@dwU !`+㯱 S ҕK/x$dzҋU䀅TղsldHtL2 (wQ<})u1Pb02#:_Sd*K1Qۗ*ġMrgeG"Ha(ec<`ッ?w l)_21'VCt@j6 "3;e;NA>gO*E#Hr2g>g^< !i40HC =zwp $Rx=j8=z1YUWj~ac֦S2z>:m/RlDَ֤,H#I=ϡzq=Ԟ@|d:GRSBd>?C`bGBI <}8}x`Trq .~QҬ5GW<;~󒁲0 =iaIQA=9=jY$!u)o*WXiݓY }uHK hQ4єfՍ?=X,\sUr9JxޔhApHPI󧎼:)<`)H_X|TO#ҦTO+KBX:(@;7uI#mD+21<ۊVW`gFmٻ+*J2G[CSCo#d["G2}'Wr\Zؒ{icXx#KD|*zsNUQStYUnՕK}ݏ|bWh-jk^_ )n:M;:#NNN (S@ӃL=F(*AsF0(,H,PjmΝ˥ 4Cr:gLJ;{RD&7<7֚j2SPqP3N P i0~ЁC+{S1VkA<. &n0W\w89sc1 QH9PcRaiꅸ:~qQŸs‹d i'vw3H Gʜy'֑@sR.W ۀ9PſW3Nw M#JdE6LŎ,Nv?A@=3T3;K sG^OPsLGX,KmߍWhDJn F8\ ؉#8vzp͹ s=vW"9B89L`u+HRH=4 B e;xX`δcDp2\ _H/$k8 9:_#?5P%S:_VBڳQU,PT9c%˷GS`dHm9ScVq~/0y8tbbxzi2Z D }ђpyۿ^59ՖR\g=y5, su]Gvʹ9tȳ$O""99?8[hIs;N܏R$\ i0K4qgLߚT,#=cY])U$aNrOYvsCq (UB:/˞:uVv`a:ȉJPDA{ &4@ n/|}F3NY< }0O?Xʄ21I \gA&0Xǯ^~k1e'wg?8~1)etoOoUB# ~VN`=pC09qWkò6+{w͆Fo4Kq4YC1#5C#!gWIl}UnM+?4mw$׷dx3~bqǯ^$HCg_ڟU"La6FJAX ӀoRS"qRE?Rr@SJB(FX<}_>EQ>\:#| ֤Z >C,=NjWEIy9q=9{weUPdO_M/BY |͐6CUBɏAV#V(0@jfJN2}gGx"4h;}?Ͻ0:x6荎 7Scd.8i@L*y_1'2&>5<1& f`9&W2qC dfuXĥ0v|xK*$0Q2`H#֚d8caRDPv>*d2PT uaژd$(GO.UO!Iϧy=Ba/}u yY7 jdMdiv(NCчo̎d0dh$$`,DGݤӷPR"m*\N১=H)xmuZUNX 9Ƿ3j!ϧr2,7ӎ?b*̙Dz#jq *[y?b63tQ_[x-X +Ǿ}{:[[syGb=A .N0OjvINTb{_\'u_SRA &ݭA^nKKmq CsQӌUcSM e$g#$m̞=s8#;z ͏A6"U=34#ATCC7+=魑NqqǽBW nj֚F9ls{R0bR'w$r ?4?hߏAJTgj{tA imhzul{=0J>n#\np3̜O|cמ;>*qu8[DךB$ 5>hҜrcPg~'ڔ$n40HsӏqUYY1݆`}=&Kðrzs4+!lS[HTr9v A,2 ^Y#'r6^+ n-5v*3}FyNN6I#F^l:>xL/r<9T~U Ň@~\c#<5 D䳹RSZmJU*HqzT-, |ONQU"*xجkԎIs|ޜ~f;;-LcPsq1zn/`19לw^s5Ufe~Q^ބH[$dO=Ol9xn9򷅔bL6ҿFߥ>)dD*S+OQϾ1֠6sĸ)9nzq$z,V=1W:v%n%\Ieu%$a;O Ϧh[N@eܮsбЏ~ՓnMDuR1kj}T&O1+xsiZgKIW|(| .n0@ l]bTtR0FIʟzQ,DHY%{uS\@'iZi'%G2yEͫK;L~SZӵ,J}"Ug= {h ڒ Hg cr>ӥZT#C ^zXHedr6!v#RLktLpqH##\붺*2k*+{{mj@|˜{*T<] %DRKH\*Lc#=[XX۱ Maho2xSw]8_c꿏QIuk*e͈*x#?Ҳ`Ieɵrrƺ4]ĪĐA]p;ҠDjF@=x?Ջp)r)Q]7ظ OZ朐FK-98#䜲+ 3Va$IY ?=iR"H a'#$}*g<`:v*2vaߥH#[ zZ] 1%1zf/ޙ?H"\<)+URpA44 4Cz p1۞_nE!S?֥ǔ <`~"F a"NÑa  `P8]gZ6"UF_xϨK#rFĖH<~&Ѕgzv*lvNFyQJ$al0=zZs 4Jь84Չ>"J7?e|!E1w*mrx珮;;-4az׭Kta 1LaP8Ȫ r2vӊ@<q֡ܜw\EPgqT@Fu9pr]: Rʏ?ϧzv䜂2F)^5߸|co?\aH30Nq9<ԎMI\_A3US00zNn\K-{^v}A⪲p'v4560:uSȳM#:(|8QBT襃aTn=hddEWܬ6qڤ5@$9P\+R:zFSWEZMPdI3jC+Dv>f '}hdbqǯ֤$K˂;gJ]r؞I}z}I"1/n6SX@>ix7gQԮM1Xd[,i\< wҟ?+w V eU-2:8i0圜'5?qٜH KpGcc6EuuEu1nv6z~Z|ù6z{*G,CLI#q S3d$20s)Lc`@} xjRݰqҘ򂘦In89_n>`O7$w`lhSk-`H'p}jlrl}\lw~Ԙ9G#522IWG?2z1e8`Gpk8e`elz~0B1dgAf 94@%RK88!>nHLϷV#rϞyJ܂~(' d4OqNH␂yҵtyTH?em+4E$>xtހJv;ьiB̰w\r^=?0 vix<,H豗rTB=)*dBewMl~B,K + U|WI"[sYZNOLXwR*RX䊗?ӕ"9~SA9 {c10y0"s¼*i#Lbg"`BcOcRq4F1EA8<QRNFNM GoJ@$P簒6KźM>!q֜1BJ8>sp({QqH'B ?ɢ"#`vAc_Pp{ӰAsҁXmC,IHH?UpՇ]#?)99qHcP0G8xQڝaןC@$ (IUF'ڇ;]XeHjЂ ϶ie2d#拁瞔AcۿH'֨,! n=TaKx>ڮE<6?Ul$fzf̄VIOݐ3֦̂ ب|sSS~떏c@!ߒb8hޯrN7fw}p1)p.eD8[jx=F?Z}&Ќ?^%hn2sq~}v_-uٱ}9Ob~veJ݆He`Nde8%'#ێ9iv:]ӷNZKIeT \ vrkiO`#d:`w?=S,!dž^w?Š+ڻA#'T*QC<3`@yӾ+2#`2Ix~wk]f9_\$*nJ1P |G^^#ݤ *A{Pi(*Y_q@}5vS$I2@篿.R,98>wb-E_D;O>*P6rM9XCP?? w*IX-b7`f@{gt;jq߷sRܼ9@,~f#~uW!*_z@9#i71nӟ~:wVŋe,X~І0'8=F? !r?/֦'pl^XŸsޚCSls{7?$XS N ҭK_y8\1f$޽&erFE\'O=FS cD Xg QN `3܊ b֥ps1R:E#8秷@,<JbɖӜҖBB O'S1i\F]woN=DDN0;6! =IVXGL:A2XjUo`dh'4w0*x!o&,c k0Ub8Ơۆ$ʧڠu@~7*ۙ#PBH9l\e@FGQT GS0ºDev'Ғt릲,GA`Y1î8X|u>9v$<.ӳֈC6p<}Hۘ%I3:qܕ%=́SQ_J#߮~RI=&@$#V Jy oZiBWۥJ ʎ֓%,x0?PzO4b{nӘƗ`׌zt9 9\\X~Ndخ1 A)7!B?U`7wF<NGL};~lGcEKA+y$2J1>avݻ=y֡e^1=HqZCflVMDЂavqϧPwHzONíF~d9AjFY@| %wevrs*wWEF;^Zh`2GsK< 9 OB) `w)tC"J2< 銘М{ 8ڗvޤ19`G*jrSX1 s\0e [p}>Ԙ@AӸZmtšܖ?Hzsҩ l>$1ǯ&vw|Gw*X<:8jib0Dt7)e =0MƁO9W!X=Z֍ GAVۉmR)J3 NOp0W细 ^JSFw{+oTL{gv)HwRL!Lk}drNwnu UIS^g9=9ɩJd!RHO~C#@=Aq܅46:I8 \{izgoO CzwP[N =?Ͻ$xWY7ja# ܏SvEs48'Q2H=jr#.Wp~# dgo@s*fL󞾽y1m ڐN=*p?/D >9(@9<N#\ېfyP P0?:$i$Hm8E*2K?jFT郆zse*J;n#*98DѱVpbB` @HR7m,UI)_cpAiw#==@995"*2Gހ"T9w1AAڥ%+o/*(9_H-6Hyj2r)ASaH?|b4u_qZ};ox cvUz `}IR]r<{ڙ3`ӿL g#֞`z^)d`{.\qzMy;9CsO8a'= P̹!yUWz8Z+n p1n Uֹ7W![M1g]}3=^'#9~s[JBvڭpqӽ]1G!th;'$uNz˚.+q%n*PާpGIj؆Y*`W?BC< }yQԯv#Vfl-$ۡ"Po NF20pA>KCm?1)uE ᜃ.pA? m#0cqǥ-Ip |Nԓd{ycP3f7Vb<`1=T!%:19 ?^-njG:BibnBQF[zDR²ef=9H&2m-=VV0Ǿ cpA=>Ƚ38^\Gt 7(q6h]ves~SG_T6+H C`O5 Ip鼰Gӎ8⶧BoOީ1*~=t)hI9`sLxUeiy tR)pq`ؠѳ*.ݬ \~*~GhJɅSA^߿N*[&tR^ui4Evm1!R9 01LE 1mO_+#Gj@mSAY3W|P"*Xg<Ԉ$ˌ~}#BeL}})QOCIH,+}*VC19"F$lʍ_*dm=.,v\cy$N:Px(ne X#ҕŽݲrjt+҈>Nv b4Dq ʣzS9'>!,8.?!b#]7/9ˌB,Ŷ>RCpp=qިDW99&b#HX/Ԓ+8cgq=8{\8o6y<OJ0?=*NLv =}Nw}3<ǜ>Aق>J[mbM(97vS|yȨ]r2NO#Qǿp냞hLBprI#ޓnhcs'ǥ;e##iOF6eA#냊b#(ZsH+E.$LxI8;x9i})`3k7T)r1V&ޣң)$DRx#ҴL6K&TtoG(j#n*HWIJQ`2#tfOj T+n})Y[Fxւver O'Ҭ\`!E8$nϥ;؂Ydnc|Hnko w,|nq+``sJB9qR3x?ZLɰрp3L czB:wET.IPxGgpqf|8G}{ARjHm `7^N=~r)ʜd4 I`dsDLc.uZp9N:k7,ln#:\ʨ&-3mO㏩Luiwg+;VkiʔM[Ƌ mZ%dg\#q$bM4NI sib-R0>(`u^iqAQEc)y$ЫJet<- P6- vOi#A`)]ɦH2n01)^c HElq?TqҒ4EBލ)`sN @8'8⟃M=r>C ~I=OW)%~G3]eLҮ>2fV#cXԪmJs5V#|6l+]K)GCrԞ{ {bffzqeii\rMI=h Pn'Tr0i}$ w.:n۟ʆXssOHpك,0F$҄%z*U *7N3"!1 c<&۸ twDIXGOƋb* t(8?J\_<2ր܅z#=)K0q,+|i3AS_ZO#pj_'?ϥ>B!ЃӷlzqܯO #,Hpø8|gvP ͎?iIy6pGOr8${'Xcs{U1Uk3qz?{o՗\){C$ c#J M!-k*YHYϭ p0P~VGhNߘg==Md=[ƸlH <L-Y@~;a|)8Fy{*e8yX*>XGgTb0Fܐ>yA0K0lv▷ 9^ߴHGHN9=i$8`3-$* sѰՌeUniN0#>XmAT!g9ڠG~4LmmnߝMȻgg5 vy$[ڬKpF{8ƱGrlw&zdJW0*ApTt9۱bX1-];+?<*G G$jSuenv5q2+Q6S$b13`0)ǿQiS#d@9Y*vB8zUty`{Wtby)#IiP~U餆!0cp >è$jDK4`>s3Ǟ{ \*?#OSS[yZ ڡNFCAPO-,F#̿.<+OOfY`Ϲ@U.ՆaPAV.Gsc'&FF6=88䏧 4H8^8?ldfv U 3}戌jh=8=9s.Km -_ӯ#/3 =qYdءTcA,NU+=GE$R3mǮG:jm U\Q\oǾGJb 2@}=BTV!^~?=%\FPrOJdAI uΝNms:do 1ڝf# w?u(QIq֗jiۏh;+Fey~S62qEOi1>n^b &w#e=xT"Bqs+=q.pT  ]R {L6 gm ztJiH;zH2APX0{q#w^5t.=;=3_HN?(0#~8 z .~S<2@fF3PzQHLC Q3"GPp1%@JG#\'r=OΖE,דe9ܖp@q-IAV[׏ښ$uRUF G=h0 ~#dW z{MtUe,FW8i61pF:z*r6  }ږYxgڋ"J@5Apv1T^p{R32#iȌ4z*ibpO'7 NH#MI@$Bdb,WpJ8 38à،DCJ0×|=1F8.T8G$`1`HRoˌԵ#N7vPv|0zgҬ̱`h}Cu{SNM `bX gb6qzTp$0qa!xǵH,-p~G+Jg30qMpNzzР/;r=;h:6 &0HK*=x #֢|JG?Ly8++M%Goq֌Im Y\{]\ 29؊Ffhv!FrTw*E&\9l"w\uI\sI hEM"C1 >ʶsQ+Ԍv NϸiF8V 0A9аHϹv3?/gC"9$KuSZ5S8aEFWGa(K"N;vn1~ý!,o^a &v-dn`cu!9F9LU>}q8ϧ!c1S [#21S^8})Y`G=iG5B6Ү8)"@<}?CNIɻry1!Xbesvzc crj E,f9|Fl&sTaTN3SJ2$)${U7fi2qP\:K3<1GmH٘bOj\gAB8g˾9,Oq d)17Olj: >2y'..`0=1!A~֚߅Gd~TT zLSQ_.F:O  "4č#UQAC`2\:j2Fåd<;!UI8>ߞFE4}N^I=ǖV$ev78'ry}#SuwV`A@;w*:-MHhft+32+cT(>jt9#vbD3MOAsVbU{9AX^ZVحchɆ!-oNukyKB,=}I[E;NCA]v8֋ bmC+7f ͨ7 "'qc_ZkypA<H%qLUX.揎}>hcy )4IOXh搎b4wF;&(v&6қ Ip=;TEmˍ `zT8 ^[!S"P@8֑"ACr@S(q\]@m*x>҈@ 㿥J28$wcJO^8 iǵ=vd?DY=zjF:d `8Vde8dwu9bRsEƥ}#AfvVz*@) HnV=F؜&@lԃ>Ke;$ `z}̨ۂ'8ןҨ]1`W8#'8=ǵ-ĝ1 0v!rF =?d\Msˇ {cj,hvdֱH$dBc4%הJ;39 9gwb6n+F>e=q?Jg _0N'w*nMfdT,)77O=\ѬbFr~:cBky#_IgQB u9fd [_6h1m0l(:{+M,½]jzW-IǕkUO4KX}ܒ.pQL)5/kwX[H |ZNjU%.Z7߻OL>lt8!@9֤pJ.`M;|C*aʭ >d#{lm$x2.~0+7"躌…Y,O^G\PtQvG=6F6럻hΜ# ,T/q@e v{ޢf,sS!W˄Ȳ0콿OH|ЬN7N{ҥ`;a8,:z~_j6'rӷ=Q?S=~߃9?bI90;b"h$_/ ?ZYCzs| L7?#v{ОFc1fͤ}L -+ r,Bž"Uf s\}1};ҌaI#Pb0p:ۂZ;㞔θz_$z(8H=ZxQԁn*q"nF@FW8!ԻIb rzړ`LL+qIH':]>~oT[qs֒dV pK9`Lr t=z&ѐ=G,W+ӯlR9JyRIRN9@Av1fT WA8';ҟ "A>)\pBG/Â4FNzA3mdz;4L1R}{y' hySƣeUa率 M_Q^ F'#<_J\"pE1:S8MI?+~ sRFG1/#j8Ob琰*ǥCp?'4$vɧCv|[,=N?!S*vL F:zTNVY|̌ ?pRO#li7|d}*<=}]=&9 = \ Jy7P*?-Rʲsj}bv'Fcm# R2su#jN8$41aӥZ_=Ɯ1P32?ZWWrR=֌AlF*Ơsb`p{wm;G)T݊tD[raAHm"w*>\6Ld { T@Ng9=P(S2v9֚Tw?Үv";sKrb) acdΤr1sN|aT1ޕQ`pPI#`Xd`g!`8b ~"S"3J?1a,K <>I=*l p@}(XuaţZEzRD?Տ\:U9_n{?XeHJ:+dP R72;U{=~%h-J4)>R/ G$\]*8=˟]ZvโWy ZGfjI}ke)3\Z.,ǎ=3ܓX7wR_jG9"љ F@ի;kr;Dww9 +HM}s(0L$#w+34pC431hN?Jܶ-ix$H9$OM7PzqZf4\Lk۟}*Cn#1H_GQh(Oi JRP+b:&r00zS espHG)szxV䃁ކɋac +u'𠑓ǥ~;˜ZȷRPr=hiR9cN"z{S| >cG?J>Tʱ<׊>ZK+EG3jAUbC j`̪^I#fݕ`ݎN3%KrU*z+pS-G8{U k!cW}j[I'ݴ|۸+Qr.fe|~PIT=G=TU@=KbYm]R߄#+|uj[, k$v8^reٙg=K}(Az:9♍j@ ^:2F@wt#&9Z% 9L7/z*kI$nȻ '~4N$) c !ۍq;zsH~#Ն=Jojv={d9 TU ,u{:|TB=+;h%Gσe:``u,xSӰ3qVlG/FS`/I`t]Fr0Щ9Wgfaп4ٽ Ȅ `rI*˂@w.A,\2`>*wv#?NQᔌi퐹-idVC!0h19<p>wd3Jṕhe(^~C#o\:QZss1>֡8ف^I"=sHQA {V.8O"9 7#{ J Ҙۑ Dׯ7H=*@s ݏ[48Z~>i&A#RiA>H=g0i!&26A?ԒN=ipzv4Q7/IZ4B~dc*pHi b2<. Ň$qi\g8c'CLf2 #T۞}i na2sw!U8Qzq3)%E== '{qAK(?L:RHoڞc'FEϵ+9 zSH<?J@9U$8!N>#q-Ԃ%<1qy- 8ϱ⚪9!{3¤ۅ)6 DK `˸c~ p mGcd~&c@Dr ni$"%֤3#P ĜPTo?M󃷮GQO(+r:{vWTIsϯ12?ʆmsjF&mPS #6?ϭ7? y6݇JhTYA?y#R@ 0 (+F-dzzdlR8;53.GGb,<շM8S=fIcX٘ƄE99@A\T5!_= gPIqiw ۞AI2Jhg'S-:EpU wPy`AGZFmnOE\GP@ @=_JA49A$|wPCN:m;*@s:B#1N29=vtp35$)ly|ҽDɜEr=V)rAшGH AޝaҤ$Sl:v֐l sS {SC1N̓M)<H@rHRlcZ< qΕ_QE2H"*#=AP.{vV!ق"a+{TrܞdEb,8ԇ2C dEv>`Ff5{ NJ;ˏۊЁU3*t3 W~ )dD^{tn ݻ}rzw8/K7ӞJȔ l[=D:].[k@?Ϝc8jsf[ޥ[ ,2wz{T&wM}Rlhd->I<|7M=W[`3%$ʪzckY4Z|k: yȪvrM&m#?{SIec ֖%E `8m&{s18Jkj vW>ޔ(l6pZ*{БJGՊǹ})TOJ=RU8Gz}( #~TAx\ 6j h9''?)0hq3SmN zr#fwpYڧ8SJq@UHcjBOjp[2(iU2Ns YdIVTl?PRw\6B@k~YH=J݄s*vl6lzց HBxwqX( ǠՒbrLXe,T $ʯ:@*'ڟ I0Vx?53.ܩQ@c#0O'\~TrB?(#>tQL[=s@q`:|hňA7X+@9$8,rCy$HrHPyfW\cSϷ.0ƻzg<>wi"b:@$nn9J0,r=qzyt.SySG99RFBrqP4$9žHRJ YO8+rr1 r?CRcLS]G XۧTXv˶X9>吗98&rrR ǡ=w$s d ~r͖?r}4JzefqVN0*5r\zgZ˹YD:fMc$~R`HzHLl=;Jj"A 9MX8qO ( 5pN[?Js,>}=_j{sg5"Cn>r<r{cD%r鴜pHXt%u lOw5Z%dm=r㓖E|p{9ܞ"=*:gHGGoj@CjPM2F2Fx FFkr00}/6>2(80tr =zs{wx=*`<28t=6 HI@9S _HF)Pds!6M+@ i߇4bސ>8:ƕjR p(S҂(@Qޔh)׎)1M7u㱤OzRGlv&O h&-$ c\#!tcӆ˓r.:ѷG){P)3?*]:朠炿BC@\f\Q8Ws!€rHRHIJW ezR05?7# &U{T.x1W]*23(LOH2k"J䃐;b4 6ପ!Ydzv#Nqb B?cR3 I;UaN99MD0?@_HAe<[.j5ٰ @c֘&@Sp4o0NQ NAn|N:?0}F`#(.a 8 ~IryX˖ x8=T '=22n.O9gS Qz}L4kr~ׯIvHԘ~HCԑJ\&/"]}yjE㍹<Zsjp q`g؀$kCfa֋$T I6by?Vb!C!9F$PK?W2hyReqA ǧY(ҴNLz8ɡTkSMC*gp0i P<b¼Zt&pL}÷JݓNQҭ#ue1y'4pOF1NA3ЎSV/G#֔ mA4vEb\XI9x?i#Py_~x&vWl>iB7dq^[d(RɹO*yƔ/|:L@qޝ rTrs81E` ;$1S t ,q灊 H=ZRIEn,?,|HCtpH֦ݷXE,{*` o~tpsLCpXx)X)8;}i0AZ`!)~i 76⤜q!be~F َ9tV*8?H=#ǯRI{1E00epI)p)cv֋@Dvx+О)@bTc''pœ4$`9}*n-m@771›KnASӁFäض$Sy".91=yԗSn%29a*\"4%X[]e 񴌃a?E`^+X6џ׬=GP\k9 1G;D]{g[(,R`8l}>$A䉨6o<&aA_jڥն"|BPUG9/ cAJ9$*%?t9SȀPǦ3Z "X? 8?Ґ+66$`]>1ׂFyH,!C#8h(`GZB0G?җh, c#??%)L*Bg=(zzRo&@?7ӷ\QԞix> ) (O^G?AЩd3e9=nQH zym`A"%*RJ0=40PeqO^Gl})@ &;zS$%ͽWDV)hFEWVe;µ|䴗瑷;~?NB`,A85)s=SZINnG+Uce-3?Zg(㹤r1RYͦ/ Ց{cZ&}uuN"3A~wyG@ڦJOjmB;u;yZ9,G9[j(ĝsN*km= ܲ^Ź'$~H,FerC _tՔI w=y& 55cN:ҘʒA%f[-4b'lDE T}?k5̓Eu| QcՄ [I=Ab+cqx$㹦SM<==i!t#?ZbӐ3Ca{PD 1ޜG#𧎴c=RczRbғo8bi'߭;aIO@ ǵ/.8R0Spqҟxҗz1ޟzQ< f1JzOh >ROZ0 Mp |際x9Pi\dA*zvO\m8.=QJ?DJW #QO#=!D)3Ҧy>& 㡦lϵ#|a@pO?fAm)1(!Ni)3 f71Q$8#DўFO> c4Mcǰ~b7g~ UC!sz#M˸y9>G֢,— *:u^?ZlNxq|F9?JtI$ Y#\9HhaAFn xdvۚ+x&y;cdw {S<;UN2Xw5H\"#$<gwQ7 wc??ϭ,FՐ7@Ym ns e cã+ ɦ"nG*Wӡpwt`zKmM(C_X#$Nլ&ڤnA1;6>0~u~ wCcV&8v\5ߜp)<(c2K- 84#6jB |(8ZDds~CO6ch+aDlr}Ȩt8wS*6ށ\iȌxHOB?DvmyL4zVAr+t<#a)9)QHFO?8= `ǥLT C0<jڬ9ʑ3zWmU7U֑!S%XF;a?Y+R`=O6-Ee*dvp6?җ,p#7@~S@Wq8zPޙ]) POZbI9= %@s?ҁ Uz2rImE4FS2)! SV9ZlǾR,g{Ν0p+vs\Χ(ئY? Ұĺޅ_H?+C;#$g`9S\M!*7Ip;c4KcuǧN*rMKc7!ř,NI>OBH'ZL ޕ$j%푺>Gڹ p#S]eZ 8$}sV \I4I嬜8DʊhDlVs^ap}ȪJp:ԌwMzM L/꯫v3:A pm''^YO4MȠB}WZʹ70̡l+z ͹mRFӏ^5:W9>UdUH}@1v=( 9>2;`*ǿ_!(=p#b 8NcwH#z4(lϵ <\E.XJ."28he8-R ۚtm"en?#"SH8\RsG[$v#ib,x=!P[Ҧ(BqQ}$z11" =sSJ`t 5ۑО?LV ?|0?QG^(R1Svg?P(DL/,rG #N''?֓yj TfPYM1 Kw!1%Xp@?΁ 4 M#C>|{})[F>nNhnց AA<0@mHZs*NMಆp߈ C(*랔1ZKs2 4Io+G222z$xeYcfYYO Q$+,rM-oX4֦ 0rqFNǯzb6Nғ'oGOnڰϙxJ~+!TJC J ?Jx@N11:zP{HbOH'FAꧢ=i W$q@>|888=zUYmFݽ8cĚ4*˶B2qX|F_ϒF2L{tǹ5(Yxځڙ9yϙ4ʮl^kmyYPj6$sUʟ_ʩwI ͣCsW,;RdE^.bdgҟ`=[W"0(:RAh˵YK3di1Ҟ899liat1:P˝Z\$qB(Q)3ҀXF>p0XԜ0*D\ x,7I83=鄀0hq F́׊VF=d`c(qB3N'4n>*rQMF8? #6UF:-6I@ QHGbP1<jeN@E".*Rč PqHE;F:L))ԘQjp 7`4\ v+LzC̩:d Lngԅ=h9A^zLi,I'4ݾy M$ [nx4A\qiXoRscs)9*C@h0@({}7"bO ֜à# ubQcҟ ݩ@@|x"/+ʚMY V\=hd:R5ǘ9T 9u{TNrTpJ>]Kt#,߭Bۃ3OJqvIyuJ U1Am@xT|;T 3jR1t"G˞y'hp2珯=[ ;?:bOL Aܑۖ WṭSGܑ)׵1cd6j[Anw}<<ƌyb1{u*_jbqY׺GUA;`h7y  gҡi\}׏3gOv+hٜ??y\ͦZ0{J Jq7{wolgt҄va'@R?ZəY奕;}Xi52uC/>"f-&q"}}>ee8"-} qk=R._M}6?-Y0[H:>];ďұ4SF|ooM *+ȵZFwnH9ީi4YZBU7VT?S77,wq,a*zy ҙbEuw[s[1w~kPdӰt2RKfzݯĽ䄸~HèPVIMdaI*yEA yGnc@ ӽ(g4PҀ3Fih=i1S=q֐niOG0hHIS1@>ϡЃm}߯OTꧣ;-ӊ07 ✥$]YXFSa=( qƑOAL>[>pz4c`w悠ʍi 7JVU iq#pF8!WtJW~U5ȾvV>oET|Z l۞{sHNA?\Q.y4aϽI{dTG'{X͸?ǽck,m< /#W }=֧t]xQ=(lM#yk hy{3|?sWZ6빉Nȃ ?j @ "`*nٓmrJp>* #4`O4Q3c<RmHc \ݷT&xOrieYtqԓL9+#Q35)$1MtHr =0T}j[b(@2_qē AxW¹DOODtg.Ϥ[",Dr\RFCNzHs~eTqX\"D u$&I"?vHpok= ;5!MʼnI<g)NR4Dcm |qOǥ#B@`GA +Ў?ȁnW 1&Q.AOsJ]󜓌dJURʼn8?&99})t<@C'`F:ԁ@> `s49Ff\6s?Қx(3BЛT0#<ja݌/΄&W@~qF9i~lRsT"-$wgƥۓ ߭𠏗8 {>$֓'R2☆0CLS2~Tq(= 9#ڝ2ElB0G=QbAR0(@#ԡGaG~Е䒻7ontW 1ԜI'CH6Imav?GǨr>zMGŚ'ڵ)C 9vƍ2ܫRskUH"NoX6vz9WͳܮۋǤVayݔoqܒvT{!}iv>Qq ^"˃UQ/7RWdwfՎI]<P3@m0 yCc@c I~i':ib c4 Ҁqhҁ; ;?qڎc34@#'4E$1P25#pnzLa׽0֓=Z?J\yށSdd Et4v S{xҀۀ*YXg~,8zR;ߵ49#֝! p{)@)! 'YYOavlx38F}+U9V:ⴟv$omw?|Oq.%]ā\f(Uʈn]^uR r =)p?4\kI<瑂띸΃Iq"~"CtЛKs J ?f< n|%[ '97aGO5xS-ɴqSؙM#|WY#v쏦}ڹ Oė(P5*@{Qs6;~Zp{ xHJpւOJ0~d(PsTv;T֪IʒsjXU_ZHn* )cv^wn̍bZ<7נYL']#۽q@;2(um$jHU.>h^z{}Om|A,Kd#'ҫ}סn+hJc'?j~\b& 0G*Mw6=+s,zO4a-x$r2:$6}z*pA/{#J嵛4Ph 4䄙>tʻǀ}?K˭6c-̐HznPxas\N˿c?ʰP6d4Y΁5U6iXq׵tgxV@>?deeWqTKo2\[Lʣ6EZ\=86kr>} {l~?07㿍Utt;O Lri6-gt51 :gPG*4m'<ŋ r3IϨw$lfRv=@O ᑚ3{cI8<< Oʋk1*W<meHާpI,Fx-Ҁd@s  ޝӏZ.+ ېsS R͝Iڋ{sҸ֧1Ǯ=GJrN;sN=)@R8SJ8ɣa#N9TxrGZ@Ǡ ]88﷭"gPE!mr;QNd n'9X <SJ|=}wb>l^⼐zc!4*w09O!=>L8!}h#iJҹv71ǡ=M$eWvQd c ӊ-tPZqePNv qh 1K냓ڜ:(#𠌜皔(4:tp:\G9Lu Os71_pyƵ$؊fBFD`ۚ n̽2Y-Xc!B?TxJ-L˻Ӵ=+k]K&7H83&w>kh2]=TS 91ʩ:1 <{y.r^I$#>@NN[&Zy*&HAsVF3})oʂ?4fqH͎ #n~UsR91\1xHPɨ#rjC IޤtZtRbOD0)1KO%!mRIn)qKI@%0Q@jLR@ jLg?u%ccrړq!V'KIydI#r~u"Wi+xzdMBe&;W8AS$xfQ!2M4,۷`g<y{scbE0 %m;s֛8x=^9<(3(N&:? @[sRHS@ѹGOiWy`:W ߈Q{(>owҚMLxM՞\Ū_%}I oX#q0)Ǯ )p{R 7o.9)PA@ȥ63PȄJ?Jv5N͊TL%֯xcvOK3@ m֗ S)Xq(2l\'eUJ`8#yO12:`dǨh"vAXxΞ1K@S lOJ=ZBIm1$zh^9IɧDHYQ׊n8'4qڂE~O\Rc9.#\c;=y(Te#?ҀZO3)_Ɛ[acF[ȧ$TG9ŽheՃu9V}jԇĚלvRlW7VАdn:wtlC0J;`^?F4ϚF<!@mޢy~\D^ߝ<ߎ*uyi6I+bGEʊyj*|yr`kFVy[@\L+~{{dܖ5 BjܺpHϽS~#Y76欑C,B 2s+״U*=qPj6u~GpL>jjsE3@YiXq 4Qm2K$I.vTl-m,|F԰S[\).?_Bv$o aҴtFjg 8qNXcgoz}j3.^}֖{\ڬ+W6Qso Ҡ1u>VWٛI#ֵ 9 j!1$`EBNc'֢lqXon@CI4*tӚ\`rM808ZMŴX%9GF*G+֫pa>湌&0 3z]b6~C~?vz0}FWZZv|Z]:&rb<s⌼(@Dž{ &3FI\F,Zv» +[Y\2IF~hД\ L(G@jW;cSpOAϯsUqXg2r=MOZ]g 8'WBpOI)a/x=)ǵ7ib#?!3R'#+VqO1I=@ 0~$yR<4E”gRuz  O;cN(O]zrI9>@Z0O'NLmpO@~Be?QL߷S]r~ llO޸96zc`#vՊ;2vޕ?5<]]N;?.O&㱼'u/KS~wC'r:j*y7&FxOv)+~! Z}+ʆ611둑kI.Pq88QWg\:fkbþ)ۧSL:4nQIW/%NiJTz}jl'4ԟ(V`gDVBi8wS^9y#r*!@昮9(#5 rOZksKO(\ugށJz&3HN&f#Q.{?@>&)ƌW 4S7 oPh.()hbsM>E-Pz@ Ac}:Ưkis_9j"W9ڋqrOЕKQuM^ I.m2F<QГ xf[j-wt@r']Vn`uk sN[:q=?W|k׾MщY n.2gA޽'H]4Qjoe#0V4#?s%MԷ=Ҋ H捹}* n›KցGn}Ӷԅ@< PN)G=p YvAb$2I*Rma%K,bE.EN^/Ʈc4vbI ,׀yUg:"шc\#CӃͪ\O?^,Tni6=UIu9%Fk b Y80[.GoBq\ MZCjHRrՐ잔sPZVFOsz0 R'fHO88:Uާ{Uho8b9Rw~ Vf'g5%=KʰiPbva*шH{/`OA΀מyh\yC1q@ M8<`[h{J(V0Sn##ۀO_9?q9~+ҁcCӱƐ(3Jc{Fp3tRܑi0yog$ $Upd !{z{ڣ"8^:սQ FVѯ;K#̅gێ唱]qm}+IIԅM14]'wE Jp<{B@)51\ޣ`z"4<ԅ:fr=)dS NJ`/HA1Mgڌp324WC('h^~5ILe@8/@%b7\%V7g0Z\5]sG^qto<p hOOO+[&[O,2ʓ_nAmr\8/?]wC O>뙳p.r0)tx7 >@hL@ 4:U)<ZM担H8 Ҧ(K QzqXԜ iCVmVpшn@ǰ6+oƛF:S52 q4G>sҔn8ǧ @aYA'QM9$`IE$q|H~ ' .J #E; m$xj23T͒9 W~\v4g5̫yrbf]}ϯyO%ԯ1@ I"CQwwmI$/ [r[0Y|WC+"O,F"TҘbݔIÎ3 F+&ՐQS>мIx6͸/* y vH+\d|þ'X%7 +ugVfԄѯ>MK!afmE=JsGԞjL6ɪJhG9?#޼V5/ݛF8Ǣ3ި3})Ɵre];L5j:swW9υA~r˝b֊):{1r~P 'ڥMFO?ykGͅg,%8.;3."' bw[Au*HpHgjZ0qSN2K+hP)g\P [>M i8 Ҡb g>ÊcԶlX$o8GAcY*1ӯֺ<,~UFWdJ6Fʁu89dGڎ#8>[r^;֝e@xzMQf߇ՅL>mM߾>0W8 ALTh5#ۻ##zM(V$nk/Lǚn]HHPSN0;P .ݱ $|vF;UUX>+m 2̇ʏ銆+ ^8!|ۣ1>NbV,ʌWnlixϲ;히'''quvZqXy*nW#I})6 p͎8xm!]D@=闗i@ 1UdLqCVE k6[[1AyگУ9EC?!@ZhmT45D\ܩc0.ϗc~|һMA% yqS%ܪɭ_2_ǩ{t3JՈ}Dj ,} qjIZ&Bw  ̖rc18韯򠭈W2&y>$zTR͜~48 } g-=z PNiB}jv4ETǷ DHI֤1I q*r<2#SnhIb8.EN:.~`(ޑhMj%-Yu*Q>1;0@>sOi w۫ cɗvOq NH?Vwrrzb*([*N֙'91DF>lkklhX+&BVSN5 P)i¢@-gУHht~=w 0'?^S[ *Fn?w~;v3[b=hbS#&eGY]pGuX듟(z23˜@?J.. 縚8aAF :r{uPCdsʘ|S̍y|y>SA88-D@4SKiqb#oj]rieF3Ux-kc< 8M5y yIYaطgyv3AE+]yu%[Sұ^;Zz}!JatQ5PF!vѸZ4~>iQ=k(b |DS\@h>߯5k_Ve# NR(#.}߭)_dR]'X ƊWdqgB{$KG`d'5imzKpHbQqҴ㔤h#˧M\Le2Dv9}?k.[Kq[wɭD@h:t.Tܙ )(y#Q"HjYveJch"(R1*/Nێ\N1Hn p(B'Zg2ةbRHMr|bX?0=Ȫd,}!=*@E<)=(8(O$3QO8SL8҄+2`sDrf` ~cq@m-R r  /zbȥ>l`]"PsBfsEO@) -n("I LRIސ)8' ~&O \_!i*=buFB{a sW4NJ;S^5Q}RWsMɏzay}ߌK{9[WjJ^Vz]VIS)=Uܻ@َj :ڟ ?,7AqH8dF Lzy0jDrsŠ$J21BZ]X3Hs1ꭻ9`r:{T8V[w {_-E~6^IH `T0iYq)Pz OhR=0{ҊP{vbl(5,V*VHWʈm@AVjIsҖnI#wIH8*HS)D怹vY *z@'+…Q) (9sL7h:F)<ԦQS > jE%T\Se,Q[BɄ_=hFTZkc}l^GS4("@Vn0=;V|4$Q{Sࢁ;n:Ԃh>qA @;~{Y#`n9hTTdPsN֍RA&dX(?)V'((U6B=PhHI,Ii*-M*]Ɲ㍥vPՉ@ž궿nb9OviV+sEk7Yk2;XO;+!`sG=/4V ;YUG'?&i6zbu]ڴ.mV' ==r;~5Vªyy~7O[hX-C䟩I]6͛$)ǹuW&[mۊڤ] i5\4q^^nT\xdi.z rPz]9Pin*G3j 0<q!H* a%i` *Ɍ֋9hlcpGS)_( JF8<#Vg0v')2+r+ԵK{9hFqЏ?ǵRC{}jѥL|9\C%GMNX Tg#kkSnm"\'fՍ)?JqJ E.-YMbFcPw'Ig{dm>:;l&{Ia劌qc?4M$vM */A@EQ/2P_h=3 [\MrFx_09.n'ڞ% f)VTCc85/m^۟?[K8YyeQzTzI"haJq&4WU!I:n2OnߍZpF$d8zJcXiL\_pY9ӯ8,6H{~(iz%1gy1ff?xw?:QbT*a@@R޽MQԒ8ĥA'PVųV<`ww'+ۭ8Hiv*/j0?J.]$Y"b)]CV~/cd+~P )׮k qb k[-4Gfxb.F ~)mSi~m ?$uQ'zVR9iVGR1Et KWyX\u~Y:QUVo\;cזZ^YL%̻pq T.m/lɲICnvO⸮r!4~2]|5ٹ 0p[%A?R3EٌiO׮ qU9dD(eVHn*߆YqWKy MJ6WA/LdQcAW_xI(n[F3H,u}VRIr]LҘ'aijsɪe,ъ3 ةOuȬ=fGc4ƃyH7ߟC@n ed#>*6^яb=2qwBb)ºxuEY91V/l\ۼ9t֯y0+A?/pA'&ˆQ c~G|{ӭE1 Bm&CIoՀ#-m9٘O-})LK!RDpm }:T dE,彙c)'%U=^RGHqFJ./:eYjA`A@=>!I d@{_~ n:w@QyIx^Ps@ 'O]*Ȕ}-rBYPi ;%?4W!0S)0(S4=)(4^k˹ xT¨aܘx&{V"N2 v_j}2p;;}=AA}ttD>iT .2OQak7g{hQq?T3):\˹X`ݖ }*ղlw =ɭ.C8PSjNNqrM=iPԎeӜc;` *H3dVh¦4.GQVm`TqP4HmhJ}󚴖Ga=karqsU\?ALv+M"#Ja.rx*XtVyGuqP!BEczy HI"3؏5rr1Z*>y57mۏZTolIJ5c%\ҀHh _Aux䙂(RyܒA=uP FΨWc*j6RBmGEs!j&fP+oX[sT9ص-,`qIjjA$ȅU_hpIJґM-@,׶wqۭX퀼$84S0-.A$s+uIt똥w)K.+x5(Qu OMpbGi]lIRicSq1^ utlc`zr~tv[b̫$wPRP.u)Uh>6搏bz~%:fxa_{:u ֝\S6~d]̲%vl@*O?A\1.z7<Ngib2 UI qSl$^DP?G5 =Ayj)ezUQژhRIH%ncz3GnK3`Np?Ito7v}+on}E~s/{f 괭F=TH]fH9ShFqX$tT{c]j4^l$` b ~{iOB#*XPL`k&}ْdRq9)?J V$qri!f':c>UmX 2NS@#VVlgAծ5&YKy0g cRi! : q-o3G+T9jREvGWPW TZei7;Upr2헒NT!s};VwԥvFQ60r?ǯ:S+}x5i:L]vUizZ^\qځ\ EDkR. ߟ˭jIu.B1)k1dt7wʍ^̥g訌T:?Ҳĉ!@cR죳\oֹ/j#;$S(} LA/lW_ 36q`[coLFXz OL`t{sӀaU䐑x :t2ᩏSzC}UN=qޮi]>[Kǀ~^A[J@GGWH"IϷnSmn>2%$ 8MaȢ-}"ʯU؄F>`]٢|?^z{R`bU`Ds"c®`3֥#@h=*dpl+*# v=V ڙ&]ҤƲdxk0:t\ztnzj l ї,OL!4+.]<.P7?i,jw)i& "X1qw7 ȣ䰮1Qfx~bEZFR>^e{W]ҥ2H7zJu[ zd.ں)TGX:ÇLWBR8*!bRJ?xT~j @#׊|ptU?]ԣH08ץ. ~xi:(bL{S$jȺe]Cӵ{*4vѢjsM[^8I#F?u[Z$BB1qt뫙a1^# `#cC ؂#t` gʰ`i#W!N?vڅHXً}rQ\]͂AolQ$4٩׸Xea;@q{momp zc?үʪ;cYHqޥ4T".NrG?ULmvBA~E ],1'ס0\lwn9TJ%)i_-ݙ~(x?}G_κMV:E\S㞸~5 j25\ W;Qim0Q׸NY3{VUH``ʍܜsj`wֆQmT~5ux $Eqנl.X|Iܖq>%%*- zT>Q82.Vi$wf,XI9'[ K8Py5+Y-"Ocsu Lby >yg~kWiQ ڡuvZZ}5à2}sS2;Ozךr݅װ̈;Ү8kHۓǵj+79 '=jeNaKs'|.&20x!m'sڄZP"JvDpA=:yR0F ~~7t^֢ⳅƃ,}*#nA\"9n:P,Ht+Sm2q: o%-Dmv ǧv1bS9 )=faxKmJ8\i)WDvs*ewrr+XR]>(`R9׽-#HN"I8dW$k#T+ p>mBA[=|$+ĻbgT ʃ`QNf~tr[* 8ԒnICp"Nq׏JTi&lW,%A~1]t/IyJ,"=!ERfɤiM!a_x+Hұo.ᦐB{i+Yhtm3u$U?-ջ+-;oðzSϩ3H]¯͎Q=rNg(,n$}sҩjIw1Ql:P}O<{ҳl]=h#((?4mWP"Q#IF*>if0x3}яR}^+Ky'] 69?#i$}qLt4P6ڧݿ* h~ˍIA?jn2Ċ{ cد}~qPA; D6?=_n]W$F<|N$`枡]J0OPEBdHݧ4 ("#=F#MxrRUuyLʴ+_i֖#9p8_J]Fb1^8%-4)" [9UEPE` N={f`Zv&&/bb<(=0{~f+dA ZƑL9X [d?*u<@ P O#E8$cbbt4p]@$vr 0~߅la>J"o\*@'JorG( *=RԉFȆEݕ̣=qZ'dϟlR}gǶ)HBqϽ$I%ݚZ"L؏ƯmoK%A^'gF*GQ#!#2gzh]ԗANGJ.lmrr[70:MRIg.w=-%G!Wy ٘$\[,zM. ݄2QDZU-^6w2]bӲCQ ܣ{A$WVDQ7mzq7zv/nnf`IlR9V_qQšRqs."K?JnwZz30+n.ź@1 GW^m'PoVG,F$+l#Tz֝vCMR*Q9F*$^?Sd;خG''%G"TJ t3U7'?^sڱ-7rOҴ`0uZ hpNv:Q'}@F@j6sΪF`~U#Ǖc9?eݳI+yxT`ޕ :tޫZq(AV.u9 2ZTT$&⩭̯!%Cmk+4n2pˏkڒ_ڤɀO \EO8QdO?[>F+(\sRSZ\U R``k#XH7ܤZP]̆,*yd9) 2JVvE*\̸}]aKYLv,?Nj͵UV#l1Jڅ\ (5''lcJfl˒7z޺MEl{YM{n5ո:ʥQcf )}& BGsAP"ԭΚh]gWcǽtg돮j`~ ᤙ+/4/,}?ƶl/EIT}&5> :;i ʎX؎ހ0{QZD/4kl݉. Hp4˹wHcǥB 9 <)$\1 ;MFXƗpSQ)2s6Kjż;K#=d7Df'uh}ݵN{Zi OiBcyD;1s~U7SeHy\ZZf+J|@ |L\ęzv#2fjZ_[:F㿽i +1fa>cި 2eueenjAmqNM$(2:bT;=E{qI5/!wJWҚS (4⾔m})Q4:08QM .џƗh8BzLS^boJ0Nw18rHv4!*0u( }}0(Q$/jV1Ɨ'}?!O@ H-qLfٌq@X-OsOՁv@Fg<&1b |}M/6K~T+侽P$?:+i#s*[Y @Xg{ҘiJ*ƥimvIF` 񞝨iԱgQ<`oqf\ҲOߤ.8Gđۙfq`=*(5V)FA =ӣ`7"Gu.X&D2*XǂQwC.ю5:H#*{3E}ź FR2xJna/xu,W0?΢*7cWR;\IS#bz0@UoZW=ˠǜv~Q?*Vcҹ=%!ڬu=fLG3Qt*+hTN7>A.@՛Za"V=y0 vX;֤Ut[Mk F mmf#ybg),-^hafJIoۢx 5TI `0PM.G=V [ cpG[5k$iAb!e!ӥ&P:-THxx8A"ޣ׊i0z91X.Hc#j7A[jqRrJm''?OGv ]wk"fĊBkBlTgГbrKslfaw#vu$|O\x\{鄋lI:n<s^4{(Yиu_%wp^k%`m;~UڳNmww"9! cly!ؘPZCӚh$1،ɮ&x m9O¯K$4-yu1IbTpn:>ث.r>l񬛹,ZW{8 n\`YomtXq}yI= Z#ͼD;OӹX6EFAOsWy!vݐ?rxҽ̂Y$VY!F:=5D/ ʭszvfi1BK cc?izisƯw0皋 "q'VL n]p~=;ꮖbMv§/e-H{TZt/ MqԞQ: iqVȷIb1OQ?4w3y#0LrG :$<)bS,z='رYa=Yph6q3.zlHf'ژķa]$چZ$G\!9={7rsKe NU`~tMȖIf=I ܦæj,Ooϧjл)X?jZƠ=N;}iLacfW8p\޹NҧIn#Е/c?:WjF6.11ڣps±V0FO? 2[ n}Ef OC'֥fS &#q@:)sKu8IA# $=U}iIǥ8/֙$dH6ZgHUJP~4#tIB)`=eP@QI`#O҅P GO_ZԡHxh#Br(O{ #kKg,>@b*~uYx9\,Kր1QZepƣF8ߕa5O9U`}7) WCVVڊ2IX~aK0'a#wxEp:ܛ15^{YDJ<.t>Vn:ymkp\ϰ<ۍA W(s9fv%OsJuʶOqOE笁KuAc#51aG3}GĀߌzf#,v|?\V=͖;1j1NY8ӎk(xb-cs+ʊ, |i%w1bf;Kq ɲWp`c<z[飊Ka+NJgp9*ⲆAJ3ڋ,90NA}r3 \@R7<$#@<}=h$zSY@0pGpr:S`\ ԇ'?)Ēz`T\OLuqOb0Y=M,n%(`e%Y.$#%o $KrT{+ˑ qtSS~c֩Jĸ܏e<l9$tj*݅όycӥM+ṂyV5Xs_d8 l45|˨\V[{k{*)8pv;w}+#1mq*c}J2r<#^*IQ}F?"{T2_O|2;LRv;˜>$ӜNB6WC)vI0&rFsH,,Z.1W4/d}gOJ7NdOx#vy?RN7uT$`}jNTzT| 5 a9wL"pp` c{Rx${`pb@ǵ.FH*8CP>79՛ $/#UP@^=iWLEFiE{"oEV3E<)Q](ykPʪ'p2kVx)*uy茬W= 5C!$8hdA:Hͷʥ?gyYU%!폭jesZ¨%DAU{;9.XHaԁU mnb<̞9 348zq?EBg~ $f[FdVyL݂;~nA"Ieb9#@ iT [nVe?) מ)HP7Wm`1bHӹQnF>S˪qN֘_MT؊r32m'ST[;)7mLuϭ2PEi,HQ#Ӭ`I^\会 p:5y"8c7cj|ȑ4"#aINh,$'8zSNIo~UKd:TY[|?Y\wl[і=Q ) #O21SF'hB*>,hJqsZ 2z̤gOF [{6$ϔ=;\TGb0UHP!e(U*1C gMCw1+(N]8hQXF&p*YzEm8U[ֆ[ qShd5nnl+FYD@pGsjkiYQr0l',: Q%!>S8j3ަBFrInU<杄zv%U\ƍkJsV3zdvN iwcw28%}=4fQϵDOCߥ9I'B&#GF9)6(Lp4`dZqzP 986{q@G8\PzQQʀqր R}h9{1jbqRb# S¡#xEbm!d9t~PG*N ʜv+U5KaGb7y6稭oz 砮_7a FTp352vCJKj[\HI*?aiO*[c53ݼV9'=+u-͕˛y|FIHv&K䙏1ߥ2ߔ&0x?œ~\5YN && >wCtF9XR)j3i#"1 kd_Ep=#?>+vBrH}5W_f]pg[[ɭ/DF8=Z6o I$w,KOֲ~{s8zF$D]mFc.AWQqҸ]N %~qn-x!vUaTjm$&/v,=st>#!ҭ!2]‘G=kS&;jh꺬$Sh_Josq P j<|UF08=zһc WVWu mۨPmUn=9q8BՃ#L;%E4Pn:bt˫[=p}ތvzd9p 5?14oR?6qV, |6k%$As8,sCXu֒AL ێ=ºGR|\1#pZv;X*\ >ݫfq4#X2q#S//YLf,VЮL6 {JWiU HEk*KpF1S}GmK{Vbʾ|@OPD`8}۲=j2DH)7qsGB&ImdLpN=2>渤ʑ)2b+ZgL Ա(So+Oˁ_T}J@ =*8xBraQsކ X$T~UG4;Xi?,j3=U14RvҞi 4%Hju&q]=B@,u6 \&i7Dބ\.?.[Z# vq?a?3\[T@b5acO0n4oZ TrCbR=|?ʐ& H> ;#̶)yè\j[̭L\[.ՅrqUH؅y$?G}ϥl\4ƻR̓`{cueέ_ xC0qړ@@W.XyQ*+#nŹb%931"DbTwc9α!HI1-6-oF =Tu$6MCϿAWFke4# Ay{4ݻH0` q*^GRͷ(Rv>SnO*3+!w ': DG""%|`+MY){hyᐐdPW$3M w٬,+-Ĺmqjw`q=@\%ZG%"c-+F9u}32"Ag B#@Ssm\Ơ e#מybyE6OǽIi;}iOE ?0 ˾dGVX[I1W.n&XKCi \)8O5\ܹ'PLh63XՠN˰$}ꝯnm`ߵ-w>ŒdqҪsRcC368KfP5nqH0H>Ģ<rӯ>(J.w@AOQ1i`LR #Y8j6ur?/n ӂyoSNx$ydbgs=*ö& 6=F3kԼ@Pmgv nAktl'f1d+~\x5֦G${Py#>)&;uMitaEgs?s7js"uxM7UČReLO~LuKZWEmdʒrJ8'k(?U S}9>(I<& NB60>/AތqL}(b?F1J>Crpyb41GZ|?ZV 7 +LGe=2)>Fy["yW.~^:c'4 4ᒤSTqx;q@v4&!'4 ~tܒp:wu8 I \!Eԁs؇8rh\n?{hd<0Ԅm6s@0SNNzzR><@8Wϴ{dxoE=q`2%ZJə jLኪm#Tx[(w]ۼ@|P~ 2?:+42Hydt:8#K| Υ~=S xyEI6N߁TrjH:95JkvO`@s5hE WmNz~5KRYKPUd(AEN֟uwqU//=1O )&*PRsTu=R,дτ8;[2LuRk.0Wb >J6һ,ZOp`$*2ߴ Gw#sUl\JvY `{~U~I.k gt0ƅRC:C,wU^($hѕTjr%& Q4Єxucv>ՙS20bdn@Tؤyδբ.wĉl8<~@~9KGrB4YOCUuCq5} Gte$Xm֥*K!.@T.@DnBU(bx5-I:%|)aWc=/[V&8Cߧaб ރz'!ʀ08rzk,s`1TIb5"E8Q6zTNq}g'nGEI' "F͆^r Ey[|l{Oˊ`XڝTCnU<+>d 46FqƸAm< Jx:FVFD\I(#đZj Q%x}~b()@q qX V:*|n W'&yt iffh[*Ǩ?/*\8crO]-ż]WC9~u WofLNxn W;l8{8 pOH|Oz"CU`>i b028擌uq`oy-e. 2:Ȍ~#E=L m,mj>\OHROMLo흂Ct~g+] %xXcB"2JO-[)DEUwŇI7[$(I_P[{h$qZ۬PU*vcp*M!sLsR*ɩ`g9cg8U%@\vH%xОņJ1#P+EnB $!w?֬ych E?yd+1ǖR!]Ӻ?X0pD#Em) C}q fY 1#0 uu$7Dy$Lw)DNPI$BO棞tRޤt$P=@,em{ blDJĨԤF$7aW)#ҡ_,3c8ZLpdc1LvԜԡrPš$)Fy 1u=)c&vM6wzl~8Pief#c*; $\T1spOA@h zG b1VSx&dye7^U?KsĎoVfQ*P?Btk1q!NpcC\a|ƉsUMC<U'P~fS7sNPR'\ Ч&CiǞp@={L*I wL5!n0Jzq1IO;PW4yHOݚd"U:+\ӑr昘7dւ=)pHԆ;7GgjPOJb(bCFMjӅo\R۴W ^2 )A]^bs֥Py*#=XۀyJ,Y^=ך?cMvpťNF,ăݟqG`b#֥K!%" ?ןVv"HbietPA=!SJ2t" qTX2T͋}G$;zvOE.02}h{;B uz$y6;8W7y^Hҡ#GG'^GO]LOTz͖ E}zhk -LdPObdjs0XQND'*ˌrsFI]nUs1(:Utd^R4q01ʝ4u, 6AN+?%e`G6 o~vF6S&CƒE_0s}y#m{kKhAOrs'?RK 9#A' `vv 5[PDܨn}kn_=r:[kY沊2ԞFKˌ@vArsǯP"YnJPuEq%m` kGARubrxU.\Qe;20i6NPr=*ؼ!=AF8_JW)}?Moa>?vrڭ[h\d3CN77[xRf=ߔ0PoPz<k&1A SJعo 6H|::o\V}6i10w M̝WYI>W21m̍׊{qg H6P:WR%gBTg{ԦE 8RB U5Tt!2.s!ʞ͓)1LEYf1jlSvqϽ-A3}1 '&qǽN.$읡N@'յM*9`#||UcU9i{Fzʹ[Y[j"$ *ΫƋ<V\j\9Y~[O62B-I~G5+-@0Jɑ?^]}PzYnbX(28jy+彁`pz ~~o5m$]:~IkDb# Uy0N:NWsd]+7sKm7KKWRwHXtWi*W"6lRx(aczV[]JPba$-JM,yqN?{}kA6@1W}y5iqQ~'daLq @=M7+#TO &lʛ#y? $WÂ=sL 79*23֕wzKc4#8I'tTu@ S889~AZI}-r zv zi}*c ;RCdڥT.N= FF>8'(ZR=iS c<7\S$ԡr # P6F'$؊s`#)&*I=:{рz{8 #9\{ӃHH)1=tR ۵* p4H8 #*ݜJ)ҹUɰ㏩`A$gHf!ANqQҥddQ@>rSiH8!Dg:C`ReÞ)N:Sl;ӃqvO1X$bJs7F*LJOQO$?6@s(#^}iwGzk.:bO5)9;XcyMP:PNhz)穤E$lZ-m m!@zoq!.f Ʋ|߅5X7484+NO^A81iHN4y8SܓKGZfpHfmG-K|NPF>9$ pޔ E$WAO^*dEulӥF )~>z̶ x8ǵI$>OE?i@NEқ&B#8~'—yvdb6zsAs׵ ޤpnG1`n2cH?J"cSڝ ר鑟i@AzbB CCU#O.-ZvD?px?2 ǯVc6Ƹm>;N;c#=1RˈF2jFm4k99i^( D 9Ǩ\49HVG`iRQjfJF\Vj9YIʭjќSu܏ʘpHkE8_ZPՍ"P9 S(Mb H4ץLj"'>}#Cp1^7lm w ¹1p}{{8 A5jZ˩kn5u ȌOE pK`wji9sBt9n%X$[ #or3j\#'-# \Z6_gr*}wQK׌Bf$k-RAsFk88?U ;ŴUI=(EGNz1v8֐ +R=}O 60~n!\rҜ1;s|vHmW=I!Nzg.0=!:5`÷9#?7n:Fx$r gӚCXPGCMCR{Tt'MS8'=5Cvژ94\,3>Ӈ˂>m7=)9'5;(?xc(p{MV jEoaM:PAޓ(Um Ne[9,@Ki-]`sL&IsH> xlLǽ2z4 :1^~8#P͜4 `=iAj`0{ v*z♰>b29AC,.mJzzG?ΜP9Pc+Cu ;gҜ}u$N 5Wkd 889FxFp' HIZsc1uHXW"u$'ҐXaXePK;E+ȵ61)W){zվѬh%U29 fHCwO&m-ˣԊF#`{oO5.(GEREu rҮw l5p02kOCoa6rq֦:¼1M-cA sqׯELHEUTp~u2bscQ}jXAdZOo;NxVLM m<qeO-$gFsZicq8iɕsև,돭78Phh[%3V.\ēJ#v4$7N2;M\RC"7=kCKy'+qGCGiEci#@rw#𪺅h60WAif52#F8wB9aW{b8s _k}1zl\]DL5+qԁ\G]X .!gp߮k%+3F{/Lco{HH7+q[r,r6s`WCTuD IeF7?0+'o۴IE,2o^aFʂLJ{ZlOU|{~5E,FkFƖ n>s^igh-SHm$~+m;KHۦu$U鷗"f&4F6Ruթ'ДQ9?ZQ#<_ªq2I+ }{ vSl'Wt@1^SnxdU9#8`’iw:H-#rX=V6ݝB;GvإqNrX Xُ|R_\Lϑad=}I+>vW)ܯ-Pbi%0/Yׯ] F r7wnub1TSH\JHXs GYH6 e,KOsޞUa֐1RƬI@=Zn6\bAISGZC yTh魂3ZsxC1 S\c|NYE&qNUu20HF>) ,K$E7d#t &=N*XUrFN03R2c x)-Xw08(HCۯqJ6 ( NT'AޓGw>P!1zWɷndv;ӛ#o=}) 4 ( }aԉ;ԲcO5HSޕ3K`ݐ9lr7dd֒єDFsQ (Iۥ !*d0#{5(*$߭(GKkj8S֞-FY5ebBH}cmԶ(I0gښ|A F{cKˉ2SUO6 O#4}%̱F,'|Ec|$,5FiOdXQ^^tӴ$3#5(22yuj͞9{BgҠIl9ݜVe ^FAbëm#'S,FQY0 y.j'<wos9O'{zs,أK Ys4dkzmfy<1j=lEK|VI/8YbNKfژ斷Cz`ѰlEcE0ڱ6'SHw(.'zVC͸n;_z2f 1#섃i'#J37,@Nw#sʴ#K`GV% :=(- 6X{ػp?Qxbl[idϸhncПZ$aCenA86ԧRh q`pG@i^@9z:Cw` R3@{S(iʛ ~sg*>x=iTgI;9~L.61ErdO9%F`B=I^P:)OQ"ŕYF9#ϥJA>LZ`dPNsng!}34$zbXحS*2P/|$=;ibnr`I7B@) pqH?om qW;jH&uxðI0A8S#*ݔqvu .qϥWTa\&NQ=@Lѡ)q8=ٸ,d  Si S~8$=irz ܁cNN㟨ґ4ƇSa\)9jgUKMǴb271)Aңfl)'R;w* Ȉ DCmÜL/AsSY g ?Jk "qz,E1gz}w*H |MjhPNh6g_MJέ`Sw=9jVR[j@ZAd$4Rz . ҥP\*/<0?6x51jXczЁd!HTg\3AoZdazz!F )1CЯc˜[ZBszRYqF@{1iTB$u/+g6H ݱzmá=_'qLٌ#+:TP9B?: 9cUrzhNO㏭=R16ޙE!9f3854w2}Kb$U&}}IkA22 ?Zh=zPZ;bƅ 3HNEJ1ːm#=#CkKI) >Ydmlq53ڦAn5TE"mHbq*>e~5:9O̼r0+ Mj(=5, my=_K{]1;rqkr*Kv :g ]M+ !4/|s:d3z>{>z'o,d`X&+oHH%*U5ؔ.,c#6֎NǎEΰn%Cv[-).bm`VzmdaI#. lI9 Zz[$(dHtt֖Z%մy[[c[[VҴFMFPdr<v@&6t}Ǧjd7:il&mgwMé?-֬1ٮ.-J75 $fN[G\Nfvڃ+[[Z3Aܟa3S~wkyr>?¹#ď{qX ֦j"֮2%M>]tז2Os-pU19cL8q؝][v;x;F#=}{E -)'R #bKe=PIW|X;}T=p 0Aqljqfz g~X $.:GZ=&dpjzϡF瞾e5 3+G{-),y#$նBͯ䘉 OjƚfSհG~Յk<~:5Emb^G*;ze5仕ن1֍2i$YH d1^_كI;6>—-cI}w#<UDҵofdUF !sJsxۊƗr WPյXtv aI<p z:^^Dw, ckSM^A! )Ibp>zd$҉ )q횯lVaZ\ðr'̤ZbiW@Zhf-lrHf$O+<8rI յu+9Z*HG#5oZR{I8 :zR08sO\*ï< a G]J`{qCrs3qdFI͌G vi20Iz QS#Z38)0A8Rm2H h w$l` }iJ<uOaM1  Zy!w1992Hc@1X|QGN(_pJj739Hu {܇𨺜y8&=(Za1BsH~x "H><GjnsOG׵=}=h}=*E݀:[VzdCuu"/W=I\qӎs+ æOk}qk#4R2!ꧨ)%lgX'd6!qIdhr1S"ϸ՟خrU{S٤hxd8PI ֛$*)2 ўc4ؑ,O:2HQ A< N t֝0B0Oz *#4x@=\l2Rds43S8h9 ={b9ޝ9ʦ v1 06Tc .xR$-{- 4\99 2A{*$/BfM m]ŸI65 JX=jYA$䌃ka=\fL{w <$h#?'tg=h恒.U${fvbs=ɧʃzR4qۏzEt$)飁q?Aӧ4\J]:i r:sqy^֞y47w4+GzyAȥ$i z,~dR# MRFB8&O 󞹦 '8zR(`!F(>P1?wϽ6GSBIF3)9ڕ 9TҀy)zt PFE:4-[ @\^~#'ۭ;r HRqQe؁b4 b) 2)H7AN<=ڬͱi J$Š#R$U)b|2"ц#L$Xg҄c $ NEH};Kŋ_zPIudZLBZ D*x+WR)0;wH'9qN$lSUXwH991*(sN1 y ̼`ZvB*h<@9Z""6_ލ59=) "_+W\sө'Ԥ|g(Pă84ؐ2q :Q;m?)lશ@J0ї EG-EZfQMAí2HY[S.pLr3C&ďX:Q&_I&G~0)2 9e~X#JrzpIRCfuq}e=ZYqA3Ҳk$92r q́O%'-i `{Ts0AzSwPAsJy Iv#.H@Vܑq4%p1I`v4)9V%#?jRA{jMjcjϴ0N{ջRe4%œ~@--C .Z+ erU[ʜ\;) py1O6qB]bgȧ XȬNJza'8'd*@\#Oc  ` dj,cNK3(V3=暘*Bx$٨1I$ qާyGؤB6cnjB zuFwz{Sf嘐cRÜd?CQ.~1L\zPq?$ xP ysQM,9$N)BAG\H)UHluSzZ_!XrBG4zTG1 2)!9crrp1S0Ya*HGC-Bl!)cirO€N'&;;rL[ < T' 6Qol#`@t “Fn109לc$89=hWlsޚ2 }Hc̒G$qM([N[ӽ&GROS(x18H_yWz-"ys)sjaZ! #w)14. sҜɐ6R)cdp;34rO֓%AE%)Rz@ (ʞ<wFx'@~bO` y_-Bc G=BEQzU,'$9#o+zS&卿Fᓎ̇z֕bòi\* rGZQu&ȧFR8#Uޗ$bsJrrQRԝݪ'yB TKvO zӮc!'N=' V,O"T'4`x=is֍#T-{Tɒz pEjg`F*{o nџސ@GZ/55~w?&{S7a1sFPx+@zU:A 㑞SO?C@.~B3Jāh8zgw q$zb0GsҔSO9s)cP+:A A#4dixC'h9F>g?.\P!)Kʻ`jI3F22hI;Zb8JRAQl|bF1׽Zb2H~Ҝ;SZ ]m@{FC yǷO֔-ZHbwTnY^UHK! a|q?^@=֟7ry{]}p#*,lOn+(9Q :=#hr(RO<׭'!p85%OphnX{Nb4NYjsP8PxzR-a$ڤ'zTNq4+lġ 沘t==kKXJ0SǮ)8ޅ BN޵( ZfAsRɁ@GG✒(9eq]%Gwy=P2r ҧg2#w\2݄z JA4asjW*,펔0A0&< 8"oZ3HWAJ%0 ;sSEȧ4k'=x4 hNTyԈیޛL#SG@j79+b ר1)u%z`p 1\hP!zTDUBcpilF2==fN `JV5ѽ8lz*Np4NOO']O1Y* JK|'Uwa{Ұ ^x>JB>ZLjۀ;~UO44`jd.qM/ҒA:s1Mu Sڕ~5:|v VVHP<JcjHB@Bт\c KRz9AhGN€rӑҕz`U Q QQQG73H2 $@o K<Kr;c!M H$MX@e)- cANXϙR+!?JwF4Y 늍AI@1ȧ[0*E0V$Id=3F*A҂n+rG$8c]EL" d LkQ'5q*X1 zRbo~is܃ts2O^)?r~`%Biy8=qؚ%Қz ӋmE)A,ãzbF8,(W*@V ;I&6Ey'X842J|FC@z{R =R9JsHhX]IFy0Wqӥ LץhowQMqvb \1SZUjaR21Sǃ" sM.HQ4Np9</++dیӆyL<Ʃ=i9Eʑ#ZHU\3O*Z ǽ5TmiKܫӊb# I (_ڟ֑>aN}iXw0)۸=qL\>!y1M p0jH 'N9EP' 3FLOA);%8>"y4s@$9o@njy)z4OK'ÔJs)@6 c֟ALJ=c9?_3 R¸mA@n'nsL^ҷU$Z'=*5=zbSfF?0C\P395"${րlJiB+*MczbW@'5 `S(1cOҔ|אI @`)Ʌ.F(y٨$$wWvK ,(xv9b*jY@#ސ1.NssAlB3sOJg$ bJrdmyF:愬 '28uRqߵEDdy9P{sMe(OzA R˂# ސ%Ux1q&ā i!N=HtivzJ\)li+"u0FJ(wmڹ4n D!CaO pzӸ,{d =hL nCG\TLO9)2irq_j/p=* inlQ5 HkiVI]R6)xc9֪`~8FRu~Ui8H7'J r3Խd?~{ҁaZ H ;mL'p|SR OJH;# Ļ0z}8e[t$cqU`9Fř#$NBɢ="s[LGiA=*@ŒLi!69ZԳnc)OJh\mmi' M\q(.a2vڔHBU7P`Ӟ,C"<6>~1}iq6^✌ :u(bD)@8Gڨlңݥ9GھZ1I €or=i[0<.xy)64#uݵ`f*@v"]TUU',x"oA,8F H壶@w9;eCiNyLnUms{S?0Fut[@;eE"leв$q)S7g#ӸpW<VS=JG]Km /^zʻڅ+dӃ8i\#5*7p~n89#6YӢ`7n9&O֔&HJrDxgI&9qM.NW<攺qN []*\v84HT ~#9C)Vyj6Yq1(vڰLPIj:G?940w94Y3֕[s& HAOJg) `wqXcZ$*FWLpMh%q@XI\*D/=)*g<tNpqJwN8(}AA ]iN#&X`+K`:] UC ϽFJUƨ%ԊHT*@=qPNzRcZ?|v`:TC?|uUlSVbOZ My̞ҾYv0 u jT19T$|$f= )$A`7=ˆ怹Xn1)PT08pSJLi" jHTmlgh$ÿAByGgfe*N }i ar$Ґ6:“7@8#<*N;Sc~c=߂C `bF8=x 7==)8OOb )nsxRviv9IϨI J=TKHS6:XiȒ>A1 NHhKRFY=0ID 0l{uY8 #ܠzH=E & f$ԐcRM0G͞sV#|Gڛt~dvIݑ\Z`? OCOLvdQڐ!;Opq{4FR ʅpa;T@䓊\sچvޔgF Ӝd䌚%rYe,1tI!;Җ?G@E+;h [֍֟!ӵDH$phzԚ6*0) $ j6 d{Ӥ ӃO%GRƣ+ EjYHp #穥KHhInqzTTjgJxrqzУpӂs'b7z)#ei[I+ XUM'$csZ&\ uF:QHd3Zi'"` 5V[BN¤=~wO9ⵆƦ&Q$qʸp2N:ojdeaZZ"w9fWQ9'`{1Md:(َO}#BqI!,֝&  ׏TMv=M5ӮޙZ.Nr==*PdIJ1ʨJк$sG5qǽ!@K0%qv^3QAl AD~U-yֆ.1{{#F9 tOTc8C@sc悌HR>f< rd cZy?bnAҁ:AI\d@" hg @YٶځnG!%sHAiPaKa3 E2FAJbE'ҧmѢM@Pڽy&Z6FȡrAV$$v֙#%?1;=1R6/ڣ;7jCxbD2Ps^2d9x .J1)]H 6p;J#fǢy($Ō s 4O MD_2sRa`G4 8n+1Oj4 T98#PƉLaT 4azUA |8dM$'A%q3P bx9$ E*%i;b1 ݖ^V. MQ4ԑ#< 7;N~ԡ9wri^ Q`=赂|2)I8Jw)ܲx"!@ d5:!}0~cУp#[Ҝa~ⓁM+ DVL*pŸ xrQL ptXԏ8'NBuNEXlp: I=hSӛ+Jp8j-BÁqQ`ҖI uiW )l4bYR֝\s?^$ u! ֤;T*jA\7Ld1R"99(b6}h. =2T}) [jn9َ<˂x&FTyI╁I@4TG 1r3z2cu(Ph(n:AՅTڤqL0際2Rơw½vcTYP`R 3"\G@cJ~&V'ZF`uS3(]c%|z8+Pqӂ&"݀ E '?AKg`G8⧐ H0cu4>n 3H9d$ldyJ%ښV\:f# ru'ڎY1ެPl(#L&4ҮONksb)uq$G~0E10\vN@3֘ |c1O!̛AC4:sO]vM# I87=y+r€۔sVH 1䜜Sf2OR{܍('❷|g!ʪ2pI&B 7F:cЃLe:TS'J,zqoaC>NfFzdHC M{P=z{җۻq$un3Q `4%Â:H)P?^Ԓ0Ļ Z03Ӹ`TE*6XvA~er0=zi op)`x4AҐ!ݹ@4~S)XPӭ>=)z~W"\v&|$qLL昄9"5r3It.d+R*0SY l#2VQ6ޚWw;r)1`ZEXT<:~܆0?jM#)1L Ra-G\T@''M.NMw( pE0bdI0 ~j#"dp0ުы FlxjV ?+b)+!i?i̠DW%H Vc=)zEL vIpM. p;ЫЅǥʩ#5QMn=sȠh|y8giRG5$1r32B#8. GtQ(cziR[Q(R[79;xPl= ӂXr2i⽈|xNl؎qT4I!Yr8@sj 3RAˌLc!b QL=1r)Ԛ<0 pLKJ.x,<9@|өNiui{Fx hV# `wlԍG~9q19gu>J͂xQl=(`%߸ )B$ o&L:|rGpHHw.ۘ$psVG'Z;犰1 v37{Cj1ʦc((GLjC9o ԘzRATHܒ7.r5 Iv4-]# hi4}? ŠxTR!# :hRAqZY~N|{R~n ?Z6f@EduSUO͞3Qk0h:IҀpr* .ӳlTtN¹-%, {UIeXÞr Yɏ1b'&3MA̷Ϧ8VCZcyaR,3ɥ] ƃ#<)T3yt*sڕv&+1Z`ܚ`Sp@3C2O8FGSS6أV }5,HdzJipہ={дXa |(?vp̱02n=4&BAT i=A^ @>ƌ'ҐPnOlp)鐬̠l TE݌qlCqqV27:}i34 kddp=J0Te 8ޥ WQ0;Z{8DE[j,:B˖qsdqsL5IqzسORIA /"'R)h3X^ 3n øʯҘ^NhWgR1̅O@x\O~wF8ڈUڤ '<4j9ҐaQΤ.c*gOD H[OHw:?2}Ei@8>X3O!CC MaB\!9 uPqNJ6sҖ2#u8lD =rEv=i(H5( CG=aŗ"2۰89 p}iN#c8VagZ&`Upښ8B| 8Z6*qɨpW#ߊVxM&/si)x $oҦVm~BN>$`d8K8nޔ1 HG曒@EJQHw6oCCyr v _ʚm$(# Fsz(C)S۽řI Sb騨mHO$liM gxAb\@0=i/9튀qO$SV|RAX1ϔ{dħ$rH4QIÁz2R&j&[R9On)\v'n3.r13'9}=>11'#HE穨t'lҥYR3i@4-k }FaBy(!!\ %I:24ۤ]TghRV$@ژ2Xs:@H85.9 r3VCG<{g;R!!ckA=G%QBy$ɟZ*nQIa8=8xFqoN\ӁXץ0CzР\@lJOS;X暤aM(ݽvSXgwOZHlF<ʙK4ւw*H!?7biN"ӽY4M#1 'JD*v' %{+9'FqӭZ?\E I~5 {(2y/9%FO ȉG.J*r Ӄ/8'wN 8W٪.im,! '1鞕"GÀF=O 0nU~li"YI3=o<ǖ0 VfC0Wy4a>PnZtH W'<~ap08J@ A#}\)*Ǫ8!2| ,`sȧ!+! 9?Z$!YclzS(qi֤3HTv83 1UwB 5_ґA7qx$j *TL8߽H'?L褨VTj(ʜn'j HvК6_>@##ҡ8etRd ;uKdZ2[Hw9q]$\jxF* HzP.@88T[ SVsJ%UѠj6AM2LW-&yԞJ{?6ik"sa\g?JhMjɰ|4"yAJ,+u1#Ҟ46p1߹~XP<ڶˆ`͞Pn#HVU`X)A m8#)_QxITcag=sIV bTxi"Qً>.6g>x̹aTE@LAmRx'5fIzj%rgrXtJ{ rb>b}jjQچy0SwogJNuF8Ǹ=jW Mk>\wDzU# y8U;SOanHvD3Q,'Miڤ掣K$`#agJ" zSp;*z H0Љ{R9H>\t`ru>(mXϭ0{R(*D #p*]`h s>bgq'$ WCOJ\bufwGg)(i:SBp9'#J *A'IXHI)"8h@#}j5sCcC2\uUzwqK <pnÌuIR9=sI(9#4}FYʔ1rq߽=J=E0 î8cI>žF3> Ƹ֜*" O֒]cKd=@(W=( @yeT.0aۦjEr;1GqI0Qa[˵@Zci`A+>tOF Q1Ob jH=R+(o^:As4!?4q{`I wy$qZhR ozWadXfʴ48yqH MPvNⶂxiH'mziPsp3)ipsޘ ΜI(5F_0%+1'qVwwEāʖ٨ĕQp0ZpQQgx?+O~{Ӄ8f>l{eH (#;:N2 x#ր =0;gI|1s1Fq1! 8 e 7 FI=iIz:Q@5,h6dLr88?I<q |mdm SU=6BAqLHV{@8ӽLIc<犙ČMf$I4 ǽ!6B($cڈn:$m$N=o8뚢md5H8>G gRrIIe'$leFA:f⇸†{qJz۾hn㌃4z,1܌&H!B@=(5(cL *u1 ea֎!|dJn ')Xw.%lvT DUvRJAڝ1iݫvtB_I&uN 8px8;GXTWGqRKRw:s'w`zj͗ nKpOyڿMDbp:g~ œG9"'Fx'ȑ"*X`_R)r3Y.F0{8_ڒ6VX_cZJ(??q]IJ6G 7lT[DzHw:"$aS;$La?mbrxQ(a:Obc#EFR"rzs@!6T$g.1.#:FR:au4X/d0ĉ87t=)+#}Ī&rPH| }Uv\aO|T11teR7QG pCq4Ѱw|Ǐjw.Ue\.:qzf%t|i; 'H{h+|-T>em3'ќn$&ʊ,?wsRe r *P$ǭKFsM2Z[\eg 1N[ccD{N`TЅ0rAܤJKq 'M@Y$gښbF@q捠#(3dZm GFWsZ lfx F! t4ݣ,A' zpQSr>nvF8OdVDsL^Ccu$ ddR@ܡnױ,AQ>Gzth% $+糰u*EFNճ", `pǯ!$)m}}h$Ecpi 5*Ȧ5G_SP1Lk I (7Z߼] ?*umxn`']g|L5hO{6@ rGz/*F zx.[ڞX 7qhV}1ޙYb-C)'皑Ir u42$eDd`GPc4ِsARKH"\E0+ VpqOKdT?)zSƨPg91.çGzWI]I߱g':L sHUt's&pOA͂,jf+&"4R3_)l9+J`Q=( NgR˕$S&?cҔH61MU3vЕq12Ğ^H5&//5y'# C#K p܂zS#dT(0 ʒA}(Tc>+AÚpUJhrsڗq(2)އ-Ew^@ҘHM lMʰfd9皗 $ñ8PeA4Пa32)#U!H(2=z~RN ޝ X1G84v8=x`HŽ)FRpC6IaڐlKw~f(Rmyx))A11 `QsO?WQp8KIҁ4fq;@# ~f9?4XlNFliSIl{@4Y܎iǀ t894J8n&)Gz^Dpe4#vI7i ҕa7|MƠ28Иߌ{SX9vzR08S% (]:# Uƌq8i M`9aNrDj=zic@yp =4p3A~M:@ێTPXrEBAOtAւPT}EPBY=1ޘbX85NE h؃)ҫ>M4`ަZS'90I88!I?* FsSA1! I.GZ0y'<T}ъN0}<|ޔd6sbaM hvx$zLerOJUJ&Ҙ<~< L$gP'ޙ3IZbHqH==p.>h :r~W1l0Iz7|'>_38%`C eO!xr֔ǡ(w6sg4FM㠤v:Isҙ72ړ8x4!dR=M'}$}AFp9ҕc tAo9Ѱn?$)0st GށNCȦ1.~`HfEiP~>ǵ4!#i zO\`@`n:aOf[(2z{=q֘Hz:u B}P[T)1&3}z M6qӵPC4nI9={Sr q4r*1?ZCH##y8wP`QC(Bٱ5]W263߹W9OOSPd|{PĮ8H;әYaG94DH0M\z v! ď4̣n;;f|9R&i$z 9(%QPN:f hsuM>\U<H= O=O4xo!cSr[92"(R3KEr9(Td)9$ieC}\ZF,lSb'.[iG 8?6L#6PGq( 2MVcFǯPƵB$.TWi xR:RHmF`r} zHxCMs1oi֣I9ԃT F6H(zj+cq$h$g h kH݁r`S֜xc֖&; wc'쪇7wnp{O`Bcgla!{sD*p9AH qA*.9NiGݎJRqri,9#2Np:T })8jTfcKcM1 qS>H;Ҡ,T(S4bb)ړG8O a]-MTUV}|Ӱ4y򁎔HT=Zym9`g b=qO@걶_œ>Q(g9, X6;lD,sIB b DTg&⪣oQ (|Ȧ1jPm Pqv+ ;*#sTm%=1QpqqJLjAٽ*@#Ng.́kB[E 9|CM=NƓ)lB h~=i7ݏC'+!;O4G#bSBb)㹧2A֚˴#t4lO@1s?Z$r~St?ti6E!;}Ƞ.OSҙN P3$6y4KJHFBM=GN+!yE {RdagSҘSiG˒~1GRP7,GANaұ MO#ژ$ fb?{94,~O44i/Ay, HN@xjO-ќ18<{a{ S߭*%QRCcX*Px)d$): Nϭ4 v5#`Sq40B <Ԍ p鞕sj!T7nǧ֜[*zHHSҡP'1hV~ ua>O#i0s#@#7҇,qN(< v}=fxR0MstvɎ))QqƟ*tj ^l-,yA؟ZGRIԁӏ9Ho v5݀ rqMݗp{Q)lF2{Wtdza0`sB\S@>@H;L@IO`l܄Ǧ?k{@˨=)KB(nfes}ipe)F$`ژ& (KqO*<'#ocML= 1ɨ4QaQrIQ9v@mGBrA*`Mu 48q\E0AR**FS, ߑI!SӈzRe*.L1HNBP1/~uPb3/sJ~>V#9[`Xc‎\F\8198xo0 u2)Pq õNXF}s4hP1J 3ڣ *iv> MGˌұ0ɓy*Ko+Gy8DnT=*Ba$<U8= HTrM+bEs#,zz{.W0@*qԃN2XsE‚9 bOO4 FvƄPӓw-ALT.裒ا2okQU64W+M&@8=۷FiQ,F%9JdxVb܁HsY A=M@=#Ҕ 92 c.0sP/Qa]H5W( fcǽ iXtH߷Ds=2*gl>XFXE1 7;Zd(1Ϲ",0I|;8″Je+lBބL1RzT} Ӑ.*@3e%r S`DĎp !S'w$v=EmczP1ܖܣwJF;JO*YC&p}j)A6J-Ǩ 'N8A; l) Dc 4ؓ RƻT1$qI D:p`{ԛAQL`ZbYTuOl =Z`HiMA>Ǘ DiJi ˀs)'ץ X\Psڐ0qk,öiA!s 9U qޙ R̸ʢc҆VpibM7(AM<q?Z,Kړ#Fbt`&2FZ zS!18];FI=GVȡ8'49zu"<jF89v:RàdO|zsAKc*rZ7,בC`3(GE-ܚ aϽ+2#)AqZtg L[cҗqV'z @wqW7\%P;sQRz1)ARRw4Pr v'4w$zS {qJ zvM EHp9fb. `upIZ0ު&NO#Қ-<%v34\,BqJ y֕Sst5@n9@,qR9zjR4|l[J9R<@АOW.p={S[lf?Te0֤#!T92s1~\Xܣd|:(,e?w֏AMILJiv )I43q9dgc/Yp8dd5xՉ#jE(j2'E (FF ʯCh@$9ےiU\XږFEBΤgbpbJ傻8wiRNnQaOV0`E-ݾZq_jHf,|4<Ъ#ߵGМ4nFr!RJ;qC#oF2@ K,QAy?!eFz EYN7r:Rq]=>HxS#H1{fHd.pNi\x>3pzR)!FMv,M; {M΀uLSb]T:ڥLAҢ~0czqC$cõ!ʰoL,pjG"/,cd 71=; F% WaIP + ,G*\Һ+\tyƓ~ۻMYٔ gނzPcݱFH99?Қ> 7ٕEcr#bO< ĻG| r*cnz(@XMX_.@t)&}ҘY'{'bRvcy+*~V$cDi\F 9S.$(F\2,( Rǩ=)QE-ZkuR$Qр^CrJ8QP )4 HTlH ϽHя\b?+zjV`[J~စHe+(#0}SE T֫0r=qJr4IFH*DuIX2QB gI ݂:F)VYsfZ¤ 9=z|;݆;؍W)UG'*5ӌsz:A"į 8 ȹ/F:%@L0^c˔lrG& I:#R"2 59RKlӦiJ*`'4rqaTHؚvܞRf__z~9րhDf Ɯ#w@*I-98& uli@AJ{Ĩ8"pwO>0x x=)\`>4,)Hhg9Abs} i1ssL`A"S41Rɐ3q@NN'S*E,Pyc q sK *). zS[ P@\*6NaQqA tӣʱ su HoJ,+\n,0vg'fTHm cWOAbG\)[lH<% ;P8dP.GJC`S=ϥ1I BqH9 +>aw,N쁒=bK}3J[Gҙ׊9#=h ci$R#+`(֔c$AHNPr8;!A8DXԨg%GShE9(sza&O8hF@-9vrN Hb'\qҐ_QOjZ'!h<3Py" '8Z`!wӑUbR({S%GҙK),A}iTriI'3;ӕ2>7,qzQ`!' БJ#v=@A }䈫`GP*3z!Qbi$=ILb亂*r<愋,9=ǭ:m8{ vUIROjkBr1R!'yn)JWyҕUtOI c(@T((ftKr7Sdaۍ=)ju85xdi „&<\dA|˖ɩ QHa=j0'N:ĪXpbrI#NQ#UIzmclHTHҦ1g) :>PpMr{J'$aH9yvY$9Hwc9 1UқVp<{&q>p 'wb ys'qXsALAQjMWjOQ+R9j36h 1$lG ˾䞔2= (K *(e40 zxdsNI!8\R(ʗbISRNX0'?jB֘ bjfϧATtO;<~\/ (Zʫ 9J`7vc )r>#1,I\ qI[9ysy'Hy8Zvb.Aϭ'8. 4FzrNpO4piA!HF{s'g#J]F$۔0XsNRO|7`;P`3H1-`)2v23L83HcS'H8ϵ)pH&bhZJ>;I`+3:rҚ20GjiZEBO b1}qG̤8fF8lҗ295ggS/!`2&YS9c)cr}4&5uM4gs>_ƣ܌bFsP!<Ԁ!,x')(U30֘lE*'aڝ2.;Hٻ .bg։1Yy83HR@BG~QTө'̤c'I"iڜ~3pOF$-qҞUF܍Bs"h1L.yn=?$9HNE1A]KNdU*~~z ծ#󞘨 {J ;дCzćrNy9J.q#LrIs@X|OŰg'jcڇ@s4Ƥ1ޤPe8:vZ83FHț$}>.pE00dgޗ8'=t`F1ϙ ;y)z~\|(,8QM(8q= {#n `qNٰٸ8)`!qMFa&qfjFcRdnajlr?* "zR9$?CNdq{Sx q͞bӖB80 Iyj9My=>cQ)M>K@Sm`y:zHm \#=iz80N $(u*I'?=,yv뎔$}9E&C`O@ 54-ذZ*/o~SB*ACg<9i P7n<G"&El} @%I緥)UA=OjR* n>?r"lt7&D*X m֫8!#1# ӿ\,H2 MAfSc]$Űzi\DZ~У{=)[#'.H]:R(LϴpG)!I)72Ry)i4)uR砥qؕ2 Q;S8* =jEcS/ Sx=>&##iU`1c]$S`U@I$8lI#昺;ϥo15BJФ sBDf*PH4pLwpzN- 27;8S#=+ۆN=7,20j¬ c"#<QHhV9${S3Ҕg~W3zar ~G>-<$ DI+!;ޢB&A$ٺ`☞1gN1U†餍T c|.GsK $zlϥ"P6zjD`B@ރ  C25$ڥbF$c89cC 'LK;ǧ@sr0jKDysJ*>O$cgf]Gg#ZNyP23O|l-OF2i-BlJ`>@sH2z086 #[8G9ێIɥx*O"@CB'aǽ($v&4)9Oj0Bg]E

Z,+Ei,0RN<sړ#S@'I'r8^yJr4X3l#@9`;bYv`?:Nl40cW+>r'ӸL#⤤( rOC#; օ FN˱y髜3}^)Y_ ޣ1if:uY?HqJ u<@v^"U<\`oJ il_5ʕv8ퟥ j>s0h2 {qG`XP1-2r}9cN9THB iBJOzM1hln8iJ׵+†9"L z7J=AķtO zq:{l\RWSA)mJ@Fiy֐ǮLݹ'1 #)FƕNػ>D6JAV'"Wt=XycJ'PF1c+&GR Pg#9A p^hR2:aqTRC;T/ c=*81R@Pp;SNM]7S @8ϭ^8zTj78đ)gӤ@逺~\zƬ*Aԑ'v20sRvv{0IJ:GqI!+!#-#tQ!P ֔ۓ1{Ұ z&4014-*3J}j8.xM$E& zSA$8iNA$=tϵJA>Ź̲p5FOoIɦ"=rG,Dh튐 8=3Rp@=2O$tbwǓևHʭF2=(14ϩ֣<{ԩ_05҆49T';aB=Nq$}`ܖsQ+U500z_tJN ڍb,~96'  aU~<>8$y#e@0ԠdR upK=z6?Z>Y9c=7pOs֍PnČq O~$1ǭ00?1ޔ`F8ICR!dUFp™$g)ܜl`PGJ"FbD~ޟ/Jd S+O~F)sqG#G@#0ԝ8Oz9 A;PD@Ԋ[n2۞ǥHH54&<0R0:pI8ǥ.~\^jJp=?;0z9ebǑi\OzV<`Ekȣ 4*6mrqЎsRqNw?ale@bF04 Ď cZJn2Ƣ=:]rpz|\F`t#''XҖ'#+ߊVcxs@u)፧֐cHFPlʣ3bBA1>ғ'AIQ(FvJ$AP+9'pW;M)8;Q;G4MRBK8qI\Pvd#9v9{bq?Z*pZ]䓊EXaaց1 eTh^g2X:@0,z `m*z ƒKJYvqpGOpP+|C;q(iP6OBt` ߊtqLpT'>Vr{S77&3)B|=)nc8N5' 0[M 2FyPNHw!,#6c3L R$d ڕ V'☄U I>,1s߰m$ LB!sRg>)6(H4O> gq0*Jր9*PP9A$H<@@B7Gwjq1S`GJpXzT0ccAf|:6FHZ6=;S%w< $K )B gj5,4I@^@ t5 (ZӐN#֒5czǵH=Z}6\dmb62Q7`!Wg cs:uhz#800"dwJz2 $OZC!&1pH DV @(,N1<тsO9Gɷ\S@@РmJ['ڕ0nL*`6T@pN*XQ8ۅNp} )󏛮}q3׷*!KS#neW(=yWЎ]=;P# ס+[u *\SB֓GL4')=XZ\vw SBlc)\0 ;IS#3⤐[{iKJxn9 IK6HJ0;{];b\x>D<.$#DȤ;8A}qRsI+ SS\/>4[l klg 1'Q2ᗎqM 1I^9gJ *J-֩#!`094G $|Ҁ92 NhlffHb!ĝxe2=8(ٳzjk 2Gԏpy )Z0@!򦐛 ,8dԱgHқ}? 0; %p1R0!8ON_bG*G>1ep9DX'4P1$psGK|X<6r犔26[Q=;:X@f trA:c֣ȏ%^~lcޚ}FV,GSU/c+qUbֻ.J0y>qަDw9-SO?RFX()͇cyrFFG; bld\7nsTsw.F6( PsR W14rr{ڗA/1=G#('%TJ @nssv}oPw8IvWc!Gjor{Sc8{=IԝsbQJY㏦1\NTz8I9?*C9V2iC|=i׿j(`6CdcҜzS[ϵn/;xԲg*:#<&@0;`SBbFRx9'MXgi?(ϭ ;[n)a4kzJrބqJpxFeACj~ѼYNw֢m`8AP9g ;zqR!"2I#PLhJy`$4sJrqI &r6:I4,B9@hRrz{Aڥ%Jy֢wN=zqAS\ǃץH3; e>:I GrjFq }sP1%MF$aHFZteNcxKeH.#6֙n3Nf/֣9&RClZFmϜq@aHz? Wu=jv E$ ~b%2t e `g"AZfҪXs`!#yϥ8/rr=D,O=@Z^a&ӓZy* #as8IO^*6E'eqҁnFÒ@v z.t>zz `0 )J,c#)20>b MW$p{S;ӲNT p<无ɛkXqϥ8=h?%Y"`=}iDŽSUrO'i xA6p9#nb_›8I*lxg2@q:TsHrP@P9asH'ZXRi~cMJN3~+=¡^ƒopmprx))Pj%wC%#EݍG![ 1Z$R"׃ECKf0I84:}h{̓׊LININ Dsȫʦ@P%Hrsw4s|♜ HroNBOsޤbq_QL!H95sҢڥ@QRlkk zc9S8hZc|;Gvf@LQ/C Q^:Sc?4B=!J<ҦV&x'S.Kydu "Qg֡=i$p; [ VrW:iШv;j<pԀ$N $E01iGr|x,''ޑn(X䲌 џ o44F0OKɧYqsOb@9'ޣ)&E4!2d@qP1 681%$ϥ KqLZk#<ӈZrA++sPR7cbPnc*&$j}ȨI;MJܔ{z`‡;RBEl81u2 ޣG, Je5!BRHĪl?ZAT3ƛ,d4c 5*r)9&6a~ڙ+*1ROjpX rxbk2*m3=@z*Ȥ5ġQY~c^ ySCg0*8F2?JCC`F@{ӝȥOJm;ԑFG͜{r9ާ#:%LY=}41!)OJr!=3Q) )?O҄61~PG9ړ[QqԟLõ!x)ؼ)'n0 6Nf zz QlTh2`ui!Pin|'+:ٌ+S}HcbA)p 8u3JC7!M>g̤I#;v)+$N>SOUqJY `gI `N}Ѿ%n*˸\:I'0E$gqcpv5WD3j@J\EPh !Ri4!h@sAM%nP2@-nI$~hbH@xg RfQyT\HlH܂}ilAQ-qrQx~O|?z:@l 9zc'U< j_8☗`v 9-HLe @#'jyQ僎i22B0sBP>^::AO֛O?|je!UQ Ozlj {h34&K9~ = "AG 6)ɐNB㑌2Rڱ瞼kq=d+?<"W,xv$5X=*A9(qxAޥ.?0hx&ڔ(JO9> qM .唒z}i%cgW@zqTNI3nifcK @d(~csҠݻ<%; Qv4EuHd$ҧ̍< JgIO= ;ڇ|j5,Q@Xq@S&0k ;|FO$clg FecޝĖt4iA9o$Sp<j@(=:S8ia`gڐZVO d`ZQOґ}h2DMÒ2zsL` cjQh昐OPJiﻶhڧңIcqM9,9NRc.Gv4[P0}S48?JcVzpb W҄LCv. Һ>l㱤_,wgN(eyWa рTrshrwc2H=1K 0z spzƇXP:ǚHl9J;1@RHqJ`i-BC:?>'Z1g-DHϽVsB1O|ќɞlibkysdk-applications/kysdk-qtwidgets/test/testloopplaypage/testloopplaypage.pro0000664000175000017500000000203515104543305027627 0ustar fengfengQT += core gui greaterThan(QT_MAJOR_VERSION, 4): QT += widgets CONFIG += c++17 CONFIG += link_pkgconfig PKGCONFIG += kysdk-widgetutils kysdk-qtwidgets # The following define makes your compiler emit warnings if you use # any Qt feature that has been marked deprecated (the exact warnings # depend on your compiler). Please consult the documentation of the # deprecated API in order to know how to port your code away from it. DEFINES += QT_DEPRECATED_WARNINGS # You can also make your code fail to compile if it uses deprecated APIs. # In order to do so, uncomment the following line. # You can also select to disable deprecated APIs only up to a certain version of Qt. #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 SOURCES += \ main.cpp \ widget.cpp HEADERS += \ widget.h # Default rules for deployment. qnx: target.path = /tmp/$${TARGET}/bin else: unix:!android: target.path = /opt/$${TARGET}/bin !isEmpty(target.path): INSTALLS += target RESOURCES += \ qrc.qrc libkysdk-applications/kysdk-qtwidgets/test/testloopplaypage/qrc.qrc0000664000175000017500000000024715104543305025010 0ustar fengfeng 1.jpeg 2.jpeg 3.jpg 4.jpg libkysdk-applications/kysdk-qtwidgets/test/testloopplaypage/widget.cpp0000664000175000017500000000471715104543305025511 0ustar fengfeng/* * * Copyright (C) 2024, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhenyu Wang * */ #include "widget.h" #include "kloopplaypage.h" #include #include #include #include #include #include using namespace kdk; Widget::Widget(QWidget *parent) : QWidget(parent) { // QWidget*widget1 = new QWidget(); QLabel *label1 = new QLabel(); QPixmap pixmap1(":/1.jpeg"); label1->setFixedWidth(400); label1->setPixmap(pixmap1.scaled(400, 200)); // QPushButton* btn1 = new QPushButton(widget1); // btn1->move(100,50); // btn1->setText("label1"); // QWidget*widget2 = new QWidget(); QLabel *label2 = new QLabel(); QPixmap pixmap2(":/2.jpeg"); label2->setPixmap(pixmap2.scaled(400, 200)); // QPushButton* btn2 = new QPushButton(widget2); // btn2->move(100,50); // btn2->setText("label2"); // QWidget*widget3 = new QWidget(this); QLabel *label3 = new QLabel(); QPixmap pixmap3(":/3.jpg"); label3->setPixmap(pixmap3.scaled(400, 200)); // QPushButton* btn3 = new QPushButton(widget3); // btn3->move(100,50); // btn3->setText("label2"); // QWidget*widget4 = new QWidget(); QLabel *label4 = new QLabel(); QPixmap pixmap4(":/4.jpg"); label4->setPixmap(pixmap4.scaled(400, 200)); // QPushButton* btn4 = new QPushButton(widget4); // btn4->move(100,50); // btn4->setText("label2"); QHBoxLayout *layout = new QHBoxLayout(this); KLoopPlayPage *page = new KLoopPlayPage(); page->addWidget(label1); page->addWidget(label2); page->addWidget(label3); page->addWidget(label4); page->setCurrentWidget(0); layout->addWidget(page); setFixedWidth(600); } Widget::~Widget() { } libkysdk-applications/kysdk-qtwidgets/test/testloopplaypage/main.cpp0000664000175000017500000000165015104543305025143 0ustar fengfeng/* * * Copyright (C) 2024, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhenyu Wang * */ #include "widget.h" #include int main(int argc, char *argv[]) { QApplication a(argc, argv); Widget w; w.show(); return a.exec(); } libkysdk-applications/kysdk-qtwidgets/test/testloopplaypage/1.jpeg0000664000175000017500000104176615104543305024537 0ustar fengfengJFIFHH XICC_PROFILE HLinomntrRGB XYZ  1acspMSFTIEC sRGB-HP cprtP3desclwtptbkptrXYZgXYZ,bXYZ@dmndTpdmddvuedLview$lumimeas $tech0 rTRC< gTRC< bTRC< textCopyright (c) 1998 Hewlett-Packard CompanydescsRGB IEC61966-2.1sRGB IEC61966-2.1XYZ QXYZ XYZ o8XYZ bXYZ $descIEC http://www.iec.chIEC http://www.iec.chdesc.IEC 61966-2.1 Default RGB colour space - sRGB.IEC 61966-2.1 Default RGB colour space - sRGBdesc,Reference Viewing Condition in IEC61966-2.1,Reference Viewing Condition in IEC61966-2.1view_. \XYZ L VPWmeassig CRT curv #(-27;@EJOTY^chmrw| %+28>ELRY`gnu| &/8AKT]gqz !-8COZfr~ -;HUcq~ +:IXgw'7HYj{+=Oat 2FZn  % : O d y  ' = T j " 9 Q i  * C \ u & @ Z t .Id %A^z &Ca~1Om&Ed#Cc'Ij4Vx&IlAe@e Ek*Qw;c*R{Gp@j>i  A l !!H!u!!!"'"U"""# #8#f###$$M$|$$% %8%h%%%&'&W&&&''I'z''( (?(q(())8)k))**5*h**++6+i++,,9,n,,- -A-v--..L.../$/Z///050l0011J1112*2c223 3F3334+4e4455M555676r667$7`7788P8899B999:6:t::;-;k;;<' >`>>?!?a??@#@d@@A)AjAAB0BrBBC:C}CDDGDDEEUEEF"FgFFG5G{GHHKHHIIcIIJ7J}JK KSKKL*LrLMMJMMN%NnNOOIOOP'PqPQQPQQR1R|RSS_SSTBTTU(UuUVV\VVWDWWX/X}XYYiYZZVZZ[E[[\5\\]']x]^^l^__a_``W``aOaabIbbcCccd@dde=eef=ffg=ggh?hhiCiijHjjkOkklWlmm`mnnknooxop+ppq:qqrKrss]sttptu(uuv>vvwVwxxnxy*yyzFz{{c{|!||}A}~~b~#G k͂0WGrׇ;iΉ3dʋ0cʍ1fΏ6n֑?zM _ɖ4 uL$h՛BdҞ@iءG&vVǥ8nRĩ7u\ЭD-u`ֲK³8%yhYѹJº;.! zpg_XQKFAǿ=ȼ:ɹ8ʷ6˶5̵5͵6ζ7ϸ9к<Ѿ?DINU\dlvۀ܊ݖޢ)߯6DScs 2F[p(@Xr4Pm8Ww)KmC     C   Y!1"AQ a2q#BR3b $Cr%4Sc&'5Tsғ)DE L !1AQ"aq2#BRbr3$CS%c4&s ?7/鏮΁xuBC`d ԃj\2p~_u9wqD/\;!&C A_ 1+dN0B }?>!'ӃM+,H}"!z!'T4FJJc͹I~\&@oIx/no[S(B1 >IU'D!l$!"=S!u1HsM@2i/&~xL\bUW{a ER4ꆘj*"PO`~J"wB6oa$]_")$;t/iLH@ uvJBw+)p,qb_\( Rbd۷IIw=\:i 1 &R膠MͰBLTepmN EUl"R#D$VҚ!":vԛJp0Um.$}9< >'k<%gL'|%mߏ:U߾pg5upؾG7';<>>O_L4ӂ-]Zb*B{0 aZL 20FQ H|]Bݰ$;K'$ CA$!&P)N 6dtD t芌eJSl [)*?@"sFՠp3 NM&$$9Oy }C-}~+'A\]3gl{n&ρv?Nt|P $s%8Vꇰ'l0Tm(QYN2}xxj0-?_IN({b¨H:%tYjPDAmWl#x$n5uQJ- J\)V%ViM7EgKk L? z4n?C553[|J<ƒ+>>dq `΅(E)js''Co 'D<!%"\H3np\IpDS^?$BJMҀO$䐛$ AIB=F$ :/@ !!#eϐl=HHN # 8H8b!1 d2j5(u?ZQMIHS)R0A\y|`HUVKhqNT Dτ>WR0@@"@ę̀`G <Ľklx%ZA0B$ 1& S`!P:L \ 0a Qkat:~:aHJ Yq#8Eѯb L2sφ}Oꣅ9F]܋TOdxL6/mNr19}1c !vJ>N TpQl {È;dh&;m#q#aϦu) w(ǰNp3kxn){? LC?x߿8NI l6l PD>~xw B9Go|)N?$I|x  bGvIJ HOl2`PUDySQˆIˢ5p}>HcM 43˷á+n”xa!߷I EXa%!?J0L!odIII`ێH_,Gql$/pxIGd$D$ƽI~]W#mtRh!$ l-SI&D~|0W|-ǿ -T8CLUl8bT?o)dmh4ne'FI"&SWDCc? lۡqw"!Gn0uܒƒ)1u~\atMD$A#e^PoaUߖO;# # JrR|ۡ!t GJn|2}DT7'R E7{bIH lyS)nP.x0'}n0 q#GhRB#v6^|"ct]C([{M*OǸŽ!.#9 2A=apH馥iI&c끝5O&?k[WpOۄG ا >.w'qe+\L!\%(bJbSƉ5Vu&.5 fH*q&Y+]P;S[WI`YWePtL>GLB6+sU * Xv;Hs@As .,?u1*8Rw }-/7ILH%Fr3l_KIZ᪓ V2cU8H:'WS8}sj zϑFnܖ¡F\rrx"[rk&CwÿI MgJJ![0)9iqMt%KU 6r8.qk~$߳-[ NȀ`3 NH< XRR+ t+O0Bx 85pa6Expdzn7Q&6aMA?/'QդI6N "xAE.m R pE (aQ&="u 8MOl19DF'Z9#sohʑɱHC<`&Ac2TIޞA PKmFZA?P np@1It~v{$?V̡bm`8 #t2lLH(^'05G7 H=p#\R8/k<2Bbmǧ8IP\$ . 1HH#b$CcěȾmD` 8IB q9] ^sapCI蘐ENWɎA (-6#4$ߘÃ"SXkX B)~s% 1 oL0B7ske8$5wP˷C{۰L` 8i>a7\{a(}i۵|;Ji;& N$% K4۠ܝq=RT͵ۆ2t%kD_lU. E67⿀լ:9YGz_Bɴcrx~K.+}8A)tRE6q{ǐsy7_0{j?ZkG34gԩ}+KdKg*%*Fd vqOo3z*xK6_Ot'ॷxWox?a}s3!_& : QSeIv k{M"L>;z-+e|Ԝ"9r#PF =Mjd.0}1D "i0 s&r̫<SdvP\MƭP_ 7p[6ZD Ӿ^-|a,=$ 2$9{zpBvmӓ pUm| HKLȕ@&NDEp#~}SeB-P\yO ?yIvXÃQ&1OfC >6x+y].}:ƍE SZ,K;(wqܜ8 ;{&P~egcVw5"٨T6_}#|89KmceHRHuCCv6$a |crin^}{<&=P͈Р&-'E  _o>$=ˊo[ P~P; $_8I.^Ep7p̢4'|$CA <^$!-gt'sD .-78IˀA\pOk`~Y\80S$.p wB{HCUA,Zm- rO|0 % `nmJWۀ~baa|$ASI<{'@{wOHKCVN-+`-4Cu8t4 Ϲ&&Pa!Cn2./cbc _.OnIvBK$ >_/=pp]qqt!qt0Ñ>d1Ӟx0BL_A@C~ŰI 1ZC&"i 1sz[ H;&; pQ;ʰ vHbbyQ 5 A s` '@NCL+ n P I6=ɉ.L0k[ d;j8I E6 ' -]?I`G|$. >s!&"T,'jWQvza&PP=ptM $ aJipE{fD@rqb;{yP E mJQB)&o̞$~JO`v(;؜1)6WD=ʲB`:Ю7(C!II"J灎!#ɽAr, ¾\<]NDBV~?1-(MsŐrjihE H6{Ca aFZ"d%+j?_ u 4核a.G`ڃ<PHQsO{|>3>c6Vt>S!õmV-&?S+P>j|vTmI`ݳG4DCO<ًͶv"ſ+lt+'qޘԦ *NԪGYWH:yNgupe EB s|(ҴJI8U@.]WSntpaӿ: #޲킥9{HTiՎA?AfP C߻՞\7㏨?g2Y<8,M :Yͤo3f7'2\M@=NJ@Qp\8fSE{N|}bUj.pۀ <Ș`G̼Ff ЖZ\xgFޛ:ѯ|xuGtP$1`o$DeXQ!Y6W谕xAt+I<'ÓMJ_\)hwq~Ɍ%d0ң0ݛO@Ӏ.#8cO.Cn*:IopM9\GbIh)8vn0J0M1 '.q] \NIw=.w7)̑q|`X_a×4y I .}RjTM~=LH DY(ሊ>9In3D򔑚*S Ӷ6rk=ǐ~CP9}1yOK$09FS<'a"b U<ᇙC  F #rMC{aTJZK.tƮ&}sD WvrC8(j)lCHD? Q|Hto{~5{ao1S,U)%);Os܌82t46`$&Rq#燜"HrSqe+E1aͧxKnA$Jx *5|$ 10U$) <ǁ;"L2 !'fMcq8'IH@T]nGᇐ|b px 80cmӿl$H$f׷儑(ǷnI@XH\n XIH'nIpeQ,uϕOnDqI'(  alc5B1yO冔:xiNZ]V#?}!Dw|?:NI{p널bJͪ膢;zvJ(;w#%PHz s醝bX\ #%,!<۞pCi>6* |(hSu`B# ]I?y?\ )B۔,p}%PȪyl a?϶"\ "\ww [}qI5Hf'M*fCSe 5L;%ϫHOIs[2|{wT+c7q0t03r_e?iHvdi77Χgoܬ-+3G;(=-0ԧ>+vAyŒbMkIPk&߉='Vs^Wh64x4@)J-PPHP<۽9#)B"czrL:rېRcE*Nv!*EUdk?W]-$>ާ! wV~˿cԬ3CBܛuWnVOiź귾(I$I폔Gl|^Rߒ1Ӝf8 JL`wT1k 'ӵ+*f}Z" ҐPՅ1= gw~'bךoU+8U[zbu,Jޢף9G*L[yDdN(lO)>V%e03;Ѯt" xM9P9յsW\n>bVlB@қ%ME+u\Iܯ.մ(3+Z4.ũqH!~.;};۷3fBڣ),<Q)ܣk?wcEU_B#B> 2Bw.RZ?5*~gTC 'm?StC u뢫rAО.9ʿ_ٛe G;@8415e&MĬ J Tu:Ma1+1Z s\;.fXFK) K̦\N{?  }5ֵi}N9ԝ'tv\zOeQUT`$Z8m!4<~UC~4:EYV~I9!& ʐqG{]o0nT`GlK + 2(+{v̛(P>u>af(4/?SZ;AG#2YDxTM[[wkq4;)OK2gVtI]?jOw.&1GRK)$N';O Q'7ϧx0=֫(x>^"`i-lIB -tB>p$;%jnOMg)츷 K{[r%pGk0m!"aJ7P8rSFW&HLvRlT(H|"S 0r-ex=#8s6~TQZNYOd?og^?4Aڗak3mIdqp;[À@4D*Ca.sk={j}}SfhԢ@H,n*iy_ܞzX"uDD(Pbk AJL1}L:paQ Sp *?JPp=pTB )IJ[I Ϧ,ҋTD}Ga'!JHNҀaA @0ROÂBSq,xJ)QM넞uE1P<Lb f|4%*6")̄b#{;j,_=QF|$7OlbHCDpی 0tBDpUbyPJdH=8bJABJr0)ˀqPba &uF|A? cP <2D#BRm :&:$fvFda!.D`@Ivmmf( k|{aL&Q@)! $ELeZZ1 i]1nx tC`G T˩c,yRRB'o ߖH'Ӄl$j/MP鄘 =pӪt1R(i$^1t\X$w`w.GB@ ~C=}o̘. J{qc$D!& o۹NHI۸jSgtDpcT"<&sD1ma%к"ۋ[a!$Wn=2x%NC9vhiJIqTmJPr|MR=21SZ;y_s> keLFޱpn)=.:lXm)KQ@Jy|G2L@m&G).몵 Uy1J!IZ/tE1$G|2Wemi"W~˺DpMGRIk͗e(M; 4h $5$$$xPp[PGV[`CCEч>*NaֻIe҅t.FXZqg|+⮷GԞ=hQ-ku;'R|Jqqqq _TYj"yHL4x]A_퀫ymlx[A%++ sz +1elU'VxGf⻵L7vGL-Vg{GA5ڥ~+2.>*j+JFԷbT(v<9bn+9.;pྎ°\:ٶx?ES2EA+@2!DVqZ^ᔋb 0eWlG}Q5Kn-W )}V 's}jT\u)QFVl%ie ).jŒ,K{d:Oej.7Ӊ]t[ Y7y[aA .g4} ( >BqPvI L<~Ǻ`ݽnŒO686@( r)7>EI_g>le@Jy O\7U(m酝I\M8|K ߪagH0FPh"3Ri@FzxN2ն9WKMw 8#}1SEIɿ5#' A'=F1W6<ٔ~?LpQp&aÊPID. m$(!!Bb0jd!^bɰMOS_Q;pN[w.SNPÊDs.nvHNDE.#s1Y3 r__r0@o Co%Q7V*hJf@r޶m6mnI.9%q*|Wө⇷}xΙGrJB5:-K7$#'tB>7LA *8ÂADX^<+ra0An)Ux:!6+W=IlE=N&Q.A 0`d# B) n}bOʋ[mN0#@(bPLqu<>b9 *0# 2EI$}0b'qM(DNӾ PLA`|$)n6}0F9H넜9͎<ҋT4ہ넋4qa%E*/<yD4( P' *9?NBLo6$*qd$yaMUԴ{p;ap$1Z၄ԲSJBaG2$j"nH-x ͮiR80bU/qYmͽބtD]cL1'tF!+o  bHC<Dm{!̌DE%(  Dlf { SH'Tp8O${aj!m;'FI#anm BLeB(B1W[ BAEܫOu7 I(p#PQ v /W.(b# d!AQYRb,J# IM3c`9E8JPI DqCLAG?&D/57>yΨ( m6 aHM']{˕oC]\hظ;/?IGMC/S{Re'wו+?dtB)YP/H]iT|S.6V=HC6+OG~ *9+}ԔM tSk<;Nuez Hoe-ϡJ+f6;jծLq')wnRCrJ8G_+u}B;.†Qʣ1ODBPR~ATZ? MݱBa8uͮ< ooJڽ2?;!(hmi$[ǰS8ՠN'&GHD /D`5kHZM@w}ky॥O3wi병Ij4ף9-O{$W8m~BxuN򃘴="+ {C~_ CÂ\'7(*YR0|vxRSE\\1H_n:"XoLAT@8o & 4D ->tۄY< GYEw’Cp-0!4TQl0H ppDQkŭnlȀ'dZ( )#XHpax*) ~TkvOq*q0A?,! GE Tcqon”`Q,E,O6_[wQI:@w::[ #@M!H% 10(a{w8\5C @@BlęF! pC-ja+u HFju&uk~U)12+>)M 7-H@'v􏹏fao/~`zU^H9Wt=(SeZq/5Lc)GLb:6fIԮ]:Q"8 BnMޤsZ4ݛvUy4<-C\?Wp1ֆG?`4g:@./qvCA,@jgqhV;\RfTrVJJ[lneqkBQ?ƶ 㯐?2ܳ3Hh&vKw[9Q> }VӉ6;lZ΍0FS2t敨zdtOh(6T]aG"}[q%\[/ìH[^*TOK[ x1$گMBo4C_Pfn1f iDYʙ MJ#'cwۢA-t8'VӀqtҰ.Or?=›+)f f,:&81 8o4&%288?Ol&sKv쐊p<f@&ڥ-KlG)&< OJʕgG2MC -NGY4͢0.Z~"d7ZMNk#knm(Q1<}AC1ZV< 3ZJ`ˈ=G (ib -ȅ *.!Nݠ[ YOM$"`9HDG)z` @Qkp$@@1E$9ryM:@E8RRbX$vT':i#tZMB)Ȅ$Tp˪JyEdDsbBx9!Bzl$pX9a q HHi#G8#(2DLDnsS9F&86HO8REy>`#t|膘":CuF&)Z 4iGn%O;J9;p`V-)w"<]^Ku>hy$D2x˛ ;YyGԙo.i3g^ĨiJRܲ*T.tמk`IU\rSIA9)q'MeM422c2lr䕩V҈R2JBwsK-rjԚC[.vb{Bbxi]W_$ooQe {0N^7V\Gѕ%T PM+$4{]ItuRd3 SBK>2U m[Qvߺ98(u3 ,;d1%{;`EI"biN =n{~v<)fb.eF@S%6O'充oW>}mup1 .?MJgDNb&$ʊv:C *m<ҪZV\r?I2m\ّٛrd2MT _>]tK{-q<*8#l |ԢGFҖ2_[9Inas>=NAA>MiymS0,nWe@& %E4!EeeT{GaC8/#B0d֣N3FɃ]W &DbrRH/&A)~-x0Ԕ̈-8_e+䀣x2㧢 vP2QR?fz4 ;a˙@c*D)PXTՌ]-H"ʓAܛ|g`5&Ⱦ7uC{J(]P?U!GSè!H? n\ws]ITpQ7bPrD=L ?\I]eY@{M.$B)3  8 ۲!;d,t]j6 Wܒ}$$;7@O#_P=Oy~>h:r Խx[RŒSoIO/=EIyS<*\~!>$AFa옖Ng$ 6R!˖sK>Qg w#hZtSM(r-&\7'}J^vLi׈J$JnU{q8Ipu]%priv8 &tfyb i:qPU׭T Aa| ?v?G~]VYXIH|B4Lf<Vvo1l(zxmBB87@26rx]!5itIfgu#ᔲUqΛ] k[bσZA*ݷ2̐S~"0GI0뚽k[RSڧe@w!JZ6/Q D} W@ϝ:LNYkI5>d3( $l,>wۢ1N55LýxwHbX_.i'ByJ/.3E-58{X2Tb q<|Yw J<j1Ť3V:V.8:hռq:W_ɱYO(Hi0Kq萧R> T ml g1+qnnxOUKt3-"Xq6V߰CŤn>]WUom:X&{uoUsN_]f“V:JzA\{w[U4ݬqG(.nl솘\X[JpaFGoQô_>Qr\Nu[PIn{X'dBѩ[Ỷ*#_2|݆bdUk\!x>&VPֹ?᷀̄r:0_KztIs1R|O@Pռ} v4uVoF?^jjL(2#)"Zn,KCan wlFwUl)5;yY tal9ro]oW ]Jk>mn.M</CcTΝ4t:tX)Ǘ&35h֠\v,C)$*4kb^ :xϒ_W)1Nƪ=83%xCBn!)k1bYOAq iѴñ i uA°01?ϩ:w'R7/nq\H\]<渞U# }:T 1W}LVot%QgG|tv'3>:kcGjK>-v-*CxRE) mTOUc|H63nG*˰wDGk~" u ~{V7`Pjx iI!}6' 8.HafK飐.R>lΨ+-d$]\[P=H@nRAIdeW ߇īq@_*5="=0_PBBr>$53ZW$S*؉hQ2(;άQgF\nf[?$LYҋd~WkZSFL+nÕۅ@0Pjco!&T}XSr`L/ѕi9[^y=>DР,1<+H2LoS S7 S2yo FS-iY5gOCMsp/TyI=$2"?{d%w(whp&KxIx sUo ol^ OM"W#YZ 2h &޿įH87MU]vI(H=Nn@Ipjies57+GS jڦéPJ*XYTM+O"wۊaᕺwAd zJQge-(yFLzjfJt! AcJ;ȱUrODjX^/au.h B H9$(uk6g2u Zy6Z\E>P).&$v!y/qͷ(ܜSCFKIRw)SL`~|DfHrM0二 %rI6-L%* n*.VsrrLN*:/#F GS#2 Ze/GH˕E)T\@q xO0> IJMnݳm5w,gڸ; #;劅m놝S"Wcӌ10SKP-{v!,!b[if) FH)A {9h|a)i Mx1eo7)i Yo۔0mRЎ}J` )i7=<<)΁'ÃsKo_ 2hBa`F"20oLb4:*(6I's&e XΨcXs\@U Q D"IR'_ӷ"Hc$xžM|?\K*aGsl Jt(28\5FPnBP{  ֱn'DpBQF*’Q)`užLDlN3 1r\04F O YV'&Q$$$1 IH7DP8!0t`o1JnǰN #Z`d{a# VjP% O %2~& …MǡL-CLrݾba WLp\ax#U{}/(+,Ea(QYM, x ”!EL$I &0(Ǡæ 1 @P6*ʓUvXY/(H rkw*<6 u^VВO6oJ`1{}>&;Q9t[] Y}y^>6Ʒv$ YVE͇7OhOss{PM6x~ 뎏g -33q\~ rHq0τJs~ ywrTBl73R <& q5*BfjU#\+uǯԞ6w#[]?\fvo,S&"'BW[ΑDDFӽ ](q]J.qTqxF.3َqč*!iqvh9f~7J]hHKM4Ɗ4~WU.$^u@Z@<ܟ5űKb׸:`93UE` ۗ5$̔Fy|a;M.qWT:HjBYbOʣIR4RG鋶Nl|9ܣdemgoLRz2e]Es8'HIa $w8M]Z@$`wrk%mqlK<~ ,uJ3(ZFUn2n/@+RSt܁iOoMtI7xl56y;͋f Fm3 ޭI9Fo!Y 8W KrUc p8`v!0堉"DtNP_RVQ9@P#1EyCKfq#&'5Ix#Q p/΀1'7Mણ=FX F>;[wDKLfp Sҳ&[U[̉'-;Т%%3m[ي`6oCs(=cÄvA;󯂝CYes$l&̔U~IŒUCH5l$g'4eOJj*-U)0O" MUtr1`x7HemjG\'^c=z±|GMCN8yZEȩۋco%OvᘧN] >ƽjN߶lrnuc|;RyG>YIlPrmiNGQ, XM ɺgwD,CzڂtdѬoR-DNf4 3+琉ߦ]̠44T:9 )ln} mP![xs~ugv)\ dmxuyYu['.Ҿ7ά(CM9TSҚARb.% D)m,ZR]$w]e 1nOh#s~ˌeC c~Xw#arM̺3~ӵs>+JK앝ˁPPxM)xin(@&\Zh,f]Ú$>xgP<֍ZfSkFHft(c"f!Lt拫+.|Vz(}b.1t{)jvN3D3Y{vp ~fPڃ2-1>iMEzqde sB>JAw7q?:#V<=INY.Ns &Q!I>۠_0?pl ;? })/iy'>%|[ƍK_jVs3c?6 P6GJPuI*eg<擎8ukwcZ_ 42,b#u3Q Z=[-?%lKvmG'QZ6b8O~XDhZ9 P vи#bC]) >J/Zoai6G"<6G2<}wE(#mu2 ;4`S}S=d4#$Aꆊ:ɲQr"A FJ-0,䔅J.R_Mժ67@ut1뷺Fkвbg[Yh|G\E)5=] se'wf?hw ?Psf-MJ@2Rc`sݢjm NyǯGTw@ L̹kU5ZK~U @>[[I$ۃ@8գ]^*5U^Ty<ɗ{smcPGhmv7eYKzzศ]W)Rȵ`J0rА_!1sGB֛iǾ9׊m5 H&ʍBb%=]\9$]<'# A"׺ dJ7_ J} @Tk_kz%"NBQrpR hT{l4E-/$W{<4J)gn@J$D'M&6E9 s "QBI# aO!ޘIe0% ,%% ,@ʐ(ı&JcIaN`1,)j)?R1 ! (GHNRn%>ܑ'r9BHg [otFR{$O$0pĀ c(=m1piD 1'm @P$)\P]pdM𓆍Pˆ7O<"[4 ꄘxlH3nӹ=: i40l6'Ԟ)05T]2N"I <[%1a6rpQIj5A!D aj"> O4<'=O@zUcEiOHyuH'+[wVh$jOmiZ( 4 &%eMRZqH[m$rbG($ۦUzQ>H;4-*w@^qT]Xͽ%JG?,k1.c?+ηIJL4Z 6)8î!)udEziPc53#> |.:(4|$6܌Puh.mrnz5sq A߹Y ` Qdnv-{<>"A\qS? o$L;V4\Q(e- Llo+ħo:7O;)9ѣ憭6KF2f#KIA/Ug&hS'8Sri4hmЃiӥK4WqqYw'┮V]D1!|#&$DMgkT=f<9Aݚ"<(IT%Go!DnQ&66;mpJ7f{0iZA;'tPXrHX3o'KN&Qim(+RB-*.Y"$abO׺d: sFPg}i:SiZYֳ젗4暂$Deټ5ԸtJIYQIBaRj %#c4kzÀ[-5Zg?0w^XX09R0a$oRʑp=$:)JASoÇHrNܗ"KFHܟY=q׹;u:Pm&\"Z K:5,z-@\&yOw&iPbC$ȫH۸< y>|O}TBA7?Mcu*G ٩7\>B /G>Q.)z !N֚Gm>~~ɹ8sM|z(tI݉;&'N$(A%~/vS8F#vwL_:頦Fr E`=+LUQjprNX}I 5)}Eҭn;li%Iv-|/>fy[-d>qMщ֩ eh]l_dJT.(anWqwLwD=~?^KnJGz2yTJUᥒI(l珺a?yKo x'eZ cx_%!5ho)!䏽{[lY!:'缦,mERF~1rM!e`cB'SjK/RlTG=?B8?MkھPc.i䝌0%\(z:̬au)+}\0 Υ ^'Ē!0ojWUKCB@#cr@ݰٵ,dJ6R%AN([I 6QYS4=Rf)ӤQj#E}N9HBW{(^U "أcX*2ٺ c@]rZ48wN*[L;cF'wEF(=03R msLH!FZiԫ ?QGy(5qL@$~If(N(œt[ =6,sFUǎ=pҟ@fbl™E 1<D$OBXR&"  GoL)9tCLB@6R!-ߓ) J0e)tjc 3 %cߛa2HF6?p$RP}p1LВRRE$n:$<3  4' , KH-lTseU]9Jd:s6|3 VNTyn36_e[ ssgrJٌe&FO4ޠJSW8oKX_IvܕrTR˭Ncͬjv_rs{JW{OG.[ηt\?MF-RרO>Or*yU:0Ziծ VSn@im.k|xY4Z֎a>'Aa\R\Oz+ڏV"q6ݳ{=P8}2U?q[Qn[gPLoˤj4J~G*LA"<pyXE]O<~!&w}?/OjPFZBl!7<-6Q"j>ǎڶasrfr>d3:vNy 6x(Zpq N{-ZŴ+8AS@JI.ZFV 䱗Y*}Ne ؜<; e$/zA'cNtwg~+?dRF9qsp:Au8NB[p?ӡ<|&4oȥ6EϜn>emUk^1-@!ᤍxH_(]PSfU)a#n߹>gZNjI)`' IPmՁ>iۻr:#٪UY'ԁ@,1l{=2{5#NuE QA*ҟOl NbDl̈s~lyA 8gW8zGJ]uHO#uz?պ#V:wOUz+Vajmqq*)@ ؼ  kmlڻZ:7{} S/ݎ9iiȎv'xJXa)*BI+_bzsNEsZ8+ۤnQ+DP뭝?2//kԨ-[{V/Y`Okl<[:qrk#cŔJ pʿ, v?~u|yOG[}ΔFYGYs9j[i `ĵʀ?>j{Y.2ۦڪɯˑi گDr^l!.GĞBY2C*hAFڃ</$Z}Ʀdz;SYM̛2HZКU\Ya7º-n29x=e>*ǸH wdHr9 $5B6;`?~ jX#~pxuK: dhyr㿰䥸ծK(f:T*{Qc!فƒ*"zV PIH <m aӳsh:FUN*:n5zd7f:5lHsL1m=3Ⱕ)d,_/z@:Sypх1n,t:@)Xk yl}F5@Qux}EfP*s1llcȾJmwlzCnH69d漁sZi'gӌ3“s%B˴cE"Dꂤ92Cl& U/rֵtIYv[01PֆsӉ" G6$͔&3Ps1|ЮX-Ϻe?6y5 —N QMd?'.\*K<[teO֝< H< d z+3}z5S/8!W RiڵK  H+H)u~-®e)pd4܍28 =ŗ)6D.\1o}2=Z3ѪԝcX殗鄧pMC7g|HD8'ɪFZp2%KZJ )`#6HaRHJ~{3a$,wBɆ((Cu6/ܰ'g9yJEM䐢ߡIn,l&>S{йA(U i~O$'u%5IaBDjp)wA"v?N$Ą%$`\2AIRkt%5);ob@'fD.p)hz/{X! N{?UgL;:eIJWWԒNP=vǙ&Ǟ0bҸlolvW0:Hp=| Jt}O4iG 4d`JP/RII.mX6$q zշ$)g > >1^AI+Q)t`T*s)T企X .j'ӎg`}VekZvsdjcE0F*}.}”Z&0$v'DB-qESIH@\bI)M܈\E {넜& NBǑ dZ:B!q;m ˄Rܦ&ŕmtG&:SpS\ahsb7!i!& J5 ,Q ?a57(h,$hhG灙)YCe,y0Ar1!W0QS G7 KW# I -0E[a lJ9) 6Q􃵦 Q8#eAD BtRhĦBbf{\ۣ HKg#TJNBIJv1uQ>-ZIDH4\7OG L5ɵ(@I@͸c* ~Yj@EyL\Ú`OdXihvǵhDjb$z1 vA =p#krF䨤ߞJ|+o0Y+GZ%npYP ;s4\Cka@d1V ~!eq,Kiq#sn!Hq$}H(Ff59΀%%>.$$f%ĕ WMnHmwi/)L0fstw4<2S-<P@|s:`}DUAƜr2 [u! ci$S3ͳ(y ^kmĸ8600_v[Xn@3 z/~=MS3ElqfC˔ҁ>xbNO9}@K{.:1mȕr~CTi-{c܃D.ST8湆ә*eZtȇS'u›Ԗށ8J|>N #\)sO71┺Z5r=oWc'2'ԷV@OH 7T׃˹Oh 65A(>H'T=>SYԹ= rMU[ۆ5 S JaJ7(rPE)tNCD ݴןaHWK}S#4L"qbvL tsQ!M QVACV'OZu/R3&3'Éxdv0?{߲@*=cx x4w@5+E.:w8&yZVj <;ᰐ[eGhKޑuӤ֍9W )VMwgni.VjCvManq:JBjz>j~F %a)C= r,rAFq&SPDϢ%\CCb(T\Nrıphaf`.8>Mjce32.ⰯF2 tIЫU-kmQW(=q !A&O&kDi]nlהZ+osrg_j#hwIfRiXyca%Op}dy(:6rM)IX{k:s#W7yV1ә{~auSli%-RR~W_-`,7u 'I|DTGBIi_}~6 .&iPsp~1*AHdA;@;OsZ::D$n^ILz$vX q;&pdI$\@@I`D$A#GoQeD;~d)r l}釐JmQ> e稽8g5N!t'1y,E{~O 'qxx{+8޶`˺'2%) L–MJÉaRq@}Quk{ѫ&|$q/D-Dn\NEy5;\b:ܵiT:G;H6uK|Bx+*kg؃8s̷}҆"-G;_- tDRFFw1< y6SI _?,苏%4 rr5E)@NUfiZZ0?{k⪊56~E&ǵғc6X >eݸ7"Mz%IBX.RҒ=ROtVޝJz=A *^پڮW__YS,C&τNz(+4[} +VMfc`p )#da| ⑷<5i qÚ(@ٱ!Z ZiqU% 7dnO>o^PuHH5*T;QaRڀ6W{Up @⧫IuM=ld(Xp>!}hςP˞;}K33O{<֦B޳jֺr~+p^M6r{qO:ڄ[6$RM [㕯-rkv]~ Ir'?l /[}?j5:[^њ9 #U_xӣmO܂A#eI|< 1( 5O߾mcQ=F}Q&v/sX}$$LVigcLohUi .D$xÈ\ Q9k_T1tr\;)өV̙Յ`B+>҃QyÔ2'OWR!ii6Vg )ԃak8^^(uW>yF(IႷByqG:/kڢy/:mW-'ܕgYFi=jYP!~fl)%`؏J;n⟄e3M>UvU؅aأ"4DRnGk8j%@^mݤ┞7%uL)CO#u$]66'_#sNhSSNHva?LWs2&vr2ڦU74N=`dP-iѬuDӚZYnBUԵn@Xߵq9κq3jO*fLqZ_`dT(IigC+%8\HFT:<> z@mO pA<$Ȟzy䟵lrq! s\ Klj6ڥJ.~f<+QdܠvI_\Y[3 WŠ8dwtkZN0N#SC$S2G!H攓Y!>77GQڌ`is ~0YND}^DBkS]&}>Ǥpn|*R}=Ch pG"sAR JPBJ=>lK?o2ASj;ȣ*ͩHG߇ߊ%*Eb6$TUI-ƍ"Cʲm)*R}H&L1.q$rsXƗ`'@\BP+dHqNzXj֘ 8Cz<qR W AmdSlӔɎ1Oqp$ӜyUlI'k\ucHc%׬J))jIQӻ}c2<壵[ϹSO`O1H}^X͡$)dpl9<ok ZcIɱnNFw8y7:-X܏N'T1=SiKbtZdd)& l؂>\}Sj% :5ԃ 3 PJ}\VE1]ݮw>xm^Y1뷿M(z8ZCK a-} y};"a&J&uu/<P#$޾lpi7lCHܒ˥_NAZv;X= ܨUe ۿ7Rjg^?{*ϗlA`bV:D$(8:{~aށ)Mj2#/zJBp oI#X)lEҟbF耓"~SC7 K؟_LHy!-lBF$f3k /)$pvHMIeUx0yKX tK(sHu=$s nE(JSa)kN;i.)H J3:h~A]-Ui'ùq˼P_؋-Vʆ%hzZב;uf⭕aY=iztyI\{-@T&J|4)Xn$,r/`ZN11+ mkx+iOs&ZDlʗ% N9V}@;Z#6:QQK%_r6?@>Lk[6^T Y]2N0+eϰqxz<{\vGp Z;Y`!q碟W<ܔ6Ɠ|'բ{ӑ㷪ὶg[wRO/R%،Zmf]dceLBρ)OFShݏ~xb+uL7u^Z "!'үF?SF+i![PW$P*X9;\;rS ,·_l[p0tYr#QuLJt˥b.p@jck# C$ $^Np(?,n9>p0$:SIIl9 %M$' :5chJ hPQ[&jb>by'ʯ`hMM=ĀI bPz DHCk_Qvt(n'[b<ګ cZ$ Gڲ'ӎ8&20"!Jd"1$p-TA)i``$a)Cwl244lmY'bJ m@<UˬcNtc`P(KCtE]ɍ!l<ݔY@bp"B]E>aIC* q aWj1 8톒`PPAp 3S{miTc8g`Q%Y]gGxm)Uj m--eh%]Eo婸ęTp!!,w;_Rw\Z|{M;Y8ioRg\rԺ c 51 a.o̢lPBI# j(Q4D.g^ ՗ 5s\2CswS52jF%Ꙩ52d5TR,%֒.mR 8tOM61!m<%qF.cf̎nAvjM?쓯=r2TtT: KZčD5uDm{yۆJe *e>%-HPABBMZHTi#fᰥ&~TJR=1؟B:C[إk`-6:W g A W9c'f;jּ6ׂn) y _p&V"OϴLψ]Qv-qu5VTD%%RfD`jd۸RR}{QQp~ {ju0#}xC,̺+&"S2zObdP ITc^RXat =u,N'Z"WF~]T$oPu`חu]k+V-e2Gn#l$|Fq0`M=>N0;M4|Jpe._?6F,t}f7iF:!LjĠ%G/ގ_QΑ?aWG,, |{ G正bFx(ac?W?NSfyզ^4)i6Yu8y=qłsݖ hD'Ę;sL M&I8I\`Yk>4ݪmV.En\wvoGcO3>l.[Y7H$m/B>Z`j)$R~#~G%]ܶ8ҜK Wy"_RR-c^ٷYM`n+:<׌rk|zY3E*ON]m q*c,jJ9@/zMuBҙ Oxn1-4@O\ %rmsPX:!_1\ 1yDw$vH8:-\Sl4FgxCs᪳t͇..338v-VFҝz'*CJBKO~S\Rp@$p8nqv7w-A08]x꼊ؿI[DZZت7SZIu|،8Zt$\}cetyqT ՘jz6|BW,$j%m(R"ê:jgV >GNGfbB%a;%xG|) 2$)C{z1J)oqVkw~Wx9`&Q@<06xd_8AaC lLTΗ)^~R-OG4Hl(%FZuܟ1r-(M=nn( ?3&@Qb4MmVV!I= Ik4e2K냧PO2萦ͲiO^?+lO~ "X)7 M YnĐ80a dتͿ$k s!#v2|K2E$&v8pb $S|eKY&Sp[1e(} I`BîbJK~,HMge+# 4bd'4=,NIX)M/vOODS=9]uI BDe(^G1+UqB05}O[wcUr­4H]s0).DTA=8zn$ΜnUZt[1rUW4ӧܟ/N!l%*YUַw]Z1'hqZPY$>eq1㬺ikM_cpSW:*fnERPp7Nao(BQ?ӷй:ViO%%+F^e2,a-m\/:8 ʅ$qW{u[:xe-^ƔƯBb $gioGqz}J$,IGT}M$3YU '2#34Ȏ~N,wΖ630-m۰X_lGQt 60R{ OslHURW.qpD PMo"QDG&lK:)ܮQL)10.@N(DPJ`Qqkqas|"aZ6ۃ̜=0E_ g<@l6?PʔNu2QG@0 1RYGۜ,#\tG5T!aqc.R@j!A_b8;b>},MFSFq 1nn>#iHBm$&Q/{[kECLez. |oNe] #S(DZþU.C0aT^8Ճ2u]6zˋiV=>,3dkNRmUW=Gpd#b7<\v?L pt4nޥ.mfBo9_/lS*@*͌<}5L3.:ӤFܜϓN(gK\͡ӠQ;) l|[dkީO3hI<ȧ@}5-|8ZJT7vj+AꂳC  G0WZ9pLW7zm)(I̿! w"f5ꌡJ6 BSbcLrUk\NqepѠL99U'35+v2U%Ӫ6iY^a8{}1G.evy'5'wv\G_l 龑"fm1#a̫JZm]ӕÚ)zREr)*.`^:;u£sS?\E~pӼ~bD+6YVKրf h  =& yQm*l<$1;osc̚.=i~=fĖIqx iI7nnRA>'? ͵Ck 5@׹eV2F ;ǘWpYVk1JiTbDP.x8mK$Oc:Yp2ȃg۹Ѭդ|gʞBk#iyEKq^gb7!I#Af]5G[A^6tNa_1W+MXdдpGȄAQ۬=W)kt%) 8bG'h&!%MR,~7R8Fj/JTJ: a+/DOiBPCIݿqB<t+LAhWM9VByjS QVp7x>y;Z[>4KLi馚̸KZ *v:;}qX4wswF0F՘Q;]4G8Yyɳ+rRA$mMKV843|v<$̃:iŭ1= 4P4 vvL [OOaֳ==6qNSɌ<y-RH /acJh+9.s8;1669F:.m1fCii֙h?L4TL9FvXCMB6=RK`ICǑP=΍W^iԇfAV+iE3+fGhڍiil9 hs1yZ4 *R)X%1W-}Z_e ev_dC:G;9G)}_.@] Zt-I{\b7 @5kiIH*q9Ws k2;[l73<>'n ]q E)V>6OV"S >Nr)[:h#`uYo(OZ~e0b`xZ@V8.!NN5<~zW uҗ߸(yܑt{yjSIRln.܆ݻx{2Eq ҺAWs>T1.%]m/Dbw BMtaw%Tik$JqV3?ӟnxm%W-1x٤=tgFI}:U,&FZڛA>skpRBJ>%P]X\vkAZ93w%Ka,eFcN9y8i%h XoVrEB.WLJDLDd5CABY Ce|'Tp1K6bOq 1 z7:I5<'d̽UQarK8> ֈk}Vcẃtz%eQKi(J$ahHNH?\et{ lT]q wvju ʿ1VDB`V0"RpWk֣ڱפ=5)}5dҙT[^2S%.Hĭ_x94#ߡubA>_ -)Y>U\V5 Y-*7 uY%Aat0/3:AH*jE34KUs[4Nm)SJniBy%n1JFq<#-kaC忙UfiZnC,s"LJ\Z\H6Suvܑ}7nf 4^5Z]'wGu _NiD @uqBUaŋ,o+qA{zZxrM&e-܂oe$@[1ZҺr5Qt?D $sř[t(.S=8Rzhz ܄X"$)t󴫷p"Q "RqH>cbv(H>pe(EI'0H"pH@Z 9 o)EF尵|02R! 䴐,a9Yn=(anA (n9Q̧]ށ%Lxܓ{'C (7L9!Bs 0Us:#71(hd_k\6F֐ #*o0 P0KIH'8ƈ*xl 0nPRS=p$qHJ<i[#-*أkz :'c%n;{ac KL^8J_ 2JDYn'-H00aEGǞm.̎>8$-a%% N#(BAn!:{f^Bҝغbcݬx=8~uWmIڰ HœJL)Wd.h*`H؀6\,r`v˪# ^P;ҖhUGHR XO$$0Z4Xb7VqE%U lGb%/$~G;XO CoXd #&m6+E*ETw(LIxj UܓdhP!f l!'L[ل]IMd}ZaRXEY<||^ RPqM{mq|EIoqӜY%$Y#nIk8Za#转7@ Z#dZnq}^3ئ\ߝS7*arpwHǜԆz8vY&`z`{zѬZU4ݧ:+N[AGĝCvBow7paPxSp;r^fi=#/U).vm2FwX>KƜa.eFj}k{!hXfSTQQMJ6>fͨG9ٷsг_: 7)mBo98BZN<n{P6|%Y:VynS MQSUKWplF̈́z_=W;?d) {}!Qa;Cf[Z5*&['Q%-0]yj@m*q@nR%ĸv,F=g߶ᄵ$A2ܦtYx@5 q\A'(/ͤ˵MMԬϬz.eʃyvf()"&uMG|ntv@~` 1aП⛣= ~U\K@. Hl TVGiUe2I*RZ: ! H7[>ΟalyM,h 6!\#e_Lz#TeV]Rq֖cNse:eqZLg$jrk-ePS~( +u=x&ݖ&e4%je-PI<\FәUzQ߯5K_f n8Oq^߆ڦ1\='Iu%i !+6_j׌=0+r\V#7^K?D"CONS-fPVKJV x_w[1O,x1.W]fjt)iL1v6IHsm\RZ4'Xȕ5ɚ{?Qh/:imSJ6k/yqt+55[ eB`4wJzI#Tg˜;LrhwK r-j+OM 2TREڅ'b }Jֲ& i-hx # uCVq1<gHEQ=A2"E>`>bj /Aa>U[F RŮmQ^cs!mͭ7#؏B9P1-pi9x]MRfJB2>'@zSW7*Oahy4֛#,[3mPZ}1#?e62<ܧZ*_Nw8/J=9L;zjVF}O2dii;T=A|IRtZߜ*<Lqĩ!ݫuTRPJRJG$z!k1@_Fɯp| sNn2d:qv3窎Ib.%ֶBŸWroy i[ ~%nڭ/zӾ^b-O:CHqF܀?tf֕.-'v9mz]#͠kpijH."Xdܐn@㦫QLJʕ*Dw=zʣ^e,J]NǏ*K1j9Ҋˎ*$[o|ʯhRAqu0Hؐڏ']bH^32sZФHH  e:zގaΧPaDUZq5G ~2ǹMo/:-PUJ_pCGRQp}.O ױis+WmuZu^7-eA>MjP&LR\ZR6蠟=YM{.yԦ6r|g9P&M 1" R,{dЉ:R]GSW;:*[0]{t-'R^B]R)Zq@A4heza >ڵcJkA؃ [ 9 ]%% wp&ֿW0&?`~8# ܀'cPAM2>M(Y.o܀G B$S^H{qj**j'i !7J6ls,0PiZ NۨՎR^?7?<1)'oTL4W|I@6Kl HnBd﯂E.8mD2y=Q·%4#iI}8 ꄷ"z wݾ;\O87N;S jb -.߀pa<ԝ# \)n3~T\.#]leO]OKn!Ċ --R@V{zqO ŭ;BY_Vݸ5SQ]#+~'zG֎.eitȱGN,6ָ 7 $$i*ǚb=T\6w o pF;ixpVfgM}d([Ej8M*&V!ӓk\R*RMSk )pt.9F-4LMjmRV[.SzL++[(JQ=<)`c GpuZLJę(;2%J $@5L}%_Uaȱ+FV)gú=uA9ǿ^::дuKwݐ$ Jq"6^Jkw?bY],pw?_eSm22}NyG̔Hl6[T}6 lm` ZUán85P6JtMEU+҂i :HBBb Jolk^f@**+6k0#%eV359lR%qϖAqeO/N:6eCq=g6u-i iGq+ii m*ZH 9Lv9qAz:m0qB!Ƞ]6ӌ>Rve ?DXD*I7BX"P(HsNRwad}l< ZÂnTCn,\hLZ!7WhnN^8ܬmϦ&W(!@j)axuxj&mXzz6Ď~2~YGe hVEp. #r@Ԣm2UY^K'º@A$ }Y0J5:_@w\+8:rwvG e D}Tr̔KT]~ p_Ľv޸'> $KqǢbdX ,vjoS'c_&M5r -ٙ$4ߊdycS!VofFJuS3fKBZiv)U?Ak"0>5o0 P@JAUÓ{V1f# 0 YG4֔kzu2$m?b`Fܝv-sٱ,uz[?@]VR͚MLr{Y.M"ZEJBwnS#]mpm;2שul03}A ^Մ6 yT`mUnS$2ŤLmF$ r1EЬ3-{ua. #1͡ڎ*S3DϔTrikQGW=?>Ja9y8|}ƺ/kdNp+6A#xhWGhp0Y>+{d'J=}v>T 7%u72\$wZХ~N㿈4exh~C}#+p;ZA LD]#-Q(N,"~6IDŽԨlm6@- fV#$\6.GJx#ۥlsܓ?=gźJK;W9i-SF`n!ѵŪ<~%˭rRZ k9d ~0aKJ*Y* 7"+jT!DO_iy;1Ă8iS15P} vd>*Y T".Az#b« _d&]zIB,۱#u2\Vv#%) 4t[rBd:N^:A>B] C Qjt9m^i\zl8'nnSݾAcQxՎk;Ӝ0X5+SR<6\y{F1Ev&x; êZLIga(2_6mw8G{~\luunDѿ:*_odb״/,ǵ T."B"xO4ߌґ7ON<Ɵ^f0dQ<#.NX :Զ^P.ufH-=ڏC%*>)nBZe'hQJJ C>3kP;GH$#0XReۡIUEWK'O{oh0D?mS=<95äJ^`HEl`Xѝ${ǃ)'*u #a=*mav xbI;zg I ZD44Pԅ)j RScг2Ѿ9[hJI}$ -8WVc8`:q"7"x&^:,hq@DD $ev8=Yi֩sMzzL':eJˍe(RCۅےx8cUumq2t ;k{zX&gRDFe" +7jYo<+:ʋ3*Cr4A\8SYV+Zcu(UikL gښb8fX(%J>Jңd8#\UtFg?/pJii^ rz䑰 H6c=ou˱#&)MLTf󖴶\'\K &:o4X0Oo5xPG QV Q̨ʝu-}8;tkѭDZK'ܰ0ᦓ] պV˪Z›Z TI`+So;VuݵkJ #ͧ6v)Ǫ/a |G# h`EzfIQ9HeP҂e+f*q_G6섲D]=J%u>#8Oĭy;I\5'KJ}8T8UYry|#ZpIQe=Qv] bw7 $XRYq=A) X)*bJҴ|jR6**Ԥ|/zk]b!&D@_{ndjn?̓N;btBzAse#i*Ut!Έ+qlQf8~"DreD@{󇔌: Ʃ+mjqE.?`Sr0IhA'႐ghK,@ya&ĥے9S5K*P m|. t4U(]VX йtRd(s`sOմģ[$rbDjs| ʗ/ $#h4F;yp$3L,Jmc)8kpN@( n"tFS B8$@ [,nq\FaJUDY)[QP6S 'Dc{Q>oJS$hѣ__XeӳnV0Gʷ4/=Zy`y2HX˩]*tW֊F*$cx;YnKRocӺZ{ M@; ?y'q_d1ˉXL9,˝Sr-WUr~%_cV⻪V2INЫ6`@[!#dV|ZQπ]VavFQVmKWX S:j*7Rm,%8u} ~4O:y(~n@>ɒ|d>ˈ?O?lCU&BҴl5OP 3N3"Vze()>gl1&Ùݰ;iEZ/ e~$zx;t}42&4Px*3}_u<б*mu{f zrR'<p- /dnRT.V+Qukdh 6lW%Շ0yOqVcKr-3$ė?nGSԝ۲ʷsr*OT"HW b?LXmoVI:V;QT?P8SL95G٧m{ӵIeӵmб_<ƺiS56,I'{ g ޺VksuSJ9s>FB hWNh x5¤.{Mk ;(ӏY!їo|T-\1`ƝTh靥*|Au'-f f% GEfP( ˊ@upOcOڅ+EGܓg3fqv/Dgձ N;s3X9eQoNg Vl%rAʝ+y^8j`N2~׷af@h9 r4йj~O%>cQ?,rsWi ^CdrmvOUqW+B6 ǧd,[6CjK":,iufвm5s}_' Dۆtt?3|F\a1Lg#Gl]S5 ]M]^ @6Rb( %L2[E{{zvzBs]C*22 nJQ0"qZwNj4MD6JBb^noZZwydKTFՓ.Ppz [km\wHT 7gt+3y4-8*ߋ_'HT"CA/UeZҖȌTiH5 R 9gR,yON;o m$DHs}y!~'C!h}0U::EyRJe vC!?"N>&Ҹ^}@r*ﭜ7h`k',ʢːe)Rst`.s`7Ƭ;6 1 REAv u)T7@lfչ/8Ѡĉ=ÞmC\\nAnQFU-rB)\_%cq* oOmSs_!3]\ֹLayN"TFYs߂l-詊p&ojx`o` F8xLL9)h.@۸(}bQܕ7H[ )p*"dHTqv 7ߋǹ1ڒQA74~]<N+8Q6dh6'9JdH&)R߲Ity) Gh4\BoD*669fOt:h9}LfI|op(1zf80Kyz}Oᴍ#-3ߊVT(W<Y7 Ѳ 'JiV+@yNZ~5Ȫ5qsylk>t&@;9yPfݎ*V6T^J6ghـAC8 UGd|4[uBIDpsN4AHkA I S ZE<6j\[QO 6.JnӫNꡕZ3u_*2b\qo_Ϳ 6es+zѶ[W~KrÙ2 ާ4\''jJm6Ll}*Diqdt:Ӊ)qp}ŰZ4TxsL #QbVSj.9"xL S̈́چj{VEB*qo蚫Yߜ9-%J͎d_>냔7OZI)N"<5 +@t?O>,:RFFʣq+I8=.Ѯ׶}G׷uAp#c󘍒)4$⊭G>Q`TUL&PCmqd`I]W'äQ=h?|?u\ϠQ=eC bp&O({>TL2G.4CCxd>, 0MS+/?\?ӜLƀQΤ&ɾ Ф;9a!bfG~2FD%AJ-[Q{~C wAoԩ*%.ǀlJn)#<$A< ێ0`$\ X{(ROĀ蔄A``( l( D&]e.TnF8Q=8H" ;yE 0O-;)(cu'җRo$4(b(nH’ Nsl94 RH q RwI#+_[G?x)kk=ok_4ۦ@8U˳9N2aH oBmRBPc;+&s tSw]#esz*8 ^V|ru4uiǛOL:_%MCXn*q+XJ|b޲*yYKܐAkTZk>Sn{n^o~,w)^Դ[7\X=f}B%D6Ǭ94D Ai{,<fq׸&)*20F`0vOH>pI(pH/(֑%'q HKg)--եE6asbpBI@v:Yamԗ\g ~>Y!FWdQXZj4k\m?#5Z !ڄ4uMv$rOM2:J:b-6W.rSKgd 6=BؐOUck/oF%aftfYSl=mO⣏WۂkAZӤ(.梅p-?,`xoM4ΐbH{>'-YܵIZM z_OamoQ4gw֏YsU쏉UJ-?5̢ygyRyWQ<m.Z׏$d*@qi%PH3ѲҕSvmG saqV= n,-ժĵ;66m~/қ: qػsd,W;3&EJ7ǐtJqS-> nq:w8GG.k,ٙLG 8q+0m. ].ު^a%_Fq|c k|h[u_Z 1i-iy撇~,‘o+̯acj]p.Ґ@3MW$>*YUTmE-Zy^tǫ"eմ4 sķuBjT sXE]w8u-̋n+aJYO?=W{"G7W`e" -#Q%_)]M`}=?b UCeXƛQu@BLW$+.&l_̒m,W' tW/?n֭z+Aihhَpy`9y>Pv"a!v -ǀqG'}bֆ*{W<4S'Mp~y:VQ=kS}ۭ%9t()< >؎J];G(^zNshձ VӨ?b-/O^} 8?|{BmhaKy$a Ӣϻ^gvr N&TEAeלLQ<[U?x]l=Ǣ[\S4@l{ok/ZYY7v`O-ps] -l*`y|\[h;n9݊oMm_Y#sǼmUUiZV&;Dl :'E%Y 29a&:œ$I@oĽY`ܟǸ(s)ϑךL!n@LT-7*o{y|*U?~2$gxN#&k.+HH-)*0)r` ~( OA#'ʤE) lT< 2,}xͥ1ñcq@vB ^"tMj Hжrg6R;k{?G{6)M(S&q$^TVͳiR|8޷pZ*R$qn3$ɞ'}^KlVe>/e(~w% % -QJnv,`sqauufS$"#O7Kcm=ʕBLV{hR&b?Jf$! qěXoCuǐRӉq[H;tqByģdNRljJ mPuXߞ,q29Spڔp=?OlF'DRJ6?)ĺ֚Od8@j#),Mdq~B%'4$ȄT6.x J&?*NaR4\RDBn!F #i@tQ;>Xa]XPk 4nE{\Ne##Q >N Si[Gc8h|N=FOڅRoq|!==8RqL_WM hL|vݰ$Gu~Xέ| ZdUb Yjǥ,|Wt0汆gs,ߜ'|SX\8 = - e_cƫ@n+ FkOT"YPҧoB4rLƒ yEYxߟD~ @*Ůss7 ۵gb ;ys  Mj`"0QآV3%ކ >3چߌ\R P> s~U6bvLٚ˰Dd h$>XxtJkʣ9N>t c?4hV}2@xJ3ەRߥ*Ab3xi9N\r@pzЀq9a']~J:'MuD|*ك+5Z[Q8EqPˊJj+@HiWHO'VQDfF1>ЬcTPlZG8= 3Jqz Po|&Ë4rWYC$v?:ٳjRijK}ZCqni>VQ;F'雒Z5m8agy8o7>:zŬk.Wtܶsa5bD%p%O(t꺸Ubݰ81=v=  7U]::ǜN_p]Kբi;2gѬ:JYj M(m1PҚ YlHڹ1Pxd6Ôau ]HJ_K 6j:*T=-Εo(WdZDp. km1cHBݔ_P =`igJ "/OԨvBC9y!IJR/ܧZBIKgAR1-iw-/r:;j˫Kii$ oPEDzFi#y<;׌b!A9[PIhGppUʅ]^%Mm[G,XUvx/8 uN9r:]9"'ьp9pXQHmy*QRq#_}zpFWԝpvN.;N[֗XRtolZ̐dF6ʔ|?BpIPJA'EJ[${a(%P A{' ^!.P40ENh)b&O| ("耄Qo.K]ѭ0%\$IAɁ)r:В}޸o4a;%Tb渦i\mOrEH_PDMcTm_1L:I G<@_;H%XaIO)`>)9jIDaR )ʋ.$2?Rsګ*2Z#Pcpa4!!<\JToqJ@N1"l%-2V9m&GfGL[uҙa专bS 4vN6$kT'`%Qd1`Ul0%q26K~FSQR -b0Аnǀa8't%@f0U$`$Xn:[OSa#TsNSVQ}j&k5G U5O͑ xQ4Oj4y (i p0cwb !?q~0ܞU^U{8NU=LjGVOc8/_:Yn5$f8 Pvl}LC˫RLadtz\GܯbdI I%$'̒Ooo+ӣWQJҺ-Ԧ\zu*S4cuLĔ?q`˰.`\^)T4&OCJ[)\p j8 pۢN5s\Bu+s%BNHӀTۭYu;a'TbB9YNQ8(U!vJ)tl:z#FOV{3w%$8))iD\[* [mſ_XNyw,qV51HV3 cDCfZp]@>`& )W {D5zHK,,2nN%r.WWXU2[pS'JA <E.ଋ]S- {'<єihC5GDhc0ĤWzo8۶I/gZԃR!2FUMS5M1V/u$]Լ)[s S% RtD>dH %,{?A<}ԡٝQƴۇ}pBz}+>j,IUze$R)sHJfbd%)R׵?rTyeZ"; 2cvXi0:gS[ tGOD$k?qx\u8k Xjs+-(}(2@Z"JUd6)"i-)W(*<X:??P:;JX4x@JT?D5VA>*3s|y̽XfzPUvأ}G|Q`,ݼhZ Kh1Z*2y)fsup{qE6 kBww,.}=*0= Ij#8,6_p$$Mf jUI)ezKXa%a{7 &mŮs9 7Mf<4vG6ܛ \iS/5zwHW5R{)dƝ6J㯃lRIpz]UA<>1}Ghv* tc门y#O4IQn^Z] CrYiI} yڕnH}WQn1+ jIi'SjVH6mZsէ (,P]dX {vN:;nf= oz.k)ZIӉWtCIu%@Xhufu}!yVlF9&A%[ޫ_ܞ;A> /4a{V(yõ3r;!ba<J `Bڔ<%lgD:[HxEcbrĶ&) ҫW-tǀVͷyPv!OdΟ١0?<֭TomÝ[]GFv;RYO+pĬu@ b?Z')ljOn6ؑ߾};fBsj2+7Vw6"*9)KX ':kqZR-ͺ/I 3jVD$SͥmsjM{(qGnvyG뱺L O@8j&5[+,Łrj GĈH6x c.lZ!y=sVŲ>jeQhrN|ÊRTԢnŶjʒt TggAIcbuN`Ȁ#^A3VTi&m$&T R(y\M֛)'5ץZpD~GoERֵpH=vd&Oi9ݸ\׎AoP@ *2H8o(6XbFԨl:/Gsޢ졓3ﶣThY5JdFJR\J8R2?71]2;Vpy-)s:DxTzղC/Kd'ko;|F[]w#.gfooju4a7Mʙ.ؤ.i0ӯ-͕Ũ{{'g Z|曦boRT5yػJ?T?1c fᷘB՝RXu>]>DdGqQ\'<̨ KVi5is.zWL=|dZ`,S P U!CkSt?~Dryop}Jk)%\kTESV˒oǵbV;3Jm6$ RG \/gL`D5^My <L!&TCϒF :aH!%C}0yd-Ior{w$Q/S8<,Txg!J,#)&-B;,9qNzZxߜ8q჈E) 6Q(ӻ}HNiS$ߝb]88R-"U+_AY` ^ ׂNv:ChR7*>LdST$CDZ(P$aQ)R1JyQ!@o\6wqBi Z!r[Ci yJH Olx̣}3$-:AaKRPX@ĵ ( w2BOw}MwŇ.Tңu$e} }lJj\?! .[ď"cG!~XTPeX6: #x)-MBVWUPM52UwIH߁'@0RR/|8 lTR+A` lj[[x[aHJj\qO.g($a# Xか%)LP@ 9 )큔nJc6a& 0K mR" % 0R LS-n2@2Q#ONeR*'`M LCQ4S6 Roŝ_\o${ql@\bt ą3d)ﲈ섋}2DBhZiRu~ BN.rih8by!!P PGzpnh2Co/#(9:RB"i[Dֵvԧ4BSC?x J4P`,?"&],DI` qOV0[8\";H\)K1PϨ8F6 zaI6H iQrO'j& )f s9.>Q !)a ALXºAMlGzhHD4@xH&8Dbol"֡MoߎFBօ m@M\4]8N~H0d$̅\P$J8λ @rHr}d,&4 j:RIK$++' IS B2Xi6.=.Jd4ܨis`gZ:2k3,G|3Z6ƽ:n˱ۗ\u)=*::MP 0cT(;&{JA <+:Jݴjl24pU;) $Ơyr5*NSP㟜!mLBvw8Ɩu+Rvͦ5g>A":#)#f2V@)!/}lHƽQX4wjқrr]Ss&Du}I266J|EYؑv=Cc,>a8;I'^Cɻ8f}3:l!d0tNgk/;͛BvnYR޻0W]@#?c=I q)8M"TBEDä_'~cNuDϲK/$FKt0(/^Gq f<]zJ]ȅE ||ȪBsdJNۏ?.+p0Xkj:x9)uKIŽ,[X2v[4C&Dv@ rǹPd0LUj5)yl(Xsce, ˡ\i/0E#ߋbv׮?ckŪ׮Kռ"YYD{ \R3-#*f&s,V|7)2*ށCߋjWዔ=e܏ˁuk?nϋ1̹JiܭܑnA>܌NM'0}…2G#?{(^^<%kwdy\ k8}v~ 2U |R|ީJk:49FIov.֕I-)2CpKVҤ YU*Z'-6s1K !>q ̤P-B531mfژJ@h=D[F2e1eZZ(P Ĵx:񉝏wq 0Gr#]:MZI'A:<םB= d㎐| 4 =n=/{pmy0a~+h2FQgtJU\͓S#ɡ1Uq| orzJmly?# eL4k}JL }?:3U~%prU2GN9r/\ǿ [iQt]EkC'CjA]MraJ(^G-,;0u0h~o V-2v)>w7O dsV0ilgY&69j!q܅ iJ2l|2l]mqnn͸#rU7?QrLS,9 ^Q%m`H<_{_ꩾ5rɥu +K/VQ&~>/%EI++fe AGʭ-Fg)H &eVe\ښ1ny;rC1BzL*K4E xkN Je  ΍AUud @ 5w=UMk(M{8}&u:eQiJYq{b̐Z{b2CFg] 7,MĔاӫ~Jq^C4dŐl1J-%;̢g1m_r1;Xy*:ETR|=x#f%+SCj q>ʕ4!3P&6-;

"z aOrڇ$xߍ?+8P? {x|uރ2e*bKN{<\)U2F9'ַç>[&,CKr@/8Vꎿr;c gQ9]3%#]UCDwHhcHW6,ҼTCN}wp "4MI8U I ñT!$zҷ{/UV 2>W!U?W A]twu@QNQ aBQMi2A 0R)=pqHCq*Ʃm"wi{ToK .T"ݱ%z~n8҄5mps%  BPumGn=0Y~AQp\_0,YH)~ i5ERxQdjA?2 t#i3;JZcgFփ= ^䔰<v{Fc[ Û.v-ē{s9Ja!6l1(`Jmqch[N*B-FA'` ,)nP*p vyr^M% \S jGB6#̌4B9[.{BP?PDS'c̘@vel Z጗#%@4GFRoTGqY?c0,G ЕvIICY6x/uQlrWoO@cxKy*Xu?G>p7%Ջ)6 +P*ŽT^*8sc5pB]>r1aR2פS(mfݐn8ޢ,/ 1}V fefHh#N{F-cKm]0Lq7˗3f7FV#NBB{}/xiĦiD=yZ7G0y0joZ-o_8RS\ZV\"f-2&SϲӘA|]$ؚ ZΘ.@NsV֨Hia>BQKeG$~#M;qږLsv-JչB*!q!䵵7)N{1׮s 'rE Si dI7+s8jD2e V4;SuzQa71@$>SvDM&L}ikrgd,c-#~MTXƋj׸wO*t-ԺӾ ȏNӉkBw]D8ӷ:4ϯ`߶*u:70hHrUķ:Sk)̝&cz,=n8>\HARZU۞{Bd8HI]7ҫzAz $5ͮp 5ϬD~2^LvhexqZ`F]`973O k@ Z $#./Xt˩ JJjɕx~uf$&;Ai) A RAGW `:AF_V4'AxJgLQ]UpI@mF]2R"@#uWSn%JihUHO {ci^ ~&t Zޭ&Cq$#'̄mW)[([AGJ>KCJ^[BnGgngkK-mw?ኮ7A43}!H) v*-uFRŏqG%ѽlmMX)DKqI,S:zPl0K% X |F`%GlXN*qMb~V0৭-02U4f09IheFm/-¢,TGx=SUR~%P0<撏J.oqk[,)1uv'f ,Te),yTOnHJL -?{O3]RLRf3wjQ yRF Gʼ ?P7/w^]h|?O#O_}[HqA#b]BK&*TH'#%7̧<7v tJ#m4 AA=]ͣ)Κx}6R:e)/ ōA Րd8zG?M2y)*aM;I<u?)|ѵ=&:oÙVpup+ zʳ/?I5;hP0Wn`y(;t&rFu@5:[~Ftl؄\}Z_i]8?fI7WrU9Q*[ijOKPB `D$%ؒQ8jޛsU r2j1U~Z s!5>1ͧ*|˥;$+Q53:)~* JLh{pu-YO~蠴+-< >c:)Z Q꾟kLqM:nYL Nå!iڄp [ޮ O=˸.t,pκP? t0FӔ\ t]x 6!K?MB壊ڞHIZG)O7a/ nRGzzYPL'm6Q" 0НS~T*n[<81x]![~Y8œnvMY&)>BA hH_Y$XP7/a@rMR.4l@ ^|JׅJ;j#snTE,5wQt"\@`; L*hIv~ā$ܫm=;b@(rdpk%],2ڄvO>[pL&MrpNcN$Sn);(JGn0b4Ƌ*&nU"U{֘H3XZHq#INUG0o47"],p;#" $s{F"E6S}7YmYa#.\x()..=cl TU.(KA،2TZ6}T! uUBXmPXePdwJaZUք]NYcµVKu1sI ejLsLtjE*gn-i rn-QBE)x%,}mqsIgJ }H#[MuQDQw鼓02O$y *o^:hJ$̨.8座$8v *ĭѫWwRC7dXWhB[ @/)#H\i> UFC9-DU>2:60'e]Je-ګ#?AKkh=:C1GrE.#pXR,Jc1tBC.sskըLu=uwP}UAt*o ,?Jz%fm YBƶS ]18^MkǮV{TDzu_v }O>sn:Rtaկ1kHkX|h$}H/%>ׂ{J[.ćYtoEԬ ێ+PmWp?rPUո4w(^u}.L[mFCx<]rʹSnru&W6ޱr9iF@*}d(hBބԔuPe7n`o>)2H5ӿ/2JDKNRFͥ "݊TF=mã>L1wxԎ@R*2e7ISM0(|,zrzoP#'ྈCFűUqT\_s9LWbԒe6<@Bq+\ +T2-Rʒ@P -~. k`ubG镩 $$|77rgZ(Myަv0EAܼ^QxRҝT9Ƶ&Y1{C0A;.` N&Ge~sPnٛNir%3MP*2 \dREצ DFt~JuXHeZfIm&HnZXyeJap1 "v\Siu{DkMX2b&"|ZB:cNLLϕcJt([2B>"^Xm," e2ty7ѻY\CHct"s6dRg:K0HS›LV ?\uX_Iך2f׌NlWax;QH6Ki '],HLu]u\6I<~|c±Ko݌%is/nFNarD:U'JԄ)4 7'`*d>d40JEHJk s:Q~%Mߞ/0 QI"`!M4,$wnEQ(`"X>aJE8(%0s bIG$!VT}(JdԯYNS6\lLYdHi$/2AJ"oTi۴ ֹ.!th1b 'QRRirx~;x#9&"`++%\)o')Xp SQVz|im56:ڬڤs)K9>o 9br6QUɗp(,JI0O{ݸM6֯~C}[ۦ HPp}4h'yg6R) BJB?)D҈T5B#BOQJbV#+k uط5wW 1,bWgE<`.z-im龃Ys2:JC^d1VytK->C|{[ۓl(τF+Rfu{YRkq1U!_|bCi| &ËZ;ܝ=76UzgqsQm`cCd<5%L޽ VřՕ:F5jm'&骣j*J.Cp% Y⚄f[kai*].$/4S:iG89RbVjLWJ!R($/ҵf#o/^ۡ>ß.x%8##X}slHXے]ț].qK%SMϭֻ=MЩm" e *7?]ّQ ÆPn@t8M# ye@bJQVlJl=ǧ᝖jUԪsj%6VƎySG:<܉1p}<͡@DŽ\PpǹZg19+.|pYJ.<<3)®9'0Wimm52A_U#I+=Hm> 73ƿ{$qh&\Bp) 0\WcDX!cs}8 $q+45WD(> W+y)G_kWLh8RTS%ȍ&BУد1zRߊ5-*YkԮ]U2$ᦑ;[{Fؚ⫠#wfz1҇Z;\RJ7 ċMՕ"Ya9YhTKrC$YqJӁ^<CC:ͯ*+RG D/Iu@N0?hMՌdA XMj#UG*7t}qq #5>ec(W:MObdEl/4 ~x7)J'R~p WRtKij?˵IlKQB4>j0HMB?Lm:U`ҠkFg󚃟H"3Q#\PPE$ZY6}&͏Vv{c:L~*veU&cS`yҒl4@l@$ ԨNYV5n|Mv:D!g}*% PtpOED?NYtmѹ~J̗)TN)"o2¡;jDUr Au[O-C[u>`u{{.~r4r׬iu:341r;/hᕲ K OD8dҜ wxa_6jPS˰徦'z?ƽj=zfx$ᛗ挪j um9* Mzsk\c%u+v^i'E=:>}hUFX6lZ[ Yp/e')I 5Y2ZaLΤоvƺc~mFa ۘ>E\TtKIr4fhB&[Cܯ @(>Q8_G -mۗ50'ӹrv)qrBCcA1aT)RF=1!" %HP*$'cfhThfn<+ʦKV+ wQ^Ri )ٰ7kZBIP'4AQ}$j#夑l3N ƛ9B6,8hK1](#o|" \^6(}AO4TO';qRKAV^L]ģP2XƒrT@ͯmP iҶKs'Ul0x@_ch0I9a"A>LE<7Y̓R<ʓBfdH $FZD'cUŭnؘ(QXD!C<4)`d(3$1娹GYް_ZP9O+0?`+̛buHSị B ;R9'Б/227TT}jFjTlKHTmK 8P3[k1Gj}GtSKX< 5J 9M~̬G1o`?c ǩ|{׮& gNwy;ZwSuYMWjH-*'p1z>IP!!\=0¯z~II֖BxypF$$XB%h(YPu0K Cr 1⯄0 xmD J _9m'qTsm;]Pj%{ ^#ipDא"RJ}2ʥ=ߊKb[ i|D<\a CP*IApGlVL_&BhN3g. ?ۓ^RcG. 5|] dG3) 6SZl[qN4X`5E7 Sr5 $ki9ĸNO-{/iU6-&\r[ZlAUK}ErIV%|Zxsy'<ڡ[O̰ O ĥJF&UwW.fB]1FeuGTm$0^&E<Q$8YBH*HEa$a$4ꣴk/L&9,39!"UʏON ҃ې-ࣹU12{YPÐ(I7m'~d8mIO.?Fi0B\6,y\)pIOCy4bkb7jQ%ÛE_-L?;*Ε~>*_aMv?4/3$KPuo3ߌDȓ.V;P4R7>޼^^ȕv. \UArbq6[LRA9G!%8/A5CT^; 3o YT)[d])㮬)j$}I78p ǟ4<UɈ)ow Ӳ`j2YG9y1/G :8 `ܐ LfҶrS+Te)d[Dqnl޼{c|J>JTd% C|ķ O愣Y"u\ -@>r*ڭv ;uJN(A'TnO {xY;$oSr0"蓲3J@Ami߸ ͕+cI0Qp {~] 8jZ^Q_j>QYY ҄[Q \^O"s^F?Va$v !)J{xM%(p$SѴM)ĝlqC&zZO[qT؏ ԃ|N.Fң4ZNNpnH(M)2j%e7ZF#ZR7|Dm7Lnɱ_}P]L4BT~Ģ@l!IPĂ0qI_&ؙ`ui$M Z)$rwͻPMb bqva 7Id&)U͆,2鳺ڻn!R  bv܂Tnv&LlY؜Ug7%*+=ęMÂA&6J\]f*̄G&B-LaߌzA0(TTwFƇa_1qTgP""lh2hBI>A!tn#'d^OplbN麸 P椋,-mC%՞hX7aGD/ O=7T ]Ϩɐa.vaYYS yR8YHim w "qM,lrTe(۠ aP eIp8pJ٪JHj9(̥3,J >;kq +ÆE)u?;ms̍6gE gqSI8Tfz 9_uIַN0s]K- R{3FUy(<+$lW,`:)ZGynU%!+HR?yAwqXjᬙ-f*\07%fUHN:'dӞ(| 'C qS,mXoez84S*MfT3Mؕ*L&% ň;*@:;W/kGJt`B<(6AH!DpAqK۞T"%ys YQcNZ\ ێ8E>Yn˜K<5(sv O?$hǙ(HsgR:JEV1o 4ط'pcLק[+y\+=U2i_HR bv[ U& V7IkڃC4,f6P[džǨ[obIN6ӦNU;ZTd>m-i!(GNX7 8@2--;=dzWsw;[5))?p[&aaJzg.+KlCA]KR&Y[+R  $rRv~۸vw1uSU[\vӻS yРffd1MoWTƆʓVᴂ-)>e5{± a4kO43.2 ]utS;G@@JH2'$u)PJm*ĵ]Ֆڍ\{39Pq'dx*JЭHܲxۏLe+zH:.$ک)#4L&Sۣcp ގHV[۽2#JB@q G1S1%uL vTuۛiJh% TVm:h7G/m|J:͹s,!:Ka=yd钤X~<^VH&퀡lq彵 j s佻}m3x' N-5R4}*,*&RVgdˉ x<9:ftW nxgc$FcF櫩 I" [!JsBLgZ .v'C,I7QmUS +/RaQg˥.PKNU)=\R5juikފ͏T溤ré.DdYXRyO:CrRydT5 ,ŮcN@wӸ<8Uo :s)ErSEC/-ol!`76Xk):hax[PwtT5^2X  elu*j !WHU(H xej>Dyk57Ry6mJqE&IMOI[Za?YYͷ aGߎNSnZt^}dNg2NP O @76Cidܞ1-<9ѹ'Aݶ~;#=)iQee9;?*KFԴ4-ߺ@V{vSă HUsf?4Fzy߲ e1*N%% Dӄ,@$CƃP2GTNuL9Ί!͑xY5G͚3W*C@zsu:\G{S{QrR 4Wk}e 3LI `"23'INu-`ӹ1DGͿd'JZDFV4¤ Mދ=5PQK_.61P1-<ߩdNӤIZfLG)߾mĦmTk@~PyO{+FYAFeL@i?N[mߛny>P2}P3[y7R)RN1*śPJiP{ܥ*S|!C3״-p} &j,G\hDI=ϔϡۂ1n_Sid'@u!n̋LDb$y-<%E @M<[iQԄ!X:!LE.xN:Pw*!`  *ZJs%SrH`J\߰'æ_2-WI`y8I/鄒%-0{aQH$뽰DY6/Fޒ(m N7M-Teť)cH &*"UJ˾dOE'(]qI!K_s߾#" ,q;'aKbl<_AIu<$qΈET*(ݩT3*zDB*R~$`L@QO:8D>2qT@QjKPiUA;. .){=S=\|2 #ޢz:(eGoeqهiGG\Bg~ˀ EAmIKh <'_[b-XtS4* '9Ģժ#UrD THſ'Z4Ma9 ӰĭaHQ#"lT_8XpU]OS9q3kפ_<.ޤH# X;  q]$b8yJ嵲<*YȔldT/ٱsq'kk8ΒʍV;GZ+q]՚xȗ3G[@4* 5=q1/Z]1wK(FAag.$2U90yS#h *Rkj,x'T/Q2,UJ)H*d kXJ,ȗ-X<.qaelKEطr1ay(I%:T cnJ3Q+8e6IL!$4ePweF)ƥqڍ-kRCZw^cdj->u&Ts$Szgʙ{,g ]ZQ0zJzZQ yFi)8qJtr..E}*Yñ|,] DVW[m9%Ӵҩ4#<:e.*yXnZ(kcRjtC 2| 7tm깍-a\7aN4fqsk~X4,?KXmr !inKQRԋwž8WTt;)53 ,=*sX--a߲ig37\9:c3RgbcibVQPi~jBkIQɿ2I'SBj)N N M)@E߈8A>v'ʧV`5;"uDe~qYK)UJpzXSh s{3Mb%=@:[RzV c`HUSMG+(?cO5%^Ϗ#ѱ`n Z۱ޑtYGx|6|ΥEzu$]\zpHٔȲcTm#@$,z~mjMo^cwYmm ]0vUeʄCJ̪OqJ!ٵt _8nth;F򁮜8~ſ]8Ro=ɕsStZ6i% i QޠS>cx;j8 T+oAD@w$ײ>aqZ6Hr.@=N#Ҭ"'TPTgHP4`&/4B55Y\jR E}%IW  }7R *}YKv4FjcNx-1 HFN]3/)efEQ6b8'\yvhG9HKj;6٭N 헵Q(sKiSYj,VZb/bB@ڀIwyϥWo5*=ң tvy&6dORµbG ?$b[D+TUTI[ D&87%` a腝=⛣⣑~%=P-D ?ȌHr2ARH!N((p W2 -rӡbfSw%XZ=ι|̌U2UL4sԄX3JRHm#j; Sbj Oןm@ը`ԺFN|-f79T:슋-%EqѰ;'zT+x|TT1ڊ 8;z'fEK4GZC*n'َwhTt~[9;(LE:Jo@O>6L!++k78'C,d$9Z JFv$?Dz67;@[Ȩr cٯZ;t]X&U_+7wfGT A?1zm/۷uˏu)LvDscӺJVLEQ+UnG#T1~=g72su|"iNKAHR*ZHmZۡV&E'끫ujUKh? yJ9J2~k =v%a撷/Y/A m Qj& zE^dilٍ@afWXTl?Ӗ^mJBJ|q{.N=~yMW~NnԻF&ܓaÚ~B]xdb6![ ;G`*OO1T󍅼 a*'Dv$PHAw<|H(䛌2%I ss{pMS6;&þ qN7M\be]) 'rTx<`HtbpBȷ,cp@ƥB7Kie %G+])l};4niyg(PJt&;x6y?A$qV-.jt\y Vm*-;STUJgq]@v]˹RQ-gau7zST@S桳v\"&|'h7 p9mL7ާ_H gN:.)[IInE)Wβpzc%S:(6ܓ`I mvS$13oںRYYp0wCWF}qnq i*^L&YMT6VySF%O]UGڸhӑJ"uQgbKӌ]uGrNzI^թVzKQDj*B6`xHWǜ~$:KÃQ'[FeY݇,pR7Lm  76ڴ*f? o^wA:J[̢zɯ+86J.7D5oԎSaEߛx쥑LN`Ru0]꾋:5@qvXBAPZXt>ZT3|~ZG7U*m%u7D;EYhU,?xB16y‚Q:$‡|WR,ik?5J?8!7aڂ\6-{!E F9P+{#*=0 ~|(/;2Uga2KU&K `pqyW1&pCֵu6 vIZc׷6n¼h):J&8pSTzF%~k4@DFw(yBUɿ֠5 aRBw7+6BƗ)r bZ #-v:x]4Vd(s|YljBuokؾQhV-51(,1W:2cCRk침pu'd%-㸶.SRu"P \{IKx;(Ao^U)F4 Ϻ# pz`CȤp=cʻm0ҖQ2j0lQny8rFLsp&?upf,mP$zϴ!J@p5, b?q$h]MY)Q= qبvY'D=Ԓ8l9i)FDܤ8B,+VTUtp ja8rƔJ )'QΒP.p{-u՚M=Myi̪Vua?8<tfr0tSF葤ʞ+d(m)( @>̯[[- 4oUಣAr>x/3i$46 }Ud;U") H ?od>N!rgo$6Narz3Ay5p]qdh*GEL,kɤe`hosZe58뫪u_w2|CvUc/e4+S#0 Ġe68mpԴ/MY<%VUqFLɪ'̨u/k3%Ѣ6lˆn"RJy H s qoGpzgjL{*:7n;&܍^ 4 nH.k$m`9{~֠DZڍwsZ' hcNS-LgOB:&3iuwO1&#ZPO*ˠxXcG 5fҪ $>SF*_URwR;%=6 2ZԿ)&Ñcc kU=>*:-? jr*jYOkY4 +^$Iڒ(( w_r}*k~= "v.^R 1ˈ@`UsI;6.Q =NvcP̵JHur}jI|GRK*q܃);x4= W@>u&D R/ }  }:[8Tm5xi\D^Ul&oS)VDA;.i.4FUnbX-F'}Q6֮W}U_n5#jhjSJ4m=2mdͬNK?U;:/l#";1?Q1Rrv]Ct5{l(*I'Ķ4q,F\t]yut )8}:ܶZ;S9g=4H&O"\VKNh7a(T)@P#Nwd]X}+:w7T*>^3%1i13e-6C}q}j 6j 2{ $R=j}ASRkf=/|rY'ulث[$>kB67+XT̠ӲTٶzԲ@t{#Ԉ`0h}iʞyF3Q$:ec;~^ATQil7 $:P6ga2)hx"#ur@/chGHIe^b5(0 tw-tG ejbQ BM $,RQ^ԧuFhFm sALSLr=Lʈ jXZNVIiTc'MxZ"hJkE?rFUQniej!#MO=_b2n> k9lD [,N>RvTO n-JbTy?CSkp)4ӌ[L[ev"IRԶ3!Mƭg1c\5Zpi<ŨSG%aWEäڅa$R)l؝I.Vc>I.o^p] = $M}ݷGJ&p M1\J}!0cU-m>VyCUPMRFS`() ,uJ ltwoYw2Qd=UoVB~@AMJ7:E(gO1Wkw]-pu.ϗZU.jIt}ԏvRCG #ߏzVeN:tOk\Wv= S:ekVQS^OH5K svQy)j mg}FjvP8O+lvorGpAlcT* .X/I\]$I ) % 'pmp1ubf*saxIܱU /%f.:7:R6mk>$nXJzGgRzA'?fV7;b/!m:aBmYU$)_>p3E(avzάF-2 oPȣ.[ׂIm[< 9\{yݝ*kZeˬS\R@I$㦡VXVcQzW1ɎgkϨaE% jN;!v cAA 9ԫƩN4 x'ܣx{u3=C,d@ x<3蒌vLjD*i,߂H#ߞFOB[Qr$ٰ_ uU뉒RTNKvN%m&ʮ\Rjc+Xgc.pRhHEňMS/[eaMV/5uLN-T)FG\Bqk*#RĽD bnXUT) xvBTȅ`) nFSZSe[p~̹q0m4*(*!%7%#0Z%νZctme pS sNm-ɬ\`DB23SK4 V07So[S;_V%,a$Un Qm~4czy߁|*m5 Qu/h .[߀^u]R)9 SڄvP]mRL)z ;kirW}x JDSdnQS4bԀ1<3bUbTbeOHr(\$-vxN m븨uQԨG)3~\Iqrroo{ c]|Lxu5#e׫4+*(~K~ A 㡰F~*gfދ v朻O&56\ O|Q/lgR;6m1(m3kp<&ֺvcotDʱg %32F3YoCխ:Ӎ,4 n˹=XGCy=B%f9M3 iSiXm:Zx{:?E}"nDKu>5ԥ,Cpwy ǘ>%6Ht*S&_VSHU"ȅ })-vi6 ElEI":w+ KG?ӜCIj&jbUʶ4mmJ?_1NGXV镜Y5[ٓ1帴zneH9\䒥Ӆq$OYuP"`QU_yX`$. 22^̺ĥ,E! Oe.FkpUէE¸FG6YE78tt˗'B5z$+@O!&W$lWXy>eOj]K)4iە:lV"@bTwYIUq @ڥ$;1ж==WV8Df5!H= bS2Cp B ~;O6Ɲ uÍ@ kF`]=5q d- iB@X[a]Tg3iiB)`R@Itj~WΩԝ܎rA Rn=QKiou{E,$jWq{AuaW;$\ቄ -_<., gI<֦6?OGqD GIDZDJqI;@<.q#/ :V(GQ6U1oNKZCh6QzOP鐔ڐ[=Nm,!ǒec>B 8JXyeo+ޣr;WhO>+=oG2EwuI m6pЮƅ?5fQ+M[ʠJL*5Vٛ3dFD$rlH?t+x( c6P'8SO*@Fb$Q Ę54}\5R{A3hD'!UZj -^5;]$o)~Jc!Iy:A>[yat4'|ꖊpdK郣%O1U y^L=m ~8ۣ R›̔Sl1]d(_{btvHQMgcJ) _BKtL-lቿ[P~A~'C! &s4lY:$:io%wOM$';n5Ek )oy9h[Up ?'EsxOZGT_oH(Dʤ^,)k wiD%h;`rʎ f/c]?4PxY3tGL} O? oi6ΣP9HA[:Tl_z&78jePˡCKbv3ru'Zpqҥt^؆vlV5NnYMa\ȂrrRsjT7QQ:d37=[ CP#EwplU32^R@ʹܛlZRT ojM>br Y*d~m1S0OH\Ff(s)u躩"۰@ O˿6[%X=0ģZupQ!t- ;/8y1ʃ'qÃ1!+Ῑ4=zی)$8WҒY#ۄ}=0] MC  :Jmet1WBIG,"PM$hXߏL NUоɱ퀒D&b #ʄwÓ RBU %P;l,9e *"B߁)ٚtmq+*G`7Cg }?~?]yx(]A!pVsI(xG]<|ڽd&(Gm"i[`yb{"Z[rS֙O,SJR_Aو 4qaVAH<( S&8IY["}S]o;}Iֹ'kVm1>]KTJbST, #mJC=WdbͺcԧQsuL\d"q4~⇾+ Xaovk&ʓnW>< •_0 +@:ËQSn-}CI!j93|@mAUF-\4RfGIZ$F' x"f,> 1 ]ĩ`lH*8{D3P>1 φiJ>DܝW8g;$ M]^0n~)~)i2L9/*--MlZѭ*ŪyMI5T.+UW) 9G%#k<?7^Vi Y#SlΏ\8W^\M,.]R-Ѐ0}&sY^zCڗॢ:8];vyzg>v-1mA!9hvYP*Ͼ9Q{ziĪHZ\u5Dʛ#9k."a%-RfCe.:z}*JeK [uG=z8Rr[m13i" rN*;yVdenV/OSKi JHp$o$lV!Qmi+$z8ɽq`˿ Xʘf@-{V˥Caɺ ^b|%=mfu3 VAD3W2+oXICI qю}Vr㦤Y}>}k-|HjE&ju1M"[qf4{$x զpt<9ҪIjcjad-`xj<_ʏO\mX73Ī5|i:fJu.!!%_p&znJp7 \ӫ_,C9e^܏sb9I7㥤AI+ Z*E!F\ L)%] {0BKx4IrLںm8g=ܧo"׌ٲ {aQ (K{lIS+Uh'PT4ԸkT+&r]7q2l }txb F t׹h82Y:rLZ,$1JyP =;>|`Vm?"஦,4%b%+);}1d )k sT/-܁~{w`) kS괴}J~r蛇R~$U]JTm3+ ʞ좕(;%"vjH`C9MI*\s~{5dVTz~G889<ɞ^t8w.$h"Db:RM֘T1#WK-_q2IJmQPC6u2oxj*pވp;?:{ ǯhi;Pj*J|_7fg3]%Q~Ց I^7)*RTmU2濲U\9v2rjT%%ځ{˶Y-[*TT֢GJtg/c!b\`l#-|yXQyRC$5Ișl|dlo̳ Zïn#Uj؍e"Heě{qb I#^IS]"6 %WKi gMRVsy9GR;~x?@vWelpQxZPӸ(H'YЬ!av`Q*,UU+=ͳ'8bI0T3S>Jn{q>V@U_]2Joz,(VÊ+˜q!Q~lp 5)@0KcTw#Z=ԓoP0FQٱ;P828B )6q QԘ=Q}p% Wg@.ⶐ 98]^B1o}I=JN$Azaj0at)\,w8x1R#TP*j&uyL[%1P7kYKhi폒h@ԝ|%=mf>%hFrq[U%('{xp]i6tNԽ;1j>S⺻\q }776@R2u;n~v'~B=HG6Ԋi)Rp,6m<ӲdWˠvI @(uׂܢJu͙c斻Du%ecgbuha'd^=ъltSUT:RÌrX6=Jгk60DDCQJFԬsr)X3> 0RP{+TppVd8PfD2մ.tbGBz]%:Vf@?|2 :;QܨU6OcPq,a3)T[Q!H Vď? A RJ˅+l(nP?O.v}5bfU?S%V]i<]BD*Rl A+a.@H')qϊ2N-Rܽ!LY9¥9 [!#9zVծ/t揿U_1:F^fWZ+ͪb92BʁGC`Lj^}`]jKhǿMa^uq'lx:,uqRÇ!}8*e͐D@m bJ  c1SZY(j6J.;6I2R 0w. q>)dD)m R P j)J2eF6QˏOCedۋیdiP*WzfPVAciLrJ(@68M@Ѱ\K+-z@fN؏tgʖFy${_fYs]j憵́tkt ۹*886Knv uTJۃʍeB<` Ok$m<³N]bWuUI+ICo%.JIBa@α%lZ*<`$jvHkd}_ˏj5-֥7-t)eI@R u$;YP~e^u]k4 vv5PdiZsHsJ>^JBj,A C!HPX#諥 [r .YaCaPO`ɛ% ~`p/Ns8v03&]=)Jy~=[gYճ\hO9Lƿs*. {"r՞,+O onqj%gVQ:ش;(fDɿ)-ҟoXv@ZE7TBɑcNfCq*[x#n,=vx&ITWamQF`̙1iR͎ VRS  pоempBj=ImC|oo0X3 Sĭ$!sJ @|YeB)uwa<~G-3)SR#(G1,PSn95lv/r,BE ZBW$8TF0SiIXQ)#i>nW/7rcn>bOZ~sf-=z5Z"[AYثےٿojYEVͨӗ:PS"ϛZiR{ ~ƥ*pO(k5 m̫e(mk+M$e(8QR2bӚah~{o]$N$#J!T)i^Q>r;IŸaM7eI̢1MTktjWstSZN2D imw8<It)ev݁9g,kQ.`su '@䲫.Zi; $LB%o(5SetN%R MX[8(j$+|| QJ|J8PӞPxdA 4?t /ùlbP{z`IjtG$1;#O\6uN-jjhs)7ߋh;"oGǡV2`u'tb(u @EG%,PuIH9FhÊV*a6sv)lB)Oy$wqJ-߰)\x.!6YR}EPΤ਋]pԭHpD~Gknъۅ"\C3B(D))x ن۴(b~;pnFۿT'osolB놟S c+ =**vpp@ ;bVp@SZM=>rXmN+F\gN#N cbZpmynG>BjZ79Rf3kGp>YN-w]Ă=tW-qM='0% F!坼J*b_ =^ׁReq*:LF_h:>Ij9$-<K~i "݁;A?)Uh;R v]yLhdl6j%f4]Dd.p1Īj82JSfL8.(Ƭ&1gM[b;%*ܻv=YWSR:\ο")B@JJGw] dSvZb|4G NŬ ۋxʫUٓRy@ 0 (6b&nT{;,.Fv ΃!ū}@?Qj VMMZt`哜>4| Ħu tXj R$rI\u'?_=Ї]yZ,WFf{H)S.|UK-I׷sn݊ХMuʨϐ @?9104#PAjSm[Ie-DJO"Oqvdge+ȗDʋ J NS-IL@@}h< EN0vF5Ty tEj/ Xspf]h 5 ˄kN*2= =q Vs#Lgan e}$ q$* ٻ{֏*Mu>g:Ed۷W11%!BM7bLfY%8M(* 0*an$bwrB>Hyw>Qk:NpcSh3&D!AS]K|w)e炊vsnrH`#f H~T8F7=Ly6-tG4n~7SC˴j|\H/k0{C 5'\!s;l}HފRTQj~L MIHqrN «S6āK㌼4DLsFJ0)Rc"=~)G#),% ,XٜHळʶp8{)>AjY8饮$:Z\Tp PlAFвޓKQ9AZsFrPd+Z)oCKiuAWXO <~=kYkId 7.n)~9lӄi.{G9JԗWॕ(]&'V}1ꔮ k6$tGu:st#<ǚ)~YSeJTe$p|=ŭ8ƅ;fZ l}7T*P.sz V:zfθG1hk\cCuR!uIY@=Mq[~Ι sm`oiuA{sfjT¶-61[}tfk}s3hm+)Xk`zM56#*+r 7VfzTr銏t`]zcIEǘq .JJ ܧ&i _>ԅ1;H)Υmp%MSJY%11RPH\Hfm /\pŎHDThRJHx! Ez^@GŪ5%W^ a5g#E]qrY 2Hy M.m\d>Z>:J P|&՝O)̬Tj^auyzAKv)nkٿ.Q忲>i忲9Sɴztͺ"IBzmV[qDPO;I:/=n憊 xzMV=|1S&_Zqm; |a R{x=cM[A gn";cHkfC S$Ay60IQ{~c.Fi)\[9Re3AVienP >fx/LUC-C)n%Bp&@T{!l#e?_(fG!V*'X>:G,_9!@*,O'+*H\vMO<@1*!B+mڔ(]ܳ xSa'~Sś$dr{zaHZr/q8&9˟N jJyRp,B\IKaJ5)De$*0`N;5Ǿ#5gbm(Єcfo0MC ޘW'1nsqQkR U[2QG&+yZxpwEHSǾ31n)otv B2av(s7u(N*Ml!P * *#E_鐈ᵦHJꭀ?oRx҈/ܑeyHRXtvST)CTп0P>gaH#,&Q JAG0*FNPV!4廍*vQp٩,H \ I=2F+:zt5]Lv 4G鈺ԭ GGv$r7h_rsteYrHmpDh ]‰'8؞+Tv  ?Nzp+{~N,3v8U"U KQ'Dm`{2SpOB1BSqğ3d3xL!RuD l޽|S?Tr2eo3Jp%mų7!G jozY'@}fUJg*eT{KqTxnvg? ιGVQQt-jUoiZ'UHs•e5dd>u*bK+ݒiB/o$߽0 9[iO4OHU >f$BVXbA5zm@ŒqՙjyP>CU_RGsr)׀[ËUHս).i: f쪻QI){c%)iipk%G3~_l;+HHUy&TTK4\X.Zn,-@H=IIP+!+mx픲H)WUnUX #hGi_ɧ:m2л8B | #}F)Nh {T־%eߵjVR>#ȱ%Pʁ汮6j٠Xi]ѼkxFJg\jG0(Yu.)*n~U}ċ}c_bo l'AĮ l<1Q}WgrOVXE YCq3orTW |ԝO7O+t[qrC}cɩ\n#S.P5l?R-V\ I8piFU[$$n]1 ڞs%J?Aj%!ߪ&=?,Ӕ$|ė,=I@,yO6 V( jY^Df^R-!2^8ؔ_ƕ X2! )"_Ў=WS>2YTwD6먺]anckccFY'N~[u:Z:۹/QY[i+W cuB dڀ=Qsn-E^᳂epM,J;I"]*)Y h[Y)n2TABցn-n68ju'u s7m%c;'VTvU"hqC?VmWt'Ď鏵%%'8v ɶ $IZHWZaڅWڑy'+cTk[αܘVمiPKh1aXNP47n]2aW򴌚 K57V[TiЛ[]b\CaoWêT$Rwmu&Jyp.:Ԥg6fTmJ >]C^)QI2ecV2F:$Ɵ\d->v))JzQDZg4ƫL8XsdlJ͔NK PqY4cX H$߯FA)H*.yÊu^%*qau:(~c=BC4b 5ⴁWG;k{\15ׁAJOy.~u*\Mzzleqh>LegtZvϞo)|w^'s )j0jtMY8qwL3,uJzJ2ߏ#5ABg6v4mk{_ݷtjT$dnRݏ%Kf_ּD T̵8MIR;qӶ;' ; m(8 Z3^sF4?E533Lg U?)jlH\XI>==Jc L/:[0NN|XN;%s4N3t( JpA&T:ӸMϰO3VsI;$E[׾ 8BlQŭ4H %Dmӆ`4, Xw7⟂%.jE~[vA;%:"@G s 4E-d$,{2BxE! r1e6&*ew Ywև YPjr'zԑ}plᥣT6h1@vV;N׵8,1bfqn|uT-0n}-7OTڗY /Mq뼩i2 To߁+S_ݸdpG=ƛ9.$U?/TɦBgXJFx([LwTu_b:qz ǚ62ƞ^ڮW:5qVңVP2kLIsŘ#L`2ܝdly LZ"ATw[M t้iKS]nXF+<ЧRΓ}&T/Gm+?TDžy]."ʐV|H-6!7hkOos>ajT"d'MD& C P{s"(aSMQq|1+C=d )_I phP>jZN2 1uJtEʹ@R2>t-c6NJ\Fo{bNiW?%S 9Q{-§c,ϧ%A?|Zs-js:b{BY1^UݙRLA%y^2<?Q) m(x=P?刚Ar;ʱ9^~_a9-1ȥ "JI [j[l^U\ 0Vnwxfj)H{ʼn&0\w=ЦϦ#E8MYݒˉm!;Ryj.St#\CH9ΞȒB܋XASP&UP>,OR6;STwRkqbch9⌉žJ4V]+LJuO6^%[ɰvm)E58Veq>Ab 99hJ5]\̚x9-#,ʄҝ#!O%£P:;o{GT{2Tk H'Alj$bcf r,ɪ!-|?;isXm6**['HԳmK(PvI@7!EڟzW F" )wOKbhS샙MkxLnyxN{j.8 b,Q3/!7!ٱRp=T[I*ܾ+jb*hϒV۹bkZKrZF龠sv0ꖦQOЌXCǚlB(vyKA9ޏl^CPpKGb޻'D>k-ungz/ĘTnR/Eݥ:E0H @est8DurG*M`+p$p_!aQڴIy;%+EBǐ%Ekae؎ؖ4VTJ D7lT=-:>Z @cdS8, BJJwQ鰶H{YnL&HJ1%F] #Y$f >]}@Tk7FZ\aef$ā{_~$䊡1Yx{n_n,J'E^*gC#M+PdgDgTIү)#6TWxfH_*1&>%e :^KK&^ho%RvBϣaT$YD j$c=jm,0!(L츥;X4ʃm[V?|g^\Z(}(*-cIy H|a.e*޴Mv@nϺtU=b[SU2K||S5m6>lӷg|9lZsOmY-T'X}zW2>o<0n# yne|z?Aq3 itiK7¯/,1ފVYڞBQj!u7YCKmŀXwK0:*2󒹿-نW~^9nFXQFU.#L=K ǝt5i@ӂ0.^sjt#kfQj2ch-%to8߼-k4iZ?x'JZˏ(Ӛ!(>e ڞ;b:Ձd nbJޤSxNV3<䪣1[p7.l-ͯD,_gWLm?Sޫeyp ӟK 5QV{y i>,c&=cZ~nL-aCf"WGUC-\4)kr6+/n+|p5 ;$m$z ñ;?ZNDƫZ(95Y!UooqW6MǦ` ܹ w\Q8fvu94`J)!šV<ܒ/\{lJs^ImJv s{!v/쯗,FؐGGtqNޗ/X qUƛM/II$*JJBO(m#H+Jm%LⵈhsU]-ԜJPn-f6t~n5yRnM5*!ôv-ꡩ9`t h Q:i7e3FV+C]W1+AF]8*R $M MO51ƱCD4[T2kn&+.U[T ҆ZTVۀ#i;|Ncx6vZcSӊs=j4{0xh/kDZ%-%%|ߋ̧d] Kl'k]Ý)z7]F[j_ ]2J^ؘX8xG_][F@܉>ZiHZjT1/Z6Te(0# {=fti񄚝SŔ;bS!Txl^fKp+Tci,?v}' Hw*L$XL-I*ߴ;H?)>қ5FUűy:)5CS:mC.\)@%`T \^3gH58}P΢|?S~_ʲt7VQ"3&ewiR*Y!&܋aw3;RS'<7|}@O.ʵf2QJW%Sk"l2P[nxⳭ<֐EYkSHjJnbVM ִYn$)) FmDv+ g͘#eFȱ%:MMlpo؅^պ}4@s_99ޢ2cel-+_0 X^Y62j'^ mTWQ:P}1x/0L%Z݀*A$zwop"~TdtohT99m,ǦW(5rP~ϋLZ\֐k۱g\Gʮޞ]:-q? v2r.b /8P~Qn%)$/cр]YMڼm =VPYv/Lj2eԩ!@SMqiHw( 뺮hu>y5#,UYQ(8ۨ"jj@Ĩ1 0`}=sF=bUYU<1ZKjnbadCIU0@׸}ӋAL8Pw)Ñ[MF%G}dnW^^ !38 NoTOZlPCڂ-M%iQI.Vq`H@%k<ջ'M7SW!2 g\5C64WDu!rR QuH$nH3[YQklNqmXЦ(O>F\H7,|?xs^H*A3}Nmp[hw\l` #В6N[OX8] AF`U)ٌ֕VE1A3,b?YV6g1@ d]7G@glo|%Dĸlx3Դ>_GeI?1zx1FƘ"T;?ЫH)moԄ9 Oh-z/%N(1Zpjch$hd'uU,QR4+8%Vc*ŧ3l*{QktYHeOYR{-~x[tbH kP4<@',?%!\]B#ڔ|vKxbųmR5y~S駈W*[T#OPh[P ܮSW,A!7CseaUTe@ v΃6IƝw]RN~龕&oJf c,Jj%""s1DeFDPDF)5ҕvim f:`.t5u4)x41UӡPuJX3K ] B5Pv!G6WymC͎ . 3$=$1s.n7B“Z_`V6v:AP2CBw&˥3t*ќndfVKA+Zcv~33l뾑]م3@:8 ;6II#Xw*(v RKIrqWj;ѕ w95] JT~6cFQ^dժt^&HYr-k*Z';^zwKT#o]r鎫dR;W},7=lmN=tqI ]^SŠ_V? 2R2r&os)+%)~<^wpxotIۼ]Z+/:Z1j]2HLV ku_ⓎiPXT4Ƈ%Cg*LMQ]=^ RfaHBROXΨҲOU tG Uʍ=+1TKkơ*MvjP\k].qJ NX疨/Zs Ȧ#MOKu=CBjKM;)SYY -)-Ņ 5+-ÉWaᷤl$ZC3)QRD`vr;n{ݳZ-Fů݊:cqB:W &Z-JzñYB,BJU}X'8p[:^0ՠ3u_|[`0cIRZڒ$Rާ!AaJl@5[*t4J*)N@uFB&/`A\Ld s yYBfn K)>Ekp9sz]F9*q`)`/A9wUL$!uֳ|‰S`OrX=OSfj*W^rg/~6y)Y VxV\̊ x:o,VeͰ|R\Zi) _݋b9%W+%{lE 4|VkP&rnʹ*w*ĎZzCA,HE%G OqCh*թKKF"t3k6ݽ-q8NhӯOi:r󈇘v@mRxJY7¦'N#i?ޭ^iS e Rc>&:)a@S,>]W씎RO85.u1c=*u:nfuwX˫ {-KlHihS$-ͩ_W><_Hws:{?E,C{Vuj5^iEB˦Cj-P%[}y7Q\x^ `h`@31\#XcW@th"u&= fgYZUYm)P\ŗѻiObJ]~3e/iL kQf=4@znϒ,s$*R\Hcn9Xn6 ?њyת <'}J#\&yi6JHp #f8)U_HJufm*7R;@p\%U-\>9l0R3T)yؘD+jYA=; Ctj*=1aS8",#{؏C *2@M%i%Ij];(9}&1.Mе(=hE{U?EYVjswIj˓QBLoWg$RpnƕFT4G6P@9/KJ9j%ȃ xA)dRźW۰إYVy ry5OͿ5#mJ@ePҕ:B @s/o3pqpų2q%|H3N~T4DMTWGQ <nO ey0GXeiY)E Ҫ0$."O/eNK(iiM{k__ZL6nj}[/|M@)RM71 re>d32V_&m"F$Dj>@hlNY4M(Vۿ,)R o);~%hmGT*1v}V +͍sw5M]B-16~q.i$nőNiHгkĂBy^Pי+MTJ2j+ZwxImrm-ʬ cBC068> T>7HFnkG3U12\@en\-im }9,_4ݩ|z7-bP;ZKZ?km) E%Co=nn[08x tjbֺܿ TCú[u]^;_J48 .?χ뵗4ޣe:šJi9rډ6|<56"m &G'=*ŝOĀ.qٿ?ɯbg.݇%6*w%T+@!|Jo`*=2"*U4zDxcRKLrK[67E$q#UWRh'+G|nzrnD"5.,LJK{A JRkb_FD|&-bWV_*F˱Жތ` B#ᄧDv7hyUE*jqDbOG$Î:I6&;+uS42~7f^Bj904|0 ІHm,'F Q0 s%Oj{ϔh=BW]NPkq$ZKaq-2S$uV]bʙO J`˔VR"V풚iͺu ӽa_{j\Q{f4*wѭ>)j H.ờ+c&eAfjhdn,̨KKV5VU ~>]N(l}ȟ+3Pa*+M3-dEel_;!qp6wosk^;P=ΩkF#ZrGU#Nj6+)hEB(a Rl<$8&=´5dHk ʍ>iNUb)25Ji %(Bn r9ŖѼm9p}i1iQ G+3MBJÏ) $ zlXj`IRӹ 66x}aOUI5UThuc͊>u%٣op;ڗ8Ul <{Ta==H*:֜*٦_dSKC&SIl B ) QφO |=]]s2{9T5W_wftiD)2ux6pllOq{(YqsY>1㺇<sb<,׫mgjz:r:JDE*J;8 Z'>A}SgK`o>깑ZѪ.VĦCL7XLة CY!! ))P,mWYCI9eZǤ`MrgҴWCPșzk0BlX@=+B1x^ժ)d3uY O1A~cR#T qN)r}۷}n+W#vZY"==O6$ڸC;9ڵDz8㘲uC=fNUS._Uhq$r/L;KZp0N֡u:Yљϑ Z`H2Ҫ^s7Fejæ (N<7ڒRwkJ̖?sDXevyȘoӿèlJM5b;~Jꆫz{ ղ=!9yRQIP]BǬ;ִ\X4Mt;Iˌ"ڳ]Q]tn0cbtpO֓S2.P˕ Q=MƫE(BM&4#w$n>whдC/Q%jL/ 3I 35EFNBIJ}zSKqڄRko6.FԢCTaAd7D$-o?:ćLiT]6Q}P>B[()Pʖv{ 5zKHUdOqᯒشejy_R幎7,h;~gSXյ2R,jZ7ԔY5ȁcS.%$ۋZ6䛯q-=7_d߻ٶolLLr'gOdm:G1RLvmG)RRIRs'/{oah7$i2'p]WMSn`Zo⫍QM.`HĒmKog 1M|4B$4hT2ZZ@$F>j롡glΐgzcd"#wX1'!UjGH鉅l$ a]]eӀ_35"b0kѯ>- ;6PM e.'ݦ˯1؅Yt'[F)RGd FGo̔\SKj:9H\s-*B{P9!:u;߆Dt.p@[[S2i.Wp?1Ir QBW!o:)BM^f;\V&dIYlpm 1T*z:IWvAzߦqMi~Tmmw >k*FTWU5isQ)Ԇ xMQSJB,#I]7GxM3tRJQ.tKj ˈHKcAJ[sÇReF'Gi%D'CW[~)6x3~mһ1CaK#ol*U)Q 'UcVzꆛ((셩K("43FT鯲?-EUsgG@oItଜ_._JGs4cM!.@>^sínSɉ<5C_\%[mFF&C:YKG 3.Jnƌ >Pb6daʗOa+S 7!hSRXWx=l`sGQ<#MQǪX\g%'vƆ$'-!Y?[}Sշ)J-x-EpzXKn2۫Nbgv8#HAylrU @FGhikңU+26)ߖdۈpէn+rII=:gT=}]KL6'E'$WHׄU=u[S٭Djr*H"-+kӎvݘige;(C[Xiu UY*-Ek/GI,}3# ^gi5GVCEY@O{D ^c⭏'J mg|S, s$Z򟢽펛X,1aIdCW)@݉]m/N`9=5n|^J@C|>:$ïe- Y'-slzK)sNdh2ޕ*V$s}B^rjڛ)O3ZPiԨLhI܅ fUJKfăL"9Fw5~|iy!u3ÙP0 96 lҪ*[,C snBHO&C\v1i}H{`[v5ii>w]i=6Scf&6RCVD6gʞi^coRk4 x!y-cƑn^A lʈ|Dee3ހ_8(.( XL~$`O~#qK@epnI08G5Y őI۱[dߧ[و"@ Je)ZRnM < jQ!5j6W0kpP|/*PG t()HjN0pФyVW }7>ہI, @yYiiڵXa J[/s0BUgL38,kOpq34NBUK-%}1`*%\I M$ŊNB1𖫦z.t袙 {2odzKJOfkROX#I2uO۱[O<$)j)tߛ_E!lO6$ܕv)JTP<ꕶa~Tx>[sꗺ7E@ \]$u?@3%BG>S5%r-@mi(ױ^}nm; /DA+PQ~52^JVXqTF ~n*uFXs ؂>yՓLJ:у0BiPS:2T!@qϛhYLL,$\6Mpyq1*sI /˹$jtG)9[+N|lMR ʰ wt"Ib}6t音dJl}v*&*(mĽᐩ $Xq%b vSO ` OŗQFz1>=SOaj)ż6 z:4I4@"<4!uTNjttQ 'Txв!qcSPP$ 8 8 5m:RR3: WX8@1${gR$̎γ3K-&IKDę&6^RYۻtNse $wĬy0*ue§*v2\rif\&O<|R\BH7Z%;("k$=>*>!wS9GˍѴ> rkzR\MI Eaځ ׶WeTeL])!jt?Q9P+@[fyČOAPQg}OV:j'-a'X0=% | EԩRUcV[OGPsXSt:6Wl-wɱ^wY׫S0 *Ԁ,ݞ:N\:XFّ͠e%>~G5~v]Ű͡U@\)NDޛVߪT<2U>_ mZХ- (JSܕC}HӘA4`St__ɋ Yf4--I2qĎI<(p(s ǂ]3$I 9zEkjFRY8oT+Pk zڒ-pokM0$ Llsj d3OEBg>IS\_әU)9emo9S >a IPͱ@28Uj\TDsO=_E<驚ׂX]0/F&))0ޔ>VA7SvWbY ~;}mi'U<Ҏh=Qjn_Fmnyi}֝UhNԨ6Ұ~Rw ?PĘoZ3Z6e=i\myG"$(7qrak#e$^+S[!:Tkٟ%eD1s_Wz!V^\VzC^0-P+n6 R}Z%c 8YX*=R̚f<,KЮrlu7JІHԔo,Bc䲫Vt.%ȅPv̸,ZRwJJ/^8r}5.0ujcr=xuiޗuNS< Z8̕e)R7u)O$X.7y"=T+[еݡìB`}-斫t2RZR9œG\&:Bl95B!X=`r}QE1ܽB͒xqih(۸x/sj6H g"KI ʿtR5~U~(Ph`7:LYqd!-_BVmbI#ck<|$/k3oSyQcO̕jL^3Ksԥ.>Ӵ_z=V)6idFddSrHǎi1':.w_Ew3hqGʔ WNAluVs"ս+£q~iZP>L%J?/sZ)XLFgn{>WVluj{ umFD?6%.,UhF@]^R qOksȰmT ?|=4]1c7y'Nޱk4ʕȮ0%Bce/6@uXxa*,G)&BA xqǀp~8dbd{'7؛(lw ȚX+&j~WFZduK}һ_qmm (u)9ằAj\?R9#PʓͲۑ+dPRC[hm~V75]Sdp*cF&uq7G!nL9=8S.NCn(%AKIAP_$\4ΕL:LWbSXܥ^m6W\8Įn^lj&Nt4Oc2 z-1//5VִY Y)M@ b~#l4`"] \Grӎ뾰UѢ N6Ls%(I'1[T;:t]/ U(*OX֯grAiӸ}tjZ HWW4gIUʙNhzi9, FEy[uimAohHRiw%@X!sRҦl._  Zt+CFGkF Z̸nS7QìcQ.XQޔ H(=㱷Kjn(ߚɾ(` GI NxS3Ss#$f(|RMlT؆wNm;1lNVß9O8T+ R31xKI @BRwm<[\aV\wfy^8ARcn2ޣW\b=Yq ;u 61Oswo՚9 L&ڽ&u>Fi-С}IȱKFMS4 . G%2ߙ3U-i4֩>N [.CSẀ]Ԟ]veҚիS*S[o;D o)㫏6k>+'\:w@c|`\ hZGL+hSϧ16>+~Q[*B%\%\dGqޒj4$,,zWz鑘KT8oc/O-//ݚ)$$Xjʲ)ު?Dd(sJjIfx5)d3\TmSH^:Å+JA7:y/2<\>y4ޣsr.+M@[R.̼q +yЅ2` Ry i>@ OK5,9sYmR3e]~I}qև[1hq;k]DP +]3Լ[h3V|a㦈ۈ:7[Sgp zyiɾ1JD~ dHNي% /M"Vi:;i-]Q[n2w(6aZޅ* z1:j I2'r(UjV-v`H-ϘIo,D2g$kRU-س)Υť?X`7ސ&ذ]1>;-7UoUU&H۷<8iJ*SzZ嶡JZ:&[mA Jپ*-7Ps28ez۱$@< F%LuPŝ~"xYj7mBn~ԝD$"''e8s5!:fF{BΥzn*73/S "G2x#ּ.(نi?*Hq M˃ $j>q%Ii2 =U,. eѤ6N̘րFLw5@%fQ9Q*c1EեQdY H-p#"7H͚wgMF8# TPETa;HTNt JW/Fj͔SWL]ÌH4n[EbURA _U70gD#>kGW.ajٸQ$0a __a kjp5uS>"}'AW>ȠԪ~bg*Ii%@*AC04tpB ?F q[Ef;S+Ǝ<,9mhy\~׫,> xw[9kfpH ™3|#9+\wJڂ\v[Pw=1ĵE$L4W]k@:7)QI# Ԝ~)NR겛[ [. ~ `:;8sR $*CcȲIM艎/ X" <p,Nv1^HP!,oHNP3A9o0Ų2o#=BH'2ۉ(n ǡĭ$T(#Ŗ5K%Ģ־b%@*βuJLb8u"**咐`RR)e½g!'Ħbհ*LEɔv̭:[Z*|9C+ݳ~<^9 6x̆m!-'E@,qa%gha v* jc@kI7I|+ Cuvʙ@U rb9jN!,B(i^Bx~"Gdx×x|Fŗr?%ΔE:1fma<ب O -нHW2#AQ5*2r~v+[m77 {vϣOJԪ},ɞt%BPɒ#(f6k BRlvs۹|&:%\>.e5(\g+CHmvĸPvۛ۸RoexP9Um:s-Nme:SCj}mb6wӶ%ij}*{rvr BaU!;f]>=Q BGu2<\-E" 84ɫ94"r2UAPhs5J'.Y IHsp0"e 9y蛪NEnd_oX9fv4!*>$6UҔ'sq^Cb=t)u!I~#UQ[ӕi# [H.9 %ҵKZ J;WyϲX9MG;>; u6T7kLC4:|ۖ_TW ܄ Ŝi@(5xGiq [Q**>nNku':|0ԶVܝX\[6"DO&':7Z4HdN:(m85[Ǖ0TE.:͗p0SLNVh뚫chӌl!;\ Iա~IC ,nr&>VfHQu˪<[*JÄY\6}-S}=Z&:y\[Qfh}eI5m)et,SMy To.)aDymŊvծ*w?$u*C@>SK,"#O,*7%.Li@٩l'i EЌHz!Y,ȥ"#A!!]A/m!ޫu*D9~7^\4FjʔX^YT͢IT$ IB;mթ9mQ+ 9Dr>*wr&_άСÒSr P@!ISI !!v 7}k+IFBkIp;ľ5TiPega\\ r&ǎl4 j$,-rLlB|SUAY8 zaL%v \Ji hZMzߜ9BYgY 9Oj4Eͩ**r4cKqIZ҃mn;^SpOta9~iG%_dz~Skn JJHQnΐfwE3ׯHPׯUYLjtq&ߦ5DhTU+ZZ B<:U'-մ'3m:\Rg*fu֩;!>v}MxATP@ y LFڋ;Kԧ%ɭˊP~#5ًx")R9!E`'5jS;UG)5J ‰[;$7cX dL/C醎?F=bP'Ttv]os`O4O$-Hx SnE|~,mt 6˓3NXQiN]uIS)$YJI +lE8YN0{+ `ukW%3_bDԌLDU5 [Kf:,.;a>&=(H }UޮiEj$g-`'bU:-*r ClhNr/r1fP䟜(n\jFinsWHڶL% !RY;oȒkԙtx䐷4"|YR̝Է\YuK2T%"82rkHUD9*USXܓ}c6HOT M:w3իYUX/DJGfRbF[|[RRT  $\cCO-J^I"gAk]d\}լ*"38a)*TH$R󈋓3ZWy"Ku9ѹ+HA0'nyR G~<>-v26pˡiJγkab;#ȯ\R}tgyUvnt5TZk||FOQZ ~ ' V=h$ x۞PE[@7' Xƃ9=4E3d(m(mhOl)xKR66'.=G0*YR?'@|#DZj-iVZ3%,ʕeعSSKQ R'ʆДntWlD!sĬ*(CGξR6bt3RZn+.=_BR$rK.&g^l-;2gUk,Ghņ*a m?,'_~&ȧWPOhy^lLbU7ts1Uo ֦uom)/AKcqжuѶN'o gikX-ߣdڅJ8r[@)v4}8|ja(sZq@:|Uk]`<'IU&`#D)uiQ1=qSYPB@~6PUI92๼Gau'ɫ%j_Z[yHhډ-FPe u+!Kءsk-^[P`c8Ls\ſN.+kY:~`@:u J==SiVZLNd Ne *bIIZ Sd F2u7n:'m"J)H4v;%Bi[BV.pcVD OuFk]ep'X$yQ\\vAG$N۪@rט-jd3ϐ(4k"?)![VAF*7kN$ >+dE Qll&ݿ LuY+Sws(3 $`&ߏny;Sl#la7%ԫiO?50l^ŢD2;V0BϖUͽѷ 5 Zk5A$hCj3c`r`&cJ`!]Zd0Z6?nth}0-X.tBA[Դi[Ӡ #T".[61݂.)Ý%*_ѢM:p(ԩ++zS6 -DY v`N44 uEWrD 7qP/m8ƽwT<}:W섐M[%n1)ndruvb"ִ)\SkSCIDuW%Ok }q WHS Trm(MMMfT*K ,8̪֪^`+cO$ۉ7˺p*Br,r\ub͏q] fuETo1Ujo< I 7*ڐ$\zdۚj6S.mHTQrve-4e~FgS7͝i.)aJ Q 6QoDӼR;ˡ/8%R;&t$Gmt͹.Nղfs͔J+T0tgۻ7MkPY*U{ૌzrUyNǔ/mZ:ui#]IEhEg j;TX󪛗!-A4'̠.I&j+nlx}ˣ2$ @gE\X4„i}]X }$.nC8D_,:K&>htY6Dy( )jo4w {[Yf3n88L73\M A;cp8´&dUf9oV׮Ř'HMTۊAAZ)k.N#RQi.&I'xM]t4^rP k==iV&^o\ S;P$`GqfJpUH{򃷇s-3e9@4NGFj3gL}B"TO̬6XKM)-Jphu lB'njHk\$L@ᮇ譽,Ҟّ6Χdžʦ.N`BaVҀkJl H%AGJΰtZI$ 5ԉ<[0QK{.ihJ\]ȍSzjRlaHBl-r174#Ӈ\PV\;2_ R5~rq@>Ϝ!b^D 7c{ Nˊ1V#qCgZ΢ZβۑhjU2%B~HEl"<(Ֆy*77fW7LiOȄݏ!@@U֭05=2$#x ׸j:OHVN[9\Wm-#^O?2\^R6yTO)$yaVADAЍ8[PQZdx#G%}O:Zr0d4) )ҐB@'-[F$XA`Au+>͗\:(F$8ȍSr6|íY[DhJaVi'bv}~:O0KhBeZyMj? gR#5ÅeoUm-OM0TePzuT'¯!UZʹ]xktUɶH=JĀK=-f6ARRr(˜4iVOJp\\;vtwLM#B~r 6.&i*[*eoqcL,X!p#pZAeԝYJTHEpqn6 Yw DwZ0Whv6 YIyhN8?ubz*'JMu<҈SM!õTp7~_aORElJIjrkEnAM- 1c{i;ШM z Kj9F-VӯRIA,E!hP-VΧ0wOǽg_RH؇j>kzo_}Crs-'K{&9N7E䶔Xt>k[ ƴvDz&5 F>}Sdyi/I :W$2n@q^EvuZs>jQym>AWod]EWӲiDY&O$;~tiSpk [N6Ndrx|kySۜ֏K6) JȸIY[|]f':.;Ӥ_Y]s8jM)!?8= Nj:q x~$]]pyf[D.,z:|_JCpPIFv[( J{))qseF\È@'螣Lڋ˫3H^.BB~Jsդ+{n]ޱc@ن3|֘#EYgA#J91uupxPJ \PvŪ]e6<z3ՓSXe쭓_w)jiIKƭXz&B32BlIA=> Q }T߆Ɖg|MfWK "iiҟt ŧӱ(I M@7U|{oQ}gb˺)c(H,7O[Jm2~Еn:ʯ)p_$vj)t 3ODǬpǨ'.4gC~PZC4ȡMbRSF*ez\IzZ|t5$+>{afڕ$ܦH;mpwqȶ*Q-TΏ Ѡ̌ԖY9PRZ ('ckq߸?0T.{LLsEO!:ЍmT9 RYIoJIr6#WѕUYEV*>:G6XIq*JH ]Q43#/Qyn= >tIers(ERite; l/)'!qt'Itp՟xU EsFd)ir+,fi)vKqMf;^W(Ӕ| Y&U7KL?(6̬2P7e遆͗ZmMܠ_Su:fC'x$G9*%ezEV-7MuJMS$KCPNeT{ܑ3nIk]efOon[y⿫X%U'8i n+ JN{<{q( ;ܩE7wwE:ZN_ԭ@ʣ~c1>;Q$ a<([m5{j BIhgAlNL]99B[e k8v!eVTA-2♌9|QT dw]tWR}iZ(DhSvR n@7$U]^߾G苦:TΓÓ-]uЮé)= 铹qVzEUnƩRZ uJB\P(y/ ު/ۉQ꘲HZu j"-EJ@ @FpH}7vZwLE1?)*u_z|+C!QҞO)>b`m m\nnTkȇLzWkzsN|:VN.Tۗ%b |IM wꓜaCd5/O,7%T̥M;K:T^t)c [zd4!4ܞN(7N3^KӳtF\HT kJ$%$fK`TJϮ"7/- #r xÇ*}:H+J̑^N**hp77DF&kTN4?8OӴ*RꛩjQʜ͛J˷8H!r`,EQƳ[GJֵoR B94Z_˭:ˎ.mItl7)G̔ptTEĉkQy.fskl[OR\eHH%i\u޸`b3j.#"LtˣJ]EU^b :l|)O/}JR@ܨ H PoXFKZ?4- Q9a^" R`|"ݽHojGW' sL̀lzg:SU̙2ȊJm:j:%V)N;@%N+!StSҮnQ4W ;ew?H~W/9!i:-S/Kʺի9zH?cКDDVf:@ J@'Mvy.=qԩUn9ǂ_S)f eYތ#ݦFu["aYlG kNO.@u L9re@r&gNw2S72(qXS ʤKJvhm)X]2GX =Q-꞊fLSJYHPƝϝ21 UiTR/a?3ǧ蓪T;S'^9WvH穿4^Y2ҚCͮێy@;[S巷3n`*MfZH&wvj̡%F@'ulSjʻFgR!O[[U?bVKrU/ĶGp&䶡JG1ϵ't?jթ 1Ԩkg3 e  QKJNs)|]mFҷMƻhYA#Xh]0"b !J}{*;_ڍ3+W*έ[Npls$d}CD~oGBC̨c̲ q,p6_Żo͖lli8gyZ-Y? 0_i%`E+{c"Tm*\FRm@ܻH۬{KZ_LN9А`kT _͆?zSc@+..F+A*]Z#aW.R^ҮbksV "cQeXU=90I u5/z48t3*ɘ2O m %8,Sܟ|ZxÚZ%'H7ۺ)5 $̃DԌٗ`|30󈳥l6,R{(_ {c .w|nUʵ:ianK+*I Zrk?sQ2 :=Yӌ@UD,DF˔MJ+/G^_<+*d%.o)+lۭa^½k3\i1:f\{cuQ,}3QksƤv ؤUea3mne8Eݲ]wlcͦdqh]XHA5gNPٓ&2~5G՛W[“"HX-[ Re\@j!ͪu v#R~+vQkI2Y ؝@Mu9RhdWfS_ithJq- h~[^2JŊX - ; 7=xwwGo]`gd@')f˺NƘEO1ԩ'jT.vuE8#=y]߈<7xR;5 4 ߁tTgٲU="b[g4%0BRK )U PAxNs@`8Ojx5N7T9ɘ'@K:u%:T©)ܻOpSfر㺉Je)¢'ͱ(6cy',C+gG1G_3.Z\ K`?LC4:f<\xj@a$T=6bqL95Vų.ۨNoҎ3I/[m3h'()/ 6tp;)K-]FOZ ĺ%eQ`u-#PN颴L?(RbȐ#()WicOigU⻩8~DHܝb|sQ&fT 4(ymjA7kMv5As0kptԹ߆VWӈv_ Z4lojLaIDvS@ek JJ`t{FV1mܬ[~VשT63:i#P.g9w21j:F3ÍiuYW qw7N\Ra=q$xKZRhC OrpåͨDv ǘ+c] $4gh[::hq:Cނ e p= 1\)YP?xpϻ2i#\DŽG=ɯ5u̕]GIK5)8cB!' loT`wNJ;ivGK:aS w#0׻(;⛩}l|:r̆6R&DI/R J@֔ĸu!Q6F$n; iir>#odtgYp Hc'>cmR-l-^2ITZlb+lIBO q V*;:=V]^6tt\3|${ZjOy*7{P o?{1,7:Q+H: :K5^3"V3*iǗF<ƨI )۴v%*>m䋋RuͽßH5l YFfE.0,*y ᡒͧ QQ XWkT[t:zI} jVq[6"[`(J vpRonݰms[[ӛSj(k^O03|w߭Y7a aCVUAqUoP&{ߊeJ?D[FϺsXeSَ_Ee l-)n(|GkH-kbM ?\_ ʠuOD;YuUL ^u'Bp{Qv-$*b |"{VJ2UN^]Ddf||5#O !>^{!q@2}tZc&玖GC:bMO;BERvݏ3L.*Ul+Նh< l_Ir+q{kBO7Ĵ Pڻ:#V.s%2t=ŋR4S. jSjq;u3#XJ7BaslKZwD6dH(Yd 0H52:˱ObJJN{XE7}@'8QU=Q4 ,ۢDW)R]r҂Jck%a&;uzPPrQտk˭Y:T2Vi`]iX7$X9BƼKyJ?yw\sW}iG\LJmґ:͍mMdBBG?ɺI33Bk.ɨȔo5N, ZRBݭ-_/=fPk/>I:[(D7P5\˝[3 *6&:/Pi >*g@՗5W69nJSPgxR֖?8Sr:P-ߟPDv!)y, hz~FQ^;yozn~;M&J}aelAkREG~ީWPBkJ5JgN5_}LSγ[ x*)7-;PQ(]?~SB̹}ca勼N.2 (PE3ċ v a氷N6hZkZRJ:|-"0|]Qmk4l9V\vR93+KDv.ut_v* IJ)*p9{VvwǪv荤i Q5[RQ{P`Iڐ6܂96JCo>Q{zg^)t^OhtG7Ud.Sm1̼/qmAp9p$.}ĜIN~t[#':R=$Mnl 3EruUaUXgw%1%$6!7U֚;G(Ż2.?:GASkã4]Ffey[RKln<|7ت/ R[ѧB*sT'A5AЎ6Cԭj6,ek'E^!-}smJT"j]-iai# uDi3Y:*w:Πcǚ50iؑτZm2B۸!DviwTsj Ϻ TvXtdI@ Tz>ˊ|tcVrƌ|A3 w5JSw;P{_{[n+jF#auPfa🚜~ ;!j+M陓 Q+قTi5Hz?nn¡rߙ`'jHn+o]V\&4 P쎪bu#__֙#sz&P}9M>cOgchKKHP[ؤ{o4lss>OYKX*&ekpڢ}H-#)Ȣ["y@YSXNɔΆ*ڍ2ILd{!cԀ/qLm|>pyQ=)i&&WfjY{%9+咡b]mHZRl:?1s^k#*z^AzV7ڤj$(-`I²A?0#6SS5ϩ1LK*רYuTԒmF|e-, WBؖKzf[|7>:L˨zmHDJ@G!7)H ,rM,nƻóL /ډOzK_+[TE1IRTl rI&u囂嘁2(Y|{FU!K !~fM =*R~~A[>-j7.nipRCK]0#g|*箟Sa8%se:c )E*UomGf C*q4|T ӥFY}ȧr W$6R~@ HMe.4 ;>:0{OZoC<AR*T[t(*IpJBS8h6~+kk\ Μ:fʕŽj1 j8yu/5-}׊ :TT3.Bdϩ(s] 6^ N1^`hؗ ӂ[ln^wecY|x}-' rlٺuvhd*aSRl6X=r7TViO uz]7zʚQJk~DjO~6QCwzG쬱R_} Vp{y|ړ֪;F)M=]Lb9[LrQZK-U~Y_W. q{? Gqnc`{%G=Crl:w_"=Q`aSsk"%.S;J Q%Jp+6K,47ѐ=T([YO73XU:HqieLk9]ꅌ}]*U//[ѭK&!>'Cs׺ֵWԏCD!tVHifOS!BZTAIpɵn vOU\T {|q'Sb̞gFb, a 'h@7=X+I߬#VLwd4QMɱ*mt->vUV|mS\~ؠjZ@%1#Bp닊uIq9@#汷ZgIOE_G7'Iѫ)JhqlR&'01 :V{iYuo#UC:O7޾2oOnq>ꗴl\T8-{J4i09VuDU4ЦsLGmakyD`GiХXGEH=+hZ]6%*f|E۩(y6+AhSq!LC2ӁA*#팻F-k-22ʻt5AeN=u4S`Sm׷79$CmT4RJѦЛY $\q-tv.wQ#|IiVmFQ;Mq^ ;Px2Dgfs4OL )6n*I1^ #惡eܝ~x{A),zXc{S`L#BHb'8Ɗp*AN+R{/OQ"}[io!LӪTj{a2JHM>r1Xdm%`c2c؊ʁut)V\1Dv- TU5a5X>ϥB t:ㅠe8BG{s4-fwR;kjk29]IКZΕV\Bjai(*%"${XoaTM`o'̘+v5xDϟ>* 56R?*Dwױ+SqD(''㹷~ӡf/@#^mC >j VmRX߱R{߾.4URITj6}czޏ--ې<*7q[򸥶f9@AE¹#{b!kBLi欛RsPu*Vm,., "ʿ!h %Xn!Ta iM}%]I !8,/oeì7Oy0葡PUJK/n/cZb4F̻QFbz]}hie l$b[RҨ9Dzlqip kwSYKiLYiAV>d۟M0QtHyc?o^6͵)|VX!DAI7H u(3(qܪm 4 ׈uޏWjg+УSJunCaM$\6))IOk^zx 9pח N:5^ A$ٷy"EA*[ѽ s:7ou-_ՍGYF~BJ 2 TV7ă{簿kgJRN<SyxS NDMj=?NfZdxo$ɸpU\4V)]0kH) (e2SKC$[) f=@נK{ڡk6rﴦ v(Bv$&<3̴AFF[ 'B:U'JvHi)JQ̀c//*WZ6:mܪQ\mBq# :2Ge"]`#H! tUԗ/rjҡ]fQnA=#y5h6_CAG*9?'RfA8RH $jt%wMN+Ky>U.$Tc?NQWX Cͩ% *Jo\z\`*{N~ L\=/[--eJL"Je\-RS游Q yǧ؝xX?䡩X=>f-*3\9MQ8iYZ3 '.U TJͦŐ^P TLXlz3:xh)UI8f&}ڮI՗TEi'HFld,[D؅V Л@kP18=i:yg4Tҫ:}^JCkPeodqaGpJJCI {vj4&u鱩 S&Jp0q6*kbuF~gGw 2٢:P LiR3s&T]LZGVMW"UY4g=Zsǡ\B 5k@bfhȞ8)+y{gt$Xku=Ϫ*APߞЊTA琫KeP{<iڝ75? xG,˭dOOưj֣JI&nif;Xk!+OVҋgDﰬSgl cw_jF]f\ߟ(ڧxJ BKwn6谸@nhι#nzQj[qG5g0OGW;-!͓aE7 m3^2H eH#MB7Ȫ}GD5L$TCِ`Lde!Дڟ1n4ğX~ YMԩy+KdB ]2ۍB?XT (m^q^=#C԰lXh&tY&R.Gm 7Ϙ`G~ؑyGߎTT{6;O pcq`nH,1L\xoP4։i^@/PqV;TЗ^$&xjW7(7.ӧLʎBK'*I4 p!LĦtHRHQ|$e6\=A$iOdwUy:S(Y#̠}=qD[~pk(OV0ynS~ivs^H]d /Zi͇bLQ1 j֘t83LN-2[S-i~nTEFB*7-c>>Cfu{[P=!]k|-t+z}&W) Piէ#! R \G6 +zwT]X;3O)T|`ʤF(::vE%J7aO<a,"eN`ֺ*9Ɯ(Wu,u<|T^Ur[IZ)YJIm)i@J(sxW h41qS^ջd׏U'Y+QlֆuTpR$ϕ" \r o(-«3SDo/i>eS}Rc- emٔ"T{h%$fa"V'C*~wPMR@iݡ I)ݠw,Gh)_G0GnFdyk:Vs!+Y5ZE+0}%Gn:w%=UҪNOh&nc̙v.ĸy(b<)"z6wu@5\O$> ;#VʮuQ0Rb&| vyZ_CJVRiJTJr^ʳ7~:AӞh 1%ܥ"+|3:(5VҨep\GnqB+jUIquH~\Gch< f#ȅ$/V9VJ)=<Ȕ*iHG$2; Kyor9,j Kkq5*٣Uz,@s]z3UYվGnBRQ &#b/S-}tD[u~dU4yrLJk5j7'إKfsK[1>(ڏMϙǤZ%י;1z]f[ S^H{ ʭCs7ktY7nӞH̀8XKyvN96]K 'pUՆy' K\@mf[I1,qy>jֶyi!״6Nf>IjٯV҃2IyrW53%ۀ$ߌkrRȕ+ms:^*#_B5 @rv&K4ȩWJSi*OuϞu-G<%Y8 hZSJr'N|zɨǣ35Φ>XLD+"Aj#nF?0) *Yk.9iւuz/ 34hTL6Eşi )K7$m&齏#t[zl'}T#/(ֵĨ*J΅j #R\BGٟOry\hl#XuoOĿ ǁP^ Eч1l.FH76 5Q؅\ 䡝]Hk\E{.>ۋ4qJSVs]Y :U1x6' FH*G5ly-'Iˢ^co:?,s/թ6Rk]PKaԗAn ) X%%E_S.cK<aRoNX?7tOçUQ []PYߥ<;9f5|{'ҋh%H@i޽,j;2DuNE?;/_u,7/cdPJ66mA0G5¶ܰcU~^P2RnNfH :| ݿh Hfmcꐢr=tP$jPIΑJjif J `'yo  cJ!Þ*w| Ӟe&7B}L 2bd%go{BoɚFU??UNu^ow vkX!:}:3eZr`Xl+6*t-D[~K%3}v֩ Ι\Hy re4,:dHM>ڐO P'hiZY4em`cT5wǃJuNizOKyU7x$O[!  Рl^v蠚{mw^ZYYj SRpJԶţ^Ζi#}l} |j-SӪGP*TR3qmV**=KxlY\mM8yE P L_tFFPb s3K]efG>u)BMD{_ZKԺ3̧If?el)t̺ssRl=q:Yu)?)rN(JT]aMͮW]r#* +S,! GFqkU7N37,w|“GO*p:y)oᖣAq +ī܆\yPE?\s@}T. I>i}Kzr:e Z~/!r3 3!<1Q$Tl|w(Y$'5g}Svd6G˚W2R않c2=RT#R)Wo'i$"9V}Vewj&mkLZ944V`- E~ذ]%pJh+CdO<5/粃\f ]ŞB \Sv6J.MjOP)ފe4m7k;dӪQ3MnID'HW*·>|V7LʇKf;te0EMN_qTKwJ P)UmQl71"eӻ4P:6\F+Yc>jNZjSԥ 6 (*Hnj츸ߊ9DzUgJF~r㓼26J\dKYyHm*ΰkݡQ0~>2iX"vnKZh,`ip)IIiBWq E=RvDZP1>ړS2WVYb*2̅19% { XV9"@hP ~7j f]-ƪT܇ZiǙ I Zy%@51&n|P5F4)5fV27XΚTz) ]Qt=OP,)k lA؛&b/ r1*J c p MqRCl@%Z?ſJ{z7A4fiyBOn71BS Cua-YuEֺµV9:1iX>3I=O-˧eJfMVNP$qp/3(S`8t`ρj=Fp?re격RK(交Yj=~2ېǂnx*Ml܌Q{7eZ tLyVX%X<\ᡀ{::vNV_c V5ϹMLQpJ,om8q',qܳp]x=F9KTy\̒tyah̶Q[V Qc`\]ZiƟS} !O5Jdqp$a&)9r%Li Y :nI0 -k{GЕcNFeP%w1QuO~FIf枦2$7#ROe<=k$u}(>|9. rݮb=>u 2s-RUBqDyb䃴2TҮHv+:g`NAQW@FQ(1UŨؠVҟnŭCTtɋx۸St}` :L1믔S)5 "|4+/!.H̟D ^Sqq KI(S YWpm4 Ӷ֝O dW2_-ۣiYWgVݶ%-$rX3;$e˖^e> O\ni ɮ~ψ%'t63l8$oݱ'[Ӫ%}~"=m@`dRǭhϵ%jLf),Ѥ?;yQVP<iOvZb8@'_m4?R;|u+]"e',!J[XJPFX\.FnM J:Xd:.x?Se̘甪W`TNǛGUpu#) {$U:C 01SAfQB vRTJPXBR9W'0׷@-Ԛ6I/8t6)% J%/9rh|e ඎu[:mJyE;IfK1) h+{縎@+.VxYk ˯S_9hMrlQnc4[ew܆TA%*Od.ۓT#TX>J OeW v^p5&;&6Z] #j**)!$ jM8GM(z}Ei^`it,W.I]]O#j6Ay3*V*2C.iyuY+n;NBR6%qTIZZ.x͕^b4>RvVu&e5u-gN"JqujRIy rC3'e&0A2OiaYJY,:\͵s.)-HRkZs:RZkGкs]WS-HZJԇRH>>U֙9E2"uKb,B͉i+A" |BA %Sa͇xi۰bN $.V(}S̪P5 ) 6k sgT I+b)*bc/#tmEL?$:cf;l/Yt[<ޒ[M7Tn|Du8BrTʙf4pd-V?P:.v8;O~;Q-3F?SY;P#iJ 2kZ?xUk014jK\B~ M'XrcZziIiܧO{h:kJ/1庖odjX6wv~l4;;~ҖCD빝OnZ[EKylD oغ`7R/~}!W'0j~jP& fj* $ K }>c}xP:T7-.6]OR;w ߇ƝTc_RB5^}&>ʼUjme-Ua[M23V{_Uɍ]qIڧ6R&6hŀG14T`.}E&fc͔ث~xESl5N4i.4<%hA#{iFb"(OY1Z_N)'@Z@q vTZ҆N>$m>_x F_OЧ *5BZR@܅>b7*fb#NRQB;㾂&23&9+["a7NT^a;Xb3V~S$z QtLN ) ll/o_|YkIP:`$NMǡŇU/5)pXosKj6vŸN(u$R^Zid`}?*$gTOFQ$V@=PV@}!;TUa銗- ZQsvTVre<P$'44 jCUm2If՗ mXZSm! Si tb/irO!K m* X'R2j&(%.ڱ$sq 0(nPnہ4A6])n)v0Z{\\[BObekLu)IE$k`2 H0YK3'Y%*j^oJW8k#-p$wLӚm%E?7ZGȮoMLC:|}{u$z9vUըX-JlGsRUvIka2O~}Ѫ.Vs# i>8Btpnͪlrvi~#J9:ӌ:X{KA$4;+)KHs |iiQ%&P e.E(jD* &Ƶ+ njY0.KS97[QbXfsj\XhD[2% DlIK%XcuS>"~aVz9[<Ջ5;=.Fyܩm.T@!VI8ݵeVQhǘ.~&r3fJulQU8'_L {Aq"!~ی^ݹg:V\v[Ioj-ʖ&vuscŰA9GCR&ASjD'h\Ho:k(&\ >蹂AvR֝O59vr OTYBJ oBVm*>\'}R@?|ҳsTbgWJ&%Q]R+Tu ,X~hIG|H--ݼT&)[ꆧ?.i9ϡ}bTUjLL̾qp'I *hGt~QY+ $LXj?!?N/Ry~ ekLwLTC&hmv _E%QSRd@q'0&ǎR=\GWm#?RfLt6KQja-s&c#3{pvؐG ᅕ'䣩x6LT޹3f<[]ؒKgaVRImj#eA3p ]a<Q_kSdˍ ʐ8?㤂NRyfj+Z>@HTA{L:Q)?^ɚl4ddy) ŇV-C(!h4WhTHMS9S R6PF*P gQutLuCJ90V`cJ(Gb:G dps LU/.#ThӺ;B&Uԣ8JP$~%kI25#|O* պA>z)h*$ꂐ<\LKAU^z Z4HskdOKm4ڒqyd\$;#nuW8OTށeiIvJ,)4kzVn qP"zFkc/jS$2͓ᄴI$o<[Euh#!s%C&RI jyŖRHq`Q'_ zEmCμYR#VcS%~49jB<#kZdٞ]RUI?)C_BQ{%\}q6 ṕ?ЭZBM˜x`O d)iO9XgRDvK+䫅--8ۛ,\=n5T#LowOz3gQQ&RޝYIRt2Y߸ssG$ۑtXfs{c?uL.i2L]ru:^[ dFd*d0$0]aIPip`kTvh#_+NJȴJvW*FC>I,nFIJ$m%F pBu9ѧ{BXV5͘P#]T9\~.ۊr8 /!*%!jVBnni#QW:=\lѿ1U]2J4*M*\f5(JSKMQ&Ä7NoV+|g=J5nky4"~KHe>r&pCgF\&~c@̰ %r JJRH$ /suЀ>ZdR9d> &ך:3OkZAAl+r#|()@)G.8*apsHA*/ `iKJnbEfDٺr  U-#ÌW>]%AD%?{ʠHO'u^.q 9M E yL_5]RblagtHиmXnIul wkXȟ33'ХdYLuO]>=9U5⎔FTUF~XT[ln1nr<"})* $_h>jHG򫐣GNd^\'c%*G>;\)@scϽB\t0 mXni:I/¬tIfx|E VrC%"q%b3V%Uk EVf-guZ12kAO Qߧʝ cٻ8 eb2K|i/ ,'yWu@w}ΡN ,_g76_I I+0FL,2%QiTbIJP;J$RH $/ -H_3y#.MWCM"~mjU"9c+FI|HK%e*y(}C]pTn+FcԲ̤8Q붻ޤu Q̝5NrmCuT)R)RC7Kw۴52j LlL?E44jKAntPoX߽*u ! =.AFA}.\3+i*0g`<'U J}*sBM{1-'R,2>hN-yP x%kg>sZ~CNU x6ݵ"X:kFuÂv[TQ|S2Jv^)rj w*NX<ǿ-N R ȰGߟ}Dw=ZUjL̏R IuqTcpI0}f=ڀ}!-S-GycD3R:0kvt=1r1@!uУsYDl(ݧDgϓz|aZ^u)D,yI;5˘ 26RzͱQKզrNv,E5Vښ8RV\؀˛͆4Y*t\y -R*sȧxHpMi0IsS̈@UZk+NɴlA&IE;u)uI[BH,V*1ìy9\igPiH55JK(aj l o|FƎDN`殩rĊvWR}+1U"D m(dGZ }@Wj0eح> _ou%/[&)FB,jTJUpw$sK 4\MEglfӥgYYB6Bf6lob T\X-%&/mJ%:^2AVYSU82aϗRn+⸫)_|5^H*OR5^ZS|/Vszl}LCn) rV/عFh01c"]tꭎzFiş'g4ˎ;5NyiPZMMk֩i=Lh~֕j4}NfݚigG(1(Bێ YE͸uFJ/XYe@?zyG@^k;\eUhϡrlpBU}͸+Ӭ\eTP*QxdwR?U)̀m/Ө^xwہbtLQ{\ҭD I 6+u"v)رZ 2ʍ;8m䜙ɯKd ZnJck M ٢{6c3EՠhoMF5L-:јUOIRXCa[PF;]V%y{F5ばU_b{.i4m[qsy1j]A3 %b)'8{2ONtŖ_M3' .1T] ]dy$?uw[Hf4[XN;G!Fj"uӕ:~Lw\-ԙS${[c/D˨CgFn`2x:AUK*T9~#)6dJ8yJ('r6{Xյ+1Q\ xIq2z^ƂK$Iy4!h}.Q(9-71gq w F up8*&4I}`sh)W'6Xv]thBȐqg!l(M4zGh*s|aGq'GYnN+"GF<7x(T]Aێp~f׾&`21@uF|PQ]:I NB{=%UMhYGt.'M(ZCXGqg¨<e^+K:i*SHJR=M@3pO0~K h4,aE˚ֹJV6TooCV$-MQp3#̔Q\-JBA'4 n):h)LXZǓl /rKI# F&[rH)GxPa{*T|5]|Fʅ753Ƙ eZ%MV|T?hG޾.~੶=Tbl[!*)ڦ_qN@Q"eۈ)'‘TH+fȦ2*]loP3U>]w4nv۸ R1)J\,=9TTϠč ʉLj~hk`A;bHP಄ưJx 8ɹZ l N H.ʍ㪪>u1;'CR4CGqY;WtrA$bKHQ4kt)ΎH=ʾuFo* U*%]yhw}8[1#TKBxiYZõ'B;LUڑ.-mWH>߿VkV5]yƀ, LIV4JReqU'dņ,J҃=ǿoL;E+!i0P|ȡԪ\tTRP=91:l5<#ذ.?#$WlU*:Tlqcѳg=ѹC[<lVq|4[{wŏR곙US ̞&w=IRD~#7 dʫZӒsl'rUGo LHJRVll y6L1 .Jt: HjihUE"m1,AI!7Q7*NC> 4CN~"~ +R^eVשʚMF[ezR]8e)u\&Raf3wGu( A~(]:e˥9iyVf N@Ӝ lŷ\ ;'g{YH#ͦD0#z'Iqo7*M7f~"CI @ Ugk ӖVvt<5uJ}3:326 yfgJBREH'iO߃mQ2~rE&t썦u\*f2ÑJut]mF֥)X P l63UͱomP Qϟ O1Z[TJ[Vq'3(޳8r?Pۢ.˅2vA)JʃRIRSR(~,Ҫ3x(jр;Z4r^"aYRY/x!2Q ~$r[=#g{927J1fei4 iqN*#i\ouFBHQ[T J O75䡭e}aҐsNefZܝ%]~- v n7 j[8ǦE mcHS ˑNjC[mQIItK &y勌A y20h3N"?[8(yUQ,->рx* $\QcX]nv_#)Z!\YLc̐7qa$$ AH [߿`0J6xjZH؊ǗY\1F1TȻҐ/-5?)W-nh\4]T"Zj)5 (gQBl()76u$#∳(9mͺyNkQ<[~MN|R%*DV6e Ju(XbvC0חR1,G!=Ԧmru2_.-iu ]+7;I$bˢ%Urt^FV矶ꊥe(wbP 6RO|U5h\= '&t&@==Іef.ۺȭ2!$rqU4+i>dYEt'z+Fjbӡ`|*٭d6C|YI!7 l#=.XhsWE2`).E&QBp_˕M?_8iܣIRn۱Ű[[R1U{Kuk-Zrn SڵFOiZ76ۈIPi 8=[ -R~Z^2Y!h5Z/ .K.,* lEbצAxy"mSЍ}0jMn3ZӫuS+:N܂ xJl(Q$^ :AGFꇏ[z}vj |5(?"χXuc$:A7;@RAaY9c^8ft#6f ^yZ%֠͏SR%H`wcR9z|IM?$·Zȑݠk_EKCx]ƃNh"nFô@C\dl#3mQr SYQ[-ؐRqnoFȞ G^`ˬ夳ZRiw2KeE0ć.7( z_l}VFuO2t5SrgEOa ﺽޓ7DBbSjsKk_rl[ T@o+7My2Ρ^/BiNIV0eCR6aOcqs4-'O9"=VJ׭?ƪwϢ3>ϥqĐ*5v^r--z |hڵJ+=-̬RA5>)9ZE|)lERLQSP!JQ%`}ðn6C w(m}ŞQdkw1WߑMGAʥfTym&I%I V^qIYOZ;bOA+1>* LRR3ԥyJ JA*rCd+&ͭh y k|um ;>.YR>!>=U'(gXU$Hj0 HB'BJ⵸ {ϪFލbjMi>=oFѳE+0Id!U]]h!0K-H!*Zag1h'_KUfUu9nФUy^SARepqrE֊ب<*JgS`?i:ws@U$I{{˭,䅮I?1*4iqR$JLGSӶ^RId6Q^ВS)P>6aLq|!JGBLC .>4Xj2REUVޠqyiA>^RӖNt`9*#'pWIO/j+̒%(H} \]:4Ϣmlz:(4ϢdICj6iضTݱHGZ? {RkQ">˕I)& dGsK='pqRQO`Jf.n|};ڣa$ʏ96P%$"ZaqDCX1D֨]?Z72]EbrVQEZ]B]*PBZ(8@BpAq^ZL=>h\yG{ErI%j-24̆n$njTTr8%*<lf踊tI#UJ38JŷJTo“6Sj :AҞT,Qq4 ;uw FMK]~[X+0 S OS?3dYzRQvlSYP rCKEACjA[-BG|x;=Jc =UC[:'߂VUXUC.(HdVߑnRO>crJd.o䫾 {;>(K Hr'ᵞpHd`K 7Ӎyx/[:ճ^öϏ%PwRZWc`g~C4${)E!lH0vm.R*QIŶᬧ$92'iK;54#BPrM13\$3pv*B<Ŕ':NJ/+&>˕dݧ6=i'dR~j^ FNy&بlovN>*Ⱦ Y}ddDӲvcTӨ ||)Jh>$mnP?v(2NϞ+ė5zW`jfaz6>Hs-,gWˡ~x e6+jo KzquT T;- $)*N0hc2ȕiq͐>؅Xҷn(S,܆-Bd\v;L6֘-vqȍ{7Njtәg8ӤsS)]ac:>#UǷ+=_BG#BdΥu%&Rԗ?qy&ຫ.Vtr0V] \BPe uH,:}9ڽÃ=#y4]%^]sMuOEr~qFp4<қmiDg_jB ,,%*6M<XٚA``*Xf'Y^ ǂ'BC&F|ʱk}W黔2XxUG)$nn?p1Q"*{z):y2}c`(j.fYJCy4B͉aG8}An˝#(:,S.Ȇb&txSLϩeƮRMԞM֫h鋸PK<~C8DZ*<N=sCL|Cl.˟4_YZB49F:cE`mFpGƽKniEѷlSU-,I%eS[Q)>Jw2[Ǘ^RG+v)g?DЅ|XVϲ%ft.-ߠr\=/!@l4);I "hON RZfc)"خ(3rrr}ٞZcz[`b{ZY zlڔ|IU=>ltj/#-kiS~s.H"Ϡ|_po  n̸,n^d)-;2Y30JvG{P}ve˺$*A.LyIml ۷cee)~e͋liIҵ)ϻ//o' R?l%~!8z`uZS&T'#obsR2g Fe7Z/k~mςU[Q켨]nLv[IˌZ vAx'dElV7/o8n`ڰ''[0I RT*)XDVK*CjjT/*"eqViB_VZlsہLX [S^8wW>^Q|-^VQj=?g. !&%@Ki>%4_QpB_mooճFLרކ<2|?P|4M]*+?*$Pwm6%67ʻVTj7Sz7=`kSZ:F DCִ8R5uy)* xZZg׊ t_LQ:0^˙☼6j 5>%ѿ\._ J4M%&mz f~};s~]w3zM+nE3+:,;%#7GkvN ) G×lt昍fѨh2W&BX5NkwʐX̤4TEg3.tK30Tj@QK/@!K  ^l.ol "xFd=͚Ñ eڜ(*:@XNQ);ԑ^خ@a/hS>͹iDf\ZN^uf.[T>xڻYO${Tl*4 £V2@)Tlu;Sՙ3nԛ} ͉U*qx{RҐ<u[[ecT.$ru1[T܈Ir՚Df:;mˋ V}#4dG'杵fX_fO[ЪRy RE6ʡl`{naReVHjοgi4o-_Y%:%Hq3^k.pmMգU/hTI)9)ي*IIu_ABVcJ-ҲS 'uűF%Ŭ9|>n\_VZu)f2n%B)4Wd!-;` +j.Pe]ﰪtl']Vk+ti zRkR)sr\ jv?cAU]Z}eD bVFZB5VDžv'TGHT7NpUZ VrdSY!֟rjUQlmJ&)VN瘑y[Gg.)4(r*a։ _U PRK'uNj4 AY6iCtIÓO6*𚐦\xBUG!lZHkrb`7҉o>ʚ35sYZnǤg̣Q\G7$s\ eIlG|1}nZhZ`M:oy\yƣ-MȚ/9 ||n`)dFJ0-(Fm*XNn-rO:l9FF(]Qy+yjH _hE6mW$SE{AgÀLg=XԪd|^ɃJvs % p 'GԥV|Āra)_*k}Cj&[2HuJ49+myGe~BV˛(mvMxԟ?A@nϛJwL$M̲s˄]Ԇ]I)P[[t5VnQf$(BSfRQqR_ Sq k>ᎆi>-!E %X=?~zҩhpseL)tI,xev:( $ҺiH5eM_fR=XNǶNM"t.M?6yo6H)%řU`Rbg9cNmWi!ED]@[ 47+yPIʗtzs9C>QM9Wndf*yէn,\.+niyy"{p'`?z7ޗC3?/ifLẔƃ4/=5[ܯ/Aa-Y&lR6\Ac;= O1[o6kRspp# Lϐ\|Զ$-[Y۰UVr3̟@{./8zs#yKV֤W'Ak9esM7 Zcv<5 y*.41{>YtW-a(G]$ iJ[W 튏@i1@ v#z:[v[IXNlJoY) qnA8'IM(ް-p)圲ʺSCAk MVGF4^:BhzSIvXr *Iq*F ^Z[tnon9[4.gTK Jam* #~/~(ycQU|el*^] s\ǒz8B)I$4O@mq 7y8KO-vy4RboBP8~1Y' jr.A41d>մ;2Zer Or8㘉SnH!g);Fn5MғV5u\[߲HQܵScUXsOGʘ?$8|H($jF1;}ey-Nc6h6T׼Pmt:Z#snۆH4p4oަP{I@PH5^ʄ4I*[TCQ[*U{YXi;C歳P{䬎oU٧1Q4^RgozeDSjRHJY *giYPUnzMT +4ƔdFW5ɽ\Ym-ly5i:wf$ ΖF0uVZ>vTO0Wt.in+S*Pn/(&<LQ2OYϨn:4LӨ3iRSI~P*IBT-p®U.jf|8U'M=RFdk~TU=Kh5,.,h!RJwr)i6;0vpg_5_. *ޏV̕==2C +)J7]'nH TڛL1zMyE&7RyNPbJE2Sju!}OnOE&8g1= ΤaRnd)Mk<8^fuWWpu#ocmO( >\xU:z?O~5>!mYm M*M\'M"Jf44IjYO]pˁTL3K -)-[ 677Up>"RLcn 'AbZCsT9[vǔ(x6e(-yHSDJp B'"6m.F pypo{I!%@6n-vKOdcuQ%@؎t;G  gae(w%ZtCh\E 8iT^s@M%q ȟ./nQ)${w1TX@WN7F5uM)zʄ>IJ{~X­8X]GAVoZ.#4[޳hm43k535T/w# U":~w R-/o=\b.m:8lZniRScq~FzjG?axmgûy Ԍ;=AiB P?cr֬d^]piFރHӟ2`yLӢk 354UiIRϲB/1i1f xΏ>ږvlp(鱑) Zw:|~4YUvQS,Xf{ƞZ#ba } ߈ֺ,׋x#E!:A6Ö;!mGt|_lf@Px[gX=x1_P+:۷Ym,rA_Ng_*H@?CZ؃+擾'XR[Q*-,|Us]a6aL#f?kh0?Bo1+dҺ:w+n:'p $m7=,IAJF*13 u\XrOb)[Jű&%`DeO̦{ZHcRE+&啅8Rbf܍%ȘMK4, Hi}Ų%}#ԓ-'nk=ƕ<7EnpMg[LCze/CFʈo]PQm %Y۔u XKI@U )VEcF] gpvȶ겛.&²FaԄ»/fUMTTn?ԵV)nԜ; ,[$Cͅ܌b5[v~|x%6XVofi>Z}BOmFCǡI虆FuO7O[jP[=j6 Z so@T= *qM8vW[){.:TIpnpQ*QVIBPAء{z%lzʑX\|Q1қ@i) ^)v9g| ^tS^-"8w`!5W> ~du4Jtt۟,ki mW:גYTb %j 7UT?2g=ԭp={o덫KN/X8$lxEҧޖ`Hk'ۑ|3ҨIJ,<̭9S@xGoO$kcO(\m"Xt֦~XrbW[W3U[ vwNr9^ lU/]>Ay[jkLEucEEۺ׷{~\[eYJ| ;|d2-JJO4Zis# Z]씋1+0ʀG paWQb:6e-;pazR#8IQRImug*~P D)4_^uԪp&-0P#ET S  m6q&=C ~;y.X:D-ك)UcW.%)JݍyrlnA$h#1`#2i.ב1 _k=d$ԟhIbKh!7)mX)Z666)5u!ډ@tϯo|`y4&?Q&)%ɱP[K$FaOqMըgȩ.sRӛƌd8bREi95RZJ@]</|9IGR] 2[:5+f,dʈӎ<8#8屺AuwvjaϚ)XR- Bіv$7mfX0I[Nǁ+#+*I 1 8OʌW%*ЬL/ɝ-tY6P*%S[Ke)|EBJ"ʰ @MjCR?Q\r{m@Lq6̄ܬ cNҊHb9z6OP:;N]`ޡIsNQï|c)*a틭,٦?|T9*QZdtuQ4x4JjeG=ʑp8ダ(BUAf`AZs>N8Yp>i O l^QɸuC D)]WܟgjR(b9C/HCiņn$\;FiǢ.!Vz'醥iQ6QS]-߉1\HGmL/ĒTn#zP<)ldj<K,ٞEdXGa6S z`ZF߂UcqПDÕC'bjujcl)ti B2^f9©qeE{NR{}4Qe]>jZWEs>E RԔ}2 mU¥7Κ۟&]LtriZe>#ʣԛ ߲t(I^u,ZHA;Zy)Z|7o[+Rs-f+t,'Mli($ry k>< G Ah:s)iCp#쌽`a%aj;Ҕ${e !&_Q}0GHc2YOqHGeɰekh47 7s{.0ưM7;#R} IΖy3^oЏL-5RoO*Uh%IY)qJH6>I&Nj㩠, @,N[~W'\vi8:×1> yzKș&>]>R'0ܜsSS%r]sRmPTm#~ Bԣ+"bϧuCeȺ%:Zf#qkP 7$GRK겜o%=YVڕI!G#XZ*Bֽ2U6bڍ"Na)oSn$KopJ@Y't$;ìa.@{|E2~?5Yպ*./y$UDGTu fBA%*#5!'h*i1Jb,OS3wyRG3Kh^qI%^Rzq\XUc##@VΡ!i$~]R|X(7f^AMvk@𑽸]BKb$Z}zNk:4.~qZAi#a攜Wzzl=Bm zC:qA6[CHv]cH=6w DŖ3*Ҡ/<]Z.ޭ@iq 0gH1 [rαblcio i%I|otr$djJlZ3eYʒKޖmQU6cf'] mlOZ֥8HN_JҘywZTQjo5nQiKi>Q%B)omr@m.BǛ'@^ *Ī hGh3SV'$8e/Ԭ Q m@-%u!IJRXmp#W qTAPF%N¥?Tk.jkFk*!5J͵AIOW)Y Z˞ lq9Ү̇7A> 8;k]#icBt#He|F2tMiԉ3'tTaOˁSݿ0iAClI?ҥ5*n4 ryW-PnꌘtM>Pې1z `AәC8dcgɌL$ԘC Ie,JHe1<8y&$;| ^j ve=Өޭ, >DMC׌#h/:{m|{ob^sy{l>;=A񔩔J ]ctz[+KanSn@qV%9š <.{uicE*A:e]eo:5>I)rFD1wJI G,kh 9Ha$"<yкo\'xج!͢޶{17~gheZk_L]V)DgU6>ls,N%V:yC.SK麶@.Ӣj9RvչH<) Ob0cW^}%V6`;$z8h|VU曢2G|GZS>SLw)+ CWf- A{"vmJQ(8*׫7]VHk4FgδB%6/[6۹/$-ͻ3`p'גʫjqcH |$SqgNmCHԼQ--hU ~1u H \ @TmjlE oT Y%51⬖OpM~L:H?5j~ftwPzq]U=]IJLG8m37 \AOKu8܂ 09 >?ӫն3}:t#KZhysGQEq1ώm-Q[BQ;@M&K`SwsV?]Z@8StiI8IM UҥS;Q,,+ 6v8p wQ lT{^w="nivv_\},8SkDPM֦ e\mJZCGח>FffM"c6PiLb! U@s7עH#OށYm9_c5gTt{BQU:|4ȉu , JRBBXm*&8\&{4S\\f(~E9FE5g%Ө),R"2׈'E:Pa#XH]od|hKVc%.h+ʇKJP6O8!Q$yX{ nj-ቫP(4,5&C~`Z)KIèinQ%W?\t:y=yBhR28e^$,zN쇜A[;R p-A[@q.|<36R_eó0;^~ 1?Lj lՊ#5 VeW;&.J -\e);RQ58 Ym>q<|bex=;Q*eabNp>FsRc ֝iJC$)*yyT1\2+OMnIUl2 AD0B)шZ 0mV AS)t J )"-EhR!h[]P< P?Qʌz+@BaWH eWꣴׁ+zۤ!xJª0H;[nܒ́Z;CcmDh⻙IM?uR6e(P=`%se-_߆6[׌- 'ߟzE/4O{mҔ#qH'Vլӡ>۩wX:% f b:'Zt#* IlK}1TLuYT k :fʢWKo=tT8$rz86mwyn*RiFR=_"sY:dC+CMXv*'f" BU'igWH@3>ƗREI@iv؝e"fUwʥk8@#o,tԂ $ws^=*E94'tcn26R6SZAJ΃r@quɨIa$|s:JXf [5EUIǩO4VɁw@^ҤꌽԚiuJ+P婇YBF(iV$%*^mv B; ި\].eIXrdFʬe kr$J\%R'8ƪŭ!jII:' :DꏰT9aJ|MΔ*IYP7l8I'ڕA7C?kVf6ie Dyp^d> u/kԃ} onfu-sqXv\xx03S~cjfXKa0"#"߷xVY<D'_.f>+r(M=>˃'q+b:P%WTmŀ8]g=SK,V7ew}4GƌtHGS9SN㑜}N\]ma+9UvIq*#N;Z*;2m`"CkaҚ!+)̄n,O @ATn:"dx Sk%dPYa)aT0R_GvI <+5 UUy}alѝR;7dnY} yߊ jY{w6wTa|?C*[^; ZBznrBDӉ@vpb]:Se{7>V=ix!Ukܬ &fT蚫0f=%0!iW~&rOjݤPVcEtOSܟ+1H1(E[) rMRa!$+bhw U PA~Z UCjAE\p(bؖ˄{-&QM?9Ҧ[u-)8Rp¹IYjqה)!hβ˛K";P jTWx7 8Hl8t 㧢U;`u JOMM+2+ZܣG) W=):ӤhU~(SgzԌ4 "P(vOaJճ +)IRlhЧd9hUkP]y6M3id=^8˺eOyHpA +ED:#'_<<1UT26c m@_w$ZonAy[;^dm\ctGtϬ,OQ3Iy3KXKW6B=%P@-+U/)K0/SBߵTIԏ=5zے'+%t_5QjܙDf @6m7`n9CPF!hw_ KR`hY8idT謲EmDR& $ rHx#sE4iχ[f$+ ߆U9fUK-y7RUb!IQU&اO`En{:nZ&[ռȷ !4${W۞;@[gfF( OyrĻB*k| =̦>s-vBZ\l (,} !Ѵ<ߢ)գO[/E.S^NxS:7H#rv$H/q0{8L{*VX;LNj[',ipru kSɬI xY~۠.-lB^Fs|&{ 8Cg}9d >#_Rs[z*eJ{1s ,9ƉSAr$$lS[?xnLh8&=(H]^fL5$'%et4!'1Q!bͯoI![oev }AI3~4Z*?M.% '.g)l;d .-Ֆ)K,<> u= <+ʉ-qpZ0kD]5tm,H+;HZ@\.hRvD׺} 5%"Lj #X$eZRz9T5/?IQ Vsq \,Y!kJ{-v塒xvAA2/Ӕ+UnMJL6u%)elT@Ek[u6CO"~&V5ɿXZFdTmKkJu ]:,(ߎJ-$&#eB@:zlUhZ'Fr$p**nHrHJ؃5jY kAHOH]JI 5 j%QLJ9HG2A7Œ,nB+R=f1O ?yc6B~_mu)9!a]!7)MI1j$@' buAI {hų;ʹoR֔v7S`TcGV<Bn|fVדJMW:z[|2kr$:ԇ Swi9.9 )al] PX^]Q47 wz"xIy*SWbOQ]I:'ۨQP=PV%Ȏ# S m~$E 9cO ߿\85LN|D/K2ˎ?U*|bš)+si@bۑz^TEgi*}mU1bW:>*WȔb|cFF6psO9gSX1.SѝD^f|Jq!)QQAd aV"{c|D$Z_l9*ٗH!TkӢPCKt8nۭRgb)yTJͧ'4_HT:~ad:%IgJtQRSTdIUA)ʥ\\aԩ o-g EH//l\YȘ VڹVZѱ2i[tc"4S[VGVFP$.x6GJ2eROoޑ"-(3T&:B/xae)HR׸NCrnT"T9+)P3Eq&!.DFUp \x6Y'jۜ?e[D,φe[)M: #5OZJxQd-k$"p)ld~jۧ3nJf! }8L=zZ۱ţ联Uм^-q~_9)U 爫@o`M5.+TleHla|B_k4By4PRpT>3 R BO՟Taҧ!TBpZȾ:$ )u zQі[(MS+֩ʆ\lnޘquuoC=G4 $ЯW-6`ITJ9#׾yVIC~My%ʔ!|'r籸#mcć8kf cZEVk>WY^0˙wO2e% e R JnlmS UbK:Vqꁿޛ*mxa>R=T;0|tPc¯."=8R))*:h]؂[I:˜>o.l{lX U yP:JԪ"QB[O!=q􍐘Dgh)Y\j uRmCnYqԺ.P@'+4G\b"A+N~6qd|xӬ %U=Z㮴uxsCʱRIH"qQFWEgEj w gTH.l|J)}DZ.6vi+:ns`5\]SOT,6UQk')lYܫ ˛GcBOv&/v4mXe𫍠p,N.`eVHh z-"/6j3L/옉q[B~K6q-,Y/ߚ[ u'T܎shC1s_*5ſ4/;}Bb͚aM'8S}Ĕ(UAR)#2Ni-,n$L5P =u~0f87th[d8ocڔ $[=nkj* G8ܩz(p8A\~(L ##\Qp<XR{IZk/:7nw4+ӄ\YV%ccAeG FHOO[H *l f)9e;sqLӨ7M$w[-[V=gZލ' &c EHS-=Ppo?UVe4kۂS:u8Bа툩 ৫X69(jH\䧢]\õO?a &EV[dž8 1ěp_:dwQ8Dڒ* ױ/l[PN2lzKiޢځLSwC,fiܶ!#}ku؏&lM(B\ZG@ƦO,6™Fĥs Q-J6)X bNLY>W)ͥ R8NASy2`藷Vөmm1‡9Yn0wsW$MIV'u,p- u !$PO6J)7q-VRT*)D:7l.d>FծۚnأS5]_'r3VBg95qiZv> ܞo8y{ oG.29K@q$f\ZEczƦkpOJ}ږ{|Vӡ>' @)E.c6AObk\Ύ*ڝce] ®֓}w6Jae8y>w܎%ka4$Mܩ U+:5(1+3)˓BWqa V퍪Y#*Wvou2{=PϧJ@}Ų\JA /cӥYj>+mU?D5 HTtM;nPUgP MRi+ - ƄCM" 5=Fĭ:@>}GM\s#[rU~H):]u}A&jb]QΕ,:] 4Or{!G1ATq vf{N:4g8GRKI}>Qm曅IS @fϾn ^Pέ5^pn^S-9'hӹ 4G5**ehnv_}!ZVa IPڲn]=]SW`S3[ hِnV[BT;rpG6Λt{&xΙ4jEs"szPZVnq(a;$6OinG>H*OY0R3%%-/5XyI jn;` teVQaʈվkzO9\89OYtq.S2 $~ͭK<@ J/ 3SM77b(BEFQ0Xڄl(v<N*sp҆\+UhV3-:![r\m ȵm >d|]n1[8c,7[ZZA=i망ar%RiV[ɺT<ܓ`S j◕ ,~;(ZR#(Ы׮ 6h)x6*ԉ T7-<A6*r "K(S3:!QBrUԺp(ZK4އa̅7G{*Utǯ]%Lf1$ \D&nT_oRwoM1A3IӖP#YG3S$*2hO|EFU&C0P `#Bڠ{[cNvӒ'JYwd<[:uԭH3_,Ҏ-%?m$؀1~{ #hTkR;*u1&N6EiǛMK!&鲂H8WkM #âM9n‚ >A ZTڒ=־).lnJٵ `Nz΂(Էb4Ԧݏ5_I Q \ͭըIt)YEE=R)YO$iTnf*WZ1Zw&OA"$s3dj>jsGgoer@r:W 49BjT,MX)@mOb[FݬZTզ||?z]̯*;P|H|͔B MR%<)bu4h=}$1eUR'!Ңg<ѝ)̻ELrҀ@ZIR[YanEZdt{*sg:wJijFkPhֿe/WLf(l)«fʣYPZ>rbzRz1vN% kaJSw{].@6ΣI9{ƞ GWdKcꦨ,|կ]`rSuLgmWu3% mW *n. vt Ds>Azte̱-/Q5 {IbrrN 5.#pdP*qD{p1hޓ"؟8Sf3e: d$'ҨQ#*ЪTgօ~?#OHC(*ʶӺ`f)QGU5-hjTgE;j< *Z'BH) %Ci€$xIX={]'^S_(׻:kb:u eY_ʳfe(WTQ®PGj/`thײ{N; 6ڙ2지=3C{Ɍ={ff ڤ2Z຅@ OC}7H#cOh5^Cmcĕ]1͓a!r()hI$"-W#clj8TihUfmjC4}R9PQ)ēU X4\hu&B&C`)`xl`FΆ9)ju-frG'/m-mVvþ<wէjyw\5Z  m$f=ztP!Х>ʀRS{q#opJ"Rj^1 NNe'-U ԇO$i ضJ%*6uϋ I*J,-ѽ8w}Lj<2[{% f2&s'⯆/ŠԐ&sqb_omfvmeqt>SWNSJH*ȪBB)oJ@DfXeahJ̵︲ \5ѾH#kn=ړQOmhrR*Y4%I*J%ՕHYm$bptzh.zvXD9‡Q1sBE迣ܶ9+UR"!q)\ ^GK\QZUNDZ6B?6#iۼY'U}YT:gw;TE.Ky =)d)AAQ [Ǫ`}Q׻ 3qx;}#t%27UP60^X~,Zeͨ)M )Z͆)R71)>Ah3uF2C {BZh^oegU2rM\Y}(n>s޲$+6s48c wZS$H#*)A8|;4Bi:vsMg3f]MR.nyd:lk 8.r{NoG鹲{:ӭa,GMզG/!!"JJ~F ؕئiwŕ"2k9P.SNTqhm!{cXIyGZ >?={BDDe^IjfdTVCJny؎6`9O{fF('S{iޑ3]kh1e4ZJ,$y{G =Ksq_;tN~EW\RnbN^`fƺz>[i*5dJS YQr@m;ByM@#,qS+|5}T4oKGo%O.nW:s4*s$ox8ZugjK6U=p+SR9mL{Q$5 >JUͦT]2MpHZWίq4ֻ)Af_p+,ι&$ 8ڝ|% ^z _Jt#.S$0\\ΖoJ;!@ GD^ a |22ǣIKj]^'] τ~*˳z~`N9QԊvgjBBN À@ T\dtGBڵ%YS2M9ՙ5:\ߺS.SI15Ź&W@c|4~ky9jԕ Oi mrepF)t,tLȢڹ\xG}|oլ_@ZӨ1t)/ F8#)e˘p?5FҎzN4iyU\F9Բ9YtӚMun m؆ !!%kn@  444$ϒ;;T$Lty5҆p`Q8Q&Z6x}cJJVQ:3Gnrm`7xx,Uyeegj|˜teĭI%čO8yU<"1wJidF =fτ֙U()'N3㥸n]=XvB\*CJB|6Ҿ~->z2kUiy6|? ssjLqm J XkVI-)&װa̞EBzΝ;u 6~SC.f4M~S.[}x;BqKSOx}}[!:cLiM8;JT?#c CD9]⺐ml'J.t8oR6B  0Fwǿ|B~q }p$&kPjdi}4wX{.>Cgd>9iA +Ne81Y4*LUJ`A=q5TR S!!E<{ԉ(T:Rۂ$P9&ӵܒB/ʄ4#LXUr$T),gotM8%?0!^> o`{"j(ihMdw VJST_Eu!i|uJb:#h<$&TSSzzh5TW?@paیo)\PH< w`ŃBqz.n)ZTf<,SC78EX-CԮ4Mw5\6ߕn?OIDsN/Um%.k-W =@_bjxN4v> *1~%͹>X{66Ԣ >Y_s .*+6c)_ǫAZexeYϿ8ѤX$$8UɆ+yw)T+1="f(hSbQ6-Vϰ}FVvFÇLY-Ŏߵ!JJx+=.@̣A.w)}ZZvAt#e74HԗZuƑI1ڏ轿M􍠺c]W4}V \5*La\͐z[v"0saK[.V[#MOiVk@oj- mjޗz:OR 2j.bK1Ä)QHTpKjTv/߲ji@Pṫpg.)u]Mqq)X!_lޣtF2ήrdErԦTu`- e&Cjf.{ޮRxZ9Dt6%^Z ,Ygw"\Ѫڭ!|ITy~bе <1QL(n8T}.3 ^5QZRUJUYH[7ڕ9䠯booMmr e|m`Pޛ*,ԦgEUr%*N_9?UiZ";S}ԅUq)]L5b}!Bw q%9R =IhnsPTsA:Qo9嚴CMdT"^]c8|QM]V7 bsfS+ײޣ3.AWs6:>Nac8n!ٰII$4D:@FڕS KҺ` iDT"Sp%ZF܄Nխ $}~HJMGS*wOTL#7ӫH[3'/R_mqoN[A߀1W5;yv7e9ܵk=C=ܣ0.]i m*{ rHǗBKl+^oLR\&;3k^1H ͍tDN|U3QdhuHw6T$:GkG|S! ơ#>nd&^HjLu"d))Gb5;t*!DmE{ml: /UuP 3-Gvys{a #7(6B,$l105>^7p<֠鳦%? [YݚeNOLmHp@Z>}`a}l>mse_9|AJ7ڕJ"%Y?9k\y)DxeV/u_rY 7^n3o sD{Ʃ$S+:KB Fَntl.ÐP|6C(ڢ ڊ|ܹأINShi ,;ܐMb$h]O':hӘu(s:լq=@QTp\yUg 'hpRE#'WbI 6ӮI9Z3I?թh$.HWm굓OIl rn)\{ރB)*nF 7;Ps)k{.@xJ[uH)*Qu6\*9e72KSw+F4ːnh"0ԦWqn_.+G!n?1ci']ܝѦU/+4&*r]qE 7cysQaMD+΍#`"+SF4O%b'>̹ğ_MN|R35n^}{fV03CKJ0ږBm[ ~juDp0|9]dԧ&x~⪌GPoSr@Ro3kLjʋm`,pp1ukH1tY\;Zm5tP AL陆= J\ZBB߰Z_բ5s@0\tT<.QMnvaix ]/|a5hR(#=e[)J+i駋8vqڡb ` 827;$yBVx6FG\}ViXjdn3_dR!ӞjҊb-#pҟ zHza4|id* -^Zs5质)iIK/>6ڍ)ݹ-';rШ^ŵ!ћqÉ@~CU[~tW/+nHn`a.!2<ƾ ZIŮ!(Uhd?h/:T+Y-D-̵GͭUFa) qN9aܛ_ ϒ']=r[ܹϐޢ5D>sc+*)yL|Dje6ᾇmwAX(ܒmݻ2.ATO{ V-:iI4^^:Ae}*TTz|F^:[ t<1I 8)PR,eGH30|S;FH#VYk>8jyk&bEt*JEMí%H(]P!FUf ZNS&?>jgӦj>p +r&Sml&&ce"O: X RN3pmg_hP?srcV`,+>Rt&,f>}՚0C-#>"RBP@QnXaP5s\ A']Z\0:T9Z]!FCj4}ߴR[%mm($bmgWSM0erˢ{}9 e uIOa\CJry|lmd9m?5@ֿC|H*Lz[=Ϩf9WJx9/9E>7ÐK ܓl*!D.[R!"{M=O6Q<1?ku7$iRd;XViu#S"LSt [, [AI!{,i9խԇĈHE3n>[&#PN4KNj% DS`n,qH΢g+9{MGʹ}HlUå@dEuYsb8wq OăbTYP?F:SVK'iyEk`|1:=n]V[k/W} ʍz:FY%NC- cXXjHh5%g *^=#n\տP2=ONӦ=GpPXzĥ+qʎq-[tb@:lGy5go2JF,R-iufQ:J:㯵dܗnH0זhgQTsfuym X(\f¬Oq=j$& 1JF% =L'u2tmD/YP~5I)E%T Tjҗ46 &$r^Mvmqo~ Wua*O"TiJ͙z!*S05em %jm.$yPV*PX\^vxˠ=m-e6OmU+~-<)!QM;eJڞB H=«X?0UԝχGpnH5,86sXKA% 3g~EM/i>ʡRg@qM:vueVCqivP[om2R;j:#R2Vw g1,̷Yf1e[˓T( $wƃlYfkA;Rv9rdS^iiŢڌ6;.%q.JZㅨ)F Jy6VhH짱oQl$ϱTn膒QΣW*8T$K(ew$̀-p V&(62B˦T(8"݌ħDmAQ 8%j&( 톫ASw.%3wAimK1*~@e0rSO޲?h^mTV |@o.\e`agr0k%FML)I~Ea͇jRY~n,V㭨ޓ*{VϺ>G}Y|H"z:LREr&;nݖOueM93 Nք3`Ӭ*=XujVPT6R'v mUmoG9VͣLq.3F7EuR̭܀6IXZ횸6:V EZ +zU2&g4jj⮓UJ uo\ X$! ǁoU|}9Rkmnji?0^CI ֺ2|_f I% LwT&?vP}FϻSÄOzN'`ql凛_m6BKTR)n(ֵ3cq}V-w]P N5Kj֐iU'UՌÑ&uB>nA!#iE%[pmZ7VŵJNWG:wo:U6AӪem3NmKRA%+H4q[rpg^uuOZ[;h>Dᓧ5MLbe*mX% 4ψMvԾz6Gcw>]B  -~*}Q}T4v"VjojG47lH#fI?=Aഩt{[x ,<ǑXмD c2*(B ^`@ݏT,skI0RmBp܁?# .rbLPa"C3!44JGC&()7 m#ʁOGKoI=4:E]-Z1 |:^{T}Jy˕h.LdaR[7狑4ZB>J O.NzJ",'xx*3Z|z@Zܘtb:"ؙԒ,x&P0Ĭh<@62| 3/N :"ɲR } _ g8EkhaǓHl$Zﹳw)BIa~&ؘ=S{7%S*4yWGleB8CA많DIYW ~c 4G$A @CF% #h䃀H 71Af84‘,>J8Ii)XBnDn}C5o$cLDK\e_2CKvNg8~V{3cRL-ѩMbPWp4K w4bM?j/mJ`4B eZd?C } ’SJح{30ب%GdNhMژl+؁pqg+]P˿85IIƽF۾;Oz-Q)fJt0BQoHcAGl>ؕ th³$D=8YgQA 7<Nj EZd~e#GD!At~-{4 } Sn}[V ZxZCe6yX[ĩG~\tTZ!t?12 y+@ $y'˵:/jd|Pd)\}qqm`4si3_ċry8HOM+5Nak.e]*.Fp-?T51[n,sr!>Gɪny㏟£M )Ŷa Ti @b!> o:Wz-d^ZVМ*jfkXHzBlSɵ %o+1*r8=~/c>lu u'eM@e "t)oSJICi"l5*k^?M<7sI-Pdƾ"}K9i4gUa̩؆ 6[ oHJŹѧ?Rs}YMaߕLOyI7eGl(S ԾEI$)6AXs8gʑ\_FǑX4Ϣ" fñ|HM3qnFC-77 :]K\9FѪE0^\O^~jUA˝=d|LQZ*$̎/hqPm[KwO$1pQI*!MZq~*A3?Ԇ}D8eXb kiQ~n<8Hpa ZV'2:┥GRNCQ@Vɶ+>j)LjJsh2YG8BhaVՅ TX)> ԄYCRŒuFb2.TT8K4dI-&qckahv`'~KM3ݧTRv. ^ K<ˈ`/;cfePZv׏$Ϲ!C4O=ΥMzi+T15GnJ-Xġ<w /`q[Hs&V{unm#d':tȉ1UeWj<͐ih\mol@h 洀m ˳FTB\dĖ% )Kjp!X6vQ٤J/g'#e86@iJStG+PBS Uɷ<=dv$Yꛧt֗fF'sfGi(b@ qbJY`X8-ixK!Q*q>NBu[8Ӱ5̗l_1nrHQK~ 0,…du5eJC:#4+QrE0#ĩ ިmT(tp:Έ'碂J}t #uYitu3=msuKO\Uw! +uwIKIqįVsj"8tUhEt[-(玘r&Py’M Hdc! v甀 ` :}vZIst;3zr9-Krr$┢wY^o͎U`N?DNZyЦE NHC$Ir&"6-mD9$XbU'XSUtvos#U^z lϖ*=9ǜܭYi 6pJ::J3Rf ;iHT4`Ghͤȵԫ8.#p$\fi>J\sAMLe,ʅMuU4ǁX}վPZ]Cwmq|] :Ls2)Е]I7$ϾJv<|j3,L,v}AʔfU2F'P-;V$f5^2 c7@64B/Nie *PllJ=r?L6`RP(:!R S K idr8&Nȷ UvmGC5"eP֡!ɨK B#jkaɵlMJ٧T=m0d]Jsʕ]>(~1dA,PmgԴomy&_F`)kѼtJ{kk-HK8Ln }Ue%%BQ00rs~m%OԎvSސP3ڊV/kK-%X$ ' s?$ VDYB; o[!\~x` &LήF -] nVB/-iqJ;3\W%CN;JҎ8Ku[w2]V %RTHBHJBM-1`nq~*2vP45h'Q:36ÓUWoC3)//:7<(V˩k]3+I' +lxᶄJvO<zfZ:\ڶ4d8qjLIB)6קJ GQ }gT'r`{Ny/#niYGc&WkLuJ6rmiŅhI:U][cɧm&I&]3AƢ3Ķc<[Tu2ԕ- % ܷ 1JjORyp:*(wVZ8 ώOBK)9vTj`f)40MCbpqe#MTBY)-FPuKۆ76GTƝאt5~|7E(L`j@e*,!EV)Bf{eJr5+jUV) ХfV:9U5E+S8Q^76IWq5ų`9 GDO*oMP9XJ t&ZϞtS=T[b\ RR&db*FcYsOBjfԑ cIǂQ fG*vꁴe؈f6^ݩqJo^\ ¹jSqD>3::cO }eZ=:ӌTҙYneԪQ$<yENh\Co=)]zr.#>)_n(93Lj f)j$+$ؕ%qe ;'*hHZ>gDNĊdI g\ϞTLht\p\] P[CUk;;%z}stGA>^ս{LM;l_4J6 TH~;u ᝡxXcpʹK7b?2ߊ+}'0-ji-˓jUr!O RPN镟4H j K]t{j\SHohBRb BMZPӠ 3BE3& j[XW;:OҦTiru.#UUZk7"ȐP{)O`8'\Q3}Q M.$wz`۶6-P.q3̆ .W. 55|85 -QnJZCm%\URvZHL|hlwJ$ RI*Gt+LR vV+%*NXUx/{IUڲ1㯈:|7?<xQ4yZШ#C9茖 %`,@C|PV{z>q6ܓdBr&Pɵ/+aGm{9x8Bˉv6bp MC;=S>`9Zo-f/4dAD\z:Z$%"BJHQ'I|Y6TѾ \a>gb<mT;e<'.e]0zťIfFUcec˺lZ]yF cqVďTILViE 0GDζ>PKc…֡؊%jvSSZ{/.wst JuSQ1Y3jVBԠ`jͨ\ )JW6ݎ!scZ^ᴷW!kӼ;T57-RXY*ʋcu\eX[q+ͯU@he iWu|cSԾd7Țqi)S9 CUJA>"|0O*I RzJXyް?? TOs猲eF.U=ir=Ri[d-}$hi,h~j xa{zEռdcK3O-RZ VInO#U~Wɏ(OuGE^'  3RYaRܠ?hWq${[Gm6iO>ioC.>T^ TB)+sCHlTCEi'ng_t]\S :q̦ި>)䬤u[f\mT/&$r僢7RI}ݍ)HKյqHn= f]9'*QRs5T#nJnӅ[BI(X+ حh]'<[֨\ZZd(1PQ:֜՜s4=pk'/F)%,-HᠩGKX Y-A⦥nnIDfZdiN^AQuZ5wSATfƟeC3TKʗқlXlвTMJqxUzQ'O#ʩ^^)Ӥs t3:VIp4H1[ҟM4-! T+AQ+Syu8i;i;eR.܏btmdu\3:f)@t)qsTcBnFP:8\5\+"FZC]{6ev:+}4V|Br*$y@*}TRx'/qjC {>3h.9 >E^y];:sP2*#&% 6e \dK+YJV,{SaVaJM+\wH?5箠u&[ u0U=15RQ,"Ileԥ+뎨:VBy|OG^q;f2D)RZHF[YR^-Ƭxh'hrI |KKfe:mF\r4[zɐShk%SݥI Om}4!I$#q@l=Ւu$O WiT)4XȫP q)  WMߓպ‚$I=l>ewҺNiM.>zԗ.vxiRIEԎZOy Ժ4[әLZZ_.7NBTuw{Qnm$d]NZTL6 ʒVe<+ | fV< [ `H)Ojga.*Zyzct]:>ڷM!@{1\:OߺgEdG ȚmsTmz ّ'SJU-B[lc~E_~@ P9Ht8qùQy/BzG-Mz Z^UxjJ찐@1~˚^ Ď+ΰ.?G&VdS$-USS[~ĩ8G,088B>nCjMV⭚U @%7m۬sż3q놺CЪn{g"n!.`G<s첎>3Tm:=X=@ǯsV[Y~!;Q˹yn/۪G>]DOH-xWFd-5N֡jj5^6uљç:b]qOSml [K'JAx48EF<>$o':r#0T"9'GlBQ *)ڋ(t;Dbx8`ռƿ_IQܮONbeJ8#ҋ ېqJJ7AQ7!@+vFGe> rQy8-JUk%k#'KDwY_xC;{ h wj>_M ava&LV|fX?gf)ZǙn$x6wmz Ԑ;*R#JrnrW!NOڐba)!<8kj\V2ruŨB;RJ< 3WS?T]\@ڙMmQN{xg<)yli:hNJ/6f]o坆R~&ě~8gRuArW!~ НW3Ot ]vRbU!Em2%~!&  Ú38<>j 8qE̟QӜaˮkcbd u%Ȯ( $zLFT- myپ\HxF^bf! 40AqUɻk[Lﯢ뼇@>R} dd*Ñ.H ; Vlv@qauNF U[5Ak.4-RwJq e8>QQܠyMr$ό|e[zVv֩نh%:* (]Wrw {A=ĐDR ͟_u/gHuݔ,>ɞRKQu)_'2B [TlVc!Ġ- 6C!cVqq>Ѐ#>I܃>陲2TfIUۿ8ͨƃFֳ*ϽRjT|>TBX4hT_X،3^\'TGrdlOփk6:(22 i-, [m/؞|=G8hTZA4H<N{6V5nwκ .((1/7'pFsn*:]qUO+]/ZًK~U/;VK} TgePE!Op]*ؕ9d*iZC:-uXCA\Q,n*Jsp6\{` 'fkleTVtL-Y<ێ6x*9A7Êt.J OnH&xN) wbV )աBuJ94#=PZ;V)bӨB7>r(R KS*@.Se x7hUI6;IJ>`mA$2D9ԦdBMi.)A7#.qJhOʙN-uN[yCDŽkP< | taSM4p(;H DT*ږ'8KH&&3&ߞKz4QgNz7[TsTsO1c&P B´*ʇb{msrDz..kZ;~r1]|@fkܚ̊뒐^^ kHn:ڐ8r,{bSmV.R;pssN!؁堕w?0Ӫr]OEV̏t3'}*f|Ӭ5Elʣa)m+|M` Zn :sy@=|-*x{Jc1>eGrOc2h ؇ZU/IFO㣰fRje-3)?h:I׏f2N2*%o7kMTyw[IlostpWQ9_5eWSWPƧe2NѬ\8eT*n0f'b)d(tYMM'z(Bsj7VyF U,bJZY* $s|Wң#cƍ)wYſ(N9L:`o<@4r.JP RvV!jGY<'ԝћ4)f6<ʶ՟7R~VT.IA.ǧiY$f qJ?Bsؖ `/ks} e^([|`'蓮zNSi֚Q-v5V$,p^P%+R76u[O0'{rje_or·fJljEZ)tT3ddS6Zacp`AX|tRTcEB#˄ٕ>/T]/O>m-Зy۫lƆ{#mcSqk oZr74<35YQ;srhF*W|gP c}B#81Ne+pJ:nvS浶zfat QϤr@Gߺ"m@lj~[10ӌ9f>f:  RU*(Cw$vU+PP3)ۼINu.-ӽ_>L .3/6dUBNaSI7`!"$qWeM'[0|lP! >k!P#,ڌ)Hzq| Q]6(QFv H)V癔٘:YfLQס% L ) }cI Ye tmE̒zW.,O2)ϸ v)S2ݐS rno.@ u` 5ܫ6b=հ6QҲRx8ΫeQC`\46 t(vtb?3f2rKQZ CNmY^QM?p>-UdoIB^m]Bm'^ &^k.q;=CΟxw$Z3#ԼV`\Ӟip ڛO*!It([-KB8fn˿䠙/~KrBQJn,8̕%VH9oEkF' => 6ʓ5VgB?-u!U@&lLVITzC!_R| Bq!dz_:2]H h=ʸ:Zڇ9{[ҽZo$4)EZ{Z{X\WU&:Wԉ߯YYC+:^eiJ|eI~`OBM"G֭R5Qg}~4Xќ1 &ZѢVy!%,vw0nH )3׷靻\i1>>*nzy7"!0f AC[B')Xܓ|T7UZ-)hO)&|eR]5 :sTRMQ5'c- n HR>nb[wXA|P55S^32K&U&So1,TVvn*v~!yWYuzVz9w0Gn^_5ؔ[rRYn-|EI.V-·pH)<$ԮBY3;f:T=f=Bl|lyJlNuZk` SY1^#~GNVL|G$īz/G% ۄ2wCYGҭ?:R\*aƐӆ=J(654Ʉ@AVmY*$߃coXC'm Y՝yvܮ>*;ZNʧD(mL.8}M"z+Z@X>iHmqUs:ɵJdB I0f/+JҟJP_e]&5-/iGB /HhøoW,j,X9~EZ-EɆɸTPT`@ ͍e+j9y88H>m\VkAfRəáB]4B~zaUcK\RTr#jlZsl+<Ė0fNqxkm]+*$I'7k:c}U֘%G=u2@6 cjv[^yfjxS3`DBPڛv\ hSl;S.)n\>T6NTYeR#* < pQQwm'6>6WPrQڶEy*$bl-$Y*+Ik]Boh)iTxtjZrMrԼ4 !>#5)T$E=#6 <S2n˝rsΙڃZ,J[lASeV>T`J$mqUFjk`sʫGhGnaC19w(FWj^55ro$6,7**B@ R@8~^0h'O_d_y>)̥&-1eq ZKi7JJ>aN*^AYAg4!5qx ѼPW 2Z36WmvwVXQ dSSJ'=]Dvf-3 Rʱs]A~h7^oZY,Cu TH*rVԄgܥmnpMu:5Z*yjm-&Ϗ/-N&Cjq?I'h6y{*)k5bGÓ2fhpMKYv HW $[%ZIq㟔0{-?Ai^T5*Պ6 'k TXYf0X;q.਑޹XKZ7D evNV9&`fKi HJݦVVVZ O֡nR6@g/'Uԧ VFC%t!ZDɦ̭'i`@XxSM;$yɟ]ogDyº4U܏(z 6WTPsw) CK I@7V+PA$wdV!wWa(gJj(ϭ N:Ć4נ'r^`}JxGGRW)u<͡q>E/nܭkpkV}U7Tfrton뉣+Rd+f-v OEeo{ljHO</>w*u2C'Vҡ6D;\S)*'rO膝յ1OkNJ{Kh!SbQC J)+vCbG }+*k|@BIҲ^dugR2.1AuiAAĄۃT.{\4~/_~8ɽ7 19&%ջ_gEIb*i)%!Ĥ#eE&۶u@ʢ 3 r#H. >Ce#r +UJiyB:jM?-ȇunv%)eHZ]HhT{ZS^1E W.j:c/dq^ٿlŞSVU-w-҆<$~I}êS7tOCHqxyXY?` Ss JsyY^D\<&| ִi@@w S њk6Tg8mS()CDA))"\hwc*8wCf=6Ti3ToM=,g:Xul:DV5J_nZ"]|"pZnXz+)V' 32toȔ9Byfftiq⨑G *E/0+zRxM}tZ)vV宐f%S?;-ҰĴ7*Y D5X/jTB].g3n2Jj:W*Š)M6Z8A>&?U-)f>dhTmU"'/S ')$%KQ[i]q|J@Y}}+ c/Sܑ3q)YPŮ;5ÈMr3e> PWO3LWR6S OD*KVM.O|4Ơ@@e`^B'/nQt9NTҫYAqA*B,)F _ _}!Lmkj$U:z4 o3SoJ+Bj9Z[y@K{vb'a>iөQGԪgR3j"4wٔ)YQr~& [SLZy!VP6@iI8kA?ۆC Q3]-m)ڞtɺm2%ɱ%1! &_>'îb鮿jG:U*zd6P3 +Q|4M0\T֫GV\fGJr-}Zś&arVe)ABIJv3θ@6 {;UQp̹\zCz̠[mt,%#e6T $^zm_5Qœg}~μv)HTVc8ye^ JE!Gq=^2CvԨ-M˕| S/*\"қIe*n Van Ĭpa:| -js%M&$W1+*p)%JI17[ w*ҩyݧ*t$.OFNWLB )̋ v CdZ!NZ8˦溦rsgӭb#K=gZ٨ fUDҞ`xOZJļu|Zs8kc>NivhΊQ~4VafQdU&wRjUҀT~-Muw{% #aXXQLL ))i66'zs!9i JhJ;& D!BZ[+ &"$ϖj96œK͔yS$~MϾ`2=% @ڔ=t {,6/F]5o %umUu/1vTえ+A{^&p[f U،Zq, ky+_@"K%,"uEMY )hVw^i|<$]Lu7LT=?2UTz1!-i!o)&Tyvo?xb+uzugku(?>M3~r&ǣt"VQ̌Dn3~YIQvRYGRaXc> '\bvPTM`6;k Jn'.Qt)P=B^z:@$?)GfrKnqq g id{A cquiq<$ue>PUZ4Pwm%v6VݳGRD/? qC-7&=DIՈ3P>]*z&j]i40Cio(؂$$~0߸$#oAzKiKAOPc=4/բ6j1-z51_C@؄ZQ?CCU]֪Op%ij 1L`rWayILMoa*U.y|\㘹WNgy8jy3Dԥiw$ʐf0xB@$\cA}(OY|Vctn`4KZ0U:-`.MԘ5Zڣ<ʬT\ ir NzsTdSܲVmk i#HQ.Gh4"FM:}mT ݏOx[(JXy^#w qk۬eLx@|T9Gdzo'i bEfte-Sp6 Q8 w*b 4y=ЭVG4i.a {`lE_qm`cɟvZ߇$_]FC $[2%`*s}W85TW' KLzڲ Pq,p#дBuJ'+tzTDyC7SS}B߆ȭRq?qagƽ,{/5s6Ad^ǮmK6H+uVt&[ "t4>ۨU]jnv2f(f )En*6.PtڀsH3O6PgDb=TL:uiZ9c2hb*JAއRv@p֮;ow ƾ=*V ~r=.fݑ2=i??L)ME"_ERI* &M(W%}ϲFb!7| 0f-/ʙrtϹ}V4h,F۾-iIm`9&ƚo)A$:2Tt2J{!JٲNe2AR];l$6~&v+^%הRu'ն_2[[4bNhi9OCuR ZVBZp@oـ]ǏPe #UlF0^67R㰵YT+U:'PdssP3FvDIJ^>KfBf@RP>p;LԝD2#߾Pk=<Ef-aoK*>bt(3k>- 7%KZo6ܥX{bbR\颹L \|FW}/ &uj\[\?rKA ͮ:Wiӻy%Uιu _;Zob|,k]oV:0?4j˰RU2m!"JQAg?s7t4kp;SyII/wV2ՍMDY97UV KuLĹ3$4%e. {cxm {ϐ]u>L] Vrs>FjrZ~&Um*(sΧRP6U\6-2g7.RctQPԭB8rS3"W)_zCT0H[~C`(P ٌb.b<"JSj7!O-V(^NT~f#/Q#M!Ibڤ6*A;ocU[%ڸ5sI]n(X=>zY5?S_Ub~ˋsd+dxW7X$ QWKco(@_qeSzuN:TdB7EBJo2w EhʮQ5NzkUϧyKj#?.%?-JХ[Oʠ?]rNdOUVfm5E*2eADwJS d͒OPms|iɔ35:R+{Ct0k22J0[!N;\ MO}JS:kB{j`lI9T9SR&E IʒdT&5 tRomb1ahi\x|v+<040gȧyڔSfM[fe!~qhTב=f}ԹLg57ԅ^m7%ijZjGin(Cwq˓mܞoڊ%!ܠ/6$HQ|ֆG͕Z/g:7}n0PHS.)%A!lq,imntI"4㬫*L;/gLeDEd'1S($]aI; H6m(`v*g[>j/V 3.0f^5P~ J9 o'k"oBٮ mi %Y Noivjt4Pa-r'J'|Tx\Rlxګ-mly癇U:eczutJ'( Z֕/s[.1 >e&[\u %ZW~7#]t ]F0EҲ{0[X *&ݘ4Q3~% 8be#+AQ.VJdϙQn7X? i˵)5]RKIX>=_>#R>b%):Kc:ҕ)b7X%GbpT1Z? 6XdOAխvn|im>g-DY"ELlC2h Esvk bxÝ6T-gQ󘃯DsQev)>ȆRX** H(B@ģVշ.:[WJ|˗uF HGNy*UvMŞd{7ͪlysN *[mҢMm)J Zsh1{%AP<کz䮥EZT|ޚ:^JS a^ڂ1ٲ8w(QӨiɔxw{uH+Jr993K:i4L25!iw;b$8>:^cA~0>G:AV2NOG&#R⭯t!))q&-q~6`sNx}UĀd&,n}bGi-%2!HQJFĦ`jZi 3$ 2k{T˸s|6i=Ek5;E{-.0U&X`ld.ᤩ &ے5CYh 4Kc̐; =٩-FʔbƦ%l[spv:l-rjTvHG|,'Vp4X6;Pv+٣Jٛ'UTzsÏf׹N1Z,yFSip& D#u vTf]: K w,G8 4_i4Lo;Gv_MS^mʭerA?C* Lۜ4Ys]]-%Vu|0O D E>^fr;^ꂎ?oFWJ<#dU>Y%sIޮiN7PrY*<l*lZKvI:dsE7&{:xwAmZ=?s.IRLJa qC)H&`ë3}IO_UŴ8j)F dXF+XHaIMRIoٹVJb$cwЫ}[q;)w>QpNYϔ <9hN4)3/%RV 촂,sbNeSzީsdo 7SPf1@ѬX0k15*X}* dv$R-iRglVpؘ$Ȁ#I3*|ϒ$f$@R!(*0mܛ2YUאczipx`"53du5[>R|5K]$n;ki;QyՆ_MC =˗Iq+Z! T)6鶢2&<”zSK ԕ7o"[;6IH'EJmMxU>(kZdﲳSi[ų`LO%GmaItXX}Fj7=ՠȧT8p6pyZR:|ε/kfkJ̴j-wO)֕$6F[=ԅJn &#EsIp1-D!gJ+7fEgǭqiiIz8+6 d4@t3iʭT/U~-RRB 7 ,{N+tM^(mNTl>>O_/*,cĒeD H7k0mISd $spb( jn}R=J3;ܨS:p3{I R,/bZ4#G…hs<%(|CU1֙,@F@f^EG԰䆞&IK~,NglX{m ͜@ܒg5 ?\Ҙ5#WP)+h{7vR&bvm({tujtpoy9hV9!Yn5(jZ&Լ 7dJ5i{JoS1T;^;~JWc z3ƏI!')犮NҜ>_Zq?#su-{x *Po G8&yj4XRs3;8ty/g9V֐r[ZEtU {ZavZOV2m3^u%^Rm*[) H-&5!<ܑk- mY .oC(=*Ӫn^nzt2\P%>b+-hH>"ڔJThKI|j.r</Z>52V56iXr4xAP\Ob$8o #h! ^gp-wĈ" OQZWѽ>?}5:s.aʌAGPϕ(݈q $oSqK*.+sD_uMX w^ljk)3lRb䬧2osazt) e\K Q2^4Uiaq?WޘdSrt=kR^ &*TJ" [ >o-bEasVk]zɐXAK3JK?&cD2VCP:n@;\DRiܑ>@AVC'S]hf WMi2>ƚAǔ6Ĕ.⒫{U\XB`kߺ23(b-9Ro"BS}e$)E8;T&FD&櫝oՎcQiZe㍻Pc$']Eh؍7ce:dQQrSz=W!5Q>r,jlZYeJJnrsi59I;rt.LtŁ QLUd%0첐-TtQrD;Bi0}tV+Qj (nN`D J v?Q䖟9*q~[X $l | $uӛaI&nB%V{8o _"JH(I~}t Vj_b Dr:͕[Ɋ`Gp꫚mNjh>zI o^kٯ2̆j_IځqSj]XH7qt&I(bp1H>+9^iߍf& mEȐx *[-4l/cٝLj{*+J-knY]'c gd>BMYz+G[j4S]79s ^w갯j520&"O>P8EˡA-UcNbUgNʊRWrB;[q1K=g5^޵e1I U늏Tǥj6HiY)U8e%)Bvk)'yIRԢEpmm딟"u u{Cbu]`iR:)Sl\cY/G[O6mV[HJpI$*a^N@ŶVw#osQjYr^m^bKa)mS5dX"8RČQX@㡏]pQM6Kɔ:R3za >bkiai@YHUTd1~3> n BҦgvۈzjQVզ̙zw xaV/@}6ksc6[Ft⥪0jב> q@z,:c%RJ7{q:IOG2i ~S-2H]RҖ`\%FS߷U+p.'niq$e|^3in촛 ݽR\ҽ.~`e".PQ)BJSG<d\w%O}cjuPѹįmxzJ2k%5F]50p()jA㄁eYF1nNQL vg@>&\ճ;1]R%CԼ'<-m<=E̹r>pR3Sje>~NH Ia5Lg\P{T-kzb&X8ךG-@ӊc^juG|Ő+/9RpPSJlཏp~/&DIOۓ`( ɒf4ޔU3 4jrH 0Jrq+l\MC#mgܶl),X&;o v4{O*h0{8 * OLȓJ>fI$Rd%ht]E*N}|#NQ|j[k5q GH?R/DW/dNs+:DgM#.!Ũ%(jk&խL: ifju 74t?M5o1>ci\:,>w:py>V1)K p8 aj`9o)F\RrGBaKsN&3ԮSuZԝTv$62Y<;p+зE k5KTpJM$#D&ٝjc("ΨTZ't9|sZ hUh8, :$zƩ=%莔&ϟY+TFT`ÆSkSRrH&KM 9"cDp*!¦O_)Q3[G9U9m?2Q9aldI瑨,!xJ~)K,`$v+kCq;:S9Nj{bVbWnޗΕiZQ"3R^H;*t GVI|̤zUvXzhSP4Nuh`~.n}tu\4ka^fƐa1qәhhԞiIt4ܷe%HZs#C;,G;Dp 9ܚf|'.:jc6au,i@S1p.Hž*F piפ$" rf^Pus$LjqV88h'pOӳ\/dꑈP*RI*R<^M܎a!fV~U$xrLɮƋ(eqj(7Z6$$tnBڰ&_?n_OGzvsE2QJf\De2 eti,M W6NFY3_FA'Q[{K)u_4jNE9Ź$@BxT]Tmk0ki%F;R.P$ѥ{OԯtP=Yw/H r<%!lQ*d nO72=, &8oZwOe__t6ju Ԫ+-ҒJn` lF!M?ı$>^[GrHKV]"cJoح)w R6;{FQu͛H*a2&u!= uZu$EؠK{~D*aQLeո/mJ/j|~*ZNL<&u"V)CMٰBOs+kʹoVVHYWy[sTӡ[1iNA(\ y$ HÙmܲ}֍Ze)DŠB$)*= n<Di*-R%5:w4F|Yg@sfFuTNWRqکC2 JJ6ԏ*RnIVsak&t2ܤ0ǫ|騂oˏrnb Hsau ے9T\ܛ}ۯCN.c5Y {C&uS,jHA*u$dZ޲JM팻f׊US#=e^V0]'tD):QCR|܆ۗFwRa"^:q+I8ے@9o>:zII27xmj|6jcUr^kyn71 Ir"<|p*ကbt{:xRLHFAV믨74KUk`ʣ5O3D M)i.=.}gbٲ⫨{m 3C&7yA<__| BZVՊ].5_mn9K2BVo!]\cΓ }&h}BoMYQ!UdJ Rb)^ҶFc؁^p.{ #|Bkf 1'[:]ܷFVMu .Dhʻɜ"̸B9Wn(&x~Pu!lvB@)@' DZ#pMka6e*plOy0ơSz˒΁}В,Uca~ W Ҧ؈~I2Y!gt[F-EK$ҶBY}Zo=^湠5/A闧ܟ*SyWjTB"_ZA-QZJUk=cD*> gB1Κ5 e*<2J@q{{Di-#Ӑۯ.d\m uV JH< gX~^R 51ڿ]>?8NSaPW|lRƚNxv*L { x*_,{Kz_ӛxSd3irBż$)U_qYE kǬ|&6P-VUUH/}H8)޺T#$:)~h?D. m5~qq\:P)5QuK+t"Gqp7#Q fQuwK !mg@:g-_YugPs2L K-xɅd%7;dDaFǐ'URta1wiL'f2BQzwѝUPeʪg/¦Ȍ%2,ZWP8ťP:8 ;mޝ.z.55~,,LvBvbp Iv ̠B'櫙%UL9#K $`x5*Kj6@Yi* *< 8!y*7Q9}T覎NJ'PQiu"Pr)SdNm %icZ8=[kBޘ1ڴݫ@3ā:P/z|ͭyZZ!5jqĨ9ԸmkbKiZSøWu,ďiղ[Ax xr T>cE^<&ԤjD<ɭd%b#yKN \ڦQEISei VVlisV'_Ry;(UJCj@`|xyuB~%@r>O9_IvZYSĵ1yWu-mU@0o#%i~ 5o$ʑ[;9ƅ,SgSMXز΋ԒC_YF5cI5ݗTZsy-|ɏ\;*dAmBBJyR-8!ڐj\ +֛WBGy}QjJ۠6(uvNQқQaGyqb& 3*.NhI4 景fܓDUARju%ʏ[QXYJl|ة_Tig KUcMwp ޴2&Bu ޗq9q_TOa;Ve߀6Yj o=Xɭa>bJ4HSe:8Fxi:uzRm[1t.Lzl$$!)$M{;yƋ06FzrFĕI-P*@<rUz5XanD㤀>\X یJYJ!xfԫSDkԌ/6L R%(e4Y]8ŝnuVsxwY0*Q qU"|H1k۹H$\o~JƵm5 {GS6B"2DX E$li ]`);qcC(SUǙr⏯S%!UjM˹uzCס<аnB7õ,*%6Ot[\4Q4O˥I1։1J<0\.  =it ph#f!Y9#\ޣ2gS%*v{yT3.P ^oc\܎Ē#UuIoA_5!U&`Ͳ>Iyz4.S\ SX65Z U?#=Lɨ34R2%:oQ̄8+P 'ےEB֜<qq"3g药|N~.dFP[˭CsuʄrJ˺AQ- sTiMnk ]BD5 ̣QZ}]|4U²[0kr.| ȵúƐpp.D_ԮxOY.SNiӵ9AmGFrk's8xU˫Bٝ-:ɲ)y&Vrd!EK6f9 n:IH"γ1E'5?-%Զ'5i~֤S*Ng]~fBm((Z4{B@QLO[*tMjMGj>&dtwpP_@! 7 Dgw߂v:|yzs醑EUHd:*B0m&K|E/*e4˨N:7P'BڦtKuKF P@y=~3]kuZA5T[HT24IQ}h #m*nV/ҷe*fqDGު { -xg)inȹZ"]ӊ39iԨ2a)Б~NbLs%ƖTW]{뎹e~WejZķۨ hc>d! So5 {:z4yjQeMU(֤r`Fy\8  JTMBO*PVDzrC?cRO1Ͱ.%KJmqoԧNl͓.X`<7 U䴄 %i!'#huGeYeWCŠ\nl6 Х}JT F$vښYEG[]^DffUΚLG}5NJTP?hbR.AAcT#+I~#=Ee& F)qkJ1:Tv_`]%h*Mvh 'sX: '$C^̚&8La_R W!zX('YTՏD~bs~|j:2hV4~B޳p\KIӉJt-|B2#q6M[qe^en*r/˨uJ7 ^[F#Jz쳦ϗ˖Iv\(x] L;< T #v)bmEN vT8MCz=JĆ p4 "?"16֕vW/^櫞e\dVzrUq:+aoeP) y[ڂ։JMQ&dtKG؇-5 A(m~&*oqOSLg8Y&PrXQ>m*Z NJ9$N9WՋN ߩZI.%u=̈bɳ,: ͻ_+:0U;]6wVc.U㔴!iV:\^vad۾:[H)B96_T0Ȁ1mjWI*8#.]3#1Q#E)UKoIJJI'ku'anjA1줾ZQ5\9@>f%S]9c7QY ?TqYx6BNo0 #[첫AQS Y{]Q鶵 TKeAi Bt$(}8Ǻx,k@v!muV6\Ln.2ë Kqd:ebeĤ,_un#nvVSnr1LD2+5:=*3r4FbЕpJuSĴh5 t0\bi>=M>ʔT19G|>[*T''ojhi.O;+֩Ɯ~fzsiJ{  !lNĞ4+ZkPI&t1,kzsMTD֑fiُVsu2CM:ZRA {k <2f\#l>GNJ8([[<ê> O%3:H EMN%5VRљ>#>';Eb+٩>m-q?(NT54E&uV*c_-Hm(mK q;q6J5\X@tΏ-au(:1ΉnY˓"Nk5Wݦ'Dq  af2m חԶQ"nQٷܠ)jQ!e”Tnw,u'4v+XIU&r&reQTv)FSu%-%a{oϮ.UyV?鼬WU!U-heׂ`JSo{YFUZCUd,h8P!D[NA[7 qn(7H!&&ź :wmʙbʤ+wȐt$M6 pꍤHwC芓Z4jL㨙9gFL-ռ%*Sr(kp uH$6tcNhR kVG,ʒԷ~b8suNu]I ;Joն9tRTkjUY0kY"hf;,M4{JRyw<^Q8 t;#bStH;0D Z#an$)7Y 5)Ӧ>eZ^xU^ Y (x(NԛIW; TV0NM6"]hyVH}{V% RQ;W“k-=[ga[(xN3ZrL2Zy곭^x);r7ݶ8[.AJKS @M 3e=:]JBJm5*jRI<&سcV:*%zT V`wBkMъ+t-QnE2Ht6ʔ 7qJ$ uj {x4pƾ4Ū|UtT$J%9BrGvSvWoP1iOuyQԧ#M̑Vq\6IRR| v~)!Z*b6:@'cI)?'zS(ЬZHyNXr9JvuDثKvF^N1p={ F U:m{yڱ:^&ZdMKԦؔdn_q(rOض Ts]. #p4ƍ7_S)%jUFTTC .:n@XXzqwH鶺i2MG O4uncI:ݘRl"(n66#2$|֍0T "D6K]2苢Wh&a2SϦD\X+쟕tό^y =8 u_:JjP5u'Vͽ0 i3 ɚcONWz?sNG;C1Ȇۄ:Q>uAیUlZaOc4*̡z_^uQ3K)."дLm-j"U8CZ'|]v.-؝ϊΙ9kI52FEGM>.Smbؠ6OH.\`g.Kd[.ܠJ1Ky%P"QW6E߹'=VUK&n`:S%Jl) 7 H.26c w!Shq^"3Â[uƀRTB }S K*۬32xC='V6Ec>͡d_(v,!v4p-õL)U-%|orqIAHGTiV*.*MaJ$(AH+pmRkb6mWH3e~΢Q.MPiM 6BGݹ$ Z a9F2 DNsٿ/䌟JSȓ12e "ؒkWecH@tϛޯZ G>U^LL=^-> R垭6i ט3*d7Q( .Xsh[MTI:|l4f<꿨fuoU(Qz$mCqܓ O|-InuRaxVh܏KKʚU<Ɗ[/Vhv7ɷrO^مŭ;YActlǘ~5G5b!JRV "jP ~$܃):5\Z0afGgj]r+ Dimܓy=z ZثZޅ2ALj *9&3:G:OޠO:*-XX60)$ @?+` 5Rbv̽6PfI;s$C~^ҺPD]9~=9VmM%D{[ۆhm]zX#)MJ15Xu;6ȋZ"ƅc3Lb 8pxú:n5׀FHm5L"ϐ/!0ܮۉyTFɝoM1tD\:\CpT!@M8qYe?${VԙG3'c5aq2X˪!20[iRJZGAXJw\鵽c5'H?o~>:o6qOFev(o[aG%F4 I5ŕ>!:: _IP!ArjoT >[5,‚|5 q.s `ThYzh~ D=J.>y]RRH^9Xp8\)n k^>0L_ϝTD)?l6RRnݶTۻVO\kk|y{O3h^ EyĆ( ރrH=8jqaK{'=鎥S3j=YTy->'UW#oK?.ʃkUuG_Czu[ ۖ(k y-vYpğ4Y* %!RcHq*I7mVjq豄5Xj^sV4RbJ*@ZCkBBO( CYZnhP@Z;5 UT_/zN(d%$mZP6Kk=[+)1qTJ͔iͦ=r;l0BRQlm꽎!gܱaۗ+-Uj@gWyܓ ws`5& ϝu⣙KG9N1H$e(Jŋ[AV5[Q&aKh8ᓚjgAm!hm$,- Ϫ?\Fn_HhslʍIY>D2'ueN-&R,OtdMoiB$w\I^[2G0~<”w$ 9BmVe6Ѫ7`UUeODeĉ %j 7wI[LMD*e*Fj^]VfJql!{`)J+*#rttB+Tj>iHp[b-{bA&uYk*6Qs&rzD˩ǁt6|d ) [J$P^9,_FPK-.TRҝހ*øp-h)IQڗ2Nh0kh2W Ki-k IJG'O8wХP 0{OnTKq +ip%͠ yM;ph3$!{ʀTu0eZܝLsQu+Vmonjd:wNٵ^4J)j(pZT92Z?HbFq,̢mCMʶuZ)ƣ֋++OU9])Pꏅ)Ku)J Jsql/k].vE En)qstwJɹj6JMԔ%$l/q(S19CU/NG&gYK@h\4>}fI_=Al,T$Bu }@E+䒢>%-kcD EZ߽T# 9h<~`$6D!LԑT8(,%ynn璠\0z,ZX6O3QHk.:U*bNH$b >$[یlgeJIO PT$\޽'dHPF^0b@=r4F5%}3)UfV[ZĢA&MsqZy殘0؄Xk%0-zyktTRb-0`:̻)o&s2Rӥ'Jh`v8*nno4`h U\Ufj߬ŋۇs~2J^;OU5KA 7`pm@‰btQd!dpHaq~G6 g.\JiX0qu M.zT M;f-tp:[]rfrT, F>#0 ?|4jM%DKm$L=Hܭ%:Bps RXHje7~Gx`ʭP &A@.[tdsXSI9P!A܃ǽÃ:%) R dVn,[a ZX)h^jO $/l&T*-G^HQQ /r#&PsKO,UV KǹA~.G ~E.1I(9Cbynә*i5&͉d`B-۹>bNc(F!id(=6$yʟTn‚EӴu,ƺ:i^VWPHX sk}hɝr4!WiPwsKAtDv(0#=[ ǑǨ~9cottNj$p1R%]hRǵ@ S6,QL2)V!SOƲDm"kplm=D8j sR=X c2A۹ K,H:"V垙!3$6U=ǁ!H+ٍnm9k%bYsA>UT{18nĝTEMFduP7 #~2DI 奚~@Lҽ8=2YC.<ރu0$8ku =U"+a7FSQm`M e!iI6Íڕ::aT49WU_/+Z,Ɗ| ̢*}u$#Xً[b)̬TopF|tko6ʧH0 !AQVEQ=M\8iffvm,I+`9 a6HղZqާ6M< ##[-Ф`FZ%\n}m?' 4LBpж78eM[XK2+qG^cfBMk)d(ʉ xao7Z9/DIdyypJب qb/qp$QvBf= Ĉ-.{,"a \ F˷8ߛc߸M+ޥDʇp.xƀ"ǰl)Ezm.=ѻ#X)>qo\@A6QJt5 uKlY!b$J0=Y6 }*A{ >un) bY6c۽ٔ2\ʥ9ع ‹vU ^M ZI!`o[7o L=-:V*<՚v2\TCgR01X>ޡy+`}ove(2>b܌,uXRPBi>z`'ECwzhu ˡt|%o c=l9Q;1e]-ڇEϏTgu8Zd` HJ6xM"'i3zO23$,r? D,R22lp~'"`uz&,¹(-0Ue^l۸9i 7k_UOG@ax̌!Fk$m.M‘ޜF^"UrŜ؂-mu%aƀ)7pMe)dzwX$n6kM^}reī:HeFTimlA Xᅄ'/:J窢1Z=;`Rd,MH];L4RyT,G#=G#-GT d"Qsj3XR5ڢ&1?x UIxVuE!(r6knH_d?{X  BZF#c6QJISyL]B<%if& N u6ķsr=D%p>]M 5"ɽ~78w!(-2[s)'TJ hJ$Dk;6ДNJ*K1ok6eJďrFHV5 WNcJJmsnO{q2%Z̢di nnϸon0H$TK3,j\4YbŔ뚌TÈM=pSb\)* &#Zu-me{z~qT#YF U/ _׶lrʵ2fy}„\#nhCCʱ^N2R@gG:jmS֖efE""7{~C`iDI`öb=c NZՐb n1+*;o< )HF&q q4^蘅(&HgY  ]U[#Hld%8& fJ(H2\{:_{`:p)ӷ1){'TZ8vv@y֓%!s3ZD6<vŧlѪ4&YH QG PALH1竦1"32"l1)CW$U,rFF-o~w'4n*0ȍbm,C_"RಐlC[F}'zZ%zK${K <oµn̥*mK-hi$+"8بw*KEkLqU),nQ',YC3C:; ]#[;0E#!MߜRDtD"Ә",] G)n7KjrB?~0ĂV&Vud> 1WGBŘj` WGUڨ!0Fi^*UnT2+ o`@07ي0hT9 3ZraÅ{Gy1lLŕũ=yVVR@LOMq;7# [[1ʹ.~ z+'7Ih?X?'"潿i?3]Y&Eh\KWMIPh@@9Ak zAbtqziQxZ$M+va44Nͽs,no~XϮ'@BjƉ P$1Rʠ}]ݛ$5ʳHpCTgdVEܬU A$qTһQSOERMkBE G>a.\5ɔ,MT匴c:^7nU 4;ڦ1vSa b,ߌ%s(ʅBorI_"mlҧd4I=DlM1D$^& T#T89CpbH۞N`SUvv_\mꗖ``C[n-~B퓰TG]B,e 63sD"5S{1Rʤ \pIbv\ebZtTp2)EĄ{.fIsHkwpAƀV)INsR)< "VLBoAlNG! IjĐĆ,1% !$`}KQ=$<Ye,v7L ZD6 @߷ rkxT9l0hPF*2$-r;c>odFx%4Yx0<.;ce! T1Xw.A Xw/@%9"==Ll-6B ht뵮86$j+X)Y;ه{nȉdR71;=`d@eSZ|ha?b69L #S!y SgQmYcñ#n5@0+ht`GئnnHnM6l@XIYe.WBJm# ==p/*H ps_`7K#4'jkeqK%qO4ml ܥ`l$[8t4Մdb,{0sbSF3MT `Moߞ>GK)f3A(i))%7IyLrPB=Ryw/6"^]Ka8ɳ(Ϙ˖-wf`UԋD^0Q#)EzsPU #uOfNᙋ+GIe-G:&x^'2o^W'ֵo&ZuVGWj/ZJ UtBy)"D4-)nWrJ 6iti#j27K%^[~ m5zRf"ftyP7 p%Ib0 >i6B饭eL,E6Tn$Xv !VZIdfK q LIU923Xrj`:%"ՑSͻoLXgk,NeO's#D(KXn;ۿrFОlƞ| ([VK40Z5T`n6 -sw:n I)HeB`Ny}&=2낡MαK8Y#!` i A+ KO%#k#GVvV ة7?O~ 3+fV#aXҚ REV*YJ-`;pq~T)ZGG,|rI',j2 ̵`Svr-qbl8?==Э47~'?Su};Dՙu[A=!ߛ^Tv[)+dpTB6$I&$Yi& PN$7.؅v l3~PD c Qw`_wº lZBU.ͮGsk\"B:tȅ#fܨ$yX\.M[p&D9/),йp?8RN0dhoI#ջd"Sw}W7U{DRpeѸkΠ*3yro *;(IUp{DY *G/'{}-Q.EO=k۩H^=ۗKr=Ϲ#*h!F'`)uo{j!X9-v k)U5M_U>`}d(oޚy$>ǹw%8Zxd$OVю"2ۚUsb0  ~қk,դFzJ8srG`IT^s,aUc^,YSB^@`vi{;a`&*#*tSbcd$cynUn )y r̦ tT@he69?Uv>!aeh>VA,lHK0?{^}X ^\&G9|ʼn$p݇R{fAwH)2 h@qu ?< F˖XR@8c Cn]ۻ?v<e%2L**޷H@"62ݺ@lnI #NވHQ%I}*',8r?F g9Χ>+L/Pk_KQU5sU)h Q.ȁdG]"16p{nNvGMOXadQWRO]GL3Ƴ,bMϸ(T$;+"΂  tt1 b}EbLBNP Z(KvNە>ݰ4CU`wѫȺ]E;#r p|֒SA `F\(%X\MTE>k.^$Rh秧T+$SčU;\+~S汱NHC(ڋp "} ^YfT]ۓe_Hv a_0'Lſw>@x,!2RŊð?-j(! ;H%.$@R$(ò ")p\ҩwb$߿n^0@$YErO|Ti*1YSUyU% -;,M')+ፆ~`;2}rOIK/LH"ͬ,}mF$:R9/5~c/N-<*aD5bNs0[%(=STHLU=fV .,9$\_튱eP]6D$ܟ_ltD11G=4I-$S#E":)(B T `(b s[ %M";,/s}sky\H3 RJC’-{^sc90+PIHU'o( 9{ Sa^H ՙh-I{wsp;04MK51SU3CLsJ+J8 L QO$'lܛ ǧ~lx0a+F om~ʭ8#t]b1 4"w p9LrUZXCߛ}8S9,T)jaF)$%QX)!ם |V[S 2Ł}=+53G\=dY[Iق%u2M12oJOpm0.OOfOJ(#&\Ƒ`ɱYZM[p.$-itB{BNwZ=dQim{@7"ݸ&BVbtG}jn{MM؛9)hAC -Jp+;a5OOV 3O^fIp?"α,C12fkMxzsLPMSimEdK̰=nq:P,fi1#X7aq e9%rG;:y`;i+F\ylS30;jH濯qx"* TOS4;z*y7nkQ lh+H*u#Pێq a0Z'Uuɺ"QNM؟K+A@`l.u"z)Q梐 +6̼ ߱JZF%ocEsU4MK /5\V%o&Zz#г!hYhWPJXޝj 5ͅ./`#);Fi>-ABnxтF"ʻ<2*M[:5kx+,IH'ӒfmG㷄%FVu5WPc,IUY̵tHIX\x*a\.BK+*zxnB9AV hGm #Q 6pE5J\eԢcrO4:IEcU(o0rM{sa`,S[oL(%5HݩO;_iS_D$,^)zrrLW+~[q!1$fH;caNjel5EIIJ{r/ů lPIY EU[?\ n MqcQybk65/U.AY(ÐљF1]t$pϰ0Y.`TS<7-f2yBa'B0%)) lBSkUNe6 /co~p.$&b*҂z{ uO5aSg]F $=y7$+alVxuX(@e09yZyd3,13} *1JBf17S慫'>kF&uT+ʙ*y Y p-:jSBPAQpY)lTj[mw~rObjڨx [D$ w7bU+2-j-KP>+;.fYUZXr?,ܮjh]]E( ݗv=<_ QB4RT#Gp=Jx5Nʔ ,I*,ѕ,.#}pY)HZFM\aKB5!gpŹ?lWj9!G[uۿY@V!ZVqpspoS36fE'ari213h{#YI%qLh8LaQHY$maAHX2_QY_Ps4#l?z[@C^PBE; "8i|Jo{lM̄&MОܛߑ-abbđa\( Ӹ@MIͧ?.љ*;k1k[[ @!&P6UF@K;,L0@L`'{o$5*LDrlpvȵz-:̕ dk>kB,ML\D!DYAnOqoǷ8B!@5D'rwW ==zeAQY/ bbNG)řřk7  ‡ P4NC9ݿ'갨j0] &D`_>Òm>G;1JI%7@i|6.nM>\Ţ IWGbB"N6{q|$]0ph + [ޖ "ǢSy `b_B@2%zYQ$ vBBrxhJ#ZvJ9m_}y{ɵVZMWhh|i0G-6c5 |%XYJ9)bB,д*ZUSE!I^Ze14n"Ȭ 췹vP!&#PJq–ȕhPY6lͶBTeRN! ׵)Tm'|M0Q .zZx괊% mq0D )#"7\L*l; _pnA{Ҫ 9ȑXߟ5KkX7"B`X+enokArj$䟷'.Vuz̩L#8!h;d,|J>RI_l}`DGm04R Mc JṮ-)$l KRf;BoL9D% (EՁ?_lth%#[4S2IԲيr,{G8 ξGj!wTKB6b5kiNS?LKe%n鉚; YX.*nx$aQL/*=TMD[*Xr:>`VINYtH@"\:s\sF˲Yd,Ȋ~9}َy6Cirzm;++r j̑ \QSk-@د!W|M+Q-¦"jx܆&v`v\Sh b&)-sLٷηQf.X/r{g6|$BuQ"Ep-۾5abj%a48탟58D9Q12* IvƺH露cH&*6 L^Wn,7 KX^}P]=I|Xvo  H{؛1 uW9,!` mkYk%ğ~78h!K n7-:)2>OYOS%HE3gQ ` v8 Y9L˗S%l44ӂ9#uyq}Ԇ ${ H-|fey`/ !HX1uDIWkM~}BW+(IvEIz612(dG T(D;Ǹ&־,,=p@DA!$ _ hʳl&)ਣpԳc"plKpA1G5_G4ԕ%)bKvT*,''܋5Z:EaM7sƈD?y55 -F_Bb#CX {5ŭ{wƇΊnqXK=9Jz I寊6CYE?~9rK+:ʬ.|܏,! ,)~{aLVOE 2U>CpHD*i7)1qsO._$<7)H\e=9+o.b Xqg neG?'ƽ#?ArIE_$}E@*JO")|/" ~9Nȕv h 3'ª_fy[W9WDG GP 0>8]Tu]-1; ? ?PxsfQiKD CĴґkHq탇ij%An5|#;3usYz*5arKIۜz, R3:j 3&bل P~{ߋb+ѯVQDdrVrL~{Ϧ-AXfeF3 &b!ie`} `8"n#5Pж_Q+L#1+h# H :kӸSs~O=0 H uc>ߦcpYrzVe1-QAߗ=ı!3%f(-$lT[؂-}yJP_zj LFe唋\n߶0i赥~%c,CU `ZלX9fXd#5/m;s-2XDIrT‘aVB% &2ޣoLr9HE3>6qM>_3jT0X8GKrG04$'4L T4je <Fc7+44J B O-I ̊ҵ:4PtU*?ϰ}Dsw; @AiHB+ Tb@1`p 0TS!2 bA=}/z[8bAPi3tŻ_ B,80tԨ`۸I㿨v'dKH7I[C\/ Ybb #bAKxR9v `Q$P 7+k (UAA'FYGp0Ћ8XJ~ރ0&ܩ1<ԑ}&*I!ŏqn8uιSezJ׷pl*@V~L,!P]nom;-11ؾu`-{z۷|P$R@$0jǯ" UVdB 8$dͪCe[L,IY8BLAT\^ۛ[&SI幙ɦS.G2F6qJ` O&HX:L\ ,d )yE8 n$IH@mArK),sfh4g!r٣ $RJeKSjefoP[I6@8rdTy實jVXI谙Zpr0\u9lrHF68 +Ժ }=Q[QKlXE8ߦ̡Q.Avc`5UṞ<ճȩm<Ự67\A -FnU{?\%jiI T_'&ic,Hz [Þ0 .% dmNH$G$b,=eU,AkZzh#/$U=Ѫ0#%ʛ-}B9͵t1fITZ9ufg y؅>o[-ϒɅt]VI3EK)C.Τ,rӖI#DwuUg̹Fi5M2٩ޗyX^o篿D;nctɴ#Z;}.H+2o<@t*w4k*S4r0b x bqL{(t U;l_(~|.FakX A {dJ٩jfiM~-[cbɳB!]=VZ|<(T52C(]]EX[0\S.Z:cs?^?%l,|6*v42J4ԐE(K.r9Ӟ/lJ_{"SN:F-m JoKȐQU/N˱.8gDfE2Ow rXO{ېTScm4+?(X)zgFIۀOƀ |QoM,Xb ӿ?h!eݾ(|^fϚMd۟i\d&f[Eyꢠ E+Q{ny2vY&:)R9T7`{E $JɧfvCcݣHyw?p \!XXU PĒ,zS$Y[7SԀlbPBy Ϊ 1A$/oD *HDLm6=8.k~JV%K_jsCeCvRVma`oA\V\u5`tYz%4 Tr;~mc}`"j2j%DK0NוR}vܛ ]EVDf hkۿnma4ꐼ$ "1X݂o^m(diMRTRU+$lGX0k{oRASݧy٧iܻq?( /qF:ؠѝ,k[ip]4Y=*cZw!vv*Jpzی2rף-K/c/LJq'=:-a@eYܮGn ؟r='F<^˰X3-6M8^)8$2ǸCIUc@RwZ] Ѣ":{1$qMk aK(3c"˖S;H?7M $IJǗSf~]iJQM鹝y#uR&\֗',ʵw팹ewoIq*͂(5 S 3qsރ™" rֹ-,A2%l_DaUZ985wg Gp9aIvJSHiDJYC'M6m|;@RqYXfTϔ--$Vs'-:FSU`wn V j\FY:{ [zo^,XRji 1/Nuan[n-Qi}uA mV^A\ihl! ܍ Jb HXjyQfaG ܏_)gVPwGT*_גp4 k fY& `M"fYae3bD>(ےQu&17-1=&Y%K%16#õبr). ;Hҗm<QAp %Gl3l`j8b]CI25{SrA WH:!Ȏx*x="sSdK Ӭ&~ 0yMW]d2 #o0R,G=88tXD(2GN8">=@3Zޛ/@%2JZ*δBZ^^Zk`~0uLVdԔngXdm Z(#w0o %L;^I3%!SM 8+b| 2oxpe#]y'@+$3l+IeWC5>Y ;_UDEW,I\3:"*#aPv$pt,)ܖd ~~|S:œD kፂ3h^IeYZ26)9{_o [IQI_-$!YdI /NGLu  r>g<0;u ;@Q(m~nޛ,5(fC>P߷(tVKQCUP"b=^1sItR _2E,`\݁nH#[ΩdP']me}EA(7S8eJHܤ~A5B١FꨑVv6`KDثL%,{䋧 % wFKą kDElJuT`SԖz>a+XisJ=9IG[ЎZUZxbvfYE2[=l)40UOېzqͰHq%H3EJ1J6n(o_uۼő$&|1b.8 rjZb#$X]Qz,LT5 Y*jxwTe+i /UBe@6Pñ"~R+ ,Vؔ2-)AEa)zN܋+Z^UdUZh2\bn,`uN\F-`L|5BW1>*Z]iʵK= oFm\7I spx$3Hs`L YS΃2F,Z8z _o1t7V]Cl{+VcL3TĢ"_`bv޼0R5'd 8 BuHI Nh?~П5d-}{`d"TR0uڷXH5}>HS{5̕S\$]d;-ٽ,/MZQV9ZFnI%Tk[urG Zڃ<%-D# Ob>p}1uRFˤi8#MMwsb ǝ[ʮ4/J9JZ*kAi>a>{0M ( xKW<]*PX.O'`HMLUo-,T5 4&3{r5Ne&Ja_`r -{b v8!>Tc}[9PsC(} s_zQH`-ȵ\ $e(hP#PC>Onăǧk|.W"HYY*tE?Xr`R,t(B ֳXۋsB]] '#f8s3_!N oߛ{-tCeU S#o#зV,JO(&L˗K'S5S:H 76FlM#DƩF>X^J5m㏽`d1t&@w)7abeCJu c{a۷tZi5ymx\X=oLbJ`g oYP|˸O .`$5pBNeEi/(vŽ<cA0Ќ'b̝w=`dv倡+mPK{\Oƀ%Q3l*4mʄ{z%hwcK5l0-,dr+2zyejf}S,d{{<%)Ƥ?liF%w</e3j)n6ǸĜ*/ dyot \^ݰ8$I~Qk ʉ;_lmV (0P= r2nڊ]ۅqBL\)רc8l›"w u@Zg<w;@Jʶnwj@.lӶ9d\J PZv⑝,܏|Xlpu敳JjgHT"yW27^B@H .X*%bM9M-NjgT<F#ih3p-q,Xtd|WyRx54žu1[}\RfT~,1@.$n9pZv|AIAʣTBڤkzuJI"R]:g2H 'M`bMCvS7&d t'fE5y;8H>iVE%M*c_+gocT4BE(%D򨌃mo5ŭq]JTHGg>lAAyhP'qp ]w2itMToEv,n#noa 7\ꀅjh)ZH"alW..Ā ͍k7/azse^v,%ɵX`(a Q18n&SH4dden68  %;CYSE <8Zi#-q`&dfy~kT(宧Z!1tޮC #s\uhBBt`T۷nuk |B9sVJ}suwXTBT20,ܢf͎~]h3oslFfY\ X-UUQTrATkI:OxA>x_T-`)sCT,T˺S0%UG@lT˩%@)=NEKAR-B EXvz/mm܃~,q7\n  険RG.,# "*G+f*.-q"Em:,;XFĪP[>×])MZfYWG4m4tKxTr(Pm ً7#h8f!1=(/jRN7 OUB#;-`~ި%XSꙨMfԔ f BI] =G.7@9siA<;Ա[%ۥ5I?bD5Q^aP-T9Ҫ˳M!>Y4DsFy=s4ʤ.,0`ݏ__%9-7ygA|TtB)ƈ81E$ 4t 36T)2q]ZSuK"mۑW@倸i&ĤGuL=5i]ކ$Nq |0z7`:Ԃyj @cs/6$s_|纞YYFA)wfWd34kOtfPC!S{Pp}7zB i|(!HQPqԧFIocݱZe?iA"U5fVJ:MYRybڒ>ۄ s*'dZ߿d%S!H,g-{g dRQB,P H_K'e!G".͸k]{{LL"j4NT-D TĆC( Rrl8>ֱ'>QB@VZMCeŨhd] )`\ !0nV&ﳶ0P >c0#my%  G22no/5x]VC24i?F9#r C ܎H7 b8\] mlb4X'fXnـqJGo8nTF,l` f!cd9 n{~H>eBH( ܪ[ /nh`jiA;kBH*Gr ;{tDKjpp '=?npI0LE3JRH 7q.siDhd1 @Py/ߏ_\To0যkn0kf$n /95ŗ)&9iwJwh-ywh!t7( VbK|ǞI~qaLD.r+T<9g5 \݇S`|ͪB*JKNҬC=--tIM7x$qTS쑖e9Yu{) {ۀy,ߋp Lɼ h#̤~1'5E0Q婤nIJQ&ƨmJ-g5$yTK`i6N4;xuf;!e}rFM6>`vd{KFbI d2`m ;V90cc4,ڀ:Ug&ә i9u@4OAEP33LS;/ Im). r0}3KϐyY󬂇8` ",@2E *zͭ4Z3RjjjŚj"Rē,o}科ו3 gyg3ڭM䩫̫$j+$bx;aM R_'ߏitD-k4 Iż HzlaTpp|k܁~&ZUX(fOg4/ y-24A,mPL]V~sŭk6Je^ 2}pr(E " =$?<ݏp8䃢4\\vô@~Ge$D[Kѭ!Ai^ u%ycA(bc>^sc, J/w^;vŃd,j9'FG&10D jA5y gc&Ȃ p@>Ͼ Ԭ- p eBcA!>~&e3H%\8š$9PTuA.B8zitCq6Fȴ{3|jڞ28Ѥ YUY4TT<1c wq `]謱6* \ =!I!m~y~{ohYSBc͘z̀)yi#ePT386$lrV`i]4ܪ"{7nF=j[yXp3慣C ͪwSDޙJ|O {[K{\lP%bRzOqin"m>S_.I@.*t6k]M-4Nȱ& #<̀'}O4"WS+2܅>p}T.L5A8ܷ؋?^E+|)seʡy*7NLE4E$8zܗA ]sju^5yMsUsg,7ȶrw\P;v-l٥u/ ^Ma]ʹL}Ml9jʫxKG!c{0`C"ŋC}GQWq+<-ý3OI&Rj2=C5MLVt,TsƲK*,} &Tq5bGSmIzLe_>"j=k`yƜ*m?*WnGBpERǸXy%iǹ`O%$zz0˳l328ZJl iPdܜup%jsIYbyZi$7R,lI,O5@leSVW,HRTI*V =x=Loo Xmp(1T˩樄Q׍y]@ 8們 ;AUҳ0ͤs!MPe݋{&I8q.~)L.GT.-{=< _1"Sδq(fV lOvӹ>Y05B]@Wb2o4]Dz+{ZZjbG>F)LpOTy ''䶿 ܛ&_ &'>J jf?W4#y6#uiOroor*FNJT)uul=%ҏAf5f[HTԥ=4)H\I r@.&Sja90f\k%u<1KRQbZ~xÀo.bL޻s[L(Xy6xm 'ڹ ˕>bcJC`v\R6j WE!y|e|Ek56|S5Y;S07[$]ena>:|msRECK.5WVeOIP̲ *J\\_plAcDSW #.*[SSSEJbzYfJ31dQBL@m 5:tËB/ h sas@;(܍]a1/Q*"1TI'{n{`KJU I&_*3¬-~8 a$.4N|>Δd2Ԩ5Rd ့¾k0+|oݳ+;ΝR9sjST*X7`yߋp0) b_Y++L%n{nO;aK 0)`pw8-ꃈqQn=Oa# mT&RaGlQy(SGTc),Gs/!^HBb\=یs o!#zyKq›\l%sY;Rf94OxBCNw6vnHTmm~={HZ2I)iT0{zy6\Ե+GRu⢎wd '7'Ļ75oUGTZ8娨H Ƃ$R,SLvyEc*bl΋R.GMne?A H dؕK[| K&VDa$^h.mO1 juO f9 :fu1?e4X"2pTIWkᥤH!WEL^F#Pmas ̩hRzV0̻O -{qsZMG[dOH<[Ab?kLd*3*Z@Z4,r,G\)0#߿y"0uY<6ߵy+f%;3̏J<ShLT9LSU7 @Z0 #Mǿ1+ MBHR-V@_uO&HJm2$AG]İr@rFCTWCJdv*6XsM= Qmdo?u=nxSh1kÕ)(cF]c]#nt5,bn,h*Dž-G&hBP̒v ;9P `,Gcqxhnsc0apEcUsieWUV@IAb? uTPFO}.,r:"fܨQ!aR7k;K`uA(MMLgڕ QPA{^mmf)8~U[wZLdj_}8TXW͸8RB`ry= HZF`)%˳)e RTP-o*w MXaNVX 0$n z=κSŒVxQԯc~H 70fyV+`Gr w`Lk'{;Hi_~:S9CTv*(յtI D6民:V=~fsIj,59gCU#,/ UQ )48R[` N;7N}4JD{5WOWYC,MPd,cpi Zdz(phVA6obΥ^:Vq0CaLaz=(mgI~ɃOIeYfosJl&s*bJ*Wj8rO@$ ue.BwQ~V-\‹82TB*JlP] l>k2I7؆`XLخE}&U[+],&w"h'/B B$W ج<Πc߻.{Q_ləQG u4H:!n﵍'p4s'U `u#y -ՎV[v] [-=`LJa};zI!购-4u!MOYWem [,ْEQ<4gf+ٶ9iɬUS"(ocoOLIc"4ADrջvQfOO4(!U"KU䁸 8hnp΃r2<>Ik.ȤO i-fVV^N `ʖVq` A~|vg/!X)A7C~\5ɬ 5RGBr "}JI@>^#oA)\W f"4҈egfmWX$[߿M.Ո]=:-E5|X+骤_jtb A:{?o}:j.Ʀ2ՔU1xiOQf) xf i6?8y/ e, Oy*P2Ros{jXw+'*kgG- X~r}06zBZE#k8;K~߷8`Й1tNWMOGMWOS H!f2Sl@EA 3 ]REG($@, >`R{f\nLI׉ٶVkqKsG*k JbF܃-)f5XL'݅a2B"S-d*HH =׸_ .b]D7ҝo郗J5GWO>ˠe,MoYB¡n&Xl;K;3G-@ JčHadžDhmJEplX ޖJu,k t3|vAG!EXvGUN٥IfԹI(j](^m77IlYLQ_2 tiBG6XQo7`n !`r=&y2˘GUU⧬u!X-JbbH6;Bxp\6xži*YZh(nIlI*6St # *fEX#ݳcؐ ❓3T$W:I(#}7߁u#~ nn;Y%#_D"[n"(D{(4MJ8b=0 7 * AHy(o-k!L+FhTh@-ݗlxqJlj1 qr;_a)vbٕNLn@bǶ K >^̖a}>ꘂ?B]ICLhJq]9&nͽ8 ijhብXI& -ÛL+ٲ2%Nj bT/V!F2B `ho6q :!FJ *`};_C7r4P1#(wYMw>lsi#@@HUb-%ˠ(ᮅ{qG7duRa.$!qmfM67=hȣIK2Ƥ*~&LljIey&T y[*cH(LUpf Τq9,A$Ơuxt<\֢idZxTPH?qsnvSDՆˬ=9DՔ$ܣ!V@E#´53/乄6#ޛ@H=4 ;n0˺w b'` ߋO_*)%: BLj \܁J#4/mȇ'{vN$ Yd}I@UZ> %-CF׆RnF x+ۃԁ O3|Fpzq<k0 kBA{ު?e 9OٶaFk:s\(Ht'P @?+.:|5 x| ;2I_Txt,2͹Q‘qI \%PjEiТ$̛GT/T2؛r@ǟUu5zU(]McbGt H0J8X ^,aV:s$ʗ)ua(:LB!uiEc;m>K"/WU6l>aKWRŕhjVZᩢ4Tk $vE6Oz+5ihEG4%$Y ߑXo`A+#ZA,d Uy9c?7UɑS]Lu&TJxWG!nـkm,lTj"H)dvI`Dl q CkJk䣖PT<R z46%}ij5&MV+-,kKO Tnb 5;{*9P34vcXXܒ{qԦrꢞ!M,nd]i^`ͬ+k^%Y4ټ#-laF:s$*ЄROH]믌uPI[oIIEGQjB F$8` rPln>@7BUUP "zHMJQW/&fK톂BI~^Un/o Cs(ԵrzE)2̲,e*C-5'׌<9Wyfzd/$ZWnK7$I? ˦JLUZ}+OFUT%)NTk ^M=B61Ɔ,rh$Y#M$,ٞć`m嵂[MᱨaBDɹHEl>S+AˊfTMP:qՊX'pF )|E )6ߕ]i)E3Vƚ}U %1V Z L QPrPTE4M+̤[ Gdyj^t|WUMU7TK_Q[ZS>k(\ AqDz/DF5_幌faTYUe TSx۳F-5Z2ˉ򷽖mVeYVOT^.51 (jWg2+ e-i'hiE5Ns>BWdZtUP1=QUJjQmRqJ m21a-) 3̳(%3NRd.\笩I6T 2Ax^Hk{-oò wpA^j=_YB~UUyIO^le- .eEʪp*G)sz3얳 je@yuC5BMh CT@fiLx$PseEr,G<_ L>R {}cl8J>ttԣZpw&㏤}'oY$g1FleQEُl! OQ(*Zt &F 9V#rBH0a0<9^QY}%t~SU1-T4tt՞//nH($%j԰tTcQի2(G2KXe mp{߽88)&B%F\Ԯ`#o1 eVݬxǦ6aebwAanIlml΃6"V^0,lĞ ~l d! 'Ź\a} )B ̶5g5CR$nUnEǵ F UgMTn%HŠEQ@Mh,8VuJySqm8+6Qiå&o -L]sT=7`dph改*JHŲID?p䭗Ԋ:tJŦX> x\Sk#ݝ.V2 F\i١ #tMc#`Ty2ql.19 ̛fh:LpPد޸!,WS+*K;pŮ@Tit/UӉ\Rѭ;BnG):$sAr`[ٗ}AGT 1ƪ/%dO˺o2U t~*1YV Xݏ>RFbW7FU#vXqbAp.7tL ZUL5NIPФ% ma$nq`|R9wDVBgo(#~Cl9w*ָwp^uQrD2IS1f{&Ź~h. ;CF$3IFm[=lSDi e@lA;=&K9hW@rs!d)槝nQ\}+a9 1cÙft#rxERHPHPnߞ ' L>) +3Fd@T{\5P<ӃW\޼j-M:TC[O|g0>]ڏ.jXllrT$؀,9;8eWtMh; J=FΧӿE+L+ھZ(1<[ML諊O8LY1w5(YnV?hK]wP㊪(ER+{Nq1hP uW&H#AzɺR_M`Y(Q!ind[^&G \}"Nfq t<3번(k#.iEtJ;K]F;k"2=岤Ib}=| 2@}IlOȏ7SGPq"]G@ml; "Bga~~hZns~8~.~ i*kǽCYy2*YG/EU _kbpXz?fԥ}zc1|*E<=aw` nvrX= o,it𴛔Xn^ԟawLnXINSyeRn/asoN-|q`\t(tW.c68!րjۤf啻<6Ed$b{8kZu_7]P^ |_Zlcn)s'u+?Jfҧsu)Mͪ2eICBE !7Ya岐nX\V!_eXj&`*RT 1G@՘xTw.<v*d2*J^- 8n1". l>^9N`2_Cs݉ 4@HO_T*%:)f5zA&7Oo)*>ЧSF$˜5Fl^ʠԥ++sc{x6㡼2 gq)xԹa.9ung,Jih:C=,b #v0TsG[*U&j"L"ܯb 'ƃ|TZT ^jߗ#)v߸Sqﻰ8&D,⛡,U/Ȓ T[rַ¿^YE_T7KؓԤXM%}'Drі*@&Pt6V`ߞ0!) 4`F 8$Be3G攵Y@)PP-T~`~.I,JʋZ6cs+9_67px&^3&z3BW"&(v{ A|s=QEm6x6SOLtہ`Tz_+-oz&M<1MʎJCM@4sct9 XGG a<~'5uB>#1Iv%ݮO|&^^1W|IklI9hM?QZ |_5\u!@a3sJ6jcf47:-=v'`RCNU+ܛ0{9> 3bA+CV3 ZcPVPָչK\}[ä8xQZpRɣqUD{AQN!E_0f1Hf<[Xi̛yGzJ5 yTTm!G_'l.K`a3fI o3VGd 7X?7y;G=gҏ]M>\) }Jb<)1BXmqpF B(OhjgWFw,|1;kJkuKZ}e`~Z0)d*: ʤu )"`.^t@kGG[dtqi82hihbH9 RStI╛au5ʼnrYuЉs@kZy*"y A'jLQIf<QGPÙT$)kJQі FsrpoL2C5Dԫ#VPf@#k$p옒ZJ&[G.eP)-쥶f r@҃Y$QSn $E%x9Zo'ۥ +QɭƹStqS40QJ!Ho瘓g&,X9naBBO$U= :DՏ4S/Oi!Of9@"lꚟ=XuYu >K1CZsDAvW{ȱee= @C<;~s8v+'߾h G+`3풟MW=prn})SUZJDjIq)KQ!K\$~a2 -] Z[Z)HrʨAItrO b!hV[A$Ǘ_D$) HkEDz&sWQ)$BPf ;-bsZMM) ^JD6b&rO\2!]곚sAdYC+LŽ (YHʱ_hX8&-5 ̷#Tjkc}?aS TxXPw}{.{g>B$rޫ)exҤ0J0Μ{`>a ̨ c nCn6!(5!!k͸{qq|X *1RHcv ۰'=cP@z rl߯`>RNbu.n/k~}0ЌtHHěǸ `soTYUBeW+f'wnHM9lp>B@ {q"J-rңKF moyk\vBbAF~`L |7ÛNũKd`"I$6[YO <sL)[,~j8*$ TU/ oc 'f4QdN m 郴&$b^i$#ji`k^(REfu1KC$z",eP> b yVWgi35m ?Ɋ)>R'a*]EfC Zڪ2W>e+UU;<M.zRKL JrlU{XX{ 6XYRYA@^l/aE2!zĈ*A}r6`Zt&-t(5QXP52 ȅaCCD͙e0e wNhBT[^H9 \ΆPGp?<ˮz&Z8tKӧzy7YUmcco7+)6'̠M  krDPT^;U3zݽ\6 ܞMeJy]fuXUsF<y,I'YH:j]G4J*a̪'Waaaˋ?@;!=W)f -G&qeg w7pׅNZ|hJNrm͍d,$ms3ʼnI[eIͪ&gI'JӋ \>ā ߧ_-S3M_-ԧ~s -*G)tt ߒ>bIMD>|Ir>'gi(Q)JAF3%TXnkqfuG:A-;SHrHO;'[wp)>fP3 ) I" =;3 ǨĜƵv], =u dbՎTq^}G8^"â2H{uT]Y] wwn9 X[s"ilQ]?2\Q mE[UT3ʳEQu&`"F "]TcI&#I&JR|JAA\#**2rmxȻ|O˦Lf: D =R.+|?Q8 W\lvD9لQWIE lUIygpBb&Z-eV3f*,(HXkiѯStAHv7_hx{hXŲmFЕ՚\5a^T^F%`S `ige-;0U'-kZ\t~Ýԡ\:?ueKSZ23<R%\؜19 I ʕwf mrG{WcT|edIqNͅ~]53GDE4%7`x^n?C *5wxAZ@^:hpH~sp{z߿9*wM@ B#ly8T*VK"/*pJ RfrqMW+a"&l}]0ֶ_jZPW|eiV0>+lH>b @{ 9Y}1Eb zԯUm{:[` * M*[}=<8 Ņ[`=@'1t>S$%jvA"vܩx;؅a0-kT6漼f0eav(y%<9>II6WGG^WК4fe'8b;L0 3}G uUpəCKxb`*= $ Ukje-%e]G&PL9YN[0~r 7'i*wy`nطE{NƗ\<1o3sji3%_0ĉ4c}W=Yڷ0|,oקOk3)SD(V [akPD-CVxWA9Eڈ *X]ajSmA]kԣfuWZLxM=moSSui)Z ;;5.f 6eSnGv=oX`]ͨ\@2j쮵f":H,P sDY1 #EM|&[/QKNe0e [cy5?H$؛aE~^1z$JUWO6hҼM#T 1Xb߱<`lV0L%z)JTeTkdIOKDL}8Vs9R7R71,N k  NMBiTFYzUٸn[ok{_4ԄfNLPItUHd8w1Faf۴0Aka%℗-H~?! ju$VTu@6Aa7a{bR䕿pNC3 4UVE%Xn7~۠H -ҙ;PO= =TY|ўJu!rÉns(3aMS4rFk[;R ie!5!Q4, ۏp}Gnk[Am:7йuY.Wi\A<֮gTzX1xpf!ruPVa Z?>f3?OUGGEOGHdAUQՂ(MQ* I;Р5gfc4T<ݽL~l2iyX|$d3*\rOě)K[ԙ7KfC0rVMZWg (= #0mQL߾i\"n9{ZmQMA9=eӲog]P1n]i$2u>sjmk>USd=ZC4\EķQvTӒB h֚5PbX ocߜ[.5CBr \jf/dSE,J@8{]hvȻ[nc#Ro1P]=*$RY*eR<+b"1Vk]*l TsUȪ i\UPOU^8ܸYv hSsȺvըe6NhLCU$?3(r9|{+aI6 U%wrı=]DFc ;mB@AL>mrK b_%SW[R!V=8"P@/ O!tV->$(JV4o",1ܪ-Xs{{\㡍a g&ig)r0j& md,ᮍ{);A 04Lg+Z DhVٌQ,2DY]uV^ ܅{ɒ8%NږUB;U+ĞئI(d*hPՌQM\f@_/49SVQT).pñ yk|FW (O$9c~GopV9$fTSeyUSĠ@軜)e7ێ Z mq* L|?G%<"P"e{MA}Ўwb"" !1}ϒCOPeuS˖P5Yu,֌ pSK2MQsSm* 5*/˫I=\SD);AͼAA ls4nWiyi$C-ǧܤiSH_3+>6d+Фl30\9``):Ja&G=ԲSgR &^K7&Ëo\.Q)Y X2<5S@ !OQA͉0V$"2DK+]n-A߶%LtLdvkI?{<`e@f`^9[d/DekApGkqd5K;cl9J8E);w@‚ {KPBrg$u-腖`< .HErH3vMUTP-daUv75,DX:UJ*cE]Ԥ0 f%mqEL`+d n`$5MT˜$-UbqXnX&>bEƟ12I=UmVcToɲ $ rM/V +4ԓHVG `y $`+?%I >9"䄷nӏ9 }5״&6k]ilLdY{C+iAh'Wy x`E7S-xp0guY j^eM==N}Q+C2$sރּLFsg޿$SCe pV`ab]3V*h)SDp =zB)_-SgjUAr `ϧT2]8jt0:NN4eWyv#s(hi٢YW#8>V o辉k m9_t&$ g֬;EJG2b̬XWRr&)8GjbRm yUo*=HDdVT Y/BqalXj k)Х.+=S;6Q#E c2kJA 5 s|+qEsԑTBI^YGŜ7[˪yE|jzQV癚QB6im|G'7nc0/m|K^f3;:Yzf9k)h',A`篆c2lnE݄i~2Nsw~c*hb&5=32$+!,&p7TS,dH'q10-]Bv`Oeӯv u;c/<ՎZ QUWf|I4u\LHEwuh\4pe6婍=AxN0f O= sJxySTWA$k-LgUe{9=1H٦#`cAxTSu_{\2˲x6[ )]-%qsHF=wHApgiW6quEU rA/Ԋ`1Et&LGUvL{eECVdUf9}LJ(jiXj&E6e,O p^ƸAFbwVɴmNj5Hf%\;\fg2c`>JyŜTe5 @u XV v{U% -3:G[O[B9)GS[p ͬ=n?2GiF4ިRl0.$4-{zMEefْG,h)y'@K7=el* K7մCTҴkϪw?ǗNKcgzgQiFkswJG=9R)BӳTty@6m\_~_^v벜>[zEIGHQ=NV5tPMWjҢȤubrBߺX\qu#,- ,Ȟf8Ā~RW2V h'ImOwf<71L4$f-LmNz"m$F\ 2ԁh!Df&  @²!*YDPAP,3 02c <=}4-r5C692\([) {lIPo왢*sm=KΓt5caV]o[mBm"|Yg 9򼶢fsUGnL}KPEͱPrg~Yg+ShLry*i̩SF0!dIӑe>Ӛf{'F5#"S>a1I^>F@2yG -.-M}Otkgɵ&iR2(b$AF0ThުNsIc߻L[uD6x޺JXvԳJXGՐD$|TSAފLQ Q繽|Zig) X"g9 vYG깻.v_}/*~7>5|Q.|NV@d3hS#l,Oo#yk.88JЩ/ml`S%=E< c`>/xŋQݻS`+BjRlLԁ4%_’mvFQce:]!s%Ǩ2lۣY A5Z$5x; X^.nH R̥T*D s~}saY7:n-;v.f`䒮`U)IuYj1(s5Z4{&v&u@QG4ʳ ʥZeOQKV6&mp}PrIQˁ4AϔAckvÈD2IgKcGp9EH<` G4%꤭2JAqpocc@!H+tT.nגcBxh%M0XzYuI*@v ,$p"<pAa3|QTNTP:6$4v!<$@ڧ4yP$q vHE-Ϙܞ0EąQ))OGc0K[{ M~ ]s,=qF7-@sTuX?DHl#, 0fQ;-pIm 2 tP:,H=E;qM{"JhT"lGq'+0S^AL{,78Q^dpX ǵ?yˤ!Y4 fdG}RVZ`5]Ly%F]Ӊ!yQ7#Fȉ26bp nx04-3Mj!I%G<))LrWe&#vȪnĦ՞60429Tv-s{7H#S8Trz`y.g;].(dj9!H\T=pPnsçA>]9ƲfFo GlV@7:6gC6R<1ĸkD^ ʹoXtvh+ +9>g5+B+m*IԌ|a:0hds*QR,4Jbb= ́mbop$XʣG_߿vQj( Iɕ <ߎANw[Nj 54G^'賕"dz>b)I7*<.7R#%}껪PZFa(e.%N'c*c%ù&;cZftPI)ޡbfHF`K_mͬ/ccn#AiLsdE"͒msGUQ,%ceuTQ4hfuH52arZڮVIey WC{E KfڔM3dl&+CG;L6:eK\rTzug{X~C%E427 r.mzo[cT! S5IY DL*vjz*Vv.7${K UCRbe`#єGԢ^:ـ2\ 9^ O{Xq(V74ZsDU[ct˻aoRx9ܮ$ʘ撘8`e<7|Md~iԵyt&gE2!c>iaa޺g%HF[醰JY T q  Įmֲ})44U&uRlmqC ihquNE}͡gww)h{ W ΧHuGR̻y'}#4k^SLrk4\oןKrH$$*'(gCp@XZoql M%]t>I2,uQ j,6k dn.~3ΗZ|=*z*FaPT*P@?m{c$Ć[סw%5Gxi2BeP.q9kpVQ+V AwUtUIOFMiޠqoͻ㒘u_X}[D&y }G)57&“"dqbB0$w0⛜`^~I|Z,PU,2 %H$lxx%WRe;ҧXlw*lB*2%=z0GsmU|Bn l&pJx=f 꾑T-4[ڵbG$-`MoN`G>K+O#=0co(9{В[I"p s eYen/5[GKL5`HFe*{Xd|.ӹ.WIs1<_)–p(_Ȱy M'_?a*&Umd hGg|+.T<,֐4M1۴mZ2:X{ (HjV0)e(NSヴ-{2RWgeAMT5P=Ce|r==]!عPZ_ZEϿZDM$Yԍ 6oI6"Ikybz[sԸj-HY:0Ӳ=,Z:"yXI,څ쓫j_=REE TNIڪ.:-ˠj*f9l[hQLhVQ7Sx~T=Jp_<-I0mys!U9dFܾG[YI틀\ 4T+:s;tvY-J%~MA[C#G:JF[w ?8鶥>0TcFf#꿫?o?hW拗.i3i5f1ukF>f&bZX\6?|;Ɠ8n6 pXߒ-C,}X+^wCb7@*ݬo{l=, ԨiiK==GL%mpJAO .leBF(O,{l;tH\cS>3*&OQ & &UIIP܌+H85fNX Ս<3.c^M7-d-`^!Nҥ,O"Zsij2FM"Jm ̣rf+&.6;Nsx褧^ob\noۿAi*vf6/d iU(JJ@?=/*STikls]AR&D9mol7$_׸bh-dX>n1RtL%3VA2s ?Ԙ8a:*ȏu)^NjX,$@L5GټAM!inv* b6_(p@D4X3 Jx壃9 Ơ qߐncpl7+4CJUpCXz=;~8Č%+Wщ@X}np%aWv/;q錌ʰ<4i:4Tٯbbmq%BV4@@ĮBH(JvUhiרWӑ-%";VsÁQf& Ⴇq< ɷcFSYqf T.)HoP 's߸ߌ;ida76meP^[pv*zwO {^fie"3N=ofk[XCDY%UBt*X0Qn7ŏ{Ie]q!>ޒ mg#77X,ud ;7:Emѩsvh!#7ez+^PE>G|Hq,[mN]sb}\nճ2'߿NȰ7TJo%}r鴕(&13T̡{Q"ۈ XN.ok[Y0VC}4DgZ~~}>3N+b9erE?8pT(M$&SCÔ1y2E0Nd{Z$RCrM$qOO:wXDgVkx)-ZQk5AЌP9/(,@ m@ D%;Eᧉy KMVfXEY,4TNFRp13qC DLF.OuVqӜN[ߖjINd;1lbX ܛr{ cIW(}MQek|37qs8MtsȔn[GVgOPQEaiRv rP<ݑ{,UCթuD&MDp&x6iPws㱶"tNO߽?T9fK32Zi&]-2KIfc$b 7⓷{mb`{TEhXݿ{ !;AEUE-V!o3[`؛"CK)i0a1yvqE7(qt_=޼ug3ӹzPW鬎!*dʡm:H=G7naX仝ξV] [k <+EgL9DL {$]87kpq" vWig%[No]SYY=*4%FA2e,eĐ!צ+444ӢPQDħj`DkkW78-JN/~Ъ[~/xZlubqB򌎆TS'u?H:ˋ+^eIUHą"E5FS1:-BE`n"U=ͬx6烏# AK~\[HPt|:_ݽI%wOUI6$qo_O8_"©a)K&E !m}hx9XSd{EgOUusFP[,XS%Jn11;쪵v\Rg/Ψ3fY'RJz )&*`@6s=$ m+)/-M1&Uz_ffT%j~ݰ3>6V\( [  h][  g@5" IH7繱b 7М2\AJ\\3ΓtnMM(jHa Ț IaiʄOuer 1Z[ɘ˫YuF+}O/k^L4וE䕡RlsO#,D6b`q3k`'(;&%{g(S솿z E\gd#)eNUtSp}.Ab8pj-cKG?5WڽCHj=JcP*<@6JlIPyYvySӐ bYv?2C4TguSG#UVtvԤ8b-\GIDmTH)9Yn ߐM&A_>Ӝ$98F_BG("y-”:^\3yPYHˢl#U'$XX~ǯ r%w sk2cIHI0dWP )aec̄\y5ZAʡZHkH3Rq$sׅ+;{٥i(qEM# ᇫ@/X1͛: ^k I&<MDQK"BuXʐGFROv7JU7" ֧LZbDh !eoUkNdR?C$@^f&iQ."٩sdGmr~{yJ`Fǧ9py&ir<\U-Z$AfHt7d$B!E0sb:uP*cTGRPC:7av[=F(>Rv$STUUtDB9jHHԓIlȶDA1tSMp*WgIaBIo7Fl1Mpi*=$}ayHV@"_I^`a!q:"CI%eH2#]醌G0qmMEͨ4a >`h*+ލ1t,^t~.awf{yvNoN `' 3?֍Mgy('z=Ө{>֐n/sώ߳c|1u2|*'J\k mҙ@=*.0ObxgIH=cH㔹tb$jgaecv*>l k 9׉."l=%(~XTMRI1}{^Ś @/ ׯ\PCWZqq˧*a t;eB/._m\ٳn|FоxcfgӹEFcT̻)_%Azo\~kS]sįQ8JHuqgz5zS-\0+̀hW-d4QMF{A{wql?Lꭲzl(9kW ʍ742$b7KͬO4_˒p6ZMi.EZX:yŌ'o*1On]Ĭ]JC@QPi7hӆ`P=ʋ>qk0{DT ]eg!iY)Uf}M5 zj I%,ĦRXNZ*Ok smJ^ԍvqQEWjJNK ed(8EK-8ғ j]]sJ : pv!GnI;ZpVDJg-T-$DvpZHBѪpQBҴUo6{+:uN4ŋU f q|9n/&m+ )Yr%r6+"h(2UHc.@H 5ӣLԨaEuG\If/ e ̷YM6ee#!h#H1G@HT{rݾH! ,.!~,`.Gvrp#hԕ[tl sakza~QҘ9*&*+cn-tLxicWu(ۑP$µdZh &@ʑq-nbҟ0 Y[MV2 +B@babA%Iۋ~Ё|*"4qu1Ozq^##Y|4I.hJ$i!H6̮y6zcHhA+**jR*zޔ!R6fkp9;[[y(z[73pǾ$_>bmy(e,`x9~x:#}W_h_H$,}!RMJf<R5e$'eTӲ-]>aM˸qHĘihy8$%"B<ͷ,x/u F&1䦵 cͯcW q3슓=82/;b 펪5SeɈm+h*h-3ΑF! 1KZM ؕ }$X6s32عQ޹}R5AY~f6";Юni6\"k?kJߐCnSٻMj+Kbu)fv sp8 ꤐ] k$1EK.aKsT!MVK+:ŮO`E8Sh AH=Am)Qm玆cBԂ/鵶s߶%lVe(+Z12=DU} Ⱦu\\P}'=x2eƮ(40TTbO .AJx#sڧ{n .ٜI;:Xܩ@6õq Xr뫵s>s_4SZS2ShA; o4S`5j9 u6Hb*HXis*ާ5'pST Y TDZV&=nFm|dr+h.Ghj Nɤ`[`t1o_[}:$L.^ď5\)ݦ%<  |'9NybZ jjdVYrͮT۸>R;[-McD>5Kǧ [K5UR eE* a`'\.qjw VA++a >̮QeG)h|W+2Y2isd̦S ` @ap1*4]k& 2i:TTdZ7/̫3$ԡjeEg:!!XD) Xؑch/߽\L4fVز2wnb<H=SCM/y|^F.9Pg*7=qnͪm4~ CSFAҳ7ہ鎖23 .Մ).ЕtI rGNG}mW ~>)Mzu!^|qJuO+M9=/^ rT* O&׏24½QiJi>Zb1dW q_۞部 84sm%dZ;Akݽ \f/鬱gHj zJ}ίӏjVnH ,݅4XOO8TT 4G$ԥԴe[0#CrfiaS4)-s { ڮi7s7|Ɗg҉iGYQIIi Leq/+ΧAxlU5XZƽOP|"1ya H^ؓk |~T{:-40D9q0: $Zu`Y$dU*bf0u@b iu1NΛo'M*1HԓHJC q3nI+(Rdz-=/bŽm9jVkC,d%A7x_mҢIJiSO!d)! F?.~c6 }EW|/[;z~O22 2ه"wQ.[MQx&ExS,yVLg^%K,Bx[ygq3gSЛbz_U8*ѳ]tU 0O! +nK56 ÃnlO59g^0$ ?zj\(+KL?SJ؜='yz}Y>FKH?a4MCmn8G#73㍩0]|K? p7~A;URlUQ, /Oq|~X]W[Mjl1ԔƝIZ2>W$Z"-7Tʀ_mQvQgO`AGP&),fGRY6V8!gSc\@MgttQYz$iYhqB[$՝ 'IE2-K 2t h_lS"hSpH躣kVJiөE>˪Ρ.(XH)rvH{sO$* (Jɣ!NRA̬;-߁ֳ $-z1{3^d%ү}]YEF,zjM<]j鳴OBY (`X0TĆW L^umD)4qI* 8efUp+ob:Ȭ ͯ~<4 kllRUgsPRU`%7 ܷSIV3 kfw;{śe2]2Q(|x$r+ -p/"$P;Zb3]2n{Zf"AKnV@#zdFɋcW% zĬ,ȑ{ ۔M=8H$XI ;˼(h#a{v$sd&/@r%27 tnv7pn;aLR]YcY(k5( +jI)1~r ؁ߋ3H:&FzSP:q)b`ְ<)n/\ZWo!ԓ[m$^|f@[$S",rfts~wv,Gr5eCZCMH/2Zrmo17l\m E'mE%aLklŀbT; K :qm{z15N: i;V:V˚Q0bvo ͍UREU]BSkm حz[ OB̂rdG-oSZuͯX1PB,`s2Gt 7k ;x[_3nܯ5$E6SX8'pk cs Na6mR\eĘ *7J:ϦQ):̟UM&A{cYp:AtX'n<m.B@j-'؉s;MuP,Yʰ/cذ>H~r9FgSMNVe-#52 ܨ[m Oa.AV dnSft5I=\2p@$)h#'>&4E>9d cbT p~Ϡ L[Y0QPi^sEB= U ʬvG%]݃8_tS,iED,KvnoaǮީhfZzPlPvwג> *;$Qj*@s~gjxuOuYv9U5;<Րd`tUquxmei=E,ML9Ž楔PeM.aMbeFR(+ۋ6A^<㺡{`SK]TU4e7yqՐXrT(/-̡Gge 5Cb i6!3z_s,urMKO 3: gOcpi/f1=Z2I SI Lt)P4O*$`\` V]]`?_$͞fYs6&F ߳E'pSM]mPkd9v\"}PdX@P&,svf>G)$g_ݵY"SgMOWB陃ʮvmI7/ْۨ+ gZ4MYAT2u3*tBg+$;VBC%@kԧ>H:4鲭z!iO#INx27^İ[;Z0-b:IKY Ŷ-S ӌ1Jw6ʲZkZoOY̲TFGF֑ۛq۶ L8B,9_uc.׉y4' .ڊUu 'Qu9 M$ru`"DSP`c2clv,G6P =hA&^?o'(*|*Z1j\T7:W׎ζKLSASGL#;%f^'8] qH ֲHRVzr}q lN^vX,z9V_I`o9Ǿ3_r= KED沊f迚]A,&k1R\X^E\j3ˡXr]BVXX O-R#NT*)しUo}q/Ȑ)LueO VblpefDc^ID7H;{h2i iTS-Zѐ0qOsW\VG/YsgHT5O:ej:H6`EOqn!y,ԼpA*F16 9bIeNQ(Ԇ79YX8&ÂG͌ P* 7i04TZ M/-C[POMpA5Ϲ XaTeSo(]d.Оד nUCrɳ :y'-eJyk' *D.Y`nUAGTpi;&኉'2.ȷ^+* _~;u~[4iWVcaC)*--aasɵqͪʢ2K1G0&5jeJq>R3uf5Z&#^Ѵ545{ )K{b*4H_?ƴ ]@%=T: SԱWQӂ4\w*O MO:| ׯ*矵=MV);Hb? 8g>G$#gH3 XyTm YA2_ÿZ&)d@!*ʑ !6RF\q1iz(XB;Y@_,k=e6ZβjiVKt73{ٿX{qw`Bsl2jlA2NJ5vN`)ޚ+ZVؑOAn,}+G=FݠkbKERMASZ@L$udaM%1$V2tV~92/%ԩLq⦘R4z.q&8wW嘝/+c]qZO| *k<|*LMԟN#,j ԬNަޢ?]I?៊IT p~r`mD$:W}Arws\vTFߢr<޷!{f VkTQedi|55,$_r.EV&:!]oQrRȿt1F's3L?5 Oڪ%:FJYh wm]vBI8:ss2 tfYfaږ&h'RIC6ѱ lm1Ů <i|鲵Xe4 D4k*یLQ$ɋ5itPjhe9e<Dn1gXFTʹlS BMu/Cgj"5/p5,4rnrH!yZ}"XlV:0`q1XWU\*,hݏMvvP0M"DI޻,(nIP$YGsD1R|> 3}k^,QZztfi"^ejÒVewsh5BDǖD,^ 0}v%PQՑNtrFcpœr k 78.h>ͳ8L,5ջTS7HDQbKTb[=[jK#!*N#pGpH"ɘFSTMK`y7 kqb`,-dZOaNf2(zwG*a?P*H"݈Ԥ4G YW 2}uֱip]9#S,%<7+p.An|$Y>`퐣wVfqQZWۥ#pͻ6,tG{&HWacؑn$j".T2Yͬo! N )Z`@D0F5x?Mqp<V$TK$Y~緮0i7)Y<'|4vz6[#!*ꪻX}IÀ%"*JXKKQ* *;arHДΘP0ORx`L5%" ۸ʀOsAmR>_<Ձ':U ""8,n$VkۅZФh#2ňY Eq؁x4%9#L&l1A榤0YD bw ), aEWCbe&m#m80%LHRFS"[I{[=V5Ց\T[{Ha@,d}%VHX  D#:k3ǺϕEK }%B>fESy.H-F()lQHh˥9Z`cR2- ᪓ô@U%<Ȱ$o,*k_aaيۋ|Y͚mTF&B^u mŬwanqŐ9\3EDUOM$@BbVmd Hͱ':z$Ϟ/&O4ld;PÿIB4˫GaY>]}U4&y)Ycg$P yUp9˄4 q\^=nݘh?ÚZJfj_Y#tˀs/M My "Q0zG)i(Di6Uw:^2ō-@wvJBzs#u&@\׵vW޿A n>axp Ee^Dy#R$ p@ n0 R:}2)WlCdMEte9eNb*vP<X+=$:YSk*p:xa* 3Ǣr1I,ZE$*T,ޗZ.)n6:-P:s#{} ƒJkT RS 8rꗧ]KP  fU+mظU}yf2OUSSR,e*v0yh$t3[+Yt)GJ ULlp. +,dgIu5SrWԥ!0%SMȾPX(\@" 'll9}=WDbw$}ED?7̼/xuPu2Ѫѡ'Z\]ΊwmUxö)J4uY9SQd++C5fptK,$tP<($ܐ/4A_0dj:saD3ֻу½ SO$Zm]n-f/cLa~Dv[i\<8ϛ:=V6kM\ºjzO2f$ lY֙Lpsb#uf׬bL^zx檧&4ѩڪO= $TpL=<Uu0Z9j8$ͣΒ,ӱeӈdg]BD*19}b~s*d"%5f :D~uL:|IfDe sby0l2ҵ}M`#`lS>c>aQ;ۙbI\V9U8.-,j+-+0YczjexZi$y [TES/eX!`sqn}}7J^a+B)Ben0?,q*9khe)Ht 㵸ݸoeUBܵ5+4pK,3""}BaFH#E˛ꪳ) }WL7H*nha .Zj@6Y - 4$ON0M5;@7=́wS l:*aruزJX(@ǰ{alllH"L|6&"r/aG$y5.]%CC TLp"DR{nQ'0`&/ .m^O]YjM*Ev\$ H-`RY]Thj(4 |n2eaN(%=^H6noAlr3?HUłAwýShz;&+**&Jht7xڴQu*VVc7UfT._UPΝ@ a`A` C%~2W|d|Qx&5/ϥX$qT"η!m[M8P E]W/CGk06+w+g#Ex Ҕu496XK; K'2Jy~3ؚUpVe[2ZJ@<{e+ !*Jyn.8!b?LceP߅g.M|5ֺ\-GEBL3$IQ؝Y1p|En&kE:ss" zSĨ' 3jO~.44uA!B@ڪ,wbT8pı/%c欩rB5մ OH 5,2QHORr$*LcsXUe.A{i㦾Q&AzO,o@"2n ZXerG,1YcIKX\0mc`d:&-iڪj, 1`Jȶzz\a)ףZ{7)Ԧ[D &I+7|z9ADhH/:UFKe~MV`x 36UE嗟ʟx ,*^g3КU4[# Y9f;yחۢF+io#{QgڣL=,E鼪 ҳ8Z)Eܱ>)tf-7UŠ/\@@jE|=xaFg>A桂 rvq$UnY`b  ^q |F@X8}DŽO :ސ<%J|@gRUi恥J^KK{F2MXurM^'*Z>@ϒF`qn#->md< SV|A}$4w|Re Q!M -̼RbA,wpJZ,ml"6K'>/į}U*x5c8y.RӂK6E %q5M*5@7_Zln}ZNkN=tZD-2ӎk]+0?/2RƝA$)\ZݭDxRq3(trwZ3Z #+i梖1 ̅j׽(+B DUt3 540n6(O76^{ᲂ,&jX`/{=PJ4BjZ-j?M I7DB׀J'vmkN FT:VӤO P77nm`=/- ;ET ,.o{)ʈtXE4LW I=9–AHꗔ v6-{c{b -n͒x-nHy${b %-c~& nAwy*-7UcIFnTJʂT~9=Ŗ3TFdAv< mc66Щ<Гy_,dH+(8RXuL($BV"Cf^.`7`98\tYws<ƪèkv*{X6v/K;d%l@e[!lŷ!BlW4{wXsϿܛ3Kb@h#o`m{qv@ CGLJJafK F \I * 9Lңnބp-p)$\qX)ɄaXS"kl GY"J&VDC.忔16,I jӒjryu~Si^XѶK(?YY~[6asuEՆ``|Bj̮)dZ9#=f )Rf:mm5ѱ:|l"ipX@ϴvUY^[ꬭ/iJ0bM7֔)=jUbDfNUez)`hkQHDe6,C} 5%Esui4^_.˫e45Ly Sj)gvbyf[sS6RKƗ]+uj- p%VM8Q$ 7nkc`Cs{wզ fm'Uki89"΁dW"nE2!FaУdjjܭK{ZG ߃KUOS4/5"dh7Y]̀>4yZٌ/.iBK%h!ab"d]IU E\tiHʹ:Z R`a5}K9Qj i3GRBt!Gw w(!WBFdK^)|r妫Zߗ%LbXV$^߂,mzrKM$M=#0q{`BI*Z-Mpi.TL.ærF1⣈*D|3TjFLyA7[_pqR( 1<1VIR/~їuJܹPTZ1E֊MG #̗nyԦ*$DBzU{Գ:P͗Q=}|K)gbv$xPMp &I'YR#.tI T$S*Y7`x<]Dt"cY,lE͘nۜR.lsDTvkmP[wlSv`wwlY,<ՎM*I$áYN\sW@Ri3tuJ%ZeyEK5V-.(rw8+:3dU%N%)++IaGeĎzޭ]jˀ"o1'cYRhͤX)-,Z(O*ꝝzhd#J[\)b< ZȔ\*rG 2rB0$ɼ$s9du]RH;~IsQYSS`R{ "UiaCo]%U-MPY[퉳Jb⚣+S_ܴ*&f)=2-GQբ~a6tvӶ憥m&ן36`|ztUfoj|*ȳ("Yk)u`Xb.<$ZtNÔ}~ #gz*uF$IUQU%bZx!Uwݻp+k8Bo}##kS'De?:}O>}0.R97C+3yFSQͯRčpLoӹ잮ϳ]!Y 9;oYzO[Ug(xa1TL'YeIgutz,8V\" <^!oSgR:H]cgÂ8/8`kT̶s-oIKJZ2 ]^fg<S )y.B.U4cqϢR[P5+=xফ8Snm1ScЖЯy`b;P[|0XKk%3ȶeq8?y]v떳Z|hPfN-5]krؕ5EC 0Lƫ/i`׳,UPwZt;o;Eوrʡ X1Nz, QAJQThkm L ꅷ(իQ,RY3JUCXT~L Li|ҽcɩ(]2~S"5ȌҾ7ͲI53TLG1T [uy WU`Q\F;H$XG $1/T 'uGÕ]%U]z~91,aj(2#bԥ{\PmS@LerwMH[ qEbI`9Vyc|piB)UtX:(Vd;p72 [QfUʔbE=,;" *ܐ=ms X2I %,~Vynwco:w.lI9e+^R˴Fi_X˰kb@ەF>|o|I3l+B.u/ (wIk-\N Ф\[߰E`Ժ <:{OɦLLeh+6'Ų<3 `<xQ4&jY/J4V3nk:|ns*jtǰ{m9|:h ~r EOK[eykCjͫPSP6K* @~=`թ%@/pp^ n~#S\z~wQ +fwZV l|7q"K-< a@NzZzf=Ǫه\p.__;#+i:zW)J CuB!EǯN6oJqLl|[/l?;Z ?Fy32UBDvJBĬ/p^S\t:hL5m ;2RMGK jп ^oh(kVV-3+;!IweE[1?Xahy@bTXwVZ&cis':t~Zh|2Ȁ=t3*#ق,n p_~c~ q94O|22Px|6[m?N [q;#QPQj+d51dZx¼b+#1/QZ~sɋ%{) g0(XϗTrE,ȂDb7UXlMtRX]vS0]Jy6;>R )C3AžS%7@bo!B@Jvo$.a{jM=D QW7Ih vCTŹ$Xi#o(f3ʚͨ )Krf4@/#eOpG[I*FԨ,hss8nidG-6on$7F4L " ?ح7&FT$Fcc-C)^mx{aM{@[0˺:4`$FO!{^A "p T(ND/|ZJJ(ꭹ Ƥ܀;L1RsI5,kv\H;{`AJ&egfD*5Mmc~S8ܞopx1tRj E!RW}ܗIĀ.N%&kH^XfɳX0V4:q5]Zlcv&UXYBqSK]Uvu6\K 12,NkRA 76b;0 \'( <p>뇳R'rIh9 4]RARZֳ6fvHI $Yv M'q"^FkBG` vPYc8v^PO5:&EH, ߂15ۦ*҈,hv,ӷ?Y(_mtQlI ](m$Fk{C&bN 6VYeNē)vR86>*^L&\:W rJ#U-3 @6- =t5 <70I'd*-ܔ<5㸩%ΨS.֏%$V)y%P@$+7{`Mk*5zUhZw](56:F2m\p;S uKNQpzZޞXgD~a 4 < 6ve[+'1(sv̻7q!"^a0YuJeU0G:I%z*F`mngAKaU&tVVy-Lu%t3! SO~=&Q9JLe*fYL{ù#llV.X07nWˇ-$EqSQSӗ/MH]Zޢb !xj:] 4نu[WKTyF!w1mk~oM` sݔj9cgIub/r =ok QQY;B""gGtf#-kJ+cEՊād|c"S:J63]A$RWO(_/C 2UE ,i`l;nI&T( @Sa$wGZ&T: 6m&KRk ‚)ʫj+i!Dh)*= (` ض`X0{O8s{-XdZ0#m6 v\#wv!̲E~j42%.joo[NGIZUV\ʐ^y !1Fhr}{C+$~=Gvy)h%4wF [Rx-ꀜQl3j?`/rF@vn+rVXkg>%g f8kݤҀT=5N@95NO5ճO$˴*14)8W־/grҸAIsX0{ q0;[?}= o{6sS׌wWg̯!U?zGjW5}uk۞b/Ifpw]◆7-u2f T .Gq{c Fg믆d5Uz{z?KR"{j]+hm>Ee=U2<OϠĘ$N5]2"Ay))#[f#+bTH`ɲ|MRf^,)ujmB[MB>IS[%f'Kc~eIi*.`+Em=41x!L24]I|{4d>zX,-<>c*]@i"xBkXcCHX*ڨsfRQTvة<N":]ʪ'擈6en1F+Xg9f2 u#aqWpa#kJlQlnO1YE\3/"`BPd/[,[:A_?x9mHݡx _:]eW4×2FjB%Dg`@$_~ &i6DKG_rftG u1y|akP{cR5^GVdQ!!*`*,yͺ7XVUiotreej"$MoQr0.t_h=x}%-<Sýc~ |3i֜)hu Kv M$2E+m %E'>-g\Hct`uRpi1${ .Cx?~ xs=AA &qV_Ky {>*1G}W3&Vb~EꃕCg*˫)DO4Y(S2F dPMTUa5HY3~zXcjwU677s sUc.>lIyftѡoQb/u~r'WByajl$tu4m.I"f0V,8] H HmJj<pRPU"lCF[r< mq`!I,dKJ(>㿾7**'e\e'0x-ScRy!N9sfmB>e ]Hruɩx*dREP T8$ֵ0|ԜAedfF$;݈Hʼj{(4eTrصxjg.+1fNʂc{75RIr,t1@\I@a68V0&Sz"J |$ˤIP"R& ;[l<Ʈ^͔#mpuH9ٜ0 kkn^T@t-Ů ɿ `I 1D셤VXߎ 2"VcR]}Bet|ଦpunK˲ܜXfVɲE܀H$;n|U7T+lLP&u1k,M؋q\³0ꮡhj㎥*$C.9$X1&ְ",C)&]Fgv6$Ob;߾ &dM{ĥ+, ˫w-+5H[m$(=NgRj2jyDba$r#F,Æyy‚yF-3B᥮MoלMBm \MALMET#Uٸ#Б kvLm{U~޸`[u>ugzIi9=d,1GLHP=@~,OxpGGzWX1꿊O.W]M[3$U9G.Mc~ |{i =y/\70|9ڮSATf!]04$/HjڎXiymm_{:sZ13r٢QR$nf R\,vI7X V&҇%=$TO49;i$ЫR cX`)fWZbc|0{:sSY2Pʪ$`.m`Iߒpج.AUHl /N @Q54W zbZiӺqDJewU`ll #ɩjb`"+;- ֲ7SxlGBW"g+.9i+554զ-D甹vX-ؒ}@0":%}\973=* YH%7Ü^#V"%yS=+ƑO"e;7aNcڔ+#m[_-W$APQiJAP/$A۹ -A544@F*Zjפ!6: -ۛԨI>j+OQ`36*#z%HxՕbbAU;9nXC-O%t9|KSrֿEY:vca!TבBA]Ҥʮ;` -ΓyhP{>$ @(ijHc$p̻!_o'loәVC_e~oEQ 0#&#Ώ%ĕu꧹i-׮%v O .htFMupoe#'Fwb[tVvWO%D T"ijn;.TZ  Z̽Me(W璿EN1z5DnWc\Mse2iLjgUUi*9`$sȌʵ.i\ ٬Jꓺyހ[slCDx+>Ѵ#=uU?䭆팸ҩm OB]D=G8]H܍ۈy29⑫9Z21k|LUXmt~՝}MYU#DD+$ _8p:hӬ k5pk7 of5}cK1ju&S2ʨZO23yH)i}֥|ZCS[PV򪨹1C&.>"5^g]Z]-=6t[UEkEG%(@ #X0mBUy^-j c\ xJNt؆šRh]uRz|"Pc=m "0*KWԪMU!V/?[+yZO?E6S,W* QN)֪Ʌ>RgqʱG7Uy'!0͚|BjʭPٔ5j2\z~jH6^)e.6<(sl+__m~ Q:tK˝Pf%-Hؤ*ϮMPuи  @zSc]=H]4朠ByP#ST(3I`U-qԠ:^*dD-ͺ1{؂?8MtimF6ѵtSҴ {vרWH7!)7U`G=+~dz <G:NP.wh^ypT ak߿93X>0Rhs£-*2cS0$+YP >*,W w>Lh/Αg w$& bj8 gyw/u׌N[5wGӍʅG ű3y+v'UL?zv >H:pDŵϿ|uԣ{6 Ep؛i{Ji 6hںLA}miUpC!K\f]u𹛇q\< xJxqաS畔fkbyV'j%D#|ֹ>TJ)%ƄC#S>-JBL8o3u4e@#䀿s_SE|_V|vj024o\w,*d8Wu ~?P-:5 "_~r5ggfuy}fCED^ ecN>/.,3Ď!D Ý"&I$u?-A'W~?a4Rk)+`6>,-V7FƋI>`.\^%@ cʖ d͟2F]ɨWH$HIhdR{ KgĐMh#(=(; |I?RWRӿ Fit>EhIRzLw7~*q^'X<+fNͦ? >]Pǖe0SĶ X4AU'92%u"?SƍhKSKYA%$RD1;:te罉 9%liZ cUx*>{\`{`蓩Q2S!9dB~HfPzEf u i$)"D[():*XMձpb7HPك)vX{]6X9?oܹEWN$%!7]Ar,Y`A RMD!ڳE(0ӽ!Ҵ[T1T:[ly}Ap}Gc녨eg ;NxrJ0 BR n6kY irُbp/yʳ)@Aqϖ݉ƇM46u~{/k9z~Ѥkr۵/=Ty$9V`7'}skxUUP.g ጮ<)ȗ$l~'GN,tFjto:Vx2-8t9]ê3#Xx᪪sIW5%|r/r-. + T *cy'_9s'~/ 1r (%=-{[)%la1_$Jd]7*HqcH0 #ـ.rsꍵuQe%P' (`>ie:oVZ)^2f sm,Z"8U6ljZ!`uܾXka!{kXP75D<3ʌEU =lULWM$L$Vۇ뇦)[UOE_(Fcpr;COq:Mjs:d _m [U,-9I:E*mp@ݓvKÖQGwTky)ߺ`zfzP%w`y$߰8:$`;*G '\BtNʲL<1 'k@olTLAG.G:dV۾77ƴPuS6 +vLx,Rr) r){\Y~~~ ,Ҍ.xQ6Q ZLgڱFBXcը\?kP =u?z-tWkn\Űa ]XD:E!M9QO,=/LtV*R6_Ph?/&iIHr~D{f^բa+T,eP etsy&$w_jnR{Uh]ïUܾi2Is*8i>d˘N`RT|xs eH`O|%{fk $Z"i҆zj(̕@?{$8qK\U ZE;08sMif⪵_' RP Bnʮen-űl?₨{gK+pLj"|u>.x!4WjM=Ct+[wc8ญzڍ 21_[MxUMKAEZ_f >=Z_?F!lOdTS=m6+DX {X6-prÄ/X=}Qj*chq`'[ m%rZֺ#x)ؕ-? :15RbNN) ~}=&eYɗ@P%C[e7evNo~?eh+5TPtDif8*{UĒ@JuHIܮ_i_v-r(+VBudtW$18*QPjoiM6OQ|CKżXsL9j|-UI桧E/5K*B؂H-F8]K @$@Ա.i~zVd^$\s3uyԬp;Z9 !w5akrp0̠WS#hOU<2,Hj=M.ͳjwq1Z|c,zs?l;$>`b<ֵ3˔UG r? %&vmn|[GrѿORqEh 1qq,n<݅x?8!LfO󘯋E Ksp+䂏pƦSQbl ->ö my'|߲~P:JL:$V=s$d #N`wrH}e[_xqqU?oރ@i &{?XV_ 9l%T:V&qXoۿ8_ oOGAK:>>?pWTJ_0&zմ7L2h+#+F t`@e_u|AO<8z9OPOɪy["@>Gy̤ے<1x^ 4̺Ŝҿ|R̴y49]~qQ>WS`vq6Ay >CR$:Rd&@<, <7!DJ4ƭӶQs )fJxT.LnTH՝籂]\+I4e_MBK F\e>iC\Tu"7 6t;ʀ8fmGF& I)8vvIW N_3$aխ@3ܪ/zOTxq]e #.efiEGQ#KBNQK&ă".5gL\=zlƥy$1P^ ;sv<-a7Ssp>KFC)8avJgኪF# 5˓dfPy`Zā}ܜ.Fe3y*Q%2I >kULLЖ1y.zQ[W$m*_ިe⾑冮X"tNBF[(w!@MĢDgܮ RH Eo n}z'GrһYIy X lfV=*7]> e;"*A]Cc?FZ,ISԚ,A?qFJ1-_C`0]ڛ>Z>sSURxU WO &^G=ۋG8egӼ?C;?Sѿu+|bi~c0|R<؛~Njc gt]J2eiO,۩Y oqq~P6:,{AG X_jf!50 a&h% ZŻ9 BJiF ʖvƒ6zj_C-9)8m/f9\eV0P=m{b,F:j`%%3u$39cI.-lD1ՔD + WJVH*%oK&$h-g)25=Ɏic!nE'/hsQ3G)U ذr-sG$38Xͳy' H DcsEǿ=8z4]$5DD-[wa@jY) 7s''-7)~i(hѦh[)66¸@s-¹SO1Z3*YzۿߎŠNe~x?teʍY 3L)Qfe'i6kËf_WP2a16؏sMՀB>WsCQI[MWTfT,+Hll===#PHy{ri10|3 IDa 5i!H$2j[TAA`*,ce]${]3%jjs 3xh TO.I,Jјmuw]RX̯uI|UtUySB]5p q|4 +܎p呢R:u0^t vZC;09 {W^99 G xM Ƕ \Tʬ=锾gGdJh"v‡?45 :_'VGH̗nGk#?UpsV }E ưH"4yHZti&-e(ss-5N Jr8"!]$_36Cns,y.o U:ENZia$ň17Tꍦ tTs1"Tb:>!SSY~{ s ;$hL&WrJ8,v%į?uc.;X14\e "Q*~`YTz [|AԆk.s[6Q ɷú#TEQ_lӤqU6^14^SiH'f,6']uԵr=SWSk KWbSLkcy |[&JV 賨9Om7㒫*5*mPnVy`|ۛuRNNhvc ~W{#;S7zb];MRȕ2+K('n[ j|V*SPW \U$')~--@֚QWf4MS>}ZΑ GFI acn䵹Ͽx$]`xN|֯zZ/PzvULVPО lSŹRXH]xC AuGQku*_:tΏ> _SY<.gH֑Ȥ}Vr8s͊n-; |=W.$n`}95܃>/|'j#=1&Š~8* '7CA)F`r~kv?im N]#"@Zq;C~%J7"IvF䱸6yXEF=G¡8JjqP+C4,@G~Iqnpjy .1Ϩe8 Kd hp.X[88je.wg_7g95ELtA q-r9$.N>A MV>?)֛:3vY5#Ie*62 gdzcE@8s4riuGRİDi9#? qi1\f=JԫUI$Df}Ihs`k 22ٓR\q{f$r] i#WRf&z: ƅC4tQu(@$\44>y>2fZW,;ʄv9$VvVВlkn"~_Wf d-e^V;O3E}]5]f\)K,9<olyOeڻ@>6PN\n&l6]F~ʯu@xi(0+5%:n DUXc]5vprzFp|7|~|`\@6{%|>x 乏uc^gDT D&,CrOrf YwJH _hθǜK=ŽɇGx/#aڼs_iQeteA1c9{dO}kZֈ Ju|6|(e7!EӹX9\Z>@Wg?xÿf=>=@Th_?A:־]+h|=ɤ;?}֢Iqpal#{mo}pkGroq1\#r7~2k?TōujݷgI(;[((aZ]u]|eL\2yNƯuʲj* jsU1S4cUV\tžKc" ɛA&vVÜ/bPv@ySC9|A]%Bf+,T;#m+yK9+G_UuwyYG $I46CY<,4Q!A`QlNpmŻTh-lLkuTXdbX vpx^QҹFD%u,đkx/s֘R|-kGarnH$L]6p}"VUFXdoavPO0)3OU4:iN _hv#8``EE]6vYL+4o'.6fU I3dCX͖Y\Oxܞru>Q_U |ԹYsꈦjt6!Z"FT;oEwtۯ ]tT3%e`ڛ#hOþ:aE 2HvE 6ے-{.:ZVi欦d7Hd3|k>a\% +`LʂjLO"N$(b>cYu`5PUO I7k`$e]=eRQH,[Ҳ*H7@>;Las4Rp!é㤎/32)[<1!EǢxM[$BXav)MԳ/ȰJԋ$I%1U7>ݏ c p*1 sO+b "Ѯqn_ف*47E*jiʊ8Dܓ'}aז<<2r"dPW%(IU3ɸ u+=)>[-k">]¦D7v[ \v t6!s !CyN,?!O1 rOV)YamK\H' rI-: mduPD%]$rWF8\5+'CלDVJ" ][j)7|5i =vZ Z)1H:Y m'v'A>@t<unZ 3ɫ^#"eZ[s!sE'xmb>_r|D)VZoJy({aö=_> Zjl3䊮 KDѡVH@#)AWZ+IP4zQoBa'hM=|M_Ejj^FFs)X۞'b.NfCޒӔoP]N;N}yjK4XӸ6]*uM:a$qԝ.H.G> ruf-OԴh%Hj%dj6)KGkDU]sir붉CLG+tU m,T3Q9'ao{XZޣ{L%sc|Xoھz2L<1B9U ! %̤`1 tiaPҧ63NĚ彫tǪZ%a,%YXHs}@FTju"aA3I$!. $mBL6":q;&JO82ϸv==— x*}I@^ĔFbLd#<AqNjs)Yw1h8A`TI-|j3Q.Heu3u'MLlʹ>\(9"Y܄\ubq9\ ^)H(咆DrK4^^Xn8۟cfug=1$[5ˣ $ၖ ,›/RRѰ40j-u"Xc /w[k%s"9\ta kcTXH Se 9b}M2O (tDdj2Gzq:`%?S U ,޿a[]Tݛ+xQR 'c:mQ$jhdb,kck74YZܺ/1K!G~i 8H˩%ݶ4,HodXRI2%z+y(pJ-Nx/ FqǨ[(9UUZu$BD 0X\ #n[LDg4V[~y;O8m2lu>%_-4jQhtq=0"n% (|uI'BEŝc1nuaPi2T t*6. (S{#2^)|@ٽ+O=tbP<{L3@^mFԮ{ʧ!/(1bTXFaɿo\z$/:M7A[.Q&ob]9MwgU+z86OkqN6x9,ZΫTW,zq=\\ c#&N,%gSՎXqE7K]%3euI2u -&Π3Jj;2r 3&@HX L۔K MۧE=Z r-J$\.n4̹n~|ShK9ftH]NJeѿso0 Awn/8lKe`8g±MaCȎDnſAfoOYd .[Voy2p@|1Zծ4#b}[0B+n[~9xQ|E{[PyE0+Ƃ,}v7FÙv\ ZZ7r3~3?l!嫖|h*s /U0K8sUe3I۩v+0S W;=3wX :G;/";7UDeTWfKOpcA"xA_|;.`cNEF&bQj%5:Ge1pgwyic@ڒogWʴg*ϗMTR%`ARE>'GbbH_qj_y؋U+xxy2\ʓQeQEM*JaowÍqu ]Ecc>JXuDi󯆯r 76< չ^TtZ,L~rŬyS\:QM\m±ŸhnE*c z}An :7yiH9M$6b3Iw:ѳ@!3^ۘm7ðà|XBO[LVUa Pe#,I g𴈺gGZz:jyd/9eR8u Zqȱa$_]Ze+SEщBJIK۽#`NrV!j"c=0&ď7"dIQjV/˩zy9Uw 8V!op.tfVRe*Lv"U-#nŹٵ@{XOO_R~h?+R]Υ~IT60IJ]c9ܑnx) DUvkCx1V`lpp6LשEIJj:1UE1 a[8PXsr c"ȳ5]J4E$ۆwf`.I[axjE0U<JJ8?>BI_IO 4Sw,1S AغT/xx:T~cwOZ !.j-&gNrPC'J:xV+Fp$YWh7TaZ`ĉm0DDܯi3!C49o}O0\#U&Zڗ/} '6^Ox020k{}91+"RKŒ ̾{` %.A4g'܅663Cu:¢Iif~Mv%nMH-j,0ǖvv8YSnuJ #q⠅h,+8˾ZM$T,l Va tT -?; GO tDY\ بBoq!ր!O14&0+\^m7 ڕhpQѠ2K<"OvbXf vLT!ְ~lly>-Xd6VyT]ËnK;'ӿ uoui5v䥖zUxjK4Lyr p7VlC0Fޖ^Wܓ2xW0ְ@k=-`?fU,mV}ڟ&ehY6 +1{cVl?,R$R1&m,&j?Xw؏@}1*%AJU'_4]SW4bPQm FFZ ͣ/95&*_4)cvHwCw+vis/T`o7[6E14PTIB̰A k0\ $틎 #vb.7}Ϳ\H1{l!枧5l-lch֌H%MR\QZeeY)נ 6.],A#rꙍ~NYbN˾^T jƒ temʸe76ceFiT vhpȾ\|۸8[wl=<i X6Jѡxa+D r8&2£햛ѝ7RC,paQT, :x`2z\`>s0mƶa?aLL6šNTFfy(\5H>c;$Zc2X.I$r}2 $ZDGcrG9lA'k$+]:)\y>[X P-9BͨkH_olAzls.2 Lƛ ]yg@B$z:i*1E_* ۍ9nu.b+\2*ڭܖCkX(7"ӌ+D2sGXU-@kyZLªC| j{㪝x7Y'EAM᫨2mWIKɣ1--.ޘmVb _hA^aiC_W%e7.Os#{ p;&-2S81+mRT0"1sn.K:_4ҡ^ v߹Ϡ#Wzw:*}NJTԕyQWs8[kkkCNqߑ{~m>eghZ|Dm$\~q3@\.53_Dɫ*vCԺn`mʎ~|32S5`6ӴN^8^;DX+~Eyxks cVB'/PO{}֒*<9s<Ȳ:LxVƧva*<$tZr3F#uO+˼LC0⌢ۈ -eŝ&r#湁L[YTntYu G}ÑzsްB@Z]|<~ [j] jjtte 5>czXƀGV%44$0o3]I :_9)12IONK8?nT.qOJIVRueaAc!}_ǯG>(ovM+⏕/QQ}]b8E 5,o~)+ecޚ5ɲM QP Xi: w,TpWvLcYp8+J= Dِ庲Tb=p"P|en5{W6szL/ȓ05ANi @G rcKZ3sN%ꎒcOBXbĆ )karIOAV.ek(xnRbu^ WxƁrG:͚tvGsNYDl#iu@@$\1$<2}5/1VZ:I]7~Ϗ c#Tgy>M\ήi =$2so[rq7x)0,k\t'/M p@1nsےL@Gk~ <3ӹ?_ (2*eC)U2*JS%I\8[5#/"a&b*rOB#r.m܎}lEƌ+I!E=E)m[@1LK*Ānc a.bBtU'\P#rk8"fZ;0aʊ6jlkAseqǕC6x:MWG }|M@ lz3]xgď,5qii.ۥ54)%bBAoA9O7 CT0%8/蒶RU {nɠ`mVg~"^mC.b_u("zG` =c}& O H0_RN䛒|MiA\mkcرh!EdHQzwur6̨5L$9MߟpGu^Q-5L,N6* [AqǸ` $5~/yX]($*GǡF1'dg壖y%"ۀ,/r;a%򄸕wQ8tDO! \׿=lk7"G2e;G%rO-3exo0񠋡}FjFm̥[p{\[\'t>|߷b$]o*QH"0PB75 O$ .l1728bo;Jn X۷ۛ_$7J."3$"zvHWnǡ|0.! 6YF,/MF?M([sev`UC+Xkq+Т(T=V~[eyICGO\_,ZUHA$f]"(SrsL/kX4,u\Ešdx D[%(I&!@Hw<]T^.-[, E 3B^.mߑ%3_˝Xn0Qqqr@<ہmL"duaDA#GQ 4N Oq,e(-_kŝ¬'= z`9sh 0q=0+er"iKpnl5Ůn8qiJihVjlHeyQqka XD SR&`nG`osn;`;r@ pr*ݑR[H_ARf PNB\=|b9.k=3̒w wr2V T^E+l`@ 81 q\Ƙu璾*tU@˻yvy&Eki(V(ʻvqpmX?D{!*OUPk^51>( i-wa<46TsAQ966mqǽ.Y$k3' x [!0iVW#(r:j^r{FXH.i OfwOW$+6cHMGӰFiw丌l5B*8G $z-sPŖYU&kפr˘O*YwU6* -UTc^CLcXJCSg*Of= % :D*3i\9p9߁]$[84'z^ԴETݶX/`n|P<+w[u7S.j̶6ҕς~2Ⱥمm8x QDl4T_sQi;(Ҏ17K( NfUYe*2SJh{I{c:%~K`l/~cS#Ek4jM*\ֿ$1 BA'霜̪Bz#` T?lfs5&]tU-.Q(Ua R*$, }OO,6 <㉬0ؓ`i<@uHTQReMUUHoPSYsVPjT0俚 Y#ʪe\2f&-(VMH YTZŪ!{[[ fSı-h. ygE2~A_Β&wN:/|] r-ŋ{+? Sp+j455/o~JQPx|γQE;A6HGEJeXFxe%xIQ0`4I2`LmqEڸǻ~㐒@9 YYA iW8͕1I HjJtyG~q*xYLEL EXX\(myd:n*yin2$S؃pIaTK.r*IiƕcxAX\ -tRA fkSDYVW<]uJpAZ}( ̮WIfTRYiC?=9 #m>f 摲RG8v;̆"7F_1Hu@)1@)|gPI(OԜD!0LO 9`gYf \s]XIjlR/(UaoeHm Qf+Vɘ"5C5C},\ۻN8]L,*f$樳| R\S!\ @UTqS5Ț7P̥>b +mq#"NaRH03t9)Epl@ c4n <{Xx#ɕz zmr qO/&d&O 0*z|]HK0M ȍ26W k؎~n%.') nec:z ,3MseF x]&Z8ަt)K4+bR=QdW*Xqv9Q r'!jQ Vr8۵{>b:z,iy Y0XzLLHJXbyfvRM }?sl#{9 no6G$AiNNgHW{+!rma#xl춚jfZSH8p"˱jxrNU>qItB~ِUR+YDo|P0 AzXN[˟%E=lBe5"+~GQ6)[#kql `Yv~,|DjHu_zPf,r)EPɰ1'ӣ p|2fkI>s^75/.wXAj" Y#(ĩ貂6e}ǿ'1\YE1[%QvROK[y%œp$P$K_4'8&Y @/W}bv pߌU1*ↆQDPmePXVE .P" '-9vIO.!]ۮs6DAK(R*IzR!5pJNUUCfu(B36M8ZjY@'&ʀ4PzT9tv2  [si oy{PCGO>V>ۛ8APa) \]u?|3oYNUTH+3cٹvnJ1<yU޳Aj> 7FJ*JYm4=q`{7 集'DnGV4u 0f~ŽkUy:: hUu%MP&NĦ \z9fõ P?ZYUMM HaDF'U&=1<|PW@~̗OACEeS,]8b@6!>= 3Eyi#DOO]Lrl6,x >MGA k ,*Fat@ssr裉hREj +@xǜsbm펌R!PR0fMR>Yd+GҐ4dܩ<~;adƉʠ*5{]R x?{0|$K9gcq{_9U[jQn Ŗ"*eQFzٓy?a-je jIKBҔe 5M0]x̹o*䑣@Ŗݻӕ)\lMetLZHRXX>x)HwH]p;U] $M;MoÆ1.wЫL.sMaCj37R51(i ? 9sNetdtkzwzث1Y ݇y$ 8ލ&|K{|kYFkUmKVi*WI x*m\fTYx1دvۄl|{"@*$5kX}[x~ޖ÷ћ^Fs p,$+&{O<~qV` p?/1R7LN'Ӓ׍Q'3,Fmإv1N jRuHvc\n{ێ09D&n/+,SI䨯7 `xob_p&@$||]9(LX vહtm^LGr?|1ғ5eaj̐BA* "HTc? Ű.ܵb:)_♈!^pzehδjJ}5HVONH+t䨞fPIU,lbnM3Q/{IOF=ZQh&:.81ک>)YGraw"C8ʯp';¢~> ATf87?,0kAOH0ba-s-k2:4pW5v?mLp gkLx W|*xEMTnMsql3qt&'ꀡY'/ܮĿ~ e\2YrP*!Q0cUOC2&;DCě {ؾ9ű1{Ls>ufw3+,j 3YNB#Y5#z_ y5|䔧f[; cɫpX{&)z2~n2Jj//e3=R$3"\F>)%f# <ǯ f+槆h8%[pH'sműN!cpt&$ԯg N{zβ`y/<7Zu:1_7)s Ş$hɴt4cpu\'8W-0zTPG1"E >uW\5C^[,}TYY婙WYڝ'k:O 6GV"GI|V'G5FGk>âʥs(=bōQ U*WCF4{[n{%IU50OӖѯ獐)b.8#Y("Q娍&+H#q Y2dʌAbr_= ̟-C3uM+R *ZJL!A!ջNjU0HvAihfI!HiUBʢ-YE7^Մǒ`ʏ1'Ynbq*8Kb)Jw(]o{bXT0s6}/n7y!z䪪^Y.̨3$ c r{X`L Och DGҒM_wX76-7)ub*%`SKm7nb97UZ>8Iu vD`;q(&U$Gܰ" ]*jih&4)$ !CV=}!-uk!6̦Mӻ@j؋X67") v˩HM 2ݮ-en7 u "4Urt9u@0*QIxSqÑc`y;]QeW0UBbͰSBk?["P7I^ `&xXy0NjZ\FbIl^x_&)[r**YמjŽl|sMWy ?oUՁjv"G4}F{OULE~7fᔨRB)ߟkv [KFa[+DH7^91uJ=gC~ف⸅~ tu'@<|W?hat;k!?#0]&w nq.vt$KڡVC^gZ<X3|ꮭB:3(e/$ۺigBB K!E]!5U&-,*ǿh"{Z8W"]_T|N 5Şsu (1>޾D*cG[JʳݗX{v8V8>s5Ps:cNV™m5M RXE\GiXͲɩ]̀-Uf۶`JdJKNYt ~\cJpn=BSN$( `@5R_dCݹ8 B)|W+Ҽ(mB~*\$Qv7c{m#QĈLז*mR Nlāq^]!QU T:mQYhURf(#.A>s&eUZs'M$,nIӎ8fgF)OTGuV$m<4X!phlتZE:eX {m0I%`VfOwY~-#q&ֱ{p!*?nW8 ne Z3W"}9~qN[ WY]$`"űR$t&\ S]XU%Br/{b;ͪدnf$]b3fGp ׼Jl-_:(t➓0XK:f ݅hs m\VT5$tUGSKh!DNmT.}EҩJK[/r+SE;n(Srr /Tq)i2YE͏Ƕ)ӟ8DOn[% 2r"1Kwr/(b!sql4}A6>V #YfM)B,n" TAa$^Ƌa+#[\Üuĵ -e~E GRJoU_mRꭓ+_AxqkqNZH Ƨ]5j8lӦN X{5$l?M|<$W@@1s3Sik4NCl]3()j 5[Ƽ=?<"Ե}¨m (`=HVm\v-. h'Qit$eQ++UX~q.1i  ښ/ 3oGAKMıKT{Xx?||;f/f004BsOFuQ)LPHݔ폱8}7"𵱯fͿ|%eVLq(`Af6b↥<(ҥR [^qkGC2: <*SHE͘Y8E3i*hUF 3D. os|q*Zʿj{_Gxˤuw8 [WJzyNrH%jGWF*Dt1^֥V{#Ry7iG7ĿG/Y6i2єս`8fܪnT*>G r'W/ˮs:Xeq.)ŰH y|7/m _kM6:W]7ґl,Ay\]V".kSU4hӠ'+k()dݐz&tZZ-rqd)+cV\_`'r/ȷ|vp`0cLO el7bK <_??Qn MW\jj\+QeIY,t$EOP {5@hdӳ1}eL۸R-ͮ1"`{W$ZJ_1KV݂ۃ~w_ 3UP59X$~bp.nv@$|u@ O.v 7;Y5;~^8ẓX][1V) U'KI6qDhySvV7@>6n={qHFLyf,'1: E ]`bsc_ IRK3Cu*`M9LI2QKRX(@J1JsLDER+,6ݸ6\3Kd*zDv>-N~Y#d =›a+P  ʙ9r8@6N*#y?sז3iC\5c9lWВQRC% l[q4()I>_9nxnq顡= <&0߹'}0 $u.[͘EGU%Jm+k61^m5uD6>]Hš o9o=bl1虬_F \9ͫN#)MDKArlbS_0 Ywi?'^~pk H^M 5Riiu^Z+,vo{h|$#؛018 ;3 G,dfo(\3ZwMXv&Mɿ'TN@̟zO4iQmU{(Ā-id6#ɿ9H`B;8 =B s6HaŇ78Ie9.uT9ld4!~(3Y "jz)e{X66$`H"ǽ3`j* mPL&)kY;k0ײ-smZmh$JMDZx5mfca؛M٢BusAG$EbsHs*Cʐ ߋz>yMڝ!/,`,j+mR;ݏ< l8i !v$Fq5nV{6^k`Gs Ť2F|W6̤s]/->[PU%,FRGacv+ʈh'C{U'qc|s8MM+J9뮆-JLڊ~a%B@^=5x xbM<:CE'|1&JgaY֪uӜnن7=hT1lkZQd)`y.oO~׷@;fJjYhlTSV )sP-OS+򚘫1ZL"8ap/s ڵ!`ZDQ2V&֝ق("$hAJ.`D!dFyR4d Zۀ7鍖P }`$I* X'}ަޝ\;ił0L/97o)# 3 3W%EjI voLq.!wXj%/@^tERlmA{|v7sۆI>*v44$4oRK0%G bmpxv: ]d>x`,JԂ]lC/؎'p9@̼G9tU1:Ip[MnH^I[5*NK@ũxQǸB۴z:!? ѕS^Eō<Tjxh0Xծy6Y qn@̳jؐtSLDdO5 pIœcpw&uW4R&&FrA@EqJԉ *hVu[ڨبuޫzmxSc-FJXVO!2~Y )_ ]vS~o04ѯ?M$*"iZzs!iT<+0bx1^H  dm &t}zPQRƆ}ٺAR܋ lx8WZK`4C^P+!zNVE]n.H>Fsֵd5z{3xFefrVMOXK\4lVQn$RCpA-'66ԧ pu鼴 ݨ8k] $[ZDf.I`{NI,) H5ph,YQdg;rnTɵ' ֹ$iZQU9T 70sSg5uEDR*rMg4+oOT˖iOoy'%Q%Ĉ?01d&]URr cvFrf^ɿ|~{<#5$&5< _֡iW+hu]UEE|FiXLi2&r_h.SJjQ51l~+U79>;d$f* lZsav"cW5\ݙ--<~٭R/^ߋ\K #̪"s֜1Axan ~ CIoR)d$fѶ!ᘊTp\lQsg&Xj8sMъvsJ!AmPs }(Qya|0mGX,nQWkX x1aS^^*O(7&7:_9\UNS?Qo(<)Ņor88BW=OYQ$ I$&)@T769X>URFQ+yf9+OWI׶g9sSmhLĔD,nb,i&"gS#qvԉ[ zr53ؤ$OGU$NdxG~p4LHeX ߱[U*,u)۶5@9ny@ t8ryLS5٢ic&YT+"$pͮ$Lehw(Fu o^xE]Xfz7"qAC(iڲ}5>+J3a]ԳTޒOn/ NÐ*4S&DFTgl5^Bnn snE IK$Ȃg$k$`6|p9V*eP~ǹ9d KB|alLLBj@TS4t qYڷ{Xo7@ASYU[TI18, '$Wʓ1̫XKQ# ="j7{UuwzG(%P˓UAE={_.6%E)S8܁iV!. !&Mq iʲ|UH6&xA*ZQP ]F>X lM8 vONfNbUzF4~d1{'Nb3ϧDg mFQCso8 \\&&nkj,&MlT;lVRJ 2 Cal:KI|a, nmZtT)TGa l?H!0!' ;QB:wG>{\!ly\5ʂ$ ^SDW^nGnq'HWc26*E.wa$t 1-bW.'{ez-cLՏBRJx"B^AŜ=U؀G[-vrlқ$z+/yNUr xy bG ifk8 VkI0'js)Ӥ$5?%:"jo|SSgSJ.Yt)p4M10Aq?⧌?s[.|(^: =ԕsTU1瘻!?S@jK\V';aǚa֡cx^/ϹtӢ_OQ2R@lVn^}|+ rn|IfYDvQ0wlޞ jw0Z_G=~mNAA2@>Z؍Z-hHi `I#9K6Y 6A&g,NfB+ybYĦ*J춦JQvʍ{;` tgF8ǑZQIH`n`-o|l\#au܇2Ψ(%+BQ%5:" X Yɿ$h@ϙ^Qt>OSe9"?Lě(UUɽ$n}}'h2L^#`7[ŽأA&8,+㖛;}v͗Pi*Ǫ \A fZUm_Hznݱ\f_Hiρa׀Jgw%x߽`+vݖꌎp j:8J sW<@tΧ,ҒLi7#ӆ@O;_1-ucԻZۮ\EJUL_ג .Һ= <)SXb89kT-q\1̩7yR"m@'F.$hC=ҩrXhYHJ*%)TaS.wNp,ozT:fh"nt zRC@`XUV|(ֵaޭVY~]vPDKaWS 7Qkv.N=)tm^:*WgSRG̅.ϛ djd }nK8GY u,mz}\lWx,u1r疢0y6,jdm Iswikd*ԡecr@8;Hw'laLͦ5:=ȲIWGK6YW,99L2"Pċb.JFڶH" ySsi Oʂy17. /pGÜ\s\yMfgsf]55e+OET&VمӷױiUZWQ{4ʹ%C&E%Og{^% [U3R)ZHI?q}/V4ie^K#poސcF;#.vǝ[Vܴ/zouB|*x]v̠Fd鴀[v@$ĎǍ㘼CeW@wbOeglH(Ec\Cs0۪^*2H6]INiXO$rGpkSl.zsVgq|CVBHu$cmySZ?]>)šͧt΅h#bVhk;n8C{b3EGTlᲁv6@e%ǮÚ~{R|_x,šmkԙ)j.#:dC#<[05"oB5ӝד&yl3ᶼL'ue?9xͩ7r:Uzyb rY"큆]> ܎t՟^+s7npGŗp؃Ŀ;VUި9K_ʤ3apq5L9{yl7_3Cb/#=7涩Y6fF f#hN KKP0 'XvJ\M[ST+kHej`DL PI}KN;[ l$^MZ5ܯ:BR/}oGFBzŨQ+֚j5U@07%t-#b;]@vt E3mbju6ToCWe^.{~:P,2րۦ$oQ,ǎ|:VMpizi z9; Ua] G ԵJV4R *{' \Ʒ13MW.J'NT1b(߰^pZ+LG)$$UNŗ;gTp6 4QޱdH=n =C`1[s`la,.AcE$PKU08 kp?\ZJ%9DE6H";Б#\p,|v7[NL{Q31Ecܛr1^PY$Lq{m =~c)6s/Kj<JJVXԭ`E|LejyFͧt1꺑LȺi˔V*OTEF,A0!x($5RDy~j2̞ZVN(ϫ}yP/bHK"2JĂA8.(:peuQGJbxWeRfY۔nF9)s2'\lRyQU3ryE"݅otrE[(QE;zP@kyqBv 4j!Gضn\O6 M0'?z*K[OӗQ*=8n=6 mCRmVU4-H |Uڵ.pEPlH@cI6ϸ|)-N )`BG\xԀ AL-<,cm?E-7}#g9=ИTS$TAxP!z,r0 ŀ} q0n&(7 _x8Pqi>/_ s0e\X8ς}9TU2thӔRܑ^ 9l4CTZy 1hB\sf]uSs녶SRVR Ve[\H7 z㖨-i [Bxs'\p${v@ /1UZ/Q_WLޜ}1c J5V˳. V-V?d[ᙌģD?uF3K/|_x_5 שYn! A dZ%^}Irn܎GT,0D@?%UUgϐ6zM BPUyV# Xw_ܛ zݦլP_]"!im h9ejW7Dʔ›1/bnA i2 +y]t$U]UcHa~A(z4](nqߌHWsB }GZ^lZiRpQPU kjڪzdm~~zT5UQEC0Y]6r 7`vnBI7(Կ,"'E%5.fmJB6a$؋XeΔKdʼGTILUbİ$\\6 bYWC)s]fj(ꞌ J DC\YxZN%F$L$3BkMk 3OSxRƪeIsAc:eUŧqQrQK$e,Sez7͏ ] NaG;}۵,D{nVЬ:Xɷs3d͝ӐwG6puP̝q0USD*ںi7ݯrqZiR)ֽ oψt햽^j*䤩Q"xfW8H~:~f 1Vv܎ f} -.uES+,Ӳ(Qw;\qTePu+hs㥢IbG7tXzsn}18 VahqlM_n鿞zwM+n2[{綸a{r׌CEI1K(Ҩ׽ǭvM}"7MC,6`)J0}B8 ܍-=F=a'53y3`5-2bnfn::HZa~6sHI4>c"_WN:YZЏ +$F[<IU z[lX jU8ri]NЬvL`ܐTh$܍ttΖZHJM`)ʪH,̅\y)?K ylUA-2.+Icj:4zƫzi#Iٗbۧ,F-?ʡUG!WWiQFLȽ3D#Z8b&`sa9$T6Mۢ-P VI.IVcaBhdRG0QlHB7'U\UT<ȭ49a Ƕ@Au}J bBjҊ\+͏Ө !j쿲so}+ G%fi'X^:jh{*4D!}' ğ*!wDI_ֺ"ѾVRx&ҚGJ+E@Ul5S%D2w3)4^`_c^?lf4>yL3J?WzA|9Y!D3@Bdg{4j q|y\n3yw幅ۉ1O AxPG$f=Z(iRR0*f)*. 3ðjxC q iHq3_P& $/,ĪO^ՕTtD[9jMP4G#7\fӨaU"Jc8R/RW `u4u=w{-Ǧ:؟%(g /pN?~|3ӿ/Q|5,4:(:4^SWMaͥQ\wckp M>"y 9DKxj|g F˩n934љ~t}dt'RDr`@ z#UNa7 h$`;nGUl;1nþMzE]js54еe@b`E%.@ rBTv(O5^[ZNihy .%R \VnPuv#e:$`2dn"`:0*zbfpesQHhwj՟,qu7HOf;DyWnAJ]03 g\$d+pͩL r׀ RdZ,AM;$yW\5J KHhFAG3#nn 5g?}z)%VRDK[|3"HZpsJzx].&x[<uRsdi(u&4ʥ̲ڞRVۣmxx-L]h6 ߘR{j|LSf[i}w3H <m&14@4򼺥*y6+鶨L$.Iͬ<`noߛ.IHfl=ԛ>`Jf\ a*#rX$^X rPI<և8&i&Rgu B)7$eJs=vOJ2 om"a7> PeYYZFΡE'>ߏO%eLd=Q("wZ% -Q`xR/l@nq;S)h"EB5J ,W7`odMNz!ԓncKIS- TU}X IJW`M\@fq4nqjM {X-m$7ٲN"4}l-^-n 0v[씶T3D=8220G\q~zc2L2Bcxe'[L@m&l`ZcҨd q8NKI@]ZXe,m 9UۮP꯲ Sr40Dxvv9+ u.bR2()(E?{|2J/+x뜎,ʠO7Ў-%zoW̚(*xK~x>h^-2ԞY#u*[p$\߷Ǫ բQi5KcyËm2%s6ēņR%T&Cv$ߟ\B$NxbQa`Iq B0TYƨ㒞I8϶R) I2J֪JYZ`fϩkJ.yLJՙ4DB2O6`TI}:TK])ĬK(*6Rϡ Ap˕T,rD-] +|6kaIzzɳ%Y#מ\@y Uom!_g O5~5A4q2}Ix[|x W=v1 :y.'¿*ZX)u4j|m0cױ80c p?ᘆ>mG$2tZ%xXQň=hXYK$Yߟn;8uʣ5մ +hV>Z8IZ\jECUZX4, ce[𩸳qa'`-UJq\K/6~6Ts\ JN\,Z9iYaI`fMOW*q^.@=[ vV0KI<[CLET^ņ)#\@ MڷHHk76J}Y Ṁz0BRy-T5]$, ^ݸk:JJ'Fty6)=j1MϺէ95@Ks!Bl9}9<:z4)7I1.洃 735 t4O7Ia6^툒 gz}Ͻ9%D$JbHKu~?U!7 UELw;d,ǀ/{rykxĿq ZS+@S{[qI[n%I'uG.̷(XbEAͻX:Bs9yAǥ/<EzFKL%4L /oќ*}un}[i5-4lfJyۆcfZuOU*9@p QL{G{"#?F'6gJu#GǸ߶$q9Ua!2i+) *bu%s ÓZSiSZgIUMWK<Yi^Cs97cs[[q]K@ ~iJc"GU*%e T*Iqw-.VWFSt(;y$/mAc#%cݗj2dl <@,iTm>Ҡ2YyfPHcе҉Z>4܋sk/>G*+͡Wԟ ,|)t}:?^rjIKyb,Ѓruewn!8 H8Z]9ip)hv ;\?>e2Nx#rZk1BYIWsX?pʼG)6M n-KnTv~69qjִ##<Y9^(!2i7σ86T ˎR0 ~1cIM04f\L_-_Cηc]e!<\8˘,B,C[!G }3CP4k 3 _)? U-G5N֋nG~(So,TF\A 9,m !F`W%4!8#bj !t?٧K|ՙ(:*4p%uQyGAN8~,൸+R2N@~Yq?wCk+oe:73Y20j\\R#FT*wlk\|/ˈ8uNô9 Htme|?nƳr"N YZ?6YŶ4٦V>ʹ8"1:ηP{Qȸ "vʦZwiM\*uhHCfƒ?>cUFc4c (5\i2'8jDAפ yW6Ƿw"N]c`v$D]|HmcH.Ot^6[uY 5[A5I:02^ӳTw e"'Ң-qEu2|*? qj朹@Ի;qxꝪ\4٦ e.iL)nB̄V|UR!豷p$cAx/!Q=w:Dz*Z=hRb u܂A<>Q}jͰ5$ nE_3,'R}$lnbC1a{cL]6SUʸ]X [{r6<`nIQ6 Ɲ.m K2G 0Ò֏~-wUrKQK8 Bz_G½ oZ4=좙NԵ_4†(hT*Y3r|I_<[udfPDVr{|<kHB-*;~bK tB}k"܂xzX`H{S-w{ Pah>_ If=frO7_|:j [gkyoK}p#rQ)H&RpMw7!J+5Ѷq5?{H8Ƥ*h#/ȻJ8b E M0n PϾviMQ &#p}հeFT*ʥvB jIR22X.}=p*ʦ^Rd~X'*SMu0dU3,6';[ktK$ܺbݧLak*8`~=IU%uG0/t=9ϲtKVarUwM۸_ln,;4\SwJTBm$^v@wD`JY&uL#]6 z ' k^F#7ͫ?8ĐtG.X:)o$qFGIZ>I 2 w|Q>HTiAUMN@ ݣr>{&sY2l.-Mdf9abySkpys^34: [co QBje+[V%.csY%ZgpP\vz}qFDZk|hRT /嵅bo~1)O0̒:Pk"IՉ `8S؏P/sP+m|k'ce'.XGn9ڑƅ9';2fCC[&tEIٱw[k݂ E7fmK 6`ZyXEWHfCpWЛbNd<79>@e%^a4tZ3}VS6{S9ޚΛO,7T"BX{}\b1l4;æED CQw>kcT8liSVe6o==-d&!gH8 =?esb-c57 rNiK2[ܖ o#q?4`yOUh]ocH&,Q[M}K>0MsTU.+ZԾ%kS eusJ iJ0Teͻ㦞6q?|*C衅㚚5SՉ\Ynepht&An %oW<~%=L]6R $ȹ';YEgI!VT ca,P 1 a"\^a5N:$5VGD94R >'y}AQ**(rC,YX1¬M, 9/pUV &@@$ p ^{ &ANgTQ,U˙VۨPOM{9@4 uxj bnj\Kb|ZzځNM84ĺJ W 򛣫 myը &@jjU/Drl !b]ϗuVd-o5)8֡1hJ.n,I_^l1UZ ±\PzXw5 wp| MRo v'ye4&]#42.Ogk}ɉŶ C Z.қZ֒.k@d9bNhz\jh #,\^SúmR;#i em0e;LVJN'zjT!b!dٔn<<_PD0 | <҇3hSWVKDvjpX=9qx?kWt4G]HNbTͦ4<9+_OOU4EV2xw'hxc W.R;FS,Dl |3je_ՙ ]sJ~ Aj3(R/ee3ZHʧBkS&x2gM&OU3_~YGyyƑ*:#;Կ)  I3+{hbL鿗%Gpl3f@&;ل\/|%R"u)"1vnÌ}HU#f6ReTBG =w.;n}1PIZd)ym8Kr-ؽͭ~mu :@Opd 'LB VqbHN2gQ`2 %RnX:cc4AIꌶ<<ͩr:Q+I9|8)wH)젒GOg crn|N kp 萰ej!2GD:#jC 9cH!-$:aFHj35[[_Msasodw DX8_w+@U#3*RD[ooo$dvT+CQ2u/PpIޘfE:de(@y~q .tŮJĴRH#(VJṋkO{vlN0 6d:exW%hk$"QȲ#r$#ߑl:IN#t1Xdedp!ye{hy.M*DNدN_E -"`6cɰ8 Д9SR{ ߮ SsCJzXY#,V"؂P;fSaU2O'Rd.{*30mՍ>a n7HȌ7W2f–FrDXLyJ.C\0UsdX5|$[)a1@gSo'tgoŽqTk\ Bf9`65 8ʻf!-3[8PoOWU1{j%;M؃\e"b7![qmõŬN91($SS,C$!_2_PRfVm崹t5o,y]U⣈Kn%M|@Lktã(I4R9=Q&qv7U-K|y?TQU!>ux奭 De=q *-~s!._r.αRB^l\a}){RZci.&%R@ Y8 yƧAnQ5G.ϿwU|ν0"]Ůl>w#֎K<, ]>d;le%; . \q]9E7[ z-? QyH*¨H*ʪԝM#veT+ c$jKqrtLz0F3cCkuL[kuV5J鋬 rI<U|n ?v_> 1i>>JMj It=`a` -sf(>:Z"IECp.GPt\@UU+*A҂v:Q$Xϖn _QqzstQwSH7*c OUZ)[2N=Ac-Q{,uqeņvA]Tgt˗UŚq4R/BFA P[/P,N@mBCtU;6:ǏU5)&3 ][aYFd6"JlA co/ 0|90u螚K}%LFb@ ,p?L~wW{}0vh2H <" ZVL_9|^ZOQb{㰶>p1r {1:e``? ԙ:TL6-4t0JAI$#*@D.D<4|4gy]~ړ|sY[P;99_2bgV}吪{& XP^{q y-A4@ cɿf!XЁc_UMgZdQy2>'WcN\n*AF81;vȗx\cRRէH8$lL Ϟs YQh$d*HTIu%~lWp]RGJElI(g3N"I?Jl1Hk5WsLGLY\YS52 ʟ5V_%Bs-u@<«>G3Jr# $&ܜSi1WAacܻlm ti.vXZZ\ *;&w FL%"RxbH;l׸_kq{ pL&lB4nYtTlL\ lOb8@ij+˘,U&@ugdUwJbʬ :~BEk{p{ }<\W̡j@z5II$cL cJ065_.\?%CđI!J^6rq.yq] {15IO:8_QftK3<̫2~]RDL^^%^7\aP犠X4fZً$,A~-ۅ@P5bI F$nVu X|4PehĒ|G|sS;cMyj7 &q]d #Ikؾ`Jeo놐ƤZE}(1(Tmp9ƐY%0PD˴a`H*1"T*BT ^s%CctBnRBq`82W+IX(X5ϰ2 ECo!P墱s`mqpb(^0Ap[n4`LV J`8aߐ=@~܀{TfH*d(Ѥipa ?/ܞ}O7zc f`{`XUHF@V$0VK\yokB+( bR\󹛐k5)x߯쥛Dz.`6p,/lI.qEt$f4ye4Efnnob Xkgw(3{ T9䵿r~(lS0X)m͏xSZAӻܱq,OD›qs ?> $HLeҙv6-g *2g/y 4<|DXwPM2%(i*UO'e=Epi繿b@L{B(ɬFd)E f;I1J?uBiҔW4NHRAK0V!& ` nWs,$ {\{v,E`yVj?,<}x/-t&Vp;E,`![ܞ;HXLb-A9+sfBT)`(avnkKWc&JK1]G<'ʨaOW?*ulϧk÷l!bZsWBMc߮%Mf#Ua`p[nfDBVy$Qupx8%#E@|ԩv%I!A+kn2gDxxbUIrçb/eb*RE2YYQ B><^bHJsG5Iysi)eSiJ6S $\놛*8%"3hPu]@-ŮU*͘aQsT=$Zj-|I$+*7``$+O 1`P lNPlV=~Tvy$Ys.ՒDn/RC _'t+f˴nG3 Ši.YSF`RH˸{U5{E疶V)wgo-uZmVAMC*B,#E#|ܒ/w&ۉ,lP.]\*Φzr5Fӊ%DV6(Q`8c ;L#0ɽ]Z*1u^5%3v}{UN3uPn`@3IIH盒>Ro -!@9}FJVQiBM^Iv Dh$~jjؘ Oop+iuѤ{d.zf7oǽċ꜐ztγj|,UԄ Xֽ{.VkD Ju7^5Q,O\88|ovCs-ծ '!cS3^%!۰[rSc T$RȢ&.Jr,T}D$Xhx&yv`K "rbV#H$GAiYA,wt DKr{ε#Y>Q>GR&ME%*e")wjd3H7mV6ڊRts$M$<>u˘>*tYbcTݍؒ@3-,*ltG(7W#X^$p4\fh#ɡhf)3*l،AiP uLi[sQ6?o4r~}x_Y^OE8ls(be1|A ]ŀF,v8<ӗ)w?]~[/暴\ tKf@:{܅HӒI roQtDX(ê>nN:͆`,iKLwj(876a"#DܢD s_CúsL" wTr氈س盋Gw^`D, I]jh4d04 I+WE 7(-Z=~INdg5d5s-DLA\y s=h~qG4E9" "M`|}jxpU@hsA洹e%2M%HF$p>"$5ۘ _,Cmޠ~=Iٝ5:jT^*HfbMPMon}/)U] `YH${ԒUwf*8IJO藚(VYVv2 dF!v7Fz[Cl+eW1T` 9uu|–Z> ĎV1ZD҃GWQt ML}.תԩeVv."uL9sD؏>^PQb 7vǖ6ⳗMdist$dPǹ~{qߞ}1[TT^Nk3&PżBAKmMFǛwkM-<&ꦻ\I,0ע@U.8RShS ]vS~3ձE1E&^Av;A= ^kFa!) ,UI#w-e `~RrJ*u~R{ $~Lcs\\!.;n޶'[>wY^^sa{z-4{6DIs ˆ,FkhVb*X)$U y87T, kD'Aۋj# V.@%3Z` Z}v+MC]Sޙ:wbD.A<~OERD*0Zv|BQȒWہ (m@'w76er}|$A{yd*IRm*rmWXb)I,lCn'')tVpւYVk,G1JYYOY} 6L9R -1u6 m$*{r~paE㨪+ `qo3p}S}#TNwʅN,? }X!xH9wpT 0 y'Ry b8G:&AX@<ޞ{"JuU0g`長{p'ߪb.*i1,E6ثr8#퉛 Kŝ@8F&pW 汷6?ˌYf+2jEɴؓlJ^H)YAE;;oYZ{p.}ԋa L%SUgPęmfpD5:3Yg?k|uVjF7BY`M'<ߎ^ZAV[ccl켁Y4ZBc!h K_a{ !+eaۢj!^˵ly^ 3NՌ1tlm |) {SӼ]=SWӴU$rRG;K9]Tm̭̊uA!v^ZnA "SgiiޖEvJ{0 w ;Hkw͂:iCK;C7+&w J'c@UZwY>ZYdJc"] ^b.M.U ЫֺLʺZ$pĒvnާj$/'&p!InUG@n^[O\!$h錝Y6_e۰`a ЬTjYk2)]<2S-2B0T1ksab]y *40-~`:HZ:/SLrS'v$d;`A+ _N$ѫgP0܉:n[x{hA$~U"f󭀳7/,plܡatc\UR6v$Q~V (-%1mvn }?Ov`:"̢rw"`e *̤ ] NR´aX(l+i$Mߩ>LV)rVM+MCM<疚YAoU`B ʃlK4uw8=]35TuQHc֤aYh#c&}<)CyXb$`Mw A ŭuH*&.JD !dci܀7Imkn q4]ll#F1V23˱I+Ÿ$3\؅.2'%me+[]Vk%6X*ieXF\6Eٙl\ɋm 6d SMnrğ4Ղ7:Z|+J\|0.D[uq"5?mۡ I=,cS-VYӾdt1sdJjrdy!2 #E_i6<ð(baO %lSTlUƂ-$fmċ"ҩ.65[4Vo[WWRJd#hd*Lcif_"Qu\eQϘf94u5TxWm+r[i! -C 7F-CWT× h(TAH{M#@2J u3(ʪH{}Ÿ9iIWJ%dر#ɸ;c8.!t&*6Y7}/^* ;ֲEs :,4ѵ͇cBOXT^%pqAFDtA ^i(FoRfYn[e̲I c,)۳)``@%nĈmGDqm깉׮V5~CK=5$k&cQ j]i#zj@ߵae$LOD3>,[US>5yY-̫RjVa%#T}&Ul8HƇ(n@`ǘ?5IgMSMNUT'H#jdA舃H7^d{ךBRYltR3UQNwG(@#L೫%ʮrJiF((j*:FzFirBU5ἤ-rQTl>_-*4)T/'ToX$"eW$Sɱ8HNrdm%s}5j,i(*zTc*0agqFxeK*6h>@\ߥL9 ne啉Q(Rdtܸ+KRE]ύ=6}|vVF)h9"O!j ."a#ޣPeʪ9O+MC2qC8 )$i^q@,nYC) AEwC UVm`mi`M(ur4)c̀-a&l :"1 FʁNtǖ6n-~ !U<*sW幹sI)AJlҴ.:al6[iB"VGi2ʥq x#!%HÁ ˪_6zzyZjX(]Hڬ0'?|PLL8.Sh(&lxVhAfP$1( 1* ۯY3 sJyC2V4s1WD7q -cn1nD´sd"uI(/"ZPBeWqRR×R4'"Rn[)$Nmqae8$8S!m͹ [7`Ǿ?qJL'D~,Wdž}a![i8&jZXRiT_iRn-Xr;-B`*ei+HL2P!N)|šC"FQm.nnHOk{ ImҘ2 0%ex *mcӱ󝔯7MTYKHkot: ñ6S*GAI%.`XIn[p;䓮˥XR]`$B_HK)Iɷ| we6WH'0rǎl6\+ if2i^#cL7#q{~EFaoO[Q=DIYU+/(.Ğ,{0s@-Nt 6Y%݅pdpBc2]}YK&ah|N&G񗵟g} nu'}'@6?/;]Mt6WGAKM32U| yB ps {Z3i3i+CDx\2@OEO= ,3*qT`,yaj ž1+e74ƪ rO۵LEG553R-N_ ΘQǖv@RJ"",%e&,Q{c[ LGגjw7-'ۡ9j(Jb+V5Kv F#,3JO崑AHS@c1y;;w'Q*qMI2f䜞_NTΩSV!!BB$a(j,!s S/ʖVP2=p#Uc"p|<$ YTOJ;yK:H3 ɱȷ0NguY#"hC(#[z  qe,f)ޱ%x՛zRx7j :xGFhhlZ :Hޠr"[ ]t24WH!gG%ݛrY,977J#""*86~67Mق:j|.3’P4b=PZ2Iǵݹ9sZHXӘIQՖ1#4*3 ͸&{w yõ몐XݩwHUkXx?e"|R)$I$l.9ckstSe)d%$zv;H .GcĜFRUOp 16T.Dsr# ~×MIjS<v \}NMeXROB,K(ܡJFV*",=-V1)**h4JO^ 7(P$mǴ*IkȸRk,i6X9 n% gC2HM} c{$qrn-kcge?4qE;V̓#F Y@aQk "ny^YYf[X,.yvHlL+qw# O u>,`@LIG*H<;.,wӔpkq7x{yyhs:z$)Ģz!"m&\hT:%K+ Xm!}M}l=𮾩%k"TkT&*+cػf)lnN޸@^לGZJ?"fT{nnlx<}̵r.iiIW-4q2Ԥe\p63Mc@``Hr2:ArkՙK /TFc"8"+9'ar[?qnEt7 e\AFYi@U'AaQ{pHsdhw˚B$>0, Jh&Ze57 ۟B[jDh3rd;4i\7sL:ȡLrڈiey"s H@Vu \e$C q qh ['8J.sA(M5 nTo]P^6.1+ _Z\Q.+]/Yi[m!ѥLb ZYcDʴKP$ `hElC8>nvnQwQLкY {!YrJej\ 閞Bv }V*ָ9]7zVG),rNŅŘm$[M&z{b:vb`|[p?}| |UT@+-aMlyEUqb{{不UjA#ҭ;X60 "6Ǽ"W CO4ŘH mc+n{ ^&WExyz|{AIX1'c~+QXi@߇pjULO㗎|x-lΘK4/E!6E4['ԩ66ZLn4$|BsQC -9^w>Q2"BBlM[ɷ׏>dṠkEQL򊝻bue*YH};D{;}'6ߊv ) 3 C{z}3a?%kH""uu =u7bc%T]ng(ẏb]K aq冠8]FlH%wPD-]W HeSO]ANUQT*9_Y+rGYn<)Y 0d]vaer.)BI"b (צ !reZQ3m, 2?'yH֠Wo4;f*;^ޤY(ngiCMC#GKU&)K1j`Tl_*&t\HjRэŘHKmAw;`!ǞQJWPdU VCoҘECSnco&\%7Cu#v $2Ej2j %eI ]GNǹT{DRj 9SDD=8ʃ ԜnPMU)V@ߟCE5eB *)/"lX Qz[ $o ٽmD]Ɉ̚M3^ĭ[?.a*!WD& m܀ +rUx-zj0+8jmwvo-` 㫖q] <MIV V*`uJȑ /‚oߓM +i:OI6YxawRiZ`FEæt#iAnM7:sH 2,pؼV6<[I#oNS!Fm^k~4jUIcwߧ.H4ҽdn(M,>EuUP­#ĞP?bmؒz_q魵C!hI«pC+:o '1;_O/T h%$s:o̩fF[Q,M=JY nM=v6a $/V$S@MT;h&n1dUe3-DTnovrG$kc._3AdmV+yHnoo鉹-$(fuaQ.aVK4RjKm%ʡ{Bn[$ԤHi }f6 +m,!m~kWvw¸ΝMfOiLRRqŔTiNco/;[`|KO=y}>֠OU3 { 7-_[@ŠjQjeyHR $876.KB8K$r*E?{~o:kePDŐ2BKx46K&x|~CJNxFD/ R23AqZ3z)h2z|(;-'>(fsI,"sIm RfJ2R̜~=rnOΨAJ+r$.&A7[r@iIgV-1z|)AȔaYZii&9-U#9fmؒŚ'ž,XY5IMTѝesd,GM,Pmrەb爻,9AO»}Cj.yCn!Ezr1QR,e'Adւ+r u ;4 .;bA|]ƻP|2. e{MAfTc(Jג =cqp6،_ EaI8߸V>(lCf3>E_sZe`iUYe 骋(#*8rh˩OSÿd5>shTgU0eh<2ZgVeZu`rIg;6 |3A2g3\ex_3O9٧OvvWV(-a\3$'H+ot$ G~1I,ukVOԒ9ly*zB SyQO sj@ s^"TON7Bg "^-mD/3A^uk)27m-qXIPM7ۏkZ)fS^ϪٖURh}GQ |$HyU*<G:vRK|-WR^r9foAk)vJ͙DL`472-=7q?"f0 yYw=-Cś95t\@YTf_c<ڦnf K]ɚT Nc%\_8Pxq 2=DyHnlfb; ߷Y]7F:Xqۗ,Yjff!UAīU(6s %=+m:bI>t Dy>RxUԵywȤifY*t;4!f){.;qc[C{Hpi` tyXo`põ.a&I<4m"[6C$%B*Sp`Mێע?zQB?kgPx-[YGYO6CU+t;K\ÿ||'įk G}af[~eOP!]=@Tzv`q|22pۈ%/'c~/KM&JмjpH(!Cֱ'Pq{ޫ ʫhb0@w1{Τy>]OI 8*-|a%3hZ+'Jc4Irr/qw,dEBXm`'na&])2rPrS{1':J` YXß$ӀVnUM۲ _F5r?6t3MMg1]^WO/Л1bx:r\8::o~p+6J7?qǰo8efx>(,32E=CY?oJD0c c]I UIJi MR 1lOX_C0|+nZ\HW(ey'ha $kb0efX&Q*(RHyښTc盐88xp "FRzO*A; 1,y~k*V:۟]buf-v/avfW;@Rz)(LRəCRgVj{0Op8wPS?shSaad9-MyBGF8@=6i$ME,KT)b퉇nabTj$qnoӱ}"ޘ$%p ZmDC0y:p~o@0% .}sojWx:a1|.I 9'}"gP$MZ@EHfґNָ"׷bbA?4#3w|ފ453Sh Jλ?kؗfƾЗZp% !;@+!%u6sO}oLp=Ҡ+9Jz_C^c`;=x9 u fZrj,ʆjj9骩Z9+́0En!QT.^YsUH< ܞ8nT9Uz"j(%R ,3 ]ՐP6S%}[kmSsk7V a#NUUUP [@6V=3.,yǾMYV1G$t=)!{\ϧ|&.^@/gOELi#H&c][M9q:3 h b#c꥕q'~"wC5zW.iYUD=ip]mp{qlMilbdb,{XH㿦 fmp 3:tˤ dTԌQbCl hShѻy@ k~wKq!N76\S?3/k sXD*M{2ٗlg*x1 :8T*`O=m?mM㗌QJlV\`o|Cǩ5SޠO±˜*p-E$O`;S|Fo\c@ߕ{dxߖj,{a׏2 _:f^xx 5fd I N&V={c!Rܮ:`*mW?d_̼4 Isp,1OޏS5[)_}$ (̮'xDHd=ے}?p'Px-?`|,U𮾩J#$QeҌ{(zqKk ]X#Ϧ5|-ri-%Tj#JH20#2`'iu~ R}7KqD gs~g̞2ޕ1t6~D+bsv)7㍒pO⟇,T"h8PH\%rK_}Bus ,Ve:0Һ2l٤̧)jZhD!(P.K?0p2r!=mTA7`:jŮq j:11"CuU[Z8$>5(uԘҙDc|hݵUWqЫ~98eV ɳ)e44ɔZ⒇5J`څSmͷob[8F-O#9쫪*`+6#~}m||GA)SK"ĆCFJ^Mt[bYZ6)f0 1yfZl*iqIc Z5F9[+bdU$`*QNf 5Eͭ0EwrsP89fbVܛ =؎`(qչCJ1u%-{A4l:ZN4pHyf@*\n35r@,gn%ܣ澋 mmS@}NJ)ĺj7ТIoXب~mD'`U@SkĩوW{xkMeFzd[ q4떧 $wI[מVQEV'xbl.77㪝Zo` U30[WAOF#꩷Dݑ׍#pwšr\F} iD,sbI<ߓ0LUp'R ;J*䧎:c<P GuFYf9\GOQ7[|̦e'Vw2glvK Ƭşf<*|R`mHp.Z(폙J:IAu?pR/;Ds:YC9 鿛yL d/etn8ՙfbw8t6UҞpoks{1+wt(PE"( u'F @RӺb tv&NK}|;\`׺߼YUhW7hfiG $ }?=\Z/yF:\ W٥nw>X5Z@aԖ?`,~/c>wƠ:uT8-YiEՠV)\$m!eV^njʏkWZ706w<6P|9j棗$1ɗWSW3'BTmKUU'o[Dˏd|d5ʍ yL[^]I9̟-cտ+=zIdl^ZE(?p|ek[$_ i.w|G6bV]RFG11=#4+88?%vI}O.:0QHkV>[w{#LRDp3CH4=~kMIKj •]e:G\s=^pEA$SpԻ|Cf>"z] sp^NkO[5$~Ejm5=_7|^o5~ɲQfZNiDN{17n:1T81{5,=@9#]'b3/t^(|>gNzyPCM,A,s,Rc`W^GF :h{\KM_9_NR|UӼye)MS(nM!A$WpN]=\϶y~poթt+i_L-}tdn(Xm@pFROsWqZ,5 CukOW2GER33(TU,oqXlS t?Pa )?iNV;7 8 RF@woۏ=1jQccQXjQ=oOo^3W]3,UIb^Sd~;qNj2Wc+B$.m/W%#ͨSr:.i\K {z۸-oM˿VgUne`-]+u ~TT'$5Z;J-Q!3҅We˓6 -/>Ko 4=׳_^/x=),QTشd4euYXc7KqlMZ֢ })Ղ?? o_/:+]E '3z2ETB*UXۋֿ=1ʦ4"0b=(Sv$H;X s\wBI IjG_r*P[a3B"QGK csJ #X<ؑ۞xX} 7u]UCV|Fw4-ʝx1oW't{{1b|AaRsL55'sb~x!jZC#ӫ29r·)`>"-E.pm,ԷpKrm`MvsE8p]ϊ3:ez )"1>d!Ek^k㮆9Qy]ޢM}?:<ꖡ m?&㱭TK LÁ {fOHč?H tTQ bѯϹ"=]'_ӯT  xߔV2+Z3l&x+nҫd1€  }SsUHfwVe6GS"|T(7LХ`f4UaPJſ %](<ͭnmc$CG?©gXkL3M56 NZBUI9? IIE$ mfO{c )*q2Jm+l=mӷ!&tQw4T45GGM`ǿ-SU4P)hX4MBJ5 d2ʠu9ǧ~pD*5}BUSe^Ѐ;T}/ H#^`%tm wI{ǎmӋqA˵Y2J] we U0ٚ֜DJZATI:kn6u5$ O,("DbtȰx7Ȅ{622fc6#l$. h{"B@*#? Ⱥ~խ2XV 2#A4Z1Qs:QUȩ434tT <(9<+B%Fje.?2WxB}Omx$q{0"'jl&wKYCJJzDU뙈֢ 9@kH01*˹a 2"fYYzmP8Nf}WSpǀ2Mx7+E,ҧ]lbګOJFE ULuQ*-յ [k wO?Y_Z%sG'6DZO&4?8OQEēLQL*ݵ~GXqq_&rV QE!TLS%"b"V m3~&[k=%_=G;爐2FV`dJ <-|a6?L?QVpbNNIRS̶"P/v^0L|ʣx6 |~2Xs#HC20M,^A4ʘo?ޣZ ? 4s q'|74ߟxp~$ԴiZ%/h`I#7Pw*lQ@as~|G٭?XsG'W+ \ClH&@??'jzįç2_~Wpwo߈??S8sGw'i$S ȀR<ޟs7Rxq~t(e%.E< -?HVY9R ų;~~$H%<)G`X{="rzQ<#,2~+|Dv*$AB* Fx3l@_ vf>?r[g| L:W4^A|b&?h>3`M@]? ju~ 53JF[c5*/cLkzCWifuWwyʦjtp|!c=p?B#@m2"kmU \p,ߪC\73Gz/63pM8DRlK*Tan;~)?T[Qiڈr#=,aq|uRFZW5GQ SxHr3$kī$`pF;Z7\.቉(5^#ygIt[$n9ºM -4x/6՜^uaK%?h]Q-Н3J ,~TOR9ϪҪt]vgIURvokڦ9F0s47-c7=Jfe'e_ Z5Ŗ-2K>Oj̴m˲뇲1w[[s2{/{OU|9Th'✑z AEq *̱dK86I=ojTCOy3ej4 G}oպFCQxLåyvB( q&} źj@>Oڳ0& P霊&&f`-6zm[_n7 qv'߿U|FPڑk~z<^4] HK""r{갸ǁYڃ_GpT*`)gĦG/͊U%\`t,sԵw]VdٶmPIi)wove%jOEC.M:ti+*WcG.bZ//7?~3r ^}[PIR#O fvv*\]0p}.X0kKZ[]٦YLtoQ R "{) &P|zu$;zPe0H&L-ڒchM7M7&?j6} Zl5O?P`ӿy]K.)tI3TT ڗ&Fe*U)LM=fhUu?_x&[j|d\˜eRXI'# kw{Qxy辛 D᭦my/lx_dWHUH8D&py8OēIpt VAAO x/AI8xHރ/OŦ$rCd9$z婩bx$.E1u\Z)XvZFsQH &>;:xNu:Ƣ<2BeI#>u's$|s5Mx>%> U{?%j3i1d&8N ۻk*$ǖ #zŽ!*?R JRVy#E&Q滉><<^JH܋zM+ur0f9^[IT~G `Vhf =ҁ6ƟT{<W.sOMY .UNCa#!eP8_o j=@m|7^c5vYI5"֒KKI;N?T^. |K?O},OޗK[RȓZi^ 8q~9?\qY7V? c5 R)~沩.昲_0T*Pvkm3J鱇G6vpG?Gp8j}n$o6b DM6x[B ͜>~ƒl/X'TT`>1VjOh7iM;wD8ʳf|Ҍ%0䠿܍a# 0T*-> !nIc~ٌER?jALg*ɼ|9D&0n?M?VV&j$IsZ^ĝ]ԬuBvo>c>p-qdt)7{oj?6ecuAلtc!Q+jA{6꧷ԬwWS[DhILm+;M(ཾ],}vK#ƫƘ`a ;n8$[ i^ܑr@m8D>5Qhv?qȅ|!Pu n#? "/1 96]5R,{Fsabҳ{aĬoS-ʻ!&ꔱedSq"|0%^ pT(Qm6Y]6N4J\k9P=m%2qXv.~uDU α&8`nPD$#AD+'@蛥A-p_ڹd4ꬩ bxsŭ}Úگܒ$/¢KmV>ظk&%r4LXb9 {,;wtZ~`z3H USnij=pKs 5^`LC]1OF$ <違Yn7GLqFk}R5/LPdy|U=)c*~=}paMt\+K-;T6YXщv̥W K;UEJ+ &PPaV9{X &S$Sey%,M<1EY؂lxlF6XzQS'T b*ԟf۞p ?0DƱvVPoHSovn)FQM9Mfv2ZڠK5uKH>:PS>}cHE|*E6_2PtR-{X@n$ Q\%Z2B0ek-&?mpNϦf5Cf&(lХZ6Vem?&(q,EQ^#pfhޝ>! l:S3RPp^_`66I+պ#º6L&P+h! 塢,?T蒘MLdHY_$l,;zV[#Q`|l 3vӦ5!]rm?qͱ@T?f׆kYF&CII*<n[c4y^$΀ #↣%54S 5iiPHmRA㊆!vИzX%*}ۖ,T,{+X?Ǩwc @'yg`opsb*@56'LbjP%SOQ;<r@H?>lq-_zGMhmQtYKK_VtgH]E 'rƜ*v#>mI k$<A|@+]˴9Se:$TdtBޥ Hc`n<ou  wmu"rff]#|P|X!~J;]jUϩci$dCabXT)%cY4hYK* Lz.Ix)&ϪrRfΈ+U,m;IM1N[Ǧ;tkk^b 9UjW+]H;_l}G=yˢ1Qs?߇q~ɫS^5yigcK " 1. rn1sM͇SuV;k+-<%䦉Mb P1Ts_C|:1x?9T<UEH-nM_{*VӳV*jQᛤ$6xTm?uu6_ZHe,XJZL ˴㬒Nccb-0ۙ+?yx"l֗:\ŒJp 7kZ^|>j1|K.I]xxmMDuGҚm'AR |>X{)a!Ƕy:d1D4F xd˾5Q>1PG%E{ǩA[ IQw74 yG4ٮ\h7GO`֎j!,K!v0 ܁{[.%'L;o*.}WoT3fZ5,ɳʥkq{NÌlE+~*첳Ŝ1Z0V{lyt.fǸSН~G_,ڼ7<<{gP^G j-D-=3OU诅ǘ,ff9MڅgPwHMFUbE-}Jgq?<5ԆXK= e4SNLAF.pjd?dEQ~rJu3[Џ_<_u$'E񹒤9rN><,mSn1?RNж}/S]O+mvqϿ8kgLjT@3'f>LV $T8%~ݿ>1|\~xs54EaJ-)`~)Ksbdjr`[?kƁ>3i=8d GGđ3 ɰ=,Z$zos7T9ޑz|궟d*V̒C58W0*GpE`TD3}-/ŦOV(,J 2ԓ˪ZN5_~^e|jXzFh)HQuxobp_~05"m'U|%p ˾y ^G{H T c@QYf'%GzzdlI[A3@m/%P0j(Sij{GaKFn`47 mOON1/5x`uyY [D"'Kmð6ŽZ%<#q:x:v{})$: Hbyi%;O8ZxV%ձ`#`џ+|;, xmcx|SϦ+}e|8ҿi=R)vMY(a9اQχ~cq"4ss_#(~xw2%q;Ʈ6J?O.&b|ǎm< ,ZuYII,ŭ6k\xH=(ѪLHY)a# }3#IRRM8XpFXWMYcKG\ yXSoTi$6]_A%zeDoڭ`㨤ߑbm'AgFYjl'vʴD wZsk\cjoM*r`L&i%}To.na$$Y.a7%1WP )dG,0>FF0ToZ77Kp4GegU'MȻ9^I# . ;k㭂'WWN&vm؃ͽ?\fL'8hcseٓ LOVݮ, U&4jDdo~3}W^ fZ$Ӵb" EyXApA!$c~-O0ïwh&~43Hq./}6]hfhs痈KMB2+9Y>/+8"6o+?OG3p%[Fs˳=6.XRSgٳMY=>gg57˜ƞXcv {lvd7>ؿ!S}@0AECZ|IiE=Q&]i|*2z(VYD0FBC`>Ē' Y }w%.Lַۖ>5UFtx[:{BU>MGR::*aqIbH,An/?$ƊGL2]V9Zu.\}QAKD=}L&)dӔB_UnJcSd  ?I4)szX54+r=v|z4漌SXk:FC[ |r['df E'Ex}Bfq!Mmhu>|3Ѿ+eWev;733*"ӑQNB"pXQN]vh kKQs@^zȟ3_Қ/JъJ*5py $rHf6$^ݭ!E!}'ݯr g2~%9%ls)8*"Y@@1$]wn*H\; %XgЮ7¦Acq:ȳ솵k*rTn[/PF=ͷ1 HTu*s2-:_OҺC'kCSKC&s-$ۢYiM781,E&a=Wf $~k|gTUSKGMi"(J˩GS+{HI?oHmMS!Eܭ}voE9OЪLVYϲz<¯8Ȏba4T>Ӵm{_}p ŗo؍2_i`H-x_`,$c*@~'Vzi[KSg5AHjjiF;6כ1Laù*X DWAkbkf_/?uT%$5v# W Z:.'W藃xOAG NKPeAiQJ!S9y%7zkcBk#v~&YQ^bA5#G(2ԑɿZ}!tPm X l4*xfz] *|qqUDȥKV~W_? h􇋿sz1DzW}NPF*yC-NΠ/ioMi^LGF2̩衛sM"ƛBG%bIv/?>5~aj(l$)Qr'LAVDxie~4e<6`kbڮr@Q)3l'\֞TE$LFrnūpM̫J]i'M>~h'F8ijlu&~[Q)[gLN;[j-`/=6ҧM|F/[ulA.qtUWQvh%|>*5r,ծW@mvmX줹F:(nJ;abŕbBiSjH*,J>m\B!2j28MSQEDK۲bq*\'u_C,rEԊ5D(d64 cC' zAr.al<ܒm0 R.iZO3bt(K}l}0J{ &-bi z.,0bVA(x#+]#_W]yGr H6I#b(P~_QxEMWGUHV.ySO?Lj+6|iuRb%muH_0$a=Ovɚ"&GaDM#;,^.!~Ӛ nZ*O<7[b')ǿy@f*Z3qΉU$wg\ q;sLW ĹϢ׳AяȨmQREk7rC=TklC)> %SZvs~!ζ̠reS4$X߂ObY5` YFH$_L 0^Z\r։B, mo|Kj-E=Lk&`:l*u.~ATB xޭzW%5qˊ[9A18><7{Y71L^@cև?3Ҕs:iWD${姳[t_?ῂx;*cb}J"{h0:غzg,T0O K_Sd a]A`{Qa߉em 8'@Hqr M- _ sF%Mh*,=|~:~5B߉>#W( :j\AOEpx%AQO>Av{e;dkT3 RYSib6y{^~+ZJZ/[ww>FV:Қl7Zj"F=ѡ 4_x{.'qI~i39H++x?WƟ+ܒ<$ҹLykI&_ASWWB?#&~|+ZL3IZA /K ZXq y$*G{!E_r_MӹfMNlR)Zxڸ!k ~wWV7 `0:8b01~7UDjTėLjxџu =_)JUןǥVˏЮjR8ό? oڟⷉ&3|G5895UK񵥾wx{GiA:}f3'ձ>HxU3KP.lReVCPQ-!m5 hmP鯌l#1NM]Ux>su98MWT=hwN5c^Bd o/sD2OAU%>cPi.ﭸx %;%EӖ噅vQU[MQ^XᬝIԷňĪwʕ6~HrװA:Un.8qnȮ(44xctItK)֦-pMapX{s\-0v_}r6=olt`_+ɦPCZ(ɩ]I'\?5GDs(jzE$y Muj{R~1MouQ#mFC`"rCk RqU<^*sQߕtP%=inI0[@ ɮ\aZզcG4AOVO-'r yOoLz:XWڸo?P>Km[r)(ɠIzn)[m c;A:cc %l?:>r+)$Qv&&UGwsnن U5B?=_ে~OPĚs=8R/ ,My@ճDM4)mk[H2~M9swg9;G<ՙTDy*a`&b6w7oPD>c!>9 {aqxj\ ~uY}C)!jOЁkmʆ@ǫ~ţWh:OÔ|YEdk\)OPjb2ul$ Z!xk9+Sv?T-Q5.i+2ȲC4 y#hq X ƴՏ,|;\Rh (ԯ!2UKeȒ1]'/ KW_3Z꬗OmW(z\NNGjvERϠ7꺛o },H/,+oz;Ǫ*ZL3GE0xфK-w!iSmUz'Q@-FCUiL™de.@ Glw# kv1x ]y>ofŘQN钞Fpήo1@8eRpN{+yFjj+M+_NvbM }At}հúw#&њxӥc9,ZXȹmzF#h4D #8-nME\*C9x'x`^'dPUR&QOM(Z` g%䵭Z8sR84>8 e*B39\K!L™zCT['bmGfc]BMVYjyj!"`Ok펂ٻ[WNTf*nQ!ݤET<*eR80XR MM1dqH$S՞^+~N[7$_qAKk>[_W:(p:؛x๹K6/斛! Uv#ucnE/XnlJk+hk mI)8 C?7C{̪ ?c#m,E= S(kK)hz"5["ZqS;\yci6@) A TC!>{2 J6Y#crWql L̫vX5i2-SYGKFs$ /TC* خznQ{u[R'$k=ag+n-ǔ"˔=p {S3ɲgwh,/3*.}r?\$c[ 0'o-2g3y]cTW**d< -hȉı]z ? uVu$יLROO#E%@k~ąl/RcZAdx}Y?JN>^S%8ʹ-w$]F֪Zr4ǗU|aÜIxA3DsJbQG k8JŦ 6U.7 ^Ky |vxJ:XZd4̧2WjZ?ir4Iܼ-O< Ne4KG(k\`Cf/c\͑tů^ȧm_[Ti'VvЧ~O=UD@9^\QJr)j)q֐{s@`#Obı!L*^ xq8 :`EUvmQq+O"VFJ)V+~3b:"έF~f6K\S#S\nA.Ȉ^{Ӥ*Zif"$ԒquWǑoc\$ثT>Ux}tH0VYyUm*solsԡU裈V&Ǫ5ƥѕ~Y)چ,/u>S2]zo7*o5=%f9!9$sP.?<]E~ ;_e5&`{ĦTb9=;6h8gUxᗊ%&Wx4#E6ZazWVA = ɺgdQ>"~iʯWM2|KRK4M0bʎJfE`əRֱQ?5eUK9 岄MWMkzby*r䒡ZJ?K$Ա)ĮX;+@X9uGZ/=O=|ӵ4k\%jXe 9,NE⢰U1+Z?j<* y楞SD7r{S2TɅhAUΚC/CCUk"V7j^,_- D&cim+<^gY6Dl8d^rLC4bI21EsY[SIYF䰼[حR.2 (k"2VgYd5ޚ(紕T:xc 4os*VoS166`ݏ' ܨ˜4b#|#Mju$_O'qQVád8ųX}9}&S&41C,*J۩(Af8p?UZՠr`S7 0J&"L<>*5z?A9夢7P"6$/cx|>  ihx7qu1Xf{&@@6]Af~&xUGE^[QVPR=+h \p;}1z#w5#FT2/4u;gqԦ"0?w<.xԜI ajv\geeZMASjZ+5QFCq&ݍqvTR WI_Am]_a[OTD/ w/1]iHz?q~T{FtzSInm]F#E @UKztp8, 0ńO^n?^+']Cs8 4iNj/m0IP\ĹiCK;58 -ynuTT1h|:ߕ"Zi"9V'.x;bD9;yv,̾'tޢ4YQߐP,9y Vݖߓl#:.JzvXw.oak/#23 Z ҋ"tP! ?uǫ.f;L>"Ma~aTQԟC%ǝ]ٔ:5*}3|CZJRu*MH*muwk aןԫ1 OQAfςګO13q9z&ޣ81/KӂKolvogP^܃${I'VM.b3uffc.Nj"'ymC!if#NwnD{۷{Ojl9Vr'մN~-o\u'2)˨mZi"UblCSK`ڿQhm9O!5oL sB0jT8U龵&4>O=5<^u>iG  j8)i&""@ub}<>4|׋W%KXv|.K]LE"+m+kr{1CW6 b[฻k]s +b)%n~;0J|>=~Ssʁ%+Q)QƁYKU:pZ(K)U̶"Yf4TR|>jF/<<)= y>E6?#U>&?bfq /.e,A{N1:SxT/s\5:$4c?saǴt@*OGѫWMꃤ[eU*1Q*obmrOow{Q\y:Z? %\yfmւB-b@pZ4_pxA/dZg'bj3jBrfY @ l11Ċ^/H?wOa fs4Z/)*(季*JKKr-ͱ/Ec]}ٵJ2JdYqd;+~$-pRYLKSH\7Jlo 5ԕ@VE,i40l~P&9?A3t,Dhj /j=k@5$o%|S{DatPw0QUUsꆹyZt+,  rBƊlu53Z21$pZ2q.G$|uhO4*;#b߲Ҿj|>xNvIVoS$8 ĀgW.-fa,H՚&bJkI#ew7#wu`]<ˇK?gw{*7k&әلKS-SBDjHRĢqng tPi|mχ^.ܾ};MI8lEr^SRva(Ѭ4Ig\WOk)ch M[dX;k$j Dy G}l{`8T{Nɩ(r)s ZJbԙyU[24[ -eL0@+6ĜwNԆ5C88IHd28EbR\\-.:]5U|(6z2LU4x S3 ,C0R `Au*ҟPͨ(li%KeA·3?HkemG 8%UVQBouf'8n5 צ|SڠKԐGFUk aQ~ ?Uu|Vf9,p7槎7 K1KҀֵ:Hkv~-ȼ ?zN cb<6߹rnlxn\5OQ:k-ٶF5y@+v,A_/ar<\rЭO{sW.]6t.Gd9}EbGISS&. XlTl0dNuSGڇsZ!Xʠ؄<&+=I]L4-w(MEsy|ʅe2P~?;3thƛ{ O/S2mIS5dEGDvc9>厶q Y kArLTU-\d^a cۀ{mM(J};yIL‘rn/{m-Q"V@jRQ4zF@׵ͱVh9WF*Iuv>uY7WPח.M<C5Uq -dX%jh+d+0U; olĄDVU{@l{q{.0< (/G8ʣZGˣ{;fBJ~Zw{ͭ{vb0䊣]JClS6W=qcJgU慇*-+k~0NѲey  r1";^(l貉`ALU},WR͘-~) *KpJ4-2|ߦK!mX& I!zR9s͎D6Ϯ yX,,sÀ5 $Q[cK0%yF'ry%Je8r#S95l!o͆x*E9cUO >b]ckH&]H)#ijmklT'*%`Mz1TrLh ~ر!Da&Gb n}XfUāO6z[ 0iDJr w.א뮗s)zĭvQkCdz!y-?-TG6SO7"| OgYk yzZf6is )[28㱿sX-*,4+m?Kj/5V%MY@%WckF% u9\@nl׌,Y&YTWgTf<});M,kum4r>1+_]7~"BSZ ԱI(ʫj挚XRNA&-+15[uޑj)ρܪxIdj$dHe %ʒ,-p&$Pi^ٽcw:lƺҘQc2#k*w]O6%oZsWhJ}Qil)Ƣ]P1G'iV$flEjq67 yo8Xn瀞^s ju9OæڞJl`lX`R4G$$(+QjWT25tJ 'NkWed/VT[g0?O_~p%ۅF2k&/bm_W̄);\w$08n4¶Qeg]dkS~8w@G\Ig-gZ/o3,/ȶjޜ bqLh<1puWmt#y~4MULFmZNBKpX;?T:31#IGWU$gVg t q'?=OL~kc@2 ҞZI2K~U$Y[װO|MP{Hru˚TU%|\jAl$+ sӚxcwͷ* ʼ\ҹ\#X5/5TA{ɱV.4_?VEFuwey-Vq3:֪8TpOQ2x DtǤCI?s)ӳ%J]o(>EY[h e)ϨuwUYX blHry—CHeׇگBepP:Ž7c̬LMi Yq %ˌ%>U{{j= i4[tG}EO xMp<]1 "foh3<9. Z֝͹pn-aָ6D((E@ɪ<5X0t 5.H}q3Bu-HS$EJfo5F>nӲT {/2dk[TiO#] E_a[fbIEoN.Ű/%.1 qtZ~k|-D59n]qkl_4 XV ':"\Ni7y36=G}47NJ9USj梎*mAV%Yz>}16q^cϞ_tLi [<l8DֱqceS-ܭ:RY-.O$D,G?kӪZ8hWi'e-Qg^ܐzNEu]l t+IUfPJRC4*CH'!ǍUcddq?}kEl𧻓6|[8sf4@Pd,b98#0UVrI W3SB}b$(u_QFmAp)`E4K{cbr#x<2Sk{ !Vb/;<,࠽;!Ksp+LX1%6Vћ}ʚJ+뺒HÀYMw{c)\Q,.O46YU{b#R BCH%Bl@0P0X!%T.,= R0*ooLP,6 6ISnϰ!༱k t.R$!}6JHR;]>-$%,8 քI<~pE2L,HYQLJFݸ1R¹!0fc,펳I(4κ%UȰvq>3.Fh@=7ai74`OM)!M4UmQCL"FMR~㬥;t. >t^iԐSjShiE ְAp6cc5. a#ܴI# (Ԃo߃PIgaB`̑(gYZ}*I۸T{a?ָRz:a:D Qɸ 1bXYTԯjCK;YDLpXcF:e=646SDKuh ׾cnkKԂMO&*D77H+? jt&w9#-1բP ;kn ݉fatju-l'o#iEAu)b-n;zczV<042M4lM$R ;Z:stUnPU|, N<%ccp̾~H͑ݗEZO,zP3:zzw 9y0dBpa^>[5A5QH3 ڞT {[chSOcY[&ʴ>W)wU"B?\O; ˧(T6Q*U$[t7' 'seQrd)3s936Vݱ*.ᵅېmckAl'3 ]4rށH9 `3 7B c𪦤sm? 44<'bl.~L&B? (a.YT6p oO&ʫpt z2!XJnѢ⌆PGa T}ե)5qG Vm)(g>޸LHVBmew$`?&SS Y7h qlygv+@XB8]l@]<t6E$:!U囘HmAr#p;6Qlj8*Gyq |0QvOU܄ck,ʭ¸gs7FqQR5AY&>蝔J od6+!Ѝir–f#ܓitL6Z;63OњzxIb¬Dlp$Jgirs'H  ߩ :)O[hqdkC>~=+ 5>Fk>_v;Zo"LSHJt+2LhVlR<Ɖ%|e5qP$3\0f_)܂|yKr(LK Ҟl*Z &`tV%We 9#,JmϘhPTLr{꬛5y(so97䃏UiA>켪9>m`OSD=WGpOboL)OdZ_6e M\(~{p{ Ztc#xsO(2F][z[ \6lO:>>>&u1h:dI%kJ@Y^nGu\4 7\͛QD' 1ͷm6ubk&ğBppo]X_mo~'xjm+UeT9whP/ٶp.lkHS ~3r]+Ml\m#E=T)wK39.K`0(aZ6p>s;㟎y.6^E\bǪdSՎhhXb݈8Rm&NU֧9}/Zy47ݶHUI%W O(E,vQ[~m|΢ՙfwIORS̋puqyMluMnnfUF!sxIQkr/m+p*by+u x<Fx§XLKs£/FGǔ'K;`tWi0nf#ȷǔ]iKI0hZJVuz kJrHȷ؜/T{G8#BTw/=v0 R;,dSb=6c^sGjm#n&#|S RГ- 8S5y&bȩ0 ;B^# =Lx(~vD]/I09<;b O0i IyqQw) zNm`*%-OY+ MRtQ}qxƎUmWZzi.JH[[\+pNK!>tGp5H(^M1:.R نt63,N彮o *9v3r<vxf`7P9;IY0K-;Zې^`q0R80hiA'R fRxOP>"87 l!E+`}i-Sў 9}>L 7AFw;&H;C[6e=a).Zk3PӼMPZ{Ku`52Qo5G=>]O $%R\_w F8'xcr(4#@lyIU}1ր3Uf0eO/ˣJָ00GUrCKA\JD2׶:J8B^DePF4V;'jnb~ r{A}~%: Pu U`o(J'7>s* F ÄHk}P^%h&uKu/FAUC5jZQxK])e0K/EDD\_wclsPN)P,:N-ZzZX6`Dv=aJgSN,PS4`莲+r@7n W T48]t|нa9@7;mqsqk.\+~1Z\֏$xEL%tQu a$\stsTH*3AKCxXe 7=ǥ0O\!ua4T7!&8u0t^fb̕TsmmoqR6D=*',aUPB32u0xF$E܀[r83XJin 4G=Ue_(\5vKc2Sa#c٤)JRa)Id6Ŏ7L '9[+bV?;RS/I )݁(*\͵TŬ-VihWpi$eRx[LdrY*h# ネ=1㹇*TT=M -Oc Fu}c"<(s@>jLT4@ѴP6闫#8;;ަ؎"QIEZ45ܾK/PxKNwHBYE\% w* 6;qj,c~TI/.\#O>-c$ҕ6s+vbܛ{cJdݧe|i)ڻ9snsأ$vpH3l<]H[kqmaSN|A)d )b Can޸jG CrLe96".P~H|XXpdNYDVP-(&7X-[͑(vD:VHٮo5ZC[~庱˫+LP~slXp}[LLJԹmKC$UdV",xo{ )9AzȠ.*ab; ,+ JW1)JG" YP\_qcq?qxv7sO[J3xibUqcxGڀ@S3M9n mEJNE㌨n7pA?Dj2l\U<+ 5SdDL*nkKgZ') :ʵ-ҤZfeEP29jSv]U %ʥ&'i`0c\O+I 㟴~DMF_X@Waur pR95D轰;plri͌zTL0T,rE|G06۶*(pb<Ȱ_^qF%Uߛ^ػhMA[p=n s9Q`[ A[枧ӕm5'eXJ n ʟMP-ݔ $6HZQ~}esuV`=F4pji$ED{X8Y9cZDLpf` #?$ 2uf, hmn=`)ۜO8gd+b@,Ld੕G ǙQ(,|U77V2$*"AfAU>޽ 0&@I9(N"ݷTS.u;qEɪ];YVC$V m?t +LehVҬ)ioaBĮz+ajjhޙhcWʥWha4%a*#G +0 "XvXߑ T݉r׊QS1sk钹t[$z"Vh]|y"o[*%HajW42URHlq{00*7 TEYMV_MyIצae!,7IG<,cvs$>ʅSIMar9x??XVSf*({p{W:A+x!fNft45=ȄhoqzaB XrS=DrI+-oݐmeKʂW}Vp;\uJ`ʵt0F6X8s$\ Q* ovvC2gE]IZԞh'l R9\MӴ],T*sH@nw+a)U&#][Xb-XFo#f v 1\- AH`=pem4-YbSf L.[vgEpu-QVR=/{0yce- 8OQds%I!W.6vI[66ˀ@aWNKCO*c-ae=\Xrys;Ad€e.9]CSg2I 7X[j\؀lO ?}GIߟpߥrau|junOL4hvJPj֨qC4[{'nZneL43\^#LSaaqQIX#! 0ORbg3'aLMMe\.5Le :n0eAFz< 8mSyv$|cy7>Ԁ' *-{+*u5'/.1#@L)MTxt1+lGx[(1β `J"kYԛ7BpI\ҽ~UJDK8ceZJzx o"ee)Gjk5.mAظ\oӾ4Y;AsWKGnh Mv\fmi0?{|'VQydƠנhN/G7G/Rk9g#ji`^IHa%:jR+OM,4a V`{̀ET|4Uff3bG~? )Y)I3K_,,OPʭ8P&J+grFL̆D+v)=m10m^f&%A9%<emO!*5Vc@jr4$u?lJƒs-!-Jh|S# ~G6blVk3[dw\aRpĢRc8mA}Uq6ej?{x,QSS$lW($79 s<ch6dִ4 ,u9Q`<.EZxV<!kḐӺGP8ssÐYw] .yi*Te8YcTw7=~ҀVTtgZ08v;~_GR߽Q + ~'[-R RiΆy}UOPV)UT&Y5YtVfCڠM>GYt <#ʢ5lDnܡc0Awk<UZ%@uJ8WtaMiZYkT }{ܐ=:wL GCa--Y]Aߞ}\\R3!wD\L.R@Ƽvr4j0oqk)5=a0V>x?^{cu!D_WKK95&rOۃ8@g]{7e2ѫL̐%Hn0X#ٸhVh&e1;YǟWwBkԪՙi1{[㊦;ʍq@QzJi'/o #{"&_=DQ x0JPHVUH'\ 3l8̒RZŚ~jSZ虇P+sL?DD쀬y&ʘ0v0{MC RmESBL̺2yP EV;M@@tG2| q oÂRUo0*Cv*9ÓP([Q$`>T7!)&:OXv|!a;!Rl@M)Ql̝e*GͯuLiq3ΨBc\381 f e}Il(5`4@Q4,išI(Q_ HITFدwGv^>aPBy_m)[2b:`nqVI)qf "$<*b͢ ɘv8qEh9DǶ*(,P r!Fک߽(@MU>{Z38knS DG2F;T$NzqvڞcNɻctGEX`x,8p\Sif ݎb&x:,R1=Ÿ P$,QO]b4ly1#&;hV5ZiQ8]h Awj}uV]4eTL6'BG0| 8ӋBŅ3=]eM:[#G? - tS0+i2l jLИ)n,~݆Se {`@n*$yLxr(aXP"I{G펺8 /Stel@D}+mv4) r%mBKsa nʝ㤙#xrM,Q7+8\R1T6ݟDy4By7f2 sGƙ&̩ٟ|u 0c@Q`T: j˾eR`o(:M$ӄl{p~9 ]aLCXn=Š2S謓5EI` ǎ5i}?>[T~* qJdn4U :,ccc)B9AMehĜ kvdkqdI9E $`879l-o/6,muYV3k( XA]dڎU搋 F m!og䴲&C,/v<8fhhAb $OJVD| ~ϴ|R~=jY$j~Mie */x!9UŎT;pO6·gdKUBxa&h$x-سԪJʌwclPc$w$~v|+RkE&8̦ޘͤ"C-֫Sb'f!˥3/hvoa} Q :ک+I/`6YYS1e}ǏHK,ej juxW;H#v9 Wr1aQDsU[Tp=ٜcrc=9}P4PRÆFTԭ:D( c-flNұet c`2~zPkKB9J< yKLyºL^hf`#aM&:Ȇ8 5TYxv0%JKP7ಅ3'䘈eUU6DLMr r#^F˒#)Ӟ+$hR6XFcߊfg4N%fMa$e[E=h,#e quk?}_هk5ҹ-=VZ*/O9~ &c)C;E@Vx͏puQ:I U'x; 9RD]nxܜ`U[r yR00+*%Vmn!өRvʭӵq#Gp'9šeO*\O ؂* PH @9(6}Г 7{[0TPn;ymJf,r㡸t tEzwŅ!7Nl,1aG!1⢒peI'i0'mcMcCjcO{#`,EOALRT1Gh)4ton 6flr,FXLHfri*V=:( 2$Sf  iKkv$ϒvvB]P:D  q$Rd&ɳY2_51f6BMП)KLfJМ Y4KNlqQA! Ht$Ӟ$3~ v2Q6A!l1'-xFq6{a oxB+ ]XQUJP /'=^auRxeR*!svD$$ ['6;*2SBܒsoa<3,nUuOr3Q 锷'sm&' OQշRfhɲ~_A;taJC WOSH\ DvLG.i"Z[Gs'iNfE9oGϞo*=^pT%aD7TVASnJ)ꪹizIxk6P*ob‘B deorqrq[*v*J8{9csDIinMVq t zG+vݕEJZ޾^L-*#nL,:zh]#) \a{8D4zZmؑlE\yL#pSW[dx&bn;NaUkXza vDfLG!{dT̀uHegt3W+%(>GqFBzVk3$I" c0 (5L8,4S@Y[*U^' }:RlºFt/WnHOqSe[IN4*FIQ|ΖC1a7Y!ZddQpYPjuea "H?lt z#SUeh՚Cel'ϫB#n`Ɠ3XG(suUM$IeXx \+˧fqPych|lߑZ|ua-nU.\8v8#C^eZ^_U#+JbTl1ZJͳZg}RYJςR$z#0#Gl0%ICLq:#*ň8%ņY 3JJH[N7j=ZxV:)e%frA?:;ۗ$r WqV+s BжTۀsQH'Fp>el')~Fxډ:v뉺S"Qz?&Y'+yb =J9e3+4qfA%BOR?n& ò5"<,ZKO+DcT ňbYQNiz8=>CTs 5UV^)BL8[qI.Y -D*)P5jZIwǦ0b;o 5:g>[=EBRGh'lO "H®JI'Zido1"aۄ,ϒFuHi^aDs_4gGSGTMLH>a# f Un-UFix罭h%,@Oa;lR$Jq;m+)FξA`-Ų4RĥRj. ^9$2Vպ_ rgycUJӛK7 ׽~>1OlUed)VԥmfaRed$YOqHldUfa.uV|NmO ڀ.G80 !Le1ڳ# ĩL$_wG~ȝU:Eɒ Rg9 *M{о_ ,Aك%6c!0!W5`ssi,=!)7Z@W­o擳AJ= Œ"Rdm9u$mFJ-.pt*4 yI8B|];Y(;HuRbА)-5IQ [?:Fk.w![He7mRl C8ͪ"553fpn|rx |Ч[JLs[ ߩ]© CmFfmASNA aq ]nYƓACR}K$ J{LEx̞(t$&ӹ9ZԠ)o`0Rf,ԕn6Wv$-XXfЎ=9 um=LD#PlT#x4 FxlAl3&_ H 1#($|s3S+NJ-A @u o7RaUu&ԚwnÌ);NVhj?lpp K%e#`9IԜݒg(T{2E}.B[q`e Άg%VO!D۶!^ʌ|#HB:o1#ˎqJP~`j,vqNǻ{y,/ZgWUCӡ뎊4Z>)MlT\ܤc2pL\dSzRf ?6u:%4*k+j9y{6'*.V VPVXplq:WE4Ʃ*'edFO*bIaJ?sNɺ(ϙT-P*iio(svn{HQ3AWwTBdo%1(cnYyeSR5SFu?% e6hRcbL*ZNGoEF#ys98cZL n*c >jU }ֿfC#lai2V`9#o9X4)ǔ$P I89A&-5=X{~].Ci_)w-@Bg9A`a +Pvݭ)D *b A=ɘ$7fQOS5cFQ I^El)(3_RD5w8FD"oq茅1,.8`v+HE\VqlnˢƠE=9F[05Ԋ ]̤5#i[1FRSȲJ)١n/YcGYu<u:'͛)|`aH!%I5DGp*yh۶dF?ʪٔav&3x[2^-O|^;A@K6F7 SoB/aC3`$-,=R¢MeRm-nYipUO)hzҡWMeU m'fn0aҝ\fy?r?,(ͯ !k﨧2B?fQ]B7Xǰ8ƒҮEeE gveu[<fFg!1d 3Z*|1pZ WgW@n|3AWjݩfCq}QH,{A Y]H#۸lHAcHBir}cKE~JM)Gc7?}`52g꘬ʳ'q ܎{;ȭ'>Jzs̭rA8u<GW V]_LCp(lMWS bf~d  ~1fjU""&^2ů"?MaOH' M*w,`{`NS&G,}Wci e3:|撩dRZd KM\{?b9!!3E'UU܂/ll0 ZR9Jd>ZSt~l֏ ~݆&{r %jXگTe)oCQW ed3PI3SK>8I˔ Z犊hj9#e{a~4W`vPo{0C)d T$n@B`P&u 7k%2S9֜rz%̫0<⭊Kb^F9}ZE1N6KO*ĪXUb}XnfU lmYMr2U'vO{;>CA]/#E=M$Nԃ3z 0?cZIt(V!jY1\SRJcGQNԲN|u2?z tZ6gCUKVԕFDnqRsA~qX r,j94S_ L"! -2#<.bP}TG`YOvkeP;Dw1Bb}Ͼ0Á:|xh PR9¿u!*;(z*Pˠ@f7+ ^"xԕa!`I5Z!%g4%>`zJyI}ߧ7&l[ISOO׮~`}ͭob.EП**PRFcN-H,ce'k_s@$!t-㉠ZJ-5[3 lSg%=-e{oqFa)RX=ҜM>x-ޞ6fA{a"`6<}LÑm.-JO6ϫَ9SP:ftyFbKj:eLRT8KI# iQQG?~=NhM+ux-sYb27+ߛp0$hF4Yjxh\L;~iG!{7َJ|ƪi&o`=|ypEL3H'(0 a4GYy_Y}% 1 |S,&S3j; kKDH;S\;nAcTpN>HߚͫEi%3%:":tR?C?&$6~i+d\4 B[qF9Oo̧ \VDv (Ty,÷̣y>M4Jl= C[]᜝KkDؖzUL"ȩi"N觹-~prY'Qi 53p1Ar1g~yYK?KܔhSNe҄,;3m~8\KFhĦ^ri3)'[ ֝9b2jlK?cݕbY[-@`)dS٭0T{};>[!ͣ"#0 n"KpK!396Dee#^q&#8n/ قQV!{7–92*"5.c6SQE:D봭V ?㽘l"zZyQt[0Y2E:aT6zQN~-˜t㪊# 7>ue%T5][u&cu[ )#T3ʕ~1j7Morykp1 .Kv_C4.r ۵,X9=AxǖmĨO5L W~c$9b>wJ$PeVBpIlΥr3ZQ(F0f$*5 A>Lv1L <>O'يsJ\mlrH'^?`XS5s 'qٕLQQ'LqŻyܠ @< م;/.oױŽ0;0bscܞ٥.^lѐy8РsO{4CJ|WBmXkʄ $wƉʭ|͜䱾-&`ق+Z냕*kFx$fVώpVO$r于Lʋ{}$#| ߜBL3Cea 3SWU hXO2%LQ;T5G#jI$iB@!~/,{sѓ|ɖ%⊓P}zucAzBa*<˩kZd;Ԋ<{\ +8>hwbH39PY*jzL<\bcuU41䀞a;#r6J7=д ՃwQicA=t˂qӬlY{bKI=" |X;6#0l T3~MdtA,6ϗcX!7gy VbDF,lKqp IzdGU½,Y$39P8?l,%|tLIT1Zj+֞%t%rۃ;ǀJaas|eOu$ ֧8gx#!B sIZZ$bNm; !SOQF 127)Q =n~K`QVy֐ oO{)❄&P!KpmSynBF/7z50E*f;ڞ7,~ߟ9]6nj8$&9coofSĝ&+Kӊ)q!PG\]4tubR/")?Qs8lԯ!(!"4\@4;dAQDʱnO}q0(+K-9ЃrMpqjx0uUp#EZUgǀ>LCh<Ԣ9)ad,?t"X**TH m_N(0%6a6 3fyXؽ<+,57^Xk9&k AƼ{ 0R@L&y])Lш􍛥Q|35c`1A.k-o]BX,&|OQS9ǂlTPhA+ 70A c;DclnuI6 sZƧ-2غf9Qo$0D-eJ |\SiE*c?K}8RܣK('I /o+ 9!EOZ4"Ws+/0ͽ\?$hKHUdW]p qr2oYebA+Hhzn0瀴yL_晲LhD_1fRR8Yd \aU2d:-FeS[SyE@ҲkME]R!(XUzmhsQO̳HZ-e DHo!}M JEcQշ)$ݰ݀&PRjjY_v7Q8`[1YQE=]VJ?vm0MYJ֏1Z~/F 4JfVcfZ;-DqFk^A&!i %4,땘-ċ_3|T3Yn/+vH[0X ֐vk0(T(iApA@sk5ʟ8nl3U$"Og ,nbq5Qhw (7fR9$aK;^ɥ`ٰE97!K?'D3(ҪDV6 ݿ[z`@ G1R|Ƣ)U›\Av[993t 3+f:/ uIE̹>śOJYp{4'U^S,U1yⱍcm[ YQ;klơ%إocY Y]thR41P ™{v9a[26+ u1Xv$'HPYQW_0y'"K.܂>بk*+[}~=2-MŜRe5I%JM m1Er}.Rs8cS85@2~˪[WCXOCT` ¨ܑ֩NsΟl~~Ff 濸bX}gꋚB5bPQu >NQw2ARZ$䈙[vQ5lsK~DvUKLH8´R٭T4l3(%{/xc'4%?+XA:V e@M"QɵnsWv;`x&tHD?۾"pΪwJ^씅1@e߃uuAX"G=Cc\a 4 浵_B2TEMm!x/?Ree .}QDnڶP0{|0F%]L>@.U?llX&;N`(FW^0& ]o{ri Ȧ0aXz9'TRjOO bB$6UXJ216DAR:4%z<$Q;2] )˜UJ&;e^[4nk~p{1lr6Gb -+;vaBw&2mz`6i>GQřT<ᦍi>£<5Uڅ*t^cߞ;}AJ5>9QhjT̍t2wltӦȐ̪s3;~T7 D$%jөqVx9b  )l47kc&b} 25@V?o_S"uEj 6jٓtڢ2B,PMOlIC%zQԴ(3#Kc6Oٌ!Qݠo~9FISzNHh-( <(-1nP2HaDJQrCGVR(_I0tg6ѳ/>G3 cKMߚr-qW-> K nCI `Ɖ҆YQl,_sحb?Zq>a|5ƊJYUkt f V:Fpm $猕k lG瓳Nq%cрq#%akpeZJϿ_덑i+-3H?ncdX ?S[,:!iGkss 3:du33RS\TK1!)q:+fՔ.mR+ēHO?b18ʘ04 Dx(Y#bkC!heUTby>]#BY)즶.|T(iI$f&/e])Npp\iVWSeCWZ.qI ?kGo: UTY ښ\K5ODe)ZdꟗVC9T%Na5H a'bE~@|/Y(~tZ)Zy%hĄNGq:&'S5謧JQM=UR)iǕϛ$)9'/(X*㩊tQovLdGYR$eS:JHW8K'7Rgp?{_R.}Xdf,5:|tarzprC_Ԛl#HN.+/gjJ_K$Hcs:RA1&rLAmt%4Z&5H65, 1kn'ΦZcv6IL O0\Ҏ:*<Ʀu%# r n7H>c D,}ů|uuJvD: @s+m#֔e#S6YYT‘C[@v%J0H* <%,"U^O߶kZe1yKV`lb2▌Y#;[D-s,HN$_! I(%~H\Y,H$ 1(e,@JPyO=M&d :n,n,TKk{eMKN'ɸO$!,Y$y4!$2b6=T{,|&BALeFn;> $/U,7%O P҅’-eU\1Wk ۬Br*Hԋ-8Bƍ>bn/H_8IR KcNU?O|Z ^‵R[agr7E!l".>!l`"q˲,4E~Ke%`~/$3,6Qy`#u(v^ gqxL lw,',h%\ =_d4p%co܋{@BBXDmcoPU"R@)Ƕ 6WVV6%xe[êf2^G)~`H hTkyc=MquroɐܟƆNy'ͥIM < W-3_ vYR$8eX8)»W%L-coL4õ",Im4,hHEA]OU 7iI}Sqs@\"SNC -AKg_:h(*CX~ۈ߰<~À*3X8~f@GFЎ|DRJs$U[OT%JzrFL/6 -|4S.2ZEuю4{8&_A4Q>1( ҌS\_9uR)8_pH?c=X4k*-G91hN-{vZv l%5 b:bmvSGhU2H-t5 def 4ңk"I@ltPrJ #}yc7>pf]Ǫ`fOU};u0:Sn 1 [_E|,@УrGEXLa7C]POhR@V'QŢBXWT3Ĭ[vk6P*fأ9"׶ Ō)ʧMM O&$R܍Vet`oE'ͨ,MUANqL`*s@HnMe$ fTo;&V:g'kY _sըhuaj9i%F8|#8z=ԇ%tAȰNxĢ 2XMCMb1MpxQ,.&dWi֥ kbt9!T"XhQk^,Q -5kjQF-Ŭ=TB5>uPIrٶnqBlź!tG0`daȥ-$fVZGeH[@@PP6Q#bXl)2V&|cm0$L }6 ·UC9`ex2TŔp=m|l^$}1+ 7Yx1khQqBW`Egr{u@d,J-Y]?N\PM@LºZJ$NCHG60T$RSy&{ߐqpI6Ywbn{pF 4CoQo&na=f>KYd2I+XNX# @oY7 [Q# ADXa<TnB{>9ӍSf(:Mq{oL5 ֺfXwۃBgUFg8iM,`8Pu},iWH!脕uSؿ,@6ǥwb7UmP %!$3m$ c 'TfRJ㫶c3=NT-r mF_ӳBX 9U{0AJU-nIJnijL.˵N_IHyr:$O_]3Xa%R e-clBɉSl7YLlVNY.U_T$ zP2G>Zfx@<|b@[deΠ2i;Eö' \$M[W&\2jQvWsIq *9Ӭٚn2QK"qkc憝=TYnsl*jzjw6 ~sEBj9W0ȵMY?2,ls5I,6SfRi:x>]X[:)irkUU05LeO㭭h .0 l{D^Gg<邊cMez:chrhoeoq:<˂fТjJ,ЩNŌlq:ꈣYU{i*NBI EВ >'aQ-J4Zb MӰ$Utb9B`3J:TɡbM}$c*peSRDkn7 C Adk W&T0El<Ĺ7` ۑ{#MvFk6ge)'TY@"]nvJӦHZ,Y+"y'l3Qna(,,VyB޸V3 Dž${cD7UĢ =o?/ lW@"M{b.ÎV+Ŋ6pg-& Y$jcI@=jl-Ǧ"UpuS5^ libkysdk-applications/kysdk-qtwidgets/test/testKLabel/0000775000175000017500000000000015104543305022147 5ustar fengfenglibkysdk-applications/kysdk-qtwidgets/test/testKLabel/widget.h0000664000175000017500000000167515104543305023614 0ustar fengfeng/* * * Copyright (C) 2024, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhenyu Wang * */ #ifndef WIDGET_H #define WIDGET_H #include class Widget : public QWidget { Q_OBJECT public: Widget(QWidget *parent = nullptr); ~Widget(); }; #endif // WIDGET_H libkysdk-applications/kysdk-qtwidgets/test/testKLabel/testKLabel.pro0000664000175000017500000000200115104543305024714 0ustar fengfengQT += core gui greaterThan(QT_MAJOR_VERSION, 4): QT += widgets CONFIG += c++17 CONFIG += link_pkgconfig PKGCONFIG += kysdk-widgetutils kysdk-qtwidgets # The following define makes your compiler emit warnings if you use # any Qt feature that has been marked deprecated (the exact warnings # depend on your compiler). Please consult the documentation of the # deprecated API in order to know how to port your code away from it. DEFINES += QT_DEPRECATED_WARNINGS # You can also make your code fail to compile if it uses deprecated APIs. # In order to do so, uncomment the following line. # You can also select to disable deprecated APIs only up to a certain version of Qt. #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 SOURCES += \ main.cpp \ widget.cpp HEADERS += \ widget.h # Default rules for deployment. qnx: target.path = /tmp/$${TARGET}/bin else: unix:!android: target.path = /opt/$${TARGET}/bin !isEmpty(target.path): INSTALLS += target libkysdk-applications/kysdk-qtwidgets/test/testKLabel/widget.cpp0000664000175000017500000001124315104543305024137 0ustar fengfeng/* * * Copyright (C) 2024, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhenyu Wang * */ #include "widget.h" #include "klabel.h" #include #include #include #include using namespace kdk; Widget::Widget(QWidget *parent) : QWidget(parent) { QVBoxLayout *vlayout = new QVBoxLayout(this); QVBoxLayout *layout = new QVBoxLayout(); KLabel *label1 = new KLabel(); label1->setText("我是一个测试tooltip的lable"); label1->setBackgroundColor(true, Qt::red); // label1->setFixedWidth(100); KLabel *label2 = new KLabel(this); label2->setPixmap(QIcon::fromTheme("system-computer-symbolic").pixmap(16, 16)); label2->setDataHightColor(true); label2->setLabelType(KLabelType::DataType); label2->setText("我是一个测试lable"); KLabel *label3 = new KLabel(); label3->setFixedWidth(100); label3->setText("测\n测dawdadafauphfuawhfawhfp"); label3->setWordWrap(true); label3->setPixmap(QIcon::fromTheme("system-computer-symbolic").pixmap(16, 16)); label3->setLabelType(KLabelType::DataType); label3->setBackgroundColor(Qt::white); label3->setDataHightColor(true); KLabel *label4 = new KLabel(); label4->setLabelType(KLabelType::CircleType); label4->setPixmap(QIcon::fromTheme("system-computer-symbolic").pixmap(16, 16)); label4->setFixedSize(50, 50); QFont font1; int i = font().pointSize(); font1.setPointSize(i + 16); label1->setFont(font1); label4->setPixmap(QIcon::fromTheme("dialog-ok").pixmap(16, 16)); label4->setBackgroundColor(true, Qt::green); QPushButton *btn1 = new QPushButton("默认"); QPushButton *btn2 = new QPushButton("高亮背景"); QPushButton *btn3 = new QPushButton("自定义背景"); QHBoxLayout *hlayout = new QHBoxLayout(); hlayout->addWidget(btn1); hlayout->addWidget(btn2); hlayout->addWidget(btn3); connect(btn1, &QPushButton::clicked, this, [=] { label4->setHighlightBackground(false); label4->setBackgroundColor(false); label4->setPixmap(QIcon::fromTheme("system-computer-symbolic").pixmap(16, 16)); }); connect(btn2, &QPushButton::clicked, this, [=] { label4->setHighlightBackground(true); label4->setPixmap(QIcon::fromTheme("system-computer-symbolic").pixmap(16, 16)); }); connect(btn3, &QPushButton::clicked, this, [=] { label4->setBackgroundColor(true, QColor(82, 196, 41)); label4->setPixmap(QIcon::fromTheme("dialog-ok").pixmap(16, 16)); }); KLabel *label5 = new KLabel(this); label5->setText("测试进入/离开信号/点击信号/双击信号"); connect(label5, &KLabel::enterWidget, this, [=] { qDebug() << "enter label5"; }); connect(label5, &KLabel::leaveWidget, this, [=] { qDebug() << "leave label5"; }); connect(label5, &KLabel::clicked, this, [=](bool checked) { qDebug() << "clicked label5" << checked; }); connect(label5,&KLabel::doubleClicked,this,[=](){ qDebug()<<"doubleClicked label5"; }); QHBoxLayout *hlayout1 = new QHBoxLayout(this); KLabel *label6 = new KLabel(this); label6->setText("测试三态"); label6->setTristate(true); QPushButton *btn = new QPushButton(this); connect(btn, &QPushButton::clicked, this, [=] { if (label6->isTristate()) label6->setTristate(false); else label6->setTristate(true); }); hlayout1->addWidget(label6); hlayout1->addWidget(btn); QHBoxLayout *hlayout2 = new QHBoxLayout(this); KLabel *label7 = new KLabel(this); label7->setText("测试font color role"); label7->setFontColorRole(QPalette::PlaceholderText); hlayout2->addWidget(label7); layout->addWidget(label1); layout->addWidget(label2); layout->addWidget(label3); layout->addLayout(hlayout); layout->addWidget(label4); layout->addWidget(label5); layout->addLayout(hlayout1); layout->addLayout(hlayout2); vlayout->addLayout(layout); } Widget::~Widget() { } libkysdk-applications/kysdk-qtwidgets/test/testKLabel/main.cpp0000664000175000017500000000165015104543305023601 0ustar fengfeng/* * * Copyright (C) 2024, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhenyu Wang * */ #include "widget.h" #include int main(int argc, char *argv[]) { QApplication a(argc, argv); Widget w; w.show(); return a.exec(); } libkysdk-applications/kysdk-qtwidgets/test/testtitlewindow/0000775000175000017500000000000015104543305023366 5ustar fengfenglibkysdk-applications/kysdk-qtwidgets/test/testtitlewindow/widget.h0000664000175000017500000000167515104543305025033 0ustar fengfeng/* * * Copyright (C) 2024, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhenyu Wang * */ #ifndef WIDGET_H #define WIDGET_H #include class Widget : public QWidget { Q_OBJECT public: Widget(QWidget *parent = nullptr); ~Widget(); }; #endif // WIDGET_H libkysdk-applications/kysdk-qtwidgets/test/testtitlewindow/widget.cpp0000664000175000017500000000260415104543305025357 0ustar fengfeng/* * * Copyright (C) 2024, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhenyu Wang * */ #include "widget.h" #include "ktextedit.h" #include "ktitlewindow.h" #include using namespace kdk; Widget::Widget(QWidget *parent) : QWidget(parent) { KTitleWindow *window = new KTitleWindow(); QPushButton *btn1 = new QPushButton(); btn1->setText("测试button"); QHBoxLayout *layout = new QHBoxLayout(); layout->addWidget(btn1); KTextEdit *edit = new KTextEdit(); edit->setLabelVisible(false); QVBoxLayout *vlayout = new QVBoxLayout(); vlayout->addLayout(layout); vlayout->addWidget(edit); window->baseWidget()->setLayout(vlayout); window->show(); } Widget::~Widget() { } libkysdk-applications/kysdk-qtwidgets/test/testtitlewindow/main.cpp0000664000175000017500000000165615104543305025026 0ustar fengfeng/* * * Copyright (C) 2024, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhenyu Wang * */ #include "widget.h" #include int main(int argc, char *argv[]) { QApplication a(argc, argv); Widget w; // w.show(); return a.exec(); } libkysdk-applications/kysdk-qtwidgets/test/testtitlewindow/testtitlewindow.pro0000664000175000017500000000200115104543305027352 0ustar fengfengQT += core gui greaterThan(QT_MAJOR_VERSION, 4): QT += widgets CONFIG += c++17 CONFIG += link_pkgconfig PKGCONFIG += kysdk-widgetutils kysdk-qtwidgets # The following define makes your compiler emit warnings if you use # any Qt feature that has been marked deprecated (the exact warnings # depend on your compiler). Please consult the documentation of the # deprecated API in order to know how to port your code away from it. DEFINES += QT_DEPRECATED_WARNINGS # You can also make your code fail to compile if it uses deprecated APIs. # In order to do so, uncomment the following line. # You can also select to disable deprecated APIs only up to a certain version of Qt. #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 SOURCES += \ main.cpp \ widget.cpp HEADERS += \ widget.h # Default rules for deployment. qnx: target.path = /tmp/$${TARGET}/bin else: unix:!android: target.path = /opt/$${TARGET}/bin !isEmpty(target.path): INSTALLS += target libkysdk-applications/kysdk-qtwidgets/test/testprogressbar/0000775000175000017500000000000015104543305023346 5ustar fengfenglibkysdk-applications/kysdk-qtwidgets/test/testprogressbar/widget.h0000664000175000017500000000232615104543305025005 0ustar fengfeng/* * * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #ifndef WIDGET_H #define WIDGET_H #include "kprogressbar.h" #include "kwidget.h" #include #include using namespace kdk; class Widget : public KWidget { Q_OBJECT public: Widget(QWidget *parent = nullptr); ~Widget(); private: KProgressBar *m_pVerticalBar; KProgressBar *m_pHorizontalBar; QPushButton *m_pStartBtn; QPushButton *m_pStopBtn; QPushButton *m_pRestoreBtn; QTimer *m_pTimer; }; #endif // WIDGET_H libkysdk-applications/kysdk-qtwidgets/test/testprogressbar/widget.cpp0000664000175000017500000000702515104543305025341 0ustar fengfeng/* * * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #include "widget.h" #include #include #include Widget::Widget(QWidget *parent) : KWidget(parent) { m_pTimer = new QTimer(this); m_pTimer->setInterval(50); QVBoxLayout *vLayout = new QVBoxLayout(this); QHBoxLayout *tmpLayout = new QHBoxLayout(); m_pVerticalBar = new KProgressBar(this); m_pVerticalBar->setOrientation(Qt::Vertical); // 设置KProgressBar方向 m_pVerticalBar->setTextVisible(false); m_pVerticalBar->setRange(0, 100); m_pVerticalBar->setValue(50); tmpLayout->addWidget(m_pVerticalBar); vLayout->addLayout(tmpLayout); QHBoxLayout *hLayout = new QHBoxLayout(this); m_pHorizontalBar = new KProgressBar(this); m_pHorizontalBar->setRange(0, 100); m_pHorizontalBar->setValue(50); hLayout->addWidget(m_pHorizontalBar); vLayout->addLayout(hLayout); hLayout = new QHBoxLayout(this); m_pStartBtn = new QPushButton(this); m_pStartBtn->setText("开始"); m_pStopBtn = new QPushButton(this); m_pStopBtn->setText("停止"); m_pRestoreBtn = new QPushButton(this); m_pRestoreBtn->setText("恢复"); hLayout->addStretch(); hLayout->addWidget(m_pStartBtn); hLayout->addWidget(m_pStopBtn); hLayout->addWidget(m_pRestoreBtn); hLayout->addStretch(); vLayout->addLayout(hLayout); baseBar()->setLayout(vLayout); connect(m_pTimer, &QTimer::timeout, this, [=]() { if (m_pVerticalBar->value() != m_pVerticalBar->maximum()) m_pVerticalBar->setValue(m_pVerticalBar->value() + 1); else { m_pVerticalBar->setValue(m_pVerticalBar->minimum()); m_pVerticalBar->setState(ProgressBarState::NormalProgress); // 设置KprogressBar状态 } if (m_pHorizontalBar->value() != m_pHorizontalBar->maximum()) m_pHorizontalBar->setValue(m_pHorizontalBar->value() + 1); else { m_pHorizontalBar->setValue(m_pHorizontalBar->minimum()); m_pHorizontalBar->setState(ProgressBarState::NormalProgress); } }); connect(m_pStartBtn, &QPushButton::clicked, this, [=]() { if (!m_pTimer->isActive()) m_pTimer->start(); // qDebug() << m_pVerticalBar->text(); //获取文本值 }); connect(m_pStopBtn, &QPushButton::clicked, this, [=]() { m_pTimer->stop(); m_pVerticalBar->setState(ProgressBarState::FailedProgress); m_pHorizontalBar->setState(ProgressBarState::FailedProgress); }); connect(m_pRestoreBtn, &QPushButton::clicked, this, [=]() { m_pTimer->start(); m_pVerticalBar->setValue(0); m_pVerticalBar->setState(ProgressBarState::NormalProgress); m_pHorizontalBar->setValue(0); m_pHorizontalBar->setState(ProgressBarState::NormalProgress); }); } Widget::~Widget() { } libkysdk-applications/kysdk-qtwidgets/test/testprogressbar/main.cpp0000664000175000017500000000244115104543305024777 0ustar fengfeng/* * * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #include "widget.h" #include #include int main(int argc, char *argv[]) { QApplication a(argc, argv); QTranslator trans; QString locale = QLocale::system().name(); if (locale == "zh_CN") { if (trans.load(":/translations/gui_zh_CN.qm")) { a.installTranslator(&trans); } } if (locale == "bo_CN") { if (trans.load(":/translations/gui_bo_CN.qm")) { a.installTranslator(&trans); } } Widget w; w.show(); return a.exec(); } libkysdk-applications/kysdk-qtwidgets/test/testprogressbar/testprogressbar.pro0000664000175000017500000000200215104543305027313 0ustar fengfengQT += core gui greaterThan(QT_MAJOR_VERSION, 4): QT += widgets CONFIG += link_pkgconfig PKGCONFIG += kysdk-qtwidgets kysdk-widgetutils CONFIG += c++17 # The following define makes your compiler emit warnings if you use # any Qt feature that has been marked deprecated (the exact warnings # depend on your compiler). Please consult the documentation of the # deprecated API in order to know how to port your code away from it. DEFINES += QT_DEPRECATED_WARNINGS # You can also make your code fail to compile if it uses deprecated APIs. # In order to do so, uncomment the following line. # You can also select to disable deprecated APIs only up to a certain version of Qt. #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 SOURCES += \ main.cpp \ widget.cpp HEADERS += \ widget.h # Default rules for deployment. qnx: target.path = /tmp/$${TARGET}/bin else: unix:!android: target.path = /opt/$${TARGET}/bin !isEmpty(target.path): INSTALLS += target libkysdk-applications/kysdk-qtwidgets/test/testprogressdialog/0000775000175000017500000000000015104543305024041 5ustar fengfenglibkysdk-applications/kysdk-qtwidgets/test/testprogressdialog/widget.h0000664000175000017500000000176015104543305025501 0ustar fengfeng/* * * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #ifndef WIDGET_H #define WIDGET_H #include "kprogressdialog.h" #include "kwidget.h" using namespace kdk; class Widget : public KWidget { Q_OBJECT public: Widget(QWidget *parent = nullptr); ~Widget(); }; #endif // WIDGET_H libkysdk-applications/kysdk-qtwidgets/test/testprogressdialog/testprogressdialog.pro0000664000175000017500000000200115104543305030500 0ustar fengfengQT += core gui greaterThan(QT_MAJOR_VERSION, 4): QT += widgets CONFIG += link_pkgconfig PKGCONFIG += kysdk-qtwidgets kysdk-widgetutils CONFIG += c++17 # The following define makes your compiler emit warnings if you use # any Qt feature that has been marked deprecated (the exact warnings # depend on your compiler). Please consult the documentation of the # deprecated API in order to know how to port your code away from it. DEFINES += QT_DEPRECATED_WARNINGS # You can also make your code fail to compile if it uses deprecated APIs. # In order to do so, uncomment the following line. # You can also select to disable deprecated APIs only up to a certain version of Qt. #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 SOURCES += \ main.cpp \ widget.cpp HEADERS += \ widget.h # Default rules for deployment. qnx: target.path = /tmp/$${TARGET}/bin else: unix:!android: target.path = /opt/$${TARGET}/bin !isEmpty(target.path): INSTALLS += target libkysdk-applications/kysdk-qtwidgets/test/testprogressdialog/widget.cpp0000664000175000017500000000345015104543305026032 0ustar fengfeng/* * * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #include "widget.h" #include "kprogressbar.h" #include #include using namespace kdk; Widget::Widget(QWidget *parent) : KWidget(parent) { KProgressDialog *progressDialog = new KProgressDialog(tr("运行中"), tr("取消"), 0, 100, this); progressDialog->setSubContent("正在下载..."); // 设置次级内容 progressDialog->setSuffix("MB"); // 设置detail的后缀 progressDialog->setWindowTitle("进度对话框"); // 设置窗口标题 progressDialog->setWindowIcon("kylin-music"); // 设置窗口图标 progressDialog->setValue(98); // 设置当前进度值 progressDialog->setShowDetail(true); // 设置是否显示详细信息 progressDialog->setAutoReset(false); // 设置进度条是否重置 QPushButton *pBtn = new QPushButton("显示", this); QVBoxLayout *vLayout = new QVBoxLayout(this); vLayout->addWidget(pBtn); baseBar()->setLayout(vLayout); connect(pBtn, &QPushButton::clicked, this, [=]() { progressDialog->show(); }); } Widget::~Widget() { } libkysdk-applications/kysdk-qtwidgets/test/testprogressdialog/main.cpp0000664000175000017500000000254415104543305025476 0ustar fengfeng/* * * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #include "widget.h" #include "kwidgetutils.h" #include #include int main(int argc, char *argv[]) { kdk::KWidgetUtils::highDpiScaling(); QApplication a(argc, argv); QTranslator trans; QString locale = QLocale::system().name(); if (locale == "zh_CN") { if (trans.load(":/translations/gui_zh_CN.qm")) { a.installTranslator(&trans); } } if (locale == "bo_CN") { if (trans.load(":/translations/gui_bo_CN.qm")) { a.installTranslator(&trans); } } Widget w; w.show(); return a.exec(); } libkysdk-applications/kysdk-qtwidgets/test/testWidget/0000775000175000017500000000000015104543305022240 5ustar fengfenglibkysdk-applications/kysdk-qtwidgets/test/testWidget/testwidget.cpp0000664000175000017500000002475615104543305025145 0ustar fengfeng/* * * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "kaboutdialog.h" #include "kbadge.h" #include "kballontip.h" #include "kborderbutton.h" #include "kborderlessbutton.h" #include "kinputdialog.h" #include "knavigationbar.h" #include "kpasswordedit.h" #include "kpixmapcontainer.h" #include "kprogressbar.h" #include "kprogressdialog.h" #include "ksearchlineedit.h" #include "ksecuritylevelbar.h" #include "kslider.h" #include "kswitchbutton.h" #include "ktabbar.h" #include "ktoolbutton.h" #include "kuninstalldialog.h" #include "kwindowbuttonbar.h" #include "testwidget.h" #include "xatom-helper.h" TestWidget::TestWidget(QWidget *parent) : KWidget(parent) { setMinimumSize(640, 800); this->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); // 窗体显示在中间 // QDesktopWidget *screenResolution = QApplication::desktop(); // this->move((screenResolution->width() - this->width()) / 2, (screenResolution->height() - this->height()) / 2); QScreen *primaryScreen = QGuiApplication::primaryScreen(); if (primaryScreen) { QRect screenGeometry = primaryScreen->availableGeometry(); this->move((screenGeometry.width() - this->width()) / 2, (screenGeometry.height() - this->height()) / 2); } this->setWindowTitle("testWindow"); KBorderButton *pLeftBtn = new KBorderButton(this); pLeftBtn->setText("Left"); KSwitchButton *pSwitchBtn1 = new KSwitchButton(this); pSwitchBtn1->setFixedSize(100, 26); pSwitchBtn1->setEnabled(false); KSwitchButton *pSwitchBtn2 = new KSwitchButton(this); pSwitchBtn2->setFixedSize(100, 26); KBorderButton *pRightBtn = new KBorderButton(this); pRightBtn->setText("Right"); // pRightBtn->setEnabled(false); QIcon icon = QIcon::fromTheme("edit-find-symbolic"); pRightBtn->setIcon(icon); KSearchLineEdit *pSearchBar = new KSearchLineEdit(this); // 默认是带completer的,如果不需要 可以设置为空 pSearchBar->setCompleter(nullptr); QVBoxLayout *vLayout = new QVBoxLayout(); QHBoxLayout *hLayout = new QHBoxLayout(); vLayout->addLayout(hLayout); vLayout->addStretch(); vLayout->addWidget(pSearchBar); hLayout = new QHBoxLayout(); KSlider *slider = new KSlider(Qt::Horizontal, this); slider->setSliderType(KSliderType::NodeSlider); slider->setRange(0, 100); slider->setTickInterval(20); slider->setValue(33); slider->setTickPosition(QSlider::TicksBothSides); hLayout->addWidget(slider); vLayout->addLayout(hLayout); hLayout = new QHBoxLayout(); hLayout->addWidget(pLeftBtn); hLayout->addWidget(pRightBtn); vLayout->addLayout(hLayout); hLayout = new QHBoxLayout(); hLayout->addWidget(pSwitchBtn1); hLayout->addWidget(pSwitchBtn2); vLayout->addLayout(hLayout); KBorderlessButton *borderlessButton1 = new KBorderlessButton(this); borderlessButton1->setText("borderless1"); KProgressDialog *progress1 = new KProgressDialog(this); connect(borderlessButton1, &KBorderlessButton::clicked, progress1, &QProgressDialog::show); progress1->setValue(20); progress1->setShowDetail(true); KBorderlessButton *borderlessButton2 = new KBorderlessButton(this); borderlessButton2->setText("borderless2"); KProgressDialog *progress2 = new KProgressDialog(tr("下载"), tr("取消"), 0, 100, this); progress2->setSubContent("下载中..."); progress2->setSuffix("MB"); progress2->setWindowTitle("进度对话框"); progress2->setWindowIcon("kylin-music"); progress2->setValue(50); progress2->setShowDetail(false); connect(borderlessButton2, &KBorderlessButton::clicked, progress2, &KProgressDialog::show); hLayout = new QHBoxLayout(); hLayout->addWidget(borderlessButton1); hLayout->addWidget(borderlessButton2); vLayout->addLayout(hLayout); KBorderlessButton *borderlessButton3 = new KBorderlessButton(QIcon::fromTheme("edit-find-symbolic"), this); KBorderlessButton *borderlessButton4 = new KBorderlessButton(QIcon::fromTheme("edit-find-symbolic"), "borderless4", this); hLayout = new QHBoxLayout(); hLayout->addWidget(borderlessButton3); hLayout->addWidget(borderlessButton4); vLayout->addLayout(hLayout); KPixmapContainer *container = new KPixmapContainer(this); // QPixmap pixmap; // pixmap.load("/home/sunzhen/my.jpg"); // pixmap = pixmap.scaled(36,36); // container->setPixmap(pixmap); container->setPixmap(QIcon::fromTheme("edit-find-symbolic").pixmap(36, 36)); container->setValue(1000); hLayout = new QHBoxLayout(); hLayout->addWidget(container); vLayout->addLayout(hLayout); KPasswordEdit *edit = new KPasswordEdit(this); edit->setFixedWidth(200); edit->setText("adad"); // edit->setLoading(true); // edit->setState(LoginState::LoginFailed); edit->setClearButtonEnabled(true); KPasswordEdit *edit2 = new KPasswordEdit(this); edit2->setFixedWidth(200); edit2->setText("12313"); edit2->setEnabled(false); edit2->setClearButtonEnabled(true); hLayout = new QHBoxLayout(); hLayout->addWidget(edit); hLayout->addWidget(edit2); vLayout->addLayout(hLayout); KProgressBar *progressbar = new KProgressBar(this); progressbar->setRange(0, 100); progressbar->setValue(100); progressbar->setTextVisible(true); progressbar->setAlignment(Qt::AlignRight); hLayout = new QHBoxLayout(); hLayout->addWidget(progressbar); vLayout->addLayout(hLayout); // KProgressBar* progressbar2 = new KProgressBar(this); // progressbar2->setOrientation(Qt::Vertical); // progressbar2->setValue(50); // progressbar2->setTextVisible(true); // progressbar2->setAlignment(Qt::AlignRight); // hLayout = new QHBoxLayout(); // hLayout->addWidget(progressbar2); // vLayout->addLayout(hLayout); KBallonTip *ballonTip = new KBallonTip("这是一段操作信息描述的文字,这是一段操作信息描述的文字,这是一段操作信息描述的文字,这是一段操作信息描述的文字", TipType::Error, this); ballonTip->setFixedWidth(400); hLayout = new QHBoxLayout(); hLayout->addWidget(ballonTip); vLayout->addLayout(hLayout); // ballonTip->setSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); KSecurityLevelBar *barrrr = new KSecurityLevelBar(this); barrrr->setSecurityLevel(SecurityLevel::Medium); hLayout = new QHBoxLayout(); hLayout->addWidget(barrrr); vLayout->addLayout(hLayout); KBadge *badge1 = new KBadge(this); badge1->setValue(-9); // badge1->setFontSize(20); KBadge *badge2 = new KBadge(this); badge2->setValue(99); // badge2->setFontSize(10); KBadge *badge3 = new KBadge(this); badge3->setValue(999); // badge3->setMinimumHeight(50); badge3->setFontSize(15); KBadge *badge4 = new KBadge(this); badge4->setValue(9991); // badge4->setColor(QColor(255,0,0)); hLayout = new QHBoxLayout(); hLayout->addWidget(badge1); hLayout->addWidget(badge2); hLayout->addWidget(badge3); hLayout->addWidget(badge4); vLayout->addLayout(hLayout); KTabBar *tabBar1 = new KTabBar(KTabBarStyle::SegmentLight, this); tabBar1->addTab("first"); tabBar1->addTab("second"); tabBar1->addTab("third"); KTabBar *tabBar2 = new KTabBar(KTabBarStyle::SegmentDark, this); tabBar2->addTab("first"); tabBar2->addTab("second"); tabBar2->addTab("third"); KTabBar *tabBar3 = new KTabBar(KTabBarStyle::Sliding, this); tabBar3->addTab("first"); tabBar3->addTab("second"); tabBar3->addTab("third"); KUninstallDialog *uninstallDialog = new KUninstallDialog("browser360-cn-stable", "104", this); KAboutDialog *aboutDialog = new KAboutDialog(this, QIcon::fromTheme("edit-find-symbolic"), "麒麟引导修复工具", tr("Version:2020.1.0")); connect(pLeftBtn, &KBorderButton::clicked, uninstallDialog, &KUninstallDialog::show); connect(pRightBtn, &KBorderButton::clicked, aboutDialog, &KAboutDialog::show); vLayout->addWidget(tabBar1); vLayout->addWidget(tabBar2); vLayout->addWidget(tabBar3); vLayout->addStretch(); baseBar()->setLayout(vLayout); vLayout = new QVBoxLayout(); KNavigationBar *bar = new KNavigationBar(this); QStandardItem *item1 = new QStandardItem(QIcon::fromTheme("system-computer-symbolic"), tr("一级导航")); QStandardItem *item2 = new QStandardItem(QIcon::fromTheme("stock-people-symbolic"), tr("二级导航")); QList list; QStandardItem *item3 = new QStandardItem(QIcon::fromTheme("camera-switch-symbolic"), tr("一组一级导航")); QStandardItem *item4 = new QStandardItem(QIcon::fromTheme("media-eq-symbolic"), tr("一组一级导航")); list << item3 << item4; bar->addItem(item1); bar->addSubItem(item2); bar->addGroupItems(list, "测试一组"); QStandardItem *item5 = new QStandardItem(QIcon::fromTheme("camera-switch-symbolic"), tr("二组一级导航")); QStandardItem *item6 = new QStandardItem(QIcon::fromTheme("media-eq-symbolic"), tr("二组一级导航")); QStandardItem *item7 = new QStandardItem(QIcon::fromTheme("media-eq-symbolic"), tr("二组二级导航")); QList list2; list2 << item5 << item6; bar->addGroupItems(list2, "测试二组"); bar->addSubItem(item7); vLayout->addWidget(bar); sideBar()->setLayout(vLayout); this->setLayoutType(HorizontalType); } TestWidget::~TestWidget() { } libkysdk-applications/kysdk-qtwidgets/test/testWidget/testwidget.h0000664000175000017500000000202315104543305024571 0ustar fengfeng/* * * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #ifndef TESTWIDGET_H #define TESTWIDGET_H #include "kwidget.h" #include using namespace kdk; class TestWidget : public KWidget { Q_OBJECT public: TestWidget(QWidget *parent = nullptr); ~TestWidget(); QSlider *slider; }; #endif // TESTWIDGET_H libkysdk-applications/kysdk-qtwidgets/test/testWidget/testWidget.pro0000664000175000017500000000201115104543305025077 0ustar fengfengQT += core gui greaterThan(QT_MAJOR_VERSION, 4): QT += widgets CONFIG += c++17 CONFIG += link_pkgconfig PKGCONFIG += kysdk-widgetutils kysdk-qtwidgets # The following define makes your compiler emit warnings if you use # any Qt feature that has been marked deprecated (the exact warnings # depend on your compiler). Please consult the documentation of the # deprecated API in order to know how to port your code away from it. DEFINES += QT_DEPRECATED_WARNINGS # You can also make your code fail to compile if it uses deprecated APIs. # In order to do so, uncomment the following line. # You can also select to disable deprecated APIs only up to a certain version of Qt. #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 SOURCES += \ main.cpp \ testwidget.cpp HEADERS += \ testwidget.h # Default rules for deployment. qnx: target.path = /tmp/$${TARGET}/bin else: unix:!android: target.path = /opt/$${TARGET}/bin !isEmpty(target.path): INSTALLS += target libkysdk-applications/kysdk-qtwidgets/test/testWidget/main.cpp0000664000175000017500000000312015104543305023664 0ustar fengfeng/* * * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #include "kdialog.h" #include "kprogressdialog.h" #include "kwidget.h" #include "kwidgetutils.h" #include "testwidget.h" #include #include #include #include using namespace kdk; int main(int argc, char *argv[]) { kdk::KWidgetUtils::highDpiScaling(); QApplication a(argc, argv); QTranslator trans; QString locale = QLocale::system().name(); if (locale == "zh_CN") { if (trans.load(":/translations/gui_zh_CN.qm")) { a.installTranslator(&trans); } } if (locale == "bo_CN") { if (trans.load(":/translations/gui_bo_CN.qm")) { a.installTranslator(&trans); } } TestWidget widget; widget.setWidgetName("TestWidget"); widget.setIcon("kylin-music"); widget.show(); return a.exec(); } libkysdk-applications/kysdk-qtwidgets/test/testbreadcrumb/0000775000175000017500000000000015104543305023123 5ustar fengfenglibkysdk-applications/kysdk-qtwidgets/test/testbreadcrumb/testbreadcrumb.pro0000664000175000017500000000200115104543305026644 0ustar fengfengQT += core gui greaterThan(QT_MAJOR_VERSION, 4): QT += widgets CONFIG += c++17 CONFIG += link_pkgconfig PKGCONFIG += kysdk-qtwidgets kysdk-widgetutils # The following define makes your compiler emit warnings if you use # any Qt feature that has been marked deprecated (the exact warnings # depend on your compiler). Please consult the documentation of the # deprecated API in order to know how to port your code away from it. DEFINES += QT_DEPRECATED_WARNINGS # You can also make your code fail to compile if it uses deprecated APIs. # In order to do so, uncomment the following line. # You can also select to disable deprecated APIs only up to a certain version of Qt. #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 SOURCES += \ main.cpp \ widget.cpp HEADERS += \ widget.h # Default rules for deployment. qnx: target.path = /tmp/$${TARGET}/bin else: unix:!android: target.path = /opt/$${TARGET}/bin !isEmpty(target.path): INSTALLS += target libkysdk-applications/kysdk-qtwidgets/test/testbreadcrumb/widget.h0000664000175000017500000000177615104543305024572 0ustar fengfeng/* * * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #ifndef WIDGET_H #define WIDGET_H #include "kbreadcrumb.h" #include "kwidget.h" #include using namespace kdk; class Widget : public KWidget { Q_OBJECT public: Widget(QWidget *parent = nullptr); ~Widget(); }; #endif // WIDGET_H libkysdk-applications/kysdk-qtwidgets/test/testbreadcrumb/widget.cpp0000664000175000017500000000410115104543305025106 0ustar fengfeng/* * * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #include "widget.h" #include Widget::Widget(QWidget *parent) : KWidget(parent) { QVBoxLayout *mainLayout = new QVBoxLayout; QHBoxLayout *hLayout = new QHBoxLayout; KBreadCrumb *crumb = new KBreadCrumb(this); // 默认是true crumb->setFlat(true); crumb->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); crumb->addTab("页面目录一"); crumb->addTab("页面目录二"); crumb->addTab("页面目录三"); crumb->addTab("短的"); crumb->addTab("长的长的长的长的长的长的"); crumb->setIcon(QIcon::fromTheme("dialog-info")); // 设置KBreadCrumb的图标 hLayout->addWidget(crumb); mainLayout->addLayout(hLayout); hLayout = new QHBoxLayout; KBreadCrumb *crumb2 = new KBreadCrumb(this); // 默认是true crumb->setFlat(false); // 设置KBreadCrumb是否为flat类型 crumb2->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); crumb2->addTab("页面目录一"); crumb2->addTab("页面目录二"); crumb2->addTab("页面目录三"); crumb2->addTab("短的"); crumb2->addTab("长的很长的特别长的特别特别长的"); crumb2->setIcon(QIcon::fromTheme("dialog-warning")); hLayout->addWidget(crumb2); mainLayout->addLayout(hLayout); baseBar()->setLayout(mainLayout); } Widget::~Widget() { } libkysdk-applications/kysdk-qtwidgets/test/testbreadcrumb/main.cpp0000664000175000017500000000254315104543305024557 0ustar fengfeng/* * * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #include "kwidgetutils.h" #include "widget.h" #include #include int main(int argc, char *argv[]) { kdk::KWidgetUtils::highDpiScaling(); QApplication a(argc, argv); QTranslator trans; QString locale = QLocale::system().name(); if (locale == "zh_CN") { if (trans.load(":/translations/gui_zh_CN.qm")) { a.installTranslator(&trans); } } if (locale == "bo_CN") { if (trans.load(":/translations/gui_bo_CN.qm")) { a.installTranslator(&trans); } } Widget w; w.show(); return a.exec(); } libkysdk-applications/kysdk-qtwidgets/test/testTag/0000775000175000017500000000000015104543305021530 5ustar fengfenglibkysdk-applications/kysdk-qtwidgets/test/testTag/widget.h0000664000175000017500000000172315104515306023167 0ustar fengfeng/* * * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #ifndef WIDGET_H #define WIDGET_H #include "kwidget.h" using namespace kdk; class Widget : public KWidget { Q_OBJECT public: Widget(QWidget *parent = nullptr); ~Widget(); }; #endif // WIDGET_H libkysdk-applications/kysdk-qtwidgets/test/testTag/widget.cpp0000664000175000017500000000472715104543305023531 0ustar fengfeng/* * * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #include "widget.h" #include "kbreadcrumb.h" #include "ktag.h" #include #include #include #include Widget::Widget(QWidget *parent) : KWidget(parent) { QVBoxLayout *vLayout = new QVBoxLayout; KTag *tag1 = new KTag(this); tag1->setText("tag1"); // 设置tag文本 // tag1->setTagStyle(TagStyle::HighlightTag); KTag *tag2 = new KTag(this); tag2->setText("tag2"); tag2->setTagStyle(TagStyle::BoderTag); // 设置tag的style,有HighlightTag,BoderTag,BaseBoderTag,GrayTag四种 KTag *tag3 = new KTag(this); tag3->setText("tag3"); tag3->setTagStyle(TagStyle::BaseBoderTag); KTag *tag4 = new KTag(this); tag4->setText("tag4"); tag4->setTagStyle(TagStyle::GrayTag); QHBoxLayout *hLayout = new QHBoxLayout; hLayout->addWidget(tag1); hLayout->addWidget(tag2); hLayout->addWidget(tag3); hLayout->addWidget(tag4); vLayout->addLayout(hLayout); hLayout = new QHBoxLayout; KTag *tag5 = new KTag(this); tag5->setText("tag5"); tag5->setClosable(true); // 设置tag是否可以关闭 KTag *tag6 = new KTag(this); tag6->setClosable(true); tag6->setText("tag6"); tag6->setTagStyle(TagStyle::BoderTag); KTag *tag7 = new KTag(this); tag7->setClosable(true); tag7->setText("tag7"); tag7->setTagStyle(TagStyle::BaseBoderTag); KTag *tag8 = new KTag(this); tag8->setClosable(true); tag8->setText("tag8"); tag8->setTagStyle(TagStyle::GrayTag); hLayout->addWidget(tag5); hLayout->addWidget(tag6); hLayout->addWidget(tag7); hLayout->addWidget(tag8); vLayout->addLayout(hLayout); baseBar()->setLayout(vLayout); sideBar()->hide(); } Widget::~Widget() { } libkysdk-applications/kysdk-qtwidgets/test/testTag/main.cpp0000664000175000017500000000254315104543305023164 0ustar fengfeng/* * * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #include "kwidgetutils.h" #include "widget.h" #include #include int main(int argc, char *argv[]) { kdk::KWidgetUtils::highDpiScaling(); QApplication a(argc, argv); QTranslator trans; QString locale = QLocale::system().name(); if (locale == "zh_CN") { if (trans.load(":/translations/gui_zh_CN.qm")) { a.installTranslator(&trans); } } if (locale == "bo_CN") { if (trans.load(":/translations/gui_bo_CN.qm")) { a.installTranslator(&trans); } } Widget w; w.show(); return a.exec(); } libkysdk-applications/kysdk-qtwidgets/test/testTag/testTag.pro0000664000175000017500000000200115104543305023656 0ustar fengfengQT += core gui greaterThan(QT_MAJOR_VERSION, 4): QT += widgets CONFIG += c++17 CONFIG += link_pkgconfig PKGCONFIG += kysdk-qtwidgets kysdk-widgetutils # The following define makes your compiler emit warnings if you use # any Qt feature that has been marked deprecated (the exact warnings # depend on your compiler). Please consult the documentation of the # deprecated API in order to know how to port your code away from it. DEFINES += QT_DEPRECATED_WARNINGS # You can also make your code fail to compile if it uses deprecated APIs. # In order to do so, uncomment the following line. # You can also select to disable deprecated APIs only up to a certain version of Qt. #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 SOURCES += \ main.cpp \ widget.cpp HEADERS += \ widget.h # Default rules for deployment. qnx: target.path = /tmp/$${TARGET}/bin else: unix:!android: target.path = /opt/$${TARGET}/bin !isEmpty(target.path): INSTALLS += target libkysdk-applications/kysdk-qtwidgets/test/testkpressbutton/0000775000175000017500000000000015104543305023560 5ustar fengfenglibkysdk-applications/kysdk-qtwidgets/test/testkpressbutton/testkpressbutton.pro0000664000175000017500000000200115104543305027736 0ustar fengfengQT += core gui greaterThan(QT_MAJOR_VERSION, 4): QT += widgets CONFIG += c++17 CONFIG += link_pkgconfig PKGCONFIG += kysdk-qtwidgets kysdk-widgetutils # The following define makes your compiler emit warnings if you use # any Qt feature that has been marked deprecated (the exact warnings # depend on your compiler). Please consult the documentation of the # deprecated API in order to know how to port your code away from it. DEFINES += QT_DEPRECATED_WARNINGS # You can also make your code fail to compile if it uses deprecated APIs. # In order to do so, uncomment the following line. # You can also select to disable deprecated APIs only up to a certain version of Qt. #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 SOURCES += \ main.cpp \ widget.cpp HEADERS += \ widget.h # Default rules for deployment. qnx: target.path = /tmp/$${TARGET}/bin else: unix:!android: target.path = /opt/$${TARGET}/bin !isEmpty(target.path): INSTALLS += target libkysdk-applications/kysdk-qtwidgets/test/testkpressbutton/widget.h0000664000175000017500000000170015104543305025212 0ustar fengfeng/* * * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhenyu Wang * */ #ifndef WIDGET_H #define WIDGET_H #include class Widget : public QWidget { Q_OBJECT public: Widget(QWidget *parent = nullptr); ~Widget(); }; #endif // WIDGET_H libkysdk-applications/kysdk-qtwidgets/test/testkpressbutton/widget.cpp0000664000175000017500000000530315104543305025550 0ustar fengfeng/* * * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhenyu Wang * */ #include "widget.h" #include "kpressbutton.h" #include "kwidget.h" #include #include using namespace kdk; Widget::Widget(QWidget *parent) : QWidget(parent) { KPressButton *button1 = new KPressButton(); button1->setIcon(QIcon::fromTheme("stock-people-symbolic")); button1->setBorderRadius(20); button1->setTranslucent(true); button1->setChecked(true); KPressButton *button2 = new KPressButton(); button2->setCheckable(false); QHBoxLayout *layout = new QHBoxLayout(); layout->addWidget(button1); layout->addWidget(button2); KPressButton *button3 = new KPressButton(this); KPressButton *button4 = new KPressButton(); button4->setFixedSize(36, 36); button4->setButtonType(KPressButton::CircleType); button4->setIcon(QIcon::fromTheme("system-computer-symbolic")); QHBoxLayout *layout1 = new QHBoxLayout(); layout1->addWidget(button3); layout1->addWidget(button4); KPressButton *button5 = new KPressButton(); button5->setLoaingStatus(true); button5->setChecked(true); KPressButton *button6 = new KPressButton(); QHBoxLayout *layout2 = new QHBoxLayout(); layout2->addWidget(button5); layout2->addWidget(button6); QVBoxLayout *vlayout = new QVBoxLayout(this); vlayout->addLayout(layout); vlayout->addLayout(layout1); vlayout->addLayout(layout2); connect(button4, &KPressButton::clicked, this, [=]() { if (button4->isChecked()) button4->setLoaingStatus(true); else button4->setLoaingStatus(false); }); connect(button5, &KPressButton::clicked, this, [=]() { if (button5->isChecked()) button5->setLoaingStatus(true); else button5->setLoaingStatus(false); }); connect(button2, &KPressButton::clicked, this, [=](bool flag) { qDebug() << flag << button2->isChecked() << button2->isCheckable(); }); } Widget::~Widget() { } libkysdk-applications/kysdk-qtwidgets/test/testkpressbutton/main.cpp0000664000175000017500000000255115104543305025213 0ustar fengfeng/* * * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhenyu Wang * */ #include "widget.h" #include "kwidgetutils.h" #include #include int main(int argc, char *argv[]) { kdk::KWidgetUtils::highDpiScaling(); QApplication a(argc, argv); QTranslator trans; QString locale = QLocale::system().name(); if (locale == "zh_CN") { if (trans.load(":/translations/gui_zh_CN.qm")) { a.installTranslator(&trans); } } if (locale == "bo_CN") { if (trans.load(":/translations/gui_bo_CN.qm")) { a.installTranslator(&trans); } } Widget w; w.show(); return a.exec(); } libkysdk-applications/kysdk-qtwidgets/test/testProgressCircle/0000775000175000017500000000000015104543305023743 5ustar fengfenglibkysdk-applications/kysdk-qtwidgets/test/testProgressCircle/testProgressCircle.pro0000664000175000017500000000200115104543305030304 0ustar fengfengQT += core gui greaterThan(QT_MAJOR_VERSION, 4): QT += widgets CONFIG += c++17 CONFIG += link_pkgconfig PKGCONFIG += kysdk-qtwidgets kysdk-widgetutils # The following define makes your compiler emit warnings if you use # any Qt feature that has been marked deprecated (the exact warnings # depend on your compiler). Please consult the documentation of the # deprecated API in order to know how to port your code away from it. DEFINES += QT_DEPRECATED_WARNINGS # You can also make your code fail to compile if it uses deprecated APIs. # In order to do so, uncomment the following line. # You can also select to disable deprecated APIs only up to a certain version of Qt. #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 SOURCES += \ main.cpp \ widget.cpp HEADERS += \ widget.h # Default rules for deployment. qnx: target.path = /tmp/$${TARGET}/bin else: unix:!android: target.path = /opt/$${TARGET}/bin !isEmpty(target.path): INSTALLS += target libkysdk-applications/kysdk-qtwidgets/test/testProgressCircle/widget.h0000664000175000017500000000200315104543305025372 0ustar fengfeng/* * * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #ifndef WIDGET_H #define WIDGET_H #include "kwidget.h" #include using namespace kdk; class Widget : public KWidget { Q_OBJECT public: Widget(QWidget *parent = nullptr); ~Widget(); private: QTimer *m_pTimer; }; #endif // WIDGET_H libkysdk-applications/kysdk-qtwidgets/test/testProgressCircle/widget.cpp0000664000175000017500000000563115104543305025737 0ustar fengfeng/* * * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #include "widget.h" #include "kprogresscircle.h" #include #include Widget::Widget(QWidget *parent) : KWidget(parent) { QVBoxLayout *vLayout = new QVBoxLayout; QHBoxLayout *hLayout = new QHBoxLayout; KProgressCircle *circle1 = new KProgressCircle(this); circle1->setValue(40); // 设置初始值 hLayout->addWidget(circle1); KProgressCircle *circle2 = new KProgressCircle(this); circle2->setValue(10); circle2->setState(ProgressBarState::FailedProgress); // 设置失败状态 hLayout->addWidget(circle2); KProgressCircle *circle3 = new KProgressCircle(this); circle3->setValue(75); circle3->setState(ProgressBarState::SuccessProgress); // 设置成功状态 hLayout->addWidget(circle3); vLayout->addLayout(hLayout); hLayout = new QHBoxLayout; KProgressCircle *circle4 = new KProgressCircle(this); circle4->setValue(40); circle4->setTextVisible(false); // 设置文本不可见 hLayout->addWidget(circle4); KProgressCircle *circle5 = new KProgressCircle(this); circle5->setValue(93); circle5->setTextVisible(false); circle5->setState(ProgressBarState::FailedProgress); hLayout->addWidget(circle5); KProgressCircle *circle6 = new KProgressCircle(this); circle6->setValue(75); circle6->setTextVisible(false); circle6->setState(ProgressBarState::SuccessProgress); hLayout->addWidget(circle6); vLayout->addLayout(hLayout); baseBar()->setLayout(vLayout); m_pTimer = new QTimer(this); m_pTimer->setInterval(20); connect(m_pTimer, &QTimer::timeout, circle1, [=]() { if (circle1->value() < circle1->maximum()) circle1->setValue(circle1->value() + 1); else { circle1->setValue(circle1->minimum()); circle1->setState(NormalProgress); } }); connect(m_pTimer, &QTimer::timeout, circle4, [=]() { if (circle4->value() < circle4->maximum()) circle4->setValue(circle4->value() + 1); else { circle4->setValue(circle4->minimum()); circle4->setState(NormalProgress); } }); m_pTimer->start(); } Widget::~Widget() { } libkysdk-applications/kysdk-qtwidgets/test/testProgressCircle/main.cpp0000664000175000017500000000254415104543305025400 0ustar fengfeng/* * * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #include "widget.h" #include "kwidgetutils.h" #include #include int main(int argc, char *argv[]) { kdk::KWidgetUtils::highDpiScaling(); QApplication a(argc, argv); QTranslator trans; QString locale = QLocale::system().name(); if (locale == "zh_CN") { if (trans.load(":/translations/gui_zh_CN.qm")) { a.installTranslator(&trans); } } if (locale == "bo_CN") { if (trans.load(":/translations/gui_bo_CN.qm")) { a.installTranslator(&trans); } } Widget w; w.show(); return a.exec(); } libkysdk-applications/kysdk-qtwidgets/test/testnavigationtrail/0000775000175000017500000000000015104543305024210 5ustar fengfenglibkysdk-applications/kysdk-qtwidgets/test/testnavigationtrail/widget.h0000664000175000017500000000167515104543305025655 0ustar fengfeng/* * * Copyright (C) 2024, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhenyu Wang * */ #ifndef WIDGET_H #define WIDGET_H #include class Widget : public QWidget { Q_OBJECT public: Widget(QWidget *parent = nullptr); ~Widget(); }; #endif // WIDGET_H libkysdk-applications/kysdk-qtwidgets/test/testnavigationtrail/widget.cpp0000664000175000017500000000347615104543305026211 0ustar fengfeng/* * * Copyright (C) 2024, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhenyu Wang * */ #include "widget.h" #include "knavigationtrail.h" #include using namespace kdk; Widget::Widget(QWidget *parent) : QWidget(parent) { QHBoxLayout *layout = new QHBoxLayout(this); KNavigationTrail *trail = new KNavigationTrail(); KCrumb *crumb1 = trail->crumb(); crumb1->addTab("页面目录一,页面目录一"); crumb1->addTab("页面目录二,页面目录二"); crumb1->addTab("页面目录三,页面目录三"); crumb1->addTab("页面目录四,页面目录四"); crumb1->addTab("页面目录五,页面目录五"); crumb1->setFlat(false); // crumb1->setIcon(QIcon::fromTheme("dialog-info")); //设置KBreadCrumb的图标 layout->addWidget(trail); connect(crumb1, &KCrumb::tabBarClicked, this, [=](int index) { if (index == 1) trail->setPosition(ButtonPosition::LeftOrRight); if (index == 2) trail->setPosition(ButtonPosition::LeftPosition); if (index == 3) trail->setPosition(ButtonPosition::RightPosition); }); } Widget::~Widget() { } libkysdk-applications/kysdk-qtwidgets/test/testnavigationtrail/main.cpp0000664000175000017500000000165015104543305025642 0ustar fengfeng/* * * Copyright (C) 2024, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhenyu Wang * */ #include "widget.h" #include int main(int argc, char *argv[]) { QApplication a(argc, argv); Widget w; w.show(); return a.exec(); } libkysdk-applications/kysdk-qtwidgets/test/testnavigationtrail/testnavigationtrail.pro0000664000175000017500000000200115104543305031016 0ustar fengfengQT += core gui greaterThan(QT_MAJOR_VERSION, 4): QT += widgets CONFIG += c++17 CONFIG += link_pkgconfig PKGCONFIG += kysdk-widgetutils kysdk-qtwidgets # The following define makes your compiler emit warnings if you use # any Qt feature that has been marked deprecated (the exact warnings # depend on your compiler). Please consult the documentation of the # deprecated API in order to know how to port your code away from it. DEFINES += QT_DEPRECATED_WARNINGS # You can also make your code fail to compile if it uses deprecated APIs. # In order to do so, uncomment the following line. # You can also select to disable deprecated APIs only up to a certain version of Qt. #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 SOURCES += \ main.cpp \ widget.cpp HEADERS += \ widget.h # Default rules for deployment. qnx: target.path = /tmp/$${TARGET}/bin else: unix:!android: target.path = /opt/$${TARGET}/bin !isEmpty(target.path): INSTALLS += target libkysdk-applications/kysdk-qtwidgets/test/testprogresslabel/0000775000175000017500000000000015104543305023661 5ustar fengfenglibkysdk-applications/kysdk-qtwidgets/test/testprogresslabel/testprogresslabel.pro0000664000175000017500000000200315104543305030142 0ustar fengfengQT += core gui greaterThan(QT_MAJOR_VERSION, 4): QT += widgets CONFIG += c++17 CONFIG += link_pkgconfig PKGCONFIG += kysdk-widgetutils kysdk-qtwidgets # The following define makes your compiler emit warnings if you use # any Qt feature that has been marked deprecated (the exact warnings # depend on your compiler). Please consult the documentation of the # deprecated API in order to know how to port your code away from it. DEFINES += QT_DEPRECATED_WARNINGS # You can also make your code fail to compile if it uses deprecated APIs. # In order to do so, uncomment the following line. # You can also select to disable deprecated APIs only up to a certain version of Qt. #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 SOURCES += \ main.cpp \ widget.cpp HEADERS += \ widget.h # Default rules for deployment. qnx: target.path = /tmp/$${TARGET}/bin else: unix:!android: target.path = /opt/$${TARGET}/bin !isEmpty(target.path): INSTALLS += target libkysdk-applications/kysdk-qtwidgets/test/testprogresslabel/widget.h0000664000175000017500000000167515104543305025326 0ustar fengfeng/* * * Copyright (C) 2024, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhenyu Wang * */ #ifndef WIDGET_H #define WIDGET_H #include class Widget : public QWidget { Q_OBJECT public: Widget(QWidget *parent = nullptr); ~Widget(); }; #endif // WIDGET_H libkysdk-applications/kysdk-qtwidgets/test/testprogresslabel/widget.cpp0000664000175000017500000000401215104543305025645 0ustar fengfeng/* * * Copyright (C) 2024, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhenyu Wang * */ #include "widget.h" #include "kprogresslabel.h" #include #include using namespace kdk; Widget::Widget(QWidget *parent) : QWidget(parent) { QVBoxLayout *vlayout = new QVBoxLayout(this); QHBoxLayout *layout = new QHBoxLayout(); KProgressLabel *label = new KProgressLabel(); QStringList list; list.append("11"); list.append("22"); list.append("33"); list.append("44"); list.append("55"); QStringList list2; list2.append("1"); list2.append("2"); list2.append("3"); list2.append("4"); list2.append("5"); label->setStringList(list); label->setCircleSize(QSize(24, 24)); label->setCurrentIndex(1); // label->setStyleSheet("background :red"); QPushButton *btn1 = new QPushButton(""); QPushButton *btn2 = new QPushButton(""); layout->addWidget(btn1); layout->addWidget(btn2); vlayout->addWidget(label); vlayout->addLayout(layout); connect(btn1, &QPushButton::clicked, this, [=] { label->setCurrentIndex(label->currentIndex() - 1); qDebug() << label->size(); }); connect(btn2, &QPushButton::clicked, this, [=] { label->setCurrentIndex(label->currentIndex() + 1); }); setFixedSize(600, 500); } Widget::~Widget() { } libkysdk-applications/kysdk-qtwidgets/test/testprogresslabel/main.cpp0000664000175000017500000000165015104543305025313 0ustar fengfeng/* * * Copyright (C) 2024, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhenyu Wang * */ #include "widget.h" #include int main(int argc, char *argv[]) { QApplication a(argc, argv); Widget w; w.show(); return a.exec(); } libkysdk-applications/kysdk-qtwidgets/test/testtabbar/0000775000175000017500000000000015104543305022250 5ustar fengfenglibkysdk-applications/kysdk-qtwidgets/test/testtabbar/testtabbar.pro0000664000175000017500000000200215104543305025117 0ustar fengfengQT += core gui greaterThan(QT_MAJOR_VERSION, 4): QT += widgets CONFIG += c++17 CONFIG += link_pkgconfig PKGCONFIG += kysdk-qtwidgets kysdk-widgetutils # The following define makes your compiler emit warnings if you use # any Qt feature that has been marked deprecated (the exact warnings # depend on your compiler). Please consult the documentation of the # deprecated API in order to know how to port your code away from it. DEFINES += QT_DEPRECATED_WARNINGS # You can also make your code fail to compile if it uses deprecated APIs. # In order to do so, uncomment the following line. # You can also select to disable deprecated APIs only up to a certain version of Qt. #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 SOURCES += \ main.cpp \ widget.cpp HEADERS += \ widget.h # Default rules for deployment. qnx: target.path = /tmp/$${TARGET}/bin else: unix:!android: target.path = /opt/$${TARGET}/bin !isEmpty(target.path): INSTALLS += target libkysdk-applications/kysdk-qtwidgets/test/testtabbar/widget.h0000664000175000017500000000172315104515306023707 0ustar fengfeng/* * * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #ifndef WIDGET_H #define WIDGET_H #include "kwidget.h" using namespace kdk; class Widget : public KWidget { Q_OBJECT public: Widget(QWidget *parent = nullptr); ~Widget(); }; #endif // WIDGET_H libkysdk-applications/kysdk-qtwidgets/test/testtabbar/widget.cpp0000664000175000017500000000733615104543305024250 0ustar fengfeng/* * * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #include "widget.h" #include "ktabbar.h" #include #include Widget::Widget(QWidget *parent) : KWidget(parent) { /* 测试说明 * 1.tabbar1-tabbar3测试三种样式的显示以及添加tab的功能(在tabbar的开始、中间和末尾位置添加图标、文字以及二者都存在的tab) * 2.tabbar4测试设置tabbar样式、修改tabbar圆角(0-20)以及设置背景色。 */ QWidget *w = new QWidget(); KTabBar *tabBar1 = new KTabBar(KTabBarStyle::SegmentLight, w); tabBar1->addTab(QIcon::fromTheme("kylin-music"), "Segment1"); tabBar1->addTab("Segment2"); tabBar1->addTab(QIcon::fromTheme("kylin-music"), ""); tabBar1->addTab("Segment4"); tabBar1->addTab("Segment5"); tabBar1->addTab("Segment6"); KTabBar *tabBar2 = new KTabBar(KTabBarStyle::SegmentDark, w); tabBar2->addTab("SegmentDark1"); tabBar2->addTab("SegmentDark2"); tabBar2->addTab(QIcon::fromTheme("kylin-music"), "SegmentDark3"); tabBar2->addTab("SegmentDark4"); tabBar2->addTab("SegmentDark5"); tabBar2->addTab(QIcon::fromTheme("kylin-music"), ""); KTabBar *tabBar3 = new KTabBar(KTabBarStyle::Sliding, w); tabBar3->addTab(QIcon::fromTheme("kylin-music"), ""); tabBar3->addTab("Sliding2"); tabBar3->addTab("Sliding3"); tabBar3->addTab("Sliding4"); tabBar3->addTab("Sliding5"); tabBar3->addTab(QIcon::fromTheme("kylin-music"), "Sliding6"); KTabBar *tabBar4 = new KTabBar(KTabBarStyle::Sliding, w); tabBar4->addTab("Segment1"); tabBar4->addTab("Segment2"); tabBar4->addTab("Segment3"); tabBar4->addTab("Segment4"); tabBar4->setTabBarStyle(KTabBarStyle::SegmentDark); // 设置style tabBar4->setBorderRadius(10); // 设置圆角半径,只对SegmentDark,SegmentLight样式生效 tabBar4->setBackgroundColor(QColor(0, 255, 0)); // 设置背景色 QLabel *pLabel = new QLabel(w); pLabel->setAlignment(Qt::AlignCenter); connect(tabBar1, &KTabBar::tabBarClicked, this, [=](int index) { pLabel->setText(tabBar1->tabText(index)); }); connect(tabBar2, &KTabBar::tabBarClicked, this, [=](int index) { pLabel->setText(tabBar2->tabText(index)); }); connect(tabBar3, &KTabBar::tabBarClicked, this, [=](int index) { pLabel->setText(tabBar3->tabText(index)); }); connect(tabBar4, &KTabBar::tabBarClicked, this, [=](int index) { pLabel->setText(tabBar4->tabText(index)); }); QHBoxLayout *hlayout = new QHBoxLayout(); QLabel *label = new QLabel(); label->setText("just a test label"); hlayout->addWidget(label); QVBoxLayout *vLayout = new QVBoxLayout; vLayout->addStretch(); vLayout->addWidget(tabBar1); vLayout->addWidget(tabBar2); vLayout->addWidget(tabBar3); vLayout->addWidget(tabBar4); vLayout->addStretch(); vLayout->addWidget(pLabel); vLayout->addStretch(); vLayout->addLayout(hlayout); vLayout->addStretch(); baseBar()->setLayout(vLayout); } Widget::~Widget() { } libkysdk-applications/kysdk-qtwidgets/test/testtabbar/main.cpp0000664000175000017500000000254415104543305023705 0ustar fengfeng/* * * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #include "widget.h" #include "kwidgetutils.h" #include #include int main(int argc, char *argv[]) { kdk::KWidgetUtils::highDpiScaling(); QApplication a(argc, argv); QTranslator trans; QString locale = QLocale::system().name(); if (locale == "zh_CN") { if (trans.load(":/translations/gui_zh_CN.qm")) { a.installTranslator(&trans); } } if (locale == "bo_CN") { if (trans.load(":/translations/gui_bo_CN.qm")) { a.installTranslator(&trans); } } Widget w; w.show(); return a.exec(); } libkysdk-applications/kysdk-qtwidgets/test/testkcolorcombobox/0000775000175000017500000000000015104543305024037 5ustar fengfenglibkysdk-applications/kysdk-qtwidgets/test/testkcolorcombobox/widget.h0000664000175000017500000000167315104515306025502 0ustar fengfeng/* * * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #ifndef WIDGET_H #define WIDGET_H #include class Widget : public QWidget { Q_OBJECT public: Widget(QWidget *parent = nullptr); ~Widget(); }; #endif // WIDGET_H libkysdk-applications/kysdk-qtwidgets/test/testkcolorcombobox/testkcolorcombobox.pro0000664000175000017500000000175715104543305030515 0ustar fengfengQT += core gui greaterThan(QT_MAJOR_VERSION, 4): QT += widgets CONFIG += c++17 CONFIG += link_pkgconfig PKGCONFIG += kysdk-qtwidgets # The following define makes your compiler emit warnings if you use # any Qt feature that has been marked deprecated (the exact warnings # depend on your compiler). Please consult the documentation of the # deprecated API in order to know how to port your code away from it. DEFINES += QT_DEPRECATED_WARNINGS # You can also make your code fail to compile if it uses deprecated APIs. # In order to do so, uncomment the following line. # You can also select to disable deprecated APIs only up to a certain version of Qt. #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 SOURCES += \ main.cpp \ widget.cpp HEADERS += \ widget.h # Default rules for deployment. qnx: target.path = /tmp/$${TARGET}/bin else: unix:!android: target.path = /opt/$${TARGET}/bin !isEmpty(target.path): INSTALLS += target libkysdk-applications/kysdk-qtwidgets/test/testkcolorcombobox/widget.cpp0000664000175000017500000000510315104543305026025 0ustar fengfeng/* * * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #include "widget.h" #include "kcolorcombobox.h" #include #include #include #include using namespace kdk; Widget::Widget(QWidget *parent) : QWidget(parent) { QHBoxLayout *hLayout = new QHBoxLayout(this); KColorComboBox *comboBoxCircle = new KColorComboBox(this); comboBoxCircle->setComboType(KColorComboBox::Circle); connect(comboBoxCircle, &KColorComboBox::currentColorChanged, this, [=]() { qDebug() << "currentColorChanged"; }); connect(comboBoxCircle, &KColorComboBox::activated, this, [=]() { qDebug() << "activatedChanged"; }); connect(comboBoxCircle, &KColorComboBox::highlighted, this, [=]() { qDebug() << "highlightChanged"; }); hLayout->addWidget(comboBoxCircle); comboBoxCircle->setFixedSize(36, 36); KColorComboBox *comboBoxRect = new KColorComboBox(this); connect(comboBoxRect, &KColorComboBox::currentColorChanged, this, [=]() { qDebug() << "currentColorChanged"; }); connect(comboBoxRect, &KColorComboBox::activated, this, [=]() { qDebug() << "activatedChanged"; }); connect(comboBoxRect, &KColorComboBox::highlighted, this, [=]() { qDebug() << "highlightChanged"; }); comboBoxRect->setComboType(KColorComboBox::RoundedRect); hLayout->addWidget(comboBoxRect); comboBoxRect->setFixedSize(36, 36); // 1.列表插入 QList list; list.append(QColor(255, 0, 0)); list.append(QColor(0, 255, 0)); list.append(QColor(255, 255, 0)); comboBoxCircle->setColorList(list); // 2.逐个插入 comboBoxRect->addColor(QColor(255, 0, 0)); comboBoxRect->addColor(QColor(0, 255, 0)); comboBoxRect->addColor(QColor(255, 255, 0)); setGeometry(400, 400, 400, 400); comboBoxCircle->setCurrentIndex(1); } Widget::~Widget() { } libkysdk-applications/kysdk-qtwidgets/test/testkcolorcombobox/main.cpp0000664000175000017500000000164615104515306025476 0ustar fengfeng/* * * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #include "widget.h" #include int main(int argc, char *argv[]) { QApplication a(argc, argv); Widget w; w.show(); return a.exec(); } libkysdk-applications/kysdk-qtwidgets/test/testSwitchButton/0000775000175000017500000000000015104543305023452 5ustar fengfenglibkysdk-applications/kysdk-qtwidgets/test/testSwitchButton/widget.h0000664000175000017500000000246415104543305025114 0ustar fengfeng/* * * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #ifndef WIDGET_H #define WIDGET_H #include "kborderlessbutton.h" #include "kswitchbutton.h" #include "kwidget.h" #include using namespace kdk; class Widget : public KWidget { Q_OBJECT public: Widget(QWidget *parent = nullptr); ~Widget(); private: KSwitchButton *m_pSwitchBtn1; QLabel *m_pLabel1; KBorderlessButton *m_pBtn1; KSwitchButton *m_pSwitchBtn2; QLabel *m_pLabel2; KBorderlessButton *m_pBtn2; KSwitchButton *m_pSwitchBtn3; QLabel *m_pLabel3; KBorderlessButton *m_pBtn3; }; #endif // WIDGET_H libkysdk-applications/kysdk-qtwidgets/test/testSwitchButton/testSwitchButton.pro0000664000175000017500000000200115104543305027522 0ustar fengfengQT += core gui greaterThan(QT_MAJOR_VERSION, 4): QT += widgets CONFIG += c++17 CONFIG += link_pkgconfig PKGCONFIG += kysdk-qtwidgets kysdk-widgetutils # The following define makes your compiler emit warnings if you use # any Qt feature that has been marked deprecated (the exact warnings # depend on your compiler). Please consult the documentation of the # deprecated API in order to know how to port your code away from it. DEFINES += QT_DEPRECATED_WARNINGS # You can also make your code fail to compile if it uses deprecated APIs. # In order to do so, uncomment the following line. # You can also select to disable deprecated APIs only up to a certain version of Qt. #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 SOURCES += \ main.cpp \ widget.cpp HEADERS += \ widget.h # Default rules for deployment. qnx: target.path = /tmp/$${TARGET}/bin else: unix:!android: target.path = /opt/$${TARGET}/bin !isEmpty(target.path): INSTALLS += target libkysdk-applications/kysdk-qtwidgets/test/testSwitchButton/widget.cpp0000664000175000017500000000761115104543305025446 0ustar fengfeng/* * * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #include "widget.h" #include Widget::Widget(QWidget *parent) : KWidget(parent) { QVBoxLayout *mainLayout = new QVBoxLayout; QHBoxLayout *hLayout = new QHBoxLayout; m_pSwitchBtn1 = new KSwitchButton(this); // 构造一个kswitchbutton m_pSwitchBtn1->setFixedSize(50, 24); // 设置button的大小 m_pSwitchBtn1->setCheckable(true); // 设置是否可选中 m_pSwitchBtn1->setChecked(true); // 设置是否为选中状态 m_pLabel1 = new QLabel(this); m_pLabel1->setText(m_pSwitchBtn1->isChecked() ? "ON" : "OFF"); // 获取button是否是选中状态 // 监听状态改变信号stateChanged connect(m_pSwitchBtn1, &KSwitchButton::stateChanged, this, [=]() { m_pLabel1->setText(m_pSwitchBtn1->isChecked() ? "ON" : "OFF"); }); m_pBtn1 = new KBorderlessButton(this); m_pBtn1->setChecked(true); m_pBtn1->setText(m_pSwitchBtn1->isEnabled() ? "Enable" : "Disable"); connect(m_pBtn1, &KBorderlessButton::clicked, this, [=]() { m_pSwitchBtn1->setEnabled(!m_pSwitchBtn1->isEnabled()); m_pBtn1->setText(m_pSwitchBtn1->isEnabled() ? "Enable" : "Disable"); }); hLayout->addWidget(m_pSwitchBtn1); hLayout->addWidget(m_pLabel1); hLayout->addWidget(m_pBtn1); hLayout->addStretch(); mainLayout->addLayout(hLayout); hLayout = new QHBoxLayout; m_pSwitchBtn2 = new KSwitchButton(this); m_pSwitchBtn2->setFixedSize(100, 48); m_pSwitchBtn2->setEnabled(false); // 设置button状态为不可点击状态 m_pLabel2 = new QLabel(this); m_pLabel2->setText(m_pSwitchBtn2->isChecked() ? "ON" : "OFF"); connect(m_pSwitchBtn2, &KSwitchButton::stateChanged, this, [=]() { m_pLabel2->setText(m_pSwitchBtn2->isChecked() ? "ON" : "OFF"); }); m_pBtn2 = new KBorderlessButton(this); m_pBtn2->setText(m_pSwitchBtn2->isEnabled() ? "Enable" : "Disable"); connect(m_pBtn2, &KBorderlessButton::clicked, this, [=]() { m_pSwitchBtn2->setEnabled(!m_pSwitchBtn2->isEnabled()); m_pBtn2->setText(m_pSwitchBtn2->isEnabled() ? "Enable" : "Disable"); }); hLayout->addWidget(m_pSwitchBtn2); hLayout->addWidget(m_pLabel2); hLayout->addWidget(m_pBtn2); hLayout->addStretch(); mainLayout->addLayout(hLayout); hLayout = new QHBoxLayout; m_pSwitchBtn3 = new KSwitchButton(this); m_pSwitchBtn3->setFixedSize(200, 96); m_pLabel3 = new QLabel(this); m_pLabel3->setText(m_pSwitchBtn3->isChecked() ? "ON" : "OFF"); connect(m_pSwitchBtn3, &KSwitchButton::stateChanged, this, [=]() { m_pLabel3->setText(m_pSwitchBtn3->isChecked() ? "ON" : "OFF"); }); m_pBtn3 = new KBorderlessButton(this); m_pBtn3->setText(m_pSwitchBtn3->isEnabled() ? "Enable" : "Disable"); connect(m_pBtn3, &KBorderlessButton::clicked, this, [=]() { m_pSwitchBtn3->setEnabled(!m_pSwitchBtn3->isEnabled()); m_pBtn3->setText(m_pSwitchBtn3->isEnabled() ? "Enable" : "Disable"); }); hLayout->addWidget(m_pSwitchBtn3); hLayout->addWidget(m_pLabel3); hLayout->addWidget(m_pBtn3); hLayout->addStretch(); mainLayout->addLayout(hLayout); baseBar()->setLayout(mainLayout); } Widget::~Widget() { } libkysdk-applications/kysdk-qtwidgets/test/testSwitchButton/main.cpp0000664000175000017500000000254415104543305025107 0ustar fengfeng/* * * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #include "widget.h" #include "kwidgetutils.h" #include #include int main(int argc, char *argv[]) { kdk::KWidgetUtils::highDpiScaling(); QApplication a(argc, argv); QTranslator trans; QString locale = QLocale::system().name(); if (locale == "zh_CN") { if (trans.load(":/translations/gui_zh_CN.qm")) { a.installTranslator(&trans); } } if (locale == "bo_CN") { if (trans.load(":/translations/gui_bo_CN.qm")) { a.installTranslator(&trans); } } Widget w; w.show(); return a.exec(); } libkysdk-applications/kysdk-qtwidgets/test/testFileWidget/0000775000175000017500000000000015104543305023040 5ustar fengfenglibkysdk-applications/kysdk-qtwidgets/test/testFileWidget/widget.h0000664000175000017500000000174715104543305024505 0ustar fengfeng/* * * Copyright (C) 2024, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhenyu Wang * */ #ifndef WIDGET_H #define WIDGET_H #include "kwidget.h" #include using namespace kdk; class Widget : public KWidget { Q_OBJECT public: Widget(QWidget *parent = nullptr); ~Widget(); }; #endif // WIDGET_H libkysdk-applications/kysdk-qtwidgets/test/testFileWidget/testFileWidget.pro0000664000175000017500000000200115104543305026476 0ustar fengfengQT += core gui greaterThan(QT_MAJOR_VERSION, 4): QT += widgets CONFIG += c++17 CONFIG += link_pkgconfig PKGCONFIG += kysdk-widgetutils kysdk-qtwidgets # The following define makes your compiler emit warnings if you use # any Qt feature that has been marked deprecated (the exact warnings # depend on your compiler). Please consult the documentation of the # deprecated API in order to know how to port your code away from it. DEFINES += QT_DEPRECATED_WARNINGS # You can also make your code fail to compile if it uses deprecated APIs. # In order to do so, uncomment the following line. # You can also select to disable deprecated APIs only up to a certain version of Qt. #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 SOURCES += \ main.cpp \ widget.cpp HEADERS += \ widget.h # Default rules for deployment. qnx: target.path = /tmp/$${TARGET}/bin else: unix:!android: target.path = /opt/$${TARGET}/bin !isEmpty(target.path): INSTALLS += target libkysdk-applications/kysdk-qtwidgets/test/testFileWidget/widget.cpp0000664000175000017500000000431615104543305025033 0ustar fengfeng/* * * Copyright (C) 2024, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhenyu Wang * */ #include "widget.h" #include "kfilewidget.h" #include "kpressbutton.h" #include #include #include Widget::Widget(QWidget *parent) : KWidget(parent) { QVBoxLayout *layout = new QVBoxLayout(); KFileWidget *widget1 = new KFileWidget(this); widget1->setFixedSize(150, 56); widget1->setMainText("文档.word"); widget1->setSubText("大小 1MB"); widget1->setIcon(QIcon::fromTheme("wps-office2019-wpsmain")); widget1->setBorderRadius(0, 10, 0, 10); connect(widget1, &KFileWidget::clicked, this, [=] { widget1->hide(); }); KFileWidget *widget2 = new KFileWidget(this); widget2->setMainText("文档.word"); widget2->setIcon(QIcon::fromTheme("wps-office2019-wpsmain")); widget2->setEnabled(false); connect(widget2, &KFileWidget::clicked, this, [=] { widget2->hide(); }); KFileWidget *widget3 = new KFileWidget(this); widget3->setMainText("文档.word"); widget3->setIcon(QIcon::fromTheme("wps-office2019-wpsmain")); widget3->setFixedSize(150, 56); widget3->setBorderRadius(0); connect(widget3, &KFileWidget::clicked, this, [=] { widget3->hide(); }); layout->addStretch(); layout->addWidget(widget1); layout->addWidget(widget2); layout->addWidget(widget3); layout->addStretch(); QHBoxLayout *hlayout = new QHBoxLayout(); hlayout->addLayout(layout); baseBar()->setLayout(hlayout); } Widget::~Widget() { } libkysdk-applications/kysdk-qtwidgets/test/testFileWidget/main.cpp0000664000175000017500000000165015104543305024472 0ustar fengfeng/* * * Copyright (C) 2024, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhenyu Wang * */ #include "widget.h" #include int main(int argc, char *argv[]) { QApplication a(argc, argv); Widget w; w.show(); return a.exec(); } libkysdk-applications/kysdk-qtwidgets/test/testnavigationbar/0000775000175000017500000000000015104543305023641 5ustar fengfenglibkysdk-applications/kysdk-qtwidgets/test/testnavigationbar/widget.h0000664000175000017500000000226515104543305025302 0ustar fengfeng/* * * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #ifndef WIDGET_H #define WIDGET_H #include "knavigationbar.h" #include "kwidget.h" #include #include #include #include #include #include #include using namespace kdk; class Widget : public KWidget { Q_OBJECT public: Widget(QWidget *parent = nullptr); ~Widget(); private: KNavigationBar *m_pBar; }; #endif // WIDGET_H libkysdk-applications/kysdk-qtwidgets/test/testnavigationbar/testnavigationbar.pro0000664000175000017500000000200115104543305030100 0ustar fengfengQT += core gui greaterThan(QT_MAJOR_VERSION, 4): QT += widgets CONFIG += c++17 CONFIG += link_pkgconfig PKGCONFIG += kysdk-qtwidgets kysdk-widgetutils # The following define makes your compiler emit warnings if you use # any Qt feature that has been marked deprecated (the exact warnings # depend on your compiler). Please consult the documentation of the # deprecated API in order to know how to port your code away from it. DEFINES += QT_DEPRECATED_WARNINGS # You can also make your code fail to compile if it uses deprecated APIs. # In order to do so, uncomment the following line. # You can also select to disable deprecated APIs only up to a certain version of Qt. #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 SOURCES += \ main.cpp \ widget.cpp HEADERS += \ widget.h # Default rules for deployment. qnx: target.path = /tmp/$${TARGET}/bin else: unix:!android: target.path = /opt/$${TARGET}/bin !isEmpty(target.path): INSTALLS += target libkysdk-applications/kysdk-qtwidgets/test/testnavigationbar/widget.cpp0000664000175000017500000000702615104543305025635 0ustar fengfeng/* * * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #include "widget.h" #include #include Widget::Widget(QWidget *parent) : KWidget(parent) { QVBoxLayout *vLayout = new QVBoxLayout(); m_pBar = new KNavigationBar(this); QStandardItem *item1 = new QStandardItem(QIcon::fromTheme("system-computer-symbolic"), tr("一级导航")); QStandardItem *item2 = new QStandardItem(QIcon::fromTheme("stock-people-symbolic"), tr("二级导航")); QList list; QStandardItem *item3 = new QStandardItem(QIcon::fromTheme("camera-switch-symbolic"), tr("一组一级导航1")); QStandardItem *item4 = new QStandardItem(QIcon::fromTheme("media-eq-symbolic"), tr("一组一级导航2")); list << item3 << item4; m_pBar->addItem(item1); // 增加常规Item m_pBar->addSubItem(item2); // 增加次级Item m_pBar->addGroupItems(list, "测试一组"); // 组增加Item,在导航栏中会显示tag QStandardItem *item5 = new QStandardItem(QIcon::fromTheme("camera-switch-symbolic"), tr("二组一级导航1")); item5->setData("1", KNavigationBar::NavigationBarDataType::ValueRole); QStandardItem *item6 = new QStandardItem(QIcon::fromTheme("media-eq-symbolic"), tr("二组一级导航2")); item6->setData("2", KNavigationBar::NavigationBarDataType::ValueRole); QStandardItem *item7 = new QStandardItem(QIcon::fromTheme("media-eq-symbolic"), tr("二组二级导航")); QList list2; list2 << item5 << item6; m_pBar->addGroupItems(list2, "测试二组"); m_pBar->setTabValueVisible(true); m_pBar->setTabValue(item7, "3"); m_pBar->insertGroupItems("测试二组", 2, item7); m_pBar->setAddTagVisible("测试二组", true); m_pBar->setAddIcon("测试二组", QIcon::fromTheme("list-add-symbolic")); m_pBar->setExtendTagVisible("测试二组", true); connect(m_pBar, &KNavigationBar::addTagClicked, this, [=]() { m_pBar->removeGroupItem("测试二组", item6); }); m_pBar->addTag("测试三组"); vLayout->addWidget(m_pBar); sideBar()->setLayout(vLayout); vLayout = new QVBoxLayout; QLabel *pLabel = new QLabel(this); pLabel->setAlignment(Qt::AlignCenter); vLayout->addWidget(pLabel); baseBar()->setLayout(vLayout); m_pBar->model()->item(1)->setEnabled(false); m_pBar->model()->item(2)->setEnabled(false); m_pBar->model()->item(3)->setEnabled(false); m_pBar->model()->item(4)->setEnabled(false); // QListView* ba= m_pBar->listview(); //获取listview // ba->setDisabled(true); //整体禁用 // QStandardItemModel* m_mode = m_pBar->model(); //获取mode connect(m_pBar->listview(), &QListView::clicked, this, [=](const QModelIndex &index) { pLabel->setText(index.data().toString()); }); this->setLayoutType(HorizontalType); } Widget::~Widget() { } libkysdk-applications/kysdk-qtwidgets/test/testnavigationbar/main.cpp0000664000175000017500000000254415104543305025276 0ustar fengfeng/* * * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #include "widget.h" #include "kwidgetutils.h" #include #include int main(int argc, char *argv[]) { kdk::KWidgetUtils::highDpiScaling(); QApplication a(argc, argv); QTranslator trans; QString locale = QLocale::system().name(); if (locale == "zh_CN") { if (trans.load(":/translations/gui_zh_CN.qm")) { a.installTranslator(&trans); } } if (locale == "bo_CN") { if (trans.load(":/translations/gui_bo_CN.qm")) { a.installTranslator(&trans); } } Widget w; w.show(); return a.exec(); } libkysdk-applications/kysdk-qtwidgets/test/testinputdialog/0000775000175000017500000000000015104543305023334 5ustar fengfenglibkysdk-applications/kysdk-qtwidgets/test/testinputdialog/widget.h0000664000175000017500000000172115104543305024771 0ustar fengfeng/* * * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #ifndef WIDGET_H #define WIDGET_H #include "kwidget.h" using namespace kdk; class Widget : public KWidget { Q_OBJECT public: Widget(QWidget *parent = nullptr); ~Widget(); }; #endif // WIDGET_H libkysdk-applications/kysdk-qtwidgets/test/testinputdialog/testinputdialog.pro0000664000175000017500000000200115104543305027266 0ustar fengfengQT += core gui greaterThan(QT_MAJOR_VERSION, 4): QT += widgets CONFIG += link_pkgconfig PKGCONFIG += kysdk-qtwidgets kysdk-widgetutils CONFIG += c++17 # The following define makes your compiler emit warnings if you use # any Qt feature that has been marked deprecated (the exact warnings # depend on your compiler). Please consult the documentation of the # deprecated API in order to know how to port your code away from it. DEFINES += QT_DEPRECATED_WARNINGS # You can also make your code fail to compile if it uses deprecated APIs. # In order to do so, uncomment the following line. # You can also select to disable deprecated APIs only up to a certain version of Qt. #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 SOURCES += \ main.cpp \ widget.cpp HEADERS += \ widget.h # Default rules for deployment. qnx: target.path = /tmp/$${TARGET}/bin else: unix:!android: target.path = /opt/$${TARGET}/bin !isEmpty(target.path): INSTALLS += target libkysdk-applications/kysdk-qtwidgets/test/testinputdialog/widget.cpp0000664000175000017500000000371315104543305025327 0ustar fengfeng/* * * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #include "widget.h" #include "kinputdialog.h" #include #include #include using namespace kdk; Widget::Widget(QWidget *parent) : KWidget(parent) { QVBoxLayout *vlayout = new QVBoxLayout(); auto btn1 = new QPushButton("inputText", this); auto btn2 = new QPushButton("inputMultiText", this); auto btn3 = new QPushButton("inputInt", this); auto btn4 = new QPushButton("inputDouble", this); vlayout->addWidget(btn1); vlayout->addWidget(btn2); vlayout->addWidget(btn3); vlayout->addWidget(btn4); connect(btn1, &QPushButton::clicked, this, [=]() { KInputDialog::getText(this, tr("please input:")); }); // 单行文本输入框 connect(btn2, &QPushButton::clicked, this, [=]() { KInputDialog::getMultiLineText(this, tr("please input:")); }); // 多行文本输入框 connect(btn3, &QPushButton::clicked, this, [=]() { KInputDialog::getInt(this, tr("please input:")); }); // 整型数字输入框 connect(btn4, &QPushButton::clicked, this, [=]() { KInputDialog::getDouble(this, tr("please input:")); }); // 浮点型数字输入框 baseBar()->setLayout(vlayout); } Widget::~Widget() { } libkysdk-applications/kysdk-qtwidgets/test/testinputdialog/main.cpp0000664000175000017500000000254415104543305024771 0ustar fengfeng/* * * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #include "widget.h" #include "kwidgetutils.h" #include #include int main(int argc, char *argv[]) { kdk::KWidgetUtils::highDpiScaling(); QApplication a(argc, argv); Widget w; QTranslator trans; QString locale = QLocale::system().name(); if (locale == "zh_CN") { if (trans.load(":/translations/gui_zh_CN.qm")) { a.installTranslator(&trans); } } if (locale == "bo_CN") { if (trans.load(":/translations/gui_bo_CN.qm")) { a.installTranslator(&trans); } } w.show(); return a.exec(); } libkysdk-applications/kysdk-qtwidgets/test/testarrowtabbar/0000775000175000017500000000000015104543305023323 5ustar fengfenglibkysdk-applications/kysdk-qtwidgets/test/testarrowtabbar/widget.h0000664000175000017500000000167515104543305024770 0ustar fengfeng/* * * Copyright (C) 2024, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhenyu Wang * */ #ifndef WIDGET_H #define WIDGET_H #include class Widget : public QWidget { Q_OBJECT public: Widget(QWidget *parent = nullptr); ~Widget(); }; #endif // WIDGET_H libkysdk-applications/kysdk-qtwidgets/test/testarrowtabbar/testarrowtabbar.pro0000664000175000017500000000200115104543305027244 0ustar fengfengQT += core gui greaterThan(QT_MAJOR_VERSION, 4): QT += widgets CONFIG += c++17 CONFIG += link_pkgconfig PKGCONFIG += kysdk-widgetutils kysdk-qtwidgets # The following define makes your compiler emit warnings if you use # any Qt feature that has been marked deprecated (the exact warnings # depend on your compiler). Please consult the documentation of the # deprecated API in order to know how to port your code away from it. DEFINES += QT_DEPRECATED_WARNINGS # You can also make your code fail to compile if it uses deprecated APIs. # In order to do so, uncomment the following line. # You can also select to disable deprecated APIs only up to a certain version of Qt. #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 SOURCES += \ main.cpp \ widget.cpp HEADERS += \ widget.h # Default rules for deployment. qnx: target.path = /tmp/$${TARGET}/bin else: unix:!android: target.path = /opt/$${TARGET}/bin !isEmpty(target.path): INSTALLS += target libkysdk-applications/kysdk-qtwidgets/test/testarrowtabbar/widget.cpp0000664000175000017500000000635415104543305025322 0ustar fengfeng/* * * Copyright (C) 2024, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhenyu Wang * */ #include "widget.h" #include "karrowtabbar.h" #include "knativetabbar.h" #include #include using namespace kdk; Widget::Widget(QWidget *parent) : QWidget(parent) { KArrowTabBar *tab1 = new KArrowTabBar(); KNativeTabbar *tabBar1 = tab1->tabbar(); tabBar1->setTabbarStyle(KNativeTabbarStyle::SegmentLight); tabBar1->addTab(QIcon::fromTheme("kylin-music"), "Segment1"); tabBar1->addTab("Segment2"); tabBar1->addTab(QIcon::fromTheme("kylin-music"), ""); tabBar1->addTab("Segment4"); tabBar1->addTab("Segment5"); tabBar1->addTab("Segment6"); KArrowTabBar *tab2 = new KArrowTabBar(); KNativeTabbar *tabBar2 = tab2->tabbar(); tabBar2->setTabbarStyle(KNativeTabbarStyle::SegmentDark); tabBar2->addTab("SegmentDark1"); tabBar2->addTab("SegmentDark2"); tabBar2->addTab(QIcon::fromTheme("kylin-music"), "SegmentDark3"); tabBar2->addTab("SegmentDark4"); tabBar2->addTab("SegmentDark5"); tabBar2->addTab(QIcon::fromTheme("kylin-music"), ""); KArrowTabBar *tab3 = new KArrowTabBar(); KNativeTabbar *tabBar3 = tab3->tabbar(); tabBar3->setTabbarStyle(KNativeTabbarStyle::Sliding); tabBar3->addTab(QIcon::fromTheme("ukui-dialog-success"), "正常"); tabBar3->addTab(QIcon::fromTheme("dialog-warning"), "错误"); tabBar3->addTab(QIcon::fromTheme("dialog-info"), "注意"); tabBar3->addTab(QIcon::fromTheme("kylin-music"), "Sliding4"); tabBar3->addTab("Sliding5"); tabBar3->addTab(QIcon::fromTheme("kylin-music"), "Sliding6"); KArrowTabBar *tab4 = new KArrowTabBar(); KNativeTabbar *tabBar4 = tab4->tabbar(); tabBar4->addTab("Segment1"); tabBar4->addTab("Segment2"); tabBar4->addTab("Segment3"); tabBar4->addTab("Segment4"); tabBar4->setTabbarStyle(KNativeTabbarStyle::SegmentDark); // 设置style tabBar4->setBorderRadius(10); // 设置圆角半径,只对SegmentDark,SegmentLight样式生效 tabBar4->setBackgroundColor(QColor(0, 255, 0)); // 设置背景色 QHBoxLayout *hlayout = new QHBoxLayout(); QLabel *label = new QLabel(); label->setText("just a test label"); hlayout->addWidget(label); QVBoxLayout *vLayout = new QVBoxLayout(this); vLayout->addStretch(); vLayout->addWidget(tab1); vLayout->addWidget(tab2); vLayout->addWidget(tab3); vLayout->addWidget(tab4); vLayout->addStretch(); vLayout->addStretch(); vLayout->addLayout(hlayout); vLayout->addStretch(); setFixedWidth(500); } Widget::~Widget() { } libkysdk-applications/kysdk-qtwidgets/test/testarrowtabbar/main.cpp0000664000175000017500000000165015104543305024755 0ustar fengfeng/* * * Copyright (C) 2024, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhenyu Wang * */ #include "widget.h" #include int main(int argc, char *argv[]) { QApplication a(argc, argv); Widget w; w.show(); return a.exec(); } libkysdk-applications/kysdk-qtwidgets/test/testdirtabbar/0000775000175000017500000000000015104543305022747 5ustar fengfenglibkysdk-applications/kysdk-qtwidgets/test/testdirtabbar/testdirtabbar.pro0000664000175000017500000000113715104543305026325 0ustar fengfengQT += core gui greaterThan(QT_MAJOR_VERSION, 4): QT += widgets CONFIG += c++17 CONFIG += link_pkgconfig PKGCONFIG += kysdk-qtwidgets # You can make your code fail to compile if it uses deprecated APIs. # In order to do so, uncomment the following line. #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 SOURCES += \ main.cpp \ widget.cpp HEADERS += \ widget.h # Default rules for deployment. qnx: target.path = /tmp/$${TARGET}/bin else: unix:!android: target.path = /opt/$${TARGET}/bin !isEmpty(target.path): INSTALLS += target libkysdk-applications/kysdk-qtwidgets/test/testdirtabbar/widget.h0000664000175000017500000000050315104543305024401 0ustar fengfeng#ifndef WIDGET_H #define WIDGET_H #include "kdirtabbar.h" #include "widget.h" #include class Widget : public QWidget { Q_OBJECT public: Widget(QWidget *parent = nullptr); ~Widget(); void getchildFolds(const QString &foldPath, QStringList &folds, QStringList &foldsName); }; #endif // WIDGET_H libkysdk-applications/kysdk-qtwidgets/test/testdirtabbar/widget.cpp0000664000175000017500000000356315104543305024745 0ustar fengfeng#include "widget.h" #include "kdirtabbar.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace kdk; Widget::Widget(QWidget *parent) : QWidget(parent) { KDirTabBar *bar = new KDirTabBar(this); QVBoxLayout *myLayout = new QVBoxLayout(); QFileDialog *fileDialog = new QFileDialog(this); ; QPushButton *button1 = new QPushButton("open files", this); QLabel *label = new QLabel(); QString path = QDir::currentPath(); QFileInfo fileInfo(path); QList btns; KDirTabBar *bar2 = new KDirTabBar(this); bar->setCurrentPath(fileInfo.absoluteFilePath()); label->setText(bar->currentPath()); btns = bar->buttons(); btns[btns.count() - 1]->setIcon(QIcon()); // 设置按钮的图标 btns[btns.count() - 2]->setEnabled(false); // 设置按钮是否可用 bar->setIcon(btns.count() - 2, QIcon::fromTheme("folder-pictures")); // 设置按钮的图标 connect(bar, &KDirTabBar::tabBarClicked, [=]() { label->setText(bar->currentPath()); }); connect(button1, &QPushButton::clicked, [=] { fileDialog->setDirectory(QStandardPaths::writableLocation(QStandardPaths::HomeLocation)); fileDialog->setFileMode(QFileDialog::ExistingFiles); bar2->setCurrentPath(fileDialog->getExistingDirectory()); }); setLayout(myLayout); myLayout->addWidget(bar); myLayout->addStretch(); myLayout->addWidget(label); myLayout->addStretch(); myLayout->addWidget(button1); myLayout->addStretch(); myLayout->addWidget(bar2); myLayout->addStretch(); } Widget::~Widget() { } libkysdk-applications/kysdk-qtwidgets/test/testdirtabbar/main.cpp0000664000175000017500000000024415104543305024377 0ustar fengfeng#include "widget.h" #include int main(int argc, char *argv[]) { QApplication a(argc, argv); Widget w; w.show(); return a.exec(); } libkysdk-applications/kysdk-qtwidgets/test/testslider/0000775000175000017500000000000015104543305022277 5ustar fengfenglibkysdk-applications/kysdk-qtwidgets/test/testslider/testslider.pro0000664000175000017500000000200115104543305025174 0ustar fengfengQT += core gui greaterThan(QT_MAJOR_VERSION, 4): QT += widgets CONFIG += link_pkgconfig PKGCONFIG += kysdk-qtwidgets kysdk-widgetutils CONFIG += c++17 # The following define makes your compiler emit warnings if you use # any Qt feature that has been marked deprecated (the exact warnings # depend on your compiler). Please consult the documentation of the # deprecated API in order to know how to port your code away from it. DEFINES += QT_DEPRECATED_WARNINGS # You can also make your code fail to compile if it uses deprecated APIs. # In order to do so, uncomment the following line. # You can also select to disable deprecated APIs only up to a certain version of Qt. #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 SOURCES += \ main.cpp \ widget.cpp HEADERS += \ widget.h # Default rules for deployment. qnx: target.path = /tmp/$${TARGET}/bin else: unix:!android: target.path = /opt/$${TARGET}/bin !isEmpty(target.path): INSTALLS += target libkysdk-applications/kysdk-qtwidgets/test/testslider/widget.h0000664000175000017500000000223615104543305023736 0ustar fengfeng/* * * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #ifndef WIDGET_H #define WIDGET_H #include "kslider.h" #include "kwidget.h" #include using namespace kdk; class Widget : public KWidget { Q_OBJECT public: Widget(QWidget *parent = nullptr); ~Widget(); private: KSlider *m_pSlider1; KSlider *m_pSlider2; KSlider *m_pSlider3; KSlider *m_pSlider4; KSlider *m_pSlider5; KSlider *m_pSlider6; }; #endif // WIDGET_H libkysdk-applications/kysdk-qtwidgets/test/testslider/widget.cpp0000664000175000017500000001543515104543305024276 0ustar fengfeng/* * * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #include "widget.h" #include "ktabbar.h" #include #include #include Widget::Widget(QWidget *parent) : KWidget(parent) { QTabWidget *tabWidget = new QTabWidget(this); // horizontal QWidget *widget1 = new QWidget(this); QVBoxLayout *vLayout1 = new QVBoxLayout; QHBoxLayout *hLayout = new QHBoxLayout; QLabel *label1 = new QLabel(this); label1->setText("并列关系:"); m_pSlider1 = new KSlider(this); // 构建一个滑动条 m_pSlider1->setFocusPolicy(Qt::ClickFocus); // 设置是否显示节点 // m_pSlider1->setNodeVisible(false); m_pSlider1->setSliderType(KSliderType::SingleSelectSlider); // 设置滑动条的类型,包含四种SmoothSlider,StepSlider,NodeSlider,SingleSelectSlider m_pSlider1->setRange(0, 4); // 设置滑动条值的范围 m_pSlider1->setMaximum(2); // 设置滑动条的最大值 m_pSlider1->setValue(1); // 设置滑动条的初始值 // m_pSlider1->setTickInterval(1); m_pSlider1->setFixedWidth(200); hLayout->addWidget(label1); hLayout->addWidget(m_pSlider1); QLabel *numLabel1 = new QLabel(this); numLabel1->setFixedWidth(30); numLabel1->setText(QString::number(m_pSlider1->value())); // 获取滑动条当前的值 hLayout->addWidget(numLabel1); hLayout->addStretch(); vLayout1->addLayout(hLayout); QLabel *label2 = new QLabel(this); label2->setText("步数关系:"); m_pSlider2 = new KSlider(this); m_pSlider2->setSliderType(KSliderType::StepSlider); // 设置滑动条的类型StepSlider m_pSlider2->setFocusPolicy(Qt::ClickFocus); // 设置刻度间隔 m_pSlider2->setTickInterval(10); // 设置步长 m_pSlider2->setSingleStep(20); // 设置取值范围 m_pSlider2->setRange(-50, 50); // 设置初始值 m_pSlider2->setValue(20); qDebug() << m_pSlider2->value(); hLayout = new QHBoxLayout; hLayout->addWidget(label2); hLayout->addWidget(m_pSlider2); QLabel *numLabel2 = new QLabel(this); numLabel2->setText(QString::number(m_pSlider2->value())); numLabel2->setFixedWidth(30); hLayout->addWidget(numLabel2); vLayout1->addLayout(hLayout); QLabel *label3 = new QLabel(this); label3->setText("节点关系:"); m_pSlider3 = new KSlider(this); m_pSlider3->setSliderType(KSliderType::NodeSlider); m_pSlider3->setFocusPolicy(Qt::ClickFocus); m_pSlider3->setTickInterval(10); m_pSlider3->setSingleStep(20); m_pSlider3->setRange(-50, 50); m_pSlider3->setValue(20); hLayout = new QHBoxLayout; hLayout->addWidget(label3); hLayout->addWidget(m_pSlider3); QLabel *numLabel3 = new QLabel(this); numLabel3->setText(QString::number(m_pSlider3->value())); numLabel3->setFixedWidth(30); hLayout->addWidget(numLabel3); vLayout1->addLayout(hLayout); connect(m_pSlider1, &QSlider::valueChanged, this, [=]() { numLabel1->setText(QString::number(m_pSlider1->value())); }); connect(m_pSlider2, &KSlider::valueChanged, this, [=]() { numLabel2->setText(QString::number(m_pSlider2->value())); }); connect(m_pSlider3, &KSlider::valueChanged, this, [=]() { numLabel3->setText(QString::number(m_pSlider3->value())); }); widget1->setLayout(vLayout1); tabWidget->addTab(widget1, "horizontal"); // vertical QWidget *widget2 = new QWidget(this); QHBoxLayout *hLayout2 = new QHBoxLayout; QVBoxLayout *vLayout2 = new QVBoxLayout; QLabel *label4 = new QLabel(this); label4->setText("非步数关系:"); m_pSlider4 = new KSlider(Qt::Vertical, this); // 设置滑动条为垂直方向 m_pSlider4->setSliderType(KSliderType::SmoothSlider); m_pSlider4->setFocusPolicy(Qt::ClickFocus); m_pSlider4->setTickInterval(20); m_pSlider4->setSingleStep(10); m_pSlider4->setValue(10); m_pSlider4->setEnabled(false); QLabel *numLabel4 = new QLabel(this); numLabel4->setFixedWidth(30); numLabel4->setText(QString::number(m_pSlider4->value())); vLayout2->addWidget(numLabel4); vLayout2->addWidget(m_pSlider4); vLayout2->addWidget(label4); hLayout2->addLayout(vLayout2); QLabel *label5 = new QLabel(this); label5->setText("步数关系:"); m_pSlider5 = new KSlider(Qt::Vertical, this); m_pSlider5->setSliderType(KSliderType::StepSlider); m_pSlider5->setFocusPolicy(Qt::ClickFocus); m_pSlider5->setTickInterval(20); m_pSlider5->setSingleStep(10); m_pSlider5->setValue(20); QLabel *numLabel5 = new QLabel(this); numLabel5->setFixedWidth(30); numLabel5->setText(QString::number(m_pSlider5->value())); vLayout2 = new QVBoxLayout; vLayout2->addWidget(numLabel5); vLayout2->addWidget(m_pSlider5); vLayout2->addWidget(label5); hLayout2->addLayout(vLayout2); QLabel *label6 = new QLabel(this); label6->setText("节点关系:"); m_pSlider6 = new KSlider(this); m_pSlider6->setSliderType(KSliderType::NodeSlider); m_pSlider6->setFocusPolicy(Qt::ClickFocus); m_pSlider6->setTickInterval(20); m_pSlider6->setSingleStep(10); m_pSlider6->setValue(30); m_pSlider6->setOrientation(Qt::Vertical); QLabel *numLabel6 = new QLabel(this); numLabel6->setFixedWidth(30); numLabel6->setText(QString::number(m_pSlider6->value())); vLayout2 = new QVBoxLayout; vLayout2->addWidget(numLabel6); vLayout2->addWidget(m_pSlider6); vLayout2->addWidget(label6); hLayout2->addLayout(vLayout2); connect(m_pSlider4, &QSlider::valueChanged, this, [=]() { numLabel4->setText(QString::number(m_pSlider4->value())); }); connect(m_pSlider5, &KSlider::valueChanged, this, [=]() { numLabel5->setText(QString::number(m_pSlider5->value())); }); connect(m_pSlider6, &KSlider::valueChanged, this, [=]() { numLabel6->setText(QString::number(m_pSlider6->value())); }); widget2->setLayout(hLayout2); tabWidget->addTab(widget2, "vertical"); QVBoxLayout *mainLayout = new QVBoxLayout(); mainLayout->addWidget(tabWidget); this->baseBar()->setLayout(mainLayout); } Widget::~Widget() { } libkysdk-applications/kysdk-qtwidgets/test/testslider/main.cpp0000664000175000017500000000254415104543305023734 0ustar fengfeng/* * * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #include "widget.h" #include "kwidgetutils.h" #include #include int main(int argc, char *argv[]) { kdk::KWidgetUtils::highDpiScaling(); QApplication a(argc, argv); QTranslator trans; QString locale = QLocale::system().name(); if (locale == "zh_CN") { if (trans.load(":/translations/gui_zh_CN.qm")) { a.installTranslator(&trans); } } if (locale == "bo_CN") { if (trans.load(":/translations/gui_bo_CN.qm")) { a.installTranslator(&trans); } } Widget w; w.show(); return a.exec(); } libkysdk-applications/kysdk-qtwidgets/test/testKPushButton/0000775000175000017500000000000015104543305023243 5ustar fengfenglibkysdk-applications/kysdk-qtwidgets/test/testKPushButton/widget.h0000664000175000017500000000175515104543305024707 0ustar fengfeng/* * * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Xiangwei Liu * */ #ifndef WIDGET_H #define WIDGET_H #include class Widget : public QWidget { Q_OBJECT public: Widget(QWidget *parent = nullptr); ~Widget(); public slots: void onButtonClicked(); }; #endif // WIDGET_H libkysdk-applications/kysdk-qtwidgets/test/testKPushButton/testKPushButton.pro0000664000175000017500000000221615104543305027114 0ustar fengfengQT += core gui greaterThan(QT_MAJOR_VERSION, 4): QT += widgets CONFIG += c++17 DEFINES += USE_UKUI_PROTOCOL DEFINES += USE_UKUI_SHELL_PLUGIN # The following define makes your compiler emit warnings if you use # any Qt feature that has been marked deprecated (the exact warnings # depend on your compiler). Please consult the documentation of the # deprecated API in order to know how to port your code away from it. DEFINES += QT_DEPRECATED_WARNINGS CONFIG += link_pkgconfig PKGCONFIG += kysdk-widgetutils kysdk-ukuiwindowhelper kysdk-waylandhelper kysdk-qtwidgets PKGCONFIG += x11 KF6WindowSystem # You can also make your code fail to compile if it uses deprecated APIs. # In order to do so, uncomment the following line. # You can also select to disable deprecated APIs only up to a certain version of Qt. #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 SOURCES += \ main.cpp \ widget.cpp HEADERS += \ widget.h # Default rules for deployment. qnx: target.path = /tmp/$${TARGET}/bin else: unix:!android: target.path = /opt/$${TARGET}/bin !isEmpty(target.path): INSTALLS += target libkysdk-applications/kysdk-qtwidgets/test/testKPushButton/src.qrc0000664000175000017500000000006415104515306024541 0ustar fengfeng libkysdk-applications/kysdk-qtwidgets/test/testKPushButton/widget.cpp0000664000175000017500000001004715104543305025234 0ustar fengfeng/* * * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Xiangwei Liu * */ #include "widget.h" #include "kpushbutton.h" #include #include #include using namespace kdk; Widget::Widget(QWidget *parent) : QWidget(parent) { QHBoxLayout *layout1 = new QHBoxLayout(); /*半透明字体按钮布局,包括按钮1、2、3*/ KPushButton *btn1 = new KPushButton(this); /*不可用透明按钮*/ btn1->setText("button1"); btn1->setTranslucent(true); btn1->setEnabled(false); KPushButton *btn2 = new KPushButton(this); /*可用透明按钮*/ btn2->setText("button2"); btn2->setTranslucent(true); btn2->setBackgroundColor(Qt::blue); KPushButton *btn3 = new KPushButton(this); /*圆形透明按钮,如果需要设置为正圆需要自己设置大小,默认跟随layout*/ btn3->setText("button3"); btn3->setTranslucent(true); btn3->setButtonType(KPushButton::CircleType); layout1->addWidget(btn1); layout1->addWidget(btn2); layout1->addWidget(btn3); QHBoxLayout *layout2 = new QHBoxLayout(); /*半透明图标按钮,包括按钮4、5*/ KPushButton *btn4 = new KPushButton(this); btn4->setIcon(QIcon::fromTheme("go-previous-symbolic")); btn4->setTranslucent(true); btn4->setFixedSize(32, 32); btn4->setIconSize(QSize(24, 24)); btn4->setBackgroundColor(Qt::blue); KPushButton *btn5 = new KPushButton(this); btn5->setIcon(QIcon::fromTheme("go-next-symbolic")); btn5->setTranslucent(true); btn5->setFixedSize(32, 32); btn5->setIconSize(QSize(24, 24)); layout2->addWidget(btn4); layout2->addWidget(btn5); QHBoxLayout *layout3 = new QHBoxLayout(); /*正常带图标不透明按钮,包括6、7*/ KPushButton *btn6 = new KPushButton(this); btn6->setIcon(QIcon::fromTheme("go-previous-symbolic")); btn6->setFixedSize(32, 32); btn6->setIconSize(QSize(24, 24)); btn6->setIconHighlight(true); btn6->setBackgroundColor(Qt::transparent); KPushButton *btn7 = new KPushButton(this); btn7->setIcon(QIcon::fromTheme("go-next-symbolic")); btn7->setFixedSize(32, 32); btn7->setIconSize(QSize(24, 24)); btn7->setIconHighlight(true); btn7->setBackgroundColor(Qt::transparent); layout3->addWidget(btn6); layout3->addWidget(btn7); QHBoxLayout *layout4 = new QHBoxLayout(); KPushButton *btn8 = new KPushButton(this); /*设置文字且设置圆角的不透明按钮*/ btn8->setText("button8"); btn8->setBorderRadius(10); KPushButton *btn9 = new KPushButton(this); /*设置图标且设置圆角的不透明按钮*/ btn9->setIcon(QIcon::fromTheme("list-add-symbolic")); btn9->setIconColor(Qt::white); btn9->setBackgroundColorHighlight(true); /*设置按钮背景色跟随系统高亮色*/ // btn9->setBackgroundColor(Qt::red); /*用户设置自定义背景色(与跟随系统高亮存在先后关系,后设置的生效)*/ btn9->setFixedSize(40, 40); btn9->setBorderRadius(20); btn9->setIconSize(QSize(24, 24)); layout4->addWidget(btn8); layout4->addWidget(btn9); QVBoxLayout *layout = new QVBoxLayout(this); layout->addLayout(layout1); layout->addLayout(layout2); layout->addLayout(layout3); layout->addLayout(layout4); this->setLayout(layout); } Widget::~Widget() { } void Widget::onButtonClicked() { qDebug() << "clicked"; } libkysdk-applications/kysdk-qtwidgets/test/testKPushButton/main.cpp0000664000175000017500000000334515104543305024700 0ustar fengfeng/* * * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Xiangwei Liu * */ #include "widget.h" #include "kwidgetutils.h" #include #include #include #include #include "ukuiwindowhelper/ukuiwindowhelper.h" int main(int argc, char *argv[]) { kdk::KWidgetUtils::highDpiScaling(); QApplication a(argc, argv); QTranslator trans; QString locale = QLocale::system().name(); if (locale == "zh_CN") { if (trans.load(":/translations/gui_zh_CN.qm")) { a.installTranslator(&trans); } } if (locale == "bo_CN") { if (trans.load(":/translations/gui_bo_CN.qm")) { a.installTranslator(&trans); } } Widget w; w.setAttribute(Qt::WA_TranslucentBackground, true); UkuiWindowHelper *m_ukuiWindowHelper = new UkuiWindowHelper(&w); #ifdef USE_UKUI_SHELL_PLUGIN m_ukuiWindowHelper->setBlurEffect(QRegion(), 0, true); #else KWindowEffects::enableBlurBehind(this->winId(),true); #endif w.show(); return a.exec(); } libkysdk-applications/kysdk-qtwidgets/test/testksettinggroup/0000775000175000017500000000000015104543305023722 5ustar fengfenglibkysdk-applications/kysdk-qtwidgets/test/testksettinggroup/widget.h0000664000175000017500000000233315104543305025357 0ustar fengfeng/* * * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Sisheng He * */ #ifndef WIDGET_H #define WIDGET_H #include "kwidget.h" #include "kaddbutton.h" #include "kcomboboxframe.h" #include "klineeditframe.h" #include "kpushbuttonframe.h" #include "kradiobuttonframe.h" #include "ksettinggroup.h" #include "ksliderframe.h" #include "kswitchbuttonframe.h" using namespace kdk; class Widget : public KWidget { Q_OBJECT public: Widget(QWidget *parent = nullptr); ~Widget(); void initUI(QWidget *parent); private: }; #endif libkysdk-applications/kysdk-qtwidgets/test/testksettinggroup/widget.cpp0000664000175000017500000000774315104543305025724 0ustar fengfeng/* * * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Sisheng He * */ #include "widget.h" #include "ktabbar.h" #include #include #include Widget::Widget(QWidget *parent) : KWidget(parent) { initUI(this); } void Widget::initUI(QWidget *parent) { setMinimumWidth(900); KPushButtonFrame *pushbutton = new KPushButtonFrame(tr("pushbutton frame")); pushbutton->pushButton()->setText(tr("click")); KSwitchButtonFrame *switchbutton = new KSwitchButtonFrame(tr("switchbutton frame")); connect(switchbutton->switchButton(), &KSwitchButton::clicked, this, [=](bool checked) { pushbutton->setVisible(checked); }); KComboBoxFrame *comboboxbutton = new KComboBoxFrame(tr("comboboxbutton frame")); comboboxbutton->comboBox()->addItem(tr("you can add item by addItem")); comboboxbutton->comboBox()->addItem(tr("you can add item by addItem1")); connect(comboboxbutton->comboBox(), &QComboBox::currentTextChanged, this, [=](QString text) { qDebug() << "selected combox item = " << text; }); KLineEditFrame *lineeditbutton = new KLineEditFrame(tr("lineeditbutton frame")); KSliderFrame *sliderbutton = new KSliderFrame(tr("sliderbutton frame"), false); sliderbutton->leftLabel()->setText(tr("small")); sliderbutton->rightLabel()->setText(tr("large")); sliderbutton->slider()->setRange(1, 10); sliderbutton->slider()->setValue(4); connect(sliderbutton->slider(), &KSlider::valueChanged, this, [=](int value) { qDebug() << "slider value = " << value; }); KRadioButtonFrame *radiobutton = new KRadioButtonFrame(tr("radiobutton frame")); QRadioButton *button1 = new QRadioButton(tr("radio1")); QRadioButton *button2 = new QRadioButton(tr("radio2")); QRadioButton *button3 = new QRadioButton(tr("radio3")); radiobutton->addButton(button1); radiobutton->addButton(button2); radiobutton->addButton(button3); connect(radiobutton->buttonGroup(), QOverload::of(&QButtonGroup::buttonClicked), [=](QAbstractButton *button) { qDebug() << "radio button = " << button->text(); }); KAddButton *addUserBtn = new KAddButton(); addUserBtn->setObjectName("addUser"); addUserBtn->setRadiusType(KBaseFrame::BorderRadiusStyle::Around); QHBoxLayout *addUserHorLayout = new QHBoxLayout(); addUserHorLayout->setContentsMargins(0, 0, 0, 0); addUserHorLayout->addWidget(addUserBtn); KBaseFrame *addUserFrame = new KBaseFrame(this, KBaseFrame::BorderRadiusStyle::Around, true); addUserFrame->setContentsMargins(0, 0, 0, 0); addUserFrame->setObjectName("continue"); addUserFrame->setLayout(addUserHorLayout); KSettingGroup *settinggroup = new KSettingGroup(parent); settinggroup->addWidget(pushbutton); settinggroup->addWidget(switchbutton); settinggroup->addWidget(comboboxbutton); settinggroup->addWidget(lineeditbutton); settinggroup->addWidget(sliderbutton); settinggroup->addWidget(radiobutton); settinggroup->addWidget(addUserFrame); QVBoxLayout *mainLayout = new QVBoxLayout(parent); mainLayout->addWidget(settinggroup); this->baseBar()->setLayout(mainLayout); this->baseBar()->setBackgroundRole(QPalette::Window); this->setLayoutType(LayoutType::HorizontalType); } Widget::~Widget() { } libkysdk-applications/kysdk-qtwidgets/test/testksettinggroup/main.cpp0000664000175000017500000000254715104543305025362 0ustar fengfeng/* * * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Sisheng He * */ #include "widget.h" #include "kwidgetutils.h" #include #include int main(int argc, char *argv[]) { kdk::KWidgetUtils::highDpiScaling(); QApplication a(argc, argv); QTranslator trans; QString locale = QLocale::system().name(); if (locale == "zh_CN") { if (trans.load(":/translations/gui_zh_CN.qm")) { a.installTranslator(&trans); } } if (locale == "bo_CN") { if (trans.load(":/translations/gui_bo_CN.qm")) { a.installTranslator(&trans); } } Widget w; w.show(); return a.exec(); } libkysdk-applications/kysdk-qtwidgets/test/testksettinggroup/testksettinggroup.pro0000664000175000017500000000200215104543305030243 0ustar fengfengQT += core gui greaterThan(QT_MAJOR_VERSION, 4): QT += widgets CONFIG += link_pkgconfig PKGCONFIG += kysdk-qtwidgets kysdk-widgetutils CONFIG += c++17 # The following define makes your compiler emit warnings if you use # any Qt feature that has been marked deprecated (the exact warnings # depend on your compiler). Please consult the documentation of the # deprecated API in order to know how to port your code away from it. DEFINES += QT_DEPRECATED_WARNINGS # You can also make your code fail to compile if it uses deprecated APIs. # In order to do so, uncomment the following line. # You can also select to disable deprecated APIs only up to a certain version of Qt. #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 SOURCES += \ main.cpp \ widget.cpp HEADERS += \ widget.h # Default rules for deployment. qnx: target.path = /tmp/$${TARGET}/bin else: unix:!android: target.path = /opt/$${TARGET}/bin !isEmpty(target.path): INSTALLS += target libkysdk-applications/kysdk-qtwidgets/test/testKTranslucentFloor/0000775000175000017500000000000015104543305024434 5ustar fengfenglibkysdk-applications/kysdk-qtwidgets/test/testKTranslucentFloor/widget.h0000664000175000017500000000170015104543305026066 0ustar fengfeng/* * * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhenyu Wang * */ #ifndef WIDGET_H #define WIDGET_H #include class Widget : public QWidget { Q_OBJECT public: Widget(QWidget *parent = nullptr); ~Widget(); }; #endif // WIDGET_H libkysdk-applications/kysdk-qtwidgets/test/testKTranslucentFloor/testKTranslucentFloor.pro0000664000175000017500000000200115104543305031466 0ustar fengfengQT += core gui greaterThan(QT_MAJOR_VERSION, 4): QT += widgets CONFIG += c++17 CONFIG += link_pkgconfig PKGCONFIG += kysdk-qtwidgets kysdk-widgetutils # The following define makes your compiler emit warnings if you use # any Qt feature that has been marked deprecated (the exact warnings # depend on your compiler). Please consult the documentation of the # deprecated API in order to know how to port your code away from it. DEFINES += QT_DEPRECATED_WARNINGS # You can also make your code fail to compile if it uses deprecated APIs. # In order to do so, uncomment the following line. # You can also select to disable deprecated APIs only up to a certain version of Qt. #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 SOURCES += \ main.cpp \ widget.cpp HEADERS += \ widget.h # Default rules for deployment. qnx: target.path = /tmp/$${TARGET}/bin else: unix:!android: target.path = /opt/$${TARGET}/bin !isEmpty(target.path): INSTALLS += target libkysdk-applications/kysdk-qtwidgets/test/testKTranslucentFloor/widget.cpp0000664000175000017500000000427515104543305026433 0ustar fengfeng/* * * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhenyu Wang * */ #include "widget.h" #include "ktranslucentfloor.h" #include #include #include #include using namespace kdk; Widget::Widget(QWidget *parent) : QWidget(parent) { QHBoxLayout *mainLayout = new QHBoxLayout(this); QPushButton *button1 = new QPushButton("常规效果", this); QPushButton *button2 = new QPushButton("毛玻璃效果", this); mainLayout->addWidget(button1); mainLayout->addWidget(button2); KTranslucentFloor *floor1 = new KTranslucentFloor(); floor1->setEnableBlur(false); floor1->setFixedSize(400, 300); floor1->setShadow(true); QHBoxLayout *layout1 = new QHBoxLayout(floor1); QPushButton *subBtn1 = new QPushButton("关闭", this); layout1->addWidget(subBtn1); KTranslucentFloor *floor2 = new KTranslucentFloor(); floor2->setEnableBlur(true); floor2->setFixedSize(400, 300); floor2->setShadow(true); QHBoxLayout *layout2 = new QHBoxLayout(floor2); QPushButton *subBtn2 = new QPushButton("关闭", this); layout2->addWidget(subBtn2); connect(subBtn1, &QPushButton::clicked, this, [=]() { floor1->close(); }); connect(subBtn2, &QPushButton::clicked, this, [=]() { floor2->close(); }); connect(button1, &QPushButton::clicked, this, [=]() { floor1->show(); }); connect(button2, &QPushButton::clicked, this, [=]() { floor2->show(); }); } Widget::~Widget() { } libkysdk-applications/kysdk-qtwidgets/test/testKTranslucentFloor/main.cpp0000664000175000017500000000255115104543305026067 0ustar fengfeng/* * * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhenyu Wang * */ #include "widget.h" #include "kwidgetutils.h" #include #include int main(int argc, char *argv[]) { kdk::KWidgetUtils::highDpiScaling(); QApplication a(argc, argv); QTranslator trans; QString locale = QLocale::system().name(); if (locale == "zh_CN") { if (trans.load(":/translations/gui_zh_CN.qm")) { a.installTranslator(&trans); } } if (locale == "bo_CN") { if (trans.load(":/translations/gui_bo_CN.qm")) { a.installTranslator(&trans); } } Widget w; w.show(); return a.exec(); } libkysdk-applications/kysdk-qtwidgets/test/testkbackground/0000775000175000017500000000000015104543305023307 5ustar fengfenglibkysdk-applications/kysdk-qtwidgets/test/testkbackground/widget.h0000664000175000017500000000174515104543305024752 0ustar fengfeng/* * * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #ifndef WIDGET_H #define WIDGET_H #include "kwidget.h" #include using namespace kdk; class Widget : public QWidget { Q_OBJECT public: Widget(QWidget *parent = nullptr); ~Widget(); }; #endif // WIDGET_H libkysdk-applications/kysdk-qtwidgets/test/testkbackground/testkbackground.pro0000664000175000017500000000175715104543305027235 0ustar fengfengQT += core gui greaterThan(QT_MAJOR_VERSION, 4): QT += widgets CONFIG += c++17 CONFIG += link_pkgconfig PKGCONFIG += kysdk-qtwidgets # The following define makes your compiler emit warnings if you use # any Qt feature that has been marked deprecated (the exact warnings # depend on your compiler). Please consult the documentation of the # deprecated API in order to know how to port your code away from it. DEFINES += QT_DEPRECATED_WARNINGS # You can also make your code fail to compile if it uses deprecated APIs. # In order to do so, uncomment the following line. # You can also select to disable deprecated APIs only up to a certain version of Qt. #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 SOURCES += \ main.cpp \ widget.cpp HEADERS += \ widget.h # Default rules for deployment. qnx: target.path = /tmp/$${TARGET}/bin else: unix:!android: target.path = /opt/$${TARGET}/bin !isEmpty(target.path): INSTALLS += target libkysdk-applications/kysdk-qtwidgets/test/testkbackground/widget.cpp0000664000175000017500000001360215104543305025300 0ustar fengfeng/* * * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #include "widget.h" #include "kbackgroundgroup.h" #include "kborderlessbutton.h" #include "klineframe.h" #include "kpushbutton.h" #include "kswitchbutton.h" #include "ktoolbutton.h" #include #include #include #include #include using namespace kdk; Widget::Widget(QWidget *parent) : QWidget(parent) { QVBoxLayout *vmainLayout = new QVBoxLayout(this); QLabel *networkLabel = new QLabel(); networkLabel->setText("有线网络"); networkLabel->setContentsMargins(20, 0, 0, 0); QWidget *widget1 = new QWidget(); QLabel *widget1Label = new QLabel(); widget1Label->setText("开启"); KSwitchButton *widget1Switch = new KSwitchButton(); QHBoxLayout *widget1Layout = new QHBoxLayout(widget1); widget1Layout->setContentsMargins(16, 0, 16, 0); widget1Layout->addWidget(widget1Label); widget1Layout->addStretch(); widget1Layout->addWidget(widget1Switch); KBackgroundGroup *back = new KBackgroundGroup(); back->addWidget(widget1); QWidget *widget2 = new QWidget(); // widget2->setFixedHeight(100); QLabel *widget2label = new QLabel(); widget2label->setText("网卡:wwwwwww"); KBorderlessButton *less = new KBorderlessButton(); less->setIcon(QIcon::fromTheme("system-computer-symbolic")); less->setAttribute(Qt::WA_TranslucentBackground); KSwitchButton *widget2Switch = new KSwitchButton(); widget2Switch->setAttribute(Qt::WA_TranslucentBackground); QHBoxLayout *widget2Layout = new QHBoxLayout(widget2); widget2Layout->setContentsMargins(16, 0, 16, 0); widget2Layout->addWidget(widget2label); widget2Layout->addStretch(); widget2Layout->addWidget(less); widget2Layout->addWidget(widget2Switch); QWidget *widget3 = new QWidget(); // QPushButton *widget3 = new QPushButton(); widget3->setProperty("isWindowButton", 0x01); QLabel *widget3Label1 = new QLabel(); widget3Label1->setPixmap(QIcon::fromTheme("system-computer-symbolic").pixmap(16, 16)); QLabel *widget3Label2 = new QLabel(); widget3Label2->setText("网络名称"); QLabel *widget3Label3 = new QLabel(); widget3Label3->setText("连接"); KBorderlessButton *widget3btn = new KBorderlessButton(this); widget3btn->setIcon(QIcon::fromTheme("stock-people-symbolic")); widget3btn->setAttribute(Qt::WA_TranslucentBackground); QHBoxLayout *widget3Layout = new QHBoxLayout(widget3); widget3Layout->setContentsMargins(16, 0, 16, 0); widget3Layout->addWidget(widget3Label1); widget3Layout->addWidget(widget3Label2); widget3Layout->addStretch(); widget3Layout->addWidget(widget3Label3); widget3Layout->addWidget(widget3btn); QWidget *widget4 = new QWidget(); QLabel *widget4Label1 = new QLabel(); widget4Label1->setText("点击添加"); QLabel *widget4Label2 = new QLabel(); widget4Label2->setPixmap(QIcon::fromTheme("system-computer-symbolic").pixmap(16, 16)); QHBoxLayout *widget4Layout = new QHBoxLayout(widget4); widget4Layout->addStretch(); widget4Layout->addWidget(widget4Label2); widget4Layout->addWidget(widget4Label1); widget4Layout->addStretch(); QList list; list.append(widget2); list.append(widget3); list.append(widget4); KBackgroundGroup *back1 = new KBackgroundGroup(); back1->addWidgetList(list); back1->setStateEnable(widget3, true); back1->setStateEnable(widget4, true); QWidget *widget5 = new QWidget(); widget5->hide(); QWidget *widget6 = new QWidget(); widget6->setWindowIcon(QIcon::fromTheme("kylin-music")); widget6->hide(); connect(widget1Switch, &KSwitchButton::clicked, this, [=]() { if (back1->isVisible()) back1->hide(); else back1->show(); }); // 插入删除 connect(widget2Switch, &KSwitchButton::clicked, this, [=]() { if (back1->widgetList().contains(widget3)) back1->removeWidget(widget3); else back1->insertWidgetAt(back1->widgetList().count() - 1, widget3); back1->setStateEnable(widget3, true); }); connect(less, &KBorderlessButton::clicked, this, [=]() { if (back1->widgetList().contains(widget3)) back1->removeWidget(widget3); else back1->insertWidgetAt(back1->widgetList().count() - 1, widget3); back1->setStateEnable(widget3, true); }); connect(back1, &KBackgroundGroup::clicked, this, [=](QWidget *widget) { if (widget == widget3) { if (widget3Label3->isVisible()) widget3Label3->hide(); else widget3Label3->show(); } if (widget == widget4) { if (widget6->isVisible()) widget6->hide(); else widget6->show(); } }); connect(widget3btn, &KBorderlessButton::clicked, this, [=]() { if (widget5->isVisible()) widget5->hide(); else widget5->show(); }); vmainLayout->addWidget(networkLabel); vmainLayout->addWidget(back); vmainLayout->addWidget(back1); vmainLayout->addStretch(); } Widget::~Widget() { } libkysdk-applications/kysdk-qtwidgets/test/testkbackground/main.cpp0000664000175000017500000000164615104515306024746 0ustar fengfeng/* * * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #include "widget.h" #include int main(int argc, char *argv[]) { QApplication a(argc, argv); Widget w; w.show(); return a.exec(); } libkysdk-applications/kysdk-qtwidgets/test/testTranslucent/0000775000175000017500000000000015104543305023317 5ustar fengfenglibkysdk-applications/kysdk-qtwidgets/test/testTranslucent/widget.h0000664000175000017500000000177615104515306024766 0ustar fengfeng/* * * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #ifndef WIDGET_H #define WIDGET_H #include class Widget : public QWidget { Q_OBJECT public: Widget(QWidget *parent = nullptr); ~Widget(); protected: bool eventFilter(QObject *watched, QEvent *event); }; #endif // WIDGET_H libkysdk-applications/kysdk-qtwidgets/test/testTranslucent/testTranslucent.pro0000664000175000017500000000216115104543305027243 0ustar fengfengQT += core gui greaterThan(QT_MAJOR_VERSION, 4): QT += widgets DEFINES += USE_UKUI_PROTOCOL DEFINES += USE_UKUI_SHELL_PLUGIN CONFIG += c++17 link_pkgconfig PKGCONFIG += kysdk-widgetutils kysdk-ukuiwindowhelper kysdk-waylandhelper kysdk-qtwidgets KF6WindowSystem # The following define makes your compiler emit warnings if you use # any Qt feature that has been marked deprecated (the exact warnings # depend on your compiler). Please consult the documentation of the # deprecated API in order to know how to port your code away from it. DEFINES += QT_DEPRECATED_WARNINGS # You can also make your code fail to compile if it uses deprecated APIs. # In order to do so, uncomment the following line. # You can also select to disable deprecated APIs only up to a certain version of Qt. #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 SOURCES += \ main.cpp \ widget.cpp HEADERS += \ widget.h # Default rules for deployment. qnx: target.path = /tmp/$${TARGET}/bin else: unix:!android: target.path = /opt/$${TARGET}/bin !isEmpty(target.path): INSTALLS += target libkysdk-applications/kysdk-qtwidgets/test/testTranslucent/widget.cpp0000664000175000017500000001024515104543305025310 0ustar fengfeng/* * * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #include "widget.h" #include "kpressbutton.h" #include "kpushbutton.h" #include "ksearchlineedit.h" #include "kslider.h" #include "kswitchbutton.h" #include #include #include #include #include #include #include using namespace kdk; Widget::Widget(QWidget *parent) : QWidget(parent) { setAttribute(Qt::WA_TranslucentBackground); QVBoxLayout *mainLayout = new QVBoxLayout(this); QWidget *mainWidget = new QWidget(this); mainWidget->setFocusPolicy(Qt::FocusPolicy::ClickFocus); mainWidget->installEventFilter(this); QLabel *label1 = new QLabel("KSlider", this); label1->move(50, 100); KSlider *slider = new KSlider(mainWidget); slider->setToolTip("this is a tool tip"); slider->setRange(0, 100); // 测试接口 slider->setTranslucent(true); slider->setTickInterval(20); slider->setFixedWidth(300); slider->move(200, 100); QLabel *label2 = new QLabel("KSwitchButton", this); label2->setFixedWidth(150); label2->move(50, 200); KSwitchButton *switchbutton = new KSwitchButton(mainWidget); // 测试接口 switchbutton->setTranslucent(true); switchbutton->move(200, 200); QLabel *label3 = new QLabel("KSearchLineEdit", this); label3->move(50, 300); KSearchLineEdit *lineEdit = new KSearchLineEdit(mainWidget); lineEdit->move(200, 300); // 测试接口 lineEdit->setTranslucent(true); QLabel *label4 = new QLabel("KPressButton", this); label4->move(50, 400); KPressButton *pressBtn1 = new KPressButton(this); pressBtn1->setButtonType(KPressButton::CircleType); pressBtn1->setFixedSize(40, 40); pressBtn1->setIcon(QIcon::fromTheme("ukui-alarm-symbolic")); // 测试接口 pressBtn1->setTranslucent(true); pressBtn1->move(200, 400); KPressButton *pressBtn2 = new KPressButton(this); pressBtn2->setFixedSize(40, 40); pressBtn2->setIcon(QIcon::fromTheme("ukui-alarm-symbolic")); // 测试接口 pressBtn2->setTranslucent(true); pressBtn2->move(250, 400); QLabel *label5 = new QLabel("KPushButton", this); label5->move(50, 500); KPushButton *pushbtn1 = new KPushButton(this); pushbtn1->setButtonType(KPushButton::CircleType); pushbtn1->setFixedSize(40, 40); pushbtn1->setIcon(QIcon::fromTheme("ukui-alarm-symbolic")); pushbtn1->setTranslucent(true); pushbtn1->move(200, 500); KPushButton *pushbtn2 = new KPushButton(this); pushbtn2->setFixedSize(40, 40); pushbtn2->setIcon(QIcon::fromTheme("ukui-alarm-symbolic")); pushbtn2->setIconColor(QColor(255, 0, 0)); // 测试接口 pushbtn2->setTranslucent(true); pushbtn2->move(250, 500); mainLayout->addWidget(mainWidget); mainLayout->setContentsMargins(0, 0, 0, 0); setFixedSize(800, 600); } Widget::~Widget() { } bool Widget::eventFilter(QObject *watched, QEvent *event) { if (event->type() == QEvent::Paint) { auto widget = qobject_cast(watched); if (widget) { widget->setAutoFillBackground(true); QPalette palette = this->palette(); auto color = this->palette().color(QPalette::Window); color.setAlphaF(0.39); palette.setColor(QPalette::Window, color); widget->setPalette(palette); widget->setBackgroundRole(QPalette::Window); } } return QObject::eventFilter(watched, event); } libkysdk-applications/kysdk-qtwidgets/test/testTranslucent/main.cpp0000664000175000017500000000253115104543305024750 0ustar fengfeng/* * * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #include "widget.h" #include #include // #include #include "ukuiwindowhelper/ukuiwindowhelper.h" int main(int argc, char *argv[]) { // kdk::KWidgetUtils::highDpiScaling(); QApplication a(argc, argv); Widget w; w.show(); // KWindowEffects::enableBlurBehind(w.winId(), true); UkuiWindowHelper *m_ukuiWindowHelper = new UkuiWindowHelper(&w); #ifdef USE_UKUI_SHELL_PLUGIN m_ukuiWindowHelper->setBlurEffect(QRegion(), 0, true); #else KWindowEffects::enableBlurBehind(this->winId(),true); #endif return a.exec(); } libkysdk-applications/kysdk-qtwidgets/test/testAddFileButton/0000775000175000017500000000000015104543305023501 5ustar fengfenglibkysdk-applications/kysdk-qtwidgets/test/testAddFileButton/widget.h0000664000175000017500000000167515104543305025146 0ustar fengfeng/* * * Copyright (C) 2024, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhenyu Wang * */ #ifndef WIDGET_H #define WIDGET_H #include class Widget : public QWidget { Q_OBJECT public: Widget(QWidget *parent = nullptr); ~Widget(); }; #endif // WIDGET_H libkysdk-applications/kysdk-qtwidgets/test/testAddFileButton/testAddFileButton.pro0000664000175000017500000000200215104543305027601 0ustar fengfengQT += core gui greaterThan(QT_MAJOR_VERSION, 4): QT += widgets CONFIG += c++17 CONFIG += link_pkgconfig PKGCONFIG += kysdk-widgetutils kysdk-qtwidgets # The following define makes your compiler emit warnings if you use # any Qt feature that has been marked deprecated (the exact warnings # depend on your compiler). Please consult the documentation of the # deprecated API in order to know how to port your code away from it. DEFINES += QT_DEPRECATED_WARNINGS # You can also make your code fail to compile if it uses deprecated APIs. # In order to do so, uncomment the following line. # You can also select to disable deprecated APIs only up to a certain version of Qt. #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 SOURCES += \ main.cpp \ widget.cpp HEADERS += \ widget.h # Default rules for deployment. qnx: target.path = /tmp/$${TARGET}/bin else: unix:!android: target.path = /opt/$${TARGET}/bin !isEmpty(target.path): INSTALLS += target libkysdk-applications/kysdk-qtwidgets/test/testAddFileButton/widget.cpp0000664000175000017500000000327315104543305025475 0ustar fengfeng/* * * Copyright (C) 2024, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhenyu Wang * */ #include "widget.h" #include "kaddfilebutton.h" #include #include #include #include using namespace kdk; Widget::Widget(QWidget *parent) : QWidget(parent) { QTreeView *view = new QTreeView(this); QHBoxLayout *layout = new QHBoxLayout(view); KAddFileButton *button1 = new KAddFileButton(); KAddFileButton *button2 = new KAddFileButton(); QStringList list; list << "JPEG Files(*.jpg)" << "PNG Files(*.png)"; button2->setNameFilters(list); layout->addWidget(button1); layout->addWidget(button2); connect(button1, &KAddFileButton::clicked, [=] { qDebug() << "button1 选择路径" << button1->fileDialog()->selectedFiles(); }); connect(button2, &KAddFileButton::clicked, [=] { qDebug() << "button2 选择路径" << button2->fileDialog()->selectedFiles(); }); setFixedSize(600, 500); } Widget::~Widget() { } libkysdk-applications/kysdk-qtwidgets/test/testAddFileButton/main.cpp0000664000175000017500000000165015104543305025133 0ustar fengfeng/* * * Copyright (C) 2024, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhenyu Wang * */ #include "widget.h" #include int main(int argc, char *argv[]) { QApplication a(argc, argv); Widget w; w.show(); return a.exec(); } libkysdk-applications/kysdk-qtwidgets/test/testKDragWidget/0000775000175000017500000000000015104543305023151 5ustar fengfenglibkysdk-applications/kysdk-qtwidgets/test/testKDragWidget/widget.h0000664000175000017500000000167515104543305024616 0ustar fengfeng/* * * Copyright (C) 2024, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhenyu Wang * */ #ifndef WIDGET_H #define WIDGET_H #include class Widget : public QWidget { Q_OBJECT public: Widget(QWidget *parent = nullptr); ~Widget(); }; #endif // WIDGET_H libkysdk-applications/kysdk-qtwidgets/test/testKDragWidget/widget.cpp0000664000175000017500000000452415104543305025145 0ustar fengfeng/* * * Copyright (C) 2024, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhenyu Wang * */ #include "widget.h" #include "kdragwidget.h" #include "kiconbar.h" #include "ktoolbutton.h" #include #include #include #include #include #include #include #include #include #include #include #include using namespace kdk; Widget::Widget(QWidget *parent) : QWidget(parent) { QVBoxLayout *mainlayout = new QVBoxLayout(this); QLabel *label1 = new QLabel(); label1->setText("添加过滤文件"); KDragWidget *widget1 = new KDragWidget(); widget1->iconButton()->setIcon(QIcon::fromTheme("list-add.symbolic")); widget1->textLabel()->setText("选择或者拖放文件夹识别路径"); QStringList list; list << "JPEG Files(*.jpg)" << "PNG Files(*.png)" << "PGM Files(*.pgm)"; widget1->setNameFilters(list); mainlayout->addWidget(label1); mainlayout->addWidget(widget1); QLabel *label2 = new QLabel(); label2->setText("添加所有文件"); KDragWidget *widget2 = new KDragWidget(); widget2->iconButton()->setIcon(QIcon::fromTheme("list-add.symbolic")); widget2->textLabel()->setText("选择或者拖放文件夹识别路径"); mainlayout->addWidget(label2); mainlayout->addWidget(widget2); connect(widget1, &KDragWidget::getPath, [=](QString str) { qDebug() << "widget1 " << str; }); connect(widget2, &KDragWidget::getPath, [=](QString str) { qDebug() << "widget2 " << str; }); setMinimumSize(600, 480); } Widget::~Widget() { } libkysdk-applications/kysdk-qtwidgets/test/testKDragWidget/main.cpp0000664000175000017500000000175215104543305024606 0ustar fengfeng/* * * Copyright (C) 2024, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhenyu Wang * */ #include "kwidgetutils.h" #include "widget.h" #include int main(int argc, char *argv[]) { kdk::KWidgetUtils::highDpiScaling(); QApplication a(argc, argv); Widget w; w.show(); return a.exec(); } libkysdk-applications/kysdk-qtwidgets/test/testKDragWidget/testKDragWidget.pro0000664000175000017500000000200115104543305026720 0ustar fengfengQT += core gui greaterThan(QT_MAJOR_VERSION, 4): QT += widgets CONFIG += c++17 CONFIG += link_pkgconfig PKGCONFIG += kysdk-widgetutils kysdk-qtwidgets # The following define makes your compiler emit warnings if you use # any Qt feature that has been marked deprecated (the exact warnings # depend on your compiler). Please consult the documentation of the # deprecated API in order to know how to port your code away from it. DEFINES += QT_DEPRECATED_WARNINGS # You can also make your code fail to compile if it uses deprecated APIs. # In order to do so, uncomment the following line. # You can also select to disable deprecated APIs only up to a certain version of Qt. #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 SOURCES += \ main.cpp \ widget.cpp HEADERS += \ widget.h # Default rules for deployment. qnx: target.path = /tmp/$${TARGET}/bin else: unix:!android: target.path = /opt/$${TARGET}/bin !isEmpty(target.path): INSTALLS += target libkysdk-applications/kysdk-qtwidgets/test/testlineedit/0000775000175000017500000000000015104543305022612 5ustar fengfenglibkysdk-applications/kysdk-qtwidgets/test/testlineedit/widget.h0000664000175000017500000000167515104543305024257 0ustar fengfeng/* * * Copyright (C) 2024, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhenyu Wang * */ #ifndef WIDGET_H #define WIDGET_H #include class Widget : public QWidget { Q_OBJECT public: Widget(QWidget *parent = nullptr); ~Widget(); }; #endif // WIDGET_H libkysdk-applications/kysdk-qtwidgets/test/testlineedit/testlineedit.pro0000664000175000017500000000200115104543305026022 0ustar fengfengQT += core gui greaterThan(QT_MAJOR_VERSION, 4): QT += widgets CONFIG += c++17 CONFIG += link_pkgconfig PKGCONFIG += kysdk-widgetutils kysdk-qtwidgets # The following define makes your compiler emit warnings if you use # any Qt feature that has been marked deprecated (the exact warnings # depend on your compiler). Please consult the documentation of the # deprecated API in order to know how to port your code away from it. DEFINES += QT_DEPRECATED_WARNINGS # You can also make your code fail to compile if it uses deprecated APIs. # In order to do so, uncomment the following line. # You can also select to disable deprecated APIs only up to a certain version of Qt. #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 SOURCES += \ main.cpp \ widget.cpp HEADERS += \ widget.h # Default rules for deployment. qnx: target.path = /tmp/$${TARGET}/bin else: unix:!android: target.path = /opt/$${TARGET}/bin !isEmpty(target.path): INSTALLS += target libkysdk-applications/kysdk-qtwidgets/test/testlineedit/widget.cpp0000664000175000017500000000255115104543305024604 0ustar fengfeng/* * * Copyright (C) 2024, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhenyu Wang * */ #include "widget.h" #include "klineedit.h" #include #include #include using namespace kdk; Widget::Widget(QWidget *parent) : QWidget(parent) { QVBoxLayout *vlayout = new QVBoxLayout(this); KLineEdit *edit = new KLineEdit(this); QPushButton *btn = edit->pushbutton(); btn->setIcon(QIcon::fromTheme("system-computer-symbolic")); connect(btn, &QPushButton::clicked, this, [=] { qDebug() << edit->text(); }); vlayout->addWidget(edit); QPushButton *btn1 = new QPushButton(this); vlayout->addWidget(btn1); } Widget::~Widget() { } libkysdk-applications/kysdk-qtwidgets/test/testlineedit/main.cpp0000664000175000017500000000165015104543305024244 0ustar fengfeng/* * * Copyright (C) 2024, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhenyu Wang * */ #include "widget.h" #include int main(int argc, char *argv[]) { QApplication a(argc, argv); Widget w; w.show(); return a.exec(); } libkysdk-applications/kysdk-qtwidgets/test/testtableview/0000775000175000017500000000000015104543305022777 5ustar fengfenglibkysdk-applications/kysdk-qtwidgets/test/testtableview/widget.h0000664000175000017500000000027115104543305024433 0ustar fengfeng#ifndef WIDGET_H #define WIDGET_H #include class Widget : public QWidget { Q_OBJECT public: Widget(QWidget *parent = nullptr); ~Widget(); }; #endif // WIDGET_H libkysdk-applications/kysdk-qtwidgets/test/testtableview/testtableview.pro0000664000175000017500000000200115104543305026374 0ustar fengfengQT += core gui greaterThan(QT_MAJOR_VERSION, 4): QT += widgets CONFIG += c++17 CONFIG += link_pkgconfig PKGCONFIG += kysdk-widgetutils kysdk-qtwidgets # The following define makes your compiler emit warnings if you use # any Qt feature that has been marked deprecated (the exact warnings # depend on your compiler). Please consult the documentation of the # deprecated API in order to know how to port your code away from it. DEFINES += QT_DEPRECATED_WARNINGS # You can also make your code fail to compile if it uses deprecated APIs. # In order to do so, uncomment the following line. # You can also select to disable deprecated APIs only up to a certain version of Qt. #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 SOURCES += \ main.cpp \ widget.cpp HEADERS += \ widget.h # Default rules for deployment. qnx: target.path = /tmp/$${TARGET}/bin else: unix:!android: target.path = /opt/$${TARGET}/bin !isEmpty(target.path): INSTALLS += target libkysdk-applications/kysdk-qtwidgets/test/testtableview/widget.cpp0000664000175000017500000000517115104543305024772 0ustar fengfeng#include "widget.h" #include "ktableheaderview.h" #include "ktablemodel.h" #include "ktableview.h" #include #include #include using namespace kdk; Widget::Widget(QWidget *parent) : QWidget(parent) { KTableModel *model = new KTableModel(); KTableView *tableview = new KTableView(this); // tableview->setShowGrid(false); tableview->verticalHeader()->setVisible(false); QStringList head_list; head_list << "文件项" << "格式" << "时间" << "大小"; tableview->setHorizontalTitle(head_list); for (int i = 0; i < 5; i++) { QList add_items; for (int index = 0; index < head_list.count(); ++index) { add_items << new QStandardItem(QString::number(i + index)); } model->appendRow(add_items); } tableview->setModel(model); tableview->setFixedSize(600, 500); tableview->setContextMenuPolicy(Qt::CustomContextMenu); // 必须设置 QMenu *tableviewMenu = new QMenu(tableview); QAction *Action1 = new QAction("tableview 1", tableview); QAction *Action2 = new QAction("tableview 2", tableview); tableviewMenu->addAction(Action1); tableviewMenu->addAction(Action2); QMenu *headmenu1 = new QMenu(tableview); QAction *Action3 = new QAction("headmenu1 1", tableview); QAction *Action4 = new QAction("headmenu1 2", tableview); headmenu1->addAction(Action3); headmenu1->addAction(Action4); QMenu *headmenu2 = new QMenu(tableview); QAction *Action5 = new QAction("headmenu2 1", tableview); QAction *Action6 = new QAction("headmenu2 2", tableview); headmenu2->addAction(Action5); headmenu2->addAction(Action6); QModelIndexList list = tableview->selectionModel()->selectedIndexes(); connect(tableview, &KTableView::customContextMenuRequested, this, [=] { tableviewMenu->exec(QCursor::pos()); for (int i = 0; i < list.count(); i++) qDebug() << list.at(i).data().toString(); }); tableview->headerView()->setMenu(headmenu1, 1); tableview->headerView()->setMenu(headmenu2, 2); // for(int i = 0;i < tableview->model()->rowCount();i++) // qDebug()<< model->data(model->index(i,1)).toString(); QPushButton *btn = new QPushButton(this); btn->move(0, 300); btn->setText("获取选中行的索引"); connect(btn, &QPushButton::clicked, this, [=] { QList list1 = tableview->selectList(); qDebug() << "list1" << list1.count(); for (int i = 0; i < list1.count(); i++) qDebug() << list1.at(i); }); } Widget::~Widget() { } libkysdk-applications/kysdk-qtwidgets/test/testtableview/main.cpp0000664000175000017500000000024415104543305024427 0ustar fengfeng#include "widget.h" #include int main(int argc, char *argv[]) { QApplication a(argc, argv); Widget w; w.show(); return a.exec(); } libkysdk-applications/kysdk-qtwidgets/test/testsearchlinedit/0000775000175000017500000000000015104543305023633 5ustar fengfenglibkysdk-applications/kysdk-qtwidgets/test/testsearchlinedit/widget.h0000664000175000017500000000221315104543305025265 0ustar fengfeng/* * * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #ifndef WIDGET_H #define WIDGET_H #include "ksearchlineedit.h" #include "kwidget.h" #include using namespace kdk; class Widget : public KWidget { Q_OBJECT public: Widget(QWidget *parent = nullptr); ~Widget(); private: KSearchLineEdit *m_pSearchLineEdit1; QLabel *m_pLabel1; KSearchLineEdit *m_pSearchLineEdit2; QLabel *m_pLabel2; }; #endif // WIDGET_H libkysdk-applications/kysdk-qtwidgets/test/testsearchlinedit/widget.cpp0000664000175000017500000000570115104543305025625 0ustar fengfeng/* * * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #include "widget.h" #include #include Widget::Widget(QWidget *parent) : KWidget(parent) { QVBoxLayout *mainLayout = new QVBoxLayout; mainLayout->addStretch(); QHBoxLayout *hLayout = new QHBoxLayout; m_pSearchLineEdit1 = new KSearchLineEdit(this); // 构造一个搜索框 // m_pSearchLineEdit1->setPlaceholderAlignment(Qt::AlignCenter); //设置placeholder的对齐方式 m_pSearchLineEdit1->setClearButtonEnabled(true); // 是否启用清除键(true为启用) m_pSearchLineEdit1->setPlaceholderText("此处需要输入很长非常长的需要查找的内容"); // 设置placeholder的文本内容 m_pSearchLineEdit1->setAlignment(Qt::AlignLeft); // 设置输入内容的对齐方式 m_pLabel1 = new QLabel(this); hLayout->addWidget(m_pSearchLineEdit1); QPushButton *btn1 = new QPushButton(this); btn1->setText("隐藏"); QPushButton *btn2 = new QPushButton(this); btn2->setText("显示"); btn2->move(110, 0); QPushButton *btn3 = new QPushButton(this); btn3->setText("清除"); btn3->move(220, 0); connect(btn1, &QPushButton::clicked, this, [=] { m_pSearchLineEdit1->hide(); }); connect(btn2, &QPushButton::clicked, this, [=] { m_pSearchLineEdit1->show(); }); connect(btn3, &QPushButton::clicked, this, [=] { m_pSearchLineEdit1->clear(); }); connect(m_pSearchLineEdit1, &KSearchLineEdit::returnPressed, this, [=]() { m_pLabel1->setText(QString("Search Content is:%1").arg(m_pSearchLineEdit1->text())); }); mainLayout->addLayout(hLayout); mainLayout->addWidget(m_pLabel1); hLayout = new QHBoxLayout; m_pSearchLineEdit2 = new KSearchLineEdit(this); m_pLabel2 = new QLabel(this); m_pSearchLineEdit2->setEnabled(false); // 设置搜索框是否可用 hLayout->addWidget(m_pSearchLineEdit2); connect(m_pSearchLineEdit2, &KSearchLineEdit::returnPressed, this, [=]() { m_pLabel2->setText(QString("Search Content is:%1").arg(m_pSearchLineEdit2->text())); }); mainLayout->addLayout(hLayout); mainLayout->addWidget(m_pLabel2); mainLayout->addStretch(); baseBar()->setLayout(mainLayout); } Widget::~Widget() { } libkysdk-applications/kysdk-qtwidgets/test/testsearchlinedit/testsearchlinedit.pro0000664000175000017500000000200315104543305030066 0ustar fengfengQT += core gui greaterThan(QT_MAJOR_VERSION, 4): QT += widgets CONFIG += c++17 CONFIG += link_pkgconfig PKGCONFIG += kysdk-qtwidgets kysdk-widgetutils # The following define makes your compiler emit warnings if you use # any Qt feature that has been marked deprecated (the exact warnings # depend on your compiler). Please consult the documentation of the # deprecated API in order to know how to port your code away from it. DEFINES += QT_DEPRECATED_WARNINGS # You can also make your code fail to compile if it uses deprecated APIs. # In order to do so, uncomment the following line. # You can also select to disable deprecated APIs only up to a certain version of Qt. #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 SOURCES += \ main.cpp \ widget.cpp HEADERS += \ widget.h # Default rules for deployment. qnx: target.path = /tmp/$${TARGET}/bin else: unix:!android: target.path = /opt/$${TARGET}/bin !isEmpty(target.path): INSTALLS += target libkysdk-applications/kysdk-qtwidgets/test/testsearchlinedit/main.cpp0000664000175000017500000000254415104543305025270 0ustar fengfeng/* * * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #include "widget.h" #include "kwidgetutils.h" #include #include int main(int argc, char *argv[]) { kdk::KWidgetUtils::highDpiScaling(); QApplication a(argc, argv); QTranslator trans; QString locale = QLocale::system().name(); if (locale == "zh_CN") { if (trans.load(":/translations/gui_zh_CN.qm")) { a.installTranslator(&trans); } } if (locale == "bo_CN") { if (trans.load(":/translations/gui_bo_CN.qm")) { a.installTranslator(&trans); } } Widget w; w.show(); return a.exec(); } libkysdk-applications/kysdk-qtwidgets/test/testsecuritylevelbar/0000775000175000017500000000000015104543305024401 5ustar fengfenglibkysdk-applications/kysdk-qtwidgets/test/testsecuritylevelbar/testsecuritylevelbar.pro0000664000175000017500000000200115104543305031400 0ustar fengfengQT += core gui greaterThan(QT_MAJOR_VERSION, 4): QT += widgets CONFIG += link_pkgconfig PKGCONFIG += kysdk-qtwidgets kysdk-widgetutils CONFIG += c++17 # The following define makes your compiler emit warnings if you use # any Qt feature that has been marked deprecated (the exact warnings # depend on your compiler). Please consult the documentation of the # deprecated API in order to know how to port your code away from it. DEFINES += QT_DEPRECATED_WARNINGS # You can also make your code fail to compile if it uses deprecated APIs. # In order to do so, uncomment the following line. # You can also select to disable deprecated APIs only up to a certain version of Qt. #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 SOURCES += \ main.cpp \ widget.cpp HEADERS += \ widget.h # Default rules for deployment. qnx: target.path = /tmp/$${TARGET}/bin else: unix:!android: target.path = /opt/$${TARGET}/bin !isEmpty(target.path): INSTALLS += target libkysdk-applications/kysdk-qtwidgets/test/testsecuritylevelbar/widget.h0000664000175000017500000000224715104543305026042 0ustar fengfeng/* * * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #ifndef WIDGET_H #define WIDGET_H #include "ksecuritylevelbar.h" #include "kwidget.h" #include #include #include using namespace kdk; class Widget : public KWidget { Q_OBJECT public: Widget(QWidget *parent = nullptr); ~Widget(); private: KSecurityLevelBar *m_pBar; QLineEdit *m_pLineEdit; QLabel *m_pInfoLabel; QPushButton *m_pBtn; }; #endif // WIDGET_H libkysdk-applications/kysdk-qtwidgets/test/testsecuritylevelbar/widget.cpp0000664000175000017500000000405615104543305026375 0ustar fengfeng/* * * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #include "widget.h" #include Widget::Widget(QWidget *parent) : KWidget(parent) { QVBoxLayout *vLayout = new QVBoxLayout(); QHBoxLayout *hLayout = new QHBoxLayout(); m_pInfoLabel = new QLabel("请设置密码:", this); m_pLineEdit = new QLineEdit(this); m_pLineEdit->setEchoMode(QLineEdit::Password); hLayout->addWidget(m_pInfoLabel); hLayout->addWidget(m_pLineEdit); vLayout->addStretch(); vLayout->addLayout(hLayout); hLayout = new QHBoxLayout(); m_pBar = new KSecurityLevelBar(this); // 构建一个安全等级提示条 m_pBar->hide(); // 隐藏安全等级提示条 hLayout->addWidget(m_pBar); vLayout->addLayout(hLayout); vLayout->addStretch(); baseBar()->setLayout(vLayout); // 连接槽函数,根据输入密码的长度来设置安全等级进度条的等级并显示。 connect(m_pLineEdit, &QLineEdit::textChanged, this, [=]() { int length = m_pLineEdit->text().length(); if (length < 8) m_pBar->setSecurityLevel(SecurityLevel::Low); // 设置安全等级 else if (length >= 8 && length < 12) m_pBar->setSecurityLevel(SecurityLevel::Medium); else m_pBar->setSecurityLevel(SecurityLevel::High); m_pBar->show(); }); } Widget::~Widget() { } libkysdk-applications/kysdk-qtwidgets/test/testsecuritylevelbar/main.cpp0000664000175000017500000000254415104543305026036 0ustar fengfeng/* * * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #include "widget.h" #include "kwidgetutils.h" #include #include int main(int argc, char *argv[]) { kdk::KWidgetUtils::highDpiScaling(); QApplication a(argc, argv); QTranslator trans; QString locale = QLocale::system().name(); if (locale == "zh_CN") { if (trans.load(":/translations/gui_zh_CN.qm")) { a.installTranslator(&trans); } } if (locale == "bo_CN") { if (trans.load(":/translations/gui_bo_CN.qm")) { a.installTranslator(&trans); } } Widget w; w.show(); return a.exec(); } libkysdk-applications/kysdk-qtwidgets/test/testDialog/0000775000175000017500000000000015104543305022214 5ustar fengfenglibkysdk-applications/kysdk-qtwidgets/test/testDialog/widget.h0000664000175000017500000000172315104543305023653 0ustar fengfeng/* * * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #ifndef WIDGET_H #define WIDGET_H #include "kwidget.h" using namespace kdk; class Widget : public KWidget { Q_OBJECT public: Widget(QWidget *parent = nullptr); ~Widget(); }; #endif // WIDGET_H libkysdk-applications/kysdk-qtwidgets/test/testDialog/testDialog.pro0000664000175000017500000000200115104543305025026 0ustar fengfengQT += core gui greaterThan(QT_MAJOR_VERSION, 4): QT += widgets CONFIG += c++17 CONFIG += link_pkgconfig PKGCONFIG += kysdk-qtwidgets kysdk-widgetutils # The following define makes your compiler emit warnings if you use # any Qt feature that has been marked deprecated (the exact warnings # depend on your compiler). Please consult the documentation of the # deprecated API in order to know how to port your code away from it. DEFINES += QT_DEPRECATED_WARNINGS # You can also make your code fail to compile if it uses deprecated APIs. # In order to do so, uncomment the following line. # You can also select to disable deprecated APIs only up to a certain version of Qt. #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 SOURCES += \ main.cpp \ widget.cpp HEADERS += \ widget.h # Default rules for deployment. qnx: target.path = /tmp/$${TARGET}/bin else: unix:!android: target.path = /opt/$${TARGET}/bin !isEmpty(target.path): INSTALLS += target libkysdk-applications/kysdk-qtwidgets/test/testDialog/widget.cpp0000664000175000017500000000574215104543305024213 0ustar fengfeng/* * * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #include "widget.h" #include #include #include "kaboutdialog.h" #include "kdialog.h" #include "kuninstalldialog.h" Widget::Widget(QWidget *parent) : KWidget(parent) { QVBoxLayout *vLayout = new QVBoxLayout; QPushButton *pBtn1 = new QPushButton("对话框", this); QPushButton *pBtn2 = new QPushButton("卸载对话框", this); QPushButton *pBtn3 = new QPushButton("关于对话框", this); KDialog *dialog = new KDialog(); // 设置标题 dialog->setWindowTitle("对话框"); // 设置icon dialog->setWindowIcon("kylin-music"); // 显示最小化和最大化按钮 dialog->maximumButton()->show(); dialog->minimumButton()->show(); KUninstallDialog *uninstallDialog = new KUninstallDialog("browser360-cn-stable", "104", this); KAboutDialog *aboutDialog = new KAboutDialog(this, QIcon::fromTheme("kylin-music"), "麒麟音乐", tr("版本:2020.1.0")); aboutDialog->setBodyText("关于对话框,包含的主要内容有:应用图标,应用名称,版本号,团队邮箱以及具体的应用描述,注意,默认应用描述是不显示的。"); aboutDialog->setBodyTextVisiable(true); vLayout->addStretch(); vLayout->addWidget(pBtn1); vLayout->addWidget(pBtn2); vLayout->addWidget(pBtn3); vLayout->addStretch(); connect(pBtn1, &QPushButton::clicked, this, [=]() { dialog->show(); }); connect(pBtn2, &QPushButton::clicked, this, [=]() { uninstallDialog->show(); }); connect(pBtn3, &QPushButton::clicked, this, [=]() { aboutDialog->show(); }); // QHBoxLayout* tmpLayout = dynamic_cast(windowButtonBar()->layout()); // QPushButton* btn = new QPushButton("btn",this); // tmpLayout->insertWidget(1,btn); QHBoxLayout *hLayout = new QHBoxLayout(dialog); QPushButton *pBtn5 = new QPushButton("对话框", dialog); hLayout->addWidget(pBtn5); dialog->mainWidget()->setLayout(hLayout); // 获取主内容区,通过setLayout()添加内容 dialog->menuButton()->show(); // 获取下拉菜单按钮,默认是隐藏的,不显示 // dialog->closeButton()->show();//获取关闭按钮。 baseBar()->setLayout(vLayout); } Widget::~Widget() { } libkysdk-applications/kysdk-qtwidgets/test/testDialog/main.cpp0000664000175000017500000000254415104543305023651 0ustar fengfeng/* * * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #include "widget.h" #include "kwidgetutils.h" #include #include int main(int argc, char *argv[]) { kdk::KWidgetUtils::highDpiScaling(); QApplication a(argc, argv); QTranslator trans; QString locale = QLocale::system().name(); if (locale == "zh_CN") { if (trans.load(":/translations/gui_zh_CN.qm")) { a.installTranslator(&trans); } } if (locale == "bo_CN") { if (trans.load(":/translations/gui_bo_CN.qm")) { a.installTranslator(&trans); } } Widget w; w.show(); return a.exec(); } libkysdk-applications/kysdk-qtwidgets/src/0000775000175000017500000000000015104543305017725 5ustar fengfenglibkysdk-applications/kysdk-qtwidgets/src/kslider.h0000664000175000017500000000626515104543305021544 0ustar fengfeng/* * libkysdk-qtwidgets's Library * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #ifndef KSLIDER_H #define KSLIDER_H #include "gui_g.h" #include #include namespace kdk { /** @defgroup SliderModule * @{ */ enum KSliderType { SmoothSlider, StepSlider, NodeSlider, SingleSelectSlider }; class KSliderPrivate; /** * @brief 支持三种样式的滑动条 * 非步数关系:步数为1,可以在任意位置点击和拖拽 * 步数关系:步数为固定值,可根据步数值点击和拖拽 * 节点关系:步数为节点间隔,可根据节点间隔点击和拖拽 * @since 1.0.0 */ class KSlider : public QSlider { Q_OBJECT public: KSlider(QWidget *parent); KSlider(Qt::Orientation orientation, QWidget *parent = nullptr); /** * @brief 设置节点间隔 * @param interval */ void setTickInterval(int interval); /** * @brief 设置滑动条类型 * @param type */ void setSliderType(KSliderType type); /** * @brief 获取滑动条类型 * @return */ KSliderType sliderType(); /** * @brief 获取节点间隔 * @return */ int tickInterval() const; /** * @brief 设置值 */ void setValue(int); /** * @brief 设置是否显示节点 * @return */ void setNodeVisible(bool flag); /** * @brief 获取是否显示节点 * @return */ bool nodeVisible(); /** * @brief 设置tooltip * @since 1.2.0 */ void setToolTip(const QString &); /** * @brief 获取toolTip * @since 1.2.0 * @return */ QString toolTip() const; /** * @brief 设置是否启用半透明效果 * @since 1.2.0 * @param flag */ void setTranslucent(bool flag); /** * @brief 获取是否启用半透明效果 * @since 1.2.0 * @return flag */ bool isTranslucent(); protected: void paintEvent(QPaintEvent *event); void resizeEvent(QResizeEvent *event); void mousePressEvent(QMouseEvent *event); void mouseReleaseEvent(QMouseEvent *event); void mouseMoveEvent(QMouseEvent *event); void wheelEvent(QWheelEvent *event); bool eventFilter(QObject *watched, QEvent *event); QSize sizeHint() const override; private: KSliderPrivate *const d_ptr; Q_DISABLE_COPY(KSlider) Q_DECLARE_PRIVATE(KSlider) }; } /** * @example testslider/widget.h * @example testslider/widget.cpp * @} */ #endif // KSLIDER_H libkysdk-applications/kysdk-qtwidgets/src/kclocktimer.h0000664000175000017500000000277315104543305022416 0ustar fengfeng/* * libkysdk-qtwidgets's Library * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhenyu Wang * */ #ifndef KCLOCKTIMER_H #define KCLOCKTIMER_H #include "gui_g.h" #include namespace kdk { class KClockTimerPrivate; /** * @defgroup timerModule * @since 2.5.2.0 */ class GUI_EXPORT KClockTimer : public QWidget { Q_OBJECT public: KClockTimer(QWidget *parent = nullptr); /** * @brief 获取当前时间 * @return */ QString time(); public slots: /** * @brief 开始计时信号 */ void startStopwatch(); /** * @brief 停止计时信号 */ void stopStopwatch(); /** * @brief 复位信号 */ void resetStopwatch(); private: KClockTimerPrivate *const d_ptr; Q_DECLARE_PRIVATE(KClockTimer) }; } #endif // KCLOCKTIMER_H libkysdk-applications/kysdk-qtwidgets/src/ktabbar.cpp0000664000175000017500000011263515104543305022047 0ustar fengfeng/* * libkysdk-qtwidgets's Library * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #include "ktabbar.h" #include "parmscontroller.h" #include "themeController.h" #include #include #include #include #include #include #include #include #include #include namespace kdk { class KTabBarPrivate : public QObject, public ThemeController { Q_OBJECT Q_DECLARE_PUBLIC(KTabBar) public: KTabBarPrivate(KTabBar *parent) : q_ptr(parent) , m_animation(new QVariantAnimation(this)) , m_nextTabWidth(0) , m_animationStarted(false) { Q_Q(KTabBar); setParent(parent); parent->installEventFilter(this); m_animation->setDuration(300); m_animation->setEasingCurve(QEasingCurve::InOutQuad); connect(m_animation, &QVariantAnimation::valueChanged, q, [=]() { q->update(); }); connect(m_animation, &QVariantAnimation::finished, this, [=]() { m_animationStarted = false; q->update(); }); } void changeTheme(); int getIndexAtPos(const QPoint &p); protected: bool eventFilter(QObject *watched, QEvent *event); private: KTabBar *q_ptr; KTabBarStyle m_kTabBarStyle; int m_borderRadius = 6; int m_horizontalMargin = 1; int m_topMargin = 0; QColor m_bkgrdColor; bool m_useCustomColor; QVariantAnimation *m_animation; int m_nextTabWidth; bool m_animationStarted; QLinearGradient m_linearGradient ; }; KTabBar::KTabBar(KTabBarStyle barStyle, QWidget *parent) : QTabBar(parent) , d_ptr(new KTabBarPrivate(this)) { Q_D(KTabBar); d->m_borderRadius = ThemeController::getRadiusFromDT("kradius-normal"); if (d->m_borderRadius == -1) d->m_borderRadius = 6; d->m_kTabBarStyle = barStyle; d->m_useCustomColor = false; // this->setObjectName("KTabbar"); d->changeTheme(); connect(d->m_gsetting, &QGSettings::changed, d, &KTabBarPrivate::changeTheme); connect(Parmscontroller::self(), &Parmscontroller::modeChanged, this, [=](bool flag) { updateGeometry(); }); } KTabBar::~KTabBar() { } void KTabBar::setTabBarStyle(KTabBarStyle barStyle) { Q_D(KTabBar); d->m_kTabBarStyle = barStyle; d->changeTheme(); } KTabBarStyle KTabBar::barStyle() { Q_D(KTabBar); return d->m_kTabBarStyle; } void KTabBar::setBorderRadius(int radius) { Q_D(KTabBar); if (radius < 0 || radius > 20) return; d->m_borderRadius = radius; update(); } int KTabBar::borderRadius() { Q_D(KTabBar); if (d->m_kTabBarStyle == Sliding) return 0; else return d->m_borderRadius; } void KTabBar::setBackgroundColor(const QColor &color) { Q_D(KTabBar); d->m_useCustomColor = true; d->m_bkgrdColor = color; } QSize KTabBar::sizeHint() const { auto size = QTabBar::sizeHint(); size.setHeight(Parmscontroller::parm(Parmscontroller::Parm::PM_TabBarHeight)); return size; } QSize KTabBar::minimumTabSizeHint(int index) const { Q_UNUSED(index) QSize size(100, Parmscontroller::parm(Parmscontroller::Parm::PM_PushButtonHeight)); return size; } QSize KTabBar::tabSizeHint(int index) const { Q_UNUSED(index) auto size = QTabBar::tabSizeHint(index); if(this->maximumHeight() == this->minimumHeight()) size.setHeight(this->minimumHeight()); else size.setHeight(Parmscontroller::parm(Parmscontroller::Parm::PM_TabBarHeight)); return size; } void KTabBar::paintEvent(QPaintEvent *event) { Q_D(KTabBar); QPainter p(this); p.setRenderHint(QPainter::Antialiasing); p.setRenderHint(QPainter::TextAntialiasing); p.setRenderHint(QPainter::SmoothPixmapTransform); QColor fontColor; QColor mix; QColor borderColor; QColor startColor; QColor endColor; QFontMetrics fm = p.fontMetrics(); for (int i = 0; i < count(); ++i) { QStyleOptionTab option; initStyleOption(&option, i); QRect rect = option.rect.adjusted(d->m_horizontalMargin, 0, 0, -d->m_topMargin); rect.setHeight(Parmscontroller::parm(Parmscontroller::Parm::PM_PushButtonHeight)); d->m_linearGradient = QLinearGradient(rect.left() + rect.width()/2, rect.top(),rect.left() + rect.width()/2, rect.bottom()); switch (d->m_kTabBarStyle) { case SegmentDark: { mix = ThemeController::getCustomColorFromDT("brighttext-active"); fontColor = ThemeController::getCustomColorFromDT("buttontext-active"); QColor bkgrdColor = d->m_bkgrdColor; d->m_linearGradient.setColorAt(0,bkgrdColor); d->m_linearGradient.setColorAt(1,bkgrdColor); borderColor = Qt::transparent; if (option.state.testFlag(QStyle::State_Selected)) { if (option.state.testFlag(QStyle::State_Sunken)) { borderColor = ThemeController::getCustomColorFromDT("kline-component-click"); ThemeController::getGradientFromDT("kbrand-click", startColor, endColor); } else if (option.state.testFlag(QStyle::State_MouseOver)) { borderColor = ThemeController::getCustomColorFromDT("kline-component-hover"); ThemeController::getGradientFromDT("kbrand-hover", startColor, endColor); } else { borderColor = ThemeController::getCustomColorFromDT("kline-component-normal"); ThemeController::getGradientFromDT("kbrand-normal", startColor, endColor); } d->m_linearGradient.setColorAt(0,startColor); d->m_linearGradient.setColorAt(1,endColor); fontColor = ThemeController::getCustomColorFromDT("kwhite"); } else if (option.state.testFlag(QStyle::State_MouseOver)) { ThemeController::getGradientFromDT("kcomponent-hover",startColor,endColor); d->m_linearGradient.setColorAt(0,startColor); d->m_linearGradient.setColorAt(1,endColor); } if (option.position == QStyleOptionTab::Middle) { p.save(); p.setBrush(d->m_linearGradient); p.setPen(borderColor); // 利用quadto绘制圆角矩形会出现一个像素的偏差,修正一下QRect底部高度 p.drawRect(rect.adjusted(0, 1, -1, -1)); // 调整启典 上描边 p.restore(); p.setBrush(Qt::NoBrush); p.setPen(fontColor); QPoint point; uint tf = Qt::AlignVCenter; if (!option.icon.isNull()) { QIcon::Mode mode = option.state & QStyle::State_Enabled ? QIcon::Normal : QIcon::Disabled; if (mode == QIcon::Normal && option.state & QStyle::State_HasFocus) mode = QIcon::Active; QIcon::State state = QIcon::Off; if (option.state & QStyle::State_On) state = QIcon::On; QPixmap pixmap = option.icon.pixmap(option.iconSize, mode, state); if(ThemeController::isPixmapPureColor(pixmap)) pixmap = ThemeController::drawColoredPixmap(pixmap,fontColor); int w = pixmap.width() / pixmap.devicePixelRatio(); int h = pixmap.height() / pixmap.devicePixelRatio(); if (!tabText(i).isEmpty()) w += option.fontMetrics.boundingRect(option.rect, tf, tabText(i)).width() + 2; point = QPoint(rect.x() + rect.width() / 2 - w / 2, rect.y() + rect.height() / 2 - h / 2); w = pixmap.width() / pixmap.devicePixelRatio(); // if (option.direction == Qt::RightToLeft) // point.rx() += w; if (fm.horizontalAdvance(tabText(i)) >= option.rect.width() - option.iconSize.width() - 7) p.drawPixmap(option.rect.x() + 4, this->style()->visualPos(option.direction, option.rect, point).y(), pixmap); else { if (option.direction == Qt::RightToLeft) p.drawPixmap(point, pixmap); else p.drawPixmap(this->style()->visualPos(option.direction, option.rect, point), pixmap); } if (!tabText(i).isEmpty()) { int subH = std::max(option.iconSize.height(), option.fontMetrics.height()); int icon_Y = (rect.height() - subH) / 2; int text_X = point.x() + option.iconSize.width() + 4; int text_Y = icon_Y; QRect textRect; if (fm.horizontalAdvance(tabText(i)) >= option.rect.width() - option.iconSize.width() - 7) { textRect = QRect(option.rect.x() + option.iconSize.width() + 8, text_Y, option.rect.width() - option.iconSize.width() - 7, option.fontMetrics.height()); setTabToolTip(i, tabText(i)); QString elidedText = fm.elidedText(tabText(i), Qt::ElideRight, option.rect.width() - option.iconSize.width() - 7); p.drawText(textRect, tf, elidedText); } else { textRect = QRect(text_X, text_Y, option.fontMetrics.horizontalAdvance(tabText(i)), option.fontMetrics.height()); setTabToolTip(i, ""); p.drawText(textRect, tf, tabText(i)); } } } else { tf |= Qt::AlignHCenter; if (fm.horizontalAdvance(tabText(i)) >= option.rect.width()) { QString elidedText = fm.elidedText(tabText(i), Qt::ElideRight, option.rect.width()); p.drawText(rect, tf, elidedText); setTabToolTip(i, tabText(i)); } else { setTabToolTip(i, ""); p.drawText(rect, tf, tabText(i)); } } } else if (option.position == QStyleOptionTab::Beginning) { p.save(); p.setBrush(d->m_linearGradient); p.setPen(Qt::NoPen); QPainterPath path; auto tempRect = rect.adjusted(0, 1, 0, 0); // 调整启典 上描边 if (layoutDirection() == Qt::LeftToRight) { path.moveTo(tempRect.topLeft() + QPointF(0, d->m_borderRadius)); path.lineTo(tempRect.bottomLeft() - QPointF(0, d->m_borderRadius)); path.quadTo(tempRect.bottomLeft(), tempRect.bottomLeft() + QPointF(d->m_borderRadius, 0)); path.lineTo(tempRect.bottomRight()); path.lineTo(tempRect.topRight()); path.lineTo(tempRect.topLeft() + QPointF(d->m_borderRadius, 0)); path.quadTo(tempRect.topLeft(), tempRect.topLeft() + QPointF(0, d->m_borderRadius)); } else { path.moveTo(tempRect.topLeft()); path.lineTo(tempRect.bottomLeft()); path.lineTo(tempRect.bottomRight() - QPointF(d->m_borderRadius, 0)); path.quadTo(tempRect.bottomRight(), tempRect.bottomRight() - QPointF(0, d->m_borderRadius)); path.lineTo(tempRect.topRight() + QPointF(0, d->m_borderRadius)); path.quadTo(tempRect.topRight(), tempRect.topRight() - QPointF(d->m_borderRadius, 0)); path.lineTo(tempRect.topLeft()); } p.drawPath(path); p.restore(); p.setBrush(Qt::NoBrush); p.setPen(fontColor); QPoint point; uint tf = Qt::AlignVCenter; if (!option.icon.isNull()) { QIcon::Mode mode = option.state & QStyle::State_Enabled ? QIcon::Normal : QIcon::Disabled; if (mode == QIcon::Normal && option.state & QStyle::State_HasFocus) mode = QIcon::Active; QIcon::State state = QIcon::Off; if (option.state & QStyle::State_On) state = QIcon::On; QPixmap pixmap = option.icon.pixmap(option.iconSize, mode, state); if(ThemeController::isPixmapPureColor(pixmap)) pixmap = ThemeController::drawColoredPixmap(pixmap,fontColor); int w = pixmap.width() / pixmap.devicePixelRatio(); int h = pixmap.height() / pixmap.devicePixelRatio(); if (!tabText(i).isEmpty()) w += option.fontMetrics.boundingRect(option.rect, tf, tabText(i)).width() + 2; point = QPoint(rect.x() + rect.width() / 2 - w / 2, rect.y() + rect.height() / 2 - h / 2); w = pixmap.width() / pixmap.devicePixelRatio(); // if (option.direction == Qt::RightToLeft) // point.rx() += w; // p.setBrush(Qt::red); // p.drawRect(option.rect.x() + 4, this->style()->visualPos(option.direction, option.rect, point).y(), pixmap.width(), pixmap.height()); // p.setBrush(Qt::NoBrush); if (fm.horizontalAdvance(tabText(i)) >= option.rect.width() - option.iconSize.width() - 7) p.drawPixmap(option.rect.x() + 4, this->style()->visualPos(option.direction, option.rect, point).y(), pixmap); else { if (option.direction == Qt::RightToLeft) p.drawPixmap(point, pixmap); else p.drawPixmap(this->style()->visualPos(option.direction, option.rect, point), pixmap); } if (option.direction == Qt::RightToLeft) rect.translate(-point.x() - 2, 0); else rect.translate(point.x() + w + 4, 0); if (!tabText(i).isEmpty()) { tf |= Qt::AlignLeft; int subH = std::max(option.iconSize.height(), option.fontMetrics.height()); int icon_Y = (rect.height() - subH) / 2; int text_X = point.x() + option.iconSize.width() + 4; int text_Y = icon_Y; QRect textRect; if (fm.horizontalAdvance(tabText(i)) >= option.rect.width() - option.iconSize.width() - 7) { textRect = QRect(option.rect.x() + option.iconSize.width() + 8, text_Y, option.rect.width() - option.iconSize.width() - 8, option.fontMetrics.height()); setTabToolTip(i, tabText(i)); QString elidedText = fm.elidedText(tabText(i), Qt::ElideRight, option.rect.width() - option.iconSize.width() - 8); p.drawText(textRect, tf, elidedText); } else { textRect = QRect(text_X, text_Y, option.fontMetrics.horizontalAdvance(tabText(i)), option.fontMetrics.height()); setTabToolTip(i, ""); p.drawText(textRect, tf, tabText(i)); } } } else { tf |= Qt::AlignHCenter; if (fm.horizontalAdvance(tabText(i)) >= option.rect.width()) { QString elidedText = fm.elidedText(tabText(i), Qt::ElideRight, option.rect.width()); p.drawText(rect, tf, elidedText); setTabToolTip(i, tabText(i)); } else { p.drawText(rect, tf, tabText(i)); setTabToolTip(i, ""); } } } else { p.save(); p.setBrush(d->m_linearGradient); rect = rect.adjusted(0, 1, 0, 0); // 调整启典 上描边 p.setPen(Qt::NoPen); QPainterPath path; if (count() == 1) { path.moveTo(rect.topLeft() + QPoint(d->m_borderRadius, 0)); path.quadTo(rect.topLeft(), rect.topLeft() + QPoint(0, d->m_borderRadius)); path.lineTo(rect.bottomLeft() - QPoint(0, d->m_borderRadius)); path.quadTo(rect.bottomLeft(), rect.bottomLeft() + QPoint(d->m_borderRadius, 0)); path.lineTo(rect.bottomRight() - QPoint(d->m_borderRadius, 0)); path.quadTo(rect.bottomRight(), rect.bottomRight() - QPoint(0, d->m_borderRadius)); path.lineTo(rect.topRight() + QPoint(0, d->m_borderRadius)); path.quadTo(rect.topRight(), rect.topRight() - QPoint(d->m_borderRadius, 0)); path.lineTo(rect.topLeft() + QPoint(d->m_borderRadius, 0)); } else { if (layoutDirection() == Qt::LeftToRight) { path.moveTo(rect.topLeft()); path.lineTo(rect.bottomLeft()); path.lineTo(rect.bottomRight() - QPointF(d->m_borderRadius, 0)); path.quadTo(rect.bottomRight(), rect.bottomRight() - QPointF(0, d->m_borderRadius)); path.lineTo(rect.topRight() + QPointF(0, d->m_borderRadius)); path.quadTo(rect.topRight(), rect.topRight() - QPointF(d->m_borderRadius, 0)); path.lineTo(rect.topLeft()); } else { path.moveTo(rect.topLeft() + QPointF(0, d->m_borderRadius)); path.lineTo(rect.bottomLeft() - QPointF(0, d->m_borderRadius)); path.quadTo(rect.bottomLeft(), rect.bottomLeft() + QPointF(d->m_borderRadius, 0)); path.lineTo(rect.bottomRight()); path.lineTo(rect.topRight()); path.lineTo(rect.topLeft() + QPointF(d->m_borderRadius, 0)); path.quadTo(rect.topLeft(), rect.topLeft() + QPointF(0, d->m_borderRadius)); } } p.drawPath(path); p.restore(); p.setBrush(Qt::NoBrush); p.setPen(fontColor); QPoint point; uint tf = Qt::AlignVCenter; if (!option.icon.isNull()) { QIcon::Mode mode = option.state & QStyle::State_Enabled ? QIcon::Normal : QIcon::Disabled; if (mode == QIcon::Normal && option.state & QStyle::State_HasFocus) mode = QIcon::Active; QIcon::State state = QIcon::Off; if (option.state & QStyle::State_On) state = QIcon::On; QPixmap pixmap = option.icon.pixmap(option.iconSize, mode, state); if(ThemeController::isPixmapPureColor(pixmap)) pixmap = ThemeController::drawColoredPixmap(pixmap,fontColor); int w = pixmap.width() / pixmap.devicePixelRatio(); int h = pixmap.height() / pixmap.devicePixelRatio(); if (!tabText(i).isEmpty()) w += option.fontMetrics.boundingRect(option.rect, tf, tabText(i)).width() + 4; point = QPoint(rect.x() + rect.width() / 2 - w / 2, rect.y() + rect.height() / 2 - h / 2); w = pixmap.width() / pixmap.devicePixelRatio(); // if (option.direction == Qt::RightToLeft) // point.rx() += w; if (fm.horizontalAdvance(tabText(i)) >= option.rect.width() - option.iconSize.width() - 7) p.drawPixmap(option.rect.x() + 4, this->style()->visualPos(option.direction, option.rect, point).y(), pixmap); else { if (option.direction == Qt::RightToLeft) p.drawPixmap(point, pixmap); else p.drawPixmap(this->style()->visualPos(option.direction, option.rect, point), pixmap); } if (!tabText(i).isEmpty()) { int subH = std::max(option.iconSize.height(), option.fontMetrics.height()); int icon_Y = (rect.height() - subH) / 2; int text_X = point.x() + option.iconSize.width() + 4; int text_Y = icon_Y; QRect textRect; if (fm.horizontalAdvance(tabText(i)) >= option.rect.width() - option.iconSize.width() - 7) { textRect = QRect(option.rect.x() + option.iconSize.width() + 8, text_Y, option.rect.width() - option.iconSize.width() - 8, option.fontMetrics.height()); setTabToolTip(i, tabText(i)); QString elidedText = fm.elidedText(tabText(i), Qt::ElideRight, option.rect.width() - option.iconSize.width() - 8); p.drawText(textRect, elidedText); } else { textRect = QRect(text_X, text_Y, option.fontMetrics.horizontalAdvance(tabText(i)), option.fontMetrics.height()); setTabToolTip(i, ""); p.drawText(textRect, tabText(i)); } } } else { tf |= Qt::AlignHCenter; if (fm.horizontalAdvance(tabText(i)) >= option.rect.width()) { QString elidedText = fm.elidedText(tabText(i), Qt::ElideRight, option.rect.width()); p.drawText(rect, tf, elidedText); setTabToolTip(i, tabText(i)); } else { p.drawText(rect, tf, tabText(i)); setTabToolTip(i, ""); } } } break; } case SegmentLight: { mix = ThemeController::getCustomColorFromDT("brighttext-active"); fontColor = ThemeController::getCustomColorFromDT("buttontext-active"); QColor bkgrdColor = d->m_bkgrdColor; d->m_linearGradient.setColorAt(0,bkgrdColor); d->m_linearGradient.setColorAt(1,bkgrdColor); if (option.state.testFlag(QStyle::State_Selected)) { if (option.state.testFlag(QStyle::State_Sunken)) { borderColor = ThemeController::getCustomColorFromDT("kline-component-click"); ThemeController::getGradientFromDT("kbrand-click", startColor, endColor); } else if (option.state.testFlag(QStyle::State_MouseOver)) { borderColor = ThemeController::getCustomColorFromDT("kline-component-hover"); ThemeController::getGradientFromDT("kbrand-hover", startColor, endColor); } else { borderColor = ThemeController::getCustomColorFromDT("kline-component-normal"); ThemeController::getGradientFromDT("kbrand-normal", startColor, endColor); } d->m_linearGradient.setColorAt(0,startColor); d->m_linearGradient.setColorAt(1,endColor); fontColor = ThemeController::getCustomColorFromDT("kwhite"); } else if (option.state.testFlag(QStyle::State_MouseOver)) { ThemeController::getGradientFromDT("kcomponent-hover",startColor,endColor); d->m_linearGradient.setColorAt(0,startColor); d->m_linearGradient.setColorAt(1,endColor); } p.save(); p.setBrush(d->m_linearGradient); p.setPen(Qt::NoPen); p.drawRoundedRect(/*option.rect.adjusted*/ rect.adjusted(d->m_horizontalMargin, 0, 0, -d->m_topMargin), d->m_borderRadius, d->m_borderRadius); p.restore(); p.setBrush(Qt::NoBrush); p.setPen(fontColor); /*QRect*/ rect = /*option.*/ rect.adjusted(d->m_horizontalMargin, 0, 0, -d->m_topMargin); QPoint point; uint tf = Qt::AlignVCenter; if (!option.icon.isNull()) { QIcon::Mode mode = option.state & QStyle::State_Enabled ? QIcon::Normal : QIcon::Disabled; if (mode == QIcon::Normal && option.state & QStyle::State_HasFocus) mode = QIcon::Active; QIcon::State state = QIcon::Off; if (option.state & QStyle::State_On) state = QIcon::On; QPixmap pixmap = option.icon.pixmap(option.iconSize, mode, state); if(ThemeController::isPixmapPureColor(pixmap)) pixmap = ThemeController::drawColoredPixmap(pixmap,fontColor); int w = pixmap.width() / pixmap.devicePixelRatio(); int h = pixmap.height() / pixmap.devicePixelRatio(); if (!tabText(i).isEmpty()) w += option.fontMetrics.boundingRect(option.rect, tf, tabText(i)).width() + 2; point = QPoint(rect.x() + rect.width() / 2 - w / 2, rect.y() + rect.height() / 2 - h / 2); w = pixmap.width() / pixmap.devicePixelRatio(); // if (option.direction == Qt::RightToLeft) // point.rx() += w; if (fm.horizontalAdvance(tabText(i)) >= option.rect.width() - option.iconSize.width() - 7) p.drawPixmap(option.rect.x() + 4, this->style()->visualPos(option.direction, option.rect, point).y(), pixmap); else { if (option.direction == Qt::RightToLeft) p.drawPixmap(point, pixmap); else p.drawPixmap(this->style()->visualPos(option.direction, option.rect, point), pixmap); } if (!tabText(i).isEmpty()) { int subH = std::max(option.iconSize.height(), option.fontMetrics.height()); int icon_Y = (rect.height() - subH) / 2; int text_X = point.x() + option.iconSize.width() + 4; int text_Y = icon_Y; QRect textRect; if (fm.horizontalAdvance(tabText(i)) >= option.rect.width() - option.iconSize.width() - 7) { textRect = QRect(option.rect.x() + option.iconSize.width() + 8, text_Y, option.rect.width() - option.iconSize.width() - 8, option.fontMetrics.height()); setTabToolTip(i, tabText(i)); QString elidedText = fm.elidedText(tabText(i), Qt::ElideRight, option.rect.width() - option.iconSize.width() - 8); p.drawText(textRect, elidedText); } else { textRect = QRect(text_X, text_Y, option.fontMetrics.horizontalAdvance(tabText(i)), option.fontMetrics.height()); setTabToolTip(i, ""); p.drawText(textRect, tabText(i)); } } } else { tf |= Qt::AlignHCenter; if (fm.horizontalAdvance(tabText(i)) >= option.rect.width()) { QString elidedText = fm.elidedText(tabText(i), Qt::ElideRight, option.rect.width()); p.drawText(rect, tf, elidedText); setTabToolTip(i, tabText(i)); } else { p.drawText(rect, tf, tabText(i)); setTabToolTip(i, ""); } } break; } case Sliding: { QColor lineColor = ThemeController::getCustomColorFromDT("kline-normal"); // mix = ThemeController::getCustomColorFromDT("brighttext-active"); fontColor = ThemeController::getCustomColorFromDT("buttontext-active"); QColor bkgrdColor = d->m_bkgrdColor; if (option.state.testFlag(QStyle::State_Selected)) { if (option.state.testFlag(QStyle::State_Sunken)) { fontColor = ThemeController::getCustomColorFromDT("kbrand-normal"); lineColor = ThemeController::getCustomColorFromDT("kbrand-click"); } else if (option.state.testFlag(QStyle::State_MouseOver)) { fontColor = ThemeController::getCustomColorFromDT("kbrand-normal"); lineColor = ThemeController::getCustomColorFromDT("kbrand-hover"); } else { fontColor = ThemeController::getCustomColorFromDT("kbrand-normal"); lineColor = ThemeController::getCustomColorFromDT("kbrand-normal"); } } else if (option.state.testFlag(QStyle::State_MouseOver)) { lineColor = ThemeController::getCustomColorFromDT("kline-normal"); } p.save(); QPen pen; if (i != currentIndex()) pen.setColor(lineColor); else pen.setColor(d->m_bkgrdColor); pen.setWidth(2); p.setPen(pen); p.drawLine(rect.bottomLeft(), rect.bottomRight()); p.restore(); if (d->m_animationStarted) { int left_border = d->m_animation->currentValue().toInt(); p.save(); QPen pen; pen.setWidth(2); pen.setColor(ThemeController::getCustomColorFromDT("kbrand-normal")); p.setPen(pen); p.drawLine(QPoint(left_border, rect.height() - 1), QPoint(left_border + d->m_nextTabWidth, rect.height() - 1)); p.restore(); } else { p.save(); QPen pen; pen.setColor(lineColor); pen.setWidth(2); p.setPen(pen); p.drawLine(rect.bottomLeft(), rect.bottomRight()); p.restore(); } p.setBrush(Qt::NoBrush); p.setPen(fontColor); QPoint point; uint tf = Qt::AlignVCenter; if (!option.icon.isNull()) { QIcon::Mode mode = option.state & QStyle::State_Enabled ? QIcon::Normal : QIcon::Disabled; if (mode == QIcon::Normal && option.state & QStyle::State_HasFocus) mode = QIcon::Active; QIcon::State state = QIcon::Off; if (option.state & QStyle::State_On) state = QIcon::On; QPixmap pixmap = option.icon.pixmap(option.iconSize, mode, state); if(ThemeController::isPixmapPureColor(pixmap)) pixmap = ThemeController::drawColoredPixmap(pixmap,fontColor); int w = pixmap.width() / pixmap.devicePixelRatio(); int h = pixmap.height() / pixmap.devicePixelRatio(); if (!tabText(i).isEmpty()) w += option.fontMetrics.boundingRect(option.rect, tf, tabText(i)).width() + 2; point = QPoint(rect.x() + rect.width() / 2 - w / 2, rect.y() + rect.height() / 2 - h / 2); w = pixmap.width() / pixmap.devicePixelRatio(); // if (option.direction == Qt::RightToLeft) // point.rx() += w; if (fm.horizontalAdvance(tabText(i)) >= option.rect.width() - option.iconSize.width() - 7) p.drawPixmap(option.rect.x() + 4, this->style()->visualPos(option.direction, option.rect, point).y(), pixmap); else { if (option.direction == Qt::RightToLeft) p.drawPixmap(point, pixmap); else p.drawPixmap(this->style()->visualPos(option.direction, option.rect, point), pixmap); } if (!tabText(i).isEmpty()) { int subH = std::max(option.iconSize.height(), option.fontMetrics.height()); int icon_Y = (rect.height() - subH) / 2; int text_X = point.x() + option.iconSize.width() + 4; int text_Y = icon_Y; QRect textRect; if (fm.horizontalAdvance(tabText(i)) >= option.rect.width() - option.iconSize.width() - 7) { textRect = QRect(option.rect.x() + option.iconSize.width() + 8, text_Y, option.rect.width() - option.iconSize.width() - 8, option.fontMetrics.height()); setTabToolTip(i, tabText(i)); QString elidedText = fm.elidedText(tabText(i), Qt::ElideRight, option.rect.width() - option.iconSize.width() - 8); p.drawText(textRect, elidedText); } else { textRect = QRect(text_X, text_Y, option.fontMetrics.horizontalAdvance(tabText(i)), option.fontMetrics.height()); setTabToolTip(i, ""); p.drawText(textRect, tabText(i)); } } } else { tf |= Qt::AlignHCenter; if (fm.horizontalAdvance(tabText(i)) >= option.rect.width()) { QString elidedText = fm.elidedText(tabText(i), Qt::ElideRight, option.rect.width()); p.drawText(rect, tf, elidedText); setTabToolTip(i, tabText(i)); } else { p.drawText(rect, tf, tabText(i)); setTabToolTip(i, ""); } } break; } default: break; } } } void KTabBarPrivate::changeTheme() { Q_Q(KTabBar); switch (m_kTabBarStyle) { case SegmentDark: { if (m_useCustomColor) return; else m_bkgrdColor = ThemeController::getCustomColorFromDT("button-active"); break; } case SegmentLight: { if (m_useCustomColor) return; else m_bkgrdColor = ThemeController::getCustomColorFromDT("kgray-alpha0"); break; } case Sliding: if (m_useCustomColor) return; else m_bkgrdColor = ThemeController::getCustomColorFromDT("button-active"); break; default: break; }; q->update(); } int KTabBarPrivate::getIndexAtPos(const QPoint &p) { Q_Q(KTabBar); if (q->tabRect(q->currentIndex()).contains(p)) return q->currentIndex(); for (int i = 0; i < q->count(); ++i) if (q->tabRect(i).contains(p)) return i; return -1; } bool KTabBarPrivate::eventFilter(QObject *watched, QEvent *event) { Q_Q(KTabBar); if (event->type() == QEvent::MouseButtonPress) { if (q->isEnabled()) { QMouseEvent *mouseEvent = dynamic_cast(event); if (mouseEvent && mouseEvent->button() == Qt::MouseButton::LeftButton) { int nextIndex = getIndexAtPos(mouseEvent->pos()); int currentIndex = q->currentIndex(); if (nextIndex != currentIndex) { int cur_left_border = q->tabRect(currentIndex).left(); int next_left_border = q->tabRect(nextIndex).left(); m_nextTabWidth = q->tabRect(nextIndex).width(); m_animation->setStartValue(cur_left_border); m_animation->setEndValue(next_left_border); m_animation->start(); m_animationStarted = true; } } if (mouseEvent && mouseEvent->button() == Qt::MouseButton::RightButton) { emit q->rightlicked(mouseEvent->globalPos()); } q->update(); } } return QObject::eventFilter(watched, event); } } #include "ktabbar.moc" #include "moc_ktabbar.cpp" libkysdk-applications/kysdk-qtwidgets/src/kcustomtabbar.cpp0000664000175000017500000030101415104543305023271 0ustar fengfeng/* * libkysdk-qtwidgets's Library * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhenyu Wang * */ // #include "gui_g.h" // #include #include "kcustomtabbar.h" // #include "private/qwidget_p.h" #include #include #include // #if QT_CONFIG(animation) #include // #endif #include // #include "private/qlayoutengine_p.h" // #if QT_CONFIG(itemviews) // #include "qabstractitemdelegate.h" // #endif #include #include #include #include #include #include #include #include // #include #include // #if QT_CONFIG(tabwidget) #include // #endif #include // #if QT_CONFIG(whatsthis) #include // #endif // #ifndef QT_NO_ACCESSIBILITY #include // #endif // #ifdef Q_OS_OSX // #include // #endif #include // #include "qdebug.h" // #include "private/KCustomTabBar_p.h" // #if 0 // Used to be included in Qt4 for Q_WS_MAC // #include // #include // #endif #define ANIMATION_DURATION 250 typedef qint64 Fixed64; static inline Fixed64 toFixed(int i) { return (Fixed64)i * 256; } static inline int fRound(Fixed64 i) { return (i % 256 < 128) ? i / 256 : 1 + i / 256; } struct QCustomLayoutStruct { inline void init(int stretchFactor = 0, int minSize = 0) { stretch = stretchFactor; minimumSize = sizeHint = minSize; maximumSize = QLAYOUTSIZE_MAX; expansive = false; empty = true; spacing = 0; } int smartSizeHint() { return (stretch > 0) ? minimumSize : sizeHint; } int effectiveSpacer(int uniformSpacer) const { Q_ASSERT(uniformSpacer >= 0 || spacing >= 0); return (uniformSpacer >= 0) ? uniformSpacer : spacing; } // parameters int stretch; int sizeHint; int maximumSize; int minimumSize; int spacing; bool expansive; bool empty; // temporary storage bool done; // result int pos; int size; }; class Q_DECL_HIDDEN KCustomMovableTabWidget : public QWidget { public: explicit KCustomMovableTabWidget(QWidget *parent = nullptr); void setPixmap(const QPixmap &pixmap); protected: void paintEvent(QPaintEvent *e) override; private: QPixmap m_pixmap; }; class Q_DECL_HIDDEN KCustomTabBarPrivate { Q_DECLARE_PUBLIC(KCustomTabBar) public: KCustomTabBarPrivate(KCustomTabBar *parent); Q_WIDGETS_EXPORT void qGeomCalc(QVector &chain, int start, int count, int pos, int space, int spacer = -1); int currentIndex; int pressedIndex; KCustomTabBar::Shape shape; bool layoutDirty; bool drawBase; int scrollOffset; struct Tab { inline Tab(const QIcon &ico, const QString &txt) : enabled(true) , shortcutId(0) , text(txt) , icon(ico) , leftWidget(0) , rightWidget(0) , lastTab(-1) , dragOffset(0) #if QT_CONFIG(animation) , animation(0) #endif // animation { } bool operator==(const Tab &other) const { return &other == this; } bool enabled; int shortcutId; QString text; #ifndef QT_NO_TOOLTIP QString toolTip; #endif #if QT_CONFIG(whatsthis) QString whatsThis; #endif QIcon icon; QRect rect; QRect minRect; QRect maxRect; QColor textColor; QVariant data; QWidget *leftWidget; QWidget *rightWidget; int lastTab; int dragOffset; #ifndef QT_NO_ACCESSIBILITY QString accessibleName; #endif #if QT_CONFIG(animation) ~Tab() { delete animation; } struct TabBarAnimation : public QVariantAnimation { TabBarAnimation(Tab *t, KCustomTabBarPrivate *_priv) : tab(t) , priv(_priv) { setEasingCurve(QEasingCurve::InOutQuad); } void updateCurrentValue(const QVariant ¤t) override; void updateState(State newState, State) override; private: // these are needed for the callbacks Tab *tab; KCustomTabBarPrivate *priv; } *animation; void startAnimation(KCustomTabBarPrivate *priv, int duration) { if (!priv->isAnimated()) { priv->moveTabFinished(priv->tabList.indexOf(*this)); return; } if (!animation) animation = new TabBarAnimation(this, priv); animation->setStartValue(dragOffset); animation->setEndValue(0); animation->setDuration(duration); animation->start(); } #else void startAnimation(KCustomTabBarPrivate *priv, int duration) { Q_UNUSED(duration); priv->moveTabFinished(priv->tabList.indexOf(*this)); } #endif // animation }; QList tabList; mutable QHash textSizes; int calculateNewPosition(int from, int to, int index) const; void slide(int from, int to); void init(); Tab *at(int index); const Tab *at(int index) const; int indexAtPos(const QPoint &p) const; inline bool isAnimated() const { Q_Q(const KCustomTabBar); return q->style()->styleHint(QStyle::SH_Widget_Animation_Duration, 0, q) > 0; } inline bool validIndex(int index) const { return index >= 0 && index < tabList.count(); } void setCurrentNextEnabledIndex(int offset); QToolButton *rightB; // right or bottom QToolButton *leftB; // left or top void moveTab(int index, int offset); void moveTabFinished(int index); QRect hoverRect; int hoverIndex; void refresh(); void layoutTabs(); void layoutWidgets(int start = 0); void layoutTab(int index); void updateMacBorderMetrics(); bool isTabInMacUnifiedToolbarArea() const; void setupMovableTab(); void autoHideTabs(); QRect normalizedScrollRect(int index = -1); int hoveredTabIndex() const; void initBasicStyleOption(QStyleOptionTab *option, int tabIndex) const; void makeVisible(int index); QSize iconSize; Qt::TextElideMode elideMode; bool elideModeSetByUser; bool useScrollButtons; bool useScrollButtonsSetByUser; bool expanding; bool closeButtonOnTabs; KCustomTabBar::SelectionBehavior selectionBehaviorOnRemove; QPoint dragStartPosition; bool paintWithOffsets; bool movable; bool dragInProgress; bool documentMode; bool autoHide; bool changeCurrentOnDrag; int switchTabCurrentIndex; int switchTabTimerId; KCustomMovableTabWidget *movingTab; // shared by tabwidget and KCustomTabBar static void initStyleBaseOption(QStyleOptionTabBarBase *optTabBase, KCustomTabBar *tabbar, QSize size) { QStyleOptionTab tabOverlap; tabOverlap.shape = static_cast(tabbar->shape()); int overlap = tabbar->style()->pixelMetric(QStyle::PM_TabBarBaseOverlap, &tabOverlap, tabbar); QWidget *theParent = tabbar->parentWidget(); optTabBase->initFrom(tabbar); optTabBase->shape = static_cast(tabbar->shape()); optTabBase->documentMode = tabbar->documentMode(); if (theParent && overlap > 0) { QRect rect; switch (tabOverlap.shape) { case KCustomTabBar::RoundedNorth: case KCustomTabBar::TriangularNorth: rect.setRect(0, size.height() - overlap, size.width(), overlap); break; case KCustomTabBar::RoundedSouth: case KCustomTabBar::TriangularSouth: rect.setRect(0, 0, size.width(), overlap); break; case KCustomTabBar::RoundedEast: case KCustomTabBar::TriangularEast: rect.setRect(0, 0, overlap, size.height()); break; case KCustomTabBar::RoundedWest: case KCustomTabBar::TriangularWest: rect.setRect(size.width() - overlap, 0, overlap, size.height()); break; } optTabBase->rect = rect; } } void killSwitchTabTimer(); private: KCustomTabBar *const q_ptr; }; namespace { class Q_DECL_HIDDEN CloseButton : public QAbstractButton { Q_OBJECT public: explicit CloseButton(QWidget *parent = 0); QSize sizeHint() const override; QSize minimumSizeHint() const override; void enterEvent(QEnterEvent *event) override; void leaveEvent(QEvent *event) override; void paintEvent(QPaintEvent *event) override; }; } KCustomMovableTabWidget::KCustomMovableTabWidget(QWidget *parent) : QWidget(parent) { } void KCustomMovableTabWidget::setPixmap(const QPixmap &pixmap) { m_pixmap = pixmap; update(); } void KCustomMovableTabWidget::paintEvent(QPaintEvent *e) { Q_UNUSED(e); QPainter p(this); p.drawPixmap(0, 0, m_pixmap); } inline static bool verticalTabs(KCustomTabBar::Shape shape) { return shape == KCustomTabBar::RoundedWest || shape == KCustomTabBar::RoundedEast || shape == KCustomTabBar::TriangularWest || shape == KCustomTabBar::TriangularEast; } void KCustomTabBarPrivate::updateMacBorderMetrics() { #if defined(Q_OS_OSX) Q_Q(KCustomTabBar); // Extend the unified title and toolbar area to cover the tab bar iff // 1) the tab bar is in document mode // 2) the tab bar is directly below an "unified" area. // The extending itself is done in the Cocoa platform plugin and Mac style, // this function registers geometry and visibility state for the tab bar. // Calculate geometry int upper, lower; if (documentMode) { QPoint windowPos = q->mapTo(q->window(), QPoint(0, 0)); upper = windowPos.y(); int tabStripHeight = q->tabSizeHint(0).height(); int pixelTweak = -3; lower = upper + tabStripHeight + pixelTweak; } else { upper = 0; lower = 0; } QPlatformNativeInterface *nativeInterface = QGuiApplication::platformNativeInterface(); quintptr identifier = reinterpret_cast(q); // Set geometry QPlatformNativeInterface::NativeResourceForIntegrationFunction function = nativeInterface->nativeResourceFunctionForIntegration("registerContentBorderArea"); if (!function) return; // Not Cocoa platform plugin. typedef void (*RegisterContentBorderAreaFunction)(QWindow *window, quintptr identifier, int upper, int lower); (reinterpret_cast(function))(q->window()->windowHandle(), identifier, upper, lower); // Set visibility state function = nativeInterface->nativeResourceFunctionForIntegration("setContentBorderAreaEnabled"); if (!function) return; typedef void (*SetContentBorderAreaEnabledFunction)(QWindow *window, quintptr identifier, bool enable); (reinterpret_cast(function))(q->window()->windowHandle(), identifier, q->isVisible()); #endif } /*! \internal This is basically KCustomTabBar::initStyleOption() but without the expensive QFontMetrics::elidedText() call. */ void KCustomTabBarPrivate::initBasicStyleOption(QStyleOptionTab *option, int tabIndex) const { Q_Q(const KCustomTabBar); const int totalTabs = tabList.size(); if (!option || (tabIndex < 0 || tabIndex >= totalTabs)) return; const KCustomTabBarPrivate::Tab &tab = tabList.at(tabIndex); option->initFrom(q); option->state &= ~(QStyle::State_HasFocus | QStyle::State_MouseOver); option->rect = q->tabRect(tabIndex); const bool isCurrent = tabIndex == currentIndex; option->row = 0; if (tabIndex == pressedIndex) option->state |= QStyle::State_Sunken; if (isCurrent) option->state |= QStyle::State_Selected; if (isCurrent && q->hasFocus()) option->state |= QStyle::State_HasFocus; if (!tab.enabled) option->state &= ~QStyle::State_Enabled; if (q->isActiveWindow()) option->state |= QStyle::State_Active; if (!dragInProgress && option->rect == hoverRect) option->state |= QStyle::State_MouseOver; option->shape = static_cast(shape); option->text = tab.text; if (tab.textColor.isValid()) option->palette.setColor(q->foregroundRole(), tab.textColor); option->icon = tab.icon; option->iconSize = q->iconSize(); // Will get the default value then. option->leftButtonSize = tab.leftWidget ? tab.leftWidget->size() : QSize(); option->rightButtonSize = tab.rightWidget ? tab.rightWidget->size() : QSize(); option->documentMode = documentMode; if (tabIndex > 0 && tabIndex - 1 == currentIndex) option->selectedPosition = QStyleOptionTab::PreviousIsSelected; else if (tabIndex + 1 < totalTabs && tabIndex + 1 == currentIndex) option->selectedPosition = QStyleOptionTab::NextIsSelected; else option->selectedPosition = QStyleOptionTab::NotAdjacent; const bool paintBeginning = (tabIndex == 0) || (dragInProgress && tabIndex == pressedIndex + 1); const bool paintEnd = (tabIndex == totalTabs - 1) || (dragInProgress && tabIndex == pressedIndex - 1); if (paintBeginning) { if (paintEnd) option->position = QStyleOptionTab::OnlyOneTab; else option->position = QStyleOptionTab::Beginning; } else if (paintEnd) { option->position = QStyleOptionTab::End; } else { option->position = QStyleOptionTab::Middle; } #if QT_CONFIG(tabwidget) if (const QTabWidget *tw = qobject_cast(q->parentWidget())) { option->features |= QStyleOptionTab::HasFrame; if (tw->cornerWidget(Qt::TopLeftCorner) || tw->cornerWidget(Qt::BottomLeftCorner)) option->cornerWidgets |= QStyleOptionTab::LeftCornerWidget; if (tw->cornerWidget(Qt::TopRightCorner) || tw->cornerWidget(Qt::BottomRightCorner)) option->cornerWidgets |= QStyleOptionTab::RightCornerWidget; } #endif } /*! Initialize \a option with the values from the tab at \a tabIndex. This method is useful for subclasses when they need a QStyleOptionTab, but don't want to fill in all the information themselves. \sa QStyleOption::initFrom(), QTabWidget::initStyleOption() */ void KCustomTabBar::initStyleOption(QStyleOptionTab *option, int tabIndex) const { Q_D(const KCustomTabBar); d->initBasicStyleOption(option, tabIndex); QRect textRect = style()->subElementRect(QStyle::SE_TabBarTabText, option, this); option->text = fontMetrics().elidedText(option->text, d->elideMode, textRect.width(), Qt::TextShowMnemonic); } void KCustomTabBarPrivate::init() { Q_Q(KCustomTabBar); leftB = new QToolButton(q); leftB->setAutoRepeat(true); // QObject::connect(leftB, SIGNAL(clicked()), q, SLOT(scrollTabs())); QObject::connect(leftB, &QToolButton::clicked, q, [=] { q->leftScrollTabs(); }); leftB->hide(); rightB = new QToolButton(q); rightB->setAutoRepeat(true); // QObject::connect(rightB, SIGNAL(clicked()), q, SLOT(scrollTabs())); QObject::connect(rightB, &QToolButton::clicked, q, [=] { q->rightScrollTabs(); }); rightB->hide(); #ifdef QT_KEYPAD_NAVIGATION if (QApplication::keypadNavigationEnabled()) { leftB->setFocusPolicy(Qt::NoFocus); rightB->setFocusPolicy(Qt::NoFocus); q->setFocusPolicy(Qt::NoFocus); } else #endif q->setFocusPolicy(Qt::TabFocus); #ifndef QT_NO_ACCESSIBILITY leftB->setAccessibleName(KCustomTabBar::tr("Scroll Left")); rightB->setAccessibleName(KCustomTabBar::tr("Scroll Right")); #endif q->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed); elideMode = Qt::TextElideMode(q->style()->styleHint(QStyle::SH_TabBar_ElideMode, 0, q)); useScrollButtons = !q->style()->styleHint(QStyle::SH_TabBar_PreferNoArrows, 0, q); } KCustomTabBarPrivate::Tab *KCustomTabBarPrivate::at(int index) { return validIndex(index) ? &tabList[index] : 0; } const KCustomTabBarPrivate::Tab *KCustomTabBarPrivate::at(int index) const { return validIndex(index) ? &tabList[index] : 0; } int KCustomTabBarPrivate::indexAtPos(const QPoint &p) const { Q_Q(const KCustomTabBar); if (q->tabRect(currentIndex).contains(p)) return currentIndex; for (int i = 0; i < tabList.count(); ++i) if (tabList.at(i).enabled && q->tabRect(i).contains(p)) return i; return -1; } void KCustomTabBarPrivate::layoutTabs() { Q_Q(KCustomTabBar); layoutDirty = false; QSize size = q->size(); int last, available; int maxExtent; int i; bool vertTabs = verticalTabs(shape); int tabChainIndex = 0; Qt::Alignment tabAlignment = Qt::Alignment(q->style()->styleHint(QStyle::SH_TabBar_Alignment, 0, q)); QVector tabChain(tabList.count() + 2); // We put an empty item at the front and back and set its expansive attribute // depending on tabAlignment and expanding. tabChain[tabChainIndex].init(); tabChain[tabChainIndex].expansive = (!expanding) && (tabAlignment != Qt::AlignLeft) && (tabAlignment != Qt::AlignJustify); tabChain[tabChainIndex].empty = true; ++tabChainIndex; // We now go through our list of tabs and set the minimum size and the size hint // This will allow us to elide text if necessary. Since we don't set // a maximum size, tabs will EXPAND to fill up the empty space. // Since tab widget is rather *ahem* strict about keeping the geometry of the // tab bar to its absolute minimum, this won't bleed through, but will show up // if you use tab bar on its own (a.k.a. not a bug, but a feature). // Update: if expanding is false, we DO set a maximum size to prevent the tabs // being wider than necessary. if (!vertTabs) { int minx = 0; int x = 0; int maxHeight = 0; for (i = 0; i < tabList.count(); ++i, ++tabChainIndex) { QSize sz = q->tabSizeHint(i); tabList[i].maxRect = QRect(x, 0, sz.width(), sz.height()); x += sz.width(); maxHeight = qMax(maxHeight, sz.height()); sz = q->minimumTabSizeHint(i); tabList[i].minRect = QRect(minx, 0, sz.width(), sz.height()); minx += sz.width(); tabChain[tabChainIndex].init(); tabChain[tabChainIndex].sizeHint = tabList.at(i).maxRect.width(); tabChain[tabChainIndex].minimumSize = sz.width(); tabChain[tabChainIndex].empty = false; tabChain[tabChainIndex].expansive = true; if (!expanding) tabChain[tabChainIndex].maximumSize = tabChain[tabChainIndex].sizeHint; } last = minx; available = size.width(); maxExtent = maxHeight; } else { int miny = 0; int y = 0; int maxWidth = 0; for (i = 0; i < tabList.count(); ++i, ++tabChainIndex) { QSize sz = q->tabSizeHint(i); tabList[i].maxRect = QRect(0, y, sz.width(), sz.height()); y += sz.height(); maxWidth = qMax(maxWidth, sz.width()); sz = q->minimumTabSizeHint(i); tabList[i].minRect = QRect(0, miny, sz.width(), sz.height()); miny += sz.height(); tabChain[tabChainIndex].init(); tabChain[tabChainIndex].sizeHint = tabList.at(i).maxRect.height(); tabChain[tabChainIndex].minimumSize = sz.height(); tabChain[tabChainIndex].empty = false; tabChain[tabChainIndex].expansive = true; if (!expanding) tabChain[tabChainIndex].maximumSize = tabChain[tabChainIndex].sizeHint; } last = miny; available = size.height(); maxExtent = maxWidth; } // Mirror our front item. tabChain[tabChainIndex].init(); tabChain[tabChainIndex].expansive = (!expanding) && (tabAlignment != Qt::AlignRight) && (tabAlignment != Qt::AlignJustify); tabChain[tabChainIndex].empty = true; Q_ASSERT(tabChainIndex == tabChain.count() - 1); // add an assert just to make sure. // Do the calculation qGeomCalc(tabChain, 0, tabChain.count(), 0, qMax(available, last), 0); // Use the results for (i = 0; i < tabList.count(); ++i) { const QCustomLayoutStruct &lstruct = tabChain.at(i + 1); if (!vertTabs) tabList[i].rect.setRect(lstruct.pos, 0, lstruct.size, maxExtent); else tabList[i].rect.setRect(0, lstruct.pos, maxExtent, lstruct.size); } if (useScrollButtons && tabList.count() && last > available) { const QRect scrollRect = normalizedScrollRect(0); scrollOffset = -scrollRect.left(); Q_Q(KCustomTabBar); QStyleOption opt; opt.initFrom(q); QRect scrollButtonLeftRect = q->style()->subElementRect(QStyle::SE_TabBarScrollLeftButton, &opt, q); QRect scrollButtonRightRect = q->style()->subElementRect(QStyle::SE_TabBarScrollRightButton, &opt, q); int scrollButtonWidth = q->style()->pixelMetric(QStyle::PM_TabBarScrollButtonWidth, &opt, q); // Normally SE_TabBarScrollLeftButton should have the same width as PM_TabBarScrollButtonWidth. // But if that is not the case, we set the actual button width to PM_TabBarScrollButtonWidth, and // use the extra space from SE_TabBarScrollLeftButton as margins towards the tabs. if (vertTabs) { scrollButtonLeftRect.setHeight(scrollButtonWidth); scrollButtonRightRect.setY(scrollButtonRightRect.bottom() + 1 - scrollButtonWidth); scrollButtonRightRect.setHeight(scrollButtonWidth); leftB->setArrowType(Qt::UpArrow); rightB->setArrowType(Qt::DownArrow); } else if (q->layoutDirection() == Qt::RightToLeft) { scrollButtonRightRect.setWidth(scrollButtonWidth); scrollButtonLeftRect.setX(scrollButtonLeftRect.right() + 1 - scrollButtonWidth); scrollButtonLeftRect.setWidth(scrollButtonWidth); leftB->setArrowType(Qt::RightArrow); rightB->setArrowType(Qt::LeftArrow); } else { scrollButtonLeftRect.setWidth(scrollButtonWidth); scrollButtonRightRect.setX(scrollButtonRightRect.right() + 1 - scrollButtonWidth); scrollButtonRightRect.setWidth(scrollButtonWidth); leftB->setArrowType(Qt::LeftArrow); rightB->setArrowType(Qt::RightArrow); } leftB->setGeometry(scrollButtonLeftRect); leftB->setEnabled(false); leftB->show(); rightB->setGeometry(scrollButtonRightRect); rightB->setEnabled(last - scrollOffset > scrollRect.x() + scrollRect.width()); rightB->show(); } else { scrollOffset = 0; rightB->hide(); leftB->hide(); } layoutWidgets(); q->tabLayoutChange(); } QRect KCustomTabBarPrivate::normalizedScrollRect(int index) { // "Normalized scroll rect" means return the free space on the tab bar // that doesn't overlap with scroll buttons or tear indicators, and // always return the rect as horizontal Qt::LeftToRight, even if the // tab bar itself is in a different orientation. Q_Q(KCustomTabBar); QStyleOptionTab opt; q->initStyleOption(&opt, currentIndex); opt.rect = q->rect(); QRect scrollButtonLeftRect = q->style()->subElementRect(QStyle::SE_TabBarScrollLeftButton, &opt, q); QRect scrollButtonRightRect = q->style()->subElementRect(QStyle::SE_TabBarScrollRightButton, &opt, q); QRect tearLeftRect = q->style()->subElementRect(QStyle::SE_TabBarTearIndicatorLeft, &opt, q); QRect tearRightRect = q->style()->subElementRect(QStyle::SE_TabBarTearIndicatorRight, &opt, q); if (verticalTabs(shape)) { int topEdge, bottomEdge; bool leftButtonIsOnTop = scrollButtonLeftRect.y() < q->height() / 2; bool rightButtonIsOnTop = scrollButtonRightRect.y() < q->height() / 2; if (leftButtonIsOnTop && rightButtonIsOnTop) { topEdge = scrollButtonRightRect.bottom() + 1; bottomEdge = q->height(); } else if (!leftButtonIsOnTop && !rightButtonIsOnTop) { topEdge = 0; bottomEdge = scrollButtonLeftRect.top(); } else { topEdge = scrollButtonLeftRect.bottom() + 1; bottomEdge = scrollButtonRightRect.top(); } bool tearTopVisible = index != 0 && topEdge != -scrollOffset; bool tearBottomVisible = index != tabList.size() - 1 && bottomEdge != tabList.constLast().rect.bottom() + 1 - scrollOffset; if (tearTopVisible && !tearLeftRect.isNull()) topEdge = tearLeftRect.bottom() + 1; if (tearBottomVisible && !tearRightRect.isNull()) bottomEdge = tearRightRect.top(); return QRect(topEdge, 0, bottomEdge - topEdge, q->height()); } else { if (q->layoutDirection() == Qt::RightToLeft) { scrollButtonLeftRect = QStyle::visualRect(Qt::RightToLeft, q->rect(), scrollButtonLeftRect); scrollButtonRightRect = QStyle::visualRect(Qt::RightToLeft, q->rect(), scrollButtonRightRect); tearLeftRect = QStyle::visualRect(Qt::RightToLeft, q->rect(), tearLeftRect); tearRightRect = QStyle::visualRect(Qt::RightToLeft, q->rect(), tearRightRect); } int leftEdge, rightEdge; bool leftButtonIsOnLeftSide = scrollButtonLeftRect.x() < q->width() / 2; bool rightButtonIsOnLeftSide = scrollButtonRightRect.x() < q->width() / 2; if (leftButtonIsOnLeftSide && rightButtonIsOnLeftSide) { leftEdge = scrollButtonRightRect.right() + 1; rightEdge = q->width(); } else if (!leftButtonIsOnLeftSide && !rightButtonIsOnLeftSide) { leftEdge = 0; rightEdge = scrollButtonLeftRect.left(); } else { leftEdge = scrollButtonLeftRect.right() + 1; rightEdge = scrollButtonRightRect.left(); } bool tearLeftVisible = index != 0 && leftEdge != -scrollOffset; bool tearRightVisible = index != tabList.size() - 1 && rightEdge != tabList.constLast().rect.right() + 1 - scrollOffset; if (tearLeftVisible && !tearLeftRect.isNull()) leftEdge = tearLeftRect.right() + 1; if (tearRightVisible && !tearRightRect.isNull()) rightEdge = tearRightRect.left(); return QRect(leftEdge, 0, rightEdge - leftEdge, q->height()); } } int KCustomTabBarPrivate::hoveredTabIndex() const { if (dragInProgress) return currentIndex; if (hoverIndex >= 0) return hoverIndex; return -1; } void KCustomTabBarPrivate::makeVisible(int index) { Q_Q(KCustomTabBar); if (!validIndex(index) || leftB->isHidden()) return; const QRect tabRect = tabList.at(index).rect; const int oldScrollOffset = scrollOffset; const bool horiz = !verticalTabs(shape); const int tabStart = horiz ? tabRect.left() : tabRect.top(); const int tabEnd = horiz ? tabRect.right() : tabRect.bottom(); const int lastTabEnd = horiz ? tabList.constLast().rect.right() : tabList.constLast().rect.bottom(); const QRect scrollRect = normalizedScrollRect(index); const int scrolledTabBarStart = qMax(1, scrollRect.left() + scrollOffset); const int scrolledTabBarEnd = qMin(lastTabEnd - 1, scrollRect.right() + scrollOffset); if (tabStart < scrolledTabBarStart) { // Tab is outside on the left, so scroll left. scrollOffset = tabStart - scrollRect.left(); } else if (tabEnd > scrolledTabBarEnd) { // Tab is outside on the right, so scroll right. scrollOffset = tabEnd - scrollRect.right(); } leftB->setEnabled(scrollOffset > -scrollRect.left()); emit q->leftBStatus(scrollOffset > -scrollRect.left()); rightB->setEnabled(scrollOffset < lastTabEnd - scrollRect.right()); emit q->rightBStatus(scrollOffset < lastTabEnd - scrollRect.right()); if (oldScrollOffset != scrollOffset) { q->update(); layoutWidgets(); } } void KCustomTabBarPrivate::killSwitchTabTimer() { Q_Q(KCustomTabBar); if (switchTabTimerId) { q->killTimer(switchTabTimerId); switchTabTimerId = 0; } switchTabCurrentIndex = -1; } void KCustomTabBarPrivate::layoutTab(int index) { Q_Q(KCustomTabBar); Q_ASSERT(index >= 0); Tab &tab = tabList[index]; bool vertical = verticalTabs(shape); if (!(tab.leftWidget || tab.rightWidget)) return; QStyleOptionTab opt; q->initStyleOption(&opt, index); if (tab.leftWidget) { QRect rect = q->style()->subElementRect(QStyle::SE_TabBarTabLeftButton, &opt, q); QPoint p = rect.topLeft(); if ((index == pressedIndex) || paintWithOffsets) { if (vertical) p.setY(p.y() + tabList[index].dragOffset); else p.setX(p.x() + tabList[index].dragOffset); } tab.leftWidget->move(p); } if (tab.rightWidget) { QRect rect = q->style()->subElementRect(QStyle::SE_TabBarTabRightButton, &opt, q); QPoint p = rect.topLeft(); if ((index == pressedIndex) || paintWithOffsets) { if (vertical) p.setY(p.y() + tab.dragOffset); else p.setX(p.x() + tab.dragOffset); } tab.rightWidget->move(p); } } void KCustomTabBarPrivate::layoutWidgets(int start) { Q_Q(KCustomTabBar); for (int i = start; i < q->count(); ++i) { layoutTab(i); } } void KCustomTabBarPrivate::autoHideTabs() { Q_Q(KCustomTabBar); if (autoHide) q->setVisible(q->count() > 1); } void KCustomTabBar::closeTab() { Q_D(KCustomTabBar); QObject *object = sender(); int tabToClose = -1; KCustomTabBar::ButtonPosition closeSide = (KCustomTabBar::ButtonPosition)style()->styleHint(QStyle::SH_TabBar_CloseButtonPosition, 0, this); for (int i = 0; i < d->tabList.count(); ++i) { if (closeSide == KCustomTabBar::LeftSide) { if (d->tabList.at(i).leftWidget == object) { tabToClose = i; break; } } else { if (d->tabList.at(i).rightWidget == object) { tabToClose = i; break; } } } if (tabToClose != -1) emit tabCloseRequested(tabToClose); } // void KCustomTabBar::scrollTabs() //{ // if (sender1 == d->leftB) { // } else if (sender1 == d->rightB) { // } //} void KCustomTabBar::leftScrollTabs() { Q_D(KCustomTabBar); // const QObject *sender1 = sender(); const bool horizontal = !verticalTabs(d->shape); const QRect scrollRect = d->normalizedScrollRect(); int i = -1; for (i = d->tabList.count() - 1; i >= 0; --i) { int start = horizontal ? d->tabList.at(i).rect.left() : d->tabList.at(i).rect.top(); if (start < scrollRect.left() + d->scrollOffset) { d->makeVisible(i); return; } } } void KCustomTabBar::rightScrollTabs() { Q_D(KCustomTabBar); // const QObject *sender1 = sender(); const bool horizontal = !verticalTabs(d->shape); const QRect scrollRect = d->normalizedScrollRect(); int i = -1; for (i = 0; i < d->tabList.count(); ++i) { int end = horizontal ? d->tabList.at(i).rect.right() : d->tabList.at(i).rect.bottom(); if (end > scrollRect.right() + d->scrollOffset) { d->makeVisible(i); return; } } } void KCustomTabBarPrivate::refresh() { Q_Q(KCustomTabBar); // be safe in case a subclass is also handling move with the tabs if (pressedIndex != -1 && movable && QApplication::mouseButtons() == Qt::NoButton) { moveTabFinished(pressedIndex); if (!validIndex(pressedIndex)) pressedIndex = -1; } if (!q->isVisible()) { layoutDirty = true; } else { layoutTabs(); makeVisible(currentIndex); q->update(); q->updateGeometry(); } } /*! Creates a new tab bar with the given \a parent. */ KCustomTabBar::KCustomTabBar(QWidget *parent) : QWidget(parent) , d_ptr(new KCustomTabBarPrivate(this)) { Q_D(KCustomTabBar); d->init(); } /*! Destroys the tab bar. */ KCustomTabBar::~KCustomTabBar() { } /*! \property KCustomTabBar::shape \brief the shape of the tabs in the tab bar Possible values for this property are described by the Shape enum. */ KCustomTabBar::Shape KCustomTabBar::shape() const { Q_D(const KCustomTabBar); return d->shape; } void KCustomTabBar::setShape(Shape shape) { Q_D(KCustomTabBar); if (d->shape == shape) return; d->shape = shape; d->refresh(); } /*! \property KCustomTabBar::drawBase \brief defines whether or not tab bar should draw its base. If true then KCustomTabBar draws a base in relation to the styles overlab. Otherwise only the tabs are drawn. \sa QStyle::pixelMetric(), QStyle::PM_TabBarBaseOverlap, QStyleOptionTabBarBase */ void KCustomTabBar::setDrawBase(bool drawBase) { Q_D(KCustomTabBar); if (d->drawBase == drawBase) return; d->drawBase = drawBase; update(); } bool KCustomTabBar::drawBase() const { Q_D(const KCustomTabBar); return d->drawBase; } /*! Adds a new tab with text \a text. Returns the new tab's index. */ int KCustomTabBar::addTab(const QString &text) { return insertTab(-1, text); } /*! \overload Adds a new tab with icon \a icon and text \a text. Returns the new tab's index. */ int KCustomTabBar::addTab(const QIcon &icon, const QString &text) { return insertTab(-1, icon, text); } /*! Inserts a new tab with text \a text at position \a index. If \a index is out of range, the new tab is appened. Returns the new tab's index. */ int KCustomTabBar::insertTab(int index, const QString &text) { return insertTab(index, QIcon(), text); } /*!\overload Inserts a new tab with icon \a icon and text \a text at position \a index. If \a index is out of range, the new tab is appended. Returns the new tab's index. If the KCustomTabBar was empty before this function is called, the inserted tab becomes the current tab. Inserting a new tab at an index less than or equal to the current index will increment the current index, but keep the current tab. */ int KCustomTabBar::insertTab(int index, const QIcon &icon, const QString &text) { Q_D(KCustomTabBar); if (!d->validIndex(index)) { index = d->tabList.count(); d->tabList.append(KCustomTabBarPrivate::Tab(icon, text)); } else { d->tabList.insert(index, KCustomTabBarPrivate::Tab(icon, text)); } #ifndef QT_NO_SHORTCUT d->tabList[index].shortcutId = grabShortcut(QKeySequence::mnemonic(text)); #endif d->refresh(); if (d->tabList.count() == 1) setCurrentIndex(index); else if (index <= d->currentIndex) ++d->currentIndex; if (d->closeButtonOnTabs) { QStyleOptionTab opt; initStyleOption(&opt, index); ButtonPosition closeSide = (ButtonPosition)style()->styleHint(QStyle::SH_TabBar_CloseButtonPosition, 0, this); QAbstractButton *closeButton = new CloseButton(this); // connect(closeButton, SIGNAL(clicked()), this, SLOT(_q_closeTab())); connect(closeButton, &QAbstractButton::clicked, this, [=] { closeTab(); }); setTabButton(index, closeSide, closeButton); } for (int i = 0; i < d->tabList.count(); ++i) { if (d->tabList[i].lastTab >= index) ++d->tabList[i].lastTab; } tabInserted(index); d->autoHideTabs(); return index; } /*! Removes the tab at position \a index. \sa SelectionBehavior */ void KCustomTabBar::removeTab(int index) { Q_D(KCustomTabBar); if (d->validIndex(index)) { if (d->dragInProgress) d->moveTabFinished(d->pressedIndex); #ifndef QT_NO_SHORTCUT releaseShortcut(d->tabList.at(index).shortcutId); #endif if (d->tabList[index].leftWidget) { d->tabList[index].leftWidget->hide(); d->tabList[index].leftWidget->deleteLater(); d->tabList[index].leftWidget = 0; } if (d->tabList[index].rightWidget) { d->tabList[index].rightWidget->hide(); d->tabList[index].rightWidget->deleteLater(); d->tabList[index].rightWidget = 0; } int newIndex = d->tabList[index].lastTab; d->tabList.removeAt(index); for (int i = 0; i < d->tabList.count(); ++i) { if (d->tabList[i].lastTab == index) d->tabList[i].lastTab = -1; if (d->tabList[i].lastTab > index) --d->tabList[i].lastTab; } if (index == d->currentIndex) { // The current tab is going away, in order to make sure // we emit that "current has changed", we need to reset this // around. d->currentIndex = -1; if (d->tabList.size() > 0) { switch (d->selectionBehaviorOnRemove) { case SelectPreviousTab: if (newIndex > index) newIndex--; if (d->validIndex(newIndex)) break; Q_FALLTHROUGH(); case SelectRightTab: newIndex = index; if (newIndex >= d->tabList.size()) newIndex = d->tabList.size() - 1; break; case SelectLeftTab: newIndex = index - 1; if (newIndex < 0) newIndex = 0; break; default: break; } if (d->validIndex(newIndex)) { // don't loose newIndex's old through setCurrentIndex int bump = d->tabList[newIndex].lastTab; setCurrentIndex(newIndex); d->tabList[newIndex].lastTab = bump; } } else { emit currentChanged(-1); } } else if (index < d->currentIndex) { setCurrentIndex(d->currentIndex - 1); } d->refresh(); d->autoHideTabs(); if (!d->hoverRect.isEmpty()) { for (int i = 0; i < d->tabList.count(); ++i) { const QRect area = tabRect(i); if (area.contains(mapFromGlobal(QCursor::pos()))) { d->hoverIndex = i; d->hoverRect = area; break; } } update(d->hoverRect); } tabRemoved(index); } } /*! Returns \c true if the tab at position \a index is enabled; otherwise returns \c false. */ bool KCustomTabBar::isTabEnabled(int index) const { Q_D(const KCustomTabBar); if (const KCustomTabBarPrivate::Tab *tab = d->at(index)) return tab->enabled; return false; } /*! If \a enabled is true then the tab at position \a index is enabled; otherwise the item at position \a index is disabled. */ void KCustomTabBar::setTabEnabled(int index, bool enabled) { Q_D(KCustomTabBar); if (KCustomTabBarPrivate::Tab *tab = d->at(index)) { tab->enabled = enabled; #ifndef QT_NO_SHORTCUT setShortcutEnabled(tab->shortcutId, enabled); #endif update(); if (!enabled && index == d->currentIndex) setCurrentIndex(d->validIndex(index + 1) ? index + 1 : 0); else if (enabled && !d->validIndex(d->currentIndex)) setCurrentIndex(index); } } /*! Returns the text of the tab at position \a index, or an empty string if \a index is out of range. */ QString KCustomTabBar::tabText(int index) const { Q_D(const KCustomTabBar); if (const KCustomTabBarPrivate::Tab *tab = d->at(index)) return tab->text; return QString(); } /*! Sets the text of the tab at position \a index to \a text. */ void KCustomTabBar::setTabText(int index, const QString &text) { Q_D(KCustomTabBar); if (KCustomTabBarPrivate::Tab *tab = d->at(index)) { d->textSizes.remove(tab->text); tab->text = text; #ifndef QT_NO_SHORTCUT releaseShortcut(tab->shortcutId); tab->shortcutId = grabShortcut(QKeySequence::mnemonic(text)); setShortcutEnabled(tab->shortcutId, tab->enabled); #endif d->refresh(); } } void KCustomTabBar::setTabContent(int index, const QString &text) { Q_D(KCustomTabBar); if (KCustomTabBarPrivate::Tab *tab = d->at(index)) { d->textSizes.remove(tab->text); tab->text = text; #ifndef QT_NO_SHORTCUT releaseShortcut(tab->shortcutId); tab->shortcutId = grabShortcut(QKeySequence::mnemonic(text)); setShortcutEnabled(tab->shortcutId, tab->enabled); #endif } } /*! Returns the text color of the tab with the given \a index, or a invalid color if \a index is out of range. \sa setTabTextColor() */ QColor KCustomTabBar::tabTextColor(int index) const { Q_D(const KCustomTabBar); if (const KCustomTabBarPrivate::Tab *tab = d->at(index)) return tab->textColor; return QColor(); } /*! Sets the color of the text in the tab with the given \a index to the specified \a color. If an invalid color is specified, the tab will use the KCustomTabBar foreground role instead. \sa tabTextColor() */ void KCustomTabBar::setTabTextColor(int index, const QColor &color) { Q_D(KCustomTabBar); if (KCustomTabBarPrivate::Tab *tab = d->at(index)) { tab->textColor = color; update(tabRect(index)); } } /*! Returns the icon of the tab at position \a index, or a null icon if \a index is out of range. */ QIcon KCustomTabBar::tabIcon(int index) const { Q_D(const KCustomTabBar); if (const KCustomTabBarPrivate::Tab *tab = d->at(index)) return tab->icon; return QIcon(); } /*! Sets the icon of the tab at position \a index to \a icon. */ void KCustomTabBar::setTabIcon(int index, const QIcon &icon) { Q_D(KCustomTabBar); if (KCustomTabBarPrivate::Tab *tab = d->at(index)) { bool simpleIconChange = (!icon.isNull() && !tab->icon.isNull()); tab->icon = icon; if (simpleIconChange) update(tabRect(index)); else d->refresh(); } } #ifndef QT_NO_TOOLTIP /*! Sets the tool tip of the tab at position \a index to \a tip. */ void KCustomTabBar::setTabToolTip(int index, const QString &tip) { Q_D(KCustomTabBar); if (KCustomTabBarPrivate::Tab *tab = d->at(index)) tab->toolTip = tip; } /*! Returns the tool tip of the tab at position \a index, or an empty string if \a index is out of range. */ QString KCustomTabBar::tabToolTip(int index) const { Q_D(const KCustomTabBar); if (const KCustomTabBarPrivate::Tab *tab = d->at(index)) return tab->toolTip; return QString(); } #endif // QT_NO_TOOLTIP #if QT_CONFIG(whatsthis) /*! \since 4.1 Sets the What's This help text of the tab at position \a index to \a text. */ void KCustomTabBar::setTabWhatsThis(int index, const QString &text) { Q_D(KCustomTabBar); if (KCustomTabBarPrivate::Tab *tab = d->at(index)) tab->whatsThis = text; } /*! \since 4.1 Returns the What's This help text of the tab at position \a index, or an empty string if \a index is out of range. */ QString KCustomTabBar::tabWhatsThis(int index) const { Q_D(const KCustomTabBar); if (const KCustomTabBarPrivate::Tab *tab = d->at(index)) return tab->whatsThis; return QString(); } #endif // QT_CONFIG(whatsthis) /*! Sets the data of the tab at position \a index to \a data. */ void KCustomTabBar::setTabData(int index, const QVariant &data) { Q_D(KCustomTabBar); if (KCustomTabBarPrivate::Tab *tab = d->at(index)) tab->data = data; } /*! Returns the data of the tab at position \a index, or a null variant if \a index is out of range. */ QVariant KCustomTabBar::tabData(int index) const { Q_D(const KCustomTabBar); if (const KCustomTabBarPrivate::Tab *tab = d->at(index)) return tab->data; return QVariant(); } /*! Returns the visual rectangle of the tab at position \a index, or a null rectangle if \a index is out of range. */ QRect KCustomTabBar::tabRect(int index) const { Q_D(const KCustomTabBar); if (const KCustomTabBarPrivate::Tab *tab = d->at(index)) { if (d->layoutDirty) const_cast(d)->layoutTabs(); QRect r = tab->rect; if (verticalTabs(d->shape)) r.translate(0, -d->scrollOffset); else r.translate(-d->scrollOffset, 0); if (!verticalTabs(d->shape)) r = QStyle::visualRect(layoutDirection(), rect(), r); return r; } return QRect(); } /*! \since 4.3 Returns the index of the tab that covers \a position or -1 if no tab covers \a position; */ int KCustomTabBar::tabAt(const QPoint &position) const { Q_D(const KCustomTabBar); if (d->validIndex(d->currentIndex) && tabRect(d->currentIndex).contains(position)) { return d->currentIndex; } const int max = d->tabList.size(); for (int i = 0; i < max; ++i) { if (tabRect(i).contains(position)) { return i; } } return -1; } /*! \property KCustomTabBar::currentIndex \brief the index of the tab bar's visible tab The current index is -1 if there is no current tab. */ int KCustomTabBar::currentIndex() const { Q_D(const KCustomTabBar); if (d->validIndex(d->currentIndex)) return d->currentIndex; return -1; } void KCustomTabBar::setCurrentIndex(int index) { Q_D(KCustomTabBar); if (d->dragInProgress && d->pressedIndex != -1) return; int oldIndex = d->currentIndex; if (d->validIndex(index) && d->currentIndex != index) { d->currentIndex = index; update(); d->makeVisible(index); d->tabList[index].lastTab = oldIndex; if (oldIndex >= 0 && oldIndex < count()) d->layoutTab(oldIndex); d->layoutTab(index); #ifndef QT_NO_ACCESSIBILITY if (QAccessible::isActive()) { if (hasFocus()) { QAccessibleEvent focusEvent(this, QAccessible::Focus); focusEvent.setChild(index); QAccessible::updateAccessibility(&focusEvent); } QAccessibleEvent selectionEvent(this, QAccessible::Selection); selectionEvent.setChild(index); QAccessible::updateAccessibility(&selectionEvent); } #endif emit currentChanged(index); } } /*! \property KCustomTabBar::iconSize \brief The size for icons in the tab bar \since 4.1 The default value is style-dependent. \c iconSize is a maximum size; icons that are smaller are not scaled up. \sa QTabWidget::iconSize */ QSize KCustomTabBar::iconSize() const { Q_D(const KCustomTabBar); if (d->iconSize.isValid()) return d->iconSize; int iconExtent = style()->pixelMetric(QStyle::PM_TabBarIconSize, 0, this); return QSize(iconExtent, iconExtent); } void KCustomTabBar::setIconSize(const QSize &size) { Q_D(KCustomTabBar); d->iconSize = size; d->layoutDirty = true; update(); updateGeometry(); } /*! \property KCustomTabBar::count \brief the number of tabs in the tab bar */ int KCustomTabBar::count() const { Q_D(const KCustomTabBar); return d->tabList.count(); } /*!\reimp */ QSize KCustomTabBar::sizeHint() const { Q_D(const KCustomTabBar); if (d->layoutDirty) const_cast(d)->layoutTabs(); QRect r; for (int i = 0; i < d->tabList.count(); ++i) r = r.united(d->tabList.at(i).maxRect); return r.size(); } /*!\reimp */ QSize KCustomTabBar::minimumSizeHint() const { Q_D(const KCustomTabBar); if (d->layoutDirty) const_cast(d)->layoutTabs(); if (!d->useScrollButtons) { QRect r; for (int i = 0; i < d->tabList.count(); ++i) r = r.united(d->tabList.at(i).minRect); return r.size(); } if (verticalTabs(d->shape)) return QSize(sizeHint().width(), d->rightB->sizeHint().height() * 2 + 75); else return QSize(d->rightB->sizeHint().width() * 2 + 75, sizeHint().height()); } // Compute the most-elided possible text, for minimumSizeHint static QString computeElidedText(Qt::TextElideMode mode, const QString &text) { if (text.length() <= 3) return text; static const QLatin1String Ellipses("..."); QString ret; switch (mode) { case Qt::ElideRight: ret = text.left(2) + Ellipses; break; case Qt::ElideMiddle: ret = text.left(1) + Ellipses + text.right(1); break; case Qt::ElideLeft: ret = Ellipses + text.right(2); break; case Qt::ElideNone: ret = text; break; } return ret; } /*! Returns the minimum tab size hint for the tab at position \a index. \since 5.0 */ QSize KCustomTabBar::minimumTabSizeHint(int index) const { Q_D(const KCustomTabBar); KCustomTabBarPrivate::Tab &tab = const_cast(d->tabList[index]); QString oldText = tab.text; tab.text = computeElidedText(d->elideMode, oldText); QSize size = tabSizeHint(index); tab.text = oldText; return size; } /*! Returns the size hint for the tab at position \a index. */ QSize KCustomTabBar::tabSizeHint(int index) const { // Note: this must match with the computations in QCommonStylePrivate::tabLayout Q_D(const KCustomTabBar); if (const KCustomTabBarPrivate::Tab *tab = d->at(index)) { QStyleOptionTab opt; d->initBasicStyleOption(&opt, index); opt.text = d->tabList.at(index).text; QSize iconSize = tab->icon.isNull() ? QSize(0, 0) : opt.iconSize; int hframe = style()->pixelMetric(QStyle::PM_TabBarTabHSpace, &opt, this); int vframe = style()->pixelMetric(QStyle::PM_TabBarTabVSpace, &opt, this); const QFontMetrics fm = fontMetrics(); int maxWidgetHeight = qMax(opt.leftButtonSize.height(), opt.rightButtonSize.height()); int maxWidgetWidth = qMax(opt.leftButtonSize.width(), opt.rightButtonSize.width()); int widgetWidth = 0; int widgetHeight = 0; int padding = 0; if (!opt.leftButtonSize.isEmpty()) { padding += 4; widgetWidth += opt.leftButtonSize.width(); widgetHeight += opt.leftButtonSize.height(); } if (!opt.rightButtonSize.isEmpty()) { padding += 4; widgetWidth += opt.rightButtonSize.width(); widgetHeight += opt.rightButtonSize.height(); } if (!opt.icon.isNull()) padding += 4; QHash::iterator it = d->textSizes.find(tab->text); if (it == d->textSizes.end()) it = d->textSizes.insert(tab->text, fm.size(Qt::TextShowMnemonic, tab->text)); const int textWidth = it.value().width(); QSize csz; if (verticalTabs(d->shape)) { csz = QSize(qMax(maxWidgetWidth, qMax(fm.height(), iconSize.height())) + vframe, textWidth + iconSize.width() + hframe + widgetHeight + padding); } else { csz = QSize(textWidth + iconSize.width() + hframe + widgetWidth + padding, qMax(maxWidgetHeight, qMax(fm.height(), iconSize.height())) + vframe); } QSize retSize = style()->sizeFromContents(QStyle::CT_TabBarTab, &opt, csz, this); return retSize; } return QSize(); } /*! This virtual handler is called after a new tab was added or inserted at position \a index. \sa tabRemoved() */ void KCustomTabBar::tabInserted(int index) { Q_UNUSED(index) } /*! This virtual handler is called after a tab was removed from position \a index. \sa tabInserted() */ void KCustomTabBar::tabRemoved(int index) { Q_UNUSED(index) } /*! This virtual handler is called whenever the tab layout changes. \sa tabRect() */ void KCustomTabBar::tabLayoutChange() { } /*!\reimp */ void KCustomTabBar::showEvent(QShowEvent *) { Q_D(KCustomTabBar); if (d->layoutDirty) d->refresh(); if (!d->validIndex(d->currentIndex)) setCurrentIndex(0); d->updateMacBorderMetrics(); } /*!\reimp */ void KCustomTabBar::hideEvent(QHideEvent *) { Q_D(KCustomTabBar); d->updateMacBorderMetrics(); } /*!\reimp */ bool KCustomTabBar::event(QEvent *event) { Q_D(KCustomTabBar); if (event->type() == QEvent::HoverMove || event->type() == QEvent::HoverEnter) { QHoverEvent *he = static_cast(event); if (!d->hoverRect.contains(he->pos())) { QRect oldHoverRect = d->hoverRect; bool cursorOverTabs = false; for (int i = 0; i < d->tabList.count(); ++i) { QRect area = tabRect(i); if (area.contains(he->pos())) { d->hoverIndex = i; d->hoverRect = area; cursorOverTabs = true; break; } } if (!cursorOverTabs) { d->hoverIndex = -1; d->hoverRect = QRect(); } if (he->oldPos() != QPoint(-1, -1)) update(oldHoverRect); update(d->hoverRect); } return true; } else if (event->type() == QEvent::HoverLeave) { QRect oldHoverRect = d->hoverRect; d->hoverIndex = -1; d->hoverRect = QRect(); update(oldHoverRect); return true; #ifndef QT_NO_TOOLTIP } else if (event->type() == QEvent::ToolTip) { if (const KCustomTabBarPrivate::Tab *tab = d->at(tabAt(static_cast(event)->pos()))) { if (!tab->toolTip.isEmpty()) { QToolTip::showText(static_cast(event)->globalPos(), tab->toolTip, this); return true; } } #endif // QT_NO_TOOLTIP #if QT_CONFIG(whatsthis) } else if (event->type() == QEvent::QueryWhatsThis) { const KCustomTabBarPrivate::Tab *tab = d->at(d->indexAtPos(static_cast(event)->pos())); if (!tab || tab->whatsThis.isEmpty()) event->ignore(); return true; } else if (event->type() == QEvent::WhatsThis) { if (const KCustomTabBarPrivate::Tab *tab = d->at(d->indexAtPos(static_cast(event)->pos()))) { if (!tab->whatsThis.isEmpty()) { QWhatsThis::showText(static_cast(event)->globalPos(), tab->whatsThis, this); return true; } } #endif // QT_CONFIG(whatsthis) #ifndef QT_NO_SHORTCUT } else if (event->type() == QEvent::Shortcut) { QShortcutEvent *se = static_cast(event); for (int i = 0; i < d->tabList.count(); ++i) { const KCustomTabBarPrivate::Tab *tab = &d->tabList.at(i); if (tab->shortcutId == se->shortcutId()) { setCurrentIndex(i); return true; } } #endif } else if (event->type() == QEvent::MouseButtonDblClick) { // ### fixme Qt 6: move to mouseDoubleClickEvent(), here for BC reasons. const QPoint pos = static_cast(event)->pos(); const bool isEventInCornerButtons = (!d->leftB->isHidden() && d->leftB->geometry().contains(pos)) || (!d->rightB->isHidden() && d->rightB->geometry().contains(pos)); if (!isEventInCornerButtons) emit tabBarDoubleClicked(tabAt(pos)); } else if (event->type() == QEvent::Move) { d->updateMacBorderMetrics(); return QWidget::event(event); #if QT_CONFIG(draganddrop) } else if (event->type() == QEvent::DragEnter) { if (d->changeCurrentOnDrag) event->accept(); } else if (event->type() == QEvent::DragMove) { if (d->changeCurrentOnDrag) { const int tabIndex = tabAt(static_cast(event)->pos()); if (isTabEnabled(tabIndex) && d->switchTabCurrentIndex != tabIndex) { d->switchTabCurrentIndex = tabIndex; if (d->switchTabTimerId) killTimer(d->switchTabTimerId); d->switchTabTimerId = startTimer(style()->styleHint(QStyle::SH_TabBar_ChangeCurrentDelay)); } event->ignore(); } } else if (event->type() == QEvent::DragLeave || event->type() == QEvent::Drop) { d->killSwitchTabTimer(); event->ignore(); #endif } return QWidget::event(event); } /*!\reimp */ void KCustomTabBar::resizeEvent(QResizeEvent *) { Q_D(KCustomTabBar); if (d->layoutDirty) updateGeometry(); d->layoutTabs(); d->makeVisible(d->currentIndex); } /*!\reimp */ void KCustomTabBar::paintEvent(QPaintEvent *) { Q_D(KCustomTabBar); QStyleOptionTabBarBase optTabBase; KCustomTabBarPrivate::initStyleBaseOption(&optTabBase, this, size()); QStylePainter p(this); int selected = -1; int cutLeft = -1; int cutRight = -1; bool vertical = verticalTabs(d->shape); QStyleOptionTab cutTabLeft; QStyleOptionTab cutTabRight; selected = d->currentIndex; if (d->dragInProgress) selected = d->pressedIndex; const QRect scrollRect = d->normalizedScrollRect(); for (int i = 0; i < d->tabList.count(); ++i) optTabBase.tabBarRect |= tabRect(i); optTabBase.selectedTabRect = tabRect(selected); if (d->drawBase) p.drawPrimitive(QStyle::PE_FrameTabBarBase, optTabBase); for (int i = 0; i < d->tabList.count(); ++i) { QStyleOptionTab tab; initStyleOption(&tab, i); if (d->paintWithOffsets && d->tabList[i].dragOffset != 0) { if (vertical) { tab.rect.moveTop(tab.rect.y() + d->tabList[i].dragOffset); } else { tab.rect.moveLeft(tab.rect.x() + d->tabList[i].dragOffset); } } if (!(tab.state & QStyle::State_Enabled)) { tab.palette.setCurrentColorGroup(QPalette::Disabled); } // If this tab is partially obscured, make a note of it so that we can pass the information // along when we draw the tear. QRect tabRect = d->tabList[i].rect; int tabStart = vertical ? tabRect.top() : tabRect.left(); int tabEnd = vertical ? tabRect.bottom() : tabRect.right(); if (tabStart < scrollRect.left() + d->scrollOffset) { cutLeft = i; cutTabLeft = tab; } else if (tabEnd > scrollRect.right() + d->scrollOffset) { cutRight = i; cutTabRight = tab; } // Don't bother drawing a tab if the entire tab is outside of the visible tab bar. if ((!vertical && (tab.rect.right() < 0 || tab.rect.left() > width())) || (vertical && (tab.rect.bottom() < 0 || tab.rect.top() > height()))) continue; optTabBase.tabBarRect |= tab.rect; if (i == selected) continue; p.drawControl(QStyle::CE_TabBarTab, tab); } // Draw the selected tab last to get it "on top" if (selected >= 0) { QStyleOptionTab tab; initStyleOption(&tab, selected); if (d->paintWithOffsets && d->tabList[selected].dragOffset != 0) { if (vertical) tab.rect.moveTop(tab.rect.y() + d->tabList[selected].dragOffset); else tab.rect.moveLeft(tab.rect.x() + d->tabList[selected].dragOffset); } if (!d->dragInProgress) p.drawControl(QStyle::CE_TabBarTab, tab); else { int taboverlap = style()->pixelMetric(QStyle::PM_TabBarTabOverlap, 0, this); if (verticalTabs(d->shape)) d->movingTab->setGeometry(tab.rect.adjusted(0, -taboverlap, 0, taboverlap)); else d->movingTab->setGeometry(tab.rect.adjusted(-taboverlap, 0, taboverlap, 0)); } } // Only draw the tear indicator if necessary. Most of the time we don't need too. if (d->leftB->isVisible() && cutLeft >= 0) { cutTabLeft.rect = rect(); cutTabLeft.rect = style()->subElementRect(QStyle::SE_TabBarTearIndicatorLeft, &cutTabLeft, this); p.drawPrimitive(QStyle::PE_IndicatorTabTearLeft, cutTabLeft); } if (d->rightB->isVisible() && cutRight >= 0) { cutTabRight.rect = rect(); cutTabRight.rect = style()->subElementRect(QStyle::SE_TabBarTearIndicatorRight, &cutTabRight, this); p.drawPrimitive(QStyle::PE_IndicatorTabTearRight, cutTabRight); } } /* Given that index at position from moved to position to where return where index goes. */ KCustomTabBarPrivate::KCustomTabBarPrivate(KCustomTabBar *parent) : q_ptr(parent) , currentIndex(-1) , pressedIndex(-1) , shape(KCustomTabBar::RoundedNorth) , layoutDirty(false) , drawBase(true) , scrollOffset(0) , hoverIndex(-1) , elideModeSetByUser(false) , useScrollButtonsSetByUser(false) , expanding(true) , closeButtonOnTabs(false) , selectionBehaviorOnRemove(KCustomTabBar::SelectRightTab) , paintWithOffsets(true) , movable(false) , dragInProgress(false) , documentMode(false) , autoHide(false) , changeCurrentOnDrag(false) , switchTabCurrentIndex(-1) , switchTabTimerId(0) , movingTab(0) { } void KCustomTabBarPrivate::qGeomCalc(QVector &chain, int start, int count, int pos, int space, int spacer) { int cHint = 0; int cMin = 0; int cMax = 0; int sumStretch = 0; int sumSpacing = 0; int expandingCount = 0; bool allEmptyNonstretch = true; int pendingSpacing = -1; int spacerCount = 0; int i; for (i = start; i < start + count; i++) { QCustomLayoutStruct *data = &chain[i]; data->done = false; cHint += data->smartSizeHint(); cMin += data->minimumSize; cMax += data->maximumSize; sumStretch += data->stretch; if (!data->empty) { /* Using pendingSpacing, we ensure that the spacing for the last (non-empty) item is ignored. */ if (pendingSpacing >= 0) { sumSpacing += pendingSpacing; ++spacerCount; } pendingSpacing = data->effectiveSpacer(spacer); } if (data->expansive) expandingCount++; allEmptyNonstretch = allEmptyNonstretch && data->empty && !data->expansive && data->stretch <= 0; } int extraspace = 0; if (space < cMin + sumSpacing) { /* Less space than minimumSize; take from the biggest first */ int minSize = cMin + sumSpacing; // shrink the spacers proportionally if (spacer >= 0) { spacer = minSize > 0 ? spacer * space / minSize : 0; sumSpacing = spacer * spacerCount; } QVarLengthArray minimumSizes; minimumSizes.reserve(count); for (i = start; i < start + count; i++) minimumSizes << chain.at(i).minimumSize; std::sort(minimumSizes.begin(), minimumSizes.end()); int space_left = space - sumSpacing; int sum = 0; int idx = 0; int space_used = 0; int current = 0; while (idx < count && space_used < space_left) { current = minimumSizes.at(idx); space_used = sum + current * (count - idx); sum += current; ++idx; } --idx; int deficit = space_used - space_left; int items = count - idx; /* * If we truncate all items to "current", we would get "deficit" too many pixels. Therefore, we have to remove * deficit/items from each item bigger than maxval. The actual value to remove is deficitPerItem + remainder/items * "rest" is the accumulated error from using integer arithmetic. */ int deficitPerItem = deficit / items; int remainder = deficit % items; int maxval = current - deficitPerItem; int rest = 0; for (i = start; i < start + count; i++) { int maxv = maxval; rest += remainder; if (rest >= items) { maxv--; rest -= items; } QCustomLayoutStruct *data = &chain[i]; data->size = qMin(data->minimumSize, maxv); data->done = true; } } else if (space < cHint + sumSpacing) { /* Less space than smartSizeHint(), but more than minimumSize. Currently take space equally from each, as in Qt 2.x. Commented-out lines will give more space to stretchier items. */ int n = count; int space_left = space - sumSpacing; int overdraft = cHint - space_left; // first give to the fixed ones: for (i = start; i < start + count; i++) { QCustomLayoutStruct *data = &chain[i]; if (!data->done && data->minimumSize >= data->smartSizeHint()) { data->size = data->smartSizeHint(); data->done = true; space_left -= data->smartSizeHint(); // sumStretch -= data->stretch; n--; } } bool finished = n == 0; while (!finished) { finished = true; Fixed64 fp_over = toFixed(overdraft); Fixed64 fp_w = 0; for (i = start; i < start + count; i++) { QCustomLayoutStruct *data = &chain[i]; if (data->done) continue; // if (sumStretch <= 0) fp_w += fp_over / n; // else // fp_w += (fp_over * data->stretch) / sumStretch; int w = fRound(fp_w); data->size = data->smartSizeHint() - w; fp_w -= toFixed(w); // give the difference to the next if (data->size < data->minimumSize) { data->done = true; data->size = data->minimumSize; finished = false; overdraft -= data->smartSizeHint() - data->minimumSize; // sumStretch -= data->stretch; n--; break; } } } } else { // extra space int n = count; int space_left = space - sumSpacing; // first give to the fixed ones, and handle non-expansiveness for (i = start; i < start + count; i++) { QCustomLayoutStruct *data = &chain[i]; if (!data->done && (data->maximumSize <= data->smartSizeHint() || (!allEmptyNonstretch && data->empty && !data->expansive && data->stretch == 0))) { data->size = data->smartSizeHint(); data->done = true; space_left -= data->size; sumStretch -= data->stretch; if (data->expansive) expandingCount--; n--; } } extraspace = space_left; /* Do a trial distribution and calculate how much it is off. If there are more deficit pixels than surplus pixels, give the minimum size items what they need, and repeat. Otherwise give to the maximum size items, and repeat. Paul Olav Tvete has a wonderful mathematical proof of the correctness of this principle, but unfortunately this comment is too small to contain it. */ int surplus, deficit; do { surplus = deficit = 0; Fixed64 fp_space = toFixed(space_left); Fixed64 fp_w = 0; for (i = start; i < start + count; i++) { QCustomLayoutStruct *data = &chain[i]; if (data->done) continue; extraspace = 0; if (sumStretch > 0) { fp_w += (fp_space * data->stretch) / sumStretch; } else if (expandingCount > 0) { fp_w += (fp_space * (data->expansive ? 1 : 0)) / expandingCount; } else { fp_w += fp_space * 1 / n; } int w = fRound(fp_w); data->size = w; fp_w -= toFixed(w); // give the difference to the next if (w < data->smartSizeHint()) { deficit += data->smartSizeHint() - w; } else if (w > data->maximumSize) { surplus += w - data->maximumSize; } } if (deficit > 0 && surplus <= deficit) { // give to the ones that have too little for (i = start; i < start + count; i++) { QCustomLayoutStruct *data = &chain[i]; if (!data->done && data->size < data->smartSizeHint()) { data->size = data->smartSizeHint(); data->done = true; space_left -= data->smartSizeHint(); sumStretch -= data->stretch; if (data->expansive) expandingCount--; n--; } } } if (surplus > 0 && surplus >= deficit) { // take from the ones that have too much for (i = start; i < start + count; i++) { QCustomLayoutStruct *data = &chain[i]; if (!data->done && data->size > data->maximumSize) { data->size = data->maximumSize; data->done = true; space_left -= data->maximumSize; sumStretch -= data->stretch; if (data->expansive) expandingCount--; n--; } } } } while (n > 0 && surplus != deficit); if (n == 0) extraspace = space_left; } /* As a last resort, we distribute the unwanted space equally among the spacers (counting the start and end of the chain). We could, but don't, attempt a sub-pixel allocation of the extra space. */ int extra = extraspace / (spacerCount + 2); int p = pos + extra; for (i = start; i < start + count; i++) { QCustomLayoutStruct *data = &chain[i]; data->pos = p; p += data->size; if (!data->empty) p += data->effectiveSpacer(spacer) + extra; } #ifdef QLAYOUT_EXTRA_DEBUG qDebug() << "qGeomCalc" << "start" << start << "count" << count << "pos" << pos << "space" << space << "spacer" << spacer; for (i = start; i < start + count; ++i) { qDebug() << i << ':' << chain[i].minimumSize << chain[i].smartSizeHint() << chain[i].maximumSize << "stretch" << chain[i].stretch << "empty" << chain[i].empty << "expansive" << chain[i].expansive << "spacing" << chain[i].spacing; qDebug() << "result pos" << chain[i].pos << "size" << chain[i].size; } #endif } int KCustomTabBarPrivate::calculateNewPosition(int from, int to, int index) const { if (index == from) return to; int start = qMin(from, to); int end = qMax(from, to); if (index >= start && index <= end) index += (from < to) ? -1 : 1; return index; } /*! Moves the item at index position \a from to index position \a to. \since 4.5 \sa tabMoved(), tabLayoutChange() */ void KCustomTabBar::moveTab(int from, int to) { Q_D(KCustomTabBar); if (from == to || !d->validIndex(from) || !d->validIndex(to)) return; bool vertical = verticalTabs(d->shape); int oldPressedPosition = 0; if (d->pressedIndex != -1) { // Record the position of the pressed tab before reordering the tabs. oldPressedPosition = vertical ? d->tabList[d->pressedIndex].rect.y() : d->tabList[d->pressedIndex].rect.x(); } // Update the locations of the tabs first int start = qMin(from, to); int end = qMax(from, to); int width = vertical ? d->tabList[from].rect.height() : d->tabList[from].rect.width(); if (from < to) width *= -1; bool rtl = isRightToLeft(); for (int i = start; i <= end; ++i) { if (i == from) continue; if (vertical) d->tabList[i].rect.moveTop(d->tabList[i].rect.y() + width); else d->tabList[i].rect.moveLeft(d->tabList[i].rect.x() + width); int direction = -1; if (rtl && !vertical) direction *= -1; if (d->tabList[i].dragOffset != 0) d->tabList[i].dragOffset += (direction * width); } if (vertical) { if (from < to) d->tabList[from].rect.moveTop(d->tabList[to].rect.bottom() + 1); else d->tabList[from].rect.moveTop(d->tabList[to].rect.top() - width); } else { if (from < to) d->tabList[from].rect.moveLeft(d->tabList[to].rect.right() + 1); else d->tabList[from].rect.moveLeft(d->tabList[to].rect.left() - width); } // Move the actual data structures d->tabList.move(from, to); // update lastTab locations for (int i = 0; i < d->tabList.count(); ++i) d->tabList[i].lastTab = d->calculateNewPosition(from, to, d->tabList[i].lastTab); // update external variables int previousIndex = d->currentIndex; d->currentIndex = d->calculateNewPosition(from, to, d->currentIndex); // If we are in the middle of a drag update the dragStartPosition if (d->pressedIndex != -1) { d->pressedIndex = d->calculateNewPosition(from, to, d->pressedIndex); int newPressedPosition = vertical ? d->tabList[d->pressedIndex].rect.top() : d->tabList[d->pressedIndex].rect.left(); int diff = oldPressedPosition - newPressedPosition; if (isRightToLeft() && !vertical) diff *= -1; if (vertical) d->dragStartPosition.setY(d->dragStartPosition.y() - diff); else d->dragStartPosition.setX(d->dragStartPosition.x() - diff); } d->layoutWidgets(start); update(); emit tabMoved(from, to); if (previousIndex != d->currentIndex) emit currentChanged(d->currentIndex); emit tabLayoutChange(); } void KCustomTabBarPrivate::slide(int from, int to) { Q_Q(KCustomTabBar); if (from == to || !validIndex(from) || !validIndex(to)) return; bool vertical = verticalTabs(shape); int preLocation = vertical ? q->tabRect(from).y() : q->tabRect(from).x(); q->setUpdatesEnabled(false); q->moveTab(from, to); q->setUpdatesEnabled(true); int postLocation = vertical ? q->tabRect(to).y() : q->tabRect(to).x(); int length = postLocation - preLocation; tabList[to].dragOffset -= length; tabList[to].startAnimation(this, ANIMATION_DURATION); } void KCustomTabBarPrivate::moveTab(int index, int offset) { if (!validIndex(index)) return; tabList[index].dragOffset = offset; layoutTab(index); // Make buttons follow tab q_func()->update(); } /*!\reimp */ void KCustomTabBar::mousePressEvent(QMouseEvent *event) { Q_D(KCustomTabBar); const QPoint pos = event->pos(); const bool isEventInCornerButtons = (!d->leftB->isHidden() && d->leftB->geometry().contains(pos)) || (!d->rightB->isHidden() && d->rightB->geometry().contains(pos)); if (!isEventInCornerButtons) { const int index = d->indexAtPos(pos); emit tabBarClicked(index); } if (event->button() != Qt::LeftButton) { event->ignore(); return; } // Be safe! if (d->pressedIndex != -1 && d->movable) d->moveTabFinished(d->pressedIndex); d->pressedIndex = d->indexAtPos(event->pos()); if (d->validIndex(d->pressedIndex)) { QStyleOptionTabBarBase optTabBase; optTabBase.initFrom(this); optTabBase.documentMode = d->documentMode; if (event->type() == style()->styleHint(QStyle::SH_TabBar_SelectMouseType, &optTabBase, this)) setCurrentIndex(d->pressedIndex); else repaint(tabRect(d->pressedIndex)); if (d->movable) { d->dragStartPosition = event->pos(); } } } /*!\reimp */ void KCustomTabBar::mouseMoveEvent(QMouseEvent *event) { Q_D(KCustomTabBar); if (d->movable) { // Be safe! if (d->pressedIndex != -1 && event->buttons() == Qt::NoButton) d->moveTabFinished(d->pressedIndex); // Start drag if (!d->dragInProgress && d->pressedIndex != -1) { if ((event->pos() - d->dragStartPosition).manhattanLength() > QApplication::startDragDistance()) { d->dragInProgress = true; d->setupMovableTab(); } } if (event->buttons() == Qt::LeftButton && d->dragInProgress && d->validIndex(d->pressedIndex)) { bool vertical = verticalTabs(d->shape); int dragDistance; if (vertical) { dragDistance = (event->pos().y() - d->dragStartPosition.y()); } else { dragDistance = (event->pos().x() - d->dragStartPosition.x()); } d->tabList[d->pressedIndex].dragOffset = dragDistance; QRect startingRect = tabRect(d->pressedIndex); if (vertical) startingRect.moveTop(startingRect.y() + dragDistance); else startingRect.moveLeft(startingRect.x() + dragDistance); int overIndex; if (dragDistance < 0) overIndex = tabAt(startingRect.topLeft()); else overIndex = tabAt(startingRect.topRight()); if (overIndex != d->pressedIndex && overIndex != -1) { int offset = 1; if (isRightToLeft() && !vertical) offset *= -1; if (dragDistance < 0) { dragDistance *= -1; offset *= -1; } for (int i = d->pressedIndex; offset > 0 ? i < overIndex : i > overIndex; i += offset) { QRect overIndexRect = tabRect(overIndex); int needsToBeOver = (vertical ? overIndexRect.height() : overIndexRect.width()) / 2; if (dragDistance > needsToBeOver) d->slide(i + offset, d->pressedIndex); } } // Buttons needs to follow the dragged tab d->layoutTab(d->pressedIndex); update(); } } if (event->buttons() != Qt::LeftButton) { event->ignore(); return; } } void KCustomTabBarPrivate::setupMovableTab() { Q_Q(KCustomTabBar); if (!movingTab) movingTab = new KCustomMovableTabWidget(q); int taboverlap = q->style()->pixelMetric(QStyle::PM_TabBarTabOverlap, 0, q); QRect grabRect = q->tabRect(pressedIndex); if (verticalTabs(shape)) grabRect.adjust(0, -taboverlap, 0, taboverlap); else grabRect.adjust(-taboverlap, 0, taboverlap, 0); QPixmap grabImage(grabRect.size() * q->devicePixelRatioF()); grabImage.setDevicePixelRatio(q->devicePixelRatioF()); grabImage.fill(Qt::transparent); QStylePainter p(&grabImage, q); QStyleOptionTab tab; q->initStyleOption(&tab, pressedIndex); tab.position = QStyleOptionTab::OnlyOneTab; if (verticalTabs(shape)) tab.rect.moveTopLeft(QPoint(0, taboverlap)); else tab.rect.moveTopLeft(QPoint(taboverlap, 0)); p.drawControl(QStyle::CE_TabBarTab, tab); p.end(); movingTab->setPixmap(grabImage); movingTab->setGeometry(grabRect); movingTab->raise(); // Re-arrange widget order to avoid overlaps if (tabList[pressedIndex].leftWidget) tabList[pressedIndex].leftWidget->raise(); if (tabList[pressedIndex].rightWidget) tabList[pressedIndex].rightWidget->raise(); if (leftB) leftB->raise(); if (rightB) rightB->raise(); movingTab->setVisible(true); } void KCustomTabBarPrivate::moveTabFinished(int index) { Q_Q(KCustomTabBar); bool cleanup = (pressedIndex == index) || (pressedIndex == -1) || !validIndex(index); bool allAnimationsFinished = true; #if QT_CONFIG(animation) for (int i = 0; allAnimationsFinished && i < tabList.count(); ++i) { const Tab &t = tabList.at(i); if (t.animation && t.animation->state() == QAbstractAnimation::Running) allAnimationsFinished = false; } #endif // animation if (allAnimationsFinished && cleanup) { if (movingTab) movingTab->setVisible(false); // We might not get a mouse release for (int i = 0; i < tabList.count(); ++i) { tabList[i].dragOffset = 0; } if (pressedIndex != -1 && movable) { pressedIndex = -1; dragInProgress = false; dragStartPosition = QPoint(); } layoutWidgets(); } else { if (!validIndex(index)) return; tabList[index].dragOffset = 0; } q->update(); } /*!\reimp */ void KCustomTabBar::mouseReleaseEvent(QMouseEvent *event) { Q_D(KCustomTabBar); if (event->button() != Qt::LeftButton) { event->ignore(); return; } if (d->movable && d->dragInProgress && d->validIndex(d->pressedIndex)) { int length = d->tabList[d->pressedIndex].dragOffset; int width = verticalTabs(d->shape) ? tabRect(d->pressedIndex).height() : tabRect(d->pressedIndex).width(); int duration = qMin(ANIMATION_DURATION, (qAbs(length) * ANIMATION_DURATION) / width); d->tabList[d->pressedIndex].startAnimation(d, duration); d->dragInProgress = false; d->movingTab->setVisible(false); d->dragStartPosition = QPoint(); } int i = d->indexAtPos(event->pos()) == d->pressedIndex ? d->pressedIndex : -1; d->pressedIndex = -1; QStyleOptionTabBarBase optTabBase; optTabBase.initFrom(this); optTabBase.documentMode = d->documentMode; const bool selectOnRelease = (style()->styleHint(QStyle::SH_TabBar_SelectMouseType, &optTabBase, this) == QEvent::MouseButtonRelease); if (selectOnRelease) setCurrentIndex(i); if (!selectOnRelease || !d->validIndex(i) || d->currentIndex == i) repaint(tabRect(i)); } /*!\reimp */ void KCustomTabBar::keyPressEvent(QKeyEvent *event) { Q_D(KCustomTabBar); if (event->key() != Qt::Key_Left && event->key() != Qt::Key_Right) { event->ignore(); return; } int offset = event->key() == (isRightToLeft() ? Qt::Key_Right : Qt::Key_Left) ? -1 : 1; d->setCurrentNextEnabledIndex(offset); } /*!\reimp */ #if QT_CONFIG(wheelevent) void KCustomTabBar::wheelEvent(QWheelEvent *event) { #ifndef Q_OS_MAC Q_D(KCustomTabBar); int offset = event->angleDelta().y() > 0 ? -1 : 1; d->setCurrentNextEnabledIndex(offset); QWidget::wheelEvent(event); #else Q_UNUSED(event) #endif } #endif // QT_CONFIG(wheelevent) void KCustomTabBarPrivate::setCurrentNextEnabledIndex(int offset) { Q_Q(KCustomTabBar); for (int index = currentIndex + offset; validIndex(index); index += offset) { if (tabList.at(index).enabled) { q->setCurrentIndex(index); break; } } } /*!\reimp */ void KCustomTabBar::changeEvent(QEvent *event) { Q_D(KCustomTabBar); switch (event->type()) { case QEvent::StyleChange: if (!d->elideModeSetByUser) d->elideMode = Qt::TextElideMode(style()->styleHint(QStyle::SH_TabBar_ElideMode, 0, this)); if (!d->useScrollButtonsSetByUser) d->useScrollButtons = !style()->styleHint(QStyle::SH_TabBar_PreferNoArrows, 0, this); Q_FALLTHROUGH(); case QEvent::FontChange: d->textSizes.clear(); d->refresh(); break; default: break; } QWidget::changeEvent(event); } /*! \reimp */ void KCustomTabBar::timerEvent(QTimerEvent *event) { Q_D(KCustomTabBar); if (event->timerId() == d->switchTabTimerId) { killTimer(d->switchTabTimerId); d->switchTabTimerId = 0; setCurrentIndex(d->switchTabCurrentIndex); d->switchTabCurrentIndex = -1; } QWidget::timerEvent(event); } /*! \property KCustomTabBar::elideMode \brief how to elide text in the tab bar \since 4.2 This property controls how items are elided when there is not enough space to show them for a given tab bar size. By default the value is style dependent. \sa QTabWidget::elideMode, usesScrollButtons, QStyle::SH_TabBar_ElideMode */ Qt::TextElideMode KCustomTabBar::elideMode() const { Q_D(const KCustomTabBar); return d->elideMode; } void KCustomTabBar::setElideMode(Qt::TextElideMode mode) { Q_D(KCustomTabBar); d->elideMode = mode; d->elideModeSetByUser = true; d->textSizes.clear(); d->refresh(); } /*! \property KCustomTabBar::usesScrollButtons \brief Whether or not a tab bar should use buttons to scroll tabs when it has many tabs. \since 4.2 When there are too many tabs in a tab bar for its size, the tab bar can either choose to expand its size or to add buttons that allow you to scroll through the tabs. By default the value is style dependant. \sa elideMode, QTabWidget::usesScrollButtons, QStyle::SH_TabBar_PreferNoArrows */ bool KCustomTabBar::usesScrollButtons() const { return d_func()->useScrollButtons; } void KCustomTabBar::setUsesScrollButtons(bool useButtons) { Q_D(KCustomTabBar); d->useScrollButtonsSetByUser = true; if (d->useScrollButtons == useButtons) return; d->useScrollButtons = useButtons; d->refresh(); } /*! \property KCustomTabBar::tabsClosable \brief Whether or not a tab bar should place close buttons on each tab \since 4.5 When tabsClosable is set to true a close button will appear on the tab on either the left or right hand side depending upon the style. When the button is clicked the tab the signal tabCloseRequested will be emitted. By default the value is false. \sa setTabButton(), tabRemoved() */ bool KCustomTabBar::tabsClosable() const { Q_D(const KCustomTabBar); return d->closeButtonOnTabs; } void KCustomTabBar::setTabsClosable(bool closable) { Q_D(KCustomTabBar); if (d->closeButtonOnTabs == closable) return; d->closeButtonOnTabs = closable; ButtonPosition closeSide = (ButtonPosition)style()->styleHint(QStyle::SH_TabBar_CloseButtonPosition, 0, this); if (!closable) { for (int i = 0; i < d->tabList.count(); ++i) { if (closeSide == LeftSide && d->tabList[i].leftWidget) { d->tabList[i].leftWidget->deleteLater(); d->tabList[i].leftWidget = 0; } if (closeSide == RightSide && d->tabList[i].rightWidget) { d->tabList[i].rightWidget->deleteLater(); d->tabList[i].rightWidget = 0; } } } else { bool newButtons = false; for (int i = 0; i < d->tabList.count(); ++i) { if (tabButton(i, closeSide)) continue; newButtons = true; QAbstractButton *closeButton = new CloseButton(this); // connect(closeButton, SIGNAL(clicked()), this, SLOT(_q_closeTab())); connect(closeButton, &QAbstractButton::clicked, this, [=] { closeTab(); }); setTabButton(i, closeSide, closeButton); } if (newButtons) d->layoutTabs(); } update(); } /*! \enum KCustomTabBar::ButtonPosition \since 4.5 This enum type lists the location of the widget on a tab. \value LeftSide Left side of the tab. \value RightSide Right side of the tab. */ /*! \enum KCustomTabBar::SelectionBehavior \since 4.5 This enum type lists the behavior of KCustomTabBar when a tab is removed and the tab being removed is also the current tab. \value SelectLeftTab Select the tab to the left of the one being removed. \value SelectRightTab Select the tab to the right of the one being removed. \value SelectPreviousTab Select the previously selected tab. */ /*! \property KCustomTabBar::selectionBehaviorOnRemove \brief What tab should be set as current when removeTab is called if the removed tab is also the current tab. \since 4.5 By default the value is SelectRightTab. \sa removeTab() */ KCustomTabBar::SelectionBehavior KCustomTabBar::selectionBehaviorOnRemove() const { Q_D(const KCustomTabBar); return d->selectionBehaviorOnRemove; } void KCustomTabBar::setSelectionBehaviorOnRemove(KCustomTabBar::SelectionBehavior behavior) { Q_D(KCustomTabBar); d->selectionBehaviorOnRemove = behavior; } /*! \property KCustomTabBar::expanding \brief When expanding is true KCustomTabBar will expand the tabs to use the empty space. \since 4.5 By default the value is true. \sa QTabWidget::documentMode */ bool KCustomTabBar::expanding() const { Q_D(const KCustomTabBar); return d->expanding; } void KCustomTabBar::setExpanding(bool enabled) { Q_D(KCustomTabBar); if (d->expanding == enabled) return; d->expanding = enabled; d->layoutTabs(); } /*! \property KCustomTabBar::movable \brief This property holds whether the user can move the tabs within the tabbar area. \since 4.5 By default, this property is \c false; */ bool KCustomTabBar::isMovable() const { Q_D(const KCustomTabBar); return d->movable; } void KCustomTabBar::setMovable(bool movable) { Q_D(KCustomTabBar); d->movable = movable; } /*! \property KCustomTabBar::documentMode \brief Whether or not the tab bar is rendered in a mode suitable for the main window. \since 4.5 This property is used as a hint for styles to draw the tabs in a different way then they would normally look in a tab widget. On \macos this will look similar to the tabs in Safari or Sierra's Terminal.app. \sa QTabWidget::documentMode */ bool KCustomTabBar::documentMode() const { return d_func()->documentMode; } void KCustomTabBar::setDocumentMode(bool enabled) { Q_D(KCustomTabBar); d->documentMode = enabled; d->updateMacBorderMetrics(); } /*! \property KCustomTabBar::autoHide \brief If true, the tab bar is automatically hidden when it contains less than 2 tabs. \since 5.4 By default, this property is false. \sa QWidget::visible */ bool KCustomTabBar::autoHide() const { Q_D(const KCustomTabBar); return d->autoHide; } void KCustomTabBar::setAutoHide(bool hide) { Q_D(KCustomTabBar); if (d->autoHide == hide) return; d->autoHide = hide; if (hide) d->autoHideTabs(); else setVisible(true); } /*! \property KCustomTabBar::changeCurrentOnDrag \brief If true, then the current tab is automatically changed when dragging over the tabbar. \since 5.4 \note You should also set acceptDrops property to true to make this feature work. By default, this property is false. */ bool KCustomTabBar::changeCurrentOnDrag() const { Q_D(const KCustomTabBar); return d->changeCurrentOnDrag; } void KCustomTabBar::setChangeCurrentOnDrag(bool change) { Q_D(KCustomTabBar); d->changeCurrentOnDrag = change; if (!change) d->killSwitchTabTimer(); } /*! Sets \a widget on the tab \a index. The widget is placed on the left or right hand side depending upon the \a position. \since 4.5 Any previously set widget in \a position is hidden. The tab bar will take ownership of the widget and so all widgets set here will be deleted by the tab bar when it is destroyed unless you separately reparent the widget after setting some other widget (or 0). \sa tabsClosable() */ void KCustomTabBar::setTabButton(int index, ButtonPosition position, QWidget *widget) { Q_D(KCustomTabBar); if (index < 0 || index >= d->tabList.count()) return; if (widget) { widget->setParent(this); // make sure our left and right widgets stay on top widget->lower(); widget->show(); } if (position == LeftSide) { if (d->tabList[index].leftWidget) d->tabList[index].leftWidget->hide(); d->tabList[index].leftWidget = widget; } else { if (d->tabList[index].rightWidget) d->tabList[index].rightWidget->hide(); d->tabList[index].rightWidget = widget; } d->layoutTabs(); d->refresh(); update(); } /*! Returns the widget set a tab \a index and \a position or 0 if one is not set. */ QWidget *KCustomTabBar::tabButton(int index, ButtonPosition position) const { Q_D(const KCustomTabBar); if (index < 0 || index >= d->tabList.count()) return 0; if (position == LeftSide) return d->tabList.at(index).leftWidget; else return d->tabList.at(index).rightWidget; } #ifndef QT_NO_ACCESSIBILITY /*! Sets the accessibleName of the tab at position \a index to \a name. */ void KCustomTabBar::setAccessibleTabName(int index, const QString &name) { Q_D(KCustomTabBar); if (KCustomTabBarPrivate::Tab *tab = d->at(index)) { tab->accessibleName = name; QAccessibleEvent event(this, QAccessible::NameChanged); event.setChild(index); QAccessible::updateAccessibility(&event); } } /*! Returns the accessibleName of the tab at position \a index, or an empty string if \a index is out of range. */ QString KCustomTabBar::accessibleTabName(int index) const { Q_D(const KCustomTabBar); if (const KCustomTabBarPrivate::Tab *tab = d->at(index)) return tab->accessibleName; return QString(); } #endif // QT_NO_ACCESSIBILITY CloseButton::CloseButton(QWidget *parent) : QAbstractButton(parent) { setFocusPolicy(Qt::NoFocus); #ifndef QT_NO_CURSOR setCursor(Qt::ArrowCursor); #endif #ifndef QT_NO_TOOLTIP setToolTip(tr("Close Tab")); #endif resize(sizeHint()); } QSize CloseButton::sizeHint() const { ensurePolished(); int width = style()->pixelMetric(QStyle::PM_TabCloseIndicatorWidth, 0, this); int height = style()->pixelMetric(QStyle::PM_TabCloseIndicatorHeight, 0, this); return QSize(width, height); } QSize CloseButton::minimumSizeHint() const { return sizeHint(); } void CloseButton::enterEvent(QEnterEvent *event) { if (isEnabled()) update(); QAbstractButton::enterEvent(event); } void CloseButton::leaveEvent(QEvent *event) { if (isEnabled()) update(); QAbstractButton::leaveEvent(event); } void CloseButton::paintEvent(QPaintEvent *) { QPainter p(this); QStyleOption opt; opt.initFrom(this); opt.state |= QStyle::State_AutoRaise; if (isEnabled() && underMouse() && !isChecked() && !isDown()) opt.state |= QStyle::State_Raised; if (isChecked()) opt.state |= QStyle::State_On; if (isDown()) opt.state |= QStyle::State_Sunken; if (const KCustomTabBar *tb = qobject_cast(parent())) { int index = tb->currentIndex(); KCustomTabBar::ButtonPosition position = (KCustomTabBar::ButtonPosition)style()->styleHint(QStyle::SH_TabBar_CloseButtonPosition, 0, tb); if (tb->tabButton(index, position) == this) opt.state |= QStyle::State_Selected; } style()->drawPrimitive(QStyle::PE_IndicatorTabClose, &opt, &p, this); } #if QT_CONFIG(animation) void KCustomTabBarPrivate::Tab::TabBarAnimation::updateCurrentValue(const QVariant ¤t) { priv->moveTab(priv->tabList.indexOf(*tab), current.toInt()); } void KCustomTabBarPrivate::Tab::TabBarAnimation::updateState(QAbstractAnimation::State newState, QAbstractAnimation::State) { if (newState == Stopped) priv->moveTabFinished(priv->tabList.indexOf(*tab)); } #endif QT_END_NAMESPACE #include "kcustomtabbar.moc" #include "moc_kcustomtabbar.cpp" libkysdk-applications/kysdk-qtwidgets/src/klistwidget.cpp0000664000175000017500000000464215104543305022771 0ustar fengfeng/* * libkysdk-qtwidgets's Library * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhenyu Wang * */ #include "klistwidget.h" #include namespace kdk { class KListWidgetPrivate : public QObject { Q_OBJECT Q_DECLARE_PUBLIC(KListWidget) public: KListWidgetPrivate(KListWidget *parent); private: KListWidget *q_ptr; QListWidgetItem *item; QListWidgetItem *m_item; }; KListWidgetPrivate::KListWidgetPrivate(KListWidget *parent) : q_ptr(parent) { Q_Q(KListWidget); setParent(parent); } KListWidget::KListWidget(QWidget *parent) : d_ptr(new KListWidgetPrivate(this)) { Q_D(KListWidget); } void KListWidget::AddItemWidget(KItemWidget *m_itemwidget) { Q_D(KListWidget); if (!m_itemwidget) return; d->item = new QListWidgetItem(this); d->item->setSizeHint(QSize(this->width(), 54)); this->setItemWidget(d->item, m_itemwidget); // 建立连接 connect(this, &KListWidget::itemClicked, this, [=](QListWidgetItem *current) { KItemWidget *curWidget = dynamic_cast(this->itemWidget(current)); if (curWidget) curWidget->SetInverse(); }); connect(this, &KListWidget::currentItemChanged, this, [=](QListWidgetItem *current, QListWidgetItem *previous) { KItemWidget *curWidget = dynamic_cast(this->itemWidget(current)); KItemWidget *preWidget = dynamic_cast(this->itemWidget(previous)); if (curWidget && !preWidget) { curWidget->CancelInverse(); } else if (curWidget) { curWidget->SetInverse(); } if (preWidget) { preWidget->CancelInverse(); } }); } } #include "klistwidget.moc" #include "moc_klistwidget.cpp" libkysdk-applications/kysdk-qtwidgets/src/kintrowidget.h0000664000175000017500000000437115104543305022615 0ustar fengfeng/* * libkysdk-qtwidgets's Library * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhenyu Wang * */ #ifndef KINTROWIDGET_H #define KINTROWIDGET_H #include "gui_g.h" #include namespace kdk { enum ViewType { IconView, ListView }; /** * @defgroup FrameModule * @since 2.5.2.0 */ class KIntroWidgetPrivate; class GUI_EXPORT KIntroWidget : public QWidget { Q_OBJECT public: KIntroWidget(QWidget *parent = nullptr); /** * @brief 设置视图样式 * @param type */ void setViewType(ViewType type); /** * @brief 设置主文本 * @param str */ void setMainLabel(QString str); /** * @brief 设置次级文本 * @param str */ void setSubLabel(QString str); /** * @brief 设置圆角 * @param radius */ void setBorderRadius(int radius); /** * @brief 设置圆角 * @param bottomLeft * @param topLeft * @param topRight * @param bottomRight */ void setBorderRadius(int bottomLeft, int topLeft, int topRight, int bottomRight); /** * @brief 设置标题颜色 * @param color */ void setTitleColor(QColor color); Q_SIGNALS: void rightClick(QPoint point); protected: void paintEvent(QPaintEvent *event); bool eventFilter(QObject *watched, QEvent *event); QSize sizeHint() const override; void mousePressEvent(QMouseEvent *event); void mouseReleaseEvent(QMouseEvent *event); private: Q_DECLARE_PRIVATE(KIntroWidget) KIntroWidgetPrivate *const d_ptr; }; } #endif // KINTROWIDGET_H libkysdk-applications/kysdk-qtwidgets/src/ktablemodel.h0000664000175000017500000000245715104543305022371 0ustar fengfeng/* * libkysdk-qtwidgets's Library * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhenyu Wang * */ #ifndef KTABLEMODEL_H #define KTABLEMODEL_H #include namespace kdk { /** * @brief 重置标题 * @since 2.5.2.0 */ class KTableModelPrivate; class KTableModel : public QStandardItemModel { Q_OBJECT public: explicit KTableModel(QObject *parent = nullptr); protected: QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override; private: Q_DECLARE_PRIVATE(KTableModel) KTableModelPrivate *const d_ptr; }; } #endif // KTABLEMODEL_H libkysdk-applications/kysdk-qtwidgets/src/kaddfilebutton.cpp0000664000175000017500000001536015104543305023435 0ustar fengfeng/* * libkysdk-qtwidgets's Library * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhenyu Wang * */ #include "kaddfilebutton.h" #include "themeController.h" #include #include #include #include #include #include #include #include "accessinfohelper.h" namespace kdk { #define BLANK_SPACE 20 class AddFileDialog : public QFileDialog { Q_OBJECT public: AddFileDialog(QWidget *parent = nullptr); virtual ~AddFileDialog(); public slots: void goAccept(); protected: void showEvent(QShowEvent *event) override; }; class KAddFileButtonPrivate : public QObject, public ThemeController { Q_DECLARE_PUBLIC(KAddFileButton) Q_OBJECT public: KAddFileButtonPrivate(KAddFileButton *parent); void updateColor(QStyleOptionButton option, QPalette palette); void openFile(); protected: void changeTheme(); private: KAddFileButton *q_ptr; QColor m_bkgColor; QString m_text; QRect m_rect; QRect m_textRect; AddFileDialog *m_FileDialog; }; KAddFileButton::KAddFileButton(QWidget *parent) : QPushButton(parent) , d_ptr(new KAddFileButtonPrivate(this)) { Q_D(KAddFileButton); setFixedSize(104, 110); connect(this, &KAddFileButton::clicked, this, [=] { d->openFile(); }); } void KAddFileButton::paintEvent(QPaintEvent *event) { Q_D(KAddFileButton); QStyleOptionButton option; initStyleOption(&option); d->updateColor(option, palette()); d->m_rect = QRect(QPoint(20, 8), QSize(64, 64)); QPainter painter(this); painter.save(); painter.setBrush(ThemeController::getCustomColorFromDT("base-active")); painter.setPen(Qt::NoPen); painter.drawRoundedRect(rect(), 0, 0); painter.restore(); QPen pen = painter.pen(); pen.setStyle(Qt::DashLine); pen.setColor(ThemeController::getCustomColorFromDT("highlight-active")); painter.save(); painter.setRenderHint(QPainter::Antialiasing); painter.setPen(pen); painter.setBrush(d->m_bkgColor); int radius = ThemeController::getRadiusFromDT("kradius-normal"); if (radius == -1) radius = 6; painter.drawRoundedRect(d->m_rect, radius, radius); painter.setPen(ThemeController::getCustomColorFromDT("highlight-active")); painter.drawLine(QPoint(d->m_rect.center().x() - 10, d->m_rect.center().y() + 1), QPoint(d->m_rect.center().x() + 10, d->m_rect.center().y() + 1)); painter.drawLine(QPoint(d->m_rect.center().x() + 1, d->m_rect.center().y() - 10), QPoint(d->m_rect.center().x() + 1, d->m_rect.center().y() + 10)); painter.restore(); painter.save(); QFontMetrics fm = painter.fontMetrics(); int width = fm.horizontalAdvance(d->m_text); painter.setPen(ThemeController::getCustomColorFromDT("highlight-active")); d->m_textRect = QRect(QPoint(rect().center().x() - width / 2, d->m_rect.bottom() + 8), QSize(width, fm.height())); painter.drawText(d->m_textRect, d->m_text); painter.restore(); } bool KAddFileButton::eventFilter(QObject *watched, QEvent *event) { return QPushButton::eventFilter(watched, event); } void KAddFileButton::mouseMoveEvent(QMouseEvent *event) { return QPushButton::mouseMoveEvent(event); } void KAddFileButton::mousePressEvent(QMouseEvent *event) { return QPushButton::mousePressEvent(event); } void KAddFileButton::mouseReleaseEvent(QMouseEvent *event) { return QPushButton::mouseReleaseEvent(event); } void KAddFileButton::setText(QString str) { Q_D(KAddFileButton); d->m_text = str; } QFileDialog *KAddFileButton::fileDialog() { Q_D(KAddFileButton); return dynamic_cast(d->m_FileDialog); } void KAddFileButton::setNameFilter(const QString &filter) { Q_D(KAddFileButton); QString f(filter); if (f.isEmpty()) return; QString sep(QLatin1String(";;")); int i = f.indexOf(sep, 0); if (i == -1) { if (f.indexOf(QLatin1Char('\n'), 0) != -1) { sep = QLatin1Char('\n'); i = f.indexOf(sep, 0); } } setNameFilters(f.split(sep)); } void KAddFileButton::setNameFilters(const QStringList &filters) { Q_D(KAddFileButton); d->m_FileDialog->setNameFilters(filters); } KAddFileButtonPrivate::KAddFileButtonPrivate(KAddFileButton *parent) : q_ptr(parent) , m_text("添加文件") { Q_Q(KAddFileButton); m_FileDialog = new AddFileDialog(q); m_FileDialog->setDirectory(QStandardPaths::writableLocation(QStandardPaths::HomeLocation)); m_FileDialog->setFileMode(QFileDialog::ExistingFiles); KDK_ALL_INFO_FORMAT(m_FileDialog,""); } void KAddFileButtonPrivate::updateColor(QStyleOptionButton option, QPalette palette) { Q_Q(KAddFileButton); m_bkgColor = ThemeController::getCustomColorFromDT("base-active"); QColor hightColor = ThemeController::getCustomColorFromDT("highlight-active"); if (option.state.testFlag(QStyle::State_MouseOver)) { m_bkgColor = hightColor; if (option.state.testFlag(QStyle::State_Sunken)) m_bkgColor.setAlphaF(0.4); else m_bkgColor.setAlphaF(0.3); } } void KAddFileButtonPrivate::openFile() { Q_Q(KAddFileButton); m_FileDialog->setWindowTitle(tr("Please select file")); m_FileDialog->exec(); } void KAddFileButtonPrivate::changeTheme() { initThemeStyle(); } AddFileDialog::AddFileDialog(QWidget *parent) { this->setFileMode(QFileDialog::ExistingFiles); } AddFileDialog::~AddFileDialog() { } void AddFileDialog::goAccept() { accept(); } void AddFileDialog::showEvent(QShowEvent *event) { if (this->isVisible()) { for (QWidget *widget : this->findChildren()) { if (widget->objectName() == "acceptButton") { QPushButton *btn = qobject_cast(widget); disconnect(btn, &QPushButton::clicked, 0, 0); connect(btn, &QPushButton::clicked, [=](bool checked) { Q_UNUSED(checked) this->goAccept(); }); } } } } } #include "kaddfilebutton.moc" #include "moc_kaddfilebutton.cpp" libkysdk-applications/kysdk-qtwidgets/src/kuninstalldialog.cpp0000664000175000017500000003034015104543305023775 0ustar fengfeng/* * libkysdk-qtwidgets's Library * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #include "kuninstalldialog.h" #include #include #include #include #include #include #include #include #include #include "accessinfohelper.h" namespace kdk { class KUninstallDialogPrivate : public QObject { Q_DECLARE_PUBLIC(KUninstallDialog) Q_OBJECT public: KUninstallDialogPrivate(KUninstallDialog *parent); QString getIconPath(QString appName); QString setLabelStringBody(QString text, QLabel *lable); QString getAppCnName(QString appName); void resetAppInfo(QString appName, QString appVersion); void fontGsettingInit(); void setLabelText(); void setAccessInfo(); private: KUninstallDialog *q_ptr; QString m_appName; QString m_appVersion; QVBoxLayout *debInfoLayout; QWidget *IconAndAppNameWidget; QHBoxLayout *IconAndAppNameLayout; QWidget *debNameAndVersionWidget; QHBoxLayout *debNameAndVersionLayout; QWidget *nameVersionWidget; QVBoxLayout *nameVersionVLayout; QGSettings *m_pGsettingFontSize; QLabel *debIconLabel; QLabel *debAppNameLabel; QLabel *debNameLabel; QLabel *debVersionLabel; QPushButton *m_pUninstallBtn; }; KUninstallDialog::~KUninstallDialog() { } QLabel *KUninstallDialog::debAppNameLabel() { Q_D(KUninstallDialog); return d->debAppNameLabel; } QLabel *KUninstallDialog::debNameLabel() { Q_D(KUninstallDialog); return d->debNameLabel; } QLabel *KUninstallDialog::debIconLabel() { Q_D(KUninstallDialog); return d->debIconLabel; } QLabel *KUninstallDialog::debVersionLabel() { Q_D(KUninstallDialog); return d->debVersionLabel; } QPushButton *KUninstallDialog::uninstallButtton() { Q_D(KUninstallDialog); return d->m_pUninstallBtn; } void KUninstallDialog::changeTheme() { KDialog::changeTheme(); if (ThemeController::themeMode() == LightTheme) { // to do 还没有具体的设计图 只有截图 } else { // to do 还没有具体的设计图 只有截图 } } KUninstallDialog::KUninstallDialog(QString appName, QString appVersion, QWidget *parent) : KDialog(parent) , d_ptr(new KUninstallDialogPrivate(this)) { Q_D(KUninstallDialog); d->m_appName = appName; d->m_appVersion = appVersion; setWindowTitle(tr("uninstall")); this->setFixedSize(550, 450); d->debInfoLayout = new QVBoxLayout(); d->debInfoLayout->setContentsMargins(0, 0, 0, 0); d->IconAndAppNameWidget = new QWidget(); d->IconAndAppNameWidget->setContentsMargins(0, 0, 0, 0); d->IconAndAppNameLayout = new QHBoxLayout(); d->IconAndAppNameLayout->setContentsMargins(0, 0, 0, 0); d->IconAndAppNameLayout->setSpacing(0); d->debIconLabel = new QLabel(); d->debIconLabel->setFixedSize(48, 48); /*先判断主题中是否有icon*/ if (QIcon::fromTheme(d->m_appName).isNull()) { QPixmap pixmap = QPixmap(d->getIconPath(d->m_appName)); pixmap.scaled(QSize(48, 48), Qt::KeepAspectRatio); d->debIconLabel->setPixmap(QIcon(QPixmap(d->getIconPath(d->m_appName))).pixmap(QSize(48, 48))); setWindowIcon(QIcon(QPixmap(d->getIconPath(d->m_appName))).pixmap(QSize(24, 24))); } else { d->debIconLabel->setPixmap(QIcon::fromTheme(d->m_appName).pixmap(QSize(48, 48))); setWindowIcon(QIcon::fromTheme(d->m_appName).pixmap(QSize(24, 24))); } d->debIconLabel->adjustSize(); d->fontGsettingInit(); d->debAppNameLabel = new QLabel(); QFont font2 = d->debAppNameLabel->font(); if (d->m_pGsettingFontSize != nullptr && d->m_pGsettingFontSize->keys().contains(GSETTING_FONT_KEY)) font2.setPixelSize(d->m_pGsettingFontSize->get(GSETTING_FONT_KEY).toInt() * 2.5); d->debAppNameLabel->setFont(font2); d->debAppNameLabel->setFixedWidth(331); QLocale locale; if (locale.language() == QLocale::Chinese) { if (d->getAppCnName(d->m_appName).isNull()) { d->debAppNameLabel->setText(d->setLabelStringBody(d->m_appName, d->debAppNameLabel)); } else { d->debAppNameLabel->setText(d->setLabelStringBody(d->getAppCnName(d->m_appName), d->debAppNameLabel)); } } else { d->debAppNameLabel->setText(d->setLabelStringBody(d->m_appName, d->debAppNameLabel)); } d->debAppNameLabel->adjustSize(); d->IconAndAppNameLayout->addItem(new QSpacerItem(124, 10, QSizePolicy::Fixed)); d->IconAndAppNameLayout->addWidget(d->debIconLabel); d->IconAndAppNameLayout->addItem(new QSpacerItem(12, 10, QSizePolicy::Fixed)); d->IconAndAppNameLayout->addWidget(d->debAppNameLabel); d->IconAndAppNameLayout->addItem(new QSpacerItem(400, 10, QSizePolicy::Expanding)); d->IconAndAppNameWidget->setLayout(d->IconAndAppNameLayout); d->debNameAndVersionWidget = new QWidget(); d->debNameAndVersionLayout = new QHBoxLayout(); d->debNameAndVersionLayout->setContentsMargins(0, 0, 0, 0); d->debNameAndVersionLayout->setSpacing(0); d->debNameLabel = new QLabel(); QString debName = tr("deb name:"); debName.append(appName); d->debNameLabel->setText(debName); d->debNameLabel->adjustSize(); d->debVersionLabel = new QLabel(); QString debVersion = tr("deb version:"); debVersion.append(appVersion); d->debVersionLabel->setText(debVersion); d->debVersionLabel->adjustSize(); if (d->debVersionLabel->width() > 329) { d->debVersionLabel->setText(debVersion.left(20) + "..."); d->debVersionLabel->setToolTip(debVersion); } d->nameVersionWidget = new QWidget(); d->nameVersionVLayout = new QVBoxLayout(); d->nameVersionVLayout->setContentsMargins(0, 0, 0, 0); d->nameVersionVLayout->addWidget(d->debNameLabel); d->nameVersionVLayout->addWidget(d->debVersionLabel); d->nameVersionVLayout->setSpacing(0); d->nameVersionWidget->setLayout(d->nameVersionVLayout); d->debNameAndVersionLayout->addItem(new QSpacerItem(184, 10, QSizePolicy::Fixed)); d->debNameAndVersionLayout->addWidget(d->nameVersionWidget); d->debNameAndVersionLayout->addItem(new QSpacerItem(330, 10, QSizePolicy::Expanding)); d->debNameAndVersionWidget->setLayout(d->debNameAndVersionLayout); d->debInfoLayout->addStretch(); d->debInfoLayout->addWidget(d->IconAndAppNameWidget); d->debInfoLayout->addWidget(d->debNameAndVersionWidget); d->debInfoLayout->addSpacing(25); d->m_pUninstallBtn = new QPushButton(tr("uninstall"), this); d->m_pUninstallBtn->setFixedSize(122, 40); QWidget *pBtnWidget = new QWidget(); QHBoxLayout *hLayout = new QHBoxLayout(); hLayout->addItem(new QSpacerItem(184, 10, QSizePolicy::Fixed)); hLayout->addWidget(d->m_pUninstallBtn); hLayout->addStretch(); pBtnWidget->setLayout(hLayout); d->debInfoLayout->addWidget(pBtnWidget); d->debInfoLayout->addStretch(); mainWidget()->setLayout(d->debInfoLayout); changeTheme(); d->setAccessInfo(); } KUninstallDialogPrivate::KUninstallDialogPrivate(KUninstallDialog *parent) : q_ptr(parent) { setParent(parent); } QString KUninstallDialogPrivate::getIconPath(QString appName) { QString iconFilePath; /*cr判断~/.cache/icons下是否有icon*/ iconFilePath.clear(); iconFilePath = QStandardPaths::writableLocation(QStandardPaths::HomeLocation) + "/.cache/uksc/icons/" + appName + ".png"; if (QFile::exists(iconFilePath)) { return iconFilePath; } /*最后判断/usr/share/ubuntu-kylin-software-center/data/icons下面是否有*/ iconFilePath.clear(); iconFilePath = "/usr/share/kylin-software-center/data/icons/" + appName + ".png"; if (QFile::exists(iconFilePath)) { return iconFilePath; } return nullptr; } QString KUninstallDialogPrivate::setLabelStringBody(QString text, QLabel *lable) { QFontMetrics fontMetrics(lable->font()); int LableWidth = lable->width(); int fontSize = fontMetrics.horizontalAdvance(text); QString formatBody = text; if (fontSize > (LableWidth - 10)) { formatBody = fontMetrics.elidedText(formatBody, Qt::ElideRight, LableWidth - 10); return formatBody; } return formatBody; } QString KUninstallDialogPrivate::getAppCnName(QString appName) { QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE"); db.setDatabaseName(QStandardPaths::writableLocation(QStandardPaths::HomeLocation) + "/.cache/uksc/uksc.db"); if (!db.open()) { return nullptr; } QSqlQuery query; query.exec(QString("SELECT * FROM application WHERE app_name IS '%1'").arg(appName)); // 执行 while (query.next()) { return query.value(4).toString(); } db.close(); return nullptr; } void KUninstallDialogPrivate::resetAppInfo(QString appName, QString appVersion) { Q_Q(KUninstallDialog); m_appName = appName; m_appVersion = appVersion; /*先判断主题中是否有icon*/ if (QIcon::fromTheme(m_appName).isNull()) { QPixmap pixmap = QPixmap(getIconPath(m_appName)); pixmap.scaled(QSize(48, 48), Qt::KeepAspectRatio); debIconLabel->setPixmap(QIcon(QPixmap(getIconPath(m_appName))).pixmap(QSize(48, 48))); } else { debIconLabel->setPixmap(QIcon::fromTheme(m_appName).pixmap(QSize(48, 48))); } if (getAppCnName(m_appName).isNull()) debAppNameLabel->setText(m_appName); else debAppNameLabel->setText(getAppCnName(m_appName)); QString debName = tr("deb name:"); debName.append(appName); debNameLabel->setText(debName); QString debVersion = tr("deb version:"); debVersion.append(appVersion); debVersionLabel->setText(debVersion); debVersionLabel->adjustSize(); if (debVersionLabel->width() > 329) { debVersionLabel->setText(debVersion.left(20) + "..."); debVersionLabel->setToolTip(debVersion); } } void KUninstallDialogPrivate::fontGsettingInit() { Q_Q(KUninstallDialog); m_pGsettingFontSize = nullptr; const QByteArray style_id(ORG_UKUI_STYLE_FONT); if (QGSettings::isSchemaInstalled(style_id)) { m_pGsettingFontSize = new QGSettings(style_id); connect(m_pGsettingFontSize, &QGSettings::changed, this, [=](const QString &key) { if (key == GSETTING_FONT_KEY) { setLabelText(); } }); } } void KUninstallDialogPrivate::setLabelText() { Q_Q(KUninstallDialog); QFont font; if (m_pGsettingFontSize != nullptr && m_pGsettingFontSize->keys().contains(GSETTING_FONT_KEY)) font.setPixelSize(m_pGsettingFontSize->get(GSETTING_FONT_KEY).toDouble() * 2.5); debAppNameLabel->setFont(font); QLocale locale; if (locale.language() == QLocale::Chinese) { if (getAppCnName(m_appName).isNull()) { q->setWindowTitle(setLabelStringBody(m_appName, debAppNameLabel)); } else { q->setWindowTitle(setLabelStringBody(getAppCnName(m_appName), debAppNameLabel)); } } else { q->setWindowTitle(setLabelStringBody(m_appName, debAppNameLabel)); } } void KUninstallDialogPrivate::setAccessInfo() { Q_Q(KUninstallDialog); KDK_ALL_INFO_FORMAT(IconAndAppNameWidget,""); KDK_ALL_INFO_FORMAT(debNameAndVersionWidget,""); KDK_ALL_INFO_FORMAT(nameVersionWidget,""); if (m_pGsettingFontSize) KDK_OBJ_INFO_FORMAT(m_pGsettingFontSize); KDK_ALL_INFO_FORMAT(debIconLabel,""); KDK_ALL_INFO_FORMAT(debAppNameLabel,""); KDK_ALL_INFO_FORMAT(debNameLabel,""); KDK_ALL_INFO_FORMAT(debVersionLabel,""); KDK_ALL_INFO_FORMAT(m_pUninstallBtn,""); } } #include "kuninstalldialog.moc"; #include "moc_kuninstalldialog.cpp"; libkysdk-applications/kysdk-qtwidgets/src/ksliderframe.cpp0000664000175000017500000000551515104543305023107 0ustar fengfeng/* * * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Sisheng He * */ #include "ksliderframe.h" #include namespace kdk { class KSliderFramePrivate : public QObject { Q_OBJECT Q_DECLARE_PUBLIC(KSliderFrame) public: KSliderFramePrivate(KSliderFrame *parent); private: KSliderFrame *q_ptr; KSlider *m_pSlider; QLabel *m_pLeftLabel; QLabel *m_pRightLabel; KLabel *m_pSettingName; QHBoxLayout *m_pMainLayout; }; KSliderFramePrivate::KSliderFramePrivate(KSliderFrame *parent) : q_ptr(parent) { Q_Q(KSliderFrame); m_pSettingName = new KLabel(q); m_pSettingName->setFixedWidth(SETTING_LABEL_WIDTH); m_pSlider = new KSlider(q); m_pLeftLabel = new QLabel(q); m_pLeftLabel->setAlignment(Qt::AlignVCenter | Qt::AlignLeft); m_pRightLabel = new QLabel(q); m_pRightLabel->setAlignment(Qt::AlignVCenter | Qt::AlignRight); m_pMainLayout = new QHBoxLayout(q); m_pMainLayout->setContentsMargins(16, 0, 16, 0); m_pMainLayout->addWidget(m_pSettingName); m_pMainLayout->addSpacing(8); m_pMainLayout->addWidget(m_pLeftLabel); m_pMainLayout->addWidget(m_pSlider); m_pMainLayout->addWidget(m_pRightLabel); q->setLayout(m_pMainLayout); } KSliderFrame::KSliderFrame(QString title, bool hasNode, QWidget *parent, BorderRadiusStyle style, Qt::Orientation orientation) : KBaseFrame(parent, style, true) , d_ptr(new KSliderFramePrivate(this)) { Q_D(KSliderFrame); setObjectName("KSliderFrame"); d->m_pSettingName->setText(title); d->m_pSlider->setNodeVisible(hasNode); d->m_pSlider->setOrientation(orientation); } KSliderFrame::~KSliderFrame() { } QLabel *KSliderFrame::leftLabel() { Q_D(KSliderFrame); return d->m_pLeftLabel; } QLabel *KSliderFrame::rightLabel() { Q_D(KSliderFrame); return d->m_pRightLabel; } KSlider *KSliderFrame::slider() { Q_D(KSliderFrame); return d->m_pSlider; } QHBoxLayout *KSliderFrame::mainHLayout() { Q_D(KSliderFrame); return d->m_pMainLayout; } KLabel *KSliderFrame::titleLabel() { Q_D(KSliderFrame); return d->m_pSettingName; } } #include "ksliderframe.moc" #include "moc_ksliderframe.cpp" libkysdk-applications/kysdk-qtwidgets/src/ktoolbutton.h0000664000175000017500000000627215104543305022471 0ustar fengfeng/* * libkysdk-qtwidgets's Library * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #ifndef KTOOLBUTTON_H #define KTOOLBUTTON_H #include "gui_g.h" #include #include #include namespace kdk { /** @defgroup PushbuttonModule * @{ */ /** * @brief 支持三种样式,暂不支持文字显示 * @since 1.0.0 */ enum KToolButtonType { Flat, SemiFlat, Background, Frameless }; class KToolButtonPrivate; /** * @brief 提供了一个快速访问按钮,暂不支持显示文本 */ class GUI_EXPORT KToolButton : public QToolButton { Q_OBJECT public: KToolButton(QWidget *parent); /** * @brief 返回类型 * @return */ KToolButtonType type(); /** * @brief 设置类型 * @param type */ void setType(KToolButtonType type); /** * @brief 设置Icon * @param icon */ void setIcon(const QIcon &icon); /** * @brief 设置正在加载状态,仅不带箭头的toolbuttuon支持该状态 * @param flag */ void setLoading(bool flag); /** * @brief 返回是否正在加载 * @return */ bool isLoading(); /** * @brief 获取Icon * @return */ QIcon icon(); /** * @brief 设置是否显示向下箭头,默认不显示 * @param flag */ void setArrow(bool flag); /** * @brief 返回是否显示箭头 * @return */ bool hasArrow() const; /** * @brief 设置图标颜色 * @param flag * @param color * @since 2.4.1.0 */ void setIconColor(bool flag, QColor color); /** * @brief setBorderRadius * @param bottomLeft * @param topLeft * @param topRight * @param bottomRight * @since 2.5.2.0 */ void setBorderRadius(int bottomLeft, int topLeft, int topRight, int bottomRight); /** * @brief setBackgroundColorEnabled * @param flag * @since 2.5.2.0 */ void setBackgroundColorEnabled(bool flag); /** * @brief backgroundColorEnabled * @return * @since 2.5.2.0 */ bool backgroundColorEnabled(); Q_SIGNALS: void checkedChanged(bool checked); protected: bool eventFilter(QObject *watched, QEvent *event); QSize sizeHint() const; void paintEvent(QPaintEvent *event); private: Q_DECLARE_PRIVATE(KToolButton) KToolButtonPrivate *const d_ptr; }; } /** * @example testtoolbutton/widget.h * @example testtoolbutton/widget.cpp * @} */ #endif // KTOOLBUTTON_H libkysdk-applications/kysdk-qtwidgets/src/kdragwidget.cpp0000664000175000017500000003647415104543305022743 0ustar fengfeng/* * libkysdk-qtwidgets's Library * * Copyright (C) 2024, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhenyu Wang * */ #include "kdragwidget.h" #include "accessinfohelper.h" #include "themeController.h" #include #include #include #include #include #include #include #include #include namespace kdk { class FileDialog : public QFileDialog { Q_OBJECT public: FileDialog(QWidget *parent = nullptr); virtual ~FileDialog(); public slots: void goAccept(); protected: void showEvent(QShowEvent *event) override; }; class KDragWidgetPrivate : public QObject, public ThemeController { Q_OBJECT Q_DECLARE_PUBLIC(KDragWidget) public: KDragWidgetPrivate(KDragWidget *parent); void openFile(); protected: void changeTheme(); private: KDragWidget *q_ptr; QColor lineColor; Qt::PenStyle mainState; KPushButton *m_pIconButton; QLabel *m_pTextLabel; FileDialog *m_FileDialog; QStringList m_NameFilterList; QStringList m_pStringList; bool m_cursorFlag; }; KDragWidgetPrivate::KDragWidgetPrivate(KDragWidget *parent) : q_ptr(parent) , mainState(Qt::DashLine) { Q_Q(KDragWidget); m_pIconButton = new KPushButton(); m_pTextLabel = new QLabel(); m_FileDialog = new FileDialog(q); m_FileDialog->setDirectory(QStandardPaths::writableLocation(QStandardPaths::HomeLocation)); m_cursorFlag = false; lineColor = ThemeController::getCustomColorFromDT("kline-normal"); KDK_ALL_INFO_FORMAT(m_pIconButton,""); KDK_ALL_INFO_FORMAT(m_pTextLabel,""); KDK_ALL_INFO_FORMAT(m_FileDialog,""); } void KDragWidgetPrivate::openFile() { Q_Q(KDragWidget); m_FileDialog->setWindowTitle(tr("Please select file")); m_pStringList.clear(); if (m_FileDialog->exec() == QDialog::Accepted) { QStringList selectFiles = m_FileDialog->selectedFiles(); if (selectFiles.count() > 1) { for (const QString &fileName : selectFiles) { QFileInfo fileinfo(fileName); if (m_FileDialog->nameFilters().count() == 1 && m_FileDialog->nameFilters().first().contains("(*)")) { m_pStringList.append(fileName); } else { if (fileinfo.isFile() && !fileName.isEmpty()) m_pStringList.append(fileName); } } if (m_pStringList.count() > 0) Q_EMIT q->getPathList(m_pStringList); } else { QString fileName = selectFiles.first(); QFileInfo fileinfo(fileName); if (m_FileDialog->nameFilters().first().contains("(*)")) Q_EMIT q->getPath(fileName); else if (fileinfo.isFile() && !fileName.isEmpty()) Q_EMIT q->getPath(fileName); } } } void KDragWidgetPrivate::changeTheme() { Q_Q(KDragWidget); initThemeStyle(); } KDragWidget::KDragWidget(QWidget *parent) : QWidget(parent) , d_ptr(new KDragWidgetPrivate(this)) { Q_D(KDragWidget); setAcceptDrops(true); // 设置接受拖拽 QVBoxLayout *mainLayout = new QVBoxLayout(this); QHBoxLayout *hLayout = new QHBoxLayout(); QHBoxLayout *hLayout1 = new QHBoxLayout(); // d->m_pIconButton = new KPushButton(); d->m_pIconButton->setFixedSize(54, 54); d->m_pIconButton->setTranslucent(true); d->m_pIconButton->setButtonType(KPushButton::CircleType); d->m_pIconButton->setIcon(QIcon::fromTheme("list-add.symbolic")); // d->m_pTextLabel = new QLabel(); d->m_pTextLabel->setText(tr("Select or drag and drop the folder identification path")); hLayout->setContentsMargins(0, 0, 0, 0); hLayout->addStretch(); hLayout->addWidget(d->m_pIconButton); hLayout->addStretch(); hLayout1->setContentsMargins(0, 0, 0, 0); hLayout1->addStretch(); hLayout1->addWidget(d->m_pTextLabel); hLayout1->addStretch(); mainLayout->setSpacing(0); mainLayout->addStretch(); mainLayout->addLayout(hLayout); mainLayout->addSpacing(16); mainLayout->addLayout(hLayout1); mainLayout->addStretch(); d->changeTheme(); connect(d->m_pIconButton, &KPushButton::clicked, this, [=]() { d->openFile(); }); connect(d->m_gsetting, &QGSettings::changed, this, [=]() { d->changeTheme(); }); installEventFilter(this); d->m_FileDialog->installEventFilter(this); } KPushButton *KDragWidget::iconButton() { Q_D(KDragWidget); return d->m_pIconButton; } QLabel *KDragWidget::textLabel() { Q_D(KDragWidget); return d->m_pTextLabel; } QFileDialog *KDragWidget::fileDialog() { Q_D(KDragWidget); return dynamic_cast(d->m_FileDialog); } void KDragWidget::setNameFilter(const QString &filter) { Q_D(KDragWidget); QString f(filter); if (f.isEmpty()) return; QString sep(QLatin1String(";;")); int i = f.indexOf(sep, 0); if (i == -1) { if (f.indexOf(QLatin1Char('\n'), 0) != -1) { sep = QLatin1Char('\n'); i = f.indexOf(sep, 0); } } setNameFilters(f.split(sep)); } void KDragWidget::setNameFilters(const QStringList &filters) { Q_D(KDragWidget); d->m_FileDialog->setNameFilters(filters); for (int i = 0; i < filters.size(); i++) { if (!d->m_NameFilterList.contains(filters.at(i))) { d->m_NameFilterList.append(filters.at(i)); } } } void KDragWidget::mouseMoveEvent(QMouseEvent *event) { Q_D(KDragWidget); return QWidget::mouseMoveEvent(event); } void KDragWidget::mousePressEvent(QMouseEvent *event) { Q_D(KDragWidget); return QWidget::mousePressEvent(event); } void KDragWidget::mouseReleaseEvent(QMouseEvent *event) { Q_D(KDragWidget); return QWidget::mouseReleaseEvent(event); } void KDragWidget::keyPressEvent(QKeyEvent *event) { return QWidget::keyPressEvent(event); } void KDragWidget::keyReleaseEvent(QKeyEvent *event) { return QWidget::keyReleaseEvent(event); } void KDragWidget::paintEvent(QPaintEvent *event) { Q_D(KDragWidget); QPainter painter(this); QPen pen = painter.pen(); pen.setColor(d->lineColor); pen.setStyle(d->mainState); pen.setWidth(1); painter.setPen(pen); painter.setBrush(Qt::NoBrush); int radius = ThemeController::getRadiusFromDT("kradius-normal"); if (radius == -1) radius = 6; painter.drawRoundedRect(rect().adjusted(1, 1, -1, -1), radius, radius); } bool KDragWidget::eventFilter(QObject *watched, QEvent *event) { Q_D(KDragWidget); if (watched == this) { switch (event->type()) { case QEvent::MouseButtonPress: { d->m_pIconButton->setAttribute(Qt::WA_UnderMouse, true); d->lineColor = ThemeController::getCustomColorFromDT("tooltiptext-active"); d->openFile(); update(); break; } case QEvent::MouseButtonRelease: { d->m_pIconButton->setAttribute(Qt::WA_UnderMouse, true); d->lineColor = ThemeController::getCustomColorFromDT("tooltiptext-active"); update(); break; } case QEvent::Leave: { d->m_pIconButton->setAttribute(Qt::WA_UnderMouse, false); d->lineColor = ThemeController::getCustomColorFromDT("placeholdertext-active"); if (d->m_cursorFlag) { d->m_cursorFlag = false; setCursor(Qt::ArrowCursor); } update(); break; } case QEvent::Enter: { d->m_pIconButton->setAttribute(Qt::WA_UnderMouse, true); d->lineColor = ThemeController::getCustomColorFromDT("tooltiptext-active"); if (d->m_cursorFlag) { d->m_cursorFlag = false; setCursor(Qt::ArrowCursor); } update(); break; } case QEvent::DragEnter: { d->m_pIconButton->setAttribute(Qt::WA_UnderMouse, true); d->lineColor = ThemeController::getCustomColorFromDT("highlight-active"); update(); break; } case QEvent::DragLeave: { d->m_pIconButton->setAttribute(Qt::WA_UnderMouse, false); d->lineColor = ThemeController::getCustomColorFromDT("placeholdertext-active"); update(); break; } default: break; } } if (watched == d->m_FileDialog) { if (event->type() == QEvent::Show) { QWidget *parentWindow = qobject_cast(this->parent()); while (parentWindow && parentWindow->parent()) parentWindow = qobject_cast(parentWindow->parent()); if (parentWindow && parentWindow->isActiveWindow()) { const QPoint parentWindowCenter = parentWindow->geometry().center(); d->m_FileDialog->move(parentWindowCenter.x() - d->m_FileDialog->width() / 2, parentWindowCenter.y() - d->m_FileDialog->height() / 2 + 40); } else { QScreen *screen = QGuiApplication::primaryScreen(); int screenWidth = screen->geometry().width(); int screenHeight = screen->geometry().height(); int messageBox_X = (screenWidth - this->width()) / 2; int messageBox_Y = (screenHeight - this->height()) / 2; d->m_FileDialog->move(messageBox_X, messageBox_Y); } } } return QWidget::eventFilter(watched, event); } void KDragWidget::dragEnterEvent(QDragEnterEvent *event) { Q_D(KDragWidget); if (event->mimeData()->hasUrls()) { QList urls = event->mimeData()->urls(); for (int i = 0; i < urls.count(); i++) { QString filePath = urls.at(i).toLocalFile(); if (!filePath.isEmpty()) { QFileInfo fileInfo(filePath); // filePath 路径 QString suffix = fileInfo.suffix(); // suffix 后缀 QStringList nameFilters = d->m_FileDialog->nameFilters(); for (QString str : nameFilters) { if (!str.contains("(*)")) { if (!fileInfo.isDir()) { if (!suffix.isEmpty() && str.contains(suffix, Qt::CaseInsensitive)) { d->m_cursorFlag = false; break; } else d->m_cursorFlag = true; } else { d->m_cursorFlag = true; } } } } } if (d->m_cursorFlag) { setCursor(Qt::ForbiddenCursor); event->setDropAction(Qt::IgnoreAction); } else { setCursor(Qt::ArrowCursor); event->acceptProposedAction(); } } else { event->ignore(); } } void KDragWidget::dragLeaveEvent(QDragLeaveEvent *event) { Q_D(KDragWidget); return QWidget::dragLeaveEvent(event); } void KDragWidget::dragMoveEvent(QDragMoveEvent *event) { Q_D(KDragWidget); return QWidget::dragMoveEvent(event); } void KDragWidget::dropEvent(QDropEvent *event) { Q_D(KDragWidget); const QMimeData *mimeData = event->mimeData(); if (mimeData->hasUrls()) { QList urlList = mimeData->urls(); if (urlList.size() > 1) { d->m_pStringList.clear(); for (int i = 0; i < urlList.size(); i++) // 选中的文件 { QString fileName = urlList.at(i).toLocalFile(); QFileInfo fileinfo(fileName); if (d->m_FileDialog->nameFilters().count() == 1 && d->m_FileDialog->nameFilters().first().contains("(*)")) { d->m_pStringList.append(fileName); } else { if (fileinfo.isFile()) { QString endStr = fileName.mid(fileName.lastIndexOf("."), fileName.size() - fileName.lastIndexOf(".")); if (d->m_NameFilterList.isEmpty()) // 若无过滤则正常选中 d->m_pStringList.append(fileName); else { for (int temp = 0; temp < d->m_NameFilterList.size(); temp++) // 遍历是否符合筛选条件 { QString curString = d->m_NameFilterList.at(temp); if (curString.contains(endStr)) { d->m_pStringList.append(fileName); } } } } } } Q_EMIT getPathList(d->m_pStringList); } else { QString fileName = urlList.first().toLocalFile(); QFileInfo fileinfo(fileName); if (d->m_FileDialog->nameFilters().count() == 1 && d->m_FileDialog->nameFilters().first().contains("(*)")) { Q_EMIT getPath(fileName); } else { if (fileinfo.isFile()) { QString endStr = fileName.mid(fileName.lastIndexOf("."), fileName.size() - fileName.lastIndexOf(".")); if (d->m_NameFilterList.isEmpty()) // 若无过滤则正常选中 Q_EMIT getPath(fileName); else { for (int temp = 0; temp < d->m_NameFilterList.size(); temp++) // 遍历是否符合筛选条件 { QString curString = d->m_NameFilterList.at(temp); if (curString.contains(endStr)) { Q_EMIT getPath(fileName); } } } } } } } if (d->m_cursorFlag) { d->m_cursorFlag = false; setCursor(Qt::ArrowCursor); event->ignore(); } } FileDialog::FileDialog(QWidget *parent) : QFileDialog(parent) { this->setFileMode(QFileDialog::ExistingFiles); } FileDialog::~FileDialog() { } void FileDialog::goAccept() { accept(); } void FileDialog::showEvent(QShowEvent *event) { Q_UNUSED(event) if (this->isVisible()) { for (QWidget *widget : this->findChildren()) { if (widget->objectName() == "acceptButton") { QPushButton *btn = qobject_cast(widget); disconnect(btn, &QPushButton::clicked, 0, 0); connect(btn, &QPushButton::clicked, [=](bool checked) { Q_UNUSED(checked) this->goAccept(); }); } } } } } #include "kdragwidget.moc" #include "moc_kdragwidget.cpp" libkysdk-applications/kysdk-qtwidgets/src/kpasswordedit.h0000664000175000017500000000643715104543305022773 0ustar fengfeng/* * libkysdk-qtwidgets's Library * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #ifndef KPASSWORDEDIT_H #define KPASSWORDEDIT_H #include "gui_g.h" #include namespace kdk { /** @defgroup InputBoxModule * @{ */ /** * @brief 支持三种状态 * @since 1.0.0 */ enum LoginState { Ordinary, LoginSuccess, LoginFailed }; class KPasswordEditPrivate; /** * @brief 密码输入框,继承于QLineEdit,支持三种不同状态显示 */ class GUI_EXPORT KPasswordEdit : public QLineEdit { Q_OBJECT public: KPasswordEdit(QWidget *parent); /** * @brief 设置状态 * @param state */ void setState(LoginState state); /** * @brief 返回状态 * @return */ LoginState state(); /** * @brief 设置加载状态 * @param flag */ void setLoading(bool flag); /** * @brief 判断是否处于加载状态 * @return */ bool isLoading(); /** * @brief 返回placeholderText * @return */ QString placeholderText(); /** * @brief 设置PlaceholderText * @param text */ void setPlaceholderText(QString &text); /** * @brief 设置是否启用ClearButton * @param enable */ void setClearButtonEnabled(bool enable); /** * @brief 返回是否启用了ClearButton * @return */ bool isClearButtonEnabled() const; /** * @brief 设置EchoModeBtn是否可见 * @return * @since 1.2.0 */ void setEchoModeBtnVisible(bool enable); /** * @brief 返回EchoModeBtn是否可见 * @return * @since 1.2.0 */ bool echoModeBtnVisible(); /** * @brief 设置ClearBtn是否可见 * @return * @since 1.2.0 */ void setClearBtnVisible(bool enable); /** * @brief 返回ClearBtn是否可见 * @return * @since 1.2.0 */ bool clearBtnVisible(); /** * @brief 设置KLineEdit是否可用 * @return */ void setEnabled(bool); /** * @brief setEchoMode * @since 1.2.0 */ void setEchoMode(EchoMode mode); /** * @brief 设置是否走默认palette * @param flag * @since 1.2.0 */ void setUseCustomPalette(bool flag); protected: void resizeEvent(QResizeEvent *event); bool eventFilter(QObject *watched, QEvent *event); QSize sizeHint() const override; private: Q_DECLARE_PRIVATE(KPasswordEdit) KPasswordEditPrivate *const d_ptr; }; } /** * @example testpasswordedit/widget.h * @example testpasswordedit/widget.cpp * @} */ #endif // KPASSWORDEDIT_H libkysdk-applications/kysdk-qtwidgets/src/kdirtabbar.h0000664000175000017500000000507015104543305022205 0ustar fengfeng/* * libkysdk-qtwidgets's Library * * Copyright (C) 2024, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Yaxian Liu * */ #ifndef KDIRTABBAR_H #define KDIRTABBAR_H #include #include namespace kdk { class KDirTabBarPrivate; /** * @brief 目录层级控件 * @since 2.5.2.0 */ class KDirTabBar : public QWidget { Q_OBJECT public: KDirTabBar(QWidget *parent = nullptr); ~KDirTabBar(); /** * @brief 设置目标路径 * @param path */ void setCurrentPath(const QString Dirpath); /** * @brief 获取目标路径 * @return QString */ QString currentPath() const; /** * @brief 设置tabbar显示个数 * @param int */ void setVisibleDepth(const int depth); /** * @brief 获取tabbar显示个数 * @return int */ int visibleDepth(); /** * @brief 设置图标 * @param icon */ void setIcon(int index, const QIcon &icon); /** * @brief 获取图标 * @return QIcon */ QIcon icon(int index); /** * @brief 设置Root * @param */ void setRootPath(const QString targetPath); /** * @brief 获取Root路径 * @return QString */ QString RootPath(); /** * @brief 设置按钮显示字体长度 * @param int */ void setTextLength(int length); /** * @brief 返回字体显示长度 * @return int */ int textLength(); /** * @brief 返回button列表 * @return */ QList buttons(); // QToolButton * buttonAt(int index); signals: void tabBarClicked(const QString uri); protected: // void paintEvent(QPaintEvent *event);//有图标和无图标,三态 // void mousePressEvent(QMouseEvent *e) override; private: Q_DECLARE_PRIVATE(KDirTabBar); KDirTabBarPrivate *const d_ptr; }; } #endif // KDIRTABBAR_H libkysdk-applications/kysdk-qtwidgets/src/parmscontroller.cpp0000664000175000017500000001706215104543305023665 0ustar fengfeng/* * libkysdk-qtwidgets's Library * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #include #include #include #include #include "parmscontroller.h" #include namespace kdk { static Parmscontroller *g_parmscontroller; static QDBusInterface *g_statusManagerDBus; static bool g_isTablet; const static QString DBUS_STATUS_MANAGER = "com.kylin.statusmanager.interface"; const static int TABLET_CONTROL_HEIGHT = 48; const static int TABLET_SLIDER_HANDLE_RADIUS = 40; const static int TABLET_SLIDER_NODE_RADIUS = 16; const static int TABLET_BADGE_HEIGHT = 20; const static int TABLET_ICONBAR_HEIGHT = 64; const static int TABLET_ICONBARICONSIZE = 32; const static int TABLET_WINDOWBUTTONBAR_SIZE = 48; const static int TABLET_NAVIGATION_INTERVAL = 4; // const static int TABLET_NAVIGATION_WIDTH = 230; const static int TABLET_WIDGET_SIDEWIDGET_WIDTH = 254; const static int TABLET_INPUTDIALOG_HEIGHT = 222; const static int TABLET_INPUTDIALOG_WIDTH = 352; const static int TABLET_INPUTDIALOG_LABEL_SPACING = 16; const static int TABLET_INPUTDIALOG_WIDGET_SPACING = 24; const static int TABLET_INPUTDIALOG_BUTTON_SPACING = 16; const static int TABLET_INPUTDIALOG_BOTTOM_SPACING = 16; const static int TABLET_INPUTDIALOG_RIGHT_SPACING = 32; const static int PC_CONTROL_HEIGHT = 36; const static int PC_SLIDER_HANDLE_RADIUS = 24; const static int PC_SLIDER_NODE_RADIUS = 10; const static int PC_BADGE_HEIGHT = 30; const static int PC_ICONBAR_HEIGHT = 40; const static int PC_ICONBARICONSIZE = 24; const static int PC_WINDOWBUTTONBAR_SIZE = 30; const static int PC_NAVIGATION_INTERVAL = 4; // const static int PC_NAVIGATION_WIDTH = 168; const static int PC_WIDGET_SIDEWIDGET_WIDTH = 200; const static int PC_INPUTDIALOG_HEIGHT = 198; const static int PC_INPUTDIALOG_WIDTH = 336; const static int PC_INPUTDIALOG_LABEL_SPACING = 8; const static int PC_INPUTDIALOG_WIDGET_SPACING = 32; const static int PC_INPUTDIALOG_BUTTON_SPACING = 10; const static int PC_INPUTDIALOG_BOTTOM_SPACING = 24; const static int PC_INPUTDIALOG_RIGHT_SPACING = 24; Parmscontroller *Parmscontroller::self() { if (g_parmscontroller) return g_parmscontroller; else { g_parmscontroller = new Parmscontroller; return g_parmscontroller; } } Parmscontroller::Parmscontroller(QObject *parent) : QObject(parent) { g_statusManagerDBus = new QDBusInterface(DBUS_STATUS_MANAGER, "/", DBUS_STATUS_MANAGER, QDBusConnection::sessionBus()); if (g_statusManagerDBus) { if (g_statusManagerDBus->isValid()) { // 平板模式切换 connect(g_statusManagerDBus, SIGNAL(mode_change_signal(bool)), this, SIGNAL(modeChanged(bool))); connect(this, &Parmscontroller::modeChanged, this, [=](bool flag) { g_isTablet = flag; }); } } g_isTablet = isTabletMode(); } Parmscontroller::~Parmscontroller() { delete g_statusManagerDBus; g_statusManagerDBus = nullptr; } bool Parmscontroller::isTabletMode() { if (g_statusManagerDBus && g_statusManagerDBus->isValid()) { QDBusReply message = g_statusManagerDBus->call("get_current_tabletmode"); if (message.isValid()) return message.value(); else return false; } else return false; } int Parmscontroller::parm(Parmscontroller::Parm p) { if (g_isTablet) { switch (p) { case PM_TabBarHeight: case PM_PushButtonHeight: case PM_ToolButtonHeight: case PM_SearchLineEditHeight: case PM_PasswordEditHeight: case PM_NavigationBatHeight: case PM_TagHeight: case PM_SearchLineEditItemHeight: return TABLET_CONTROL_HEIGHT; case PM_SliderHandleRadius: return TABLET_SLIDER_HANDLE_RADIUS; case PM_SliderNodeRadius: return TABLET_SLIDER_NODE_RADIUS; case PM_BadgeHeight: return TABLET_BADGE_HEIGHT; case PM_IconbarHeight: return TABLET_ICONBAR_HEIGHT; case PM_IconBarIconSize: return TABLET_ICONBARICONSIZE; case PM_WindowButtonBarSize: return TABLET_WINDOWBUTTONBAR_SIZE; case PM_NavigationBatInterval: return TABLET_NAVIGATION_INTERVAL; // case PM_NavigationBarWidth: // return TABLET_NAVIGATION_WIDTH; case PM_Widget_SideWidget_Width: return TABLET_WIDGET_SIDEWIDGET_WIDTH; case PM_InputDialog_Height: return TABLET_INPUTDIALOG_HEIGHT; case PM_InputDialog_Width: return TABLET_INPUTDIALOG_WIDTH; case PM_InputDialog_Label_Spacing: return TABLET_INPUTDIALOG_LABEL_SPACING; case PM_InputDialog_Widget_Spacing: return TABLET_INPUTDIALOG_WIDGET_SPACING; case PM_InputDialog_Button_Spacing: return TABLET_INPUTDIALOG_BUTTON_SPACING; case PM_InputDialog_Bottom_Spacing: return TABLET_INPUTDIALOG_BOTTOM_SPACING; case PM_InputDialog_Right_Spacing: return TABLET_INPUTDIALOG_RIGHT_SPACING; default: return 0; break; } } else { switch (p) { case PM_TabBarHeight: case PM_PushButtonHeight: case PM_ToolButtonHeight: case PM_SearchLineEditHeight: case PM_PasswordEditHeight: case PM_NavigationBatHeight: case PM_TagHeight: case PM_SearchLineEditItemHeight: return PC_CONTROL_HEIGHT; case PM_SliderHandleRadius: return PC_SLIDER_HANDLE_RADIUS; case PM_SliderNodeRadius: return PC_SLIDER_NODE_RADIUS; case PM_BadgeHeight: return PC_BADGE_HEIGHT; case PM_IconbarHeight: return PC_ICONBAR_HEIGHT; case PM_IconBarIconSize: return PC_ICONBARICONSIZE; case PM_WindowButtonBarSize: return PC_WINDOWBUTTONBAR_SIZE; case PM_NavigationBatInterval: return PC_NAVIGATION_INTERVAL; // case PM_NavigationBarWidth: // return PC_NAVIGATION_WIDTH; case PM_Widget_SideWidget_Width: return PC_WIDGET_SIDEWIDGET_WIDTH; case PM_InputDialog_Height: return PC_INPUTDIALOG_HEIGHT; case PM_InputDialog_Width: return PC_INPUTDIALOG_WIDTH; case PM_InputDialog_Label_Spacing: return PC_INPUTDIALOG_LABEL_SPACING; case PM_InputDialog_Widget_Spacing: return PC_INPUTDIALOG_WIDGET_SPACING; case PM_InputDialog_Button_Spacing: return PC_INPUTDIALOG_BUTTON_SPACING; case PM_InputDialog_Bottom_Spacing: return PC_INPUTDIALOG_BOTTOM_SPACING; case PM_InputDialog_Right_Spacing: return PC_INPUTDIALOG_RIGHT_SPACING; default: return 0; break; } } } } libkysdk-applications/kysdk-qtwidgets/src/kfilewidget.h0000664000175000017500000000374415104543305022404 0ustar fengfeng/* * libkysdk-qtwidgets's Library * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhenyu Wang * */ #ifndef KFILEWIDGET_H #define KFILEWIDGET_H #include "gui_g.h" #include namespace kdk { /** @defgroup FrameModule * { */ class KFileWidgetPrivate; /** * @brief The KFileWidget class * @since 2.4.1.0 */ class GUI_EXPORT KFileWidget : public QWidget { Q_OBJECT public: KFileWidget(QWidget *parent = nullptr); public: /** @brief 设置主要文本 * @param str */ void setMainText(QString str); /** * @brief 设置次级文本 * @param str */ void setSubText(QString str); /** * @brief 设置图片 * @param icon */ void setIcon(QIcon icon); /** * @brief 设置圆角 * @param radius */ void setBorderRadius(int radius); /** * @brief 设置圆角 * @param bottomLeft * @param topLeft * @param topRight * @param bottomRight */ void setBorderRadius(int bottomLeft, int topLeft, int topRight, int bottomRight); Q_SIGNALS: void clicked(); protected: void paintEvent(QPaintEvent *event); bool eventFilter(QObject *watched, QEvent *event); private: Q_DECLARE_PRIVATE(KFileWidget) KFileWidgetPrivate *const d_ptr; }; } #endif // KFILEWIDGET_H libkysdk-applications/kysdk-qtwidgets/src/ktranslucentfloor.cpp0000664000175000017500000001351215104543305024212 0ustar fengfeng/* * libkysdk-qtwidgets's Library * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhenyu Wang * */ #include "ktranslucentfloor.h" #include "kshadowhelper.h" #include "themeController.h" #include #include #include #include #include #include "kysdk-ukuiwindowhelper/ukuiwindowhelper.h" #include #include #include "ukuistylehelper/ukui-decoration-manager.h" #include "ukuistylehelper/ukui-shell-manager.h" #include "xatom-helper.h" namespace kdk { class KTranslucentFloorPrivate : public QObject { Q_OBJECT Q_DECLARE_PUBLIC(KTranslucentFloor) public: KTranslucentFloorPrivate(KTranslucentFloor *parent); protected: bool eventFilter(QObject *target, QEvent *event) override; private: KTranslucentFloor *q_ptr; int m_radius; bool m_shadowFlag; bool m_enableBlur; qreal m_opacity; QRegion m_region; UkuiWindowHelper *m_ukuiWindowHelper; }; KTranslucentFloor::KTranslucentFloor(QWidget *parent) : QFrame(parent) , d_ptr(new KTranslucentFloorPrivate(this)) { Q_D(KTranslucentFloor); // setWindowFlags(Qt::FramelessWindowHint); setAttribute(Qt::WA_TranslucentBackground, true); d->m_ukuiWindowHelper = new UkuiWindowHelper(this); QString platform = QGuiApplication::platformName(); if (platform.startsWith(QLatin1String("xcb"), Qt::CaseInsensitive)) { MotifWmHints hints; hints.flags = MWM_HINTS_FUNCTIONS | MWM_HINTS_DECORATIONS; hints.functions = MWM_FUNC_ALL; hints.decorations = MWM_DECOR_BORDER; XAtomHelper::getInstance()->setWindowMotifHint(this->winId(), hints); } } void KTranslucentFloor::setBorderRadius(int radius) { Q_D(KTranslucentFloor); d->m_radius = radius; if (shadow()) { effects::KShadowHelper::self()->setWidget(this, d->m_radius); } } int KTranslucentFloor::borderRadius() { Q_D(KTranslucentFloor); return d->m_radius; } void KTranslucentFloor::setShadow(bool flag) { Q_D(KTranslucentFloor); d->m_shadowFlag = flag; if (d->m_shadowFlag) effects::KShadowHelper::self()->setWidget(this, d->m_radius); } bool KTranslucentFloor::shadow() { Q_D(KTranslucentFloor); return d->m_shadowFlag; } void KTranslucentFloor::setEnableBlur(bool flag) { Q_D(KTranslucentFloor); d->m_enableBlur = flag; } bool KTranslucentFloor::enableBlur() { Q_D(KTranslucentFloor); return d->m_enableBlur; } void KTranslucentFloor::setOpacity(qreal opacity) { Q_D(KTranslucentFloor); d->m_opacity = opacity; } qreal KTranslucentFloor::opacity() { Q_D(KTranslucentFloor); return d->m_opacity; } void KTranslucentFloor::paintEvent(QPaintEvent *event) { Q_D(KTranslucentFloor); QPainter painter(this); painter.setRenderHints(QPainter::Antialiasing); QPainterPath path; QRect rect = this->rect(); path.addRoundedRect(rect, d->m_radius, d->m_radius); if (d->m_enableBlur && isActiveWindow()) { // 开启毛玻璃时 d->m_region =QRegion(path.toFillPolygon().toPolygon()); if(d->m_enableBlur) { #ifdef USE_UKUI_SHELL_PLUGIN d->m_ukuiWindowHelper->setBlurEffect(d->m_region, 0, true); #else KWindowEffects::enableBlurBehind(this->winId(), true, d->m_region); #endif } this->setMask(d->m_region); painter.setOpacity(d->m_opacity); painter.setBrush(Qt::NoBrush); } else { // 未开启毛玻璃时 #ifdef USE_UKUI_SHELL_PLUGIN d->m_ukuiWindowHelper->setBlurEffect(d->m_region, 0, false); #else KWindowEffects::enableBlurBehind(this->winId(), false, d->m_region); #endif painter.setOpacity(1); painter.setBrush(this->palette().color(this->backgroundRole())); } painter.setPen(Qt::NoPen); painter.drawPath(path); } KTranslucentFloorPrivate::KTranslucentFloorPrivate(KTranslucentFloor *parent) : q_ptr(parent) , m_shadowFlag(true) , m_enableBlur(true) , m_opacity(0.5) { parent->installEventFilter(this); m_radius = ThemeController::getRadiusFromDT("kradius-window"); if (m_radius == -1) m_radius = 12; } bool KTranslucentFloorPrivate::eventFilter(QObject *target, QEvent *event) { QString platform = QGuiApplication::platformName(); if (platform.startsWith(QLatin1String("wayland"), Qt::CaseInsensitive)) { if ((event->type() == QEvent::PlatformSurface || event->type() == QEvent::Show || event->type() == QEvent::UpdateRequest)) { #ifdef USE_UKUI_SHELL_PLUGIN m_ukuiWindowHelper->removeTitleBar(); #else #ifdef USE_UKUI_PROTOCOL if (UkuiShellManager::getInstance()->ukuishellReady()) UkuiShellManager::getInstance()->removeHeaderBar(this->windowHandle()); else UKUIDecorationManager::getInstance()->removeHeaderBar(this->windowHandle()); #else UKUIDecorationManager::getInstance()->removeHeaderBar(this->windowHandle()); #endif #endif } } return QObject::eventFilter(target,event); } } #include "ktranslucentfloor.moc" #include "moc_ktranslucentfloor.cpp" libkysdk-applications/kysdk-qtwidgets/src/kswitchbuttonframe.cpp0000664000175000017500000000557715104543305024372 0ustar fengfeng/* * * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Sisheng He * */ #include "kswitchbuttonframe.h" #include "themeController.h" #include namespace kdk { class KSwitchButtonFramePrivate : public QObject { Q_OBJECT Q_DECLARE_PUBLIC(KSwitchButtonFrame) public: KSwitchButtonFramePrivate(KSwitchButtonFrame *parent); private: KSwitchButtonFrame *q_ptr; QVBoxLayout *m_pVLayout; KLabel *m_pHintLabel; KSwitchButton *m_pSwitchButton; KLabel *m_pSettingName; QHBoxLayout *m_pMainLayout; }; KSwitchButtonFramePrivate::KSwitchButtonFramePrivate(KSwitchButtonFrame *parent) : q_ptr(parent) { Q_Q(KSwitchButtonFrame); setParent(parent); m_pSettingName = new KLabel(q); m_pHintLabel = new KLabel(q); m_pHintLabel->setVisible(false); m_pHintLabel->setFontColor(ThemeController::getCustomColorFromDT("placeholdertext-active")); m_pVLayout = new QVBoxLayout(); m_pVLayout->addWidget(m_pSettingName); m_pVLayout->addWidget(m_pHintLabel); m_pSwitchButton = new KSwitchButton(); m_pMainLayout = new QHBoxLayout(q); m_pMainLayout->setContentsMargins(16, 0, 16, 0); m_pMainLayout->addLayout(m_pVLayout); m_pMainLayout->addStretch(); m_pMainLayout->addWidget(m_pSwitchButton); q->setLayout(m_pMainLayout); } KSwitchButtonFrame::KSwitchButtonFrame(const QString title, QWidget *parent, BorderRadiusStyle style) : KBaseFrame(parent, style, true) , d_ptr(new KSwitchButtonFramePrivate(this)) { Q_D(KSwitchButtonFrame); d->setObjectName("KSwitchButtonFrame"); d->m_pSettingName->setText(title); } KSwitchButtonFrame::~KSwitchButtonFrame() { } void KSwitchButtonFrame::setHintText(QString &hintText) { Q_D(KSwitchButtonFrame); d->m_pHintLabel->setText(hintText); d->m_pHintLabel->setVisible(true); } KSwitchButton *KSwitchButtonFrame::switchButton() { Q_D(KSwitchButtonFrame); return d->m_pSwitchButton; } QHBoxLayout *KSwitchButtonFrame::mainHLayout() { Q_D(KSwitchButtonFrame); return d->m_pMainLayout; } KLabel *KSwitchButtonFrame::titleLabel() { Q_D(KSwitchButtonFrame); return d->m_pSettingName; } } #include "kswitchbuttonframe.moc" #include "moc_kswitchbuttonframe.cpp" libkysdk-applications/kysdk-qtwidgets/src/klunardateedit.cpp0000664000175000017500000002123115104543305023430 0ustar fengfeng/* * libkysdk-qtwidgets's Library * * Copyright (C) 2024, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhenyu Wang * */ #include "klunardateedit.h" #include "kcustomdateedit.h" #include #include #include #include #include #include #include #include #include #define THEME_SCHAME "org.ukui.style" #define COLOR_THEME "styleName" namespace kdk { class KLunarDateEditPrivate : public QObject { Q_OBJECT Q_DECLARE_PUBLIC(KLunarDateEdit) public: KLunarDateEditPrivate(KLunarDateEdit *parent); private: QPixmap loadSvg(const QString &path, int size); QPixmap drawSymbolicColoredPixmap(const QPixmap &source); private: KLunarDateEdit *q_ptr; QGSettings *colorGsettings; KCustomDateEdit *dateEdit; QWidget *m_pLunarWidget; QLabel *lunarLabel; QPushButton *popButton; }; KLunarDateEditPrivate::KLunarDateEditPrivate(KLunarDateEdit *parent) : q_ptr(parent) { Q_Q(KLunarDateEdit); dateEdit = new KCustomDateEdit(q); dateEdit->setContextMenuPolicy(Qt::NoContextMenu); dateEdit->setCalendarPopup(true); dateEdit->setDisplayFormat("yyyy-MM-dd"); QSizePolicy sizePolicy(QSizePolicy::Ignored, QSizePolicy::Preferred); sizePolicy.setHorizontalStretch(0); sizePolicy.setVerticalStretch(0); sizePolicy.setHeightForWidth(dateEdit->sizePolicy().hasHeightForWidth()); dateEdit->setSizePolicy(sizePolicy); // lunarDateEdit m_pLunarWidget = new QWidget(q); m_pLunarWidget->setObjectName(QString::fromUtf8("LunarWidget")); QHBoxLayout *horizontalLayout = new QHBoxLayout(m_pLunarWidget); horizontalLayout->setSpacing(0); horizontalLayout->setContentsMargins(0, 0, 0, 0); lunarLabel = new QLabel(m_pLunarWidget); sizePolicy.setHeightForWidth(lunarLabel->sizePolicy().hasHeightForWidth()); // lunarLabel->setMargin(10); lunarLabel->setSizePolicy(sizePolicy); popButton = new QPushButton(m_pLunarWidget); sizePolicy.setHeightForWidth(popButton->sizePolicy().hasHeightForWidth()); popButton->setSizePolicy(sizePolicy); popButton->setFixedWidth(34); popButton->setStyleSheet(QString::fromUtf8("QPushButton{background-color: rgba(255, 255, 255, 0);border: none;}" "QPushButton:hover { background-color: rgba(255, 255, 255, 0); }" "QPushButton:pressed { background-color: rgba(255, 255, 255, 0);}")); popButton->setFlat(true); connect(popButton, SIGNAL(clicked()), q, SLOT(slotClicked())); horizontalLayout->addSpacing(10); horizontalLayout->addWidget(lunarLabel); horizontalLayout->addWidget(popButton); dateEdit->setVisible(true); m_pLunarWidget->setVisible(false); connect(dateEdit, SIGNAL(dateChanged(QDate)), q, SIGNAL(dateChanged(QDate))); connect(dateEdit, SIGNAL(dateChanged(QDate)), q, SLOT(slotDateChanged(QDate))); const QByteArray id(THEME_SCHAME); if (QGSettings::isSchemaInstalled(id)) { colorGsettings = new QGSettings(id, QByteArray(), q); connect(colorGsettings, &QGSettings::changed, this, [=](QString key) { if ("themeColor" == key || "styleName" == key) { q->slotPaletteChanged(); } }); } } QPixmap KLunarDateEditPrivate::loadSvg(const QString &path, int size) { Q_Q(KLunarDateEdit); int origSize = size; const auto ratio = qApp->devicePixelRatio(); if (2 == ratio) { size += origSize; } else if (3 == ratio) { size += origSize; } QPixmap pixmap(size, size); QSvgRenderer renderer(path); pixmap.fill(Qt::transparent); QPainter painter; painter.begin(&pixmap); renderer.render(&painter); painter.end(); pixmap.setDevicePixelRatio(ratio); return drawSymbolicColoredPixmap(pixmap); } QPixmap KLunarDateEditPrivate::drawSymbolicColoredPixmap(const QPixmap &source) { Q_Q(KLunarDateEdit); QImage img = source.toImage(); for (int x = 0; x < img.width(); x++) { for (int y = 0; y < img.height(); y++) { QColor color = img.pixelColor(x, y); if (color.alpha() > 0) { QColor colorSet = q->palette().color(popButton->palette().ButtonText); color.setRed(colorSet.red()); color.setGreen(colorSet.green()); color.setBlue(colorSet.blue()); img.setPixelColor(x, y, color); } } } return QPixmap::fromImage(img); } KLunarDateEdit::KLunarDateEdit(QWidget *parent) : QWidget{parent} , d_ptr(new KLunarDateEditPrivate(this)) { Q_D(KLunarDateEdit); slotPaletteChanged(); } void KLunarDateEdit::setShowLunar(bool showLunar) { Q_D(KLunarDateEdit); slotDateChanged(d->dateEdit->date()); d->m_pLunarWidget->setVisible(showLunar); d->dateEdit->setShowLunar(showLunar); } void KLunarDateEdit::slotPaletteChanged() { Q_D(KLunarDateEdit); if (d->popButton == nullptr || d->lunarLabel == nullptr || d->m_pLunarWidget == nullptr) return; QPalette pal = qApp->palette(); this->setPalette(pal); d->dateEdit->setPalette(pal); d->m_pLunarWidget->setPalette(pal); d->lunarLabel->setPalette(pal); d->popButton->setPalette(pal); QGSettings *styleGsettings = nullptr; const QByteArray style_id(THEME_SCHAME); if (QGSettings::isSchemaInstalled(style_id)) { styleGsettings = new QGSettings(style_id); QString currentTheme = styleGsettings->get(COLOR_THEME).toString(); if (currentTheme == "ukui-default" || currentTheme == "ukui-light") { d->dateEdit->updateStyle(false); d->m_pLunarWidget->setStyleSheet(QString("QWidget#LunarWidget{background-color: rgb(233,233,233); border:none;border-radius:5px;}")); d->lunarLabel->setStyleSheet(QString("color:rgb(0,0,0);")); } else if (currentTheme == "ukui-dark") { d->dateEdit->updateStyle(true); d->m_pLunarWidget->setStyleSheet(QString("QWidget#LunarWidget{background-color: rgb(55,55,59); border:none;border-radius:5px;}")); d->lunarLabel->setStyleSheet(QString("color:rgb(233,233,233);")); } } QPixmap pixmap = d->loadSvg("/usr/share/kylin-user-guide/data/ukui-down-symbolic.svg", 64); pixmap = pixmap.scaled(QSize(16, 16), Qt::KeepAspectRatio, Qt::SmoothTransformation); QIcon icon(pixmap); d->popButton->setIcon(icon); d->popButton->setIconSize(QSize(16, 16)); if (styleGsettings != nullptr) { delete styleGsettings; styleGsettings = nullptr; } } QDateTimeEdit *KLunarDateEdit::getDateEdit() { Q_D(KLunarDateEdit); return static_cast(d->dateEdit); } void KLunarDateEdit::resizeEvent(QResizeEvent *event) { Q_D(KLunarDateEdit); d->dateEdit->setFixedSize(event->size()); d->m_pLunarWidget->setFixedSize(event->size()); } void KLunarDateEdit::slotDateChanged(QDate date) { Q_D(KLunarDateEdit); QString strHoliday; QString strSolarTerms; QString strLunarFestival; QString strLunarYear; QString strLunarMonth; QString strLunarDay; KLunarCalendarInfo::Instance()->getLunarCalendarInfo(date.year(), date.month(), date.day(), strHoliday, strSolarTerms, strLunarFestival, strLunarYear, strLunarMonth, strLunarDay); QString labBottomarg = strLunarMonth + strLunarDay; d->lunarLabel->setText(labBottomarg); } void KLunarDateEdit::slotClicked() { Q_D(KLunarDateEdit); d->dateEdit->showCalendar(); } } #include "klunardateedit.moc" #include "moc_klunardateedit.cpp" libkysdk-applications/kysdk-qtwidgets/src/klineedit.cpp0000664000175000017500000001530215104543305022402 0ustar fengfeng/* * libkysdk-qtwidgets's Library * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhenyu Wang * */ #include "klineedit.h" #include "themeController.h" #include #include #include #include #include #include namespace kdk { class Q_DECL_HIDDEN PushButton : public QPushButton, public ThemeController { Q_OBJECT public: PushButton(QWidget *parent = nullptr); void setFocusStyle(bool flag); protected: void paintEvent(QPaintEvent *event); void mouseReleaseEvent(QMouseEvent *event); void mousePressEvent(QMouseEvent *event); void leaveEvent(QEvent *e); void enterEvent(QEnterEvent *e); private: bool m_pressEnter; bool m_mouseEnter; bool m_foucusStyle; QLinearGradient m_linearGradient ; }; class Q_DECL_HIDDEN KLineEditPrivate : public QObject, public ThemeController { Q_OBJECT Q_DECLARE_PUBLIC(KLineEdit) public: KLineEditPrivate(KLineEdit *parent); void adjustLayout(); protected: void changeTheme() override; private: KLineEdit *q_ptr; QWidget *m_pWidget; PushButton *m_pPushButton; }; KLineEdit::KLineEdit(QWidget *parent) : QLineEdit(parent) , d_ptr(new KLineEditPrivate(this)) { installEventFilter(this); setFocusPolicy(Qt::StrongFocus); clearFocus(); connect(this, &KLineEdit::returnPressed, this, &KLineEdit::clearFocus); } QPushButton *KLineEdit::pushbutton() { Q_D(KLineEdit); return d->m_pPushButton; } void KLineEdit::resizeEvent(QResizeEvent *event) { Q_D(KLineEdit); QLineEdit::resizeEvent(event); d->adjustLayout(); } bool KLineEdit::eventFilter(QObject *watched, QEvent *event) { Q_D(KLineEdit); if (watched == this) { switch (event->type()) { case QEvent::FocusIn: d->m_pPushButton->setFocusStyle(true); break; case QEvent::FocusOut: d->m_pPushButton->setFocusStyle(false); break; default: break; } } return QLineEdit::eventFilter(watched, event); } void PushButton::mouseReleaseEvent(QMouseEvent *event) { m_pressEnter = false; m_mouseEnter = true; QPushButton::mouseReleaseEvent(event); } void PushButton::mousePressEvent(QMouseEvent *event) { m_pressEnter = true; m_mouseEnter = false; QPushButton::mousePressEvent(event); } void PushButton::leaveEvent(QEvent *e) { m_mouseEnter = false; QPushButton::leaveEvent(e); } void PushButton::enterEvent(QEnterEvent *e) { m_mouseEnter = true; QPushButton::enterEvent(e); } KLineEditPrivate::KLineEditPrivate(KLineEdit *parent) : q_ptr(parent) { Q_Q(KLineEdit); m_pPushButton = new PushButton(); m_pPushButton->setFixedSize(24, 24); m_pWidget = new QWidget(q); QHBoxLayout *hlayout = new QHBoxLayout(m_pWidget); hlayout->setContentsMargins(0, 0, 0, 0); hlayout->addWidget(m_pPushButton); connect(m_gsetting, &QGSettings::changed, this, [=] { changeTheme(); }); } void KLineEditPrivate::adjustLayout() { Q_Q(KLineEdit); int spacing = 5; int width = spacing; if (!m_pPushButton->isHidden()) width += (spacing + m_pPushButton->width()); m_pWidget->setFixedSize(width, q->height()); m_pWidget->move(q->width() - m_pWidget->width(), (q->rect().height() - m_pWidget->height()) / 2); q->setTextMargins(0, 0, m_pWidget->width(), 0); } void KLineEditPrivate::changeTheme() { initThemeStyle(); } PushButton::PushButton(QWidget *parent) { // connect(m_ge) m_pressEnter = false; m_mouseEnter = false; m_foucusStyle = false; } void PushButton::setFocusStyle(bool flag) { m_foucusStyle = flag; if (flag) setFocusPolicy(Qt::NoFocus); else setFocusPolicy(Qt::StrongFocus); } void PushButton::paintEvent(QPaintEvent *event) { QStyleOptionButton option; initStyleOption(&option); QPainter p(this); p.setRenderHint(QPainter::Antialiasing); p.setRenderHint(QPainter::TextAntialiasing); p.setRenderHint(QPainter::SmoothPixmapTransform); p.setPen(Qt::NoPen); QPixmap pixmap = icon().pixmap(iconSize()); m_linearGradient = QLinearGradient(rect().left() + rect().width()/2, rect().top(),rect().left() + rect().width()/2, rect().bottom()); QColor startColor; QColor endColor; if (m_foucusStyle) { if (ThemeController::themeMode() == DarkTheme) pixmap = ThemeController::drawSymbolicColoredPixmap(pixmap); if (m_mouseEnter || m_pressEnter) { pixmap = ThemeController::drawSymbolicColoredPixmap(pixmap); m_linearGradient.setColorAt(0, ThemeController::getCustomColorFromDT("highlight-active")); m_linearGradient.setColorAt(1, ThemeController::getCustomColorFromDT("highlight-active")); p.setBrush(m_linearGradient); } else { p.setBrush(Qt::NoBrush); } } else { if (ThemeController::themeMode() == DarkTheme) pixmap = ThemeController::drawSymbolicColoredPixmap(pixmap); if (m_mouseEnter) { ThemeController::getGradientFromDT("kcomponent-hover",startColor,endColor); m_linearGradient.setColorAt(0,startColor); m_linearGradient.setColorAt(1,endColor); p.setBrush(m_linearGradient); } else if (m_pressEnter) { ThemeController::getGradientFromDT("kcomponent-click",startColor,endColor); m_linearGradient.setColorAt(0,startColor); m_linearGradient.setColorAt(1,endColor); p.setBrush(m_linearGradient); } else { p.setBrush(Qt::NoBrush); } } int radius = ThemeController::getRadiusFromDT("kradius-normal"); if (radius == -1) radius = 6; p.drawRoundedRect(rect(), radius, radius); QRect iconRect((rect().width() - iconSize().width()) / 2, (rect().height() - iconSize().height()) / 2, iconSize().width(), iconSize().height()); p.drawPixmap(iconRect, pixmap); } } #include "klineedit.moc" #include "moc_klineedit.cpp" libkysdk-applications/kysdk-qtwidgets/src/kpushbutton.cpp0000664000175000017500000015315215104543305023026 0ustar fengfeng/* * libkysdk-qtwidgets's Library * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Xiangwei Liu * */ #include "kpushbutton.h" #include "accessinfohelper.h" #include "themeController.h" #include #include #include #include #include #include #include #include #include #include namespace kdk { static int margin = 5; // 左右边距 static int spacing = 4; // 图标文本间距 QStringList iconList{ "ukui-priority-symbolic", "ukui-priority-low-symbolic", "ukui-priority-middling-symbolic", "ukui-priority-high-symbolic" }; class KPushButtonPrivate : public QObject, public ThemeController { Q_DECLARE_PUBLIC(KPushButton) Q_OBJECT public: KPushButtonPrivate(KPushButton *parent) : q_ptr(parent) { setParent(parent); } void changeTheme(); void updateColor(QPainter &painter, QStyleOptionButton &option, QColor &backgroundColor, QColor &highlight, QColor &mix, QColor &fontColor, QColor &pixmapColor); void drawBackground(QPainter &painter, QStyleOptionButton &option, QColor &backgroundColor); void updateArrowDirection(QPixmap &arrowPixmap, QPoint pos, QPoint desktopPos, QPoint globalPos, QIcon::Mode mode, QIcon::State state); void updatePixmap(QPixmap &arrowPixmap, QPixmap &pixmap, QStyleOptionButton &option, QColor &highlight, QColor &fontColor, QColor &pixmapColor, QIcon::Mode mode, QIcon::State state); void updateGrayColor(QPainter &painter, QStyleOptionButton &option, QColor &backgroundColor, QColor &pixmapColor); void drawContent(QPainter &painter, QStyleOptionButton &option, QColor &fontColor, QRect &arrowRect, QRect &textRect, QRect &iconRect, QFontMetrics fm, QPixmap &pixmap, QPixmap &arrowPixmap, uint tf, QPoint iconPosition, int iconWidth, int iconHeight, int textWidth); private: KPushButton *q_ptr; int m_radius; int m_bottomLeft; int m_topLeft; int m_topRight; int m_bottomRight; int m_flashState; QColor m_backgroundColor; bool m_useCustomColor; bool m_hasOneParam; bool m_isTranslucent; bool m_isIconHighlight; QColor m_iconColor; bool m_useCustomIconColor; bool m_isBackgroundColorHighlight; bool m_isTranslucentFlag; bool m_hasArrow; bool m_isLoading; KPushButton::ArrowDirection m_arrowDirection; KPushButton::ButtonType m_buttonType; QGraphicsDropShadowEffect *m_pShadowEffect; QTimer *m_pTimer; QIcon m_icon; QLinearGradient m_linearGradient ; QColor m_borderColor; }; KPushButton::KPushButton(QWidget *parent) : QPushButton(parent) , d_ptr(new KPushButtonPrivate(this)) { Q_D(KPushButton); int radius = ThemeController::getRadiusFromDT("kradius-normal"); if (radius == -1) { d->m_radius = 6; d->m_bottomLeft = 6; d->m_topLeft = 6; d->m_topRight = 6; d->m_bottomRight = 6; } else { d->m_radius = radius; d->m_bottomLeft = radius; d->m_topLeft = radius; d->m_topRight = radius; d->m_bottomRight = radius; } d->m_flashState = 0; d->m_backgroundColor = ThemeController::getCustomColorFromDT("button-active"); d->m_useCustomColor = false; d->m_hasOneParam = true; d->m_buttonType = NormalType; d->m_isTranslucent = false; d->m_isIconHighlight = false; d->m_iconColor = ThemeController::getCustomColorFromDT("buttontext-active"); d->m_useCustomIconColor = false; d->m_isBackgroundColorHighlight = false; d->m_isTranslucentFlag = false; d->m_hasArrow = false; d->m_isLoading = false; d->m_arrowDirection = ArrowBottom; d->m_pShadowEffect = new QGraphicsDropShadowEffect(this); KDK_OBJ_INFO_FORMAT(d->m_pShadowEffect); d->m_pTimer = new QTimer(this); d->m_pTimer->setInterval(100); connect(d->m_gsetting, &QGSettings::changed, d, &KPushButtonPrivate::changeTheme); connect(d->m_pTimer, &QTimer::timeout, this, [=]() { if (d->m_flashState < 7) d->m_flashState++; else d->m_flashState = 0; setIcon(QIcon::fromTheme(QString("ukui-loading-%1.symbolic").arg(d->m_flashState))); }); } KPushButton::~KPushButton() { } void KPushButton::setBorderRadius(int radius) { Q_D(KPushButton); d->m_hasOneParam = true; d->m_radius = radius; update(); } void KPushButton::setBorderRadius(int bottomLeft, int topLeft, int topRight, int bottomRight) { Q_D(KPushButton); d->m_hasOneParam = false; d->m_bottomLeft = bottomLeft; d->m_topLeft = topLeft; d->m_topRight = topRight; d->m_bottomRight = bottomRight; update(); } int KPushButton::borderRadius() { Q_D(KPushButton); return d->m_radius; } void KPushButton::setBackgroundColor(QColor color) { Q_D(KPushButton); if (d->m_isBackgroundColorHighlight) d->m_isBackgroundColorHighlight = false; d->m_useCustomColor = true; d->m_backgroundColor = color; update(); } QColor KPushButton::backgroundColor() { Q_D(KPushButton); return d->m_backgroundColor; } void KPushButton::setButtonType(ButtonType type) { Q_D(KPushButton); if (type == KPushButton::ShadowType) { d->m_pShadowEffect->setOffset(0, 3); // 阴影颜色 QColor color(0, 0, 0); // 阴影半径 if (ThemeController::themeMode() == LightTheme) color.setAlphaF(0.25); else color.setAlphaF(0.45); d->m_pShadowEffect->setColor(color); d->m_pShadowEffect->setBlurRadius(8); setGraphicsEffect(d->m_pShadowEffect); } if (type == KPushButton::GrayType) setFocusPolicy(Qt::StrongFocus); else setFocusPolicy(Qt::NoFocus); d->m_buttonType = type; } KPushButton::ButtonType KPushButton::buttonType() { Q_D(KPushButton); return d->m_buttonType; } void KPushButton::setTranslucent(bool flag) { Q_D(KPushButton); d->m_isTranslucentFlag = flag; d->m_isTranslucent = flag; d->changeTheme(); } bool KPushButton::isTranslucent() { Q_D(KPushButton); return d->m_isTranslucent; } void KPushButton::setIconHighlight(bool flag) { Q_D(KPushButton); d->m_isIconHighlight = flag; } bool KPushButton::isIconHighlight() { Q_D(KPushButton); return d->m_isIconHighlight; } void KPushButton::setIconColor(QColor color) { Q_D(KPushButton); d->m_useCustomIconColor = true; d->m_iconColor = color; update(); } QColor KPushButton::IconColor() { Q_D(KPushButton); return d->m_iconColor; } void KPushButton::setBackgroundColorHighlight(bool flag) { Q_D(KPushButton); if (d->m_useCustomColor) d->m_useCustomColor = false; d->m_isBackgroundColorHighlight = flag; } bool KPushButton::isBackgroundColorHighlight() { Q_D(KPushButton); return d->m_isBackgroundColorHighlight; } void KPushButton::setArrow(bool flag, KPushButton::ArrowDirection arrowDirection) { Q_D(KPushButton); d->m_hasArrow = flag; d->m_arrowDirection = arrowDirection; } bool KPushButton::hasArrow() const { Q_D(const KPushButton); return d->m_hasArrow; } void KPushButton::setLoaingStatus(bool flag) { Q_D(KPushButton); if (!d->m_isLoading) { d->m_icon = icon(); } d->m_isLoading = flag; if (flag) { d->m_pTimer->start(); } else { d->m_pTimer->stop(); setIcon(d->m_icon); } } bool KPushButton::isLoading() { Q_D(KPushButton); return d->m_isLoading; } bool KPushButton::eventFilter(QObject *watched, QEvent *event) { Q_D(KPushButton); return QPushButton::eventFilter(watched, event); } void KPushButton::paintEvent(QPaintEvent *event) { Q_D(KPushButton); d->m_linearGradient = QLinearGradient(width() / 2, y(), width() / 2, height() + y()); QStyleOptionButton option; initStyleOption(&option); QColor pixmapColor; QPainter painter(this); painter.setRenderHint(QPainter::Antialiasing); painter.setRenderHint(QPainter::TextAntialiasing); painter.setRenderHint(QPainter::SmoothPixmapTransform); QColor fontColor = ThemeController::getCustomColorFromDT("buttontext-disable"); QColor mix = ThemeController::getCustomColorFromDT("brighttext-active"); // QColor highlight = ThemeController::getCustomColorFromDT("highlight-active"); QColor highlight = ThemeController::getCustomColorFromDT("kbrand-normal"); QColor backgroundColor; if (ThemeController::widgetTheme() == ClassicTheme) { if (painter.pen().width() == 1) painter.translate(0.5, 0.5); } d->updateColor(painter, option, backgroundColor, highlight, mix, fontColor, pixmapColor); d->drawBackground(painter, option, backgroundColor); /*绘制图标和文字*/ QPen pen; pen.setColor(fontColor); painter.setBrush(Qt::NoBrush); painter.setPen(pen); QPoint point; QRect ir = option.rect; uint tf = Qt::AlignVCenter; QPixmap pixmap; QPixmap arrowPixmap; QIcon::Mode mode = option.state & QStyle::State_Enabled ? QIcon::Normal : QIcon::Disabled; if (mode == QIcon::Normal && option.state & QStyle::State_HasFocus) mode = QIcon::Active; QIcon::State state = QIcon::Off; if (option.state & QStyle::State_On) state = QIcon::On; QPoint pos; QPoint desktopPos(QGuiApplication::primaryScreen()->availableGeometry().width(), QGuiApplication::primaryScreen()->availableGeometry().height()); QPoint globalPos; d->updateArrowDirection(arrowPixmap, pos, desktopPos, globalPos, mode, state); d->updatePixmap(arrowPixmap, pixmap, option, highlight, fontColor, pixmapColor, mode, state); if (!option.icon.isNull()) { // QPixmap pixmap = option.icon.pixmap(option.iconSize, mode, state); // QImage image = pixmap.toImage(); // if(mode != QIcon::Disabled){ // if(d->m_isIconHighlight){ // pixmap = ThemeController::drawColoredPixmap(this->icon().pixmap(iconSize()),highlight); // }else if(d->m_useCustomIconColor){ // pixmap = ThemeController::drawColoredPixmap(this->icon().pixmap(iconSize()),d->m_iconColor); // }else{ // pixmap = ThemeController::drawColoredPixmap(this->icon().pixmap(iconSize()),fontColor); // } // } int w = pixmap.width() / pixmap.devicePixelRatio(); int h = pixmap.height() / pixmap.devicePixelRatio(); if (!option.text.isEmpty()) w += option.fontMetrics.boundingRect(option.rect, tf, option.text).width() + 2; point = QPoint(ir.x() + ir.width() / 2 - w / 2, ir.y() + ir.height() / 2 - h / 2); w = pixmap.width() / pixmap.devicePixelRatio(); if (option.direction == Qt::RightToLeft) point.rx() += w; // if(mode == QIcon::Disabled){ // qreal opacity = 0.35; // QPainter painter(&image); // painter.setOpacity(opacity); // painter.setCompositionMode(QPainter::CompositionMode_SourceIn); // painter.fillRect(image.rect(),fontColor); // painter.end(); // p.drawPixmap(this->style()->visualPos(option.direction, option.rect, point), QPixmap::fromImage(image)); // } // else // p.drawPixmap(this->style()->visualPos(option.direction, option.rect, point), pixmap); if (option.direction == Qt::RightToLeft) ir.translate(-point.x() - 2, 0); else ir.translate(point.x() + w + 4, 0); // left-align text if there is if (!option.text.isEmpty()) tf |= Qt::AlignLeft; } else { tf |= Qt::AlignHCenter; } if (hasArrow()) point.rx() -= arrowPixmap.width() / 2; QFontMetrics fm = option.fontMetrics; // if(!this->isEnabled()){ // qreal opacity = 0.35; // fontColor.setAlphaF(opacity); // QPen pen ; // pen.setColor(fontColor); // p.setPen(pen); // if(option.icon.isNull() && (fm.horizontalAdvance(option.text) > option.rect.width() - 10)) // { // QString elidedText = fm.elidedText(option.text,Qt::ElideRight,option.rect.width() - 10); // p.drawText(option.rect.adjusted(5,0,-5,0),tf,elidedText); // setToolTip(option.text); // } // else // p.drawText(ir,tf,option.text); // } // else // { // if(option.icon.isNull() && (fm.horizontalAdvance(option.text) > option.rect.width() - 10)){ // QString elidedText = fm.elidedText(option.text,Qt::ElideRight,option.rect.width() - 10); // p.drawText(option.rect.adjusted(5,0,-5,0),tf,elidedText); // setToolTip(option.text); // } // else // p.drawText(ir,tf,option.text); // } QPoint iconPosition = this->style()->visualPos(option.direction, option.rect, point); int iconWidth = option.iconSize.width(); int iconHeight = option.iconSize.height(); int textWidth = option.rect.width() - iconWidth * 2 - iconPosition.x(); QRect arrowRect; QRect textRect; QRect iconRect = QRect(iconPosition.x(), iconPosition.y(), iconWidth, iconHeight); d->drawContent(painter, option, fontColor, arrowRect, textRect, iconRect, fm, pixmap, arrowPixmap, tf, iconPosition, iconWidth, iconHeight, textWidth); } void KPushButtonPrivate::changeTheme() { Q_Q(KPushButton); if (m_isTranslucentFlag) { if (ThemeController::widgetTheme() == ClassicTheme) m_isTranslucent = false; else m_isTranslucent = true; } else { m_isTranslucent = false; } initThemeStyle(); if (m_buttonType == KPushButton::ShadowType) { m_pShadowEffect->setOffset(0, 3); // 阴影颜色 QColor color(0, 0, 0); // 阴影半径 if (ThemeController::themeMode() == LightTheme) color.setAlphaF(0.25); else color.setAlphaF(0.45); m_pShadowEffect->setColor(color); m_pShadowEffect->setBlurRadius(8); q->setGraphicsEffect(m_pShadowEffect); } } void KPushButtonPrivate::updateColor(QPainter &painter, QStyleOptionButton &option, QColor &backgroundColor, QColor &highlight, QColor &mix, QColor &fontColor, QColor &pixmapColor) { Q_Q(KPushButton); QColor startColor; QColor endColor; if(!q->isDown()) { if (m_buttonType == KPushButton::NormalType || m_buttonType == KPushButton::CircleType || m_buttonType == KPushButton::ShadowType) { if (m_isTranslucent) { /*判断使用用户设置的背景色、跟随系统高亮色或是使用默认的背景色*/ if (!q->isFlat()) { if (m_useCustomColor) { backgroundColor = m_backgroundColor; m_linearGradient.setColorAt(0,m_backgroundColor); m_linearGradient.setColorAt(1,m_backgroundColor); } else if (m_isBackgroundColorHighlight) { backgroundColor = highlight; m_linearGradient.setColorAt(0,highlight); m_linearGradient.setColorAt(1,highlight); } else if (m_buttonType == KPushButton::ShadowType) { backgroundColor = ThemeController::getCustomColorFromDT("base-active"); } else { ThemeController::getGradientFromDT("kcomponent-alpha-normal",startColor,endColor); m_linearGradient.setColorAt(0,startColor); m_linearGradient.setColorAt(1,endColor); } } else { backgroundColor = Qt::transparent; m_linearGradient.setColorAt(0,Qt::transparent); m_linearGradient.setColorAt(1,Qt::transparent); } if (!option.state.testFlag(QStyle::State_Enabled)) { fontColor = ThemeController::getCustomColorFromDT("buttontext-disable"); ThemeController::getGradientFromDT("kcomponent-alpha-disable",startColor,endColor); m_linearGradient.setColorAt(0,startColor); m_linearGradient.setColorAt(1,endColor); pixmapColor = fontColor; m_borderColor = ThemeController::getCustomColorFromDT("kline-component-disable"); } else /*按钮处于可用(Enabled)状态*/ { fontColor = ThemeController::getCustomColorFromDT("kfont-primary"); m_borderColor = ThemeController::getCustomColorFromDT("kline-component-normal"); pixmapColor = ThemeController::getCustomColorFromDT("kfont-primary"); if (option.state.testFlag(QStyle::State_MouseOver)) /*鼠标在按钮上(hover状态)*/ { if (m_buttonType == KPushButton::ShadowType) { backgroundColor = ThemeController::getCustomColorFromDT("kbrand-normal"); } if (option.state.testFlag(QStyle::State_Sunken)) /*按钮被选中(clicked)*/ { m_borderColor = ThemeController::getCustomColorFromDT("kline-component-click"); if (m_useCustomColor || m_isBackgroundColorHighlight || m_buttonType == KPushButton::ShadowType) { fontColor = ThemeController::getCustomColorFromDT("highlightedtext-active"); backgroundColor.setAlphaF(0.45); m_linearGradient.setColorAt(0,backgroundColor); m_linearGradient.setColorAt(1,backgroundColor); } else { fontColor = ThemeController::getCustomColorFromDT("kfont-primary"); ThemeController::getGradientFromDT("kcomponent-alpha-click",startColor,endColor); m_linearGradient.setColorAt(0,startColor); m_linearGradient.setColorAt(1,endColor); m_borderColor = ThemeController::getCustomColorFromDT("kline-component-click"); } } else { m_borderColor = ThemeController::getCustomColorFromDT("kline-component-hover"); if (m_useCustomColor || m_isBackgroundColorHighlight) { backgroundColor.setAlphaF(0.3); m_linearGradient.setColorAt(0,backgroundColor); m_linearGradient.setColorAt(1,backgroundColor); fontColor = ThemeController::getCustomColorFromDT("highlightedtext-active"); } else { ThemeController::getGradientFromDT("kcomponent-alpha-hover",startColor,endColor); m_linearGradient.setColorAt(0,startColor); m_linearGradient.setColorAt(1,endColor); fontColor = ThemeController::getCustomColorFromDT("buttontext-active"); m_borderColor = ThemeController::getCustomColorFromDT("kline-component-hover"); } } } else { if (m_useCustomColor || m_isBackgroundColorHighlight) { fontColor = ThemeController::getCustomColorFromDT("highlightedtext-active"); backgroundColor.setAlphaF(0.15); } else if (m_buttonType == KPushButton::ShadowType) { if (ThemeController::themeMode() == DarkTheme) backgroundColor.setAlphaF(0.2); } } } } else { /*判断使用用户设置的背景色或是使用默认的背景色*/ if (!q->isFlat()) { if (m_useCustomColor) { backgroundColor = m_backgroundColor; m_linearGradient.setColorAt(0,m_backgroundColor); m_linearGradient.setColorAt(1,m_backgroundColor); } else if (m_isBackgroundColorHighlight) { ThemeController::getGradientFromDT("kbrand-normal",startColor,endColor); m_linearGradient.setColorAt(0,startColor); m_linearGradient.setColorAt(1,endColor); } else { ThemeController::getGradientFromDT("kcomponent-normal",startColor,endColor); m_linearGradient.setColorAt(0,startColor); m_linearGradient.setColorAt(1,endColor); } } else { backgroundColor = Qt::transparent; m_linearGradient.setColorAt(0,Qt::transparent); m_linearGradient.setColorAt(1,Qt::transparent); } /*按钮处于不可用(Disabled)状态*/ if (!option.state.testFlag(QStyle::State_Enabled)) { if(m_isBackgroundColorHighlight) { fontColor = ThemeController::getCustomColorFromDT("kfont-white-disable"); ThemeController::getGradientFromDT("kbrand-disable",startColor,endColor); m_linearGradient.setColorAt(0,startColor); m_linearGradient.setColorAt(1,endColor); } else { fontColor = ThemeController::getCustomColorFromDT("buttontext-disable"); pixmapColor = ThemeController::getCustomColorFromDT("buttontext-disable"); ThemeController::getGradientFromDT("kcomponent-disable",startColor,endColor); startColor = ThemeController::getCustomColorFromDT("kcomponent-disable"); m_linearGradient.setColorAt(0,startColor); m_linearGradient.setColorAt(1,endColor); } m_borderColor = ThemeController::getCustomColorFromDT("kline-component-disable"); } else { m_borderColor = ThemeController::getCustomColorFromDT("kline-component-normal"); pixmapColor = ThemeController::getCustomColorFromDT("buttontext-active"); if (m_useCustomColor || m_isBackgroundColorHighlight) { if(m_isBackgroundColorHighlight) fontColor = ThemeController::getCustomColorFromDT("kfont-white"); else fontColor = ThemeController::getCustomColorFromDT("buttontext-active"); if (option.state.testFlag(QStyle::State_MouseOver)) /*鼠标在按钮上(hover状态)*/ { if (option.state.testFlag(QStyle::State_Sunken)) /*按钮被选中(clicked)*/ { if(m_isBackgroundColorHighlight) { m_borderColor = ThemeController::getCustomColorFromDT("kline-component-click"); ThemeController::getGradientFromDT("kbrand-click",startColor,endColor); m_linearGradient.setColorAt(0,startColor); m_linearGradient.setColorAt(1,endColor); } else { m_borderColor = ThemeController::getCustomColorFromDT("kline-component-click"); backgroundColor = ThemeController::mixColor(backgroundColor, mix, 0.2); m_linearGradient.setColorAt(0,backgroundColor); m_linearGradient.setColorAt(1,backgroundColor); } } else { if(m_isBackgroundColorHighlight) { m_borderColor = ThemeController::getCustomColorFromDT("kline-component-hover"); ThemeController::getGradientFromDT("kbrand-hover",startColor,endColor); m_linearGradient.setColorAt(0,startColor); m_linearGradient.setColorAt(1,endColor); } else { m_borderColor = ThemeController::getCustomColorFromDT("kline-component-hover"); backgroundColor = ThemeController::mixColor(backgroundColor, mix, 0.05); m_linearGradient.setColorAt(0,backgroundColor); m_linearGradient.setColorAt(1,backgroundColor); } } } } else { /*按钮处于可用(Enabled)状态*/ fontColor = ThemeController::getCustomColorFromDT("buttontext-active"); if (option.state.testFlag(QStyle::State_MouseOver)) /*鼠标在按钮上(hover状态)*/ { if (option.state.testFlag(QStyle::State_Sunken)) /*按钮被选中(clicked)*/ { ThemeController::getGradientFromDT("kcomponent-click",startColor,endColor); m_linearGradient.setColorAt(0,startColor); m_linearGradient.setColorAt(1,endColor); m_borderColor = ThemeController::getCustomColorFromDT("kline-component-click"); } else { ThemeController::getGradientFromDT("kcomponent-hover",startColor,endColor); m_linearGradient.setColorAt(0,startColor); m_linearGradient.setColorAt(1,endColor); m_borderColor = ThemeController::getCustomColorFromDT("kline-component-hover"); } } } } } if (q->isChecked()) { fontColor = ThemeController::getCustomColorFromDT("highlightedtext-active"); m_linearGradient.setColorAt(0,highlight); m_linearGradient.setColorAt(1,highlight); if (option.state.testFlag(QStyle::State_MouseOver)) /*鼠标在按钮上(hover状态)*/ { if (option.state.testFlag(QStyle::State_Sunken)) /*按钮被选中(clicked)*/ { ThemeController::getGradientFromDT("kbrand-click",startColor,endColor); m_linearGradient.setColorAt(0,startColor); m_linearGradient.setColorAt(1,endColor); m_borderColor = ThemeController::getCustomColorFromDT("kline-component-click"); } else { ThemeController::getGradientFromDT("kbrand-hover",startColor,endColor); m_linearGradient.setColorAt(0,startColor); m_linearGradient.setColorAt(1,endColor); m_borderColor = ThemeController::getCustomColorFromDT("kline-component-hover"); } } } } else if (m_buttonType == KPushButton::GrayType) { updateGrayColor(painter, option, backgroundColor, pixmapColor); } } else { if (m_isTranslucent) { if (m_useCustomColor) { backgroundColor = m_backgroundColor; } else if (m_isBackgroundColorHighlight) { backgroundColor = highlight; } else if (m_buttonType == KPushButton::ShadowType) { backgroundColor = ThemeController::getCustomColorFromDT("base-active"); } else { ThemeController::getGradientFromDT("kcomponent-alpha-normal",startColor,endColor); m_linearGradient.setColorAt(0,startColor); m_linearGradient.setColorAt(1,endColor); } m_borderColor =ThemeController::getCustomColorFromDT("kline-component-click"); if (m_useCustomColor || m_isBackgroundColorHighlight ||m_buttonType == KPushButton::ShadowType) { fontColor = ThemeController::getCustomColorFromDT("highlightedtext-active"); backgroundColor.setAlphaF(0.45); m_linearGradient.setColorAt(0, backgroundColor); m_linearGradient.setColorAt(1, backgroundColor); } else { fontColor = ThemeController::getCustomColorFromDT("kfont-primary"); ThemeController::getGradientFromDT("kcomponent-alpha-click",startColor, endColor); m_linearGradient.setColorAt(0, startColor); m_linearGradient.setColorAt(1, endColor); m_borderColor = ThemeController::getCustomColorFromDT("kline-component-click"); } } else { if (m_useCustomColor || m_isBackgroundColorHighlight) { if (m_useCustomColor) { backgroundColor = m_backgroundColor; } else if (m_isBackgroundColorHighlight) { backgroundColor = highlight; } if (m_isBackgroundColorHighlight) fontColor = ThemeController::getCustomColorFromDT("kfont-white"); else fontColor = ThemeController::getCustomColorFromDT("buttontext-active"); if (m_isBackgroundColorHighlight) { m_borderColor =ThemeController::getCustomColorFromDT("kline-component-click"); ThemeController::getGradientFromDT("kbrand-click", startColor,endColor); m_linearGradient.setColorAt(0, startColor); m_linearGradient.setColorAt(1, endColor); } else { m_borderColor =ThemeController::getCustomColorFromDT("kline-component-click"); backgroundColor =ThemeController::mixColor(backgroundColor, mix, 0.2); m_linearGradient.setColorAt(0, backgroundColor); m_linearGradient.setColorAt(1, backgroundColor); } } else { fontColor = ThemeController::getCustomColorFromDT("buttontext-active"); ThemeController::getGradientFromDT("kcomponent-click", startColor,endColor); m_linearGradient.setColorAt(0, startColor); m_linearGradient.setColorAt(1, endColor); m_borderColor = ThemeController::getCustomColorFromDT("kline-component-click"); } } if (q->isChecked()) { fontColor = ThemeController::getCustomColorFromDT("highlightedtext-active"); ThemeController::getGradientFromDT("kbrand-click", startColor,endColor); m_linearGradient.setColorAt(0, startColor); m_linearGradient.setColorAt(1, endColor); m_borderColor = ThemeController::getCustomColorFromDT("kline-component-click"); } } } void KPushButtonPrivate::drawBackground(QPainter &painter, QStyleOptionButton &option, QColor &backgroundColor) { Q_Q(KPushButton); /*绘制背景色和rect*/ painter.save(); if (((m_buttonType == KPushButton::NormalType || m_buttonType == KPushButton::CircleType) && !m_useCustomColor) || q->isChecked()) { painter.setBrush(m_linearGradient); painter.setPen(m_borderColor); } else { painter.setBrush(backgroundColor); painter.setPen(Qt::NoPen); } switch (m_buttonType) { case KPushButton::NormalType: { if (m_hasOneParam) { if (ThemeController::widgetTheme() == ClassicTheme) painter.drawRoundedRect(option.rect.adjusted(0, 0, -1, -1), 0, 0); else painter.drawRoundedRect(option.rect.adjusted(0, 0, -1, -1), m_radius, m_radius); } else { QPainterPath path; if (ThemeController::widgetTheme() == ClassicTheme) path.addRect(option.rect.adjusted(0, 0, -1, -1)); else { path.moveTo(option.rect.topLeft() + QPointF(0, m_topLeft)); path.lineTo(option.rect.bottomLeft() - QPointF(0, m_bottomLeft)); path.quadTo(option.rect.bottomLeft(), option.rect.bottomLeft() + QPointF(m_bottomLeft, 0)); path.lineTo(option.rect.bottomRight() - QPointF(m_bottomRight, 0)); path.quadTo(option.rect.bottomRight(), option.rect.bottomRight() - QPointF(0, m_bottomRight)); path.lineTo(option.rect.topRight() + QPointF(0, m_topRight)); path.quadTo(option.rect.topRight(), option.rect.topRight() - QPointF(m_topRight, 0)); path.lineTo(option.rect.topLeft() + QPointF(m_topLeft, 0)); path.quadTo(option.rect.topLeft(), option.rect.topLeft() + QPointF(0, m_topLeft)); } painter.drawPath(path); } painter.restore(); break; } case KPushButton::CircleType: painter.drawRoundedRect(option.rect.adjusted(0, 0, 0, 0), q->width() / 2, q->height() / 2); painter.restore(); break; case KPushButton::GrayType: { if (option.state.testFlag(QStyle::State_HasFocus)) { QPen pen; pen.setWidth(2); pen.setColor(ThemeController::getCustomColorFromDT("kbrand-normal")); painter.setPen(pen); } else { painter.setPen(Qt::NoPen); } if (m_hasOneParam) { painter.drawRoundedRect(option.rect.adjusted(1, 1, -1, -1), m_radius, m_radius); } else { QPainterPath path; path.moveTo(option.rect.topLeft() + QPointF(0, m_topLeft)); path.lineTo(option.rect.bottomLeft() - QPointF(0, m_bottomLeft)); path.quadTo(option.rect.bottomLeft(), option.rect.bottomLeft() + QPointF(m_bottomLeft, 0)); path.lineTo(option.rect.bottomRight() - QPointF(m_bottomRight, 0)); path.quadTo(option.rect.bottomRight(), option.rect.bottomRight() - QPointF(0, m_bottomRight)); path.lineTo(option.rect.topRight() + QPointF(0, m_topRight)); path.quadTo(option.rect.topRight(), option.rect.topRight() - QPointF(m_topRight, 0)); path.lineTo(option.rect.topLeft() + QPointF(m_topLeft, 0)); path.quadTo(option.rect.topLeft(), option.rect.topLeft() + QPointF(0, m_topLeft)); painter.setRenderHint(QPainter::Antialiasing); painter.setRenderHint(QPainter::TextAntialiasing); painter.setRenderHint(QPainter::SmoothPixmapTransform); painter.drawPath(path); } painter.restore(); break; } case KPushButton::ShadowType: { QColor penColor = Qt::white; if (!q->isEnabled()) { if (ThemeController::themeMode() == LightTheme) penColor.setAlphaF(0.05); else penColor.setAlphaF(0.1); } painter.setPen(penColor); painter.setBrush(backgroundColor); painter.drawEllipse(option.rect.adjusted(0, 0, -1, -1)); painter.restore(); } break; default: break; } } void KPushButtonPrivate::updateArrowDirection(QPixmap &arrowPixmap, QPoint pos, QPoint desktopPos, QPoint globalPos, QIcon::Mode mode, QIcon::State state) { Q_Q(KPushButton); if (q->hasArrow()) { switch (m_arrowDirection) { case KPushButton::ArrowTop: arrowPixmap = QIcon::fromTheme("ukui-up-symbolic").pixmap(QSize(16, 16), mode, state); if (q->menu()) { pos.setX(q->rect().left()); pos.setY(-q->menu()->height()); globalPos = q->mapToGlobal(pos); // 现在 if (globalPos.x() > (desktopPos.x() - q->menu()->width())) globalPos.setX(desktopPos.x() - q->menu()->width()); if (globalPos.x() < 0) globalPos.setX(0); if (globalPos.y() < 0) { pos.setY(q->rect().bottom()); globalPos.setY(q->mapToGlobal(pos).y()); } q->menu()->move(globalPos); } break; case KPushButton::ArrowBottom: arrowPixmap = QIcon::fromTheme("ukui-down-symbolic").pixmap(QSize(16, 16), mode, state); break; case KPushButton::ArrowLeft: arrowPixmap = QIcon::fromTheme("ukui-start-symbolic").pixmap(QSize(16, 16), mode, state); if (q->menu()) { pos.setX(q->rect().left() - q->menu()->width()); pos.setY(q->rect().center().y() / 2); globalPos = q->mapToGlobal(pos); if (globalPos.x() < 0) { pos.setY(q->rect().bottom()); globalPos.setX(0); globalPos.setY(q->mapToGlobal(pos).y()); } if (globalPos.y() > desktopPos.y() - q->menu()->height()) { globalPos.setY(desktopPos.y() - q->menu()->height()); } q->menu()->move(globalPos); } break; case KPushButton::ArrowRight: arrowPixmap = QIcon::fromTheme("ukui-end-symbolic").pixmap(QSize(16, 16), mode, state); if (q->menu()) { pos.setX(q->rect().right()); q->menu()->move(q->mapToGlobal(pos)); globalPos = q->mapToGlobal(pos); if (globalPos.x() > (desktopPos.x() - q->menu()->width())) { pos.setX(q->rect().left() - q->menu()->width()); globalPos.setX(q->mapToGlobal(pos).x()); } if (globalPos.y() > desktopPos.y() - q->menu()->height()) { globalPos.setY(desktopPos.y() - q->menu()->height()); } q->menu()->move(globalPos); } break; default: break; } } if(arrowPixmap.size() != QSize(16,16)) arrowPixmap = arrowPixmap.scaled(QSize(16,16),Qt::KeepAspectRatio,Qt::SmoothTransformation); } void KPushButtonPrivate::updatePixmap(QPixmap &arrowPixmap, QPixmap &pixmap, QStyleOptionButton &option, QColor &highlight, QColor &fontColor, QColor &pixmapColor, QIcon::Mode mode, QIcon::State state) { Q_Q(KPushButton); pixmap = option.icon.pixmap(option.iconSize, mode, state); if (mode != QIcon::Disabled) { if (m_buttonType == KPushButton::NormalType || m_buttonType == KPushButton::CircleType || m_buttonType == KPushButton::ShadowType) { if (m_isIconHighlight) { pixmap = ThemeController::drawColoredPixmap(q->icon().pixmap(q->iconSize()), highlight); arrowPixmap = ThemeController::drawColoredPixmap(arrowPixmap, highlight); } else if (m_useCustomIconColor) { pixmap = ThemeController::drawColoredPixmap(q->icon().pixmap(q->iconSize()), m_iconColor); arrowPixmap = ThemeController::drawColoredPixmap(arrowPixmap, m_iconColor); } else { if (!pixmap.isNull()) { if (iconList.contains(option.icon.name())) { pixmap = q->icon().pixmap(q->iconSize()); } else if (ThemeController::isPixmapPureColor(pixmap)) pixmap = ThemeController::drawColoredPixmap( q->icon().pixmap(q->iconSize()), fontColor); } if (!arrowPixmap.isNull()) { if (ThemeController::isPixmapPureColor(arrowPixmap)) arrowPixmap = ThemeController::drawColoredPixmap(arrowPixmap, fontColor); } } } else { pixmap = ThemeController::drawColoredPixmap(q->icon().pixmap(q->iconSize()), pixmapColor); arrowPixmap = ThemeController::drawColoredPixmap(arrowPixmap, pixmapColor); } } else { arrowPixmap = ThemeController::drawColoredPixmap(arrowPixmap, ThemeController::getCustomColorFromDT("buttontext-disable")); if (ThemeController::isPixmapPureColor(pixmap) && !iconList.contains(option.icon.name())) pixmap = ThemeController::drawColoredPixmap(pixmap, ThemeController::getCustomColorFromDT("buttontext-disable")); } } void KPushButtonPrivate::updateGrayColor(QPainter &painter, QStyleOptionButton &option, QColor &backgroundColor, QColor &pixmapColor) { Q_Q(KPushButton); if (!m_isTranslucent) { pixmapColor = ThemeController::getCustomColorFromDT("text-active"); if (!q->isEnabled()) { backgroundColor = ThemeController::getCustomColorFromDT("kcomponent-disable"); pixmapColor = ThemeController::getCustomColorFromDT("text-disable"); painter.setPen(Qt::NoPen); } else { if (q->isLoading()) { backgroundColor = ThemeController::getCustomColorFromDT("kcomponent-normal"); painter.setPen(Qt::NoPen); } else { if (option.state.testFlag(QStyle::State_MouseOver)) { if (option.state.testFlag(QStyle::State_Sunken)) { backgroundColor = ThemeController::getCustomColorFromDT("kcomponent-click"); } else { backgroundColor = ThemeController::getCustomColorFromDT("kcomponent-hover"); } } else { backgroundColor = ThemeController::getCustomColorFromDT("kcomponent-normal"); } } } } else { pixmapColor = ThemeController::getCustomColorFromDT("text-active"); if (!q->isEnabled()) { backgroundColor = ThemeController::getCustomColorFromDT("kcomponent-alpha-disable"); pixmapColor = ThemeController::getCustomColorFromDT("text-disable"); } else { if (q->isLoading()) { backgroundColor = ThemeController::getCustomColorFromDT("kcomponent-alpha-normal"); painter.setPen(Qt::NoPen); } else { if (option.state.testFlag(QStyle::State_MouseOver)) { if (option.state.testFlag(QStyle::State_Sunken)) { backgroundColor = ThemeController::getCustomColorFromDT("kcomponent-alpha-click"); } else { backgroundColor = ThemeController::getCustomColorFromDT("kcomponent-alpha-hover"); } } else { backgroundColor = ThemeController::getCustomColorFromDT("kcomponent-alpha-normal"); } } } } } void KPushButtonPrivate::drawContent(QPainter &painter, QStyleOptionButton &option, QColor &fontColor, QRect &arrowRect, QRect &textRect, QRect &iconRect, QFontMetrics fm, QPixmap &pixmap, QPixmap &arrowPixmap, uint tf, QPoint iconPosition, int iconWidth, int iconHeight, int textWidth) { Q_Q(KPushButton); if (m_isLoading) { iconRect = QRect((q->rect().width() - iconWidth) / 2 + 1, iconPosition.y() - 1, iconWidth, iconHeight); painter.drawPixmap(iconRect, pixmap); } else { if (q->hasArrow()) { if (!q->isEnabled()) { QPen pen; pen.setColor(fontColor); painter.setPen(pen); if (option.icon.isNull()) { textRect = QRect(margin, (option.rect.height() - fm.height()) / 2, option.rect.width() - iconWidth - margin*2 - spacing, fm.height()); if ((fm.horizontalAdvance(option.text) >= textRect.width())) { arrowRect = QRect(textRect.right() + spacing, (option.rect.height() - arrowPixmap.width()) / 2, arrowPixmap.width(), arrowPixmap.height()); QString elidedText = fm.elidedText(option.text, Qt::ElideRight, textRect.width()); painter.drawText(textRect, tf, elidedText); painter.drawPixmap(arrowRect, arrowPixmap); } else { arrowRect = QRect(textRect.right() + spacing, (option.rect.height() - arrowPixmap.width()) / 2, arrowPixmap.width(), arrowPixmap.height()); painter.drawText(textRect, tf, option.text); painter.drawPixmap(arrowRect, arrowPixmap); } } else { painter.drawPixmap(iconRect, pixmap); textRect = QRect(iconPosition.x() + spacing + iconWidth, 0, textWidth - margin - spacing, option.rect.height()); if (fm.horizontalAdvance(option.text) > textRect.width()) { arrowRect = QRect(textRect.right() + spacing, (option.rect.height() - arrowPixmap.width()) / 2, arrowPixmap.width(), arrowPixmap.height()); QString elidedText = fm.elidedText(option.text, Qt::ElideRight, textRect.width()); painter.drawText(textRect, tf, elidedText); painter.drawPixmap(arrowRect, arrowPixmap); } else { textRect = QRect(iconPosition.x() + spacing + iconWidth, 0, fm.horizontalAdvance(option.text), option.rect.height()); arrowRect = QRect(textRect.right() + spacing, (option.rect.height() - arrowPixmap.width()) / 2, arrowPixmap.width(), arrowPixmap.height()); painter.drawText(textRect, tf, option.text); painter.drawPixmap(arrowRect, arrowPixmap); } } } else { if (option.icon.isNull()) { textRect = QRect(margin, (option.rect.height() - fm.height()) / 2, option.rect.width() - iconWidth - margin*2 - spacing, fm.height()); arrowRect = QRect(textRect.right() + spacing, (option.rect.height() - arrowPixmap.width()) / 2, arrowPixmap.width(), arrowPixmap.height()); if (fm.horizontalAdvance(option.text) > textRect.width()) { QString elidedText = fm.elidedText(option.text, Qt::ElideRight, textRect.width()); painter.drawText(textRect, tf, elidedText); painter.drawPixmap(arrowRect, arrowPixmap); } else { painter.drawText(textRect, tf, option.text); painter.drawPixmap(arrowRect, arrowPixmap); } } else { textRect = QRect(iconPosition.x() + spacing + iconWidth, 0, textWidth - margin - spacing, option.rect.height()); painter.drawPixmap(iconRect, pixmap); if (fm.horizontalAdvance(option.text) > textRect.width()) { arrowRect = QRect(textRect.right() + spacing, (option.rect.height() - arrowPixmap.width()) / 2, arrowPixmap.width(), arrowPixmap.height()); QString elidedText = fm.elidedText(option.text, Qt::ElideRight, textRect.width()); painter.drawText(textRect, tf, elidedText); painter.drawPixmap(arrowRect, arrowPixmap); } else { textRect = QRect(iconPosition.x() + spacing + iconWidth, 0, fm.horizontalAdvance(option.text), option.rect.height()); arrowRect = QRect(textRect.right() + spacing, (option.rect.height() - arrowPixmap.width()) / 2, arrowPixmap.width(), arrowPixmap.height()); painter.drawText(textRect, tf, option.text); painter.drawPixmap(arrowRect, arrowPixmap); } } } } else { if (!q->isEnabled()) { qreal opacity = 0.35; fontColor.setAlphaF(opacity); QPen pen; pen.setColor(fontColor); painter.setPen(pen); if (option.icon.isNull()) { QString elidedText = fm.elidedText(option.text, Qt::ElideRight, option.rect.width() - 10); if (fm.horizontalAdvance(option.text) > option.rect.width() - 10) { painter.drawText(option.rect.adjusted(margin, 0, -margin, 0), tf, elidedText); q->setToolTip(option.text); } else { painter.drawText(option.rect.adjusted(margin, 0, -margin, 0), tf, option.text); q->setToolTip(""); } } else { QString elidedText = option.text; if (elidedText.isEmpty()) { iconRect = QRect((q->rect().width() - iconWidth) / 2 + 1, iconPosition.y() - 1, iconWidth, iconHeight); } else { if ((fm.horizontalAdvance(option.text) > option.rect.width() - margin * 2 - spacing - iconWidth)) { iconRect = QRect(margin, iconPosition.y(), iconWidth, iconHeight); textRect = QRect(iconRect.right() + spacing, 0, option.rect.width() - margin * 2 - spacing - iconWidth, option.rect.height()); elidedText = fm.elidedText(option.text, Qt::ElideRight, textRect.width()); q->setToolTip(option.text); } else { textRect = QRect(iconRect.right() + spacing, 0, option.rect.width() - margin * 2 - spacing - iconWidth, option.rect.height()); } } painter.drawPixmap(iconRect, pixmap); painter.drawText(textRect, tf, elidedText); } } else { if (option.icon.isNull()) { if (fm.horizontalAdvance(option.text) > option.rect.width() - 10) { QString elidedText = fm.elidedText(option.text, Qt::ElideRight, option.rect.width() - 10); painter.drawText(option.rect.adjusted(margin, 0, -margin, 0), tf, elidedText); q->setToolTip(option.text); } else { painter.drawText(option.rect.adjusted(margin, 0, -margin, 0), tf, option.text); q->setToolTip(""); } } else { QString elidedText = option.text; if (elidedText.isEmpty()) { iconRect = QRect((q->rect().width() - iconWidth) / 2 + 1, iconPosition.y() - 1, iconWidth, iconHeight); } else { if ((fm.horizontalAdvance(option.text) > option.rect.width() - margin * 2 - spacing - iconWidth)) { iconRect = QRect(margin, iconPosition.y(), iconWidth, iconHeight); textRect = QRect(iconRect.right() + spacing, 0, option.rect.width() - margin * 2 - spacing - iconWidth, option.rect.height()); elidedText = fm.elidedText(option.text, Qt::ElideRight, textRect.width()); q->setToolTip(option.text); } else { textRect = QRect(iconRect.right() + spacing, 0, option.rect.width() - margin * 2 - spacing - iconWidth, option.rect.height()); } } painter.drawPixmap(iconRect, pixmap); painter.drawText(textRect, tf, elidedText); } } } } } } #include "kpushbutton.moc" #include "moc_kpushbutton.cpp" libkysdk-applications/kysdk-qtwidgets/src/kprogressdialog.cpp0000664000175000017500000004105115104543305023631 0ustar fengfeng/* * libkysdk-qtwidgets's Library * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #include "kprogressdialog.h" #include "parmscontroller.h" #include #include "accessinfohelper.h" namespace kdk { class KProgressDialogPrivate : public QObject { Q_OBJECT Q_DECLARE_PUBLIC(KProgressDialog) public: KProgressDialogPrivate(KProgressDialog *parent); void adjustNormalMode(); void infoReset(); void setAccessInfo(); private: KProgressDialog *const q_ptr; QProgressBar *m_pProgressBar; QLabel *m_pMainLabel; QLabel *m_pPercentLabel; QLabel *m_pSubContentLabel; QLabel *m_pProgressLabel; QPushButton *m_pCanelButton; QList m_pButtons; QVBoxLayout *m_pMainLayout; QString m_suffix; QString m_numerator; QString m_denominator; QString m_speed; BarType m_type; bool m_autoClose; bool m_autoReset; bool m_forceHide; int m_maxValue; int m_minVlaue; }; KProgressDialog::KProgressDialog(QWidget *parent) : KDialog(parent) , d_ptr(new KProgressDialogPrivate(this)) { Q_D(KProgressDialog); // setFixedSize(440,265); this->layout()->setSizeConstraint(QLayout::SizeConstraint::SetFixedSize); d->m_pMainLayout = new QVBoxLayout(); d->m_pMainLayout->setContentsMargins(24, 0, 24, 24); d->m_pMainLayout->setSpacing(0); d->m_pMainLabel = new QLabel(this); d->m_pMainLabel->setAlignment(Qt::AlignLeft); d->m_pProgressBar = new QProgressBar(this); d->m_pCanelButton = new QPushButton(this); d->m_pCanelButton->setText(tr("cancel")); d->m_pSubContentLabel = new QLabel(this); d->m_pPercentLabel = new QLabel(this); d->m_pProgressLabel = new QLabel(this); d->m_autoClose = true; d->m_autoReset = true; d->m_forceHide = false; d->m_maxValue = maximum(); d->m_minVlaue = minimum(); d->m_type = BarType::NormalBar; d->adjustNormalMode(); setShowDetail(false); changeTheme(); connect(m_gsetting, &QGSettings::changed, this, &KProgressDialog::changeTheme); connect(this, SIGNAL(canceled()), this, SLOT(cancel())); connect(d->m_pCanelButton, SIGNAL(clicked()), this, SIGNAL(canceled())); d->setAccessInfo(); } KProgressDialog::KProgressDialog(const QString &labelText, const QString &cancelButtonText, int minimum, int maximum, QWidget *parent) : KProgressDialog(parent) { Q_D(KProgressDialog); d->m_pMainLabel->setText(labelText); d->m_pProgressBar->setRange(minimum, maximum); d->m_pCanelButton->setText(cancelButtonText); d->adjustNormalMode(); setShowDetail(true); } KProgressDialog::~KProgressDialog() { } void KProgressDialog::setLabel(QLabel *label) { Q_D(KProgressDialog); if (!label) return; if (d->m_pMainLabel) delete d->m_pMainLabel; d->m_pMainLabel = label; d->m_pMainLabel->setVisible(true); } void KProgressDialog::setCancelButton(QPushButton *button) { Q_D(KProgressDialog); if (!button) return; if (d->m_pCanelButton) delete d->m_pCanelButton; d->m_pCanelButton = button; } void KProgressDialog::setBar(QProgressBar *bar) { Q_D(KProgressDialog); if (!bar) return; if (d->m_pProgressBar) delete d->m_pProgressBar; d->m_pProgressBar = bar; } void KProgressDialog::setSuffix(const QString &suffix) { Q_D(KProgressDialog); if (myType() == BarType::NormalBar) { d->m_suffix = suffix; } d->adjustNormalMode(); } void KProgressDialog::setSuffix(const QString &numerator, const QString &denominator) { Q_D(KProgressDialog); // 加一些type的判断 if (myType() == BarType::SpeedBar) { d->m_numerator = numerator; d->m_denominator = denominator; } d->adjustNormalMode(); } void KProgressDialog::setSpeed(const float &speed) { Q_D(KProgressDialog); d->m_speed = QString::number(speed); if (d->m_type == BarType::SpeedBar) d->m_pProgressLabel->setText(QString("%1 %2/%3").arg(d->m_speed).arg(d->m_numerator).arg(d->m_denominator)); } void KProgressDialog::setShowDetail(bool flag) { Q_D(KProgressDialog); if (flag) { d->m_pSubContentLabel->setVisible(true); d->m_pProgressLabel->setVisible(true); d->m_pPercentLabel->setVisible(true); } else { d->m_pSubContentLabel->setVisible(false); d->m_pProgressLabel->setVisible(false); d->m_pPercentLabel->setVisible(false); } } int KProgressDialog::minimum() const { Q_D(const KProgressDialog); if (d->m_pProgressBar) return d->m_pProgressBar->minimum(); else return -1; } int KProgressDialog::maximum() const { Q_D(const KProgressDialog); if (d->m_pProgressBar) return d->m_pProgressBar->maximum(); else return -1; } int KProgressDialog::value() const { Q_D(const KProgressDialog); if (d->m_pProgressBar) return d->m_pProgressBar->value(); else return -1; } QString KProgressDialog::labelText() const { Q_D(const KProgressDialog); if (d->m_pMainLabel) return d->m_pMainLabel->text(); else { return QString(); } } void KProgressDialog::setAutoReset(bool reset) { Q_D(KProgressDialog); d->m_autoReset = reset; } bool KProgressDialog::autoReset() const { Q_D(const KProgressDialog); return d->m_autoReset; } void KProgressDialog::setAutoClose(bool close) { Q_D(KProgressDialog); d->m_autoClose = close; } bool KProgressDialog::autoClose() const { Q_D(const KProgressDialog); return d->m_autoClose; } QProgressBar *KProgressDialog::progressBar() { Q_D(KProgressDialog); return d->m_pProgressBar; } void KProgressDialog::setBarType(const BarType &type) { Q_D(KProgressDialog); d->m_type = type; if (type == BarType::ScrollBar) { if (d->m_pProgressBar->minimum() != d->m_pProgressBar->maximum() != 0) { d->m_maxValue = d->m_pProgressBar->maximum(); d->m_minVlaue = d->m_pProgressBar->minimum(); } } if (type == BarType::NormalBar) d->m_pProgressLabel->setText(QString("%1%2/%3%4").arg(d->m_pProgressBar->value()).arg(d->m_suffix).arg(maximum()).arg(d->m_suffix)); else if (type == BarType::SpeedBar) d->m_pProgressLabel->setText(QString("%1 %2/%3").arg(d->m_speed).arg(d->m_numerator).arg(d->m_denominator)); d->adjustNormalMode(); } void KProgressDialog::addButton(QPushButton *button) { Q_D(KProgressDialog); if (!d->m_pButtons.contains(button)) { if (d->m_pButtons.count() >= 3) return; if (button) d->m_pButtons.append(button); d->adjustNormalMode(); } } void KProgressDialog::removeButton(QPushButton *button) { Q_D(KProgressDialog); if (d->m_pButtons.contains(button)) { d->m_pButtons.removeAll(button); } d->adjustNormalMode(); } BarType KProgressDialog::myType() { Q_D(KProgressDialog); return d->m_type; } void KProgressDialog::cancel() { Q_D(KProgressDialog); d->m_forceHide = true; reset(); d->m_forceHide = false; } void KProgressDialog::reset() { Q_D(KProgressDialog); if (d->m_autoClose || d->m_forceHide) hide(); d->m_pProgressBar->reset(); d->infoReset(); } void KProgressDialog::setMaximum(int maximum) { Q_D(KProgressDialog); if (d->m_pProgressBar) d->m_pProgressBar->setMaximum(maximum); } void KProgressDialog::setMinimum(int minimum) { Q_D(KProgressDialog); if (d->m_pProgressBar) d->m_pProgressBar->setMinimum(minimum); } void KProgressDialog::setRange(int minimum, int maximum) { Q_D(KProgressDialog); if (d->m_pProgressBar) d->m_pProgressBar->setRange(minimum, maximum); } void KProgressDialog::setValue(int progress) { Q_D(KProgressDialog); if (d->m_pProgressBar) d->m_pProgressBar->setValue(progress); if (d->m_pPercentLabel) d->m_pPercentLabel->setText(QString::number(progress * 100 / maximum()) + "%"); if (d->m_pProgressLabel) { if (d->m_type != BarType::SpeedBar) d->m_pProgressLabel->setText(QString("%1%2/%3%4").arg(progress).arg(d->m_suffix).arg(maximum()).arg(d->m_suffix)); // else // d->m_pProgressLabel->setText(QString("%1 %2/%3").arg(d->m_speed).arg(d->m_numerator).arg(d->m_denominator)); } } void KProgressDialog::setLabelText(const QString &text) { Q_D(KProgressDialog); if (d->m_pMainLabel) d->m_pMainLabel->setText(text); } void KProgressDialog::setCancelButtonText(const QString &text) { Q_D(KProgressDialog); if (d->m_pCanelButton) d->m_pCanelButton->setText(text); } void KProgressDialog::setSubContent(const QString &text) { Q_D(KProgressDialog); if (d->m_pSubContentLabel) { d->m_pSubContentLabel->setText(text); setShowDetail(true); } } void KProgressDialog::changeTheme() { Q_D(KProgressDialog); KDialog::changeTheme(); QFont font; font.setPixelSize(ThemeController::systemFontSize() * 1.7); d->m_pMainLabel->setFont(font); font.setPixelSize(ThemeController::systemFontSize() * 1.2); d->m_pPercentLabel->setFont(font); d->m_pSubContentLabel->setFont(font); d->m_pProgressLabel->setFont(font); } KProgressDialogPrivate::KProgressDialogPrivate(KProgressDialog *parent) : q_ptr(parent) { setParent(parent); } void KProgressDialogPrivate::adjustNormalMode() { Q_Q(KProgressDialog); QLayoutItem *child; while ((child = m_pMainLayout->takeAt(0)) != 0) { // 删除Stretch(弹簧)等布局 if (child->spacerItem()) { m_pMainLayout->removeItem(child); continue; } // 删除layout else if (child->layout()) { QLayoutItem *item = child->layout()->takeAt(0); while (item != 0) { child->layout()->removeItem(item); delete item; item = child->layout()->takeAt(0); } } else // 删除布局 { m_pMainLayout->removeWidget(child->widget()); child->widget()->setParent(nullptr); } delete child; child = nullptr; } q->mainWidget()->setLayout(m_pMainLayout); switch (m_type) { case BarType::NothingBar: { m_pProgressBar->setTextVisible(false); m_pMainLayout->addStretch(); m_pMainLayout->addSpacing(24); m_pMainLayout->addWidget(m_pMainLabel); m_pMainLayout->addSpacing(8); m_pProgressBar->setMaximum(m_maxValue); m_pProgressBar->setMinimum(m_minVlaue); m_pProgressBar->setFixedHeight(8); QHBoxLayout *hLayout = new QHBoxLayout; hLayout->setSpacing(0); hLayout->addWidget(m_pProgressBar); hLayout->addSpacing(8); hLayout->addWidget(m_pPercentLabel); m_pMainLayout->addLayout(hLayout); m_pProgressBar->show(); m_pSubContentLabel->hide(); m_pPercentLabel->show(); m_pProgressLabel->hide(); m_pCanelButton->hide(); q->iconBar()->setFixedHeight(0); q->windowButtonBar()->setVisible(false); break; } case BarType::NormalBar: { q->iconBar()->setFixedHeight(Parmscontroller::parm(Parmscontroller::Parm::PM_IconbarHeight)); q->iconBar()->show(); m_pProgressBar->setTextVisible(true); m_pMainLayout->addStretch(); m_pMainLayout->addSpacing(30); m_pMainLayout->addWidget(m_pMainLabel); m_pMainLayout->addSpacing(10); m_pMainLayout->addWidget(m_pProgressBar); m_pProgressBar->setMaximum(m_maxValue); m_pProgressBar->setMinimum(m_minVlaue); m_pProgressBar->setFixedHeight(8); QHBoxLayout *hLayout = new QHBoxLayout; hLayout->setSpacing(0); hLayout->addWidget(m_pSubContentLabel); hLayout->addStretch(); hLayout->addWidget(m_pPercentLabel); hLayout->addSpacing(15); hLayout->addWidget(m_pProgressLabel); m_pMainLayout->addLayout(hLayout); hLayout = new QHBoxLayout; hLayout->addStretch(); hLayout->addWidget(m_pCanelButton); m_pMainLayout->addSpacing(30); m_pMainLayout->addLayout(hLayout); m_pProgressBar->show(); m_pSubContentLabel->show(); m_pPercentLabel->show(); m_pProgressLabel->show(); m_pCanelButton->show(); q->windowButtonBar()->setVisible(true); break; } case BarType::ScrollBar: { m_pProgressBar->setTextVisible(false); m_pProgressBar->setMaximum(0); m_pProgressBar->setMinimum(0); m_pProgressBar->setFixedHeight(30); m_pMainLayout->addStretch(); m_pMainLayout->addSpacing(24); m_pMainLayout->addWidget(m_pMainLabel); m_pMainLayout->addSpacing(8); m_pMainLayout->addWidget(m_pProgressBar); q->iconBar()->setFixedHeight(0); m_pSubContentLabel->hide(); m_pPercentLabel->hide(); m_pProgressLabel->hide(); m_pCanelButton->hide(); q->windowButtonBar()->setVisible(false); break; } case BarType::SpeedBar: { q->iconBar()->setFixedHeight(Parmscontroller::parm(Parmscontroller::Parm::PM_IconbarHeight)); q->iconBar()->hide(); m_pProgressBar->setTextVisible(false); m_pMainLayout->addStretch(); m_pMainLayout->addSpacing(4); m_pMainLayout->addWidget(m_pMainLabel); m_pMainLayout->addSpacing(8); m_pProgressBar->setMaximum(m_maxValue); m_pProgressBar->setMinimum(m_minVlaue); QHBoxLayout *hLayout = new QHBoxLayout; hLayout->setSpacing(0); hLayout->addWidget(m_pProgressBar); hLayout->addSpacing(8); hLayout->addWidget(m_pPercentLabel); m_pMainLayout->addLayout(hLayout); hLayout = new QHBoxLayout; hLayout->setSpacing(0); hLayout->addWidget(m_pSubContentLabel); hLayout->addStretch(); hLayout->addWidget(m_pProgressLabel); hLayout->addSpacing(36); m_pMainLayout->addSpacing(4); m_pMainLayout->addLayout(hLayout); hLayout = new QHBoxLayout; if (!m_pButtons.isEmpty()) { if (m_pButtons.count() == 1) { hLayout->addStretch(); hLayout->addWidget((m_pButtons.first())); } else if (m_pButtons.count() == 2) { hLayout->addStretch(); hLayout->addWidget(m_pButtons[1]); hLayout->addSpacing(8); hLayout->addWidget(m_pButtons[0]); } else { hLayout->addWidget(m_pButtons[2]); hLayout->addStretch(); hLayout->addWidget(m_pButtons[1]); hLayout->addSpacing(8); hLayout->addWidget(m_pButtons[0]); } } m_pMainLayout->addSpacing(32); m_pMainLayout->addLayout(hLayout); m_pMainLayout->addStretch(); m_pProgressBar->show(); m_pSubContentLabel->show(); m_pPercentLabel->show(); m_pProgressLabel->show(); m_pCanelButton->hide(); q->windowButtonBar()->setVisible(true); break; } default: break; } } void KProgressDialogPrivate::infoReset() { Q_Q(KProgressDialog); if (m_pPercentLabel) m_pPercentLabel->setText(+"0%"); if (m_pProgressLabel) { if (m_type != BarType::SpeedBar) m_pProgressLabel->setText(QString("%1%2/%3%4").arg(0).arg(m_suffix).arg(q->maximum()).arg(m_suffix)); else m_pProgressLabel->setText(QString("%1 %2/%3").arg(0).arg(m_numerator).arg(m_denominator)); } } void KProgressDialogPrivate::setAccessInfo() { Q_Q(KProgressDialog); KDK_ALL_INFO_FORMAT(m_pProgressBar,""); KDK_ALL_INFO_FORMAT(m_pMainLabel,""); KDK_ALL_INFO_FORMAT(m_pPercentLabel,""); KDK_ALL_INFO_FORMAT(m_pSubContentLabel,""); KDK_ALL_INFO_FORMAT(m_pProgressLabel,""); KDK_ALL_INFO_FORMAT(m_pCanelButton,""); } } #include "kprogressdialog.moc" #include "moc_kprogressdialog.cpp" libkysdk-applications/kysdk-qtwidgets/src/ktableheaderview.cpp0000664000175000017500000001515415104543305023745 0ustar fengfeng/* * libkysdk-qtwidgets's Library * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhenyu Wang * */ #include "ktableheaderview.h" #include "themeController.h" #include #include #include #include #include #include #include #include #include namespace kdk { class Q_DECL_HIDDEN KTableHeaderViewPrivate : public QObject, public ThemeController { Q_OBJECT Q_DECLARE_PUBLIC(KTableHeaderView) public: KTableHeaderViewPrivate(KTableHeaderView *PARENT); void changeTheme(); private: KTableHeaderView *q_ptr; QStringList m_HeaderList; bool m_bChecked; bool m_bTristate; bool m_bNoChange; bool m_bPressed; QMap m_map; }; KTableHeaderView::KTableHeaderView(Qt::Orientation orientation, QWidget *parent) : QHeaderView(orientation, parent) , d_ptr(new KTableHeaderViewPrivate(this)) { Q_D(KTableHeaderView); // 设置Section可点击,若不设置则不能发出sectionClicked信号 this->setSectionsClickable(true); connect(this, &KTableHeaderView::clickedHeader, this, [=](int column) { if (d->m_map.contains(column)) { d->m_map.value(column)->exec(QCursor::pos()); } }); } void KTableHeaderView::setTitle(QStringList list) { Q_D(KTableHeaderView); d->m_HeaderList = list; } void KTableHeaderView::setMenu(QMenu *menu, int column) { Q_D(KTableHeaderView); d->m_map.insert(column, menu); } void KTableHeaderView::paintSection(QPainter *painter, const QRect &rect, int logicalIndex) const { Q_D(const KTableHeaderView); painter->save(); QHeaderView::paintSection(painter, rect, logicalIndex); painter->restore(); if (logicalIndex == 0) { QStyleOptionButton option; option.initFrom(this); if (d->m_bTristate && d->m_bNoChange) { option.state |= QStyle::State_NoChange; } else option.state |= d->m_bChecked ? QStyle::State_On : QStyle::State_Off; option.iconSize = QSize(16, 16); option.rect = QRect(rect.x() + 8, rect.y() + (rect.height() - 16) / 2, 16, 16); style()->drawPrimitive(QStyle::PE_IndicatorCheckBox, &option, painter, this); } else { if (d->m_map.contains(logicalIndex)) { QPixmap pixmap = QIcon::fromTheme("ukui-down-symbolic").pixmap(16, 16); if (ThemeController::themeMode() == DarkTheme) pixmap = ThemeController::drawSymbolicColoredPixmap(pixmap); QRect iconRect(rect.right() - 24, rect.height() / 2 - 8, 16, 16); painter->drawPixmap(iconRect, pixmap); } } QRect textRect; if (logicalIndex > -1 || logicalIndex < d->m_HeaderList.size()) { if (logicalIndex == 0) { textRect = rect.adjusted(32, 0, 0, 0); if (fontMetrics().horizontalAdvance(d->m_HeaderList.at(logicalIndex)) > textRect.width()) { QString str = fontMetrics().elidedText(d->m_HeaderList.at(logicalIndex), Qt::ElideRight, textRect.width()); painter->drawText(textRect, Qt::AlignVCenter, str); } else painter->drawText(textRect, Qt::AlignVCenter, d->m_HeaderList.at(logicalIndex)); } else { if (d->m_map.contains(logicalIndex)) textRect = rect.adjusted(6, 0, -24, 0); else textRect = rect.adjusted(6, 0, -6, 0); if (fontMetrics().horizontalAdvance(d->m_HeaderList.at(logicalIndex)) > textRect.width()) { QString str = fontMetrics().elidedText(d->m_HeaderList.at(logicalIndex), Qt::ElideRight, textRect.width()); painter->drawText(textRect, Qt::AlignVCenter, str); } else painter->drawText(textRect, Qt::AlignVCenter, d->m_HeaderList.at(logicalIndex)); } } } void KTableHeaderView::mousePressEvent(QMouseEvent *e) { Q_D(KTableHeaderView); int nColumn = logicalIndexAt(e->pos()); if ((e->buttons() & Qt::LeftButton)) { if (nColumn == 0) d->m_bPressed = true; else { // 每个标题栏的rect QRect tabRect(sectionPosition(nColumn), 0, sectionSize(nColumn), viewport()->rect().height()); // 是否在图标区域被点击 QRect sectionRect(tabRect.right() - 24, tabRect.y() + (tabRect.height() - 16) / 2, 16, 16); if (sectionRect.contains(e->pos()) && d->m_map.contains(nColumn)) emit clickedHeader(nColumn); QHeaderView::mousePressEvent(e); } } else { QHeaderView::mousePressEvent(e); } viewport()->update(); } void KTableHeaderView::mouseReleaseEvent(QMouseEvent *e) { Q_D(KTableHeaderView); if (d->m_bPressed) { if (d->m_bTristate && d->m_bNoChange) { d->m_bChecked = true; d->m_bNoChange = false; } else { d->m_bChecked = !d->m_bChecked; } } else { QHeaderView::mouseReleaseEvent(e); } this->viewport()->update(); d->m_bPressed = false; if (d->m_bChecked) emit checkStateChange(Qt::Checked); else emit checkStateChange(Qt::Unchecked); } bool KTableHeaderView::event(QEvent *e) { this->viewport()->update(); return QHeaderView::event(e); } void KTableHeaderView::checkStateChangeSlot(int iState) { Q_D(KTableHeaderView); if (iState == Qt::PartiallyChecked) { d->m_bTristate = true; d->m_bNoChange = true; } else { d->m_bNoChange = false; } d->m_bChecked = (iState != Qt::Unchecked); this->viewport()->update(); } KTableHeaderViewPrivate::KTableHeaderViewPrivate(KTableHeaderView *parent) : q_ptr(parent) , m_bTristate(false) , m_bNoChange(false) , m_bChecked(false) , m_bPressed(false) { } void KTableHeaderViewPrivate::changeTheme() { Q_Q(KTableHeaderView); initThemeStyle(); } } #include "ktableheaderview.moc" #include "moc_ktableheaderview.cpp" libkysdk-applications/kysdk-qtwidgets/src/kcomboboxframe.h0000664000175000017500000000363215104543305023100 0ustar fengfeng/* * * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Sisheng He * */ #ifndef KCOMBOBOXFRAME_H #define KCOMBOBOXFRAME_H #include "klabel.h" #include #include #include "kbaseframe.h" namespace kdk { /** * @defgroup ContainerModules * @brief 存在combox的frame * @since 3.0.1.0 * { */ class KComboBoxFramePrivate; class KComboBoxFrame : public KBaseFrame { Q_OBJECT public: /** * @brief 创建一个带 QComboBox 的 Frame * * @param title: text of m_settingName * @param style: 设置圆角(None:无圆角,Top:上圆角,Bottom:下圆角,Around:四圆角) * @param parent */ explicit KComboBoxFrame(const QString title, QWidget *parent = nullptr, BorderRadiusStyle style = BorderRadiusStyle::None); ~KComboBoxFrame(); /** * @brief 获取label * * @return QLabel */ KLabel *titleLabel(); /** * @brief 获取layout * * @return QHBoxLayout */ QHBoxLayout *mainHLayout(); /** * @brief 获取下拉框控件 * * @return QComboBox */ QComboBox *comboBox(); private: Q_DECLARE_PRIVATE(KComboBoxFrame) KComboBoxFramePrivate *const d_ptr; }; } #endif // KCOMBOBOXFRAME_H libkysdk-applications/kysdk-qtwidgets/src/kmenubutton.h0000664000175000017500000000514515104543305022456 0ustar fengfeng/* * libkysdk-qtwidgets's Library * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #ifndef KMENUBUTTON_H #define KMENUBUTTON_H #include "gui_g.h" #include "themeController.h" #include #include #include #include namespace kdk { /** * @defgroup PushbuttonModule * @{ */ class KMenuButtonPrivate; /** * @brief 下拉菜单按钮 * @since 1.0.0 */ class GUI_EXPORT KMenuButton : public QToolButton, public ThemeController { Q_OBJECT public: KMenuButton(QWidget *parent = nullptr); ~KMenuButton(); /** * @brief 获取主菜单 * @return */ QMenu *menu(); /** * @brief 获取主题菜单 * @return */ QMenu *themeMenu(); /** * @brief 获取设置action * @return */ QAction *settingAction(); /** * @brief 获取主题Action * @return */ QAction *themeAction(); /** * @brief 获取帮助Action * @return */ QAction *assistAction(); /** * @brief 获取关于Action * @return */ QAction *aboutAction(); /** * @brief 获取意见反馈Action * @since 2.4.1.0-0k1.0 * @return */ QAction *feedbackAction(); /** * @brief 获取离开Action * @return */ QAction *quitAction(); /** * @brief 获取跟随主题Action * @return */ QAction *autoAction(); /** * @brief 获取浅色主题Action * @return */ QAction *lightAction(); /** * @brief 获取深色Action * @return */ QAction *darkAction(); protected: void changeTheme() override; void paintEvent(QPaintEvent *painteEvent); QSize sizeHint() const override; private: Q_DECLARE_PRIVATE(KMenuButton) KMenuButtonPrivate *const d_ptr; }; } /** * @example testWidget/testwidget.h * @example testWidget/testwidget.cpp * @} */ #endif // KMENUBUTTON_H libkysdk-applications/kysdk-qtwidgets/src/kflowlayout.h0000664000175000017500000000522515104543305022462 0ustar fengfeng/* * * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Sisheng He * */ #ifndef KFLOWLAYOUT_H #define KFLOWLAYOUT_H #include #include #include namespace kdk { /** * @defgroup LayoutModule * @brief 存在水平间距、垂直间距的布局 * @since 3.0.1.0 * { */ class KFlowLayoutPrivate; class KFlowLayout : public QLayout { Q_OBJECT public: /** * @brief 创建一个父对象为parent,边距为margin,水平间距为hSpacing,垂直间距为vSpacing的布局。 * * @param home 是否首页布局 * @param margin 边距 * @param hSpacing 水平间距 * @param vSpacing 垂直间距 * @param parent */ explicit KFlowLayout(QWidget *parent, bool home = false, int margin = -1, int hSpacing = -1, int vSpacing = -1); /** * @brief 创建一个边距为margin,水平间距为hSpacing,垂直间距为vSpacing的布局。 * * @param margin 边距 * @param hSpacing 水平间距 * @param vSpacing 垂直间距 */ explicit KFlowLayout(int margin = -1, int hSpacing = -1, int vSpacing = -1); ~KFlowLayout(); public: /** * @brief 水平间距 * * @param 无 */ int horizontalSpacing() const; /** * @brief 垂直间距 * * @param 无 */ int verticalSpacing() const; protected: void addItem(QLayoutItem *item) Q_DECL_OVERRIDE; Qt::Orientations expandingDirections() const Q_DECL_OVERRIDE; bool hasHeightForWidth() const Q_DECL_OVERRIDE; int heightForWidth(int) const Q_DECL_OVERRIDE; int count() const Q_DECL_OVERRIDE; QLayoutItem *itemAt(int index) const Q_DECL_OVERRIDE; QSize minimumSize() const Q_DECL_OVERRIDE; void setGeometry(const QRect &rect) Q_DECL_OVERRIDE; QSize sizeHint() const Q_DECL_OVERRIDE; QLayoutItem *takeAt(int index) Q_DECL_OVERRIDE; private: Q_DECLARE_PRIVATE(KFlowLayout) KFlowLayoutPrivate *const d_ptr; }; } #endif // KFLOWLAYOUT_H libkysdk-applications/kysdk-qtwidgets/src/ksettinggroup.cpp0000664000175000017500000001523615104543305023345 0ustar fengfeng/* * * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Sisheng He * */ #include "ksettinggroup.h" #include namespace kdk { class KSettingGroupPrivate : public QObject { Q_OBJECT Q_DECLARE_PUBLIC(KSettingGroup) public: KSettingGroupPrivate(KSettingGroup *parent); private: KSettingGroup *q_ptr; QVBoxLayout *m_pMainLayout; KBaseFrame::BorderRadiusStyle m_lastRadiusStyle = KBaseFrame::BorderRadiusStyle::Bottom; KBaseFrame::BorderRadiusStyle m_OneRadiusStyle = KBaseFrame::BorderRadiusStyle::Around; QList m_showItemList; QList m_allItemList; private: /** * 递归添加显示出来的 KBaseFrame */ void updateShowItemList(KBaseFrame *frame); /** * 递归获取所有 KBaseFrame */ void updateAllItemList(KBaseFrame *frame); }; KSettingGroupPrivate::KSettingGroupPrivate(KSettingGroup *parent) : q_ptr(parent) { Q_Q(KSettingGroup); m_pMainLayout = new QVBoxLayout(q); m_pMainLayout->setSpacing(1); m_pMainLayout->setContentsMargins(0, 0, 0, 0); q->setLayout(m_pMainLayout); qApp->installEventFilter(q); q->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed); } void KSettingGroupPrivate::updateAllItemList(KBaseFrame *frame) { if (frame->isContainer() && frame->frameShape() == QFrame::NoFrame && frame->layout()) { for (int i = 0; i < frame->layout()->count(); i++) { QLayoutItem *it = frame->layout()->itemAt(i); KBaseFrame *item = qobject_cast(it->widget()); if (!item) { continue; } updateAllItemList(item); } } else { m_allItemList.append(frame); return; } } void KSettingGroupPrivate::updateShowItemList(KBaseFrame *frame) { Q_Q(KSettingGroup); if (frame->isContainer() && frame->frameShape() == QFrame::NoFrame && frame->layout()) { for (int i = 0; i < frame->layout()->count(); i++) { QLayoutItem *it = frame->layout()->itemAt(i); KBaseFrame *item = qobject_cast(it->widget()); if (!item) { continue; } updateShowItemList(item); } } else { if (frame->isVisibleTo(q)) { m_showItemList.append(frame); } return; } } KSettingGroup::KSettingGroup(QWidget *parent, Shape shape, BorderRadiusStyle style) : KBaseFrame(parent, style, false) , d_ptr(new KSettingGroupPrivate(this)) { Q_D(KSettingGroup); setFrameShape(shape); } KSettingGroup::~KSettingGroup() { } void KSettingGroup::addWidget(QFrame *item, bool autoUpdateShape, bool visible) { Q_D(KSettingGroup); d->m_pMainLayout->addWidget(item, autoUpdateShape); item->setVisible(visible); if (autoUpdateShape) { updateShape(); } } void KSettingGroup::insertWidget(int index, QFrame *item, bool autoUpdateShape, bool visible) { Q_D(KSettingGroup); d->m_pMainLayout->insertWidget(index, item); item->setVisible(visible); if (autoUpdateShape) { updateShape(); } } void KSettingGroup::removeWidget(QWidget *w, bool autoUpdateShape) { Q_D(KSettingGroup); d->m_pMainLayout->removeWidget(w); if (autoUpdateShape) { updateShape(); } } void KSettingGroup::updateShape() { Q_D(KSettingGroup); d->m_showItemList.clear(); for (int i = 0; i < d->m_pMainLayout->count(); i++) { QLayoutItem *it = d->m_pMainLayout->itemAt(i); KBaseFrame *item = qobject_cast(it->widget()); if (!item) { continue; } d->updateShowItemList(item); } for (int i = 0; i < d->m_showItemList.size(); i++) { KBaseFrame *item = d->m_showItemList.at(i); if (d->m_showItemList.size() == 1) { item->setRadiusType(d->m_OneRadiusStyle); } else if (i == 0) { item->setRadiusType(BorderRadiusStyle::Top); } else if (i == d->m_showItemList.size() - 1) { item->setRadiusType(d->m_lastRadiusStyle); } else { item->setRadiusType(BorderRadiusStyle::None); } } } QVBoxLayout *KSettingGroup::layout() { Q_D(KSettingGroup); return d->m_pMainLayout; } void KSettingGroup::setLastRadiusStyle(BorderRadiusStyle style) { Q_D(KSettingGroup); d->m_lastRadiusStyle = style; } void KSettingGroup::setOneRadiusStyle(BorderRadiusStyle style) { Q_D(KSettingGroup); d->m_OneRadiusStyle = style; } bool KSettingGroup::eventFilter(QObject *watched, QEvent *event) { Q_D(KSettingGroup); if (event->type() == QEvent::Hide || event->type() == QEvent::Show) { d->m_allItemList.clear(); for (int i = 0; i < d->m_pMainLayout->count(); i++) { QLayoutItem *it = d->m_pMainLayout->itemAt(i); KBaseFrame *item = qobject_cast(it->widget()); d->updateAllItemList(item); } for (int i = 0; i < d->m_allItemList.size(); i++) { if (d->m_allItemList.at(i) == watched) { updateShape(); } } } return KBaseFrame::eventFilter(watched, event); } int KSettingGroup::showItemsCount() { Q_D(KSettingGroup); d->m_showItemList.clear(); for (int i = 0; i < d->m_pMainLayout->count(); i++) { QLayoutItem *it = d->m_pMainLayout->itemAt(i); KBaseFrame *item = qobject_cast(it->widget()); if (!item) { continue; } d->updateShowItemList(item); } return d->m_showItemList.size(); } void KSettingGroup::removeAndDeleteAllWidget() { Q_D(KSettingGroup); while (d->m_pMainLayout->count() > 0) { QLayoutItem *it = d->m_pMainLayout->itemAt(0); KBaseFrame *item = qobject_cast(it->widget()); if (!item) { continue; } d->m_pMainLayout->removeWidget(item); item->deleteLater(); item = nullptr; } return; } } #include "ksettinggroup.moc" #include "moc_ksettinggroup.cpp" libkysdk-applications/kysdk-qtwidgets/src/kslider.cpp0000664000175000017500000007220615104543305022075 0ustar fengfeng/* * libkysdk-qtwidgets's Library * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #include "kslider.h" #include "parmscontroller.h" #include "themeController.h" #include #include #include #include #include #include #include #include #include #include #include using namespace kdk; namespace kdk { static const int node_radius = 5; static const int handle_radius = 10; static const int spaceing = handle_radius + 2; static const int line_width = 4; static const int line_border_radius = 2; class KSliderPrivate : public QObject, public ThemeController { Q_DECLARE_PUBLIC(KSlider) public: KSliderPrivate(KSlider *parent); ~KSliderPrivate(); void animationStart(); private: KSlider *q_ptr; KSliderType m_sliderType; void drawCoverNode(QPainter *painter); void drawSlider(QPainter *painter); void locateNode(); void drawBasePath(QPainter *painter); void drawCoverLine(QPainter *painter); void updateValuePosition(); void updateValue(); void updateColor(QPalette palette); void changeTheme(); QRect baseLineRect(); QRect coverLineRect(); QList m_nodes; bool m_isPressed; bool m_isHovered; int m_valuePosition; QPoint m_currentpos; QColor m_baseColor; QColor m_coverColor; QColor m_startColor; QColor m_endColor; bool m_nodeVisible; QRect m_rect; QString m_pToolTipText; QLinearGradient m_linearGradient; bool m_isTranslucent; bool m_isTranslucentFlag; int m_handleRadius; QVariantAnimation *m_animation; bool m_animationStarted; bool m_ismoving; bool m_resize; bool m_forceUpdate; QTime m_clickTime; }; KSliderPrivate::KSliderPrivate(KSlider *parent) : q_ptr(parent) , m_sliderType(SmoothSlider) , m_isPressed(false) , m_isHovered(false) , m_valuePosition(0) , m_currentpos(QPoint(0, 0)) , m_nodeVisible(true) , m_handleRadius(0) , m_animationStarted(false) , m_ismoving(false) , m_resize(false) , m_forceUpdate(false) , m_isTranslucent(false) , m_isTranslucentFlag(false) { Q_Q(KSlider); q->setProperty("animation", false); QStyleOptionSlider sliderOption; m_animation = new QVariantAnimation(this); m_animation->setDuration(150); m_animation->setEasingCurve(QEasingCurve::InOutQuad); connect(m_animation, &QVariantAnimation::finished, q, [=]() { m_animationStarted = false; if (m_animation->endValue().toInt() != m_valuePosition) q->update(); }); connect(m_animation, &QVariantAnimation::valueChanged, q, [=]() { q->update(); }); animationStart(); connect(q, &KSlider::valueChanged, this, [=]() { animationStart(); }); connect(q, &KSlider::sliderReleased, this, [=]() { if(m_isPressed) m_isPressed = false; }); // 获取滑动块大小 QRect handle = q->style()->proxy()->subControlRect(QStyle::CC_Slider, &sliderOption, QStyle::SC_SliderHandle, q); m_handleRadius = handle.width() / 2; } KSliderPrivate::~KSliderPrivate() { } void KSliderPrivate::animationStart() { Q_Q(KSlider); // int prePosition = m_valuePosition; updateValuePosition(); // if ((m_forceUpdate || !m_animationStarted) && !m_ismoving) { // m_animation->stop(); // m_animation->setStartValue(prePosition); // m_animation->setEndValue(m_valuePosition); // m_animation->start(); // m_animationStarted = true; // m_forceUpdate = false; // m_resize = false; // } } void KSliderPrivate::drawCoverNode(QPainter *painter) { Q_Q(KSlider); painter->setRenderHint(QPainter::Antialiasing); painter->setPen(Qt::NoPen); painter->setBrush(ThemeController::getCustomColorFromDT("highlight-active")); int side = 0; if(q->isEnabled()) painter->setBrush(ThemeController::getCustomColorFromDT("kbrand-normal")); else painter->setBrush(ThemeController::getCustomColorFromDT("kbrand-disable")); if (q->orientation() == Qt::Horizontal) { for (auto point : m_nodes) { if (m_ismoving) side = m_currentpos.x(); else if (m_resize) side = m_valuePosition; else side = m_animation->currentValue().toInt(); QRect rect(point.x() - 1, point.y() - 5, 3, 10); if (point.x() <= side) { int radius = ThemeController::getRadiusFromDT("kradius-min"); painter->drawRoundedRect(rect,radius,radius); // 选中基点 } } } else { for (auto point : m_nodes) { if (m_ismoving) side = m_currentpos.y(); else if (m_resize) side = m_valuePosition; else side = m_animation->currentValue().toInt(); QRect rect(point.x() - 5, point.y() - 3, 10, 3); if (point.y() >= side) { int radius = ThemeController::getRadiusFromDT("kradius-min"); painter->drawRoundedRect(rect,radius,radius); // 选中基点 } } } } void KSliderPrivate::drawSlider(QPainter *painter) { Q_Q(KSlider); painter->setRenderHint(QPainter::Antialiasing); painter->setBrush(Qt::white); QPen pen ; // if (ThemeController::widgetTheme() == FashionTheme && m_isHovered && !m_isPressed && q->isEnabled()) { pen.setBrush(m_linearGradient); pen.setWidth(3); painter->setPen(pen); // 获取滑动块大小 int handle_radius = Parmscontroller::parm(Parmscontroller::Parm::PM_SliderHandleRadius) / 2 - 2; QPoint point; if (q->orientation() == Qt::Horizontal) { int x = 0; if (m_ismoving) x = m_currentpos.x(); else if (m_resize) x = m_valuePosition; else x = m_animation->currentValue().toInt(); point = QPoint(x, q->height() / 2); } else { int y = 0; if (m_ismoving) y = m_currentpos.y(); else if (m_resize) y = m_valuePosition; else y = m_animation->currentValue().toInt(); point = QPoint(q->width() / 2, y); } if( (!m_isPressed && !m_isHovered && q->isEnabled() ) || !q->isEnabled()) handle_radius = handle_radius - 2; painter->drawEllipse(point, handle_radius, handle_radius); m_rect = QRect(point.x() - handle_radius, point.y() - handle_radius, handle_radius * 2 , handle_radius * 2); } void KSliderPrivate::locateNode() { Q_Q(KSlider); if (q->orientation() == Qt::Horizontal) { m_nodes.clear(); if (q->layoutDirection() == Qt::LeftToRight) { QPoint beginNode(baseLineRect().left(), q->height() / 2); QPoint endNode(baseLineRect().right(), q->height() / 2); m_nodes.append(beginNode); if (!q->tickInterval()) { m_nodes.append(endNode); return; } for (int i = q->minimum() + q->tickInterval(); i < q->maximum(); i += q->tickInterval()) { QPoint point; int x = baseLineRect().left() + baseLineRect().width() * (i - q->minimum()) / (q->maximum() - q->minimum()); int y = q->height() / 2; point.setX(x); point.setY(y); m_nodes.append(point); } m_nodes.append(endNode); } else { QPoint beginNode(baseLineRect().right(), q->height() / 2); QPoint endNode(baseLineRect().left(), q->height() / 2); m_nodes.append(beginNode); if (!q->tickInterval()) { m_nodes.append(endNode); return; } for (int i = q->minimum() + q->tickInterval(); i < q->maximum(); i += q->tickInterval()) { QPoint point; int x = baseLineRect().right() - baseLineRect().width() * (i - q->minimum()) / (q->maximum() - q->minimum()); int y = q->height() / 2; point.setX(x); point.setY(y); m_nodes.append(point); } m_nodes.append(endNode); } } else { m_nodes.clear(); QPoint beginNode(q->width() / 2, baseLineRect().bottom()); QPoint endNode(q->width() / 2, baseLineRect().top()); m_nodes.append(beginNode); if (!q->tickInterval()) { m_nodes.append(endNode); return; } for (int i = q->minimum() + q->tickInterval(); i < q->maximum(); i += q->tickInterval()) { QPoint point; int x = q->width() / 2; int y = baseLineRect().top() + baseLineRect().height() * (i - q->minimum()) / (q->maximum() - q->minimum()); point.setX(x); point.setY(y); m_nodes.append(point); } m_nodes.append(endNode); } } void KSliderPrivate::drawBasePath(QPainter *painter) { Q_Q(KSlider); painter->setRenderHint(QPainter::Antialiasing); painter->setPen(Qt::NoPen); painter->setBrush(m_baseColor); QPainterPath basePath; basePath.addRoundedRect(this->baseLineRect(), line_border_radius, line_border_radius); QColor color; color = ThemeController::getCustomColorFromDT("kcomponent-alpha-normal"); basePath.addRect(this->baseLineRect()); painter->setBrush(m_baseColor); if (m_nodeVisible) { painter->setBrush(color); for (auto point : m_nodes) { if (q->orientation() == Qt::Horizontal) basePath.addRect(point.x() - 1, point.y() - 5, 3, 10); else basePath.addRect(point.x() - 5, point.y() - 3, 10, 3); } } basePath.setFillRule(Qt::FillRule::WindingFill); painter->drawPath(basePath.simplified()); } void KSliderPrivate::drawCoverLine(QPainter *painter) { Q_Q(KSlider); painter->setRenderHint(QPainter::Antialiasing); painter->setPen(Qt::NoPen); painter->setBrush(m_coverColor); painter->drawRoundedRect(this->coverLineRect(), line_border_radius, line_border_radius); } void KSliderPrivate::updateValuePosition() { Q_Q(KSlider); int prePosition = m_valuePosition; if (q->orientation() == Qt::Horizontal) { if (q->layoutDirection() == Qt::LeftToRight) { if (q->maximum() != q->minimum()) m_valuePosition = this->baseLineRect().left() + this->baseLineRect().width() * (q->value() - q->minimum()) / (q->maximum() - q->minimum()); } else { if (q->maximum() != q->minimum()) { m_valuePosition = this->baseLineRect().adjusted(0, 0, 1, 0).right() - this->baseLineRect().width() * (q->value() - q->minimum()) / (q->maximum() - q->minimum()); } } } else { if (q->maximum() != q->minimum()) m_valuePosition = this->baseLineRect().top() + this->baseLineRect().height() - this->baseLineRect().height() * (q->value() - q->minimum()) / (q->maximum() - q->minimum()); } if ((m_forceUpdate || !m_animationStarted) && !m_ismoving) { m_animation->stop(); m_animation->setStartValue(prePosition); m_animation->setEndValue(m_valuePosition); m_animation->start(); m_animationStarted = true; m_resize = false; } } void KSliderPrivate::updateValue() { Q_Q(KSlider); int dur = q->maximum() - q->minimum(); int pos, value; int step = q->singleStep(); int nodeInterval = q->tickInterval(); if (q->orientation() == Qt::Horizontal) { int left, width, right; if (q->layoutDirection() == Qt::LeftToRight) { if (m_currentpos.x() > baseLineRect().right()) value = q->maximum(); else if (m_currentpos.x() < baseLineRect().left()) value = q->minimum(); pos = qRound(q->minimum() + dur * ((double)m_currentpos.x() - baseLineRect().left()) / baseLineRect().width()); left = baseLineRect().left(); width = baseLineRect().width(); } else { if (m_currentpos.x() > baseLineRect().right()) value = q->minimum(); else if (m_currentpos.x() < baseLineRect().left()) value = q->maximum(); pos = qRound(q->minimum() - dur * ((double)m_currentpos.x() - baseLineRect().right() - 1) / baseLineRect().width()); right = baseLineRect().right(); width = baseLineRect().width(); } switch (m_sliderType) { case SingleSelectSlider: case SmoothSlider: value = pos; break; case StepSlider: { int frontIndex = (pos - q->minimum()) / step; int backIndex = (pos - q->minimum()) / step + 1; if (q->layoutDirection() == Qt::LeftToRight) { if ((m_currentpos.x() - left - frontIndex * step * width / dur) < (backIndex * step * width / dur - (m_currentpos.x() - left))) pos = frontIndex * step + q->minimum(); else pos = backIndex * step + q->minimum(); } else { if ((right - m_currentpos.x() - frontIndex * step * width / dur) < (backIndex * step * width / dur - (right - m_currentpos.x()))) pos = frontIndex * step + q->minimum(); else pos = backIndex * step + q->minimum(); } value = pos; } break; case NodeSlider: { int frontIndex = (pos - q->minimum()) / nodeInterval; int backIndex = (pos - q->minimum()) / nodeInterval + 1; if (q->layoutDirection() == Qt::LeftToRight) { if ((m_currentpos.x() - left - frontIndex * nodeInterval * width / dur) < (backIndex * nodeInterval * width / dur - (m_currentpos.x() - left))) pos = frontIndex * nodeInterval + q->minimum(); else pos = backIndex * nodeInterval + q->minimum(); } else { if ((right - m_currentpos.x() - frontIndex * nodeInterval * width / dur) < (backIndex * nodeInterval * width / dur - (right - m_currentpos.x()))) pos = frontIndex * nodeInterval + q->minimum(); else pos = backIndex * nodeInterval + q->minimum(); } value = pos; } break; default: break; } } else { if (m_currentpos.y() < baseLineRect().top()) value = q->maximum(); else if (m_currentpos.y() > baseLineRect().bottom()) value = q->minimum(); pos = qRound(q->minimum() + dur * ((double)q->height() - m_currentpos.y()) / q->height()); int top = baseLineRect().top(); int height = baseLineRect().height(); switch (m_sliderType) { case SingleSelectSlider: case SmoothSlider: value = pos; break; case StepSlider: { int frontIndex = (pos - q->minimum()) / step + 1; int backIndex = (pos - q->minimum()) / step; if ((m_currentpos.y() - top - (height - frontIndex * step * height / dur)) < ((height - backIndex * step * height / dur) - (m_currentpos.y() - top))) pos = frontIndex * step + q->minimum(); else pos = backIndex * step + q->minimum(); value = pos; } break; case NodeSlider: { int frontIndex = (pos - q->minimum()) / nodeInterval + 1; int backIndex = (pos - q->minimum()) / nodeInterval; if ((m_currentpos.y() - top - (height - frontIndex * nodeInterval * height / dur)) < ((height - backIndex * nodeInterval * height / dur) - (m_currentpos.y() - top))) pos = frontIndex * nodeInterval + q->minimum(); else pos = backIndex * nodeInterval + q->minimum(); value = pos; } break; default: break; } } if (q->tickInterval() != 0) { if (!m_ismoving) { q->setValue(value); } } else { q->setValue(value); } } void KSliderPrivate::updateColor(QPalette palette) { Q_Q(KSlider); QColor startColor; QColor endColor; if (m_isTranslucent) { m_baseColor = ThemeController::getCustomColorFromDT("brighttext-active"); m_baseColor.setAlphaF(0.1); } else m_baseColor = ThemeController::getCustomColorFromDT("button-active"); if (!q->isEnabled()) { m_coverColor = ThemeController::getCustomColorFromDT("kbrand-disable"); ThemeController::getGradientFromDT("kbrand-disable", startColor, endColor); m_linearGradient.setColorAt(0, startColor); m_linearGradient.setColorAt(1, endColor); return; } else { m_coverColor = ThemeController::getCustomColorFromDT("kbrand-normal"); if (m_isPressed) { ThemeController::getGradientFromDT("kbrand-hover", startColor, endColor); m_linearGradient.setColorAt(0, startColor); m_linearGradient.setColorAt(1, endColor); } else if (m_isHovered) { ThemeController::getGradientFromDT("kbrand-hover", startColor, endColor); m_linearGradient.setColorAt(0, startColor); m_linearGradient.setColorAt(1, endColor); } else { ThemeController::getGradientFromDT("kbrand-hover", startColor, endColor); m_linearGradient.setColorAt(0, startColor); m_linearGradient.setColorAt(1, endColor); } } } void KSliderPrivate::changeTheme() { Q_Q(KSlider); if (m_isTranslucentFlag) { if (ThemeController::widgetTheme() == ClassicTheme) m_isTranslucent = false; else m_isTranslucent = true; } else { m_isTranslucent = false; } initThemeStyle(); } QRect KSliderPrivate::baseLineRect() { Q_Q(KSlider); QRect rect; if (q->orientation() == Qt::Horizontal) { rect.setBottom(q->height() / 2 + line_width / 2); rect.setTop(q->height() / 2 - line_width / 2); rect.setLeft(spaceing + Parmscontroller::parm(Parmscontroller::Parm::PM_SliderHandleRadius) / 2); rect.setRight(q->width() - spaceing - Parmscontroller::parm(Parmscontroller::Parm::PM_SliderHandleRadius) / 2); } else { rect.setBottom(q->height() - spaceing - m_handleRadius); rect.setTop(spaceing); rect.setLeft(q->width() / 2 - line_width / 2); rect.setRight(q->width() / 2 + line_width / 2); } return rect; } QRect KSliderPrivate::coverLineRect() { Q_Q(KSlider); QRect rect; if (q->orientation() == Qt::Horizontal) { if (q->layoutDirection() == Qt::LeftToRight) { rect.setBottom(q->height() / 2 + line_width / 2); rect.setTop(q->height() / 2 - line_width / 2); rect.setLeft(spaceing + Parmscontroller::parm(Parmscontroller::Parm::PM_SliderHandleRadius) / 2); if (m_ismoving) rect.setRight(m_currentpos.x()); else if (m_resize) rect.setRight(m_valuePosition); else rect.setRight(m_animation->currentValue().toInt()); } else { rect.setBottom(q->height() / 2 + line_width / 2); rect.setTop(q->height() / 2 - line_width / 2); if (m_ismoving) rect.setLeft(m_currentpos.x()); else if (m_resize) rect.setLeft(m_valuePosition); else rect.setLeft(m_animation->currentValue().toInt()); rect.setRight(q->width() - spaceing - Parmscontroller::parm(Parmscontroller::Parm::PM_SliderHandleRadius) / 2); } } else { rect.setBottom(q->height() - spaceing - m_handleRadius); rect.setLeft(q->width() / 2 - line_width / 2); rect.setRight(q->width() / 2 + line_width / 2); if (m_ismoving) rect.setTop(m_currentpos.y()); else if (m_resize) rect.setTop(m_valuePosition); else rect.setTop(m_animation->currentValue().toInt()); } return rect; } KSlider::KSlider(QWidget *parent) : KSlider(Qt::Horizontal, parent) { } KSlider::KSlider(Qt::Orientation orientation, QWidget *parent) : QSlider(orientation, parent) , d_ptr(new KSliderPrivate(this)) { Q_D(KSlider); d->changeTheme(); connect(d->m_gsetting, &QGSettings::changed, d, &KSliderPrivate::changeTheme); connect(Parmscontroller::self(), &Parmscontroller::modeChanged, this, [=]() { updateGeometry(); update(); }); installEventFilter(this); setFocusPolicy(Qt::ClickFocus); d->m_resize = false; } void KSlider::setTickInterval(int interval) { QSlider::setTickInterval(interval); update(); } void KSlider::setSliderType(KSliderType type) { Q_D(KSlider); d->m_sliderType = type; if (!tickInterval() && type == KSliderType::NodeSlider) setTickInterval(10); if (!singleStep() && type == KSliderType::StepSlider) setSingleStep(10); if (type == KSliderType::SingleSelectSlider) { setTickInterval(1); setSingleStep(1); setRange(0, 2); } } KSliderType KSlider::sliderType() { Q_D(KSlider); return d->m_sliderType; } int KSlider::tickInterval() const { return QSlider::tickInterval(); } void KSlider::setValue(int value) { Q_D(KSlider); QSlider::setValue(value); d->animationStart(); update(); } void KSlider::setNodeVisible(bool flag) { Q_D(KSlider); if (d->m_nodeVisible != flag) { d->m_nodeVisible = flag; repaint(); } } bool KSlider::nodeVisible() { Q_D(KSlider); return d->m_nodeVisible; } void KSlider::setToolTip(const QString &str) { Q_D(KSlider); d->m_pToolTipText = str; } QString KSlider::toolTip() const { Q_D(const KSlider); return d->m_pToolTipText; } void KSlider::setTranslucent(bool flag) { Q_D(KSlider); d->m_isTranslucentFlag = flag; d->m_isTranslucent = flag; d->changeTheme(); } bool KSlider::isTranslucent() { Q_D(KSlider); return d->m_isTranslucent; } void KSlider::paintEvent(QPaintEvent *event) { Q_D(KSlider); if (orientation() == Qt::Horizontal) { for (auto point : d->m_nodes) { if (point.x() <= d->m_valuePosition) d->m_linearGradient = QLinearGradient(point.x(), point.y() - node_radius, point.x(), point.y() + node_radius); } } else { for (auto point : d->m_nodes) { if (point.y() >= d->m_valuePosition) d->m_linearGradient = QLinearGradient(point.x(), point.y() - node_radius, point.x(), point.y() + node_radius); } } d->updateColor(palette()); d->locateNode(); d->updateValuePosition(); QPainter p(this); p.setRenderHint(QPainter::Antialiasing, true); p.setRenderHint(QPainter::SmoothPixmapTransform, true); if (ThemeController::widgetTheme() == ClassicTheme) { if (p.pen().width() == 1) p.translate(0.5, 0.5); } d->drawBasePath(&p); if (d->m_sliderType != SingleSelectSlider) d->drawCoverLine(&p); if (d->m_nodeVisible) { if (d->m_sliderType != SingleSelectSlider) d->drawCoverNode(&p); } d->drawSlider(&p); } void KSlider::resizeEvent(QResizeEvent *event) { Q_D(KSlider); d->m_resize = true; QSlider::resizeEvent(event); } void KSlider::mousePressEvent(QMouseEvent *event) { Q_D(KSlider); if (event->button() == Qt::LeftButton) { d->m_clickTime = QTime::currentTime(); d->m_currentpos = event->pos(); d->m_isPressed = true; d->updateColor(palette()); d->updateValue(); update(); } QSlider::mousePressEvent(event); } void KSlider::mouseReleaseEvent(QMouseEvent *event) { Q_D(KSlider); if (event->button() == Qt::LeftButton) { if (orientation() == Qt::Horizontal) { if (event->pos().x() >= d->baseLineRect().left() && event->pos().x() <= d->baseLineRect().adjusted(0, 0, 1, 0).right()) d->m_currentpos = event->pos(); else if (event->pos().x() < d->baseLineRect().left()) d->m_currentpos.setX(d->baseLineRect().left()); else if (event->pos().x() > d->baseLineRect().adjusted(0, 0, 1, 0).right()) d->m_currentpos.setX(d->baseLineRect().adjusted(0, 0, 1, 0).right()); } else { if (event->pos().y() >= d->baseLineRect().top() && event->pos().y() <= d->baseLineRect().adjusted(0, 0, 0, 1).bottom()) d->m_currentpos = event->pos(); else if (event->pos().y() > d->baseLineRect().adjusted(0, 0, 0, 1).bottom()) d->m_currentpos.setY(d->baseLineRect().adjusted(0, 0, 0, 1).bottom()); else if (event->pos().y() < d->baseLineRect().top()) d->m_currentpos.setY(d->baseLineRect().top()); } if (d->m_ismoving) { if (orientation() == Qt::Horizontal) d->m_valuePosition = d->m_currentpos.x(); else d->m_valuePosition = d->m_currentpos.y(); } d->m_ismoving = false; d->updateColor(palette()); d->updateValue(); update(); d->animationStart(); } QSlider::mouseReleaseEvent(event); if(d->m_isPressed) emit sliderReleased(); } void KSlider::mouseMoveEvent(QMouseEvent *event) { Q_D(KSlider); QTime currentTime = QTime::currentTime(); int timeDiff = d->m_clickTime.msecsTo(currentTime); // 计算从按下到移动的时间差 if(d->m_isPressed && timeDiff >= 100 ) { if (orientation() == Qt::Horizontal) { if (event->pos().x() >= d->baseLineRect().left() && event->pos().x() <= d->baseLineRect().adjusted(0, 0, 1, 0).right()) d->m_currentpos = event->pos(); else if (event->pos().x() < d->baseLineRect().left()) d->m_currentpos.setX(d->baseLineRect().left()); else if (event->pos().x() > d->baseLineRect().adjusted(0, 0, 1, 0).right()) d->m_currentpos.setX(d->baseLineRect().adjusted(0, 0, 1, 0).right()); d->m_ismoving = true; d->updateValue(); update(); } else { if (event->pos().y() >= d->baseLineRect().top() && event->pos().y() <= d->baseLineRect().adjusted(0, 0, 0, 1).bottom()) d->m_currentpos = event->pos(); else if (event->pos().y() > d->baseLineRect().adjusted(0, 0, 0, 1).bottom()) d->m_currentpos.setY(d->baseLineRect().adjusted(0, 0, 0, 1).bottom()); else if (event->pos().y() < d->baseLineRect().top()) d->m_currentpos.setY(d->baseLineRect().top()); d->m_ismoving = true; d->updateValue(); update(); } } else { d->m_ismoving = false; } QSlider::mouseMoveEvent(event); } void KSlider::wheelEvent(QWheelEvent *event) { QSlider::wheelEvent(event); } bool KSlider::eventFilter(QObject *watched, QEvent *event) { Q_D(KSlider); if (watched == this) { switch (event->type()) { case QEvent::Enter: d->m_isHovered = true; d->updateColor(palette()); break; case QEvent::Leave: d->m_isHovered = false; d->updateColor(palette()); break; case QEvent::ToolTip: { QHelpEvent *ex = static_cast(event); d->m_rect = QRect(d->m_currentpos.x() - handle_radius, d->m_currentpos.y() - handle_radius, handle_radius * 2, handle_radius * 2); if (d->m_rect.contains(ex->pos())) { QToolTip::showText(cursor().pos(), d->m_pToolTipText); } else return true; break; } case QEvent::Wheel: d->m_forceUpdate = true; break; case QEvent::KeyPress: d->m_forceUpdate = true; break; case QEvent::Show: d->animationStart(); break; default: break; } } return QSlider::eventFilter(watched, event); } QSize KSlider::sizeHint() const { auto size = QSlider::sizeHint(); if (orientation() == Qt::Horizontal) size.setHeight(Parmscontroller::parm(Parmscontroller::Parm::PM_SliderHandleRadius) + 2); else size.setWidth(Parmscontroller::parm(Parmscontroller::Parm::PM_SliderHandleRadius) + 2); return size; } } // #include "kslider.moc" #include "moc_kslider.cpp" libkysdk-applications/kysdk-qtwidgets/src/kbuttonbox.cpp0000664000175000017500000002356415104543305022642 0ustar fengfeng/* * libkysdk-qtwidgets's Library * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #include "kbuttonbox.h" #include "themeController.h" #include #include #include #include #include #include #include #include "accessinfohelper.h" namespace kdk { class KButtonBoxPrivate : public QObject, public ThemeController { Q_OBJECT Q_DECLARE_PUBLIC(KButtonBox) public: KButtonBoxPrivate(KButtonBox *parent); void updateBorderRadius(); void updateButtonList(); protected: void changeTheme(); private: KButtonBox *q_ptr; QButtonGroup *m_buttonGroup; QBoxLayout *m_layout; int m_radius; bool m_isCheckable; bool m_shadowFlag; QList m_buttonList; QGraphicsDropShadowEffect *m_pShadow_effect; }; KButtonBoxPrivate::KButtonBoxPrivate(KButtonBox *parent) : q_ptr(parent) { Q_Q(KButtonBox); m_buttonGroup = new QButtonGroup(q); q->connect(m_buttonGroup, SIGNAL(buttonClicked(QAbstractButton *)), q, SIGNAL(buttonClicked(QAbstractButton *))); q->connect(m_buttonGroup, SIGNAL(buttonPressed(QAbstractButton *)), q, SIGNAL(buttonPressed(QAbstractButton *))); q->connect(m_buttonGroup, SIGNAL(buttonReleased(QAbstractButton *)), q, SIGNAL(buttonReleased(QAbstractButton *))); q->connect(m_buttonGroup, SIGNAL(buttonToggled(QAbstractButton *, bool)), q, SIGNAL(buttonToggled(QAbstractButton *, bool))); q->connect(m_gsetting, &QGSettings::changed, this, [=] { changeTheme(); }); m_layout = new QHBoxLayout(q); m_layout->setSizeConstraint(QLayout::SetFixedSize); m_layout->setContentsMargins(0, 0, 0, 0); m_layout->setSpacing(0); m_radius = ThemeController::getRadiusFromDT("kradius-normal"); if (m_radius == -1) m_radius = 6; m_isCheckable = false; m_shadowFlag = false; m_pShadow_effect = new QGraphicsDropShadowEffect(); KDK_OBJ_INFO_FORMAT(m_buttonGroup); KDK_OBJ_INFO_FORMAT(m_pShadow_effect); } void KButtonBoxPrivate::updateBorderRadius() { Q_Q(KButtonBox); QList buttonList = q->buttonList(); switch (q->orientation()) { case Qt::Horizontal: { for (int i = 0; i < buttonList.count(); i++) { KPushButton *button = buttonList.at(i); if (i == 0) { Q_ASSERT(button); button->setBorderRadius(m_radius, m_radius, 0, 0); } else if (i == buttonList.count() - 1) { Q_ASSERT(button); button->setBorderRadius(0, 0, m_radius, m_radius); } else { Q_ASSERT(button); button->setBorderRadius(0); } } break; } case Qt::Vertical: { for (int i = 0; i < buttonList.count(); i++) { KPushButton *button = buttonList.at(i); if (i == 0) { Q_ASSERT(button); button->setBorderRadius(0, m_radius, m_radius, 0); } else if (i == buttonList.count() - 1) { Q_ASSERT(button); button->setBorderRadius(m_radius, 0, 0, m_radius); } else { Q_ASSERT(button); button->setBorderRadius(0); } } break; } default: break; } q->update(); } void KButtonBoxPrivate::updateButtonList() { Q_Q(KButtonBox); QColor shadowColor; if (ThemeController::themeMode() == LightTheme) shadowColor = ThemeController::getCustomColorFromDT("kblack"); else shadowColor = ThemeController::getCustomColorFromDT("kwhite"); shadowColor.setAlphaF(0.1); for (QAbstractButton *button : m_buttonGroup->buttons()) { m_buttonGroup->removeButton(button); m_layout->removeWidget(button); } for (int i = 0; i < m_buttonList.count(); ++i) { KPushButton *button = m_buttonList.at(i); button->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Expanding); m_layout->insertWidget(i, button); m_buttonGroup->addButton(button, i); button->setCheckable(m_isCheckable); if (m_shadowFlag) { m_pShadow_effect->setOffset(0, 2); m_pShadow_effect->setColor(shadowColor); m_pShadow_effect->setBlurRadius(4); q->setGraphicsEffect(m_pShadow_effect); } } updateBorderRadius(); } void KButtonBoxPrivate::changeTheme() { Q_Q(KButtonBox); initThemeStyle(); if (ThemeController::themeMode() == LightTheme) { QColor shadowColor(ThemeController::getCustomColorFromDT("kblack")); shadowColor.setAlphaF(0.1); if (m_shadowFlag) { m_pShadow_effect->setOffset(0, 2); m_pShadow_effect->setColor(shadowColor); m_pShadow_effect->setBlurRadius(4); q->setGraphicsEffect(m_pShadow_effect); } } else { QColor shadowColor(255, 255, 255); shadowColor.setAlphaF(0.1); if (m_shadowFlag) { m_pShadow_effect->setOffset(0, 2); m_pShadow_effect->setColor(shadowColor); m_pShadow_effect->setBlurRadius(4); q->setGraphicsEffect(m_pShadow_effect); } } } KButtonBox::KButtonBox(QWidget *parent) : QWidget(parent) , d_ptr(new KButtonBoxPrivate(this)) { Q_D(KButtonBox); } KButtonBox::~KButtonBox() { } Qt::Orientation KButtonBox::orientation() { Q_D(KButtonBox); QBoxLayout::Direction layoutDirection = d->m_layout->direction(); if (layoutDirection == QBoxLayout::LeftToRight || layoutDirection == QBoxLayout::RightToLeft) { return Qt::Horizontal; } return Qt::Vertical; } void KButtonBox::setOrientation(Qt::Orientation orientation) { Q_D(KButtonBox); if (orientation == Qt::Vertical) { d->m_layout->setDirection(QBoxLayout::TopToBottom); d->updateBorderRadius(); return; } d->m_layout->setDirection(QBoxLayout::LeftToRight); d->updateBorderRadius(); } void KButtonBox::addButton(KPushButton *button, int i) { Q_D(KButtonBox); if (i < -1) return; if (i == -1 || i >= d->m_buttonList.count()) { d->m_buttonList.append(button); } else { d->m_buttonList.insert(i, button); } button->show(); setButtonList(d->m_buttonList); } void KButtonBox::removeButton(KPushButton *button) { Q_D(KButtonBox); if (d->m_buttonList.contains(button)) { d->m_buttonList.removeAll(button); button->hide(); } setButtonList(d->m_buttonList); } void KButtonBox::removeButton(int i) { Q_D(KButtonBox); if (i < 0 || i >= d->m_buttonList.count()) return; auto button = d->m_buttonList.at(i); if (button) button->hide(); d->m_buttonList.removeAt(i); setButtonList(d->m_buttonList); } void KButtonBox::setButtonList(const QList &list) { Q_D(KButtonBox); d->m_buttonList = list; d->updateButtonList(); } QList KButtonBox::buttonList() { Q_D(KButtonBox); return d->m_buttonList; } void KButtonBox::setBorderRadius(int radius) { Q_D(KButtonBox); d->m_radius = radius; update(); } int KButtonBox::borderRadius() { Q_D(KButtonBox); return d->m_radius; } void KButtonBox::setId(KPushButton *button, int id) { Q_D(KButtonBox); d->m_buttonGroup->setId(button, id); } int KButtonBox::id(KPushButton *button) { Q_D(KButtonBox); return d->m_buttonGroup->id(button); } KPushButton *KButtonBox::checkedButton() { Q_D(KButtonBox); KPushButton *button = dynamic_cast(d->m_buttonGroup->checkedButton()); return button; } KPushButton *KButtonBox::button(int id) { Q_D(KButtonBox); KPushButton *button = dynamic_cast(d->m_buttonGroup->button(id)); return button; } int KButtonBox::checkedId() { Q_D(KButtonBox); return d->m_buttonGroup->checkedId(); } void KButtonBox::setExclusive(bool exclusive) { Q_D(KButtonBox); d->m_buttonGroup->setExclusive(exclusive); } bool KButtonBox::exclusive() { Q_D(KButtonBox); return d->m_buttonGroup->exclusive(); } void KButtonBox::setCheckable(bool flag) { Q_D(KButtonBox); d->m_isCheckable = flag; QList list = buttonList(); for (int i = 0; i < list.count(); ++i) { KPushButton *button = list.at(i); button->setCheckable(d->m_isCheckable); } update(); } bool KButtonBox::isCheckable() { Q_D(KButtonBox); return d->m_isCheckable; } void KButtonBox::setShadow(bool flag) { Q_D(KButtonBox); QColor shadowColor(0, 0, 0); shadowColor.setAlphaF(0.1); d->m_shadowFlag = flag; if (flag) { d->updateButtonList(); } else { for (int i = 0; i < d->m_buttonList.count(); ++i) { KPushButton *button = d->m_buttonList.at(i); d->m_pShadow_effect->setOffset(0, 2); d->m_pShadow_effect->setColor(Qt::NoBrush); d->m_pShadow_effect->setBlurRadius(4); button->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Expanding); setGraphicsEffect(d->m_pShadow_effect); } } } bool KButtonBox::shadow() { Q_D(KButtonBox); return d->m_shadowFlag; } } #include "kbuttonbox.moc" #include "moc_kbuttonbox.cpp" libkysdk-applications/kysdk-qtwidgets/src/ksearchlineedit.cpp0000664000175000017500000011074215104543305023574 0ustar fengfeng/* * libkysdk-qtwidgets's Library * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #include "ksearchlineedit.h" #include "klineframe.h" #include "kshadowhelper.h" #include "ktoolbutton.h" #include "parmscontroller.h" #include "themeController.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "accessinfohelper.h" namespace kdk { class MyStyle : public QProxyStyle { public: MyStyle() { } ~MyStyle() { } void drawControl(QStyle::ControlElement element, const QStyleOption *option, QPainter *painter, const QWidget *widget = nullptr) const override; QRect subElementRect(QStyle::SubElement element, const QStyleOption *option, const QWidget *widget) const override; }; class CursorProxyStyle : public QProxyStyle { public: CursorProxyStyle() { } ~CursorProxyStyle() { } virtual int pixelMetric(PixelMetric metric, const QStyleOption *option = 0, const QWidget *widget = 0) const { if (metric == QStyle::PM_TextCursorWidth) { return 0; } return QProxyStyle::pixelMetric(metric, option, widget); } }; class ListViewDelegate : public QStyledItemDelegate, public ThemeController { public: ListViewDelegate(QObject *parent); protected: void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override; QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const override; }; static const int iconMargin = 6; static const int buttonMargin = 6; static const int icontextSpacing = 5; class KSearchLineEditPrivate : public QObject, public ThemeController { Q_OBJECT Q_DECLARE_PUBLIC(KSearchLineEdit) public: KSearchLineEditPrivate(KSearchLineEdit *parent); void adjustHolderRect(); void adjustLayout(); public Q_SLOTS: void doAnimationFinished(); void doEditingFinished(); protected: void changeTheme(); private: KSearchLineEdit *q_ptr; QHBoxLayout *m_pWidgetLayout; QWidget *m_pWidget; QLabel *m_pTextLabel; QLabel *m_pIconLabel; QPropertyAnimation *m_pAnimation; bool m_isSearching; QStringListModel *m_pListModel; QStringList m_List; QCompleter *m_pCompleter; QString m_placeHolderText; Qt::Alignment m_placeHolderAlignment; bool m_hasFocus; QRect m_holderRect; QRect m_sideRect; ListViewDelegate *m_pListViewDelegate; bool m_isTranslucent; bool m_isTranslucentFlag; bool isTextEmpty; KToolButton *m_pClearButton; KToolButton *m_pCustomButton; KVLineFrame *m_pLineFrame; QWidget *m_pSubWidget; QLinearGradient m_linearGradient; bool m_isClearVisible; bool m_isGradient; bool m_isCustomButtonHover; bool m_isClearHover; bool m_showCursor; bool m_isGradientFlag; QTimer *m_timer; void sltUpdateCursorRect(); void init(); QString m_systemName; bool m_contextMenu; QGSettings *m_ukuiGsetting; int m_cursorBlinkTime; bool m_isFoucus; }; KSearchLineEdit::KSearchLineEdit(QWidget *parent) : QLineEdit(parent) , d_ptr(new KSearchLineEditPrivate(this)) { Q_D(KSearchLineEdit); setFocusPolicy(Qt::ClickFocus); // 应设计师要求,1.2.0.8之后的版本默认显示右键菜单 // setContextMenuPolicy(Qt::NoContextMenu); d->init(); installEventFilter(this); d->m_pCustomButton->installEventFilter(this); d->m_pClearButton->installEventFilter(this); // d->m_pCompleter->popup()->installEventFilter(this); connect(d->m_pAnimation, &QPropertyAnimation::finished, d, &KSearchLineEditPrivate::doAnimationFinished); connect(d->m_gsetting, &QGSettings::changed, d, &KSearchLineEditPrivate::changeTheme); connect(this, &KSearchLineEdit::editingFinished, d, &KSearchLineEditPrivate::doEditingFinished); connect(this, &KSearchLineEdit::returnPressed, this, &KSearchLineEdit::clearFocus); connect(Parmscontroller::self(), &Parmscontroller::modeChanged, this, [=]() { updateGeometry(); }); connect(this, &QLineEdit::textChanged, this, [=]() { if (!text().isEmpty() && d->m_pClearButton->isEnabled() && hasFocus() && d->m_isClearVisible) { d->m_pClearButton->show(); d->adjustLayout(); } else { d->m_pClearButton->hide(); d->adjustLayout(); } }); connect(d->m_pCustomButton, &KToolButton::clicked, this, [=] { d->m_isGradient = !d->m_isGradient; if (d->m_isGradientFlag && d->m_isGradient) { d->m_pCustomButton->setIconColor(true, ThemeController::getCustomColorFromDT("highlight-active")); } update(); }); connect(d->m_pClearButton, &QPushButton::clicked, this, [=]() { this->clear(); }); connect(d->m_pAnimation, &QPropertyAnimation::finished, this, [=]() { d->sltUpdateCursorRect(); if (hasFocus()) d->m_timer->start(); else d->m_timer->stop(); }); d->changeTheme(); CursorProxyStyle *style = new CursorProxyStyle(); this->setStyle(style); d->m_showCursor = false; d->m_timer = new QTimer(this); if (QGSettings::isSchemaInstalled("org.ukui.style")) { d->m_ukuiGsetting = new QGSettings("org.ukui.style"); if (d->m_ukuiGsetting->keys().contains("cursorBlinkTime")) { d->m_cursorBlinkTime = d->m_ukuiGsetting->get("cursorBlinkTime").toInt(); if (d->m_cursorBlinkTime == 0) { d->m_timer->stop(); d->sltUpdateCursorRect(); } else { d->m_timer->setInterval(d->m_cursorBlinkTime / 2); connect(d->m_timer, &QTimer::timeout, this, [=] { d->sltUpdateCursorRect(); }); } } connect(d->m_ukuiGsetting, &QGSettings::changed, d, [=] { if (d->m_ukuiGsetting->keys().contains("cursorBlinkTime")) { d->m_cursorBlinkTime = d->m_ukuiGsetting->get("cursorBlinkTime").toInt(); d->m_timer->setInterval(d->m_cursorBlinkTime / 2); } }); } } KSearchLineEdit::~KSearchLineEdit() { Q_D(KSearchLineEdit); } void KSearchLineEdit::setEnabled(bool enable) { Q_D(KSearchLineEdit); QLineEdit::setEnabled(enable); d->changeTheme(); } bool KSearchLineEdit::isEnabled() { Q_D(KSearchLineEdit); return QLineEdit::isEnabled(); } void KSearchLineEdit::setClearButtonEnabled(bool enable) { Q_D(KSearchLineEdit); d->m_isClearVisible = enable; QLineEdit::setClearButtonEnabled(false); } bool KSearchLineEdit::isClearButtonEnabled() const { Q_D(const KSearchLineEdit); return d->m_pClearButton->isHidden(); // QLineEdit::isClearButtonEnabled(); } QString KSearchLineEdit::placeholderText() const { Q_D(const KSearchLineEdit); return d->m_placeHolderText; } void KSearchLineEdit::setPlaceholderText(const QString &text) { Q_D(KSearchLineEdit); d->m_placeHolderText = text; d->m_pTextLabel->setText(text); } Qt::Alignment KSearchLineEdit::placeholderAlignment() const { Q_D(const KSearchLineEdit); return d->m_placeHolderAlignment; } void KSearchLineEdit::setPlaceholderAlignment(Qt::Alignment flag) { Q_D(KSearchLineEdit); d->m_placeHolderAlignment = flag; } Qt::Alignment KSearchLineEdit::alignment() const { return QLineEdit::alignment(); } void KSearchLineEdit::setAlignment(Qt::Alignment flag) { Q_D(KSearchLineEdit); QLineEdit::setAlignment(flag); } void KSearchLineEdit::setTranslucent(bool flag) { Q_D(KSearchLineEdit); d->m_isTranslucentFlag = flag; d->m_isTranslucent = flag; d->changeTheme(); setProperty("needTranslucent", flag); } bool KSearchLineEdit::isTranslucent() { Q_D(KSearchLineEdit); return d->m_isTranslucent; } void KSearchLineEdit::reloadStyle() { Q_D(KSearchLineEdit); QAbstractItemView *popup = completer()->popup(); kdk::effects::KShadowHelper::self()->setWidget(popup); popup->setItemDelegate(d->m_pListViewDelegate); MyStyle *style = new MyStyle; popup->setStyle(style); } KToolButton *KSearchLineEdit::customButton() { Q_D(KSearchLineEdit); return d->m_pCustomButton; } void KSearchLineEdit::setGradation(bool flag) { Q_D(KSearchLineEdit); d->m_isGradientFlag = flag; } void KSearchLineEdit::setCustomButtonVisible(bool flag) { Q_D(KSearchLineEdit); d->m_pCustomButton->setVisible(flag); d->m_pLineFrame->setVisible(flag); d->adjustLayout(); } bool KSearchLineEdit::isCustomButtonVisible() { Q_D(KSearchLineEdit); return d->m_pCustomButton->isVisible(); } void KSearchLineEdit::clear() { Q_D(KSearchLineEdit); if (this->text().isEmpty()) return; QLineEdit::clear(); d->isTextEmpty = true; if (this->hasFocus()) { d->m_pTextLabel->setVisible(false); d->m_pTextLabel->adjustSize(); d->m_pWidget->update(); } else { d->m_pTextLabel->setVisible(true); d->m_pTextLabel->adjustSize(); d->adjustHolderRect(); d->m_pAnimation->setStartValue(d->m_sideRect); d->m_pAnimation->setEndValue(d->m_holderRect); d->m_pAnimation->start(); } } bool KSearchLineEdit::eventFilter(QObject *watched, QEvent *event) { Q_D(KSearchLineEdit); QFont font; font = QApplication::font(); QFontMetrics fm(font); if (watched == this) { switch (event->type()) { case QEvent::ContextMenu: if (!d->m_contextMenu) d->m_contextMenu = true; break; case QEvent::Show: { d->adjustHolderRect(); if (text().isEmpty()) d->m_pWidget->setGeometry(d->m_holderRect); else d->m_pWidget->setGeometry(d->m_sideRect); break; } case QEvent::FocusIn: { d->m_isFoucus = true; if (d->m_contextMenu) d->m_contextMenu = false; d->m_pTextLabel->setVisible(false); // 文本为空时获取焦点延时显示光标 if (text().isEmpty()) { d->m_showCursor = false; } d->m_isSearching = true; d->m_hasFocus = false; if (!this->text().isEmpty()) { if (d->isTextEmpty) { d->m_pTextLabel->setVisible(false); d->isTextEmpty = false; } } else { if (d->isTextEmpty) { d->adjustHolderRect(); d->m_pAnimation->setStartValue(d->m_holderRect); d->m_pAnimation->setEndValue(d->m_sideRect); d->m_pAnimation->start(); d->isTextEmpty = false; } d->m_pTextLabel->setVisible(false); } d->adjustLayout(); break; } case QEvent::FocusOut: { d->m_isFoucus = false; if (!d->m_contextMenu) { d->m_isSearching = false; d->m_hasFocus = true; if (!this->text().isEmpty()) { d->m_pTextLabel->setVisible(false); } else { d->m_pTextLabel->setVisible(true); d->adjustHolderRect(); d->m_pAnimation->setStartValue(d->m_sideRect); d->m_pAnimation->setEndValue(d->m_holderRect); d->m_pAnimation->start(); d->isTextEmpty = true; } d->adjustLayout(); } break; } case QEvent::HoverEnter: case QEvent::HoverMove: { if (width() - icontextSpacing - d->m_pIconLabel->width() < fm.horizontalAdvance(d->m_placeHolderText)) { if (d->m_hasFocus) setToolTip(d->m_placeHolderText); else setToolTip(""); } break; } default: break; } } if (watched == d->m_pCustomButton) { if (!d->m_isGradient) { switch (event->type()) { case QEvent::HoverEnter: case QEvent::HoverMove: d->m_pCustomButton->setIconColor(true, ThemeController::getCustomColorFromDT("windowtext-active")); break; case QEvent::Leave: d->m_pCustomButton->setIconColor(true, ThemeController::getCustomColorFromDT("mid-active")); break; default: break; } } } if (watched == d->m_pClearButton) { switch (event->type()) { case QEvent::HoverEnter: case QEvent::HoverMove: d->m_pClearButton->setIconColor(true, ThemeController::getCustomColorFromDT("windowtext-active")); break; case QEvent::Leave: d->m_pClearButton->setIconColor(true, ThemeController::getCustomColorFromDT("mid-active")); break; default: break; } } return QLineEdit::eventFilter(watched, event); } void KSearchLineEditPrivate::adjustHolderRect() { Q_Q(KSearchLineEdit); m_pWidget->adjustSize(); auto maxVisualWidth = q->width() - icontextSpacing - m_pIconLabel->width(); QFont font(QApplication::font()); QFontMetrics fm(font); auto elidedText = fm.elidedText(m_placeHolderText, Qt::ElideRight, maxVisualWidth); m_pTextLabel->setText(elidedText); m_pWidget->adjustSize(); if (q->hasFocus()) m_pWidget->setFixedHeight(m_pIconLabel->height()); else m_pWidget->setFixedHeight(m_pTextLabel->height()); m_sideRect = m_pWidget->rect(); if (m_systemName == "ug_CN" || m_systemName == "kk_KZ" || m_systemName == "ky_KG") { m_sideRect.moveTop((q->rect().height() - m_pWidget->height()) / 2); m_sideRect.moveLeft(q->rect().width() - m_sideRect.width() - iconMargin); } else { m_sideRect.moveTop((q->rect().height() - m_pWidget->height()) / 2); m_sideRect.moveLeft(iconMargin); } if (m_placeHolderAlignment & Qt::AlignCenter) { m_holderRect = m_pWidget->rect(); m_holderRect.moveCenter(q->rect().center()); } else if (m_placeHolderAlignment & Qt::AlignLeft) { m_holderRect = m_pWidget->rect(); m_holderRect.moveTop((q->rect().height() - m_pWidget->height()) / 2); m_holderRect.moveLeft(iconMargin); } else if (m_placeHolderAlignment & Qt::AlignRight) { m_holderRect = m_pWidget->rect(); m_holderRect.moveTop((q->height() - m_pWidget->height()) / 2); m_holderRect.moveRight(q->width() - iconMargin); } } void KSearchLineEditPrivate::adjustLayout() { Q_Q(KSearchLineEdit); int spacing = 5; int width = spacing * 2; m_pLineFrame->setFixedHeight(m_pSubWidget->height() - 12); if (!m_pClearButton->isHidden()) width += (spacing + m_pClearButton->iconSize().width()); if (!m_pLineFrame->isHidden()) width += (spacing + m_pLineFrame->width()); if (!m_pCustomButton->isHidden()) width += (spacing + m_pCustomButton->iconSize().width()); m_pSubWidget->setFixedSize(width, q->cursorRect().height()); if (m_systemName == "ug_CN" || m_systemName == "kk_KZ" || m_systemName == "ky_KG") { m_pSubWidget->move(0, (q->rect().height() - m_pSubWidget->height()) / 2 + 1); q->setTextMargins(m_pSubWidget->width(), 0, m_pWidget->width(), 0); } else { m_pSubWidget->move(q->width() - m_pSubWidget->width(), (q->rect().height() - m_pSubWidget->height()) / 2 + 1); q->setTextMargins(m_pWidget->width(), 0, m_pSubWidget->width(), 0); } } void KSearchLineEdit::resizeEvent(QResizeEvent *event) { Q_D(KSearchLineEdit); QLineEdit::resizeEvent(event); d->adjustHolderRect(); if (text().isEmpty() && !hasFocus()) d->m_pWidget->setGeometry(d->m_holderRect); else d->m_pWidget->setGeometry(d->m_sideRect); d->adjustLayout(); } void KSearchLineEdit::setVisible(bool visible) { Q_D(KSearchLineEdit); QLineEdit::setVisible(visible); if (!text().isEmpty()) { d->m_pTextLabel->setVisible(false); d->adjustHolderRect(); d->m_pWidget->setGeometry(d->m_sideRect); } else { d->m_pTextLabel->setVisible(true); } } void KSearchLineEdit::paintEvent(QPaintEvent *event) { Q_D(KSearchLineEdit); QLineEdit::paintEvent(event); QStyleOptionFrame option; initStyleOption(&option); QPainter painter(this); painter.setRenderHints(QPainter::Antialiasing); painter.setRenderHints(QPainter::SmoothPixmapTransform); style()->drawPrimitive(QStyle::PE_PanelLineEdit, &option, &painter, this); QRect textRect = style()->subElementRect(QStyle::SE_LineEditContents, &option, this); int margins = textMargins().left() + textMargins().right(); textRect.adjust(textMargins().left() +1, 3, -textMargins().right() - 1, -3); QString text = this->text(); QString elidedText = fontMetrics().elidedText(text, Qt::ElideRight, textRect.width() - margins); if (hasSelectedText()) { int selectStart = this->selectionStart(); int selectLength = selectedText().length(); int selectEnd = selectStart + selectLength; QFontMetrics fm = fontMetrics(); int startX = fm.horizontalAdvance(this->text().left(selectStart)); int endX = fm.horizontalAdvance(this->text().left(selectEnd)); int selectWidth = endX - startX; QRect selectRect(textRect.x() + startX, textRect.y(),selectWidth, textRect.height()); painter.fillRect(selectRect, ThemeController::getCustomColorFromDT("kbrand-normal")); if (selectStart > 0) { painter.setPen(isEnabled() ? ThemeController::getCustomColorFromDT("text-active") : ThemeController::getCustomColorFromDT("placeholdertext-active")); QString beforeSelect = text.left(selectStart); painter.drawText(textRect, alignment(), beforeSelect); } painter.setPen(ThemeController::getCustomColorFromDT("highlightedtext-active")); QString selectedPart = text.mid(selectStart, selectLength); int selectX = textRect.x() + fm.horizontalAdvance(text.left(selectStart)); QRect selectTextRect(selectX, textRect.y(),fm.horizontalAdvance(selectedPart), textRect.height()); painter.drawText(selectTextRect, Qt::AlignLeft | Qt::AlignVCenter, selectedPart); if (selectStart + selectLength < text.length()) { painter.setPen(isEnabled() ? ThemeController::getCustomColorFromDT("text-active") : ThemeController::getCustomColorFromDT("placeholdertext-active")); QString afterSelect = text.mid(selectStart + selectLength); int afterX = selectX + fm.horizontalAdvance(selectedPart); QRect afterTextRect(afterX, textRect.y(), textRect.width() - afterX, textRect.height()); painter.drawText(afterTextRect, Qt::AlignLeft | Qt::AlignVCenter, afterSelect); } } else { painter.setPen(isEnabled() ? ThemeController::getCustomColorFromDT("text-active") : ThemeController::getCustomColorFromDT("placeholdertext-active")); painter.drawText(textRect, alignment(), elidedText); } d->m_linearGradient = QLinearGradient(QPointF(rect().left(), rect().center().y()), QPointF(rect().right(), rect().center().y())); if (d->m_isFoucus && d->m_showCursor) { QRect rect = this->cursorRect(); painter.fillRect(QRect(rect.center().x(), rect.y(), 1, rect.height()), ThemeController::getCustomColorFromDT("windowtext-active")); } QPen pen = painter.pen(); pen.setWidth(2); if (isEnabled()) { d->m_pClearButton->setEnabled(true); d->m_pCustomButton->setEnabled(true); if (d->m_isGradientFlag && d->m_isGradient) { d->m_linearGradient.setColorAt(0, QColor(232, 136, 248)); d->m_linearGradient.setColorAt(0.4, QColor(138, 65, 255)); d->m_linearGradient.setColorAt(0.7, QColor(78, 117, 255)); d->m_linearGradient.setColorAt(1, QColor(0, 54, 245)); pen.setBrush(d->m_linearGradient); } else { pen.setBrush(ThemeController::getCustomColorFromDT("highlight-active")); } } else { pen.setBrush(ThemeController::getCustomColorFromDT("button-disable")); d->m_pClearButton->setEnabled(false); d->m_pCustomButton->setEnabled(false); } if (!hasFocus() && !d->m_isGradient) painter.setPen(Qt::NoPen); else painter.setPen(pen); int radius = ThemeController::getRadiusFromDT("kradius-normal"); if (radius == -1) radius = 6; painter.drawRoundedRect(rect().adjusted(1, 3, -1, -3), radius, radius); } QSize KSearchLineEdit::sizeHint() const { auto size = QLineEdit::sizeHint(); size.setHeight(Parmscontroller::parm(Parmscontroller::Parm::PM_SearchLineEditHeight)); return size; } KSearchLineEditPrivate::KSearchLineEditPrivate(KSearchLineEdit *parent) : q_ptr(parent) , m_placeHolderText(tr("Search")) , m_placeHolderAlignment(Qt::AlignCenter) , m_hasFocus(true) , isTextEmpty(true) , m_isTranslucent(false) , m_isTranslucentFlag(false) , m_isClearVisible(false) , m_isGradient(false) , m_isCustomButtonHover(false) , m_isClearHover(false) , m_contextMenu(false) , m_isGradientFlag(false) , m_isFoucus(false) { Q_Q(KSearchLineEdit); q->setContentsMargins(0,2,0,2); m_pCompleter = new QCompleter(this); m_pCompleter->setCaseSensitivity(Qt::CaseInsensitive); m_pListModel = new QStringListModel(m_List, this); m_pCompleter->setModel(m_pListModel); q->setCompleter(m_pCompleter); QAbstractItemView *popup = m_pCompleter->popup(); kdk::effects::KShadowHelper::self()->setWidget(popup); m_pListViewDelegate = new ListViewDelegate(popup); popup->setItemDelegate(m_pListViewDelegate); MyStyle *style = new MyStyle; popup->setStyle(style); popup->setContentsMargins(0,1,0,1); setParent(parent); } void KSearchLineEditPrivate::doAnimationFinished() { Q_Q(KSearchLineEdit); if (m_isSearching) { if (m_systemName == "ug_CN" || m_systemName == "kk_KZ" || m_systemName == "ky_KG") q->setTextMargins(m_pSubWidget->width(), 0, iconMargin + m_pIconLabel->width(), 0); else q->setTextMargins(iconMargin + m_pIconLabel->width(), 0, m_pSubWidget->width(), 0); } } void KSearchLineEditPrivate::doEditingFinished() { Q_Q(KSearchLineEdit); QString text = q->text(); if (QString::compare(text.trimmed(), "") != 0) { bool flag = m_List.contains(text, Qt::CaseInsensitive); if (!flag) { m_List.append(text); m_pListModel->setStringList(m_List); } } } void KSearchLineEditPrivate::changeTheme() { Q_Q(KSearchLineEdit); if (m_isTranslucentFlag) { if (ThemeController::widgetTheme() == ClassicTheme) { m_isTranslucent = false; setProperty("needTranslucent", false); } else { m_isTranslucent = true; setProperty("needTranslucent", true); } } else { m_isTranslucent = false; setProperty("needTranslucent", false); } adjustHolderRect(); if (q->text().isEmpty()) m_pWidget->setGeometry(m_holderRect); else m_pWidget->setGeometry(m_sideRect); QPixmap pixmap = QIcon::fromTheme("search-symbolic").pixmap(QSize(16, 16)); initThemeStyle(); if (!q->isEnabled()) { QPalette palette = q->palette(); // palette.setColor(QPalette::Text,q->palette().color(QPalette::Disabled,QPalette::ButtonText)); palette.setColor(QPalette::Text, ThemeController::getCustomColorFromDT("buttontext-disable")); m_pTextLabel->setPalette(palette); } else { QPalette palette = q->palette(); #if (QT_VERSION >= QT_VERSION_CHECK(5, 12, 0)) palette.setColor(QPalette::Text, ThemeController::getCustomColorFromDT("placeholdertext-active")); #else if (QT_VERSION >= QT_VERSION_CHECK(5, 6, 0)) palette.setColor(QPalette::Text, ThemeController::getCustomColorFromDT("shadow-active")); #endif m_pTextLabel->setPalette(palette); } if (ThemeController::themeMode() == LightTheme) { m_pIconLabel->setPixmap(pixmap); auto palette = qApp->palette(); palette.setColor(QPalette::Base, Qt::transparent); m_pCompleter->popup()->setPalette(palette); m_pCompleter->popup()->setBackgroundRole(QPalette::Base); m_pCompleter->popup()->setAutoFillBackground(true); QPalette lineFramePalette = qApp->palette(); lineFramePalette.setColor(QPalette::Base, QColor(207, 207, 207)); m_pLineFrame->setPalette(lineFramePalette); } else { m_pIconLabel->setPixmap(drawSymbolicColoredPixmap(pixmap)); auto palette = qApp->palette(); palette.setColor(QPalette::Base, Qt::transparent); m_pCompleter->popup()->setPalette(palette); m_pCompleter->popup()->setBackgroundRole(QPalette::Base); m_pCompleter->popup()->setAutoFillBackground(true); QPalette pal = qApp->palette(); m_pTextLabel->setPalette(pal); QPalette lineFramePalette = qApp->palette(); lineFramePalette.setColor(QPalette::Base, ThemeController::getCustomColorFromDT("kgray-13")); m_pLineFrame->setPalette(lineFramePalette); } q->update(); } void KSearchLineEditPrivate::sltUpdateCursorRect() { Q_Q(KSearchLineEdit); if (m_cursorBlinkTime == 0) { m_showCursor = true; } else { m_showCursor = !m_showCursor; } QRect rect = q->cursorRect(); q->update(rect); } void KSearchLineEditPrivate::init() { Q_Q(KSearchLineEdit); QPalette btnPalette; btnPalette.setBrush(QPalette::Active, QPalette::Button, Qt::transparent); btnPalette.setBrush(QPalette::Inactive, QPalette::Button, Qt::transparent); btnPalette.setBrush(QPalette::Disabled, QPalette::Button, Qt::transparent); btnPalette.setBrush(QPalette::Active, QPalette::Highlight, Qt::transparent); btnPalette.setBrush(QPalette::Inactive, QPalette::Highlight, Qt::transparent); btnPalette.setBrush(QPalette::Disabled, QPalette::Highlight, Qt::transparent); m_pClearButton = new KToolButton(q); m_pClearButton->setType(KToolButtonType::Flat); m_pClearButton->setAutoFillBackground(true); m_pClearButton->setPalette(btnPalette); m_pClearButton->setIconSize(QSize(16, 16)); m_pClearButton->setFixedSize(QSize(16, 16)); m_pClearButton->setFocusPolicy(Qt::NoFocus); m_pClearButton->setCursor(Qt::ArrowCursor); m_pClearButton->setIcon(QIcon::fromTheme("application-exit-symbolic")); m_pClearButton->setVisible(false); m_pLineFrame = new KVLineFrame(); m_pLineFrame->setFollowPalette(false); m_pLineFrame->setVisible(false); m_pCustomButton = new KToolButton(q); m_pCustomButton->setCheckable(true); m_pCustomButton->setType(KToolButtonType::Flat); m_pCustomButton->setAutoFillBackground(true); m_pCustomButton->setPalette(btnPalette); m_pCustomButton->setIconSize(QSize(16, 16)); m_pCustomButton->setFixedSize(QSize(16, 16)); m_pCustomButton->setFocusPolicy(Qt::NoFocus); m_pCustomButton->setCursor(Qt::ArrowCursor); m_pCustomButton->setVisible(false); m_pCustomButton->setIcon(QIcon()); m_pSubWidget = new QWidget(q); QHBoxLayout *layout = new QHBoxLayout(m_pSubWidget); layout->setContentsMargins(0, 0, 0, 0); layout->addSpacing(iconMargin); layout->addWidget(m_pClearButton); layout->addWidget(m_pLineFrame); layout->addWidget(m_pCustomButton); layout->addSpacing(iconMargin); m_pSubWidget->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); m_isSearching = false; m_pTextLabel = new QLabel(tr("Search")); m_pIconLabel = new QLabel; m_pIconLabel->setScaledContents(true); QPixmap pixmap = QIcon::fromTheme("search-symbolic").pixmap(QSize(16, 16)); m_pIconLabel->setPixmap(pixmap); m_pIconLabel->setFixedSize(QSize(16, 16)); m_pWidget = new QWidget(q); m_pWidget->setFocusPolicy(Qt::NoFocus); m_pWidgetLayout = new QHBoxLayout(); m_pWidgetLayout->setContentsMargins(0, 0, 0, 0); m_pWidgetLayout->setSpacing(0); m_pWidgetLayout->addWidget(m_pIconLabel, Qt::AlignVCenter); m_pWidgetLayout->addSpacing(icontextSpacing); m_pWidgetLayout->addWidget(m_pTextLabel, Qt::AlignVCenter); m_pWidgetLayout->addStretch(); m_pWidgetLayout->setSizeConstraint(QLayout::SizeConstraint::SetFixedSize); m_pWidget->setLayout(m_pWidgetLayout); m_pAnimation = new QPropertyAnimation(m_pWidget, "geometry"); m_pAnimation->setEasingCurve(QEasingCurve::InOutQuad); m_pAnimation->setDuration(100); m_systemName = QLocale::system().name(); if (m_systemName == "ug_CN" || m_systemName == "kk_KZ" || m_systemName == "ky_KG") q->setAlignment(Qt::AlignRight); else q->setAlignment(Qt::AlignLeft); q->setTextMargins(iconMargin + m_pIconLabel->width(), 0, m_pSubWidget->width(), 0); KDK_ALL_INFO_FORMAT(m_pWidget,""); KDK_ALL_INFO_FORMAT(m_pTextLabel,""); KDK_ALL_INFO_FORMAT(m_pIconLabel,""); KDK_OBJ_INFO_FORMAT(m_pAnimation); KDK_OBJ_INFO_FORMAT(m_pListModel); KDK_OBJ_INFO_FORMAT(m_pCompleter); KDK_OBJ_INFO_FORMAT(m_pListViewDelegate); KDK_ALL_INFO_FORMAT(m_pClearButton,""); KDK_ALL_INFO_FORMAT(m_pCustomButton,""); KDK_ALL_INFO_FORMAT(m_pLineFrame,""); KDK_ALL_INFO_FORMAT(m_pSubWidget,""); } ListViewDelegate::ListViewDelegate(QObject *parent) : QStyledItemDelegate(parent) { } void ListViewDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const { QRect rect; rect.setX(option.rect.x()); rect.setY(option.rect.y() + 1); rect.setWidth(option.rect.width()); rect.setHeight(option.rect.height()); qreal radius; if (ThemeController::widgetTheme() == ClassicTheme) { if (painter->pen().width() == 1) painter->translate(0.5, 0.5); radius = 0; } else { radius = ThemeController::getRadiusFromDT("kradius-normal"); if (radius == -1) radius = 6; } QPainterPath path; path.moveTo(rect.topRight() - QPointF(radius, 0)); path.lineTo(rect.topLeft() + QPointF(radius, 0)); path.quadTo(rect.topLeft(), rect.topLeft() + QPointF(0, radius)); path.lineTo(rect.bottomLeft() + QPointF(0, -radius)); path.quadTo(rect.bottomLeft(), rect.bottomLeft() + QPointF(radius, 0)); path.lineTo(rect.bottomRight() - QPointF(radius, 0)); path.quadTo(rect.bottomRight(), rect.bottomRight() + QPointF(0, -radius)); path.lineTo(rect.topRight() + QPointF(0, radius)); path.quadTo(rect.topRight(), rect.topRight() + QPointF(-radius, -0)); painter->setRenderHint(QPainter::Antialiasing); QColor color = Qt::transparent; QColor fontColor = ThemeController::getCustomColorFromDT("buttontext-active"); if (ThemeController::themeMode() == ThemeFlag::LightTheme) { if (!(option.state & QStyle::State_Enabled)) { color = ThemeController::getCustomColorFromDT("kcomponent-disable"); } else if (((option.state & QStyle::State_HasFocus) || (option.state & QStyle::State_Selected) || (option.state & QStyle::State_MouseOver))) { if (option.state.testFlag(QStyle::State_HasFocus) && option.state.testFlag(QStyle::State_Selected)) // QStyle::State_Enabled { color = ThemeController::getCustomColorFromDT("highlight-active"); fontColor = ThemeController::getCustomColorFromDT("highlightedtext-active"); } else if ((option.state & QStyle::State_MouseOver)) { color = ThemeController::getCustomColorFromDT("highlight-active"); fontColor = ThemeController::getCustomColorFromDT("highlightedtext-active"); } else { color = ThemeController::getCustomColorFromDT("windowtext-active"); } painter->save(); painter->setPen(QPen(Qt::NoPen)); painter->setBrush(color); painter->drawPath(path); painter->restore(); } } else { if (!(option.state & QStyle::State_Enabled)) { color = ThemeController::getCustomColorFromDT("kcomponent-disable"); } else if (((option.state & QStyle::State_HasFocus) || (option.state & QStyle::State_Selected) || (option.state & QStyle::State_MouseOver))) { if (option.state.testFlag(QStyle::State_HasFocus) && option.state.testFlag(QStyle::State_Selected)) // QStyle::State_Enabled { color = ThemeController::getCustomColorFromDT("highlight-active"); fontColor = ThemeController::getCustomColorFromDT("highlightedtext-active"); } else if ((option.state & QStyle::State_MouseOver)) { color = ThemeController::getCustomColorFromDT("highlight-active"); fontColor = ThemeController::getCustomColorFromDT("highlightedtext-active"); } else { color = ThemeController::getCustomColorFromDT("windowtext-active"); } painter->save(); painter->setPen(QPen(Qt::NoPen)); painter->setBrush(color); painter->drawPath(path); painter->restore(); } } QPen pen; pen.setWidth(1); pen.setColor(fontColor); painter->setPen(pen); QFontMetrics fm = option.fontMetrics; auto str = index.model()->data(index, Qt::DisplayRole).toString(); if (fm.horizontalAdvance(str) >= rect.width() - 12) { if (option.state.testFlag(QStyle::State_MouseOver)) QToolTip::showText(QCursor::pos(), str, qobject_cast(const_cast(option.widget))); str = fm.elidedText(str, Qt::ElideRight, rect.width() - 12); } painter->drawText(rect.adjusted(12, 0, 0, 0), Qt::AlignLeft | Qt::AlignVCenter, str); } QSize ListViewDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const { QSize size; size.setWidth(option.widget->width()); size.setHeight(Parmscontroller::parm(Parmscontroller::Parm::PM_SearchLineEditItemHeight)); return size; } void MyStyle::drawControl(QStyle::ControlElement element, const QStyleOption *option, QPainter *painter, const QWidget *widget) const { switch (element) { case CE_ShapedFrame: { painter->setRenderHint(QPainter::Antialiasing); QColor color; if (ThemeController::themeMode() == LightTheme) { color = ThemeController::getCustomColorFromDT("kgray-17"); color.setAlphaF(0.15); painter->setBrush(ThemeController::getCustomColorFromDT("kwhite")); } else { color = ThemeController::getCustomColorFromDT("kgray-3"); painter->setBrush(color); } painter->setPen(color); int radius = ThemeController::getRadiusFromDT("kradius-menu"); painter->drawRoundedRect(option->rect, radius, radius); break; } default: QProxyStyle::drawControl(element, option, painter, widget); } } QRect MyStyle::subElementRect(QStyle::SubElement element, const QStyleOption *option, const QWidget *widget) const { switch (element) { case SE_ShapedFrameContents: return QProxyStyle::subElementRect(element, option, widget).adjusted(0, 4, 0, 2); default: return QProxyStyle::subElementRect(element, option, widget); } } } #include "ksearchlineedit.moc" #include "moc_ksearchlineedit.cpp" libkysdk-applications/kysdk-qtwidgets/src/ksliderframe.h0000664000175000017500000000424115104543305022547 0ustar fengfeng/* * * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Sisheng He * */ #ifndef SLIDERWIDGET_H #define SLIDERWIDGET_H #include "kbaseframe.h" #include "klabel.h" #include "kslider.h" /** * @defgroup ContainerModules * @brief 创建一个带 KSlider 的 Frame * @since 3.0.1.0 * { */ namespace kdk { class KSliderFramePrivate; class KSliderFrame : public KBaseFrame { Q_OBJECT public: /** * @brief 创建一个带 KSlider 的 Frame * * @param title: text of m_settingName * @param hasNode: 是否带节点 * @param style: 设置圆角(None:无圆角,Top:上圆角,Bottom:下圆角,Around:四圆角) * @param parent */ explicit KSliderFrame(QString title, bool hasNode, QWidget *parent = nullptr, BorderRadiusStyle style = BorderRadiusStyle::None, Qt::Orientation orientation = Qt::Horizontal); ~KSliderFrame(); /** * @brief 获取 m_slider * @return KSlider */ KSlider *slider(); /** * @brief 获取滑动条左侧label * @return QLabel */ QLabel *leftLabel(); /** * @brief 获取滑动条右侧label * @return QLabel */ QLabel *rightLabel(); /** * @brief 获取label * * @return QLabel */ KLabel *titleLabel(); /** * @brief 获取layout * * @return QHBoxLayout */ QHBoxLayout *mainHLayout(); private: Q_DECLARE_PRIVATE(KSliderFrame) KSliderFramePrivate *const d_ptr; }; } #endif // SLIDERWIDGET_H libkysdk-applications/kysdk-qtwidgets/src/karrowtabbar.cpp0000664000175000017500000001210515104543305023111 0ustar fengfeng/* * libkysdk-qtwidgets's Library * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhenyu Wang * */ #include "karrowtabbar.h" #include "kborderlessbutton.h" #include "knativetabbar.h" #include "themeController.h" #include #include #include namespace kdk { class Q_DECL_HIDDEN ArrowTabBarStyle : public QProxyStyle { Q_OBJECT public: ArrowTabBarStyle(QStyle *style = nullptr); QRect subElementRect(QStyle::SubElement element, const QStyleOption *option, const QWidget *widget) const override; }; class Q_DECL_HIDDEN KArrowTabBarPrivate : public QObject, public ThemeController { Q_OBJECT Q_DECLARE_PUBLIC(KArrowTabBar) public: KArrowTabBarPrivate(KArrowTabBar *parent); void currentChangeUpdateBtnStatus(int index); void updateBtnVisible(); private: KArrowTabBar *q_ptr; KBorderlessButton *m_pLeftButton; KBorderlessButton *m_pRightButton; KNativeTabbar *m_pTabBar; QHBoxLayout *m_pHLayout; }; KArrowTabBar::KArrowTabBar(QWidget *parent) : QWidget(parent) , d_ptr(new KArrowTabBarPrivate(this)) { Q_D(KArrowTabBar); connect(this, &KArrowTabBar::sizeChange, this, [=] { d->updateBtnVisible(); }); } KNativeTabbar *KArrowTabBar::tabbar() { Q_D(KArrowTabBar); return d->m_pTabBar; } void KArrowTabBar::resizeEvent(QResizeEvent *event) { Q_D(KArrowTabBar); QWidget::resizeEvent(event); emit sizeChange(); } KArrowTabBarPrivate::KArrowTabBarPrivate(KArrowTabBar *parent) : q_ptr(parent) { Q_Q(KArrowTabBar); m_pHLayout = new QHBoxLayout(q); m_pTabBar = new KNativeTabbar(); ArrowTabBarStyle *style = new ArrowTabBarStyle(); m_pTabBar->setStyle(style); m_pLeftButton = new KBorderlessButton(); m_pLeftButton->setIcon(QIcon::fromTheme("go-previous.symbolic")); m_pRightButton = new KBorderlessButton(); m_pRightButton->setIcon(QIcon::fromTheme("go-next.symbolic")); m_pHLayout->addWidget(m_pLeftButton); m_pHLayout->addWidget(m_pTabBar); m_pHLayout->addWidget(m_pRightButton); connect(m_pTabBar, &KNativeTabbar::currentChanged, this, [=](int index) { currentChangeUpdateBtnStatus(index); }); connect(m_pLeftButton, &KBorderlessButton::clicked, this, [=] { m_pTabBar->leftScrollTabs(); }); connect(m_pRightButton, &KBorderlessButton::clicked, this, [=] { m_pTabBar->rightScrollTabs(); }); connect(m_pTabBar, &KNativeTabbar::leftBStatus, q, [=](bool flag) { m_pLeftButton->setEnabled(flag); }); connect(m_pTabBar, &KNativeTabbar::rightBStatus, q, [=](bool flag) { m_pRightButton->setEnabled(flag); }); } void KArrowTabBarPrivate::currentChangeUpdateBtnStatus(int index) { Q_Q(KArrowTabBar); if (index == 0) { m_pLeftButton->setEnabled(false); if (!m_pRightButton->isEnabled()) m_pRightButton->setEnabled(true); } else if (index == m_pTabBar->count() - 1) { m_pRightButton->setEnabled(false); if (!m_pLeftButton->isEnabled()) m_pLeftButton->setEnabled(true); } else { if (!m_pLeftButton->isEnabled()) m_pLeftButton->setEnabled(true); if (!m_pRightButton->isEnabled()) m_pRightButton->setEnabled(true); } } void KArrowTabBarPrivate::updateBtnVisible() { Q_Q(KArrowTabBar); int wid = 0; for (int i = 0; i < q->tabbar()->count(); i++) wid += q->tabbar()->tabRect(i).width(); if (q->rect().width() < wid) { if (m_pTabBar->usesScrollButtons()) { m_pLeftButton->setVisible(true); m_pRightButton->setVisible(true); } else { m_pLeftButton->setVisible(false); m_pRightButton->setVisible(false); } } else { m_pLeftButton->setVisible(false); m_pRightButton->setVisible(false); } } ArrowTabBarStyle::ArrowTabBarStyle(QStyle *style) { } QRect ArrowTabBarStyle::subElementRect(QStyle::SubElement element, const QStyleOption *option, const QWidget *widget) const { QRect rc; switch (element) { case QStyle::SE_TabBarScrollLeftButton: rc = option->rect; rc.setWidth(0); rc.setHeight(0); break; case QStyle::SE_TabBarScrollRightButton: rc = option->rect; rc.setWidth(0); rc.setHeight(0); break; default: break; } return rc; } } #include "karrowtabbar.moc" #include "moc_karrowtabbar.cpp" libkysdk-applications/kysdk-qtwidgets/src/kaddbutton.h0000664000175000017500000000352515104543305022242 0ustar fengfeng/* * * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Sisheng He * */ #ifndef ADDBUTTON_H #define ADDBUTTON_H #include #include #include #include #include "kbaseframe.h" /** * @defgroup PushButtonModule * @brief 添加按钮 * @since 3.0.1.0 * { */ namespace kdk { class KAddButtonPrivate; class KAddButton : public QPushButton { Q_OBJECT public: explicit KAddButton(QWidget *parent = nullptr, KBaseFrame::BorderRadiusStyle style = KBaseFrame::BorderRadiusStyle::Bottom, bool heightAdaptive = true); ~KAddButton(); /** * @brief 设置圆角模式 * * @param style */ void setRadiusType(KBaseFrame::BorderRadiusStyle style); /** * @brief 获取平板模式 * * @return bool 是否是平板模式 */ bool getTabletMode(); /** * @brief 设置高度是否自适应 * @param flag */ void setHeightAdaptive(bool flag); protected: void paintEvent(QPaintEvent *event); Q_SIGNALS: void tabletModeChanged(bool b); private: Q_DECLARE_PRIVATE(KAddButton) KAddButtonPrivate *const d_ptr; }; } #endif // ADDBUTTON_H libkysdk-applications/kysdk-qtwidgets/src/kradiobuttonframe.h0000664000175000017500000000500215104543305023613 0ustar fengfeng/* * * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Sisheng He * */ #ifndef RADIOBUTTONWIDGET_H #define RADIOBUTTONWIDGET_H #include #include #include #include "kbaseframe.h" #include "klabel.h" /** * @defgroup ContainerModules * @brief 创建一个带 QButtonGroup 的 Frame * @since 3.0.1.0 * { */ namespace kdk { class KRadioButtonFramePrivate; class KRadioButtonFrame : public KBaseFrame { Q_OBJECT public: /** * @brief 创建一个带 QButtonGroup 的 Frame * * @param title: text of m_settingName * @param style: 设置圆角(None:无圆角,Top:上圆角,Bottom:下圆角,Around:四圆角) * @param parent */ explicit KRadioButtonFrame(const QString title, QWidget *parent = nullptr, BorderRadiusStyle style = BorderRadiusStyle::None); /** * @brief * */ ~KRadioButtonFrame(); /** * @brief 添加一个 id = id 的 QRadioButton 到 m_buttonGroup,并放到 radioLayout 中 * * @param button: 需要添加的 QRadioButton * @param id: 用于 buttonClicked 信号传递的参数 * @param addStretch: 是否 addStretch */ void addButton(QRadioButton *button, int id = -1, bool addStretch = false); /** * @brief layout of radiobutton * * @return QHBoxLayout */ QHBoxLayout *radioHLayout(); /** * @brief 获取 m_buttonGroup * * @return QButtonGroup */ QButtonGroup *buttonGroup(); /** * @brief 获取label * * @return QLabel */ KLabel *titleLabel(); /** * @brief 获取layout * * @return QHBoxLayout */ QHBoxLayout *mainHLayout(); private: Q_DECLARE_PRIVATE(KRadioButtonFrame) KRadioButtonFramePrivate *const d_ptr; }; } #endif // RADIOBUTTONWIDGET_H libkysdk-applications/kysdk-qtwidgets/src/kfilewidget.cpp0000664000175000017500000002405715104543305022737 0ustar fengfeng/* * libkysdk-qtwidgets's Library * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhenyu Wang * */ #include "kfilewidget.h" #include "themeController.h" #include #include #include #include #include #include #include #include #include #include #include "accessinfohelper.h" namespace kdk { class KFileWidgetPrivate : public QObject, public ThemeController { Q_OBJECT Q_DECLARE_PUBLIC(KFileWidget) public: KFileWidgetPrivate(KFileWidget *parent); protected: void changeTheme(); private: KFileWidget *q_ptr; QHBoxLayout *m_pHLayout; QVBoxLayout *m_pVLayout; QLabel *m_pIconLabel; QLabel *m_pMainLabel; QLabel *m_pSubLabel; QColor m_buttonBkgColor; QColor m_iconColor; QRect m_buttonRect; int m_bottomRightRadius; int m_topLeftRadius; int m_bottomLeftRadius; int m_topRightRadius; }; KFileWidget::KFileWidget(QWidget *parent) : QWidget(parent) , d_ptr(new KFileWidgetPrivate(this)) { Q_D(KFileWidget); installEventFilter(this); setMouseTracking(true); d->m_pMainLabel->installEventFilter(this); setFixedHeight(56); } void KFileWidget::setMainText(QString str) { Q_D(KFileWidget); d->m_pMainLabel->setText(str); } void KFileWidget::setSubText(QString str) { Q_D(KFileWidget); d->m_pSubLabel->setText(str); } void KFileWidget::setIcon(QIcon icon) { Q_D(KFileWidget); d->m_pIconLabel->setFixedSize(32, 32); d->m_pIconLabel->setPixmap(icon.pixmap(32, 32)); } void KFileWidget::setBorderRadius(int radius) { Q_D(KFileWidget); d->m_bottomRightRadius = radius; d->m_topLeftRadius = radius; d->m_bottomLeftRadius = radius; d->m_topRightRadius = radius; } void KFileWidget::setBorderRadius(int bottomLeft, int topLeft, int topRight, int bottomRight) { Q_D(KFileWidget); d->m_bottomRightRadius = bottomRight; d->m_topLeftRadius = topLeft; d->m_bottomLeftRadius = bottomLeft; d->m_topRightRadius = topRight; } void KFileWidget::paintEvent(QPaintEvent *event) { Q_D(KFileWidget); if (d->m_pSubLabel->text().isNull()) d->m_pSubLabel->setVisible(false); d->m_buttonRect = QRect(rect().width() - 17, 0, 16, 16); QPainter painter(this); painter.setRenderHint(QPainter::Antialiasing); painter.setRenderHint(QPainter::SmoothPixmapTransform); painter.setBrush(ThemeController::getCustomColorFromDT("window-active")); if (ThemeController::themeMode() == LightTheme) { QColor color(38, 38, 38); color.setAlphaF(0.15); painter.setPen(color); } else { QColor color(255, 255, 255); color.setAlphaF(0.15); painter.setPen(color); } QPainterPath path; QRect rectPath = rect().adjusted(0, 2, -2, 0); path.moveTo(rectPath.topRight() - QPoint(d->m_topRightRadius, 0)); // 右上 path.lineTo(rectPath.topLeft() + QPointF(d->m_topLeftRadius, 0)); // 上方线 path.quadTo(rectPath.topLeft(), rectPath.topLeft() + QPointF(0, d->m_topLeftRadius)); // 圆角 path.lineTo(rectPath.bottomLeft() + QPointF(0, -d->m_bottomLeftRadius)); // 左方线 path.quadTo(rectPath.bottomLeft(), rectPath.bottomLeft() + QPointF(d->m_bottomLeftRadius, 0)); // 圆角 path.lineTo(rectPath.bottomRight() - QPointF(d->m_bottomRightRadius, 0)); // 下方线 path.quadTo(rectPath.bottomRight(), rectPath.bottomRight() + QPointF(0, -d->m_bottomRightRadius)); // 圆角 path.lineTo(rectPath.topRight() + QPointF(0, d->m_topRightRadius)); // 右方线 path.quadTo(rectPath.topRight(), rectPath.topRight() - QPointF(d->m_topRightRadius, 0)); // 圆角 if (!isEnabled()) { d->m_buttonBkgColor = ThemeController::getCustomColorFromDT("button-disable"); d->m_iconColor = ThemeController::getCustomColorFromDT("highlightedtext-active"); } painter.drawPath(path); painter.setBrush(d->m_buttonBkgColor); painter.drawEllipse(d->m_buttonRect); d->m_pHLayout->setContentsMargins(8, 8, d->m_buttonRect.width(), 8); QIcon icon(QIcon::fromTheme("application-exit-symbolic")); QPixmap pixmap = icon.pixmap(d->m_buttonRect.size()); painter.drawPixmap(d->m_buttonRect, ThemeController::drawColoredPixmap(pixmap, d->m_iconColor)); } bool KFileWidget::eventFilter(QObject *watched, QEvent *event) { Q_D(KFileWidget); QMouseEvent *mouseEvent = static_cast(event); switch (event->type()) { case QEvent::Enter: case QEvent::MouseMove: { if (d->m_buttonRect.contains(mouseEvent->pos())) { d->m_iconColor = ThemeController::getCustomColorFromDT("kwhite"); d->m_buttonBkgColor = ThemeController::getCustomColorFromDT("kred1"); } else { if (ThemeController::themeMode() == LightTheme) { d->m_iconColor = ThemeController::getCustomColorFromDT("kgray-17"); d->m_buttonBkgColor = ThemeController::getCustomColorFromDT("kwhite"); } else { d->m_iconColor = ThemeController::getCustomColorFromDT("kwhite"); d->m_buttonBkgColor = ThemeController::getCustomColorFromDT("window-active"); } } update(); break; } case QEvent::MouseButtonPress: { if (d->m_buttonRect.contains(mouseEvent->pos())) { d->m_iconColor = ThemeController::getCustomColorFromDT("kwhite"); d->m_buttonBkgColor = ThemeController::getCustomColorFromDT("error-click"); } else { if (ThemeController::themeMode() == LightTheme) { d->m_iconColor = ThemeController::getCustomColorFromDT("kgray-17"); d->m_buttonBkgColor = ThemeController::getCustomColorFromDT("kwhite"); } else { d->m_iconColor = ThemeController::getCustomColorFromDT("kwhite"); d->m_buttonBkgColor = ThemeController::getCustomColorFromDT("window-active"); } } update(); break; } case QEvent::MouseButtonRelease: { if (d->m_buttonRect.contains(mouseEvent->pos())) { d->m_iconColor = ThemeController::getCustomColorFromDT("kwhite"); d->m_buttonBkgColor = ThemeController::getCustomColorFromDT("kred1"); if (isEnabled()) emit clicked(); } else { if (ThemeController::themeMode() == LightTheme) { d->m_iconColor = ThemeController::getCustomColorFromDT("kgray-17"); d->m_buttonBkgColor = ThemeController::getCustomColorFromDT("kwhite"); } else { d->m_iconColor = ThemeController::getCustomColorFromDT("kwhite"); d->m_buttonBkgColor = ThemeController::getCustomColorFromDT("window-active"); } } update(); break; } case QEvent::Leave: { if (ThemeController::themeMode() == LightTheme) { d->m_iconColor = ThemeController::getCustomColorFromDT("kgray-17"); d->m_buttonBkgColor = ThemeController::getCustomColorFromDT("kwhite"); } else { d->m_iconColor = ThemeController::getCustomColorFromDT("kwhite"); d->m_buttonBkgColor = ThemeController::getCustomColorFromDT("window-active"); } update(); break; } default: break; } return QWidget::eventFilter(watched, event); } KFileWidgetPrivate::KFileWidgetPrivate(KFileWidget *parent) : q_ptr(parent) { Q_Q(KFileWidget); int radius = ThemeController::getRadiusFromDT("kradius-normal"); if (radius == -1) { m_bottomRightRadius = 6; m_topLeftRadius = 6; m_bottomLeftRadius = 6; m_topRightRadius = 6; } else { m_bottomRightRadius = radius; m_topLeftRadius = radius; m_bottomLeftRadius = radius; m_topRightRadius = radius; } m_pMainLabel = new QLabel(); m_pSubLabel = new QLabel(); m_pVLayout = new QVBoxLayout(); m_pVLayout->setSpacing(0); m_pVLayout->addStretch(); m_pVLayout->addWidget(m_pMainLabel); m_pVLayout->addWidget(m_pSubLabel); m_pVLayout->addStretch(); m_pVLayout->setContentsMargins(0, 0, 0, 0); m_pIconLabel = new QLabel(); m_pHLayout = new QHBoxLayout(q); m_pHLayout->setContentsMargins(0, 0, 0, 0); m_pHLayout->setSpacing(0); m_pHLayout->addWidget(m_pIconLabel); m_pHLayout->addSpacing(8); m_pHLayout->addLayout(m_pVLayout); q->setContentsMargins(0, 0, 0, 0); changeTheme(); connect(m_gsetting, &QGSettings::changed, this, [=]() { changeTheme(); }); setParent(parent); KDK_ALL_INFO_FORMAT(m_pIconLabel,""); KDK_ALL_INFO_FORMAT(m_pMainLabel,""); KDK_ALL_INFO_FORMAT(m_pSubLabel,""); } void KFileWidgetPrivate::changeTheme() { Q_Q(KFileWidget); initThemeStyle(); QPalette subPalette = q->palette(); QColor color = ThemeController::getCustomColorFromDT("windowtext-disable"); subPalette.setColor(QPalette::Text, color); m_pSubLabel->setPalette(subPalette); if (ThemeController::themeMode() == LightTheme) { m_iconColor = ThemeController::getCustomColorFromDT("kgray-17"); m_buttonBkgColor = ThemeController::getCustomColorFromDT("kwhite"); } else { m_iconColor = ThemeController::getCustomColorFromDT("kwhite"); m_buttonBkgColor = ThemeController::getCustomColorFromDT("window-active"); } } } #include "kfilewidget.moc" #include "moc_kfilewidget.cpp" libkysdk-applications/kysdk-qtwidgets/src/klunarcalendarinfo.h0000664000175000017500000001031515104543305023740 0ustar fengfeng/* * libkysdk-qtwidgets's Library * * Copyright (C) 2024, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhenyu Wang * */ #ifndef KLUNARCALENDARINFO_H #define KLUNARCALENDARINFO_H #include "gui_g.h" #include namespace kdk { class KLunarCalendarInfoPrivate; /** * @defgroup KLunarCalendarInfo * @since 2.5.2.0 */ class GUI_EXPORT KLunarCalendarInfo : public QObject { Q_OBJECT public: static KLunarCalendarInfo *Instance(); explicit KLunarCalendarInfo(QObject *parent = 0); /** * @brief 计算是否闰年 * @param year * @return */ bool isLoopYear(int year); /** * @brief 计算指定年月该月共多少天 * @param year * @param month * @return */ int getMonthDays(int year, int month); /** * @brief 计算指定年月对应到该月共多少天 * @param year * @param month * @return */ int getTotalMonthDays(int year, int month); /** * @brief 计算指定年月对应星期几 * @param year * @param month * @param FirstDayisSun:第一天是否以周日开始 * @return */ int getFirstDayOfWeek(int year, int month, bool FirstDayisSun); /** * @brief 计算国际节日 * @param month * @param day * @return */ QString getHoliday(int month, int day); /** * @brief 计算二十四节气 * @param year * @param month * @param day * @return */ QString getSolarTerms(int year, int month, int day); /** * @brief 计算农历节日(必须传入农历年份月份) * @param month * @param day * @return */ QString getLunarFestival(int month, int day); /** * @brief 计算农历年 天干+地支+生肖 * @param year * @return */ QString getLunarYear(int year); /** * @brief 计算指定年月日农历信息,包括公历节日和农历节日及二十四节气 * @param year * @param month * @param day * @param strHoliday * @param strSolarTerms * @param strLunarFestival * @param strLunarYear * @param strLunarMonth * @param strLunarDay */ void getLunarCalendarInfo(int year, int month, int day, QString &strHoliday, QString &strSolarTerms, QString &strLunarFestival, QString &strLunarYear, QString &strLunarMonth, QString &strLunarDay); /** * @brief 获取指定年月日农历信息 * @param year * @param month * @param day * @param yearInfo * @param monthInfo * @param dayInfo * @return */ QString getLunarInfo(int year, int month, int day, bool yearInfo, bool monthInfo, bool dayInfo); /** * @brief 获取农历年月日 * @param year * @param month * @param day * @return */ QString getLunarYearMonthDay(int year, int month, int day); /** * @brief 获取农历月日 * @param year * @param month * @param day * @return */ QString getLunarMonthDay(int year, int month, int day); /** * @brief 获取农历日 * @param year * @param month * @param day * @return */ QString getLunarDay(int year, int month, int day); private: Q_DECLARE_PRIVATE(KLunarCalendarInfo) KLunarCalendarInfoPrivate *const d_ptr; static QScopedPointer self; }; } #endif // KLUNARCALENDARINFO_H libkysdk-applications/kysdk-qtwidgets/src/kcommentpanel.h0000664000175000017500000000363515104543305022742 0ustar fengfeng/* * libkysdk-qtwidgets's Library * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #ifndef KCOMMENTPANEL_H #define KCOMMENTPANEL_H #include "gui_g.h" #include namespace kdk { /** * @defgroup CommentsPanel */ class KCommentPanelPrivate; /** * @brief 提供六种评论等级 */ enum StarLevel { LevelZero = 0, LevelOne, LevelTwo, LevelThree, LevelFour, LevelFive }; /** * @brief 显示用户评论的详细信息 * @since 1.0.0 */ class GUI_EXPORT KCommentPanel : public QWidget { Q_OBJECT public: explicit KCommentPanel(QWidget *parent = nullptr); /** * @brief 设置评论用户头像 */ void setIcon(const QIcon &); /** * @brief 设置评论时间 */ void setTime(const QString &); /** * @brief 设置评论用户昵称 */ void setName(const QString &); /** * @brief 设置评论文本 */ void setText(const QString &); /** * @brief 设置等级 * @param level */ void setGrade(StarLevel level); protected: void paintEvent(QPaintEvent *event) override; private: Q_DECLARE_PRIVATE(KCommentPanel) KCommentPanelPrivate *const d_ptr; }; } #endif // KCOMMENTPANEL_H libkysdk-applications/kysdk-qtwidgets/src/kswitchbutton.h0000664000175000017500000000447215104543305023015 0ustar fengfeng/* * libkysdk-qtwidgets's Library * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #ifndef KSWITCHBUTTON_H #define KSWITCHBUTTON_H #include "gui_g.h" #include #include #include #include namespace kdk { /** @defgroup PushbuttonModule * @{ */ class KSwitchButtonPrivate; /** * @brief 指示打开/关闭两种状态 * @since 1.0.0 */ class GUI_EXPORT KSwitchButton : public QPushButton { Q_OBJECT public: KSwitchButton(QWidget *parent = 0); ~KSwitchButton(); /** * @brief 设置是否可选中 */ void setCheckable(bool); /** * @brief 返回是否可选中 * @return */ bool isCheckable() const; /** * @brief 返回是否选中 * @return */ bool isChecked() const; /** * @brief 设置是否选中 * @return */ void setChecked(bool); /** * @brief 设置是否启用半透明效果 * @since 1.2.0 * @param flag */ void setTranslucent(bool flag); /** * @brief 获取是否启用半透明效果 * @since 1.2.0 * @return flag */ bool isTranslucent(); Q_SIGNALS: /** * @brief 当选中状态发生变化时,发出此信号 */ void stateChanged(bool); protected: void paintEvent(QPaintEvent *event) override; void resizeEvent(QResizeEvent *event) override; QSize sizeHint() const; private: Q_DECLARE_PRIVATE(KSwitchButton) KSwitchButtonPrivate *const d_ptr; }; } /** * @example testSwitchbutton/widget.h * @example testSwitchbutton/widget.cpp * @} */ #endif // KSWITCHBUTTON_H libkysdk-applications/kysdk-qtwidgets/src/kpushbuttonframe.cpp0000664000175000017500000000455215104543305024040 0ustar fengfeng/* * * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Sisheng He * */ #include "kpushbuttonframe.h" #include namespace kdk { class KPushButtonFramePrivate : public QObject { Q_OBJECT Q_DECLARE_PUBLIC(KPushButtonFrame) public: KPushButtonFramePrivate(KPushButtonFrame *parent); private: KPushButtonFrame *q_ptr; KPushButton *m_pPushButton; KLabel *m_pSettingName; QHBoxLayout *m_pMainLayout; }; KPushButtonFramePrivate::KPushButtonFramePrivate(KPushButtonFrame *parent) : q_ptr(parent) { Q_Q(KPushButtonFrame); setParent(parent); m_pMainLayout = new QHBoxLayout(q); m_pMainLayout->setContentsMargins(16, 0, 16, 0); m_pMainLayout->setSpacing(16); m_pSettingName = new KLabel(q); m_pPushButton = new KPushButton(); m_pPushButton->setFixedWidth(100); m_pMainLayout->addWidget(m_pSettingName); m_pMainLayout->addStretch(); m_pMainLayout->addWidget(m_pPushButton); q->setLayout(m_pMainLayout); } KPushButtonFrame::KPushButtonFrame(const QString title, QWidget *parent, BorderRadiusStyle style) : KBaseFrame(parent, style, true) , d_ptr(new KPushButtonFramePrivate(this)) { Q_D(KPushButtonFrame); setObjectName("KPushButtonFrame"); d->m_pSettingName->setText(title); } KPushButtonFrame::~KPushButtonFrame() { } KPushButton *KPushButtonFrame::pushButton() { Q_D(KPushButtonFrame); return d->m_pPushButton; } QHBoxLayout *KPushButtonFrame::mainHLayout() { Q_D(KPushButtonFrame); return d->m_pMainLayout; } KLabel *KPushButtonFrame::titleLabel() { Q_D(KPushButtonFrame); return d->m_pSettingName; } } #include "kpushbuttonframe.moc" #include "moc_kpushbuttonframe.cpp" libkysdk-applications/kysdk-qtwidgets/src/kcomboboxframe.cpp0000664000175000017500000000437515104543305023440 0ustar fengfeng/* * * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Sisheng He * */ #include "kcomboboxframe.h" namespace kdk { class KComboBoxFramePrivate : public QObject { Q_OBJECT Q_DECLARE_PUBLIC(KComboBoxFrame) public: KComboBoxFramePrivate(KComboBoxFrame *parent); private: KComboBoxFrame *q_ptr; QComboBox *m_pCombox; KLabel *m_pSettingName; QHBoxLayout *m_pMainLayout; }; KComboBoxFramePrivate::KComboBoxFramePrivate(KComboBoxFrame *parent) : q_ptr(parent) { Q_Q(KComboBoxFrame); setParent(parent); m_pMainLayout = new QHBoxLayout(q); m_pMainLayout->setContentsMargins(16, 0, 16, 0); m_pMainLayout->setSpacing(16); m_pSettingName = new KLabel(q); m_pSettingName->setFixedWidth(SETTING_LABEL_WIDTH); m_pMainLayout->addWidget(m_pSettingName); m_pCombox = new QComboBox(q); m_pMainLayout->addWidget(m_pCombox); q->setLayout(m_pMainLayout); } KComboBoxFrame::KComboBoxFrame(const QString title, QWidget *parent, BorderRadiusStyle style) : KBaseFrame(parent, style, true) , d_ptr(new KComboBoxFramePrivate(this)) { Q_D(KComboBoxFrame); setObjectName("KComboBoxFrame"); d->m_pSettingName->setText(title); } KComboBoxFrame::~KComboBoxFrame() { } QComboBox *KComboBoxFrame::comboBox() { Q_D(KComboBoxFrame); return d->m_pCombox; } QHBoxLayout *KComboBoxFrame::mainHLayout() { Q_D(KComboBoxFrame); return d->m_pMainLayout; } KLabel *KComboBoxFrame::titleLabel() { Q_D(KComboBoxFrame); return d->m_pSettingName; } } #include "kcomboboxframe.moc" #include "moc_kcomboboxframe.cpp" libkysdk-applications/kysdk-qtwidgets/src/kaboutdialog.cpp0000664000175000017500000003403215104543305023100 0ustar fengfeng/* * libkysdk-qtwidgets's Library * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #include "kaboutdialog.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "accessinfohelper.h" namespace kdk { #define MAILTYPE "x-scheme-handler/mailto" #define LOCAL_CONFIG_DIR "/.config/" #define SYSTEM_CONFIG_DIR "/usr/share/applications/" class LinkLabel : public QLabel { Q_OBJECT public: LinkLabel(QWidget *parent = nullptr); protected: void mousePressEvent(QMouseEvent *event); }; class KAboutDialogPrivate : public QObject { Q_OBJECT Q_DECLARE_PUBLIC(KAboutDialog) public: KAboutDialogPrivate(KAboutDialog *parent); void adjustMiniMode(); QString getDefaultAppId(const char *contentType); bool isOpenKylin(); void updateAppVersionText(); QString ConvertFirstLetterCase(const QString &input); QStringList getSystemConfigDir(); void setAccessInfo(); private: KAboutDialog *q_ptr; QLabel *m_pAppIconLabel; QLabel *m_pAppNameLabel; QLabel *m_pAppVersionLabel; QLabel *m_pAppSupportLabel; LinkLabel *m_pAppPrivacyLabel; QString m_iconName; QString m_bodyText; bool m_appVersionFlag; }; KAboutDialog::KAboutDialog(QWidget *parent, const QIcon &appIcon, const QString &appName, const QString &appVersion, const QString &appInfo) : KDialog(parent) , d_ptr(new KAboutDialogPrivate(this)) { Q_D(KAboutDialog); setProperty("isAboutDialog", true); mainLayout()->setSizeConstraint(QLayout::SizeConstraint::SetFixedSize); d->m_iconName = appIcon.name(); d->m_pAppIconLabel = new QLabel(this); QPixmap pix(appIcon.pixmap(QSize(96, 96))); d->m_pAppIconLabel->setPixmap(pix); d->m_pAppIconLabel->setAlignment(Qt::AlignCenter); d->m_pAppNameLabel = new QLabel(this); d->m_pAppNameLabel->setText(d->ConvertFirstLetterCase(appName)); d->m_pAppNameLabel->setAlignment(Qt::AlignCenter); if (!(appVersion == "") && (!(appVersion.isNull()))) d->m_appVersionFlag = false; d->m_pAppVersionLabel = new QLabel(this); d->m_pAppVersionLabel->setText(appVersion); d->m_pAppVersionLabel->setAlignment(Qt::AlignCenter); d->m_pAppVersionLabel->setFixedWidth(400); d->m_pAppSupportLabel = new QLabel(this); d->m_pAppSupportLabel->setMinimumWidth(400); d->m_pAppPrivacyLabel = new LinkLabel(this); d->m_pAppPrivacyLabel->setAlignment(Qt::AlignCenter); d->m_pAppPrivacyLabel->setVisible(false); d->adjustMiniMode(); connect(d->m_pAppSupportLabel, &QLabel::linkActivated, this, [=](const QString url) { QString appid = d->getDefaultAppId(MAILTYPE); if (appid.isEmpty()) { QMessageBox msg(this); msg.setIcon(QMessageBox::Icon::Information); msg.setIconPixmap(QIcon::fromTheme("dialog-info").pixmap(24, 24)); msg.setInformativeText(tr("Your system does not have any email application installed or the default mail application is not set up")); msg.setText(tr("Unable to open mail application")); msg.exec(); } else QDesktopServices::openUrl(QUrl(url)); }); changeTheme(); connect(m_gsetting, &QGSettings::changed, this, [=]() { changeTheme(); }); QString qtTransPath = QLibraryInfo::location(QLibraryInfo::TranslationsPath); QTranslator *trans_qt = new QTranslator(this); if (trans_qt->load(QLocale(), "qt", "_", qtTransPath)) qApp->installTranslator(trans_qt); QTranslator *trans = new QTranslator(this); if (trans->load(QString(":/translations/gui_%1.qm").arg(QLocale::system().name()))) qApp->installTranslator(trans); if (d->isOpenKylin()) d->m_pAppSupportLabel->hide(); d->setAccessInfo(); } KAboutDialog::~KAboutDialog() { } void KAboutDialog::setAppIcon(const QIcon &icon) { Q_D(KAboutDialog); d->m_iconName = icon.name(); QPixmap pix(icon.pixmap(QSize(96, 96))); d->m_pAppIconLabel->setPixmap(pix); d->m_pAppIconLabel->setAlignment(Qt::AlignCenter); update(); } void KAboutDialog::setAppName(const QString &appName) { Q_D(KAboutDialog); d->m_pAppNameLabel->setText(d->ConvertFirstLetterCase(appName)); update(); } QString KAboutDialog::appName() { Q_D(KAboutDialog); return d->m_pAppNameLabel->text(); } void KAboutDialog::setAppVersion(const QString &appVersion) { Q_D(KAboutDialog); if (!appVersion.isNull()) { d->m_appVersionFlag = false; d->m_pAppVersionLabel->setText(appVersion); update(); } } QString KAboutDialog::appVersion() { Q_D(KAboutDialog); return d->m_pAppVersionLabel->text(); } void KAboutDialog::setBodyText(const QString &bodyText) { Q_D(KAboutDialog); d->m_bodyText = bodyText; } QString KAboutDialog::bodyText() { Q_D(KAboutDialog); return d->m_bodyText; } void KAboutDialog::setAppSupport(const QString &appSupport) { Q_D(KAboutDialog); d->m_pAppSupportLabel->setText(appSupport); update(); } QString KAboutDialog::appSupport() { Q_D(KAboutDialog); return d->m_pAppSupportLabel->text(); } void KAboutDialog::setBodyTextVisiable(bool flag) { Q_D(KAboutDialog); // do nothing } void KAboutDialog::setAppPrivacyLabelVisible(bool flag) { Q_D(KAboutDialog); d->m_pAppPrivacyLabel->setVisible(flag); } bool KAboutDialog::AppPrivacyLabelIsVisible() { Q_D(KAboutDialog); return d->m_pAppPrivacyLabel->isVisible(); } void KAboutDialog::changeTheme() { Q_D(KAboutDialog); KDialog::changeTheme(); auto icon = QIcon::fromTheme(d->m_iconName); if (!icon.isNull()) { QPixmap pix(icon.pixmap(QSize(96, 96))); d->m_pAppIconLabel->setPixmap(pix); } QPalette palette = qApp->palette(); QFont font; font.setPixelSize(ThemeController::systemFontSize() * 1.7); font.setWeight(QFont::Medium); QColor fontColor = ThemeController::getCustomColorFromDT("kfont-primary"); if (fontColor.isValid()) { palette.setColor(QPalette::Text, fontColor); palette.setColor(QPalette::WindowText, fontColor); d->m_pAppNameLabel->setPalette(palette); } d->m_pAppNameLabel->setFont(font); QColor textColor = ThemeController::getCustomColorFromDT("kfont-secondary"); palette.setColor(QPalette::Text, textColor); palette.setColor(QPalette::WindowText, textColor); d->m_pAppSupportLabel->setPalette(palette); d->m_pAppVersionLabel->setPalette(palette); int r = textColor.red(); int g = textColor.green(); int b = textColor.blue(); float a = textColor.alphaF(); QString rgbaColor = QString("rgba(%1, %2, %3, %4)") .arg(r).arg(g).arg(b).arg(a); d->m_pAppSupportLabel->setText(tr("Service & Support: ") + QString("" "support@kylinos.cn").arg(rgbaColor)); QColor privacyColor = ThemeController::getCustomColorFromDT("highlight-active"); palette.setColor(QPalette::WindowText, privacyColor); d->m_pAppPrivacyLabel->setPalette(palette); d->m_pAppPrivacyLabel->setText(tr("Privacy statement")); } void KAboutDialog::paintEvent(QPaintEvent *paintEvent) { Q_D(KAboutDialog); if (d->m_appVersionFlag) d->updateAppVersionText(); QStyleOption opt; opt.initFrom(this); QPainter p(this); style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this); } KAboutDialogPrivate::KAboutDialogPrivate(KAboutDialog *parent) : q_ptr(parent) , m_appVersionFlag(true) { setParent(parent); } void KAboutDialogPrivate::adjustMiniMode() { Q_Q(KAboutDialog); if (q->mainWidget()->layout()) delete q->mainWidget()->layout(); m_pAppSupportLabel->setAlignment(Qt::AlignCenter); QVBoxLayout *vBoxLayout = new QVBoxLayout(); vBoxLayout->setSpacing(0); vBoxLayout->addSpacing(20); vBoxLayout->addWidget(m_pAppIconLabel); vBoxLayout->addSpacing(24); vBoxLayout->addWidget(m_pAppNameLabel); vBoxLayout->addSpacing(16); vBoxLayout->addWidget(m_pAppVersionLabel); vBoxLayout->addSpacing(16); vBoxLayout->addWidget(m_pAppSupportLabel); vBoxLayout->addSpacing(16); vBoxLayout->addWidget(m_pAppPrivacyLabel); vBoxLayout->setContentsMargins(25, 0, 25, 0); vBoxLayout->addSpacing(35); q->mainWidget()->setLayout(vBoxLayout); } QString KAboutDialogPrivate::getDefaultAppId(const char *contentType) { QString localfile = QDir::homePath() + LOCAL_CONFIG_DIR + "mimeapps.list"; QString systemfile = SYSTEM_CONFIG_DIR + QString("ukui-mimeapps.list"); if (QFile(localfile).exists()) { QSettings *mimeappFile = new QSettings(localfile, QSettings::IniFormat); // mimeappFile->setIniCodec("utf-8"); QString str = mimeappFile->value(QString("Default Applications/%1").arg(contentType)).toString(); for(int i = 0; i setIniCodec("utf-8"); QString str = mimeappFile->value(QString("Default Applications/%1").arg(contentType)).toString(); for(int i = 0; i setText(result); } process.close(); } QString KAboutDialogPrivate::ConvertFirstLetterCase(const QString &input) { QStringList words; if (input.contains('-')) { words = input.split('-', Qt::SkipEmptyParts); for (int i = 0; i < words.size(); ++i) { QString &word = words[i]; word[0] = word[0].toUpper(); // 将每个单词的首字母转换为大写 } } else { words = input.split(' ', Qt::SkipEmptyParts); for (int i = 0; i < words.size(); ++i) { QString &word = words[i]; word[0] = word[0].toUpper(); // 将每个单词的首字母转换为大写 } } return words.join(" "); } QStringList KAboutDialogPrivate::getSystemConfigDir() { QString xdgDataDirs = QProcessEnvironment::systemEnvironment().value("XDG_DATA_DIRS"); if (xdgDataDirs.isEmpty()) { qWarning() << "XDG_DATA_DIRS environment variable is not set!"; } QStringList paths = xdgDataDirs.split(':', Qt::SkipEmptyParts); for (QString &path : paths) { path = path.trimmed(); } return paths; } void KAboutDialogPrivate::setAccessInfo() { Q_Q(KAboutDialog); KDK_ALL_INFO_FORMAT(m_pAppIconLabel,""); KDK_ALL_INFO_FORMAT(m_pAppNameLabel,""); KDK_ALL_INFO_FORMAT(m_pAppVersionLabel,""); KDK_ALL_INFO_FORMAT(m_pAppSupportLabel,""); KDK_ALL_INFO_FORMAT(m_pAppPrivacyLabel,""); } LinkLabel::LinkLabel(QWidget *parent) : QLabel(parent) { } void LinkLabel::mousePressEvent(QMouseEvent *event) { if (event->button() == Qt::LeftButton) { QProcess *process = new QProcess(this); QStringList l; l << "-A" << "kylin-os"; process->start("kylin-user-guide", l); } QLabel::mousePressEvent(event); } } #include "kaboutdialog.moc" #include "moc_kaboutdialog.cpp" libkysdk-applications/kysdk-qtwidgets/src/kuninstalldialog.h0000664000175000017500000000426115104543305023445 0ustar fengfeng/* * libkysdk-qtwidgets's Library * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #ifndef KUNINSTALLDIALOG_H #define KUNINSTALLDIALOG_H #include "gui_g.h" #include "kdialog.h" #include "themeController.h" #include #include #include #include #include namespace kdk { /** @defgroup DialogBoxModule * @{ */ static const QByteArray ORG_UKUI_STYLE_FONT = "org.ukui.style"; static const QByteArray GSETTING_FONT_KEY = "systemFontSize"; class KUninstallDialogPrivate; /** * @brief 卸载对话框,当用户卸载时可能会弹出此提示对话框 * @since 1.0.0 */ class GUI_EXPORT KUninstallDialog : public KDialog { Q_OBJECT public: KUninstallDialog(QString appName, QString appVersion, QWidget *parent = nullptr); ~KUninstallDialog(); /** * @brief debAppNameLabel * @return */ QLabel *debAppNameLabel(); /** * @brief 包名Label * @return */ QLabel *debNameLabel(); /** * @brief 包IconLabel * @return */ QLabel *debIconLabel(); /** * @brief 包版本Label * @return */ QLabel *debVersionLabel(); /** * @brief 卸载按钮 * @return */ QPushButton *uninstallButtton(); protected: void changeTheme(); private: Q_DECLARE_PRIVATE(KUninstallDialog) KUninstallDialogPrivate *const d_ptr; }; } /** * @example testDialog/widget.h * @example testDialog/widget.cpp * @} */ #endif // KUNINSTALLDIALOG_H libkysdk-applications/kysdk-qtwidgets/src/kcolorbutton.cpp0000664000175000017500000001365115104543305023164 0ustar fengfeng/* * libkysdk-qtwidgets's Library * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #include "kcolorbutton.h" #include "themeController.h" #include #include #include namespace kdk { static const int circleButtonSize = 20; static const int normalButtonSize = 24; class KColorButtonPrivate : public QObject, public ThemeController { Q_OBJECT Q_DECLARE_PUBLIC(KColorButton) public: KColorButtonPrivate(KColorButton *parent); protected: void changeTheme(); private: KColorButton *const q_ptr; bool m_backgroundFlag; QColor m_backgroundColor; int m_radius; KColorButton::ButtonType m_buttonType; }; KColorButton::KColorButton(QWidget *parent) : QPushButton(parent) , d_ptr(new KColorButtonPrivate(this)) { Q_D(KColorButton); setCheckable(true); } void KColorButton::setBackgroundColor(QColor color) { Q_D(KColorButton); d->m_backgroundFlag = true; d->m_backgroundColor = color; update(); } QColor KColorButton::backgroundColor() { Q_D(KColorButton); return d->m_backgroundColor; } void KColorButton::setBorderRadius(int radious) { Q_D(KColorButton); d->m_radius = radious; } int KColorButton::borderRadius() { Q_D(KColorButton); return d->m_radius; } void KColorButton::setButtonType(KColorButton::ButtonType type) { Q_D(KColorButton); d->m_buttonType = type; } KColorButton::ButtonType KColorButton::buttonType() { Q_D(KColorButton); return d->m_buttonType; } void KColorButton::paintEvent(QPaintEvent *) { Q_D(KColorButton); QStyleOptionButton option; initStyleOption(&option); QRect rect = option.rect; QPainter painter(this); painter.setRenderHint(QPainter::Antialiasing); painter.setRenderHint(QPainter::SmoothPixmapTransform); painter.setPen(Qt::NoPen); if (!option.state.testFlag(QStyle::State_Enabled)) { painter.save(); painter.setBrush(ThemeController::getCustomColorFromDT("buttontext-disable")); painter.drawRoundedRect(rect, d->m_radius, d->m_radius); painter.restore(); } else if (d->m_buttonType == RoundedRect) { painter.save(); if (d->m_backgroundFlag) { painter.setBrush(d->m_backgroundColor); } else { painter.setBrush(ThemeController::getCustomColorFromDT("highlight-active")); } if (isChecked() || option.state.testFlag(QStyle::State_MouseOver)) { painter.save(); painter.setBrush(Qt::white); painter.drawRoundedRect(rect, d->m_radius, d->m_radius); // 绘制边框 rect = rect.adjusted(2, 2, -2, -2); painter.restore(); painter.drawRoundedRect(rect, d->m_radius / 2, d->m_radius / 2); } else painter.drawRoundedRect(rect, d->m_radius, d->m_radius); painter.restore(); } else if (d->m_buttonType == Circle) { painter.save(); QRect rect = option.rect.adjusted(1, 1, 0, 0); if (d->m_backgroundFlag) { painter.setBrush(d->m_backgroundColor); } else { painter.setBrush(ThemeController::getCustomColorFromDT("highlight-active")); } painter.drawEllipse(rect); QRect rect1 = rect.adjusted(rect.width() / 4, rect.height() / 4, -rect.width() / 4, -rect.height() / 4); if (option.state.testFlag(QStyle::State_MouseOver) || isChecked()) { painter.save(); painter.setBrush(Qt::white); painter.drawEllipse(rect1); painter.restore(); } painter.restore(); } else { painter.save(); if (d->m_backgroundFlag) { painter.setBrush(d->m_backgroundColor); } else { painter.setBrush(ThemeController::getCustomColorFromDT("highlight-active")); } if (isChecked()) { QPointF points[3] = { QPointF(rect.x() + rect.width() * 2 / 11, rect.y() + rect.height() * 6 / 11), QPointF(rect.x() + rect.width() * 5 / 11, rect.y() + rect.height() * 8 / 11), QPointF(rect.x() + rect.width() * 9 / 11, rect.y() + rect.height() * 4 / 11), }; painter.drawRoundedRect(rect, d->m_radius, d->m_radius); painter.setPen(QPen(Qt::white, 2)); painter.drawPolyline(points, 3); } else { painter.drawRoundedRect(rect, d->m_radius, d->m_radius); } painter.restore(); } } QSize KColorButton::sizeHint() const { Q_D(const KColorButton); if (d->m_buttonType == Circle) return QSize(circleButtonSize, circleButtonSize); else return QSize(normalButtonSize, normalButtonSize); } KColorButtonPrivate::KColorButtonPrivate(KColorButton *parent) : q_ptr(parent) { Q_Q(KColorButton); m_backgroundFlag = false; m_radius = ThemeController::getRadiusFromDT("kradius-normal"); m_buttonType = KColorButton::RoundedRect; m_backgroundColor = ThemeController::getCustomColorFromDT("highlight-active"); connect(m_gsetting, &QGSettings::changed, this, [=]() { changeTheme(); q->update(); }); } void KColorButtonPrivate::changeTheme() { Q_Q(KColorButton); initThemeStyle(); } } #include "kcolorbutton.moc" #include "moc_kcolorbutton.cpp" libkysdk-applications/kysdk-qtwidgets/src/kcustomdateedit.cpp0000664000175000017500000002277515104543305023637 0ustar fengfeng/* * libkysdk-qtwidgets's Library * * Copyright (C) 2024, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #include "kcustomdateedit.h" #include "themeController.h" #include #include #include #include #include #include #include #include namespace kdk { class KCustomDateEditPrivate : public QObject { Q_DECLARE_PUBLIC(KCustomDateEdit) Q_OBJECT public: KCustomDateEditPrivate(KCustomDateEdit *parent); private slots: void onDateSelected(const QDate &date); QPixmap loadSvg(const QString &path, int size); QPixmap drawSymbolicColoredPixmap(const QPixmap &source); private: KCustomDateEdit *q_ptr; KMiniCalendarWidget *m_pCalendar; bool hoverFlag = false; bool focusFlag = false; }; KCustomDateEditPrivate::KCustomDateEditPrivate(KCustomDateEdit *parent) : q_ptr(parent) { Q_Q(KCustomDateEdit); m_pCalendar = new KMiniCalendarWidget(q); m_pCalendar->setFixedSize(244, 264); m_pCalendar->setWeekNameFormat(KMiniCalendarWidget::WeekNameFormat_Short); connect(m_pCalendar, &KMiniCalendarWidget::clicked, this, &KCustomDateEditPrivate::onDateSelected); } void KCustomDateEditPrivate::onDateSelected(const QDate &date) { Q_Q(KCustomDateEdit); q->setDate(date); } QPixmap KCustomDateEditPrivate::loadSvg(const QString &path, int size) { Q_Q(KCustomDateEdit); int origSize = size; const auto ratio = qApp->devicePixelRatio(); if (2 == ratio) { size += origSize; } else if (3 == ratio) { size += origSize; } QPixmap pixmap(size, size); QSvgRenderer renderer(path); pixmap.fill(Qt::transparent); QPainter painter; painter.begin(&pixmap); renderer.render(&painter); painter.end(); pixmap.setDevicePixelRatio(ratio); return drawSymbolicColoredPixmap(pixmap); } QPixmap KCustomDateEditPrivate::drawSymbolicColoredPixmap(const QPixmap &source) { Q_Q(KCustomDateEdit); QImage img = source.toImage(); for (int x = 0; x < img.width(); x++) { for (int y = 0; y < img.height(); y++) { QColor color = img.pixelColor(x, y); if (color.alpha() > 0) { QColor colorSet = ThemeController::getCustomColorFromDT("buttontext-active"); color.setRed(colorSet.red()); color.setGreen(colorSet.green()); color.setBlue(colorSet.blue()); img.setPixelColor(x, y, color); } } } return QPixmap::fromImage(img); } KCustomDateEdit::KCustomDateEdit(QWidget *parent) : QDateTimeEdit(parent) , d_ptr(new KCustomDateEditPrivate(this)) { Q_D(KCustomDateEdit); this->installEventFilter(this); this->setButtonSymbols(QAbstractSpinBox::NoButtons); } void KCustomDateEdit::showCalendar() { Q_D(KCustomDateEdit); QStyleOptionComboBox opt; opt.initFrom(this); QRect arrowRect = style()->subControlRect(QStyle::CC_ComboBox, &opt, QStyle::SC_ComboBoxArrow, this); int randomX = QRandomGenerator::global()->bounded(arrowRect.x(), arrowRect.x() + arrowRect.width()); int randomY = QRandomGenerator::global()->bounded(arrowRect.y(), arrowRect.y() + arrowRect.height()); QMouseEvent *event = new QMouseEvent(QEvent::MouseButtonPress, QPoint(randomX, randomY), Qt::LeftButton, Qt::LeftButton, Qt::NoModifier); QApplication::postEvent(this, event); } void KCustomDateEdit::setShowLunar(bool showLunar) { Q_D(KCustomDateEdit); d->m_pCalendar->setShowLunar(showLunar); } void KCustomDateEdit::updateStyle(bool isDark) { Q_D(KCustomDateEdit); if (d->m_pCalendar == nullptr) return; if (isDark) { d->m_pCalendar->setWeekBgColor(QColor(29, 29, 29)); d->m_pCalendar->setWeekTextColor(QColor(255, 255, 255)); d->m_pCalendar->setBorderColor(QColor(180, 180, 180)); d->m_pCalendar->setWeekColor(QColor(255, 255, 255)); d->m_pCalendar->setLunarColor(QColor(55, 156, 238)); d->m_pCalendar->setCurrentTextColor(QColor(255, 255, 255)); d->m_pCalendar->setOtherTextColor(QColor(200, 200, 200)); d->m_pCalendar->setSelectTextColor(QColor(255, 255, 255)); d->m_pCalendar->setHoverTextColor(QColor(250, 250, 250)); d->m_pCalendar->setCurrentLunarColor(QColor(179, 179, 179)); d->m_pCalendar->setOtherLunarColor(QColor(179, 179, 179)); d->m_pCalendar->setSelectLunarColor(QColor(179, 179, 179)); d->m_pCalendar->setHoverLunarColor(QColor(179, 179, 179)); d->m_pCalendar->setCurrentBgColor(QColor(29, 29, 29)); d->m_pCalendar->setOtherBgColor(QColor(29, 29, 29)); d->m_pCalendar->setSelectBgColor(ThemeController::getCustomColorFromDT("kbrand-normal")); d->m_pCalendar->setHoverBgColor(QColor(180, 180, 180)); } else { d->m_pCalendar->setWeekBgColor(QColor(255, 255, 255)); d->m_pCalendar->setWeekTextColor(QColor(0, 0, 0)); d->m_pCalendar->setBorderColor(QColor(180, 180, 180)); d->m_pCalendar->setWeekColor(QColor(0, 0, 0)); d->m_pCalendar->setLunarColor(QColor(55, 156, 238)); d->m_pCalendar->setCurrentTextColor(QColor(0, 0, 0)); d->m_pCalendar->setOtherTextColor(QColor(200, 200, 200)); d->m_pCalendar->setSelectTextColor(QColor(255, 255, 255)); d->m_pCalendar->setHoverTextColor(QColor(250, 250, 250)); d->m_pCalendar->setCurrentLunarColor(QColor(179, 179, 179)); d->m_pCalendar->setOtherLunarColor(QColor(179, 179, 179)); d->m_pCalendar->setSelectLunarColor(QColor(179, 179, 179)); d->m_pCalendar->setHoverLunarColor(QColor(179, 179, 179)); d->m_pCalendar->setCurrentBgColor(QColor(255, 255, 255)); d->m_pCalendar->setOtherBgColor(QColor(255, 255, 255)); d->m_pCalendar->setSelectBgColor(ThemeController::getCustomColorFromDT("kbrand-normal")); d->m_pCalendar->setHoverBgColor(QColor(180, 180, 180)); } } void KCustomDateEdit::mousePressEvent(QMouseEvent *event) { Q_D(KCustomDateEdit); QStyleOptionComboBox opt; opt.initFrom(this); QRect arrowRect = style()->subControlRect(QStyle::CC_ComboBox, &opt, QStyle::SC_ComboBoxArrow, this); QPoint point = event->pos(); if (arrowRect.contains(event->pos())) { d->m_pCalendar->setDate(this->date()); d->m_pCalendar->move(mapToGlobal(QPoint(0, height()))); d->m_pCalendar->show(); } else { QDateTimeEdit::mousePressEvent(event); } } void KCustomDateEdit::paintEvent(QPaintEvent *e) { Q_D(KCustomDateEdit); Q_UNUSED(e); QPainter painter(this); painter.setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform); // 反锯齿; QBrush brush = QBrush(ThemeController::getCustomColorFromDT("button-active")); painter.setPen(Qt::NoPen); painter.setBrush(brush); int radius = ThemeController::getRadiusFromDT("kradius-normal"); if (radius == -1) radius = 6; painter.drawRoundedRect(this->rect(), radius, radius); QPixmap pix = d->loadSvg("/usr/share/kylin-user-guide/data/ukui-down-symbolic.svg", 64); // QRect rect = QRect(113, 10, 15, 15); QRect rect = QRect(this->rect().right()-24, 10, 16, 16); painter.drawPixmap(rect, pix); QRect rectBoxt = this->rect(); painter.setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform); // 反锯齿; if (d->m_pCalendar && d->m_pCalendar->isVisible()) { d->focusFlag = true; } if (d->focusFlag == true) { // QPen pen(palette().brush(QPalette::Active, QPalette::Highlight), 2); QPen pen(ThemeController::getCustomColorFromDT("highlight-active"), 2); pen.setJoinStyle(Qt::RoundJoin); painter.setPen(pen); painter.setBrush(Qt::NoBrush); painter.translate(1, 1); painter.drawRoundedRect(rectBoxt.adjusted(0, 0, -2, -2), 6, 6); } else if (d->hoverFlag == true) { painter.setPen(ThemeController::getCustomColorFromDT("highlight-active")); painter.setBrush(Qt::NoBrush); painter.translate(0.5, 0.5); painter.drawRoundedRect(rectBoxt.adjusted(0, 0, -1, -1), 6, 6); } } bool KCustomDateEdit::eventFilter(QObject *obj, QEvent *event) { Q_D(KCustomDateEdit); if (QEvent::HoverEnter == event->type()) { d->hoverFlag = true; repaint(); } else if (QEvent::HoverLeave == event->type()) { d->hoverFlag = false; repaint(); } else if (QEvent::FocusIn == event->type()) { d->focusFlag = true; repaint(); } else if (QEvent::FocusOut == event->type()) { d->focusFlag = false; d->hoverFlag = false; repaint(); if (this->date() != QDateTime::currentDateTime().date() && !d->m_pCalendar->isVisible()) { Q_EMIT changeDate(); } } return QObject::eventFilter(obj, event); } } #include "kcustomdateedit.moc" #include "moc_kcustomdateedit.cpp" libkysdk-applications/kysdk-qtwidgets/src/klineframe.cpp0000664000175000017500000000725315104543305022555 0ustar fengfeng/* * libkysdk-qtwidgets's Library * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #include "klineframe.h" #include "themeController.h" #include #include namespace kdk { class KHLineFramePrivate : public QObject, public ThemeController { Q_OBJECT Q_DECLARE_PUBLIC(KHLineFrame) public: KHLineFramePrivate(KHLineFrame *parent); void changeTheme(); private: KHLineFrame *q_ptr; bool m_isFollowPalette; }; class KVLineFramePrivate : public QObject, public ThemeController { Q_OBJECT Q_DECLARE_PUBLIC(KVLineFrame) public: KVLineFramePrivate(KVLineFrame *parent); void changeTheme(); private: KVLineFrame *q_ptr; bool m_isFollowPalette; }; KHLineFrame::KHLineFrame(QWidget *parent) : QFrame(parent) , d_ptr(new KHLineFramePrivate(this)) { setContentsMargins(0, 10, 0, 10); this->setFrameShape(QFrame::Shape::HLine); setLineWidth(1); QPalette palette = qApp->palette(); QColor color(ThemeController::getCustomColorFromDT("kline-normal")); palette.setColor(QPalette::Window, color); setPalette(palette); setFixedHeight(1); setAutoFillBackground(true); } KHLineFrame::~KHLineFrame() { } void KHLineFrame::setFollowPalette(bool flag) { Q_D(KHLineFrame); d->m_isFollowPalette = flag; } KHLineFramePrivate::KHLineFramePrivate(KHLineFrame *parent) : q_ptr(parent) { Q_Q(KHLineFrame); m_isFollowPalette = true; connect(m_gsetting, &QGSettings::changed, this, [=]() { changeTheme(); }); } void KHLineFramePrivate::changeTheme() { Q_Q(KHLineFrame); if (m_isFollowPalette) { QPalette palette = qApp->palette(); QColor color(ThemeController::getCustomColorFromDT("kline-normal")); palette.setColor(QPalette::Window, color); q->setPalette(palette); } } KVLineFrame::KVLineFrame(QWidget *parent) : QFrame(parent) , d_ptr(new KVLineFramePrivate(this)) { setContentsMargins(10, 0, 10, 0); setLineWidth(1); this->setFrameShape(QFrame::Shape::VLine); QPalette palette = qApp->palette(); QColor color(ThemeController::getCustomColorFromDT("kline-normal")); palette.setColor(QPalette::Window, color); setPalette(palette); setFixedWidth(1); setAutoFillBackground(true); } KVLineFrame::~KVLineFrame() { } void KVLineFrame::setFollowPalette(bool flag) { Q_D(KVLineFrame); d->m_isFollowPalette = flag; } KVLineFramePrivate::KVLineFramePrivate(KVLineFrame *parent) : q_ptr(parent) { Q_Q(KVLineFrame); m_isFollowPalette = true; connect(m_gsetting, &QGSettings::changed, this, [=]() { changeTheme(); }); } void KVLineFramePrivate::changeTheme() { Q_Q(KVLineFrame); if (m_isFollowPalette) { QPalette palette = qApp->palette(); QColor color(ThemeController::getCustomColorFromDT("kline-normal")); palette.setColor(QPalette::Window, color); q->setPalette(palette); } } } #include "klineframe.moc" #include "moc_klineframe.cpp" libkysdk-applications/kysdk-qtwidgets/src/kborderbutton.h0000664000175000017500000000353415104543305022767 0ustar fengfeng/* * libkysdk-qtwidgets's Library * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #ifndef KBORDERBUTTON_H #define KBORDERBUTTON_H #include "gui_g.h" #include #include #include #include namespace kdk { /** @defgroup PushbuttonModule * @{ */ class KBorderButtonPrivate; /** * @brief 带边框的按钮 * @since 1.0.0 */ class GUI_EXPORT KBorderButton : public QPushButton { Q_OBJECT public: KBorderButton(QWidget *parent = nullptr); KBorderButton(const QString &text, QWidget *parent = nullptr); KBorderButton(const QIcon &icon, const QString &text, QWidget *parent = nullptr); KBorderButton(const QIcon &icon, QWidget *parent = nullptr); /** * @brief 设置按钮图标 * @param icon */ void setIcon(const QIcon &icon); ~KBorderButton(); protected: bool eventFilter(QObject *watched, QEvent *event); void paintEvent(QPaintEvent *event); QSize sizeHint() const override; private: Q_DECLARE_PRIVATE(KBorderButton) KBorderButtonPrivate *const d_ptr; }; } /** * @example testPushbutton/widget.h * @example testPushbutton/widget.cpp * @} */ #endif libkysdk-applications/kysdk-qtwidgets/src/klineedit.h0000664000175000017500000000262415104543305022052 0ustar fengfeng/* * libkysdk-qtwidgets's Library * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhenyu Wang * */ #ifndef KLINEEDIT_H #define KLINEEDIT_H #include "gui_g.h" #include #include namespace kdk { class KLineEditPrivate; /** * @defgroup InputBoxModule * @since 2.5.2.0 * { */ class GUI_EXPORT KLineEdit : public QLineEdit { Q_OBJECT public: KLineEdit(QWidget *parent = nullptr); /** * @brief 获取按钮 * @return */ QPushButton *pushbutton(); protected: void resizeEvent(QResizeEvent *event); bool eventFilter(QObject *watched, QEvent *event); private: Q_DECLARE_PRIVATE(KLineEdit) KLineEditPrivate *const d_ptr; }; } #endif // KLINEEDIT_H libkysdk-applications/kysdk-qtwidgets/src/kshadowhelper.cpp0000664000175000017500000001603415104543305023275 0ustar fengfeng/* * libkysdk-qtwidgets's Library * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #include "kshadowhelper.h" #include #include #include #include #include #include #include extern void qt_blurImage(QImage &blurImage, qreal radius, bool quality, int transposed); namespace kdk { namespace effects { class KShadowHelperPrivate : public QObject { Q_DECLARE_PUBLIC(KShadowHelper) Q_OBJECT public: KShadowHelperPrivate(KShadowHelper *parent); QPixmap getShadowPixmap(QColor color, int shadowBorder, qreal darkness, int borderRadius = 0); KWindowShadow *getShadow(QColor color, int shadowBorder, qreal darkness, int borderRadius = 0); protected: bool eventFilter(QObject *watched, QEvent *event); private: KShadowHelper *q_ptr; QMap m_shadows; }; static KShadowHelper *g_kshadowHelper = nullptr; KShadowHelper *KShadowHelper::self() { if (g_kshadowHelper) return g_kshadowHelper; g_kshadowHelper = new KShadowHelper(); return g_kshadowHelper; } void KShadowHelper::setWidget(QWidget *widget, int borderRadius, int shadowWidth, qreal darkness) { Q_D(KShadowHelper); KWindowShadow *shadow = d->getShadow(QColor(26, 26, 26), shadowWidth, darkness, borderRadius); shadow->setPadding(QMargins(shadowWidth, shadowWidth, shadowWidth, shadowWidth)); widget->installEventFilter(d); d->m_shadows.insert(widget, shadow); connect(widget, &QWidget::destroyed, this, [=]() { if (auto shadowToBeDelete = d->m_shadows.value(widget)) { if (shadowToBeDelete->isCreated()) shadowToBeDelete->destroy(); shadowToBeDelete->deleteLater(); d->m_shadows.remove(widget); } }); } KShadowHelper::KShadowHelper(QObject *parent) : QObject(parent) , d_ptr(new KShadowHelperPrivate(this)) { } KShadowHelperPrivate::KShadowHelperPrivate(KShadowHelper *parent) : q_ptr(parent) { } QPixmap KShadowHelperPrivate::getShadowPixmap(QColor color, int shadowBorder, qreal darkness, int borderRadius) { QPixmap pixmap(QSize(100, 100)); pixmap.fill(Qt::transparent); QPainter painter(&pixmap); painter.setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform); painter.setBrush(color); painter.setPen(Qt::NoPen); painter.drawRoundedRect(pixmap.rect().adjusted(shadowBorder, shadowBorder, -shadowBorder, -shadowBorder), borderRadius, borderRadius); QImage rawImg = pixmap.toImage(); qt_blurImage(rawImg, shadowBorder, true, true); for (int x = 0; x < rawImg.width(); x++) { for (int y = 0; y < rawImg.height(); y++) { auto color = rawImg.pixelColor(x, y); if (color.alpha() == 0) continue; color.setAlphaF(darkness * color.alphaF()); rawImg.setPixelColor(x, y, color); } } QPixmap target = QPixmap::fromImage(rawImg); QPainter painter2(&target); painter2.setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform); painter2.setCompositionMode(QPainter::CompositionMode_Clear); painter2.setBrush(Qt::transparent); painter2.setPen(Qt::NoPen); painter2.drawRoundedRect(target.rect().adjusted(shadowBorder, shadowBorder, -shadowBorder, -shadowBorder), borderRadius, borderRadius); return target; } KWindowShadow *KShadowHelperPrivate::getShadow(QColor color, int shadowBorder, qreal darkness, int borderRadius) { QPixmap pixmap = getShadowPixmap(color, shadowBorder, darkness, borderRadius); int parm = shadowBorder * 2; QPixmap topLeftPixmap = pixmap.copy(0, 0, parm, parm); QPixmap topPixmap = pixmap.copy(parm, 0, pixmap.width() - parm * 2, parm); QPixmap topRightPixmap = pixmap.copy(pixmap.width() - parm, 0, parm, parm); QPixmap leftPixmap = pixmap.copy(0, parm, parm, pixmap.height() - parm * 2); QPixmap rightPixmap = pixmap.copy(pixmap.width() - parm, parm, parm, pixmap.height() - parm * 2); QPixmap bottomLeftPixmap = pixmap.copy(0, pixmap.height() - parm, parm, parm); QPixmap bottomPixmap = pixmap.copy(parm, pixmap.height() - parm, pixmap.width() - parm * 2, parm); QPixmap bottomRightPixmap = pixmap.copy(pixmap.width() - parm, pixmap.height() - parm, parm, parm); KWindowShadow *shadow = new KWindowShadow; KWindowShadowTile::Ptr topLeftTile = KWindowShadowTile::Ptr::create(); topLeftTile.get()->setImage(topLeftPixmap.toImage()); shadow->setTopLeftTile(topLeftTile); KWindowShadowTile::Ptr topTile = KWindowShadowTile::Ptr::create(); topTile.get()->setImage(topPixmap.toImage()); shadow->setTopTile(topTile); KWindowShadowTile::Ptr topRightTile = KWindowShadowTile::Ptr::create(); topRightTile.get()->setImage(topRightPixmap.toImage()); shadow->setTopRightTile(topRightTile); KWindowShadowTile::Ptr leftTile = KWindowShadowTile::Ptr::create(); leftTile.get()->setImage(leftPixmap.toImage()); shadow->setLeftTile(leftTile); KWindowShadowTile::Ptr rightTile = KWindowShadowTile::Ptr::create(); rightTile.get()->setImage(rightPixmap.toImage()); shadow->setRightTile(rightTile); KWindowShadowTile::Ptr bottomLeftTile = KWindowShadowTile::Ptr::create(); bottomLeftTile.get()->setImage(bottomLeftPixmap.toImage()); shadow->setBottomLeftTile(bottomLeftTile); KWindowShadowTile::Ptr bottomTile = KWindowShadowTile::Ptr::create(); bottomTile.get()->setImage(bottomPixmap.toImage()); shadow->setBottomTile(bottomTile); KWindowShadowTile::Ptr bottomRightTile = KWindowShadowTile::Ptr::create(); bottomRightTile.get()->setImage(bottomRightPixmap.toImage()); shadow->setBottomRightTile(bottomRightTile); return shadow; } bool KShadowHelperPrivate::eventFilter(QObject *watched, QEvent *event) { if (watched->isWidgetType()) { auto widget = qobject_cast(watched); if (widget->isTopLevel() && event->type() == QEvent::Show) { if (auto shadow = m_shadows.value(widget)) { shadow->setWindow(widget->windowHandle()); shadow->create(); } } } return QObject::eventFilter(watched, event); } } } #include "kshadowhelper.moc" #include "moc_kshadowhelper.cpp" libkysdk-applications/kysdk-qtwidgets/src/kloopplaypage.h0000664000175000017500000000410015104543305022740 0ustar fengfeng/* * libkysdk-qtwidgets's Library * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhenyu Wang * */ #ifndef KLOOPPLAYPAGE_H #define KLOOPPLAYPAGE_H #include "gui_g.h" #include namespace kdk { class KLoopPlayPagePrivate; /** * @defgroup FrameModule * @brief 轮播图片控件 * @since 2.5.2.0 * { */ class GUI_EXPORT KLoopPlayPage : public QWidget { Q_OBJECT public: KLoopPlayPage(QWidget *parent = nullptr); /** * @brief 添加widget * @param widget */ void addWidget(QWidget *widget); /** * @brief 删除widget * @param widget */ void removeWidget(QWidget *widget); /** * @brief 设置当前中心界面 * @param i */ void setCurrentWidget(int i); /** * @brief 获取当前中心界面index * @return */ int currentWidget(); /** * @brief 设置窗体间距 * @param spacing */ void setWidgetSpacing(int spacing); /** * @brief 设置轮播时长 * @param time */ void setLoopTime(int time); Q_SIGNALS: void leftClick(); void centerClick(); void rightClick(); protected: void resizeEvent(QResizeEvent *event); void paintEvent(QPaintEvent *event); void showEvent(QShowEvent *event) override; private: KLoopPlayPagePrivate *const d_ptr; Q_DECLARE_PRIVATE(KLoopPlayPage) }; } #endif // KLOOPPLAYPAGE_H libkysdk-applications/kysdk-qtwidgets/src/kprogresslabel.cpp0000664000175000017500000003235715104543305023462 0ustar fengfeng/* * libkysdk-qtwidgets's Library * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhenyu Wang * */ #include "kprogresslabel.h" #include "themeController.h" #include #include #include #include namespace kdk { class Q_DECL_HIDDEN LineLabel : public QLabel { Q_OBJECT public: LineLabel(QWidget *parent = nullptr); virtual ~LineLabel(); void setBackgroundHighlight(bool flag); protected: virtual void paintEvent(QPaintEvent *); private: QColor m_backgroundColor; bool colorFlag; }; class Q_DECL_HIDDEN CircleLable : public QLabel { Q_OBJECT public: CircleLable(const QString &text, QWidget *parent = nullptr); virtual ~CircleLable(); void setText(const QString &text); void setBackgroundHighlight(bool flag); void setSucceed(bool flag); protected: virtual void paintEvent(QPaintEvent *); private: QString m_text; QColor m_textColor; QColor m_backgroundColor; bool colorFlag; bool isSucceed; int m_radius; }; class Q_DECL_HIDDEN TextLabel : public QLabel, public ThemeController { Q_OBJECT public: TextLabel(QString str, QWidget *parent = nullptr); virtual ~TextLabel(); void setTextHighlight(bool flag); void followPalette(bool flag); protected: virtual void paintEvent(QPaintEvent *); private: bool isPalette; }; class Q_DECL_HIDDEN KProgressLabelPrivate : public QObject, public ThemeController { Q_OBJECT Q_DECLARE_PUBLIC(KProgressLabel) public: KProgressLabelPrivate(KProgressLabel *parent); protected: void changeTheme(); private: KProgressLabel *const q_ptr; QVBoxLayout *mainLayout; QHBoxLayout *circleLayout; QHBoxLayout *textLayout; int m_count; QSize m_circleSize; QList circleList; QList lineList; QList textList; }; KProgressLabel::KProgressLabel(QWidget *parent) : QWidget(parent) , d_ptr(new KProgressLabelPrivate(this)) { Q_D(KProgressLabel); d->mainLayout = new QVBoxLayout(this); QWidget *wid1 = new QWidget(); QWidget *wid2 = new QWidget(); d->circleLayout = new QHBoxLayout(wid1); d->circleLayout->setContentsMargins(0, 0, 0, 0); d->textLayout = new QHBoxLayout(wid2); d->textLayout->setContentsMargins(8, 0, 8, 0); d->mainLayout->setSpacing(0); d->mainLayout->addWidget(wid1); d->mainLayout->addSpacing(8); d->mainLayout->addWidget(wid2); setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed); } KProgressLabel::~KProgressLabel() { } void KProgressLabel::setStringList(QStringList list1, QStringList list2) { Q_D(KProgressLabel); // 若布局不为空,则清空布局 if (!d->circleLayout->isEmpty() || !d->textLayout->isEmpty()) { // 先清除list d->circleList.clear(); d->lineList.clear(); d->textList.clear(); QLayoutItem *child; while ((child = d->circleLayout->takeAt(0)) != 0) { // 删除Stretch(弹簧)等布局 if (child->spacerItem()) { d->circleLayout->removeItem(child); continue; } // 删除布局 d->circleLayout->removeWidget(child->widget()); child->widget()->setParent(nullptr); delete child; child = nullptr; } while ((child = d->textLayout->takeAt(0)) != 0) { if (child->spacerItem()) { d->textLayout->removeItem(child); continue; } d->textLayout->removeWidget(child->widget()); child->widget()->setParent(nullptr); delete child; child = nullptr; } d->circleLayout->addSpacing(80); d->textLayout->addSpacing(11); } for (int i = 0; i < list1.count(); i++) { // 第一行圆形label QString str; if (i < list1.count()) str = list1.at(i); CircleLable *circlelabel = new CircleLable(str, this); circlelabel->setFixedSize(d->m_circleSize); d->circleList.append(circlelabel); d->circleLayout->addWidget(circlelabel); if (i < list1.count() - 1) { // 第一行线条label LineLabel *lineLabel; lineLabel = new LineLabel(this); d->lineList.append(lineLabel); d->circleLayout->addWidget(lineLabel); } } // 第二行文本label for (int i = 0; i < list2.count(); i++) { TextLabel *textLabel = new TextLabel(list2.at(i), this); textLabel->setWordWrap(true); textLabel->setAlignment(Qt::AlignCenter); textLabel->setScaledContents(true); d->textList.append(textLabel); d->textLayout->addWidget(textLabel); if (i < list2.count() - 1) d->textLayout->addStretch(); } } void KProgressLabel::setStringList(QStringList list1) { Q_D(KProgressLabel); if (!d->circleLayout->isEmpty() || !d->textLayout->isEmpty()) { // 先清除list d->circleList.clear(); d->lineList.clear(); d->textList.clear(); QLayoutItem *child; while ((child = d->circleLayout->takeAt(0)) != 0) { // 删除Stretch(弹簧)等布局 if (child->spacerItem()) { d->circleLayout->removeItem(child); continue; } // 删除布局 d->circleLayout->removeWidget(child->widget()); child->widget()->setParent(nullptr); delete child; child = nullptr; } while ((child = d->textLayout->takeAt(0)) != 0) { if (child->spacerItem()) { d->textLayout->removeItem(child); continue; } d->textLayout->removeWidget(child->widget()); child->widget()->setParent(nullptr); delete child; child = nullptr; } d->circleLayout->addSpacing(80); // d->textLayout->addSpacing(11); } for (int i = 0; i < list1.count(); i++) { // 第一行圆形label QString str; CircleLable *circlelabel = new CircleLable(str, this); circlelabel->setFixedSize(d->m_circleSize); d->circleList.append(circlelabel); d->circleLayout->addWidget(circlelabel); if (i < list1.count() - 1) { // 第一行线条label LineLabel *lineLabel; lineLabel = new LineLabel(this); d->lineList.append(lineLabel); d->circleLayout->addWidget(lineLabel); } } // 第二行文本label for (int i = 0; i < list1.count(); i++) { TextLabel *textLabel = new TextLabel(list1.at(i), this); textLabel->setWordWrap(true); textLabel->setAlignment(Qt::AlignCenter); textLabel->setScaledContents(true); d->textList.append(textLabel); d->textLayout->addWidget(textLabel); if (i < list1.count() - 1) d->textLayout->addStretch(); } } void KProgressLabel::setCurrentIndex(int index) { Q_D(KProgressLabel); if (index < -1) return; if (index > d->circleList.count() - 1) return; for (int i = 0; i <= index; i++) { if (i < index) d->circleList.at(i)->setBackgroundHighlight(true); if (i < d->lineList.count()) d->lineList.at(i)->setBackgroundHighlight(true); if (i < index) d->textList.at(i)->setTextHighlight(false); if (i == index) { d->circleList.at(i)->setBackgroundHighlight(false); d->circleList.at(i)->setSucceed(true); d->textList.at(i)->setTextHighlight(true); } } if (d->m_count > index) { for (int j = index + 1; j < d->circleList.count(); j++) { if (j < d->circleList.count()) { d->circleList.at(j)->setSucceed(false); d->circleList.at(j)->setBackgroundHighlight(false); } if (j < d->lineList.count()) d->lineList.at(j)->setBackgroundHighlight(false); if (j < d->textList.count()) d->textList.at(j)->followPalette(false); } } d->m_count = index; repaint(); } int KProgressLabel::currentIndex() { Q_D(KProgressLabel); return d->m_count; } void KProgressLabel::setCircleSize(QSize size) { Q_D(KProgressLabel); for (int count = 0; count < d->circleList.count(); count++) { d->m_circleSize = size; d->circleList.at(count)->setFixedSize(size); d->textLayout->setContentsMargins(size.width() / 2 - 6, 0, size.width() / 2 - 6, 0); } } LineLabel::LineLabel(QWidget *parent) : QLabel(parent) , colorFlag(false) { setMaximumHeight(30); setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); } LineLabel::~LineLabel() { } void LineLabel::setBackgroundHighlight(bool flag) { colorFlag = flag; } void LineLabel::paintEvent(QPaintEvent *event) { Q_UNUSED(event) QPainter painter(this); painter.setRenderHint(QPainter::Antialiasing); painter.save(); if (!colorFlag) { m_backgroundColor = ThemeController::getCustomColorFromDT("midlight-active"); } else { m_backgroundColor = ThemeController::getCustomColorFromDT("highlight-active"); } QPen pen = painter.pen(); pen.setColor(m_backgroundColor); pen.setWidth(2); painter.setPen(pen); QRect rect = this->rect(); painter.drawLine(0, rect.height() / 2, rect.width(), rect.height() / 2); painter.restore(); QLabel::paintEvent(event); } CircleLable::CircleLable(const QString &text, QWidget *parent) : QLabel(parent) , m_text(text) , m_radius(24) , colorFlag(false) , isSucceed(false) , m_textColor(Qt::white) { setFixedSize(QSize(m_radius, m_radius)); } CircleLable::~CircleLable() { } void CircleLable::setText(const QString &text) { m_text = text; repaint(); } void CircleLable::setBackgroundHighlight(bool flag) { colorFlag = flag; } void CircleLable::setSucceed(bool flag) { isSucceed = flag; } void CircleLable::paintEvent(QPaintEvent *event) { QPainter painter(this); painter.setRenderHint(QPainter::Antialiasing); // 反锯齿; // 深浅主题切换 if (!colorFlag && !isSucceed) { m_backgroundColor = ThemeController::getCustomColorFromDT("midlight-active"); m_textColor = ThemeController::getCustomColorFromDT("kwhite"); painter.setBrush(QBrush(m_backgroundColor)); } else if (isSucceed || colorFlag) { painter.setBrush(ThemeController::getCustomColorFromDT("highlight-active")); } painter.setPen(Qt::NoPen); QRect rect = this->rect(); painter.drawRoundedRect(rect, rect.width() / 2, rect.width() / 2); painter.setPen(m_textColor); if (colorFlag) { QPixmap pixmap = QIcon::fromTheme("dialog-apply").pixmap(16, 16); pixmap = ThemeController::drawSymbolicColoredPixmap(pixmap); QRect pixRect((rect.width() - 16) / 2, (rect.height() - 16) / 2, 16, 16); painter.drawPixmap(pixRect, pixmap); } else painter.drawText(rect, Qt::AlignCenter, m_text); QLabel::paintEvent(event); } TextLabel::TextLabel(QString str, QWidget *parent) : QLabel(parent) { setText(str); isPalette = false; } TextLabel::~TextLabel() { } void TextLabel::setTextHighlight(bool flag) { isPalette = flag; if (flag) { QPalette palette = this->palette(); palette.setColor(QPalette::WindowText, ThemeController::getCustomColorFromDT("highlight-active")); this->setPalette(palette); } else { QPalette palette; this->setPalette(palette); } } void TextLabel::followPalette(bool flag) { isPalette = flag; } void TextLabel::paintEvent(QPaintEvent *e) { if (!isPalette) { QPalette palette = this->palette(); QColor textColor = ThemeController::getCustomColorFromDT("brighttext-active"); textColor.setAlphaF(0.35); palette.setColor(QPalette::WindowText, textColor); this->setPalette(palette); } else { QPalette palette = this->palette(); palette.setColor(QPalette::WindowText, ThemeController::getCustomColorFromDT("highlight-active")); this->setPalette(palette); } QLabel::paintEvent(e); } KProgressLabelPrivate::KProgressLabelPrivate(KProgressLabel *parent) : q_ptr(parent) , m_count(-1) , m_circleSize(24, 24) { Q_Q(KProgressLabel); connect(m_gsetting, &QGSettings::changed, this, [=] { changeTheme(); }); } void KProgressLabelPrivate::changeTheme() { Q_Q(KProgressLabel); initThemeStyle(); } } #include "kprogresslabel.moc" #include "moc_kprogresslabel.cpp" libkysdk-applications/kysdk-qtwidgets/src/kbadge.h0000664000175000017500000000422615104543305021317 0ustar fengfeng/* * libkysdk-qtwidgets's Library * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #ifndef KBADGE_H #define KBADGE_H #include "gui_g.h" #include #include #include namespace kdk { class KBadgePrivate; /** * @defgroup MessageAlertModule * @{ */ /** * @brief 消息提醒气泡 * @since 1.0.0 */ class GUI_EXPORT KBadge : public QWidget { Q_OBJECT public: KBadge(QWidget *parent); /** * @brief 返回值 * @return */ int value(); /** * @brief 设置值,最大显示数值为999,大于999显示"..." * @param value */ void setValue(int value); /** * @brief 设置值是否可见 * @param flag */ void setValueVisiable(bool flag); /** * @brief 获取值是否可见 */ bool isValueVisiable() const; /** * @brief 获取背景色 * @return */ QColor color(); /** * @brief 设置背景色 * @param color */ void setColor(const QColor &color); /** * @brief 获取字体大小 * @return */ int fontSize(); /** * @brief 设置字体大小 * @param size */ void setFontSize(int size); protected: void paintEvent(QPaintEvent *event); void resizeEvent(QResizeEvent *event); private: Q_DECLARE_PRIVATE(KBadge) KBadgePrivate *const d_ptr; }; } /** * @example testbadge/widget.h * @example testbadge/widget.cpp * @} */ #endif // KBADGE_H libkysdk-applications/kysdk-qtwidgets/src/kcomboboxwidget.h0000664000175000017500000000363515104543305023274 0ustar fengfeng/* * libkysdk-qtwidgets's Library * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhenyu Wang * */ #ifndef KCOMBOBOXWIDGET_H #define KCOMBOBOXWIDGET_H #include "gui_g.h" #include #include #include namespace kdk { /** * @brief 可选择多个或者单个选项 * @since 2.5.2.0 */ class KComboBoxWidgetPrivate; class KComboBoxWidget : public QWidget { Q_OBJECT public: KComboBoxWidget(QWidget *parent = nullptr); /** * @brief 设置combobox的选项列表 * @param list */ void setStringList(QStringList list); /** * @brief 获取选中的列表 * @return */ QStringList getChosenList(); /** * @brief 设置主文本 * @param text */ void setMainText(QString text); /** * @brief 获取弹出菜单 * @return */ QMenu *menu(); protected: void mouseReleaseEvent(QMouseEvent *event); void mousePressEvent(QMouseEvent *event); void leaveEvent(QEvent *e); void enterEvent(QEvent *e); void paintEvent(QPaintEvent *event); signals: void comBoxWidgetClicked(); private: KComboBoxWidgetPrivate *const d_ptr; Q_DECLARE_PRIVATE(KComboBoxWidget) }; } #endif // KCOMBOBOXWIDGET_H libkysdk-applications/kysdk-qtwidgets/src/ktag.cpp0000664000175000017500000003533415104543305021367 0ustar fengfeng/* * libkysdk-qtwidgets's Library * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #include "ktag.h" #include "ktoolbutton.h" #include "parmscontroller.h" #include "themeController.h" #include #include #include #include #include #include #include #include "accessinfohelper.h" namespace kdk { class KTagPrivate : public QObject, public ThemeController { Q_OBJECT Q_DECLARE_PUBLIC(KTag) public: KTagPrivate(KTag *parent); void changeTheme(); void updateDeleteBtnColor(); private: KTag *q_ptr; QString m_text; KToolButton *m_pDeleteBtn; TagStyle m_style; QColor m_backgroundColor; bool m_isClosable; bool m_isBackgroundFlag; bool m_isTranslucent; }; KTag::KTag(QWidget *parent) : QPushButton(parent) , d_ptr(new KTagPrivate(this)) { Q_D(KTag); setClosable(false); d->changeTheme(); connect(Parmscontroller::self(), &Parmscontroller::modeChanged, this, [=](bool flag) { updateGeometry(); }); } void KTag::setClosable(bool flag) { Q_D(KTag); d->m_isClosable = flag; if (flag) setMinimumWidth(88); d->updateDeleteBtnColor(); update(); } bool KTag::closable() { Q_D(KTag); return d->m_isClosable; } void KTag::setText(const QString &text) { Q_D(KTag); d->m_text = text; update(); } void KTag::setTagStyle(TagStyle style) { Q_D(KTag); d->m_style = style; d->changeTheme(); } TagStyle KTag::tagStyle() { Q_D(KTag); d->updateDeleteBtnColor(); return d->m_style; } void KTag::setBackgroundColor(QColor color) { Q_D(KTag); d->m_isBackgroundFlag = true; d->m_backgroundColor = color; d->updateDeleteBtnColor(); } void KTag::setTranslucent(bool flag) { Q_D(KTag); d->m_isTranslucent = flag; if (flag) d->updateDeleteBtnColor(); } bool KTag::translucent() { Q_D(KTag); return d->m_isTranslucent; } QString KTag::text() { Q_D(KTag); return d->m_text; } void KTag::paintEvent(QPaintEvent *event) { Q_D(KTag); QStyleOptionButton option; initStyleOption(&option); QColor bkgColor; QColor highColor = ThemeController::getCustomColorFromDT("highlight-active"); QColor iconColor; QColor fontColor; QRect iconRect; QRect textRect; if (!option.state.testFlag(QStyle::State_Enabled)) { if(d->m_style == IconTag) bkgColor = ThemeController::getCustomColorFromDT("button-disable"); else bkgColor = ThemeController::getCustomColorFromDT("kbrand-disable"); iconColor = ThemeController::getCustomColorFromDT("highlightedtext-disable"); fontColor = ThemeController::getCustomColorFromDT("highlightedtext-disable"); } else { if (d->m_isTranslucent || d->m_isBackgroundFlag) { iconColor = ThemeController::getCustomColorFromDT("highlight-active"); fontColor = ThemeController::getCustomColorFromDT("highlight-active"); } else { iconColor = Qt::white; fontColor = Qt::white; } if (!d->m_isBackgroundFlag) { bkgColor = highColor; if (option.state.testFlag(QStyle::State_MouseOver)) { if (option.state.testFlag(QStyle::State_Sunken)) { if (d->m_isTranslucent) bkgColor.setAlphaF(0.45); else bkgColor = ThemeController::mixColor(bkgColor, ThemeController::getCustomColorFromDT("brighttext-active"), 0.2); } else { if (d->m_isTranslucent) bkgColor.setAlphaF(0.3); else bkgColor = ThemeController::mixColor(bkgColor, ThemeController::getCustomColorFromDT("brighttext-active"), 0.05); } } else { if (d->m_isTranslucent) bkgColor.setAlphaF(0.15); } } else { bkgColor = d->m_backgroundColor; } } if (closable()) { QRect rect = option.rect.adjusted(8, 0, -(d->m_pDeleteBtn->width()), 0); int drawLength = option.iconSize.width() + 4 + fontMetrics().horizontalAdvance((d->m_text)); if(!option.icon.isNull()) { if (rect.width() > drawLength) { iconRect = QRect(rect.center().x() - drawLength / 2, rect.center().y() - option.iconSize.height() / 2, option.iconSize.width(), option.iconSize.height()); textRect = QRect(iconRect.right() + 4, 0, fontMetrics().horizontalAdvance(d->m_text), rect.height()); } else { iconRect = QRect(rect.x() + 4, rect.center().y() - option.iconSize.height() / 2, option.iconSize.width(), option.iconSize.height()); textRect = QRect(iconRect.right() + 4, 0, rect.width() - 4 - iconRect.width(), rect.height()); } } else { if (rect.width() > drawLength) { textRect = QRect(4, 0, rect.width() - 4, rect.height()); } else { textRect = QRect( 4, 0, rect.width() - 4, rect.height()); } } } else { QRect rect = option.rect.adjusted(8, 0, 0, 0); int drawLength = option.iconSize.width() + 4 + fontMetrics().horizontalAdvance((d->m_text)); if(!option.icon.isNull()) { if (rect.width() > drawLength) { iconRect = QRect(rect.center().x() - drawLength / 2, rect.center().y() - option.iconSize.height() / 2, option.iconSize.width(), option.iconSize.height()); textRect = QRect(iconRect.right() + 4, 0, fontMetrics().horizontalAdvance(d->m_text), rect.height()); } else { iconRect = QRect(rect.x() + 4, rect.center().y() - option.iconSize.height() / 2, option.iconSize.width(), option.iconSize.height()); textRect = QRect(iconRect.right() + 4, 0, rect.width() - 4 - iconRect.width(), rect.height()); } } else { if (rect.width() > drawLength) { textRect = QRect(4, 0, rect.width() - 4, rect.height()); } else { textRect = QRect( 4, 0, rect.width() - 4, rect.height()); } } } QPainter painter(this); painter.setRenderHint(QPainter::Antialiasing); if (ThemeController::widgetTheme() == ClassicTheme) { if (painter.pen().width() == 1) painter.translate(0.5, 0.5); } QRect rect = this->rect(); if (d->m_isClosable) { d->m_pDeleteBtn->show(); d->m_pDeleteBtn->move(width() - d->m_pDeleteBtn->width(), (height() - d->m_pDeleteBtn->height()) / 2 + 2); rect.adjust(0, 0, -16, 0); } else { d->m_pDeleteBtn->hide(); } QColor color = ThemeController::getCustomColorFromDT("highlight-active"); QFontMetrics fm = fontMetrics(); switch (d->m_style) { case HighlightTag: if (ThemeController::widgetTheme() == ClassicTheme) { QColor backColor = color; backColor.setAlpha(38); painter.setBrush(backColor); painter.setPen(color); painter.drawRoundedRect(this->rect(), 0, 0); } else { painter.setBrush(color); painter.setPen(Qt::PenStyle::NoPen); int radius = ThemeController::getRadiusFromDT("kradius-normal"); if (radius == -1) radius = 6; painter.drawRoundedRect(this->rect(), radius, radius); painter.setPen(QColor("#FFFFFF")); } break; case BoderTag: painter.setBrush(QColor(Qt::transparent)); painter.setPen(color); if (ThemeController::widgetTheme() == ClassicTheme) painter.drawRoundedRect(this->rect(), 0, 0); else { int radius = ThemeController::getRadiusFromDT("kradius-normal"); if (radius == -1) radius = 6; painter.drawRoundedRect(this->rect(), radius, radius); } break; case BaseBoderTag: { QColor backColor = color; backColor.setAlpha(38); painter.setBrush(backColor); painter.setPen(color); if (ThemeController::widgetTheme() == ClassicTheme) { painter.drawRoundedRect(this->rect(), 0, 0); } else { int radius = ThemeController::getRadiusFromDT("kradius-normal"); if (radius == -1) radius = 6; painter.drawRoundedRect(this->rect(), radius, radius); } break; } case GrayTag: if (ThemeController::widgetTheme() == ClassicTheme) { painter.setBrush(QColor(Qt::transparent)); painter.setPen(color); painter.drawRoundedRect(this->rect(), 0, 0); } else { painter.setPen(Qt::PenStyle::NoPen); painter.setBrush(ThemeController::getCustomColorFromDT("kcomponent-normal")); int radius = ThemeController::getRadiusFromDT("kradius-normal"); if (radius == -1) radius = 6; painter.drawRoundedRect(this->rect(), radius, radius); painter.setPen(ThemeController::getCustomColorFromDT("text-active")); } break; case IconTag: { QPixmap pixmap = option.icon.pixmap(option.iconSize); painter.setPen(Qt::NoPen); painter.setBrush(bkgColor); int radius = ThemeController::getRadiusFromDT("kradius-normal"); if (radius == -1) radius = 6; painter.drawRoundedRect(this->rect(), radius, radius); painter.drawPixmap(iconRect, ThemeController::drawColoredPixmap(pixmap, iconColor)); painter.setPen(fontColor); break; } default: break; } if (fm.horizontalAdvance(d->m_text) > textRect.width()) { QString str = fm.elidedText(d->m_text,Qt::TextElideMode::ElideRight,textRect.width()); setToolTip(d->m_text); painter.drawText(textRect,Qt::AlignCenter,str); } else { setToolTip(""); painter.drawText(textRect, Qt::AlignCenter, d->m_text); } } QSize KTag::sizeHint() const { auto size = QPushButton::sizeHint(); size.setHeight(Parmscontroller::parm(Parmscontroller::Parm::PM_TagHeight)); return size; } KTagPrivate::KTagPrivate(KTag *parent) : q_ptr(parent) , m_isClosable(false) , m_text("") , m_style(HighlightTag) , m_isBackgroundFlag(false) , m_isTranslucent(false) { Q_Q(KTag); m_pDeleteBtn = new KToolButton(q); m_pDeleteBtn->setIconSize(QSize(16, 16)); connect(m_pDeleteBtn, &KToolButton::clicked, q, &KTag::close); m_pDeleteBtn->hide(); QPalette btnPalette; btnPalette.setBrush(QPalette::Active, QPalette::Button, Qt::transparent); btnPalette.setBrush(QPalette::Inactive, QPalette::Button, Qt::transparent); btnPalette.setBrush(QPalette::Disabled, QPalette::Button, Qt::transparent); btnPalette.setBrush(QPalette::Active, QPalette::Highlight, Qt::transparent); btnPalette.setBrush(QPalette::Inactive, QPalette::Highlight, Qt::transparent); btnPalette.setBrush(QPalette::Disabled, QPalette::Highlight, Qt::transparent); m_pDeleteBtn->setAutoFillBackground(true); m_pDeleteBtn->setPalette(btnPalette); m_pDeleteBtn->setFocusPolicy(Qt::NoFocus); m_pDeleteBtn->setCursor(Qt::ArrowCursor); QIcon icon = QIcon::fromTheme("application-exit-symbolic"); m_pDeleteBtn->setIcon(icon); connect(m_gsetting, &QGSettings::changed, this, [=]() { changeTheme(); }); KDK_ALL_INFO_FORMAT(m_pDeleteBtn,""); } void KTagPrivate::changeTheme() { Q_Q(KTag); initThemeStyle(); updateDeleteBtnColor(); } void KTagPrivate::updateDeleteBtnColor() { Q_Q(KTag); switch (m_style) { case HighlightTag: if(q->isEnabled()) m_pDeleteBtn->setIconColor(true, ThemeController::getCustomColorFromDT("kfont-white")); else m_pDeleteBtn->setIconColor(true, ThemeController::getCustomColorFromDT("kfont-white-disable")); break; case BoderTag: case BaseBoderTag: if(q->isEnabled()) m_pDeleteBtn->setIconColor(true, ThemeController::getCustomColorFromDT("kbrand-normal")); else m_pDeleteBtn->setIconColor(true, ThemeController::getCustomColorFromDT("kbrand-disable")); break; case GrayTag: if(q->isEnabled()) m_pDeleteBtn->setIconColor(true, ThemeController::getCustomColorFromDT("kfont-primary")); else m_pDeleteBtn->setIconColor(true, ThemeController::getCustomColorFromDT("kfont-primary-disable")); break; break; case IconTag: if (m_isTranslucent || m_isBackgroundFlag) m_pDeleteBtn->setIconColor(true, ThemeController::getCustomColorFromDT("highlight-active")); // m_backgroundColor else m_pDeleteBtn->setIconColor(true, Qt::white); break; default: break; } } } #include "ktag.moc" #include "moc_ktag.cpp" libkysdk-applications/kysdk-qtwidgets/src/ktablemodel.cpp0000664000175000017500000000347115104543305022721 0ustar fengfeng/* * libkysdk-qtwidgets's Library * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhenyu Wang * */ #include "ktablemodel.h" #include "themeController.h" #include #include #include #include namespace kdk { class Q_DECL_HIDDEN KTableModelPrivate : public QObject, public ThemeController { Q_OBJECT Q_DECLARE_PUBLIC(KTableModel) public: KTableModelPrivate(KTableModel *parent); void changeTheme(); private: KTableModel *q_ptr; }; KTableModel::KTableModel(QObject *parent) : QStandardItemModel(parent) , d_ptr(new KTableModelPrivate(this)) { } QVariant KTableModel::headerData(int section, Qt::Orientation orientation, int role) const { (void)section; if (orientation == Qt::Horizontal && role == Qt::TextAlignmentRole) { return QVariant(Qt::AlignLeft | Qt::AlignVCenter); } return QVariant(); } KTableModelPrivate::KTableModelPrivate(KTableModel *parent) : q_ptr(parent) { } void KTableModelPrivate::changeTheme() { Q_Q(KTableModel); initThemeStyle(); } } #include "ktablemodel.moc" #include "moc_ktablemodel.cpp" libkysdk-applications/kysdk-qtwidgets/src/ktabbar.h0000664000175000017500000000450215104543305021505 0ustar fengfeng/* * libkysdk-qtwidgets's Library * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #ifndef KTABBAR_H #define KTABBAR_H #include "gui_g.h" #include #include namespace kdk { /** @defgroup BarModule * @{ */ /** * @brief 支持三种样式 */ enum KTabBarStyle { SegmentDark, SegmentLight, Sliding }; class KTabBarPrivate; /** * @brief 支持三种样式 * @since 1.0.0 */ class GUI_EXPORT KTabBar : public QTabBar { Q_OBJECT public: KTabBar(KTabBarStyle barStyle = SegmentLight, QWidget *parent = nullptr); ~KTabBar(); /** * @brief 设置TabBar样式 * @param barStyle */ void setTabBarStyle(KTabBarStyle barStyle); /** * @brief 返回TabBar样式 * @return */ KTabBarStyle barStyle(); /** * @brief 设置圆角半径,只对SegmentDark,SegmentLight样式生效 * @param radius */ void setBorderRadius(int radius); /** * @brief 获取圆角半径 * @return */ int borderRadius(); /** * @brief 设置背景色 * @param color * @since 1.2.0 */ void setBackgroundColor(const QColor &color); Q_SIGNALS: /** * @brief 鼠标右键信号 * @param point * @since 2.4.1.0 */ void rightlicked(QPoint point); protected: QSize sizeHint() const; QSize minimumTabSizeHint(int index) const; QSize tabSizeHint(int index) const; void paintEvent(QPaintEvent *event); private: Q_DECLARE_PRIVATE(KTabBar) KTabBarPrivate *const d_ptr; }; } /** * @example testtabbar/widget.h * @example testtabbar/widget.cpp * @} */ #endif // KTABBAR_H libkysdk-applications/kysdk-qtwidgets/src/knavigationbar.h0000664000175000017500000000702615104543305023102 0ustar fengfeng/* * libkysdk-qtwidgets's Library * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #ifndef KNAVIGATIONBAR_H #define KNAVIGATIONBAR_H #include "gui_g.h" #include #include #include #include #include #include namespace kdk { /** @defgroup BarModule * @{ */ class KNavigationBarPrivate; class ListView; /** * @brief 导航栏控件 * @since 1.0.0 */ class GUI_EXPORT KNavigationBar : public QScrollArea { Q_OBJECT public: enum NavigationBarDataType { ValueRole = Qt::UserRole + 1, StringRole = Qt::UserRole + 2, boolRole = Qt::UserRole + 3 }; KNavigationBar(QWidget *parent); /** * @brief 增加常规Item * @param item */ void addItem(QStandardItem *item); /** * @brief 增加次级Item * @param subItem */ void addSubItem(QStandardItem *subItem); /** * @brief 成组增加Item,在导航栏中会显示tag * @param items * @param tag */ void addGroupItems(QList items, const QString &tag); /** * @brief 在指定tag组中指定位置row插入item * @param tag * @param row * @param item * @since 3.0.1.0 */ void insertGroupItems(QString tag, int row, QStandardItem *item); /** * @brief 在指定组中删除item * @param tag * @param item * @since 3.0.1.0 */ void removeGroupItem(QString tag, QStandardItem *item); /** * @brief 添加tag * @param tag */ void addTag(const QString &tag); /** * @brief 获取model * @return */ QStandardItemModel *model(); /** * @brief 获取view * @return */ QListView *listview(); /** * @brief 设置tabvalue * @param item * @param value * @since 3.0.1.0 */ void setTabValue(QStandardItem *item, QString value); // item /** * @brief 设置tabvalue是否可见 * @param visible * @since 3.0.1.0 */ void setTabValueVisible(bool visible); /** * @brief tag 添加add图标 * @param tag * @param icon * @since 3.0.1.0 */ void setAddIcon(QString tag, QIcon icon); /** * @brief 设置tag add图标是否可见 * @param tag * @param visible * @since 3.0.1.0 */ void setAddTagVisible(QString tag, bool visible); /** * @brief 设置折叠图标是否可见 * @param tag * @param visible * @since 3.0.1.0 */ void setExtendTagVisible(QString tag, bool visible); Q_SIGNALS: void addTagClicked(QString str); private: Q_DECLARE_PRIVATE(KNavigationBar) KNavigationBarPrivate *const d_ptr; }; } /** * @example testnavigationbar/widget.h * @example testnavigationbar/widget.cpp * @} */ #endif // KNAVIGATIONBAR_H libkysdk-applications/kysdk-qtwidgets/src/themeController.h0000664000175000017500000000707115104543305023251 0ustar fengfeng/* * libkysdk-qtwidgets's Library * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #ifndef THEMECONTROLLER_H #define THEMECONTROLLER_H #include #include static const QByteArray FITTHEMEWINDOW = "org.ukui.style"; /** * @brief 监听主题控制 * @since 1.0.0 */ enum ThemeFlag { LightTheme, DarkTheme }; enum IconFlag { DefaultStyle, ClassicStyle }; enum WidgetThemeFlag { DefaultTheme, // 寻光 ClassicTheme, // 启典 FashionTheme, // 和印 DawnLightTheme // 破晓 }; class ThemeController { public: static QPixmap drawSymbolicColoredPixmap(const QPixmap &source); static QPixmap drawColoredPixmap(const QPixmap &source, const QColor &sampleColor); static QColor getCurrentIconColor(); static QColor mixColor(const QColor &c1, const QColor &c2, qreal bias = 0.5); static WidgetThemeFlag widgetTheme(); static ThemeFlag themeMode(); static IconFlag iconTheme(); static int systemFontSize(); static QPixmap drawFashionBackground(const QRect &rect, int sub_width, int sub_height, int radius, int flag); // flag ? rightBottom : leftBottom; static bool isPixmapPureColor(const QPixmap &pixmap); static QIcon overlayIcons(const QIcon &icon1, const QIcon &icon2, int iconWidth, int iconHeight, int offsetX = 0, int offsetY = 0); static QPixmap overlayPixmaps(const QPixmap &pixmap1, const QPixmap &pixmap2, int offsetX = 0, int offsetY = 0); static QColor lanhuHSLToQtHsl(int h, int s, int l, int a = 255); static QColor adjustH(const QColor c, int range); static QColor adjustS(const QColor c, int range); static QColor adjustL(const QColor c, int range); static QColor adjustA(const QColor c, int range); static QColor highlightClick(bool isDark, QPalette p); static QColor highlightHover(bool isDark, QPalette p); static QColor buttonDarkClick(bool isDark, QPalette p); // static void normalButtonColor(bool isDark, QPalette p, QPen &defaultPen, QBrush &defaultBrush, QPen &hoverPen, QBrush &hoverBrush, // QPen &clickPen, QBrush &clickBrush, QPen &disablePen, QBrush &disableBrush); static bool systemLang(); static QColor getPaletteColorFromDT(QString dtString, QPalette::ColorGroup group = QPalette::Normal); static QColor getCustomColorFromDT(QString dtString); static QString getFontStylesFromDT(QString dtString); static int getRadiusFromDT(QString dtString); static int getLineOrMarginFromDT(QString dtString); static void getGradientFromDT(QString key, QColor &startColor, QColor &endColor); ThemeController(); ~ThemeController(); virtual void changeTheme() { } virtual void changeIconStyle() { } void initThemeStyle(); QGSettings *m_gsetting; // unused ThemeFlag m_themeFlag; IconFlag m_iconFlag; }; #endif // THEMECONTROLLER_H libkysdk-applications/kysdk-qtwidgets/src/kinputdialog.cpp0000664000175000017500000007123615104543305023134 0ustar fengfeng/* * libkysdk-qtwidgets's Library * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #include #include #include #include #include "kinputdialog.h" #include "qevent.h" #include "qvalidator.h" #include #include #include #include #include #include #include #include "accessinfohelper.h" namespace kdk { enum CandidateSignal { TextValueSelectedSignal, IntValueSelectedSignal, DoubleValueSelectedSignal, NumCandidateSignals }; static const char *candidateSignal(int which) { switch (CandidateSignal(which)) { case TextValueSelectedSignal: return SIGNAL(textValueSelected(QString)); case IntValueSelectedSignal: return SIGNAL(intValueSelected(int)); case DoubleValueSelectedSignal: return SIGNAL(doubleValueSelected(double)); case NumCandidateSignals: break; }; Q_UNREACHABLE(); return nullptr; } static const char *signalForMember(const char *member) { QByteArray normalizedMember(QMetaObject::normalizedSignature(member)); for (int i = 0; i < NumCandidateSignals; ++i) if (QMetaObject::checkConnectArgs(candidateSignal(i), normalizedMember)) return candidateSignal(i); return SIGNAL(accepted()); } QT_BEGIN_NAMESPACE class KInputDialogSpinBox : public QSpinBox { Q_OBJECT public: KInputDialogSpinBox(QWidget *parent) : QSpinBox(parent) { connect(lineEdit(), SIGNAL(textChanged(QString)), this, SLOT(notifyTextChanged())); connect(this, SIGNAL(editingFinished()), this, SLOT(notifyTextChanged())); } protected: QSize sizeHint() const; Q_SIGNALS: void textChanged(int); private Q_SLOTS: void notifyTextChanged() { Q_EMIT textChanged(hasAcceptableInput() ? 1 : 0); } private: void keyPressEvent(QKeyEvent *event) override { if ((event->key() == Qt::Key_Return || event->key() == Qt::Key_Enter) && !hasAcceptableInput()) { #ifndef QT_NO_PROPERTIES setProperty("value", property("value")); #endif } else { QSpinBox::keyPressEvent(event); } notifyTextChanged(); } void mousePressEvent(QMouseEvent *event) override { QSpinBox::mousePressEvent(event); notifyTextChanged(); } }; class KInputDialogDoubleSpinBox : public QDoubleSpinBox { Q_OBJECT public: KInputDialogDoubleSpinBox(QWidget *parent = nullptr) : QDoubleSpinBox(parent) { connect(lineEdit(), SIGNAL(textChanged(QString)), this, SLOT(notifyTextChanged())); connect(this, SIGNAL(editingFinished()), this, SLOT(notifyTextChanged())); } protected: QSize sizeHint() const; Q_SIGNALS: void textChanged(int); private Q_SLOTS: void notifyTextChanged() { Q_EMIT textChanged(hasAcceptableInput() ? 1 : 0); } private: void keyPressEvent(QKeyEvent *event) override { if ((event->key() == Qt::Key_Return || event->key() == Qt::Key_Enter) && !hasAcceptableInput()) { #ifndef QT_NO_PROPERTIES setProperty("value", property("value")); #endif } else { QDoubleSpinBox::keyPressEvent(event); } notifyTextChanged(); } void mousePressEvent(QMouseEvent *event) override { QDoubleSpinBox::mousePressEvent(event); notifyTextChanged(); } }; class KInputDialogLineEdit : public QLineEdit { public: KInputDialogLineEdit(QWidget *parent = nullptr) : QLineEdit(parent) { } protected: QSize sizeHint() const; }; class KInputDialogListView : public QListView { public: KInputDialogListView(QWidget *parent = nullptr) : QListView(parent) { } QVariant inputMethodQuery(Qt::InputMethodQuery query) const override { if (query == Qt::ImEnabled) return false; return QListView::inputMethodQuery(query); } }; class KInputDialogPrivate : public QObject { Q_DECLARE_PUBLIC(KInputDialog) public: KInputDialogPrivate(KInputDialog *parent); void ensureLayout(); void ensureLineEdit(); void ensurePlainTextEdit(); void ensureComboBox(); void ensureListView(); void ensureIntSpinBox(); void ensureDoubleSpinBox(); void ensureEnabledConnection(QAbstractSpinBox *spinBox); void setInputWidget(QWidget *widget); void chooseRightTextInputWidget(); void setComboBoxText(const QString &text); void setListViewText(const QString &text); QString listViewText() const; void ensureLayout() const { const_cast(this)->ensureLayout(); } bool useComboBoxOrListView() const { return comboBox && comboBox->count() > 0; } void _q_textChanged(const QString &text); void _q_plainTextEditTextChanged(); void _q_currentRowChanged(const QModelIndex &newIndex, const QModelIndex &oldIndex); void setAccessInfo(); mutable QLabel *label; mutable QPushButton *okButton; mutable QPushButton *cancelButton; mutable KInputDialogLineEdit *lineEdit; mutable QPlainTextEdit *plainTextEdit; mutable QSpinBox *intSpinBox; mutable QDoubleSpinBox *doubleSpinBox; mutable QComboBox *comboBox; mutable KInputDialogListView *listView; mutable QWidget *inputWidget; mutable QVBoxLayout *mainLayout; KInputDialog::InputDialogOptions opts; QString textValue; QPointer receiverToDisconnectOnClose; QByteArray memberToDisconnectOnClose; private: KInputDialog *q_ptr; }; KInputDialogPrivate::KInputDialogPrivate(KInputDialog *parent) : q_ptr(parent) , label(nullptr) , okButton(nullptr) , cancelButton(nullptr) , lineEdit(nullptr) , plainTextEdit(nullptr) , intSpinBox(nullptr) , doubleSpinBox(nullptr) , comboBox(nullptr) , listView(nullptr) , inputWidget(nullptr) , mainLayout(nullptr) { Q_Q(KInputDialog); q->setMinimumHeight(198); q->setMinimumWidth(336); connect(q->m_gsetting, &QGSettings::changed, q, &KInputDialog::changeTheme); } void KInputDialogPrivate::ensureLayout() { Q_Q(KInputDialog); if (mainLayout) return; if (!inputWidget) { ensureLineEdit(); inputWidget = lineEdit; } if (!label) { label = new QLabel(KInputDialog::tr("Enter a value:"), q); setAccessInfo(); } q->mainLayout()->setSizeConstraint(QLayout::SizeConstraint::SetFixedSize); #ifndef QT_NO_SHORTCUT label->setBuddy(inputWidget); #endif label->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed); label->setWordWrap(true); QHBoxLayout *hLayout = new QHBoxLayout(); okButton = new QPushButton(tr("ok"), q); okButton->setFixedSize(96, 36); cancelButton = new QPushButton(tr("cancel"), q); cancelButton->setFixedSize(96, 36); hLayout->setContentsMargins(0, 0, 0, 0); hLayout->setSpacing(0); hLayout->addStretch(); hLayout->addWidget(cancelButton); hLayout->addSpacing(10); hLayout->addWidget(okButton); QObject::connect(okButton, SIGNAL(clicked(bool)), q, SLOT(accept())); QObject::connect(cancelButton, SIGNAL(clicked(bool)), q, SLOT(reject())); mainLayout = new QVBoxLayout(); mainLayout->setSpacing(0); mainLayout->setContentsMargins(24, 0, 24, 24); mainLayout->addWidget(label); mainLayout->addSpacing(8); mainLayout->addWidget(inputWidget); mainLayout->addSpacing(32); // mainLayout->addStretch(); mainLayout->addLayout(hLayout); q->mainWidget()->setLayout(mainLayout); q->changeTheme(); ensureEnabledConnection(qobject_cast(inputWidget)); inputWidget->show(); KDK_ALL_INFO_FORMAT(okButton,""); KDK_ALL_INFO_FORMAT(cancelButton,""); } void KInputDialogPrivate::ensureLineEdit() { Q_Q(KInputDialog); if (!lineEdit) { lineEdit = new KInputDialogLineEdit(q); lineEdit->setFixedHeight(36); lineEdit->hide(); KDK_ALL_INFO_FORMAT(lineEdit,""); QObject::connect(lineEdit, SIGNAL(textChanged(QString)), q, SLOT(_q_textChanged(QString))); } } void KInputDialogPrivate::ensurePlainTextEdit() { Q_Q(KInputDialog); if (!plainTextEdit) { plainTextEdit = new QPlainTextEdit(q); plainTextEdit->setLineWrapMode(QPlainTextEdit::NoWrap); plainTextEdit->hide(); KDK_ALL_INFO_FORMAT(plainTextEdit,""); QObject::connect(plainTextEdit, SIGNAL(textChanged()), q, SLOT(_q_plainTextEditTextChanged())); } } void KInputDialogPrivate::ensureComboBox() { Q_Q(KInputDialog); if (!comboBox) { comboBox = new QComboBox(q); comboBox->hide(); KDK_ALL_INFO_FORMAT(comboBox,""); QObject::connect(comboBox, SIGNAL(editTextChanged(QString)), q, SLOT(_q_textChanged(QString))); QObject::connect(comboBox, SIGNAL(currentIndexChanged(QString)), q, SLOT(_q_textChanged(QString))); } } void KInputDialogPrivate::ensureListView() { Q_Q(KInputDialog); if (!listView) { ensureComboBox(); listView = new KInputDialogListView(q); listView->hide(); KDK_ALL_INFO_FORMAT(listView,""); listView->setEditTriggers(QAbstractItemView::NoEditTriggers); listView->setSelectionMode(QAbstractItemView::SingleSelection); listView->setModel(comboBox->model()); listView->setCurrentIndex(QModelIndex()); QObject::connect(listView->selectionModel(), SIGNAL(currentRowChanged(QModelIndex, QModelIndex)), q, SLOT(_q_currentRowChanged(QModelIndex, QModelIndex))); } } void KInputDialogPrivate::ensureIntSpinBox() { Q_Q(KInputDialog); if (!intSpinBox) { intSpinBox = new KInputDialogSpinBox(q); intSpinBox->hide(); KDK_ALL_INFO_FORMAT(intSpinBox,""); QObject::connect(intSpinBox, SIGNAL(valueChanged(int)), q, SIGNAL(intValueChanged(int))); } } void KInputDialogPrivate::ensureDoubleSpinBox() { Q_Q(KInputDialog); if (!doubleSpinBox) { doubleSpinBox = new KInputDialogDoubleSpinBox(q); doubleSpinBox->hide(); KDK_ALL_INFO_FORMAT(doubleSpinBox,""); QObject::connect(doubleSpinBox, SIGNAL(valueChanged(double)), q, SIGNAL(doubleValueChanged(double))); } } void KInputDialogPrivate::ensureEnabledConnection(QAbstractSpinBox *spinBox) { if (spinBox) { QAbstractButton *okBtn = okButton; QObject::connect(spinBox, SIGNAL(textChanged(int)), okBtn, SLOT(setEnabled(bool)), Qt::UniqueConnection); } } void KInputDialogPrivate::setInputWidget(QWidget *widget) { Q_Q(KInputDialog); Q_ASSERT(widget); if (inputWidget == widget) return; if (mainLayout) { Q_ASSERT(inputWidget); mainLayout->removeWidget(inputWidget); inputWidget->hide(); mainLayout->insertWidget(1, widget); widget->show(); QAbstractButton *okBtn = okButton; if (QAbstractSpinBox *spinBox = qobject_cast(inputWidget)) QObject::disconnect(spinBox, SIGNAL(textChanged(int)), okBtn, SLOT(setEnabled(bool))); QAbstractSpinBox *spinBox = qobject_cast(widget); ensureEnabledConnection(spinBox); okButton->setEnabled(!spinBox || spinBox->hasAcceptableInput()); q->changeTheme(); } inputWidget = widget; if (widget == lineEdit) { lineEdit->setText(textValue); } else if (widget == plainTextEdit) { plainTextEdit->setPlainText(textValue); } else if (widget == comboBox) { setComboBoxText(textValue); } else if (widget == listView) { setListViewText(textValue); ensureLayout(); okButton->setEnabled(listView->selectionModel()->hasSelection()); } } void KInputDialogPrivate::chooseRightTextInputWidget() { QWidget *widget; if (useComboBoxOrListView()) { if ((opts & KInputDialog::UseListViewForComboBoxItems) && !comboBox->isEditable()) { ensureListView(); widget = listView; } else { widget = comboBox; } } else if (opts & KInputDialog::UsePlainTextEditForTextInput) { ensurePlainTextEdit(); widget = plainTextEdit; } else { ensureLineEdit(); widget = lineEdit; } setInputWidget(widget); if (inputWidget == comboBox) { _q_textChanged(comboBox->currentText()); } else if (inputWidget == listView) { _q_textChanged(listViewText()); } } void KInputDialogPrivate::setComboBoxText(const QString &text) { int index = comboBox->findText(text); if (index != -1) { comboBox->setCurrentIndex(index); } else if (comboBox->isEditable()) { comboBox->setEditText(text); } } void KInputDialogPrivate::setListViewText(const QString &text) { int row = comboBox->findText(text); if (row != -1) { QModelIndex index(comboBox->model()->index(row, 0)); listView->selectionModel()->setCurrentIndex(index, QItemSelectionModel::Clear | QItemSelectionModel::SelectCurrent); } } QString KInputDialogPrivate::listViewText() const { if (listView->selectionModel()->hasSelection()) { int row = listView->selectionModel()->selectedRows().value(0).row(); return comboBox->itemText(row); } else { return QString(); } } void KInputDialogPrivate::_q_textChanged(const QString &text) { Q_Q(KInputDialog); if (textValue != text) { textValue = text; Q_EMIT q->textValueChanged(text); } } void KInputDialogPrivate::_q_plainTextEditTextChanged() { Q_Q(KInputDialog); QString text = plainTextEdit->toPlainText(); if (textValue != text) { textValue = text; Q_EMIT q->textValueChanged(text); } } void KInputDialogPrivate::_q_currentRowChanged(const QModelIndex &newIndex, const QModelIndex & /* oldIndex */) { _q_textChanged(comboBox->model()->data(newIndex).toString()); okButton->setEnabled(true); } void KInputDialogPrivate::setAccessInfo() { Q_Q(KInputDialog); KDK_ALL_INFO_FORMAT(label,""); } KInputDialog::KInputDialog(QWidget *parent) : KDialog(parent) , d_ptr(new KInputDialogPrivate(this)) { } KInputDialog::~KInputDialog() { } void KInputDialog::setInputMode(InputMode mode) { Q_D(KInputDialog); QWidget *widget; /* Warning: Some functions in KInputDialog rely on implementation details of the code below. Look for the comments that accompany the calls to setInputMode() throughout this file before you change the code below. */ switch (mode) { case IntInput: d->ensureIntSpinBox(); widget = d->intSpinBox; break; case DoubleInput: d->ensureDoubleSpinBox(); widget = d->doubleSpinBox; break; default: Q_ASSERT(mode == TextInput); d->chooseRightTextInputWidget(); return; } d->setInputWidget(widget); } KInputDialog::InputMode KInputDialog::inputMode() const { Q_D(const KInputDialog); if (d->inputWidget) { if (d->inputWidget == d->intSpinBox) { return IntInput; } else if (d->inputWidget == d->doubleSpinBox) { return DoubleInput; } } return TextInput; } void KInputDialog::setLabelText(const QString &text) { Q_D(KInputDialog); if (!d->label) { d->label = new QLabel(text, this); d->setAccessInfo(); } else { d->label->setText(text); } } QString KInputDialog::labelText() const { Q_D(const KInputDialog); d->ensureLayout(); return d->label->text(); } void KInputDialog::setOption(InputDialogOption option, bool on) { Q_D(KInputDialog); if (!(d->opts & option) != !on) setOptions(d->opts ^ option); } bool KInputDialog::testOption(InputDialogOption option) const { Q_D(const KInputDialog); return (d->opts & option) != 0; } void KInputDialog::setOptions(InputDialogOptions options) { Q_D(KInputDialog); InputDialogOptions changed = (options ^ d->opts); if (!changed) return; d->opts = options; d->ensureLayout(); if (changed & NoButtons) { d->okButton->setVisible(!(options & NoButtons)); d->cancelButton->setVisible(!(options & NoButtons)); } if ((changed & UseListViewForComboBoxItems) && inputMode() == TextInput) d->chooseRightTextInputWidget(); if ((changed & UsePlainTextEditForTextInput) && inputMode() == TextInput) d->chooseRightTextInputWidget(); } KInputDialog::InputDialogOptions KInputDialog::options() const { Q_D(const KInputDialog); return d->opts; } void KInputDialog::setTextValue(const QString &text) { Q_D(KInputDialog); setInputMode(TextInput); if (d->inputWidget == d->lineEdit) { d->lineEdit->setText(text); } else if (d->inputWidget == d->plainTextEdit) { d->plainTextEdit->setPlainText(text); } else if (d->inputWidget == d->comboBox) { d->setComboBoxText(text); } else { d->setListViewText(text); } } QString KInputDialog::textValue() const { Q_D(const KInputDialog); return d->textValue; } void KInputDialog::setTextEchoMode(QLineEdit::EchoMode mode) { Q_D(KInputDialog); d->ensureLineEdit(); d->lineEdit->setEchoMode(mode); } QLineEdit::EchoMode KInputDialog::textEchoMode() const { Q_D(const KInputDialog); if (d->lineEdit) { return d->lineEdit->echoMode(); } else { return QLineEdit::Normal; } } void KInputDialog::setComboBoxEditable(bool editable) { Q_D(KInputDialog); d->ensureComboBox(); d->comboBox->setEditable(editable); if (inputMode() == TextInput) d->chooseRightTextInputWidget(); } bool KInputDialog::isComboBoxEditable() const { Q_D(const KInputDialog); if (d->comboBox) { return d->comboBox->isEditable(); } else { return false; } } void KInputDialog::setComboBoxItems(const QStringList &items) { Q_D(KInputDialog); d->ensureComboBox(); { const QSignalBlocker blocker(d->comboBox); d->comboBox->clear(); d->comboBox->addItems(items); } if (inputMode() == TextInput) d->chooseRightTextInputWidget(); } QStringList KInputDialog::comboBoxItems() const { Q_D(const KInputDialog); QStringList result; if (d->comboBox) { const int count = d->comboBox->count(); result.reserve(count); for (int i = 0; i < count; ++i) result.append(d->comboBox->itemText(i)); } return result; } void KInputDialog::setIntValue(int value) { Q_D(KInputDialog); setInputMode(IntInput); d->intSpinBox->setValue(value); } int KInputDialog::intValue() const { Q_D(const KInputDialog); if (d->intSpinBox) { return d->intSpinBox->value(); } else { return 0; } } void KInputDialog::setIntMinimum(int min) { Q_D(KInputDialog); d->ensureIntSpinBox(); d->intSpinBox->setMinimum(min); } int KInputDialog::intMinimum() const { Q_D(const KInputDialog); if (d->intSpinBox) { return d->intSpinBox->minimum(); } else { return 0; } } void KInputDialog::setIntMaximum(int max) { Q_D(KInputDialog); d->ensureIntSpinBox(); d->intSpinBox->setMaximum(max); } int KInputDialog::intMaximum() const { Q_D(const KInputDialog); if (d->intSpinBox) { return d->intSpinBox->maximum(); } else { return 99; } } void KInputDialog::setIntRange(int min, int max) { Q_D(KInputDialog); d->ensureIntSpinBox(); d->intSpinBox->setRange(min, max); } void KInputDialog::setIntStep(int step) { Q_D(KInputDialog); d->ensureIntSpinBox(); d->intSpinBox->setSingleStep(step); } int KInputDialog::intStep() const { Q_D(const KInputDialog); if (d->intSpinBox) { return d->intSpinBox->singleStep(); } else { return 1; } } void KInputDialog::setDoubleValue(double value) { Q_D(KInputDialog); setInputMode(DoubleInput); d->doubleSpinBox->setValue(value); } double KInputDialog::doubleValue() const { Q_D(const KInputDialog); if (d->doubleSpinBox) { return d->doubleSpinBox->value(); } else { return 0.0; } } void KInputDialog::setDoubleMinimum(double min) { Q_D(KInputDialog); d->ensureDoubleSpinBox(); d->doubleSpinBox->setMinimum(min); } double KInputDialog::doubleMinimum() const { Q_D(const KInputDialog); if (d->doubleSpinBox) { return d->doubleSpinBox->minimum(); } else { return 0.0; } } void KInputDialog::setDoubleMaximum(double max) { Q_D(KInputDialog); d->ensureDoubleSpinBox(); d->doubleSpinBox->setMaximum(max); } double KInputDialog::doubleMaximum() const { Q_D(const KInputDialog); if (d->doubleSpinBox) { return d->doubleSpinBox->maximum(); } else { return 99.99; } } void KInputDialog::setDoubleRange(double min, double max) { Q_D(KInputDialog); d->ensureDoubleSpinBox(); d->doubleSpinBox->setRange(min, max); } void KInputDialog::setDoubleDecimals(int decimals) { Q_D(KInputDialog); d->ensureDoubleSpinBox(); d->doubleSpinBox->setDecimals(decimals); } int KInputDialog::doubleDecimals() const { Q_D(const KInputDialog); if (d->doubleSpinBox) { return d->doubleSpinBox->decimals(); } else { return 2; } } void KInputDialog::setOkButtonText(const QString &text) { Q_D(const KInputDialog); d->ensureLayout(); d->okButton->setText(text); } QString KInputDialog::okButtonText() const { Q_D(const KInputDialog); d->ensureLayout(); return d->okButton->text(); } void KInputDialog::setCancelButtonText(const QString &text) { Q_D(const KInputDialog); d->ensureLayout(); d->cancelButton->setText(text); } QString KInputDialog::cancelButtonText() const { Q_D(const KInputDialog); d->ensureLayout(); return d->cancelButton->text(); } void KInputDialog::open(QObject *receiver, const char *member) { Q_D(KInputDialog); connect(this, signalForMember(member), receiver, member); d->receiverToDisconnectOnClose = receiver; d->memberToDisconnectOnClose = member; QDialog::open(); } QSize KInputDialog::minimumSizeHint() const { Q_D(const KInputDialog); d->ensureLayout(); return QDialog::minimumSizeHint(); } QSize KInputDialog::sizeHint() const { Q_D(const KInputDialog); d->ensureLayout(); return QDialog::sizeHint(); } void KInputDialog::setVisible(bool visible) { Q_D(const KInputDialog); if (visible) { d->ensureLayout(); d->inputWidget->setFocus(); if (d->inputWidget == d->lineEdit) { d->lineEdit->selectAll(); } else if (d->inputWidget == d->plainTextEdit) { d->plainTextEdit->selectAll(); } else if (d->inputWidget == d->intSpinBox) { d->intSpinBox->selectAll(); } else if (d->inputWidget == d->doubleSpinBox) { d->doubleSpinBox->selectAll(); } } QDialog::setVisible(visible); } QString KInputDialog::placeholderText() const { Q_D(const KInputDialog); if (d->lineEdit) return d->lineEdit->placeholderText(); else return QString(); } void KInputDialog::setPlaceholderText(const QString &str) { Q_D(const KInputDialog); if (d->lineEdit) d->lineEdit->setPlaceholderText(str); } void KInputDialog::done(int result) { Q_D(KInputDialog); QDialog::done(result); if (result) { InputMode mode = inputMode(); switch (mode) { case DoubleInput: Q_EMIT doubleValueSelected(doubleValue()); break; case IntInput: Q_EMIT intValueSelected(intValue()); break; default: Q_ASSERT(mode == TextInput); Q_EMIT textValueSelected(textValue()); } } if (d->receiverToDisconnectOnClose) { disconnect(this, signalForMember(d->memberToDisconnectOnClose), d->receiverToDisconnectOnClose, d->memberToDisconnectOnClose); d->receiverToDisconnectOnClose = nullptr; } d->memberToDisconnectOnClose.clear(); } void KInputDialog::changeTheme() { Q_D(KInputDialog); KDialog::changeTheme(); if (d->okButton) d->okButton->setProperty("isImportant", true); } QString KInputDialog::getText(QWidget *parent, const QString &label, QLineEdit::EchoMode mode, const QString &text, bool *ok, Qt::WindowFlags flags, Qt::InputMethodHints inputMethodHints) { KInputDialog *dialog = new KInputDialog(parent); dialog->setLabelText(label); dialog->setTextValue(text); dialog->setTextEchoMode(mode); dialog->setInputMethodHints(inputMethodHints); const int ret = dialog->exec(); if (ok) *ok = !!ret; if (ret) { return dialog->textValue(); } else { return QString(); } } QString KInputDialog::getMultiLineText(QWidget *parent, const QString &label, const QString &text, bool *ok, Qt::WindowFlags flags, Qt::InputMethodHints inputMethodHints) { KInputDialog *dialog = new KInputDialog(parent); dialog->setOptions(KInputDialog::UsePlainTextEditForTextInput); dialog->setLabelText(label); dialog->setTextValue(text); dialog->setInputMethodHints(inputMethodHints); const int ret = dialog->exec(); if (ok) *ok = !!ret; if (ret) { return dialog->textValue(); } else { return QString(); } } int KInputDialog::getInt(QWidget *parent, const QString &label, int value, int min, int max, int step, bool *ok, Qt::WindowFlags flags) { KInputDialog *dialog = new KInputDialog(parent); dialog->setLabelText(label); dialog->setIntRange(min, max); dialog->setIntValue(value); dialog->setIntStep(step); const int ret = dialog->exec(); if (ok) *ok = !!ret; if (ret) { return dialog->intValue(); } else { return value; } } double KInputDialog::getDouble(QWidget *parent, const QString &label, double value, double minValue, double maxValue, int decimals, bool *ok, Qt::WindowFlags flags) { KInputDialog *dialog = new KInputDialog(parent); dialog->setLabelText(label); dialog->setDoubleDecimals(decimals); dialog->setDoubleRange(minValue, maxValue); dialog->setDoubleValue(value); const int ret = dialog->exec(); if (ok) *ok = !!ret; if (ret) { return dialog->doubleValue(); } else { return value; } } QString KInputDialog::getItem(QWidget *parent, const QString &label, const QStringList &items, int current, bool editable, bool *ok, Qt::WindowFlags flags, Qt::InputMethodHints inputMethodHints) { QString text(items.value(current)); KInputDialog *dialog = new KInputDialog(parent); dialog->setLabelText(label); dialog->setComboBoxItems(items); dialog->setTextValue(text); dialog->setComboBoxEditable(editable); dialog->setInputMethodHints(inputMethodHints); const int ret = dialog->exec(); if (ok) *ok = !!ret; if (ret) { return dialog->textValue(); } else { return text; } } void KInputDialog::setDoubleStep(double step) { Q_D(KInputDialog); d->ensureDoubleSpinBox(); d->doubleSpinBox->setSingleStep(step); } double KInputDialog::doubleStep() const { Q_D(const KInputDialog); if (d->doubleSpinBox) return d->doubleSpinBox->singleStep(); else return 1.0; } QSize KInputDialogSpinBox::sizeHint() const { QSize size; size.setWidth(288); size.setHeight(36); return size; } QSize KInputDialogLineEdit::sizeHint() const { QSize size; size.setWidth(288); size.setHeight(36); return size; } QSize KInputDialogDoubleSpinBox::sizeHint() const { QSize size; size.setWidth(288); size.setHeight(36); return size; } } #include "kinputdialog.moc" #include "moc_kinputdialog.cpp" libkysdk-applications/kysdk-qtwidgets/src/kdragwidget.h0000664000175000017500000000520715104543305022376 0ustar fengfeng/* * libkysdk-qtwidgets's Library * * Copyright (C) 2024, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhenyu Wang * */ #ifndef KDRAGWIDGET_H #define KDRAGWIDGET_H #include "gui_g.h" #include "kpushbutton.h" #include #include #include #include namespace kdk { /** * @defgroup DragModule * { */ class KDragWidgetPrivate; /** * @brief 拖动文件或文件夹,可识别并获取文件或文件夹路径 * @since 2.3.1.0 */ class GUI_EXPORT KDragWidget : public QWidget { Q_OBJECT public: KDragWidget(QWidget *parent = nullptr); /** * @brief iconButton * @return 返回iconbutton */ KPushButton *iconButton(); /** * @brief textLabel * @return 返回textlabel */ QLabel *textLabel(); /** * @brief fileDialog * @return 返回QFiledialog */ QFileDialog *fileDialog(); /** * @brief 将文件对话框中使用的过滤器设置为给定的过滤器。 * @param filter */ void setNameFilter(const QString &filter); /** * @brief 设置文件对话框中使用的过滤器。 * @param filters */ void setNameFilters(const QStringList &filters); protected: void mouseMoveEvent(QMouseEvent *event); void mousePressEvent(QMouseEvent *event); void mouseReleaseEvent(QMouseEvent *event); void keyPressEvent(QKeyEvent *event); void keyReleaseEvent(QKeyEvent *event); void paintEvent(QPaintEvent *event); bool eventFilter(QObject *watched, QEvent *event); void dragEnterEvent(QDragEnterEvent *event); void dragLeaveEvent(QDragLeaveEvent *event); void dragMoveEvent(QDragMoveEvent *event); void dropEvent(QDropEvent *event); Q_SIGNALS: void getPath(QString); /** * @brief 获取列表信号 * @since 2.5.1.2-0k1.0 */ void getPathList(QStringList); private: Q_DECLARE_PRIVATE(KDragWidget) KDragWidgetPrivate *const d_ptr; }; } #endif // KDRAGWIDGET_H libkysdk-applications/kysdk-qtwidgets/src/kbreadcrumb.h0000664000175000017500000000344215104543305022362 0ustar fengfeng/* * libkysdk-qtwidgets's Library * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #ifndef KBREADCRUMB_H #define KBREADCRUMB_H #include namespace kdk { /** * @defgroup BreadCrumb */ class KBreadCrumbPrivate; /** * @brief KBreadCrumbType,包括两种类型。 */ enum KBreadCrumbType { FlatBreadCrumb, CubeBreadCrumb }; /** * @brief 面包屑控件 * @since 1.0.0 */ class KBreadCrumb : public QTabBar { Q_OBJECT public: explicit KBreadCrumb(QWidget *parent = nullptr); /** * @brief 设置图标 * @param icon */ void setIcon(const QIcon &icon); /** * @brief 获取图标 * @return */ QIcon icon() const; /** * @brief 返回按钮边框是否凸起 * @return */ bool isFlat() const; /** * @brief 设置按钮边框是否凸起 * @param flat */ void setFlat(bool flat); protected: QSize tabSizeHint(int index) const; void paintEvent(QPaintEvent *event); private: Q_DECLARE_PRIVATE(KBreadCrumb) KBreadCrumbPrivate *const d_ptr; }; } #endif // KBREADCRUMB_H libkysdk-applications/kysdk-qtwidgets/src/kpixmapcontainer.cpp0000664000175000017500000001310415104543305024004 0ustar fengfeng/* * libkysdk-qtwidgets's Library * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #include "kpixmapcontainer.h" #include "themeController.h" #include #include #include #include #include const static int margin = 10; namespace kdk { class KPixmapContainerPrivate : public QObject { Q_OBJECT Q_DECLARE_PUBLIC(KPixmapContainer) public: KPixmapContainerPrivate(KPixmapContainer *parent); private: KPixmapContainer *q_ptr; QPixmap m_pixmap; QColor m_color; int m_fontSize; int m_value; bool m_isShowValue; }; KPixmapContainer::KPixmapContainer(QWidget *parent) : QWidget(parent) , d_ptr(new KPixmapContainerPrivate(this)) { Q_D(KPixmapContainer); setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); } int KPixmapContainer::value() const { Q_D(const KPixmapContainer); return d->m_value; } void KPixmapContainer::setValue(int value) { Q_D(KPixmapContainer); d->m_value = value; } void KPixmapContainer::setValueVisiable(bool flag) { Q_D(KPixmapContainer); d->m_isShowValue = flag; } bool KPixmapContainer::isValueVisiable() const { Q_D(const KPixmapContainer); return d->m_isShowValue; } void KPixmapContainer::setPixmap(const QPixmap &pixmap) { Q_D(KPixmapContainer); d->m_pixmap = pixmap; QSize size = QSize(d->m_pixmap.size().width() + 20, d->m_pixmap.size().height() + 20); this->setFixedSize(size); update(); } QPixmap KPixmapContainer::pixmap() const { Q_D(const KPixmapContainer); if (!d->m_pixmap.isNull()) return d->m_pixmap; else return QPixmap(); } void KPixmapContainer::clearValue() { Q_D(KPixmapContainer); d->m_value = 0; } QColor KPixmapContainer::color() { Q_D(KPixmapContainer); return d->m_color; } void KPixmapContainer::setColor(const QColor &color) { Q_D(KPixmapContainer); d->m_color = color; } int KPixmapContainer::fontSize() { Q_D(KPixmapContainer); return d->m_fontSize; } void KPixmapContainer::setFontSize(int size) { Q_D(KPixmapContainer); if (size < 1 || size > 100) return; d->m_fontSize = size; update(); } void KPixmapContainer::paintEvent(QPaintEvent *event) { Q_D(KPixmapContainer); QWidget::paintEvent(event); QPainter p(this); p.setPen(Qt::NoPen); p.drawRect(this->rect()); QFont font(QApplication::font()); font.setPixelSize(d->m_fontSize); QFontMetrics fm(font); int height = fm.height(); int width; if (d->m_value < 1 || !d->m_isShowValue) { width = 10; height = 10; } else if (d->m_value >= 1 && d->m_value < 1000) { width = fm.horizontalAdvance(QString::number(d->m_value)); width = width > height ? width : height; } else { width = fm.horizontalAdvance(QString::number(999)); width = width > height ? width : height; } QPainter painter(this); painter.setRenderHint(QPainter::Antialiasing); painter.setPen(Qt::NoPen); d->m_color = ThemeController::getCustomColorFromDT("highlight-active"); painter.setBrush(d->m_color); if (ThemeController::themeMode() == LightTheme) painter.drawPixmap(margin, margin, d->m_pixmap.width(), d->m_pixmap.height(), d->m_pixmap); else { if (!d->m_pixmap.isNull()) { if (ThemeController::isPixmapPureColor(d->m_pixmap)) painter.drawPixmap(margin, margin, d->m_pixmap.width(), d->m_pixmap.height(), ThemeController::drawSymbolicColoredPixmap(d->m_pixmap)); } } QRect tmpRect(this->rect().topRight().x() - width / 2 - margin, this->rect().topRight().y() - height / 2 + margin, width, height); painter.drawRoundedRect(tmpRect, height / 2, height / 2); painter.setPen(ThemeController::getCustomColorFromDT("kwhite")); if (d->m_value >= 1 && d->m_value < 1000 && d->m_isShowValue) { QFont font(QApplication::font()); font.setPixelSize(d->m_fontSize); painter.setFont(font); painter.drawText(tmpRect, Qt::AlignCenter, QString::number(d->m_value)); } if (d->m_value >= 1000 && d->m_value < INTMAX_MAX && d->m_isShowValue) { painter.setBrush(ThemeController::getCustomColorFromDT("kwhite")); QPointF pointf(tmpRect.center().x(), tmpRect.center().y()); painter.drawEllipse(pointf, qreal(1.0), qreal(1.0)); QPointF leff(pointf.x() - 5, pointf.y()); QPointF rightf(pointf.x() + 5, pointf.y()); painter.drawEllipse(leff, qreal(1.0), qreal(1.0)); painter.drawEllipse(rightf, qreal(1.0), qreal(1.0)); } } KPixmapContainerPrivate::KPixmapContainerPrivate(KPixmapContainer *parent) : q_ptr(parent) { Q_Q(KPixmapContainer); m_value = -1; m_isShowValue = true; m_color = ThemeController::getCustomColorFromDT("kbrand1"); m_fontSize = 10; setParent(parent); } } #include "kpixmapcontainer.moc" #include "moc_kpixmapcontainer.cpp" libkysdk-applications/kysdk-qtwidgets/src/kpushbuttonframe.h0000664000175000017500000000402515104543305023500 0ustar fengfeng/* * * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Sisheng He * */ #ifndef PUSHBUTTONWIDGET_H #define PUSHBUTTONWIDGET_H #include "kbaseframe.h" #include "klabel.h" #include "kpushbutton.h" /** * @brief 创建一个带 QPushButton 的 Frame * */ namespace kdk { /** * @defgroup ContainerModules * @brief 带QpushButton的frame * @since 3.0.1.0 * { */ class KPushButtonFramePrivate; class KPushButtonFrame : public KBaseFrame { Q_OBJECT public: /** * @brief 创建一个带 QPushButton 的 Frame * * @param title: text of m_settingName * @param style: 设置圆角(None:无圆角,Top:上圆角,Bottom:下圆角,Around:四圆角) * @param parent */ explicit KPushButtonFrame(const QString title, QWidget *parent = nullptr, BorderRadiusStyle style = BorderRadiusStyle::None); /** * @brief * */ ~KPushButtonFrame(); /** * @brief 获取 m_pushButton * * @return KPushButton: m_pushButton */ KPushButton *pushButton(); /** * @brief 获取label * * @return KLabel */ KLabel *titleLabel(); /** * @brief 获取layout * * @return QHBoxLayout */ QHBoxLayout *mainHLayout(); private: Q_DECLARE_PRIVATE(KPushButtonFrame) KPushButtonFramePrivate *const d_ptr; }; } #endif // PUSHBUTTONWIDGET_H libkysdk-applications/kysdk-qtwidgets/src/klineeditframe.cpp0000664000175000017500000000442315104543305023417 0ustar fengfeng/* * * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Sisheng He * */ #include "klineeditframe.h" #include namespace kdk { class KLineEditFramePrivate : public QObject { Q_OBJECT Q_DECLARE_PUBLIC(KLineEditFrame) public: KLineEditFramePrivate(KLineEditFrame *parent); private: KLineEditFrame *q_ptr; QLineEdit *m_pLineEdit; KLabel *m_pSettingName; QHBoxLayout *m_pMainLayout; }; KLineEditFramePrivate::KLineEditFramePrivate(KLineEditFrame *parent) : q_ptr(parent) { Q_Q(KLineEditFrame); setParent(parent); m_pMainLayout = new QHBoxLayout(q); m_pMainLayout->setContentsMargins(16, 0, 16, 0); m_pMainLayout->setSpacing(16); m_pSettingName = new KLabel(q); m_pSettingName->setFixedWidth(SETTING_LABEL_WIDTH); m_pLineEdit = new QLineEdit(q); m_pMainLayout->addWidget(m_pSettingName); m_pMainLayout->addWidget(m_pLineEdit); q->setLayout(m_pMainLayout); } KLineEditFrame::KLineEditFrame(const QString title, QWidget *parent, BorderRadiusStyle style) : KBaseFrame(parent, style, true) , d_ptr(new KLineEditFramePrivate(this)) { Q_D(KLineEditFrame); setObjectName("KLineEditFrame"); d->m_pSettingName->setText(title); } KLineEditFrame::~KLineEditFrame() { } QLineEdit *KLineEditFrame::lineEdit() { Q_D(KLineEditFrame); return d->m_pLineEdit; } QHBoxLayout *KLineEditFrame::mainHLayout() { Q_D(KLineEditFrame); return d->m_pMainLayout; } KLabel *KLineEditFrame::titleLabel() { Q_D(KLineEditFrame); return d->m_pSettingName; } } #include "klineeditframe.moc" #include "moc_klineeditframe.cpp" libkysdk-applications/kysdk-qtwidgets/src/kwidget.h0000664000175000017500000000715715104543305021546 0ustar fengfeng/* * libkysdk-qtwidgets's Library * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #ifndef KWIDGET_H #define KWIDGET_H #include "kiconbar.h" #include "kwindowbuttonbar.h" #include #include #include namespace kdk { /** * @brief 支持切换三种结构布局 */ enum LayoutType { VerticalType, // 上下结构 HorizontalType, // 左右结构 MixedType // 过渡结构 }; /** @defgroup FrameModule * @{ */ class KWidgetPrivate; /** * @brief 继承自QWidget,支持响应主题背景切换,图标主题切换,标题颜色响应窗口激活状态,内容区域分为side区和base区 * @since 1.0.0 */ class GUI_EXPORT KWidget : public QWidget, public ThemeController { Q_OBJECT public: explicit KWidget(QWidget *parent = nullptr); ~KWidget(); /** * @brief 设置窗体图标 * @param icon */ void setIcon(const QIcon &icon); /** * @brief 设置窗体图标 * @param iconName 直接指定系统目录中的图标名称,如"kylin-music" */ void setIcon(const QString &iconName); /** * @brief 设置窗体名称 * @param widgetName */ void setWidgetName(const QString &widgetName); /** * @brief 获取左边栏widget,通过setlayout添加自定义内容 * @return 返回左边栏widget */ QWidget *sideBar(); /** * @brief 获取主内容区widget,通过setlayout添加自定义内容 * @return 返回主内容区widget */ QWidget *baseBar(); /** * @brief 获取窗口三联组合控件,以控制是否显示最大化、最小化按钮和下拉菜单按钮;也可增加自定义按钮 * @return 返回窗口三联组合控件 */ KWindowButtonBar *windowButtonBar(); /** * @brief 获取窗口标题、图标组合控件,以控制相关样式 * @return 返回窗口标题、图标组合控件 */ KIconBar *iconBar(); /** * @brief 设置布局结构类型 */ void setLayoutType(LayoutType type); /** * @brief 设置窗口标志 * @param type * @since 1.2.0 */ void setWindowFlags(Qt::WindowFlags type); /** * @brief 设置窗口标志 * @param flag * @param on * @since 1.2.0 */ void setWindowFlag(Qt::WindowType flag, bool on = true); /** * @brief 设置sidebar是否遵循系统更改宽度 * @param flag * @since 1.2.0 */ void setSidebarFollowMode(bool flag); /** * @brief 返回sidebar是否遵循系统更改宽度 * @return * @since 1.2.0 */ bool sidebarFollowMode(); protected: bool eventFilter(QObject *target, QEvent *event) override; virtual void changeIconStyle(); virtual void changeTheme(); private: Q_DECLARE_PRIVATE(KWidget) KWidgetPrivate *const d_ptr; }; } /** * @example testWidget/testwidget.h * @example testWidget/testwidget.cpp * @} */ #endif // KWIDGET_H libkysdk-applications/kysdk-qtwidgets/src/kminicalendaritem.cpp0000664000175000017500000004125415104543305024117 0ustar fengfeng/* * libkysdk-qtwidgets's Library * * Copyright (C) 2024, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhenyu Wang * */ #pragma execution_character_set("utf-8") #include "kminicalendaritem.h" #include "qdatetime.h" #include "qdebug.h" #include "qevent.h" #include "qpainter.h" namespace kdk { class KMiniCalendarItemPrivate : public QObject { Q_OBJECT Q_DECLARE_PUBLIC(KMiniCalendarItem) public: KMiniCalendarItemPrivate(KMiniCalendarItem *parent); private: KMiniCalendarItem *q_ptr; KMiniCalendarItem::SelectType selectType; // 选中模式 KMiniCalendarItem::DayType dayType; // 当前日类型 bool hover; // 鼠标是否悬停 bool pressed; // 鼠标是否按下 bool select; // 是否选中 bool showLunar; // 显示农历 bool enableBorder; // 显示边框 QDate date; // 当前日期 QString lunar; // 农历信息 QColor borderColor; // 边框颜色 QColor weekColor; // 周末颜色 QColor superColor; // 角标颜色 QColor lunarColor; // 农历节日颜色 QColor currentTextColor; // 当前月文字颜色 QColor otherTextColor; // 其他月文字颜色 QColor selectTextColor; // 选中日期文字颜色 QColor hoverTextColor; // 悬停日期文字颜色 QColor currentLunarColor; // 当前月农历文字颜色 QColor otherLunarColor; // 其他月农历文字颜色 QColor selectLunarColor; // 选中日期农历文字颜色 QColor hoverLunarColor; // 悬停日期农历文字颜色 QColor currentBgColor; // 当前月背景颜色 QColor otherBgColor; // 其他月背景颜色 QColor selectBgColor; // 选中日期背景颜色 QColor hoverBgColor; // 悬停日期背景颜色 }; KMiniCalendarItemPrivate::KMiniCalendarItemPrivate(KMiniCalendarItem *parent) : q_ptr(parent) { Q_Q(KMiniCalendarItem); hover = false; pressed = false; select = false; showLunar = true; enableBorder = false; selectType = KMiniCalendarItem::SelectType_Rect; date = QDate::currentDate(); lunar = "初一"; dayType = KMiniCalendarItem::DayType_MonthCurrent; borderColor = QColor(180, 180, 180); weekColor = QColor(255, 0, 0); superColor = QColor(255, 129, 6); lunarColor = QColor(55, 156, 238); currentTextColor = QColor(0, 0, 0); otherTextColor = QColor(200, 200, 200); selectTextColor = QColor(255, 255, 255); hoverTextColor = QColor(250, 250, 250); currentLunarColor = QColor(150, 150, 150); otherLunarColor = QColor(200, 200, 200); selectLunarColor = QColor(255, 255, 255); hoverLunarColor = QColor(250, 250, 250); currentBgColor = QColor(255, 255, 255); otherBgColor = QColor(240, 240, 240); selectBgColor = QColor(208, 47, 18); hoverBgColor = QColor(204, 183, 180); } KMiniCalendarItem::KMiniCalendarItem(QWidget *parent) : QWidget(parent) , d_ptr(new KMiniCalendarItemPrivate(this)) { Q_D(KMiniCalendarItem); } void KMiniCalendarItem::enterEvent(QEvent *) { Q_D(KMiniCalendarItem); d->hover = true; update(); } void KMiniCalendarItem::leaveEvent(QEvent *) { Q_D(KMiniCalendarItem); d->hover = false; update(); } void KMiniCalendarItem::mousePressEvent(QMouseEvent *) { Q_D(KMiniCalendarItem); d->pressed = true; update(); emit clicked(d->date, d->dayType); } void KMiniCalendarItem::mouseReleaseEvent(QMouseEvent *) { Q_D(KMiniCalendarItem); d->pressed = false; update(); } void KMiniCalendarItem::paintEvent(QPaintEvent *) { Q_D(KMiniCalendarItem); // 绘制准备工作,启用反锯齿 QPainter painter(this); painter.setRenderHints(QPainter::Antialiasing | QPainter::TextAntialiasing); // 绘制背景和边框 drawBg(&painter); // 优先绘制选中状态,其次绘制悬停状态 if (d->select) { drawBgCurrent(&painter, d->selectBgColor); } else if (d->hover) { drawBgCurrent(&painter, d->hoverBgColor); } // 绘制日期 drawDay(&painter); // 绘制农历信息 drawLunar(&painter); } void KMiniCalendarItem::drawBg(QPainter *painter) { Q_D(KMiniCalendarItem); painter->save(); // 根据当前类型选择对应的颜色 QColor bgColor = d->currentBgColor; if (d->dayType == DayType_MonthPre || d->dayType == DayType_MonthNext) { bgColor = d->otherBgColor; } if (getEnableBorder()) painter->setPen(d->borderColor); else painter->setPen(bgColor); painter->setBrush(bgColor); painter->drawRect(rect()); painter->restore(); } void KMiniCalendarItem::drawBgCurrent(QPainter *painter, const QColor &color) { Q_D(KMiniCalendarItem); int width = this->width(); int height = this->height(); int side = qMin(width, height); painter->save(); painter->setPen(Qt::NoPen); painter->setBrush(color); // 根据设定绘制背景样式 if (d->selectType == SelectType_Rect) { painter->drawRect(rect()); } else if (d->selectType == SelectType_Circle) { int radius = side / 2; painter->drawEllipse(QPointF(width / 2, height / 2), radius, radius); } else if (d->selectType == SelectType_Triangle) { int radius = side / 3; QPolygon pts; pts.setPoints(3, 1, 1, radius, 1, 1, radius); painter->drawRect(rect()); painter->setBrush(d->superColor); painter->drawConvexPolygon(pts); } painter->restore(); } void KMiniCalendarItem::drawDay(QPainter *painter) { Q_D(KMiniCalendarItem); int width = this->width(); int height = this->height(); int side = qMin(width, height); painter->save(); // 根据当前类型选择对应的颜色 QColor color = d->currentTextColor; if (d->dayType == DayType_MonthPre || d->dayType == DayType_MonthNext) { color = d->otherTextColor; } else if (d->dayType == DayType_WeekEnd) { color = d->weekColor; } if (d->select) { color = d->selectTextColor; } else if (d->hover) { color = d->hoverTextColor; } painter->setPen(color); if (d->showLunar) { QFont font; font.setPixelSize(side / 2.7); painter->setFont(font); QRect dayRect = QRect(0, 0, width, height / 1.5); painter->drawText(dayRect, Qt::AlignHCenter | Qt::AlignBottom, QString::number(d->date.day())); } else { QFont font; font.setPixelSize(side / 2); painter->setFont(font); QRect dayRect = QRect(0, 0, width, height); painter->drawText(dayRect, Qt::AlignCenter, QString::number(d->date.day())); } painter->restore(); } void KMiniCalendarItem::drawLunar(QPainter *painter) { Q_D(KMiniCalendarItem); if (!d->showLunar) { return; } int width = this->width(); int height = this->height(); int side = qMin(width, height); painter->save(); QStringList listDayName; listDayName << "*" << "初一" << "初二" << "初三" << "初四" << "初五" << "初六" << "初七" << "初八" << "初九" << "初十" << "十一" << "十二" << "十三" << "十四" << "十五" << "十六" << "十七" << "十八" << "十九" << "二十" << "廿一" << "廿二" << "廿三" << "廿四" << "廿五" << "廿六" << "廿七" << "廿八" << "廿九" << "三十"; // 根据当前类型选择对应的颜色 QColor color = d->currentLunarColor; if (d->dayType == DayType_MonthPre || d->dayType == DayType_MonthNext) { color = d->otherLunarColor; } if (d->select) { color = d->selectTextColor; } else if (d->hover) { color = d->hoverTextColor; } painter->setPen(color); QFont font; font.setPixelSize(side / 4); font.setBold(true); painter->setFont(font); QRect lunarRect(0, height / 2, width, height / 2.2); painter->drawText(lunarRect, Qt::AlignCenter, d->lunar); painter->restore(); } bool KMiniCalendarItem::getSelect() const { Q_D(const KMiniCalendarItem); return d->select; } bool KMiniCalendarItem::getShowLunar() const { Q_D(const KMiniCalendarItem); return d->showLunar; } bool KMiniCalendarItem::getEnableBorder() const { Q_D(const KMiniCalendarItem); return d->enableBorder; } KMiniCalendarItem::SelectType KMiniCalendarItem::getSelectType() const { Q_D(const KMiniCalendarItem); return d->selectType; } QDate KMiniCalendarItem::getDate() const { Q_D(const KMiniCalendarItem); return d->date; } QString KMiniCalendarItem::getLunar() const { Q_D(const KMiniCalendarItem); return d->lunar; } KMiniCalendarItem::DayType KMiniCalendarItem::getDayType() const { Q_D(const KMiniCalendarItem); return d->dayType; } QColor KMiniCalendarItem::getBorderColor() const { Q_D(const KMiniCalendarItem); return d->borderColor; } QColor KMiniCalendarItem::getWeekColor() const { Q_D(const KMiniCalendarItem); return d->weekColor; } QColor KMiniCalendarItem::getSuperColor() const { Q_D(const KMiniCalendarItem); return d->superColor; } QColor KMiniCalendarItem::getLunarColor() const { Q_D(const KMiniCalendarItem); return d->lunarColor; } QColor KMiniCalendarItem::getCurrentTextColor() const { Q_D(const KMiniCalendarItem); return d->currentTextColor; } QColor KMiniCalendarItem::getOtherTextColor() const { Q_D(const KMiniCalendarItem); return d->otherTextColor; } QColor KMiniCalendarItem::getSelectTextColor() const { Q_D(const KMiniCalendarItem); return d->selectTextColor; } QColor KMiniCalendarItem::getHoverTextColor() const { Q_D(const KMiniCalendarItem); return d->hoverTextColor; } QColor KMiniCalendarItem::getCurrentLunarColor() const { Q_D(const KMiniCalendarItem); return d->currentLunarColor; } QColor KMiniCalendarItem::getOtherLunarColor() const { Q_D(const KMiniCalendarItem); return d->otherLunarColor; } QColor KMiniCalendarItem::getSelectLunarColor() const { Q_D(const KMiniCalendarItem); return d->selectLunarColor; } QColor KMiniCalendarItem::getHoverLunarColor() const { Q_D(const KMiniCalendarItem); return d->hoverLunarColor; } QColor KMiniCalendarItem::getCurrentBgColor() const { Q_D(const KMiniCalendarItem); return d->currentBgColor; } QColor KMiniCalendarItem::getOtherBgColor() const { Q_D(const KMiniCalendarItem); return d->otherBgColor; } QColor KMiniCalendarItem::getSelectBgColor() const { Q_D(const KMiniCalendarItem); return d->selectBgColor; } QColor KMiniCalendarItem::getHoverBgColor() const { Q_D(const KMiniCalendarItem); return d->hoverBgColor; } QSize KMiniCalendarItem::sizeHint() const { Q_D(const KMiniCalendarItem); return QSize(100, 100); } QSize KMiniCalendarItem::minimumSizeHint() const { Q_D(const KMiniCalendarItem); return QSize(20, 20); } void KMiniCalendarItem::setSelect(bool select) { Q_D(KMiniCalendarItem); if (d->select != select) { d->select = select; update(); } } void KMiniCalendarItem::setShowLunar(bool showLunar) { Q_D(KMiniCalendarItem); if (d->showLunar != showLunar) { d->showLunar = showLunar; update(); } } void KMiniCalendarItem::setSelectType(const KMiniCalendarItem::SelectType &selectType) { Q_D(KMiniCalendarItem); if (d->selectType != selectType) { d->selectType = selectType; update(); } } void KMiniCalendarItem::setDate(const QDate &date) { Q_D(KMiniCalendarItem); if (d->date != date) { d->date = date; update(); } } void KMiniCalendarItem::setLunar(const QString &lunar) { Q_D(KMiniCalendarItem); if (d->lunar != lunar) { d->lunar = lunar; update(); } } void KMiniCalendarItem::setDayType(const DayType &dayType) { Q_D(KMiniCalendarItem); if (d->dayType != dayType) { d->dayType = dayType; update(); } } void KMiniCalendarItem::setDate(const QDate &date, const QString &lunar, const DayType &dayType) { Q_D(KMiniCalendarItem); d->date = date; d->lunar = lunar; d->dayType = dayType; update(); } void KMiniCalendarItem::setEnableBorder(bool bVisible) { Q_D(KMiniCalendarItem); if (d->enableBorder != bVisible) { d->enableBorder = bVisible; update(); } } void KMiniCalendarItem::setBorderColor(const QColor &borderColor) { Q_D(KMiniCalendarItem); if (d->borderColor != borderColor) { d->borderColor = borderColor; update(); } } void KMiniCalendarItem::setWeekColor(const QColor &weekColor) { Q_D(KMiniCalendarItem); if (d->weekColor != weekColor) { d->weekColor = weekColor; update(); } } void KMiniCalendarItem::setSuperColor(const QColor &superColor) { Q_D(KMiniCalendarItem); if (d->superColor != superColor) { d->superColor = superColor; update(); } } void KMiniCalendarItem::setLunarColor(const QColor &lunarColor) { Q_D(KMiniCalendarItem); if (d->lunarColor != lunarColor) { d->lunarColor = lunarColor; update(); } } void KMiniCalendarItem::setCurrentTextColor(const QColor ¤tTextColor) { Q_D(KMiniCalendarItem); if (d->currentTextColor != currentTextColor) { d->currentTextColor = currentTextColor; update(); } } void KMiniCalendarItem::setOtherTextColor(const QColor &otherTextColor) { Q_D(KMiniCalendarItem); if (d->otherTextColor != otherTextColor) { d->otherTextColor = otherTextColor; update(); } } void KMiniCalendarItem::setSelectTextColor(const QColor &selectTextColor) { Q_D(KMiniCalendarItem); if (d->selectTextColor != selectTextColor) { d->selectTextColor = selectTextColor; update(); } } void KMiniCalendarItem::setHoverTextColor(const QColor &hoverTextColor) { Q_D(KMiniCalendarItem); if (d->hoverTextColor != hoverTextColor) { d->hoverTextColor = hoverTextColor; update(); } } void KMiniCalendarItem::setCurrentLunarColor(const QColor ¤tLunarColor) { Q_D(KMiniCalendarItem); if (d->currentLunarColor != currentLunarColor) { d->currentLunarColor = currentLunarColor; update(); } } void KMiniCalendarItem::setOtherLunarColor(const QColor &otherLunarColor) { Q_D(KMiniCalendarItem); if (d->otherLunarColor != otherLunarColor) { d->otherLunarColor = otherLunarColor; update(); } } void KMiniCalendarItem::setSelectLunarColor(const QColor &selectLunarColor) { Q_D(KMiniCalendarItem); if (d->selectLunarColor != selectLunarColor) { d->selectLunarColor = selectLunarColor; update(); } } void KMiniCalendarItem::setHoverLunarColor(const QColor &hoverLunarColor) { Q_D(KMiniCalendarItem); if (d->hoverLunarColor != hoverLunarColor) { d->hoverLunarColor = hoverLunarColor; update(); } } void KMiniCalendarItem::setCurrentBgColor(const QColor ¤tBgColor) { Q_D(KMiniCalendarItem); if (d->currentBgColor != currentBgColor) { d->currentBgColor = currentBgColor; update(); } } void KMiniCalendarItem::setOtherBgColor(const QColor &otherBgColor) { Q_D(KMiniCalendarItem); if (d->otherBgColor != otherBgColor) { d->otherBgColor = otherBgColor; update(); } } void KMiniCalendarItem::setSelectBgColor(const QColor &selectBgColor) { Q_D(KMiniCalendarItem); if (d->selectBgColor != selectBgColor) { d->selectBgColor = selectBgColor; update(); } } void KMiniCalendarItem::setHoverBgColor(const QColor &hoverBgColor) { Q_D(KMiniCalendarItem); if (d->hoverBgColor != hoverBgColor) { d->hoverBgColor = hoverBgColor; update(); } } } #include "kminicalendaritem.moc" #include "moc_kminicalendaritem.cpp" libkysdk-applications/kysdk-qtwidgets/src/kaddbutton.cpp0000664000175000017500000001565615104543305022605 0ustar fengfeng/* * * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Sisheng He * */ #include "kaddbutton.h" #include "themeController.h" #include #include #include #include #include #include #include #include #include #define TOP_LEFT_CORNER 1 #define TOP_RIGHT_CORNER 2 #define BOTTOM_RIGHT_CORNER 4 #define BOTTOM_LEFT_CORNER 8 namespace kdk { class KAddButtonPrivate : public QObject, public ThemeController { Q_OBJECT Q_DECLARE_PUBLIC(KAddButton) public: KAddButtonPrivate(KAddButton *parent); private: KAddButton *q_ptr; KBaseFrame::BorderRadiusStyle m_radiusType; bool m_isTabletMode = false; QDBusInterface *m_statusSessionDbus = nullptr; bool m_heightAdaptive = false; private: QPainterPath getPaintrPath(); private Q_SLOTS: void mode_change_signal_slots(bool b); }; KAddButtonPrivate::KAddButtonPrivate(KAddButton *parent) : q_ptr(parent) { Q_Q(KAddButton); setParent(parent); QHBoxLayout *addLyt = new QHBoxLayout(q); QLabel *iconLabel = new QLabel(q); QLabel *textLabel = new QLabel(tr("Add")); QIcon mAddIcon = QIcon::fromTheme("list-add-symbolic"); iconLabel->setPixmap(mAddIcon.pixmap(mAddIcon.actualSize(QSize(16, 16)))); iconLabel->setProperty("iconHighlightEffectMode", 1); addLyt->addStretch(); addLyt->addWidget(iconLabel); addLyt->addWidget(textLabel); addLyt->addStretch(); q->setLayout(addLyt); if (ThemeController::themeMode() == DarkTheme) iconLabel->setProperty("useIconHighlightEffect", true); connect(m_gsetting, &QGSettings::changed, this, [=](const QString &key) { if (ThemeController::themeMode() == LightTheme) iconLabel->setProperty("useIconHighlightEffect", false); else iconLabel->setProperty("useIconHighlightEffect", true); }); } void KAddButtonPrivate::mode_change_signal_slots(bool b) { Q_Q(KAddButton); if (m_heightAdaptive) { if (b) { q->setMinimumSize(550, TABLET_HEIGHT); q->setMaximumSize(16777215, TABLET_HEIGHT); } else { q->setMinimumSize(550, PC_HEIGHT); q->setMaximumSize(16777215, PC_HEIGHT); } } m_isTabletMode = b; Q_EMIT q->tabletModeChanged(b); } KAddButton::KAddButton(QWidget *parent, KBaseFrame::BorderRadiusStyle style, bool heightAdaptive) : QPushButton(parent) , d_ptr(new KAddButtonPrivate(this)) { Q_D(KAddButton); setObjectName("AddButton"); setProperty("useButtonPalette", true); setProperty("needTranslucent", true); setFlat(true); d->m_radiusType = style; d->m_heightAdaptive = heightAdaptive; d->m_statusSessionDbus = new QDBusInterface("com.kylin.statusmanager.interface", "/", "com.kylin.statusmanager.interface", QDBusConnection::sessionBus(), this); if (d->m_statusSessionDbus->isValid()) { QDBusReply is_tabletmode = d->m_statusSessionDbus->call("get_current_tabletmode"); d->mode_change_signal_slots(is_tabletmode.isValid() ? is_tabletmode.value() : false); connect(d->m_statusSessionDbus, SIGNAL(mode_change_signal(bool)), this, SLOT(mode_change_signal_slots(bool))); } else { d->mode_change_signal_slots(false); qWarning() << "Create com.kylin.statusmanager.interface Interface Failed When : " << QDBusConnection::systemBus().lastError(); } } KAddButton::~KAddButton() { } void KAddButton::setRadiusType(KBaseFrame::BorderRadiusStyle style) { Q_D(KAddButton); d->m_radiusType = style; update(); } bool KAddButton::getTabletMode() { Q_D(KAddButton); return d->m_isTabletMode; } void KAddButton::setHeightAdaptive(bool flag) { Q_D(KAddButton); d->m_heightAdaptive = flag; } void KAddButton::paintEvent(QPaintEvent *event) { Q_D(KAddButton); QPainter painter(this); painter.setRenderHint(QPainter::Antialiasing); // 反锯齿; painter.setClipping(true); painter.setPen(Qt::transparent); // painter.setBrush(qApp->palette().base()); painter.setBrush(ThemeController::getCustomColorFromDT("base-active")); QPainterPath painterPath = d->getPaintrPath(); painter.setClipPath(painterPath); painter.drawPath(painterPath); QPushButton::paintEvent(event); } QPainterPath KAddButtonPrivate::getPaintrPath() { Q_Q(KAddButton); const QRect rect = q->rect(); int radius = RADIUS_VALUE; int corner = 0; if (m_radiusType == KBaseFrame::BorderRadiusStyle::None) { corner = 0; } else if (m_radiusType == KBaseFrame::BorderRadiusStyle::Top) { corner = TOP_LEFT_CORNER + TOP_RIGHT_CORNER; } else if (m_radiusType == KBaseFrame::BorderRadiusStyle::Bottom) { corner = BOTTOM_LEFT_CORNER + BOTTOM_RIGHT_CORNER; } else { corner = TOP_LEFT_CORNER + TOP_RIGHT_CORNER + BOTTOM_LEFT_CORNER + BOTTOM_RIGHT_CORNER; } QPainterPath path; if (corner & TOP_LEFT_CORNER) { path.moveTo(rect.x() + radius, rect.y()); path.arcTo(rect.x(), rect.y(), radius * 2, radius * 2, 90.f, 90.f); // 画左上圆角 } else { path.moveTo(rect.x(), rect.y()); } if (corner & BOTTOM_LEFT_CORNER) { path.lineTo(rect.x(), rect.y() + rect.height() - radius); path.arcTo(rect.x(), rect.y() + rect.height() - radius * 2, radius * 2, radius * 2, 180.0f, 90.f); } else { path.lineTo(rect.x(), rect.y() + rect.height()); } if (corner & BOTTOM_RIGHT_CORNER) { path.lineTo(rect.x() + rect.width() - radius, rect.y() + rect.height()); path.arcTo(rect.x() + rect.width() - 2 * radius, rect.y() + rect.height() - 2 * radius, radius * 2, radius * 2, 270.0f, 90.f); } else { path.lineTo(rect.x() + rect.width(), rect.y() + rect.height()); } if (corner & TOP_RIGHT_CORNER) { path.lineTo(rect.x() + rect.width(), rect.y() + radius); path.arcTo(rect.x() + rect.width() - 2 * radius, rect.y(), radius * 2, radius * 2, 0.f, 90.f); } else { path.lineTo(rect.x() + rect.width(), rect.y()); } return path; } } #include "kaddbutton.moc" #include "moc_kaddbutton.cpp" libkysdk-applications/kysdk-qtwidgets/src/kborderlessbutton.h0000664000175000017500000000365315104543305023660 0ustar fengfeng/* * libkysdk-qtwidgets's Library * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #ifndef KBORDERLESSBUTTON_H #define KBORDERLESSBUTTON_H #include "gui_g.h" #include #include #include #include namespace kdk { /** @defgroup PushbuttonModule * @{ */ class KBorderlessButtonPrivate; /** * @brief 无边框按钮 * @since 1.0.0 */ class GUI_EXPORT KBorderlessButton : public QPushButton { Q_OBJECT public: KBorderlessButton(QWidget *parent = nullptr); KBorderlessButton(const QString &text, QWidget *parent = nullptr); KBorderlessButton(const QIcon &icon, const QString &text, QWidget *parent = nullptr); KBorderlessButton(const QIcon &icon, QWidget *parent = nullptr); ~KBorderlessButton(); /** * @brief 设置按钮图标 * @param icon */ void setIcon(const QIcon &icon); protected: bool eventFilter(QObject *watched, QEvent *event); void paintEvent(QPaintEvent *event); QSize sizeHint() const; private: KBorderlessButtonPrivate *const d_ptr; Q_DECLARE_PRIVATE(KBorderlessButton) Q_PRIVATE_SLOT(d_ptr, void changeTheme()) }; } /** * @example testPushbutton/widget.h * @example testPushbutton/widget.cpp * @} */ #endif libkysdk-applications/kysdk-qtwidgets/src/ktextedit.h0000664000175000017500000000353515104543305022111 0ustar fengfeng/* * libkysdk-qtwidgets's Library * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhenyu Wang * */ #ifndef KTEXTEDIT_H #define KTEXTEDIT_H #include "gui_g.h" #include "klabel.h" #include "ktag.h" #include #include namespace kdk { /** * @defgroup @DialogBoxModule * { */ class KTextEditPrivate; /** * @brief 继承QTextEdit * @since 2.4.1.0 */ class GUI_EXPORT KTextEdit : public QTextEdit { Q_OBJECT public: KTextEdit(QWidget *parent = nullptr); /** * @brief 设置label是否可见 * @param flag */ void setLabelVisible(bool flag); /** * @brief 设置图标 * @param pixmap */ void setPixmap(const QPixmap &pixmap); /** * @brief 获取图标 * @return */ const QPixmap *pixmap() const; /** * @brief 设置label文本 * @param text */ void setLabelText(const QString &text); /** * @brief 设置是否可编辑状态 * @param ro */ void setReadOnly(bool ro); protected: void paintEvent(QPaintEvent *event); private: Q_DECLARE_PRIVATE(KTextEdit) KTextEditPrivate *const d_ptr; }; } #endif // KTEXTEDIT_H libkysdk-applications/kysdk-qtwidgets/src/kcustomdateedit.h0000664000175000017500000000345415104543305023275 0ustar fengfeng/* * libkysdk-qtwidgets's Library * * Copyright (C) 2024, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #ifndef KCUSTOMDATEEDIT_H #define KCUSTOMDATEEDIT_H #include "gui_g.h" #include "kminicalendarwidget.h" #include #include namespace kdk { class KCustomDateEditPrivate; /** * @defgroup KCustomDateEdit * @since 2.5.2.0 */ class GUI_EXPORT KCustomDateEdit : public QDateTimeEdit { Q_OBJECT public: KCustomDateEdit(QWidget *parent = nullptr); /** * @brief 触发日历控件显示 */ void showCalendar(); /** * @brief 是否显示农历 * @param showLunar */ void setShowLunar(bool showLunar); /** * @brief 适应系统风格 * @param isDark:是否深色模式 */ void updateStyle(bool isDark); signals: void changeDate(); protected: void mousePressEvent(QMouseEvent *event) override; void paintEvent(QPaintEvent *e) override; bool eventFilter(QObject *obj, QEvent *event) override; private: Q_DECLARE_PRIVATE(KCustomDateEdit) KCustomDateEditPrivate *const d_ptr; }; } #endif // KCUSTOMDATEEDIT_H libkysdk-applications/kysdk-qtwidgets/src/kitemwidget.cpp0000664000175000017500000000752515104543305022757 0ustar fengfeng/* * libkysdk-qtwidgets's Library * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhenyu Wang * */ #include "kitemwidget.h" #include "klistwidget.h" #include #include #include namespace kdk { class KItemWidgetPrivate : public QObject, public ThemeController { Q_OBJECT Q_DECLARE_PUBLIC(KItemWidget) public: KItemWidgetPrivate(KItemWidget *parent); protected: void changeTheme(); private: KItemWidget *q_ptr; QIcon m_icon; QString m_maintext; QString m_sectext; QSize m_iconsize; QPixmap pixmap; int x; int y; KItemWidget *m_ltem; bool flag = false; }; KItemWidgetPrivate::KItemWidgetPrivate(KItemWidget *parent) : q_ptr(parent) { Q_Q(KItemWidget); setParent(parent); m_iconsize = QSize(35, 35); x = m_iconsize.width(); y = m_iconsize.height(); changeTheme(); connect(m_gsetting, &QGSettings::changed, this, &KItemWidgetPrivate::changeTheme); } void KItemWidgetPrivate::changeTheme() { Q_Q(KItemWidget); initThemeStyle(); } KItemWidget::KItemWidget(const QIcon &Myicon, QString MmainText, QString MsecText, QWidget *parent) : QWidget(parent) , d_ptr(new KItemWidgetPrivate(this)) { Q_D(KItemWidget); setMinimumSize(800, 800); d->pixmap = Myicon.pixmap(QSize(d->m_iconsize)); d->m_maintext = MmainText; d->m_sectext = MsecText; } void KItemWidget::SetInverse() { Q_D(KItemWidget); d->flag = true; update(); } void KItemWidget::CancelInverse() { Q_D(KItemWidget); d->flag = false; update(); } void KItemWidget::SetIconSize(QSize size) { Q_D(KItemWidget); d->m_iconsize = size; d->x = d->m_iconsize.width(); d->y = d->m_iconsize.height(); update(); } void KItemWidget::paintEvent(QPaintEvent *event) { Q_D(KItemWidget); QPainter painter(this); painter.drawPixmap(8, 10, d->x, d->y, d->pixmap); // 画图片 QFont font = painter.font(); font.setPointSize(10); // 设置字体 painter.setFont(font); if (ThemeController::themeMode() == LightTheme) // 判断主题 { if (d->flag) { painter.setPen(ThemeController::getCustomColorFromDT("kwhite")); // 白色 painter.drawText(QRect(52, 10, 1000, 16), d->m_maintext); // 画文本 } else { painter.setPen(QColor(54, 54, 54)); // 黑色 painter.drawText(QRect(52, 10, 1000, 16), d->m_maintext); // 画文本 } painter.setPen(QColor(150, 150, 150)); // 褐色 painter.drawText(QRect(52, 28, 1000, 16), d->m_sectext); } else if (ThemeController::themeMode() == DarkTheme) { painter.setPen(ThemeController::getCustomColorFromDT("kwhite")); // 白色 painter.drawText(QRect(52, 10, 1000, 16), d->m_maintext); // 画文本 painter.setPen(QColor(150, 150, 150)); // 褐色 painter.drawText(QRect(52, 28, 1000, 16), d->m_sectext); } painter.setRenderHint(QPainter::Antialiasing); /* 尽可能消除文本锯齿边缘 */ painter.setRenderHint(QPainter::TextAntialiasing); this->setContentsMargins(8, 10, 10, 5); // 边距 } } #include "kitemwidget.moc" #include "moc_kitemwidget.cpp" libkysdk-applications/kysdk-qtwidgets/src/kprogressbar.cpp0000664000175000017500000004415715104543305023150 0ustar fengfeng/* * libkysdk-qtwidgets's Library * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #include "kprogressbar.h" #include "themeController.h" #include #include #include #include #include #include #include #include namespace kdk { class KProgressBarPrivate : public QObject, public ThemeController { Q_OBJECT Q_DECLARE_PUBLIC(KProgressBar) public: KProgressBarPrivate(KProgressBar *parent); void calculateTextRect(); void calculateRect(); void calculateContenteRect(); void changeTheme(); int computeHardLightChannel(int base, int blend); QColor hardLight(QColor blendColor, QColor baseColor = Qt::white); Q_SIGNALS: void progressStateChanged(); private: KProgressBar *q_ptr; ProgressBarState m_state; int m_contentMargin; QRect m_textRect; QRect m_contentRect; QRect m_rect; int m_bodyWidth; QLinearGradient m_linearGradient; bool isLinearGradient; QColor m_color1; QColor m_color2; QColor m_backgroundColor; bool isBackgroundColor; QColor m_fillColor; bool isFillColor; QVariantAnimation *m_pAnimation; qreal m_animationPos; bool linearGradient; bool animationsFlag; }; KProgressBar::KProgressBar(QWidget *parent) : QProgressBar(parent) , d_ptr(new KProgressBarPrivate(this)) { Q_D(KProgressBar); d->changeTheme(); connect(d->m_gsetting, &QGSettings::changed, d, &KProgressBarPrivate::changeTheme); connect(this, &KProgressBar::valueChanged, this, [=]() { if (this->value() == this->maximum()) { setState(SuccessProgress); } }); connect(d->m_pAnimation, &QVariantAnimation::valueChanged, this, [=](const QVariant &value) { if (orientation() == Qt::Horizontal) d->m_animationPos = value.toDouble() / d->m_contentRect.width(); else { d->m_animationPos = (value.toDouble() - d->m_contentRect.top()) / d->m_contentRect.height(); } update(); }); setContentsMargins(6, 6, 6, 6); setValue(0); } ProgressBarState KProgressBar::state() { Q_D(KProgressBar); return d->m_state; } void KProgressBar::setState(ProgressBarState state) { Q_D(KProgressBar); d->m_state = state; if (d->animationsFlag && state == ProgressBarState::NormalProgress) { d->m_pAnimation->start(); } else { d->m_pAnimation->stop(); } update(); } void KProgressBar::paintEvent(QPaintEvent *event) { Q_D(KProgressBar); d->calculateTextRect(); d->calculateRect(); d->calculateContenteRect(); // 以上三个函数有逻辑关系,相对位置不能改变 QPainter painter(this); painter.setRenderHint(QPainter::Antialiasing); painter.setPen(Qt::NoPen); int radius = ThemeController::getRadiusFromDT("kradius-normal"); if (radius == -1) radius = 6; if (this->orientation() == Qt::Horizontal) { if (d->isBackgroundColor) painter.setBrush(d->m_backgroundColor); else painter.setBrush(ThemeController::getCustomColorFromDT("kcomponent-alpha-disable")); painter.setPen(ThemeController::getCustomColorFromDT("kline-component-normal")); painter.drawRoundedRect(d->m_rect, radius, radius); // QLinearGradient linear(this->rect().topLeft(), this->rect().bottomRight()); QLinearGradient linear(d->m_contentRect.left(), 0, d->m_contentRect.right(), 0); d->m_linearGradient = QLinearGradient(d->m_contentRect.topLeft(), d->m_contentRect.bottomRight()); QColor color = ThemeController::getCustomColorFromDT("highlight-active"); switch (d->m_state) { case NormalProgress: if (d->animationsFlag) { linear.setColorAt(0, color); linear.setColorAt(d->m_animationPos, d->hardLight(color)); linear.setColorAt(1, color); } else { QColor startColor; QColor endColor; ThemeController::getGradientFromDT("kbrand-normal",startColor,endColor); linear.setColorAt(0, startColor); linear.setColorAt(1, endColor); } linear.setSpread(QGradient::PadSpread); if (d->isLinearGradient) { if (!d->linearGradient) { d->m_color1 = ThemeController::mixColor(color, Qt::white, 0.2); d->m_color2 = ThemeController::mixColor(color, Qt::white, 0.05); } d->m_linearGradient.setColorAt(0, d->m_color1); d->m_linearGradient.setColorAt(1, d->m_color2); painter.setBrush(d->m_linearGradient); } else if (d->isFillColor) painter.setBrush(d->m_fillColor); else painter.setBrush(linear); painter.drawRoundedRect(d->m_contentRect, 6, 6); if (isTextVisible()) { painter.setPen(ThemeController::getCustomColorFromDT("kfont-primary")); painter.drawText(d->m_textRect, Qt::AlignCenter, text()); } break; case FailedProgress: { QColor startColor; QColor endColor; ThemeController::getGradientFromDT("kerror-normal",startColor,endColor); linear.setColorAt(0,startColor); linear.setColorAt(1,endColor); linear.setSpread(QGradient::PadSpread); painter.setBrush(linear); painter.drawRoundedRect(d->m_contentRect, 6, 6); if (isTextVisible()) { QPixmap pixmap = QIcon::fromTheme("dialog-error").pixmap(16, 16); QRect rect(0, 0, 16, 16); rect.moveCenter(d->m_textRect.center()); painter.drawPixmap(rect, pixmap); } break; } case SuccessProgress: { QColor startColor; QColor endColor; ThemeController::getGradientFromDT("ksuccess-normal",startColor,endColor); linear.setColorAt(0,startColor); linear.setColorAt(1,endColor); linear.setSpread(QGradient::PadSpread); painter.setBrush(linear); painter.drawRoundedRect(d->m_contentRect, 6, 6); if (isTextVisible()) { QPixmap pixmap = QIcon::fromTheme("ukui-dialog-success").pixmap(16, 16); QRect rect(0, 0, 16, 16); rect.moveCenter(d->m_textRect.center()); painter.drawPixmap(rect, pixmap); } break; } default: break; } } else { if (d->isBackgroundColor) painter.setBrush(d->m_backgroundColor); else { painter.setBrush(ThemeController::getCustomColorFromDT("kcomponent-alpha-disable")); } painter.setPen(ThemeController::getCustomColorFromDT("kline-component-normal")); painter.drawRoundedRect(d->m_rect, 6, 6); QLinearGradient linear(0, d->m_contentRect.top(), 0, d->m_contentRect.bottom()); d->m_linearGradient = QLinearGradient(d->m_contentRect.topLeft(), d->m_contentRect.bottomRight()); QColor color = ThemeController::getCustomColorFromDT("highlight-active"); switch (d->m_state) { case NormalProgress: if (d->animationsFlag) { linear.setColorAt(0, color); linear.setColorAt(d->m_animationPos, d->hardLight(color)); linear.setColorAt(1, color); } else { QColor startColor; QColor endColor; ThemeController::getGradientFromDT("kbrand-normal",startColor,endColor); linear.setColorAt(0, startColor); linear.setColorAt(1, endColor); } linear.setSpread(QGradient::PadSpread); if (d->isLinearGradient) { if (!d->linearGradient) { d->m_color1 = ThemeController::mixColor(color, Qt::white, 0.2); d->m_color2 = ThemeController::mixColor(color, Qt::white, 0.05); } d->m_linearGradient.setColorAt(0, d->m_color1); d->m_linearGradient.setColorAt(1, d->m_color2); painter.setBrush(d->m_linearGradient); } else if (d->isFillColor) painter.setBrush(d->m_fillColor); else painter.setBrush(linear); painter.drawRoundedRect(d->m_contentRect, 6, 6); if (isTextVisible()) { painter.setPen(ThemeController::getCustomColorFromDT("kfont-primary")); painter.drawText(d->m_textRect, Qt::AlignCenter, text()); } break; case FailedProgress: { QColor startColor; QColor endColor; ThemeController::getGradientFromDT("kerror-normal",startColor,endColor); linear.setColorAt(0,startColor); linear.setColorAt(1,endColor); linear.setSpread(QGradient::PadSpread); painter.setBrush(linear); painter.drawRoundedRect(d->m_contentRect, 6, 6); if (isTextVisible()) { QPixmap pixmap = QIcon::fromTheme("dialog-error").pixmap(16, 16); QRect rect(0, 0, 16, 16); rect.moveCenter(d->m_textRect.center()); painter.drawPixmap(rect, pixmap); } break; } case SuccessProgress: { QColor startColor; QColor endColor; ThemeController::getGradientFromDT("ksuccess-normal",startColor,endColor); linear.setColorAt(0,startColor); linear.setColorAt(1,endColor); linear.setSpread(QGradient::PadSpread); painter.setBrush(linear); painter.drawRoundedRect(d->m_contentRect, 6, 6); if (isTextVisible()) { QPixmap pixmap = QIcon::fromTheme("ukui-dialog-success").pixmap(16, 16); // painter.drawPixmap(d->m_textRect,pixmap); QRect rect(0, 0, 16, 16); rect.moveCenter(d->m_textRect.center()); painter.drawPixmap(rect, pixmap); } break; } default: break; } } } QSize KProgressBar::sizeHint() const { QSize size = QProgressBar::sizeHint(); if (this->orientation() == Qt::Horizontal) size.setHeight(30); else size.setWidth(30); return size; } QString KProgressBar::text() const { Q_D(const KProgressBar); if ((maximum() == 0 && minimum() == 0) || value() < minimum() || (minimum() == INT_MIN && minimum() == INT_MIN)) return QString(); qint64 totalSteps = qint64(maximum()) - minimum(); QString result = format(); QLocale locale = this->locale(); // Omit group separators for compatibility with previous versions that were non-localized. locale.setNumberOptions(locale.numberOptions() | QLocale::OmitGroupSeparator); result.replace(QLatin1String("%m"), locale.toString(totalSteps)); result.replace(QLatin1String("%v"), locale.toString(value())); // If max and min are equal and we get this far, it means that the // progress bar has one step and that we are on that step. Return // 100% here in order to avoid division by zero further down. if (totalSteps == 0) { result.replace(QLatin1String("%p"), locale.toString(100)); return result; } const auto progress = static_cast((qint64(value()) - minimum()) * 100.0 / totalSteps); result.replace(QLatin1String("%p"), locale.toString(progress)); return result; } void KProgressBar::setOrientation(Qt::Orientation orientation) { if (orientation == Qt::Vertical) this->setMinimumHeight(200); QProgressBar::setOrientation(orientation); } void KProgressBar::setBodyWidth(int width) { Q_D(KProgressBar); d->m_bodyWidth = width; update(); } void KProgressBar::setGradationColor(QColor color1, QColor color2) { Q_D(KProgressBar); d->linearGradient = true; d->m_color1 = color1; d->m_color2 = color2; } void KProgressBar::setBackgroundColor(QColor color) { Q_D(KProgressBar); d->m_backgroundColor = color; d->isBackgroundColor = true; } void KProgressBar::setFillColor(QColor color) { Q_D(KProgressBar); d->m_fillColor = color; d->isFillColor = true; } void KProgressBar::setGradation(bool flag) { Q_D(KProgressBar); d->isLinearGradient = flag; } bool KProgressBar::gradation() { Q_D(KProgressBar); return d->isLinearGradient; } void KProgressBar::setAnimation(bool flag) { Q_D(KProgressBar); d->animationsFlag = flag; if (!flag) { d->m_pAnimation->stop(); } else { d->m_pAnimation->start(); } } bool KProgressBar::animation() { Q_D(KProgressBar); return d->animationsFlag; } KProgressBarPrivate::KProgressBarPrivate(KProgressBar *parent) : q_ptr(parent) { Q_Q(KProgressBar); m_contentMargin = 2; m_state = NormalProgress; setParent(parent); m_bodyWidth = 0; isLinearGradient = false; isBackgroundColor = false; isFillColor = false; linearGradient = false; animationsFlag = false; m_animationPos = 0.00; m_pAnimation = new QVariantAnimation(); m_pAnimation->setDuration(1000); m_pAnimation->setEasingCurve(QEasingCurve::Linear); m_pAnimation->setLoopCount(-1); } void KProgressBarPrivate::calculateTextRect() { Q_Q(KProgressBar); if (!q->isTextVisible()) m_textRect = QRect(); else { QFont font(QApplication::font()); QFontMetrics fm(font); m_textRect = QRect(0, 0, fm.horizontalAdvance(q->text()), fm.height()); m_textRect.moveCenter(q->rect().center()); if (q->orientation() == Qt::Horizontal) { if (q->alignment() & Qt::AlignCenter) return; else { if (ThemeController::systemLang()) m_textRect.moveLeft(q->rect().left()); else m_textRect.moveRight(q->rect().right()); } } else { if (q->alignment() & Qt::AlignCenter) return; else m_textRect.moveTop(q->rect().top()); } } } void KProgressBarPrivate::calculateRect() // 背景矩形 { Q_Q(KProgressBar); QMargins margins = q->contentsMargins(); m_rect = q->rect(); if (q->orientation() == Qt::Horizontal) { if (m_bodyWidth != 0) m_rect.setHeight(m_bodyWidth); if (!q->isTextVisible()) return; else { m_rect.moveCenter(q->rect().center()); if (q->alignment() & Qt::AlignCenter) return; else { if (ThemeController::systemLang()) m_rect.setLeft(margins.right() + m_textRect.width() /*-gSpace*/); else m_rect.setRight(q->rect().width() - margins.right() - m_textRect.width() /*-gSpace*/); } } } else { if (m_bodyWidth != 0) m_rect.setWidth(m_bodyWidth); if (!q->isTextVisible()) return; else { m_rect.moveCenter(q->rect().center()); if (q->alignment() & Qt::AlignCenter) return; else { m_rect.setTop(margins.top() + m_textRect.height() /* + gSpace*/); } } } } void KProgressBarPrivate::calculateContenteRect() // 填充矩形 { Q_Q(KProgressBar); m_contentRect = m_rect; if (q->orientation() == Qt::Horizontal) { int width; qint64 totalSteps = qint64(q->maximum()) - q->minimum(); width = m_rect.width() * (q->value() - q->minimum()) / totalSteps; if (!width) { m_contentRect = QRect(); } // 没设置反方向的情况下,即普通情况下 if (!q->invertedAppearance()) { m_contentRect.setRight(width + m_rect.left()); } else { m_contentRect.setLeft(m_rect.width() - width); } m_pAnimation->setStartValue(m_contentRect.x()); m_pAnimation->setEndValue(m_contentRect.width()); } else { int height; qint64 totalSteps = q->maximum() - q->minimum(); height = m_rect.height() * (q->value() - q->minimum()) / totalSteps; if (!height) { m_contentRect = QRect(); } // 没设置反方向的情况下,即普通情况下 if (!q->invertedAppearance()) { m_contentRect.setTop(m_rect.top() + m_rect.height() - height); } else { m_contentRect.setBottom(m_rect.top() + height); } m_pAnimation->setStartValue(m_contentRect.bottom()); m_pAnimation->setEndValue(m_contentRect.top()); } } void KProgressBarPrivate::changeTheme() { Q_Q(KProgressBar); initThemeStyle(); q->repaint(); } int KProgressBarPrivate::computeHardLightChannel(int base, int blend) { if (blend <= 128) { return (base * blend) / 128; } return 255 - ((255 - blend) * (255 - base)) / 128; } QColor KProgressBarPrivate::hardLight(QColor blendColor, QColor baseColor) { int r = computeHardLightChannel(baseColor.red(), blendColor.red()); int g = computeHardLightChannel(baseColor.green(), blendColor.green()); int b = computeHardLightChannel(baseColor.blue(), blendColor.blue()); return QColor(r, g, b, blendColor.alpha()); } } #include "kprogressbar.moc" #include "moc_kprogressbar.cpp" libkysdk-applications/kysdk-qtwidgets/src/kbackgroundgroup.cpp0000664000175000017500000004100415104543305023777 0ustar fengfeng/* * libkysdk-qtwidgets's Library * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #include "kbackgroundgroup.h" #include "klineframe.h" #include "themeController.h" #include #include #include #include namespace kdk { class KBackgroundGroupPrivate : public QObject, public ThemeController { Q_OBJECT Q_DECLARE_PUBLIC(KBackgroundGroup) public: enum WidgetPosition { Beginning, Middle, End }; KBackgroundGroupPrivate(KBackgroundGroup *parent); void updateLayout(); void updateVisibleLayout(); private: KBackgroundGroup *q_ptr; QVBoxLayout *m_pmainWidgetLayout; QList m_pwidgetList; QList m_pwidgetStateList; QList m_pwidgetVisibleList; QList m_pFrameList; QPalette::ColorRole m_brushColorRole; QColor m_backgroundColor; WidgetPosition m_widgetPosition; QRect m_rect; int m_rectLocal; int m_radius; bool m_borderVisble; }; KBackgroundGroup::KBackgroundGroup(QWidget *parent) : QFrame(parent) , d_ptr(new KBackgroundGroupPrivate(this)) { Q_D(KBackgroundGroup); setFrameShape(QFrame::Box); setFrameShadow(QFrame::Plain); setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); connect(d->m_gsetting, &QGSettings::changed, this, [=] { d->initThemeStyle(); d->m_backgroundColor = palette().color(d->m_brushColorRole); }); } void KBackgroundGroup::addWidget(QWidget *widget) { Q_D(KBackgroundGroup); widget->installEventFilter(this); if (widget->maximumHeight() != widget->minimumHeight()) widget->setFixedHeight(60); if (!d->m_pwidgetList.contains(widget)) d->m_pwidgetList.append(widget); else return; d->updateLayout(); } void KBackgroundGroup::addWidgetList(QList list) { Q_D(KBackgroundGroup); for (int i = 0; i < list.count(); i++) { auto widget = list.at(i); widget->installEventFilter(this); if (widget->maximumHeight() != widget->minimumHeight()) widget->setFixedHeight(60); if (!d->m_pwidgetList.contains(list.at(i))) d->m_pwidgetList.append(list.at(i)); else continue; } d->updateLayout(); } void KBackgroundGroup::removeWidgetAt(int i) { Q_D(KBackgroundGroup); if (d->m_pwidgetList.contains(d->m_pwidgetList.at(i))) d->m_pwidgetList.removeAt(i); else return; d->updateLayout(); } void KBackgroundGroup::removeWidget(QWidget *widget) { Q_D(KBackgroundGroup); if (d->m_pwidgetList.contains(widget)) d->m_pwidgetList.removeOne(widget); else return; d->updateLayout(); } void KBackgroundGroup::removeWidgetList(QList list) { Q_D(KBackgroundGroup); for (int i = 0; i < list.count(); i++) { if (d->m_pwidgetList.contains(list.at(i))) d->m_pwidgetList.removeOne(list.at(i)); else continue; } d->updateLayout(); } void KBackgroundGroup::insertWidgetAt(int index, QWidget *widget) { Q_D(KBackgroundGroup); widget->installEventFilter(this); if(widget->maximumHeight() != widget->minimumHeight()) widget->setFixedHeight(60); if (!d->m_pwidgetList.contains(widget)) d->m_pwidgetList.insert(index, widget); else return; d->updateLayout(); } void KBackgroundGroup::insertWidgetList(int index, QList list) { Q_D(KBackgroundGroup); for (int i = 0; i < list.count(); i++) { auto widget = list.at(i); widget->installEventFilter(this); if (widget->maximumHeight() != widget->minimumHeight()) widget->setFixedHeight(60); if (!d->m_pwidgetList.contains(list.at(i))) d->m_pwidgetList.insert(index++, list.at(i)); else continue; } d->updateLayout(); } void KBackgroundGroup::setBorderRadius(int radius) { Q_D(KBackgroundGroup); d->m_radius = radius; } int KBackgroundGroup::borderRadius() { Q_D(KBackgroundGroup); return d->m_radius; } void KBackgroundGroup::setBackgroundRole(QPalette::ColorRole role) { Q_D(KBackgroundGroup); d->m_brushColorRole = role; d->m_backgroundColor = palette().color(role); } QPalette::ColorRole KBackgroundGroup::backgroundRole() const { Q_D(const KBackgroundGroup); return d->m_brushColorRole; } void KBackgroundGroup::setStateEnable(QWidget *widget, bool flag) { Q_D(KBackgroundGroup); if (!d->m_pwidgetStateList.contains(widget) && flag) { d->m_pwidgetStateList.append(widget); widget->installEventFilter(this); widget->setAttribute(Qt::WA_TranslucentBackground); } else if (d->m_pwidgetStateList.contains(widget) && !flag) { d->m_pwidgetStateList.removeOne(widget); } } QList KBackgroundGroup::widgetList() { Q_D(KBackgroundGroup); return d->m_pwidgetList; } void KBackgroundGroup::setBorderVisible(bool flag) { Q_D(KBackgroundGroup); d->m_borderVisble = flag; } void KBackgroundGroup::paintEvent(QPaintEvent *event) { Q_D(KBackgroundGroup); // 绘制backgroundgroup QRect rect =this->rect().adjusted(1,1,0,0); QPainter painter(this); painter.setRenderHint(QPainter::Antialiasing); QPen pen; pen.setWidth(1); if(d->m_borderVisble) { QColor borderColor; if(ThemeController::themeMode() == LightTheme) { borderColor = ThemeController::mixColor(Qt::gray,Qt::white,0.1); borderColor.setAlphaF(0.2); } else { borderColor =ThemeController::mixColor(Qt::gray,Qt::white,0.1); borderColor.setAlphaF(0.3); } pen.setColor(borderColor); } else pen.setColor(Qt::transparent); painter.setPen(pen); painter.setBrush(palette().color(d->m_brushColorRole)); QPainterPath path; path.moveTo(rect.topLeft() + QPointF(d->m_radius, 0)); path.quadTo(rect.topLeft(), rect.topLeft() + QPointF(0, d->m_radius)); path.lineTo(rect.bottomLeft() - QPointF(0, d->m_radius)); path.quadTo(rect.bottomLeft(), rect.bottomLeft() + QPointF(d->m_radius, 0)); path.lineTo(rect.bottomRight() - QPointF(d->m_radius, 0)); path.quadTo(rect.bottomRight(), rect.bottomRight() - QPointF(0, d->m_radius)); path.lineTo(rect.topRight() + QPointF(0, d->m_radius)); path.quadTo(rect.topRight(), rect.topRight() - QPointF(d->m_radius, 0)); path.lineTo(rect.topLeft() + QPointF(d->m_radius, 0)); painter.drawPath(path); // 三态事件响应颜色 painter.save(); painter.setBrush(d->m_backgroundColor); painter.setRenderHint(QPainter::Antialiasing); painter.setPen(Qt::transparent); // 确定三态区域 int index, offset = 0; if (d->m_pwidgetStateList.count() > 0) { for (index = 0; index < d->m_pwidgetList.count(); index++) { auto widget = d->m_pwidgetList.at(index); if( widget != d->m_pwidgetStateList.at(d->m_rectLocal)) offset = /*offset +*/ d->m_pwidgetList.at(index)->height()*( d->m_pwidgetVisibleList.indexOf(d->m_pwidgetStateList.at(d->m_rectLocal))); else break; } d->m_rect = d->m_rect.translated(0, offset + d->m_pwidgetList.indexOf(d->m_pwidgetStateList.at(d->m_rectLocal)) * 1); if(d->m_borderVisble) d->m_rect = d->m_rect.adjusted(2,1,0,0); else d->m_rect = d->m_rect.adjusted(0,-1,1,0); } // 三态区域颜色调整 QPainterPath path1; if (d->m_pwidgetList.count() == 1 && d->m_pwidgetStateList.count() == 1) { painter.drawRoundedRect(d->m_rect, d->m_radius, d->m_radius); } else if (d->m_pwidgetList.count() > 1 && d->m_pwidgetStateList.count() > 1) { if(d->m_pwidgetVisibleList.count() == 1) { painter.drawRoundedRect(d->m_rect,d->m_radius,d->m_radius); } else { switch (d->m_widgetPosition) { case KBackgroundGroupPrivate::Beginning: path1.moveTo(d->m_rect.topLeft() + QPointF(0, d->m_radius)); path1.lineTo(d->m_rect.bottomLeft()); path1.lineTo(d->m_rect.bottomRight()); path1.lineTo(d->m_rect.topRight() + QPointF(0, d->m_radius)); path1.quadTo(d->m_rect.topRight(), d->m_rect.topRight() - QPointF(d->m_radius, 0)); path1.lineTo(d->m_rect.topLeft() + QPointF(d->m_radius, 0)); path1.quadTo(d->m_rect.topLeft(), d->m_rect.topLeft() + QPointF(0, d->m_radius)); painter.drawPath(path1); break; case KBackgroundGroupPrivate::Middle: painter.drawRoundedRect(d->m_rect, 0, 0); break; case KBackgroundGroupPrivate::End: d->m_rect = d->m_rect.adjusted(1,-1,2,2); path1.moveTo(d->m_rect.topLeft()); path1.lineTo(d->m_rect.bottomLeft() - QPointF(0, d->m_radius)); path1.quadTo(d->m_rect.bottomLeft(), d->m_rect.bottomLeft() + QPointF(d->m_radius, 0)); path1.lineTo(d->m_rect.bottomRight() - QPointF(d->m_radius, 0)); path1.quadTo(d->m_rect.bottomRight(), d->m_rect.bottomRight() - QPointF(0, d->m_radius)); path1.lineTo(d->m_rect.topRight()); path1.lineTo(d->m_rect.topLeft()); painter.drawPath(path1); break; default: break; } } } painter.restore(); } bool KBackgroundGroup::eventFilter(QObject *watched, QEvent *event) { Q_D(KBackgroundGroup); auto widget = static_cast(watched); if (d->m_pwidgetStateList.contains(widget)) { // 事件过滤器判断事件设置颜色 switch (event->type()) { case QEvent::Enter: d->m_rect = widget->rect(); d->m_backgroundColor = ThemeController::getCustomColorFromDT("kgray-3");//kcontain-hover 不可用看配置文件用kgray-3替代 if (d->m_pwidgetVisibleList.at(0) == widget) d->m_widgetPosition = KBackgroundGroupPrivate::Beginning; else if(d->m_pwidgetVisibleList.at(d->m_pwidgetVisibleList.count()-1) == widget) d->m_widgetPosition = KBackgroundGroupPrivate::End; else d->m_widgetPosition = KBackgroundGroupPrivate::Middle; d->m_rectLocal = d->m_pwidgetStateList.indexOf(widget); update(); break; case QEvent::MouseButtonPress: d->m_rect = widget->rect(); d->m_backgroundColor = ThemeController::getCustomColorFromDT("kgray-4"); if (d->m_pwidgetVisibleList.at(0) == widget) d->m_widgetPosition = KBackgroundGroupPrivate::Beginning; else if (d->m_pwidgetVisibleList.at(d->m_pwidgetVisibleList.count() - 1) == widget) d->m_widgetPosition = KBackgroundGroupPrivate::End; else d->m_widgetPosition = KBackgroundGroupPrivate::Middle; d->m_rectLocal = d->m_pwidgetStateList.indexOf(widget); update(); break; case QEvent::MouseButtonRelease: { d->m_rect = widget->rect(); d->m_backgroundColor = ThemeController::getCustomColorFromDT("kgray-3"); if (d->m_pwidgetVisibleList.at(0) == widget) d->m_widgetPosition = KBackgroundGroupPrivate::Beginning; else if (d->m_pwidgetVisibleList.at(d->m_pwidgetVisibleList.count() - 1) == widget) d->m_widgetPosition = KBackgroundGroupPrivate::End; else d->m_widgetPosition = KBackgroundGroupPrivate::Middle; Q_EMIT clicked(widget); d->m_rectLocal = d->m_pwidgetStateList.indexOf(widget); update(); break; } case QEvent::Leave: d->m_rect = widget->rect(); d->m_backgroundColor = palette().color(d->m_brushColorRole); if (d->m_pwidgetVisibleList.at(0) == widget) d->m_widgetPosition = KBackgroundGroupPrivate::Beginning; else if (d->m_pwidgetVisibleList.at(d->m_pwidgetVisibleList.count() - 1) == widget) d->m_widgetPosition = KBackgroundGroupPrivate::End; else d->m_widgetPosition = KBackgroundGroupPrivate::Middle; d->m_rectLocal = d->m_pwidgetStateList.indexOf(widget); update(); break; case QEvent::Paint: d->m_rect = widget->rect(); break; case QEvent::Show: d->updateVisibleLayout(); break; case QEvent::Hide: d->updateVisibleLayout(); break; default: break; } } else { switch (event->type()) { case QEvent::Show: d->updateVisibleLayout(); break; case QEvent::Hide: d->updateVisibleLayout(); break; default: break; } } return QObject::eventFilter(watched,event); } KBackgroundGroupPrivate::KBackgroundGroupPrivate(KBackgroundGroup *parent) :q_ptr(parent) ,m_widgetPosition(KBackgroundGroupPrivate::Beginning),m_rectLocal(0) ,m_radius(12) ,m_brushColorRole(QPalette::Base) ,m_backgroundColor(parent->palette().color(m_brushColorRole)) ,m_borderVisble(false) { Q_Q(KBackgroundGroup); m_pmainWidgetLayout = new QVBoxLayout(q); m_pmainWidgetLayout->setContentsMargins(0, 0, 0, 0); m_pmainWidgetLayout->setSpacing(0); int radius = ThemeController::getRadiusFromDT("kradius-window"); if (radius == -1) m_radius = 12; else m_radius = radius; // q->setFocus(Qt::MouseFocusReason); connect(m_gsetting, &QGSettings::changed, this, [=]() { initThemeStyle(); }); } void KBackgroundGroupPrivate::updateLayout() { Q_Q(KBackgroundGroup); // 清空 m_pwidgetVisibleList = m_pwidgetList; QLayoutItem *child; while ((child = m_pmainWidgetLayout->takeAt(0)) != 0) { // 删除Stretch(弹簧)等布局 if (child->spacerItem()) { m_pmainWidgetLayout->removeItem(child); continue; } // 删除布局 m_pmainWidgetLayout->removeWidget(child->widget()); child->widget()->setParent(nullptr); delete child; child = nullptr; } m_pFrameList.clear(); // 添加布局 if (m_pwidgetList.count() < 1) return; else if (m_pwidgetList.count() == 1) { m_pmainWidgetLayout->addWidget(m_pwidgetList.at(0)); } else { for (int i = 0; i < m_pwidgetList.count(); ++i) { m_pmainWidgetLayout->addWidget(m_pwidgetList.at(i)); if (i != m_pwidgetList.count() - 1) { KHLineFrame *frame = new KHLineFrame(); m_pFrameList.append(frame); m_pmainWidgetLayout->addWidget(frame); } } } } void KBackgroundGroupPrivate::updateVisibleLayout() { QList visibleIndices; m_pwidgetVisibleList.clear(); for(auto widget : m_pwidgetList) { if(widget->isVisible()) m_pwidgetVisibleList.append(widget); } for (int i = 0; i < m_pwidgetList.size(); ++i) { if (m_pwidgetList[i]->isVisible()) { visibleIndices.append(i); } } if (visibleIndices.size() <= 1) { for (auto frame : m_pFrameList) { frame->setVisible(false); } return; } for (auto frame : m_pFrameList) { frame->setVisible(false); } for (int i = 0; i < visibleIndices.size() - 1; ++i) { int index = visibleIndices[i]; if (index >= 0 && index < m_pFrameList.size()) { m_pFrameList[index]->setVisible(true); } } } } #include "kbackgroundgroup.moc" #include "moc_kbackgroundgroup.cpp" libkysdk-applications/kysdk-qtwidgets/src/klistviewdelegate.cpp0000664000175000017500000002407015104543305024150 0ustar fengfeng/* * libkysdk-qtwidgets's Library * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhenyu Wang * */ #include "klistviewdelegate.h" #include "themeController.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace kdk { class KListViewDelegatePrivate : public QObject, public ThemeController { Q_OBJECT Q_DECLARE_PUBLIC(KListViewDelegate) public: KListViewDelegatePrivate(KListViewDelegate *parent); ~KListViewDelegatePrivate(); private: KListViewDelegate *q_ptr; QAbstractItemView *m_listView; }; KListViewDelegatePrivate::KListViewDelegatePrivate(KListViewDelegate *parent) : q_ptr(parent) { Q_Q(KListViewDelegate); initThemeStyle(); connect(m_gsetting, &QGSettings::changed, this, [=]() { initThemeStyle(); }); } KListViewDelegatePrivate::~KListViewDelegatePrivate() { } KListViewDelegate::KListViewDelegate(QAbstractItemView *parent) : QStyledItemDelegate(parent) , d_ptr(new KListViewDelegatePrivate(this)) { Q_D(KListViewDelegate); d->m_listView = parent; } KListViewDelegate::~KListViewDelegate() { } void KListViewDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const { Q_D(const KListViewDelegate); QFont font; font = QApplication::font(); QFontMetrics fm(font); int height = fm.height(); if (index.isValid()) { QListView *view = dynamic_cast(d->m_listView); if (!view) return; if (view->viewMode() == QListView::ListMode) { QRectF rect; rect.setX(option.rect.x()); rect.setY(option.rect.y()); rect.setWidth(option.rect.width()); rect.setHeight(option.rect.height()); // QPainterPath画圆角矩形 qreal radius = ThemeController::getRadiusFromDT("kradius-min"); if (radius == -1) radius = 4; QLinearGradient m_linearGradient = QLinearGradient(rect.width() / 2, rect.y(), rect.width() / 2, rect.height() + rect.y()); QColor startColor; QColor endColor; QPainterPath path; path.moveTo(rect.topRight() - QPointF(radius, 0)); path.lineTo(rect.topLeft() + QPointF(radius, 0)); path.quadTo(rect.topLeft(), rect.topLeft() + QPointF(0, radius)); path.lineTo(rect.bottomLeft() + QPointF(0, -radius)); path.quadTo(rect.bottomLeft(), rect.bottomLeft() + QPointF(radius, 0)); path.lineTo(rect.bottomRight() - QPointF(radius, 0)); path.quadTo(rect.bottomRight(), rect.bottomRight() + QPointF(0, -radius)); path.lineTo(rect.topRight() + QPointF(0, radius)); path.quadTo(rect.topRight(), rect.topRight() + QPointF(-radius, -0)); QString mainText = index.data(Qt::DisplayRole).toString(); // 获取主文本和副文本 QString subText = index.data(Qt::UserRole).toString(); if (subText.isNull()) { auto *model = dynamic_cast(const_cast(index.model())); // 获取图标 QIcon icon = model->item(index.row())->icon(); QRect iconRect = QRect(rect.left() + 8, rect.top() + 10, d->m_listView->iconSize().width() + (height - 23) * 2, d->m_listView->iconSize().height() + (height - 23) * 2); // 绘制图标的位置 QRect mainTextRect = QRect(iconRect.right() + 8, rect.top() + 10 + iconRect.height() / 2 - height / 2, rect.width(), height); // 绘制文本的位置 painter->save(); // item可选中 (单选) if (option.state.testFlag(QStyle::State_MouseOver) && !(option.state.testFlag(QStyle::State_Selected))) { ThemeController::getGradientFromDT("kcontain-hover",startColor,endColor); m_linearGradient.setColorAt(0,startColor); m_linearGradient.setColorAt(1,endColor); painter->setPen(QPen(Qt::NoPen)); painter->setBrush(m_linearGradient); painter->drawPath(path); } else if (option.state.testFlag(QStyle::State_MouseOver) && (option.state.testFlag(QStyle::State_Selected))) { ThemeController::getGradientFromDT("kcomponent-hover",startColor,endColor); m_linearGradient.setColorAt(0,startColor); m_linearGradient.setColorAt(1,endColor); painter->setPen(QPen(Qt::NoPen)); painter->setBrush(m_linearGradient); painter->drawPath(path); } else if (option.state.testFlag(QStyle::State_Selected)) { ThemeController::getGradientFromDT("kcomponent-normal",startColor,endColor); m_linearGradient.setColorAt(0,startColor); m_linearGradient.setColorAt(1,endColor); painter->setPen(QPen(Qt::NoPen)); painter->setBrush(m_linearGradient); painter->drawPath(path); } QPixmap pixmap = icon.pixmap(d->m_listView->iconSize().width() + (height - 23) * 2, d->m_listView->iconSize().width() + (height - 23) * 2); painter->drawPixmap(iconRect, pixmap); // 点击反白效果,画icon和text painter->setPen(ThemeController::getCustomColorFromDT("kfont-primary")); painter->drawText(mainTextRect, mainText); painter->restore(); } else { auto *model = dynamic_cast(const_cast(index.model())); // 获取图标 QIcon icon = model->item(index.row())->icon(); QRect iconRect = QRect(rect.left() + 8, rect.top() + 10, d->m_listView->iconSize().width() + (height - 23) * 2, d->m_listView->iconSize().height() + (height - 23) * 2); // 绘制图标的位置 QRect mainTextRect = QRect(iconRect.right() + 8, rect.top() + 5, rect.width(), height); // 绘制两个文本的位置 QRect subTextRect = QRect(iconRect.right() + 8, rect.bottom() - 5 - height, rect.width(), height); painter->save(); // item可选中 (单选) if (option.state.testFlag(QStyle::State_MouseOver) && !(option.state.testFlag(QStyle::State_Selected))) { ThemeController::getGradientFromDT("kcontain-hover",startColor,endColor); m_linearGradient.setColorAt(0,startColor); m_linearGradient.setColorAt(1,endColor); painter->setPen(QPen(Qt::NoPen)); painter->setBrush(m_linearGradient); painter->drawPath(path); } else if (option.state.testFlag(QStyle::State_MouseOver) && (option.state.testFlag(QStyle::State_Selected))) { ThemeController::getGradientFromDT("kcomponent-hover",startColor,endColor); m_linearGradient.setColorAt(0,startColor); m_linearGradient.setColorAt(1,endColor); painter->setPen(QPen(Qt::NoPen)); painter->setBrush(m_linearGradient); painter->drawPath(path); } else if (option.state.testFlag(QStyle::State_Selected)) { ThemeController::getGradientFromDT("kcomponent-normal",startColor,endColor); m_linearGradient.setColorAt(0,startColor); m_linearGradient.setColorAt(1,endColor); painter->setPen(QPen(Qt::NoPen)); painter->setBrush(m_linearGradient); painter->drawPath(path); } // icon.paint(painter,iconRect); QPixmap pixmap = icon.pixmap(QSize(d->m_listView->iconSize().width() + (height - 23) * 2, d->m_listView->iconSize().height() + (height - 23) * 2)); painter->drawPixmap(iconRect, pixmap); // 点击反白效果,画icon和text painter->setPen(ThemeController::getCustomColorFromDT("kfont-primary")); painter->drawText(mainTextRect, mainText); painter->setPen(ThemeController::getCustomColorFromDT("kfont-secondary")); painter->drawText(subTextRect, subText); painter->restore(); } } else if (view->viewMode() == QListView::IconMode) { QStyleOptionViewItem styleOptionViewItem(option); // 定义 initStyleOption(&styleOptionViewItem, index); // 初始化 QStyle *pStyle = styleOptionViewItem.widget->style(); pStyle->drawControl(QStyle::CE_ItemViewItem, &styleOptionViewItem, painter, styleOptionViewItem.widget); } } } QSize KListViewDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const { Q_D(const KListViewDelegate); QFont font; // 获取系统字体大小 font = QApplication::font(); QFontMetrics fm(font); int height = fm.height(); return QSize(option.rect.width(), height * 2 + 6); } } #include "klistviewdelegate.moc" #include "moc_klistviewdelegate.cpp" libkysdk-applications/kysdk-qtwidgets/src/ksecurityquestiondialog.h0000664000175000017500000000756715104543305025107 0ustar fengfeng/* * libkysdk-qtwidgets's Library * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: SiSheng He * */ #ifndef KSECURITYQUESTIONDIALOG_H #define KSECURITYQUESTIONDIALOG_H #include "gui_g.h" #include "kdialog.h" #include "kpushbutton.h" #include #include #include #include namespace kdk { class KSecurityQuestionDialogPrivate; /** * @brief 继承自 KDialog, * @since 2.4.1.0 */ class GUI_EXPORT KSecurityQuestionDialog : public KDialog { Q_OBJECT public: explicit KSecurityQuestionDialog(QWidget *parent = nullptr); ~KSecurityQuestionDialog(); /** * @brief 设置对话框标题 * * @param text 标题 */ void setTitleText(const QString &text); /** * @brief 添加安全问题控件 *Label combox *Label lineedit * tipsLabel * @param count 控件个数 * @param mutex 是否开启下拉框互斥校验,若开启后,已被选择项,在其他下拉框中被置灰 */ void addSecurityQuestionItem(const int count, bool mutex); /** * @brief 添加安全问题控件 *Label combox/lineedit *Label lineedit * tipsLabel * @param count 控件个数 * @param mutex 是否开启下拉框互斥校验,若开启后,已被选择项,在其他下拉框中被置灰 * @param isVerify 是否为校验窗口 */ void addSecurityQuestionItem(const int count, bool mutex, bool isVerify); /** * @brief 添加下拉框选项列表 * * @param questionlist */ void initQustionCombox(const QStringList &questionlist); /** * @brief 获取下拉框左侧Label * * @param questionIndex item索引 [0,count) * @return QLabel 下拉框左侧Label,若未获取到,返回nullptr */ QLabel *questionLabel(const int questionIndex); /** * @brief 获取combox * * @param questionIndex item索引 [0,count) * @return QComboBox 下拉框,若未获取到,返回nullptr */ QComboBox *questionCombox(const int questionIndex); /** * @brief 获取lineedit左侧label * * @param answerIndex item索引 [0,count) * @return QLabel lineedit左侧label,若未获取到,返回nullptr */ QLabel *answerLabel(const int answerIndex); /** * @brief 获取 lineedit * * @param answerIndex item索引 [0,count) * @return QLineEdit lineedit,若未获取到,返回nullptr */ QLineEdit *answerLineedit(const int answerIndex); /** * @brief 获取提示 label * * @param index item 索引 [0,count) * @return QLabel 提示label,若未获取到,返回nullptr */ QLabel *tipsLabel(const int index); /** * @brief 获取取消按钮 * * @return KPushButton */ KPushButton *cancelButton(); /** * @brief 获取确认按钮 * * @return KPushButton */ KPushButton *confirmButton(); protected: void keyPressEvent(QKeyEvent *); private: Q_DECLARE_PRIVATE(KSecurityQuestionDialog) KSecurityQuestionDialogPrivate *const d_ptr; }; } /** * @example testsecurityquestiondialog/main.cpp * @} */ #endif // KSECURITYQUESTIONDIALOG_H libkysdk-applications/kysdk-qtwidgets/src/kswitchbutton.cpp0000664000175000017500000003275215104543305023352 0ustar fengfeng/* * libkysdk-qtwidgets's Library * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #include "kswitchbutton.h" #include "themeController.h" #include #include #include #include #include #include #include namespace kdk { class KSwitchButtonPrivate : public QObject, public ThemeController { Q_OBJECT Q_DECLARE_PUBLIC(KSwitchButton) public: KSwitchButtonPrivate(KSwitchButton *parent) : q_ptr(parent) , m_animation(new QVariantAnimation(parent)) { setParent(parent); m_animation->setDuration(200); m_animation->setStartValue(0.0); m_animation->setEndValue(1.0); m_animation->setEasingCurve(QEasingCurve::Linear); m_animation->setLoopCount(1); } protected: void changeTheme(); private: KSwitchButton *q_ptr; QVariantAnimation *m_animation; int m_space; // 滑块离背景间隔 int m_rectRadius; // 圆角角度 int m_startX; // 滑块开始X轴坐标 int m_endX; // 滑块结束X轴坐标 QColor m_sliderColor; QColor m_bkgStartColor; QColor m_bkgEndColor; QColor m_borderColor; bool m_isHoverd; bool m_isTranslucent; bool m_isTranslucentFlag; QLinearGradient m_linearGradient; void updateColor(const QStyleOptionButton &opt); void drawBackground(QPainter *painter); void drawSlider(QPainter *painter); void stepChanged(); }; KSwitchButton::KSwitchButton(QWidget *parent) : QPushButton(parent) , d_ptr(new KSwitchButtonPrivate(this)) { Q_D(KSwitchButton); d->m_isHoverd = false; d->m_isTranslucent = false; d->m_isTranslucentFlag = false; this->setCheckable(true); d->changeTheme(); connect(d->m_gsetting, &QGSettings::changed, d, &KSwitchButtonPrivate::changeTheme); connect(d->m_animation, &QVariantAnimation::valueChanged, d, &KSwitchButtonPrivate::stepChanged); connect(this, &KSwitchButton::toggled, this, [=](bool flag) { d->m_endX = width() > height() ? width() - height() : 0; d->m_animation->start(); Q_EMIT stateChanged(flag); }); d->m_space = 4; } KSwitchButton::~KSwitchButton() { } void KSwitchButton::setCheckable(bool flag) { QPushButton::setCheckable(flag); this->update(); } bool KSwitchButton::isCheckable() const { return QPushButton::isCheckable(); } bool KSwitchButton::isChecked() const { return QPushButton::isChecked(); } void KSwitchButton::setChecked(bool flag) { Q_D(KSwitchButton); QPushButton::setChecked(flag); if (signalsBlocked()) { d->m_animation->start(); } this->update(); } void KSwitchButton::setTranslucent(bool flag) { Q_D(KSwitchButton); d->m_isTranslucentFlag = flag; d->m_isTranslucent = flag; d->changeTheme(); } bool KSwitchButton::isTranslucent() { Q_D(KSwitchButton); return d->m_isTranslucent; } void KSwitchButton::paintEvent(QPaintEvent *event) { Q_D(KSwitchButton); d->m_linearGradient = QLinearGradient(this->width() / 2, 0, this->width() / 2, this->height()); QStyleOptionButton opt; initStyleOption(&opt); QPainter painter(this); painter.setRenderHint(QPainter::Antialiasing); d->updateColor(opt); d->drawBackground(&painter); d->drawSlider(&painter); painter.drawText(0, 0, width(), height(), Qt::AlignCenter, text()); } void KSwitchButton::resizeEvent(QResizeEvent *event) { Q_D(KSwitchButton); QPushButton::resizeEvent(event); if (this->isChecked()) d->m_startX = width() > height() ? width() - height() : 0; else d->m_startX = 0; d->m_rectRadius = height() / 2; d->m_endX = width() > height() ? width() - height() : 0; } QSize KSwitchButton::sizeHint() const { return QSize(50, 24); } void KSwitchButtonPrivate::changeTheme() { Q_Q(KSwitchButton); if (m_isTranslucentFlag) { if (ThemeController::widgetTheme() == ClassicTheme) m_isTranslucent = false; else m_isTranslucent = true; } else { m_isTranslucent = false; } initThemeStyle(); q->update(); } void KSwitchButtonPrivate::updateColor(const QStyleOptionButton &opt) { Q_Q(KSwitchButton); // 根据option状态去指定以下两个子部件的颜色 // m_sliderColor // m_linearGradient if(q->isChecked()) { ThemeController::getGradientFromDT("kbrand-normal",m_bkgStartColor,m_bkgEndColor); m_linearGradient.setColorAt(0,m_bkgStartColor); m_linearGradient.setColorAt(1,m_bkgEndColor); m_borderColor = ThemeController::getCustomColorFromDT("kline-component-normal"); m_sliderColor = ThemeController::getCustomColorFromDT("kfont-white"); if (!opt.state.testFlag(QStyle::State_Enabled)) // disable { m_sliderColor = ThemeController::getCustomColorFromDT("kfont-white-disable"); // m_bkgStartColor=ThemeController::getCustomColorFromDT("kcomponent-disable"); ThemeController::getGradientFromDT("kbrand-disable",m_bkgStartColor,m_bkgEndColor); m_linearGradient.setColorAt(0,m_bkgStartColor); m_linearGradient.setColorAt(1,m_bkgEndColor); m_borderColor = ThemeController::getCustomColorFromDT("kline-component-disable"); return; } if (opt.state.testFlag(QStyle::State_MouseOver)) { if (opt.state & QStyle::State_Sunken) // clicked { m_isHoverd = false; ThemeController::getGradientFromDT("kbrand-click",m_bkgStartColor,m_bkgEndColor); m_linearGradient.setColorAt(0,m_bkgStartColor); m_linearGradient.setColorAt(1,m_bkgEndColor); m_borderColor = ThemeController::getCustomColorFromDT("kline-component-click"); } else // hover { m_isHoverd = true; ThemeController::getGradientFromDT("kbrand-hover",m_bkgStartColor,m_bkgEndColor); m_linearGradient.setColorAt(0,m_bkgStartColor); m_linearGradient.setColorAt(1,m_bkgEndColor); m_borderColor = ThemeController::getCustomColorFromDT("kline-component-hover"); } } } else { if(m_isTranslucent) { ThemeController::getGradientFromDT("kcomponent-alpha-normal",m_bkgStartColor,m_bkgEndColor); m_linearGradient.setColorAt(0,m_bkgStartColor); m_linearGradient.setColorAt(1,m_bkgEndColor); m_borderColor = ThemeController::getCustomColorFromDT("kline-component-normal"); m_sliderColor = ThemeController::getCustomColorFromDT("kfont-white"); if (!opt.state.testFlag(QStyle::State_Enabled)) // disable { m_sliderColor = ThemeController::getCustomColorFromDT("kfont-white-disable"); ThemeController::getGradientFromDT("kcomponent-alpha-disable",m_bkgStartColor,m_bkgEndColor); m_linearGradient.setColorAt(0,m_bkgStartColor); m_linearGradient.setColorAt(1,m_bkgEndColor); m_borderColor = ThemeController::getCustomColorFromDT("kline-component-disable"); return; } if (opt.state.testFlag(QStyle::State_MouseOver)) { if (opt.state & QStyle::State_Sunken) // clicked { m_isHoverd = false; ThemeController::getGradientFromDT("kcomponent-alpha-click",m_bkgStartColor,m_bkgEndColor); m_linearGradient.setColorAt(0,m_bkgStartColor); m_linearGradient.setColorAt(1,m_bkgEndColor); m_borderColor = ThemeController::getCustomColorFromDT("kline-component-click"); } else // hover { m_isHoverd = true; ThemeController::getGradientFromDT("kcomponent-alpha-hover",m_bkgStartColor,m_bkgEndColor); m_linearGradient.setColorAt(0,m_bkgStartColor); m_linearGradient.setColorAt(1,m_bkgEndColor); m_borderColor = ThemeController::getCustomColorFromDT("kline-component-hover"); } } } else { ThemeController::getGradientFromDT("kcomponent-normal",m_bkgStartColor,m_bkgEndColor); m_linearGradient.setColorAt(0,m_bkgStartColor); m_linearGradient.setColorAt(1,m_bkgEndColor); m_borderColor = ThemeController::getCustomColorFromDT("kline-component-normal"); m_sliderColor = ThemeController::getCustomColorFromDT("kfont-white"); if (!opt.state.testFlag(QStyle::State_Enabled)) // disable { m_sliderColor = ThemeController::getCustomColorFromDT("kfont-white-disable"); ThemeController::getGradientFromDT("kcomponent-disable",m_bkgStartColor,m_bkgEndColor); m_linearGradient.setColorAt(0,m_bkgStartColor); m_linearGradient.setColorAt(1,m_bkgEndColor); m_borderColor = ThemeController::getCustomColorFromDT("kline-component-disable"); return; } if (opt.state.testFlag(QStyle::State_MouseOver)) { if (opt.state & QStyle::State_Sunken) // clicked { m_isHoverd = false; ThemeController::getGradientFromDT("kcomponent-click",m_bkgStartColor,m_bkgEndColor); m_linearGradient.setColorAt(0,m_bkgStartColor); m_linearGradient.setColorAt(1,m_bkgEndColor); m_borderColor = ThemeController::getCustomColorFromDT("kline-component-click"); } else // hover { m_isHoverd = true; ThemeController::getGradientFromDT("kcomponent-hover",m_bkgStartColor,m_bkgEndColor); m_linearGradient.setColorAt(0,m_bkgStartColor); m_linearGradient.setColorAt(1,m_bkgEndColor); m_borderColor = ThemeController::getCustomColorFromDT("kline-component-hover"); } } } } } void KSwitchButtonPrivate::drawBackground(QPainter *painter) { Q_Q(KSwitchButton); painter->save(); painter->setPen(m_borderColor); painter->setBrush(m_linearGradient); QRect rect(0, 0, q->width() , q->height() ); // 背景框两边是半圆,所以圆角的半径应该固定是矩形高度的一半 int radius = rect.height() / 2; int circleWidth = rect.height(); QPainterPath path; path.moveTo(radius, rect.top()); path.arcTo(QRectF(rect.left(), rect.top(), circleWidth, circleWidth), 90, 180); path.lineTo(rect.width() - radius, rect.height()); path.arcTo(QRectF(rect.width() - rect.height(), rect.top(), circleWidth, circleWidth), 270, 180); path.lineTo(radius, rect.top()); painter->drawPath(path); painter->restore(); } void KSwitchButtonPrivate::drawSlider(QPainter *painter) { Q_Q(KSwitchButton); painter->save(); painter->setRenderHint(QPainter::Antialiasing); painter->setRenderHint(QPainter::TextAntialiasing); painter->setRenderHint(QPainter::SmoothPixmapTransform); painter->setPen(Qt::NoPen); painter->setBrush(m_sliderColor); // 滑块的直径 int sliderWidth = q->height() - m_space * 2; QRect sliderRect(m_startX + m_space, m_space, sliderWidth, sliderWidth); painter->drawEllipse(sliderRect); // if (!q->isEnabled()) { // // 绘制disenable状态下的小矩形条 // if (!q->isChecked()) { // int topX = q->width() - sliderWidth / 2 - 10; // int topY = (q->height() - sliderWidth / 4) / 2; // QRect lineRect(topX, topY, sliderWidth / 2, sliderWidth / 4); // int radius = lineRect.height() / 2; // painter->drawRoundedRect(lineRect, radius, radius); // } else { // int topX = 10; // int topY = (q->height() - sliderWidth / 4) / 2; // QRect lineRect(topX, topY, sliderWidth / 2, sliderWidth / 4); // int radius = lineRect.height() / 2; // painter->drawRoundedRect(lineRect, radius, radius); // } // } painter->restore(); } void KSwitchButtonPrivate::stepChanged() { Q_Q(KSwitchButton); if (q->isChecked()) { if (m_startX < m_endX) { m_startX = qCeil(m_endX * m_animation->currentValue().toDouble()); } else { m_startX = m_endX; m_animation->stop(); } } else { if (m_startX > 0) { double percent = 1.0 - m_animation->currentValue().toDouble(); m_startX = qCeil(m_endX * percent); } else { m_startX = 0; m_animation->stop(); } } q->update(); } } #include "kswitchbutton.moc" #include "moc_kswitchbutton.cpp" libkysdk-applications/kysdk-qtwidgets/src/ktranslucentfloor.h0000664000175000017500000000422215104543305023655 0ustar fengfeng/* * libkysdk-qtwidgets's Library * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhenyu Wang * */ #ifndef KTRANSLUCENTFLOOR_H #define KTRANSLUCENTFLOOR_H #include "gui_g.h" #include namespace kdk { /** * @defgroup FrameModule * { */ class KTranslucentFloorPrivate; /** * @brief 提供一个半透明底板,可作为基础窗体进行布局 * @since 1.2.0 */ class GUI_EXPORT KTranslucentFloor : public QFrame { Q_OBJECT public: KTranslucentFloor(QWidget *parent = nullptr); /** * @brief 设置圆角半径 * @param radius */ void setBorderRadius(int radius); /** * @brief 返回圆角半径 * @return */ int borderRadius(); /** * @brief 设置是否显示阴影 * @param flag */ void setShadow(bool flag); /** * @brief 返回是否显示阴影 * @return */ bool shadow(); /** * @brief 设置是否启用毛玻璃效果 * @param flag */ void setEnableBlur(bool flag); /** * @brief 获取是否已启用毛玻璃效果 * @return */ bool enableBlur(); /** * @brief 设置透明度 * @param opacity */ void setOpacity(qreal opacity); /** * @brief 获取透明度 * @return */ qreal opacity(); protected: void paintEvent(QPaintEvent *); private: KTranslucentFloorPrivate *const d_ptr; Q_DECLARE_PRIVATE(KTranslucentFloor) }; } #endif // KTRANSLUCENTFLOOR_H libkysdk-applications/kysdk-qtwidgets/src/kcustomtabbar.h0000664000175000017500000001513615104543305022745 0ustar fengfeng/* * libkysdk-qtwidgets's Library * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhenyu Wang * */ #ifndef KCUSTOMBAR_H #define KCUSTOMBAR_H #include #include #include #include #include #include class KCustomTabBarPrivate; /** * @defgroup KCustomTabBar * @since 2.5.2.0 */ class KCustomTabBar : public QWidget { Q_OBJECT Q_PROPERTY(Shape shape READ shape WRITE setShape) Q_PROPERTY(int currentIndex READ currentIndex WRITE setCurrentIndex NOTIFY currentChanged) Q_PROPERTY(int count READ count) Q_PROPERTY(bool drawBase READ drawBase WRITE setDrawBase) Q_PROPERTY(QSize iconSize READ iconSize WRITE setIconSize) Q_PROPERTY(Qt::TextElideMode elideMode READ elideMode WRITE setElideMode) Q_PROPERTY(bool usesScrollButtons READ usesScrollButtons WRITE setUsesScrollButtons) Q_PROPERTY(bool tabsClosable READ tabsClosable WRITE setTabsClosable) Q_PROPERTY(SelectionBehavior selectionBehaviorOnRemove READ selectionBehaviorOnRemove WRITE setSelectionBehaviorOnRemove) Q_PROPERTY(bool expanding READ expanding WRITE setExpanding) Q_PROPERTY(bool movable READ isMovable WRITE setMovable) Q_PROPERTY(bool documentMode READ documentMode WRITE setDocumentMode) Q_PROPERTY(bool autoHide READ autoHide WRITE setAutoHide) Q_PROPERTY(bool changeCurrentOnDrag READ changeCurrentOnDrag WRITE setChangeCurrentOnDrag) public: explicit KCustomTabBar(QWidget *parent = nullptr); ~KCustomTabBar(); enum Shape { RoundedNorth, RoundedSouth, RoundedWest, RoundedEast, TriangularNorth, TriangularSouth, TriangularWest, TriangularEast }; Q_ENUM(Shape) enum ButtonPosition { LeftSide, RightSide }; enum SelectionBehavior { SelectLeftTab, SelectRightTab, SelectPreviousTab }; Shape shape() const; void setShape(Shape shape); int addTab(const QString &text); int addTab(const QIcon &icon, const QString &text); int insertTab(int index, const QString &text); int insertTab(int index, const QIcon &icon, const QString &text); void removeTab(int index); void moveTab(int from, int to); bool isTabEnabled(int index) const; void setTabEnabled(int index, bool); QString tabText(int index) const; void setTabText(int index, const QString &text); void setTabContent(int index, const QString &text); QColor tabTextColor(int index) const; void setTabTextColor(int index, const QColor &color); QIcon tabIcon(int index) const; void setTabIcon(int index, const QIcon &icon); Qt::TextElideMode elideMode() const; void setElideMode(Qt::TextElideMode); // #ifndef QT_NO_TOOLTIP void setTabToolTip(int index, const QString &tip); QString tabToolTip(int index) const; // #endif // #if QT_CONFIG(whatsthis) void setTabWhatsThis(int index, const QString &text); QString tabWhatsThis(int index) const; // #endif void setTabData(int index, const QVariant &data); QVariant tabData(int index) const; QRect tabRect(int index) const; int tabAt(const QPoint &pos) const; int currentIndex() const; int count() const; QSize sizeHint() const override; QSize minimumSizeHint() const override; void setDrawBase(bool drawTheBase); bool drawBase() const; QSize iconSize() const; void setIconSize(const QSize &size); bool usesScrollButtons() const; void setUsesScrollButtons(bool useButtons); bool tabsClosable() const; void setTabsClosable(bool closable); void setTabButton(int index, ButtonPosition position, QWidget *widget); QWidget *tabButton(int index, ButtonPosition position) const; SelectionBehavior selectionBehaviorOnRemove() const; void setSelectionBehaviorOnRemove(SelectionBehavior behavior); bool expanding() const; void setExpanding(bool enabled); bool isMovable() const; void setMovable(bool movable); bool documentMode() const; void setDocumentMode(bool set); bool autoHide() const; void setAutoHide(bool hide); bool changeCurrentOnDrag() const; void setChangeCurrentOnDrag(bool change); // #ifndef QT_NO_ACCESSIBILITY QString accessibleTabName(int index) const; void setAccessibleTabName(int index, const QString &name); // #endif public Q_SLOTS: void setCurrentIndex(int index); // void scrollTabs(); void leftScrollTabs(); void rightScrollTabs(); void closeTab(); Q_SIGNALS: void currentChanged(int index); void tabCloseRequested(int index); void tabMoved(int from, int to); void tabBarClicked(int index); void tabBarDoubleClicked(int index); void leftBStatus(bool flag); void rightBStatus(bool flag); protected: virtual QSize tabSizeHint(int index) const; virtual QSize minimumTabSizeHint(int index) const; virtual void tabInserted(int index); virtual void tabRemoved(int index); virtual void tabLayoutChange(); bool event(QEvent *) override; void resizeEvent(QResizeEvent *) override; void showEvent(QShowEvent *) override; void hideEvent(QHideEvent *) override; void paintEvent(QPaintEvent *) override; void mousePressEvent(QMouseEvent *) override; void mouseMoveEvent(QMouseEvent *) override; void mouseReleaseEvent(QMouseEvent *) override; void wheelEvent(QWheelEvent *event) override; void keyPressEvent(QKeyEvent *) override; void changeEvent(QEvent *) override; void timerEvent(QTimerEvent *event) override; void initStyleOption(QStyleOptionTab *option, int tabIndex) const; // #ifndef QT_NO_ACCESSIBILITY // friend class QAccessibleTabBar; // #endif private: Q_DISABLE_COPY(KCustomTabBar) Q_DECLARE_PRIVATE(KCustomTabBar) KCustomTabBarPrivate *const d_ptr; }; #endif // QTABBAR_H libkysdk-applications/kysdk-qtwidgets/src/kshadowhelper.h0000664000175000017500000000252115104543305022736 0ustar fengfeng/* * libkysdk-qtwidgets's Library * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #ifndef KSHADOWHELPER_H #define KSHADOWHELPER_H #include "gui_g.h" #include #include namespace kdk { namespace effects { /** * @since 2.0.2.1 */ class KShadowHelperPrivate; class KShadowHelper : public QObject { Q_OBJECT public: static KShadowHelper *self(); void setWidget(QWidget *widget, int borderRadius = 12, int shadowWidth = 20, qreal darkness = 0.5); private: KShadowHelper(QObject *parent = nullptr); Q_DECLARE_PRIVATE(KShadowHelper) KShadowHelperPrivate *const d_ptr; }; } } #endif // KSHADOWHELPER_H libkysdk-applications/kysdk-qtwidgets/src/kprogresscircle.cpp0000664000175000017500000003060015104543305023631 0ustar fengfeng/* * libkysdk-qtwidgets's Library * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #include "kprogresscircle.h" #include "themeController.h" #include #include #include #include namespace kdk { class KProgressCirclePrivate : public QObject, public ThemeController { Q_OBJECT Q_DECLARE_PUBLIC(KProgressCircle) public: KProgressCirclePrivate(KProgressCircle *parent); void initDefaultFormat(); void drawBaseCircle(QPainter *painter); void dawColoredCircle(QPainter *painter); void drawText(QPainter *painter); void calculateCircleRect(); void changeTheme(); private: KProgressCircle *q_ptr; int m_minimum; int m_maximum; int m_value; QString m_format; QString m_text; bool m_defaultFormat; bool m_isTextVisiable; ProgressBarState m_state; QColor m_color; QColor m_baseColor; QColor m_baseCircleColor; QRect m_baseRect; QRect m_contentRect; int m_cirleWidth; int m_startAngel; int m_pixWidth; int m_textWidth; }; KProgressCircle::KProgressCircle(QWidget *parent) : QWidget(parent) , d_ptr(new KProgressCirclePrivate(this)) { setFixedSize(60, 60); connect(this, &KProgressCircle::valueChanged, this, [=]() { if (this->value() == this->maximum()) setState(SuccessProgress); }); } int KProgressCircle::minimum() const { Q_D(const KProgressCircle); return d->m_minimum; } int KProgressCircle::maximum() const { Q_D(const KProgressCircle); return d->m_maximum; } int KProgressCircle::value() const { Q_D(const KProgressCircle); return d->m_value; } QString KProgressCircle::text() const { Q_D(const KProgressCircle); if ((d->m_maximum == 0 && d->m_minimum == 0) || d->m_value < d->m_minimum || (d->m_value == INT_MIN && d->m_minimum == INT_MIN)) return QString(); qint64 totalSteps = qint64(d->m_maximum) - d->m_minimum; QString result = d->m_format; QLocale locale = QWidget::locale(); locale.setNumberOptions(locale.numberOptions() | QLocale::OmitGroupSeparator); result.replace(QLatin1String("%m"), QString::number(totalSteps)); result.replace(QLatin1String("%v"), QString::number(d->m_value)); if (totalSteps == 0) { result.replace(QLatin1String("%p"), locale.toString(100)); return result; } const auto progress = static_cast((qint64(d->m_value) - d->m_minimum) * 100.0 / totalSteps); result.replace(QLatin1String("%p"), QString::number(progress)); return result; } void KProgressCircle::setTextVisible(bool visible) { Q_D(KProgressCircle); d->m_isTextVisiable = visible; update(); } bool KProgressCircle::isTextVisible() const { Q_D(const KProgressCircle); return d->m_isTextVisiable; } ProgressBarState KProgressCircle::state() { Q_D(const KProgressCircle); return d->m_state; } void KProgressCircle::setState(ProgressBarState state) { Q_D(KProgressCircle); d->m_state = state; switch (d->m_state) { case FailedProgress: d->m_color = "#FF4D4F"; break; case SuccessProgress: d->m_color = "#52C429"; break; case NormalProgress: default: d->m_color = "#3790FA"; break; } update(); } void KProgressCircle::reset() { Q_D(KProgressCircle); if (d->m_minimum == INT_MIN) d->m_value = INT_MIN; else d->m_value = d->m_minimum - 1; repaint(); } void KProgressCircle::setRange(int minimum, int maximum) { Q_D(KProgressCircle); if (minimum != d->m_minimum || maximum != d->m_maximum) { d->m_minimum = minimum; d->m_maximum = qMax(minimum, maximum); if (d->m_value < qint64(d->m_minimum) - 1 || d->m_value > d->m_maximum) reset(); else update(); } } void KProgressCircle::setMinimum(int minimum) { Q_D(KProgressCircle); setRange(minimum, qMax(d->m_maximum, minimum)); } void KProgressCircle::setMaximum(int maximum) { Q_D(KProgressCircle); setRange(qMin(d->m_minimum, maximum), maximum); } void KProgressCircle::setValue(int value) { Q_D(KProgressCircle); if (d->m_value == value || ((value > d->m_maximum || value < d->m_minimum) && (d->m_maximum != 0 || d->m_minimum != 0))) return; d->m_value = value; Q_EMIT valueChanged(value); repaint(); } void KProgressCircle::paintEvent(QPaintEvent *) { Q_D(KProgressCircle); QPainter painter(this); painter.setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform); if (painter.pen().width() == 1) painter.translate(0.5, 0.5); d->calculateCircleRect(); d->drawBaseCircle(&painter); d->dawColoredCircle(&painter); d->drawText(&painter); } KProgressCirclePrivate::KProgressCirclePrivate(KProgressCircle *parent) : q_ptr(parent) , m_minimum(0) , m_maximum(100) , m_value(0) , m_cirleWidth(6) , m_isTextVisiable(true) , m_startAngel(90) , m_pixWidth(20) , m_textWidth(30) , m_state(NormalProgress) , m_color("#3790FA") , m_defaultFormat(true) { initDefaultFormat(); changeTheme(); connect(m_gsetting, &QGSettings::changed, this, &KProgressCirclePrivate::changeTheme); } void KProgressCirclePrivate::initDefaultFormat() { Q_Q(KProgressCircle); if (m_defaultFormat) { QLocale locale = q->locale(); m_format = QLatin1String("%p") + locale.percent(); } } void KProgressCirclePrivate::drawBaseCircle(QPainter *painter) { Q_Q(KProgressCircle); QPen pen; if (m_isTextVisiable) { if (ThemeController::widgetTheme() == ClassicTheme) { if (ThemeController::themeMode() == LightTheme) pen.setColor(ThemeController::lanhuHSLToQtHsl(0, 0, 73)); else pen.setColor(ThemeController::lanhuHSLToQtHsl(0, 0, 35)); pen.setWidth(8); painter->setPen(pen); painter->setBrush(Qt::NoBrush); painter->setRenderHint(QPainter::Antialiasing); painter->drawEllipse(m_baseRect.adjusted(1, 1, -1, -1)); } pen.setColor(m_baseColor); pen.setWidth(m_cirleWidth); painter->setPen(pen); painter->setBrush(Qt::NoBrush); painter->setRenderHint(QPainter::Antialiasing); painter->drawEllipse(m_baseRect.adjusted(1, 1, -1, -1)); } else { QPen penColor; QBrush outBrush, inBrush; if (ThemeController::widgetTheme() == ClassicTheme) { if (ThemeController::themeMode() == LightTheme) { outBrush = QBrush(ThemeController::lanhuHSLToQtHsl(0, 0, 98)); inBrush = QBrush(ThemeController::lanhuHSLToQtHsl(0, 0, 98)); penColor.setColor(ThemeController::lanhuHSLToQtHsl(0, 0, 73)); } else { outBrush = QBrush(ThemeController::lanhuHSLToQtHsl(0, 0, 27)); inBrush = QBrush(ThemeController::lanhuHSLToQtHsl(0, 0, 27)); penColor.setColor(ThemeController::lanhuHSLToQtHsl(0, 0, 35)); } } else { outBrush = m_baseColor; inBrush = QBrush(Qt::NoBrush); penColor = QPen(Qt::NoPen); } painter->save(); painter->setPen(penColor); painter->setBrush(outBrush); painter->setRenderHint(QPainter::Antialiasing); painter->drawEllipse(m_baseRect); painter->restore(); pen.setColor(m_baseCircleColor); pen.setWidth(m_cirleWidth); painter->setPen(pen); painter->setBrush(inBrush); painter->setRenderHint(QPainter::Antialiasing); painter->drawEllipse(m_contentRect); } } void KProgressCirclePrivate::dawColoredCircle(QPainter *painter) { Q_Q(KProgressCircle); QPen pen; int angleSpan = m_value * 360 / m_maximum; if (m_state == ProgressBarState::NormalProgress) { m_color = ThemeController::getCustomColorFromDT("kbrand-normal"); } if (m_isTextVisiable) { pen.setColor(m_color); pen.setWidth(m_cirleWidth); if (ThemeController::widgetTheme() == ClassicTheme) pen.setCapStyle(Qt::SquareCap); else pen.setCapStyle(Qt::RoundCap); painter->setPen(pen); painter->setBrush(Qt::NoBrush); painter->setRenderHint(QPainter::Antialiasing); if (ThemeController::widgetTheme() == ClassicTheme) painter->drawArc(m_baseRect.adjusted(1, 1, -1, -1), m_startAngel * 16, -angleSpan * 16); else painter->drawArc(m_baseRect, m_startAngel * 16, -angleSpan * 16); } else { pen.setColor(m_color); pen.setWidth(m_cirleWidth); if (ThemeController::widgetTheme() == ClassicTheme) pen.setCapStyle(Qt::SquareCap); else pen.setCapStyle(Qt::RoundCap); painter->setPen(pen); painter->setBrush(Qt::NoBrush); painter->setRenderHint(QPainter::Antialiasing); painter->drawArc(m_contentRect, m_startAngel * 16, -angleSpan * 16); } } void KProgressCirclePrivate::drawText(QPainter *painter) { Q_Q(KProgressCircle); QRect pixRect; pixRect.setLeft(q->rect().center().x() - m_pixWidth / 2); pixRect.setTop(q->rect().center().y() - m_pixWidth / 2); pixRect.setRight(q->rect().center().x() + m_pixWidth / 2); pixRect.setBottom(q->rect().center().y() + m_pixWidth / 2); QRect textRect; textRect.setLeft(q->rect().center().x() - m_textWidth / 2); textRect.setTop(q->rect().center().y() - m_textWidth / 2); textRect.setRight(q->rect().center().x() + m_textWidth / 2); textRect.setBottom(q->rect().center().y() + m_textWidth / 2); if (m_isTextVisiable) { switch (m_state) { case NormalProgress: { painter->setRenderHint(QPainter::Antialiasing); painter->drawText(textRect, Qt::AlignCenter, q->text()); } break; case SuccessProgress: { QColor green = ThemeController::getCustomColorFromDT("ksuccess-normal"); QPixmap pixmap = ThemeController::drawColoredPixmap(QIcon::fromTheme("object-select-symbolic").pixmap(m_pixWidth, m_pixWidth), green); painter->setRenderHint(QPainter::Antialiasing); painter->drawPixmap(pixRect, pixmap); break; } case FailedProgress: { QColor red = ThemeController::getCustomColorFromDT("kerror-normal");; QPixmap pixmap = ThemeController::drawColoredPixmap(QIcon::fromTheme("window-close-symbolic").pixmap(20, 20), red); painter->setRenderHint(QPainter::Antialiasing); painter->drawPixmap(pixRect, pixmap); break; } default: break; } } } void KProgressCirclePrivate::calculateCircleRect() { Q_Q(KProgressCircle); m_baseRect.setTop(1 + m_cirleWidth / 2); m_baseRect.setLeft(1 + m_cirleWidth / 2); m_baseRect.setBottom(q->rect().height() - 1 - m_cirleWidth / 2); m_baseRect.setRight(q->rect().right() - 1 - m_cirleWidth / 2); m_contentRect.setTop(1 + m_cirleWidth * 2); m_contentRect.setLeft(1 + m_cirleWidth * 2); m_contentRect.setBottom(q->rect().height() - 1 - m_cirleWidth * 2); m_contentRect.setRight(q->rect().right() - 1 - m_cirleWidth * 2); } void KProgressCirclePrivate::changeTheme() { Q_Q(KProgressCircle); initThemeStyle(); if (ThemeController::themeMode() == LightTheme) { m_baseColor = ThemeController::getCustomColorFromDT("kgray-6"); m_baseCircleColor = ThemeController::getCustomColorFromDT("kgray-10"); } else { m_baseColor = ThemeController::getCustomColorFromDT("kgray-16"); m_baseCircleColor = ThemeController::getCustomColorFromDT("kgray-17"); } q->update(); } } #include "kprogresscircle.moc" #include "moc_kprogresscircle.cpp" libkysdk-applications/kysdk-qtwidgets/src/klineeditframe.h0000664000175000017500000000366615104543305023074 0ustar fengfeng/* * * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Sisheng He * */ #ifndef LINEEDITWIDGET_H #define LINEEDITWIDGET_H #include "kbaseframe.h" #include "klabel.h" #include /** * @defgroup ContainerModules * @brief 创建一个带 QLineEdit 的 Frame * @since 3.0.1.0 * { */ namespace kdk { class KLineEditFramePrivate; class KLineEditFrame : public KBaseFrame { Q_OBJECT public: /** * @brief 创建一个带 QLineEdit 的 Frame * * @param title: text of m_settingName * @param style: 设置圆角(None:无圆角,Top:上圆角,Bottom:下圆角,Around:四圆角) * @param parent */ explicit KLineEditFrame(const QString title, QWidget *parent = nullptr, BorderRadiusStyle style = BorderRadiusStyle::None); /** * @brief * */ ~KLineEditFrame(); /** * @brief 获取输入框 * * @return QLineEdit */ QLineEdit *lineEdit(); /** * @brief 获取label * * @return QLabel */ KLabel *titleLabel(); /** * @brief 获取layout * * @return QHBoxLayout */ QHBoxLayout *mainHLayout(); private: Q_DECLARE_PRIVATE(KLineEditFrame) KLineEditFramePrivate *const d_ptr; }; } #endif // LINEEDITWIDGET_H libkysdk-applications/kysdk-qtwidgets/src/kprogressbar.h0000664000175000017500000000571615104543305022613 0ustar fengfeng/* * libkysdk-qtwidgets's Library * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #ifndef KPROGRESSBAR_H #define KPROGRESSBAR_H #include "gui_g.h" #include namespace kdk { /** @defgroup BarModule * @{ */ /** * @brief 支持三种状态 * @since 1.0.0 */ enum ProgressBarState { NormalProgress, FailedProgress, SuccessProgress }; class KProgressBarPrivate; /** * @brief 进度条,支持三种状态显示 */ class GUI_EXPORT KProgressBar : public QProgressBar { Q_OBJECT public: KProgressBar(QWidget *parent); /** * @brief 获取状态 * @return */ ProgressBarState state(); /** * @brief 设置状态 * @param state */ void setState(ProgressBarState state); /** * @brief 获取文本 * @return */ QString text() const override; /** * @brief 设置方向 */ void setOrientation(Qt::Orientation); /** * @brief 设置进度条宽度 * @param width * @since 1.2.0 */ void setBodyWidth(int width); /** * @brief 设置首尾位置的渐变颜色 * @since 2.5.2.0 * @param color1 * @param color2 */ void setGradationColor(QColor color1, QColor color2); /** * @brief 设置背景色 * @since 2.5.2.0 * @param color */ void setBackgroundColor(QColor color); /** * @brief 设置填充色 * @since 2.5.2.0 * @param color */ void setFillColor(QColor color); /** * @brief 是否启用自定义渐变色 * @since 2.5.2.0 * @param flag */ void setGradation(bool flag); /** * @brief 获取是否启用自定义渐变色 * @since 2.5.2.0 * @return */ bool gradation(); /** * @brief 是否启用动画 * @since 2.5.2.0 * @param flag */ void setAnimation(bool flag); /** * @brief 获取是否启用动画 * @since 2.5.2.0 * @return */ bool animation(); protected: void paintEvent(QPaintEvent *event) override; QSize sizeHint() const; private: Q_DECLARE_PRIVATE(KProgressBar) KProgressBarPrivate *const d_ptr; }; } /** * @example testprogressbar/widget.h * @example testprogressbar/widget.cpp * @} */ #endif // KPROGRESSBAR_H libkysdk-applications/kysdk-qtwidgets/src/kbubblewidget.h0000664000175000017500000000620515104543305022713 0ustar fengfeng/* * libkysdk-qtwidgets's Library * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhenyu Wang * */ #ifndef KBubbleWidget_H #define KBubbleWidget_H #include #include namespace kdk { /** * @brief 指定气泡尾部显示的方向 */ enum TailDirection { TopDirection, LeftDirection, BottomDirection, RightDirection, None }; /** * @brief 指定气泡尾部的显示位置 */ enum TailLocation { LeftLocation, MiddleLocation, RightLocation }; /** * @defgroup FrameModule */ class KBubbleWidgetPrivate; /** * @brief 提供了一个带三角形窗体。 * @since 2.0.2.1 */ class KBubbleWidget : public QWidget { Q_OBJECT public: KBubbleWidget(QWidget *parent = nullptr); /** * @brief 设置气泡尾部尺寸 * @param size */ void setTailSize(const QSize &size); /** * @brief 获取气泡尾部尺寸 * @return */ QSize tailSize(); /** * @brief 设置气泡尾部显示位置 * @param dirType * @param locType */ void setTailPosition(TailDirection dirType, TailLocation locType = MiddleLocation); /** * @brief 获取气泡尾部显示方向 * @return 左、上、右、下 */ TailDirection tailDirection(); /** * @brief 获取气泡尾部显示位置 * @return 居左、居中、居右 */ TailLocation tailLocation(); /** * @brief 设置窗体圆角半径 * @param bottomLeft * @param topLeft * @param topRight * @param bottomRight */ void setBorderRadius(int bottomLeft, int topLeft, int topRight, int bottomRight); /** * @brief 设置窗体圆角半径 * @param radius */ void setBorderRadius(int radius); /** * @brief 设置是否启用毛玻璃效果 * @param flag */ void setEnableBlur(bool flag); /** * @brief 获取是否已启用毛玻璃效果 * @return */ bool enableBlur(); /** * @brief 设置透明度 * @param opacity */ void setOpacity(qreal opacity); /** * @brief 获取透明度 * @return */ qreal opacity(); /** * @brief 设置是否启用高亮背景色 * @param flag * @since 2.4.1.0 */ void setHighlightBackground(bool flag); protected: void paintEvent(QPaintEvent *); private: Q_DECLARE_PRIVATE(KBubbleWidget) KBubbleWidgetPrivate *const d_ptr; }; } #endif // KBubbleWidget_H libkysdk-applications/kysdk-qtwidgets/src/kprogressdialog.h0000664000175000017500000001102315104543305023272 0ustar fengfeng/* * libkysdk-qtwidgets's Library * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #ifndef KPROGRESSDIALOG_H #define KPROGRESSDIALOG_H #include "gui_g.h" #include "kdialog.h" #include "kiconbar.h" #include "kwidget.h" #include "kwindowbuttonbar.h" #include "themeController.h" #include #include #include #include namespace kdk { /** @defgroup DialogBoxModule * @{ */ /** * @brief 支持三种样式 * @since 1.0.0 */ enum BarType { ScrollBar, NothingBar, NormalBar, SpeedBar }; class KProgressDialogPrivate; /** * @brief 进度对话框,会实时显示当前进度 */ class GUI_EXPORT KProgressDialog : public KDialog { Q_OBJECT public: explicit KProgressDialog(QWidget *parent = nullptr); KProgressDialog(const QString &labelText, const QString &cancelButtonText = "cancel", int minimum = 0, int maximum = 100, QWidget *parent = nullptr); ~KProgressDialog(); /** * @brief 设置提示文字 * @param label */ void setLabel(QLabel *label); /** * @brief 设置取消按钮 * @param button */ void setCancelButton(QPushButton *button); /** * @brief 设置进度条 * @param bar */ void setBar(QProgressBar *bar); /** * @brief 设置detail的后缀 * @param suffix */ void setSuffix(const QString &suffix); void setSuffix(const QString &numerator, const QString &denominator); void setSpeed(const float &speed); /** * @brief 设置是否显示详细信息 * @param flag */ void setShowDetail(bool flag); /** * @brief 返回最小值 * @return */ int minimum() const; /** * @brief 返回最大值 * @return */ int maximum() const; /** * @brief 返回当前值 * @return */ int value() const; /** * @brief 返回提示内容 * @return */ QString labelText() const; /** * @brief 设置自动重置 * @param reset */ void setAutoReset(bool reset); /** * @brief 返回是否自动重置 * @return */ bool autoReset() const; /** * @brief 设置是否自动关闭对话框 * @param close */ void setAutoClose(bool close); /** * @brief 返回是否自动关闭对话框 * @return */ bool autoClose() const; /** * @brief 获取进度条 * @return */ QProgressBar *progressBar(); void setBarType(const BarType &type); void addButton(QPushButton *button); void removeButton(QPushButton *button); BarType myType(); Q_SIGNALS: void canceled(); public Q_SLOTS: /** * @brief 取消进度条 */ void cancel(); /** * @brief 重置进度条 */ void reset(); /** * @brief 设置最大值 * @param maximum */ void setMaximum(int maximum); /** * @brief 设置最小值 * @param minimum */ void setMinimum(int minimum); /** * @brief 设置范围 * @param minimum * @param maximum */ void setRange(int minimum, int maximum); /** * @brief 设置当前值 * @param progress */ void setValue(int progress); /** * @brief 设置提示内容 * @param text */ void setLabelText(const QString &text); /** * @brief 设置取消按钮内容 * @param text */ void setCancelButtonText(const QString &text); /** * @brief 设置次级内容 * @param text */ void setSubContent(const QString &text); protected: void changeTheme(); private: Q_DECLARE_PRIVATE(KProgressDialog) KProgressDialogPrivate *const d_ptr; }; } /** * @example testprogressdialog/widget.h * @example testprogressdialog/widget.cpp * @} */ #endif // KPROGRESSDIALOG_H libkysdk-applications/kysdk-qtwidgets/src/xatom-helper.h0000664000175000017500000000620215104543305022503 0ustar fengfeng/* * KWin Style UKUI * * Copyright (C) 2020, KylinSoft Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authors: Yue Lan */ #ifndef XATOMHELPER_H #define XATOMHELPER_H #include #include // #include /** * @brief 窗口属性 * @since 1.0.0 */ struct UnityCorners { ulong topLeft = 0; ulong topRight = 0; ulong bottomLeft = 0; ulong bottomRight = 0; }; typedef struct { ulong flags = 0; ulong functions = 0; ulong decorations = 0; long input_mode = 0; ulong status = 0; } MotifWmHints, MwmHints; #define MWM_HINTS_FUNCTIONS (1L << 0) #define MWM_HINTS_DECORATIONS (1L << 1) #define MWM_HINTS_INPUT_MODE (1L << 2) #define MWM_HINTS_STATUS (1L << 3) #define MWM_FUNC_ALL (1L << 0) #define MWM_FUNC_RESIZE (1L << 1) #define MWM_FUNC_MOVE (1L << 2) #define MWM_FUNC_MINIMIZE (1L << 3) #define MWM_FUNC_MAXIMIZE (1L << 4) #define MWM_FUNC_CLOSE (1L << 5) #define MWM_DECOR_ALL (1L << 0) #define MWM_DECOR_BORDER (1L << 1) #define MWM_DECOR_RESIZEH (1L << 2) #define MWM_DECOR_TITLE (1L << 3) #define MWM_DECOR_MENU (1L << 4) #define MWM_DECOR_MINIMIZE (1L << 5) #define MWM_DECOR_MAXIMIZE (1L << 6) #define MWM_INPUT_MODELESS 0 #define MWM_INPUT_PRIMARY_APPLICATION_MODAL 1 #define MWM_INPUT_SYSTEM_MODAL 2 #define MWM_INPUT_FULL_APPLICATION_MODAL 3 #define MWM_INPUT_APPLICATION_MODAL MWM_INPUT_PRIMARY_APPLICATION_MODAL #define MWM_TEAROFF_WINDOW (1L << 0) namespace kdk { class Decoration; class XAtomHelper : public QObject { // friend class UKUI::Decoration; Q_OBJECT public: static XAtomHelper *getInstance(); static bool isFrameLessWindow(int winId); static bool isWindowDecorateBorderOnly(int winId); static bool isWindowMotifHintDecorateBorderOnly(const MotifWmHints &hint); bool isUKUICsdSupported(); bool isUKUIDecorationWindow(int winId); UnityCorners getWindowBorderRadius(int winId); void setWindowBorderRadius(int winId, const UnityCorners &data); void setWindowBorderRadius(int winId, int topLeft, int topRight, int bottomLeft, int bottomRight); void setUKUIDecoraiontHint(int winId, bool set = true); void setWindowMotifHint(int winId, const MotifWmHints &hints); MotifWmHints getWindowMotifHint(int winId); private: explicit XAtomHelper(QObject *parent = nullptr); Atom registerUKUICsdNetWmSupportAtom(); void unregisterUKUICsdNetWmSupportAtom(); Atom m_motifWMHintsAtom = None; Atom m_unityBorderRadiusAtom = None; Atom m_ukuiDecorationAtion = None; }; } #endif // XATOMHELPER_H libkysdk-applications/kysdk-qtwidgets/src/kcrumb.cpp0000664000175000017500000002051415104543305021716 0ustar fengfeng/* * libkysdk-qtwidgets's Library * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhenyu Wang * */ #include "kcrumb.h" #include "kborderlessbutton.h" #include "kcustomtabbar.h" #include "themeController.h" #include #include #include #include #include #include #include namespace kdk { static int spacing = 4; class Q_DECL_HIDDEN CrumbStyle : public QProxyStyle { Q_OBJECT public: CrumbStyle(QStyle *style = nullptr); QRect subElementRect(QStyle::SubElement element, const QStyleOption *option, const QWidget *widget) const override; }; class Q_DECL_HIDDEN KCrumbPrivate : public QObject, public ThemeController { Q_OBJECT Q_DECLARE_PUBLIC(KCrumb) public: KCrumbPrivate(KCrumb *parent); private: KCrumb *q_ptr; QIcon m_icon; bool m_isFlat; QStringList m_stringList; }; KCrumb::KCrumb(QWidget *parent) : KCustomTabBar(parent) , d_ptr(new KCrumbPrivate(this)) { Q_D(KCrumb); CrumbStyle *style = new CrumbStyle(); setStyle(style); connect(d->m_gsetting, &QGSettings::changed, this, [=] { d->initThemeStyle(); update(); }); } int KCrumb::addTab(const QString &text) { Q_D(KCrumb); d->m_stringList.append(text); return KCustomTabBar::addTab(text); } int KCrumb::addTab(const QIcon &icon, const QString &text) { Q_D(KCrumb); d->m_stringList.append(text); return KCustomTabBar::addTab(icon, text); } int KCrumb::insertTab(int index, const QString &text) { Q_D(KCrumb); d->m_stringList.insert(index, text); return KCustomTabBar::insertTab(index, text); } int KCrumb::insertTab(int index, const QIcon &icon, const QString &text) { Q_D(KCrumb); d->m_stringList.insert(index, text); return insertTab(index, icon, text); } void KCrumb::removeTab(int index) { Q_D(KCrumb); d->m_stringList.removeAt(index); KCustomTabBar::removeTab(index); } void KCrumb::moveTab(int from, int to) { Q_D(KCrumb); d->m_stringList.move(from, to); KCustomTabBar::moveTab(from, to); } void KCrumb::setIcon(const QIcon &icon) { Q_D(KCrumb); d->m_icon = icon; update(); } QIcon KCrumb::icon() const { Q_D(const KCrumb); return d->m_icon; } bool KCrumb::isFlat() const { Q_D(const KCrumb); return d->m_isFlat; } void KCrumb::setFlat(bool flat) { Q_D(KCrumb); d->m_isFlat = flat; update(); } void KCrumb::leftScroll() { Q_D(KCrumb); leftScrollTabs(); } void KCrumb::rightScroll() { Q_D(KCrumb); rightScrollTabs(); } QSize KCrumb::tabSizeHint(int index) const { Q_D(const KCrumb); QSize size = KCustomTabBar::tabSizeHint(index); QFont font(QApplication::font()); QFontMetrics fm(font); int width = fm.horizontalAdvance(tabText(index)); size.setWidth(width + 40); if (index == 0 && !d->m_icon.isNull()) size.setWidth(size.width() + 50); return size; } void KCrumb::paintEvent(QPaintEvent *event) { Q_D(const KCrumb); QPainter p(this); p.setRenderHint(QPainter::Antialiasing); p.setRenderHint(QPainter::TextAntialiasing); p.setRenderHint(QPainter::SmoothPixmapTransform); QFontMetrics fm = p.fontMetrics(); QColor highLightColor = ThemeController::getCustomColorFromDT("highlight-active"); QColor baseColor; QColor focusColor; if (ThemeController::themeMode() == ThemeFlag::DarkTheme) { if (d->m_isFlat) baseColor = "#D9D9D9"; else baseColor = "#47474A"; focusColor = "#D9D9D9"; } else { if (d->m_isFlat) baseColor = "#262626"; else baseColor = "#B3B3B3"; focusColor = "#262626"; } int width = 0; for (int i = 0; i < count(); i++) { width += fm.horizontalAdvance(d->m_stringList.at(i)) + 40; } if (!d->m_icon.isNull()) width += 50; int useWidth = fm.horizontalAdvance(d->m_stringList.at(count() - 1)) + 40; for (int i = 0; i < count(); i++) { QRect rc = tabRect(i); QStyleOptionTab option; initStyleOption(&option, i); p.setPen(Qt::NoPen); p.drawRect(rc); if (QStyle::State_MouseOver & option.state) p.setPen(highLightColor); else if (QStyle::State_Selected & option.state) p.setPen(focusColor); else p.setPen(baseColor); p.setBrush(Qt::NoBrush); if (rect().width() >= width) { if (i == 0 && !d->m_icon.isNull()) { p.drawPixmap(rc.left() + 10, (rc.height() - 24) / 2, 24, 24, d->m_icon.pixmap(24, 24)); p.drawText(rc.adjusted(30, 0, -24, 0), Qt::AlignCenter, d->m_stringList.at(i)); } else p.drawText(rc.adjusted(0, 0, -24, 0), Qt::AlignCenter, d->m_stringList.at(i)); if (i != count() - 1) p.drawPixmap(rc.right() - 24, (rc.height() - 16) / 2, 16, 16, ThemeController::drawColoredPixmap(QIcon::fromTheme("ukui-end-symbolic").pixmap(16, 16), baseColor)); } else { if (i == 0) { if (!d->m_icon.isNull()) { p.drawPixmap(rc.left() + 10, (rc.height() - 24) / 2, 24, 24, d->m_icon.pixmap(24, 24)); p.drawText(rc.adjusted(30, 0, -24, 0), Qt::AlignCenter, d->m_stringList.at(i)); useWidth += fm.horizontalAdvance(d->m_stringList.at(0)) + 90; ; } else { p.drawText(rc.adjusted(0, 0, -24, 0), Qt::AlignCenter, d->m_stringList.at(i)); useWidth += fm.horizontalAdvance(d->m_stringList.at(0)) + 40; } } else if (i == count() - 1) { p.drawText(rc.adjusted(0, 0, -24, 0), Qt::AlignCenter, d->m_stringList.at(i)); } else { int usableWidth = 0; for (int j = i; j < count() - 1; j++) { usableWidth += fm.horizontalAdvance(d->m_stringList.at(j)) + 40; } if ((rect().width() - useWidth) <= usableWidth) { setTabContent(i, "..."); setTabToolTip(i, d->m_stringList.at(i)); p.drawText(rc.adjusted(0, 0, -24, 0), Qt::AlignCenter, "..."); useWidth += fm.horizontalAdvance("...") + 40; } else // 如果可用长度 大于 需用长度 则正常显示 { setTabContent(i, d->m_stringList.at(i)); p.drawText(rc.adjusted(0, 0, -24, 0), Qt::AlignCenter, d->m_stringList.at(i)); useWidth += fm.horizontalAdvance(d->m_stringList.at(i)) + 40; if (!tabToolTip(i).isEmpty()) setTabToolTip(i, ""); } } if (i != count() - 1) { p.drawPixmap(rc.right() - 24, (rc.height() - 16) / 2, 16, 16, ThemeController::drawColoredPixmap(QIcon::fromTheme("ukui-end-symbolic").pixmap(16, 16), baseColor)); } } } } KCrumbPrivate::KCrumbPrivate(KCrumb *parent) : q_ptr(parent) , m_isFlat(true) { } CrumbStyle::CrumbStyle(QStyle *style) { } QRect CrumbStyle::subElementRect(QStyle::SubElement element, const QStyleOption *option, const QWidget *widget) const { switch (element) { case QStyle::SE_TabBarScrollLeftButton: return QRect(); break; case QStyle::SE_TabBarScrollRightButton: return QRect(); break; default: break; } return QProxyStyle::subElementRect(element, option, widget); } } #include "kcrumb.moc" #include "moc_kcrumb.cpp" libkysdk-applications/kysdk-qtwidgets/src/kpixmapcontainer.h0000664000175000017500000000465415104543305023463 0ustar fengfeng/* * libkysdk-qtwidgets's Library * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #ifndef KPIXMAPCONTAINER_H #define KPIXMAPCONTAINER_H #include "gui_g.h" #include #include namespace kdk { /** @defgroup BarModule * @{ */ class KPixmapContainerPrivate; /** * @brief 为指定的pixmap添加右上角消息提示气泡,样式类似微信头像的消息提示 * @since 1.0.0 */ class GUI_EXPORT KPixmapContainer : public QWidget { Q_OBJECT public: KPixmapContainer(QWidget *parent = nullptr); /** * @brief 获取值 */ int value() const; /** * @brief 设置值 * @param value */ void setValue(int value); /** * @brief 设置值是否可见 * @param flag */ void setValueVisiable(bool flag); /** * @brief 获取值是否可见 */ bool isValueVisiable() const; /** * @brief 设置pixmap * @param pixmap */ void setPixmap(const QPixmap &pixmap); /** * @brief 获取pixmap */ QPixmap pixmap() const; /** * @brief 清除值 */ void clearValue(); /** * @brief 返回背景色 * @return */ QColor color(); /** * @brief 设置背景色 * @param color */ void setColor(const QColor &color); /** * @brief 返回字体大小 * @return */ int fontSize(); /** * @brief 设置字体大小 * @param size */ void setFontSize(int size); protected: void paintEvent(QPaintEvent *event); private: Q_DECLARE_PRIVATE(KPixmapContainer) KPixmapContainerPrivate *const d_ptr; }; } /** * @example testbadge/widget.h * @example testbadge/widget.cpp * @} */ #endif // KPIXMAPCONTAINER_H libkysdk-applications/kysdk-qtwidgets/src/ktoolbutton.cpp0000664000175000017500000004272515104543305023027 0ustar fengfeng/* * libkysdk-qtwidgets's Library * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #include "ktoolbutton.h" #include "parmscontroller.h" #include "themeController.h" #include #include #include #include #include #include #include #include namespace kdk { class KToolButtonPrivate : public QObject, public ThemeController { Q_DECLARE_PUBLIC(KToolButton) Q_OBJECT public: KToolButtonPrivate(KToolButton *parent); ~KToolButtonPrivate() { } void changePalette(); void doLoadingFlash(); protected: void changeTheme(); private: KToolButton *q_ptr; KToolButtonType m_type; QLinearGradient m_pLinearGradient; bool m_isLoading; QTimer *m_pTimer; int m_flashState; bool m_hasArrow; QPixmap m_arrowPixmap; QColor m_pixColor; QSize m_pixmapSize; bool m_isIconColor; QColor m_iconColor; int m_bottomLeftRadius; int m_topLeftRadius; int m_topRightRadius; int m_bottomRightRadius; bool m_isBkgColorEnable; }; KToolButton::KToolButton(QWidget *parent) : QToolButton(parent) , d_ptr(new KToolButtonPrivate(this)) { Q_D(KToolButton); d->m_pTimer = new QTimer(this); d->m_pTimer->setInterval(100); d->m_flashState = 0; d->m_isLoading = false; int radius = ThemeController::getRadiusFromDT("kradius-normal"); if (radius == -1) { d->m_bottomLeftRadius = 6; d->m_topLeftRadius = 6; d->m_topRightRadius = 6; d->m_bottomRightRadius = 6; } else { d->m_bottomLeftRadius = radius; d->m_topLeftRadius = radius; d->m_topRightRadius = radius; d->m_bottomRightRadius = radius; } d->m_isBkgColorEnable = false; setType(Flat); installEventFilter(this); QToolButton::setIcon(QIcon::fromTheme("open-menu-symbolic")); setFocusPolicy(Qt::FocusPolicy::TabFocus); d->changeTheme(); connect(d->m_gsetting, &QGSettings::changed, d, &KToolButtonPrivate::changeTheme); connect(d->m_pTimer, &QTimer::timeout, d, &KToolButtonPrivate::doLoadingFlash); connect(Parmscontroller::self(), &Parmscontroller::modeChanged, this, [=]() { updateGeometry(); }); connect(this, &KToolButton::toggled, this, [=](bool checked) { emit checkedChanged(checked); }); } KToolButtonType KToolButton::type() { Q_D(KToolButton); return d->m_type; } void KToolButton::setType(KToolButtonType type) { Q_D(KToolButton); d->m_type = type; d->changePalette(); } void KToolButton::setIcon(const QIcon &icon) { Q_D(KToolButton); QToolButton::setIcon(icon); d->changeTheme(); } void KToolButton::setLoading(bool flag) { Q_D(KToolButton); if (!isEnabled()) return; if (hasArrow()) return; d->m_isLoading = flag; if (flag) d->m_pTimer->start(); else d->m_pTimer->stop(); } bool KToolButton::isLoading() { Q_D(KToolButton); return d->m_isLoading; } QIcon KToolButton::icon() { return QToolButton::icon(); } void KToolButton::setArrow(bool flag) { Q_D(KToolButton); if (!d->m_isLoading) d->m_hasArrow = flag; update(); } bool KToolButton::hasArrow() const { Q_D(const KToolButton); return d->m_hasArrow; } void KToolButton::setIconColor(bool flag, QColor color) { Q_D(KToolButton); d->m_isIconColor = flag; d->m_iconColor = color; update(); } void KToolButton::setBorderRadius(int bottomLeft, int topLeft, int topRight, int bottomRight) { Q_D(KToolButton); d->m_bottomLeftRadius = bottomLeft; d->m_topLeftRadius = topLeft; d->m_topRightRadius = topRight; d->m_bottomRightRadius = bottomRight; } void KToolButton::setBackgroundColorEnabled(bool flag) { Q_D(KToolButton); d->m_isBkgColorEnable = flag; } bool KToolButton::backgroundColorEnabled() { Q_D(KToolButton); return d->m_isBkgColorEnable; } bool KToolButton::eventFilter(QObject *watched, QEvent *event) { Q_D(KToolButton); QColor highlightColor = ThemeController::getCustomColorFromDT("highlight-active"); if (watched == this) { // 根据不同状态重绘icon颜色 if (highlightColor == Qt::transparent) { if (ThemeController::themeMode() == LightTheme) d->m_pixColor = ThemeController::getCustomColorFromDT("kgray-17"); else d->m_pixColor = ThemeController::getCustomColorFromDT("kwhite"); } else { switch (event->type()) { case QEvent::MouseButtonPress: if (isEnabled() && !d->m_isLoading) { if (ThemeController::themeMode() == LightTheme) d->m_pixColor = highlightColor.darker(120); else d->m_pixColor = highlightColor.lighter(120); } break; case QEvent::Enter: if (isEnabled() && !d->m_isLoading) { if (ThemeController::themeMode() == LightTheme) d->m_pixColor = highlightColor.darker(105); else d->m_pixColor = highlightColor.lighter(105); } break; case QEvent::FocusIn: if (isEnabled() && !d->m_isLoading) { if (ThemeController::themeMode() == LightTheme) d->m_pixColor = highlightColor.darker(120); else d->m_pixColor = highlightColor.lighter(120); } break; case QEvent::EnabledChange: { if (!isEnabled() && !d->m_isLoading) { if (d->m_isLoading) { d->m_isLoading = false; d->m_pTimer->stop(); } if (ThemeController::themeMode() == LightTheme) d->m_pixColor = ThemeController::getCustomColorFromDT("kgray-10"); else d->m_pixColor = ThemeController::getCustomColorFromDT("kgray-14"); } else if (isEnabled() && !d->m_isLoading) { if (ThemeController::themeMode() == LightTheme) d->m_pixColor = ThemeController::getCustomColorFromDT("kgray-17"); else d->m_pixColor = ThemeController::getCustomColorFromDT("kwhite"); } } break; case QEvent::MouseButtonRelease: if (isEnabled() && !d->m_isLoading) { if (ThemeController::themeMode() == LightTheme) d->m_pixColor = highlightColor.darker(105); else d->m_pixColor = highlightColor.lighter(105); } break; case QEvent::Leave: case QEvent::FocusOut: if (isEnabled() && !d->m_isLoading) { if (ThemeController::themeMode() == LightTheme) d->m_pixColor = ThemeController::getCustomColorFromDT("kgray-17"); else d->m_pixColor = ThemeController::getCustomColorFromDT("kwhite"); } break; default: break; } } } return QToolButton::eventFilter(watched, event); } QSize KToolButton::sizeHint() const { Q_D(const KToolButton); QSize size(Parmscontroller::parm(Parmscontroller::Parm::PM_ToolButtonHeight), Parmscontroller::parm(Parmscontroller::Parm::PM_ToolButtonHeight)); if (d->m_hasArrow) size.setWidth(Parmscontroller::parm(Parmscontroller::Parm::PM_ToolButtonHeight) + 24); return size; } void KToolButton::paintEvent(QPaintEvent *event) { Q_D(KToolButton); d->m_pLinearGradient.setStart(this->width() / 2, 0); d->m_pLinearGradient.setFinalStop(this->width() / 2, this->height()); QPainter painter(this); painter.setRenderHint(QPainter::SmoothPixmapTransform); // 绘制边框 QStyleOptionToolButton option; initStyleOption(&option); d->m_arrowPixmap = QIcon::fromTheme("ukui-down-symbolic").pixmap(option.iconSize); QPen pen; QColor color = ThemeController::getCustomColorFromDT("highlight-active"); pen.setColor(color); pen.setWidth(2); if (((QStyle::State_HasFocus & option.state) && isEnabled() && !isLoading() && (this->focusPolicy() != Qt::FocusPolicy::NoFocus)) && d->m_type != Frameless) painter.setPen(pen); else painter.setPen(Qt::NoPen); QColor startColor; QColor endColor; if(!isChecked()) { if (!isEnabled()) { if(type() != Flat) { ThemeController::getGradientFromDT("kcomponent-disable", startColor, endColor); d->m_pLinearGradient.setColorAt(0, startColor); d->m_pLinearGradient.setColorAt(1, endColor); painter.setBrush(d->m_pLinearGradient); } else { painter.setBrush(Qt::NoBrush); } } else if (QStyle::State_Sunken & option.state) { if(type() != Flat) { ThemeController::getGradientFromDT("kcomponent-click", startColor, endColor); d->m_pLinearGradient.setColorAt(0, startColor); d->m_pLinearGradient.setColorAt(1, endColor); painter.setBrush(d->m_pLinearGradient); } else { painter.setBrush(Qt::NoBrush); } } else if (QStyle::State_MouseOver & option.state) { if(type() != Flat) { ThemeController::getGradientFromDT("kcomponent-hover", startColor, endColor); d->m_pLinearGradient.setColorAt(0, startColor); d->m_pLinearGradient.setColorAt(1, endColor); painter.setBrush(d->m_pLinearGradient); } else { painter.setBrush(Qt::NoBrush); } } else { if(type() != Flat && type() != SemiFlat) { ThemeController::getGradientFromDT("kcomponent-normal", startColor, endColor); d->m_pLinearGradient.setColorAt(0, startColor); d->m_pLinearGradient.setColorAt(1, endColor); painter.setBrush(d->m_pLinearGradient); } else { painter.setBrush(Qt::NoBrush); } } } else { if (!isEnabled()) { ThemeController::getGradientFromDT("kbrand-disable", startColor, endColor); d->m_pLinearGradient.setColorAt(0, startColor); d->m_pLinearGradient.setColorAt(1, endColor); painter.setBrush(d->m_pLinearGradient); } else if (QStyle::State_Sunken & option.state) { ThemeController::getGradientFromDT("kbrand-click", startColor, endColor); d->m_pLinearGradient.setColorAt(0, startColor); d->m_pLinearGradient.setColorAt(1, endColor); painter.setBrush(d->m_pLinearGradient); } else if (QStyle::State_MouseOver & option.state) { ThemeController::getGradientFromDT("kbrand-hover", startColor, endColor); d->m_pLinearGradient.setColorAt(0, startColor); d->m_pLinearGradient.setColorAt(1, endColor); painter.setBrush(d->m_pLinearGradient); } else { ThemeController::getGradientFromDT("kbrand-normal", startColor, endColor); d->m_pLinearGradient.setColorAt(0, startColor); d->m_pLinearGradient.setColorAt(1, endColor); painter.setBrush(d->m_pLinearGradient); } } if (ThemeController::widgetTheme() == ClassicTheme) painter.drawRoundedRect(this->rect().adjusted(1, 1, -1, -1), 0, 0); else { QRect drawRect = this->rect().adjusted(1, 1, 0, 0); QPainterPath path; path.moveTo(drawRect.topLeft() + QPoint(0, d->m_topLeftRadius)); path.lineTo(drawRect.bottomLeft() - QPoint(0, d->m_bottomLeftRadius)); path.quadTo(drawRect.bottomLeft(), drawRect.bottomLeft() + QPoint(d->m_bottomLeftRadius, 0)); path.lineTo(drawRect.bottomRight() - QPoint(d->m_bottomRightRadius, 0)); path.quadTo(drawRect.bottomRight(), drawRect.bottomRight() - QPoint(0, d->m_bottomRightRadius)); path.lineTo(drawRect.topRight() + QPoint(0, d->m_topRightRadius)); path.quadTo(drawRect.topRight(), drawRect.topRight() - QPoint(d->m_topRightRadius, 0)); path.lineTo(drawRect.topLeft() + QPoint(d->m_topLeftRadius, 0)); path.quadTo(drawRect.topLeft(), drawRect.topLeft() + QPoint(0, d->m_topLeftRadius)); painter.drawPath(path); } // 绘制图标 QRect rect(0, 0, option.iconSize.width(), option.iconSize.height()); QPixmap pixmap = this->icon().pixmap(option.iconSize); if (!pixmap.isNull()) { if (ThemeController::isPixmapPureColor(pixmap)) { if(isChecked()) pixmap = ThemeController::drawColoredPixmap(pixmap, ThemeController::getCustomColorFromDT("kwhite")); else { if (d->m_type == KToolButtonType::Flat || !isEnabled()) pixmap = ThemeController::drawColoredPixmap(pixmap, d->m_pixColor); else if (ThemeController::themeMode() == DarkTheme) pixmap = ThemeController::drawSymbolicColoredPixmap(pixmap); } } } if (d->m_isIconColor) { pixmap = ThemeController::drawColoredPixmap(pixmap, d->m_iconColor); } if (!hasArrow()) { rect.moveCenter(this->rect().center()); painter.drawPixmap(rect, pixmap); } else { QRect newRect = this->rect().adjusted(0, 0, -20, 0); rect.moveCenter(newRect.center()); if (sizePolicy().horizontalPolicy() == QSizePolicy::Expanding) this->style()->drawItemPixmap(&painter, this->rect(), Qt::AlignCenter, pixmap); else this->style()->drawItemPixmap(&painter, rect, Qt::AlignCenter, pixmap); QRect arrowRect(0, 0, option.iconSize.width(), option.iconSize.height()); arrowRect.moveLeft(this->rect().width() - option.iconSize.width() - 8); arrowRect.moveTop((this->height() - option.iconSize.height()) / 2); QPixmap arrowPixmap = d->m_arrowPixmap; if(isChecked()) arrowPixmap = ThemeController::drawSymbolicColoredPixmap(arrowPixmap); else if (d->m_type == KToolButtonType::Flat || !isEnabled()) arrowPixmap = ThemeController::drawColoredPixmap(arrowPixmap, d->m_pixColor); else if (ThemeController::themeMode() == DarkTheme) arrowPixmap = ThemeController::drawSymbolicColoredPixmap(arrowPixmap); if(property("isWindowButton").toBool() && !isActiveWindow()) { if(ThemeController::themeMode() == LightTheme) { QIcon icon = QIcon::fromTheme("ukui-down-symbolic"); QIcon::State state = QIcon::Off; if (option.state & QStyle::State_On) state = QIcon::On; arrowPixmap = icon.pixmap(option.iconSize, QIcon::Disabled, state); } else { arrowPixmap = ThemeController::drawColoredPixmap(arrowPixmap,ThemeController::getCustomColorFromDT("kgray-14")); } } painter.drawPixmap(arrowRect, arrowPixmap); } } KToolButtonPrivate::KToolButtonPrivate(KToolButton *parent) : q_ptr(parent) , m_hasArrow(false) { m_isIconColor = false; setParent(parent); } void KToolButtonPrivate::changePalette() { Q_Q(KToolButton); } void KToolButtonPrivate::doLoadingFlash() { Q_Q(KToolButton); if (m_flashState < 7) m_flashState++; else m_flashState = 0; if (ThemeController::themeMode() == LightTheme) { q->QToolButton::setIcon(QIcon::fromTheme(QString("ukui-loading-%1.symbolic").arg(m_flashState))); } else { q->QToolButton::setIcon(ThemeController::drawColoredPixmap(QIcon::fromTheme(QString("ukui-loading-%1.symbolic").arg(m_flashState)).pixmap(q->iconSize()), ThemeController::getCustomColorFromDT("kwhite"))); } } void KToolButtonPrivate::changeTheme() { Q_Q(KToolButton); initThemeStyle(); changePalette(); if (ThemeController::themeMode() == LightTheme) { if (q->isEnabled()) m_pixColor = ThemeController::getCustomColorFromDT("kgray-17"); else m_pixColor = ThemeController::getCustomColorFromDT("kgray-10"); } else { if (q->isEnabled()) m_pixColor = ThemeController::getCustomColorFromDT("kwhite"); else m_pixColor = ThemeController::getCustomColorFromDT("kgray-14"); } } } #include "ktoolbutton.moc" #include "moc_ktoolbutton.cpp" libkysdk-applications/kysdk-qtwidgets/src/klunarcalendarinfo.cpp0000664000175000017500000012431415104543305024300 0ustar fengfeng/* * libkysdk-qtwidgets's Library * * Copyright (C) 2024, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhenyu Wang * */ #pragma execution_character_set("utf-8") #include "klunarcalendarinfo.h" #include "qmutex.h" #include #include #include #define year_2099 namespace kdk { QScopedPointer KLunarCalendarInfo::self; class KLunarCalendarInfoPrivate : public QObject { Q_DECLARE_PUBLIC(KLunarCalendarInfo) Q_OBJECT public: KLunarCalendarInfoPrivate(KLunarCalendarInfo *parent); private: KLunarCalendarInfo *q_ptr; QList lunarCalendarTable; // 农历年表 QList springFestival; // 春节公历日期 QList lunarData; // 农历每月数据 QList chineseTwentyFourData; // 农历二十四节气数据 QList monthAdd; // 公历每月前面的天数 QList listDayName; // 农历日期名称集合 QList listMonthName; // 农历月份名称集合 QList listSolarTerm; // 二十四节气名称集合 QList listTianGan; // 天干名称集合 QList listDiZhi; // 地支名称集合 QList listShuXiang; // 属相名称集合 }; KLunarCalendarInfoPrivate::KLunarCalendarInfoPrivate(KLunarCalendarInfo *parent) : q_ptr(parent) { Q_Q(KLunarCalendarInfo); // 农历查表 lunarCalendarTable << 0x04AE53 << 0x0A5748 << 0x5526BD << 0x0D2650 << 0x0D9544 << 0x46AAB9 << 0x056A4D << 0x09AD42 << 0x24AEB6 << 0x04AE4A; // 1901-1910 lunarCalendarTable << 0x6A4DBE << 0x0A4D52 << 0x0D2546 << 0x5D52BA << 0x0B544E << 0x0D6A43 << 0x296D37 << 0x095B4B << 0x749BC1 << 0x049754; // 1911-1920 lunarCalendarTable << 0x0A4B48 << 0x5B25BC << 0x06A550 << 0x06D445 << 0x4ADAB8 << 0x02B64D << 0x095742 << 0x2497B7 << 0x04974A << 0x664B3E; // 1921-1930 lunarCalendarTable << 0x0D4A51 << 0x0EA546 << 0x56D4BA << 0x05AD4E << 0x02B644 << 0x393738 << 0x092E4B << 0x7C96BF << 0x0C9553 << 0x0D4A48; // 1931-1940 lunarCalendarTable << 0x6DA53B << 0x0B554F << 0x056A45 << 0x4AADB9 << 0x025D4D << 0x092D42 << 0x2C95B6 << 0x0A954A << 0x7B4ABD << 0x06CA51; // 1941-1950 lunarCalendarTable << 0x0B5546 << 0x555ABB << 0x04DA4E << 0x0A5B43 << 0x352BB8 << 0x052B4C << 0x8A953F << 0x0E9552 << 0x06AA48 << 0x6AD53C; // 1951-1960 lunarCalendarTable << 0x0AB54F << 0x04B645 << 0x4A5739 << 0x0A574D << 0x052642 << 0x3E9335 << 0x0D9549 << 0x75AABE << 0x056A51 << 0x096D46; // 1961-1970 lunarCalendarTable << 0x54AEBB << 0x04AD4F << 0x0A4D43 << 0x4D26B7 << 0x0D254B << 0x8D52BF << 0x0B5452 << 0x0B6A47 << 0x696D3C << 0x095B50; // 1971-1980 lunarCalendarTable << 0x049B45 << 0x4A4BB9 << 0x0A4B4D << 0xAB25C2 << 0x06A554 << 0x06D449 << 0x6ADA3D << 0x0AB651 << 0x093746 << 0x5497BB; // 1981-1990 lunarCalendarTable << 0x04974F << 0x064B44 << 0x36A537 << 0x0EA54A << 0x86B2BF << 0x05AC53 << 0x0AB647 << 0x5936BC << 0x092E50 << 0x0C9645; // 1991-2000 lunarCalendarTable << 0x4D4AB8 << 0x0D4A4C << 0x0DA541 << 0x25AAB6 << 0x056A49 << 0x7AADBD << 0x025D52 << 0x092D47 << 0x5C95BA << 0x0A954E; // 2001-2010 lunarCalendarTable << 0x0B4A43 << 0x4B5537 << 0x0AD54A << 0x955ABF << 0x04BA53 << 0x0A5B48 << 0x652BBC << 0x052B50 << 0x0A9345 << 0x474AB9; // 2011-2020 lunarCalendarTable << 0x06AA4C << 0x0AD541 << 0x24DAB6 << 0x04B64A << 0x69573D << 0x0A4E51 << 0x0D2646 << 0x5E933A << 0x0D534D << 0x05AA43; // 2021-2030 lunarCalendarTable << 0x36B537 << 0x096D4B << 0xB4AEBF << 0x04AD53 << 0x0A4D48 << 0x6D25BC << 0x0D254F << 0x0D5244 << 0x5DAA38 << 0x0B5A4C; // 2031-2040 lunarCalendarTable << 0x056D41 << 0x24ADB6 << 0x049B4A << 0x7A4BBE << 0x0A4B51 << 0x0AA546 << 0x5B52BA << 0x06D24E << 0x0ADA42 << 0x355B37; // 2041-2050 lunarCalendarTable << 0x09374B << 0x8497C1 << 0x049753 << 0x064B48 << 0x66A53C << 0x0EA54F << 0x06B244 << 0x4AB638 << 0x0AAE4C << 0x092E42; // 2051-2060 lunarCalendarTable << 0x3C9735 << 0x0C9649 << 0x7D4ABD << 0x0D4A51 << 0x0DA545 << 0x55AABA << 0x056A4E << 0x0A6D43 << 0x452EB7 << 0x052D4B; // 2061-2070 lunarCalendarTable << 0x8A95BF << 0x0A9553 << 0x0B4A47 << 0x6B553B << 0x0AD54F << 0x055A45 << 0x4A5D38 << 0x0A5B4C << 0x052B42 << 0x3A93B6; // 2071-2080 lunarCalendarTable << 0x069349 << 0x7729BD << 0x06AA51 << 0x0AD546 << 0x54DABA << 0x04B64E << 0x0A5743 << 0x452738 << 0x0D264A << 0x8E933E; // 2081-2090 lunarCalendarTable << 0x0D5252 << 0x0DAA47 << 0x66B53B << 0x056D4F << 0x04AE45 << 0x4A4EB9 << 0x0A4D4C << 0x0D1541 << 0x2D92B5; // 2091-2099 // 每年春节对应的公历日期 springFestival << 130 << 217 << 206; // 1968 1969 1970 springFestival << 127 << 215 << 203 << 123 << 211 << 131 << 218 << 207 << 128 << 216; // 1971--1980 springFestival << 205 << 125 << 213 << 202 << 220 << 209 << 219 << 217 << 206 << 127; // 1981--1990 springFestival << 215 << 204 << 123 << 210 << 131 << 219 << 207 << 128 << 216 << 205; // 1991--2000 springFestival << 124 << 212 << 201 << 122 << 209 << 129 << 218 << 207 << 126 << 214; // 2001--2010 springFestival << 203 << 123 << 210 << 131 << 219 << 208 << 128 << 216 << 205 << 125; // 2011--2020 springFestival << 212 << 201 << 122 << 210 << 129 << 217 << 206 << 126 << 213 << 203; // 2021--2030 springFestival << 123 << 211 << 131 << 219 << 208 << 128 << 215 << 204 << 124 << 212; // 2031--2040 // 16--18位表示闰几月 0--12位表示农历每月的数据 高位表示1月 低位表示12月(农历闰月就会多一个月) lunarData << 461653 << 1386 << 2413; // 1968 1969 1970 lunarData << 330077 << 1197 << 2637 << 268877 << 3365 << 531109 << 2900 << 2922 << 398042 << 2395; // 1971--1980 lunarData << 1179 << 267415 << 2635 << 661067 << 1701 << 1748 << 398772 << 2742 << 2391 << 330031; // 1981--1990 lunarData << 1175 << 1611 << 200010 << 3749 << 527717 << 1452 << 2742 << 332397 << 2350 << 3222; // 1991--2000 lunarData << 268949 << 3402 << 3493 << 133973 << 1386 << 464219 << 605 << 2349 << 334123 << 2709; // 2001--2010 lunarData << 2890 << 267946 << 2773 << 592565 << 1210 << 2651 << 395863 << 1323 << 2707 << 265877; // 2011--2020 lunarData << 1706 << 2773 << 133557 << 1206 << 398510 << 2638 << 3366 << 335142 << 3411 << 1450; // 2021--2030 lunarData << 200042 << 2413 << 723293 << 1197 << 2637 << 399947 << 3365 << 3410 << 334676 << 2906; // 2031--2040 // 二十四节气表 chineseTwentyFourData << 0x95 << 0xB4 << 0x96 << 0xA5 << 0x96 << 0x97 << 0x88 << 0x78 << 0x78 << 0x69 << 0x78 << 0x87; // 1970 chineseTwentyFourData << 0x96 << 0xB4 << 0x96 << 0xA6 << 0x97 << 0x97 << 0x78 << 0x79 << 0x79 << 0x69 << 0x78 << 0x77; // 1971 chineseTwentyFourData << 0x96 << 0xA4 << 0xA5 << 0xA5 << 0xA6 << 0xA6 << 0x88 << 0x88 << 0x88 << 0x78 << 0x87 << 0x87; // 1972 chineseTwentyFourData << 0xA5 << 0xB5 << 0x96 << 0xA5 << 0xA6 << 0x96 << 0x88 << 0x78 << 0x78 << 0x78 << 0x87 << 0x87; // 1973 chineseTwentyFourData << 0x95 << 0xB4 << 0x96 << 0xA5 << 0x96 << 0x97 << 0x88 << 0x78 << 0x78 << 0x69 << 0x78 << 0x87; // 1974 chineseTwentyFourData << 0x96 << 0xB4 << 0x96 << 0xA6 << 0x97 << 0x97 << 0x78 << 0x79 << 0x78 << 0x69 << 0x78 << 0x77; // 1975 chineseTwentyFourData << 0x96 << 0xA4 << 0xA5 << 0xB5 << 0xA6 << 0xA6 << 0x88 << 0x89 << 0x88 << 0x78 << 0x87 << 0x87; // 1976 chineseTwentyFourData << 0xA5 << 0xB4 << 0x96 << 0xA5 << 0x96 << 0x96 << 0x88 << 0x88 << 0x78 << 0x78 << 0x87 << 0x87; // 1977 chineseTwentyFourData << 0x95 << 0xB4 << 0x96 << 0xA5 << 0x96 << 0x97 << 0x88 << 0x78 << 0x78 << 0x79 << 0x78 << 0x87; // 1978 chineseTwentyFourData << 0x96 << 0xB4 << 0x96 << 0xA6 << 0x96 << 0x97 << 0x78 << 0x79 << 0x78 << 0x69 << 0x78 << 0x77; // 1979 chineseTwentyFourData << 0x96 << 0xA4 << 0xA5 << 0xB5 << 0xA6 << 0xA6 << 0x88 << 0x88 << 0x88 << 0x78 << 0x87 << 0x87; // 1980 chineseTwentyFourData << 0xA5 << 0xB4 << 0x96 << 0xA5 << 0xA6 << 0x96 << 0x88 << 0x88 << 0x78 << 0x78 << 0x77 << 0x87; // 1981 chineseTwentyFourData << 0x95 << 0xB4 << 0x96 << 0xA5 << 0x96 << 0x97 << 0x88 << 0x78 << 0x78 << 0x79 << 0x77 << 0x87; // 1982 chineseTwentyFourData << 0x95 << 0xB4 << 0x96 << 0xA5 << 0x96 << 0x97 << 0x78 << 0x79 << 0x78 << 0x69 << 0x78 << 0x77; // 1983 chineseTwentyFourData << 0x96 << 0xB4 << 0xA5 << 0xB5 << 0xA6 << 0xA6 << 0x87 << 0x88 << 0x88 << 0x78 << 0x87 << 0x87; // 1984 chineseTwentyFourData << 0xA5 << 0xB4 << 0xA6 << 0xA5 << 0xA6 << 0x96 << 0x88 << 0x88 << 0x78 << 0x78 << 0x87 << 0x87; // 1985 chineseTwentyFourData << 0xA5 << 0xB4 << 0x96 << 0xA5 << 0x96 << 0x97 << 0x88 << 0x78 << 0x78 << 0x79 << 0x77 << 0x87; // 1986 chineseTwentyFourData << 0x95 << 0xB4 << 0x96 << 0xA5 << 0x96 << 0x97 << 0x88 << 0x79 << 0x78 << 0x69 << 0x78 << 0x87; // 1987 chineseTwentyFourData << 0x96 << 0xB4 << 0xA5 << 0xB5 << 0xA6 << 0xA6 << 0x87 << 0x88 << 0x88 << 0x78 << 0x87 << 0x86; // 1988 chineseTwentyFourData << 0xA5 << 0xB4 << 0xA5 << 0xA5 << 0xA6 << 0x96 << 0x88 << 0x88 << 0x88 << 0x78 << 0x87 << 0x87; // 1989 chineseTwentyFourData << 0xA5 << 0xB4 << 0x96 << 0xA5 << 0x96 << 0x96 << 0x88 << 0x78 << 0x78 << 0x79 << 0x77 << 0x87; // 1990 chineseTwentyFourData << 0x95 << 0xB4 << 0x96 << 0xA5 << 0x86 << 0x97 << 0x88 << 0x78 << 0x78 << 0x69 << 0x78 << 0x87; // 1991 chineseTwentyFourData << 0x96 << 0xB4 << 0xA5 << 0xB5 << 0xA6 << 0xA6 << 0x87 << 0x88 << 0x88 << 0x78 << 0x87 << 0x86; // 1992 chineseTwentyFourData << 0xA5 << 0xB3 << 0xA5 << 0xA5 << 0xA6 << 0x96 << 0x88 << 0x88 << 0x88 << 0x78 << 0x87 << 0x87; // 1993 chineseTwentyFourData << 0xA5 << 0xB4 << 0x96 << 0xA5 << 0x96 << 0x96 << 0x88 << 0x78 << 0x78 << 0x78 << 0x87 << 0x87; // 1994 chineseTwentyFourData << 0x95 << 0xB4 << 0x96 << 0xA5 << 0x96 << 0x97 << 0x88 << 0x76 << 0x78 << 0x69 << 0x78 << 0x87; // 1995 chineseTwentyFourData << 0x96 << 0xB4 << 0xA5 << 0xB5 << 0xA6 << 0xA6 << 0x87 << 0x88 << 0x88 << 0x78 << 0x87 << 0x86; // 1996 chineseTwentyFourData << 0xA5 << 0xB3 << 0xA5 << 0xA5 << 0xA6 << 0xA6 << 0x88 << 0x88 << 0x88 << 0x78 << 0x87 << 0x87; // 1997 chineseTwentyFourData << 0xA5 << 0xB4 << 0x96 << 0xA5 << 0x96 << 0x96 << 0x88 << 0x78 << 0x78 << 0x78 << 0x87 << 0x87; // 1998 chineseTwentyFourData << 0x95 << 0xB4 << 0x96 << 0xA5 << 0x96 << 0x97 << 0x88 << 0x78 << 0x78 << 0x69 << 0x78 << 0x87; // 1999 chineseTwentyFourData << 0x96 << 0xB4 << 0xA5 << 0xB5 << 0xA6 << 0xA6 << 0x87 << 0x88 << 0x88 << 0x78 << 0x87 << 0x86; // 2000 chineseTwentyFourData << 0xA5 << 0xB3 << 0xA5 << 0xA5 << 0xA6 << 0xA6 << 0x88 << 0x88 << 0x88 << 0x78 << 0x87 << 0x87; // 2001 chineseTwentyFourData << 0xA5 << 0xB4 << 0x96 << 0xA5 << 0x96 << 0x96 << 0x88 << 0x78 << 0x78 << 0x78 << 0x87 << 0x87; // 2002 chineseTwentyFourData << 0x95 << 0xB4 << 0x96 << 0xA5 << 0x96 << 0x97 << 0x88 << 0x78 << 0x78 << 0x69 << 0x78 << 0x87; // 2003 chineseTwentyFourData << 0x96 << 0xB4 << 0xA5 << 0xB5 << 0xA6 << 0xA6 << 0x87 << 0x88 << 0x88 << 0x78 << 0x87 << 0x86; // 2004 chineseTwentyFourData << 0xA5 << 0xB3 << 0xA5 << 0xA5 << 0xA6 << 0xA6 << 0x88 << 0x88 << 0x88 << 0x78 << 0x87 << 0x87; // 2005 chineseTwentyFourData << 0xA5 << 0xB4 << 0x96 << 0xA5 << 0xA6 << 0x96 << 0x88 << 0x88 << 0x78 << 0x78 << 0x87 << 0x87; // 2006 chineseTwentyFourData << 0x95 << 0xB4 << 0x96 << 0xA5 << 0x96 << 0x97 << 0x88 << 0x78 << 0x78 << 0x69 << 0x78 << 0x87; // 2007 chineseTwentyFourData << 0x96 << 0xB4 << 0xA5 << 0xB5 << 0xA6 << 0xA6 << 0x87 << 0x88 << 0x87 << 0x78 << 0x87 << 0x86; // 2008 chineseTwentyFourData << 0xA5 << 0xB3 << 0xA5 << 0xB5 << 0xA6 << 0xA6 << 0x88 << 0x88 << 0x88 << 0x78 << 0x87 << 0x87; // 2009 chineseTwentyFourData << 0xA5 << 0xB4 << 0x96 << 0xA5 << 0xA6 << 0x96 << 0x88 << 0x88 << 0x78 << 0x78 << 0x87 << 0x87; // 2010 chineseTwentyFourData << 0x95 << 0xB4 << 0x96 << 0xA5 << 0x96 << 0x97 << 0x88 << 0x78 << 0x78 << 0x79 << 0x78 << 0x87; // 2011 chineseTwentyFourData << 0x96 << 0xB4 << 0xA5 << 0xB5 << 0xA5 << 0xA6 << 0x87 << 0x88 << 0x87 << 0x78 << 0x87 << 0x86; // 2012 chineseTwentyFourData << 0xA5 << 0xB3 << 0xA5 << 0xB5 << 0xA6 << 0xA6 << 0x87 << 0x88 << 0x88 << 0x78 << 0x87 << 0x87; // 2013 chineseTwentyFourData << 0xA5 << 0xB4 << 0x96 << 0xA5 << 0xA6 << 0x96 << 0x88 << 0x88 << 0x78 << 0x78 << 0x87 << 0x87; // 2014 chineseTwentyFourData << 0x95 << 0xB4 << 0x96 << 0xA5 << 0x96 << 0x97 << 0x88 << 0x78 << 0x78 << 0x79 << 0x77 << 0x87; // 2015 chineseTwentyFourData << 0x95 << 0xB4 << 0xA5 << 0xB4 << 0xA5 << 0xA6 << 0x87 << 0x88 << 0x87 << 0x78 << 0x87 << 0x86; // 2016 chineseTwentyFourData << 0xA5 << 0xC3 << 0xA5 << 0xB5 << 0xA6 << 0xA6 << 0x87 << 0x88 << 0x88 << 0x78 << 0x87 << 0x87; // 2017 chineseTwentyFourData << 0xA5 << 0xB4 << 0xA6 << 0xA5 << 0xA6 << 0x96 << 0x88 << 0x88 << 0x78 << 0x78 << 0x87 << 0x87; // 2018 chineseTwentyFourData << 0xA5 << 0xB4 << 0x96 << 0xA5 << 0x96 << 0x96 << 0x88 << 0x78 << 0x78 << 0x79 << 0x77 << 0x87; // 2019 chineseTwentyFourData << 0x95 << 0xB4 << 0xA5 << 0xB4 << 0xA5 << 0xA6 << 0x97 << 0x87 << 0x87 << 0x78 << 0x87 << 0x86; // 2020 chineseTwentyFourData << 0xA5 << 0xC3 << 0xA5 << 0xB5 << 0xA6 << 0xA6 << 0x87 << 0x88 << 0x88 << 0x78 << 0x87 << 0x86; // 2021 chineseTwentyFourData << 0xA5 << 0xB4 << 0xA5 << 0xA5 << 0xA6 << 0x96 << 0x88 << 0x88 << 0x88 << 0x78 << 0x87 << 0x87; // 2022 chineseTwentyFourData << 0xA5 << 0xB4 << 0x96 << 0xA5 << 0x96 << 0x96 << 0x88 << 0x78 << 0x78 << 0x79 << 0x77 << 0x87; // 2023 chineseTwentyFourData << 0x95 << 0xB4 << 0xA5 << 0xB4 << 0xA5 << 0xA6 << 0x97 << 0x87 << 0x87 << 0x78 << 0x87 << 0x96; // 2024 chineseTwentyFourData << 0xA5 << 0xC3 << 0xA5 << 0xB5 << 0xA6 << 0xA6 << 0x87 << 0x88 << 0x88 << 0x78 << 0x87 << 0x86; // 2025 chineseTwentyFourData << 0xA5 << 0xB3 << 0xA5 << 0xA5 << 0xA6 << 0xA6 << 0x88 << 0x88 << 0x88 << 0x78 << 0x87 << 0x87; // 2026 chineseTwentyFourData << 0xA5 << 0xB4 << 0x96 << 0xA5 << 0x96 << 0x96 << 0x88 << 0x78 << 0x78 << 0x78 << 0x87 << 0x87; // 2027 chineseTwentyFourData << 0x95 << 0xB4 << 0xA5 << 0xB4 << 0xA5 << 0xA6 << 0x97 << 0x87 << 0x87 << 0x78 << 0x87 << 0x96; // 2028 chineseTwentyFourData << 0xA5 << 0xC3 << 0xA5 << 0xB5 << 0xA6 << 0xA6 << 0x87 << 0x88 << 0x88 << 0x78 << 0x87 << 0x86; // 2029 chineseTwentyFourData << 0xA5 << 0xB3 << 0xA5 << 0xA5 << 0xA6 << 0xA6 << 0x88 << 0x88 << 0x88 << 0x78 << 0x87 << 0x87; // 2030 chineseTwentyFourData << 0xA5 << 0xB4 << 0x96 << 0xA5 << 0x96 << 0x96 << 0x88 << 0x78 << 0x78 << 0x78 << 0x87 << 0x87; // 2031 chineseTwentyFourData << 0x95 << 0xB4 << 0xA5 << 0xB4 << 0xA5 << 0xA6 << 0x97 << 0x87 << 0x87 << 0x78 << 0x87 << 0x96; // 2032 chineseTwentyFourData << 0xA5 << 0xC3 << 0xA5 << 0xB5 << 0xA6 << 0xA6 << 0x88 << 0x88 << 0x88 << 0x78 << 0x87 << 0x86; // 2033 chineseTwentyFourData << 0xA5 << 0xB3 << 0xA5 << 0xA5 << 0xA6 << 0xA6 << 0x88 << 0x78 << 0x88 << 0x78 << 0x87 << 0x87; // 2034 chineseTwentyFourData << 0xA5 << 0xB4 << 0x96 << 0xA5 << 0xA6 << 0x96 << 0x88 << 0x88 << 0x78 << 0x78 << 0x87 << 0x87; // 2035 chineseTwentyFourData << 0x95 << 0xB4 << 0xA5 << 0xB4 << 0xA5 << 0xA6 << 0x97 << 0x87 << 0x87 << 0x78 << 0x87 << 0x96; // 2036 chineseTwentyFourData << 0xA5 << 0xC3 << 0xA5 << 0xB5 << 0xA6 << 0xA6 << 0x87 << 0x88 << 0x88 << 0x78 << 0x87 << 0x86; // 2037 chineseTwentyFourData << 0xA5 << 0xB3 << 0xA5 << 0xA5 << 0xA6 << 0xA6 << 0x88 << 0x88 << 0x88 << 0x78 << 0x87 << 0x87; // 2038 chineseTwentyFourData << 0xA5 << 0xB4 << 0x96 << 0xA5 << 0xA6 << 0x96 << 0x88 << 0x88 << 0x78 << 0x78 << 0x87 << 0x87; // 2039 chineseTwentyFourData << 0x95 << 0xB4 << 0x96 << 0xA5 << 0x96 << 0x97 << 0x88 << 0x78 << 0x78 << 0x69 << 0x78 << 0x87; // 2040 chineseTwentyFourData << 0xA5 << 0xC3 << 0xA5 << 0xB5 << 0xA5 << 0xA6 << 0x87 << 0x88 << 0x87 << 0x78 << 0x87 << 0x86; // 2041 chineseTwentyFourData << 0xA5 << 0xB3 << 0xA5 << 0xB5 << 0xA6 << 0xA6 << 0x88 << 0x88 << 0x88 << 0x78 << 0x87 << 0x87; // 2042 chineseTwentyFourData << 0xA5 << 0xB4 << 0x96 << 0xA5 << 0xA6 << 0x96 << 0x88 << 0x88 << 0x78 << 0x78 << 0x87 << 0x87; // 2043 chineseTwentyFourData << 0x95 << 0xB4 << 0x96 << 0xA5 << 0x96 << 0x97 << 0x88 << 0x78 << 0x78 << 0x79 << 0x78 << 0x87; // 2044 chineseTwentyFourData << 0xA5 << 0xC3 << 0xA5 << 0xB4 << 0xA5 << 0xA6 << 0x87 << 0x88 << 0x87 << 0x78 << 0x87 << 0x86; // 2045 chineseTwentyFourData << 0xA5 << 0xB3 << 0xA5 << 0xB5 << 0xA6 << 0xA6 << 0x87 << 0x88 << 0x88 << 0x78 << 0x87 << 0x87; // 2046 chineseTwentyFourData << 0xA5 << 0xB4 << 0x96 << 0xA5 << 0xA6 << 0x96 << 0x88 << 0x88 << 0x78 << 0x78 << 0x87 << 0x87; // 2047 chineseTwentyFourData << 0x95 << 0xB4 << 0x96 << 0xA5 << 0x96 << 0x96 << 0x88 << 0x78 << 0x78 << 0x79 << 0x77 << 0x87; // 2048 chineseTwentyFourData << 0xA4 << 0xC3 << 0xA5 << 0xB4 << 0xA5 << 0xA6 << 0x97 << 0x87 << 0x87 << 0x78 << 0x87 << 0x86; // 2049 chineseTwentyFourData << 0xA5 << 0xC3 << 0xA5 << 0xB5 << 0xA6 << 0xA6 << 0x87 << 0x88 << 0x88 << 0x78 << 0x87 << 0x87; // 2050 chineseTwentyFourData << 0xA5 << 0xB4 << 0xA5 << 0xA5 << 0xA6 << 0x96 << 0x88 << 0x88 << 0x88 << 0x78 << 0x87 << 0x87; // 2051 chineseTwentyFourData << 0xA5 << 0xB4 << 0x96 << 0xA5 << 0x96 << 0x96 << 0x88 << 0x78 << 0x78 << 0x79 << 0x77 << 0x87; // 2052 chineseTwentyFourData << 0xA4 << 0xC3 << 0xA5 << 0xB4 << 0xA5 << 0xA6 << 0x97 << 0x87 << 0x87 << 0x78 << 0x87 << 0x86; // 2053 chineseTwentyFourData << 0xA5 << 0xC3 << 0xA5 << 0xB5 << 0xA6 << 0xA6 << 0x87 << 0x88 << 0x88 << 0x78 << 0x87 << 0x87; // 2054 chineseTwentyFourData << 0xA5 << 0xB4 << 0xA5 << 0xA5 << 0xA6 << 0xA6 << 0x88 << 0x88 << 0x88 << 0x78 << 0x87 << 0x87; // 2055 chineseTwentyFourData << 0xA5 << 0xB4 << 0x96 << 0xA5 << 0x96 << 0x96 << 0x88 << 0x78 << 0x78 << 0x79 << 0x77 << 0x87; // 2056 chineseTwentyFourData << 0xA4 << 0xC3 << 0xA5 << 0xB4 << 0xA5 << 0xA6 << 0x97 << 0x87 << 0x87 << 0x78 << 0x87 << 0x96; // 2057 chineseTwentyFourData << 0xA5 << 0xC3 << 0xA5 << 0xB5 << 0xA6 << 0xA6 << 0x87 << 0x88 << 0x88 << 0x78 << 0x87 << 0x86; // 2058 chineseTwentyFourData << 0xA5 << 0xB4 << 0xA5 << 0xA5 << 0xA6 << 0xA6 << 0x88 << 0x88 << 0x88 << 0x78 << 0x87 << 0x87; // 2059 chineseTwentyFourData << 0xA5 << 0xB4 << 0x96 << 0xA5 << 0x96 << 0x96 << 0x88 << 0x78 << 0x78 << 0x78 << 0x87 << 0x87; // 2060 chineseTwentyFourData << 0xA4 << 0xC3 << 0xA5 << 0xB4 << 0xA5 << 0xA6 << 0x97 << 0x87 << 0x87 << 0x78 << 0x87 << 0x96; // 2061 chineseTwentyFourData << 0xA5 << 0xC3 << 0xA5 << 0xB5 << 0xA6 << 0xA6 << 0x87 << 0x88 << 0x88 << 0x78 << 0x87 << 0x86; // 2062 chineseTwentyFourData << 0xA5 << 0xB3 << 0xA5 << 0xA5 << 0xA6 << 0xA6 << 0x88 << 0x88 << 0x88 << 0x78 << 0x87 << 0x87; // 2063 chineseTwentyFourData << 0xA5 << 0xB4 << 0x96 << 0xA5 << 0x96 << 0x96 << 0x88 << 0x78 << 0x78 << 0x78 << 0x87 << 0x87; // 2064 chineseTwentyFourData << 0xA4 << 0xC3 << 0xA5 << 0xB4 << 0xA5 << 0xA6 << 0x97 << 0x87 << 0x87 << 0x78 << 0x87 << 0x96; // 2065 chineseTwentyFourData << 0xA5 << 0xC3 << 0xA5 << 0xB5 << 0xA6 << 0xA6 << 0x87 << 0x88 << 0x88 << 0x78 << 0x87 << 0x86; // 2066 chineseTwentyFourData << 0xA5 << 0xB3 << 0xA5 << 0xA5 << 0xA6 << 0xA6 << 0x88 << 0x88 << 0x88 << 0x78 << 0x87 << 0x87; // 2067 chineseTwentyFourData << 0xA5 << 0xB4 << 0x96 << 0xA5 << 0xA6 << 0x96 << 0x88 << 0x88 << 0x78 << 0x78 << 0x87 << 0x87; // 2068 chineseTwentyFourData << 0xA4 << 0xC3 << 0xA5 << 0xB4 << 0xA5 << 0xA6 << 0x97 << 0x87 << 0x87 << 0x78 << 0x87 << 0x96; // 2069 chineseTwentyFourData << 0xA5 << 0xC3 << 0xA5 << 0xB5 << 0xA5 << 0xA6 << 0x87 << 0x88 << 0x87 << 0x78 << 0x87 << 0x86; // 2070 chineseTwentyFourData << 0xA5 << 0xB3 << 0xA5 << 0xA5 << 0xA6 << 0xA6 << 0x88 << 0x88 << 0x88 << 0x78 << 0x87 << 0x87; // 2071 chineseTwentyFourData << 0xA5 << 0xB4 << 0x96 << 0xA5 << 0xA6 << 0x96 << 0x88 << 0x88 << 0x78 << 0x78 << 0x87 << 0x87; // 2072 chineseTwentyFourData << 0xA4 << 0xC3 << 0xA5 << 0xB4 << 0xA5 << 0xA6 << 0x97 << 0x87 << 0x87 << 0x88 << 0x87 << 0x96; // 2073 chineseTwentyFourData << 0xA5 << 0xC3 << 0xA5 << 0xB5 << 0xA5 << 0xA6 << 0x87 << 0x88 << 0x87 << 0x78 << 0x87 << 0x86; // 2074 chineseTwentyFourData << 0xA5 << 0xB3 << 0xA5 << 0xB5 << 0xA6 << 0xA6 << 0x87 << 0x88 << 0x88 << 0x78 << 0x87 << 0x87; // 2075 chineseTwentyFourData << 0xA5 << 0xB4 << 0x96 << 0xA5 << 0xA6 << 0x96 << 0x88 << 0x88 << 0x78 << 0x78 << 0x87 << 0x87; // 2076 chineseTwentyFourData << 0xA4 << 0xC3 << 0xA5 << 0xB4 << 0xA5 << 0xA6 << 0x97 << 0x87 << 0x87 << 0x88 << 0x87 << 0x96; // 2077 chineseTwentyFourData << 0xA5 << 0xC3 << 0xA5 << 0xB4 << 0xA5 << 0xA6 << 0x97 << 0x88 << 0x87 << 0x78 << 0x87 << 0x86; // 2078 chineseTwentyFourData << 0xA5 << 0xB3 << 0xA5 << 0xB5 << 0xA6 << 0xA6 << 0x87 << 0x88 << 0x88 << 0x78 << 0x87 << 0x87; // 2079 chineseTwentyFourData << 0xA5 << 0xB4 << 0x96 << 0xA5 << 0xA6 << 0x96 << 0x88 << 0x88 << 0x78 << 0x78 << 0x87 << 0x87; // 2080 chineseTwentyFourData << 0xA4 << 0xC3 << 0xA5 << 0xB4 << 0xA5 << 0xA5 << 0x97 << 0x87 << 0x87 << 0x88 << 0x86 << 0x96; // 2081 chineseTwentyFourData << 0xA5 << 0xC3 << 0xA5 << 0xB4 << 0xA5 << 0xA6 << 0x97 << 0x87 << 0x87 << 0x78 << 0x87 << 0x86; // 2082 chineseTwentyFourData << 0xA5 << 0xC3 << 0xA5 << 0xB5 << 0xA6 << 0xA6 << 0x87 << 0x88 << 0x88 << 0x78 << 0x87 << 0x87; // 2083 chineseTwentyFourData << 0xA5 << 0xB4 << 0xA6 << 0xA5 << 0xA6 << 0x96 << 0x88 << 0x88 << 0x88 << 0x78 << 0x87 << 0x87; // 2084 chineseTwentyFourData << 0xB4 << 0xC3 << 0xA5 << 0xB4 << 0xA5 << 0xA5 << 0x97 << 0x87 << 0x87 << 0x88 << 0x86 << 0x96; // 2085 chineseTwentyFourData << 0xA4 << 0xC3 << 0xA5 << 0xB4 << 0xA5 << 0xA6 << 0x97 << 0x87 << 0x87 << 0x78 << 0x87 << 0x86; // 2086 chineseTwentyFourData << 0xA5 << 0xC3 << 0xA5 << 0xB5 << 0xA6 << 0xA6 << 0x87 << 0x88 << 0x88 << 0x78 << 0x87 << 0x87; // 2087 chineseTwentyFourData << 0xA5 << 0xB4 << 0xA5 << 0xA5 << 0xA6 << 0xA6 << 0x88 << 0x88 << 0x88 << 0x78 << 0x87 << 0x87; // 2088 chineseTwentyFourData << 0xB4 << 0xC3 << 0xA5 << 0xB4 << 0xA5 << 0xA5 << 0x97 << 0x87 << 0x87 << 0x88 << 0x96 << 0x96; // 2089 chineseTwentyFourData << 0xA4 << 0xC3 << 0xA5 << 0xB4 << 0xA5 << 0xA6 << 0x97 << 0x87 << 0x87 << 0x78 << 0x87 << 0x96; // 2090 chineseTwentyFourData << 0xA5 << 0xC3 << 0xA5 << 0xB5 << 0xA6 << 0xA6 << 0x87 << 0x88 << 0x88 << 0x78 << 0x87 << 0x86; // 2091 chineseTwentyFourData << 0xA5 << 0xB4 << 0xA5 << 0xA5 << 0xA6 << 0xA6 << 0x88 << 0x88 << 0x88 << 0x78 << 0x87 << 0x87; // 2092 chineseTwentyFourData << 0xB4 << 0xC3 << 0xA5 << 0xB4 << 0xA5 << 0xA5 << 0x97 << 0x87 << 0x87 << 0x87 << 0x96 << 0x96; // 2093 chineseTwentyFourData << 0xA4 << 0xC3 << 0xA5 << 0xB4 << 0xA5 << 0xA6 << 0x97 << 0x87 << 0x87 << 0x78 << 0x87 << 0x96; // 2094 chineseTwentyFourData << 0xA5 << 0xC3 << 0xA5 << 0xB5 << 0xA6 << 0xA6 << 0x87 << 0x88 << 0x88 << 0x78 << 0x87 << 0x86; // 2095 chineseTwentyFourData << 0xA5 << 0xB3 << 0xA5 << 0xA5 << 0xA6 << 0xA6 << 0x88 << 0x88 << 0x88 << 0x78 << 0x87 << 0x87; // 2096 chineseTwentyFourData << 0xB4 << 0xC3 << 0xA5 << 0xB4 << 0xA5 << 0xA5 << 0x97 << 0x97 << 0x87 << 0x87 << 0x96 << 0x96; // 2097 chineseTwentyFourData << 0xA4 << 0xC3 << 0xA5 << 0xB4 << 0xA5 << 0xA6 << 0x97 << 0x87 << 0x87 << 0x78 << 0x87 << 0x96; // 2098 chineseTwentyFourData << 0xA5 << 0xC3 << 0xA5 << 0xB5 << 0xA6 << 0xA6 << 0x87 << 0x88 << 0x88 << 0x78 << 0x87 << 0x86; // 2099 // 公历每月前面的天数 monthAdd << 0 << 31 << 59 << 90 << 120 << 151 << 181 << 212 << 243 << 273 << 304 << 334; // 农历日期名称 listDayName << "*" << "初一" << "初二" << "初三" << "初四" << "初五" << "初六" << "初七" << "初八" << "初九" << "初十" << "十一" << "十二" << "十三" << "十四" << "十五" << "十六" << "十七" << "十八" << "十九" << "二十" << "廿一" << "廿二" << "廿三" << "廿四" << "廿五" << "廿六" << "廿七" << "廿八" << "廿九" << "三十"; // 农历月份名称 listMonthName << "*" << "正月" << "二月" << "三月" << "四月" << "五月" << "六月" << "七月" << "八月" << "九月" << "十月" << "冬月" << "腊月"; // 二十四节气名称 listSolarTerm << "小寒" << "大寒" << "立春" << "雨水" << "惊蛰" << "春分" << "清明" << "谷雨" << "立夏" << "小满" << "芒种" << "夏至" << "小暑" << "大暑" << "立秋" << "处暑" << "白露" << "秋分" << "寒露" << "霜降" << "立冬" << "小雪" << "大雪" << "冬至"; // 天干 listTianGan << "甲" << "乙" << "丙" << "丁" << "戊" << "己" << "庚" << "辛" << "壬" << "癸"; // 地支 listDiZhi << "子" << "丑" << "寅" << "卯" << "辰" << "巳" << "午" << "未" << "申" << "酉" << "戌" << "亥"; // 属相 listShuXiang << "鼠" << "牛" << "虎" << "兔" << "龙" << "蛇" << "马" << "羊" << "猴" << "鸡" << "狗" << "猪"; } KLunarCalendarInfo *KLunarCalendarInfo::Instance() { if (self.isNull()) { static QMutex mutex; QMutexLocker locker(&mutex); if (self.isNull()) { self.reset(new KLunarCalendarInfo); } } return self.data(); } KLunarCalendarInfo::KLunarCalendarInfo(QObject *parent) : QObject(parent) , d_ptr(new KLunarCalendarInfoPrivate(this)) { Q_D(KLunarCalendarInfo); } // 计算是否闰年 bool KLunarCalendarInfo::isLoopYear(int year) { Q_D(KLunarCalendarInfo); return (((0 == (year % 4)) && (0 != (year % 100))) || (0 == (year % 400))); } // 计算指定年月该月共多少天 int KLunarCalendarInfo::getMonthDays(int year, int month) { Q_D(KLunarCalendarInfo); int countDay = 0; int loopDay = isLoopYear(year) ? 1 : 0; switch (month) { case 1: countDay = 31; break; case 2: countDay = 28 + loopDay; break; case 3: countDay = 31; break; case 4: countDay = 30; break; case 5: countDay = 31; break; case 6: countDay = 30; break; case 7: countDay = 31; break; case 8: countDay = 31; break; case 9: countDay = 30; break; case 10: countDay = 31; break; case 11: countDay = 30; break; case 12: countDay = 31; break; default: countDay = 30; break; } return countDay; } // 计算指定年月对应到该月共多少天 int KLunarCalendarInfo::getTotalMonthDays(int year, int month) { Q_D(KLunarCalendarInfo); int countDay = 0; int loopDay = isLoopYear(year) ? 1 : 0; switch (month) { case 1: countDay = 0; break; case 2: countDay = 31; break; case 3: countDay = 59 + loopDay; break; case 4: countDay = 90 + loopDay; break; case 5: countDay = 120 + loopDay; break; case 6: countDay = 151 + loopDay; break; case 7: countDay = 181 + loopDay; break; case 8: countDay = 212 + loopDay; break; case 9: countDay = 243 + loopDay; break; case 10: countDay = 273 + loopDay; break; case 11: countDay = 304 + loopDay; break; case 12: countDay = 334 + loopDay; break; default: countDay = 0; break; } return countDay; } // 计算指定年月对应星期几 int KLunarCalendarInfo::getFirstDayOfWeek(int year, int month, bool FirstDayisSun) { Q_D(KLunarCalendarInfo); int week = 0; week = (year + (year - 1) / 4 - (year - 1) / 100 + (year - 1) / 400) % 7; week += getTotalMonthDays(year, month); week = week % 7 - (!FirstDayisSun); if (week == -1) week = 6; return week; } // 计算国际节日 QString KLunarCalendarInfo::getHoliday(int month, int day) { Q_D(KLunarCalendarInfo); int temp = (month << 8) | day; QString strHoliday; switch (temp) { case 0x0101: strHoliday = "元旦"; break; case 0x020E: strHoliday = "情人节"; break; case 0x0305: strHoliday = "志愿者"; break; case 0x0308: strHoliday = "妇女节"; break; case 0x030C: strHoliday = "植树节"; break; case 0x0401: strHoliday = "愚人节"; break; case 0x0501: strHoliday = "劳动节"; break; case 0x0504: strHoliday = "青年节"; break; case 0x0601: strHoliday = "儿童节"; break; case 0x0606: strHoliday = "爱眼日"; break; case 0x0701: strHoliday = "建党节"; break; case 0x0707: strHoliday = "抗战日"; break; case 0x0801: strHoliday = "建军节"; break; case 0x090A: strHoliday = "教师节"; break; case 0x0A01: strHoliday = "国庆节"; break; case 0x0B08: strHoliday = "记者节"; break; case 0x0B09: strHoliday = "消防日"; break; case 0x0C18: strHoliday = "平安夜"; break; case 0x0C19: strHoliday = "圣诞节"; break; default: break; } return strHoliday; } // 计算二十四节气 QString KLunarCalendarInfo::getSolarTerms(int year, int month, int day) { Q_D(KLunarCalendarInfo); QString strSolarTerms; int dayTemp = 0; int index = (year - 1970) * 12 + month - 1; if (day < 15) { dayTemp = 15 - day; if ((d->chineseTwentyFourData.at(index) >> 4) == dayTemp) { strSolarTerms = d->listSolarTerm.at(2 * (month - 1)); } } else if (day > 15) { dayTemp = day - 15; if ((d->chineseTwentyFourData.at(index) & 0x0f) == dayTemp) { strSolarTerms = d->listSolarTerm.at(2 * (month - 1) + 1); } } return strSolarTerms; } // 计算农历节日(必须传入农历年份月份) QString KLunarCalendarInfo::getLunarFestival(int month, int day) { Q_D(KLunarCalendarInfo); int temp = (month << 8) | day; QString strFestival; switch (temp) { case 0x0201: strFestival = "二月"; break; case 0x0301: strFestival = "三月"; break; case 0x0401: strFestival = "四月"; break; case 0x0501: strFestival = "五月"; break; case 0x0601: strFestival = "六月"; break; case 0x0701: strFestival = "七月"; break; case 0x0801: strFestival = "八月"; break; case 0x0901: strFestival = "九月"; break; case 0x0A01: strFestival = "十月"; break; case 0x0B01: strFestival = "冬月"; break; case 0x0C01: strFestival = "腊月"; break; case 0x0101: strFestival = "春节"; break; case 0x010F: strFestival = "元宵节"; break; case 0x0202: strFestival = "龙抬头"; break; case 0x0505: strFestival = "端午节"; break; case 0x0707: strFestival = "七夕节"; break; case 0x080F: strFestival = "中秋节"; break; case 0x0909: strFestival = "重阳节"; break; case 0x0C08: strFestival = "腊八节"; break; case 0x0C1E: strFestival = "除夕"; break; default: break; } return strFestival; } // 计算农历年 天干+地支+生肖 QString KLunarCalendarInfo::getLunarYear(int year) { Q_D(KLunarCalendarInfo); QString strYear; if (year > 1924) { int temp = year - 1924; strYear.append(d->listTianGan.at(temp % 10)); strYear.append(d->listDiZhi.at(temp % 12)); strYear.append("年"); strYear.append(d->listShuXiang.at(temp % 12)); strYear.append("年"); } return strYear; } void KLunarCalendarInfo::getLunarCalendarInfo(int year, int month, int day, QString &strHoliday, QString &strSolarTerms, QString &strLunarFestival, QString &strLunarYear, QString &strLunarMonth, QString &strLunarDay) { Q_D(KLunarCalendarInfo); if (year < 1901 || year > 2099 || month < 1 || month > 12 || day < 1 || day > 31) { return; } strHoliday = getHoliday(month, day); strSolarTerms = getSolarTerms(year, month, day); #ifndef year_2099 // 现在计算农历:获得当年春节的公历日期(比如:2015年春节日期为(2月19日)) // 以此为分界点,2.19前面的农历是2014年农历(用2014年农历数据来计算) // 2.19以及之后的日期,农历为2015年农历(用2015年农历数据来计算) int temp, tempYear, tempMonth, isEnd, k, n; tempMonth = year - 1968; int springFestivalMonth = d->springFestival.at(tempMonth) / 100; int springFestivalDaty = d->springFestival.at(tempMonth) % 100; if (month < springFestivalMonth) { tempMonth--; tempYear = 365 * 1 + day + d->monthAdd.at(month - 1) - 31 * ((d->springFestival.at(tempMonth) / 100) - 1) - d->springFestival.at(tempMonth) % 100 + 1; if ((!(year % 4)) && (month > 2)) { tempYear = tempYear + 1; } if ((!((year - 1) % 4))) { tempYear = tempYear + 1; } } else if (month == springFestivalMonth) { if (day < springFestivalDaty) { tempMonth--; tempYear = 365 * 1 + day + d->monthAdd.at(month - 1) - 31 * ((d->springFestival.at(tempMonth) / 100) - 1) - d->springFestival.at(tempMonth) % 100 + 1; if ((!(year % 4)) && (month > 2)) { tempYear = tempYear + 1; } if ((!((year - 1) % 4))) { tempYear = tempYear + 1; } } else { tempYear = day + d->monthAdd.at(month - 1) - 31 * ((d->springFestival.at(tempMonth) / 100) - 1) - d->springFestival.at(tempMonth) % 100 + 1; if ((!(year % 4)) && (month > 2)) { tempYear = tempYear + 1; } } } else { tempYear = day + d->monthAdd.at(month - 1) - 31 * ((d->springFestival.at(tempMonth) / 100) - 1) - d->springFestival.at(tempMonth) % 100 + 1; if ((!(year % 4)) && (month > 2)) { tempYear = tempYear + 1; } } // 计算农历天干地支月日 isEnd = 0; while (isEnd != 1) { if (d->lunarData.at(tempMonth) < 4095) { k = 11; } else { k = 12; } n = k; while (n >= 0) { temp = d->lunarData.at(tempMonth); temp = temp >> n; temp = temp % 2; if (tempYear <= (29 + temp)) { isEnd = 1; break; } tempYear = tempYear - 29 - temp; n = n - 1; } if (isEnd) { break; } tempMonth = tempMonth + 1; } // 农历的年月日 year = 1969 + tempMonth - 1; month = k - n + 1; day = tempYear; if (k == 12) { if (month == (d->lunarData.at(tempMonth) / 65536) + 1) { month = 1 - month; } else if (month > (d->lunarData.at(tempMonth) / 65536) + 1) { month = month - 1; } } strLunarYear = getLunarYear(year); if (month < 1 && (1 == day)) { month = month * -1; strLunarMonth = "闰" + d->listMonthName.at(month); } else { strLunarMonth = d->listMonthName.at(month); } strLunarDay = d->listDayName.at(day); strLunarFestival = getLunarFestival(month, day); #else // 记录春节离当年元旦的天数 int springOffset = 0; // 记录阳历日离当年元旦的天数 int newYearOffset = 0; // 记录大小月的天数 29或30 int monthCount = 0; if (((d->lunarCalendarTable.at(year - 1901) & 0x0060) >> 5) == 1) { springOffset = (d->lunarCalendarTable.at(year - 1901) & 0x001F) - 1; } else { springOffset = (d->lunarCalendarTable.at(year - 1901) & 0x001F) - 1 + 31; } // 如果是不闰年且不是2月份 +1 newYearOffset = d->monthAdd.at(month - 1) + day - 1; if ((!(year % 4)) && (month > 2)) { newYearOffset++; } // 记录从哪个月开始来计算 int index = 0; // 用来对闰月的特殊处理 int flag = 0; // 判断阳历日在春节前还是春节后,计算农历的月/日 if (newYearOffset >= springOffset) { newYearOffset -= springOffset; month = 1; index = 1; flag = 0; if ((d->lunarCalendarTable.at(year - 1901) & (0x80000 >> (index - 1))) == 0) { monthCount = 29; } else { monthCount = 30; } while (newYearOffset >= monthCount) { newYearOffset -= monthCount; index++; if (month == ((d->lunarCalendarTable.at(year - 1901) & 0xF00000) >> 20)) { flag = ~flag; if (flag == 0) { month++; } } else { month++; } if ((d->lunarCalendarTable.at(year - 1901) & (0x80000 >> (index - 1))) == 0) { monthCount = 29; } else { monthCount = 30; } } day = newYearOffset + 1; } else { springOffset -= newYearOffset; year--; month = 12; flag = 0; if (((d->lunarCalendarTable.at(year - 1901) & 0xF00000) >> 20) == 0) { index = 12; } else { index = 13; } if ((d->lunarCalendarTable.at(year - 1901) & (0x80000 >> (index - 1))) == 0) { monthCount = 29; } else { monthCount = 30; } while (springOffset > monthCount) { springOffset -= monthCount; index--; if (flag == 0) { month--; } if (month == ((d->lunarCalendarTable.at(year - 1901) & 0xF00000) >> 20)) { flag = ~flag; } if ((d->lunarCalendarTable.at(year - 1901) & (0x80000 >> (index - 1))) == 0) { monthCount = 29; } else { monthCount = 30; } } day = monthCount - springOffset + 1; } // 计算农历的索引配置 int temp = 0; temp |= day; temp |= (month << 6); // 转换农历的年月 month = (temp & 0x3C0) >> 6; day = temp & 0x3F; strLunarYear = getLunarYear(year); if ((month == ((d->lunarCalendarTable.at(year - 1901) & 0xF00000) >> 20)) && (1 == day)) { strLunarMonth = "闰" + d->listMonthName.at(month); } else { strLunarMonth = d->listMonthName.at(month); } strLunarDay = d->listDayName.at(day); strLunarFestival = getLunarFestival(month, day); #endif } QString KLunarCalendarInfo::getLunarInfo(int year, int month, int day, bool yearInfo, bool monthInfo, bool dayInfo) { Q_D(KLunarCalendarInfo); QString strHoliday, strSolarTerms, strLunarFestival, strLunarYear, strLunarMonth, strLunarDay; KLunarCalendarInfo::Instance()->getLunarCalendarInfo(year, month, day, strHoliday, strSolarTerms, strLunarFestival, strLunarYear, strLunarMonth, strLunarDay); // 农历节日优先,其次农历节气,然后公历节日,最后才是农历月份名称 if (!strLunarFestival.isEmpty()) { strLunarDay = strLunarFestival; } else if (!strSolarTerms.isEmpty()) { strLunarDay = strSolarTerms; } else if (!strHoliday.isEmpty()) { strLunarDay = strHoliday; } QString info = QString("%1%2%3") .arg(yearInfo ? strLunarYear + "年" : "") .arg(monthInfo ? strLunarMonth : "") .arg(dayInfo ? strLunarDay : ""); return info; } QString KLunarCalendarInfo::getLunarYearMonthDay(int year, int month, int day) { return getLunarInfo(year, month, day, true, true, true); } QString KLunarCalendarInfo::getLunarMonthDay(int year, int month, int day) { return getLunarInfo(year, month, day, false, true, true); } QString KLunarCalendarInfo::getLunarDay(int year, int month, int day) { return getLunarInfo(year, month, day, false, false, true); } } #include "klunarcalendarinfo.moc" #include "moc_klunarcalendarinfo.cpp" libkysdk-applications/kysdk-qtwidgets/src/klabel.cpp0000664000175000017500000004505115104543305021670 0ustar fengfeng/* * libkysdk-qtwidgets's Library * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhenyu Wang * */ #include "klabel.h" #include "themeController.h" #include #include #include #include #include #include #include namespace kdk { static const int spacing = 4; class KLabelPrivate : public QObject, public ThemeController { Q_OBJECT Q_DECLARE_PUBLIC(KLabel) public: KLabelPrivate(KLabel *parent); protected: void changeTheme(); private: KLabel *q_ptr; KLabelType m_labelType; QPixmap m_pixmap; QString m_text; QColor m_backgroundColor; QColor m_fontColor; QIcon m_icon; QPalette::ColorRole m_fontColorRole; bool m_dataHightColorFlag; bool m_isBackgroundFlag; int m_topLeftRadius; int m_topRightRadius; int m_bottomLeftRadius; int m_bottomRightRadius; int diffPointSize; int m_pixmapWidth; int m_pixmapHeight; bool m_isHighlightBackgroundFlag; bool m_wordWrap; bool m_fontColorFlag; bool m_isIcon; bool m_fontColorRoleFlag; bool m_isTristate; bool m_clicked; }; KLabel::KLabel(QWidget *parent) : QLabel(parent) , d_ptr(new KLabelPrivate(this)) { Q_D(KLabel); int pointSize = QApplication::font().pointSize(); connect(d->m_gsetting, &QGSettings::changed, this, [=](const QString &key) { d->changeTheme(); int now = this->font().pointSize(); if (now != QApplication::font().pointSize()) { if (d->diffPointSize == 0) d->diffPointSize = now - pointSize; QFont font = this->font(); font.setPointSize(d->diffPointSize + QApplication::font().pointSize()); setFont(font); } if ("styleName" == key) { QColor textColor = ThemeController::getCustomColorFromDT("placeholdertext-active"); } }); } void KLabel::setLabelType(KLabelType type) { Q_D(KLabel); d->m_labelType = type; } void KLabel::setDataHightColor(bool flag) { Q_D(KLabel); d->m_dataHightColorFlag = flag; } void KLabel::setPixmap(const QPixmap &pixmap) { Q_D(KLabel); d->m_isIcon = false; if(pixmap.devicePixelRatio() != 1) d->m_pixmap = pixmap.scaled(pixmap.size() / pixmap.devicePixelRatio() , Qt::KeepAspectRatio , Qt::SmoothTransformation); else d->m_pixmap = pixmap; update(); } void KLabel::setPixmap(QIcon icon, int width, int height) { Q_D(KLabel); d->m_isIcon = true; d->m_pixmapWidth = width; d->m_pixmapHeight = height; d->m_icon = icon; update(); } const QPixmap *KLabel::pixmap() const { Q_D(const KLabel); return &d->m_pixmap; } void KLabel::setText(const QString &str) { Q_D(KLabel); QLabel::setText(str); } QString KLabel::text() { Q_D(KLabel); return QLabel::text(); } void KLabel::setBackgroundColor(bool flag, QColor color) { Q_D(KLabel); if (d->m_isHighlightBackgroundFlag) d->m_isHighlightBackgroundFlag = false; d->m_isBackgroundFlag = flag; d->m_backgroundColor = color; update(); } void KLabel::setHighlightBackground(bool flag) { Q_D(KLabel); if (d->m_isBackgroundFlag) d->m_isBackgroundFlag = false; d->m_isHighlightBackgroundFlag = flag; update(); } void KLabel::setBorderRadius(int bottomLeft, int topLeft, int topRight, int bottomRight) { Q_D(KLabel); d->m_bottomRightRadius = bottomRight; d->m_topLeftRadius = topLeft; d->m_bottomLeftRadius = bottomLeft; d->m_topRightRadius = topRight; } void KLabel::setBorderRadius(int radius) { Q_D(KLabel); d->m_bottomRightRadius = radius; d->m_topLeftRadius = radius; d->m_bottomLeftRadius = radius; d->m_topRightRadius = radius; } void KLabel::setWordWrap(bool flag) { Q_D(KLabel); d->m_wordWrap = flag; QLabel::setWordWrap(true); } bool KLabel::wordWrap() { Q_D(KLabel); return d->m_wordWrap; } void KLabel::setFontColor(QColor color) { Q_D(KLabel); d->m_fontColor = color; d->m_fontColorFlag = true; d->m_fontColorRoleFlag = false; update(); } void KLabel::setFontColorRole(QPalette::ColorRole role) { Q_D(KLabel); d->m_fontColorRoleFlag = true; d->m_fontColorFlag = false; d->m_fontColorRole = role; update(); } void KLabel::setTristate(bool flag) { Q_D(KLabel); d->m_isTristate = flag; if (d->m_isTristate) { QColor textColor = ThemeController::getCustomColorFromDT("placeholdertext-active"); setFontColor(textColor); } else { d->m_pixmap = ThemeController::drawColoredPixmap(d->m_pixmap, ThemeController::getCustomColorFromDT("highlight-active")); if (d->m_fontColorRoleFlag) setFontColorRole(d->m_fontColorRole); else if (d->m_fontColorRoleFlag) setFontColorRole(d->m_fontColorRole); else if (d->m_dataHightColorFlag) setFontColorRole(QPalette::Highlight); else setFontColorRole(QPalette::Text); } } bool KLabel::isTristate() { Q_D(KLabel); return d->m_isTristate; } void KLabel::paintEvent(QPaintEvent *event) { Q_D(KLabel); QPainter painter(this); painter.setRenderHint(QPainter::SmoothPixmapTransform); painter.setRenderHint(QPainter::Antialiasing); QColor bkgColor; QMargins margins = contentsMargins(); QRect drawRect = rect().adjusted(margins.left(),margins.top(),-margins.right(),-margins.bottom()); QRect iconRect; QRect textRect; painter.setPen(Qt::NoPen); QString str = text(); // 绘制背景 QPainterPath path; path.moveTo(drawRect.topRight() - QPoint(d->m_topRightRadius, 0)); // 右上 path.lineTo(drawRect.topLeft() + QPointF(d->m_topLeftRadius, 0)); // 上方线 path.quadTo(drawRect.topLeft(), drawRect.topLeft() + QPointF(0, d->m_topLeftRadius)); // 圆角 path.lineTo(drawRect.bottomLeft() + QPointF(0, -d->m_bottomLeftRadius)); // 左方线 path.quadTo(drawRect.bottomLeft(), drawRect.bottomLeft() + QPointF(d->m_bottomLeftRadius, 0)); // 圆角 path.lineTo(drawRect.bottomRight() - QPointF(d->m_bottomRightRadius, 0)); // 下方线 path.quadTo(drawRect.bottomRight(), drawRect.bottomRight() + QPointF(0, -d->m_bottomRightRadius)); // 圆角 path.lineTo(drawRect.topRight() + QPointF(0, d->m_topRightRadius)); // 右方线 path.quadTo(drawRect.topRight(), drawRect.topRight() - QPointF(d->m_topRightRadius, 0)); // 圆角 switch (d->m_labelType) { case DataType: bkgColor = ThemeController::getCustomColorFromDT("highlight-active"); bkgColor.setAlphaF(0.15); if (d->m_isBackgroundFlag) { painter.setBrush(d->m_backgroundColor); painter.setPen(Qt::NoPen); } else { painter.setBrush(bkgColor); painter.setPen(Qt::NoPen); } painter.drawPath(path); break; case NormalType: if (d->m_isBackgroundFlag) painter.setBrush(d->m_backgroundColor); else if (d->m_isHighlightBackgroundFlag) painter.setBrush(ThemeController::getCustomColorFromDT("highlight-active")); else painter.setBrush(Qt::NoBrush); painter.setPen(Qt::NoPen); painter.drawPath(path); break; case CircleType: if (d->m_isBackgroundFlag) painter.setBrush(d->m_backgroundColor); else if (d->m_isHighlightBackgroundFlag) painter.setBrush(ThemeController::getCustomColorFromDT("highlight-active")); else painter.setBrush(ThemeController::getCustomColorFromDT("button-active")); painter.setPen(Qt::NoPen); painter.drawEllipse(rect()); break; default: break; } // 绘制图标和文字 if (d->m_isIcon) { d->m_pixmap = d->m_icon.pixmap(d->m_pixmapWidth, d->m_pixmapHeight); if ((d->m_pixmap.size().width() != d->m_pixmapWidth || d->m_pixmap.size().height() != d->m_pixmapHeight) && !d->m_pixmap.isNull()) d->m_pixmap = d->m_pixmap.scaled(d->m_pixmapWidth, d->m_pixmapHeight, Qt::KeepAspectRatio, Qt::SmoothTransformation); } if (!wordWrap()) { int drawLength; if (!text().isEmpty() && !d->m_pixmap.isNull()) drawLength = d->m_pixmap.width() + spacing + fontMetrics().horizontalAdvance(text()); else if (!text().isEmpty() && d->m_pixmap.isNull()) drawLength = fontMetrics().horizontalAdvance(text()); else if (text().isEmpty() && !d->m_pixmap.isNull()) drawLength = d->m_pixmap.width(); if (!text().isEmpty() && !d->m_pixmap.isNull()) { iconRect = QRect(drawRect.x() , drawRect.height()/2 - d->m_pixmap.height() / 2 + 1, d->m_pixmap.width(), d->m_pixmap.height()); textRect = QRect(iconRect.right() + spacing, drawRect.top(), drawRect.width() - spacing - iconRect.width(), drawRect.height()); int drawLength = d->m_pixmap.width() + spacing + fontMetrics().horizontalAdvance(text()); if (drawRect.width() >= drawLength) { setToolTip(""); } else { setToolTip(str); str = fontMetrics().elidedText(str, Qt::ElideRight, textRect.width()); } } else { if (text().isEmpty()) { iconRect = QRect(drawRect.width()/2 - drawLength / 2 , drawRect.height()/2 - d->m_pixmap.height() / 2 , d->m_pixmap.width(), d->m_pixmap.height()); } else { textRect = QRect(drawRect.x(), drawRect.top(), drawRect.width(), drawRect.height()); if (drawRect.width() >= drawLength) { setToolTip(""); } else { setToolTip(str); str = fontMetrics().elidedText(str, Qt::ElideRight, textRect.width()); } } } if (d->m_dataHightColorFlag) { d->m_pixmap = ThemeController::drawColoredPixmap(d->m_pixmap, ThemeController::getCustomColorFromDT("highlight-active")); if (d->m_fontColorFlag) painter.setPen(d->m_fontColor); else if (d->m_fontColorRoleFlag) painter.setPen(palette().color(d->m_fontColorRole)); else painter.setPen(ThemeController::getCustomColorFromDT("highlight-active")); } else if (d->m_isBackgroundFlag || d->m_isHighlightBackgroundFlag) { d->m_pixmap = ThemeController::drawSymbolicColoredPixmap(d->m_pixmap); if (d->m_fontColorFlag) painter.setPen(d->m_fontColor); else if (d->m_fontColorRoleFlag) painter.setPen(palette().color(d->m_fontColorRole)); else painter.setPen(ThemeController::getCustomColorFromDT("text-active")); } else { if (d->m_fontColorFlag) painter.setPen(d->m_fontColor); else if (d->m_fontColorRoleFlag) painter.setPen(palette().color(d->m_fontColorRole)); else painter.setPen(ThemeController::getCustomColorFromDT("text-active")); if (!d->m_pixmap.isNull()) { if (ThemeController::isPixmapPureColor(d->m_pixmap)) { if (ThemeController::themeMode() == DarkTheme) d->m_pixmap = ThemeController::drawColoredPixmap(d->m_pixmap, Qt::white); else d->m_pixmap = ThemeController::drawColoredPixmap(d->m_pixmap, ThemeController::getCustomColorFromDT("windowtext-active")); } } } if (alignment() == Qt::AlignCenter || alignment() == Qt::AlignHCenter) { if (!text().isEmpty() && !d->m_pixmap.isNull()) { if (drawRect.width() >= drawLength) iconRect.moveLeft(drawRect.width() / 2 - drawLength / 2); else iconRect.moveLeft(drawRect.left()); } else { if (text().isEmpty()) iconRect.moveLeft(drawRect.width() / 2 - drawLength / 2); } } else if(alignment() == Qt::AlignRight) iconRect.moveLeft(drawRect.width() - fontMetrics().horizontalAdvance(str) - spacing - iconRect.width()); painter.drawText(textRect, alignment() | Qt::AlignVCenter, str); painter.drawPixmap(iconRect, d->m_pixmap); } else { QRect contentRect = drawRect.adjusted(margins.left(), margins.top(), -margins.right(), -margins.bottom()); if (!d->m_pixmap.isNull()) { int iconX = contentRect.x(); int iconY = contentRect.y() + (contentRect.height() - d->m_pixmap.height()) / 2; if (alignment() & Qt::AlignHCenter) { iconX = contentRect.x() + (contentRect.width() - d->m_pixmap.width()) / 2; } else if (alignment() & Qt::AlignRight) { iconX = contentRect.right() - d->m_pixmap.width(); } iconRect = QRect(iconX, iconY, d->m_pixmap.width(), d->m_pixmap.height()); if (alignment() & Qt::AlignLeft) { contentRect.setLeft(iconRect.right() + spacing); } else if (alignment() & Qt::AlignRight) { contentRect.setRight(iconRect.left() - spacing); } painter.drawPixmap(iconRect, d->m_pixmap); } if (!text().isEmpty()) { QTextDocument doc; doc.setDefaultFont(font()); doc.setPlainText(text()); QTextOption textOption; textOption.setWrapMode(QTextOption::WordWrap); textOption.setAlignment(alignment()); doc.setDefaultTextOption(textOption); doc.setTextWidth(contentRect.width()); qreal textHeight = doc.size().height(); qreal yPos = static_cast(contentRect.y()); if (alignment() & Qt::AlignBottom) { yPos = static_cast(contentRect.bottom()) - textHeight; } else if (alignment() & Qt::AlignVCenter) { yPos = static_cast(contentRect.y()) + (static_cast(contentRect.height()) - textHeight) / 2; } yPos = qMax(static_cast(contentRect.y()), qMin(yPos, static_cast(contentRect.bottom()) - textHeight)); painter.save(); painter.translate(contentRect.x(), static_cast(yPos)); painter.setClipRect(QRect(0, 0, contentRect.width(), contentRect.height())); doc.drawContents(&painter, QRectF(0, 0, contentRect.width(), contentRect.height())); painter.restore(); } } } void KLabel::resizeEvent(QResizeEvent *event) { Q_D(KLabel); int height = d->m_pixmapHeight > fontMetrics().height() ? d->m_pixmapHeight : fontMetrics().height(); if (height > size().height()) { setMinimumHeight(height); } QLabel::resizeEvent(event); } void KLabel::enterEvent(QEnterEvent *event) { Q_D(KLabel); if (d->m_isTristate) { QColor textColor = ThemeController::getCustomColorFromDT("placeholdertext-active"); QColor highlight = ThemeController::getCustomColorFromDT("highlight-active"); QColor mix = ThemeController::getCustomColorFromDT("brighttext-active"); textColor = ThemeController::mixColor(highlight, mix, 0.05); setFontColor(textColor); } Q_EMIT enterWidget(); QLabel::enterEvent(event); } void KLabel::leaveEvent(QEvent *event) { Q_D(KLabel); if (d->m_isTristate) { QColor textColor = ThemeController::getCustomColorFromDT("placeholdertext-active"); setFontColor(textColor); } Q_EMIT leaveWidget(); QLabel::leaveEvent(event); } void KLabel::mousePressEvent(QMouseEvent *event) { Q_D(KLabel); if (event->button() == Qt::LeftButton && d->m_isTristate) { QColor textColor = ThemeController::getCustomColorFromDT("placeholdertext-active"); QColor highlight = ThemeController::getCustomColorFromDT("highlight-active"); QColor mix = ThemeController::getCustomColorFromDT("brighttext-active"); textColor = ThemeController::mixColor(highlight, mix, 0.2); setFontColor(textColor); } QLabel::mousePressEvent(event); } void KLabel::mouseReleaseEvent(QMouseEvent *event) { Q_D(KLabel); if (event->button() == Qt::LeftButton && d->m_isTristate) { QColor textColor = ThemeController::getCustomColorFromDT("placeholdertext-active"); QColor highlight = ThemeController::getCustomColorFromDT("highlight-active"); QColor mix = ThemeController::getCustomColorFromDT("brighttext-active"); textColor = ThemeController::mixColor(highlight, mix, 0.05); setFontColor(textColor); } d->m_clicked = !d->m_clicked; Q_EMIT clicked(d->m_clicked); QLabel::mouseReleaseEvent(event); } void KLabel::mouseDoubleClickEvent(QMouseEvent *event) { Q_EMIT doubleClicked(); QLabel::mouseDoubleClickEvent(event); } QSize KLabel::sizeHint() const { Q_D(const KLabel); return QLabel::sizeHint(); } KLabelPrivate::KLabelPrivate(KLabel *parent) : q_ptr(parent) , m_isBackgroundFlag(false) , m_dataHightColorFlag(false) , m_bottomRightRadius(6) , m_topLeftRadius(6) , m_bottomLeftRadius(6) , m_topRightRadius(6) , diffPointSize(0) , m_pixmapWidth(16) , m_pixmapHeight(16) , m_isHighlightBackgroundFlag(false) , m_wordWrap(false) , m_fontColorFlag(false) , m_isIcon(false) , m_fontColorRoleFlag(false) , m_isTristate(false) , m_clicked(false) { Q_Q(KLabel); m_labelType = NormalType; } void KLabelPrivate::changeTheme() { Q_Q(KLabel); initThemeStyle(); } } #include "klabel.moc" #include "moc_klabel.cpp" libkysdk-applications/kysdk-qtwidgets/src/kwindowbuttonbar.cpp0000664000175000017500000004453115104543305024043 0ustar fengfeng/* * libkysdk-qtwidgets's Library * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #include "kwindowbuttonbar.h" #include "parmscontroller.h" #include "themeController.h" #include #include #include #include #include #include #include #include "kysdk-ukuiwindowhelper/ukuiwindowhelper.h" #include "accessinfohelper.h" namespace kdk { class KWindowButtonBarPrivate : public QObject, public ThemeController { Q_OBJECT Q_DECLARE_PUBLIC(KWindowButtonBar) public: KWindowButtonBarPrivate(KWindowButtonBar *parent); protected: void changeTheme() override; private: KWindowButtonBar *q_ptr; KMenuButton *m_pMenuBtn; QPushButton *m_pMinimumBtn; QPushButton *m_pmaximumBtn; QPushButton *m_pCloseBtn; MaximumButtonState m_maximumButtonState; QWidget *m_pParentWidget; UkuiWindowHelper *m_pUkuiWindowHelper; QColor m_pixColor; QRect m_splitScreenRect; bool m_followMode; }; KWindowButtonBar::KWindowButtonBar(QWidget *parent) : QFrame(parent) , d_ptr(new KWindowButtonBarPrivate(this)) { Q_D(KWindowButtonBar); d->m_pParentWidget = parent; d->m_pMenuBtn->setFocusPolicy(Qt::NoFocus); d->m_pMinimumBtn->setFocusPolicy(Qt::NoFocus); d->m_pmaximumBtn->setFocusPolicy(Qt::NoFocus); d->m_pCloseBtn->setFocusPolicy(Qt::NoFocus); setFixedHeight(Parmscontroller::parm(Parmscontroller::Parm::PM_IconbarHeight)); // setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Fixed); d->m_pCloseBtn->installEventFilter(this); d->m_pmaximumBtn->installEventFilter(this); d->m_pMinimumBtn->installEventFilter(this); d->m_pMenuBtn->installEventFilter(this); connect(Parmscontroller::self(), &Parmscontroller::modeChanged, this, [=]() { setFixedHeight(Parmscontroller::parm(Parmscontroller::Parm::PM_IconbarHeight)); d->m_pMenuBtn->setFixedSize(Parmscontroller::parm(Parmscontroller::Parm::PM_WindowButtonBarSize), Parmscontroller::parm(Parmscontroller::Parm::PM_WindowButtonBarSize)); d->m_pmaximumBtn->setFixedSize(Parmscontroller::parm(Parmscontroller::Parm::PM_WindowButtonBarSize), Parmscontroller::parm(Parmscontroller::Parm::PM_WindowButtonBarSize)); d->m_pCloseBtn->setFixedSize(Parmscontroller::parm(Parmscontroller::Parm::PM_WindowButtonBarSize), Parmscontroller::parm(Parmscontroller::Parm::PM_WindowButtonBarSize)); d->m_pMinimumBtn->setFixedSize(Parmscontroller::parm(Parmscontroller::Parm::PM_WindowButtonBarSize), Parmscontroller::parm(Parmscontroller::Parm::PM_WindowButtonBarSize)); updateGeometry(); repaint(); }); } KWindowButtonBar::~KWindowButtonBar() { } QPushButton *KWindowButtonBar::minimumButton() { Q_D(KWindowButtonBar); return d->m_pMinimumBtn; } QPushButton *KWindowButtonBar::maximumButton() { Q_D(KWindowButtonBar); return d->m_pmaximumBtn; } QPushButton *KWindowButtonBar::closeButton() { Q_D(KWindowButtonBar); return d->m_pCloseBtn; } KMenuButton *KWindowButtonBar::menuButton() { Q_D(KWindowButtonBar); return d->m_pMenuBtn; } MaximumButtonState KWindowButtonBar::maximumButtonState() { Q_D(KWindowButtonBar); return d->m_maximumButtonState; } void KWindowButtonBar::setMaximumButtonState(MaximumButtonState state) { Q_D(KWindowButtonBar); d->m_maximumButtonState = state; d->changeTheme(); } void KWindowButtonBar::setFollowMode(bool flag) { Q_D(KWindowButtonBar); d->m_followMode = flag; } bool KWindowButtonBar::followMode() { Q_D(KWindowButtonBar); return d->m_followMode; } void KWindowButtonBar::setSplitScreenGeometry(QRect rect) { Q_D(KWindowButtonBar); d->m_splitScreenRect = rect; } void KWindowButtonBar::mouseDoubleClickEvent(QMouseEvent *event) { Q_D(KWindowButtonBar); if (event->button() == Qt::LeftButton && d->m_pmaximumBtn->isEnabled()) Q_EMIT doubleClick(); } bool KWindowButtonBar::eventFilter(QObject *watched, QEvent *event) { Q_D(KWindowButtonBar); if (QEvent::WindowDeactivate == event->type()) { if (ThemeController::themeMode() == LightTheme) d->m_pixColor = ThemeController::getCustomColorFromDT("kgray-11"); else d->m_pixColor = ThemeController::getCustomColorFromDT("kwhite"); auto closeIcon = ThemeController::drawColoredPixmap(QIcon::fromTheme("window-close-symbolic").pixmap(QSize(Parmscontroller::parm(Parmscontroller::Parm::PM_WindowButtonBarSize), Parmscontroller::parm(Parmscontroller::Parm::PM_WindowButtonBarSize))), d->m_pixColor); auto minIcon = ThemeController::drawColoredPixmap(QIcon::fromTheme("window-minimize-symbolic").pixmap(QSize(Parmscontroller::parm(Parmscontroller::Parm::PM_WindowButtonBarSize), Parmscontroller::parm(Parmscontroller::Parm::PM_WindowButtonBarSize))), d->m_pixColor); d->m_pCloseBtn->setIcon(closeIcon); d->m_pMinimumBtn->setIcon(minIcon); if (d->m_maximumButtonState == Maximum) { auto maxIcon = ThemeController::drawColoredPixmap(QIcon::fromTheme("window-maximize-symbolic").pixmap(QSize(Parmscontroller::parm(Parmscontroller::Parm::PM_WindowButtonBarSize), Parmscontroller::parm(Parmscontroller::Parm::PM_WindowButtonBarSize))), d->m_pixColor); d->m_pmaximumBtn->setIcon(maxIcon); } else { auto maxIcon = ThemeController::drawColoredPixmap(QIcon::fromTheme("window-restore-symbolic").pixmap(QSize(Parmscontroller::parm(Parmscontroller::Parm::PM_WindowButtonBarSize), Parmscontroller::parm(Parmscontroller::Parm::PM_WindowButtonBarSize))), d->m_pixColor); d->m_pmaximumBtn->setIcon(maxIcon); } } if (QEvent::WindowActivate == event->type() || QEvent::MouseButtonPress == event->type()) { if (ThemeController::themeMode() == LightTheme) d->m_pixColor = ThemeController::getCustomColorFromDT("kgray-17"); else d->m_pixColor = ThemeController::getCustomColorFromDT("kwhite"); auto closeIcon = ThemeController::drawColoredPixmap(QIcon::fromTheme("window-close-symbolic").pixmap(QSize(Parmscontroller::parm(Parmscontroller::Parm::PM_WindowButtonBarSize), Parmscontroller::parm(Parmscontroller::Parm::PM_WindowButtonBarSize))), d->m_pixColor); d->m_pCloseBtn->setIcon(closeIcon); d->m_pMinimumBtn->setIcon(QIcon::fromTheme("window-minimize-symbolic")); if (d->m_maximumButtonState == Maximum) { if(ThemeController::themeMode() == LightTheme) d->m_pmaximumBtn->setIcon(QIcon::fromTheme("window-maximize-symbolic")); else { auto closeIcon = ThemeController::drawColoredPixmap(QIcon::fromTheme("window-maximize-symbolic").pixmap(QSize(Parmscontroller::parm(Parmscontroller::Parm::PM_WindowButtonBarSize), Parmscontroller::parm(Parmscontroller::Parm::PM_WindowButtonBarSize))), d->m_pixColor); d->m_pmaximumBtn->setIcon(closeIcon); } } else { if(ThemeController::themeMode() == LightTheme) d->m_pmaximumBtn->setIcon(QIcon::fromTheme("window-restore-symbolic")); else { auto closeIcon = ThemeController::drawColoredPixmap(QIcon::fromTheme("window-restore-symbolic").pixmap(QSize(Parmscontroller::parm(Parmscontroller::Parm::PM_WindowButtonBarSize), Parmscontroller::parm(Parmscontroller::Parm::PM_WindowButtonBarSize))), d->m_pixColor); d->m_pmaximumBtn->setIcon(closeIcon); } } } if (watched == d->m_pCloseBtn) { // 根据不同状态重绘icon颜色 switch (event->type()) { case QEvent::MouseButtonPress: if (isEnabled()) { auto mouseEvent = dynamic_cast(event); if (mouseEvent->button() == Qt::LeftButton) d->m_pixColor = ThemeController::getCustomColorFromDT("kwhite"); auto closeIcon = ThemeController::drawColoredPixmap(QIcon::fromTheme("window-close-symbolic").pixmap(QSize(Parmscontroller::parm(Parmscontroller::Parm::PM_WindowButtonBarSize), Parmscontroller::parm(Parmscontroller::Parm::PM_WindowButtonBarSize))), d->m_pixColor); d->m_pCloseBtn->setIcon(closeIcon); } break; case QEvent::Enter: if (isEnabled()) { d->m_pixColor = ThemeController::getCustomColorFromDT("kwhite"); auto closeIcon = ThemeController::drawColoredPixmap(QIcon::fromTheme("window-close-symbolic").pixmap(QSize(Parmscontroller::parm(Parmscontroller::Parm::PM_WindowButtonBarSize), Parmscontroller::parm(Parmscontroller::Parm::PM_WindowButtonBarSize))), d->m_pixColor); d->m_pCloseBtn->setIcon(closeIcon); } break; case QEvent::MouseButtonRelease: if (isEnabled()) { auto mouseEvent = dynamic_cast(event); if (mouseEvent->button() == Qt::LeftButton) d->m_pixColor = ThemeController::getCustomColorFromDT("kwhite"); auto closeIcon = ThemeController::drawColoredPixmap(QIcon::fromTheme("window-close-symbolic").pixmap(QSize(Parmscontroller::parm(Parmscontroller::Parm::PM_WindowButtonBarSize), Parmscontroller::parm(Parmscontroller::Parm::PM_WindowButtonBarSize))), d->m_pixColor); d->m_pCloseBtn->setIcon(closeIcon); } break; case QEvent::Leave: if (isEnabled()) { if (d->m_pCloseBtn->isActiveWindow()) { if (ThemeController::themeMode() == LightTheme) d->m_pixColor = ThemeController::getCustomColorFromDT("kgray-17"); else d->m_pixColor = ThemeController::getCustomColorFromDT("kwhite"); } else { if (ThemeController::themeMode() == LightTheme) d->m_pixColor = ThemeController::getCustomColorFromDT("kgray-11"); else d->m_pixColor = ThemeController::getCustomColorFromDT("kwhite"); } auto closeIcon = ThemeController::drawColoredPixmap(QIcon::fromTheme("window-close-symbolic").pixmap(QSize(Parmscontroller::parm(Parmscontroller::Parm::PM_WindowButtonBarSize), Parmscontroller::parm(Parmscontroller::Parm::PM_WindowButtonBarSize))), d->m_pixColor); d->m_pCloseBtn->setIcon(closeIcon); } break; case QEvent::WindowDeactivate: { d->m_pixColor = ThemeController::getCustomColorFromDT("kgray-11"); auto closeIcon = ThemeController::drawColoredPixmap(QIcon::fromTheme("window-close-symbolic").pixmap(QSize(Parmscontroller::parm(Parmscontroller::Parm::PM_WindowButtonBarSize), Parmscontroller::parm(Parmscontroller::Parm::PM_WindowButtonBarSize))), d->m_pixColor); d->m_pCloseBtn->setIcon(closeIcon); } break; default: break; } } if (watched == d->m_pmaximumBtn) { switch (event->type()) { case QEvent::ToolTip: { QPoint pos = d->m_pmaximumBtn->mapTo(d->m_pmaximumBtn->window(), QPoint(0, 0)); d->m_pUkuiWindowHelper->showTileFlyout(QRect(pos, d->m_pmaximumBtn->size())); break; } } } return QFrame::eventFilter(watched, event); } QSize KWindowButtonBar::sizeHint() const { auto size = QFrame::sizeHint(); size.setHeight(Parmscontroller::parm(Parmscontroller::Parm::PM_PushButtonHeight)); return size; } KWindowButtonBarPrivate::KWindowButtonBarPrivate(KWindowButtonBar *parent) : q_ptr(parent) , m_followMode(true) { Q_Q(KWindowButtonBar); QHBoxLayout *hLayout = new QHBoxLayout(); hLayout->setSpacing(8); hLayout->setContentsMargins(0, 0, 0, 0); // m_maximumButtonState = Maximum; m_pMenuBtn = new KMenuButton(q); m_pMenuBtn->setFixedSize(Parmscontroller::parm(Parmscontroller::Parm::PM_WindowButtonBarSize), Parmscontroller::parm(Parmscontroller::Parm::PM_WindowButtonBarSize)); m_pMinimumBtn = new QPushButton(q); m_pMinimumBtn->setToolTip(tr("Minimize")); m_pMinimumBtn->setFixedSize(Parmscontroller::parm(Parmscontroller::Parm::PM_WindowButtonBarSize), Parmscontroller::parm(Parmscontroller::Parm::PM_WindowButtonBarSize)); m_pmaximumBtn = new QPushButton(q); m_pmaximumBtn->setFixedSize(Parmscontroller::parm(Parmscontroller::Parm::PM_WindowButtonBarSize), Parmscontroller::parm(Parmscontroller::Parm::PM_WindowButtonBarSize)); m_pCloseBtn = new QPushButton(q); m_pCloseBtn->setObjectName("CloseButton"); m_pCloseBtn->setFixedSize(Parmscontroller::parm(Parmscontroller::Parm::PM_WindowButtonBarSize), Parmscontroller::parm(Parmscontroller::Parm::PM_WindowButtonBarSize)); m_pCloseBtn->setToolTip(tr("Close")); hLayout->setAlignment(Qt::AlignRight); hLayout->setContentsMargins(0, 0, 4, 0); hLayout->setSpacing(2); // hLayout->addStretch(); hLayout->addWidget(m_pMenuBtn); hLayout->addWidget(m_pMinimumBtn); hLayout->addWidget(m_pmaximumBtn); hLayout->addWidget(m_pCloseBtn); q->setLayout(hLayout); // 控件自己控制样式、响应主题变化 m_pMinimumBtn->setProperty("isWindowButton", 0x1); m_pMinimumBtn->setProperty("useIconHighlightEffect", 0x2); m_pMinimumBtn->setFlat(true); m_pMinimumBtn->setIcon(QIcon::fromTheme("window-minimize-symbolic")); m_pmaximumBtn->setProperty("isWindowButton", 0x1); m_pmaximumBtn->setProperty("useIconHighlightEffect", 0x2); m_pmaximumBtn->setFlat(true); m_pCloseBtn->setProperty("isWindowButton", 0x02); m_pCloseBtn->setProperty("useIconHighlightEffect", 0x08); m_pCloseBtn->setFlat(true); m_pCloseBtn->setIcon(QIcon::fromTheme("window-close-symbolic")); m_pUkuiWindowHelper = new UkuiWindowHelper(q->window()); changeTheme(); connect(m_gsetting, &QGSettings::changed, this, [=]() { changeTheme(); }); connect(m_pmaximumBtn, &QPushButton::clicked, this, [=]() { if (m_maximumButtonState == Maximum) m_maximumButtonState = Restore; else m_maximumButtonState = Maximum; changeTheme(); }); setParent(parent); KDK_ALL_INFO_FORMAT(m_pMenuBtn,""); KDK_ALL_INFO_FORMAT(m_pMinimumBtn,""); KDK_ALL_INFO_FORMAT(m_pmaximumBtn,""); KDK_ALL_INFO_FORMAT(m_pCloseBtn,""); } void KWindowButtonBarPrivate::changeTheme() { Q_Q(KWindowButtonBar); initThemeStyle(); if (q->isActiveWindow()) { if (ThemeController::themeMode() == LightTheme) m_pixColor = ThemeController::getCustomColorFromDT("kgray-17"); else m_pixColor = ThemeController::getCustomColorFromDT("kwhite"); auto closeIcon = ThemeController::drawColoredPixmap(QIcon::fromTheme("window-close-symbolic").pixmap(QSize(Parmscontroller::parm(Parmscontroller::Parm::PM_WindowButtonBarSize), Parmscontroller::parm(Parmscontroller::Parm::PM_WindowButtonBarSize))), m_pixColor); m_pCloseBtn->setIcon(closeIcon); m_pMinimumBtn->setIcon(QIcon::fromTheme("window-minimize-symbolic")); if (m_maximumButtonState == Maximum) { if(ThemeController::themeMode() == LightTheme) m_pmaximumBtn->setIcon(QIcon::fromTheme("window-maximize-symbolic")); else { auto closeIcon = ThemeController::drawColoredPixmap(QIcon::fromTheme("window-maximize-symbolic").pixmap(QSize(Parmscontroller::parm(Parmscontroller::Parm::PM_WindowButtonBarSize), Parmscontroller::parm(Parmscontroller::Parm::PM_WindowButtonBarSize))), m_pixColor); m_pmaximumBtn->setIcon(closeIcon); } } else { if(ThemeController::themeMode() == LightTheme) m_pmaximumBtn->setIcon(QIcon::fromTheme("window-restore-symbolic")); else { auto closeIcon = ThemeController::drawColoredPixmap(QIcon::fromTheme("window-restore-symbolic").pixmap(QSize(Parmscontroller::parm(Parmscontroller::Parm::PM_WindowButtonBarSize), Parmscontroller::parm(Parmscontroller::Parm::PM_WindowButtonBarSize))), m_pixColor); m_pmaximumBtn->setIcon(closeIcon); } } } else { if (ThemeController::themeMode() == LightTheme) m_pixColor = ThemeController::getCustomColorFromDT("kgray-11"); else m_pixColor = ThemeController::getCustomColorFromDT("kwhite"); auto closeIcon = ThemeController::drawColoredPixmap(QIcon::fromTheme("window-close-symbolic").pixmap(QSize(Parmscontroller::parm(Parmscontroller::Parm::PM_WindowButtonBarSize), Parmscontroller::parm(Parmscontroller::Parm::PM_WindowButtonBarSize))), m_pixColor); auto minIcon = ThemeController::drawColoredPixmap(QIcon::fromTheme("window-minimize-symbolic").pixmap(QSize(Parmscontroller::parm(Parmscontroller::Parm::PM_WindowButtonBarSize), Parmscontroller::parm(Parmscontroller::Parm::PM_WindowButtonBarSize))), m_pixColor); m_pCloseBtn->setIcon(closeIcon); m_pMinimumBtn->setIcon(minIcon); if (m_maximumButtonState == Maximum) { auto maxIcon = ThemeController::drawColoredPixmap(QIcon::fromTheme("window-maximize-symbolic").pixmap(QSize(Parmscontroller::parm(Parmscontroller::Parm::PM_WindowButtonBarSize), Parmscontroller::parm(Parmscontroller::Parm::PM_WindowButtonBarSize))), m_pixColor); m_pmaximumBtn->setIcon(maxIcon); } else { auto maxIcon = ThemeController::drawColoredPixmap(QIcon::fromTheme("window-restore-symbolic").pixmap(QSize(Parmscontroller::parm(Parmscontroller::Parm::PM_WindowButtonBarSize), Parmscontroller::parm(Parmscontroller::Parm::PM_WindowButtonBarSize))), m_pixColor); m_pmaximumBtn->setIcon(maxIcon); } } } } #include "kwindowbuttonbar.moc" #include "moc_kwindowbuttonbar.cpp" libkysdk-applications/kysdk-qtwidgets/src/knavigationbar.cpp0000664000175000017500000012717615104543305023446 0ustar fengfeng/* * libkysdk-qtwidgets's Library * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #include "knavigationbar.h" #include "parmscontroller.h" #include "themeController.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "accessinfohelper.h" namespace kdk { enum ItemType { StandardItem = 0, SubItem, TagItem }; class ListView : public QListView { public: ListView(QWidget *parent); QPoint mousePoint(); protected: void mousePressEvent(QMouseEvent *event); virtual void mouseMoveEvent(QMouseEvent *e) override; virtual void leaveEvent(QEvent *event); bool eventFilter(QObject *watched, QEvent *event); private: QPoint m_mousePoint; }; class Delegate : public QStyledItemDelegate, public ThemeController { Q_OBJECT public: Delegate(QObject *parent, ListView *view); void setTabValueVisible(bool visible); void setAddIcon(QString tag, QIcon icon); void setAddTagVisible(QString tag, bool visible); void setExtendIcon(QString tag, QIcon icon); void setExtendTagVisible(QString tag, bool visible); Q_SIGNALS: void addClicked(QString str); void extendClicked(QString str, int row); protected: void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override; QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const override; virtual bool editorEvent(QEvent *event, QAbstractItemModel *model, const QStyleOptionViewItem &option, const QModelIndex &index) override; private: ListView *m_listView; bool tabValueVisible; QList m_extendList; QList m_addList; QMap m_addVisibleMap; QMap m_extendVisibleMap; QMap m_addIconMap; QMap m_extendIconMap; bool addPress; bool extendPress; }; class KNavigationBarPrivate : public QObject { Q_OBJECT Q_DECLARE_PUBLIC(KNavigationBar) public: KNavigationBarPrivate(KNavigationBar *parent); void changeTheme(); QString setTagForItem(QStandardItem *item); private: KNavigationBar *q_ptr; ListView *m_pView; QStandardItemModel *m_pModel; Delegate *m_pDelegate; QMap> m_itemMap; int num; QModelIndex m_index; bool m_indexFlag; }; KNavigationBar::KNavigationBar(QWidget *parent) : QScrollArea(parent) , d_ptr(new KNavigationBarPrivate(this)) { Q_D(KNavigationBar); d->m_pView->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); d->m_pView->verticalScrollBar()->setProperty("drawScrollBarGroove",false); setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); d->num = 0; d->m_indexFlag = false; setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Expanding); // d->m_pView = new ListView (this); d->m_pView->setResizeMode(QListView::Adjust); // d->m_pModel = new QStandardItemModel(d->m_pView); d->m_pView->setModel(d->m_pModel); QVBoxLayout *vLayout = new QVBoxLayout(this); vLayout->setSizeConstraint(QLayout::SizeConstraint::SetMaximumSize); vLayout->setContentsMargins(0, 0, 0, 0); vLayout->setSpacing(0); vLayout->addWidget(d->m_pView); QWidget *vp = viewport(); vp->setLayout(vLayout); setWidget(d->m_pView); d->m_pView->setFocus(); QPalette p = this->palette(); QColor color(0, 0, 0, 0); p.setColor(QPalette::Base, color); d->m_pView->setPalette(p); this->setPalette(p); d->m_pView->setFrameStyle(0); // d->m_pDelegate = new Delegate(this,d->m_pView); d->m_pView->setItemDelegate(d->m_pDelegate); d->m_pView->setEditTriggers(QAbstractItemView::NoEditTriggers); this->setFrameStyle(0); this->setBackgroundRole(QPalette::Base); this->setAutoFillBackground(true); d->changeTheme(); connect(d->m_pDelegate->m_gsetting, &QGSettings::changed, this, [=]() { d->changeTheme(); }); connect(Parmscontroller::self(), &Parmscontroller::modeChanged, this, [=]() { // if(Parmscontroller::isTabletMode()) //解决导航栏滑动条切换主题为白条 // d->m_pView->setStyleSheet("QListView item {height : 48}"); // else // d->m_pView->setStyleSheet("QListView item {height : 36}"); updateGeometry(); }); connect(d->m_pDelegate, &Delegate::addClicked, this, &KNavigationBar::addTagClicked); connect(d->m_pDelegate, &Delegate::extendClicked, this, [=](QString str, int row) { if (d->m_itemMap.contains(str)) { QStringList list; for (auto item : d->m_itemMap[str]) { list.append(item->data(Qt::DisplayRole).toString()); } if (list.contains(d->m_pView->currentIndex().data(Qt::DisplayRole).toString())) // 选中的为group中 { d->m_index = d->m_pView->currentIndex(); d->m_pView->setCurrentIndex(QModelIndex()); } else if (!list.contains(d->m_pView->currentIndex().data(Qt::DisplayRole).toString()) && d->m_pView->currentIndex().isValid()) // 选中的为group外 { d->m_index = d->m_pView->currentIndex(); d->m_pView->setCurrentIndex(QModelIndex()); } for (auto item : d->m_itemMap[str]) { bool flag = item->data(boolRole).toBool(); if (flag) { item->setData(false, boolRole); d->m_pModel->takeRow(item->row()); d->m_pDelegate->setExtendIcon(str, QIcon::fromTheme("ukui-down.symbolic")); if (list.contains(d->m_index.data(Qt::DisplayRole).toString())) // 选中的group中item才更改标志位 d->m_indexFlag = true; } else { item->setData(true, boolRole); d->m_pModel->insertRow(++row, item); d->m_pDelegate->setExtendIcon(str, QIcon::fromTheme("ukui-up.symbolic")); d->m_indexFlag = false; } } if (!d->m_indexFlag && d->m_index.isValid()) { d->m_pView->setCurrentIndex(d->m_index); d->m_index = QModelIndex(); } else if (d->m_indexFlag && d->m_index.isValid()) { d->m_pView->setCurrentIndex(QModelIndex()); } } }); setMouseTracking(true); } void KNavigationBar::addItem(QStandardItem *item) { Q_D(KNavigationBar); item->setData(ItemType::StandardItem, Qt::UserRole); item->setData(true, boolRole); d->m_pModel->appendRow(item); d->num++; d->setTagForItem(item); } void KNavigationBar::addSubItem(QStandardItem *subItem) { Q_D(KNavigationBar); subItem->setData(ItemType::SubItem, Qt::UserRole); subItem->setData(true, boolRole); QPixmap pix(24, 24); pix.fill(Qt::transparent); QIcon icon(pix); subItem->setIcon(icon); d->m_pModel->appendRow(subItem); d->num++; d->setTagForItem(subItem); } void KNavigationBar::addGroupItems(QList items, const QString &tag) { Q_D(KNavigationBar); QStandardItem *item = new QStandardItem(tag); QList itemList; item->setEnabled(false); item->setData(ItemType::TagItem, Qt::UserRole); item->setData(true, boolRole); d->num++; QFileInfo cmdInfo(QApplication::arguments().at(0)); QString accessibleName = cmdInfo.fileName(); accessibleName += "_KNavigationBar_tag_" + tag; item->setAccessibleText(accessibleName); d->m_pModel->appendRow(item); for (auto item : items) { item->setData(true, boolRole); item->setData(ItemType::StandardItem, Qt::UserRole); itemList.append(item); d->m_pModel->appendRow(item); d->num++; d->setTagForItem(item); } d->m_itemMap[tag] = itemList; } void KNavigationBar::insertGroupItems(QString tag, int row, QStandardItem *item) { Q_D(KNavigationBar); if (d->m_itemMap.contains(tag)) { QList itemList = d->m_itemMap[tag]; if (!itemList.contains(item)) { if ((0 <= row && row < itemList.count())) { QStandardItem *privItem = itemList.at(row); item->setData(itemList.at(0)->data(boolRole).toBool(), boolRole); itemList.insert(row, item); d->m_itemMap[tag] = itemList; d->m_pModel->insertRow(privItem->row(), item); } else if (0 <= row && row == itemList.count()) { for (int insertRow = 0; insertRow < d->m_pModel->rowCount(); ++insertRow) { QStandardItem *privItem = d->m_pModel->item(insertRow); if (privItem && privItem->data(Qt::DisplayRole).toString() == tag) { item->setData(itemList.at(0)->data(boolRole).toBool(), boolRole); itemList.insert(insertRow, item); d->m_itemMap[tag] = itemList; d->m_pModel->insertRow(privItem->row() + itemList.count(), item); break; } } } } } } void KNavigationBar::removeGroupItem(QString tag, QStandardItem *item) { Q_D(KNavigationBar); if (d->m_itemMap.contains(tag)) { QList itemList = d->m_itemMap[tag]; if (itemList.contains(item)) { itemList.removeOne(item); d->m_itemMap[tag] = itemList; for (int row = 0; row < d->m_pModel->rowCount(); ++row) { QStandardItem *modelItem = d->m_pModel->item(row); if (modelItem == item) { d->m_pModel->takeRow(modelItem->row()); } } } } } void KNavigationBar::addTag(const QString &tag) { Q_D(KNavigationBar); QStandardItem *item = new QStandardItem(tag); d->num++; d->setTagForItem(item); QFileInfo cmdInfo(QApplication::arguments().at(0)); QString accessibleName = cmdInfo.fileName(); accessibleName += "_KNavigationBar_tag_" + tag; item->setAccessibleText(accessibleName); item->setEnabled(false); item->setData(ItemType::TagItem, Qt::UserRole); item->setData(true, boolRole); d->m_pModel->appendRow(item); } QStandardItemModel *KNavigationBar::model() { Q_D(KNavigationBar); return d->m_pModel; } QListView *KNavigationBar::listview() { Q_D(KNavigationBar); return d->m_pView; } void KNavigationBar::setTabValue(QStandardItem *item, QString value) { Q_D(KNavigationBar); item->setData(value, ValueRole); update(); } void KNavigationBar::setTabValueVisible(bool visible) { Q_D(KNavigationBar); d->m_pDelegate->setTabValueVisible(visible); } void KNavigationBar::setAddIcon(QString tag, QIcon icon) { Q_D(KNavigationBar); d->m_pDelegate->setAddIcon(tag, icon); } void KNavigationBar::setAddTagVisible(QString tag, bool visible) { Q_D(KNavigationBar); d->m_pDelegate->setAddTagVisible(tag, visible); } void KNavigationBar::setExtendTagVisible(QString tag, bool visible) { Q_D(KNavigationBar); d->m_pDelegate->setExtendTagVisible(tag, visible); } KNavigationBarPrivate::KNavigationBarPrivate(KNavigationBar *parent) : q_ptr(parent) { Q_Q(KNavigationBar); setParent(parent); m_pView = new ListView(q); m_pModel = new QStandardItemModel(m_pView); m_pDelegate = new Delegate(q, m_pView); KDK_ALL_INFO_FORMAT(m_pView,""); KDK_OBJ_INFO_FORMAT(m_pModel); KDK_OBJ_INFO_FORMAT(m_pDelegate); } void KNavigationBarPrivate::changeTheme() { Q_Q(KNavigationBar); m_pDelegate->initThemeStyle(); } QString KNavigationBarPrivate::setTagForItem(QStandardItem *item) { QFileInfo cmdInfo(QApplication::arguments().at(0)); QString accessibleName = cmdInfo.fileName(); accessibleName += "_"; accessibleName += "QStandardItem"; accessibleName += "_"; accessibleName += item->data(0).toString(); item->setAccessibleText(accessibleName); return accessibleName; } Delegate::Delegate(QObject *parent, ListView *view) : QStyledItemDelegate(parent) , m_listView(view) { tabValueVisible = false; addPress = false; extendPress = false; m_listView->setMouseTracking(true); } void Delegate::setTabValueVisible(bool visible) { tabValueVisible = visible; } void Delegate::setAddIcon(QString tag, QIcon icon) { m_addIconMap[tag] = icon; } void Delegate::setAddTagVisible(QString tag, bool visible) { if (!m_addList.contains(tag)) m_addList.append(tag); if (!m_addIconMap.contains(tag)) m_addIconMap[tag] = QIcon::fromTheme("list-add.symbolic"); m_addVisibleMap[tag] = visible; } void Delegate::setExtendIcon(QString tag, QIcon icon) { m_extendIconMap[tag] = icon; } void Delegate::setExtendTagVisible(QString tag, bool visible) { if (!m_extendList.contains(tag)) m_extendList.append(tag); if (!m_extendIconMap.contains(tag)) m_extendIconMap[tag] = QIcon::fromTheme("ukui-up.symbolic"); m_extendVisibleMap[tag] = visible; } void Delegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const { QLinearGradient m_linearGradient; QRectF rect; rect.setX(option.rect.x()); rect.setY(option.rect.y() + 1); rect.setWidth(m_listView->width() - 16 -1 );//16滑动条宽度 1修正右侧显示滑动条选中item显示不全 // rect.setHeight(option.rect.height()-2); rect.setHeight(option.rect.height() - Parmscontroller::parm(Parmscontroller::Parm::PM_NavigationBatInterval)); // QPainterPath画圆角矩形 qreal radius = ThemeController::getRadiusFromDT("kradius-normal"); // 圆角半径6px if (radius == -1) radius = 6; QPainterPath path; path.moveTo(rect.topRight() - QPointF(radius, 0)); path.lineTo(rect.topLeft() + QPointF(radius, 0)); path.quadTo(rect.topLeft(), rect.topLeft() + QPointF(0, radius)); path.lineTo(rect.bottomLeft() + QPointF(0, -radius)); path.quadTo(rect.bottomLeft(), rect.bottomLeft() + QPointF(radius, 0)); path.lineTo(rect.bottomRight() - QPointF(radius, 0)); path.quadTo(rect.bottomRight(), rect.bottomRight() + QPointF(0, -radius)); path.lineTo(rect.topRight() + QPointF(0, radius)); path.quadTo(rect.topRight(), rect.topRight() + QPointF(-radius, -0)); int flag = index.model()->data(index, Qt::UserRole).toInt(); painter->setRenderHint(QPainter::Antialiasing); painter->setRenderHint(QPainter::TextAntialiasing); painter->setRenderHint(QPainter::SmoothPixmapTransform); QColor color; QColor valueColor = ThemeController::getCustomColorFromDT("windowtext-active"); QColor borColor; m_linearGradient = QLinearGradient(rect.width() / 2, rect.y(), rect.width() / 2, rect.height() + rect.y()); if (!(option.state & QStyle::State_Enabled)) { color = ThemeController::getCustomColorFromDT("kcomponent-selected-alpha-disable"); borColor = ThemeController::getCustomColorFromDT("kfont-primary-disable"); } else if (((m_listView->currentIndex() == index) || (option.state & QStyle::State_Selected) || (option.state & QStyle::State_MouseOver)) && flag != 2) { if ((m_listView->currentIndex() == index) || (option.state & QStyle::State_Selected)) { color = ThemeController::getCustomColorFromDT("highlight-active"); borColor = ThemeController::getCustomColorFromDT("kline-brand-normal"); if(ThemeController::widgetTheme() == FashionTheme) { QColor startColor; QColor endColor; ThemeController::getGradientFromDT("highlight-active",startColor,endColor); m_linearGradient.setColorAt(0,startColor); m_linearGradient.setColorAt(1,endColor); } } else { // hover时 color = ThemeController::getCustomColorFromDT("kcomponent-selected-alpha-normal"); borColor = ThemeController::getCustomColorFromDT("kline-component-normal"); if(ThemeController::widgetTheme() == FashionTheme) { QColor startColor; QColor endColor; ThemeController::getGradientFromDT("kcomponent-selected-alpha-normal",startColor,endColor); m_linearGradient.setColorAt(0,startColor); m_linearGradient.setColorAt(1,endColor); } } painter->save(); painter->setPen(borColor); if(ThemeController::widgetTheme() == FashionTheme) painter->setBrush(m_linearGradient); else painter->setBrush(color); if (painter->pen().width() == 1) painter->translate(0.5, 0.5); painter->drawPath(path); painter->restore(); } switch (flag) { case 0: // standardItem { QRect iconRect; if (ThemeController::systemLang()) iconRect = QRect(rect.right() - 32, rect.y() + (rect.height() - 16) / 2, 16, 16); // 图片大小16*16 左边距16 else iconRect = QRect(rect.x() + 16, rect.y() + (rect.height() - 16) / 2, 16, 16); auto *model = dynamic_cast(const_cast(index.model())); auto icon = model->item(index.row())->icon(); if (!icon.pixmap(16, 16).isNull()) { if (ThemeController::isPixmapPureColor(icon.pixmap(16, 16))) { if (ThemeController::themeMode() == DarkTheme) icon = ThemeController::drawSymbolicColoredPixmap(icon.pixmap(16, 16)); if ((m_listView->currentIndex() == index) || (option.state & QStyle::State_Selected)) if (ThemeController::widgetTheme() != ClassicTheme) icon = ThemeController::drawColoredPixmap(icon.pixmap(16, 16), ThemeController::getCustomColorFromDT("kwhite")); if (!(option.state & QStyle::State_Enabled)) icon = ThemeController::drawColoredPixmap(icon.pixmap(16, 16), ThemeController::getCustomColorFromDT("kgray-14")); } } icon.paint(painter, iconRect); QFontMetrics fm = painter->fontMetrics(); QString mainText = index.data(Qt::DisplayRole).toString(); QString subText = index.data(Qt::UserRole + 1).toString(); QString elidedText; QRect textRect, subRect; if (subText.isEmpty()) { elidedText = fm.elidedText(mainText, Qt::ElideRight, rect.width() - 56); // 左边距+图片宽度+文本图片间距+右边距 if (fm.horizontalAdvance(mainText) > rect.width() - 56) model->item(index.row())->setToolTip(mainText); if (!icon.isNull()) { textRect = QRect(iconRect.right() + 8, rect.y(), rect.width() - 56, rect.height()); } else { textRect = QRect(rect.x() + 16, rect.y(), rect.width() - 56, rect.height()); } } else { elidedText = fm.elidedText(mainText, Qt::ElideRight, rect.width() - 56 - fm.horizontalAdvance(subText)); subRect = QRect(rect.right() - 8 - fm.horizontalAdvance(subText), rect.y(), fm.horizontalAdvance(subText), rect.height()); if (fm.horizontalAdvance(mainText) > rect.width() - 56 - fm.horizontalAdvance(subText)) model->item(index.row())->setToolTip(mainText); if (!icon.isNull()) { textRect = QRect(iconRect.right() + 8, rect.y(), rect.width() - 56 - fm.horizontalAdvance(subText), rect.height()); } else { textRect = QRect(rect.x() + 16, rect.y(), rect.width() - 56 - fm.horizontalAdvance(subText), rect.height()); } } painter->save(); if ((m_listView->currentIndex() == index) || (option.state & QStyle::State_Selected)) { valueColor = ThemeController::getCustomColorFromDT("kwhite"); painter->setPen(ThemeController::getCustomColorFromDT("highlightedtext-active")); } QFont font; font.setPointSize(ThemeController::systemFontSize()); if (!(option.state & QStyle::State_Enabled)) { painter->setPen(borColor); } painter->setFont(font); if (!subText.isEmpty() && tabValueVisible) { if (ThemeController::themeMode() == LightTheme) valueColor.setAlphaF(0.4); painter->save(); painter->setPen(valueColor); painter->drawText(subRect, Qt::AlignVCenter, subText); painter->restore(); } if (!icon.isNull()) { if (ThemeController::systemLang()) { painter->drawText(QRect(rect.left() + 16, rect.y(), rect.width() - 56, rect.height()), Qt::AlignVCenter, elidedText); // 文本 图片间距8px } else painter->drawText(QRect(iconRect.right() + 8, rect.y(), rect.width() - 56, rect.height()), Qt::AlignVCenter, elidedText); } else { if (ThemeController::systemLang()) painter->drawText(QRect(rect.x() + 16, rect.y(), rect.width() - 56, rect.height()), Qt::AlignVCenter, elidedText); else painter->drawText(QRect(rect.x() + 16, rect.y(), rect.width() - 56, rect.height()), Qt::AlignVCenter, elidedText); } painter->restore(); break; } case 1: // subItem { QRect iconRect = QRect(rect.x() + 16, rect.y() + (rect.height() - 16) / 2, 16, 16); // 图片大小16*16 左边距16 auto *model = dynamic_cast(const_cast(index.model())); QFontMetrics fm = painter->fontMetrics(); QString mainText = index.data(Qt::DisplayRole).toString(); QString subText = index.data(Qt::UserRole + 1).toString(); QString elidedText; QRect textRect, subRect; if (subText.isEmpty()) { elidedText = fm.elidedText(mainText, Qt::ElideRight, rect.width() - 56); // 左边距+图片宽度+文本图片间距+右边距 textRect = QRect(iconRect.right() + 8, rect.y(), rect.width() - 56, rect.height()); if (fm.horizontalAdvance(mainText) > rect.width() - 56) model->item(index.row())->setToolTip(mainText); } else { elidedText = fm.elidedText(mainText, Qt::ElideRight, rect.width() - 56 - fm.horizontalAdvance(subText)); textRect = QRect(iconRect.right() + 8, rect.y(), rect.width() - 56 - fm.horizontalAdvance(subText), rect.height()); subRect = QRect(rect.right() - 8 - fm.horizontalAdvance(subText), rect.y(), fm.horizontalAdvance(subText), rect.height()); if (fm.horizontalAdvance(mainText) > rect.width() - 56 - fm.horizontalAdvance(subText)) model->item(index.row())->setToolTip(mainText); } painter->save(); if ((option.state & QStyle::State_Selected)) { valueColor = ThemeController::getCustomColorFromDT("kwhite"); painter->setPen(ThemeController::getCustomColorFromDT("highlightedtext-active")); } QFont font; font.setPointSize(ThemeController::systemFontSize()); if (!(option.state & QStyle::State_Enabled)) { painter->setPen(borColor); } painter->setFont(font); if (!subText.isEmpty() && tabValueVisible) { if (ThemeController::themeMode() == LightTheme) valueColor.setAlphaF(0.4); painter->setPen(valueColor); painter->drawText(subRect, Qt::AlignVCenter, subText); } if (ThemeController::systemLang()) painter->drawText(QRect(rect.x() + 16, rect.y(), rect.width() - 56, rect.height()), Qt::AlignVCenter, elidedText); // 文本 图片间距8px else painter->drawText(QRect(iconRect.right() + 8, rect.y(), rect.width() - 56, rect.height()), Qt::AlignVCenter, elidedText); painter->restore(); break; } case 2: // tagItem { painter->save(); auto *model = dynamic_cast(const_cast(index.model())); QFontMetrics fm = painter->fontMetrics(); QString elidedText = fm.elidedText(index.model()->data(index, Qt::DisplayRole).toString(), Qt::ElideRight, rect.width() - 56); // 左边距+图片宽度+文本图片间距+右边距 QString mainText = index.data(Qt::DisplayRole).toString(); if (fm.horizontalAdvance(mainText) > rect.width() - 56) model->item(index.row())->setToolTip(mainText); painter->setPen(ThemeController::getCustomColorFromDT("kfont-secondary")); if (m_addList.contains(mainText) || m_extendList.contains(mainText)) { QPixmap extendPixmap = m_extendIconMap.value(mainText).pixmap(16, 16); QPixmap addPixmap = m_addIconMap.value(mainText).pixmap(16, 16); if (ThemeController::themeMode() == DarkTheme) { extendPixmap = ThemeController::drawColoredPixmap(extendPixmap, ThemeController::getCustomColorFromDT("windowtext-active")); addPixmap = ThemeController::drawColoredPixmap(addPixmap, ThemeController::getCustomColorFromDT("windowtext-active")); } if (m_addVisibleMap.value(mainText)) { painter->save(); painter->setRenderHints(QPainter::Antialiasing | QPainter::TextAntialiasing | QPainter::SmoothPixmapTransform); painter->setPen(Qt::NoPen); painter->setBrush(Qt::NoBrush); if (m_extendVisibleMap.value(mainText)) { QRect extendRect; // = option.rect.adjusted(option.rect.width() - 28 , 22 , -12 , -10 ); QRect extendBkgRect; // = option.rect.adjusted(option.rect.width() - 32 , 18 , -8 , -6 ); if (m_listView->verticalScrollBar()->isVisible()) { extendRect = option.rect.adjusted(option.rect.width() - 28, 22, -12, -10); extendBkgRect = option.rect.adjusted(option.rect.width() - 32, 18, -8, -6); } else { extendRect = option.rect.adjusted(option.rect.width() - 28 - 16, 22, -12 - 16, -10); extendBkgRect = option.rect.adjusted(option.rect.width() - 32 - 16, 18, -8 - 16, -6); } if (extendPress && extendBkgRect.contains(m_listView->mousePoint())) painter->setBrush(ThemeController::mixColor(ThemeController::getCustomColorFromDT("button-active"), ThemeController::getCustomColorFromDT("brighttext-active"), 0.2)); else if (extendBkgRect.contains(m_listView->mousePoint())) { if (m_extendIconMap.value(mainText).name().contains("ukui-down.symbolic")) QToolTip::showText(QCursor::pos(), tr("Expand"), qobject_cast(const_cast(option.widget))); else QToolTip::showText(QCursor::pos(), tr("Fold"), qobject_cast(const_cast(option.widget))); painter->setBrush(ThemeController::mixColor(ThemeController::getCustomColorFromDT("button-active"), ThemeController::getCustomColorFromDT("brighttext-active"), 0.05)); } painter->drawRoundedRect(extendBkgRect, 6, 6); painter->drawPixmap(extendRect, extendPixmap); painter->setBrush(Qt::NoBrush); QRect addRect; // = option.rect.adjusted(option.rect.width() - 60, 22 , -44 , -10 ); QRect addBkgRect; // = option.rect.adjusted(option.rect.width() - 64, 18 , -40 , -6 ); if (m_listView->verticalScrollBar()->isVisible()) { addRect = option.rect.adjusted(option.rect.width() - 60, 22, -44, -10); addBkgRect = option.rect.adjusted(option.rect.width() - 64, 18, -40, -6); } else { addRect = option.rect.adjusted(option.rect.width() - 60 - 16, 22, -44 - 16, -10); addBkgRect = option.rect.adjusted(option.rect.width() - 64 - 16, 18, -40 - 16, -6); } if (addPress && addBkgRect.contains(m_listView->mousePoint())) { painter->setBrush(ThemeController::mixColor(ThemeController::getCustomColorFromDT("button-active"), ThemeController::getCustomColorFromDT("brighttext-active"), 0.2)); } else if (addBkgRect.contains(m_listView->mousePoint())) { QToolTip::showText(QCursor::pos(), tr("Add tag"), qobject_cast(const_cast(option.widget))); painter->setBrush(ThemeController::mixColor(ThemeController::getCustomColorFromDT("button-active"), ThemeController::getCustomColorFromDT("brighttext-active"), 0.05)); } if (!addBkgRect.contains(m_listView->mousePoint()) && !extendBkgRect.contains(m_listView->mousePoint())) { QToolTip::showText(QCursor::pos(), "", qobject_cast(const_cast(option.widget))); } painter->drawRoundedRect(addBkgRect, 6, 6); painter->drawPixmap(addRect, addPixmap); } else { QRect addRect; // = option.rect.adjusted(option.rect.width() - 28 , 22 , -12 , -10 ); QRect addBkgRect; // = option.rect.adjusted(option.rect.width() - 32 , 18 , -8 , -6); if (m_listView->verticalScrollBar()->isVisible()) { addRect = option.rect.adjusted(option.rect.width() - 28, 22, -12, -10); addBkgRect = option.rect.adjusted(option.rect.width() - 32, 18, -8, -6); } else { addRect = option.rect.adjusted(option.rect.width() - 28 - 16, 22, -12 - 16, -10); addBkgRect = option.rect.adjusted(option.rect.width() - 32 - 16, 18, -8 - 16, -6); } if (addPress && addBkgRect.contains(m_listView->mousePoint())) { painter->setBrush(ThemeController::mixColor(ThemeController::getCustomColorFromDT("button-active"), ThemeController::getCustomColorFromDT("brighttext-active"), 0.2)); } else if (addBkgRect.contains(m_listView->mousePoint())) { QToolTip::showText(QCursor::pos(), tr("Add tag"), qobject_cast(const_cast(option.widget))); painter->setBrush(ThemeController::mixColor(ThemeController::getCustomColorFromDT("button-active"), ThemeController::getCustomColorFromDT("brighttext-active"), 0.05)); } if (!addBkgRect.contains(m_listView->mousePoint())) { QToolTip::showText(QCursor::pos(), "", qobject_cast(const_cast(option.widget))); } painter->drawRoundedRect(addBkgRect, 6, 6); painter->drawPixmap(addRect, addPixmap); } painter->restore(); } else { painter->save(); painter->setRenderHints(QPainter::Antialiasing | QPainter::TextAntialiasing | QPainter::SmoothPixmapTransform); painter->setBrush(Qt::NoBrush); QPixmap extendPixmap = m_extendIconMap.value(mainText).pixmap(16, 16); if (ThemeController::themeMode() == DarkTheme) { extendPixmap = ThemeController::drawSymbolicColoredPixmap(extendPixmap); } if (m_extendVisibleMap.value(mainText)) { QRect extendRect; // = option.rect.adjusted(option.rect.width() - 28 , 22 , -12 , -10 ); QRect extendBkgRect; // = option.rect.adjusted(option.rect.width() - 32 , 18 , -8 , -6 ); if (m_listView->verticalScrollBar()->isVisible()) { extendRect = option.rect.adjusted(option.rect.width() - 28, 22, -12, -10); extendBkgRect = option.rect.adjusted(option.rect.width() - 32, 18, -8, -6); } else { extendRect = option.rect.adjusted(option.rect.width() - 28 - 16, 22, -12 - 16, -10); extendBkgRect = option.rect.adjusted(option.rect.width() - 32 - 16, 18, -8 - 16, -6); } if (extendPress && extendBkgRect.contains(m_listView->mousePoint())) painter->setBrush(ThemeController::mixColor(ThemeController::getCustomColorFromDT("button-active"), ThemeController::getCustomColorFromDT("brighttext-active"), 0.2)); else if (extendBkgRect.contains(m_listView->mousePoint())) { if (m_extendIconMap.value(mainText).name().contains("ukui-down.symbolic")) QToolTip::showText(QCursor::pos(), tr("Expand"), qobject_cast(const_cast(option.widget))); else QToolTip::showText(QCursor::pos(), tr("Fold"), qobject_cast(const_cast(option.widget))); painter->setBrush(ThemeController::mixColor(ThemeController::getCustomColorFromDT("button-active"), ThemeController::getCustomColorFromDT("brighttext-active"), 0.05)); } if (!extendBkgRect.contains(m_listView->mousePoint())) { QToolTip::showText(QCursor::pos(), ""); } painter->drawRoundedRect(extendBkgRect, 6, 6); painter->drawPixmap(extendRect, extendPixmap); } painter->restore(); } } QRect textRect = option.rect; textRect = textRect.adjusted(16, 12, 0, 0); QFont font; font.setPointSize(ThemeController::systemFontSize()); painter->setFont(font); painter->drawText(textRect, Qt::AlignVCenter, elidedText); painter->restore(); break; } default: break; } } QSize Delegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const { int flag = index.model()->data(index, Qt::UserRole).toInt(); QSize size; switch (flag) { case 2: // tagItem size.setHeight(Parmscontroller::parm(Parmscontroller::Parm::PM_NavigationBatHeight) + 12); break; default: size.setHeight(Parmscontroller::parm(Parmscontroller::Parm::PM_NavigationBatHeight) + Parmscontroller::parm(Parmscontroller::Parm::PM_NavigationBatInterval)); break; } size.setWidth(m_listView->width() - 16); return size; } bool Delegate::editorEvent(QEvent *event, QAbstractItemModel *model, const QStyleOptionViewItem &option, const QModelIndex &index) { if (event->type() == QEvent::MouseButtonPress || event->type() == QEvent::Enter) { QMouseEvent *mouseEvent = static_cast(event); QRect addRect; QRect extendRect; QString mainText = index.data(Qt::DisplayRole).toString(); if (m_addList.contains(mainText) || m_extendList.contains(mainText)) { if (m_addVisibleMap.value(mainText)) { if (m_extendVisibleMap.value(mainText)) { if (m_listView->verticalScrollBar()->isVisible()) { extendRect = option.rect.adjusted(option.rect.width() - 32, 18, -8, -6); addRect = option.rect.adjusted(option.rect.width() - 64, 18, -40, -6); } else { extendRect = option.rect.adjusted(option.rect.width() - 32 - 16, 18, -8 - 16, -6); addRect = option.rect.adjusted(option.rect.width() - 64 - 16, 18, -40 - 16, -6); } if (extendRect.contains(mouseEvent->pos())) { if (event->type() == QEvent::MouseButtonPress) { extendPress = true; emit extendClicked(mainText, index.row()); } else { extendPress = false; } } if (addRect.contains(mouseEvent->pos())) { if (event->type() == QEvent::MouseButtonPress) { addPress = true; emit addClicked(mainText); } else { addPress = false; } } } else { if (m_listView->verticalScrollBar()->isVisible()) addRect = option.rect.adjusted(option.rect.width() - 32, 18, -8, -6); else addRect = option.rect.adjusted(option.rect.width() - 32 - 16, 18, -8 - 16, -6); if (addRect.contains(mouseEvent->pos())) { if (event->type() == QEvent::MouseButtonPress) { addPress = true; emit addClicked(mainText); } else { addPress = false; } } } } else { if (m_extendVisibleMap.value(mainText)) { if (m_listView->verticalScrollBar()->isVisible()) extendRect = option.rect.adjusted(option.rect.width() - 32, 18, -8, -6); else extendRect = option.rect.adjusted(option.rect.width() - 32 - 16, 18, -8 - 16, -6); if (extendRect.contains(mouseEvent->pos())) { if (event->type() == QEvent::MouseButtonPress) { extendPress = true; emit extendClicked(mainText, index.row()); } else { extendPress = false; } } } } } } else { addPress = false; extendPress = false; } m_listView->viewport()->update(); return QStyledItemDelegate::editorEvent(event, model, option, index); } ListView::ListView(QWidget *parent) : QListView(parent) { setMouseTracking(true); installEventFilter(this); } QPoint ListView::mousePoint() { return m_mousePoint; } void ListView::mousePressEvent(QMouseEvent *event) { if (event->button() & Qt::RightButton) return; else if (event->button() & Qt::LeftButton) QListView::mousePressEvent(event); } void ListView::mouseMoveEvent(QMouseEvent *e) { m_mousePoint = e->pos(); QListView::mouseMoveEvent(e); } void ListView::leaveEvent(QEvent *event) { // QMouseEvent *mouseEvent = dynamic_cast(event); // m_mousePoint = mouseEvent->pos(); m_mousePoint = mapFromGlobal(QCursor::pos()); QListView::leaveEvent(event); } bool ListView::eventFilter(QObject *watched, QEvent *event) { if ( event->type() == QEvent::KeyPress) { QKeyEvent *keyEvent = static_cast(event); // 处理Tab键导航 if (keyEvent->key() == Qt::Key_Tab || keyEvent->key() == Qt::Key_Backtab || keyEvent->key() == Qt::Key_Up || keyEvent->key() == Qt::Key_Down) { QModelIndex currentIndex = this->currentIndex(); int rowCount = model()->rowCount(); if (rowCount == 0) { return true; } int newRow; if (currentIndex.isValid()) { if (keyEvent->key() == Qt::Key_Tab || keyEvent->key() == Qt::Key_Down) { newRow = (currentIndex.row() + 1) % rowCount; } else { newRow = (currentIndex.row() - 1 + rowCount) % rowCount; } } else { newRow = 0; } int attempts = 0; while (attempts < rowCount) { QModelIndex candidateIndex = model()->index(newRow, 0); if (candidateIndex.isValid() && (model()->flags(candidateIndex) & Qt::ItemIsEnabled) && (model()->flags(candidateIndex) & Qt::ItemIsSelectable)) { QVariant itemTypeData = model()->data(candidateIndex, Qt::UserRole); if (itemTypeData.isValid() && itemTypeData.toInt() == 2) { // TagItem if (keyEvent->key() == Qt::Key_Tab || keyEvent->key() == Qt::Key_Down) { newRow = (newRow + 1) % rowCount; } else { newRow = (newRow - 1 + rowCount) % rowCount; } attempts++; continue; } if(!isRowHidden(candidateIndex.row())) { setCurrentIndex(candidateIndex); scrollTo(candidateIndex); emit clicked(candidateIndex); return true; } } if ((keyEvent->key() == Qt::Key_Tab || keyEvent->key() == Qt::Key_Down)) { newRow = (newRow + 1) % rowCount; } else { newRow = (newRow - 1 + rowCount) % rowCount; } attempts++; } return true; } } if(event->type() == QEvent::FocusIn) { if(this->currentIndex().row() == -1 ) { if (model() && model()->rowCount() > 0) { for (int row = 0; row < model()->rowCount(); ++row) { QModelIndex candidateIndex = model()->index(row, 0); if (candidateIndex.isValid() && (model()->flags(candidateIndex) & Qt::ItemIsEnabled) && (model()->flags(candidateIndex) & Qt::ItemIsSelectable)) { QVariant itemTypeData = model()->data(candidateIndex, Qt::UserRole); if (!itemTypeData.isValid() || itemTypeData.toInt() != 2 && !isRowHidden(candidateIndex.row())) { setCurrentIndex(candidateIndex); emit clicked(candidateIndex); break; } } } } } } return QObject::eventFilter(watched, event); } } #include "knavigationbar.moc"; #include "moc_knavigationbar.cpp"; libkysdk-applications/kysdk-qtwidgets/src/kprogresscircle.h0000664000175000017500000000465115104543305023305 0ustar fengfeng/* * libkysdk-qtwidgets's Library * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #ifndef KPROGRESSCIRCLE_H #define KPROGRESSCIRCLE_H #include "gui_g.h" #include "kprogressbar.h" #include /** * @defgroup BarModule * { */ namespace kdk { class KProgressCirclePrivate; /** * @brief 以圆环样式显示进度,支持三种状态 * @since 1.0.0 */ class GUI_EXPORT KProgressCircle : public QWidget { Q_OBJECT public: explicit KProgressCircle(QWidget *parent = nullptr); /** * @brief 获取KProgressCircle最小值 * @return int */ int minimum() const; /** * @brief 获取KProgressCircle最大值 * @return int */ int maximum() const; /** * @brief 获取当前值 * @return int */ int value() const; /** * @brief 获取文本 * @return QString */ QString text() const; /** * @brief 设置文本是否可见 * @param visible */ void setTextVisible(bool visible); /** * @brief 返回文本是否可见 * @return bool */ bool isTextVisible() const; /** * @brief 获取当前KProgressCircle状态 * @return */ ProgressBarState state(); /** * @brief 设置当前KProgressCircle状态 * @param state */ void setState(ProgressBarState state); Q_SIGNALS: void valueChanged(int value); public Q_SLOTS: void reset(); void setRange(int minimum, int maximum); void setMinimum(int minimum); void setMaximum(int maximum); void setValue(int value); protected: void paintEvent(QPaintEvent *) override; private: Q_DECLARE_PRIVATE(KProgressCircle) KProgressCirclePrivate *const d_ptr; }; } #endif // KPROGRESSCIRCLE_H libkysdk-applications/kysdk-qtwidgets/src/kaddfilebutton.h0000664000175000017500000000403215104543305023074 0ustar fengfeng/* * libkysdk-qtwidgets's Library * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhenyu Wang * */ #ifndef KADDFILEBUTTON_H #define KADDFILEBUTTON_H #include "gui_g.h" #include #include namespace kdk { /** @defgroup PushbuttonModule */ class KAddFileButtonPrivate; /** * @brief 选择文件的按钮 * @since 2.4.1.0 */ class GUI_EXPORT KAddFileButton : public QPushButton { Q_OBJECT public: KAddFileButton(QWidget *parent = nullptr); /** * @brief 设置文本 * @param str */ void setText(QString str); /** * @brief 获取filedialog * @return QFileDialog */ QFileDialog *fileDialog(); /** * @brief 将文件对话框中使用的过滤器设置为给定的过滤器。 * @param filter */ void setNameFilter(const QString &filter); /** * @brief 设置文件对话框中使用的过滤器。 * @param filters */ void setNameFilters(const QStringList &filters); protected: void paintEvent(QPaintEvent *event); bool eventFilter(QObject *watched, QEvent *event); void mouseMoveEvent(QMouseEvent *event); void mousePressEvent(QMouseEvent *event); void mouseReleaseEvent(QMouseEvent *event); private: KAddFileButtonPrivate *const d_ptr; Q_DECLARE_PRIVATE(KAddFileButton) }; } #endif // KADDFILEBUTTON_H libkysdk-applications/kysdk-qtwidgets/src/kballontip.h0000664000175000017500000000567415104543305022251 0ustar fengfeng/* * libkysdk-qtwidgets's Library * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #ifndef KBALLONTIP_H #define KBALLONTIP_H #include "gui_g.h" #include #include namespace kdk { /** @defgroup MessageAlertModule * @{ */ /** * @brief 支持五种样式 * @since 1.0.0 */ enum TipType { Nothing, Normal, Info, Warning, Error, Variable, Loading }; class KBallonTipPrivate; /** * @brief 消息提示框,支持五种样式 */ class GUI_EXPORT KBallonTip : public QWidget { Q_OBJECT public: explicit KBallonTip(QWidget *parent = nullptr); explicit KBallonTip(const QString &content, const TipType &type, QWidget *parent = nullptr); /** * @brief 显示时间完毕后消失 * @since 1.2.0 */ void showInfo(); /** * @brief 设置类型 * @param type */ void setTipType(const TipType &type); /** * @brief 返回类型 * @return */ TipType tipType(); /** * @brief 设置文本内容 * @param text */ void setText(const QString &text); /** * @brief text * @return */ QString text(); /** * @brief 设置内容边距 * @param left * @param top * @param right * @param bottom */ void setContentsMargins(int left, int top, int right, int bottom); /** * @brief 设置内容边距 * @param margins */ void setContentsMargins(const QMargins &margins); /** * @brief 设置持续时间 * @since 1.2.0 */ void setTipTime(int my_time); /** * @brief 获取kballontip的水平布局 * @return * @since 2.4.1.0 */ QHBoxLayout *hBoxLayout(); /** * @brief 设置可变类型的icon * @param icon * @since 2.5.2.0 */ void setVariableIcon(QIcon icon); /** * @brief 获取可变类型的icon * @return * @since 2.5.2.0 */ QPixmap variableIcon(); private Q_SLOTS: void onTimeupDestroy(); protected: void paintEvent(QPaintEvent *event) override; private: Q_DECLARE_PRIVATE(KBallonTip) KBallonTipPrivate *const d_ptr; }; } /** * @example testballontip/widget.h * @example testballontip/widget.cpp * @} */ #endif // KBALLONTIP_H libkysdk-applications/kysdk-qtwidgets/src/knavigationtrail.h0000664000175000017500000000316215104543305023446 0ustar fengfeng/* * libkysdk-qtwidgets's Library * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhenyu Wang * */ #ifndef KNAVIGATIONTRAIL_H #define KNAVIGATIONTRAIL_H #include "kcrumb.h" #include namespace kdk { enum ButtonPosition { LeftPosition, LeftOrRight, RightPosition }; /** * @defgroup BarModule * @since 2.5.2.0 */ class KNavigationTrailPrivate; class KNavigationTrail : public QWidget { Q_OBJECT public: KNavigationTrail(QWidget *parent = nullptr); /** * @brief 获取kcrumb * @return */ KCrumb *crumb(); /** * @brief 设置箭头位置 * @param type */ void setPosition(ButtonPosition type); Q_SIGNALS: /** * @brief 点击会发出信号 */ void sizeChange(); protected: void resizeEvent(QResizeEvent *event); private: Q_DECLARE_PRIVATE(KNavigationTrail) KNavigationTrailPrivate *const d_ptr; }; } #endif // KNAVIGATIONTRAIL_H libkysdk-applications/kysdk-qtwidgets/src/knativetabbar.h0000664000175000017500000000453215104543305022717 0ustar fengfeng/* * libkysdk-qtwidgets's Library * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhenyu Wang * */ #ifndef KNAVETABBAR_H #define KNAVETABBAR_H #include "gui_g.h" #include "kcustomtabbar.h" #include #include namespace kdk { /** @defgroup BarModule * @brief 支持三种样式 * @since 2.5.2.0 * { */ enum KNativeTabbarStyle { SegmentDark, SegmentLight, Sliding }; class KNativeTabbarPrivate; class GUI_EXPORT KNativeTabbar : public KCustomTabBar { Q_OBJECT public: KNativeTabbar(KNativeTabbarStyle barStyle = SegmentLight, QWidget *parent = nullptr); ~KNativeTabbar(); /** * @brief 设置TabBar样式 * @param barStyle */ void setTabbarStyle(KNativeTabbarStyle barStyle); /** * @brief 返回TabBar样式 * @return */ KNativeTabbarStyle barStyle(); /** * @brief 设置圆角半径,只对SegmentDark,SegmentLight样式生效 * @param radius */ void setBorderRadius(int radius); /** * @brief 获取圆角半径 * @return */ int borderRadius(); /** * @brief 设置背景色 * @param color */ void setBackgroundColor(const QColor &color); Q_SIGNALS: /** * @brief 鼠标右键信号 * @param point */ void rightlicked(QPoint point); protected: QSize sizeHint() const; QSize minimumTabSizeHint(int index) const; QSize tabSizeHint(int index) const; void paintEvent(QPaintEvent *event); private: Q_DECLARE_PRIVATE(KNativeTabbar) KNativeTabbarPrivate *const d_ptr; }; } /** * @example testtabbar/widget.h * @example testtabbar/widget.cpp * @} */ #endif // KNAVETABBAR_H libkysdk-applications/kysdk-qtwidgets/src/kintrowidget.cpp0000664000175000017500000002450215104543305023146 0ustar fengfeng/* * libkysdk-qtwidgets's Library * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhenyu Wang * */ #include "kintrowidget.h" #include "klabel.h" #include "themeController.h" #include #include #include #include #include #include #include namespace kdk { class Q_DECL_HIDDEN KIntroWidgetPrivate : public QObject, public ThemeController { Q_OBJECT Q_DECLARE_PUBLIC(KIntroWidget) public: KIntroWidgetPrivate(KIntroWidget *parent); protected: void changeTheme(); private: KIntroWidget *const q_ptr; ViewType m_viewType; int m_bottomRightRadius; int m_topLeftRadius; int m_bottomLeftRadius; int m_topRightRadius; KLabel *m_pMainLabel; KLabel *m_pSubLabel; QColor m_bkgColor; QColor m_mixColor; QColor m_borderColor; QColor m_titleColor; }; KIntroWidgetPrivate::KIntroWidgetPrivate(KIntroWidget *parent) : q_ptr(parent) , m_viewType(ListView) { Q_Q(KIntroWidget); m_pMainLabel = new KLabel(); QFont font = q->font(); font.setBold(true); m_pMainLabel->setFont(font); m_pSubLabel = new KLabel(); QPalette palette; palette.setColor(QPalette::WindowText, QColor(140, 140, 140)); m_pSubLabel->setPalette(palette); m_pMainLabel->setAttribute(Qt::WA_TransparentForMouseEvents, true); m_pSubLabel->setAttribute(Qt::WA_TransparentForMouseEvents, true); m_titleColor = ThemeController::getCustomColorFromDT("highlight-active"); int radius = ThemeController::getRadiusFromDT("kradius-normal"); if (radius == -1) { m_bottomLeftRadius = 6; m_bottomRightRadius = 6; m_topLeftRadius = 6; m_topRightRadius = 6; } else { m_bottomLeftRadius = radius; m_bottomRightRadius = radius; m_topLeftRadius = radius; m_topRightRadius = radius; } } void KIntroWidgetPrivate::changeTheme() { Q_Q(KIntroWidget); initThemeStyle(); m_bkgColor = ThemeController::getCustomColorFromDT("tooltipbase-active"); m_borderColor = ThemeController::getCustomColorFromDT("tooltipbase-active"); m_borderColor.setAlphaF(0.08); if (ThemeController::themeMode() == LightTheme) m_mixColor = Qt::black; else m_mixColor = Qt::white; q->update(); } KIntroWidget::KIntroWidget(QWidget *parent) : QWidget(parent) , d_ptr(new KIntroWidgetPrivate(this)) { Q_D(KIntroWidget); if (d->m_viewType == ListView) setContentsMargins(22, 4, 16, 4); else setContentsMargins(22, d->m_topLeftRadius + 4, 16, 4); QVBoxLayout *vlayout = new QVBoxLayout(this); vlayout->setSpacing(0); vlayout->addWidget(d->m_pMainLabel); // vlayout->addSpacing(4); vlayout->addWidget(d->m_pSubLabel); installEventFilter(this); // setFixedSize(rect().width(),74); d->m_pMainLabel->setAlignment(Qt::AlignLeft); d->m_pSubLabel->setAlignment(Qt::AlignLeft); d->changeTheme(); connect(d->m_gsetting, &QGSettings::changed, this, [=] { d->changeTheme(); }); } void KIntroWidget::setViewType(ViewType type) { Q_D(KIntroWidget); d->m_viewType = type; if (d->m_viewType == ListView) setContentsMargins(22, 4, 16, 4); else setContentsMargins(22, d->m_topLeftRadius + 4, 16, 4); } void KIntroWidget::setMainLabel(QString str) { Q_D(KIntroWidget); d->m_pMainLabel->setText(str); } void KIntroWidget::setSubLabel(QString str) { Q_D(KIntroWidget); d->m_pSubLabel->setText(str); } void KIntroWidget::setBorderRadius(int radius) { Q_D(KIntroWidget); d->m_bottomRightRadius = radius; d->m_topLeftRadius = radius; d->m_bottomLeftRadius = radius; d->m_topRightRadius = radius; if (d->m_viewType == ListView) setContentsMargins(22, 4, 16, 4); else setContentsMargins(22, d->m_topLeftRadius + 4, 16, 4); } void KIntroWidget::setBorderRadius(int bottomLeft, int topLeft, int topRight, int bottomRight) { Q_D(KIntroWidget); d->m_bottomRightRadius = bottomRight; d->m_topLeftRadius = topLeft; d->m_bottomLeftRadius = bottomLeft; d->m_topRightRadius = topRight; if (d->m_viewType == ListView) setContentsMargins(22, 4, 16, 4); else setContentsMargins(22, d->m_topLeftRadius + 4, 16, 4); } void KIntroWidget::setTitleColor(QColor color) { Q_D(KIntroWidget); d->m_titleColor = color; } void KIntroWidget::paintEvent(QPaintEvent *event) { Q_D(KIntroWidget); QPainter painter(this); painter.setRenderHint(QPainter::Antialiasing); painter.setRenderHint(QPainter::SmoothPixmapTransform); painter.setPen(Qt::NoPen); QPainterPath path; QPainterPath path1; QPainterPath path2; QRect drawRect = this->rect(); path.moveTo(drawRect.topLeft() + QPoint(d->m_topLeftRadius, 0)); path.lineTo(drawRect.topRight() - QPoint(d->m_topRightRadius, 0)); path.quadTo(drawRect.topRight(), drawRect.topRight() + QPoint(0, d->m_topRightRadius)); path.lineTo(drawRect.bottomRight() - QPoint(0, d->m_bottomRightRadius)); path.quadTo(drawRect.bottomRight(), drawRect.bottomRight() - QPoint(d->m_bottomRightRadius, 0)); path.lineTo(drawRect.bottomLeft() + QPoint(d->m_bottomLeftRadius, 0)); path.quadTo(drawRect.bottomLeft(), drawRect.bottomLeft() - QPoint(0, d->m_bottomLeftRadius)); path.lineTo(drawRect.topLeft() + QPoint(0, d->m_topLeftRadius)); path.quadTo(drawRect.topLeft(), drawRect.topLeft() + QPoint(d->m_topLeftRadius, 0)); switch (d->m_viewType) { case ViewType::IconView: { // d->m_pMainLabel->setAlignment(Qt::AlignCenter); // d->m_pSubLabel->setAlignment(Qt::AlignCenter); d->m_pMainLabel->setWordWrap(true); d->m_pSubLabel->setWordWrap(true); path1.moveTo(drawRect.topLeft() + QPoint(d->m_topLeftRadius, 0)); path1.lineTo(drawRect.topRight() - QPoint(d->m_topRightRadius, 0)); path1.quadTo(drawRect.topRight(), drawRect.topRight() + QPoint(0, d->m_topRightRadius)); path1.lineTo(drawRect.topLeft() + QPoint(0, d->m_topLeftRadius)); path1.quadTo(drawRect.topLeft(), drawRect.topLeft() + QPoint(d->m_topLeftRadius, 0)); path2.moveTo(drawRect.topLeft() + QPoint(0, d->m_topLeftRadius)); path2.lineTo(drawRect.bottomLeft() - QPoint(0, d->m_bottomLeftRadius)); path2.quadTo(drawRect.bottomLeft(), drawRect.bottomLeft() + QPoint(d->m_bottomLeftRadius, 0)); path2.lineTo(drawRect.bottomRight() - QPoint(d->m_bottomRightRadius, 0)); path2.quadTo(drawRect.bottomRight(), drawRect.bottomRight() - QPoint(0, d->m_bottomRightRadius)); path2.lineTo(drawRect.topRight() + QPoint(0, d->m_topRightRadius)); path2.lineTo(drawRect.topLeft() + QPoint(0, d->m_topLeftRadius)); } break; case ViewType::ListView: { d->m_pMainLabel->setWordWrap(false); d->m_pSubLabel->setWordWrap(false); path1.moveTo(drawRect.topLeft() + QPoint(d->m_topLeftRadius, 0)); path1.lineTo(drawRect.bottomLeft() + QPoint(d->m_bottomLeftRadius, 0)); path1.quadTo(drawRect.bottomLeft(), drawRect.bottomLeft() - QPoint(0, d->m_bottomLeftRadius)); path1.lineTo(drawRect.topLeft() + QPoint(0, d->m_topLeftRadius)); path1.quadTo(drawRect.topLeft(), drawRect.topLeft() + QPoint(d->m_topLeftRadius, 0)); path2.moveTo(drawRect.topLeft() + QPoint(d->m_topLeftRadius, 0)); path2.lineTo(drawRect.topRight() - QPoint(d->m_topLeftRadius, 0)); path2.quadTo(drawRect.topRight(), drawRect.topRight() + QPoint(0, d->m_topRightRadius)); path2.lineTo(drawRect.bottomRight() - QPoint(0, d->m_bottomRightRadius)); path2.quadTo(drawRect.bottomRight(), drawRect.bottomRight() - QPoint(d->m_bottomRightRadius, 0)); path2.lineTo(drawRect.bottomLeft() + QPoint(d->m_bottomLeftRadius, 0)); path2.lineTo(drawRect.topLeft() + QPoint(d->m_topLeftRadius, 0)); } break; default: break; } painter.setPen(d->m_borderColor); painter.drawPath(path); painter.setPen(Qt::NoPen); painter.setBrush(d->m_titleColor); painter.drawPath(path1); painter.setBrush(d->m_bkgColor); painter.drawPath(path2); } bool KIntroWidget::eventFilter(QObject *watched, QEvent *event) { Q_D(KIntroWidget); if (watched == this) { switch (event->type()) { case QEvent::Enter: d->m_bkgColor = ThemeController::mixColor(ThemeController::getCustomColorFromDT("tooltipbase-active"), d->m_mixColor, 0.05); update(); break; case QEvent::Leave: d->m_bkgColor = ThemeController::getCustomColorFromDT("tooltipbase-active"); update(); break; case QEvent::MouseButtonPress: d->m_bkgColor = ThemeController::mixColor(ThemeController::getCustomColorFromDT("tooltipbase-active"), d->m_mixColor, 0.1); update(); break; case QEvent::MouseButtonRelease: d->m_bkgColor = ThemeController::mixColor(ThemeController::getCustomColorFromDT("tooltipbase-active"), d->m_mixColor, 0.05); update(); break; default: break; } } return QWidget::eventFilter(watched, event); } QSize KIntroWidget::sizeHint() const { Q_D(const KIntroWidget); return QWidget::sizeHint(); } void KIntroWidget::mousePressEvent(QMouseEvent *event) { Q_D(KIntroWidget); if (event->button() == Qt::MouseButton::RightButton) { emit rightClick(event->globalPos()); } return QWidget::mousePressEvent(event); } void KIntroWidget::mouseReleaseEvent(QMouseEvent *event) { Q_D(KIntroWidget); return QWidget::mouseReleaseEvent(event); } } #include "kintrowidget.moc" #include "moc_kintrowidget.cpp" libkysdk-applications/kysdk-qtwidgets/src/kclocktimer.cpp0000664000175000017500000001072215104543305022742 0ustar fengfeng/* * libkysdk-qtwidgets's Library * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhenyu Wang * */ #include "kclocktimer.h" #include "themeController.h" #include #include #include #include #include namespace kdk { class Q_DECL_HIDDEN KClockTimerPrivate : public QObject, public ThemeController { Q_OBJECT Q_DECLARE_PUBLIC(KClockTimer) public: KClockTimerPrivate(KClockTimer *parent); void updateTime(); private: KClockTimer *q_ptr; QLabel *m_pMainLabel; QLabel *m_pSubLabel; QVBoxLayout *m_vLayout; QTimer *m_pTimer; qint64 m_runningTime; bool isRunning; }; KClockTimer::KClockTimer(QWidget *parent) : QWidget(parent) , d_ptr(new KClockTimerPrivate(this)) { Q_D(KClockTimer); } QString KClockTimer::time() { Q_D(KClockTimer); return d->m_pMainLabel->text(); } void KClockTimer::startStopwatch() { Q_D(KClockTimer); if (!d->isRunning) { d->m_pTimer->start(); d->isRunning = true; } } void KClockTimer::stopStopwatch() { Q_D(KClockTimer); if (d->isRunning) { d->m_pTimer->stop(); d->isRunning = false; } } void KClockTimer::resetStopwatch() { Q_D(KClockTimer); if (d->isRunning) { d->m_pTimer->stop(); d->isRunning = false; } d->m_runningTime = 0; d->m_pMainLabel->setText("00:00.00"); d->m_pSubLabel->setText("00:00.00"); } KClockTimerPrivate::KClockTimerPrivate(KClockTimer *parent) : q_ptr(parent) , isRunning(false) { Q_Q(KClockTimer); m_vLayout = new QVBoxLayout(q); m_pMainLabel = new QLabel(); m_pMainLabel->setFixedSize(210, 70); m_pMainLabel->setAlignment(Qt::AlignHCenter); m_pMainLabel->setText("00:00.00"); m_pSubLabel = new QLabel(); m_pSubLabel->setFixedSize(210, 41); m_pSubLabel->setAlignment(Qt::AlignHCenter); m_pSubLabel->setText("00:00.00"); QPalette pale; pale.setColor(QPalette::WindowText, Qt::gray); m_pSubLabel->setPalette(pale); m_vLayout->setSpacing(0); m_vLayout->addWidget(m_pMainLabel); m_vLayout->addWidget(m_pSubLabel); m_runningTime = 0; m_pTimer = new QTimer(); m_pTimer->setInterval(10); QPalette mainPalette; mainPalette.setColor(QPalette::WindowText, ThemeController::getCustomColorFromDT("brighttext-active")); m_pMainLabel->setPalette(mainPalette); QFont f = q->font(); f.setPointSize(f.pointSize() + 15); m_pMainLabel->setFont(f); connect(m_gsetting, &QGSettings::changed, q, [=] { QFont f = q->font(); f.setPointSize(f.pointSize() + 15); m_pMainLabel->setFont(f); QPalette mainPalette; mainPalette.setColor(QPalette::WindowText, ThemeController::getCustomColorFromDT("brighttext-active")); m_pMainLabel->setPalette(mainPalette); }); connect(m_pTimer, &QTimer::timeout, this, [=] { updateTime(); }); } void KClockTimerPrivate::updateTime() { Q_Q(KClockTimer); m_runningTime += 10; // 增加10毫秒 int minutes = m_runningTime / (1000 * 60); int seconds = (m_runningTime / 1000) % 60; int milliseconds = m_runningTime % 1000; // 取毫秒的前两位 milliseconds = milliseconds / 10; // 使用QString的arg方法格式化输出 m_pMainLabel->setText(QString("%1:%2.%3") .arg(minutes, 2, 10, QChar('0')) .arg(seconds, 2, 10, QChar('0')) .arg(milliseconds, 2, 10, QChar('0'))); m_pSubLabel->setText(QString("%1:%2.%3") .arg(minutes, 2, 10, QChar('0')) .arg(seconds, 2, 10, QChar('0')) .arg(milliseconds, 2, 10, QChar('0'))); } } #include "kclocktimer.moc" #include "moc_kclocktimer.cpp" libkysdk-applications/kysdk-qtwidgets/src/knativetabbar.cpp0000664000175000017500000010101015104543305023237 0ustar fengfeng/* * libkysdk-qtwidgets's Library * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhenyu Wang * */ #include "knativetabbar.h" #include "parmscontroller.h" #include "themeController.h" #include #include #include #include #include #include #include #include #include #include namespace kdk { class Q_DECL_HIDDEN KNativeTabbarPrivate : public QObject, public ThemeController { Q_OBJECT Q_DECLARE_PUBLIC(KNativeTabbar) public: KNativeTabbarPrivate(KNativeTabbar *parent) : q_ptr(parent) , m_animation(new QVariantAnimation(this)) , m_nextTabWidth(0) , m_animationStarted(false) { Q_Q(KNativeTabbar); setParent(parent); parent->installEventFilter(this); m_animation->setDuration(300); m_animation->setEasingCurve(QEasingCurve::InOutQuad); connect(m_animation, &QVariantAnimation::valueChanged, q, [=]() { q->update(); }); connect(m_animation, &QVariantAnimation::finished, this, [=]() { m_animationStarted = false; }); m_borderRadius = ThemeController::getRadiusFromDT("kradius-normal"); if (m_borderRadius == -1) m_borderRadius = 6; } void changeTheme(); int getIndexAtPos(const QPoint &p); protected: bool eventFilter(QObject *watched, QEvent *event); private: KNativeTabbar *q_ptr; KNativeTabbarStyle m_KNativeTabbarStyle; int m_borderRadius; int m_horizontalMargin = 1; int m_topMargin = 0; QColor m_bkgrdColor; bool m_useCustomColor; QVariantAnimation *m_animation; int m_nextTabWidth; bool m_animationStarted; QLinearGradient m_linearGradient ; }; KNativeTabbar::KNativeTabbar(KNativeTabbarStyle barStyle, QWidget *parent) : KCustomTabBar(parent) , d_ptr(new KNativeTabbarPrivate(this)) { Q_D(KNativeTabbar); setAttribute(Qt::WA_Hover, true); d->m_borderRadius = 6; d->m_KNativeTabbarStyle = barStyle; d->m_useCustomColor = false; // this->setObjectName("KNativeTabbar"); d->changeTheme(); connect(d->m_gsetting, &QGSettings::changed, d, &KNativeTabbarPrivate::changeTheme); connect(Parmscontroller::self(), &Parmscontroller::modeChanged, this, [=](bool flag) { updateGeometry(); }); } KNativeTabbar::~KNativeTabbar() { } void KNativeTabbar::setTabbarStyle(KNativeTabbarStyle barStyle) { Q_D(KNativeTabbar); d->m_KNativeTabbarStyle = barStyle; d->changeTheme(); } KNativeTabbarStyle KNativeTabbar::barStyle() { Q_D(KNativeTabbar); return d->m_KNativeTabbarStyle; } void KNativeTabbar::setBorderRadius(int radius) { Q_D(KNativeTabbar); if (radius < 0 || radius > 20) return; d->m_borderRadius = radius; update(); } int KNativeTabbar::borderRadius() { Q_D(KNativeTabbar); if (d->m_KNativeTabbarStyle == Sliding) return 0; else return d->m_borderRadius; } void KNativeTabbar::setBackgroundColor(const QColor &color) { Q_D(KNativeTabbar); d->m_useCustomColor = true; d->m_bkgrdColor = color; } QSize KNativeTabbar::sizeHint() const { auto size = KCustomTabBar::sizeHint(); size.setHeight(Parmscontroller::parm(Parmscontroller::Parm::PM_TabBarHeight)); return size; } QSize KNativeTabbar::minimumTabSizeHint(int index) const { Q_UNUSED(index) QSize size(100, Parmscontroller::parm(Parmscontroller::Parm::PM_PushButtonHeight)); return size; } QSize KNativeTabbar::tabSizeHint(int index) const { Q_UNUSED(index) // 判断外部是否设置了固定宽度或者固定高度,如果设置,走默认的tabSizeHint if ((this->maximumHeight() == this->minimumHeight()) || this->maximumWidth() == this->minimumWidth()) return KCustomTabBar::tabSizeHint(index); auto size = KCustomTabBar::tabSizeHint(index); size.setHeight(Parmscontroller::parm(Parmscontroller::Parm::PM_TabBarHeight)); return size; } void KNativeTabbar::paintEvent(QPaintEvent *event) { Q_D(KNativeTabbar); QPainter p(this); p.setRenderHint(QPainter::Antialiasing); p.setRenderHint(QPainter::TextAntialiasing); p.setRenderHint(QPainter::SmoothPixmapTransform); QColor fontColor; QColor mix; QColor startColor; QColor endColor; QFontMetrics fm = p.fontMetrics(); for (int i = 0; i < count(); ++i) { QStyleOptionTab option; initStyleOption(&option, i); QRect rect = option.rect.adjusted(d->m_horizontalMargin, 0, 0, -d->m_topMargin); rect.setHeight(Parmscontroller::parm(Parmscontroller::Parm::PM_PushButtonHeight)); d->m_linearGradient = QLinearGradient(rect.left() + rect.width()/2, rect.top(),rect.left() + rect.width()/2, rect.bottom()); switch (d->m_KNativeTabbarStyle) { case SegmentDark: { mix = ThemeController::getCustomColorFromDT("brighttext-active"); fontColor = ThemeController::getCustomColorFromDT("buttontext-active"); QColor bkgrdColor = d->m_bkgrdColor; d->m_linearGradient.setColorAt(0,bkgrdColor); d->m_linearGradient.setColorAt(1,bkgrdColor); if (option.state.testFlag(QStyle::State_Selected)) { bkgrdColor = ThemeController::getCustomColorFromDT("highlight-active"); d->m_linearGradient.setColorAt(0,bkgrdColor); d->m_linearGradient.setColorAt(1,bkgrdColor); fontColor = ThemeController::getCustomColorFromDT("kwhite"); } else if (option.state.testFlag(QStyle::State_MouseOver)) { ThemeController::getGradientFromDT("kcomponent-hover",startColor,endColor); d->m_linearGradient.setColorAt(0,startColor); d->m_linearGradient.setColorAt(1,endColor); } if (option.position == QStyleOptionTab::Middle) { p.save(); p.setBrush(d->m_linearGradient); p.setPen(Qt::NoPen); // 利用quadto绘制圆角矩形会出现一个像素的偏差,修正一下QRect底部高度 p.drawRect(rect.adjusted(0, 1, -1, -1)); // 调整启典 上描边 p.restore(); p.setBrush(Qt::NoBrush); p.setPen(fontColor); QPoint point; uint tf = Qt::AlignVCenter; if (!option.icon.isNull()) { QIcon::Mode mode = option.state & QStyle::State_Enabled ? QIcon::Normal : QIcon::Disabled; if (mode == QIcon::Normal && option.state & QStyle::State_HasFocus) mode = QIcon::Active; QIcon::State state = QIcon::Off; if (option.state & QStyle::State_On) state = QIcon::On; QPixmap pixmap = option.icon.pixmap(option.iconSize, mode, state); if(ThemeController::isPixmapPureColor(pixmap)) pixmap = ThemeController::drawColoredPixmap(pixmap,fontColor); int w = pixmap.width() / pixmap.devicePixelRatio(); int h = pixmap.height() / pixmap.devicePixelRatio(); if (!tabText(i).isEmpty()) w += option.fontMetrics.boundingRect(option.rect, tf, tabText(i)).width() + 2; point = QPoint(rect.x() + rect.width() / 2 - w / 2, rect.y() + rect.height() / 2 - h / 2); w = pixmap.width() / pixmap.devicePixelRatio(); if (option.direction == Qt::RightToLeft) point.rx() += w; if (fm.horizontalAdvance(tabText(i)) >= option.rect.width() - option.iconSize.width() - 7) p.drawPixmap(option.rect.x() + 4, this->style()->visualPos(option.direction, option.rect, point).y(), pixmap); else p.drawPixmap(this->style()->visualPos(option.direction, option.rect, point), pixmap); if (!tabText(i).isEmpty()) { int subH = std::max(option.iconSize.height(), option.fontMetrics.height()); int icon_Y = (rect.height() - subH) / 2; int text_X = point.x() + option.iconSize.width() + 4; int text_Y = icon_Y; QRect textRect; if (fm.horizontalAdvance(tabText(i)) >= option.rect.width() - option.iconSize.width() - 7) { textRect = QRect(option.rect.x() + option.iconSize.width() + 8, text_Y, option.rect.width() - option.iconSize.width() - 7, option.fontMetrics.height()); setTabToolTip(i, tabText(i)); QString elidedText = fm.elidedText(tabText(i), Qt::ElideRight, option.rect.width() - option.iconSize.width() - 7); p.drawText(textRect, tf, elidedText); } else { textRect = QRect(text_X, text_Y, option.fontMetrics.horizontalAdvance(tabText(i)), option.fontMetrics.height()); setTabToolTip(i, ""); p.drawText(textRect, tf, tabText(i)); } } } else { tf |= Qt::AlignHCenter; if (fm.horizontalAdvance(tabText(i)) >= option.rect.width()) { QString elidedText = fm.elidedText(tabText(i), Qt::ElideRight, option.rect.width()); p.drawText(rect, tf, elidedText); setTabToolTip(i, tabText(i)); } else { setTabToolTip(i, ""); p.drawText(rect, tf, tabText(i)); } } } else if (option.position == QStyleOptionTab::Beginning) { p.save(); p.setBrush(d->m_linearGradient); p.setPen(Qt::NoPen); QPainterPath path; auto tempRect = rect.adjusted(0, 0, 1, 0); path.moveTo(tempRect.topLeft() + QPointF(0, d->m_borderRadius)); path.lineTo(tempRect.bottomLeft() - QPointF(0, d->m_borderRadius)); path.quadTo(tempRect.bottomLeft(), tempRect.bottomLeft() + QPointF(d->m_borderRadius, 0)); path.lineTo(tempRect.bottomRight()); path.lineTo(tempRect.topRight()); path.lineTo(tempRect.topLeft() + QPointF(d->m_borderRadius, 0)); path.quadTo(tempRect.topLeft(), tempRect.topLeft() + QPointF(0, d->m_borderRadius)); p.drawPath(path); p.restore(); p.setBrush(Qt::NoBrush); p.setPen(fontColor); QPoint point; uint tf = Qt::AlignVCenter; if (!option.icon.isNull()) { QIcon::Mode mode = option.state & QStyle::State_Enabled ? QIcon::Normal : QIcon::Disabled; if (mode == QIcon::Normal && option.state & QStyle::State_HasFocus) mode = QIcon::Active; QIcon::State state = QIcon::Off; if (option.state & QStyle::State_On) state = QIcon::On; QPixmap pixmap = option.icon.pixmap(option.iconSize, mode, state); if(ThemeController::isPixmapPureColor(pixmap)) pixmap = ThemeController::drawColoredPixmap(pixmap,fontColor); int w = pixmap.width() / pixmap.devicePixelRatio(); int h = pixmap.height() / pixmap.devicePixelRatio(); if (!tabText(i).isEmpty()) w += option.fontMetrics.boundingRect(option.rect, tf, tabText(i)).width() + 2; point = QPoint(rect.x() + rect.width() / 2 - w / 2, rect.y() + rect.height() / 2 - h / 2); w = pixmap.width() / pixmap.devicePixelRatio(); if (option.direction == Qt::RightToLeft) point.rx() += w; if (fm.horizontalAdvance(tabText(i)) >= option.rect.width() - option.iconSize.width() - 7) p.drawPixmap(option.rect.x() + 4, this->style()->visualPos(option.direction, option.rect, point).y(), pixmap); else p.drawPixmap(this->style()->visualPos(option.direction, option.rect, point), pixmap); if (option.direction == Qt::RightToLeft) rect.translate(-point.x() - 2, 0); else rect.translate(point.x() + w + 4, 0); if (!tabText(i).isEmpty()) { tf |= Qt::AlignLeft; int subH = std::max(option.iconSize.height(), option.fontMetrics.height()); int icon_Y = (rect.height() - subH) / 2; int text_X = point.x() + option.iconSize.width() + 4; int text_Y = icon_Y; QRect textRect; if (fm.horizontalAdvance(tabText(i)) >= option.rect.width() - option.iconSize.width() - 7) { textRect = QRect(option.rect.x() + option.iconSize.width() + 8, text_Y, option.rect.width() - option.iconSize.width() - 8, option.fontMetrics.height()); setTabToolTip(i, tabText(i)); QString elidedText = fm.elidedText(tabText(i), Qt::ElideRight, option.rect.width() - option.iconSize.width() - 8); p.drawText(textRect, tf, elidedText); } else { textRect = QRect(text_X, text_Y, option.fontMetrics.horizontalAdvance(tabText(i)), option.fontMetrics.height()); setTabToolTip(i, ""); p.drawText(textRect, tf, tabText(i)); } } } else { tf |= Qt::AlignHCenter; if (fm.horizontalAdvance(tabText(i)) >= option.rect.width()) { QString elidedText = fm.elidedText(tabText(i), Qt::ElideRight, option.rect.width()); p.drawText(rect, tf, elidedText); setTabToolTip(i, tabText(i)); } else { p.drawText(rect, tf, tabText(i)); setTabToolTip(i, ""); } } } else { p.save(); p.setBrush(d->m_linearGradient); rect = rect.adjusted(0, 1, 0, 0); // 调整启典 上描边 p.setPen(Qt::NoPen); QPainterPath path; path.moveTo(rect.topLeft()); path.lineTo(rect.bottomLeft()); path.lineTo(rect.bottomRight() - QPointF(d->m_borderRadius, 0)); path.quadTo(rect.bottomRight(), rect.bottomRight() - QPointF(0, d->m_borderRadius)); path.lineTo(rect.topRight() + QPointF(0, d->m_borderRadius)); path.quadTo(rect.topRight(), rect.topRight() - QPointF(d->m_borderRadius, 0)); path.lineTo(rect.topLeft()); p.drawPath(path); p.restore(); p.setBrush(Qt::NoBrush); p.setPen(fontColor); QPoint point; uint tf = Qt::AlignVCenter; if (!option.icon.isNull()) { QIcon::Mode mode = option.state & QStyle::State_Enabled ? QIcon::Normal : QIcon::Disabled; if (mode == QIcon::Normal && option.state & QStyle::State_HasFocus) mode = QIcon::Active; QIcon::State state = QIcon::Off; if (option.state & QStyle::State_On) state = QIcon::On; QPixmap pixmap = option.icon.pixmap(option.iconSize, mode, state); if(ThemeController::isPixmapPureColor(pixmap)) pixmap = ThemeController::drawColoredPixmap(pixmap,fontColor); int w = pixmap.width() / pixmap.devicePixelRatio(); int h = pixmap.height() / pixmap.devicePixelRatio(); if (!tabText(i).isEmpty()) w += option.fontMetrics.boundingRect(option.rect, tf, tabText(i)).width() + 4; point = QPoint(rect.x() + rect.width() / 2 - w / 2, rect.y() + rect.height() / 2 - h / 2); w = pixmap.width() / pixmap.devicePixelRatio(); if (option.direction == Qt::RightToLeft) point.rx() += w; if (fm.horizontalAdvance(tabText(i)) >= option.rect.width() - option.iconSize.width() - 7) p.drawPixmap(option.rect.x() + 4, this->style()->visualPos(option.direction, option.rect, point).y(), pixmap); else p.drawPixmap(this->style()->visualPos(option.direction, option.rect, point), pixmap); if (!tabText(i).isEmpty()) { int subH = std::max(option.iconSize.height(), option.fontMetrics.height()); int icon_Y = (rect.height() - subH) / 2; int text_X = point.x() + option.iconSize.width() + 4; int text_Y = icon_Y; QRect textRect; if (fm.horizontalAdvance(tabText(i)) >= option.rect.width() - option.iconSize.width() - 7) { textRect = QRect(option.rect.x() + option.iconSize.width() + 8, text_Y, option.rect.width() - option.iconSize.width() - 8, option.fontMetrics.height()); setTabToolTip(i, tabText(i)); QString elidedText = fm.elidedText(tabText(i), Qt::ElideRight, option.rect.width() - option.iconSize.width() - 8); p.drawText(textRect, elidedText); } else { textRect = QRect(text_X, text_Y, option.fontMetrics.horizontalAdvance(tabText(i)), option.fontMetrics.height()); setTabToolTip(i, ""); p.drawText(textRect, tabText(i)); } } } else { tf |= Qt::AlignHCenter; if (fm.horizontalAdvance(tabText(i)) >= option.rect.width()) { QString elidedText = fm.elidedText(tabText(i), Qt::ElideRight, option.rect.width()); p.drawText(rect, tf, elidedText); setTabToolTip(i, tabText(i)); } else { p.drawText(rect, tf, tabText(i)); setTabToolTip(i, ""); } } } break; } case SegmentLight: { mix = ThemeController::getCustomColorFromDT("brighttext-active"); fontColor = ThemeController::getCustomColorFromDT("buttontext-active"); QColor bkgrdColor = d->m_bkgrdColor; d->m_linearGradient.setColorAt(0,bkgrdColor); d->m_linearGradient.setColorAt(1,bkgrdColor); if (option.state.testFlag(QStyle::State_Selected)) { bkgrdColor = ThemeController::getCustomColorFromDT("highlight-active"); d->m_linearGradient.setColorAt(0,bkgrdColor); d->m_linearGradient.setColorAt(1,bkgrdColor); fontColor = ThemeController::getCustomColorFromDT("kwhite"); } else if (option.state.testFlag(QStyle::State_MouseOver)) { ThemeController::getGradientFromDT("kcomponent-hover",startColor,endColor); d->m_linearGradient.setColorAt(0,startColor); d->m_linearGradient.setColorAt(1,endColor); } p.save(); p.setBrush(d->m_linearGradient); p.setPen(Qt::NoPen); p.drawRoundedRect(/*option.rect.adjusted*/ rect.adjusted(d->m_horizontalMargin, 0, 0, -d->m_topMargin), d->m_borderRadius, d->m_borderRadius); p.restore(); p.setBrush(Qt::NoBrush); p.setPen(fontColor); /*QRect*/ rect = /*option.*/ rect.adjusted(d->m_horizontalMargin, 0, 0, -d->m_topMargin); QPoint point; uint tf = Qt::AlignVCenter; if (!option.icon.isNull()) { QIcon::Mode mode = option.state & QStyle::State_Enabled ? QIcon::Normal : QIcon::Disabled; if (mode == QIcon::Normal && option.state & QStyle::State_HasFocus) mode = QIcon::Active; QIcon::State state = QIcon::Off; if (option.state & QStyle::State_On) state = QIcon::On; QPixmap pixmap = option.icon.pixmap(option.iconSize, mode, state); if(ThemeController::isPixmapPureColor(pixmap)) pixmap = ThemeController::drawColoredPixmap(pixmap,fontColor); int w = pixmap.width() / pixmap.devicePixelRatio(); int h = pixmap.height() / pixmap.devicePixelRatio(); if (!tabText(i).isEmpty()) w += option.fontMetrics.boundingRect(option.rect, tf, tabText(i)).width() + 2; point = QPoint(rect.x() + rect.width() / 2 - w / 2, rect.y() + rect.height() / 2 - h / 2); w = pixmap.width() / pixmap.devicePixelRatio(); if (option.direction == Qt::RightToLeft) point.rx() += w; if (fm.horizontalAdvance(tabText(i)) >= option.rect.width() - option.iconSize.width() - 7) p.drawPixmap(option.rect.x() + 4, this->style()->visualPos(option.direction, option.rect, point).y(), pixmap); else p.drawPixmap(this->style()->visualPos(option.direction, option.rect, point), pixmap); if (!tabText(i).isEmpty()) { int subH = std::max(option.iconSize.height(), option.fontMetrics.height()); int icon_Y = (rect.height() - subH) / 2; int text_X = point.x() + option.iconSize.width() + 4; int text_Y = icon_Y; QRect textRect; if (fm.horizontalAdvance(tabText(i)) >= option.rect.width() - option.iconSize.width() - 7) { textRect = QRect(option.rect.x() + option.iconSize.width() + 8, text_Y, option.rect.width() - option.iconSize.width() - 8, option.fontMetrics.height()); setTabToolTip(i, tabText(i)); QString elidedText = fm.elidedText(tabText(i), Qt::ElideRight, option.rect.width() - option.iconSize.width() - 8); p.drawText(textRect, elidedText); } else { textRect = QRect(text_X, text_Y, option.fontMetrics.horizontalAdvance(tabText(i)), option.fontMetrics.height()); setTabToolTip(i, ""); p.drawText(textRect, tabText(i)); } } } else { tf |= Qt::AlignHCenter; if (fm.horizontalAdvance(tabText(i)) >= option.rect.width()) { QString elidedText = fm.elidedText(tabText(i), Qt::ElideRight, option.rect.width()); p.drawText(rect, tf, elidedText); setTabToolTip(i, tabText(i)); } else { p.drawText(rect, tf, tabText(i)); setTabToolTip(i, ""); } } break; } case Sliding: { mix = ThemeController::getCustomColorFromDT("brighttext-active"); fontColor = ThemeController::getCustomColorFromDT("buttontext-active"); QColor bkgrdColor = d->m_bkgrdColor; d->m_linearGradient.setColorAt(0,bkgrdColor); d->m_linearGradient.setColorAt(1,bkgrdColor); if (option.state.testFlag(QStyle::State_Selected)) { bkgrdColor = ThemeController::getCustomColorFromDT("highlight-active"); fontColor = ThemeController::getCustomColorFromDT("highlight-active"); d->m_linearGradient.setColorAt(0,bkgrdColor); d->m_linearGradient.setColorAt(1,bkgrdColor); } else if (option.state.testFlag(QStyle::State_MouseOver)) { ThemeController::getGradientFromDT("kline-normal",startColor,endColor); d->m_linearGradient.setColorAt(0,Qt::red); d->m_linearGradient.setColorAt(1,Qt::blue); } p.save(); QPen pen; if (i != currentIndex()) pen.setColor(bkgrdColor); else pen.setColor(d->m_bkgrdColor); pen.setWidth(2); p.setPen(pen); /*QRect*/ rect = /*option.*/ rect.adjusted(d->m_horizontalMargin, 0, 0, -5); p.drawLine(rect.bottomLeft(), rect.bottomRight()); p.restore(); if (d->m_animationStarted) { int left_border = d->m_animation->currentValue().toInt(); p.save(); QPen pen; pen.setWidth(2); pen.setColor(ThemeController::getCustomColorFromDT("highlight-active")); p.setPen(pen); p.drawLine(QPoint(left_border, rect.height() - 1), QPoint(left_border + d->m_nextTabWidth, rect.height() - 1)); p.restore(); } else { p.save(); QPen pen; pen.setColor(bkgrdColor); pen.setWidth(2); p.setPen(pen); p.drawLine(rect.bottomLeft(), rect.bottomRight()); p.restore(); } p.setBrush(Qt::NoBrush); p.setPen(fontColor); QPoint point; uint tf = Qt::AlignVCenter; if (!option.icon.isNull()) { QIcon::Mode mode = option.state & QStyle::State_Enabled ? QIcon::Normal : QIcon::Disabled; if (mode == QIcon::Normal && option.state & QStyle::State_HasFocus) mode = QIcon::Active; QIcon::State state = QIcon::Off; if (option.state & QStyle::State_On) state = QIcon::On; QPixmap pixmap = option.icon.pixmap(option.iconSize, mode, state); if(ThemeController::isPixmapPureColor(pixmap)) pixmap = ThemeController::drawColoredPixmap(pixmap,fontColor); int w = pixmap.width() / pixmap.devicePixelRatio(); int h = pixmap.height() / pixmap.devicePixelRatio(); if (!tabText(i).isEmpty()) w += option.fontMetrics.boundingRect(option.rect, tf, tabText(i)).width() + 2; point = QPoint(rect.x() + rect.width() / 2 - w / 2, rect.y() + rect.height() / 2 - h / 2); w = pixmap.width() / pixmap.devicePixelRatio(); if (option.direction == Qt::RightToLeft) point.rx() += w; if (fm.horizontalAdvance(tabText(i)) >= option.rect.width() - option.iconSize.width() - 7) p.drawPixmap(option.rect.x() + 4, this->style()->visualPos(option.direction, option.rect, point).y(), pixmap); else p.drawPixmap(this->style()->visualPos(option.direction, option.rect, point), pixmap); if (!tabText(i).isEmpty()) { int subH = std::max(option.iconSize.height(), option.fontMetrics.height()); int icon_Y = (rect.height() - subH) / 2; int text_X = point.x() + option.iconSize.width() + 4; int text_Y = icon_Y; QRect textRect; if (fm.horizontalAdvance(tabText(i)) >= option.rect.width() - option.iconSize.width() - 7) { textRect = QRect(option.rect.x() + option.iconSize.width() + 8, text_Y, option.rect.width() - option.iconSize.width() - 8, option.fontMetrics.height()); setTabToolTip(i, tabText(i)); QString elidedText = fm.elidedText(tabText(i), Qt::ElideRight, option.rect.width() - option.iconSize.width() - 8); p.drawText(textRect, elidedText); } else { textRect = QRect(text_X, text_Y, option.fontMetrics.horizontalAdvance(tabText(i)), option.fontMetrics.height()); setTabToolTip(i, ""); p.drawText(textRect, tabText(i)); } } } else { tf |= Qt::AlignHCenter; if (fm.horizontalAdvance(tabText(i)) >= option.rect.width()) { QString elidedText = fm.elidedText(tabText(i), Qt::ElideRight, option.rect.width()); p.drawText(rect, tf, elidedText); setTabToolTip(i, tabText(i)); } else { p.drawText(rect, tf, tabText(i)); setTabToolTip(i, ""); } } break; } default: break; } } } void KNativeTabbarPrivate::changeTheme() { Q_Q(KNativeTabbar); switch (m_KNativeTabbarStyle) { case SegmentDark: { if (m_useCustomColor) return; else m_bkgrdColor = ThemeController::getCustomColorFromDT("button-active"); break; } case SegmentLight: { if (m_useCustomColor) return; else m_bkgrdColor = ThemeController::getCustomColorFromDT("kgray-alpha0"); break; } case Sliding: if (m_useCustomColor) return; else m_bkgrdColor = ThemeController::getCustomColorFromDT("button-active"); break; default: break; }; q->update(); } int KNativeTabbarPrivate::getIndexAtPos(const QPoint &p) { Q_Q(KNativeTabbar); if (q->tabRect(q->currentIndex()).contains(p)) return q->currentIndex(); for (int i = 0; i < q->count(); ++i) if (q->tabRect(i).contains(p)) return i; return -1; } bool KNativeTabbarPrivate::eventFilter(QObject *watched, QEvent *event) { Q_Q(KNativeTabbar); if (event->type() == QEvent::MouseButtonPress) { if (q->isEnabled()) { QMouseEvent *mouseEvent = dynamic_cast(event); if (mouseEvent && mouseEvent->button() == Qt::MouseButton::LeftButton) { int nextIndex = getIndexAtPos(mouseEvent->pos()); int currentIndex = q->currentIndex(); if (nextIndex != currentIndex) { int cur_left_border = q->tabRect(currentIndex).left(); int next_left_border = q->tabRect(nextIndex).left(); m_nextTabWidth = q->tabRect(nextIndex).width(); m_animation->setStartValue(cur_left_border); m_animation->setEndValue(next_left_border); m_animation->start(); m_animationStarted = true; } } if (mouseEvent && mouseEvent->button() == Qt::MouseButton::RightButton) { emit q->rightlicked(mouseEvent->globalPos()); } } } return QObject::eventFilter(watched, event); } } #include "knativetabbar.moc" #include "moc_knativetabbar.cpp" libkysdk-applications/kysdk-qtwidgets/src/karrowtabbar.h0000664000175000017500000000273015104543305022561 0ustar fengfeng/* * libkysdk-qtwidgets's Library * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhenyu Wang * */ #ifndef KARROWTABBAR_H #define KARROWTABBAR_H #include "knativetabbar.h" #include namespace kdk { /** @defgroup BarModule * @{ */ class KArrowTabBarPrivate; /** * @brief 可显示箭头的tabbar * @since 2.5.2.0 */ class KArrowTabBar : public QWidget { Q_OBJECT public: KArrowTabBar(QWidget *parent = nullptr); /** * @brief 获取knativetabbar * @return */ KNativeTabbar *tabbar(); Q_SIGNALS: /** * @brief 点击会发出信号 */ void sizeChange(); protected: void resizeEvent(QResizeEvent *event); private: Q_DECLARE_PRIVATE(KArrowTabBar) KArrowTabBarPrivate *const d_ptr; }; } #endif // KArrowTabBar_H libkysdk-applications/kysdk-qtwidgets/src/ktitlewindow.h0000664000175000017500000000370215104543305022624 0ustar fengfeng/* * libkysdk-qtwidgets's Library * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhenyu Wang * */ #ifndef KTITLEWINDOW_H #define KTITLEWINDOW_H #include "gui_g.h" #include "kpushbutton.h" #include #include #include #include #include namespace kdk { /** * @defgroup FrameModule * @since 2.5.2.0 * { */ class KTitleWindowPrivate; class GUI_EXPORT KTitleWindow : public QWidget { Q_OBJECT public: KTitleWindow(QWidget *parent = nullptr); /** * @brief 获取添加按钮 * @return */ KPushButton *addButton(); /** * @brief 获取颜色按钮 * @return */ QPushButton *colorButton(); /** * @brief 获取menu按钮 * @return */ QPushButton *menuButton(); /** * @brief 获取widget * @return */ QWidget *baseWidget(); /** * @brief 设置标题颜色 * @param color */ void setTitleColor(QColor color); protected: void resizeEvent(QResizeEvent *event); void paintEvent(QPaintEvent *event); bool eventFilter(QObject *watched, QEvent *event); private: Q_DECLARE_PRIVATE(KTitleWindow) KTitleWindowPrivate *const d_ptr; }; } #endif // KTITLEWINDOW_H libkysdk-applications/kysdk-qtwidgets/src/kwindowbuttonbar.h0000664000175000017500000000565415104543305023513 0ustar fengfeng/* * libkysdk-qtwidgets's Library * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #ifndef KTITLEBAR_H #define KTITLEBAR_H #include "gui_g.h" #include "kmenubutton.h" #include #include #include #include namespace kdk { /** @defgroup BarModule * @{ */ /** * @brief 最大化按钮提供两种状态响应 * @since 1.0.0 */ enum MaximumButtonState { Maximum, Restore }; class KWindowButtonBarPrivate; /** * @brief 窗口三联按钮和菜单按钮的集合 */ class GUI_EXPORT KWindowButtonBar : public QFrame { Q_OBJECT public: KWindowButtonBar(QWidget *parent = nullptr); ~KWindowButtonBar(); /** * @brief 获取最小化按钮 * @return */ QPushButton *minimumButton(); /** * @brief 获取最大化按钮 * @return */ QPushButton *maximumButton(); /** * @brief 获取关闭按钮 * @return */ QPushButton *closeButton(); /** * @brief 获取菜单按钮 * @return */ KMenuButton *menuButton(); /** * @brief 获取最大化按钮的状态(最大化/恢复) * @return */ MaximumButtonState maximumButtonState(); /** * @brief 设置最大化按钮图标状态(最大化/恢复) * @param state */ void setMaximumButtonState(MaximumButtonState state); /** * @brief 设置是否遵循模式 * @since 2.0 * @param flag */ void setFollowMode(bool flag); /** * @brief 返回是否遵循模式 * @since 2.0 * @return */ bool followMode(); /** * @brief setSplitScreenGeometry * @param 弹出界面的显示位置rect * @since 3.0.1.0 */ void setSplitScreenGeometry(QRect rect); Q_SIGNALS: /** * @brief 双击会发出双击信号,父widget可以绑定相应槽函数 */ void doubleClick(); protected: void mouseDoubleClickEvent(QMouseEvent *event); bool eventFilter(QObject *watched, QEvent *event); QSize sizeHint() const override; private: Q_DECLARE_PRIVATE(KWindowButtonBar) KWindowButtonBarPrivate *d_ptr; }; } /** * @example testWidget/testwidget.h * @example testWidget/testwidget.cpp * @} */ #endif // KTITLEBAR_H libkysdk-applications/kysdk-qtwidgets/src/kcrumb.h0000664000175000017500000000525715104543305021372 0ustar fengfeng/* * libkysdk-qtwidgets's Library * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhenyu Wang * */ #ifndef KCRUMB_H #define KCRUMB_H #include "kcustomtabbar.h" #include namespace kdk { /** * @defgroup KCrumb * @since 2.5.2.0 */ class KCrumbPrivate; /** * @brief KCrumbType,包括两种类型。 */ enum KCrumbType { FlatBreadCrumb, CubeBreadCrumb }; /** * @brief 面包屑控件 */ class KCrumb : public KCustomTabBar { Q_OBJECT public: explicit KCrumb(QWidget *parent = nullptr); /** * @brief 添加tab * @param text * @return */ int addTab(const QString &text); /** * @brief 添加tab * @param icon * @param text * @return */ int addTab(const QIcon &icon, const QString &text); /** * @brief 在index位置插入tab * @param index * @param text * @return */ int insertTab(int index, const QString &text); /** * @brief 在index位置插入tab * @param index * @param icon * @param text * @return */ int insertTab(int index, const QIcon &icon, const QString &text); /** * @brief 删除index位置的tab * @param index */ void removeTab(int index); /** * @brief 将from位置tab移至to位置 * @param from * @param to */ void moveTab(int from, int to); /** * @brief 设置图标 * @param icon */ void setIcon(const QIcon &icon); /** * @brief 获取图标 * @return */ QIcon icon() const; /** * @brief 返回按钮边框是否凸起 * @return */ bool isFlat() const; /** * @brief 设置按钮边框是否凸起 * @param flat */ void setFlat(bool flat); public slots: void leftScroll(); void rightScroll(); protected: QSize tabSizeHint(int index) const; void paintEvent(QPaintEvent *event); private: Q_DECLARE_PRIVATE(KCrumb) KCrumbPrivate *const d_ptr; }; } #endif // KCRUMB_H libkysdk-applications/kysdk-qtwidgets/src/kwidget.cpp0000664000175000017500000004553215104543305022100 0ustar fengfeng/* * libkysdk-qtwidgets's Library * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #include "kwidget.h" #include "KWindowEffects" #include "gui_g.h" #include "parmscontroller.h" #include "ukuistylehelper/ukui-decoration-manager.h" #include "ukuistylehelper/ukui-shell-manager.h" #include #include #include #include #include #include #include "kysdk-ukuiwindowhelper/ukuiwindowhelper.h" #include "accessinfohelper.h" #include "xatom-helper.h" namespace kdk { #define FocusIn QEvent::FocusIn #define FocusOut QEvent::FocusOut class KWidgetPrivate : public QObject { Q_OBJECT Q_DECLARE_PUBLIC(KWidget) public: KWidgetPrivate(KWidget *parent); private: KWidget *q_ptr; KIconBar *m_pIconBar; KWindowButtonBar *m_pWindowButtonBar; QHBoxLayout *m_pTitleLayout; QHBoxLayout *m_pWidgetLayout; QVBoxLayout *m_pMainLayout; QWidget *m_pBaseWidget; QWidget *m_pSideWidget; QColor m_pBaseColor; QColor m_pSideColor; QString m_IconName; QGSettings *m_pTransparency; double tranSparency; LayoutType m_layoutType; bool m_sidebarFollowMode; UkuiWindowHelper *m_ukuiWindowHelper; void adjustBackground(); void adjustFlagsTitleStatus(Qt::WindowFlags type); void adjustFlagTitleStatus(Qt::WindowFlags type); }; KWidget::KWidget(QWidget *parent) : QWidget(parent) , d_ptr(new KWidgetPrivate(this)) { Q_D(KWidget); setAttribute(Qt::WA_AlwaysShowToolTips); setFocusPolicy(Qt::ClickFocus); setObjectName("Kwidget"); // this->setAttribute(Qt::WA_TranslucentBackground, true); //透明 // bug 163681 弃用主题毛玻璃,改用kwindowsystem毛玻璃接口 // this->setProperty("useSystemStyleBlur", true); /* 开启背景模糊效果(毛玻璃) */ // KWindowEffects::enableBlurBehind(this->winId()); d->m_ukuiWindowHelper = new UkuiWindowHelper(this); if (Parmscontroller::isTabletMode()) { d->m_pWindowButtonBar->maximumButton()->hide(); } else { d->m_pWindowButtonBar->maximumButton()->show(); } connect(d->m_pWindowButtonBar->minimumButton(), &QPushButton::clicked, this, &KWidget::showMinimized); connect(d->m_pWindowButtonBar->maximumButton(), &QPushButton::clicked, this, [=]() { if (this->isMaximized()) showNormal(); else showMaximized(); }); connect(d->m_pWindowButtonBar->closeButton(), &QPushButton::clicked, this, &KWidget::close); connect(d->m_pWindowButtonBar, &KWindowButtonBar::doubleClick, this, [=]() { if (this->isMaximized()) showNormal(); else showMaximized(); }); connect(d->m_pIconBar, &KIconBar::doubleClick, this, [=]() { if (this->isMaximized()) showNormal(); else showMaximized(); }); changeIconStyle(); connect(m_gsetting, &QGSettings::changed, this, [=]() { changeIconStyle(); }); if (QGSettings::isSchemaInstalled("org.ukui.control-center.personalise")) { d->m_pTransparency = new QGSettings("org.ukui.control-center.personalise"); d->tranSparency = d->m_pTransparency->get("transparency").toDouble(); connect(d->m_pTransparency, &QGSettings::changed, this, [=](QString value) { if (value == "transparency") { d->tranSparency = d->m_pTransparency->get("transparency").toDouble(); d->adjustBackground(); } }); } d->adjustBackground(); connect(Parmscontroller::self(), &Parmscontroller::modeChanged, this, [=]() { if (d->m_sidebarFollowMode) { d->m_pSideWidget->setFixedWidth(Parmscontroller::parm(Parmscontroller::Parm::PM_Widget_SideWidget_Width)); d->m_pIconBar->setFixedWidth(Parmscontroller::parm(Parmscontroller::Parm::PM_Widget_SideWidget_Width)); } if (Parmscontroller::isTabletMode()) { if (d->m_pWindowButtonBar->followMode()) d->m_pWindowButtonBar->maximumButton()->hide(); } else { if (d->m_pWindowButtonBar->followMode()) d->m_pWindowButtonBar->maximumButton()->show(); } updateGeometry(); }); changeTheme(); connect(m_gsetting, &QGSettings::changed, this, [=]() { changeTheme(); }); QString platform = QGuiApplication::platformName(); if (platform.startsWith(QLatin1String("xcb"), Qt::CaseInsensitive)) { MotifWmHints hints; hints.flags = MWM_HINTS_FUNCTIONS | MWM_HINTS_DECORATIONS; hints.functions = MWM_FUNC_ALL; hints.decorations = MWM_DECOR_BORDER; XAtomHelper::getInstance()->setWindowMotifHint(this->winId(), hints); } installEventFilter(this); resize(800, 600); } KWidget::~KWidget() { } void KWidget::setIcon(const QIcon &icon) { Q_D(KWidget); d->m_IconName = icon.name(); d->m_pIconBar->setIcon(icon); // setWindowIcon(icon.pixmap(QSize(36,36))); setWindowIcon(icon); } void KWidget::setIcon(const QString &iconName) { Q_D(KWidget); d->m_IconName = iconName; d->m_pIconBar->setIcon(iconName); // setWindowIcon(QIcon::fromTheme(iconName).pixmap(QSize(36,36))); setWindowIcon(QIcon::fromTheme(iconName)); } void KWidget::setWidgetName(const QString &widgetName) { Q_D(KWidget); d->m_pIconBar->setWidgetName(widgetName); QWidget::setWindowTitle(widgetName); } QWidget *KWidget::sideBar() { Q_D(KWidget); return d->m_pSideWidget; } QWidget *KWidget::baseBar() { Q_D(KWidget); return d->m_pBaseWidget; } KWindowButtonBar *KWidget::windowButtonBar() { Q_D(KWidget); return d->m_pWindowButtonBar; } KIconBar *KWidget::iconBar() { Q_D(KWidget); return d->m_pIconBar; } void KWidget::setLayoutType(LayoutType type) { Q_D(KWidget); d->m_layoutType = type; d->adjustBackground(); } void KWidget::setWindowFlags(Qt::WindowFlags type) { Q_D(KWidget); QWidget::setWindowFlags(type); d->adjustFlagsTitleStatus(type); QString platform = QGuiApplication::platformName(); if (platform.startsWith(QLatin1String("xcb"), Qt::CaseInsensitive)) { MotifWmHints hints; hints.flags = MWM_HINTS_FUNCTIONS | MWM_HINTS_DECORATIONS; hints.functions = MWM_FUNC_ALL; hints.decorations = MWM_DECOR_BORDER; XAtomHelper::getInstance()->setWindowMotifHint(this->winId(), hints); } } void KWidget::setWindowFlag(Qt::WindowType flag, bool on) { Q_D(KWidget); QWidget::setWindowFlag(flag, on); d->adjustFlagTitleStatus(flag); QString platform = QGuiApplication::platformName(); if (platform.startsWith(QLatin1String("xcb"), Qt::CaseInsensitive)) { MotifWmHints hints; hints.flags = MWM_HINTS_FUNCTIONS | MWM_HINTS_DECORATIONS; hints.functions = MWM_FUNC_ALL; hints.decorations = MWM_DECOR_BORDER; XAtomHelper::getInstance()->setWindowMotifHint(this->winId(), hints); } } void KWidget::setSidebarFollowMode(bool flag) { Q_D(KWidget); d->m_sidebarFollowMode = flag; } bool KWidget::sidebarFollowMode() { Q_D(KWidget); return d->m_sidebarFollowMode; } bool KWidget::eventFilter(QObject *target, QEvent *event) { Q_D(KWidget); if (target == this && (event->type() == QEvent::WindowStateChange || event->type() == QEvent::Show)) { if (this->isMaximized()) d->m_pWindowButtonBar->setMaximumButtonState(MaximumButtonState::Restore); else d->m_pWindowButtonBar->setMaximumButtonState(MaximumButtonState::Maximum); } if (target == this && (event->type() == FocusIn || event->type() == FocusOut) || event->type() == QEvent::ActivationChange ||event->type() == QEvent::WindowActivate ||event->type() == QEvent::WindowDeactivate ) { if ( event->type() == QEvent::WindowActivate ) { // 窗口被激活 d->m_pSideColor = ThemeController::getCustomColorFromDT("kcontain-secondary-normal"); d->m_pBaseColor = ThemeController::getCustomColorFromDT("kcontain-general-normal"); #ifdef USE_UKUI_SHELL_PLUGIN d->m_ukuiWindowHelper->setBlurEffect(QRegion(), 0, true); #else KWindowEffects::enableBlurBehind(this->winId(), true); #endif } else if(event->type() == QEvent::WindowDeactivate){ // 窗口失去激活 d->m_pSideColor = ThemeController::getCustomColorFromDT("kcontain-secondary-inactive"); d->m_pBaseColor = ThemeController::getCustomColorFromDT("kcontain-general-inactive"); #ifdef USE_UKUI_SHELL_PLUGIN d->m_ukuiWindowHelper->setBlurEffect(QRegion(), 0, false); #else KWindowEffects::enableBlurBehind(this->winId(), false); #endif } d->adjustBackground(); update(); } QString platform = QGuiApplication::platformName(); if (platform.startsWith(QLatin1String("wayland"), Qt::CaseInsensitive)) { if ((event->type() == QEvent::PlatformSurface || event->type() == QEvent::Show || event->type() == QEvent::UpdateRequest)) { #ifdef USE_UKUI_SHELL_PLUGIN this->setProperty("ukui_surface_no_titlebar", true); #else #ifdef USE_UKUI_PROTOCOL if (UkuiShellManager::getInstance()->ukuishellReady()) UkuiShellManager::getInstance()->removeHeaderBar(this->windowHandle()); else UKUIDecorationManager::getInstance()->removeHeaderBar(this->windowHandle()); #else UKUIDecorationManager::getInstance()->removeHeaderBar(this->windowHandle()); #endif #endif } } if (target == this && (event->type() == QEvent::Close || event->type() == QEvent::Hide)) { d->m_pWindowButtonBar->closeButton()->setAttribute(Qt::WA_UnderMouse, false); QHoverEvent hoverEvent(QEvent::HoverLeave, QPoint(10, 10), QPoint(0, 0)); QCoreApplication::sendEvent(d->m_pWindowButtonBar->closeButton(), &hoverEvent); } return QWidget::eventFilter(target, event); } void KWidget::changeIconStyle() { Q_D(KWidget); initThemeStyle(); setIcon(d->m_IconName); } void KWidget::changeTheme() { Q_D(KWidget); d->m_pSideColor = ThemeController::getCustomColorFromDT("kcontain-secondary-normal"); d->m_pBaseColor = ThemeController::getCustomColorFromDT("kcontain-general-normal"); if (ThemeController::widgetTheme() != ClassicTheme) { this->setAttribute(Qt::WA_TranslucentBackground, true); // 透明 } initThemeStyle(); d->adjustBackground(); } KWidgetPrivate::KWidgetPrivate(KWidget *parent) : q_ptr(parent) , m_sidebarFollowMode(true) { Q_Q(KWidget); m_pMainLayout = new QVBoxLayout(); m_pTitleLayout = new QHBoxLayout(); m_layoutType = VerticalType; // 图标和标题名称 m_pIconBar = new KIconBar(q); m_pIconBar->setObjectName("IconBar"); m_pIconBar->setFixedWidth(Parmscontroller::parm(Parmscontroller::Parm::PM_Widget_SideWidget_Width)); m_pIconBar->setFixedHeight(Parmscontroller::parm(Parmscontroller::Parm::PM_IconbarHeight)); // 窗口三联 m_pWindowButtonBar = new KWindowButtonBar(q); m_pWindowButtonBar->setObjectName("TitleBar"); m_pWindowButtonBar->setFixedHeight(Parmscontroller::parm(Parmscontroller::Parm::PM_IconbarHeight)); m_pTitleLayout->addWidget(m_pIconBar); m_pTitleLayout->addWidget(m_pWindowButtonBar); m_pTitleLayout->setSpacing(0); m_pTitleLayout->setContentsMargins(0, 0, 0, 0); m_pWidgetLayout = new QHBoxLayout(); m_pBaseWidget = new QWidget(q); m_pBaseWidget->setObjectName("BaseWidget"); m_pSideWidget = new QWidget(q); m_pSideWidget->setObjectName("SideWidget"); m_pSideWidget->setFixedWidth(Parmscontroller::parm(Parmscontroller::Parm::PM_Widget_SideWidget_Width)); m_pWidgetLayout->addWidget(m_pSideWidget); m_pWidgetLayout->addWidget(m_pBaseWidget); m_pMainLayout->addLayout(m_pTitleLayout); m_pMainLayout->addLayout(m_pWidgetLayout); m_pMainLayout->setSpacing(0); m_pMainLayout->setContentsMargins(0, 0, 0, 0); q->setLayout(m_pMainLayout); m_pBaseWidget->setAutoFillBackground(true); m_pBaseWidget->setBackgroundRole(QPalette::Base); m_pWindowButtonBar->setAutoFillBackground(true); m_pWindowButtonBar->setBackgroundRole(QPalette::Base); setParent(parent); KDK_ALL_INFO_FORMAT(m_pIconBar,""); KDK_ALL_INFO_FORMAT(m_pWindowButtonBar,""); KDK_ALL_INFO_FORMAT(m_pBaseWidget,""); KDK_ALL_INFO_FORMAT(m_pSideWidget,""); KDK_ALL_INFO_FORMAT(m_pSideWidget,""); } void KWidgetPrivate::adjustBackground() { Q_Q(KWidget); m_pIconBar->setAutoFillBackground(true); m_pSideWidget->setAutoFillBackground(true); if(q->isActiveWindow()) { m_pSideColor.setAlphaF(tranSparency); } QPalette sidePalette ; sidePalette.setColor(QPalette::Window, m_pSideColor); QPalette basePalette; basePalette.setColor(QPalette::Base, m_pBaseColor); m_pWindowButtonBar->setPalette(basePalette); m_pIconBar->setPalette(basePalette); m_pBaseWidget->setPalette(basePalette); m_pWindowButtonBar->setBackgroundRole(QPalette::Base); m_pBaseWidget->setBackgroundRole(QPalette::Base); switch (m_layoutType) { case VerticalType: m_pIconBar->setBackgroundRole(QPalette::Base); m_pSideWidget->hide(); break; case HorizontalType: m_pSideWidget->setPalette(sidePalette); m_pIconBar->setBackgroundRole(QPalette::Window); m_pIconBar->setPalette(sidePalette); m_pSideWidget->show(); break; case MixedType: m_pIconBar->setBackgroundRole(QPalette::Base); m_pSideWidget->setPalette(sidePalette); m_pSideWidget->show(); break; default: break; } } void KWidgetPrivate::adjustFlagsTitleStatus(Qt::WindowFlags type) { Q_Q(KWidget); m_pWindowButtonBar->menuButton()->hide(); switch (type) { case Qt::Drawer: m_pWindowButtonBar->minimumButton()->hide(); // m_pWindowButtonBar->menuButton()->hide(); break; case Qt::Tool: m_pWindowButtonBar->minimumButton()->hide(); m_pWindowButtonBar->maximumButton()->hide(); // m_pWindowButtonBar->menuButton()->hide(); break; case Qt::ToolTip: m_pWindowButtonBar->minimumButton()->hide(); m_pWindowButtonBar->maximumButton()->hide(); m_pWindowButtonBar->closeButton()->hide(); // m_pWindowButtonBar->menuButton()->hide(); break; case Qt::SplashScreen: m_pWindowButtonBar->minimumButton()->hide(); m_pWindowButtonBar->maximumButton()->hide(); m_pWindowButtonBar->closeButton()->hide(); // m_pWindowButtonBar->menuButton()->hide(); break; case Qt::Dialog: m_pWindowButtonBar->minimumButton()->hide(); m_pWindowButtonBar->maximumButton()->hide(); // m_pWindowButtonBar->menuButton()->hide(); break; case Qt::Sheet: m_pWindowButtonBar->minimumButton()->hide(); m_pWindowButtonBar->maximumButton()->hide(); // m_pWindowButtonBar->menuButton()->hide(); break; case Qt::Popup: m_pWindowButtonBar->minimumButton()->hide(); m_pWindowButtonBar->maximumButton()->hide(); m_pWindowButtonBar->closeButton()->hide(); // m_pWindowButtonBar->menuButton()->hide(); break; case Qt::Desktop: m_pWindowButtonBar->minimumButton()->hide(); m_pWindowButtonBar->maximumButton()->hide(); m_pWindowButtonBar->closeButton()->hide(); // m_pWindowButtonBar->menuButton()->hide(); q->deleteLater(); break; case Qt::ForeignWindow: // m_pWindowButtonBar->menuButton()->hide(); // break; case Qt::CoverWindow: // m_pWindowButtonBar->menuButton()->hide(); // break; case Qt::Window: // m_pWindowButtonBar->menuButton()->hide(); // break; case Qt::Widget: // m_pWindowButtonBar->menuButton()->hide(); // break; case Qt::SubWindow: // m_pWindowButtonBar->menuButton()->hide(); break; default: break; } } void KWidgetPrivate::adjustFlagTitleStatus(Qt::WindowFlags type) { Q_Q(KWidget); switch (type) { case Qt::Drawer: m_pWindowButtonBar->minimumButton()->hide(); m_pWindowButtonBar->menuButton()->hide(); break; case Qt::Tool: m_pWindowButtonBar->minimumButton()->hide(); m_pWindowButtonBar->menuButton()->hide(); break; case Qt::ToolTip: m_pWindowButtonBar->minimumButton()->hide(); m_pWindowButtonBar->maximumButton()->hide(); m_pWindowButtonBar->closeButton()->hide(); m_pWindowButtonBar->menuButton()->hide(); break; case Qt::SplashScreen: m_pWindowButtonBar->minimumButton()->hide(); m_pWindowButtonBar->maximumButton()->hide(); m_pWindowButtonBar->closeButton()->hide(); m_pWindowButtonBar->menuButton()->hide(); break; case Qt::Dialog: m_pWindowButtonBar->menuButton()->hide(); break; case Qt::Sheet: m_pWindowButtonBar->menuButton()->hide(); break; case Qt::Popup: m_pWindowButtonBar->minimumButton()->hide(); m_pWindowButtonBar->maximumButton()->hide(); m_pWindowButtonBar->closeButton()->hide(); m_pWindowButtonBar->menuButton()->hide(); break; case Qt::Desktop: m_pWindowButtonBar->minimumButton()->hide(); m_pWindowButtonBar->maximumButton()->hide(); m_pWindowButtonBar->closeButton()->hide(); m_pWindowButtonBar->menuButton()->hide(); q->deleteLater(); break; case Qt::ForeignWindow: q->setWindowFlags(Qt::WindowMinMaxButtonsHint); // 为窗口添加最大化和最小化按钮 m_pWindowButtonBar->menuButton()->hide(); break; case Qt::CoverWindow: m_pWindowButtonBar->menuButton()->hide(); break; case Qt::Window: m_pWindowButtonBar->menuButton()->hide(); break; case Qt::Widget: m_pWindowButtonBar->menuButton()->hide(); break; case Qt::SubWindow: m_pWindowButtonBar->menuButton()->hide(); break; default: break; } } } #include "kwidget.moc" #include "moc_kwidget.cpp" libkysdk-applications/kysdk-qtwidgets/src/kdirtabbar.cpp0000664000175000017500000003331015104543305022536 0ustar fengfeng/* * libkysdk-qtwidgets's Library * * Copyright (C) 2024, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Yaxian Liu * */ #include "kdirtabbar.h" #include "themeController.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace kdk { class CustomButton : public QToolButton { Q_OBJECT public: CustomButton(QWidget *parent = nullptr); QIcon setIconColor(QIcon icon, QColor color) { QPixmap pixmap = icon.pixmap(QSize(16, 16)); QPainter painter(&pixmap); painter.setCompositionMode(QPainter::CompositionMode_SourceIn); painter.fillRect(pixmap.rect(), color); QIcon colorIcon = QIcon(pixmap); return colorIcon; } protected: void paintEvent(QPaintEvent *event); }; class KDirTabBarPrivate : public QObject, public ThemeController { Q_OBJECT Q_DECLARE_PUBLIC(KDirTabBar) public: KDirTabBarPrivate(KDirTabBar *parent); void clearButtons(); void addButton(const QString &uri, QString buttonName, bool setMenu = true); void doLayout(); void changeTheme(); private: KDirTabBar *q_ptr; int m_visibleDepth; int m_textLength; QString m_currentPath; QString m_rootPath; QHBoxLayout *buttonLayout; QHBoxLayout *m_layout; // QSpacerItem *spacer; QList m_buttonList; QList m_button_info; }; KDirTabBar::KDirTabBar(QWidget *parent) : QWidget(parent) , d_ptr(new KDirTabBarPrivate(this)) { Q_D(KDirTabBar); d->m_visibleDepth = 5; d->m_textLength = 5; // d->spacer = new QSpacerItem(40, 20, QSizePolicy::Expanding, QSizePolicy::Minimum); d->buttonLayout = new QHBoxLayout; d->buttonLayout->setContentsMargins(0, 0, 0, 0); d->buttonLayout->setSpacing(0); d->m_layout = new QHBoxLayout(this); d->m_layout->setContentsMargins(0, 0, 0, 0); d->m_layout->setSpacing(0); d->m_layout->addLayout(d->buttonLayout); // d->m_layout->addItem(d->spacer); d->m_layout->addStretch(); setLayout(d->m_layout); // setFocusPolicy(Qt::ClickFocus); setObjectName("KDirTabBar"); connect(d->m_gsetting, &QGSettings::changed, d, &KDirTabBarPrivate::changeTheme); } KDirTabBar::~KDirTabBar() { } void KDirTabBar::setCurrentPath(const QString Dirpath) { Q_D(KDirTabBar); QList lastInfo; for (auto info : d->m_button_info) { QFileInfo *fileinfo = new QFileInfo(); fileinfo = info; lastInfo.append(fileinfo); } d->m_currentPath = Dirpath; d->m_button_info.clear(); auto tmpUri = Dirpath; QFileInfo *file = new QFileInfo(tmpUri); while (tmpUri != "/" && tmpUri != "") { d->m_button_info.prepend(file); tmpUri = file->absolutePath(); file = new QFileInfo(tmpUri); } if (lastInfo.isEmpty()) { d->clearButtons(); for (auto info : d->m_button_info) { d->addButton(info->absoluteFilePath(), info->fileName(), true); } } else { while (d->m_button_info.size() < d->m_buttonList.size()) // 新的比旧的列表短时,去掉多余的Qlist项 { d->m_buttonList.last()->deleteLater(); d->m_buttonList.removeLast(); } for (int i = d->m_buttonList.size() - 1; i >= 0; i--) { if (lastInfo[i]->absoluteFilePath() != d->m_button_info[i]->absoluteFilePath()) // 对比新旧列表中的每一项,如果不相同则remove按钮列表中的元素 { d->m_buttonList[i]->hide(); d->m_buttonList[i]->deleteLater(); d->m_buttonList.removeAt(i); } } for (int i = d->m_buttonList.size(); i < d->m_button_info.size(); i++) { d->addButton(d->m_button_info[i]->absoluteFilePath(), d->m_button_info[i]->fileName(), true); } } for (auto info : lastInfo) { delete info; } lastInfo.clear(); d->doLayout(); // 布局,最大显示个数 } QString KDirTabBar::currentPath() const { Q_D(const KDirTabBar); return d->m_currentPath; } void KDirTabBar::setVisibleDepth(const int depth) { Q_D(KDirTabBar); d->m_visibleDepth = depth; // dolayout } int KDirTabBar::visibleDepth() { Q_D(KDirTabBar); return d->m_visibleDepth; } void KDirTabBar::setIcon(int index, const QIcon &icon) { Q_D(KDirTabBar); if (index < d->m_buttonList.size()) { d->m_buttonList[index - 1]->setIcon(icon); d->doLayout(); } } QIcon KDirTabBar::icon(int index) { Q_D(KDirTabBar); return d->m_buttonList[index - 1]->icon(); } void KDirTabBar::setTextLength(int length) { Q_D(KDirTabBar); d->m_textLength = length; } int KDirTabBar::textLength() { Q_D(KDirTabBar); return d->m_textLength; } QList KDirTabBar::buttons() { Q_D(KDirTabBar); return d->m_buttonList; } // void KDirTabBar::mousePressEvent(QMouseEvent *event) //{ // QWidget::mousePressEvent(event); //} void KDirTabBarPrivate::addButton(const QString &uri, QString buttonName, bool setMenu) { Q_Q(KDirTabBar); CustomButton *button = new CustomButton(q); QString displayName = buttonName; button->setFocusPolicy(Qt::FocusPolicy(button->focusPolicy() & ~Qt::TabFocus)); button->setAutoRaise(true); button->setProperty("uri", uri); button->setIconSize(QSize(16, 16)); button->setToolButtonStyle(Qt::ToolButtonTextBesideIcon); button->setPopupMode(CustomButton::MenuButtonPopup); m_buttonList.append(static_cast(button)); buttonLayout->addWidget(button); button->setIcon(QIcon::fromTheme("folder")); QFontMetrics ftm(q->font()); if (displayName.length() > m_textLength) { int charWidth = ftm.averageCharWidth(); displayName = ftm.elidedText(displayName, Qt::ElideRight, m_textLength * charWidth); } button->setText(displayName); if (buttonName != displayName) { button->setToolTip(buttonName); } connect(button, &CustomButton::clicked, [=]() { q->setCurrentPath(uri); emit q->tabBarClicked(uri); }); if (setMenu) { QList uris; QDirIterator it(uri, QDir::Dirs | QDir::NoDotAndDotDot); while (it.hasNext()) { it.next(); QFileInfo fileInfo = it.fileInfo(); if (fileInfo.isDir()) { uris << fileInfo; } } QMenu *menu = new QMenu; connect(button, &CustomButton::destroyed, menu, &QMenu::deleteLater); const int WIDTH_EXTEND = 5; connect(menu, &QMenu::aboutToShow, this, [=]() { menu->setMinimumWidth(button->width() + WIDTH_EXTEND); }); connect(menu, &QMenu::aboutToHide, this, [=]() { }); if (uris.isEmpty()) button->setPopupMode(CustomButton::InstantPopup); else { QList actions; for (auto uri : uris) { QIcon icon; if (uri.baseName() == "图片") icon = QIcon::fromTheme("folder-pictures"); else if (uri.baseName() == "下载") icon = QIcon::fromTheme("folder-download"); else if (uri.baseName() == "公共的") icon = QIcon::fromTheme("folder-publicshare"); else if (uri.baseName() == "文档") icon = QIcon::fromTheme("folder-documents"); else if (uri.baseName() == "桌面") icon = QIcon::fromTheme("user-desktop"); else if (uri.baseName() == "模板") icon = QIcon::fromTheme("folder-templates"); else if (uri.baseName() == "视频") icon = QIcon::fromTheme("folder-videos"); else if (uri.baseName() == "音乐") icon = QIcon::fromTheme("folder-music"); else icon = QIcon::fromTheme("folder"); QAction *action = new QAction(icon, uri.fileName(), this); actions << action; connect(action, &QAction::triggered, [=]() { q->setCurrentPath(uri.absoluteFilePath()); emit q->tabBarClicked(uri.absoluteFilePath()); }); } menu->addActions(actions); if (menu) button->setMenu(menu); } } } void KDirTabBarPrivate::doLayout() { Q_Q(KDirTabBar); int counter = 0; if (m_buttonList.size() > m_visibleDepth) { counter = m_buttonList.size() - m_visibleDepth; } for (int i = 0; i < m_buttonList.size(); i++) { m_buttonList[i]->setVisible(false); } for (counter; counter < m_buttonList.size(); counter++) { m_buttonList[counter]->setVisible(true); m_buttonList[counter]->setToolButtonStyle(Qt::ToolButtonTextBesideIcon); m_buttonList[counter]->adjustSize(); // buttonLayout->addWidget(m_buttonList[counter]); } } void KDirTabBarPrivate::changeTheme() { Q_Q(KDirTabBar); initThemeStyle(); } void KDirTabBarPrivate::clearButtons() { Q_Q(KDirTabBar); for (auto button : m_buttonList) { button->hide(); button->deleteLater(); } m_buttonList.clear(); } KDirTabBarPrivate::KDirTabBarPrivate(KDirTabBar *parent) : q_ptr(parent) { } CustomButton::CustomButton(QWidget *parent) { } void CustomButton::paintEvent(QPaintEvent *event) { QStyleOptionToolButton option; initStyleOption(&option); // QToolButton::paintEvent(event); int ra = ThemeController::getRadiusFromDT("kradius-normal"); if (ra == -1) ra = 6; QColor textColor = ThemeController::getCustomColorFromDT("text-active"); QColor backgroundColor; QPen pen; QPainter painter(this); painter.setRenderHint(QPainter::Antialiasing); if (ThemeController::themeMode() == LightTheme) { // 浅色模式 if (!option.state.testFlag(QStyle::State_Enabled)) { textColor = ThemeController::getCustomColorFromDT("text-disable"); } else { // 三态 if (option.state.testFlag(QStyle::State_Sunken)) { backgroundColor = ThemeController::getCustomColorFromDT("kgray-10"); // 绘制背景颜色 painter.setBrush(backgroundColor); pen = QPen(backgroundColor); painter.setPen(pen); painter.drawRoundedRect(rect(), ra, ra); } else if (option.state.testFlag(QStyle::State_MouseOver)) { backgroundColor = ThemeController::getCustomColorFromDT("kgray-7"); // 绘制背景颜色 painter.setBrush(backgroundColor); pen = QPen(backgroundColor); painter.setPen(pen); painter.drawRoundedRect(rect(), ra, ra); } } } else { if (!option.state.testFlag(QStyle::State_Enabled)) { textColor = ThemeController::getCustomColorFromDT("text-disable"); } else { // 三态 if (option.state.testFlag(QStyle::State_Sunken)) { backgroundColor = ThemeController::getCustomColorFromDT("kgray-13"); // 绘制背景颜色 painter.setBrush(backgroundColor); pen = QPen(backgroundColor); painter.setPen(pen); painter.drawRoundedRect(rect(), ra, ra); } else if (option.state.testFlag(QStyle::State_MouseOver)) { backgroundColor = QColor("#545454"); // 绘制背景颜色 painter.setBrush(backgroundColor); pen = QPen(backgroundColor); painter.setPen(pen); painter.drawRoundedRect(rect(), ra, ra); } } } painter.end(); // 绘制图标、文本、箭头 QPainter p(this); QRect textRect; uint tf = Qt::AlignVCenter; textRect = QRect(32, 0, option.rect.width() - 64, option.rect.height()); if (menu() && menu()->isVisible()) { p.drawPixmap(this->width() - 24, (this->height() - 16) / 2, 16, 16, ThemeController::drawColoredPixmap(QIcon::fromTheme("ukui-down-symbolic").pixmap(16, 16), textColor)); } else if (menu() && !menu()->isVisible()) { p.drawPixmap(this->width() - 24, (this->height() - 16) / 2, 16, 16, setIconColor(QIcon::fromTheme("ukui-end-symbolic"), textColor).pixmap(16.16)); } else textRect = QRect(32, 0, option.rect.width() - 32, option.rect.height()); if (!icon().isNull()) p.drawPixmap(8, (option.rect.height() - 16) / 2, 16, 16, icon().pixmap(16, 16)); else textRect = QRect(8, 0, option.rect.width() - 32, option.rect.height()); pen = QPen(textColor); p.setPen(pen); p.drawText(textRect, tf, this->text()); p.end(); } } #include "kdirtabbar.moc" #include "moc_kdirtabbar.cpp" libkysdk-applications/kysdk-qtwidgets/src/kflowlayout.cpp0000664000175000017500000001567315104543305023025 0ustar fengfeng/* * * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Sisheng He * */ #include "kflowlayout.h" #include #include namespace kdk { class KFlowLayoutPrivate : public QObject { Q_OBJECT Q_DECLARE_PUBLIC(KFlowLayout) public: KFlowLayoutPrivate(KFlowLayout *parent); private: KFlowLayout *q_ptr; QList m_itemList; int m_hSpace; int m_vSpace; bool m_home = false; private: int doLayout(const QRect &rect, bool testOnly) const; int smartSpacing(QStyle::PixelMetric pm) const; int fillSpaceX(QWidget *wid) const; }; KFlowLayoutPrivate::KFlowLayoutPrivate(KFlowLayout *parent) : q_ptr(parent) { } int KFlowLayoutPrivate::smartSpacing(QStyle::PixelMetric pm) const { Q_Q(const KFlowLayout); QObject *parent = q->parent(); if (!parent) { return -1; } else if (parent->isWidgetType()) { QWidget *pw = static_cast(parent); return pw->style()->pixelMetric(pm, 0, pw); } else { return static_cast(parent)->spacing(); } } int KFlowLayoutPrivate::doLayout(const QRect &rect, bool testOnly) const { Q_Q(const KFlowLayout); int left, top, right, bottom; q->getContentsMargins(&left, &top, &right, &bottom); QRect effectiveRect = rect.adjusted(+left, +top, -right, -bottom); int x = effectiveRect.x(); int y = effectiveRect.y(); int lineHeight = 0; int fillX = 0; bool bFillX = false; QLayoutItem *item; foreach (item, m_itemList) { QWidget *wid = item->widget(); int spaceX = q->horizontalSpacing(); if (spaceX == -1) { if (!bFillX) { bFillX = true; fillX = fillSpaceX(wid); } spaceX = fillX; } int spaceY = q->verticalSpacing(); if (spaceY == -1 && fillX >= 0) { spaceY = fillX; } /*else { spaceY = wid->style()->layoutSpacing( QSizePolicy::PushButton, QSizePolicy::PushButton, Qt::Vertical); }*/ if (m_home) { spaceY = 32; } int nextX = x + item->sizeHint().width() + spaceX; if (nextX - spaceX > effectiveRect.right() && lineHeight > 0) { x = effectiveRect.x(); y = y + lineHeight + spaceY; nextX = x + item->sizeHint().width() + spaceX; lineHeight = 0; } if (!testOnly) item->setGeometry(QRect(QPoint(x, y), item->sizeHint())); x = nextX; lineHeight = qMax(lineHeight, item->sizeHint().height()); } return y + lineHeight - rect.y() + bottom; } int KFlowLayoutPrivate::fillSpaceX(QWidget *wid) const { Q_Q(const KFlowLayout); int num = 0; int x = 0; int numH = 0; int space = 4; if (m_home) { space = 24; } int len = q->parentWidget()->width() - q->contentsMargins().left() - q->contentsMargins().right(); while (true) { num++; if (num * (wid->width() + space) - space >= len) { // 最小间距space break; } } num = num - 1; if (num <= 1) { numH = m_itemList.size(); return 32; } int height = wid->height(); numH = ceil(double(m_itemList.size()) / num); x = len + space - num * (wid->width() + space); x = ceil(double(x) / (num - 1)) + space; x = x - 1; // 考虑边框等因素影响 int maxY = numH * (height + x) + 32 - x; if (m_home) { maxY = numH * (height + 32); q->parentWidget()->parentWidget()->setFixedHeight(maxY); } q->parentWidget()->setFixedHeight(maxY); return x; } KFlowLayout::KFlowLayout(QWidget *parent, bool home, int margin, int hSpacing, int vSpacing) : QLayout(parent) , d_ptr(new KFlowLayoutPrivate(this)) { Q_D(KFlowLayout); d->m_hSpace = hSpacing; d->m_vSpace = vSpacing; d->m_home = home; setContentsMargins(margin, margin, margin, margin); } KFlowLayout::KFlowLayout(int margin, int hSpacing, int vSpacing) : d_ptr(new KFlowLayoutPrivate(this)) { Q_D(KFlowLayout); d->m_hSpace = hSpacing; d->m_vSpace = vSpacing; setContentsMargins(margin, margin, margin, margin); } KFlowLayout::~KFlowLayout() { QLayoutItem *item; while ((item = takeAt(0))) { } } void KFlowLayout::addItem(QLayoutItem *item) { Q_D(KFlowLayout); d->m_itemList.append(item); } int KFlowLayout::horizontalSpacing() const { Q_D(const KFlowLayout); if (d->m_hSpace >= 0 || d->m_hSpace == -1) { return d->m_hSpace; } else { return d->smartSpacing(QStyle::PM_LayoutHorizontalSpacing); } } int KFlowLayout::verticalSpacing() const { Q_D(const KFlowLayout); if (d->m_vSpace >= 0 || d->m_vSpace == -1) { return d->m_vSpace; } else { return d->smartSpacing(QStyle::PM_LayoutVerticalSpacing); } } int KFlowLayout::count() const { Q_D(const KFlowLayout); return d->m_itemList.size(); } QLayoutItem *KFlowLayout::itemAt(int index) const { Q_D(const KFlowLayout); return d->m_itemList.value(index); } QLayoutItem *KFlowLayout::takeAt(int index) { Q_D(KFlowLayout); if (index >= 0 && index < d->m_itemList.size()) return d->m_itemList.takeAt(index); else return 0; } Qt::Orientations KFlowLayout::expandingDirections() const { Q_D(const KFlowLayout); return Qt::Orientations(); } bool KFlowLayout::hasHeightForWidth() const { Q_D(const KFlowLayout); return true; } int KFlowLayout::heightForWidth(int width) const { Q_D(const KFlowLayout); int height = d->doLayout(QRect(0, 0, width, 0), true); return height; } void KFlowLayout::setGeometry(const QRect &rect) { Q_D(KFlowLayout); QLayout::setGeometry(rect); d->doLayout(rect, false); } QSize KFlowLayout::sizeHint() const { Q_D(const KFlowLayout); return minimumSize(); } QSize KFlowLayout::minimumSize() const { Q_D(const KFlowLayout); QSize size; QLayoutItem *item; foreach (item, d->m_itemList) size = size.expandedTo(item->minimumSize()); // size += QSize(2 * margin(), 2 * margin()); QMargins margins = contentsMargins(); size += QSize(margins.left() + margins.right(), margins.top() + margins.bottom()); return size; } } #include "kflowlayout.moc" #include "moc_kflowlayout.cpp" libkysdk-applications/kysdk-qtwidgets/src/ktexteditor.h0000664000175000017500000000263115104543305022446 0ustar fengfeng/* * libkysdk-qtwidgets's Library * * Copyright (C) 2024, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhenyu Wang * */ #ifndef KTEXTEDITOR_H #define KTEXTEDITOR_H #include "gui_g.h" #include #include namespace kdk { /** * @defgroup TextEditModule * @since 2.5.2.0 * { */ class KTextEditorPrivate; class GUI_EXPORT KTextEditor : public QWidget { Q_OBJECT public: KTextEditor(QWidget *parent = nullptr); /** * @brief 获取QTextedit * @return */ QTextEdit *textEdit(); protected: void paintEvent(QPaintEvent *event); bool eventFilter(QObject *watched, QEvent *event); private: Q_DECLARE_PRIVATE(KTextEditor) KTextEditorPrivate *const d_ptr; }; } #endif // KTEXTEDITOR_H libkysdk-applications/kysdk-qtwidgets/src/kbackgroundgroup.h0000664000175000017500000000633515104543305023454 0ustar fengfeng/* * libkysdk-qtwidgets's Library * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #ifndef KBACKGROUNDGROUP_H #define KBACKGROUNDGROUP_H #include "gui_g.h" #include #include namespace kdk { /** * @defgroup ContainerModule * { */ class KBackgroundGroupPrivate; /** * @brief 提供了一个用于存储部件的容器 * @since 2.0.2.1 */ class GUI_EXPORT KBackgroundGroup : public QFrame { Q_OBJECT public: KBackgroundGroup(QWidget *parent = nullptr); /** * @brief 添加一个widget控件 * @param widget */ void addWidget(QWidget *widget); /** * @brief 添加一个widget list * @param list */ void addWidgetList(QList list); /** * @brief 删除一个指定index的widget * @param i */ void removeWidgetAt(int i); /** * @brief 删除一个widget * @param widget */ void removeWidget(QWidget *widget); /** * @brief 删除一个widget list * @param list */ void removeWidgetList(QList list); /** * @brief 指定位置插入一个widget * @param index * @param widget */ void insertWidgetAt(int index, QWidget *widget); /** * @brief 指定位置插入一个widget list * @param index * @param list */ void insertWidgetList(int index, QList list); /** * @brief 设置KBackgroundGroup的圆角 * @param radius */ void setBorderRadius(int radius); /** * @brief 返回KBackgroundGroup的圆角 * @return */ int borderRadius(); /** * @brief 设置背景颜色 * @param role */ void setBackgroundRole(QPalette::ColorRole role); /** * @brief 返回背景颜色 * @return */ QPalette::ColorRole backgroundRole() const; /** * @brief 设置窗体是否可以响应三态 * @param flag * @param widget */ void setStateEnable(QWidget *widget, bool flag); /** * @brief 返回widget列表 * @return */ QList widgetList(); /** * @brief 设置边框是否可见 * @param flag * @since 3.0.1.0 */ void setBorderVisible(bool flag); Q_SIGNALS: /** * @brief 点击会发出信号 */ void clicked(QWidget *); protected: void paintEvent(QPaintEvent *event); bool eventFilter(QObject *watched, QEvent *event); private: Q_DECLARE_PRIVATE(KBackgroundGroup) KBackgroundGroupPrivate *const d_ptr; }; } #endif // KBACKGROUNDGROUP_H libkysdk-applications/kysdk-qtwidgets/src/kbuttonbox.h0000664000175000017500000000753515104543305022307 0ustar fengfeng/* * libkysdk-qtwidgets's Library * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #ifndef KBUTTONBOX_H #define KBUTTONBOX_H #include "gui_g.h" #include "kpushbutton.h" #include #include namespace kdk { /** * @defgroup ContainerModule */ class KButtonBoxPrivate; /** * @brief 提供了一个按钮类容器 * @since 2.0.2.1 */ class GUI_EXPORT KButtonBox : public QWidget { Q_OBJECT public: explicit KButtonBox(QWidget *parent = nullptr); ~KButtonBox(); /** * @brief 获取KButtonBox的布局类型 * @return */ Qt::Orientation orientation(); /** * @brief 设置KButtonBox的布局类型,包括水平类型和垂直类型 * @param orientation */ void setOrientation(Qt::Orientation orientation); /** * @brief 添加按钮 * @param button */ void addButton(KPushButton *button, int i = -1); /** * @brief 删除按钮 * @param button */ void removeButton(KPushButton *button); /** * @brief 按id删除指定按钮 * @param i */ void removeButton(int i); /** * @brief 以列表形式向KButtonBox中添加按钮 * @param list * @param checkable */ void setButtonList(const QList &list); /** * @brief 获取KButtonBox中的按钮列表 * @return */ QList buttonList(); /** * @brief 设置KButtonBox首尾部分按钮的圆角 * @param radius */ void setBorderRadius(int radius); /** * @brief 获取KButtonBox首尾部分按钮的圆角 * @return */ int borderRadius(); /** * @brief 设置按钮id * @param button * @param id */ void setId(KPushButton *button, int id); /** * @brief 获取按钮id * @param button * @return */ int id(KPushButton *button); /** * @brief 返回已选中的按钮 * @return */ KPushButton *checkedButton(); /** * @brief 通过按钮id获取按钮 * @param id * @return */ KPushButton *button(int id); /** * @brief 返回已选中按钮的id * @return */ int checkedId(); /** * @brief 设置KButtonBox按钮间是否互斥 */ void setExclusive(bool); /** * @brief 返回KButtonBox按钮间是否互斥 * @return */ bool exclusive(); /** * @brief 设置KButtonBox中的按钮是否可选中 */ void setCheckable(bool flag); /** * @brief 返回KButtonBox中的按钮是否可选中 * @return */ bool isCheckable(); /** * @brief 设置是否启动阴影效果 * @param flag * @since 2.4.1.0 */ void setShadow(bool flag); /** * @brief 获取是否启用阴影效果 * @return bool * @since 2.4.1.0 */ bool shadow(); Q_SIGNALS: void buttonClicked(QAbstractButton *); void buttonPressed(QAbstractButton *); void buttonReleased(QAbstractButton *); void buttonToggled(QAbstractButton *, bool); private: Q_DECLARE_PRIVATE(KButtonBox) KButtonBoxPrivate *const d_ptr; }; } #endif // KBUTTONBOX_H libkysdk-applications/kysdk-qtwidgets/src/accessinfohelper.h0000664000175000017500000000761615104543305023425 0ustar fengfeng/* * libkysdk-qtwidgets's Library * * Copyright (C) 2024, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #ifndef ACCESSIBLEFORMAT_H #define ACCESSIBLEFORMAT_H #include #include #include #include #include #include /** * @brief 设置控件属性 * @since 2.5.2.0 */ namespace kdk { template QString combineAccessibleName(T *obj, QString widgetName, const QString &pluginName, const QString &extend = QString()) { if (!obj) return QString(); if (!std::is_base_of::value) return QString(); QFileInfo cmdInfo(QApplication::arguments().at(0)); QString accessibleName = cmdInfo.fileName(); accessibleName += "_"; if (!pluginName.isEmpty()) { accessibleName += pluginName; accessibleName += "_"; } accessibleName += obj->metaObject()->className(); accessibleName += "_"; accessibleName += widgetName.remove(QRegularExpression("[&*]")); if (!extend.isEmpty()) { accessibleName += "_"; accessibleName += extend; } return accessibleName; } template QString combineAccessibleDescription(T *obj, const QString &widgetName) { if (!obj) return QString(); if (!std::is_base_of::value) return QString(); QFileInfo cmdInfo(QApplication::arguments().at(0)); return QString("[%1] is [%2] type in process:[%3]") .arg(widgetName) .arg(obj->metaObject()->className()) .arg(cmdInfo.fileName()); } template class AccessInfoHelper { public: AccessInfoHelper(T *widget) : m_widget(widget) { } void setObjectInfo(const QString &widgetName, const QString &pluginName, const QString &extend = QString()) { if (m_widget->objectName().isEmpty()) m_widget->setObjectName(combineAccessibleName(m_widget, widgetName, pluginName, extend)); } void setAllAttribute(const QString &widgetName, const QString &pluginName = QString(), const QString &extend = QString(), const QString &description = QString()) { if (!m_widget) return; setObjectInfo(widgetName, pluginName, extend); if (std::is_base_of::value) { m_widget->setAccessibleName(combineAccessibleName(m_widget, widgetName, pluginName, extend)); if (!description.isEmpty()) { m_widget->setAccessibleDescription(description); } else { m_widget->setAccessibleDescription(combineAccessibleDescription(m_widget, widgetName)); } } } private: T *m_widget; }; template AccessInfoHelper getHandle(T *widget) { return AccessInfoHelper(widget); } #define KDK_ALL_INFO_FORMAT(widget, description) getHandle(widget).setAllAttribute(#widget, "", "", description) #define KDK_EXTEND_ALL_INFO_FORMAT(widget, pluginName, extend, description) getHandle(widget).setAllAttribute(#widget, pluginName, extend, description) #define KDK_OBJ_INFO_FORMAT(obj) getHandle(obj).setObjectInfo(#obj, "") #define KDK_EXTEND_OBJ_INFO_FORMAT(obj, pluginName, extend) getHandle(obj).setObjectInfo(#obj, pluginName, extend) } #endif // ACCESSIBLEFORMAT_H libkysdk-applications/kysdk-qtwidgets/src/kcommentpanel.cpp0000664000175000017500000002171015104543305023267 0ustar fengfeng/* * libkysdk-qtwidgets's Library * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #include "kcommentpanel.h" #include "themeController.h" #include #include #include #include #include "accessinfohelper.h" namespace kdk { class StarWidget : public QWidget { public: StarWidget(QWidget *parent); void setGrade(StarLevel level); private: void doFresh(); StarLevel m_starLevel; QLabel *m_plbl1; QLabel *m_plbl2; QLabel *m_plbl3; QLabel *m_plbl4; QLabel *m_plbl5; }; StarWidget::StarWidget(QWidget *parent) : QWidget(parent) , m_starLevel(LevelZero) { setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); QHBoxLayout *hLayout = new QHBoxLayout(this); hLayout->setContentsMargins(0, 0, 0, 0); hLayout->setSpacing(2); m_plbl1 = new QLabel(this); m_plbl2 = new QLabel(this); m_plbl3 = new QLabel(this); m_plbl4 = new QLabel(this); m_plbl5 = new QLabel(this); m_plbl1->setAlignment(Qt::AlignTop); m_plbl2->setAlignment(Qt::AlignTop); m_plbl3->setAlignment(Qt::AlignTop); m_plbl4->setAlignment(Qt::AlignTop); m_plbl5->setAlignment(Qt::AlignTop); m_plbl1->setFixedSize(14, 14); m_plbl2->setFixedSize(14, 14); m_plbl3->setFixedSize(14, 14); m_plbl4->setFixedSize(14, 14); m_plbl5->setFixedSize(14, 14); hLayout->addWidget(m_plbl1); hLayout->addWidget(m_plbl2); hLayout->addWidget(m_plbl3); hLayout->addWidget(m_plbl4); hLayout->addWidget(m_plbl5); KDK_ALL_INFO_FORMAT(m_plbl1,""); KDK_ALL_INFO_FORMAT(m_plbl2,""); KDK_ALL_INFO_FORMAT(m_plbl3,""); KDK_ALL_INFO_FORMAT(m_plbl4,""); KDK_ALL_INFO_FORMAT(m_plbl5,""); } void StarWidget::setGrade(StarLevel level) { if (level != m_starLevel) { m_starLevel = level; doFresh(); } } void StarWidget::doFresh() { switch (m_starLevel) { case LevelZero: break; case LevelOne: m_plbl1->setPixmap(QIcon::fromTheme("ukui-starred-on-symbolic").pixmap(12, 12)); m_plbl2->setPixmap(QIcon::fromTheme("ukui-starred-symbolic").pixmap(12, 12)); m_plbl3->setPixmap(QIcon::fromTheme("ukui-starred-symbolic").pixmap(12, 12)); m_plbl4->setPixmap(QIcon::fromTheme("ukui-starred-symbolic").pixmap(12, 12)); m_plbl5->setPixmap(QIcon::fromTheme("ukui-starred-symbolic").pixmap(12, 12)); break; case LevelTwo: m_plbl1->setPixmap(QIcon::fromTheme("ukui-starred-on-symbolic").pixmap(12, 12)); m_plbl2->setPixmap(QIcon::fromTheme("ukui-starred-on-symbolic").pixmap(12, 12)); m_plbl3->setPixmap(QIcon::fromTheme("ukui-starred-symbolic").pixmap(12, 12)); m_plbl4->setPixmap(QIcon::fromTheme("ukui-starred-symbolic").pixmap(12, 12)); m_plbl5->setPixmap(QIcon::fromTheme("ukui-starred-symbolic").pixmap(12, 12)); break; case LevelThree: m_plbl1->setPixmap(QIcon::fromTheme("ukui-starred-on-symbolic").pixmap(12, 12)); m_plbl2->setPixmap(QIcon::fromTheme("ukui-starred-on-symbolic").pixmap(12, 12)); m_plbl3->setPixmap(QIcon::fromTheme("ukui-starred-on-symbolic").pixmap(12, 12)); m_plbl4->setPixmap(QIcon::fromTheme("ukui-starred-symbolic").pixmap(12, 12)); m_plbl5->setPixmap(QIcon::fromTheme("ukui-starred-symbolic").pixmap(12, 12)); break; case LevelFour: m_plbl1->setPixmap(QIcon::fromTheme("ukui-starred-on-symbolic").pixmap(12, 12)); m_plbl2->setPixmap(QIcon::fromTheme("ukui-starred-on-symbolic").pixmap(12, 12)); m_plbl3->setPixmap(QIcon::fromTheme("ukui-starred-on-symbolic").pixmap(12, 12)); m_plbl4->setPixmap(QIcon::fromTheme("ukui-starred-on-symbolic").pixmap(12, 12)); m_plbl5->setPixmap(QIcon::fromTheme("ukui-starred-symbolic").pixmap(12, 12)); break; case LevelFive: m_plbl1->setPixmap(QIcon::fromTheme("ukui-starred-on-symbolic").pixmap(12, 12)); m_plbl2->setPixmap(QIcon::fromTheme("ukui-starred-on-symbolic").pixmap(12, 12)); m_plbl3->setPixmap(QIcon::fromTheme("ukui-starred-on-symbolic").pixmap(12, 12)); m_plbl4->setPixmap(QIcon::fromTheme("ukui-starred-on-symbolic").pixmap(12, 12)); m_plbl5->setPixmap(QIcon::fromTheme("ukui-starred-on-symbolic").pixmap(12, 12)); break; } } class KCommentPanelPrivate : public QObject, public ThemeController { Q_DECLARE_PUBLIC(KCommentPanel) Q_OBJECT public: KCommentPanelPrivate(KCommentPanel *parent); void changeTheme(); private: QLabel *m_pContentLabel; QLabel *m_pPicLabel; QLabel *m_pTimeLabel; QLabel *m_pNameLabel; StarWidget *m_pStarWidget; QColor m_color; KCommentPanel *q_ptr; }; KCommentPanel::KCommentPanel(QWidget *parent) : QWidget(parent) , d_ptr(new KCommentPanelPrivate(this)) { } void KCommentPanel::setIcon(const QIcon &icon) { Q_D(KCommentPanel); d->m_pPicLabel->setPixmap(icon.pixmap(50, 50)); } void KCommentPanel::setTime(const QString &str) { Q_D(KCommentPanel); d->m_pTimeLabel->setText(str); } void KCommentPanel::setName(const QString &str) { Q_D(KCommentPanel); d->m_pNameLabel->setText(str); } void KCommentPanel::setText(const QString &str) { Q_D(KCommentPanel); d->m_pContentLabel->setText(str); } void KCommentPanel::setGrade(StarLevel level) { Q_D(KCommentPanel); d->m_pStarWidget->setGrade(level); } void KCommentPanel::paintEvent(QPaintEvent *event) { Q_D(KCommentPanel); QPainter painter(this); painter.setRenderHint(QPainter::Antialiasing); // 反锯齿; painter.setPen(Qt::NoPen); painter.setBrush(d->m_color); QRect rect = this->rect(); rect.setWidth(rect.width()); rect.setHeight(rect.height()); int radius = ThemeController::getRadiusFromDT("kradius-normal"); if (radius == -1) radius = 6; painter.drawRoundedRect(rect, radius, radius); } KCommentPanelPrivate::KCommentPanelPrivate(KCommentPanel *parent) : q_ptr(parent) { Q_Q(KCommentPanel); QVBoxLayout *mainLayout = new QVBoxLayout(q); mainLayout->setContentsMargins(16, 16, 16, 16); QHBoxLayout *controlLayout = new QHBoxLayout; m_pPicLabel = new QLabel(q); m_pPicLabel->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); m_pPicLabel->setFixedSize(50, 50); controlLayout->addWidget(m_pPicLabel); QVBoxLayout *vLayout = new QVBoxLayout; vLayout->setSpacing(1); vLayout->setContentsMargins(0, 0, 0, 0); controlLayout->addLayout(vLayout); QHBoxLayout *hLayout = new QHBoxLayout; hLayout->setContentsMargins(0, 0, 0, 0); m_pNameLabel = new QLabel(q); m_pNameLabel->setAlignment(Qt::AlignBottom); m_pNameLabel->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); m_pTimeLabel = new QLabel(q); m_pTimeLabel->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); hLayout->addWidget(m_pNameLabel); hLayout->addStretch(); hLayout->addWidget(m_pTimeLabel); vLayout->addLayout(hLayout); hLayout = new QHBoxLayout; hLayout->setContentsMargins(0, 0, 0, 0); m_pStarWidget = new StarWidget(q); hLayout->addWidget(m_pStarWidget); hLayout->addStretch(); vLayout->addLayout(hLayout); m_pContentLabel = new QLabel(q); m_pContentLabel->setWordWrap(true); m_pContentLabel->setAlignment(Qt::AlignTop); m_pContentLabel->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); mainLayout->addLayout(controlLayout); mainLayout->addWidget(m_pContentLabel); mainLayout->addStretch(); changeTheme(); connect(m_gsetting, &QGSettings::changed, this, &KCommentPanelPrivate::changeTheme); } void KCommentPanelPrivate::changeTheme() { Q_Q(KCommentPanel); initThemeStyle(); if (ThemeController::themeMode() == LightTheme) { m_pTimeLabel->setStyleSheet("font-size:14px;color:#8C8C8C;"); m_pNameLabel->setStyleSheet("font-size:16px;font-weight:500;color:#262626;"); m_color = ThemeController::getCustomColorFromDT("kgray-2"); m_pContentLabel->setStyleSheet("color:#595959"); } else { m_pTimeLabel->setStyleSheet("font-size:14px;color:#737373;"); m_pNameLabel->setStyleSheet("font-size:16px;font-weight:500;color:#FFFFFF;"); m_color = ThemeController::getCustomColorFromDT("kgray-17"); m_pContentLabel->setStyleSheet("color:#D9D9D9"); } } } #include "kcommentpanel.moc" #include "moc_kcommentpanel.cpp" libkysdk-applications/kysdk-qtwidgets/src/kpasswordedit.cpp0000664000175000017500000003511515104543305023321 0ustar fengfeng/* * libkysdk-qtwidgets's Library * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #include "kpasswordedit.h" #include "ktoolbutton.h" #include "parmscontroller.h" #include "themeController.h" #include #include #include #include #include #include #include #include #include #include "accessinfohelper.h" namespace kdk { class KPasswordEditPrivate : public QObject, public ThemeController { Q_OBJECT Q_DECLARE_PUBLIC(KPasswordEdit) public: KPasswordEditPrivate(KPasswordEdit *parent); void adjustLayout(); void repaintIcon(); protected: void changeTheme(); private: KPasswordEdit *q_ptr; KToolButton *m_pEchoModeBtn; LoginState m_state; KToolButton *m_pLoadingBtn; KToolButton *m_pClearBtn; QWidget *m_pWidget; QHBoxLayout *m_pWidgetLayout; QTimer *m_pTimer; bool m_isLoading; bool m_hasFocus; bool m_useCustomPalette; int m_flashState; }; KPasswordEdit::KPasswordEdit(QWidget *parent) : QLineEdit(parent) , d_ptr(new KPasswordEditPrivate(this)) { Q_D(KPasswordEdit); d->m_pEchoModeBtn->setType(KToolButtonType::Flat); d->m_pClearBtn->setType(KToolButtonType::Flat); d->m_pLoadingBtn->setType(KToolButtonType::Flat); connect(d->m_pEchoModeBtn, &QToolButton::clicked, this, [=]() { if (echoMode() == QLineEdit::Password) setEchoMode(QLineEdit::Normal); else setEchoMode(QLineEdit::Password); d->repaintIcon(); }); connect(this, &QLineEdit::textChanged, this, [=]() { if (!text().isEmpty() && d->m_pClearBtn->isEnabled() && hasFocus()) { d->m_pClearBtn->show(); d->adjustLayout(); } else { d->m_pClearBtn->hide(); d->adjustLayout(); } }); connect(d->m_pClearBtn, &QPushButton::clicked, this, [=]() { this->clear(); }); connect(d->m_pTimer, &QTimer::timeout, this, [=]() { if (d->m_flashState < 7) d->m_flashState++; else d->m_flashState = 0; d->m_pLoadingBtn->setIcon(QIcon::fromTheme(QString("ukui-loading-%1.symbolic").arg(d->m_flashState))); }); connect(d->m_gsetting, &QGSettings::changed, d, &KPasswordEditPrivate::changeTheme); connect(Parmscontroller::self(), &Parmscontroller::modeChanged, this, [=]() { updateGeometry(); }); d->repaintIcon(); installEventFilter(this); setContextMenuPolicy(Qt::NoContextMenu); setFocusPolicy(Qt::StrongFocus); setAttribute(Qt::WA_InputMethodEnabled, false); d->changeTheme(); } void KPasswordEdit::setState(LoginState state) { Q_D(KPasswordEdit); d->m_state = state; auto palette = this->palette(); switch (d->m_state) { case Ordinary: palette.setBrush(QPalette::Highlight, ThemeController::getCustomColorFromDT("kbrand-normal")); setPalette(palette); break; case LoginSuccess: palette.setBrush(QPalette::Highlight, ThemeController::getCustomColorFromDT("ksuccess-normal")); setPalette(palette); break; case LoginFailed: palette.setBrush(QPalette::Highlight, ThemeController::getCustomColorFromDT("kerror-normal")); setPalette(palette); break; default: break; } } LoginState KPasswordEdit::state() { Q_D(KPasswordEdit); return d->m_state; } void KPasswordEdit::setLoading(bool flag) { Q_D(KPasswordEdit); d->m_isLoading = flag; if (flag) { d->m_pLoadingBtn->show(); d->m_pTimer->start(); QLineEdit::setEnabled(false); } else { d->m_pLoadingBtn->hide(); d->m_pTimer->stop(); QLineEdit::setEnabled(true); } d->adjustLayout(); } bool KPasswordEdit::isLoading() { Q_D(KPasswordEdit); return d->m_isLoading; } QString KPasswordEdit::placeholderText() { return QLineEdit::placeholderText(); } void KPasswordEdit::setPlaceholderText(QString &text) { QLineEdit::setPlaceholderText(text); } void KPasswordEdit::setClearButtonEnabled(bool enable) { Q_D(KPasswordEdit); d->m_pClearBtn->setEnabled(enable); } bool KPasswordEdit::isClearButtonEnabled() const { bool result = d_ptr->m_pClearBtn->isEnabled(); return result; } void KPasswordEdit::setEchoModeBtnVisible(bool enable) { Q_D(KPasswordEdit); d->m_pEchoModeBtn->setVisible(enable); d->adjustLayout(); } bool KPasswordEdit::echoModeBtnVisible() { Q_D(KPasswordEdit); return d->m_pEchoModeBtn->isVisible(); } void KPasswordEdit::setClearBtnVisible(bool enable) { Q_D(KPasswordEdit); d->m_pClearBtn->setEnabled(enable); d->adjustLayout(); } bool KPasswordEdit::clearBtnVisible() { Q_D(KPasswordEdit); return d->m_pClearBtn->isVisible(); } void KPasswordEdit::setEnabled(bool flag) { Q_D(KPasswordEdit); if (!flag) { d->m_pClearBtn->hide(); d->m_pLoadingBtn->hide(); } QLineEdit::setEnabled(flag); d->repaintIcon(); } void KPasswordEdit::setEchoMode(QLineEdit::EchoMode mode) { Q_D(KPasswordEdit); QLineEdit::setEchoMode(mode); d->repaintIcon(); } void KPasswordEdit::setUseCustomPalette(bool flag) { Q_D(KPasswordEdit); d->m_useCustomPalette = flag; } void KPasswordEdit::resizeEvent(QResizeEvent *event) { Q_D(KPasswordEdit); QLineEdit::resizeEvent(event); d->adjustLayout(); } bool KPasswordEdit::eventFilter(QObject *watched, QEvent *event) { Q_D(KPasswordEdit); if (watched == this) { if (event->type() == QEvent::FocusIn) { d->m_hasFocus = true; if (this->text().isEmpty()) d->m_pClearBtn->hide(); else { if (d->m_pClearBtn->isEnabled()) d->m_pClearBtn->show(); } d->adjustLayout(); d->changeTheme(); } if (event->type() == QEvent::FocusOut) { d->m_hasFocus = false; d->m_pClearBtn->hide(); d->adjustLayout(); d->changeTheme(); } } return QLineEdit::eventFilter(watched, event); } QSize KPasswordEdit::sizeHint() const { auto size = QLineEdit::sizeHint(); size.setHeight(Parmscontroller::parm(Parmscontroller::Parm::PM_PasswordEditHeight)); return size; } KPasswordEditPrivate::KPasswordEditPrivate(KPasswordEdit *parent) : q_ptr(parent) , m_useCustomPalette(false) { Q_Q(KPasswordEdit); m_flashState = 0; m_state = Ordinary; m_hasFocus = q->hasFocus(); m_isLoading = false; m_pTimer = new QTimer(this); m_pTimer->setInterval(100); q->QLineEdit::setEchoMode(QLineEdit::Password); QPalette btnPalette; btnPalette.setBrush(QPalette::Active, QPalette::Button, Qt::transparent); btnPalette.setBrush(QPalette::Inactive, QPalette::Button, Qt::transparent); btnPalette.setBrush(QPalette::Disabled, QPalette::Button, Qt::transparent); btnPalette.setBrush(QPalette::Active, QPalette::Highlight, Qt::transparent); btnPalette.setBrush(QPalette::Inactive, QPalette::Highlight, Qt::transparent); btnPalette.setBrush(QPalette::Disabled, QPalette::Highlight, Qt::transparent); m_pEchoModeBtn = new KToolButton(q); m_pEchoModeBtn->setAutoFillBackground(true); m_pEchoModeBtn->setPalette(btnPalette); m_pEchoModeBtn->setType(KToolButtonType::Background); m_pEchoModeBtn->setIconSize(QSize(16, 16)); m_pEchoModeBtn->setFixedSize(QSize(16, 16)); m_pEchoModeBtn->setFocusPolicy(Qt::NoFocus); m_pEchoModeBtn->setCursor(Qt::ArrowCursor); m_pEchoModeBtn->setIcon(QIcon::fromTheme("ukui-eye-hidden-symbolic")); m_pLoadingBtn = new KToolButton(q); m_pLoadingBtn->setAutoFillBackground(true); m_pLoadingBtn->setPalette(btnPalette); m_pLoadingBtn->setType(KToolButtonType::Background); m_pLoadingBtn->setIconSize(QSize(16, 16)); m_pLoadingBtn->setFixedSize(QSize(16, 16)); m_pLoadingBtn->setFocusPolicy(Qt::NoFocus); m_pLoadingBtn->setCursor(Qt::ArrowCursor); m_pLoadingBtn->setIcon(QIcon::fromTheme("ukui-loading-0")); m_pLoadingBtn->hide(); m_pClearBtn = new KToolButton(q); m_pClearBtn->setAutoFillBackground(true); m_pClearBtn->setPalette(btnPalette); m_pClearBtn->setType(KToolButtonType::Background); m_pClearBtn->setIconSize(QSize(16, 16)); m_pClearBtn->setFixedSize(QSize(16, 16)); m_pClearBtn->setFocusPolicy(Qt::NoFocus); m_pClearBtn->setCursor(Qt::ArrowCursor); m_pClearBtn->setIcon(QIcon::fromTheme("application-exit-symbolic")); m_pClearBtn->setVisible(false); m_pWidget = new QWidget(q); m_pWidgetLayout = new QHBoxLayout(m_pWidget); m_pWidgetLayout->setContentsMargins(0, 0, 0, 0); m_pWidgetLayout->setSpacing(5); if (ThemeController::systemLang()) m_pWidget->setLayoutDirection(Qt::RightToLeft); else m_pWidget->setLayoutDirection(Qt::LeftToRight); m_pWidgetLayout->addWidget(m_pLoadingBtn); m_pWidgetLayout->addWidget(m_pClearBtn); m_pWidgetLayout->addWidget(m_pEchoModeBtn); m_pWidgetLayout->addSpacing(5); m_pWidget->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); setParent(parent); KDK_ALL_INFO_FORMAT(m_pEchoModeBtn,""); KDK_ALL_INFO_FORMAT(m_pLoadingBtn,""); KDK_ALL_INFO_FORMAT(m_pClearBtn,""); KDK_ALL_INFO_FORMAT(m_pWidget,""); } void KPasswordEditPrivate::adjustLayout() { Q_Q(KPasswordEdit); int spacing = 5; int width = spacing; if (!m_pEchoModeBtn->isHidden()) width += (spacing + m_pEchoModeBtn->iconSize().width()); if (!m_pClearBtn->isHidden()) width += (spacing + m_pClearBtn->iconSize().width()); if (!m_pLoadingBtn->isHidden()) width += (spacing + m_pLoadingBtn->iconSize().width()); m_pWidget->setFixedSize(width, q->height()); if (ThemeController::systemLang()) { m_pWidget->move(spacing, 0); q->setTextMargins(m_pWidget->width(), 0, 0, 0); } else { m_pWidget->move(q->width() - m_pWidget->width(), 0); q->setTextMargins(0, 0, m_pWidget->width(), 0); } } void KPasswordEditPrivate::repaintIcon() { Q_Q(KPasswordEdit); if (ThemeController::themeMode() == LightTheme) { m_pClearBtn->setIcon(drawColoredPixmap(QIcon::fromTheme("application-exit-symbolic").pixmap(16, 16), ThemeController::getCustomColorFromDT("buttontext-active"))); if (q->echoMode() == QLineEdit::Password) m_pEchoModeBtn->setIcon(drawColoredPixmap(QIcon::fromTheme("ukui-eye-hidden-symbolic").pixmap(16, 16), ThemeController::getCustomColorFromDT("buttontext-active"))); else m_pEchoModeBtn->setIcon(drawColoredPixmap(QIcon::fromTheme("ukui-eye-display-symbolic").pixmap(16, 16), ThemeController::getCustomColorFromDT("buttontext-active"))); } else { m_pClearBtn->setIcon(drawColoredPixmap(QIcon::fromTheme("application-exit-symbolic").pixmap(16, 16), ThemeController::getCustomColorFromDT("buttontext-active"))); if (q->echoMode() == QLineEdit::Password) { if (q->isEnabled()) m_pEchoModeBtn->setIcon(drawColoredPixmap(QIcon::fromTheme("ukui-eye-hidden-symbolic").pixmap(16, 16), ThemeController::getCustomColorFromDT("buttontext-active"))); else m_pEchoModeBtn->setIcon(drawColoredPixmap(QIcon::fromTheme("ukui-eye-hidden-symbolic").pixmap(16, 16), ThemeController::getCustomColorFromDT("kgray-17"))); } else { if (q->isEnabled()) m_pEchoModeBtn->setIcon(drawColoredPixmap(QIcon::fromTheme("ukui-eye-display-symbolic").pixmap(16, 16), ThemeController::getCustomColorFromDT("buttontext-active"))); else m_pEchoModeBtn->setIcon(drawColoredPixmap(QIcon::fromTheme("ukui-eye-display-symbolic").pixmap(16, 16), ThemeController::getCustomColorFromDT("kgray-17"))); } } } void KPasswordEditPrivate::changeTheme() { Q_Q(KPasswordEdit); initThemeStyle(); if (m_useCustomPalette) return; repaintIcon(); QPalette palette = q->palette(); if (q->hasFocus()) { QColor color = ThemeController::getCustomColorFromDT("base-active"); palette.setBrush(QPalette::Button, color); if (ThemeController::themeMode() == LightTheme) palette.setBrush(QPalette::Text, ThemeController::getCustomColorFromDT("kgray-17")); else palette.setBrush(QPalette::Active, QPalette::Text, ThemeController::getCustomColorFromDT("kwhite")); q->setPalette(palette); } else { if (ThemeController::themeMode() == LightTheme) { palette.setBrush(QPalette::Active, QPalette::Button, ThemeController::getCustomColorFromDT("kgray-6")); palette.setBrush(QPalette::Inactive, QPalette::Button, ThemeController::getCustomColorFromDT("kgray-6")); palette.setBrush(QPalette::Disabled, QPalette::Button, ThemeController::getCustomColorFromDT("kgray-5")); palette.setBrush(QPalette::Active, QPalette::Text, QColor(140, 140, 140)); palette.setBrush(QPalette::Inactive, QPalette::Text, QColor(140, 140, 140)); palette.setBrush(QPalette::Disabled, QPalette::Text, ThemeController::getCustomColorFromDT("kgray-11")); q->setPalette(palette); } else { palette.setBrush(QPalette::Active, QPalette::Button, ThemeController::getCustomColorFromDT("kgray-16")); palette.setBrush(QPalette::Inactive, QPalette::Button, ThemeController::getCustomColorFromDT("kgray-16")); palette.setBrush(QPalette::Disabled, QPalette::Button, ThemeController::getCustomColorFromDT("kgray-17")); palette.setBrush(QPalette::Active, QPalette::Text, ThemeController::getCustomColorFromDT("kgray-13")); palette.setBrush(QPalette::Inactive, QPalette::Text, ThemeController::getCustomColorFromDT("kgray-13")); palette.setBrush(QPalette::Disabled, QPalette::Text, ThemeController::getCustomColorFromDT("kgray-15")); q->setPalette(palette); } } } } #include "kpasswordedit.moc" #include "moc_kpasswordedit.cpp" libkysdk-applications/kysdk-qtwidgets/src/knavigationtrail.cpp0000664000175000017500000001115515104543305024002 0ustar fengfeng/* * libkysdk-qtwidgets's Library * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhenyu Wang * */ #include "knavigationtrail.h" #include "kborderlessbutton.h" #include "kcrumb.h" #include "themeController.h" #include #include namespace kdk { class Q_DECL_HIDDEN KNavigationTrailPrivate : public QObject, public ThemeController { Q_OBJECT Q_DECLARE_PUBLIC(KNavigationTrail) public: KNavigationTrailPrivate(KNavigationTrail *parent); void updateLayout(); private: KNavigationTrail *q_ptr; KBorderlessButton *m_pLeftButton; KBorderlessButton *m_pRightButton; KCrumb *m_pCrumb; QHBoxLayout *m_pHLayout; ButtonPosition m_position; }; KNavigationTrail::KNavigationTrail(QWidget *parent) : QWidget(parent) , d_ptr(new KNavigationTrailPrivate(this)) { Q_D(KNavigationTrail); } KCrumb *KNavigationTrail::crumb() { Q_D(KNavigationTrail); return d->m_pCrumb; } void KNavigationTrail::setPosition(ButtonPosition type) { Q_D(KNavigationTrail); d->m_position = type; d->updateLayout(); } void KNavigationTrail::resizeEvent(QResizeEvent *event) { Q_D(KNavigationTrail); QWidget::resizeEvent(event); emit sizeChange(); } KNavigationTrailPrivate::KNavigationTrailPrivate(KNavigationTrail *parent) : q_ptr(parent) { Q_Q(KNavigationTrail); m_position = ButtonPosition::LeftOrRight; m_pHLayout = new QHBoxLayout(q); m_pCrumb = new KCrumb(); m_pLeftButton = new KBorderlessButton(); m_pLeftButton->setIcon(QIcon::fromTheme("go-previous.symbolic")); m_pRightButton = new KBorderlessButton(); m_pRightButton->setIcon(QIcon::fromTheme("go-next.symbolic")); m_pHLayout->addWidget(m_pLeftButton); m_pHLayout->addWidget(m_pRightButton); m_pHLayout->addWidget(m_pCrumb); connect(m_pCrumb, &KCrumb::currentChanged, this, [=](int index) { if (index == 0) { m_pLeftButton->setEnabled(false); if (!m_pRightButton->isEnabled()) m_pRightButton->setEnabled(true); } else if (index == m_pCrumb->count() - 1) { m_pRightButton->setEnabled(false); if (!m_pLeftButton->isEnabled()) m_pLeftButton->setEnabled(true); } else { if (!m_pLeftButton->isEnabled()) m_pLeftButton->setEnabled(true); if (!m_pRightButton->isEnabled()) m_pRightButton->setEnabled(true); } }); connect(m_pLeftButton, &KBorderlessButton::clicked, this, [=] { // m_pCrumb->leftScroll(); m_pCrumb->setCurrentIndex(m_pCrumb->currentIndex() - 1); }); connect(m_pRightButton, &KBorderlessButton::clicked, this, [=] { // m_pCrumb->rightScroll(); m_pCrumb->setCurrentIndex(m_pCrumb->currentIndex() + 1); }); } void KNavigationTrailPrivate::updateLayout() { Q_Q(KNavigationTrail); QLayoutItem *child; while ((child = m_pHLayout->takeAt(0)) != 0) { // 删除Stretch(弹簧)等布局 if (child->spacerItem()) { m_pHLayout->removeItem(child); continue; } // 删除布局 m_pHLayout->removeWidget(child->widget()); child->widget()->setParent(nullptr); delete child; child = nullptr; } switch (m_position) { case ButtonPosition::LeftPosition: m_pHLayout->addWidget(m_pLeftButton); m_pHLayout->addWidget(m_pRightButton); m_pHLayout->addWidget(m_pCrumb); break; case ButtonPosition::LeftOrRight: m_pHLayout->addWidget(m_pLeftButton); m_pHLayout->addWidget(m_pCrumb); m_pHLayout->addWidget(m_pRightButton); break; case ButtonPosition::RightPosition: m_pHLayout->addWidget(m_pCrumb); m_pHLayout->addWidget(m_pLeftButton); m_pHLayout->addWidget(m_pRightButton); break; default: break; } } } #include "knavigationtrail.moc" #include "moc_knavigationtrail.cpp" libkysdk-applications/kysdk-qtwidgets/src/kprogresslabel.h0000664000175000017500000000361215104543305023117 0ustar fengfeng/* * libkysdk-qtwidgets's Library * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhenyu Wang * */ #ifndef MYWIDGET_H #define MYWIDGET_H #include #include #include #include #include #include #include namespace kdk { /** * @defgroup ProgressModule * @since 2.5.2.0 * { */ class KProgressLabelPrivate; class KProgressLabel : public QWidget { Q_OBJECT public: KProgressLabel(QWidget *parent = nullptr); ~KProgressLabel(); public: /** * @brief 设置第二行文本和第一行文本 * @param list1 * @param list2 */ void setStringList(QStringList list1, QStringList list2); /** * @brief setStringList * @param list1 */ void setStringList(QStringList list1); /** * @brief 设置当前进度 * @param index */ void setCurrentIndex(int index); /** * @brief 获取当前进度 * @return */ int currentIndex(); /** * @brief 设置圆形label的大小 * @param size */ void setCircleSize(QSize size); private: Q_DECLARE_PRIVATE(KProgressLabel) KProgressLabelPrivate *const d_ptr; }; } #endif // MYWIDGET_H libkysdk-applications/kysdk-qtwidgets/src/klabel.h0000664000175000017500000001042715104543305021334 0ustar fengfeng/* * libkysdk-qtwidgets's Library * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhenyu Wang * */ #ifndef KLABEL_H #define KLABEL_H #include "gui_g.h" #include namespace kdk { /** * @defgroup LabelModule * { */ enum KLabelType { NormalType, DataType, CircleType }; class KLabelPrivate; /** * @brief 继承qlabel * @since 2.4.1.0 */ class GUI_EXPORT KLabel : public QLabel { Q_OBJECT public: KLabel(QWidget *parent = nullptr); /** * @brief 设置label类型,NormalType和IconAndTextType * @param type */ void setLabelType(KLabelType type = KLabelType::DataType); /** * @brief 设置是否启用文本/图标高亮色 * @param flag */ void setDataHightColor(bool flag); /** * @brief 设置图标pixmap * @param pixmap */ void setPixmap(const QPixmap &pixmap); /** * @brief 设置图标icon * @param icon * @since 2.5.2.0-0k0.3 */ void setPixmap(QIcon icon, int width, int height); /** * @brief 获取图标 * @return */ const QPixmap *pixmap() const; /** * @brief 设置文本 * @since 2.5.2.0 * @param str */ void setText(const QString &str); /** * @brief 获取文本 * @since 2.5.2.0 * @return */ QString text(); /** * @brief 设置背景颜色 * @param flag */ void setBackgroundColor(bool flag, QColor color = Qt::white); /** * @brief 设置是否启用背景高亮色 * @since 2.5.2.0 * @param flag */ void setHighlightBackground(bool flag); /** * @brief 设置圆角 * @param bottomLeft * @param topLeft * @param topRight * @param bottomRight */ void setBorderRadius(int bottomLeft, int topLeft, int topRight, int bottomRight); /** * @brief 设置圆角 * @param radius */ void setBorderRadius(int radius); /** * @brief 设置是否启用换行 * @since 2.5.2.0 * @param flag */ void setWordWrap(bool flag); /** * @brief 获取是否启用换行 * @since 2.5.2.0 * @return */ bool wordWrap(); /** * @brief 设置字体颜色 * @param color * @since 2.5.2.0 */ void setFontColor(QColor color); /** * @brief 设置字体颜色colorRole * @param role * @since 3.0.1.0 */ void setFontColorRole(QPalette::ColorRole role); // lightlabel /** * @brief 设置三态是否开启 * @param flag * @since 3.0.1.0 */ void setTristate(bool flag); // tristatelabel /** * @brief 获取三态是否开启 * @return * @since 3.0.1.0 */ bool isTristate(); Q_SIGNALS: /** * @brief 鼠标进入信号 * @since 3.0.1.0 */ void enterWidget(); // iconlabel /** * @brief 鼠标离开信号 * @since 3.0.1.0 */ void leaveWidget(); /** * @brief 鼠标点击信号 * @param clicked * @since 3.0.1.0 */ void clicked(bool clicked); // eyelabel /** * @brief 鼠标双击信号 * @since 3.0.1.0 */ void doubleClicked(); protected: void paintEvent(QPaintEvent *event); QSize sizeHint() const; void resizeEvent(QResizeEvent *event); virtual void enterEvent(QEnterEvent *event); virtual void leaveEvent(QEvent *event); void mousePressEvent(QMouseEvent *event); void mouseReleaseEvent(QMouseEvent *event); void mouseDoubleClickEvent(QMouseEvent *event); private: Q_DECLARE_PRIVATE(KLabel) KLabelPrivate *const d_ptr; }; } #endif // KLABEL_H libkysdk-applications/kysdk-qtwidgets/src/kloopplaypage.cpp0000664000175000017500000002341315104543305023303 0ustar fengfeng/* * libkysdk-qtwidgets's Library * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhenyu Wang * */ #include "kloopplaypage.h" #include "themeController.h" #include #include #include #include #include #include #include #include namespace kdk { class Q_DECL_HIDDEN CircleButton : public QPushButton { Q_OBJECT public: enum ButtonType { CircleType, NormalType }; CircleButton(QWidget *parent = nullptr); void setButtonType(ButtonType type); protected: void paintEvent(QPaintEvent *event); private: ButtonType m_type; }; class Q_DECL_HIDDEN Widget : public QWidget { Q_OBJECT public: Widget(QWidget *parent = nullptr); Q_SIGNALS: void leftClick(); protected: void mousePressEvent(QMouseEvent *event); void paintEvent(QPaintEvent *event); }; class Q_DECL_HIDDEN KLoopPlayPagePrivate : public QObject, public ThemeController { Q_OBJECT Q_DECLARE_PUBLIC(KLoopPlayPage) public: KLoopPlayPagePrivate(KLoopPlayPage *parent); void updateWidget(int i); void updateButton(); void updateShowPosition(); private: KLoopPlayPage *q_ptr; Widget *m_pWidget1; Widget *m_pWidget2; Widget *m_pWidget3; QWidget *m_pScrollWidget; QHBoxLayout *m_pWidgetLayout; QHBoxLayout *m_pButtonLayout; QVBoxLayout *m_pLayout; QList m_WidgetList; CircleButton *m_pCircleButton; QList m_ButtonList; QScrollArea *m_pScrollArea; int m_index; int m_spacing; int m_timer; QTimer *m_pTimer; }; KLoopPlayPagePrivate::KLoopPlayPagePrivate(KLoopPlayPage *parent) : q_ptr(parent) , m_index(0) , m_spacing(24) , m_timer(3000) { Q_Q(KLoopPlayPage); m_pLayout = new QVBoxLayout(q); m_pLayout->setSpacing(16); m_pScrollWidget = new QWidget(); m_pScrollWidget->setContentsMargins(0, 0, 0, 0); m_pScrollArea = new QScrollArea(q); m_pScrollArea->setFrameStyle(QFrame::NoFrame); m_pScrollArea->setWidgetResizable(true); m_pScrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); m_pScrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); m_pScrollArea->setWidget(m_pScrollWidget); m_pWidgetLayout = new QHBoxLayout(m_pScrollWidget); m_pWidgetLayout->setSpacing(0); m_pButtonLayout = new QHBoxLayout(q); m_pButtonLayout->setSpacing(6); m_pLayout->addWidget(m_pScrollArea); m_pLayout->addLayout(m_pButtonLayout); m_pTimer = new QTimer(q); m_pTimer->start(m_timer); connect(m_pTimer, &QTimer::timeout, this, [=] { q->setCurrentWidget(q->currentWidget() + 1); }); } void KLoopPlayPagePrivate::updateWidget(int i) { Q_Q(KLoopPlayPage); if (m_WidgetList.count() < 3) return; QLayoutItem *child; while ((child = m_pWidgetLayout->takeAt(0)) != 0) { // 删除Stretch(弹簧)等布局 if (child->spacerItem()) { m_pWidgetLayout->removeItem(child); continue; } // 删除布局 m_pWidgetLayout->removeWidget(child->widget()); child->widget()->setParent(nullptr); delete child; child = nullptr; } int prev; int next; if (i == 0) { prev = m_WidgetList.count() - 1; next = i + 1; } else if (i == m_WidgetList.count() - 1) { prev = i - 1; next = 0; } else { prev = i - 1; next = i + 1; } m_pWidget1 = new Widget(); m_pWidget2 = new Widget(); m_pWidget3 = new Widget(); m_pWidgetLayout->addWidget(m_pWidget1); m_pWidgetLayout->addSpacing(m_spacing); m_pWidgetLayout->addWidget(m_pWidget2); m_pWidgetLayout->addSpacing(m_spacing); m_pWidgetLayout->addWidget(m_pWidget3); m_pWidgetLayout->setContentsMargins(8, 8, 8, 18); QHBoxLayout *w1layout = new QHBoxLayout(m_pWidget1); w1layout->setContentsMargins(0, 0, 0, 0); w1layout->setSpacing(0); w1layout->addWidget(m_WidgetList.at(prev)); QHBoxLayout *w2layout = new QHBoxLayout(m_pWidget2); w2layout->setContentsMargins(0, 0, 0, 0); w2layout->setSpacing(0); w2layout->addWidget(m_WidgetList.at(i)); QHBoxLayout *w3layout = new QHBoxLayout(m_pWidget3); w3layout->setContentsMargins(0, 0, 0, 0); w3layout->setSpacing(0); w3layout->addWidget(m_WidgetList.at(next)); updateShowPosition(); connect(m_pWidget1, &Widget::leftClick, q, [=] { q->setCurrentWidget(prev); m_pTimer->start(m_timer); emit q->leftClick(); }); connect(m_pWidget2, &Widget::leftClick, q, [=] { emit q->centerClick(); }); connect(m_pWidget3, &Widget::leftClick, q, [=] { q->setCurrentWidget(next); m_pTimer->start(m_timer); emit q->rightClick(); }); updateButton(); } void KLoopPlayPagePrivate::updateButton() { Q_Q(KLoopPlayPage); m_ButtonList.clear(); QLayoutItem *child; while ((child = m_pButtonLayout->takeAt(0)) != 0) { // 删除Stretch(弹簧)等布局 if (child->spacerItem()) { m_pButtonLayout->removeItem(child); continue; } // 删除布局 m_pButtonLayout->removeWidget(child->widget()); child->widget()->setParent(nullptr); delete child; child = nullptr; } m_pButtonLayout->addStretch(); m_pButtonLayout->setSpacing(8); for (int i = 0; i < m_WidgetList.count(); i++) { CircleButton *circleButton = new CircleButton(); m_ButtonList.append(circleButton); m_pCircleButton = new CircleButton(); if (i == q->currentWidget()) { m_pCircleButton->setFixedSize(12, 6); m_pCircleButton->setButtonType(CircleButton::NormalType); } else { m_pCircleButton->setFixedSize(6, 6); m_pCircleButton->setButtonType(CircleButton::CircleType); } m_pButtonLayout->addWidget(m_pCircleButton); connect(m_pCircleButton, &CircleButton::clicked, this, [=] { q->setCurrentWidget(i); m_pTimer->start(m_timer); }); } m_pButtonLayout->addStretch(); } void KLoopPlayPagePrivate::updateShowPosition() { Q_Q(KLoopPlayPage); int viewportWidth = m_pScrollArea->viewport()->width(); int scrollValue = (m_pScrollWidget->width() - viewportWidth) / 2; if (scrollValue < 0) scrollValue = 0; m_pScrollArea->horizontalScrollBar()->setValue(scrollValue); } KLoopPlayPage::KLoopPlayPage(QWidget *parent) : QWidget(parent) , d_ptr(new KLoopPlayPagePrivate(this)) { Q_D(KLoopPlayPage); } void KLoopPlayPage::addWidget(QWidget *widget) { Q_D(KLoopPlayPage); if (!d->m_WidgetList.contains(widget)) d->m_WidgetList.append(widget); d->updateWidget(d->m_index); } void KLoopPlayPage::removeWidget(QWidget *widget) { Q_D(KLoopPlayPage); if (d->m_WidgetList.contains(widget)) d->m_WidgetList.removeOne(widget); d->updateWidget(d->m_index); } void KLoopPlayPage::setCurrentWidget(int index) { Q_D(KLoopPlayPage); if (index >= d->m_WidgetList.count()) d->m_index = 0; else if (index < 0) d->m_index = d->m_WidgetList.count() - 1; else d->m_index = index; d->updateWidget(d->m_index); } int KLoopPlayPage::currentWidget() { Q_D(KLoopPlayPage); return d->m_index; } void KLoopPlayPage::setWidgetSpacing(int spacing) { Q_D(KLoopPlayPage); d->m_spacing = spacing; } void KLoopPlayPage::setLoopTime(int time) { Q_D(KLoopPlayPage); d->m_timer = time; d->m_pTimer->start(time); } void KLoopPlayPage::resizeEvent(QResizeEvent *event) { Q_D(KLoopPlayPage); QWidget::resizeEvent(event); d->updateShowPosition(); } void KLoopPlayPage::paintEvent(QPaintEvent *event) { Q_D(KLoopPlayPage); QWidget::paintEvent(event); } void KLoopPlayPage::showEvent(QShowEvent *event) { Q_D(KLoopPlayPage); QWidget::showEvent(event); d->updateShowPosition(); } Widget::Widget(QWidget *parent) { } void Widget::mousePressEvent(QMouseEvent *event) { if (event->button() == Qt::MouseButton::LeftButton) { emit leftClick(); } return QWidget::mousePressEvent(event); } void Widget::paintEvent(QPaintEvent *event) { QPainter painter(this); painter.setBrush(Qt::NoBrush); painter.setPen(Qt::NoPen); painter.drawRect(rect()); } CircleButton::CircleButton(QWidget *parent) { m_type = ButtonType::CircleType; } void CircleButton::setButtonType(CircleButton::ButtonType type) { m_type = type; update(); } void CircleButton::paintEvent(QPaintEvent *event) { QPainter painter(this); painter.setRenderHint(QPainter::Antialiasing); painter.setRenderHint(QPainter::SmoothPixmapTransform); painter.setPen(Qt::NoPen); QColor color(18, 18, 18); color.setAlphaF(0.2); painter.setBrush(color); switch (m_type) { case ButtonType::CircleType: painter.drawEllipse(rect()); break; case ButtonType::NormalType: painter.drawRoundedRect(rect(), 3, 3); break; default: break; } } } #include "kloopplaypage.moc" #include "moc_kloopplaypage.cpp" libkysdk-applications/kysdk-qtwidgets/src/ksecuritylevelbar.h0000664000175000017500000000342315104543305023637 0ustar fengfeng/* * libkysdk-qtwidgets's Library * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #ifndef KSECURITYLEVELBAR_H #define KSECURITYLEVELBAR_H #include "gui_g.h" #include namespace kdk { /** @defgroup MessageAlertModule * @{ */ /** * @brief 分为三个安全等级 * @since 1.0.0 */ enum SecurityLevel { Low, Medium, High }; class KSecurityLevelBarPrivate; /** * @brief 密码安全等级提示条,支持三个安全等级 */ class GUI_EXPORT KSecurityLevelBar : public QWidget { Q_OBJECT public: explicit KSecurityLevelBar(QWidget *parent = nullptr); /** * @brief 设置安全等级 * @param level */ void setSecurityLevel(SecurityLevel level); /** * @brief 获取安全等级 * @return */ SecurityLevel securityLevel(); protected: void paintEvent(QPaintEvent *event); private: Q_DECLARE_PRIVATE(KSecurityLevelBar) KSecurityLevelBarPrivate *const d_ptr; }; } /** * @example testsecuritylevelbar/widget.h * @example testsecuritylevelbar/widget.cpp * @} */ #endif // KSECURITYLEVELBAR_H libkysdk-applications/kysdk-qtwidgets/src/kballontip.cpp0000664000175000017500000002446115104543305022577 0ustar fengfeng/* * libkysdk-qtwidgets's Library * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #include "kballontip.h" #include "themeController.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "accessinfohelper.h" namespace kdk { class KBallonTipPrivate : public QObject, public ThemeController { Q_DECLARE_PUBLIC(KBallonTip) Q_OBJECT public: KBallonTipPrivate(KBallonTip *parent); void adjustStyle(); void setAccessInfo(); protected: void changeTheme(); private: KBallonTip *q_ptr; QLabel *m_pContentLabel; QLabel *m_pIconLabel; TipType m_type; QIcon m_icon; QPixmap m_variablePixmap; QPixmap m_pixmap; QColor m_color; QHBoxLayout *m_pLayout; QVBoxLayout *m_pVLayout; int m_time; QGraphicsDropShadowEffect *m_pShadow_effect; QTimer *m_pTimer; int m_flashState; }; KBallonTip::KBallonTip(QWidget *parent) : QWidget(parent) , d_ptr(new KBallonTipPrivate(this)) { Q_D(KBallonTip); setAttribute(Qt::WA_TranslucentBackground); setWindowFlag(Qt::ToolTip); setFixedWidth(544); d->m_pVLayout = new QVBoxLayout(this); d->m_pLayout = new QHBoxLayout(); d->m_pLayout->setSpacing(12); this->setContentsMargins(24, 18, 24, 18); d->m_pContentLabel = new QLabel(this); // d->m_pContentLabel->setWordWrap(true); // 设置具体阴影 d->m_pShadow_effect = new QGraphicsDropShadowEffect(this); d->m_pShadow_effect->setOffset(0, 0); // 阴影颜色 d->m_pShadow_effect->setColor(ThemeController::getCustomColorFromDT("text-disable")); // 阴影半径 if (ThemeController::themeMode() == LightTheme) d->m_pShadow_effect->setBlurRadius(15); else d->m_pShadow_effect->setBlurRadius(0); this->setGraphicsEffect(d->m_pShadow_effect); d->m_pIconLabel = new QLabel(this); QVBoxLayout *vLayout = new QVBoxLayout; vLayout->addWidget(d->m_pIconLabel); // vLayout->addStretch(); d->m_pLayout->addLayout(vLayout); d->m_pLayout->addWidget(d->m_pContentLabel); d->m_pLayout->setAlignment(Qt::AlignVCenter); d->m_type = TipType::Nothing; d->m_pVLayout->addStretch(); d->m_pVLayout->addLayout(d->m_pLayout); d->m_pVLayout->addStretch(); d->adjustStyle(); d->m_pVLayout->setSizeConstraint(QLayout::SizeConstraint::SetFixedSize); if (ThemeController::systemFontSize() > 11) vLayout->setContentsMargins(0, (ThemeController::systemFontSize() - 11), 0, 0); else vLayout->setContentsMargins(0, 0, 0, 0); connect(d->m_gsetting, &QGSettings::changed, this, [=]() { if (ThemeController::themeMode() == LightTheme) d->m_pShadow_effect->setBlurRadius(15); else d->m_pShadow_effect->setBlurRadius(0); }); connect(d->m_gsetting, &QGSettings::changed, this, [=](const QString &key) { if (key.contains("systemFontSize")) if (ThemeController::systemFontSize() > 11) vLayout->setContentsMargins(0, (ThemeController::systemFontSize() - 11), 0, 0); else vLayout->setContentsMargins(0, 0, 0, 0); }); connect(d->m_pTimer, &QTimer::timeout, this, [=]() { if (d->m_flashState < 7) d->m_flashState++; else d->m_flashState = 0; if (ThemeController::themeMode() == LightTheme) { d->m_pIconLabel->setPixmap(QIcon::fromTheme(QString("ukui-loading-%1.symbolic").arg(d->m_flashState)).pixmap(22, 22)); } else { d->m_pIconLabel->setPixmap(ThemeController::drawColoredPixmap(QIcon::fromTheme(QString("ukui-loading-%1.symbolic").arg(d->m_flashState)).pixmap(22, 22), ThemeController::getCustomColorFromDT("kwhite"))); } }); d->setAccessInfo(); } KBallonTip::KBallonTip(const QString &content, const TipType &type, QWidget *parent) : KBallonTip(parent) { Q_D(KBallonTip); d->m_pContentLabel->setText(content); d->m_type = type; d->adjustStyle(); setAttribute(Qt::WA_TranslucentBackground); } void KBallonTip::showInfo() { Q_D(KBallonTip); show(); QTimer *timer = new QTimer(this); timer->start(d->m_time); timer->setSingleShot(true); connect(timer, SIGNAL(timeout()), this, SLOT(onTimeupDestroy())); } void KBallonTip::setTipType(const TipType &type) { Q_D(KBallonTip); d->m_type = type; d->adjustStyle(); } TipType KBallonTip::tipType() { Q_D(KBallonTip); return d->m_type; } void KBallonTip::setText(const QString &text) { Q_D(KBallonTip); d->m_pContentLabel->setText(text); } QString KBallonTip::text() { Q_D(KBallonTip); return d->m_pContentLabel->text(); } void KBallonTip::setContentsMargins(int left, int top, int right, int bottom) { Q_D(KBallonTip); d->m_pLayout->setContentsMargins(left, top, right, bottom); repaint(); } void KBallonTip::setContentsMargins(const QMargins &margins) { Q_D(KBallonTip); d->m_pLayout->setContentsMargins(margins); repaint(); } void KBallonTip::setTipTime(int my_time) { Q_D(KBallonTip); d->m_time = my_time; } QHBoxLayout *KBallonTip::hBoxLayout() { Q_D(KBallonTip); return d->m_pLayout; } void KBallonTip::setVariableIcon(QIcon icon) { Q_D(KBallonTip); d->m_variablePixmap = icon.pixmap(22, 22); update(); } QPixmap KBallonTip::variableIcon() { Q_D(KBallonTip); return d->m_variablePixmap; } void KBallonTip::onTimeupDestroy() { this->close(); } void KBallonTip::paintEvent(QPaintEvent *event) { Q_D(KBallonTip); // bug 173714 173165 adjustSize(); d->m_pShadow_effect->setColor(ThemeController::getCustomColorFromDT("text-disable")); QPainter painter(this); painter.setRenderHint(QPainter::Antialiasing); // 反锯齿; auto color = ThemeController::getCustomColorFromDT("kline-window-inactive"); QPen pen; pen.setColor(color); pen.setWidthF(0.2); painter.setPen(pen); painter.setBrush(ThemeController::getCustomColorFromDT("window-active")); QRect rect = this->rect(); if (!mask().isNull()) clearMask(); painter.setBrush(ThemeController::getCustomColorFromDT("window-active")); int radius = ThemeController::getRadiusFromDT("kradius-normal"); if (radius == -1) radius = 6; painter.drawRoundedRect(rect.adjusted(8, 8, -8, -8), radius, radius); if (!d->m_variablePixmap.isNull()) { if (ThemeController::isPixmapPureColor(d->m_variablePixmap)) { if (ThemeController::themeMode() == LightTheme) d->m_pixmap = d->m_variablePixmap; else d->m_pixmap = ThemeController::drawColoredPixmap(d->m_variablePixmap, Qt::white); } } d->adjustStyle(); } KBallonTipPrivate::KBallonTipPrivate(KBallonTip *parent) : q_ptr(parent) { Q_Q(KBallonTip); m_pTimer = new QTimer(this); m_pTimer->setInterval(100); m_time = 1000; setParent(parent); connect(m_gsetting, &QGSettings::changed, this, [=]() { changeTheme(); }); } void KBallonTipPrivate::adjustStyle() { Q_Q(KBallonTip); switch (m_type) { case TipType::Nothing: m_icon = QIcon(); m_pIconLabel->setPixmap(m_icon.pixmap(22, 22)); m_pIconLabel->hide(); if (m_pTimer->isActive()) m_pTimer->stop(); break; case TipType::Normal: // m_icon = QIcon::fromTheme("ukui-dialog-success"); m_icon = QIcon::fromTheme("ukui-dialog-success", QIcon::fromTheme("emblem-default")); m_pIconLabel->setPixmap(m_icon.pixmap(22, 22)); m_pIconLabel->show(); if (m_pTimer->isActive()) m_pTimer->stop(); break; case TipType::Info:; m_icon = QIcon::fromTheme("dialog-info"); m_pIconLabel->setPixmap(m_icon.pixmap(22, 22)); m_pIconLabel->show(); if (m_pTimer->isActive()) m_pTimer->stop(); break; case TipType::Warning: m_icon = QIcon::fromTheme("dialog-warning"); m_pIconLabel->setPixmap(m_icon.pixmap(22, 22)); m_pIconLabel->show(); if (m_pTimer->isActive()) m_pTimer->stop(); break; case TipType::Error: m_icon = QIcon::fromTheme("dialog-error"); m_pIconLabel->setPixmap(m_icon.pixmap(22, 22)); m_pIconLabel->show(); if (m_pTimer->isActive()) m_pTimer->stop(); break; case TipType::Variable: m_pIconLabel->setPixmap(m_pixmap); m_pIconLabel->show(); if (m_pTimer->isActive()) m_pTimer->stop(); break; case TipType::Loading: if (!m_pTimer->isActive()) { m_pTimer->start(); m_pIconLabel->show(); } break; default: break; } m_pIconLabel->setFixedSize(22, 22); // m_pContentLabel->setAlignment(Qt::AlignLeft); } void KBallonTipPrivate::setAccessInfo() { Q_Q(KBallonTip); KDK_ALL_INFO_FORMAT(m_pContentLabel,""); KDK_ALL_INFO_FORMAT(m_pIconLabel,""); KDK_OBJ_INFO_FORMAT(m_pShadow_effect); } void KBallonTipPrivate::changeTheme() { Q_Q(KBallonTip); m_pShadow_effect->setOffset(0, 0); // 阴影颜色 m_pShadow_effect->setColor(ThemeController::getCustomColorFromDT("text-disable")); // 阴影半径 if (ThemeController::themeMode() == LightTheme) { m_pShadow_effect->setBlurRadius(15); } else m_pShadow_effect->setBlurRadius(0); q->setGraphicsEffect(m_pShadow_effect); } } #include "kballontip.moc" #include "moc_kballontip.cpp" libkysdk-applications/kysdk-qtwidgets/src/kcolorcombobox.h0000664000175000017500000000464315104543305023127 0ustar fengfeng/* * libkysdk-qtwidgets's Library * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #ifndef KCOLORCOMBOBOX_H #define KCOLORCOMBOBOX_H #include "gui_g.h" #include #include #include namespace kdk { /** * @defgroup ContainerModule */ class KColorComboBoxPrivate; /** * @brief 颜色选择框 * @since 2.0.2.1 */ class GUI_EXPORT KColorComboBox : public QComboBox { Q_OBJECT public: /** * @brief 指定显示样式,圆形或者圆角矩形 */ enum ComboType { Circle, RoundedRect }; explicit KColorComboBox(QWidget *parent = nullptr); /** * @brief 以列表形式添加颜色选项 * @param list */ void setColorList(const QList &list); /** * @brief 获取颜色列表 * @return */ QList colorList(); /** * @brief 添加颜色选项 * @param color */ void addColor(const QColor &color); /** * @brief 设置显示样式 * @param type */ void setComboType(const ComboType &type); /** * @brief 获取显示样式 * @return */ ComboType comboType(); /** * @brief 设置item尺寸 * @param size */ void setPopupItemSize(const QSize &size); /** * @brief 返回item尺寸 * @return */ QSize popupItemSzie(); Q_SIGNALS: void activated(const QColor &color); void currentColorChanged(const QColor &color); void highlighted(const QColor &color); protected: void paintEvent(QPaintEvent *event) override; void resizeEvent(QResizeEvent *event) override; private: Q_DECLARE_PRIVATE(KColorComboBox) KColorComboBoxPrivate *const d_ptr; }; } #endif // KCOLORCOMBOBOX_H libkysdk-applications/kysdk-qtwidgets/src/klistviewdelegate.h0000664000175000017500000000340415104543305023613 0ustar fengfeng/* * libkysdk-qtwidgets's Library * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhenyu Wang * */ #ifndef KLISTVIEWDELEGATE_H #define KLISTVIEWDELEGATE_H #include "themeController.h" #include #include #include #include namespace kdk { /** * @defgroup ListViewModule */ class KListViewDelegatePrivate; /** * @brief 配合KListview可以提供一个图片两行文字的显示效果,若只有一行文字,则对于 icon 居中显示 。 * @since 1.2.0 */ class KListViewDelegate : public QStyledItemDelegate, public ThemeController { Q_OBJECT public: KListViewDelegate(QAbstractItemView *parent); ~KListViewDelegate(); protected: void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override; // 重写绘制事件 virtual QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const; private: Q_DECLARE_PRIVATE(KListViewDelegate); KListViewDelegatePrivate *const d_ptr; }; } #endif // KLISTVIEWDELEGATE_H libkysdk-applications/kysdk-qtwidgets/src/kiconbar.cpp0000664000175000017500000001746015104543305022231 0ustar fengfeng/* * libkysdk-qtwidgets's Library * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #include "kiconbar.h" #include "parmscontroller.h" #include "themeController.h" #include #include #include #include #include "accessinfohelper.h" namespace kdk { class KIconBarPrivate : public QObject, public ThemeController { Q_OBJECT Q_DECLARE_PUBLIC(KIconBar) public: KIconBarPrivate(KIconBar *parent); void elideWidgetName(); protected: void changeTheme(); void changeIconStyle(); bool eventFilter(QObject *watched, QEvent *event); private: KIconBar *q_ptr; QLabel *m_pIconLabel; QLabel *m_pNameLabel; QHBoxLayout *m_pMainLayout; QString m_IconName; QString m_widgetName; QColor inactiveColor; }; KIconBar::KIconBar(QWidget *parent) : QFrame(parent) , d_ptr(new KIconBarPrivate(this)) { Q_D(KIconBar); setObjectName("IconBar"); setFixedHeight(Parmscontroller::parm(Parmscontroller::Parm::PM_IconbarHeight)); connect(Parmscontroller::self(), &Parmscontroller::modeChanged, this, [=]() { setFixedHeight(Parmscontroller::parm(Parmscontroller::Parm::PM_IconbarHeight)); d->m_pIconLabel->setPixmap(QIcon::fromTheme(d->m_IconName).pixmap(QSize(Parmscontroller::parm(Parmscontroller::Parm::PM_IconBarIconSize), Parmscontroller::parm(Parmscontroller::Parm::PM_IconBarIconSize)))); updateGeometry(); }); } KIconBar::KIconBar(const QString &iconName, const QString &text, QWidget *parent) : KIconBar(parent) { setIcon(iconName); setWidgetName(text); } KIconBar::~KIconBar() { } void KIconBar::setIcon(const QString &iconName) { Q_D(KIconBar); if (iconName.isEmpty()) return; if (!d->m_pIconLabel) return; d->m_IconName = iconName; d->m_pIconLabel->setPixmap(QIcon::fromTheme(iconName).pixmap(QSize(Parmscontroller::parm(Parmscontroller::Parm::PM_IconBarIconSize), Parmscontroller::parm(Parmscontroller::Parm::PM_IconBarIconSize)))); setWindowIcon(QIcon::fromTheme(iconName).pixmap(QSize(Parmscontroller::parm(Parmscontroller::Parm::PM_IconBarIconSize), Parmscontroller::parm(Parmscontroller::Parm::PM_IconBarIconSize)))); } void KIconBar::setIcon(const QIcon &icon) { Q_D(KIconBar); if (!d->m_pIconLabel) return; d->m_pIconLabel->setPixmap(icon.pixmap(QSize(Parmscontroller::parm(Parmscontroller::Parm::PM_IconBarIconSize), Parmscontroller::parm(Parmscontroller::Parm::PM_IconBarIconSize)))); d->m_IconName = icon.name(); setWindowIcon(icon.pixmap(QSize(Parmscontroller::parm(Parmscontroller::Parm::PM_IconBarIconSize), Parmscontroller::parm(Parmscontroller::Parm::PM_IconBarIconSize)))); } void KIconBar::setWidgetName(const QString &widgetName) { Q_D(KIconBar); if (widgetName.isEmpty()) return; if (!d->m_pNameLabel) return; d->m_widgetName = widgetName; d->elideWidgetName(); } QSize KIconBar::sizeHint() const { auto size = QFrame::sizeHint(); size.setHeight(Parmscontroller::parm(Parmscontroller::Parm::PM_PushButtonHeight)); return size; } QLabel *KIconBar::nameLabel() { Q_D(KIconBar); return d->m_pNameLabel; } QLabel *KIconBar::iconLabel() { Q_D(KIconBar); return d->m_pIconLabel; } void KIconBar::mouseDoubleClickEvent(QMouseEvent *event) { Q_D(KIconBar); if (event->button() == Qt::LeftButton) Q_EMIT doubleClick(); } void KIconBar::resizeEvent(QResizeEvent *event) { Q_D(KIconBar); QFrame::resizeEvent(event); d->elideWidgetName(); } KIconBarPrivate::KIconBarPrivate(KIconBar *parent) : q_ptr(parent) { Q_Q(KIconBar); setParent(parent); parent->installEventFilter(this); q->setContentsMargins(0, 0, 0, 0); m_pMainLayout = new QHBoxLayout(q); m_pIconLabel = new QLabel(q); m_pIconLabel->setScaledContents(true); m_pIconLabel->setFixedSize(24, 24); m_pNameLabel = new QLabel(q); QHBoxLayout *iconLayout = new QHBoxLayout(); iconLayout->setSpacing(0); iconLayout->setContentsMargins(0, 8, 0, 8); iconLayout->addWidget(m_pIconLabel); m_pMainLayout->setSpacing(8); m_pMainLayout->addSpacing(8); m_pMainLayout->addLayout(iconLayout); m_pMainLayout->addWidget(m_pNameLabel); m_pMainLayout->setContentsMargins(0, 0, 0, 0); m_pMainLayout->addStretch(); changeIconStyle(); connect(m_gsetting, &QGSettings::changed, this, &KIconBarPrivate::changeIconStyle); changeTheme(); connect(m_gsetting, &QGSettings::changed, this, &KIconBarPrivate::changeTheme); connect(m_gsetting, &QGSettings::changed, this, [=](const QString &key) { if (key.contains("systemFontSize")) elideWidgetName(); }); KDK_ALL_INFO_FORMAT(m_pIconLabel,""); KDK_ALL_INFO_FORMAT(m_pNameLabel,""); } void KIconBarPrivate::elideWidgetName() { Q_Q(KIconBar); QFontMetrics fm = QApplication::fontMetrics(); // bug 175664 修正1px auto visualWidth = q->width() - m_pNameLabel->geometry().left() - 1; QString elidedText = fm.elidedText(m_widgetName, Qt::TextElideMode::ElideRight, visualWidth); m_pNameLabel->setText(elidedText); if (fm.horizontalAdvance(m_widgetName) >= visualWidth) m_pNameLabel->setToolTip(m_widgetName); else m_pNameLabel->setToolTip(""); } void KIconBarPrivate::changeTheme() { Q_Q(KIconBar); initThemeStyle(); } void KIconBarPrivate::changeIconStyle() { Q_Q(KIconBar); initThemeStyle(); q->setIcon(m_IconName); if (!q->isActiveWindow()) { if(ThemeController::themeMode() == LightTheme) inactiveColor = ThemeController::getCustomColorFromDT("kfont-placeholdertext"); else inactiveColor = ThemeController::getCustomColorFromDT("kfont-secondary-disable"); QPalette palette = q->palette(); palette.setBrush(QPalette::Inactive, QPalette::Text, inactiveColor); m_pNameLabel->setPalette(palette); } else { inactiveColor = ThemeController::getCustomColorFromDT("kfont-primary"); QPalette palette = q->palette(); palette.setBrush(QPalette::Active, QPalette::Text, inactiveColor); m_pNameLabel->setPalette(palette); } } bool KIconBarPrivate::eventFilter(QObject *watched, QEvent *event) { Q_Q(KIconBar); // 窗口停用,变为不活动的窗口 if (QEvent::WindowDeactivate == event->type()) { if(ThemeController::themeMode() == LightTheme) inactiveColor = ThemeController::getCustomColorFromDT("kfont-placeholdertext"); else inactiveColor = ThemeController::getCustomColorFromDT("kfont-secondary-disable"); QPalette palette = q->palette(); palette.setBrush(QPalette::Inactive, QPalette::Text, inactiveColor); m_pNameLabel->setPalette(palette); } else if(QEvent::WindowActivate == event->type()) { inactiveColor = ThemeController::getCustomColorFromDT("kfont-primary"); QPalette palette = q->palette(); palette.setBrush(QPalette::Active, QPalette::Text, inactiveColor); m_pNameLabel->setPalette(palette); } return QObject::eventFilter(watched, event); } } #include "kiconbar.moc" #include "moc_kiconbar.cpp" libkysdk-applications/kysdk-qtwidgets/src/ktableview.cpp0000664000175000017500000002351615104543305022575 0ustar fengfeng/* * libkysdk-qtwidgets's Library * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhenyu Wang * */ #include "ktableview.h" #include "ktableheaderview.h" #include "themeController.h" #include #include #include #include #include #include #include #include #include namespace kdk { class Q_DECL_HIDDEN TableDelegate : public QStyledItemDelegate { Q_OBJECT public: TableDelegate(QObject *parent); void updateState(Qt::CheckState state, const QModelIndex &index); QList selectList(); protected: void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override; virtual bool editorEvent(QEvent *event, QAbstractItemModel *model, const QStyleOptionViewItem &option, const QModelIndex &index) override; Q_SIGNALS: void checkChange(int state); public slots: void checkChangeSlot(int state); void onHoverIndexChanged(QModelIndex index); // void selectChange(int row); private: QList m_checkList; int m_hoverRow; }; class Q_DECL_HIDDEN KTableViewPrivate : public QObject, public ThemeController { Q_OBJECT Q_DECLARE_PUBLIC(KTableView) public: KTableViewPrivate(KTableView *parent); virtual ~KTableViewPrivate(); void changeTheme(); private: KTableView *q_ptr; KTableHeaderView *m_pHeaderView; TableDelegate *m_pDelegate; }; KTableView::KTableView(QWidget *parent) : QTableView(parent) , d_ptr(new KTableViewPrivate(this)) { Q_D(KTableView); setShowGrid(false); verticalHeader()->setVisible(false); setEditTriggers(QAbstractItemView::NoEditTriggers); setSelectionBehavior(QAbstractItemView::SelectRows); setMouseTracking(true); installEventFilter(this); d->m_pHeaderView = new KTableHeaderView(Qt::Horizontal, this); d->m_pHeaderView->installEventFilter(this); d->m_pDelegate = new TableDelegate(this); setItemDelegate(d->m_pDelegate); connect(d->m_pDelegate, &TableDelegate::checkChange, d->m_pHeaderView, [=](int state) { d->m_pHeaderView->checkStateChangeSlot(state); }); connect(d->m_pHeaderView, &KTableHeaderView::checkStateChange, d->m_pDelegate, [=](int state) { d->m_pDelegate->checkChangeSlot(state); QItemSelectionModel *SelectionModel = selectionModel(); if (SelectionModel) { SelectionModel->clearSelection(); } emit hoverIndexChanged(QModelIndex()); }); connect(this, SIGNAL(hoverIndexChanged(QModelIndex)), d->m_pDelegate, SLOT(onHoverIndexChanged(QModelIndex))); connect(d->m_gsetting, &QGSettings::changed, this, [=] { d->changeTheme(); }); } void KTableView::setHorizontalTitle(QStringList list) { Q_D(KTableView); d->m_pHeaderView->setTitle(list); setHorizontalHeader(d->m_pHeaderView); } KTableHeaderView *KTableView::headerView() { Q_D(KTableView); if (d->m_pHeaderView) return d->m_pHeaderView; } QList KTableView::selectList() { Q_D(KTableView); return d->m_pDelegate->selectList(); } void KTableView::mouseMoveEvent(QMouseEvent *event) { QModelIndex index = indexAt(event->pos()); emit hoverIndexChanged(index); QTableView::mouseMoveEvent(event); this->viewport()->update(); } bool KTableView::eventFilter(QObject *object, QEvent *event) { Q_D(KTableView); if (object == this) { switch (event->type()) { case QEvent::Leave: emit hoverIndexChanged(QModelIndex()); break; default: break; } } if (object == d->m_pHeaderView) { switch (event->type()) { case QEvent::Enter: emit hoverIndexChanged(QModelIndex()); break; default: break; } } this->viewport()->update(); return QTableView::eventFilter(object, event); } KTableViewPrivate::KTableViewPrivate(KTableView *parent) : q_ptr(parent) { } KTableViewPrivate::~KTableViewPrivate() { } void KTableViewPrivate::changeTheme() { initThemeStyle(); } TableDelegate::TableDelegate(QObject *parent) : QStyledItemDelegate(parent) { m_hoverRow = -1; } void TableDelegate::updateState(Qt::CheckState state, const QModelIndex &index) { if (state == Qt::Checked) { m_checkList.append(index.row()); } else if (state == Qt::Unchecked) { m_checkList.removeOne(index.row()); } QAbstractItemView *view = qobject_cast(parent()); int count = view->model()->rowCount(); if (m_checkList.count() == 0) emit checkChange(Qt::Unchecked); else if (m_checkList.count() == count) emit checkChange(Qt::Checked); else emit checkChange(Qt::PartiallyChecked); } void TableDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const { QPalette pale; QColor bkgColor; QColor hoverColor; if (ThemeController::themeMode() == LightTheme) { if (index.row() % 2 == 0) bkgColor = QColor(245, 245, 245); else bkgColor = ThemeController::getCustomColorFromDT("kwhite"); hoverColor = ThemeController::getCustomColorFromDT("kblack"); hoverColor.setAlphaF(0.05); } else { if (index.row() % 2 == 0) bkgColor = ThemeController::getCustomColorFromDT("kgray-17"); else bkgColor = QColor(18, 18, 18); hoverColor = ThemeController::getCustomColorFromDT("kwhite"); hoverColor.setAlphaF(0.10); } if (index.row() == m_hoverRow && !option.state.testFlag(QStyle::State_Selected)) { painter->fillRect(option.rect, hoverColor); } else { if (option.state.testFlag(QStyle::State_Selected)) painter->fillRect(option.rect, ThemeController::getCustomColorFromDT("highlight-active")); else { painter->fillRect(option.rect, bkgColor); } painter->setPen(Qt::NoPen); painter->drawRect(option.rect); } painter->setPen(ThemeController::getCustomColorFromDT("windowtext-active")); if (index.column() == 0) { QRect rect = option.rect; // 绘制复选框 QStyleOptionButton checkBoxStyle; checkBoxStyle.rect = QRect(rect.x() + 8, rect.y() + (rect.height() - 16) / 2, 16, 16); Qt::CheckState checkState = static_cast(index.data(Qt::CheckStateRole).toInt()); checkBoxStyle.state = (checkState == Qt::Checked) ? QStyle::State_On : QStyle::State_Off; checkBoxStyle.state |= QStyle::State_Enabled; QApplication::style()->drawPrimitive(QStyle::PE_IndicatorItemViewItemCheck, &checkBoxStyle, painter, option.widget); painter->drawText(option.rect.adjusted(checkBoxStyle.rect.right() + 10, 0, 0, 0), index.data(Qt::DisplayRole).toString()); } else { painter->drawText(option.rect, index.data(Qt::DisplayRole).toString()); } } bool TableDelegate::editorEvent(QEvent *event, QAbstractItemModel *model, const QStyleOptionViewItem &option, const QModelIndex &index) { if ((event->type() == QEvent::MouseButtonRelease) && (index.column() == 0)) { QMouseEvent *mouse_event = static_cast(event); if (mouse_event->button() == Qt::LeftButton) { QRect r(option.rect.left() + 8, option.rect.y() + (option.rect.height() - 16) / 2, 16, 16); bool flag = r.contains(mouse_event->pos()); if (flag) { // 根据当前单元格的选中状态来在 选中/未选中 之间切换 QVariant value = index.data(Qt::CheckStateRole); Qt::CheckState state = (static_cast(value.toInt()) == Qt::Checked ? Qt::Unchecked : Qt::Checked); // 设置当前单元格的选中状态 bool checkState = model->setData(index, state, Qt::CheckStateRole); updateState(state, index); return checkState; } } return false; } else return QStyledItemDelegate::editorEvent(event, model, option, index); } QList TableDelegate::selectList() { return m_checkList; } void TableDelegate::checkChangeSlot(int state) { m_checkList.clear(); QAbstractItemView *view = qobject_cast(parent()); int count = view->model()->rowCount(); Qt::CheckState checkState; for (int i = 0; i < count; i++) { if (state == 0) { m_checkList.append(view->model()->index(i, 0).row()); checkState = Qt::Unchecked; } else { m_checkList.removeOne(view->model()->index(i, 0).row()); checkState = Qt::Checked; } // 设置当前单元格的选中状态 view->model()->setData(view->model()->index(i, 0), checkState, Qt::CheckStateRole); updateState(checkState, view->model()->index(i, 0)); } } void TableDelegate::onHoverIndexChanged(QModelIndex index) { if (index.isValid()) { m_hoverRow = index.row(); } else { m_hoverRow = -1; } } } #include "ktableview.moc" #include "moc_ktableview.cpp" libkysdk-applications/kysdk-qtwidgets/src/kitemwidget.h0000664000175000017500000000356215104543305022421 0ustar fengfeng/* * libkysdk-qtwidgets's Library * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhenyu Wang * */ #ifndef KITEMWIDGET_H #define KITEMWIDGET_H #include "gui_g.h" #include "themeController.h" #include #include #include #include #include #include #include #include #include #include #include namespace kdk { /** * @since 1.2.0 */ class KItemWidgetPrivate; class GUI_EXPORT KItemWidget : public QWidget { Q_OBJECT public: /* * Myicon 需要显示的图片 * MmainText 需要写入的miantext * MsecText 需要写入的sectext */ KItemWidget(const QIcon &Myicon, QString MmainText, QString MsecText, QWidget *parent); /* * 设置反白效果 */ void SetInverse(); /* * 取消反白效果 */ void CancelInverse(); /* * 设置图片大小 */ void SetIconSize(QSize size); protected: void paintEvent(QPaintEvent *event); /*void mousePressEvent(QMouseEvent *event);*/ private: Q_DECLARE_PRIVATE(KItemWidget); KItemWidgetPrivate *const d_ptr; }; } #endif // KITEMWIDGET_H libkysdk-applications/kysdk-qtwidgets/src/kbaseframe.cpp0000664000175000017500000001211015104543305022524 0ustar fengfeng/* * * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Sisheng He * */ #include "kbaseframe.h" #include "themeController.h" #include #include #include #include #include namespace kdk { class KBaseFramePrivate : public QObject { Q_OBJECT Q_DECLARE_PUBLIC(KBaseFrame) public: KBaseFramePrivate(KBaseFrame *parent); protected: void paintEvent(QPaintEvent *e); private: KBaseFrame *q_ptr; KBaseFrame::BorderRadiusStyle m_RadiusType; bool m_IsTabletMode = false; QDBusInterface *m_pStatusSessionDbus = nullptr; bool m_HeightAdaptive = false; bool m_IsContainer = false; void autoAdjustFollowTabletMode(); private Q_SLOTS: void mode_change_signal_slots(bool b); }; KBaseFramePrivate::KBaseFramePrivate(KBaseFrame *parent) : q_ptr(parent) { Q_Q(KBaseFrame); setParent(parent); q->setFrameShape(QFrame::Box); } void KBaseFramePrivate::autoAdjustFollowTabletMode() { m_pStatusSessionDbus = new QDBusInterface("com.kylin.statusmanager.interface", "/", "com.kylin.statusmanager.interface", QDBusConnection::sessionBus(), this); if (m_pStatusSessionDbus->isValid()) { QDBusReply is_tabletmode = m_pStatusSessionDbus->call("get_current_tabletmode"); mode_change_signal_slots(is_tabletmode.isValid() ? is_tabletmode.value() : false); connect(m_pStatusSessionDbus, SIGNAL(mode_change_signal(bool)), this, SLOT(mode_change_signal_slots(bool))); } else { mode_change_signal_slots(false); // qWarning() << "Create com.kylin.statusmanager.interface Interface Failed When : " << QDBusConnection::systemBus().lastError(); } } void KBaseFramePrivate::mode_change_signal_slots(bool b) { Q_Q(KBaseFrame); if (m_HeightAdaptive) { if (b) { q->setMinimumSize(550, TABLET_HEIGHT); q->setMaximumSize(16777215, TABLET_HEIGHT); } else { q->setMinimumSize(550, PC_HEIGHT); q->setMaximumSize(16777215, PC_HEIGHT); } } m_IsTabletMode = b; Q_EMIT q->tabletModeChanged(b); } KBaseFrame::KBaseFrame(QWidget *parent, KBaseFrame::BorderRadiusStyle style, bool heightAdaptive) : QFrame(parent) , d_ptr(new KBaseFramePrivate(this)) { Q_D(KBaseFrame); setObjectName("KBaseFrame"); d->m_RadiusType = style; d->m_HeightAdaptive = heightAdaptive; d->m_IsContainer = false; if (heightAdaptive) { d->autoAdjustFollowTabletMode(); } else { d->mode_change_signal_slots(false); } } KBaseFrame::~KBaseFrame() { } void KBaseFrame::setRadiusType(BorderRadiusStyle style) { Q_D(KBaseFrame); d->m_RadiusType = style; update(); } bool KBaseFrame::getTabletMode() { Q_D(KBaseFrame); return d->m_IsTabletMode; } void KBaseFrame::setContainer(bool b) { Q_D(KBaseFrame); d->m_IsContainer = b; if (b) { this->setFrameShape(QFrame::NoFrame); } } bool KBaseFrame::isContainer() { Q_D(KBaseFrame); return d->m_IsContainer; } void KBaseFrame::paintEvent(QPaintEvent *e) { Q_UNUSED(e); Q_D(KBaseFrame); QPainter painter(this); painter.setRenderHint(QPainter::Antialiasing); // 反锯齿; if (this->frameShape() != QFrame::NoFrame) { painter.setBrush(ThemeController::getCustomColorFromDT("base-active")); } painter.setPen(Qt::transparent); QRect rect = this->rect(); if (d->m_RadiusType == BorderRadiusStyle::None) { painter.drawRoundedRect(rect, 0, 0); } else { QPainterPath painterPath; painterPath.addRoundedRect(rect, RADIUS_VALUE, RADIUS_VALUE); painterPath.setFillRule(Qt::WindingFill); if (d->m_RadiusType == BorderRadiusStyle::Bottom) { painterPath.addRect(rect.width() - RADIUS_VALUE, 0, RADIUS_VALUE, RADIUS_VALUE); painterPath.addRect(0, 0, RADIUS_VALUE, RADIUS_VALUE); } else if (d->m_RadiusType == BorderRadiusStyle::Top) { painterPath.addRect(0, rect.height() - RADIUS_VALUE, RADIUS_VALUE, RADIUS_VALUE); painterPath.addRect(rect.width() - RADIUS_VALUE, rect.height() - RADIUS_VALUE, RADIUS_VALUE, RADIUS_VALUE); } painter.drawPath(painterPath); } } } #include "kbaseframe.moc" #include "moc_kbaseframe.cpp" libkysdk-applications/kysdk-qtwidgets/src/ksettinggroup.h0000664000175000017500000000714115104543305023006 0ustar fengfeng/* * * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Sisheng He * */ #ifndef SETTINGGROUP_H #define SETTINGGROUP_H #include "kbaseframe.h" #include #include #include #include #include #include #include /** * @defgroup ContainerModules * @brief 创建一个 Spacing 为 1 的垂直布局 Frame * @since 3.0.1.0 * { */ namespace kdk { class KSettingGroupPrivate; class KSettingGroup : public KBaseFrame { Q_OBJECT public: /** * @brief 创建一个 Spacing 为 1 的垂直布局 Frame * * @param Shape: 设置frameShap * @param style: 设置圆角(None:无圆角,Top:上圆角,Bottom:下圆角,Around:四圆角) * @param parent */ explicit KSettingGroup(QWidget *parent = nullptr, Shape shape = QFrame::NoFrame, BorderRadiusStyle style = BorderRadiusStyle::None); ~KSettingGroup(); /** * @brief 为 mainLayout 添加控件并更新圆角 * * @param item: 需要添加的控件 * @param autoUpdateShape: 是否自动更新item圆角样式 * @param visible 实际未show控件时isVisible总是false,导致圆角无法正常,因此重新设置,应为Qt的BUG */ void addWidget(QFrame *item, bool autoUpdateShape = true, bool visible = true); /** * @brief 为 mainLayout 添加控件并更新圆角 * * @param index: 序号 * @param item: 需要添加的控件 * @param autoUpdateShape: 是否自动更新item圆角样式 * @param visible 实际未show控件时isVisible总是false,导致圆角无法正常,因此重新设置,应为Qt的BUG */ void insertWidget(int index, QFrame *item, bool autoUpdateShape = true, bool visible = true); /** * @brief 为 mainLayout 移除控件并更新圆角 * * @param w: 需要移除的控件 * @param autoUpdateShape: 是否自动更新item圆角样式 */ void removeWidget(QWidget *w, bool autoUpdateShape = true); /** * @brief 更新圆角 * */ void updateShape(); /** * @brief 获取 mainLayout * * @return QVBoxLayout mainLayout */ QVBoxLayout *layout(); /** * @brief 设置最后一个frame的圆角风格 * * @param style 圆角风格 */ void setLastRadiusStyle(BorderRadiusStyle style); /** * @brief 设置仅一个frame时的圆角风格 * * @param style */ void setOneRadiusStyle(BorderRadiusStyle style); /** * @brief 获取显示的子控件个数 * * @return int 显示的子控件个数 */ int showItemsCount(); /** * @brief 移除并删除所有子控件 * */ void removeAndDeleteAllWidget(); protected: bool eventFilter(QObject *watched, QEvent *event); private: Q_DECLARE_PRIVATE(KSettingGroup) KSettingGroupPrivate *const d_ptr; }; } #endif // SETTINGGROUP_H libkysdk-applications/kysdk-qtwidgets/src/ktoolbar.cpp0000664000175000017500000002465115104543305022256 0ustar fengfeng/* * libkysdk-qtwidgets's Library * * Copyright (C) 2024, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhenyu Wang * */ #include "ktoolbar.h" #include "klineframe.h" #include "themeController.h" #include #include #include namespace kdk { class KToolBarPrivate : public QObject, public ThemeController { Q_DECLARE_PUBLIC(KToolBar) Q_OBJECT public: KToolBarPrivate(KToolBar *parent); void init(); void updateButtonLayout(); void clearButtonLayout(); void getSelectList(KToolButton *button, bool checked); private: KToolBar *q_ptr; QBoxLayout *m_pLayout; QList m_pButtonList; QList m_pCheckList; int m_radius; bool m_exclusive; bool m_isCheckable; bool m_isLineVisible; bool m_isBkgColorEnable; }; KToolBar::KToolBar(QWidget *parent) : QWidget(parent) , d_ptr(new KToolBarPrivate(this)) { } Qt::Orientation KToolBar::orientation() { Q_D(KToolBar); QBoxLayout::Direction layoutDirection = d->m_pLayout->direction(); if (layoutDirection == QBoxLayout::LeftToRight || layoutDirection == QBoxLayout::RightToLeft) { return Qt::Horizontal; } return Qt::Vertical; } void KToolBar::setOrientation(Qt::Orientation orientation) { Q_D(KToolBar); if (orientation == Qt::Vertical) d->m_pLayout->setDirection(QBoxLayout::TopToBottom); else d->m_pLayout->setDirection(QBoxLayout::LeftToRight); d->updateButtonLayout(); } KToolButton *KToolBar::addButton(QIcon icon) { Q_D(KToolBar); KToolButton *button = new KToolButton(this); button->setType(KToolButtonType::Frameless); button->setIcon(icon); button->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); d->m_pButtonList.append(button); d->updateButtonLayout(); return button; } KToolButton *KToolBar::addButton(QString string) { Q_D(KToolBar); KToolButton *button = new KToolButton(this); button->setType(KToolButtonType::Frameless); button->setText(string); button->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); d->m_pButtonList.append(button); d->updateButtonLayout(); return button; } QList KToolBar::addButton(QList list) { Q_D(KToolBar); QList btnList; for (int i = 0; i < list.count(); i++) { KToolButton *button = new KToolButton(this); button->setType(KToolButtonType::Frameless); button->setIcon(list.at(i)); button->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); d->m_pButtonList.append(button); btnList.append(button); } d->updateButtonLayout(); return btnList; } QList KToolBar::addButton(QList list) { Q_D(KToolBar); QList btnList; for (int i = 0; i < list.count(); i++) { KToolButton *button = new KToolButton(this); button->setType(KToolButtonType::Frameless); button->setText(list.at(i)); button->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); d->m_pButtonList.append(button); btnList.append(button); } d->updateButtonLayout(); return btnList; } // void KToolBar::addButton(KToolButton *button) //{ // Q_D(KToolBar); // if(!d->m_pButtonList.contains(button)) // { // d->m_pButtonList.append(button); // d->updateButtonLayout(); // } // } // void KToolBar::addButton(QList list) //{ // Q_D(KToolBar); // for(int i = 0 ; i < list.count() ; i++) // { // if(!d->m_pButtonList.contains(list.at(i))) // { // d->m_pButtonList.append(list.at(i)); // } // } // d->updateButtonLayout(); // } QList KToolBar::buttonList() { Q_D(KToolBar); return d->m_pButtonList; } void KToolBar::removeButton(KToolButton *button) { Q_D(KToolBar); if (d->m_pButtonList.contains(button)) { d->m_pButtonList.removeAll(button); } d->updateButtonLayout(); } void KToolBar::removeButton(int id) { Q_D(KToolBar); if (id < 0 || id >= d->m_pButtonList.count()) return; d->m_pButtonList.removeAt(id); d->updateButtonLayout(); } void KToolBar::removeButton(QList list) { Q_D(KToolBar); for (int i = 0; i < list.count(); i++) { if (d->m_pButtonList.contains(list.at(i))) { d->m_pButtonList.removeAll(list.at(i)); } } d->updateButtonLayout(); } void KToolBar::setBorderRadius(int radius) { Q_D(KToolBar); d->m_radius = radius; } int KToolBar::borderRadius() { Q_D(KToolBar); return d->m_radius; } void KToolBar::setExclusive(bool exclusive) { Q_D(KToolBar); d->m_exclusive = exclusive; } bool KToolBar::exclusive() { Q_D(KToolBar); return d->m_exclusive; } void KToolBar::setCheckable(bool flag) { Q_D(KToolBar); d->m_isCheckable = flag; QList list = buttonList(); for (int i = 0; i < list.count(); ++i) { KToolButton *button = list.at(i); button->setCheckable(d->m_isCheckable); } update(); } bool KToolBar::isCheckable() { Q_D(KToolBar); return d->m_isCheckable; } QList KToolBar::checkedButton() { Q_D(KToolBar); return d->m_pCheckList; } void KToolBar::setLineVisible(bool flag) { Q_D(KToolBar); d->m_isLineVisible = flag; d->updateButtonLayout(); } bool KToolBar::isLineVisible() { Q_D(KToolBar); return d->m_isLineVisible; } void KToolBar::setBackgroundColorEnabled(bool flag) { Q_D(KToolBar); d->m_isBkgColorEnable = flag; d->updateButtonLayout(); } bool KToolBar::backgroundColorEnabled() { Q_D(KToolBar); return d->m_isBkgColorEnable; } void KToolBar::paintEvent(QPaintEvent *event) { Q_D(KToolBar); QPainter painter(this); painter.setRenderHint(QPainter::Antialiasing); if (d->m_isBkgColorEnable) painter.setBrush(ThemeController::getCustomColorFromDT("button-active")); else painter.setBrush(Qt::transparent); painter.setPen(Qt::NoPen); painter.drawRoundedRect(this->rect(), d->m_radius, d->m_radius); QWidget::paintEvent(event); } KToolBarPrivate::KToolBarPrivate(KToolBar *parent) : q_ptr(parent) { Q_Q(KToolBar); init(); } void KToolBarPrivate::init() { Q_Q(KToolBar); m_pLayout = new QHBoxLayout(q); m_pLayout->setContentsMargins(0, 0, 0, 0); m_pLayout->setSpacing(0); m_pLayout->setDirection(QBoxLayout::LeftToRight); m_radius = ThemeController::getRadiusFromDT("kradius-normal"); if (m_radius == -1) m_radius = 6; m_exclusive = false; m_isCheckable = false; m_isLineVisible = false; m_isBkgColorEnable = false; } void KToolBarPrivate::updateButtonLayout() { Q_Q(KToolBar); clearButtonLayout(); for (int i = 0; i < m_pButtonList.count(); i++) { if (m_isBkgColorEnable) m_pButtonList.at(i)->setBackgroundColorEnabled(true); else m_pButtonList.at(i)->setBackgroundColorEnabled(false); m_pButtonList.at(i)->setBorderRadius(m_radius, m_radius, m_radius, m_radius); m_pLayout->addWidget(m_pButtonList.at(i)); q->setCheckable(q->isCheckable()); if (m_pButtonList.at(i)->menu()) m_pButtonList.at(i)->setArrow(true); connect(m_pButtonList.at(i), &KToolButton::checkedChanged, this, [=](bool checked) { getSelectList(m_pButtonList.at(i), checked); }); if (i != m_pButtonList.count() - 1 && m_isLineVisible) { if (q->orientation() == Qt::Vertical) { KHLineFrame *lineFrame = new KHLineFrame(q); lineFrame->setFollowPalette(false); QPalette pale; QColor color(0, 0, 0); color.setAlphaF(0.1); pale.setColor(QPalette::Window, color); lineFrame->setPalette(pale); m_pLayout->addWidget(lineFrame); } else { KVLineFrame *lineFrame = new KVLineFrame(q); lineFrame->setFollowPalette(false); QPalette pale; QColor color(0, 0, 0); color.setAlphaF(0.1); pale.setColor(QPalette::Window, color); lineFrame->setPalette(pale); m_pLayout->addWidget(lineFrame); } } } } void KToolBarPrivate::clearButtonLayout() { for (int i = 0; i < m_pButtonList.count(); i++) { disconnect(m_pButtonList.at(i), SIGNAL(checkedChanged(bool)), 0, 0); } QLayoutItem *child; while ((child = m_pLayout->takeAt(0)) != 0) { if (child->spacerItem()) { m_pLayout->removeItem(child); continue; } m_pLayout->removeWidget(child->widget()); child->widget()->setParent(nullptr); delete child; child = nullptr; } } void KToolBarPrivate::getSelectList(KToolButton *button, bool checked) { m_pCheckList.clear(); if (m_exclusive) { if (checked) { for (int i = 0; i < m_pButtonList.count(); i++) { if (button == m_pButtonList.at(i)) { button->setChecked(checked); } else m_pButtonList.at(i)->setChecked(false); } } else { button->setChecked(checked); } } else { for (int i = 0; i < m_pButtonList.count(); i++) { if (button == m_pButtonList.at(i)) { button->setChecked(checked); } else m_pButtonList.at(i)->setChecked(m_pButtonList.at(i)->isChecked()); } } for (int i = 0; i < m_pButtonList.count(); i++) { if (m_pButtonList.at(i)->isChecked()) m_pCheckList.append(m_pButtonList.at(i)); } } } #include "ktoolbar.moc" #include "moc_ktoolbar.cpp" libkysdk-applications/kysdk-qtwidgets/src/kcomboboxwidget.cpp0000664000175000017500000002662615104543305023634 0ustar fengfeng/* * libkysdk-qtwidgets's Library * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhenyu Wang * */ #include "kcomboboxwidget.h" #include "klabel.h" #include "ktoolbutton.h" #include "themeController.h" #include #include #include #include #include #include #include #include #include #include #include #include #include namespace kdk { class Q_DECL_HIDDEN ProxyStyle : public QProxyStyle { Q_OBJECT public: ProxyStyle(QWidget *parent = nullptr) { } void drawComplexControl(ComplexControl control, const QStyleOptionComplex *option, QPainter *painter, const QWidget *widget = nullptr) const override; }; class Q_DECL_HIDDEN MenuItem : public QToolButton, public ThemeController { Q_OBJECT public: MenuItem(QString week, int id, QWidget *parent = nullptr); void setIconVisible(bool status); protected: void mouseReleaseEvent(QMouseEvent *event); void enterEvent(QEvent *e); void leaveEvent(QEvent *e); Q_SIGNALS: void showLabelIcon(int id); void hideLabelIcon(int id); private: QLabel *m_pTextLabel; QLabel *m_pMenuIconLabel; QHBoxLayout *m_pHLayout; int m_id = 0; ProxyStyle *m_proxyStyle = nullptr; }; class Q_DECL_HIDDEN KComboBoxWidgetPrivate : public QObject, public ThemeController { Q_OBJECT Q_DECLARE_PUBLIC(KComboBoxWidget) public: KComboBoxWidgetPrivate(KComboBoxWidget *parent); void initLayout(); void setChosenString(); QStringList reorderListBasedOnSelection(const QStringList stringList, const QStringList chosenList); private: KComboBoxWidget *q_ptr; QLabel *m_pMainLabel; KLabel *m_pSubLabel; QLabel *m_pIconLabel; QHBoxLayout *m_pHLayout; bool m_mouseEnter = false; QStringList m_stringList; QStringList m_chosenList; QMenu *m_pMenu; }; KComboBoxWidget::KComboBoxWidget(QWidget *parent) : QWidget(parent) , d_ptr(new KComboBoxWidgetPrivate(this)) { } void KComboBoxWidget::setStringList(QStringList list) { Q_D(KComboBoxWidget); d->m_stringList = list; for (int i = 0; i < list.count(); i++) { MenuItem *item = new MenuItem(list[i], i, this); connect(item, &MenuItem::showLabelIcon, this, [=](int index) { if (!d->m_chosenList.contains(d->m_stringList.at(index))) d->m_chosenList.append(d->m_stringList.at(index)); d->setChosenString(); }); connect(item, &MenuItem::hideLabelIcon, this, [=](int index) { if (d->m_chosenList.contains(d->m_stringList.at(index))) d->m_chosenList.removeOne(d->m_stringList.at(index)); d->setChosenString(); }); QWidgetAction *action = new QWidgetAction(this); action->setDefaultWidget(item); d->m_pMenu->addAction(action); } } QStringList KComboBoxWidget::getChosenList() { Q_D(KComboBoxWidget); return d->m_chosenList; } void KComboBoxWidget::setMainText(QString text) { Q_D(KComboBoxWidget); d->m_pMainLabel->setText(text); } QMenu *KComboBoxWidget::menu() { Q_D(KComboBoxWidget); return d->m_pMenu; } void KComboBoxWidget::mouseReleaseEvent(QMouseEvent *event) { Q_D(KComboBoxWidget); emit comBoxWidgetClicked(); QWidget::mouseReleaseEvent(event); return; } void KComboBoxWidget::mousePressEvent(QMouseEvent *event) { Q_D(KComboBoxWidget); } void KComboBoxWidget::leaveEvent(QEvent *e) { Q_D(KComboBoxWidget); d->m_mouseEnter = false; repaint(); } void KComboBoxWidget::enterEvent(QEvent *e) { Q_D(KComboBoxWidget); d->m_mouseEnter = true; repaint(); } void KComboBoxWidget::paintEvent(QPaintEvent *event) { Q_D(KComboBoxWidget); QStyleOption opt; opt.initFrom(this); QPainter p(this); QPainterPath path; opt.rect.adjust(0, 0, 0, 0); if (!opt.state.testFlag(QStyle::State_Enabled)) { p.setBrush(ThemeController::getCustomColorFromDT("button-disable")); } else { if (d->m_mouseEnter) { p.setBrush(ThemeController::getCustomColorFromDT("midlight-active")); } else { p.setBrush(ThemeController::getCustomColorFromDT("button-active")); } } p.setOpacity(1); p.setPen(Qt::NoPen); int radius = ThemeController::getRadiusFromDT("kradius-normal"); if (radius == -1) radius = 6; p.drawRoundedRect(opt.rect, radius, radius); p.setRenderHint(QPainter::Antialiasing); // 反锯齿 setProperty("blurRegion", QRegion(path.toFillPolygon().toPolygon())); } KComboBoxWidgetPrivate::KComboBoxWidgetPrivate(KComboBoxWidget *parent) : q_ptr(parent) { Q_Q(KComboBoxWidget); initLayout(); } void KComboBoxWidgetPrivate::initLayout() { Q_Q(KComboBoxWidget); m_pMenu = new QMenu; m_pMainLabel = new QLabel(); m_pMainLabel->setAlignment(Qt::AlignVCenter); m_pSubLabel = new KLabel(); m_pSubLabel->setAlignment(Qt::AlignRight); m_pSubLabel->setFixedWidth(165); m_pIconLabel = new QLabel(); QIcon labelIcon = QIcon::fromTheme("ukui-down.symbolic"); m_pIconLabel->setPixmap(labelIcon.pixmap(QSize(16, 16))); m_pIconLabel->setProperty("useIconHighlightEffect", 0x1); m_pHLayout = new QHBoxLayout(); m_pHLayout->setSpacing(0); m_pHLayout->setContentsMargins(0, 0, 0, 0); q->setContentsMargins(0, 0, 0, 0); m_pHLayout->addItem(new QSpacerItem(16, 1, QSizePolicy::Fixed)); m_pHLayout->addWidget(m_pMainLabel, Qt::AlignVCenter); m_pMainLabel->setAlignment(Qt::AlignVCenter); m_pHLayout->addItem(new QSpacerItem(12, 20, QSizePolicy::Expanding)); m_pHLayout->addWidget(m_pSubLabel, Qt::AlignVCenter); m_pSubLabel->setAlignment(Qt::AlignVCenter); m_pHLayout->addItem(new QSpacerItem(8, 30, QSizePolicy::Minimum)); m_pHLayout->addWidget(m_pIconLabel, Qt::AlignVCenter); m_pHLayout->addItem(new QSpacerItem(8, 5, QSizePolicy::Fixed)); q->setLayout(m_pHLayout); connect(q, &KComboBoxWidget::comBoxWidgetClicked, q, [=] { if (!m_pMenu->isVisible()) { m_pMenu->exec(q->mapToGlobal(QPoint(0, q->rect().height()))); } else { m_pMenu->hide(); } }); } void KComboBoxWidgetPrivate::setChosenString() { Q_Q(KComboBoxWidget); QStringList list = reorderListBasedOnSelection(m_stringList, m_chosenList); QString text; for (int i = 0; i < list.count(); i++) { text.append(list.at(i)); if (i < list.count() - 1) text.append(" "); } m_pSubLabel->setText(text); } QStringList KComboBoxWidgetPrivate::reorderListBasedOnSelection(const QStringList stringList, const QStringList chosenList) { QStringList result; QVector isSelected(chosenList.size(), false); for (const QString &selected : stringList) { int index = chosenList.indexOf(selected); if (index != -1) { result.append(selected); isSelected[index] = true; } } for (int i = 0; i < chosenList.size(); ++i) { if (!isSelected[i]) { result.append(chosenList.at(i)); } } return result; } void ProxyStyle::drawComplexControl(QStyle::ComplexControl control, const QStyleOptionComplex *option, QPainter *painter, const QWidget *widget) const { switch (control) { case CC_ToolButton: { if (const QStyleOptionComplex *f = qstyleoption_cast(option)) { const bool hover = f->state & State_MouseOver; if (hover) { painter->save(); painter->setRenderHint(QPainter::Antialiasing, true); painter->setPen(Qt::NoPen); QStyleOption opt; QColor color = ThemeController::getCustomColorFromDT("highlight-active"); painter->setBrush(color); int radius = ThemeController::getRadiusFromDT("kradius-normal"); if (radius == -1) radius = 6; painter->drawRoundedRect(option->rect, radius, radius); painter->restore(); return; } } break; } default: break; } } MenuItem::MenuItem(QString week, int id, QWidget *parent) : QToolButton(parent) , m_id(id) { m_proxyStyle = new ProxyStyle(this); this->setStyle(m_proxyStyle); m_pTextLabel = new QLabel(); m_pTextLabel->setText(week); this->setAutoRaise(true); // 设置默认状态背景透明 m_pMenuIconLabel = new QLabel(); m_pMenuIconLabel->setFixedSize(16, 16); QIcon labelIcon = QIcon::fromTheme("object-select-symbolic"); m_pMenuIconLabel->setPixmap(labelIcon.pixmap(QSize(16, 16))); m_pMenuIconLabel->setProperty("useIconHighlightEffect", 0x8); m_pMenuIconLabel->setFixedSize(16, 16); m_pHLayout = new QHBoxLayout(); m_pHLayout->setContentsMargins(17, 0, 0, 0); this->setLayout(m_pHLayout); m_pHLayout->addWidget(m_pMenuIconLabel); m_pHLayout->addWidget(m_pTextLabel); QSizePolicy policy = m_pMenuIconLabel->sizePolicy(); policy.setRetainSizeWhenHidden(true); m_pMenuIconLabel->setSizePolicy(policy); m_pMenuIconLabel->setVisible(false); connect(m_gsetting, &QGSettings::changed, this, [=](const QString &key) { if (ThemeController::themeMode() == DarkTheme) { QPalette palette; palette.setColor(QPalette::Active, QPalette::ButtonText, Qt::white); m_pTextLabel->setPalette(palette); } else { QPalette palette; palette.setColor(QPalette::Active, QPalette::ButtonText, Qt::black); m_pTextLabel->setPalette(palette); } }); } void MenuItem::setIconVisible(bool status) { m_pMenuIconLabel->setVisible(status); } void MenuItem::mouseReleaseEvent(QMouseEvent *event) { if (event->button() == Qt::LeftButton) { if (!this->m_pMenuIconLabel->isVisible()) { m_pMenuIconLabel->setVisible(true); emit showLabelIcon(m_id); } else { m_pMenuIconLabel->setVisible(false); emit hideLabelIcon(m_id); } } QToolButton::mouseReleaseEvent(event); } void MenuItem::enterEvent(QEvent *e) { QApplication::postEvent(m_pMenuIconLabel, new QEvent(QEvent::Enter)); QPalette palette; palette.setColor(QPalette::Active, QPalette::ButtonText, Qt::white); m_pTextLabel->setPalette(palette); } void MenuItem::leaveEvent(QEvent *e) { if (ThemeController::themeMode() == LightTheme) { QPalette palette; palette.setColor(QPalette::Active, QPalette::ButtonText, Qt::black); m_pTextLabel->setPalette(palette); } QApplication::postEvent(m_pMenuIconLabel, new QEvent(QEvent::Leave)); } } #include "kcomboboxwidget.moc" #include "moc_kcomboboxwidget.cpp" libkysdk-applications/kysdk-qtwidgets/src/kpressbutton.cpp0000664000175000017500000003453515104543305023206 0ustar fengfeng/* * libkysdk-qtwidgets's Library * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhenyu Wang * */ #include "kpressbutton.h" #include "themeController.h" #include #include #include #include #include #include #include namespace kdk { class KPressButtonPrivate : public QObject, public ThemeController { Q_OBJECT Q_DECLARE_PUBLIC(KPressButton) public: KPressButtonPrivate(KPressButton *parent); void changeTheme(); private: KPressButton *q_ptr; QColor m_pbkgColor; QTimer *m_pTimer; KPressButton::ButtonType m_pButtonType; QIcon m_pIcon; int m_flashState; int m_pTopLeftRadius; int m_pTopRightRadius; int m_pBottomLeftRadius; int m_pBottomRightRadius; bool m_pLoading; // loafing标志位 bool m_pCheackable; // 开启标志位 bool m_pTranslucent; bool m_isTranslucentFlag; }; KPressButtonPrivate::KPressButtonPrivate(KPressButton *parent) : q_ptr(parent) { Q_Q(KPressButton); } void KPressButtonPrivate::changeTheme() { Q_Q(KPressButton); if (m_isTranslucentFlag) { if (ThemeController::widgetTheme() == ClassicTheme) m_pTranslucent = false; else m_pTranslucent = true; } else { m_pTranslucent = false; } initThemeStyle(); } KPressButton::KPressButton(QWidget *parent) : QPushButton(parent) , d_ptr(new KPressButtonPrivate(this)) { Q_D(KPressButton); int radius = ThemeController::getRadiusFromDT("kradius-normal"); if (radius == -1) { d->m_pTopLeftRadius = 6; d->m_pTopRightRadius = 6; d->m_pBottomLeftRadius = 6; d->m_pBottomRightRadius = 6; } else { d->m_pTopLeftRadius = radius; d->m_pTopRightRadius = radius; d->m_pBottomLeftRadius = radius; d->m_pBottomRightRadius = radius; } d->m_pButtonType = KPressButton::NormalType; d->m_pCheackable = false; d->m_pTranslucent = false; d->m_isTranslucentFlag = false; d->m_pTimer = new QTimer(this); d->m_pTimer->setInterval(100); d->m_flashState = 0; setCheckable(true); connect(d->m_pTimer, &QTimer::timeout, this, [=]() { if (d->m_flashState < 7) d->m_flashState++; else d->m_flashState = 0; setIcon(QIcon::fromTheme(QString("ukui-loading-%1.symbolic").arg(d->m_flashState))); }); connect(d->m_gsetting, &QGSettings::changed, this, [=]() { d->changeTheme(); }); } void KPressButton::setBorderRadius(int radius) { Q_D(KPressButton); d->m_pTopLeftRadius = radius; d->m_pTopRightRadius = radius; d->m_pBottomLeftRadius = radius; d->m_pBottomRightRadius = radius; } void KPressButton::setBorderRadius(int bottomLeft, int topLeft, int topRight, int bottomRight) { Q_D(KPressButton); d->m_pBottomLeftRadius = bottomLeft; d->m_pTopLeftRadius = topLeft; d->m_pTopRightRadius = topRight; d->m_pBottomRightRadius = bottomRight; } void KPressButton::setCheckable(bool flag) { QPushButton::setCheckable(flag); } bool KPressButton::isCheckable() const { return QPushButton::isCheckable(); } void KPressButton::setChecked(bool flag) { QPushButton::setChecked(flag); } bool KPressButton::isChecked() const { return QPushButton::isChecked(); } void KPressButton::setButtonType(ButtonType type) { Q_D(KPressButton); d->m_pButtonType = type; } KPressButton::ButtonType KPressButton::buttonType() { Q_D(KPressButton); return d->m_pButtonType; } void KPressButton::setLoaingStatus(bool flag) { Q_D(KPressButton); d->m_pLoading = flag; if (flag) d->m_pTimer->start(); else d->m_pTimer->stop(); update(); } bool KPressButton::isLoading() { Q_D(KPressButton); return d->m_pLoading; } void KPressButton::setTranslucent(bool flag) { Q_D(KPressButton); d->m_isTranslucentFlag = flag; d->m_pTranslucent = flag; d->changeTheme(); } bool KPressButton::isTranslucent() { Q_D(KPressButton); return d->m_pTranslucent; } void KPressButton::paintEvent(QPaintEvent *event) { Q_D(KPressButton); QStyleOptionButton opt; initStyleOption(&opt); QPainter p(this); QColor borderColor; p.setRenderHint(QPainter::Antialiasing); p.setRenderHint(QPainter::TextAntialiasing); p.setRenderHint(QPainter::SmoothPixmapTransform); if (ThemeController::widgetTheme() == ClassicTheme) { d->m_pTranslucent = false; if (p.pen().width() == 1) p.translate(0.5, 0.5); } QColor startColor; QColor endColor; QLinearGradient m_linearGradient = QLinearGradient(rect().left() + rect().width()/2, rect().top(),rect().left() + rect().width()/2, rect().bottom()); if (d->m_pTranslucent) { if (isChecked() /*&& !isLoading()*/) { d->m_pbkgColor = ThemeController::getCustomColorFromDT("highlight-active"); m_linearGradient.setColorAt(0,d->m_pbkgColor); m_linearGradient.setColorAt(1,d->m_pbkgColor); } else { d->m_pbkgColor = ThemeController::getCustomColorFromDT("kcomponent-alpha-normal"); m_linearGradient.setColorAt(0,d->m_pbkgColor); m_linearGradient.setColorAt(1,d->m_pbkgColor); } if (opt.state.testFlag(QStyle::State_MouseOver) && isCheckable() /*&& !isLoading()*/) { if (isChecked()) { if (opt.state & QStyle::State_Sunken) { d->m_pbkgColor = ThemeController::mixColor(d->m_pbkgColor, ThemeController::getCustomColorFromDT("brighttext-active"), 0.2); // 点击变深 m_linearGradient.setColorAt(0,d->m_pbkgColor); m_linearGradient.setColorAt(1,d->m_pbkgColor); } else { d->m_pbkgColor = ThemeController::mixColor(d->m_pbkgColor, ThemeController::getCustomColorFromDT("brighttext-active"), 0.05); // 悬浮变浅 m_linearGradient.setColorAt(0,d->m_pbkgColor); m_linearGradient.setColorAt(1,d->m_pbkgColor); } } else { if (opt.state & QStyle::State_Sunken) { ThemeController::getGradientFromDT("kcomponent-alpha-click",startColor,endColor); // 点击变深 m_linearGradient.setColorAt(0,startColor); m_linearGradient.setColorAt(1,endColor); } else { ThemeController::getGradientFromDT("kcomponent-alpha-hover",startColor,endColor); // 悬浮变浅 m_linearGradient.setColorAt(0,startColor); m_linearGradient.setColorAt(1,endColor); } } } else if (opt.state.testFlag(QStyle::State_Selected)) { if (isChecked()) { d->m_pbkgColor = ThemeController::getCustomColorFromDT("highlight-active"); m_linearGradient.setColorAt(0,d->m_pbkgColor); m_linearGradient.setColorAt(1,d->m_pbkgColor); } else { ThemeController::getGradientFromDT("kcomponent-alpha-normal",startColor,endColor); m_linearGradient.setColorAt(0,startColor); m_linearGradient.setColorAt(1,endColor); } } } else // 关闭透明度 { if (isChecked() /*&& !isLoading()*/) { d->m_pbkgColor = ThemeController::getCustomColorFromDT("highlight-active"); m_linearGradient.setColorAt(0,d->m_pbkgColor); m_linearGradient.setColorAt(1,d->m_pbkgColor); } else { d->m_pbkgColor = ThemeController::getCustomColorFromDT("button-active"); m_linearGradient.setColorAt(0,d->m_pbkgColor); m_linearGradient.setColorAt(1,d->m_pbkgColor); } if (opt.state.testFlag(QStyle::State_MouseOver) && isCheckable() /*&& !isLoading()*/) { if (isChecked()) { if (opt.state & QStyle::State_Sunken) { d->m_pbkgColor = ThemeController::mixColor(d->m_pbkgColor, ThemeController::getCustomColorFromDT("brighttext-active"), 0.2); // 点击变深 m_linearGradient.setColorAt(0,d->m_pbkgColor); m_linearGradient.setColorAt(1,d->m_pbkgColor); } else { d->m_pbkgColor = ThemeController::mixColor(d->m_pbkgColor, ThemeController::getCustomColorFromDT("brighttext-active"), 0.05); // 悬浮变浅 m_linearGradient.setColorAt(0,d->m_pbkgColor); m_linearGradient.setColorAt(1,d->m_pbkgColor); } } else { if (opt.state & QStyle::State_Sunken) { ThemeController::getGradientFromDT("kcomponent-click",startColor,endColor); m_linearGradient.setColorAt(0,startColor); m_linearGradient.setColorAt(1,endColor); } else { ThemeController::getGradientFromDT("kcomponent-hover",startColor,endColor); m_linearGradient.setColorAt(0,startColor); m_linearGradient.setColorAt(1,endColor); } } } else if (opt.state.testFlag(QStyle::State_Selected)) { if (isChecked()) { d->m_pbkgColor = ThemeController::getCustomColorFromDT("highlight-active"); m_linearGradient.setColorAt(0,d->m_pbkgColor); m_linearGradient.setColorAt(1,d->m_pbkgColor); } else { d->m_pbkgColor = ThemeController::getCustomColorFromDT("button-active"); m_linearGradient.setColorAt(0,d->m_pbkgColor); m_linearGradient.setColorAt(1,d->m_pbkgColor); } } } if (opt.icon.name() != "ukui-loading-0.symbolic" && opt.icon.name() != "ukui-loading-1.symbolic" && opt.icon.name() != "ukui-loading-2.symbolic" && opt.icon.name() != "ukui-loading-3.symbolic" && opt.icon.name() != "ukui-loading-4.symbolic" && opt.icon.name() != "ukui-loading-5.symbolic" && opt.icon.name() != "ukui-loading-6.symbolic" && opt.icon.name() != "ukui-loading-7.symbolic") d->m_pIcon = opt.icon; QRect rect = this->rect(); QPainterPath path; switch (d->m_pButtonType) { case NormalType: if (ThemeController::widgetTheme() == ClassicTheme) { path.addRect(rect.adjusted(0, 0, -1, -1)); p.setPen(borderColor); } else { path.moveTo(rect.topLeft() + QPointF(0, d->m_pTopLeftRadius)); path.lineTo(rect.bottomLeft() - QPointF(0, d->m_pBottomLeftRadius)); path.quadTo(rect.bottomLeft(), rect.bottomLeft() + QPointF(d->m_pBottomLeftRadius, 0)); path.lineTo(rect.bottomRight() - QPointF(d->m_pBottomRightRadius, 0)); path.quadTo(rect.bottomRight(), rect.bottomRight() - QPointF(0, d->m_pBottomRightRadius)); path.lineTo(rect.topRight() + QPointF(0, d->m_pTopRightRadius)); path.quadTo(rect.topRight(), rect.topRight() - QPointF(d->m_pTopRightRadius, 0)); path.lineTo(rect.topLeft() + QPointF(d->m_pTopLeftRadius, 0)); path.quadTo(rect.topLeft(), rect.topLeft() + QPointF(0, d->m_pTopLeftRadius)); p.setPen(Qt::NoPen); } // if(ThemeController::widgetTheme() == FashionTheme && (opt.state & QStyle::State_Sunken || opt.state & QStyle::State_MouseOver) && !isChecked()) p.setBrush(m_linearGradient); // else // p.setBrush(d->m_pbkgColor); p.drawPath(path); break; case CircleType: if (ThemeController::widgetTheme() == ClassicTheme) p.setPen(borderColor); else p.setPen(Qt::NoPen); // if(ThemeController::widgetTheme() == FashionTheme && (opt.state & QStyle::State_Sunken || opt.state & QStyle::State_MouseOver) && !isChecked()) p.setBrush(m_linearGradient); // else // p.setBrush(d->m_pbkgColor); p.drawEllipse(rect.adjusted(1, 1, -1, -1)); default: break; } int iconSize = opt.iconSize.width(); if(!isEnabled()) { opt.icon = ThemeController::drawColoredPixmap(opt.icon.pixmap(iconSize, iconSize), ThemeController::getCustomColorFromDT("buttontext-disable")); d->m_pIcon = ThemeController::drawColoredPixmap(d->m_pIcon.pixmap(iconSize, iconSize), ThemeController::getCustomColorFromDT("buttontext-disable")); } else if (isChecked() || ThemeController::themeMode() == DarkTheme) { opt.icon = ThemeController::drawColoredPixmap(opt.icon.pixmap(iconSize, iconSize), ThemeController::getCustomColorFromDT("kwhite")); d->m_pIcon = ThemeController::drawColoredPixmap(d->m_pIcon.pixmap(iconSize, iconSize), ThemeController::getCustomColorFromDT("kwhite")); } else { opt.icon = ThemeController::drawColoredPixmap(opt.icon.pixmap(iconSize, iconSize), ThemeController::getCustomColorFromDT("kblack")); d->m_pIcon = ThemeController::drawColoredPixmap(d->m_pIcon.pixmap(iconSize, iconSize), ThemeController::getCustomColorFromDT("kblack")); } if (isLoading()) p.drawPixmap(rect.center().x() - iconSize / 2, rect.center().y() - iconSize / 2, iconSize, iconSize, opt.icon.pixmap(iconSize, iconSize)); // opt.icon loading else p.drawPixmap(rect.center().x() - iconSize / 2, rect.center().y() - iconSize / 2, iconSize, iconSize, d->m_pIcon.pixmap(iconSize, iconSize)); } } #include "kpressbutton.moc" #include "moc_kpressbutton.cpp" libkysdk-applications/kysdk-qtwidgets/src/kbubblewidget.cpp0000664000175000017500000002557615104543305023262 0ustar fengfeng/* * libkysdk-qtwidgets's Library * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhenyu Wang * */ #include "kbubblewidget.h" #include "themeController.h" #include #include #include #include #include #include "kshadowhelper.h" #include #include #include "kysdk-ukuiwindowhelper/ukuiwindowhelper.h" namespace kdk { class KBubbleWidgetPrivate : public QObject, public ThemeController { Q_OBJECT Q_DECLARE_PUBLIC(KBubbleWidget) public: KBubbleWidgetPrivate(KBubbleWidget *parent); private: KBubbleWidget *q_ptr; int m_startX; int m_startY; int m_tailWidth; int m_tailHeight; TailDirection m_tailDirection; TailLocation m_tailLocation; int m_topLeftRadius; int m_topRightRadius; int m_bottomLeftRadius; int m_bottomRightRadius; bool m_enableBlur; bool m_isHighlightBackground; qreal m_opacity; QGraphicsDropShadowEffect *m_shadowEffect; QRegion m_region; UkuiWindowHelper *m_ukuiWindowHelper; }; void KBubbleWidget::setTailPosition(TailDirection dirType, TailLocation locType) { Q_D(KBubbleWidget); d->m_tailDirection = dirType; d->m_tailLocation = locType; this->update(); } TailDirection KBubbleWidget ::tailDirection() { Q_D(KBubbleWidget); return d->m_tailDirection; } TailLocation KBubbleWidget::tailLocation() { Q_D(KBubbleWidget); return d->m_tailLocation; } void KBubbleWidget::setBorderRadius(int bottomLeft, int topLeft, int topRight, int bottomRight) { Q_D(KBubbleWidget); d->m_bottomRightRadius = bottomRight; d->m_topLeftRadius = topLeft; d->m_bottomLeftRadius = bottomLeft; d->m_topRightRadius = topRight; } void KBubbleWidget::setBorderRadius(int radius) { Q_D(KBubbleWidget); d->m_topLeftRadius = radius; d->m_bottomLeftRadius = radius; d->m_bottomRightRadius = radius; d->m_topRightRadius = radius; } void KBubbleWidget::setEnableBlur(bool flag) { Q_D(KBubbleWidget); d->m_enableBlur = flag; } bool KBubbleWidget::enableBlur() { Q_D(KBubbleWidget); return d->m_enableBlur; } void KBubbleWidget::setOpacity(qreal opacity) { Q_D(KBubbleWidget); if (opacity < 0 || opacity > 1) return; d->m_opacity = opacity; } qreal KBubbleWidget::opacity() { Q_D(KBubbleWidget); return d->m_opacity; } void KBubbleWidget::setHighlightBackground(bool flag) { Q_D(KBubbleWidget); d->m_isHighlightBackground = flag; update(); } KBubbleWidget::KBubbleWidget(QWidget *parent) : QWidget(parent) , d_ptr(new KBubbleWidgetPrivate(this)) { Q_D(KBubbleWidget); setWindowFlags(Qt::FramelessWindowHint); setAttribute(Qt::WA_TranslucentBackground); // effects::KShadowHelper::self()->setWidget(this); d->m_shadowEffect = new QGraphicsDropShadowEffect(this); d->m_shadowEffect->setBlurRadius(12); d->m_shadowEffect->setColor(ThemeController::getCustomColorFromDT("text-disable")); d->m_shadowEffect->setOffset(0, 0); setGraphicsEffect(d->m_shadowEffect); d->m_ukuiWindowHelper = new UkuiWindowHelper(this); } void KBubbleWidget::setTailSize(const QSize &size) { Q_D(KBubbleWidget); d->m_tailWidth = size.width(); d->m_tailHeight = size.height(); } QSize KBubbleWidget::tailSize() { Q_D(KBubbleWidget); QSize size; size.setWidth(d->m_tailWidth); size.setHeight(d->m_tailHeight); return size; } void KBubbleWidget ::paintEvent(QPaintEvent *) { Q_D(KBubbleWidget); QPainter painter(this); painter.setPen(Qt::NoPen); painter.setBrush(Qt::NoBrush); painter.drawRoundedRect(rect(), 0, 0); QPolygon trianglePolygon; QPainterPath path; QRect targetRect = this->rect()/*.adjusted(8,8,-8,-8)*/; switch (d->m_tailDirection) { case TopDirection: targetRect = targetRect.adjusted(8, d->m_tailHeight, -8, -8); if (d->m_tailLocation == LeftLocation) d->m_startX = 18; else if (d->m_tailLocation == MiddleLocation) d->m_startX = (targetRect.width() - d->m_tailWidth * 2) / 2; else if (d->m_tailLocation == RightLocation) d->m_startX = targetRect.width() - d->m_tailHeight * 2 - d->m_tailWidth - 19; d->m_startY = 0; trianglePolygon << QPoint(d->m_startX + d->m_tailHeight, d->m_tailHeight); trianglePolygon << QPoint(d->m_startX + d->m_tailWidth / 2 + d->m_tailHeight, 0); trianglePolygon << QPoint(d->m_startX + d->m_tailWidth + d->m_tailHeight, d->m_tailHeight); setContentsMargins(4, 4 + d->m_tailHeight, 4, 4); break; case LeftDirection: targetRect = targetRect.adjusted(d->m_tailHeight, 8, -8, -8); if (d->m_tailLocation == LeftLocation) d->m_startY = d->m_tailHeight + 18; else if (d->m_tailLocation == MiddleLocation) d->m_startY = targetRect.height() / 2 - d->m_tailWidth / 2; else if (d->m_tailLocation == RightLocation) d->m_startY = d->m_tailHeight + static_cast((targetRect.height() - d->m_tailHeight * 2 - d->m_tailWidth)) - 19; d->m_startX = 0; trianglePolygon << QPoint(d->m_startX + d->m_tailHeight, d->m_startY); trianglePolygon << QPoint(d->m_startX, d->m_startY + d->m_tailWidth / 2); trianglePolygon << QPoint(d->m_startX + d->m_tailHeight, d->m_startY + d->m_tailWidth); setContentsMargins(4 + d->m_tailHeight, 4, 4, 4); break; case RightDirection: targetRect = targetRect.adjusted(8, 8, -d->m_tailHeight, -8); if (d->m_tailLocation == LeftLocation) d->m_startY = d->m_tailHeight + 18; else if (d->m_tailLocation == MiddleLocation) d->m_startY = targetRect.height() / 2 - d->m_tailWidth / 2; else if (d->m_tailLocation == RightLocation) d->m_startY = d->m_tailHeight + static_cast((targetRect.height() - d->m_tailHeight * 2 - d->m_tailWidth)) - 19; d->m_startX = targetRect.width(); trianglePolygon << QPoint(d->m_startX - 1, d->m_startY); trianglePolygon << QPoint(d->m_startX + d->m_tailHeight - 1, d->m_startY + d->m_tailWidth / 2); trianglePolygon << QPoint(d->m_startX - 1, d->m_startY + d->m_tailWidth); setContentsMargins(4, 4, 4 + d->m_tailHeight, 4); break; case BottomDirection: targetRect = targetRect.adjusted(8, 8, -8, -d->m_tailHeight); if (d->m_tailLocation == LeftLocation) d->m_startX = 18; else if (d->m_tailLocation == MiddleLocation) d->m_startX = (this->rect().width() - d->m_tailWidth * 2) / 2; else if (d->m_tailLocation == RightLocation) d->m_startX = this->rect().width() - d->m_tailHeight * 2 - d->m_tailWidth - 19; d->m_startY = this->rect().height(); trianglePolygon << QPoint(d->m_startX + d->m_tailHeight, d->m_startY - d->m_tailHeight - 1); trianglePolygon << QPoint(d->m_startX + d->m_tailWidth / 2 + d->m_tailHeight, d->m_startY - 1); trianglePolygon << QPoint(d->m_startX + d->m_tailWidth + d->m_tailHeight, d->m_startY - d->m_tailHeight - 1); setContentsMargins(4, 4, 4, 4 + d->m_tailHeight); break; case None: break; } path.moveTo(targetRect.topRight() - QPoint(d->m_topRightRadius, 0)); // 右上 path.lineTo(targetRect.topLeft() + QPointF(d->m_topLeftRadius, 0)); // 上方线 path.quadTo(targetRect.topLeft(), targetRect.topLeft() + QPointF(0, d->m_topLeftRadius)); // 圆角 path.lineTo(targetRect.bottomLeft() + QPointF(0, -d->m_bottomLeftRadius)); // 左方线 path.quadTo(targetRect.bottomLeft(), targetRect.bottomLeft() + QPointF(d->m_bottomLeftRadius, 0)); // 圆角 path.lineTo(targetRect.bottomRight() - QPointF(d->m_bottomRightRadius, 0)); // 下方线 path.quadTo(targetRect.bottomRight(), targetRect.bottomRight() + QPointF(0, -d->m_bottomRightRadius)); // 圆角 path.lineTo(targetRect.topRight() + QPointF(0, d->m_topRightRadius)); // 右方线 path.quadTo(targetRect.topRight(), targetRect.topRight() - QPointF(d->m_topRightRadius, 0)); // 圆角 path.addPolygon(trianglePolygon); path = path.simplified(); // 合并subpath,取消交集部分的线 painter.setRenderHints(QPainter::Antialiasing); if (d->m_enableBlur && !d->m_isHighlightBackground && isActiveWindow()) { // 开启毛玻璃时 d->m_region = QRegion(path.toFillPolygon().toPolygon()); #ifdef USE_UKUI_SHELL_PLUGIN d->m_ukuiWindowHelper->setBlurEffect(d->m_region, 0, true); #else KWindowEffects::enableBlurBehind(this->winId(), true, d->m_region); #endif this->setMask(rect()); painter.setOpacity(d->m_opacity); painter.setBrush(Qt::NoBrush); } else { // 未开启毛玻璃时 painter.setOpacity(1); #ifdef USE_UKUI_SHELL_PLUGIN d->m_ukuiWindowHelper->setBlurEffect(d->m_region, 0, false); #else KWindowEffects::enableBlurBehind(this->winId(), false, d->m_region); #endif if (d->m_isHighlightBackground) painter.setBrush(ThemeController::getCustomColorFromDT("highlight-active")); else painter.setBrush(ThemeController::getCustomColorFromDT("kmenu"));//ThemeController::getCustomColorFromDT("base-active")); } QPen pen; pen.setJoinStyle(Qt::RoundJoin); pen.setWidthF(1); pen.setColor(Qt::transparent); painter.translate(0.5, 0.5); painter.setPen(pen); painter.drawPath(path); } KBubbleWidgetPrivate::KBubbleWidgetPrivate(KBubbleWidget *parent) : q_ptr(parent) , m_tailHeight(8) , m_tailWidth(16) , m_enableBlur(false) , m_opacity(0.5) , m_isHighlightBackground(false) , m_tailLocation(TailLocation::LeftLocation) , m_tailDirection(TailDirection::BottomDirection) { Q_Q(KBubbleWidget); int radius = ThemeController::getRadiusFromDT("kradius-menu"); if (radius == -1) { m_bottomLeftRadius = 8; m_topLeftRadius = 8; m_bottomRightRadius = 8; m_topRightRadius = 8; } else { m_bottomLeftRadius = radius; m_topLeftRadius = radius; m_bottomRightRadius = radius; m_topRightRadius = radius; } } } #include "kbubblewidget.moc" #include "moc_kbubblewidget.cpp" libkysdk-applications/kysdk-qtwidgets/src/kpressbutton.h0000664000175000017500000000536115104543305022646 0ustar fengfeng/* * libkysdk-qtwidgets's Library * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhenyu Wang * */ #ifndef KPRESSBUTTON_H #define KPRESSBUTTON_H #include "gui_g.h" #include #include namespace kdk { /** * @defgroup PushbuttonModule */ class KPressButtonPrivate; /** * @brief 按压按钮,可根据情况设置loading状态 * @since 1.2.0 */ class GUI_EXPORT KPressButton : public QPushButton { Q_OBJECT public: enum ButtonType { NormalType, CircleType }; KPressButton(QWidget *parent = 0); /** * @brief 设置圆角 * @param radius */ void setBorderRadius(int radius); /** * @brief 设置圆角 * @param buttomLeft * @param topLeft * @param topRight * @param bottomRight */ void setBorderRadius(int bottomLeft, int topLeft, int topRight, int bottomRight); /** * @brief 设置是否可选中 * @param flag */ void setCheckable(bool); /** * @brief 返回是否可选中 * @return */ bool isCheckable() const; /** * @brief 设置是否选中 * @return */ void setChecked(bool); /** * @brief 返回是否选中 * @return */ bool isChecked() const; /** * @brief 设置button类型 * @param type */ void setButtonType(ButtonType type); /** * @brief 返回button类型 * @return */ KPressButton::ButtonType buttonType(); /** * @brief 设置是否启用loading状态 * @param flag */ void setLoaingStatus(bool flag); /** * @brief 返回是否启用loading状态 * @return */ bool isLoading(); /** * @brief 设置是否启用透明度 * @param flag */ void setTranslucent(bool flag); /** * @brief 返回是否启用透明度 * @return */ bool isTranslucent(); protected: void paintEvent(QPaintEvent *event) override; private: Q_DECLARE_PRIVATE(KPressButton) KPressButtonPrivate *const d_ptr; }; } #endif // KPRESSBUTTON_H libkysdk-applications/kysdk-qtwidgets/src/ktoolbar.h0000664000175000017500000000417515104543305021722 0ustar fengfeng/* * libkysdk-qtwidgets's Library * * Copyright (C) 2024, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhenyu Wang * */ #ifndef KTOOLBAR_H #define KTOOLBAR_H #include "gui_g.h" #include "ktoolbutton.h" #include #include namespace kdk { class KToolBarPrivate; /** * @since 2.5.2.0 */ class GUI_EXPORT KToolBar : public QWidget { Q_OBJECT public: KToolBar(QWidget *parent = nullptr); Qt::Orientation orientation(); void setOrientation(Qt::Orientation orientation); KToolButton *addButton(QIcon icon); KToolButton *addButton(QString string); // KToolButton* addButton (const QIcon&icon ,const QString text = QString()); QList addButton(QList list); QList addButton(QList list); QList buttonList(); void removeButton(KToolButton *button); void removeButton(int id); void removeButton(QList list); void setBorderRadius(int radius); int borderRadius(); void setExclusive(bool); bool exclusive(); void setCheckable(bool flag); bool isCheckable(); QList checkedButton(); void setLineVisible(bool flag); bool isLineVisible(); void setBackgroundColorEnabled(bool flag); bool backgroundColorEnabled(); protected: void paintEvent(QPaintEvent *event); private: Q_DECLARE_PRIVATE(KToolBar) KToolBarPrivate *const d_ptr; }; } #endif // KTOOLBAR_H libkysdk-applications/kysdk-qtwidgets/src/kborderlessbutton.cpp0000664000175000017500000001566515104543305024221 0ustar fengfeng/* * libkysdk-qtwidgets's Library * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #include "kborderlessbutton.h" #include "themeController.h" #include #include #include namespace kdk { class KBorderlessButtonPrivate : public QObject, public ThemeController { Q_DECLARE_PUBLIC(KBorderlessButton) Q_OBJECT public: KBorderlessButtonPrivate(KBorderlessButton *parent) : q_ptr(parent) , m_hoverd(false) { setParent(parent); } protected: void changeTheme(); private: KBorderlessButton *q_ptr; bool m_hoverd; }; KBorderlessButton::KBorderlessButton(QWidget *parent) : QPushButton(parent) , d_ptr(new KBorderlessButtonPrivate(this)) { Q_D(KBorderlessButton); setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); setFocusPolicy(Qt::NoFocus); } KBorderlessButton::KBorderlessButton(const QString &text, QWidget *parent) : KBorderlessButton(parent) { setText(text); } KBorderlessButton::KBorderlessButton(const QIcon &icon, const QString &text, QWidget *parent) : KBorderlessButton(parent) { setIcon(icon); setText(text); } KBorderlessButton::KBorderlessButton(const QIcon &icon, QWidget *parent) : KBorderlessButton(parent) { setIcon(icon); } KBorderlessButton::~KBorderlessButton() { } void KBorderlessButton::setIcon(const QIcon &icon) { Q_D(KBorderlessButton); QPushButton::setIcon(icon); d->changeTheme(); } bool KBorderlessButton::eventFilter(QObject *watched, QEvent *event) { Q_D(KBorderlessButton); return QPushButton::eventFilter(watched, event); } void KBorderlessButton::paintEvent(QPaintEvent *event) { Q_D(KBorderlessButton); QStyleOptionButton option; initStyleOption(&option); QPainter p(this); QColor fontColor; QColor highlight = ThemeController::getCustomColorFromDT("highlight-active"); QColor startColor; QColor endColor; if (!option.state.testFlag(QStyle::State_Enabled)) { fontColor = ThemeController::getCustomColorFromDT("kfont-primary-disable"); } else { if (option.state.testFlag(QStyle::State_MouseOver)) { if (option.state.testFlag(QStyle::State_Sunken)) { ThemeController::getGradientFromDT("kbrand-click",startColor,endColor); fontColor = startColor; } else { ThemeController::getGradientFromDT("kbrand-hover",startColor,endColor); fontColor = startColor; } } else { if (!this->icon().isNull()) { fontColor = ThemeController::getCustomColorFromDT("kfont-primary"); } else { fontColor = highlight; } } } p.setBrush(Qt::NoBrush); p.setRenderHint(QPainter::Antialiasing); p.setRenderHint(QPainter::TextAntialiasing); p.setRenderHint(QPainter::SmoothPixmapTransform); QPen pen; pen.setCapStyle(Qt::RoundCap); pen.setJoinStyle(Qt::RoundJoin); pen.setWidth(1); pen.setColor(fontColor); p.setPen(pen); QPoint point; // bug 170516 修正1px QRect ir = option.rect.adjusted(0, 0, -1, 0); uint tf = Qt::AlignVCenter; if (!option.icon.isNull()) { // Center both icon and text QIcon::Mode mode = option.state & QStyle::State_Enabled ? QIcon::Normal : QIcon::Disabled; if (mode == QIcon::Normal && option.state & QStyle::State_HasFocus) mode = QIcon::Active; QIcon::State state = QIcon::Off; if (option.state & QStyle::State_On) state = QIcon::On; QPixmap pixmap = option.icon.pixmap(option.iconSize, mode, state); pixmap = ThemeController::drawColoredPixmap(pixmap, fontColor); int w = pixmap.width() / pixmap.devicePixelRatio(); int h = pixmap.height() / pixmap.devicePixelRatio(); if (!option.text.isEmpty()) w += option.fontMetrics.boundingRect(option.rect, tf, option.text).width() + 2; point = QPoint(ir.x() + ir.width() / 2 - w / 2, ir.y() + ir.height() / 2 - h / 2); w = pixmap.width() / pixmap.devicePixelRatio(); if (option.direction == Qt::RightToLeft) point.rx() += w; if (option.direction == Qt::RightToLeft) ir.translate(-point.x() - 2, 0); else ir.translate(point.x() + w + 4, 0); // left-align text if there is if (!option.text.isEmpty()) tf |= Qt::AlignLeft; QFontMetrics fm = option.fontMetrics; int width = option.iconSize.width(); int height = option.iconSize.height(); if (fm.horizontalAdvance(option.text) > option.rect.width() - width - 4) { QRect rect(option.rect.x(), (option.rect.height() - height) / 2, width, height); p.drawPixmap(rect, pixmap); QRect rect1(width + 4, 0, option.rect.width() - width - 4, option.rect.height()); QString elidedText1 = fm.elidedText(option.text, Qt::ElideRight, option.rect.width() - width - 4); p.drawText(rect1, tf, elidedText1); if (toolTip().isNull()) setToolTip(option.text); } else { p.drawPixmap(this->style()->visualPos(option.direction, option.rect, point), pixmap); p.drawText(ir, tf, option.text); } } else { tf |= Qt::AlignHCenter; QFontMetrics fm = option.fontMetrics; QString elidedText = fm.elidedText(option.text, Qt::ElideRight, option.rect.width()); p.drawText(option.rect, tf, elidedText); if (fm.horizontalAdvance(option.text) > option.rect.width()) setToolTip(option.text); } } QSize KBorderlessButton::sizeHint() const { QSize size = QPushButton::sizeHint(); QFontMetrics fm(this->font()); if (this->icon().isNull()) size.setWidth(fm.horizontalAdvance(this->text()) + 2); else { int width = fm.horizontalAdvance(this->text()) + this->iconSize().width() + 4; size.setWidth(width); } return size; } void KBorderlessButtonPrivate::changeTheme() { Q_Q(KBorderlessButton); initThemeStyle(); } } #include "kborderlessbutton.moc" #include "moc_kborderlessbutton.cpp" libkysdk-applications/kysdk-qtwidgets/src/klistview.h0000664000175000017500000000255515104543305022126 0ustar fengfeng/* * libkysdk-qtwidgets's Library * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhenyu Wang * */ #ifndef KLISTVIEW_H #define KLISTVIEW_H #include #include namespace kdk { /** * @defgroup ListViewModule */ class KListViewPrivate; /** * @brief 配合KListviewdelegate可以提供一个图片两行文字的显示效果,若只有一行文字,则对于 icon 居中显示 。 * @since 1.2.0 */ class KListView : public QListView { Q_OBJECT public: KListView(QWidget *parent); protected: void mousePressEvent(QMouseEvent *event); private: Q_DECLARE_PRIVATE(KListView); KListViewPrivate *const d_ptr; }; } #endif // KLISTVIEW_H libkysdk-applications/kysdk-qtwidgets/src/kcolorcombobox.cpp0000664000175000017500000002146515104543305023463 0ustar fengfeng/* * libkysdk-qtwidgets's Library * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #include "kcolorcombobox.h" #include "themeController.h" #include #include #include #include #include #include #include #include #include namespace kdk { const static QSize defaultPopupItemSize(20, 20); static QSize g_size; class KComboStyle : public QProxyStyle { public: KComboStyle() { } ~KComboStyle() { } QSize sizeFromContents(QStyle::ContentsType type, const QStyleOption *option, const QSize &contentsSize, const QWidget *widget = nullptr) const override; }; class KColorComboBoxDelegate : public QStyledItemDelegate { Q_OBJECT public: enum ItemRoles { ColorRole = Qt::UserRole + 1 }; KColorComboBoxDelegate(QObject *parent = nullptr, KColorComboBox *combo = nullptr); void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override; QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const override; private: KColorComboBox *m_combo; }; class KColorComboBoxPrivate : public QObject, public ThemeController { Q_OBJECT Q_DECLARE_PUBLIC(KColorComboBox) public: KColorComboBoxPrivate(KColorComboBox *parent); void updateList(); public Q_SLOTS: void slotActivated(int); void slotHighlighted(int); void slotCurrentIndexChanged(int); private: KColorComboBox *q_ptr; KColorComboBox::ComboType m_comboType; QList m_colorList; int m_borderRadius; QColor m_currentColor; QSize m_popupItemSize; }; KColorComboBox::KColorComboBox(QWidget *parent) : QComboBox(parent) , d_ptr(new KColorComboBoxPrivate(this)) { Q_D(KColorComboBox); setItemDelegate(new KColorComboBoxDelegate(this, this)); KComboStyle *style = new KComboStyle(); setStyle(style); view()->setFixedWidth(d->m_popupItemSize.width()); connect(this, SIGNAL(activated(int)), d, SLOT(slotActivated(int))); connect(this, SIGNAL(highlighted(int)), d, SLOT(slotHighlighted(int))); connect(this, SIGNAL(currentIndexChanged(int)), d, SLOT(slotCurrentIndexChanged(int))); } void KColorComboBox::setColorList(const QList &list) { Q_D(KColorComboBox); d->m_colorList = list; d->updateList(); } QList KColorComboBox::colorList() { Q_D(KColorComboBox); return d->m_colorList; } void KColorComboBox::addColor(const QColor &color) { Q_D(KColorComboBox); d->m_colorList.append(color); addItem(QString()); setItemData(d->m_colorList.count() - 1, d->m_colorList.back(), KColorComboBoxDelegate::ColorRole); update(); } void KColorComboBox::setComboType(const KColorComboBox::ComboType &type) { Q_D(KColorComboBox); d->m_comboType = type; update(); } KColorComboBox::ComboType KColorComboBox::comboType() { Q_D(KColorComboBox); return d->m_comboType; } void KColorComboBox::setPopupItemSize(const QSize &size) { Q_D(KColorComboBox); d->m_popupItemSize = size.expandedTo(this->size()); g_size = d->m_popupItemSize; if (QListView *listView = qobject_cast(view())) { listView->setFixedWidth(d->m_popupItemSize.width()); listView->setGridSize(d->m_popupItemSize); } view()->updateGeometry(); update(); } QSize KColorComboBox::popupItemSzie() { Q_D(KColorComboBox); return d->m_popupItemSize; } void KColorComboBox::paintEvent(QPaintEvent *event) { Q_UNUSED(event) Q_D(KColorComboBox); QStylePainter painter(this); painter.setPen(Qt::NoPen); QStyleOptionComboBox opt; initStyleOption(&opt); QRect frame = this->rect(); painter.setRenderHint(QPainter::Antialiasing); painter.setPen(Qt::transparent); if (d->m_currentColor.isValid()) painter.setBrush(d->m_currentColor); if (d->m_comboType == KColorComboBox::Circle) { painter.drawEllipse(frame.adjusted(1, 1, -1, -1)); } else { painter.drawRoundedRect(frame.adjusted(1, 1, -1, -1), d->m_borderRadius, d->m_borderRadius); } } void KColorComboBox::resizeEvent(QResizeEvent *event) { setPopupItemSize(event->size()); QComboBox::resizeEvent(event); } KColorComboBoxPrivate::KColorComboBoxPrivate(KColorComboBox *parent) : q_ptr(parent) , m_comboType(KColorComboBox::Circle) , m_popupItemSize(defaultPopupItemSize) { setParent(parent); m_borderRadius = ThemeController::getRadiusFromDT("kradius-min"); if (m_borderRadius == -1) m_borderRadius = 4; } void KColorComboBoxPrivate::updateList() { Q_Q(KColorComboBox); while (q->count()) { q->removeItem(0); } for (int i = 0; i < m_colorList.count(); ++i) { q->addItem(QString()); q->setItemData(i, m_colorList[i], KColorComboBoxDelegate::ColorRole); } q->update(); } void KColorComboBoxPrivate::slotActivated(int index) { Q_Q(KColorComboBox); m_currentColor = m_colorList[index]; q->update(); Q_EMIT q->activated(m_currentColor); } void KColorComboBoxPrivate::slotHighlighted(int index) { Q_Q(KColorComboBox); auto color = m_colorList[index]; q->update(); Q_EMIT q->highlighted(color); } void KColorComboBoxPrivate::slotCurrentIndexChanged(int index) { Q_Q(KColorComboBox); m_currentColor = m_colorList[index]; q->update(); Q_EMIT q->currentColorChanged(m_currentColor); } KColorComboBoxDelegate::KColorComboBoxDelegate(QObject *parent, KColorComboBox *combo) : QStyledItemDelegate(parent) , m_combo(combo) { } void KColorComboBoxDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const { auto variant = index.data(ItemRoles::ColorRole); auto color = variant.value(); auto paintRect = option.rect.adjusted(5, 5, -5, -5); switch (m_combo->comboType()) { case KColorComboBox::Circle: { if (color.isValid()) { painter->save(); painter->setRenderHint(QPainter::Antialiasing); painter->setPen(Qt::NoPen); painter->setBrush(color); painter->drawEllipse(paintRect); painter->restore(); } if (option.state & (QStyle::State_MouseOver | QStyle::State_Selected)) { painter->save(); painter->setRenderHint(QPainter::Antialiasing); painter->setPen(Qt::NoPen); painter->setBrush(Qt::white); QRect subRect(paintRect.top(), paintRect.left(), paintRect.width() / 2, paintRect.height() / 2); subRect.moveCenter(paintRect.center()); painter->drawEllipse(subRect); painter->restore(); } break; } case KColorComboBox::RoundedRect: { if (color.isValid()) { painter->save(); painter->setRenderHint(QPainter::Antialiasing); if (option.state & (QStyle::State_MouseOver | QStyle::State_Selected)) { QPen pen; pen.setWidth(2); pen.setBrush(Qt::white); painter->setBrush(color); painter->setPen(pen); } else { painter->setBrush(color); painter->setPen(Qt::NoPen); } int radius = ThemeController::getRadiusFromDT("kradius-min"); if (radius == -1) radius = 4; painter->drawRoundedRect(paintRect, radius, radius); painter->restore(); } break; } default: break; } } QSize KColorComboBoxDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const { return m_combo->popupItemSzie(); } QSize KComboStyle::sizeFromContents(QStyle::ContentsType type, const QStyleOption *option, const QSize &contentsSize, const QWidget *widget) const { if (type == QStyle::CT_ComboBox) return g_size; return QProxyStyle::sizeFromContents(type, option, contentsSize, widget); } } #include "kcolorcombobox.moc" #include "moc_kcolorcombobox.cpp" libkysdk-applications/kysdk-qtwidgets/src/ktableview.h0000664000175000017500000000331615104543305022236 0ustar fengfeng/* * libkysdk-qtwidgets's Library * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhenyu Wang * */ #ifndef KTABLEVIEW_H #define KTABLEVIEW_H #include "ktableheaderview.h" #include namespace kdk { /** * @defgroup ContainerModules * @brief 继承qtbaleview * @since 2.5.2.0 * { */ class KTableViewPrivate; class KTableView : public QTableView { Q_OBJECT public: KTableView(QWidget *parent = nullptr); /** * @brief 设置水平标题 * @param list */ void setHorizontalTitle(QStringList list); /** * @brief 返回水平标题栏 * @return */ KTableHeaderView *headerView(); /** * @brief 返回所有选中item的行索引 * @return */ QList selectList(); Q_SIGNALS: void hoverIndexChanged(QModelIndex index); protected: void mouseMoveEvent(QMouseEvent *event); bool eventFilter(QObject *object, QEvent *event); private: Q_DECLARE_PRIVATE(KTableView) KTableViewPrivate *const d_ptr; }; } #endif // KTABLEVIEW_H libkysdk-applications/kysdk-qtwidgets/src/kdialog.h0000664000175000017500000000536315104543305021517 0ustar fengfeng/* * libkysdk-qtwidgets's Library * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #ifndef KDIALOG_H #define KDIALOG_H #include "gui_g.h" #include "kiconbar.h" #include "kwindowbuttonbar.h" #include "themeController.h" #include #include #include namespace kdk { /** @defgroup DialogBoxModule * @{ */ class KDialogPrivate; /** * @brief 继承自 QDialog,支持响应式主题背景切换和图标主题切换、 标题颜色响应窗口激活状态 * @since 1.0.0 */ class GUI_EXPORT KDialog : public QDialog, public ThemeController { Q_OBJECT public: explicit KDialog(QWidget *parent = nullptr); ~KDialog(); /** * @brief 设置对话框图标 * @param icon */ void setWindowIcon(const QIcon &icon); /** * @brief 设置对话框图标 * @param iconName */ void setWindowIcon(const QString &iconName); /** * @brief 设置对话框标题名称 * @param widgetName */ void setWindowTitle(const QString &); /** * @brief 获取最大化按钮 * @return */ QPushButton *maximumButton(); /** * @brief 获取最小化按钮 * @return */ QPushButton *minimumButton(); /** * @brief 获取关闭按钮 * @return */ QPushButton *closeButton(); /** * @brief 获取下拉菜单按钮 * @return */ KMenuButton *menuButton(); /** * @brief 获取主内容区Widget * @return */ QWidget *mainWidget(); /** * @brief windowButtonBar * @return * @2.5.2.0 */ KWindowButtonBar *windowButtonBar(); /** * @brief iconBar * @return * @2.5.2.0 */ KIconBar *iconBar(); protected: bool eventFilter(QObject *target, QEvent *event) override; void changeTheme(); void changeIconStyle(); QBoxLayout *mainLayout(); private: Q_DECLARE_PRIVATE(KDialog) KDialogPrivate *const d_ptr; }; } /** * @example testDialog/widget.h * @example testDialog/widget.cpp * @} */ #endif // KDIALOG_H libkysdk-applications/kysdk-qtwidgets/src/kiconbar.h0000664000175000017500000000431515104543305021671 0ustar fengfeng/* * libkysdk-qtwidgets's Library * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #ifndef KICONBAR_H #define KICONBAR_H #include "gui_g.h" #include #include #include #include namespace kdk { /** @defgroup BarModule * @{ */ class KIconBarPrivate; /** * @brief 图标和标题组合控件 * @since 1.0.0 */ class GUI_EXPORT KIconBar : public QFrame { Q_OBJECT public: KIconBar(QWidget *parent = nullptr); KIconBar(const QString &iconName, const QString &text, QWidget *parent = nullptr); ~KIconBar(); /** * @brief 设置图标 * @param iconName */ void setIcon(const QString &iconName); /** * @brief 设置图标 * @param icon */ void setIcon(const QIcon &icon); /** * @brief 设置标题 * @param widgetName */ void setWidgetName(const QString &widgetName); /** * @brief 获取标题label * @return */ QLabel *nameLabel(); /** * @brief 获取图标label * @return */ QLabel *iconLabel(); Q_SIGNALS: /** * @brief 双击会发出双击信号,父widget可以绑定相应槽函数 */ void doubleClick(); protected: void mouseDoubleClickEvent(QMouseEvent *event); void resizeEvent(QResizeEvent *event); QSize sizeHint() const override; private: Q_DECLARE_PRIVATE(KIconBar) KIconBarPrivate *const d_ptr; }; } /** * @example testWidget/testwidget.h * @example testWidget/testwidget.cpp * @} */ #endif // KICONBAR_H libkysdk-applications/kysdk-qtwidgets/src/xatom-helper.cpp0000664000175000017500000001476215104543305023050 0ustar fengfeng/* * KWin Style UKUI * * Copyright (C) 2020, KylinSoft Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authors: Yue Lan */ #include #include #include #include #include #include "xatom-helper.h" // #include using namespace kdk; static XAtomHelper *global_instance = nullptr; class X11Display { public: static Display *display(); static void closeDisplay(); private: static Display *s_display; }; Display *X11Display::s_display = nullptr; Display *X11Display::display() { if (!s_display) { s_display = XOpenDisplay(nullptr); if (s_display) { atexit(closeDisplay); } } return s_display; } void X11Display::closeDisplay() { if (s_display) { XCloseDisplay(s_display); s_display = nullptr; } } XAtomHelper *XAtomHelper::getInstance() { if (!global_instance) global_instance = new XAtomHelper; return global_instance; } bool XAtomHelper::isFrameLessWindow(int winId) { auto hints = getInstance()->getWindowMotifHint(winId); if (hints.flags == MWM_HINTS_DECORATIONS && hints.functions == 1) { return true; } return false; } bool XAtomHelper::isWindowDecorateBorderOnly(int winId) { return isWindowMotifHintDecorateBorderOnly(getInstance()->getWindowMotifHint(winId)); } bool XAtomHelper::isWindowMotifHintDecorateBorderOnly(const MotifWmHints &hint) { bool isDeco = false; if (hint.flags & MWM_HINTS_DECORATIONS && hint.flags != MWM_HINTS_DECORATIONS) { if (hint.decorations == MWM_DECOR_BORDER) isDeco = true; } return isDeco; } bool XAtomHelper::isUKUICsdSupported() { // fixme: return false; } bool XAtomHelper::isUKUIDecorationWindow(int winId) { if (m_ukuiDecorationAtion == None) return false; Atom type; int format; ulong nitems; ulong bytes_after; uchar *data; bool isUKUIDecoration = false; XGetWindowProperty(X11Display::display(), winId, m_ukuiDecorationAtion, 0, LONG_MAX, false, m_ukuiDecorationAtion, &type, &format, &nitems, &bytes_after, &data); if (type == m_ukuiDecorationAtion) { if (nitems == 1) { isUKUIDecoration = data[0]; } } return isUKUIDecoration; } UnityCorners XAtomHelper::getWindowBorderRadius(int winId) { UnityCorners corners; Atom type; int format; ulong nitems; ulong bytes_after; uchar *data; if (m_unityBorderRadiusAtom != None) { XGetWindowProperty(X11Display::display(), winId, m_unityBorderRadiusAtom, 0, LONG_MAX, false, XA_CARDINAL, &type, &format, &nitems, &bytes_after, &data); if (type == XA_CARDINAL) { if (nitems == 4) { corners.topLeft = static_cast(data[0]); corners.topRight = static_cast(data[1 * sizeof(ulong)]); corners.bottomLeft = static_cast(data[2 * sizeof(ulong)]); corners.bottomRight = static_cast(data[3 * sizeof(ulong)]); } XFree(data); } } return corners; } void XAtomHelper::setWindowBorderRadius(int winId, const UnityCorners &data) { if (m_unityBorderRadiusAtom == None) return; ulong corners[4] = {data.topLeft, data.topRight, data.bottomLeft, data.bottomRight}; XChangeProperty(X11Display::display(), winId, m_unityBorderRadiusAtom, XA_CARDINAL, 32, 0, (const unsigned char *)&corners, sizeof(corners) / sizeof(corners[0])); } void XAtomHelper::setWindowBorderRadius(int winId, int topLeft, int topRight, int bottomLeft, int bottomRight) { if (m_unityBorderRadiusAtom == None) return; ulong corners[4] = {(ulong)topLeft, (ulong)topRight, (ulong)bottomLeft, (ulong)bottomRight}; XChangeProperty(X11Display::display(), winId, m_unityBorderRadiusAtom, XA_CARDINAL, 32, 0, (const unsigned char *)&corners, sizeof(corners) / sizeof(corners[0])); } void XAtomHelper::setUKUIDecoraiontHint(int winId, bool set) { if (m_ukuiDecorationAtion == None) return; XChangeProperty(X11Display::display(), winId, m_ukuiDecorationAtion, m_ukuiDecorationAtion, 32, 0, (const unsigned char *)&set, 1); } void XAtomHelper::setWindowMotifHint(int winId, const MotifWmHints &hints) { if (m_unityBorderRadiusAtom == None) return; XChangeProperty(X11Display::display(), winId, m_motifWMHintsAtom, m_motifWMHintsAtom, 32, 0, (const unsigned char *)&hints, sizeof(MotifWmHints) / sizeof(ulong)); } MotifWmHints XAtomHelper::getWindowMotifHint(int winId) { MotifWmHints hints; if (m_unityBorderRadiusAtom == None) return hints; uchar *data; Atom type; int format; ulong nitems; ulong bytes_after; XGetWindowProperty(X11Display::display(), winId, m_motifWMHintsAtom, 0, sizeof(MotifWmHints) / sizeof(long), false, AnyPropertyType, &type, &format, &nitems, &bytes_after, &data); if (type == None) { return hints; } else { hints = *(MotifWmHints *)data; XFree(data); } return hints; } XAtomHelper::XAtomHelper(QObject *parent) : QObject(parent) { if (QGuiApplication::platformName() != "xcb") return; m_motifWMHintsAtom = XInternAtom(X11Display::display(), "_MOTIF_WM_HINTS", true); m_unityBorderRadiusAtom = XInternAtom(X11Display::display(), "_UNITY_GTK_BORDER_RADIUS", false); m_ukuiDecorationAtion = XInternAtom(X11Display::display(), "_KWIN_UKUI_DECORAION", false); } Atom XAtomHelper::registerUKUICsdNetWmSupportAtom() { // fixme: return None; } void XAtomHelper::unregisterUKUICsdNetWmSupportAtom() { // fixme: } libkysdk-applications/kysdk-qtwidgets/src/ksecurityquestiondialog.cpp0000664000175000017500000003243715104543305025434 0ustar fengfeng/* * libkysdk-qtwidgets's Library * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: SiSheng He * */ #include "ksecurityquestiondialog.h" #include #include #include #include "accessinfohelper.h" #define LABELWIDTH 92 #define BUTTONWIDTH 96 #define DIALOGWIDTH 424 #define DIALOGHEIGHT 476 namespace kdk { class KSecurityQuestionDialogPrivate : public QObject { Q_OBJECT Q_DECLARE_PUBLIC(KSecurityQuestionDialog) public: KSecurityQuestionDialogPrivate(KSecurityQuestionDialog *parent); private: KSecurityQuestionDialog *q_ptr; QScrollArea *m_pScrollArea; QVBoxLayout *m_pMainVLayout = nullptr; QLabel *m_pTitleLabel = nullptr; KPushButton *m_pCancelKBtn = nullptr; KPushButton *m_pConfirmKBtn = nullptr; QList m_questionComboxList; QList m_questionLineeditList; QList m_answerLineeditList; QList m_questionLabelList; QList m_answerLabelList; QList m_tipsLabelList; QStringList m_questionlist; QWidget *m_pScrollWidget; bool m_isVerify = false; public Q_SLOTS: void setQustionCombox(); void refreshConfirmBtn(); }; KSecurityQuestionDialog::KSecurityQuestionDialog(QWidget *parent) : KDialog(parent) , d_ptr(new KSecurityQuestionDialogPrivate(this)) { Q_D(KSecurityQuestionDialog); setObjectName("KSecurityQuestionDialog"); } KSecurityQuestionDialog::~KSecurityQuestionDialog() { } KPushButton *KSecurityQuestionDialog::cancelButton() { Q_D(KSecurityQuestionDialog); return d->m_pCancelKBtn; } KPushButton *KSecurityQuestionDialog::confirmButton() { Q_D(KSecurityQuestionDialog); return d->m_pConfirmKBtn; } void KSecurityQuestionDialog::setTitleText(const QString &text) { Q_D(KSecurityQuestionDialog); d->m_pTitleLabel->setText(text); } void KSecurityQuestionDialog::addSecurityQuestionItem(const int count, bool mutex) { Q_D(KSecurityQuestionDialog); for (int i = 1; i <= count; i++) { QLabel *questionLabel = new QLabel(tr("Security question%1").arg(i)); questionLabel->setFixedWidth(LABELWIDTH); QHBoxLayout *questionHlayout = new QHBoxLayout(); questionHlayout->setContentsMargins(0, 0, 0, 0); questionHlayout->addWidget(questionLabel); questionHlayout->addSpacing(16); QLabel *answerLabel = new QLabel(tr("Answer")); answerLabel->setFixedWidth(LABELWIDTH); QLineEdit *answerLineEdit = new QLineEdit(); answerLineEdit->setPlaceholderText(tr("Required")); answerLineEdit->setFixedHeight(36); QHBoxLayout *answerHlayout = new QHBoxLayout(); answerHlayout->setContentsMargins(0, 0, 0, 0); answerHlayout->addWidget(answerLabel); answerHlayout->addSpacing(16); answerHlayout->addWidget(answerLineEdit); d->m_answerLineeditList.append(answerLineEdit); d->m_questionLabelList.append(questionLabel); d->m_answerLabelList.append(answerLabel); KDK_EXTEND_ALL_INFO_FORMAT(answerLineEdit,"",QString("%1").arg(i),""); KDK_EXTEND_ALL_INFO_FORMAT(questionLabel,"",QString("%1").arg(i),""); KDK_EXTEND_ALL_INFO_FORMAT(answerLabel,"",QString("%1").arg(i),""); QVBoxLayout *itemVLayout = new QVBoxLayout; itemVLayout->setContentsMargins(0, 0, 0, 0); itemVLayout->setSpacing(8); itemVLayout->addLayout(questionHlayout); itemVLayout->addLayout(answerHlayout); if (d->m_isVerify) { QLineEdit *questionLineedit = new QLineEdit(); questionLineedit->setFixedHeight(36); d->m_questionLineeditList.append(questionLineedit); KDK_EXTEND_ALL_INFO_FORMAT(questionLineedit,"",QString("%1").arg(i),""); questionLineedit->setEnabled(false); QPalette palette = questionLineedit->palette(); QColor color = ThemeController::getCustomColorFromDT("text-active"); palette.setColor(QPalette::Disabled, QPalette::Text, color); questionLineedit->setPalette(palette); questionHlayout->addWidget(questionLineedit); QLabel *tiplabel = new QLabel(); d->m_tipsLabelList.append(tiplabel); KDK_EXTEND_ALL_INFO_FORMAT(tiplabel,"",QString("%1").arg(i),""); QPalette pe; pe.setColor(QPalette::WindowText, Qt::red); tiplabel->setPalette(pe); QLabel *placeholderLabel = new QLabel(); placeholderLabel->setFixedWidth(LABELWIDTH); QHBoxLayout *tipHLayout = new QHBoxLayout(); tipHLayout->setContentsMargins(0, 0, 0, 0); tipHLayout->addWidget(placeholderLabel); tipHLayout->addSpacing(16); tipHLayout->addWidget(tiplabel); itemVLayout->addLayout(tipHLayout); } else { QComboBox *questionCombox = new QComboBox(); questionCombox->setFixedHeight(36); d->m_questionComboxList.append(questionCombox); KDK_EXTEND_ALL_INFO_FORMAT(questionCombox,"",QString("%1").arg(i),""); questionHlayout->addWidget(questionCombox); itemVLayout->addStretch(); if (mutex) { connect(questionCombox, &QComboBox::currentTextChanged, d, &KSecurityQuestionDialogPrivate::setQustionCombox); } } d->m_pMainVLayout->insertLayout(d->m_pMainVLayout->count() - 1, itemVLayout); connect(answerLineEdit, &QLineEdit::textChanged, d, &KSecurityQuestionDialogPrivate::refreshConfirmBtn); } } void KSecurityQuestionDialog::addSecurityQuestionItem(const int count, bool mutex, bool isVerify) { Q_D(KSecurityQuestionDialog); d->m_isVerify = isVerify; addSecurityQuestionItem(count, mutex); } void KSecurityQuestionDialog::initQustionCombox(const QStringList &questionlist) { Q_D(KSecurityQuestionDialog); d->m_questionlist = questionlist; for (int i = 0; i < d->m_questionComboxList.count(); i++) { QComboBox *question = d->m_questionComboxList.at(i); question->blockSignals(true); question->addItems(questionlist); question->blockSignals(false); question->setCurrentIndex(i); } for (int i = 0; i < d->m_questionLineeditList.count(); i++) { QLineEdit *question = d->m_questionLineeditList.at(i); if (questionlist.count() > i) { question->setText(questionlist.at(i)); } } } QLabel *KSecurityQuestionDialog::tipsLabel(const int index) { Q_D(KSecurityQuestionDialog); // questionIndex 最小为0 count最小为1, if (index >= 0 && d->m_tipsLabelList.count() > index) { return d->m_tipsLabelList.at(index); } return nullptr; } QLabel *KSecurityQuestionDialog::questionLabel(const int questionIndex) { Q_D(KSecurityQuestionDialog); // questionIndex 最小为0 count最小为1, if (questionIndex >= 0 && d->m_questionLabelList.count() > questionIndex) { return d->m_questionLabelList.at(questionIndex); } return nullptr; } QLabel *KSecurityQuestionDialog::answerLabel(const int answerIndex) { Q_D(KSecurityQuestionDialog); if (answerIndex >= 0 && d->m_answerLabelList.count() > answerIndex) { return d->m_answerLabelList.at(answerIndex); } return nullptr; } QComboBox *KSecurityQuestionDialog::questionCombox(const int questionIndex) { Q_D(KSecurityQuestionDialog); if (questionIndex >= 0 && d->m_questionComboxList.count() > questionIndex) { return d->m_questionComboxList.at(questionIndex); } return nullptr; } QLineEdit *KSecurityQuestionDialog::answerLineedit(const int answerIndex) { Q_D(KSecurityQuestionDialog); if (answerIndex >= 0 && d->m_answerLineeditList.count() > answerIndex) { return d->m_answerLineeditList.at(answerIndex); } return nullptr; } void KSecurityQuestionDialog::keyPressEvent(QKeyEvent *event) { Q_D(KSecurityQuestionDialog); switch (event->key()) { case Qt::Key_Enter: if (d->m_pConfirmKBtn->isEnabled()) d->m_pConfirmKBtn->clicked(); break; case Qt::Key_Return: if (d->m_pConfirmKBtn->isEnabled()) d->m_pConfirmKBtn->clicked(); break; default: KDialog::keyPressEvent(event); } } KSecurityQuestionDialogPrivate::KSecurityQuestionDialogPrivate(KSecurityQuestionDialog *parent) : q_ptr(parent) { Q_Q(KSecurityQuestionDialog); m_pScrollArea = new QScrollArea(q->mainWidget()); m_pScrollArea->setFrameShape(QScrollArea::NoFrame); m_pScrollWidget = new QWidget(); setParent(parent); q->setWindowIcon("ukui-control-center"); q->setWindowTitle(tr("Security Question")); m_pTitleLabel = new QLabel(tr("Setting security questions to reset password when forget it, " "please remember answer.")); m_pTitleLabel->setWordWrap(true); m_pCancelKBtn = new KPushButton(); m_pCancelKBtn->setFocusPolicy(Qt::FocusPolicy::NoFocus); m_pCancelKBtn->setFixedWidth(BUTTONWIDTH); m_pCancelKBtn->setText(tr("Cancel")); m_pConfirmKBtn = new KPushButton(); m_pConfirmKBtn->setFixedWidth(BUTTONWIDTH); m_pConfirmKBtn->setText(tr("Save")); m_pConfirmKBtn->setEnabled(false); m_pConfirmKBtn->setFocusPolicy(Qt::FocusPolicy::NoFocus); q->closeButton()->setFocusPolicy(Qt::FocusPolicy::NoFocus); QHBoxLayout *hLayout = new QHBoxLayout(); hLayout->setContentsMargins(0, 0, 0, 0); hLayout->setSpacing(16); hLayout->addStretch(); hLayout->addWidget(m_pCancelKBtn); hLayout->addWidget(m_pConfirmKBtn); QVBoxLayout *scrollAreaLayout = new QVBoxLayout(); scrollAreaLayout->setContentsMargins(0, 0, 0, 0); scrollAreaLayout->addWidget(m_pScrollArea); m_pScrollArea->setWidgetResizable(true); m_pScrollArea->horizontalScrollBar()->setVisible(false); m_pMainVLayout = new QVBoxLayout(m_pScrollWidget); m_pMainVLayout->setContentsMargins(21, 16, 27, 24); m_pMainVLayout->setSpacing(24); m_pMainVLayout->addWidget(m_pTitleLabel); m_pMainVLayout->addLayout(hLayout); m_pScrollWidget->setLayout(m_pMainVLayout); m_pScrollArea->setWidget(m_pScrollWidget); q->mainWidget()->setLayout(scrollAreaLayout); m_pScrollWidget->setFixedWidth(DIALOGWIDTH); q->setFixedSize(DIALOGWIDTH, DIALOGHEIGHT); QObject::connect(m_pCancelKBtn, SIGNAL(clicked(bool)), q, SLOT(reject())); QObject::connect(m_pConfirmKBtn, &KPushButton::clicked, this, [=]() { foreach (QLineEdit *tempLineedit, m_answerLineeditList) { if (tempLineedit != nullptr) { tempLineedit->clearFocus(); } } }); KDK_ALL_INFO_FORMAT(m_pScrollArea,""); KDK_ALL_INFO_FORMAT(m_pTitleLabel,""); KDK_ALL_INFO_FORMAT(m_pCancelKBtn,""); KDK_ALL_INFO_FORMAT(m_pConfirmKBtn,""); KDK_ALL_INFO_FORMAT(m_pScrollWidget,""); } // 安全问题下拉框问题不可重复,已选择问题下拉框中置灰 void KSecurityQuestionDialogPrivate::setQustionCombox() { Q_Q(KSecurityQuestionDialog); QStringList allComboxCurrentText; for (int i = 0; i < m_questionComboxList.count(); i++) { QComboBox *tempCombox = m_questionComboxList.at(i); // 获取所有combox当前选择的text allComboxCurrentText.append(tempCombox->currentText()); } for (int j = 0; j < m_questionComboxList.count(); j++) { QComboBox *tempCombox = m_questionComboxList.at(j); QString currentText = tempCombox->currentText(); if (m_questionlist.contains(currentText)) { tempCombox->blockSignals(true); tempCombox->clear(); tempCombox->addItems(m_questionlist); tempCombox->setCurrentText(currentText); tempCombox->blockSignals(false); // 将在当前combox的其他combox的当前项置灰 foreach (QString text, allComboxCurrentText) { if (text != currentText) { QVariant v(0); tempCombox->setItemData(tempCombox->findText(text), v, Qt::UserRole - 1); } } } } } void KSecurityQuestionDialogPrivate::refreshConfirmBtn() { foreach (QLabel *tempLabel, m_tipsLabelList) { if (!tempLabel->text().isEmpty()) { tempLabel->clear(); } } foreach (QLineEdit *tempLineedit, m_answerLineeditList) { if (tempLineedit->text().isEmpty()) { m_pConfirmKBtn->setEnabled(false); m_pConfirmKBtn->setProperty("isImportant", false); return; } } m_pConfirmKBtn->setEnabled(true); m_pConfirmKBtn->setProperty("isImportant", true); } } #include "ksecurityquestiondialog.moc" #include "moc_ksecurityquestiondialog.cpp" libkysdk-applications/kysdk-qtwidgets/src/kminicalendaritem.h0000664000175000017500000002071115104543305023557 0ustar fengfeng/* * libkysdk-qtwidgets's Library * * Copyright (C) 2024, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhenyu Wang * */ #ifndef KMINICALENDARITEM_H #define KMINICALENDARITEM_H #include "gui_g.h" #include #include namespace kdk { /** * @defgroup KMiniCalendarItem * @since 2.5.2.0 */ class KMiniCalendarItemPrivate; class GUI_EXPORT KMiniCalendarItem : public QWidget { Q_OBJECT Q_ENUMS(DayType) Q_ENUMS(SelectType) Q_PROPERTY(bool select READ getSelect WRITE setSelect) Q_PROPERTY(bool showLunar READ getShowLunar WRITE setShowLunar) Q_PROPERTY(bool enableBorder READ getEnableBorder WRITE setEnableBorder) Q_PROPERTY(SelectType selectType READ getSelectType WRITE setSelectType) Q_PROPERTY(QDate date READ getDate WRITE setDate) Q_PROPERTY(QString lunar READ getLunar WRITE setLunar) Q_PROPERTY(DayType dayType READ getDayType WRITE setDayType) Q_PROPERTY(QColor borderColor READ getBorderColor WRITE setBorderColor) Q_PROPERTY(QColor weekColor READ getWeekColor WRITE setWeekColor) Q_PROPERTY(QColor superColor READ getSuperColor WRITE setSuperColor) Q_PROPERTY(QColor lunarColor READ getLunarColor WRITE setLunarColor) Q_PROPERTY(QColor currentTextColor READ getCurrentTextColor WRITE setCurrentTextColor) Q_PROPERTY(QColor otherTextColor READ getOtherTextColor WRITE setOtherTextColor) Q_PROPERTY(QColor selectTextColor READ getSelectTextColor WRITE setSelectTextColor) Q_PROPERTY(QColor hoverTextColor READ getHoverTextColor WRITE setHoverTextColor) Q_PROPERTY(QColor currentLunarColor READ getCurrentLunarColor WRITE setCurrentLunarColor) Q_PROPERTY(QColor otherLunarColor READ getOtherLunarColor WRITE setOtherLunarColor) Q_PROPERTY(QColor selectLunarColor READ getSelectLunarColor WRITE setSelectLunarColor) Q_PROPERTY(QColor hoverLunarColor READ getHoverLunarColor WRITE setHoverLunarColor) Q_PROPERTY(QColor currentBgColor READ getCurrentBgColor WRITE setCurrentBgColor) Q_PROPERTY(QColor otherBgColor READ getOtherBgColor WRITE setOtherBgColor) Q_PROPERTY(QColor selectBgColor READ getSelectBgColor WRITE setSelectBgColor) Q_PROPERTY(QColor hoverBgColor READ getHoverBgColor WRITE setHoverBgColor) public: enum DayType { DayType_MonthPre = 0, // 上月剩余天数 DayType_MonthNext = 1, // 下个月的天数 DayType_MonthCurrent = 2, // 当月天数 DayType_WeekEnd = 3 // 周末 }; enum SelectType { SelectType_Rect = 0, // 矩形背景 SelectType_Circle = 1, // 圆形背景 SelectType_Triangle = 2, // 带三角标 SelectType_Image = 3 // 图片背景 }; explicit KMiniCalendarItem(QWidget *parent = 0); protected: void enterEvent(QEvent *); void leaveEvent(QEvent *); void mousePressEvent(QMouseEvent *); void mouseReleaseEvent(QMouseEvent *); void paintEvent(QPaintEvent *); void drawBg(QPainter *painter); void drawBgCurrent(QPainter *painter, const QColor &color); void drawDay(QPainter *painter); void drawLunar(QPainter *painter); public: /** * @brief 获取是否选中 * @return */ bool getSelect() const; /** * @brief 获取是否显示农历 * @return */ bool getShowLunar() const; /** * @brief 获取启用边界 * @return */ bool getEnableBorder() const; /** * @brief 获取选择类型 * @return */ SelectType getSelectType() const; /** * @brief 获取当前日期 * @return */ QDate getDate() const; /** * @brief 获取农历信息 * @return */ QString getLunar() const; /** * @brief 获取日期类型 * @return */ DayType getDayType() const; /** * @brief 获取边框颜色 * @return */ QColor getBorderColor() const; /** * @brief 获取周颜色 * @return */ QColor getWeekColor() const; /** * @brief 获取角标颜色 * @return */ QColor getSuperColor() const; /** * @brief 获取农历节日颜色 * @return */ QColor getLunarColor() const; /** * @brief 获取当前月文字颜色 * @return */ QColor getCurrentTextColor() const; /** * @brief 获取其他月文字颜色 * @return */ QColor getOtherTextColor() const; /** * @brief 获取选中日期文字颜色 * @return */ QColor getSelectTextColor() const; /** * @brief 获取悬停日期文字颜色 * @return */ QColor getHoverTextColor() const; /** * @brief 获取当前月农历文字颜色 * @return */ QColor getCurrentLunarColor() const; /** * @brief 获取其他月农历文字颜色 * @return */ QColor getOtherLunarColor() const; /** * @brief 获取选中日期农历文字颜色 * @return */ QColor getSelectLunarColor() const; /** * @brief 获取悬停日期农历文字颜色 * @return */ QColor getHoverLunarColor() const; /** * @brief 获取当前月背景颜色 * @return */ QColor getCurrentBgColor() const; /** * @brief 获取其他月背景颜色 * @return */ QColor getOtherBgColor() const; /** * @brief 获取选中日期背景颜色 * @return */ QColor getSelectBgColor() const; /** * @brief 获取悬停日期背景颜色 * @return */ QColor getHoverBgColor() const; QSize sizeHint() const; QSize minimumSizeHint() const; public Q_SLOTS: // 设置是否选中 void setSelect(bool select); // 设置是否显示农历信息 void setShowLunar(bool showLunar); // 设置选中背景样式 void setSelectType(const SelectType &selectType); // 设置日期 void setDate(const QDate &date); // 设置农历 void setLunar(const QString &lunar); // 设置类型 void setDayType(const DayType &dayType); // 设置日期/农历/类型 void setDate(const QDate &date, const QString &lunar, const DayType &dayType); // 是否显示边框 void setEnableBorder(bool bVisible); // 设置边框颜色 void setBorderColor(const QColor &borderColor); // 设置周末颜色 void setWeekColor(const QColor &weekColor); // 设置角标颜色 void setSuperColor(const QColor &superColor); // 设置农历节日颜色 void setLunarColor(const QColor &lunarColor); // 设置当前月文字颜色 void setCurrentTextColor(const QColor ¤tTextColor); // 设置其他月文字颜色 void setOtherTextColor(const QColor &otherTextColor); // 设置选中日期文字颜色 void setSelectTextColor(const QColor &selectTextColor); // 设置悬停日期文字颜色 void setHoverTextColor(const QColor &hoverTextColor); // 设置当前月农历文字颜色 void setCurrentLunarColor(const QColor ¤tLunarColor); // 设置其他月农历文字颜色 void setOtherLunarColor(const QColor &otherLunarColor); // 设置选中日期农历文字颜色 void setSelectLunarColor(const QColor &selectLunarColor); // 设置悬停日期农历文字颜色 void setHoverLunarColor(const QColor &hoverLunarColor); // 设置当前月背景颜色 void setCurrentBgColor(const QColor ¤tBgColor); // 设置其他月背景颜色 void setOtherBgColor(const QColor &otherBgColor); // 设置选中日期背景颜色 void setSelectBgColor(const QColor &selectBgColor); // 设置悬停日期背景颜色 void setHoverBgColor(const QColor &hoverBgColor); signals: void clicked(const QDate &date, const KMiniCalendarItem::DayType &dayType); private: Q_DECLARE_PRIVATE(KMiniCalendarItem) KMiniCalendarItemPrivate *const d_ptr; }; } #endif // KMINICALENDARITEM_H libkysdk-applications/kysdk-qtwidgets/src/kpushbutton.h0000664000175000017500000001070715104543305022471 0ustar fengfeng/* * libkysdk-qtwidgets's Library * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Xiangwei Liu * */ #ifndef KPUSHBUTTON_H #define KPUSHBUTTON_H #include "gui_g.h" #include #include namespace kdk { /** * @defgroup PushbuttonModule * { */ class KPushButtonPrivate; /** * @brief 1.提供半透明效果 * 2.可以设置按钮圆角、背景色、图标是否跟随系统高亮 * 3.可以设置按钮类型,分为正常类型和圆形(需要设置大小实现正圆),其余同QPushButton * @since 1.2.0 */ class GUI_EXPORT KPushButton : public QPushButton { Q_OBJECT public: /** * @brief 支持两种样式的按钮 */ enum ButtonType { NormalType, CircleType, GrayType, ShadowType }; enum ArrowDirection { ArrowTop, ArrowBottom, ArrowLeft, ArrowRight }; KPushButton(QWidget *parent = nullptr); ~KPushButton(); /** * @brief 设置按钮圆角 * 通过圆角半径设置按钮圆角(每个圆角相同) * @param radius */ void setBorderRadius(int radius); /** * @brief 设置按钮圆角 * 通过四个点来设置圆角 * @param bottomLeft(左下) * @param topLeft(左上) * @param topRight(右上) * @param bottomRight(右下) */ void setBorderRadius(int bottomLeft, int topLeft, int topRight, int bottomRight); /** * @brief 获取按钮圆角 * @return radius */ int borderRadius(); /** * @brief 设置按钮背景色 * @param color */ void setBackgroundColor(QColor color); /** * @brief 获取按钮背景色 * @return color */ QColor backgroundColor(); /** * @brief 设置KPushButton的类型 * @param type */ void setButtonType(ButtonType type); /** * @brief 获取KPushButton的类型 * @return */ ButtonType buttonType(); /** * @brief 设置KPushButton是否为半透明 * @param flag */ void setTranslucent(bool flag); /** * @brief 判断KPushButton是否为半透明 * @return */ bool isTranslucent(); /** * @brief 设置图标是否跟随系统高亮色,默认不跟随 * @param flag */ void setIconHighlight(bool flag); /** * @brief 判断图标是否跟随系统高亮色 * @return */ bool isIconHighlight(); /** * @brief 设置按钮添加图标的颜色 * @param color */ void setIconColor(QColor color); /** * @brief 获取按钮添加图标的颜色 * @return */ QColor IconColor(); /** * @brief 设置按钮背景色是否跟随系统高亮色,默认不跟随 * @param flag */ void setBackgroundColorHighlight(bool flag); /** * @brief 判断按钮背景色是否跟随系统高亮色 * @return */ bool isBackgroundColorHighlight(); /** * @brief 设置是否显示箭头flag,设置箭头方向arrowDirection * @param flag * @param arrowDirection * @since 2.4.1.0 */ void setArrow(bool flag, ArrowDirection arrowDirection = ArrowBottom); /** * @brief 返回是否显示箭头 * @return bool * @since 2.4.1.0 */ bool hasArrow() const; /** * @brief 设置加载样式 * @param flag * @since 2.5.2.0 */ void setLoaingStatus(bool flag); /** * @brief 返回加载样式 * @return * @since 2.5.2.0 */ bool isLoading(); protected: bool eventFilter(QObject *watched, QEvent *event); void paintEvent(QPaintEvent *event); private: Q_DECLARE_PRIVATE(KPushButton) KPushButtonPrivate *const d_ptr; }; } #endif // KPUSHBUTTON_H libkysdk-applications/kysdk-qtwidgets/src/kdialog.cpp0000664000175000017500000002251715104543305022052 0ustar fengfeng/* * libkysdk-qtwidgets's Library * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #include "kdialog.h" #include "accessinfohelper.h" #include "parmscontroller.h" #include "ukuistylehelper/ukui-decoration-manager.h" #include "ukuistylehelper/ukui-shell-manager.h" #include #include #include #include "xatom-helper.h" namespace kdk { class KDialogPrivate : public QObject { Q_OBJECT Q_DECLARE_PUBLIC(KDialog) public: KDialogPrivate(KDialog *parent); private: KDialog *q_ptr; KIconBar *m_pIconBar; KWindowButtonBar *m_pWindowButtonBar; QHBoxLayout *m_pTitleLayout; QVBoxLayout *m_pMainLayout; QWidget *m_pMainWidget; QString m_IconName; }; KDialog::KDialog(QWidget *parent) : QDialog(parent) , d_ptr(new KDialogPrivate(this)) { Q_D(KDialog); setAttribute(Qt::WA_AlwaysShowToolTips); setFocusPolicy(Qt::ClickFocus); setObjectName("Kdialog"); QString platform = QGuiApplication::platformName(); if (platform.startsWith(QLatin1String("xcb"), Qt::CaseInsensitive)) { MotifWmHints hints; hints.flags = MWM_HINTS_FUNCTIONS | MWM_HINTS_DECORATIONS; hints.functions = MWM_FUNC_ALL; hints.decorations = MWM_DECOR_BORDER; XAtomHelper::getInstance()->setWindowMotifHint(this->winId(), hints); } connect(d->m_pWindowButtonBar->minimumButton(), &QPushButton::clicked, this, &KDialog::showMinimized); connect(d->m_pWindowButtonBar->maximumButton(), &QPushButton::clicked, this, [=]() { if (this->isMaximized()) showNormal(); else showMaximized(); }); connect(d->m_pWindowButtonBar->closeButton(), &QPushButton::clicked, this, &KDialog::close); connect(d->m_pWindowButtonBar, &KWindowButtonBar::doubleClick, this, [=]() { if (this->isMaximized()) showNormal(); else showMaximized(); }); connect(d->m_pIconBar, &KIconBar::doubleClick, this, [=]() { if (this->isMaximized()) showNormal(); else showMaximized(); }); changeIconStyle(); connect(m_gsetting, &QGSettings::changed, this, [=]() { changeIconStyle(); }); changeTheme(); connect(m_gsetting, &QGSettings::changed, this, &KDialog::changeTheme); connect(Parmscontroller::self(), &Parmscontroller::modeChanged, this, [=]() { updateGeometry(); }); installEventFilter(this); resize(600, 480); } KDialog::~KDialog() { } void KDialog::setWindowIcon(const QIcon &icon) { Q_D(KDialog); d->m_pIconBar->setIcon(icon); d->m_IconName = icon.name(); QWidget::setWindowIcon(icon); } void KDialog::setWindowIcon(const QString &iconName) { Q_D(KDialog); d->m_IconName = iconName; d->m_pIconBar->setIcon(iconName); QWidget::setWindowIcon(QIcon::fromTheme(iconName)); } void KDialog::setWindowTitle(const QString &title) { Q_D(KDialog); QVariant value = this->property("isAboutDialog"); if (value.isNull() || !value.toBool()) { d->m_pIconBar->setWidgetName(title); } QDialog::setWindowTitle(title); } QPushButton *KDialog::maximumButton() { Q_D(KDialog); return d->m_pWindowButtonBar->maximumButton(); } QPushButton *KDialog::minimumButton() { Q_D(KDialog); return d->m_pWindowButtonBar->minimumButton(); } QPushButton *KDialog::closeButton() { Q_D(KDialog); return d->m_pWindowButtonBar->closeButton(); } KMenuButton *KDialog::menuButton() { Q_D(KDialog); return d->m_pWindowButtonBar->menuButton(); } QWidget *KDialog::mainWidget() { Q_D(KDialog); if (d->m_pMainWidget) return d->m_pMainWidget; } KWindowButtonBar *KDialog::windowButtonBar() { Q_D(KDialog); return d->m_pWindowButtonBar; } KIconBar *KDialog::iconBar() { Q_D(KDialog); return d->m_pIconBar; } bool KDialog::eventFilter(QObject *target, QEvent *event) { Q_D(KDialog); if (target == this && (event->type() == QEvent::WindowStateChange || event->type() == QEvent::Show)) { if (event->type() == QEvent::Show) { MotifWmHints hints; hints.flags = MWM_HINTS_FUNCTIONS | MWM_HINTS_DECORATIONS; hints.functions = MWM_FUNC_ALL; hints.decorations = MWM_DECOR_BORDER; XAtomHelper::getInstance()->setWindowMotifHint(this->winId(), hints); QWidget *parentWindow = qobject_cast(this->parent()); while (parentWindow && parentWindow->parent()) parentWindow = qobject_cast(parentWindow->parent()); if (parentWindow && parentWindow->isVisible()) { const QPoint parentWindowCenter = parentWindow->geometry().center(); const QPoint dialogCenter = this->geometry().center(); const QPoint moveOffset = parentWindowCenter - dialogCenter; move(pos() + moveOffset); } else { QScreen *screen = QGuiApplication::primaryScreen(); int screenWidth = screen->geometry().width(); int screenHeight = screen->geometry().height(); int messageBox_X = (screenWidth - this->width()) / 2; int messageBox_Y = (screenHeight - this->height()) / 2; this->move(messageBox_X, messageBox_Y); } } if (this->isMaximized()) d->m_pWindowButtonBar->setMaximumButtonState(MaximumButtonState::Restore); else d->m_pWindowButtonBar->setMaximumButtonState(MaximumButtonState::Maximum); } if (target == this && (event->type() == QEvent::WindowActivate || event->type() == QEvent::WindowDeactivate)) { changeTheme(); } QString platform = QGuiApplication::platformName(); if (platform.startsWith(QLatin1String("wayland"), Qt::CaseInsensitive)) { if ((event->type() == QEvent::PlatformSurface || event->type() == QEvent::Show || event->type() == QEvent::UpdateRequest || event->type() == QEvent::ChildAdded || event->type() == QEvent::ChildPolished)) { #ifdef USE_UKUI_SHELL_PLUGIN this->setProperty("ukui_surface_no_titlebar", true); #else #ifdef USE_UKUI_PROTOCOL if (UkuiShellManager::getInstance()->ukuishellReady()) UkuiShellManager::getInstance()->removeHeaderBar(this->windowHandle()); else UKUIDecorationManager::getInstance()->removeHeaderBar(this->windowHandle()); #else UKUIDecorationManager::getInstance()->removeHeaderBar(this->windowHandle()); #endif #endif } } if (target == this && (event->type() == QEvent::Close || event->type() == QEvent::Hide)) { d->m_pWindowButtonBar->closeButton()->setAttribute(Qt::WA_UnderMouse, false); QHoverEvent hoverEvent(QEvent::HoverLeave, QPoint(10, 10), QPoint(0, 0)); QCoreApplication::sendEvent(d->m_pWindowButtonBar->closeButton(), &hoverEvent); } return QDialog::eventFilter(target, event); } void KDialog::changeTheme() { Q_D(KDialog); initThemeStyle(); QPalette p = this->palette(); QColor color = ThemeController::getCustomColorFromDT("base-active"); p.setColor(QPalette::Window, color); this->setPalette(p); if (!d->m_IconName.isEmpty()) this->setWindowIcon(d->m_IconName); } void KDialog::changeIconStyle() { Q_D(KDialog); initThemeStyle(); setWindowIcon(d->m_IconName); } QBoxLayout *KDialog::mainLayout() { Q_D(KDialog); return d->m_pMainLayout; } KDialogPrivate::KDialogPrivate(KDialog *parent) : q_ptr(parent) { Q_Q(KDialog); m_pMainLayout = new QVBoxLayout(q); m_pTitleLayout = new QHBoxLayout(); m_pTitleLayout->setContentsMargins(0, 0, 0, 0); m_pTitleLayout->setSpacing(0); m_pTitleLayout = new QHBoxLayout; m_pIconBar = new KIconBar(q); m_pWindowButtonBar = new KWindowButtonBar(q); m_pTitleLayout->addWidget(m_pIconBar); m_pTitleLayout->addWidget(m_pWindowButtonBar); m_pMainWidget = new QWidget(q); m_pMainLayout->setSpacing(0); m_pMainLayout->setContentsMargins(0, 0, 0, 0); m_pMainLayout->addLayout(m_pTitleLayout, Qt::AlignTop); m_pMainLayout->addWidget(m_pMainWidget); // 暂时先默认只显示关闭按钮 m_pWindowButtonBar->maximumButton()->hide(); m_pWindowButtonBar->menuButton()->hide(); m_pWindowButtonBar->minimumButton()->hide(); connect(m_pWindowButtonBar->minimumButton(), &QPushButton::clicked, q, &KDialog::showMinimized); connect(m_pWindowButtonBar->closeButton(), &QPushButton::clicked, q, &KDialog::close); setParent(parent); KDK_ALL_INFO_FORMAT(m_pIconBar,""); KDK_ALL_INFO_FORMAT(m_pWindowButtonBar,""); KDK_ALL_INFO_FORMAT(m_pMainWidget,""); } } #include "kdialog.moc" #include "moc_kdialog.cpp" libkysdk-applications/kysdk-qtwidgets/src/klunardateedit.h0000664000175000017500000000332115104543305023075 0ustar fengfeng/* * libkysdk-qtwidgets's Library * * Copyright (C) 2024, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhenyu Wang * */ #ifndef KLUNARDATEEDIT_H #define KLUNARDATEEDIT_H #include "gui_g.h" #include #include #include namespace kdk { class KLunarDateEditPrivate; /** * @defgroup KLunarDateEdit * @since 2.5.2.0 */ class GUI_EXPORT KLunarDateEdit : public QWidget { Q_OBJECT public: explicit KLunarDateEdit(QWidget *parent = nullptr); /** * @brief 是否显示农历 * @param showLunar:true显示,false不显示 */ void setShowLunar(bool showLunar); /** * @brief 获取控件中的DateEdit控件 * @return */ QDateTimeEdit *getDateEdit(); protected: void resizeEvent(QResizeEvent *event); signals: void dateChanged(QDate); private slots: void slotPaletteChanged(); void slotDateChanged(QDate date); void slotClicked(); private: Q_DECLARE_PRIVATE(KLunarDateEdit) KLunarDateEditPrivate *const d_ptr; }; } #endif // KLUNARDATEEDIT_H libkysdk-applications/kysdk-qtwidgets/src/themeController.cpp0000664000175000017500000005742215104543305023611 0ustar fengfeng/* * libkysdk-qtwidgets's Library * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #include "themeController.h" #include #include #include #include #include #include #include #include #include #include #include #define ColorDifference 10 static WidgetThemeFlag g_widgetThemeFlag = DefaultTheme; static ThemeFlag g_themeFlag = LightTheme; static IconFlag g_iconFlag = ClassicStyle; static int g_fontSize = 11; static QGSettings *g_gsetting = nullptr; QStringList applist{ // "kylin-nm", "ukui-menu", "ukui-panel", "ukui-sidebar", "ukui-volume-control-applet-qt", "panelukui-panel", "ukui-power-manager-tray", // "ukui-bluetooth", "sogouimebs", "kylin-device-daemoon", "ukui-notifications", "ukui-flash-disk", "mktip", "kylin-video"}; static inline QString getUppercaseLetters(QString str) { if (str.isEmpty()) { return str; } QString firstStr = str.left(1).toUpper(); QString remainingStr = str.mid(1); return firstStr + remainingStr; } static inline QString getDTColorGroup(QPalette::ColorGroup colorGroup) { // QPalette::ColorGroup colorGroup; QString str; if (colorGroup == QPalette::Active) str = "active"; else if (colorGroup == QPalette::Inactive) str = "inactive"; else if (colorGroup == QPalette::Disabled) str = "disable"; else if (colorGroup == QPalette::NColorGroups) str = "ncolorgroups"; else if (colorGroup == QPalette::Current) str = "current"; else if (colorGroup == QPalette::All) str = "all"; else if (colorGroup == QPalette::Normal) str = "normal"; return str; } static inline QPalette::ColorRole getColorRole(QString str) { QPalette::ColorRole colorRole; if (str.contains("windowtext")) colorRole = QPalette::WindowText; else if (str.contains("button")) colorRole = QPalette::Button; else if (str.contains("light")) colorRole = QPalette::Light; else if (str.contains("midlight")) colorRole = QPalette::Midlight; else if (str.contains("dark")) colorRole = QPalette::Dark; else if (str.contains("mid")) colorRole = QPalette::Mid; else if (str.contains("text")) colorRole = QPalette::Text; else if (str.contains("brighttext")) colorRole = QPalette::BrightText; else if (str.contains("buttontext")) colorRole = QPalette::ButtonText; else if (str.contains("base")) colorRole = QPalette::Base; else if (str.contains("window")) colorRole = QPalette::Window; else if (str.contains("shadow")) colorRole = QPalette::Shadow; else if (str.contains("highlight")) colorRole = QPalette::Highlight; else if (str.contains("highlightedtext")) colorRole = QPalette::HighlightedText; else if (str.contains("link")) colorRole = QPalette::Link; else if (str.contains("linkvisited")) colorRole = QPalette::LinkVisited; else if (str.contains("alternatebase")) colorRole = QPalette::AlternateBase; else if (str.contains("norole")) colorRole = QPalette::NoRole; else if (str.contains("tooltipbase")) colorRole = QPalette::ToolTipBase; else if (str.contains("tooltiptext")) colorRole = QPalette::ToolTipText; else if (str.contains("placeholdertext")) colorRole = QPalette::PlaceholderText; else if (str.contains("accent")) colorRole = QPalette::Accent; else if (str.contains("ncolorroles")) colorRole = QPalette::NColorRoles; return colorRole; } static inline qreal mixQreal(qreal a, qreal b, qreal bias) { return a + (b - a) * bias; } static inline QColor adjustColor(const QColor c, int hRange = 0, int sRange = 0, int lRange = 0, int aRange = 0) { QColor cc; int s, l, a; if ((c.hslSaturationF() + sRange * 1.0 / 100.0) > 1) { // qWarning() << "adjustColor s out of range1"; s = 255; } else if ((c.hslSaturationF() + sRange * 1.0 / 100.0) < 0) { // qWarning() << "adjustColor s out of range0"; s = 0; } else s = (c.hslSaturationF() + sRange * 1.0 / 100.0) * 255.0; if ((c.lightnessF() + lRange * 1.0 / 100.0) > 0.97) { // 根据设计稿寻光色彩识别 l应<=0.97 qWarning() << "adjustColor l out of range1" << c.lightnessF() << lRange << (c.lightnessF() + lRange * 1.0 / 100.0); l = 255.0 * 0.97; } else if ((c.lightnessF() + lRange * 1.0 / 100.0) < 0.15) { // 根据设计稿上l最小取的均值 qWarning() << "adjustColor l out of range0"; l = 0.15 * 255.0; } else l = (c.lightnessF() + lRange * 1.0 / 100.0) * 255.0; if ((c.alphaF() + aRange * 1.0 / 100.0) > 1) { qWarning() << "adjustColor a out of range1"; a = 255; } else if ((c.alphaF() + aRange * 1.0 / 100.0) < 0) { qWarning() << "adjustColor a out of range0"; a = 0; } else a = (c.alphaF() + aRange * 1.0 / 100.0) * 255.0; cc.setHsl(c.hslHue() + hRange, s, l, a); return cc; } QPixmap ThemeController::drawSymbolicColoredPixmap(const QPixmap &source) { QColor gray(128, 128, 128); QColor standard(31, 32, 34); QImage img = source.toImage(); for (int x = 0; x < img.width(); x++) { for (int y = 0; y < img.height(); y++) { auto color = img.pixelColor(x, y); if (color.alpha() > 0) { if (qAbs(color.red() - gray.red()) < 20 && qAbs(color.green() - gray.green()) < 20 && qAbs(color.blue() - gray.blue()) < 20) { color.setRed(255); color.setGreen(255); color.setBlue(255); img.setPixelColor(x, y, color); } else if (qAbs(color.red() - standard.red()) < 20 && qAbs(color.green() - standard.green()) < 20 && qAbs(color.blue() - standard.blue()) < 20) { color.setRed(255); color.setGreen(255); color.setBlue(255); img.setPixelColor(x, y, color); } else { img.setPixelColor(x, y, color); } } } } return QPixmap::fromImage(img); } QPixmap ThemeController::drawColoredPixmap(const QPixmap &source, const QColor &sampleColor) { QImage img = source.toImage(); for(int x = 0 ; x < img.width() ;x++) { for( int y = 0; y < img.height();y++) { auto color = img.pixelColor(x,y); if(color.alpha() > 0) { color.setRed(sampleColor.red()); color.setGreen(sampleColor.green()); color.setBlue(sampleColor.blue()); img.setPixelColor(x,y,color); } } } return QPixmap::fromImage(img); } QColor ThemeController::getCurrentIconColor() { QPixmap pixmap = QIcon::fromTheme("open-menu-symbolic").pixmap(16, 16); QImage img = pixmap.toImage(); for (int x = 0; x < img.width(); x++) { for (int y = 0; y < img.height(); y++) { auto color = img.pixelColor(x, y); if (color.alpha() > 0) { return color; } } } } QColor ThemeController::mixColor(const QColor &c1, const QColor &c2, qreal bias) { if (bias <= 0.0) { return c1; } if (bias >= 1.0) { return c2; } if (qIsNaN(bias)) { return c1; } qreal r = mixQreal(c1.redF(), c2.redF(), bias); qreal g = mixQreal(c1.greenF(), c2.greenF(), bias); qreal b = mixQreal(c1.blueF(), c2.blueF(), bias); qreal a = mixQreal(c1.alphaF(), c2.alphaF(), bias); return QColor::fromRgbF(r, g, b, a); } WidgetThemeFlag ThemeController::widgetTheme() { return g_widgetThemeFlag; } ThemeFlag ThemeController::themeMode() { return g_themeFlag; } IconFlag ThemeController::iconTheme() { return g_iconFlag; } int ThemeController::systemFontSize() { if (!g_gsetting) return 11; if (g_gsetting->keys().contains("systemFontSize")) { g_fontSize = (int)g_gsetting->get("systemFontSize").toDouble(); } return g_fontSize; } QPixmap ThemeController::drawFashionBackground(const QRect &rect, int sub_width, int sub_height, int radius, int flag) { // int radius = 6; // int sub_width = 32; // int sub_height = 36; QPixmap framePixmap(rect.size()); framePixmap.fill(Qt::transparent); QRect drawRect; drawRect = rect.adjusted(0, 0, 1, 1); auto baseColor = qApp->palette().color(QPalette::Active, QPalette::Button); QColor startColor = mixColor(baseColor, getCustomColorFromDT("kwhite"), 0.5); QColor endColor = mixColor(baseColor, getCustomColorFromDT("kblack"), 0.1); QLinearGradient linearGradient; QPainterPath path; if (flag) // right { path.moveTo(drawRect.bottomRight() - QPoint(0, radius + sub_height)); path.lineTo(drawRect.bottomRight() - QPoint(0, radius)); path.quadTo(drawRect.bottomRight(), drawRect.bottomRight() - QPoint(radius, 0)); path.lineTo(drawRect.bottomRight() - QPoint(radius + sub_width, 0)); path.quadTo(drawRect.bottomRight(), drawRect.bottomRight() - QPoint(0, radius + sub_height)); linearGradient.setColorAt(0, startColor); linearGradient.setColorAt(1, endColor); linearGradient.setStart(drawRect.right(), drawRect.bottom() - (radius + sub_height)); linearGradient.setFinalStop(drawRect.right(), drawRect.bottom()); } else // left { path.moveTo(drawRect.bottomLeft() - QPoint(0, radius + sub_height)); path.lineTo(drawRect.bottomLeft() - QPoint(0, radius)); path.quadTo(drawRect.bottomLeft(), drawRect.bottomLeft() + QPoint(radius, 0)); path.lineTo(drawRect.bottomLeft() + QPoint(radius + sub_width, 0)); path.quadTo(drawRect.bottomLeft(), drawRect.bottomLeft() - QPoint(0, radius + sub_height)); linearGradient.setColorAt(0, startColor); linearGradient.setColorAt(1, endColor); linearGradient.setStart(drawRect.left(), drawRect.bottom() - (radius + sub_height)); linearGradient.setFinalStop(drawRect.left(), drawRect.bottom()); } QPainter painter(&framePixmap); painter.setRenderHint(QPainter::Antialiasing); painter.setPen(Qt::transparent); painter.setBrush(linearGradient); painter.drawPath(path); return framePixmap; } bool ThemeController::isPixmapPureColor(const QPixmap &pixmap) { QColor symbolic_color = getCustomColorFromDT("kgray-17"); if (pixmap.isNull()) { qWarning("pixmap is null!"); return false; } QImage image = pixmap.toImage(); QVector vector; int total_red = 0; int total_green = 0; int total_blue = 0; bool pure = true; for (int y = 0; y < image.height(); ++y) { for (int x = 0; x < image.width(); ++x) { if (image.pixelColor(x, y).alphaF() > 0.3) { QColor color = image.pixelColor(x, y); vector << color; total_red += color.red(); total_green += color.green(); total_blue += color.blue(); int dr = qAbs(color.red() - symbolic_color.red()); int dg = qAbs(color.green() - symbolic_color.green()); int db = qAbs(color.blue() - symbolic_color.blue()); if (dr > ColorDifference || dg > ColorDifference || db > ColorDifference) pure = false; } } } if (pure) return true; qreal squareRoot_red = 0; qreal squareRoot_green = 0; qreal squareRoot_blue = 0; qreal average_red = total_red / vector.count(); qreal average_green = total_green / vector.count(); qreal average_blue = total_blue / vector.count(); for (QColor color : vector) { squareRoot_red += (color.red() - average_red) * (color.red() - average_red); squareRoot_green += (color.green() - average_green) * (color.green() - average_green); squareRoot_blue += (color.blue() - average_blue) * (color.blue() - average_blue); } qreal arithmeticSquareRoot_red = qSqrt(squareRoot_red / vector.count()); qreal arithmeticSquareRoot_green = qSqrt(squareRoot_green / vector.count()); qreal arithmeticSquareRoot_blue = qSqrt(squareRoot_blue / vector.count()); return arithmeticSquareRoot_red < 2.0 && arithmeticSquareRoot_green < 2.0 && arithmeticSquareRoot_blue < 2.0; } QIcon ThemeController::overlayIcons(const QIcon &icon1, const QIcon &icon2, int iconWidth, int iconHeight, int offsetX, int offsetY) { if (!icon1.isNull() && !icon2.isNull()) { QSize size = icon1.actualSize(QSize(iconWidth, iconHeight)); QPixmap pixmap(size); pixmap.fill(Qt::transparent); QPainter painter(&pixmap); painter.setRenderHint(QPainter::Antialiasing); painter.setRenderHint(QPainter::TextAntialiasing); painter.setRenderHint(QPainter::SmoothPixmapTransform); icon1.paint(&painter, QRect(0, 0, size.width(), size.height()), Qt::AlignCenter); if (iconWidth > offsetX && iconHeight > offsetY) icon2.paint(&painter, QRect(offsetX, offsetY, pixmap.width() - offsetX, size.height() - offsetY), Qt::AlignCenter); else icon2.paint(&painter, QRect(pixmap.width() - 16, pixmap.height() - 16, 16, 16), Qt::AlignCenter); QIcon resultIcon(pixmap); return resultIcon; } else { return QIcon(); } } QPixmap ThemeController::overlayPixmaps(const QPixmap &pixmap1, const QPixmap &pixmap2, int offsetX, int offsetY) { if (!pixmap1.isNull() && !pixmap2.isNull()) { QPixmap resultPixmap(pixmap1.size()); resultPixmap.fill(Qt::transparent); QPainter painter(&resultPixmap); painter.setRenderHint(QPainter::Antialiasing); painter.setRenderHint(QPainter::TextAntialiasing); painter.setRenderHint(QPainter::SmoothPixmapTransform); painter.drawPixmap(QRect(0, 0, pixmap1.width(), pixmap1.height()), pixmap1); if (pixmap1.width() > offsetX && pixmap1.height() > offsetY) painter.drawPixmap(QRect(offsetX, offsetY, pixmap1.width() - offsetX, pixmap1.height() - offsetY), pixmap2); else painter.drawPixmap(QRect(pixmap1.width() - 16, pixmap1.height() - 16, 16, 16), pixmap2); painter.end(); return resultPixmap; } else { return QPixmap(); } } QColor ThemeController::lanhuHSLToQtHsl(int h, int s, int l, int a) { QColor c; c.setHsl(h, s * 255.0 / 100.0, l * 255.0 / 100.0, a); return c; } QColor ThemeController::adjustH(const QColor c, int range) { QColor cc; if ((c.hslHue() + range) >= 0) cc.setHsl(c.hslHue() + range, c.hslSaturation(), c.lightness(), c.alpha()); else cc.setHsl(c.hslHue(), c.hslSaturation(), c.lightness(), c.alpha()); return cc; } QColor ThemeController::adjustS(const QColor c, int range) { QColor cc; int s; if ((c.hslSaturationF() + range * 1.0 / 100.0) > 1) { // qWarning() << "adjustS s out of range1"; s = 255; } else if ((c.hslSaturationF() + range * 1.0 / 100.0) < 0) { // qWarning() << "adjustS s out of range0"; s = 0; } else s = (c.hslSaturationF() + range * 1.0 / 100.0) * 255.0; cc.setHsl(c.hslHue(), s, c.lightness(), c.alpha()); return cc; } QColor ThemeController::adjustL(const QColor c, int range) { QColor cc; int l; if ((c.lightnessF() + range * 1.0 / 100.0) > 0.97) { // qWarning() << "adjustL l out of range1"; l = 255.0 * 0.97; } else if ((c.lightnessF() + range * 1.0 / 100.0) < 0.15) { // qWarning() << "adjustL l out of range0" << c.lightnessF() << range << (c.lightnessF() + range * 1.0 / 100.0); l = 255.0 * 0.15; } else l = (c.lightnessF() + range * 1.0 / 100.0) * 255.0; cc.setHsl(c.hslHue(), c.hslSaturation(), l, c.alpha()); return cc; } QColor ThemeController::adjustA(const QColor c, int range) { QColor cc; int a; if ((c.alphaF() + range * 1.0 / 100.0) > 1) { // qWarning() << "adjustA a out of range1"; a = 255; } else if ((c.alphaF() + range * 1.0 / 100.0) < 0) { // qWarning() << "adjustA a out of range0"; a = 0; } else a = (c.alphaF() + range * 1.0 / 100.0) * 255.0; cc.setHsl(c.hslHue(), c.hslSaturation(), c.lightness(), a); return cc; } QColor ThemeController::highlightClick(bool isDark, QPalette p) { if (isDark) { return adjustColor(p.color(QPalette::Active, QPalette::Highlight), 0, -25, -34); // hightlight->210,72%,71% 210,47%,37% } return adjustColor(p.color(QPalette::Active, QPalette::Highlight), 3, 10, 31); // hightlight->209,87%,57% 212,97%,88% } QColor ThemeController::highlightHover(bool isDark, QPalette p) { if (isDark) { return adjustColor(p.color(QPalette::Active, QPalette::Highlight), 0, -26, -40); // 210,46%,31% } return adjustColor(p.color(QPalette::Active, QPalette::Highlight), 4, 2, 36); // 213,89%,93% } QColor ThemeController::buttonDarkClick(bool isDark, QPalette p) { if (isDark) { return adjustColor(p.color(QPalette::Disabled, QPalette::ButtonText), 0, 1, 5); } return QColor(); } bool ThemeController::systemLang() { QString systemLang = QLocale::system().name(); if (systemLang == "ug_CN" || systemLang == "ky_KG" || systemLang == "kk_KZ") return true; else return false; } QColor ThemeController::getPaletteColorFromDT(QString dtString, QPalette::ColorGroup group) { QColor color; char *m_char = dtString.toLocal8Bit().data(); if (qApp->property(m_char).isValid() && qApp->property(m_char).canConvert()) { QBrush brush = qApp->property(m_char).value(); color = brush.color(); } if (!color.isValid()) { QPalette::ColorGroup colorGroup; colorGroup = qApp->palette().currentColorGroup(); QPalette::ColorRole colorRole = getColorRole(dtString); color = qApp->palette().color(colorGroup, colorRole); } return color; } QColor ThemeController::getCustomColorFromDT(QString dtString) { QColor color; char *m_char = dtString.toLocal8Bit().data(); if (qApp->property(m_char).isValid() && qApp->property(m_char).canConvert()) { QBrush brush = qApp->property(m_char).value(); color = brush.color(); } return color; } QString ThemeController::getFontStylesFromDT(QString dtString) { char *m_char = dtString.toLocal8Bit().data(); if (qApp->property(m_char).isValid() && qApp->property(m_char).canConvert()) { return qApp->property(m_char).value(); } return QString(); } int ThemeController::getRadiusFromDT(QString dtString) { char *m_char = dtString.toLocal8Bit().data(); if (qApp->property(m_char).isValid() && qApp->property(m_char).canConvert()) { return qApp->property(m_char).value(); } return -1; } int ThemeController::getLineOrMarginFromDT(QString dtString) { char *m_char = dtString.toLocal8Bit().data(); if (qApp->property(m_char).isValid() && qApp->property(m_char).canConvert()) { return qApp->property(m_char).value(); } return -1; } void ThemeController::getGradientFromDT(QString key, QColor &startColor, QColor &endColor) { // int type; // QVariantMap option; // QDBusConnection bus = QDBusConnection::sessionBus(); // QDBusMessage message = QDBusMessage::createMethodCall( // "com.kylin.themeConfig", // "/com/kylin/ThemeConfig", // "com.kylin.ThemeConfig.DTParameters", // "GetDTThemeConfig"); // QVariantList arguments; // arguments.append(key); // message.setArguments(arguments); // QDBusReply reply = bus.call(message); // if (!reply.isValid()) { // qDebug() << "complex type failed!"; // } else { // option = reply.value(); // if (option.contains("type")) { // type = option.value("type").toUInt(); // } // if (type == 3 && option.contains(QStringLiteral("start_color")) && option.contains(QStringLiteral("end_color"))) { // QByteArray startvalue = option.value(QStringLiteral("start_color")).toByteArray(); // uint8_t c[4]; // c[0] = startvalue[0]; // c[1] = startvalue[1]; // c[2] = startvalue[2]; // c[3] = startvalue[3]; // startColor.setRed(c[0]); // startColor.setGreen(c[1]); // startColor.setBlue(c[2]); // startColor.setAlpha(c[3]); // QByteArray endvalue = option.value(QStringLiteral("end_color")).toByteArray(); // c[0] = endvalue[0]; // c[1] = endvalue[1]; // c[2] = endvalue[2]; // c[3] = endvalue[3]; // endColor.setRed(c[0]); // endColor.setGreen(c[1]); // endColor.setBlue(c[2]); // endColor.setAlpha(c[3]); // } // } char *m_char = key.toLocal8Bit().data(); if (qApp->property(m_char).isValid() && qApp->property(m_char).canConvert()) { QBrush brush = qApp->property(m_char).value(); if(brush.gradient() && brush.gradient()->stops().length() > 1) { startColor = brush.gradient()->stops().at(0).second; endColor = brush.gradient()->stops().at(1).second; } else { startColor = brush.color(); endColor = brush.color(); } } } ThemeController::ThemeController() : m_gsetting(nullptr) { if (QGSettings::isSchemaInstalled(FITTHEMEWINDOW)) { m_gsetting = new QGSettings(FITTHEMEWINDOW); g_gsetting = m_gsetting; initThemeStyle(); } } ThemeController::~ThemeController() { } void ThemeController::initThemeStyle() { if (!m_gsetting) return; if (m_gsetting->keys().contains("styleName")) { QString styleName = m_gsetting->get("styleName").toString(); if (styleName == "ukui-dark" || styleName == "ukui-black" || (styleName == "ukui-default" && applist.contains(QApplication::applicationName()))) g_themeFlag = DarkTheme; else g_themeFlag = LightTheme; } // 初始化图标主题 if (m_gsetting->keys().contains("iconThemeName")) { QString iconThemeName = m_gsetting->get("iconThemeName").toString(); if (iconThemeName == "ukui-icon-theme-default") g_iconFlag = DefaultStyle; else { g_iconFlag = ClassicStyle; } } if (m_gsetting->keys().contains("widgetThemeName")) { // 初始化样式主题 QString widgetThemeName = m_gsetting->get("widgetThemeName").toString(); if (widgetThemeName == "default") g_widgetThemeFlag = DefaultTheme; else if (widgetThemeName == "classical") g_widgetThemeFlag = ClassicTheme; else if(widgetThemeName == "fashion") g_widgetThemeFlag = FashionTheme; else if(widgetThemeName == "dawnlight") g_widgetThemeFlag = DawnLightTheme; } } libkysdk-applications/kysdk-qtwidgets/src/klistwidget.h0000664000175000017500000000277615104543305022444 0ustar fengfeng/* * libkysdk-qtwidgets's Library * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhenyu Wang * */ #ifndef KLISTWIDGET_H #define KLISTWIDGET_H #include "gui_g.h" #include "kitemwidget.h" #include "themeController.h" #include namespace kdk { /** * @since 1.2.0 */ class KListWidgetPrivate; /* * 一个可以显示两行文本的listwidget */ class GUI_EXPORT KListWidget : public QListWidget { Q_OBJECT public: KListWidget(QWidget *parent); /* * 将Itemwidget插入到listwidget * m_itemwidget需要插入的Itemwidget */ void AddItemWidget(KItemWidget *m_itemwidget); // void mousePressEvent(QMouseEvent *event); // void itemClicked(QListWidgetItem * item); private: Q_DECLARE_PRIVATE(KListWidget); KListWidgetPrivate *const d_ptr; }; } #endif // KLISTWIDGET_H libkysdk-applications/kysdk-qtwidgets/src/ktextedit.cpp0000664000175000017500000001001315104543305022431 0ustar fengfeng/* * libkysdk-qtwidgets's Library * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhenyu Wang * */ #include "ktextedit.h" #include "ktag.h" #include "themeController.h" #include #include #include #include #include #include #include #include #include "accessinfohelper.h" namespace kdk { class KTextEditPrivate : public QObject, public ThemeController { Q_OBJECT Q_DECLARE_PUBLIC(KTextEdit) public: KTextEditPrivate(KTextEdit *parent); protected: void changeTheme(); private: KTextEdit *q_ptr; KLabel *m_pLabel; QTextBlockFormat m_blockFormat; QTextCursor *m_pTextCursor; }; KTextEdit::KTextEdit(QWidget *parent) : QTextEdit(parent) , d_ptr(new KTextEditPrivate(this)) { Q_D(KTextEdit); viewport()->setContentsMargins(0, 0, 0, 0); setFrameShape(QFrame::NoFrame); } void KTextEdit::setLabelVisible(bool flag) { Q_D(KTextEdit); d->m_pLabel->setVisible(flag); } void KTextEdit::setPixmap(const QPixmap &pixmap) { Q_D(KTextEdit); d->m_pLabel->setPixmap(pixmap); } const QPixmap *KTextEdit::pixmap() const { Q_D(const KTextEdit); return d->m_pLabel->pixmap(); } void KTextEdit::setLabelText(const QString &text) { Q_D(KTextEdit); d->m_pLabel->setText(text); } void KTextEdit::setReadOnly(bool ro) { Q_D(KTextEdit); QTextEdit::setReadOnly(ro); if (isReadOnly()) { QPalette pale = palette(); pale.setColor(QPalette::Base, ThemeController::getCustomColorFromDT("highlight-active")); pale.setColor(QPalette::Text, Qt::white); setPalette(pale); d->m_pLabel->setBackgroundColor(true, Qt::white); } else { QPalette pale; setPalette(pale); d->m_pLabel->setBackgroundColor(false); } } void KTextEdit::paintEvent(QPaintEvent *event) { Q_D(KTextEdit); QTextEdit::paintEvent(event); if (d->m_pLabel->isVisible()) { d->m_blockFormat.setTextIndent(d->m_pLabel->width() + 4); d->m_blockFormat.setLineHeight(3, QTextBlockFormat::LineDistanceHeight); d->m_pTextCursor->setBlockFormat(d->m_blockFormat); } else { d->m_blockFormat.setTextIndent(0); d->m_blockFormat.setLineHeight(3, QTextBlockFormat::LineDistanceHeight); d->m_pTextCursor->setBlockFormat(d->m_blockFormat); } } KTextEditPrivate::KTextEditPrivate(KTextEdit *parent) : q_ptr(parent) { Q_Q(KTextEdit); m_pLabel = new KLabel(q); m_pLabel->setAlignment(Qt::AlignCenter); m_pLabel->setFixedHeight(30); m_pLabel->setLabelType(KLabelType::DataType); // 调整位置使其不遮盖边框 m_pLabel->move(2, 2); m_pLabel->setVisible(false); m_pLabel->setDataHightColor(true); m_pLabel->setFixedWidth(70); m_pTextCursor = new QTextCursor(q->textCursor()); connect(m_gsetting, &QGSettings::changed, q, [=] { changeTheme(); m_pLabel->setFixedWidth(q->fontMetrics().horizontalAdvance(m_pLabel->text()) + m_pLabel->pixmap()->width() + 12); // if(q->fontMetrics().height() > 30) // m_pLabel->setFixedHeight(q->fontMetrics().height() + 4); }); KDK_ALL_INFO_FORMAT(m_pLabel,""); } void KTextEditPrivate::changeTheme() { Q_Q(KTextEdit); initThemeStyle(); } } #include "ktextedit.moc" #include "moc_ktextedit.cpp" libkysdk-applications/kysdk-qtwidgets/src/klineframe.h0000664000175000017500000000332415104543305022215 0ustar fengfeng/* * libkysdk-qtwidgets's Library * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #ifndef KLINEFRAME_H #define KLINEFRAME_H #include "gui_g.h" #include namespace kdk { class KHLineFramePrivate; class KVLineFramePrivate; /** * @defgroup FrameModule * @since 2.0.2.1 * { */ class GUI_EXPORT KHLineFrame : public QFrame { Q_OBJECT public: KHLineFrame(QWidget *parent = nullptr); ~KHLineFrame(); /** * @brief 设置是否遵循默认色板 * @param flag * @since 2.4.1.0 */ void setFollowPalette(bool flag); private: Q_DECLARE_PRIVATE(KHLineFrame) KHLineFramePrivate *const d_ptr; }; class GUI_EXPORT KVLineFrame : public QFrame { Q_OBJECT public: KVLineFrame(QWidget *parent = nullptr); ~KVLineFrame(); /** * @brief 设置是否遵循默认色板 * @param flag * @since 2.4.1.0 */ void setFollowPalette(bool flag); private: Q_DECLARE_PRIVATE(KVLineFrame) KVLineFramePrivate *const d_ptr; }; } #endif // KLINEFRAME_H libkysdk-applications/kysdk-qtwidgets/src/gui_g.h0000664000175000017500000000177415104543305021201 0ustar fengfeng/* * libkysdk-qtwidgets's Library * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #ifndef GUI_G_H #define GUI_G_H #include /** * @since 1.0.0 */ #if defined(GUI_LIBRARY) #define GUI_EXPORT Q_DECL_EXPORT #else #define GUI_EXPORT Q_DECL_IMPORT #endif #endif // KYSDKTEST_GLOBAL_H libkysdk-applications/kysdk-qtwidgets/src/kaboutdialog.h0000664000175000017500000000623715104543305022553 0ustar fengfeng/* * libkysdk-qtwidgets's Library * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #ifndef KABOUTDIALOG_H #define KABOUTDIALOG_H #include "gui_g.h" #include "kdialog.h" #include "themeController.h" #include #include #include namespace kdk { /** @defgroup DialogBoxModule * @{ */ class KAboutDialogPrivate; /** * @brief 关于对话框,支持两种样式,一种是无特定说明的,另一种是有特定说明的。 * @since 1.0.0 */ class GUI_EXPORT KAboutDialog : public KDialog { Q_OBJECT public: KAboutDialog(QWidget *parent = nullptr, const QIcon &appIcon = QIcon(), const QString &appName = "", const QString &appVersion = "", const QString &appInfo = ""); ~KAboutDialog(); /** * @brief 设置应用程序图标 * @param icon */ void setAppIcon(const QIcon &icon); /** * @brief 设置应用程序名称 * @param appName */ void setAppName(const QString &appName); /** * @brief 获取应用程序名称 * @return */ QString appName(); /** * @brief 设置应用程序版本号 * @param appVersion */ void setAppVersion(const QString &appVersion); /** * @brief 获取应用程序版本号 * @return */ QString appVersion(); /** * @brief 设置具体的说明内容 * @param bodyText */ void setBodyText(const QString &bodyText); /** * @brief 获取具体的说明内容 * @return */ QString bodyText(); /** * @brief 设置服务与支持邮箱,有默认缺省 * @param appSupport */ void setAppSupport(const QString &appSupport); /** * @brief 获取服务与支持邮箱 * @return */ QString appSupport(); /** * @brief 设置是否显示说明内容,应设计要求,1.2.0.9中不再显示说明内容 * @param flag */ void setBodyTextVisiable(bool flag); /** * @brief 设置隐私按钮是否可见 * @param flag * @since 1.2.0 */ void setAppPrivacyLabelVisible(bool flag); /** * @brief 返回隐私按钮是否可见 * @return * @since 1.2.0 */ bool AppPrivacyLabelIsVisible(); protected: void changeTheme() override; void paintEvent(QPaintEvent *paintEvent) override; private: Q_DECLARE_PRIVATE(KAboutDialog) KAboutDialogPrivate *const d_ptr; }; } /** * @example testDialog/widget.h * @example testDialog/widget.cpp * @} */ #endif libkysdk-applications/kysdk-qtwidgets/src/ktag.h0000664000175000017500000000453115104543305021027 0ustar fengfeng/* * libkysdk-qtwidgets's Library * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #ifndef KTAG_H #define KTAG_H #include "gui_g.h" #include namespace kdk { /** * @defgroup TagModule * { */ class KTagPrivate; /** * @brief 支持四种风格的tag */ enum TagStyle { HighlightTag, BoderTag, BaseBoderTag, GrayTag, IconTag }; /** * @brief 提供四种样式的标签,响应系统主题色变化 * @since 1.0.0 */ class GUI_EXPORT KTag : public QPushButton { Q_OBJECT public: explicit KTag(QWidget *parent = nullptr); /** * @brief 设置关闭按钮是否可见 */ void setClosable(bool); /** * @brief 返回关闭按钮是否可见 * @return bool */ bool closable(); /** * @brief 设置文本 */ void setText(const QString &); /** * @brief 获取当前文本 * @return QString */ QString text(); /** * @brief 设置tag样式 */ void setTagStyle(TagStyle); /** * @brief 获取当前tag样式 * @return TagStyle */ TagStyle tagStyle(); /** * @brief 设置背景颜色 * @param flag * @since 2.4.1.0 */ void setBackgroundColor(QColor color); /** * @brief 设置半透明 * @param flag * @since 2.4.1.0 */ void setTranslucent(bool flag); /** * @brief 获取是否启用半透明 * @return bool * @since 2.4.1.0 */ bool translucent(); protected: void paintEvent(QPaintEvent *event); QSize sizeHint() const override; private: Q_DECLARE_PRIVATE(KTag) KTagPrivate *const d_ptr; }; } #endif // KTAG_H libkysdk-applications/kysdk-qtwidgets/src/kcolorbutton.h0000664000175000017500000000432715104543305022631 0ustar fengfeng/* * libkysdk-qtwidgets's Library * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #ifndef KCOLORBUTTON_H #define KCOLORBUTTON_H #include "gui_g.h" #include namespace kdk { /** * @defgroup PushbuttonModule */ class KColorButtonPrivate; /** * @brief 提供用于设置颜色和样式的按钮,以适用于不同的场景。 * @since 2.0.2.1 */ class GUI_EXPORT KColorButton : public QPushButton { Q_OBJECT public: /** * @brief KColorButton提供三种不同的样式 */ enum ButtonType { Circle, RoundedRect, CheckedRect }; KColorButton(QWidget *parent = nullptr); /** * @brief 设置colorButton背景色 * @param color */ void setBackgroundColor(QColor color); /** * @brief 返回colorButton背景色 * @return */ QColor backgroundColor(); /** * @brief 设置圆角(RoundedRect,CheckedRect类型生效) * @param radious */ void setBorderRadius(int radious); /** * @brief 返回圆角 * @return */ int borderRadius(); /** * @brief 设置colorButton类型 * @param type */ void setButtonType(KColorButton::ButtonType type); /** * @brief 返回colorButton类型 * @return */ KColorButton::ButtonType buttonType(); protected: void paintEvent(QPaintEvent *) override; QSize sizeHint() const override; private: Q_DECLARE_PRIVATE(KColorButton) KColorButtonPrivate *const d_ptr; }; } #endif // KCOLORBUTTON_H libkysdk-applications/kysdk-qtwidgets/src/kmessagebox.h0000664000175000017500000002273415104543305022416 0ustar fengfeng/* * libkysdk-qtwidgets's Library * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #ifndef KMESSAGEBOX_H #define KMESSAGEBOX_H #include "gui_g.h" #include "kdialog.h" #include #include #include namespace kdk { /** * @defgroup DialogBoxModule */ class KMessageBoxPrivate; /** * @brief 继承自KDialog,提供一个可自定义设置按钮和图标的对话框,类似QMessageBox * @since 2.0.2.1 */ class GUI_EXPORT KMessageBox : public KDialog { Q_OBJECT public: /** * @brief The Icon enum,icon的五种类型,与 QMessageDialogOptions::Icon 保持同步 */ enum Icon { // keep this in sync with QMessageDialogOptions::Icon NoIcon = 0, Information = 1, Warning = 2, Critical = 3, Question = 4, }; Q_ENUM(Icon) /** * @brief The ButtonRole enum,可供设置的按钮role */ enum ButtonRole { InvalidRole = -1, AcceptRole, RejectRole, DestructiveRole, ActionRole, HelpRole, YesRole, NoRole, ResetRole, ApplyRole, NRoles }; /** * @brief The StandardButton enum,可供添加的按钮类型,与 QDialogButtonBox::StandardButton * 和 QPlatformDialogHelper::StandardButton 保持同步 */ enum StandardButton { // keep this in sync with QDialogButtonBox::StandardButton and QPlatformDialogHelper::StandardButton NoButton = 0x00000000, Ok = 0x00000400, Save = 0x00000800, SaveAll = 0x00001000, Open = 0x00002000, Yes = 0x00004000, YesToAll = 0x00008000, No = 0x00010000, NoToAll = 0x00020000, Abort = 0x00040000, Retry = 0x00080000, Ignore = 0x00100000, Close = 0x00200000, Cancel = 0x00400000, Discard = 0x00800000, Help = 0x01000000, Apply = 0x02000000, Reset = 0x04000000, RestoreDefaults = 0x08000000, FirstButton = Ok, // internal LastButton = RestoreDefaults, // internal YesAll = YesToAll, // obsolete NoAll = NoToAll, // obsolete Default = 0x00000100, // obsolete Escape = 0x00000200, // obsolete FlagMask = 0x00000300, // obsolete ButtonMask = ~FlagMask // obsolete }; typedef StandardButton Button; Q_DECLARE_FLAGS(StandardButtons, StandardButton) Q_FLAG(StandardButtons) KMessageBox(QWidget *parent = nullptr); ~KMessageBox(); /** * @brief 自定义KMessageBox的提示图标 * @param icon */ void setCustomIcon(const QIcon &icon); /** * @brief 添加一个自定义按钮 * @param button * @param role */ void addButton(QAbstractButton *button, ButtonRole role); /** * @brief 添加设置好文本的按钮 * @param text * @param role * @return */ QPushButton *addButton(const QString &text, ButtonRole role); /** * @brief 添加一个标准按钮并且返回这个按钮 * @param button * @return */ QPushButton *addButton(StandardButton button); /** * @brief 移除一个按钮 * @param button */ void removeButton(QAbstractButton *button); /** * @brief 返回与标准按钮对应的指针,如果此消息框中不存在标准按钮,则返回0。 * @param which * @return */ QAbstractButton *button(StandardButton which) const; /** * @brief 返回已添加到消息框中的所有按钮的列表 * @return */ QList buttons() const; /** * @brief 返回指定按钮的按钮角色,如果按钮为0或尚未添加到消息框中,此函数将返回InvalidRole * @param button * @return */ KMessageBox::ButtonRole buttonRole(QAbstractButton *button) const; /** * @brief 返回KMessageBox中显示的复选框 * @return */ QCheckBox *checkBox() const; /** * @brief 设置KMessageBox显示的复选框,未设置则为0 * @param cb */ void setCheckBox(QCheckBox *cb); /** * @brief 获取KMessageBox的文本 * @return */ QString text() const; /** * @brief 设置KMessageBox的文本 * @param text */ void setText(const QString &text); /** * @brief 获取KMessageBox信息性文本的描述 * @return */ QString informativeText() const; /** * @brief 设置KMessageBox信息性文本的描述 * @param text */ void setInformativeText(const QString &text); /** * @brief 获取KMessageBox的图标 * @return */ Icon icon() const; /** * @brief 设置KMessageBox的图标 * @param icon */ void setIcon(Icon icon); /** * @brief 返回当前KMessageBox的icon * @return */ QPixmap iconPixmap() const; /** * @brief 设置当前KMessageBox的icon * @param pixmap */ void setIconPixmap(const QPixmap &pixmap); /** * @brief KMessageBox中标准按钮的集合 * @return */ KMessageBox::StandardButtons standardButtons() const; /** * @brief 设置多个标准按钮 * @param buttons */ void setStandardButtons(KMessageBox::StandardButtons buttons); /** * @brief 返回与给定按钮对应的标准按钮枚举值,如果给定按钮不是标准按钮,则返回NoButton * @param button * @return */ KMessageBox::StandardButton standardButton(QAbstractButton *button) const; /** * @brief 返回KMessageBox的默认按钮 * @return */ QPushButton *defaultButton() const; /** * @brief 设置KMessageBox的默认按钮 * @param button */ void setDefaultButton(QPushButton *button); /** * @brief 设置KMessageBox的默认按钮 * @param button */ void setDefaultButton(KMessageBox::StandardButton button); /** * @brief 返回被点击的按钮 * @return */ QAbstractButton *clickedButton() const; /** * @brief 返回用于标准图标的pixmap。 * @param icon * @return */ static QPixmap standardIcon(Icon icon); /** * @brief 打开带有给定标题和文本的信息消息框。对话框最多可以有三个按钮 * @param parent * @param title * @param text * @param buttons * @param defaultButton * @return */ static StandardButton information(QWidget *parent, const QString &title, const QString &text, StandardButtons buttons = Ok, StandardButton defaultButton = NoButton); /** * @brief 打开一个带有给定标题和文本的问题消息框 * @param parent * @param title * @param text * @param buttons * @param defaultButton * @return */ static StandardButton question(QWidget *parent, const QString &title, const QString &text, StandardButtons buttons = StandardButtons(Yes | No), StandardButton defaultButton = NoButton); /** * @brief 打开一个带有给定标题和文本的警告消息框 * @param parent * @param title * @param text * @param buttons * @param defaultButton * @return */ static StandardButton warning(QWidget *parent, const QString &title, const QString &text, StandardButtons buttons = Ok, StandardButton defaultButton = NoButton); /** * @brief 用给定的标题和文本打开一个关键信息框 * @param parent * @param title * @param text * @param buttons * @param defaultButton * @return */ static StandardButton critical(QWidget *parent, const QString &title, const QString &text, StandardButtons buttons = Ok, StandardButton defaultButton = NoButton); /** * @brief 用给定的标题和文本打开一个成功消息框 * @param parent * @param title * @param text * @param buttons * @param defaultButton * @return */ static StandardButton success(QWidget *parent, const QString &title, const QString &text, StandardButtons buttons = Ok, StandardButton defaultButton = NoButton); /** * @brief 返回informativeLabel * @return * @since 3.0.1.0 */ QLabel *informativeLabel(); Q_SIGNALS: void buttonClicked(QAbstractButton *button); protected: bool event(QEvent *e) override; private: Q_DECLARE_PRIVATE(KMessageBox) KMessageBoxPrivate *const d_ptr; }; } #endif // KMESSAGEBOX_H libkysdk-applications/kysdk-qtwidgets/src/ktexteditor.cpp0000664000175000017500000001016415104543305023001 0ustar fengfeng/* * libkysdk-qtwidgets's Library * * Copyright (C) 2024, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhenyu Wang * */ #include "ktexteditor.h" #include "themeController.h" #include #include #include #include #include #include #include namespace kdk { class KTextEditorPrivate : public QObject, public ThemeController { Q_OBJECT Q_DECLARE_PUBLIC(KTextEditor) public: KTextEditorPrivate(KTextEditor *parent); virtual ~KTextEditorPrivate(); private: KTextEditor *q_ptr; QVBoxLayout *m_pVBoxLayout; QScrollArea *m_pScrollArea; QTextEdit *m_pTextEdit; bool m_focus; }; KTextEditor::KTextEditor(QWidget *parent) : QWidget(parent) , d_ptr(new KTextEditorPrivate(this)) { Q_D(KTextEditor); this->setFocusPolicy(Qt::ClickFocus); installEventFilter(this); d->m_pTextEdit->installEventFilter(this); d->m_pScrollArea->installEventFilter(this); } QTextEdit *KTextEditor::textEdit() { Q_D(KTextEditor); return d->m_pTextEdit; } void KTextEditor::paintEvent(QPaintEvent *event) { Q_D(KTextEditor); QPainter painter(this); painter.setRenderHint(QPainter::Antialiasing); painter.fillRect(this->rect(), ThemeController::getCustomColorFromDT("window-active")); QPen pen; pen.setWidth(2); if (d->m_focus) { pen.setColor(ThemeController::getCustomColorFromDT("highlight-active")); painter.setPen(pen); } else { pen.setColor(ThemeController::getCustomColorFromDT("placeholdertext-active")); painter.setPen(pen); } painter.setBrush(ThemeController::getCustomColorFromDT("base-active")); QRect rect = this->rect().adjusted(1, 1, -1, -1); int radius = ThemeController::getRadiusFromDT("kradius-menu"); if (radius == -1) radius = 8; painter.drawRoundedRect(rect, radius, radius); } bool KTextEditor::eventFilter(QObject *watched, QEvent *event) { Q_D(KTextEditor); if (watched == this) { switch (event->type()) { case QEvent::FocusIn: d->m_focus = true; update(); break; case QEvent::FocusOut: d->m_focus = false; update(); break; default: break; } return QWidget::eventFilter(watched, event); } else { switch (event->type()) { case QEvent::FocusIn: d->m_focus = true; update(); break; case QEvent::FocusOut: d->m_focus = false; update(); break; default: break; } return false; } } KTextEditorPrivate::KTextEditorPrivate(KTextEditor *parent) : q_ptr(parent) { Q_Q(KTextEditor); m_pVBoxLayout = new QVBoxLayout(); m_pScrollArea = new QScrollArea(); m_pTextEdit = new QTextEdit(); m_focus = false; q->setContentsMargins(8, 12, 0, 13); // 上下左右边距为20 ,因控件自带边距调整 m_pScrollArea->setWidget(m_pTextEdit); m_pScrollArea->horizontalScrollBar()->setVisible(false); m_pScrollArea->setWidgetResizable(true); m_pScrollArea->setFocusPolicy(Qt::ClickFocus); m_pTextEdit->setFrameShape(QFrame::NoFrame); m_pScrollArea->setFrameShape(QFrame::NoFrame); m_pVBoxLayout->addWidget(m_pScrollArea); q->setLayout(m_pVBoxLayout); } KTextEditorPrivate::~KTextEditorPrivate() { } } #include "ktexteditor.moc" #include "moc_ktexteditor.cpp" libkysdk-applications/kysdk-qtwidgets/src/ksearchlineedit.h0000664000175000017500000000725015104543305023240 0ustar fengfeng/* * libkysdk-qtwidgets's Library * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #ifndef KSEARCHBAR_H #define KSEARCHBAR_H #include "gui_g.h" #include "ktoolbutton.h" #include #include namespace kdk { /** @defgroup InputBoxModule * @{ */ class KSearchLineEditPrivate; /** * @brief 搜索输入框,可搜索匹配条件的item * @since 1.0.0 */ class GUI_EXPORT KSearchLineEdit : public QLineEdit { Q_OBJECT public: explicit KSearchLineEdit(QWidget *parent = nullptr); ~KSearchLineEdit(); /** * @brief 设置是否可用 */ void setEnabled(bool); /** * @brief 返回是否可用 * @return */ bool isEnabled(); /** * @brief 设置是否显示清除按钮 * @return */ void setClearButtonEnabled(bool enable); /** * @brief 返回是否显示清除按钮 * @return */ bool isClearButtonEnabled() const; /** * @brief 返回placeholder * @return */ QString placeholderText() const; /** * @brief 设置placeholder * @return */ void setPlaceholderText(const QString &); /** * @brief 返回placeholder的对齐方式 * @return */ Qt::Alignment placeholderAlignment() const; /** * @brief 设置placeholder的对齐方式 * @return */ void setPlaceholderAlignment(Qt::Alignment flag); /** * @brief 设置输入文本的对齐方式 * @return */ Qt::Alignment alignment() const; /** * @brief 设置输入文本的对齐方式返回 * @return */ void setAlignment(Qt::Alignment flag); /** * @brief 设置是否启用半透明效果 * @since 1.2.0 * @param flag */ void setTranslucent(bool flag); /** * @brief 获取是否启用半透明效果 * @since 1.2.0 * @return flag */ bool isTranslucent(); /** * @brief 重新加载style * @since 2.0.2.1 */ void reloadStyle(); /** * @brief 获取自定义按钮 * @return * @since 2.4.1.0 */ KToolButton *customButton(); /** * @brief 是否启用渐变色 * @param flag * @since 2.4.1.0 */ void setGradation(bool flag); /** * @brief 设置智能语义按钮是否可见 * @param flag * @since 2.4.1.0 */ void setCustomButtonVisible(bool flag); /** * @brief 返回智能语义按钮是否可见 * @return bool * @since 2.4.1.0 */ bool isCustomButtonVisible(); public Q_SLOTS: void clear(); protected: bool eventFilter(QObject *watched, QEvent *event); void resizeEvent(QResizeEvent *event); void setVisible(bool visible); void paintEvent(QPaintEvent *event); QSize sizeHint() const override; private: Q_DECLARE_PRIVATE(KSearchLineEdit) KSearchLineEditPrivate *d_ptr; }; } /** * @example testsearchlinedit/widget.h * @example testsearchlinedit/widget.cpp * @} */ #endif // KSEARCHBAR_H libkysdk-applications/kysdk-qtwidgets/src/kmessagebox.cpp0000664000175000017500000005603615104543305022753 0ustar fengfeng/* * libkysdk-qtwidgets's Library * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #include "kmessagebox.h" #include "accessinfohelper.h" #include "themeController.h" #include #include #include #include #include #include #include #include #include #include #include namespace kdk { enum Button { Old_Ok = 1, Old_Cancel = 2, Old_Yes = 3, Old_No = 4, Old_Abort = 5, Old_Retry = 6, Old_Ignore = 7, Old_YesAll = 8, Old_NoAll = 9, Old_ButtonMask = 0xFF, NewButtonMask = 0xFFFFFC00 }; static QString iconName = ""; class KMessageBoxPrivate : public QObject, public ThemeController { Q_OBJECT Q_DECLARE_PUBLIC(KMessageBox) public: KMessageBoxPrivate(KMessageBox *parent); void init(const QString &title = QString(), const QString &text = QString()); static QPixmap standardIcon(KMessageBox::Icon icon, KMessageBox *mb); void setupLayout(); void updateSize(); void setClickedButton(QAbstractButton *button); int execReturnCode(QAbstractButton *button); int dialogCodeForButton(QAbstractButton *button) const; void addOldButtons(int button0, int button1, int button2); QAbstractButton *findButton(int button0, int button1, int button2, int flags); void setAccessInfo(); public Q_SLOTS: void _q_buttonClicked(QAbstractButton *); protected: void changeTheme(); private: KMessageBox *q_ptr; QLabel *iconLabel; QLabel *label; QLabel *informativeLabel; QDialogButtonBox *buttonBox; QList customButtonList; KMessageBox::Icon icon; QAbstractButton *clickedButton; QCheckBox *checkbox; QPushButton *defaultButton; bool autoAddOkButton; bool compatMode; QString m_iconName; }; KMessageBox::KMessageBox(QWidget *parent) : KDialog(parent) , d_ptr(new KMessageBoxPrivate(this)) { Q_D(KMessageBox); d->init(); d->changeTheme(); connect(d->m_gsetting, &QGSettings::changed, this, [=]() { d->changeTheme(); }); } KMessageBox::~KMessageBox() { } void KMessageBox::setCustomIcon(const QIcon &icon) { Q_D(KMessageBox); d->m_iconName = icon.name(); this->setIconPixmap(icon.pixmap(24, 24)); } void KMessageBox::addButton(QAbstractButton *button, ButtonRole role) { Q_D(KMessageBox); if (!button) return; removeButton(button); d->buttonBox->addButton(button, (QDialogButtonBox::ButtonRole)role); d->customButtonList.append(button); d->autoAddOkButton = false; } QPushButton *KMessageBox::addButton(const QString &text, ButtonRole role) { Q_D(KMessageBox); QPushButton *pushButton = new QPushButton(text); addButton(pushButton, role); return pushButton; } QPushButton *KMessageBox::addButton(StandardButton button) { Q_D(KMessageBox); QPushButton *pushButton = d->buttonBox->addButton((QDialogButtonBox::StandardButton)button); pushButton->setIcon(QIcon()); if (pushButton) d->autoAddOkButton = false; return pushButton; } void KMessageBox::removeButton(QAbstractButton *button) { Q_D(KMessageBox); d->customButtonList.removeAll(button); if (d->defaultButton == button) d->defaultButton = 0; d->buttonBox->removeButton(button); } QAbstractButton *KMessageBox::button(KMessageBox::StandardButton which) const { Q_D(const KMessageBox); return d->buttonBox->button(QDialogButtonBox::StandardButton(which)); } QList KMessageBox::buttons() const { Q_D(const KMessageBox); return d->buttonBox->buttons(); } KMessageBox::ButtonRole KMessageBox::buttonRole(QAbstractButton *button) const { Q_D(const KMessageBox); return KMessageBox::ButtonRole(d->buttonBox->buttonRole(button)); } QCheckBox *KMessageBox::checkBox() const { Q_D(const KMessageBox); return d->checkbox; } void KMessageBox::setCheckBox(QCheckBox *cb) { Q_D(KMessageBox); if (cb == d->checkbox) return; if (d->checkbox) { d->checkbox->hide(); layout()->removeWidget(d->checkbox); if (d->checkbox->parentWidget() == this) { d->checkbox->setParent(0); d->checkbox->deleteLater(); } } d->checkbox = cb; if (d->checkbox) { QSizePolicy sp = d->checkbox->sizePolicy(); sp.setHorizontalPolicy(QSizePolicy::MinimumExpanding); d->checkbox->setSizePolicy(sp); } d->setupLayout(); } QString KMessageBox::text() const { Q_D(const KMessageBox); return d->label->text(); } void KMessageBox::setText(const QString &text) { Q_D(KMessageBox); d->label->setText(text); d->label->setWordWrap(d->label->textFormat() == Qt::RichText || (d->label->textFormat() == Qt::AutoText && Qt::mightBeRichText(text))); d->updateSize(); } QString KMessageBox::informativeText() const { Q_D(const KMessageBox); return d->informativeLabel ? d->informativeLabel->text() : QString(); } void KMessageBox::setInformativeText(const QString &text) { Q_D(KMessageBox); if (text.isEmpty()) { if (d->informativeLabel) { d->informativeLabel->hide(); d->informativeLabel->deleteLater(); } d->informativeLabel = 0; } else { if (!d->informativeLabel) { QLabel *label = new QLabel; label->setObjectName(QLatin1String("qt_msgbox_informativelabel")); label->setTextInteractionFlags(Qt::TextInteractionFlags(style()->styleHint(QStyle::SH_MessageBox_TextInteractionFlags, 0, this))); label->setAlignment(Qt::AlignTop | Qt::AlignLeft); label->setOpenExternalLinks(true); label->setWordWrap(true); d->informativeLabel = label; d->setAccessInfo(); } d->informativeLabel->setText(text); } d->setupLayout(); } KMessageBox::Icon KMessageBox::icon() const { Q_D(const KMessageBox); return d->icon; } void KMessageBox::setIcon(Icon icon) { Q_D(KMessageBox); setIconPixmap(KMessageBoxPrivate::standardIcon((KMessageBox::Icon)icon, this)); d->icon = icon; } QPixmap KMessageBox::iconPixmap() const { Q_D(const KMessageBox); if (d->iconLabel && d->iconLabel->pixmap().isNull()) return d->iconLabel->pixmap(); return QPixmap(); } void KMessageBox::setIconPixmap(const QPixmap &pixmap) { Q_D(KMessageBox); d->iconLabel->setPixmap(pixmap); d->icon = NoIcon; d->setupLayout(); } KMessageBox::StandardButtons KMessageBox::standardButtons() const { Q_D(const KMessageBox); return KMessageBox::StandardButtons(int(d->buttonBox->standardButtons())); } void KMessageBox::setStandardButtons(KMessageBox::StandardButtons buttons) { Q_D(KMessageBox); d->buttonBox->setStandardButtons(QDialogButtonBox::StandardButtons(int(buttons))); QList buttonList = d->buttonBox->buttons(); if (!buttonList.contains(d->defaultButton)) d->defaultButton = 0; d->autoAddOkButton = false; } KMessageBox::StandardButton KMessageBox::standardButton(QAbstractButton *button) const { Q_D(const KMessageBox); return (KMessageBox::StandardButton)d->buttonBox->standardButton(button); } QPushButton *KMessageBox::defaultButton() const { Q_D(const KMessageBox); return d->defaultButton; } void KMessageBox::setDefaultButton(QPushButton *button) { Q_D(KMessageBox); if (!d->buttonBox->buttons().contains(button)) { return; } d->defaultButton = button; button->setProperty("isImportant", true); button->setDefault(true); button->setFocus(); } void KMessageBox::setDefaultButton(KMessageBox::StandardButton button) { Q_D(KMessageBox); setDefaultButton(d->buttonBox->button(QDialogButtonBox::StandardButton(button))); } QAbstractButton *KMessageBox::clickedButton() const { Q_D(const KMessageBox); return d->clickedButton; } QPixmap KMessageBox::standardIcon(KMessageBox::Icon icon) { return KMessageBoxPrivate::standardIcon(icon, 0); } KMessageBox::StandardButton KMessageBox::information(QWidget *parent, const QString &title, const QString &text, StandardButtons buttons, KMessageBox::StandardButton defaultButton) { KMessageBox msgBox(parent); msgBox.setIcon(KMessageBox::Icon::Information); msgBox.setWindowTitle(title); msgBox.setText(text); msgBox.setStandardButtons(buttons); msgBox.setDefaultButton(defaultButton); msgBox.setParent(parent); QDialogButtonBox *buttonBox = msgBox.findChild(); Q_ASSERT(buttonBox != 0); if (msgBox.exec() == -1) return KMessageBox::Cancel; return msgBox.standardButton(msgBox.clickedButton()); } KMessageBox::StandardButton KMessageBox::question(QWidget *parent, const QString &title, const QString &text, StandardButtons buttons, KMessageBox::StandardButton defaultButton) { KMessageBox msgBox(parent); msgBox.setIcon(KMessageBox::Icon::Question); msgBox.setWindowTitle(title); msgBox.setText(text); msgBox.setStandardButtons(buttons); msgBox.setDefaultButton(defaultButton); msgBox.setParent(parent); QDialogButtonBox *buttonBox = msgBox.findChild(); Q_ASSERT(buttonBox != 0); if (msgBox.exec() == -1) return KMessageBox::Cancel; return msgBox.standardButton(msgBox.clickedButton()); } KMessageBox::StandardButton KMessageBox::warning(QWidget *parent, const QString &title, const QString &text, StandardButtons buttons, KMessageBox::StandardButton defaultButton) { KMessageBox msgBox(parent); msgBox.setIcon(KMessageBox::Icon::Warning); msgBox.setWindowTitle(title); msgBox.setText(text); msgBox.setStandardButtons(buttons); msgBox.setDefaultButton(defaultButton); msgBox.setParent(parent); QDialogButtonBox *buttonBox = msgBox.findChild(); Q_ASSERT(buttonBox != 0); if (msgBox.exec() == -1) return KMessageBox::Cancel; return msgBox.standardButton(msgBox.clickedButton()); } KMessageBox::StandardButton KMessageBox::critical(QWidget *parent, const QString &title, const QString &text, StandardButtons buttons, KMessageBox::StandardButton defaultButton) { KMessageBox msgBox(parent); msgBox.setIcon(KMessageBox::Icon::Critical); msgBox.setWindowTitle(title); msgBox.setText(text); msgBox.setStandardButtons(buttons); msgBox.setDefaultButton(defaultButton); msgBox.setParent(parent); QDialogButtonBox *buttonBox = msgBox.findChild(); Q_ASSERT(buttonBox != 0); if (msgBox.exec() == -1) return KMessageBox::Cancel; return msgBox.standardButton(msgBox.clickedButton()); } KMessageBox::StandardButton KMessageBox::success(QWidget *parent, const QString &title, const QString &text, StandardButtons buttons, KMessageBox::StandardButton defaultButton) { KMessageBox msgBox(parent); msgBox.setCustomIcon(QIcon::fromTheme("ukui-dialog-success")); msgBox.setWindowTitle(title); msgBox.setText(text); msgBox.setStandardButtons(buttons); msgBox.setDefaultButton(defaultButton); msgBox.setParent(parent); QDialogButtonBox *buttonBox = msgBox.findChild(); Q_ASSERT(buttonBox != 0); if (msgBox.exec() == -1) return KMessageBox::Cancel; return msgBox.standardButton(msgBox.clickedButton()); } QLabel *KMessageBox::informativeLabel() { Q_D(KMessageBox); return d->informativeLabel; } bool KMessageBox::event(QEvent *e) { Q_D(KMessageBox); bool result = KDialog::event(e); switch (e->type()) { case QEvent::LayoutRequest: d->updateSize(); break; case QEvent::FontChange: d->updateSize(); break; case QEvent::Show: { d->updateSize(); QWidget *parentWindow = qobject_cast(this->parent()); if (parentWindow && parentWindow->isActiveWindow()) { const QPoint parentWindowCenter = parentWindow->geometry().center(); const QPoint messageBoxCenter = this->geometry().center(); const QPoint moveOffset = parentWindowCenter - messageBoxCenter; move(pos() + moveOffset); } else { QScreen *screen = QGuiApplication::primaryScreen(); int screenWidth = screen->geometry().width(); int screenHeight = screen->geometry().height(); int messageBox_X = (screenWidth - this->width()) / 2; int messageBox_Y = (screenHeight - this->height()) / 2; this->move(messageBox_X, messageBox_Y); } break; } default: break; } return result; } KMessageBoxPrivate::KMessageBoxPrivate(KMessageBox *parent) : q_ptr(parent) , informativeLabel(0) , checkbox(0) , compatMode(false) , clickedButton(0) , defaultButton(0) { Q_Q(KMessageBox); setParent(parent); } void KMessageBoxPrivate::init(const QString &title, const QString &text) { Q_Q(KMessageBox); label = new QLabel; label->setObjectName(QLatin1String("qt_kmsgbox_label")); label->setTextInteractionFlags(Qt::TextInteractionFlags(q->style()->styleHint(QStyle::SH_MessageBox_TextInteractionFlags, 0, q))); label->setAlignment(Qt::AlignVCenter | Qt::AlignLeft); label->setOpenExternalLinks(true); iconLabel = new QLabel(q); iconLabel->setObjectName(QLatin1String("qt_kmsgbox_icon_label")); iconLabel->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); buttonBox = new QDialogButtonBox; buttonBox->setObjectName(QLatin1String("qt_kmsgbox_buttonbox")); buttonBox->setCenterButtons(q->style()->styleHint(QStyle::SH_MessageBox_CenterButtons, nullptr, q)); QObject::connect(buttonBox, SIGNAL(clicked(QAbstractButton *)), this, SLOT(_q_buttonClicked(QAbstractButton *))); setupLayout(); if (!title.isEmpty() || !text.isEmpty()) { q->setWindowTitle(title); q->setText(text); } q->setModal(true); icon = KMessageBox::NoIcon; KDK_ALL_INFO_FORMAT(iconLabel,""); KDK_ALL_INFO_FORMAT(label,""); KDK_ALL_INFO_FORMAT(buttonBox,""); } QPixmap KMessageBoxPrivate::standardIcon(KMessageBox::Icon icon, KMessageBox *mb) { QStyle *style = mb ? mb->style() : QApplication::style(); int iconSize = style->pixelMetric(QStyle::PM_MessageBoxIconSize, nullptr, mb); QIcon tmpIcon; switch (icon) { case KMessageBox::Information: tmpIcon = style->standardIcon(QStyle::SP_MessageBoxInformation, nullptr, mb); iconName = tmpIcon.name(); break; case KMessageBox::Warning: tmpIcon = style->standardIcon(QStyle::SP_MessageBoxWarning, nullptr, mb); iconName = tmpIcon.name(); break; case KMessageBox::Critical: tmpIcon = style->standardIcon(QStyle::SP_MessageBoxCritical, nullptr, mb); iconName = tmpIcon.name(); break; case KMessageBox::Question: tmpIcon = style->standardIcon(QStyle::SP_MessageBoxQuestion, nullptr, mb); iconName = tmpIcon.name(); default: break; } if (!tmpIcon.isNull()) { QWindow *window = nullptr; if (mb) { window = mb->windowHandle(); if (!window) { if (const QWidget *nativeParent = mb->nativeParentWidget()) window = nativeParent->windowHandle(); } } return tmpIcon.pixmap(window, QSize(iconSize, iconSize)); } return QPixmap(); } void KMessageBoxPrivate::setupLayout() { Q_Q(KMessageBox); if (q->mainWidget()->layout()) delete q->mainWidget()->layout(); QGridLayout *grid = new QGridLayout; QHBoxLayout *buttonLayout = new QHBoxLayout; buttonLayout->setContentsMargins(0, 0, 0, 0); grid->setHorizontalSpacing(8); if (informativeLabel) grid->setVerticalSpacing(8); else grid->setVerticalSpacing(0); grid->setContentsMargins(0, 0, 0, 0); bool hasIcon = !iconLabel->pixmap().isNull(); if (hasIcon) grid->addWidget(iconLabel, 0, 0, 2, 1, Qt::AlignTop); iconLabel->setVisible(hasIcon); grid->addWidget(label, 0, hasIcon ? 2 : 1, 1, 1); if (informativeLabel) { grid->addWidget(informativeLabel, 1, hasIcon ? 2 : 1, 1, 1); } grid->setSizeConstraint(QLayout::SetNoConstraint); QVBoxLayout *layout = new QVBoxLayout; layout->setContentsMargins(24, 0, 24, 24); buttonLayout->setSizeConstraint(QLayout::SetNoConstraint); if (checkbox) buttonLayout->addWidget(checkbox, 0, Qt::AlignLeft | Qt::AlignVCenter); buttonLayout->addWidget(buttonBox, 0, Qt::AlignRight | Qt::AlignVCenter); layout->setSpacing(0); layout->addLayout(grid); layout->addSpacing(32); layout->addLayout(buttonLayout); q->mainWidget()->setLayout(layout); updateSize(); } void KMessageBoxPrivate::updateSize() { Q_Q(KMessageBox); if (!q->isVisible()) return; while (buttonBox->layout()->count() < buttonBox->buttons().count() + 1) { QEvent event(QEvent::StyleChange); QGuiApplication::sendEvent(buttonBox, &event); } QSize minSize(424, 156); QSize size; QSize screenSize = QGuiApplication::screenAt(QCursor::pos())->availableGeometry().size(); QSize maxSize(screenSize.width() * 0.8, screenSize.height() * 0.8); label->setWordWrap(false); if (informativeLabel) { informativeLabel->setWordWrap(false); } q->mainWidget()->layout()->activate(); if (q->sizeHint().width() > qMax(buttonBox->sizeHint().width() + 24 + 24, 452)) { label->setWordWrap(true); if (informativeLabel) { informativeLabel->setWordWrap(true); } } q->mainWidget()->layout()->activate(); q->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); size.setWidth(qMax(qMin(maxSize.width(), q->sizeHint().width()), minSize.width())); size.setHeight(qMax(qMin(maxSize.height(), q->layout()->hasHeightForWidth() ? q->layout()->totalHeightForWidth(size.width()) : q->layout()->totalMinimumSize().height()), minSize.height())); q->setFixedSize(size); QCoreApplication::removePostedEvents(q, QEvent::LayoutRequest); } void KMessageBoxPrivate::_q_buttonClicked(QAbstractButton *button) { Q_Q(KMessageBox); setClickedButton(button); } static int oldButton(int button) { switch (button & KMessageBox::ButtonMask) { case KMessageBox::Ok: return Old_Ok; case KMessageBox::Cancel: return Old_Cancel; case KMessageBox::Yes: return Old_Yes; case KMessageBox::No: return Old_No; case KMessageBox::Abort: return Old_Abort; case KMessageBox::Retry: return Old_Retry; case KMessageBox::Ignore: return Old_Ignore; case KMessageBox::YesToAll: return Old_YesAll; case KMessageBox::NoToAll: return Old_NoAll; default: return 0; } } void KMessageBoxPrivate::setClickedButton(QAbstractButton *button) { Q_Q(KMessageBox); clickedButton = button; emit q->buttonClicked(clickedButton); int resultCode = execReturnCode(button); q->setResult(resultCode); q->hide(); q->close(); int dialogCode = dialogCodeForButton(button); if (dialogCode == QDialog::Accepted) emit q->accepted(); else if (dialogCode == QDialog::Rejected) emit q->rejected(); emit q->finished(resultCode); } int KMessageBoxPrivate::execReturnCode(QAbstractButton *button) { int ret = buttonBox->standardButton(button); if (ret == KMessageBox::NoButton) { ret = customButtonList.indexOf(button); // if button == 0, correctly sets ret = -1 } else if (compatMode) { ret = oldButton(ret); } return ret; } int KMessageBoxPrivate::dialogCodeForButton(QAbstractButton *button) const { Q_Q(const KMessageBox); switch (q->buttonRole(button)) { case KMessageBox::AcceptRole: case KMessageBox::YesRole: return KDialog::Accepted; case KMessageBox::RejectRole: case KMessageBox::NoRole: return KDialog::Rejected; default: return -1; } } static KMessageBox::StandardButton newButton(int button) { // this is needed for source compatibility with Qt 4.0 and 4.1 if (button == KMessageBox::NoButton || (button & NewButtonMask)) return KMessageBox::StandardButton(button & KMessageBox::ButtonMask); #if QT_VERSION < 0x050000 // this is needed for binary compatibility with Qt 4.0 and 4.1 switch (button & Old_ButtonMask) { case Old_Ok: return KMessageBox::Ok; case Old_Cancel: return KMessageBox::Cancel; case Old_Yes: return KMessageBox::Yes; case Old_No: return KMessageBox::No; case Old_Abort: return KMessageBox::Abort; case Old_Retry: return KMessageBox::Retry; case Old_Ignore: return KMessageBox::Ignore; case Old_YesAll: return KMessageBox::YesToAll; case Old_NoAll: return KMessageBox::NoToAll; default: return KMessageBox::NoButton; } #else return KMessageBox::NoButton; #endif } static bool detectedCompat(int button0, int button1, int button2) { if (button0 != 0 && !(button0 & NewButtonMask)) return true; if (button1 != 0 && !(button1 & NewButtonMask)) return true; if (button2 != 0 && !(button2 & NewButtonMask)) return true; return false; } void KMessageBoxPrivate::addOldButtons(int button0, int button1, int button2) { Q_Q(KMessageBox); q->addButton(newButton(button0)); q->addButton(newButton(button1)); q->addButton(newButton(button2)); q->setDefaultButton( static_cast(findButton(button0, button1, button2, KMessageBox::Default))); compatMode = detectedCompat(button0, button1, button2); } QAbstractButton *KMessageBoxPrivate::findButton(int button0, int button1, int button2, int flags) { Q_Q(KMessageBox); int button = 0; if (button0 & flags) { button = button0; } else if (button1 & flags) { button = button1; } else if (button2 & flags) { button = button2; } return q->button(newButton(button)); } void KMessageBoxPrivate::setAccessInfo() { Q_Q(KMessageBox); KDK_ALL_INFO_FORMAT(informativeLabel,""); } void KMessageBoxPrivate::changeTheme() { Q_Q(KMessageBox); if (iconName != "") m_iconName = iconName; q->setIconPixmap(QIcon::fromTheme(m_iconName).pixmap(24, 24)); } } #include "kmessagebox.moc" #include "moc_kmessagebox.cpp" libkysdk-applications/kysdk-qtwidgets/src/ksecuritylevelbar.cpp0000664000175000017500000001232415104543305024172 0ustar fengfeng/* * libkysdk-qtwidgets's Library * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #include "ksecuritylevelbar.h" #include "themeController.h" #include #include #include #include #include #include "accessinfohelper.h" namespace kdk { class KSecurityLevelBarPrivate : public QObject { Q_OBJECT Q_DECLARE_PUBLIC(KSecurityLevelBar) public: KSecurityLevelBarPrivate(KSecurityLevelBar *parent); private: KSecurityLevelBar *q_ptr; SecurityLevel m_level; QLabel *m_pLabel; int m_contentMargin = 5; int m_textWidth = 0; int m_space = 5; }; KSecurityLevelBar::KSecurityLevelBar(QWidget *parent) : QWidget(parent) , d_ptr(new KSecurityLevelBarPrivate(this)) { Q_D(KSecurityLevelBar); setFixedSize(300, 30); } void KSecurityLevelBar::setSecurityLevel(SecurityLevel level) { Q_D(KSecurityLevelBar); d->m_level = level; switch (level) { case Low: d->m_pLabel->setText(tr("Low")); break; case Medium: d->m_pLabel->setText(tr("Medium")); break; case High: d->m_pLabel->setText(tr("High")); break; default: break; } repaint(); } SecurityLevel KSecurityLevelBar::securityLevel() { Q_D(KSecurityLevelBar); return d->m_level; } void KSecurityLevelBar::paintEvent(QPaintEvent *event) { Q_D(KSecurityLevelBar); QPainter painter(this); painter.setRenderHint(QPainter::Antialiasing); painter.setPen(Qt::NoPen); d->m_pLabel->adjustSize(); d->m_textWidth = this->fontMetrics().horizontalAdvance(d->m_pLabel->text()) + d->m_space; int rectWitdth = 32; //(rect().width() - d->m_textWidth - d->m_contentMargin * 2) / 3 - d->m_space; int rectHeight = 8; /*height() > 6 ? 6 : height();*/ int currentPos = d->m_contentMargin + d->m_textWidth + d->m_space; switch (d->m_level) { case Low: painter.setBrush(ThemeController::getCustomColorFromDT("kerror-normal")); painter.drawRoundedRect(currentPos, (rect().height() - rectHeight) / 2, rectWitdth, rectHeight, rectHeight / 2, rectHeight / 2); currentPos = currentPos + d->m_space + rectWitdth; painter.setBrush(ThemeController::getCustomColorFromDT("kcomponent-normal")); painter.drawRoundedRect(currentPos, (rect().height() - rectHeight) / 2, rectWitdth, rectHeight, rectHeight / 2, rectHeight / 2); currentPos = currentPos + d->m_space + rectWitdth; painter.drawRoundedRect(currentPos, (rect().height() - rectHeight) / 2, rectWitdth, rectHeight, rectHeight / 2, rectHeight / 2); break; case Medium: painter.setBrush(ThemeController::getCustomColorFromDT("kwarning-normal")); painter.drawRoundedRect(currentPos, (rect().height() - rectHeight) / 2, rectWitdth, rectHeight, rectHeight / 2, rectHeight / 2); currentPos = currentPos + d->m_space + rectWitdth; painter.drawRoundedRect(currentPos, (rect().height() - rectHeight) / 2, rectWitdth, rectHeight, rectHeight / 2, rectHeight / 2); currentPos = currentPos + d->m_space + rectWitdth; painter.setBrush(ThemeController::getCustomColorFromDT("kcomponent-normal")); painter.drawRoundedRect(currentPos, (rect().height() - rectHeight) / 2, rectWitdth, rectHeight, rectHeight / 2, rectHeight / 2); break; case High: painter.setBrush(ThemeController::getCustomColorFromDT("ksuccess-normal")); painter.drawRoundedRect(currentPos, (rect().height() - rectHeight) / 2, rectWitdth, rectHeight, rectHeight / 2, rectHeight / 2); currentPos = currentPos + d->m_space + rectWitdth; painter.drawRoundedRect(currentPos, (rect().height() - rectHeight) / 2, rectWitdth, rectHeight, rectHeight / 2, rectHeight / 2); currentPos = currentPos + d->m_space + rectWitdth; painter.drawRoundedRect(currentPos, (rect().height() - rectHeight) / 2, rectWitdth, rectHeight, rectHeight / 2, rectHeight / 2); break; default: break; } } KSecurityLevelBarPrivate::KSecurityLevelBarPrivate(KSecurityLevelBar *parent) : q_ptr(parent) { Q_Q(KSecurityLevelBar); m_pLabel = new QLabel(q); m_pLabel->setAlignment(Qt::AlignRight | Qt::AlignVCenter); int textHeight = q->fontMetrics().height(); int yPos = (q->height() - textHeight) / 2; m_pLabel->setGeometry(q->rect().left(), yPos, m_textWidth, textHeight); m_level = Low; m_pLabel->setText(tr("Low")); setParent(parent); KDK_ALL_INFO_FORMAT(m_pLabel,""); } } #include "ksecuritylevelbar.moc" #include "moc_ksecuritylevelbar.cpp" libkysdk-applications/kysdk-qtwidgets/src/parmscontroller.h0000664000175000017500000000405315104543305023326 0ustar fengfeng/* * libkysdk-qtwidgets's Library * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #ifndef PARMSCONTROLLER_H #define PARMSCONTROLLER_H #include class QDBusConnection; namespace kdk { /** * @brief The Parmscontroller class * @since 2.0.2.1 */ class Parmscontroller : public QObject { Q_OBJECT public: enum Parm { PM_TabBarHeight, PM_PushButtonHeight, PM_ToolButtonHeight, PM_SearchLineEditHeight, PM_PasswordEditHeight, PM_NavigationBatHeight, PM_TagHeight, PM_SearchLineEditItemHeight, PM_SliderHandleRadius, PM_SliderNodeRadius, PM_BadgeHeight, PM_IconbarHeight, PM_IconBarIconSize, PM_WindowButtonBarSize, PM_NavigationBatInterval, // PM_NavigationBarWidth, PM_Widget_SideWidget_Width, PM_InputDialog_Height, PM_InputDialog_Width, PM_InputDialog_Label_Spacing, PM_InputDialog_Widget_Spacing, PM_InputDialog_Button_Spacing, PM_InputDialog_Bottom_Spacing, PM_InputDialog_Right_Spacing, }; static Parmscontroller *self(); static bool isTabletMode(); static int parm(Parm p); Q_SIGNALS: void modeChanged(bool); private: explicit Parmscontroller(QObject *parent = nullptr); ~Parmscontroller(); }; } #endif // PARMSCONTROLLER_H libkysdk-applications/kysdk-qtwidgets/src/klistview.cpp0000664000175000017500000000321715104543305022455 0ustar fengfeng/* * libkysdk-qtwidgets's Library * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhenyu Wang * */ #include "klistview.h" #include namespace kdk { class KListViewPrivate : public QObject { Q_OBJECT Q_DECLARE_PUBLIC(KListView) public: KListViewPrivate(KListView *parent); private: KListView *q_ptr; }; KListViewPrivate::KListViewPrivate(KListView *parent) : q_ptr(parent) { Q_Q(KListView); setParent(parent); } KListView::KListView(QWidget *parent) : QListView(parent) , d_ptr(new KListViewPrivate(this)) { Q_D(KListView); } void KListView::mousePressEvent(QMouseEvent *event) { Q_D(KListView); QPoint p = event->pos(); // 获取点击坐标 QModelIndex index = indexAt(p); // 点击位置是否为空 if (!index.isValid()) { setCurrentIndex(QModelIndex()); // 实现点空白处取消选择 } QListView::mousePressEvent(event); } } #include "klistview.moc" #include "moc_klistview.cpp" libkysdk-applications/kysdk-qtwidgets/src/ktitlewindow.cpp0000664000175000017500000002333015104543305023156 0ustar fengfeng/* * libkysdk-qtwidgets's Library * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhenyu Wang * */ #include "ktitlewindow.h" #include "themeController.h" #include "ukuistylehelper/ukui-decoration-manager.h" #include "ukuistylehelper/ukui-shell-manager.h" #include #include #include #include #include #include #include #include "xatom-helper.h" namespace kdk { class TitleButton : public QPushButton { Q_OBJECT public: TitleButton(QWidget *widget = nullptr); private: QColor m_color; protected: void paintEvent(QPaintEvent *event); }; class Q_DECL_HIDDEN KTitleWindowPrivate : public QObject, public ThemeController { Q_OBJECT Q_DECLARE_PUBLIC(KTitleWindow) public: KTitleWindowPrivate(KTitleWindow *parent); protected: void changeTheme(); private: KTitleWindow *q_ptr; QWidget *m_pTitleWidget; QWidget *m_pBaseWidget; KPushButton *m_pAddBtn; TitleButton *m_pColorBtn; TitleButton *m_pMenuBtn; QPushButton *m_pCloseBtn; QHBoxLayout *m_pTitleWidgetLayou; QVBoxLayout *m_pVLayout; QColor m_titleColor; }; KTitleWindow::KTitleWindow(QWidget *parent) : QWidget(parent) , d_ptr(new KTitleWindowPrivate(this)) { Q_D(KTitleWindow); installEventFilter(this); MotifWmHints hints; hints.flags = MWM_HINTS_FUNCTIONS | MWM_HINTS_DECORATIONS; hints.functions = MWM_FUNC_ALL; hints.decorations = MWM_DECOR_BORDER; XAtomHelper::getInstance()->setWindowMotifHint(this->winId(), hints); setMinimumSize(390, 364); } KPushButton *KTitleWindow::addButton() { Q_D(KTitleWindow); return d->m_pAddBtn; } QPushButton *KTitleWindow::colorButton() { Q_D(KTitleWindow); return static_cast(d->m_pColorBtn); } QPushButton *KTitleWindow::menuButton() { Q_D(KTitleWindow); return static_cast(d->m_pMenuBtn); } QWidget *KTitleWindow::baseWidget() { Q_D(KTitleWindow); return d->m_pBaseWidget; } void KTitleWindow::setTitleColor(QColor color) { Q_D(KTitleWindow); d->m_titleColor = color; } void KTitleWindow::resizeEvent(QResizeEvent *event) { Q_D(KTitleWindow); QWidget::resizeEvent(event); d->m_pTitleWidget->setFixedWidth(width()); repaint(); } void KTitleWindow::paintEvent(QPaintEvent *event) { Q_D(KTitleWindow); QPainter painter(this); painter.setRenderHint(QPainter::Antialiasing); painter.setRenderHint(QPainter::TextAntialiasing); painter.setRenderHint(QPainter::SmoothPixmapTransform); painter.setPen(Qt::NoPen); painter.setBrush(ThemeController::getCustomColorFromDT("base-active")); int radius = ThemeController::getRadiusFromDT("kradius-window"); if (radius == -1) radius = 12; painter.drawRoundedRect(this->rect(), radius, radius); d->m_pAddBtn->setIconColor(d->m_titleColor); d->m_pColorBtn->setIcon(ThemeController::drawColoredPixmap(d->m_pColorBtn->icon().pixmap(24, 24), Qt::white)); d->m_pMenuBtn->setIcon(ThemeController::drawColoredPixmap(d->m_pMenuBtn->icon().pixmap(24, 24), Qt::white)); d->m_pCloseBtn->setIcon(ThemeController::drawColoredPixmap(d->m_pCloseBtn->icon().pixmap(24, 24), Qt::white)); QPainterPath path1; QRect rect = this->rect().adjusted(0, 0, 1, 1); if (isActiveWindow()) { if (!d->m_pTitleWidget->isVisible()) { d->m_pTitleWidget->show(); d->m_pVLayout->setContentsMargins(8, 40, 8, 0); } path1.lineTo(rect.topLeft() + QPoint(12, 0)); path1.lineTo(rect.topRight() - QPoint(12, 0)); path1.quadTo(rect.topRight(), rect.topRight() + QPoint(0, 12)); path1.lineTo(rect.topRight() + QPoint(0, 40)); path1.lineTo(rect.topLeft() + QPoint(0, 40)); path1.lineTo(rect.topLeft() + QPoint(0, 12)); path1.quadTo(rect.topLeft(), rect.topLeft() + QPoint(12, 0)); } else { if (d->m_pTitleWidget->isVisible()) { d->m_pTitleWidget->hide(); d->m_pVLayout->setContentsMargins(8, 12, 8, 0); } path1.lineTo(rect.topLeft() + QPoint(12, 0)); path1.lineTo(rect.topRight() - QPoint(12, 0)); path1.quadTo(rect.topRight(), rect.topRight() + QPoint(0, 12)); path1.lineTo(rect.topRight() + QPoint(0, 12)); path1.lineTo(rect.topLeft() + QPoint(0, 12)); path1.lineTo(rect.topLeft() + QPoint(0, 12)); path1.quadTo(rect.topLeft(), rect.topLeft() + QPoint(12, 0)); } painter.setBrush(d->m_titleColor); painter.drawPath(path1); } bool KTitleWindow::eventFilter(QObject *watched, QEvent *event) { Q_D(KTitleWindow); QString platform = QGuiApplication::platformName(); if (platform.startsWith(QLatin1String("wayland"), Qt::CaseInsensitive)) { if ((event->type() == QEvent::PlatformSurface || event->type() == QEvent::Show || event->type() == QEvent::UpdateRequest)) { #ifdef USE_UKUI_PROTOCOL if (UkuiShellManager::getInstance()->ukuishellReady()) UkuiShellManager::getInstance()->removeHeaderBar(this->windowHandle()); else UKUIDecorationManager::getInstance()->removeHeaderBar(this->windowHandle()); #else UKUIDecorationManager::getInstance()->removeHeaderBar(this->windowHandle()); #endif } } return QWidget::eventFilter(watched, event); } KTitleWindowPrivate::KTitleWindowPrivate(KTitleWindow *parent) : q_ptr(parent) { Q_Q(KTitleWindow); m_titleColor = ThemeController::getCustomColorFromDT("highlight-active"); m_pTitleWidget = new QWidget(q); m_pTitleWidget->setAttribute(Qt::WA_TranslucentBackground, true); m_pTitleWidget->setContentsMargins(0, 0, 0, 0); m_pTitleWidget->setFixedHeight(40); m_pTitleWidgetLayou = new QHBoxLayout(m_pTitleWidget); m_pAddBtn = new KPushButton(); m_pAddBtn->setProperty("useIconHighlightEffect", 0x2); m_pAddBtn->setBackgroundColor(Qt::white); m_pAddBtn->setFixedSize(24, 24); m_pAddBtn->setBorderRadius(12); m_pAddBtn->setIcon(QIcon::fromTheme("list-add-symbolic")); m_pColorBtn = new TitleButton(); // m_pColorBtn->setProperty("useIconHighlightEffect", 0x2); m_pColorBtn->setFlat(true); m_pColorBtn->setFixedSize(24, 24); m_pColorBtn->setIcon(QIcon::fromTheme("window-close-symbolic")); m_pMenuBtn = new TitleButton(); // m_pMenuBtn->setProperty("useIconHighlightEffect", 0x2); m_pMenuBtn->setFlat(true); m_pMenuBtn->setFixedSize(24, 24); m_pMenuBtn->setIcon(QIcon::fromTheme("open-menu-symbolic")); m_pCloseBtn = new QPushButton(); m_pCloseBtn->setProperty("isWindowButton", 0x02); m_pCloseBtn->setProperty("useIconHighlightEffect", 0x08); m_pCloseBtn->setFlat(true); m_pCloseBtn->setFixedSize(24, 24); m_pCloseBtn->setIcon(QIcon::fromTheme("window-close-symbolic")); connect(m_pCloseBtn, &QPushButton::clicked, q, [=] { q->close(); }); m_pBaseWidget = new QWidget(); m_pVLayout = new QVBoxLayout(q); m_pTitleWidgetLayou->setSpacing(8); m_pTitleWidgetLayou->setContentsMargins(8, 8, 8, 8); m_pTitleWidgetLayou->addWidget(m_pAddBtn); m_pTitleWidgetLayou->addStretch(); m_pTitleWidgetLayou->addWidget(m_pColorBtn); m_pTitleWidgetLayou->addWidget(m_pMenuBtn); m_pTitleWidgetLayou->addWidget(m_pCloseBtn); m_pVLayout->addLayout(m_pTitleWidgetLayou); m_pVLayout->addWidget(m_pBaseWidget); m_pBaseWidget->setBackgroundRole(QPalette::Base); connect(m_gsetting, &QGSettings::changed, this, [=] { changeTheme(); m_pBaseWidget->setBackgroundRole(QPalette::Base); }); } void KTitleWindowPrivate::changeTheme() { Q_Q(KTitleWindow); initThemeStyle(); } TitleButton::TitleButton(QWidget *widget) { } void TitleButton::paintEvent(QPaintEvent *event) { QStyleOptionButton option; initStyleOption(&option); m_color = Qt::transparent; QPainter painter(this); painter.setRenderHint(QPainter::Antialiasing); painter.setRenderHint(QPainter::TextAntialiasing); painter.setRenderHint(QPainter::SmoothPixmapTransform); if (option.state.testFlag(QStyle::State_MouseOver)) { m_color = ThemeController::getCustomColorFromDT("brighttext-active"); if (option.state.testFlag(QStyle::State_Sunken)) { if (ThemeController::themeMode() == LightTheme) m_color.setAlphaF(0.28); else m_color.setAlphaF(0.15); } else { if (ThemeController::themeMode() == LightTheme) m_color.setAlphaF(0.15); else m_color.setAlphaF(0.28); } } painter.setBrush(m_color); painter.setPen(Qt::NoPen); painter.drawRoundedRect(this->rect(), 6, 6); QRect rect = option.rect.adjusted(0, 0, 1, 1); QRect iconRect(rect.center().x() - option.iconSize.width() / 2, rect.center().y() - option.iconSize.height() / 2, option.iconSize.width(), option.iconSize.height()); painter.drawPixmap(iconRect, option.icon.pixmap(option.iconSize)); } } #include "ktitlewindow.moc" #include "moc_ktitlewindow.cpp" libkysdk-applications/kysdk-qtwidgets/src/kbadge.cpp0000664000175000017500000001057615104543305021657 0ustar fengfeng/* * libkysdk-qtwidgets's Library * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #include "kbadge.h" #include "themeController.h" #include #include #include #include #include namespace kdk { class KBadgePrivate : public QObject, public ThemeController { Q_OBJECT Q_DECLARE_PUBLIC(KBadge) public: KBadgePrivate(KBadge *parent); private: KBadge *q_ptr; QColor m_color; int m_value; int m_fontSize; bool m_isShowValue; bool m_useCustomColor; }; KBadgePrivate::KBadgePrivate(KBadge *parent) : q_ptr(parent) { Q_Q(KBadge); m_value = -1; m_color = ThemeController::getCustomColorFromDT("highlight-active"); m_fontSize = 14; m_isShowValue = true; m_useCustomColor = false; setParent(parent); } KBadge::KBadge(QWidget *parent) : QWidget(parent) , d_ptr(new KBadgePrivate(this)) { Q_D(KBadge); setMinimumSize(40, 30); } void KBadge::setValue(int value) { Q_D(KBadge); d->m_value = value; } void KBadge::setValueVisiable(bool flag) { Q_D(KBadge); d->m_isShowValue = flag; } bool KBadge::isValueVisiable() const { Q_D(const KBadge); return d->m_isShowValue; } int KBadge::value() { Q_D(KBadge); return d->m_value; } QColor KBadge::color() { Q_D(KBadge); return d->m_color; } void KBadge::setColor(const QColor &color) { Q_D(KBadge); d->m_useCustomColor = true; d->m_color = color; } int KBadge::fontSize() { Q_D(KBadge); return d->m_fontSize; } void KBadge::setFontSize(int size) { Q_D(KBadge); if (size < 1 || size > 100) return; d->m_fontSize = size; } void KBadge::paintEvent(QPaintEvent *event) { Q_D(KBadge); QFont font(QApplication::font()); font.setPixelSize(d->m_fontSize); QFontMetrics fm(font); int height = fm.height(); int width; if (d->m_value < 1 || !d->m_isShowValue) { width = 10; height = 10; } else if (d->m_value >= 1 && d->m_value < 1000) { width = fm.horizontalAdvance(QString::number(d->m_value)) + 10; width = width > height ? width : height; } else { width = fm.horizontalAdvance(QString::number(999)) + 10; width = width > height ? width : height; } QPainter painter(this); painter.setRenderHint(QPainter::Antialiasing); painter.setPen(Qt::NoPen); if (d->m_useCustomColor) painter.setBrush(d->m_color); else painter.setBrush(ThemeController::getCustomColorFromDT("highlight-active")); QRect tmpRect(rect().center().x() - width / 2, rect().center().y() - height / 2, width, height); painter.drawRoundedRect(tmpRect, height / 2, height / 2); // 文字颜色固定 painter.setPen(ThemeController::getCustomColorFromDT("light-active")); if (d->m_value >= 1 && d->m_value < 1000 && d->m_isShowValue) { QFont font(QApplication::font()); font.setPixelSize(d->m_fontSize); painter.setFont(font); painter.drawText(tmpRect, Qt::AlignCenter, QString::number(d->m_value)); } if (d->m_value >= 1000 && d->m_value < INTMAX_MAX && d->m_isShowValue) { painter.setBrush(ThemeController::getCustomColorFromDT("light-active")); QPointF pointf(rect().center().x(), rect().center().y()); painter.drawEllipse(pointf, qreal(1.5), qreal(1.5)); QPointF leff(pointf.x() - 10, pointf.y()); QPointF rightf(pointf.x() + 10, pointf.y()); painter.drawEllipse(leff, qreal(1.5), qreal(1.5)); painter.drawEllipse(rightf, qreal(1.5), qreal(1.5)); } } void KBadge::resizeEvent(QResizeEvent *event) { QWidget::resizeEvent(event); repaint(); } } #include "kbadge.moc" #include "moc_kbadge.cpp" libkysdk-applications/kysdk-qtwidgets/src/kinputdialog.h0000664000175000017500000003041315104543305022571 0ustar fengfeng/* * libkysdk-qtwidgets's Library * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #ifndef KINPUTDIALOG_H #define KINPUTDIALOG_H #include #include "kdialog.h" #include namespace kdk { /** @defgroup DialogBoxModule * @{ */ class KInputDialogPrivate; /** * @brief 输入对话框,接口与 QInputDialog 相同。 * @since 1.0.0 */ class GUI_EXPORT KInputDialog : public KDialog { Q_OBJECT Q_ENUMS(InputMode InputDialogOption) QDOC_PROPERTY(InputMode inputMode READ inputMode WRITE setInputMode) QDOC_PROPERTY(QString labelText READ labelText WRITE setLabelText) QDOC_PROPERTY(InputDialogOptions options READ options WRITE setOptions) QDOC_PROPERTY(QString textValue READ textValue WRITE setTextValue NOTIFY textValueChanged) QDOC_PROPERTY(int intValue READ intValue WRITE setIntValue NOTIFY intValueChanged) QDOC_PROPERTY(int doubleValue READ doubleValue WRITE setDoubleValue NOTIFY doubleValueChanged) QDOC_PROPERTY(QLineEdit::EchoMode textEchoMode READ textEchoMode WRITE setTextEchoMode) QDOC_PROPERTY(bool comboBoxEditable READ isComboBoxEditable WRITE setComboBoxEditable) QDOC_PROPERTY(QStringList comboBoxItems READ comboBoxItems WRITE setComboBoxItems) QDOC_PROPERTY(int intMinimum READ intMinimum WRITE setIntMinimum) QDOC_PROPERTY(int intMaximum READ intMaximum WRITE setIntMaximum) QDOC_PROPERTY(int intStep READ intStep WRITE setIntStep) QDOC_PROPERTY(double doubleMinimum READ doubleMinimum WRITE setDoubleMinimum) QDOC_PROPERTY(double doubleMaximum READ doubleMaximum WRITE setDoubleMaximum) QDOC_PROPERTY(int doubleDecimals READ doubleDecimals WRITE setDoubleDecimals) QDOC_PROPERTY(QString okButtonText READ okButtonText WRITE setOkButtonText) QDOC_PROPERTY(QString cancelButtonText READ cancelButtonText WRITE setCancelButtonText) QDOC_PROPERTY(double doubleStep READ doubleStep WRITE setDoubleStep) public: enum InputDialogOption { NoButtons = 0x00000001, UseListViewForComboBoxItems = 0x00000002, UsePlainTextEditForTextInput = 0x00000004 }; Q_DECLARE_FLAGS(InputDialogOptions, InputDialogOption) enum InputMode { TextInput, IntInput, DoubleInput }; KInputDialog(QWidget *parent = nullptr); ~KInputDialog(); /** * @brief 设置输入模式 * @param mode */ void setInputMode(InputMode mode); /** * @brief 返回输入模式 * @return InputMode */ InputMode inputMode() const; /** * @brief 设置提示信息 * @param text */ void setLabelText(const QString &text); /** * @brief 获取提示信息 * @return QString */ QString labelText() const; /** * @brief 设置option类型 * @param option * @param on */ void setOption(InputDialogOption option, bool on = true); /** * @brief 返回是否设置了option类型 * @param option * @return bool */ bool testOption(InputDialogOption option) const; /** * @brief 设置options类型 * @param options */ void setOptions(InputDialogOptions options); /** * @brief 返回options类型 * @return InputDialogOptions */ InputDialogOptions options() const; /** * @brief 设置文本值 * @param text */ void setTextValue(const QString &text); /** * @brief 获取当前文本值 * @return QString */ QString textValue() const; /** * @brief 设置保存文本值的回声模式 QLineEdit::EchoMode * @param mode */ void setTextEchoMode(QLineEdit::EchoMode mode); /** * @brief 返回保存文本值的回声模式 * @return QLineEdit::EchoMode */ QLineEdit::EchoMode textEchoMode() const; /** * @brief 设置输入对话框中使用的组合框是否可编辑 * @param editable */ void setComboBoxEditable(bool editable); /** * @brief 返回输入对话框中使用的组合框是否可编辑 * @return bool */ bool isComboBoxEditable() const; /** * @brief 设置输入对话框组合框中使用的项目 * @param items */ void setComboBoxItems(const QStringList &items); /** * @brief 返回输入对话框组合框中使用的项目 * @return QStringList */ QStringList comboBoxItems() const; /** * @brief 设置int类型值 * @param value */ void setIntValue(int value); /** * @brief 获取int类型值 * @return int */ int intValue() const; /** * @brief 设置int类型最小值 * @param min */ void setIntMinimum(int min); /** * @brief 获取int类型最小值 * @return int */ int intMinimum() const; /** * @brief 设置int类型最大值 * @param max */ void setIntMaximum(int max); /** * @brief 获取int类型最大值 * @return int */ int intMaximum() const; /** * @brief 设置int类型值范围 * @param min * @param max */ void setIntRange(int min, int max); /** * @brief 设置步长 * @param step */ void setIntStep(int step); /** * @brief 获取int类型步长 * @return int */ int intStep() const; /** * @brief 设置double类型值 * @param value */ void setDoubleValue(double value); /** * @brief 获取double类型值 * @return double */ double doubleValue() const; /** * @brief 设置double类型最小值 * @param min */ void setDoubleMinimum(double min); /** * @brief 获取double类型最小值 * @return double */ double doubleMinimum() const; /** * @brief 设置double类型最大值 * @param max */ void setDoubleMaximum(double max); /** * @brief 获取double类型最大值 * @return double */ double doubleMaximum() const; /** * @brief 设置double类型值范围 * @param min * @param max */ void setDoubleRange(double min, double max); /** * @brief 以小数为单位设置双自旋盒的精度 * @param decimals */ void setDoubleDecimals(int decimals); /** * @brief 获取双自旋盒的精度 * @return int */ int doubleDecimals() const; /** * @brief 设置OK按钮的文本 * @param text */ void setOkButtonText(const QString &text); /** * @brief 获取OK按钮的文本 * @return QString */ QString okButtonText() const; /** * @brief 设置cancel按钮的文本 * @param text */ void setCancelButtonText(const QString &text); /** * @brief 获取cancel按钮的文本 * @return */ QString cancelButtonText() const; using QDialog::open; /** * @brief 将对话框显示为窗口模式对话框,并立即返回。 * @param receiver * @param member */ void open(QObject *receiver, const char *member); /** * @brief 获取部件的推荐最小尺寸 * @return QSize */ QSize minimumSizeHint() const override; /** * @brief 获取保存部件的推荐尺寸 * @return */ QSize sizeHint() const override; /** * @brief 设置窗口部件是否可见 * @param visible */ void setVisible(bool visible) override; /** * @brief 获取背景提示文本 * @return * @since 1.2.0 */ QString placeholderText() const; /** * @brief 设置背景提示文本 * @since 1.2.0 */ void setPlaceholderText(const QString &); /** * @brief 静态便利函数,用于从用户处获取单行字符串。 * @param parent * @param label * @param echo * @param text * @param ok * @param flags * @param inputMethodHints * @return */ static QString getText(QWidget *parent, const QString &label, QLineEdit::EchoMode echo = QLineEdit::Normal, const QString &text = QString(), bool *ok = nullptr, Qt::WindowFlags flags = Qt::WindowFlags(), Qt::InputMethodHints inputMethodHints = Qt::ImhNone); /** * @brief 静态便利函数,用于从用户处获取多行字符串。 * @param parent * @param label * @param text * @param ok * @param flags * @param inputMethodHints * @return */ static QString getMultiLineText(QWidget *parent, const QString &label, const QString &text = QString(), bool *ok = nullptr, Qt::WindowFlags flags = Qt::WindowFlags(), Qt::InputMethodHints inputMethodHints = Qt::ImhNone); /** * @brief 静态便利函数,用于让用户从字符串列表中选择一个项目。 * @param parent * @param label * @param items * @param current * @param editable * @param ok * @param flags * @param inputMethodHints * @return */ static QString getItem(QWidget *parent, const QString &label, const QStringList &items, int current = 0, bool editable = true, bool *ok = nullptr, Qt::WindowFlags flags = Qt::WindowFlags(), Qt::InputMethodHints inputMethodHints = Qt::ImhNone); /** * @brief 静态便利函数,用于从用户处获取整数输入值。 * @param parent * @param label * @param value * @param minValue * @param maxValue * @param step * @param ok * @param flags * @return */ static int getInt(QWidget *parent, const QString &label, int value = 0, int minValue = -2147483647, int maxValue = 2147483647, int step = 1, bool *ok = nullptr, Qt::WindowFlags flags = Qt::WindowFlags()); /** * @brief 静态便利函数,用于从用户处获取浮点数。 * @param parent * @param label * @param value * @param minValue * @param maxValue * @param decimals * @param ok * @param flags * @return */ static double getDouble(QWidget *parent, const QString &label, double value = 0, double minValue = -2147483647, double maxValue = 2147483647, int decimals = 1, bool *ok = nullptr, Qt::WindowFlags flags = Qt::WindowFlags()); /** * @brief 设置doubel类型步长 * @param step */ void setDoubleStep(double step); /** * @brief 获取doubel类型步长 * @return double */ double doubleStep() const; Q_SIGNALS: // ### emit signals! void textValueChanged(const QString &text); void textValueSelected(const QString &text); void intValueChanged(int value); void intValueSelected(int value); void doubleValueChanged(double value); void doubleValueSelected(double value); public: void done(int result) override; protected: void changeTheme(); private: KInputDialogPrivate *const d_ptr; Q_DISABLE_COPY(KInputDialog) Q_DECLARE_PRIVATE(KInputDialog) Q_PRIVATE_SLOT(d_ptr, void _q_textChanged(const QString &)) Q_PRIVATE_SLOT(d_ptr, void _q_plainTextEditTextChanged()) Q_PRIVATE_SLOT(d_ptr, void _q_currentRowChanged(const QModelIndex &, const QModelIndex &)) }; Q_DECLARE_OPERATORS_FOR_FLAGS(KInputDialog::InputDialogOptions) } /** * @example testinputdialog/widget.h * @example testinputdialog/widget.cpp * @} */ #endif // KINPUTDIALOG_H libkysdk-applications/kysdk-qtwidgets/src/kminicalendarwidget.h0000664000175000017500000002173115104543305024107 0ustar fengfeng/* * libkysdk-qtwidgets's Library * * Copyright (C) 2024, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhenyu Wang * */ #ifndef KMINICALENDARWIDGET_H #define KMINICALENDARWIDGET_H #include "gui_g.h" #include "klunarcalendarinfo.h" #include "kminicalendaritem.h" #include #include #include #include #include #include namespace kdk { class KMiniCalendarWidgetPrivate; /** * @defgroup KMiniCalendarWidget * @since 2.5.2.0 */ class GUI_EXPORT KMiniCalendarWidget : public QWidget { Q_OBJECT Q_ENUMS(CalendarStyle) Q_ENUMS(WeekNameFormat) Q_ENUMS(SelectType) Q_PROPERTY(CalendarStyle calendarStyle READ getCalendarStyle WRITE setCalendarStyle) Q_PROPERTY(WeekNameFormat weekNameFormat READ getWeekNameFormat WRITE setWeekNameFormat) Q_PROPERTY(QDate date READ getDate WRITE setDate) Q_PROPERTY(QColor weekTextColor READ getWeekTextColor WRITE setWeekTextColor) Q_PROPERTY(QColor weekBgColor READ getWeekBgColor WRITE setWeekBgColor) Q_PROPERTY(bool showLunar READ getShowLunar WRITE setShowLunar) Q_PROPERTY(bool enableBorder READ getEnableBorder WRITE setEnableBorder) Q_PROPERTY(SelectType selectType READ getSelectType WRITE setSelectType) Q_PROPERTY(QColor borderColor READ getBorderColor WRITE setBorderColor) Q_PROPERTY(QColor weekColor READ getWeekColor WRITE setWeekColor) Q_PROPERTY(QColor lunarColor READ getLunarColor WRITE setLunarColor) Q_PROPERTY(QColor currentTextColor READ getCurrentTextColor WRITE setCurrentTextColor) Q_PROPERTY(QColor otherTextColor READ getOtherTextColor WRITE setOtherTextColor) Q_PROPERTY(QColor selectTextColor READ getSelectTextColor WRITE setSelectTextColor) Q_PROPERTY(QColor hoverTextColor READ getHoverTextColor WRITE setHoverTextColor) Q_PROPERTY(QColor currentLunarColor READ getCurrentLunarColor WRITE setCurrentLunarColor) Q_PROPERTY(QColor otherLunarColor READ getOtherLunarColor WRITE setOtherLunarColor) Q_PROPERTY(QColor selectLunarColor READ getSelectLunarColor WRITE setSelectLunarColor) Q_PROPERTY(QColor hoverLunarColor READ getHoverLunarColor WRITE setHoverLunarColor) Q_PROPERTY(QColor currentBgColor READ getCurrentBgColor WRITE setCurrentBgColor) Q_PROPERTY(QColor otherBgColor READ getOtherBgColor WRITE setOtherBgColor) Q_PROPERTY(QColor selectBgColor READ getSelectBgColor WRITE setSelectBgColor) Q_PROPERTY(QColor hoverBgColor READ getHoverBgColor WRITE setHoverBgColor) public: enum CalendarStyle { CalendarStyle_Red = 0 }; enum WeekNameFormat { WeekNameFormat_Short = 0, // 短名称模式 WeekNameFormat_Normal = 1, // 普通名称模式 WeekNameFormat_Long = 2, // 长名称模式 WeekNameFormat_En = 3 // 英文模式 }; enum SelectType { SelectType_Rect = 0, // 矩形背景 SelectType_Circle = 1, // 圆形背景 SelectType_Triangle = 2, // 带三角标 SelectType_Image = 3 // 图片背景 }; explicit KMiniCalendarWidget(QWidget *parent = 0); ~KMiniCalendarWidget(); public: /** * @brief 获取整体样式 * @return */ CalendarStyle getCalendarStyle() const; /** * @brief 获取星期名称格式 * @return */ WeekNameFormat getWeekNameFormat() const; /** * @brief 获取当前日期 * @return */ QDate getDate() const; /** * @brief 获取星期文本颜色 * @return */ QColor getWeekTextColor() const; /** * @brief 获取周末名称背景色 * @return */ QColor getWeekBgColor() const; /** * @brief 获取农历显示 * @return */ bool getShowLunar() const; /** * @brief 获取启用边框 * @return */ bool getEnableBorder() const; /** * @brief 获取选择类型 * @return */ SelectType getSelectType() const; /** * @brief 获取边框颜色 * @return */ QColor getBorderColor() const; /** * @brief 获取周末颜色 * @return */ QColor getWeekColor() const; /** * @brief 获取农历节日颜色 * @return */ QColor getLunarColor() const; /** * @brief 获取当前月文本颜色 * @return */ QColor getCurrentTextColor() const; /** * @brief 获取其他月文本颜色 * @return */ QColor getOtherTextColor() const; /** * @brief 获取选中日期文本颜色 * @return */ QColor getSelectTextColor() const; /** * @brief 获取悬浮日期文本颜色 * @return */ QColor getHoverTextColor() const; /** * @brief 获取当前月农历文字颜色 * @return */ QColor getCurrentLunarColor() const; /** * @brief 获取其他月农历文本颜色 * @return */ QColor getOtherLunarColor() const; /** * @brief 获取选中日期农历颜文本色 * @return */ QColor getSelectLunarColor() const; /** * @brief 获取悬浮日期农历文本颜色 * @return */ QColor getHoverLunarColor() const; /** * @brief 获取当前月背景色 * @return */ QColor getCurrentBgColor() const; /** * @brief 获取其他月背景色 * @return */ QColor getOtherBgColor() const; /** * @brief 获取选择日期背景色 * @return */ QColor getSelectBgColor() const; /** * @brief 获取悬浮日期背景色 * @return */ QColor getHoverBgColor() const; QSize sizeHint() const; QSize minimumSizeHint() const; public Q_SLOTS: // 上一月,下一月 void showPreviousMonth(); void showNextMonth(); // 转到今天 void showToday(); // 设置整体样式 void setCalendarStyle(const CalendarStyle &calendarStyle); // 设置星期名称格式 void setWeekNameFormat(const WeekNameFormat &weekNameFormat); // 设置日期 void setDate(const QDate &date); // 设置顶部星期名称文字颜色+背景色 void setWeekTextColor(const QColor &weekTextColor); void setWeekBgColor(const QColor &weekBgColor); // 设置是否显示农历信息 void setShowLunar(bool showLunar); // 是否显示边框 void setEnableBorder(bool bVisible); // 设置选中背景样式 void setSelectType(const SelectType &selectType); // 设置边框颜色 void setBorderColor(const QColor &borderColor); // 设置周末颜色 void setWeekColor(const QColor &weekColor); // 设置农历节日颜色 void setLunarColor(const QColor &lunarColor); // 设置当前月文字颜色 void setCurrentTextColor(const QColor ¤tTextColor); // 设置其他月文字颜色 void setOtherTextColor(const QColor &otherTextColor); // 设置选中日期文字颜色 void setSelectTextColor(const QColor &selectTextColor); // 设置悬停日期文字颜色 void setHoverTextColor(const QColor &hoverTextColor); // 设置当前月农历文字颜色 void setCurrentLunarColor(const QColor ¤tLunarColor); // 设置其他月农历文字颜色 void setOtherLunarColor(const QColor &otherLunarColor); // 设置选中日期农历文字颜色 void setSelectLunarColor(const QColor &selectLunarColor); // 设置悬停日期农历文字颜色 void setHoverLunarColor(const QColor &hoverLunarColor); // 设置当前月背景颜色 void setCurrentBgColor(const QColor ¤tBgColor); // 设置其他月背景颜色 void setOtherBgColor(const QColor &otherBgColor); // 设置选中日期背景颜色 void setSelectBgColor(const QColor &selectBgColor); // 设置悬停日期背景颜色 void setHoverBgColor(const QColor &hoverBgColor); protected: void wheelEvent(QWheelEvent *event) override; void paintEvent(QPaintEvent *event) override; signals: void clicked(const QDate &date); void selectionChanged(); private slots: void initWidget(); void initStyle(); void initDate(); void slotClicked(const QDate &date, const KMiniCalendarItem::DayType &dayType); void dayChanged(const QDate &date); void dateChanged(int year, int month, int day); private: Q_DECLARE_PRIVATE(KMiniCalendarWidget) KMiniCalendarWidgetPrivate *const d_ptr; }; } #endif // KMINICALENDARWIDGET_H libkysdk-applications/kysdk-qtwidgets/src/kradiobuttonframe.cpp0000664000175000017500000000570715104543305024162 0ustar fengfeng/* * * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Sisheng He * */ #include "kradiobuttonframe.h" #include namespace kdk { class KRadioButtonFramePrivate : public QObject { Q_OBJECT Q_DECLARE_PUBLIC(KRadioButtonFrame) public: KRadioButtonFramePrivate(KRadioButtonFrame *parent); private: KRadioButtonFrame *q_ptr; QButtonGroup *m_pButtonGroup; QHBoxLayout *m_pRadioLayout; KLabel *m_pSettingName; QHBoxLayout *m_pMainLayout; }; KRadioButtonFramePrivate::KRadioButtonFramePrivate(KRadioButtonFrame *parent) : q_ptr(parent) { Q_Q(KRadioButtonFrame); m_pMainLayout = new QHBoxLayout(q); m_pMainLayout->setContentsMargins(16, 0, 16, 0); m_pMainLayout->setSpacing(16); m_pSettingName = new KLabel(q); m_pSettingName->setFixedWidth(SETTING_LABEL_WIDTH); m_pButtonGroup = new QButtonGroup(q); m_pRadioLayout = new QHBoxLayout(); m_pRadioLayout->setContentsMargins(0, 0, 0, 0); m_pRadioLayout->setSpacing(80); m_pMainLayout->addWidget(m_pSettingName); m_pMainLayout->addLayout(m_pRadioLayout); m_pMainLayout->addStretch(); q->setLayout(m_pMainLayout); } KRadioButtonFrame::KRadioButtonFrame(const QString title, QWidget *parent, BorderRadiusStyle style) : KBaseFrame(parent, style, true) , d_ptr(new KRadioButtonFramePrivate(this)) { Q_D(KRadioButtonFrame); setObjectName("KRadioButtonFrame"); d->m_pSettingName->setText(title); } KRadioButtonFrame::~KRadioButtonFrame() { } void KRadioButtonFrame::addButton(QRadioButton *button, int id, bool addStretch) { Q_D(KRadioButtonFrame); d->m_pButtonGroup->addButton(button, id); d->m_pRadioLayout->addWidget(button, 0, Qt::AlignLeft | Qt::AlignVCenter); if (addStretch) { d->m_pRadioLayout->addStretch(); } } QHBoxLayout *KRadioButtonFrame::radioHLayout() { Q_D(KRadioButtonFrame); return d->m_pRadioLayout; } QButtonGroup *KRadioButtonFrame::buttonGroup() { Q_D(KRadioButtonFrame); return d->m_pButtonGroup; } QHBoxLayout *KRadioButtonFrame::mainHLayout() { Q_D(KRadioButtonFrame); return d->m_pMainLayout; } KLabel *KRadioButtonFrame::titleLabel() { Q_D(KRadioButtonFrame); return d->m_pSettingName; } } #include "kradiobuttonframe.moc" #include "moc_kradiobuttonframe.cpp" libkysdk-applications/kysdk-qtwidgets/src/ktableheaderview.h0000664000175000017500000000400015104543305023376 0ustar fengfeng/* * libkysdk-qtwidgets's Library * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhenyu Wang * */ #ifndef KTABLEHEADVIEW_H #define KTABLEHEADVIEW_H #include #include #include #include namespace kdk { /** * @brief 继承自QHeaderView,设置view视图标题 * @since 2.5.2.0 */ class KTableHeaderViewPrivate; class KTableHeaderView : public QHeaderView { Q_OBJECT public: /** * @brief KTableHeaderView 构造函数 * @param orientation 方向 * @param parent 父类对象 */ KTableHeaderView(Qt::Orientation orientation, QWidget *parent = nullptr); /** * @brief 设置水平标题 * @param list */ void setTitle(QStringList list); /** * @brief 设置menu * @param menu * @param column */ void setMenu(QMenu *menu, int column); protected: void paintSection(QPainter *painter, const QRect &rect, int logicalIndex) const; void mousePressEvent(QMouseEvent *e); void mouseReleaseEvent(QMouseEvent *e); bool event(QEvent *e); Q_SIGNALS: void checkStateChange(int state); void clickedHeader(int column); public slots: void checkStateChangeSlot(int iState); private: Q_DECLARE_PRIVATE(KTableHeaderView) KTableHeaderViewPrivate *const d_ptr; }; } #endif // KTABLEHEADVIEW_H libkysdk-applications/kysdk-qtwidgets/src/kminicalendarwidget.cpp0000664000175000017500000006733515104543305024454 0ustar fengfeng/* * libkysdk-qtwidgets's Library * * Copyright (C) 2024, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhenyu Wang * */ #pragma execution_character_set("utf-8") #include "kminicalendarwidget.h" #include "kborderlessbutton.h" #include "kpushbutton.h" #include "qdatetime.h" #include "qfontdatabase.h" #include "qlayout.h" #include "themeController.h" #include #include #include //#include "kshadowhelper.h" //2503 namespace kdk { class KMiniCalendarWidgetPrivate : public QObject, public ThemeController { Q_DECLARE_PUBLIC(KMiniCalendarWidget) Q_OBJECT public: KMiniCalendarWidgetPrivate(KMiniCalendarWidget *parent); protected: void changeTheme(); private: KMiniCalendarWidget *q_ptr; KMiniCalendarWidget::CalendarStyle calendarStyle; // 整体样式 KMiniCalendarWidget::WeekNameFormat weekNameFormat; // 星期名称格式 KMiniCalendarWidget::SelectType selectType; // 选中模式 bool btnClick; // 按钮单击,避开下拉选择重复触发 QLabel *labelYearMonth; // 年月 QList labWeeks; // 顶部星期名称 QList dayItems; // 日期元素 QDate date; // 当前日期 QColor weekTextColor; // 星期名称文字颜色 QColor weekBgColor; // 星期名称背景色 bool showLunar; // 显示农历 bool enableBorder; // 显示边框 QColor borderColor; // 边框颜色 QColor weekColor; // 周末颜色 QColor lunarColor; // 农历节日颜色 QColor currentTextColor; // 当前月文字颜色 QColor otherTextColor; // 其他月文字颜色 QColor selectTextColor; // 选中日期文字颜色 QColor hoverTextColor; // 悬停日期文字颜色 QColor currentLunarColor; // 当前月农历文字颜色 QColor otherLunarColor; // 其他月农历文字颜色 QColor selectLunarColor; // 选中日期农历文字颜色 QColor hoverLunarColor; // 悬停日期农历文字颜色 QColor currentBgColor; // 当前月背景颜色 QColor otherBgColor; // 其他月背景颜色 QColor selectBgColor; // 选中日期背景颜色 QColor hoverBgColor; // 悬停日期背景颜色 }; KMiniCalendarWidgetPrivate::KMiniCalendarWidgetPrivate(KMiniCalendarWidget *parent) : q_ptr(parent) { Q_Q(KMiniCalendarWidget); btnClick = false; calendarStyle = KMiniCalendarWidget::CalendarStyle_Red; weekNameFormat = KMiniCalendarWidget::WeekNameFormat_Short; date = QDate::currentDate(); weekBgColor = QColor(255, 255, 255); weekBgColor = QColor(255, 255, 255); showLunar = false; enableBorder = false; selectType = KMiniCalendarWidget::SelectType_Circle; borderColor = QColor(180, 180, 180); weekColor = QColor(0, 0, 0); lunarColor = QColor(55, 156, 238); currentTextColor = QColor(0, 0, 0); otherTextColor = QColor(200, 200, 200); selectTextColor = QColor(255, 255, 255); hoverTextColor = QColor(250, 250, 250); currentLunarColor = QColor(179, 179, 179); otherLunarColor = QColor(179, 179, 179); selectLunarColor = QColor(179, 179, 179); hoverLunarColor = QColor(179, 179, 179); currentBgColor = QColor(255, 255, 255); otherBgColor = QColor(255, 255, 255); selectBgColor = ThemeController::getCustomColorFromDT("kbrand-normal"); hoverBgColor = QColor(180, 180, 180); } void KMiniCalendarWidgetPrivate::changeTheme() { Q_Q(KMiniCalendarWidget); selectBgColor = ThemeController::getCustomColorFromDT("kbrand-normal"); q->initStyle(); q->update(); } KMiniCalendarWidget::KMiniCalendarWidget(QWidget *parent) : QWidget(parent) , d_ptr(new KMiniCalendarWidgetPrivate(this)) { Q_D(KMiniCalendarWidget); setWindowFlags(Qt::Popup | Qt::FramelessWindowHint); setAttribute(Qt::WA_TranslucentBackground); // effects::KShadowHelper::self()->setWidget(this,15); QGraphicsDropShadowEffect *m_pShadow_effect = new QGraphicsDropShadowEffect(this); m_pShadow_effect->setOffset(0, 0); m_pShadow_effect->setColor(ThemeController::getCustomColorFromDT("text-disable")); m_pShadow_effect->setBlurRadius(15); setContentsMargins(10,10,10,10); this->setGraphicsEffect(m_pShadow_effect); connect(d->m_gsetting, &QGSettings::changed, this, [=](){ d->changeTheme(); }); d->changeTheme(); initWidget(); initStyle(); initDate(); } KMiniCalendarWidget::~KMiniCalendarWidget() { } void KMiniCalendarWidget::initWidget() { Q_D(KMiniCalendarWidget); this->setObjectName("miniCalendarWidget"); // 顶部widget QWidget *widgetTop = new QWidget(); widgetTop->setObjectName("widgetTop"); widgetTop->setMinimumHeight(36); // 上个月按钮 kdk::KBorderlessButton *btnPrevMonth = new kdk::KBorderlessButton(); btnPrevMonth->setObjectName("btnPrevMonth"); btnPrevMonth->setFixedSize(45, 36); btnPrevMonth->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Expanding); btnPrevMonth->setIcon(QIcon::fromTheme("ukui-start-symbolic")); // 下个月按钮 kdk::KBorderlessButton *btnNextMonth = new kdk::KBorderlessButton(); btnNextMonth->setObjectName("btnNextMonth"); btnNextMonth->setFixedSize(45, 36); btnNextMonth->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Expanding); btnNextMonth->setIcon(QIcon::fromTheme("ukui-end-symbolic")); d->labelYearMonth = new QLabel(); d->labelYearMonth->setFixedSize(96, 36); d->labelYearMonth->setAlignment(Qt::AlignCenter); QFont labelFont; labelFont.setFamily("Microsoft Yahei"); labelFont.setPixelSize(14); d->labelYearMonth->setFont(labelFont); // 顶部横向布局 QHBoxLayout *layoutTop = new QHBoxLayout(widgetTop); layoutTop->setContentsMargins(0, 0, 0, 0); layoutTop->addWidget(btnPrevMonth); layoutTop->addWidget(d->labelYearMonth); layoutTop->addWidget(btnNextMonth); // 星期widget QWidget *widgetWeek = new QWidget(); widgetWeek->setObjectName("widgetWeek"); widgetWeek->setMinimumHeight(30); // 星期布局 QHBoxLayout *layoutWeek = new QHBoxLayout(widgetWeek); layoutWeek->setContentsMargins(0, 0, 0, 0); layoutWeek->setSpacing(0); for (int i = 0; i < 7; i++) { QLabel *lab = new QLabel; lab->setAlignment(Qt::AlignCenter); layoutWeek->addWidget(lab); d->labWeeks.append(lab); } setWeekNameFormat(WeekNameFormat_Long); // 日期标签widget QWidget *widgetBody = new QWidget(); widgetBody->setObjectName("widgetBody"); // 日期标签布局 QGridLayout *layoutBody = new QGridLayout(widgetBody); layoutBody->setContentsMargins(0, 0, 0, 0); layoutBody->setHorizontalSpacing(0); layoutBody->setVerticalSpacing(0); // 逐个添加日标签 for (int i = 0; i < 42; i++) { KMiniCalendarItem *lab = new KMiniCalendarItem(); lab->setObjectName("KMiniCalendarItem"); connect(lab, SIGNAL(clicked(QDate, KMiniCalendarItem::DayType)), this, SLOT(slotClicked(QDate, KMiniCalendarItem::DayType))); layoutBody->addWidget(lab, i / 7, i % 7); d->dayItems.append(lab); } // 主布局 QVBoxLayout *verLayoutCalendar = new QVBoxLayout(this); verLayoutCalendar->setContentsMargins(15, 10, 15, 15); verLayoutCalendar->setSpacing(0); verLayoutCalendar->addWidget(widgetTop); verLayoutCalendar->addWidget(widgetWeek); verLayoutCalendar->addWidget(widgetBody, 1); // 绑定按钮和下拉框信号 connect(btnPrevMonth, SIGNAL(clicked(bool)), this, SLOT(showPreviousMonth())); connect(btnNextMonth, SIGNAL(clicked(bool)), this, SLOT(showNextMonth())); } void KMiniCalendarWidget::initStyle() { Q_D(KMiniCalendarWidget); // 设置样式 QStringList qss; // 星期名称样式 qss.append(QString("QLabel{background:%1;color:%2;}").arg(d->weekBgColor.name()).arg(d->weekTextColor.name())); // 边框 qss.append("QWidget#widgetBody{border:0px;}"); // 顶部下拉框 qss.append(QString("QToolButton{padding:0px;background:none;border:none;border-radius:5px;}")); // qss.append(QString("QToolButton:hover{background:rgb(180,180,180);color:#FFFFFF;}")); // 自定义日控件颜色 QString strSelectType; if (d->selectType == SelectType_Rect) { strSelectType = "SelectType_Rect"; } else if (d->selectType == SelectType_Circle) { strSelectType = "SelectType_Circle"; } else if (d->selectType == SelectType_Triangle) { strSelectType = "SelectType_Triangle"; } qss.append(QString("KMiniCalendarItem{qproperty-showLunar:%1;}").arg(d->showLunar)); qss.append(QString("KMiniCalendarItem{qproperty-selectType:%1;}").arg(strSelectType)); qss.append(QString("KMiniCalendarItem{qproperty-borderColor:%1;}").arg(d->borderColor.name())); qss.append(QString("KMiniCalendarItem{qproperty-weekColor:%1;}").arg(d->weekColor.name())); qss.append(QString("KMiniCalendarItem{qproperty-lunarColor:%1;}").arg(d->lunarColor.name())); qss.append(QString("KMiniCalendarItem{qproperty-currentTextColor:%1;}").arg(d->currentTextColor.name())); qss.append(QString("KMiniCalendarItem{qproperty-otherTextColor:%1;}").arg(d->otherTextColor.name())); qss.append(QString("KMiniCalendarItem{qproperty-selectTextColor:%1;}").arg(d->selectTextColor.name())); qss.append(QString("KMiniCalendarItem{qproperty-hoverTextColor:%1;}").arg(d->hoverTextColor.name())); qss.append(QString("KMiniCalendarItem{qproperty-currentLunarColor:%1;}").arg(d->currentLunarColor.name())); qss.append(QString("KMiniCalendarItem{qproperty-otherLunarColor:%1;}").arg(d->otherLunarColor.name())); qss.append(QString("KMiniCalendarItem{qproperty-selectLunarColor:%1;}").arg(d->selectLunarColor.name())); qss.append(QString("KMiniCalendarItem{qproperty-hoverLunarColor:%1;}").arg(d->hoverLunarColor.name())); qss.append(QString("KMiniCalendarItem{qproperty-currentBgColor:%1;}").arg(d->currentBgColor.name())); qss.append(QString("KMiniCalendarItem{qproperty-otherBgColor:%1;}").arg(d->otherBgColor.name())); qss.append(QString("KMiniCalendarItem{qproperty-selectBgColor:%1;}").arg(d->selectBgColor.name())); qss.append(QString("KMiniCalendarItem{qproperty-hoverBgColor:%1;}").arg(d->hoverBgColor.name())); for (KMiniCalendarItem *dayItem : d->dayItems) { dayItem->setShowLunar(d->showLunar); dayItem->setSelectType(static_cast(d->selectType)); dayItem->setBorderColor(d->borderColor); dayItem->setWeekColor(d->weekColor); dayItem->setLunarColor(d->lunarColor); dayItem->setCurrentTextColor(d->currentTextColor); dayItem->setOtherTextColor(d->otherTextColor); dayItem->setSelectTextColor(d->selectTextColor); dayItem->setHoverTextColor(d->hoverTextColor); dayItem->setCurrentLunarColor(d->currentLunarColor); dayItem->setOtherLunarColor(d->otherLunarColor); dayItem->setSelectLunarColor(d->selectLunarColor); dayItem->setHoverLunarColor(d->hoverLunarColor); dayItem->setCurrentBgColor(d->currentBgColor); dayItem->setOtherBgColor(d->otherBgColor); dayItem->setSelectBgColor(d->selectBgColor); dayItem->setHoverBgColor(d->hoverBgColor); } this->setStyleSheet(qss.join("")); } // 初始化日期面板 void KMiniCalendarWidget::initDate() { Q_D(KMiniCalendarWidget); int year = d->date.year(); int month = d->date.month(); // 设置为今天,设置变量防止重复触发 d->btnClick = true; d->labelYearMonth->setText(QString("%1年%2月").arg(year).arg(month)); d->btnClick = false; // 首先判断当前月的第一天是星期几 int week = KLunarCalendarInfo::Instance()->getFirstDayOfWeek(year, month, false); // 当前月天数 int countDay = KLunarCalendarInfo::Instance()->getMonthDays(year, month); // 上月天数 int countDayPre = KLunarCalendarInfo::Instance()->getMonthDays(1 == month ? year - 1 : year, 1 == month ? 12 : month - 1); // 如果上月天数上月刚好一周则另外处理 int startPre, endPre, startNext, endNext, index, tempYear, tempMonth, tempDay; if (0 == week) { startPre = 0; endPre = 7; startNext = 0; endNext = 42 - (countDay + 7); } else { startPre = 0; endPre = week; startNext = week + countDay; endNext = 42; } // 纠正1月份前面部分偏差,1月份前面部分是上一年12月份 tempYear = year; tempMonth = month - 1; if (tempMonth < 1) { tempYear--; tempMonth = 12; } // 显示上月天数 for (int i = startPre; i < endPre; i++) { index = i; tempDay = countDayPre - endPre + i + 1; QDate date(tempYear, tempMonth, tempDay); QString lunar = KLunarCalendarInfo::Instance()->getLunarDay(tempYear, tempMonth, tempDay); d->dayItems.at(index)->setDate(date, lunar, KMiniCalendarItem::DayType_MonthPre); } // 纠正12月份后面部分偏差,12月份后面部分是下一年1月份 tempYear = year; tempMonth = month + 1; if (tempMonth > 12) { tempYear++; tempMonth = 1; } // 显示下月天数 for (int i = startNext; i < endNext; i++) { index = 42 - endNext + i; tempDay = i - startNext + 1; QDate date(tempYear, tempMonth, tempDay); QString lunar = KLunarCalendarInfo::Instance()->getLunarDay(tempYear, tempMonth, tempDay); d->dayItems.at(index)->setDate(date, lunar, KMiniCalendarItem::DayType_MonthNext); } // 重新置为当前年月 tempYear = year; tempMonth = month; // 显示当前月 for (int i = week; i < (countDay + week); i++) { index = (0 == week ? (i + 7) : i); tempDay = i - week + 1; QDate date(tempYear, tempMonth, tempDay); QString lunar = KLunarCalendarInfo::Instance()->getLunarDay(tempYear, tempMonth, tempDay); if (0 == (i % 7) || 6 == (i % 7)) { d->dayItems.at(index)->setDate(date, lunar, KMiniCalendarItem::DayType_WeekEnd); } else { d->dayItems.at(index)->setDate(date, lunar, KMiniCalendarItem::DayType_MonthCurrent); } } dayChanged(d->date); } void KMiniCalendarWidget::slotClicked(const QDate &date, const KMiniCalendarItem::DayType &dayType) { Q_D(KMiniCalendarWidget); d->date = date; if (KMiniCalendarItem::DayType_MonthPre == dayType) { d->date = date.addMonths(1); showPreviousMonth(); } else if (KMiniCalendarItem::DayType_MonthNext == dayType) { d->date = date.addMonths(-1); showNextMonth(); } else { dayChanged(d->date); } this->close(); } void KMiniCalendarWidget::dayChanged(const QDate &date) { Q_D(KMiniCalendarWidget); // 计算星期几,当前天对应标签索引=日期+星期几-1 int year = date.year(); int month = date.month(); int day = date.day(); int week = KLunarCalendarInfo::Instance()->getFirstDayOfWeek(year, month, false); // qDebug() << QString("%1-%2-%3").arg(year).arg(month).arg(day); // 选中当前日期,其他日期恢复,这里还有优化空间,比方说类似单选框机制 for (int i = 0; i < 42; i++) { // 当月第一天是星期天要另外计算 int index = day + week - 1; if (week == 0) { index = day + 6; } d->dayItems.at(i)->setSelect(i == index); } // 发送日期单击信号 emit clicked(date); // 发送日期更新信号 emit selectionChanged(); } void KMiniCalendarWidget::dateChanged(int year, int month, int day) { Q_D(KMiniCalendarWidget); // 如果原有天大于28则设置为1,防止出错 d->date.setDate(year, month, day > 28 ? 1 : day); initDate(); } KMiniCalendarWidget::CalendarStyle KMiniCalendarWidget::getCalendarStyle() const { Q_D(const KMiniCalendarWidget); return d->calendarStyle; } KMiniCalendarWidget::WeekNameFormat KMiniCalendarWidget::getWeekNameFormat() const { Q_D(const KMiniCalendarWidget); return d->weekNameFormat; } QDate KMiniCalendarWidget::getDate() const { Q_D(const KMiniCalendarWidget); return d->date; } QColor KMiniCalendarWidget::getWeekTextColor() const { Q_D(const KMiniCalendarWidget); return d->weekTextColor; } QColor KMiniCalendarWidget::getWeekBgColor() const { Q_D(const KMiniCalendarWidget); return d->weekBgColor; } bool KMiniCalendarWidget::getShowLunar() const { Q_D(const KMiniCalendarWidget); return d->showLunar; } bool KMiniCalendarWidget::getEnableBorder() const { Q_D(const KMiniCalendarWidget); return d->enableBorder; } KMiniCalendarWidget::SelectType KMiniCalendarWidget::getSelectType() const { Q_D(const KMiniCalendarWidget); return d->selectType; } QColor KMiniCalendarWidget::getBorderColor() const { Q_D(const KMiniCalendarWidget); return d->borderColor; } QColor KMiniCalendarWidget::getWeekColor() const { Q_D(const KMiniCalendarWidget); return d->weekColor; } QColor KMiniCalendarWidget::getLunarColor() const { Q_D(const KMiniCalendarWidget); return d->lunarColor; } QColor KMiniCalendarWidget::getCurrentTextColor() const { Q_D(const KMiniCalendarWidget); return d->currentTextColor; } QColor KMiniCalendarWidget::getOtherTextColor() const { Q_D(const KMiniCalendarWidget); return d->otherTextColor; } QColor KMiniCalendarWidget::getSelectTextColor() const { Q_D(const KMiniCalendarWidget); return d->selectTextColor; } QColor KMiniCalendarWidget::getHoverTextColor() const { Q_D(const KMiniCalendarWidget); return d->hoverTextColor; } QColor KMiniCalendarWidget::getCurrentLunarColor() const { Q_D(const KMiniCalendarWidget); return d->currentLunarColor; } QColor KMiniCalendarWidget::getOtherLunarColor() const { Q_D(const KMiniCalendarWidget); return d->otherLunarColor; } QColor KMiniCalendarWidget::getSelectLunarColor() const { Q_D(const KMiniCalendarWidget); return d->selectLunarColor; } QColor KMiniCalendarWidget::getHoverLunarColor() const { Q_D(const KMiniCalendarWidget); return d->hoverLunarColor; } QColor KMiniCalendarWidget::getCurrentBgColor() const { Q_D(const KMiniCalendarWidget); return d->currentBgColor; } QColor KMiniCalendarWidget::getOtherBgColor() const { Q_D(const KMiniCalendarWidget); return d->otherBgColor; } QColor KMiniCalendarWidget::getSelectBgColor() const { Q_D(const KMiniCalendarWidget); return d->selectBgColor; } QColor KMiniCalendarWidget::getHoverBgColor() const { Q_D(const KMiniCalendarWidget); return d->hoverBgColor; } QSize KMiniCalendarWidget::sizeHint() const { Q_D(const KMiniCalendarWidget); return QSize(600, 500); } QSize KMiniCalendarWidget::minimumSizeHint() const { Q_D(const KMiniCalendarWidget); return QSize(200, 150); } // 显示上月日期 void KMiniCalendarWidget::showPreviousMonth() { Q_D(KMiniCalendarWidget); int year = d->date.year(); int month = d->date.month(); int day = d->date.day(); if (year <= 1901 && month == 1) { return; } month--; if (month < 1) { month = 12; year--; } dateChanged(year, month, day); } // 显示下月日期 void KMiniCalendarWidget::showNextMonth() { Q_D(KMiniCalendarWidget); int year = d->date.year(); int month = d->date.month(); int day = d->date.day(); if (year >= 2099 && month == 12) { return; } month++; if (month > 12) { month = 1; year++; } dateChanged(year, month, day); } // 转到今天 void KMiniCalendarWidget::showToday() { Q_D(KMiniCalendarWidget); d->date = QDate::currentDate(); initDate(); dayChanged(d->date); } void KMiniCalendarWidget::setCalendarStyle(const KMiniCalendarWidget::CalendarStyle &calendarStyle) { Q_D(KMiniCalendarWidget); if (d->calendarStyle != calendarStyle) { d->calendarStyle = calendarStyle; } } void KMiniCalendarWidget::setWeekNameFormat(const KMiniCalendarWidget::WeekNameFormat &weekNameFormat) { Q_D(KMiniCalendarWidget); if (d->weekNameFormat != weekNameFormat) { d->weekNameFormat = weekNameFormat; QStringList listWeek; if (weekNameFormat == WeekNameFormat_Short) { listWeek << "一" << "二" << "三" << "四" << "五" << "六" << "日"; } else if (weekNameFormat == WeekNameFormat_Normal) { listWeek << "周一" << "周二" << "周三" << "周四" << "周五" << "周六" << "周日"; } else if (weekNameFormat == WeekNameFormat_Long) { listWeek << "星期一" << "星期二" << "星期三" << "星期四" << "星期五" << "星期六" << "星期天"; } else if (weekNameFormat == WeekNameFormat_En) { listWeek << "Mon" << "Tue" << "Wed" << "Thu" << "Fri" << "Sat" << "Sun"; } // 逐个添加日期文字 for (int i = 0; i < 7; i++) { d->labWeeks.at(i)->setText(listWeek.at(i)); } } } void KMiniCalendarWidget::setDate(const QDate &date) { Q_D(KMiniCalendarWidget); if (d->date != date) { d->date = date; initDate(); } } void KMiniCalendarWidget::setWeekTextColor(const QColor &weekTextColor) { Q_D(KMiniCalendarWidget); if (d->weekTextColor != weekTextColor) { d->weekTextColor = weekTextColor; initStyle(); } } void KMiniCalendarWidget::setWeekBgColor(const QColor &weekBgColor) { Q_D(KMiniCalendarWidget); if (d->weekBgColor != weekBgColor) { d->weekBgColor = weekBgColor; initStyle(); } } void KMiniCalendarWidget::setShowLunar(bool showLunar) { Q_D(KMiniCalendarWidget); if (d->showLunar != showLunar) { d->showLunar = showLunar; initStyle(); } } void KMiniCalendarWidget::setEnableBorder(bool bVisible) { Q_D(KMiniCalendarWidget); if (d->enableBorder != bVisible) { d->enableBorder = bVisible; update(); } } void KMiniCalendarWidget::setSelectType(const KMiniCalendarWidget::SelectType &selectType) { Q_D(KMiniCalendarWidget); if (d->selectType != selectType) { d->selectType = selectType; initStyle(); } } void KMiniCalendarWidget::setBorderColor(const QColor &borderColor) { Q_D(KMiniCalendarWidget); if (d->borderColor != borderColor) { d->borderColor = borderColor; initStyle(); } } void KMiniCalendarWidget::setWeekColor(const QColor &weekColor) { Q_D(KMiniCalendarWidget); if (d->weekColor != weekColor) { d->weekColor = weekColor; initStyle(); } } void KMiniCalendarWidget::setLunarColor(const QColor &lunarColor) { Q_D(KMiniCalendarWidget); if (d->lunarColor != lunarColor) { d->lunarColor = lunarColor; initStyle(); } } void KMiniCalendarWidget::setCurrentTextColor(const QColor ¤tTextColor) { Q_D(KMiniCalendarWidget); if (d->currentTextColor != currentTextColor) { d->currentTextColor = currentTextColor; initStyle(); } } void KMiniCalendarWidget::setOtherTextColor(const QColor &otherTextColor) { Q_D(KMiniCalendarWidget); if (d->otherTextColor != otherTextColor) { d->otherTextColor = otherTextColor; initStyle(); } } void KMiniCalendarWidget::setSelectTextColor(const QColor &selectTextColor) { Q_D(KMiniCalendarWidget); if (d->selectTextColor != selectTextColor) { d->selectTextColor = selectTextColor; initStyle(); } } void KMiniCalendarWidget::setHoverTextColor(const QColor &hoverTextColor) { Q_D(KMiniCalendarWidget); if (d->hoverTextColor != hoverTextColor) { d->hoverTextColor = hoverTextColor; initStyle(); } } void KMiniCalendarWidget::setCurrentLunarColor(const QColor ¤tLunarColor) { Q_D(KMiniCalendarWidget); if (d->currentLunarColor != currentLunarColor) { d->currentLunarColor = currentLunarColor; initStyle(); } } void KMiniCalendarWidget::setOtherLunarColor(const QColor &otherLunarColor) { Q_D(KMiniCalendarWidget); if (d->otherLunarColor != otherLunarColor) { d->otherLunarColor = otherLunarColor; initStyle(); } } void KMiniCalendarWidget::setSelectLunarColor(const QColor &selectLunarColor) { Q_D(KMiniCalendarWidget); if (d->selectLunarColor != selectLunarColor) { d->selectLunarColor = selectLunarColor; initStyle(); } } void KMiniCalendarWidget::setHoverLunarColor(const QColor &hoverLunarColor) { Q_D(KMiniCalendarWidget); if (d->hoverLunarColor != hoverLunarColor) { d->hoverLunarColor = hoverLunarColor; initStyle(); } } void KMiniCalendarWidget::setCurrentBgColor(const QColor ¤tBgColor) { Q_D(KMiniCalendarWidget); if (d->currentBgColor != currentBgColor) { d->currentBgColor = currentBgColor; initStyle(); } } void KMiniCalendarWidget::setOtherBgColor(const QColor &otherBgColor) { Q_D(KMiniCalendarWidget); if (d->otherBgColor != otherBgColor) { d->otherBgColor = otherBgColor; initStyle(); } } void KMiniCalendarWidget::setSelectBgColor(const QColor &selectBgColor) { Q_D(KMiniCalendarWidget); if (d->selectBgColor != selectBgColor) { d->selectBgColor = selectBgColor; initStyle(); } } void KMiniCalendarWidget::setHoverBgColor(const QColor &hoverBgColor) { Q_D(KMiniCalendarWidget); if (d->hoverBgColor != hoverBgColor) { d->hoverBgColor = hoverBgColor; initStyle(); } } void KMiniCalendarWidget::wheelEvent(QWheelEvent *event) { Q_D(KMiniCalendarWidget); if (event->angleDelta().ry() > 100) { showPreviousMonth(); } else if (event->angleDelta().ry() < -100) { showNextMonth(); } } void KMiniCalendarWidget::paintEvent(QPaintEvent *event) { Q_D(KMiniCalendarWidget); QPainter painter(this); painter.setRenderHint(QPainter::Antialiasing, true); // 开启抗锯齿 // 圆角矩形的尺寸和圆角大小 QRect rect(0, 0, width(), height()); rect.adjust(8,8,-8,-8); int radius = ThemeController::getRadiusFromDT("kradius-window"); if (radius == -1) radius = 12; // 使用QPainterPath来绘制圆角矩形 QPainterPath path; path.addRoundedRect(rect, radius, radius); // 设置画刷 painter.setBrush(QBrush(d->weekBgColor)); // 设置背景色 // 设置画笔颜色为灰色 QPen pen(QColor(233, 233, 233), 1); // 创建一个灰色、宽度为1的画笔 painter.setPen(pen); // 将画笔应用于QPainter // 绘制圆角矩形(这将包括边框和背景) painter.drawPath(path); // 调用基类的paintEvent来绘制子控件(如果有的话) QWidget::paintEvent(event); } } #include "kminicalendarwidget.moc" #include "moc_kminicalendarwidget.cpp" libkysdk-applications/kysdk-qtwidgets/src/kbreadcrumb.cpp0000664000175000017500000000775015104543305022723 0ustar fengfeng/* * libkysdk-qtwidgets's Library * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #include "kbreadcrumb.h" #include "themeController.h" #include #include #include #include #include #include namespace kdk { class KBreadCrumbPrivate : public QObject, public ThemeController { Q_OBJECT Q_DECLARE_PUBLIC(KBreadCrumb) public: KBreadCrumbPrivate(KBreadCrumb *parent); private: KBreadCrumb *q_ptr; QIcon m_icon; bool m_isFlat; }; KBreadCrumb::KBreadCrumb(QWidget *parent) : QTabBar(parent) , d_ptr(new KBreadCrumbPrivate(this)) { } void KBreadCrumb::setIcon(const QIcon &icon) { Q_D(KBreadCrumb); d->m_icon = icon; update(); } QIcon KBreadCrumb::icon() const { Q_D(const KBreadCrumb); return d->m_icon; } bool KBreadCrumb::isFlat() const { Q_D(const KBreadCrumb); return d->m_isFlat; } void KBreadCrumb::setFlat(bool flat) { Q_D(KBreadCrumb); d->m_isFlat = flat; update(); } QSize KBreadCrumb::tabSizeHint(int index) const { Q_D(const KBreadCrumb); QSize size = QTabBar::tabSizeHint(index); QFont font(QApplication::font()); QFontMetrics fm(font); int width = fm.horizontalAdvance(tabText(index)); size.setWidth(width + 40); if (index == 0 && !d->m_icon.isNull()) size.setWidth(size.width() + 50); return size; } void KBreadCrumb::paintEvent(QPaintEvent *event) { Q_D(const KBreadCrumb); QColor highLightColor = ThemeController::getCustomColorFromDT("highlight-active"); QColor baseColor; QColor focusColor; if (ThemeController::themeMode() == ThemeFlag::DarkTheme) { if (d->m_isFlat) baseColor = "#D9D9D9"; else baseColor = "#47474A"; focusColor = "#D9D9D9"; } else { if (d->m_isFlat) baseColor = "#262626"; else baseColor = "#B3B3B3"; focusColor = "#262626"; } QPainter p(this); p.setRenderHint(QPainter::Antialiasing); p.setRenderHint(QPainter::TextAntialiasing); p.setRenderHint(QPainter::SmoothPixmapTransform); for (int i = 0; i < count(); i++) { QRect rc = tabRect(i); QStyleOptionTab option; initStyleOption(&option, i); p.setPen(Qt::NoPen); p.drawRect(rc); if (QStyle::State_MouseOver & option.state) p.setPen(highLightColor); else if (QStyle::State_Selected & option.state) p.setPen(focusColor); else p.setPen(baseColor); p.setBrush(Qt::NoBrush); if (i == 0 && !d->m_icon.isNull()) { p.drawPixmap(rc.left() + 10, (rc.height() - 24) / 2, 24, 24, d->m_icon.pixmap(24, 24)); p.drawText(rc.adjusted(30, 0, -24, 0), Qt::AlignCenter, tabText(i)); } else p.drawText(rc.adjusted(0, 0, -24, 0), Qt::AlignCenter, tabText(i)); if (i != count() - 1) p.drawPixmap(rc.right() - 24, (rc.height() - 16) / 2, 16, 16, ThemeController::drawColoredPixmap(QIcon::fromTheme("ukui-end-symbolic").pixmap(16, 16), baseColor)); } } KBreadCrumbPrivate::KBreadCrumbPrivate(KBreadCrumb *parent) : q_ptr(parent) , m_isFlat(true) { } } #include "kbreadcrumb.moc" #include "moc_kbreadcrumb.cpp" libkysdk-applications/kysdk-qtwidgets/src/kbaseframe.h0000664000175000017500000000515315104543305022202 0ustar fengfeng/* * * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Sisheng He * */ #ifndef KBASEFRAME_H #define KBASEFRAME_H #include #include #include "klabel.h" #define RADIUS_VALUE 6 /**< 圆角数值 */ #define PC_HEIGHT 60 /**< pc模式下高度 */ #define TABLET_HEIGHT 64 /**< 平板模式下高度 */ #define SETTING_LABEL_WIDTH 214 /**< label 宽度*/ namespace kdk { /** * @defgroup ContainerModule * @brief 支持圆角四种类型的容器 * @since 3.0.1.0 * { */ class KBaseFramePrivate; class KBaseFrame : public QFrame { Q_OBJECT public: enum BorderRadiusStyle { Top, /**< 顶部有圆角 */ None, /**< 没有圆角 */ Bottom, /**< 底部有圆角 */ Around /**< 四周都有圆角 */ }; /** * @brief 构造函数 * * @param parent 父对象 * @param style 圆角风格枚举值 * @param heightAdaptive 是否自动调整高度,默认PC下60,平板模式64 */ explicit KBaseFrame(QWidget *parent = nullptr, BorderRadiusStyle style = Around, bool heightAdaptive = false); ~KBaseFrame(); /** * @brief 设置圆角风格 * * @param style 圆角风格枚举值 */ void setRadiusType(BorderRadiusStyle style); /** * @brief 获取平板模式 * * @return bool 是否是平板模式 */ bool getTabletMode(); /** * @brief 获取是否是一个容器frame,此时settinggroup需要设置的是其子frame的圆角 * * @return bool 是/不是 */ bool isContainer(); /** * @brief 设置该frame是否是一个容器frame,如果是同时setFrameShape(NoFrame); * * @param b 是/不是 */ void setContainer(bool b = false); Q_SIGNALS: void tabletModeChanged(bool b); protected: void paintEvent(QPaintEvent *e); private: Q_DECLARE_PRIVATE(KBaseFrame) KBaseFramePrivate *const d_ptr; }; } #endif // KBASEFRAME_H libkysdk-applications/kysdk-qtwidgets/src/kborderbutton.cpp0000664000175000017500000001362315104543305023322 0ustar fengfeng/* * libkysdk-qtwidgets's Library * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #include "kborderbutton.h" #include "parmscontroller.h" #include "themeController.h" #include #include #include #include namespace kdk { class KBorderButtonPrivate : public QObject, public ThemeController { Q_DECLARE_PUBLIC(KBorderButton) Q_OBJECT public: KBorderButtonPrivate(KBorderButton *parent); protected: void changeTheme(); private: KBorderButton *q_ptr; bool m_hoverd; int m_radius; }; KBorderButton::KBorderButton(QWidget *parent) : QPushButton(parent) , d_ptr(new KBorderButtonPrivate(this)) { Q_D(KBorderButton); connect(Parmscontroller::self(), &Parmscontroller::modeChanged, this, [=]() { updateGeometry(); }); } KBorderButton::~KBorderButton() { } QSize KBorderButton::sizeHint() const { auto size = QPushButton::sizeHint(); size.setHeight(Parmscontroller::parm(Parmscontroller::Parm::PM_PushButtonHeight)); return size; } bool KBorderButton::eventFilter(QObject *watched, QEvent *event) { Q_D(KBorderButton); return QPushButton::eventFilter(watched, event); } void KBorderButton::paintEvent(QPaintEvent *event) { Q_D(KBorderButton); QStyleOptionButton option; initStyleOption(&option); QPainter p(this); QColor borderColor; QColor fontColor; int borderWidth = 1; QColor startColor; QColor endColor; if (!option.state.testFlag(QStyle::State_Enabled)) { borderColor = ThemeController::getCustomColorFromDT("kfont-primary-disable"); fontColor = ThemeController::getCustomColorFromDT("kfont-primary-disable"); } else if (option.state.testFlag(QStyle::State_MouseOver)) { if (option.state.testFlag(QStyle::State_Sunken)) { ThemeController::getGradientFromDT("kbrand-click",startColor,endColor); fontColor = endColor; borderColor = endColor; } else { ThemeController::getGradientFromDT("kbrand-hover",startColor,endColor); fontColor = endColor; borderColor = endColor; } } else { fontColor = ThemeController::getCustomColorFromDT("buttontext-active"); borderColor = ThemeController::getCustomColorFromDT("button-active"); } p.setBrush(Qt::NoBrush); p.setRenderHint(QPainter::Antialiasing); p.setRenderHint(QPainter::TextAntialiasing); p.setRenderHint(QPainter::SmoothPixmapTransform); QPen pen; pen.setCapStyle(Qt::RoundCap); pen.setJoinStyle(Qt::RoundJoin); p.save(); pen.setWidth(borderWidth); pen.setColor(borderColor); p.setPen(pen); p.drawRoundedRect(option.rect.adjusted(1, 1, -1, -1), d->m_radius, d->m_radius); p.restore(); pen.setWidth(1); pen.setColor(fontColor); p.setPen(pen); QPoint point; QRect ir = option.rect; uint tf = Qt::AlignVCenter; if (!option.icon.isNull()) { // Center both icon and text QIcon::Mode mode = option.state & QStyle::State_Enabled ? QIcon::Normal : QIcon::Disabled; if (mode == QIcon::Normal && option.state & QStyle::State_HasFocus) mode = QIcon::Active; QIcon::State state = QIcon::Off; if (option.state & QStyle::State_On) state = QIcon::On; QPixmap pixmap = option.icon.pixmap(option.iconSize, mode, state); pixmap = ThemeController::drawColoredPixmap(pixmap, fontColor); int w = pixmap.width() / pixmap.devicePixelRatio(); int h = pixmap.height() / pixmap.devicePixelRatio(); if (!option.text.isEmpty()) w += option.fontMetrics.boundingRect(option.rect, tf, option.text).width() + 2; point = QPoint(ir.x() + ir.width() / 2 - w / 2, ir.y() + ir.height() / 2 - h / 2); w = pixmap.width() / pixmap.devicePixelRatio(); if (option.direction == Qt::RightToLeft) point.rx() += w; p.drawPixmap(this->style()->visualPos(option.direction, option.rect, point), pixmap); if (option.direction == Qt::RightToLeft) ir.translate(-point.x() - 2, 0); else ir.translate(point.x() + w + 4, 0); // left-align text if there is if (!option.text.isEmpty()) tf |= Qt::AlignLeft; } else { tf |= Qt::AlignHCenter; } p.drawText(ir, tf, option.text); } KBorderButton::KBorderButton(const QString &text, QWidget *parent) : KBorderButton(parent) { setText(text); } KBorderButton::KBorderButton(const QIcon &icon, const QString &text, QWidget *parent) : KBorderButton(parent) { setIcon(icon); setText(text); } void KBorderButton::setIcon(const QIcon &icon) { Q_D(KBorderButton); QPushButton::setIcon(icon); } KBorderButtonPrivate::KBorderButtonPrivate(KBorderButton *parent) : q_ptr(parent) , m_hoverd(false) { setParent(parent); m_radius = ThemeController::getRadiusFromDT("kradius-normal"); if (m_radius == -1) m_radius = 6; } void KBorderButtonPrivate::changeTheme() { Q_Q(KBorderButton); initThemeStyle(); } } #include "kborderbutton.moc" #include "moc_kborderbutton.cpp" libkysdk-applications/kysdk-qtwidgets/src/kmenubutton.cpp0000664000175000017500000002245615104543305023015 0ustar fengfeng/* * libkysdk-qtwidgets's Library * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #include "kmenubutton.h" #include "accessinfohelper.h" #include "parmscontroller.h" #include #include #include #include #include #include #include namespace kdk { class KMenuButtonPrivate : public QObject { Q_DECLARE_PUBLIC(KMenuButton) Q_OBJECT public: KMenuButtonPrivate(KMenuButton *parent); void feedbackShow(); void setAccessInfo(); protected: bool eventFilter(QObject *watched, QEvent *event); private: KMenuButton *q_ptr; QMenu *m_pMenu; QAction *m_pSettingAction; QAction *m_pThemeAction; QAction *m_pAssistAction; QAction *m_pAboutAction; QAction *m_pFeedbackAction; QAction *m_pQuitAction; QMenu *m_pThemeMenu; QAction *m_pAutoAction; QAction *m_pLightAction; QAction *m_pDarkAction; QProcess m_feedbackProcess; }; KMenuButton::KMenuButton(QWidget *parent) : QToolButton(parent) , d_ptr(new KMenuButtonPrivate(this)) { Q_D(KMenuButton); // setArrowType(Qt::NoArrow); d->m_pMenu = new QMenu(this); setMenu(d->m_pMenu); setToolTip(tr("Options")); d->m_pSettingAction = new QAction(tr("Setting"), d->m_pMenu); d->m_pThemeAction = new QAction(tr("Theme"), d->m_pMenu); d->m_pAssistAction = new QAction(tr("Help"), d->m_pMenu); d->m_pAboutAction = new QAction(tr("About"), d->m_pMenu); d->m_pFeedbackAction = new QAction(tr("Feedback"), d->m_pMenu); d->m_pQuitAction = new QAction(tr("Quit"), d->m_pMenu); QList actionList; actionList << d->m_pSettingAction << d->m_pThemeAction << d->m_pAssistAction << d->m_pAboutAction << d->m_pFeedbackAction << d->m_pQuitAction; d->m_pMenu->addActions(actionList); setPopupMode(QToolButton::InstantPopup); d->m_pThemeMenu = new QMenu(this); d->m_pAutoAction = new QAction(tr("Auto"), d->m_pThemeMenu); d->m_pAutoAction->setCheckable(true); d->m_pLightAction = new QAction(tr("Light"), d->m_pThemeMenu); d->m_pLightAction->setCheckable(true); d->m_pDarkAction = new QAction(tr("Dark"), d->m_pThemeMenu); d->m_pDarkAction->setCheckable(true); QActionGroup *group = new QActionGroup(this); group->addAction(d->m_pAutoAction); group->addAction(d->m_pLightAction); group->addAction(d->m_pDarkAction); QList list; list << d->m_pAutoAction << d->m_pLightAction << d->m_pDarkAction; d->m_pThemeMenu->addActions(list); d->m_pThemeAction->setMenu(d->m_pThemeMenu); setIcon(QIcon::fromTheme("open-menu-symbolic")); setProperty("isWindowButton", 0x1); setProperty("useIconHighlightEffect", 0x2); setAutoRaise(true); changeTheme(); connect(m_gsetting, &QGSettings::changed, this, [=]() { changeTheme(); }); connect(Parmscontroller::self(), &Parmscontroller::modeChanged, this, [=]() { updateGeometry(); update(); }); QString directoryPath = "/opt/kylin-os-manager/tools/service-support-mini"; QFile file(directoryPath); if (file.exists()) feedbackAction()->setVisible(true); else feedbackAction()->setVisible(false); connect(feedbackAction(), &QAction::triggered, this, [=] { d->feedbackShow(); }); d->setAccessInfo(); } KMenuButton::~KMenuButton() { } QMenu *KMenuButton::menu() { Q_D(KMenuButton); return d->m_pMenu; } QMenu *KMenuButton::themeMenu() { Q_D(KMenuButton); return d->m_pThemeMenu; } QAction *KMenuButton::settingAction() { Q_D(KMenuButton); return d->m_pSettingAction; } QAction *KMenuButton::themeAction() { Q_D(KMenuButton); return d->m_pThemeAction; } QAction *KMenuButton::assistAction() { Q_D(KMenuButton); return d->m_pAssistAction; } QAction *KMenuButton::aboutAction() { Q_D(KMenuButton); return d->m_pAboutAction; } QAction *KMenuButton::feedbackAction() { Q_D(KMenuButton); return d->m_pFeedbackAction; } QAction *KMenuButton::quitAction() { Q_D(KMenuButton); return d->m_pQuitAction; } QAction *KMenuButton::autoAction() { Q_D(KMenuButton); return d->m_pAutoAction; } QAction *KMenuButton::lightAction() { Q_D(KMenuButton); return d->m_pLightAction; } QAction *KMenuButton::darkAction() { Q_D(KMenuButton); return d->m_pDarkAction; } void KMenuButton::changeTheme() { initThemeStyle(); QIcon menuIcon = QIcon::fromTheme("open-menu-symbolic"); QColor color; if (!isActiveWindow()) { if (ThemeController::themeMode() == LightTheme) color = ThemeController::getCustomColorFromDT("kgray-11"); else color = ThemeController::getCustomColorFromDT("kwhite"); menuIcon = ThemeController::drawColoredPixmap(menuIcon.pixmap(QSize(Parmscontroller::parm(Parmscontroller::Parm::PM_WindowButtonBarSize), Parmscontroller::parm(Parmscontroller::Parm::PM_WindowButtonBarSize))), color); setIcon(menuIcon); } else { if (ThemeController::themeMode() == LightTheme) color = ThemeController::getCustomColorFromDT("kgray-17"); else color = ThemeController::getCustomColorFromDT("kwhite"); menuIcon = ThemeController::drawColoredPixmap(menuIcon.pixmap(QSize(Parmscontroller::parm(Parmscontroller::Parm::PM_WindowButtonBarSize), Parmscontroller::parm(Parmscontroller::Parm::PM_WindowButtonBarSize))), color); setIcon(menuIcon); } } void KMenuButton::paintEvent(QPaintEvent *painteEvent) { QToolButton::paintEvent(painteEvent); } QSize KMenuButton::sizeHint() const { auto size = QToolButton::sizeHint(); size.setHeight(Parmscontroller::parm(Parmscontroller::Parm::PM_PushButtonHeight)); size.setWidth(Parmscontroller::parm(Parmscontroller::Parm::PM_PushButtonHeight)); return size; } KMenuButtonPrivate::KMenuButtonPrivate(KMenuButton *parent) : q_ptr(parent) { setParent(parent); parent->installEventFilter(this); } void KMenuButtonPrivate::feedbackShow() { Q_Q(KMenuButton); QString directoryPath = "/opt/kylin-os-manager/tools/service-support-mini"; QFile file(directoryPath); if (file.exists()) { QStringList arguments; QString processName; QString fileName = QString("/proc/%1/cmdline").arg(QApplication::applicationPid()); QFile file(fileName); if (file.open(QIODevice::ReadOnly)) { QByteArray data = file.readAll(); int pos = data.indexOf('\0'); if (pos != -1) { QStringList list = QString::fromUtf8(data.left(pos)).trimmed().split("/"); processName = list.last(); } file.close(); } arguments << "-mode=1" << "-exe=" + processName; m_feedbackProcess.startDetached(directoryPath, arguments); m_feedbackProcess.waitForFinished(); } } void KMenuButtonPrivate::setAccessInfo() { Q_Q(KMenuButton); KDK_ALL_INFO_FORMAT(m_pMenu,""); KDK_OBJ_INFO_FORMAT(m_pSettingAction); KDK_OBJ_INFO_FORMAT(m_pThemeAction); KDK_OBJ_INFO_FORMAT(m_pAssistAction); KDK_OBJ_INFO_FORMAT(m_pAboutAction); KDK_OBJ_INFO_FORMAT(m_pFeedbackAction); KDK_OBJ_INFO_FORMAT(m_pQuitAction); KDK_ALL_INFO_FORMAT(m_pThemeMenu,""); KDK_OBJ_INFO_FORMAT(m_pAutoAction); KDK_OBJ_INFO_FORMAT(m_pLightAction); KDK_OBJ_INFO_FORMAT(m_pDarkAction); } bool KMenuButtonPrivate::eventFilter(QObject *watched, QEvent *event) { Q_Q(KMenuButton); QIcon menuIcon = QIcon::fromTheme("open-menu-symbolic"); QColor color; if (QEvent::WindowDeactivate == event->type()) { if (ThemeController::themeMode() == LightTheme) color = ThemeController::getCustomColorFromDT("kgray-11"); else color = ThemeController::getCustomColorFromDT("kwhite"); menuIcon = ThemeController::drawColoredPixmap(menuIcon.pixmap(QSize(Parmscontroller::parm(Parmscontroller::Parm::PM_WindowButtonBarSize), Parmscontroller::parm(Parmscontroller::Parm::PM_WindowButtonBarSize))), color); q->setIcon(menuIcon); } if (QEvent::WindowActivate == event->type() || QEvent::MouseButtonPress == event->type()) { if (ThemeController::themeMode() == DarkTheme) { color = ThemeController::getCustomColorFromDT("kwhite"); } menuIcon = ThemeController::drawColoredPixmap(menuIcon.pixmap(QSize(Parmscontroller::parm(Parmscontroller::Parm::PM_WindowButtonBarSize), Parmscontroller::parm(Parmscontroller::Parm::PM_WindowButtonBarSize))), color); q->setIcon(menuIcon); } return QObject::eventFilter(watched, event); } } #include "kmenubutton.moc" #include "moc_kmenubutton.cpp" libkysdk-applications/kysdk-qtwidgets/src/kswitchbuttonframe.h0000664000175000017500000000403115104543305024017 0ustar fengfeng/* * * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Sisheng He * */ #ifndef SWITCHWIDGET_H #define SWITCHWIDGET_H #include "kbaseframe.h" #include "kswitchbutton.h" /** * @defgroup ContainerModules * @brief 创建一个带 KSwitchButton 的 Frame * @since 3.0.1.0 * { */ namespace kdk { class KSwitchButtonFramePrivate; class KSwitchButtonFrame : public KBaseFrame { Q_OBJECT public: /** * @brief 创建一个带 KSwitchButton 的 Frame * * @param title: text of m_settingName * @param style: 设置圆角(None:无圆角,Top:上圆角,Bottom:下圆角,Around:四圆角) * @param parent */ explicit KSwitchButtonFrame(const QString title, QWidget *parent = nullptr, BorderRadiusStyle style = BorderRadiusStyle::None); ~KSwitchButtonFrame(); /** * @brief 设置提示文案 * @param hintText */ void setHintText(QString &hintText); /** * @brief 获取 switchbutton * @return KSlider: m_slider */ KSwitchButton *switchButton(); /** * @brief 获取label * * @return QLabel */ KLabel *titleLabel(); /** * @brief 获取layout * * @return QHBoxLayout */ QHBoxLayout *mainHLayout(); private: Q_DECLARE_PRIVATE(KSwitchButtonFrame) KSwitchButtonFramePrivate *const d_ptr; }; } #endif // SWITCHWIDGET_H libkysdk-applications/kysdk-qtwidgets/kysdk-qtwidgets.pro0000664000175000017500000001551615104543305023026 0ustar fengfengQT += widgets core sql dbus svg TEMPLATE = lib DEFINES += GUI_LIBRARY CONFIG += c++17 VERSION = 1.2.0 # 适配窗口管理器圆角阴影 LIBS +=-lX11 # The following define makes your compiler emit warnings if you use # any Qt feature that has been marked deprecated (the exact warnings # depend on your compiler). Please consult the documentation of the # deprecated API in order to know how to port your code away from it. DEFINES += QT_DEPRECATED_WARNINGS DEFINES += USE_UKUI_PROTOCOL DEFINES += USE_UKUI_SHELL_PLUGIN # You can also make your code fail to compile if it uses deprecated APIs. # In order to do so, uncomment the following line. # You can also select to disable deprecated APIs only up to a certain version of Qt. #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 CONFIG += link_pkgconfig PKGCONFIG += gsettings-qt6 PKGCONFIG += KF6WindowSystem x11 INCLUDEPATH += ../kysdk-waylandhelper/src LIBS += -L../kysdk-waylandhelper -lkysdk-waylandhelper LIBS += -L../kysdk-waylandhelper/src/kysdk-ukuiwindowhelper -lkysdk-ukuiwindowhelper TRANSLATIONS += ./translations/gui_zh_CN.ts \ ./translations/gui_bo_CN.ts \ ./translations/gui_zh_HK.ts \ ./translations/gui_mn.ts \ ./translations/gui_de.ts \ ./translations/gui_es.ts \ ./translations/gui_fr.ts \ ./translations/gui_kk.ts \ ./translations/gui_ug.ts \ ./translations/gui_ky.ts system(lrelease ./translations/gui_zh_CN.ts ./translations/gui_zh_CN.qm) system(lrelease ./translations/gui_bo_CN.ts ./translations/gui_bo_CN.qm) system(lrelease ./translations/gui_zh_HK.ts ./translations/gui_zh_HK.qm) system(lrelease ./translations/gui_mn.ts ./translations/gui_mn.qm) system(lrelease ./translations/gui_de.ts ./translations/gui_de.qm) system(lrelease ./translations/gui_es.ts ./translations/gui_es.qm) system(lrelease ./translations/gui_fr.ts ./translations/gui_fr.qm) system(lrelease ./translations/gui_kk.ts ./translations/gui_kk.qm) system(lrelease ./translations/gui_ug.ts ./translations/gui_ug.qm) system(lrelease ./translations/gui_ky.ts ./translations/gui_ky.qm) SOURCES += \ src/kaboutdialog.cpp \ src/kaddfilebutton.cpp \ src/karrowtabbar.cpp \ src/kbackgroundgroup.cpp\ src/kbadge.cpp \ src/kballontip.cpp \ src/kborderbutton.cpp \ src/kborderlessbutton.cpp \ src/kbreadcrumb.cpp \ src/kbubblewidget.cpp\ src/kbuttonbox.cpp\ src/kclocktimer.cpp \ src/kcolorbutton.cpp\ src/kcolorcombobox.cpp \ src/kcomboboxwidget.cpp \ src/kcommentpanel.cpp \ src/kcrumb.cpp \ src/kcustomdateedit.cpp \ src/kcustomtabbar.cpp \ src/kdialog.cpp \ src/kdirtabbar.cpp \ src/kdragwidget.cpp \ src/kfilewidget.cpp \ src/kiconbar.cpp \ src/kinputdialog.cpp \ src/kintrowidget.cpp \ src/kitemwidget.cpp\ src/klabel.cpp \ src/klineedit.cpp \ src/klineframe.cpp\ src/klistview.cpp\ src/klistviewdelegate.cpp\ src/klistwidget.cpp\ src/kloopplaypage.cpp \ src/klunarcalendarinfo.cpp \ src/klunardateedit.cpp \ src/kmenubutton.cpp \ src/kmessagebox.cpp\ src/kminicalendaritem.cpp \ src/kminicalendarwidget.cpp \ src/knativetabbar.cpp \ src/knavigationbar.cpp \ src/knavigationtrail.cpp \ src/kpasswordedit.cpp \ src/kpixmapcontainer.cpp \ src/kpressbutton.cpp\ src/kprogressbar.cpp \ src/kprogresscircle.cpp \ src/kprogressdialog.cpp \ src/kprogresslabel.cpp \ src/kpushbutton.cpp\ src/ksearchlineedit.cpp \ src/ksecuritylevelbar.cpp \ src/ksecurityquestiondialog.cpp \ src/kshadowhelper.cpp\ src/kslider.cpp \ src/kswitchbutton.cpp \ src/ktabbar.cpp \ src/ktableheaderview.cpp \ src/ktablemodel.cpp \ src/ktableview.cpp \ src/ktag.cpp \ src/ktextedit.cpp \ src/ktexteditor.cpp \ src/ktitlewindow.cpp \ src/ktoolbar.cpp \ src/ktoolbutton.cpp \ src/ktranslucentfloor.cpp\ src/kuninstalldialog.cpp \ src/kwidget.cpp \ src/kwindowbuttonbar.cpp \ src/parmscontroller.cpp\ src/themeController.cpp \ src/xatom-helper.cpp \ src/kaddbutton.cpp \ src/kbaseframe.cpp \ src/kcomboboxframe.cpp \ src/kflowlayout.cpp \ src/klineeditframe.cpp \ src/kpushbuttonframe.cpp \ src/kradiobuttonframe.cpp \ src/ksettinggroup.cpp \ src/ksliderframe.cpp \ src/kswitchbuttonframe.cpp \ HEADERS += \ src/gui_g.h \ src/kaboutdialog.h \ src/kaddfilebutton.h \ src/karrowtabbar.h \ src/kbackgroundgroup.h\ src/kbadge.h \ src/kballontip.h \ src/kborderbutton.h \ src/kborderlessbutton.h \ src/kbreadcrumb.h \ src/kbubblewidget.h\ src/kbuttonbox.h\ src/kclocktimer.h \ src/kcolorbutton.h\ src/kcolorcombobox.h \ src/kcomboboxwidget.h \ src/kcommentpanel.h \ src/kcrumb.h \ src/kcustomdateedit.h \ src/kcustomtabbar.h \ src/kdialog.h \ src/kdirtabbar.h \ src/kdragwidget.h \ src/kfilewidget.h \ src/kiconbar.h \ src/kinputdialog.h \ src/kintrowidget.h \ src/kitemwidget.h\ src/klabel.h \ src/klineedit.h \ src/klineframe.h\ src/klistviewdelegate.h\ src/klistview.h\ src/klistwidget.h\ src/kloopplaypage.h \ src/klunarcalendarinfo.h \ src/klunardateedit.h \ src/kmenubutton.h \ src/kmessagebox.h\ src/kminicalendaritem.h \ src/kminicalendarwidget.h \ src/knativetabbar.h \ src/knavigationbar.h \ src/knavigationtrail.h \ src/kpasswordedit.h \ src/kpixmapcontainer.h \ src/kpressbutton.h\ src/kprogressbar.h \ src/kprogresscircle.h \ src/kprogressdialog.h \ src/kprogresslabel.h \ src/kpushbutton.h\ src/ksearchlineedit.h \ src/ksecuritylevelbar.h \ src/ksecurityquestiondialog.h \ src/kshadowhelper.h\ src/kslider.h \ src/kswitchbutton.h \ src/ktabbar.h \ src/ktableheaderview.h \ src/ktablemodel.h \ src/ktableview.h \ src/ktag.h \ src/ktextedit.h \ src/ktexteditor.h \ src/ktitlewindow.h \ src/ktoolbar.h \ src/ktoolbutton.h \ src/ktranslucentfloor.h\ src/kuninstalldialog.h \ src/kwidget.h \ src/kwindowbuttonbar.h \ src/parmscontroller.h\ src/themeController.h \ src/accessinfohelper.h \ src/xatom-helper.h \ src/kaddbutton.h \ src/kbaseframe.h \ src/kcomboboxframe.h \ src/kflowlayout.h \ src/klineeditframe.h \ src/kpushbuttonframe.h \ src/kradiobuttonframe.h \ src/ksettinggroup.h \ src/ksliderframe.h \ src/kswitchbuttonframe.h \ # Default rules for deployment. headers.files = $${HEADERS} headers.path = /usr/include/kysdk/applications/ target.path = $$[QT_INSTALL_LIBS] INSTALLS += target headers RESOURCES += \ sdk_res.qrc DISTFILES += \ translations/gui_bo_CN.ts libkysdk-applications/kysdk-qtwidgets/readme.md0000664000175000017500000000000015104515306020703 0ustar fengfenglibkysdk-applications/pre-commit0000664000175000017500000000120615104543305015776 0ustar fengfeng#!/bin/bash # This script is used to format the code using clang-format before git commit. readonly output=$(git clang-format --extensions 'cpp,h,hpp,c' -v --diff) if [[ "$output" == *"no modified files to format"* ]]; then exit 0; fi if [[ "$output" == *"clang-format did not modify any files"* ]]; then exit 0; fi echo "ERROR: You have unformatted changes, please format your files. You can do this using the following commands:" echo " git clang-format --extensions 'cpp,h,hpp,c' --force # format the changed parts" echo " git clang-format --extensions 'cpp,h,hpp,c' --diff # preview the changes done by the formatter" exit 1 libkysdk-applications/kysdk-waylandhelper/0000775000175000017500000000000015155674255020001 5ustar fengfenglibkysdk-applications/kysdk-waylandhelper/kysdk-waylandhelper.pro0000664000175000017500000001614015104543305024470 0ustar fengfengQT += gui widgets concurrent TEMPLATE = lib DEFINES += KYSDKWAYLANDHELPER_LIBRARY CONFIG += c++17 link_pkgconfig PKGCONFIG += wayland-client wayland-server x11 PKGCONFIG += KF6WindowSystem KWaylandClient LIBS += -lKF6IconThemes INCLUDEPATH += /usr/include/KF6/KIconThemes/ # The following define makes your compiler emit warnings if you use # any Qt feature that has been marked deprecated (the exact warnings # depend on your compiler). Please consult the documentation of the # deprecated API in order to know how to port your code away from it. DEFINES += QT_DEPRECATED_WARNINGS DEFINES += USE_UKUI_PROTOCOL DEFINES += USE_UKUI_SHELL_PLUGIN DEFINES += DEPERCATED_OLD_API # You can also make your code fail to compile if it uses deprecated APIs. # In order to do so, uncomment the following line. # You can also select to disable deprecated APIs only up to a certain version of Qt. #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 system(wayland-scanner client-header protocols/ukui-shell.xml $$OUT_PWD/ukui-shell-client-protocol.h) system(wayland-scanner private-code protocols/ukui-shell.xml $$OUT_PWD/ukui-shell-core-protocol.c) system(wayland-scanner client-header protocols/ukui-window-management.xml $$OUT_PWD/ukui-window-management-client-protocol.h) system(wayland-scanner private-code protocols/ukui-window-management.xml $$OUT_PWD/ukui-window-management-core-protocol.c) system(wayland-scanner client-header protocols/xdg-activation-v1.xml $$OUT_PWD/wayland-xdg-activation-v1-client-protocol.h) system(wayland-scanner private-code protocols/xdg-activation-v1.xml $$OUT_PWD/wayland-xdg-activation-v1-protocol.c) system(wayland-scanner client-header protocols/ext-idle-notify-v1.xml $$OUT_PWD/wayland-ext-idle-notify-v1-client-protocol.h) system(wayland-scanner private-code protocols/ext-idle-notify-v1.xml $$OUT_PWD/wayland-ext-idle-notify-v1-protocol.c) system(wayland-scanner client-header protocols/ukui-blur-v1.xml $$OUT_PWD/ukui-blur-manager-client-protocol.h) system(wayland-scanner private-code protocols/ukui-blur-v1.xml $$OUT_PWD/ukui-blur-manager-core-protocol.c) system(wayland-scanner client-header protocols/plasma-window-management.xml $$OUT_PWD/wayland-plasma-window-management-client-protocol.h) system(wayland-scanner private-code protocols/plasma-window-management.xml $$OUT_PWD/wayland-plasma-window-management-protocol.c) SOURCES += \ src/ukuistylehelper/ukui-decoration-core.c \ src/ukuistylehelper/ukui-decoration-manager.cpp \ src/ukuistylehelper/ukuistylehelper.cpp \ src/ukuistylehelper/xatom-helper.cpp \ src/ukuistylehelper/ukui-shell-manager.cpp \ src/waylandhelper.cpp \ src/windowmanager/abstractinterface.cpp \ src/windowmanager/kdewaylandinterface.cpp \ src/windowmanager/outputinfo.cpp \ src/windowmanager/ukuiwaylandinterface.cpp \ src/windowmanager/xcbinterface.cpp \ src/windowmanager/ukuiwindowmanagement.cpp \ src/windowmanager/wmregister.cpp \ src/windowmanager/windowmanager.cpp \ src/windowmanager/extidlenotifier.cpp \ src/windowmanager/idlenotifier.cpp \ src/windowmanager/ukuishell.cpp \ src/windowmanager/xdgactivation.cpp \ src/blurmanager/ukuiblur.cpp \ src/blurmanager/blurmanager.cpp \ src/blurmanager/blurwaylandinterface.cpp \ src/blurmanager/blurxcbinterface.cpp \ $$OUT_PWD/ukui-blur-manager-core-protocol.c \ $$OUT_PWD/ukui-window-management-core-protocol.c \ $$OUT_PWD/ukui-shell-core-protocol.c \ $$OUT_PWD/wayland-xdg-activation-v1-protocol.c \ $$OUT_PWD/wayland-ext-idle-notify-v1-protocol.c \ $$OUT_PWD/wayland-plasma-window-management-protocol.c \ HEADERS += \ src/ukuistylehelper/ukui-decoration-client.h \ src/ukuistylehelper/ukui-decoration-manager.h \ src/ukuistylehelper/ukuistylehelper.h \ src/ukuistylehelper/xatom-helper.h \ src/ukuistylehelper/ukui-shell-manager.h \ src/waylandhelper.h \ src/windowmanager/abstractinterface.h \ src/windowmanager/kdewaylandinterface.h \ src/windowmanager/outputinfo.h \ src/windowmanager/xcbinterface.h \ src/windowmanager/ukuiwaylandinterface.h \ src/windowmanager/ukuiwaylandpointer.h \ src/windowmanager/ukuiwindowmanagement.h \ src/windowmanager/windowinfo.h \ src/windowmanager/wmregister.h \ src/windowmanager/windowmanager.h \ src/windowmanager/xdgactivation.h \ src/windowmanager/ukuishell.h \ src/windowmanager/extidlenotifier.h \ src/windowmanager/idlenotifier.h \ src/windowmanager/kyatoms_p.h \ src/blurmanager/ukuiblur.h \ src/blurmanager/blurmanager.h \ src/blurmanager/blurabstractinterface.h \ src/blurmanager/blurwaylandinterface.h \ src/blurmanager/blurxcbinterface.h \ $$OUT_PWD/ukui-blur-manager-client-protocol.h\ $$OUT_PWD/ukui-shell-client-protocol.h \ $$OUT_PWD/wayland-plasma-window-management-client-protocol.h \ $$OUT_PWD/ukui-window-management-client-protocol.h \ $$OUT_PWD/wayland-xdg-activation-v1-client-protocol.h \ $$OUT_PWD/wayland-ext-idle-notify-v1-client-protocol.h \ INCLUDEPATH+=src \ src/windowmanager \ $$OUT_PWD \ # Default rules for deployment. headers.files = src/kysdk-waylandhelper_global.h \ src/waylandhelper.h headers.path = /usr/include/kysdk/applications/ wm_headers.files = src/windowmanager/abstractinterface.h \ src/windowmanager/kdewaylandinterface.h \ src/windowmanager/xcbinterface.h \ src/windowmanager/ukuiwaylandinterface.h \ src/windowmanager/ukuiwaylandpointer.h \ src/windowmanager/ukuiwindowmanagement.h \ src/windowmanager/windowinfo.h \ src/windowmanager/wmregister.h \ src/windowmanager/windowmanager.h \ src/windowmanager/xdgactivation.h \ src/windowmanager/ukuishell.h \ src/windowmanager/extidlenotifier.h \ src/windowmanager/idlenotifier.h \ src/windowmanager/kyatoms_p.h \ src/windowmanager/outputinfo.h \ $$OUT_PWD/ukui-shell-client-protocol.h \ $$OUT_PWD/wayland-plasma-window-management-client-protocol.h \ $$OUT_PWD/ukui-window-management-client-protocol.h \ $$OUT_PWD/wayland-xdg-activation-v1-client-protocol.h \ $$OUT_PWD/wayland-ext-idle-notify-v1-client-protocol.h \ wm_headers.path = /usr/include/kysdk/applications/windowmanager/ sty_headers.files = src/ukuistylehelper/ukui-decoration-client.h \ src/ukuistylehelper/ukui-decoration-manager.h \ src/ukuistylehelper/ukuistylehelper.h \ src/ukuistylehelper/xatom-helper.h \ src/ukuistylehelper/ukui-shell-manager.h sty_headers.path = /usr/include/kysdk/applications/ukuistylehelper/ blur_headers.files = src/blurmanager/ukuiblur.h \ src/blurmanager/blurmanager.h \ src/blurmanager/blurabstractinterface.h \ src/blurmanager/blurwaylandinterface.h \ src/blurmanager/blurxcbinterface.h \ $$OUT_PWD/ukui-blur-manager-client-protocol.h \ blur_headers.path = /usr/include/kysdk/applications/blurmanager/ target.path = $$[QT_INSTALL_LIBS] INSTALLS += target headers wm_headers sty_headers blur_headers libkysdk-applications/kysdk-waylandhelper/protocols/0000775000175000017500000000000015155674255022025 5ustar fengfenglibkysdk-applications/kysdk-waylandhelper/protocols/ukui-window-management.xml0000664000175000017500000004221615104543305027131 0ustar fengfeng This interface manages application windows. It provides requests to show and hide the desktop and emits an event every time a window is created so that the client can use it to manage the window. Tell the compositor to show/hide the desktop. This event will be sent whenever the show desktop mode changes. E.g. when it is entered or left. On binding the interface the current state is sent. This event will be sent when stacking order changed and on bind This event will be sent immediately after a window is mapped. Manages and control an application window. Set window state. Can set multiple states at once. Values for state argument are described by ukui_window_management.state and can be used together in a bitfield. The flags bitfield describes which flags are supposed to be set, the state bitfield the value for the set flags. The state argument is not a boolean value, but a bitfield, so it is possible to set multiple states at once. Only the states that are set in the flags bitfield will be changed. For example: If flags was 0x14(keep_above|maximized) and state was 0x04(maximized), the window would be maximized, but not keep above. If flags was 0x04(maximized) and state was 0x14(keep_above|maximized), the window would be maximized but not change keep above state. Sets the geometry of the taskbar/desktop entry for this window. The geometry is relative to a panel/desktop in particular. Sets the geometry of the taskbar entry for this window. The geometry is relative to a panel in particular. Remove the task geometry information for a particular panel. Close this window. Request an interactive move for this window. The pointer will move to the center of the window and move with the pointer. When mouse button is released, the interactive move ends. Request an interactive resize for this window. The pointer will move to window right bottom corner and resize with the pointer. When mouse button is released, the interactive resize ends. Removes the resource bound for this ukui_window. The compositor will write the window icon into the provided file descriptor. This is an array of 32bit packed CARDINAL ARGB with high byte being A, low byte being B. The first two cardinals are width, height. Data is in rows, left to right and top to bottom. This event will be sent as soon as the window title is changed. This event will be sent as soon as the application identifier is changed. This event will be sent as soon as the window state changes. Values for state argument are described by ukui_window_management.state. It contains the whole new state of the window. This event will be sent whenever the themed icon name changes. May be null. This event will be sent immediately after the window is closed and its surface is unmapped. This event will be sent immediately after all initial state been sent to the client. If the Plasma window is already unmapped, the unmapped event will be sent before the initial_state event. This event will be sent whenever the parent window of this ukui_window changes. The passed parent is another ukui_window and this ukui_window is a transient window to the parent window. If the parent argument is null, this ukui_window does not have a parent window. This event will be sent whenever the window geometry of this ukui_window changes. The coordinates are in absolute coordinates of the windowing system. This event will be sent whenever the icon of the window changes, but there is no themed icon name. Common examples are Xwayland windows which have a pixmap based icon. The client can request the icon using get_icon. This event will be sent when the compositor has set the process id this window belongs to. This should be set once before the initial_state is sent. Make the window enter a virtual desktop. A window can enter more than one virtual desktop. if the id is empty or invalid, no action will be performed. RFC: do this with an empty id to request_enter_virtual_desktop? Make the window enter a new virtual desktop. If the server consents the request, it will create a new virtual desktop and assign the window to it. Make the window exit a virtual desktop. If it exits all desktops it will be considered on all of them. This event will be sent when the window has entered a new virtual desktop. The window can be on more than one desktop, or none: then is considered on all of them. This event will be sent when the window left a virtual desktop. If the window leaves all desktops, it can be considered on all. If the window gets manually added on all desktops, the server has to send virtual_desktop_left for every previous desktop it was in for the window to be really considered on all desktops. This event will be sent after the application menu for the window has changed. Make the window enter an activity. A window can enter more activity. If the id is empty or invalid, no action will be performed. Make the window exit a an activity. If it exits all activities it will be considered on all of them. This event will be sent when the window has entered an activity. The window can be on more than one activity, or none: then is considered on all of them. This event will be sent when the window left an activity. If the window leaves all activities, it will be considered on all. If the window gets manually added on all activities, the server has to send activity_left for every previous activity it was in for the window to be really considered on all activities. Requests this window to be displayed in a specific output. This event will be sent when the X11 resource name of the window has changed. This is only set for XWayland windows. Tell the compositor to highlight this window. Tell the compositor to unset highlight window. The activation manager interface provides a way to get notified when an application is about to be activated. Destroy the activation manager object. The activation objects introduced by this manager object will be unaffected. Will be issued when an app is set to be activated. It offers an instance of org_ukui_activation that will tell us the app_id and the extent of the activation. Notify the compositor that the org_ukui_activation object will no longer be used. libkysdk-applications/kysdk-waylandhelper/protocols/plasma-window-management.xml0000664000175000017500000004330515104543305027431 0ustar fengfeng This interface manages application windows. It provides requests to show and hide the desktop and emits an event every time a window is created so that the client can use it to manage the window. Only one client can bind this interface at a time. Tell the compositor to show/hide the desktop. Deprecated: use get_window_by_uuid This event will be sent whenever the show desktop mode changes. E.g. when it is entered or left. On binding the interface the current state is sent. This event will be sent immediately after a window is mapped. This event will be sent when stacking order changed and on bind This event will be sent when stacking order changed and on bind This event will be sent immediately after a window is mapped. Manages and control an application window. Only one client can bind this interface at a time. Set window state. Values for state argument are described by org_kde_plasma_window_management.state and can be used together in a bitfield. The flags bitfield describes which flags are supposed to be set, the state bitfield the value for the set flags Deprecated: use enter_virtual_desktop Maps the window to a different virtual desktop. To show the window on all virtual desktops, call the org_kde_plasma_window.set_state request and specify a on_all_desktops state in the bitfield. Sets the geometry of the taskbar entry for this window. The geometry is relative to a panel in particular. Remove the task geometry information for a particular panel. Close this window. Request an interactive move for this window. Request an interactive resize for this window. Removes the resource bound for this org_kde_plasma_window. The compositor will write the window icon into the provided file descriptor. The data is a serialized QIcon with QDataStream. This event will be sent as soon as the window title is changed. This event will be sent as soon as the application identifier is changed. This event will be sent as soon as the window state changes. Values for state argument are described by org_kde_plasma_window_management.state. DEPRECATED: use virtual_desktop_entered and virtual_desktop_left instead This event will be sent when a window is moved to another virtual desktop. It is not sent if it becomes visible on all virtual desktops though. This event will be sent whenever the themed icon name changes. May be null. This event will be sent immediately after the window is closed and its surface is unmapped. This event will be sent immediately after all initial state been sent to the client. If the Plasma window is already unmapped, the unmapped event will be sent before the initial_state event. This event will be sent whenever the parent window of this org_kde_plasma_window changes. The passed parent is another org_kde_plasma_window and this org_kde_plasma_window is a transient window to the parent window. If the parent argument is null, this org_kde_plasma_window does not have a parent window. This event will be sent whenever the window geometry of this org_kde_plasma_window changes. The coordinates are in absolute coordinates of the windowing system. This event will be sent whenever the icon of the window changes, but there is no themed icon name. Common examples are Xwayland windows which have a pixmap based icon. The client can request the icon using get_icon. This event will be sent when the compositor has set the process id this window belongs to. This should be set once before the initial_state is sent. Make the window enter a virtual desktop. A window can enter more than one virtual desktop. if the id is empty or invalid, no action will be performed. RFC: do this with an empty id to request_enter_virtual_desktop? Make the window enter a new virtual desktop. If the server consents the request, it will create a new virtual desktop and assign the window to it. Make the window exit a virtual desktop. If it exits all desktops it will be considered on all of them. This event will be sent when the window has entered a new virtual desktop. The window can be on more than one desktop, or none: then is considered on all of them. This event will be sent when the window left a virtual desktop. If the window leaves all desktops, it can be considered on all. If the window gets manually added on all desktops, the server has to send virtual_desktop_left for every previous desktop it was in for the window to be really considered on all desktops. This event will be sent after the application menu for the window has changed. Make the window enter an activity. A window can enter more activity. If the id is empty or invalid, no action will be performed. Make the window exit a an activity. If it exits all activities it will be considered on all of them. This event will be sent when the window has entered an activity. The window can be on more than one activity, or none: then is considered on all of them. This event will be sent when the window left an activity. If the window leaves all activities, it will be considered on all. If the window gets manually added on all activities, the server has to send activity_left for every previous activity it was in for the window to be really considered on all activities. Requests this window to be displayed in a specific output. The activation manager interface provides a way to get notified when an application is about to be activated. Destroy the activation manager object. The activation objects introduced by this manager object will be unaffected. Will be issued when an app is set to be activated. It offers an instance of org_kde_plasma_activation that will tell us the app_id and the extent of the activation. Notify the compositor that the org_kde_plasma_activation object will no longer be used. libkysdk-applications/kysdk-waylandhelper/protocols/ukui-shell-v1.xml0000664000175000017500000003477115155674255025171 0ustar fengfeng This interface is used by UKUI Wayland shells to communicate with the compositor and can only be bound one time. Create a shell surface for an existing surface. Only one shell surface can be associated with a given surface. Should create ukui_surface_v1 before create xdg_surface and surface map. Request get the output under cursor per seat. Send current_output and done event after this request. Create a shell decoration for an existing surface. Only one shell decoration can be associated with a given surface. This request needs be called before surface map. Emitted after bind ukui_shell or receive get_current_output request. This event is sent after all information have been sent on binding to the ukui shell object. An interface that may be implemented by a wl_surface, for implementations that provide the shell user interface. It provides requests to set surface roles, state or set the position in global coordinates. On the server side the object is automatically destroyed when the related wl_surface is destroyed. On client side, ukui_surface_v1.destroy() must be called before destroying the wl_surface object. The ukui_surface_v1 interface is removed from the wl_surface object that was turned into a shell surface with the ukui_shell_v1.get_surface request. Move the surface to new coordinates. Coordinates are global. Setting this will say the surface prefers to not be listed in the taskbar. This request needs be called before surface map. Setting this will say the surface prefers to not be listed in the switcher. This request needs be called before surface map. Assign a role to a shell surface. The compositor handles surfaces depending on their role. This request needs be called before surface map. Set surface state. Can set multiple states at once. Values for state argument are described by ukui_surface.state and can be used together in a bitfield. The flags bitfield describes which flags are supposed to be set, the state bitfield the value for the set flags. The state argument is not a boolean value, but a bitfield, so it is possible to set multiple states at once. Only the states that are set in the flags bitfield will be changed. The keep_above and keep_below can only used for the normal window. For example: If flags was 0x12(movable|maximizable) and state was 0x02(maximizable), the window would be maximizable, but not movable. Setting this bit will indicate that the panel area not to be calculate in output usable area. Request the initial position of this surface to be under the current cursor position. This request needs be called before surface map. This request makes the created surface take an explicit keyboard grab. This keyboard grab will be dismissed when the client destroys the surface. Grab all keyboard when seat is set to null. Setting server decoration icon by icon name. Set icon name to null will use app_id to find icon. This request needs be called before surface map. This event informs the client that the position of the surface is about to change. This request makes the created surface to be activated. There is no guarantee the surface will be actually activated, and behaviour may be compositor-dependentption. Sets the startup geometry of the taskbar/desktop entry for this surface. Coordinates are global. One established way of doing this is through the UKUI_SURFACE_STARTUP_GEOMETRY environment variable of a newly launched child process. The child process should unset the environment variable again right after reading it out in order to avoid propagating it to other child processes. This request needs be called before surface map. This request is for showing tile flyout on the client side decoration. The parameters represent a mouse region, tile flyout will autohide when mouse leave the region. Coordinates are relative to the surface. Use default seat when seat is set to null. This request needs be called after surface map. This event will be sent as soon as the surface state changes. Values for state argument are described by ukui_surface_v1.surface_state. It contains the whole new state of the window. Set the restore geometry for this surface. The restore geometry is used for window doing restore from maximized/fullscreen state. Coordinates are global. Move the surface to new coordinates. Coordinates are global. The position will be applied on the next wl_surface.commit. It provides requests to set surface need to draw corner/shadow/border or not. On the server side the object is automatically destroyed when the related wl_surface is destroyed. On client side, ukui_decoration_v1.destroy() must be called before destroying the wl_surface object. Setting this will say the surface prefers not to show titlebar. This request needs be called before surface map. The flags bitfield describes which components of decoration are supposed to be set and can be set together in a bitfield. Draw decoration will be based on the flags. This flags needs be called before surface map and become immutable when surface is mapped. This request is only for xdg_popup now. libkysdk-applications/kysdk-waylandhelper/protocols/virtual-keyboard-unstable-v1.xml0000664000175000017500000001142615104543305030157 0ustar fengfeng Copyright © 2008-2011 Kristian Høgsberg Copyright © 2010-2013 Intel Corporation Copyright © 2012-2013 Collabora, Ltd. Copyright © 2018 Purism SPC Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice (including the next paragraph) shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. The virtual keyboard provides an application with requests which emulate the behaviour of a physical keyboard. This interface can be used by clients on its own to provide raw input events, or it can accompany the input method protocol. Provide a file descriptor to the compositor which can be memory-mapped to provide a keyboard mapping description. Format carries a value from the keymap_format enumeration. A key was pressed or released. The time argument is a timestamp with millisecond granularity, with an undefined base. All requests regarding a single object must share the same clock. Keymap must be set before issuing this request. State carries a value from the key_state enumeration. Notifies the compositor that the modifier and/or group state has changed, and it should update state. The client should use wl_keyboard.modifiers event to synchronize its internal state with seat state. Keymap must be set before issuing this request. A virtual keyboard manager allows an application to provide keyboard input events as if they came from a physical keyboard. Creates a new virtual keyboard associated to a seat. If the compositor enables a keyboard to perform arbitrary actions, it should present an error when an untrusted client requests a new keyboard. libkysdk-applications/kysdk-waylandhelper/protocols/xdg-activation-v1.xml0000664000175000017500000002147015104543305026001 0ustar fengfeng Copyright © 2020 Aleix Pol Gonzalez <aleixpol@kde.org> Copyright © 2020 Carlos Garnacho <carlosg@gnome.org> Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice (including the next paragraph) shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. The way for a client to pass focus to another toplevel is as follows. The client that intends to activate another toplevel uses the xdg_activation_v1.get_activation_token request to get an activation token. This token is then forwarded to the client, which is supposed to activate one of its surfaces, through a separate band of communication. One established way of doing this is through the XDG_ACTIVATION_TOKEN environment variable of a newly launched child process. The child process should unset the environment variable again right after reading it out in order to avoid propagating it to other child processes. Another established way exists for Applications implementing the D-Bus interface org.freedesktop.Application, which should get their token under activation-token on their platform_data. In general activation tokens may be transferred across clients through means not described in this protocol. The client to be activated will then pass the token it received to the xdg_activation_v1.activate request. The compositor can then use this token to decide how to react to the activation request. The token the activating client gets may be ineffective either already at the time it receives it, for example if it was not focused, for focus stealing prevention. The activating client will have no way to discover the validity of the token, and may still forward it to the to be activated client. The created activation token may optionally get information attached to it that can be used by the compositor to identify the application that we intend to activate. This can for example be used to display a visual hint about what application is being started. Warning! The protocol described in this file is currently in the testing phase. Backward compatible changes may be added together with the corresponding interface version bump. Backward incompatible changes can only be done by creating a new major version of the extension. A global interface used for informing the compositor about applications being activated or started, or for applications to request to be activated. Notify the compositor that the xdg_activation object will no longer be used. The child objects created via this interface are unaffected and should be destroyed separately. Creates an xdg_activation_token_v1 object that will provide the initiating client with a unique token for this activation. This token should be offered to the clients to be activated. Requests surface activation. It's up to the compositor to display this information as desired, for example by placing the surface above the rest. The compositor may know who requested this by checking the activation token and might decide not to follow through with the activation if it's considered unwanted. Compositors can ignore unknown activation tokens when an invalid token is passed. An object for setting up a token and receiving a token handle that can be passed as an activation token to another client. The object is created using the xdg_activation_v1.get_activation_token request. This object should then be populated with the app_id, surface and serial information and committed. The compositor shall then issue a done event with the token. In case the request's parameters are invalid, the compositor will provide an invalid token. Provides information about the seat and serial event that requested the token. The serial can come from an input or focus event. For instance, if a click triggers the launch of a third-party client, the launcher client should send a set_serial request with the serial and seat from the wl_pointer.button event. Some compositors might refuse to activate toplevels when the token doesn't have a valid and recent enough event serial. Must be sent before commit. This information is optional. The requesting client can specify an app_id to associate the token being created with it. Must be sent before commit. This information is optional. This request sets the surface requesting the activation. Note, this is different from the surface that will be activated. Some compositors might refuse to activate toplevels when the token doesn't have a requesting surface. Must be sent before commit. This information is optional. Requests an activation token based on the different parameters that have been offered through set_serial, set_surface and set_app_id. The 'done' event contains the unique token of this activation request and notifies that the provider is done. Notify the compositor that the xdg_activation_token_v1 object will no longer be used. The received token stays valid. libkysdk-applications/kysdk-waylandhelper/protocols/ukui-blur-v1.xml0000664000175000017500000000726315104543305025003 0ustar fengfeng This protocol provides a way to improve visuals of translucent surfaces by blurring background behind them. Warning! The protocol described in this file is currently in the testing phase. Backward compatible changes may be added together with the corresponding interface version bump. Backward incompatible changes can only be done by creating a new major version of the extension. Informs the server that the client will no longer be using this protocol object. Existing objects created by this object are not affected. Instantiate an interface extension for the given wl_surface to blur background behind it. If the given wl_surface already has a ukui_blur_surface_v1 object associated, the blur_exists protocol error will be raised. The blur object provides a way to specify a region behind a surface that should be blurred by the compositor. If the wl_surface associated with the ukui_blur_surface_v1 object has been destroyed, this object becomes inert. Informs the server that the client will no longer be using this protocol object. The blur region will be unset on the next commit. This request sets the region of the surface that will have its background blurred. The blur region is specified in the surface-local coordinates. The initial value for the blur region is empty. Setting the pending blur region has copy semantics, and the wl_region object can be destroyed immediately. A NULL wl_region causes the blur region to be set to infinite. The blur region is double-buffered state, and will be applied on the next wl_surface.commit. The blur algorithm is subject to compositor policies. Change blur algorithm level in compositor. The range of level is 1 to 15. The compositor default blur algorithm level is 5. The blur level will be applied on the next wl_surface.commit. libkysdk-applications/kysdk-waylandhelper/protocols/keystate.xml0000664000175000017500000000261715104543305024367 0ustar fengfeng SPDX-License-Identifier: LGPL-2.1-or-later ]]> Keeps track of the states of the different keys that have a state attached to it. libkysdk-applications/kysdk-waylandhelper/protocols/ukui-shell.xml0000664000175000017500000002230215104543305024611 0ustar fengfeng This interface is used by kylin powered Wayland shells to communicate with the compositor and can only be bound one time. Create a shell surface for an existing surface. Only one shell surface can be associated with a given surface. Request get the output under cursor. Send current_output and done event after this request. Emitted after bind ukui_shell or receive get_current_output request. This event is sent after all information has been sent after binding to the ukui shell object. An interface that may be implemented by a wl_surface, for implementations that provide the shell user interface. It provides requests to set surface roles, assign an output or set the position in output coordinates. On the server side the object is automatically destroyed when the related wl_surface is destroyed. On client side, ukui_surface.destroy() must be called before destroying the wl_surface object. The ukui_surface interface is removed from the wl_surface object that was turned into a shell surface with the ukui_shell.get_surface request. The shell surface role is lost and wl_surface is unmapped. Assign an output to this shell surface. The compositor will use this information to set the position when ukui_surface.set_position request is called. Move the surface to new coordinates. Coordinates are global, for example 50,50 for a 1920,0+1920x1080 output is 1970,50 in global coordinates space. Setting this bit to the window, will make it say it prefers to not be listed in the taskbar. Taskbar implementations may or may not follow this hint. Setting this bit will indicate that the window prefers not to be listed in a switcher. Set window property. Values for property argument are described by ukui_shell.property and can be used together in a bitfield. The flags bitfield describes which property are supposed to be set. Assign a role to a shell surface. The compositor handles surfaces depending on their role. See the explanation below. This request fails if the surface already has a role, this means the surface role may be assigned only once. Setting this bit will indicate that the panel area not to be calculate in output usable area. Request the initial position of this surface to be under the current cursor position. Has to be called before attaching any buffer to this surface. By default various ukui_surface roles do not take focus and cannot be activated. With this request the compositor can be instructed to pass focus also to this ukui_surface. This request makes the created surface take an explicit keyboard grab. This keyboard grab will be dismissed when the client destroys the surface. Grab all keyboard when seat is set to null. Setting server decoration icon by icon name. Set icon name to null will use app_id to find icon. This event informs the client that the position of the window is about to change. This request makes the created surface to be activated. There is no guarantee the surface will be actually activated, and behaviour may be compositor-dependentption. libkysdk-applications/kysdk-waylandhelper/protocols/ukui-startup-v2.xml0000664000175000017500000000440415104543305025534 0ustar fengfeng This interface manages startup infos. The startup_info object provides a way sets the startup geometry of the taskbar/desktop entry for app. The object will auto destroy when arrive the retire time. Sets the startup geometry of the taskbar/desktop entry. Coordinates are global. The pid determines which process will use the startup_geometry. The child process of this process will also use the startup_geometry. The appid determines which app should use the startup_geometry. It only uses when not set pid or not find the app from pid. Must call destroy after set info completely. libkysdk-applications/kysdk-waylandhelper/protocols/ext-idle-notify-v1.xml0000664000175000017500000001065215104543305026101 0ustar fengfeng Copyright © 2015 Martin Gräßlin Copyright © 2022 Simon Ser Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice (including the next paragraph) shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. This interface allows clients to monitor user idle status. After binding to this global, clients can create ext_idle_notification_v1 objects to get notified when the user is idle for a given amount of time. Destroy the manager object. All objects created via this interface remain valid. Create a new idle notification object. The notification object has a minimum timeout duration and is tied to a seat. The client will be notified if the seat is inactive for at least the provided timeout. See ext_idle_notification_v1 for more details. A zero timeout is valid and means the client wants to be notified as soon as possible when the seat is inactive. This interface is used by the compositor to send idle notification events to clients. Initially the notification object is not idle. The notification object becomes idle when no user activity has happened for at least the timeout duration, starting from the creation of the notification object. User activity may include input events or a presence sensor, but is compositor-specific. If an idle inhibitor is active (e.g. another client has created a zwp_idle_inhibitor_v1 on a visible surface), the compositor must not make the notification object idle. When the notification object becomes idle, an idled event is sent. When user activity starts again, the notification object stops being idle, a resumed event is sent and the timeout is restarted. Destroy the notification object. This event is sent when the notification object becomes idle. It's a compositor protocol error to send this event twice without a resumed event in-between. This event is sent when the notification object stops being idle. It's a compositor protocol error to send this event twice without an idled event in-between. It's a compositor protocol error to send this event prior to any idled event. libkysdk-applications/kysdk-waylandhelper/protocols/plasma-shell.xml0000664000175000017500000003007415155674255025135 0ustar fengfeng This interface is used by KF5 powered Wayland shells to communicate with the compositor and can only be bound one time. Warning! The protocol described in this file is a desktop environment implementation detail. Regular clients must not use this protocol. Backward incompatible changes may be added without bumping the major version of the extension. Create a shell surface for an existing surface. Only one shell surface can be associated with a given surface. An interface that may be implemented by a wl_surface, for implementations that provide the shell user interface. It provides requests to set surface roles, assign an output or set the position in output coordinates. On the server side the object is automatically destroyed when the related wl_surface is destroyed. On client side, org_kde_plasma_surface.destroy() must be called before destroying the wl_surface object. The org_kde_plasma_surface interface is removed from the wl_surface object that was turned into a shell surface with the org_kde_plasma_shell.get_surface request. The shell surface role is lost and wl_surface is unmapped. Assign an output to this shell surface. The compositor will use this information to set the position when org_kde_plasma_surface.set_position request is called. Move the surface to new coordinates. Coordinates are global, for example 50,50 for a 1920,0+1920x1080 output is 1970,50 in global coordinates space. Use org_kde_plasma_surface.set_output to assign an output to this surface. Assign a role to a shell surface. The compositor handles surfaces depending on their role. See the explanation below. This request fails if the surface already has a role, this means the surface role may be assigned only once. == Surfaces with splash role == Splash surfaces are placed above every other surface during the shell startup phase. The surfaces are placed according to the output coordinates. No size is imposed to those surfaces, the shell has to resize them according to output size. These surfaces are meant to hide the desktop during the startup phase so that the user will always see a ready to work desktop. A shell might not create splash surfaces if the compositor reveals the desktop in an alternative fashion, for example with a fade in effect. That depends on how much time the desktop usually need to prepare the workspace or specific design decisions. This specification doesn't impose any particular design. When the startup phase is finished, the shell will send the org_kde_plasma.desktop_ready request to the compositor. == Surfaces with desktop role == Desktop surfaces are placed below all other surfaces and are used to show the actual desktop view with icons, search results or controls the user will interact with. What to show depends on the shell implementation. The surfaces are placed according to the output coordinates. No size is imposed to those surfaces, the shell has to resize them according to output size. Only one surface per output can have the desktop role. == Surfaces with dashboard role == Dashboard surfaces are placed above desktop surfaces and are used to show additional widgets and controls. The surfaces are placed according to the output coordinates. No size is imposed to those surfaces, the shell has to resize them according to output size. Only one surface per output can have the dashboard role. == Surfaces with config role == A configuration surface is shown when the user wants to configure panel or desktop views. Only one surface per output can have the config role. TODO: This should grab the input like popup menus, right? == Surfaces with overlay role == Overlays are special surfaces that shows for a limited amount of time. Such surfaces are useful to display things like volume, brightness and status changes. Compositors may decide to show those surfaces in a layer above all surfaces, even full screen ones if so is desired. == Surfaces with notification role == Notification surfaces display informative content for a limited amount of time. The compositor may decide to show them in a corner depending on the configuration. These surfaces are shown in a layer above all other surfaces except for full screen ones. == Surfaces with lock role == The lock surface is shown by the compositor when the session is locked, users interact with it to unlock the session. Compositors should move lock surfaces to 0,0 in output coordinates space and hide all other surfaces for security sake. For the same reason it is recommended that clients make the lock surface as big as the screen. Only one surface per output can have the lock role. The panel is on top of other surfaces, windows cannot cover (full screen windows excluded). The panel is hidden automatically and restored when the mouse is over. Windows can cover the panel. Maximized windows take the whole screen space but the panel is above the windows. Set flags bitmask as described by the flag enum. Pass 0 to unset any flag, the surface will adjust its behavior to the default. Deprecated in Plasma 6. Setting this flag will have no effect. Applications should use layer shell where appropriate. Setting this bit to the window, will make it say it prefers to not be listed in the taskbar. Taskbar implementations may or may not follow this hint. A panel surface with panel_behavior auto_hide can perform this request to hide the panel on a screen edge without unmapping it. The compositor informs the client about the panel being hidden with the event auto_hidden_panel_hidden. The compositor will restore the visibility state of the surface when the pointer touches the screen edge the panel borders. Once the compositor restores the visibility the event auto_hidden_panel_shown will be sent. This event will also be sent if the compositor is unable to hide the panel. The client can also request to show the panel again with the request panel_auto_hide_show. A panel surface with panel_behavior auto_hide can perform this request to show the panel again which got hidden with panel_auto_hide_hide. By default various org_kde_plasma_surface roles do not take focus and cannot be activated. With this request the compositor can be instructed to pass focus also to this org_kde_plasma_surface. An auto-hiding panel got hidden by the compositor. An auto-hiding panel got shown by the compositor. Setting this bit will indicate that the window prefers not to be listed in a switcher. Request the initial position of this surface to be under the current cursor position. Has to be called before attaching any buffer to this surface. libkysdk-applications/kysdk-waylandhelper/protocols/kywc-capture-v1.xml0000664000175000017500000001671015104543305025477 0ustar fengfeng This object is a manager which offers requests to start capturing from a source. Capture the next frame of an entire output. Capture the next frame of an entire workspace in one output. Capture the next frame of an entire toplevel. Capture the cursor of the seat and frame. All objects created by the manager will still remain valid, until their appropriate destroy request has been called. Destroys the frame. This request can be sent at any time by the client. This event indicates that the attempted frame copy has failed. After receiving this event, the client should destroy the object. Sent if the compositor cancels the frame because the source has gone. Upon receiving this event, the client should destroy this object. Provides information about buffer parameters that need to be used for this frame. Mark the buffer is not used by client. This request is sent after buffer event. Provides information about buffer parameters with the plane index that need to be used for this frame. When the seat or frame is destroyed, this object becomes inert. Destroys the object. This request can be sent at any time by the client. This event indicates that when a cursor enters the frame. It shall be generated before the "position" and "hotspot" events. If the pointer object referenced by the seat does not exist, this event will not be triggered. This event indicates that when a cursor leaves the frame. No "position" or "hotspot" event is generated for the cursor until the cursor enters the frame again. If the pointer object referenced by the seat is removed, this event will be sent. This event informs the cursor position. The given position is relative to the frame's top left corner in transformed buffer pixel coordinates. Note, if the frame parameter is set to null in the capture_cursor request, the given position coordinates are global. This event informs the cursor hotspot. The hotspot describes the offset between the cursor image and the position of the input device. The parameters x and y represent the offset of the new hotspot relative to the origin of the cursor image, which is typically the top-left corner of the image. libkysdk-applications/kysdk-waylandhelper/protocols/ukui-startup-v1.xml0000664000175000017500000000175615104543305025542 0ustar fengfeng This interface is a manager that allows to set app startup info. Sets the startup geometry of the taskbar/desktop entry for app. Coordinates are global. libkysdk-applications/kysdk-waylandhelper/test/0000775000175000017500000000000015104543305020741 5ustar fengfenglibkysdk-applications/kysdk-waylandhelper/test/testWindowManager/0000775000175000017500000000000015104543305024403 5ustar fengfenglibkysdk-applications/kysdk-waylandhelper/test/testWindowManager/widget.h0000664000175000017500000000567315104543305026052 0ustar fengfeng/* * * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #ifndef WIDGET_H #define WIDGET_H #include "windowmanager/windowmanager.h" #include #include #include #include #include #include #include using namespace kdk; class QSpinBox; class QComboBox; class Widget : public QWidget { Q_OBJECT public: Widget(QWidget *parent = nullptr); ~Widget(); void initUI(); void initConnection(); private: QLabel *m_label; QWidget *m_subWidget; QPushButton *m_btnMinimize; QPushButton *m_btnMaximum; QPushButton *m_btnActivate; QPushButton *m_btnStayOnTop; QPushButton *m_btnClose; QPushButton *m_btnShowDesktop; QPushButton *m_btnChangeIcon; QPushButton *m_btnChangeTitle; QPushButton *m_btnShowGroup; QPushButton *m_shwWdgbtn; QPushButton *m_shwWindowTitle; QPushButton *m_shwWindowIcon; QPushButton *m_btnprintList; QPushButton *m_btnSetGeometry; QPushButton *m_btnGetType; QComboBox *m_setTypeBox; kdk::WindowManager *m_manager; QSpinBox *m_posX; QSpinBox *m_posY; QSpinBox *m_width; QSpinBox *m_height; QTimer *m_timer; WindowId m_lastestWindowId; QPushButton *m_skipTaskbarBtn; QPushButton *m_skipSwitcherBtn; QPushButton *m_showOnAllDesktop; QPushButton *m_isDesktopShowing; QPushButton *m_isOnCurrentDesktop; QPushButton *m_btnPanelWidget; QCheckBox *m_chbPanel; bool m_isPanelShown; QWidget *m_panelWidget; QPushButton *m_demandBtn; QPushButton *m_fullscreenBtn; QPushButton *m_processName; QPushButton *m_getGeometryBtn; QPushButton *m_setGrabKeyboardBtn; QPushButton *m_setSwitcherLayer; QPushButton *m_setHighlightBtn; QPushButton *m_unsetHighlightBtn; QPushButton *m_openUnderCursorBtn; QPushButton *m_openUnderCursorWithOffsetBtn; QSpinBox *m_xOffset; QSpinBox *m_yOffset; QPushButton *m_setIconNameBtn; QPushButton *m_unsetIconNameBtn; QPushButton *m_getCurrentOutputBtn; QPushButton *m_getOutputsInfoBtn; QPushButton *m_getWindowIdByTitleBtn; QLineEdit *m_getWindowIdByTitleEdit; QPushButton *m_getWindowIdByPidBtn; QLineEdit *m_getWindowIdByPidEdit; }; #endif // WIDGET_H libkysdk-applications/kysdk-waylandhelper/test/testWindowManager/testWindowManager.pro0000664000175000017500000000177015104543305030574 0ustar fengfengQT += core gui greaterThan(QT_MAJOR_VERSION, 4): QT += widgets CONFIG += c++17 link_pkgconfig PKGCONFIG += KF6WindowSystem kysdk-waylandhelper # The following define makes your compiler emit warnings if you use # any Qt feature that has been marked deprecated (the exact warnings # depend on your compiler). Please consult the documentation of the # deprecated API in order to know how to port your code away from it. DEFINES += QT_DEPRECATED_WARNINGS # You can also make your code fail to compile if it uses deprecated APIs. # In order to do so, uncomment the following line. # You can also select to disable deprecated APIs only up to a certain version of Qt. #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 SOURCES += \ main.cpp \ widget.cpp HEADERS += \ widget.h # Default rules for deployment. qnx: target.path = /tmp/$${TARGET}/bin else: unix:!android: target.path = /opt/$${TARGET}/bin !isEmpty(target.path): INSTALLS += target libkysdk-applications/kysdk-waylandhelper/test/testWindowManager/widget.cpp0000664000175000017500000006422215104543305026400 0ustar fengfeng/* * * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #include "widget.h" #include #include #include #include #include #include #include #include #include using namespace kdk; Widget::Widget(QWidget *parent) : QWidget(parent) , m_subWidget(nullptr) { m_timer = new QTimer(this); m_timer->setInterval(2000); setWindowTitle("windowtitle"); connect(WindowManager::self(), &WindowManager::outputInfoChanged, this, [=](OutputInfo *info) { qDebug() << "output info changed!name:" << info->outputName() << " usablearea:" << info->usableArea(); }); connect(WindowManager::self(), &WindowManager::iconChanged, this, [=](const WindowId &windowId) { if (m_lastestWindowId == windowId) qDebug() << "icon changed"; }); connect(WindowManager::self(), &WindowManager::maximizedChanged, this, [=](const WindowId &windowId) { if (m_lastestWindowId == windowId) qDebug() << "maximizedChanged"; }); connect(WindowManager::self(), &WindowManager::minimizedChanged, this, [=](const WindowId &windowId) { if (m_lastestWindowId == windowId) qDebug() << "minimizedChanged"; }); connect(WindowManager::self(), &WindowManager::fullscreenChanged, this, [=](const WindowId &windowId) { if (m_lastestWindowId == windowId) qDebug() << "fullscreenChanged"; }); connect(WindowManager::self(), &WindowManager::keepAboveChanged, this, [=](const WindowId &windowId) { if (m_lastestWindowId == windowId) qDebug() << "keepAboveChanged"; }); connect(WindowManager::self(), &WindowManager::skipSwitcherChanged, this, [=](const WindowId &windowId) { if (m_lastestWindowId == windowId) qDebug() << "skipSwitcherChanged"; }); connect(WindowManager::self(), &WindowManager::skipTaskbarChanged, this, [=](const WindowId &windowId) { if (m_lastestWindowId == windowId) qDebug() << "skipTaskbarChanged"; }); connect(WindowManager::self(), &WindowManager::activeChanged, this, [=](const WindowId &windowId) { if (m_lastestWindowId == windowId) qDebug() << "activeChanged"; }); connect(WindowManager::self(), &WindowManager::titleChanged, this, [=](const WindowId &windowId) { if (m_lastestWindowId == windowId) qDebug() << "titleChanged"; }); connect(WindowManager::self(), &WindowManager::geometryChanged, this, [=](const WindowId &windowId) { // if(m_lastestWindowId == windowId) // qDebug() << "geometryChanged"; }); connect(WindowManager::self(), &WindowManager::demandsAttentionChanged, this, [=](const WindowId &windowId) { if (m_lastestWindowId == windowId) qDebug() << "demandsAttentionChanged"; }); connect(WindowManager::self(), &WindowManager::onAllDesktopsChanged, this, [=](const WindowId &windowId) { if (m_lastestWindowId == windowId) qDebug() << "jnihbj,bhmjbhgbhmvgv"; }); connect(WindowManager::self(), &WindowManager::windowAdded, this, [=](const WindowId &windowId) { /*注意: * 最新创建的窗体被设置为操作窗体,此demo中每个按钮对应一个接口函数调用,所有接口函数操作的窗口都是该最新创建的窗体 */ // qDebug()<<"窗口添加:"<setText("注意:最新创建的窗体被设置为操作窗体,此demo中每个按钮对应一个接口函数调用,所有接口函数操作的窗口都是该最新创建的窗体"); m_btnMinimize = new QPushButton("最小化窗口", this); m_btnMaximum = new QPushButton("最大化窗口", this); m_btnActivate = new QPushButton("激活窗口", this); m_btnStayOnTop = new QPushButton("置顶窗口", this); m_btnClose = new QPushButton("关闭窗口", this); m_btnShowDesktop = new QPushButton("显示桌面", this); m_shwWindowTitle = new QPushButton("获取窗口标题", this); m_shwWindowIcon = new QPushButton("获取窗口图标", this); m_btnShowGroup = new QPushButton("获取窗口所属组", this); m_btnprintList = new QPushButton("获取窗口列表", this); m_btnSetGeometry = new QPushButton("设置窗口大小", this); hLayout1->addWidget(m_btnMinimize); hLayout1->addWidget(m_btnMaximum); hLayout1->addWidget(m_btnActivate); hLayout1->addWidget(m_btnStayOnTop); hLayout1->addWidget(m_btnClose); QLabel *label = new QLabel(this); label->setText("依次输入起点x,起点y,宽度w,高度h"); m_posX = new QSpinBox(this); m_posY = new QSpinBox(this); m_width = new QSpinBox(this); m_height = new QSpinBox(this); m_posX->setRange(0, 2000); m_posY->setRange(0, 2000); m_width->setRange(1, 2000); m_height->setRange(1, 2000); m_posX->setValue(0); m_posY->setValue(0); m_width->setValue(800); m_height->setValue(600); QHBoxLayout *hLayout5 = new QHBoxLayout; hLayout5->addWidget(m_posX); hLayout5->addWidget(m_posY); hLayout5->addWidget(m_width); hLayout5->addWidget(m_height); QHBoxLayout *hLayout2 = new QHBoxLayout(); m_shwWdgbtn = new QPushButton("打开测试窗口", this); hLayout2->addWidget(m_shwWdgbtn); hLayout2->addWidget(m_btnSetGeometry); hLayout2->addWidget(new QLabel("设置窗口类型", this)); m_setTypeBox = new QComboBox(this); QStringList l; l << "Widget" << "Window" << "Dialog" << "Sheet" << "Drawer" << "Popup" << "Tool" << "ToolTip" << "SplashScreen" << "Desktop" << "SubWindow" << "ForeignWindow" << "CoverWindow"; m_setTypeBox->addItems(l); hLayout2->addWidget(m_setTypeBox); QHBoxLayout *hLayout4 = new QHBoxLayout(); hLayout4->addWidget(m_btnShowDesktop); hLayout4->addWidget(m_shwWindowTitle); hLayout4->addWidget(m_shwWindowIcon); hLayout4->addWidget(m_btnShowGroup); hLayout4->addWidget(m_btnprintList); QHBoxLayout *hLayout3 = new QHBoxLayout(); m_btnChangeIcon = new QPushButton("更改图标", this); m_btnChangeTitle = new QPushButton("更改标题", this); m_btnGetType = new QPushButton("获取窗口类型", this); hLayout3->addWidget(m_btnChangeIcon); hLayout3->addWidget(m_btnChangeTitle); hLayout3->addWidget(m_btnGetType); QGroupBox *box2 = new QGroupBox("2.0需求接口", this); QHBoxLayout *hLayout6 = new QHBoxLayout(); m_skipTaskbarBtn = new QPushButton("跳过任务栏", this); m_skipSwitcherBtn = new QPushButton("跳过窗口选择器", this); hLayout6->addWidget(m_skipTaskbarBtn); hLayout6->addWidget(m_skipSwitcherBtn); QHBoxLayout *hLayout7 = new QHBoxLayout(); m_showOnAllDesktop = new QPushButton("在所有桌面中显示", this); m_isDesktopShowing = new QPushButton("获取桌面是否处于显示状态", this); hLayout7->addWidget(m_showOnAllDesktop); hLayout7->addWidget(m_isDesktopShowing); QVBoxLayout *vlayout = new QVBoxLayout(); vlayout->addLayout(hLayout6); vlayout->addLayout(hLayout7); box2->setLayout(vlayout); QGroupBox *box3 = new QGroupBox("2.1需求接口", this); QVBoxLayout *vLayout = new QVBoxLayout(); QHBoxLayout *hLayout8 = new QHBoxLayout(); m_isOnCurrentDesktop = new QPushButton("被测窗体是否在当前桌面", this); hLayout8->addStretch(); hLayout8->addWidget(m_isOnCurrentDesktop); vLayout->addLayout(hLayout8); box3->setLayout(vLayout); QGroupBox *box4 = new QGroupBox("2.3需求接口", this); m_btnPanelWidget = new QPushButton("显示panel窗口", this); m_chbPanel = new QCheckBox(this); m_chbPanel->setText("设置panel窗体获取焦点"); QVBoxLayout *vLayout2 = new QVBoxLayout(); QHBoxLayout *hLayout9 = new QHBoxLayout(); hLayout9->addWidget(m_chbPanel); hLayout9->addWidget(m_btnPanelWidget); vLayout2->addLayout(hLayout9); box4->setLayout(vLayout2); m_demandBtn = new QPushButton("demandAttention", this); m_fullscreenBtn = new QPushButton("全屏", this); m_processName = new QPushButton("打印进程名", this); hLayout9->addWidget(m_demandBtn); hLayout9->addWidget(m_fullscreenBtn); hLayout9->addWidget(m_processName); vLayout2->addLayout(hLayout9); box4->setLayout(vLayout2); QGroupBox *box5 = new QGroupBox("2.5需求接口", this); m_getGeometryBtn = new QPushButton("getGeometry", this); m_setGrabKeyboardBtn = new QPushButton("setGrabKeyboard", this); m_setSwitcherLayer = new QPushButton("setSwitcherLayer", this); m_setHighlightBtn = new QPushButton("setHighlight", this); m_unsetHighlightBtn = new QPushButton("unsetHighlight", this); m_setIconNameBtn = new QPushButton("setIconName", this); m_unsetIconNameBtn = new QPushButton("unsetIconName", this); QHBoxLayout *layout10 = new QHBoxLayout(); layout10->addWidget(m_getGeometryBtn); layout10->addWidget(m_setGrabKeyboardBtn); layout10->addWidget(m_setSwitcherLayer); layout10->addWidget(m_setHighlightBtn); layout10->addWidget(m_setIconNameBtn); layout10->addWidget(m_unsetIconNameBtn); QVBoxLayout *vLayout3 = new QVBoxLayout(); vLayout3->addLayout(layout10); m_openUnderCursorBtn = new QPushButton("openUnderCursor", this); m_openUnderCursorWithOffsetBtn = new QPushButton("openUnderCursorWithOffset", this); m_xOffset = new QSpinBox(this); m_xOffset->setRange(-1920 * 2, 1920 * 2); m_xOffset->setValue(10); m_yOffset = new QSpinBox(this); m_yOffset->setValue(10); m_yOffset->setRange(-1080 * 2, 1080 * 2); QHBoxLayout *layout11 = new QHBoxLayout(); layout11->addWidget(m_unsetHighlightBtn); layout11->addWidget(m_openUnderCursorBtn); layout11->addWidget(m_openUnderCursorWithOffsetBtn); layout11->addWidget(m_xOffset); layout11->addWidget(m_yOffset); layout11->addWidget(m_setIconNameBtn); layout11->addWidget(m_unsetIconNameBtn); layout11->addStretch(); vLayout3->addLayout(layout11); QHBoxLayout *layout12 = new QHBoxLayout(); m_getCurrentOutputBtn = new QPushButton(tr("GetCurrentOutput"), this); m_getOutputsInfoBtn = new QPushButton(tr("GetOutputsInfo"), this); layout12->addWidget(m_getCurrentOutputBtn); layout12->addWidget(m_getOutputsInfoBtn); layout12->addStretch(); vLayout3->addLayout(layout12); QHBoxLayout *layout13 = new QHBoxLayout(); m_getWindowIdByTitleBtn = new QPushButton("Search", this); m_getWindowIdByTitleEdit = new QLineEdit(this); m_getWindowIdByTitleEdit->setPlaceholderText("get window id by title"); m_getWindowIdByPidBtn = new QPushButton("Search", this); m_getWindowIdByPidEdit = new QLineEdit(this); m_getWindowIdByPidEdit->setPlaceholderText("get window id by pid"); layout13->addWidget(m_getWindowIdByTitleEdit); layout13->addWidget(m_getWindowIdByTitleBtn); layout13->addWidget(m_getWindowIdByPidEdit); layout13->addWidget(m_getWindowIdByPidBtn); vLayout3->addLayout(layout13); box5->setLayout(vLayout3); mainLayout->addWidget(m_label); mainLayout->addLayout(hLayout1); mainLayout->addWidget(label); mainLayout->addLayout(hLayout5); mainLayout->addLayout(hLayout2); mainLayout->addLayout(hLayout3); mainLayout->addLayout(hLayout4); mainLayout->addWidget(box2); mainLayout->addWidget(box3); mainLayout->addWidget(box4); mainLayout->addWidget(box5); m_subWidget = new QWidget(); m_subWidget->setWindowIcon(QIcon::fromTheme("kylin-music")); m_subWidget->setWindowTitle("widget"); m_panelWidget = new QWidget(); WindowManager::setWindowLayer(m_panelWidget->windowHandle(), WindowLayer::Panel); } void Widget::initConnection() { connect(m_getWindowIdByPidBtn, &QPushButton::clicked, this, [=]() { qDebug() << QString("windows id of %1:").arg(m_getWindowIdByPidEdit->text()) << WindowManager::getWindowIdByPid(m_getWindowIdByPidEdit->text().toInt()); }); connect(m_getWindowIdByTitleBtn, &QPushButton::clicked, this, [=]() { qDebug() << QString("windows id of %1:").arg(m_getWindowIdByTitleEdit->text()) << WindowManager::getWindowIdByTtile(m_getWindowIdByTitleEdit->text()); }); connect(m_getCurrentOutputBtn, &::QPushButton::clicked, this, [=]() { qDebug() << "current output name:" << WindowManager::currentOutputName(); qDebug() << "current seat name:" << WindowManager::currentSeatName(); }); connect(m_getOutputsInfoBtn, &::QPushButton::clicked, this, [=]() { QList infos = WindowManager::outputsInfo(); for (auto info : infos) { qDebug() << "output name:" << info->outputName(); qDebug() << "output usable area:" << info->usableArea(); ; } }); connect(m_getOutputsInfoBtn, &::QPushButton::clicked, this, [=]() { WindowManager::setIconName(m_subWidget->windowHandle(), "kylin-music"); }); connect(m_setIconNameBtn, &::QPushButton::clicked, this, [=]() { WindowManager::setIconName(m_subWidget->windowHandle(), "kylin-music"); }); connect(m_unsetIconNameBtn, &::QPushButton::clicked, this, [=]() { WindowManager::setIconName(m_subWidget->windowHandle(), ""); }); connect(m_openUnderCursorWithOffsetBtn, &::QPushButton::clicked, this, [=]() { WindowManager::setOpenUnderCursor(m_subWidget->windowHandle(), m_xOffset->value(), m_yOffset->value()); }); connect(m_openUnderCursorBtn, &::QPushButton::clicked, this, [=]() { WindowManager::setOpenUnderCursor(m_subWidget->windowHandle()); }); connect(m_setHighlightBtn, &::QPushButton::clicked, this, [=]() { WindowManager::setHighlight(m_lastestWindowId, true); }); connect(m_unsetHighlightBtn, &::QPushButton::clicked, this, [=]() { WindowManager::setHighlight(m_lastestWindowId, false); }); connect(m_setSwitcherLayer, &::QPushButton::clicked, this, [=]() { WindowManager::setWindowLayer(m_subWidget->windowHandle(), WindowLayer::Switcher); }); connect(m_setGrabKeyboardBtn, &::QPushButton::clicked, this, [=]() { WindowManager::setGrabKeyboard(m_subWidget->windowHandle(), true); }); connect(m_getGeometryBtn, &QPushButton::clicked, this, [=]() { qDebug() << WindowManager::windowGeometry(m_lastestWindowId); }); connect(m_btnPanelWidget, &QPushButton::clicked, this, [=]() { if (m_panelWidget->isVisible()) { m_panelWidget->hide(); m_btnPanelWidget->setText("显示panel窗口"); } else { m_panelWidget->show(); m_btnPanelWidget->setText("隐藏panel窗口"); } WindowManager::setWindowLayer(m_panelWidget->windowHandle(), WindowLayer::Panel); WindowManager::setPanelTakefocus(m_panelWidget->windowHandle(), m_chbPanel->isChecked()); }); connect(m_setTypeBox, static_cast(&QComboBox::currentIndexChanged), this, [=](int index) { switch (index) { case 0: m_subWidget->setWindowFlags(Qt::Widget); break; case 1: m_subWidget->setWindowFlags(Qt::Window); break; case 2: m_subWidget->setWindowFlags(Qt::Dialog); break; case 3: m_subWidget->setWindowFlags(Qt::Sheet); break; case 4: m_subWidget->setWindowFlags(Qt::Drawer); break; case 5: m_subWidget->setWindowFlags(Qt::Popup); break; case 6: m_subWidget->setWindowFlags(Qt::Tool); break; case 7: m_subWidget->setWindowFlags(Qt::ToolTip); break; case 8: m_subWidget->setWindowFlags(Qt::SplashScreen); break; case 9: m_subWidget->setWindowFlags(Qt::Desktop); break; case 10: m_subWidget->setWindowFlags(Qt::SubWindow); break; case 11: m_subWidget->setWindowFlags(Qt::ForeignWindow); break; case 12: m_subWidget->setWindowFlags(Qt::CoverWindow); break; default: break; } }); connect(WindowManager::self(), &WindowManager::activeWindowChanged, this, [=](const WindowId &wid) { // qDebug()<<"活动窗口改变:"<start(); connect(m_timer, &QTimer::timeout, this, [=]() { WindowManager::hideDesktop(); }); }); connect(m_btnShowGroup, &QPushButton::clicked, this, [=]() { qDebug() << "窗口所属组:" << WindowManager::getWindowGroup(m_lastestWindowId); }); connect(m_shwWdgbtn, &QPushButton::clicked, this, [=]() { m_subWidget->show(); }); connect(m_btnChangeTitle, &QPushButton::clicked, this, [=]() { if (m_subWidget) { if (m_subWidget->windowTitle() != QString("originTitle")) m_subWidget->setWindowTitle("originTitle"); else m_subWidget->setWindowTitle("changedTitle"); } }); connect(m_btnChangeIcon, &QPushButton::clicked, this, [=]() { if (m_subWidget) { if (!m_subWidget->windowIcon().name().contains("kylin-music")) m_subWidget->setWindowIcon(QIcon::fromTheme("kylin-music")); else m_subWidget->setWindowIcon(QIcon::fromTheme("kylin-network")); } }); connect(m_shwWindowTitle, &QPushButton::clicked, this, [=]() { if (m_subWidget) qDebug() << "窗口标题为:" << WindowManager::getWindowTitle(m_lastestWindowId); }); connect(m_shwWindowIcon, &QPushButton::clicked, this, [=]() { if (m_subWidget) { qDebug() << "窗口图标为:" << WindowManager::getWindowIcon(m_lastestWindowId); } }); connect(m_btnprintList, &QPushButton::clicked, this, [=]() { QList lists = WindowManager::windows(); qDebug() << "打印窗口列表:"; for (auto id : lists) { qDebug() << id << "title:" << WindowManager::getWindowTitle(id) << "pid:" << WindowManager::getPid(id); } }); connect(m_btnSetGeometry, &QPushButton::clicked, this, [=]() { m_subWidget->show(); QRect rect(m_posX->value(), m_posY->value(), m_width->value(), m_height->value()); WindowManager::setGeometry(m_subWidget->windowHandle(), rect); }); connect(m_btnGetType, &QPushButton::clicked, this, [=]() { /* *Unknown = -1, *Normal = 0 *Desktop = 1, *Dock = 2, *Toolbar = 3, *Menu = 4, *Dialog = 5, *Override = 6, // NON STANDARD *TopMenu = 7, // NON STANDARD *Utility = 8, *Splash = 9, *DropdownMenu = 10, *PopupMenu = 11, *Tooltip = 12, *Notification = 13, *ComboBox = 14, *DNDIcon = 15, *OnScreenDisplay = 16, *CriticalNotification = 17 */ switch (WindowManager::getWindowType(m_subWidget->winId())) { case NET::WindowType::Unknown: qDebug() << "Unknown"; break; case NET::WindowType::Normal: qDebug() << "normal"; break; case NET::WindowType::Desktop: qDebug() << "Desktop"; break; case NET::WindowType::Dock: qDebug() << "Dock"; break; case NET::WindowType::Toolbar: qDebug() << "Toolbar"; break; case NET::WindowType::Menu: qDebug() << "Menu"; break; case NET::WindowType::Dialog: qDebug() << "Dialog"; break; case NET::WindowType::Override: qDebug() << "Override"; break; case NET::WindowType::TopMenu: qDebug() << "TopMenu"; break; case NET::WindowType::Splash: qDebug() << "Splash"; break; case NET::WindowType::Utility: qDebug() << "Utility"; break; case NET::WindowType::DropdownMenu: qDebug() << "DropdownMenu"; break; case NET::WindowType::PopupMenu: qDebug() << "PopupMenu"; break; case NET::WindowType::Tooltip: qDebug() << "Tooltip"; break; case NET::WindowType::Notification: qDebug() << "Notification"; break; case NET::WindowType::ComboBox: qDebug() << "ComboBox"; break; case NET::WindowType::DNDIcon: qDebug() << "DNDIcon"; break; case NET::WindowType::OnScreenDisplay: qDebug() << "OnScreenDisplay"; break; case NET::WindowType::CriticalNotification: qDebug() << "CriticalNotification"; break; default: qDebug() << WindowManager::getWindowType(m_subWidget->winId()); break; }; }); connect(m_skipTaskbarBtn, &QPushButton::clicked, this, [=]() { ; WindowManager::setSkipTaskBar(m_subWidget->windowHandle(), true); QTimer::singleShot(1000, this, [=]() { qDebug() << "跳过任务栏:" << WindowManager::skipTaskBar(m_lastestWindowId); }); }); connect(m_skipSwitcherBtn, &QPushButton::clicked, this, [=]() { WindowManager::setSkipSwitcher(m_subWidget->windowHandle(), true); QTimer::singleShot(1000, this, [=]() { qDebug() << "跳过窗口选择器" << WindowManager::skipSwitcher(m_lastestWindowId); }); }); connect(m_showOnAllDesktop, &QPushButton::clicked, this, [=]() { WindowManager::setOnAllDesktops(m_lastestWindowId); QTimer::singleShot(1000, this, [=]() { qDebug() << "设置窗口在所有桌面中显示:" << WindowManager::isOnAllDesktops(m_lastestWindowId); }); }); connect(m_isDesktopShowing, &QPushButton::clicked, this, [=]() { qDebug() << "桌面处于显示状态:" << WindowManager::isShowingDesktop(); }); connect(m_isOnCurrentDesktop, &QPushButton::clicked, this, [=]() { qDebug() << m_lastestWindowId; qDebug() << "被测窗体是否在当前桌面:" << WindowManager::isOnCurrentDesktop(m_lastestWindowId); }); connect(m_demandBtn, &QPushButton::clicked, this, [=]() { QTimer::singleShot(2000, this, [=]() { WindowManager::demandAttention(m_lastestWindowId); }); }); connect(m_fullscreenBtn, &QPushButton::clicked, this, [=]() { if (!m_subWidget) return; if (m_subWidget->isFullScreen()) { m_subWidget->resize(640, 480); m_subWidget->showNormal(); } else m_subWidget->showFullScreen(); }); connect(m_processName, &QPushButton::clicked, this, [=]() { if (!m_subWidget) return; qDebug() << WindowManager::getProcessName(m_lastestWindowId); }); } libkysdk-applications/kysdk-waylandhelper/test/testWindowManager/main.cpp0000664000175000017500000000207515104543305026037 0ustar fengfeng/* * * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #include "widget.h" #include #include #include using namespace kdk; int main(int argc, char *argv[]) { QApplication a(argc, argv); a.setApplicationDisplayName("myAppDisplayName"); a.setApplicationName("myAppName"); Widget w; w.show(); return a.exec(); } libkysdk-applications/kysdk-waylandhelper/test/testukuistylehelper/0000775000175000017500000000000015104543305025077 5ustar fengfenglibkysdk-applications/kysdk-waylandhelper/test/testukuistylehelper/widget.h0000664000175000017500000000201715104543305026533 0ustar fengfeng/* * * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #ifndef WIDGET_H #define WIDGET_H #include #include class Widget : public QWidget { Q_OBJECT public: Widget(QWidget *parent = nullptr); ~Widget(); private: QPushButton *m_btn; QWidget *m_testWidget; }; #endif // WIDGET_H libkysdk-applications/kysdk-waylandhelper/test/testukuistylehelper/testukuistylehelper.pro0000664000175000017500000000176715104543305031772 0ustar fengfengQT += core gui greaterThan(QT_MAJOR_VERSION, 4): QT += widgets CONFIG += c++17 link_pkgconfig PKGCONFIG += kysdk-waylandhelper KF6WindowSystem # The following define makes your compiler emit warnings if you use # any Qt feature that has been marked deprecated (the exact warnings # depend on your compiler). Please consult the documentation of the # deprecated API in order to know how to port your code away from it. DEFINES += QT_DEPRECATED_WARNINGS # You can also make your code fail to compile if it uses deprecated APIs. # In order to do so, uncomment the following line. # You can also select to disable deprecated APIs only up to a certain version of Qt. #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 SOURCES += \ main.cpp \ widget.cpp HEADERS += \ widget.h # Default rules for deployment. qnx: target.path = /tmp/$${TARGET}/bin else: unix:!android: target.path = /opt/$${TARGET}/bin !isEmpty(target.path): INSTALLS += target libkysdk-applications/kysdk-waylandhelper/test/testukuistylehelper/widget.cpp0000664000175000017500000000322015104543305027063 0ustar fengfeng/* * * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #include "widget.h" #include "ukuistylehelper/ukuistylehelper.h" #include "windowmanager/windowmanager.h" #include #include Widget::Widget(QWidget *parent) : QWidget(parent) { m_btn = new QPushButton("switch", this); m_btn->setCheckable(true); m_btn->move(100, 100); m_testWidget = new QWidget(); QPushButton *btn = new QPushButton(this); btn->move(200, 100); connect(m_btn, &QPushButton::clicked, this, [=](bool checked) { if (checked) { kdk::UkuiStyleHelper::self()->removeHeader(m_testWidget); m_testWidget->show(); } else m_testWidget->hide(); }); connect(btn, &QPushButton::clicked, this, [=](bool checked) { QPoint pos = m_testWidget->pos(); // m_testWidget->move(pos.x()-10,pos.y()-10); m_testWidget->move(-100, -100); }); } Widget::~Widget() { } libkysdk-applications/kysdk-waylandhelper/test/testukuistylehelper/main.cpp0000664000175000017500000000167115104543305026534 0ustar fengfeng/* * * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #include "widget.h" #include #include int main(int argc, char *argv[]) { QApplication a(argc, argv); Widget w; w.show(); return a.exec(); } libkysdk-applications/kysdk-waylandhelper/test/testBlurManager/0000775000175000017500000000000015104543305024040 5ustar fengfenglibkysdk-applications/kysdk-waylandhelper/test/testBlurManager/widget.h0000664000175000017500000000201415104543305025471 0ustar fengfeng/* * * Copyright (C) 2024, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #ifndef WIDGET_H #define WIDGET_H #include #include class Widget : public QWidget { Q_OBJECT public: Widget(QWidget *parent = nullptr); ~Widget(); private: QPushButton *m_btn; QWidget *m_testWidget; }; #endif // WIDGET_H libkysdk-applications/kysdk-waylandhelper/test/testBlurManager/.gitignore0000664000175000017500000000134515104543305026033 0ustar fengfeng# This file is used to ignore files which are generated # ---------------------------------------------------------------------------- *~ *.autosave *.a *.core *.moc *.o *.obj *.orig *.rej *.so *.so.* *_pch.h.cpp *_resource.rc *.qm .#* *.*# core !core/ tags .DS_Store .directory *.debug Makefile* *.prl *.app moc_*.cpp ui_*.h qrc_*.cpp Thumbs.db *.res *.rc /.qmake.cache /.qmake.stash # qtcreator generated files *.pro.user* # xemacs temporary files *.flc # Vim temporary files .*.swp # Visual Studio generated files *.ib_pdb_index *.idb *.ilk *.pdb *.sln *.suo *.vcproj *vcproj.*.*.user *.ncb *.sdf *.opensdf *.vcxproj *vcxproj.* # MinGW generated files *.Debug *.Release # Python byte code *.pyc # Binaries # -------- *.dll *.exe libkysdk-applications/kysdk-waylandhelper/test/testBlurManager/testBlurManager.pro0000664000175000017500000000115015104543305027656 0ustar fengfengQT += core gui greaterThan(QT_MAJOR_VERSION, 4): QT += widgets CONFIG += c++17 link_pkgconfig PKGCONFIG += kysdk-waylandhelper KF6WindowSystem # You can make your code fail to compile if it uses deprecated APIs. # In order to do so, uncomment the following line. #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 SOURCES += \ main.cpp \ widget.cpp HEADERS += \ widget.h # Default rules for deployment. qnx: target.path = /tmp/$${TARGET}/bin else: unix:!android: target.path = /opt/$${TARGET}/bin !isEmpty(target.path): INSTALLS += target libkysdk-applications/kysdk-waylandhelper/test/testBlurManager/widget.cpp0000664000175000017500000000302515104543305026027 0ustar fengfeng/* * * Copyright (C) 2024, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #include "widget.h" #include "widget.h" #include #include #include #include Widget::Widget(QWidget *parent) : QWidget(parent) { m_btn = new QPushButton("switch", this); m_btn->setCheckable(true); m_btn->move(100, 100); m_testWidget = new QWidget(); connect(m_btn, &QPushButton::clicked, this, [=](bool checked) { if (checked) { m_testWidget->setAttribute(Qt::WA_TranslucentBackground); m_testWidget->show(); kdk::BlurManager::setBlurBehindWithStrength(m_testWidget->windowHandle(), true, QRegion(m_testWidget->rect()), 400); } else m_testWidget->hide(); }); } Widget::~Widget() { } libkysdk-applications/kysdk-waylandhelper/test/testBlurManager/main.cpp0000664000175000017500000000164315104543305025474 0ustar fengfeng/* * * Copyright (C) 2024, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #include "widget.h" #include int main(int argc, char *argv[]) { QApplication a(argc, argv); Widget w; w.show(); return a.exec(); } libkysdk-applications/kysdk-waylandhelper/test/testxdgactivation/0000775000175000017500000000000015104543305024505 5ustar fengfenglibkysdk-applications/kysdk-waylandhelper/test/testxdgactivation/widget.h0000664000175000017500000000167015104543305026145 0ustar fengfeng/* * * Copyright (C) 2024, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #ifndef WIDGET_H #define WIDGET_H #include class Widget : public QWidget { Q_OBJECT public: Widget(QWidget *parent = nullptr); ~Widget(); }; #endif // WIDGET_H libkysdk-applications/kysdk-waylandhelper/test/testxdgactivation/.gitignore0000664000175000017500000000134515104543305026500 0ustar fengfeng# This file is used to ignore files which are generated # ---------------------------------------------------------------------------- *~ *.autosave *.a *.core *.moc *.o *.obj *.orig *.rej *.so *.so.* *_pch.h.cpp *_resource.rc *.qm .#* *.*# core !core/ tags .DS_Store .directory *.debug Makefile* *.prl *.app moc_*.cpp ui_*.h qrc_*.cpp Thumbs.db *.res *.rc /.qmake.cache /.qmake.stash # qtcreator generated files *.pro.user* # xemacs temporary files *.flc # Vim temporary files .*.swp # Visual Studio generated files *.ib_pdb_index *.idb *.ilk *.pdb *.sln *.suo *.vcproj *vcproj.*.*.user *.ncb *.sdf *.opensdf *.vcxproj *vcxproj.* # MinGW generated files *.Debug *.Release # Python byte code *.pyc # Binaries # -------- *.dll *.exe libkysdk-applications/kysdk-waylandhelper/test/testxdgactivation/widget.cpp0000664000175000017500000000154515104543305026501 0ustar fengfeng/* * * Copyright (C) 2024, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #include "widget.h" Widget::Widget(QWidget *parent) : QWidget(parent) { } Widget::~Widget() { } libkysdk-applications/kysdk-waylandhelper/test/testxdgactivation/main.cpp0000664000175000017500000000277515104543305026150 0ustar fengfeng/* * * Copyright (C) 2024, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #include "ukuistylehelper/ukuistylehelper.h" #include "widget.h" #include "windowmanager/windowmanager.h" #include #include #include #include int main(int argc, char *argv[]) { QApplication a(argc, argv); QWidget window1(nullptr, Qt::Window); window1.setWindowTitle("Window 1"); window1.setLayout(new QVBoxLayout); QPushButton p("Raise the Window 2"); window1.layout()->addWidget(&p); window1.show(); QWidget window2(nullptr, Qt::Window); window2.setWindowTitle("Window 2"); window2.show(); QObject::connect(&p, &QPushButton::clicked, &a, [&] { kdk::WindowManager::activateWindow(window1.windowHandle(), window2.windowHandle()); }); return a.exec(); } libkysdk-applications/kysdk-waylandhelper/test/testxdgactivation/testxdgactivation.pro0000664000175000017500000000122415104543305030772 0ustar fengfengQT += core gui greaterThan(QT_MAJOR_VERSION, 4): QT += widgets CONFIG += c++17 CONFIG += link_pkgconfig PKGCONFIG += kysdk-widgetutils kysdk-qtwidgets KF6WindowSystem kysdk-waylandhelper # You can make your code fail to compile if it uses deprecated APIs. # In order to do so, uncomment the following line. #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 SOURCES += \ main.cpp \ widget.cpp HEADERS += \ widget.h # Default rules for deployment. qnx: target.path = /tmp/$${TARGET}/bin else: unix:!android: target.path = /opt/$${TARGET}/bin !isEmpty(target.path): INSTALLS += target libkysdk-applications/kysdk-waylandhelper/test/testukuiwindowhelper/0000775000175000017500000000000015155674255025265 5ustar fengfenglibkysdk-applications/kysdk-waylandhelper/test/testukuiwindowhelper/widget.h0000664000175000017500000000315415104543305026705 0ustar fengfeng#pragma once #include #include class QLineEdit; class QComboBox; class QCheckBox; class Widget : public QWidget { Q_OBJECT public: explicit Widget(QWidget *parent = nullptr); ~Widget() override; enum state { state_minimizable = 0x1, state_maximizable = 0x2, state_fullscreenable = 0x4, state_closeable = 0x8, state_movable = 0x10, state_resizable = 0x20, state_focusable = 0x40, state_activatable = 0x80, state_keep_above = 0x100, state_keep_below = 0x200, }; private: QWidget *childWindow = nullptr; QLineEdit *lineEdit_pos = nullptr; QComboBox *comboBox_role = nullptr; QCheckBox *checkBox_skipTaskbar = nullptr; QCheckBox *checkBox_skipSwitcher = nullptr; QCheckBox *checkBox_state_minimizable = nullptr; QCheckBox *checkBox_state_maximizable = nullptr; QCheckBox *checkBox_state_fullscreenable = nullptr; QCheckBox *checkBox_state_closeable = nullptr; QCheckBox *checkBox_state_movable = nullptr; QCheckBox *checkBox_state_resizable = nullptr; QCheckBox *checkBox_state_focusable = nullptr; QCheckBox *checkBox_state_activatable = nullptr; QCheckBox *checkBox_state_keep_above = nullptr; QCheckBox *checkBox_state_keep_below = nullptr; QLineEdit *lineEdit_icon = nullptr; QCheckBox *checkBox_titleBar = nullptr; QCheckBox *checkBox_round_corner = nullptr; QCheckBox *checkBox_border = nullptr; QCheckBox *checkBox_shadow = nullptr; QPushButton *button_show_tile_flyout = nullptr; void initChildWindow(QWidget *window); };libkysdk-applications/kysdk-waylandhelper/test/testukuiwindowhelper/testukuiwindowhelper.pro0000664000175000017500000000165015155674255032316 0ustar fengfengQT += core gui greaterThan(QT_MAJOR_VERSION, 4): QT += widgets CONFIG += c++17 link_pkgconfig # The following define makes your compiler emit warnings if you use # any Qt feature that has been marked deprecated (the exact warnings # depend on your compiler). Please consult the documentation of the # deprecated API in order to know how to port your code away from it. DEFINES += QT_DEPRECATED_WARNINGS # You can also make your code fail to compile if it uses deprecated APIs. # In order to do so, uncomment the following line. # You can also select to disable deprecated APIs only up to a certain version of Qt. #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 SOURCES += \ main.cpp \ widget.cpp HEADERS += \ widget.h INCLUDEPATH += \ ../../src/kysdk-ukuiwindowhelper/ LIBS += $$OUT_PWD/../../src/kysdk-ukuiwindowhelper/libkysdk-ukuiwindowhelper.so libkysdk-applications/kysdk-waylandhelper/test/testukuiwindowhelper/widget.cpp0000664000175000017500000002020015155674255027246 0ustar fengfeng#include "widget.h" #include "ukuiwindowhelper.h" #include "ukuistartup.h" #include #include #include #include #include #include #include #include #include #include #include Widget::Widget(QWidget *parent) : QWidget(parent) { UkuiWindowHelper *windowHelper = new UkuiWindowHelper(this); windowHelper->setSkipTaskBar(true); windowHelper->setSkipSwitcher(true); qDebug() << "Current Screen: " << windowHelper->getCurrentScreenBlocking(); QGridLayout *layout = new QGridLayout(this); // 位置 QHBoxLayout *hbox_pos = new QHBoxLayout(); QLabel *label = new QLabel("位置", this); lineEdit_pos = new QLineEdit("200,200", this); hbox_pos->addWidget(label); hbox_pos->addWidget(lineEdit_pos); // role QLabel *label_role = new QLabel("Role", this); comboBox_role = new QComboBox(this); comboBox_role->addItem("normal"); comboBox_role->addItem("desktop"); comboBox_role->addItem("panel"); comboBox_role->addItem("onscreendisplay"); comboBox_role->addItem("notification"); comboBox_role->addItem("tooltip"); comboBox_role->addItem("criticalnotification"); comboBox_role->addItem("appletpopup"); comboBox_role->addItem("screenlock"); comboBox_role->addItem("watermark"); comboBox_role->addItem("systemwindow"); comboBox_role->addItem("inputpanel"); comboBox_role->addItem("logout"); comboBox_role->addItem("screenlocknotification"); comboBox_role->addItem("switcher"); comboBox_role->addItem("authentication"); hbox_pos->addWidget(label_role); hbox_pos->addWidget(comboBox_role); layout->addLayout(hbox_pos, 0, 0, 1, 4); int row = 1; int col = 0; auto addWidget = [layout, &row, &col](QWidget *widget) { layout->addWidget(widget, row, col); if (++col > 3) { col = 0; ++row; } }; // 跳过任务栏 checkBox_skipTaskbar = new QCheckBox("SkipTaskBar", this); addWidget(checkBox_skipTaskbar); // 跳过Switcher checkBox_skipSwitcher = new QCheckBox("SkipSwitcher", this); addWidget(checkBox_skipSwitcher); // state checkBox_state_maximizable = new QCheckBox("Maximizable", this); addWidget(checkBox_state_maximizable); checkBox_state_minimizable = new QCheckBox("Minimizable", this); addWidget(checkBox_state_minimizable); checkBox_state_fullscreenable = new QCheckBox("Fullscreenable", this); addWidget(checkBox_state_fullscreenable); checkBox_state_closeable = new QCheckBox("Closeable", this); addWidget(checkBox_state_closeable); checkBox_state_movable = new QCheckBox("Movable", this); addWidget(checkBox_state_movable); checkBox_state_resizable = new QCheckBox("Resizable", this); addWidget(checkBox_state_resizable); checkBox_state_focusable = new QCheckBox("Focusable", this); addWidget(checkBox_state_focusable); checkBox_state_activatable = new QCheckBox("Activatable", this); addWidget(checkBox_state_activatable); checkBox_state_keep_above = new QCheckBox("KeepAbove", this); addWidget(checkBox_state_keep_above); checkBox_state_keep_below = new QCheckBox("KeepBelow", this); addWidget(checkBox_state_keep_below); // 窗口标题栏 checkBox_titleBar = new QCheckBox("NoTitleBar", this); addWidget(checkBox_titleBar); checkBox_round_corner = new QCheckBox("RoundCorner(Popup Only)", this); addWidget(checkBox_round_corner); checkBox_border = new QCheckBox("Border(Popup Only)", this); addWidget(checkBox_border); checkBox_shadow = new QCheckBox("Shadow(Popup Only)", this); addWidget(checkBox_shadow); QHBoxLayout *hbox_icon = new QHBoxLayout(); QLabel *label_icon = new QLabel("图标", this); lineEdit_icon = new QLineEdit("kylin-printer", this); lineEdit_icon->setPlaceholderText("请输入主题库中包含的图标名称"); hbox_icon->addWidget(label_icon); hbox_icon->addWidget(lineEdit_icon); layout->addLayout(hbox_icon, 5, 0, 1, 4); QPushButton *btn = new QPushButton("打开窗口", this); connect(btn, &QPushButton::clicked, [this] { if (childWindow == nullptr) { childWindow = new QDialog(this); initChildWindow(childWindow); childWindow->resize(420, 360); childWindow->show(); } }); QPushButton *btnClose = new QPushButton("关闭窗口", this); connect(btnClose, &QPushButton::clicked, [this] { if (childWindow != nullptr) { childWindow->close(); childWindow = nullptr; } }); QPushButton *btn_openPopup = new QPushButton("打开Popup窗口", this); connect(btn_openPopup, &QPushButton::clicked, [this] { QScopedPointer menu(new QMenu(this)); menu->addAction("菜单1"); menu->addAction("菜单2"); menu->addAction("菜单3"); initChildWindow(menu.data()); menu->exec(QCursor::pos()); }); QHBoxLayout *hbox_btn = new QHBoxLayout(); hbox_btn->addWidget(btn); hbox_btn->addWidget(btnClose); hbox_btn->addWidget(btn_openPopup); layout->addLayout(hbox_btn, 6, 0, 1, 4); QPushButton *btnStartupGeo = new QPushButton("启动终端(StartUpGeometry接口测试)", this); connect(btnStartupGeo, &QPushButton::clicked, [] { QProcess p; p.setProgram("mate-terminal"); qint64 pid; p.startDetached(&pid); ukuiStartupManager()->setStartupGeometryByPid(pid, 200, 200, 100, 100); }); layout->addWidget(btnStartupGeo, 7, 0, 1, 4); button_show_tile_flyout = new QPushButton("显示分屏窗口", this); connect(button_show_tile_flyout, &QPushButton::clicked, [this, windowHelper] { windowHelper->showTileFlyout(button_show_tile_flyout->geometry()); }); layout->addWidget(button_show_tile_flyout, 8, 0, 1, 4); setLayout(layout); } Widget::~Widget() { } void Widget::initChildWindow(QWidget *w) { UkuiWindowHelper *windowHelper = new UkuiWindowHelper(w); if (QStringList pos = lineEdit_pos->text().split(","); pos.size() == 2) { windowHelper->setPosition(QPoint(pos[0].toInt(), pos[1].toInt())); } windowHelper->setSkipTaskBar(checkBox_skipTaskbar->isChecked()); windowHelper->setSkipSwitcher(checkBox_skipSwitcher->isChecked()); if (checkBox_titleBar->isChecked()) windowHelper->removeTitleBar(); windowHelper->setWindowRole((UkuiWindowHelper::WindowRole)comboBox_role->currentIndex()); UkuiWindowHelper::States states; if (checkBox_state_minimizable->isChecked()) states |= UkuiWindowHelper::State::Minimizable; if (checkBox_state_maximizable->isChecked()) states |= UkuiWindowHelper::State::Maximizable; if (checkBox_state_fullscreenable->isChecked()) states |= UkuiWindowHelper::State::Fullscreenable; if (checkBox_state_closeable->isChecked()) states |= UkuiWindowHelper::State::Closeable; if (checkBox_state_movable->isChecked()) states |= UkuiWindowHelper::State::Movable; if (checkBox_state_resizable->isChecked()) states |= UkuiWindowHelper::State::Resizable; if (checkBox_state_focusable->isChecked()) states |= UkuiWindowHelper::State::Focusable; if (checkBox_state_activatable->isChecked()) states |= UkuiWindowHelper::State::Activatable; if (checkBox_state_keep_above->isChecked()) states |= UkuiWindowHelper::State::KeepAbove; if (checkBox_state_keep_below->isChecked()) states |= UkuiWindowHelper::State::KeepBelow; windowHelper->setWindowState(states); UkuiWindowHelper::DecorationComponents decorationComponents; if (checkBox_round_corner->isChecked()) decorationComponents |= UkuiWindowHelper::DecorationComponent::RoundCorner; if (checkBox_border->isChecked()) decorationComponents |= UkuiWindowHelper::DecorationComponent::Border; if (checkBox_shadow->isChecked()) decorationComponents |= UkuiWindowHelper::DecorationComponent::Shadow; windowHelper->setDecorationCompoents(decorationComponents); windowHelper->setWindowIcon(lineEdit_icon->text().trimmed()); }libkysdk-applications/kysdk-waylandhelper/test/testukuiwindowhelper/main.cpp0000664000175000017500000000024315104543305026675 0ustar fengfeng#include "widget.h" #include int main(int argc, char *argv[]) { QApplication a(argc, argv); Widget w; w.show(); return a.exec(); } libkysdk-applications/kysdk-waylandhelper/test/testidlenotifier/0000775000175000017500000000000015104543305024316 5ustar fengfenglibkysdk-applications/kysdk-waylandhelper/test/testidlenotifier/widget.h0000664000175000017500000000174015104543305025754 0ustar fengfeng/* * * Copyright (C) 2024, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #ifndef WIDGET_H #define WIDGET_H #include "windowmanager/idlenotifier.h" #include class Widget : public QWidget { Q_OBJECT public: Widget(QWidget *parent = nullptr); ~Widget(); }; #endif // WIDGET_H libkysdk-applications/kysdk-waylandhelper/test/testidlenotifier/.gitignore0000664000175000017500000000134515104543305026311 0ustar fengfeng# This file is used to ignore files which are generated # ---------------------------------------------------------------------------- *~ *.autosave *.a *.core *.moc *.o *.obj *.orig *.rej *.so *.so.* *_pch.h.cpp *_resource.rc *.qm .#* *.*# core !core/ tags .DS_Store .directory *.debug Makefile* *.prl *.app moc_*.cpp ui_*.h qrc_*.cpp Thumbs.db *.res *.rc /.qmake.cache /.qmake.stash # qtcreator generated files *.pro.user* # xemacs temporary files *.flc # Vim temporary files .*.swp # Visual Studio generated files *.ib_pdb_index *.idb *.ilk *.pdb *.sln *.suo *.vcproj *vcproj.*.*.user *.ncb *.sdf *.opensdf *.vcxproj *vcxproj.* # MinGW generated files *.Debug *.Release # Python byte code *.pyc # Binaries # -------- *.dll *.exe libkysdk-applications/kysdk-waylandhelper/test/testidlenotifier/widget.cpp0000664000175000017500000000223315104543305026305 0ustar fengfeng/* * * Copyright (C) 2024, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #include "widget.h" #include using namespace kdk; Widget::Widget(QWidget *parent) : QWidget(parent) { IdleNotifier *notifier = new IdleNotifier(this); notifier->setIdleInterval(10); connect(notifier, &IdleNotifier::idled, [=]() { qDebug() << "idled"; }); connect(notifier, &IdleNotifier::resumed, [=]() { qDebug() << "resumed"; }); } Widget::~Widget() { } libkysdk-applications/kysdk-waylandhelper/test/testidlenotifier/main.cpp0000664000175000017500000000164315104543305025752 0ustar fengfeng/* * * Copyright (C) 2024, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #include "widget.h" #include int main(int argc, char *argv[]) { QApplication a(argc, argv); Widget w; w.show(); return a.exec(); } libkysdk-applications/kysdk-waylandhelper/test/testidlenotifier/testidlenotifier.pro0000664000175000017500000000115115104543305030413 0ustar fengfengQT += core gui greaterThan(QT_MAJOR_VERSION, 4): QT += widgets CONFIG += c++17 link_pkgconfig PKGCONFIG += kysdk-waylandhelper KF6WindowSystem # You can make your code fail to compile if it uses deprecated APIs. # In order to do so, uncomment the following line. #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 SOURCES += \ main.cpp \ widget.cpp HEADERS += \ widget.h # Default rules for deployment. qnx: target.path = /tmp/$${TARGET}/bin else: unix:!android: target.path = /opt/$${TARGET}/bin !isEmpty(target.path): INSTALLS += target libkysdk-applications/kysdk-waylandhelper/test/testWindowInfo/0000775000175000017500000000000015104543305023724 5ustar fengfenglibkysdk-applications/kysdk-waylandhelper/test/testWindowInfo/testWindowInfo.pro0000664000175000017500000000177015104543305027436 0ustar fengfengQT += core gui greaterThan(QT_MAJOR_VERSION, 4): QT += widgets CONFIG += c++17 link_pkgconfig PKGCONFIG += KF6WindowSystem kysdk-waylandhelper # The following define makes your compiler emit warnings if you use # any Qt feature that has been marked deprecated (the exact warnings # depend on your compiler). Please consult the documentation of the # deprecated API in order to know how to port your code away from it. DEFINES += QT_DEPRECATED_WARNINGS # You can also make your code fail to compile if it uses deprecated APIs. # In order to do so, uncomment the following line. # You can also select to disable deprecated APIs only up to a certain version of Qt. #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 SOURCES += \ main.cpp \ widget.cpp HEADERS += \ widget.h # Default rules for deployment. qnx: target.path = /tmp/$${TARGET}/bin else: unix:!android: target.path = /opt/$${TARGET}/bin !isEmpty(target.path): INSTALLS += target libkysdk-applications/kysdk-waylandhelper/test/testWindowInfo/widget.h0000664000175000017500000000252215104543305025361 0ustar fengfeng/* * * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #ifndef WIDGET_H #define WIDGET_H #include "windowmanager/windowinfo.h" #include "windowmanager/windowmanager.h" #include #include using namespace kdk; class Widget : public QWidget { Q_OBJECT public: Widget(QWidget *parent = nullptr); ~Widget(); void initUi(); void initConnections(); private: QPushButton *m_btnMinimize; QPushButton *m_btnMaximum; QPushButton *m_btnActivate; QPushButton *m_btnStayOnTop; QPushButton *m_btnClose; kdk::WindowManager *m_manager; WindowId m_lastestWindowId; }; #endif // WIDGET_H libkysdk-applications/kysdk-waylandhelper/test/testWindowInfo/widget.cpp0000664000175000017500000000744615104543305025726 0ustar fengfeng/* * * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #include "widget.h" #include #include Widget::Widget(QWidget *parent) : QWidget(parent) { this->setWindowTitle("testWindowInfo"); initUi(); initConnections(); } Widget::~Widget() { } void Widget::initUi() { QHBoxLayout *hLayout = new QHBoxLayout(); m_btnActivate = new QPushButton("Activate", this); m_btnMaximum = new QPushButton("Maximum", this); m_btnMinimize = new QPushButton("Minimum", this); m_btnClose = new QPushButton("Close", this); m_btnStayOnTop = new QPushButton("StayOnTop", this); hLayout->addWidget(m_btnActivate); hLayout->addWidget(m_btnMaximum); hLayout->addWidget(m_btnMinimize); hLayout->addWidget(m_btnClose); hLayout->addWidget(m_btnStayOnTop); QVBoxLayout *vLayout = new QVBoxLayout(this); vLayout->addLayout(hLayout); } void Widget::initConnections() { qDebug() << "xxxx11"; connect(WindowManager::self(), &WindowManager::windowAdded, this, [=](const WindowId &windowId) { if (WindowManager::getWindowTitle(windowId) == "testWindowInfo") m_lastestWindowId = windowId; qDebug() << "xxxx"; if (m_lastestWindowId.isValid()) qDebug() << "111234" << m_lastestWindowId; }); connect(m_btnActivate, &QPushButton::clicked, this, [=]() { WindowManager::activateWindow(m_lastestWindowId); }); connect(m_btnClose, &QPushButton::clicked, this, [=]() { WindowManager::closeWindow(m_lastestWindowId); }); connect(m_btnMaximum, &QPushButton::clicked, this, [=]() { WindowManager::maximizeWindow(m_lastestWindowId); }); connect(m_btnMinimize, &QPushButton::clicked, this, [=]() { WindowManager::minimizeWindow(m_lastestWindowId); }); connect(m_btnStayOnTop, &QPushButton::clicked, this, [=]() { WindowManager::keepWindowAbove(m_lastestWindowId); }); connect(WindowManager::self(), &WindowManager::windowChanged, this, [=](const WindowId &windowId) { if (m_lastestWindowId == windowId) { kdk::WindowInfo windowInfo = WindowManager::getwindowInfo(m_lastestWindowId); qDebug() << "-----------window state-----------"; qDebug() << "isActive:" << windowInfo.isActive(); qDebug() << "isMaximized:" << windowInfo.isMaximized(); qDebug() << "isMinimized" << windowInfo.isMinimized(); qDebug() << "isValid" << windowInfo.isValid(); qDebug() << "isKeepAbove" << windowInfo.isKeepAbove(); // qDebug() << "isWaylandWindow"<. * * Authors: Zhen Sun * */ #include "widget.h" #include int main(int argc, char *argv[]) { QApplication a(argc, argv); Widget w; w.show(); return a.exec(); } libkysdk-applications/kysdk-waylandhelper/src/0000775000175000017500000000000015104543305020551 5ustar fengfenglibkysdk-applications/kysdk-waylandhelper/src/windowmanager/0000775000175000017500000000000015104543305023413 5ustar fengfenglibkysdk-applications/kysdk-waylandhelper/src/windowmanager/abstractinterface.cpp0000664000175000017500000001165115104543305027607 0ustar fengfeng/* * libkysdk-waylandhelper's Library * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #include #include "abstractinterface.h" #include #include #include #include using namespace kdk; inline bool operator<(const QVariant &v1, const QVariant &v2) { return v1.toString() < v2.toString(); } AbstractInterface::AbstractInterface(QObject *parent) : QObject(parent) { } AbstractInterface::~AbstractInterface() { } bool AbstractInterface::inCurrentDesktopActivity(const WindowInfo &winfo) { if (winfo.isValid() && winfo.isOnDesktop(currentDesktop())) return (winfo.isValid() && winfo.isOnDesktop(currentDesktop()) /*&& winfo.isOnActivity(currentActivity())*/); } bool AbstractInterface::isPlasmaDesktop(const QRect &wGeometry) { if (wGeometry.isEmpty()) { return false; } for (const auto scr : qGuiApp->screens()) { if (wGeometry == scr->geometry()) { return true; } } return false; } QString AbstractInterface::currentDesktop() { return m_currentDesktop; } QString AbstractInterface::currentActivity() { return m_currentActivity; } void AbstractInterface::setPlasmaDesktop(WindowId wid) { if (!m_windows.contains(wid)) { return; } if (!m_windows[wid].isPlasmaDesktop()) { m_windows[wid].setIsPlasmaDesktop(true); // updateAllHints(); } } bool AbstractInterface::isValidFor(const WindowId &wid) { if (!m_windows.contains(wid)) { return false; } return m_windows[wid].isValid() && !m_windows[wid].isPlasmaDesktop(); } QList AbstractInterface::windows() { return m_windows.keys(); } QString AbstractInterface::getProcessName(const WindowId &wid) { auto id = pid(wid); char path[128]; memset(path, 0, 128); char name[128]; memset(name, 0, 128); if (!name) { return NULL; } char link[512]; memset(link, 0, 512); snprintf(path, sizeof(path), "/proc/%d/exe", id); int count = readlink(path, link, sizeof(link)); if (count != -1) { strncpy(name, basename(link), sizeof(name) - 1); name[sizeof(name) - 1] = '\0'; } return QString(name); } bool AbstractInterface::setWindowRadius(QWindow *windowHandle, int radius) { Q_UNUSED(windowHandle) Q_UNUSED(radius) return false; } void AbstractInterface::activateWindow(QWindow *window1, QWindow *window2) { Q_UNUSED(window1) Q_UNUSED(window2) return; } void AbstractInterface::setIdleInterval(int msec) { Q_UNUSED(msec) return; } QRect AbstractInterface::windowGeometry(const WindowId &windowId) { Q_UNUSED(windowId) return QRect(); } void AbstractInterface::setPanelAutoHide(QWindow *window, bool autoHide) { Q_UNUSED(window) Q_UNUSED(autoHide) return; } void AbstractInterface::setGrabKeyboard(QWindow *window, bool grabKeyboard) { Q_UNUSED(window) Q_UNUSED(grabKeyboard) return; } void AbstractInterface::setWindowLayer(QWindow *window, WindowLayer layer) { Q_UNUSED(window) Q_UNUSED(layer) return; } WindowLayer AbstractInterface::windowLayer(QWindow *window) { Q_UNUSED(window) return WindowLayer::Normal; } void AbstractInterface::setHighlight(const WindowId &wid, bool highlight) { Q_UNUSED(wid) Q_UNUSED(highlight) } bool AbstractInterface::istHighlight(const WindowId &wid) { Q_UNUSED(wid) } void AbstractInterface::setOpenUnderCursor(QWindow *window) { Q_UNUSED(window) } void AbstractInterface::setOpenUnderCursor(QWindow *window, int x, int y) { Q_UNUSED(window) Q_UNUSED(x) Q_UNUSED(y) } void AbstractInterface::setIconName(QWindow *window, const QString &iconName) { Q_UNUSED(window) Q_UNUSED(iconName) } QString AbstractInterface::currentSeatName() { return QString(); } QString AbstractInterface::currentOutputName() { return QString(); } QList AbstractInterface::outputsInfo() { QList list; return list; } QList AbstractInterface::getWindowIdByPid(quint32 pid) { Q_UNUSED(pid) QList list; return list; } QList AbstractInterface::getWindowIdByTtile(const QString &title) { Q_UNUSED(title) QList list; return list; } libkysdk-applications/kysdk-waylandhelper/src/windowmanager/windowinfo.h0000664000175000017500000002405115104543305025751 0ustar fengfeng/* * libkysdk-waylandhelper's Library * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #ifndef WINDOWINFO_H #define WINDOWINFO_H #include #include #include namespace kdk { /** * @since 1.2.0 */ class WindowInfo { using WindowId = QVariant; public: WindowInfo() : m_handle(nullptr) , m_isValid(false) , m_isActive(false) , m_isMinimized(false) , m_isMaxVert(false) , m_isMaxHoriz(false) , m_isFullscreen(false) , m_isShaded(false) , m_isPlasmaDesktop(false) , m_isKeepAbove(false) , m_hasSkipTaskbar(false) , m_hasSkipSwitcher(false) , m_isOnAllDesktops(false) , m_isOnAllActivities(false) , m_isClosable(false) , m_isFullScreenable(false) , m_isGroupable(false) , m_isMaximizable(false) , m_isMinimizable(false) , m_isMovable(false) , m_isResizable(false) , m_isShadeable(false) , m_isVirtualDesktopsChangeable(false) , m_isDemandAttention(false) { } inline bool isPlasmaDesktop() const; inline void setIsPlasmaDesktop(bool isPlasmaDesktop); inline bool isValid() const; inline void setIsValid(bool isValid); inline bool isActive() const noexcept; inline void setIsActive(bool isActive) noexcept; inline bool isMaxVert() const; inline void setIsMaxVert(bool isMaxVert); inline bool isMaxHoriz() const; inline void setIsMaxHoriz(bool isMaxHoriz); inline WindowId wid() const; inline void setWid(const WindowId &wid); inline bool isKeepAbove() const; inline void setIsKeepAbove(bool isKeepAbove); inline bool isMinimized() const; inline void setIsMinimized(bool isMinimized); inline bool isMaximized() const; inline bool isFullscreen() const noexcept; inline void setIsFullscreen(bool isFullscreen) noexcept; inline bool isShaded() const noexcept; inline void setIsShaded(bool isShaded) noexcept; inline bool hasSkipTaskbar() const noexcept; inline void setHasSkipTaskbar(bool skipTaskbar) noexcept; inline bool hasSkipSwitcher() const noexcept; inline void setHasSkipSwitcher(bool skipSwitcher) noexcept; inline bool isOnAllDesktops() const noexcept; inline void setIsOnAllDesktops(bool alldesktops) noexcept; inline bool isOnAllActivities() const noexcept; inline void setIsOnAllActivities(bool allactivities) noexcept; // ability inline bool isCloseable() const noexcept; inline void setIsClosable(bool closable) noexcept; inline bool isFullScreenable() const noexcept; inline void setIsFullScreenable(bool fullscreenable) noexcept; inline bool isGroupable() const noexcept; inline void setIsGroupable(bool groupable) noexcept; inline bool isMaximizable() const; inline void setIsMaximizable(bool maximizable); inline bool isMinimizable() const; inline void setIsMinimizable(bool minimizable); inline bool isMovable() const noexcept; inline void setIsMovable(bool movable) noexcept; inline bool isResizable() const noexcept; inline void setIsResizable(bool resizable) noexcept; inline bool isShadeable() const noexcept; inline void setIsShadeable(bool shadeble) noexcept; inline bool isVirtualDesktopsChangeable() const noexcept; inline void setIsVirtualDesktopsChangeable(bool virtualdesktopchangeable) noexcept; inline QIcon icon() const noexcept; inline void setIcon(const QIcon &icon) noexcept; inline QStringList desktops() const noexcept; inline void setDesktops(const QStringList &desktops) noexcept; inline bool isOnDesktop(const QString &desktop) const noexcept; inline bool isDemandAttention() const noexcept; inline void setIsDemandAttention(bool demandAttention) noexcept; private: void *m_handle; bool m_isWayland; WindowId m_wid{0}; WindowId m_parentId{0}; QRect m_geometry; bool m_isValid : 1; bool m_isActive : 1; bool m_isMinimized : 1; bool m_isMaxVert : 1; bool m_isMaxHoriz : 1; bool m_isFullscreen : 1; bool m_isShaded : 1; bool m_isPlasmaDesktop : 1; bool m_isKeepAbove : 1; bool m_hasSkipTaskbar : 1; bool m_isOnAllDesktops : 1; bool m_isOnAllActivities : 1; bool m_hasSkipSwitcher : 1; //! BEGIN: Window Abilities bool m_isClosable : 1; bool m_isFullScreenable : 1; bool m_isGroupable : 1; bool m_isMaximizable : 1; bool m_isMinimizable : 1; bool m_isMovable : 1; bool m_isResizable : 1; bool m_isShadeable : 1; bool m_isVirtualDesktopsChangeable : 1; bool m_isDemandAttention : 1; QString m_appName; QString m_display; QIcon m_icon; QStringList m_desktops; QStringList m_activities; }; bool WindowInfo::isPlasmaDesktop() const { return m_isPlasmaDesktop; } void WindowInfo::setIsPlasmaDesktop(bool isPlasmaDesktop) { m_isPlasmaDesktop = isPlasmaDesktop; } bool WindowInfo::isValid() const { return m_isValid; } void WindowInfo::setIsValid(bool isValid) { m_isValid = isValid; } bool WindowInfo::isActive() const noexcept { return m_isActive; } void WindowInfo::setIsActive(bool isActive) noexcept { m_isActive = isActive; } bool WindowInfo::isMaxVert() const { return m_isMaxVert; } void WindowInfo::setIsMaxVert(bool isMaxVert) { m_isMaxVert = isMaxVert; } bool WindowInfo::isMaxHoriz() const { return m_isMaxHoriz; } void WindowInfo::setIsMaxHoriz(bool isMaxHoriz) { m_isMaxHoriz = isMaxHoriz; } WindowInfo::WindowId WindowInfo::wid() const { return m_wid; } void WindowInfo::setWid(const WindowId &wid) { m_wid = wid; } bool WindowInfo::isKeepAbove() const { return m_isKeepAbove; } void WindowInfo::setIsKeepAbove(bool isKeepAbove) { m_isKeepAbove = isKeepAbove; } bool WindowInfo::isMinimized() const { return m_isMinimized; } void WindowInfo::setIsMinimized(bool isMinimized) { m_isMinimized = isMinimized; } bool WindowInfo::isMaximized() const { return m_isMaxVert && m_isMaxHoriz; } bool WindowInfo::isFullscreen() const noexcept { return m_isFullscreen; } void WindowInfo::setIsFullscreen(bool isFullscreen) noexcept { m_isFullscreen = isFullscreen; } bool WindowInfo::isShaded() const noexcept { return m_isShaded; } void WindowInfo::setIsShaded(bool isShaded) noexcept { m_isShaded = isShaded; } bool WindowInfo::hasSkipTaskbar() const noexcept { return m_hasSkipTaskbar; } void WindowInfo::setHasSkipTaskbar(bool skipTaskbar) noexcept { m_hasSkipTaskbar = skipTaskbar; } inline bool WindowInfo::hasSkipSwitcher() const noexcept { return m_hasSkipSwitcher; } inline void WindowInfo::setHasSkipSwitcher(bool skipSwitcher) noexcept { m_hasSkipSwitcher = skipSwitcher; } bool WindowInfo::isOnAllDesktops() const noexcept { return m_isOnAllDesktops; } void WindowInfo::setIsOnAllDesktops(bool alldesktops) noexcept { m_isOnAllDesktops = alldesktops; } bool WindowInfo::isOnAllActivities() const noexcept { return m_isOnAllActivities; } void WindowInfo::setIsOnAllActivities(bool allactivities) noexcept { m_isOnAllActivities = allactivities; } bool WindowInfo::isCloseable() const noexcept { return m_isClosable; } void WindowInfo::setIsClosable(bool closable) noexcept { m_isClosable = closable; } bool WindowInfo::isFullScreenable() const noexcept { return m_isFullScreenable; } void WindowInfo::setIsFullScreenable(bool fullscreenable) noexcept { m_isFullScreenable = fullscreenable; } bool WindowInfo::isGroupable() const noexcept { return m_isGroupable; } void WindowInfo::setIsGroupable(bool groupable) noexcept { m_isGroupable = groupable; } bool WindowInfo::isMaximizable() const { return m_isMaximizable; } void WindowInfo::setIsMaximizable(bool maximizable) { m_isMaximizable = maximizable; } bool WindowInfo::isMinimizable() const { return m_isMinimizable; } void WindowInfo::setIsMinimizable(bool minimizable) { m_isMinimizable = minimizable; } bool WindowInfo::isOnDesktop(const QString &desktop) const noexcept { return m_isOnAllDesktops || m_desktops.contains(desktop); } bool WindowInfo::isDemandAttention() const noexcept { return m_isDemandAttention; } void WindowInfo::setIsDemandAttention(bool demandAttention) noexcept { m_isDemandAttention = demandAttention; } bool WindowInfo::isMovable() const noexcept { return m_isMovable; } void WindowInfo::setIsMovable(bool movable) noexcept { m_isMovable = movable; } bool WindowInfo::isResizable() const noexcept { return m_isResizable; } void WindowInfo::setIsResizable(bool resizable) noexcept { m_isResizable = resizable; } bool WindowInfo::isShadeable() const noexcept { return m_isShadeable; } void WindowInfo::setIsShadeable(bool shadeble) noexcept { m_isShadeable = shadeble; } bool WindowInfo::isVirtualDesktopsChangeable() const noexcept { return m_isVirtualDesktopsChangeable; } void WindowInfo::setIsVirtualDesktopsChangeable(bool virtualdesktopchangeable) noexcept { m_isVirtualDesktopsChangeable = virtualdesktopchangeable; } QIcon WindowInfo::icon() const noexcept { return m_icon; } void WindowInfo::setIcon(const QIcon &icon) noexcept { m_icon = icon; } QStringList WindowInfo::desktops() const noexcept { return m_desktops; } void WindowInfo::setDesktops(const QStringList &desktops) noexcept { m_desktops = desktops; } } #endif // WINDOWINFO_H ././@LongLink0000644000000000000000000000015000000000000011577 Lustar rootrootlibkysdk-applications/kysdk-waylandhelper/src/windowmanager/wayland-plasma-window-management-protocol.clibkysdk-applications/kysdk-waylandhelper/src/windowmanager/wayland-plasma-window-management-protoco0000664000175000017500000001336115104543305033356 0ustar fengfeng/* Generated by wayland-scanner 1.20.0 */ /* * libkysdk-waylandhelper's Library * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun */ #include #include #include "wayland-util.h" extern const struct wl_interface org_kde_plasma_activation_interface; extern const struct wl_interface org_kde_plasma_window_interface; extern const struct wl_interface wl_output_interface; extern const struct wl_interface wl_surface_interface; static const struct wl_interface *plasma_window_management_types[] = { NULL, NULL, NULL, NULL, &org_kde_plasma_window_interface, NULL, &org_kde_plasma_window_interface, NULL, &wl_surface_interface, NULL, NULL, NULL, NULL, &wl_surface_interface, &wl_output_interface, &org_kde_plasma_window_interface, &org_kde_plasma_activation_interface, }; static const struct wl_message org_kde_plasma_window_management_requests[] = { { "show_desktop", "u", plasma_window_management_types + 0 }, { "get_window", "nu", plasma_window_management_types + 4 }, { "get_window_by_uuid", "12ns", plasma_window_management_types + 6 }, }; static const struct wl_message org_kde_plasma_window_management_events[] = { { "show_desktop_changed", "u", plasma_window_management_types + 0 }, { "window", "u", plasma_window_management_types + 0 }, { "stacking_order_changed", "11a", plasma_window_management_types + 0 }, { "stacking_order_uuid_changed", "12s", plasma_window_management_types + 0 }, { "window_with_uuid", "13us", plasma_window_management_types + 0 }, }; WL_EXPORT const struct wl_interface org_kde_plasma_window_management_interface = { "org_kde_plasma_window_management", 15, 3, org_kde_plasma_window_management_requests, 5, org_kde_plasma_window_management_events, }; static const struct wl_message org_kde_plasma_window_requests[] = { { "set_state", "uu", plasma_window_management_types + 0 }, { "set_virtual_desktop", "u", plasma_window_management_types + 0 }, { "set_minimized_geometry", "ouuuu", plasma_window_management_types + 8 }, { "unset_minimized_geometry", "o", plasma_window_management_types + 13 }, { "close", "", plasma_window_management_types + 0 }, { "request_move", "3", plasma_window_management_types + 0 }, { "request_resize", "3", plasma_window_management_types + 0 }, { "destroy", "4", plasma_window_management_types + 0 }, { "get_icon", "7h", plasma_window_management_types + 0 }, { "request_enter_virtual_desktop", "8s", plasma_window_management_types + 0 }, { "request_enter_new_virtual_desktop", "8", plasma_window_management_types + 0 }, { "request_leave_virtual_desktop", "8s", plasma_window_management_types + 0 }, { "request_enter_activity", "14s", plasma_window_management_types + 0 }, { "request_leave_activity", "14s", plasma_window_management_types + 0 }, { "send_to_output", "15o", plasma_window_management_types + 14 }, }; static const struct wl_message org_kde_plasma_window_events[] = { { "title_changed", "s", plasma_window_management_types + 0 }, { "app_id_changed", "s", plasma_window_management_types + 0 }, { "state_changed", "u", plasma_window_management_types + 0 }, { "virtual_desktop_changed", "i", plasma_window_management_types + 0 }, { "themed_icon_name_changed", "s", plasma_window_management_types + 0 }, { "unmapped", "", plasma_window_management_types + 0 }, { "initial_state", "4", plasma_window_management_types + 0 }, { "parent_window", "5?o", plasma_window_management_types + 15 }, { "geometry", "6iiuu", plasma_window_management_types + 0 }, { "icon_changed", "7", plasma_window_management_types + 0 }, { "pid_changed", "u", plasma_window_management_types + 0 }, { "virtual_desktop_entered", "8s", plasma_window_management_types + 0 }, { "virtual_desktop_left", "8s", plasma_window_management_types + 0 }, { "application_menu", "10ss", plasma_window_management_types + 0 }, { "activity_entered", "14s", plasma_window_management_types + 0 }, { "activity_left", "14s", plasma_window_management_types + 0 }, }; WL_EXPORT const struct wl_interface org_kde_plasma_window_interface = { "org_kde_plasma_window", 15, 15, org_kde_plasma_window_requests, 16, org_kde_plasma_window_events, }; static const struct wl_message org_kde_plasma_activation_feedback_requests[] = { { "destroy", "", plasma_window_management_types + 0 }, }; static const struct wl_message org_kde_plasma_activation_feedback_events[] = { { "activation", "n", plasma_window_management_types + 16 }, }; WL_EXPORT const struct wl_interface org_kde_plasma_activation_feedback_interface = { "org_kde_plasma_activation_feedback", 1, 1, org_kde_plasma_activation_feedback_requests, 1, org_kde_plasma_activation_feedback_events, }; static const struct wl_message org_kde_plasma_activation_requests[] = { { "destroy", "", plasma_window_management_types + 0 }, }; static const struct wl_message org_kde_plasma_activation_events[] = { { "app_id", "s", plasma_window_management_types + 0 }, { "finished", "", plasma_window_management_types + 0 }, }; WL_EXPORT const struct wl_interface org_kde_plasma_activation_interface = { "org_kde_plasma_activation", 1, 1, org_kde_plasma_activation_requests, 2, org_kde_plasma_activation_events, }; libkysdk-applications/kysdk-waylandhelper/src/windowmanager/xcbinterface.h0000664000175000017500000000562515104543305026231 0ustar fengfeng/* * libkysdk-waylandhelper's Library * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #ifndef XCBINTERFACE_H #define XCBINTERFACE_H #include "abstractinterface.h" #include #include /** * @since 1.2.0 */ using namespace kdk; class XcbInterface : public AbstractInterface { public: XcbInterface(QObject *parent = nullptr); ~XcbInterface(); WindowInfo requestInfo(WindowId wid) override; void requestActivate(WindowId wid) override; void requestClose(WindowId wid) override; void requestToggleKeepAbove(WindowId wid) override; void requestToggleMinimized(WindowId wid) override; void requestToggleMaximized(WindowId wid) override; QIcon iconFor(WindowId wid) override; QString titleFor(WindowId wid) override; QString windowGroupFor(WindowId wid) override; void showCurrentDesktop() override; void hideCurrentDesktop() override; quint32 pid(WindowId wid) override; WindowId activeWindow() override; bool windowCanBeDragged(WindowId wid) override; bool windowCanBeMaximized(WindowId wid) override; void setGeometry(QWindow *window, const QRect &rect) override; void setSkipTaskBar(QWindow *window, bool skip) override; void setSkipSwitcher(QWindow *window, bool skip) override; bool skipTaskBar(const WindowId &wid) override; bool skipSwitcher(const WindowId &wid) override; bool isShowingDesktop() override; void setOnAllDesktops(const WindowId &wid) override; NET::WindowType windowType(WindowId wid) override; void setPanelTakefocus(QWindow *window, bool flag) override; void demandAttention(const WindowId &wid) override; QRect windowGeometry(const WindowId &windowId) override; void setWindowLayer(QWindow *window, WindowLayer layer) override; WindowLayer windowLayer(QWindow *window) override; QList getWindowIdByPid(quint32 pid) override; QList getWindowIdByTtile(const QString &title) override; private: bool isValidWindow(WindowId wid); bool isValidWindow(const KWindowInfo &winfo); void windowChangedProxy(WId wid, NET::Properties prop1, NET::Properties2 prop2); private: WindowId m_desktopId{-1}; }; #endif // XCBINTERFACE_H libkysdk-applications/kysdk-waylandhelper/src/windowmanager/windowmanager.h0000664000175000017500000002551715104543305026440 0ustar fengfeng/* * libkysdk-waylandhelper's Library * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #ifndef WINDOWMANAGER_H #define WINDOWMANAGER_H #include "windowinfo.h" #include "wmregister.h" #include #include #include namespace kdk { /** * @defgroup WindowManagerModule */ using WindowId = QVariant; /** * @brief 通常用于对窗口的一些操作 * @since 1.2.0 */ class WindowManager : public QObject { Q_OBJECT public: /** * @brief self * @return */ static WindowManager *self(); /** * @brief 获取窗口信息 * @param windowId * @return */ static WindowInfo getwindowInfo(const WindowId &windowId); /** * @brief 获取当前活动窗口 * @return */ static WindowId currentActiveWindow(); /** * @brief 置顶窗口 * @param windowId */ static void keepWindowAbove(const WindowId &windowId); /** * @brief 获取窗口标题 * @param windowId * @return */ static QString getWindowTitle(const WindowId &windowId); /** * @brief 获取窗口图标 * @param windowId * @return */ static QIcon getWindowIcon(const WindowId &windowId); /** * @brief 获取窗口所在组的组名 * @param windowId * @return */ static QString getWindowGroup(const WindowId &windowId); /** * @brief 关闭窗口 * @param windowId */ static void closeWindow(const WindowId &windowId); /** * @brief 激活窗口 * @param windowId */ static void activateWindow(const WindowId &windowId); /** * @brief 最大化窗口 * @param windowId */ static void maximizeWindow(const WindowId &windowId); /** * @brief 最小化窗口 * @param windowId */ static void minimizeWindow(const WindowId &windowId); /** * @brief 获取窗口进程pid * @return */ static quint32 getPid(const WindowId &windowId); /** * @brief 显示当前桌面 */ static void showDesktop(); /** * @brief 取消显示当前桌面 */ static void hideDesktop(); /** * @brief 获取当前桌面的名称 * @return */ static QString currentDesktop(); /** * @brief 获取当前窗口列表 * @return */ static QList windows(); /** * @brief 获取窗口类型,仅适用于X环境下,wayland下统一返回normal * @param windowId * @return */ static NET::WindowType getWindowType(const WindowId &windowId); /** * @brief 设置窗口位置 * @param window * @param rect */ static void setGeometry(QWindow *window, const QRect &rect); /** * @brief 设置是否跳过任务栏 * @since 2.0.2.1 * @param window * @param skip */ static void setSkipTaskBar(QWindow *window, bool skip); /** * @brief 设置是否跳过窗口选择 * @since 2.0.2.1 * @param window * @param skip */ static void setSkipSwitcher(QWindow *window, bool skip); /** * @brief 判断窗体是否跳过任务栏 * @since 2.0.2.1 * @param windowId * @return */ static bool skipTaskBar(const WindowId &windowId); /** * @brief 判断窗体是否跳过窗口选择 * @since 2.0.2.1 * @param windowId * @return */ static bool skipSwitcher(const WindowId &windowId); /** * @brief 判断桌面是否处于显示状态 * @since 2.0.2.1 * @return */ static bool isShowingDesktop(); /** * @brief 设置窗口在所有桌面中显示 * @since 2.0.2.1 * @param wid */ static void setOnAllDesktops(const WindowId &windowId); /** * @brief 判断窗口在所有桌面中显示 * @since 2.0.2.1 * @param windowId * @return */ static bool isOnAllDesktops(const WindowId &windowId); /** * @brief 判断窗口是否在当前桌面 * @param 窗口id * @since 2.1.1.0 * @return */ static bool isOnCurrentDesktop(const WindowId &id); /** * @brief 判断窗口是否在指定桌面 * @param 窗口id * @param 桌面id * @since 2.1.1.0 * @return */ static bool isOnDesktop(const WindowId &id, int desktop); /** * @brief 设置panel属性窗体是否获取焦点,仅wayland环境下生效 * @since 2.3.1.0 * @param window * @param flag */ static void setPanelTakefocus(QWindow *window, bool flag); /** * @brief 发送demandAttention状态 * @since 2.3.1.0 * @param wid */ static void demandAttention(const WindowId &wid); /** * @brief 获取窗口所属的进程名称 * @since 2.3.1.0 * @param windowId * @return */ static QString getProcessName(const WindowId &windowId); /** * @brief setWindowRadius * @since 2.5.1.0 * @param window * @param radius */ static void setWindowRadius(QWindow *window, int radius); /** * @brief activateWindow * @since 2.5.1.0 * @param window1 * @param window2 */ static void activateWindow(QWindow *window1, QWindow *window2); /** * @brief windowGeometry * @since 2.5.1.0 * @param windowId * @return */ static QRect windowGeometry(const WindowId &windowId); /** * @brief setPanelAutoHide * @since 2.5.1.0 * @param window * @param autoHide */ static void setPanelAutoHide(QWindow *window, bool autoHide); /** * @brief setGrabKeyboard * @since 2.5.1.0 * @param window * @param grabKeyboard */ static void setGrabKeyboard(QWindow *window, bool grabKeyboard); /** * @brief setWindowLayer * @since 2.5.1.0 * @param window * @param layer */ static void setWindowLayer(QWindow *window, WindowLayer layer); /** * @brief windowLayer * @since 2.5.1.0 * @param window * @return */ static WindowLayer windowLayer(QWindow *window); /** * @brief setHighlight * @since 2.5.1.0 * @param wid * @param highlight */ static void setHighlight(const WindowId &wid, bool highlight); /** * @brief isHightlight * @since 2.5.1.0 * @param wid */ static bool isHightlight(const WindowId &wid); /** * @brief setOpenUnderCursor * @since 2.5.1.0 * @param window */ static void setOpenUnderCursor(QWindow *window); /** * @brief setOpenUnderCursor * @since 2.5.1.0 * @param window * @param x * @param y */ static void setOpenUnderCursor(QWindow *window, int x, int y); /** * @brief setIconName * @since 2.5.1.0 * @param window * @param iconName */ static void setIconName(QWindow *window, const QString &iconName); /** * @brief currentSeatName * @since 2.5.1.0 * @return */ static QString currentSeatName(); /** * @brief currentOutputName * @since 2.5.1.0 * @return */ static QString currentOutputName(); /** * @brief outputsInfo * @since 2.5.1.0 * @return */ static QList outputsInfo(); /** * @brief getWindowIdByPid * @since 2.5.1.0 * @return */ static QList getWindowIdByPid(quint32 pid); /** * @brief getWindowIdByTtile * @since 2.5.1.0 * @return */ static QList getWindowIdByTtile(const QString &title); Q_SIGNALS: /** * @brief 窗口添加信号 * @param windowId */ void windowAdded(const WindowId &windowId); /** * @brief 窗口删除信号 * @param windowId */ void windowRemoved(const WindowId &windowId); /** * @brief 活动窗口改变信号 * @param wid */ void activeWindowChanged(const WindowId &wid); /** * @brief 窗口改变信号 * @param wid */ void windowChanged(const WindowId &wid); /** * @brief 当前桌面改变信号 * @param wid */ void currentDesktopChanged(); /** * @brief 桌面显示状态变化信号 */ void isShowingDesktopChanged(); /** * @brief 窗口标题改变信号 * @since 2.3.1.0 * @param wid */ void titleChanged(const WindowId &wid); /** * @brief 窗口图标改变信号 * @since 2.3.1.0 * @param wid */ void iconChanged(const WindowId &wid); /** * @brief 窗口活动状态改变信号 * @since 2.3.1.0 * @param wid */ void activeChanged(const WindowId &wid); /** * @brief 窗口全屏状态改变信号 * @since 2.3.1.0 * @param wid */ void fullscreenChanged(const WindowId &wid); /** * @brief 窗口置顶状态改变信号 * @since 2.3.1.0 * @param wid */ void keepAboveChanged(const WindowId &wid); /** * @brief 窗口最小化状态改变信号 * @since 2.3.1.0 * @param wid */ void minimizedChanged(const WindowId &wid); /** * @brief 窗口最大化状态改变信号 * @since 2.3.1.0 * @param wid */ void maximizedChanged(const WindowId &wid); /** * @brief onAllDesktopsChanged * @since 2.3.1.0 * @param wid */ void onAllDesktopsChanged(const WindowId &wid); /** * @brief demandsAttention状态改变信号 * @since 2.3.1.0 * @param wid */ void demandsAttentionChanged(const WindowId &wid); /** * @brief 跳过任务栏状态改变信号 * @since 2.3.1.0 * @param wid */ void skipTaskbarChanged(const WindowId &wid); /** * @brief 跳过窗口选择器状态改变信号 * @since 2.3.1.0 * @param wid */ void skipSwitcherChanged(const WindowId &wid); /** * @brief 窗口位置改变信号 * @since 2.3.1.0 * @param wid */ void geometryChanged(const WindowId &wid); /** * @brief 屏幕信息改变信号 * @since 2.5.1.0 */ void outputInfoChanged(OutputInfo *); private: WindowManager(QObject *parent = nullptr); }; } #endif // WINDOWMANAGER_H libkysdk-applications/kysdk-waylandhelper/src/windowmanager/outputinfo.h0000664000175000017500000000244715104543305026007 0ustar fengfeng/* * libkysdk-waylandhelper's Library * * Copyright (C) 2024, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #ifndef OUTPUTINFO_H #define OUTPUTINFO_H #include #include /** * @since 2.5.1.0 */ class OutputInfo : public QObject { Q_OBJECT public: ~OutputInfo(); QString outputName(); QRect usableArea(); private: explicit OutputInfo(QObject *parent = nullptr); void setOutputName(const QString &outputName); void setUsableArea(const QRect &usableArea); friend class OutputUsableAreaManager; class Private; QScopedPointer d; }; #endif // OUTPUTINFO_H libkysdk-applications/kysdk-waylandhelper/src/windowmanager/xdgactivation.h0000664000175000017500000000470415104543305026435 0ustar fengfeng/* * libkysdk-waylandhelper's Library * * Copyright (C) 2024, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #ifndef XDGACTIVATION_H #define XDGACTIVATION_H #include #include #include #include #include "wayland-xdg-activation-v1-client-protocol.h" /** * @since 2.5.1.0 */ using namespace KWayland::Client; class XdgActivationToken; class XdgActivation : public QObject { Q_OBJECT public: explicit XdgActivation(QObject *parent = nullptr); ~XdgActivation(); bool isValid() const; void release(); void destroy(); void setup(xdg_activation_v1 *activation); void setEventQueue(EventQueue *queue); EventQueue *eventQueue(); operator xdg_activation_v1 *(); operator xdg_activation_v1 *() const; XdgActivationToken *getXdgActivationToken(); XdgActivationToken *requestXdgActivationToken(wl_seat *seat, Surface *surface, uint32_t serial, const QString &app_id); void activateWindow(const QString &token, Surface *surface); private: class Private; QScopedPointer d; }; class XdgActivationToken : public QObject { Q_OBJECT public: explicit XdgActivationToken(QObject *parent = nullptr); ~XdgActivationToken(); bool isValid() const; void release(); void destroy(); void setup(xdg_activation_token_v1 *token); void set_serial(uint32_t serial, wl_seat *seat); void set_app_id(const QString &app_id); void set_surface(Surface *surface); void commit(); operator xdg_activation_token_v1 *(); operator xdg_activation_token_v1 *() const; Q_SIGNALS: void done(const QString &token); private: class Private; QScopedPointer d; }; #endif // XDGACTIVATION_H libkysdk-applications/kysdk-waylandhelper/src/windowmanager/xcbinterface.cpp0000664000175000017500000006445615104543305026573 0ustar fengfeng/* * libkysdk-waylandhelper's Library * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #include "xcbinterface.h" #include "kwindowinfo.h" #include "kyatoms_p.h" #include #include #include #include #include #include #include #include // #include #include #include #include #ifndef STRNLEN_MAX #define STRNLEN_MAX 1024 * 1024 * 1024 #endif #include // 为 QVariant 定义 operator< inline bool operator<(const QVariant &v1, const QVariant &v2) { // 如果类型相同,直接比较 if (v1.userType() == v2.userType()) { switch (v1.userType()) { case QMetaType::Int: return v1.toInt() < v2.toInt(); case QMetaType::UInt: return v1.toUInt() < v2.toUInt(); case QMetaType::LongLong: return v1.toLongLong() < v2.toLongLong(); case QMetaType::ULongLong: return v1.toULongLong() < v2.toULongLong(); case QMetaType::Double: return v1.toDouble() < v2.toDouble(); case QMetaType::Float: return v1.toFloat() < v2.toFloat(); case QMetaType::QString: return v1.toString() < v2.toString(); case QMetaType::QByteArray: return v1.toByteArray() < v2.toByteArray(); default: break; } } // 类型不同时,按类型编号比较,然后按字符串比较 if (v1.userType() != v2.userType()) { return v1.userType() < v2.userType(); } // 最后回退到字符串比较 return v1.toString() < v2.toString(); } class KylinAtoms : public QSharedData { public: explicit KylinAtoms(xcb_connection_t *c); xcb_atom_t atom(KyAtom atom) const { return m_atoms[atom]; } xcb_connection_t *m_connection; private: void init(); xcb_atom_t m_atoms[KyAtomCount]; }; typedef QHash> AtomHash; Q_GLOBAL_STATIC(AtomHash, s_gAtomsHash) static QSharedDataPointer atomsForConnection(xcb_connection_t *c) { auto it = s_gAtomsHash->constFind(c); if (it == s_gAtomsHash->constEnd()) { QSharedDataPointer atom(new KylinAtoms(c)); s_gAtomsHash->insert(c, atom); return atom; } return it.value(); } class KyWinInfo { public: explicit KyWinInfo(xcb_connection_t *c, xcb_window_t w) { atoms = atomsForConnection(c); connection = c; window = w; } xcb_atom_t atom(KyAtom atom) const { return atoms->atom(atom); } void setWindowLayer(WindowLayer layer); QSharedDataPointer atoms; xcb_connection_t *connection; xcb_window_t window; }; xcb_connection_t *getXcbConnection() { static xcb_connection_t *connection = nullptr; if (!connection) { connection = xcb_connect(nullptr, nullptr); // 连接到默认显示器 if (xcb_connection_has_error(connection)) { xcb_disconnect(connection); connection = nullptr; } } return connection; } xcb_window_t getRootWindow() { xcb_connection_t *connection = getXcbConnection(); if (!connection) return 0; const xcb_setup_t *setup = xcb_get_setup(connection); xcb_screen_iterator_t iter = xcb_setup_roots_iterator(setup); xcb_screen_t *screen = iter.data; return screen ? screen->root : 0; } void KyWinInfo::setWindowLayer(WindowLayer layer) { int len; uint32_t data[2]; switch (layer) { case WindowLayer::Panel: data[0] = this->atom(_NET_WM_WINDOW_TYPE_DOCK); data[1] = XCB_NONE; len = 1; break; case WindowLayer::Desktop: data[0] = this->atom(_NET_WM_WINDOW_TYPE_DESKTOP); data[1] = XCB_NONE; len = 1; break; case WindowLayer::ToolTip: data[0] = this->atom(_NET_WM_WINDOW_TYPE_TOOLTIP); data[1] = XCB_NONE; len = 1; break; case WindowLayer::Notification: data[0] = this->atom(_NET_WM_WINDOW_TYPE_NOTIFICATION); data[1] = this->atom(_NET_WM_WINDOW_TYPE_UTILITY); // fallback (utility seems to be the best) len = 1; break; case WindowLayer::OnScreenDisplay: data[0] = this->atom(_KDE_NET_WM_WINDOW_TYPE_ON_SCREEN_DISPLAY); data[1] = this->atom(_NET_WM_WINDOW_TYPE_NOTIFICATION); len = 2; break; case WindowLayer::CriticalNotification: data[0] = this->atom(_KDE_NET_WM_WINDOW_TYPE_CRITICAL_NOTIFICATION); data[1] = this->atom(_NET_WM_WINDOW_TYPE_NOTIFICATION); len = 2; break; case WindowLayer::AppletPop: data[0] = this->atom(_KDE_NET_WM_WINDOW_TYPE_APPLET_POPUP); data[1] = XCB_NONE; len = 1; break; // UKUI extensions case WindowLayer::SystemWindow: data[0] = this->atom(_UKUI_NET_WM_WINDOW_TYPE_SYSTEMWINDOW); data[1] = XCB_NONE; len = 1; break; case WindowLayer::InputPanel: data[0] = this->atom(_UKUI_NET_WM_WINDOW_TYPE_INPUTPANEL); data[1] = XCB_NONE; len = 1; break; case WindowLayer::Logout: data[0] = this->atom(_UKUI_NET_WM_WINDOW_TYPE_LOGOUT); data[1] = XCB_NONE; len = 1; break; case WindowLayer::ScreenLock: data[0] = this->atom(_UKUI_NET_WM_WINDOW_TYPE_SCREENLOCK); data[1] = XCB_NONE; len = 1; break; case WindowLayer::ScreenLockNotification: data[0] = this->atom(_UKUI_NET_WM_WINDOW_TYPE_SCREENLOCKNOTIFICATION); data[1] = XCB_NONE; len = 1; break; case WindowLayer::Watermark: data[0] = this->atom(_UKUI_NET_WM_WINDOW_TYPE_WATERMARK); data[1] = XCB_NONE; len = 1; break; default: case WindowLayer::Normal: data[0] = this->atom(_NET_WM_WINDOW_TYPE_NORMAL); data[1] = XCB_NONE; len = 1; break; } xcb_change_property(this->connection, XCB_PROP_MODE_REPLACE, this->window, atom(_NET_WM_WINDOW_TYPE), XCB_ATOM_ATOM, 32, len, (const void *)&data); } KylinAtoms::KylinAtoms(xcb_connection_t *c) : QSharedData() , m_connection(c) { for (int i = 0; i < KyAtomCount; ++i) { m_atoms[i] = XCB_ATOM_NONE; } init(); } XcbInterface::XcbInterface(QObject *parent) : AbstractInterface(parent) { m_currentDesktop = QString::number(KX11Extras::self()->currentDesktop()); connect(KWindowSystem::self(), &KWindowSystem::showingDesktopChanged, this, &AbstractInterface::isShowingDesktopChanged); // connect(KWindowSystem::self(), &KX11Extras::activeWindowChanged, this, &AbstractInterface::activeWindowChanged); connect(KX11Extras::self(), &KX11Extras::activeWindowChanged, this, [=](WId window) { emit activeWindowChanged(static_cast(window)); }); connect(KX11Extras::self(), &KX11Extras::windowAdded, this, [=](WId wid) { kdk::WindowId window = static_cast(wid); if (!m_windows.contains(window)) { m_windows.insert(window, this->requestInfo(window)); } emit windowAdded(window); }); connect(KX11Extras::self(), &KX11Extras::windowRemoved, this, [=](WId wid) { kdk::WindowId window = static_cast(wid); m_windows.remove(window); emit windowRemoved(window); }); connect(KX11Extras::self(), &KX11Extras::currentDesktopChanged, this, [&](int desktop) { m_currentDesktop = QString::number(desktop); emit currentDesktopChanged(); }); // connect(KWindowSystem::self(), static_cast(&KWindowSystem::windowChanged), this, &XcbInterface::windowChangedProxy); // connect(KWindowSystem::self(), &KWindowSystem::activeWindowChanged, this, &AbstractInterface::activeChanged); connect(KX11Extras::self(), &KX11Extras::windowChanged, this, &XcbInterface::windowChangedProxy); connect(KX11Extras::self(), &KX11Extras::activeWindowChanged, this, &AbstractInterface::activeChanged); } XcbInterface::~XcbInterface() { } WindowInfo XcbInterface::requestInfo(WindowId wid) { const KWindowInfo winfo{wid.value(), NET::WMFrameExtents | NET::WMWindowType | NET::WMGeometry | NET::WMDesktop | NET::WMState | NET::WMName | NET::WMVisibleName, NET::WM2WindowClass | NET::WM2Activities | NET::WM2AllowedActions | NET::WM2TransientFor}; bool isDesktop{false}; if (winfo.windowClassName() == "plasmashell" && isPlasmaDesktop(winfo.geometry())) { isDesktop = true; this->setPlasmaDesktop(wid); } WindowInfo windowInfo; if (!winfo.valid()) { windowInfo.setIsValid(false); windowInfo.setHasSkipTaskbar(winfo.hasState(NET::SkipTaskbar)); windowInfo.setHasSkipSwitcher(winfo.hasState(NET::SkipSwitcher)); } else if (isValidWindow(winfo) && !isDesktop) { windowInfo.setIsValid(true); windowInfo.setWid(wid); windowInfo.setIsPlasmaDesktop(false); windowInfo.setIsActive(KX11Extras::activeWindow() == wid.value()); windowInfo.setIsMinimized(winfo.hasState(NET::Hidden)); windowInfo.setIsMaxVert(winfo.hasState(NET::MaxVert)); windowInfo.setIsMaxHoriz(winfo.hasState(NET::MaxHoriz)); windowInfo.setIsFullscreen(winfo.hasState(NET::FullScreen)); windowInfo.setIsShaded(winfo.hasState(NET::Shaded)); windowInfo.setIsOnAllDesktops(winfo.onAllDesktops()); windowInfo.setIsOnAllActivities(winfo.activities().empty()); windowInfo.setIsKeepAbove(winfo.hasState(NET::KeepAbove)); windowInfo.setHasSkipTaskbar(winfo.hasState(NET::SkipTaskbar)); windowInfo.setIsDemandAttention(winfo.hasState(NET::DemandsAttention)); windowInfo.setHasSkipSwitcher(winfo.hasState(NET::SkipSwitcher)); //! Window Abilities windowInfo.setIsClosable(winfo.actionSupported(NET::ActionClose)); windowInfo.setIsFullScreenable(winfo.actionSupported(NET::ActionFullScreen)); windowInfo.setIsMaximizable(winfo.actionSupported(NET::ActionMax)); windowInfo.setIsMinimizable(winfo.actionSupported(NET::ActionMinimize)); windowInfo.setIsMovable(winfo.actionSupported(NET::ActionMove)); windowInfo.setIsResizable(winfo.actionSupported(NET::ActionResize)); windowInfo.setIsShadeable(winfo.actionSupported(NET::ActionShade)); windowInfo.setIsVirtualDesktopsChangeable(winfo.actionSupported(NET::ActionChangeDesktop)); //! Window Abilities windowInfo.setDesktops({QString::number(winfo.desktop())}); } else if (m_desktopId == wid) { windowInfo.setIsValid(true); windowInfo.setIsPlasmaDesktop(true); windowInfo.setWid(wid); windowInfo.setHasSkipTaskbar(true); //! Window Abilities windowInfo.setIsClosable(false); windowInfo.setIsFullScreenable(false); windowInfo.setIsGroupable(false); windowInfo.setIsMaximizable(false); windowInfo.setIsMinimizable(false); windowInfo.setIsMovable(false); windowInfo.setIsResizable(false); windowInfo.setIsShadeable(false); windowInfo.setIsVirtualDesktopsChangeable(false); //! Window Abilities } return windowInfo; } void XcbInterface::requestActivate(WindowId wid) { KX11Extras::activateWindow(wid.toInt()); } void XcbInterface::requestClose(WindowId wid) { WindowInfo wInfo = requestInfo(wid); if (!wInfo.isValid() || wInfo.isPlasmaDesktop()) { return; } NETRootInfo ri(getXcbConnection(), NET::CloseWindow); ri.closeWindowRequest(wInfo.wid().toUInt()); } void XcbInterface::requestToggleKeepAbove(WindowId wid) { WindowInfo wInfo = requestInfo(wid); if (!wInfo.isValid() || wInfo.isPlasmaDesktop()) { return; } NETWinInfo ni(getXcbConnection(), wid.toUInt(), getRootWindow(), NET::WMState, NET::Properties2()); if (wInfo.isKeepAbove()) { ni.setState(NET::States(), NET::KeepAbove); } else { ni.setState(NET::KeepAbove, NET::KeepAbove); } } void XcbInterface::requestToggleMinimized(WindowId wid) { WindowInfo wInfo = requestInfo(wid); if (!wInfo.isValid() || wInfo.isPlasmaDesktop() || !inCurrentDesktopActivity(wInfo)) { return; } if (wInfo.isMinimized()) { bool onCurrent = wInfo.isOnDesktop(m_currentDesktop); KX11Extras::unminimizeWindow(wid.toUInt()); if (onCurrent) { KX11Extras::forceActiveWindow(wid.toUInt()); } } else { KX11Extras::minimizeWindow(wid.toUInt()); } } void XcbInterface::requestToggleMaximized(WindowId wid) { WindowInfo wInfo = requestInfo(wid); if (!windowCanBeMaximized(wid) || !inCurrentDesktopActivity(wInfo)) { return; } bool restore = wInfo.isMaxHoriz() && wInfo.isMaxVert(); if (wInfo.isMinimized()) { KX11Extras::unminimizeWindow(wid.toUInt()); } NETWinInfo ni(getXcbConnection(), wid.toUInt(), getRootWindow(), NET::WMState, NET::Properties2()); if (restore) { ni.setState(NET::States(), NET::Max); } else { ni.setState(NET::Max, NET::Max); } } QIcon XcbInterface::iconFor(WindowId wid) { QIcon icon; icon.addPixmap(KX11Extras::icon(wid.value(), KIconLoader::SizeSmall, KIconLoader::SizeSmall, false)); icon.addPixmap(KX11Extras::icon(wid.value(), KIconLoader::SizeSmallMedium, KIconLoader::SizeSmallMedium, false)); icon.addPixmap(KX11Extras::icon(wid.value(), KIconLoader::SizeMedium, KIconLoader::SizeMedium, false)); icon.addPixmap(KX11Extras::icon(wid.value(), KIconLoader::SizeLarge, KIconLoader::SizeLarge, false)); icon.addPixmap(KX11Extras::icon(wid.value(), KIconLoader::SizeHuge, KIconLoader::SizeHuge, false)); icon.addPixmap(KX11Extras::icon(wid.value(), KIconLoader::SizeEnormous, KIconLoader::SizeEnormous, false)); return icon; } QString XcbInterface::titleFor(WindowId wid) { const KWindowInfo winfo{wid.value(), NET::WMName}; if (winfo.valid()) return winfo.name(); else return QString(); } QString XcbInterface::windowGroupFor(WindowId wid) { KWindowInfo winfo(wid.toULongLong(), NET::WMName, NET::WM2WindowClass); if (winfo.valid()) return winfo.windowClassClass(); else return QString(); } void XcbInterface::showCurrentDesktop() { KWindowSystem::setShowingDesktop(true); } void XcbInterface::hideCurrentDesktop() { KWindowSystem::setShowingDesktop(false); } quint32 XcbInterface::pid(WindowId wid) { quint64 pid = 0; const KWindowInfo winfo{wid.value(), NET::WMName}; if (!winfo.valid()) return pid; else { pid = winfo.pid(); } return pid; } WindowId XcbInterface::activeWindow() { WId wid = KX11Extras::self()->activeWindow(); return QVariant::fromValue(wid); } bool XcbInterface::windowCanBeDragged(WindowId wid) { WindowInfo winfo = requestInfo(wid); return (winfo.isValid() && !winfo.isMinimized() && winfo.isMovable() && inCurrentDesktopActivity(winfo) && !winfo.isPlasmaDesktop()); } bool XcbInterface::windowCanBeMaximized(WindowId wid) { WindowInfo winfo = requestInfo(wid); return (winfo.isValid() && !winfo.isMinimized() && winfo.isMaximizable() && inCurrentDesktopActivity(winfo) && !winfo.isPlasmaDesktop()); } void XcbInterface::setGeometry(QWindow *window, const QRect &rect) { if (window) window->setGeometry(rect); } void XcbInterface::setSkipTaskBar(QWindow *window, bool skip) { if (skip) KX11Extras::setState(window->winId(), NET::SkipTaskbar); else KX11Extras::clearState(window->winId(), NET::SkipTaskbar); } void XcbInterface::setSkipSwitcher(QWindow *window, bool skip) { if (skip) KX11Extras::setState(window->winId(), NET::SkipSwitcher); else KX11Extras::clearState(window->winId(), NET::SkipSwitcher); } bool XcbInterface::skipTaskBar(const WindowId &wid) { const KWindowInfo winfo(wid.value(), NET::WMState); return winfo.hasState(NET::SkipTaskbar); } bool XcbInterface::skipSwitcher(const WindowId &wid) { const KWindowInfo winfo(wid.value(), NET::WMState); return winfo.hasState(NET::SkipSwitcher); } bool XcbInterface::isShowingDesktop() { return KWindowSystem::showingDesktop(); } void XcbInterface::setOnAllDesktops(const WindowId &wid) { WindowInfo wInfo = requestInfo(wid); if (!wInfo.isValid()) { return; } if (KX11Extras::numberOfDesktops() <= 1) { return; } if (wInfo.isOnAllDesktops()) { KX11Extras::setOnDesktop(wid.toUInt(), KX11Extras::currentDesktop()); KX11Extras::forceActiveWindow(wid.toUInt()); } else { KX11Extras::setOnAllDesktops(wid.toUInt(), true); } } void XcbInterface::setPanelTakefocus(QWindow *window, bool flag) { // do nothing return; } NET::WindowType XcbInterface::windowType(WindowId wid) { KWindowInfo info(wid.value(), NET::WMWindowType | NET::WMState, NET::WM2TransientFor); return info.windowType(NET::AllTypesMask); } void XcbInterface::demandAttention(const WindowId &wid) { // KWindowSystem::demandAttention(wid.value()); #ifdef Q_OS_LINUX if (QGuiApplication::platformName() != "xcb") return; xcb_connection_t *connection = getXcbConnection(); if (!connection) return; auto getAtom = [connection](const char *name) -> xcb_atom_t { xcb_intern_atom_cookie_t cookie = xcb_intern_atom(connection, 0, strlen(name), name); xcb_intern_atom_reply_t *reply = xcb_intern_atom_reply(connection, cookie, nullptr); if (!reply) return 0; xcb_atom_t atom = reply->atom; free(reply); return atom; }; xcb_atom_t net_wm_state = getAtom("_NET_WM_STATE"); xcb_atom_t demands_attention = getAtom("_NET_WM_STATE_DEMANDS_ATTENTION"); if (!net_wm_state || !demands_attention) return; xcb_client_message_event_t event{}; event.response_type = XCB_CLIENT_MESSAGE; event.format = 32; event.window = wid.value(); event.type = net_wm_state; event.data.data32[0] = 1; // _NET_WM_STATE_ADD event.data.data32[1] = demands_attention; event.data.data32[2] = 0; event.data.data32[3] = 0; event.data.data32[4] = 0; xcb_send_event(connection, 0, getRootWindow(), XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT | XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY, reinterpret_cast(&event)); xcb_flush(connection); #endif } QRect XcbInterface::windowGeometry(const WindowId &windowId) { KWindowInfo info(windowId.value(), NET::WMGeometry); if (info.valid()) return info.geometry(); else return QRect(); } void XcbInterface::setWindowLayer(QWindow *window, WindowLayer layer) { if (!window) return; KyWinInfo info(getXcbConnection(), window->winId()); info.setWindowLayer(layer); } WindowLayer XcbInterface::windowLayer(QWindow *window) { if (!window) return WindowLayer::Normal; WindowLayer layer; KWindowInfo info(window->winId(), NET::WMWindowType | NET::WMState, NET::WM2TransientFor); switch (info.windowType(NET::AllTypesMask)) { case NET::Normal: layer = WindowLayer::Normal; break; case NET::Desktop: layer = WindowLayer::Desktop; break; case NET::Dock: { layer = WindowLayer::Panel; qWarning() << "NET::Dock replaced by WindowLayer::Panel"; break; } case NET::Toolbar: { layer = WindowLayer::Normal; qWarning() << "NET::Toolbar replaced by WindowLayer::Normal"; break; } case NET::Menu: { layer = WindowLayer::AppletPop; qWarning() << "NET::Menu replaced by WindowLayer::AppletPop"; break; } case NET::Dialog: layer = WindowLayer::Normal; qWarning() << "NET::Dialog replaced by WindowLayer::Normal"; break; case NET::Override: layer = WindowLayer::Normal; qWarning() << "NET::Override replaced by WindowLayer::Normal"; break; case NET::Utility: layer = WindowLayer::Normal; qWarning() << "NET::Utility replaced by WindowLayer::Normal"; break; case NET::Splash: layer = WindowLayer::Normal; qWarning() << "NET::Splash replaced by WindowLayer::Normal"; break; case NET::DropdownMenu: layer = WindowLayer::AppletPop; qWarning() << "NET::DropdownMenu replaced by WindowLayer::AppletPop"; break; case NET::PopupMenu: layer = WindowLayer::AppletPop; qWarning() << "NET::PopupMenu replaced by WindowLayer::AppletPop"; break; case NET::Tooltip: layer = WindowLayer::ToolTip; break; case NET::Notification: layer = WindowLayer::Notification; break; case NET::ComboBox: layer = WindowLayer::Normal; qWarning() << "NET::Dialog replaced by WindowLayer::Normal"; break; case NET::DNDIcon: layer = WindowLayer::Normal; qWarning() << "NET::DNDIcon replaced by WindowLayer::Normal"; break; case NET::OnScreenDisplay: layer = WindowLayer::OnScreenDisplay; break; case NET::CriticalNotification: layer = WindowLayer::CriticalNotification; break; case NET::AppletPopup: layer = WindowLayer::AppletPop; break; default: layer = WindowLayer::Normal; break; } return layer; } QList XcbInterface::getWindowIdByPid(quint32 p) { QList list; for (auto windowId : windows()) { if (pid(windowId) == p) { list.append(windowId); } } return list; } QList XcbInterface::getWindowIdByTtile(const QString &title) { QList list; for (auto windowId : windows()) { if (titleFor(windowId) == title) { list.append(windowId); } } return list; } bool XcbInterface::isValidWindow(WindowId wid) { if (this->isValidFor(wid)) { return true; } const KWindowInfo winfo{wid.value(), NET::WMWindowType | NET::WMState}; return isValidWindow(winfo); } bool XcbInterface::isValidWindow(const KWindowInfo &winfo) { if (this->isValidFor(winfo.win())) { return true; } if (m_desktopId == winfo.win()) { return false; } bool hasSkipTaskbar = winfo.hasState(NET::SkipTaskbar); bool hasSkipPager = winfo.hasState(NET::SkipPager); bool isSkipped = hasSkipTaskbar && hasSkipPager; return !isSkipped; } void XcbInterface::windowChangedProxy(WId wid, NET::Properties prop1, NET::Properties2 prop2) { if (prop1 == 0 && !(prop2 & (NET::WM2Activities | NET::WM2TransientFor))) { return; } if (!isValidWindow(wid)) { return; } emit windowChanged(wid); const KWindowInfo info(wid, prop1, prop2); WindowInfo kInfo = m_windows.value(wid); if (prop1.testFlag(NET::WMState) && kInfo.isValid()) { if (info.hasState(NET::State::FullScreen) != kInfo.isFullscreen()) { kInfo.setIsFullscreen(info.hasState(NET::State::FullScreen)); emit fullscreenChanged(wid); } if (info.hasState(NET::State::KeepAbove) != kInfo.isKeepAbove()) { kInfo.setIsKeepAbove(info.hasState(NET::State::KeepAbove)); emit keepAboveChanged(wid); } if (info.hasState(NET::State::SkipSwitcher) != kInfo.hasSkipSwitcher()) { kInfo.setHasSkipSwitcher(info.hasState(NET::State::SkipSwitcher)); emit skipSwitcherChanged(wid); } if (info.hasState(NET::State::SkipTaskbar) != kInfo.hasSkipTaskbar()) { kInfo.setHasSkipTaskbar(info.hasState(NET::State::SkipTaskbar)); emit skipTaskbarChanged(wid); } if (info.hasState(NET::State::DemandsAttention) != kInfo.isDemandAttention()) { kInfo.setIsDemandAttention(info.hasState(NET::State::DemandsAttention)); emit demandsAttentionChanged(wid); } if (info.hasState(NET::State::Max) != kInfo.isMaximized()) { kInfo.setIsMaxHoriz(info.hasState(NET::State::Max)); kInfo.setIsMaxVert(info.hasState(NET::State::Max)); emit maximizedChanged(wid); } if (info.hasState(NET::State::Hidden) != kInfo.isMinimized()) { kInfo.setIsMinimized(info.hasState(NET::State::Hidden)); emit minimizedChanged(wid); } } if (prop1.testFlag(NET::WMIcon)) emit iconChanged(wid); if (prop1.testFlag(NET::ActiveWindow)) emit activeChanged(wid); if (prop1.testFlag(NET::WMName) || prop1.testFlag(NET::WMVisibleName)) emit titleChanged(wid); if (prop1.testFlag(NET::WMGeometry)) emit geometryChanged(wid); if (prop1.testFlag(NET::WMDesktop) && info.onAllDesktops()) emit onAllDesktopsChanged(wid); } void KylinAtoms::init() { #define ENUM_CREATE_CHAR_ARRAY 1 #include "kyatoms_p.h" // creates const char* array "KyAtomStrings" // Send the intern atom requests xcb_intern_atom_cookie_t cookies[KyAtomCount]; for (int i = 0; i < KyAtomCount; ++i) { cookies[i] = xcb_intern_atom(m_connection, false, strnlen(KyAtomStrings[i], STRNLEN_MAX), KyAtomStrings[i]); } // Get the replies for (int i = 0; i < KyAtomCount; ++i) { xcb_intern_atom_reply_t *reply = xcb_intern_atom_reply(m_connection, cookies[i], nullptr); if (!reply) { continue; } m_atoms[i] = reply->atom; free(reply); } } libkysdk-applications/kysdk-waylandhelper/src/windowmanager/idlenotifier.h0000664000175000017500000000226215104543305026243 0ustar fengfeng/* * libkysdk-waylandhelper's Library * * Copyright (C) 2024, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #ifndef IDLENOTIFIER_H #define IDLENOTIFIER_H #include "wmregister.h" #include namespace kdk { /** * @since 2.5.1.0 */ class IdleNotifier : public QObject { Q_OBJECT public: IdleNotifier(QObject *parent = nullptr); void setIdleInterval(int msec); Q_SIGNALS: void idled(); void resumed(); private: WmRegister *m_wm = nullptr; }; } #endif // IDLENOTIFIER_H libkysdk-applications/kysdk-waylandhelper/src/windowmanager/kdewaylandinterface.cpp0000664000175000017500000006531215104543305030132 0ustar fengfeng/* * libkysdk-waylandhelper's Library * * Copyright (C) 2024, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #include "kdewaylandinterface.h" #include "wayland-plasma-window-management-client-protocol.h" #include #include #include #include #include inline bool operator<(const QVariant &v1, const QVariant &v2) { return v1.toString() < v2.toString(); } KdeWaylandInterface::KdeWaylandInterface(QObject *parent) : AbstractInterface(parent) { m_connection = KWayland::Client::ConnectionThread::fromApplication(qApp); m_registry = new Registry(this); m_registry->create(m_connection->display()); connect(m_registry, &KWayland::Client::Registry::shellAnnounced, this, [=]() { const auto interface = m_registry->interface(KWayland::Client::Registry::Interface::Shell); if (interface.name != 0) { m_shell = m_registry->createShell(interface.name, interface.version, this); } }); connect(m_registry, &KWayland::Client::Registry::plasmaShellAnnounced, this, [=]() { const auto interface = m_registry->interface(KWayland::Client::Registry::Interface::PlasmaShell); if (interface.name != 0) { m_plasmaShell = m_registry->createPlasmaShell(interface.name, interface.version, this); } }); connect(m_registry, &Registry::plasmaWindowManagementAnnounced, this, [=]() { const auto interface = m_registry->interface(Registry::Interface::PlasmaWindowManagement); if (interface.name != 0) { m_windowManager = m_registry->createPlasmaWindowManagement(interface.name, interface.version, this); } if (m_windowManager) { connect(m_windowManager, &PlasmaWindowManagement::showingDesktopChanged, this, &AbstractInterface::isShowingDesktopChanged); connect(m_windowManager, &PlasmaWindowManagement::windowCreated, this, &KdeWaylandInterface::windowCreatedProxy); connect( m_windowManager, &PlasmaWindowManagement::activeWindowChanged, this, [&]() noexcept { auto w = m_windowManager->activeWindow(); if (w) { emit activeWindowChanged(w ? w->uuid().toInt() : 0); } }, Qt::QueuedConnection); connect(m_windowManager, &PlasmaWindowManagement::windowCreated, this, [this](PlasmaWindow *window) { if (!m_windows.contains(window->uuid())) { m_windows.insert(window->uuid(), this->requestInfo(window->uuid())); } emit windowAdded(window->uuid()); }); } }); connect(m_registry, &KWayland::Client::Registry::plasmaVirtualDesktopManagementAnnounced, [=](quint32 name, quint32 version) { m_virtualDesktopManagement = m_registry->createPlasmaVirtualDesktopManagement(name, version, this); if (m_virtualDesktopManagement) { connect(m_virtualDesktopManagement, &KWayland::Client::PlasmaVirtualDesktopManagement::desktopCreated, this, [this](const QString &id, quint32 position) { addDesktop(id, position); }); connect(m_virtualDesktopManagement, &KWayland::Client::PlasmaVirtualDesktopManagement::desktopRemoved, this, [this](const QString &id) { m_desktops.removeAll(id); if (m_currentDesktop == id) { setCurrentDesktop(QString()); } }); } }); m_registry->setup(); m_connection->roundtrip(); } KdeWaylandInterface::~KdeWaylandInterface() { } WindowInfo KdeWaylandInterface::requestInfo(WindowId wid) { WindowInfo windowInfo; auto w = windowFor(wid); if (w) { if (isPlasmaDesktop(w)) { windowInfo.setIsValid(true); windowInfo.setIsPlasmaDesktop(true); windowInfo.setWid(wid); //! Window Abilities windowInfo.setIsClosable(false); windowInfo.setIsFullScreenable(false); windowInfo.setIsGroupable(false); windowInfo.setIsMaximizable(false); windowInfo.setIsMinimizable(false); windowInfo.setIsMovable(false); windowInfo.setIsResizable(false); windowInfo.setIsShadeable(false); windowInfo.setIsVirtualDesktopsChangeable(false); //! Window Abilities } else if (isValidWindow(w)) { windowInfo.setIsValid(true); windowInfo.setWid(wid); windowInfo.setIsActive(w->isActive()); windowInfo.setIsMinimized(w->isMinimized()); windowInfo.setIsMaxVert(w->isMaximized()); windowInfo.setIsMaxHoriz(w->isMaximized()); windowInfo.setIsFullscreen(w->isFullscreen()); windowInfo.setIsShaded(w->isShaded()); windowInfo.setIsOnAllDesktops(w->isOnAllDesktops()); windowInfo.setIsOnAllActivities(true); windowInfo.setHasSkipTaskbar(w->skipTaskbar()); windowInfo.setHasSkipSwitcher(w->skipSwitcher()); windowInfo.setIsKeepAbove(w->isKeepAbove()); //! Window Abilities windowInfo.setIsClosable(w->isCloseable()); windowInfo.setIsFullScreenable(w->isFullscreenable()); windowInfo.setIsMaximizable(w->isMaximizeable()); windowInfo.setIsMinimizable(w->isMinimizeable()); windowInfo.setIsMovable(w->isMovable()); windowInfo.setIsResizable(w->isResizable()); windowInfo.setIsShadeable(w->isShadeable()); windowInfo.setIsVirtualDesktopsChangeable(w->isVirtualDesktopChangeable()); //! Window Abilities windowInfo.setDesktops(w->plasmaVirtualDesktops()); } } else { windowInfo.setIsValid(false); } return windowInfo; } void KdeWaylandInterface::requestActivate(WindowId wid) { auto w = windowFor(wid); if (w) { w->requestActivate(); m_connection->roundtrip(); emit windowChanged(w->uuid()); } } void KdeWaylandInterface::requestClose(WindowId wid) { auto w = windowFor(wid); if (w) { w->requestClose(); m_connection->roundtrip(); } } void KdeWaylandInterface::requestToggleKeepAbove(WindowId wid) { auto w = windowFor(wid); if (w) { w->requestToggleKeepAbove(); m_connection->roundtrip(); emit windowChanged(w->uuid()); } } void KdeWaylandInterface::requestToggleMinimized(WindowId wid) { auto w = windowFor(wid); if (w) { w->requestToggleMinimized(); m_connection->roundtrip(); } } void KdeWaylandInterface::requestToggleMaximized(WindowId wid) { auto w = windowFor(wid); if (w) { w->requestToggleMaximized(); m_connection->roundtrip(); } } QIcon KdeWaylandInterface::iconFor(WindowId wid) { auto window = windowFor(wid); if (window) { return window->icon(); } return QIcon(); } QString KdeWaylandInterface::titleFor(WindowId wid) { auto window = windowFor(wid); if (window) { return window->title(); } return QString(); } QString KdeWaylandInterface::windowGroupFor(WindowId wid) { auto window = windowFor(wid); if (window) { m_connection->roundtrip(); return window->appId(); } else return QString(); } quint32 KdeWaylandInterface::pid(WindowId wid) { quint32 pid = 0; auto window = windowFor(wid); if (window) { m_connection->roundtrip(); return window->pid(); } else return pid; } void KdeWaylandInterface::showCurrentDesktop() { if (m_windowManager) { m_windowManager->showDesktop(); m_connection->roundtrip(); } } void KdeWaylandInterface::hideCurrentDesktop() { if (m_windowManager) { m_windowManager->hideDesktop(); m_connection->roundtrip(); } } bool KdeWaylandInterface::windowCanBeDragged(WindowId wid) { auto w = windowFor(wid); if (w && isValidWindow(w)) { WindowInfo winfo = requestInfo(wid); return (winfo.isValid() && w->isMovable() && !winfo.isMinimized() && inCurrentDesktopActivity(winfo) && !winfo.isPlasmaDesktop()); } return false; } bool KdeWaylandInterface::windowCanBeMaximized(WindowId wid) { auto w = windowFor(wid); if (w && isValidWindow(w)) { WindowInfo winfo = requestInfo(wid); return (winfo.isValid() && w->isMaximizeable() && !winfo.isMinimized() && inCurrentDesktopActivity(winfo) && !winfo.isPlasmaDesktop()); } return false; } WindowId KdeWaylandInterface::activeWindow() { if (!m_windowManager) { return 0; } m_connection->roundtrip(); auto wid = m_windowManager->activeWindow(); return wid ? QVariant(wid->uuid()) : 0; } void KdeWaylandInterface::setGeometry(QWindow *window, const QRect &rect) { if (!window) return; if (!m_plasmaShell) return; auto surface = KWayland::Client::Surface::fromWindow(window); if (!surface) return; if (!m_surfaces.contains(window)) { m_surfaces.insert(window, surface); } auto plasmaShellSurface = m_plasmaShell->createSurface(surface, window); if (!plasmaShellSurface) return; if (!m_plasmaShellSurfaces.contains(window)) { m_plasmaShellSurfaces.insert(window, plasmaShellSurface); } plasmaShellSurface->setPosition(rect.topLeft()); window->resize(rect.size()); window->installEventFilter(this); } void KdeWaylandInterface::setSkipTaskBar(QWindow *window, bool skip) { if (!window) return; if (!m_plasmaShell) return; auto surface = KWayland::Client::Surface::fromWindow(window); if (!surface) return; if (!m_surfaces.contains(window)) m_surfaces.insert(window, surface); auto plasmaShellSurface = m_plasmaShell->createSurface(surface, window); if (!plasmaShellSurface) return; if (!m_plasmaShellSurfaces.contains(window)) m_plasmaShellSurfaces.insert(window, plasmaShellSurface); plasmaShellSurface->setSkipTaskbar(skip); window->installEventFilter(this); } void KdeWaylandInterface::setSkipSwitcher(QWindow *window, bool skip) { if (!window) return; if (!m_plasmaShell) return; auto surface = KWayland::Client::Surface::fromWindow(window); if (!surface) return; if (!m_surfaces.contains(window)) m_surfaces.insert(window, surface); auto plasmaShellSurface = m_plasmaShell->createSurface(surface, window); if (!plasmaShellSurface) return; if (!m_plasmaShellSurfaces.contains(window)) m_plasmaShellSurfaces.insert(window, plasmaShellSurface); plasmaShellSurface->setSkipSwitcher(skip); window->installEventFilter(this); } bool KdeWaylandInterface::skipTaskBar(const WindowId &wid) { auto window = windowFor(wid); return window ? window->skipTaskbar() : false; } bool KdeWaylandInterface::skipSwitcher(const WindowId &wid) { auto window = windowFor(wid); return window ? window->skipSwitcher() : false; } bool KdeWaylandInterface::isShowingDesktop() { bool flag = false; if (m_windowManager) { flag = m_windowManager->isShowingDesktop(); m_connection->roundtrip(); } return flag; } void KdeWaylandInterface::setOnAllDesktops(const WindowId &wid) { auto w = windowFor(wid); if (w && isValidWindow(w) && m_desktops.count() > 1) { if (w->isOnAllDesktops()) { w->requestEnterVirtualDesktop(m_currentDesktop); } else { const QStringList &now = w->plasmaVirtualDesktops(); foreach (const QString &desktop, now) { w->requestLeaveVirtualDesktop(desktop); } } } } NET::WindowType KdeWaylandInterface::windowType(WindowId wid) { return NET::WindowType::Normal; } void KdeWaylandInterface::setPanelTakefocus(QWindow *window, bool flag) { if (!window) return; if (!m_plasmaShell) return; auto surface = KWayland::Client::Surface::fromWindow(window); if (!surface) return; if (!m_surfaces.contains(window)) { m_surfaces.insert(window, surface); } auto plasmaShellSurface = m_plasmaShell->createSurface(surface, window); if (!plasmaShellSurface) return; if (!m_plasmaShellSurfaces.contains(window)) { m_plasmaShellSurfaces.insert(window, plasmaShellSurface); } plasmaShellSurface->setPanelTakesFocus(flag); window->installEventFilter(this); } void KdeWaylandInterface::demandAttention(const WindowId &wid) { auto w = windowFor(wid); if (w) { org_kde_plasma_window_set_state(*w, ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_DEMANDS_ATTENTION, ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_DEMANDS_ATTENTION); m_connection->roundtrip(); } } QRect KdeWaylandInterface::windowGeometry(const WindowId &windowId) { PlasmaWindow *w = windowFor(windowId); if (w) return w->geometry(); else return QRect(0, 0, 0, 0); } void KdeWaylandInterface::setWindowLayer(QWindow *window, WindowLayer layer) { if (!window) return; if (!m_plasmaShell) return; auto surface = KWayland::Client::Surface::fromWindow(window); if (!surface) return; if (!m_surfaces.contains(window)) { m_surfaces.insert(window, surface); } auto plasmaShellSurface = m_plasmaShell->createSurface(surface, window); if (!plasmaShellSurface) return; if (!m_plasmaShellSurfaces.contains(window)) { m_plasmaShellSurfaces.insert(window, plasmaShellSurface); } window->installEventFilter(this); switch (layer) { case WindowLayer::Normal: plasmaShellSurface->setRole(PlasmaShellSurface::Role::Normal); break; case WindowLayer::Desktop: plasmaShellSurface->setRole(PlasmaShellSurface::Role::Desktop); break; case WindowLayer::Panel: plasmaShellSurface->setRole(PlasmaShellSurface::Role::Panel); break; case WindowLayer::OnScreenDisplay: plasmaShellSurface->setRole(PlasmaShellSurface::Role::OnScreenDisplay); break; case WindowLayer::Notification: plasmaShellSurface->setRole(PlasmaShellSurface::Role::Notification); break; case WindowLayer::ToolTip: plasmaShellSurface->setRole(PlasmaShellSurface::Role::ToolTip); break; case WindowLayer::CriticalNotification: plasmaShellSurface->setRole(PlasmaShellSurface::Role::CriticalNotification); break; case WindowLayer::AppletPop: { plasmaShellSurface->setRole(PlasmaShellSurface::Role::ToolTip); qWarning() << "plasmashellsurface does not surpport AppletPop layer, replaced by Tooltip"; break; } case WindowLayer::ScreenLock: { plasmaShellSurface->setRole(PlasmaShellSurface::Role::Normal); qWarning() << "plasmashellsurface does not surpport ScreenLock layer, replaced by Normal"; break; } case WindowLayer::Watermark: { plasmaShellSurface->setRole(PlasmaShellSurface::Role::Normal); qWarning() << "plasmashellsurface does not surpport Watermark layer, replaced by Normal"; break; } case WindowLayer::SystemWindow: { plasmaShellSurface->setRole(PlasmaShellSurface::Role::Normal); qWarning() << "plasmashellsurface does not surpport SystemWindow layer, replaced by Normal"; break; } case WindowLayer::InputPanel: { plasmaShellSurface->setRole(PlasmaShellSurface::Role::Normal); qWarning() << "plasmashellsurface does not surpport InputPanel layer, replaced by Normal"; break; } case WindowLayer::Logout: { plasmaShellSurface->setRole(PlasmaShellSurface::Role::Normal); qWarning() << "plasmashellsurface does not surpport Logout layer, replaced by Normal"; break; } case WindowLayer::ScreenLockNotification: { plasmaShellSurface->setRole(PlasmaShellSurface::Role::Normal); qWarning() << "plasmashellsurface does not surpport ScreenLockNotification layer, replaced by Normal"; break; } case WindowLayer::Switcher: { plasmaShellSurface->setRole(PlasmaShellSurface::Role::Panel); qWarning() << "plasmashellsurface does not surpport Switcher layer, replaced by Panel"; break; } default: { qWarning() << "It is not a surpported window layer by kde protocols! id:" << (int)layer; plasmaShellSurface->setRole(PlasmaShellSurface::Role::Normal); break; } } } WindowLayer KdeWaylandInterface::windowLayer(QWindow *window) { if (!window) return WindowLayer::Normal; if (!m_plasmaShell) return WindowLayer::Normal; auto surface = KWayland::Client::Surface::fromWindow(window); if (!surface) return WindowLayer::Normal; if (!m_surfaces.contains(window)) { m_surfaces.insert(window, surface); } auto plasmaShellSurface = m_plasmaShell->createSurface(surface, window); if (!plasmaShellSurface) return WindowLayer::Normal; if (!m_plasmaShellSurfaces.contains(window)) { m_plasmaShellSurfaces.insert(window, plasmaShellSurface); } window->installEventFilter(this); WindowLayer layer; // not surpport applet and switcher layer switch (plasmaShellSurface->role()) { case PlasmaShellSurface::Role::Normal: layer = WindowLayer::Normal; break; case PlasmaShellSurface::Role::Desktop: layer = WindowLayer::Desktop; break; case PlasmaShellSurface::Role::Panel: layer = WindowLayer::Panel; break; case PlasmaShellSurface::Role::OnScreenDisplay: layer = WindowLayer::OnScreenDisplay; break; case PlasmaShellSurface::Role::Notification: layer = WindowLayer::Notification; break; case PlasmaShellSurface::Role::ToolTip: layer = WindowLayer::ToolTip; break; case PlasmaShellSurface::Role::CriticalNotification: layer = WindowLayer::CriticalNotification; break; default: layer = WindowLayer::Normal; break; } return layer; } bool KdeWaylandInterface::eventFilter(QObject *obj, QEvent *ev) { auto window = qobject_cast(obj); if (window && ev->type() == QEvent::Hide) { if (m_plasmaShellSurfaces.contains(window)) { auto plasmaShellSurface = m_plasmaShellSurfaces.value(window); if (plasmaShellSurface) { plasmaShellSurface->release(); plasmaShellSurface->destroy(); } m_plasmaShellSurfaces.remove(window); } if (m_surfaces.contains(window)) { auto surface = m_surfaces.value(window); if (surface) { surface->release(); surface->destroy(); } m_surfaces.remove(window); } } return QObject::eventFilter(obj, ev); } void KdeWaylandInterface::updateWindow() { PlasmaWindow *w = qobject_cast(QObject::sender()); if (w && !isPlasmaPanel(w)) { m_connection->roundtrip(); emit windowChanged(w->uuid()); } } void KdeWaylandInterface::windowUnmapped() { PlasmaWindow *pW = qobject_cast(QObject::sender()); if (pW) { untrackWindow(pW); if (!m_windows.contains(pW->uuid())) { m_windows.remove(pW->uuid()); } emit windowRemoved(pW->uuid()); } } PlasmaWindow *KdeWaylandInterface::windowFor(WindowId wid) { auto it = std::find_if(m_windowManager->windows().constBegin(), m_windowManager->windows().constEnd(), [&wid](PlasmaWindow *w) noexcept { return w->isValid() && w->uuid() == wid; }); if (it == m_windowManager->windows().constEnd()) { return nullptr; } return *it; } bool KdeWaylandInterface::isValidWindow(const PlasmaWindow *w) { return w->isValid(); } bool KdeWaylandInterface::isPlasmaDesktop(const PlasmaWindow *w) { if (!w || (w->appId() != QLatin1String("org.kde.plasmashell"))) { return false; } return AbstractInterface::isPlasmaDesktop(w->geometry()); } bool KdeWaylandInterface::isPlasmaPanel(const PlasmaWindow *w) { if (w && w->appId() == QLatin1String("ukui-panel")) return true; else return false; } void KdeWaylandInterface::windowCreatedProxy(PlasmaWindow *w) { if (!isValidWindow(w)) { return; } if ((w->appId() == QLatin1String("org.kde.plasmashell")) && isPlasmaPanel(w)) { return; } else { trackWindow(w); } } void KdeWaylandInterface::trackWindow(PlasmaWindow *w) { if (!w || isPlasmaPanel(w)) { return; } // 兼容旧的windowchanged信号 connect(w, &PlasmaWindow::titleChanged, this, &KdeWaylandInterface::updateWindow); connect(w, &PlasmaWindow::fullscreenChanged, this, &KdeWaylandInterface::updateWindow); connect(w, &PlasmaWindow::geometryChanged, this, &KdeWaylandInterface::updateWindow); connect(w, &PlasmaWindow::maximizedChanged, this, &KdeWaylandInterface::updateWindow); connect(w, &PlasmaWindow::minimizedChanged, this, &KdeWaylandInterface::updateWindow); connect(w, &PlasmaWindow::shadedChanged, this, &KdeWaylandInterface::updateWindow); connect(w, &PlasmaWindow::skipTaskbarChanged, this, &KdeWaylandInterface::updateWindow); connect(w, &PlasmaWindow::onAllDesktopsChanged, this, &KdeWaylandInterface::updateWindow); connect(w, &PlasmaWindow::parentWindowChanged, this, &KdeWaylandInterface::updateWindow); connect(w, &PlasmaWindow::iconChanged, this, &KdeWaylandInterface::updateWindow); connect(w, &PlasmaWindow::plasmaVirtualDesktopEntered, this, &KdeWaylandInterface::updateWindow); connect(w, &PlasmaWindow::plasmaVirtualDesktopLeft, this, &KdeWaylandInterface::updateWindow); connect(w, &PlasmaWindow::unmapped, this, &KdeWaylandInterface::windowUnmapped); // 按照具体事件新增信号,since2.3.1.0 connect(w, &PlasmaWindow::titleChanged, this, [=]() { emit titleChanged(w->uuid()); }); connect(w, &PlasmaWindow::fullscreenChanged, this, [=]() { emit fullscreenChanged(w->uuid()); }); connect(w, &PlasmaWindow::iconChanged, this, [=]() { emit iconChanged(w->uuid()); }); connect(w, &PlasmaWindow::activeChanged, this, [=]() { emit activeChanged(w->uuid()); }); connect(w, &PlasmaWindow::keepAboveChanged, this, [=]() { emit keepAboveChanged(w->uuid()); }); connect(w, &PlasmaWindow::minimizedChanged, this, [=]() { emit minimizedChanged(w->uuid()); }); connect(w, &PlasmaWindow::maximizedChanged, this, [=]() { emit maximizedChanged(w->uuid()); }); connect(w, &PlasmaWindow::onAllDesktopsChanged, this, [=]() { emit onAllDesktopsChanged(w->uuid()); }); connect(w, &PlasmaWindow::demandsAttentionChanged, this, [=]() { emit demandsAttentionChanged(w->uuid()); }); connect(w, &PlasmaWindow::skipTaskbarChanged, this, [=]() { emit skipTaskbarChanged(w->uuid()); }); connect(w, &PlasmaWindow::skipSwitcherChanged, this, [=]() { emit skipSwitcherChanged(w->uuid()); }); connect(w, &PlasmaWindow::geometryChanged, this, [=]() { emit geometryChanged(w->uuid()); }); } void KdeWaylandInterface::untrackWindow(PlasmaWindow *w) { if (!w) { return; } disconnect(w, &PlasmaWindow::activeChanged, this, &KdeWaylandInterface::updateWindow); disconnect(w, &PlasmaWindow::titleChanged, this, &KdeWaylandInterface::updateWindow); disconnect(w, &PlasmaWindow::fullscreenChanged, this, &KdeWaylandInterface::updateWindow); disconnect(w, &PlasmaWindow::geometryChanged, this, &KdeWaylandInterface::updateWindow); disconnect(w, &PlasmaWindow::maximizedChanged, this, &KdeWaylandInterface::updateWindow); disconnect(w, &PlasmaWindow::minimizedChanged, this, &KdeWaylandInterface::updateWindow); disconnect(w, &PlasmaWindow::shadedChanged, this, &KdeWaylandInterface::updateWindow); disconnect(w, &PlasmaWindow::skipTaskbarChanged, this, &KdeWaylandInterface::updateWindow); disconnect(w, &PlasmaWindow::onAllDesktopsChanged, this, &KdeWaylandInterface::updateWindow); disconnect(w, &PlasmaWindow::parentWindowChanged, this, &KdeWaylandInterface::updateWindow); disconnect(w, &PlasmaWindow::plasmaVirtualDesktopEntered, this, &KdeWaylandInterface::updateWindow); disconnect(w, &PlasmaWindow::plasmaVirtualDesktopLeft, this, &KdeWaylandInterface::updateWindow); disconnect(w, &PlasmaWindow::unmapped, this, &KdeWaylandInterface::windowUnmapped); disconnect(w, &PlasmaWindow::titleChanged, 0, 0); disconnect(w, &PlasmaWindow::iconChanged, 0, 0); disconnect(w, &PlasmaWindow::activeChanged, 0, 0); disconnect(w, &PlasmaWindow::keepAboveChanged, 0, 0); disconnect(w, &PlasmaWindow::keepBelowChanged, 0, 0); disconnect(w, &PlasmaWindow::minimizedChanged, 0, 0); disconnect(w, &PlasmaWindow::maximizedChanged, 0, 0); disconnect(w, &PlasmaWindow::onAllDesktopsChanged, 0, 0); disconnect(w, &PlasmaWindow::demandsAttentionChanged, 0, 0); disconnect(w, &PlasmaWindow::skipTaskbarChanged, 0, 0); disconnect(w, &PlasmaWindow::skipSwitcherChanged, 0, 0); disconnect(w, &PlasmaWindow::geometryChanged, 0, 0); } void KdeWaylandInterface::setCurrentDesktop(QString desktop) { if (m_currentDesktop == desktop) { return; } m_currentDesktop = desktop; emit currentDesktopChanged(); } void KdeWaylandInterface::addDesktop(const QString &id, quint32 position) { if (m_desktops.contains(id)) { return; } m_desktops.append(id); const KWayland::Client::PlasmaVirtualDesktop *desktop = m_virtualDesktopManagement->getVirtualDesktop(id); QObject::connect(desktop, &KWayland::Client::PlasmaVirtualDesktop::activated, this, [desktop, this]() { setCurrentDesktop(desktop->id()); }); if (desktop->isActive()) { setCurrentDesktop(id); } } void KdeWaylandInterface::initKdeProtocol() { } libkysdk-applications/kysdk-waylandhelper/src/windowmanager/ukuiwaylandinterface.h0000664000175000017500000001147415104543305030011 0ustar fengfeng/* * libkysdk-waylandhelper's Library * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #ifndef UKUIWAYLANDINTERFACE_H #define UKUIWAYLANDINTERFACE_H #include "extidlenotifier.h" #include "ukuishell.h" #include "ukuiwindowmanagement.h" #include "xdgactivation.h" #include #include #include #include "abstractinterface.h" #include "kdewaylandinterface.h" /** * @since 2.5.1.0 */ class UkuiWaylandInterface : public AbstractInterface { Q_OBJECT public: explicit UkuiWaylandInterface(QObject *parent = nullptr); ~UkuiWaylandInterface(); WindowInfo requestInfo(WindowId wid) override; void requestActivate(WindowId wid) override; void requestClose(WindowId wid) override; void requestToggleKeepAbove(WindowId wid) override; void requestToggleMinimized(WindowId wid) override; void requestToggleMaximized(WindowId wid) override; QIcon iconFor(WindowId wid) override; QString titleFor(WindowId wid) override; QString windowGroupFor(WindowId wid) override; quint32 pid(WindowId wid) override; void showCurrentDesktop() override; void hideCurrentDesktop() override; bool windowCanBeDragged(WindowId wid) override; bool windowCanBeMaximized(WindowId wid) override; WindowId activeWindow() override; void setGeometry(QWindow *window, const QRect &rect) override; void setSkipTaskBar(QWindow *window, bool skip) override; void setSkipSwitcher(QWindow *window, bool skip) override; bool skipTaskBar(const WindowId &wid) override; bool skipSwitcher(const WindowId &wid) override; bool isShowingDesktop() override; void setOnAllDesktops(const WindowId &wid) override; NET::WindowType windowType(WindowId wid) override; void setPanelTakefocus(QWindow *window, bool flag) override; void demandAttention(const WindowId &wid) override; bool ukuiProtocolReady(); Registry *registry(); void handleGlobal(void *data, struct wl_registry *registry, uint32_t name, const char *interface, uint32_t version); void handleGlobalRemove(void *data, struct wl_registry *registry, uint32_t name); bool removeHeaderBar(QWindow *windowHandle); bool setWindowRadius(QWindow *windowHandle, int radius) override; void activateWindow(QWindow *window1, QWindow *window2) override; void setIdleInterval(int msec) override; QRect windowGeometry(const WindowId &windowId) override; void setPanelAutoHide(QWindow *window, bool autoHide) override; void setGrabKeyboard(QWindow *window, bool autoHide) override; void setWindowLayer(QWindow *window, WindowLayer layer) override; WindowLayer windowLayer(QWindow *window) override; void setHighlight(const WindowId &wid, bool highlight) override; bool istHighlight(const WindowId &wid) override; void setOpenUnderCursor(QWindow *window) override; void setOpenUnderCursor(QWindow *window, int x, int y) override; void setIconName(QWindow *window, const QString &iconName) override; QString currentSeatName() override; QString currentOutputName() override; QList outputsInfo() override; QList getWindowIdByPid(quint32 pid) override; QList getWindowIdByTtile(const QString &title) override; protected: bool eventFilter(QObject *obj, QEvent *ev) override; private: UkuiWindow *windowFor(WindowId wid); void ukuiWindowCreatedProxy(UkuiWindow *w); void trackUkuiWindow(UkuiWindow *w); void untrackUkuiWindow(UkuiWindow *w); static const struct wl_registry_listener s_registryListener; private: ExtIdleNotifier *m_notifier = nullptr; wl_seat *m_seat = nullptr; Shell *m_shell = nullptr; ConnectionThread *m_connection = nullptr; Registry *m_registry = nullptr; QMap m_surfaces; QStringList m_desktops; UkuiShell *m_ukuiShell = nullptr; UkuiWindowManagement *m_ukuiWindowManager = nullptr; XdgActivation *m_xdgActivation = nullptr; XdgActivationToken *m_xdgActivationToken = nullptr; QMap m_ukuiShellSurfaces; }; #endif // UKUIWAYLANDINTERFACE_H libkysdk-applications/kysdk-waylandhelper/src/windowmanager/outputinfo.cpp0000664000175000017500000000276115104543305026341 0ustar fengfeng/* * libkysdk-waylandhelper's Library * * Copyright (C) 2024, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #include "outputinfo.h" class Q_DECL_HIDDEN OutputInfo::Private { public: Private(OutputInfo *q); ~Private(); QRect m_usableArea; QString m_name; OutputInfo *q; }; OutputInfo::OutputInfo(QObject *parent) : QObject(parent) , d(new Private(this)) { } void OutputInfo::setOutputName(const QString &outputName) { d->m_name = outputName; } void OutputInfo::setUsableArea(const QRect &usableArea) { d->m_usableArea = usableArea; } OutputInfo::~OutputInfo() { } QString OutputInfo::outputName() { return d->m_name; } QRect OutputInfo::usableArea() { return d->m_usableArea; } OutputInfo::Private::Private(OutputInfo *q) : q(q) { } OutputInfo::Private::~Private() { } libkysdk-applications/kysdk-waylandhelper/src/windowmanager/xdgactivation.cpp0000664000175000017500000001245515104543305026772 0ustar fengfeng/* * libkysdk-waylandhelper's Library * * Copyright (C) 2024, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #include "xdgactivation.h" #include "ukuiwaylandpointer.h" class Q_DECL_HIDDEN XdgActivation::Private { public: Private(XdgActivation *q); ~Private(); UkuiWaylandPointer activation; EventQueue *queue = nullptr; XdgActivation *q; }; XdgActivation::XdgActivation(QObject *parent) : QObject(parent) , d(new Private(this)) { } XdgActivation::~XdgActivation() { } bool XdgActivation::isValid() const { return d->activation.isValid(); } void XdgActivation::release() { return d->activation.release(); } void XdgActivation::destroy() { return d->activation.destroy(); } void XdgActivation::setup(xdg_activation_v1 *activation) { Q_ASSERT(!d->activation); Q_ASSERT(activation); d->activation.setup(activation); } void XdgActivation::setEventQueue(EventQueue *queue) { d->queue = queue; } EventQueue *XdgActivation::eventQueue() { return d->queue; } XdgActivation::operator xdg_activation_v1 *() { return d->activation; } XdgActivationToken *XdgActivation::getXdgActivationToken() { XdgActivationToken *token = new XdgActivationToken(this); auto origin_token = xdg_activation_v1_get_activation_token((d->activation)); token->setup(origin_token); return token; } void XdgActivation::activateWindow(const QString &token, Surface *surface) { xdg_activation_v1_activate( d->activation, token.toUtf8().constData(), *surface); } XdgActivationToken *XdgActivation::requestXdgActivationToken(wl_seat *seat, Surface *surface, uint32_t serial, const QString &app_id) { auto provider = getXdgActivationToken(); if (surface) { provider->set_surface(surface); } if (!app_id.isEmpty()) { provider->set_app_id(app_id); } if (seat) { provider->set_serial(serial, seat); } provider->commit(); return provider; } XdgActivation::operator xdg_activation_v1 *() const { return d->activation; } class Q_DECL_HIDDEN XdgActivationToken::Private { public: Private(XdgActivationToken *q); ~Private(); UkuiWaylandPointer token; void init_listener(); private: XdgActivationToken *q; static const struct xdg_activation_token_v1_listener m_xdg_activation_token_v1_listener; static void handle_done( void *data, struct ::xdg_activation_token_v1 *object, const char *token); void doneCallback(const QString &token); }; XdgActivationToken::XdgActivationToken(QObject *parent) : QObject(parent) , d(new Private(this)) { } XdgActivationToken::~XdgActivationToken() { } bool XdgActivationToken::isValid() const { return d->token.isValid(); } void XdgActivationToken::release() { return d->token.release(); } void XdgActivationToken::destroy() { return d->token.destroy(); } void XdgActivationToken::setup(xdg_activation_token_v1 *token) { Q_ASSERT(!d->token); Q_ASSERT(token); d->token.setup(token); d->init_listener(); } void XdgActivationToken::set_serial(uint32_t serial, wl_seat *seat) { xdg_activation_token_v1_set_serial(d->token, serial, seat); } void XdgActivationToken::set_app_id(const QString &app_id) { xdg_activation_token_v1_set_app_id( d->token, app_id.toUtf8().constData()); } void XdgActivationToken::set_surface(Surface *surface) { xdg_activation_token_v1_set_surface( d->token, *surface); } void XdgActivationToken::commit() { xdg_activation_token_v1_commit( d->token); } XdgActivationToken::operator xdg_activation_token_v1 *() { return d->token; } XdgActivationToken::operator xdg_activation_token_v1 *() const { return d->token; } XdgActivationToken::Private::Private(XdgActivationToken *q) : q(q) { } XdgActivationToken::Private::~Private() { } const struct xdg_activation_token_v1_listener XdgActivationToken::Private::m_xdg_activation_token_v1_listener = { XdgActivationToken::Private::handle_done, }; void XdgActivationToken::Private::init_listener() { xdg_activation_token_v1_add_listener(token, &m_xdg_activation_token_v1_listener, this); } void XdgActivationToken::Private::handle_done(void *data, xdg_activation_token_v1 *object, const char *token) { static_cast(data)->doneCallback(QString::fromUtf8(token)); } void XdgActivationToken::Private::doneCallback(const QString &token) { Q_EMIT q->done(token); } XdgActivation::Private::Private(XdgActivation *q) : q(q) { } XdgActivation::Private::~Private() { } libkysdk-applications/kysdk-waylandhelper/src/windowmanager/kdewaylandinterface.h0000664000175000017500000001007015104543305027566 0ustar fengfeng/* * libkysdk-waylandhelper's Library * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #ifndef KDEWAYLANDINTERFACE_H #define KDEWAYLANDINTERFACE_H #include "abstractinterface.h" #include #include #include #include #include #include #include // #include #include using namespace kdk; using namespace KWayland::Client; /** * @since 2.5.1.0 */ class KdeWaylandInterface : public AbstractInterface { Q_OBJECT public: KdeWaylandInterface(QObject *parent = nullptr); ~KdeWaylandInterface(); WindowInfo requestInfo(WindowId wid) override; void requestActivate(WindowId wid) override; void requestClose(WindowId wid) override; void requestToggleKeepAbove(WindowId wid) override; void requestToggleMinimized(WindowId wid) override; void requestToggleMaximized(WindowId wid) override; QIcon iconFor(WindowId wid) override; QString titleFor(WindowId wid) override; QString windowGroupFor(WindowId wid) override; quint32 pid(WindowId wid) override; void showCurrentDesktop() override; void hideCurrentDesktop() override; bool windowCanBeDragged(WindowId wid) override; bool windowCanBeMaximized(WindowId wid) override; WindowId activeWindow() override; void setGeometry(QWindow *window, const QRect &rect) override; void setSkipTaskBar(QWindow *window, bool skip) override; void setSkipSwitcher(QWindow *window, bool skip) override; bool skipTaskBar(const WindowId &wid) override; bool skipSwitcher(const WindowId &wid) override; bool isShowingDesktop() override; void setOnAllDesktops(const WindowId &wid) override; NET::WindowType windowType(WindowId wid) override; void setPanelTakefocus(QWindow *window, bool flag) override; void demandAttention(const WindowId &wid) override; QRect windowGeometry(const WindowId &windowId) override; void setWindowLayer(QWindow *window, WindowLayer layer) override; WindowLayer windowLayer(QWindow *window) override; protected: bool eventFilter(QObject *obj, QEvent *ev) override; private slots: void updateWindow(); void windowUnmapped(); private: PlasmaWindow *windowFor(WindowId wid); bool isValidWindow(const KWayland::Client::PlasmaWindow *w); bool isPlasmaDesktop(const KWayland::Client::PlasmaWindow *w); bool isPlasmaPanel(const KWayland::Client::PlasmaWindow *w); void windowCreatedProxy(KWayland::Client::PlasmaWindow *w); void trackWindow(KWayland::Client::PlasmaWindow *w); void untrackWindow(KWayland::Client::PlasmaWindow *w); void setCurrentDesktop(QString desktop); void addDesktop(const QString &id, quint32 position); void initKdeProtocol(); private: PlasmaShell *m_plasmaShell = nullptr; PlasmaWindowManagement *m_windowManager = nullptr; PlasmaVirtualDesktopManagement *m_virtualDesktopManagement = nullptr; Shell *m_shell = nullptr; ConnectionThread *m_connection = nullptr; Registry *m_registry = nullptr; QMap m_surfaces; QStringList m_desktops; QMap m_plasmaShellSurfaces; }; #endif // KDEWAYLANDINTERFACE_H libkysdk-applications/kysdk-waylandhelper/src/windowmanager/waylandinterface.cpp0000664000175000017500000005264315104515306027451 0ustar fengfeng/* * libkysdk-waylandhelper's Library * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #include "waylandinterface.h" #include #include #include #include #include #include #include "wayland-plasma-window-management-client-protocol.h" WaylandInterface::WaylandInterface(QObject *parent) :AbstractInterface(parent) { m_connection = KWayland::Client::ConnectionThread::fromApplication(qApp); auto registry = new Registry(this); registry->create(m_connection->display()); connect(registry, &KWayland::Client::Registry::plasmaShellAnnounced, this, [=](){ const auto interface = registry->interface(KWayland::Client::Registry::Interface::PlasmaShell); if (interface.name != 0) { m_plasmaShell = registry->createPlasmaShell(interface.name, interface.version, this); } }); connect(registry, &Registry::plasmaWindowManagementAnnounced, this, [=](){ const auto interface = registry->interface(Registry::Interface::PlasmaWindowManagement); if (interface.name != 0) { m_windowManager = registry->createPlasmaWindowManagement(interface.name, interface.version, this); } if(m_windowManager) { connect(m_windowManager, &PlasmaWindowManagement::showingDesktopChanged,this,&AbstractInterface::isShowingDesktopChanged); connect(m_windowManager, &PlasmaWindowManagement::windowCreated, this, &WaylandInterface::windowCreatedProxy); connect(m_windowManager, &PlasmaWindowManagement::activeWindowChanged, this, [&]() noexcept { auto w = m_windowManager->activeWindow(); if(w) { emit activeWindowChanged(w ? w->internalId() : 0); } }, Qt::QueuedConnection); connect(m_windowManager, &PlasmaWindowManagement::windowCreated,this, [this](PlasmaWindow *window) { if (!m_windows.contains(window->internalId())) { m_windows.insert(window->internalId(), this->requestInfo(window->internalId())); } emit windowAdded(window->internalId()); }); } }); connect(registry, &KWayland::Client::Registry::plasmaVirtualDesktopManagementAnnounced, [this, registry] (quint32 name, quint32 version) { m_virtualDesktopManagement = registry->createPlasmaVirtualDesktopManagement(name, version, this); if(m_virtualDesktopManagement) { connect(m_virtualDesktopManagement, &KWayland::Client::PlasmaVirtualDesktopManagement::desktopCreated, this, [this](const QString &id, quint32 position) { addDesktop(id, position); }); connect(m_virtualDesktopManagement, &KWayland::Client::PlasmaVirtualDesktopManagement::desktopRemoved, this, [this](const QString &id) { m_desktops.removeAll(id); if (m_currentDesktop == id) { setCurrentDesktop(QString()); } }); } }); connect(registry, &KWayland::Client::Registry::shellAnnounced, this, [=](){ const auto interface = registry->interface(KWayland::Client::Registry::Interface::Shell); if (interface.name != 0) { m_shell = registry->createShell(interface.name, interface.version, this); } }); registry->setup(); m_connection->roundtrip(); } WaylandInterface::~WaylandInterface() { } WindowInfo WaylandInterface::requestInfo(WindowId wid) { WindowInfo windowInfo; auto w = windowFor(wid); if (w) { if (isPlasmaDesktop(w)) { windowInfo.setIsValid(true); windowInfo.setIsPlasmaDesktop(true); windowInfo.setWid(wid); //! Window Abilities windowInfo.setIsClosable(false); windowInfo.setIsFullScreenable(false); windowInfo.setIsGroupable(false); windowInfo.setIsMaximizable(false); windowInfo.setIsMinimizable(false); windowInfo.setIsMovable(false); windowInfo.setIsResizable(false); windowInfo.setIsShadeable(false); windowInfo.setIsVirtualDesktopsChangeable(false); //! Window Abilities } else if (isValidWindow(w)) { windowInfo.setIsValid(true); windowInfo.setWid(wid); windowInfo.setIsActive(w->isActive()); windowInfo.setIsMinimized(w->isMinimized()); windowInfo.setIsMaxVert(w->isMaximized()); windowInfo.setIsMaxHoriz(w->isMaximized()); windowInfo.setIsFullscreen(w->isFullscreen()); windowInfo.setIsShaded(w->isShaded()); windowInfo.setIsOnAllDesktops(w->isOnAllDesktops()); windowInfo.setIsOnAllActivities(true); windowInfo.setHasSkipTaskbar(w->skipTaskbar()); windowInfo.setHasSkipSwitcher(w->skipSwitcher()); windowInfo.setIsKeepAbove(w->isKeepAbove()); //! Window Abilities windowInfo.setIsClosable(w->isCloseable()); windowInfo.setIsFullScreenable(w->isFullscreenable()); windowInfo.setIsMaximizable(w->isMaximizeable()); windowInfo.setIsMinimizable(w->isMinimizeable()); windowInfo.setIsMovable(w->isMovable()); windowInfo.setIsResizable(w->isResizable()); windowInfo.setIsShadeable(w->isShadeable()); windowInfo.setIsVirtualDesktopsChangeable(w->isVirtualDesktopChangeable()); //! Window Abilities windowInfo.setDesktops(w->plasmaVirtualDesktops()); } } else { windowInfo.setIsValid(false); } return windowInfo; } void WaylandInterface::requestActivate(WindowId wid) { auto w = windowFor(wid); if (w) { w->requestActivate(); m_connection->roundtrip(); emit windowChanged(w->internalId()); } } void WaylandInterface::requestClose(WindowId wid) { auto w = windowFor(wid); if (w) { w->requestClose(); m_connection->roundtrip(); } } void WaylandInterface::requestToggleKeepAbove(WindowId wid) { auto w = windowFor(wid); if (w) { w->requestToggleKeepAbove(); m_connection->roundtrip(); emit windowChanged(w->internalId()); } } void WaylandInterface::requestToggleMinimized(WindowId wid) { auto w = windowFor(wid); if (w) { w->requestToggleMinimized(); m_connection->roundtrip(); } } void WaylandInterface::requestToggleMaximized(WindowId wid) { auto w = windowFor(wid); if (w) { w->requestToggleMaximized(); m_connection->roundtrip(); } } QIcon WaylandInterface::iconFor(WindowId wid) { auto window = windowFor(wid); if (window) { return window->icon(); } return QIcon(); } QString WaylandInterface::titleFor(WindowId wid) { auto window = windowFor(wid); if (window) { return window->title(); } return QString(); } QString WaylandInterface::windowGroupFor(WindowId wid) { auto window = windowFor(wid); if (window) { m_connection->roundtrip(); return window->appId(); } else return QString(); } quint32 WaylandInterface::pid(WindowId wid) { quint32 pid = 0; auto window = windowFor(wid); if (window) { m_connection->roundtrip(); return window->pid(); } else return pid; } void WaylandInterface::showCurrentDesktop() { if(m_windowManager) { m_windowManager->showDesktop(); m_connection->roundtrip(); } } void WaylandInterface::hideCurrentDesktop() { if(m_windowManager) { m_windowManager->hideDesktop(); m_connection->roundtrip(); } } bool WaylandInterface::windowCanBeDragged(WindowId wid) { auto w = windowFor(wid); if (w && isValidWindow(w)) { WindowInfo winfo = requestInfo(wid); return (winfo.isValid() && w->isMovable() && !winfo.isMinimized() && inCurrentDesktopActivity(winfo) && !winfo.isPlasmaDesktop()); } return false; } bool WaylandInterface::windowCanBeMaximized(WindowId wid) { auto w = windowFor(wid); if (w && isValidWindow(w)) { WindowInfo winfo = requestInfo(wid); return (winfo.isValid() && w->isMaximizeable() && !winfo.isMinimized() && inCurrentDesktopActivity(winfo) && !winfo.isPlasmaDesktop()); } return false; } WindowId WaylandInterface::activeWindow() { if (!m_windowManager) { return 0; } m_connection->roundtrip(); auto wid = m_windowManager->activeWindow(); return wid ? QVariant(wid->internalId()) : 0; } void WaylandInterface::setGeometry(QWindow *window, const QRect &rect) { if(!window) return; if (!m_plasmaShell) return; auto surface = KWayland::Client::Surface::fromWindow(window); if (!surface) return; if(!m_surfaces.contains(window)) { m_surfaces.insert(window,surface); } auto plasmaShellSurface = m_plasmaShell->createSurface(surface, window); if (!plasmaShellSurface) return; if(!m_plasmaShellSurfaces.contains(window)) { m_plasmaShellSurfaces.insert(window,plasmaShellSurface); } plasmaShellSurface->setPosition(rect.topLeft()); window->resize(rect.size()); window->installEventFilter(this); } void WaylandInterface::setSkipTaskBar(QWindow *window, bool skip) { if(!window) return; if (!m_plasmaShell) return; auto surface = KWayland::Client::Surface::fromWindow(window); if (!surface) return; if(!m_surfaces.contains(window)) m_surfaces.insert(window,surface); auto plasmaShellSurface = m_plasmaShell->createSurface(surface, window); if (!plasmaShellSurface) return; if(!m_plasmaShellSurfaces.contains(window)) m_plasmaShellSurfaces.insert(window,plasmaShellSurface); plasmaShellSurface->setSkipTaskbar(skip); window->installEventFilter(this); } void WaylandInterface::setSkipSwitcher(QWindow *window, bool skip) { if(!window) return; if (!m_plasmaShell) return; auto surface = KWayland::Client::Surface::fromWindow(window); if (!surface) return; if(!m_surfaces.contains(window)) m_surfaces.insert(window,surface); auto plasmaShellSurface = m_plasmaShell->createSurface(surface, window); if (!plasmaShellSurface) return; if(!m_plasmaShellSurfaces.contains(window)) m_plasmaShellSurfaces.insert(window,plasmaShellSurface); plasmaShellSurface->setSkipSwitcher(skip); window->installEventFilter(this); } bool WaylandInterface::skipTaskBar(const WindowId &wid) { auto window = windowFor(wid); return window ? window->skipTaskbar() : false; } bool WaylandInterface::skipSwitcher(const WindowId &wid) { auto window = windowFor(wid); return window ? window->skipSwitcher() : false; } bool WaylandInterface::isShowingDesktop() { bool flag = false; if(m_windowManager) { flag = m_windowManager->isShowingDesktop(); m_connection->roundtrip(); } return flag; } void WaylandInterface::setOnAllDesktops(const WindowId &wid) { auto w = windowFor(wid); if (w && isValidWindow(w) && m_desktops.count() > 1) { if (w->isOnAllDesktops()) { w->requestEnterVirtualDesktop(m_currentDesktop); } else { const QStringList &now = w->plasmaVirtualDesktops(); foreach (const QString &desktop, now) { w->requestLeaveVirtualDesktop(desktop); } } } } void WaylandInterface::setPanelTakefocus(QWindow *window,bool flag) { if(!window) return; if (!m_plasmaShell) return; auto surface = KWayland::Client::Surface::fromWindow(window); if (!surface) return; if(!m_surfaces.contains(window)) { m_surfaces.insert(window,surface); } auto plasmaShellSurface = m_plasmaShell->createSurface(surface, window); if (!plasmaShellSurface) return; if(!m_plasmaShellSurfaces.contains(window)) { m_plasmaShellSurfaces.insert(window,plasmaShellSurface); } plasmaShellSurface->setPanelTakesFocus(flag); window->installEventFilter(this); } NET::WindowType WaylandInterface::windowType(WindowId wid) { return NET::WindowType::Normal; } void WaylandInterface::demandAttention(const WindowId &wid) { auto w = windowFor(wid); if (w) { org_kde_plasma_window_set_state(*w, ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_DEMANDS_ATTENTION, ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_DEMANDS_ATTENTION); m_connection->roundtrip(); } } bool WaylandInterface::eventFilter(QObject *obj, QEvent *ev) { auto window = qobject_cast(obj); if(window && ev->type() == QEvent::Hide) { if(m_plasmaShellSurfaces.contains(window)) { auto plasmaShellSurface = m_plasmaShellSurfaces.value(window); if(plasmaShellSurface) { plasmaShellSurface->release(); plasmaShellSurface->destroy(); } m_plasmaShellSurfaces.remove(window); } if(m_surfaces.contains(window)) { auto surface = m_surfaces.value(window); if(surface) { surface->release(); surface->destroy(); } m_surfaces.remove(window); } } return QObject::eventFilter(obj,ev); } void WaylandInterface::updateWindow() { PlasmaWindow* w = qobject_cast(QObject::sender()); if(w && !isPlasmaPanel(w)) { m_connection->roundtrip(); emit windowChanged(w->internalId()); } } void WaylandInterface::windowUnmapped() { PlasmaWindow *pW = qobject_cast(QObject::sender()); if (pW) { untrackWindow(pW); if (!m_windows.contains(pW->internalId())) { m_windows.remove(pW->internalId()); } emit windowRemoved(pW->internalId()); } } PlasmaWindow *WaylandInterface::windowFor(WindowId wid) { auto it = std::find_if(m_windowManager->windows().constBegin(), m_windowManager->windows().constEnd(), [&wid](PlasmaWindow * w) noexcept { return w->isValid() && w->internalId() == wid; }); if (it == m_windowManager->windows().constEnd()) { return nullptr; } return *it; } bool WaylandInterface::isValidWindow(const PlasmaWindow *w) { return w->isValid(); } bool WaylandInterface::isPlasmaDesktop(const PlasmaWindow *w) { if (!w || (w->appId() != QLatin1String("org.kde.plasmashell"))) { return false; } return AbstractInterface::isPlasmaDesktop(w->geometry()); } bool WaylandInterface::isPlasmaPanel(const PlasmaWindow *w) { if(w && w->appId() == QLatin1String("ukui-panel")) return true; else return false; } void WaylandInterface::windowCreatedProxy(PlasmaWindow *w) { if (!isValidWindow(w)) { return; } if ((w->appId() == QLatin1String("org.kde.plasmashell")) && isPlasmaPanel(w)) { return; } else { trackWindow(w); } } void WaylandInterface::trackWindow(PlasmaWindow *w) { if(!w || isPlasmaPanel(w)){ return; } //兼容旧的windowchanged信号 connect(w, &PlasmaWindow::titleChanged, this, &WaylandInterface::updateWindow); connect(w, &PlasmaWindow::fullscreenChanged, this, &WaylandInterface::updateWindow); connect(w, &PlasmaWindow::geometryChanged, this, &WaylandInterface::updateWindow); connect(w, &PlasmaWindow::maximizedChanged, this, &WaylandInterface::updateWindow); connect(w, &PlasmaWindow::minimizedChanged, this, &WaylandInterface::updateWindow); connect(w, &PlasmaWindow::shadedChanged, this, &WaylandInterface::updateWindow); connect(w, &PlasmaWindow::skipTaskbarChanged, this, &WaylandInterface::updateWindow); connect(w, &PlasmaWindow::onAllDesktopsChanged, this, &WaylandInterface::updateWindow); connect(w, &PlasmaWindow::parentWindowChanged, this, &WaylandInterface::updateWindow); connect(w, &PlasmaWindow::iconChanged, this, &WaylandInterface::updateWindow); connect(w, &PlasmaWindow::plasmaVirtualDesktopEntered, this, &WaylandInterface::updateWindow); connect(w, &PlasmaWindow::plasmaVirtualDesktopLeft, this, &WaylandInterface::updateWindow); connect(w, &PlasmaWindow::unmapped, this, &WaylandInterface::windowUnmapped); //按照具体事件新增信号,since2.3 connect(w, &PlasmaWindow::titleChanged, this, [=](){emit titleChanged(w->internalId());}); connect(w, &PlasmaWindow::fullscreenChanged, this, [=](){emit fullscreenChanged(w->internalId());}); connect(w, &PlasmaWindow::iconChanged, this, [=](){emit iconChanged(w->internalId());}); connect(w, &PlasmaWindow::activeChanged, this, [=](){emit activeChanged(w->internalId());}); connect(w, &PlasmaWindow::keepAboveChanged, this, [=](){emit keepAboveChanged(w->internalId());}); connect(w, &PlasmaWindow::minimizedChanged, this, [=](){emit minimizedChanged(w->internalId());}); connect(w, &PlasmaWindow::maximizedChanged, this, [=](){emit maximizedChanged(w->internalId());}); connect(w, &PlasmaWindow::onAllDesktopsChanged, this, [=](){emit onAllDesktopsChanged(w->internalId());}); connect(w, &PlasmaWindow::demandsAttentionChanged, this, [=](){emit demandsAttentionChanged(w->internalId());}); connect(w, &PlasmaWindow::skipTaskbarChanged, this, [=](){emit skipTaskbarChanged(w->internalId());}); connect(w, &PlasmaWindow::skipSwitcherChanged, this, [=](){emit skipSwitcherChanged(w->internalId());}); connect(w, &PlasmaWindow::geometryChanged, this, [=](){emit geometryChanged(w->internalId());}); } void WaylandInterface::untrackWindow(PlasmaWindow *w) { if (!w) { return; } disconnect(w, &PlasmaWindow::activeChanged, this, &WaylandInterface::updateWindow); disconnect(w, &PlasmaWindow::titleChanged, this, &WaylandInterface::updateWindow); disconnect(w, &PlasmaWindow::fullscreenChanged, this, &WaylandInterface::updateWindow); disconnect(w, &PlasmaWindow::geometryChanged, this, &WaylandInterface::updateWindow); disconnect(w, &PlasmaWindow::maximizedChanged, this, &WaylandInterface::updateWindow); disconnect(w, &PlasmaWindow::minimizedChanged, this, &WaylandInterface::updateWindow); disconnect(w, &PlasmaWindow::shadedChanged, this, &WaylandInterface::updateWindow); disconnect(w, &PlasmaWindow::skipTaskbarChanged, this, &WaylandInterface::updateWindow); disconnect(w, &PlasmaWindow::onAllDesktopsChanged, this, &WaylandInterface::updateWindow); disconnect(w, &PlasmaWindow::parentWindowChanged, this, &WaylandInterface::updateWindow); disconnect(w, &PlasmaWindow::plasmaVirtualDesktopEntered, this, &WaylandInterface::updateWindow); disconnect(w, &PlasmaWindow::plasmaVirtualDesktopLeft, this, &WaylandInterface::updateWindow); disconnect(w, &PlasmaWindow::unmapped, this, &WaylandInterface::windowUnmapped); disconnect(w, &PlasmaWindow::titleChanged, 0, 0); disconnect(w, &PlasmaWindow::iconChanged, 0, 0); disconnect(w, &PlasmaWindow::activeChanged, 0, 0); disconnect(w, &PlasmaWindow::keepAboveChanged, 0, 0); disconnect(w, &PlasmaWindow::keepBelowChanged, 0, 0); disconnect(w, &PlasmaWindow::minimizedChanged, 0, 0); disconnect(w, &PlasmaWindow::maximizedChanged, 0, 0); disconnect(w, &PlasmaWindow::onAllDesktopsChanged, 0, 0); disconnect(w, &PlasmaWindow::demandsAttentionChanged, 0, 0); disconnect(w, &PlasmaWindow::skipTaskbarChanged, 0, 0); disconnect(w, &PlasmaWindow::skipSwitcherChanged, 0, 0); disconnect(w, &PlasmaWindow::geometryChanged, 0, 0); } void WaylandInterface::setCurrentDesktop(QString desktop) { if (m_currentDesktop == desktop) { return; } m_currentDesktop = desktop; emit currentDesktopChanged(); } void WaylandInterface::addDesktop(const QString &id, quint32 position) { if (m_desktops.contains(id)) { return; } m_desktops.append(id); const KWayland::Client::PlasmaVirtualDesktop *desktop = m_virtualDesktopManagement->getVirtualDesktop(id); QObject::connect(desktop, &KWayland::Client::PlasmaVirtualDesktop::activated, this, [desktop, this]() { setCurrentDesktop(desktop->id()); } ); if (desktop->isActive()) { setCurrentDesktop(id); } } libkysdk-applications/kysdk-waylandhelper/src/windowmanager/waylandinterface.h0000664000175000017500000000731715104515306027114 0ustar fengfeng/* * libkysdk-waylandhelper's Library * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #ifndef WAYLANDINTERFACE_H #define WAYLANDINTERFACE_H #include "abstractinterface.h" #include #include #include #include #include #include #include using namespace kdk; using namespace KWayland::Client; class Q_DECL_HIDDEN WaylandInterface:public AbstractInterface { public: WaylandInterface(QObject* parent=nullptr); ~WaylandInterface(); WindowInfo requestInfo(WindowId wid) override; void requestActivate(WindowId wid) override; void requestClose(WindowId wid) override; void requestToggleKeepAbove(WindowId wid) override; void requestToggleMinimized(WindowId wid) override; void requestToggleMaximized(WindowId wid) override; QIcon iconFor(WindowId wid) override; QString titleFor(WindowId wid) override; QString windowGroupFor(WindowId wid) override; quint32 pid(WindowId wid) override; void showCurrentDesktop() override; void hideCurrentDesktop() override; bool windowCanBeDragged(WindowId wid) override; bool windowCanBeMaximized(WindowId wid) override; WindowId activeWindow() override; void setGeometry(QWindow *window, const QRect &rect) override; void setSkipTaskBar(QWindow* window,bool skip) override; void setSkipSwitcher(QWindow* window,bool skip) override; bool skipTaskBar(const WindowId &wid) override; bool skipSwitcher(const WindowId &wid) override; bool isShowingDesktop(); void setOnAllDesktops(const WindowId &wid); NET::WindowType windowType(WindowId wid) override; void setPanelTakefocus(QWindow *window, bool flag) override; void demandAttention(const WindowId &wid) override; protected: bool eventFilter(QObject *obj, QEvent *ev) override; private slots: void updateWindow(); void windowUnmapped(); private: PlasmaWindow *windowFor(WindowId wid) ; bool isValidWindow(const KWayland::Client::PlasmaWindow *w) ; bool isPlasmaDesktop(const KWayland::Client::PlasmaWindow *w) ; bool isPlasmaPanel(const KWayland::Client::PlasmaWindow *w) ; void windowCreatedProxy(KWayland::Client::PlasmaWindow *w); void trackWindow(KWayland::Client::PlasmaWindow *w); void untrackWindow(KWayland::Client::PlasmaWindow *w); void setCurrentDesktop(QString desktop); void addDesktop(const QString &id, quint32 position); private: ConnectionThread *m_connection=nullptr; PlasmaShell *m_plasmaShell = nullptr; Shell *m_shell = nullptr; PlasmaWindowManagement *m_windowManager = nullptr; PlasmaWindow *m_appWindow = nullptr; PlasmaVirtualDesktopManagement *m_virtualDesktopManagement{nullptr}; QStringList m_desktops; QMapm_surfaces; QMapm_plasmaShellSurfaces; }; #endif // WAYLANDINTERFACE_H libkysdk-applications/kysdk-waylandhelper/src/windowmanager/netwm.h0000664000175000017500000015347715104543305024737 0ustar fengfeng/* Copyright (c) 2000 Troll Tech AS Copyright (c) 2003 Lubos Lunak Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef netwm_h #define netwm_h #include #include #include #if KWINDOWSYSTEM_HAVE_X11 #include #include #include "netwm_def.h" #define KDE_ALL_ACTIVITIES_UUID "00000000-0000-0000-0000-000000000000" // forward declaration struct NETRootInfoPrivate; struct NETWinInfoPrivate; template class NETRArray; /** Common API for root window properties/protocols. The NETRootInfo class provides a common API for clients and window managers to set/read/change properties on the root window as defined by the NET Window Manager Specification.. @author Bradley T. Hughes @see NET @see NETWinInfo **/ class KWINDOWSYSTEM_EXPORT NETRootInfo : public NET { public: /** Indexes for the properties array. **/ // update also NETRootInfoPrivate::properties[] size when extending this enum { PROTOCOLS, WINDOW_TYPES, STATES, PROTOCOLS2, ACTIONS, PROPERTIES_SIZE }; /** Window Managers should use this constructor to create a NETRootInfo object, which will be used to set/update information stored on the rootWindow. The application role is automatically set to WindowManager when using this constructor. @param connection XCB connection @param supportWindow The Window id of the supportWindow. The supportWindow must be created by the window manager as a child of the rootWindow. The supportWindow must not be destroyed until the Window Manager exits. @param wmName A string which should be the window manager's name (ie. "KWin" or "Blackbox"). @param properties The properties the window manager supports @param windowTypes The window types the window manager supports @param states The states the window manager supports @param properties2 The properties2 the window manager supports @param actions The actions the window manager supports @param screen For Window Managers that support multiple screen (ie. "multiheaded") displays, the screen number may be explicitly defined. If this argument is omitted, the default screen will be used. @param doActivate true to activate the window **/ NETRootInfo(xcb_connection_t *connection, xcb_window_t supportWindow, const char *wmName, NET::Properties properties, NET::WindowTypes windowTypes, NET::States states, NET::Properties2 properties2, NET::Actions actions, int screen = -1, bool doActivate = true); /** Clients should use this constructor to create a NETRootInfo object, which will be used to query information set on the root window. The application role is automatically set to Client when using this constructor. @param connection XCB connection @param properties The properties the client is interested in. @param properties2 The properties2 the client is interested in. @param properties_size The number of elements in the properties array. @param screen For Clients that support multiple screen (ie. "multiheaded") displays, the screen number may be explicitly defined. If this argument is omitted, the default screen will be used. @param doActivate true to call activate() to do an initial data read/update of the query information. **/ NETRootInfo(xcb_connection_t *connection, NET::Properties properties, NET::Properties2 properties2 = NET::Properties2(), int screen = -1, bool doActivate = true); /** Creates a shared copy of the specified NETRootInfo object. @param rootinfo the NETRootInfo object to copy **/ NETRootInfo(const NETRootInfo &rootinfo); /** Destroys the NETRootInfo object. **/ virtual ~NETRootInfo(); /** Returns the xcb connection used. @return the XCB connection **/ xcb_connection_t *xcbConnection() const; /** Returns the Window id of the rootWindow. @return the id of the root window **/ xcb_window_t rootWindow() const; /** Returns the Window id of the supportWindow. @return the id of the support window **/ xcb_window_t supportWindow() const; /** Returns the name of the Window Manager. @return the name of the window manager **/ const char *wmName() const; /** Sets the given property if on is true, and clears the property otherwise. In WindowManager mode this function updates _NET_SUPPORTED. In Client mode this function does nothing. @since 4.4 **/ void setSupported(NET::Property property, bool on = true); /** @overload @since 4.4 **/ void setSupported(NET::Property2 property, bool on = true); /** @overload @since 4.4 **/ void setSupported(NET::WindowTypeMask property, bool on = true); /** @overload @since 4.4 **/ void setSupported(NET::State property, bool on = true); /** @overload @since 4.4 **/ void setSupported(NET::Action property, bool on = true); /** Returns true if the given property is supported by the window manager. Note that for Client mode, NET::Supported needs to be passed in the properties argument for this to work. **/ bool isSupported(NET::Property property) const; /** @overload **/ bool isSupported(NET::Property2 property) const; /** @overload **/ bool isSupported(NET::WindowTypeMask type) const; /** @overload **/ bool isSupported(NET::State state) const; /** @overload **/ bool isSupported(NET::Action action) const; /** In the Window Manager mode, this is equivalent to the properties argument passed to the constructor. In the Client mode, if NET::Supported was passed in the properties argument, the returned value are all properties supported by the Window Manager. Other supported protocols and properties are returned by the specific methods. @see supportedProperties2() @see supportedStates() @see supportedWindowTypes() @see supportedActions() **/ NET::Properties supportedProperties() const; /** * In the Window Manager mode, this is equivalent to the properties2 * argument passed to the constructor. In the Client mode, if * NET::Supported was passed in the properties argument, the returned * value are all properties2 supported by the Window Manager. Other supported * protocols and properties are returned by the specific methods. * @see supportedProperties() * @see supportedStates() * @see supportedWindowTypes() * @see supportedActions() * @since 5.0 **/ NET::Properties2 supportedProperties2() const; /** * In the Window Manager mode, this is equivalent to the states * argument passed to the constructor. In the Client mode, if * NET::Supported was passed in the properties argument, the returned * value are all states supported by the Window Manager. Other supported * protocols and properties are returned by the specific methods. * @see supportedProperties() @see supportedProperties2() * @see supportedWindowTypes() * @see supportedActions() * @since 5.0 **/ NET::States supportedStates() const; /** * In the Window Manager mode, this is equivalent to the windowTypes * argument passed to the constructor. In the Client mode, if * NET::Supported was passed in the properties argument, the returned * value are all window types supported by the Window Manager. Other supported * protocols and properties are returned by the specific methods. * @see supportedProperties() @see supportedProperties2() * @see supportedStates() * @see supportedActions() * @since 5.0 **/ NET::WindowTypes supportedWindowTypes() const; /** * In the Window Manager mode, this is equivalent to the actions * argument passed to the constructor. In the Client mode, if * NET::Supported was passed in the properties argument, the returned * value are all actions supported by the Window Manager. Other supported * protocols and properties are returned by the specific methods. * @see supportedProperties() @see supportedProperties2() * @see supportedStates() * @see supportedWindowTypes() * @since 5.0 **/ NET::Actions supportedActions() const; /** * @returns the properties argument passed to the constructor. * @see passedProperties2() * @see passedStates() * @see passedWindowTypes() * @see passedActions() **/ NET::Properties passedProperties() const; /** * @returns the properties2 argument passed to the constructor. * @see passedProperties() * @see passedStates() * @see passedWindowTypes() * @see passedActions() * @since 5.0 **/ NET::Properties2 passedProperties2() const; /** * @returns the states argument passed to the constructor. * @see passedProperties() * @see passedProperties2() * @see passedWindowTypes() * @see passedActions() * @since 5.0 **/ NET::States passedStates() const; /** * @returns the windowTypes argument passed to the constructor. * @see passedProperties() * @see passedProperties2() * @see passedStates() * @see passedActions() * @since 5.0 **/ NET::WindowTypes passedWindowTypes() const; /** * @returns the actions argument passed to the constructor. * @see passedProperties() * @see passedProperties2() * @see passedStates() * @see passedWindowTypes() * @since 5.0 **/ NET::Actions passedActions() const; /** Returns an array of Window id's, which contain all managed windows. @return the array of Window id's @see clientListCount() **/ const xcb_window_t *clientList() const; /** Returns the number of managed windows in clientList array. @return the number of managed windows in the clientList array @see clientList() **/ int clientListCount() const; /** Returns an array of Window id's, which contain all managed windows in stacking order. @return the array of Window id's in stacking order @see clientListStackingCount() **/ const xcb_window_t *clientListStacking() const; /** Returns the number of managed windows in the clientListStacking array. @return the number of Window id's in the client list @see clientListStacking() **/ int clientListStackingCount() const; /** Returns the desktop geometry size. NOTE: KDE uses virtual desktops and does not directly support viewport in any way. You should use calls for virtual desktops, viewport is mapped to them if needed. @return the size of the desktop **/ NETSize desktopGeometry() const; /** Returns the viewport of the specified desktop. NOTE: KDE uses virtual desktops and does not directly support viewport in any way. You should use calls for virtual desktops, viewport is mapped to them if needed. @param desktop the number of the desktop @return the position of the desktop's viewport **/ NETPoint desktopViewport(int desktop) const; /** Returns the workArea for the specified desktop. @param desktop the number of the desktop @return the size of the work area **/ NETRect workArea(int desktop) const; /** Returns the name for the specified desktop. @param desktop the number of the desktop @return the name of the desktop **/ const char *desktopName(int desktop) const; /** Returns an array of Window id's, which contain the virtual root windows. @return the array of Window id's @see virtualRootsCount() **/ const xcb_window_t *virtualRoots() const; /** Returns the number of window in the virtualRoots array. @return the number of Window id's in the virtual root array @see virtualRoots() **/ int virtualRootsCount() const; /** Returns the desktop layout orientation. **/ NET::Orientation desktopLayoutOrientation() const; /** Returns the desktop layout number of columns and rows. Note that either may be 0 (see _NET_DESKTOP_LAYOUT). **/ QSize desktopLayoutColumnsRows() const; /** Returns the desktop layout starting corner. **/ NET::DesktopLayoutCorner desktopLayoutCorner() const; /** Returns the number of desktops. NOTE: KDE uses virtual desktops and does not directly support viewport in any way. They are however mapped to virtual desktops if needed. @param ignore_viewport if false, viewport is mapped to virtual desktops @return the number of desktops **/ int numberOfDesktops(bool ignore_viewport = false) const; /** Returns the current desktop. NOTE: KDE uses virtual desktops and does not directly support viewport in any way. They are however mapped to virtual desktops if needed. @param ignore_viewport if false, viewport is mapped to virtual desktops @return the number of the current desktop **/ int currentDesktop(bool ignore_viewport = false) const; /** Returns the active (focused) window. @return the id of the active window **/ xcb_window_t activeWindow() const; /** Window Managers must call this after creating the NETRootInfo object, and before using any other method in the class. This method sets initial data on the root window and does other post-construction duties. Clients must also call this after creating the object to do an initial data read/update. **/ void activate(); /** Sets the list of managed windows on the Root/Desktop window. @param windows The array of Window id's @param count The number of windows in the array **/ void setClientList(const xcb_window_t *windows, unsigned int count); /** Sets the list of managed windows in stacking order on the Root/Desktop window. @param windows The array of Window id's @param count The number of windows in the array. **/ void setClientListStacking(const xcb_window_t *windows, unsigned int count); /** Sets the current desktop to the specified desktop. NOTE: KDE uses virtual desktops and does not directly support viewport in any way. It is however mapped to virtual desktops if needed. @param desktop the number of the desktop @param ignore_viewport if false, viewport is mapped to virtual desktops **/ void setCurrentDesktop(int desktop, bool ignore_viewport = false); /** Sets the desktop geometry to the specified geometry. NOTE: KDE uses virtual desktops and does not directly support viewport in any way. You should use calls for virtual desktops, viewport is mapped to them if needed. @param geometry the new size of the desktop **/ void setDesktopGeometry(const NETSize &geometry); /** Sets the viewport for the current desktop to the specified point. NOTE: KDE uses virtual desktops and does not directly support viewport in any way. You should use calls for virtual desktops, viewport is mapped to them if needed. @param desktop the number of the desktop @param viewport the new position of the desktop's viewport **/ void setDesktopViewport(int desktop, const NETPoint &viewport); /** Sets the number of desktops to the specified number. NOTE: KDE uses virtual desktops and does not directly support viewport in any way. Viewport is mapped to virtual desktops if needed, but not for this call. @param numberOfDesktops the number of desktops **/ void setNumberOfDesktops(int numberOfDesktops); /** Sets the name of the specified desktop. NOTE: KDE uses virtual desktops and does not directly support viewport in any way. Viewport is mapped to virtual desktops if needed, but not for this call. @param desktop the number of the desktop @param desktopName the new name of the desktop **/ void setDesktopName(int desktop, const char *desktopName); /** Requests that the specified window becomes the active (focused) one. @param window the id of the new active window @param src whether the request comes from normal application or from a pager or similar tool @param timestamp X server timestamp of the user action that caused the request @param active_window active window of the requesting application, if any **/ void setActiveWindow(xcb_window_t window, NET::RequestSource src, xcb_timestamp_t timestamp, xcb_window_t active_window); /** Sets the active (focused) window the specified window. This should be used only in the window manager mode. @param window the if of the new active window **/ void setActiveWindow(xcb_window_t window); /** Sets the workarea for the specified desktop @param desktop the number of the desktop @param workArea the new work area of the desktop **/ void setWorkArea(int desktop, const NETRect &workArea); /** Sets the list of virtual root windows on the root window. @param windows The array of Window id's @param count The number of windows in the array. **/ void setVirtualRoots(const xcb_window_t *windows, unsigned int count); /** Sets the desktop layout. This is set by the pager. When setting, the pager must own the _NET_DESKTOP_LAYOUT_Sn manager selection. See _NET_DESKTOP_LAYOUT for details. **/ void setDesktopLayout(NET::Orientation orientation, int columns, int rows, NET::DesktopLayoutCorner corner); /** * Sets the _NET_SHOWING_DESKTOP status (whether desktop is being shown). */ void setShowingDesktop(bool showing); /** * Returns the status of _NET_SHOWING_DESKTOP. */ bool showingDesktop() const; /** Assignment operator. Ensures that the shared data reference counts are correct. **/ const NETRootInfo &operator=(const NETRootInfo &rootinfo); /** Clients (such as pagers/taskbars) that wish to close a window should call this function. This will send a request to the Window Manager, which usually can usually decide how to react to such requests. @param window the id of the window to close **/ void closeWindowRequest(xcb_window_t window); /** Clients (such as pagers/taskbars) that wish to start a WMMoveResize (where the window manager controls the resize/movement, i.e. _NET_WM_MOVERESIZE) should call this function. This will send a request to the Window Manager. @param window The client window that would be resized/moved. @param x_root X position of the cursor relative to the root window. @param y_root Y position of the cursor relative to the root window. @param direction One of NET::Direction (see base class documentation for a description of the different directions). **/ void moveResizeRequest(xcb_window_t window, int x_root, int y_root, Direction direction); /** Clients (such as pagers/taskbars) that wish to move/resize a window using WM2MoveResizeWindow (_NET_MOVERESIZE_WINDOW) should call this function. This will send a request to the Window Manager. See _NET_MOVERESIZE_WINDOW description for details. @param window The client window that would be resized/moved. @param flags Flags specifying the operation (see _NET_MOVERESIZE_WINDOW description) @param x Requested X position for the window @param y Requested Y position for the window @param width Requested width for the window @param height Requested height for the window **/ void moveResizeWindowRequest(xcb_window_t window, int flags, int x, int y, int width, int height); /** Sends the _NET_RESTACK_WINDOW request. **/ void restackRequest(xcb_window_t window, RequestSource source, xcb_window_t above, int detail, xcb_timestamp_t timestamp); /** Sends a ping with the given timestamp to the window, using the _NET_WM_PING protocol. */ void sendPing(xcb_window_t window, xcb_timestamp_t timestamp); #if KWINDOWSYSTEM_ENABLE_DEPRECATED_SINCE(5, 0) /** This function takes the passed XEvent and returns an OR'ed list of NETRootInfo properties that have changed in the properties argument. The new information will be read immediately by the class. The elements of the properties argument are as they would be passed to the constructor, if the array is not large enough, changed properties that don't fit in it won't be listed there (they'll be updated in the class though). @param event the event @param properties properties that changed @param properties_size size of the passed properties array @deprecated since 5.0 use event(xcb_generic_event_t*, NET::Properties*, NET::Properties2*) **/ // KWINDOWSYSTEM_DEPRECATED_VERSION(5, 0, "Use NETRootInfo::event(xcb_generic_event_t*, NET::Properties*, NET::Properties2*)") Q_DECL_DEPRECATED_X("Use NETWinInfo(xcb_connection_t *, xcb_window_t, xcb_window_t, NET::Properties, NET::Properties2, Role") void event(xcb_generic_event_t *event, unsigned long *properties, int properties_size); #endif /** * This function takes the passed xcb_generic_event_t and returns the updated properties in the passed in arguments. * * The new information will be read immediately by the class. It is possible to pass in a * null pointer in the arguments. In that case the passed in argument will obviously not * be updated, but the class will process the information nevertheless. * * @param event the event * @param properties The NET::Properties that changed * @param properties2 The NET::Properties2 that changed * @since 5.0 **/ void event(xcb_generic_event_t *event, NET::Properties *properties, NET::Properties2 *properties2 = nullptr); /** This function takes the passed XEvent and returns an OR'ed list of NETRootInfo properties that have changed. The new information will be read immediately by the class. This overloaded version returns only a single mask, and therefore cannot check state of all properties like the other variant. @param event the event @return the properties **/ NET::Properties event(xcb_generic_event_t *event); protected: /** A Client should subclass NETRootInfo and reimplement this function when it wants to know when a window has been added. @param window the id of the window to add **/ virtual void addClient(xcb_window_t window) { Q_UNUSED(window); } /** A Client should subclass NETRootInfo and reimplement this function when it wants to know when a window has been removed. @param window the id of the window to remove **/ virtual void removeClient(xcb_window_t window) { Q_UNUSED(window); } /** A Window Manager should subclass NETRootInfo and reimplement this function when it wants to know when a Client made a request to change the number of desktops. @param numberOfDesktops the new number of desktops **/ virtual void changeNumberOfDesktops(int numberOfDesktops) { Q_UNUSED(numberOfDesktops); } /** A Window Manager should subclass NETRootInfo and reimplement this function when it wants to know when a Client made a request to change the specified desktop geometry. @param desktop the number of the desktop @param geom the new size **/ virtual void changeDesktopGeometry(int desktop, const NETSize &geom) { Q_UNUSED(desktop); Q_UNUSED(geom); } /** A Window Manager should subclass NETRootInfo and reimplement this function when it wants to know when a Client made a request to change the specified desktop viewport. @param desktop the number of the desktop @param viewport the new position of the viewport **/ virtual void changeDesktopViewport(int desktop, const NETPoint &viewport) { Q_UNUSED(desktop); Q_UNUSED(viewport); } /** A Window Manager should subclass NETRootInfo and reimplement this function when it wants to know when a Client made a request to change the current desktop. @param desktop the number of the desktop **/ virtual void changeCurrentDesktop(int desktop) { Q_UNUSED(desktop); } /** A Window Manager should subclass NETRootInfo and reimplement this function when it wants to know when a Client made a request to close a window. @param window the id of the window to close **/ virtual void closeWindow(xcb_window_t window) { Q_UNUSED(window); } /** A Window Manager should subclass NETRootInfo and reimplement this function when it wants to know when a Client made a request to start a move/resize. @param window The window that wants to move/resize @param x_root X position of the cursor relative to the root window. @param y_root Y position of the cursor relative to the root window. @param direction One of NET::Direction (see base class documentation for a description of the different directions). **/ virtual void moveResize(xcb_window_t window, int x_root, int y_root, unsigned long direction) { Q_UNUSED(window); Q_UNUSED(x_root); Q_UNUSED(y_root); Q_UNUSED(direction); } /** A Window Manager should subclass NETRootInfo and reimplement this function when it wants to receive replies to the _NET_WM_PING protocol. @param window the window from which the reply came @param timestamp timestamp of the ping */ virtual void gotPing(xcb_window_t window, xcb_timestamp_t timestamp) { Q_UNUSED(window); Q_UNUSED(timestamp); } /** A Window Manager should subclass NETRootInfo and reimplement this function when it wants to know when a Client made a request to change the active (focused) window. @param window the id of the window to activate @param src the source from which the request came @param timestamp the timestamp of the user action causing this request @param active_window active window of the requesting application, if any **/ virtual void changeActiveWindow(xcb_window_t window, NET::RequestSource src, xcb_timestamp_t timestamp, xcb_window_t active_window) { Q_UNUSED(window); Q_UNUSED(src); Q_UNUSED(timestamp); Q_UNUSED(active_window); } /** A Window Manager should subclass NETRootInfo and reimplement this function when it wants to know when a pager made a request to move/resize a window. See _NET_MOVERESIZE_WINDOW for details. @param window the id of the window to more/resize @param flags Flags specifying the operation (see _NET_MOVERESIZE_WINDOW description) @param x Requested X position for the window @param y Requested Y position for the window @param width Requested width for the window @param height Requested height for the window **/ virtual void moveResizeWindow(xcb_window_t window, int flags, int x, int y, int width, int height) { Q_UNUSED(window); Q_UNUSED(flags); Q_UNUSED(x); Q_UNUSED(y); Q_UNUSED(width); Q_UNUSED(height); } /** A Window Manager should subclass NETRootInfo and reimplement this function when it wants to know when a Client made a request to restack a window. See _NET_RESTACK_WINDOW for details. @param window the id of the window to restack @param source the source of the request @param above other window in the restack request @param detail restack detail @param timestamp the timestamp of the request **/ virtual void restackWindow(xcb_window_t window, RequestSource source, xcb_window_t above, int detail, xcb_timestamp_t timestamp) { Q_UNUSED(window); Q_UNUSED(source); Q_UNUSED(above); Q_UNUSED(detail); Q_UNUSED(timestamp); } /** A Window Manager should subclass NETRootInfo and reimplement this function when it wants to know when a pager made a request to change showing the desktop. See _NET_SHOWING_DESKTOP for details. @param showing whether to activate the showing desktop mode **/ virtual void changeShowingDesktop(bool showing) { Q_UNUSED(showing); } private: void update(NET::Properties properties, NET::Properties2 properties2); void setSupported(); void setDefaultProperties(); void updateSupportedProperties(xcb_atom_t atom); protected: /** Virtual hook, used to add new "virtual" functions while maintaining binary compatibility. Unused in this class. */ virtual void virtual_hook(int id, void *data); private: NETRootInfoPrivate *p; // krazy:exclude=dpointer (implicitly shared) }; /** Common API for application window properties/protocols. The NETWinInfo class provides a common API for clients and window managers to set/read/change properties on an application window as defined by the NET Window Manager Specification. @author Bradley T. Hughes @see NET @see NETRootInfo @see http://www.freedesktop.org/standards/wm-spec/ **/ class KWINDOWSYSTEM_EXPORT NETWinInfo : public NET { public: /** Indexes for the properties array. **/ // update also NETWinInfoPrivate::properties[] size when extending this enum { PROTOCOLS, PROTOCOLS2, PROPERTIES_SIZE }; /** Create a NETWinInfo object, which will be used to set/read/change information stored on an application window. @param connection XCB connection @param window The Window id of the application window. @param rootWindow The Window id of the root window. @param properties The NET::Properties flags @param properties2 The NET::Properties2 flags @param role Select the application role. If this argument is omitted, the role will default to Client. **/ NETWinInfo(xcb_connection_t *connection, xcb_window_t window, xcb_window_t rootWindow, NET::Properties properties, NET::Properties2 properties2, Role role = Client); #if KWINDOWSYSTEM_ENABLE_DEPRECATED_SINCE(5, 0) /** This constructor differs from the above one only in the way it accepts the list of properties the client is interested in. @deprecated since 5.0 use above ctor **/ // KWINDOWSYSTEM_DEPRECATED_VERSION(5, 0, "Use NETWinInfo(xcb_connection_t *, xcb_window_t, xcb_window_t, NET::Properties, NET::Properties2, Role") Q_DECL_DEPRECATED_X("Use NETWinInfo(xcb_connection_t *, xcb_window_t, xcb_window_t, NET::Properties, NET::Properties2, Role") NETWinInfo(xcb_connection_t *connection, xcb_window_t window, xcb_window_t rootWindow, NET::Properties properties, Role role = Client); #endif /** Creates a shared copy of the specified NETWinInfo object. @param wininfo the NETWinInfo to copy **/ NETWinInfo(const NETWinInfo &wininfo); /** Destroys the NETWinInfo object. **/ virtual ~NETWinInfo(); /** Assignment operator. Ensures that the shared data reference counts are correct. **/ const NETWinInfo &operator=(const NETWinInfo &wintinfo); /** Returns the xcb connection used. @return the XCB connection **/ xcb_connection_t *xcbConnection() const; /** Returns true if the window has any window type set, even if the type itself is not known to this implementation. Presence of a window type as specified by the NETWM spec is considered as the window supporting this specification. @return true if the window has support for the NETWM spec **/ bool hasNETSupport() const; /** @returns the properties argument passed to the constructor. @see passedProperties2() **/ NET::Properties passedProperties() const; /** * @returns the properties2 argument passed to the constructor. * @see passedProperties() * @since 5.0 **/ NET::Properties2 passedProperties2() const; /** Returns the icon geometry. @return the geometry of the icon **/ NETRect iconGeometry() const; /** Returns the state of the window (see the NET base class documentation for a description of the various states). @return the state of the window **/ NET::States state() const; /** Returns the extended (partial) strut specified by this client. See _NET_WM_STRUT_PARTIAL in the spec. **/ NETExtendedStrut extendedStrut() const; // Still used internally, e.g. by KWindowSystem::strutChanged() logic /** @deprecated use strutPartial() Returns the strut specified by this client. @return the strut of the window **/ NETStrut strut() const; /** Returns the window type for this client (see the NET base class documentation for a description of the various window types). Since clients may specify several windows types for a window in order to support backwards compatibility and extensions not available in the NETWM spec, you should specify all window types you application supports (see the NET::WindowTypeMask mask values for various window types). This method will return the first window type that is listed in the supported types, or NET::Unknown if none of the window types is supported. @return the type of the window **/ WindowType windowType(WindowTypes supported_types) const; /** This function returns false if the window has not window type specified at all. Used by KWindowInfo::windowType() to return either NET::Normal or NET::Dialog as appropriate as a fallback. **/ bool hasWindowType() const; /** Returns the name of the window in UTF-8 format. @return the name of the window **/ const char *name() const; /** Returns the visible name as set by the window manager in UTF-8 format. @return the visible name of the window **/ const char *visibleName() const; /** Returns the iconic name of the window in UTF-8 format. Note that this has nothing to do with icons, but it's for "iconic" representations of the window (taskbars etc.), that should be shown when the window is in iconic state. See description of _NET_WM_ICON_NAME for details. @return the iconic name **/ const char *iconName() const; /** Returns the visible iconic name as set by the window manager in UTF-8 format. Note that this has nothing to do with icons, but it's for "iconic" representations of the window (taskbars etc.), that should be shown when the window is in iconic state. See description of _NET_WM_VISIBLE_ICON_NAME for details. @return the visible iconic name **/ const char *visibleIconName() const; /** Returns the desktop where the window is residing. NOTE: KDE uses virtual desktops and does not directly support viewport in any way. It is however mapped to virtual desktops if needed. @param ignore_viewport if false, viewport is mapped to virtual desktops @return the number of the window's desktop @see OnAllDesktops() **/ int desktop(bool ignore_viewport = false) const; /** Returns the process id for the client window. @return the process id of the window **/ int pid() const; /** Returns whether or not this client handles icons. @return true if this client handles icons, false otherwise **/ bool handledIcons() const; /** Returns the mapping state for the window (see the NET base class documentation for a description of mapping state). @return the mapping state **/ MappingState mappingState() const; /** Set icons for the application window. If replace is True, then the specified icon is defined to be the only icon. If replace is False, then the specified icon is added to a list of icons. @param icon the new icon @param replace true to replace, false to append to the list of icons **/ void setIcon(NETIcon icon, bool replace = true); /** Set the icon geometry for the application window. @param geometry the new icon geometry **/ void setIconGeometry(NETRect geometry); /** Set the extended (partial) strut for the application window. @param extended_strut the new strut **/ void setExtendedStrut(const NETExtendedStrut &extended_strut); // Still used internally, e.g. by KWindowSystem::strutChanged() logic /** @deprecated use setExtendedStrut() Set the strut for the application window. @param strut the new strut **/ void setStrut(NETStrut strut); /** Set the state for the application window (see the NET base class documentation for a description of window state). @param state the name state @param mask the mask for the state **/ void setState(NET::States state, NET::States mask); /** Sets the window type for this client (see the NET base class documentation for a description of the various window types). @param type the window type **/ void setWindowType(WindowType type); /** Sets the name for the application window. @param name the new name of the window **/ void setName(const char *name); /** For Window Managers only: set the visible name ( i.e. xterm, xterm <2>, xterm <3>, ... ) @param visibleName the new visible name **/ void setVisibleName(const char *visibleName); /** Sets the iconic name for the application window. @param name the new iconic name **/ void setIconName(const char *name); /** For Window Managers only: set the visible iconic name ( i.e. xterm, xterm <2>, xterm <3>, ... ) @param name the new visible iconic name **/ void setVisibleIconName(const char *name); /** Set which window the desktop is (should be) on. NOTE: KDE uses virtual desktops and does not directly support viewport in any way. It is however mapped to virtual desktops if needed. @param desktop the number of the new desktop @param ignore_viewport if false, viewport is mapped to virtual desktops @see OnAllDesktops() **/ void setDesktop(int desktop, bool ignore_viewport = false); /** Set the application window's process id. @param pid the window's process id **/ void setPid(int pid); /** Set whether this application window handles icons. @param handled true if the window handles icons, false otherwise **/ void setHandledIcons(bool handled); /** Set the frame decoration strut, i.e. the width of the decoration borders. @param strut the new strut **/ void setFrameExtents(NETStrut strut); /** Returns the frame decoration strut, i.e. the width of the decoration borders. @since 4.3 **/ NETStrut frameExtents() const; /** Sets the window frame overlap strut, i.e. how far the window frame extends behind the client area on each side. Set the strut values to -1 if you want the window frame to cover the whole client area. The default values are 0. @since 4.4 **/ void setFrameOverlap(NETStrut strut); /** Returns the frame overlap strut, i.e. how far the window frame extends behind the client area on each side. @since 4.4 **/ NETStrut frameOverlap() const; /** Sets the extents of the drop-shadow drawn by the client. @since 5.65 **/ void setGtkFrameExtents(NETStrut strut); /** Returns the extents of the drop-shadow drawn by a GTK client. @since 5.65 **/ NETStrut gtkFrameExtents() const; /** Returns an icon. If width and height are passed, the icon returned will be the closest it can find (the next biggest). If width and height are omitted, then the largest icon in the list is returned. @param width the preferred width for the icon, -1 to ignore @param height the preferred height for the icon, -1 to ignore @return the icon **/ NETIcon icon(int width = -1, int height = -1) const; /** Returns a list of provided icon sizes. Each size is pair width,height, terminated with pair 0,0. @since 4.3 **/ const int *iconSizes() const; /** * Sets user timestamp @p time on the window (property _NET_WM_USER_TIME). * The timestamp is expressed as XServer time. If a window * is shown with user timestamp older than the time of the last * user action, it won't be activated after being shown, with the special * value 0 meaning not to activate the window after being shown. */ void setUserTime(xcb_timestamp_t time); /** * Returns the time of last user action on the window, or -1 if not set. */ xcb_timestamp_t userTime() const; /** * Sets the startup notification id @p id on the window. */ void setStartupId(const char *startup_id); /** * Returns the startup notification id of the window. */ const char *startupId() const; /** * Sets opacity (0 = transparent, 0xffffffff = opaque ) on the window. */ void setOpacity(unsigned long opacity); /** * Returns the opacity of the window. */ unsigned long opacity() const; /** * Sets actions that the window manager allows for the window. */ void setAllowedActions(NET::Actions actions); /** * Returns actions that the window manager allows for the window. */ NET::Actions allowedActions() const; /** * Returns the WM_TRANSIENT_FOR property for the window, i.e. the mainwindow * for this window. */ xcb_window_t transientFor() const; /** * Returns the leader window for the group the window is in, if any. */ xcb_window_t groupLeader() const; /** * Returns whether the UrgencyHint is set in the WM_HINTS.flags. * See ICCCM 4.1.2.4. * * @since 5.3 **/ bool urgency() const; /** * Returns whether the Input flag is set in WM_HINTS. * See ICCCM 4.1.2.4 and 4.1.7. * * The default value is @c true in case the Client is mapped without a WM_HINTS property. * * @since 5.3 **/ bool input() const; /** * Returns the initial mapping state as set in WM_HINTS. * See ICCCM 4.1.2.4 and 4.1.4. * * The default value if @c Withdrawn in case the Client is mapped without * a WM_HINTS property or without the initial state hint set. * * @since 5.5 **/ MappingState initialMappingState() const; /** * Returns the icon pixmap as set in WM_HINTS. * See ICCCM 4.1.2.4. * * The default value is @c XCB_PIXMAP_NONE. * * Using the ICCCM variant for the icon is deprecated and only * offers a limited functionality compared to {@link icon}. * Only use this variant as a fallback. * * @see icccmIconPixmapMask * @see icon * @since 5.7 **/ xcb_pixmap_t icccmIconPixmap() const; /** * Returns the mask for the icon pixmap as set in WM_HINTS. * See ICCCM 4.1.2.4. * * The default value is @c XCB_PIXMAP_NONE. * * @see icccmIconPixmap * @since 5.7 **/ xcb_pixmap_t icccmIconPixmapMask() const; /** * Returns the class component of the window class for the window * (i.e. WM_CLASS property). */ const char *windowClassClass() const; /** * Returns the name component of the window class for the window * (i.e. WM_CLASS property). */ const char *windowClassName() const; /** * Returns the window role for the window (i.e. WM_WINDOW_ROLE property). */ const char *windowRole() const; /** * Returns the client machine for the window (i.e. WM_CLIENT_MACHINE property). */ const char *clientMachine() const; /** * returns a comma-separated list of the activities the window is associated with. * FIXME this might be better as a NETRArray ? * @since 4.6 */ const char *activities() const; /** * Sets the comma-separated list of activities the window is associated with. * @since 5.1 */ void setActivities(const char *activities); /** * Sets whether the client wishes to block compositing (for better performance) * @since 4.7 */ void setBlockingCompositing(bool active); /** * Returns whether the client wishes to block compositing (for better performance) * @since 4.7 */ bool isBlockingCompositing() const; /** Places the window frame geometry in frame, and the application window geometry in window. Both geometries are relative to the root window. @param frame the geometry for the frame @param window the geometry for the window **/ void kdeGeometry(NETRect &frame, NETRect &window); /** Sets the desired multiple-monitor topology (4 monitor indices indicating the top, bottom, left, and right edges of the window) when the fullscreen state is enabled. The indices are from the set returned by the Xinerama extension. See _NET_WM_FULLSCREEN_MONITORS for details. @param topology A struct that models the desired monitor topology, namely: top is the monitor whose top edge defines the top edge of the fullscreen window, bottom is the monitor whose bottom edge defines the bottom edge of the fullscreen window, left is the monitor whose left edge defines the left edge of the fullscreen window, and right is the monitor whose right edge defines the right edge of the fullscreen window. **/ void setFullscreenMonitors(NETFullscreenMonitors topology); /** Returns the desired fullscreen monitor topology for this client, should it be in fullscreen state. See _NET_WM_FULLSCREEN_MONITORS in the spec. **/ NETFullscreenMonitors fullscreenMonitors() const; #if KWINDOWSYSTEM_ENABLE_DEPRECATED_SINCE(5, 0) /** This function takes the passed XEvent and returns an OR'ed list of NETWinInfo properties that have changed in the properties argument. The new information will be read immediately by the class. The elements of the properties argument are as they would be passed to the constructor, if the array is not large enough, changed properties that don't fit in it won't be listed there (they'll be updated in the class though). @param event the event @param properties properties that changed @param properties_size size of the passed properties array @deprecated since 5.0 use event(xcb_generic_event_t*, NET::Properties*, NET::Properties2*) **/ // KWINDOWSYSTEM_DEPRECATED_VERSION(5, 0, "Use NETWinInfo::event(xcb_generic_event_t*, NET::Properties*, NET::Properties2*)") Q_DECL_DEPRECATED_X("Use NETWinInfo(xcb_connection_t *, xcb_window_t, xcb_window_t, NET::Properties, NET::Properties2, Role") void event(xcb_generic_event_t *event, unsigned long *properties, int properties_size); #endif /** * This function takes the passed in xcb_generic_event_t and returns the updated properties * in the passed in arguments. * * The new information will be read immediately by the class. It is possible to pass in a * null pointer in the arguments. In that case the passed in * argument will obviously not be updated, but the class will process the information * nevertheless. * * @param event the event * @param properties The NET::Properties that changed * @param properties2 The NET::Properties2 that changed * @since 5.0 **/ void event(xcb_generic_event_t *event, NET::Properties *properties, NET::Properties2 *properties2 = nullptr); /** This function takes the pass XEvent and returns an OR'ed list of NETWinInfo properties that have changed. The new information will be read immediately by the class. This overloaded version returns only a single mask, and therefore cannot check state of all properties like the other variant. @param event the event @return the properties **/ NET::Properties event(xcb_generic_event_t *event); /** * @returns The window manager protocols this Client supports. * @since 5.3 **/ NET::Protocols protocols() const; /** * @returns @c true if the Client supports the @p protocol. * @param protocol The window manager protocol to test for * @since 5.3 **/ bool supportsProtocol(NET::Protocol protocol) const; /** * @returns The opaque region as specified by the Client. * @since 5.7 **/ std::vector opaqueRegion() const; /** * Sets the @p name as the desktop file name. * * This is either the base name without full path and without file extension of the * desktop file for the window's application (e.g. "org.kde.foo"). * * If the application's desktop file name is not at a standard location it should be * the full path to the desktop file name (e.g. "/opt/kde/share/org.kde.foo.desktop"). * * If the window does not know the desktop file name, it should not set the name at all. * * @since 5.28 **/ void setDesktopFileName(const char *name); /** * @returns The desktop file name of the window's application if present. * @since 5.28 * @see setDesktopFileName **/ const char *desktopFileName() const; /** Sentinel value to indicate that the client wishes to be visible on all desktops. @return the value to be on all desktops **/ static const int OnAllDesktops; protected: /** A Window Manager should subclass NETWinInfo and reimplement this function when it wants to know when a Client made a request to change desktops (ie. move to another desktop). @param desktop the number of the desktop **/ virtual void changeDesktop(int desktop) { Q_UNUSED(desktop); } /** A Window Manager should subclass NETWinInfo and reimplement this function when it wants to know when a Client made a request to change state (ie. to Shade / Unshade). @param state the new state @param mask the mask for the state **/ virtual void changeState(NET::States state, NET::States mask) { Q_UNUSED(state); Q_UNUSED(mask); } /** A Window Manager should subclass NETWinInfo2 and reimplement this function when it wants to know when a Client made a request to change the fullscreen monitor topology for its fullscreen state. @param topology A structure (top, bottom, left, right) representing the fullscreen monitor topology. **/ virtual void changeFullscreenMonitors(NETFullscreenMonitors topology) { Q_UNUSED(topology); } private: void update(NET::Properties dirtyProperties, NET::Properties2 dirtyProperties2 = NET::Properties2()); void updateWMState(); void setIconInternal(NETRArray &icons, int &icon_count, xcb_atom_t property, NETIcon icon, bool replace); NETIcon iconInternal(NETRArray &icons, int icon_count, int width, int height) const; protected: /** Virtual hook, used to add new "virtual" functions while maintaining binary compatibility. Unused in this class. */ virtual void virtual_hook(int id, void *data); private: NETWinInfoPrivate *p; // krazy:exclude=dpointer (implicitly shared) }; // #define KWIN_FOCUS #endif #endif // netwm_h libkysdk-applications/kysdk-waylandhelper/src/windowmanager/idlenotifier.cpp0000664000175000017500000000233515104543305026577 0ustar fengfeng/* * libkysdk-waylandhelper's Library * * Copyright (C) 2024, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #include "idlenotifier.h" using namespace kdk; IdleNotifier::IdleNotifier(QObject *parent) : QObject(parent) { m_wm = new WmRegister(this); connect(m_wm->winInterface(), &AbstractInterface::idled, this, &IdleNotifier::idled); connect(m_wm->winInterface(), &AbstractInterface::resumed, this, &IdleNotifier::resumed); } void IdleNotifier::setIdleInterval(int msec) { return m_wm->winInterface()->setIdleInterval(msec); } libkysdk-applications/kysdk-waylandhelper/src/windowmanager/ukuishell.h0000664000175000017500000000720515104543305025575 0ustar fengfeng/* * libkysdk-waylandhelper's Library * * Copyright (C) 2024, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #ifndef UKUISHELL_H #define UKUISHELL_H #include "ukui-shell-client-protocol.h" #include #include #include #include #include /** * @since 2.5.1.0 */ struct wl_surface; struct ukui_surface; struct wl_seat; class UkuiShellSurface; using namespace KWayland::Client; class UkuiShell : public QObject { Q_OBJECT public: explicit UkuiShell(QObject *parent = nullptr); ~UkuiShell() override; bool isValid() const; void release(); void destroy(); void setup(ukui_shell *shell); void setEventQueue(EventQueue *queue); EventQueue *eventQueue(); QString seatName(); QString outputName(); bool isCurrentOutputReady(); UkuiShellSurface *createSurface(wl_surface *surface, QObject *parent = nullptr); UkuiShellSurface *createSurface(Surface *surface, QObject *parent = nullptr); void updateCurrentOutput(); operator ukui_shell *(); operator ukui_shell *() const; Q_SIGNALS: void interfaceAboutToBeReleased(); void interfaceAboutToBeDestroyed(); void removed(); void currentOutputReady(); private: class Private; QScopedPointer d; }; class UkuiShellSurface : public QObject { Q_OBJECT public: explicit UkuiShellSurface(QObject *parent); ~UkuiShellSurface() override; void release(); void destroy(); void setup(ukui_surface *surface); static UkuiShellSurface *get(Surface *surf); bool isValid() const; operator ukui_surface *(); operator ukui_surface *() const; enum class Role { Normal, Desktop, Panel, OnScreenDisplay, Notification, ToolTip, CriticalNotification, AppletPop, ScreenLock, Watermark, SystemWindow, InputPanel, Logout, ScreenLockNotification, Switcher, Authentication, }; enum class SurfaceProperty { NoTitleBar, Theme, WindowRadius, BorderWidth, BorderColor, ShadowRadius, ShadowOffset, ShadowColor }; void setRole(Role role); Role role() const; void setSurfaceProperty(SurfaceProperty property, uint32_t value); SurfaceProperty surfaceProperty() const; void setPosition(const QPoint &point); void setSkipTaskbar(bool skip); void setSkipSwitcher(bool skip); void setPanelTakesFocus(bool takesFocus); void setPanelAutoHide(bool autoHide); void setGrabKeyboard(wl_seat *seat); void setOpenUnderCursor(); void setOpenUnderCursor(int x, int y); void setIconName(const QString &iconName); Q_SIGNALS: void autoHidePanelHidden(); void autoHidePanelShown(); private: friend class UkuiShell; class Private; QScopedPointer d; }; #endif // UKUISHELL_H libkysdk-applications/kysdk-waylandhelper/src/windowmanager/extidlenotifier.h0000664000175000017500000000437015104543305026766 0ustar fengfeng/* * libkysdk-waylandhelper's Library * * Copyright (C) 2024, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #ifndef EXTIDLENOTIFIER_H #define EXTIDLENOTIFIER_H #include #include #include #include "wayland-ext-idle-notify-v1-client-protocol.h" using namespace KWayland::Client; /** * @since 2.5.1.0 */ class ExtIdleNotification; class ExtIdleNotifier : public QObject { Q_OBJECT public: explicit ExtIdleNotifier(QObject *parent = nullptr); ~ExtIdleNotifier(); bool isValid() const; void release(); void destroy(); void setup(ext_idle_notifier_v1 *notifier); operator ext_idle_notifier_v1 *(); operator ext_idle_notifier_v1 *() const; // static inline struct ext_idle_notification_v1 * // ext_idle_notifier_v1_get_idle_notification(struct ext_idle_notifier_v1 *ext_idle_notifier_v1, uint32_t timeout, struct wl_seat *seat) ExtIdleNotification *requestExtIdleNotification(wl_seat *seat, int msec); private: class Private; QScopedPointer d; }; class ExtIdleNotification : public QObject { Q_OBJECT public: explicit ExtIdleNotification(QObject *parent = nullptr); ~ExtIdleNotification(); bool isValid() const; void release(); void destroy(); void setup(ext_idle_notification_v1 *notification); operator ext_idle_notification_v1 *(); operator ext_idle_notification_v1 *() const; Q_SIGNALS: void idled(); void resumed(); private: class Private; QScopedPointer d; }; #endif // EXTIDLENOTIFIER_H libkysdk-applications/kysdk-waylandhelper/src/windowmanager/ukuiwindowmanagement.h0000664000175000017500000001361415104543305030033 0ustar fengfeng/* * libkysdk-waylandhelper's Library * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #ifndef UKUIWINDOWMANAGEMENT_H #define UKUIWINDOWMANAGEMENT_H #include #include #include #include #include #include #include struct ukui_activation; struct ukui_activation_feedback; struct ukui_window; struct ukui_window_management; class UkuiWindow; using namespace KWayland::Client; /** * @since 2.5.1.0 */ class UkuiWindowManagement : public QObject { Q_OBJECT public: explicit UkuiWindowManagement(QObject *parent = nullptr); ~UkuiWindowManagement() override; bool isValid() const; void release(); void destroy(); void setup(ukui_window_management *wm); void setEventQueue(EventQueue *queue); EventQueue *eventQueue(); operator ukui_window_management *(); operator ukui_window_management *() const; bool isShowingDesktop() const; void setShowingDesktop(bool show); void showDesktop(); void hideDesktop(); QList windows() const; UkuiWindow *activeWindow() const; QVector stackingOrder() const; QVector stackingOrderUuids() const; Q_SIGNALS: void interfaceAboutToBeReleased(); void interfaceAboutToBeDestroyed(); void showingDesktopChanged(bool); void windowCreated(UkuiWindow *window); void activeWindowChanged(); void removed(); void stackingOrderChanged(); void stackingOrderUuidsChanged(); public: class Private; private: QScopedPointer d; }; class UkuiWindow : public QObject { Q_OBJECT public: ~UkuiWindow() override; void release(); void destroy(); bool isValid() const; operator ukui_window *(); operator ukui_window *() const; QString title() const; QString appId() const; quint32 virtualDesktop() const; bool isActive() const; bool isFullscreen() const; bool isKeepAbove() const; bool isKeepBelow() const; bool isMinimized() const; bool isMaximized() const; bool isOnAllDesktops() const; bool isDemandingAttention() const; bool isCloseable() const; bool isMaximizeable() const; bool isMinimizeable() const; bool isFullscreenable() const; bool skipTaskbar() const; bool skipSwitcher() const; QIcon icon() const; bool isShadeable() const; bool isShaded() const; bool isMovable() const; bool isResizable() const; bool isVirtualDesktopChangeable() const; quint32 pid() const; void requestActivate(); void requestClose(); void requestMove(); void requestResize(); void requestVirtualDesktop(quint32 desktop); void requestToggleKeepAbove(); void requestDemandAttention(); void requestToggleKeepBelow(); void requestToggleMinimized(); void requestToggleMaximized(); void setStartupGeometry(Surface *surface, const QRect &geometry); void setMinimizedGeometry(Surface *panel, const QRect &geom); void unsetMinimizedGeometry(Surface *panel); void requestToggleShaded(); quint32 internalId() const; QByteArray uuid() const; QPointer parentWindow() const; QRect geometry() const; void requestEnterVirtualDesktop(const QString &id); void requestEnterNewVirtualDesktop(); void requestLeaveVirtualDesktop(const QString &id); QStringList ukuiVirtualDesktops() const; void requestEnterActivity(const QString &id); void requestLeaveActivity(const QString &id); QStringList ukuiActivities() const; QString applicationMenuServiceName() const; QString applicationMenuObjectPath() const; void sendToOutput(Output *output) const; void setHighlight(); void unsetHightlight(); bool isHighlight(); Q_SIGNALS: void titleChanged(); void appIdChanged(); void virtualDesktopChanged(); void activeChanged(); void fullscreenChanged(); void keepAboveChanged(); void keepBelowChanged(); void minimizedChanged(); void maximizedChanged(); void onAllDesktopsChanged(); void demandsAttentionChanged(); void closeableChanged(); void minimizeableChanged(); void maximizeableChanged(); void fullscreenableChanged(); void skipTaskbarChanged(); void skipSwitcherChanged(); void iconChanged(); void shadeableChanged(); void shadedChanged(); void movableChanged(); void resizableChanged(); void modalityChanged(); void acceptFocusChanged(); void virtualDesktopChangeableChanged(); void unmapped(); void parentWindowChanged(); void geometryChanged(); void ukuiVirtualDesktopEntered(const QString &id); void ukuiVirtualDesktopLeft(const QString &id); void ukuiActivityEntered(const QString &id); void ukuiActivityLeft(const QString &id); void applicationMenuChanged(); private: friend class UkuiWindowManagement; explicit UkuiWindow(UkuiWindowManagement *parent, ukui_window *activation, quint32 internalId, const char *uuid); class Private; QScopedPointer d; }; Q_DECLARE_METATYPE(UkuiWindow *) #endif // UKUIWINDOWMANAGEMENT_H libkysdk-applications/kysdk-waylandhelper/src/windowmanager/wmregister.h0000664000175000017500000000232515104543305025756 0ustar fengfeng/* * libkysdk-waylandhelper's Library * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #ifndef WMREGISTER_H #define WMREGISTER_H #include "abstractinterface.h" #include "kysdk-waylandhelper_global.h" #include /** * @since 1.2.0 */ namespace kdk { class KYSDKWAYLANDHELPER_EXPORT WmRegister : public QObject { public: WmRegister(QObject *parent = nullptr); ~WmRegister(); AbstractInterface *winInterface(); private: AbstractInterface *m_winInterface{nullptr}; }; } #endif // WMREGISTER_H libkysdk-applications/kysdk-waylandhelper/src/windowmanager/ukuiwaylandpointer.h0000664000175000017500000000454315104543305027530 0ustar fengfeng/* * libkysdk-waylandhelper's Library * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #ifndef UKUIWAYLANDPOINTER_H #define UKUIWAYLANDPOINTER_H #include /** * @since 2.5.1.0 */ struct wl_proxy; template class UkuiWaylandPointer { public: UkuiWaylandPointer() = default; UkuiWaylandPointer(Pointer *p) : m_pointer(p) { } UkuiWaylandPointer(const UkuiWaylandPointer &other) = delete; virtual ~UkuiWaylandPointer() { release(); } void setup(Pointer *pointer, bool foreign = false) { Q_ASSERT(pointer); Q_ASSERT(!m_pointer); m_pointer = pointer; m_foreign = foreign; } void release() { if (!m_pointer) { return; } if (!m_foreign) { deleter(m_pointer); } m_pointer = nullptr; } void destroy() { if (!m_pointer) { return; } if (!m_foreign) { free(m_pointer); } m_pointer = nullptr; } bool isValid() const { return m_pointer != nullptr; } operator Pointer *() { return m_pointer; } operator Pointer *() const { return m_pointer; } operator wl_proxy *() { return reinterpret_cast(m_pointer); } Pointer *operator->() { return m_pointer; } operator bool() { return isValid(); } operator bool() const { return isValid(); } private: Pointer *m_pointer = nullptr; bool m_foreign = false; }; #endif // UKUIWAYLANDPOINTER_H libkysdk-applications/kysdk-waylandhelper/src/windowmanager/kyatoms_p.h0000664000175000017500000001417015104543305025575 0ustar fengfeng /* * libkysdk-waylandhelper's Library * * Copyright (C) 2024, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #if (!defined ATOMS_H) || (defined ENUM_CREATE_CHAR_ARRAY) #undef ENUM_BEGIN #undef ENUM #undef ENUM_END #undef ENUM_COUNT // the following macros are set in a way so that // the code below will either construct an enum for "" // or a const *char array "Strings" containing all enum // symbols as strings, depending on whether ENUM_CREATE_CHAR_ARRAY is // defined // The enum gets one extra item "Count", describing also the // length of the array // The header is safe for re-inclusion unless you define ENUM_CREATE_CHAR_ARRAY // which is therefore undefined after usage // => You *must* "#define ENUM_CREATE_CHAR_ARRAY 1" *every* time you want to create // a string array! // clang-format off /** * @since 2.5.1.0 */ #ifndef ENUM_CREATE_CHAR_ARRAY #define ATOMS_H #define ENUM_BEGIN(typ) enum typ { #define ENUM(nam) nam #define ENUM_COUNT(typ) , typ##Count #else #define ENUM_BEGIN(typ) const char * typ##Strings [] = { #define ENUM(nam) #nam #define ENUM_COUNT(typ) #undef ENUM_CREATE_CHAR_ARRAY #endif #define ENUM_END(typ) }; ENUM_BEGIN(KyAtom) ENUM(UTF8_STRING), // root window properties ENUM(_NET_SUPPORTED), ENUM(_NET_SUPPORTING_WM_CHECK), ENUM(_NET_CLIENT_LIST), ENUM(_NET_CLIENT_LIST_STACKING), ENUM(_NET_NUMBER_OF_DESKTOPS), ENUM(_NET_DESKTOP_GEOMETRY), ENUM(_NET_DESKTOP_VIEWPORT), ENUM(_NET_CURRENT_DESKTOP), ENUM(_NET_DESKTOP_NAMES), ENUM(_NET_ACTIVE_WINDOW), ENUM(_NET_WORKAREA), ENUM(_NET_VIRTUAL_ROOTS), ENUM(_NET_DESKTOP_LAYOUT), ENUM(_NET_SHOWING_DESKTOP), // root window messages ENUM(_NET_CLOSE_WINDOW), ENUM(_NET_RESTACK_WINDOW), ENUM(_NET_WM_MOVERESIZE), ENUM(_NET_MOVERESIZE_WINDOW), // application window properties ENUM(_NET_WM_NAME), ENUM(_NET_WM_VISIBLE_NAME), ENUM(_NET_WM_ICON_NAME), ENUM(_NET_WM_VISIBLE_ICON_NAME), ENUM(_NET_WM_DESKTOP), ENUM(_NET_WM_WINDOW_TYPE), ENUM(_NET_WM_STATE), ENUM(_NET_WM_STRUT), ENUM(_NET_WM_STRUT_PARTIAL), ENUM(_NET_WM_ICON_GEOMETRY), ENUM(_NET_WM_ICON), ENUM(_NET_WM_PID), ENUM(_NET_WM_USER_TIME), ENUM(_NET_WM_HANDLED_ICONS), ENUM(_NET_STARTUP_ID), ENUM(_NET_WM_ALLOWED_ACTIONS), ENUM(WM_WINDOW_ROLE), ENUM(_NET_FRAME_EXTENTS), ENUM(_NET_WM_WINDOW_OPACITY), ENUM(_NET_WM_FULLSCREEN_MONITORS), ENUM(_NET_WM_OPAQUE_REGION), ENUM(_KDE_NET_WM_DESKTOP_FILE), // used to determine whether application window is managed or not ENUM(WM_STATE), // application window types ENUM(_NET_WM_WINDOW_TYPE_NORMAL), ENUM(_NET_WM_WINDOW_TYPE_DESKTOP), ENUM(_NET_WM_WINDOW_TYPE_DOCK), ENUM(_NET_WM_WINDOW_TYPE_TOOLBAR), ENUM(_NET_WM_WINDOW_TYPE_MENU), ENUM(_NET_WM_WINDOW_TYPE_DIALOG), ENUM(_NET_WM_WINDOW_TYPE_UTILITY), ENUM(_NET_WM_WINDOW_TYPE_SPLASH), ENUM(_NET_WM_WINDOW_TYPE_DROPDOWN_MENU), ENUM(_NET_WM_WINDOW_TYPE_POPUP_MENU), ENUM(_NET_WM_WINDOW_TYPE_TOOLTIP), ENUM(_NET_WM_WINDOW_TYPE_NOTIFICATION), ENUM(_NET_WM_WINDOW_TYPE_COMBO), ENUM(_NET_WM_WINDOW_TYPE_DND), // application window state ENUM(_NET_WM_STATE_MODAL), ENUM(_NET_WM_STATE_STICKY), ENUM(_NET_WM_STATE_MAXIMIZED_VERT), ENUM(_NET_WM_STATE_MAXIMIZED_HORZ), ENUM(_NET_WM_STATE_SHADED), ENUM(_NET_WM_STATE_SKIP_TASKBAR), ENUM(_NET_WM_STATE_SKIP_PAGER), ENUM(_NET_WM_STATE_HIDDEN), ENUM(_NET_WM_STATE_FULLSCREEN), ENUM(_NET_WM_STATE_ABOVE), ENUM(_NET_WM_STATE_BELOW), ENUM(_NET_WM_STATE_DEMANDS_ATTENTION), ENUM(_NET_WM_STATE_FOCUSED), // KDE-specific atom ENUM(_KDE_NET_WM_STATE_SKIP_SWITCHER), // allowed actions ENUM(_NET_WM_ACTION_MOVE), ENUM(_NET_WM_ACTION_RESIZE), ENUM(_NET_WM_ACTION_MINIMIZE), ENUM(_NET_WM_ACTION_SHADE), ENUM(_NET_WM_ACTION_STICK), ENUM(_NET_WM_ACTION_MAXIMIZE_VERT), ENUM(_NET_WM_ACTION_MAXIMIZE_HORZ), ENUM(_NET_WM_ACTION_FULLSCREEN), ENUM(_NET_WM_ACTION_CHANGE_DESKTOP), ENUM(_NET_WM_ACTION_CLOSE), // KDE extensions ENUM(_KDE_NET_WM_FRAME_STRUT), ENUM(_KDE_NET_WM_WINDOW_TYPE_OVERRIDE), ENUM(_KDE_NET_WM_WINDOW_TYPE_TOPMENU), ENUM(_KDE_NET_WM_WINDOW_TYPE_ON_SCREEN_DISPLAY), ENUM(_KDE_NET_WM_WINDOW_TYPE_CRITICAL_NOTIFICATION), ENUM(_KDE_NET_WM_WINDOW_TYPE_APPLET_POPUP), ENUM(_KDE_NET_WM_TEMPORARY_RULES), ENUM(_NET_WM_FRAME_OVERLAP), ENUM(_KDE_NET_WM_APPMENU_SERVICE_NAME), ENUM(_KDE_NET_WM_APPMENU_OBJECT_PATH), // UKUI extensions ENUM(_UKUI_NET_WM_WINDOW_TYPE_SYSTEMWINDOW), ENUM(_UKUI_NET_WM_WINDOW_TYPE_INPUTPANEL), ENUM(_UKUI_NET_WM_WINDOW_TYPE_LOGOUT), ENUM(_UKUI_NET_WM_WINDOW_TYPE_SCREENLOCK), ENUM(_UKUI_NET_WM_WINDOW_TYPE_SCREENLOCKNOTIFICATION), ENUM(_UKUI_NET_WM_WINDOW_TYPE_WATERMARK), // deprecated and naming convention violation ENUM(_NET_WM_STATE_STAYS_ON_TOP), // GTK extensions ENUM(_GTK_FRAME_EXTENTS), ENUM(_GTK_APPLICATION_ID), ENUM(_GTK_SHOW_WINDOW_MENU), // application protocols ENUM(WM_PROTOCOLS), ENUM(WM_TAKE_FOCUS), ENUM(WM_DELETE_WINDOW), ENUM(_NET_WM_PING), ENUM(_NET_WM_SYNC_REQUEST), ENUM(_NET_WM_CONTEXT_HELP), // ability flags ENUM(_NET_WM_FULL_PLACEMENT), ENUM(_NET_WM_BYPASS_COMPOSITOR), ENUM(_KDE_NET_WM_ACTIVITIES), ENUM(_KDE_NET_WM_BLOCK_COMPOSITING), ENUM(_KDE_NET_WM_SHADOW) ENUM_COUNT(KyAtom) ENUM_END(KyAtom) #endif // ATOMS_H libkysdk-applications/kysdk-waylandhelper/src/windowmanager/extidlenotifier.cpp0000664000175000017500000001133715104543305027322 0ustar fengfeng/* * libkysdk-waylandhelper's Library * * Copyright (C) 2024, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #include "extidlenotifier.h" #include "ukuiwaylandpointer.h" class Q_DECL_HIDDEN ExtIdleNotifier::Private { public: Private(ExtIdleNotifier *q); ~Private(); UkuiWaylandPointer notifier; ExtIdleNotifier *q; }; ExtIdleNotifier::ExtIdleNotifier(QObject *parent) : QObject(parent) , d(new Private(this)) { } ExtIdleNotifier::~ExtIdleNotifier() { } bool ExtIdleNotifier::isValid() const { return d->notifier.isValid(); } void ExtIdleNotifier::release() { return d->notifier.release(); } void ExtIdleNotifier::destroy() { return d->notifier.destroy(); } void ExtIdleNotifier::setup(ext_idle_notifier_v1 *notifier) { Q_ASSERT(!d->notifier); Q_ASSERT(notifier); d->notifier.setup(notifier); } ExtIdleNotifier::operator ext_idle_notifier_v1 *() { return d->notifier; } ExtIdleNotification *ExtIdleNotifier::requestExtIdleNotification(wl_seat *seat, int msec) { ExtIdleNotification *notification = new ExtIdleNotification(this); if (!seat || msec <= 0) return notification; ext_idle_notification_v1 *origin_notification = ext_idle_notifier_v1_get_idle_notification(d->notifier, msec, seat); notification->setup(origin_notification); return notification; } ExtIdleNotifier::operator ext_idle_notifier_v1 *() const { return d->notifier; } ExtIdleNotifier::Private::Private(ExtIdleNotifier *q) : q(q) { } ExtIdleNotifier::Private::~Private() { } class Q_DECL_HIDDEN ExtIdleNotification::Private { public: Private(ExtIdleNotification *q); ~Private(); UkuiWaylandPointer notification; void init_listener(); private: ExtIdleNotification *q; static const struct ext_idle_notification_v1_listener s_ext_idle_notification_v1_listener; static void handle_idled(void *data, struct ext_idle_notification_v1 *ext_idle_notification_v1); static void handle_resumed(void *data, struct ext_idle_notification_v1 *ext_idle_notification_v1); void idled_callback(); void resumed_callback(); }; const struct ext_idle_notification_v1_listener ExtIdleNotification::Private::s_ext_idle_notification_v1_listener = { ExtIdleNotification::Private::handle_idled, ExtIdleNotification::Private::handle_resumed}; ExtIdleNotification::ExtIdleNotification(QObject *parent) : QObject(parent) , d(new Private(this)) { } ExtIdleNotification::~ExtIdleNotification() { } bool ExtIdleNotification::isValid() const { return d->notification.isValid(); } void ExtIdleNotification::release() { return d->notification.release(); } void ExtIdleNotification::destroy() { return d->notification.destroy(); } void ExtIdleNotification::setup(ext_idle_notification_v1 *notification) { Q_ASSERT(!d->notification); Q_ASSERT(notification); d->notification.setup(notification); d->init_listener(); } ExtIdleNotification::operator ext_idle_notification_v1 *() { return d->notification; } ExtIdleNotification::operator ext_idle_notification_v1 *() const { return d->notification; } ExtIdleNotification::Private::Private(ExtIdleNotification *q) : q(q) { } ExtIdleNotification::Private::~Private() { } void ExtIdleNotification::Private::init_listener() { ext_idle_notification_v1_add_listener(notification, &s_ext_idle_notification_v1_listener, this); } void ExtIdleNotification::Private::handle_idled(void *data, ext_idle_notification_v1 *ext_idle_notification_v1) { static_cast(data)->idled_callback(); } void ExtIdleNotification::Private::handle_resumed(void *data, ext_idle_notification_v1 *ext_idle_notification_v1) { static_cast(data)->resumed_callback(); } void ExtIdleNotification::Private::idled_callback() { Q_EMIT q->idled(); } void ExtIdleNotification::Private::resumed_callback() { Q_EMIT q->resumed(); } libkysdk-applications/kysdk-waylandhelper/src/windowmanager/ukuiwaylandinterface.cpp0000664000175000017500000007554215104543305030352 0ustar fengfeng/* * libkysdk-waylandhelper's Library * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #include "ukuiwaylandinterface.h" #include "ukui-shell-client-protocol.h" #include "ukui-window-management-client-protocol.h" #include "wayland-ext-idle-notify-v1-client-protocol.h" #include "wayland-xdg-activation-v1-client-protocol.h" #include #include #include static const u_int32_t ukui_window_management_surpported_version = 1; static const u_int32_t ukui_shell_surpported_version = 2; static const u_int32_t wayland_xdg_activation_surpported_version = 1; static const u_int32_t wayland_ext_idle_notify_surpported_version = 1; inline bool operator<(const QVariant &v1, const QVariant &v2) { return v1.toString() < v2.toString(); } void handle_global(void *data, struct wl_registry *wl_registry, uint32_t name, const char *interface, uint32_t version) { auto waylandInterface = reinterpret_cast(data); Q_ASSERT(wl_registry == *waylandInterface->registry()); waylandInterface->handleGlobal(data, wl_registry, name, interface, version); } void handle_global_remove(void *data, struct wl_registry *wl_registry, uint32_t name) { } const struct wl_registry_listener UkuiWaylandInterface::s_registryListener = {handle_global, handle_global_remove}; UkuiWaylandInterface::UkuiWaylandInterface(QObject *parent) : AbstractInterface(parent) { m_connection = KWayland::Client::ConnectionThread::fromApplication(qApp); m_registry = new Registry(this); m_registry->create(m_connection->display()); connect(m_registry, &KWayland::Client::Registry::shellAnnounced, this, [=]() { const auto interface = m_registry->interface(KWayland::Client::Registry::Interface::Shell); if (interface.name != 0) { m_shell = m_registry->createShell(interface.name, interface.version, this); } }); wl_registry *registry = *m_registry; wl_registry_add_listener(registry, &s_registryListener, this); wl_display_dispatch(m_connection->display()); wl_display_roundtrip(m_connection->display()); m_registry->setup(); // m_connection->roundtrip(); } UkuiWaylandInterface::~UkuiWaylandInterface() { } WindowInfo UkuiWaylandInterface::requestInfo(WindowId wid) { WindowInfo windowInfo; auto w = windowFor(wid); if (w) { windowInfo.setIsValid(true); windowInfo.setWid(wid); windowInfo.setIsActive(w->isActive()); windowInfo.setIsMinimized(w->isMinimized()); windowInfo.setIsMaxVert(w->isMaximized()); windowInfo.setIsMaxHoriz(w->isMaximized()); windowInfo.setIsFullscreen(w->isFullscreen()); windowInfo.setIsShaded(w->isShaded()); windowInfo.setIsOnAllDesktops(w->isOnAllDesktops()); windowInfo.setIsOnAllActivities(true); windowInfo.setHasSkipTaskbar(w->skipTaskbar()); windowInfo.setHasSkipSwitcher(w->skipSwitcher()); windowInfo.setIsKeepAbove(w->isKeepAbove()); //! Window Abilities windowInfo.setIsClosable(w->isCloseable()); windowInfo.setIsFullScreenable(w->isFullscreenable()); windowInfo.setIsMaximizable(w->isMaximizeable()); windowInfo.setIsMinimizable(w->isMinimizeable()); windowInfo.setIsMovable(w->isMovable()); windowInfo.setIsResizable(w->isResizable()); windowInfo.setIsShadeable(w->isShadeable()); windowInfo.setIsVirtualDesktopsChangeable(w->isVirtualDesktopChangeable()); } else { windowInfo.setIsValid(false); } return windowInfo; } void UkuiWaylandInterface::requestActivate(WindowId wid) { auto w = windowFor(wid); if (w) { w->requestActivate(); m_connection->roundtrip(); emit windowChanged(w->uuid()); } } void UkuiWaylandInterface::requestClose(WindowId wid) { auto w = windowFor(wid); if (w) { w->requestClose(); m_connection->roundtrip(); } } void UkuiWaylandInterface::requestToggleKeepAbove(WindowId wid) { auto w = windowFor(wid); if (w) { w->requestToggleKeepAbove(); m_connection->roundtrip(); emit windowChanged(w->uuid()); } } void UkuiWaylandInterface::requestToggleMinimized(WindowId wid) { auto w = windowFor(wid); if (w) { w->requestToggleMinimized(); m_connection->roundtrip(); } } void UkuiWaylandInterface::requestToggleMaximized(WindowId wid) { auto w = windowFor(wid); if (w) { w->requestToggleMaximized(); m_connection->roundtrip(); } } QIcon UkuiWaylandInterface::iconFor(WindowId wid) { auto window = windowFor(wid); if (window) { return window->icon(); } return QIcon(); } QString UkuiWaylandInterface::titleFor(WindowId wid) { auto window = windowFor(wid); if (window) { return window->title(); } return QString(); } QString UkuiWaylandInterface::windowGroupFor(WindowId wid) { auto window = windowFor(wid); if (window) { m_connection->roundtrip(); return window->appId(); } else return QString(); } quint32 UkuiWaylandInterface::pid(WindowId wid) { quint32 pid = 0; auto window = windowFor(wid); if (window) { m_connection->roundtrip(); return window->pid(); } else return pid; } void UkuiWaylandInterface::showCurrentDesktop() { if (m_ukuiWindowManager) { m_ukuiWindowManager->showDesktop(); m_connection->roundtrip(); } } void UkuiWaylandInterface::hideCurrentDesktop() { if (m_ukuiWindowManager) { m_ukuiWindowManager->hideDesktop(); m_connection->roundtrip(); } } bool UkuiWaylandInterface::windowCanBeDragged(WindowId wid) { auto w = windowFor(wid); if (w) { WindowInfo winfo = requestInfo(wid); return (winfo.isValid() && w->isMovable() && !winfo.isMinimized() && inCurrentDesktopActivity(winfo) && !winfo.isPlasmaDesktop()); } return false; } bool UkuiWaylandInterface::windowCanBeMaximized(WindowId wid) { auto w = windowFor(wid); if (w) { WindowInfo winfo = requestInfo(wid); return (winfo.isValid() && w->isMaximizeable() && !winfo.isMinimized() && inCurrentDesktopActivity(winfo) && !winfo.isPlasmaDesktop()); } return false; } WindowId UkuiWaylandInterface::activeWindow() { if (!m_ukuiWindowManager) { return 0; } m_connection->roundtrip(); auto wid = m_ukuiWindowManager->activeWindow(); return wid ? QVariant(wid->uuid()) : ""; } bool UkuiWaylandInterface::removeHeaderBar(QWindow *window) { if (!window) return false; if (!m_ukuiShell) return false; auto surface = KWayland::Client::Surface::fromWindow(window); if (!surface) return false; if (!m_surfaces.contains(window)) { m_surfaces.insert(window, surface); } auto ukuiShellSurface = m_ukuiShell->createSurface(surface, window); if (!ukuiShellSurface) return false; if (!m_ukuiShellSurfaces.contains(window)) { m_ukuiShellSurfaces.insert(window, ukuiShellSurface); } ukuiShellSurface->setSurfaceProperty(UkuiShellSurface::SurfaceProperty::NoTitleBar, 1); window->installEventFilter(this); return true; } bool UkuiWaylandInterface::setWindowRadius(QWindow *window, int radius) { if (!window || radius < 0) return false; if (!m_ukuiShell) return false; auto surface = KWayland::Client::Surface::fromWindow(window); if (!surface) return false; if (!m_surfaces.contains(window)) { m_surfaces.insert(window, surface); } auto ukuiShellSurface = m_ukuiShell->createSurface(surface, window); if (!ukuiShellSurface) return false; if (!m_ukuiShellSurfaces.contains(window)) { m_ukuiShellSurfaces.insert(window, ukuiShellSurface); } ukuiShellSurface->setSurfaceProperty(UkuiShellSurface::SurfaceProperty::WindowRadius, radius); window->installEventFilter(this); return true; } void UkuiWaylandInterface::activateWindow(QWindow *window1, QWindow *window2) { if (!window1 || !window2) return; if (!m_seat) return; if (!m_xdgActivation) return; auto surface = KWayland::Client::Surface::fromWindow(window1); if (!surface) return; if (!m_surfaces.contains(window1)) { m_surfaces.insert(window1, surface); } XdgActivationToken *token = m_xdgActivation->requestXdgActivationToken(m_seat, surface, 0, ""); connect(token, &XdgActivationToken::done, this, [=](const QString &str) { auto surface2 = KWayland::Client::Surface::fromWindow(window2); if (!surface2) return; if (!m_surfaces.contains(window2)) { m_surfaces.insert(window2, surface2); } m_xdgActivation->activateWindow(str, surface2); }); } void UkuiWaylandInterface::setIdleInterval(int msec) { if (!m_notifier || !m_seat) return; ExtIdleNotification *notification = m_notifier->requestExtIdleNotification(m_seat, msec); if (!notification) return; connect(notification, &ExtIdleNotification::idled, this, [=]() { Q_EMIT idled(); }); connect(notification, &ExtIdleNotification::resumed, this, [=]() { Q_EMIT resumed(); }); } QRect UkuiWaylandInterface::windowGeometry(const WindowId &windowId) { UkuiWindow *w = windowFor(windowId); if (w) return w->geometry(); else return QRect(0, 0, 0, 0); } void UkuiWaylandInterface::setPanelAutoHide(QWindow *window, bool autoHide) { if (!window) return; #ifdef USE_UKUI_SHELL_PLUGIN window->setProperty("ukui_surface_panel_auto_hide", autoHide); #elif if (!m_ukuiShell) return; auto surface = KWayland::Client::Surface::fromWindow(window); if (!surface) return; if (!m_surfaces.contains(window)) { m_surfaces.insert(window, surface); } auto ukuiShellSurface = m_ukuiShell->createSurface(surface, window); if (!ukuiShellSurface) return; if (!m_ukuiShellSurfaces.contains(window)) { m_ukuiShellSurfaces.insert(window, ukuiShellSurface); } ukuiShellSurface->setPanelAutoHide(autoHide); window->installEventFilter(this); #endif } void UkuiWaylandInterface::setGrabKeyboard(QWindow *window, bool autoHide) { Q_UNUSED(autoHide) if (!window) return; if (!m_ukuiShell) return; auto surface = KWayland::Client::Surface::fromWindow(window); if (!surface) return; if (!m_surfaces.contains(window)) { m_surfaces.insert(window, surface); } auto ukuiShellSurface = m_ukuiShell->createSurface(surface, window); if (!ukuiShellSurface) return; if (!m_ukuiShellSurfaces.contains(window)) { m_ukuiShellSurfaces.insert(window, ukuiShellSurface); } ukuiShellSurface->setGrabKeyboard(m_seat); window->installEventFilter(this); } void UkuiWaylandInterface::setWindowLayer(QWindow *window, WindowLayer layer) { if (!window) return; if (!m_ukuiShell) return; auto surface = KWayland::Client::Surface::fromWindow(window); if (!surface) return; if (!m_surfaces.contains(window)) { m_surfaces.insert(window, surface); } auto ukuiShellSurface = m_ukuiShell->createSurface(surface, window); if (!ukuiShellSurface) return; if (!m_ukuiShellSurfaces.contains(window)) { m_ukuiShellSurfaces.insert(window, ukuiShellSurface); } switch (layer) { case WindowLayer::Desktop: ukuiShellSurface->setRole(UkuiShellSurface::Role::Desktop); break; case WindowLayer::Panel: ukuiShellSurface->setRole(UkuiShellSurface::Role::Panel); break; case WindowLayer::OnScreenDisplay: ukuiShellSurface->setRole(UkuiShellSurface::Role::OnScreenDisplay); break; case WindowLayer::Notification: ukuiShellSurface->setRole(UkuiShellSurface::Role::Notification); break; case WindowLayer::ToolTip: ukuiShellSurface->setRole(UkuiShellSurface::Role::ToolTip); break; case WindowLayer::CriticalNotification: ukuiShellSurface->setRole(UkuiShellSurface::Role::CriticalNotification); break; case WindowLayer::AppletPop: ukuiShellSurface->setRole(UkuiShellSurface::Role::AppletPop); break; case WindowLayer::ScreenLock: ukuiShellSurface->setRole(UkuiShellSurface::Role::ScreenLock); break; case WindowLayer::Watermark: ukuiShellSurface->setRole(UkuiShellSurface::Role::Watermark); break; case WindowLayer::SystemWindow: ukuiShellSurface->setRole(UkuiShellSurface::Role::SystemWindow); break; case WindowLayer::InputPanel: ukuiShellSurface->setRole(UkuiShellSurface::Role::InputPanel); break; case WindowLayer::Logout: ukuiShellSurface->setRole(UkuiShellSurface::Role::Logout); break; case WindowLayer::ScreenLockNotification: ukuiShellSurface->setRole(UkuiShellSurface::Role::ScreenLockNotification); break; case WindowLayer::Switcher: ukuiShellSurface->setRole(UkuiShellSurface::Role::Switcher); break; case WindowLayer::Authentication: ukuiShellSurface->setRole(UkuiShellSurface::Role::Authentication); break; default: { qWarning() << "It is not a surpported window layer by ukui protocols! id:" << (int)layer; ukuiShellSurface->setRole(UkuiShellSurface::Role::Normal); break; } } window->installEventFilter(this); } WindowLayer UkuiWaylandInterface::windowLayer(QWindow *window) { if (!window) return WindowLayer::Normal; if (!m_ukuiShell) return WindowLayer::Normal; ; auto surface = KWayland::Client::Surface::fromWindow(window); if (!surface) return WindowLayer::Normal; ; if (!m_surfaces.contains(window)) { m_surfaces.insert(window, surface); } auto ukuiShellSurface = m_ukuiShell->createSurface(surface, window); if (!ukuiShellSurface) return WindowLayer::Normal; ; if (!m_ukuiShellSurfaces.contains(window)) { m_ukuiShellSurfaces.insert(window, ukuiShellSurface); } window->installEventFilter(this); WindowLayer layer; switch (ukuiShellSurface->role()) { case UkuiShellSurface::Role::Normal: layer = WindowLayer::Normal; break; case UkuiShellSurface::Role::Desktop: layer = WindowLayer::Desktop; break; case UkuiShellSurface::Role::Panel: layer = WindowLayer::Panel; break; case UkuiShellSurface::Role::OnScreenDisplay: layer = WindowLayer::OnScreenDisplay; break; case UkuiShellSurface::Role::Notification: layer = WindowLayer::Notification; break; case UkuiShellSurface::Role::ToolTip: layer = WindowLayer::ToolTip; break; case UkuiShellSurface::Role::CriticalNotification: layer = WindowLayer::CriticalNotification; break; case UkuiShellSurface::Role::AppletPop: layer = WindowLayer::AppletPop; break; case UkuiShellSurface::Role::ScreenLock: layer = WindowLayer::ScreenLock; break; case UkuiShellSurface::Role::Watermark: layer = WindowLayer::Watermark; break; case UkuiShellSurface::Role::SystemWindow: layer = WindowLayer::SystemWindow; break; case UkuiShellSurface::Role::InputPanel: layer = WindowLayer::InputPanel; break; case UkuiShellSurface::Role::Logout: layer = WindowLayer::Logout; break; case UkuiShellSurface::Role::ScreenLockNotification: layer = WindowLayer::ScreenLockNotification; break; case UkuiShellSurface::Role::Switcher: layer = WindowLayer::Switcher; break; default: layer = WindowLayer::Normal; break; } return layer; } void UkuiWaylandInterface::setHighlight(const WindowId &wid, bool highlight) { auto w = windowFor(wid); if (w) { highlight ? w->setHighlight() : w->unsetHightlight(); m_connection->roundtrip(); } } bool UkuiWaylandInterface::istHighlight(const WindowId &wid) { auto w = windowFor(wid); if (w) { return w->isHighlight(); } else return false; } void UkuiWaylandInterface::setOpenUnderCursor(QWindow *window) { if (!window) return; if (!m_ukuiShell) return; auto surface = KWayland::Client::Surface::fromWindow(window); if (!surface) return; if (!m_surfaces.contains(window)) { m_surfaces.insert(window, surface); } auto ukuiShellSurface = m_ukuiShell->createSurface(surface, window); if (!ukuiShellSurface) return; if (!m_ukuiShellSurfaces.contains(window)) { m_ukuiShellSurfaces.insert(window, ukuiShellSurface); } ukuiShellSurface->setOpenUnderCursor(); window->installEventFilter(this); } void UkuiWaylandInterface::setOpenUnderCursor(QWindow *window, int x, int y) { if (!window) return; if (!m_ukuiShell) return; auto surface = KWayland::Client::Surface::fromWindow(window); if (!surface) return; if (!m_surfaces.contains(window)) { m_surfaces.insert(window, surface); } auto ukuiShellSurface = m_ukuiShell->createSurface(surface, window); if (!ukuiShellSurface) return; if (!m_ukuiShellSurfaces.contains(window)) { m_ukuiShellSurfaces.insert(window, ukuiShellSurface); } ukuiShellSurface->setOpenUnderCursor(x, y); window->installEventFilter(this); } void UkuiWaylandInterface::setIconName(QWindow *window, const QString &iconName) { if (!window || !m_ukuiShell) return; auto surface = KWayland::Client::Surface::fromWindow(window); if (!surface) return; if (!m_surfaces.contains(window)) { m_surfaces.insert(window, surface); } auto ukuiShellSurface = m_ukuiShell->createSurface(surface, window); if (!ukuiShellSurface) return; if (!m_ukuiShellSurfaces.contains(window)) { m_ukuiShellSurfaces.insert(window, ukuiShellSurface); } ukuiShellSurface->setIconName(iconName); window->installEventFilter(this); } QString UkuiWaylandInterface::currentSeatName() { if (!m_ukuiShell) return QString(); m_ukuiShell->updateCurrentOutput(); wl_display_dispatch(m_connection->display()); wl_display_roundtrip(m_connection->display()); return m_ukuiShell->seatName(); } QString UkuiWaylandInterface::currentOutputName() { if (!m_ukuiShell) return QString(); m_ukuiShell->updateCurrentOutput(); wl_display_dispatch(m_connection->display()); wl_display_roundtrip(m_connection->display()); return m_ukuiShell->outputName(); } QList UkuiWaylandInterface::outputsInfo() { } QList UkuiWaylandInterface::getWindowIdByPid(quint32 pid) { QList list; wl_display_dispatch(m_connection->display()); qDebug() << m_ukuiWindowManager->windows().count(); for (auto w : m_ukuiWindowManager->windows()) { if (w->pid() == pid) list.append(w->uuid()); } return list; } QList UkuiWaylandInterface::getWindowIdByTtile(const QString &title) { QList list; for (auto w : m_ukuiWindowManager->windows()) { if (w->title() == title) list.append(w->uuid()); } return list; } void UkuiWaylandInterface::setGeometry(QWindow *window, const QRect &rect) { if (!window) return; #ifdef USE_UKUI_SHELL_PLUGIN window->setGeometry(rect); #elif if (!m_ukuiShell) return; auto surface = KWayland::Client::Surface::fromWindow(window); if (!surface) return; if (!m_surfaces.contains(window)) { m_surfaces.insert(window, surface); } auto ukuiShellSurface = m_ukuiShell->createSurface(surface, window); if (!ukuiShellSurface) return; if (!m_ukuiShellSurfaces.contains(window)) { m_ukuiShellSurfaces.insert(window, ukuiShellSurface); } ukuiShellSurface->setPosition(rect.topLeft()); window->resize(rect.size()); window->installEventFilter(this); #endif } void UkuiWaylandInterface::setSkipTaskBar(QWindow *window, bool skip) { if (!window) return; #ifdef USE_UKUI_SHELL_PLUGIN window->setProperty("ukui_surface_skip_taskbar", skip); #elif if (!m_ukuiShell) return; auto surface = KWayland::Client::Surface::fromWindow(window); if (!surface) return; if (!m_surfaces.contains(window)) m_surfaces.insert(window, surface); auto ukuiShellSurface = m_ukuiShell->createSurface(surface, window); if (!ukuiShellSurface) return; if (!m_ukuiShellSurfaces.contains(window)) m_ukuiShellSurfaces.insert(window, ukuiShellSurface); ukuiShellSurface->setSkipTaskbar(skip); window->installEventFilter(this); #endif } void UkuiWaylandInterface::setSkipSwitcher(QWindow *window, bool skip) { if (!window) return; #ifdef USE_UKUI_SHELL_PLUGIN window->setProperty("ukui_surface_skip_switcher", skip); #elif if (!m_ukuiShell) return; auto surface = KWayland::Client::Surface::fromWindow(window); if (!surface) return; if (!m_surfaces.contains(window)) m_surfaces.insert(window, surface); auto ukuiShellSurface = m_ukuiShell->createSurface(surface, window); if (!ukuiShellSurface) return; if (!m_ukuiShellSurfaces.contains(window)) m_ukuiShellSurfaces.insert(window, ukuiShellSurface); ukuiShellSurface->setSkipSwitcher(skip); window->installEventFilter(this); #endif } bool UkuiWaylandInterface::skipTaskBar(const WindowId &wid) { auto window = windowFor(wid); return window ? window->skipTaskbar() : false; } bool UkuiWaylandInterface::skipSwitcher(const WindowId &wid) { auto window = windowFor(wid); return window ? window->skipSwitcher() : false; } bool UkuiWaylandInterface::isShowingDesktop() { bool flag = false; if (m_ukuiWindowManager) { flag = m_ukuiWindowManager->isShowingDesktop(); } return flag; } void UkuiWaylandInterface::setOnAllDesktops(const WindowId &wid) { auto w = windowFor(wid); if (w && m_desktops.count() > 1) { if (w->isOnAllDesktops()) { w->requestEnterVirtualDesktop(m_currentDesktop); } } } NET::WindowType UkuiWaylandInterface::windowType(WindowId wid) { return NET::WindowType::Normal; } void UkuiWaylandInterface::setPanelTakefocus(QWindow *window, bool flag) { if (!window) return; #ifdef USE_UKUI_SHELL_PLUGIN window->setProperty("ukui_surface_panel_takes_focus", flag); #elif if (!m_ukuiShell) return; auto surface = KWayland::Client::Surface::fromWindow(window); if (!surface) return; if (!m_surfaces.contains(window)) { m_surfaces.insert(window, surface); } auto ukuiShellSurface = m_ukuiShell->createSurface(surface, window); if (!ukuiShellSurface) return; if (!m_ukuiShellSurfaces.contains(window)) { m_ukuiShellSurfaces.insert(window, ukuiShellSurface); } ukuiShellSurface->setPanelTakesFocus(flag); window->installEventFilter(this); #endif } void UkuiWaylandInterface::demandAttention(const WindowId &wid) { auto w = windowFor(wid); if (w) { w->requestDemandAttention(); m_connection->roundtrip(); } } bool UkuiWaylandInterface::eventFilter(QObject *obj, QEvent *ev) { auto window = qobject_cast(obj); if (window && ev->type() == QEvent::Hide) { if (m_ukuiShellSurfaces.contains(window)) { auto ukuiShellSurface = m_ukuiShellSurfaces.value(window); if (ukuiShellSurface) { ukuiShellSurface->release(); ukuiShellSurface->destroy(); } m_ukuiShellSurfaces.remove(window); } if (m_surfaces.contains(window)) { auto surface = m_surfaces.value(window); if (surface) { surface->release(); surface->destroy(); } m_surfaces.remove(window); } } return QObject::eventFilter(obj, ev); } bool UkuiWaylandInterface::ukuiProtocolReady() { return m_ukuiShell && m_ukuiWindowManager; } Registry *UkuiWaylandInterface::registry() { return m_registry; } UkuiWindow *UkuiWaylandInterface::windowFor(WindowId wid) { auto it = std::find_if(m_ukuiWindowManager->windows().constBegin(), m_ukuiWindowManager->windows().constEnd(), [&wid](UkuiWindow *w) noexcept { return w->isValid() && w->uuid() == wid; }); if (it == m_ukuiWindowManager->windows().constEnd()) { return nullptr; } return *it; } void UkuiWaylandInterface::handleGlobal(void *data, wl_registry *registry, uint32_t name, const char *interface, uint32_t version) { if (strcmp(interface, ext_idle_notifier_v1_interface.name) == 0) { u_int32_t supportedVersion = qMin(wayland_ext_idle_notify_surpported_version, version); ext_idle_notifier_v1 *notifier = (ext_idle_notifier_v1 *)wl_registry_bind(registry, name, &ext_idle_notifier_v1_interface, supportedVersion); if (notifier) { m_notifier = new ExtIdleNotifier(this); m_notifier->setup(notifier); } } if (strcmp(interface, wl_seat_interface.name) == 0) { m_seat = (wl_seat *)wl_registry_bind(registry, name, &wl_seat_interface, version); } if (strcmp(interface, xdg_activation_v1_interface.name) == 0) { u_int32_t supportedVersion = qMin(wayland_xdg_activation_surpported_version, version); xdg_activation_v1 *xdg_activation = (xdg_activation_v1 *)wl_registry_bind(registry, name, &xdg_activation_v1_interface, supportedVersion); if (xdg_activation) { m_xdgActivation = new XdgActivation(this); m_xdgActivation->setup(xdg_activation); } } if (strcmp(interface, ukui_shell_interface.name) == 0) { u_int32_t supportedVersion = qMin(ukui_shell_surpported_version, version); ukui_shell *shell = (ukui_shell *)wl_registry_bind(registry, name, &ukui_shell_interface, supportedVersion); if (shell) { m_ukuiShell = new UkuiShell(this); m_ukuiShell->setup(shell); } } if (strcmp(interface, ukui_window_management_interface.name) == 0) { u_int32_t supportedVersion = qMin(ukui_window_management_surpported_version, version); ukui_window_management *wm = (ukui_window_management *)wl_registry_bind(registry, name, &ukui_window_management_interface, supportedVersion); if (wm) { m_ukuiWindowManager = new UkuiWindowManagement(this); m_ukuiWindowManager->setup(wm); connect(m_ukuiWindowManager, &UkuiWindowManagement::showingDesktopChanged, this, &AbstractInterface::isShowingDesktopChanged); connect(m_ukuiWindowManager, &UkuiWindowManagement::windowCreated, this, &UkuiWaylandInterface::ukuiWindowCreatedProxy); connect( m_ukuiWindowManager, &UkuiWindowManagement::activeWindowChanged, this, [&]() noexcept { UkuiWindow *w = m_ukuiWindowManager->activeWindow(); if (w) { emit activeWindowChanged(w ? w->uuid() : ""); } }, Qt::QueuedConnection); connect(m_ukuiWindowManager, &UkuiWindowManagement::windowCreated, this, [this](UkuiWindow *window) { if (!m_windows.contains(window->uuid())) { m_windows.insert(window->uuid(), this->requestInfo(window->uuid())); } emit windowAdded(window->uuid()); }); } } } void UkuiWaylandInterface::handleGlobalRemove(void *data, wl_registry *registry, uint32_t name) { } void UkuiWaylandInterface::ukuiWindowCreatedProxy(UkuiWindow *w) { if (!w->isValid()) return; if ((w->appId() == "ukui-panel")) return; trackUkuiWindow(w); } void UkuiWaylandInterface::trackUkuiWindow(UkuiWindow *w) { if (!w || w->appId() == "ukui-panel") return; connect(w, &UkuiWindow::titleChanged, this, [=]() { emit titleChanged(w->uuid()); }); connect(w, &UkuiWindow::fullscreenChanged, this, [=]() { emit fullscreenChanged(w->uuid()); }); connect(w, &UkuiWindow::iconChanged, this, [=]() { emit iconChanged(w->uuid()); }); connect(w, &UkuiWindow::activeChanged, this, [=]() { emit activeChanged(w->uuid()); }); connect(w, &UkuiWindow::keepAboveChanged, this, [=]() { emit keepAboveChanged(w->uuid()); }); connect(w, &UkuiWindow::minimizedChanged, this, [=]() { emit minimizedChanged(w->uuid()); }); connect(w, &UkuiWindow::maximizedChanged, this, [=]() { emit maximizedChanged(w->uuid()); }); connect(w, &UkuiWindow::onAllDesktopsChanged, this, [=]() { emit onAllDesktopsChanged(w->uuid()); }); connect(w, &UkuiWindow::demandsAttentionChanged, this, [=]() { emit demandsAttentionChanged(w->uuid()); }); connect(w, &UkuiWindow::skipTaskbarChanged, this, [=]() { emit skipTaskbarChanged(w->uuid()); }); connect(w, &UkuiWindow::skipSwitcherChanged, this, [=]() { emit skipSwitcherChanged(w->uuid()); }); connect(w, &UkuiWindow::geometryChanged, this, [=]() { emit geometryChanged(w->uuid()); }); connect(w, &UkuiWindow::unmapped, this, [=]() { emit windowRemoved(w->uuid()); untrackUkuiWindow(w); }); } void UkuiWaylandInterface::untrackUkuiWindow(UkuiWindow *w) { disconnect(w, &UkuiWindow::titleChanged, 0, 0); disconnect(w, &UkuiWindow::iconChanged, 0, 0); disconnect(w, &UkuiWindow::activeChanged, 0, 0); disconnect(w, &UkuiWindow::keepAboveChanged, 0, 0); disconnect(w, &UkuiWindow::keepBelowChanged, 0, 0); disconnect(w, &UkuiWindow::minimizedChanged, 0, 0); disconnect(w, &UkuiWindow::maximizedChanged, 0, 0); disconnect(w, &UkuiWindow::onAllDesktopsChanged, 0, 0); disconnect(w, &UkuiWindow::demandsAttentionChanged, 0, 0); disconnect(w, &UkuiWindow::skipTaskbarChanged, 0, 0); disconnect(w, &UkuiWindow::skipSwitcherChanged, 0, 0); disconnect(w, &UkuiWindow::geometryChanged, 0, 0); } libkysdk-applications/kysdk-waylandhelper/src/windowmanager/wmregister.cpp0000664000175000017500000000357315104543305026317 0ustar fengfeng/* * libkysdk-waylandhelper's Library * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #include "wmregister.h" #include "kdewaylandinterface.h" #include "ukuiwaylandinterface.h" #include "waylandhelper.h" #include "xcbinterface.h" #include #include #include #include using namespace kdk; using namespace KWayland::Client; kdk::WmRegister::WmRegister(QObject *parent) : QObject(parent) { QString platform = QGuiApplication::platformName(); if (platform.startsWith(QLatin1String("wayland"), Qt::CaseInsensitive)) { #ifdef USE_UKUI_PROTOCOL m_winInterface = new UkuiWaylandInterface(this); UkuiWaylandInterface *interface = dynamic_cast(m_winInterface); if (!interface->ukuiProtocolReady()) { delete m_winInterface; m_winInterface = new KdeWaylandInterface(this); } #else m_winInterface = new KdeWaylandInterface(this); #endif } else m_winInterface = new XcbInterface(this); } WmRegister::~WmRegister() { } AbstractInterface *WmRegister::winInterface() { return m_winInterface; } libkysdk-applications/kysdk-waylandhelper/src/windowmanager/ukuishell.cpp0000664000175000017500000002502315104543305026126 0ustar fengfeng/* * libkysdk-waylandhelper's Library * * Copyright (C) 2024, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #include "ukuishell.h" #include "ukuiwaylandpointer.h" class Q_DECL_HIDDEN UkuiShell::Private { public: Private(UkuiShell *q); UkuiWaylandPointer shell; EventQueue *queue = nullptr; UkuiShell *q; QString m_seatName; QString m_outputName; bool m_currentOutputReady = false; void init_listener(); static struct ukui_shell_listener s_listener; static void currentOutputCallback(void *data, struct ukui_shell *ukui_shell, const char *output_name, const char *seat_name); static void doneCallback(void *data, struct ukui_shell *ukui_shell); }; ukui_shell_listener UkuiShell::Private::s_listener = { .current_output = currentOutputCallback, .done = doneCallback}; class Q_DECL_HIDDEN UkuiShellSurface::Private { public: Private(UkuiShellSurface *q); ~Private(); void setup(ukui_surface *surface); UkuiWaylandPointer surface; QSize size; QPointer parentSurface; UkuiShellSurface::Role role; UkuiShellSurface::SurfaceProperty property; static UkuiShellSurface *get(Surface *surface); private: UkuiShellSurface *q; static QVector s_surfaces; }; QVector UkuiShellSurface::Private::s_surfaces; UkuiShell::UkuiShell(QObject *parent) : QObject(parent) , d(new Private(this)) { } UkuiShell::~UkuiShell() { release(); } void UkuiShell::destroy() { if (!d->shell) { return; } Q_EMIT interfaceAboutToBeDestroyed(); d->shell.destroy(); } void UkuiShell::release() { if (!d->shell) { return; } Q_EMIT interfaceAboutToBeReleased(); d->shell.release(); } void UkuiShell::setup(ukui_shell *shell) { Q_ASSERT(!d->shell); Q_ASSERT(shell); d->shell.setup(shell); d->init_listener(); } void UkuiShell::setEventQueue(EventQueue *queue) { d->queue = queue; } EventQueue *UkuiShell::eventQueue() { return d->queue; } QString UkuiShell::seatName() { if (d->m_currentOutputReady) return d->m_seatName; else return QString(); } QString UkuiShell::outputName() { if (d->m_currentOutputReady) return d->m_outputName; else return QString(); } bool UkuiShell::isCurrentOutputReady() { return d->m_currentOutputReady; } UkuiShellSurface *UkuiShell::createSurface(wl_surface *surface, QObject *parent) { Q_ASSERT(isValid()); auto kwS = Surface::get(surface); if (kwS) { if (auto s = UkuiShellSurface::Private::get(kwS)) { return s; } } UkuiShellSurface *s = new UkuiShellSurface(parent); connect(this, &UkuiShell::interfaceAboutToBeReleased, s, &UkuiShellSurface::release); connect(this, &UkuiShell::interfaceAboutToBeDestroyed, s, &UkuiShellSurface::destroy); auto w = ukui_shell_create_surface(d->shell, surface); if (d->queue) { d->queue->addProxy(w); } s->setup(w); s->d->parentSurface = QPointer(kwS); return s; } UkuiShellSurface *UkuiShell::createSurface(Surface *surface, QObject *parent) { return createSurface(*surface, parent); } void UkuiShell::updateCurrentOutput() { ukui_shell_get_current_output(d->shell); } bool UkuiShell::isValid() const { return d->shell.isValid(); } UkuiShell::operator ukui_shell *() { return d->shell; } UkuiShell::operator ukui_shell *() const { return d->shell; } UkuiShellSurface::Private::Private(UkuiShellSurface *q) : role(UkuiShellSurface::Role::Normal) , q(q) { s_surfaces << this; } UkuiShellSurface::Private::~Private() { s_surfaces.removeAll(this); } UkuiShellSurface *UkuiShellSurface::Private::get(Surface *surface) { if (!surface) { return nullptr; } for (auto it = s_surfaces.constBegin(); it != s_surfaces.constEnd(); ++it) { if ((*it)->parentSurface == surface) { return (*it)->q; } } return nullptr; } void UkuiShellSurface::Private::setup(ukui_surface *s) { Q_ASSERT(s); Q_ASSERT(!surface); surface.setup(s); } UkuiShellSurface::UkuiShellSurface(QObject *parent) : QObject(parent) , d(new Private(this)) { } UkuiShellSurface::~UkuiShellSurface() { release(); } void UkuiShellSurface::release() { d->surface.release(); } void UkuiShellSurface::destroy() { d->surface.destroy(); } void UkuiShellSurface::setup(ukui_surface *surface) { d->setup(surface); } UkuiShellSurface *UkuiShellSurface::get(Surface *surface) { if (auto s = UkuiShellSurface::Private::get(surface)) { return s; } return nullptr; } bool UkuiShellSurface::isValid() const { return d->surface.isValid(); } UkuiShellSurface::operator ukui_surface *() { return d->surface; } UkuiShellSurface::operator ukui_surface *() const { return d->surface; } void UkuiShellSurface::setPosition(const QPoint &point) { Q_ASSERT(isValid()); ukui_surface_set_position(d->surface, point.x(), point.y()); } void UkuiShellSurface::setRole(UkuiShellSurface::Role role) { Q_ASSERT(isValid()); uint32_t wlRole = UKUI_SURFACE_ROLE_NORMAL; switch (role) { case Role::Normal: wlRole = UKUI_SURFACE_ROLE_NORMAL; break; case Role::Desktop: wlRole = UKUI_SURFACE_ROLE_DESKTOP; break; case Role::Panel: wlRole = UKUI_SURFACE_ROLE_PANEL; break; case Role::OnScreenDisplay: wlRole = UKUI_SURFACE_ROLE_ONSCREENDISPLAY; break; case Role::Notification: wlRole = UKUI_SURFACE_ROLE_NOTIFICATION; break; case Role::ToolTip: wlRole = UKUI_SURFACE_ROLE_TOOLTIP; break; case Role::CriticalNotification: wlRole = UKUI_SURFACE_ROLE_CRITICALNOTIFICATION; break; case Role::AppletPop: wlRole = UKUI_SURFACE_ROLE_APPLETPOPUP; break; case Role::ScreenLock: wlRole = UKUI_SURFACE_ROLE_SCREENLOCK; break; case Role::Watermark: wlRole = UKUI_SURFACE_ROLE_WATERMARK; break; case Role::SystemWindow: wlRole = UKUI_SURFACE_ROLE_SYSTEMWINDOW; break; case Role::InputPanel: wlRole = UKUI_SURFACE_ROLE_INPUTPANEL; break; case Role::Logout: wlRole = UKUI_SURFACE_ROLE_LOGOUT; break; case Role::ScreenLockNotification: wlRole = UKUI_SURFACE_ROLE_SCREENLOCKNOTIFICATION; break; case Role::Switcher: wlRole = UKUI_SURFACE_ROLE_SWITCHER; break; case Role::Authentication: wlRole = UKUI_SURFACE_ROLE_AUTHENTICATION; break; default: Q_UNREACHABLE(); break; } ukui_surface_set_role(d->surface, wlRole); d->role = role; } UkuiShellSurface::Role UkuiShellSurface::role() const { return d->role; } void UkuiShellSurface::setSurfaceProperty(SurfaceProperty property, uint32_t value) { uint32_t wlPropery = -1; switch (property) { case SurfaceProperty::NoTitleBar: wlPropery = UKUI_SURFACE_PROPERTY_NO_TITLEBAR; break; case SurfaceProperty::Theme: wlPropery = UKUI_SURFACE_PROPERTY_THEME; break; case SurfaceProperty::WindowRadius: wlPropery = UKUI_SURFACE_PROPERTY_WINDOW_RADIUS; break; case SurfaceProperty::BorderWidth: wlPropery = UKUI_SURFACE_PROPERTY_BORDER_WIDTH; break; case SurfaceProperty::BorderColor: wlPropery = UKUI_SURFACE_PROPERTY_BORDER_COLOR; break; case SurfaceProperty::ShadowRadius: wlPropery = UKUI_SURFACE_PROPERTY_SHADOW_RADIUS; break; case SurfaceProperty::ShadowOffset: wlPropery = UKUI_SURFACE_PROPERTY_SHADOW_OFFSET; break; case SurfaceProperty::ShadowColor: wlPropery = UKUI_SURFACE_PROPERTY_SHADOW_COLOR; break; default: Q_UNREACHABLE(); break; } ukui_surface_set_property(d->surface, wlPropery, value); d->property = property; } UkuiShellSurface::SurfaceProperty UkuiShellSurface::surfaceProperty() const { return d->property; } void UkuiShellSurface::setSkipTaskbar(bool skip) { ukui_surface_set_skip_taskbar(d->surface, skip); } void UkuiShellSurface::setSkipSwitcher(bool skip) { ukui_surface_set_skip_switcher(d->surface, skip); } void UkuiShellSurface::setPanelTakesFocus(bool takesFocus) { ukui_surface_set_panel_takes_focus(d->surface, takesFocus); } void UkuiShellSurface::setPanelAutoHide(bool autoHide) { ukui_surface_set_panel_auto_hide(d->surface, autoHide); } void UkuiShellSurface::setGrabKeyboard(wl_seat *seat) { ukui_surface_grab_keyboard(d->surface, seat); } void UkuiShellSurface::setOpenUnderCursor() { ukui_surface_open_under_cursor(d->surface, 0, 0); } void UkuiShellSurface::setOpenUnderCursor(int x, int y) { ukui_surface_open_under_cursor(d->surface, x, y); } void UkuiShellSurface::setIconName(const QString &iconName) { if (iconName.isEmpty()) { ukui_surface_set_icon(d->surface, NULL); } else { ukui_surface_set_icon(d->surface, iconName.toStdString().c_str()); } } UkuiShell::Private::Private(UkuiShell *q) : q(q) { } void UkuiShell::Private::init_listener() { ukui_shell_add_listener(shell, &s_listener, this); } void UkuiShell::Private::currentOutputCallback(void *data, ukui_shell *ukui_shell, const char *output_name, const char *seat_name) { auto ukuiShell = reinterpret_cast(data); if (ukuiShell->shell != ukui_shell) return; ukuiShell->m_outputName = QString::fromUtf8(output_name); ukuiShell->m_seatName = QString::fromUtf8(seat_name); } void UkuiShell::Private::doneCallback(void *data, ukui_shell *ukui_shell) { auto ukuiShell = reinterpret_cast(data); if (ukuiShell->shell != ukui_shell) return; ukuiShell->m_currentOutputReady = true; Q_EMIT ukuiShell->q->currentOutputReady(); } ././@LongLink0000644000000000000000000000015700000000000011606 Lustar rootrootlibkysdk-applications/kysdk-waylandhelper/src/windowmanager/wayland-plasma-window-management-client-protocol.hlibkysdk-applications/kysdk-waylandhelper/src/windowmanager/wayland-plasma-window-management-client-0000664000175000017500000011414315104515306033224 0ustar fengfeng/* Generated by wayland-scanner 1.20.0 */ /* * libkysdk-waylandhelper's Library * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #ifndef PLASMA_WINDOW_MANAGEMENT_CLIENT_PROTOCOL_H #define PLASMA_WINDOW_MANAGEMENT_CLIENT_PROTOCOL_H #include #include #include "wayland-client.h" #ifdef __cplusplus extern "C" { #endif /** * @page page_plasma_window_management The plasma_window_management protocol * @section page_ifaces_plasma_window_management Interfaces * - @subpage page_iface_org_kde_plasma_window_management - application windows management * - @subpage page_iface_org_kde_plasma_window - interface to control application windows * - @subpage page_iface_org_kde_plasma_activation_feedback - activation feedback * - @subpage page_iface_org_kde_plasma_activation - * @section page_copyright_plasma_window_management Copyright *

 *
 * SPDX-FileCopyrightText: 2013-2014 Pier Luigi Fiorini
 *
 * SPDX-License-Identifier: LGPL-2.1-or-later
 * 
*/ struct org_kde_plasma_activation; struct org_kde_plasma_activation_feedback; struct org_kde_plasma_window; struct org_kde_plasma_window_management; struct wl_output; struct wl_surface; #ifndef ORG_KDE_PLASMA_WINDOW_MANAGEMENT_INTERFACE #define ORG_KDE_PLASMA_WINDOW_MANAGEMENT_INTERFACE /** * @page page_iface_org_kde_plasma_window_management org_kde_plasma_window_management * @section page_iface_org_kde_plasma_window_management_desc Description * * This interface manages application windows. * It provides requests to show and hide the desktop and emits * an event every time a window is created so that the client can * use it to manage the window. * * Only one client can bind this interface at a time. * @section page_iface_org_kde_plasma_window_management_api API * See @ref iface_org_kde_plasma_window_management. */ /** * @defgroup iface_org_kde_plasma_window_management The org_kde_plasma_window_management interface * * This interface manages application windows. * It provides requests to show and hide the desktop and emits * an event every time a window is created so that the client can * use it to manage the window. * * Only one client can bind this interface at a time. */ extern const struct wl_interface org_kde_plasma_window_management_interface; #endif #ifndef ORG_KDE_PLASMA_WINDOW_INTERFACE #define ORG_KDE_PLASMA_WINDOW_INTERFACE /** * @page page_iface_org_kde_plasma_window org_kde_plasma_window * @section page_iface_org_kde_plasma_window_desc Description * * Manages and control an application window. * * Only one client can bind this interface at a time. * @section page_iface_org_kde_plasma_window_api API * See @ref iface_org_kde_plasma_window. */ /** * @defgroup iface_org_kde_plasma_window The org_kde_plasma_window interface * * Manages and control an application window. * * Only one client can bind this interface at a time. */ extern const struct wl_interface org_kde_plasma_window_interface; #endif #ifndef ORG_KDE_PLASMA_ACTIVATION_FEEDBACK_INTERFACE #define ORG_KDE_PLASMA_ACTIVATION_FEEDBACK_INTERFACE /** * @page page_iface_org_kde_plasma_activation_feedback org_kde_plasma_activation_feedback * @section page_iface_org_kde_plasma_activation_feedback_desc Description * * The activation manager interface provides a way to get notified * when an application is about to be activated. * @section page_iface_org_kde_plasma_activation_feedback_api API * See @ref iface_org_kde_plasma_activation_feedback. */ /** * @defgroup iface_org_kde_plasma_activation_feedback The org_kde_plasma_activation_feedback interface * * The activation manager interface provides a way to get notified * when an application is about to be activated. */ extern const struct wl_interface org_kde_plasma_activation_feedback_interface; #endif #ifndef ORG_KDE_PLASMA_ACTIVATION_INTERFACE #define ORG_KDE_PLASMA_ACTIVATION_INTERFACE /** * @page page_iface_org_kde_plasma_activation org_kde_plasma_activation * @section page_iface_org_kde_plasma_activation_api API * See @ref iface_org_kde_plasma_activation. */ /** * @defgroup iface_org_kde_plasma_activation The org_kde_plasma_activation interface */ extern const struct wl_interface org_kde_plasma_activation_interface; #endif #ifndef ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_ENUM #define ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_ENUM enum org_kde_plasma_window_management_state { ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_ACTIVE = 1 << 0, ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_MINIMIZED = 1 << 1, ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_MAXIMIZED = 1 << 2, ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_FULLSCREEN = 1 << 3, ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_KEEP_ABOVE = 1 << 4, ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_KEEP_BELOW = 1 << 5, ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_ON_ALL_DESKTOPS = 1 << 6, ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_DEMANDS_ATTENTION = 1 << 7, ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_CLOSEABLE = 1 << 8, ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_MINIMIZABLE = 1 << 9, ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_MAXIMIZABLE = 1 << 10, ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_FULLSCREENABLE = 1 << 11, /** * @since 2 */ ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_SKIPTASKBAR = 1 << 12, /** * @since 3 */ ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_SHADEABLE = 1 << 13, /** * @since 3 */ ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_SHADED = 1 << 14, /** * @since 3 */ ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_MOVABLE = 1 << 15, /** * @since 3 */ ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_RESIZABLE = 1 << 16, /** * @since 3 */ ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_VIRTUAL_DESKTOP_CHANGEABLE = 1 << 17, /** * @since 9 */ ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_SKIPSWITCHER = 1 << 18, }; /** * @ingroup iface_org_kde_plasma_window_management */ #define ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_SKIPTASKBAR_SINCE_VERSION 2 /** * @ingroup iface_org_kde_plasma_window_management */ #define ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_SHADEABLE_SINCE_VERSION 3 /** * @ingroup iface_org_kde_plasma_window_management */ #define ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_SHADED_SINCE_VERSION 3 /** * @ingroup iface_org_kde_plasma_window_management */ #define ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_MOVABLE_SINCE_VERSION 3 /** * @ingroup iface_org_kde_plasma_window_management */ #define ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_RESIZABLE_SINCE_VERSION 3 /** * @ingroup iface_org_kde_plasma_window_management */ #define ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_VIRTUAL_DESKTOP_CHANGEABLE_SINCE_VERSION 3 /** * @ingroup iface_org_kde_plasma_window_management */ #define ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_SKIPSWITCHER_SINCE_VERSION 9 #endif /* ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STATE_ENUM */ #ifndef ORG_KDE_PLASMA_WINDOW_MANAGEMENT_SHOW_DESKTOP_ENUM #define ORG_KDE_PLASMA_WINDOW_MANAGEMENT_SHOW_DESKTOP_ENUM enum org_kde_plasma_window_management_show_desktop { ORG_KDE_PLASMA_WINDOW_MANAGEMENT_SHOW_DESKTOP_DISABLED = 0, ORG_KDE_PLASMA_WINDOW_MANAGEMENT_SHOW_DESKTOP_ENABLED = 1, }; #endif /* ORG_KDE_PLASMA_WINDOW_MANAGEMENT_SHOW_DESKTOP_ENUM */ /** * @ingroup iface_org_kde_plasma_window_management * @struct org_kde_plasma_window_management_listener */ struct org_kde_plasma_window_management_listener { /** * notify the client when the show desktop mode is entered/left * * This event will be sent whenever the show desktop mode * changes. E.g. when it is entered or left. * * On binding the interface the current state is sent. * @param state new state */ void (*show_desktop_changed)(void *data, struct org_kde_plasma_window_management *org_kde_plasma_window_management, uint32_t state); /** * notify the client that a window was mapped * * This event will be sent immediately after a window is mapped. * @param id Deprecated: internal window Id */ void (*window)(void *data, struct org_kde_plasma_window_management *org_kde_plasma_window_management, uint32_t id); /** * notify the client when stacking order changed * * This event will be sent when stacking order changed and on * bind * @param ids internal windows id array * @since 11 */ void (*stacking_order_changed)(void *data, struct org_kde_plasma_window_management *org_kde_plasma_window_management, struct wl_array *ids); /** * notify the client when stacking order changed * * This event will be sent when stacking order changed and on * bind * @param uuids internal windows id ;-separated * @since 12 */ void (*stacking_order_uuid_changed)(void *data, struct org_kde_plasma_window_management *org_kde_plasma_window_management, const char *uuids); /** * notify the client that a window was mapped * * This event will be sent immediately after a window is mapped. * @param id Deprecated: internal window Id * @param uuid internal window uuid * @since 13 */ void (*window_with_uuid)(void *data, struct org_kde_plasma_window_management *org_kde_plasma_window_management, uint32_t id, const char *uuid); }; /** * @ingroup iface_org_kde_plasma_window_management */ static inline int org_kde_plasma_window_management_add_listener(struct org_kde_plasma_window_management *org_kde_plasma_window_management, const struct org_kde_plasma_window_management_listener *listener, void *data) { return wl_proxy_add_listener((struct wl_proxy *) org_kde_plasma_window_management, (void (**)(void)) listener, data); } #define ORG_KDE_PLASMA_WINDOW_MANAGEMENT_SHOW_DESKTOP 0 #define ORG_KDE_PLASMA_WINDOW_MANAGEMENT_GET_WINDOW 1 #define ORG_KDE_PLASMA_WINDOW_MANAGEMENT_GET_WINDOW_BY_UUID 2 /** * @ingroup iface_org_kde_plasma_window_management */ #define ORG_KDE_PLASMA_WINDOW_MANAGEMENT_SHOW_DESKTOP_CHANGED_SINCE_VERSION 1 /** * @ingroup iface_org_kde_plasma_window_management */ #define ORG_KDE_PLASMA_WINDOW_MANAGEMENT_WINDOW_SINCE_VERSION 1 /** * @ingroup iface_org_kde_plasma_window_management */ #define ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STACKING_ORDER_CHANGED_SINCE_VERSION 11 /** * @ingroup iface_org_kde_plasma_window_management */ #define ORG_KDE_PLASMA_WINDOW_MANAGEMENT_STACKING_ORDER_UUID_CHANGED_SINCE_VERSION 12 /** * @ingroup iface_org_kde_plasma_window_management */ #define ORG_KDE_PLASMA_WINDOW_MANAGEMENT_WINDOW_WITH_UUID_SINCE_VERSION 13 /** * @ingroup iface_org_kde_plasma_window_management */ #define ORG_KDE_PLASMA_WINDOW_MANAGEMENT_SHOW_DESKTOP_SINCE_VERSION 1 /** * @ingroup iface_org_kde_plasma_window_management */ #define ORG_KDE_PLASMA_WINDOW_MANAGEMENT_GET_WINDOW_SINCE_VERSION 1 /** * @ingroup iface_org_kde_plasma_window_management */ #define ORG_KDE_PLASMA_WINDOW_MANAGEMENT_GET_WINDOW_BY_UUID_SINCE_VERSION 12 /** @ingroup iface_org_kde_plasma_window_management */ static inline void org_kde_plasma_window_management_set_user_data(struct org_kde_plasma_window_management *org_kde_plasma_window_management, void *user_data) { wl_proxy_set_user_data((struct wl_proxy *) org_kde_plasma_window_management, user_data); } /** @ingroup iface_org_kde_plasma_window_management */ static inline void * org_kde_plasma_window_management_get_user_data(struct org_kde_plasma_window_management *org_kde_plasma_window_management) { return wl_proxy_get_user_data((struct wl_proxy *) org_kde_plasma_window_management); } static inline uint32_t org_kde_plasma_window_management_get_version(struct org_kde_plasma_window_management *org_kde_plasma_window_management) { return wl_proxy_get_version((struct wl_proxy *) org_kde_plasma_window_management); } /** @ingroup iface_org_kde_plasma_window_management */ static inline void org_kde_plasma_window_management_destroy(struct org_kde_plasma_window_management *org_kde_plasma_window_management) { wl_proxy_destroy((struct wl_proxy *) org_kde_plasma_window_management); } /** * @ingroup iface_org_kde_plasma_window_management * * Tell the compositor to show/hide the desktop. */ static inline void org_kde_plasma_window_management_show_desktop(struct org_kde_plasma_window_management *org_kde_plasma_window_management, uint32_t state) { wl_proxy_marshal_flags((struct wl_proxy *) org_kde_plasma_window_management, ORG_KDE_PLASMA_WINDOW_MANAGEMENT_SHOW_DESKTOP, NULL, wl_proxy_get_version((struct wl_proxy *) org_kde_plasma_window_management), 0, state); } /** * @ingroup iface_org_kde_plasma_window_management * Deprecated: use get_window_by_uuid */ static inline struct org_kde_plasma_window * org_kde_plasma_window_management_get_window(struct org_kde_plasma_window_management *org_kde_plasma_window_management, uint32_t internal_window_id) { struct wl_proxy *id; id = wl_proxy_marshal_flags((struct wl_proxy *) org_kde_plasma_window_management, ORG_KDE_PLASMA_WINDOW_MANAGEMENT_GET_WINDOW, &org_kde_plasma_window_interface, wl_proxy_get_version((struct wl_proxy *) org_kde_plasma_window_management), 0, NULL, internal_window_id); return (struct org_kde_plasma_window *) id; } /** * @ingroup iface_org_kde_plasma_window_management */ static inline struct org_kde_plasma_window * org_kde_plasma_window_management_get_window_by_uuid(struct org_kde_plasma_window_management *org_kde_plasma_window_management, const char *internal_window_uuid) { struct wl_proxy *id; id = wl_proxy_marshal_flags((struct wl_proxy *) org_kde_plasma_window_management, ORG_KDE_PLASMA_WINDOW_MANAGEMENT_GET_WINDOW_BY_UUID, &org_kde_plasma_window_interface, wl_proxy_get_version((struct wl_proxy *) org_kde_plasma_window_management), 0, NULL, internal_window_uuid); return (struct org_kde_plasma_window *) id; } /** * @ingroup iface_org_kde_plasma_window * @struct org_kde_plasma_window_listener */ struct org_kde_plasma_window_listener { /** * window title has been changed * * This event will be sent as soon as the window title is * changed. * @param title window title */ void (*title_changed)(void *data, struct org_kde_plasma_window *org_kde_plasma_window, const char *title); /** * application identifier has been changed * * This event will be sent as soon as the application identifier * is changed. */ void (*app_id_changed)(void *data, struct org_kde_plasma_window *org_kde_plasma_window, const char *app_id); /** * window state has been changed * * This event will be sent as soon as the window state changes. * * Values for state argument are described by * org_kde_plasma_window_management.state. * @param flags bitfield of state flags */ void (*state_changed)(void *data, struct org_kde_plasma_window *org_kde_plasma_window, uint32_t flags); /** * window was moved to another workspace * * DEPRECATED: use virtual_desktop_entered and * virtual_desktop_left instead This event will be sent when a * window is moved to another virtual desktop. * * It is not sent if it becomes visible on all virtual desktops * though. * @param number zero based virtual desktop number */ void (*virtual_desktop_changed)(void *data, struct org_kde_plasma_window *org_kde_plasma_window, int32_t number); /** * window's icon name changed * * This event will be sent whenever the themed icon name changes. * May be null. * @param name the new themed icon name */ void (*themed_icon_name_changed)(void *data, struct org_kde_plasma_window *org_kde_plasma_window, const char *name); /** * window's surface was unmapped * * This event will be sent immediately after the window is closed * and its surface is unmapped. */ void (*unmapped)(void *data, struct org_kde_plasma_window *org_kde_plasma_window); /** * All initial known state is submitted * * This event will be sent immediately after all initial state * been sent to the client. If the Plasma window is already * unmapped, the unmapped event will be sent before the * initial_state event. * @since 4 */ void (*initial_state)(void *data, struct org_kde_plasma_window *org_kde_plasma_window); /** * The parent window changed * * This event will be sent whenever the parent window of this * org_kde_plasma_window changes. The passed parent is another * org_kde_plasma_window and this org_kde_plasma_window is a * transient window to the parent window. If the parent argument is * null, this org_kde_plasma_window does not have a parent window. * @param parent The parent window * @since 5 */ void (*parent_window)(void *data, struct org_kde_plasma_window *org_kde_plasma_window, struct org_kde_plasma_window *parent); /** * The geometry of this window in absolute coordinates * * This event will be sent whenever the window geometry of this * org_kde_plasma_window changes. The coordinates are in absolute * coordinates of the windowing system. * @param x x position of the org_kde_plasma_window * @param y y position of the org_kde_plasma_window * @param width width of the org_kde_plasma_window * @param height height of the org_kde_plasma_window * @since 6 */ void (*geometry)(void *data, struct org_kde_plasma_window *org_kde_plasma_window, int32_t x, int32_t y, uint32_t width, uint32_t height); /** * The icon of the window changed * * This event will be sent whenever the icon of the window * changes, but there is no themed icon name. Common examples are * Xwayland windows which have a pixmap based icon. * * The client can request the icon using get_icon. * @since 7 */ void (*icon_changed)(void *data, struct org_kde_plasma_window *org_kde_plasma_window); /** * process id of application owning the window has changed * * This event will be sent when the compositor has set the * process id this window belongs to. This should be set once * before the initial_state is sent. * @param pid process id */ void (*pid_changed)(void *data, struct org_kde_plasma_window *org_kde_plasma_window, uint32_t pid); /** * the window entered a new virtual desktop * * This event will be sent when the window has entered a new * virtual desktop. The window can be on more than one desktop, or * none: then is considered on all of them. * @param id desktop id * @since 8 */ void (*virtual_desktop_entered)(void *data, struct org_kde_plasma_window *org_kde_plasma_window, const char *id); /** * the window left a virtual desktop * * This event will be sent when the window left a virtual * desktop. If the window leaves all desktops, it can be considered * on all. If the window gets manually added on all desktops, the * server has to send virtual_desktop_left for every previous * desktop it was in for the window to be really considered on all * desktops. * @param is desktop id * @since 8 */ void (*virtual_desktop_left)(void *data, struct org_kde_plasma_window *org_kde_plasma_window, const char *is); /** * notify the client that the current appmenu changed * * This event will be sent after the application menu for the * window has changed. * @since 10 */ void (*application_menu)(void *data, struct org_kde_plasma_window *org_kde_plasma_window, const char *service_name, const char *object_path); /** * the window entered an activity * * This event will be sent when the window has entered an * activity. The window can be on more than one activity, or none: * then is considered on all of them. * @param id activity id * @since 14 */ void (*activity_entered)(void *data, struct org_kde_plasma_window *org_kde_plasma_window, const char *id); /** * the window left an activity * * This event will be sent when the window left an activity. If * the window leaves all activities, it will be considered on all. * If the window gets manually added on all activities, the server * has to send activity_left for every previous activity it was in * for the window to be really considered on all activities. * @param id activity id * @since 14 */ void (*activity_left)(void *data, struct org_kde_plasma_window *org_kde_plasma_window, const char *id); }; /** * @ingroup iface_org_kde_plasma_window */ static inline int org_kde_plasma_window_add_listener(struct org_kde_plasma_window *org_kde_plasma_window, const struct org_kde_plasma_window_listener *listener, void *data) { return wl_proxy_add_listener((struct wl_proxy *) org_kde_plasma_window, (void (**)(void)) listener, data); } #define ORG_KDE_PLASMA_WINDOW_SET_STATE 0 #define ORG_KDE_PLASMA_WINDOW_SET_VIRTUAL_DESKTOP 1 #define ORG_KDE_PLASMA_WINDOW_SET_MINIMIZED_GEOMETRY 2 #define ORG_KDE_PLASMA_WINDOW_UNSET_MINIMIZED_GEOMETRY 3 #define ORG_KDE_PLASMA_WINDOW_CLOSE 4 #define ORG_KDE_PLASMA_WINDOW_REQUEST_MOVE 5 #define ORG_KDE_PLASMA_WINDOW_REQUEST_RESIZE 6 #define ORG_KDE_PLASMA_WINDOW_DESTROY 7 #define ORG_KDE_PLASMA_WINDOW_GET_ICON 8 #define ORG_KDE_PLASMA_WINDOW_REQUEST_ENTER_VIRTUAL_DESKTOP 9 #define ORG_KDE_PLASMA_WINDOW_REQUEST_ENTER_NEW_VIRTUAL_DESKTOP 10 #define ORG_KDE_PLASMA_WINDOW_REQUEST_LEAVE_VIRTUAL_DESKTOP 11 #define ORG_KDE_PLASMA_WINDOW_REQUEST_ENTER_ACTIVITY 12 #define ORG_KDE_PLASMA_WINDOW_REQUEST_LEAVE_ACTIVITY 13 #define ORG_KDE_PLASMA_WINDOW_SEND_TO_OUTPUT 14 /** * @ingroup iface_org_kde_plasma_window */ #define ORG_KDE_PLASMA_WINDOW_TITLE_CHANGED_SINCE_VERSION 1 /** * @ingroup iface_org_kde_plasma_window */ #define ORG_KDE_PLASMA_WINDOW_APP_ID_CHANGED_SINCE_VERSION 1 /** * @ingroup iface_org_kde_plasma_window */ #define ORG_KDE_PLASMA_WINDOW_STATE_CHANGED_SINCE_VERSION 1 /** * @ingroup iface_org_kde_plasma_window */ #define ORG_KDE_PLASMA_WINDOW_VIRTUAL_DESKTOP_CHANGED_SINCE_VERSION 1 /** * @ingroup iface_org_kde_plasma_window */ #define ORG_KDE_PLASMA_WINDOW_THEMED_ICON_NAME_CHANGED_SINCE_VERSION 1 /** * @ingroup iface_org_kde_plasma_window */ #define ORG_KDE_PLASMA_WINDOW_UNMAPPED_SINCE_VERSION 1 /** * @ingroup iface_org_kde_plasma_window */ #define ORG_KDE_PLASMA_WINDOW_INITIAL_STATE_SINCE_VERSION 4 /** * @ingroup iface_org_kde_plasma_window */ #define ORG_KDE_PLASMA_WINDOW_PARENT_WINDOW_SINCE_VERSION 5 /** * @ingroup iface_org_kde_plasma_window */ #define ORG_KDE_PLASMA_WINDOW_GEOMETRY_SINCE_VERSION 6 /** * @ingroup iface_org_kde_plasma_window */ #define ORG_KDE_PLASMA_WINDOW_ICON_CHANGED_SINCE_VERSION 7 /** * @ingroup iface_org_kde_plasma_window */ #define ORG_KDE_PLASMA_WINDOW_PID_CHANGED_SINCE_VERSION 1 /** * @ingroup iface_org_kde_plasma_window */ #define ORG_KDE_PLASMA_WINDOW_VIRTUAL_DESKTOP_ENTERED_SINCE_VERSION 8 /** * @ingroup iface_org_kde_plasma_window */ #define ORG_KDE_PLASMA_WINDOW_VIRTUAL_DESKTOP_LEFT_SINCE_VERSION 8 /** * @ingroup iface_org_kde_plasma_window */ #define ORG_KDE_PLASMA_WINDOW_APPLICATION_MENU_SINCE_VERSION 10 /** * @ingroup iface_org_kde_plasma_window */ #define ORG_KDE_PLASMA_WINDOW_ACTIVITY_ENTERED_SINCE_VERSION 14 /** * @ingroup iface_org_kde_plasma_window */ #define ORG_KDE_PLASMA_WINDOW_ACTIVITY_LEFT_SINCE_VERSION 14 /** * @ingroup iface_org_kde_plasma_window */ #define ORG_KDE_PLASMA_WINDOW_SET_STATE_SINCE_VERSION 1 /** * @ingroup iface_org_kde_plasma_window */ #define ORG_KDE_PLASMA_WINDOW_SET_VIRTUAL_DESKTOP_SINCE_VERSION 1 /** * @ingroup iface_org_kde_plasma_window */ #define ORG_KDE_PLASMA_WINDOW_SET_MINIMIZED_GEOMETRY_SINCE_VERSION 1 /** * @ingroup iface_org_kde_plasma_window */ #define ORG_KDE_PLASMA_WINDOW_UNSET_MINIMIZED_GEOMETRY_SINCE_VERSION 1 /** * @ingroup iface_org_kde_plasma_window */ #define ORG_KDE_PLASMA_WINDOW_CLOSE_SINCE_VERSION 1 /** * @ingroup iface_org_kde_plasma_window */ #define ORG_KDE_PLASMA_WINDOW_REQUEST_MOVE_SINCE_VERSION 3 /** * @ingroup iface_org_kde_plasma_window */ #define ORG_KDE_PLASMA_WINDOW_REQUEST_RESIZE_SINCE_VERSION 3 /** * @ingroup iface_org_kde_plasma_window */ #define ORG_KDE_PLASMA_WINDOW_DESTROY_SINCE_VERSION 4 /** * @ingroup iface_org_kde_plasma_window */ #define ORG_KDE_PLASMA_WINDOW_GET_ICON_SINCE_VERSION 7 /** * @ingroup iface_org_kde_plasma_window */ #define ORG_KDE_PLASMA_WINDOW_REQUEST_ENTER_VIRTUAL_DESKTOP_SINCE_VERSION 8 /** * @ingroup iface_org_kde_plasma_window */ #define ORG_KDE_PLASMA_WINDOW_REQUEST_ENTER_NEW_VIRTUAL_DESKTOP_SINCE_VERSION 8 /** * @ingroup iface_org_kde_plasma_window */ #define ORG_KDE_PLASMA_WINDOW_REQUEST_LEAVE_VIRTUAL_DESKTOP_SINCE_VERSION 8 /** * @ingroup iface_org_kde_plasma_window */ #define ORG_KDE_PLASMA_WINDOW_REQUEST_ENTER_ACTIVITY_SINCE_VERSION 14 /** * @ingroup iface_org_kde_plasma_window */ #define ORG_KDE_PLASMA_WINDOW_REQUEST_LEAVE_ACTIVITY_SINCE_VERSION 14 /** * @ingroup iface_org_kde_plasma_window */ #define ORG_KDE_PLASMA_WINDOW_SEND_TO_OUTPUT_SINCE_VERSION 15 /** @ingroup iface_org_kde_plasma_window */ static inline void org_kde_plasma_window_set_user_data(struct org_kde_plasma_window *org_kde_plasma_window, void *user_data) { wl_proxy_set_user_data((struct wl_proxy *) org_kde_plasma_window, user_data); } /** @ingroup iface_org_kde_plasma_window */ static inline void * org_kde_plasma_window_get_user_data(struct org_kde_plasma_window *org_kde_plasma_window) { return wl_proxy_get_user_data((struct wl_proxy *) org_kde_plasma_window); } static inline uint32_t org_kde_plasma_window_get_version(struct org_kde_plasma_window *org_kde_plasma_window) { return wl_proxy_get_version((struct wl_proxy *) org_kde_plasma_window); } /** * @ingroup iface_org_kde_plasma_window * * Set window state. * * Values for state argument are described by org_kde_plasma_window_management.state * and can be used together in a bitfield. The flags bitfield describes which flags are * supposed to be set, the state bitfield the value for the set flags */ static inline void org_kde_plasma_window_set_state(struct org_kde_plasma_window *org_kde_plasma_window, uint32_t flags, uint32_t state) { wl_proxy_marshal_flags((struct wl_proxy *) org_kde_plasma_window, ORG_KDE_PLASMA_WINDOW_SET_STATE, NULL, wl_proxy_get_version((struct wl_proxy *) org_kde_plasma_window), 0, flags, state); } /** * @ingroup iface_org_kde_plasma_window * * Deprecated: use enter_virtual_desktop * Maps the window to a different virtual desktop. * * To show the window on all virtual desktops, call the * org_kde_plasma_window.set_state request and specify a on_all_desktops * state in the bitfield. */ static inline void org_kde_plasma_window_set_virtual_desktop(struct org_kde_plasma_window *org_kde_plasma_window, uint32_t number) { wl_proxy_marshal_flags((struct wl_proxy *) org_kde_plasma_window, ORG_KDE_PLASMA_WINDOW_SET_VIRTUAL_DESKTOP, NULL, wl_proxy_get_version((struct wl_proxy *) org_kde_plasma_window), 0, number); } /** * @ingroup iface_org_kde_plasma_window * * Sets the geometry of the taskbar entry for this window. * The geometry is relative to a panel in particular. */ static inline void org_kde_plasma_window_set_minimized_geometry(struct org_kde_plasma_window *org_kde_plasma_window, struct wl_surface *panel, uint32_t x, uint32_t y, uint32_t width, uint32_t height) { wl_proxy_marshal_flags((struct wl_proxy *) org_kde_plasma_window, ORG_KDE_PLASMA_WINDOW_SET_MINIMIZED_GEOMETRY, NULL, wl_proxy_get_version((struct wl_proxy *) org_kde_plasma_window), 0, panel, x, y, width, height); } /** * @ingroup iface_org_kde_plasma_window * * Remove the task geometry information for a particular panel. */ static inline void org_kde_plasma_window_unset_minimized_geometry(struct org_kde_plasma_window *org_kde_plasma_window, struct wl_surface *panel) { wl_proxy_marshal_flags((struct wl_proxy *) org_kde_plasma_window, ORG_KDE_PLASMA_WINDOW_UNSET_MINIMIZED_GEOMETRY, NULL, wl_proxy_get_version((struct wl_proxy *) org_kde_plasma_window), 0, panel); } /** * @ingroup iface_org_kde_plasma_window * * Close this window. */ static inline void org_kde_plasma_window_close(struct org_kde_plasma_window *org_kde_plasma_window) { wl_proxy_marshal_flags((struct wl_proxy *) org_kde_plasma_window, ORG_KDE_PLASMA_WINDOW_CLOSE, NULL, wl_proxy_get_version((struct wl_proxy *) org_kde_plasma_window), 0); } /** * @ingroup iface_org_kde_plasma_window * * Request an interactive move for this window. */ static inline void org_kde_plasma_window_request_move(struct org_kde_plasma_window *org_kde_plasma_window) { wl_proxy_marshal_flags((struct wl_proxy *) org_kde_plasma_window, ORG_KDE_PLASMA_WINDOW_REQUEST_MOVE, NULL, wl_proxy_get_version((struct wl_proxy *) org_kde_plasma_window), 0); } /** * @ingroup iface_org_kde_plasma_window * * Request an interactive resize for this window. */ static inline void org_kde_plasma_window_request_resize(struct org_kde_plasma_window *org_kde_plasma_window) { wl_proxy_marshal_flags((struct wl_proxy *) org_kde_plasma_window, ORG_KDE_PLASMA_WINDOW_REQUEST_RESIZE, NULL, wl_proxy_get_version((struct wl_proxy *) org_kde_plasma_window), 0); } /** * @ingroup iface_org_kde_plasma_window * * Removes the resource bound for this org_kde_plasma_window. */ static inline void org_kde_plasma_window_destroy(struct org_kde_plasma_window *org_kde_plasma_window) { wl_proxy_marshal_flags((struct wl_proxy *) org_kde_plasma_window, ORG_KDE_PLASMA_WINDOW_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) org_kde_plasma_window), WL_MARSHAL_FLAG_DESTROY); } /** * @ingroup iface_org_kde_plasma_window * * The compositor will write the window icon into the provided file descriptor. * The data is a serialized QIcon with QDataStream. */ static inline void org_kde_plasma_window_get_icon(struct org_kde_plasma_window *org_kde_plasma_window, int32_t fd) { wl_proxy_marshal_flags((struct wl_proxy *) org_kde_plasma_window, ORG_KDE_PLASMA_WINDOW_GET_ICON, NULL, wl_proxy_get_version((struct wl_proxy *) org_kde_plasma_window), 0, fd); } /** * @ingroup iface_org_kde_plasma_window * * Make the window enter a virtual desktop. A window can enter more * than one virtual desktop. if the id is empty or invalid, no action will be performed. */ static inline void org_kde_plasma_window_request_enter_virtual_desktop(struct org_kde_plasma_window *org_kde_plasma_window, const char *id) { wl_proxy_marshal_flags((struct wl_proxy *) org_kde_plasma_window, ORG_KDE_PLASMA_WINDOW_REQUEST_ENTER_VIRTUAL_DESKTOP, NULL, wl_proxy_get_version((struct wl_proxy *) org_kde_plasma_window), 0, id); } /** * @ingroup iface_org_kde_plasma_window * RFC: do this with an empty id to request_enter_virtual_desktop? * Make the window enter a new virtual desktop. If the server consents the request, * it will create a new virtual desktop and assign the window to it. */ static inline void org_kde_plasma_window_request_enter_new_virtual_desktop(struct org_kde_plasma_window *org_kde_plasma_window) { wl_proxy_marshal_flags((struct wl_proxy *) org_kde_plasma_window, ORG_KDE_PLASMA_WINDOW_REQUEST_ENTER_NEW_VIRTUAL_DESKTOP, NULL, wl_proxy_get_version((struct wl_proxy *) org_kde_plasma_window), 0); } /** * @ingroup iface_org_kde_plasma_window * * Make the window exit a virtual desktop. If it exits all desktops it will be considered on all of them. */ static inline void org_kde_plasma_window_request_leave_virtual_desktop(struct org_kde_plasma_window *org_kde_plasma_window, const char *id) { wl_proxy_marshal_flags((struct wl_proxy *) org_kde_plasma_window, ORG_KDE_PLASMA_WINDOW_REQUEST_LEAVE_VIRTUAL_DESKTOP, NULL, wl_proxy_get_version((struct wl_proxy *) org_kde_plasma_window), 0, id); } /** * @ingroup iface_org_kde_plasma_window * * Make the window enter an activity. A window can enter more activity. If the id is empty or invalid, no action will be performed. */ static inline void org_kde_plasma_window_request_enter_activity(struct org_kde_plasma_window *org_kde_plasma_window, const char *id) { wl_proxy_marshal_flags((struct wl_proxy *) org_kde_plasma_window, ORG_KDE_PLASMA_WINDOW_REQUEST_ENTER_ACTIVITY, NULL, wl_proxy_get_version((struct wl_proxy *) org_kde_plasma_window), 0, id); } /** * @ingroup iface_org_kde_plasma_window * * Make the window exit a an activity. If it exits all activities it will be considered on all of them. */ static inline void org_kde_plasma_window_request_leave_activity(struct org_kde_plasma_window *org_kde_plasma_window, const char *id) { wl_proxy_marshal_flags((struct wl_proxy *) org_kde_plasma_window, ORG_KDE_PLASMA_WINDOW_REQUEST_LEAVE_ACTIVITY, NULL, wl_proxy_get_version((struct wl_proxy *) org_kde_plasma_window), 0, id); } /** * @ingroup iface_org_kde_plasma_window * * Requests this window to be displayed in a specific output. */ static inline void org_kde_plasma_window_send_to_output(struct org_kde_plasma_window *org_kde_plasma_window, struct wl_output *output) { wl_proxy_marshal_flags((struct wl_proxy *) org_kde_plasma_window, ORG_KDE_PLASMA_WINDOW_SEND_TO_OUTPUT, NULL, wl_proxy_get_version((struct wl_proxy *) org_kde_plasma_window), 0, output); } /** * @ingroup iface_org_kde_plasma_activation_feedback * @struct org_kde_plasma_activation_feedback_listener */ struct org_kde_plasma_activation_feedback_listener { /** * notify that an app is starting * * Will be issued when an app is set to be activated. It offers * an instance of org_kde_plasma_activation that will tell us the * app_id and the extent of the activation. */ void (*activation)(void *data, struct org_kde_plasma_activation_feedback *org_kde_plasma_activation_feedback, struct org_kde_plasma_activation *id); }; /** * @ingroup iface_org_kde_plasma_activation_feedback */ static inline int org_kde_plasma_activation_feedback_add_listener(struct org_kde_plasma_activation_feedback *org_kde_plasma_activation_feedback, const struct org_kde_plasma_activation_feedback_listener *listener, void *data) { return wl_proxy_add_listener((struct wl_proxy *) org_kde_plasma_activation_feedback, (void (**)(void)) listener, data); } #define ORG_KDE_PLASMA_ACTIVATION_FEEDBACK_DESTROY 0 /** * @ingroup iface_org_kde_plasma_activation_feedback */ #define ORG_KDE_PLASMA_ACTIVATION_FEEDBACK_ACTIVATION_SINCE_VERSION 1 /** * @ingroup iface_org_kde_plasma_activation_feedback */ #define ORG_KDE_PLASMA_ACTIVATION_FEEDBACK_DESTROY_SINCE_VERSION 1 /** @ingroup iface_org_kde_plasma_activation_feedback */ static inline void org_kde_plasma_activation_feedback_set_user_data(struct org_kde_plasma_activation_feedback *org_kde_plasma_activation_feedback, void *user_data) { wl_proxy_set_user_data((struct wl_proxy *) org_kde_plasma_activation_feedback, user_data); } /** @ingroup iface_org_kde_plasma_activation_feedback */ static inline void * org_kde_plasma_activation_feedback_get_user_data(struct org_kde_plasma_activation_feedback *org_kde_plasma_activation_feedback) { return wl_proxy_get_user_data((struct wl_proxy *) org_kde_plasma_activation_feedback); } static inline uint32_t org_kde_plasma_activation_feedback_get_version(struct org_kde_plasma_activation_feedback *org_kde_plasma_activation_feedback) { return wl_proxy_get_version((struct wl_proxy *) org_kde_plasma_activation_feedback); } /** * @ingroup iface_org_kde_plasma_activation_feedback * * Destroy the activation manager object. The activation objects introduced * by this manager object will be unaffected. */ static inline void org_kde_plasma_activation_feedback_destroy(struct org_kde_plasma_activation_feedback *org_kde_plasma_activation_feedback) { wl_proxy_marshal_flags((struct wl_proxy *) org_kde_plasma_activation_feedback, ORG_KDE_PLASMA_ACTIVATION_FEEDBACK_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) org_kde_plasma_activation_feedback), WL_MARSHAL_FLAG_DESTROY); } /** * @ingroup iface_org_kde_plasma_activation * @struct org_kde_plasma_activation_listener */ struct org_kde_plasma_activation_listener { /** * Offers the app_id * * * @param app_id application id, as described in xdg_activation_v1 */ void (*app_id)(void *data, struct org_kde_plasma_activation *org_kde_plasma_activation, const char *app_id); /** * Notifies about activation finished, either by activation or because it got invalidated * * */ void (*finished)(void *data, struct org_kde_plasma_activation *org_kde_plasma_activation); }; /** * @ingroup iface_org_kde_plasma_activation */ static inline int org_kde_plasma_activation_add_listener(struct org_kde_plasma_activation *org_kde_plasma_activation, const struct org_kde_plasma_activation_listener *listener, void *data) { return wl_proxy_add_listener((struct wl_proxy *) org_kde_plasma_activation, (void (**)(void)) listener, data); } #define ORG_KDE_PLASMA_ACTIVATION_DESTROY 0 /** * @ingroup iface_org_kde_plasma_activation */ #define ORG_KDE_PLASMA_ACTIVATION_APP_ID_SINCE_VERSION 1 /** * @ingroup iface_org_kde_plasma_activation */ #define ORG_KDE_PLASMA_ACTIVATION_FINISHED_SINCE_VERSION 1 /** * @ingroup iface_org_kde_plasma_activation */ #define ORG_KDE_PLASMA_ACTIVATION_DESTROY_SINCE_VERSION 1 /** @ingroup iface_org_kde_plasma_activation */ static inline void org_kde_plasma_activation_set_user_data(struct org_kde_plasma_activation *org_kde_plasma_activation, void *user_data) { wl_proxy_set_user_data((struct wl_proxy *) org_kde_plasma_activation, user_data); } /** @ingroup iface_org_kde_plasma_activation */ static inline void * org_kde_plasma_activation_get_user_data(struct org_kde_plasma_activation *org_kde_plasma_activation) { return wl_proxy_get_user_data((struct wl_proxy *) org_kde_plasma_activation); } static inline uint32_t org_kde_plasma_activation_get_version(struct org_kde_plasma_activation *org_kde_plasma_activation) { return wl_proxy_get_version((struct wl_proxy *) org_kde_plasma_activation); } /** * @ingroup iface_org_kde_plasma_activation * * Notify the compositor that the org_kde_plasma_activation object will no * longer be used. */ static inline void org_kde_plasma_activation_destroy(struct org_kde_plasma_activation *org_kde_plasma_activation) { wl_proxy_marshal_flags((struct wl_proxy *) org_kde_plasma_activation, ORG_KDE_PLASMA_ACTIVATION_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) org_kde_plasma_activation), WL_MARSHAL_FLAG_DESTROY); } #ifdef __cplusplus } #endif #endif libkysdk-applications/kysdk-waylandhelper/src/windowmanager/ukuiwindowmanagement.cpp0000664000175000017500000007646615104543305030404 0ustar fengfeng/* * libkysdk-waylandhelper's Library * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #include "ukuiwindowmanagement.h" #include "ukui-window-management-client-protocol.h" #include "ukuiwaylandpointer.h" #include #include #include #include #include #include class Q_DECL_HIDDEN UkuiWindowManagement::Private { public: Private(UkuiWindowManagement *q); UkuiWaylandPointer wm; EventQueue *queue = nullptr; bool showingDesktop = false; QList windows; UkuiWindow *activeWindow = nullptr; QVector stackingOrder; QVector stackingOrderUuids; void setup(ukui_window_management *wm); private: static void showDesktopCallback(void *data, ukui_window_management *ukui_window_management, uint32_t state); static void windowCallback(void *data, struct ukui_window_management *ukui_window_management, const char *uuid); static void windowWithUuidCallback(void *data, struct ukui_window_management *ukui_window_management, uint32_t id, const char *uuid); static void stackingOrderUuidsCallback(void *data, struct ukui_window_management *ukui_window_management, const char *uuids); void setShowDesktop(bool set); void windowCreated(ukui_window *id, quint32 internalId, const char *uuid); void setStackingOrder(const QVector &ids); void setStackingOrder(const QVector &uuids); static struct ukui_window_management_listener s_listener; UkuiWindowManagement *q; }; class Q_DECL_HIDDEN UkuiWindow::Private { public: Private(ukui_window *window, quint32 internalId, const char *uuid, UkuiWindow *q); UkuiWaylandPointer window; quint32 internalId; ///< @deprecated QByteArray uuid; QString title; QString appId; quint32 desktop = 0; bool active = false; bool minimized = false; bool maximized = false; bool fullscreen = false; bool keepAbove = false; bool keepBelow = false; bool onAllDesktops = false; bool demandsAttention = false; bool closeable = false; bool minimizeable = false; bool maximizeable = false; bool fullscreenable = false; bool skipTaskbar = false; bool skipSwitcher = false; bool shadeable = false; bool shaded = false; bool movable = false; bool resizable = false; bool acceptFocus = false; bool modality = false; bool virtualDesktopChangeable = false; QIcon icon; UkuiWindowManagement *wm = nullptr; bool unmapped = false; QPointer parentWindow; QMetaObject::Connection parentWindowUnmappedConnection; QStringList ukuiVirtualDesktops; QStringList ukuiActivities; QRect geometry; quint32 pid = 0; QString applicationMenuServiceName; QString applicationMenuObjectPath; bool highlight = false; private: static void titleChangedCallback(void *data, ukui_window *window, const char *title); static void appIdChangedCallback(void *data, ukui_window *window, const char *app_id); static void pidChangedCallback(void *data, ukui_window *window, uint32_t pid); static void stateChangedCallback(void *data, ukui_window *window, uint32_t state); static void themedIconNameChangedCallback(void *data, ukui_window *window, const char *name); static void unmappedCallback(void *data, ukui_window *window); static void initialStateCallback(void *data, ukui_window *window); static void parentWindowCallback(void *data, ukui_window *window, ukui_window *parent); static void windowGeometryCallback(void *data, ukui_window *window, int32_t x, int32_t y, uint32_t width, uint32_t height); static void iconChangedCallback(void *data, ukui_window *ukui_window); static void virtualDesktopEnteredCallback(void *data, ukui_window *ukui_window, const char *id); static void virtualDesktopLeftCallback(void *data, ukui_window *ukui_window, const char *id); static void appmenuChangedCallback(void *data, ukui_window *ukui_window, const char *service_name, const char *object_path); static void activityEnteredCallback(void *data, ukui_window *ukui_window, const char *id); static void activityLeftCallback(void *data, ukui_window *ukui_window, const char *id); void setActive(bool set); void setMinimized(bool set); void setMaximized(bool set); void setFullscreen(bool set); void setKeepAbove(bool set); void setKeepBelow(bool set); void setOnAllDesktops(bool set); void setDemandsAttention(bool set); void setCloseable(bool set); void setMinimizeable(bool set); void setMaximizeable(bool set); void setFullscreenable(bool set); void setSkipTaskbar(bool skip); void setSkipSwitcher(bool skip); void setShadeable(bool set); void setShaded(bool set); void setMovable(bool set); void setResizable(bool set); void setVirtualDesktopChangeable(bool set); void setAcceptFocus(bool set); void setModality(bool set); void setParentWindow(UkuiWindow *parentWindow); void setPid(const quint32 pid); static Private *cast(void *data) { return reinterpret_cast(data); } UkuiWindow *q; static struct ukui_window_listener s_listener; }; UkuiWindowManagement::Private::Private(UkuiWindowManagement *q) : q(q) { } ukui_window_management_listener UkuiWindowManagement::Private::s_listener = { .show_desktop_changed = showDesktopCallback, .stacking_order_changed = stackingOrderUuidsCallback, .window_created = windowCallback, }; void UkuiWindowManagement::Private::setup(ukui_window_management *windowManagement) { Q_ASSERT(!wm); Q_ASSERT(windowManagement); wm.setup(windowManagement); ukui_window_management_add_listener(windowManagement, &s_listener, this); } void UkuiWindowManagement::Private::showDesktopCallback(void *data, ukui_window_management *ukui_window_management, uint32_t state) { auto wm = reinterpret_cast(data); Q_ASSERT(wm->wm == ukui_window_management); switch (state) { case UKUI_WINDOW_MANAGEMENT_SHOW_DESKTOP_ENABLED: wm->setShowDesktop(true); break; case UKUI_WINDOW_MANAGEMENT_SHOW_DESKTOP_DISABLED: wm->setShowDesktop(false); break; default: Q_UNREACHABLE(); break; } } void UkuiWindowManagement::Private::setShowDesktop(bool set) { if (showingDesktop == set) { return; } showingDesktop = set; Q_EMIT q->showingDesktopChanged(showingDesktop); } void UkuiWindowManagement::Private::windowCallback(void *data, ukui_window_management *interface, const char *_uuid) { QByteArray uuid(_uuid); auto wm = reinterpret_cast(data); Q_ASSERT(wm->wm == interface); QTimer *timer = new QTimer(); timer->setSingleShot(true); timer->setInterval(0); QObject::connect( timer, &QTimer::timeout, wm->q, [timer, wm, uuid] { // internalId 不用了,以uuid为唯一标识 wm->windowCreated(ukui_window_management_create_window(wm->wm, uuid), 0, uuid); timer->deleteLater(); }, Qt::QueuedConnection); timer->start(); } // not used void UkuiWindowManagement::Private::windowWithUuidCallback(void *data, ukui_window_management *interface, uint32_t id, const char *_uuid) { QByteArray uuid(_uuid); auto wm = reinterpret_cast(data); Q_ASSERT(wm->wm == interface); QTimer *timer = new QTimer(); timer->setSingleShot(true); timer->setInterval(0); QObject::connect( timer, &QTimer::timeout, wm->q, [timer, wm, id, uuid] { wm->windowCreated(ukui_window_management_create_window(wm->wm, uuid), id, uuid); timer->deleteLater(); }, Qt::QueuedConnection); timer->start(); } void UkuiWindowManagement::Private::windowCreated(ukui_window *id, quint32 internalId, const char *uuid) { if (queue) { queue->addProxy(id); } UkuiWindow *window = new UkuiWindow(q, id, internalId, uuid); window->d->wm = q; windows << window; const auto windowRemoved = [this, window] { windows.removeAll(window); if (activeWindow == window) { activeWindow = nullptr; Q_EMIT q->activeWindowChanged(); } }; QObject::connect(window, &QObject::destroyed, q, windowRemoved); QObject::connect(window, &UkuiWindow::unmapped, q, windowRemoved); QObject::connect(window, &UkuiWindow::activeChanged, q, [this, window] { if (window->d->unmapped) { return; } if (window->isActive()) { if (activeWindow == window) { return; } activeWindow = window; Q_EMIT q->activeWindowChanged(); } else { if (activeWindow == window) { activeWindow = nullptr; Q_EMIT q->activeWindowChanged(); } } }); } void UkuiWindowManagement::Private::stackingOrderUuidsCallback(void *data, ukui_window_management *interface, const char *uuids) { auto wm = reinterpret_cast(data); Q_ASSERT(wm->wm == interface); wm->setStackingOrder(QByteArray(uuids).split(';').toVector()); } void UkuiWindowManagement::Private::setStackingOrder(const QVector &ids) { if (stackingOrder == ids) { return; } stackingOrder = ids; Q_EMIT q->stackingOrderChanged(); } void UkuiWindowManagement::Private::setStackingOrder(const QVector &uuids) { if (stackingOrderUuids == uuids) { return; } stackingOrderUuids = uuids; Q_EMIT q->stackingOrderUuidsChanged(); } UkuiWindowManagement::UkuiWindowManagement(QObject *parent) : QObject(parent) , d(new Private(this)) { } UkuiWindowManagement::~UkuiWindowManagement() { release(); } void UkuiWindowManagement::destroy() { if (!d->wm) { return; } Q_EMIT interfaceAboutToBeDestroyed(); d->wm.destroy(); } void UkuiWindowManagement::release() { if (!d->wm) { return; } Q_EMIT interfaceAboutToBeReleased(); d->wm.release(); } void UkuiWindowManagement::setup(ukui_window_management *wm) { d->setup(wm); } void UkuiWindowManagement::setEventQueue(EventQueue *queue) { d->queue = queue; } EventQueue *UkuiWindowManagement::eventQueue() { return d->queue; } bool UkuiWindowManagement::isValid() const { return d->wm.isValid(); } UkuiWindowManagement::operator ukui_window_management *() { return d->wm; } UkuiWindowManagement::operator ukui_window_management *() const { return d->wm; } void UkuiWindowManagement::hideDesktop() { setShowingDesktop(false); } void UkuiWindowManagement::showDesktop() { setShowingDesktop(true); } void UkuiWindowManagement::setShowingDesktop(bool show) { ukui_window_management_show_desktop(d->wm, show ? UKUI_WINDOW_MANAGEMENT_SHOW_DESKTOP_ENABLED : UKUI_WINDOW_MANAGEMENT_SHOW_DESKTOP_DISABLED); } bool UkuiWindowManagement::isShowingDesktop() const { return d->showingDesktop; } QList UkuiWindowManagement::windows() const { return d->windows; } UkuiWindow *UkuiWindowManagement::activeWindow() const { return d->activeWindow; } QVector UkuiWindowManagement::stackingOrder() const { return d->stackingOrder; } QVector UkuiWindowManagement::stackingOrderUuids() const { return d->stackingOrderUuids; } ukui_window_listener UkuiWindow::Private::s_listener = { .title_changed = titleChangedCallback, .app_id_changed = appIdChangedCallback, .state_changed = stateChangedCallback, .themed_icon_name_changed = themedIconNameChangedCallback, .unmapped = unmappedCallback, .initial_state = initialStateCallback, .parent_window = parentWindowCallback, .geometry = windowGeometryCallback, .icon_changed = iconChangedCallback, .pid_changed = pidChangedCallback, .virtual_desktop_entered = virtualDesktopEnteredCallback, .virtual_desktop_left = virtualDesktopLeftCallback, .application_menu = appmenuChangedCallback, .activity_entered = activityEnteredCallback, .activity_left = activityLeftCallback}; void UkuiWindow::Private::appmenuChangedCallback(void *data, ukui_window *window, const char *service_name, const char *object_path) { Q_UNUSED(window) Private *p = cast(data); p->applicationMenuServiceName = QString::fromUtf8(service_name); p->applicationMenuObjectPath = QString::fromUtf8(object_path); Q_EMIT p->q->applicationMenuChanged(); } void UkuiWindow::Private::parentWindowCallback(void *data, ukui_window *window, ukui_window *parent) { Q_UNUSED(window) Private *p = cast(data); const auto windows = p->wm->windows(); auto it = std::find_if(windows.constBegin(), windows.constEnd(), [parent](const UkuiWindow *w) { return *w == parent; }); p->setParentWindow(it != windows.constEnd() ? *it : nullptr); } void UkuiWindow::Private::windowGeometryCallback(void *data, ukui_window *window, int32_t x, int32_t y, uint32_t width, uint32_t height) { Q_UNUSED(window) Private *p = cast(data); QRect geo(x, y, width, height); if (geo == p->geometry) { return; } p->geometry = geo; Q_EMIT p->q->geometryChanged(); } void UkuiWindow::Private::setParentWindow(UkuiWindow *parent) { const auto old = parentWindow; QObject::disconnect(parentWindowUnmappedConnection); if (parent && !parent->d->unmapped) { parentWindow = QPointer(parent); parentWindowUnmappedConnection = QObject::connect(parent, &UkuiWindow::unmapped, q, [this] { setParentWindow(nullptr); }); } else { parentWindow = QPointer(); parentWindowUnmappedConnection = QMetaObject::Connection(); } if (parentWindow.data() != old.data()) { Q_EMIT q->parentWindowChanged(); } } void UkuiWindow::Private::initialStateCallback(void *data, ukui_window *window) { Q_UNUSED(window) Private *p = cast(data); if (!p->unmapped) { Q_EMIT p->wm->windowCreated(p->q); } } void UkuiWindow::Private::titleChangedCallback(void *data, ukui_window *window, const char *title) { Q_UNUSED(window) Private *p = cast(data); const QString t = QString::fromUtf8(title); if (p->title == t) { return; } p->title = t; Q_EMIT p->q->titleChanged(); } void UkuiWindow::Private::appIdChangedCallback(void *data, ukui_window *window, const char *appId) { Q_UNUSED(window) Private *p = cast(data); const QString s = QString::fromUtf8(appId); if (s == p->appId) { return; } p->appId = s; Q_EMIT p->q->appIdChanged(); } void UkuiWindow::Private::pidChangedCallback(void *data, ukui_window *window, uint32_t pid) { Q_UNUSED(window) Private *p = cast(data); if (p->pid == static_cast(pid)) { return; } p->pid = pid; } void UkuiWindow::Private::unmappedCallback(void *data, ukui_window *window) { auto p = cast(data); Q_UNUSED(window); p->unmapped = true; Q_EMIT p->q->unmapped(); p->q->deleteLater(); } void UkuiWindow::Private::virtualDesktopEnteredCallback(void *data, ukui_window *window, const char *id) { auto p = cast(data); Q_UNUSED(window); const QString stringId(QString::fromUtf8(id)); p->ukuiVirtualDesktops << stringId; Q_EMIT p->q->ukuiVirtualDesktopEntered(stringId); if (p->ukuiVirtualDesktops.count() == 1) { Q_EMIT p->q->onAllDesktopsChanged(); } } void UkuiWindow::Private::virtualDesktopLeftCallback(void *data, ukui_window *window, const char *id) { auto p = cast(data); Q_UNUSED(window); const QString stringId(QString::fromUtf8(id)); p->ukuiVirtualDesktops.removeAll(stringId); Q_EMIT p->q->ukuiVirtualDesktopLeft(stringId); if (p->ukuiVirtualDesktops.isEmpty()) { Q_EMIT p->q->onAllDesktopsChanged(); } } void UkuiWindow::Private::activityEnteredCallback(void *data, ukui_window *window, const char *id) { auto p = cast(data); Q_UNUSED(window); const QString stringId(QString::fromUtf8(id)); p->ukuiActivities << stringId; Q_EMIT p->q->ukuiActivityEntered(stringId); } void UkuiWindow::Private::activityLeftCallback(void *data, ukui_window *window, const char *id) { auto p = cast(data); Q_UNUSED(window); const QString stringId(QString::fromUtf8(id)); p->ukuiActivities.removeAll(stringId); Q_EMIT p->q->ukuiActivityLeft(stringId); } void UkuiWindow::Private::stateChangedCallback(void *data, ukui_window *window, uint32_t state) { auto p = cast(data); Q_UNUSED(window); p->setActive(state & UKUI_WINDOW_STATE_ACTIVE); p->setMinimized(state & UKUI_WINDOW_STATE_MINIMIZED); p->setMaximized(state & UKUI_WINDOW_STATE_MAXIMIZED); p->setFullscreen(state & UKUI_WINDOW_STATE_FULLSCREEN); p->setKeepAbove(state & UKUI_WINDOW_STATE_KEEP_ABOVE); p->setKeepBelow(state & UKUI_WINDOW_STATE_KEEP_BELOW); p->setOnAllDesktops(state & UKUI_WINDOW_STATE_ON_ALL_DESKTOPS); p->setDemandsAttention(state & UKUI_WINDOW_STATE_DEMANDS_ATTENTION); p->setCloseable(state & UKUI_WINDOW_STATE_CLOSEABLE); p->setFullscreenable(state & UKUI_WINDOW_STATE_FULLSCREENABLE); p->setMaximizeable(state & UKUI_WINDOW_STATE_MAXIMIZABLE); p->setMinimizeable(state & UKUI_WINDOW_STATE_MINIMIZABLE); p->setSkipTaskbar(state & UKUI_WINDOW_STATE_SKIPTASKBAR); p->setSkipSwitcher(state & UKUI_WINDOW_STATE_SKIPSWITCHER); p->setShadeable(state & UKUI_WINDOW_STATE_SHADEABLE); p->setShaded(state & UKUI_WINDOW_STATE_SHADED); p->setMovable(state & UKUI_WINDOW_STATE_MOVABLE); p->setResizable(state & UKUI_WINDOW_STATE_RESIZABLE); p->setVirtualDesktopChangeable(state & UKUI_WINDOW_STATE_VIRTUAL_DESKTOP_CHANGEABLE); } void UkuiWindow::Private::themedIconNameChangedCallback(void *data, ukui_window *window, const char *name) { auto p = cast(data); Q_UNUSED(window); const QString themedName = QString::fromUtf8(name); if (!themedName.isEmpty()) { QIcon icon = QIcon::fromTheme(themedName); p->icon = icon; } else { p->icon = QIcon(); } Q_EMIT p->q->iconChanged(); } static int readData(int fd, QByteArray &data) { char buf[4096]; int retryCount = 0; int n; while (true) { n = read(fd, buf, 4096); if (n == -1 && (errno == EAGAIN) && ++retryCount < 1000) { usleep(1000); } else { break; } } if (n > 0) { data.append(buf, n); n = readData(fd, data); } return n; } void UkuiWindow::Private::iconChangedCallback(void *data, ukui_window *window) { auto p = cast(data); Q_UNUSED(window); int pipeFds[2]; if (pipe2(pipeFds, O_CLOEXEC | O_NONBLOCK) != 0) { return; } ukui_window_get_icon(p->window, pipeFds[1]); close(pipeFds[1]); const int pipeFd = pipeFds[0]; auto readIcon = [pipeFd]() -> QIcon { QByteArray content; if (readData(pipeFd, content) != 0) { close(pipeFd); return QIcon(); } close(pipeFd); if (qgetenv("XDG_SESSION_DESKTOP") == QString("kylin-wlcom")) { int width = (content.at(0) << 0) | (content.at(1) << 8) | (content.at(2) << 16) | (content.at(3) << 24); int height = (content.at(4) << 0) | (content.at(5) << 8) | (content.at(6) << 16) | (content.at(7) << 24); if (content.size() - 8 != width * height * 4) { return QIcon(); } QImage image(width, height, QImage::Format_ARGB32); memcpy(image.bits(), content.constData() + 8, content.size() - 8); QIcon icon = QIcon(QPixmap::fromImage(image)); return icon; } else { QDataStream ds(content); QIcon icon; ds >> icon; return icon; } }; QFutureWatcher *watcher = new QFutureWatcher(p->q); QObject::connect(watcher, &QFutureWatcher::finished, p->q, [p, watcher] { watcher->deleteLater(); QIcon icon = watcher->result(); if (!icon.isNull()) { p->icon = icon; } else { p->icon = QIcon::fromTheme(QStringLiteral("wayland")); } Q_EMIT p->q->iconChanged(); }); watcher->setFuture(QtConcurrent::run(readIcon)); } void UkuiWindow::Private::setActive(bool set) { if (active == set) { return; } active = set; Q_EMIT q->activeChanged(); } void UkuiWindow::Private::setFullscreen(bool set) { if (fullscreen == set) { return; } fullscreen = set; Q_EMIT q->fullscreenChanged(); } void UkuiWindow::Private::setKeepAbove(bool set) { if (keepAbove == set) { return; } keepAbove = set; Q_EMIT q->keepAboveChanged(); } void UkuiWindow::Private::setKeepBelow(bool set) { if (keepBelow == set) { return; } keepBelow = set; Q_EMIT q->keepBelowChanged(); } void UkuiWindow::Private::setMaximized(bool set) { if (maximized == set) { return; } maximized = set; Q_EMIT q->maximizedChanged(); } void UkuiWindow::Private::setMinimized(bool set) { if (minimized == set) { return; } minimized = set; Q_EMIT q->minimizedChanged(); } void UkuiWindow::Private::setOnAllDesktops(bool set) { if (onAllDesktops == set) { return; } onAllDesktops = set; Q_EMIT q->onAllDesktopsChanged(); } void UkuiWindow::Private::setDemandsAttention(bool set) { if (demandsAttention == set) { return; } demandsAttention = set; Q_EMIT q->demandsAttentionChanged(); } void UkuiWindow::Private::setCloseable(bool set) { if (closeable == set) { return; } closeable = set; Q_EMIT q->closeableChanged(); } void UkuiWindow::Private::setFullscreenable(bool set) { if (fullscreenable == set) { return; } fullscreenable = set; Q_EMIT q->fullscreenableChanged(); } void UkuiWindow::Private::setMaximizeable(bool set) { if (maximizeable == set) { return; } maximizeable = set; Q_EMIT q->maximizeableChanged(); } void UkuiWindow::Private::setMinimizeable(bool set) { if (minimizeable == set) { return; } minimizeable = set; Q_EMIT q->minimizeableChanged(); } void UkuiWindow::Private::setSkipTaskbar(bool skip) { if (skipTaskbar == skip) { return; } skipTaskbar = skip; Q_EMIT q->skipTaskbarChanged(); } void UkuiWindow::Private::setSkipSwitcher(bool skip) { if (skipSwitcher == skip) { return; } skipSwitcher = skip; Q_EMIT q->skipSwitcherChanged(); } void UkuiWindow::Private::setShadeable(bool set) { if (shadeable == set) { return; } shadeable = set; Q_EMIT q->shadeableChanged(); } void UkuiWindow::Private::setShaded(bool set) { if (shaded == set) { return; } shaded = set; Q_EMIT q->shadedChanged(); } void UkuiWindow::Private::setMovable(bool set) { if (movable == set) { return; } movable = set; Q_EMIT q->movableChanged(); } void UkuiWindow::Private::setResizable(bool set) { if (resizable == set) { return; } resizable = set; Q_EMIT q->resizableChanged(); } void UkuiWindow::Private::setVirtualDesktopChangeable(bool set) { if (virtualDesktopChangeable == set) { return; } virtualDesktopChangeable = set; Q_EMIT q->virtualDesktopChangeableChanged(); } void UkuiWindow::Private::setAcceptFocus(bool set) { if (acceptFocus == set) { return; } acceptFocus = set; Q_EMIT q->acceptFocusChanged(); } void UkuiWindow::Private::setModality(bool set) { if (modality == set) { return; } modality = set; Q_EMIT q->modalityChanged(); } UkuiWindow::Private::Private(ukui_window *w, quint32 internalId, const char *uuid, UkuiWindow *q) : internalId(internalId) , uuid(uuid) , q(q) { Q_ASSERT(!this->uuid.isEmpty()); window.setup(w); ukui_window_add_listener(w, &s_listener, this); } UkuiWindow::UkuiWindow(UkuiWindowManagement *parent, ukui_window *window, quint32 internalId, const char *uuid) : QObject(parent) , d(new Private(window, internalId, uuid, this)) { } UkuiWindow::~UkuiWindow() { release(); } void UkuiWindow::destroy() { d->window.destroy(); } void UkuiWindow::release() { d->window.release(); } bool UkuiWindow::isValid() const { return d->window.isValid(); } UkuiWindow::operator ukui_window *() const { return d->window; } UkuiWindow::operator ukui_window *() { return d->window; } QString UkuiWindow::appId() const { return d->appId; } quint32 UkuiWindow::pid() const { return d->pid; } QString UkuiWindow::title() const { return d->title; } quint32 UkuiWindow::virtualDesktop() const { return d->desktop; } bool UkuiWindow::isActive() const { return d->active; } bool UkuiWindow::isFullscreen() const { return d->fullscreen; } bool UkuiWindow::isKeepAbove() const { return d->keepAbove; } bool UkuiWindow::isKeepBelow() const { return d->keepBelow; } bool UkuiWindow::isMaximized() const { return d->maximized; } bool UkuiWindow::isMinimized() const { return d->minimized; } bool UkuiWindow::isOnAllDesktops() const { if (ukui_window_get_version(d->window) < 8) { return d->onAllDesktops; } else { return d->ukuiVirtualDesktops.isEmpty(); } } bool UkuiWindow::isDemandingAttention() const { return d->demandsAttention; } bool UkuiWindow::isCloseable() const { return d->closeable; } bool UkuiWindow::isFullscreenable() const { return d->fullscreenable; } bool UkuiWindow::isMaximizeable() const { return d->maximizeable; } bool UkuiWindow::isMinimizeable() const { return d->minimizeable; } bool UkuiWindow::skipTaskbar() const { return d->skipTaskbar; } bool UkuiWindow::skipSwitcher() const { return d->skipSwitcher; } QIcon UkuiWindow::icon() const { return d->icon; } bool UkuiWindow::isShadeable() const { return d->shadeable; } bool UkuiWindow::isShaded() const { return d->shaded; } bool UkuiWindow::isResizable() const { return d->resizable; } bool UkuiWindow::isMovable() const { return d->movable; } bool UkuiWindow::isVirtualDesktopChangeable() const { return d->virtualDesktopChangeable; } QString UkuiWindow::applicationMenuObjectPath() const { return d->applicationMenuObjectPath; } QString UkuiWindow::applicationMenuServiceName() const { return d->applicationMenuServiceName; } void UkuiWindow::requestActivate() { ukui_window_set_state(d->window, UKUI_WINDOW_STATE_ACTIVE, UKUI_WINDOW_STATE_ACTIVE); } void UkuiWindow::requestClose() { ukui_window_close(d->window); } void UkuiWindow::requestMove() { ukui_window_request_move(d->window); } void UkuiWindow::requestResize() { ukui_window_request_resize(d->window); } void UkuiWindow::requestVirtualDesktop(quint32 desktop) { // not used } void UkuiWindow::requestToggleKeepAbove() { if (d->keepAbove) { ukui_window_set_state(d->window, UKUI_WINDOW_STATE_KEEP_ABOVE, 0); } else { ukui_window_set_state(d->window, UKUI_WINDOW_STATE_KEEP_ABOVE, UKUI_WINDOW_STATE_KEEP_ABOVE); } } void UkuiWindow::requestDemandAttention() { if (d->demandsAttention) { ukui_window_set_state(d->window, UKUI_WINDOW_STATE_DEMANDS_ATTENTION, 0); } else { ukui_window_set_state(d->window, UKUI_WINDOW_STATE_DEMANDS_ATTENTION, UKUI_WINDOW_STATE_DEMANDS_ATTENTION); } } void UkuiWindow::requestToggleKeepBelow() { if (d->keepBelow) { ukui_window_set_state(d->window, UKUI_WINDOW_STATE_KEEP_BELOW, 0); } else { ukui_window_set_state(d->window, UKUI_WINDOW_STATE_KEEP_BELOW, UKUI_WINDOW_STATE_KEEP_BELOW); } } void UkuiWindow::requestToggleMinimized() { if (d->minimized) { ukui_window_set_state(d->window, UKUI_WINDOW_STATE_MINIMIZED, 0); } else { ukui_window_set_state(d->window, UKUI_WINDOW_STATE_MINIMIZED, UKUI_WINDOW_STATE_MINIMIZED); } } void UkuiWindow::requestToggleMaximized() { if (d->maximized) { ukui_window_set_state(d->window, UKUI_WINDOW_STATE_MAXIMIZED, 0); } else { ukui_window_set_state(d->window, UKUI_WINDOW_STATE_MAXIMIZED, UKUI_WINDOW_STATE_MAXIMIZED); } } void UkuiWindow::setStartupGeometry(Surface *surface, const QRect &geometry) { ukui_window_set_startup_geometry(d->window, *surface, geometry.x(), geometry.y(), geometry.width(), geometry.height()); } void UkuiWindow::setMinimizedGeometry(Surface *panel, const QRect &geom) { ukui_window_set_minimized_geometry(d->window, *panel, geom.x(), geom.y(), geom.width(), geom.height()); } void UkuiWindow::unsetMinimizedGeometry(Surface *panel) { ukui_window_unset_minimized_geometry(d->window, *panel); } void UkuiWindow::requestToggleShaded() { if (d->shaded) { ukui_window_set_state(d->window, UKUI_WINDOW_STATE_SHADED, 0); } else { ukui_window_set_state(d->window, UKUI_WINDOW_STATE_SHADED, UKUI_WINDOW_STATE_SHADED); } } quint32 UkuiWindow::internalId() const { return d->internalId; } QByteArray UkuiWindow::uuid() const { return d->uuid; } QPointer UkuiWindow::parentWindow() const { return d->parentWindow; } QRect UkuiWindow::geometry() const { return d->geometry; } void UkuiWindow::requestEnterVirtualDesktop(const QString &id) { ukui_window_request_enter_virtual_desktop(d->window, id.toUtf8()); } void UkuiWindow::requestEnterNewVirtualDesktop() { ukui_window_request_enter_new_virtual_desktop(d->window); } void UkuiWindow::requestLeaveVirtualDesktop(const QString &id) { ukui_window_request_leave_virtual_desktop(d->window, id.toUtf8()); } QStringList UkuiWindow::ukuiVirtualDesktops() const { return d->ukuiVirtualDesktops; } void UkuiWindow::requestEnterActivity(const QString &id) { ukui_window_request_enter_activity(d->window, id.toUtf8()); } void UkuiWindow::requestLeaveActivity(const QString &id) { ukui_window_request_leave_activity(d->window, id.toUtf8()); } QStringList UkuiWindow::ukuiActivities() const { return d->ukuiActivities; } void UkuiWindow::sendToOutput(KWayland::Client::Output *output) const { if (ukui_window_get_version(d->window) >= UKUI_WINDOW_SEND_TO_OUTPUT_SINCE_VERSION) { ukui_window_send_to_output(d->window, *output); } } void UkuiWindow::setHighlight() { if (d->highlight) return; ukui_window_highlight(d->window); d->highlight = true; } void UkuiWindow::unsetHightlight() { if (!d->highlight) return; ukui_window_unset_highlight(d->window); d->highlight = false; } bool UkuiWindow::isHighlight() { return d->highlight; } libkysdk-applications/kysdk-waylandhelper/src/windowmanager/abstractinterface.h0000664000175000017500000001335315104543305027255 0ustar fengfeng/* * libkysdk-waylandhelper's Library * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #ifndef ABSTRACTINTERFACE_H #define ABSTRACTINTERFACE_H #include "netwm.h" #include "outputinfo.h" #include "windowinfo.h" #include #include #include /** * @since 1.2.0 */ namespace kdk { using WindowId = QVariant; class KWindows; enum class WindowLayer { Normal, Desktop, Panel, OnScreenDisplay, Notification, ToolTip, CriticalNotification, AppletPop, ScreenLock, Watermark, SystemWindow, InputPanel, Logout, ScreenLockNotification, Switcher, Authentication }; class AbstractInterface : public QObject { Q_OBJECT public: AbstractInterface(QObject *parent = nullptr); virtual ~AbstractInterface(); virtual WindowInfo requestInfo(WindowId wid) = 0; virtual void requestActivate(WindowId wid) = 0; virtual void requestClose(WindowId wid) = 0; virtual void requestToggleKeepAbove(WindowId wid) = 0; virtual void requestToggleMinimized(WindowId wid) = 0; virtual void requestToggleMaximized(WindowId wid) = 0; virtual WindowId activeWindow() = 0; virtual QIcon iconFor(WindowId wid) = 0; virtual QString titleFor(WindowId wid) = 0; virtual QString windowGroupFor(WindowId wid) = 0; virtual bool windowCanBeDragged(WindowId wid) = 0; virtual bool windowCanBeMaximized(WindowId wid) = 0; virtual void showCurrentDesktop() = 0; virtual void hideCurrentDesktop() = 0; virtual quint32 pid(WindowId wid) = 0; virtual void setGeometry(QWindow *window, const QRect &rect) = 0; virtual NET::WindowType windowType(WindowId wid) = 0; virtual void setSkipTaskBar(QWindow *window, bool skip) = 0; virtual void setSkipSwitcher(QWindow *window, bool skip) = 0; virtual bool skipTaskBar(const WindowId &wid) = 0; virtual bool skipSwitcher(const WindowId &wid) = 0; virtual bool isShowingDesktop() = 0; virtual void setOnAllDesktops(const WindowId &wid) = 0; bool inCurrentDesktopActivity(const WindowInfo &winfo); bool isPlasmaDesktop(const QRect &wGeometry); QString currentDesktop(); QString currentActivity(); void setPlasmaDesktop(WindowId wid); bool isValidFor(const WindowId &wid); QList windows(); virtual void setPanelTakefocus(QWindow *window, bool flag) = 0; virtual void demandAttention(const WindowId &wid) = 0; virtual QString getProcessName(const WindowId &wid); virtual bool setWindowRadius(QWindow *windowHandle, int radius); virtual void activateWindow(QWindow *window1, QWindow *window2); virtual void setIdleInterval(int msec); virtual QRect windowGeometry(const WindowId &windowId); virtual void setPanelAutoHide(QWindow *window, bool autoHide); virtual void setGrabKeyboard(QWindow *window, bool grabKeyboard); virtual void setWindowLayer(QWindow *window, WindowLayer layer); virtual WindowLayer windowLayer(QWindow *window); virtual void setHighlight(const WindowId &wid, bool highlight); virtual bool istHighlight(const WindowId &wid); virtual void setOpenUnderCursor(QWindow *window); virtual void setOpenUnderCursor(QWindow *window, int x, int y); virtual void setIconName(QWindow *window, const QString &iconName); virtual QString currentSeatName(); virtual QString currentOutputName(); virtual QList outputsInfo(); virtual QList getWindowIdByPid(quint32 pid); virtual QList getWindowIdByTtile(const QString &title); Q_SIGNALS: void activeWindowChanged(WindowId wid); void windowChanged(WindowId winfo); void windowAdded(WindowId wid); void windowRemoved(WindowId wid); void currentDesktopChanged(); void isShowingDesktopChanged(); // since 2.3.1.0 /** * @since 2.3.1.0 */ void titleChanged(WindowId wid); /** * @since 2.3.1.0 */ void iconChanged(WindowId wid); /** * @since 2.3.1.0 */ void activeChanged(WindowId wid); /** * @since 2.3.1.0 */ void fullscreenChanged(WindowId wid); /** * @since 2.3.1.0 */ void keepAboveChanged(WindowId wid); /** * @since 2.3.1.0 */ void minimizedChanged(WindowId wid); /** * @since 2.3.1.0 */ void maximizedChanged(WindowId wid); /** * @since 2.3.1.0 */ void onAllDesktopsChanged(WindowId wid); /** * @since 2.3.1.0 */ void demandsAttentionChanged(WindowId wid); /** * @since 2.3.1.0 */ void skipTaskbarChanged(WindowId wid); /** * @since 2.3.1.0 */ void skipSwitcherChanged(WindowId wid); /** * @since 2.3.1.0 */ void geometryChanged(WindowId wid); /** * @since 2.4.1.0 */ void idled(); /** * @since 2.4.1.0 */ void resumed(); /** * @since 2.5.1.0 */ void outputInfoChanged(OutputInfo *); public: QMap m_windows; QString m_currentDesktop; QString m_currentActivity; }; } #endif // ABSTRACTINTERFACE_H libkysdk-applications/kysdk-waylandhelper/src/windowmanager/windowmanager.cpp0000664000175000017500000002614615104543305026772 0ustar fengfeng/* * libkysdk-waylandhelper's Library * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #include "windowmanager.h" #include #include #include using namespace kdk; static WindowManager *g_windowmanger = nullptr; static WmRegister *m_wm = nullptr; kdk::WindowManager::WindowManager(QObject *parent) : QObject(parent) { m_wm = new WmRegister(this); connect(m_wm->winInterface(), &AbstractInterface::windowAdded, this, &WindowManager::windowAdded); connect(m_wm->winInterface(), &AbstractInterface::windowRemoved, this, &WindowManager::windowRemoved); connect(m_wm->winInterface(), &AbstractInterface::activeWindowChanged, this, &WindowManager::activeWindowChanged); connect(m_wm->winInterface(), &AbstractInterface::windowChanged, this, &WindowManager::windowChanged); connect(m_wm->winInterface(), &AbstractInterface::currentDesktopChanged, this, &WindowManager::currentDesktopChanged); connect(m_wm->winInterface(), &AbstractInterface::isShowingDesktopChanged, this, &WindowManager::isShowingDesktopChanged); connect(m_wm->winInterface(), &AbstractInterface::titleChanged, this, &WindowManager::titleChanged); connect(m_wm->winInterface(), &AbstractInterface::iconChanged, this, &WindowManager::iconChanged); connect(m_wm->winInterface(), &AbstractInterface::activeChanged, this, &WindowManager::activeChanged); connect(m_wm->winInterface(), &AbstractInterface::fullscreenChanged, this, &WindowManager::fullscreenChanged); connect(m_wm->winInterface(), &AbstractInterface::keepAboveChanged, this, &WindowManager::keepAboveChanged); connect(m_wm->winInterface(), &AbstractInterface::minimizedChanged, this, &WindowManager::minimizedChanged); connect(m_wm->winInterface(), &AbstractInterface::maximizedChanged, this, &WindowManager::maximizedChanged); connect(m_wm->winInterface(), &AbstractInterface::onAllDesktopsChanged, this, &WindowManager::onAllDesktopsChanged); connect(m_wm->winInterface(), &AbstractInterface::demandsAttentionChanged, this, &WindowManager::demandsAttentionChanged); connect(m_wm->winInterface(), &AbstractInterface::skipTaskbarChanged, this, &WindowManager::skipTaskbarChanged); connect(m_wm->winInterface(), &AbstractInterface::skipSwitcherChanged, this, &WindowManager::skipSwitcherChanged); connect(m_wm->winInterface(), &AbstractInterface::geometryChanged, this, &WindowManager::geometryChanged); connect(m_wm->winInterface(), &AbstractInterface::outputInfoChanged, this, &WindowManager::outputInfoChanged); } WindowId WindowManager::currentActiveWindow() { self(); if (!m_wm) return QVariant(); return m_wm->winInterface()->activeWindow(); } void WindowManager::keepWindowAbove(const WindowId &windowId) { self(); if (!m_wm) return; m_wm->winInterface()->requestToggleKeepAbove(windowId); } QString WindowManager::getWindowTitle(const WindowId &windowId) { self(); if (!m_wm) return QString(); return m_wm->winInterface()->titleFor(windowId); } QIcon WindowManager::getWindowIcon(const WindowId &windowId) { self(); if (!m_wm) return QIcon(); return m_wm->winInterface()->iconFor(windowId); } QString WindowManager::getWindowGroup(const WindowId &windowId) { if (!m_wm) return QString(); self(); return m_wm->winInterface()->windowGroupFor(windowId); } void WindowManager::closeWindow(const WindowId &windowId) { self(); if (!m_wm) return; m_wm->winInterface()->requestClose(windowId); } void WindowManager::activateWindow(const WindowId &windowId) { self(); if (!m_wm) return; m_wm->winInterface()->requestActivate(windowId); } void WindowManager::maximizeWindow(const WindowId &windowId) { self(); if (!m_wm) return; m_wm->winInterface()->requestToggleMaximized(windowId); } void WindowManager::minimizeWindow(const WindowId &windowId) { self(); if (!m_wm) return; m_wm->winInterface()->requestToggleMinimized(windowId); } quint32 WindowManager::getPid(const WindowId &windowId) { self(); quint32 pid = 0; if (!m_wm) return pid; pid = m_wm->winInterface()->pid(windowId); return pid; } WindowManager *WindowManager::self() { if (g_windowmanger) return g_windowmanger; g_windowmanger = new WindowManager(); return g_windowmanger; } WindowInfo WindowManager::getwindowInfo(const WindowId &windowId) { self(); if (!m_wm) return WindowInfo(); return m_wm->winInterface()->requestInfo(windowId); } void WindowManager::showDesktop() { self(); if (!m_wm) return; m_wm->winInterface()->showCurrentDesktop(); } void WindowManager::hideDesktop() { self(); if (!m_wm) return; m_wm->winInterface()->hideCurrentDesktop(); } QString WindowManager::currentDesktop() { self(); if (!m_wm) return 0; return m_wm->winInterface()->currentDesktop(); } QList WindowManager::windows() { self(); if (!m_wm) return QList(); return m_wm->winInterface()->windows(); } NET::WindowType WindowManager::getWindowType(const WindowId &windowId) { self(); if (!m_wm) return NET::WindowType::Unknown; return m_wm->winInterface()->windowType(windowId); } void WindowManager::setGeometry(QWindow *window, const QRect &rect) { self(); if (!m_wm) return; m_wm->winInterface()->setGeometry(window, rect); } void WindowManager::setSkipTaskBar(QWindow *window, bool skip) { self(); if (!m_wm) return; m_wm->winInterface()->setSkipTaskBar(window, skip); } void WindowManager::setSkipSwitcher(QWindow *window, bool skip) { self(); if (!m_wm) return; m_wm->winInterface()->setSkipSwitcher(window, skip); } bool WindowManager::skipTaskBar(const WindowId &windowId) { self(); if (!m_wm) return false; return m_wm->winInterface()->skipTaskBar(windowId); } bool WindowManager::skipSwitcher(const WindowId &windowId) { self(); if (!m_wm) return false; return m_wm->winInterface()->skipSwitcher(windowId); } bool WindowManager::isShowingDesktop() { self(); if (!m_wm) return false; return m_wm->winInterface()->isShowingDesktop(); } void WindowManager::setOnAllDesktops(const WindowId &windowId) { self(); if (!m_wm) return; m_wm->winInterface()->setOnAllDesktops(windowId); } bool WindowManager::isOnAllDesktops(const WindowId &windowId) { kdk::WindowInfo windowInfo = WindowManager::getwindowInfo(windowId); return windowInfo.isOnAllDesktops(); } bool WindowManager::isOnCurrentDesktop(const WindowId &windowId) { kdk::WindowInfo windowinfo = WindowManager::getwindowInfo(windowId); return windowinfo.isOnDesktop(currentDesktop()); } bool WindowManager::isOnDesktop(const WindowId &windowId, int desktop) { kdk::WindowInfo windowinfo = WindowManager::getwindowInfo(windowId); return windowinfo.isOnDesktop(QString::number(desktop)); } void WindowManager::setPanelTakefocus(QWindow *window, bool flag) { self(); if (!m_wm || !window) return; m_wm->winInterface()->setPanelTakefocus(window, flag); } void WindowManager::demandAttention(const WindowId &wid) { self(); if (!m_wm) return; m_wm->winInterface()->demandAttention(wid); } QString WindowManager::getProcessName(const WindowId &windowId) { self(); if (!m_wm) return QString(); return m_wm->winInterface()->getProcessName(windowId); } void WindowManager::setWindowRadius(QWindow *window, int radius) { self(); if (!m_wm) return; m_wm->winInterface()->setWindowRadius(window, radius); } void WindowManager::activateWindow(QWindow *window1, QWindow *window2) { self(); if (!m_wm) return; m_wm->winInterface()->activateWindow(window1, window2); } QRect WindowManager::windowGeometry(const WindowId &windowId) { self(); if (!m_wm) return QRect(); return m_wm->winInterface()->windowGeometry(windowId); } void WindowManager::setPanelAutoHide(QWindow *window, bool autoHide) { self(); if (!m_wm) return; return m_wm->winInterface()->setPanelAutoHide(window, autoHide); } void WindowManager::setGrabKeyboard(QWindow *window, bool grabKeyboard) { self(); if (!m_wm) return; return m_wm->winInterface()->setGrabKeyboard(window, grabKeyboard); } void WindowManager::setWindowLayer(QWindow *window, WindowLayer layer) { self(); if (!m_wm) return; return m_wm->winInterface()->setWindowLayer(window, layer); } WindowLayer WindowManager::windowLayer(QWindow *window) { self(); if (!m_wm) return WindowLayer::Normal; return m_wm->winInterface()->windowLayer(window); } void WindowManager::setHighlight(const WindowId &wid, bool highlight) { self(); if (!m_wm) return; return m_wm->winInterface()->setHighlight(wid, highlight); } bool WindowManager::isHightlight(const WindowId &wid) { self(); if (!m_wm) return false; return m_wm->winInterface()->istHighlight(wid); } void WindowManager::setOpenUnderCursor(QWindow *window) { self(); if (!m_wm) return; return m_wm->winInterface()->setOpenUnderCursor(window); } void WindowManager::setOpenUnderCursor(QWindow *window, int x, int y) { self(); if (!m_wm) return; return m_wm->winInterface()->setOpenUnderCursor(window, x, y); } void WindowManager::setIconName(QWindow *window, const QString &iconName) { self(); if (!m_wm) return; return m_wm->winInterface()->setIconName(window, iconName); } QString WindowManager::currentSeatName() { self(); if (!m_wm) return QString(); return m_wm->winInterface()->currentSeatName(); } QString WindowManager::currentOutputName() { self(); if (!m_wm) return QString(); return m_wm->winInterface()->currentOutputName(); } QList WindowManager::outputsInfo() { QList list; self(); if (!m_wm) return list; return m_wm->winInterface()->outputsInfo(); } QList WindowManager::getWindowIdByPid(quint32 pid) { QList list; self(); if (!m_wm) return list; return m_wm->winInterface()->getWindowIdByPid(pid); } QList WindowManager::getWindowIdByTtile(const QString &title) { QList list; self(); if (!m_wm) return list; return m_wm->winInterface()->getWindowIdByTtile(title); } libkysdk-applications/kysdk-waylandhelper/src/ukuistylehelper/0000775000175000017500000000000015104543305024007 5ustar fengfenglibkysdk-applications/kysdk-waylandhelper/src/ukuistylehelper/ukuistylehelper.cpp0000664000175000017500000000517315104543305027757 0ustar fengfeng/* * libkysdk-waylandhelper's Library * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #include "ukuistylehelper.h" #include "ukui-decoration-manager.h" #include "ukui-shell-manager.h" #include "waylandhelper.h" #include "windowmanager/ukuiwaylandinterface.h" #include #include #include "xatom-helper.h" namespace kdk { static UkuiStyleHelper *global_instance = nullptr; UkuiStyleHelper *UkuiStyleHelper::self() { if (global_instance) return global_instance; else { global_instance = new UkuiStyleHelper(); return global_instance; } } void UkuiStyleHelper::removeHeader(QWidget *widget) { if (!widget) return; QString platform = QGuiApplication::platformName(); if (platform.startsWith(QLatin1String("wayland"), Qt::CaseInsensitive)) { #ifdef USE_UKUI_SHELL_PLUGIN widget->setProperty("ukui_surface_no_titlebar", true); #else m_widget = widget; m_widget->installEventFilter(this); #endif } else { MotifWmHints hints1; hints1.flags = MWM_HINTS_FUNCTIONS | MWM_HINTS_DECORATIONS; hints1.functions = MWM_FUNC_ALL; hints1.decorations = MWM_DECOR_BORDER; XAtomHelper::getInstance()->setWindowMotifHint(widget->winId(), hints1); } } bool UkuiStyleHelper::eventFilter(QObject *obj, QEvent *ev) { if (obj == m_widget && (ev->type() == QEvent::PlatformSurface || ev->type() == QEvent::Show || ev->type() == QEvent::UpdateRequest)) { #ifdef USE_UKUI_PROTOCOL if (UkuiShellManager::getInstance()->ukuishellReady()) UkuiShellManager::getInstance()->removeHeaderBar(m_widget->windowHandle()); else UKUIDecorationManager::getInstance()->removeHeaderBar(m_widget->windowHandle()); #else UKUIDecorationManager::getInstance()->removeHeaderBar(m_widget->windowHandle()); #endif } return QObject::eventFilter(obj, ev); } UkuiStyleHelper::UkuiStyleHelper() { } } libkysdk-applications/kysdk-waylandhelper/src/ukuistylehelper/ukui-decoration-manager.h0000664000175000017500000000244215104543305030674 0ustar fengfeng/* * libkysdk-waylandhelper's Library * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #ifndef UKUIDECORATIONMANAGER_H #define UKUIDECORATIONMANAGER_H #include /** * @since 1.2.0 */ class UKUIDecorationManager { public: static UKUIDecorationManager *getInstance(); bool supportUKUIDecoration(); bool moveWindow(QWindow *windowHandle); bool removeHeaderBar(QWindow *windowHandle); bool setCornerRadius(QWindow *windowHandle, int topleft, int topright, int bottomleft, int bottomright); private: UKUIDecorationManager(); }; #endif // UKUIDECORATIONMANAGER_H libkysdk-applications/kysdk-waylandhelper/src/ukuistylehelper/ukui-decoration-core.c0000664000175000017500000000342115104543305030203 0ustar fengfeng/* * libkysdk-waylandhelper's Library * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ /* Generated by wayland-scanner 1.18.0 */ #include "wayland-util.h" #include #include #ifndef __has_attribute #define __has_attribute(x) 0 /* Compatibility with non-clang compilers. */ #endif #if (__has_attribute(visibility) || defined(__GNUC__) && __GNUC__ >= 4) #define WL_PRIVATE __attribute__((visibility("hidden"))) #else #define WL_PRIVATE #endif extern const struct wl_interface wl_surface_interface; static const struct wl_interface *custom_types[] = { &wl_surface_interface, &wl_surface_interface, NULL, &wl_surface_interface, NULL, NULL, NULL, NULL, }; static const struct wl_message ukui_decoration_requests[] = { {"move_surface", "o", custom_types + 0}, {"set_ukui_decoration_mode", "ou", custom_types + 1}, {"set_unity_border_radius", "ouuuu", custom_types + 3}, }; WL_PRIVATE const struct wl_interface ukui_decoration_interface = { "ukui_decoration", 1, 3, ukui_decoration_requests, 0, NULL, }; libkysdk-applications/kysdk-waylandhelper/src/ukuistylehelper/ukui-shell-manager.h0000664000175000017500000000212115104543305027646 0ustar fengfeng/* * libkysdk-waylandhelper's Library * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #ifndef UKUI_SHELL_MANAGER_H #define UKUI_SHELL_MANAGER_H #include /** * @since 1.2.0 */ class UkuiShellManager { public: static UkuiShellManager *getInstance(); bool removeHeaderBar(QWindow *windowHandle); bool ukuishellReady(); private: UkuiShellManager(); }; #endif libkysdk-applications/kysdk-waylandhelper/src/ukuistylehelper/ukui-decoration-client.h0000664000175000017500000001021515104543305030535 0ustar fengfeng/* * libkysdk-waylandhelper's Library * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ /* Generated by wayland-scanner 1.18.0 */ #ifndef CUSTOM_CLIENT_PROTOCOL_H #define CUSTOM_CLIENT_PROTOCOL_H #include "wayland-client.h" #include #include /** * @since 1.2.0 */ #ifdef __cplusplus extern "C" { #endif struct ukui_decoration; struct wl_surface; /** * @page page_iface_ukui_decoration ukui_decoration * @section page_iface_ukui_decoration_desc Description * * This example shows how to add extra functionality to Wayland * through an extension. This is the global object of the extension. * @section page_iface_ukui_decoration_api API * See @ref iface_ukui_decoration. */ /** * @defgroup iface_ukui_decoration The ukui_decoration interface * * This example shows how to add extra functionality to Wayland * through an extension. This is the global object of the extension. */ extern const struct wl_interface ukui_decoration_interface; #define UKUI_DECORATION_MOVE_SURFACE 0 #define UKUI_DECORATION_SET_UKUI_DECORATION_MODE 1 #define UKUI_DECORATION_SET_UNITY_BORDER_RADIUS 2 /** * @ingroup iface_ukui_decoration */ #define UKUI_DECORATION_MOVE_SURFACE_SINCE_VERSION 1 /** * @ingroup iface_ukui_decoration */ #define UKUI_DECORATION_SET_UKUI_DECORATION_MODE_SINCE_VERSION 1 /** * @ingroup iface_ukui_decoration */ #define UKUI_DECORATION_SET_UNITY_BORDER_RADIUS_SINCE_VERSION 1 /** @ingroup iface_ukui_decoration */ static inline void ukui_decoration_set_user_data(struct ukui_decoration *ukui_decoration, void *user_data) { wl_proxy_set_user_data((struct wl_proxy *)ukui_decoration, user_data); } /** @ingroup iface_ukui_decoration */ static inline void * ukui_decoration_get_user_data(struct ukui_decoration *ukui_decoration) { return wl_proxy_get_user_data((struct wl_proxy *)ukui_decoration); } static inline uint32_t ukui_decoration_get_version(struct ukui_decoration *ukui_decoration) { return wl_proxy_get_version((struct wl_proxy *)ukui_decoration); } /** @ingroup iface_ukui_decoration */ static inline void ukui_decoration_destroy(struct ukui_decoration *ukui_decoration) { wl_proxy_destroy((struct wl_proxy *)ukui_decoration); } /** * @ingroup iface_ukui_decoration * * Inform the compositor that the client has a new surface that is * covered by the extension. */ static inline void ukui_decoration_move_surface(struct ukui_decoration *ukui_decoration, struct wl_surface *surface) { wl_proxy_marshal((struct wl_proxy *)ukui_decoration, UKUI_DECORATION_MOVE_SURFACE, surface); } /** * @ingroup iface_ukui_decoration * * The compositor should perform a move animation on the surface. */ static inline void ukui_decoration_set_ukui_decoration_mode(struct ukui_decoration *ukui_decoration, struct wl_surface *surface, uint32_t mode) { wl_proxy_marshal((struct wl_proxy *)ukui_decoration, UKUI_DECORATION_SET_UKUI_DECORATION_MODE, surface, mode); } /** * @ingroup iface_ukui_decoration * * The compositor should perform a move animation on the surface. */ static inline void ukui_decoration_set_unity_border_radius(struct ukui_decoration *ukui_decoration, struct wl_surface *surface, uint32_t topleft, uint32_t topright, uint32_t bottomleft, uint32_t bottomright) { wl_proxy_marshal((struct wl_proxy *)ukui_decoration, UKUI_DECORATION_SET_UNITY_BORDER_RADIUS, surface, topleft, topright, bottomleft, bottomright); } #ifdef __cplusplus } #endif #endif libkysdk-applications/kysdk-waylandhelper/src/ukuistylehelper/xatom-helper.h0000664000175000017500000000615115104543305026570 0ustar fengfeng/* * KWin Style UKUI * * Copyright (C) 2020, KylinSoft Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authors: Yue Lan * */ #ifndef XATOMHELPER_H #define XATOMHELPER_H #include /** * @brief 去标题栏 * @since 1.2.0 */ struct UnityCorners { ulong topLeft = 0; ulong topRight = 0; ulong bottomLeft = 0; ulong bottomRight = 0; }; typedef struct { ulong flags = 0; ulong functions = 0; ulong decorations = 0; long input_mode = 0; ulong status = 0; } MotifWmHints, MwmHints; #define MWM_HINTS_FUNCTIONS (1L << 0) #define MWM_HINTS_DECORATIONS (1L << 1) #define MWM_HINTS_INPUT_MODE (1L << 2) #define MWM_HINTS_STATUS (1L << 3) #define MWM_FUNC_ALL (1L << 0) #define MWM_FUNC_RESIZE (1L << 1) #define MWM_FUNC_MOVE (1L << 2) #define MWM_FUNC_MINIMIZE (1L << 3) #define MWM_FUNC_MAXIMIZE (1L << 4) #define MWM_FUNC_CLOSE (1L << 5) #define MWM_DECOR_ALL (1L << 0) #define MWM_DECOR_BORDER (1L << 1) #define MWM_DECOR_RESIZEH (1L << 2) #define MWM_DECOR_TITLE (1L << 3) #define MWM_DECOR_MENU (1L << 4) #define MWM_DECOR_MINIMIZE (1L << 5) #define MWM_DECOR_MAXIMIZE (1L << 6) #define MWM_INPUT_MODELESS 0 #define MWM_INPUT_PRIMARY_APPLICATION_MODAL 1 #define MWM_INPUT_SYSTEM_MODAL 2 #define MWM_INPUT_FULL_APPLICATION_MODAL 3 #define MWM_INPUT_APPLICATION_MODAL MWM_INPUT_PRIMARY_APPLICATION_MODAL #define MWM_TEAROFF_WINDOW (1L << 0) namespace UKUI { class Decoration; } class XAtomHelper : public QObject { friend class UKUI::Decoration; Q_OBJECT public: static XAtomHelper *getInstance(); static bool isFrameLessWindow(int winId); bool isWindowDecorateBorderOnly(int winId); bool isWindowMotifHintDecorateBorderOnly(const MotifWmHints &hint); bool isUKUICsdSupported(); bool isUKUIDecorationWindow(int winId); UnityCorners getWindowBorderRadius(int winId); void setWindowBorderRadius(int winId, const UnityCorners &data); void setWindowBorderRadius(int winId, int topLeft, int topRight, int bottomLeft, int bottomRight); void setUKUIDecoraiontHint(int winId, bool set = true); void setWindowMotifHint(int winId, const MotifWmHints &hints); MotifWmHints getWindowMotifHint(int winId); private: explicit XAtomHelper(QObject *parent = nullptr); unsigned long registerUKUICsdNetWmSupportAtom(); void unregisterUKUICsdNetWmSupportAtom(); unsigned long m_motifWMHintsAtom = 0l; unsigned long m_unityBorderRadiusAtom = 0l; unsigned long m_ukuiDecorationAtion = 0l; }; #endif // XATOMHELPER_H libkysdk-applications/kysdk-waylandhelper/src/ukuistylehelper/ukui-shell-manager.cpp0000664000175000017500000000333015104543305030204 0ustar fengfeng/* * libkysdk-waylandhelper's Library * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #include "ukui-shell-manager.h" #include "ukui-shell-client-protocol.h" #include "ukuiwaylandinterface.h" #include #include #include #include static UkuiShellManager *global_instance = nullptr; static UkuiWaylandInterface *g_ukuiwaylandInterface = nullptr; UkuiShellManager::UkuiShellManager() { if (!g_ukuiwaylandInterface) g_ukuiwaylandInterface = new UkuiWaylandInterface; } UkuiShellManager *UkuiShellManager::getInstance() { if (!global_instance) global_instance = new UkuiShellManager; return global_instance; } bool UkuiShellManager::removeHeaderBar(QWindow *windowHandle) { if (!g_ukuiwaylandInterface->ukuiProtocolReady()) return false; return g_ukuiwaylandInterface->removeHeaderBar(windowHandle); } bool UkuiShellManager::ukuishellReady() { return g_ukuiwaylandInterface->ukuiProtocolReady(); } libkysdk-applications/kysdk-waylandhelper/src/ukuistylehelper/ukuistylehelper.h0000664000175000017500000000252615104543305027423 0ustar fengfeng/* * libkysdk-waylandhelper's Library * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #ifndef UKUISTYLEHELPER_H #define UKUISTYLEHELPER_H #include namespace kdk { /** * @defgroup UkuiStyleModule */ /** * @brief 解决wayland环境下的双标题栏问题 * @since 1.2.0 */ class UkuiStyleHelper : public QObject { public: static UkuiStyleHelper *self(); /** * @brief 移除窗管标题栏 * @param widget */ void removeHeader(QWidget *widget); protected: bool eventFilter(QObject *obj, QEvent *ev) override; private: UkuiStyleHelper(); QWidget *m_widget; }; } #endif // UKUISTYLEHELPER_H libkysdk-applications/kysdk-waylandhelper/src/ukuistylehelper/ukui-decoration-manager.cpp0000664000175000017500000001031715104543305031227 0ustar fengfeng/* * libkysdk-waylandhelper's Library * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #include "ukui-decoration-manager.h" #include "ukui-decoration-client.h" #include #include #include #include static const u_int32_t ukui_decoration_surpported_version = 1; static UKUIDecorationManager *global_instance = nullptr; static wl_display *display = nullptr; static ukui_decoration *ukui_decoration_manager = nullptr; static void handle_global(void *data, struct wl_registry *registry, uint32_t name, const char *interface, uint32_t version) { if (strcmp(interface, ukui_decoration_interface.name) == 0) { u_int32_t surpportedVersion = qMin(ukui_decoration_surpported_version, version); ukui_decoration_manager = (ukui_decoration *)wl_registry_bind(registry, name, &ukui_decoration_interface, surpportedVersion); } } static void handle_global_remove(void *data, struct wl_registry *registry, uint32_t name) { // Who cares } static const struct wl_registry_listener registry_listener = { .global = handle_global, .global_remove = handle_global_remove, }; UKUIDecorationManager *UKUIDecorationManager::getInstance() { if (!global_instance) global_instance = new UKUIDecorationManager; return global_instance; } bool UKUIDecorationManager::supportUKUIDecoration() { return ukui_decoration_manager; } bool UKUIDecorationManager::moveWindow(QWindow *windowHandle) { if (!supportUKUIDecoration()) return false; auto kde_surface = KWayland::Client::Surface::fromWindow(windowHandle); if (!kde_surface) return false; wl_surface *surface = *kde_surface; if (!surface) return false; ukui_decoration_move_surface(ukui_decoration_manager, surface); wl_surface_commit(surface); wl_display_roundtrip(display); return true; } bool UKUIDecorationManager::removeHeaderBar(QWindow *windowHandle) { if (!supportUKUIDecoration()) return false; auto kde_surface = KWayland::Client::Surface::fromWindow(windowHandle); if (!kde_surface) { qDebug() << "UKUIDecorationManager::get kde_surface failed!"; return false; } wl_surface *surface = *kde_surface; if (!surface) { qDebug() << "UKUIDecorationManager::get wl_surface failed!"; return false; } ukui_decoration_set_ukui_decoration_mode(ukui_decoration_manager, surface, 1); wl_surface_commit(surface); return true; } bool UKUIDecorationManager::setCornerRadius(QWindow *windowHandle, int topleft, int topright, int bottomleft, int bottomright) { if (!supportUKUIDecoration()) return false; auto kde_surface = KWayland::Client::Surface::fromWindow(windowHandle); if (!kde_surface) return false; wl_surface *surface = *kde_surface; if (!surface) return false; ukui_decoration_set_unity_border_radius(ukui_decoration_manager, surface, topleft, topright, bottomleft, bottomright); wl_surface_commit(surface); wl_display_roundtrip(display); return true; } UKUIDecorationManager::UKUIDecorationManager() { auto connectionThread = KWayland::Client::ConnectionThread::fromApplication(qApp); display = connectionThread->display(); struct wl_registry *registry = wl_display_get_registry(display); // get ukui_decoration_manager wl_registry_add_listener(registry, ®istry_listener, nullptr); wl_display_roundtrip(display); } libkysdk-applications/kysdk-waylandhelper/src/ukuistylehelper/xatom-helper.cpp0000664000175000017500000001524615104543305027130 0ustar fengfeng/* * KWin Style UKUI * * Copyright (C) 2020, KylinSoft Co., Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authors: Yue Lan * */ // #include // #include #include #include #include #include #include #include #include "xatom-helper.h" static XAtomHelper *global_instance = nullptr; class X11Display { public: static Display *display(); static void closeDisplay(); private: static Display *s_display; }; Display *X11Display::s_display = nullptr; Display *X11Display::display() { if (!s_display) { s_display = XOpenDisplay(nullptr); if (s_display) { // qAddPostRoutine(closeDisplay()); atexit(closeDisplay); } } return s_display; } void X11Display::closeDisplay() { if (s_display) { XCloseDisplay(s_display); s_display = nullptr; } } XAtomHelper *XAtomHelper::getInstance() { if (!global_instance) global_instance = new XAtomHelper; return global_instance; } bool XAtomHelper::isFrameLessWindow(int winId) { auto hints = getInstance()->getWindowMotifHint(winId); if (hints.flags == MWM_HINTS_DECORATIONS && hints.functions == 1) { return true; } return false; } bool XAtomHelper::isWindowDecorateBorderOnly(int winId) { return isWindowMotifHintDecorateBorderOnly(getInstance()->getWindowMotifHint(winId)); } bool XAtomHelper::isWindowMotifHintDecorateBorderOnly(const MotifWmHints &hint) { bool isDeco = false; if (hint.flags & MWM_HINTS_DECORATIONS && hint.flags != MWM_HINTS_DECORATIONS) { if (hint.decorations == MWM_DECOR_BORDER) isDeco = true; } return isDeco; } bool XAtomHelper::isUKUICsdSupported() { // fixme: return false; } bool XAtomHelper::isUKUIDecorationWindow(int winId) { if (m_ukuiDecorationAtion == None) return false; Atom type; int format; ulong nitems; ulong bytes_after; uchar *data; bool isUKUIDecoration = false; XGetWindowProperty(X11Display::display(), winId, m_ukuiDecorationAtion, 0, LONG_MAX, false, m_ukuiDecorationAtion, &type, &format, &nitems, &bytes_after, &data); if (type == m_ukuiDecorationAtion) { if (nitems == 1) { isUKUIDecoration = data[0]; } } return isUKUIDecoration; } UnityCorners XAtomHelper::getWindowBorderRadius(int winId) { UnityCorners corners; Atom type; int format; ulong nitems; ulong bytes_after; uchar *data; if (m_unityBorderRadiusAtom != None) { XGetWindowProperty(X11Display::display(), winId, m_unityBorderRadiusAtom, 0, LONG_MAX, false, XA_CARDINAL, &type, &format, &nitems, &bytes_after, &data); if (type == XA_CARDINAL) { if (nitems == 4) { corners.topLeft = static_cast(data[0]); corners.topRight = static_cast(data[1 * sizeof(ulong)]); corners.bottomLeft = static_cast(data[2 * sizeof(ulong)]); corners.bottomRight = static_cast(data[3 * sizeof(ulong)]); } XFree(data); } } return corners; } void XAtomHelper::setWindowBorderRadius(int winId, const UnityCorners &data) { if (m_unityBorderRadiusAtom == None) return; ulong corners[4] = {data.topLeft, data.topRight, data.bottomLeft, data.bottomRight}; XChangeProperty(X11Display::display(), winId, m_unityBorderRadiusAtom, XA_CARDINAL, 32, XCB_PROP_MODE_REPLACE, (const unsigned char *)&corners, sizeof(corners) / sizeof(corners[0])); } void XAtomHelper::setWindowBorderRadius(int winId, int topLeft, int topRight, int bottomLeft, int bottomRight) { if (m_unityBorderRadiusAtom == None) return; ulong corners[4] = {(ulong)topLeft, (ulong)topRight, (ulong)bottomLeft, (ulong)bottomRight}; XChangeProperty(X11Display::display(), winId, m_unityBorderRadiusAtom, XA_CARDINAL, 32, XCB_PROP_MODE_REPLACE, (const unsigned char *)&corners, sizeof(corners) / sizeof(corners[0])); } void XAtomHelper::setUKUIDecoraiontHint(int winId, bool set) { if (m_ukuiDecorationAtion == None) return; XChangeProperty(X11Display::display(), winId, m_ukuiDecorationAtion, m_ukuiDecorationAtion, 32, XCB_PROP_MODE_REPLACE, (const unsigned char *)&set, 1); } void XAtomHelper::setWindowMotifHint(int winId, const MotifWmHints &hints) { if (m_unityBorderRadiusAtom == None) return; XChangeProperty(X11Display::display(), winId, m_motifWMHintsAtom, m_motifWMHintsAtom, 32, XCB_PROP_MODE_REPLACE, (const unsigned char *)&hints, sizeof(MotifWmHints) / sizeof(ulong)); } MotifWmHints XAtomHelper::getWindowMotifHint(int winId) { MotifWmHints hints; if (m_unityBorderRadiusAtom == None) return hints; uchar *data; Atom type; int format; ulong nitems; ulong bytes_after; XGetWindowProperty(X11Display::display(), winId, m_motifWMHintsAtom, 0, sizeof(MotifWmHints) / sizeof(long), false, AnyPropertyType, &type, &format, &nitems, &bytes_after, &data); if (type == None) { return hints; } else { hints = *(MotifWmHints *)data; XFree(data); } return hints; } XAtomHelper::XAtomHelper(QObject *parent) : QObject(parent) { if (QGuiApplication::platformName() != "xcb") return; m_motifWMHintsAtom = XInternAtom(X11Display::display(), "_MOTIF_WM_HINTS", true); m_unityBorderRadiusAtom = XInternAtom(X11Display::display(), "_UNITY_GTK_BORDER_RADIUS", false); m_ukuiDecorationAtion = XInternAtom(X11Display::display(), "_KWIN_UKUI_DECORAION", false); } Atom XAtomHelper::registerUKUICsdNetWmSupportAtom() { // fixme: return None; } void XAtomHelper::unregisterUKUICsdNetWmSupportAtom() { // fixme: } libkysdk-applications/kysdk-waylandhelper/src/waylandhelper.cpp0000664000175000017500000000303415104543305024114 0ustar fengfeng/* * libkysdk-waylandhelper's Library * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #include "waylandhelper.h" #include #include using namespace kdk; static const char *server_flag = "XDG_SESSION_TYPE"; static const char *client_flag = "QT_QPA_PLATFORM"; static WaylandHelper *g_instance = nullptr; bool WaylandHelper::isWaylandServer() { if (qgetenv(server_flag) == QString("wayland")) { return true; } else { return false; } } bool WaylandHelper::isWaylandClient() { if (qgetenv(client_flag) == QString("wayland")) { return true; } else { return false; } } WaylandHelper *WaylandHelper::self() { if (!g_instance) g_instance = new WaylandHelper(); return g_instance; } WaylandHelper::WaylandHelper(QObject *parent) : QObject(parent) { } libkysdk-applications/kysdk-waylandhelper/src/waylandhelper.h0000664000175000017500000000230215104543305023556 0ustar fengfeng/* * libkysdk-waylandhelper's Library * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #ifndef WAYLANDHELPER_H #define WAYLANDHELPER_H #include "kysdk-waylandhelper_global.h" #include /** * @since 1.2.0 */ namespace kdk { class KYSDKWAYLANDHELPER_EXPORT WaylandHelper : public QObject { public: static bool isWaylandServer(); static bool isWaylandClient(); static WaylandHelper *self(); private: WaylandHelper(QObject *parent = nullptr); }; } #endif // WAYLANDHELPER_H libkysdk-applications/kysdk-waylandhelper/src/blurmanager/0000775000175000017500000000000015104543305023050 5ustar fengfenglibkysdk-applications/kysdk-waylandhelper/src/blurmanager/ukuiblur.h0000664000175000017500000000426615104543305025073 0ustar fengfeng/* * libkysdk-waylandhelper's Library * * Copyright (C) 2024, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #ifndef UKUIBLUR_H #define UKUIBLUR_H #include "ukui-blur-manager-client-protocol.h" #include #include #include #include struct ukui_blur_manager_v1; struct ukui_blur_surface_v1; using namespace KWayland::Client; /** * @since 2.5.1.0 */ class UkuiBlur : public QObject { Q_OBJECT public: explicit UkuiBlur(QObject *parent = nullptr); ~UkuiBlur(); bool isValid() const; void release(); void destroy(); void setup(ukui_blur_surface_v1 *blur); void setRegion(Region *region); void setStrength(uint32_t strength); operator ukui_blur_surface_v1 *(); operator ukui_blur_surface_v1 *() const; private: class Private; QScopedPointer d; }; class UkuiBlurManager : public QObject { Q_OBJECT public: explicit UkuiBlurManager(QObject *parent = nullptr); ~UkuiBlurManager(); bool isValid() const; void release(); void destroy(); void setup(ukui_blur_manager_v1 *blur_manager); void setEventQueue(EventQueue *queue); EventQueue *eventQueue(); UkuiBlur *createBlur(Surface *surface, QObject *parent = nullptr); void removeBlur(Surface *surface); operator ukui_blur_manager_v1 *(); operator ukui_blur_manager_v1 *() const; private: class Private; QScopedPointer d; }; #endif // UKUIBLUR_H libkysdk-applications/kysdk-waylandhelper/src/blurmanager/ukuiblur.cpp0000664000175000017500000000650215104543305025421 0ustar fengfeng/* * libkysdk-waylandhelper's Library * * Copyright (C) 2024, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #include "ukuiblur.h" #include "ukuiwaylandpointer.h" class Q_DECL_HIDDEN UkuiBlur::Private { public: UkuiWaylandPointer blur; }; class Q_DECL_HIDDEN UkuiBlurManager::Private { public: Private(UkuiBlurManager *q); UkuiWaylandPointer blurManager; EventQueue *queue = nullptr; private: UkuiBlurManager *q; }; UkuiBlur::UkuiBlur(QObject *parent) : QObject(parent) , d(new Private) { } UkuiBlur::~UkuiBlur() { release(); } bool UkuiBlur::isValid() const { return d->blur.isValid(); } void UkuiBlur::release() { d->blur.release(); } void UkuiBlur::destroy() { d->blur.destroy(); } void UkuiBlur::setup(ukui_blur_surface_v1 *blur) { Q_ASSERT(blur); Q_ASSERT(!d->blur); d->blur.setup(blur); } void UkuiBlur::setRegion(Region *region) { ukui_blur_surface_v1_set_region(d->blur, *region); } void UkuiBlur::setStrength(uint32_t strength) { ukui_blur_surface_v1_set_level(d->blur, strength); } UkuiBlur::operator ukui_blur_surface_v1 *() { return d->blur; } UkuiBlur::operator ukui_blur_surface_v1 *() const { return d->blur; } UkuiBlurManager::UkuiBlurManager(QObject *parent) : QObject(parent) , d(new Private(this)) { } UkuiBlurManager::~UkuiBlurManager() { release(); } bool UkuiBlurManager::isValid() const { if (!d->blurManager) return false; return d->blurManager.isValid(); } void UkuiBlurManager::release() { d->blurManager.release(); } void UkuiBlurManager::destroy() { d->blurManager.destroy(); } void UkuiBlurManager::setup(ukui_blur_manager_v1 *blur_manager) { d->blurManager.setup(blur_manager); } void UkuiBlurManager::setEventQueue(EventQueue *queue) { d->queue = queue; } EventQueue *UkuiBlurManager::eventQueue() { return d->queue; } UkuiBlur *UkuiBlurManager::createBlur(Surface *surface, QObject *parent) { if (!isValid()) return nullptr; UkuiBlur *s = new UkuiBlur(parent); auto w = ukui_blur_manager_v1_get_blur(d->blurManager, *surface); if (d->queue) { d->queue->addProxy(w); } s->setup(w); return s; } void UkuiBlurManager::removeBlur(Surface *surface) { Q_ASSERT(isValid()); // ukui_blur_manager_unset(d->blurManager, *surface); } UkuiBlurManager::operator ukui_blur_manager_v1 *() { return d->blurManager; } UkuiBlurManager::operator ukui_blur_manager_v1 *() const { return d->blurManager; } UkuiBlurManager::Private::Private(UkuiBlurManager *q) : q(q) { } libkysdk-applications/kysdk-waylandhelper/src/blurmanager/blurxcbinterface.h0000664000175000017500000000234215104543305026544 0ustar fengfeng/* * libkysdk-waylandhelper's Library * * Copyright (C) 2024, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #ifndef BLURXCBINTERFACE_H #define BLURXCBINTERFACE_H #include "blurabstractinterface.h" #include /** * @since 2.5.1.0 */ class BlurXcbInterface : public BlurAbstractInterface { Q_OBJECT public: explicit BlurXcbInterface(QObject *parent = nullptr); bool setBlurBehindWithStrength(QWindow *window, bool enable = true, const QRegion ®ion = QRegion(), uint32_t strength = -1) override; }; #endif // BLURXCBINTERFACE_H libkysdk-applications/kysdk-waylandhelper/src/blurmanager/blurwaylandinterface.cpp0000664000175000017500000001156315104543305027767 0ustar fengfeng/* * libkysdk-waylandhelper's Library * * Copyright (C) 2024, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #include "blurwaylandinterface.h" #include static const u_int32_t ukui_blur_surpported_version = 1; static void handle_global(void *data, struct wl_registry *wl_registry, uint32_t name, const char *interface, uint32_t version) { auto blurInterface = reinterpret_cast(data); blurInterface->handleGlobal(data, wl_registry, name, interface, version); } static void handle_global_remove(void *data, struct wl_registry *wl_registry, uint32_t name) { } const struct wl_registry_listener BlurWaylandInterface::s_registryListener = {handle_global, handle_global_remove}; BlurWaylandInterface::BlurWaylandInterface(QObject *parent) : BlurAbstractInterface(parent) { m_connection = KWayland::Client::ConnectionThread::fromApplication(qApp); m_registry = new Registry(this); m_registry->create(m_connection->display()); wl_registry *registry = *m_registry; wl_registry_add_listener(registry, &s_registryListener, this); m_registry->setup(); m_connection->roundtrip(); } void BlurWaylandInterface::handleGlobal(void *data, wl_registry *registry, uint32_t name, const char *interface, uint32_t version) { if (strcmp(interface, ukui_blur_manager_v1_interface.name) == 0) { ukui_blur_manager_v1 *blur_manager_handle = (ukui_blur_manager_v1 *)wl_registry_bind(registry, name, &ukui_blur_manager_v1_interface, qMin(ukui_blur_surpported_version, version)); if (blur_manager_handle) { m_blur_manager = new UkuiBlurManager(this); m_blur_manager->setup(blur_manager_handle); } } if (strcmp(interface, wl_compositor_interface.name) == 0) { wl_compositor *wl_compositor_handle = (wl_compositor *)wl_registry_bind(registry, name, &wl_compositor_interface, version); if (wl_compositor_handle) { m_compositor = new Compositor(this); m_compositor->setup(wl_compositor_handle); } } } bool BlurWaylandInterface::eventFilter(QObject *obj, QEvent *ev) { auto window = qobject_cast(obj); if (window && ev->type() == QEvent::Hide) { if (m_surfaces.contains(window)) { auto surface = m_surfaces.value(window); if (surface) { surface->release(); surface->destroy(); } m_surfaces.remove(window); } if (m_regions.contains(window)) { auto region = m_regions.value(window); if (region) { region->release(); region->destroy(); } m_regions.remove(window); } if (m_blurs.contains(window)) { auto blur_handle = m_blurs.value(window); if (blur_handle) { blur_handle->release(); blur_handle->destroy(); } m_blurs.remove(window); } } return QObject::eventFilter(obj, ev); } bool BlurWaylandInterface::setBlurBehindWithStrength(QWindow *window, bool enable, const QRegion ®ion, uint32_t strength) { if (!window || !m_blur_manager || !m_compositor) return false; auto surface = KWayland::Client::Surface::fromWindow(window); if (!surface) return false; if (!m_surfaces.contains(window)) { m_surfaces.insert(window, surface); } if (enable) { UkuiBlur *blurHandle = m_blur_manager->createBlur(surface, this); if (!blurHandle) return false; if (!m_blurs.contains(window)) { m_blurs.insert(window, blurHandle); } Region *region_hanlde = m_compositor->createRegion(this); if (!region_hanlde) return false; if (!m_regions.contains(window)) { m_regions.insert(window, region_hanlde); } for (const QRect &rect : region) { region_hanlde->add(rect); } blurHandle->setRegion(region_hanlde); blurHandle->setStrength(strength); window->installEventFilter(this); return true; } else { m_blur_manager->removeBlur(surface); window->removeEventFilter(this); return true; } } libkysdk-applications/kysdk-waylandhelper/src/blurmanager/blurmanager.h0000664000175000017500000000263215104543305025523 0ustar fengfeng/* * libkysdk-waylandhelper's Library * * Copyright (C) 2024, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #ifndef BLURMANAGER_H #define BLURMANAGER_H #include #include #include #include "blurabstractinterface.h" /** * @since 2.5.1.0 */ namespace kdk { class BlurManagerPrivate; class Q_DECL_EXPORT BlurManager : public QObject { Q_OBJECT public: static BlurManager *self(); static bool setBlurBehindWithStrength(QWindow *window, bool enable = true, const QRegion ®ion = QRegion(), uint32_t strength = -1); private: BlurManager(QObject *parent = nullptr); BlurAbstractInterface *interface(); BlurAbstractInterface *m_blurInterface = nullptr; }; } #endif // BLURMANAGER_H libkysdk-applications/kysdk-waylandhelper/src/blurmanager/blurmanager.cpp0000664000175000017500000000346515104543305026063 0ustar fengfeng/* * libkysdk-waylandhelper's Library * * Copyright (C) 2024, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #include "blurmanager.h" #include "ukui-blur-manager-client-protocol.h" #include #include #include #include "blurwaylandinterface.h" #include "blurxcbinterface.h" namespace kdk { static BlurManager *g_blurmanager = nullptr; BlurManager::BlurManager(QObject *parent) : QObject(parent) { QString platform = QGuiApplication::platformName(); if (platform.startsWith(QLatin1String("wayland"), Qt::CaseInsensitive)) m_blurInterface = new BlurWaylandInterface(this); else m_blurInterface = new BlurXcbInterface(this); } BlurAbstractInterface *BlurManager::interface() { return m_blurInterface; } BlurManager *BlurManager::self() { if (g_blurmanager) return g_blurmanager; g_blurmanager = new BlurManager(); return g_blurmanager; } bool BlurManager::setBlurBehindWithStrength(QWindow *window, bool enable, const QRegion ®ion, uint32_t strength) { return self()->interface()->setBlurBehindWithStrength(window, enable, region, strength); } } libkysdk-applications/kysdk-waylandhelper/src/blurmanager/blurwaylandinterface.h0000664000175000017500000000432115104543305027426 0ustar fengfeng/* * libkysdk-waylandhelper's Library * * Copyright (C) 2024, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #ifndef BLURWAYLANDINTERFACE_H #define BLURWAYLANDINTERFACE_H #include "blurabstractinterface.h" #include "ukuiblur.h" #include #include #include #include #include #include #include #include #include /** * @since 2.5.1.0 */ using namespace KWayland::Client; class BlurWaylandInterface : public BlurAbstractInterface { Q_OBJECT public: explicit BlurWaylandInterface(QObject *parent = nullptr); bool setBlurBehindWithStrength(QWindow *window, bool enable = true, const QRegion ®ion = QRegion(), uint32_t strength = -1) override; void handleGlobal(void *data, struct wl_registry *registry, uint32_t name, const char *interface, uint32_t version); protected: bool eventFilter(QObject *obj, QEvent *ev) override; private: BlurWaylandInterface *q_ptr; ConnectionThread *m_connection = nullptr; Compositor *m_compositor = nullptr; Registry *m_registry = nullptr; UkuiBlur *m_blur = nullptr; UkuiBlurManager *m_blur_manager = nullptr; QMap m_surfaces; QMap m_regions; QMap m_blurs; static const struct wl_registry_listener s_registryListener; }; #endif // BLURWAYLANDINTERFACE_H libkysdk-applications/kysdk-waylandhelper/src/blurmanager/blurabstractinterface.h0000664000175000017500000000242715104543305027577 0ustar fengfeng/* * libkysdk-waylandhelper's Library * * Copyright (C) 2024, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #ifndef BLURABSTRACTINTERFACE_H #define BLURABSTRACTINTERFACE_H #include #include /** * @brief The BlurAbstractInterface class * @since 2.5.1.0 */ class BlurAbstractInterface : public QObject { public: BlurAbstractInterface(QObject *parent = nullptr) : QObject(parent) { } virtual bool setBlurBehindWithStrength(QWindow *window, bool enable = true, const QRegion ®ion = QRegion(), uint32_t strength = -1) = 0; }; #endif // BLURABSTRACTINTERFACE_H libkysdk-applications/kysdk-waylandhelper/src/blurmanager/blurxcbinterface.cpp0000664000175000017500000000461415104543305027103 0ustar fengfeng/* * libkysdk-waylandhelper's Library * * Copyright (C) 2024, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #include "blurxcbinterface.h" #include #include #include // #include BlurXcbInterface::BlurXcbInterface(QObject *parent) : BlurAbstractInterface(parent) { } bool BlurXcbInterface::setBlurBehindWithStrength(QWindow *window, bool enable, const QRegion ®ion, uint32_t strength) { // xcb_connection_t *c = QX11Info::connection(); // if (!c) { // return false; // } if (!window) { return false; } xcb_connection_t *c = xcb_connect(nullptr, nullptr); if (!c || xcb_connection_has_error(c)) { if (c) xcb_disconnect(c); return false; } const QByteArray effectName = QByteArrayLiteral("_KDE_NET_WM_BLUR_BEHIND_REGION"); xcb_intern_atom_cookie_t atomCookie = xcb_intern_atom_unchecked(c, false, effectName.length(), effectName.constData()); QScopedPointer atom(xcb_intern_atom_reply(c, atomCookie, nullptr)); if (!atom) { return false; } if (enable) { QVector data; data.reserve(region.rectCount() * 4 + 1); for (const QRect &r : region) { auto dpr = qApp->devicePixelRatio(); data << r.x() * dpr << r.y() * dpr << r.width() * dpr << r.height() * dpr; } data << strength; xcb_change_property(c, XCB_PROP_MODE_REPLACE, window->winId(), atom->atom, XCB_ATOM_CARDINAL, 32, data.size(), data.constData()); return true; } else { xcb_delete_property(c, window->winId(), atom->atom); xcb_flush(c); return true; } } libkysdk-applications/kysdk-waylandhelper/src/kysdk-waylandhelper_global.h0000664000175000017500000000210515104543305026222 0ustar fengfeng/* * libkysdk-waylandhelper's Library * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Zhen Sun * */ #ifndef KYSDKWAYLANDHELPER_GLOBAL_H #define KYSDKWAYLANDHELPER_GLOBAL_H #include #if defined(KYSDKWAYLANDHELPER_LIBRARY) #define KYSDKWAYLANDHELPER_EXPORT Q_DECL_EXPORT #else #define KYSDKWAYLANDHELPER_EXPORT Q_DECL_IMPORT #endif #endif // KYSDKWAYLANDHELPER_GLOBAL_H libkysdk-applications/kysdk-waylandhelper/src/kysdk-ukuiwindowhelper/0000775000175000017500000000000015155674255025320 5ustar fengfenglibkysdk-applications/kysdk-waylandhelper/src/kysdk-ukuiwindowhelper/ukuistartup.h0000664000175000017500000000104715104543305030054 0ustar fengfeng#pragma once #include class UkuiStartupManager; class UkuiStartupManagerPrivate; UkuiStartupManager *ukuiStartupManager(); class UkuiStartupManager { public: ~UkuiStartupManager(); void setStartupGeometryByPid(uint32_t pid, int x, int y, uint32_t width, uint32_t height); void setStartupGeometryEx(std::string appId, uint32_t pid, int x, int y, uint32_t width, uint32_t height); private: UkuiStartupManagerPrivate *p = nullptr; explicit UkuiStartupManager(); friend UkuiStartupManager *ukuiStartupManager(); }; libkysdk-applications/kysdk-waylandhelper/src/kysdk-ukuiwindowhelper/ukuiglobalcursor.cpp0000664000175000017500000000342015155674255031417 0ustar fengfeng#include "ukuiglobalcursor.h" #include "ukuidisplay_p.h" #include "kywc-capture-v1.h" #include class UkuiGolbalCursorPrivate { public: UkuiGolbalCursorPrivate(); ~UkuiGolbalCursorPrivate(); wayland::kywc_capture_manager_v1_t m_captureManager = nullptr; wayland::kywc_capture_cursor_v1_t m_captureCursor = nullptr; }; UkuiGolbalCursorPrivate::UkuiGolbalCursorPrivate() { m_captureManager = static_cast(ukuiDisplay()->bind(wayland::detail::kywc_capture_cursor_v1_interface.name, m_captureManager, wayland::detail::kywc_capture_cursor_v1_interface.version)); if (!m_captureManager) { qWarning() << "Failed to bind kywc_capture_manager_v1"; return; } m_captureCursor = m_captureManager.capture_cursor(ukuiDisplay()->seat(), 0); } UkuiGolbalCursorPrivate::~UkuiGolbalCursorPrivate() { } UkuiGolbalCursor *ukuiGolbalCursor() { static UkuiGolbalCursor *instance = nullptr; if (!instance) { instance = new UkuiGolbalCursor(); } return instance; } UkuiGolbalCursor::UkuiGolbalCursor() : m_ukuiGolbalCursorPrivate(new UkuiGolbalCursorPrivate()) { } UkuiGolbalCursor::~UkuiGolbalCursor() { delete m_ukuiGolbalCursorPrivate; m_ukuiGolbalCursorPrivate = nullptr; } std::function &UkuiGolbalCursor::on_enter() { return m_ukuiGolbalCursorPrivate->m_captureCursor.on_enter(); } std::function &UkuiGolbalCursor::on_leave() { return m_ukuiGolbalCursorPrivate->m_captureCursor.on_leave(); } std::function &UkuiGolbalCursor::on_position() { return m_ukuiGolbalCursorPrivate->m_captureCursor.on_position(); } std::function &UkuiGolbalCursor::on_hotspot() { return m_ukuiGolbalCursorPrivate->m_captureCursor.on_hotspot(); }libkysdk-applications/kysdk-waylandhelper/src/kysdk-ukuiwindowhelper/ukuidisplay.cpp0000664000175000017500000000577615155674255030406 0ustar fengfeng#include "ukuidisplay_p.h" #include #include #include static UkuiDisplay *s_ukuiDisplay = nullptr; UkuiDisplay *ukuiDisplay() { if (!s_ukuiDisplay) { s_ukuiDisplay = new UkuiDisplay(); } return s_ukuiDisplay; } UkuiDisplay::UkuiDisplay(QObject *parent) : QObject(parent) { m_initialized = init(); } UkuiDisplay::~UkuiDisplay() { } bool UkuiDisplay::init() { if (QGuiApplication::platformName() != "wayland") { return false; } QPlatformNativeInterface *native = qApp->platformNativeInterface(); if (!native) { qWarning() << "Failed to get QPlatformNativeInterface"; return false; } auto display = static_cast(native->nativeResourceForIntegration("wl_display")); if (!display) { qWarning() << "Failed to get native display"; return false; } m_display = std::make_unique(display); if (!m_display) { qWarning() << "Failed to get wl_display"; return false; } m_seat = wayland::seat_t(static_cast(native->nativeResourceForIntegration("wl_seat")), wayland::proxy_t::wrapper_type::foreign); if (!m_seat) { qWarning() << "Failed to get wl_seat"; return false; } m_registry = m_display->get_registry(); if (!m_registry) { qWarning() << "Failed to get wl_registry"; return false; } m_registry.on_global() = std::bind(&UkuiDisplay::handle_global, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3); m_registry.on_global_remove() = std::bind(&UkuiDisplay::handle_global_remove, this, std::placeholders::_1); // roundtrip to get all global interfaces m_display->roundtrip(); return true; } bool UkuiDisplay::isInitialized() const { return m_initialized; } const wayland::display_t &UkuiDisplay::display() const { return *m_display; } const wayland::seat_t &UkuiDisplay::seat() const { return m_seat; } void UkuiDisplay::handle_global(uint32_t name, const std::string &interface, uint32_t version) { m_globalInterfaces.append({name, interface, version}); } void UkuiDisplay::handle_global_remove(uint32_t name) { for (int i = 0; i < m_globalInterfaces.size(); ++i) { if (m_globalInterfaces.at(i).name == name) { m_globalInterfaces.removeAt(i); break; } } } QList UkuiDisplay::globalInterfaces() { return m_globalInterfaces; } wayland::proxy_t UkuiDisplay::bind(const std::string &name, wayland::proxy_t &proxy, uint32_t minVersion) { if (QGuiApplication::platformName() != "wayland") { return nullptr; } if (!isInitialized()) { return nullptr; } for (const WaylandInterface &interface : m_globalInterfaces) { if (interface.interface == name) { return m_registry.bind(interface.name, proxy, qMax(interface.version, minVersion)); } } return nullptr; } libkysdk-applications/kysdk-waylandhelper/src/kysdk-ukuiwindowhelper/ukuivirtualkeyboard.h0000664000175000017500000000205415104543305031560 0ustar fengfeng#pragma once #include #include class UkuiVirtualKeyboard; class UkuiVirtualKeyboardPrivate; class UkuiVirtualKeyboard { public: /** * @brief Constructor for UkuiVirtualKeyboard * @param keymap The keymap to use for the virtual keyboard */ UkuiVirtualKeyboard(const char *keymap); ~UkuiVirtualKeyboard(); /** * @brief Press a key on the virtual keyboard * @param key The key to press */ void keyPress(uint32_t key); /** * @brief Release a key on the virtual keyboard * @param key The key to release */ void keyRelease(uint32_t key); /** * @brief Set the modifiers on the virtual keyboard * @param mods_depressed The modifiers that are currently depressed * @param mods_latched The modifiers that are latched * @param mods_locked The modifiers that are locked */ void modifiers(uint32_t mods_depressed, uint32_t mods_latched, uint32_t mods_locked); private: UkuiVirtualKeyboardPrivate *m_ukuiVirtualKeyboardPrivate = nullptr; }; libkysdk-applications/kysdk-waylandhelper/src/kysdk-ukuiwindowhelper/ukuiwindowhelper.h0000664000175000017500000001146615155674255031106 0ustar fengfeng#pragma once #include class QWidget; class QWindow; class QScreen; struct UkuiWindowHelperPrivate; class UkuiWindowHelper : public QObject { Q_OBJECT public: explicit UkuiWindowHelper(QWidget *widget); explicit UkuiWindowHelper(QWindow *window); ~UkuiWindowHelper(); enum class WindowRole { // UKUI window types which is supported on ukui wayland environment. Normal = 0, Desktop = 1, Panel = 2, OnScreenDisplay = 3, Notification = 4, Tooltip = 5, CriticalNotification = 6, AppletPopup = 7, ScreenLock = 8, Watermark = 9, SystemWindow = 10, InputPanel = 11, Logout = 12, ScreenLockNotification = 13, Switcher = 14, Authentication = 15, // Other upstream window types contains kde specific window types and standard window types // Warning: These types are not supported on ukui wayland environment. Override = 101, Dialog = 102, Menu = 103, TopMenu = 104, ToolBar = 105, Dock = 106, Utility = 107, Splash = 108, DropdownMenu = 109, PopupMenu = 110, ComboBox = 111, DNDIcon = 112, }; Q_ENUM(WindowRole) enum class State : uint32_t { Minimizable = 0x1, Maximizable = 0x2, Closeable = 0x4, Fullscreenable = 0x8, Movable = 0x10, Resizable = 0x20, Focusable = 0x40, Activatable = 0x80, KeepAbove = 0x100, KeepBelow = 0x200, }; Q_DECLARE_FLAGS(States, State) enum class DecorationState : uint32_t { RoundCorner = 0x1, Border = 0x2, Shadow = 0x4, }; Q_DECLARE_FLAGS(DecorationStates, DecorationState) enum class Position { Left = 0, Top = 1, Right = 2, Bottom = 3 }; Q_ENUM(Position) enum class DecorationComponent : uint32_t { RoundCorner = 0x1, Border = 0x2, Shadow = 0x4, }; Q_DECLARE_FLAGS(DecorationComponents, DecorationComponent) void removeTitleBar(); void setWindowRole(WindowRole role); void setWindowState(States state); void setWindowIcon(const QString &iconName); void setSkipTaskBar(bool skip); void setSkipSwitcher(bool skip); void setPanelAutoHide(bool autoHide); void grabKeyboard(); void openUnderCursor(QPoint pos); void setBlurEffect(QRegion region, int level = 0, bool enable = true); void setSlideEffect(Position position, int offset = 0, bool enable = true); States defaultState() const; Q_DECL_DEPRECATED_X("Use UkuiWindowHelper::showTileFlyout(QRect rect) instead") void showTileFlyout(); Q_DECL_DEPRECATED_X("Use UkuiWindowHelper::setDecorationCompoents(DecorationComponents components) instead") void setDecorationState(DecorationStates state); /** * @brief showTileFlyout * Show the tile flyout, the flyout will be closed when the poiner leave the given rect. * @param rect The rect to show the flyout. * @note The rect is in the coordinate of the window. */ void showTileFlyout(QRect rect); void setDecorationCompoents(DecorationComponents components); /** * @brief requestGetCurrentScreen * Request to get the screen where the pointer is located. * This is useful when the screen information is not available immediately. You need to * connect to the `currentScreenChanged(QScreen *screen)` signal to get the current * screen after this request. * @note This function is only available on Wayland. */ void requestGetCurrentScreen(); /** * @brief currentScreen * Get the current screen where the window is located. * If the window has not been mapped to a screen yet, this function may return nullptr. * You should connect to the `currentScreenChanged(QScreen *screen)` signal to * get the current screen. * @return The current screen, or nullptr if not available. */ QScreen *currentScreen() const; /** * Get the current screen where the window is located. * Warning: it's a block function */ QScreen *getCurrentScreenBlocking(); void setOpaqueRegion(QRegion region); void setPosition(QPoint pos); QPoint position() const; void setWindowStateEx(States mask, States state); Q_SIGNALS: /** * @brief currentScreenChanged * This signal is emitted after requestedGetCurrentScreen() being called. * @param screen The current screen where the window is located. */ void currentScreenChanged(QScreen *screen); private: UkuiWindowHelperPrivate *p = nullptr; friend class UkuiWindowHelperPrivate; }; Q_DECLARE_OPERATORS_FOR_FLAGS(UkuiWindowHelper::States) Q_DECLARE_OPERATORS_FOR_FLAGS(UkuiWindowHelper::DecorationComponents) libkysdk-applications/kysdk-waylandhelper/src/kysdk-ukuiwindowhelper/ukuidisplay_p.h0000664000175000017500000000201215155674255030346 0ustar fengfeng#include #include class UkuiDisplay; UkuiDisplay *ukuiDisplay(); class UkuiDisplay : public QObject { Q_OBJECT public: ~UkuiDisplay(); bool isInitialized() const; const wayland::display_t &display() const; const wayland::seat_t &seat() const; wayland::proxy_t bind(const std::string &name, wayland::proxy_t &interface, uint32_t minVersion = 1); private: explicit UkuiDisplay(QObject *parent = nullptr); bool init(); void handle_global(uint32_t name, const std::string &interface, uint32_t version); void handle_global_remove(uint32_t name); struct WaylandInterface { uint32_t name; std::string interface; uint32_t version; }; QList globalInterfaces(); std::unique_ptr m_display; wayland::seat_t m_seat; wayland::registry_t m_registry; QList m_globalInterfaces; bool m_initialized = false; friend UkuiDisplay * ::ukuiDisplay(); }; libkysdk-applications/kysdk-waylandhelper/src/kysdk-ukuiwindowhelper/ukuiglobalcursor.h0000664000175000017500000000404315155674255031066 0ustar fengfeng#pragma once #include class UkuiGolbalCursor; class UkuiGolbalCursorPrivate; UkuiGolbalCursor *ukuiGolbalCursor(); class UkuiGolbalCursor { public: ~UkuiGolbalCursor(); /** \brief cursor entered a frame This event indicates that when a cursor enters the frame. It shall be generated before the "position" and "hotspot" events. If the pointer object referenced by the seat does not exist, this event will not be triggered. */ std::function &on_enter(); /** \brief cursor left frame This event indicates that when a cursor leaves the frame. No "position" or "hotspot" event is generated for the cursor until the cursor enters the frame again. If the pointer object referenced by the seat is removed, this event will be sent. */ std::function &on_leave(); /** \brief informs cursor position \param x position x coordinates \param y position y coordinates This event informs the cursor position. The given position is relative to the frame's top left corner in transformed buffer pixel coordinates. Note, if the frame parameter is set to null in the capture_cursor request, the given position coordinates are global. */ std::function &on_position(); /** \brief informs cursor hotspot \param x hotspot x coordinates \param y hotspot y coordinates This event informs the cursor hotspot. The hotspot describes the offset between the cursor image and the position of the input device. The parameters x and y represent the offset of the new hotspot relative to the origin of the cursor image, which is typically the top-left corner of the image. */ std::function &on_hotspot(); private: UkuiGolbalCursorPrivate *m_ukuiGolbalCursorPrivate = nullptr; explicit UkuiGolbalCursor(); friend UkuiGolbalCursor *ukuiGolbalCursor(); }; libkysdk-applications/kysdk-waylandhelper/src/kysdk-ukuiwindowhelper/ukuiwindowhelper.cpp0000664000175000017500000010446015155674255031436 0ustar fengfeng#include "ukuiwindowhelper.h" #include "qapplication.h" #include "qguiapplication.h" #include "ukuidisplay_p.h" #include "plasma-shell.h" #include "ukui-shell-v1.h" #include #include #include #include #include #include #include #include #include // #include #include #include #include #include #include #include class X11Display { public: static Display *display(); static void closeDisplay(); private: static Display *s_display; }; Display *X11Display::s_display = nullptr; Display *X11Display::display() { if (!s_display) { s_display = XOpenDisplay(nullptr); if (s_display) { atexit(closeDisplay); } } return s_display; } void X11Display::closeDisplay() { if (s_display) { XCloseDisplay(s_display); s_display = nullptr; } } static QMap s_plasmaSurfaceMap; static QMap s_ukuiSurfaceMap; static QMap s_ukuiDecorationMap; class UkuiWindowHelperPrivate : public QObject { public: explicit UkuiWindowHelperPrivate(UkuiWindowHelper *windowHelper, QWidget *widget); explicit UkuiWindowHelperPrivate(UkuiWindowHelper *windowHelper, QWindow *window); ~UkuiWindowHelperPrivate(); void removeTitleBar(); void setWindowRole(UkuiWindowHelper::WindowRole role); void setWindowState(UkuiWindowHelper::States state); void setWindowIcon(const QString &iconName); void setSkipTaskBar(bool skip); void setSkipSwitcher(bool skip); void setPanelAutoHide(bool autoHide); void grabKeyboard(); void openUnderCursor(QPoint pos); void setBlurEffect(QRegion region, int level = 0, bool enable = true); void setSlideEffect(UkuiWindowHelper::Position position, int offset = 0, bool enable = true); void showTileFlyout(QRect rect); void setDecorationCompoents(UkuiWindowHelper::DecorationComponents components); void requestGetCurrentScreen(); QScreen *currentScreen() const; void setOpaqueRegion(QRegion); void setPosition(QPoint pos); QPoint position() const; void setWindowStateEx(UkuiWindowHelper::States mask, UkuiWindowHelper::States states); private: bool eventFilter(QObject *obj, QEvent *event) override; void ukui_shell_v1_current_output(const std::string &output_name, const std::string &seat_name); void ukui_shell_v1_done(); wayland::org_kde_plasma_surface_role getPlasmaSurfaceRole(UkuiWindowHelper::WindowRole role); wayland::ukui_surface_v1_role getUkuiSurfaceRole(UkuiWindowHelper::WindowRole role); void initShellSurface(); void sendPendingRequests(); QNativeInterface::Private::QWaylandWindow *m_waylandWindow = nullptr; wayland::ukui_shell_v1_t m_ukuiShellv1; wayland::ukui_surface_v1_t m_ukuiSurfacev1; wayland::ukui_decoration_v1_t m_ukuiDecorationv1; wayland::org_kde_plasma_shell_t m_plasmaShell; wayland::org_kde_plasma_surface_t m_plasmaSurface; UkuiWindowHelper *m_windowHelper = nullptr; QWidget *m_widget = nullptr; QWindow *m_window = nullptr; QString m_currentOutputName; QString m_currentSeatName; QScreen *m_currentScreen = nullptr; std::optional m_currentPos; std::optional m_currentStatesMask; std::optional m_currentStates; std::optional m_titleBarRemoved; std::optional m_iconName; std::optional m_skipTaskBar; std::optional m_skipSwitcher; std::optional m_panelAutoHide; std::optional m_grabKeyboard; std::optional m_openUnderCursor; std::optional m_windowRole; }; UkuiWindowHelperPrivate::UkuiWindowHelperPrivate(UkuiWindowHelper *windowHelper, QWidget *widget) : m_windowHelper(windowHelper) , m_widget(widget) { if (!m_widget) { qWarning() << "Creating a UkuiWindowHelperPrivate for a null QWidget(nullptr)!"; } m_widget->installEventFilter(this); m_ukuiShellv1 = wayland::ukui_shell_v1_t(ukuiDisplay()->bind(wayland::detail::ukui_shell_v1_interface.name, m_ukuiShellv1, wayland::detail::ukui_shell_v1_interface.version)); if (m_ukuiShellv1) { m_ukuiShellv1.on_current_output() = std::bind(&UkuiWindowHelperPrivate::ukui_shell_v1_current_output, this, std::placeholders::_1, std::placeholders::_2); m_ukuiShellv1.on_done() = std::bind(&UkuiWindowHelperPrivate::ukui_shell_v1_done, this); } m_plasmaShell = wayland::org_kde_plasma_shell_t(ukuiDisplay()->bind(wayland::detail::org_kde_plasma_shell_interface.name, m_plasmaShell, wayland::detail::org_kde_plasma_shell_interface.version)); } UkuiWindowHelperPrivate::UkuiWindowHelperPrivate(UkuiWindowHelper *windowHelper, QWindow *window) : m_windowHelper(windowHelper) , m_window(window) { if (!m_window) { qWarning() << "Creating a UkuiWindowHelperPrivate for a QWindow(nullptr)!"; } m_window->installEventFilter(this); m_ukuiShellv1 = wayland::ukui_shell_v1_t(ukuiDisplay()->bind(wayland::detail::ukui_shell_v1_interface.name, m_ukuiShellv1, wayland::detail::ukui_shell_v1_interface.version)); if (m_ukuiShellv1) { m_ukuiShellv1.on_current_output() = std::bind(&UkuiWindowHelperPrivate::ukui_shell_v1_current_output, this, std::placeholders::_1, std::placeholders::_2); m_ukuiShellv1.on_done() = std::bind(&UkuiWindowHelperPrivate::ukui_shell_v1_done, this); } m_plasmaShell = wayland::org_kde_plasma_shell_t(ukuiDisplay()->bind(wayland::detail::org_kde_plasma_shell_interface.name, m_plasmaShell, wayland::detail::org_kde_plasma_shell_interface.version)); } UkuiWindowHelperPrivate::~UkuiWindowHelperPrivate() { } bool UkuiWindowHelperPrivate::eventFilter(QObject *obj, QEvent *event) { if (obj != m_widget && obj != m_window) { return QObject::eventFilter(obj, event); } if (event->type() == QEvent::PlatformSurface) { if (m_waylandWindow) return QObject::eventFilter(obj, event); QWindow *window = m_window ? m_window : m_widget->windowHandle(); if (!window) return QObject::eventFilter(obj, event); m_waylandWindow = window->nativeInterface(); if (!m_waylandWindow) return QObject::eventFilter(obj, event); initShellSurface(); connect(m_waylandWindow, &QNativeInterface::Private::QWaylandWindow::surfaceDestroyed, m_windowHelper, [this]() { s_plasmaSurfaceMap.remove(m_waylandWindow); s_ukuiSurfaceMap.remove(m_waylandWindow); m_plasmaSurface = nullptr; m_ukuiSurfacev1 = nullptr; m_ukuiDecorationv1 = nullptr; m_waylandWindow = nullptr; }); } return QObject::eventFilter(obj, event); } void UkuiWindowHelperPrivate::removeTitleBar() { if (m_widget) { m_widget->setProperty("ukui_surface_no_titlebar", true); } else if (m_window) { m_window->setProperty("ukui_surface_no_titlebar", true); } if (m_ukuiDecorationv1) { m_ukuiDecorationv1.set_no_titlebar(1); } m_titleBarRemoved = true; if (QGuiApplication::platformName() == "xcb") { Display *display = X11Display::display(); if (!display) { return; } Atom atom = XInternAtom(display, "_KWIN_UKUI_DECORAION", False); if (atom == None) { return; } unsigned long data = 1; Window winId = m_widget ? m_widget->winId() : (m_window ? m_window->winId() : 0); if (winId != 0) { XChangeProperty(display, winId, atom, atom, 32, PropModeReplace, reinterpret_cast(&data), 1); XFlush(display); } } } static QMap roleMap = { {UkuiWindowHelper::WindowRole::Normal, {"_NET_WM_WINDOW_TYPE_NORMAL"}}, {UkuiWindowHelper::WindowRole::Desktop, {"_NET_WM_WINDOW_TYPE_DESKTOP"}}, {UkuiWindowHelper::WindowRole::Panel, {"_UKUI_NET_WM_WINDOW_TYPE_PANEL", "_NET_WM_WINDOW_TYPE_DOCK"}}, {UkuiWindowHelper::WindowRole::OnScreenDisplay, {"_KDE_NET_WM_WINDOW_TYPE_ON_SCREEN_DISPLAY", "_NET_WM_WINDOW_TYPE_NOTIFICATION"}}, {UkuiWindowHelper::WindowRole::Notification, {"_NET_WM_WINDOW_TYPE_NOTIFICATION", "_NET_WM_WINDOW_TYPE_UTILITY"}}, {UkuiWindowHelper::WindowRole::Tooltip, {"_NET_WM_WINDOW_TYPE_TOOLTIP"}}, {UkuiWindowHelper::WindowRole::CriticalNotification, {"_NET_WM_WINDOW_TYPE_CRITICAL_NOTIFICATION", "_NET_WM_WINDOW_TYPE_NOTIFICATION"}}, {UkuiWindowHelper::WindowRole::AppletPopup, {"_NET_WM_WINDOW_TYPE_APPLET_POPUP"}}, {UkuiWindowHelper::WindowRole::ScreenLock, {"_UKUI_NET_WM_WINDOW_TYPE_SCREENLOCK"}}, {UkuiWindowHelper::WindowRole::Watermark, {"_UKUI_NET_WM_WINDOW_TYPE_WATERMARK"}}, {UkuiWindowHelper::WindowRole::SystemWindow, {"_UKUI_NET_WM_WINDOW_TYPE_SYSTEMWINDOW"}}, {UkuiWindowHelper::WindowRole::InputPanel, {"_UKUI_NET_WM_WINDOW_TYPE_INPUTPANEL"}}, {UkuiWindowHelper::WindowRole::Logout, {"_UKUI_NET_WM_WINDOW_TYPE_LOGOUT"}}, {UkuiWindowHelper::WindowRole::ScreenLockNotification, {"_UKUI_NET_WM_WINDOW_TYPE_SCREENLOCKNOTIFICATION"}}, {UkuiWindowHelper::WindowRole::Switcher, {"_UKUI_NET_WM_WINDOW_TYPE_SWITCHER"}}, {UkuiWindowHelper::WindowRole::Authentication, {"_UKUI_NET_WM_WINDOW_TYPE_AUTHENTICATION"}}, {UkuiWindowHelper::WindowRole::Override, {"_NET_WM_WINDOW_TYPE_OVERRIDE", "_NET_WM_WINDOW_TYPE_NORMAL"}}, {UkuiWindowHelper::WindowRole::Dialog, {"_NET_WM_WINDOW_TYPE_DIALOG"}}, {UkuiWindowHelper::WindowRole::Menu, {"_NET_WM_WINDOW_TYPE_MENU"}}, {UkuiWindowHelper::WindowRole::TopMenu, {"_KDE_NET_WM_WINDOW_TYPE_TOPMENU", "_NET_WM_WINDOW_TYPE_DOCK"}}, {UkuiWindowHelper::WindowRole::ToolBar, {"_NET_WM_WINDOW_TYPE_TOOLBAR"}}, {UkuiWindowHelper::WindowRole::Dock, {"_NET_WM_WINDOW_TYPE_DOCK"}}, {UkuiWindowHelper::WindowRole::Utility, {"_NET_WM_WINDOW_TYPE_UTILITY", "_NET_WM_WINDOW_TYPE_DIALOG"}}, {UkuiWindowHelper::WindowRole::Splash, {"_NET_WM_WINDOW_TYPE_SPLASH", "_NET_WM_WINDOW_TYPE_DOCK"}}, {UkuiWindowHelper::WindowRole::DropdownMenu, {"_NET_WM_WINDOW_TYPE_DROPDOWN_MENU", "_NET_WM_WINDOW_TYPE_MENU"}}, {UkuiWindowHelper::WindowRole::PopupMenu, {"_NET_WM_WINDOW_TYPE_POPUP_MENU", "_NET_WM_WINDOW_TYPE_MENU"}}, {UkuiWindowHelper::WindowRole::ComboBox, {"_NET_WM_WINDOW_TYPE_COMBO"}}, {UkuiWindowHelper::WindowRole::DNDIcon, {"_NET_WM_WINDOW_TYPE_DND"}}, }; void UkuiWindowHelperPrivate::setWindowRole(UkuiWindowHelper::WindowRole role) { if (m_widget) { m_widget->setProperty("ukui_surface_role_v1", qBound(0, (int)role, 100)); } else if (m_window) { m_window->setProperty("ukui_surface_role_v1", qBound(0, (int)role, 100)); } if (m_plasmaSurface) { m_plasmaSurface.set_role(static_cast(getPlasmaSurfaceRole(role))); return; } else if (m_ukuiSurfacev1) { m_ukuiSurfacev1.set_role(static_cast(getUkuiSurfaceRole(role))); return; } m_windowRole = role; if (QGuiApplication::platformName() == "xcb") { Display *display = X11Display::display(); if (!display) { return; } Atom prop = XInternAtom(display, "_NET_WM_WINDOW_TYPE", False); if (prop == None) { return; } QStringList types = roleMap.value(role); if (types.isEmpty()) { return; } QVector atomList; for (const QString &type : types) { Atom atom = XInternAtom(display, type.toUtf8().constData(), False); if (atom != None) { atomList.append(atom); } } if (atomList.isEmpty()) { return; } Window win = m_widget ? m_widget->winId() : (m_window ? m_window->winId() : 0); if (!win) return; XChangeProperty(X11Display::display(), win, prop, XA_ATOM, 32, PropModeReplace, (unsigned char *)atomList.constData(), atomList.size()); } } void UkuiWindowHelperPrivate::setWindowState(UkuiWindowHelper::States states) { QPair pair(0x3ff, states); if (m_widget) { m_widget->setProperty("ukui_surface_state", QVariant::fromValue(pair)); } else if (m_window) { m_window->setProperty("ukui_surface_state", QVariant::fromValue(pair)); } setWindowStateEx(states, states); if (QGuiApplication::platformName() == "xcb") { Display *display = X11Display::display(); if (!display) { return; } Atom prop = XInternAtom(display, "_NET_WM_STATE", False); if (prop == None) { return; } Window win = m_widget ? m_widget->winId() : (m_window ? m_window->winId() : 0); if (!win) return; Atom actualType; int actualFormat; unsigned long nItems, bytesAfter; Atom *currentAtoms = nullptr; QVector finalAtoms; QStringList atomList = {"_NET_WM_STATE_ABOVE", "_NET_WM_STATE_BELOW"}; if (Success == XGetWindowProperty(display, win, prop, 0, 1024, False, XA_ATOM, &actualType, &actualFormat, &nItems, &bytesAfter, (unsigned char **)¤tAtoms)) { for (unsigned long i = 0; i < nItems; ++i) { char *name = XGetAtomName(display, currentAtoms[i]); if (name) { QString nameStr = QString::fromUtf8(name); if (!atomList.contains(nameStr)) finalAtoms.append(currentAtoms[i]); XFree(name); } } if (currentAtoms) XFree(currentAtoms); } if (states & UkuiWindowHelper::State::KeepAbove) { Atom atom = XInternAtom(display, "_NET_WM_STATE_ABOVE", False); if (atom != None) { finalAtoms.append(atom); } } if (states & UkuiWindowHelper::State::KeepBelow) { Atom atom = XInternAtom(display, "_NET_WM_STATE_BELOW", False); if (atom != None) { finalAtoms.append(atom); } } if (finalAtoms.isEmpty()) { return; } XChangeProperty(X11Display::display(), win, prop, XA_ATOM, 32, PropModeReplace, (unsigned char *)finalAtoms.constData(), finalAtoms.size()); } } void UkuiWindowHelperPrivate::setWindowIcon(const QString &iconName) { if (m_widget) { m_widget->setProperty("ukui_surface_icon", iconName); } else if (m_window) { m_window->setProperty("ukui_surface_icon", iconName); } if (m_ukuiSurfacev1) m_ukuiSurfacev1.set_icon(iconName.toStdString()); m_iconName = iconName; } void UkuiWindowHelperPrivate::setSkipTaskBar(bool skip) { if (m_widget) { m_widget->setProperty("ukui_surface_skip_taskbar", skip); } else if (m_window) { m_window->setProperty("ukui_surface_skip_taskbar", skip); } if (m_ukuiSurfacev1) m_ukuiSurfacev1.set_skip_taskbar(skip ? 1 : 0); if (m_plasmaSurface) m_plasmaSurface.set_skip_taskbar(skip ? 1 : 0); m_skipTaskBar = skip; if (QGuiApplication::platformName() == "xcb") { Display *display = X11Display::display(); if (!display) { return; } Atom prop = XInternAtom(display, "_NET_WM_STATE", False); if (prop == None) { return; } Window win = m_widget ? m_widget->winId() : (m_window ? m_window->winId() : 0); if (!win) return; Atom actualType; int actualFormat; unsigned long nItems, bytesAfter; Atom *currentAtoms = nullptr; QVector finalAtoms; QString atomStr = "_NET_WM_STATE_SKIP_TASKBAR"; if (Success == XGetWindowProperty(display, win, prop, 0, 1024, False, XA_ATOM, &actualType, &actualFormat, &nItems, &bytesAfter, (unsigned char **)¤tAtoms)) { for (unsigned long i = 0; i < nItems; ++i) { char *name = XGetAtomName(display, currentAtoms[i]); if (name) { QString nameStr = QString::fromUtf8(name); if (nameStr != atomStr) finalAtoms.append(currentAtoms[i]); XFree(name); } } if (currentAtoms) XFree(currentAtoms); } if (skip) { Atom skipAtom = XInternAtom(display, atomStr.toUtf8().constData(), False); if (skipAtom != None) { finalAtoms.append(skipAtom); } } if (finalAtoms.isEmpty()) { XDeleteProperty(display, win, prop); } else { XChangeProperty(X11Display::display(), win, prop, XA_ATOM, 32, PropModeReplace, (unsigned char *)finalAtoms.constData(), finalAtoms.size()); } } } void UkuiWindowHelperPrivate::setSkipSwitcher(bool skip) { if (m_widget) { m_widget->setProperty("ukui_surface_skip_switcher", skip); } else if (m_window) { m_window->setProperty("ukui_surface_skip_switcher", skip); } if (m_ukuiSurfacev1) m_ukuiSurfacev1.set_skip_switcher(skip ? 1 : 0); if (m_plasmaSurface) m_plasmaSurface.set_skip_switcher(skip ? 1 : 0); m_skipSwitcher = skip; if (QGuiApplication::platformName() == "xcb") { Display *display = X11Display::display(); if (!display) { return; } Atom prop = XInternAtom(display, "_NET_WM_STATE", False); if (prop == None) { return; } Window win = m_widget ? m_widget->winId() : (m_window ? m_window->winId() : 0); if (!win) return; Atom actualType; int actualFormat; unsigned long nItems, bytesAfter; Atom *currentAtoms = nullptr; QVector finalAtoms; QString atomStr = "_KDE_NET_WM_STATE_SKIP_SWITCHER"; if (Success == XGetWindowProperty(display, win, prop, 0, 1024, False, XA_ATOM, &actualType, &actualFormat, &nItems, &bytesAfter, (unsigned char **)¤tAtoms)) { for (unsigned long i = 0; i < nItems; ++i) { char *name = XGetAtomName(display, currentAtoms[i]); if (name) { QString nameStr = QString::fromUtf8(name); if (nameStr != atomStr) finalAtoms.append(currentAtoms[i]); XFree(name); } } if (currentAtoms) XFree(currentAtoms); } if (skip) { Atom skipAtom = XInternAtom(display, atomStr.toUtf8().constData(), False); if (skipAtom != None) { finalAtoms.append(skipAtom); } } if (finalAtoms.isEmpty()) { XDeleteProperty(display, win, prop); } else { XChangeProperty(display, win, prop, XA_ATOM, 32, PropModeReplace, (unsigned char *)finalAtoms.constData(), finalAtoms.size()); } } } void UkuiWindowHelperPrivate::setPanelAutoHide(bool autoHide) { if (m_widget) { m_widget->setProperty("ukui_surface_panel_auto_hide", autoHide); } else if (m_window) { m_window->setProperty("ukui_surface_panel_auto_hide", autoHide); } if (m_ukuiSurfacev1) m_ukuiSurfacev1.set_panel_auto_hide(autoHide ? 1 : 0); if (m_plasmaSurface) m_plasmaSurface.set_panel_behavior(autoHide ? 2 : 1); m_panelAutoHide = autoHide; } void UkuiWindowHelperPrivate::grabKeyboard() { if (m_widget) { m_widget->setProperty("ukui_surface_grab_keyboard", true); } else if (m_window) { m_window->setProperty("ukui_surface_grab_keyboard", true); } if (m_ukuiSurfacev1) m_ukuiSurfacev1.grab_keyboard(nullptr); m_grabKeyboard = true; } void UkuiWindowHelperPrivate::openUnderCursor(QPoint pos) { if (m_widget) { m_widget->setProperty("ukui_surface_open_under_cursor", pos); } else if (m_window) { m_window->setProperty("ukui_surface_open_under_cursor", pos); } if (m_ukuiSurfacev1) m_ukuiSurfacev1.open_under_cursor(pos.x(), pos.y()); m_openUnderCursor = pos; } void UkuiWindowHelperPrivate::setBlurEffect(QRegion region, int level, bool enable) { QPair pair(region, level); if (!enable) pair.second = -1; if (m_widget) { m_widget->setProperty("ukui_surface_blur", QVariant::fromValue(pair)); } else if (m_window) { m_window->setProperty("ukui_surface_blur", QVariant::fromValue(pair)); } if (QGuiApplication::platformName() == "xcb") { Display *display = X11Display::display(); if (!display) return; Atom blurAtom = XInternAtom(display, "_KDE_NET_WM_BLUR_BEHIND_REGION", False); if (blurAtom == None) return; Window win = m_widget ? m_widget->winId() : (m_window ? m_window->winId() : 0); if (!win) return; if (enable) { QVector data; data.reserve(region.rectCount() * 4 + 1); // 每个 QRect 占4个uint,最后加1是 level qreal dpr = qApp->devicePixelRatio(); // 设备像素缩放 for (const QRect &r : region) { data << static_cast(std::floor(r.x() * dpr)) << static_cast(std::floor(r.y() * dpr)) << static_cast(std::ceil(r.width() * dpr)) << static_cast(std::ceil(r.height() * dpr)); } data << static_cast(level); // 添加 level(模糊强度) XChangeProperty(display, win, blurAtom, XA_CARDINAL, 32, PropModeReplace, reinterpret_cast(data.constData()), data.size()); XFlush(display); } else { XDeleteProperty(display, win, blurAtom); XFlush(display); } } } void UkuiWindowHelperPrivate::setSlideEffect(UkuiWindowHelper::Position position, int offset, bool enable) { QPair pair((int)position, offset); if (!enable) pair.first = -1; if (m_widget) { m_widget->setProperty("ukui_surface_slide", QVariant::fromValue(pair)); } else if (m_window) { m_window->setProperty("ukui_surface_slide", QVariant::fromValue(pair)); } if (QGuiApplication::platformName() == "xcb") { Display *display = X11Display::display(); if (!display) return; Atom slideAtom = XInternAtom(display, "_KDE_SLIDE", False); if (slideAtom == None) return; Window winId = m_widget ? m_widget->winId() : (m_window ? m_window->winId() : 0); if (!winId) return; if (!enable) { XDeleteProperty(display, winId, slideAtom); XFlush(display); return; } unsigned long data[2]; data[0] = offset; switch (position) { case UkuiWindowHelper::Position::Left: data[1] = 0; break; case UkuiWindowHelper::Position::Top: data[1] = 1; break; case UkuiWindowHelper::Position::Right: data[1] = 2; break; case UkuiWindowHelper::Position::Bottom: default: data[1] = 3; break; } XChangeProperty(display, winId, slideAtom, slideAtom, 32, PropModeReplace, reinterpret_cast(data), 2); XFlush(display); } } void UkuiWindowHelperPrivate::showTileFlyout(QRect rect) { if (m_ukuiSurfacev1) m_ukuiSurfacev1.show_tile_flyout(nullptr, rect.x(), rect.y(), rect.width(), rect.height()); } void UkuiWindowHelperPrivate::setDecorationCompoents(UkuiWindowHelper::DecorationComponents components) { if (m_widget) { m_widget->setProperty("ukui_surface_decoration_components", (uint32_t)components); } else if (m_window) { m_window->setProperty("ukui_surface_decoration_components", (uint32_t)components); } } void UkuiWindowHelperPrivate::requestGetCurrentScreen() { if (m_ukuiShellv1) m_ukuiShellv1.get_current_output(); } QScreen *UkuiWindowHelperPrivate::currentScreen() const { return m_currentScreen; } void UkuiWindowHelperPrivate::setOpaqueRegion(QRegion region) { if (m_widget) { m_widget->setProperty("ukui_surface_opaque_region", region); } else if (m_window) { m_window->setProperty("ukui_surface_opaque_region", region); } } void UkuiWindowHelperPrivate::setPosition(QPoint pos) { if (m_plasmaSurface) { m_plasmaSurface.set_position(pos.x(), pos.y()); } else if (m_ukuiSurfacev1) { m_ukuiSurfacev1.set_position(pos.x(), pos.y()); } m_currentPos = pos; } QPoint UkuiWindowHelperPrivate::position() const { return m_currentPos.value_or(QPoint(0, 0)); } void UkuiWindowHelperPrivate::setWindowStateEx(UkuiWindowHelper::States mask, UkuiWindowHelper::States states) { if (m_ukuiSurfacev1) m_ukuiSurfacev1.set_state(static_cast(mask), static_cast(states)); m_currentStatesMask = mask; m_currentStates = states; } void UkuiWindowHelperPrivate::ukui_shell_v1_current_output(const std::string &output_name, const std::string &seat_name) { m_currentOutputName = QString::fromUtf8(output_name); m_currentSeatName = QString::fromUtf8(seat_name); } void UkuiWindowHelperPrivate::ukui_shell_v1_done() { for (QScreen *screen : QGuiApplication::screens()) { if (screen->name() == m_currentOutputName) { m_currentScreen = screen; Q_EMIT m_windowHelper->currentScreenChanged(screen); return; } } } wayland::org_kde_plasma_surface_role UkuiWindowHelperPrivate::getPlasmaSurfaceRole(UkuiWindowHelper::WindowRole role) { switch (role) { case UkuiWindowHelper::WindowRole::Normal: return wayland::org_kde_plasma_surface_role::normal; case UkuiWindowHelper::WindowRole::Desktop: return wayland::org_kde_plasma_surface_role::desktop; case UkuiWindowHelper::WindowRole::Panel: return wayland::org_kde_plasma_surface_role::panel; case UkuiWindowHelper::WindowRole::OnScreenDisplay: return wayland::org_kde_plasma_surface_role::onscreendisplay; case UkuiWindowHelper::WindowRole::Notification: return wayland::org_kde_plasma_surface_role::notification; case UkuiWindowHelper::WindowRole::Tooltip: return wayland::org_kde_plasma_surface_role::tooltip; case UkuiWindowHelper::WindowRole::CriticalNotification: return wayland::org_kde_plasma_surface_role::criticalnotification; case UkuiWindowHelper::WindowRole::AppletPopup: return wayland::org_kde_plasma_surface_role::appletpopup; // remap ukui specific roles case UkuiWindowHelper::WindowRole::Watermark: return wayland::org_kde_plasma_surface_role::onscreendisplay; case UkuiWindowHelper::WindowRole::ScreenLockNotification: return wayland::org_kde_plasma_surface_role::notification; case UkuiWindowHelper::WindowRole::Dock: return wayland::org_kde_plasma_surface_role::panel; default: return wayland::org_kde_plasma_surface_role::normal; } } wayland::ukui_surface_v1_role UkuiWindowHelperPrivate::getUkuiSurfaceRole(UkuiWindowHelper::WindowRole role) { switch (role) { case UkuiWindowHelper::WindowRole::Normal: return wayland::ukui_surface_v1_role::normal; case UkuiWindowHelper::WindowRole::Desktop: return wayland::ukui_surface_v1_role::desktop; case UkuiWindowHelper::WindowRole::Panel: return wayland::ukui_surface_v1_role::panel; case UkuiWindowHelper::WindowRole::OnScreenDisplay: return wayland::ukui_surface_v1_role::onscreendisplay; case UkuiWindowHelper::WindowRole::Notification: return wayland::ukui_surface_v1_role::notification; case UkuiWindowHelper::WindowRole::Tooltip: return wayland::ukui_surface_v1_role::tooltip; case UkuiWindowHelper::WindowRole::CriticalNotification: return wayland::ukui_surface_v1_role::criticalnotification; case UkuiWindowHelper::WindowRole::AppletPopup: return wayland::ukui_surface_v1_role::appletpopup; case UkuiWindowHelper::WindowRole::Watermark: return wayland::ukui_surface_v1_role::watermark; case UkuiWindowHelper::WindowRole::ScreenLock: return wayland::ukui_surface_v1_role::screenlock; case UkuiWindowHelper::WindowRole::SystemWindow: return wayland::ukui_surface_v1_role::systemwindow; case UkuiWindowHelper::WindowRole::InputPanel: return wayland::ukui_surface_v1_role::inputpanel; case UkuiWindowHelper::WindowRole::Logout: return wayland::ukui_surface_v1_role::logout; case UkuiWindowHelper::WindowRole::ScreenLockNotification: return wayland::ukui_surface_v1_role::screenlocknotification; case UkuiWindowHelper::WindowRole::Switcher: return wayland::ukui_surface_v1_role::switcher; case UkuiWindowHelper::WindowRole::Authentication: return wayland::ukui_surface_v1_role::authentication; // remap some roles case UkuiWindowHelper::WindowRole::Dock: return wayland::ukui_surface_v1_role::panel; default: return wayland::ukui_surface_v1_role::normal; } } void UkuiWindowHelperPrivate::initShellSurface() { if (!m_waylandWindow) return; if (s_plasmaSurfaceMap.contains(m_waylandWindow)) { m_plasmaSurface = s_plasmaSurfaceMap.value(m_waylandWindow); return; } if (s_ukuiSurfaceMap.contains(m_waylandWindow)) { m_ukuiSurfacev1 = s_ukuiSurfaceMap.value(m_waylandWindow); return; } QWindow *window = m_window ? m_window : m_widget->windowHandle(); if (!window) return; wayland::surface_t surface(m_waylandWindow->surface(), wayland::proxy_t::wrapper_type::foreign); if (!surface) return; if (m_plasmaShell) { m_plasmaSurface = m_plasmaShell.get_surface(surface); if (m_plasmaSurface) s_plasmaSurfaceMap.insert(m_waylandWindow, m_plasmaSurface); } if (m_ukuiShellv1) { m_ukuiSurfacev1 = m_ukuiShellv1.create_surface(surface); m_ukuiDecorationv1 = m_ukuiShellv1.create_decoration(surface); if (m_ukuiSurfacev1) s_ukuiSurfaceMap.insert(m_waylandWindow, m_ukuiSurfacev1); if (m_ukuiDecorationv1) s_ukuiDecorationMap.insert(m_waylandWindow, m_ukuiDecorationv1); } sendPendingRequests(); } void UkuiWindowHelperPrivate::sendPendingRequests() { if (m_windowRole.has_value()) setWindowRole(m_windowRole.value()); if (m_currentPos.has_value()) setPosition(m_currentPos.value()); if (m_currentStatesMask.has_value() && m_currentStates.has_value()) setWindowStateEx(m_currentStatesMask.value(), m_currentStates.value()); if (m_titleBarRemoved.has_value()) removeTitleBar(); if (m_iconName.has_value()) setWindowIcon(m_iconName.value()); if (m_skipTaskBar.has_value()) setSkipTaskBar(m_skipTaskBar.value()); if (m_skipSwitcher.has_value()) setSkipSwitcher(m_skipSwitcher.value()); if (m_panelAutoHide.has_value()) setPanelAutoHide(m_panelAutoHide.value()); if (m_grabKeyboard.has_value()) grabKeyboard(); if (m_openUnderCursor.has_value()) openUnderCursor(m_openUnderCursor.value()); } UkuiWindowHelper::UkuiWindowHelper(QWidget *widget) : p(new UkuiWindowHelperPrivate(this, widget)) { connect(widget, &QObject::destroyed, this, &QObject::deleteLater); } UkuiWindowHelper::UkuiWindowHelper(QWindow *window) : p(new UkuiWindowHelperPrivate(this, window)) { connect(window, &QObject::destroyed, this, &QObject::deleteLater); } UkuiWindowHelper::~UkuiWindowHelper() { delete p; p = nullptr; } void UkuiWindowHelper::removeTitleBar() { p->removeTitleBar(); } void UkuiWindowHelper::setWindowRole(WindowRole role) { p->setWindowRole(role); } void UkuiWindowHelper::setWindowState(States states) { p->setWindowState(states); } void UkuiWindowHelper::setWindowIcon(const QString &iconName) { p->setWindowIcon(iconName); } void UkuiWindowHelper::setSkipTaskBar(bool skip) { p->setSkipTaskBar(skip); } void UkuiWindowHelper::setSkipSwitcher(bool skip) { p->setSkipSwitcher(skip); } void UkuiWindowHelper::setPanelAutoHide(bool autoHide) { p->setPanelAutoHide(autoHide); } void UkuiWindowHelper::grabKeyboard() { p->grabKeyboard(); } void UkuiWindowHelper::openUnderCursor(QPoint pos) { p->openUnderCursor(pos); } void UkuiWindowHelper::setBlurEffect(QRegion region, int level, bool enable) { p->setBlurEffect(region, level, enable); } void UkuiWindowHelper::setSlideEffect(Position position, int offset, bool enable) { p->setSlideEffect(position, offset, enable); } UkuiWindowHelper::States UkuiWindowHelper::defaultState() const { return UkuiWindowHelper::States(0xff); } void UkuiWindowHelper::showTileFlyout() { p->showTileFlyout(QRect()); } void UkuiWindowHelper::showTileFlyout(QRect rect) { p->showTileFlyout(rect); } void UkuiWindowHelper::setDecorationState(DecorationStates state) { p->setDecorationCompoents((DecorationComponents)(int)state); } void UkuiWindowHelper::setDecorationCompoents(DecorationComponents components) { p->setDecorationCompoents(components); } void UkuiWindowHelper::requestGetCurrentScreen() { p->requestGetCurrentScreen(); } QScreen *UkuiWindowHelper::currentScreen() const { return p->currentScreen(); } QScreen *UkuiWindowHelper::getCurrentScreenBlocking() { if (QGuiApplication::platformName() != "wayland") { qWarning() << "getCurrentScreenBlocking() is only available on Wayland!"; return nullptr; } p->requestGetCurrentScreen(); wl_display_roundtrip(ukuiDisplay()->display()); return p->currentScreen(); } void UkuiWindowHelper::setOpaqueRegion(QRegion region) { p->setOpaqueRegion(region); } void UkuiWindowHelper::setPosition(QPoint point) { p->setPosition(point); } QPoint UkuiWindowHelper::position() const { return p->position(); } void UkuiWindowHelper::setWindowStateEx(UkuiWindowHelper::States mask, UkuiWindowHelper::States states) { p->setWindowStateEx(mask, states); }libkysdk-applications/kysdk-waylandhelper/src/kysdk-ukuiwindowhelper/ukuikeystate.h0000664000175000017500000000164315104543305030205 0ustar fengfeng#pragma once #include #include class UkuiKeyState; class UkuiKeyStatePrivate; UkuiKeyState *ukuiKeyState(); class UkuiKeyState { public: enum Key { CapsLock = 0, NumLock = 1, ScrollLock = 2, Alt = 3, Control = 4, Shift = 5, Meta = 6, AltGr = 7, }; enum State { Unlocked = 0, Latched = 1, Locked = 2, Pressed = 3, }; ~UkuiKeyState(); /* * @brief fetch the current state of all keys */ void fetchStates(); /* * @brief handler for key state changed * @param1 The key that changed state * @param2 The new state of the key */ std::function &on_state_changed(); private: UkuiKeyStatePrivate *m_ukuiKeyStatePrivate = nullptr; explicit UkuiKeyState(); friend UkuiKeyState *ukuiKeyState(); }; libkysdk-applications/kysdk-waylandhelper/src/kysdk-ukuiwindowhelper/ukuivirtualkeyboard.cpp0000664000175000017500000000654015155674255032136 0ustar fengfeng#include "ukuivirtualkeyboard.h" #include "ukuidisplay_p.h" #include "virtual-keyboard-unstable-v1.h" #include #include #include #include class UkuiVirtualKeyboardPrivate { public: explicit UkuiVirtualKeyboardPrivate(const char *keymap); ~UkuiVirtualKeyboardPrivate(); void keyPress(uint32_t key); void keyRelease(uint32_t key); void modifiers(uint32_t mods_depressed, uint32_t mods_latched, uint32_t mods_locked); private: wayland::zwp_virtual_keyboard_manager_v1_t m_virtualKeyboardManager; wayland::zwp_virtual_keyboard_v1_t m_virtualKeyboard; uint32_t symToKeyCode(uint32_t sym) const; }; UkuiVirtualKeyboardPrivate::UkuiVirtualKeyboardPrivate(const char *keymap) { if (!keymap || keymap[0] == '\0') { qWarning() << "Keymap is empty or nullptr"; return; } m_virtualKeyboardManager = static_cast(ukuiDisplay()->bind(wayland::detail::zwp_virtual_keyboard_manager_v1_interface.name, m_virtualKeyboardManager, wayland::detail::zwp_virtual_keyboard_manager_v1_interface.version)); if (!m_virtualKeyboardManager) { qWarning() << "Failed to bind zwp_virtual_keyboard_manager_v1"; return; } m_virtualKeyboard = m_virtualKeyboardManager.create_virtual_keyboard(ukuiDisplay()->seat()); std::string keymap_file = "/tmp/waylandpp-XXXXXX"; int fd = mkstemp(const_cast(keymap_file.c_str())); if (fd == -1) { qWarning() << "Failed to create keymap file"; return; } unlink(keymap_file.c_str()); FILE *f = fdopen(fd, "w"); fprintf(f, "%s", keymap); fflush(f); size_t keymap_size = ftell(f); m_virtualKeyboard.keymap(0, fd, keymap_size); fclose(f); } UkuiVirtualKeyboardPrivate::~UkuiVirtualKeyboardPrivate() { } void UkuiVirtualKeyboardPrivate::keyPress(uint32_t key) { if (!m_virtualKeyboard) { qWarning() << "Virtual keyboard is not initialized"; return; } m_virtualKeyboard.key(0, key, 1); } void UkuiVirtualKeyboardPrivate::keyRelease(uint32_t key) { if (!m_virtualKeyboard) { qWarning() << "Virtual keyboard is not initialized"; return; } m_virtualKeyboard.key(0, key, 0); } void UkuiVirtualKeyboardPrivate::modifiers(uint32_t mods_depressed, uint32_t mods_latched, uint32_t mods_locked) { if (!m_virtualKeyboard) { qWarning() << "Virtual keyboard is not initialized"; return; } m_virtualKeyboard.modifiers(mods_depressed, mods_latched, mods_locked, 0); } UkuiVirtualKeyboard::UkuiVirtualKeyboard(const char *keymap) : m_ukuiVirtualKeyboardPrivate(new UkuiVirtualKeyboardPrivate(keymap)) { } UkuiVirtualKeyboard::~UkuiVirtualKeyboard() { delete m_ukuiVirtualKeyboardPrivate; m_ukuiVirtualKeyboardPrivate = nullptr; } void UkuiVirtualKeyboard::keyPress(uint32_t key) { if (m_ukuiVirtualKeyboardPrivate) { m_ukuiVirtualKeyboardPrivate->keyPress(key); } } void UkuiVirtualKeyboard::keyRelease(uint32_t key) { if (m_ukuiVirtualKeyboardPrivate) { m_ukuiVirtualKeyboardPrivate->keyRelease(key); } } void UkuiVirtualKeyboard::modifiers(uint32_t mods_depressed, uint32_t mods_latched, uint32_t mods_locked) { if (m_ukuiVirtualKeyboardPrivate) { m_ukuiVirtualKeyboardPrivate->modifiers(mods_depressed, mods_latched, mods_locked); } } libkysdk-applications/kysdk-waylandhelper/src/kysdk-ukuiwindowhelper/kysdk-ukuiwindowhelper.pro0000664000175000017500000000362515155674255032600 0ustar fengfengQT += gui widgets gui-private TEMPLATE = lib CONFIG += c++17 link_pkgconfig PKGCONFIG += wayland-client x11 wayland-client++ system(wayland-scanner++ ../../protocols/ukui-startup-v1.xml $$OUT_PWD/ukui-startup-v1.h $$OUT_PWD/ukui-startup-v1.cpp) system(wayland-scanner++ ../../protocols/ukui-startup-v2.xml $$OUT_PWD/ukui-startup-v2.h $$OUT_PWD/ukui-startup-v2.cpp) system(wayland-scanner++ ../../protocols/ukui-shell-v1.xml $$OUT_PWD/ukui-shell-v1.h $$OUT_PWD/ukui-shell-v1.cpp) system(wayland-scanner++ ../../protocols/kywc-capture-v1.xml $$OUT_PWD/kywc-capture-v1.h $$OUT_PWD/kywc-capture-v1.cpp) system(wayland-scanner++ ../../protocols/keystate.xml $$OUT_PWD/keystate.h $$OUT_PWD/keystate.cpp) system(wayland-scanner++ ../../protocols/virtual-keyboard-unstable-v1.xml $$OUT_PWD/virtual-keyboard-unstable-v1.h $$OUT_PWD/virtual-keyboard-unstable-v1.cpp) system(wayland-scanner++ ../../protocols/plasma-shell.xml $$OUT_PWD/plasma-shell.h $$OUT_PWD/plasma-shell.cpp) INCLUDEPATH += $$OUT_PWD SOURCES += \ ukuiwindowhelper.cpp \ ukuistartup.cpp \ ukui-startup-v1.cpp \ ukui-startup-v2.cpp \ ukui-shell-v1.cpp \ kywc-capture-v1.cpp \ keystate.cpp \ virtual-keyboard-unstable-v1.cpp \ plasma-shell.cpp \ ukuidisplay.cpp \ ukuiglobalcursor.cpp \ ukuikeystate.cpp \ ukuivirtualkeyboard.cpp \ INSTALL_HEADERS += \ ukuiwindowhelper.h \ ukuistartup.h \ ukuiglobalcursor.h \ ukuikeystate.h \ ukuivirtualkeyboard.h \ PRIVATE_HEADERS += \ ukuidisplay_p.h \ ukui-startup-v1.h \ ukui-startup-v2.h \ ukui-shell-v1.h \ kywc-capture-v1.h \ virtual-keyboard-unstable-v1.h \ plasma-shell.h \ HEADERS += \ $${INSTALL_HEADERS} \ $${PRIVATE_HEADERS} # Default rules for deployment. headers.files = $${INSTALL_HEADERS} headers.path = /usr/include/kysdk/applications/ukuiwindowhelper/ target.path = $$[QT_INSTALL_LIBS] INSTALLS += target headers libkysdk-applications/kysdk-waylandhelper/src/kysdk-ukuiwindowhelper/ukuistartup.cpp0000664000175000017500000001022715155674255030426 0ustar fengfeng#include "ukuistartup.h" #include "ukuidisplay_p.h" #include "ukui-startup-v1.h" #include "ukui-startup-v2.h" #include #include UkuiStartupManager *ukuiStartupManager() { static UkuiStartupManager *instance = nullptr; if (!instance) { instance = new UkuiStartupManager(); } return instance; } class UkuiStartupManagerPrivate { public: UkuiStartupManagerPrivate(); ~UkuiStartupManagerPrivate(); void setStartupGeometryByPid(uint32_t pid, int x, int y, uint32_t width, uint32_t height); void setStartupGeometryEx(std::string appId, uint32_t pid, int x, int y, uint32_t width, uint32_t height); private: wayland::ukui_startup_management_v1_t m_ukuiStartupManager; wayland::ukui_startup_management_v2_t m_ukuiStartupManagerV2; }; UkuiStartupManagerPrivate::UkuiStartupManagerPrivate() { // m_ukuiStartupManager = static_cast(ukui_startup_management_v1_interface.name, &ukui_startup_management_v1_interface, ukui_startup_management_v1_interface.version)); // m_ukuiStartupManagerV2 = static_cast(ukuiDisplay()->bind(ukui_startup_management_v2_interface.name, &ukui_startup_management_v2_interface, ukui_startup_management_v2_interface.version)); } UkuiStartupManagerPrivate::~UkuiStartupManagerPrivate() { } void UkuiStartupManagerPrivate::setStartupGeometryByPid(uint32_t pid, int x, int y, uint32_t width, uint32_t height) { if (width <= 0 || height <= 0) { qWarning() << "Invalid width or height for startup geometry"; return; } if (m_ukuiStartupManagerV2) { auto start_info = m_ukuiStartupManagerV2.create_startup_info(); start_info.set_startup_geometry(x, y, width, height); start_info.set_pid(pid); QFile file("/proc/" + QString::number(pid) + "/cmdline"); if (file.open(QIODevice::ReadOnly)) { QByteArray raw = file.readAll(); QString cmdline = QString::fromUtf8(raw).replace('\0', ' '); QString appId; if (!cmdline.trimmed().isEmpty()) { QStringList parts = cmdline.split(" ", Qt::SkipEmptyParts); if (!parts.isEmpty()) { QString first = parts.first(); QStringList pathParts = first.split("/", Qt::SkipEmptyParts); if (!pathParts.isEmpty()) { appId = pathParts.last(); } } } if (!appId.isEmpty()) { start_info.set_appid(appId.toUtf8().constData()); } else { qWarning() << "Failed to extract appId from cmdline:" << cmdline; } } wl_display_roundtrip(ukuiDisplay()->display()); } else if (m_ukuiStartupManager) { m_ukuiStartupManager.set_startup_geometry(pid, x, y, width, height); wl_display_roundtrip(ukuiDisplay()->display()); } } void UkuiStartupManagerPrivate::setStartupGeometryEx(std::string appId, uint32_t pid, int x, int y, uint32_t width, uint32_t height) { if (width <= 0 || height <= 0) { qWarning() << "Invalid width or height for startup geometry"; return; } if (m_ukuiStartupManagerV2) { auto start_info = m_ukuiStartupManagerV2.create_startup_info(); start_info.set_startup_geometry(x, y, width, height); start_info.set_pid(pid); start_info.set_appid(appId); wl_display_roundtrip(ukuiDisplay()->display()); } else if (m_ukuiStartupManager) { m_ukuiStartupManager.set_startup_geometry(pid, x, y, width, height); wl_display_roundtrip(ukuiDisplay()->display()); } } UkuiStartupManager::UkuiStartupManager() : p(new UkuiStartupManagerPrivate()) { } UkuiStartupManager::~UkuiStartupManager() { delete p; p = nullptr; } void UkuiStartupManager::setStartupGeometryByPid(uint32_t pid, int x, int y, uint32_t width, uint32_t height) { p->setStartupGeometryByPid(pid, x, y, width, height); } void UkuiStartupManager::setStartupGeometryEx(std::string appId, uint32_t pid, int x, int y, uint32_t width, uint32_t height) { p->setStartupGeometryEx(appId, pid, x, y, width, height); }libkysdk-applications/kysdk-waylandhelper/src/kysdk-ukuiwindowhelper/ukuikeystate.cpp0000664000175000017500000000314315155674255030554 0ustar fengfeng#include "ukuikeystate.h" #include "ukuidisplay_p.h" #include "keystate.h" #include class UkuiKeyStatePrivate { public: UkuiKeyStatePrivate(); ~UkuiKeyStatePrivate(); std::function stateChanged; wayland::org_kde_kwin_keystate_t m_keystate; }; UkuiKeyStatePrivate::UkuiKeyStatePrivate() { m_keystate = static_cast(ukuiDisplay()->bind(wayland::detail::org_kde_kwin_keystate_interface.name, m_keystate, wayland::detail::org_kde_kwin_keystate_interface.version)); if (!m_keystate) { qWarning() << "Failed to bind org_kde_kwin_keystate"; return; } m_keystate.on_stateChanged() = [this](uint32_t key, uint32_t state) { if (stateChanged) { stateChanged(static_cast(key), static_cast(state)); } }; } UkuiKeyStatePrivate::~UkuiKeyStatePrivate() { } UkuiKeyState *ukuiKeyState() { static UkuiKeyState *instance = nullptr; if (!instance) { instance = new UkuiKeyState(); } return instance; } UkuiKeyState::UkuiKeyState() : m_ukuiKeyStatePrivate(new UkuiKeyStatePrivate()) { } UkuiKeyState::~UkuiKeyState() { delete m_ukuiKeyStatePrivate; m_ukuiKeyStatePrivate = nullptr; } void UkuiKeyState::fetchStates() { if (m_ukuiKeyStatePrivate && m_ukuiKeyStatePrivate->m_keystate) { m_ukuiKeyStatePrivate->m_keystate.fetchStates(); } } std::function &UkuiKeyState::on_state_changed() { return m_ukuiKeyStatePrivate->stateChanged; } libkysdk-applications/kysdk-waylandhelper/readme.md0000664000175000017500000000000015104515306021527 0ustar fengfenglibkysdk-applications/config/0000775000175000017500000000000015104543305015245 5ustar fengfenglibkysdk-applications/config/kysdk-applications.conf0000664000175000017500000000023615104543305021726 0ustar fengfeng/usr/lib/kysdk/base/ /usr/lib/kysdk/applications/ /usr/lib/kysdk/system/ /usr/lib/kysdk/kysdk-base/ /usr/lib/kysdk/kysdk-system/ /usr/libs/kysdk/applications/libkysdk-applications/kysdk-alm/0000775000175000017500000000000015147772510015705 5ustar fengfenglibkysdk-applications/kysdk-alm/kysdk-alm.pro0000664000175000017500000000100015104543305020301 0ustar fengfengQT += core network widgets TARGET = kysdk-alm TEMPLATE = lib CONFIG += c++17 console link_pkgconfig PKGCONFIG += KF6WindowSystem HEADERS += src/singleapplication/singleapplication.h \ src/singleapplication/localpeer.h \ SOURCES += src/singleapplication/singleapplication.cpp \ src/singleapplication/localpeer.cpp \ # Default rules for deployment. headers.files = $${HEADERS} headers.path = /usr/include/kysdk/applications/ target.path = $$[QT_INSTALL_LIBS] INSTALLS += target headers libkysdk-applications/kysdk-alm/test/0000775000175000017500000000000015104515306016653 5ustar fengfenglibkysdk-applications/kysdk-alm/test/testsingleapplication/0000775000175000017500000000000015104543305023260 5ustar fengfenglibkysdk-applications/kysdk-alm/test/testsingleapplication/main.cpp0000664000175000017500000000233315104543305024711 0ustar fengfeng/* * * * Copyright (C) 2023, KylinSoft Co., Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * * Authors: Shengjie Ji * */ #include #include #include #include "singleapplication.h" int main(int argc, char *argv[]) { kdk::QtSingleApplication app(argc, argv); /* 设置单例 */ if (app.isRunning()) { qDebug() << "app is running"; app.sendMessage("running", 4000); return 0; } QWidget widget; /* 设置最小化拉起 */ app.setActivationWindow(&widget); widget.show(); return app.exec(); } libkysdk-applications/kysdk-alm/test/testsingleapplication/testsingleapplication.pro0000664000175000017500000000021015104543305030400 0ustar fengfengQT += widgets TARGET = testsingleapplication TEMPLATE = app CONFIG += c++17 link_pkgconfig PKGCONFIG += kysdk-alm SOURCES += main.cpplibkysdk-applications/kysdk-alm/src/0000775000175000017500000000000015104515306016463 5ustar fengfenglibkysdk-applications/kysdk-alm/src/singleapplication/0000775000175000017500000000000015104543305022170 5ustar fengfenglibkysdk-applications/kysdk-alm/src/singleapplication/singleapplication.h0000664000175000017500000000774515104543305026063 0ustar fengfeng/**************************************************************************** ** ** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). ** Contact: http://www.qt-project.org/legal ** ** This file is part of the Qt Solutions component. ** ** $QT_BEGIN_LICENSE:BSD$ ** You may use this file under the terms of the BSD license as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names ** of its contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef KYSDK_ALM_SINGLEAPPLICATION_SINGLEAPPLICATION_H_ #define KYSDK_ALM_SINGLEAPPLICATION_SINGLEAPPLICATION_H_ #include /** * @since 1.2.0 */ namespace kdk { class QtLocalPeer; #if defined(Q_OS_WIN) #if !defined(QT_QTSINGLEAPPLICATION_EXPORT) && !defined(QT_QTSINGLEAPPLICATION_IMPORT) #define QT_QTSINGLEAPPLICATION_EXPORT #elif defined(QT_QTSINGLEAPPLICATION_IMPORT) #if defined(QT_QTSINGLEAPPLICATION_EXPORT) #undef QT_QTSINGLEAPPLICATION_EXPORT #endif #define QT_QTSINGLEAPPLICATION_EXPORT __declspec(dllimport) #elif defined(QT_QTSINGLEAPPLICATION_EXPORT) #undef QT_QTSINGLEAPPLICATION_EXPORT #define QT_QTSINGLEAPPLICATION_EXPORT __declspec(dllexport) #endif #else #define QT_QTSINGLEAPPLICATION_EXPORT #endif class QT_QTSINGLEAPPLICATION_EXPORT QtSingleApplication : public QApplication { Q_OBJECT public: QtSingleApplication(int &argc, char **argv, bool GUIenabled = true); QtSingleApplication(const QString &id, int &argc, char **argv); #if QT_VERSION < 0x050000 QtSingleApplication(int &argc, char **argv, Type type); #if defined(Q_WS_X11) QtSingleApplication(Display *dpy, Qt::HANDLE visual = 0, Qt::HANDLE colormap = 0); QtSingleApplication(Display *dpy, int &argc, char **argv, Qt::HANDLE visual = 0, Qt::HANDLE cmap = 0); QtSingleApplication(Display *dpy, const QString &appId, int argc, char **argv, Qt::HANDLE visual = 0, Qt::HANDLE colormap = 0); #endif // Q_WS_X11 #endif // QT_VERSION < 0x050000 bool isRunning(); QString id() const; void setActivationWindow(QWidget *aw, bool activateOnMessage = true); QWidget *activationWindow() const; // Obsolete: void initialize(bool dummy = true) { isRunning(); Q_UNUSED(dummy) } public Q_SLOTS: bool sendMessage(const QString &message, int timeout = 5000); void activateWindow(); Q_SIGNALS: void messageReceived(const QString &message); private: void sysInit(const QString &appId = QString()); QtLocalPeer *peer; QWidget *actWin; }; } // namespace kdk #endif libkysdk-applications/kysdk-alm/src/singleapplication/localpeer.h0000664000175000017500000000535615104543305024320 0ustar fengfeng/**************************************************************************** ** ** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). ** Contact: http://www.qt-project.org/legal ** ** This file is part of the Qt Solutions component. ** ** $QT_BEGIN_LICENSE:BSD$ ** You may use this file under the terms of the BSD license as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names ** of its contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef KYSDK_ALM_SINGLEAPPLICATION_LOCALPEER_H_ #define KYSDK_ALM_SINGLEAPPLICATION_LOCALPEER_H_ #include #include #include #include "lockedfile.h" /** * @since 1.2.0 */ namespace kdk { class QtLocalPeer : public QObject { Q_OBJECT public: QtLocalPeer(QObject *parent = 0, const QString &appId = QString()); bool isClient(); bool sendMessage(const QString &message, int timeout); QString applicationId() const { return id; } Q_SIGNALS: void messageReceived(const QString &message); protected Q_SLOTS: void receiveConnection(); protected: QString id; QString socketName; QLocalServer *server; QtLP_Private::QtLockedFile lockFile; private: static const char *ack; }; } // namespace kdk #endif libkysdk-applications/kysdk-alm/src/singleapplication/singleapplication.cpp0000664000175000017500000002752415104543305026413 0ustar fengfeng/**************************************************************************** ** ** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). ** Contact: http://www.qt-project.org/legal ** ** This file is part of the Qt Solutions component. ** ** $QT_BEGIN_LICENSE:BSD$ ** You may use this file under the terms of the BSD license as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names ** of its contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include #include #include #include "localpeer.h" #include "singleapplication.h" /*! \class QtSingleApplication qtsingleapplication.h \brief The QtSingleApplication class provides an API to detect and communicate with running instances of an application. This class allows you to create applications where only one instance should be running at a time. I.e., if the user tries to launch another instance, the already running instance will be activated instead. Another usecase is a client-server system, where the first started instance will assume the role of server, and the later instances will act as clients of that server. By default, the full path of the executable file is used to determine whether two processes are instances of the same application. You can also provide an explicit identifier string that will be compared instead. The application should create the QtSingleApplication object early in the startup phase, and call isRunning() to find out if another instance of this application is already running. If isRunning() returns false, it means that no other instance is running, and this instance has assumed the role as the running instance. In this case, the application should continue with the initialization of the application user interface before entering the event loop with exec(), as normal. The messageReceived() signal will be emitted when the running application receives messages from another instance of the same application. When a message is received it might be helpful to the user to raise the application so that it becomes visible. To facilitate this, QtSingleApplication provides the setActivationWindow() function and the activateWindow() slot. If isRunning() returns true, another instance is already running. It may be alerted to the fact that another instance has started by using the sendMessage() function. Also data such as startup parameters (e.g. the name of the file the user wanted this new instance to open) can be passed to the running instance with this function. Then, the application should terminate (or enter client mode). If isRunning() returns true, but sendMessage() fails, that is an indication that the running instance is frozen. Here's an example that shows how to convert an existing application to use QtSingleApplication. It is very simple and does not make use of all QtSingleApplication's functionality (see the examples for that). \code // Original int main(int argc, char **argv) { QApplication app(argc, argv); MyMainWidget mmw; mmw.show(); return app.exec(); } // Single instance int main(int argc, char **argv) { QtSingleApplication app(argc, argv); if (app.isRunning()) return !app.sendMessage(someDataString); MyMainWidget mmw; app.setActivationWindow(&mmw); mmw.show(); return app.exec(); } \endcode Once this QtSingleApplication instance is destroyed (normally when the process exits or crashes), when the user next attempts to run the application this instance will not, of course, be encountered. The next instance to call isRunning() or sendMessage() will assume the role as the new running instance. For console (non-GUI) applications, QtSingleCoreApplication may be used instead of this class, to avoid the dependency on the QtGui library. \sa QtSingleCoreApplication */ namespace kdk { void QtSingleApplication::sysInit(const QString &appId) { actWin = 0; peer = new QtLocalPeer(this, appId); connect(peer, SIGNAL(messageReceived(const QString &)), SIGNAL(messageReceived(const QString &))); } /*! Creates a QtSingleApplication object. The application identifier will be QCoreApplication::applicationFilePath(). \a argc, \a argv, and \a GUIenabled are passed on to the QAppliation constructor. If you are creating a console application (i.e. setting \a GUIenabled to false), you may consider using QtSingleCoreApplication instead. */ QtSingleApplication::QtSingleApplication(int &argc, char **argv, bool GUIenabled) : QApplication(argc, argv, GUIenabled) { sysInit(); } /*! Creates a QtSingleApplication object with the application identifier \a appId. \a argc and \a argv are passed on to the QAppliation constructor. */ QtSingleApplication::QtSingleApplication(const QString &appId, int &argc, char **argv) : QApplication(argc, argv) { sysInit(appId); } #if QT_VERSION < 0x050000 /*! Creates a QtSingleApplication object. The application identifier will be QCoreApplication::applicationFilePath(). \a argc, \a argv, and \a type are passed on to the QAppliation constructor. */ QtSingleApplication::QtSingleApplication(int &argc, char **argv, Type type) : QApplication(argc, argv, type) { sysInit(); } #if defined(Q_WS_X11) /*! Special constructor for X11, ref. the documentation of QApplication's corresponding constructor. The application identifier will be QCoreApplication::applicationFilePath(). \a dpy, \a visual, and \a cmap are passed on to the QApplication constructor. */ QtSingleApplication::QtSingleApplication(Display *dpy, Qt::HANDLE visual, Qt::HANDLE cmap) : QApplication(dpy, visual, cmap) { sysInit(); } /*! Special constructor for X11, ref. the documentation of QApplication's corresponding constructor. The application identifier will be QCoreApplication::applicationFilePath(). \a dpy, \a argc, \a argv, \a visual, and \a cmap are passed on to the QApplication constructor. */ QtSingleApplication::QtSingleApplication(Display *dpy, int &argc, char **argv, Qt::HANDLE visual, Qt::HANDLE cmap) : QApplication(dpy, argc, argv, visual, cmap) { sysInit(); } /*! Special constructor for X11, ref. the documentation of QApplication's corresponding constructor. The application identifier will be \a appId. \a dpy, \a argc, \a argv, \a visual, and \a cmap are passed on to the QApplication constructor. */ QtSingleApplication::QtSingleApplication(Display *dpy, const QString &appId, int argc, char **argv, Qt::HANDLE visual, Qt::HANDLE cmap) : QApplication(dpy, argc, argv, visual, cmap) { sysInit(appId); } #endif // Q_WS_X11 #endif // QT_VERSION < 0x050000 /*! Returns true if another instance of this application is running; otherwise false. This function does not find instances of this application that are being run by a different user (on Windows: that are running in another session). \sa sendMessage() */ bool QtSingleApplication::isRunning() { return peer->isClient(); } /*! Tries to send the text \a message to the currently running instance. The QtSingleApplication object in the running instance will emit the messageReceived() signal when it receives the message. This function returns true if the message has been sent to, and processed by, the current instance. If there is no instance currently running, or if the running instance fails to process the message within \a timeout milliseconds, this function return false. \sa isRunning(), messageReceived() */ bool QtSingleApplication::sendMessage(const QString &message, int timeout) { return peer->sendMessage(message, timeout); } /*! Returns the application identifier. Two processes with the same identifier will be regarded as instances of the same application. */ QString QtSingleApplication::id() const { return peer->applicationId(); } /*! Sets the activation window of this application to \a aw. The activation window is the widget that will be activated by activateWindow(). This is typically the application's main window. If \a activateOnMessage is true (the default), the window will be activated automatically every time a message is received, just prior to the messageReceived() signal being emitted. \sa activateWindow(), messageReceived() */ void QtSingleApplication::setActivationWindow(QWidget *aw, bool activateOnMessage) { actWin = aw; if (activateOnMessage) connect(peer, SIGNAL(messageReceived(const QString &)), this, SLOT(activateWindow())); else disconnect(peer, SIGNAL(messageReceived(const QString &)), this, SLOT(activateWindow())); } /*! Returns the applications activation window if one has been set by calling setActivationWindow(), otherwise returns 0. \sa setActivationWindow() */ QWidget *QtSingleApplication::activationWindow() const { return actWin; } /*! De-minimizes, raises, and activates this application's activation window. This function does nothing if no activation window has been set. This is a convenience function to show the user that this application instance has been activated when he has tried to start another instance. This function should typically be called in response to the messageReceived() signal. By default, that will happen automatically, if an activation window has been set. \sa setActivationWindow(), messageReceived(), initialize() */ void QtSingleApplication::activateWindow() { if (actWin) { // actWin->setWindowState(actWin->windowState() & ~Qt::WindowMinimized); // actWin->raise(); // actWin->activateWindow(); /* 改用窗管接口来激活界面 */ qDebug() << "kabase : activate window , window id is " << actWin->winId(); KX11Extras::forceActiveWindow(actWin->winId()); actWin->update(); } } /*! \fn void QtSingleApplication::messageReceived(const QString& message) This signal is emitted when the current instance receives a \a message from another instance of this application. \sa sendMessage(), setActivationWindow(), activateWindow() */ /*! \fn void QtSingleApplication::initialize(bool dummy = true) \obsolete */ } // namespace kdk libkysdk-applications/kysdk-alm/src/singleapplication/lockedfile.h0000664000175000017500000000652615104543305024453 0ustar fengfeng/**************************************************************************** ** ** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). ** Contact: http://www.qt-project.org/legal ** ** This file is part of the Qt Solutions component. ** ** $QT_BEGIN_LICENSE:BSD$ ** You may use this file under the terms of the BSD license as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names ** of its contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef KYSDK_ALM_SINGLEAPPLICATION_LOCKEDFILE_H_ #define KYSDK_ALM_SINGLEAPPLICATION_LOCKEDFILE_H_ #include #ifdef Q_OS_WIN #include #endif #if defined(Q_OS_WIN) #if !defined(QT_QTLOCKEDFILE_EXPORT) && !defined(QT_QTLOCKEDFILE_IMPORT) #define QT_QTLOCKEDFILE_EXPORT #elif defined(QT_QTLOCKEDFILE_IMPORT) #if defined(QT_QTLOCKEDFILE_EXPORT) #undef QT_QTLOCKEDFILE_EXPORT #endif #define QT_QTLOCKEDFILE_EXPORT __declspec(dllimport) #elif defined(QT_QTLOCKEDFILE_EXPORT) #undef QT_QTLOCKEDFILE_EXPORT #define QT_QTLOCKEDFILE_EXPORT __declspec(dllexport) #endif #else #define QT_QTLOCKEDFILE_EXPORT #endif /** * @since 1.2.0 */ namespace kdk { namespace QtLP_Private { class QT_QTLOCKEDFILE_EXPORT QtLockedFile : public QFile { public: enum LockMode { NoLock = 0, ReadLock, WriteLock }; QtLockedFile(); QtLockedFile(const QString &name); ~QtLockedFile(); bool open(OpenMode mode); bool lock(LockMode mode, bool block = true); bool unlock(); bool isLocked() const; LockMode lockMode() const; private: #ifdef Q_OS_WIN Qt::HANDLE wmutex; Qt::HANDLE rmutex; QVector rmutexes; QString mutexname; Qt::HANDLE getMutexHandle(int idx, bool doCreate); bool waitMutex(Qt::HANDLE mutex, bool doBlock); #endif LockMode m_lock_mode; }; } // namespace QtLP_Private } // namespace kdk #endif libkysdk-applications/kysdk-alm/src/singleapplication/lockedfile_unix.cpp0000664000175000017500000000655215104543305026050 0ustar fengfeng/**************************************************************************** ** ** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). ** Contact: http://www.qt-project.org/legal ** ** This file is part of the Qt Solutions component. ** ** $QT_BEGIN_LICENSE:BSD$ ** You may use this file under the terms of the BSD license as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names ** of its contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include #include #include #include #include "lockedfile.h" bool QtLockedFile::lock(LockMode mode, bool block) { if (!isOpen()) { qWarning("QtLockedFile::lock(): file is not opened"); return false; } if (mode == NoLock) return unlock(); if (mode == m_lock_mode) return true; if (m_lock_mode != NoLock) unlock(); struct flock fl; fl.l_whence = SEEK_SET; fl.l_start = 0; fl.l_len = 0; fl.l_type = (mode == ReadLock) ? F_RDLCK : F_WRLCK; int cmd = block ? F_SETLKW : F_SETLK; int ret = fcntl(handle(), cmd, &fl); if (ret == -1) { if (errno != EINTR && errno != EAGAIN) qWarning("QtLockedFile::lock(): fcntl: %s", strerror(errno)); return false; } m_lock_mode = mode; return true; } bool QtLockedFile::unlock() { if (!isOpen()) { qWarning("QtLockedFile::unlock(): file is not opened"); return false; } if (!isLocked()) return true; struct flock fl; fl.l_whence = SEEK_SET; fl.l_start = 0; fl.l_len = 0; fl.l_type = F_UNLCK; int ret = fcntl(handle(), F_SETLKW, &fl); if (ret == -1) { qWarning("QtLockedFile::lock(): fcntl: %s", strerror(errno)); return false; } m_lock_mode = NoLock; return true; } QtLockedFile::~QtLockedFile() { if (isOpen()) unlock(); }libkysdk-applications/kysdk-alm/src/singleapplication/lockedfile.cpp0000664000175000017500000001374015104543305025002 0ustar fengfeng/**************************************************************************** ** ** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). ** Contact: http://www.qt-project.org/legal ** ** This file is part of the Qt Solutions component. ** ** $QT_BEGIN_LICENSE:BSD$ ** You may use this file under the terms of the BSD license as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names ** of its contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "lockedfile.h" /*! \class QtLockedFile \brief The QtLockedFile class extends QFile with advisory locking functions. A file may be locked in read or write mode. Multiple instances of \e QtLockedFile, created in multiple processes running on the same machine, may have a file locked in read mode. Exactly one instance may have it locked in write mode. A read and a write lock cannot exist simultaneously on the same file. The file locks are advisory. This means that nothing prevents another process from manipulating a locked file using QFile or file system functions offered by the OS. Serialization is only guaranteed if all processes that access the file use QLockedFile. Also, while holding a lock on a file, a process must not open the same file again (through any API), or locks can be unexpectedly lost. The lock provided by an instance of \e QtLockedFile is released whenever the program terminates. This is true even when the program crashes and no destructors are called. */ /*! \enum QtLockedFile::LockMode This enum describes the available lock modes. \value ReadLock A read lock. \value WriteLock A write lock. \value NoLock Neither a read lock nor a write lock. */ /*! Constructs an unlocked \e QtLockedFile object. This constructor behaves in the same way as \e QFile::QFile(). \sa QFile::QFile() */ QtLockedFile::QtLockedFile() : QFile() { #ifdef Q_OS_WIN wmutex = 0; rmutex = 0; #endif m_lock_mode = NoLock; } /*! Constructs an unlocked QtLockedFile object with file \a name. This constructor behaves in the same way as \e QFile::QFile(const QString&). \sa QFile::QFile() */ QtLockedFile::QtLockedFile(const QString &name) : QFile(name) { #ifdef Q_OS_WIN wmutex = 0; rmutex = 0; #endif m_lock_mode = NoLock; } /*! Opens the file in OpenMode \a mode. This is identical to QFile::open(), with the one exception that the Truncate mode flag is disallowed. Truncation would conflict with the advisory file locking, since the file would be modified before the write lock is obtained. If truncation is required, use resize(0) after obtaining the write lock. Returns true if successful; otherwise false. \sa QFile::open(), QFile::resize() */ bool QtLockedFile::open(OpenMode mode) { if (mode & QIODevice::Truncate) { qWarning("QtLockedFile::open(): Truncate mode not allowed."); return false; } return QFile::open(mode); } /*! Returns \e true if this object has a in read or write lock; otherwise returns \e false. \sa lockMode() */ bool QtLockedFile::isLocked() const { return m_lock_mode != NoLock; } /*! Returns the type of lock currently held by this object, or \e QtLockedFile::NoLock. \sa isLocked() */ QtLockedFile::LockMode QtLockedFile::lockMode() const { return m_lock_mode; } /*! \fn bool QtLockedFile::lock(LockMode mode, bool block = true) Obtains a lock of type \a mode. The file must be opened before it can be locked. If \a block is true, this function will block until the lock is aquired. If \a block is false, this function returns \e false immediately if the lock cannot be aquired. If this object already has a lock of type \a mode, this function returns \e true immediately. If this object has a lock of a different type than \a mode, the lock is first released and then a new lock is obtained. This function returns \e true if, after it executes, the file is locked by this object, and \e false otherwise. \sa unlock(), isLocked(), lockMode() */ /*! \fn bool QtLockedFile::unlock() Releases a lock. If the object has no lock, this function returns immediately. This function returns \e true if, after it executes, the file is not locked by this object, and \e false otherwise. \sa lock(), isLocked(), lockMode() */ /*! \fn QtLockedFile::~QtLockedFile() Destroys the \e QtLockedFile object. If any locks were held, they are released. */libkysdk-applications/kysdk-alm/src/singleapplication/localpeer.cpp0000664000175000017500000001554715104543305024656 0ustar fengfeng/**************************************************************************** ** ** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). ** Contact: http://www.qt-project.org/legal ** ** This file is part of the Qt Solutions component. ** ** $QT_BEGIN_LICENSE:BSD$ ** You may use this file under the terms of the BSD license as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names ** of its contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include #include #include #include #include "localpeer.h" namespace kdk { #if defined(Q_OS_WIN) #include #include typedef BOOL(WINAPI *PProcessIdToSessionId)(DWORD, DWORD *); static PProcessIdToSessionId pProcessIdToSessionId = 0; #endif #if defined(Q_OS_UNIX) #include #include #include #endif namespace QtLP_Private { #include "lockedfile.cpp" #if defined(Q_OS_WIN) #include "qtlockedfile_win.cpp" #else #include "lockedfile_unix.cpp" #endif } // namespace QtLP_Private const char *QtLocalPeer::ack = "ack"; QtLocalPeer::QtLocalPeer(QObject *parent, const QString &appId) : QObject(parent) , id(appId) { QString prefix = id; if (id.isEmpty()) { id = QCoreApplication::applicationFilePath(); #if defined(Q_OS_WIN) id = id.toLower(); #endif prefix = id.section(QLatin1Char('/'), -1); } prefix.remove(QRegularExpression("[^a-zA-Z]")); prefix.truncate(6); QByteArray idc = id.toUtf8(); quint16 idNum = qChecksum(idc.constData(), idc.size()); socketName = QLatin1String("qtsingleapp-") + prefix + QLatin1Char('-') + QString::number(idNum, 16); #if defined(Q_OS_WIN) if (!pProcessIdToSessionId) { QLibrary lib("kernel32"); pProcessIdToSessionId = (PProcessIdToSessionId)lib.resolve("ProcessIdToSessionId"); } if (pProcessIdToSessionId) { DWORD sessionId = 0; pProcessIdToSessionId(GetCurrentProcessId(), &sessionId); socketName += QLatin1Char('-') + QString::number(sessionId, 16); } #else socketName += QLatin1Char('-') + QString::number(getuid(), 16); #endif server = new QLocalServer(this); QString lockName = QDir(QDir::tempPath()).absolutePath() + QLatin1Char('/') + socketName + QLatin1String("-lockfile"); lockFile.setFileName(lockName); lockFile.open(QIODevice::ReadWrite); } /* 服务端加锁 */ bool QtLocalPeer::isClient() { if (lockFile.isLocked()) return false; if (!lockFile.lock(QtLP_Private::QtLockedFile::WriteLock, false)) return true; bool res = server->listen(socketName); #if defined(Q_OS_UNIX) && (QT_VERSION >= QT_VERSION_CHECK(4, 5, 0)) // ### Workaround if (!res && server->serverError() == QAbstractSocket::AddressInUseError) { QFile::remove(QDir::cleanPath(QDir::tempPath()) + QLatin1Char('/') + socketName); res = server->listen(socketName); } #endif if (!res) qWarning("QtSingleCoreApplication: listen on local socket failed, %s", qPrintable(server->errorString())); QObject::connect(server, SIGNAL(newConnection()), SLOT(receiveConnection())); return false; } bool QtLocalPeer::sendMessage(const QString &message, int timeout) { if (!isClient()) return false; QLocalSocket socket; bool connOk = false; for (int i = 0; i < 2; i++) { // Try twice, in case the other instance is just starting up socket.connectToServer(socketName); connOk = socket.waitForConnected(timeout / 2); if (connOk || i) break; int ms = 250; #if defined(Q_OS_WIN) Sleep(DWORD(ms)); #else struct timespec ts = {ms / 1000, (ms % 1000) * 1000 * 1000}; nanosleep(&ts, NULL); #endif } if (!connOk) return false; QByteArray uMsg(message.toUtf8()); QDataStream ds(&socket); ds.writeBytes(uMsg.constData(), uMsg.size()); bool res = socket.waitForBytesWritten(timeout); if (res) { res &= socket.waitForReadyRead(timeout); // wait for ack if (res) res &= (socket.read(qstrlen(ack)) == ack); } return res; } void QtLocalPeer::receiveConnection() { QLocalSocket *socket = server->nextPendingConnection(); if (!socket) return; while (true) { if (socket->state() == QLocalSocket::UnconnectedState) { qWarning("QtLocalPeer: Peer disconnected"); delete socket; return; } if (socket->bytesAvailable() >= qint64(sizeof(quint32))) break; socket->waitForReadyRead(); } QDataStream ds(socket); QByteArray uMsg; quint32 remaining; ds >> remaining; uMsg.resize(remaining); int got = 0; char *uMsgBuf = uMsg.data(); do { got = ds.readRawData(uMsgBuf, remaining); remaining -= got; uMsgBuf += got; } while (remaining && got >= 0 && socket->waitForReadyRead(2000)); if (got < 0) { qWarning("QtLocalPeer: Message reception failed %s", socket->errorString().toLatin1().constData()); delete socket; return; } QString message(QString::fromUtf8(uMsg)); socket->write(ack, qstrlen(ack)); socket->waitForBytesWritten(1000); socket->waitForDisconnected(1000); // make sure client reads ack delete socket; Q_EMIT messageReceived(message); // ### (might take a long time to return) } } // namespace kdk libkysdk-applications/doxygen/0000775000175000017500000000000015104543305015455 5ustar fengfenglibkysdk-applications/doxygen/man/0000775000175000017500000000000015104515306016230 5ustar fengfenglibkysdk-applications/doxygen/man/man3/0000775000175000017500000000000015104543305017066 5ustar fengfenglibkysdk-applications/doxygen/man/man3/CommentsPanel.30000664000175000017500000000044415104543305021721 0ustar fengfeng.TH "CommentsPanel" 3 "Version version:3.0" "LIBKYSDK-APPLICATIONS" \" -*- nroff -*- .ad l .nh .SH NAME CommentsPanel \- CommentsPanel .SH SYNOPSIS .br .PP .SH "Detailed Description" .PP .SH "Author" .PP Generated automatically by Doxygen for LIBKYSDK-APPLICATIONS from the source code\&. libkysdk-applications/doxygen/man/man3/kdk_KLoopPlayPage.30000664000175000017500000000405715104543305022460 0ustar fengfeng.TH "kdk::KLoopPlayPage" 3 "Version version:3.0" "LIBKYSDK-APPLICATIONS" \" -*- nroff -*- .ad l .nh .SH NAME kdk::KLoopPlayPage .SH SYNOPSIS .br .PP .PP Inherits QWidget\&. .SS "Signals" .in +1c .ti -1c .RI "void \fBleftClick\fP ()" .br .ti -1c .RI "void \fBcenterClick\fP ()" .br .ti -1c .RI "void \fBrightClick\fP ()" .br .in -1c .SS "Public Member Functions" .in +1c .ti -1c .RI "\fBKLoopPlayPage\fP (QWidget *parent=nullptr)" .br .ti -1c .RI "void \fBaddWidget\fP (QWidget *widget)" .br .RI "添加widget " .ti -1c .RI "void \fBremoveWidget\fP (QWidget *widget)" .br .RI "删除widget " .ti -1c .RI "void \fBsetCurrentWidget\fP (int i)" .br .RI "设置当前中心界面 " .ti -1c .RI "int \fBcurrentWidget\fP ()" .br .RI "获取当前中心界面index " .ti -1c .RI "void \fBsetWidgetSpacing\fP (int spacing)" .br .RI "设置窗体间距 " .ti -1c .RI "void \fBsetLoopTime\fP (int time)" .br .RI "设置轮播时长 " .in -1c .SS "Protected Member Functions" .in +1c .ti -1c .RI "void \fBresizeEvent\fP (QResizeEvent *event)" .br .ti -1c .RI "void \fBpaintEvent\fP (QPaintEvent *event)" .br .ti -1c .RI "void \fBshowEvent\fP (QShowEvent *event) override" .br .in -1c .SH "Member Function Documentation" .PP .SS "void kdk::KLoopPlayPage::addWidget (QWidget * widget)" .PP 添加widget .PP \fBParameters\fP .RS 4 \fIwidget\fP .RE .PP .SS "int kdk::KLoopPlayPage::currentWidget ()" .PP 获取当前中心界面index .PP \fBReturns\fP .RS 4 .RE .PP .SS "void kdk::KLoopPlayPage::removeWidget (QWidget * widget)" .PP 删除widget .PP \fBParameters\fP .RS 4 \fIwidget\fP .RE .PP .SS "void kdk::KLoopPlayPage::setCurrentWidget (int i)" .PP 设置当前中心界面 .PP \fBParameters\fP .RS 4 \fIi\fP .RE .PP .SS "void kdk::KLoopPlayPage::setLoopTime (int time)" .PP 设置轮播时长 .PP \fBParameters\fP .RS 4 \fItime\fP .RE .PP .SS "void kdk::KLoopPlayPage::setWidgetSpacing (int spacing)" .PP 设置窗体间距 .PP \fBParameters\fP .RS 4 \fIspacing\fP .RE .PP .SH "Author" .PP Generated automatically by Doxygen for LIBKYSDK-APPLICATIONS from the source code\&. libkysdk-applications/doxygen/man/man3/kdk_KListView.30000664000175000017500000000154615104543305021672 0ustar fengfeng.TH "kdk::KListView" 3 "Version version:3.0" "LIBKYSDK-APPLICATIONS" \" -*- nroff -*- .ad l .nh .SH NAME kdk::KListView \- 配合KListviewdelegate可以提供一个图片两行文字的显示效果,若只有一行文字,则对于 icon 居中显示 。 .SH SYNOPSIS .br .PP .PP \fC#include \fP .PP Inherits QListView\&. .SS "Public Member Functions" .in +1c .ti -1c .RI "\fBKListView\fP (QWidget *parent)" .br .in -1c .SS "Protected Member Functions" .in +1c .ti -1c .RI "void \fBmousePressEvent\fP (QMouseEvent *event)" .br .in -1c .SH "Detailed Description" .PP 配合KListviewdelegate可以提供一个图片两行文字的显示效果,若只有一行文字,则对于 icon 居中显示 。 .PP \fBSince\fP .RS 4 1\&.2\&.0 .RE .PP .SH "Author" .PP Generated automatically by Doxygen for LIBKYSDK-APPLICATIONS from the source code\&. libkysdk-applications/doxygen/man/man3/kdk_KWidget.30000664000175000017500000000564515104543305021353 0ustar fengfeng.TH "kdk::KWidget" 3 "Version version:3.0" "LIBKYSDK-APPLICATIONS" \" -*- nroff -*- .ad l .nh .SH NAME kdk::KWidget \- 继承自QWidget,支持响应主题背景切换,图标主题切换,标题颜色响应窗口激活状态,内容区域分为side区和base区 .SH SYNOPSIS .br .PP .PP \fC#include \fP .PP Inherits QWidget, and ThemeController\&. .SS "Public Member Functions" .in +1c .ti -1c .RI "\fBKWidget\fP (QWidget *parent=nullptr)" .br .ti -1c .RI "void \fBsetIcon\fP (const QIcon &icon)" .br .RI "设置窗体图标 " .ti -1c .RI "void \fBsetIcon\fP (const QString &iconName)" .br .RI "设置窗体图标 " .ti -1c .RI "void \fBsetWidgetName\fP (const QString &widgetName)" .br .RI "设置窗体名称 " .ti -1c .RI "QWidget * \fBsideBar\fP ()" .br .RI "获取左边栏widget,通过setlayout添加自定义内容 " .ti -1c .RI "QWidget * \fBbaseBar\fP ()" .br .RI "获取主内容区widget,通过setlayout添加自定义内容 " .ti -1c .RI "\fBKWindowButtonBar\fP * \fBwindowButtonBar\fP ()" .br .RI "获取窗口三联组合控件,以控制是否显示最大化、最小化按钮和下拉菜单按钮;也可增加自定义按钮 " .ti -1c .RI "\fBKIconBar\fP * \fBiconBar\fP ()" .br .RI "获取窗口标题、图标组合控件,以控制相关样式 " .ti -1c .RI "void \fBsetLayoutType\fP (\fBLayoutType\fP type)" .br .RI "设置布局结构类型 " .ti -1c .RI "void \fBsetWindowFlags\fP (Qt::WindowFlags type)" .br .RI "设置窗口标志 " .ti -1c .RI "void \fBsetWindowFlag\fP (Qt::WindowType flag, bool on=true)" .br .RI "设置窗口标志 " .ti -1c .RI "void \fBsetSidebarFollowMode\fP (bool flag)" .br .RI "设置sidebar是否遵循系统更改宽度 " .ti -1c .RI "bool \fBsidebarFollowMode\fP ()" .br .RI "返回sidebar是否遵循系统更改宽度 " .in -1c .SS "Protected Member Functions" .in +1c .ti -1c .RI "bool \fBeventFilter\fP (QObject *target, QEvent *event) override" .br .ti -1c .RI "virtual void \fBchangeIconStyle\fP ()" .br .ti -1c .RI "virtual void \fBchangeTheme\fP ()" .br .in -1c .SH "Detailed Description" .PP 继承自QWidget,支持响应主题背景切换,图标主题切换,标题颜色响应窗口激活状态,内容区域分为side区和base区 .PP \fBSince\fP .RS 4 1\&.0\&.0 .RE .PP .PP \fBExamples\fP .in +1c \fBtestDialog/widget\&.h\fP, \fBtestPushbutton/widget\&.h\fP, \fBtestWidget/testwidget\&.h\fP, \fBtestbadge/widget\&.h\fP, \fBtestballontip/widget\&.h\fP, \fBtestinputdialog/widget\&.cpp\fP, \fBtestinputdialog/widget\&.h\fP, \fBtestnavigationbar/widget\&.h\fP, \fBtestpasswordedit/widget\&.h\fP, \fBtestprogressbar/widget\&.h\fP, \fBtestprogressdialog/widget\&.cpp\fP, \fBtestprogressdialog/widget\&.h\fP, \fBtestsearchlinedit/widget\&.h\fP, \fBtestsecuritylevelbar/widget\&.h\fP, \fBtestslider/widget\&.h\fP, \fBtesttabbar/widget\&.h\fP, and \fBtesttoolbutton/widget\&.h\fP\&. .SH "Author" .PP Generated automatically by Doxygen for LIBKYSDK-APPLICATIONS from the source code\&. libkysdk-applications/doxygen/man/man3/kdk_KSliderFrame.30000664000175000017500000000635215104543305022321 0ustar fengfeng.TH "kdk::KSliderFrame" 3 "Version version:3.0" "LIBKYSDK-APPLICATIONS" \" -*- nroff -*- .ad l .nh .SH NAME kdk::KSliderFrame .SH SYNOPSIS .br .PP .PP Inherits \fBkdk::KBaseFrame\fP\&. .SS "Public Member Functions" .in +1c .ti -1c .RI "\fBKSliderFrame\fP (QString title, bool hasNode, QWidget *parent=nullptr, \fBBorderRadiusStyle\fP style=\fBBorderRadiusStyle::None\fP, Qt::Orientation orientation=Qt::Horizontal)" .br .RI "创建一个带 \fBKSlider\fP 的 Frame " .ti -1c .RI "\fBKSlider\fP * \fBslider\fP ()" .br .RI "获取 m_slider " .ti -1c .RI "QLabel * \fBleftLabel\fP ()" .br .RI "获取滑动条左侧label " .ti -1c .RI "QLabel * \fBrightLabel\fP ()" .br .RI "获取滑动条右侧label " .ti -1c .RI "\fBKLabel\fP * \fBtitleLabel\fP ()" .br .RI "获取label " .ti -1c .RI "QHBoxLayout * \fBmainHLayout\fP ()" .br .RI "获取layout " .in -1c Public Member Functions inherited from \fBkdk::KBaseFrame\fP .in +1c .ti -1c .RI "\fBKBaseFrame\fP (QWidget *parent=nullptr, \fBBorderRadiusStyle\fP style=\fBAround\fP, bool heightAdaptive=false)" .br .RI "构造函数 " .ti -1c .RI "void \fBsetRadiusType\fP (\fBBorderRadiusStyle\fP style)" .br .RI "设置圆角风格 " .ti -1c .RI "bool \fBgetTabletMode\fP ()" .br .RI "获取平板模式 " .ti -1c .RI "bool \fBisContainer\fP ()" .br .RI "获取是否是一个容器frame,此时settinggroup需要设置的是其子frame的圆角 " .ti -1c .RI "void \fBsetContainer\fP (bool b=false)" .br .RI "设置该frame是否是一个容器frame,如果是同时setFrameShape(NoFrame); " .in -1c .SS "Additional Inherited Members" Public Types inherited from \fBkdk::KBaseFrame\fP .in +1c .ti -1c .RI "enum \fBBorderRadiusStyle\fP { \fBTop\fP, \fBNone\fP, \fBBottom\fP, \fBAround\fP }" .br .in -1c Signals inherited from \fBkdk::KBaseFrame\fP .in +1c .ti -1c .RI "void \fBtabletModeChanged\fP (bool b)" .br .in -1c Protected Member Functions inherited from \fBkdk::KBaseFrame\fP .in +1c .ti -1c .RI "void \fBpaintEvent\fP (QPaintEvent *e)" .br .in -1c .SH "Constructor & Destructor Documentation" .PP .SS "kdk::KSliderFrame::KSliderFrame (QString title, bool hasNode, QWidget * parent = \fCnullptr\fP, \fBBorderRadiusStyle\fP style = \fC\fBBorderRadiusStyle::None\fP\fP, Qt::Orientation orientation = \fCQt::Horizontal\fP)\fC [explicit]\fP" .PP 创建一个带 \fBKSlider\fP 的 Frame .PP \fBParameters\fP .RS 4 \fItitle\fP text of m_settingName .br \fIhasNode\fP 是否带节点 .br \fIstyle\fP 设置圆角(None:无圆角,Top:上圆角,Bottom:下圆角,Around:四圆角) .br \fIparent\fP .RE .PP .SH "Member Function Documentation" .PP .SS "QLabel * kdk::KSliderFrame::leftLabel ()" .PP 获取滑动条左侧label .PP \fBReturns\fP .RS 4 QLabel .RE .PP .SS "QHBoxLayout * kdk::KSliderFrame::mainHLayout ()" .PP 获取layout .PP \fBReturns\fP .RS 4 QHBoxLayout .RE .PP .SS "QLabel * kdk::KSliderFrame::rightLabel ()" .PP 获取滑动条右侧label .PP \fBReturns\fP .RS 4 QLabel .RE .PP .SS "\fBKSlider\fP * kdk::KSliderFrame::slider ()" .PP 获取 m_slider .PP \fBReturns\fP .RS 4 \fBKSlider\fP .RE .PP .SS "\fBKLabel\fP * kdk::KSliderFrame::titleLabel ()" .PP 获取label .PP \fBReturns\fP .RS 4 QLabel .RE .PP .SH "Author" .PP Generated automatically by Doxygen for LIBKYSDK-APPLICATIONS from the source code\&. libkysdk-applications/doxygen/man/man3/DragModule.30000664000175000017500000000043515104543305021177 0ustar fengfeng.TH "DragModule" 3 "Version version:3.0" "LIBKYSDK-APPLICATIONS" \" -*- nroff -*- .ad l .nh .SH NAME DragModule \- DragModule .SH SYNOPSIS .br .PP .SH "Detailed Description" .PP { .SH "Author" .PP Generated automatically by Doxygen for LIBKYSDK-APPLICATIONS from the source code\&. libkysdk-applications/doxygen/man/man3/ProgressModule.30000664000175000017500000000052715104543305022130 0ustar fengfeng.TH "ProgressModule" 3 "Version version:3.0" "LIBKYSDK-APPLICATIONS" \" -*- nroff -*- .ad l .nh .SH NAME ProgressModule \- ProgressModule .SH SYNOPSIS .br .PP .SH "Detailed Description" .PP .PP \fBSince\fP .RS 4 2\&.5\&.2\&.0 { .RE .PP .SH "Author" .PP Generated automatically by Doxygen for LIBKYSDK-APPLICATIONS from the source code\&. libkysdk-applications/doxygen/man/man3/TextEditModule.30000664000175000017500000000052715104543305022056 0ustar fengfeng.TH "TextEditModule" 3 "Version version:3.0" "LIBKYSDK-APPLICATIONS" \" -*- nroff -*- .ad l .nh .SH NAME TextEditModule \- TextEditModule .SH SYNOPSIS .br .PP .SH "Detailed Description" .PP .PP \fBSince\fP .RS 4 2\&.5\&.2\&.0 { .RE .PP .SH "Author" .PP Generated automatically by Doxygen for LIBKYSDK-APPLICATIONS from the source code\&. libkysdk-applications/doxygen/man/man3/SliderModule.30000664000175000017500000000760115104543305021546 0ustar fengfeng.TH "SliderModule" 3 "Version version:3.0" "LIBKYSDK-APPLICATIONS" \" -*- nroff -*- .ad l .nh .SH NAME SliderModule \- SliderModule .SH SYNOPSIS .br .PP .SS "Classes" .in +1c .ti -1c .RI "class \fBkdk::KSlider\fP" .br .RI "支持三种样式的滑动条 非步数关系:步数为1,可以在任意位置点击和拖拽 步数关系:步数为固定值,可根据步数值点击和拖拽 节点关系:步数为节点间隔,可根据节点间隔点击和拖拽 " .in -1c .SS "Enumerations" .in +1c .ti -1c .RI "enum \fBKSliderType\fP { \fBSmoothSlider\fP, \fBStepSlider\fP, \fBNodeSlider\fP, \fBSingleSelectSlider\fP }" .br .in -1c .SS "Functions" .in +1c .ti -1c .RI "\fBkdk::KSlider::KSlider\fP (QWidget *parent)" .br .ti -1c .RI "\fBkdk::KSlider::KSlider\fP (Qt::Orientation orientation, QWidget *parent=nullptr)" .br .ti -1c .RI "void \fBkdk::KSlider::setTickInterval\fP (int interval)" .br .RI "设置节点间隔 " .ti -1c .RI "void \fBkdk::KSlider::setSliderType\fP (KSliderType type)" .br .RI "设置滑动条类型 " .ti -1c .RI "KSliderType \fBkdk::KSlider::sliderType\fP ()" .br .RI "获取滑动条类型 " .ti -1c .RI "int \fBkdk::KSlider::tickInterval\fP () const" .br .RI "获取节点间隔 " .ti -1c .RI "void \fBkdk::KSlider::setValue\fP (int)" .br .RI "设置值 " .ti -1c .RI "void \fBkdk::KSlider::setNodeVisible\fP (bool flag)" .br .RI "设置是否显示节点 " .ti -1c .RI "bool \fBkdk::KSlider::nodeVisible\fP ()" .br .RI "获取是否显示节点 " .ti -1c .RI "void \fBkdk::KSlider::setToolTip\fP (const QString &)" .br .RI "设置tooltip " .ti -1c .RI "QString \fBkdk::KSlider::toolTip\fP () const" .br .RI "获取toolTip " .ti -1c .RI "void \fBkdk::KSlider::setTranslucent\fP (bool flag)" .br .RI "设置是否启用半透明效果 " .ti -1c .RI "bool \fBkdk::KSlider::isTranslucent\fP ()" .br .RI "获取是否启用半透明效果 " .ti -1c .RI "void \fBkdk::KSlider::paintEvent\fP (QPaintEvent *event)" .br .ti -1c .RI "void \fBkdk::KSlider::resizeEvent\fP (QResizeEvent *event)" .br .ti -1c .RI "void \fBkdk::KSlider::mousePressEvent\fP (QMouseEvent *event)" .br .ti -1c .RI "void \fBkdk::KSlider::mouseReleaseEvent\fP (QMouseEvent *event)" .br .ti -1c .RI "void \fBkdk::KSlider::mouseMoveEvent\fP (QMouseEvent *event)" .br .ti -1c .RI "void \fBkdk::KSlider::wheelEvent\fP (QWheelEvent *event)" .br .ti -1c .RI "bool \fBkdk::KSlider::eventFilter\fP (QObject *watched, QEvent *event)" .br .ti -1c .RI "QSize \fBkdk::KSlider::sizeHint\fP () const override" .br .in -1c .SH "Detailed Description" .PP .SH "Function Documentation" .PP .SS "bool kdk::KSlider::isTranslucent ()" .PP 获取是否启用半透明效果 .PP \fBSince\fP .RS 4 1\&.2\&.0 .RE .PP \fBReturns\fP .RS 4 flag .RE .PP .SS "bool kdk::KSlider::nodeVisible ()" .PP 获取是否显示节点 .PP \fBReturns\fP .RS 4 .RE .PP .SS "void kdk::KSlider::setNodeVisible (bool flag)" .PP 设置是否显示节点 .PP \fBReturns\fP .RS 4 .RE .PP .SS "void kdk::KSlider::setSliderType (KSliderType type)" .PP 设置滑动条类型 .PP \fBParameters\fP .RS 4 \fItype\fP .RE .PP .SS "void kdk::KSlider::setTickInterval (int interval)" .PP 设置节点间隔 .PP \fBParameters\fP .RS 4 \fIinterval\fP .RE .PP .SS "void kdk::KSlider::setToolTip (const QString &)" .PP 设置tooltip .PP \fBSince\fP .RS 4 1\&.2\&.0 .RE .PP .SS "void kdk::KSlider::setTranslucent (bool flag)" .PP 设置是否启用半透明效果 .PP \fBSince\fP .RS 4 1\&.2\&.0 .RE .PP \fBParameters\fP .RS 4 \fIflag\fP .RE .PP .SS "KSliderType kdk::KSlider::sliderType ()" .PP 获取滑动条类型 .PP \fBReturns\fP .RS 4 .RE .PP .SS "int kdk::KSlider::tickInterval () const" .PP 获取节点间隔 .PP \fBReturns\fP .RS 4 .RE .PP .SS "QString kdk::KSlider::toolTip () const" .PP 获取toolTip .PP \fBSince\fP .RS 4 1\&.2\&.0 .RE .PP \fBReturns\fP .RS 4 .RE .PP .SH "Author" .PP Generated automatically by Doxygen for LIBKYSDK-APPLICATIONS from the source code\&. libkysdk-applications/doxygen/man/man3/kdk_KAddButton.30000664000175000017500000000264515104543305022011 0ustar fengfeng.TH "kdk::KAddButton" 3 "Version version:3.0" "LIBKYSDK-APPLICATIONS" \" -*- nroff -*- .ad l .nh .SH NAME kdk::KAddButton .SH SYNOPSIS .br .PP .PP Inherits QPushButton\&. .SS "Signals" .in +1c .ti -1c .RI "void \fBtabletModeChanged\fP (bool b)" .br .in -1c .SS "Public Member Functions" .in +1c .ti -1c .RI "\fBKAddButton\fP (QWidget *parent=nullptr, \fBKBaseFrame::BorderRadiusStyle\fP style=\fBKBaseFrame::BorderRadiusStyle::Bottom\fP, bool heightAdaptive=true)" .br .ti -1c .RI "void \fBsetRadiusType\fP (\fBKBaseFrame::BorderRadiusStyle\fP style)" .br .RI "设置圆角模式 " .ti -1c .RI "bool \fBgetTabletMode\fP ()" .br .RI "获取平板模式 " .ti -1c .RI "void \fBsetHeightAdaptive\fP (bool flag)" .br .RI "设置高度是否自适应 " .in -1c .SS "Protected Member Functions" .in +1c .ti -1c .RI "void \fBpaintEvent\fP (QPaintEvent *event)" .br .in -1c .SH "Member Function Documentation" .PP .SS "bool kdk::KAddButton::getTabletMode ()" .PP 获取平板模式 .PP \fBReturns\fP .RS 4 bool 是否是平板模式 .RE .PP .SS "void kdk::KAddButton::setHeightAdaptive (bool flag)" .PP 设置高度是否自适应 .PP \fBParameters\fP .RS 4 \fIflag\fP .RE .PP .SS "void kdk::KAddButton::setRadiusType (\fBKBaseFrame::BorderRadiusStyle\fP style)" .PP 设置圆角模式 .PP \fBParameters\fP .RS 4 \fIstyle\fP .RE .PP .SH "Author" .PP Generated automatically by Doxygen for LIBKYSDK-APPLICATIONS from the source code\&. libkysdk-applications/doxygen/man/man3/kdk_KLunarCalendarInfo.30000664000175000017500000001251015104543305023444 0ustar fengfeng.TH "kdk::KLunarCalendarInfo" 3 "Version version:3.0" "LIBKYSDK-APPLICATIONS" \" -*- nroff -*- .ad l .nh .SH NAME kdk::KLunarCalendarInfo .SH SYNOPSIS .br .PP .PP Inherits QObject\&. .SS "Public Member Functions" .in +1c .ti -1c .RI "\fBKLunarCalendarInfo\fP (QObject *parent=0)" .br .ti -1c .RI "bool \fBisLoopYear\fP (int year)" .br .RI "计算是否闰年 " .ti -1c .RI "int \fBgetMonthDays\fP (int year, int month)" .br .RI "计算指定年月该月共多少天 " .ti -1c .RI "int \fBgetTotalMonthDays\fP (int year, int month)" .br .RI "计算指定年月对应到该月共多少天 " .ti -1c .RI "int \fBgetFirstDayOfWeek\fP (int year, int month, bool FirstDayisSun)" .br .RI "计算指定年月对应星期几 " .ti -1c .RI "QString \fBgetHoliday\fP (int month, int day)" .br .RI "计算国际节日 " .ti -1c .RI "QString \fBgetSolarTerms\fP (int year, int month, int day)" .br .RI "计算二十四节气 " .ti -1c .RI "QString \fBgetLunarFestival\fP (int month, int day)" .br .RI "计算农历节日(必须传入农历年份月份) " .ti -1c .RI "QString \fBgetLunarYear\fP (int year)" .br .RI "计算农历年 天干+地支+生肖 " .ti -1c .RI "void \fBgetLunarCalendarInfo\fP (int year, int month, int day, QString &strHoliday, QString &strSolarTerms, QString &strLunarFestival, QString &strLunarYear, QString &strLunarMonth, QString &strLunarDay)" .br .RI "计算指定年月日农历信息,包括公历节日和农历节日及二十四节气 " .ti -1c .RI "QString \fBgetLunarInfo\fP (int year, int month, int day, bool yearInfo, bool monthInfo, bool dayInfo)" .br .RI "获取指定年月日农历信息 " .ti -1c .RI "QString \fBgetLunarYearMonthDay\fP (int year, int month, int day)" .br .RI "获取农历年月日 " .ti -1c .RI "QString \fBgetLunarMonthDay\fP (int year, int month, int day)" .br .RI "获取农历月日 " .ti -1c .RI "QString \fBgetLunarDay\fP (int year, int month, int day)" .br .RI "获取农历日 " .in -1c .SS "Static Public Member Functions" .in +1c .ti -1c .RI "static \fBKLunarCalendarInfo\fP * \fBInstance\fP ()" .br .in -1c .SH "Member Function Documentation" .PP .SS "int kdk::KLunarCalendarInfo::getFirstDayOfWeek (int year, int month, bool FirstDayisSun)" .PP 计算指定年月对应星期几 .PP \fBParameters\fP .RS 4 \fIyear\fP .br \fImonth\fP .br \fIFirstDayisSun:第一天是否以周日开始\fP .RE .PP \fBReturns\fP .RS 4 .RE .PP .SS "QString kdk::KLunarCalendarInfo::getHoliday (int month, int day)" .PP 计算国际节日 .PP \fBParameters\fP .RS 4 \fImonth\fP .br \fIday\fP .RE .PP \fBReturns\fP .RS 4 .RE .PP .SS "void kdk::KLunarCalendarInfo::getLunarCalendarInfo (int year, int month, int day, QString & strHoliday, QString & strSolarTerms, QString & strLunarFestival, QString & strLunarYear, QString & strLunarMonth, QString & strLunarDay)" .PP 计算指定年月日农历信息,包括公历节日和农历节日及二十四节气 .PP \fBParameters\fP .RS 4 \fIyear\fP .br \fImonth\fP .br \fIday\fP .br \fIstrHoliday\fP .br \fIstrSolarTerms\fP .br \fIstrLunarFestival\fP .br \fIstrLunarYear\fP .br \fIstrLunarMonth\fP .br \fIstrLunarDay\fP .RE .PP .SS "QString kdk::KLunarCalendarInfo::getLunarDay (int year, int month, int day)" .PP 获取农历日 .PP \fBParameters\fP .RS 4 \fIyear\fP .br \fImonth\fP .br \fIday\fP .RE .PP \fBReturns\fP .RS 4 .RE .PP .SS "QString kdk::KLunarCalendarInfo::getLunarFestival (int month, int day)" .PP 计算农历节日(必须传入农历年份月份) .PP \fBParameters\fP .RS 4 \fImonth\fP .br \fIday\fP .RE .PP \fBReturns\fP .RS 4 .RE .PP .SS "QString kdk::KLunarCalendarInfo::getLunarInfo (int year, int month, int day, bool yearInfo, bool monthInfo, bool dayInfo)" .PP 获取指定年月日农历信息 .PP \fBParameters\fP .RS 4 \fIyear\fP .br \fImonth\fP .br \fIday\fP .br \fIyearInfo\fP .br \fImonthInfo\fP .br \fIdayInfo\fP .RE .PP \fBReturns\fP .RS 4 .RE .PP .SS "QString kdk::KLunarCalendarInfo::getLunarMonthDay (int year, int month, int day)" .PP 获取农历月日 .PP \fBParameters\fP .RS 4 \fIyear\fP .br \fImonth\fP .br \fIday\fP .RE .PP \fBReturns\fP .RS 4 .RE .PP .SS "QString kdk::KLunarCalendarInfo::getLunarYear (int year)" .PP 计算农历年 天干+地支+生肖 .PP \fBParameters\fP .RS 4 \fIyear\fP .RE .PP \fBReturns\fP .RS 4 .RE .PP .SS "QString kdk::KLunarCalendarInfo::getLunarYearMonthDay (int year, int month, int day)" .PP 获取农历年月日 .PP \fBParameters\fP .RS 4 \fIyear\fP .br \fImonth\fP .br \fIday\fP .RE .PP \fBReturns\fP .RS 4 .RE .PP .SS "int kdk::KLunarCalendarInfo::getMonthDays (int year, int month)" .PP 计算指定年月该月共多少天 .PP \fBParameters\fP .RS 4 \fIyear\fP .br \fImonth\fP .RE .PP \fBReturns\fP .RS 4 .RE .PP .SS "QString kdk::KLunarCalendarInfo::getSolarTerms (int year, int month, int day)" .PP 计算二十四节气 .PP \fBParameters\fP .RS 4 \fIyear\fP .br \fImonth\fP .br \fIday\fP .RE .PP \fBReturns\fP .RS 4 .RE .PP .SS "int kdk::KLunarCalendarInfo::getTotalMonthDays (int year, int month)" .PP 计算指定年月对应到该月共多少天 .PP \fBParameters\fP .RS 4 \fIyear\fP .br \fImonth\fP .RE .PP \fBReturns\fP .RS 4 .RE .PP .SS "bool kdk::KLunarCalendarInfo::isLoopYear (int year)" .PP 计算是否闰年 .PP \fBParameters\fP .RS 4 \fIyear\fP .RE .PP \fBReturns\fP .RS 4 .RE .PP .SH "Author" .PP Generated automatically by Doxygen for LIBKYSDK-APPLICATIONS from the source code\&. libkysdk-applications/doxygen/man/man3/TagModule.30000664000175000017500000000043215104543305021032 0ustar fengfeng.TH "TagModule" 3 "Version version:3.0" "LIBKYSDK-APPLICATIONS" \" -*- nroff -*- .ad l .nh .SH NAME TagModule \- TagModule .SH SYNOPSIS .br .PP .SH "Detailed Description" .PP { .SH "Author" .PP Generated automatically by Doxygen for LIBKYSDK-APPLICATIONS from the source code\&. libkysdk-applications/doxygen/man/man3/WindowManagerModule.30000664000175000017500000000046615104543305023070 0ustar fengfeng.TH "WindowManagerModule" 3 "Version version:3.0" "LIBKYSDK-APPLICATIONS" \" -*- nroff -*- .ad l .nh .SH NAME WindowManagerModule \- WindowManagerModule .SH SYNOPSIS .br .PP .SH "Detailed Description" .PP .SH "Author" .PP Generated automatically by Doxygen for LIBKYSDK-APPLICATIONS from the source code\&. libkysdk-applications/doxygen/man/man3/kdk_KVLineFrame.30000664000175000017500000000127615104543305022114 0ustar fengfeng.TH "kdk::KVLineFrame" 3 "Version version:3.0" "LIBKYSDK-APPLICATIONS" \" -*- nroff -*- .ad l .nh .SH NAME kdk::KVLineFrame .SH SYNOPSIS .br .PP .PP Inherits QFrame\&. .SS "Public Member Functions" .in +1c .ti -1c .RI "\fBKVLineFrame\fP (QWidget *parent=nullptr)" .br .ti -1c .RI "void \fBsetFollowPalette\fP (bool flag)" .br .RI "设置是否遵循默认色板 " .in -1c .SH "Member Function Documentation" .PP .SS "void kdk::KVLineFrame::setFollowPalette (bool flag)" .PP 设置是否遵循默认色板 .PP \fBParameters\fP .RS 4 \fIflag\fP .RE .PP \fBSince\fP .RS 4 2\&.4\&.1\&.0 .RE .PP .SH "Author" .PP Generated automatically by Doxygen for LIBKYSDK-APPLICATIONS from the source code\&. libkysdk-applications/doxygen/man/man3/kdk_KUninstallDialog.30000664000175000017500000000464315104543305023216 0ustar fengfeng.TH "kdk::KUninstallDialog" 3 "Version version:3.0" "LIBKYSDK-APPLICATIONS" \" -*- nroff -*- .ad l .nh .SH NAME kdk::KUninstallDialog \- 卸载对话框,当用户卸载时可能会弹出此提示对话框 .SH SYNOPSIS .br .PP .PP \fC#include \fP .PP Inherits \fBkdk::KDialog\fP\&. .SS "Public Member Functions" .in +1c .ti -1c .RI "\fBKUninstallDialog\fP (QString appName, QString appVersion, QWidget *parent=nullptr)" .br .ti -1c .RI "QLabel * \fBdebAppNameLabel\fP ()" .br .RI "debAppNameLabel " .ti -1c .RI "QLabel * \fBdebNameLabel\fP ()" .br .RI "包名Label " .ti -1c .RI "QLabel * \fBdebIconLabel\fP ()" .br .RI "包IconLabel " .ti -1c .RI "QLabel * \fBdebVersionLabel\fP ()" .br .RI "包版本Label " .ti -1c .RI "QPushButton * \fBuninstallButtton\fP ()" .br .RI "卸载按钮 " .in -1c Public Member Functions inherited from \fBkdk::KDialog\fP .in +1c .ti -1c .RI "\fBKDialog\fP (QWidget *parent=nullptr)" .br .ti -1c .RI "void \fBsetWindowIcon\fP (const QIcon &icon)" .br .RI "设置对话框图标 " .ti -1c .RI "void \fBsetWindowIcon\fP (const QString &iconName)" .br .RI "设置对话框图标 " .ti -1c .RI "void \fBsetWindowTitle\fP (const QString &)" .br .RI "设置对话框标题名称 " .ti -1c .RI "QPushButton * \fBmaximumButton\fP ()" .br .RI "获取最大化按钮 " .ti -1c .RI "QPushButton * \fBminimumButton\fP ()" .br .RI "获取最小化按钮 " .ti -1c .RI "QPushButton * \fBcloseButton\fP ()" .br .RI "获取关闭按钮 " .ti -1c .RI "\fBKMenuButton\fP * \fBmenuButton\fP ()" .br .RI "获取下拉菜单按钮 " .ti -1c .RI "QWidget * \fBmainWidget\fP ()" .br .RI "获取主内容区Widget " .ti -1c .RI "\fBKWindowButtonBar\fP * \fBwindowButtonBar\fP ()" .br .RI "windowButtonBar " .ti -1c .RI "\fBKIconBar\fP * \fBiconBar\fP ()" .br .RI "iconBar " .in -1c .SS "Protected Member Functions" .in +1c .ti -1c .RI "void \fBchangeTheme\fP ()" .br .in -1c Protected Member Functions inherited from \fBkdk::KDialog\fP .in +1c .ti -1c .RI "bool \fBeventFilter\fP (QObject *target, QEvent *event) override" .br .ti -1c .RI "void \fBchangeTheme\fP ()" .br .ti -1c .RI "void \fBchangeIconStyle\fP ()" .br .ti -1c .RI "QBoxLayout * \fBmainLayout\fP ()" .br .in -1c .SH "Detailed Description" .PP 卸载对话框,当用户卸载时可能会弹出此提示对话框 .PP \fBSince\fP .RS 4 1\&.0\&.0 .RE .PP .SH "Author" .PP Generated automatically by Doxygen for LIBKYSDK-APPLICATIONS from the source code\&. libkysdk-applications/doxygen/man/man3/kdk_KComboBoxWidget.30000664000175000017500000000323715104543305022777 0ustar fengfeng.TH "kdk::KComboBoxWidget" 3 "Version version:3.0" "LIBKYSDK-APPLICATIONS" \" -*- nroff -*- .ad l .nh .SH NAME kdk::KComboBoxWidget .SH SYNOPSIS .br .PP .PP Inherits QWidget\&. .SS "Signals" .in +1c .ti -1c .RI "void \fBcomBoxWidgetClicked\fP ()" .br .in -1c .SS "Public Member Functions" .in +1c .ti -1c .RI "\fBKComboBoxWidget\fP (QWidget *parent=nullptr)" .br .ti -1c .RI "void \fBsetStringList\fP (QStringList list)" .br .RI "设置combobox的选项列表 " .ti -1c .RI "QStringList \fBgetChosenList\fP ()" .br .RI "获取选中的列表 " .ti -1c .RI "void \fBsetMainText\fP (QString text)" .br .RI "设置主文本 " .ti -1c .RI "QMenu * \fBmenu\fP ()" .br .RI "获取弹出菜单 " .in -1c .SS "Protected Member Functions" .in +1c .ti -1c .RI "void \fBmouseReleaseEvent\fP (QMouseEvent *event)" .br .ti -1c .RI "void \fBmousePressEvent\fP (QMouseEvent *event)" .br .ti -1c .RI "void \fBleaveEvent\fP (QEvent *e)" .br .ti -1c .RI "void \fBenterEvent\fP (QEvent *e)" .br .ti -1c .RI "void \fBpaintEvent\fP (QPaintEvent *event)" .br .in -1c .SH "Member Function Documentation" .PP .SS "QStringList kdk::KComboBoxWidget::getChosenList ()" .PP 获取选中的列表 .PP \fBReturns\fP .RS 4 .RE .PP .SS "QMenu * kdk::KComboBoxWidget::menu ()" .PP 获取弹出菜单 .PP \fBReturns\fP .RS 4 .RE .PP .SS "void kdk::KComboBoxWidget::setMainText (QString text)" .PP 设置主文本 .PP \fBParameters\fP .RS 4 \fItext\fP .RE .PP .SS "void kdk::KComboBoxWidget::setStringList (QStringList list)" .PP 设置combobox的选项列表 .PP \fBParameters\fP .RS 4 \fIlist\fP .RE .PP .SH "Author" .PP Generated automatically by Doxygen for LIBKYSDK-APPLICATIONS from the source code\&. libkysdk-applications/doxygen/man/man3/kdk_KBorderlessButton.30000664000175000017500000000231115104543305023413 0ustar fengfeng.TH "kdk::KBorderlessButton" 3 "Version version:3.0" "LIBKYSDK-APPLICATIONS" \" -*- nroff -*- .ad l .nh .SH NAME kdk::KBorderlessButton \- 无边框按钮 .SH SYNOPSIS .br .PP .PP \fC#include \fP .PP Inherits QPushButton\&. .SS "Public Member Functions" .in +1c .ti -1c .RI "\fBKBorderlessButton\fP (QWidget *parent=nullptr)" .br .ti -1c .RI "\fBKBorderlessButton\fP (const QString &text, QWidget *parent=nullptr)" .br .ti -1c .RI "\fBKBorderlessButton\fP (const QIcon &icon, const QString &text, QWidget *parent=nullptr)" .br .ti -1c .RI "\fBKBorderlessButton\fP (const QIcon &icon, QWidget *parent=nullptr)" .br .ti -1c .RI "void \fBsetIcon\fP (const QIcon &icon)" .br .RI "设置按钮图标 " .in -1c .SS "Protected Member Functions" .in +1c .ti -1c .RI "bool \fBeventFilter\fP (QObject *watched, QEvent *event)" .br .ti -1c .RI "void \fBpaintEvent\fP (QPaintEvent *event)" .br .ti -1c .RI "QSize \fBsizeHint\fP () const" .br .in -1c .SH "Detailed Description" .PP 无边框按钮 .PP \fBSince\fP .RS 4 1\&.0\&.0 .RE .PP .PP \fBExamples\fP .in +1c \fBtestPushbutton/widget\&.h\fP\&. .SH "Author" .PP Generated automatically by Doxygen for LIBKYSDK-APPLICATIONS from the source code\&. libkysdk-applications/doxygen/man/man3/kdk_KClockTimer.30000664000175000017500000000150415104543305022152 0ustar fengfeng.TH "kdk::KClockTimer" 3 "Version version:3.0" "LIBKYSDK-APPLICATIONS" \" -*- nroff -*- .ad l .nh .SH NAME kdk::KClockTimer .SH SYNOPSIS .br .PP .PP Inherits QWidget\&. .SS "Public Slots" .in +1c .ti -1c .RI "void \fBstartStopwatch\fP ()" .br .RI "开始计时信号 " .ti -1c .RI "void \fBstopStopwatch\fP ()" .br .RI "停止计时信号 " .ti -1c .RI "void \fBresetStopwatch\fP ()" .br .RI "复位信号 " .in -1c .SS "Public Member Functions" .in +1c .ti -1c .RI "\fBKClockTimer\fP (QWidget *parent=nullptr)" .br .ti -1c .RI "QString \fBtime\fP ()" .br .RI "获取当前时间 " .in -1c .SH "Member Function Documentation" .PP .SS "QString kdk::KClockTimer::time ()" .PP 获取当前时间 .PP \fBReturns\fP .RS 4 .RE .PP .SH "Author" .PP Generated automatically by Doxygen for LIBKYSDK-APPLICATIONS from the source code\&. libkysdk-applications/doxygen/man/man3/FormModule.30000664000175000017500000001041715104515306021226 0ustar fengfeng.TH "FormModule" 3 "Thu Oct 12 2023" "Version version:2.3" "LIBKYSDK-APPLICATIONS" \" -*- nroff -*- .ad l .nh .SH NAME FormModule .SH SYNOPSIS .br .PP .SS "Classes" .in +1c .ti -1c .RI "class \fBkdk::KWidget\fP" .br .RI "继承自QWidget,支持响应主题背景切换,图标主题切换,标题颜色响应窗口激活状态,内容区域分为side区和base区 " .in -1c .SS "Functions" .in +1c .ti -1c .RI "\fBkdk::KWidget::KWidget\fP (QWidget *parent=nullptr)" .br .ti -1c .RI "void \fBkdk::KWidget::setIcon\fP (const QIcon &icon)" .br .RI "设置窗体图标 " .ti -1c .RI "void \fBkdk::KWidget::setIcon\fP (const QString &iconName)" .br .RI "设置窗体图标 " .ti -1c .RI "void \fBkdk::KWidget::setWidgetName\fP (const QString &widgetName)" .br .RI "设置窗体名称 " .ti -1c .RI "QWidget * \fBkdk::KWidget::sideBar\fP ()" .br .RI "获取左边栏widget,通过setlayout添加自定义内容 " .ti -1c .RI "QWidget * \fBkdk::KWidget::baseBar\fP ()" .br .RI "获取主内容区widget,通过setlayout添加自定义内容 " .ti -1c .RI "\fBKWindowButtonBar\fP * \fBkdk::KWidget::windowButtonBar\fP ()" .br .RI "获取窗口三联组合控件,以控制是否显示最大化、最小化按钮和下拉菜单按钮;也可增加自定义按钮 " .ti -1c .RI "\fBKIconBar\fP * \fBkdk::KWidget::iconBar\fP ()" .br .RI "获取窗口标题、图标组合控件,以控制相关样式 " .ti -1c .RI "void \fBkdk::KWidget::setLayoutType\fP (LayoutType type)" .br .RI "设置布局结构类型 " .ti -1c .RI "void \fBkdk::KWidget::setWindowFlags\fP (Qt::WindowFlags type)" .br .RI "设置窗口标志 " .ti -1c .RI "void \fBkdk::KWidget::setWindowFlag\fP (Qt::WindowType flag, bool on=true)" .br .RI "设置窗口标志 " .ti -1c .RI "void \fBkdk::KWidget::setSidebarFollowMode\fP (bool flag)" .br .RI "设置sidebar是否遵循系统更改宽度 " .ti -1c .RI "bool \fBkdk::KWidget::sidebarFollowMode\fP ()" .br .RI "返回sidebar是否遵循系统更改宽度 " .ti -1c .RI "bool \fBkdk::KWidget::eventFilter\fP (QObject *target, QEvent *event) override" .br .ti -1c .RI "virtual void \fBkdk::KWidget::changeIconStyle\fP ()" .br .ti -1c .RI "virtual void \fBkdk::KWidget::changeTheme\fP ()" .br .in -1c .SH "Detailed Description" .PP .SH "Function Documentation" .PP .SS "QWidget* kdk::KWidget::baseBar ()" .PP 获取主内容区widget,通过setlayout添加自定义内容 .PP \fBReturns\fP .RS 4 返回主内容区widget .RE .PP .SS "\fBKIconBar\fP* kdk::KWidget::iconBar ()" .PP 获取窗口标题、图标组合控件,以控制相关样式 .PP \fBReturns\fP .RS 4 返回窗口标题、图标组合控件 .RE .PP .SS "void kdk::KWidget::setIcon (const QIcon & icon)" .PP 设置窗体图标 .PP \fBParameters\fP .RS 4 \fIicon\fP .RE .PP .SS "void kdk::KWidget::setIcon (const QString & iconName)" .PP 设置窗体图标 .PP \fBParameters\fP .RS 4 \fIiconName\fP 直接指定系统目录中的图标名称,如'kylin-music' .RE .PP .SS "void kdk::KWidget::setSidebarFollowMode (bool flag)" .PP 设置sidebar是否遵循系统更改宽度 .PP \fBParameters\fP .RS 4 \fIflag\fP .RE .PP \fBSince\fP .RS 4 1\&.2 .RE .PP .SS "void kdk::KWidget::setWidgetName (const QString & widgetName)" .PP 设置窗体名称 .PP \fBParameters\fP .RS 4 \fIwidgetName\fP .RE .PP .SS "void kdk::KWidget::setWindowFlag (Qt::WindowType flag, bool on = \fCtrue\fP)" .PP 设置窗口标志 .PP \fBParameters\fP .RS 4 \fIflag\fP .br \fIon\fP .RE .PP \fBSince\fP .RS 4 1\&.2 .RE .PP .SS "void kdk::KWidget::setWindowFlags (Qt::WindowFlags type)" .PP 设置窗口标志 .PP \fBParameters\fP .RS 4 \fItype\fP .RE .PP \fBSince\fP .RS 4 1\&.2 .RE .PP .SS "QWidget* kdk::KWidget::sideBar ()" .PP 获取左边栏widget,通过setlayout添加自定义内容 .PP \fBReturns\fP .RS 4 返回左边栏widget .RE .PP .SS "bool kdk::KWidget::sidebarFollowMode ()" .PP 返回sidebar是否遵循系统更改宽度 .PP \fBReturns\fP .RS 4 .RE .PP \fBSince\fP .RS 4 1\&.2 .RE .PP .SS "\fBKWindowButtonBar\fP* kdk::KWidget::windowButtonBar ()" .PP 获取窗口三联组合控件,以控制是否显示最大化、最小化按钮和下拉菜单按钮;也可增加自定义按钮 .PP \fBReturns\fP .RS 4 返回窗口三联组合控件 .RE .PP .SH "Author" .PP Generated automatically by Doxygen for LIBKYSDK-APPLICATIONS from the source code\&. libkysdk-applications/doxygen/man/man3/kdk_effects_KShadowHelper.30000664000175000017500000000110115104543305024173 0ustar fengfeng.TH "kdk::effects::KShadowHelper" 3 "Version version:3.0" "LIBKYSDK-APPLICATIONS" \" -*- nroff -*- .ad l .nh .SH NAME kdk::effects::KShadowHelper .SH SYNOPSIS .br .PP .PP Inherits QObject\&. .SS "Public Member Functions" .in +1c .ti -1c .RI "void \fBsetWidget\fP (QWidget *widget, int borderRadius=12, int shadowWidth=20, qreal darkness=0\&.5)" .br .in -1c .SS "Static Public Member Functions" .in +1c .ti -1c .RI "static \fBKShadowHelper\fP * \fBself\fP ()" .br .in -1c .SH "Author" .PP Generated automatically by Doxygen for LIBKYSDK-APPLICATIONS from the source code\&. libkysdk-applications/doxygen/man/man3/kdk_KProgressLabel.30000664000175000017500000000310015104543305022654 0ustar fengfeng.TH "kdk::KProgressLabel" 3 "Version version:3.0" "LIBKYSDK-APPLICATIONS" \" -*- nroff -*- .ad l .nh .SH NAME kdk::KProgressLabel .SH SYNOPSIS .br .PP .PP Inherits QWidget\&. .SS "Public Member Functions" .in +1c .ti -1c .RI "\fBKProgressLabel\fP (QWidget *parent=nullptr)" .br .ti -1c .RI "void \fBsetStringList\fP (QStringList list1, QStringList list2)" .br .RI "设置第二行文本和第一行文本 " .ti -1c .RI "void \fBsetStringList\fP (QStringList list1)" .br .RI "setStringList " .ti -1c .RI "void \fBsetCurrentIndex\fP (int index)" .br .RI "设置当前进度 " .ti -1c .RI "int \fBcurrentIndex\fP ()" .br .RI "获取当前进度 " .ti -1c .RI "void \fBsetCircleSize\fP (QSize size)" .br .RI "设置圆形label的大小 " .in -1c .SH "Member Function Documentation" .PP .SS "int kdk::KProgressLabel::currentIndex ()" .PP 获取当前进度 .PP \fBReturns\fP .RS 4 .RE .PP .SS "void kdk::KProgressLabel::setCircleSize (QSize size)" .PP 设置圆形label的大小 .PP \fBParameters\fP .RS 4 \fIsize\fP .RE .PP .SS "void kdk::KProgressLabel::setCurrentIndex (int index)" .PP 设置当前进度 .PP \fBParameters\fP .RS 4 \fIindex\fP .RE .PP .SS "void kdk::KProgressLabel::setStringList (QStringList list1)" .PP setStringList .PP \fBParameters\fP .RS 4 \fIlist1\fP .RE .PP .SS "void kdk::KProgressLabel::setStringList (QStringList list1, QStringList list2)" .PP 设置第二行文本和第一行文本 .PP \fBParameters\fP .RS 4 \fIlist1\fP .br \fIlist2\fP .RE .PP .SH "Author" .PP Generated automatically by Doxygen for LIBKYSDK-APPLICATIONS from the source code\&. libkysdk-applications/doxygen/man/man3/kdk_Parmscontroller.30000664000175000017500000000277715104543305023206 0ustar fengfeng.TH "kdk::Parmscontroller" 3 "Version version:3.0" "LIBKYSDK-APPLICATIONS" \" -*- nroff -*- .ad l .nh .SH NAME kdk::Parmscontroller \- The \fBParmscontroller\fP class\&. .SH SYNOPSIS .br .PP .PP \fC#include \fP .PP Inherits QObject\&. .SS "Public Types" .in +1c .ti -1c .RI "enum \fBParm\fP { \fBPM_TabBarHeight\fP, \fBPM_PushButtonHeight\fP, \fBPM_ToolButtonHeight\fP, \fBPM_SearchLineEditHeight\fP, \fBPM_PasswordEditHeight\fP, \fBPM_NavigationBatHeight\fP, \fBPM_TagHeight\fP, \fBPM_SearchLineEditItemHeight\fP, \fBPM_SliderHandleRadius\fP, \fBPM_SliderNodeRadius\fP, \fBPM_BadgeHeight\fP, \fBPM_IconbarHeight\fP, \fBPM_IconBarIconSize\fP, \fBPM_WindowButtonBarSize\fP, \fBPM_NavigationBatInterval\fP, \fBPM_Widget_SideWidget_Width\fP, \fBPM_InputDialog_Height\fP, \fBPM_InputDialog_Width\fP, \fBPM_InputDialog_Label_Spacing\fP, \fBPM_InputDialog_Widget_Spacing\fP, \fBPM_InputDialog_Button_Spacing\fP, \fBPM_InputDialog_Bottom_Spacing\fP, \fBPM_InputDialog_Right_Spacing\fP }" .br .in -1c .SS "Signals" .in +1c .ti -1c .RI "void \fBmodeChanged\fP (bool)" .br .in -1c .SS "Static Public Member Functions" .in +1c .ti -1c .RI "static \fBParmscontroller\fP * \fBself\fP ()" .br .ti -1c .RI "static bool \fBisTabletMode\fP ()" .br .ti -1c .RI "static int \fBparm\fP (Parm p)" .br .in -1c .SH "Detailed Description" .PP The \fBParmscontroller\fP class\&. .PP \fBSince\fP .RS 4 2\&.0\&.2\&.1 .RE .PP .SH "Author" .PP Generated automatically by Doxygen for LIBKYSDK-APPLICATIONS from the source code\&. libkysdk-applications/doxygen/man/man3/kdk_KColorButton.30000664000175000017500000000463115104543305022374 0ustar fengfeng.TH "kdk::KColorButton" 3 "Version version:3.0" "LIBKYSDK-APPLICATIONS" \" -*- nroff -*- .ad l .nh .SH NAME kdk::KColorButton \- 提供用于设置颜色和样式的按钮,以适用于不同的场景。 .SH SYNOPSIS .br .PP .PP \fC#include \fP .PP Inherits QPushButton\&. .SS "Public Types" .in +1c .ti -1c .RI "enum \fBButtonType\fP { \fBCircle\fP, \fBRoundedRect\fP, \fBCheckedRect\fP }" .br .RI "KColorButton提供三种不同的样式 " .in -1c .SS "Public Member Functions" .in +1c .ti -1c .RI "\fBKColorButton\fP (QWidget *parent=nullptr)" .br .ti -1c .RI "void \fBsetBackgroundColor\fP (QColor color)" .br .RI "设置colorButton背景色 " .ti -1c .RI "QColor \fBbackgroundColor\fP ()" .br .RI "返回colorButton背景色 " .ti -1c .RI "void \fBsetBorderRadius\fP (int radious)" .br .RI "设置圆角(RoundedRect,CheckedRect类型生效) " .ti -1c .RI "int \fBborderRadius\fP ()" .br .RI "返回圆角 " .ti -1c .RI "void \fBsetButtonType\fP (\fBKColorButton::ButtonType\fP type)" .br .RI "设置colorButton类型 " .ti -1c .RI "\fBKColorButton::ButtonType\fP \fBbuttonType\fP ()" .br .RI "返回colorButton类型 " .in -1c .SS "Protected Member Functions" .in +1c .ti -1c .RI "void \fBpaintEvent\fP (QPaintEvent *) override" .br .ti -1c .RI "QSize \fBsizeHint\fP () const override" .br .in -1c .SH "Detailed Description" .PP 提供用于设置颜色和样式的按钮,以适用于不同的场景。 .PP \fBSince\fP .RS 4 2\&.0\&.2\&.1 .RE .PP .SH "Member Function Documentation" .PP .SS "QColor kdk::KColorButton::backgroundColor ()" .PP 返回colorButton背景色 .PP \fBReturns\fP .RS 4 .RE .PP .SS "int kdk::KColorButton::borderRadius ()" .PP 返回圆角 .PP \fBReturns\fP .RS 4 .RE .PP .SS "\fBKColorButton::ButtonType\fP kdk::KColorButton::buttonType ()" .PP 返回colorButton类型 .PP \fBReturns\fP .RS 4 .RE .PP .SS "void kdk::KColorButton::setBackgroundColor (QColor color)" .PP 设置colorButton背景色 .PP \fBParameters\fP .RS 4 \fIcolor\fP .RE .PP .SS "void kdk::KColorButton::setBorderRadius (int radious)" .PP 设置圆角(RoundedRect,CheckedRect类型生效) .PP \fBParameters\fP .RS 4 \fIradious\fP .RE .PP .SS "void kdk::KColorButton::setButtonType (\fBKColorButton::ButtonType\fP type)" .PP 设置colorButton类型 .PP \fBParameters\fP .RS 4 \fItype\fP .RE .PP .SH "Author" .PP Generated automatically by Doxygen for LIBKYSDK-APPLICATIONS from the source code\&. libkysdk-applications/doxygen/man/man3/kdk_KIntroWidget.30000664000175000017500000000440415104543305022357 0ustar fengfeng.TH "kdk::KIntroWidget" 3 "Version version:3.0" "LIBKYSDK-APPLICATIONS" \" -*- nroff -*- .ad l .nh .SH NAME kdk::KIntroWidget .SH SYNOPSIS .br .PP .PP Inherits QWidget\&. .SS "Signals" .in +1c .ti -1c .RI "void \fBrightClick\fP (QPoint point)" .br .in -1c .SS "Public Member Functions" .in +1c .ti -1c .RI "\fBKIntroWidget\fP (QWidget *parent=nullptr)" .br .ti -1c .RI "void \fBsetViewType\fP (ViewType type)" .br .RI "设置视图样式 " .ti -1c .RI "void \fBsetMainLabel\fP (QString str)" .br .RI "设置主文本 " .ti -1c .RI "void \fBsetSubLabel\fP (QString str)" .br .RI "设置次级文本 " .ti -1c .RI "void \fBsetBorderRadius\fP (int radius)" .br .RI "设置圆角 " .ti -1c .RI "void \fBsetBorderRadius\fP (int bottomLeft, int topLeft, int topRight, int bottomRight)" .br .RI "设置圆角 " .ti -1c .RI "void \fBsetTitleColor\fP (QColor color)" .br .RI "设置标题颜色 " .in -1c .SS "Protected Member Functions" .in +1c .ti -1c .RI "void \fBpaintEvent\fP (QPaintEvent *event)" .br .ti -1c .RI "bool \fBeventFilter\fP (QObject *watched, QEvent *event)" .br .ti -1c .RI "QSize \fBsizeHint\fP () const override" .br .ti -1c .RI "void \fBmousePressEvent\fP (QMouseEvent *event)" .br .ti -1c .RI "void \fBmouseReleaseEvent\fP (QMouseEvent *event)" .br .in -1c .SH "Member Function Documentation" .PP .SS "void kdk::KIntroWidget::setBorderRadius (int bottomLeft, int topLeft, int topRight, int bottomRight)" .PP 设置圆角 .PP \fBParameters\fP .RS 4 \fIbottomLeft\fP .br \fItopLeft\fP .br \fItopRight\fP .br \fIbottomRight\fP .RE .PP .SS "void kdk::KIntroWidget::setBorderRadius (int radius)" .PP 设置圆角 .PP \fBParameters\fP .RS 4 \fIradius\fP .RE .PP .SS "void kdk::KIntroWidget::setMainLabel (QString str)" .PP 设置主文本 .PP \fBParameters\fP .RS 4 \fIstr\fP .RE .PP .SS "void kdk::KIntroWidget::setSubLabel (QString str)" .PP 设置次级文本 .PP \fBParameters\fP .RS 4 \fIstr\fP .RE .PP .SS "void kdk::KIntroWidget::setTitleColor (QColor color)" .PP 设置标题颜色 .PP \fBParameters\fP .RS 4 \fIcolor\fP .RE .PP .SS "void kdk::KIntroWidget::setViewType (ViewType type)" .PP 设置视图样式 .PP \fBParameters\fP .RS 4 \fItype\fP .RE .PP .SH "Author" .PP Generated automatically by Doxygen for LIBKYSDK-APPLICATIONS from the source code\&. libkysdk-applications/doxygen/man/man3/kdk_KBubbleWidget.30000664000175000017500000000733715104543305022467 0ustar fengfeng.TH "kdk::KBubbleWidget" 3 "Version version:3.0" "LIBKYSDK-APPLICATIONS" \" -*- nroff -*- .ad l .nh .SH NAME kdk::KBubbleWidget \- 提供了一个带三角形窗体。 .SH SYNOPSIS .br .PP .PP \fC#include \fP .PP Inherits QWidget\&. .SS "Public Member Functions" .in +1c .ti -1c .RI "\fBKBubbleWidget\fP (QWidget *parent=nullptr)" .br .ti -1c .RI "void \fBsetTailSize\fP (const QSize &size)" .br .RI "设置气泡尾部尺寸 " .ti -1c .RI "QSize \fBtailSize\fP ()" .br .RI "获取气泡尾部尺寸 " .ti -1c .RI "void \fBsetTailPosition\fP (\fBTailDirection\fP dirType, \fBTailLocation\fP locType=MiddleLocation)" .br .RI "设置气泡尾部显示位置 " .ti -1c .RI "\fBTailDirection\fP \fBtailDirection\fP ()" .br .RI "获取气泡尾部显示方向 " .ti -1c .RI "\fBTailLocation\fP \fBtailLocation\fP ()" .br .RI "获取气泡尾部显示位置 " .ti -1c .RI "void \fBsetBorderRadius\fP (int bottomLeft, int topLeft, int topRight, int bottomRight)" .br .RI "设置窗体圆角半径 " .ti -1c .RI "void \fBsetBorderRadius\fP (int radius)" .br .RI "设置窗体圆角半径 " .ti -1c .RI "void \fBsetEnableBlur\fP (bool flag)" .br .RI "设置是否启用毛玻璃效果 " .ti -1c .RI "bool \fBenableBlur\fP ()" .br .RI "获取是否已启用毛玻璃效果 " .ti -1c .RI "void \fBsetOpacity\fP (qreal \fBopacity\fP)" .br .RI "设置透明度 " .ti -1c .RI "qreal \fBopacity\fP ()" .br .RI "获取透明度 " .ti -1c .RI "void \fBsetHighlightBackground\fP (bool flag)" .br .RI "设置是否启用高亮背景色 " .in -1c .SS "Protected Member Functions" .in +1c .ti -1c .RI "void \fBpaintEvent\fP (QPaintEvent *)" .br .in -1c .SH "Detailed Description" .PP 提供了一个带三角形窗体。 .PP \fBSince\fP .RS 4 2\&.0\&.2\&.1 .RE .PP .SH "Member Function Documentation" .PP .SS "bool kdk::KBubbleWidget::enableBlur ()" .PP 获取是否已启用毛玻璃效果 .PP \fBReturns\fP .RS 4 .RE .PP .SS "qreal kdk::KBubbleWidget::opacity ()" .PP 获取透明度 .PP \fBReturns\fP .RS 4 .RE .PP .SS "void kdk::KBubbleWidget::setBorderRadius (int bottomLeft, int topLeft, int topRight, int bottomRight)" .PP 设置窗体圆角半径 .PP \fBParameters\fP .RS 4 \fIbottomLeft\fP .br \fItopLeft\fP .br \fItopRight\fP .br \fIbottomRight\fP .RE .PP .SS "void kdk::KBubbleWidget::setBorderRadius (int radius)" .PP 设置窗体圆角半径 .PP \fBParameters\fP .RS 4 \fIradius\fP .RE .PP .SS "void kdk::KBubbleWidget::setEnableBlur (bool flag)" .PP 设置是否启用毛玻璃效果 .PP \fBParameters\fP .RS 4 \fIflag\fP .RE .PP .SS "void kdk::KBubbleWidget::setHighlightBackground (bool flag)" .PP 设置是否启用高亮背景色 .PP \fBParameters\fP .RS 4 \fIflag\fP .RE .PP \fBSince\fP .RS 4 2\&.4\&.1\&.0 .RE .PP .SS "void kdk::KBubbleWidget::setOpacity (qreal opacity)" .PP 设置透明度 .PP \fBParameters\fP .RS 4 \fIopacity\fP .RE .PP .SS "void kdk::KBubbleWidget::setTailPosition (\fBTailDirection\fP dirType, \fBTailLocation\fP locType = \fCMiddleLocation\fP)" .PP 设置气泡尾部显示位置 .PP \fBParameters\fP .RS 4 \fIdirType\fP .br \fIlocType\fP .RE .PP .SS "void kdk::KBubbleWidget::setTailSize (const QSize & size)" .PP 设置气泡尾部尺寸 .PP \fBParameters\fP .RS 4 \fIsize\fP .RE .PP .SS "\fBTailDirection\fP kdk::KBubbleWidget::tailDirection ()" .PP 获取气泡尾部显示方向 .PP \fBReturns\fP .RS 4 左、上、右、下 .RE .PP .SS "\fBTailLocation\fP kdk::KBubbleWidget::tailLocation ()" .PP 获取气泡尾部显示位置 .PP \fBReturns\fP .RS 4 居左、居中、居右 .RE .PP .SS "QSize kdk::KBubbleWidget::tailSize ()" .PP 获取气泡尾部尺寸 .PP \fBReturns\fP .RS 4 .RE .PP .SH "Author" .PP Generated automatically by Doxygen for LIBKYSDK-APPLICATIONS from the source code\&. libkysdk-applications/doxygen/man/man3/kdk_KMiniCalendarWidget.30000664000175000017500000002224615104543305023616 0ustar fengfeng.TH "kdk::KMiniCalendarWidget" 3 "Version version:3.0" "LIBKYSDK-APPLICATIONS" \" -*- nroff -*- .ad l .nh .SH NAME kdk::KMiniCalendarWidget .SH SYNOPSIS .br .PP .PP Inherits QWidget\&. .SS "Public Types" .in +1c .ti -1c .RI "enum \fBCalendarStyle\fP { \fBCalendarStyle_Red\fP = 0 }" .br .ti -1c .RI "enum \fBWeekNameFormat\fP { \fBWeekNameFormat_Short\fP = 0, \fBWeekNameFormat_Normal\fP = 1, \fBWeekNameFormat_Long\fP = 2, \fBWeekNameFormat_En\fP = 3 }" .br .ti -1c .RI "enum \fBSelectType\fP { \fBSelectType_Rect\fP = 0, \fBSelectType_Circle\fP = 1, \fBSelectType_Triangle\fP = 2, \fBSelectType_Image\fP = 3 }" .br .in -1c .SS "Public Slots" .in +1c .ti -1c .RI "void \fBshowPreviousMonth\fP ()" .br .ti -1c .RI "void \fBshowNextMonth\fP ()" .br .ti -1c .RI "void \fBshowToday\fP ()" .br .ti -1c .RI "void \fBsetCalendarStyle\fP (const CalendarStyle &calendarStyle)" .br .ti -1c .RI "void \fBsetWeekNameFormat\fP (const WeekNameFormat &weekNameFormat)" .br .ti -1c .RI "void \fBsetDate\fP (const QDate &date)" .br .ti -1c .RI "void \fBsetWeekTextColor\fP (const QColor &weekTextColor)" .br .ti -1c .RI "void \fBsetWeekBgColor\fP (const QColor &weekBgColor)" .br .ti -1c .RI "void \fBsetShowLunar\fP (bool showLunar)" .br .ti -1c .RI "void \fBsetEnableBorder\fP (bool bVisible)" .br .ti -1c .RI "void \fBsetSelectType\fP (const SelectType &selectType)" .br .ti -1c .RI "void \fBsetBorderColor\fP (const QColor &borderColor)" .br .ti -1c .RI "void \fBsetWeekColor\fP (const QColor &weekColor)" .br .ti -1c .RI "void \fBsetLunarColor\fP (const QColor &lunarColor)" .br .ti -1c .RI "void \fBsetCurrentTextColor\fP (const QColor ¤tTextColor)" .br .ti -1c .RI "void \fBsetOtherTextColor\fP (const QColor &otherTextColor)" .br .ti -1c .RI "void \fBsetSelectTextColor\fP (const QColor &selectTextColor)" .br .ti -1c .RI "void \fBsetHoverTextColor\fP (const QColor &hoverTextColor)" .br .ti -1c .RI "void \fBsetCurrentLunarColor\fP (const QColor ¤tLunarColor)" .br .ti -1c .RI "void \fBsetOtherLunarColor\fP (const QColor &otherLunarColor)" .br .ti -1c .RI "void \fBsetSelectLunarColor\fP (const QColor &selectLunarColor)" .br .ti -1c .RI "void \fBsetHoverLunarColor\fP (const QColor &hoverLunarColor)" .br .ti -1c .RI "void \fBsetCurrentBgColor\fP (const QColor ¤tBgColor)" .br .ti -1c .RI "void \fBsetOtherBgColor\fP (const QColor &otherBgColor)" .br .ti -1c .RI "void \fBsetSelectBgColor\fP (const QColor &selectBgColor)" .br .ti -1c .RI "void \fBsetHoverBgColor\fP (const QColor &hoverBgColor)" .br .in -1c .SS "Signals" .in +1c .ti -1c .RI "void \fBclicked\fP (const QDate &date)" .br .ti -1c .RI "void \fBselectionChanged\fP ()" .br .in -1c .SS "Public Member Functions" .in +1c .ti -1c .RI "\fBKMiniCalendarWidget\fP (QWidget *parent=0)" .br .ti -1c .RI "CalendarStyle \fBgetCalendarStyle\fP () const" .br .RI "获取整体样式 " .ti -1c .RI "WeekNameFormat \fBgetWeekNameFormat\fP () const" .br .RI "获取星期名称格式 " .ti -1c .RI "QDate \fBgetDate\fP () const" .br .RI "获取当前日期 " .ti -1c .RI "QColor \fBgetWeekTextColor\fP () const" .br .RI "获取星期文本颜色 " .ti -1c .RI "QColor \fBgetWeekBgColor\fP () const" .br .RI "获取周末名称背景色 " .ti -1c .RI "bool \fBgetShowLunar\fP () const" .br .RI "获取农历显示 " .ti -1c .RI "bool \fBgetEnableBorder\fP () const" .br .RI "获取启用边框 " .ti -1c .RI "SelectType \fBgetSelectType\fP () const" .br .RI "获取选择类型 " .ti -1c .RI "QColor \fBgetBorderColor\fP () const" .br .RI "获取边框颜色 " .ti -1c .RI "QColor \fBgetWeekColor\fP () const" .br .RI "获取周末颜色 " .ti -1c .RI "QColor \fBgetLunarColor\fP () const" .br .RI "获取农历节日颜色 " .ti -1c .RI "QColor \fBgetCurrentTextColor\fP () const" .br .RI "获取当前月文本颜色 " .ti -1c .RI "QColor \fBgetOtherTextColor\fP () const" .br .RI "获取其他月文本颜色 " .ti -1c .RI "QColor \fBgetSelectTextColor\fP () const" .br .RI "获取选中日期文本颜色 " .ti -1c .RI "QColor \fBgetHoverTextColor\fP () const" .br .RI "获取悬浮日期文本颜色 " .ti -1c .RI "QColor \fBgetCurrentLunarColor\fP () const" .br .RI "获取当前月农历文字颜色 " .ti -1c .RI "QColor \fBgetOtherLunarColor\fP () const" .br .RI "获取其他月农历文本颜色 " .ti -1c .RI "QColor \fBgetSelectLunarColor\fP () const" .br .RI "获取选中日期农历颜文本色 " .ti -1c .RI "QColor \fBgetHoverLunarColor\fP () const" .br .RI "获取悬浮日期农历文本颜色 " .ti -1c .RI "QColor \fBgetCurrentBgColor\fP () const" .br .RI "获取当前月背景色 " .ti -1c .RI "QColor \fBgetOtherBgColor\fP () const" .br .RI "获取其他月背景色 " .ti -1c .RI "QColor \fBgetSelectBgColor\fP () const" .br .RI "获取选择日期背景色 " .ti -1c .RI "QColor \fBgetHoverBgColor\fP () const" .br .RI "获取悬浮日期背景色 " .ti -1c .RI "QSize \fBsizeHint\fP () const" .br .ti -1c .RI "QSize \fBminimumSizeHint\fP () const" .br .in -1c .SS "Protected Member Functions" .in +1c .ti -1c .RI "void \fBwheelEvent\fP (QWheelEvent *event) override" .br .ti -1c .RI "void \fBpaintEvent\fP (QPaintEvent *event) override" .br .in -1c .SS "Properties" .in +1c .ti -1c .RI "CalendarStyle \fBcalendarStyle\fP" .br .ti -1c .RI "WeekNameFormat \fBweekNameFormat\fP" .br .ti -1c .RI "QDate \fBdate\fP" .br .ti -1c .RI "QColor \fBweekTextColor\fP" .br .ti -1c .RI "QColor \fBweekBgColor\fP" .br .ti -1c .RI "bool \fBshowLunar\fP" .br .ti -1c .RI "bool \fBenableBorder\fP" .br .ti -1c .RI "SelectType \fBselectType\fP" .br .ti -1c .RI "QColor \fBborderColor\fP" .br .ti -1c .RI "QColor \fBweekColor\fP" .br .ti -1c .RI "QColor \fBlunarColor\fP" .br .ti -1c .RI "QColor \fBcurrentTextColor\fP" .br .ti -1c .RI "QColor \fBotherTextColor\fP" .br .ti -1c .RI "QColor \fBselectTextColor\fP" .br .ti -1c .RI "QColor \fBhoverTextColor\fP" .br .ti -1c .RI "QColor \fBcurrentLunarColor\fP" .br .ti -1c .RI "QColor \fBotherLunarColor\fP" .br .ti -1c .RI "QColor \fBselectLunarColor\fP" .br .ti -1c .RI "QColor \fBhoverLunarColor\fP" .br .ti -1c .RI "QColor \fBcurrentBgColor\fP" .br .ti -1c .RI "QColor \fBotherBgColor\fP" .br .ti -1c .RI "QColor \fBselectBgColor\fP" .br .ti -1c .RI "QColor \fBhoverBgColor\fP" .br .in -1c .SH "Member Function Documentation" .PP .SS "QColor kdk::KMiniCalendarWidget::getBorderColor () const" .PP 获取边框颜色 .PP \fBReturns\fP .RS 4 .RE .PP .SS "CalendarStyle kdk::KMiniCalendarWidget::getCalendarStyle () const" .PP 获取整体样式 .PP \fBReturns\fP .RS 4 .RE .PP .SS "QColor kdk::KMiniCalendarWidget::getCurrentBgColor () const" .PP 获取当前月背景色 .PP \fBReturns\fP .RS 4 .RE .PP .SS "QColor kdk::KMiniCalendarWidget::getCurrentLunarColor () const" .PP 获取当前月农历文字颜色 .PP \fBReturns\fP .RS 4 .RE .PP .SS "QColor kdk::KMiniCalendarWidget::getCurrentTextColor () const" .PP 获取当前月文本颜色 .PP \fBReturns\fP .RS 4 .RE .PP .SS "QDate kdk::KMiniCalendarWidget::getDate () const" .PP 获取当前日期 .PP \fBReturns\fP .RS 4 .RE .PP .SS "bool kdk::KMiniCalendarWidget::getEnableBorder () const" .PP 获取启用边框 .PP \fBReturns\fP .RS 4 .RE .PP .SS "QColor kdk::KMiniCalendarWidget::getHoverBgColor () const" .PP 获取悬浮日期背景色 .PP \fBReturns\fP .RS 4 .RE .PP .SS "QColor kdk::KMiniCalendarWidget::getHoverLunarColor () const" .PP 获取悬浮日期农历文本颜色 .PP \fBReturns\fP .RS 4 .RE .PP .SS "QColor kdk::KMiniCalendarWidget::getHoverTextColor () const" .PP 获取悬浮日期文本颜色 .PP \fBReturns\fP .RS 4 .RE .PP .SS "QColor kdk::KMiniCalendarWidget::getLunarColor () const" .PP 获取农历节日颜色 .PP \fBReturns\fP .RS 4 .RE .PP .SS "QColor kdk::KMiniCalendarWidget::getOtherBgColor () const" .PP 获取其他月背景色 .PP \fBReturns\fP .RS 4 .RE .PP .SS "QColor kdk::KMiniCalendarWidget::getOtherLunarColor () const" .PP 获取其他月农历文本颜色 .PP \fBReturns\fP .RS 4 .RE .PP .SS "QColor kdk::KMiniCalendarWidget::getOtherTextColor () const" .PP 获取其他月文本颜色 .PP \fBReturns\fP .RS 4 .RE .PP .SS "QColor kdk::KMiniCalendarWidget::getSelectBgColor () const" .PP 获取选择日期背景色 .PP \fBReturns\fP .RS 4 .RE .PP .SS "QColor kdk::KMiniCalendarWidget::getSelectLunarColor () const" .PP 获取选中日期农历颜文本色 .PP \fBReturns\fP .RS 4 .RE .PP .SS "QColor kdk::KMiniCalendarWidget::getSelectTextColor () const" .PP 获取选中日期文本颜色 .PP \fBReturns\fP .RS 4 .RE .PP .SS "SelectType kdk::KMiniCalendarWidget::getSelectType () const" .PP 获取选择类型 .PP \fBReturns\fP .RS 4 .RE .PP .SS "bool kdk::KMiniCalendarWidget::getShowLunar () const" .PP 获取农历显示 .PP \fBReturns\fP .RS 4 .RE .PP .SS "QColor kdk::KMiniCalendarWidget::getWeekBgColor () const" .PP 获取周末名称背景色 .PP \fBReturns\fP .RS 4 .RE .PP .SS "QColor kdk::KMiniCalendarWidget::getWeekColor () const" .PP 获取周末颜色 .PP \fBReturns\fP .RS 4 .RE .PP .SS "WeekNameFormat kdk::KMiniCalendarWidget::getWeekNameFormat () const" .PP 获取星期名称格式 .PP \fBReturns\fP .RS 4 .RE .PP .SS "QColor kdk::KMiniCalendarWidget::getWeekTextColor () const" .PP 获取星期文本颜色 .PP \fBReturns\fP .RS 4 .RE .PP .SH "Author" .PP Generated automatically by Doxygen for LIBKYSDK-APPLICATIONS from the source code\&. libkysdk-applications/doxygen/man/man3/kdk_KColorComboBox.30000664000175000017500000000524015104543305022626 0ustar fengfeng.TH "kdk::KColorComboBox" 3 "Version version:3.0" "LIBKYSDK-APPLICATIONS" \" -*- nroff -*- .ad l .nh .SH NAME kdk::KColorComboBox \- 颜色选择框 .SH SYNOPSIS .br .PP .PP \fC#include \fP .PP Inherits QComboBox\&. .SS "Public Types" .in +1c .ti -1c .RI "enum \fBComboType\fP { \fBCircle\fP, \fBRoundedRect\fP }" .br .RI "指定显示样式,圆形或者圆角矩形 " .in -1c .SS "Signals" .in +1c .ti -1c .RI "void \fBactivated\fP (const QColor &color)" .br .ti -1c .RI "void \fBcurrentColorChanged\fP (const QColor &color)" .br .ti -1c .RI "void \fBhighlighted\fP (const QColor &color)" .br .in -1c .SS "Public Member Functions" .in +1c .ti -1c .RI "\fBKColorComboBox\fP (QWidget *parent=nullptr)" .br .ti -1c .RI "void \fBsetColorList\fP (const QList< QColor > &list)" .br .RI "以列表形式添加颜色选项 " .ti -1c .RI "QList< QColor > \fBcolorList\fP ()" .br .RI "获取颜色列表 " .ti -1c .RI "void \fBaddColor\fP (const QColor &color)" .br .RI "添加颜色选项 " .ti -1c .RI "void \fBsetComboType\fP (const \fBComboType\fP &type)" .br .RI "设置显示样式 " .ti -1c .RI "\fBComboType\fP \fBcomboType\fP ()" .br .RI "获取显示样式 " .ti -1c .RI "void \fBsetPopupItemSize\fP (const QSize &size)" .br .RI "设置item尺寸 " .ti -1c .RI "QSize \fBpopupItemSzie\fP ()" .br .RI "返回item尺寸 " .in -1c .SS "Protected Member Functions" .in +1c .ti -1c .RI "void \fBpaintEvent\fP (QPaintEvent *event) override" .br .ti -1c .RI "void \fBresizeEvent\fP (QResizeEvent *event) override" .br .in -1c .SH "Detailed Description" .PP 颜色选择框 .PP \fBSince\fP .RS 4 2\&.0\&.2\&.1 .RE .PP .SH "Member Function Documentation" .PP .SS "void kdk::KColorComboBox::addColor (const QColor & color)" .PP 添加颜色选项 .PP \fBParameters\fP .RS 4 \fIcolor\fP .RE .PP .SS "QList< QColor > kdk::KColorComboBox::colorList ()" .PP 获取颜色列表 .PP \fBReturns\fP .RS 4 .RE .PP .SS "\fBComboType\fP kdk::KColorComboBox::comboType ()" .PP 获取显示样式 .PP \fBReturns\fP .RS 4 .RE .PP .SS "QSize kdk::KColorComboBox::popupItemSzie ()" .PP 返回item尺寸 .PP \fBReturns\fP .RS 4 .RE .PP .SS "void kdk::KColorComboBox::setColorList (const QList< QColor > & list)" .PP 以列表形式添加颜色选项 .PP \fBParameters\fP .RS 4 \fIlist\fP .RE .PP .SS "void kdk::KColorComboBox::setComboType (const \fBComboType\fP & type)" .PP 设置显示样式 .PP \fBParameters\fP .RS 4 \fItype\fP .RE .PP .SS "void kdk::KColorComboBox::setPopupItemSize (const QSize & size)" .PP 设置item尺寸 .PP \fBParameters\fP .RS 4 \fIsize\fP .RE .PP .SH "Author" .PP Generated automatically by Doxygen for LIBKYSDK-APPLICATIONS from the source code\&. libkysdk-applications/doxygen/man/man3/timerModule.30000664000175000017500000000051415104543305021440 0ustar fengfeng.TH "timerModule" 3 "Version version:3.0" "LIBKYSDK-APPLICATIONS" \" -*- nroff -*- .ad l .nh .SH NAME timerModule \- TimerModule .SH SYNOPSIS .br .PP .SH "Detailed Description" .PP .PP \fBSince\fP .RS 4 2\&.5\&.2\&.0 .RE .PP .SH "Author" .PP Generated automatically by Doxygen for LIBKYSDK-APPLICATIONS from the source code\&. libkysdk-applications/doxygen/man/man3/kdk_KIconBar.30000664000175000017500000000263215104543305021436 0ustar fengfeng.TH "kdk::KIconBar" 3 "Version version:3.0" "LIBKYSDK-APPLICATIONS" \" -*- nroff -*- .ad l .nh .SH NAME kdk::KIconBar \- 图标和标题组合控件 .SH SYNOPSIS .br .PP .PP \fC#include \fP .PP Inherits QFrame\&. .SS "Signals" .in +1c .ti -1c .RI "void \fBdoubleClick\fP ()" .br .RI "双击会发出双击信号,父widget可以绑定相应槽函数 " .in -1c .SS "Public Member Functions" .in +1c .ti -1c .RI "\fBKIconBar\fP (QWidget *parent=nullptr)" .br .ti -1c .RI "\fBKIconBar\fP (const QString &iconName, const QString &text, QWidget *parent=nullptr)" .br .ti -1c .RI "void \fBsetIcon\fP (const QString &iconName)" .br .RI "设置图标 " .ti -1c .RI "void \fBsetIcon\fP (const QIcon &icon)" .br .RI "设置图标 " .ti -1c .RI "void \fBsetWidgetName\fP (const QString &widgetName)" .br .RI "设置标题 " .ti -1c .RI "QLabel * \fBnameLabel\fP ()" .br .RI "获取标题label " .ti -1c .RI "QLabel * \fBiconLabel\fP ()" .br .RI "获取图标label " .in -1c .SS "Protected Member Functions" .in +1c .ti -1c .RI "void \fBmouseDoubleClickEvent\fP (QMouseEvent *event)" .br .ti -1c .RI "void \fBresizeEvent\fP (QResizeEvent *event)" .br .ti -1c .RI "QSize \fBsizeHint\fP () const override" .br .in -1c .SH "Detailed Description" .PP 图标和标题组合控件 .PP \fBSince\fP .RS 4 1\&.0\&.0 .RE .PP .SH "Author" .PP Generated automatically by Doxygen for LIBKYSDK-APPLICATIONS from the source code\&. libkysdk-applications/doxygen/man/man3/kdk_KMiniCalendarItem.30000664000175000017500000002227215104543305023270 0ustar fengfeng.TH "kdk::KMiniCalendarItem" 3 "Version version:3.0" "LIBKYSDK-APPLICATIONS" \" -*- nroff -*- .ad l .nh .SH NAME kdk::KMiniCalendarItem .SH SYNOPSIS .br .PP .PP Inherits QWidget\&. .SS "Public Types" .in +1c .ti -1c .RI "enum \fBDayType\fP { \fBDayType_MonthPre\fP = 0, \fBDayType_MonthNext\fP = 1, \fBDayType_MonthCurrent\fP = 2, \fBDayType_WeekEnd\fP = 3 }" .br .ti -1c .RI "enum \fBSelectType\fP { \fBSelectType_Rect\fP = 0, \fBSelectType_Circle\fP = 1, \fBSelectType_Triangle\fP = 2, \fBSelectType_Image\fP = 3 }" .br .in -1c .SS "Public Slots" .in +1c .ti -1c .RI "void \fBsetSelect\fP (bool select)" .br .ti -1c .RI "void \fBsetShowLunar\fP (bool showLunar)" .br .ti -1c .RI "void \fBsetSelectType\fP (const SelectType &selectType)" .br .ti -1c .RI "void \fBsetDate\fP (const QDate &date)" .br .ti -1c .RI "void \fBsetLunar\fP (const QString &lunar)" .br .ti -1c .RI "void \fBsetDayType\fP (const DayType &dayType)" .br .ti -1c .RI "void \fBsetDate\fP (const QDate &date, const QString &lunar, const DayType &dayType)" .br .ti -1c .RI "void \fBsetEnableBorder\fP (bool bVisible)" .br .ti -1c .RI "void \fBsetBorderColor\fP (const QColor &borderColor)" .br .ti -1c .RI "void \fBsetWeekColor\fP (const QColor &weekColor)" .br .ti -1c .RI "void \fBsetSuperColor\fP (const QColor &superColor)" .br .ti -1c .RI "void \fBsetLunarColor\fP (const QColor &lunarColor)" .br .ti -1c .RI "void \fBsetCurrentTextColor\fP (const QColor ¤tTextColor)" .br .ti -1c .RI "void \fBsetOtherTextColor\fP (const QColor &otherTextColor)" .br .ti -1c .RI "void \fBsetSelectTextColor\fP (const QColor &selectTextColor)" .br .ti -1c .RI "void \fBsetHoverTextColor\fP (const QColor &hoverTextColor)" .br .ti -1c .RI "void \fBsetCurrentLunarColor\fP (const QColor ¤tLunarColor)" .br .ti -1c .RI "void \fBsetOtherLunarColor\fP (const QColor &otherLunarColor)" .br .ti -1c .RI "void \fBsetSelectLunarColor\fP (const QColor &selectLunarColor)" .br .ti -1c .RI "void \fBsetHoverLunarColor\fP (const QColor &hoverLunarColor)" .br .ti -1c .RI "void \fBsetCurrentBgColor\fP (const QColor ¤tBgColor)" .br .ti -1c .RI "void \fBsetOtherBgColor\fP (const QColor &otherBgColor)" .br .ti -1c .RI "void \fBsetSelectBgColor\fP (const QColor &selectBgColor)" .br .ti -1c .RI "void \fBsetHoverBgColor\fP (const QColor &hoverBgColor)" .br .in -1c .SS "Signals" .in +1c .ti -1c .RI "void \fBclicked\fP (const QDate &date, const KMiniCalendarItem::DayType &dayType)" .br .in -1c .SS "Public Member Functions" .in +1c .ti -1c .RI "\fBKMiniCalendarItem\fP (QWidget *parent=0)" .br .ti -1c .RI "bool \fBgetSelect\fP () const" .br .RI "获取是否选中 " .ti -1c .RI "bool \fBgetShowLunar\fP () const" .br .RI "获取是否显示农历 " .ti -1c .RI "bool \fBgetEnableBorder\fP () const" .br .RI "获取启用边界 " .ti -1c .RI "SelectType \fBgetSelectType\fP () const" .br .RI "获取选择类型 " .ti -1c .RI "QDate \fBgetDate\fP () const" .br .RI "获取当前日期 " .ti -1c .RI "QString \fBgetLunar\fP () const" .br .RI "获取农历信息 " .ti -1c .RI "DayType \fBgetDayType\fP () const" .br .RI "获取日期类型 " .ti -1c .RI "QColor \fBgetBorderColor\fP () const" .br .RI "获取边框颜色 " .ti -1c .RI "QColor \fBgetWeekColor\fP () const" .br .RI "获取周颜色 " .ti -1c .RI "QColor \fBgetSuperColor\fP () const" .br .RI "获取角标颜色 " .ti -1c .RI "QColor \fBgetLunarColor\fP () const" .br .RI "获取农历节日颜色 " .ti -1c .RI "QColor \fBgetCurrentTextColor\fP () const" .br .RI "获取当前月文字颜色 " .ti -1c .RI "QColor \fBgetOtherTextColor\fP () const" .br .RI "获取其他月文字颜色 " .ti -1c .RI "QColor \fBgetSelectTextColor\fP () const" .br .RI "获取选中日期文字颜色 " .ti -1c .RI "QColor \fBgetHoverTextColor\fP () const" .br .RI "获取悬停日期文字颜色 " .ti -1c .RI "QColor \fBgetCurrentLunarColor\fP () const" .br .RI "获取当前月农历文字颜色 " .ti -1c .RI "QColor \fBgetOtherLunarColor\fP () const" .br .RI "获取其他月农历文字颜色 " .ti -1c .RI "QColor \fBgetSelectLunarColor\fP () const" .br .RI "获取选中日期农历文字颜色 " .ti -1c .RI "QColor \fBgetHoverLunarColor\fP () const" .br .RI "获取悬停日期农历文字颜色 " .ti -1c .RI "QColor \fBgetCurrentBgColor\fP () const" .br .RI "获取当前月背景颜色 " .ti -1c .RI "QColor \fBgetOtherBgColor\fP () const" .br .RI "获取其他月背景颜色 " .ti -1c .RI "QColor \fBgetSelectBgColor\fP () const" .br .RI "获取选中日期背景颜色 " .ti -1c .RI "QColor \fBgetHoverBgColor\fP () const" .br .RI "获取悬停日期背景颜色 " .ti -1c .RI "QSize \fBsizeHint\fP () const" .br .ti -1c .RI "QSize \fBminimumSizeHint\fP () const" .br .in -1c .SS "Protected Member Functions" .in +1c .ti -1c .RI "void \fBenterEvent\fP (QEvent *)" .br .ti -1c .RI "void \fBleaveEvent\fP (QEvent *)" .br .ti -1c .RI "void \fBmousePressEvent\fP (QMouseEvent *)" .br .ti -1c .RI "void \fBmouseReleaseEvent\fP (QMouseEvent *)" .br .ti -1c .RI "void \fBpaintEvent\fP (QPaintEvent *)" .br .ti -1c .RI "void \fBdrawBg\fP (QPainter *painter)" .br .ti -1c .RI "void \fBdrawBgCurrent\fP (QPainter *painter, const QColor &color)" .br .ti -1c .RI "void \fBdrawDay\fP (QPainter *painter)" .br .ti -1c .RI "void \fBdrawLunar\fP (QPainter *painter)" .br .in -1c .SS "Properties" .in +1c .ti -1c .RI "bool \fBselect\fP" .br .ti -1c .RI "bool \fBshowLunar\fP" .br .ti -1c .RI "bool \fBenableBorder\fP" .br .ti -1c .RI "SelectType \fBselectType\fP" .br .ti -1c .RI "QDate \fBdate\fP" .br .ti -1c .RI "QString \fBlunar\fP" .br .ti -1c .RI "DayType \fBdayType\fP" .br .ti -1c .RI "QColor \fBborderColor\fP" .br .ti -1c .RI "QColor \fBweekColor\fP" .br .ti -1c .RI "QColor \fBsuperColor\fP" .br .ti -1c .RI "QColor \fBlunarColor\fP" .br .ti -1c .RI "QColor \fBcurrentTextColor\fP" .br .ti -1c .RI "QColor \fBotherTextColor\fP" .br .ti -1c .RI "QColor \fBselectTextColor\fP" .br .ti -1c .RI "QColor \fBhoverTextColor\fP" .br .ti -1c .RI "QColor \fBcurrentLunarColor\fP" .br .ti -1c .RI "QColor \fBotherLunarColor\fP" .br .ti -1c .RI "QColor \fBselectLunarColor\fP" .br .ti -1c .RI "QColor \fBhoverLunarColor\fP" .br .ti -1c .RI "QColor \fBcurrentBgColor\fP" .br .ti -1c .RI "QColor \fBotherBgColor\fP" .br .ti -1c .RI "QColor \fBselectBgColor\fP" .br .ti -1c .RI "QColor \fBhoverBgColor\fP" .br .in -1c .SH "Member Function Documentation" .PP .SS "QColor kdk::KMiniCalendarItem::getBorderColor () const" .PP 获取边框颜色 .PP \fBReturns\fP .RS 4 .RE .PP .SS "QColor kdk::KMiniCalendarItem::getCurrentBgColor () const" .PP 获取当前月背景颜色 .PP \fBReturns\fP .RS 4 .RE .PP .SS "QColor kdk::KMiniCalendarItem::getCurrentLunarColor () const" .PP 获取当前月农历文字颜色 .PP \fBReturns\fP .RS 4 .RE .PP .SS "QColor kdk::KMiniCalendarItem::getCurrentTextColor () const" .PP 获取当前月文字颜色 .PP \fBReturns\fP .RS 4 .RE .PP .SS "QDate kdk::KMiniCalendarItem::getDate () const" .PP 获取当前日期 .PP \fBReturns\fP .RS 4 .RE .PP .SS "DayType kdk::KMiniCalendarItem::getDayType () const" .PP 获取日期类型 .PP \fBReturns\fP .RS 4 .RE .PP .SS "bool kdk::KMiniCalendarItem::getEnableBorder () const" .PP 获取启用边界 .PP \fBReturns\fP .RS 4 .RE .PP .SS "QColor kdk::KMiniCalendarItem::getHoverBgColor () const" .PP 获取悬停日期背景颜色 .PP \fBReturns\fP .RS 4 .RE .PP .SS "QColor kdk::KMiniCalendarItem::getHoverLunarColor () const" .PP 获取悬停日期农历文字颜色 .PP \fBReturns\fP .RS 4 .RE .PP .SS "QColor kdk::KMiniCalendarItem::getHoverTextColor () const" .PP 获取悬停日期文字颜色 .PP \fBReturns\fP .RS 4 .RE .PP .SS "QString kdk::KMiniCalendarItem::getLunar () const" .PP 获取农历信息 .PP \fBReturns\fP .RS 4 .RE .PP .SS "QColor kdk::KMiniCalendarItem::getLunarColor () const" .PP 获取农历节日颜色 .PP \fBReturns\fP .RS 4 .RE .PP .SS "QColor kdk::KMiniCalendarItem::getOtherBgColor () const" .PP 获取其他月背景颜色 .PP \fBReturns\fP .RS 4 .RE .PP .SS "QColor kdk::KMiniCalendarItem::getOtherLunarColor () const" .PP 获取其他月农历文字颜色 .PP \fBReturns\fP .RS 4 .RE .PP .SS "QColor kdk::KMiniCalendarItem::getOtherTextColor () const" .PP 获取其他月文字颜色 .PP \fBReturns\fP .RS 4 .RE .PP .SS "bool kdk::KMiniCalendarItem::getSelect () const" .PP 获取是否选中 .PP \fBReturns\fP .RS 4 .RE .PP .SS "QColor kdk::KMiniCalendarItem::getSelectBgColor () const" .PP 获取选中日期背景颜色 .PP \fBReturns\fP .RS 4 .RE .PP .SS "QColor kdk::KMiniCalendarItem::getSelectLunarColor () const" .PP 获取选中日期农历文字颜色 .PP \fBReturns\fP .RS 4 .RE .PP .SS "QColor kdk::KMiniCalendarItem::getSelectTextColor () const" .PP 获取选中日期文字颜色 .PP \fBReturns\fP .RS 4 .RE .PP .SS "SelectType kdk::KMiniCalendarItem::getSelectType () const" .PP 获取选择类型 .PP \fBReturns\fP .RS 4 .RE .PP .SS "bool kdk::KMiniCalendarItem::getShowLunar () const" .PP 获取是否显示农历 .PP \fBReturns\fP .RS 4 .RE .PP .SS "QColor kdk::KMiniCalendarItem::getSuperColor () const" .PP 获取角标颜色 .PP \fBReturns\fP .RS 4 .RE .PP .SS "QColor kdk::KMiniCalendarItem::getWeekColor () const" .PP 获取周颜色 .PP \fBReturns\fP .RS 4 .RE .PP .SH "Author" .PP Generated automatically by Doxygen for LIBKYSDK-APPLICATIONS from the source code\&. libkysdk-applications/doxygen/man/man3/kdk_KBallonTip.30000664000175000017500000000333515104543305022006 0ustar fengfeng.TH "kdk::KBallonTip" 3 "Version version:3.0" "LIBKYSDK-APPLICATIONS" \" -*- nroff -*- .ad l .nh .SH NAME kdk::KBallonTip \- 消息提示框,支持五种样式 .SH SYNOPSIS .br .PP .PP \fC#include \fP .PP Inherits QWidget\&. .SS "Public Member Functions" .in +1c .ti -1c .RI "\fBKBallonTip\fP (QWidget *parent=nullptr)" .br .ti -1c .RI "\fBKBallonTip\fP (const QString &content, const \fBTipType\fP &type, QWidget *parent=nullptr)" .br .ti -1c .RI "void \fBshowInfo\fP ()" .br .RI "显示时间完毕后消失 " .ti -1c .RI "void \fBsetTipType\fP (const \fBTipType\fP &type)" .br .RI "设置类型 " .ti -1c .RI "\fBTipType\fP \fBtipType\fP ()" .br .RI "返回类型 " .ti -1c .RI "void \fBsetText\fP (const QString &\fBtext\fP)" .br .RI "设置文本内容 " .ti -1c .RI "QString \fBtext\fP ()" .br .RI "text " .ti -1c .RI "void \fBsetContentsMargins\fP (int left, int top, int right, int bottom)" .br .RI "设置内容边距 " .ti -1c .RI "void \fBsetContentsMargins\fP (const QMargins &margins)" .br .RI "设置内容边距 " .ti -1c .RI "void \fBsetTipTime\fP (int my_time)" .br .RI "设置持续时间 " .ti -1c .RI "QHBoxLayout * \fBhBoxLayout\fP ()" .br .RI "获取kballontip的水平布局 " .ti -1c .RI "void \fBsetVariableIcon\fP (QIcon icon)" .br .RI "设置可变类型的icon " .ti -1c .RI "QPixmap \fBvariableIcon\fP ()" .br .RI "获取可变类型的icon " .in -1c .SS "Protected Member Functions" .in +1c .ti -1c .RI "void \fBpaintEvent\fP (QPaintEvent *event) override" .br .in -1c .SH "Detailed Description" .PP 消息提示框,支持五种样式 .PP \fBExamples\fP .in +1c \fBtestballontip/widget\&.h\fP\&. .SH "Author" .PP Generated automatically by Doxygen for LIBKYSDK-APPLICATIONS from the source code\&. libkysdk-applications/doxygen/man/man3/ContainerModules.30000664000175000017500000000127115104543305022426 0ustar fengfeng.TH "ContainerModules" 3 "Version version:3.0" "LIBKYSDK-APPLICATIONS" \" -*- nroff -*- .ad l .nh .SH NAME ContainerModules \- ContainerModules .PP \- 存在combox的frame .SH SYNOPSIS .br .PP .SH "Detailed Description" .PP 存在combox的frame 继承qtbaleview .PP 创建一个带 \fBKSwitchButton\fP 的 Frame .PP 创建一个带 \fBKSlider\fP 的 Frame .PP 创建一个 Spacing 为 1 的垂直布局 Frame .PP 创建一个带 QButtonGroup 的 Frame .PP 带QpushButton的frame .PP 创建一个带 QLineEdit 的 Frame .PP \fBSince\fP .RS 4 3\&.0\&.1\&.0 { .PP 2\&.5\&.2\&.0 { .RE .PP .SH "Author" .PP Generated automatically by Doxygen for LIBKYSDK-APPLICATIONS from the source code\&. libkysdk-applications/doxygen/man/man3/kdk_KCustomDateEdit.30000664000175000017500000000245515104543305023002 0ustar fengfeng.TH "kdk::KCustomDateEdit" 3 "Version version:3.0" "LIBKYSDK-APPLICATIONS" \" -*- nroff -*- .ad l .nh .SH NAME kdk::KCustomDateEdit .SH SYNOPSIS .br .PP .PP Inherits QDateTimeEdit\&. .SS "Signals" .in +1c .ti -1c .RI "void \fBchangeDate\fP ()" .br .in -1c .SS "Public Member Functions" .in +1c .ti -1c .RI "\fBKCustomDateEdit\fP (QWidget *parent=nullptr)" .br .ti -1c .RI "void \fBshowCalendar\fP ()" .br .RI "触发日历控件显示 " .ti -1c .RI "void \fBsetShowLunar\fP (bool showLunar)" .br .RI "是否显示农历 " .ti -1c .RI "void \fBupdateStyle\fP (bool isDark)" .br .RI "适应系统风格 " .in -1c .SS "Protected Member Functions" .in +1c .ti -1c .RI "void \fBmousePressEvent\fP (QMouseEvent *event) override" .br .ti -1c .RI "void \fBpaintEvent\fP (QPaintEvent *e) override" .br .ti -1c .RI "bool \fBeventFilter\fP (QObject *obj, QEvent *event) override" .br .in -1c .SH "Member Function Documentation" .PP .SS "void kdk::KCustomDateEdit::setShowLunar (bool showLunar)" .PP 是否显示农历 .PP \fBParameters\fP .RS 4 \fIshowLunar\fP .RE .PP .SS "void kdk::KCustomDateEdit::updateStyle (bool isDark)" .PP 适应系统风格 .PP \fBParameters\fP .RS 4 \fIisDark:是否深色模式\fP .RE .PP .SH "Author" .PP Generated automatically by Doxygen for LIBKYSDK-APPLICATIONS from the source code\&. libkysdk-applications/doxygen/man/man3/kdk_KSecurityQuestionDialog.30000664000175000017500000001356515104543305024607 0ustar fengfeng.TH "kdk::KSecurityQuestionDialog" 3 "Version version:3.0" "LIBKYSDK-APPLICATIONS" \" -*- nroff -*- .ad l .nh .SH NAME kdk::KSecurityQuestionDialog \- 继承自 KDialog, .SH SYNOPSIS .br .PP .PP \fC#include \fP .PP Inherits \fBkdk::KDialog\fP\&. .SS "Public Member Functions" .in +1c .ti -1c .RI "\fBKSecurityQuestionDialog\fP (QWidget *parent=nullptr)" .br .ti -1c .RI "void \fBsetTitleText\fP (const QString &text)" .br .RI "设置对话框标题 " .ti -1c .RI "void \fBaddSecurityQuestionItem\fP (const int count, bool mutex)" .br .RI "添加安全问题控件 Label combox Label lineedit tipsLabel " .ti -1c .RI "void \fBaddSecurityQuestionItem\fP (const int count, bool mutex, bool isVerify)" .br .RI "添加安全问题控件 Label combox/lineedit Label lineedit tipsLabel " .ti -1c .RI "void \fBinitQustionCombox\fP (const QStringList &questionlist)" .br .RI "添加下拉框选项列表 " .ti -1c .RI "QLabel * \fBquestionLabel\fP (const int questionIndex)" .br .RI "获取下拉框左侧Label " .ti -1c .RI "QComboBox * \fBquestionCombox\fP (const int questionIndex)" .br .RI "获取combox " .ti -1c .RI "QLabel * \fBanswerLabel\fP (const int answerIndex)" .br .RI "获取lineedit左侧label " .ti -1c .RI "QLineEdit * \fBanswerLineedit\fP (const int answerIndex)" .br .RI "获取 lineedit " .ti -1c .RI "QLabel * \fBtipsLabel\fP (const int index)" .br .RI "获取提示 label " .ti -1c .RI "\fBKPushButton\fP * \fBcancelButton\fP ()" .br .RI "获取取消按钮 " .ti -1c .RI "\fBKPushButton\fP * \fBconfirmButton\fP ()" .br .RI "获取确认按钮 " .in -1c Public Member Functions inherited from \fBkdk::KDialog\fP .in +1c .ti -1c .RI "\fBKDialog\fP (QWidget *parent=nullptr)" .br .ti -1c .RI "void \fBsetWindowIcon\fP (const QIcon &icon)" .br .RI "设置对话框图标 " .ti -1c .RI "void \fBsetWindowIcon\fP (const QString &iconName)" .br .RI "设置对话框图标 " .ti -1c .RI "void \fBsetWindowTitle\fP (const QString &)" .br .RI "设置对话框标题名称 " .ti -1c .RI "QPushButton * \fBmaximumButton\fP ()" .br .RI "获取最大化按钮 " .ti -1c .RI "QPushButton * \fBminimumButton\fP ()" .br .RI "获取最小化按钮 " .ti -1c .RI "QPushButton * \fBcloseButton\fP ()" .br .RI "获取关闭按钮 " .ti -1c .RI "\fBKMenuButton\fP * \fBmenuButton\fP ()" .br .RI "获取下拉菜单按钮 " .ti -1c .RI "QWidget * \fBmainWidget\fP ()" .br .RI "获取主内容区Widget " .ti -1c .RI "\fBKWindowButtonBar\fP * \fBwindowButtonBar\fP ()" .br .RI "windowButtonBar " .ti -1c .RI "\fBKIconBar\fP * \fBiconBar\fP ()" .br .RI "iconBar " .in -1c .SS "Protected Member Functions" .in +1c .ti -1c .RI "void \fBkeyPressEvent\fP (QKeyEvent *)" .br .in -1c Protected Member Functions inherited from \fBkdk::KDialog\fP .in +1c .ti -1c .RI "bool \fBeventFilter\fP (QObject *target, QEvent *event) override" .br .ti -1c .RI "void \fBchangeTheme\fP ()" .br .ti -1c .RI "void \fBchangeIconStyle\fP ()" .br .ti -1c .RI "QBoxLayout * \fBmainLayout\fP ()" .br .in -1c .SH "Detailed Description" .PP 继承自 KDialog, .PP \fBSince\fP .RS 4 2\&.4\&.1\&.0 .RE .PP .SH "Member Function Documentation" .PP .SS "void kdk::KSecurityQuestionDialog::addSecurityQuestionItem (const int count, bool mutex)" .PP 添加安全问题控件 Label combox Label lineedit tipsLabel .PP \fBParameters\fP .RS 4 \fIcount\fP 控件个数 .br \fImutex\fP 是否开启下拉框互斥校验,若开启后,已被选择项,在其他下拉框中被置灰 .RE .PP .SS "void kdk::KSecurityQuestionDialog::addSecurityQuestionItem (const int count, bool mutex, bool isVerify)" .PP 添加安全问题控件 Label combox/lineedit Label lineedit tipsLabel .PP \fBParameters\fP .RS 4 \fIcount\fP 控件个数 .br \fImutex\fP 是否开启下拉框互斥校验,若开启后,已被选择项,在其他下拉框中被置灰 .br \fIisVerify\fP 是否为校验窗口 .RE .PP .SS "QLabel * kdk::KSecurityQuestionDialog::answerLabel (const int answerIndex)" .PP 获取lineedit左侧label .PP \fBParameters\fP .RS 4 \fIanswerIndex\fP item索引 [0,count) .RE .PP \fBReturns\fP .RS 4 QLabel lineedit左侧label,若未获取到,返回nullptr .RE .PP .SS "QLineEdit * kdk::KSecurityQuestionDialog::answerLineedit (const int answerIndex)" .PP 获取 lineedit .PP \fBParameters\fP .RS 4 \fIanswerIndex\fP item索引 [0,count) .RE .PP \fBReturns\fP .RS 4 QLineEdit lineedit,若未获取到,返回nullptr .RE .PP .SS "\fBKPushButton\fP * kdk::KSecurityQuestionDialog::cancelButton ()" .PP 获取取消按钮 .PP \fBReturns\fP .RS 4 \fBKPushButton\fP .RE .PP .SS "\fBKPushButton\fP * kdk::KSecurityQuestionDialog::confirmButton ()" .PP 获取确认按钮 .PP \fBReturns\fP .RS 4 \fBKPushButton\fP .RE .PP .SS "void kdk::KSecurityQuestionDialog::initQustionCombox (const QStringList & questionlist)" .PP 添加下拉框选项列表 .PP \fBParameters\fP .RS 4 \fIquestionlist\fP .RE .PP .SS "QComboBox * kdk::KSecurityQuestionDialog::questionCombox (const int questionIndex)" .PP 获取combox .PP \fBParameters\fP .RS 4 \fIquestionIndex\fP item索引 [0,count) .RE .PP \fBReturns\fP .RS 4 QComboBox 下拉框,若未获取到,返回nullptr .RE .PP .SS "QLabel * kdk::KSecurityQuestionDialog::questionLabel (const int questionIndex)" .PP 获取下拉框左侧Label .PP \fBParameters\fP .RS 4 \fIquestionIndex\fP item索引 [0,count) .RE .PP \fBReturns\fP .RS 4 QLabel 下拉框左侧Label,若未获取到,返回nullptr .RE .PP .SS "void kdk::KSecurityQuestionDialog::setTitleText (const QString & text)" .PP 设置对话框标题 .PP \fBParameters\fP .RS 4 \fItext\fP 标题 .RE .PP .SS "QLabel * kdk::KSecurityQuestionDialog::tipsLabel (const int index)" .PP 获取提示 label .PP \fBParameters\fP .RS 4 \fIindex\fP item 索引 [0,count) .RE .PP \fBReturns\fP .RS 4 QLabel 提示label,若未获取到,返回nullptr .RE .PP .SH "Author" .PP Generated automatically by Doxygen for LIBKYSDK-APPLICATIONS from the source code\&. libkysdk-applications/doxygen/man/man3/KLunarCalendarInfo.30000664000175000017500000000054115104543305022614 0ustar fengfeng.TH "KLunarCalendarInfo" 3 "Version version:3.0" "LIBKYSDK-APPLICATIONS" \" -*- nroff -*- .ad l .nh .SH NAME KLunarCalendarInfo \- KLunarCalendarInfo .SH SYNOPSIS .br .PP .SH "Detailed Description" .PP .PP \fBSince\fP .RS 4 2\&.5\&.2\&.0 .RE .PP .SH "Author" .PP Generated automatically by Doxygen for LIBKYSDK-APPLICATIONS from the source code\&. libkysdk-applications/doxygen/man/man3/kdk_KLineEdit.30000664000175000017500000000141615104543305021615 0ustar fengfeng.TH "kdk::KLineEdit" 3 "Version version:3.0" "LIBKYSDK-APPLICATIONS" \" -*- nroff -*- .ad l .nh .SH NAME kdk::KLineEdit .SH SYNOPSIS .br .PP .PP Inherits QLineEdit\&. .SS "Public Member Functions" .in +1c .ti -1c .RI "\fBKLineEdit\fP (QWidget *parent=nullptr)" .br .ti -1c .RI "QPushButton * \fBpushbutton\fP ()" .br .RI "获取按钮 " .in -1c .SS "Protected Member Functions" .in +1c .ti -1c .RI "void \fBresizeEvent\fP (QResizeEvent *event)" .br .ti -1c .RI "bool \fBeventFilter\fP (QObject *watched, QEvent *event)" .br .in -1c .SH "Member Function Documentation" .PP .SS "QPushButton * kdk::KLineEdit::pushbutton ()" .PP 获取按钮 .PP \fBReturns\fP .RS 4 .RE .PP .SH "Author" .PP Generated automatically by Doxygen for LIBKYSDK-APPLICATIONS from the source code\&. libkysdk-applications/doxygen/man/man3/kdk_KPushButtonFrame.30000664000175000017500000000541715104543305023213 0ustar fengfeng.TH "kdk::KPushButtonFrame" 3 "Version version:3.0" "LIBKYSDK-APPLICATIONS" \" -*- nroff -*- .ad l .nh .SH NAME kdk::KPushButtonFrame .SH SYNOPSIS .br .PP .PP Inherits \fBkdk::KBaseFrame\fP\&. .SS "Public Member Functions" .in +1c .ti -1c .RI "\fBKPushButtonFrame\fP (const QString title, QWidget *parent=nullptr, \fBBorderRadiusStyle\fP style=\fBBorderRadiusStyle::None\fP)" .br .RI "创建一个带 QPushButton 的 Frame " .ti -1c .RI "\fBKPushButton\fP * \fBpushButton\fP ()" .br .RI "获取 m_pushButton " .ti -1c .RI "\fBKLabel\fP * \fBtitleLabel\fP ()" .br .RI "获取label " .ti -1c .RI "QHBoxLayout * \fBmainHLayout\fP ()" .br .RI "获取layout " .in -1c Public Member Functions inherited from \fBkdk::KBaseFrame\fP .in +1c .ti -1c .RI "\fBKBaseFrame\fP (QWidget *parent=nullptr, \fBBorderRadiusStyle\fP style=\fBAround\fP, bool heightAdaptive=false)" .br .RI "构造函数 " .ti -1c .RI "void \fBsetRadiusType\fP (\fBBorderRadiusStyle\fP style)" .br .RI "设置圆角风格 " .ti -1c .RI "bool \fBgetTabletMode\fP ()" .br .RI "获取平板模式 " .ti -1c .RI "bool \fBisContainer\fP ()" .br .RI "获取是否是一个容器frame,此时settinggroup需要设置的是其子frame的圆角 " .ti -1c .RI "void \fBsetContainer\fP (bool b=false)" .br .RI "设置该frame是否是一个容器frame,如果是同时setFrameShape(NoFrame); " .in -1c .SS "Additional Inherited Members" Public Types inherited from \fBkdk::KBaseFrame\fP .in +1c .ti -1c .RI "enum \fBBorderRadiusStyle\fP { \fBTop\fP, \fBNone\fP, \fBBottom\fP, \fBAround\fP }" .br .in -1c Signals inherited from \fBkdk::KBaseFrame\fP .in +1c .ti -1c .RI "void \fBtabletModeChanged\fP (bool b)" .br .in -1c Protected Member Functions inherited from \fBkdk::KBaseFrame\fP .in +1c .ti -1c .RI "void \fBpaintEvent\fP (QPaintEvent *e)" .br .in -1c .SH "Constructor & Destructor Documentation" .PP .SS "kdk::KPushButtonFrame::KPushButtonFrame (const QString title, QWidget * parent = \fCnullptr\fP, \fBBorderRadiusStyle\fP style = \fC\fBBorderRadiusStyle::None\fP\fP)\fC [explicit]\fP" .PP 创建一个带 QPushButton 的 Frame .PP \fBParameters\fP .RS 4 \fItitle\fP text of m_settingName .br \fIstyle\fP 设置圆角(None:无圆角,Top:上圆角,Bottom:下圆角,Around:四圆角) .br \fIparent\fP .RE .PP .SH "Member Function Documentation" .PP .SS "QHBoxLayout * kdk::KPushButtonFrame::mainHLayout ()" .PP 获取layout .PP \fBReturns\fP .RS 4 QHBoxLayout .RE .PP .SS "\fBKPushButton\fP * kdk::KPushButtonFrame::pushButton ()" .PP 获取 m_pushButton .PP \fBReturns\fP .RS 4 \fBKPushButton\fP: m_pushButton .RE .PP .SS "\fBKLabel\fP * kdk::KPushButtonFrame::titleLabel ()" .PP 获取label .PP \fBReturns\fP .RS 4 \fBKLabel\fP .RE .PP .SH "Author" .PP Generated automatically by Doxygen for LIBKYSDK-APPLICATIONS from the source code\&. libkysdk-applications/doxygen/man/man3/kdk_KWidgetUtils.30000664000175000017500000000157215104543305022367 0ustar fengfeng.TH "kdk::KWidgetUtils" 3 "Version version:3.0" "LIBKYSDK-APPLICATIONS" \" -*- nroff -*- .ad l .nh .SH NAME kdk::KWidgetUtils .SH SYNOPSIS .br .PP .SS "Static Public Member Functions" .in +1c .ti -1c .RI "static void \fBhighDpiScaling\fP ()" .br .RI "适配高分屏,需要在定义QApplication对象前,调用该函数 \fBKWidgetUtils::highDpiScaling()\fP; QApplication a(argc, argv); " .ti -1c .RI "static bool \fBcheckCompositorRunning\fP (void)" .br .RI "判断合成器是否开启 " .in -1c .SH "Member Function Documentation" .PP .SS "static bool kdk::KWidgetUtils::checkCompositorRunning (void)\fC [static]\fP" .PP 判断合成器是否开启 .PP \fBParameters\fP .RS 4 \fI无\fP .RE .PP \fBReturn values\fP .RS 4 \fItrue\fP 开启 .br \fIfalse\fP 没开启 .RE .PP .SH "Author" .PP Generated automatically by Doxygen for LIBKYSDK-APPLICATIONS from the source code\&. libkysdk-applications/doxygen/man/man3/ContainerModule.30000664000175000017500000000065415104543305022247 0ustar fengfeng.TH "ContainerModule" 3 "Version version:3.0" "LIBKYSDK-APPLICATIONS" \" -*- nroff -*- .ad l .nh .SH NAME ContainerModule \- ContainerModule .PP \- 支持圆角四种类型的容器 .SH SYNOPSIS .br .PP .SH "Detailed Description" .PP 支持圆角四种类型的容器 { .PP \fBSince\fP .RS 4 3\&.0\&.1\&.0 { .RE .PP .SH "Author" .PP Generated automatically by Doxygen for LIBKYSDK-APPLICATIONS from the source code\&. libkysdk-applications/doxygen/man/man3/kdk_KListWidget.30000664000175000017500000000070715104543305022201 0ustar fengfeng.TH "kdk::KListWidget" 3 "Version version:3.0" "LIBKYSDK-APPLICATIONS" \" -*- nroff -*- .ad l .nh .SH NAME kdk::KListWidget .SH SYNOPSIS .br .PP .PP Inherits QListWidget\&. .SS "Public Member Functions" .in +1c .ti -1c .RI "\fBKListWidget\fP (QWidget *parent)" .br .ti -1c .RI "void \fBAddItemWidget\fP (\fBKItemWidget\fP *m_itemwidget)" .br .in -1c .SH "Author" .PP Generated automatically by Doxygen for LIBKYSDK-APPLICATIONS from the source code\&. libkysdk-applications/doxygen/man/man3/kdk_KButtonBox.30000664000175000017500000001264715104543305022054 0ustar fengfeng.TH "kdk::KButtonBox" 3 "Version version:3.0" "LIBKYSDK-APPLICATIONS" \" -*- nroff -*- .ad l .nh .SH NAME kdk::KButtonBox \- 提供了一个按钮类容器 .SH SYNOPSIS .br .PP .PP \fC#include \fP .PP Inherits QWidget\&. .SS "Signals" .in +1c .ti -1c .RI "void \fBbuttonClicked\fP (QAbstractButton *)" .br .ti -1c .RI "void \fBbuttonPressed\fP (QAbstractButton *)" .br .ti -1c .RI "void \fBbuttonReleased\fP (QAbstractButton *)" .br .ti -1c .RI "void \fBbuttonToggled\fP (QAbstractButton *, bool)" .br .in -1c .SS "Public Member Functions" .in +1c .ti -1c .RI "\fBKButtonBox\fP (QWidget *parent=nullptr)" .br .ti -1c .RI "Qt::Orientation \fBorientation\fP ()" .br .RI "获取KButtonBox的布局类型 " .ti -1c .RI "void \fBsetOrientation\fP (Qt::Orientation \fBorientation\fP)" .br .RI "设置KButtonBox的布局类型,包括水平类型和垂直类型 " .ti -1c .RI "void \fBaddButton\fP (\fBKPushButton\fP *\fBbutton\fP, int i=\-1)" .br .RI "添加按钮 " .ti -1c .RI "void \fBremoveButton\fP (\fBKPushButton\fP *\fBbutton\fP)" .br .RI "删除按钮 " .ti -1c .RI "void \fBremoveButton\fP (int i)" .br .RI "按id删除指定按钮 " .ti -1c .RI "void \fBsetButtonList\fP (const QList< \fBKPushButton\fP * > &list)" .br .RI "以列表形式向KButtonBox中添加按钮 " .ti -1c .RI "QList< \fBKPushButton\fP * > \fBbuttonList\fP ()" .br .RI "获取KButtonBox中的按钮列表 " .ti -1c .RI "void \fBsetBorderRadius\fP (int radius)" .br .RI "设置KButtonBox首尾部分按钮的圆角 " .ti -1c .RI "int \fBborderRadius\fP ()" .br .RI "获取KButtonBox首尾部分按钮的圆角 " .ti -1c .RI "void \fBsetId\fP (\fBKPushButton\fP *\fBbutton\fP, int \fBid\fP)" .br .RI "设置按钮id " .ti -1c .RI "int \fBid\fP (\fBKPushButton\fP *\fBbutton\fP)" .br .RI "获取按钮id " .ti -1c .RI "\fBKPushButton\fP * \fBcheckedButton\fP ()" .br .RI "返回已选中的按钮 " .ti -1c .RI "\fBKPushButton\fP * \fBbutton\fP (int \fBid\fP)" .br .RI "通过按钮id获取按钮 " .ti -1c .RI "int \fBcheckedId\fP ()" .br .RI "返回已选中按钮的id " .ti -1c .RI "void \fBsetExclusive\fP (bool)" .br .RI "设置KButtonBox按钮间是否互斥 " .ti -1c .RI "bool \fBexclusive\fP ()" .br .RI "返回KButtonBox按钮间是否互斥 " .ti -1c .RI "void \fBsetCheckable\fP (bool flag)" .br .RI "设置KButtonBox中的按钮是否可选中 " .ti -1c .RI "bool \fBisCheckable\fP ()" .br .RI "返回KButtonBox中的按钮是否可选中 " .ti -1c .RI "void \fBsetShadow\fP (bool flag)" .br .RI "设置是否启动阴影效果 " .ti -1c .RI "bool \fBshadow\fP ()" .br .RI "获取是否启用阴影效果 " .in -1c .SH "Detailed Description" .PP 提供了一个按钮类容器 .PP \fBSince\fP .RS 4 2\&.0\&.2\&.1 .RE .PP .SH "Member Function Documentation" .PP .SS "void kdk::KButtonBox::addButton (\fBKPushButton\fP * button, int i = \fC\-1\fP)" .PP 添加按钮 .PP \fBParameters\fP .RS 4 \fIbutton\fP .RE .PP .SS "int kdk::KButtonBox::borderRadius ()" .PP 获取KButtonBox首尾部分按钮的圆角 .PP \fBReturns\fP .RS 4 .RE .PP .SS "\fBKPushButton\fP * kdk::KButtonBox::button (int id)" .PP 通过按钮id获取按钮 .PP \fBParameters\fP .RS 4 \fIid\fP .RE .PP \fBReturns\fP .RS 4 .RE .PP .SS "QList< \fBKPushButton\fP * > kdk::KButtonBox::buttonList ()" .PP 获取KButtonBox中的按钮列表 .PP \fBReturns\fP .RS 4 .RE .PP .SS "\fBKPushButton\fP * kdk::KButtonBox::checkedButton ()" .PP 返回已选中的按钮 .PP \fBReturns\fP .RS 4 .RE .PP .SS "int kdk::KButtonBox::checkedId ()" .PP 返回已选中按钮的id .PP \fBReturns\fP .RS 4 .RE .PP .SS "bool kdk::KButtonBox::exclusive ()" .PP 返回KButtonBox按钮间是否互斥 .PP \fBReturns\fP .RS 4 .RE .PP .SS "int kdk::KButtonBox::id (\fBKPushButton\fP * button)" .PP 获取按钮id .PP \fBParameters\fP .RS 4 \fIbutton\fP .RE .PP \fBReturns\fP .RS 4 .RE .PP .SS "bool kdk::KButtonBox::isCheckable ()" .PP 返回KButtonBox中的按钮是否可选中 .PP \fBReturns\fP .RS 4 .RE .PP .SS "Qt::Orientation kdk::KButtonBox::orientation ()" .PP 获取KButtonBox的布局类型 .PP \fBReturns\fP .RS 4 .RE .PP .SS "void kdk::KButtonBox::removeButton (int i)" .PP 按id删除指定按钮 .PP \fBParameters\fP .RS 4 \fIi\fP .RE .PP .SS "void kdk::KButtonBox::removeButton (\fBKPushButton\fP * button)" .PP 删除按钮 .PP \fBParameters\fP .RS 4 \fIbutton\fP .RE .PP .SS "void kdk::KButtonBox::setBorderRadius (int radius)" .PP 设置KButtonBox首尾部分按钮的圆角 .PP \fBParameters\fP .RS 4 \fIradius\fP .RE .PP .SS "void kdk::KButtonBox::setButtonList (const QList< \fBKPushButton\fP * > & list)" .PP 以列表形式向KButtonBox中添加按钮 .PP \fBParameters\fP .RS 4 \fIlist\fP .br \fIcheckable\fP .RE .PP .SS "void kdk::KButtonBox::setId (\fBKPushButton\fP * button, int id)" .PP 设置按钮id .PP \fBParameters\fP .RS 4 \fIbutton\fP .br \fIid\fP .RE .PP .SS "void kdk::KButtonBox::setOrientation (Qt::Orientation orientation)" .PP 设置KButtonBox的布局类型,包括水平类型和垂直类型 .PP \fBParameters\fP .RS 4 \fIorientation\fP .RE .PP .SS "void kdk::KButtonBox::setShadow (bool flag)" .PP 设置是否启动阴影效果 .PP \fBParameters\fP .RS 4 \fIflag\fP .RE .PP \fBSince\fP .RS 4 2\&.4\&.1\&.0 .RE .PP .SS "bool kdk::KButtonBox::shadow ()" .PP 获取是否启用阴影效果 .PP \fBReturns\fP .RS 4 bool .RE .PP \fBSince\fP .RS 4 2\&.4\&.1\&.0 .RE .PP .SH "Author" .PP Generated automatically by Doxygen for LIBKYSDK-APPLICATIONS from the source code\&. libkysdk-applications/doxygen/man/man3/PushButtonModule.30000664000175000017500000000060415104543305022433 0ustar fengfeng.TH "PushButtonModule" 3 "Version version:3.0" "LIBKYSDK-APPLICATIONS" \" -*- nroff -*- .ad l .nh .SH NAME PushButtonModule \- PushButtonModule .PP \- 添加按钮 .SH SYNOPSIS .br .PP .SH "Detailed Description" .PP 添加按钮 .PP \fBSince\fP .RS 4 3\&.0\&.1\&.0 { .RE .PP .SH "Author" .PP Generated automatically by Doxygen for LIBKYSDK-APPLICATIONS from the source code\&. libkysdk-applications/doxygen/man/man3/kdk_AccessInfoHelper.30000664000175000017500000000125115104543305023157 0ustar fengfeng.TH "kdk::AccessInfoHelper< T >" 3 "Version version:3.0" "LIBKYSDK-APPLICATIONS" \" -*- nroff -*- .ad l .nh .SH NAME kdk::AccessInfoHelper< T > .SH SYNOPSIS .br .PP .SS "Public Member Functions" .in +1c .ti -1c .RI "\fBAccessInfoHelper\fP (T *widget)" .br .ti -1c .RI "void \fBsetObjectInfo\fP (const QString &widgetName, const QString &pluginName, const QString &extend=QString())" .br .ti -1c .RI "void \fBsetAllAttribute\fP (const QString &widgetName, const QString &pluginName=QString(), const QString &extend=QString(), const QString &description=QString())" .br .in -1c .SH "Author" .PP Generated automatically by Doxygen for LIBKYSDK-APPLICATIONS from the source code\&. libkysdk-applications/doxygen/man/man3/kdk_KSearchLineEdit.30000664000175000017500000000520115104543305022737 0ustar fengfeng.TH "kdk::KSearchLineEdit" 3 "Version version:3.0" "LIBKYSDK-APPLICATIONS" \" -*- nroff -*- .ad l .nh .SH NAME kdk::KSearchLineEdit \- 搜索输入框,可搜索匹配条件的item .SH SYNOPSIS .br .PP .PP \fC#include \fP .PP Inherits QLineEdit\&. .SS "Public Slots" .in +1c .ti -1c .RI "void \fBclear\fP ()" .br .in -1c .SS "Public Member Functions" .in +1c .ti -1c .RI "\fBKSearchLineEdit\fP (QWidget *parent=nullptr)" .br .ti -1c .RI "void \fBsetEnabled\fP (bool)" .br .RI "设置是否可用 " .ti -1c .RI "bool \fBisEnabled\fP ()" .br .RI "返回是否可用 " .ti -1c .RI "void \fBsetClearButtonEnabled\fP (bool enable)" .br .RI "设置是否显示清除按钮 " .ti -1c .RI "bool \fBisClearButtonEnabled\fP () const" .br .RI "返回是否显示清除按钮 " .ti -1c .RI "QString \fBplaceholderText\fP () const" .br .RI "返回placeholder " .ti -1c .RI "void \fBsetPlaceholderText\fP (const QString &)" .br .RI "设置placeholder " .ti -1c .RI "Qt::Alignment \fBplaceholderAlignment\fP () const" .br .RI "返回placeholder的对齐方式 " .ti -1c .RI "void \fBsetPlaceholderAlignment\fP (Qt::Alignment flag)" .br .RI "设置placeholder的对齐方式 " .ti -1c .RI "Qt::Alignment \fBalignment\fP () const" .br .RI "设置输入文本的对齐方式 " .ti -1c .RI "void \fBsetAlignment\fP (Qt::Alignment flag)" .br .RI "设置输入文本的对齐方式返回 " .ti -1c .RI "void \fBsetTranslucent\fP (bool flag)" .br .RI "设置是否启用半透明效果 " .ti -1c .RI "bool \fBisTranslucent\fP ()" .br .RI "获取是否启用半透明效果 " .ti -1c .RI "void \fBreloadStyle\fP ()" .br .RI "重新加载style " .ti -1c .RI "\fBKToolButton\fP * \fBcustomButton\fP ()" .br .RI "获取自定义按钮 " .ti -1c .RI "void \fBsetGradation\fP (bool flag)" .br .RI "是否启用渐变色 " .ti -1c .RI "void \fBsetCustomButtonVisible\fP (bool flag)" .br .RI "设置智能语义按钮是否可见 " .ti -1c .RI "bool \fBisCustomButtonVisible\fP ()" .br .RI "返回智能语义按钮是否可见 " .in -1c .SS "Protected Member Functions" .in +1c .ti -1c .RI "bool \fBeventFilter\fP (QObject *watched, QEvent *event)" .br .ti -1c .RI "void \fBresizeEvent\fP (QResizeEvent *event)" .br .ti -1c .RI "void \fBsetVisible\fP (bool visible)" .br .ti -1c .RI "void \fBpaintEvent\fP (QPaintEvent *event)" .br .ti -1c .RI "QSize \fBsizeHint\fP () const override" .br .in -1c .SH "Detailed Description" .PP 搜索输入框,可搜索匹配条件的item .PP \fBSince\fP .RS 4 1\&.0\&.0 .RE .PP .PP \fBExamples\fP .in +1c \fBtestsearchlinedit/widget\&.h\fP\&. .SH "Author" .PP Generated automatically by Doxygen for LIBKYSDK-APPLICATIONS from the source code\&. libkysdk-applications/doxygen/man/man3/kdk_KTextEditor.30000664000175000017500000000142015104543305022206 0ustar fengfeng.TH "kdk::KTextEditor" 3 "Version version:3.0" "LIBKYSDK-APPLICATIONS" \" -*- nroff -*- .ad l .nh .SH NAME kdk::KTextEditor .SH SYNOPSIS .br .PP .PP Inherits QWidget\&. .SS "Public Member Functions" .in +1c .ti -1c .RI "\fBKTextEditor\fP (QWidget *parent=nullptr)" .br .ti -1c .RI "QTextEdit * \fBtextEdit\fP ()" .br .RI "获取QTextedit " .in -1c .SS "Protected Member Functions" .in +1c .ti -1c .RI "void \fBpaintEvent\fP (QPaintEvent *event)" .br .ti -1c .RI "bool \fBeventFilter\fP (QObject *watched, QEvent *event)" .br .in -1c .SH "Member Function Documentation" .PP .SS "QTextEdit * kdk::KTextEditor::textEdit ()" .PP 获取QTextedit .PP \fBReturns\fP .RS 4 .RE .PP .SH "Author" .PP Generated automatically by Doxygen for LIBKYSDK-APPLICATIONS from the source code\&. libkysdk-applications/doxygen/man/man3/kdk_KDirTabBar.30000664000175000017500000000557215104543305021721 0ustar fengfeng.TH "kdk::KDirTabBar" 3 "Version version:3.0" "LIBKYSDK-APPLICATIONS" \" -*- nroff -*- .ad l .nh .SH NAME kdk::KDirTabBar \- 目录层级控件 .SH SYNOPSIS .br .PP .PP \fC#include \fP .PP Inherits QWidget\&. .SS "Signals" .in +1c .ti -1c .RI "void \fBtabBarClicked\fP (const QString uri)" .br .in -1c .SS "Public Member Functions" .in +1c .ti -1c .RI "\fBKDirTabBar\fP (QWidget *parent=nullptr)" .br .ti -1c .RI "void \fBsetCurrentPath\fP (const QString Dirpath)" .br .RI "设置目标路径 " .ti -1c .RI "QString \fBcurrentPath\fP () const" .br .RI "获取目标路径 " .ti -1c .RI "void \fBsetVisibleDepth\fP (const int depth)" .br .RI "设置tabbar显示个数 " .ti -1c .RI "int \fBvisibleDepth\fP ()" .br .RI "获取tabbar显示个数 " .ti -1c .RI "void \fBsetIcon\fP (int index, const QIcon &\fBicon\fP)" .br .RI "设置图标 " .ti -1c .RI "QIcon \fBicon\fP (int index)" .br .RI "获取图标 " .ti -1c .RI "void \fBsetRootPath\fP (const QString targetPath)" .br .RI "设置Root " .ti -1c .RI "QString \fBRootPath\fP ()" .br .RI "获取Root路径 " .ti -1c .RI "void \fBsetTextLength\fP (int length)" .br .RI "设置按钮显示字体长度 " .ti -1c .RI "int \fBtextLength\fP ()" .br .RI "返回字体显示长度 " .ti -1c .RI "QList< QToolButton * > \fBbuttons\fP ()" .br .RI "返回button列表 " .in -1c .SH "Detailed Description" .PP 目录层级控件 .PP \fBSince\fP .RS 4 2\&.5\&.2\&.0 .RE .PP .SH "Member Function Documentation" .PP .SS "QList< QToolButton * > kdk::KDirTabBar::buttons ()" .PP 返回button列表 .PP \fBReturns\fP .RS 4 .RE .PP .SS "QString kdk::KDirTabBar::currentPath () const" .PP 获取目标路径 .PP \fBReturns\fP .RS 4 QString .RE .PP .SS "QIcon kdk::KDirTabBar::icon (int index)" .PP 获取图标 .PP \fBReturns\fP .RS 4 QIcon .RE .PP .SS "QString kdk::KDirTabBar::RootPath ()" .PP 获取Root路径 .PP \fBReturns\fP .RS 4 QString .RE .PP .SS "void kdk::KDirTabBar::setCurrentPath (const QString Dirpath)" .PP 设置目标路径 .PP \fBParameters\fP .RS 4 \fIpath\fP .RE .PP .SS "void kdk::KDirTabBar::setIcon (int index, const QIcon & icon)" .PP 设置图标 .PP \fBParameters\fP .RS 4 \fIicon\fP .RE .PP .SS "void kdk::KDirTabBar::setRootPath (const QString targetPath)" .PP 设置Root .PP \fBParameters\fP .RS 4 \fI\fP .RE .PP .SS "void kdk::KDirTabBar::setTextLength (int length)" .PP 设置按钮显示字体长度 .PP \fBParameters\fP .RS 4 \fIint\fP .RE .PP .SS "void kdk::KDirTabBar::setVisibleDepth (const int depth)" .PP 设置tabbar显示个数 .PP \fBParameters\fP .RS 4 \fIint\fP .RE .PP .SS "int kdk::KDirTabBar::textLength ()" .PP 返回字体显示长度 .PP \fBReturns\fP .RS 4 int .RE .PP .SS "int kdk::KDirTabBar::visibleDepth ()" .PP 获取tabbar显示个数 .PP \fBReturns\fP .RS 4 int .RE .PP .SH "Author" .PP Generated automatically by Doxygen for LIBKYSDK-APPLICATIONS from the source code\&. libkysdk-applications/doxygen/man/man3/InputBoxModule.30000664000175000017500000002336415104543305022100 0ustar fengfeng.TH "InputBoxModule" 3 "Version version:3.0" "LIBKYSDK-APPLICATIONS" \" -*- nroff -*- .ad l .nh .SH NAME InputBoxModule \- InputBoxModule .SH SYNOPSIS .br .PP .SS "Classes" .in +1c .ti -1c .RI "class \fBkdk::KPasswordEdit\fP" .br .RI "密码输入框,继承于QLineEdit,支持三种不同状态显示 " .ti -1c .RI "class \fBkdk::KSearchLineEdit\fP" .br .RI "搜索输入框,可搜索匹配条件的item " .in -1c .SS "Enumerations" .in +1c .ti -1c .RI "enum \fBkdk::LoginState\fP { \fBOrdinary\fP, \fBLoginSuccess\fP, \fBLoginFailed\fP }" .br .RI "支持三种状态 " .in -1c .SS "Functions" .in +1c .ti -1c .RI "\fBkdk::KPasswordEdit::KPasswordEdit\fP (QWidget *parent)" .br .ti -1c .RI "void \fBkdk::KPasswordEdit::setState\fP (\fBLoginState\fP \fBstate\fP)" .br .RI "设置状态 " .ti -1c .RI "\fBLoginState\fP \fBkdk::KPasswordEdit::state\fP ()" .br .RI "返回状态 " .ti -1c .RI "void \fBkdk::KPasswordEdit::setLoading\fP (bool flag)" .br .RI "设置加载状态 " .ti -1c .RI "bool \fBkdk::KPasswordEdit::isLoading\fP ()" .br .RI "判断是否处于加载状态 " .ti -1c .RI "QString \fBkdk::KPasswordEdit::placeholderText\fP ()" .br .RI "返回placeholderText " .ti -1c .RI "void \fBkdk::KPasswordEdit::setPlaceholderText\fP (QString &text)" .br .RI "设置PlaceholderText " .ti -1c .RI "void \fBkdk::KPasswordEdit::setClearButtonEnabled\fP (bool enable)" .br .RI "设置是否启用ClearButton " .ti -1c .RI "bool \fBkdk::KPasswordEdit::isClearButtonEnabled\fP () const" .br .RI "返回是否启用了ClearButton " .ti -1c .RI "void \fBkdk::KPasswordEdit::setEchoModeBtnVisible\fP (bool enable)" .br .RI "设置EchoModeBtn是否可见 " .ti -1c .RI "bool \fBkdk::KPasswordEdit::echoModeBtnVisible\fP ()" .br .RI "返回EchoModeBtn是否可见 " .ti -1c .RI "void \fBkdk::KPasswordEdit::setClearBtnVisible\fP (bool enable)" .br .RI "设置ClearBtn是否可见 " .ti -1c .RI "bool \fBkdk::KPasswordEdit::clearBtnVisible\fP ()" .br .RI "返回ClearBtn是否可见 " .ti -1c .RI "void \fBkdk::KPasswordEdit::setEnabled\fP (bool)" .br .RI "设置KLineEdit是否可用 " .ti -1c .RI "void \fBkdk::KPasswordEdit::setEchoMode\fP (EchoMode mode)" .br .RI "setEchoMode " .ti -1c .RI "void \fBkdk::KPasswordEdit::setUseCustomPalette\fP (bool flag)" .br .RI "设置是否走默认palette " .ti -1c .RI "void \fBkdk::KPasswordEdit::resizeEvent\fP (QResizeEvent *event)" .br .ti -1c .RI "bool \fBkdk::KPasswordEdit::eventFilter\fP (QObject *watched, QEvent *event)" .br .ti -1c .RI "QSize \fBkdk::KPasswordEdit::sizeHint\fP () const override" .br .ti -1c .RI "\fBkdk::KSearchLineEdit::KSearchLineEdit\fP (QWidget *parent=nullptr)" .br .ti -1c .RI "void \fBkdk::KSearchLineEdit::setEnabled\fP (bool)" .br .RI "设置是否可用 " .ti -1c .RI "bool \fBkdk::KSearchLineEdit::isEnabled\fP ()" .br .RI "返回是否可用 " .ti -1c .RI "void \fBkdk::KSearchLineEdit::setClearButtonEnabled\fP (bool enable)" .br .RI "设置是否显示清除按钮 " .ti -1c .RI "bool \fBkdk::KSearchLineEdit::isClearButtonEnabled\fP () const" .br .RI "返回是否显示清除按钮 " .ti -1c .RI "QString \fBkdk::KSearchLineEdit::placeholderText\fP () const" .br .RI "返回placeholder " .ti -1c .RI "void \fBkdk::KSearchLineEdit::setPlaceholderText\fP (const QString &)" .br .RI "设置placeholder " .ti -1c .RI "Qt::Alignment \fBkdk::KSearchLineEdit::placeholderAlignment\fP () const" .br .RI "返回placeholder的对齐方式 " .ti -1c .RI "void \fBkdk::KSearchLineEdit::setPlaceholderAlignment\fP (Qt::Alignment flag)" .br .RI "设置placeholder的对齐方式 " .ti -1c .RI "Qt::Alignment \fBkdk::KSearchLineEdit::alignment\fP () const" .br .RI "设置输入文本的对齐方式 " .ti -1c .RI "void \fBkdk::KSearchLineEdit::setAlignment\fP (Qt::Alignment flag)" .br .RI "设置输入文本的对齐方式返回 " .ti -1c .RI "void \fBkdk::KSearchLineEdit::setTranslucent\fP (bool flag)" .br .RI "设置是否启用半透明效果 " .ti -1c .RI "bool \fBkdk::KSearchLineEdit::isTranslucent\fP ()" .br .RI "获取是否启用半透明效果 " .ti -1c .RI "void \fBkdk::KSearchLineEdit::reloadStyle\fP ()" .br .RI "重新加载style " .ti -1c .RI "\fBKToolButton\fP * \fBkdk::KSearchLineEdit::customButton\fP ()" .br .RI "获取自定义按钮 " .ti -1c .RI "void \fBkdk::KSearchLineEdit::setGradation\fP (bool flag)" .br .RI "是否启用渐变色 " .ti -1c .RI "void \fBkdk::KSearchLineEdit::setCustomButtonVisible\fP (bool flag)" .br .RI "设置智能语义按钮是否可见 " .ti -1c .RI "bool \fBkdk::KSearchLineEdit::isCustomButtonVisible\fP ()" .br .RI "返回智能语义按钮是否可见 " .ti -1c .RI "bool \fBkdk::KSearchLineEdit::eventFilter\fP (QObject *watched, QEvent *event)" .br .ti -1c .RI "void \fBkdk::KSearchLineEdit::resizeEvent\fP (QResizeEvent *event)" .br .ti -1c .RI "void \fBkdk::KSearchLineEdit::setVisible\fP (bool visible)" .br .ti -1c .RI "void \fBkdk::KSearchLineEdit::paintEvent\fP (QPaintEvent *event)" .br .ti -1c .RI "QSize \fBkdk::KSearchLineEdit::sizeHint\fP () const override" .br .in -1c .SS "Public Slots" .in +1c .ti -1c .RI "void \fBkdk::KSearchLineEdit::clear\fP ()" .br .in -1c .SH "Detailed Description" .PP .PP \fBSince\fP .RS 4 2\&.5\&.2\&.0 { .RE .PP .SH "Enumeration Type Documentation" .PP .SS "enum \fBkdk::LoginState\fP" .PP 支持三种状态 .PP \fBSince\fP .RS 4 1\&.0\&.0 .RE .PP .SH "Function Documentation" .PP .SS "Qt::Alignment kdk::KSearchLineEdit::alignment () const" .PP 设置输入文本的对齐方式 .PP \fBReturns\fP .RS 4 .RE .PP .SS "bool kdk::KPasswordEdit::clearBtnVisible ()" .PP 返回ClearBtn是否可见 .PP \fBReturns\fP .RS 4 .RE .PP \fBSince\fP .RS 4 1\&.2\&.0 .RE .PP .SS "\fBKToolButton\fP * kdk::KSearchLineEdit::customButton ()" .PP 获取自定义按钮 .PP \fBReturns\fP .RS 4 .RE .PP \fBSince\fP .RS 4 2\&.4\&.1\&.0 .RE .PP .SS "bool kdk::KPasswordEdit::echoModeBtnVisible ()" .PP 返回EchoModeBtn是否可见 .PP \fBReturns\fP .RS 4 .RE .PP \fBSince\fP .RS 4 1\&.2\&.0 .RE .PP .SS "bool kdk::KPasswordEdit::isClearButtonEnabled () const" .PP 返回是否启用了ClearButton .PP \fBReturns\fP .RS 4 .RE .PP .SS "bool kdk::KSearchLineEdit::isClearButtonEnabled () const" .PP 返回是否显示清除按钮 .PP \fBReturns\fP .RS 4 .RE .PP .SS "bool kdk::KSearchLineEdit::isCustomButtonVisible ()" .PP 返回智能语义按钮是否可见 .PP \fBReturns\fP .RS 4 bool .RE .PP \fBSince\fP .RS 4 2\&.4\&.1\&.0 .RE .PP .SS "bool kdk::KSearchLineEdit::isEnabled ()" .PP 返回是否可用 .PP \fBReturns\fP .RS 4 .RE .PP .SS "bool kdk::KPasswordEdit::isLoading ()" .PP 判断是否处于加载状态 .PP \fBReturns\fP .RS 4 .RE .PP .SS "bool kdk::KSearchLineEdit::isTranslucent ()" .PP 获取是否启用半透明效果 .PP \fBSince\fP .RS 4 1\&.2\&.0 .RE .PP \fBReturns\fP .RS 4 flag .RE .PP .SS "Qt::Alignment kdk::KSearchLineEdit::placeholderAlignment () const" .PP 返回placeholder的对齐方式 .PP \fBReturns\fP .RS 4 .RE .PP .SS "QString kdk::KPasswordEdit::placeholderText ()" .PP 返回placeholderText .PP \fBReturns\fP .RS 4 .RE .PP .SS "QString kdk::KSearchLineEdit::placeholderText () const" .PP 返回placeholder .PP \fBReturns\fP .RS 4 .RE .PP .SS "void kdk::KSearchLineEdit::reloadStyle ()" .PP 重新加载style .PP \fBSince\fP .RS 4 2\&.0\&.2\&.1 .RE .PP .SS "void kdk::KSearchLineEdit::setAlignment (Qt::Alignment flag)" .PP 设置输入文本的对齐方式返回 .PP \fBReturns\fP .RS 4 .RE .PP .SS "void kdk::KPasswordEdit::setClearBtnVisible (bool enable)" .PP 设置ClearBtn是否可见 .PP \fBReturns\fP .RS 4 .RE .PP \fBSince\fP .RS 4 1\&.2\&.0 .RE .PP .SS "void kdk::KPasswordEdit::setClearButtonEnabled (bool enable)" .PP 设置是否启用ClearButton .PP \fBParameters\fP .RS 4 \fIenable\fP .RE .PP .SS "void kdk::KSearchLineEdit::setClearButtonEnabled (bool enable)" .PP 设置是否显示清除按钮 .PP \fBReturns\fP .RS 4 .RE .PP .SS "void kdk::KSearchLineEdit::setCustomButtonVisible (bool flag)" .PP 设置智能语义按钮是否可见 .PP \fBParameters\fP .RS 4 \fIflag\fP .RE .PP \fBSince\fP .RS 4 2\&.4\&.1\&.0 .RE .PP .SS "void kdk::KPasswordEdit::setEchoMode (EchoMode mode)" .PP setEchoMode .PP \fBSince\fP .RS 4 1\&.2\&.0 .RE .PP .SS "void kdk::KPasswordEdit::setEchoModeBtnVisible (bool enable)" .PP 设置EchoModeBtn是否可见 .PP \fBReturns\fP .RS 4 .RE .PP \fBSince\fP .RS 4 1\&.2\&.0 .RE .PP .SS "void kdk::KPasswordEdit::setEnabled (bool)" .PP 设置KLineEdit是否可用 .PP \fBReturns\fP .RS 4 .RE .PP .SS "void kdk::KSearchLineEdit::setGradation (bool flag)" .PP 是否启用渐变色 .PP \fBParameters\fP .RS 4 \fIflag\fP .RE .PP \fBSince\fP .RS 4 2\&.4\&.1\&.0 .RE .PP .SS "void kdk::KPasswordEdit::setLoading (bool flag)" .PP 设置加载状态 .PP \fBParameters\fP .RS 4 \fIflag\fP .RE .PP .SS "void kdk::KSearchLineEdit::setPlaceholderAlignment (Qt::Alignment flag)" .PP 设置placeholder的对齐方式 .PP \fBReturns\fP .RS 4 .RE .PP .SS "void kdk::KSearchLineEdit::setPlaceholderText (const QString &)" .PP 设置placeholder .PP \fBReturns\fP .RS 4 .RE .PP .SS "void kdk::KPasswordEdit::setPlaceholderText (QString & text)" .PP 设置PlaceholderText .PP \fBParameters\fP .RS 4 \fItext\fP .RE .PP .SS "void kdk::KPasswordEdit::setState (\fBLoginState\fP state)" .PP 设置状态 .PP \fBParameters\fP .RS 4 \fIstate\fP .RE .PP .SS "void kdk::KSearchLineEdit::setTranslucent (bool flag)" .PP 设置是否启用半透明效果 .PP \fBSince\fP .RS 4 1\&.2\&.0 .RE .PP \fBParameters\fP .RS 4 \fIflag\fP .RE .PP .SS "void kdk::KPasswordEdit::setUseCustomPalette (bool flag)" .PP 设置是否走默认palette .PP \fBParameters\fP .RS 4 \fIflag\fP .RE .PP \fBSince\fP .RS 4 1\&.2\&.0 .RE .PP .SS "\fBLoginState\fP kdk::KPasswordEdit::state ()" .PP 返回状态 .PP \fBReturns\fP .RS 4 .RE .PP .SH "Author" .PP Generated automatically by Doxygen for LIBKYSDK-APPLICATIONS from the source code\&. libkysdk-applications/doxygen/man/man3/kdk_KTranslucentFloor.30000664000175000017500000000461715104543305023432 0ustar fengfeng.TH "kdk::KTranslucentFloor" 3 "Version version:3.0" "LIBKYSDK-APPLICATIONS" \" -*- nroff -*- .ad l .nh .SH NAME kdk::KTranslucentFloor \- 提供一个半透明底板,可作为基础窗体进行布局 .SH SYNOPSIS .br .PP .PP \fC#include \fP .PP Inherits QFrame\&. .SS "Public Member Functions" .in +1c .ti -1c .RI "\fBKTranslucentFloor\fP (QWidget *parent=nullptr)" .br .ti -1c .RI "void \fBsetBorderRadius\fP (int radius)" .br .RI "设置圆角半径 " .ti -1c .RI "int \fBborderRadius\fP ()" .br .RI "返回圆角半径 " .ti -1c .RI "void \fBsetShadow\fP (bool flag)" .br .RI "设置是否显示阴影 " .ti -1c .RI "bool \fBshadow\fP ()" .br .RI "返回是否显示阴影 " .ti -1c .RI "void \fBsetEnableBlur\fP (bool flag)" .br .RI "设置是否启用毛玻璃效果 " .ti -1c .RI "bool \fBenableBlur\fP ()" .br .RI "获取是否已启用毛玻璃效果 " .ti -1c .RI "void \fBsetOpacity\fP (qreal \fBopacity\fP)" .br .RI "设置透明度 " .ti -1c .RI "qreal \fBopacity\fP ()" .br .RI "获取透明度 " .in -1c .SS "Protected Member Functions" .in +1c .ti -1c .RI "void \fBpaintEvent\fP (QPaintEvent *)" .br .in -1c .SH "Detailed Description" .PP 提供一个半透明底板,可作为基础窗体进行布局 .PP \fBSince\fP .RS 4 1\&.2\&.0 .RE .PP .SH "Member Function Documentation" .PP .SS "int kdk::KTranslucentFloor::borderRadius ()" .PP 返回圆角半径 .PP \fBReturns\fP .RS 4 .RE .PP .SS "bool kdk::KTranslucentFloor::enableBlur ()" .PP 获取是否已启用毛玻璃效果 .PP \fBReturns\fP .RS 4 .RE .PP .SS "qreal kdk::KTranslucentFloor::opacity ()" .PP 获取透明度 .PP \fBReturns\fP .RS 4 .RE .PP .SS "void kdk::KTranslucentFloor::setBorderRadius (int radius)" .PP 设置圆角半径 .PP \fBParameters\fP .RS 4 \fIradius\fP .RE .PP .SS "void kdk::KTranslucentFloor::setEnableBlur (bool flag)" .PP 设置是否启用毛玻璃效果 .PP \fBParameters\fP .RS 4 \fIflag\fP .RE .PP .SS "void kdk::KTranslucentFloor::setOpacity (qreal opacity)" .PP 设置透明度 .PP \fBParameters\fP .RS 4 \fIopacity\fP .RE .PP .SS "void kdk::KTranslucentFloor::setShadow (bool flag)" .PP 设置是否显示阴影 .PP \fBParameters\fP .RS 4 \fIflag\fP .RE .PP .SS "bool kdk::KTranslucentFloor::shadow ()" .PP 返回是否显示阴影 .PP \fBReturns\fP .RS 4 .RE .PP .SH "Author" .PP Generated automatically by Doxygen for LIBKYSDK-APPLICATIONS from the source code\&. libkysdk-applications/doxygen/man/man3/kdk_KLabel.30000664000175000017500000001423715104543305021144 0ustar fengfeng.TH "kdk::KLabel" 3 "Version version:3.0" "LIBKYSDK-APPLICATIONS" \" -*- nroff -*- .ad l .nh .SH NAME kdk::KLabel \- 继承qlabel .SH SYNOPSIS .br .PP .PP \fC#include \fP .PP Inherits QLabel\&. .SS "Signals" .in +1c .ti -1c .RI "void \fBenterWidget\fP ()" .br .RI "鼠标进入信号 " .ti -1c .RI "void \fBleaveWidget\fP ()" .br .RI "鼠标离开信号 " .ti -1c .RI "void \fBclicked\fP (bool clicked)" .br .RI "鼠标点击信号 " .ti -1c .RI "void \fBdoubleClicked\fP ()" .br .RI "鼠标双击信号 " .in -1c .SS "Public Member Functions" .in +1c .ti -1c .RI "\fBKLabel\fP (QWidget *parent=nullptr)" .br .ti -1c .RI "void \fBsetLabelType\fP (KLabelType type=KLabelType::DataType)" .br .RI "设置label类型,NormalType和IconAndTextType " .ti -1c .RI "void \fBsetDataHightColor\fP (bool flag)" .br .RI "设置是否启用文本/图标高亮色 " .ti -1c .RI "void \fBsetPixmap\fP (const QPixmap &\fBpixmap\fP)" .br .RI "设置图标pixmap " .ti -1c .RI "void \fBsetPixmap\fP (QIcon icon, int width, int height)" .br .RI "设置图标icon " .ti -1c .RI "const QPixmap * \fBpixmap\fP () const" .br .RI "获取图标 " .ti -1c .RI "void \fBsetText\fP (const QString &str)" .br .RI "设置文本 " .ti -1c .RI "QString \fBtext\fP ()" .br .RI "获取文本 " .ti -1c .RI "void \fBsetBackgroundColor\fP (bool flag, QColor color=Qt::white)" .br .RI "设置背景颜色 " .ti -1c .RI "void \fBsetHighlightBackground\fP (bool flag)" .br .RI "设置是否启用背景高亮色 " .ti -1c .RI "void \fBsetBorderRadius\fP (int bottomLeft, int topLeft, int topRight, int bottomRight)" .br .RI "设置圆角 " .ti -1c .RI "void \fBsetBorderRadius\fP (int radius)" .br .RI "设置圆角 " .ti -1c .RI "void \fBsetWordWrap\fP (bool flag)" .br .RI "设置是否启用换行 " .ti -1c .RI "bool \fBwordWrap\fP ()" .br .RI "获取是否启用换行 " .ti -1c .RI "void \fBsetFontColor\fP (QColor color)" .br .RI "设置字体颜色 " .ti -1c .RI "void \fBsetFontColorRole\fP (QPalette::ColorRole role)" .br .RI "设置字体颜色colorRole " .ti -1c .RI "void \fBsetTristate\fP (bool flag)" .br .RI "设置三态是否开启 " .ti -1c .RI "bool \fBisTristate\fP ()" .br .RI "获取三态是否开启 " .in -1c .SS "Protected Member Functions" .in +1c .ti -1c .RI "void \fBpaintEvent\fP (QPaintEvent *event)" .br .ti -1c .RI "QSize \fBsizeHint\fP () const" .br .ti -1c .RI "void \fBresizeEvent\fP (QResizeEvent *event)" .br .ti -1c .RI "virtual void \fBenterEvent\fP (QEvent *event)" .br .ti -1c .RI "virtual void \fBleaveEvent\fP (QEvent *event)" .br .ti -1c .RI "void \fBmousePressEvent\fP (QMouseEvent *event)" .br .ti -1c .RI "void \fBmouseReleaseEvent\fP (QMouseEvent *event)" .br .ti -1c .RI "void \fBmouseDoubleClickEvent\fP (QMouseEvent *event)" .br .in -1c .SH "Detailed Description" .PP 继承qlabel .PP \fBSince\fP .RS 4 2\&.4\&.1\&.0 .RE .PP .SH "Member Function Documentation" .PP .SS "void kdk::KLabel::clicked (bool clicked)\fC [signal]\fP" .PP 鼠标点击信号 .PP \fBParameters\fP .RS 4 \fIclicked\fP .RE .PP \fBSince\fP .RS 4 3\&.0\&.1\&.0 .RE .PP .SS "void kdk::KLabel::doubleClicked ()\fC [signal]\fP" .PP 鼠标双击信号 .PP \fBSince\fP .RS 4 3\&.0\&.1\&.0 .RE .PP .SS "void kdk::KLabel::enterWidget ()\fC [signal]\fP" .PP 鼠标进入信号 .PP \fBSince\fP .RS 4 3\&.0\&.1\&.0 .RE .PP .SS "bool kdk::KLabel::isTristate ()" .PP 获取三态是否开启 .PP \fBReturns\fP .RS 4 .RE .PP \fBSince\fP .RS 4 3\&.0\&.1\&.0 .RE .PP .SS "void kdk::KLabel::leaveWidget ()\fC [signal]\fP" .PP 鼠标离开信号 .PP \fBSince\fP .RS 4 3\&.0\&.1\&.0 .RE .PP .SS "const QPixmap * kdk::KLabel::pixmap () const" .PP 获取图标 .PP \fBReturns\fP .RS 4 .RE .PP .SS "void kdk::KLabel::setBackgroundColor (bool flag, QColor color = \fCQt::white\fP)" .PP 设置背景颜色 .PP \fBParameters\fP .RS 4 \fIflag\fP .RE .PP .SS "void kdk::KLabel::setBorderRadius (int bottomLeft, int topLeft, int topRight, int bottomRight)" .PP 设置圆角 .PP \fBParameters\fP .RS 4 \fIbottomLeft\fP .br \fItopLeft\fP .br \fItopRight\fP .br \fIbottomRight\fP .RE .PP .SS "void kdk::KLabel::setBorderRadius (int radius)" .PP 设置圆角 .PP \fBParameters\fP .RS 4 \fIradius\fP .RE .PP .SS "void kdk::KLabel::setDataHightColor (bool flag)" .PP 设置是否启用文本/图标高亮色 .PP \fBParameters\fP .RS 4 \fIflag\fP .RE .PP .SS "void kdk::KLabel::setFontColor (QColor color)" .PP 设置字体颜色 .PP \fBParameters\fP .RS 4 \fIcolor\fP .RE .PP \fBSince\fP .RS 4 2\&.5\&.2\&.0 .RE .PP .SS "void kdk::KLabel::setFontColorRole (QPalette::ColorRole role)" .PP 设置字体颜色colorRole .PP \fBParameters\fP .RS 4 \fIrole\fP .RE .PP \fBSince\fP .RS 4 3\&.0\&.1\&.0 .RE .PP .SS "void kdk::KLabel::setHighlightBackground (bool flag)" .PP 设置是否启用背景高亮色 .PP \fBSince\fP .RS 4 2\&.5\&.2\&.0 .RE .PP \fBParameters\fP .RS 4 \fIflag\fP .RE .PP .SS "void kdk::KLabel::setLabelType (KLabelType type = \fCKLabelType::DataType\fP)" .PP 设置label类型,NormalType和IconAndTextType .PP \fBParameters\fP .RS 4 \fItype\fP .RE .PP .SS "void kdk::KLabel::setPixmap (const QPixmap & pixmap)" .PP 设置图标pixmap .PP \fBParameters\fP .RS 4 \fIpixmap\fP .RE .PP .SS "void kdk::KLabel::setPixmap (QIcon icon, int width, int height)" .PP 设置图标icon .PP \fBParameters\fP .RS 4 \fIicon\fP .RE .PP \fBSince\fP .RS 4 2\&.5\&.2\&.0-0k0\&.3 .RE .PP .SS "void kdk::KLabel::setText (const QString & str)" .PP 设置文本 .PP \fBSince\fP .RS 4 2\&.5\&.2\&.0 .RE .PP \fBParameters\fP .RS 4 \fIstr\fP .RE .PP .SS "void kdk::KLabel::setTristate (bool flag)" .PP 设置三态是否开启 .PP \fBParameters\fP .RS 4 \fIflag\fP .RE .PP \fBSince\fP .RS 4 3\&.0\&.1\&.0 .RE .PP .SS "void kdk::KLabel::setWordWrap (bool flag)" .PP 设置是否启用换行 .PP \fBSince\fP .RS 4 2\&.5\&.2\&.0 .RE .PP \fBParameters\fP .RS 4 \fIflag\fP .RE .PP .SS "QString kdk::KLabel::text ()" .PP 获取文本 .PP \fBSince\fP .RS 4 2\&.5\&.2\&.0 .RE .PP \fBReturns\fP .RS 4 .RE .PP .SS "bool kdk::KLabel::wordWrap ()" .PP 获取是否启用换行 .PP \fBSince\fP .RS 4 2\&.5\&.2\&.0 .RE .PP \fBReturns\fP .RS 4 .RE .PP .SH "Author" .PP Generated automatically by Doxygen for LIBKYSDK-APPLICATIONS from the source code\&. libkysdk-applications/doxygen/man/man3/kdk_KSwitchButtonFrame.30000664000175000017500000000602215104543305023526 0ustar fengfeng.TH "kdk::KSwitchButtonFrame" 3 "Version version:3.0" "LIBKYSDK-APPLICATIONS" \" -*- nroff -*- .ad l .nh .SH NAME kdk::KSwitchButtonFrame .SH SYNOPSIS .br .PP .PP Inherits \fBkdk::KBaseFrame\fP\&. .SS "Public Member Functions" .in +1c .ti -1c .RI "\fBKSwitchButtonFrame\fP (const QString title, QWidget *parent=nullptr, \fBBorderRadiusStyle\fP style=\fBBorderRadiusStyle::None\fP)" .br .RI "创建一个带 \fBKSwitchButton\fP 的 Frame " .ti -1c .RI "void \fBsetHintText\fP (QString &hintText)" .br .RI "设置提示文案 " .ti -1c .RI "\fBKSwitchButton\fP * \fBswitchButton\fP ()" .br .RI "获取 switchbutton " .ti -1c .RI "\fBKLabel\fP * \fBtitleLabel\fP ()" .br .RI "获取label " .ti -1c .RI "QHBoxLayout * \fBmainHLayout\fP ()" .br .RI "获取layout " .in -1c Public Member Functions inherited from \fBkdk::KBaseFrame\fP .in +1c .ti -1c .RI "\fBKBaseFrame\fP (QWidget *parent=nullptr, \fBBorderRadiusStyle\fP style=\fBAround\fP, bool heightAdaptive=false)" .br .RI "构造函数 " .ti -1c .RI "void \fBsetRadiusType\fP (\fBBorderRadiusStyle\fP style)" .br .RI "设置圆角风格 " .ti -1c .RI "bool \fBgetTabletMode\fP ()" .br .RI "获取平板模式 " .ti -1c .RI "bool \fBisContainer\fP ()" .br .RI "获取是否是一个容器frame,此时settinggroup需要设置的是其子frame的圆角 " .ti -1c .RI "void \fBsetContainer\fP (bool b=false)" .br .RI "设置该frame是否是一个容器frame,如果是同时setFrameShape(NoFrame); " .in -1c .SS "Additional Inherited Members" Public Types inherited from \fBkdk::KBaseFrame\fP .in +1c .ti -1c .RI "enum \fBBorderRadiusStyle\fP { \fBTop\fP, \fBNone\fP, \fBBottom\fP, \fBAround\fP }" .br .in -1c Signals inherited from \fBkdk::KBaseFrame\fP .in +1c .ti -1c .RI "void \fBtabletModeChanged\fP (bool b)" .br .in -1c Protected Member Functions inherited from \fBkdk::KBaseFrame\fP .in +1c .ti -1c .RI "void \fBpaintEvent\fP (QPaintEvent *e)" .br .in -1c .SH "Constructor & Destructor Documentation" .PP .SS "kdk::KSwitchButtonFrame::KSwitchButtonFrame (const QString title, QWidget * parent = \fCnullptr\fP, \fBBorderRadiusStyle\fP style = \fC\fBBorderRadiusStyle::None\fP\fP)\fC [explicit]\fP" .PP 创建一个带 \fBKSwitchButton\fP 的 Frame .PP \fBParameters\fP .RS 4 \fItitle\fP text of m_settingName .br \fIstyle\fP 设置圆角(None:无圆角,Top:上圆角,Bottom:下圆角,Around:四圆角) .br \fIparent\fP .RE .PP .SH "Member Function Documentation" .PP .SS "QHBoxLayout * kdk::KSwitchButtonFrame::mainHLayout ()" .PP 获取layout .PP \fBReturns\fP .RS 4 QHBoxLayout .RE .PP .SS "void kdk::KSwitchButtonFrame::setHintText (QString & hintText)" .PP 设置提示文案 .PP \fBParameters\fP .RS 4 \fIhintText\fP .RE .PP .SS "\fBKSwitchButton\fP * kdk::KSwitchButtonFrame::switchButton ()" .PP 获取 switchbutton .PP \fBReturns\fP .RS 4 \fBKSlider\fP: m_slider .RE .PP .SS "\fBKLabel\fP * kdk::KSwitchButtonFrame::titleLabel ()" .PP 获取label .PP \fBReturns\fP .RS 4 QLabel .RE .PP .SH "Author" .PP Generated automatically by Doxygen for LIBKYSDK-APPLICATIONS from the source code\&. libkysdk-applications/doxygen/man/man3/kdk_KDialog.30000664000175000017500000000402115104543305021312 0ustar fengfeng.TH "kdk::KDialog" 3 "Version version:3.0" "LIBKYSDK-APPLICATIONS" \" -*- nroff -*- .ad l .nh .SH NAME kdk::KDialog \- 继承自 QDialog,支持响应式主题背景切换和图标主题切换、 标题颜色响应窗口激活状态 .SH SYNOPSIS .br .PP .PP \fC#include \fP .PP Inherits QDialog, and ThemeController\&. .PP Inherited by \fBkdk::KAboutDialog\fP, \fBkdk::KInputDialog\fP, \fBkdk::KMessageBox\fP, \fBkdk::KProgressDialog\fP, \fBkdk::KSecurityQuestionDialog\fP, and \fBkdk::KUninstallDialog\fP\&. .SS "Public Member Functions" .in +1c .ti -1c .RI "\fBKDialog\fP (QWidget *parent=nullptr)" .br .ti -1c .RI "void \fBsetWindowIcon\fP (const QIcon &icon)" .br .RI "设置对话框图标 " .ti -1c .RI "void \fBsetWindowIcon\fP (const QString &iconName)" .br .RI "设置对话框图标 " .ti -1c .RI "void \fBsetWindowTitle\fP (const QString &)" .br .RI "设置对话框标题名称 " .ti -1c .RI "QPushButton * \fBmaximumButton\fP ()" .br .RI "获取最大化按钮 " .ti -1c .RI "QPushButton * \fBminimumButton\fP ()" .br .RI "获取最小化按钮 " .ti -1c .RI "QPushButton * \fBcloseButton\fP ()" .br .RI "获取关闭按钮 " .ti -1c .RI "\fBKMenuButton\fP * \fBmenuButton\fP ()" .br .RI "获取下拉菜单按钮 " .ti -1c .RI "QWidget * \fBmainWidget\fP ()" .br .RI "获取主内容区Widget " .ti -1c .RI "\fBKWindowButtonBar\fP * \fBwindowButtonBar\fP ()" .br .RI "windowButtonBar " .ti -1c .RI "\fBKIconBar\fP * \fBiconBar\fP ()" .br .RI "iconBar " .in -1c .SS "Protected Member Functions" .in +1c .ti -1c .RI "bool \fBeventFilter\fP (QObject *target, QEvent *event) override" .br .ti -1c .RI "void \fBchangeTheme\fP ()" .br .ti -1c .RI "void \fBchangeIconStyle\fP ()" .br .ti -1c .RI "QBoxLayout * \fBmainLayout\fP ()" .br .in -1c .SH "Detailed Description" .PP 继承自 QDialog,支持响应式主题背景切换和图标主题切换、 标题颜色响应窗口激活状态 .PP \fBSince\fP .RS 4 1\&.0\&.0 .RE .PP .SH "Author" .PP Generated automatically by Doxygen for LIBKYSDK-APPLICATIONS from the source code\&. libkysdk-applications/doxygen/man/man3/kdk_KMessageBox.30000664000175000017500000003621415104543305022161 0ustar fengfeng.TH "kdk::KMessageBox" 3 "Version version:3.0" "LIBKYSDK-APPLICATIONS" \" -*- nroff -*- .ad l .nh .SH NAME kdk::KMessageBox \- 继承自KDialog,提供一个可自定义设置按钮和图标的对话框,类似QMessageBox .SH SYNOPSIS .br .PP .PP \fC#include \fP .PP Inherits \fBkdk::KDialog\fP\&. .SS "Public Types" .in +1c .ti -1c .RI "enum \fBIcon\fP { \fBNoIcon\fP = 0, \fBInformation\fP = 1, \fBWarning\fP = 2, \fBCritical\fP = 3, \fBQuestion\fP = 4 }" .br .RI "The Icon enum,icon的五种类型,与 QMessageDialogOptions::Icon 保持同步 " .ti -1c .RI "enum \fBButtonRole\fP { \fBInvalidRole\fP = -1, \fBAcceptRole\fP, \fBRejectRole\fP, \fBDestructiveRole\fP, \fBActionRole\fP, \fBHelpRole\fP, \fBYesRole\fP, \fBNoRole\fP, \fBResetRole\fP, \fBApplyRole\fP, \fBNRoles\fP }" .br .RI "The ButtonRole enum,可供设置的按钮role\&. " .ti -1c .RI "enum \fBStandardButton\fP { \fBNoButton\fP = 0x00000000, \fBOk\fP = 0x00000400, \fBSave\fP = 0x00000800, \fBSaveAll\fP = 0x00001000, \fBOpen\fP = 0x00002000, \fBYes\fP = 0x00004000, \fBYesToAll\fP = 0x00008000, \fBNo\fP = 0x00010000, \fBNoToAll\fP = 0x00020000, \fBAbort\fP = 0x00040000, \fBRetry\fP = 0x00080000, \fBIgnore\fP = 0x00100000, \fBClose\fP = 0x00200000, \fBCancel\fP = 0x00400000, \fBDiscard\fP = 0x00800000, \fBHelp\fP = 0x01000000, \fBApply\fP = 0x02000000, \fBReset\fP = 0x04000000, \fBRestoreDefaults\fP = 0x08000000, \fBFirstButton\fP = Ok, \fBLastButton\fP = RestoreDefaults, \fBYesAll\fP = YesToAll, \fBNoAll\fP = NoToAll, \fBDefault\fP = 0x00000100, \fBEscape\fP = 0x00000200, \fBFlagMask\fP = 0x00000300, \fBButtonMask\fP = ~FlagMask }" .br .RI "The StandardButton enum,可供添加的按钮类型,与 QDialogButtonBox::StandardButton 和 QPlatformDialogHelper::StandardButton 保持同步 " .ti -1c .RI "typedef \fBStandardButton\fP \fBButton\fP" .br .in -1c .SS "Signals" .in +1c .ti -1c .RI "void \fBbuttonClicked\fP (QAbstractButton *\fBbutton\fP)" .br .in -1c .SS "Public Member Functions" .in +1c .ti -1c .RI "\fBKMessageBox\fP (QWidget *parent=nullptr)" .br .ti -1c .RI "void \fBsetCustomIcon\fP (const QIcon &\fBicon\fP)" .br .RI "自定义KMessageBox的提示图标 " .ti -1c .RI "void \fBaddButton\fP (QAbstractButton *\fBbutton\fP, \fBButtonRole\fP role)" .br .RI "添加一个自定义按钮 " .ti -1c .RI "QPushButton * \fBaddButton\fP (const QString &\fBtext\fP, \fBButtonRole\fP role)" .br .RI "添加设置好文本的按钮 " .ti -1c .RI "QPushButton * \fBaddButton\fP (\fBStandardButton\fP \fBbutton\fP)" .br .RI "添加一个标准按钮并且返回这个按钮 " .ti -1c .RI "void \fBremoveButton\fP (QAbstractButton *\fBbutton\fP)" .br .RI "移除一个按钮 " .ti -1c .RI "QAbstractButton * \fBbutton\fP (\fBStandardButton\fP which) const" .br .RI "返回与标准按钮对应的指针,如果此消息框中不存在标准按钮,则返回0。 " .ti -1c .RI "QList< QAbstractButton * > \fBbuttons\fP () const" .br .RI "返回已添加到消息框中的所有按钮的列表 " .ti -1c .RI "\fBKMessageBox::ButtonRole\fP \fBbuttonRole\fP (QAbstractButton *\fBbutton\fP) const" .br .RI "返回指定按钮的按钮角色,如果按钮为0或尚未添加到消息框中,此函数将返回InvalidRole " .ti -1c .RI "QCheckBox * \fBcheckBox\fP () const" .br .RI "返回KMessageBox中显示的复选框 " .ti -1c .RI "void \fBsetCheckBox\fP (QCheckBox *cb)" .br .RI "设置KMessageBox显示的复选框,未设置则为0 " .ti -1c .RI "QString \fBtext\fP () const" .br .RI "获取KMessageBox的文本 " .ti -1c .RI "void \fBsetText\fP (const QString &\fBtext\fP)" .br .RI "设置KMessageBox的文本 " .ti -1c .RI "QString \fBinformativeText\fP () const" .br .RI "获取KMessageBox信息性文本的描述 " .ti -1c .RI "void \fBsetInformativeText\fP (const QString &\fBtext\fP)" .br .RI "设置KMessageBox信息性文本的描述 " .ti -1c .RI "\fBIcon\fP \fBicon\fP () const" .br .RI "获取KMessageBox的图标 " .ti -1c .RI "void \fBsetIcon\fP (\fBIcon\fP \fBicon\fP)" .br .RI "设置KMessageBox的图标 " .ti -1c .RI "QPixmap \fBiconPixmap\fP () const" .br .RI "返回当前KMessageBox的icon " .ti -1c .RI "void \fBsetIconPixmap\fP (const QPixmap &pixmap)" .br .RI "设置当前KMessageBox的icon " .ti -1c .RI "KMessageBox::StandardButtons \fBstandardButtons\fP () const" .br .RI "KMessageBox中标准按钮的集合 " .ti -1c .RI "void \fBsetStandardButtons\fP (KMessageBox::StandardButtons \fBbuttons\fP)" .br .RI "设置多个标准按钮 " .ti -1c .RI "\fBKMessageBox::StandardButton\fP \fBstandardButton\fP (QAbstractButton *\fBbutton\fP) const" .br .RI "返回与给定按钮对应的标准按钮枚举值,如果给定按钮不是标准按钮,则返回NoButton " .ti -1c .RI "QPushButton * \fBdefaultButton\fP () const" .br .RI "返回KMessageBox的默认按钮 " .ti -1c .RI "void \fBsetDefaultButton\fP (QPushButton *\fBbutton\fP)" .br .RI "设置KMessageBox的默认按钮 " .ti -1c .RI "void \fBsetDefaultButton\fP (\fBKMessageBox::StandardButton\fP \fBbutton\fP)" .br .RI "设置KMessageBox的默认按钮 " .ti -1c .RI "QAbstractButton * \fBclickedButton\fP () const" .br .RI "返回被点击的按钮 " .ti -1c .RI "QLabel * \fBinformativeLabel\fP ()" .br .RI "返回informativeLabel " .in -1c Public Member Functions inherited from \fBkdk::KDialog\fP .in +1c .ti -1c .RI "\fBKDialog\fP (QWidget *parent=nullptr)" .br .ti -1c .RI "void \fBsetWindowIcon\fP (const QIcon &icon)" .br .RI "设置对话框图标 " .ti -1c .RI "void \fBsetWindowIcon\fP (const QString &iconName)" .br .RI "设置对话框图标 " .ti -1c .RI "void \fBsetWindowTitle\fP (const QString &)" .br .RI "设置对话框标题名称 " .ti -1c .RI "QPushButton * \fBmaximumButton\fP ()" .br .RI "获取最大化按钮 " .ti -1c .RI "QPushButton * \fBminimumButton\fP ()" .br .RI "获取最小化按钮 " .ti -1c .RI "QPushButton * \fBcloseButton\fP ()" .br .RI "获取关闭按钮 " .ti -1c .RI "\fBKMenuButton\fP * \fBmenuButton\fP ()" .br .RI "获取下拉菜单按钮 " .ti -1c .RI "QWidget * \fBmainWidget\fP ()" .br .RI "获取主内容区Widget " .ti -1c .RI "\fBKWindowButtonBar\fP * \fBwindowButtonBar\fP ()" .br .RI "windowButtonBar " .ti -1c .RI "\fBKIconBar\fP * \fBiconBar\fP ()" .br .RI "iconBar " .in -1c .SS "Static Public Member Functions" .in +1c .ti -1c .RI "static QPixmap \fBstandardIcon\fP (\fBIcon\fP \fBicon\fP)" .br .RI "返回用于标准图标的pixmap。 " .ti -1c .RI "static \fBStandardButton\fP \fBinformation\fP (QWidget *parent, const QString &title, const QString &\fBtext\fP, StandardButtons \fBbuttons\fP=Ok, \fBStandardButton\fP \fBdefaultButton\fP=NoButton)" .br .RI "打开带有给定标题和文本的信息消息框。对话框最多可以有三个按钮 " .ti -1c .RI "static \fBStandardButton\fP \fBquestion\fP (QWidget *parent, const QString &title, const QString &\fBtext\fP, StandardButtons \fBbuttons\fP=StandardButtons(Yes|No), \fBStandardButton\fP \fBdefaultButton\fP=NoButton)" .br .RI "打开一个带有给定标题和文本的问题消息框 " .ti -1c .RI "static \fBStandardButton\fP \fBwarning\fP (QWidget *parent, const QString &title, const QString &\fBtext\fP, StandardButtons \fBbuttons\fP=Ok, \fBStandardButton\fP \fBdefaultButton\fP=NoButton)" .br .RI "打开一个带有给定标题和文本的警告消息框 " .ti -1c .RI "static \fBStandardButton\fP \fBcritical\fP (QWidget *parent, const QString &title, const QString &\fBtext\fP, StandardButtons \fBbuttons\fP=Ok, \fBStandardButton\fP \fBdefaultButton\fP=NoButton)" .br .RI "用给定的标题和文本打开一个关键信息框 " .ti -1c .RI "static \fBStandardButton\fP \fBsuccess\fP (QWidget *parent, const QString &title, const QString &\fBtext\fP, StandardButtons \fBbuttons\fP=Ok, \fBStandardButton\fP \fBdefaultButton\fP=NoButton)" .br .RI "用给定的标题和文本打开一个成功消息框 " .in -1c .SS "Protected Member Functions" .in +1c .ti -1c .RI "bool \fBevent\fP (QEvent *e) override" .br .in -1c Protected Member Functions inherited from \fBkdk::KDialog\fP .in +1c .ti -1c .RI "bool \fBeventFilter\fP (QObject *target, QEvent *event) override" .br .ti -1c .RI "void \fBchangeTheme\fP ()" .br .ti -1c .RI "void \fBchangeIconStyle\fP ()" .br .ti -1c .RI "QBoxLayout * \fBmainLayout\fP ()" .br .in -1c .SH "Detailed Description" .PP 继承自KDialog,提供一个可自定义设置按钮和图标的对话框,类似QMessageBox .PP \fBSince\fP .RS 4 2\&.0\&.2\&.1 .RE .PP .SH "Member Function Documentation" .PP .SS "QPushButton * kdk::KMessageBox::addButton (const QString & text, \fBButtonRole\fP role)" .PP 添加设置好文本的按钮 .PP \fBParameters\fP .RS 4 \fItext\fP .br \fIrole\fP .RE .PP \fBReturns\fP .RS 4 .RE .PP .SS "void kdk::KMessageBox::addButton (QAbstractButton * button, \fBButtonRole\fP role)" .PP 添加一个自定义按钮 .PP \fBParameters\fP .RS 4 \fIbutton\fP .br \fIrole\fP .RE .PP .SS "QPushButton * kdk::KMessageBox::addButton (\fBStandardButton\fP button)" .PP 添加一个标准按钮并且返回这个按钮 .PP \fBParameters\fP .RS 4 \fIbutton\fP .RE .PP \fBReturns\fP .RS 4 .RE .PP .SS "QAbstractButton * kdk::KMessageBox::button (\fBStandardButton\fP which) const" .PP 返回与标准按钮对应的指针,如果此消息框中不存在标准按钮,则返回0。 .PP \fBParameters\fP .RS 4 \fIwhich\fP .RE .PP \fBReturns\fP .RS 4 .RE .PP .SS "\fBKMessageBox::ButtonRole\fP kdk::KMessageBox::buttonRole (QAbstractButton * button) const" .PP 返回指定按钮的按钮角色,如果按钮为0或尚未添加到消息框中,此函数将返回InvalidRole .PP \fBParameters\fP .RS 4 \fIbutton\fP .RE .PP \fBReturns\fP .RS 4 .RE .PP .SS "QList< QAbstractButton * > kdk::KMessageBox::buttons () const" .PP 返回已添加到消息框中的所有按钮的列表 .PP \fBReturns\fP .RS 4 .RE .PP .SS "QCheckBox * kdk::KMessageBox::checkBox () const" .PP 返回KMessageBox中显示的复选框 .PP \fBReturns\fP .RS 4 .RE .PP .SS "QAbstractButton * kdk::KMessageBox::clickedButton () const" .PP 返回被点击的按钮 .PP \fBReturns\fP .RS 4 .RE .PP .SS "static \fBStandardButton\fP kdk::KMessageBox::critical (QWidget * parent, const QString & title, const QString & text, StandardButtons buttons = \fCOk\fP, \fBStandardButton\fP defaultButton = \fCNoButton\fP)\fC [static]\fP" .PP 用给定的标题和文本打开一个关键信息框 .PP \fBParameters\fP .RS 4 \fIparent\fP .br \fItitle\fP .br \fItext\fP .br \fIbuttons\fP .br \fIdefaultButton\fP .RE .PP \fBReturns\fP .RS 4 .RE .PP .SS "QPushButton * kdk::KMessageBox::defaultButton () const" .PP 返回KMessageBox的默认按钮 .PP \fBReturns\fP .RS 4 .RE .PP .SS "\fBIcon\fP kdk::KMessageBox::icon () const" .PP 获取KMessageBox的图标 .PP \fBReturns\fP .RS 4 .RE .PP .SS "QPixmap kdk::KMessageBox::iconPixmap () const" .PP 返回当前KMessageBox的icon .PP \fBReturns\fP .RS 4 .RE .PP .SS "static \fBStandardButton\fP kdk::KMessageBox::information (QWidget * parent, const QString & title, const QString & text, StandardButtons buttons = \fCOk\fP, \fBStandardButton\fP defaultButton = \fCNoButton\fP)\fC [static]\fP" .PP 打开带有给定标题和文本的信息消息框。对话框最多可以有三个按钮 .PP \fBParameters\fP .RS 4 \fIparent\fP .br \fItitle\fP .br \fItext\fP .br \fIbuttons\fP .br \fIdefaultButton\fP .RE .PP \fBReturns\fP .RS 4 .RE .PP .SS "QLabel * kdk::KMessageBox::informativeLabel ()" .PP 返回informativeLabel .PP \fBReturns\fP .RS 4 .RE .PP \fBSince\fP .RS 4 3\&.0\&.1\&.0 .RE .PP .SS "QString kdk::KMessageBox::informativeText () const" .PP 获取KMessageBox信息性文本的描述 .PP \fBReturns\fP .RS 4 .RE .PP .SS "static \fBStandardButton\fP kdk::KMessageBox::question (QWidget * parent, const QString & title, const QString & text, StandardButtons buttons = \fCStandardButtons(Yes|No)\fP, \fBStandardButton\fP defaultButton = \fCNoButton\fP)\fC [static]\fP" .PP 打开一个带有给定标题和文本的问题消息框 .PP \fBParameters\fP .RS 4 \fIparent\fP .br \fItitle\fP .br \fItext\fP .br \fIbuttons\fP .br \fIdefaultButton\fP .RE .PP \fBReturns\fP .RS 4 .RE .PP .SS "void kdk::KMessageBox::removeButton (QAbstractButton * button)" .PP 移除一个按钮 .PP \fBParameters\fP .RS 4 \fIbutton\fP .RE .PP .SS "void kdk::KMessageBox::setCheckBox (QCheckBox * cb)" .PP 设置KMessageBox显示的复选框,未设置则为0 .PP \fBParameters\fP .RS 4 \fIcb\fP .RE .PP .SS "void kdk::KMessageBox::setCustomIcon (const QIcon & icon)" .PP 自定义KMessageBox的提示图标 .PP \fBParameters\fP .RS 4 \fIicon\fP .RE .PP .SS "void kdk::KMessageBox::setDefaultButton (\fBKMessageBox::StandardButton\fP button)" .PP 设置KMessageBox的默认按钮 .PP \fBParameters\fP .RS 4 \fIbutton\fP .RE .PP .SS "void kdk::KMessageBox::setDefaultButton (QPushButton * button)" .PP 设置KMessageBox的默认按钮 .PP \fBParameters\fP .RS 4 \fIbutton\fP .RE .PP .SS "void kdk::KMessageBox::setIcon (\fBIcon\fP icon)" .PP 设置KMessageBox的图标 .PP \fBParameters\fP .RS 4 \fIicon\fP .RE .PP .SS "void kdk::KMessageBox::setIconPixmap (const QPixmap & pixmap)" .PP 设置当前KMessageBox的icon .PP \fBParameters\fP .RS 4 \fIpixmap\fP .RE .PP .SS "void kdk::KMessageBox::setInformativeText (const QString & text)" .PP 设置KMessageBox信息性文本的描述 .PP \fBParameters\fP .RS 4 \fItext\fP .RE .PP .SS "void kdk::KMessageBox::setStandardButtons (KMessageBox::StandardButtons buttons)" .PP 设置多个标准按钮 .PP \fBParameters\fP .RS 4 \fIbuttons\fP .RE .PP .SS "void kdk::KMessageBox::setText (const QString & text)" .PP 设置KMessageBox的文本 .PP \fBParameters\fP .RS 4 \fItext\fP .RE .PP .SS "\fBKMessageBox::StandardButton\fP kdk::KMessageBox::standardButton (QAbstractButton * button) const" .PP 返回与给定按钮对应的标准按钮枚举值,如果给定按钮不是标准按钮,则返回NoButton .PP \fBParameters\fP .RS 4 \fIbutton\fP .RE .PP \fBReturns\fP .RS 4 .RE .PP .SS "KMessageBox::StandardButtons kdk::KMessageBox::standardButtons () const" .PP KMessageBox中标准按钮的集合 .PP \fBReturns\fP .RS 4 .RE .PP .SS "static QPixmap kdk::KMessageBox::standardIcon (\fBIcon\fP icon)\fC [static]\fP" .PP 返回用于标准图标的pixmap。 .PP \fBParameters\fP .RS 4 \fIicon\fP .RE .PP \fBReturns\fP .RS 4 .RE .PP .SS "static \fBStandardButton\fP kdk::KMessageBox::success (QWidget * parent, const QString & title, const QString & text, StandardButtons buttons = \fCOk\fP, \fBStandardButton\fP defaultButton = \fCNoButton\fP)\fC [static]\fP" .PP 用给定的标题和文本打开一个成功消息框 .PP \fBParameters\fP .RS 4 \fIparent\fP .br \fItitle\fP .br \fItext\fP .br \fIbuttons\fP .br \fIdefaultButton\fP .RE .PP \fBReturns\fP .RS 4 .RE .PP .SS "QString kdk::KMessageBox::text () const" .PP 获取KMessageBox的文本 .PP \fBReturns\fP .RS 4 .RE .PP .SS "static \fBStandardButton\fP kdk::KMessageBox::warning (QWidget * parent, const QString & title, const QString & text, StandardButtons buttons = \fCOk\fP, \fBStandardButton\fP defaultButton = \fCNoButton\fP)\fC [static]\fP" .PP 打开一个带有给定标题和文本的警告消息框 .PP \fBParameters\fP .RS 4 \fIparent\fP .br \fItitle\fP .br \fItext\fP .br \fIbuttons\fP .br \fIdefaultButton\fP .RE .PP \fBReturns\fP .RS 4 .RE .PP .SH "Author" .PP Generated automatically by Doxygen for LIBKYSDK-APPLICATIONS from the source code\&. libkysdk-applications/doxygen/man/man3/BreadCrumb.30000664000175000017500000000043315104543305021160 0ustar fengfeng.TH "BreadCrumb" 3 "Version version:3.0" "LIBKYSDK-APPLICATIONS" \" -*- nroff -*- .ad l .nh .SH NAME BreadCrumb \- BreadCrumb .SH SYNOPSIS .br .PP .SH "Detailed Description" .PP .SH "Author" .PP Generated automatically by Doxygen for LIBKYSDK-APPLICATIONS from the source code\&. libkysdk-applications/doxygen/man/man3/kdk_KBadge.30000664000175000017500000000256015104543305021123 0ustar fengfeng.TH "kdk::KBadge" 3 "Version version:3.0" "LIBKYSDK-APPLICATIONS" \" -*- nroff -*- .ad l .nh .SH NAME kdk::KBadge \- 消息提醒气泡 .SH SYNOPSIS .br .PP .PP \fC#include \fP .PP Inherits QWidget\&. .SS "Public Member Functions" .in +1c .ti -1c .RI "\fBKBadge\fP (QWidget *parent)" .br .ti -1c .RI "int \fBvalue\fP ()" .br .RI "返回值 " .ti -1c .RI "void \fBsetValue\fP (int \fBvalue\fP)" .br .RI "设置值,最大显示数值为999,大于999显示'\&.\&.\&.' " .ti -1c .RI "void \fBsetValueVisiable\fP (bool flag)" .br .RI "设置值是否可见 " .ti -1c .RI "bool \fBisValueVisiable\fP () const" .br .RI "获取值是否可见 " .ti -1c .RI "QColor \fBcolor\fP ()" .br .RI "获取背景色 " .ti -1c .RI "void \fBsetColor\fP (const QColor &\fBcolor\fP)" .br .RI "设置背景色 " .ti -1c .RI "int \fBfontSize\fP ()" .br .RI "获取字体大小 " .ti -1c .RI "void \fBsetFontSize\fP (int size)" .br .RI "设置字体大小 " .in -1c .SS "Protected Member Functions" .in +1c .ti -1c .RI "void \fBpaintEvent\fP (QPaintEvent *event)" .br .ti -1c .RI "void \fBresizeEvent\fP (QResizeEvent *event)" .br .in -1c .SH "Detailed Description" .PP 消息提醒气泡 .PP \fBSince\fP .RS 4 1\&.0\&.0 .RE .PP .PP \fBExamples\fP .in +1c \fBtestbadge/widget\&.h\fP\&. .SH "Author" .PP Generated automatically by Doxygen for LIBKYSDK-APPLICATIONS from the source code\&. libkysdk-applications/doxygen/man/man3/kdk_KSlider.30000664000175000017500000000501115104543305021335 0ustar fengfeng.TH "kdk::KSlider" 3 "Version version:3.0" "LIBKYSDK-APPLICATIONS" \" -*- nroff -*- .ad l .nh .SH NAME kdk::KSlider \- 支持三种样式的滑动条 非步数关系:步数为1,可以在任意位置点击和拖拽 步数关系:步数为固定值,可根据步数值点击和拖拽 节点关系:步数为节点间隔,可根据节点间隔点击和拖拽 .SH SYNOPSIS .br .PP .PP \fC#include \fP .PP Inherits QSlider\&. .SS "Public Member Functions" .in +1c .ti -1c .RI "\fBKSlider\fP (QWidget *parent)" .br .ti -1c .RI "\fBKSlider\fP (Qt::Orientation orientation, QWidget *parent=nullptr)" .br .ti -1c .RI "void \fBsetTickInterval\fP (int interval)" .br .RI "设置节点间隔 " .ti -1c .RI "void \fBsetSliderType\fP (KSliderType type)" .br .RI "设置滑动条类型 " .ti -1c .RI "KSliderType \fBsliderType\fP ()" .br .RI "获取滑动条类型 " .ti -1c .RI "int \fBtickInterval\fP () const" .br .RI "获取节点间隔 " .ti -1c .RI "void \fBsetValue\fP (int)" .br .RI "设置值 " .ti -1c .RI "void \fBsetNodeVisible\fP (bool flag)" .br .RI "设置是否显示节点 " .ti -1c .RI "bool \fBnodeVisible\fP ()" .br .RI "获取是否显示节点 " .ti -1c .RI "void \fBsetToolTip\fP (const QString &)" .br .RI "设置tooltip " .ti -1c .RI "QString \fBtoolTip\fP () const" .br .RI "获取toolTip " .ti -1c .RI "void \fBsetTranslucent\fP (bool flag)" .br .RI "设置是否启用半透明效果 " .ti -1c .RI "bool \fBisTranslucent\fP ()" .br .RI "获取是否启用半透明效果 " .in -1c .SS "Protected Member Functions" .in +1c .ti -1c .RI "void \fBpaintEvent\fP (QPaintEvent *event)" .br .ti -1c .RI "void \fBresizeEvent\fP (QResizeEvent *event)" .br .ti -1c .RI "void \fBmousePressEvent\fP (QMouseEvent *event)" .br .ti -1c .RI "void \fBmouseReleaseEvent\fP (QMouseEvent *event)" .br .ti -1c .RI "void \fBmouseMoveEvent\fP (QMouseEvent *event)" .br .ti -1c .RI "void \fBwheelEvent\fP (QWheelEvent *event)" .br .ti -1c .RI "bool \fBeventFilter\fP (QObject *watched, QEvent *event)" .br .ti -1c .RI "QSize \fBsizeHint\fP () const override" .br .in -1c .SH "Detailed Description" .PP 支持三种样式的滑动条 非步数关系:步数为1,可以在任意位置点击和拖拽 步数关系:步数为固定值,可根据步数值点击和拖拽 节点关系:步数为节点间隔,可根据节点间隔点击和拖拽 .PP \fBSince\fP .RS 4 1\&.0\&.0 .RE .PP .PP \fBExamples\fP .in +1c \fBtestslider/widget\&.h\fP\&. .SH "Author" .PP Generated automatically by Doxygen for LIBKYSDK-APPLICATIONS from the source code\&. libkysdk-applications/doxygen/man/man3/kdk_KNavigationBar.30000664000175000017500000000422615104543305022646 0ustar fengfeng.TH "kdk::KNavigationBar" 3 "Version version:3.0" "LIBKYSDK-APPLICATIONS" \" -*- nroff -*- .ad l .nh .SH NAME kdk::KNavigationBar \- 导航栏控件 .SH SYNOPSIS .br .PP .PP \fC#include \fP .PP Inherits QScrollArea\&. .SS "Public Types" .in +1c .ti -1c .RI "enum \fBNavigationBarDataType\fP { \fBValueRole\fP = Qt::UserRole + 1, \fBStringRole\fP = Qt::UserRole + 2, \fBboolRole\fP = Qt::UserRole + 3 }" .br .in -1c .SS "Signals" .in +1c .ti -1c .RI "void \fBaddTagClicked\fP (QString str)" .br .in -1c .SS "Public Member Functions" .in +1c .ti -1c .RI "\fBKNavigationBar\fP (QWidget *parent)" .br .ti -1c .RI "void \fBaddItem\fP (QStandardItem *item)" .br .RI "增加常规Item " .ti -1c .RI "void \fBaddSubItem\fP (QStandardItem *subItem)" .br .RI "增加次级Item " .ti -1c .RI "void \fBaddGroupItems\fP (QList< QStandardItem * > items, const QString &tag)" .br .RI "成组增加Item,在导航栏中会显示tag " .ti -1c .RI "void \fBinsertGroupItems\fP (QString tag, int row, QStandardItem *item)" .br .RI "在指定tag组中指定位置row插入item " .ti -1c .RI "void \fBremoveGroupItem\fP (QString tag, QStandardItem *item)" .br .RI "在指定组中删除item " .ti -1c .RI "void \fBaddTag\fP (const QString &tag)" .br .RI "添加tag " .ti -1c .RI "QStandardItemModel * \fBmodel\fP ()" .br .RI "获取model " .ti -1c .RI "QListView * \fBlistview\fP ()" .br .RI "获取view " .ti -1c .RI "void \fBsetTabValue\fP (QStandardItem *item, QString value)" .br .RI "设置tabvalue " .ti -1c .RI "void \fBsetTabValueVisible\fP (bool visible)" .br .RI "设置tabvalue是否可见 " .ti -1c .RI "void \fBsetAddIcon\fP (QString tag, QIcon icon)" .br .RI "tag 添加add图标 " .ti -1c .RI "void \fBsetAddTagVisible\fP (QString tag, bool visible)" .br .RI "设置tag add图标是否可见 " .ti -1c .RI "void \fBsetExtendTagVisible\fP (QString tag, bool visible)" .br .RI "设置折叠图标是否可见 " .in -1c .SH "Detailed Description" .PP 导航栏控件 .PP \fBSince\fP .RS 4 1\&.0\&.0 .RE .PP .PP \fBExamples\fP .in +1c \fBtestnavigationbar/widget\&.h\fP\&. .SH "Author" .PP Generated automatically by Doxygen for LIBKYSDK-APPLICATIONS from the source code\&. libkysdk-applications/doxygen/man/man3/PushbuttonModule.30000664000175000017500000002527315104543305022504 0ustar fengfeng.TH "PushbuttonModule" 3 "Version version:3.0" "LIBKYSDK-APPLICATIONS" \" -*- nroff -*- .ad l .nh .SH NAME PushbuttonModule \- PushbuttonModule .SH SYNOPSIS .br .PP .SS "Classes" .in +1c .ti -1c .RI "class \fBkdk::KBorderButton\fP" .br .RI "带边框的按钮 " .ti -1c .RI "class \fBkdk::KBorderlessButton\fP" .br .RI "无边框按钮 " .ti -1c .RI "class \fBkdk::KMenuButton\fP" .br .RI "下拉菜单按钮 " .ti -1c .RI "class \fBkdk::KSwitchButton\fP" .br .RI "指示打开/关闭两种状态 " .ti -1c .RI "class \fBkdk::KToolButton\fP" .br .RI "提供了一个快速访问按钮,暂不支持显示文本 " .in -1c .SS "Enumerations" .in +1c .ti -1c .RI "enum \fBkdk::KToolButtonType\fP { \fBFlat\fP, \fBSemiFlat\fP, \fBBackground\fP, \fBFrameless\fP }" .br .RI "支持三种样式,暂不支持文字显示 " .in -1c .SS "Functions" .in +1c .ti -1c .RI "\fBkdk::KBorderButton::KBorderButton\fP (QWidget *parent=nullptr)" .br .ti -1c .RI "\fBkdk::KBorderButton::KBorderButton\fP (const QString &text, QWidget *parent=nullptr)" .br .ti -1c .RI "\fBkdk::KBorderButton::KBorderButton\fP (const QIcon &icon, const QString &text, QWidget *parent=nullptr)" .br .ti -1c .RI "\fBkdk::KBorderButton::KBorderButton\fP (const QIcon &icon, QWidget *parent=nullptr)" .br .ti -1c .RI "void \fBkdk::KBorderButton::setIcon\fP (const QIcon &icon)" .br .RI "设置按钮图标 " .ti -1c .RI "bool \fBkdk::KBorderButton::eventFilter\fP (QObject *watched, QEvent *event)" .br .ti -1c .RI "void \fBkdk::KBorderButton::paintEvent\fP (QPaintEvent *event)" .br .ti -1c .RI "QSize \fBkdk::KBorderButton::sizeHint\fP () const override" .br .ti -1c .RI "\fBkdk::KBorderlessButton::KBorderlessButton\fP (QWidget *parent=nullptr)" .br .ti -1c .RI "\fBkdk::KBorderlessButton::KBorderlessButton\fP (const QString &text, QWidget *parent=nullptr)" .br .ti -1c .RI "\fBkdk::KBorderlessButton::KBorderlessButton\fP (const QIcon &icon, const QString &text, QWidget *parent=nullptr)" .br .ti -1c .RI "\fBkdk::KBorderlessButton::KBorderlessButton\fP (const QIcon &icon, QWidget *parent=nullptr)" .br .ti -1c .RI "void \fBkdk::KBorderlessButton::setIcon\fP (const QIcon &icon)" .br .RI "设置按钮图标 " .ti -1c .RI "bool \fBkdk::KBorderlessButton::eventFilter\fP (QObject *watched, QEvent *event)" .br .ti -1c .RI "void \fBkdk::KBorderlessButton::paintEvent\fP (QPaintEvent *event)" .br .ti -1c .RI "QSize \fBkdk::KBorderlessButton::sizeHint\fP () const" .br .ti -1c .RI "\fBkdk::KMenuButton::KMenuButton\fP (QWidget *parent=nullptr)" .br .ti -1c .RI "QMenu * \fBkdk::KMenuButton::menu\fP ()" .br .RI "获取主菜单 " .ti -1c .RI "QMenu * \fBkdk::KMenuButton::themeMenu\fP ()" .br .RI "获取主题菜单 " .ti -1c .RI "QAction * \fBkdk::KMenuButton::settingAction\fP ()" .br .RI "获取设置action " .ti -1c .RI "QAction * \fBkdk::KMenuButton::themeAction\fP ()" .br .RI "获取主题Action " .ti -1c .RI "QAction * \fBkdk::KMenuButton::assistAction\fP ()" .br .RI "获取帮助Action " .ti -1c .RI "QAction * \fBkdk::KMenuButton::aboutAction\fP ()" .br .RI "获取关于Action " .ti -1c .RI "QAction * \fBkdk::KMenuButton::feedbackAction\fP ()" .br .RI "获取意见反馈Action " .ti -1c .RI "QAction * \fBkdk::KMenuButton::quitAction\fP ()" .br .RI "获取离开Action " .ti -1c .RI "QAction * \fBkdk::KMenuButton::autoAction\fP ()" .br .RI "获取跟随主题Action " .ti -1c .RI "QAction * \fBkdk::KMenuButton::lightAction\fP ()" .br .RI "获取浅色主题Action " .ti -1c .RI "QAction * \fBkdk::KMenuButton::darkAction\fP ()" .br .RI "获取深色Action " .ti -1c .RI "void \fBkdk::KMenuButton::changeTheme\fP () override" .br .ti -1c .RI "void \fBkdk::KMenuButton::paintEvent\fP (QPaintEvent *painteEvent)" .br .ti -1c .RI "QSize \fBkdk::KMenuButton::sizeHint\fP () const override" .br .ti -1c .RI "\fBkdk::KSwitchButton::KSwitchButton\fP (QWidget *parent=0)" .br .ti -1c .RI "void \fBkdk::KSwitchButton::setCheckable\fP (bool)" .br .RI "设置是否可选中 " .ti -1c .RI "bool \fBkdk::KSwitchButton::isCheckable\fP () const" .br .RI "返回是否可选中 " .ti -1c .RI "bool \fBkdk::KSwitchButton::isChecked\fP () const" .br .RI "返回是否选中 " .ti -1c .RI "void \fBkdk::KSwitchButton::setChecked\fP (bool)" .br .RI "设置是否选中 " .ti -1c .RI "void \fBkdk::KSwitchButton::setTranslucent\fP (bool flag)" .br .RI "设置是否启用半透明效果 " .ti -1c .RI "bool \fBkdk::KSwitchButton::isTranslucent\fP ()" .br .RI "获取是否启用半透明效果 " .ti -1c .RI "void \fBkdk::KSwitchButton::paintEvent\fP (QPaintEvent *event) override" .br .ti -1c .RI "void \fBkdk::KSwitchButton::resizeEvent\fP (QResizeEvent *event) override" .br .ti -1c .RI "QSize \fBkdk::KSwitchButton::sizeHint\fP () const" .br .ti -1c .RI "\fBkdk::KToolButton::KToolButton\fP (QWidget *parent)" .br .ti -1c .RI "\fBKToolButtonType\fP \fBkdk::KToolButton::type\fP ()" .br .RI "返回类型 " .ti -1c .RI "void \fBkdk::KToolButton::setType\fP (\fBKToolButtonType\fP \fBtype\fP)" .br .RI "设置类型 " .ti -1c .RI "void \fBkdk::KToolButton::setIcon\fP (const QIcon &\fBicon\fP)" .br .RI "设置Icon " .ti -1c .RI "void \fBkdk::KToolButton::setLoading\fP (bool flag)" .br .RI "设置正在加载状态,仅不带箭头的toolbuttuon支持该状态 " .ti -1c .RI "bool \fBkdk::KToolButton::isLoading\fP ()" .br .RI "返回是否正在加载 " .ti -1c .RI "QIcon \fBkdk::KToolButton::icon\fP ()" .br .RI "获取Icon " .ti -1c .RI "void \fBkdk::KToolButton::setArrow\fP (bool flag)" .br .RI "设置是否显示向下箭头,默认不显示 " .ti -1c .RI "bool \fBkdk::KToolButton::hasArrow\fP () const" .br .RI "返回是否显示箭头 " .ti -1c .RI "void \fBkdk::KToolButton::setIconColor\fP (bool flag, QColor color)" .br .RI "设置图标颜色 " .ti -1c .RI "void \fBkdk::KToolButton::setBorderRadius\fP (int bottomLeft, int topLeft, int topRight, int bottomRight)" .br .RI "setBorderRadius " .ti -1c .RI "void \fBkdk::KToolButton::setBackgroundColorEnabled\fP (bool flag)" .br .RI "setBackgroundColorEnabled " .ti -1c .RI "bool \fBkdk::KToolButton::backgroundColorEnabled\fP ()" .br .RI "backgroundColorEnabled " .ti -1c .RI "bool \fBkdk::KToolButton::eventFilter\fP (QObject *watched, QEvent *event)" .br .ti -1c .RI "QSize \fBkdk::KToolButton::sizeHint\fP () const" .br .ti -1c .RI "void \fBkdk::KToolButton::paintEvent\fP (QPaintEvent *event)" .br .in -1c .SS "Signals" .in +1c .ti -1c .RI "void \fBkdk::KSwitchButton::stateChanged\fP (bool)" .br .RI "当选中状态发生变化时,发出此信号 " .ti -1c .RI "void \fBkdk::KToolButton::checkedChanged\fP (bool checked)" .br .in -1c .SH "Detailed Description" .PP { .SH "Enumeration Type Documentation" .PP .SS "enum \fBkdk::KToolButtonType\fP" .PP 支持三种样式,暂不支持文字显示 .PP \fBSince\fP .RS 4 1\&.0\&.0 .RE .PP .SH "Function Documentation" .PP .SS "QAction * kdk::KMenuButton::aboutAction ()" .PP 获取关于Action .PP \fBReturns\fP .RS 4 .RE .PP .SS "QAction * kdk::KMenuButton::assistAction ()" .PP 获取帮助Action .PP \fBReturns\fP .RS 4 .RE .PP .SS "QAction * kdk::KMenuButton::autoAction ()" .PP 获取跟随主题Action .PP \fBReturns\fP .RS 4 .RE .PP .SS "bool kdk::KToolButton::backgroundColorEnabled ()" .PP backgroundColorEnabled .PP \fBReturns\fP .RS 4 .RE .PP \fBSince\fP .RS 4 2\&.5\&.2\&.0 .RE .PP .SS "QAction * kdk::KMenuButton::darkAction ()" .PP 获取深色Action .PP \fBReturns\fP .RS 4 .RE .PP .SS "QAction * kdk::KMenuButton::feedbackAction ()" .PP 获取意见反馈Action .PP \fBSince\fP .RS 4 2\&.4\&.1\&.0-0k1\&.0 .RE .PP \fBReturns\fP .RS 4 .RE .PP .SS "bool kdk::KToolButton::hasArrow () const" .PP 返回是否显示箭头 .PP \fBReturns\fP .RS 4 .RE .PP .SS "QIcon kdk::KToolButton::icon ()" .PP 获取Icon .PP \fBReturns\fP .RS 4 .RE .PP .SS "bool kdk::KSwitchButton::isCheckable () const" .PP 返回是否可选中 .PP \fBReturns\fP .RS 4 .RE .PP .SS "bool kdk::KSwitchButton::isChecked () const" .PP 返回是否选中 .PP \fBReturns\fP .RS 4 .RE .PP .SS "bool kdk::KToolButton::isLoading ()" .PP 返回是否正在加载 .PP \fBReturns\fP .RS 4 .RE .PP .SS "bool kdk::KSwitchButton::isTranslucent ()" .PP 获取是否启用半透明效果 .PP \fBSince\fP .RS 4 1\&.2\&.0 .RE .PP \fBReturns\fP .RS 4 flag .RE .PP .SS "QAction * kdk::KMenuButton::lightAction ()" .PP 获取浅色主题Action .PP \fBReturns\fP .RS 4 .RE .PP .SS "QMenu * kdk::KMenuButton::menu ()" .PP 获取主菜单 .PP \fBReturns\fP .RS 4 .RE .PP .SS "QAction * kdk::KMenuButton::quitAction ()" .PP 获取离开Action .PP \fBReturns\fP .RS 4 .RE .PP .SS "void kdk::KToolButton::setArrow (bool flag)" .PP 设置是否显示向下箭头,默认不显示 .PP \fBParameters\fP .RS 4 \fIflag\fP .RE .PP .SS "void kdk::KToolButton::setBackgroundColorEnabled (bool flag)" .PP setBackgroundColorEnabled .PP \fBParameters\fP .RS 4 \fIflag\fP .RE .PP \fBSince\fP .RS 4 2\&.5\&.2\&.0 .RE .PP .SS "void kdk::KToolButton::setBorderRadius (int bottomLeft, int topLeft, int topRight, int bottomRight)" .PP setBorderRadius .PP \fBParameters\fP .RS 4 \fIbottomLeft\fP .br \fItopLeft\fP .br \fItopRight\fP .br \fIbottomRight\fP .RE .PP \fBSince\fP .RS 4 2\&.5\&.2\&.0 .RE .PP .SS "void kdk::KSwitchButton::setChecked (bool)" .PP 设置是否选中 .PP \fBReturns\fP .RS 4 .RE .PP .SS "void kdk::KBorderButton::setIcon (const QIcon & icon)" .PP 设置按钮图标 .PP \fBParameters\fP .RS 4 \fIicon\fP .RE .PP .SS "void kdk::KBorderlessButton::setIcon (const QIcon & icon)" .PP 设置按钮图标 .PP \fBParameters\fP .RS 4 \fIicon\fP .RE .PP .SS "void kdk::KToolButton::setIcon (const QIcon & icon)" .PP 设置Icon .PP \fBParameters\fP .RS 4 \fIicon\fP .RE .PP .SS "void kdk::KToolButton::setIconColor (bool flag, QColor color)" .PP 设置图标颜色 .PP \fBParameters\fP .RS 4 \fIflag\fP .br \fIcolor\fP .RE .PP \fBSince\fP .RS 4 2\&.4\&.1\&.0 .RE .PP .SS "void kdk::KToolButton::setLoading (bool flag)" .PP 设置正在加载状态,仅不带箭头的toolbuttuon支持该状态 .PP \fBParameters\fP .RS 4 \fIflag\fP .RE .PP .SS "QAction * kdk::KMenuButton::settingAction ()" .PP 获取设置action .PP \fBReturns\fP .RS 4 .RE .PP .SS "void kdk::KSwitchButton::setTranslucent (bool flag)" .PP 设置是否启用半透明效果 .PP \fBSince\fP .RS 4 1\&.2\&.0 .RE .PP \fBParameters\fP .RS 4 \fIflag\fP .RE .PP .SS "void kdk::KToolButton::setType (\fBKToolButtonType\fP type)" .PP 设置类型 .PP \fBParameters\fP .RS 4 \fItype\fP .RE .PP .SS "QAction * kdk::KMenuButton::themeAction ()" .PP 获取主题Action .PP \fBReturns\fP .RS 4 .RE .PP .SS "QMenu * kdk::KMenuButton::themeMenu ()" .PP 获取主题菜单 .PP \fBReturns\fP .RS 4 .RE .PP .SS "\fBKToolButtonType\fP kdk::KToolButton::type ()" .PP 返回类型 .PP \fBReturns\fP .RS 4 .RE .PP .SH "Author" .PP Generated automatically by Doxygen for LIBKYSDK-APPLICATIONS from the source code\&. libkysdk-applications/doxygen/man/man3/kdk_KToolButton.30000664000175000017500000000371715104543305022237 0ustar fengfeng.TH "kdk::KToolButton" 3 "Version version:3.0" "LIBKYSDK-APPLICATIONS" \" -*- nroff -*- .ad l .nh .SH NAME kdk::KToolButton \- 提供了一个快速访问按钮,暂不支持显示文本 .SH SYNOPSIS .br .PP .PP \fC#include \fP .PP Inherits QToolButton\&. .SS "Signals" .in +1c .ti -1c .RI "void \fBcheckedChanged\fP (bool checked)" .br .in -1c .SS "Public Member Functions" .in +1c .ti -1c .RI "\fBKToolButton\fP (QWidget *parent)" .br .ti -1c .RI "\fBKToolButtonType\fP \fBtype\fP ()" .br .RI "返回类型 " .ti -1c .RI "void \fBsetType\fP (\fBKToolButtonType\fP \fBtype\fP)" .br .RI "设置类型 " .ti -1c .RI "void \fBsetIcon\fP (const QIcon &\fBicon\fP)" .br .RI "设置Icon " .ti -1c .RI "void \fBsetLoading\fP (bool flag)" .br .RI "设置正在加载状态,仅不带箭头的toolbuttuon支持该状态 " .ti -1c .RI "bool \fBisLoading\fP ()" .br .RI "返回是否正在加载 " .ti -1c .RI "QIcon \fBicon\fP ()" .br .RI "获取Icon " .ti -1c .RI "void \fBsetArrow\fP (bool flag)" .br .RI "设置是否显示向下箭头,默认不显示 " .ti -1c .RI "bool \fBhasArrow\fP () const" .br .RI "返回是否显示箭头 " .ti -1c .RI "void \fBsetIconColor\fP (bool flag, QColor color)" .br .RI "设置图标颜色 " .ti -1c .RI "void \fBsetBorderRadius\fP (int bottomLeft, int topLeft, int topRight, int bottomRight)" .br .RI "setBorderRadius " .ti -1c .RI "void \fBsetBackgroundColorEnabled\fP (bool flag)" .br .RI "setBackgroundColorEnabled " .ti -1c .RI "bool \fBbackgroundColorEnabled\fP ()" .br .RI "backgroundColorEnabled " .in -1c .SS "Protected Member Functions" .in +1c .ti -1c .RI "bool \fBeventFilter\fP (QObject *watched, QEvent *event)" .br .ti -1c .RI "QSize \fBsizeHint\fP () const" .br .ti -1c .RI "void \fBpaintEvent\fP (QPaintEvent *event)" .br .in -1c .SH "Detailed Description" .PP 提供了一个快速访问按钮,暂不支持显示文本 .SH "Author" .PP Generated automatically by Doxygen for LIBKYSDK-APPLICATIONS from the source code\&. libkysdk-applications/doxygen/man/man3/kdk_KTableModel.30000664000175000017500000000107315104543305022127 0ustar fengfeng.TH "kdk::KTableModel" 3 "Version version:3.0" "LIBKYSDK-APPLICATIONS" \" -*- nroff -*- .ad l .nh .SH NAME kdk::KTableModel .SH SYNOPSIS .br .PP .PP Inherits QStandardItemModel\&. .SS "Public Member Functions" .in +1c .ti -1c .RI "\fBKTableModel\fP (QObject *parent=nullptr)" .br .in -1c .SS "Protected Member Functions" .in +1c .ti -1c .RI "QVariant \fBheaderData\fP (int section, Qt::Orientation orientation, int role=Qt::DisplayRole) const override" .br .in -1c .SH "Author" .PP Generated automatically by Doxygen for LIBKYSDK-APPLICATIONS from the source code\&. libkysdk-applications/doxygen/man/man3/kdk_KPixmapContainer.30000664000175000017500000000323615104543305023223 0ustar fengfeng.TH "kdk::KPixmapContainer" 3 "Version version:3.0" "LIBKYSDK-APPLICATIONS" \" -*- nroff -*- .ad l .nh .SH NAME kdk::KPixmapContainer \- 为指定的pixmap添加右上角消息提示气泡,样式类似微信头像的消息提示 .SH SYNOPSIS .br .PP .PP \fC#include \fP .PP Inherits QWidget\&. .SS "Public Member Functions" .in +1c .ti -1c .RI "\fBKPixmapContainer\fP (QWidget *parent=nullptr)" .br .ti -1c .RI "int \fBvalue\fP () const" .br .RI "获取值 " .ti -1c .RI "void \fBsetValue\fP (int \fBvalue\fP)" .br .RI "设置值 " .ti -1c .RI "void \fBsetValueVisiable\fP (bool flag)" .br .RI "设置值是否可见 " .ti -1c .RI "bool \fBisValueVisiable\fP () const" .br .RI "获取值是否可见 " .ti -1c .RI "void \fBsetPixmap\fP (const QPixmap &\fBpixmap\fP)" .br .RI "设置pixmap " .ti -1c .RI "QPixmap \fBpixmap\fP () const" .br .RI "获取pixmap " .ti -1c .RI "void \fBclearValue\fP ()" .br .RI "清除值 " .ti -1c .RI "QColor \fBcolor\fP ()" .br .RI "返回背景色 " .ti -1c .RI "void \fBsetColor\fP (const QColor &\fBcolor\fP)" .br .RI "设置背景色 " .ti -1c .RI "int \fBfontSize\fP ()" .br .RI "返回字体大小 " .ti -1c .RI "void \fBsetFontSize\fP (int size)" .br .RI "设置字体大小 " .in -1c .SS "Protected Member Functions" .in +1c .ti -1c .RI "void \fBpaintEvent\fP (QPaintEvent *event)" .br .in -1c .SH "Detailed Description" .PP 为指定的pixmap添加右上角消息提示气泡,样式类似微信头像的消息提示 .PP \fBSince\fP .RS 4 1\&.0\&.0 .RE .PP .PP \fBExamples\fP .in +1c \fBtestbadge/widget\&.h\fP\&. .SH "Author" .PP Generated automatically by Doxygen for LIBKYSDK-APPLICATIONS from the source code\&. libkysdk-applications/doxygen/man/man3/kdk_KArrowTabBar.30000664000175000017500000000153315104543305022266 0ustar fengfeng.TH "kdk::KArrowTabBar" 3 "Version version:3.0" "LIBKYSDK-APPLICATIONS" \" -*- nroff -*- .ad l .nh .SH NAME kdk::KArrowTabBar \- 可显示箭头的tabbar .SH SYNOPSIS .br .PP .PP \fC#include \fP .PP Inherits QWidget\&. .SS "Signals" .in +1c .ti -1c .RI "void \fBsizeChange\fP ()" .br .RI "点击会发出信号 " .in -1c .SS "Public Member Functions" .in +1c .ti -1c .RI "\fBKArrowTabBar\fP (QWidget *parent=nullptr)" .br .ti -1c .RI "\fBKNativeTabbar\fP * \fBtabbar\fP ()" .br .RI "获取knativetabbar " .in -1c .SS "Protected Member Functions" .in +1c .ti -1c .RI "void \fBresizeEvent\fP (QResizeEvent *event)" .br .in -1c .SH "Detailed Description" .PP 可显示箭头的tabbar .PP \fBSince\fP .RS 4 2\&.5\&.2\&.0 .RE .PP .SH "Author" .PP Generated automatically by Doxygen for LIBKYSDK-APPLICATIONS from the source code\&. libkysdk-applications/doxygen/man/man3/kdk_KMenuButton.30000664000175000017500000000312615104543305022220 0ustar fengfeng.TH "kdk::KMenuButton" 3 "Version version:3.0" "LIBKYSDK-APPLICATIONS" \" -*- nroff -*- .ad l .nh .SH NAME kdk::KMenuButton \- 下拉菜单按钮 .SH SYNOPSIS .br .PP .PP \fC#include \fP .PP Inherits QToolButton, and ThemeController\&. .SS "Public Member Functions" .in +1c .ti -1c .RI "\fBKMenuButton\fP (QWidget *parent=nullptr)" .br .ti -1c .RI "QMenu * \fBmenu\fP ()" .br .RI "获取主菜单 " .ti -1c .RI "QMenu * \fBthemeMenu\fP ()" .br .RI "获取主题菜单 " .ti -1c .RI "QAction * \fBsettingAction\fP ()" .br .RI "获取设置action " .ti -1c .RI "QAction * \fBthemeAction\fP ()" .br .RI "获取主题Action " .ti -1c .RI "QAction * \fBassistAction\fP ()" .br .RI "获取帮助Action " .ti -1c .RI "QAction * \fBaboutAction\fP ()" .br .RI "获取关于Action " .ti -1c .RI "QAction * \fBfeedbackAction\fP ()" .br .RI "获取意见反馈Action " .ti -1c .RI "QAction * \fBquitAction\fP ()" .br .RI "获取离开Action " .ti -1c .RI "QAction * \fBautoAction\fP ()" .br .RI "获取跟随主题Action " .ti -1c .RI "QAction * \fBlightAction\fP ()" .br .RI "获取浅色主题Action " .ti -1c .RI "QAction * \fBdarkAction\fP ()" .br .RI "获取深色Action " .in -1c .SS "Protected Member Functions" .in +1c .ti -1c .RI "void \fBchangeTheme\fP () override" .br .ti -1c .RI "void \fBpaintEvent\fP (QPaintEvent *painteEvent)" .br .ti -1c .RI "QSize \fBsizeHint\fP () const override" .br .in -1c .SH "Detailed Description" .PP 下拉菜单按钮 .PP \fBSince\fP .RS 4 1\&.0\&.0 .RE .PP .SH "Author" .PP Generated automatically by Doxygen for LIBKYSDK-APPLICATIONS from the source code\&. libkysdk-applications/doxygen/man/man3/kdk_KBaseFrame.30000664000175000017500000000556315104543305021754 0ustar fengfeng.TH "kdk::KBaseFrame" 3 "Version version:3.0" "LIBKYSDK-APPLICATIONS" \" -*- nroff -*- .ad l .nh .SH NAME kdk::KBaseFrame .SH SYNOPSIS .br .PP .PP Inherits QFrame\&. .PP Inherited by \fBkdk::KComboBoxFrame\fP, \fBkdk::KLineEditFrame\fP, \fBkdk::KPushButtonFrame\fP, \fBkdk::KRadioButtonFrame\fP, \fBkdk::KSettingGroup\fP, \fBkdk::KSliderFrame\fP, and \fBkdk::KSwitchButtonFrame\fP\&. .SS "Public Types" .in +1c .ti -1c .RI "enum \fBBorderRadiusStyle\fP { \fBTop\fP, \fBNone\fP, \fBBottom\fP, \fBAround\fP }" .br .in -1c .SS "Signals" .in +1c .ti -1c .RI "void \fBtabletModeChanged\fP (bool b)" .br .in -1c .SS "Public Member Functions" .in +1c .ti -1c .RI "\fBKBaseFrame\fP (QWidget *parent=nullptr, \fBBorderRadiusStyle\fP style=\fBAround\fP, bool heightAdaptive=false)" .br .RI "构造函数 " .ti -1c .RI "void \fBsetRadiusType\fP (\fBBorderRadiusStyle\fP style)" .br .RI "设置圆角风格 " .ti -1c .RI "bool \fBgetTabletMode\fP ()" .br .RI "获取平板模式 " .ti -1c .RI "bool \fBisContainer\fP ()" .br .RI "获取是否是一个容器frame,此时settinggroup需要设置的是其子frame的圆角 " .ti -1c .RI "void \fBsetContainer\fP (bool b=false)" .br .RI "设置该frame是否是一个容器frame,如果是同时setFrameShape(NoFrame); " .in -1c .SS "Protected Member Functions" .in +1c .ti -1c .RI "void \fBpaintEvent\fP (QPaintEvent *e)" .br .in -1c .SH "Member Enumeration Documentation" .PP .SS "enum \fBkdk::KBaseFrame::BorderRadiusStyle\fP" .PP \fBEnumerator\fP .in +1c .TP \fB\fITop \fP\fP 顶部有圆角 .TP \fB\fINone \fP\fP 没有圆角 .TP \fB\fIBottom \fP\fP 底部有圆角 .TP \fB\fIAround \fP\fP 四周都有圆角 .SH "Constructor & Destructor Documentation" .PP .SS "kdk::KBaseFrame::KBaseFrame (QWidget * parent = \fCnullptr\fP, \fBBorderRadiusStyle\fP style = \fC\fBAround\fP\fP, bool heightAdaptive = \fCfalse\fP)\fC [explicit]\fP" .PP 构造函数 .PP \fBParameters\fP .RS 4 \fIparent\fP 父对象 .br \fIstyle\fP 圆角风格枚举值 .br \fIheightAdaptive\fP 是否自动调整高度,默认PC下60,平板模式64 .RE .PP .SH "Member Function Documentation" .PP .SS "bool kdk::KBaseFrame::getTabletMode ()" .PP 获取平板模式 .PP \fBReturns\fP .RS 4 bool 是否是平板模式 .RE .PP .SS "bool kdk::KBaseFrame::isContainer ()" .PP 获取是否是一个容器frame,此时settinggroup需要设置的是其子frame的圆角 .PP \fBReturns\fP .RS 4 bool 是/不是 .RE .PP .SS "void kdk::KBaseFrame::setContainer (bool b = \fCfalse\fP)" .PP 设置该frame是否是一个容器frame,如果是同时setFrameShape(NoFrame); .PP \fBParameters\fP .RS 4 \fIb\fP 是/不是 .RE .PP .SS "void kdk::KBaseFrame::setRadiusType (\fBBorderRadiusStyle\fP style)" .PP 设置圆角风格 .PP \fBParameters\fP .RS 4 \fIstyle\fP 圆角风格枚举值 .RE .PP .SH "Author" .PP Generated automatically by Doxygen for LIBKYSDK-APPLICATIONS from the source code\&. libkysdk-applications/doxygen/man/man3/ListViewModule.30000664000175000017500000000044715104543305022073 0ustar fengfeng.TH "ListViewModule" 3 "Version version:3.0" "LIBKYSDK-APPLICATIONS" \" -*- nroff -*- .ad l .nh .SH NAME ListViewModule \- ListViewModule .SH SYNOPSIS .br .PP .SH "Detailed Description" .PP .SH "Author" .PP Generated automatically by Doxygen for LIBKYSDK-APPLICATIONS from the source code\&. libkysdk-applications/doxygen/man/man3/KCustomTabBar.30000664000175000017500000001533215104543305021617 0ustar fengfeng.TH "KCustomTabBar" 3 "Version version:3.0" "LIBKYSDK-APPLICATIONS" \" -*- nroff -*- .ad l .nh .SH NAME KCustomTabBar .SH SYNOPSIS .br .PP .PP Inherits QWidget\&. .PP Inherited by \fBkdk::KCrumb\fP, and \fBkdk::KNativeTabbar\fP\&. .SS "Public Types" .in +1c .ti -1c .RI "enum \fBShape\fP { \fBRoundedNorth\fP, \fBRoundedSouth\fP, \fBRoundedWest\fP, \fBRoundedEast\fP, \fBTriangularNorth\fP, \fBTriangularSouth\fP, \fBTriangularWest\fP, \fBTriangularEast\fP }" .br .ti -1c .RI "enum \fBButtonPosition\fP { \fBLeftSide\fP, \fBRightSide\fP }" .br .ti -1c .RI "enum \fBSelectionBehavior\fP { \fBSelectLeftTab\fP, \fBSelectRightTab\fP, \fBSelectPreviousTab\fP }" .br .in -1c .SS "Public Slots" .in +1c .ti -1c .RI "void \fBsetCurrentIndex\fP (int index)" .br .ti -1c .RI "void \fBleftScrollTabs\fP ()" .br .ti -1c .RI "void \fBrightScrollTabs\fP ()" .br .ti -1c .RI "void \fBcloseTab\fP ()" .br .in -1c .SS "Signals" .in +1c .ti -1c .RI "void \fBcurrentChanged\fP (int index)" .br .ti -1c .RI "void \fBtabCloseRequested\fP (int index)" .br .ti -1c .RI "void \fBtabMoved\fP (int from, int to)" .br .ti -1c .RI "void \fBtabBarClicked\fP (int index)" .br .ti -1c .RI "void \fBtabBarDoubleClicked\fP (int index)" .br .ti -1c .RI "void \fBleftBStatus\fP (bool flag)" .br .ti -1c .RI "void \fBrightBStatus\fP (bool flag)" .br .in -1c .SS "Public Member Functions" .in +1c .ti -1c .RI "\fBKCustomTabBar\fP (QWidget *parent=nullptr)" .br .ti -1c .RI "Shape \fBshape\fP () const" .br .ti -1c .RI "void \fBsetShape\fP (Shape shape)" .br .ti -1c .RI "int \fBaddTab\fP (const QString &text)" .br .ti -1c .RI "int \fBaddTab\fP (const QIcon &icon, const QString &text)" .br .ti -1c .RI "int \fBinsertTab\fP (int index, const QString &text)" .br .ti -1c .RI "int \fBinsertTab\fP (int index, const QIcon &icon, const QString &text)" .br .ti -1c .RI "void \fBremoveTab\fP (int index)" .br .ti -1c .RI "void \fBmoveTab\fP (int from, int to)" .br .ti -1c .RI "bool \fBisTabEnabled\fP (int index) const" .br .ti -1c .RI "void \fBsetTabEnabled\fP (int index, bool)" .br .ti -1c .RI "QString \fBtabText\fP (int index) const" .br .ti -1c .RI "void \fBsetTabText\fP (int index, const QString &text)" .br .ti -1c .RI "void \fBsetTabContent\fP (int index, const QString &text)" .br .ti -1c .RI "QColor \fBtabTextColor\fP (int index) const" .br .ti -1c .RI "void \fBsetTabTextColor\fP (int index, const QColor &color)" .br .ti -1c .RI "QIcon \fBtabIcon\fP (int index) const" .br .ti -1c .RI "void \fBsetTabIcon\fP (int index, const QIcon &icon)" .br .ti -1c .RI "Qt::TextElideMode \fBelideMode\fP () const" .br .ti -1c .RI "void \fBsetElideMode\fP (Qt::TextElideMode)" .br .ti -1c .RI "void \fBsetTabToolTip\fP (int index, const QString &tip)" .br .ti -1c .RI "QString \fBtabToolTip\fP (int index) const" .br .ti -1c .RI "void \fBsetTabWhatsThis\fP (int index, const QString &text)" .br .ti -1c .RI "QString \fBtabWhatsThis\fP (int index) const" .br .ti -1c .RI "void \fBsetTabData\fP (int index, const QVariant &data)" .br .ti -1c .RI "QVariant \fBtabData\fP (int index) const" .br .ti -1c .RI "QRect \fBtabRect\fP (int index) const" .br .ti -1c .RI "int \fBtabAt\fP (const QPoint &pos) const" .br .ti -1c .RI "int \fBcurrentIndex\fP () const" .br .ti -1c .RI "int \fBcount\fP () const" .br .ti -1c .RI "QSize \fBsizeHint\fP () const override" .br .ti -1c .RI "QSize \fBminimumSizeHint\fP () const override" .br .ti -1c .RI "void \fBsetDrawBase\fP (bool drawTheBase)" .br .ti -1c .RI "bool \fBdrawBase\fP () const" .br .ti -1c .RI "QSize \fBiconSize\fP () const" .br .ti -1c .RI "void \fBsetIconSize\fP (const QSize &size)" .br .ti -1c .RI "bool \fBusesScrollButtons\fP () const" .br .ti -1c .RI "void \fBsetUsesScrollButtons\fP (bool useButtons)" .br .ti -1c .RI "bool \fBtabsClosable\fP () const" .br .ti -1c .RI "void \fBsetTabsClosable\fP (bool closable)" .br .ti -1c .RI "void \fBsetTabButton\fP (int index, ButtonPosition position, QWidget *widget)" .br .ti -1c .RI "QWidget * \fBtabButton\fP (int index, ButtonPosition position) const" .br .ti -1c .RI "SelectionBehavior \fBselectionBehaviorOnRemove\fP () const" .br .ti -1c .RI "void \fBsetSelectionBehaviorOnRemove\fP (SelectionBehavior behavior)" .br .ti -1c .RI "bool \fBexpanding\fP () const" .br .ti -1c .RI "void \fBsetExpanding\fP (bool enabled)" .br .ti -1c .RI "bool \fBisMovable\fP () const" .br .ti -1c .RI "void \fBsetMovable\fP (bool movable)" .br .ti -1c .RI "bool \fBdocumentMode\fP () const" .br .ti -1c .RI "void \fBsetDocumentMode\fP (bool set)" .br .ti -1c .RI "bool \fBautoHide\fP () const" .br .ti -1c .RI "void \fBsetAutoHide\fP (bool hide)" .br .ti -1c .RI "bool \fBchangeCurrentOnDrag\fP () const" .br .ti -1c .RI "void \fBsetChangeCurrentOnDrag\fP (bool change)" .br .ti -1c .RI "QString \fBaccessibleTabName\fP (int index) const" .br .ti -1c .RI "void \fBsetAccessibleTabName\fP (int index, const QString &name)" .br .in -1c .SS "Protected Member Functions" .in +1c .ti -1c .RI "virtual QSize \fBtabSizeHint\fP (int index) const" .br .ti -1c .RI "virtual QSize \fBminimumTabSizeHint\fP (int index) const" .br .ti -1c .RI "virtual void \fBtabInserted\fP (int index)" .br .ti -1c .RI "virtual void \fBtabRemoved\fP (int index)" .br .ti -1c .RI "virtual void \fBtabLayoutChange\fP ()" .br .ti -1c .RI "bool \fBevent\fP (QEvent *) override" .br .ti -1c .RI "void \fBresizeEvent\fP (QResizeEvent *) override" .br .ti -1c .RI "void \fBshowEvent\fP (QShowEvent *) override" .br .ti -1c .RI "void \fBhideEvent\fP (QHideEvent *) override" .br .ti -1c .RI "void \fBpaintEvent\fP (QPaintEvent *) override" .br .ti -1c .RI "void \fBmousePressEvent\fP (QMouseEvent *) override" .br .ti -1c .RI "void \fBmouseMoveEvent\fP (QMouseEvent *) override" .br .ti -1c .RI "void \fBmouseReleaseEvent\fP (QMouseEvent *) override" .br .ti -1c .RI "void \fBwheelEvent\fP (QWheelEvent *event) override" .br .ti -1c .RI "void \fBkeyPressEvent\fP (QKeyEvent *) override" .br .ti -1c .RI "void \fBchangeEvent\fP (QEvent *) override" .br .ti -1c .RI "void \fBtimerEvent\fP (QTimerEvent *event) override" .br .ti -1c .RI "void \fBinitStyleOption\fP (QStyleOptionTab *option, int tabIndex) const" .br .in -1c .SS "Properties" .in +1c .ti -1c .RI "Shape \fBshape\fP" .br .ti -1c .RI "int \fBcurrentIndex\fP" .br .ti -1c .RI "int \fBcount\fP" .br .ti -1c .RI "bool \fBdrawBase\fP" .br .ti -1c .RI "QSize \fBiconSize\fP" .br .ti -1c .RI "Qt::TextElideMode \fBelideMode\fP" .br .ti -1c .RI "bool \fBusesScrollButtons\fP" .br .ti -1c .RI "bool \fBtabsClosable\fP" .br .ti -1c .RI "SelectionBehavior \fBselectionBehaviorOnRemove\fP" .br .ti -1c .RI "bool \fBexpanding\fP" .br .ti -1c .RI "bool \fBmovable\fP" .br .ti -1c .RI "bool \fBdocumentMode\fP" .br .ti -1c .RI "bool \fBautoHide\fP" .br .ti -1c .RI "bool \fBchangeCurrentOnDrag\fP" .br .in -1c .SH "Author" .PP Generated automatically by Doxygen for LIBKYSDK-APPLICATIONS from the source code\&. libkysdk-applications/doxygen/man/man3/kdk_KTableView.30000664000175000017500000000254015104543305022001 0ustar fengfeng.TH "kdk::KTableView" 3 "Version version:3.0" "LIBKYSDK-APPLICATIONS" \" -*- nroff -*- .ad l .nh .SH NAME kdk::KTableView .SH SYNOPSIS .br .PP .PP Inherits QTableView\&. .SS "Signals" .in +1c .ti -1c .RI "void \fBhoverIndexChanged\fP (QModelIndex index)" .br .in -1c .SS "Public Member Functions" .in +1c .ti -1c .RI "\fBKTableView\fP (QWidget *parent=nullptr)" .br .ti -1c .RI "void \fBsetHorizontalTitle\fP (QStringList list)" .br .RI "设置水平标题 " .ti -1c .RI "\fBKTableHeaderView\fP * \fBheaderView\fP ()" .br .RI "返回水平标题栏 " .ti -1c .RI "QList< int > \fBselectList\fP ()" .br .RI "返回所有选中item的行索引 " .in -1c .SS "Protected Member Functions" .in +1c .ti -1c .RI "void \fBmouseMoveEvent\fP (QMouseEvent *event)" .br .ti -1c .RI "bool \fBeventFilter\fP (QObject *object, QEvent *event)" .br .in -1c .SH "Member Function Documentation" .PP .SS "\fBKTableHeaderView\fP * kdk::KTableView::headerView ()" .PP 返回水平标题栏 .PP \fBReturns\fP .RS 4 .RE .PP .SS "QList< int > kdk::KTableView::selectList ()" .PP 返回所有选中item的行索引 .PP \fBReturns\fP .RS 4 .RE .PP .SS "void kdk::KTableView::setHorizontalTitle (QStringList list)" .PP 设置水平标题 .PP \fBParameters\fP .RS 4 \fIlist\fP .RE .PP .SH "Author" .PP Generated automatically by Doxygen for LIBKYSDK-APPLICATIONS from the source code\&. libkysdk-applications/doxygen/man/man3/KCrumb.30000664000175000017500000000047515104543305020343 0ustar fengfeng.TH "KCrumb" 3 "Version version:3.0" "LIBKYSDK-APPLICATIONS" \" -*- nroff -*- .ad l .nh .SH NAME KCrumb \- KCrumb .SH SYNOPSIS .br .PP .SH "Detailed Description" .PP .PP \fBSince\fP .RS 4 2\&.5\&.2\&.0 .RE .PP .SH "Author" .PP Generated automatically by Doxygen for LIBKYSDK-APPLICATIONS from the source code\&. libkysdk-applications/doxygen/man/man3/kdk_KProgressCircle.30000664000175000017500000000553515104543305023054 0ustar fengfeng.TH "kdk::KProgressCircle" 3 "Version version:3.0" "LIBKYSDK-APPLICATIONS" \" -*- nroff -*- .ad l .nh .SH NAME kdk::KProgressCircle \- 以圆环样式显示进度,支持三种状态 .SH SYNOPSIS .br .PP .PP \fC#include \fP .PP Inherits QWidget\&. .SS "Public Slots" .in +1c .ti -1c .RI "void \fBreset\fP ()" .br .ti -1c .RI "void \fBsetRange\fP (int \fBminimum\fP, int \fBmaximum\fP)" .br .ti -1c .RI "void \fBsetMinimum\fP (int \fBminimum\fP)" .br .ti -1c .RI "void \fBsetMaximum\fP (int \fBmaximum\fP)" .br .ti -1c .RI "void \fBsetValue\fP (int \fBvalue\fP)" .br .in -1c .SS "Signals" .in +1c .ti -1c .RI "void \fBvalueChanged\fP (int \fBvalue\fP)" .br .in -1c .SS "Public Member Functions" .in +1c .ti -1c .RI "\fBKProgressCircle\fP (QWidget *parent=nullptr)" .br .ti -1c .RI "int \fBminimum\fP () const" .br .RI "获取KProgressCircle最小值 " .ti -1c .RI "int \fBmaximum\fP () const" .br .RI "获取KProgressCircle最大值 " .ti -1c .RI "int \fBvalue\fP () const" .br .RI "获取当前值 " .ti -1c .RI "QString \fBtext\fP () const" .br .RI "获取文本 " .ti -1c .RI "void \fBsetTextVisible\fP (bool visible)" .br .RI "设置文本是否可见 " .ti -1c .RI "bool \fBisTextVisible\fP () const" .br .RI "返回文本是否可见 " .ti -1c .RI "\fBProgressBarState\fP \fBstate\fP ()" .br .RI "获取当前KProgressCircle状态 " .ti -1c .RI "void \fBsetState\fP (\fBProgressBarState\fP \fBstate\fP)" .br .RI "设置当前KProgressCircle状态 " .in -1c .SS "Protected Member Functions" .in +1c .ti -1c .RI "void \fBpaintEvent\fP (QPaintEvent *) override" .br .in -1c .SH "Detailed Description" .PP 以圆环样式显示进度,支持三种状态 .PP \fBSince\fP .RS 4 1\&.0\&.0 .RE .PP .SH "Member Function Documentation" .PP .SS "bool kdk::KProgressCircle::isTextVisible () const" .PP 返回文本是否可见 .PP \fBReturns\fP .RS 4 bool .RE .PP .SS "int kdk::KProgressCircle::maximum () const" .PP 获取KProgressCircle最大值 .PP \fBReturns\fP .RS 4 int .RE .PP .SS "int kdk::KProgressCircle::minimum () const" .PP 获取KProgressCircle最小值 .PP \fBReturns\fP .RS 4 int .RE .PP .SS "void kdk::KProgressCircle::setState (\fBProgressBarState\fP state)" .PP 设置当前KProgressCircle状态 .PP \fBParameters\fP .RS 4 \fIstate\fP .RE .PP .SS "void kdk::KProgressCircle::setTextVisible (bool visible)" .PP 设置文本是否可见 .PP \fBParameters\fP .RS 4 \fIvisible\fP .RE .PP .SS "\fBProgressBarState\fP kdk::KProgressCircle::state ()" .PP 获取当前KProgressCircle状态 .PP \fBReturns\fP .RS 4 .RE .PP .SS "QString kdk::KProgressCircle::text () const" .PP 获取文本 .PP \fBReturns\fP .RS 4 QString .RE .PP .SS "int kdk::KProgressCircle::value () const" .PP 获取当前值 .PP \fBReturns\fP .RS 4 int .RE .PP .SH "Author" .PP Generated automatically by Doxygen for LIBKYSDK-APPLICATIONS from the source code\&. libkysdk-applications/doxygen/man/man3/LayoutModule.30000664000175000017500000000066415104543305021603 0ustar fengfeng.TH "LayoutModule" 3 "Version version:3.0" "LIBKYSDK-APPLICATIONS" \" -*- nroff -*- .ad l .nh .SH NAME LayoutModule \- LayoutModule .PP \- 存在水平间距、垂直间距的布局 .SH SYNOPSIS .br .PP .SH "Detailed Description" .PP 存在水平间距、垂直间距的布局 .PP \fBSince\fP .RS 4 3\&.0\&.1\&.0 { .RE .PP .SH "Author" .PP Generated automatically by Doxygen for LIBKYSDK-APPLICATIONS from the source code\&. libkysdk-applications/doxygen/man/man3/kdk_KAddFileButton.30000664000175000017500000000375615104543305022615 0ustar fengfeng.TH "kdk::KAddFileButton" 3 "Version version:3.0" "LIBKYSDK-APPLICATIONS" \" -*- nroff -*- .ad l .nh .SH NAME kdk::KAddFileButton \- 选择文件的按钮 .SH SYNOPSIS .br .PP .PP \fC#include \fP .PP Inherits QPushButton\&. .SS "Public Member Functions" .in +1c .ti -1c .RI "\fBKAddFileButton\fP (QWidget *parent=nullptr)" .br .ti -1c .RI "void \fBsetText\fP (QString str)" .br .RI "设置文本 " .ti -1c .RI "QFileDialog * \fBfileDialog\fP ()" .br .RI "获取filedialog " .ti -1c .RI "void \fBsetNameFilter\fP (const QString &filter)" .br .RI "将文件对话框中使用的过滤器设置为给定的过滤器。 " .ti -1c .RI "void \fBsetNameFilters\fP (const QStringList &filters)" .br .RI "设置文件对话框中使用的过滤器。 " .in -1c .SS "Protected Member Functions" .in +1c .ti -1c .RI "void \fBpaintEvent\fP (QPaintEvent *event)" .br .ti -1c .RI "bool \fBeventFilter\fP (QObject *watched, QEvent *event)" .br .ti -1c .RI "void \fBmouseMoveEvent\fP (QMouseEvent *event)" .br .ti -1c .RI "void \fBmousePressEvent\fP (QMouseEvent *event)" .br .ti -1c .RI "void \fBmouseReleaseEvent\fP (QMouseEvent *event)" .br .in -1c .SH "Detailed Description" .PP 选择文件的按钮 .PP \fBSince\fP .RS 4 2\&.4\&.1\&.0 .RE .PP .SH "Member Function Documentation" .PP .SS "QFileDialog * kdk::KAddFileButton::fileDialog ()" .PP 获取filedialog .PP \fBReturns\fP .RS 4 QFileDialog .RE .PP .SS "void kdk::KAddFileButton::setNameFilter (const QString & filter)" .PP 将文件对话框中使用的过滤器设置为给定的过滤器。 .PP \fBParameters\fP .RS 4 \fIfilter\fP .RE .PP .SS "void kdk::KAddFileButton::setNameFilters (const QStringList & filters)" .PP 设置文件对话框中使用的过滤器。 .PP \fBParameters\fP .RS 4 \fIfilters\fP .RE .PP .SS "void kdk::KAddFileButton::setText (QString str)" .PP 设置文本 .PP \fBParameters\fP .RS 4 \fIstr\fP .RE .PP .SH "Author" .PP Generated automatically by Doxygen for LIBKYSDK-APPLICATIONS from the source code\&. libkysdk-applications/doxygen/man/man3/kdk_KLunarDateEdit.30000664000175000017500000000212215104543305022600 0ustar fengfeng.TH "kdk::KLunarDateEdit" 3 "Version version:3.0" "LIBKYSDK-APPLICATIONS" \" -*- nroff -*- .ad l .nh .SH NAME kdk::KLunarDateEdit .SH SYNOPSIS .br .PP .PP Inherits QWidget\&. .SS "Signals" .in +1c .ti -1c .RI "void \fBdateChanged\fP (QDate)" .br .in -1c .SS "Public Member Functions" .in +1c .ti -1c .RI "\fBKLunarDateEdit\fP (QWidget *parent=nullptr)" .br .ti -1c .RI "void \fBsetShowLunar\fP (bool showLunar)" .br .RI "是否显示农历 " .ti -1c .RI "QDateTimeEdit * \fBgetDateEdit\fP ()" .br .RI "获取控件中的DateEdit控件 " .in -1c .SS "Protected Member Functions" .in +1c .ti -1c .RI "void \fBresizeEvent\fP (QResizeEvent *event)" .br .in -1c .SH "Member Function Documentation" .PP .SS "QDateTimeEdit * kdk::KLunarDateEdit::getDateEdit ()" .PP 获取控件中的DateEdit控件 .PP \fBReturns\fP .RS 4 .RE .PP .SS "void kdk::KLunarDateEdit::setShowLunar (bool showLunar)" .PP 是否显示农历 .PP \fBParameters\fP .RS 4 \fIshowLunar:true显示,false不显示\fP .RE .PP .SH "Author" .PP Generated automatically by Doxygen for LIBKYSDK-APPLICATIONS from the source code\&. libkysdk-applications/doxygen/man/man3/kdk_KListViewDelegate.30000664000175000017500000000212515104543305023317 0ustar fengfeng.TH "kdk::KListViewDelegate" 3 "Version version:3.0" "LIBKYSDK-APPLICATIONS" \" -*- nroff -*- .ad l .nh .SH NAME kdk::KListViewDelegate \- 配合KListview可以提供一个图片两行文字的显示效果,若只有一行文字,则对于 icon 居中显示 。 .SH SYNOPSIS .br .PP .PP \fC#include \fP .PP Inherits QStyledItemDelegate, and ThemeController\&. .SS "Public Member Functions" .in +1c .ti -1c .RI "\fBKListViewDelegate\fP (QAbstractItemView *parent)" .br .in -1c .SS "Protected Member Functions" .in +1c .ti -1c .RI "void \fBpaint\fP (QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override" .br .ti -1c .RI "virtual QSize \fBsizeHint\fP (const QStyleOptionViewItem &option, const QModelIndex &index) const" .br .in -1c .SH "Detailed Description" .PP 配合KListview可以提供一个图片两行文字的显示效果,若只有一行文字,则对于 icon 居中显示 。 .PP \fBSince\fP .RS 4 1\&.2\&.0 .RE .PP .SH "Author" .PP Generated automatically by Doxygen for LIBKYSDK-APPLICATIONS from the source code\&. libkysdk-applications/doxygen/man/man3/kdk_KTitleWindow.30000664000175000017500000000315015104543305022366 0ustar fengfeng.TH "kdk::KTitleWindow" 3 "Version version:3.0" "LIBKYSDK-APPLICATIONS" \" -*- nroff -*- .ad l .nh .SH NAME kdk::KTitleWindow .SH SYNOPSIS .br .PP .PP Inherits QWidget\&. .SS "Public Member Functions" .in +1c .ti -1c .RI "\fBKTitleWindow\fP (QWidget *parent=nullptr)" .br .ti -1c .RI "\fBKPushButton\fP * \fBaddButton\fP ()" .br .RI "获取添加按钮 " .ti -1c .RI "QPushButton * \fBcolorButton\fP ()" .br .RI "获取颜色按钮 " .ti -1c .RI "QPushButton * \fBmenuButton\fP ()" .br .RI "获取menu按钮 " .ti -1c .RI "QWidget * \fBbaseWidget\fP ()" .br .RI "获取widget " .ti -1c .RI "void \fBsetTitleColor\fP (QColor color)" .br .RI "设置标题颜色 " .in -1c .SS "Protected Member Functions" .in +1c .ti -1c .RI "void \fBresizeEvent\fP (QResizeEvent *event)" .br .ti -1c .RI "void \fBpaintEvent\fP (QPaintEvent *event)" .br .ti -1c .RI "bool \fBeventFilter\fP (QObject *watched, QEvent *event)" .br .in -1c .SH "Member Function Documentation" .PP .SS "\fBKPushButton\fP * kdk::KTitleWindow::addButton ()" .PP 获取添加按钮 .PP \fBReturns\fP .RS 4 .RE .PP .SS "QWidget * kdk::KTitleWindow::baseWidget ()" .PP 获取widget .PP \fBReturns\fP .RS 4 .RE .PP .SS "QPushButton * kdk::KTitleWindow::colorButton ()" .PP 获取颜色按钮 .PP \fBReturns\fP .RS 4 .RE .PP .SS "QPushButton * kdk::KTitleWindow::menuButton ()" .PP 获取menu按钮 .PP \fBReturns\fP .RS 4 .RE .PP .SS "void kdk::KTitleWindow::setTitleColor (QColor color)" .PP 设置标题颜色 .PP \fBParameters\fP .RS 4 \fIcolor\fP .RE .PP .SH "Author" .PP Generated automatically by Doxygen for LIBKYSDK-APPLICATIONS from the source code\&. libkysdk-applications/doxygen/man/man3/Label.30000664000175000017500000000042515104543305020172 0ustar fengfeng.TH "Label" 3 "Thu Nov 14 2024" "Version version:2.3" "LIBKYSDK-APPLICATIONS" \" -*- nroff -*- .ad l .nh .SH NAME Label .SH SYNOPSIS .br .PP .SH "Detailed Description" .PP .SH "Author" .PP Generated automatically by Doxygen for LIBKYSDK-APPLICATIONS from the source code\&. libkysdk-applications/doxygen/man/man3/kdk_KFileWidget.30000664000175000017500000000376715104543305022156 0ustar fengfeng.TH "kdk::KFileWidget" 3 "Version version:3.0" "LIBKYSDK-APPLICATIONS" \" -*- nroff -*- .ad l .nh .SH NAME kdk::KFileWidget \- The \fBKFileWidget\fP class\&. .SH SYNOPSIS .br .PP .PP \fC#include \fP .PP Inherits QWidget\&. .SS "Signals" .in +1c .ti -1c .RI "void \fBclicked\fP ()" .br .in -1c .SS "Public Member Functions" .in +1c .ti -1c .RI "\fBKFileWidget\fP (QWidget *parent=nullptr)" .br .ti -1c .RI "void \fBsetMainText\fP (QString str)" .br .RI "设置主要文本 " .ti -1c .RI "void \fBsetSubText\fP (QString str)" .br .RI "设置次级文本 " .ti -1c .RI "void \fBsetIcon\fP (QIcon icon)" .br .RI "设置图片 " .ti -1c .RI "void \fBsetBorderRadius\fP (int radius)" .br .RI "设置圆角 " .ti -1c .RI "void \fBsetBorderRadius\fP (int bottomLeft, int topLeft, int topRight, int bottomRight)" .br .RI "设置圆角 " .in -1c .SS "Protected Member Functions" .in +1c .ti -1c .RI "void \fBpaintEvent\fP (QPaintEvent *event)" .br .ti -1c .RI "bool \fBeventFilter\fP (QObject *watched, QEvent *event)" .br .in -1c .SH "Detailed Description" .PP The \fBKFileWidget\fP class\&. .PP \fBSince\fP .RS 4 2\&.4\&.1\&.0 .RE .PP .SH "Member Function Documentation" .PP .SS "void kdk::KFileWidget::setBorderRadius (int bottomLeft, int topLeft, int topRight, int bottomRight)" .PP 设置圆角 .PP \fBParameters\fP .RS 4 \fIbottomLeft\fP .br \fItopLeft\fP .br \fItopRight\fP .br \fIbottomRight\fP .RE .PP .SS "void kdk::KFileWidget::setBorderRadius (int radius)" .PP 设置圆角 .PP \fBParameters\fP .RS 4 \fIradius\fP .RE .PP .SS "void kdk::KFileWidget::setIcon (QIcon icon)" .PP 设置图片 .PP \fBParameters\fP .RS 4 \fIicon\fP .RE .PP .SS "void kdk::KFileWidget::setMainText (QString str)" .PP 设置主要文本 .PP \fBParameters\fP .RS 4 \fIstr\fP .RE .PP .SS "void kdk::KFileWidget::setSubText (QString str)" .PP 设置次级文本 .PP \fBParameters\fP .RS 4 \fIstr\fP .RE .PP .SH "Author" .PP Generated automatically by Doxygen for LIBKYSDK-APPLICATIONS from the source code\&. libkysdk-applications/doxygen/man/man3/DialogBoxModule.30000664000175000017500000010035215104543305022171 0ustar fengfeng.TH "DialogBoxModule" 3 "Version version:3.0" "LIBKYSDK-APPLICATIONS" \" -*- nroff -*- .ad l .nh .SH NAME DialogBoxModule \- DialogBoxModule .SH SYNOPSIS .br .PP .SS "Classes" .in +1c .ti -1c .RI "class \fBkdk::KAboutDialog\fP" .br .RI "关于对话框,支持两种样式,一种是无特定说明的,另一种是有特定说明的。 " .ti -1c .RI "class \fBkdk::KDialog\fP" .br .RI "继承自 QDialog,支持响应式主题背景切换和图标主题切换、 标题颜色响应窗口激活状态 " .ti -1c .RI "class \fBkdk::KInputDialog\fP" .br .RI "输入对话框,接口与 QInputDialog 相同。 " .ti -1c .RI "class \fBkdk::KProgressDialog\fP" .br .RI "进度对话框,会实时显示当前进度 " .ti -1c .RI "class \fBkdk::KUninstallDialog\fP" .br .RI "卸载对话框,当用户卸载时可能会弹出此提示对话框 " .in -1c .SS "Enumerations" .in +1c .ti -1c .RI "enum \fBInputDialogOption\fP { \fBNoButtons\fP = 0x00000001, \fBUseListViewForComboBoxItems\fP = 0x00000002, \fBUsePlainTextEditForTextInput\fP = 0x00000004 }" .br .ti -1c .RI "enum \fBInputMode\fP { \fBTextInput\fP, \fBIntInput\fP, \fBDoubleInput\fP }" .br .ti -1c .RI "enum \fBkdk::BarType\fP { \fBScrollBar\fP, \fBNothingBar\fP, \fBNormalBar\fP, \fBSpeedBar\fP }" .br .RI "支持三种样式 " .in -1c .SS "Functions" .in +1c .ti -1c .RI "\fBkdk::KAboutDialog::KAboutDialog\fP (QWidget *parent=nullptr, const QIcon &appIcon=QIcon(), const QString &\fBappName\fP='', const QString &\fBappVersion\fP='', const QString &appInfo='')" .br .ti -1c .RI "void \fBkdk::KAboutDialog::setAppIcon\fP (const QIcon &icon)" .br .RI "设置应用程序图标 " .ti -1c .RI "void \fBkdk::KAboutDialog::setAppName\fP (const QString &\fBappName\fP)" .br .RI "设置应用程序名称 " .ti -1c .RI "QString \fBkdk::KAboutDialog::appName\fP ()" .br .RI "获取应用程序名称 " .ti -1c .RI "void \fBkdk::KAboutDialog::setAppVersion\fP (const QString &\fBappVersion\fP)" .br .RI "设置应用程序版本号 " .ti -1c .RI "QString \fBkdk::KAboutDialog::appVersion\fP ()" .br .RI "获取应用程序版本号 " .ti -1c .RI "void \fBkdk::KAboutDialog::setBodyText\fP (const QString &\fBbodyText\fP)" .br .RI "设置具体的说明内容 " .ti -1c .RI "QString \fBkdk::KAboutDialog::bodyText\fP ()" .br .RI "获取具体的说明内容 " .ti -1c .RI "void \fBkdk::KAboutDialog::setAppSupport\fP (const QString &\fBappSupport\fP)" .br .RI "设置服务与支持邮箱,有默认缺省 " .ti -1c .RI "QString \fBkdk::KAboutDialog::appSupport\fP ()" .br .RI "获取服务与支持邮箱 " .ti -1c .RI "void \fBkdk::KAboutDialog::setBodyTextVisiable\fP (bool flag)" .br .RI "设置是否显示说明内容,应设计要求,1\&.2\&.0\&.9中不再显示说明内容 " .ti -1c .RI "void \fBkdk::KAboutDialog::setAppPrivacyLabelVisible\fP (bool flag)" .br .RI "设置隐私按钮是否可见 " .ti -1c .RI "bool \fBkdk::KAboutDialog::AppPrivacyLabelIsVisible\fP ()" .br .RI "返回隐私按钮是否可见 " .ti -1c .RI "void \fBkdk::KAboutDialog::changeTheme\fP () override" .br .ti -1c .RI "void \fBkdk::KAboutDialog::paintEvent\fP (QPaintEvent *paintEvent) override" .br .ti -1c .RI "\fBkdk::KDialog::KDialog\fP (QWidget *parent=nullptr)" .br .ti -1c .RI "void \fBkdk::KDialog::setWindowIcon\fP (const QIcon &icon)" .br .RI "设置对话框图标 " .ti -1c .RI "void \fBkdk::KDialog::setWindowIcon\fP (const QString &iconName)" .br .RI "设置对话框图标 " .ti -1c .RI "void \fBkdk::KDialog::setWindowTitle\fP (const QString &)" .br .RI "设置对话框标题名称 " .ti -1c .RI "QPushButton * \fBkdk::KDialog::maximumButton\fP ()" .br .RI "获取最大化按钮 " .ti -1c .RI "QPushButton * \fBkdk::KDialog::minimumButton\fP ()" .br .RI "获取最小化按钮 " .ti -1c .RI "QPushButton * \fBkdk::KDialog::closeButton\fP ()" .br .RI "获取关闭按钮 " .ti -1c .RI "\fBKMenuButton\fP * \fBkdk::KDialog::menuButton\fP ()" .br .RI "获取下拉菜单按钮 " .ti -1c .RI "QWidget * \fBkdk::KDialog::mainWidget\fP ()" .br .RI "获取主内容区Widget " .ti -1c .RI "\fBKWindowButtonBar\fP * \fBkdk::KDialog::windowButtonBar\fP ()" .br .RI "windowButtonBar " .ti -1c .RI "\fBKIconBar\fP * \fBkdk::KDialog::iconBar\fP ()" .br .RI "iconBar " .ti -1c .RI "bool \fBkdk::KDialog::eventFilter\fP (QObject *target, QEvent *event) override" .br .ti -1c .RI "void \fBkdk::KDialog::changeTheme\fP ()" .br .ti -1c .RI "void \fBkdk::KDialog::changeIconStyle\fP ()" .br .ti -1c .RI "QBoxLayout * \fBkdk::KDialog::mainLayout\fP ()" .br .ti -1c .RI "\fBkdk::KInputDialog::KInputDialog\fP (QWidget *parent=nullptr)" .br .ti -1c .RI "void \fBkdk::KInputDialog::setInputMode\fP (InputMode mode)" .br .RI "设置输入模式 " .ti -1c .RI "InputMode \fBkdk::KInputDialog::inputMode\fP () const" .br .RI "返回输入模式 " .ti -1c .RI "void \fBkdk::KInputDialog::setLabelText\fP (const QString &text)" .br .RI "设置提示信息 " .ti -1c .RI "QString \fBkdk::KInputDialog::labelText\fP () const" .br .RI "获取提示信息 " .ti -1c .RI "void \fBkdk::KInputDialog::setOption\fP (InputDialogOption option, bool on=true)" .br .RI "设置option类型 " .ti -1c .RI "bool \fBkdk::KInputDialog::testOption\fP (InputDialogOption option) const" .br .RI "返回是否设置了option类型 " .ti -1c .RI "void \fBkdk::KInputDialog::setOptions\fP (InputDialogOptions \fBoptions\fP)" .br .RI "设置options类型 " .ti -1c .RI "InputDialogOptions \fBkdk::KInputDialog::options\fP () const" .br .RI "返回options类型 " .ti -1c .RI "void \fBkdk::KInputDialog::setTextValue\fP (const QString &text)" .br .RI "设置文本值 " .ti -1c .RI "QString \fBkdk::KInputDialog::textValue\fP () const" .br .RI "获取当前文本值 " .ti -1c .RI "void \fBkdk::KInputDialog::setTextEchoMode\fP (QLineEdit::EchoMode mode)" .br .RI "设置保存文本值的回声模式 QLineEdit::EchoMode " .ti -1c .RI "QLineEdit::EchoMode \fBkdk::KInputDialog::textEchoMode\fP () const" .br .RI "返回保存文本值的回声模式 " .ti -1c .RI "void \fBkdk::KInputDialog::setComboBoxEditable\fP (bool editable)" .br .RI "设置输入对话框中使用的组合框是否可编辑 " .ti -1c .RI "bool \fBkdk::KInputDialog::isComboBoxEditable\fP () const" .br .RI "返回输入对话框中使用的组合框是否可编辑 " .ti -1c .RI "void \fBkdk::KInputDialog::setComboBoxItems\fP (const QStringList &items)" .br .RI "设置输入对话框组合框中使用的项目 " .ti -1c .RI "QStringList \fBkdk::KInputDialog::comboBoxItems\fP () const" .br .RI "返回输入对话框组合框中使用的项目 " .ti -1c .RI "void \fBkdk::KInputDialog::setIntValue\fP (int value)" .br .RI "设置int类型值 " .ti -1c .RI "int \fBkdk::KInputDialog::intValue\fP () const" .br .RI "获取int类型值 " .ti -1c .RI "void \fBkdk::KInputDialog::setIntMinimum\fP (int min)" .br .RI "设置int类型最小值 " .ti -1c .RI "int \fBkdk::KInputDialog::intMinimum\fP () const" .br .RI "获取int类型最小值 " .ti -1c .RI "void \fBkdk::KInputDialog::setIntMaximum\fP (int max)" .br .RI "设置int类型最大值 " .ti -1c .RI "int \fBkdk::KInputDialog::intMaximum\fP () const" .br .RI "获取int类型最大值 " .ti -1c .RI "void \fBkdk::KInputDialog::setIntRange\fP (int min, int max)" .br .RI "设置int类型值范围 " .ti -1c .RI "void \fBkdk::KInputDialog::setIntStep\fP (int step)" .br .RI "设置步长 " .ti -1c .RI "int \fBkdk::KInputDialog::intStep\fP () const" .br .RI "获取int类型步长 " .ti -1c .RI "void \fBkdk::KInputDialog::setDoubleValue\fP (double value)" .br .RI "设置double类型值 " .ti -1c .RI "double \fBkdk::KInputDialog::doubleValue\fP () const" .br .RI "获取double类型值 " .ti -1c .RI "void \fBkdk::KInputDialog::setDoubleMinimum\fP (double min)" .br .RI "设置double类型最小值 " .ti -1c .RI "double \fBkdk::KInputDialog::doubleMinimum\fP () const" .br .RI "获取double类型最小值 " .ti -1c .RI "void \fBkdk::KInputDialog::setDoubleMaximum\fP (double max)" .br .RI "设置double类型最大值 " .ti -1c .RI "double \fBkdk::KInputDialog::doubleMaximum\fP () const" .br .RI "获取double类型最大值 " .ti -1c .RI "void \fBkdk::KInputDialog::setDoubleRange\fP (double min, double max)" .br .RI "设置double类型值范围 " .ti -1c .RI "void \fBkdk::KInputDialog::setDoubleDecimals\fP (int decimals)" .br .RI "以小数为单位设置双自旋盒的精度 " .ti -1c .RI "int \fBkdk::KInputDialog::doubleDecimals\fP () const" .br .RI "获取双自旋盒的精度 " .ti -1c .RI "void \fBkdk::KInputDialog::setOkButtonText\fP (const QString &text)" .br .RI "设置OK按钮的文本 " .ti -1c .RI "QString \fBkdk::KInputDialog::okButtonText\fP () const" .br .RI "获取OK按钮的文本 " .ti -1c .RI "void \fBkdk::KInputDialog::setCancelButtonText\fP (const QString &text)" .br .RI "设置cancel按钮的文本 " .ti -1c .RI "QString \fBkdk::KInputDialog::cancelButtonText\fP () const" .br .RI "获取cancel按钮的文本 " .ti -1c .RI "void \fBkdk::KInputDialog::open\fP (QObject *receiver, const char *member)" .br .RI "将对话框显示为窗口模式对话框,并立即返回。 " .ti -1c .RI "QSize \fBkdk::KInputDialog::minimumSizeHint\fP () const override" .br .RI "获取部件的推荐最小尺寸 " .ti -1c .RI "QSize \fBkdk::KInputDialog::sizeHint\fP () const override" .br .RI "获取保存部件的推荐尺寸 " .ti -1c .RI "void \fBkdk::KInputDialog::setVisible\fP (bool visible) override" .br .RI "设置窗口部件是否可见 " .ti -1c .RI "QString \fBkdk::KInputDialog::placeholderText\fP () const" .br .RI "获取背景提示文本 " .ti -1c .RI "void \fBkdk::KInputDialog::setPlaceholderText\fP (const QString &)" .br .RI "设置背景提示文本 " .ti -1c .RI "static QString \fBkdk::KInputDialog::getText\fP (QWidget *parent, const QString &label, QLineEdit::EchoMode echo=QLineEdit::Normal, const QString &text=QString(), bool *ok=nullptr, Qt::WindowFlags flags=Qt::WindowFlags(), Qt::InputMethodHints inputMethodHints=Qt::ImhNone)" .br .RI "静态便利函数,用于从用户处获取单行字符串。 " .ti -1c .RI "static QString \fBkdk::KInputDialog::getMultiLineText\fP (QWidget *parent, const QString &label, const QString &text=QString(), bool *ok=nullptr, Qt::WindowFlags flags=Qt::WindowFlags(), Qt::InputMethodHints inputMethodHints=Qt::ImhNone)" .br .RI "静态便利函数,用于从用户处获取多行字符串。 " .ti -1c .RI "static QString \fBkdk::KInputDialog::getItem\fP (QWidget *parent, const QString &label, const QStringList &items, int current=0, bool editable=true, bool *ok=nullptr, Qt::WindowFlags flags=Qt::WindowFlags(), Qt::InputMethodHints inputMethodHints=Qt::ImhNone)" .br .RI "静态便利函数,用于让用户从字符串列表中选择一个项目。 " .ti -1c .RI "static int \fBkdk::KInputDialog::getInt\fP (QWidget *parent, const QString &label, int value=0, int minValue=\-2147483647, int maxValue=2147483647, int step=1, bool *ok=nullptr, Qt::WindowFlags flags=Qt::WindowFlags())" .br .RI "静态便利函数,用于从用户处获取整数输入值。 " .ti -1c .RI "static double \fBkdk::KInputDialog::getDouble\fP (QWidget *parent, const QString &label, double value=0, double minValue=\-2147483647, double maxValue=2147483647, int decimals=1, bool *ok=nullptr, Qt::WindowFlags flags=Qt::WindowFlags())" .br .RI "静态便利函数,用于从用户处获取浮点数。 " .ti -1c .RI "void \fBkdk::KInputDialog::setDoubleStep\fP (double step)" .br .RI "设置doubel类型步长 " .ti -1c .RI "double \fBkdk::KInputDialog::doubleStep\fP () const" .br .RI "获取doubel类型步长 " .ti -1c .RI "void \fBkdk::KInputDialog::done\fP (int result) override" .br .ti -1c .RI "void \fBkdk::KInputDialog::changeTheme\fP ()" .br .ti -1c .RI "\fBkdk::KProgressDialog::KProgressDialog\fP (QWidget *parent=nullptr)" .br .ti -1c .RI "\fBkdk::KProgressDialog::KProgressDialog\fP (const QString &\fBlabelText\fP, const QString &cancelButtonText='cancel', int \fBminimum\fP=0, int \fBmaximum\fP=100, QWidget *parent=nullptr)" .br .ti -1c .RI "void \fBkdk::KProgressDialog::setLabel\fP (QLabel *label)" .br .RI "设置提示文字 " .ti -1c .RI "void \fBkdk::KProgressDialog::setCancelButton\fP (QPushButton *button)" .br .RI "设置取消按钮 " .ti -1c .RI "void \fBkdk::KProgressDialog::setBar\fP (QProgressBar *bar)" .br .RI "设置进度条 " .ti -1c .RI "void \fBkdk::KProgressDialog::setSuffix\fP (const QString &suffix)" .br .RI "设置detail的后缀 " .ti -1c .RI "void \fBkdk::KProgressDialog::setSuffix\fP (const QString &numerator, const QString &denominator)" .br .ti -1c .RI "void \fBkdk::KProgressDialog::setSpeed\fP (const float &speed)" .br .ti -1c .RI "void \fBkdk::KProgressDialog::setShowDetail\fP (bool flag)" .br .RI "设置是否显示详细信息 " .ti -1c .RI "int \fBkdk::KProgressDialog::minimum\fP () const" .br .RI "返回最小值 " .ti -1c .RI "int \fBkdk::KProgressDialog::maximum\fP () const" .br .RI "返回最大值 " .ti -1c .RI "int \fBkdk::KProgressDialog::value\fP () const" .br .RI "返回当前值 " .ti -1c .RI "QString \fBkdk::KProgressDialog::labelText\fP () const" .br .RI "返回提示内容 " .ti -1c .RI "void \fBkdk::KProgressDialog::setAutoReset\fP (bool \fBreset\fP)" .br .RI "设置自动重置 " .ti -1c .RI "bool \fBkdk::KProgressDialog::autoReset\fP () const" .br .RI "返回是否自动重置 " .ti -1c .RI "void \fBkdk::KProgressDialog::setAutoClose\fP (bool close)" .br .RI "设置是否自动关闭对话框 " .ti -1c .RI "bool \fBkdk::KProgressDialog::autoClose\fP () const" .br .RI "返回是否自动关闭对话框 " .ti -1c .RI "QProgressBar * \fBkdk::KProgressDialog::progressBar\fP ()" .br .RI "获取进度条 " .ti -1c .RI "void \fBkdk::KProgressDialog::setBarType\fP (const \fBBarType\fP &type)" .br .ti -1c .RI "void \fBkdk::KProgressDialog::addButton\fP (QPushButton *button)" .br .ti -1c .RI "void \fBkdk::KProgressDialog::removeButton\fP (QPushButton *button)" .br .ti -1c .RI "\fBBarType\fP \fBkdk::KProgressDialog::myType\fP ()" .br .ti -1c .RI "void \fBkdk::KProgressDialog::changeTheme\fP ()" .br .ti -1c .RI "\fBkdk::KUninstallDialog::KUninstallDialog\fP (QString appName, QString appVersion, QWidget *parent=nullptr)" .br .ti -1c .RI "QLabel * \fBkdk::KUninstallDialog::debAppNameLabel\fP ()" .br .RI "debAppNameLabel " .ti -1c .RI "QLabel * \fBkdk::KUninstallDialog::debNameLabel\fP ()" .br .RI "包名Label " .ti -1c .RI "QLabel * \fBkdk::KUninstallDialog::debIconLabel\fP ()" .br .RI "包IconLabel " .ti -1c .RI "QLabel * \fBkdk::KUninstallDialog::debVersionLabel\fP ()" .br .RI "包版本Label " .ti -1c .RI "QPushButton * \fBkdk::KUninstallDialog::uninstallButtton\fP ()" .br .RI "卸载按钮 " .ti -1c .RI "void \fBkdk::KUninstallDialog::changeTheme\fP ()" .br .in -1c .SS "Signals" .in +1c .ti -1c .RI "void \fBkdk::KInputDialog::textValueChanged\fP (const QString &text)" .br .ti -1c .RI "void \fBkdk::KInputDialog::textValueSelected\fP (const QString &text)" .br .ti -1c .RI "void \fBkdk::KInputDialog::intValueChanged\fP (int value)" .br .ti -1c .RI "void \fBkdk::KInputDialog::intValueSelected\fP (int value)" .br .ti -1c .RI "void \fBkdk::KInputDialog::doubleValueChanged\fP (double value)" .br .ti -1c .RI "void \fBkdk::KInputDialog::doubleValueSelected\fP (double value)" .br .ti -1c .RI "void \fBkdk::KProgressDialog::canceled\fP ()" .br .in -1c .SS "Public Slots" .in +1c .ti -1c .RI "void \fBkdk::KProgressDialog::cancel\fP ()" .br .RI "取消进度条 " .ti -1c .RI "void \fBkdk::KProgressDialog::reset\fP ()" .br .RI "重置进度条 " .ti -1c .RI "void \fBkdk::KProgressDialog::setMaximum\fP (int \fBmaximum\fP)" .br .RI "设置最大值 " .ti -1c .RI "void \fBkdk::KProgressDialog::setMinimum\fP (int \fBminimum\fP)" .br .RI "设置最小值 " .ti -1c .RI "void \fBkdk::KProgressDialog::setRange\fP (int \fBminimum\fP, int \fBmaximum\fP)" .br .RI "设置范围 " .ti -1c .RI "void \fBkdk::KProgressDialog::setValue\fP (int progress)" .br .RI "设置当前值 " .ti -1c .RI "void \fBkdk::KProgressDialog::setLabelText\fP (const QString &text)" .br .RI "设置提示内容 " .ti -1c .RI "void \fBkdk::KProgressDialog::setCancelButtonText\fP (const QString &text)" .br .RI "设置取消按钮内容 " .ti -1c .RI "void \fBkdk::KProgressDialog::setSubContent\fP (const QString &text)" .br .RI "设置次级内容 " .in -1c .SH "Detailed Description" .PP { .SH "Enumeration Type Documentation" .PP .SS "enum \fBkdk::BarType\fP" .PP 支持三种样式 .PP \fBSince\fP .RS 4 1\&.0\&.0 .RE .PP .SH "Function Documentation" .PP .SS "QString kdk::KAboutDialog::appName ()" .PP 获取应用程序名称 .PP \fBReturns\fP .RS 4 .RE .PP .SS "bool kdk::KAboutDialog::AppPrivacyLabelIsVisible ()" .PP 返回隐私按钮是否可见 .PP \fBReturns\fP .RS 4 .RE .PP \fBSince\fP .RS 4 1\&.2\&.0 .RE .PP .SS "QString kdk::KAboutDialog::appSupport ()" .PP 获取服务与支持邮箱 .PP \fBReturns\fP .RS 4 .RE .PP .SS "QString kdk::KAboutDialog::appVersion ()" .PP 获取应用程序版本号 .PP \fBReturns\fP .RS 4 .RE .PP .SS "bool kdk::KProgressDialog::autoClose () const" .PP 返回是否自动关闭对话框 .PP \fBReturns\fP .RS 4 .RE .PP .SS "bool kdk::KProgressDialog::autoReset () const" .PP 返回是否自动重置 .PP \fBReturns\fP .RS 4 .RE .PP .SS "QString kdk::KAboutDialog::bodyText ()" .PP 获取具体的说明内容 .PP \fBReturns\fP .RS 4 .RE .PP .SS "QString kdk::KInputDialog::cancelButtonText () const" .PP 获取cancel按钮的文本 .PP \fBReturns\fP .RS 4 .RE .PP .SS "QPushButton * kdk::KDialog::closeButton ()" .PP 获取关闭按钮 .PP \fBReturns\fP .RS 4 .RE .PP .SS "QStringList kdk::KInputDialog::comboBoxItems () const" .PP 返回输入对话框组合框中使用的项目 .PP \fBReturns\fP .RS 4 QStringList .RE .PP .SS "QLabel * kdk::KUninstallDialog::debAppNameLabel ()" .PP debAppNameLabel .PP \fBReturns\fP .RS 4 .RE .PP .SS "QLabel * kdk::KUninstallDialog::debIconLabel ()" .PP 包IconLabel .PP \fBReturns\fP .RS 4 .RE .PP .SS "QLabel * kdk::KUninstallDialog::debNameLabel ()" .PP 包名Label .PP \fBReturns\fP .RS 4 .RE .PP .SS "QLabel * kdk::KUninstallDialog::debVersionLabel ()" .PP 包版本Label .PP \fBReturns\fP .RS 4 .RE .PP .SS "int kdk::KInputDialog::doubleDecimals () const" .PP 获取双自旋盒的精度 .PP \fBReturns\fP .RS 4 int .RE .PP .SS "double kdk::KInputDialog::doubleMaximum () const" .PP 获取double类型最大值 .PP \fBReturns\fP .RS 4 double .RE .PP .SS "double kdk::KInputDialog::doubleMinimum () const" .PP 获取double类型最小值 .PP \fBReturns\fP .RS 4 double .RE .PP .SS "double kdk::KInputDialog::doubleStep () const" .PP 获取doubel类型步长 .PP \fBReturns\fP .RS 4 double .RE .PP .SS "double kdk::KInputDialog::doubleValue () const" .PP 获取double类型值 .PP \fBReturns\fP .RS 4 double .RE .PP .SS "static double kdk::KInputDialog::getDouble (QWidget * parent, const QString & label, double value = \fC0\fP, double minValue = \fC\-2147483647\fP, double maxValue = \fC2147483647\fP, int decimals = \fC1\fP, bool * ok = \fCnullptr\fP, Qt::WindowFlags flags = \fCQt::WindowFlags()\fP)\fC [static]\fP" .PP 静态便利函数,用于从用户处获取浮点数。 .PP \fBParameters\fP .RS 4 \fIparent\fP .br \fIlabel\fP .br \fIvalue\fP .br \fIminValue\fP .br \fImaxValue\fP .br \fIdecimals\fP .br \fIok\fP .br \fIflags\fP .RE .PP \fBReturns\fP .RS 4 .RE .PP .SS "static int kdk::KInputDialog::getInt (QWidget * parent, const QString & label, int value = \fC0\fP, int minValue = \fC\-2147483647\fP, int maxValue = \fC2147483647\fP, int step = \fC1\fP, bool * ok = \fCnullptr\fP, Qt::WindowFlags flags = \fCQt::WindowFlags()\fP)\fC [static]\fP" .PP 静态便利函数,用于从用户处获取整数输入值。 .PP \fBParameters\fP .RS 4 \fIparent\fP .br \fIlabel\fP .br \fIvalue\fP .br \fIminValue\fP .br \fImaxValue\fP .br \fIstep\fP .br \fIok\fP .br \fIflags\fP .RE .PP \fBReturns\fP .RS 4 .RE .PP .SS "static QString kdk::KInputDialog::getItem (QWidget * parent, const QString & label, const QStringList & items, int current = \fC0\fP, bool editable = \fCtrue\fP, bool * ok = \fCnullptr\fP, Qt::WindowFlags flags = \fCQt::WindowFlags()\fP, Qt::InputMethodHints inputMethodHints = \fCQt::ImhNone\fP)\fC [static]\fP" .PP 静态便利函数,用于让用户从字符串列表中选择一个项目。 .PP \fBParameters\fP .RS 4 \fIparent\fP .br \fIlabel\fP .br \fIitems\fP .br \fIcurrent\fP .br \fIeditable\fP .br \fIok\fP .br \fIflags\fP .br \fIinputMethodHints\fP .RE .PP \fBReturns\fP .RS 4 .RE .PP .SS "static QString kdk::KInputDialog::getMultiLineText (QWidget * parent, const QString & label, const QString & text = \fCQString()\fP, bool * ok = \fCnullptr\fP, Qt::WindowFlags flags = \fCQt::WindowFlags()\fP, Qt::InputMethodHints inputMethodHints = \fCQt::ImhNone\fP)\fC [static]\fP" .PP 静态便利函数,用于从用户处获取多行字符串。 .PP \fBParameters\fP .RS 4 \fIparent\fP .br \fIlabel\fP .br \fItext\fP .br \fIok\fP .br \fIflags\fP .br \fIinputMethodHints\fP .RE .PP \fBReturns\fP .RS 4 .RE .PP .SS "static QString kdk::KInputDialog::getText (QWidget * parent, const QString & label, QLineEdit::EchoMode echo = \fCQLineEdit::Normal\fP, const QString & text = \fCQString()\fP, bool * ok = \fCnullptr\fP, Qt::WindowFlags flags = \fCQt::WindowFlags()\fP, Qt::InputMethodHints inputMethodHints = \fCQt::ImhNone\fP)\fC [static]\fP" .PP 静态便利函数,用于从用户处获取单行字符串。 .PP \fBParameters\fP .RS 4 \fIparent\fP .br \fIlabel\fP .br \fIecho\fP .br \fItext\fP .br \fIok\fP .br \fIflags\fP .br \fIinputMethodHints\fP .RE .PP \fBReturns\fP .RS 4 .RE .PP .SS "\fBKIconBar\fP * kdk::KDialog::iconBar ()" .PP iconBar .PP \fBReturns\fP .RS 4 @2\&.5\&.2\&.0 .RE .PP .SS "InputMode kdk::KInputDialog::inputMode () const" .PP 返回输入模式 .PP \fBReturns\fP .RS 4 InputMode .RE .PP .SS "int kdk::KInputDialog::intMaximum () const" .PP 获取int类型最大值 .PP \fBReturns\fP .RS 4 int .RE .PP .SS "int kdk::KInputDialog::intMinimum () const" .PP 获取int类型最小值 .PP \fBReturns\fP .RS 4 int .RE .PP .SS "int kdk::KInputDialog::intStep () const" .PP 获取int类型步长 .PP \fBReturns\fP .RS 4 int .RE .PP .SS "int kdk::KInputDialog::intValue () const" .PP 获取int类型值 .PP \fBReturns\fP .RS 4 int .RE .PP .SS "bool kdk::KInputDialog::isComboBoxEditable () const" .PP 返回输入对话框中使用的组合框是否可编辑 .PP \fBReturns\fP .RS 4 bool .RE .PP .SS "QString kdk::KInputDialog::labelText () const" .PP 获取提示信息 .PP \fBReturns\fP .RS 4 QString .RE .PP .SS "QString kdk::KProgressDialog::labelText () const" .PP 返回提示内容 .PP \fBReturns\fP .RS 4 .RE .PP .SS "QWidget * kdk::KDialog::mainWidget ()" .PP 获取主内容区Widget .PP \fBReturns\fP .RS 4 .RE .PP .SS "int kdk::KProgressDialog::maximum () const" .PP 返回最大值 .PP \fBReturns\fP .RS 4 .RE .PP .SS "QPushButton * kdk::KDialog::maximumButton ()" .PP 获取最大化按钮 .PP \fBReturns\fP .RS 4 .RE .PP .SS "\fBKMenuButton\fP * kdk::KDialog::menuButton ()" .PP 获取下拉菜单按钮 .PP \fBReturns\fP .RS 4 .RE .PP .SS "int kdk::KProgressDialog::minimum () const" .PP 返回最小值 .PP \fBReturns\fP .RS 4 .RE .PP .SS "QPushButton * kdk::KDialog::minimumButton ()" .PP 获取最小化按钮 .PP \fBReturns\fP .RS 4 .RE .PP .SS "QSize kdk::KInputDialog::minimumSizeHint () const\fC [override]\fP" .PP 获取部件的推荐最小尺寸 .PP \fBReturns\fP .RS 4 QSize .RE .PP .SS "QString kdk::KInputDialog::okButtonText () const" .PP 获取OK按钮的文本 .PP \fBReturns\fP .RS 4 QString .RE .PP .SS "void kdk::KInputDialog::open (QObject * receiver, const char * member)" .PP 将对话框显示为窗口模式对话框,并立即返回。 .PP \fBParameters\fP .RS 4 \fIreceiver\fP .br \fImember\fP .RE .PP .SS "InputDialogOptions kdk::KInputDialog::options () const" .PP 返回options类型 .PP \fBReturns\fP .RS 4 InputDialogOptions .RE .PP .SS "QString kdk::KInputDialog::placeholderText () const" .PP 获取背景提示文本 .PP \fBReturns\fP .RS 4 .RE .PP \fBSince\fP .RS 4 1\&.2\&.0 .RE .PP .SS "QProgressBar * kdk::KProgressDialog::progressBar ()" .PP 获取进度条 .PP \fBReturns\fP .RS 4 .RE .PP .SS "void kdk::KAboutDialog::setAppIcon (const QIcon & icon)" .PP 设置应用程序图标 .PP \fBParameters\fP .RS 4 \fIicon\fP .RE .PP .SS "void kdk::KAboutDialog::setAppName (const QString & appName)" .PP 设置应用程序名称 .PP \fBParameters\fP .RS 4 \fIappName\fP .RE .PP .SS "void kdk::KAboutDialog::setAppPrivacyLabelVisible (bool flag)" .PP 设置隐私按钮是否可见 .PP \fBParameters\fP .RS 4 \fIflag\fP .RE .PP \fBSince\fP .RS 4 1\&.2\&.0 .RE .PP .SS "void kdk::KAboutDialog::setAppSupport (const QString & appSupport)" .PP 设置服务与支持邮箱,有默认缺省 .PP \fBParameters\fP .RS 4 \fIappSupport\fP .RE .PP .SS "void kdk::KAboutDialog::setAppVersion (const QString & appVersion)" .PP 设置应用程序版本号 .PP \fBParameters\fP .RS 4 \fIappVersion\fP .RE .PP .SS "void kdk::KProgressDialog::setAutoClose (bool close)" .PP 设置是否自动关闭对话框 .PP \fBParameters\fP .RS 4 \fIclose\fP .RE .PP .SS "void kdk::KProgressDialog::setAutoReset (bool reset)" .PP 设置自动重置 .PP \fBParameters\fP .RS 4 \fIreset\fP .RE .PP .PP \fBExamples\fP .in +1c \fBtestprogressdialog/widget\&.cpp\fP\&. .SS "void kdk::KProgressDialog::setBar (QProgressBar * bar)" .PP 设置进度条 .PP \fBParameters\fP .RS 4 \fIbar\fP .RE .PP .SS "void kdk::KAboutDialog::setBodyText (const QString & bodyText)" .PP 设置具体的说明内容 .PP \fBParameters\fP .RS 4 \fIbodyText\fP .RE .PP .SS "void kdk::KAboutDialog::setBodyTextVisiable (bool flag)" .PP 设置是否显示说明内容,应设计要求,1\&.2\&.0\&.9中不再显示说明内容 .PP \fBParameters\fP .RS 4 \fIflag\fP .RE .PP .SS "void kdk::KProgressDialog::setCancelButton (QPushButton * button)" .PP 设置取消按钮 .PP \fBParameters\fP .RS 4 \fIbutton\fP .RE .PP .SS "void kdk::KInputDialog::setCancelButtonText (const QString & text)" .PP 设置cancel按钮的文本 .PP \fBParameters\fP .RS 4 \fItext\fP .RE .PP .SS "void kdk::KInputDialog::setComboBoxEditable (bool editable)" .PP 设置输入对话框中使用的组合框是否可编辑 .PP \fBParameters\fP .RS 4 \fIeditable\fP .RE .PP .SS "void kdk::KInputDialog::setComboBoxItems (const QStringList & items)" .PP 设置输入对话框组合框中使用的项目 .PP \fBParameters\fP .RS 4 \fIitems\fP .RE .PP .SS "void kdk::KInputDialog::setDoubleDecimals (int decimals)" .PP 以小数为单位设置双自旋盒的精度 .PP \fBParameters\fP .RS 4 \fIdecimals\fP .RE .PP .SS "void kdk::KInputDialog::setDoubleMaximum (double max)" .PP 设置double类型最大值 .PP \fBParameters\fP .RS 4 \fImax\fP .RE .PP .SS "void kdk::KInputDialog::setDoubleMinimum (double min)" .PP 设置double类型最小值 .PP \fBParameters\fP .RS 4 \fImin\fP .RE .PP .SS "void kdk::KInputDialog::setDoubleRange (double min, double max)" .PP 设置double类型值范围 .PP \fBParameters\fP .RS 4 \fImin\fP .br \fImax\fP .RE .PP .SS "void kdk::KInputDialog::setDoubleStep (double step)" .PP 设置doubel类型步长 .PP \fBParameters\fP .RS 4 \fIstep\fP .RE .PP .SS "void kdk::KInputDialog::setDoubleValue (double value)" .PP 设置double类型值 .PP \fBParameters\fP .RS 4 \fIvalue\fP .RE .PP .SS "void kdk::KInputDialog::setInputMode (InputMode mode)" .PP 设置输入模式 .PP \fBParameters\fP .RS 4 \fImode\fP .RE .PP .SS "void kdk::KInputDialog::setIntMaximum (int max)" .PP 设置int类型最大值 .PP \fBParameters\fP .RS 4 \fImax\fP .RE .PP .SS "void kdk::KInputDialog::setIntMinimum (int min)" .PP 设置int类型最小值 .PP \fBParameters\fP .RS 4 \fImin\fP .RE .PP .SS "void kdk::KInputDialog::setIntRange (int min, int max)" .PP 设置int类型值范围 .PP \fBParameters\fP .RS 4 \fImin\fP .br \fImax\fP .RE .PP .SS "void kdk::KInputDialog::setIntStep (int step)" .PP 设置步长 .PP \fBParameters\fP .RS 4 \fIstep\fP .RE .PP .SS "void kdk::KInputDialog::setIntValue (int value)" .PP 设置int类型值 .PP \fBParameters\fP .RS 4 \fIvalue\fP .RE .PP .SS "void kdk::KProgressDialog::setLabel (QLabel * label)" .PP 设置提示文字 .PP \fBParameters\fP .RS 4 \fIlabel\fP .RE .PP .SS "void kdk::KInputDialog::setLabelText (const QString & text)" .PP 设置提示信息 .PP \fBParameters\fP .RS 4 \fItext\fP .RE .PP .SS "void kdk::KInputDialog::setOkButtonText (const QString & text)" .PP 设置OK按钮的文本 .PP \fBParameters\fP .RS 4 \fItext\fP .RE .PP .SS "void kdk::KInputDialog::setOption (InputDialogOption option, bool on = \fCtrue\fP)" .PP 设置option类型 .PP \fBParameters\fP .RS 4 \fIoption\fP .br \fIon\fP .RE .PP .SS "void kdk::KInputDialog::setOptions (InputDialogOptions options)" .PP 设置options类型 .PP \fBParameters\fP .RS 4 \fIoptions\fP .RE .PP .SS "void kdk::KInputDialog::setPlaceholderText (const QString &)" .PP 设置背景提示文本 .PP \fBSince\fP .RS 4 1\&.2\&.0 .RE .PP .SS "void kdk::KProgressDialog::setShowDetail (bool flag)" .PP 设置是否显示详细信息 .PP \fBParameters\fP .RS 4 \fIflag\fP .RE .PP .PP \fBExamples\fP .in +1c \fBtestprogressdialog/widget\&.cpp\fP\&. .SS "void kdk::KProgressDialog::setSuffix (const QString & suffix)" .PP 设置detail的后缀 .PP \fBParameters\fP .RS 4 \fIsuffix\fP .RE .PP .PP \fBExamples\fP .in +1c \fBtestprogressdialog/widget\&.cpp\fP\&. .SS "void kdk::KInputDialog::setTextEchoMode (QLineEdit::EchoMode mode)" .PP 设置保存文本值的回声模式 QLineEdit::EchoMode .PP \fBParameters\fP .RS 4 \fImode\fP .RE .PP .SS "void kdk::KInputDialog::setTextValue (const QString & text)" .PP 设置文本值 .PP \fBParameters\fP .RS 4 \fItext\fP .RE .PP .SS "void kdk::KInputDialog::setVisible (bool visible)\fC [override]\fP" .PP 设置窗口部件是否可见 .PP \fBParameters\fP .RS 4 \fIvisible\fP .RE .PP .SS "void kdk::KDialog::setWindowIcon (const QIcon & icon)" .PP 设置对话框图标 .PP \fBParameters\fP .RS 4 \fIicon\fP .RE .PP .PP \fBExamples\fP .in +1c \fBtestprogressdialog/widget\&.cpp\fP\&. .SS "void kdk::KDialog::setWindowIcon (const QString & iconName)" .PP 设置对话框图标 .PP \fBParameters\fP .RS 4 \fIiconName\fP .RE .PP .SS "void kdk::KDialog::setWindowTitle (const QString &)" .PP 设置对话框标题名称 .PP \fBParameters\fP .RS 4 \fIwidgetName\fP .RE .PP .PP \fBExamples\fP .in +1c \fBtestprogressdialog/widget\&.cpp\fP\&. .SS "QSize kdk::KInputDialog::sizeHint () const\fC [override]\fP" .PP 获取保存部件的推荐尺寸 .PP \fBReturns\fP .RS 4 .RE .PP .SS "bool kdk::KInputDialog::testOption (InputDialogOption option) const" .PP 返回是否设置了option类型 .PP \fBParameters\fP .RS 4 \fIoption\fP .RE .PP \fBReturns\fP .RS 4 bool .RE .PP .SS "QLineEdit::EchoMode kdk::KInputDialog::textEchoMode () const" .PP 返回保存文本值的回声模式 .PP \fBReturns\fP .RS 4 QLineEdit::EchoMode .RE .PP .SS "QString kdk::KInputDialog::textValue () const" .PP 获取当前文本值 .PP \fBReturns\fP .RS 4 QString .RE .PP .SS "QPushButton * kdk::KUninstallDialog::uninstallButtton ()" .PP 卸载按钮 .PP \fBReturns\fP .RS 4 .RE .PP .SS "int kdk::KProgressDialog::value () const" .PP 返回当前值 .PP \fBReturns\fP .RS 4 .RE .PP .SS "\fBKWindowButtonBar\fP * kdk::KDialog::windowButtonBar ()" .PP windowButtonBar .PP \fBReturns\fP .RS 4 @2\&.5\&.2\&.0 .RE .PP .SH "Public Slots" .PP .SS "void kdk::KProgressDialog::setCancelButtonText (const QString & text)\fC [slot]\fP" .PP 设置取消按钮内容 .PP \fBParameters\fP .RS 4 \fItext\fP .RE .PP .SS "void kdk::KProgressDialog::setLabelText (const QString & text)\fC [slot]\fP" .PP 设置提示内容 .PP \fBParameters\fP .RS 4 \fItext\fP .RE .PP .SS "void kdk::KProgressDialog::setMaximum (int maximum)\fC [slot]\fP" .PP 设置最大值 .PP \fBParameters\fP .RS 4 \fImaximum\fP .RE .PP .SS "void kdk::KProgressDialog::setMinimum (int minimum)\fC [slot]\fP" .PP 设置最小值 .PP \fBParameters\fP .RS 4 \fIminimum\fP .RE .PP .SS "void kdk::KProgressDialog::setRange (int minimum, int maximum)\fC [slot]\fP" .PP 设置范围 .PP \fBParameters\fP .RS 4 \fIminimum\fP .br \fImaximum\fP .RE .PP .SS "void kdk::KProgressDialog::setSubContent (const QString & text)\fC [slot]\fP" .PP 设置次级内容 .PP \fBParameters\fP .RS 4 \fItext\fP .RE .PP .PP \fBExamples\fP .in +1c \fBtestprogressdialog/widget\&.cpp\fP\&. .SS "void kdk::KProgressDialog::setValue (int progress)\fC [slot]\fP" .PP 设置当前值 .PP \fBParameters\fP .RS 4 \fIprogress\fP .RE .PP .PP \fBExamples\fP .in +1c \fBtestprogressdialog/widget\&.cpp\fP\&. .SH "Author" .PP Generated automatically by Doxygen for LIBKYSDK-APPLICATIONS from the source code\&. libkysdk-applications/doxygen/man/man3/BarModule.30000664000175000017500000004415115104543305021031 0ustar fengfeng.TH "BarModule" 3 "Version version:3.0" "LIBKYSDK-APPLICATIONS" \" -*- nroff -*- .ad l .nh .SH NAME BarModule \- BarModule .PP \- 支持三种样式 .SH SYNOPSIS .br .PP .SS "Classes" .in +1c .ti -1c .RI "class \fBkdk::KArrowTabBar\fP" .br .RI "可显示箭头的tabbar " .ti -1c .RI "class \fBkdk::KIconBar\fP" .br .RI "图标和标题组合控件 " .ti -1c .RI "class \fBkdk::KNavigationBar\fP" .br .RI "导航栏控件 " .ti -1c .RI "class \fBkdk::KPixmapContainer\fP" .br .RI "为指定的pixmap添加右上角消息提示气泡,样式类似微信头像的消息提示 " .ti -1c .RI "class \fBkdk::KProgressBar\fP" .br .RI "进度条,支持三种状态显示 " .ti -1c .RI "class \fBkdk::KTabBar\fP" .br .RI "支持三种样式 " .ti -1c .RI "class \fBkdk::KWindowButtonBar\fP" .br .RI "窗口三联按钮和菜单按钮的集合 " .in -1c .SS "Enumerations" .in +1c .ti -1c .RI "enum \fBNavigationBarDataType\fP { \fBValueRole\fP = Qt::UserRole + 1, \fBStringRole\fP = Qt::UserRole + 2, \fBboolRole\fP = Qt::UserRole + 3 }" .br .ti -1c .RI "enum \fBkdk::ProgressBarState\fP { \fBNormalProgress\fP, \fBFailedProgress\fP, \fBSuccessProgress\fP }" .br .RI "支持三种状态 " .ti -1c .RI "enum \fBkdk::KTabBarStyle\fP { \fBSegmentDark\fP, \fBSegmentLight\fP, \fBSliding\fP }" .br .RI "支持三种样式 " .ti -1c .RI "enum \fBkdk::MaximumButtonState\fP { \fBMaximum\fP, \fBRestore\fP }" .br .RI "最大化按钮提供两种状态响应 " .in -1c .SS "Functions" .in +1c .ti -1c .RI "\fBkdk::KArrowTabBar::KArrowTabBar\fP (QWidget *parent=nullptr)" .br .ti -1c .RI "\fBKNativeTabbar\fP * \fBkdk::KArrowTabBar::tabbar\fP ()" .br .RI "获取knativetabbar " .ti -1c .RI "void \fBkdk::KArrowTabBar::resizeEvent\fP (QResizeEvent *event)" .br .ti -1c .RI "\fBkdk::KIconBar::KIconBar\fP (QWidget *parent=nullptr)" .br .ti -1c .RI "\fBkdk::KIconBar::KIconBar\fP (const QString &iconName, const QString &text, QWidget *parent=nullptr)" .br .ti -1c .RI "void \fBkdk::KIconBar::setIcon\fP (const QString &iconName)" .br .RI "设置图标 " .ti -1c .RI "void \fBkdk::KIconBar::setIcon\fP (const QIcon &icon)" .br .RI "设置图标 " .ti -1c .RI "void \fBkdk::KIconBar::setWidgetName\fP (const QString &widgetName)" .br .RI "设置标题 " .ti -1c .RI "QLabel * \fBkdk::KIconBar::nameLabel\fP ()" .br .RI "获取标题label " .ti -1c .RI "QLabel * \fBkdk::KIconBar::iconLabel\fP ()" .br .RI "获取图标label " .ti -1c .RI "void \fBkdk::KIconBar::mouseDoubleClickEvent\fP (QMouseEvent *event)" .br .ti -1c .RI "void \fBkdk::KIconBar::resizeEvent\fP (QResizeEvent *event)" .br .ti -1c .RI "QSize \fBkdk::KIconBar::sizeHint\fP () const override" .br .ti -1c .RI "\fBkdk::KNavigationBar::KNavigationBar\fP (QWidget *parent)" .br .ti -1c .RI "void \fBkdk::KNavigationBar::addItem\fP (QStandardItem *item)" .br .RI "增加常规Item " .ti -1c .RI "void \fBkdk::KNavigationBar::addSubItem\fP (QStandardItem *subItem)" .br .RI "增加次级Item " .ti -1c .RI "void \fBkdk::KNavigationBar::addGroupItems\fP (QList< QStandardItem * > items, const QString &tag)" .br .RI "成组增加Item,在导航栏中会显示tag " .ti -1c .RI "void \fBkdk::KNavigationBar::insertGroupItems\fP (QString tag, int row, QStandardItem *item)" .br .RI "在指定tag组中指定位置row插入item " .ti -1c .RI "void \fBkdk::KNavigationBar::removeGroupItem\fP (QString tag, QStandardItem *item)" .br .RI "在指定组中删除item " .ti -1c .RI "void \fBkdk::KNavigationBar::addTag\fP (const QString &tag)" .br .RI "添加tag " .ti -1c .RI "QStandardItemModel * \fBkdk::KNavigationBar::model\fP ()" .br .RI "获取model " .ti -1c .RI "QListView * \fBkdk::KNavigationBar::listview\fP ()" .br .RI "获取view " .ti -1c .RI "void \fBkdk::KNavigationBar::setTabValue\fP (QStandardItem *item, QString value)" .br .RI "设置tabvalue " .ti -1c .RI "void \fBkdk::KNavigationBar::setTabValueVisible\fP (bool visible)" .br .RI "设置tabvalue是否可见 " .ti -1c .RI "void \fBkdk::KNavigationBar::setAddIcon\fP (QString tag, QIcon icon)" .br .RI "tag 添加add图标 " .ti -1c .RI "void \fBkdk::KNavigationBar::setAddTagVisible\fP (QString tag, bool visible)" .br .RI "设置tag add图标是否可见 " .ti -1c .RI "void \fBkdk::KNavigationBar::setExtendTagVisible\fP (QString tag, bool visible)" .br .RI "设置折叠图标是否可见 " .ti -1c .RI "\fBkdk::KPixmapContainer::KPixmapContainer\fP (QWidget *parent=nullptr)" .br .ti -1c .RI "int \fBkdk::KPixmapContainer::value\fP () const" .br .RI "获取值 " .ti -1c .RI "void \fBkdk::KPixmapContainer::setValue\fP (int \fBvalue\fP)" .br .RI "设置值 " .ti -1c .RI "void \fBkdk::KPixmapContainer::setValueVisiable\fP (bool flag)" .br .RI "设置值是否可见 " .ti -1c .RI "bool \fBkdk::KPixmapContainer::isValueVisiable\fP () const" .br .RI "获取值是否可见 " .ti -1c .RI "void \fBkdk::KPixmapContainer::setPixmap\fP (const QPixmap &\fBpixmap\fP)" .br .RI "设置pixmap " .ti -1c .RI "QPixmap \fBkdk::KPixmapContainer::pixmap\fP () const" .br .RI "获取pixmap " .ti -1c .RI "void \fBkdk::KPixmapContainer::clearValue\fP ()" .br .RI "清除值 " .ti -1c .RI "QColor \fBkdk::KPixmapContainer::color\fP ()" .br .RI "返回背景色 " .ti -1c .RI "void \fBkdk::KPixmapContainer::setColor\fP (const QColor &\fBcolor\fP)" .br .RI "设置背景色 " .ti -1c .RI "int \fBkdk::KPixmapContainer::fontSize\fP ()" .br .RI "返回字体大小 " .ti -1c .RI "void \fBkdk::KPixmapContainer::setFontSize\fP (int size)" .br .RI "设置字体大小 " .ti -1c .RI "void \fBkdk::KPixmapContainer::paintEvent\fP (QPaintEvent *event)" .br .ti -1c .RI "\fBkdk::KProgressBar::KProgressBar\fP (QWidget *parent)" .br .ti -1c .RI "\fBProgressBarState\fP \fBkdk::KProgressBar::state\fP ()" .br .RI "获取状态 " .ti -1c .RI "void \fBkdk::KProgressBar::setState\fP (\fBProgressBarState\fP \fBstate\fP)" .br .RI "设置状态 " .ti -1c .RI "QString \fBkdk::KProgressBar::text\fP () const override" .br .RI "获取文本 " .ti -1c .RI "void \fBkdk::KProgressBar::setOrientation\fP (Qt::Orientation)" .br .RI "设置方向 " .ti -1c .RI "void \fBkdk::KProgressBar::setBodyWidth\fP (int width)" .br .RI "设置进度条宽度 " .ti -1c .RI "void \fBkdk::KProgressBar::setGradationColor\fP (QColor color1, QColor color2)" .br .RI "设置首尾位置的渐变颜色 " .ti -1c .RI "void \fBkdk::KProgressBar::setBackgroundColor\fP (QColor color)" .br .RI "设置背景色 " .ti -1c .RI "void \fBkdk::KProgressBar::setFillColor\fP (QColor color)" .br .RI "设置填充色 " .ti -1c .RI "void \fBkdk::KProgressBar::setGradation\fP (bool flag)" .br .RI "是否启用自定义渐变色 " .ti -1c .RI "bool \fBkdk::KProgressBar::gradation\fP ()" .br .RI "获取是否启用自定义渐变色 " .ti -1c .RI "void \fBkdk::KProgressBar::setAnimation\fP (bool flag)" .br .RI "是否启用动画 " .ti -1c .RI "bool \fBkdk::KProgressBar::animation\fP ()" .br .RI "获取是否启用动画 " .ti -1c .RI "void \fBkdk::KProgressBar::paintEvent\fP (QPaintEvent *event) override" .br .ti -1c .RI "QSize \fBkdk::KProgressBar::sizeHint\fP () const" .br .ti -1c .RI "\fBkdk::KTabBar::KTabBar\fP (\fBKTabBarStyle\fP \fBbarStyle\fP=SegmentLight, QWidget *parent=nullptr)" .br .ti -1c .RI "void \fBkdk::KTabBar::setTabBarStyle\fP (\fBKTabBarStyle\fP \fBbarStyle\fP)" .br .RI "设置TabBar样式 " .ti -1c .RI "\fBKTabBarStyle\fP \fBkdk::KTabBar::barStyle\fP ()" .br .RI "返回TabBar样式 " .ti -1c .RI "void \fBkdk::KTabBar::setBorderRadius\fP (int radius)" .br .RI "设置圆角半径,只对SegmentDark,SegmentLight样式生效 " .ti -1c .RI "int \fBkdk::KTabBar::borderRadius\fP ()" .br .RI "获取圆角半径 " .ti -1c .RI "void \fBkdk::KTabBar::setBackgroundColor\fP (const QColor &color)" .br .RI "设置背景色 " .ti -1c .RI "QSize \fBkdk::KTabBar::sizeHint\fP () const" .br .ti -1c .RI "QSize \fBkdk::KTabBar::minimumTabSizeHint\fP (int index) const" .br .ti -1c .RI "QSize \fBkdk::KTabBar::tabSizeHint\fP (int index) const" .br .ti -1c .RI "void \fBkdk::KTabBar::paintEvent\fP (QPaintEvent *event)" .br .ti -1c .RI "\fBkdk::KWindowButtonBar::KWindowButtonBar\fP (QWidget *parent=nullptr)" .br .ti -1c .RI "QPushButton * \fBkdk::KWindowButtonBar::minimumButton\fP ()" .br .RI "获取最小化按钮 " .ti -1c .RI "QPushButton * \fBkdk::KWindowButtonBar::maximumButton\fP ()" .br .RI "获取最大化按钮 " .ti -1c .RI "QPushButton * \fBkdk::KWindowButtonBar::closeButton\fP ()" .br .RI "获取关闭按钮 " .ti -1c .RI "\fBKMenuButton\fP * \fBkdk::KWindowButtonBar::menuButton\fP ()" .br .RI "获取菜单按钮 " .ti -1c .RI "\fBMaximumButtonState\fP \fBkdk::KWindowButtonBar::maximumButtonState\fP ()" .br .RI "获取最大化按钮的状态(最大化/恢复) " .ti -1c .RI "void \fBkdk::KWindowButtonBar::setMaximumButtonState\fP (\fBMaximumButtonState\fP state)" .br .RI "设置最大化按钮图标状态(最大化/恢复) " .ti -1c .RI "void \fBkdk::KWindowButtonBar::setFollowMode\fP (bool flag)" .br .RI "设置是否遵循模式 " .ti -1c .RI "bool \fBkdk::KWindowButtonBar::followMode\fP ()" .br .RI "返回是否遵循模式 " .ti -1c .RI "void \fBkdk::KWindowButtonBar::setSplitScreenGeometry\fP (QRect rect)" .br .RI "setSplitScreenGeometry " .ti -1c .RI "void \fBkdk::KWindowButtonBar::mouseDoubleClickEvent\fP (QMouseEvent *event)" .br .ti -1c .RI "bool \fBkdk::KWindowButtonBar::eventFilter\fP (QObject *watched, QEvent *event)" .br .ti -1c .RI "QSize \fBkdk::KWindowButtonBar::sizeHint\fP () const override" .br .in -1c .SS "Signals" .in +1c .ti -1c .RI "void \fBkdk::KArrowTabBar::sizeChange\fP ()" .br .RI "点击会发出信号 " .ti -1c .RI "void \fBkdk::KIconBar::doubleClick\fP ()" .br .RI "双击会发出双击信号,父widget可以绑定相应槽函数 " .ti -1c .RI "void \fBkdk::KNavigationBar::addTagClicked\fP (QString str)" .br .ti -1c .RI "void \fBkdk::KTabBar::rightlicked\fP (QPoint point)" .br .RI "鼠标右键信号 " .ti -1c .RI "void \fBkdk::KWindowButtonBar::doubleClick\fP ()" .br .RI "双击会发出双击信号,父widget可以绑定相应槽函数 " .in -1c .SH "Detailed Description" .PP 支持三种样式 .PP \fBSince\fP .RS 4 2\&.5\&.2\&.0 { .PP 2\&.5\&.2\&.0 .RE .PP { .SH "Enumeration Type Documentation" .PP .SS "enum \fBkdk::MaximumButtonState\fP" .PP 最大化按钮提供两种状态响应 .PP \fBSince\fP .RS 4 1\&.0\&.0 .RE .PP .SS "enum \fBkdk::ProgressBarState\fP" .PP 支持三种状态 .PP \fBSince\fP .RS 4 1\&.0\&.0 .RE .PP .SH "Function Documentation" .PP .SS "void kdk::KNavigationBar::addGroupItems (QList< QStandardItem * > items, const QString & tag)" .PP 成组增加Item,在导航栏中会显示tag .PP \fBParameters\fP .RS 4 \fIitems\fP .br \fItag\fP .RE .PP .SS "void kdk::KNavigationBar::addItem (QStandardItem * item)" .PP 增加常规Item .PP \fBParameters\fP .RS 4 \fIitem\fP .RE .PP .SS "void kdk::KNavigationBar::addSubItem (QStandardItem * subItem)" .PP 增加次级Item .PP \fBParameters\fP .RS 4 \fIsubItem\fP .RE .PP .SS "void kdk::KNavigationBar::addTag (const QString & tag)" .PP 添加tag .PP \fBParameters\fP .RS 4 \fItag\fP .RE .PP .SS "bool kdk::KProgressBar::animation ()" .PP 获取是否启用动画 .PP \fBSince\fP .RS 4 2\&.5\&.2\&.0 .RE .PP \fBReturns\fP .RS 4 .RE .PP .SS "\fBKTabBarStyle\fP kdk::KTabBar::barStyle ()" .PP 返回TabBar样式 .PP \fBReturns\fP .RS 4 .RE .PP .SS "int kdk::KTabBar::borderRadius ()" .PP 获取圆角半径 .PP \fBReturns\fP .RS 4 .RE .PP .SS "QPushButton * kdk::KWindowButtonBar::closeButton ()" .PP 获取关闭按钮 .PP \fBReturns\fP .RS 4 .RE .PP .SS "QColor kdk::KPixmapContainer::color ()" .PP 返回背景色 .PP \fBReturns\fP .RS 4 .RE .PP .SS "bool kdk::KWindowButtonBar::followMode ()" .PP 返回是否遵循模式 .PP \fBSince\fP .RS 4 2\&.0 .RE .PP \fBReturns\fP .RS 4 .RE .PP .SS "int kdk::KPixmapContainer::fontSize ()" .PP 返回字体大小 .PP \fBReturns\fP .RS 4 .RE .PP .SS "bool kdk::KProgressBar::gradation ()" .PP 获取是否启用自定义渐变色 .PP \fBSince\fP .RS 4 2\&.5\&.2\&.0 .RE .PP \fBReturns\fP .RS 4 .RE .PP .SS "QLabel * kdk::KIconBar::iconLabel ()" .PP 获取图标label .PP \fBReturns\fP .RS 4 .RE .PP .SS "void kdk::KNavigationBar::insertGroupItems (QString tag, int row, QStandardItem * item)" .PP 在指定tag组中指定位置row插入item .PP \fBParameters\fP .RS 4 \fItag\fP .br \fIrow\fP .br \fIitem\fP .RE .PP \fBSince\fP .RS 4 3\&.0\&.1\&.0 .RE .PP .SS "QListView * kdk::KNavigationBar::listview ()" .PP 获取view .PP \fBReturns\fP .RS 4 .RE .PP .SS "QPushButton * kdk::KWindowButtonBar::maximumButton ()" .PP 获取最大化按钮 .PP \fBReturns\fP .RS 4 .RE .PP .SS "\fBMaximumButtonState\fP kdk::KWindowButtonBar::maximumButtonState ()" .PP 获取最大化按钮的状态(最大化/恢复) .PP \fBReturns\fP .RS 4 .RE .PP .SS "\fBKMenuButton\fP * kdk::KWindowButtonBar::menuButton ()" .PP 获取菜单按钮 .PP \fBReturns\fP .RS 4 .RE .PP .SS "QPushButton * kdk::KWindowButtonBar::minimumButton ()" .PP 获取最小化按钮 .PP \fBReturns\fP .RS 4 .RE .PP .SS "QStandardItemModel * kdk::KNavigationBar::model ()" .PP 获取model .PP \fBReturns\fP .RS 4 .RE .PP .SS "QLabel * kdk::KIconBar::nameLabel ()" .PP 获取标题label .PP \fBReturns\fP .RS 4 .RE .PP .SS "void kdk::KNavigationBar::removeGroupItem (QString tag, QStandardItem * item)" .PP 在指定组中删除item .PP \fBParameters\fP .RS 4 \fItag\fP .br \fIitem\fP .RE .PP \fBSince\fP .RS 4 3\&.0\&.1\&.0 .RE .PP .SS "void kdk::KNavigationBar::setAddIcon (QString tag, QIcon icon)" .PP tag 添加add图标 .PP \fBParameters\fP .RS 4 \fItag\fP .br \fIicon\fP .RE .PP \fBSince\fP .RS 4 3\&.0\&.1\&.0 .RE .PP .SS "void kdk::KNavigationBar::setAddTagVisible (QString tag, bool visible)" .PP 设置tag add图标是否可见 .PP \fBParameters\fP .RS 4 \fItag\fP .br \fIvisible\fP .RE .PP \fBSince\fP .RS 4 3\&.0\&.1\&.0 .RE .PP .SS "void kdk::KProgressBar::setAnimation (bool flag)" .PP 是否启用动画 .PP \fBSince\fP .RS 4 2\&.5\&.2\&.0 .RE .PP \fBParameters\fP .RS 4 \fIflag\fP .RE .PP .SS "void kdk::KTabBar::setBackgroundColor (const QColor & color)" .PP 设置背景色 .PP \fBParameters\fP .RS 4 \fIcolor\fP .RE .PP \fBSince\fP .RS 4 1\&.2\&.0 .RE .PP .SS "void kdk::KProgressBar::setBackgroundColor (QColor color)" .PP 设置背景色 .PP \fBSince\fP .RS 4 2\&.5\&.2\&.0 .RE .PP \fBParameters\fP .RS 4 \fIcolor\fP .RE .PP .SS "void kdk::KProgressBar::setBodyWidth (int width)" .PP 设置进度条宽度 .PP \fBParameters\fP .RS 4 \fIwidth\fP .RE .PP \fBSince\fP .RS 4 1\&.2\&.0 .RE .PP .SS "void kdk::KTabBar::setBorderRadius (int radius)" .PP 设置圆角半径,只对SegmentDark,SegmentLight样式生效 .PP \fBParameters\fP .RS 4 \fIradius\fP .RE .PP .SS "void kdk::KPixmapContainer::setColor (const QColor & color)" .PP 设置背景色 .PP \fBParameters\fP .RS 4 \fIcolor\fP .RE .PP .SS "void kdk::KNavigationBar::setExtendTagVisible (QString tag, bool visible)" .PP 设置折叠图标是否可见 .PP \fBParameters\fP .RS 4 \fItag\fP .br \fIvisible\fP .RE .PP \fBSince\fP .RS 4 3\&.0\&.1\&.0 .RE .PP .SS "void kdk::KProgressBar::setFillColor (QColor color)" .PP 设置填充色 .PP \fBSince\fP .RS 4 2\&.5\&.2\&.0 .RE .PP \fBParameters\fP .RS 4 \fIcolor\fP .RE .PP .SS "void kdk::KWindowButtonBar::setFollowMode (bool flag)" .PP 设置是否遵循模式 .PP \fBSince\fP .RS 4 2\&.0 .RE .PP \fBParameters\fP .RS 4 \fIflag\fP .RE .PP .SS "void kdk::KPixmapContainer::setFontSize (int size)" .PP 设置字体大小 .PP \fBParameters\fP .RS 4 \fIsize\fP .RE .PP .SS "void kdk::KProgressBar::setGradation (bool flag)" .PP 是否启用自定义渐变色 .PP \fBSince\fP .RS 4 2\&.5\&.2\&.0 .RE .PP \fBParameters\fP .RS 4 \fIflag\fP .RE .PP .SS "void kdk::KProgressBar::setGradationColor (QColor color1, QColor color2)" .PP 设置首尾位置的渐变颜色 .PP \fBSince\fP .RS 4 2\&.5\&.2\&.0 .RE .PP \fBParameters\fP .RS 4 \fIcolor1\fP .br \fIcolor2\fP .RE .PP .SS "void kdk::KIconBar::setIcon (const QIcon & icon)" .PP 设置图标 .PP \fBParameters\fP .RS 4 \fIicon\fP .RE .PP .SS "void kdk::KIconBar::setIcon (const QString & iconName)" .PP 设置图标 .PP \fBParameters\fP .RS 4 \fIiconName\fP .RE .PP .SS "void kdk::KWindowButtonBar::setMaximumButtonState (\fBMaximumButtonState\fP state)" .PP 设置最大化按钮图标状态(最大化/恢复) .PP \fBParameters\fP .RS 4 \fIstate\fP .RE .PP .SS "void kdk::KPixmapContainer::setPixmap (const QPixmap & pixmap)" .PP 设置pixmap .PP \fBParameters\fP .RS 4 \fIpixmap\fP .RE .PP .SS "void kdk::KWindowButtonBar::setSplitScreenGeometry (QRect rect)" .PP setSplitScreenGeometry .PP \fBParameters\fP .RS 4 \fI弹出界面的显示位置rect\fP .RE .PP \fBSince\fP .RS 4 3\&.0\&.1\&.0 .RE .PP .SS "void kdk::KProgressBar::setState (\fBProgressBarState\fP state)" .PP 设置状态 .PP \fBParameters\fP .RS 4 \fIstate\fP .RE .PP .SS "void kdk::KTabBar::setTabBarStyle (\fBKTabBarStyle\fP barStyle)" .PP 设置TabBar样式 .PP \fBParameters\fP .RS 4 \fIbarStyle\fP .RE .PP .SS "void kdk::KNavigationBar::setTabValue (QStandardItem * item, QString value)" .PP 设置tabvalue .PP \fBParameters\fP .RS 4 \fIitem\fP .br \fIvalue\fP .RE .PP \fBSince\fP .RS 4 3\&.0\&.1\&.0 .RE .PP .SS "void kdk::KNavigationBar::setTabValueVisible (bool visible)" .PP 设置tabvalue是否可见 .PP \fBParameters\fP .RS 4 \fIvisible\fP .RE .PP \fBSince\fP .RS 4 3\&.0\&.1\&.0 .RE .PP .SS "void kdk::KPixmapContainer::setValue (int value)" .PP 设置值 .PP \fBParameters\fP .RS 4 \fIvalue\fP .RE .PP .SS "void kdk::KPixmapContainer::setValueVisiable (bool flag)" .PP 设置值是否可见 .PP \fBParameters\fP .RS 4 \fIflag\fP .RE .PP .SS "void kdk::KIconBar::setWidgetName (const QString & widgetName)" .PP 设置标题 .PP \fBParameters\fP .RS 4 \fIwidgetName\fP .RE .PP .SS "\fBProgressBarState\fP kdk::KProgressBar::state ()" .PP 获取状态 .PP \fBReturns\fP .RS 4 .RE .PP .SS "\fBKNativeTabbar\fP * kdk::KArrowTabBar::tabbar ()" .PP 获取knativetabbar .PP \fBReturns\fP .RS 4 .RE .PP .SS "QString kdk::KProgressBar::text () const\fC [override]\fP" .PP 获取文本 .PP \fBReturns\fP .RS 4 .RE .PP .SH "Signals" .PP .SS "void kdk::KTabBar::rightlicked (QPoint point)\fC [signal]\fP" .PP 鼠标右键信号 .PP \fBParameters\fP .RS 4 \fIpoint\fP .RE .PP \fBSince\fP .RS 4 2\&.4\&.1\&.0 .RE .PP .SH "Author" .PP Generated automatically by Doxygen for LIBKYSDK-APPLICATIONS from the source code\&. libkysdk-applications/doxygen/man/man3/kdk_KCommentPanel.30000664000175000017500000000240715104543305022503 0ustar fengfeng.TH "kdk::KCommentPanel" 3 "Version version:3.0" "LIBKYSDK-APPLICATIONS" \" -*- nroff -*- .ad l .nh .SH NAME kdk::KCommentPanel \- 显示用户评论的详细信息 .SH SYNOPSIS .br .PP .PP \fC#include \fP .PP Inherits QWidget\&. .SS "Public Member Functions" .in +1c .ti -1c .RI "\fBKCommentPanel\fP (QWidget *parent=nullptr)" .br .ti -1c .RI "void \fBsetIcon\fP (const QIcon &)" .br .RI "设置评论用户头像 " .ti -1c .RI "void \fBsetTime\fP (const QString &)" .br .RI "设置评论时间 " .ti -1c .RI "void \fBsetName\fP (const QString &)" .br .RI "设置评论用户昵称 " .ti -1c .RI "void \fBsetText\fP (const QString &)" .br .RI "设置评论文本 " .ti -1c .RI "void \fBsetGrade\fP (\fBStarLevel\fP level)" .br .RI "设置等级 " .in -1c .SS "Protected Member Functions" .in +1c .ti -1c .RI "void \fBpaintEvent\fP (QPaintEvent *event) override" .br .in -1c .SH "Detailed Description" .PP 显示用户评论的详细信息 .PP \fBSince\fP .RS 4 1\&.0\&.0 .RE .PP .SH "Member Function Documentation" .PP .SS "void kdk::KCommentPanel::setGrade (\fBStarLevel\fP level)" .PP 设置等级 .PP \fBParameters\fP .RS 4 \fIlevel\fP .RE .PP .SH "Author" .PP Generated automatically by Doxygen for LIBKYSDK-APPLICATIONS from the source code\&. libkysdk-applications/doxygen/man/man3/kdk_KBackgroundGroup.30000664000175000017500000001057515104543305023222 0ustar fengfeng.TH "kdk::KBackgroundGroup" 3 "Version version:3.0" "LIBKYSDK-APPLICATIONS" \" -*- nroff -*- .ad l .nh .SH NAME kdk::KBackgroundGroup \- 提供了一个用于存储部件的容器 .SH SYNOPSIS .br .PP .PP \fC#include \fP .PP Inherits QFrame\&. .SS "Signals" .in +1c .ti -1c .RI "void \fBclicked\fP (QWidget *)" .br .RI "点击会发出信号 " .in -1c .SS "Public Member Functions" .in +1c .ti -1c .RI "\fBKBackgroundGroup\fP (QWidget *parent=nullptr)" .br .ti -1c .RI "void \fBaddWidget\fP (QWidget *widget)" .br .RI "添加一个widget控件 " .ti -1c .RI "void \fBaddWidgetList\fP (QList< QWidget * > list)" .br .RI "添加一个widget list " .ti -1c .RI "void \fBremoveWidgetAt\fP (int i)" .br .RI "删除一个指定index的widget " .ti -1c .RI "void \fBremoveWidget\fP (QWidget *widget)" .br .RI "删除一个widget " .ti -1c .RI "void \fBremoveWidgetList\fP (QList< QWidget * > list)" .br .RI "删除一个widget list " .ti -1c .RI "void \fBinsertWidgetAt\fP (int index, QWidget *widget)" .br .RI "指定位置插入一个widget " .ti -1c .RI "void \fBinsertWidgetList\fP (int index, QList< QWidget * > list)" .br .RI "指定位置插入一个widget list " .ti -1c .RI "void \fBsetBorderRadius\fP (int radius)" .br .RI "设置KBackgroundGroup的圆角 " .ti -1c .RI "int \fBborderRadius\fP ()" .br .RI "返回KBackgroundGroup的圆角 " .ti -1c .RI "void \fBsetBackgroundRole\fP (QPalette::ColorRole role)" .br .RI "设置背景颜色 " .ti -1c .RI "QPalette::ColorRole \fBbackgroundRole\fP () const" .br .RI "返回背景颜色 " .ti -1c .RI "void \fBsetStateEnable\fP (QWidget *widget, bool flag)" .br .RI "设置窗体是否可以响应三态 " .ti -1c .RI "QList< QWidget * > \fBwidgetList\fP ()" .br .RI "返回widget列表 " .ti -1c .RI "void \fBsetBorderVisible\fP (bool flag)" .br .RI "设置边框是否可见 " .in -1c .SS "Protected Member Functions" .in +1c .ti -1c .RI "void \fBpaintEvent\fP (QPaintEvent *event)" .br .ti -1c .RI "bool \fBeventFilter\fP (QObject *watched, QEvent *event)" .br .in -1c .SH "Detailed Description" .PP 提供了一个用于存储部件的容器 .PP \fBSince\fP .RS 4 2\&.0\&.2\&.1 .RE .PP .SH "Member Function Documentation" .PP .SS "void kdk::KBackgroundGroup::addWidget (QWidget * widget)" .PP 添加一个widget控件 .PP \fBParameters\fP .RS 4 \fIwidget\fP .RE .PP .SS "void kdk::KBackgroundGroup::addWidgetList (QList< QWidget * > list)" .PP 添加一个widget list .PP \fBParameters\fP .RS 4 \fIlist\fP .RE .PP .SS "QPalette::ColorRole kdk::KBackgroundGroup::backgroundRole () const" .PP 返回背景颜色 .PP \fBReturns\fP .RS 4 .RE .PP .SS "int kdk::KBackgroundGroup::borderRadius ()" .PP 返回KBackgroundGroup的圆角 .PP \fBReturns\fP .RS 4 .RE .PP .SS "void kdk::KBackgroundGroup::insertWidgetAt (int index, QWidget * widget)" .PP 指定位置插入一个widget .PP \fBParameters\fP .RS 4 \fIindex\fP .br \fIwidget\fP .RE .PP .SS "void kdk::KBackgroundGroup::insertWidgetList (int index, QList< QWidget * > list)" .PP 指定位置插入一个widget list .PP \fBParameters\fP .RS 4 \fIindex\fP .br \fIlist\fP .RE .PP .SS "void kdk::KBackgroundGroup::removeWidget (QWidget * widget)" .PP 删除一个widget .PP \fBParameters\fP .RS 4 \fIwidget\fP .RE .PP .SS "void kdk::KBackgroundGroup::removeWidgetAt (int i)" .PP 删除一个指定index的widget .PP \fBParameters\fP .RS 4 \fIi\fP .RE .PP .SS "void kdk::KBackgroundGroup::removeWidgetList (QList< QWidget * > list)" .PP 删除一个widget list .PP \fBParameters\fP .RS 4 \fIlist\fP .RE .PP .SS "void kdk::KBackgroundGroup::setBackgroundRole (QPalette::ColorRole role)" .PP 设置背景颜色 .PP \fBParameters\fP .RS 4 \fIrole\fP .RE .PP .SS "void kdk::KBackgroundGroup::setBorderRadius (int radius)" .PP 设置KBackgroundGroup的圆角 .PP \fBParameters\fP .RS 4 \fIradius\fP .RE .PP .SS "void kdk::KBackgroundGroup::setBorderVisible (bool flag)" .PP 设置边框是否可见 .PP \fBParameters\fP .RS 4 \fIflag\fP .RE .PP \fBSince\fP .RS 4 3\&.0\&.1\&.0 .RE .PP .SS "void kdk::KBackgroundGroup::setStateEnable (QWidget * widget, bool flag)" .PP 设置窗体是否可以响应三态 .PP \fBParameters\fP .RS 4 \fIflag\fP .br \fIwidget\fP .RE .PP .SS "QList< QWidget * > kdk::KBackgroundGroup::widgetList ()" .PP 返回widget列表 .PP \fBReturns\fP .RS 4 .RE .PP .SH "Author" .PP Generated automatically by Doxygen for LIBKYSDK-APPLICATIONS from the source code\&. libkysdk-applications/doxygen/man/man3/kdk_KSwitchButton.30000664000175000017500000000263415104543305022560 0ustar fengfeng.TH "kdk::KSwitchButton" 3 "Version version:3.0" "LIBKYSDK-APPLICATIONS" \" -*- nroff -*- .ad l .nh .SH NAME kdk::KSwitchButton \- 指示打开/关闭两种状态 .SH SYNOPSIS .br .PP .PP \fC#include \fP .PP Inherits QPushButton\&. .SS "Signals" .in +1c .ti -1c .RI "void \fBstateChanged\fP (bool)" .br .RI "当选中状态发生变化时,发出此信号 " .in -1c .SS "Public Member Functions" .in +1c .ti -1c .RI "\fBKSwitchButton\fP (QWidget *parent=0)" .br .ti -1c .RI "void \fBsetCheckable\fP (bool)" .br .RI "设置是否可选中 " .ti -1c .RI "bool \fBisCheckable\fP () const" .br .RI "返回是否可选中 " .ti -1c .RI "bool \fBisChecked\fP () const" .br .RI "返回是否选中 " .ti -1c .RI "void \fBsetChecked\fP (bool)" .br .RI "设置是否选中 " .ti -1c .RI "void \fBsetTranslucent\fP (bool flag)" .br .RI "设置是否启用半透明效果 " .ti -1c .RI "bool \fBisTranslucent\fP ()" .br .RI "获取是否启用半透明效果 " .in -1c .SS "Protected Member Functions" .in +1c .ti -1c .RI "void \fBpaintEvent\fP (QPaintEvent *event) override" .br .ti -1c .RI "void \fBresizeEvent\fP (QResizeEvent *event) override" .br .ti -1c .RI "QSize \fBsizeHint\fP () const" .br .in -1c .SH "Detailed Description" .PP 指示打开/关闭两种状态 .PP \fBSince\fP .RS 4 1\&.0\&.0 .RE .PP .SH "Author" .PP Generated automatically by Doxygen for LIBKYSDK-APPLICATIONS from the source code\&. libkysdk-applications/doxygen/man/man3/UkuiStyleModule.30000664000175000017500000000045215104543305022257 0ustar fengfeng.TH "UkuiStyleModule" 3 "Version version:3.0" "LIBKYSDK-APPLICATIONS" \" -*- nroff -*- .ad l .nh .SH NAME UkuiStyleModule \- UkuiStyleModule .SH SYNOPSIS .br .PP .SH "Detailed Description" .PP .SH "Author" .PP Generated automatically by Doxygen for LIBKYSDK-APPLICATIONS from the source code\&. libkysdk-applications/doxygen/man/man3/kdk_KTag.30000664000175000017500000000442315104543305020634 0ustar fengfeng.TH "kdk::KTag" 3 "Version version:3.0" "LIBKYSDK-APPLICATIONS" \" -*- nroff -*- .ad l .nh .SH NAME kdk::KTag \- 提供四种样式的标签,响应系统主题色变化 .SH SYNOPSIS .br .PP .PP \fC#include \fP .PP Inherits QPushButton\&. .SS "Public Member Functions" .in +1c .ti -1c .RI "\fBKTag\fP (QWidget *parent=nullptr)" .br .ti -1c .RI "void \fBsetClosable\fP (bool)" .br .RI "设置关闭按钮是否可见 " .ti -1c .RI "bool \fBclosable\fP ()" .br .RI "返回关闭按钮是否可见 " .ti -1c .RI "void \fBsetText\fP (const QString &)" .br .RI "设置文本 " .ti -1c .RI "QString \fBtext\fP ()" .br .RI "获取当前文本 " .ti -1c .RI "void \fBsetTagStyle\fP (\fBTagStyle\fP)" .br .RI "设置tag样式 " .ti -1c .RI "\fBTagStyle\fP \fBtagStyle\fP ()" .br .RI "获取当前tag样式 " .ti -1c .RI "void \fBsetBackgroundColor\fP (QColor color)" .br .RI "设置背景颜色 " .ti -1c .RI "void \fBsetTranslucent\fP (bool flag)" .br .RI "设置半透明 " .ti -1c .RI "bool \fBtranslucent\fP ()" .br .RI "获取是否启用半透明 " .in -1c .SS "Protected Member Functions" .in +1c .ti -1c .RI "void \fBpaintEvent\fP (QPaintEvent *event)" .br .ti -1c .RI "QSize \fBsizeHint\fP () const override" .br .in -1c .SH "Detailed Description" .PP 提供四种样式的标签,响应系统主题色变化 .PP \fBSince\fP .RS 4 1\&.0\&.0 .RE .PP .SH "Member Function Documentation" .PP .SS "bool kdk::KTag::closable ()" .PP 返回关闭按钮是否可见 .PP \fBReturns\fP .RS 4 bool .RE .PP .SS "void kdk::KTag::setBackgroundColor (QColor color)" .PP 设置背景颜色 .PP \fBParameters\fP .RS 4 \fIflag\fP .RE .PP \fBSince\fP .RS 4 2\&.4\&.1\&.0 .RE .PP .SS "void kdk::KTag::setTranslucent (bool flag)" .PP 设置半透明 .PP \fBParameters\fP .RS 4 \fIflag\fP .RE .PP \fBSince\fP .RS 4 2\&.4\&.1\&.0 .RE .PP .SS "\fBTagStyle\fP kdk::KTag::tagStyle ()" .PP 获取当前tag样式 .PP \fBReturns\fP .RS 4 TagStyle .RE .PP .SS "QString kdk::KTag::text ()" .PP 获取当前文本 .PP \fBReturns\fP .RS 4 QString .RE .PP .SS "bool kdk::KTag::translucent ()" .PP 获取是否启用半透明 .PP \fBReturns\fP .RS 4 bool .RE .PP \fBSince\fP .RS 4 2\&.4\&.1\&.0 .RE .PP .SH "Author" .PP Generated automatically by Doxygen for LIBKYSDK-APPLICATIONS from the source code\&. libkysdk-applications/doxygen/man/man3/kdk_WindowManager.30000664000175000017500000005005415104543305022551 0ustar fengfeng.TH "kdk::WindowManager" 3 "Version version:3.0" "LIBKYSDK-APPLICATIONS" \" -*- nroff -*- .ad l .nh .SH NAME kdk::WindowManager \- 通常用于对窗口的一些操作 .SH SYNOPSIS .br .PP .PP \fC#include \fP .PP Inherits QObject\&. .SS "Signals" .in +1c .ti -1c .RI "void \fBwindowAdded\fP (const WindowId &windowId)" .br .RI "窗口添加信号 " .ti -1c .RI "void \fBwindowRemoved\fP (const WindowId &windowId)" .br .RI "窗口删除信号 " .ti -1c .RI "void \fBactiveWindowChanged\fP (const WindowId &wid)" .br .RI "活动窗口改变信号 " .ti -1c .RI "void \fBwindowChanged\fP (const WindowId &wid)" .br .RI "窗口改变信号 " .ti -1c .RI "void \fBcurrentDesktopChanged\fP ()" .br .RI "当前桌面改变信号 " .ti -1c .RI "void \fBisShowingDesktopChanged\fP ()" .br .RI "桌面显示状态变化信号 " .ti -1c .RI "void \fBtitleChanged\fP (const WindowId &wid)" .br .RI "窗口标题改变信号 " .ti -1c .RI "void \fBiconChanged\fP (const WindowId &wid)" .br .RI "窗口图标改变信号 " .ti -1c .RI "void \fBactiveChanged\fP (const WindowId &wid)" .br .RI "窗口活动状态改变信号 " .ti -1c .RI "void \fBfullscreenChanged\fP (const WindowId &wid)" .br .RI "窗口全屏状态改变信号 " .ti -1c .RI "void \fBkeepAboveChanged\fP (const WindowId &wid)" .br .RI "窗口置顶状态改变信号 " .ti -1c .RI "void \fBminimizedChanged\fP (const WindowId &wid)" .br .RI "窗口最小化状态改变信号 " .ti -1c .RI "void \fBmaximizedChanged\fP (const WindowId &wid)" .br .RI "窗口最大化状态改变信号 " .ti -1c .RI "void \fBonAllDesktopsChanged\fP (const WindowId &wid)" .br .RI "onAllDesktopsChanged " .ti -1c .RI "void \fBdemandsAttentionChanged\fP (const WindowId &wid)" .br .RI "demandsAttention状态改变信号 " .ti -1c .RI "void \fBskipTaskbarChanged\fP (const WindowId &wid)" .br .RI "跳过任务栏状态改变信号 " .ti -1c .RI "void \fBskipSwitcherChanged\fP (const WindowId &wid)" .br .RI "跳过窗口选择器状态改变信号 " .ti -1c .RI "void \fBgeometryChanged\fP (const WindowId &wid)" .br .RI "窗口位置改变信号 " .ti -1c .RI "void \fBoutputInfoChanged\fP (OutputInfo *)" .br .RI "屏幕信息改变信号 " .in -1c .SS "Static Public Member Functions" .in +1c .ti -1c .RI "static \fBWindowManager\fP * \fBself\fP ()" .br .RI "self " .ti -1c .RI "static WindowInfo \fBgetwindowInfo\fP (const WindowId &windowId)" .br .RI "获取窗口信息 " .ti -1c .RI "static WindowId \fBcurrentActiveWindow\fP ()" .br .RI "获取当前活动窗口 " .ti -1c .RI "static void \fBkeepWindowAbove\fP (const WindowId &windowId)" .br .RI "置顶窗口 " .ti -1c .RI "static QString \fBgetWindowTitle\fP (const WindowId &windowId)" .br .RI "获取窗口标题 " .ti -1c .RI "static QIcon \fBgetWindowIcon\fP (const WindowId &windowId)" .br .RI "获取窗口图标 " .ti -1c .RI "static QString \fBgetWindowGroup\fP (const WindowId &windowId)" .br .RI "获取窗口所在组的组名 " .ti -1c .RI "static void \fBcloseWindow\fP (const WindowId &windowId)" .br .RI "关闭窗口 " .ti -1c .RI "static void \fBactivateWindow\fP (const WindowId &windowId)" .br .RI "激活窗口 " .ti -1c .RI "static void \fBmaximizeWindow\fP (const WindowId &windowId)" .br .RI "最大化窗口 " .ti -1c .RI "static void \fBminimizeWindow\fP (const WindowId &windowId)" .br .RI "最小化窗口 " .ti -1c .RI "static quint32 \fBgetPid\fP (const WindowId &windowId)" .br .RI "获取窗口进程pid " .ti -1c .RI "static void \fBshowDesktop\fP ()" .br .RI "显示当前桌面 " .ti -1c .RI "static void \fBhideDesktop\fP ()" .br .RI "取消显示当前桌面 " .ti -1c .RI "static QString \fBcurrentDesktop\fP ()" .br .RI "获取当前桌面的名称 " .ti -1c .RI "static QList< WindowId > \fBwindows\fP ()" .br .RI "获取当前窗口列表 " .ti -1c .RI "static NET::WindowType \fBgetWindowType\fP (const WindowId &windowId)" .br .RI "获取窗口类型,仅适用于X环境下,wayland下统一返回normal " .ti -1c .RI "static void \fBsetGeometry\fP (QWindow *window, const QRect &rect)" .br .RI "设置窗口位置 " .ti -1c .RI "static void \fBsetSkipTaskBar\fP (QWindow *window, bool skip)" .br .RI "设置是否跳过任务栏 " .ti -1c .RI "static void \fBsetSkipSwitcher\fP (QWindow *window, bool skip)" .br .RI "设置是否跳过窗口选择 " .ti -1c .RI "static bool \fBskipTaskBar\fP (const WindowId &windowId)" .br .RI "判断窗体是否跳过任务栏 " .ti -1c .RI "static bool \fBskipSwitcher\fP (const WindowId &windowId)" .br .RI "判断窗体是否跳过窗口选择 " .ti -1c .RI "static bool \fBisShowingDesktop\fP ()" .br .RI "判断桌面是否处于显示状态 " .ti -1c .RI "static void \fBsetOnAllDesktops\fP (const WindowId &windowId)" .br .RI "设置窗口在所有桌面中显示 " .ti -1c .RI "static bool \fBisOnAllDesktops\fP (const WindowId &windowId)" .br .RI "判断窗口在所有桌面中显示 " .ti -1c .RI "static bool \fBisOnCurrentDesktop\fP (const WindowId &id)" .br .RI "判断窗口是否在当前桌面 " .ti -1c .RI "static bool \fBisOnDesktop\fP (const WindowId &id, int desktop)" .br .RI "判断窗口是否在指定桌面 " .ti -1c .RI "static void \fBsetPanelTakefocus\fP (QWindow *window, bool flag)" .br .RI "设置panel属性窗体是否获取焦点,仅wayland环境下生效 " .ti -1c .RI "static void \fBdemandAttention\fP (const WindowId &wid)" .br .RI "发送demandAttention状态 " .ti -1c .RI "static QString \fBgetProcessName\fP (const WindowId &windowId)" .br .RI "获取窗口所属的进程名称 " .ti -1c .RI "static void \fBsetWindowRadius\fP (QWindow *window, int radius)" .br .RI "setWindowRadius " .ti -1c .RI "static void \fBactivateWindow\fP (QWindow *window1, QWindow *window2)" .br .RI "activateWindow " .ti -1c .RI "static QRect \fBwindowGeometry\fP (const WindowId &windowId)" .br .RI "windowGeometry " .ti -1c .RI "static void \fBsetPanelAutoHide\fP (QWindow *window, bool autoHide)" .br .RI "setPanelAutoHide " .ti -1c .RI "static void \fBsetGrabKeyboard\fP (QWindow *window, bool grabKeyboard)" .br .RI "setGrabKeyboard " .ti -1c .RI "static void \fBsetWindowLayer\fP (QWindow *window, WindowLayer layer)" .br .RI "setWindowLayer " .ti -1c .RI "static WindowLayer \fBwindowLayer\fP (QWindow *window)" .br .RI "windowLayer " .ti -1c .RI "static void \fBsetHighlight\fP (const WindowId &wid, bool highlight)" .br .RI "setHighlight " .ti -1c .RI "static bool \fBisHightlight\fP (const WindowId &wid)" .br .RI "isHightlight " .ti -1c .RI "static void \fBsetOpenUnderCursor\fP (QWindow *window)" .br .RI "setOpenUnderCursor " .ti -1c .RI "static void \fBsetOpenUnderCursor\fP (QWindow *window, int x, int y)" .br .RI "setOpenUnderCursor " .ti -1c .RI "static void \fBsetIconName\fP (QWindow *window, const QString &iconName)" .br .RI "setIconName " .ti -1c .RI "static QString \fBcurrentSeatName\fP ()" .br .RI "currentSeatName " .ti -1c .RI "static QString \fBcurrentOutputName\fP ()" .br .RI "currentOutputName " .ti -1c .RI "static QList< OutputInfo * > \fBoutputsInfo\fP ()" .br .RI "outputsInfo " .ti -1c .RI "static QList< WindowId > \fBgetWindowIdByPid\fP (quint32 pid)" .br .RI "getWindowIdByPid " .ti -1c .RI "static QList< WindowId > \fBgetWindowIdByTtile\fP (const QString &title)" .br .RI "getWindowIdByTtile " .in -1c .SH "Detailed Description" .PP 通常用于对窗口的一些操作 .PP \fBSince\fP .RS 4 1\&.2\&.0 .RE .PP .SH "Member Function Documentation" .PP .SS "static void kdk::WindowManager::activateWindow (const WindowId & windowId)\fC [static]\fP" .PP 激活窗口 .PP \fBParameters\fP .RS 4 \fIwindowId\fP .RE .PP .SS "static void kdk::WindowManager::activateWindow (QWindow * window1, QWindow * window2)\fC [static]\fP" .PP activateWindow .PP \fBSince\fP .RS 4 2\&.5\&.1\&.0 .RE .PP \fBParameters\fP .RS 4 \fIwindow1\fP .br \fIwindow2\fP .RE .PP .SS "void kdk::WindowManager::activeChanged (const WindowId & wid)\fC [signal]\fP" .PP 窗口活动状态改变信号 .PP \fBSince\fP .RS 4 2\&.3\&.1\&.0 .RE .PP \fBParameters\fP .RS 4 \fIwid\fP .RE .PP .SS "void kdk::WindowManager::activeWindowChanged (const WindowId & wid)\fC [signal]\fP" .PP 活动窗口改变信号 .PP \fBParameters\fP .RS 4 \fIwid\fP .RE .PP .SS "static void kdk::WindowManager::closeWindow (const WindowId & windowId)\fC [static]\fP" .PP 关闭窗口 .PP \fBParameters\fP .RS 4 \fIwindowId\fP .RE .PP .SS "static WindowId kdk::WindowManager::currentActiveWindow ()\fC [static]\fP" .PP 获取当前活动窗口 .PP \fBReturns\fP .RS 4 .RE .PP .SS "static QString kdk::WindowManager::currentDesktop ()\fC [static]\fP" .PP 获取当前桌面的名称 .PP \fBReturns\fP .RS 4 .RE .PP .SS "void kdk::WindowManager::currentDesktopChanged ()\fC [signal]\fP" .PP 当前桌面改变信号 .PP \fBParameters\fP .RS 4 \fIwid\fP .RE .PP .SS "static QString kdk::WindowManager::currentOutputName ()\fC [static]\fP" .PP currentOutputName .PP \fBSince\fP .RS 4 2\&.5\&.1\&.0 .RE .PP \fBReturns\fP .RS 4 .RE .PP .SS "static QString kdk::WindowManager::currentSeatName ()\fC [static]\fP" .PP currentSeatName .PP \fBSince\fP .RS 4 2\&.5\&.1\&.0 .RE .PP \fBReturns\fP .RS 4 .RE .PP .SS "static void kdk::WindowManager::demandAttention (const WindowId & wid)\fC [static]\fP" .PP 发送demandAttention状态 .PP \fBSince\fP .RS 4 2\&.3\&.1\&.0 .RE .PP \fBParameters\fP .RS 4 \fIwid\fP .RE .PP .SS "void kdk::WindowManager::demandsAttentionChanged (const WindowId & wid)\fC [signal]\fP" .PP demandsAttention状态改变信号 .PP \fBSince\fP .RS 4 2\&.3\&.1\&.0 .RE .PP \fBParameters\fP .RS 4 \fIwid\fP .RE .PP .SS "void kdk::WindowManager::fullscreenChanged (const WindowId & wid)\fC [signal]\fP" .PP 窗口全屏状态改变信号 .PP \fBSince\fP .RS 4 2\&.3\&.1\&.0 .RE .PP \fBParameters\fP .RS 4 \fIwid\fP .RE .PP .SS "void kdk::WindowManager::geometryChanged (const WindowId & wid)\fC [signal]\fP" .PP 窗口位置改变信号 .PP \fBSince\fP .RS 4 2\&.3\&.1\&.0 .RE .PP \fBParameters\fP .RS 4 \fIwid\fP .RE .PP .SS "static quint32 kdk::WindowManager::getPid (const WindowId & windowId)\fC [static]\fP" .PP 获取窗口进程pid .PP \fBReturns\fP .RS 4 .RE .PP .SS "static QString kdk::WindowManager::getProcessName (const WindowId & windowId)\fC [static]\fP" .PP 获取窗口所属的进程名称 .PP \fBSince\fP .RS 4 2\&.3\&.1\&.0 .RE .PP \fBParameters\fP .RS 4 \fIwindowId\fP .RE .PP \fBReturns\fP .RS 4 .RE .PP .SS "static QString kdk::WindowManager::getWindowGroup (const WindowId & windowId)\fC [static]\fP" .PP 获取窗口所在组的组名 .PP \fBParameters\fP .RS 4 \fIwindowId\fP .RE .PP \fBReturns\fP .RS 4 .RE .PP .SS "static QIcon kdk::WindowManager::getWindowIcon (const WindowId & windowId)\fC [static]\fP" .PP 获取窗口图标 .PP \fBParameters\fP .RS 4 \fIwindowId\fP .RE .PP \fBReturns\fP .RS 4 .RE .PP .SS "static QList< WindowId > kdk::WindowManager::getWindowIdByPid (quint32 pid)\fC [static]\fP" .PP getWindowIdByPid .PP \fBSince\fP .RS 4 2\&.5\&.1\&.0 .RE .PP \fBReturns\fP .RS 4 .RE .PP .SS "static QList< WindowId > kdk::WindowManager::getWindowIdByTtile (const QString & title)\fC [static]\fP" .PP getWindowIdByTtile .PP \fBSince\fP .RS 4 2\&.5\&.1\&.0 .RE .PP \fBReturns\fP .RS 4 .RE .PP .SS "static WindowInfo kdk::WindowManager::getwindowInfo (const WindowId & windowId)\fC [static]\fP" .PP 获取窗口信息 .PP \fBParameters\fP .RS 4 \fIwindowId\fP .RE .PP \fBReturns\fP .RS 4 .RE .PP .SS "static QString kdk::WindowManager::getWindowTitle (const WindowId & windowId)\fC [static]\fP" .PP 获取窗口标题 .PP \fBParameters\fP .RS 4 \fIwindowId\fP .RE .PP \fBReturns\fP .RS 4 .RE .PP .SS "static NET::WindowType kdk::WindowManager::getWindowType (const WindowId & windowId)\fC [static]\fP" .PP 获取窗口类型,仅适用于X环境下,wayland下统一返回normal .PP \fBParameters\fP .RS 4 \fIwindowId\fP .RE .PP \fBReturns\fP .RS 4 .RE .PP .SS "void kdk::WindowManager::iconChanged (const WindowId & wid)\fC [signal]\fP" .PP 窗口图标改变信号 .PP \fBSince\fP .RS 4 2\&.3\&.1\&.0 .RE .PP \fBParameters\fP .RS 4 \fIwid\fP .RE .PP .SS "static bool kdk::WindowManager::isHightlight (const WindowId & wid)\fC [static]\fP" .PP isHightlight .PP \fBSince\fP .RS 4 2\&.5\&.1\&.0 .RE .PP \fBParameters\fP .RS 4 \fIwid\fP .RE .PP .SS "static bool kdk::WindowManager::isOnAllDesktops (const WindowId & windowId)\fC [static]\fP" .PP 判断窗口在所有桌面中显示 .PP \fBSince\fP .RS 4 2\&.0\&.2\&.1 .RE .PP \fBParameters\fP .RS 4 \fIwindowId\fP .RE .PP \fBReturns\fP .RS 4 .RE .PP .SS "static bool kdk::WindowManager::isOnCurrentDesktop (const WindowId & id)\fC [static]\fP" .PP 判断窗口是否在当前桌面 .PP \fBParameters\fP .RS 4 \fI窗口id\fP .RE .PP \fBSince\fP .RS 4 2\&.1\&.1\&.0 .RE .PP \fBReturns\fP .RS 4 .RE .PP .SS "static bool kdk::WindowManager::isOnDesktop (const WindowId & id, int desktop)\fC [static]\fP" .PP 判断窗口是否在指定桌面 .PP \fBParameters\fP .RS 4 \fI窗口id\fP .br \fI桌面id\fP .RE .PP \fBSince\fP .RS 4 2\&.1\&.1\&.0 .RE .PP \fBReturns\fP .RS 4 .RE .PP .SS "static bool kdk::WindowManager::isShowingDesktop ()\fC [static]\fP" .PP 判断桌面是否处于显示状态 .PP \fBSince\fP .RS 4 2\&.0\&.2\&.1 .RE .PP \fBReturns\fP .RS 4 .RE .PP .SS "void kdk::WindowManager::keepAboveChanged (const WindowId & wid)\fC [signal]\fP" .PP 窗口置顶状态改变信号 .PP \fBSince\fP .RS 4 2\&.3\&.1\&.0 .RE .PP \fBParameters\fP .RS 4 \fIwid\fP .RE .PP .SS "static void kdk::WindowManager::keepWindowAbove (const WindowId & windowId)\fC [static]\fP" .PP 置顶窗口 .PP \fBParameters\fP .RS 4 \fIwindowId\fP .RE .PP .SS "void kdk::WindowManager::maximizedChanged (const WindowId & wid)\fC [signal]\fP" .PP 窗口最大化状态改变信号 .PP \fBSince\fP .RS 4 2\&.3\&.1\&.0 .RE .PP \fBParameters\fP .RS 4 \fIwid\fP .RE .PP .SS "static void kdk::WindowManager::maximizeWindow (const WindowId & windowId)\fC [static]\fP" .PP 最大化窗口 .PP \fBParameters\fP .RS 4 \fIwindowId\fP .RE .PP .SS "void kdk::WindowManager::minimizedChanged (const WindowId & wid)\fC [signal]\fP" .PP 窗口最小化状态改变信号 .PP \fBSince\fP .RS 4 2\&.3\&.1\&.0 .RE .PP \fBParameters\fP .RS 4 \fIwid\fP .RE .PP .SS "static void kdk::WindowManager::minimizeWindow (const WindowId & windowId)\fC [static]\fP" .PP 最小化窗口 .PP \fBParameters\fP .RS 4 \fIwindowId\fP .RE .PP .SS "void kdk::WindowManager::onAllDesktopsChanged (const WindowId & wid)\fC [signal]\fP" .PP onAllDesktopsChanged .PP \fBSince\fP .RS 4 2\&.3\&.1\&.0 .RE .PP \fBParameters\fP .RS 4 \fIwid\fP .RE .PP .SS "void kdk::WindowManager::outputInfoChanged (OutputInfo *)\fC [signal]\fP" .PP 屏幕信息改变信号 .PP \fBSince\fP .RS 4 2\&.5\&.1\&.0 .RE .PP .SS "static QList< OutputInfo * > kdk::WindowManager::outputsInfo ()\fC [static]\fP" .PP outputsInfo .PP \fBSince\fP .RS 4 2\&.5\&.1\&.0 .RE .PP \fBReturns\fP .RS 4 .RE .PP .SS "static \fBWindowManager\fP * kdk::WindowManager::self ()\fC [static]\fP" .PP self .PP \fBReturns\fP .RS 4 .RE .PP .SS "static void kdk::WindowManager::setGeometry (QWindow * window, const QRect & rect)\fC [static]\fP" .PP 设置窗口位置 .PP \fBParameters\fP .RS 4 \fIwindow\fP .br \fIrect\fP .RE .PP .SS "static void kdk::WindowManager::setGrabKeyboard (QWindow * window, bool grabKeyboard)\fC [static]\fP" .PP setGrabKeyboard .PP \fBSince\fP .RS 4 2\&.5\&.1\&.0 .RE .PP \fBParameters\fP .RS 4 \fIwindow\fP .br \fIgrabKeyboard\fP .RE .PP .SS "static void kdk::WindowManager::setHighlight (const WindowId & wid, bool highlight)\fC [static]\fP" .PP setHighlight .PP \fBSince\fP .RS 4 2\&.5\&.1\&.0 .RE .PP \fBParameters\fP .RS 4 \fIwid\fP .br \fIhighlight\fP .RE .PP .SS "static void kdk::WindowManager::setIconName (QWindow * window, const QString & iconName)\fC [static]\fP" .PP setIconName .PP \fBSince\fP .RS 4 2\&.5\&.1\&.0 .RE .PP \fBParameters\fP .RS 4 \fIwindow\fP .br \fIiconName\fP .RE .PP .SS "static void kdk::WindowManager::setOnAllDesktops (const WindowId & windowId)\fC [static]\fP" .PP 设置窗口在所有桌面中显示 .PP \fBSince\fP .RS 4 2\&.0\&.2\&.1 .RE .PP \fBParameters\fP .RS 4 \fIwid\fP .RE .PP .SS "static void kdk::WindowManager::setOpenUnderCursor (QWindow * window)\fC [static]\fP" .PP setOpenUnderCursor .PP \fBSince\fP .RS 4 2\&.5\&.1\&.0 .RE .PP \fBParameters\fP .RS 4 \fIwindow\fP .RE .PP .SS "static void kdk::WindowManager::setOpenUnderCursor (QWindow * window, int x, int y)\fC [static]\fP" .PP setOpenUnderCursor .PP \fBSince\fP .RS 4 2\&.5\&.1\&.0 .RE .PP \fBParameters\fP .RS 4 \fIwindow\fP .br \fIx\fP .br \fIy\fP .RE .PP .SS "static void kdk::WindowManager::setPanelAutoHide (QWindow * window, bool autoHide)\fC [static]\fP" .PP setPanelAutoHide .PP \fBSince\fP .RS 4 2\&.5\&.1\&.0 .RE .PP \fBParameters\fP .RS 4 \fIwindow\fP .br \fIautoHide\fP .RE .PP .SS "static void kdk::WindowManager::setPanelTakefocus (QWindow * window, bool flag)\fC [static]\fP" .PP 设置panel属性窗体是否获取焦点,仅wayland环境下生效 .PP \fBSince\fP .RS 4 2\&.3\&.1\&.0 .RE .PP \fBParameters\fP .RS 4 \fIwindow\fP .br \fIflag\fP .RE .PP .SS "static void kdk::WindowManager::setSkipSwitcher (QWindow * window, bool skip)\fC [static]\fP" .PP 设置是否跳过窗口选择 .PP \fBSince\fP .RS 4 2\&.0\&.2\&.1 .RE .PP \fBParameters\fP .RS 4 \fIwindow\fP .br \fIskip\fP .RE .PP .SS "static void kdk::WindowManager::setSkipTaskBar (QWindow * window, bool skip)\fC [static]\fP" .PP 设置是否跳过任务栏 .PP \fBSince\fP .RS 4 2\&.0\&.2\&.1 .RE .PP \fBParameters\fP .RS 4 \fIwindow\fP .br \fIskip\fP .RE .PP .SS "static void kdk::WindowManager::setWindowLayer (QWindow * window, WindowLayer layer)\fC [static]\fP" .PP setWindowLayer .PP \fBSince\fP .RS 4 2\&.5\&.1\&.0 .RE .PP \fBParameters\fP .RS 4 \fIwindow\fP .br \fIlayer\fP .RE .PP .SS "static void kdk::WindowManager::setWindowRadius (QWindow * window, int radius)\fC [static]\fP" .PP setWindowRadius .PP \fBSince\fP .RS 4 2\&.5\&.1\&.0 .RE .PP \fBParameters\fP .RS 4 \fIwindow\fP .br \fIradius\fP .RE .PP .SS "static bool kdk::WindowManager::skipSwitcher (const WindowId & windowId)\fC [static]\fP" .PP 判断窗体是否跳过窗口选择 .PP \fBSince\fP .RS 4 2\&.0\&.2\&.1 .RE .PP \fBParameters\fP .RS 4 \fIwindowId\fP .RE .PP \fBReturns\fP .RS 4 .RE .PP .SS "void kdk::WindowManager::skipSwitcherChanged (const WindowId & wid)\fC [signal]\fP" .PP 跳过窗口选择器状态改变信号 .PP \fBSince\fP .RS 4 2\&.3\&.1\&.0 .RE .PP \fBParameters\fP .RS 4 \fIwid\fP .RE .PP .SS "static bool kdk::WindowManager::skipTaskBar (const WindowId & windowId)\fC [static]\fP" .PP 判断窗体是否跳过任务栏 .PP \fBSince\fP .RS 4 2\&.0\&.2\&.1 .RE .PP \fBParameters\fP .RS 4 \fIwindowId\fP .RE .PP \fBReturns\fP .RS 4 .RE .PP .SS "void kdk::WindowManager::skipTaskbarChanged (const WindowId & wid)\fC [signal]\fP" .PP 跳过任务栏状态改变信号 .PP \fBSince\fP .RS 4 2\&.3\&.1\&.0 .RE .PP \fBParameters\fP .RS 4 \fIwid\fP .RE .PP .SS "void kdk::WindowManager::titleChanged (const WindowId & wid)\fC [signal]\fP" .PP 窗口标题改变信号 .PP \fBSince\fP .RS 4 2\&.3\&.1\&.0 .RE .PP \fBParameters\fP .RS 4 \fIwid\fP .RE .PP .SS "void kdk::WindowManager::windowAdded (const WindowId & windowId)\fC [signal]\fP" .PP 窗口添加信号 .PP \fBParameters\fP .RS 4 \fIwindowId\fP .RE .PP .SS "void kdk::WindowManager::windowChanged (const WindowId & wid)\fC [signal]\fP" .PP 窗口改变信号 .PP \fBParameters\fP .RS 4 \fIwid\fP .RE .PP .SS "static QRect kdk::WindowManager::windowGeometry (const WindowId & windowId)\fC [static]\fP" .PP windowGeometry .PP \fBSince\fP .RS 4 2\&.5\&.1\&.0 .RE .PP \fBParameters\fP .RS 4 \fIwindowId\fP .RE .PP \fBReturns\fP .RS 4 .RE .PP .SS "static WindowLayer kdk::WindowManager::windowLayer (QWindow * window)\fC [static]\fP" .PP windowLayer .PP \fBSince\fP .RS 4 2\&.5\&.1\&.0 .RE .PP \fBParameters\fP .RS 4 \fIwindow\fP .RE .PP \fBReturns\fP .RS 4 .RE .PP .SS "void kdk::WindowManager::windowRemoved (const WindowId & windowId)\fC [signal]\fP" .PP 窗口删除信号 .PP \fBParameters\fP .RS 4 \fIwindowId\fP .RE .PP .SS "static QList< WindowId > kdk::WindowManager::windows ()\fC [static]\fP" .PP 获取当前窗口列表 .PP \fBReturns\fP .RS 4 .RE .PP .SH "Author" .PP Generated automatically by Doxygen for LIBKYSDK-APPLICATIONS from the source code\&. libkysdk-applications/doxygen/man/man3/kdk_KSettingGroup.30000664000175000017500000001206115104543305022550 0ustar fengfeng.TH "kdk::KSettingGroup" 3 "Version version:3.0" "LIBKYSDK-APPLICATIONS" \" -*- nroff -*- .ad l .nh .SH NAME kdk::KSettingGroup .SH SYNOPSIS .br .PP .PP Inherits \fBkdk::KBaseFrame\fP\&. .SS "Public Member Functions" .in +1c .ti -1c .RI "\fBKSettingGroup\fP (QWidget *parent=nullptr, Shape shape=QFrame::NoFrame, \fBBorderRadiusStyle\fP style=\fBBorderRadiusStyle::None\fP)" .br .RI "创建一个 Spacing 为 1 的垂直布局 Frame " .ti -1c .RI "void \fBaddWidget\fP (QFrame *item, bool autoUpdateShape=true, bool visible=true)" .br .RI "为 mainLayout 添加控件并更新圆角 " .ti -1c .RI "void \fBinsertWidget\fP (int index, QFrame *item, bool autoUpdateShape=true, bool visible=true)" .br .RI "为 mainLayout 添加控件并更新圆角 " .ti -1c .RI "void \fBremoveWidget\fP (QWidget *w, bool autoUpdateShape=true)" .br .RI "为 mainLayout 移除控件并更新圆角 " .ti -1c .RI "void \fBupdateShape\fP ()" .br .RI "更新圆角 " .ti -1c .RI "QVBoxLayout * \fBlayout\fP ()" .br .RI "获取 mainLayout " .ti -1c .RI "void \fBsetLastRadiusStyle\fP (\fBBorderRadiusStyle\fP style)" .br .RI "设置最后一个frame的圆角风格 " .ti -1c .RI "void \fBsetOneRadiusStyle\fP (\fBBorderRadiusStyle\fP style)" .br .RI "设置仅一个frame时的圆角风格 " .ti -1c .RI "int \fBshowItemsCount\fP ()" .br .RI "获取显示的子控件个数 " .ti -1c .RI "void \fBremoveAndDeleteAllWidget\fP ()" .br .RI "移除并删除所有子控件 " .in -1c Public Member Functions inherited from \fBkdk::KBaseFrame\fP .in +1c .ti -1c .RI "\fBKBaseFrame\fP (QWidget *parent=nullptr, \fBBorderRadiusStyle\fP style=\fBAround\fP, bool heightAdaptive=false)" .br .RI "构造函数 " .ti -1c .RI "void \fBsetRadiusType\fP (\fBBorderRadiusStyle\fP style)" .br .RI "设置圆角风格 " .ti -1c .RI "bool \fBgetTabletMode\fP ()" .br .RI "获取平板模式 " .ti -1c .RI "bool \fBisContainer\fP ()" .br .RI "获取是否是一个容器frame,此时settinggroup需要设置的是其子frame的圆角 " .ti -1c .RI "void \fBsetContainer\fP (bool b=false)" .br .RI "设置该frame是否是一个容器frame,如果是同时setFrameShape(NoFrame); " .in -1c .SS "Protected Member Functions" .in +1c .ti -1c .RI "bool \fBeventFilter\fP (QObject *watched, QEvent *event)" .br .in -1c Protected Member Functions inherited from \fBkdk::KBaseFrame\fP .in +1c .ti -1c .RI "void \fBpaintEvent\fP (QPaintEvent *e)" .br .in -1c .SS "Additional Inherited Members" Public Types inherited from \fBkdk::KBaseFrame\fP .in +1c .ti -1c .RI "enum \fBBorderRadiusStyle\fP { \fBTop\fP, \fBNone\fP, \fBBottom\fP, \fBAround\fP }" .br .in -1c Signals inherited from \fBkdk::KBaseFrame\fP .in +1c .ti -1c .RI "void \fBtabletModeChanged\fP (bool b)" .br .in -1c .SH "Constructor & Destructor Documentation" .PP .SS "kdk::KSettingGroup::KSettingGroup (QWidget * parent = \fCnullptr\fP, Shape shape = \fCQFrame::NoFrame\fP, \fBBorderRadiusStyle\fP style = \fC\fBBorderRadiusStyle::None\fP\fP)\fC [explicit]\fP" .PP 创建一个 Spacing 为 1 的垂直布局 Frame .PP \fBParameters\fP .RS 4 \fIShape\fP 设置frameShap .br \fIstyle\fP 设置圆角(None:无圆角,Top:上圆角,Bottom:下圆角,Around:四圆角) .br \fIparent\fP .RE .PP .SH "Member Function Documentation" .PP .SS "void kdk::KSettingGroup::addWidget (QFrame * item, bool autoUpdateShape = \fCtrue\fP, bool visible = \fCtrue\fP)" .PP 为 mainLayout 添加控件并更新圆角 .PP \fBParameters\fP .RS 4 \fIitem\fP 需要添加的控件 .br \fIautoUpdateShape\fP 是否自动更新item圆角样式 .br \fIvisible\fP 实际未show控件时isVisible总是false,导致圆角无法正常,因此重新设置,应为Qt的BUG .RE .PP .SS "void kdk::KSettingGroup::insertWidget (int index, QFrame * item, bool autoUpdateShape = \fCtrue\fP, bool visible = \fCtrue\fP)" .PP 为 mainLayout 添加控件并更新圆角 .PP \fBParameters\fP .RS 4 \fIindex\fP 序号 .br \fIitem\fP 需要添加的控件 .br \fIautoUpdateShape\fP 是否自动更新item圆角样式 .br \fIvisible\fP 实际未show控件时isVisible总是false,导致圆角无法正常,因此重新设置,应为Qt的BUG .RE .PP .SS "QVBoxLayout * kdk::KSettingGroup::layout ()" .PP 获取 mainLayout .PP \fBReturns\fP .RS 4 QVBoxLayout mainLayout .RE .PP .SS "void kdk::KSettingGroup::removeWidget (QWidget * w, bool autoUpdateShape = \fCtrue\fP)" .PP 为 mainLayout 移除控件并更新圆角 .PP \fBParameters\fP .RS 4 \fIw\fP 需要移除的控件 .br \fIautoUpdateShape\fP 是否自动更新item圆角样式 .RE .PP .SS "void kdk::KSettingGroup::setLastRadiusStyle (\fBBorderRadiusStyle\fP style)" .PP 设置最后一个frame的圆角风格 .PP \fBParameters\fP .RS 4 \fIstyle\fP 圆角风格 .RE .PP .SS "void kdk::KSettingGroup::setOneRadiusStyle (\fBBorderRadiusStyle\fP style)" .PP 设置仅一个frame时的圆角风格 .PP \fBParameters\fP .RS 4 \fIstyle\fP .RE .PP .SS "int kdk::KSettingGroup::showItemsCount ()" .PP 获取显示的子控件个数 .PP \fBReturns\fP .RS 4 int 显示的子控件个数 .RE .PP .SH "Author" .PP Generated automatically by Doxygen for LIBKYSDK-APPLICATIONS from the source code\&. libkysdk-applications/doxygen/man/man3/kdk_KToolBar.30000664000175000017500000000353715104543305021470 0ustar fengfeng.TH "kdk::KToolBar" 3 "Version version:3.0" "LIBKYSDK-APPLICATIONS" \" -*- nroff -*- .ad l .nh .SH NAME kdk::KToolBar .SH SYNOPSIS .br .PP .PP \fC#include \fP .PP Inherits QWidget\&. .SS "Public Member Functions" .in +1c .ti -1c .RI "\fBKToolBar\fP (QWidget *parent=nullptr)" .br .ti -1c .RI "Qt::Orientation \fBorientation\fP ()" .br .ti -1c .RI "void \fBsetOrientation\fP (Qt::Orientation orientation)" .br .ti -1c .RI "\fBKToolButton\fP * \fBaddButton\fP (QIcon icon)" .br .ti -1c .RI "\fBKToolButton\fP * \fBaddButton\fP (QString string)" .br .ti -1c .RI "QList< \fBKToolButton\fP * > \fBaddButton\fP (QList< QIcon > list)" .br .ti -1c .RI "QList< \fBKToolButton\fP * > \fBaddButton\fP (QList< QString > list)" .br .ti -1c .RI "QList< \fBKToolButton\fP * > \fBbuttonList\fP ()" .br .ti -1c .RI "void \fBremoveButton\fP (\fBKToolButton\fP *button)" .br .ti -1c .RI "void \fBremoveButton\fP (int id)" .br .ti -1c .RI "void \fBremoveButton\fP (QList< \fBKToolButton\fP * > list)" .br .ti -1c .RI "void \fBsetBorderRadius\fP (int radius)" .br .ti -1c .RI "int \fBborderRadius\fP ()" .br .ti -1c .RI "void \fBsetExclusive\fP (bool)" .br .ti -1c .RI "bool \fBexclusive\fP ()" .br .ti -1c .RI "void \fBsetCheckable\fP (bool flag)" .br .ti -1c .RI "bool \fBisCheckable\fP ()" .br .ti -1c .RI "QList< \fBKToolButton\fP * > \fBcheckedButton\fP ()" .br .ti -1c .RI "void \fBsetLineVisible\fP (bool flag)" .br .ti -1c .RI "bool \fBisLineVisible\fP ()" .br .ti -1c .RI "void \fBsetBackgroundColorEnabled\fP (bool flag)" .br .ti -1c .RI "bool \fBbackgroundColorEnabled\fP ()" .br .in -1c .SS "Protected Member Functions" .in +1c .ti -1c .RI "void \fBpaintEvent\fP (QPaintEvent *event)" .br .in -1c .SH "Detailed Description" .PP .PP \fBSince\fP .RS 4 2\&.5\&.2\&.0 .RE .PP .SH "Author" .PP Generated automatically by Doxygen for LIBKYSDK-APPLICATIONS from the source code\&. libkysdk-applications/doxygen/man/man3/kdk_KInputDialog.30000664000175000017500000002117015104543305022336 0ustar fengfeng.TH "kdk::KInputDialog" 3 "Version version:3.0" "LIBKYSDK-APPLICATIONS" \" -*- nroff -*- .ad l .nh .SH NAME kdk::KInputDialog \- 输入对话框,接口与 QInputDialog 相同。 .SH SYNOPSIS .br .PP .PP \fC#include \fP .PP Inherits \fBkdk::KDialog\fP\&. .SS "Public Types" .in +1c .ti -1c .RI "enum \fBInputDialogOption\fP { \fBNoButtons\fP = 0x00000001, \fBUseListViewForComboBoxItems\fP = 0x00000002, \fBUsePlainTextEditForTextInput\fP = 0x00000004 }" .br .ti -1c .RI "enum \fBInputMode\fP { \fBTextInput\fP, \fBIntInput\fP, \fBDoubleInput\fP }" .br .in -1c .SS "Signals" .in +1c .ti -1c .RI "void \fBtextValueChanged\fP (const QString &text)" .br .ti -1c .RI "void \fBtextValueSelected\fP (const QString &text)" .br .ti -1c .RI "void \fBintValueChanged\fP (int value)" .br .ti -1c .RI "void \fBintValueSelected\fP (int value)" .br .ti -1c .RI "void \fBdoubleValueChanged\fP (double value)" .br .ti -1c .RI "void \fBdoubleValueSelected\fP (double value)" .br .in -1c .SS "Public Member Functions" .in +1c .ti -1c .RI "\fBKInputDialog\fP (QWidget *parent=nullptr)" .br .ti -1c .RI "void \fBsetInputMode\fP (InputMode mode)" .br .RI "设置输入模式 " .ti -1c .RI "InputMode \fBinputMode\fP () const" .br .RI "返回输入模式 " .ti -1c .RI "void \fBsetLabelText\fP (const QString &text)" .br .RI "设置提示信息 " .ti -1c .RI "QString \fBlabelText\fP () const" .br .RI "获取提示信息 " .ti -1c .RI "void \fBsetOption\fP (InputDialogOption option, bool on=true)" .br .RI "设置option类型 " .ti -1c .RI "bool \fBtestOption\fP (InputDialogOption option) const" .br .RI "返回是否设置了option类型 " .ti -1c .RI "void \fBsetOptions\fP (InputDialogOptions \fBoptions\fP)" .br .RI "设置options类型 " .ti -1c .RI "InputDialogOptions \fBoptions\fP () const" .br .RI "返回options类型 " .ti -1c .RI "void \fBsetTextValue\fP (const QString &text)" .br .RI "设置文本值 " .ti -1c .RI "QString \fBtextValue\fP () const" .br .RI "获取当前文本值 " .ti -1c .RI "void \fBsetTextEchoMode\fP (QLineEdit::EchoMode mode)" .br .RI "设置保存文本值的回声模式 QLineEdit::EchoMode " .ti -1c .RI "QLineEdit::EchoMode \fBtextEchoMode\fP () const" .br .RI "返回保存文本值的回声模式 " .ti -1c .RI "void \fBsetComboBoxEditable\fP (bool editable)" .br .RI "设置输入对话框中使用的组合框是否可编辑 " .ti -1c .RI "bool \fBisComboBoxEditable\fP () const" .br .RI "返回输入对话框中使用的组合框是否可编辑 " .ti -1c .RI "void \fBsetComboBoxItems\fP (const QStringList &items)" .br .RI "设置输入对话框组合框中使用的项目 " .ti -1c .RI "QStringList \fBcomboBoxItems\fP () const" .br .RI "返回输入对话框组合框中使用的项目 " .ti -1c .RI "void \fBsetIntValue\fP (int value)" .br .RI "设置int类型值 " .ti -1c .RI "int \fBintValue\fP () const" .br .RI "获取int类型值 " .ti -1c .RI "void \fBsetIntMinimum\fP (int min)" .br .RI "设置int类型最小值 " .ti -1c .RI "int \fBintMinimum\fP () const" .br .RI "获取int类型最小值 " .ti -1c .RI "void \fBsetIntMaximum\fP (int max)" .br .RI "设置int类型最大值 " .ti -1c .RI "int \fBintMaximum\fP () const" .br .RI "获取int类型最大值 " .ti -1c .RI "void \fBsetIntRange\fP (int min, int max)" .br .RI "设置int类型值范围 " .ti -1c .RI "void \fBsetIntStep\fP (int step)" .br .RI "设置步长 " .ti -1c .RI "int \fBintStep\fP () const" .br .RI "获取int类型步长 " .ti -1c .RI "void \fBsetDoubleValue\fP (double value)" .br .RI "设置double类型值 " .ti -1c .RI "double \fBdoubleValue\fP () const" .br .RI "获取double类型值 " .ti -1c .RI "void \fBsetDoubleMinimum\fP (double min)" .br .RI "设置double类型最小值 " .ti -1c .RI "double \fBdoubleMinimum\fP () const" .br .RI "获取double类型最小值 " .ti -1c .RI "void \fBsetDoubleMaximum\fP (double max)" .br .RI "设置double类型最大值 " .ti -1c .RI "double \fBdoubleMaximum\fP () const" .br .RI "获取double类型最大值 " .ti -1c .RI "void \fBsetDoubleRange\fP (double min, double max)" .br .RI "设置double类型值范围 " .ti -1c .RI "void \fBsetDoubleDecimals\fP (int decimals)" .br .RI "以小数为单位设置双自旋盒的精度 " .ti -1c .RI "int \fBdoubleDecimals\fP () const" .br .RI "获取双自旋盒的精度 " .ti -1c .RI "void \fBsetOkButtonText\fP (const QString &text)" .br .RI "设置OK按钮的文本 " .ti -1c .RI "QString \fBokButtonText\fP () const" .br .RI "获取OK按钮的文本 " .ti -1c .RI "void \fBsetCancelButtonText\fP (const QString &text)" .br .RI "设置cancel按钮的文本 " .ti -1c .RI "QString \fBcancelButtonText\fP () const" .br .RI "获取cancel按钮的文本 " .ti -1c .RI "void \fBopen\fP (QObject *receiver, const char *member)" .br .RI "将对话框显示为窗口模式对话框,并立即返回。 " .ti -1c .RI "QSize \fBminimumSizeHint\fP () const override" .br .RI "获取部件的推荐最小尺寸 " .ti -1c .RI "QSize \fBsizeHint\fP () const override" .br .RI "获取保存部件的推荐尺寸 " .ti -1c .RI "void \fBsetVisible\fP (bool visible) override" .br .RI "设置窗口部件是否可见 " .ti -1c .RI "QString \fBplaceholderText\fP () const" .br .RI "获取背景提示文本 " .ti -1c .RI "void \fBsetPlaceholderText\fP (const QString &)" .br .RI "设置背景提示文本 " .ti -1c .RI "void \fBsetDoubleStep\fP (double step)" .br .RI "设置doubel类型步长 " .ti -1c .RI "double \fBdoubleStep\fP () const" .br .RI "获取doubel类型步长 " .ti -1c .RI "void \fBdone\fP (int result) override" .br .in -1c Public Member Functions inherited from \fBkdk::KDialog\fP .in +1c .ti -1c .RI "\fBKDialog\fP (QWidget *parent=nullptr)" .br .ti -1c .RI "void \fBsetWindowIcon\fP (const QIcon &icon)" .br .RI "设置对话框图标 " .ti -1c .RI "void \fBsetWindowIcon\fP (const QString &iconName)" .br .RI "设置对话框图标 " .ti -1c .RI "void \fBsetWindowTitle\fP (const QString &)" .br .RI "设置对话框标题名称 " .ti -1c .RI "QPushButton * \fBmaximumButton\fP ()" .br .RI "获取最大化按钮 " .ti -1c .RI "QPushButton * \fBminimumButton\fP ()" .br .RI "获取最小化按钮 " .ti -1c .RI "QPushButton * \fBcloseButton\fP ()" .br .RI "获取关闭按钮 " .ti -1c .RI "\fBKMenuButton\fP * \fBmenuButton\fP ()" .br .RI "获取下拉菜单按钮 " .ti -1c .RI "QWidget * \fBmainWidget\fP ()" .br .RI "获取主内容区Widget " .ti -1c .RI "\fBKWindowButtonBar\fP * \fBwindowButtonBar\fP ()" .br .RI "windowButtonBar " .ti -1c .RI "\fBKIconBar\fP * \fBiconBar\fP ()" .br .RI "iconBar " .in -1c .SS "Static Public Member Functions" .in +1c .ti -1c .RI "static QString \fBgetText\fP (QWidget *parent, const QString &label, QLineEdit::EchoMode echo=QLineEdit::Normal, const QString &text=QString(), bool *ok=nullptr, Qt::WindowFlags flags=Qt::WindowFlags(), Qt::InputMethodHints inputMethodHints=Qt::ImhNone)" .br .RI "静态便利函数,用于从用户处获取单行字符串。 " .ti -1c .RI "static QString \fBgetMultiLineText\fP (QWidget *parent, const QString &label, const QString &text=QString(), bool *ok=nullptr, Qt::WindowFlags flags=Qt::WindowFlags(), Qt::InputMethodHints inputMethodHints=Qt::ImhNone)" .br .RI "静态便利函数,用于从用户处获取多行字符串。 " .ti -1c .RI "static QString \fBgetItem\fP (QWidget *parent, const QString &label, const QStringList &items, int current=0, bool editable=true, bool *ok=nullptr, Qt::WindowFlags flags=Qt::WindowFlags(), Qt::InputMethodHints inputMethodHints=Qt::ImhNone)" .br .RI "静态便利函数,用于让用户从字符串列表中选择一个项目。 " .ti -1c .RI "static int \fBgetInt\fP (QWidget *parent, const QString &label, int value=0, int minValue=\-2147483647, int maxValue=2147483647, int step=1, bool *ok=nullptr, Qt::WindowFlags flags=Qt::WindowFlags())" .br .RI "静态便利函数,用于从用户处获取整数输入值。 " .ti -1c .RI "static double \fBgetDouble\fP (QWidget *parent, const QString &label, double value=0, double minValue=\-2147483647, double maxValue=2147483647, int decimals=1, bool *ok=nullptr, Qt::WindowFlags flags=Qt::WindowFlags())" .br .RI "静态便利函数,用于从用户处获取浮点数。 " .in -1c .SS "Protected Member Functions" .in +1c .ti -1c .RI "void \fBchangeTheme\fP ()" .br .in -1c Protected Member Functions inherited from \fBkdk::KDialog\fP .in +1c .ti -1c .RI "bool \fBeventFilter\fP (QObject *target, QEvent *event) override" .br .ti -1c .RI "void \fBchangeTheme\fP ()" .br .ti -1c .RI "void \fBchangeIconStyle\fP ()" .br .ti -1c .RI "QBoxLayout * \fBmainLayout\fP ()" .br .in -1c .SH "Detailed Description" .PP 输入对话框,接口与 QInputDialog 相同。 .PP \fBSince\fP .RS 4 1\&.0\&.0 .RE .PP .SH "Author" .PP Generated automatically by Doxygen for LIBKYSDK-APPLICATIONS from the source code\&. libkysdk-applications/doxygen/man/man3/kdk_KDragWidget.30000664000175000017500000000564315104543305022147 0ustar fengfeng.TH "kdk::KDragWidget" 3 "Version version:3.0" "LIBKYSDK-APPLICATIONS" \" -*- nroff -*- .ad l .nh .SH NAME kdk::KDragWidget \- 拖动文件或文件夹,可识别并获取文件或文件夹路径 .SH SYNOPSIS .br .PP .PP \fC#include \fP .PP Inherits QWidget\&. .SS "Signals" .in +1c .ti -1c .RI "void \fBgetPath\fP (QString)" .br .ti -1c .RI "void \fBgetPathList\fP (QStringList)" .br .RI "获取列表信号 " .in -1c .SS "Public Member Functions" .in +1c .ti -1c .RI "\fBKDragWidget\fP (QWidget *parent=nullptr)" .br .ti -1c .RI "\fBKPushButton\fP * \fBiconButton\fP ()" .br .RI "iconButton " .ti -1c .RI "QLabel * \fBtextLabel\fP ()" .br .RI "textLabel " .ti -1c .RI "QFileDialog * \fBfileDialog\fP ()" .br .RI "fileDialog " .ti -1c .RI "void \fBsetNameFilter\fP (const QString &filter)" .br .RI "将文件对话框中使用的过滤器设置为给定的过滤器。 " .ti -1c .RI "void \fBsetNameFilters\fP (const QStringList &filters)" .br .RI "设置文件对话框中使用的过滤器。 " .in -1c .SS "Protected Member Functions" .in +1c .ti -1c .RI "void \fBmouseMoveEvent\fP (QMouseEvent *event)" .br .ti -1c .RI "void \fBmousePressEvent\fP (QMouseEvent *event)" .br .ti -1c .RI "void \fBmouseReleaseEvent\fP (QMouseEvent *event)" .br .ti -1c .RI "void \fBkeyPressEvent\fP (QKeyEvent *event)" .br .ti -1c .RI "void \fBkeyReleaseEvent\fP (QKeyEvent *event)" .br .ti -1c .RI "void \fBpaintEvent\fP (QPaintEvent *event)" .br .ti -1c .RI "bool \fBeventFilter\fP (QObject *watched, QEvent *event)" .br .ti -1c .RI "void \fBdragEnterEvent\fP (QDragEnterEvent *event)" .br .ti -1c .RI "void \fBdragLeaveEvent\fP (QDragLeaveEvent *event)" .br .ti -1c .RI "void \fBdragMoveEvent\fP (QDragMoveEvent *event)" .br .ti -1c .RI "void \fBdropEvent\fP (QDropEvent *event)" .br .in -1c .SH "Detailed Description" .PP 拖动文件或文件夹,可识别并获取文件或文件夹路径 .PP \fBSince\fP .RS 4 2\&.3\&.1\&.0 .RE .PP .SH "Member Function Documentation" .PP .SS "QFileDialog * kdk::KDragWidget::fileDialog ()" .PP fileDialog .PP \fBReturns\fP .RS 4 返回QFiledialog .RE .PP .SS "void kdk::KDragWidget::getPathList (QStringList)\fC [signal]\fP" .PP 获取列表信号 .PP \fBSince\fP .RS 4 2\&.5\&.1\&.2-0k1\&.0 .RE .PP .SS "\fBKPushButton\fP * kdk::KDragWidget::iconButton ()" .PP iconButton .PP \fBReturns\fP .RS 4 返回iconbutton .RE .PP .SS "void kdk::KDragWidget::setNameFilter (const QString & filter)" .PP 将文件对话框中使用的过滤器设置为给定的过滤器。 .PP \fBParameters\fP .RS 4 \fIfilter\fP .RE .PP .SS "void kdk::KDragWidget::setNameFilters (const QStringList & filters)" .PP 设置文件对话框中使用的过滤器。 .PP \fBParameters\fP .RS 4 \fIfilters\fP .RE .PP .SS "QLabel * kdk::KDragWidget::textLabel ()" .PP textLabel .PP \fBReturns\fP .RS 4 返回textlabel .RE .PP .SH "Author" .PP Generated automatically by Doxygen for LIBKYSDK-APPLICATIONS from the source code\&. libkysdk-applications/doxygen/man/man3/kdk_KTextEdit.30000664000175000017500000000332315104543305021651 0ustar fengfeng.TH "kdk::KTextEdit" 3 "Version version:3.0" "LIBKYSDK-APPLICATIONS" \" -*- nroff -*- .ad l .nh .SH NAME kdk::KTextEdit \- 继承QTextEdit .SH SYNOPSIS .br .PP .PP \fC#include \fP .PP Inherits QTextEdit\&. .SS "Public Member Functions" .in +1c .ti -1c .RI "\fBKTextEdit\fP (QWidget *parent=nullptr)" .br .ti -1c .RI "void \fBsetLabelVisible\fP (bool flag)" .br .RI "设置label是否可见 " .ti -1c .RI "void \fBsetPixmap\fP (const QPixmap &\fBpixmap\fP)" .br .RI "设置图标 " .ti -1c .RI "const QPixmap * \fBpixmap\fP () const" .br .RI "获取图标 " .ti -1c .RI "void \fBsetLabelText\fP (const QString &text)" .br .RI "设置label文本 " .ti -1c .RI "void \fBsetReadOnly\fP (bool ro)" .br .RI "设置是否可编辑状态 " .in -1c .SS "Protected Member Functions" .in +1c .ti -1c .RI "void \fBpaintEvent\fP (QPaintEvent *event)" .br .in -1c .SH "Detailed Description" .PP 继承QTextEdit .PP \fBSince\fP .RS 4 2\&.4\&.1\&.0 .RE .PP .SH "Member Function Documentation" .PP .SS "const QPixmap * kdk::KTextEdit::pixmap () const" .PP 获取图标 .PP \fBReturns\fP .RS 4 .RE .PP .SS "void kdk::KTextEdit::setLabelText (const QString & text)" .PP 设置label文本 .PP \fBParameters\fP .RS 4 \fItext\fP .RE .PP .SS "void kdk::KTextEdit::setLabelVisible (bool flag)" .PP 设置label是否可见 .PP \fBParameters\fP .RS 4 \fIflag\fP .RE .PP .SS "void kdk::KTextEdit::setPixmap (const QPixmap & pixmap)" .PP 设置图标 .PP \fBParameters\fP .RS 4 \fIpixmap\fP .RE .PP .SS "void kdk::KTextEdit::setReadOnly (bool ro)" .PP 设置是否可编辑状态 .PP \fBParameters\fP .RS 4 \fIro\fP .RE .PP .SH "Author" .PP Generated automatically by Doxygen for LIBKYSDK-APPLICATIONS from the source code\&. libkysdk-applications/doxygen/man/man3/kdk_KItemWidget.30000664000175000017500000000125615104543305022164 0ustar fengfeng.TH "kdk::KItemWidget" 3 "Version version:3.0" "LIBKYSDK-APPLICATIONS" \" -*- nroff -*- .ad l .nh .SH NAME kdk::KItemWidget .SH SYNOPSIS .br .PP .PP Inherits QWidget\&. .SS "Public Member Functions" .in +1c .ti -1c .RI "\fBKItemWidget\fP (const QIcon &Myicon, QString MmainText, QString MsecText, QWidget *parent)" .br .ti -1c .RI "void \fBSetInverse\fP ()" .br .ti -1c .RI "void \fBCancelInverse\fP ()" .br .ti -1c .RI "void \fBSetIconSize\fP (QSize size)" .br .in -1c .SS "Protected Member Functions" .in +1c .ti -1c .RI "void \fBpaintEvent\fP (QPaintEvent *event)" .br .in -1c .SH "Author" .PP Generated automatically by Doxygen for LIBKYSDK-APPLICATIONS from the source code\&. libkysdk-applications/doxygen/man/man3/kdk_KProgressDialog.30000664000175000017500000001100715104543305023041 0ustar fengfeng.TH "kdk::KProgressDialog" 3 "Version version:3.0" "LIBKYSDK-APPLICATIONS" \" -*- nroff -*- .ad l .nh .SH NAME kdk::KProgressDialog \- 进度对话框,会实时显示当前进度 .SH SYNOPSIS .br .PP .PP \fC#include \fP .PP Inherits \fBkdk::KDialog\fP\&. .SS "Public Slots" .in +1c .ti -1c .RI "void \fBcancel\fP ()" .br .RI "取消进度条 " .ti -1c .RI "void \fBreset\fP ()" .br .RI "重置进度条 " .ti -1c .RI "void \fBsetMaximum\fP (int \fBmaximum\fP)" .br .RI "设置最大值 " .ti -1c .RI "void \fBsetMinimum\fP (int \fBminimum\fP)" .br .RI "设置最小值 " .ti -1c .RI "void \fBsetRange\fP (int \fBminimum\fP, int \fBmaximum\fP)" .br .RI "设置范围 " .ti -1c .RI "void \fBsetValue\fP (int progress)" .br .RI "设置当前值 " .ti -1c .RI "void \fBsetLabelText\fP (const QString &text)" .br .RI "设置提示内容 " .ti -1c .RI "void \fBsetCancelButtonText\fP (const QString &text)" .br .RI "设置取消按钮内容 " .ti -1c .RI "void \fBsetSubContent\fP (const QString &text)" .br .RI "设置次级内容 " .in -1c .SS "Signals" .in +1c .ti -1c .RI "void \fBcanceled\fP ()" .br .in -1c .SS "Public Member Functions" .in +1c .ti -1c .RI "\fBKProgressDialog\fP (QWidget *parent=nullptr)" .br .ti -1c .RI "\fBKProgressDialog\fP (const QString &\fBlabelText\fP, const QString &cancelButtonText='cancel', int \fBminimum\fP=0, int \fBmaximum\fP=100, QWidget *parent=nullptr)" .br .ti -1c .RI "void \fBsetLabel\fP (QLabel *label)" .br .RI "设置提示文字 " .ti -1c .RI "void \fBsetCancelButton\fP (QPushButton *button)" .br .RI "设置取消按钮 " .ti -1c .RI "void \fBsetBar\fP (QProgressBar *bar)" .br .RI "设置进度条 " .ti -1c .RI "void \fBsetSuffix\fP (const QString &suffix)" .br .RI "设置detail的后缀 " .ti -1c .RI "void \fBsetSuffix\fP (const QString &numerator, const QString &denominator)" .br .ti -1c .RI "void \fBsetSpeed\fP (const float &speed)" .br .ti -1c .RI "void \fBsetShowDetail\fP (bool flag)" .br .RI "设置是否显示详细信息 " .ti -1c .RI "int \fBminimum\fP () const" .br .RI "返回最小值 " .ti -1c .RI "int \fBmaximum\fP () const" .br .RI "返回最大值 " .ti -1c .RI "int \fBvalue\fP () const" .br .RI "返回当前值 " .ti -1c .RI "QString \fBlabelText\fP () const" .br .RI "返回提示内容 " .ti -1c .RI "void \fBsetAutoReset\fP (bool \fBreset\fP)" .br .RI "设置自动重置 " .ti -1c .RI "bool \fBautoReset\fP () const" .br .RI "返回是否自动重置 " .ti -1c .RI "void \fBsetAutoClose\fP (bool close)" .br .RI "设置是否自动关闭对话框 " .ti -1c .RI "bool \fBautoClose\fP () const" .br .RI "返回是否自动关闭对话框 " .ti -1c .RI "QProgressBar * \fBprogressBar\fP ()" .br .RI "获取进度条 " .ti -1c .RI "void \fBsetBarType\fP (const \fBBarType\fP &type)" .br .ti -1c .RI "void \fBaddButton\fP (QPushButton *button)" .br .ti -1c .RI "void \fBremoveButton\fP (QPushButton *button)" .br .ti -1c .RI "\fBBarType\fP \fBmyType\fP ()" .br .in -1c Public Member Functions inherited from \fBkdk::KDialog\fP .in +1c .ti -1c .RI "\fBKDialog\fP (QWidget *parent=nullptr)" .br .ti -1c .RI "void \fBsetWindowIcon\fP (const QIcon &icon)" .br .RI "设置对话框图标 " .ti -1c .RI "void \fBsetWindowIcon\fP (const QString &iconName)" .br .RI "设置对话框图标 " .ti -1c .RI "void \fBsetWindowTitle\fP (const QString &)" .br .RI "设置对话框标题名称 " .ti -1c .RI "QPushButton * \fBmaximumButton\fP ()" .br .RI "获取最大化按钮 " .ti -1c .RI "QPushButton * \fBminimumButton\fP ()" .br .RI "获取最小化按钮 " .ti -1c .RI "QPushButton * \fBcloseButton\fP ()" .br .RI "获取关闭按钮 " .ti -1c .RI "\fBKMenuButton\fP * \fBmenuButton\fP ()" .br .RI "获取下拉菜单按钮 " .ti -1c .RI "QWidget * \fBmainWidget\fP ()" .br .RI "获取主内容区Widget " .ti -1c .RI "\fBKWindowButtonBar\fP * \fBwindowButtonBar\fP ()" .br .RI "windowButtonBar " .ti -1c .RI "\fBKIconBar\fP * \fBiconBar\fP ()" .br .RI "iconBar " .in -1c .SS "Protected Member Functions" .in +1c .ti -1c .RI "void \fBchangeTheme\fP ()" .br .in -1c Protected Member Functions inherited from \fBkdk::KDialog\fP .in +1c .ti -1c .RI "bool \fBeventFilter\fP (QObject *target, QEvent *event) override" .br .ti -1c .RI "void \fBchangeTheme\fP ()" .br .ti -1c .RI "void \fBchangeIconStyle\fP ()" .br .ti -1c .RI "QBoxLayout * \fBmainLayout\fP ()" .br .in -1c .SH "Detailed Description" .PP 进度对话框,会实时显示当前进度 .PP \fBExamples\fP .in +1c \fBtestprogressdialog/widget\&.cpp\fP\&. .SH "Author" .PP Generated automatically by Doxygen for LIBKYSDK-APPLICATIONS from the source code\&. libkysdk-applications/doxygen/man/man3/kdk_KPasswordEdit.30000664000175000017500000000425315104543305022532 0ustar fengfeng.TH "kdk::KPasswordEdit" 3 "Version version:3.0" "LIBKYSDK-APPLICATIONS" \" -*- nroff -*- .ad l .nh .SH NAME kdk::KPasswordEdit \- 密码输入框,继承于QLineEdit,支持三种不同状态显示 .SH SYNOPSIS .br .PP .PP \fC#include \fP .PP Inherits QLineEdit\&. .SS "Public Member Functions" .in +1c .ti -1c .RI "\fBKPasswordEdit\fP (QWidget *parent)" .br .ti -1c .RI "void \fBsetState\fP (\fBLoginState\fP \fBstate\fP)" .br .RI "设置状态 " .ti -1c .RI "\fBLoginState\fP \fBstate\fP ()" .br .RI "返回状态 " .ti -1c .RI "void \fBsetLoading\fP (bool flag)" .br .RI "设置加载状态 " .ti -1c .RI "bool \fBisLoading\fP ()" .br .RI "判断是否处于加载状态 " .ti -1c .RI "QString \fBplaceholderText\fP ()" .br .RI "返回placeholderText " .ti -1c .RI "void \fBsetPlaceholderText\fP (QString &text)" .br .RI "设置PlaceholderText " .ti -1c .RI "void \fBsetClearButtonEnabled\fP (bool enable)" .br .RI "设置是否启用ClearButton " .ti -1c .RI "bool \fBisClearButtonEnabled\fP () const" .br .RI "返回是否启用了ClearButton " .ti -1c .RI "void \fBsetEchoModeBtnVisible\fP (bool enable)" .br .RI "设置EchoModeBtn是否可见 " .ti -1c .RI "bool \fBechoModeBtnVisible\fP ()" .br .RI "返回EchoModeBtn是否可见 " .ti -1c .RI "void \fBsetClearBtnVisible\fP (bool enable)" .br .RI "设置ClearBtn是否可见 " .ti -1c .RI "bool \fBclearBtnVisible\fP ()" .br .RI "返回ClearBtn是否可见 " .ti -1c .RI "void \fBsetEnabled\fP (bool)" .br .RI "设置KLineEdit是否可用 " .ti -1c .RI "void \fBsetEchoMode\fP (EchoMode mode)" .br .RI "setEchoMode " .ti -1c .RI "void \fBsetUseCustomPalette\fP (bool flag)" .br .RI "设置是否走默认palette " .in -1c .SS "Protected Member Functions" .in +1c .ti -1c .RI "void \fBresizeEvent\fP (QResizeEvent *event)" .br .ti -1c .RI "bool \fBeventFilter\fP (QObject *watched, QEvent *event)" .br .ti -1c .RI "QSize \fBsizeHint\fP () const override" .br .in -1c .SH "Detailed Description" .PP 密码输入框,继承于QLineEdit,支持三种不同状态显示 .PP \fBExamples\fP .in +1c \fBtestpasswordedit/widget\&.h\fP\&. .SH "Author" .PP Generated automatically by Doxygen for LIBKYSDK-APPLICATIONS from the source code\&. libkysdk-applications/doxygen/man/man3/kdk_KNavigationTrail.30000664000175000017500000000204215104543305023207 0ustar fengfeng.TH "kdk::KNavigationTrail" 3 "Version version:3.0" "LIBKYSDK-APPLICATIONS" \" -*- nroff -*- .ad l .nh .SH NAME kdk::KNavigationTrail .SH SYNOPSIS .br .PP .PP Inherits QWidget\&. .SS "Signals" .in +1c .ti -1c .RI "void \fBsizeChange\fP ()" .br .RI "点击会发出信号 " .in -1c .SS "Public Member Functions" .in +1c .ti -1c .RI "\fBKNavigationTrail\fP (QWidget *parent=nullptr)" .br .ti -1c .RI "\fBKCrumb\fP * \fBcrumb\fP ()" .br .RI "获取kcrumb " .ti -1c .RI "void \fBsetPosition\fP (ButtonPosition type)" .br .RI "设置箭头位置 " .in -1c .SS "Protected Member Functions" .in +1c .ti -1c .RI "void \fBresizeEvent\fP (QResizeEvent *event)" .br .in -1c .SH "Member Function Documentation" .PP .SS "\fBKCrumb\fP * kdk::KNavigationTrail::crumb ()" .PP 获取kcrumb .PP \fBReturns\fP .RS 4 .RE .PP .SS "void kdk::KNavigationTrail::setPosition (ButtonPosition type)" .PP 设置箭头位置 .PP \fBParameters\fP .RS 4 \fItype\fP .RE .PP .SH "Author" .PP Generated automatically by Doxygen for LIBKYSDK-APPLICATIONS from the source code\&. libkysdk-applications/doxygen/man/man3/kdk_KPressButton.30000664000175000017500000000666415104543305022422 0ustar fengfeng.TH "kdk::KPressButton" 3 "Version version:3.0" "LIBKYSDK-APPLICATIONS" \" -*- nroff -*- .ad l .nh .SH NAME kdk::KPressButton \- 按压按钮,可根据情况设置loading状态 .SH SYNOPSIS .br .PP .PP \fC#include \fP .PP Inherits QPushButton\&. .SS "Public Types" .in +1c .ti -1c .RI "enum \fBButtonType\fP { \fBNormalType\fP, \fBCircleType\fP }" .br .in -1c .SS "Public Member Functions" .in +1c .ti -1c .RI "\fBKPressButton\fP (QWidget *parent=0)" .br .ti -1c .RI "void \fBsetBorderRadius\fP (int radius)" .br .RI "设置圆角 " .ti -1c .RI "void \fBsetBorderRadius\fP (int bottomLeft, int topLeft, int topRight, int bottomRight)" .br .RI "设置圆角 " .ti -1c .RI "void \fBsetCheckable\fP (bool)" .br .RI "设置是否可选中 " .ti -1c .RI "bool \fBisCheckable\fP () const" .br .RI "返回是否可选中 " .ti -1c .RI "void \fBsetChecked\fP (bool)" .br .RI "设置是否选中 " .ti -1c .RI "bool \fBisChecked\fP () const" .br .RI "返回是否选中 " .ti -1c .RI "void \fBsetButtonType\fP (ButtonType type)" .br .RI "设置button类型 " .ti -1c .RI "KPressButton::ButtonType \fBbuttonType\fP ()" .br .RI "返回button类型 " .ti -1c .RI "void \fBsetLoaingStatus\fP (bool flag)" .br .RI "设置是否启用loading状态 " .ti -1c .RI "bool \fBisLoading\fP ()" .br .RI "返回是否启用loading状态 " .ti -1c .RI "void \fBsetTranslucent\fP (bool flag)" .br .RI "设置是否启用透明度 " .ti -1c .RI "bool \fBisTranslucent\fP ()" .br .RI "返回是否启用透明度 " .in -1c .SS "Protected Member Functions" .in +1c .ti -1c .RI "void \fBpaintEvent\fP (QPaintEvent *event) override" .br .in -1c .SH "Detailed Description" .PP 按压按钮,可根据情况设置loading状态 .PP \fBSince\fP .RS 4 1\&.2\&.0 .RE .PP .SH "Member Function Documentation" .PP .SS "KPressButton::ButtonType kdk::KPressButton::buttonType ()" .PP 返回button类型 .PP \fBReturns\fP .RS 4 .RE .PP .SS "bool kdk::KPressButton::isCheckable () const" .PP 返回是否可选中 .PP \fBReturns\fP .RS 4 .RE .PP .SS "bool kdk::KPressButton::isChecked () const" .PP 返回是否选中 .PP \fBReturns\fP .RS 4 .RE .PP .SS "bool kdk::KPressButton::isLoading ()" .PP 返回是否启用loading状态 .PP \fBReturns\fP .RS 4 .RE .PP .SS "bool kdk::KPressButton::isTranslucent ()" .PP 返回是否启用透明度 .PP \fBReturns\fP .RS 4 .RE .PP .SS "void kdk::KPressButton::setBorderRadius (int bottomLeft, int topLeft, int topRight, int bottomRight)" .PP 设置圆角 .PP \fBParameters\fP .RS 4 \fIbuttomLeft\fP .br \fItopLeft\fP .br \fItopRight\fP .br \fIbottomRight\fP .RE .PP .SS "void kdk::KPressButton::setBorderRadius (int radius)" .PP 设置圆角 .PP \fBParameters\fP .RS 4 \fIradius\fP .RE .PP .SS "void kdk::KPressButton::setButtonType (ButtonType type)" .PP 设置button类型 .PP \fBParameters\fP .RS 4 \fItype\fP .RE .PP .SS "void kdk::KPressButton::setCheckable (bool)" .PP 设置是否可选中 .PP \fBParameters\fP .RS 4 \fIflag\fP .RE .PP .SS "void kdk::KPressButton::setChecked (bool)" .PP 设置是否选中 .PP \fBReturns\fP .RS 4 .RE .PP .SS "void kdk::KPressButton::setLoaingStatus (bool flag)" .PP 设置是否启用loading状态 .PP \fBParameters\fP .RS 4 \fIflag\fP .RE .PP .SS "void kdk::KPressButton::setTranslucent (bool flag)" .PP 设置是否启用透明度 .PP \fBParameters\fP .RS 4 \fIflag\fP .RE .PP .SH "Author" .PP Generated automatically by Doxygen for LIBKYSDK-APPLICATIONS from the source code\&. libkysdk-applications/doxygen/man/man3/kdk_KComboBoxFrame.30000664000175000017500000000531715104543305022607 0ustar fengfeng.TH "kdk::KComboBoxFrame" 3 "Version version:3.0" "LIBKYSDK-APPLICATIONS" \" -*- nroff -*- .ad l .nh .SH NAME kdk::KComboBoxFrame .SH SYNOPSIS .br .PP .PP Inherits \fBkdk::KBaseFrame\fP\&. .SS "Public Member Functions" .in +1c .ti -1c .RI "\fBKComboBoxFrame\fP (const QString title, QWidget *parent=nullptr, \fBBorderRadiusStyle\fP style=\fBBorderRadiusStyle::None\fP)" .br .RI "创建一个带 QComboBox 的 Frame " .ti -1c .RI "\fBKLabel\fP * \fBtitleLabel\fP ()" .br .RI "获取label " .ti -1c .RI "QHBoxLayout * \fBmainHLayout\fP ()" .br .RI "获取layout " .ti -1c .RI "QComboBox * \fBcomboBox\fP ()" .br .RI "获取下拉框控件 " .in -1c Public Member Functions inherited from \fBkdk::KBaseFrame\fP .in +1c .ti -1c .RI "\fBKBaseFrame\fP (QWidget *parent=nullptr, \fBBorderRadiusStyle\fP style=\fBAround\fP, bool heightAdaptive=false)" .br .RI "构造函数 " .ti -1c .RI "void \fBsetRadiusType\fP (\fBBorderRadiusStyle\fP style)" .br .RI "设置圆角风格 " .ti -1c .RI "bool \fBgetTabletMode\fP ()" .br .RI "获取平板模式 " .ti -1c .RI "bool \fBisContainer\fP ()" .br .RI "获取是否是一个容器frame,此时settinggroup需要设置的是其子frame的圆角 " .ti -1c .RI "void \fBsetContainer\fP (bool b=false)" .br .RI "设置该frame是否是一个容器frame,如果是同时setFrameShape(NoFrame); " .in -1c .SS "Additional Inherited Members" Public Types inherited from \fBkdk::KBaseFrame\fP .in +1c .ti -1c .RI "enum \fBBorderRadiusStyle\fP { \fBTop\fP, \fBNone\fP, \fBBottom\fP, \fBAround\fP }" .br .in -1c Signals inherited from \fBkdk::KBaseFrame\fP .in +1c .ti -1c .RI "void \fBtabletModeChanged\fP (bool b)" .br .in -1c Protected Member Functions inherited from \fBkdk::KBaseFrame\fP .in +1c .ti -1c .RI "void \fBpaintEvent\fP (QPaintEvent *e)" .br .in -1c .SH "Constructor & Destructor Documentation" .PP .SS "kdk::KComboBoxFrame::KComboBoxFrame (const QString title, QWidget * parent = \fCnullptr\fP, \fBBorderRadiusStyle\fP style = \fC\fBBorderRadiusStyle::None\fP\fP)\fC [explicit]\fP" .PP 创建一个带 QComboBox 的 Frame .PP \fBParameters\fP .RS 4 \fItitle\fP text of m_settingName .br \fIstyle\fP 设置圆角(None:无圆角,Top:上圆角,Bottom:下圆角,Around:四圆角) .br \fIparent\fP .RE .PP .SH "Member Function Documentation" .PP .SS "QComboBox * kdk::KComboBoxFrame::comboBox ()" .PP 获取下拉框控件 .PP \fBReturns\fP .RS 4 QComboBox .RE .PP .SS "QHBoxLayout * kdk::KComboBoxFrame::mainHLayout ()" .PP 获取layout .PP \fBReturns\fP .RS 4 QHBoxLayout .RE .PP .SS "\fBKLabel\fP * kdk::KComboBoxFrame::titleLabel ()" .PP 获取label .PP \fBReturns\fP .RS 4 QLabel .RE .PP .SH "Author" .PP Generated automatically by Doxygen for LIBKYSDK-APPLICATIONS from the source code\&. libkysdk-applications/doxygen/man/man3/kdk_KProgressBar.30000664000175000017500000000340015104543305022344 0ustar fengfeng.TH "kdk::KProgressBar" 3 "Version version:3.0" "LIBKYSDK-APPLICATIONS" \" -*- nroff -*- .ad l .nh .SH NAME kdk::KProgressBar \- 进度条,支持三种状态显示 .SH SYNOPSIS .br .PP .PP \fC#include \fP .PP Inherits QProgressBar\&. .SS "Public Member Functions" .in +1c .ti -1c .RI "\fBKProgressBar\fP (QWidget *parent)" .br .ti -1c .RI "\fBProgressBarState\fP \fBstate\fP ()" .br .RI "获取状态 " .ti -1c .RI "void \fBsetState\fP (\fBProgressBarState\fP \fBstate\fP)" .br .RI "设置状态 " .ti -1c .RI "QString \fBtext\fP () const override" .br .RI "获取文本 " .ti -1c .RI "void \fBsetOrientation\fP (Qt::Orientation)" .br .RI "设置方向 " .ti -1c .RI "void \fBsetBodyWidth\fP (int width)" .br .RI "设置进度条宽度 " .ti -1c .RI "void \fBsetGradationColor\fP (QColor color1, QColor color2)" .br .RI "设置首尾位置的渐变颜色 " .ti -1c .RI "void \fBsetBackgroundColor\fP (QColor color)" .br .RI "设置背景色 " .ti -1c .RI "void \fBsetFillColor\fP (QColor color)" .br .RI "设置填充色 " .ti -1c .RI "void \fBsetGradation\fP (bool flag)" .br .RI "是否启用自定义渐变色 " .ti -1c .RI "bool \fBgradation\fP ()" .br .RI "获取是否启用自定义渐变色 " .ti -1c .RI "void \fBsetAnimation\fP (bool flag)" .br .RI "是否启用动画 " .ti -1c .RI "bool \fBanimation\fP ()" .br .RI "获取是否启用动画 " .in -1c .SS "Protected Member Functions" .in +1c .ti -1c .RI "void \fBpaintEvent\fP (QPaintEvent *event) override" .br .ti -1c .RI "QSize \fBsizeHint\fP () const" .br .in -1c .SH "Detailed Description" .PP 进度条,支持三种状态显示 .PP \fBExamples\fP .in +1c \fBtestprogressbar/widget\&.h\fP\&. .SH "Author" .PP Generated automatically by Doxygen for LIBKYSDK-APPLICATIONS from the source code\&. libkysdk-applications/doxygen/man/man3/kdk.30000664000175000017500000002444615104543305017735 0ustar fengfeng.TH "kdk" 3 "Version version:3.0" "LIBKYSDK-APPLICATIONS" \" -*- nroff -*- .ad l .nh .SH NAME kdk \- 设置控件属性 .SH SYNOPSIS .br .PP .SS "Classes" .in +1c .ti -1c .RI "class \fBAccessInfoHelper\fP" .br .ti -1c .RI "class \fBKAboutDialog\fP" .br .RI "关于对话框,支持两种样式,一种是无特定说明的,另一种是有特定说明的。 " .ti -1c .RI "class \fBKAddButton\fP" .br .ti -1c .RI "class \fBKAddFileButton\fP" .br .RI "选择文件的按钮 " .ti -1c .RI "class \fBKArrowTabBar\fP" .br .RI "可显示箭头的tabbar " .ti -1c .RI "class \fBKBackgroundGroup\fP" .br .RI "提供了一个用于存储部件的容器 " .ti -1c .RI "class \fBKBadge\fP" .br .RI "消息提醒气泡 " .ti -1c .RI "class \fBKBallonTip\fP" .br .RI "消息提示框,支持五种样式 " .ti -1c .RI "class \fBKBaseFrame\fP" .br .ti -1c .RI "class \fBKBorderButton\fP" .br .RI "带边框的按钮 " .ti -1c .RI "class \fBKBorderlessButton\fP" .br .RI "无边框按钮 " .ti -1c .RI "class \fBKBreadCrumb\fP" .br .RI "面包屑控件 " .ti -1c .RI "class \fBKBubbleWidget\fP" .br .RI "提供了一个带三角形窗体。 " .ti -1c .RI "class \fBKButtonBox\fP" .br .RI "提供了一个按钮类容器 " .ti -1c .RI "class \fBKClockTimer\fP" .br .ti -1c .RI "class \fBKColorButton\fP" .br .RI "提供用于设置颜色和样式的按钮,以适用于不同的场景。 " .ti -1c .RI "class \fBKColorComboBox\fP" .br .RI "颜色选择框 " .ti -1c .RI "class \fBKComboBoxFrame\fP" .br .ti -1c .RI "class \fBKComboBoxWidget\fP" .br .ti -1c .RI "class \fBKCommentPanel\fP" .br .RI "显示用户评论的详细信息 " .ti -1c .RI "class \fBKCrumb\fP" .br .RI "面包屑控件 " .ti -1c .RI "class \fBKCustomDateEdit\fP" .br .ti -1c .RI "class \fBKDialog\fP" .br .RI "继承自 QDialog,支持响应式主题背景切换和图标主题切换、 标题颜色响应窗口激活状态 " .ti -1c .RI "class \fBKDirTabBar\fP" .br .RI "目录层级控件 " .ti -1c .RI "class \fBKDragWidget\fP" .br .RI "拖动文件或文件夹,可识别并获取文件或文件夹路径 " .ti -1c .RI "class \fBKFileWidget\fP" .br .RI "The \fBKFileWidget\fP class\&. " .ti -1c .RI "class \fBKFlowLayout\fP" .br .ti -1c .RI "class \fBKHLineFrame\fP" .br .ti -1c .RI "class \fBKIconBar\fP" .br .RI "图标和标题组合控件 " .ti -1c .RI "class \fBKInputDialog\fP" .br .RI "输入对话框,接口与 QInputDialog 相同。 " .ti -1c .RI "class \fBKIntroWidget\fP" .br .ti -1c .RI "class \fBKItemWidget\fP" .br .ti -1c .RI "class \fBKLabel\fP" .br .RI "继承qlabel " .ti -1c .RI "class \fBKLineEdit\fP" .br .ti -1c .RI "class \fBKLineEditFrame\fP" .br .ti -1c .RI "class \fBKListView\fP" .br .RI "配合KListviewdelegate可以提供一个图片两行文字的显示效果,若只有一行文字,则对于 icon 居中显示 。 " .ti -1c .RI "class \fBKListViewDelegate\fP" .br .RI "配合KListview可以提供一个图片两行文字的显示效果,若只有一行文字,则对于 icon 居中显示 。 " .ti -1c .RI "class \fBKListWidget\fP" .br .ti -1c .RI "class \fBKLoopPlayPage\fP" .br .ti -1c .RI "class \fBKLunarCalendarInfo\fP" .br .ti -1c .RI "class \fBKLunarDateEdit\fP" .br .ti -1c .RI "class \fBKMenuButton\fP" .br .RI "下拉菜单按钮 " .ti -1c .RI "class \fBKMessageBox\fP" .br .RI "继承自KDialog,提供一个可自定义设置按钮和图标的对话框,类似QMessageBox " .ti -1c .RI "class \fBKMiniCalendarItem\fP" .br .ti -1c .RI "class \fBKMiniCalendarWidget\fP" .br .ti -1c .RI "class \fBKNativeTabbar\fP" .br .ti -1c .RI "class \fBKNavigationBar\fP" .br .RI "导航栏控件 " .ti -1c .RI "class \fBKNavigationTrail\fP" .br .ti -1c .RI "class \fBKPasswordEdit\fP" .br .RI "密码输入框,继承于QLineEdit,支持三种不同状态显示 " .ti -1c .RI "class \fBKPixmapContainer\fP" .br .RI "为指定的pixmap添加右上角消息提示气泡,样式类似微信头像的消息提示 " .ti -1c .RI "class \fBKPressButton\fP" .br .RI "按压按钮,可根据情况设置loading状态 " .ti -1c .RI "class \fBKProgressBar\fP" .br .RI "进度条,支持三种状态显示 " .ti -1c .RI "class \fBKProgressCircle\fP" .br .RI "以圆环样式显示进度,支持三种状态 " .ti -1c .RI "class \fBKProgressDialog\fP" .br .RI "进度对话框,会实时显示当前进度 " .ti -1c .RI "class \fBKProgressLabel\fP" .br .ti -1c .RI "class \fBKPushButton\fP" .br .RI "1\&.提供半透明效果 2\&.可以设置按钮圆角、背景色、图标是否跟随系统高亮 3\&.可以设置按钮类型,分为正常类型和圆形(需要设置大小实现正圆),其余同QPushButton " .ti -1c .RI "class \fBKPushButtonFrame\fP" .br .ti -1c .RI "class \fBKRadioButtonFrame\fP" .br .ti -1c .RI "class \fBKSearchLineEdit\fP" .br .RI "搜索输入框,可搜索匹配条件的item " .ti -1c .RI "class \fBKSecurityLevelBar\fP" .br .RI "密码安全等级提示条,支持三个安全等级 " .ti -1c .RI "class \fBKSecurityQuestionDialog\fP" .br .RI "继承自 KDialog, " .ti -1c .RI "class \fBKSettingGroup\fP" .br .ti -1c .RI "class \fBKSlider\fP" .br .RI "支持三种样式的滑动条 非步数关系:步数为1,可以在任意位置点击和拖拽 步数关系:步数为固定值,可根据步数值点击和拖拽 节点关系:步数为节点间隔,可根据节点间隔点击和拖拽 " .ti -1c .RI "class \fBKSliderFrame\fP" .br .ti -1c .RI "class \fBKSwitchButton\fP" .br .RI "指示打开/关闭两种状态 " .ti -1c .RI "class \fBKSwitchButtonFrame\fP" .br .ti -1c .RI "class \fBKTabBar\fP" .br .RI "支持三种样式 " .ti -1c .RI "class \fBKTableHeaderView\fP" .br .ti -1c .RI "class \fBKTableModel\fP" .br .ti -1c .RI "class \fBKTableView\fP" .br .ti -1c .RI "class \fBKTag\fP" .br .RI "提供四种样式的标签,响应系统主题色变化 " .ti -1c .RI "class \fBKTextEdit\fP" .br .RI "继承QTextEdit " .ti -1c .RI "class \fBKTextEditor\fP" .br .ti -1c .RI "class \fBKTitleWindow\fP" .br .ti -1c .RI "class \fBKToolBar\fP" .br .ti -1c .RI "class \fBKToolButton\fP" .br .RI "提供了一个快速访问按钮,暂不支持显示文本 " .ti -1c .RI "class \fBKTranslucentFloor\fP" .br .RI "提供一个半透明底板,可作为基础窗体进行布局 " .ti -1c .RI "class \fBKUninstallDialog\fP" .br .RI "卸载对话框,当用户卸载时可能会弹出此提示对话框 " .ti -1c .RI "class \fBKVLineFrame\fP" .br .ti -1c .RI "class \fBKWidget\fP" .br .RI "继承自QWidget,支持响应主题背景切换,图标主题切换,标题颜色响应窗口激活状态,内容区域分为side区和base区 " .ti -1c .RI "class \fBKWidgetUtils\fP" .br .ti -1c .RI "class \fBKWindowButtonBar\fP" .br .RI "窗口三联按钮和菜单按钮的集合 " .ti -1c .RI "class \fBParmscontroller\fP" .br .RI "The \fBParmscontroller\fP class\&. " .ti -1c .RI "class \fBUkuiStyleHelper\fP" .br .RI "解决wayland环境下的双标题栏问题 " .ti -1c .RI "class \fBWindowManager\fP" .br .RI "通常用于对窗口的一些操作 " .ti -1c .RI "class \fBXAtomHelper\fP" .br .in -1c .SS "Typedefs" .in +1c .ti -1c .RI "using \fBWindowId\fP = QVariant" .br .in -1c .SS "Enumerations" .in +1c .ti -1c .RI "enum \fBTipType\fP { \fBNothing\fP, \fBNormal\fP, \fBInfo\fP, \fBWarning\fP, \fBError\fP, \fBVariable\fP }" .br .RI "支持五种样式 " .ti -1c .RI "enum \fBKBreadCrumbType\fP { \fBFlatBreadCrumb\fP, \fBCubeBreadCrumb\fP }" .br .RI "KBreadCrumbType,包括两种类型。 " .ti -1c .RI "enum \fBTailDirection\fP { \fBTopDirection\fP, \fBLeftDirection\fP, \fBBottomDirection\fP, \fBRightDirection\fP, \fBNone\fP }" .br .RI "指定气泡尾部显示的方向 " .ti -1c .RI "enum \fBTailLocation\fP { \fBLeftLocation\fP, \fBMiddleLocation\fP, \fBRightLocation\fP }" .br .RI "指定气泡尾部的显示位置 " .ti -1c .RI "enum \fBStarLevel\fP { \fBLevelZero\fP = 0, \fBLevelOne\fP, \fBLevelTwo\fP, \fBLevelThree\fP, \fBLevelFour\fP, \fBLevelFive\fP }" .br .RI "提供六种评论等级 " .ti -1c .RI "enum \fBKCrumbType\fP { \fBFlatBreadCrumb\fP, \fBCubeBreadCrumb\fP }" .br .RI "KCrumbType,包括两种类型。 " .ti -1c .RI "enum \fBViewType\fP { \fBIconView\fP, \fBListView\fP }" .br .ti -1c .RI "enum \fBKLabelType\fP { \fBNormalType\fP, \fBDataType\fP, \fBCircleType\fP }" .br .ti -1c .RI "enum \fBKNativeTabbarStyle\fP { \fBSegmentDark\fP, \fBSegmentLight\fP, \fBSliding\fP }" .br .ti -1c .RI "enum \fBButtonPosition\fP { \fBLeftPosition\fP, \fBLeftOrRight\fP, \fBRightPosition\fP }" .br .ti -1c .RI "enum \fBLoginState\fP { \fBOrdinary\fP, \fBLoginSuccess\fP, \fBLoginFailed\fP }" .br .RI "支持三种状态 " .ti -1c .RI "enum \fBProgressBarState\fP { \fBNormalProgress\fP, \fBFailedProgress\fP, \fBSuccessProgress\fP }" .br .RI "支持三种状态 " .ti -1c .RI "enum \fBBarType\fP { \fBScrollBar\fP, \fBNothingBar\fP, \fBNormalBar\fP, \fBSpeedBar\fP }" .br .RI "支持三种样式 " .ti -1c .RI "enum \fBSecurityLevel\fP { \fBLow\fP, \fBMedium\fP, \fBHigh\fP }" .br .RI "分为三个安全等级 " .ti -1c .RI "enum \fBKSliderType\fP { \fBSmoothSlider\fP, \fBStepSlider\fP, \fBNodeSlider\fP, \fBSingleSelectSlider\fP }" .br .ti -1c .RI "enum \fBKTabBarStyle\fP { \fBSegmentDark\fP, \fBSegmentLight\fP, \fBSliding\fP }" .br .RI "支持三种样式 " .ti -1c .RI "enum \fBTagStyle\fP { \fBHighlightTag\fP, \fBBoderTag\fP, \fBBaseBoderTag\fP, \fBGrayTag\fP, \fBIconTag\fP }" .br .RI "支持四种风格的tag " .ti -1c .RI "enum \fBKToolButtonType\fP { \fBFlat\fP, \fBSemiFlat\fP, \fBBackground\fP, \fBFrameless\fP }" .br .RI "支持三种样式,暂不支持文字显示 " .ti -1c .RI "enum \fBLayoutType\fP { \fBVerticalType\fP, \fBHorizontalType\fP, \fBMixedType\fP }" .br .RI "支持切换三种结构布局 " .ti -1c .RI "enum \fBMaximumButtonState\fP { \fBMaximum\fP, \fBRestore\fP }" .br .RI "最大化按钮提供两种状态响应 " .in -1c .SS "Functions" .in +1c .ti -1c .RI "template QString \fBcombineAccessibleName\fP (T *obj, QString widgetName, const QString &pluginName, const QString &extend=QString())" .br .ti -1c .RI "template QString \fBcombineAccessibleDescription\fP (T *obj, const QString &widgetName)" .br .ti -1c .RI "template \fBAccessInfoHelper\fP< T > \fBgetHandle\fP (T *widget)" .br .in -1c .SH "Detailed Description" .PP 设置控件属性 高分屏和合成器接口 .PP 创建一个带 QPushButton 的 Frame .PP \fBSince\fP .RS 4 2\&.5\&.2\&.0 .PP 1\&.0\&.0 .RE .PP .SH "Author" .PP Generated automatically by Doxygen for LIBKYSDK-APPLICATIONS from the source code\&. libkysdk-applications/doxygen/man/man3/LabelModule.30000664000175000017500000000044015104543305021335 0ustar fengfeng.TH "LabelModule" 3 "Version version:3.0" "LIBKYSDK-APPLICATIONS" \" -*- nroff -*- .ad l .nh .SH NAME LabelModule \- LabelModule .SH SYNOPSIS .br .PP .SH "Detailed Description" .PP { .SH "Author" .PP Generated automatically by Doxygen for LIBKYSDK-APPLICATIONS from the source code\&. libkysdk-applications/doxygen/man/man3/KLunarDateEdit.30000664000175000017500000000052515104543305021754 0ustar fengfeng.TH "KLunarDateEdit" 3 "Version version:3.0" "LIBKYSDK-APPLICATIONS" \" -*- nroff -*- .ad l .nh .SH NAME KLunarDateEdit \- KLunarDateEdit .SH SYNOPSIS .br .PP .SH "Detailed Description" .PP .PP \fBSince\fP .RS 4 2\&.5\&.2\&.0 .RE .PP .SH "Author" .PP Generated automatically by Doxygen for LIBKYSDK-APPLICATIONS from the source code\&. libkysdk-applications/doxygen/man/man3/kdk_KHLineFrame.30000664000175000017500000000127615104543305022076 0ustar fengfeng.TH "kdk::KHLineFrame" 3 "Version version:3.0" "LIBKYSDK-APPLICATIONS" \" -*- nroff -*- .ad l .nh .SH NAME kdk::KHLineFrame .SH SYNOPSIS .br .PP .PP Inherits QFrame\&. .SS "Public Member Functions" .in +1c .ti -1c .RI "\fBKHLineFrame\fP (QWidget *parent=nullptr)" .br .ti -1c .RI "void \fBsetFollowPalette\fP (bool flag)" .br .RI "设置是否遵循默认色板 " .in -1c .SH "Member Function Documentation" .PP .SS "void kdk::KHLineFrame::setFollowPalette (bool flag)" .PP 设置是否遵循默认色板 .PP \fBParameters\fP .RS 4 \fIflag\fP .RE .PP \fBSince\fP .RS 4 2\&.4\&.1\&.0 .RE .PP .SH "Author" .PP Generated automatically by Doxygen for LIBKYSDK-APPLICATIONS from the source code\&. libkysdk-applications/doxygen/man/man3/kdk_KWindowButtonBar.30000664000175000017500000000344415104543305023213 0ustar fengfeng.TH "kdk::KWindowButtonBar" 3 "Version version:3.0" "LIBKYSDK-APPLICATIONS" \" -*- nroff -*- .ad l .nh .SH NAME kdk::KWindowButtonBar \- 窗口三联按钮和菜单按钮的集合 .SH SYNOPSIS .br .PP .PP \fC#include \fP .PP Inherits QFrame\&. .SS "Signals" .in +1c .ti -1c .RI "void \fBdoubleClick\fP ()" .br .RI "双击会发出双击信号,父widget可以绑定相应槽函数 " .in -1c .SS "Public Member Functions" .in +1c .ti -1c .RI "\fBKWindowButtonBar\fP (QWidget *parent=nullptr)" .br .ti -1c .RI "QPushButton * \fBminimumButton\fP ()" .br .RI "获取最小化按钮 " .ti -1c .RI "QPushButton * \fBmaximumButton\fP ()" .br .RI "获取最大化按钮 " .ti -1c .RI "QPushButton * \fBcloseButton\fP ()" .br .RI "获取关闭按钮 " .ti -1c .RI "\fBKMenuButton\fP * \fBmenuButton\fP ()" .br .RI "获取菜单按钮 " .ti -1c .RI "\fBMaximumButtonState\fP \fBmaximumButtonState\fP ()" .br .RI "获取最大化按钮的状态(最大化/恢复) " .ti -1c .RI "void \fBsetMaximumButtonState\fP (\fBMaximumButtonState\fP state)" .br .RI "设置最大化按钮图标状态(最大化/恢复) " .ti -1c .RI "void \fBsetFollowMode\fP (bool flag)" .br .RI "设置是否遵循模式 " .ti -1c .RI "bool \fBfollowMode\fP ()" .br .RI "返回是否遵循模式 " .ti -1c .RI "void \fBsetSplitScreenGeometry\fP (QRect rect)" .br .RI "setSplitScreenGeometry " .in -1c .SS "Protected Member Functions" .in +1c .ti -1c .RI "void \fBmouseDoubleClickEvent\fP (QMouseEvent *event)" .br .ti -1c .RI "bool \fBeventFilter\fP (QObject *watched, QEvent *event)" .br .ti -1c .RI "QSize \fBsizeHint\fP () const override" .br .in -1c .SH "Detailed Description" .PP 窗口三联按钮和菜单按钮的集合 .SH "Author" .PP Generated automatically by Doxygen for LIBKYSDK-APPLICATIONS from the source code\&. libkysdk-applications/doxygen/man/man3/kdk_KRadioButtonFrame.30000664000175000017500000000702115104543305023323 0ustar fengfeng.TH "kdk::KRadioButtonFrame" 3 "Version version:3.0" "LIBKYSDK-APPLICATIONS" \" -*- nroff -*- .ad l .nh .SH NAME kdk::KRadioButtonFrame .SH SYNOPSIS .br .PP .PP Inherits \fBkdk::KBaseFrame\fP\&. .SS "Public Member Functions" .in +1c .ti -1c .RI "\fBKRadioButtonFrame\fP (const QString title, QWidget *parent=nullptr, \fBBorderRadiusStyle\fP style=\fBBorderRadiusStyle::None\fP)" .br .RI "创建一个带 QButtonGroup 的 Frame " .ti -1c .RI "void \fBaddButton\fP (QRadioButton *button, int id=\-1, bool addStretch=false)" .br .RI "添加一个 id = id 的 QRadioButton 到 m_buttonGroup,并放到 radioLayout 中 " .ti -1c .RI "QHBoxLayout * \fBradioHLayout\fP ()" .br .RI "layout of radiobutton " .ti -1c .RI "QButtonGroup * \fBbuttonGroup\fP ()" .br .RI "获取 m_buttonGroup " .ti -1c .RI "\fBKLabel\fP * \fBtitleLabel\fP ()" .br .RI "获取label " .ti -1c .RI "QHBoxLayout * \fBmainHLayout\fP ()" .br .RI "获取layout " .in -1c Public Member Functions inherited from \fBkdk::KBaseFrame\fP .in +1c .ti -1c .RI "\fBKBaseFrame\fP (QWidget *parent=nullptr, \fBBorderRadiusStyle\fP style=\fBAround\fP, bool heightAdaptive=false)" .br .RI "构造函数 " .ti -1c .RI "void \fBsetRadiusType\fP (\fBBorderRadiusStyle\fP style)" .br .RI "设置圆角风格 " .ti -1c .RI "bool \fBgetTabletMode\fP ()" .br .RI "获取平板模式 " .ti -1c .RI "bool \fBisContainer\fP ()" .br .RI "获取是否是一个容器frame,此时settinggroup需要设置的是其子frame的圆角 " .ti -1c .RI "void \fBsetContainer\fP (bool b=false)" .br .RI "设置该frame是否是一个容器frame,如果是同时setFrameShape(NoFrame); " .in -1c .SS "Additional Inherited Members" Public Types inherited from \fBkdk::KBaseFrame\fP .in +1c .ti -1c .RI "enum \fBBorderRadiusStyle\fP { \fBTop\fP, \fBNone\fP, \fBBottom\fP, \fBAround\fP }" .br .in -1c Signals inherited from \fBkdk::KBaseFrame\fP .in +1c .ti -1c .RI "void \fBtabletModeChanged\fP (bool b)" .br .in -1c Protected Member Functions inherited from \fBkdk::KBaseFrame\fP .in +1c .ti -1c .RI "void \fBpaintEvent\fP (QPaintEvent *e)" .br .in -1c .SH "Constructor & Destructor Documentation" .PP .SS "kdk::KRadioButtonFrame::KRadioButtonFrame (const QString title, QWidget * parent = \fCnullptr\fP, \fBBorderRadiusStyle\fP style = \fC\fBBorderRadiusStyle::None\fP\fP)\fC [explicit]\fP" .PP 创建一个带 QButtonGroup 的 Frame .PP \fBParameters\fP .RS 4 \fItitle\fP text of m_settingName .br \fIstyle\fP 设置圆角(None:无圆角,Top:上圆角,Bottom:下圆角,Around:四圆角) .br \fIparent\fP .RE .PP .SH "Member Function Documentation" .PP .SS "void kdk::KRadioButtonFrame::addButton (QRadioButton * button, int id = \fC\-1\fP, bool addStretch = \fCfalse\fP)" .PP 添加一个 id = id 的 QRadioButton 到 m_buttonGroup,并放到 radioLayout 中 .PP \fBParameters\fP .RS 4 \fIbutton\fP 需要添加的 QRadioButton .br \fIid\fP 用于 buttonClicked 信号传递的参数 .br \fIaddStretch\fP 是否 addStretch .RE .PP .SS "QButtonGroup * kdk::KRadioButtonFrame::buttonGroup ()" .PP 获取 m_buttonGroup .PP \fBReturns\fP .RS 4 QButtonGroup .RE .PP .SS "QHBoxLayout * kdk::KRadioButtonFrame::mainHLayout ()" .PP 获取layout .PP \fBReturns\fP .RS 4 QHBoxLayout .RE .PP .SS "QHBoxLayout * kdk::KRadioButtonFrame::radioHLayout ()" .PP layout of radiobutton .PP \fBReturns\fP .RS 4 QHBoxLayout .RE .PP .SS "\fBKLabel\fP * kdk::KRadioButtonFrame::titleLabel ()" .PP 获取label .PP \fBReturns\fP .RS 4 QLabel .RE .PP .SH "Author" .PP Generated automatically by Doxygen for LIBKYSDK-APPLICATIONS from the source code\&. libkysdk-applications/doxygen/man/man3/KMiniCalendarItem.30000664000175000017500000000053615104543305022436 0ustar fengfeng.TH "KMiniCalendarItem" 3 "Version version:3.0" "LIBKYSDK-APPLICATIONS" \" -*- nroff -*- .ad l .nh .SH NAME KMiniCalendarItem \- KMiniCalendarItem .SH SYNOPSIS .br .PP .SH "Detailed Description" .PP .PP \fBSince\fP .RS 4 2\&.5\&.2\&.0 .RE .PP .SH "Author" .PP Generated automatically by Doxygen for LIBKYSDK-APPLICATIONS from the source code\&. libkysdk-applications/doxygen/man/man3/KCustomDateEdit.30000664000175000017500000000053015104543305022141 0ustar fengfeng.TH "KCustomDateEdit" 3 "Version version:3.0" "LIBKYSDK-APPLICATIONS" \" -*- nroff -*- .ad l .nh .SH NAME KCustomDateEdit \- KCustomDateEdit .SH SYNOPSIS .br .PP .SH "Detailed Description" .PP .PP \fBSince\fP .RS 4 2\&.5\&.2\&.0 .RE .PP .SH "Author" .PP Generated automatically by Doxygen for LIBKYSDK-APPLICATIONS from the source code\&. libkysdk-applications/doxygen/man/man3/kdk_KLineEditFrame.30000664000175000017500000000530315104543305022567 0ustar fengfeng.TH "kdk::KLineEditFrame" 3 "Version version:3.0" "LIBKYSDK-APPLICATIONS" \" -*- nroff -*- .ad l .nh .SH NAME kdk::KLineEditFrame .SH SYNOPSIS .br .PP .PP Inherits \fBkdk::KBaseFrame\fP\&. .SS "Public Member Functions" .in +1c .ti -1c .RI "\fBKLineEditFrame\fP (const QString title, QWidget *parent=nullptr, \fBBorderRadiusStyle\fP style=\fBBorderRadiusStyle::None\fP)" .br .RI "创建一个带 QLineEdit 的 Frame " .ti -1c .RI "QLineEdit * \fBlineEdit\fP ()" .br .RI "获取输入框 " .ti -1c .RI "\fBKLabel\fP * \fBtitleLabel\fP ()" .br .RI "获取label " .ti -1c .RI "QHBoxLayout * \fBmainHLayout\fP ()" .br .RI "获取layout " .in -1c Public Member Functions inherited from \fBkdk::KBaseFrame\fP .in +1c .ti -1c .RI "\fBKBaseFrame\fP (QWidget *parent=nullptr, \fBBorderRadiusStyle\fP style=\fBAround\fP, bool heightAdaptive=false)" .br .RI "构造函数 " .ti -1c .RI "void \fBsetRadiusType\fP (\fBBorderRadiusStyle\fP style)" .br .RI "设置圆角风格 " .ti -1c .RI "bool \fBgetTabletMode\fP ()" .br .RI "获取平板模式 " .ti -1c .RI "bool \fBisContainer\fP ()" .br .RI "获取是否是一个容器frame,此时settinggroup需要设置的是其子frame的圆角 " .ti -1c .RI "void \fBsetContainer\fP (bool b=false)" .br .RI "设置该frame是否是一个容器frame,如果是同时setFrameShape(NoFrame); " .in -1c .SS "Additional Inherited Members" Public Types inherited from \fBkdk::KBaseFrame\fP .in +1c .ti -1c .RI "enum \fBBorderRadiusStyle\fP { \fBTop\fP, \fBNone\fP, \fBBottom\fP, \fBAround\fP }" .br .in -1c Signals inherited from \fBkdk::KBaseFrame\fP .in +1c .ti -1c .RI "void \fBtabletModeChanged\fP (bool b)" .br .in -1c Protected Member Functions inherited from \fBkdk::KBaseFrame\fP .in +1c .ti -1c .RI "void \fBpaintEvent\fP (QPaintEvent *e)" .br .in -1c .SH "Constructor & Destructor Documentation" .PP .SS "kdk::KLineEditFrame::KLineEditFrame (const QString title, QWidget * parent = \fCnullptr\fP, \fBBorderRadiusStyle\fP style = \fC\fBBorderRadiusStyle::None\fP\fP)\fC [explicit]\fP" .PP 创建一个带 QLineEdit 的 Frame .PP \fBParameters\fP .RS 4 \fItitle\fP text of m_settingName .br \fIstyle\fP 设置圆角(None:无圆角,Top:上圆角,Bottom:下圆角,Around:四圆角) .br \fIparent\fP .RE .PP .SH "Member Function Documentation" .PP .SS "QLineEdit * kdk::KLineEditFrame::lineEdit ()" .PP 获取输入框 .PP \fBReturns\fP .RS 4 QLineEdit .RE .PP .SS "QHBoxLayout * kdk::KLineEditFrame::mainHLayout ()" .PP 获取layout .PP \fBReturns\fP .RS 4 QHBoxLayout .RE .PP .SS "\fBKLabel\fP * kdk::KLineEditFrame::titleLabel ()" .PP 获取label .PP \fBReturns\fP .RS 4 QLabel .RE .PP .SH "Author" .PP Generated automatically by Doxygen for LIBKYSDK-APPLICATIONS from the source code\&. libkysdk-applications/doxygen/man/man3/FrameModule.30000664000175000017500000001066215104543305021357 0ustar fengfeng.TH "FrameModule" 3 "Version version:3.0" "LIBKYSDK-APPLICATIONS" \" -*- nroff -*- .ad l .nh .SH NAME FrameModule \- FrameModule .PP \- 轮播图片控件 .SH SYNOPSIS .br .PP .SS "Classes" .in +1c .ti -1c .RI "class \fBkdk::KWidget\fP" .br .RI "继承自QWidget,支持响应主题背景切换,图标主题切换,标题颜色响应窗口激活状态,内容区域分为side区和base区 " .in -1c .SS "Functions" .in +1c .ti -1c .RI "\fBkdk::KWidget::KWidget\fP (QWidget *parent=nullptr)" .br .ti -1c .RI "void \fBkdk::KWidget::setIcon\fP (const QIcon &icon)" .br .RI "设置窗体图标 " .ti -1c .RI "void \fBkdk::KWidget::setIcon\fP (const QString &iconName)" .br .RI "设置窗体图标 " .ti -1c .RI "void \fBkdk::KWidget::setWidgetName\fP (const QString &widgetName)" .br .RI "设置窗体名称 " .ti -1c .RI "QWidget * \fBkdk::KWidget::sideBar\fP ()" .br .RI "获取左边栏widget,通过setlayout添加自定义内容 " .ti -1c .RI "QWidget * \fBkdk::KWidget::baseBar\fP ()" .br .RI "获取主内容区widget,通过setlayout添加自定义内容 " .ti -1c .RI "\fBKWindowButtonBar\fP * \fBkdk::KWidget::windowButtonBar\fP ()" .br .RI "获取窗口三联组合控件,以控制是否显示最大化、最小化按钮和下拉菜单按钮;也可增加自定义按钮 " .ti -1c .RI "\fBKIconBar\fP * \fBkdk::KWidget::iconBar\fP ()" .br .RI "获取窗口标题、图标组合控件,以控制相关样式 " .ti -1c .RI "void \fBkdk::KWidget::setLayoutType\fP (\fBLayoutType\fP type)" .br .RI "设置布局结构类型 " .ti -1c .RI "void \fBkdk::KWidget::setWindowFlags\fP (Qt::WindowFlags type)" .br .RI "设置窗口标志 " .ti -1c .RI "void \fBkdk::KWidget::setWindowFlag\fP (Qt::WindowType flag, bool on=true)" .br .RI "设置窗口标志 " .ti -1c .RI "void \fBkdk::KWidget::setSidebarFollowMode\fP (bool flag)" .br .RI "设置sidebar是否遵循系统更改宽度 " .ti -1c .RI "bool \fBkdk::KWidget::sidebarFollowMode\fP ()" .br .RI "返回sidebar是否遵循系统更改宽度 " .ti -1c .RI "bool \fBkdk::KWidget::eventFilter\fP (QObject *target, QEvent *event) override" .br .ti -1c .RI "virtual void \fBkdk::KWidget::changeIconStyle\fP ()" .br .ti -1c .RI "virtual void \fBkdk::KWidget::changeTheme\fP ()" .br .in -1c .SH "Detailed Description" .PP 轮播图片控件 { .PP \fBSince\fP .RS 4 2\&.5\&.2\&.0 .PP 2\&.0\&.2\&.1 { .PP 2\&.5\&.2\&.0 { .RE .PP .SH "Function Documentation" .PP .SS "QWidget * kdk::KWidget::baseBar ()" .PP 获取主内容区widget,通过setlayout添加自定义内容 .PP \fBReturns\fP .RS 4 返回主内容区widget .RE .PP .SS "\fBKIconBar\fP * kdk::KWidget::iconBar ()" .PP 获取窗口标题、图标组合控件,以控制相关样式 .PP \fBReturns\fP .RS 4 返回窗口标题、图标组合控件 .RE .PP .SS "void kdk::KWidget::setIcon (const QIcon & icon)" .PP 设置窗体图标 .PP \fBParameters\fP .RS 4 \fIicon\fP .RE .PP .SS "void kdk::KWidget::setIcon (const QString & iconName)" .PP 设置窗体图标 .PP \fBParameters\fP .RS 4 \fIiconName\fP 直接指定系统目录中的图标名称,如'kylin-music' .RE .PP .SS "void kdk::KWidget::setSidebarFollowMode (bool flag)" .PP 设置sidebar是否遵循系统更改宽度 .PP \fBParameters\fP .RS 4 \fIflag\fP .RE .PP \fBSince\fP .RS 4 1\&.2\&.0 .RE .PP .SS "void kdk::KWidget::setWidgetName (const QString & widgetName)" .PP 设置窗体名称 .PP \fBParameters\fP .RS 4 \fIwidgetName\fP .RE .PP .SS "void kdk::KWidget::setWindowFlag (Qt::WindowType flag, bool on = \fCtrue\fP)" .PP 设置窗口标志 .PP \fBParameters\fP .RS 4 \fIflag\fP .br \fIon\fP .RE .PP \fBSince\fP .RS 4 1\&.2\&.0 .RE .PP .SS "void kdk::KWidget::setWindowFlags (Qt::WindowFlags type)" .PP 设置窗口标志 .PP \fBParameters\fP .RS 4 \fItype\fP .RE .PP \fBSince\fP .RS 4 1\&.2\&.0 .RE .PP .SS "QWidget * kdk::KWidget::sideBar ()" .PP 获取左边栏widget,通过setlayout添加自定义内容 .PP \fBReturns\fP .RS 4 返回左边栏widget .RE .PP .SS "bool kdk::KWidget::sidebarFollowMode ()" .PP 返回sidebar是否遵循系统更改宽度 .PP \fBReturns\fP .RS 4 .RE .PP \fBSince\fP .RS 4 1\&.2\&.0 .RE .PP .SS "\fBKWindowButtonBar\fP * kdk::KWidget::windowButtonBar ()" .PP 获取窗口三联组合控件,以控制是否显示最大化、最小化按钮和下拉菜单按钮;也可增加自定义按钮 .PP \fBReturns\fP .RS 4 返回窗口三联组合控件 .RE .PP .SH "Author" .PP Generated automatically by Doxygen for LIBKYSDK-APPLICATIONS from the source code\&. libkysdk-applications/doxygen/man/man3/kdk_KNativeTabbar.30000664000175000017500000002163715104543305022471 0ustar fengfeng.TH "kdk::KNativeTabbar" 3 "Version version:3.0" "LIBKYSDK-APPLICATIONS" \" -*- nroff -*- .ad l .nh .SH NAME kdk::KNativeTabbar .SH SYNOPSIS .br .PP .PP Inherits \fBKCustomTabBar\fP\&. .SS "Signals" .in +1c .ti -1c .RI "void \fBrightlicked\fP (QPoint point)" .br .RI "鼠标右键信号 " .in -1c Signals inherited from \fBKCustomTabBar\fP .in +1c .ti -1c .RI "void \fBcurrentChanged\fP (int index)" .br .ti -1c .RI "void \fBtabCloseRequested\fP (int index)" .br .ti -1c .RI "void \fBtabMoved\fP (int from, int to)" .br .ti -1c .RI "void \fBtabBarClicked\fP (int index)" .br .ti -1c .RI "void \fBtabBarDoubleClicked\fP (int index)" .br .ti -1c .RI "void \fBleftBStatus\fP (bool flag)" .br .ti -1c .RI "void \fBrightBStatus\fP (bool flag)" .br .in -1c .SS "Public Member Functions" .in +1c .ti -1c .RI "\fBKNativeTabbar\fP (KNativeTabbarStyle \fBbarStyle\fP=SegmentLight, QWidget *parent=nullptr)" .br .ti -1c .RI "void \fBsetTabbarStyle\fP (KNativeTabbarStyle \fBbarStyle\fP)" .br .RI "设置TabBar样式 " .ti -1c .RI "KNativeTabbarStyle \fBbarStyle\fP ()" .br .RI "返回TabBar样式 " .ti -1c .RI "void \fBsetBorderRadius\fP (int radius)" .br .RI "设置圆角半径,只对SegmentDark,SegmentLight样式生效 " .ti -1c .RI "int \fBborderRadius\fP ()" .br .RI "获取圆角半径 " .ti -1c .RI "void \fBsetBackgroundColor\fP (const QColor &color)" .br .RI "设置背景色 " .in -1c Public Member Functions inherited from \fBKCustomTabBar\fP .in +1c .ti -1c .RI "\fBKCustomTabBar\fP (QWidget *parent=nullptr)" .br .ti -1c .RI "Shape \fBshape\fP () const" .br .ti -1c .RI "void \fBsetShape\fP (Shape shape)" .br .ti -1c .RI "int \fBaddTab\fP (const QString &text)" .br .ti -1c .RI "int \fBaddTab\fP (const QIcon &icon, const QString &text)" .br .ti -1c .RI "int \fBinsertTab\fP (int index, const QString &text)" .br .ti -1c .RI "int \fBinsertTab\fP (int index, const QIcon &icon, const QString &text)" .br .ti -1c .RI "void \fBremoveTab\fP (int index)" .br .ti -1c .RI "void \fBmoveTab\fP (int from, int to)" .br .ti -1c .RI "bool \fBisTabEnabled\fP (int index) const" .br .ti -1c .RI "void \fBsetTabEnabled\fP (int index, bool)" .br .ti -1c .RI "QString \fBtabText\fP (int index) const" .br .ti -1c .RI "void \fBsetTabText\fP (int index, const QString &text)" .br .ti -1c .RI "void \fBsetTabContent\fP (int index, const QString &text)" .br .ti -1c .RI "QColor \fBtabTextColor\fP (int index) const" .br .ti -1c .RI "void \fBsetTabTextColor\fP (int index, const QColor &color)" .br .ti -1c .RI "QIcon \fBtabIcon\fP (int index) const" .br .ti -1c .RI "void \fBsetTabIcon\fP (int index, const QIcon &icon)" .br .ti -1c .RI "Qt::TextElideMode \fBelideMode\fP () const" .br .ti -1c .RI "void \fBsetElideMode\fP (Qt::TextElideMode)" .br .ti -1c .RI "void \fBsetTabToolTip\fP (int index, const QString &tip)" .br .ti -1c .RI "QString \fBtabToolTip\fP (int index) const" .br .ti -1c .RI "void \fBsetTabWhatsThis\fP (int index, const QString &text)" .br .ti -1c .RI "QString \fBtabWhatsThis\fP (int index) const" .br .ti -1c .RI "void \fBsetTabData\fP (int index, const QVariant &data)" .br .ti -1c .RI "QVariant \fBtabData\fP (int index) const" .br .ti -1c .RI "QRect \fBtabRect\fP (int index) const" .br .ti -1c .RI "int \fBtabAt\fP (const QPoint &pos) const" .br .ti -1c .RI "int \fBcurrentIndex\fP () const" .br .ti -1c .RI "int \fBcount\fP () const" .br .ti -1c .RI "QSize \fBsizeHint\fP () const override" .br .ti -1c .RI "QSize \fBminimumSizeHint\fP () const override" .br .ti -1c .RI "void \fBsetDrawBase\fP (bool drawTheBase)" .br .ti -1c .RI "bool \fBdrawBase\fP () const" .br .ti -1c .RI "QSize \fBiconSize\fP () const" .br .ti -1c .RI "void \fBsetIconSize\fP (const QSize &size)" .br .ti -1c .RI "bool \fBusesScrollButtons\fP () const" .br .ti -1c .RI "void \fBsetUsesScrollButtons\fP (bool useButtons)" .br .ti -1c .RI "bool \fBtabsClosable\fP () const" .br .ti -1c .RI "void \fBsetTabsClosable\fP (bool closable)" .br .ti -1c .RI "void \fBsetTabButton\fP (int index, ButtonPosition position, QWidget *widget)" .br .ti -1c .RI "QWidget * \fBtabButton\fP (int index, ButtonPosition position) const" .br .ti -1c .RI "SelectionBehavior \fBselectionBehaviorOnRemove\fP () const" .br .ti -1c .RI "void \fBsetSelectionBehaviorOnRemove\fP (SelectionBehavior behavior)" .br .ti -1c .RI "bool \fBexpanding\fP () const" .br .ti -1c .RI "void \fBsetExpanding\fP (bool enabled)" .br .ti -1c .RI "bool \fBisMovable\fP () const" .br .ti -1c .RI "void \fBsetMovable\fP (bool movable)" .br .ti -1c .RI "bool \fBdocumentMode\fP () const" .br .ti -1c .RI "void \fBsetDocumentMode\fP (bool set)" .br .ti -1c .RI "bool \fBautoHide\fP () const" .br .ti -1c .RI "void \fBsetAutoHide\fP (bool hide)" .br .ti -1c .RI "bool \fBchangeCurrentOnDrag\fP () const" .br .ti -1c .RI "void \fBsetChangeCurrentOnDrag\fP (bool change)" .br .ti -1c .RI "QString \fBaccessibleTabName\fP (int index) const" .br .ti -1c .RI "void \fBsetAccessibleTabName\fP (int index, const QString &name)" .br .in -1c .SS "Protected Member Functions" .in +1c .ti -1c .RI "QSize \fBsizeHint\fP () const" .br .ti -1c .RI "QSize \fBminimumTabSizeHint\fP (int index) const" .br .ti -1c .RI "QSize \fBtabSizeHint\fP (int index) const" .br .ti -1c .RI "void \fBpaintEvent\fP (QPaintEvent *event)" .br .in -1c Protected Member Functions inherited from \fBKCustomTabBar\fP .in +1c .ti -1c .RI "virtual void \fBtabInserted\fP (int index)" .br .ti -1c .RI "virtual void \fBtabRemoved\fP (int index)" .br .ti -1c .RI "virtual void \fBtabLayoutChange\fP ()" .br .ti -1c .RI "bool \fBevent\fP (QEvent *) override" .br .ti -1c .RI "void \fBresizeEvent\fP (QResizeEvent *) override" .br .ti -1c .RI "void \fBshowEvent\fP (QShowEvent *) override" .br .ti -1c .RI "void \fBhideEvent\fP (QHideEvent *) override" .br .ti -1c .RI "void \fBpaintEvent\fP (QPaintEvent *) override" .br .ti -1c .RI "void \fBmousePressEvent\fP (QMouseEvent *) override" .br .ti -1c .RI "void \fBmouseMoveEvent\fP (QMouseEvent *) override" .br .ti -1c .RI "void \fBmouseReleaseEvent\fP (QMouseEvent *) override" .br .ti -1c .RI "void \fBwheelEvent\fP (QWheelEvent *event) override" .br .ti -1c .RI "void \fBkeyPressEvent\fP (QKeyEvent *) override" .br .ti -1c .RI "void \fBchangeEvent\fP (QEvent *) override" .br .ti -1c .RI "void \fBtimerEvent\fP (QTimerEvent *event) override" .br .ti -1c .RI "void \fBinitStyleOption\fP (QStyleOptionTab *option, int tabIndex) const" .br .in -1c .SS "Additional Inherited Members" Public Types inherited from \fBKCustomTabBar\fP .in +1c .ti -1c .RI "enum \fBShape\fP { \fBRoundedNorth\fP, \fBRoundedSouth\fP, \fBRoundedWest\fP, \fBRoundedEast\fP, \fBTriangularNorth\fP, \fBTriangularSouth\fP, \fBTriangularWest\fP, \fBTriangularEast\fP }" .br .ti -1c .RI "enum \fBButtonPosition\fP { \fBLeftSide\fP, \fBRightSide\fP }" .br .ti -1c .RI "enum \fBSelectionBehavior\fP { \fBSelectLeftTab\fP, \fBSelectRightTab\fP, \fBSelectPreviousTab\fP }" .br .in -1c Public Slots inherited from \fBKCustomTabBar\fP .in +1c .ti -1c .RI "void \fBsetCurrentIndex\fP (int index)" .br .ti -1c .RI "void \fBleftScrollTabs\fP ()" .br .ti -1c .RI "void \fBrightScrollTabs\fP ()" .br .ti -1c .RI "void \fBcloseTab\fP ()" .br .in -1c Properties inherited from \fBKCustomTabBar\fP .in +1c .ti -1c .RI "Shape \fBshape\fP" .br .ti -1c .RI "int \fBcurrentIndex\fP" .br .ti -1c .RI "int \fBcount\fP" .br .ti -1c .RI "bool \fBdrawBase\fP" .br .ti -1c .RI "QSize \fBiconSize\fP" .br .ti -1c .RI "Qt::TextElideMode \fBelideMode\fP" .br .ti -1c .RI "bool \fBusesScrollButtons\fP" .br .ti -1c .RI "bool \fBtabsClosable\fP" .br .ti -1c .RI "SelectionBehavior \fBselectionBehaviorOnRemove\fP" .br .ti -1c .RI "bool \fBexpanding\fP" .br .ti -1c .RI "bool \fBmovable\fP" .br .ti -1c .RI "bool \fBdocumentMode\fP" .br .ti -1c .RI "bool \fBautoHide\fP" .br .ti -1c .RI "bool \fBchangeCurrentOnDrag\fP" .br .in -1c .SH "Member Function Documentation" .PP .SS "KNativeTabbarStyle kdk::KNativeTabbar::barStyle ()" .PP 返回TabBar样式 .PP \fBReturns\fP .RS 4 .RE .PP .SS "int kdk::KNativeTabbar::borderRadius ()" .PP 获取圆角半径 .PP \fBReturns\fP .RS 4 .RE .PP .SS "QSize kdk::KNativeTabbar::minimumTabSizeHint (int index) const\fC [protected]\fP, \fC [virtual]\fP" .PP Reimplemented from \fBKCustomTabBar\fP\&. .SS "void kdk::KNativeTabbar::rightlicked (QPoint point)\fC [signal]\fP" .PP 鼠标右键信号 .PP \fBParameters\fP .RS 4 \fIpoint\fP .RE .PP .SS "void kdk::KNativeTabbar::setBackgroundColor (const QColor & color)" .PP 设置背景色 .PP \fBParameters\fP .RS 4 \fIcolor\fP .RE .PP .SS "void kdk::KNativeTabbar::setBorderRadius (int radius)" .PP 设置圆角半径,只对SegmentDark,SegmentLight样式生效 .PP \fBParameters\fP .RS 4 \fIradius\fP .RE .PP .SS "void kdk::KNativeTabbar::setTabbarStyle (KNativeTabbarStyle barStyle)" .PP 设置TabBar样式 .PP \fBParameters\fP .RS 4 \fIbarStyle\fP .RE .PP .SS "QSize kdk::KNativeTabbar::tabSizeHint (int index) const\fC [protected]\fP, \fC [virtual]\fP" .PP Reimplemented from \fBKCustomTabBar\fP\&. .SH "Author" .PP Generated automatically by Doxygen for LIBKYSDK-APPLICATIONS from the source code\&. libkysdk-applications/doxygen/man/man3/kdk_KFlowLayout.30000664000175000017500000000540415104543305022226 0ustar fengfeng.TH "kdk::KFlowLayout" 3 "Version version:3.0" "LIBKYSDK-APPLICATIONS" \" -*- nroff -*- .ad l .nh .SH NAME kdk::KFlowLayout .SH SYNOPSIS .br .PP .PP Inherits QLayout\&. .SS "Public Member Functions" .in +1c .ti -1c .RI "\fBKFlowLayout\fP (QWidget *parent, bool home=false, int margin=\-1, int hSpacing=\-1, int vSpacing=\-1)" .br .RI "创建一个父对象为parent,边距为margin,水平间距为hSpacing,垂直间距为vSpacing的布局。 " .ti -1c .RI "\fBKFlowLayout\fP (int margin=\-1, int hSpacing=\-1, int vSpacing=\-1)" .br .RI "创建一个边距为margin,水平间距为hSpacing,垂直间距为vSpacing的布局。 " .ti -1c .RI "int \fBhorizontalSpacing\fP () const" .br .RI "水平间距 " .ti -1c .RI "int \fBverticalSpacing\fP () const" .br .RI "垂直间距 " .in -1c .SS "Protected Member Functions" .in +1c .ti -1c .RI "void \fBaddItem\fP (QLayoutItem *item) Q_DECL_OVERRIDE" .br .ti -1c .RI "Qt::Orientations \fBexpandingDirections\fP () const Q_DECL_OVERRIDE" .br .ti -1c .RI "bool \fBhasHeightForWidth\fP () const Q_DECL_OVERRIDE" .br .ti -1c .RI "int \fBheightForWidth\fP (int) const Q_DECL_OVERRIDE" .br .ti -1c .RI "int \fBcount\fP () const Q_DECL_OVERRIDE" .br .ti -1c .RI "QLayoutItem * \fBitemAt\fP (int index) const Q_DECL_OVERRIDE" .br .ti -1c .RI "QSize \fBminimumSize\fP () const Q_DECL_OVERRIDE" .br .ti -1c .RI "void \fBsetGeometry\fP (const QRect &rect) Q_DECL_OVERRIDE" .br .ti -1c .RI "QSize \fBsizeHint\fP () const Q_DECL_OVERRIDE" .br .ti -1c .RI "QLayoutItem * \fBtakeAt\fP (int index) Q_DECL_OVERRIDE" .br .in -1c .SH "Constructor & Destructor Documentation" .PP .SS "kdk::KFlowLayout::KFlowLayout (QWidget * parent, bool home = \fCfalse\fP, int margin = \fC\-1\fP, int hSpacing = \fC\-1\fP, int vSpacing = \fC\-1\fP)\fC [explicit]\fP" .PP 创建一个父对象为parent,边距为margin,水平间距为hSpacing,垂直间距为vSpacing的布局。 .PP \fBParameters\fP .RS 4 \fIhome\fP 是否首页布局 .br \fImargin\fP 边距 .br \fIhSpacing\fP 水平间距 .br \fIvSpacing\fP 垂直间距 .br \fIparent\fP .RE .PP .SS "kdk::KFlowLayout::KFlowLayout (int margin = \fC\-1\fP, int hSpacing = \fC\-1\fP, int vSpacing = \fC\-1\fP)\fC [explicit]\fP" .PP 创建一个边距为margin,水平间距为hSpacing,垂直间距为vSpacing的布局。 .PP \fBParameters\fP .RS 4 \fImargin\fP 边距 .br \fIhSpacing\fP 水平间距 .br \fIvSpacing\fP 垂直间距 .RE .PP .SH "Member Function Documentation" .PP .SS "int kdk::KFlowLayout::horizontalSpacing () const" .PP 水平间距 .PP \fBParameters\fP .RS 4 \fI无\fP .RE .PP .SS "int kdk::KFlowLayout::verticalSpacing () const" .PP 垂直间距 .PP \fBParameters\fP .RS 4 \fI无\fP .RE .PP .SH "Author" .PP Generated automatically by Doxygen for LIBKYSDK-APPLICATIONS from the source code\&. libkysdk-applications/doxygen/man/man3/kdk_KSecurityLevelBar.30000664000175000017500000000167615104543305023354 0ustar fengfeng.TH "kdk::KSecurityLevelBar" 3 "Version version:3.0" "LIBKYSDK-APPLICATIONS" \" -*- nroff -*- .ad l .nh .SH NAME kdk::KSecurityLevelBar \- 密码安全等级提示条,支持三个安全等级 .SH SYNOPSIS .br .PP .PP \fC#include \fP .PP Inherits QWidget\&. .SS "Public Member Functions" .in +1c .ti -1c .RI "\fBKSecurityLevelBar\fP (QWidget *parent=nullptr)" .br .ti -1c .RI "void \fBsetSecurityLevel\fP (\fBSecurityLevel\fP level)" .br .RI "设置安全等级 " .ti -1c .RI "\fBSecurityLevel\fP \fBsecurityLevel\fP ()" .br .RI "获取安全等级 " .in -1c .SS "Protected Member Functions" .in +1c .ti -1c .RI "void \fBpaintEvent\fP (QPaintEvent *event)" .br .in -1c .SH "Detailed Description" .PP 密码安全等级提示条,支持三个安全等级 .PP \fBExamples\fP .in +1c \fBtestsecuritylevelbar/widget\&.h\fP\&. .SH "Author" .PP Generated automatically by Doxygen for LIBKYSDK-APPLICATIONS from the source code\&. libkysdk-applications/doxygen/man/man3/KMiniCalendarWidget.30000664000175000017500000000054415104543305022762 0ustar fengfeng.TH "KMiniCalendarWidget" 3 "Version version:3.0" "LIBKYSDK-APPLICATIONS" \" -*- nroff -*- .ad l .nh .SH NAME KMiniCalendarWidget \- KMiniCalendarWidget .SH SYNOPSIS .br .PP .SH "Detailed Description" .PP .PP \fBSince\fP .RS 4 2\&.5\&.2\&.0 .RE .PP .SH "Author" .PP Generated automatically by Doxygen for LIBKYSDK-APPLICATIONS from the source code\&. libkysdk-applications/doxygen/man/man3/kdk_KBorderButton.30000664000175000017500000000227415104543305022534 0ustar fengfeng.TH "kdk::KBorderButton" 3 "Version version:3.0" "LIBKYSDK-APPLICATIONS" \" -*- nroff -*- .ad l .nh .SH NAME kdk::KBorderButton \- 带边框的按钮 .SH SYNOPSIS .br .PP .PP \fC#include \fP .PP Inherits QPushButton\&. .SS "Public Member Functions" .in +1c .ti -1c .RI "\fBKBorderButton\fP (QWidget *parent=nullptr)" .br .ti -1c .RI "\fBKBorderButton\fP (const QString &text, QWidget *parent=nullptr)" .br .ti -1c .RI "\fBKBorderButton\fP (const QIcon &icon, const QString &text, QWidget *parent=nullptr)" .br .ti -1c .RI "\fBKBorderButton\fP (const QIcon &icon, QWidget *parent=nullptr)" .br .ti -1c .RI "void \fBsetIcon\fP (const QIcon &icon)" .br .RI "设置按钮图标 " .in -1c .SS "Protected Member Functions" .in +1c .ti -1c .RI "bool \fBeventFilter\fP (QObject *watched, QEvent *event)" .br .ti -1c .RI "void \fBpaintEvent\fP (QPaintEvent *event)" .br .ti -1c .RI "QSize \fBsizeHint\fP () const override" .br .in -1c .SH "Detailed Description" .PP 带边框的按钮 .PP \fBSince\fP .RS 4 1\&.0\&.0 .RE .PP .PP \fBExamples\fP .in +1c \fBtestPushbutton/widget\&.h\fP\&. .SH "Author" .PP Generated automatically by Doxygen for LIBKYSDK-APPLICATIONS from the source code\&. libkysdk-applications/doxygen/man/man3/kdk_KAboutDialog.30000664000175000017500000000673115104543305022317 0ustar fengfeng.TH "kdk::KAboutDialog" 3 "Version version:3.0" "LIBKYSDK-APPLICATIONS" \" -*- nroff -*- .ad l .nh .SH NAME kdk::KAboutDialog \- 关于对话框,支持两种样式,一种是无特定说明的,另一种是有特定说明的。 .SH SYNOPSIS .br .PP .PP \fC#include \fP .PP Inherits \fBkdk::KDialog\fP\&. .SS "Public Member Functions" .in +1c .ti -1c .RI "\fBKAboutDialog\fP (QWidget *parent=nullptr, const QIcon &appIcon=QIcon(), const QString &\fBappName\fP='', const QString &\fBappVersion\fP='', const QString &appInfo='')" .br .ti -1c .RI "void \fBsetAppIcon\fP (const QIcon &icon)" .br .RI "设置应用程序图标 " .ti -1c .RI "void \fBsetAppName\fP (const QString &\fBappName\fP)" .br .RI "设置应用程序名称 " .ti -1c .RI "QString \fBappName\fP ()" .br .RI "获取应用程序名称 " .ti -1c .RI "void \fBsetAppVersion\fP (const QString &\fBappVersion\fP)" .br .RI "设置应用程序版本号 " .ti -1c .RI "QString \fBappVersion\fP ()" .br .RI "获取应用程序版本号 " .ti -1c .RI "void \fBsetBodyText\fP (const QString &\fBbodyText\fP)" .br .RI "设置具体的说明内容 " .ti -1c .RI "QString \fBbodyText\fP ()" .br .RI "获取具体的说明内容 " .ti -1c .RI "void \fBsetAppSupport\fP (const QString &\fBappSupport\fP)" .br .RI "设置服务与支持邮箱,有默认缺省 " .ti -1c .RI "QString \fBappSupport\fP ()" .br .RI "获取服务与支持邮箱 " .ti -1c .RI "void \fBsetBodyTextVisiable\fP (bool flag)" .br .RI "设置是否显示说明内容,应设计要求,1\&.2\&.0\&.9中不再显示说明内容 " .ti -1c .RI "void \fBsetAppPrivacyLabelVisible\fP (bool flag)" .br .RI "设置隐私按钮是否可见 " .ti -1c .RI "bool \fBAppPrivacyLabelIsVisible\fP ()" .br .RI "返回隐私按钮是否可见 " .in -1c Public Member Functions inherited from \fBkdk::KDialog\fP .in +1c .ti -1c .RI "\fBKDialog\fP (QWidget *parent=nullptr)" .br .ti -1c .RI "void \fBsetWindowIcon\fP (const QIcon &icon)" .br .RI "设置对话框图标 " .ti -1c .RI "void \fBsetWindowIcon\fP (const QString &iconName)" .br .RI "设置对话框图标 " .ti -1c .RI "void \fBsetWindowTitle\fP (const QString &)" .br .RI "设置对话框标题名称 " .ti -1c .RI "QPushButton * \fBmaximumButton\fP ()" .br .RI "获取最大化按钮 " .ti -1c .RI "QPushButton * \fBminimumButton\fP ()" .br .RI "获取最小化按钮 " .ti -1c .RI "QPushButton * \fBcloseButton\fP ()" .br .RI "获取关闭按钮 " .ti -1c .RI "\fBKMenuButton\fP * \fBmenuButton\fP ()" .br .RI "获取下拉菜单按钮 " .ti -1c .RI "QWidget * \fBmainWidget\fP ()" .br .RI "获取主内容区Widget " .ti -1c .RI "\fBKWindowButtonBar\fP * \fBwindowButtonBar\fP ()" .br .RI "windowButtonBar " .ti -1c .RI "\fBKIconBar\fP * \fBiconBar\fP ()" .br .RI "iconBar " .in -1c .SS "Protected Member Functions" .in +1c .ti -1c .RI "void \fBchangeTheme\fP () override" .br .ti -1c .RI "void \fBpaintEvent\fP (QPaintEvent *paintEvent) override" .br .in -1c Protected Member Functions inherited from \fBkdk::KDialog\fP .in +1c .ti -1c .RI "bool \fBeventFilter\fP (QObject *target, QEvent *event) override" .br .ti -1c .RI "void \fBchangeTheme\fP ()" .br .ti -1c .RI "void \fBchangeIconStyle\fP ()" .br .ti -1c .RI "QBoxLayout * \fBmainLayout\fP ()" .br .in -1c .SH "Detailed Description" .PP 关于对话框,支持两种样式,一种是无特定说明的,另一种是有特定说明的。 .PP \fBSince\fP .RS 4 1\&.0\&.0 .RE .PP .SH "Author" .PP Generated automatically by Doxygen for LIBKYSDK-APPLICATIONS from the source code\&. libkysdk-applications/doxygen/man/man3/kdk_KBreadCrumb.30000664000175000017500000000277715104543305022141 0ustar fengfeng.TH "kdk::KBreadCrumb" 3 "Version version:3.0" "LIBKYSDK-APPLICATIONS" \" -*- nroff -*- .ad l .nh .SH NAME kdk::KBreadCrumb \- 面包屑控件 .SH SYNOPSIS .br .PP .PP \fC#include \fP .PP Inherits QTabBar\&. .SS "Public Member Functions" .in +1c .ti -1c .RI "\fBKBreadCrumb\fP (QWidget *parent=nullptr)" .br .ti -1c .RI "void \fBsetIcon\fP (const QIcon &\fBicon\fP)" .br .RI "设置图标 " .ti -1c .RI "QIcon \fBicon\fP () const" .br .RI "获取图标 " .ti -1c .RI "bool \fBisFlat\fP () const" .br .RI "返回按钮边框是否凸起 " .ti -1c .RI "void \fBsetFlat\fP (bool flat)" .br .RI "设置按钮边框是否凸起 " .in -1c .SS "Protected Member Functions" .in +1c .ti -1c .RI "QSize \fBtabSizeHint\fP (int index) const" .br .ti -1c .RI "void \fBpaintEvent\fP (QPaintEvent *event)" .br .in -1c .SH "Detailed Description" .PP 面包屑控件 .PP \fBSince\fP .RS 4 1\&.0\&.0 .RE .PP .SH "Member Function Documentation" .PP .SS "QIcon kdk::KBreadCrumb::icon () const" .PP 获取图标 .PP \fBReturns\fP .RS 4 .RE .PP .SS "bool kdk::KBreadCrumb::isFlat () const" .PP 返回按钮边框是否凸起 .PP \fBReturns\fP .RS 4 .RE .PP .SS "void kdk::KBreadCrumb::setFlat (bool flat)" .PP 设置按钮边框是否凸起 .PP \fBParameters\fP .RS 4 \fIflat\fP .RE .PP .SS "void kdk::KBreadCrumb::setIcon (const QIcon & icon)" .PP 设置图标 .PP \fBParameters\fP .RS 4 \fIicon\fP .RE .PP .SH "Author" .PP Generated automatically by Doxygen for LIBKYSDK-APPLICATIONS from the source code\&. libkysdk-applications/doxygen/man/man3/MessageAlertModule.30000664000175000017500000001501415104543305022675 0ustar fengfeng.TH "MessageAlertModule" 3 "Version version:3.0" "LIBKYSDK-APPLICATIONS" \" -*- nroff -*- .ad l .nh .SH NAME MessageAlertModule \- MessageAlertModule .SH SYNOPSIS .br .PP .SS "Classes" .in +1c .ti -1c .RI "class \fBkdk::KBadge\fP" .br .RI "消息提醒气泡 " .ti -1c .RI "class \fBkdk::KBallonTip\fP" .br .RI "消息提示框,支持五种样式 " .ti -1c .RI "class \fBkdk::KSecurityLevelBar\fP" .br .RI "密码安全等级提示条,支持三个安全等级 " .in -1c .SS "Enumerations" .in +1c .ti -1c .RI "enum \fBkdk::TipType\fP { \fBNothing\fP, \fBNormal\fP, \fBInfo\fP, \fBWarning\fP, \fBError\fP, \fBVariable\fP }" .br .RI "支持五种样式 " .ti -1c .RI "enum \fBkdk::SecurityLevel\fP { \fBLow\fP, \fBMedium\fP, \fBHigh\fP }" .br .RI "分为三个安全等级 " .in -1c .SS "Functions" .in +1c .ti -1c .RI "\fBkdk::KBadge::KBadge\fP (QWidget *parent)" .br .ti -1c .RI "int \fBkdk::KBadge::value\fP ()" .br .RI "返回值 " .ti -1c .RI "void \fBkdk::KBadge::setValue\fP (int \fBvalue\fP)" .br .RI "设置值,最大显示数值为999,大于999显示'\&.\&.\&.' " .ti -1c .RI "void \fBkdk::KBadge::setValueVisiable\fP (bool flag)" .br .RI "设置值是否可见 " .ti -1c .RI "bool \fBkdk::KBadge::isValueVisiable\fP () const" .br .RI "获取值是否可见 " .ti -1c .RI "QColor \fBkdk::KBadge::color\fP ()" .br .RI "获取背景色 " .ti -1c .RI "void \fBkdk::KBadge::setColor\fP (const QColor &\fBcolor\fP)" .br .RI "设置背景色 " .ti -1c .RI "int \fBkdk::KBadge::fontSize\fP ()" .br .RI "获取字体大小 " .ti -1c .RI "void \fBkdk::KBadge::setFontSize\fP (int size)" .br .RI "设置字体大小 " .ti -1c .RI "void \fBkdk::KBadge::paintEvent\fP (QPaintEvent *event)" .br .ti -1c .RI "void \fBkdk::KBadge::resizeEvent\fP (QResizeEvent *event)" .br .ti -1c .RI "\fBkdk::KBallonTip::KBallonTip\fP (QWidget *parent=nullptr)" .br .ti -1c .RI "\fBkdk::KBallonTip::KBallonTip\fP (const QString &content, const \fBTipType\fP &type, QWidget *parent=nullptr)" .br .ti -1c .RI "void \fBkdk::KBallonTip::showInfo\fP ()" .br .RI "显示时间完毕后消失 " .ti -1c .RI "void \fBkdk::KBallonTip::setTipType\fP (const \fBTipType\fP &type)" .br .RI "设置类型 " .ti -1c .RI "\fBTipType\fP \fBkdk::KBallonTip::tipType\fP ()" .br .RI "返回类型 " .ti -1c .RI "void \fBkdk::KBallonTip::setText\fP (const QString &\fBtext\fP)" .br .RI "设置文本内容 " .ti -1c .RI "QString \fBkdk::KBallonTip::text\fP ()" .br .RI "text " .ti -1c .RI "void \fBkdk::KBallonTip::setContentsMargins\fP (int left, int top, int right, int bottom)" .br .RI "设置内容边距 " .ti -1c .RI "void \fBkdk::KBallonTip::setContentsMargins\fP (const QMargins &margins)" .br .RI "设置内容边距 " .ti -1c .RI "void \fBkdk::KBallonTip::setTipTime\fP (int my_time)" .br .RI "设置持续时间 " .ti -1c .RI "QHBoxLayout * \fBkdk::KBallonTip::hBoxLayout\fP ()" .br .RI "获取kballontip的水平布局 " .ti -1c .RI "void \fBkdk::KBallonTip::setVariableIcon\fP (QIcon icon)" .br .RI "设置可变类型的icon " .ti -1c .RI "QPixmap \fBkdk::KBallonTip::variableIcon\fP ()" .br .RI "获取可变类型的icon " .ti -1c .RI "void \fBkdk::KBallonTip::paintEvent\fP (QPaintEvent *event) override" .br .ti -1c .RI "\fBkdk::KSecurityLevelBar::KSecurityLevelBar\fP (QWidget *parent=nullptr)" .br .ti -1c .RI "void \fBkdk::KSecurityLevelBar::setSecurityLevel\fP (\fBSecurityLevel\fP level)" .br .RI "设置安全等级 " .ti -1c .RI "\fBSecurityLevel\fP \fBkdk::KSecurityLevelBar::securityLevel\fP ()" .br .RI "获取安全等级 " .ti -1c .RI "void \fBkdk::KSecurityLevelBar::paintEvent\fP (QPaintEvent *event)" .br .in -1c .SH "Detailed Description" .PP .SH "Enumeration Type Documentation" .PP .SS "enum \fBkdk::SecurityLevel\fP" .PP 分为三个安全等级 .PP \fBSince\fP .RS 4 1\&.0\&.0 .RE .PP .SS "enum \fBkdk::TipType\fP" .PP 支持五种样式 .PP \fBSince\fP .RS 4 1\&.0\&.0 .RE .PP .SH "Function Documentation" .PP .SS "QColor kdk::KBadge::color ()" .PP 获取背景色 .PP \fBReturns\fP .RS 4 .RE .PP .SS "int kdk::KBadge::fontSize ()" .PP 获取字体大小 .PP \fBReturns\fP .RS 4 .RE .PP .SS "QHBoxLayout * kdk::KBallonTip::hBoxLayout ()" .PP 获取kballontip的水平布局 .PP \fBReturns\fP .RS 4 .RE .PP \fBSince\fP .RS 4 2\&.4\&.1\&.0 .RE .PP .SS "\fBSecurityLevel\fP kdk::KSecurityLevelBar::securityLevel ()" .PP 获取安全等级 .PP \fBReturns\fP .RS 4 .RE .PP .SS "void kdk::KBadge::setColor (const QColor & color)" .PP 设置背景色 .PP \fBParameters\fP .RS 4 \fIcolor\fP .RE .PP .SS "void kdk::KBallonTip::setContentsMargins (const QMargins & margins)" .PP 设置内容边距 .PP \fBParameters\fP .RS 4 \fImargins\fP .RE .PP .SS "void kdk::KBallonTip::setContentsMargins (int left, int top, int right, int bottom)" .PP 设置内容边距 .PP \fBParameters\fP .RS 4 \fIleft\fP .br \fItop\fP .br \fIright\fP .br \fIbottom\fP .RE .PP .SS "void kdk::KBadge::setFontSize (int size)" .PP 设置字体大小 .PP \fBParameters\fP .RS 4 \fIsize\fP .RE .PP .SS "void kdk::KSecurityLevelBar::setSecurityLevel (\fBSecurityLevel\fP level)" .PP 设置安全等级 .PP \fBParameters\fP .RS 4 \fIlevel\fP .RE .PP .SS "void kdk::KBallonTip::setText (const QString & text)" .PP 设置文本内容 .PP \fBParameters\fP .RS 4 \fItext\fP .RE .PP .SS "void kdk::KBallonTip::setTipTime (int my_time)" .PP 设置持续时间 .PP \fBSince\fP .RS 4 1\&.2\&.0 .RE .PP .SS "void kdk::KBallonTip::setTipType (const \fBTipType\fP & type)" .PP 设置类型 .PP \fBParameters\fP .RS 4 \fItype\fP .RE .PP .SS "void kdk::KBadge::setValue (int value)" .PP 设置值,最大显示数值为999,大于999显示'\&.\&.\&.' .PP \fBParameters\fP .RS 4 \fIvalue\fP .RE .PP .SS "void kdk::KBadge::setValueVisiable (bool flag)" .PP 设置值是否可见 .PP \fBParameters\fP .RS 4 \fIflag\fP .RE .PP .SS "void kdk::KBallonTip::setVariableIcon (QIcon icon)" .PP 设置可变类型的icon .PP \fBParameters\fP .RS 4 \fIicon\fP .RE .PP \fBSince\fP .RS 4 2\&.5\&.2\&.0 .RE .PP .SS "void kdk::KBallonTip::showInfo ()" .PP 显示时间完毕后消失 .PP \fBSince\fP .RS 4 1\&.2\&.0 .RE .PP .SS "QString kdk::KBallonTip::text ()" .PP text .PP \fBReturns\fP .RS 4 .RE .PP .SS "\fBTipType\fP kdk::KBallonTip::tipType ()" .PP 返回类型 .PP \fBReturns\fP .RS 4 .RE .PP .SS "int kdk::KBadge::value ()" .PP 返回值 .PP \fBReturns\fP .RS 4 .RE .PP .SS "QPixmap kdk::KBallonTip::variableIcon ()" .PP 获取可变类型的icon .PP \fBReturns\fP .RS 4 .RE .PP \fBSince\fP .RS 4 2\&.5\&.2\&.0 .RE .PP .SH "Author" .PP Generated automatically by Doxygen for LIBKYSDK-APPLICATIONS from the source code\&. libkysdk-applications/doxygen/man/man3/kdk_UkuiStyleHelper.30000664000175000017500000000204115104543305023076 0ustar fengfeng.TH "kdk::UkuiStyleHelper" 3 "Version version:3.0" "LIBKYSDK-APPLICATIONS" \" -*- nroff -*- .ad l .nh .SH NAME kdk::UkuiStyleHelper \- 解决wayland环境下的双标题栏问题 .SH SYNOPSIS .br .PP .PP \fC#include \fP .PP Inherits QObject\&. .SS "Public Member Functions" .in +1c .ti -1c .RI "void \fBremoveHeader\fP (QWidget *widget)" .br .RI "移除窗管标题栏 " .in -1c .SS "Static Public Member Functions" .in +1c .ti -1c .RI "static \fBUkuiStyleHelper\fP * \fBself\fP ()" .br .in -1c .SS "Protected Member Functions" .in +1c .ti -1c .RI "bool \fBeventFilter\fP (QObject *obj, QEvent *ev) override" .br .in -1c .SH "Detailed Description" .PP 解决wayland环境下的双标题栏问题 .PP \fBSince\fP .RS 4 1\&.2\&.0 .RE .PP .SH "Member Function Documentation" .PP .SS "void kdk::UkuiStyleHelper::removeHeader (QWidget * widget)" .PP 移除窗管标题栏 .PP \fBParameters\fP .RS 4 \fIwidget\fP .RE .PP .SH "Author" .PP Generated automatically by Doxygen for LIBKYSDK-APPLICATIONS from the source code\&. libkysdk-applications/doxygen/man/man3/kdk_KPushButton.30000664000175000017500000001460515104543305022237 0ustar fengfeng.TH "kdk::KPushButton" 3 "Version version:3.0" "LIBKYSDK-APPLICATIONS" \" -*- nroff -*- .ad l .nh .SH NAME kdk::KPushButton \- 1\&.提供半透明效果 2\&.可以设置按钮圆角、背景色、图标是否跟随系统高亮 3\&.可以设置按钮类型,分为正常类型和圆形(需要设置大小实现正圆),其余同QPushButton .SH SYNOPSIS .br .PP .PP \fC#include \fP .PP Inherits QPushButton\&. .SS "Public Types" .in +1c .ti -1c .RI "enum \fBButtonType\fP { \fBNormalType\fP, \fBCircleType\fP, \fBGrayType\fP, \fBShadowType\fP }" .br .RI "支持两种样式的按钮 " .ti -1c .RI "enum \fBArrowDirection\fP { \fBArrowTop\fP, \fBArrowBottom\fP, \fBArrowLeft\fP, \fBArrowRight\fP }" .br .in -1c .SS "Public Member Functions" .in +1c .ti -1c .RI "\fBKPushButton\fP (QWidget *parent=nullptr)" .br .ti -1c .RI "void \fBsetBorderRadius\fP (int radius)" .br .RI "设置按钮圆角 通过圆角半径设置按钮圆角(每个圆角相同) " .ti -1c .RI "void \fBsetBorderRadius\fP (int bottomLeft, int topLeft, int topRight, int bottomRight)" .br .RI "设置按钮圆角 通过四个点来设置圆角 " .ti -1c .RI "int \fBborderRadius\fP ()" .br .RI "获取按钮圆角 " .ti -1c .RI "void \fBsetBackgroundColor\fP (QColor color)" .br .RI "设置按钮背景色 " .ti -1c .RI "QColor \fBbackgroundColor\fP ()" .br .RI "获取按钮背景色 " .ti -1c .RI "void \fBsetButtonType\fP (\fBButtonType\fP type)" .br .RI "设置KPushButton的类型 " .ti -1c .RI "\fBButtonType\fP \fBbuttonType\fP ()" .br .RI "获取KPushButton的类型 " .ti -1c .RI "void \fBsetTranslucent\fP (bool flag)" .br .RI "设置KPushButton是否为半透明 " .ti -1c .RI "bool \fBisTranslucent\fP ()" .br .RI "判断KPushButton是否为半透明 " .ti -1c .RI "void \fBsetIconHighlight\fP (bool flag)" .br .RI "设置图标是否跟随系统高亮色,默认不跟随 " .ti -1c .RI "bool \fBisIconHighlight\fP ()" .br .RI "判断图标是否跟随系统高亮色 " .ti -1c .RI "void \fBsetIconColor\fP (QColor color)" .br .RI "设置按钮添加图标的颜色 " .ti -1c .RI "QColor \fBIconColor\fP ()" .br .RI "获取按钮添加图标的颜色 " .ti -1c .RI "void \fBsetBackgroundColorHighlight\fP (bool flag)" .br .RI "设置按钮背景色是否跟随系统高亮色,默认不跟随 " .ti -1c .RI "bool \fBisBackgroundColorHighlight\fP ()" .br .RI "判断按钮背景色是否跟随系统高亮色 " .ti -1c .RI "void \fBsetArrow\fP (bool flag, ArrowDirection arrowDirection=ArrowBottom)" .br .RI "设置是否显示箭头flag,设置箭头方向arrowDirection " .ti -1c .RI "bool \fBhasArrow\fP () const" .br .RI "返回是否显示箭头 " .ti -1c .RI "void \fBsetLoaingStatus\fP (bool flag)" .br .RI "设置加载样式 " .ti -1c .RI "bool \fBisLoading\fP ()" .br .RI "返回加载样式 " .in -1c .SS "Protected Member Functions" .in +1c .ti -1c .RI "bool \fBeventFilter\fP (QObject *watched, QEvent *event)" .br .ti -1c .RI "void \fBpaintEvent\fP (QPaintEvent *event)" .br .in -1c .SH "Detailed Description" .PP 1\&.提供半透明效果 2\&.可以设置按钮圆角、背景色、图标是否跟随系统高亮 3\&.可以设置按钮类型,分为正常类型和圆形(需要设置大小实现正圆),其余同QPushButton .PP \fBSince\fP .RS 4 1\&.2\&.0 .RE .PP .SH "Member Function Documentation" .PP .SS "QColor kdk::KPushButton::backgroundColor ()" .PP 获取按钮背景色 .PP \fBReturns\fP .RS 4 color .RE .PP .SS "int kdk::KPushButton::borderRadius ()" .PP 获取按钮圆角 .PP \fBReturns\fP .RS 4 radius .RE .PP .SS "\fBButtonType\fP kdk::KPushButton::buttonType ()" .PP 获取KPushButton的类型 .PP \fBReturns\fP .RS 4 .RE .PP .SS "bool kdk::KPushButton::hasArrow () const" .PP 返回是否显示箭头 .PP \fBReturns\fP .RS 4 bool .RE .PP \fBSince\fP .RS 4 2\&.4\&.1\&.0 .RE .PP .SS "QColor kdk::KPushButton::IconColor ()" .PP 获取按钮添加图标的颜色 .PP \fBReturns\fP .RS 4 .RE .PP .SS "bool kdk::KPushButton::isBackgroundColorHighlight ()" .PP 判断按钮背景色是否跟随系统高亮色 .PP \fBReturns\fP .RS 4 .RE .PP .SS "bool kdk::KPushButton::isIconHighlight ()" .PP 判断图标是否跟随系统高亮色 .PP \fBReturns\fP .RS 4 .RE .PP .SS "bool kdk::KPushButton::isLoading ()" .PP 返回加载样式 .PP \fBReturns\fP .RS 4 .RE .PP \fBSince\fP .RS 4 2\&.5\&.2\&.0 .RE .PP .SS "bool kdk::KPushButton::isTranslucent ()" .PP 判断KPushButton是否为半透明 .PP \fBReturns\fP .RS 4 .RE .PP .SS "void kdk::KPushButton::setArrow (bool flag, ArrowDirection arrowDirection = \fCArrowBottom\fP)" .PP 设置是否显示箭头flag,设置箭头方向arrowDirection .PP \fBParameters\fP .RS 4 \fIflag\fP .br \fIarrowDirection\fP .RE .PP \fBSince\fP .RS 4 2\&.4\&.1\&.0 .RE .PP .SS "void kdk::KPushButton::setBackgroundColor (QColor color)" .PP 设置按钮背景色 .PP \fBParameters\fP .RS 4 \fIcolor\fP .RE .PP .SS "void kdk::KPushButton::setBackgroundColorHighlight (bool flag)" .PP 设置按钮背景色是否跟随系统高亮色,默认不跟随 .PP \fBParameters\fP .RS 4 \fIflag\fP .RE .PP .SS "void kdk::KPushButton::setBorderRadius (int bottomLeft, int topLeft, int topRight, int bottomRight)" .PP 设置按钮圆角 通过四个点来设置圆角 .PP \fBParameters\fP .RS 4 \fIbottomLeft(左下)\fP .br \fItopLeft(左上)\fP .br \fItopRight(右上)\fP .br \fIbottomRight(右下)\fP .RE .PP .SS "void kdk::KPushButton::setBorderRadius (int radius)" .PP 设置按钮圆角 通过圆角半径设置按钮圆角(每个圆角相同) .PP \fBParameters\fP .RS 4 \fIradius\fP .RE .PP .SS "void kdk::KPushButton::setButtonType (\fBButtonType\fP type)" .PP 设置KPushButton的类型 .PP \fBParameters\fP .RS 4 \fItype\fP .RE .PP .SS "void kdk::KPushButton::setIconColor (QColor color)" .PP 设置按钮添加图标的颜色 .PP \fBParameters\fP .RS 4 \fIcolor\fP .RE .PP .SS "void kdk::KPushButton::setIconHighlight (bool flag)" .PP 设置图标是否跟随系统高亮色,默认不跟随 .PP \fBParameters\fP .RS 4 \fIflag\fP .RE .PP .SS "void kdk::KPushButton::setLoaingStatus (bool flag)" .PP 设置加载样式 .PP \fBParameters\fP .RS 4 \fIflag\fP .RE .PP \fBSince\fP .RS 4 2\&.5\&.2\&.0 .RE .PP .SS "void kdk::KPushButton::setTranslucent (bool flag)" .PP 设置KPushButton是否为半透明 .PP \fBParameters\fP .RS 4 \fIflag\fP .RE .PP .SH "Author" .PP Generated automatically by Doxygen for LIBKYSDK-APPLICATIONS from the source code\&. libkysdk-applications/doxygen/man/man3/kdk_KCrumb.30000664000175000017500000002342015104543305021167 0ustar fengfeng.TH "kdk::KCrumb" 3 "Version version:3.0" "LIBKYSDK-APPLICATIONS" \" -*- nroff -*- .ad l .nh .SH NAME kdk::KCrumb \- 面包屑控件 .SH SYNOPSIS .br .PP .PP \fC#include \fP .PP Inherits \fBKCustomTabBar\fP\&. .SS "Public Slots" .in +1c .ti -1c .RI "void \fBleftScroll\fP ()" .br .ti -1c .RI "void \fBrightScroll\fP ()" .br .in -1c Public Slots inherited from \fBKCustomTabBar\fP .in +1c .ti -1c .RI "void \fBsetCurrentIndex\fP (int index)" .br .ti -1c .RI "void \fBleftScrollTabs\fP ()" .br .ti -1c .RI "void \fBrightScrollTabs\fP ()" .br .ti -1c .RI "void \fBcloseTab\fP ()" .br .in -1c .SS "Public Member Functions" .in +1c .ti -1c .RI "\fBKCrumb\fP (QWidget *parent=nullptr)" .br .ti -1c .RI "int \fBaddTab\fP (const QString &text)" .br .RI "添加tab " .ti -1c .RI "int \fBaddTab\fP (const QIcon &\fBicon\fP, const QString &text)" .br .RI "添加tab " .ti -1c .RI "int \fBinsertTab\fP (int index, const QString &text)" .br .RI "在index位置插入tab " .ti -1c .RI "int \fBinsertTab\fP (int index, const QIcon &\fBicon\fP, const QString &text)" .br .RI "在index位置插入tab " .ti -1c .RI "void \fBremoveTab\fP (int index)" .br .RI "删除index位置的tab " .ti -1c .RI "void \fBmoveTab\fP (int from, int to)" .br .RI "将from位置tab移至to位置 " .ti -1c .RI "void \fBsetIcon\fP (const QIcon &\fBicon\fP)" .br .RI "设置图标 " .ti -1c .RI "QIcon \fBicon\fP () const" .br .RI "获取图标 " .ti -1c .RI "bool \fBisFlat\fP () const" .br .RI "返回按钮边框是否凸起 " .ti -1c .RI "void \fBsetFlat\fP (bool flat)" .br .RI "设置按钮边框是否凸起 " .in -1c Public Member Functions inherited from \fBKCustomTabBar\fP .in +1c .ti -1c .RI "\fBKCustomTabBar\fP (QWidget *parent=nullptr)" .br .ti -1c .RI "Shape \fBshape\fP () const" .br .ti -1c .RI "void \fBsetShape\fP (Shape shape)" .br .ti -1c .RI "int \fBaddTab\fP (const QString &text)" .br .ti -1c .RI "int \fBaddTab\fP (const QIcon &icon, const QString &text)" .br .ti -1c .RI "int \fBinsertTab\fP (int index, const QString &text)" .br .ti -1c .RI "int \fBinsertTab\fP (int index, const QIcon &icon, const QString &text)" .br .ti -1c .RI "void \fBremoveTab\fP (int index)" .br .ti -1c .RI "void \fBmoveTab\fP (int from, int to)" .br .ti -1c .RI "bool \fBisTabEnabled\fP (int index) const" .br .ti -1c .RI "void \fBsetTabEnabled\fP (int index, bool)" .br .ti -1c .RI "QString \fBtabText\fP (int index) const" .br .ti -1c .RI "void \fBsetTabText\fP (int index, const QString &text)" .br .ti -1c .RI "void \fBsetTabContent\fP (int index, const QString &text)" .br .ti -1c .RI "QColor \fBtabTextColor\fP (int index) const" .br .ti -1c .RI "void \fBsetTabTextColor\fP (int index, const QColor &color)" .br .ti -1c .RI "QIcon \fBtabIcon\fP (int index) const" .br .ti -1c .RI "void \fBsetTabIcon\fP (int index, const QIcon &icon)" .br .ti -1c .RI "Qt::TextElideMode \fBelideMode\fP () const" .br .ti -1c .RI "void \fBsetElideMode\fP (Qt::TextElideMode)" .br .ti -1c .RI "void \fBsetTabToolTip\fP (int index, const QString &tip)" .br .ti -1c .RI "QString \fBtabToolTip\fP (int index) const" .br .ti -1c .RI "void \fBsetTabWhatsThis\fP (int index, const QString &text)" .br .ti -1c .RI "QString \fBtabWhatsThis\fP (int index) const" .br .ti -1c .RI "void \fBsetTabData\fP (int index, const QVariant &data)" .br .ti -1c .RI "QVariant \fBtabData\fP (int index) const" .br .ti -1c .RI "QRect \fBtabRect\fP (int index) const" .br .ti -1c .RI "int \fBtabAt\fP (const QPoint &pos) const" .br .ti -1c .RI "int \fBcurrentIndex\fP () const" .br .ti -1c .RI "int \fBcount\fP () const" .br .ti -1c .RI "QSize \fBsizeHint\fP () const override" .br .ti -1c .RI "QSize \fBminimumSizeHint\fP () const override" .br .ti -1c .RI "void \fBsetDrawBase\fP (bool drawTheBase)" .br .ti -1c .RI "bool \fBdrawBase\fP () const" .br .ti -1c .RI "QSize \fBiconSize\fP () const" .br .ti -1c .RI "void \fBsetIconSize\fP (const QSize &size)" .br .ti -1c .RI "bool \fBusesScrollButtons\fP () const" .br .ti -1c .RI "void \fBsetUsesScrollButtons\fP (bool useButtons)" .br .ti -1c .RI "bool \fBtabsClosable\fP () const" .br .ti -1c .RI "void \fBsetTabsClosable\fP (bool closable)" .br .ti -1c .RI "void \fBsetTabButton\fP (int index, ButtonPosition position, QWidget *widget)" .br .ti -1c .RI "QWidget * \fBtabButton\fP (int index, ButtonPosition position) const" .br .ti -1c .RI "SelectionBehavior \fBselectionBehaviorOnRemove\fP () const" .br .ti -1c .RI "void \fBsetSelectionBehaviorOnRemove\fP (SelectionBehavior behavior)" .br .ti -1c .RI "bool \fBexpanding\fP () const" .br .ti -1c .RI "void \fBsetExpanding\fP (bool enabled)" .br .ti -1c .RI "bool \fBisMovable\fP () const" .br .ti -1c .RI "void \fBsetMovable\fP (bool movable)" .br .ti -1c .RI "bool \fBdocumentMode\fP () const" .br .ti -1c .RI "void \fBsetDocumentMode\fP (bool set)" .br .ti -1c .RI "bool \fBautoHide\fP () const" .br .ti -1c .RI "void \fBsetAutoHide\fP (bool hide)" .br .ti -1c .RI "bool \fBchangeCurrentOnDrag\fP () const" .br .ti -1c .RI "void \fBsetChangeCurrentOnDrag\fP (bool change)" .br .ti -1c .RI "QString \fBaccessibleTabName\fP (int index) const" .br .ti -1c .RI "void \fBsetAccessibleTabName\fP (int index, const QString &name)" .br .in -1c .SS "Protected Member Functions" .in +1c .ti -1c .RI "QSize \fBtabSizeHint\fP (int index) const" .br .ti -1c .RI "void \fBpaintEvent\fP (QPaintEvent *event)" .br .in -1c Protected Member Functions inherited from \fBKCustomTabBar\fP .in +1c .ti -1c .RI "virtual QSize \fBminimumTabSizeHint\fP (int index) const" .br .ti -1c .RI "virtual void \fBtabInserted\fP (int index)" .br .ti -1c .RI "virtual void \fBtabRemoved\fP (int index)" .br .ti -1c .RI "virtual void \fBtabLayoutChange\fP ()" .br .ti -1c .RI "bool \fBevent\fP (QEvent *) override" .br .ti -1c .RI "void \fBresizeEvent\fP (QResizeEvent *) override" .br .ti -1c .RI "void \fBshowEvent\fP (QShowEvent *) override" .br .ti -1c .RI "void \fBhideEvent\fP (QHideEvent *) override" .br .ti -1c .RI "void \fBpaintEvent\fP (QPaintEvent *) override" .br .ti -1c .RI "void \fBmousePressEvent\fP (QMouseEvent *) override" .br .ti -1c .RI "void \fBmouseMoveEvent\fP (QMouseEvent *) override" .br .ti -1c .RI "void \fBmouseReleaseEvent\fP (QMouseEvent *) override" .br .ti -1c .RI "void \fBwheelEvent\fP (QWheelEvent *event) override" .br .ti -1c .RI "void \fBkeyPressEvent\fP (QKeyEvent *) override" .br .ti -1c .RI "void \fBchangeEvent\fP (QEvent *) override" .br .ti -1c .RI "void \fBtimerEvent\fP (QTimerEvent *event) override" .br .ti -1c .RI "void \fBinitStyleOption\fP (QStyleOptionTab *option, int tabIndex) const" .br .in -1c .SS "Additional Inherited Members" Public Types inherited from \fBKCustomTabBar\fP .in +1c .ti -1c .RI "enum \fBShape\fP { \fBRoundedNorth\fP, \fBRoundedSouth\fP, \fBRoundedWest\fP, \fBRoundedEast\fP, \fBTriangularNorth\fP, \fBTriangularSouth\fP, \fBTriangularWest\fP, \fBTriangularEast\fP }" .br .ti -1c .RI "enum \fBButtonPosition\fP { \fBLeftSide\fP, \fBRightSide\fP }" .br .ti -1c .RI "enum \fBSelectionBehavior\fP { \fBSelectLeftTab\fP, \fBSelectRightTab\fP, \fBSelectPreviousTab\fP }" .br .in -1c Signals inherited from \fBKCustomTabBar\fP .in +1c .ti -1c .RI "void \fBcurrentChanged\fP (int index)" .br .ti -1c .RI "void \fBtabCloseRequested\fP (int index)" .br .ti -1c .RI "void \fBtabMoved\fP (int from, int to)" .br .ti -1c .RI "void \fBtabBarClicked\fP (int index)" .br .ti -1c .RI "void \fBtabBarDoubleClicked\fP (int index)" .br .ti -1c .RI "void \fBleftBStatus\fP (bool flag)" .br .ti -1c .RI "void \fBrightBStatus\fP (bool flag)" .br .in -1c Properties inherited from \fBKCustomTabBar\fP .in +1c .ti -1c .RI "Shape \fBshape\fP" .br .ti -1c .RI "int \fBcurrentIndex\fP" .br .ti -1c .RI "int \fBcount\fP" .br .ti -1c .RI "bool \fBdrawBase\fP" .br .ti -1c .RI "QSize \fBiconSize\fP" .br .ti -1c .RI "Qt::TextElideMode \fBelideMode\fP" .br .ti -1c .RI "bool \fBusesScrollButtons\fP" .br .ti -1c .RI "bool \fBtabsClosable\fP" .br .ti -1c .RI "SelectionBehavior \fBselectionBehaviorOnRemove\fP" .br .ti -1c .RI "bool \fBexpanding\fP" .br .ti -1c .RI "bool \fBmovable\fP" .br .ti -1c .RI "bool \fBdocumentMode\fP" .br .ti -1c .RI "bool \fBautoHide\fP" .br .ti -1c .RI "bool \fBchangeCurrentOnDrag\fP" .br .in -1c .SH "Detailed Description" .PP 面包屑控件 .SH "Member Function Documentation" .PP .SS "int kdk::KCrumb::addTab (const QIcon & icon, const QString & text)" .PP 添加tab .PP \fBParameters\fP .RS 4 \fIicon\fP .br \fItext\fP .RE .PP \fBReturns\fP .RS 4 .RE .PP .SS "int kdk::KCrumb::addTab (const QString & text)" .PP 添加tab .PP \fBParameters\fP .RS 4 \fItext\fP .RE .PP \fBReturns\fP .RS 4 .RE .PP .SS "QIcon kdk::KCrumb::icon () const" .PP 获取图标 .PP \fBReturns\fP .RS 4 .RE .PP .SS "int kdk::KCrumb::insertTab (int index, const QIcon & icon, const QString & text)" .PP 在index位置插入tab .PP \fBParameters\fP .RS 4 \fIindex\fP .br \fIicon\fP .br \fItext\fP .RE .PP \fBReturns\fP .RS 4 .RE .PP .SS "int kdk::KCrumb::insertTab (int index, const QString & text)" .PP 在index位置插入tab .PP \fBParameters\fP .RS 4 \fIindex\fP .br \fItext\fP .RE .PP \fBReturns\fP .RS 4 .RE .PP .SS "bool kdk::KCrumb::isFlat () const" .PP 返回按钮边框是否凸起 .PP \fBReturns\fP .RS 4 .RE .PP .SS "void kdk::KCrumb::moveTab (int from, int to)" .PP 将from位置tab移至to位置 .PP \fBParameters\fP .RS 4 \fIfrom\fP .br \fIto\fP .RE .PP .SS "void kdk::KCrumb::removeTab (int index)" .PP 删除index位置的tab .PP \fBParameters\fP .RS 4 \fIindex\fP .RE .PP .SS "void kdk::KCrumb::setFlat (bool flat)" .PP 设置按钮边框是否凸起 .PP \fBParameters\fP .RS 4 \fIflat\fP .RE .PP .SS "void kdk::KCrumb::setIcon (const QIcon & icon)" .PP 设置图标 .PP \fBParameters\fP .RS 4 \fIicon\fP .RE .PP .SS "QSize kdk::KCrumb::tabSizeHint (int index) const\fC [protected]\fP, \fC [virtual]\fP" .PP Reimplemented from \fBKCustomTabBar\fP\&. .SH "Author" .PP Generated automatically by Doxygen for LIBKYSDK-APPLICATIONS from the source code\&. libkysdk-applications/doxygen/man/man3/kdk_KTabBar.30000664000175000017500000000265415104543305021260 0ustar fengfeng.TH "kdk::KTabBar" 3 "Version version:3.0" "LIBKYSDK-APPLICATIONS" \" -*- nroff -*- .ad l .nh .SH NAME kdk::KTabBar \- 支持三种样式 .SH SYNOPSIS .br .PP .PP \fC#include \fP .PP Inherits QTabBar\&. .SS "Signals" .in +1c .ti -1c .RI "void \fBrightlicked\fP (QPoint point)" .br .RI "鼠标右键信号 " .in -1c .SS "Public Member Functions" .in +1c .ti -1c .RI "\fBKTabBar\fP (\fBKTabBarStyle\fP \fBbarStyle\fP=SegmentLight, QWidget *parent=nullptr)" .br .ti -1c .RI "void \fBsetTabBarStyle\fP (\fBKTabBarStyle\fP \fBbarStyle\fP)" .br .RI "设置TabBar样式 " .ti -1c .RI "\fBKTabBarStyle\fP \fBbarStyle\fP ()" .br .RI "返回TabBar样式 " .ti -1c .RI "void \fBsetBorderRadius\fP (int radius)" .br .RI "设置圆角半径,只对SegmentDark,SegmentLight样式生效 " .ti -1c .RI "int \fBborderRadius\fP ()" .br .RI "获取圆角半径 " .ti -1c .RI "void \fBsetBackgroundColor\fP (const QColor &color)" .br .RI "设置背景色 " .in -1c .SS "Protected Member Functions" .in +1c .ti -1c .RI "QSize \fBsizeHint\fP () const" .br .ti -1c .RI "QSize \fBminimumTabSizeHint\fP (int index) const" .br .ti -1c .RI "QSize \fBtabSizeHint\fP (int index) const" .br .ti -1c .RI "void \fBpaintEvent\fP (QPaintEvent *event)" .br .in -1c .SH "Detailed Description" .PP 支持三种样式 .PP \fBSince\fP .RS 4 1\&.0\&.0 .RE .PP .SH "Author" .PP Generated automatically by Doxygen for LIBKYSDK-APPLICATIONS from the source code\&. libkysdk-applications/doxygen/man/man3/kdk_KTableHeaderView.30000664000175000017500000000345015104543305023113 0ustar fengfeng.TH "kdk::KTableHeaderView" 3 "Version version:3.0" "LIBKYSDK-APPLICATIONS" \" -*- nroff -*- .ad l .nh .SH NAME kdk::KTableHeaderView .SH SYNOPSIS .br .PP .PP Inherits QHeaderView\&. .SS "Public Slots" .in +1c .ti -1c .RI "void \fBcheckStateChangeSlot\fP (int iState)" .br .in -1c .SS "Signals" .in +1c .ti -1c .RI "void \fBcheckStateChange\fP (int state)" .br .ti -1c .RI "void \fBclickedHeader\fP (int column)" .br .in -1c .SS "Public Member Functions" .in +1c .ti -1c .RI "\fBKTableHeaderView\fP (Qt::Orientation orientation, QWidget *parent=nullptr)" .br .RI "\fBKTableHeaderView\fP 构造函数 " .ti -1c .RI "void \fBsetTitle\fP (QStringList list)" .br .RI "设置水平标题 " .ti -1c .RI "void \fBsetMenu\fP (QMenu *menu, int column)" .br .RI "设置menu " .in -1c .SS "Protected Member Functions" .in +1c .ti -1c .RI "void \fBpaintSection\fP (QPainter *painter, const QRect &rect, int logicalIndex) const" .br .ti -1c .RI "void \fBmousePressEvent\fP (QMouseEvent *e)" .br .ti -1c .RI "void \fBmouseReleaseEvent\fP (QMouseEvent *e)" .br .ti -1c .RI "bool \fBevent\fP (QEvent *e)" .br .in -1c .SH "Constructor & Destructor Documentation" .PP .SS "kdk::KTableHeaderView::KTableHeaderView (Qt::Orientation orientation, QWidget * parent = \fCnullptr\fP)" .PP \fBKTableHeaderView\fP 构造函数 .PP \fBParameters\fP .RS 4 \fIorientation\fP 方向 .br \fIparent\fP 父类对象 .RE .PP .SH "Member Function Documentation" .PP .SS "void kdk::KTableHeaderView::setMenu (QMenu * menu, int column)" .PP 设置menu .PP \fBParameters\fP .RS 4 \fImenu\fP .br \fIcolumn\fP .RE .PP .SS "void kdk::KTableHeaderView::setTitle (QStringList list)" .PP 设置水平标题 .PP \fBParameters\fP .RS 4 \fIlist\fP .RE .PP .SH "Author" .PP Generated automatically by Doxygen for LIBKYSDK-APPLICATIONS from the source code\&. libkysdk-applications/doxygen/doxy_config0000664000175000017500000033227415104543305017723 0ustar fengfeng# Doxyfile 1.8.17 # This file describes the settings to be used by the documentation system # doxygen (www.doxygen.org) for a project. # # All text after a double hash (##) is considered a comment and is placed in # front of the TAG it is preceding. # # All text after a single hash (#) is considered a comment and will be ignored. # The format is: # TAG = value [value, ...] # For lists, items can also be appended using: # TAG += value [value, ...] # Values that contain spaces should be placed between quotes (\" \"). #--------------------------------------------------------------------------- # Project related configuration options #--------------------------------------------------------------------------- # This tag specifies the encoding used for all characters in the configuration # file that follow. The default is UTF-8 which is also the encoding used for all # text before the first occurrence of this tag. Doxygen uses libiconv (or the # iconv built into libc) for the transcoding. See # https://www.gnu.org/software/libiconv/ for the list of possible encodings. # The default value is: UTF-8. DOXYFILE_ENCODING = UTF-8 # The PROJECT_NAME tag is a single word (or a sequence of words surrounded by # double-quotes, unless you are using Doxywizard) that should identify the # project for which the documentation is generated. This name is used in the # title of most generated pages and in a few other places. # The default value is: My Project. PROJECT_NAME = "LIBKYSDK-APPLICATIONS" # The PROJECT_NUMBER tag can be used to enter a project or revision number. This # could be handy for archiving the generated documentation or if some version # control system is used. PROJECT_NUMBER ="version:3.0" # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer a # quick idea about the purpose of the project. Keep the description short. PROJECT_BRIEF = # With the PROJECT_LOGO tag one can specify a logo or an icon that is included # in the documentation. The maximum height of the logo should not exceed 55 # pixels and the maximum width should not exceed 200 pixels. Doxygen will copy # the logo to the output directory. PROJECT_LOGO = # The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path # into which the generated documentation will be written. If a relative path is # entered, it will be relative to the location where doxygen was started. If # left blank the current directory will be used. OUTPUT_DIRECTORY = # If the CREATE_SUBDIRS tag is set to YES then doxygen will create 4096 sub- # directories (in 2 levels) under the output directory of each output format and # will distribute the generated files over these directories. Enabling this # option can be useful when feeding doxygen a huge amount of source files, where # putting all generated files in the same directory would otherwise causes # performance problems for the file system. # The default value is: NO. CREATE_SUBDIRS = NO # If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII # characters to appear in the names of generated files. If set to NO, non-ASCII # characters will be escaped, for example _xE3_x81_x84 will be used for Unicode # U+3044. # The default value is: NO. ALLOW_UNICODE_NAMES = NO # The OUTPUT_LANGUAGE tag is used to specify the language in which all # documentation generated by doxygen is written. Doxygen will use this # information to generate all constant output in the proper language. # Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese, # Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States), # Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian, # Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages), # Korean, Korean-en (Korean with English messages), Latvian, Lithuanian, # Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian, # Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish, # Ukrainian and Vietnamese. # The default value is: English. OUTPUT_LANGUAGE = English # The OUTPUT_TEXT_DIRECTION tag is used to specify the direction in which all # documentation generated by doxygen is written. Doxygen will use this # information to generate all generated output in the proper direction. # Possible values are: None, LTR, RTL and Context. # The default value is: None. OUTPUT_TEXT_DIRECTION = None # If the BRIEF_MEMBER_DESC tag is set to YES, doxygen will include brief member # descriptions after the members that are listed in the file and class # documentation (similar to Javadoc). Set to NO to disable this. # The default value is: YES. BRIEF_MEMBER_DESC = YES # If the REPEAT_BRIEF tag is set to YES, doxygen will prepend the brief # description of a member or function before the detailed description # # Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the # brief descriptions will be completely suppressed. # The default value is: YES. REPEAT_BRIEF = YES # This tag implements a quasi-intelligent brief description abbreviator that is # used to form the text in various listings. Each string in this list, if found # as the leading text of the brief description, will be stripped from the text # and the result, after processing the whole list, is used as the annotated # text. Otherwise, the brief description is used as-is. If left blank, the # following values are used ($name is automatically replaced with the name of # the entity):The $name class, The $name widget, The $name file, is, provides, # specifies, contains, represents, a, an and the. ABBREVIATE_BRIEF = "The $name class" \ "The $name widget" \ "The $name file" \ is \ provides \ specifies \ contains \ represents \ a \ an \ the # If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then # doxygen will generate a detailed section even if there is only a brief # description. # The default value is: NO. ALWAYS_DETAILED_SEC = NO # If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all # inherited members of a class in the documentation of that class as if those # members were ordinary class members. Constructors, destructors and assignment # operators of the base classes will not be shown. # The default value is: NO. INLINE_INHERITED_MEMB = NO # If the FULL_PATH_NAMES tag is set to YES, doxygen will prepend the full path # before files name in the file list and in the header files. If set to NO the # shortest path that makes the file name unique will be used # The default value is: YES. FULL_PATH_NAMES = YES # The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path. # Stripping is only done if one of the specified strings matches the left-hand # part of the path. The tag can be used to show relative paths in the file list. # If left blank the directory from which doxygen is run is used as the path to # strip. # # Note that you can specify absolute paths here, but also relative paths, which # will be relative from the directory where doxygen is started. # This tag requires that the tag FULL_PATH_NAMES is set to YES. STRIP_FROM_PATH = # The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the # path mentioned in the documentation of a class, which tells the reader which # header file to include in order to use a class. If left blank only the name of # the header file containing the class definition is used. Otherwise one should # specify the list of include paths that are normally passed to the compiler # using the -I flag. STRIP_FROM_INC_PATH = # If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but # less readable) file names. This can be useful is your file systems doesn't # support long names like on DOS, Mac, or CD-ROM. # The default value is: NO. SHORT_NAMES = NO # If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the # first line (until the first dot) of a Javadoc-style comment as the brief # description. If set to NO, the Javadoc-style will behave just like regular Qt- # style comments (thus requiring an explicit @brief command for a brief # description.) # The default value is: NO. JAVADOC_AUTOBRIEF = NO # If the JAVADOC_BANNER tag is set to YES then doxygen will interpret a line # such as # /*************** # as being the beginning of a Javadoc-style comment "banner". If set to NO, the # Javadoc-style will behave just like regular comments and it will not be # interpreted by doxygen. # The default value is: NO. JAVADOC_BANNER = NO # If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first # line (until the first dot) of a Qt-style comment as the brief description. If # set to NO, the Qt-style will behave just like regular Qt-style comments (thus # requiring an explicit \brief command for a brief description.) # The default value is: NO. QT_AUTOBRIEF = NO # The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a # multi-line C++ special comment block (i.e. a block of //! or /// comments) as # a brief description. This used to be the default behavior. The new default is # to treat a multi-line C++ comment block as a detailed description. Set this # tag to YES if you prefer the old behavior instead. # # Note that setting this tag to YES also means that rational rose comments are # not recognized any more. # The default value is: NO. MULTILINE_CPP_IS_BRIEF = NO # If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the # documentation from any documented member that it re-implements. # The default value is: YES. INHERIT_DOCS = YES # If the SEPARATE_MEMBER_PAGES tag is set to YES then doxygen will produce a new # page for each member. If set to NO, the documentation of a member will be part # of the file/class/namespace that contains it. # The default value is: NO. SEPARATE_MEMBER_PAGES = NO # The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen # uses this value to replace tabs by spaces in code fragments. # Minimum value: 1, maximum value: 16, default value: 4. TAB_SIZE = 4 # This tag can be used to specify a number of aliases that act as commands in # the documentation. An alias has the form: # name=value # For example adding # "sideeffect=@par Side Effects:\n" # will allow you to put the command \sideeffect (or @sideeffect) in the # documentation, which will result in a user-defined paragraph with heading # "Side Effects:". You can put \n's in the value part of an alias to insert # newlines (in the resulting output). You can put ^^ in the value part of an # alias to insert a newline as if a physical newline was in the original file. # When you need a literal { or } or , in the value part of an alias you have to # escape them by means of a backslash (\), this can lead to conflicts with the # commands \{ and \} for these it is advised to use the version @{ and @} or use # a double escape (\\{ and \\}) ALIASES = # This tag can be used to specify a number of word-keyword mappings (TCL only). # A mapping has the form "name=value". For example adding "class=itcl::class" # will allow you to use the command class in the itcl::class meaning. TCL_SUBST = # Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources # only. Doxygen will then generate output that is more tailored for C. For # instance, some of the names that are used will be different. The list of all # members will be omitted, etc. # The default value is: NO. OPTIMIZE_OUTPUT_FOR_C = NO # Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or # Python sources only. Doxygen will then generate output that is more tailored # for that language. For instance, namespaces will be presented as packages, # qualified scopes will look different, etc. # The default value is: NO. OPTIMIZE_OUTPUT_JAVA = NO # Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran # sources. Doxygen will then generate output that is tailored for Fortran. # The default value is: NO. OPTIMIZE_FOR_FORTRAN = NO # Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL # sources. Doxygen will then generate output that is tailored for VHDL. # The default value is: NO. OPTIMIZE_OUTPUT_VHDL = NO # Set the OPTIMIZE_OUTPUT_SLICE tag to YES if your project consists of Slice # sources only. Doxygen will then generate output that is more tailored for that # language. For instance, namespaces will be presented as modules, types will be # separated into more groups, etc. # The default value is: NO. OPTIMIZE_OUTPUT_SLICE = NO # Doxygen selects the parser to use depending on the extension of the files it # parses. With this tag you can assign which parser to use for a given # extension. Doxygen has a built-in mapping, but you can override or extend it # using this tag. The format is ext=language, where ext is a file extension, and # language is one of the parsers supported by doxygen: IDL, Java, JavaScript, # Csharp (C#), C, C++, D, PHP, md (Markdown), Objective-C, Python, Slice, # Fortran (fixed format Fortran: FortranFixed, free formatted Fortran: # FortranFree, unknown formatted Fortran: Fortran. In the later case the parser # tries to guess whether the code is fixed or free formatted code, this is the # default for Fortran type files), VHDL, tcl. For instance to make doxygen treat # .inc files as Fortran files (default is PHP), and .f files as C (default is # Fortran), use: inc=Fortran f=C. # # Note: For files without extension you can use no_extension as a placeholder. # # Note that for custom extensions you also need to set FILE_PATTERNS otherwise # the files are not read by doxygen. EXTENSION_MAPPING = # If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments # according to the Markdown format, which allows for more readable # documentation. See https://daringfireball.net/projects/markdown/ for details. # The output of markdown processing is further processed by doxygen, so you can # mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in # case of backward compatibilities issues. # The default value is: YES. MARKDOWN_SUPPORT = YES # When the TOC_INCLUDE_HEADINGS tag is set to a non-zero value, all headings up # to that level are automatically included in the table of contents, even if # they do not have an id attribute. # Note: This feature currently applies only to Markdown headings. # Minimum value: 0, maximum value: 99, default value: 5. # This tag requires that the tag MARKDOWN_SUPPORT is set to YES. TOC_INCLUDE_HEADINGS = 5 # When enabled doxygen tries to link words that correspond to documented # classes, or namespaces to their corresponding documentation. Such a link can # be prevented in individual cases by putting a % sign in front of the word or # globally by setting AUTOLINK_SUPPORT to NO. # The default value is: YES. AUTOLINK_SUPPORT = YES # If you use STL classes (i.e. std::string, std::vector, etc.) but do not want # to include (a tag file for) the STL sources as input, then you should set this # tag to YES in order to let doxygen match functions declarations and # definitions whose arguments contain STL classes (e.g. func(std::string); # versus func(std::string) {}). This also make the inheritance and collaboration # diagrams that involve STL classes more complete and accurate. # The default value is: NO. BUILTIN_STL_SUPPORT = NO # If you use Microsoft's C++/CLI language, you should set this option to YES to # enable parsing support. # The default value is: NO. CPP_CLI_SUPPORT = NO # Set the SIP_SUPPORT tag to YES if your project consists of sip (see: # https://www.riverbankcomputing.com/software/sip/intro) sources only. Doxygen # will parse them like normal C++ but will assume all classes use public instead # of private inheritance when no explicit protection keyword is present. # The default value is: NO. SIP_SUPPORT = NO # For Microsoft's IDL there are propget and propput attributes to indicate # getter and setter methods for a property. Setting this option to YES will make # doxygen to replace the get and set methods by a property in the documentation. # This will only work if the methods are indeed getting or setting a simple # type. If this is not the case, or you want to show the methods anyway, you # should set this option to NO. # The default value is: YES. IDL_PROPERTY_SUPPORT = YES # If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC # tag is set to YES then doxygen will reuse the documentation of the first # member in the group (if any) for the other members of the group. By default # all members of a group must be documented explicitly. # The default value is: NO. DISTRIBUTE_GROUP_DOC = NO # If one adds a struct or class to a group and this option is enabled, then also # any nested class or struct is added to the same group. By default this option # is disabled and one has to add nested compounds explicitly via \ingroup. # The default value is: NO. GROUP_NESTED_COMPOUNDS = NO # Set the SUBGROUPING tag to YES to allow class member groups of the same type # (for instance a group of public functions) to be put as a subgroup of that # type (e.g. under the Public Functions section). Set it to NO to prevent # subgrouping. Alternatively, this can be done per class using the # \nosubgrouping command. # The default value is: YES. SUBGROUPING = YES # When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions # are shown inside the group in which they are included (e.g. using \ingroup) # instead of on a separate page (for HTML and Man pages) or section (for LaTeX # and RTF). # # Note that this feature does not work in combination with # SEPARATE_MEMBER_PAGES. # The default value is: NO. INLINE_GROUPED_CLASSES = NO # When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions # with only public data fields or simple typedef fields will be shown inline in # the documentation of the scope in which they are defined (i.e. file, # namespace, or group documentation), provided this scope is documented. If set # to NO, structs, classes, and unions are shown on a separate page (for HTML and # Man pages) or section (for LaTeX and RTF). # The default value is: NO. INLINE_SIMPLE_STRUCTS = NO # When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or # enum is documented as struct, union, or enum with the name of the typedef. So # typedef struct TypeS {} TypeT, will appear in the documentation as a struct # with name TypeT. When disabled the typedef will appear as a member of a file, # namespace, or class. And the struct will be named TypeS. This can typically be # useful for C code in case the coding convention dictates that all compound # types are typedef'ed and only the typedef is referenced, never the tag name. # The default value is: NO. TYPEDEF_HIDES_STRUCT = NO # The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This # cache is used to resolve symbols given their name and scope. Since this can be # an expensive process and often the same symbol appears multiple times in the # code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small # doxygen will become slower. If the cache is too large, memory is wasted. The # cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range # is 0..9, the default is 0, corresponding to a cache size of 2^16=65536 # symbols. At the end of a run doxygen will report the cache usage and suggest # the optimal cache size from a speed point of view. # Minimum value: 0, maximum value: 9, default value: 0. LOOKUP_CACHE_SIZE = 0 #--------------------------------------------------------------------------- # Build related configuration options #--------------------------------------------------------------------------- # If the EXTRACT_ALL tag is set to YES, doxygen will assume all entities in # documentation are documented, even if no documentation was available. Private # class members and static file members will be hidden unless the # EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES. # Note: This will also disable the warnings about undocumented members that are # normally produced when WARNINGS is set to YES. # The default value is: NO. EXTRACT_ALL = NO # If the EXTRACT_PRIVATE tag is set to YES, all private members of a class will # be included in the documentation. # The default value is: NO. EXTRACT_PRIVATE = NO # If the EXTRACT_PRIV_VIRTUAL tag is set to YES, documented private virtual # methods of a class will be included in the documentation. # The default value is: NO. EXTRACT_PRIV_VIRTUAL = NO # If the EXTRACT_PACKAGE tag is set to YES, all members with package or internal # scope will be included in the documentation. # The default value is: NO. EXTRACT_PACKAGE = NO # If the EXTRACT_STATIC tag is set to YES, all static members of a file will be # included in the documentation. # The default value is: NO. EXTRACT_STATIC = NO # If the EXTRACT_LOCAL_CLASSES tag is set to YES, classes (and structs) defined # locally in source files will be included in the documentation. If set to NO, # only classes defined in header files are included. Does not have any effect # for Java sources. # The default value is: YES. EXTRACT_LOCAL_CLASSES = YES # This flag is only useful for Objective-C code. If set to YES, local methods, # which are defined in the implementation section but not in the interface are # included in the documentation. If set to NO, only methods in the interface are # included. # The default value is: NO. EXTRACT_LOCAL_METHODS = NO # If this flag is set to YES, the members of anonymous namespaces will be # extracted and appear in the documentation as a namespace called # 'anonymous_namespace{file}', where file will be replaced with the base name of # the file that contains the anonymous namespace. By default anonymous namespace # are hidden. # The default value is: NO. EXTRACT_ANON_NSPACES = NO # If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all # undocumented members inside documented classes or files. If set to NO these # members will be included in the various overviews, but no documentation # section is generated. This option has no effect if EXTRACT_ALL is enabled. # The default value is: NO. HIDE_UNDOC_MEMBERS = NO # If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all # undocumented classes that are normally visible in the class hierarchy. If set # to NO, these classes will be included in the various overviews. This option # has no effect if EXTRACT_ALL is enabled. # The default value is: NO. HIDE_UNDOC_CLASSES = NO # If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend # declarations. If set to NO, these declarations will be included in the # documentation. # The default value is: NO. HIDE_FRIEND_COMPOUNDS = NO # If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any # documentation blocks found inside the body of a function. If set to NO, these # blocks will be appended to the function's detailed documentation block. # The default value is: NO. HIDE_IN_BODY_DOCS = NO # The INTERNAL_DOCS tag determines if documentation that is typed after a # \internal command is included. If the tag is set to NO then the documentation # will be excluded. Set it to YES to include the internal documentation. # The default value is: NO. INTERNAL_DOCS = NO # If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file # names in lower-case letters. If set to YES, upper-case letters are also # allowed. This is useful if you have classes or files whose names only differ # in case and if your file system supports case sensitive file names. Windows # (including Cygwin) ands Mac users are advised to set this option to NO. # The default value is: system dependent. CASE_SENSE_NAMES = YES # If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with # their full class and namespace scopes in the documentation. If set to YES, the # scope will be hidden. # The default value is: NO. HIDE_SCOPE_NAMES = NO # If the HIDE_COMPOUND_REFERENCE tag is set to NO (default) then doxygen will # append additional text to a page's title, such as Class Reference. If set to # YES the compound reference will be hidden. # The default value is: NO. HIDE_COMPOUND_REFERENCE= NO # If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of # the files that are included by a file in the documentation of that file. # The default value is: YES. SHOW_INCLUDE_FILES = YES # If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each # grouped member an include statement to the documentation, telling the reader # which file to include in order to use the member. # The default value is: NO. SHOW_GROUPED_MEMB_INC = NO # If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include # files with double quotes in the documentation rather than with sharp brackets. # The default value is: NO. FORCE_LOCAL_INCLUDES = NO # If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the # documentation for inline members. # The default value is: YES. INLINE_INFO = YES # If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the # (detailed) documentation of file and class members alphabetically by member # name. If set to NO, the members will appear in declaration order. # The default value is: YES. SORT_MEMBER_DOCS = YES # If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief # descriptions of file, namespace and class members alphabetically by member # name. If set to NO, the members will appear in declaration order. Note that # this will also influence the order of the classes in the class list. # The default value is: NO. SORT_BRIEF_DOCS = NO # If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the # (brief and detailed) documentation of class members so that constructors and # destructors are listed first. If set to NO the constructors will appear in the # respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS. # Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief # member documentation. # Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting # detailed member documentation. # The default value is: NO. SORT_MEMBERS_CTORS_1ST = NO # If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy # of group names into alphabetical order. If set to NO the group names will # appear in their defined order. # The default value is: NO. SORT_GROUP_NAMES = NO # If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by # fully-qualified names, including namespaces. If set to NO, the class list will # be sorted only by class name, not including the namespace part. # Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. # Note: This option applies only to the class list, not to the alphabetical # list. # The default value is: NO. SORT_BY_SCOPE_NAME = NO # If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper # type resolution of all parameters of a function it will reject a match between # the prototype and the implementation of a member function even if there is # only one candidate or it is obvious which candidate to choose by doing a # simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still # accept a match between prototype and implementation in such cases. # The default value is: NO. STRICT_PROTO_MATCHING = NO # The GENERATE_TODOLIST tag can be used to enable (YES) or disable (NO) the todo # list. This list is created by putting \todo commands in the documentation. # The default value is: YES. GENERATE_TODOLIST = YES # The GENERATE_TESTLIST tag can be used to enable (YES) or disable (NO) the test # list. This list is created by putting \test commands in the documentation. # The default value is: YES. GENERATE_TESTLIST = YES # The GENERATE_BUGLIST tag can be used to enable (YES) or disable (NO) the bug # list. This list is created by putting \bug commands in the documentation. # The default value is: YES. GENERATE_BUGLIST = YES # The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or disable (NO) # the deprecated list. This list is created by putting \deprecated commands in # the documentation. # The default value is: YES. GENERATE_DEPRECATEDLIST= YES # The ENABLED_SECTIONS tag can be used to enable conditional documentation # sections, marked by \if ... \endif and \cond # ... \endcond blocks. ENABLED_SECTIONS = # The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the # initial value of a variable or macro / define can have for it to appear in the # documentation. If the initializer consists of more lines than specified here # it will be hidden. Use a value of 0 to hide initializers completely. The # appearance of the value of individual variables and macros / defines can be # controlled using \showinitializer or \hideinitializer command in the # documentation regardless of this setting. # Minimum value: 0, maximum value: 10000, default value: 30. MAX_INITIALIZER_LINES = 30 # Set the SHOW_USED_FILES tag to NO to disable the list of files generated at # the bottom of the documentation of classes and structs. If set to YES, the # list will mention the files that were used to generate the documentation. # The default value is: YES. SHOW_USED_FILES = YES # Set the SHOW_FILES tag to NO to disable the generation of the Files page. This # will remove the Files entry from the Quick Index and from the Folder Tree View # (if specified). # The default value is: YES. SHOW_FILES = YES # Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces # page. This will remove the Namespaces entry from the Quick Index and from the # Folder Tree View (if specified). # The default value is: YES. SHOW_NAMESPACES = YES # The FILE_VERSION_FILTER tag can be used to specify a program or script that # doxygen should invoke to get the current version for each file (typically from # the version control system). Doxygen will invoke the program by executing (via # popen()) the command command input-file, where command is the value of the # FILE_VERSION_FILTER tag, and input-file is the name of an input file provided # by doxygen. Whatever the program writes to standard output is used as the file # version. For an example see the documentation. FILE_VERSION_FILTER = # The LAYOUT_FILE tag can be used to specify a layout file which will be parsed # by doxygen. The layout file controls the global structure of the generated # output files in an output format independent way. To create the layout file # that represents doxygen's defaults, run doxygen with the -l option. You can # optionally specify a file name after the option, if omitted DoxygenLayout.xml # will be used as the name of the layout file. # # Note that if you run doxygen from a directory containing a file called # DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE # tag is left empty. LAYOUT_FILE = # The CITE_BIB_FILES tag can be used to specify one or more bib files containing # the reference definitions. This must be a list of .bib files. The .bib # extension is automatically appended if omitted. This requires the bibtex tool # to be installed. See also https://en.wikipedia.org/wiki/BibTeX for more info. # For LaTeX the style of the bibliography can be controlled using # LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the # search path. See also \cite for info how to create references. CITE_BIB_FILES = #--------------------------------------------------------------------------- # Configuration options related to warning and progress messages #--------------------------------------------------------------------------- # The QUIET tag can be used to turn on/off the messages that are generated to # standard output by doxygen. If QUIET is set to YES this implies that the # messages are off. # The default value is: NO. QUIET = NO # The WARNINGS tag can be used to turn on/off the warning messages that are # generated to standard error (stderr) by doxygen. If WARNINGS is set to YES # this implies that the warnings are on. # # Tip: Turn warnings on while writing the documentation. # The default value is: YES. WARNINGS = YES # If the WARN_IF_UNDOCUMENTED tag is set to YES then doxygen will generate # warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag # will automatically be disabled. # The default value is: YES. WARN_IF_UNDOCUMENTED = YES # If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for # potential errors in the documentation, such as not documenting some parameters # in a documented function, or documenting parameters that don't exist or using # markup commands wrongly. # The default value is: YES. WARN_IF_DOC_ERROR = YES # This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that # are documented, but have no documentation for their parameters or return # value. If set to NO, doxygen will only warn about wrong or incomplete # parameter documentation, but not about the absence of documentation. If # EXTRACT_ALL is set to YES then this flag will automatically be disabled. # The default value is: NO. WARN_NO_PARAMDOC = NO # If the WARN_AS_ERROR tag is set to YES then doxygen will immediately stop when # a warning is encountered. # The default value is: NO. WARN_AS_ERROR = NO # The WARN_FORMAT tag determines the format of the warning messages that doxygen # can produce. The string should contain the $file, $line, and $text tags, which # will be replaced by the file and line number from which the warning originated # and the warning text. Optionally the format may contain $version, which will # be replaced by the version of the file (if it could be obtained via # FILE_VERSION_FILTER) # The default value is: $file:$line: $text. WARN_FORMAT = "$file:$line: $text" # The WARN_LOGFILE tag can be used to specify a file to which warning and error # messages should be written. If left blank the output is written to standard # error (stderr). WARN_LOGFILE = #--------------------------------------------------------------------------- # Configuration options related to the input files #--------------------------------------------------------------------------- # The INPUT tag is used to specify the files and/or directories that contain # documented source files. You may enter file names like myfile.cpp or # directories like /usr/src/myproject. Separate the files or directories with # spaces. See also FILE_PATTERNS and EXTENSION_MAPPING # Note: If this tag is empty the current directory is searched. INPUT = ../kysdk-qtwidgets/src \ ../kysdk-waylandhelper/src/ukuistylehelper/ukuistylehelper.h \ ../kysdk-waylandhelper/src/windowmanager/windowmanager.h \ ../kysdk-notification/src \ ../kysdk-widgetutils/src # This tag can be used to specify the character encoding of the source files # that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses # libiconv (or the iconv built into libc) for the transcoding. See the libiconv # documentation (see: https://www.gnu.org/software/libiconv/) for the list of # possible encodings. # The default value is: UTF-8. INPUT_ENCODING = UTF-8 # If the value of the INPUT tag contains directories, you can use the # FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and # *.h) to filter out the source-files in the directories. # # Note that for custom extensions or not directly supported extensions you also # need to set EXTENSION_MAPPING for the extension otherwise the files are not # read by doxygen. # # If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cpp, # *.c++, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, # *.hh, *.hxx, *.hpp, *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc, # *.m, *.markdown, *.md, *.mm, *.dox (to be provided as doxygen C comment), # *.doc (to be provided as doxygen C comment), *.txt (to be provided as doxygen # C comment), *.py, *.pyw, *.f90, *.f95, *.f03, *.f08, *.f, *.for, *.tcl, *.vhd, # *.vhdl, *.ucf, *.qsf and *.ice. FILE_PATTERNS = *.h # The RECURSIVE tag can be used to specify whether or not subdirectories should # be searched for input files as well. # The default value is: NO. RECURSIVE = NO # The EXCLUDE tag can be used to specify files and/or directories that should be # excluded from the INPUT source files. This way you can easily exclude a # subdirectory from a directory tree whose root is specified with the INPUT tag. # # Note that relative paths are relative to the directory from which doxygen is # run. EXCLUDE = # The EXCLUDE_SYMLINKS tag can be used to select whether or not files or # directories that are symbolic links (a Unix file system feature) are excluded # from the input. # The default value is: NO. EXCLUDE_SYMLINKS = NO # If the value of the INPUT tag contains directories, you can use the # EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude # certain files from those directories. # # Note that the wildcards are matched against the file with absolute path, so to # exclude all test directories for example use the pattern */test/* EXCLUDE_PATTERNS = # The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names # (namespaces, classes, functions, etc.) that should be excluded from the # output. The symbol name can be a fully qualified name, a word, or if the # wildcard * is used, a substring. Examples: ANamespace, AClass, # AClass::ANamespace, ANamespace::*Test # # Note that the wildcards are matched against the file with absolute path, so to # exclude all test directories use the pattern */test/* EXCLUDE_SYMBOLS = XAtomHelper,MotifWmHints,TestWidget,ThemeController,UnityCorners # The EXAMPLE_PATH tag can be used to specify one or more files or directories # that contain example code fragments that are included (see the \include # command). EXAMPLE_PATH = ../kysdk-qtwidgets/test \ ../kysdk-waylandhelper/test \ ../kysdk-notification/test \ ../kysdk-ukenv/test \ ../kysdk-widgetutils/test \ ../kysdk-kabase/test \ ../kysdk-alm/test # If the value of the EXAMPLE_PATH tag contains directories, you can use the # EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and # *.h) to filter out the source-files in the directories. If left blank all # files are included. EXAMPLE_PATTERNS = * # If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be # searched for input files to be used with the \include or \dontinclude commands # irrespective of the value of the RECURSIVE tag. # The default value is: NO. EXAMPLE_RECURSIVE = NO # The IMAGE_PATH tag can be used to specify one or more files or directories # that contain images that are to be included in the documentation (see the # \image command). IMAGE_PATH = # The INPUT_FILTER tag can be used to specify a program that doxygen should # invoke to filter for each input file. Doxygen will invoke the filter program # by executing (via popen()) the command: # # # # where is the value of the INPUT_FILTER tag, and is the # name of an input file. Doxygen will then use the output that the filter # program writes to standard output. If FILTER_PATTERNS is specified, this tag # will be ignored. # # Note that the filter must not add or remove lines; it is applied before the # code is scanned, but not when the output code is generated. If lines are added # or removed, the anchors will not be placed correctly. # # Note that for custom extensions or not directly supported extensions you also # need to set EXTENSION_MAPPING for the extension otherwise the files are not # properly processed by doxygen. INPUT_FILTER = # The FILTER_PATTERNS tag can be used to specify filters on a per file pattern # basis. Doxygen will compare the file name with each pattern and apply the # filter if there is a match. The filters are a list of the form: pattern=filter # (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how # filters are used. If the FILTER_PATTERNS tag is empty or if none of the # patterns match the file name, INPUT_FILTER is applied. # # Note that for custom extensions or not directly supported extensions you also # need to set EXTENSION_MAPPING for the extension otherwise the files are not # properly processed by doxygen. FILTER_PATTERNS = # If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using # INPUT_FILTER) will also be used to filter the input files that are used for # producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES). # The default value is: NO. FILTER_SOURCE_FILES = NO # The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file # pattern. A pattern will override the setting for FILTER_PATTERN (if any) and # it is also possible to disable source filtering for a specific pattern using # *.ext= (so without naming a filter). # This tag requires that the tag FILTER_SOURCE_FILES is set to YES. FILTER_SOURCE_PATTERNS = # If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that # is part of the input, its contents will be placed on the main page # (index.html). This can be useful if you have a project on for instance GitHub # and want to reuse the introduction page also for the doxygen output. USE_MDFILE_AS_MAINPAGE = #--------------------------------------------------------------------------- # Configuration options related to source browsing #--------------------------------------------------------------------------- # If the SOURCE_BROWSER tag is set to YES then a list of source files will be # generated. Documented entities will be cross-referenced with these sources. # # Note: To get rid of all source code in the generated output, make sure that # also VERBATIM_HEADERS is set to NO. # The default value is: NO. SOURCE_BROWSER = NO # Setting the INLINE_SOURCES tag to YES will include the body of functions, # classes and enums directly into the documentation. # The default value is: NO. INLINE_SOURCES = NO # Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any # special comment blocks from generated source code fragments. Normal C, C++ and # Fortran comments will always remain visible. # The default value is: YES. STRIP_CODE_COMMENTS = YES # If the REFERENCED_BY_RELATION tag is set to YES then for each documented # entity all documented functions referencing it will be listed. # The default value is: NO. REFERENCED_BY_RELATION = NO # If the REFERENCES_RELATION tag is set to YES then for each documented function # all documented entities called/used by that function will be listed. # The default value is: NO. REFERENCES_RELATION = NO # If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set # to YES then the hyperlinks from functions in REFERENCES_RELATION and # REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will # link to the documentation. # The default value is: YES. REFERENCES_LINK_SOURCE = YES # If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the # source code will show a tooltip with additional information such as prototype, # brief description and links to the definition and documentation. Since this # will make the HTML file larger and loading of large files a bit slower, you # can opt to disable this feature. # The default value is: YES. # This tag requires that the tag SOURCE_BROWSER is set to YES. SOURCE_TOOLTIPS = YES # If the USE_HTAGS tag is set to YES then the references to source code will # point to the HTML generated by the htags(1) tool instead of doxygen built-in # source browser. The htags tool is part of GNU's global source tagging system # (see https://www.gnu.org/software/global/global.html). You will need version # 4.8.6 or higher. # # To use it do the following: # - Install the latest version of global # - Enable SOURCE_BROWSER and USE_HTAGS in the configuration file # - Make sure the INPUT points to the root of the source tree # - Run doxygen as normal # # Doxygen will invoke htags (and that will in turn invoke gtags), so these # tools must be available from the command line (i.e. in the search path). # # The result: instead of the source browser generated by doxygen, the links to # source code will now point to the output of htags. # The default value is: NO. # This tag requires that the tag SOURCE_BROWSER is set to YES. USE_HTAGS = NO # If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a # verbatim copy of the header file for each class for which an include is # specified. Set to NO to disable this. # See also: Section \class. # The default value is: YES. VERBATIM_HEADERS = YES # If the CLANG_ASSISTED_PARSING tag is set to YES then doxygen will use the # clang parser (see: http://clang.llvm.org/) for more accurate parsing at the # cost of reduced performance. This can be particularly helpful with template # rich C++ code for which doxygen's built-in parser lacks the necessary type # information. # Note: The availability of this option depends on whether or not doxygen was # generated with the -Duse_libclang=ON option for CMake. # The default value is: NO. CLANG_ASSISTED_PARSING = NO # If clang assisted parsing is enabled you can provide the compiler with command # line options that you would normally use when invoking the compiler. Note that # the include paths will already be set by doxygen for the files and directories # specified with INPUT and INCLUDE_PATH. # This tag requires that the tag CLANG_ASSISTED_PARSING is set to YES. CLANG_OPTIONS = # If clang assisted parsing is enabled you can provide the clang parser with the # path to the compilation database (see: # http://clang.llvm.org/docs/HowToSetupToolingForLLVM.html) used when the files # were built. This is equivalent to specifying the "-p" option to a clang tool, # such as clang-check. These options will then be passed to the parser. # Note: The availability of this option depends on whether or not doxygen was # generated with the -Duse_libclang=ON option for CMake. CLANG_DATABASE_PATH = #--------------------------------------------------------------------------- # Configuration options related to the alphabetical class index #--------------------------------------------------------------------------- # If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all # compounds will be generated. Enable this if the project contains a lot of # classes, structs, unions or interfaces. # The default value is: YES. ALPHABETICAL_INDEX = YES # The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in # which the alphabetical index list will be split. # Minimum value: 1, maximum value: 20, default value: 5. # This tag requires that the tag ALPHABETICAL_INDEX is set to YES. COLS_IN_ALPHA_INDEX = 5 # In case all classes in a project start with a common prefix, all classes will # be put under the same header in the alphabetical index. The IGNORE_PREFIX tag # can be used to specify a prefix (or a list of prefixes) that should be ignored # while generating the index headers. # This tag requires that the tag ALPHABETICAL_INDEX is set to YES. IGNORE_PREFIX = #--------------------------------------------------------------------------- # Configuration options related to the HTML output #--------------------------------------------------------------------------- # If the GENERATE_HTML tag is set to YES, doxygen will generate HTML output # The default value is: YES. GENERATE_HTML = YES # The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a # relative path is entered the value of OUTPUT_DIRECTORY will be put in front of # it. # The default directory is: html. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_OUTPUT = html # The HTML_FILE_EXTENSION tag can be used to specify the file extension for each # generated HTML page (for example: .htm, .php, .asp). # The default value is: .html. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_FILE_EXTENSION = .html # The HTML_HEADER tag can be used to specify a user-defined HTML header file for # each generated HTML page. If the tag is left blank doxygen will generate a # standard header. # # To get valid HTML the header file that includes any scripts and style sheets # that doxygen needs, which is dependent on the configuration options used (e.g. # the setting GENERATE_TREEVIEW). It is highly recommended to start with a # default header using # doxygen -w html new_header.html new_footer.html new_stylesheet.css # YourConfigFile # and then modify the file new_header.html. See also section "Doxygen usage" # for information on how to generate the default header that doxygen normally # uses. # Note: The header is subject to change so you typically have to regenerate the # default header when upgrading to a newer version of doxygen. For a description # of the possible markers and block names see the documentation. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_HEADER = # The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each # generated HTML page. If the tag is left blank doxygen will generate a standard # footer. See HTML_HEADER for more information on how to generate a default # footer and what special commands can be used inside the footer. See also # section "Doxygen usage" for information on how to generate the default footer # that doxygen normally uses. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_FOOTER = # The HTML_STYLESHEET tag can be used to specify a user-defined cascading style # sheet that is used by each HTML page. It can be used to fine-tune the look of # the HTML output. If left blank doxygen will generate a default style sheet. # See also section "Doxygen usage" for information on how to generate the style # sheet that doxygen normally uses. # Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as # it is more robust and this tag (HTML_STYLESHEET) will in the future become # obsolete. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_STYLESHEET = # The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined # cascading style sheets that are included after the standard style sheets # created by doxygen. Using this option one can overrule certain style aspects. # This is preferred over using HTML_STYLESHEET since it does not replace the # standard style sheet and is therefore more robust against future updates. # Doxygen will copy the style sheet files to the output directory. # Note: The order of the extra style sheet files is of importance (e.g. the last # style sheet in the list overrules the setting of the previous ones in the # list). For an example see the documentation. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_EXTRA_STYLESHEET = # The HTML_EXTRA_FILES tag can be used to specify one or more extra images or # other source files which should be copied to the HTML output directory. Note # that these files will be copied to the base HTML output directory. Use the # $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these # files. In the HTML_STYLESHEET file, use the file name only. Also note that the # files will be copied as-is; there are no commands or markers available. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_EXTRA_FILES = # The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen # will adjust the colors in the style sheet and background images according to # this color. Hue is specified as an angle on a colorwheel, see # https://en.wikipedia.org/wiki/Hue for more information. For instance the value # 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300 # purple, and 360 is red again. # Minimum value: 0, maximum value: 359, default value: 220. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_COLORSTYLE_HUE = 220 # The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors # in the HTML output. For a value of 0 the output will use grayscales only. A # value of 255 will produce the most vivid colors. # Minimum value: 0, maximum value: 255, default value: 100. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_COLORSTYLE_SAT = 100 # The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the # luminance component of the colors in the HTML output. Values below 100 # gradually make the output lighter, whereas values above 100 make the output # darker. The value divided by 100 is the actual gamma applied, so 80 represents # a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not # change the gamma. # Minimum value: 40, maximum value: 240, default value: 80. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_COLORSTYLE_GAMMA = 80 # If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML # page will contain the date and time when the page was generated. Setting this # to YES can help to show when doxygen was last run and thus if the # documentation is up to date. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_TIMESTAMP = NO # If the HTML_DYNAMIC_MENUS tag is set to YES then the generated HTML # documentation will contain a main index with vertical navigation menus that # are dynamically created via JavaScript. If disabled, the navigation index will # consists of multiple levels of tabs that are statically embedded in every HTML # page. Disable this option to support browsers that do not have JavaScript, # like the Qt help browser. # The default value is: YES. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_DYNAMIC_MENUS = YES # If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML # documentation will contain sections that can be hidden and shown after the # page has loaded. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_DYNAMIC_SECTIONS = NO # With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries # shown in the various tree structured indices initially; the user can expand # and collapse entries dynamically later on. Doxygen will expand the tree to # such a level that at most the specified number of entries are visible (unless # a fully collapsed tree already exceeds this amount). So setting the number of # entries 1 will produce a full collapsed tree by default. 0 is a special value # representing an infinite number of entries and will result in a full expanded # tree by default. # Minimum value: 0, maximum value: 9999, default value: 100. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_INDEX_NUM_ENTRIES = 100 # If the GENERATE_DOCSET tag is set to YES, additional index files will be # generated that can be used as input for Apple's Xcode 3 integrated development # environment (see: https://developer.apple.com/xcode/), introduced with OSX # 10.5 (Leopard). To create a documentation set, doxygen will generate a # Makefile in the HTML output directory. Running make will produce the docset in # that directory and running make install will install the docset in # ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at # startup. See https://developer.apple.com/library/archive/featuredarticles/Doxy # genXcode/_index.html for more information. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. GENERATE_DOCSET = NO # This tag determines the name of the docset feed. A documentation feed provides # an umbrella under which multiple documentation sets from a single provider # (such as a company or product suite) can be grouped. # The default value is: Doxygen generated docs. # This tag requires that the tag GENERATE_DOCSET is set to YES. DOCSET_FEEDNAME = "Doxygen generated docs" # This tag specifies a string that should uniquely identify the documentation # set bundle. This should be a reverse domain-name style string, e.g. # com.mycompany.MyDocSet. Doxygen will append .docset to the name. # The default value is: org.doxygen.Project. # This tag requires that the tag GENERATE_DOCSET is set to YES. DOCSET_BUNDLE_ID = org.doxygen.Project # The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify # the documentation publisher. This should be a reverse domain-name style # string, e.g. com.mycompany.MyDocSet.documentation. # The default value is: org.doxygen.Publisher. # This tag requires that the tag GENERATE_DOCSET is set to YES. DOCSET_PUBLISHER_ID = org.doxygen.Publisher # The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher. # The default value is: Publisher. # This tag requires that the tag GENERATE_DOCSET is set to YES. DOCSET_PUBLISHER_NAME = Publisher # If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three # additional HTML index files: index.hhp, index.hhc, and index.hhk. The # index.hhp is a project file that can be read by Microsoft's HTML Help Workshop # (see: https://www.microsoft.com/en-us/download/details.aspx?id=21138) on # Windows. # # The HTML Help Workshop contains a compiler that can convert all HTML output # generated by doxygen into a single compiled HTML file (.chm). Compiled HTML # files are now used as the Windows 98 help format, and will replace the old # Windows help format (.hlp) on all Windows platforms in the future. Compressed # HTML files also contain an index, a table of contents, and you can search for # words in the documentation. The HTML workshop also contains a viewer for # compressed HTML files. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. GENERATE_HTMLHELP = NO # The CHM_FILE tag can be used to specify the file name of the resulting .chm # file. You can add a path in front of the file if the result should not be # written to the html output directory. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. CHM_FILE = # The HHC_LOCATION tag can be used to specify the location (absolute path # including file name) of the HTML help compiler (hhc.exe). If non-empty, # doxygen will try to run the HTML help compiler on the generated index.hhp. # The file has to be specified with full path. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. HHC_LOCATION = # The GENERATE_CHI flag controls if a separate .chi index file is generated # (YES) or that it should be included in the master .chm file (NO). # The default value is: NO. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. GENERATE_CHI = NO # The CHM_INDEX_ENCODING is used to encode HtmlHelp index (hhk), content (hhc) # and project file content. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. CHM_INDEX_ENCODING = # The BINARY_TOC flag controls whether a binary table of contents is generated # (YES) or a normal table of contents (NO) in the .chm file. Furthermore it # enables the Previous and Next buttons. # The default value is: NO. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. BINARY_TOC = NO # The TOC_EXPAND flag can be set to YES to add extra items for group members to # the table of contents of the HTML help documentation and to the tree view. # The default value is: NO. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. TOC_EXPAND = NO # If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and # QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that # can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help # (.qch) of the generated HTML documentation. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. GENERATE_QHP = NO # If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify # the file name of the resulting .qch file. The path specified is relative to # the HTML output folder. # This tag requires that the tag GENERATE_QHP is set to YES. QCH_FILE = # The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help # Project output. For more information please see Qt Help Project / Namespace # (see: https://doc.qt.io/archives/qt-4.8/qthelpproject.html#namespace). # The default value is: org.doxygen.Project. # This tag requires that the tag GENERATE_QHP is set to YES. QHP_NAMESPACE = org.doxygen.Project # The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt # Help Project output. For more information please see Qt Help Project / Virtual # Folders (see: https://doc.qt.io/archives/qt-4.8/qthelpproject.html#virtual- # folders). # The default value is: doc. # This tag requires that the tag GENERATE_QHP is set to YES. QHP_VIRTUAL_FOLDER = doc # If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom # filter to add. For more information please see Qt Help Project / Custom # Filters (see: https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom- # filters). # This tag requires that the tag GENERATE_QHP is set to YES. QHP_CUST_FILTER_NAME = # The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the # custom filter to add. For more information please see Qt Help Project / Custom # Filters (see: https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom- # filters). # This tag requires that the tag GENERATE_QHP is set to YES. QHP_CUST_FILTER_ATTRS = # The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this # project's filter section matches. Qt Help Project / Filter Attributes (see: # https://doc.qt.io/archives/qt-4.8/qthelpproject.html#filter-attributes). # This tag requires that the tag GENERATE_QHP is set to YES. QHP_SECT_FILTER_ATTRS = # The QHG_LOCATION tag can be used to specify the location of Qt's # qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the # generated .qhp file. # This tag requires that the tag GENERATE_QHP is set to YES. QHG_LOCATION = # If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be # generated, together with the HTML files, they form an Eclipse help plugin. To # install this plugin and make it available under the help contents menu in # Eclipse, the contents of the directory containing the HTML and XML files needs # to be copied into the plugins directory of eclipse. The name of the directory # within the plugins directory should be the same as the ECLIPSE_DOC_ID value. # After copying Eclipse needs to be restarted before the help appears. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. GENERATE_ECLIPSEHELP = NO # A unique identifier for the Eclipse help plugin. When installing the plugin # the directory name containing the HTML and XML files should also have this # name. Each documentation set should have its own identifier. # The default value is: org.doxygen.Project. # This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES. ECLIPSE_DOC_ID = org.doxygen.Project # If you want full control over the layout of the generated HTML pages it might # be necessary to disable the index and replace it with your own. The # DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top # of each HTML page. A value of NO enables the index and the value YES disables # it. Since the tabs in the index contain the same information as the navigation # tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. DISABLE_INDEX = NO # The GENERATE_TREEVIEW tag is used to specify whether a tree-like index # structure should be generated to display hierarchical information. If the tag # value is set to YES, a side panel will be generated containing a tree-like # index structure (just like the one that is generated for HTML Help). For this # to work a browser that supports JavaScript, DHTML, CSS and frames is required # (i.e. any modern browser). Windows users are probably better off using the # HTML help feature. Via custom style sheets (see HTML_EXTRA_STYLESHEET) one can # further fine-tune the look of the index. As an example, the default style # sheet generated by doxygen has an example that shows how to put an image at # the root of the tree instead of the PROJECT_NAME. Since the tree basically has # the same information as the tab index, you could consider setting # DISABLE_INDEX to YES when enabling this option. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. GENERATE_TREEVIEW = NO # The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that # doxygen will group on one line in the generated HTML documentation. # # Note that a value of 0 will completely suppress the enum values from appearing # in the overview section. # Minimum value: 0, maximum value: 20, default value: 4. # This tag requires that the tag GENERATE_HTML is set to YES. ENUM_VALUES_PER_LINE = 4 # If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used # to set the initial width (in pixels) of the frame in which the tree is shown. # Minimum value: 0, maximum value: 1500, default value: 250. # This tag requires that the tag GENERATE_HTML is set to YES. TREEVIEW_WIDTH = 250 # If the EXT_LINKS_IN_WINDOW option is set to YES, doxygen will open links to # external symbols imported via tag files in a separate window. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. EXT_LINKS_IN_WINDOW = NO # Use this tag to change the font size of LaTeX formulas included as images in # the HTML documentation. When you change the font size after a successful # doxygen run you need to manually remove any form_*.png images from the HTML # output directory to force them to be regenerated. # Minimum value: 8, maximum value: 50, default value: 10. # This tag requires that the tag GENERATE_HTML is set to YES. FORMULA_FONTSIZE = 10 # Use the FORMULA_TRANSPARENT tag to determine whether or not the images # generated for formulas are transparent PNGs. Transparent PNGs are not # supported properly for IE 6.0, but are supported on all modern browsers. # # Note that when changing this option you need to delete any form_*.png files in # the HTML output directory before the changes have effect. # The default value is: YES. # This tag requires that the tag GENERATE_HTML is set to YES. FORMULA_TRANSPARENT = YES # The FORMULA_MACROFILE can contain LaTeX \newcommand and \renewcommand commands # to create new LaTeX commands to be used in formulas as building blocks. See # the section "Including formulas" for details. FORMULA_MACROFILE = # Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see # https://www.mathjax.org) which uses client side JavaScript for the rendering # instead of using pre-rendered bitmaps. Use this if you do not have LaTeX # installed or if you want to formulas look prettier in the HTML output. When # enabled you may also need to install MathJax separately and configure the path # to it using the MATHJAX_RELPATH option. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. USE_MATHJAX = NO # When MathJax is enabled you can set the default output format to be used for # the MathJax output. See the MathJax site (see: # http://docs.mathjax.org/en/latest/output.html) for more details. # Possible values are: HTML-CSS (which is slower, but has the best # compatibility), NativeMML (i.e. MathML) and SVG. # The default value is: HTML-CSS. # This tag requires that the tag USE_MATHJAX is set to YES. MATHJAX_FORMAT = HTML-CSS # When MathJax is enabled you need to specify the location relative to the HTML # output directory using the MATHJAX_RELPATH option. The destination directory # should contain the MathJax.js script. For instance, if the mathjax directory # is located at the same level as the HTML output directory, then # MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax # Content Delivery Network so you can quickly see the result without installing # MathJax. However, it is strongly recommended to install a local copy of # MathJax from https://www.mathjax.org before deployment. # The default value is: https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/. # This tag requires that the tag USE_MATHJAX is set to YES. MATHJAX_RELPATH = https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/ # The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax # extension names that should be enabled during MathJax rendering. For example # MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols # This tag requires that the tag USE_MATHJAX is set to YES. MATHJAX_EXTENSIONS = # The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces # of code that will be used on startup of the MathJax code. See the MathJax site # (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an # example see the documentation. # This tag requires that the tag USE_MATHJAX is set to YES. MATHJAX_CODEFILE = # When the SEARCHENGINE tag is enabled doxygen will generate a search box for # the HTML output. The underlying search engine uses javascript and DHTML and # should work on any modern browser. Note that when using HTML help # (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET) # there is already a search function so this one should typically be disabled. # For large projects the javascript based search engine can be slow, then # enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to # search using the keyboard; to jump to the search box use + S # (what the is depends on the OS and browser, but it is typically # , /