diff --git a/.github/.well-known/funding-manifest-urls b/.github/.well-known/funding-manifest-urls new file mode 100644 index 000000000..9514af76b --- /dev/null +++ b/.github/.well-known/funding-manifest-urls @@ -0,0 +1 @@ +https://imageglass.org/funding.json diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml index ebeb349c2..c014174bb 100644 --- a/.github/FUNDING.yml +++ b/.github/FUNDING.yml @@ -5,4 +5,4 @@ patreon: d2phap open_collective: # Replace with a single Open Collective username ko_fi: # Replace with a single Ko-fi username tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel -custom: https://www.paypal.me/d2phap +custom: ["https://donate.stripe.com/6oE15Kab3740du828a", "https://www.paypal.me/d2phap"] diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md deleted file mode 100644 index 090b60fe6..000000000 --- a/.github/ISSUE_TEMPLATE.md +++ /dev/null @@ -1,27 +0,0 @@ - - -### System info: -- ImageGlass version: ____tell_me_here____ -- OS version: ____tell_me_here____ - - -### Expected behavior: -____tell_me_here____ - - -### Actual behavior: -____tell_me_here____ - - -### Steps to reproduce: -1. ____tell_me_here____ -2. ____tell_me_here____ -3. ____tell_me_here____ - - -### Other info: -____tell_me_here____ - - - diff --git a/.github/ISSUE_TEMPLATE/01-bug.yml b/.github/ISSUE_TEMPLATE/01-bug.yml new file mode 100644 index 000000000..251231810 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/01-bug.yml @@ -0,0 +1,81 @@ +name: 🐞 Report a Bug +description: Create a report to help us improve. Clearly attach screenshots or video to help reproduce the issue quickly. Include a sample file if the problem involves image formats. +labels: ['🐞 bug'] +body: +- type: markdown + attributes: + value: | + Before you fill in this template, + **please search** open/closed issues and discussions before submitting. + It might be already known and fixed before. + +- type: input + id: os-version + attributes: + label: Windows OS version + description: e.g. Windows 11 24H2 + validations: + required: true + +- type: input + id: ig-version + attributes: + label: ImageGlass version + description: | + - ✅ Do provide full version number found in ImageGlass About dialog (press F1). E.g. v9.3.1.518 + - ❌ Do not use "latest" + validations: + required: true + +- type: dropdown + id: ig-release + attributes: + label: ImageGlass release + options: + - Classic + - Store + description: Select "Store" if you installed ImageGlass from [MS Store](https://apps.microsoft.com/detail/9N33VZK3C7TH?launch=true&cid=ig_github_bug_report&mode=full). + validations: + required: true + +- type: textarea + id: reproduction-steps + attributes: + label: 1️⃣ Steps to reproduce + placeholder: | + 1. Go to... + 2. Click on... + 3. Scroll down to... + 4. See error when... + validations: + required: true + +- type: textarea + id: actual-behavior + attributes: + label: 2️⃣ Actual behavior + description: Use list bullets to make it clear and concise. + validations: + required: true + +- type: textarea + id: expected-behavior + attributes: + label: 3️⃣ Expected behavior + description: A clear and concise description of what you expected to happen. + validations: + required: true + +- type: textarea + id: media + attributes: + label: 4️⃣ Screenshots / Video / Sample image file + description: | + - ✅ Do attach SCREENSHOTS, VIDEO to help explain your problem quickly. + - ✅ Do attach a SAMPLE FILE if the problem involves image formats. + +- type: textarea + id: additional-context + attributes: + label: 5️⃣ Additional context + description: Add any other context about the problem here. diff --git a/.github/ISSUE_TEMPLATE/02-feature-request.yml b/.github/ISSUE_TEMPLATE/02-feature-request.yml new file mode 100644 index 000000000..938fd2084 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/02-feature-request.yml @@ -0,0 +1,63 @@ +name: 🎯 Request a Feature +description: Suggest an idea you wish to have in ImageGlass. +labels: ['🎯 feature'] +body: +- type: markdown + attributes: + value: | + Before you fill in this template, + **please search** open/closed issues and discussions before submitting. + It might be already known before. + +- type: input + id: os-version + attributes: + label: Windows OS version + description: e.g. Windows 11 24H2 + validations: + required: true + +- type: input + id: ig-version + attributes: + label: ImageGlass version + description: | + - ✅ Do provide full version number found in ImageGlass About dialog (press F1). E.g. v9.3.1.518 + - ❌ Do not use "latest" + validations: + required: true + +- type: dropdown + id: ig-release + attributes: + label: ImageGlass release + options: + - Classic + - Store + description: Select "Store" if you installed ImageGlass from [MS Store](https://apps.microsoft.com/detail/9N33VZK3C7TH?launch=true&cid=ig_github_bug_report&mode=full). + validations: + required: true + +- type: textarea + id: feature-description + attributes: + label: 1️⃣ Describe the feature + description: | + - ✅ Do make it SHORT and STRAIGHT FORWARD. + - ✅ Do use list bullets to describe, I'm LAZY to read an essay. + +- type: textarea + id: feature-usage + attributes: + label: 2️⃣ How to use feature + description: List the steps to activate the feature and how other people use it. + placeholder: | + 1. + 2. + 3. + +- type: textarea + id: additional-context + attributes: + label: 3️⃣ Additional context + description: Add any other context or SCREENSHOTS about the new feature. diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md deleted file mode 100644 index ed9ed61cf..000000000 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ /dev/null @@ -1,36 +0,0 @@ ---- -name: Bug report -about: Create a report to help us improve -title: '' -labels: "\U0001F41E bug" -assignees: d2phap - ---- - -### System information: - - Windows OS version: - - ImageGlass version: - - -### To Reproduce -Steps to reproduce the behavior: -1. -2. -3. -4. - - -### Actual behavior: - - - -### Expected behavior: - - - -### Screenshots: - - - -### Additional context: - diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 000000000..c0af63e3e --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,13 @@ +blank_issues_enabled: false +contact_links: + - name: ⭐ Request for Paid Support + url: https://imageglass.org/support#premium-support + about: Unlock premium assistance directly from the creator of ImageGlass. + + - name: 🤔 Ask a Question + url: https://github.com/d2phap/ImageGlass/discussions/new/choose + about: Ask a question about ImageGlass features. + + - name: 🦜 Ask Discord Community + url: https://discord.gg/tWjbynH2X8 + about: Join in official Discord server of ImageGlass. diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md deleted file mode 100644 index 751c4b4d6..000000000 --- a/.github/ISSUE_TEMPLATE/feature_request.md +++ /dev/null @@ -1,20 +0,0 @@ ---- -name: Feature request -about: Suggest an idea for this project -title: '' -labels: "✨ feature request" -assignees: '' - ---- - -### Is your feature request related to a problem? Please describe. - - -### Describe the solution you'd like - - -### Describe alternatives you've considered - - -### Additional context - diff --git a/.github/ISSUE_TEMPLATE/question.md b/.github/ISSUE_TEMPLATE/question.md deleted file mode 100644 index a6fdfb2ce..000000000 --- a/.github/ISSUE_TEMPLATE/question.md +++ /dev/null @@ -1,14 +0,0 @@ ---- -name: Question -about: General questions about ImageGlass -title: '' -labels: "⁉ question" -assignees: '' - ---- - -### System information: - - Windows OS version: - - ImageGlass version: - -### Questions diff --git a/.gitignore b/.gitignore index 3446e94c5..a57aed105 100644 --- a/.gitignore +++ b/.gitignore @@ -58,6 +58,7 @@ ipch/ *.psess *.vsp *.vspx +.vs/ # Guidance Automation Toolkit *.gpState @@ -160,11 +161,13 @@ $RECYCLE.BIN/ *.lock *.sqlite .DS_Store -.vs/VSWorkspaceState.json -/Source/.vs/ImageGlass/v15/Server/sqlite3 Setup/*.zip -Setup/AdvancedInstaller/x86/ImageGlass-x86-cache -Setup/AdvancedInstaller/x64/ImageGlass-x64-cache -Source/.vs/ImageGlass.sqlite +**/ImageGlass_9_x64-cache Source/ImageGlass/obj/Debug/DesignTimeResolveAssemblyReferences.cache +**/Properties/launchSettings.json +BundleArtifacts +BundleArtifactsUpload +node_modules/ +launchSettings.json +Setup/Assets/WebView2_Runtime/ diff --git a/Assets/Ext Icons/KyoGrou/ICO/AVIF.ico b/Assets/Ext Icons/KyoGrou/ICO/AVIF.ico new file mode 100644 index 000000000..39f61ac95 Binary files /dev/null and b/Assets/Ext Icons/KyoGrou/ICO/AVIF.ico differ diff --git a/Assets/Ext Icons/KyoGrou/ICO/B64.ico b/Assets/Ext Icons/KyoGrou/ICO/B64.ico new file mode 100644 index 000000000..ce680c68a Binary files /dev/null and b/Assets/Ext Icons/KyoGrou/ICO/B64.ico differ diff --git a/Assets/Ext Icons/KyoGrou/ICO/HEIC.ico b/Assets/Ext Icons/KyoGrou/ICO/HEIC.ico new file mode 100644 index 000000000..c2981b0ad Binary files /dev/null and b/Assets/Ext Icons/KyoGrou/ICO/HEIC.ico differ diff --git a/Assets/Ext Icons/KyoGrou/ICO/HEIF.ico b/Assets/Ext Icons/KyoGrou/ICO/HEIF.ico new file mode 100644 index 000000000..51aa6ba21 Binary files /dev/null and b/Assets/Ext Icons/KyoGrou/ICO/HEIF.ico differ diff --git a/Assets/Ext Icons/KyoGrou/ICO/JXL.ico b/Assets/Ext Icons/KyoGrou/ICO/JXL.ico new file mode 100644 index 000000000..cc7c070ba Binary files /dev/null and b/Assets/Ext Icons/KyoGrou/ICO/JXL.ico differ diff --git a/Assets/Ext Icons/KyoGrou/ICO/QOI.ico b/Assets/Ext Icons/KyoGrou/ICO/QOI.ico new file mode 100644 index 000000000..b750c9b7c Binary files /dev/null and b/Assets/Ext Icons/KyoGrou/ICO/QOI.ico differ diff --git a/Assets/Ext Icons/KyoGrou/ICO/Raw/CR3.ico b/Assets/Ext Icons/KyoGrou/ICO/Raw/CR3.ico new file mode 100644 index 000000000..236c419c1 Binary files /dev/null and b/Assets/Ext Icons/KyoGrou/ICO/Raw/CR3.ico differ diff --git a/Assets/Ext Icons/KyoGrou/PSD/B64_S.psd b/Assets/Ext Icons/KyoGrou/PSD/B64_S.psd new file mode 100644 index 000000000..01278a48a Binary files /dev/null and b/Assets/Ext Icons/KyoGrou/PSD/B64_S.psd differ diff --git a/Assets/Ext Icons/KyoGrou/PSD/HEIC_S.psd b/Assets/Ext Icons/KyoGrou/PSD/HEIC_S.psd new file mode 100644 index 000000000..37b8f9cff Binary files /dev/null and b/Assets/Ext Icons/KyoGrou/PSD/HEIC_S.psd differ diff --git a/Assets/Ext Icons/KyoGrou/PSD/HEIF_S.psd b/Assets/Ext Icons/KyoGrou/PSD/HEIF_S.psd new file mode 100644 index 000000000..4c6c65f16 Binary files /dev/null and b/Assets/Ext Icons/KyoGrou/PSD/HEIF_S.psd differ diff --git a/Assets/Ext Icons/KyoGrou/PSD/JXL_S.psd b/Assets/Ext Icons/KyoGrou/PSD/JXL_S.psd new file mode 100644 index 000000000..43cf4fcdb Binary files /dev/null and b/Assets/Ext Icons/KyoGrou/PSD/JXL_S.psd differ diff --git a/Assets/Ext Icons/KyoGrou/PSD/QOI_S.psd b/Assets/Ext Icons/KyoGrou/PSD/QOI_S.psd new file mode 100644 index 000000000..37378aa22 Binary files /dev/null and b/Assets/Ext Icons/KyoGrou/PSD/QOI_S.psd differ diff --git a/Assets/Ext Icons/KyoGrou/PSD/_Raw/CR3_S.psd b/Assets/Ext Icons/KyoGrou/PSD/_Raw/CR3_S.psd new file mode 100644 index 000000000..e9d236416 Binary files /dev/null and b/Assets/Ext Icons/KyoGrou/PSD/_Raw/CR3_S.psd differ diff --git a/Assets/Logo/2019/PNG/MSIX/100.png b/Assets/Logo/2019/PNG/MSIX/100.png new file mode 100644 index 000000000..39e813fe8 Binary files /dev/null and b/Assets/Logo/2019/PNG/MSIX/100.png differ diff --git a/Assets/Logo/2019/PNG/MSIX/200.png b/Assets/Logo/2019/PNG/MSIX/200.png new file mode 100644 index 000000000..b59b3e90f Binary files /dev/null and b/Assets/Logo/2019/PNG/MSIX/200.png differ diff --git a/Assets/Logo/2019/PNG/MSIX/300-sub.png b/Assets/Logo/2019/PNG/MSIX/300-sub.png new file mode 100644 index 000000000..38093e54b Binary files /dev/null and b/Assets/Logo/2019/PNG/MSIX/300-sub.png differ diff --git a/Assets/Logo/2019/PNG/MSIX/300.png b/Assets/Logo/2019/PNG/MSIX/300.png new file mode 100644 index 000000000..b7da68d09 Binary files /dev/null and b/Assets/Logo/2019/PNG/MSIX/300.png differ diff --git a/Assets/Logo/2019/PNG/MSIX/50.png b/Assets/Logo/2019/PNG/MSIX/50.png new file mode 100644 index 000000000..3033c3eaf Binary files /dev/null and b/Assets/Logo/2019/PNG/MSIX/50.png differ diff --git a/Assets/Logo/2019/PNG/MSIX/63.png b/Assets/Logo/2019/PNG/MSIX/63.png new file mode 100644 index 000000000..295d93524 Binary files /dev/null and b/Assets/Logo/2019/PNG/MSIX/63.png differ diff --git a/Assets/Logo/2019/PNG/MSIX/75.png b/Assets/Logo/2019/PNG/MSIX/75.png new file mode 100644 index 000000000..b94755f6b Binary files /dev/null and b/Assets/Logo/2019/PNG/MSIX/75.png differ diff --git a/Assets/Logo/2019/SVG/1024.svg b/Assets/Logo/2019/SVG/1024.svg index c37c97885..c86d207ab 100644 --- a/Assets/Logo/2019/SVG/1024.svg +++ b/Assets/Logo/2019/SVG/1024.svg @@ -1,4 +1,4 @@ - + diff --git a/Assets/Logo/2019/SVG/128.svg b/Assets/Logo/2019/SVG/128.svg index 7685a684c..f25ef7da2 100644 --- a/Assets/Logo/2019/SVG/128.svg +++ b/Assets/Logo/2019/SVG/128.svg @@ -1,4 +1,4 @@ - + diff --git a/Assets/Logo/2019/SVG/256.svg b/Assets/Logo/2019/SVG/256.svg index 348b7bc48..695aae5a2 100644 --- a/Assets/Logo/2019/SVG/256.svg +++ b/Assets/Logo/2019/SVG/256.svg @@ -1,4 +1,4 @@ - + diff --git a/Assets/Logo/2019/SVG/512.svg b/Assets/Logo/2019/SVG/512.svg index 6b2dfffc8..3248d7fdb 100644 --- a/Assets/Logo/2019/SVG/512.svg +++ b/Assets/Logo/2019/SVG/512.svg @@ -1,4 +1,4 @@ - + diff --git a/Assets/Logo/2019/SVG/96.svg b/Assets/Logo/2019/SVG/96.svg index e52264b2d..5da8608c9 100644 --- a/Assets/Logo/2019/SVG/96.svg +++ b/Assets/Logo/2019/SVG/96.svg @@ -1,4 +1,4 @@ - + diff --git a/Assets/Logo/2021 - Maroon/256.svg b/Assets/Logo/2021 - Maroon/256.svg new file mode 100644 index 000000000..904f6e99c --- /dev/null +++ b/Assets/Logo/2021 - Maroon/256.svg @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Assets/Logo/2021 - Maroon/icon-256.ico b/Assets/Logo/2021 - Maroon/icon-256.ico new file mode 100644 index 000000000..27d1aca98 Binary files /dev/null and b/Assets/Logo/2021 - Maroon/icon-256.ico differ diff --git a/Assets/Logo/2021 - Maroon/icon-48px.ico b/Assets/Logo/2021 - Maroon/icon-48px.ico new file mode 100644 index 000000000..e2905c4b0 Binary files /dev/null and b/Assets/Logo/2021 - Maroon/icon-48px.ico differ diff --git a/Assets/Logo/2023/DefaultLogo.png b/Assets/Logo/2023/DefaultLogo.png new file mode 100644 index 000000000..cab87fb18 Binary files /dev/null and b/Assets/Logo/2023/DefaultLogo.png differ diff --git a/Assets/Logo/2023/Logo.svg b/Assets/Logo/2023/Logo.svg new file mode 100644 index 000000000..a587c3c70 --- /dev/null +++ b/Assets/Logo/2023/Logo.svg @@ -0,0 +1,90 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Assets/Logo/2023/icon256.ico b/Assets/Logo/2023/icon256.ico new file mode 100644 index 000000000..047442b6a Binary files /dev/null and b/Assets/Logo/2023/icon256.ico differ diff --git a/Assets/Logo/2023/icon48.ico b/Assets/Logo/2023/icon48.ico new file mode 100644 index 000000000..75da9cbd4 Binary files /dev/null and b/Assets/Logo/2023/icon48.ico differ diff --git a/Assets/Logo/2023/logo512.png b/Assets/Logo/2023/logo512.png new file mode 100644 index 000000000..b1f18de8c Binary files /dev/null and b/Assets/Logo/2023/logo512.png differ diff --git a/Assets/github.psd b/Assets/github.psd new file mode 100644 index 000000000..bfe5775af Binary files /dev/null and b/Assets/github.psd differ diff --git a/Assets/instagram.psd b/Assets/instagram.psd new file mode 100644 index 000000000..2cc6b35ad Binary files /dev/null and b/Assets/instagram.psd differ diff --git a/Assets/youtube_bg.psd b/Assets/youtube_bg.psd new file mode 100644 index 000000000..1849345ab Binary files /dev/null and b/Assets/youtube_bg.psd differ diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index a353394a9..d8608f269 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -9,23 +9,19 @@ We welcome any type of contribution, not only code. You can help with - **Marketing**: writing blog posts, howto's, printing stickers, ... - **Community**: presenting the project at meetups, organizing a dedicated meetup for the local community, ... - **Code**: take a look at the [open issues](https://github.com/d2phap/ImageGlass/issues). Even if you can't write code, commenting on them, showing that you care about a given issue matters. It helps us triage them. -- **Money**: we welcome financial contributions in full transparency on our [Open Collective](https://opencollective.com/imageglass) or [Paypal](https://www.paypal.me/d2phap). +- **Money**: we welcome financial contributions in full transparency on our [Github Sponsor](https://github.com/sponsors/d2phap) or [Paypal](https://www.paypal.me/d2phap). +- **Translation**: because we want our software to be accessible by anyone, even if they don't speak English. We have a [Crowdin page](https://crowdin.com/project/imageglass/invite) to make the translation of ImageGlass easier. ## Submitting code -Any code change should be submitted as a pull request. The description should explain what the code does and give steps to execute it. The pull request should also contain tests. +Any code change should be submitted as a pull request, **based on `develop` branch**. The description should explain what the code does and give steps to execute it. The pull request should also contain tests. ## Code review process The bigger the pull request, the longer it will take to review and merge. Try to break down large pull requests in smaller chunks that are easier to review and merge. It is also always helpful to have some context for your pull request. What was the purpose? Why does it matter to you? -## Financial contributions - -We also welcome financial contributions in full transparency on our [Open Collective](https://opencollective.com/imageglass) or [Paypal](https://www.paypal.me/d2phap). -Anyone can file an expense. If the expense makes sense for the development of the community, it will be "merged" in the ledger of our open collective by the core contributors and the person who filed the expense will be reimbursed. - ## Questions If you have any questions, create an [issue](https://github.com/d2phap/ImageGlass/issues) (protip: do a quick search first to see if someone else didn't ask the same question before!). @@ -39,26 +35,8 @@ Thank you to all the people who have already contributed to imageglass! -### Backers - -Thank you to all our backers! [[Become a backer](https://opencollective.com/imageglass#backer)] - - - - ### Sponsors -Thank you to all our sponsors! (please ask your company to also support this open source project by [becoming a sponsor](https://opencollective.com/imageglass#sponsor)) - - - - - - - - - - - +Thank you to all our sponsors! (please ask your company to also support this open source project by [[become a Sponsor](https://github.com/sponsors/d2phap)] - + diff --git a/LICENSE b/LICENSE index 02d490815..9638aa1e9 100644 --- a/LICENSE +++ b/LICENSE @@ -1,12 +1,42 @@ -ImageGlass is copyright (c) 2010 - 2019 by Duong Dieu Phap. - -Official website: https://imageglass.org -Source code: https://imageglass.org/source or -https://github.com/d2phap/ImageGlass - -ImageGlass is released under the terms of the GNU General Public License, -Version 3, which is available at https://www.gnu.org/licenses/gpl.html -and is reproduced verbatim below. +ImageGlass Software End-User License Agreement (EULA) + +This is a legal agreement between you and ImageGlass Software +(Duong Dieu Phap) covering the use of ImageGlass (the "Software"). + +ImageGlass is copyright (c) 2010 - 2025 by Duong Dieu Phap. +- Official website: https://imageglass.org +- Source code: https://github.com/d2phap/ImageGlass + +1) ImageGlass is an open-source software available in two main releases: +ImageGlass Store and ImageGlass Classic. + 1a) ImageGlass Store, which is published on the Microsoft Store, is a + paid version. + 1b) ImageGlass Classic is free for both personal and commercial use. + It is not available on Microsoft Store. + 1c) If you intend to use ImageGlass Classic at your place of business + or for commercial purposes, submitting an optional registration + at https://imageglass.org/license would be appreciated. + 1d) By installing, copying, or otherwise using the Software, you agree to + be bound by the terms of this EULA. + +2) The ImageGlass name and logo are trademarks of Duong Dieu Phap. +Written permission must be obtained prior to using the ImageGlass name +or logo in any distributed works. + +3) Warranty Disclaimer: ImageGlass and documentation are provided "as is" +without any warranty, express or implied, including, but not limited to, +the implied warranties of merchantability and fitness for a particular +purpose. The entire risk as to the quality and performance of the +Software is with you, the user. In no event shall ImageGlass or anyone +else who has been involved in the creation, development, production, or +delivery of this software be liable for any direct, indirect, incidental, +special, or consequential damages arising out of the use or inability to +use the software, even if ImageGlass has been advised of the possibility +of such damages. + +4) ImageGlass source code is released under the terms of the GNU General +Public License, Version 3, which is available at +https://www.gnu.org/licenses/gpl.html and is reproduced verbatim below. GNU GENERAL PUBLIC LICENSE diff --git a/README.md b/README.md index c0aadc773..2ae226588 100644 --- a/README.md +++ b/README.md @@ -1,92 +1,80 @@ -ImageGlass - A lightweight, versatile image viewer. +ImageGlass - A lightweight, versatile image viewer === +[![Website](https://img.shields.io/badge/www-imageglass.org-0099BC.svg?maxAge=3600&color=%233097B8)](https://imageglass.org) +[![Total downloads](https://img.shields.io/github/downloads/d2phap/imageglass/total?color=%23d60068&label=Total%20downloads&)](https://imageglass.org/download) +[![Latest version downloads](https://img.shields.io/github/downloads/d2phap/imageglass/latest/total?color=%23e66700&label=Latest%20version&)](https://imageglass.org/download) -[![Website](https://img.shields.io/badge/www-imageglass.org-0099BC.svg?maxAge=3600)](https://imageglass.org) +[![Discord](https://img.shields.io/discord/818852544859209748?label=chat&logo=discord&color=%233097B8&style=social)](https://discord.gg/tWjbynH2X8) +[![Twitter Follow](https://img.shields.io/twitter/follow/duongdieuphap?style=social)](https://twitter.com/duongdieuphap) [![GPL Licence](https://img.shields.io/badge/license-GPLv3-green.svg?maxAge=3600)](https://github.com/d2phap/ImageGlass/blob/master/LICENSE) [![Crowdin](https://d322cqt584bo4o.cloudfront.net/imageglass/localized.svg)](https://crowdin.com/project/imageglass) +ImageGlass is a lightweight software designed for seamless viewing of images in a clean and intuitive interface. With support for over 90 common image formats including `WEBP`, `GIF`, `SVG`, `PNG`, `JXL`, `HEIC`,... ImageGlass also offers advanced features that cater to the needs of both regular users and designers, making it the excellent tool to enhance workflow efficiency. -ImageGlass is a lightweight software application whose purpose is to help you view images in a clean and intuitive working environment. -It gives you the possibility to view over **70+** common image formats, including `.gif`, `.svg`, `.png`, `.heic`, ... and many more advanced features which help normal users or designers to speed up their work. - - -## Download & Screen shots -[![Total Downloads](https://img.shields.io/github/downloads/d2phap/imageglass/total?color=%233097B8&label=downloads&style=for-the-badge)](https://imageglass.org/download) -[![Latest Downloads](https://img.shields.io/github/downloads/d2phap/imageglass/latest/total?color=%23E17206&label=v7.5.1.1%20downloads&style=for-the-badge)](https://imageglass.org/download) - - - -ImageGlass 7.5.1.1 -
- - -## Development -![Visual Studio 2019](https://img.shields.io/badge/IDE-Visual%20Studio%202019-964ad4.svg?maxAge=3600) -![.NET Framework 4.7.1](https://img.shields.io/badge/.NET-Framework%204.7.1-lightgrey.svg?maxAge=3600) -![Windows OS](https://img.shields.io/badge/OS-Windows%207+-00adef.svg?maxAge=3600) - -```develop``` branch contains the lastest commits while ```master``` branch is for the final stable release. - -**``Pull Request``** is most welcome! - - - -## Docs - -[![Features](https://img.shields.io/badge/docs-Features-brightgreen.svg?maxAge=3600)](https://imageglass.org/docs/features) -[![Supported formats](https://img.shields.io/badge/docs-Supported%20Formats-brightgreen.svg?maxAge=3600)](https://imageglass.org/docs/supported-formats) -[![UI Shortcuts](https://img.shields.io/badge/docs-UI%20Shortcuts-brightgreen.svg?maxAge=3600)](https://imageglass.org/docs/ui-shortcuts-reference) -[![App configuration](https://img.shields.io/badge/docs-App%20configuration-brightgreen.svg?maxAge=3600)](https://imageglass.org/docs/app-configs) -[![Command line utilities](https://img.shields.io/badge/docs-Command%20lines%20Utils-brightgreen.svg?maxAge=3600)](https://imageglass.org/docs/command-line-utilities) - - -For information of the future developments, please visit [Wiki](https://github.com/d2phap/ImageGlass/wiki) and [Project](https://github.com/d2phap/ImageGlass/projects) page. - -For more information about ImageGlass, go to [Documentation](https://imageglass.org/docs) - - - + +image + -## Donation -ImageGlass is free and open source but developing it has taken thousands of hours of my time and a large part of my sanity. If you feel this little viewer useful to you, it would go a great way to ensuring that I can afford to take the time to continue to develop it. -Thanks for your gratitude and finance help! +## 📥 Download - -Buy me a beer? + + - -Become a sponsor - - +### ImageGlass on Microsoft Store! +- If you want to support the development of ImageGlass, you can purchase ImageGlass from Microsoft Store. +- Alternatively, you can use the one-time donation from [♥ GitHub Sponsor](https://github.com/sponsors/d2phap), then drop me a message in [ImageGlass Discord](https://discord.gg/tWjbynH2X8) or [email](https://imageglass.org/about), and I will send the code shortly. +- ImageGlass Store provides the convenience of fast, easy installation onto all of your Windows devices along with fully automatic, behind-the-scenes updates with all the newest features, improvements, and fixes. +### Difference Between ImageGlass Classic and Store Release +| | ImageGlass Classic | [ImageGlass Store](https://apps.microsoft.com/detail/9N33VZK3C7TH?launch=true&cid=GitHubRelease&mode=full) | +| -- | -- | -- | +| [All features](https://imageglass.org/docs/features),
including Explorer sort order | ✅ | ✅ | +| [Advanced configs
for Power users](https://imageglass.org/docs/app-configs) | ✅ | ✅ | +| Distribution | 🌐[ImageGlass.org](https://imageglass.org) and various sources | 🛍️[Microsoft Store](https://apps.microsoft.com/detail/9N33VZK3C7TH?launch=true&cid=GitHubRelease&mode=full) only | +| Price | 🆓 Free | 🪙Fee, with a 7-day trial | +| Commercial use | ✅ Recommended to [register](https://imageglass.org/license) | ✅ | +| Auto-update | ❌ User-managed | ✅ Seamless auto-updates | +| Hotfix update | ❌ Available in official releases only | ✅ Available as soon as they are fixed | -Bitcoin -``` -3Hp7QLP9Fxpb1s4CAcZFYR7NUgN1bR93Hy -``` +## 🪁 System Requirements +- Windows 10/11 64-bit, version 1809 (build 17763) or later +- Optional: [WebView2 Runtime 64-bit v119.0.2151 or later](https://go.microsoft.com/fwlink/p/?LinkId=2124703) +## 👨‍💻 Development +- Windows 11 +- Visual Studio 2026 +The `develop` branch contains the latest commits while the `prod` branch is for the final stable release. -Ethereum -``` -0x6DDBd646586bebF7a97e022D615cbE789D39a965 -``` +## 🗝️ License +ImageGlass is free for both personal and commercial use, except the Store version. If you intend to use ImageGlass at your place of business or for commercial purposes, it's recommended but not enforced to register at https://imageglass.org/license. +## 📚 Docs +- [Features](https://imageglass.org/docs/features) +- [Supported formats](https://imageglass.org/docs/supported-formats) +- [Shortcuts](https://imageglass.org/docs/ui-shortcuts-reference) +- [App configs](https://imageglass.org/docs/app-configs) +- [Command lines](https://imageglass.org/docs/command-line-utilities) +- [EULA](https://imageglass.org/license) +For more information about ImageGlass, go to [ImageGlass Docs](https://imageglass.org/docs). +## 🧑‍🤝‍🧑 Community and Support +- [GitHub issues](https://github.com/d2phap/ImageGlass/issues) +- [ImageGlass Discord](https://discord.gg/tWjbynH2X8) -## Contributors -This project exists thanks to all the people who contribute. [[Contribute]](CONTRIBUTING.md). - +## 💖 This project needs your help! +If you find ImageGlass useful and would like to support its ongoing development, consider making a donation. Your support, whether financial or simply sharing ImageGlass with others, means the world to me. Every bit helps keep the project alive and free for everyone. +Explorer the ways to support at: https://imageglass.org/donate diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 000000000..1facda43c --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,13 @@ +# Security Policy + +## Supported Versions + +Use this section to tell people about which versions of your project are +currently being supported with security updates. + +| Version | Supported | +| ------- | --------- | +| 9.x | ✅ | +| > [8.12](https://github.com/d2phap/ImageGlass/releases/tag/8.12.4.30) | ✅ Paid Support only | +| ≤ [8.12](https://github.com/d2phap/ImageGlass/releases/tag/8.12.4.30) | ❌ | + diff --git a/Setup/AdvancedInstaller/IG_Opera_Download.ps1 b/Setup/AdvancedInstaller/IG_Opera_Download.ps1 new file mode 100644 index 000000000..269b031d3 --- /dev/null +++ b/Setup/AdvancedInstaller/IG_Opera_Download.ps1 @@ -0,0 +1,8 @@ + +$url = "https://net.geo.opera.com/opera/stable/windows?utm_source=IMAGEGLASS&utm_medium=pb&utm_campaign=imagebundle" +$tempPath = [System.IO.Path]::GetTempPath() +$outpath = "$tempPath/IG_OperaSetup.exe" +Invoke-WebRequest -Uri $url -OutFile $outpath + +$args = @("--silent", "--allusers=0", "--show-onboarding-overlay", "--setdefaultbrowser=1") +Start-Process -Filepath $outpath -ArgumentList $args diff --git a/Setup/AdvancedInstaller/ImageGlass_9_x64.aip b/Setup/AdvancedInstaller/ImageGlass_9_x64.aip new file mode 100644 index 000000000..36b4fd9a7 --- /dev/null +++ b/Setup/AdvancedInstaller/ImageGlass_9_x64.aip @@ -0,0 +1,1766 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Setup/AdvancedInstaller/ImageGlass_9_x64.back(21.8.2).aip b/Setup/AdvancedInstaller/ImageGlass_9_x64.back(21.8.2).aip new file mode 100644 index 000000000..e9dd1bbc4 --- /dev/null +++ b/Setup/AdvancedInstaller/ImageGlass_9_x64.back(21.8.2).aip @@ -0,0 +1,982 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Setup/AdvancedInstaller/ImageGlass_9_x64.back(22.2).aip b/Setup/AdvancedInstaller/ImageGlass_9_x64.back(22.2).aip new file mode 100644 index 000000000..763016e37 --- /dev/null +++ b/Setup/AdvancedInstaller/ImageGlass_9_x64.back(22.2).aip @@ -0,0 +1,947 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Setup/AdvancedInstaller/ImageGlass_9_x64.back(22.6).aip b/Setup/AdvancedInstaller/ImageGlass_9_x64.back(22.6).aip new file mode 100644 index 000000000..4b6647943 --- /dev/null +++ b/Setup/AdvancedInstaller/ImageGlass_9_x64.back(22.6).aip @@ -0,0 +1,1678 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Setup/AdvancedInstaller/installer_bg.jpg b/Setup/AdvancedInstaller/installer_bg.jpg new file mode 100644 index 000000000..7f5fc89ac Binary files /dev/null and b/Setup/AdvancedInstaller/installer_bg.jpg differ diff --git a/Setup/AdvancedInstaller/opera.jpg b/Setup/AdvancedInstaller/opera.jpg new file mode 100644 index 000000000..2cf95aa85 Binary files /dev/null and b/Setup/AdvancedInstaller/opera.jpg differ diff --git a/Setup/AdvancedInstaller/x64/ImageGlass-x64.aip b/Setup/AdvancedInstaller/x64/ImageGlass-x64.aip deleted file mode 100644 index 5cc52a95d..000000000 --- a/Setup/AdvancedInstaller/x64/ImageGlass-x64.aip +++ /dev/null @@ -1,383 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Setup/AdvancedInstaller/x86/ImageGlass-x86.aip b/Setup/AdvancedInstaller/x86/ImageGlass-x86.aip deleted file mode 100644 index 5850fdd49..000000000 --- a/Setup/AdvancedInstaller/x86/ImageGlass-x86.aip +++ /dev/null @@ -1,383 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Setup/Assets/DefaultTheme/2017 (Light Gray).igtheme b/Setup/Assets/DefaultTheme/2017 (Light Gray).igtheme deleted file mode 100644 index 3235fe5b8..000000000 Binary files a/Setup/Assets/DefaultTheme/2017 (Light Gray).igtheme and /dev/null differ diff --git a/Setup/Assets/DefaultTheme/ActualSize.svg b/Setup/Assets/DefaultTheme/ActualSize.svg deleted file mode 100644 index e21aa68bb..000000000 --- a/Setup/Assets/DefaultTheme/ActualSize.svg +++ /dev/null @@ -1,16 +0,0 @@ - - - - - background - - - - - - - Layer 1 - - - - \ No newline at end of file diff --git a/Setup/Assets/DefaultTheme/AdjustWindowSize.svg b/Setup/Assets/DefaultTheme/AdjustWindowSize.svg deleted file mode 100644 index 190a5f789..000000000 --- a/Setup/Assets/DefaultTheme/AdjustWindowSize.svg +++ /dev/null @@ -1,37 +0,0 @@ - - - - - background - - - - - - - Layer 1 - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Setup/Assets/DefaultTheme/AutoZoom.svg b/Setup/Assets/DefaultTheme/AutoZoom.svg deleted file mode 100644 index 3bcf5e089..000000000 --- a/Setup/Assets/DefaultTheme/AutoZoom.svg +++ /dev/null @@ -1,13 +0,0 @@ - - - - Layer 1 - - - - - - - - - \ No newline at end of file diff --git a/Setup/Assets/DefaultTheme/Checkerboard.svg b/Setup/Assets/DefaultTheme/Checkerboard.svg deleted file mode 100644 index d873d922f..000000000 --- a/Setup/Assets/DefaultTheme/Checkerboard.svg +++ /dev/null @@ -1,22 +0,0 @@ - - - - background - - - - - - - Layer 1 - - - - - - - - - - - \ No newline at end of file diff --git a/Setup/Assets/DefaultTheme/Convert.svg b/Setup/Assets/DefaultTheme/Convert.svg deleted file mode 100644 index bcc8033c6..000000000 --- a/Setup/Assets/DefaultTheme/Convert.svg +++ /dev/null @@ -1,20 +0,0 @@ - - - - - background - - - - - - - Layer 1 - - - - - - - - \ No newline at end of file diff --git a/Setup/Assets/DefaultTheme/Delete.svg b/Setup/Assets/DefaultTheme/Delete.svg deleted file mode 100644 index 025af41b5..000000000 --- a/Setup/Assets/DefaultTheme/Delete.svg +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/Setup/Assets/DefaultTheme/Edit.svg b/Setup/Assets/DefaultTheme/Edit.svg deleted file mode 100644 index a7ecabc18..000000000 --- a/Setup/Assets/DefaultTheme/Edit.svg +++ /dev/null @@ -1,17 +0,0 @@ - - - - Layer 1 - - - - - - - - - - - - - \ No newline at end of file diff --git a/Setup/Assets/DefaultTheme/FlipHorz.svg b/Setup/Assets/DefaultTheme/FlipHorz.svg deleted file mode 100644 index 95aba23ad..000000000 --- a/Setup/Assets/DefaultTheme/FlipHorz.svg +++ /dev/null @@ -1,18 +0,0 @@ - - - - - background - - - - - - - Layer 1 - - - - - - \ No newline at end of file diff --git a/Setup/Assets/DefaultTheme/FlipVert.svg b/Setup/Assets/DefaultTheme/FlipVert.svg deleted file mode 100644 index 2c43b94c1..000000000 --- a/Setup/Assets/DefaultTheme/FlipVert.svg +++ /dev/null @@ -1,18 +0,0 @@ - - - - - background - - - - - - - Layer 1 - - - - - - \ No newline at end of file diff --git a/Setup/Assets/DefaultTheme/FullScreen.svg b/Setup/Assets/DefaultTheme/FullScreen.svg deleted file mode 100644 index f93e71c5a..000000000 --- a/Setup/Assets/DefaultTheme/FullScreen.svg +++ /dev/null @@ -1,25 +0,0 @@ - - - - - background - - - - - - - Layer 1 - - - - - - - - - - - - - \ No newline at end of file diff --git a/Setup/Assets/DefaultTheme/GoToFirst.svg b/Setup/Assets/DefaultTheme/GoToFirst.svg deleted file mode 100644 index c6d14f7cb..000000000 --- a/Setup/Assets/DefaultTheme/GoToFirst.svg +++ /dev/null @@ -1,14 +0,0 @@ - - - - Layer 1 - - - - - - - - - - \ No newline at end of file diff --git a/Setup/Assets/DefaultTheme/GoToImage.svg b/Setup/Assets/DefaultTheme/GoToImage.svg deleted file mode 100644 index 3ea01611c..000000000 --- a/Setup/Assets/DefaultTheme/GoToImage.svg +++ /dev/null @@ -1,22 +0,0 @@ - - - - - background - - - - - - - Layer 1 - - - - - - - - - - \ No newline at end of file diff --git a/Setup/Assets/DefaultTheme/GotoLast.svg b/Setup/Assets/DefaultTheme/GotoLast.svg deleted file mode 100644 index d29f337f2..000000000 --- a/Setup/Assets/DefaultTheme/GotoLast.svg +++ /dev/null @@ -1,14 +0,0 @@ - - - - Layer 1 - - - - - - - - - - \ No newline at end of file diff --git a/Setup/Assets/DefaultTheme/LockRatio.svg b/Setup/Assets/DefaultTheme/LockRatio.svg deleted file mode 100644 index 7d9185028..000000000 --- a/Setup/Assets/DefaultTheme/LockRatio.svg +++ /dev/null @@ -1,23 +0,0 @@ - - - - Layer 1 - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/Setup/Assets/DefaultTheme/Menu.svg b/Setup/Assets/DefaultTheme/Menu.svg deleted file mode 100644 index bcd9b7e81..000000000 --- a/Setup/Assets/DefaultTheme/Menu.svg +++ /dev/null @@ -1,19 +0,0 @@ - - - - - background - - - - - - - Layer 1 - - - - - - - \ No newline at end of file diff --git a/Setup/Assets/DefaultTheme/OpenFile.svg b/Setup/Assets/DefaultTheme/OpenFile.svg deleted file mode 100644 index e2e89e1a4..000000000 --- a/Setup/Assets/DefaultTheme/OpenFile.svg +++ /dev/null @@ -1,27 +0,0 @@ - - - - - background - - - - - - - Layer 1 - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/Setup/Assets/DefaultTheme/Print.svg b/Setup/Assets/DefaultTheme/Print.svg deleted file mode 100644 index e2d5aea04..000000000 --- a/Setup/Assets/DefaultTheme/Print.svg +++ /dev/null @@ -1,23 +0,0 @@ - - - - - background - - - - - - - Layer 1 - - - - - - - - - - - \ No newline at end of file diff --git a/Setup/Assets/DefaultTheme/Refresh.svg b/Setup/Assets/DefaultTheme/Refresh.svg deleted file mode 100644 index 96c204814..000000000 --- a/Setup/Assets/DefaultTheme/Refresh.svg +++ /dev/null @@ -1,24 +0,0 @@ - - - - - background - - - - - - - Layer 1 - - - - - - - - - - - - \ No newline at end of file diff --git a/Setup/Assets/DefaultTheme/RotateLeft.svg b/Setup/Assets/DefaultTheme/RotateLeft.svg deleted file mode 100644 index 80480144d..000000000 --- a/Setup/Assets/DefaultTheme/RotateLeft.svg +++ /dev/null @@ -1,25 +0,0 @@ - - - - - background - - - - - - - Layer 1 - - - - - - - - - - - - - \ No newline at end of file diff --git a/Setup/Assets/DefaultTheme/RotateRight.svg b/Setup/Assets/DefaultTheme/RotateRight.svg deleted file mode 100644 index 16705d2e1..000000000 --- a/Setup/Assets/DefaultTheme/RotateRight.svg +++ /dev/null @@ -1,25 +0,0 @@ - - - - - background - - - - - - - Layer 1 - - - - - - - - - - - - - \ No newline at end of file diff --git a/Setup/Assets/DefaultTheme/ScaleToFill.svg b/Setup/Assets/DefaultTheme/ScaleToFill.svg deleted file mode 100644 index c69920587..000000000 --- a/Setup/Assets/DefaultTheme/ScaleToFill.svg +++ /dev/null @@ -1,14 +0,0 @@ - - - - Layer 1 - - - - - - - - - - \ No newline at end of file diff --git a/Setup/Assets/DefaultTheme/ScaleToFit.svg b/Setup/Assets/DefaultTheme/ScaleToFit.svg deleted file mode 100644 index 1feef0cfc..000000000 --- a/Setup/Assets/DefaultTheme/ScaleToFit.svg +++ /dev/null @@ -1,13 +0,0 @@ - - - - Layer 1 - - - - - - - - - \ No newline at end of file diff --git a/Setup/Assets/DefaultTheme/ScaleToHeight.svg b/Setup/Assets/DefaultTheme/ScaleToHeight.svg deleted file mode 100644 index 465610fcd..000000000 --- a/Setup/Assets/DefaultTheme/ScaleToHeight.svg +++ /dev/null @@ -1,13 +0,0 @@ - - - - Layer 1 - - - - - - - - - \ No newline at end of file diff --git a/Setup/Assets/DefaultTheme/ScaleToWidth.svg b/Setup/Assets/DefaultTheme/ScaleToWidth.svg deleted file mode 100644 index 9109ce057..000000000 --- a/Setup/Assets/DefaultTheme/ScaleToWidth.svg +++ /dev/null @@ -1,13 +0,0 @@ - - - - Layer 1 - - - - - - - - - \ No newline at end of file diff --git a/Setup/Assets/DefaultTheme/Slideshow.svg b/Setup/Assets/DefaultTheme/Slideshow.svg deleted file mode 100644 index 64ea49798..000000000 --- a/Setup/Assets/DefaultTheme/Slideshow.svg +++ /dev/null @@ -1,26 +0,0 @@ - - - - - background - - - - - - - Layer 1 - - - - - - - - - - - - - - \ No newline at end of file diff --git a/Setup/Assets/DefaultTheme/ThumbnailBar.svg b/Setup/Assets/DefaultTheme/ThumbnailBar.svg deleted file mode 100644 index 4256bddb5..000000000 --- a/Setup/Assets/DefaultTheme/ThumbnailBar.svg +++ /dev/null @@ -1,18 +0,0 @@ - - - - background - - - - - - - Layer 1 - - - - - - - \ No newline at end of file diff --git a/Setup/Assets/DefaultTheme/ViewNextImage.svg b/Setup/Assets/DefaultTheme/ViewNextImage.svg deleted file mode 100644 index fdc326ea7..000000000 --- a/Setup/Assets/DefaultTheme/ViewNextImage.svg +++ /dev/null @@ -1,18 +0,0 @@ - - - - - background - - - - - - - Layer 1 - - - - - - \ No newline at end of file diff --git a/Setup/Assets/DefaultTheme/ViewPreviousImage.svg b/Setup/Assets/DefaultTheme/ViewPreviousImage.svg deleted file mode 100644 index 3c83ff516..000000000 --- a/Setup/Assets/DefaultTheme/ViewPreviousImage.svg +++ /dev/null @@ -1,18 +0,0 @@ - - - - - background - - - - - - - Layer 1 - - - - - - \ No newline at end of file diff --git a/Setup/Assets/DefaultTheme/ZoomIn.svg b/Setup/Assets/DefaultTheme/ZoomIn.svg deleted file mode 100644 index ba9e8e13d..000000000 --- a/Setup/Assets/DefaultTheme/ZoomIn.svg +++ /dev/null @@ -1,18 +0,0 @@ - - - - - background - - - - - - - Layer 1 - - - - - - \ No newline at end of file diff --git a/Setup/Assets/DefaultTheme/ZoomOut.svg b/Setup/Assets/DefaultTheme/ZoomOut.svg deleted file mode 100644 index a668674c7..000000000 --- a/Setup/Assets/DefaultTheme/ZoomOut.svg +++ /dev/null @@ -1,17 +0,0 @@ - - - - - background - - - - - - - Layer 1 - - - - - \ No newline at end of file diff --git a/Setup/Assets/DefaultTheme/config.xml b/Setup/Assets/DefaultTheme/config.xml deleted file mode 100644 index 8c57060de..000000000 --- a/Setup/Assets/DefaultTheme/config.xml +++ /dev/null @@ -1,38 +0,0 @@ - - - -
- - - \ No newline at end of file diff --git a/Setup/Assets/DefaultTheme/preview.png b/Setup/Assets/DefaultTheme/preview.png deleted file mode 100644 index ca8279a2e..000000000 Binary files a/Setup/Assets/DefaultTheme/preview.png and /dev/null differ diff --git a/Setup/Assets/Ext-Icons/AVIF.ico b/Setup/Assets/Ext-Icons/AVIF.ico new file mode 100644 index 000000000..39f61ac95 Binary files /dev/null and b/Setup/Assets/Ext-Icons/AVIF.ico differ diff --git a/Setup/Assets/Ext-Icons/B64.ico b/Setup/Assets/Ext-Icons/B64.ico new file mode 100644 index 000000000..ce680c68a Binary files /dev/null and b/Setup/Assets/Ext-Icons/B64.ico differ diff --git a/Setup/Assets/Ext-Icons/CR3.ico b/Setup/Assets/Ext-Icons/CR3.ico new file mode 100644 index 000000000..236c419c1 Binary files /dev/null and b/Setup/Assets/Ext-Icons/CR3.ico differ diff --git a/Setup/Assets/Ext-Icons/HEIC.ico b/Setup/Assets/Ext-Icons/HEIC.ico new file mode 100644 index 000000000..c2981b0ad Binary files /dev/null and b/Setup/Assets/Ext-Icons/HEIC.ico differ diff --git a/Setup/Assets/Ext-Icons/HEIF.ico b/Setup/Assets/Ext-Icons/HEIF.ico new file mode 100644 index 000000000..51aa6ba21 Binary files /dev/null and b/Setup/Assets/Ext-Icons/HEIF.ico differ diff --git a/Setup/Assets/Ext-Icons/JXL.ico b/Setup/Assets/Ext-Icons/JXL.ico new file mode 100644 index 000000000..cc7c070ba Binary files /dev/null and b/Setup/Assets/Ext-Icons/JXL.ico differ diff --git a/Setup/Assets/Ext-Icons/QOI.ico b/Setup/Assets/Ext-Icons/QOI.ico new file mode 100644 index 000000000..b750c9b7c Binary files /dev/null and b/Setup/Assets/Ext-Icons/QOI.ico differ diff --git a/Setup/Assets/LICENSE.rtf b/Setup/Assets/LICENSE.rtf deleted file mode 100644 index 7015d8d3d..000000000 --- a/Setup/Assets/LICENSE.rtf +++ /dev/null @@ -1,690 +0,0 @@ -{\rtf1\ansi\ansicpg1252\deff0\nouicompat{\fonttbl{\f0\fnil\fcharset0 Calibri;}} -{\colortbl ;\red0\green0\blue255;} -{\*\generator Riched20 10.0.19041}\viewkind4\uc1 -\pard\sl240\slmult1\f0\fs20\lang9 ImageGlass is copyright (c) 2010 - 2020 by Duong Dieu Phap.\par -\par -Official website: {{\field{\*\fldinst{HYPERLINK https://imageglass.org }}{\fldrslt{https://imageglass.org\ul0\cf0}}}}\f0\fs20\par -Source code: {{\field{\*\fldinst{HYPERLINK https://imageglass.org/source }}{\fldrslt{https://imageglass.org/source\ul0\cf0}}}}\f0\fs20 or \par -{{\field{\*\fldinst{HYPERLINK https://github.com/d2phap/ImageGlass }}{\fldrslt{https://github.com/d2phap/ImageGlass\ul0\cf0}}}}\f0\fs20\par -\par -ImageGlass is released under the terms of the GNU General Public License,\par -Version 3, which is available at {{\field{\*\fldinst{HYPERLINK https://www.gnu.org/licenses/gpl.html }}{\fldrslt{https://www.gnu.org/licenses/gpl.html\ul0\cf0}}}}\f0\fs20 \par -and is reproduced verbatim below.\par -\par -\par - GNU GENERAL PUBLIC LICENSE\par - Version 3, 29 June 2007\par -\par - Copyright (C) 2007 Free Software Foundation, Inc. <{{\field{\*\fldinst{HYPERLINK "https://fsf.org/"}}{\fldrslt{https://fsf.org/\ul0\cf0}}}}\f0\fs20 >\par - Everyone is permitted to copy and distribute verbatim copies\par - of this license document, but changing it is not allowed.\par -\par - Preamble\par -\par - The GNU General Public License is a free, copyleft license for\par -software and other kinds of works.\par -\par - The licenses for most software and other practical works are designed\par -to take away your freedom to share and change the works. By contrast,\par -the GNU General Public License is intended to guarantee your freedom to\par -share and change all versions of a program--to make sure it remains free\par -software for all its users. We, the Free Software Foundation, use the\par -GNU General Public License for most of our software; it applies also to\par -any other work released this way by its authors. You can apply it to\par -your programs, too.\par -\par - When we speak of free software, we are referring to freedom, not\par -price. Our General Public Licenses are designed to make sure that you\par -have the freedom to distribute copies of free software (and charge for\par -them if you wish), that you receive source code or can get it if you\par -want it, that you can change the software or use pieces of it in new\par -free programs, and that you know you can do these things.\par -\par - To protect your rights, we need to prevent others from denying you\par -these rights or asking you to surrender the rights. Therefore, you have\par -certain responsibilities if you distribute copies of the software, or if\par -you modify it: responsibilities to respect the freedom of others.\par -\par - For example, if you distribute copies of such a program, whether\par -gratis or for a fee, you must pass on to the recipients the same\par -freedoms that you received. You must make sure that they, too, receive\par -or can get the source code. And you must show them these terms so they\par -know their rights.\par -\par - Developers that use the GNU GPL protect your rights with two steps:\par -(1) assert copyright on the software, and (2) offer you this License\par -giving you legal permission to copy, distribute and/or modify it.\par -\par - For the developers' and authors' protection, the GPL clearly explains\par -that there is no warranty for this free software. For both users' and\par -authors' sake, the GPL requires that modified versions be marked as\par -changed, so that their problems will not be attributed erroneously to\par -authors of previous versions.\par -\par - Some devices are designed to deny users access to install or run\par -modified versions of the software inside them, although the manufacturer\par -can do so. This is fundamentally incompatible with the aim of\par -protecting users' freedom to change the software. The systematic\par -pattern of such abuse occurs in the area of products for individuals to\par -use, which is precisely where it is most unacceptable. Therefore, we\par -have designed this version of the GPL to prohibit the practice for those\par -products. If such problems arise substantially in other domains, we\par -stand ready to extend this provision to those domains in future versions\par -of the GPL, as needed to protect the freedom of users.\par -\par - Finally, every program is threatened constantly by software patents.\par -States should not allow patents to restrict development and use of\par -software on general-purpose computers, but in those that do, we wish to\par -avoid the special danger that patents applied to a free program could\par -make it effectively proprietary. To prevent this, the GPL assures that\par -patents cannot be used to render the program non-free.\par -\par - The precise terms and conditions for copying, distribution and\par -modification follow.\par -\par - TERMS AND CONDITIONS\par -\par - 0. Definitions.\par -\par - "This License" refers to version 3 of the GNU General Public License.\par -\par - "Copyright" also means copyright-like laws that apply to other kinds of\par -works, such as semiconductor masks.\par -\par - "The Program" refers to any copyrightable work licensed under this\par -License. Each licensee is addressed as "you". "Licensees" and\par -"recipients" may be individuals or organizations.\par -\par - To "modify" a work means to copy from or adapt all or part of the work\par -in a fashion requiring copyright permission, other than the making of an\par -exact copy. The resulting work is called a "modified version" of the\par -earlier work or a work "based on" the earlier work.\par -\par - A "covered work" means either the unmodified Program or a work based\par -on the Program.\par -\par - To "propagate" a work means to do anything with it that, without\par -permission, would make you directly or secondarily liable for\par -infringement under applicable copyright law, except executing it on a\par -computer or modifying a private copy. Propagation includes copying,\par -distribution (with or without modification), making available to the\par -public, and in some countries other activities as well.\par -\par - To "convey" a work means any kind of propagation that enables other\par -parties to make or receive copies. Mere interaction with a user through\par -a computer network, with no transfer of a copy, is not conveying.\par -\par - An interactive user interface displays "Appropriate Legal Notices"\par -to the extent that it includes a convenient and prominently visible\par -feature that (1) displays an appropriate copyright notice, and (2)\par -tells the user that there is no warranty for the work (except to the\par -extent that warranties are provided), that licensees may convey the\par -work under this License, and how to view a copy of this License. If\par -the interface presents a list of user commands or options, such as a\par -menu, a prominent item in the list meets this criterion.\par -\par - 1. Source Code.\par -\par - The "source code" for a work means the preferred form of the work\par -for making modifications to it. "Object code" means any non-source\par -form of a work.\par -\par - A "Standard Interface" means an interface that either is an official\par -standard defined by a recognized standards body, or, in the case of\par -interfaces specified for a particular programming language, one that\par -is widely used among developers working in that language.\par -\par - The "System Libraries" of an executable work include anything, other\par -than the work as a whole, that (a) is included in the normal form of\par -packaging a Major Component, but which is not part of that Major\par -Component, and (b) serves only to enable use of the work with that\par -Major Component, or to implement a Standard Interface for which an\par -implementation is available to the public in source code form. A\par -"Major Component", in this context, means a major essential component\par -(kernel, window system, and so on) of the specific operating system\par -(if any) on which the executable work runs, or a compiler used to\par -produce the work, or an object code interpreter used to run it.\par -\par - The "Corresponding Source" for a work in object code form means all\par -the source code needed to generate, install, and (for an executable\par -work) run the object code and to modify the work, including scripts to\par -control those activities. However, it does not include the work's\par -System Libraries, or general-purpose tools or generally available free\par -programs which are used unmodified in performing those activities but\par -which are not part of the work. For example, Corresponding Source\par -includes interface definition files associated with source files for\par -the work, and the source code for shared libraries and dynamically\par -linked subprograms that the work is specifically designed to require,\par -such as by intimate data communication or control flow between those\par -subprograms and other parts of the work.\par -\par - The Corresponding Source need not include anything that users\par -can regenerate automatically from other parts of the Corresponding\par -Source.\par -\par - The Corresponding Source for a work in source code form is that\par -same work.\par -\par - 2. Basic Permissions.\par -\par - All rights granted under this License are granted for the term of\par -copyright on the Program, and are irrevocable provided the stated\par -conditions are met. This License explicitly affirms your unlimited\par -permission to run the unmodified Program. The output from running a\par -covered work is covered by this License only if the output, given its\par -content, constitutes a covered work. This License acknowledges your\par -rights of fair use or other equivalent, as provided by copyright law.\par -\par - You may make, run and propagate covered works that you do not\par -convey, without conditions so long as your license otherwise remains\par -in force. You may convey covered works to others for the sole purpose\par -of having them make modifications exclusively for you, or provide you\par -with facilities for running those works, provided that you comply with\par -the terms of this License in conveying all material for which you do\par -not control copyright. Those thus making or running the covered works\par -for you must do so exclusively on your behalf, under your direction\par -and control, on terms that prohibit them from making any copies of\par -your copyrighted material outside their relationship with you.\par -\par - Conveying under any other circumstances is permitted solely under\par -the conditions stated below. Sublicensing is not allowed; section 10\par -makes it unnecessary.\par -\par - 3. Protecting Users' Legal Rights From Anti-Circumvention Law.\par -\par - No covered work shall be deemed part of an effective technological\par -measure under any applicable law fulfilling obligations under article\par -11 of the WIPO copyright treaty adopted on 20 December 1996, or\par -similar laws prohibiting or restricting circumvention of such\par -measures.\par -\par - When you convey a covered work, you waive any legal power to forbid\par -circumvention of technological measures to the extent such circumvention\par -is effected by exercising rights under this License with respect to\par -the covered work, and you disclaim any intention to limit operation or\par -modification of the work as a means of enforcing, against the work's\par -users, your or third parties' legal rights to forbid circumvention of\par -technological measures.\par -\par - 4. Conveying Verbatim Copies.\par -\par - You may convey verbatim copies of the Program's source code as you\par -receive it, in any medium, provided that you conspicuously and\par -appropriately publish on each copy an appropriate copyright notice;\par -keep intact all notices stating that this License and any\par -non-permissive terms added in accord with section 7 apply to the code;\par -keep intact all notices of the absence of any warranty; and give all\par -recipients a copy of this License along with the Program.\par -\par - You may charge any price or no price for each copy that you convey,\par -and you may offer support or warranty protection for a fee.\par -\par - 5. Conveying Modified Source Versions.\par -\par - You may convey a work based on the Program, or the modifications to\par -produce it from the Program, in the form of source code under the\par -terms of section 4, provided that you also meet all of these conditions:\par -\par - a) The work must carry prominent notices stating that you modified\par - it, and giving a relevant date.\par -\par - b) The work must carry prominent notices stating that it is\par - released under this License and any conditions added under section\par - 7. This requirement modifies the requirement in section 4 to\par - "keep intact all notices".\par -\par - c) You must license the entire work, as a whole, under this\par - License to anyone who comes into possession of a copy. This\par - License will therefore apply, along with any applicable section 7\par - additional terms, to the whole of the work, and all its parts,\par - regardless of how they are packaged. This License gives no\par - permission to license the work in any other way, but it does not\par - invalidate such permission if you have separately received it.\par -\par - d) If the work has interactive user interfaces, each must display\par - Appropriate Legal Notices; however, if the Program has interactive\par - interfaces that do not display Appropriate Legal Notices, your\par - work need not make them do so.\par -\par - A compilation of a covered work with other separate and independent\par -works, which are not by their nature extensions of the covered work,\par -and which are not combined with it such as to form a larger program,\par -in or on a volume of a storage or distribution medium, is called an\par -"aggregate" if the compilation and its resulting copyright are not\par -used to limit the access or legal rights of the compilation's users\par -beyond what the individual works permit. Inclusion of a covered work\par -in an aggregate does not cause this License to apply to the other\par -parts of the aggregate.\par -\par - 6. Conveying Non-Source Forms.\par -\par - You may convey a covered work in object code form under the terms\par -of sections 4 and 5, provided that you also convey the\par -machine-readable Corresponding Source under the terms of this License,\par -in one of these ways:\par -\par - a) Convey the object code in, or embodied in, a physical product\par - (including a physical distribution medium), accompanied by the\par - Corresponding Source fixed on a durable physical medium\par - customarily used for software interchange.\par -\par - b) Convey the object code in, or embodied in, a physical product\par - (including a physical distribution medium), accompanied by a\par - written offer, valid for at least three years and valid for as\par - long as you offer spare parts or customer support for that product\par - model, to give anyone who possesses the object code either (1) a\par - copy of the Corresponding Source for all the software in the\par - product that is covered by this License, on a durable physical\par - medium customarily used for software interchange, for a price no\par - more than your reasonable cost of physically performing this\par - conveying of source, or (2) access to copy the\par - Corresponding Source from a network server at no charge.\par -\par - c) Convey individual copies of the object code with a copy of the\par - written offer to provide the Corresponding Source. This\par - alternative is allowed only occasionally and noncommercially, and\par - only if you received the object code with such an offer, in accord\par - with subsection 6b.\par -\par - d) Convey the object code by offering access from a designated\par - place (gratis or for a charge), and offer equivalent access to the\par - Corresponding Source in the same way through the same place at no\par - further charge. You need not require recipients to copy the\par - Corresponding Source along with the object code. If the place to\par - copy the object code is a network server, the Corresponding Source\par - may be on a different server (operated by you or a third party)\par - that supports equivalent copying facilities, provided you maintain\par - clear directions next to the object code saying where to find the\par - Corresponding Source. Regardless of what server hosts the\par - Corresponding Source, you remain obligated to ensure that it is\par - available for as long as needed to satisfy these requirements.\par -\par - e) Convey the object code using peer-to-peer transmission, provided\par - you inform other peers where the object code and Corresponding\par - Source of the work are being offered to the general public at no\par - charge under subsection 6d.\par -\par - A separable portion of the object code, whose source code is excluded\par -from the Corresponding Source as a System Library, need not be\par -included in conveying the object code work.\par -\par - A "User Product" is either (1) a "consumer product", which means any\par -tangible personal property which is normally used for personal, family,\par -or household purposes, or (2) anything designed or sold for incorporation\par -into a dwelling. In determining whether a product is a consumer product,\par -doubtful cases shall be resolved in favor of coverage. For a particular\par -product received by a particular user, "normally used" refers to a\par -typical or common use of that class of product, regardless of the status\par -of the particular user or of the way in which the particular user\par -actually uses, or expects or is expected to use, the product. A product\par -is a consumer product regardless of whether the product has substantial\par -commercial, industrial or non-consumer uses, unless such uses represent\par -the only significant mode of use of the product.\par -\par - "Installation Information" for a User Product means any methods,\par -procedures, authorization keys, or other information required to install\par -and execute modified versions of a covered work in that User Product from\par -a modified version of its Corresponding Source. The information must\par -suffice to ensure that the continued functioning of the modified object\par -code is in no case prevented or interfered with solely because\par -modification has been made.\par -\par - If you convey an object code work under this section in, or with, or\par -specifically for use in, a User Product, and the conveying occurs as\par -part of a transaction in which the right of possession and use of the\par -User Product is transferred to the recipient in perpetuity or for a\par -fixed term (regardless of how the transaction is characterized), the\par -Corresponding Source conveyed under this section must be accompanied\par -by the Installation Information. But this requirement does not apply\par -if neither you nor any third party retains the ability to install\par -modified object code on the User Product (for example, the work has\par -been installed in ROM).\par -\par - The requirement to provide Installation Information does not include a\par -requirement to continue to provide support service, warranty, or updates\par -for a work that has been modified or installed by the recipient, or for\par -the User Product in which it has been modified or installed. Access to a\par -network may be denied when the modification itself materially and\par -adversely affects the operation of the network or violates the rules and\par -protocols for communication across the network.\par -\par - Corresponding Source conveyed, and Installation Information provided,\par -in accord with this section must be in a format that is publicly\par -documented (and with an implementation available to the public in\par -source code form), and must require no special password or key for\par -unpacking, reading or copying.\par -\par - 7. Additional Terms.\par -\par - "Additional permissions" are terms that supplement the terms of this\par -License by making exceptions from one or more of its conditions.\par -Additional permissions that are applicable to the entire Program shall\par -be treated as though they were included in this License, to the extent\par -that they are valid under applicable law. If additional permissions\par -apply only to part of the Program, that part may be used separately\par -under those permissions, but the entire Program remains governed by\par -this License without regard to the additional permissions.\par -\par - When you convey a copy of a covered work, you may at your option\par -remove any additional permissions from that copy, or from any part of\par -it. (Additional permissions may be written to require their own\par -removal in certain cases when you modify the work.) You may place\par -additional permissions on material, added by you to a covered work,\par -for which you have or can give appropriate copyright permission.\par -\par - Notwithstanding any other provision of this License, for material you\par -add to a covered work, you may (if authorized by the copyright holders of\par -that material) supplement the terms of this License with terms:\par -\par - a) Disclaiming warranty or limiting liability differently from the\par - terms of sections 15 and 16 of this License; or\par -\par - b) Requiring preservation of specified reasonable legal notices or\par - author attributions in that material or in the Appropriate Legal\par - Notices displayed by works containing it; or\par -\par - c) Prohibiting misrepresentation of the origin of that material, or\par - requiring that modified versions of such material be marked in\par - reasonable ways as different from the original version; or\par -\par - d) Limiting the use for publicity purposes of names of licensors or\par - authors of the material; or\par -\par - e) Declining to grant rights under trademark law for use of some\par - trade names, trademarks, or service marks; or\par -\par - f) Requiring indemnification of licensors and authors of that\par - material by anyone who conveys the material (or modified versions of\par - it) with contractual assumptions of liability to the recipient, for\par - any liability that these contractual assumptions directly impose on\par - those licensors and authors.\par -\par - All other non-permissive additional terms are considered "further\par -restrictions" within the meaning of section 10. If the Program as you\par -received it, or any part of it, contains a notice stating that it is\par -governed by this License along with a term that is a further\par -restriction, you may remove that term. If a license document contains\par -a further restriction but permits relicensing or conveying under this\par -License, you may add to a covered work material governed by the terms\par -of that license document, provided that the further restriction does\par -not survive such relicensing or conveying.\par -\par - If you add terms to a covered work in accord with this section, you\par -must place, in the relevant source files, a statement of the\par -additional terms that apply to those files, or a notice indicating\par -where to find the applicable terms.\par -\par - Additional terms, permissive or non-permissive, may be stated in the\par -form of a separately written license, or stated as exceptions;\par -the above requirements apply either way.\par -\par - 8. Termination.\par -\par - You may not propagate or modify a covered work except as expressly\par -provided under this License. Any attempt otherwise to propagate or\par -modify it is void, and will automatically terminate your rights under\par -this License (including any patent licenses granted under the third\par -paragraph of section 11).\par -\par - However, if you cease all violation of this License, then your\par -license from a particular copyright holder is reinstated (a)\par -provisionally, unless and until the copyright holder explicitly and\par -finally terminates your license, and (b) permanently, if the copyright\par -holder fails to notify you of the violation by some reasonable means\par -prior to 60 days after the cessation.\par -\par - Moreover, your license from a particular copyright holder is\par -reinstated permanently if the copyright holder notifies you of the\par -violation by some reasonable means, this is the first time you have\par -received notice of violation of this License (for any work) from that\par -copyright holder, and you cure the violation prior to 30 days after\par -your receipt of the notice.\par -\par - Termination of your rights under this section does not terminate the\par -licenses of parties who have received copies or rights from you under\par -this License. If your rights have been terminated and not permanently\par -reinstated, you do not qualify to receive new licenses for the same\par -material under section 10.\par -\par - 9. Acceptance Not Required for Having Copies.\par -\par - You are not required to accept this License in order to receive or\par -run a copy of the Program. Ancillary propagation of a covered work\par -occurring solely as a consequence of using peer-to-peer transmission\par -to receive a copy likewise does not require acceptance. However,\par -nothing other than this License grants you permission to propagate or\par -modify any covered work. These actions infringe copyright if you do\par -not accept this License. Therefore, by modifying or propagating a\par -covered work, you indicate your acceptance of this License to do so.\par -\par - 10. Automatic Licensing of Downstream Recipients.\par -\par - Each time you convey a covered work, the recipient automatically\par -receives a license from the original licensors, to run, modify and\par -propagate that work, subject to this License. You are not responsible\par -for enforcing compliance by third parties with this License.\par -\par - An "entity transaction" is a transaction transferring control of an\par -organization, or substantially all assets of one, or subdividing an\par -organization, or merging organizations. If propagation of a covered\par -work results from an entity transaction, each party to that\par -transaction who receives a copy of the work also receives whatever\par -licenses to the work the party's predecessor in interest had or could\par -give under the previous paragraph, plus a right to possession of the\par -Corresponding Source of the work from the predecessor in interest, if\par -the predecessor has it or can get it with reasonable efforts.\par -\par - You may not impose any further restrictions on the exercise of the\par -rights granted or affirmed under this License. For example, you may\par -not impose a license fee, royalty, or other charge for exercise of\par -rights granted under this License, and you may not initiate litigation\par -(including a cross-claim or counterclaim in a lawsuit) alleging that\par -any patent claim is infringed by making, using, selling, offering for\par -sale, or importing the Program or any portion of it.\par -\par - 11. Patents.\par -\par - A "contributor" is a copyright holder who authorizes use under this\par -License of the Program or a work on which the Program is based. The\par -work thus licensed is called the contributor's "contributor version".\par -\par - A contributor's "essential patent claims" are all patent claims\par -owned or controlled by the contributor, whether already acquired or\par -hereafter acquired, that would be infringed by some manner, permitted\par -by this License, of making, using, or selling its contributor version,\par -but do not include claims that would be infringed only as a\par -consequence of further modification of the contributor version. For\par -purposes of this definition, "control" includes the right to grant\par -patent sublicenses in a manner consistent with the requirements of\par -this License.\par -\par - Each contributor grants you a non-exclusive, worldwide, royalty-free\par -patent license under the contributor's essential patent claims, to\par -make, use, sell, offer for sale, import and otherwise run, modify and\par -propagate the contents of its contributor version.\par -\par - In the following three paragraphs, a "patent license" is any express\par -agreement or commitment, however denominated, not to enforce a patent\par -(such as an express permission to practice a patent or covenant not to\par -sue for patent infringement). To "grant" such a patent license to a\par -party means to make such an agreement or commitment not to enforce a\par -patent against the party.\par -\par - If you convey a covered work, knowingly relying on a patent license,\par -and the Corresponding Source of the work is not available for anyone\par -to copy, free of charge and under the terms of this License, through a\par -publicly available network server or other readily accessible means,\par -then you must either (1) cause the Corresponding Source to be so\par -available, or (2) arrange to deprive yourself of the benefit of the\par -patent license for this particular work, or (3) arrange, in a manner\par -consistent with the requirements of this License, to extend the patent\par -license to downstream recipients. "Knowingly relying" means you have\par -actual knowledge that, but for the patent license, your conveying the\par -covered work in a country, or your recipient's use of the covered work\par -in a country, would infringe one or more identifiable patents in that\par -country that you have reason to believe are valid.\par -\par - If, pursuant to or in connection with a single transaction or\par -arrangement, you convey, or propagate by procuring conveyance of, a\par -covered work, and grant a patent license to some of the parties\par -receiving the covered work authorizing them to use, propagate, modify\par -or convey a specific copy of the covered work, then the patent license\par -you grant is automatically extended to all recipients of the covered\par -work and works based on it.\par -\par - A patent license is "discriminatory" if it does not include within\par -the scope of its coverage, prohibits the exercise of, or is\par -conditioned on the non-exercise of one or more of the rights that are\par -specifically granted under this License. You may not convey a covered\par -work if you are a party to an arrangement with a third party that is\par -in the business of distributing software, under which you make payment\par -to the third party based on the extent of your activity of conveying\par -the work, and under which the third party grants, to any of the\par -parties who would receive the covered work from you, a discriminatory\par -patent license (a) in connection with copies of the covered work\par -conveyed by you (or copies made from those copies), or (b) primarily\par -for and in connection with specific products or compilations that\par -contain the covered work, unless you entered into that arrangement,\par -or that patent license was granted, prior to 28 March 2007.\par -\par - Nothing in this License shall be construed as excluding or limiting\par -any implied license or other defenses to infringement that may\par -otherwise be available to you under applicable patent law.\par -\par - 12. No Surrender of Others' Freedom.\par -\par - If conditions are imposed on you (whether by court order, agreement or\par -otherwise) that contradict the conditions of this License, they do not\par -excuse you from the conditions of this License. If you cannot convey a\par -covered work so as to satisfy simultaneously your obligations under this\par -License and any other pertinent obligations, then as a consequence you may\par -not convey it at all. For example, if you agree to terms that obligate you\par -to collect a royalty for further conveying from those to whom you convey\par -the Program, the only way you could satisfy both those terms and this\par -License would be to refrain entirely from conveying the Program.\par -\par - 13. Use with the GNU Affero General Public License.\par -\par - Notwithstanding any other provision of this License, you have\par -permission to link or combine any covered work with a work licensed\par -under version 3 of the GNU Affero General Public License into a single\par -combined work, and to convey the resulting work. The terms of this\par -License will continue to apply to the part which is the covered work,\par -but the special requirements of the GNU Affero General Public License,\par -section 13, concerning interaction through a network will apply to the\par -combination as such.\par -\par - 14. Revised Versions of this License.\par -\par - The Free Software Foundation may publish revised and/or new versions of\par -the GNU General Public License from time to time. Such new versions will\par -be similar in spirit to the present version, but may differ in detail to\par -address new problems or concerns.\par -\par - Each version is given a distinguishing version number. If the\par -Program specifies that a certain numbered version of the GNU General\par -Public License "or any later version" applies to it, you have the\par -option of following the terms and conditions either of that numbered\par -version or of any later version published by the Free Software\par -Foundation. If the Program does not specify a version number of the\par -GNU General Public License, you may choose any version ever published\par -by the Free Software Foundation.\par -\par - If the Program specifies that a proxy can decide which future\par -versions of the GNU General Public License can be used, that proxy's\par -public statement of acceptance of a version permanently authorizes you\par -to choose that version for the Program.\par -\par - Later license versions may give you additional or different\par -permissions. However, no additional obligations are imposed on any\par -author or copyright holder as a result of your choosing to follow a\par -later version.\par -\par - 15. Disclaimer of Warranty.\par -\par - THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY\par -APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT\par -HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY\par -OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,\par -THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\par -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM\par -IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF\par -ALL NECESSARY SERVICING, REPAIR OR CORRECTION.\par -\par - 16. Limitation of Liability.\par -\par - IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING\par -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS\par -THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY\par -GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE\par -USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF\par -DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD\par -PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),\par -EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF\par -SUCH DAMAGES.\par -\par - 17. Interpretation of Sections 15 and 16.\par -\par - If the disclaimer of warranty and limitation of liability provided\par -above cannot be given local legal effect according to their terms,\par -reviewing courts shall apply local law that most closely approximates\par -an absolute waiver of all civil liability in connection with the\par -Program, unless a warranty or assumption of liability accompanies a\par -copy of the Program in return for a fee.\par -\par - END OF TERMS AND CONDITIONS\par -\par - How to Apply These Terms to Your New Programs\par -\par - If you develop a new program, and you want it to be of the greatest\par -possible use to the public, the best way to achieve this is to make it\par -free software which everyone can redistribute and change under these terms.\par -\par - To do so, attach the following notices to the program. It is safest\par -to attach them to the start of each source file to most effectively\par -state the exclusion of warranty; and each file should have at least\par -the "copyright" line and a pointer to where the full notice is found.\par -\par - \par - Copyright (C) \par -\par - This program is free software: you can redistribute it and/or modify\par - it under the terms of the GNU General Public License as published by\par - the Free Software Foundation, either version 3 of the License, or\par - (at your option) any later version.\par -\par - This program is distributed in the hope that it will be useful,\par - but WITHOUT ANY WARRANTY; without even the implied warranty of\par - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\par - GNU General Public License for more details.\par -\par - You should have received a copy of the GNU General Public License\par - along with this program. If not, see <{{\field{\*\fldinst{HYPERLINK "https://www.gnu.org/licenses/"}}{\fldrslt{https://www.gnu.org/licenses/\ul0\cf0}}}}\f0\fs20 >.\par -\par -Also add information on how to contact you by electronic and paper mail.\par -\par - If the program does terminal interaction, make it output a short\par -notice like this when it starts in an interactive mode:\par -\par - Copyright (C) \par - This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.\par - This is free software, and you are welcome to redistribute it\par - under certain conditions; type `show c' for details.\par -\par -The hypothetical commands `show w' and `show c' should show the appropriate\par -parts of the General Public License. Of course, your program's commands\par -might be different; for a GUI interface, you would use an "about box".\par -\par - You should also get your employer (if you work as a programmer) or school,\par -if any, to sign a "copyright disclaimer" for the program, if necessary.\par -For more information on this, and how to apply and follow the GNU GPL, see\par -<{{\field{\*\fldinst{HYPERLINK "https://www.gnu.org/licenses/"}}{\fldrslt{https://www.gnu.org/licenses/\ul0\cf0}}}}\f0\fs20 >.\par -\par - The GNU General Public License does not permit incorporating your program\par -into proprietary programs. If your program is a subroutine library, you\par -may consider it more useful to permit linking proprietary applications with\par -the library. If this is what you want to do, use the GNU Lesser General\par -Public License instead of this License. But first, please read\par -<{{\field{\*\fldinst{HYPERLINK "https://www.gnu.org/licenses/why-not-lgpl.html"}}{\fldrslt{https://www.gnu.org/licenses/why-not-lgpl.html\ul0\cf0}}}}\f0\fs20 >.\par -} - \ No newline at end of file diff --git a/Setup/Assets/Language/Arabic, Egypt.iglang.json b/Setup/Assets/Language/Arabic, Egypt.iglang.json new file mode 100644 index 000000000..f46d22679 --- /dev/null +++ b/Setup/Assets/Language/Arabic, Egypt.iglang.json @@ -0,0 +1,504 @@ +{ + "_Metadata": { + "Code": "ar-SA", + "EnglishName": "Arabic", + "LocalName": "الاسم المحلي للغة", + "Author": "sysy1413", + "MinVersion": "9.3" + }, + "Items": { + "FrmCrop.SelectionAspectRatio._Original": "Original", + "FrmMain.MnuShare._Error": "Could not open Share dialog.", + "_.Metadata._FileLastAccessTime": "Date accessed", + "FrmAbout._License": "Software license", + "FrmSettings.Toolbar._Errors._ButtonIdDuplicated": "A button with the ID '{0}' has already been defined. Please choose a different and unique ID for your button to avoid conflicts.", + "FrmMain.MnuSave._Confirm": "Are you sure you want to override this image?", + "FrmSettings._OpenDefaultAppsSetting": "Open Default apps setting", + "FrmMain.MnuCopyPath": "نسخ مسار الصورة", + "FrmCropSettings.DefaultSelectionType._SelectNone": "Select none", + "_.MouseWheelAction._PanHorizontally": "Pan left / right", + "FrmMain.MnuPrint": "إطبع…", + "FrmSettings.Toolbar._ToolbarButtons": "Toolbar buttons", + "FrmResize.LblResample": "Resample:", + "_.ImageOrderBy._Extension": "ملحق", + "FrmSettings.Nav._Viewer": "العارض", + "FrmSettings.EditAppDialog._EditApp": "Edit app", + "FrmCrop.BtnReset._Tooltip": "Reset selection", + "FrmMain.MnuRename._Description": "Enter a new filename:", + "_._No": "Yes", + "FrmSlideshow.MnuToggleCountdown": "إظهار العد التنازلي لعرض الشرائح", + "FrmSettings._OpenStartupAppsSetting": "Open Startup apps setting", + "FrmMain.MnuViewPreviousFrame": "View previous frame", + "_.ImageOrderBy._DateModified": "Date modified", + "FrmMain.MnuViewNextFrame": "View next frame", + "FrmMain.MnuUnload": "Unload image", + "FrmSettings.Toolbar._HideToolbarInFullscreen": "Hide toolbar in Full Screen mode", + "_.ImageOrderType._Desc": "تنازلي", + "_._Update": "Update", + "FrmSettings._EnableImageAsyncLoading": "Enable image asynchronous loading", + "FrmSettings._DefaultPhotoViewer._Description": "Register the supported formats of ImageGlass with Windows. You might need to open the Default apps settings and manually select ImageGlass from the list for it to take effect.", + "_.MouseWheelAction._BrowseImages": "View next / previous Image", + "FrmSettings._EditApps": "Image editing apps", + "FrmColorPickerSettings.ChkShowCIELabA": "Use CIELAB format with alpha value", + "_._GetHelp": "Get help", + "FrmQuickSetup._SkipQuickSetup": "Skip this and launch ImageGlass", + "FrmColorPickerSettings._Title": "Color picker settings", + "_._Copy": "نسخ", + "FrmSettings._ImageBoosterCacheCount": "Number of images cached by Image Booster (one direction)", + "FrmMain.MnuPanToBottom": "Pan image to bottom", + "FrmMain.MnuZoom": "تكبير", + "FrmCropSettings.ChkCloseToolAfterSaving": "Close Crop tool after saving", + "FrmSettings._ShowWelcomeImage": "Show welcome image", + "FrmSettings._ColorProfile": "لون الملف الشخصي", + "FrmSettings._Theme._UninstallTheme": "Uninstall a theme pack", + "FrmMain._OpenWith": "Open with {0}", + "FrmMain.MnuRemoveDefaultPhotoViewer": "Remove default photo viewer", + "_.AfterEditAppAction._Nothing": "لا شيء", + "FrmCrop.BtnSave": "حفظ", + "FrmMain.MnuScaleToFit": "مقياس لملائمة", + "FrmToolNotFound.LblDownloadToolText": "You can download more tools for ImageGlass at:", + "_._LearnMore": "Learn more…", + "FrmCrop.LblAspectRatio": "Aspect ratio:", + "FrmExportFrames._FileNotExist": "Image file does not exist", + "FrmSettings._LightTheme": "Light", + "FrmSettings.Nav._Slideshow": "عرض شرائح", + "_._Continue": "Continue", + "_._AddHotkey": "Add hotkey…", + "FrmMain.MnuSetDesktopBackground": "تعيين كخلفية سطح المكتب", + "FrmMain.MnuReload": "اعادة تحميل الصورة", + "FrmSlideshow.MnuExitSlideshow": "الخروج من عرض الشرائح", + "FrmMain.MnuAutoZoom": "التكبير التلقائي", + "FrmSettings._ShowImagePreview": "Display image preview while it's being loaded", + "FrmCrop.BtnCopy._Tooltip": "Copy the selection to clipboard", + "FrmSettings.Nav._Toolbar": "شريط الأدوات", + "FrmMain.MnuSave._Error": "Could not save the image", + "FrmSettings._AfterEditingAction": "بعد فتح تطبيق التعديل", + "FrmSettings._ShouldUseColorProfileForAll": "تطبيق أيضًا على الصور بدون ملف تعريف الألوان المضمنة", + "FrmCropSettings.DefaultSelectionType._UseTheLastSelection": "Use the last selection", + "FrmSettings._SlideshowInterval._From": "From", + "FrmSettings._ImageInterpolation": "Image interpolation", + "FrmQuickSetup._StepInfo": "الخطوة {0}", + "FrmMain.MnuColorPicker": "منتقي الألوان", + "FrmCrop.SelectionAspectRatio._FreeRatio": "Free ratio", + "FrmSettings._ResetSettings": "Reset settings", + "FrmSettings._Startup": "Startup", + "_.BackdropStyle._None": "لا شيء", + "FrmSettings._LoadDefaultZoomLevels": "Load default zoom levels", + "FrmColorPicker.BtnSettings._Tooltip": "Open Color picker settings…", + "FrmSettings._UseThemeForDarkMode": "Use this theme for dark mode", + "FrmSettings._ShowDeleteConfirmation": "Show confirmation dialog when deleting file", + "FrmSettings._ShowAppIcon": "Show app icon on the title bar", + "_._InvalidAction": "Invalid action", + "FrmQuickSetup._SelectProfile": "Select a profile", + "_.Metadata._FileCreationTime": "Date created", + "FrmSettings._SlideshowImagesToNotifySound": "Number of images to trigger a notification sound", + "FrmSettings._BackgroundColor": "Viewer background color", + "FrmSettings._RealTimeFileUpdate": "Real-time file update", + "_.ColorProfileOption._CurrentMonitorProfile": "Current monitor profile", + "FrmSettings._EnableCutMultipleFiles": "Enable the cutting of multiple files at once", + "FrmSettings._AutoUpdate": "التحقق من التحديث تلقائياً", + "FrmCropSettings.LblDefaultSelection": "Default selection", + "FrmSettings._UseThemeForLightMode": "Use this theme for light mode", + "FrmSettings._ZoomLevels": "مستويات التكبير", + "FrmMain.MnuSetLockScreen._Success": "Lock screen image is updated", + "FrmSettings._ShowGalleryFileName": "Show thumbnail filename", + "FrmSettings.Layout._Order": "Order", + "FrmCropSettings.ChkAutoCenterSelection": "Auto-center selection", + "FrmSettings.Nav._FileTypeAssociations": "File type associations", + "_._Back": "Back", + "FrmMain.MnuSetDesktopBackground._Success": "Desktop background is updated", + "FrmSettings._ShouldAutoOpenNewAddedImage": "Open the new added image automatically", + "FrmCrop.SelectionAspectRatio._Custom": "مخصص…", + "FrmMain.MnuCopyPath._Success": "Copied the current image path.", + "FrmSettings._StartupBoost._Error": "Could not change Startup Boost setting", + "FrmToolNotFound.LblDescription": "ImageGlass was unable to locate the path to the '{0}' executable. To resolve this issue, please update the path to the '{0}' as necessary.", + "FrmMain.MnuClearClipboard": "مسح الحافظة", + "FrmSettings._ColorManagement": "إدارة الألوان", + "FrmMain._ReachedLastLast": "وصلت إلى آخر صورة", + "FrmMain.MnuPanUp": "Pan image up", + "FrmMain.MnuRemoveDefaultPhotoViewer._Success": "ImageGlass is no longer the default photo viewer.", + "FrmSettings._GetMoreLanguagePacks": "احصل على المزيد من حزم اللغات…", + "FrmAbout._Privacy": "Privacy policy", + "FrmSettings._EnableRecursiveLoading": "Load images in subfolders", + "_._UserAction._MethodArgumentNotSupported": "The argument type of method '{0}' is not supported", + "FrmSettings._FileExtensionIcons._Description": "For customizing file extension icons, download an icon pack, place all .ICO files in the extension icon folder, and click the '{0}' button. This will also set ImageGlass as default photo viewer.", + "_.ImageOrderType._Asc": "تصاعدي", + "FrmExportFrames._Title": "Export image frames", + "_._Install": "تثبيت…", + "FrmMain.MnuFlipHorizontal": "قلب أفقي", + "FrmSettings._OpenExtensionIconFolder": "Open extension icon folder", + "FrmAbout._Collaborator": "Collaborator:", + "FrmQuickSetup._ConfirmCloseProcess": "Before applying the new settings, it's essential to close all ImageGlass processes. Are you ready to proceed?", + "FrmExportFrames._ExportDone": "Exported {0} frames successfully to \r\n{1}", + "FrmCrop.BtnSaveAs._Tooltip": "Save as a copy…", + "FrmMain.MnuOpenFile": "فتح الملف…", + "FrmColorPickerSettings.ChkShowRgbA": "Use RGB format with alpha value", + "_.ImageInfo._ListCount": "{0} file(s)", + "FrmMain.MnuGoToLast": "Go to last image", + "FrmSettings._EditApps._AppName": "اسم التطبيق", + "FrmSettings._SlideshowBackgroundColor": "Slideshow background color", + "FrmAbout._Email": "البريد الإلكتروني:", + "_.MouseWheelAction._DoNothing": "لا تفعل شيئا", + "FrmMain.MnuSaveAs": "حفظ باسم…", + "FrmMain._Loading": "Loading…", + "_._Browse": "تصفح…", + "FrmMain.MnuSetDefaultPhotoViewer._Error": "Could not set ImageGlass as default photo viewer.", + "FrmSettings.Nav._Language": "اللغة", + "FrmQuickSetup._SeeWhatNew": "See what's new in this version…", + "FrmSettings._ImageInterpolation._ScaleUp": "When zoom > 100%", + "FrmSettings.Layout._ToolbarContextPosition": "Contextual toolbar position", + "FrmMain.MnuDeleteFromHardDisk": "Delete permanently", + "FrmSettings._EmbeddedThumbnail": "Embedded thumbnail", + "FrmMain.MnuDeleteFromHardDisk._Description": "Are you sure you want to permanently delete this file?", + "FrmMain.MnuScaleToFill": "إعادة القياس لملء", + "FrmCrop.BtnCrop": "Crop", + "_.AfterEditAppAction._Minimize": "تصغير", + "FrmMain.MnuInvertColors": "Invert colors", + "FrmSettings._StartupBoost": "Startup Boost", + "FrmMain.MnuViewFirstFrame": "View first frame", + "_.MouseWheelEvent._CtrlAndScroll": "Hold Ctrl and scroll", + "FrmSettings._HideMainWindowInSlideshow": "Automatically hide main window", + "_.Metadata._FrameCount": "Frames", + "FrmSettings._EnableCopyMultipleFiles": "Enable the copying of multiple files at once", + "FrmMain.MnuFrameless._EnableDescription": "Hold Shift key to move the window.", + "_.ImageOrderBy._ExifDateTaken": "EXIF: Date taken", + "FrmAbout._Credits": "Credits", + "FrmSettings._AddNewFileExtension": "Add new file extension", + "FrmMain.MnuQuickSetup": "Open ImageGlass Quick Setup", + "FrmMain.MnuSave._Success": "Image is saved", + "FrmMain.MnuPanLeft": "Pan image left", + "FrmUpdate._StatusChecking": "Checking for update…", + "FrmSettings.Nav._Layout": "تخطيط", + "FrmMain.MnuOpenWith": "فتح الملف…", + "FrmAbout._Thanks": "Special thanks to", + "_._Warning": "Warning", + "FrmSettings.Nav._Keyboard": "لوحة المفاتيح", + "FrmSlideshow._PauseSlideshow": "Slideshow is paused.", + "_._Add+": "إضافة…", + "_._Email": "البريد الإلكتروني", + "FrmMain.MnuPanDown": "Pan image down", + "_._Cancel": "الغاء", + "_._OK": "حسناً", + "FrmMain.MnuPanRight": "Pan image right", + "_.Position._Right": "Right", + "_._Icon": "Icon", + "FrmSettings._ShouldLoadHiddenImages": "Load hidden images", + "_._InvalidAction._Transformation": "ImageGlass does not support rotation, flipping for this image.", + "FrmSettings._MakeDefault": "Make default", + "FrmMain.MnuCopyImageData._Copying": "Copying the image data. It's going to take a while…", + "FrmSettings._UseEmbeddedThumbnailRawFormats": "Load only the embedded thumbnail for RAW formats", + "_.ImageInterpolation._Linear": "Linear", + "FrmSettings._ImageInfoTags": "Image information tags", + "FrmSettings._FileExtensionIcons": "File extension icons", + "FrmMain.MnuEdit._AppNotFound": "Could not find the associated app for editing. You can assign an app for editing this format in ImageGlass Settings > Edit.", + "_.ColorProfileOption._None": "لا شيء", + "FrmSettings._TotalSupportedFormats": "Total supported formats: {0}", + "FrmSettings._Clipboard": "الحافظة", + "_._UserAction._Win32ExeError": "Cannot execute command '{0}'. Make sure the name is correct.", + "FrmCropSettings.DefaultSelectionType._SelectX": "Select {0}", + "_.AfterEditAppAction._Close": "أغلق", + "FrmAbout._LogoDesigner": "Logo designer:", + "_.ImageOrderBy._Name": "الاسم (افتراضي)", + "FrmMain.MnuRemoveDefaultPhotoViewer._Error": "Could not remove ImageGlass as the default photo viewer.", + "FrmExportFrames._FolderPickerTitle": "Select output folder for exporting image frames", + "FrmAbout._Donate": "Donate", + "FrmMain.MnuFrameNav": "Frame navigation", + "FrmMain.MnuSetLockScreen": "تعيين كصورة شاشة قفل", + "_._Delete": "حذف", + "FrmMain.MnuViewPrevious": "عرض الصفحة السابقة", + "_.Position._Top": "أعلى", + "FrmSettings.Toolbar._CurrentButtons": "Current buttons:", + "FrmMain.MnuAbout": "حول", + "FrmSettings._RemoveDefault": "Remove default", + "_._Description": "الوصف", + "FrmMain.MnuPasteImage._Error": "Could not find image data in the Clipboard", + "FrmMain.MnuSettings": "الإعدادات", + "FrmCropSettings._Title": "Crop settings", + "FrmSettings.Toolbar._ToolbarIconHeight": "حجم أيقونة شريط الأدوات", + "FrmSettings._SlideshowInterval._To": "To", + "FrmSettings.Layout._ToolbarPosition": "موضع شريط الأدوات", + "FrmUpdate._StatusUpdated": "You are using the latest version!", + "FrmMain.MnuExit": "خروج", + "_._Webview2._Outdated": "Your WebView2 Runtime is not supported. Please update to version {0} or later.", + "_._Yes": "نعم", + "FrmMain.MnuRotateLeft": "تدوير لليسار", + "FrmSettings._EnableStartupBoost": "Enable Startup Boost", + "_.ImageOrderBy._ExifRating": "EXIF: Rating", + "FrmMain.MnuZoomIn": "تكبير و تقريب", + "_.Metadata._ColorSpace": "Color space", + "FrmAbout._Version": "الإصدار:", + "FrmMain.MnuToggleTopMost._Enable": "Enabled window always on top", + "FrmSettings.Toolbar._AvailableButtons": "Available buttons:", + "FrmMain.MnuSave._Saving": "Saving image…", + "FrmQuickSetup._StandardUser": "Standard user", + "FrmMain.MnuSetLockScreen._Error": "Could not set the viewing image as lock screen image", + "FrmSettings.Nav._Image": "صورة", + "FrmSettings._Theme._InstallTheme": "Install theme packs", + "FrmSettings._EnableMultiInstances": "اسمح بعدة نوافذ للبرنامج", + "FrmMain.MnuCropTool": "Crop image", + "_._IgCommandExe._DefaultError._Heading": "Invalid commands", + "_._Refresh": "تحديث", + "FrmMain.MnuLosslessCompression._Description": "This tool uses Magick.NET library for lossless compression, optimizing file size. Overwrites only if the compressed file is smaller than the original.", + "_._MoveDown": "Move down", + "FrmSettings._GetExtensionIconPacks": "Get extension icon packs…", + "FrmSettings._InAppMessageDuration": "In-app message duration (milliseconds)", + "FrmMain.MnuFrameless": "بلا إطار", + "_._Reset": "مسح التعديلات", + "FrmSettings._ConfigDir": "Configuration location", + "FrmQuickSetup._SettingsWillBeApplied": "Settings will be applied:", + "FrmSettings._UnmanagedSettingReminder": "This setting is not managed by ImageGlass. Don't forget to disable it before you remove or relocate the app because ImageGlass does not handle this automatically.", + "FrmMain.MnuClipboard": "الحافظة", + "FrmMain.MnuCustomZoom": "تكبير مخصص…", + "FrmSettings._DisplayLanguage": "Display language", + "FrmMain.MnuPrint._Error": "Could not print the viewing image", + "FrmSettings._ShouldPreserveModifiedDate": "الحفاظ على تاريخ تعديل الصورة عند الحفظ", + "FrmSettings._ShowSaveOverrideConfirmation": "Show confirmation dialog when overriding file", + "FrmColorPickerSettings.ChkShowHexA": "Use HEX format with alpha value", + "FrmMain.MnuFullScreen": "Full Screen", + "FrmSettings._StartupDir": "Startup location", + "FrmSettings._ShowCheckerboardOnlyImageRegion": "Show checkerboard only within the image region", + "FrmMain.MnuClearClipboard._Success": "Cleared clipboard.", + "FrmQuickSetup._Text": "ImageGlass Quick Setup", + "FrmMain.MnuLosslessCompression._Done": "Done lossless compression.\r\nThe new file size is {0}, saved {1}.", + "FrmMain.MnuLosslessCompression": "Magick.NET Lossless Compression", + "FrmResize.RadResizeByPercentage": "Percentage", + "FrmSettings._StartupBoost._Disabled": "Startup Boost is disabled", + "FrmMain.MnuToggleCheckerboard": "خلفية لوحة التدقيق", + "FrmSettings._MinEmbeddedThumbnailSize._Height": "الطول", + "FrmSettings.Nav._General": "عام", + "FrmSettings._ImageLoading": "تحميل الصورة", + "FrmSettings._ShowSlideshowCountdown": "إظهار العد التنازلي لعرض الشرائح", + "FrmMain.MnuSave": "حفظ", + "FrmMain.MnuMoveToRecycleBin": "Move to the Recycle Bin", + "FrmMain.MnuRefresh": "تحديث", + "FrmToolNotFound.LblHeading": "'{0}' is not found!", + "FrmMain.MnuReportIssue": "الإبلاغ عن مشكلة…", + "FrmMain.MnuCopyImageData": "نسخ بيانات الصورة", + "FrmMain.MnuCheckForUpdate._NewVersion": "يتوفر إصدار جديد!", + "_._Empty": "(empty)", + "FrmSettings._Zooming": "تكبير و تقريب", + "FrmMain.MnuCutFile": "Cut file", + "FrmHotkeyPicker.LblHotkey": "Press hotkeys", + "FrmSettings.Layout._Gallery": "Gallery", + "FrmMain.MnuNewWindow": "افتح نافذة جديدة", + "FrmMain.MnuMoveToRecycleBin._Description": "Do you want to move this file to the Recycle bin?", + "FrmSettings._DefaultPhotoViewer": "Default photo viewer", + "_.Metadata._ExifDateTimeOriginal": "EXIF: DateTimeOriginal", + "FrmMain.MnuRotateRight": "تدوير لليمين", + "FrmSettings._MinEmbeddedThumbnailSize": "Minimum size of the embedded thumbnail to be loaded", + "FrmMain.MnuSetDefaultPhotoViewer": "Set default photo viewer", + "FrmMain.MnuImageProperties": "خصائص الصورة", + "FrmSettings._EnableNavigationButtons": "Show navigation arrow buttons", + "_._Edit": "تحرير", + "FrmSettings._ImageBooster": "Image Booster", + "FrmSettings.Tools._IntegratedWith": "Integrated with {0}", + "_._Next": "التالى", + "FrmExportFrames._OpenOutputFolder": "Open output folder", + "FrmMain.MnuOpenLocation": "فتح مكان الصورة", + "FrmMain.MnuLockZoom": "تثبيت نسبة التكبير", + "FrmSettings._StartupBoost._Description": "Preload and run ImageGlass in the background for a few seconds during Windows startup to accelerate the first launch.", + "FrmSettings._WindowBackdrop": "Window backdrop", + "FrmSettings._EnableRealTimeFileUpdate": "Monitor file changes in the viewing folder and update in realtime", + "_._NotSupported": "Unsupported format", + "FrmSettings._Theme._GetMoreThemes": "Get more theme packs…", + "FrmMain.MnuNewWindow._Error": "Cannot open new window because only one instance is allowed", + "FrmMain.MnuZoomOut": "تكبير خارجي", + "FrmSettings.Toolbar._EditButton": "Edit toolbar button", + "FrmMain.MnuCustomZoom._Description": "أدخل قيمة التكبير/التصغير الجديدة", + "FrmResize.RadResizeByPixels": "Pixels", + "FrmMain.MnuEdit": "تحرير الصورة {0}…", + "FrmSettings.Layout._GalleryPosition": "Gallery position", + "FrmMain.MnuWindowFit": "Window Fit", + "FrmMain._OpenFileDialog": "جميع الملفات المدعومة", + "FrmSettings._UseRandomIntervalForSlideshow": "استخدام فاصل زمني عشوائي", + "_.Position._Left": "Left", + "FrmSettings._ShouldOpenLastSeenImage": "Open the last seen image", + "_.Position._Bottom": "أسفل", + "FrmResize.ChkKeepRatio": "Keep ratio propotional", + "FrmMain.MnuGoTo": "انتقل إلى…", + "FrmSlideshow.MnuPauseResumeSlideshow": "Pause/resume slideshow", + "FrmSettings.Tools._Integrated": "Integrated", + "FrmSettings._Contributors": "Contributors", + "_.MouseWheelAction._Zoom": "Zoom in / out", + "_._CommandPreview": "معاينة الأمر", + "FrmSettings._DarkTheme": "Dark", + "_._Hotkeys": "Hotkeys", + "_.Metadata._ExifDateTime": "EXIF: DateTime", + "FrmSettings.Toolbar._Errors._ButtonIdRequired": "Button ID required.", + "FrmSettings._MinEmbeddedThumbnailSize._Width": "العرض", + "_._Executable": "Executable", + "_.ImageInterpolation._MultiSampleLinear": "Multi-sample linear", + "_._Separator": "فاصل", + "FrmQuickSetup._ProfessionalUser": "Professional user", + "FrmMain.MnuFlipVertical": "قلب عمودي", + "FrmSlideshow._ResumeSlideshow": "تم استئناف عرض الشرائح.", + "FrmCropSettings.DefaultSelectionType._CustomArea": "Custom area…", + "FrmMain.MnuActualSize": "الحجم الحقيقي", + "FrmCrop.BtnSaveAs": "حفظ باسم…", + "FrmSettings._InstallNewLanguagePack": "Install new language packs…", + "FrmSlideshow.MnuZoomModes": "Zoom modes", + "FrmMain.MnuTools": "الأدوات", + "_.ImageInterpolation._Cubic": "Cubic", + "FrmUpdate._LatestVersion": "The latest version: {0}", + "FrmMain.MnuViewNext": "عرض الصورة التالية", + "_.MouseWheelEvent._AltAndScroll": "Hold Alt and scroll", + "FrmToolNotFound._Title": "Tool not found", + "FrmCrop.BtnCrop._Tooltip": "Crop the image only", + "FrmSettings.EditAppDialog._AddApp": "Add an app for editing", + "FrmMain.MnuPanning": "Panning", + "_._MoveUp": "Move up", + "FrmCropSettings.DefaultSelectionType._SelectAll": "Select all", + "_._Name": "الاسم", + "FrmColorPickerSettings.ChkShowHslA": "Use HSL format with alpha value", + "FrmMain.MnuToggleImageAnimation": "Start / stop animating image", + "FrmSettings._DisableStartupBoost": "Disable Startup Boost", + "FrmMain.MnuCopyFile._Success": "Copied {0} file(s).", + "FrmMain.MnuSave._ConfirmDescription": "ImageGlass is not a professional photo editor, please be aware of losing the quality, metadata, layers,… when saving your image.", + "FrmToolNotFound.BtnSelectExecutable": "Select…", + "FrmUpdate._StatusOutdated": "A new update is available!", + "_.ImageOrderBy._Random": "عشوائي", + "FrmResize.LblCurrentSize": "Current Size:", + "_._Apply": "تطبيق", + "FrmAbout._Slogan": "عارض صور متنوع", + "FrmMain.MnuPanToTop": "Pan image to top", + "FrmSettings.Toolbar._AddNewButton": "Add a custom toolbar button", + "FrmCrop.LblSize": "Size:", + "FrmSettings._ImageInterpolation._ScaleDown": "When zoom < 100%", + "_._CreatingFileError": "Could not create temporary image file", + "FrmMain.MnuGoTo._Description": "Enter the image index to view, and then press ENTER", + "FrmSettings.Toolbar._EnableCenterToolbar": "Use center alignment for toolbar", + "FrmMain.MnuResizeTool": "Resize image", + "FrmSettings.Layout._Toolbar": "شريط الأدوات", + "FrmMain.MnuHelp": "مساعدة", + "_.ImageOrderBy._FileSize": "File size", + "FrmSettings._Theme._OpenThemeFolder": "فتح مجلد السمة", + "FrmMain.MnuNavigation": "التنقل", + "_._Save": "حفظ", + "FrmQuickSetup._SettingProfileDescription": "To modify these settings, simply access app settings.", + "_._UserAction._MenuNotFound": "Cannot find menu '{0}' to invoke the action", + "FrmMain.MnuPanToLeftSide": "Pan image to left edge", + "FrmUpdate._CurrentVersion": "Current version: {0}", + "FrmCrop.BtnSettings._Tooltip": "Open Crop tool settings", + "_.ColorProfileOption._Custom": "مخصص…", + "FrmSettings._UseEmbeddedThumbnailOtherFormats": "Load only the embedded thumbnail for other formats", + "FrmMain.MnuGoToFirst": "Go to first image", + "FrmSettings._ExportLanguagePack": "Export language pack…", + "FrmSettings.Nav._Mouse": "Mouse", + "_.ImageOrderBy._DateCreated": "Date created", + "FrmSettings._EnableFullscreenSlideshow": "Start slideshow in Full Screen mode", + "FrmAbout._Homepage": "Homepage:", + "FrmSettings._GalleryCacheSizeInMb": "Maximum gallery cache size (in megabytes)", + "FrmMain.MnuCopyImageData._Success": "Copied the current image data.", + "FrmSettings._EnableLoopBackNavigation": "Loop back to the first image when reaching the end of the image list", + "_.MouseWheelEvent._Scroll": "Scroll", + "FrmCrop.BtnSave._Tooltip": "حفظ الصورة", + "FrmMain.MnuSlideshow": "عرض شرائح", + "FrmMain.MnuShare": "مشاركة…", + "FrmSettings._SlideshowNotification": "Slideshow notification", + "FrmMain.MnuViewChannels": "عرض القنوات", + "FrmSettings._Refresh": "تحديث", + "_._UserAction._MethodNotFound": "Cannot find method '{0}' to invoke the action", + "FrmMain.MnuCopyFile": "Copy file", + "_._CreatingFile": "Creating a temporary image file…", + "FrmMain.MnuToggleTopMost": "إبقاء النافذة دائماً في الأعلى", + "FrmMain.MnuLosslessCompression._Confirm": "Are you sure you want to proceed?", + "FrmMain.MnuImage": "صورة", + "FrmSettings._StartupBoost._Enabled": "Startup Boost is enabled", + "FrmQuickSetup._SetDefaultViewer": "Do you want to set ImageGlass as the default photo viewer?", + "FrmMain.MnuScaleToWidth": "تكبير لملائمة عرض معين", + "_._FileExtension": "امتداد الملف", + "FrmUpdate._PublishedDate": "Published date: {0}", + "_._DoNotShowThisMessageAgain": "Do not show this message again", + "_.ImageInterpolation._NearestNeighbor": "Nearest neighbor", + "FrmCrop.LblLocation": "Location:", + "_._Download": "Download", + "_.Metadata._ColorProfile": "لون الملف الشخصي", + "FrmSettings._CenterWindowFit": "Automatically center the window in Window Fit mode", + "FrmSettings._ImageLoadingOrder": "طلب تحميل الصورة", + "FrmSettings._GalleryColumns": "Number of thumbnail columns in vertical gallery layout", + "_._Quit": "Quit", + "_._Add": "اضافة", + "FrmMain.MnuChangeBackgroundColor": "Change background color…", + "FrmMain.MnuToggleToolbar": "شريط الأدوات", + "FrmAbout._Contact": "معلومات الاتصال", + "FrmSettings.Toolbar._AddCustomButton": "Add a custom button…", + "FrmCrop.BtnQuickSelect._Tooltip": "Quick select…", + "FrmMain.MnuCutFile._Success": "Cut {0} file(s).", + "FrmSettings._ZoomSpeed": "Zoom speed", + "FrmMain.MnuToggleTopMost._Disable": "Disabled window always on top", + "FrmSettings._ShouldUseExplorerSortOrder": "Use Explorer sort order if possible", + "_.ImageInterpolation._Antisotropic": "Antisotropic", + "FrmMain._ReachedFirstImage": "وصلت إلى أول صورة", + "_._UnhandledException": "Unhandled exception", + "FrmResize.LblNewSize": "New Size:", + "FrmMain._ClipboardImage": "Clipboard image", + "FrmMain.MnuExportFrames": "Export image frames…", + "FrmMain.MnuFile": "ملف", + "_._Close": "أغلق", + "FrmMain.MnuMain": "القائمة الرئيسية", + "_._ResetToDefault": "إعادة التعيين إلى الافتراضي", + "FrmSettings.Nav._Gallery": "Gallery", + "FrmMain.MnuSetDefaultPhotoViewer._Success": "You have successfully set ImageGlass as default photo viewer.", + "FrmSettings._HideGalleryInFullscreen": "Hide gallery in Full Screen mode", + "FrmSettings._AvailableImageInfoTags": "Available tags:", + "FrmExportFrames._Exporting": "Exporting {0}/{1} frames \r\n{2}…", + "_._Argument": "Argument", + "FrmSettings._ImageEditQuality": "جودة الصورة", + "_._ID": "ID", + "FrmSettings._UserConfigFile": "User settings file (igconfig.json)", + "FrmMain.MnuLoadingOrders": "Loading orders", + "FrmSettings._OpenSaveAsDialogInTheCurrentImageDir": "Open the Save As dialog in the current image directory", + "_.MouseWheelEvent._ShiftAndScroll": "Hold Shift and scroll", + "FrmSettings._UseSmoothZooming": "Use smooth zooming", + "FrmSettings._Theme": "السمة", + "FrmSettings._ImageBoosterCacheMaxDimension": "Maximum image dimension to be cached (in pixels)", + "FrmMain.MnuScaleToHeight": "تكبير لملائمة طول معين", + "_.Metadata._FileLastWriteTime": "Date modified", + "FrmSettings._Author": "المؤلف", + "FrmSettings._Others": "أخرى", + "_.MouseWheelAction._PanVertically": "Pan up / down", + "FrmSettings._MouseWheelAction": "Mouse wheel action", + "FrmSettings.Nav._Tools": "الأدوات", + "FrmMain.MnuSetDesktopBackground._Error": "Could not set the viewing image as desktop background", + "FrmSettings.Toolbar._Errors._ButtonExecutableRequired": "Button executable required.", + "_.ImageOrderBy._DateAccessed": "Date accessed", + "FrmSettings._ThumbnailSize": "Thumbnail size (in pixels)", + "FrmSettings._FileFormats": "File formats", + "FrmMain.MnuReloadImageList": "إعادة تحميل قائمة الصور", + "FrmSettings._UseWebview2ForSvg": "Use Webview2 for viewing SVG format", + "FrmCrop.BtnCopy": "نسخ", + "FrmSettings._CurrentMonitorProfile._Description": "ImageGlass does not auto-update the color when moving its window between monitors", + "FrmMain.PicMain._ErrorText": "Could not open this image", + "FrmSettings.Tools._AddNewTool": "Add an external tool", + "FrmMain.MnuRename": "إعادة تسمية الصورة…", + "FrmMain.MnuViewLastFrame": "View last frame", + "_._Webview2._NotFound": "Please install WebView2 Runtime to access full features of ImageGlass.", + "FrmMain.MnuGetMoreTools": "Get more tools…", + "FrmSettings.Nav._Appearance": "Appearance", + "FrmSettings._SlideshowInterval": "الفاصل الزمني لعرض الشرائح:", + "_.ImageInterpolation._HighQualityBicubic": "High quality bicubic", + "FrmColorPickerSettings.ChkShowHsvA": "Use HSV format with alpha value", + "FrmSettings.Tools._EditTool": "Edit external tool", + "_._Error": "Error", + "FrmSettings._ImageBoosterCacheMaxFileSizeInMb": "Maximum image file size to be cached (in megabytes)", + "_._UnhandledException._Description": "Unhandled exception has occurred. If you click Continue, the application will ignore this error and attempt to continue. If you click Quit, the application will close immediately.", + "_.Metadata._FileSize": "File size", + "FrmSettings.Toolbar._ButtonJson": "Button JSON", + "FrmQuickSetup._SetDefaultViewer._Description": "You can reset it in the app settings > File type associations tab.", + "FrmSettings.Nav._Edit": "تحرير", + "FrmMain.MnuToggleGallery": "Gallery panel", + "_._IgCommandExe._DefaultError._Description": "Make sure you pass the correct commands!\r\nThis executable file contains command-line functions for ImageGlass software.\r\n\r\nTo explore all command lines, please visit:\r\n{0}", + "FrmMain.MnuLosslessCompression._Compressing": "Performing lossless compression…", + "FrmSettings._ShouldGroupImagesByDirectory": "تجميع الصور حسب اماكن الملفات", + "FrmMain.MnuPanToRightSide": "Pan image to right edge", + "_.Metadata._ExifRatingPercent": "Rating", + "FrmSettings._PanSpeed": "Panning speed", + "_._CheckForUpdate": "التحقق من التحديثات…", + "FrmSettings.Layout._ToolbarContext": "Contextual toolbar", + "_.ImageInfo._FrameCount": "{0} frame(s)", + "FrmMain.MnuLayout": "تخطيط", + "_._Website": "الموقع", + "FrmMain.MnuPasteImage": "Paste image", + "FrmSettings._ShowGalleryScrollbars": "Show gallery scrollbars" + } +} \ No newline at end of file diff --git a/Setup/Assets/Language/Armenian.iglang.json b/Setup/Assets/Language/Armenian.iglang.json new file mode 100644 index 000000000..583940564 --- /dev/null +++ b/Setup/Assets/Language/Armenian.iglang.json @@ -0,0 +1,504 @@ +{ + "_Metadata": { + "Code": "hy-AM", + "EnglishName": "Armenian", + "LocalName": "Հայերեն", + "Author": "Hrach Mkrtchyan", + "MinVersion": "9.3" + }, + "Items": { + "FrmCrop.SelectionAspectRatio._Original": "Original", + "FrmMain.MnuShare._Error": "Could not open Share dialog.", + "_.Metadata._FileLastAccessTime": "Date accessed", + "FrmAbout._License": "Software license", + "FrmSettings.Toolbar._Errors._ButtonIdDuplicated": "A button with the ID '{0}' has already been defined. Please choose a different and unique ID for your button to avoid conflicts.", + "FrmMain.MnuSave._Confirm": "Are you sure you want to override this image?", + "FrmSettings._OpenDefaultAppsSetting": "Open Default apps setting", + "FrmMain.MnuCopyPath": "Պատճենել պատկերի գտնվելու ուղին", + "FrmCropSettings.DefaultSelectionType._SelectNone": "Select none", + "_.MouseWheelAction._PanHorizontally": "Pan left / right", + "FrmMain.MnuPrint": "Տպել…", + "FrmSettings.Toolbar._ToolbarButtons": "Toolbar buttons", + "FrmResize.LblResample": "Resample:", + "_.ImageOrderBy._Extension": "Կցորդ", + "FrmSettings.Nav._Viewer": "Դիտման պատուհան", + "FrmSettings.EditAppDialog._EditApp": "Edit app", + "FrmCrop.BtnReset._Tooltip": "Reset selection", + "FrmMain.MnuRename._Description": "Enter a new filename:", + "_._No": "No", + "FrmSlideshow.MnuToggleCountdown": "Սլայդերի ցուցադրման հետհաշվարկ", + "FrmSettings._OpenStartupAppsSetting": "Open Startup apps setting", + "FrmMain.MnuViewPreviousFrame": "View previous frame", + "_.ImageOrderBy._DateModified": "Date modified", + "FrmMain.MnuViewNextFrame": "View next frame", + "FrmMain.MnuUnload": "Unload image", + "FrmSettings.Toolbar._HideToolbarInFullscreen": "Hide toolbar in Full Screen mode", + "_.ImageOrderType._Desc": "Նվազման կարգով", + "_._Update": "Update", + "FrmSettings._EnableImageAsyncLoading": "Enable image asynchronous loading", + "FrmSettings._DefaultPhotoViewer._Description": "Register the supported formats of ImageGlass with Windows. You might need to open the Default apps settings and manually select ImageGlass from the list for it to take effect.", + "_.MouseWheelAction._BrowseImages": "View next / previous Image", + "FrmSettings._EditApps": "Image editing apps", + "FrmColorPickerSettings.ChkShowCIELabA": "Use CIELAB format with alpha value", + "_._GetHelp": "Ստանալ օգնություն", + "FrmQuickSetup._SkipQuickSetup": "Skip this and launch ImageGlass", + "FrmColorPickerSettings._Title": "Color picker settings", + "_._Copy": "Պատճենել", + "FrmSettings._ImageBoosterCacheCount": "Number of images cached by Image Booster (one direction)", + "FrmMain.MnuPanToBottom": "Pan image to bottom", + "FrmMain.MnuZoom": "Մասշտաբ", + "FrmCropSettings.ChkCloseToolAfterSaving": "Close Crop tool after saving", + "FrmSettings._ShowWelcomeImage": "Show welcome image", + "FrmSettings._ColorProfile": "Color profile", + "FrmSettings._Theme._UninstallTheme": "Uninstall a theme pack", + "FrmMain._OpenWith": "Open with {0}", + "FrmMain.MnuRemoveDefaultPhotoViewer": "Remove default photo viewer", + "_.AfterEditAppAction._Nothing": "Ոչինչ", + "FrmCrop.BtnSave": "Պահպանել", + "FrmMain.MnuScaleToFit": "Համապատասխանեցնել չափսը", + "FrmToolNotFound.LblDownloadToolText": "You can download more tools for ImageGlass at:", + "_._LearnMore": "Իմանալ ավելին…", + "FrmCrop.LblAspectRatio": "Aspect ratio:", + "FrmExportFrames._FileNotExist": "Image file does not exist", + "FrmSettings._LightTheme": "Light", + "FrmSettings.Nav._Slideshow": "Սլայդերի ցուցադրում", + "_._Continue": "Շարունակել", + "_._AddHotkey": "Add hotkey…", + "FrmMain.MnuSetDesktopBackground": "Տեղադրել որպես աշխատասեղանի պատկեր", + "FrmMain.MnuReload": "Վերաբեռնել պատկերը", + "FrmSlideshow.MnuExitSlideshow": "Դադարեցնել սլայդերի ցուցադրումը", + "FrmMain.MnuAutoZoom": "Մոտեցնել ինքնաշխատորեն", + "FrmSettings._ShowImagePreview": "Display image preview while it's being loaded", + "FrmCrop.BtnCopy._Tooltip": "Copy the selection to clipboard", + "FrmSettings.Nav._Toolbar": "Գործիքների վահանակ", + "FrmMain.MnuSave._Error": "Could not save the image", + "FrmSettings._AfterEditingAction": "After opening editing app", + "FrmSettings._ShouldUseColorProfileForAll": "Կիրառել նաև ներառված գունային պրոֆիլ չունեցող պատկերների դեպքում", + "FrmCropSettings.DefaultSelectionType._UseTheLastSelection": "Use the last selection", + "FrmSettings._SlideshowInterval._From": "From", + "FrmSettings._ImageInterpolation": "Image interpolation", + "FrmQuickSetup._StepInfo": "Քայլ {0}", + "FrmMain.MnuColorPicker": "Գույնի ընտրիչ", + "FrmCrop.SelectionAspectRatio._FreeRatio": "Free ratio", + "FrmSettings._ResetSettings": "Reset settings", + "FrmSettings._Startup": "Startup", + "_.BackdropStyle._None": "Բացակայում է", + "FrmSettings._LoadDefaultZoomLevels": "Load default zoom levels", + "FrmColorPicker.BtnSettings._Tooltip": "Open Color picker settings…", + "FrmSettings._UseThemeForDarkMode": "Use this theme for dark mode", + "FrmSettings._ShowDeleteConfirmation": "Show confirmation dialog when deleting file", + "FrmSettings._ShowAppIcon": "Show app icon on the title bar", + "_._InvalidAction": "Invalid action", + "FrmQuickSetup._SelectProfile": "Select a profile", + "_.Metadata._FileCreationTime": "Ստեղծման ամսաթիվը", + "FrmSettings._SlideshowImagesToNotifySound": "Number of images to trigger a notification sound", + "FrmSettings._BackgroundColor": "Viewer background color", + "FrmSettings._RealTimeFileUpdate": "Real-time file update", + "_.ColorProfileOption._CurrentMonitorProfile": "Current monitor profile", + "FrmSettings._EnableCutMultipleFiles": "Enable the cutting of multiple files at once", + "FrmSettings._AutoUpdate": "Ավտոմատ ստուգել թարմացումները", + "FrmCropSettings.LblDefaultSelection": "Default selection", + "FrmSettings._UseThemeForLightMode": "Use this theme for light mode", + "FrmSettings._ZoomLevels": "Մոտեցման աստիճաններ", + "FrmMain.MnuSetLockScreen._Success": "Lock screen image is updated", + "FrmSettings._ShowGalleryFileName": "Show thumbnail filename", + "FrmSettings.Layout._Order": "Order", + "FrmCropSettings.ChkAutoCenterSelection": "Auto-center selection", + "FrmSettings.Nav._FileTypeAssociations": "File type associations", + "_._Back": "Ետ", + "FrmMain.MnuSetDesktopBackground._Success": "Desktop background is updated", + "FrmSettings._ShouldAutoOpenNewAddedImage": "Open the new added image automatically", + "FrmCrop.SelectionAspectRatio._Custom": "Անհատական…", + "FrmMain.MnuCopyPath._Success": "Copied the current image path.", + "FrmSettings._StartupBoost._Error": "Could not change Startup Boost setting", + "FrmToolNotFound.LblDescription": "ImageGlass was unable to locate the path to the '{0}' executable. To resolve this issue, please update the path to the '{0}' as necessary.", + "FrmMain.MnuClearClipboard": "Դատարկել ժամանակավոր հիշողությունը", + "FrmSettings._ColorManagement": "Գունային կարգավորումներ", + "FrmMain._ReachedLastLast": "Հասել ենք վերջին պատկերին", + "FrmMain.MnuPanUp": "Pan image up", + "FrmMain.MnuRemoveDefaultPhotoViewer._Success": "ImageGlass is no longer the default photo viewer.", + "FrmSettings._GetMoreLanguagePacks": "Ավելացնել նոր լեզվային փաթեթներ…", + "FrmAbout._Privacy": "Privacy policy", + "FrmSettings._EnableRecursiveLoading": "Load images in subfolders", + "_._UserAction._MethodArgumentNotSupported": "The argument type of method '{0}' is not supported", + "FrmSettings._FileExtensionIcons._Description": "For customizing file extension icons, download an icon pack, place all .ICO files in the extension icon folder, and click the '{0}' button. This will also set ImageGlass as default photo viewer.", + "_.ImageOrderType._Asc": "Աճման կարգով", + "FrmExportFrames._Title": "Export image frames", + "_._Install": "Տեղադրել…", + "FrmMain.MnuFlipHorizontal": "Պտտել հորիզոնապես", + "FrmSettings._OpenExtensionIconFolder": "Open extension icon folder", + "FrmAbout._Collaborator": "Collaborator:", + "FrmQuickSetup._ConfirmCloseProcess": "Before applying the new settings, it's essential to close all ImageGlass processes. Are you ready to proceed?", + "FrmExportFrames._ExportDone": "Exported {0} frames successfully to \r\n{1}", + "FrmCrop.BtnSaveAs._Tooltip": "Save as a copy…", + "FrmMain.MnuOpenFile": "Բացել նիշքը…", + "FrmColorPickerSettings.ChkShowRgbA": "Use RGB format with alpha value", + "_.ImageInfo._ListCount": "{0} file(s)", + "FrmMain.MnuGoToLast": "Go to last image", + "FrmSettings._EditApps._AppName": "Հավելվածի անվանումը", + "FrmSettings._SlideshowBackgroundColor": "Slideshow background color", + "FrmAbout._Email": "Էլ. հասցե:", + "_.MouseWheelAction._DoNothing": "Ոչինչ չանել", + "FrmMain.MnuSaveAs": "Պահպանել որպես…", + "FrmMain._Loading": "Բեռնվում է…", + "_._Browse": "Դիտարկել…", + "FrmMain.MnuSetDefaultPhotoViewer._Error": "Could not set ImageGlass as default photo viewer.", + "FrmSettings.Nav._Language": "Լեզու", + "FrmQuickSetup._SeeWhatNew": "See what's new in this version…", + "FrmSettings._ImageInterpolation._ScaleUp": "When zoom > 100%", + "FrmSettings.Layout._ToolbarContextPosition": "Contextual toolbar position", + "FrmMain.MnuDeleteFromHardDisk": "Delete permanently", + "FrmSettings._EmbeddedThumbnail": "Embedded thumbnail", + "FrmMain.MnuDeleteFromHardDisk._Description": "Are you sure you want to permanently delete this file?", + "FrmMain.MnuScaleToFill": "Խոշորացնելով համապատասխանեցնել", + "FrmCrop.BtnCrop": "Crop", + "_.AfterEditAppAction._Minimize": "Փոքրացնել", + "FrmMain.MnuInvertColors": "Invert colors", + "FrmSettings._StartupBoost": "Startup Boost", + "FrmMain.MnuViewFirstFrame": "View first frame", + "_.MouseWheelEvent._CtrlAndScroll": "Hold Ctrl and scroll", + "FrmSettings._HideMainWindowInSlideshow": "Automatically hide main window", + "_.Metadata._FrameCount": "Frames", + "FrmSettings._EnableCopyMultipleFiles": "Enable the copying of multiple files at once", + "FrmMain.MnuFrameless._EnableDescription": "Hold Shift key to move the window.", + "_.ImageOrderBy._ExifDateTaken": "EXIF: Date taken", + "FrmAbout._Credits": "Credits", + "FrmSettings._AddNewFileExtension": "Add new file extension", + "FrmMain.MnuQuickSetup": "Open ImageGlass Quick Setup", + "FrmMain.MnuSave._Success": "Image is saved", + "FrmMain.MnuPanLeft": "Pan image left", + "FrmUpdate._StatusChecking": "Checking for update…", + "FrmSettings.Nav._Layout": "Դասավորություն", + "FrmMain.MnuOpenWith": "Բացել հետևյալով…", + "FrmAbout._Thanks": "Special thanks to", + "_._Warning": "Ուշադրություն", + "FrmSettings.Nav._Keyboard": "Ստեղնաշար", + "FrmSlideshow._PauseSlideshow": "Սլայդերի ցուցադրումը ընդմիջված է.", + "_._Add+": "Ավելացնել…", + "_._Email": "Էլ. հասցե", + "FrmMain.MnuPanDown": "Pan image down", + "_._Cancel": "Չեղարկել", + "_._OK": "Լավ", + "FrmMain.MnuPanRight": "Pan image right", + "_.Position._Right": "Աջ", + "_._Icon": "Պատկերակ", + "FrmSettings._ShouldLoadHiddenImages": "Load hidden images", + "_._InvalidAction._Transformation": "ImageGlass does not support rotation, flipping for this image.", + "FrmSettings._MakeDefault": "Դարձնել լռելյայն", + "FrmMain.MnuCopyImageData._Copying": "Copying the image data. It's going to take a while…", + "FrmSettings._UseEmbeddedThumbnailRawFormats": "Load only the embedded thumbnail for RAW formats", + "_.ImageInterpolation._Linear": "Linear", + "FrmSettings._ImageInfoTags": "Image information tags", + "FrmSettings._FileExtensionIcons": "File extension icons", + "FrmMain.MnuEdit._AppNotFound": "Could not find the associated app for editing. You can assign an app for editing this format in ImageGlass Settings > Edit.", + "_.ColorProfileOption._None": "Բացակայում է", + "FrmSettings._TotalSupportedFormats": "Total supported formats: {0}", + "FrmSettings._Clipboard": "Ժամանակավոր հիշողություն", + "_._UserAction._Win32ExeError": "Cannot execute command '{0}'. Make sure the name is correct.", + "FrmCropSettings.DefaultSelectionType._SelectX": "Select {0}", + "_.AfterEditAppAction._Close": "Փակել", + "FrmAbout._LogoDesigner": "Logo designer:", + "_.ImageOrderBy._Name": "Անուն (լռելյայն)", + "FrmMain.MnuRemoveDefaultPhotoViewer._Error": "Could not remove ImageGlass as the default photo viewer.", + "FrmExportFrames._FolderPickerTitle": "Select output folder for exporting image frames", + "FrmAbout._Donate": "Նվիրաբերել", + "FrmMain.MnuFrameNav": "Frame navigation", + "FrmMain.MnuSetLockScreen": "Տեղադրել որպես կողպված էկրանի պատկեր", + "_._Delete": "Ջնջել", + "FrmMain.MnuViewPrevious": "Դիտել նախորդ պատկերը", + "_.Position._Top": "Վերև", + "FrmSettings.Toolbar._CurrentButtons": "Current buttons:", + "FrmMain.MnuAbout": "Ծրագրի մասին", + "FrmSettings._RemoveDefault": "Հեռացնել լռելյայնը", + "_._Description": "Նկարագրություն", + "FrmMain.MnuPasteImage._Error": "Could not find image data in the Clipboard", + "FrmMain.MnuSettings": "Կարգավորումներ", + "FrmCropSettings._Title": "Crop settings", + "FrmSettings.Toolbar._ToolbarIconHeight": "Toolbar icon size", + "FrmSettings._SlideshowInterval._To": "To", + "FrmSettings.Layout._ToolbarPosition": "Toolbar position", + "FrmUpdate._StatusUpdated": "You are using the latest version!", + "FrmMain.MnuExit": "Ելք", + "_._Webview2._Outdated": "Your WebView2 Runtime is not supported. Please update to version {0} or later.", + "_._Yes": "Այո", + "FrmMain.MnuRotateLeft": "Շրջել ձախ", + "FrmSettings._EnableStartupBoost": "Enable Startup Boost", + "_.ImageOrderBy._ExifRating": "EXIF: Rating", + "FrmMain.MnuZoomIn": "Մոտեցնել", + "_.Metadata._ColorSpace": "Color space", + "FrmAbout._Version": "Տարբերակ:", + "FrmMain.MnuToggleTopMost._Enable": "Enabled window always on top", + "FrmSettings.Toolbar._AvailableButtons": "Available buttons:", + "FrmMain.MnuSave._Saving": "Saving image…", + "FrmQuickSetup._StandardUser": "Standard user", + "FrmMain.MnuSetLockScreen._Error": "Could not set the viewing image as lock screen image", + "FrmSettings.Nav._Image": "Պատկեր", + "FrmSettings._Theme._InstallTheme": "Install theme packs", + "FrmSettings._EnableMultiInstances": "Թույլատրել հավելվածի մի քանի տարբերակ", + "FrmMain.MnuCropTool": "Crop image", + "_._IgCommandExe._DefaultError._Heading": "Invalid commands", + "_._Refresh": "Թարմացնել", + "FrmMain.MnuLosslessCompression._Description": "This tool uses Magick.NET library for lossless compression, optimizing file size. Overwrites only if the compressed file is smaller than the original.", + "_._MoveDown": "Իջեցնել", + "FrmSettings._GetExtensionIconPacks": "Get extension icon packs…", + "FrmSettings._InAppMessageDuration": "In-app message duration (milliseconds)", + "FrmMain.MnuFrameless": "Առանց շրջանակ", + "_._Reset": "Զրոյացնել", + "FrmSettings._ConfigDir": "Configuration location", + "FrmQuickSetup._SettingsWillBeApplied": "Settings will be applied:", + "FrmSettings._UnmanagedSettingReminder": "This setting is not managed by ImageGlass. Don't forget to disable it before you remove or relocate the app because ImageGlass does not handle this automatically.", + "FrmMain.MnuClipboard": "Ժամանակավոր հիշողություն", + "FrmMain.MnuCustomZoom": "Անհատական մասշտաբ…", + "FrmSettings._DisplayLanguage": "Display language", + "FrmMain.MnuPrint._Error": "Could not print the viewing image", + "FrmSettings._ShouldPreserveModifiedDate": "Պահել պատկերի խմբագրման ամսաթիվը՝ պատկերի պահպանման ընթացքում", + "FrmSettings._ShowSaveOverrideConfirmation": "Show confirmation dialog when overriding file", + "FrmColorPickerSettings.ChkShowHexA": "Use HEX format with alpha value", + "FrmMain.MnuFullScreen": "Full Screen", + "FrmSettings._StartupDir": "Startup location", + "FrmSettings._ShowCheckerboardOnlyImageRegion": "Show checkerboard only within the image region", + "FrmMain.MnuClearClipboard._Success": "Cleared clipboard.", + "FrmQuickSetup._Text": "ImageGlass Quick Setup", + "FrmMain.MnuLosslessCompression._Done": "Done lossless compression.\r\nThe new file size is {0}, saved {1}.", + "FrmMain.MnuLosslessCompression": "Magick.NET Lossless Compression", + "FrmResize.RadResizeByPercentage": "Percentage", + "FrmSettings._StartupBoost._Disabled": "Startup Boost is disabled", + "FrmMain.MnuToggleCheckerboard": "Ֆոն (լիարժեք / թափանցիկ)", + "FrmSettings._MinEmbeddedThumbnailSize._Height": "Բարձրություն", + "FrmSettings.Nav._General": "Գլխավոր", + "FrmSettings._ImageLoading": "Պատկերի բեռնում", + "FrmSettings._ShowSlideshowCountdown": "Սլայդերի ցուցադրման հետհաշվարկ", + "FrmMain.MnuSave": "Պահպանել", + "FrmMain.MnuMoveToRecycleBin": "Move to the Recycle Bin", + "FrmMain.MnuRefresh": "Թարմացնել", + "FrmToolNotFound.LblHeading": "'{0}' is not found!", + "FrmMain.MnuReportIssue": "Տեղեկացնել խնդրի մասին…", + "FrmMain.MnuCopyImageData": "Պատճենել պատկերի տվյալները", + "FrmMain.MnuCheckForUpdate._NewVersion": "Հասանելի է՜ նոր թարմացում։", + "_._Empty": "(դատարկ)", + "FrmSettings._Zooming": "Մոտեցնել", + "FrmMain.MnuCutFile": "Cut file", + "FrmHotkeyPicker.LblHotkey": "Press hotkeys", + "FrmSettings.Layout._Gallery": "Պատկերասրահ", + "FrmMain.MnuNewWindow": "Բացել նոր պատուհան", + "FrmMain.MnuMoveToRecycleBin._Description": "Do you want to move this file to the Recycle bin?", + "FrmSettings._DefaultPhotoViewer": "Default photo viewer", + "_.Metadata._ExifDateTimeOriginal": "EXIF: DateTimeOriginal", + "FrmMain.MnuRotateRight": "Շրջել աջ", + "FrmSettings._MinEmbeddedThumbnailSize": "Minimum size of the embedded thumbnail to be loaded", + "FrmMain.MnuSetDefaultPhotoViewer": "Set default photo viewer", + "FrmMain.MnuImageProperties": "Պատկերի կարգավորումներ", + "FrmSettings._EnableNavigationButtons": "Show navigation arrow buttons", + "_._Edit": "Խմբագրել", + "FrmSettings._ImageBooster": "Image Booster", + "FrmSettings.Tools._IntegratedWith": "Integrated with {0}", + "_._Next": "Հաջորդը", + "FrmExportFrames._OpenOutputFolder": "Open output folder", + "FrmMain.MnuOpenLocation": "Բացել պատկերի գտնվելու վայրը", + "FrmMain.MnuLockZoom": "Ֆիքսել խոշորացման մակարդակը", + "FrmSettings._StartupBoost._Description": "Preload and run ImageGlass in the background for a few seconds during Windows startup to accelerate the first launch.", + "FrmSettings._WindowBackdrop": "Window backdrop", + "FrmSettings._EnableRealTimeFileUpdate": "Monitor file changes in the viewing folder and update in realtime", + "_._NotSupported": "Unsupported format", + "FrmSettings._Theme._GetMoreThemes": "Get more theme packs…", + "FrmMain.MnuNewWindow._Error": "Cannot open new window because only one instance is allowed", + "FrmMain.MnuZoomOut": "Հեռացնել", + "FrmSettings.Toolbar._EditButton": "Edit toolbar button", + "FrmMain.MnuCustomZoom._Description": "Գրեք մասշտաբի նոր արժեքը", + "FrmResize.RadResizeByPixels": "Pixels", + "FrmMain.MnuEdit": "Խմբագրել պատկերը {0}…", + "FrmSettings.Layout._GalleryPosition": "Gallery position", + "FrmMain.MnuWindowFit": "Window Fit", + "FrmMain._OpenFileDialog": "Բոլոր սպասարկվող նիշքերը", + "FrmSettings._UseRandomIntervalForSlideshow": "Կիրառել կամայական ժամանակահատված", + "_.Position._Left": "Ձախ", + "FrmSettings._ShouldOpenLastSeenImage": "Open the last seen image", + "_.Position._Bottom": "Ներքև", + "FrmResize.ChkKeepRatio": "Keep ratio propotional", + "FrmMain.MnuGoTo": "Անցնել…", + "FrmSlideshow.MnuPauseResumeSlideshow": "Pause/resume slideshow", + "FrmSettings.Tools._Integrated": "Integrated", + "FrmSettings._Contributors": "Contributors", + "_.MouseWheelAction._Zoom": "Zoom in / out", + "_._CommandPreview": "Command preview", + "FrmSettings._DarkTheme": "Dark", + "_._Hotkeys": "Դյուրանցումներ", + "_.Metadata._ExifDateTime": "EXIF: DateTime", + "FrmSettings.Toolbar._Errors._ButtonIdRequired": "Button ID required.", + "FrmSettings._MinEmbeddedThumbnailSize._Width": "Լայնություն", + "_._Executable": "Executable", + "_.ImageInterpolation._MultiSampleLinear": "Multi-sample linear", + "_._Separator": "Բաժանարար", + "FrmQuickSetup._ProfessionalUser": "Professional user", + "FrmMain.MnuFlipVertical": "Պտտել ուղղահայաց", + "FrmSlideshow._ResumeSlideshow": "Սլայդերի ցուցադրումը շարունակվում է.", + "FrmCropSettings.DefaultSelectionType._CustomArea": "Custom area…", + "FrmMain.MnuActualSize": "Իրական չափս", + "FrmCrop.BtnSaveAs": "Պահպանել որպես…", + "FrmSettings._InstallNewLanguagePack": "Install new language packs…", + "FrmSlideshow.MnuZoomModes": "Zoom modes", + "FrmMain.MnuTools": "Գործիքներ", + "_.ImageInterpolation._Cubic": "Cubic", + "FrmUpdate._LatestVersion": "The latest version: {0}", + "FrmMain.MnuViewNext": "Դիտել հաջորդ պատկերը", + "_.MouseWheelEvent._AltAndScroll": "Hold Alt and scroll", + "FrmToolNotFound._Title": "Tool not found", + "FrmCrop.BtnCrop._Tooltip": "Crop the image only", + "FrmSettings.EditAppDialog._AddApp": "Add an app for editing", + "FrmMain.MnuPanning": "Համայնապատկեր (նկարի պտտման արագություն՝ պիքսելների քանակը կոճակի մեկ սեղմումով)", + "_._MoveUp": "Բարձրացնել", + "FrmCropSettings.DefaultSelectionType._SelectAll": "Select all", + "_._Name": "Անվանում", + "FrmColorPickerSettings.ChkShowHslA": "Use HSL format with alpha value", + "FrmMain.MnuToggleImageAnimation": "Start / stop animating image", + "FrmSettings._DisableStartupBoost": "Disable Startup Boost", + "FrmMain.MnuCopyFile._Success": "Copied {0} file(s).", + "FrmMain.MnuSave._ConfirmDescription": "ImageGlass is not a professional photo editor, please be aware of losing the quality, metadata, layers,… when saving your image.", + "FrmToolNotFound.BtnSelectExecutable": "Select…", + "FrmUpdate._StatusOutdated": "A new update is available!", + "_.ImageOrderBy._Random": "Պատահական", + "FrmResize.LblCurrentSize": "Current Size:", + "_._Apply": "Կիրառել", + "FrmAbout._Slogan": "Պատկեր դիտելու թեթև, ճկուն հավելված", + "FrmMain.MnuPanToTop": "Pan image to top", + "FrmSettings.Toolbar._AddNewButton": "Add a custom toolbar button", + "FrmCrop.LblSize": "Size:", + "FrmSettings._ImageInterpolation._ScaleDown": "When zoom < 100%", + "_._CreatingFileError": "Could not create temporary image file", + "FrmMain.MnuGoTo._Description": "Enter the image index to view, and then press ENTER", + "FrmSettings.Toolbar._EnableCenterToolbar": "Use center alignment for toolbar", + "FrmMain.MnuResizeTool": "Resize image", + "FrmSettings.Layout._Toolbar": "Գործիքների վահանակ", + "FrmMain.MnuHelp": "Օգնություն", + "_.ImageOrderBy._FileSize": "Ֆայլի չափը", + "FrmSettings._Theme._OpenThemeFolder": "Բացել ոճերի պանակը", + "FrmMain.MnuNavigation": "Նավիգացիա", + "_._Save": "Պահպանել", + "FrmQuickSetup._SettingProfileDescription": "To modify these settings, simply access app settings.", + "_._UserAction._MenuNotFound": "Cannot find menu '{0}' to invoke the action", + "FrmMain.MnuPanToLeftSide": "Pan image to left edge", + "FrmUpdate._CurrentVersion": "Current version: {0}", + "FrmCrop.BtnSettings._Tooltip": "Open Crop tool settings", + "_.ColorProfileOption._Custom": "Անհատական…", + "FrmSettings._UseEmbeddedThumbnailOtherFormats": "Load only the embedded thumbnail for other formats", + "FrmMain.MnuGoToFirst": "Go to first image", + "FrmSettings._ExportLanguagePack": "Export language pack…", + "FrmSettings.Nav._Mouse": "Մկնիկ", + "_.ImageOrderBy._DateCreated": "Ստեղծման ամսաթիվը", + "FrmSettings._EnableFullscreenSlideshow": "Start slideshow in Full Screen mode", + "FrmAbout._Homepage": "Homepage:", + "FrmSettings._GalleryCacheSizeInMb": "Maximum gallery cache size (in megabytes)", + "FrmMain.MnuCopyImageData._Success": "Copied the current image data.", + "FrmSettings._EnableLoopBackNavigation": "Loop back to the first image when reaching the end of the image list", + "_.MouseWheelEvent._Scroll": "Scroll", + "FrmCrop.BtnSave._Tooltip": "Պահպանել պատկերը", + "FrmMain.MnuSlideshow": "Սլայդերի ցուցադրում", + "FrmMain.MnuShare": "Կիսվել…", + "FrmSettings._SlideshowNotification": "Slideshow notification", + "FrmMain.MnuViewChannels": "Դիտել ալիքները", + "FrmSettings._Refresh": "Թարմացնել", + "_._UserAction._MethodNotFound": "Cannot find method '{0}' to invoke the action", + "FrmMain.MnuCopyFile": "Copy file", + "_._CreatingFile": "Creating a temporary image file…", + "FrmMain.MnuToggleTopMost": "Միշտ ցուցադրել այլ պատուհանների առջևից", + "FrmMain.MnuLosslessCompression._Confirm": "Are you sure you want to proceed?", + "FrmMain.MnuImage": "Պատկեր", + "FrmSettings._StartupBoost._Enabled": "Startup Boost is enabled", + "FrmQuickSetup._SetDefaultViewer": "Do you want to set ImageGlass as the default photo viewer?", + "FrmMain.MnuScaleToWidth": "Համապատասխանեցնել լայնությամբ", + "_._FileExtension": "Նիշքի տիպը", + "FrmUpdate._PublishedDate": "Published date: {0}", + "_._DoNotShowThisMessageAgain": "Do not show this message again", + "_.ImageInterpolation._NearestNeighbor": "Nearest neighbor", + "FrmCrop.LblLocation": "Location:", + "_._Download": "Ներբեռնել", + "_.Metadata._ColorProfile": "Color profile", + "FrmSettings._CenterWindowFit": "Automatically center the window in Window Fit mode", + "FrmSettings._ImageLoadingOrder": "Պատկերների բեռնման հերթականություն", + "FrmSettings._GalleryColumns": "Number of thumbnail columns in vertical gallery layout", + "_._Quit": "Ելք", + "_._Add": "Ավելացնել", + "FrmMain.MnuChangeBackgroundColor": "Change background color…", + "FrmMain.MnuToggleToolbar": "Գործիքների վահանակ", + "FrmAbout._Contact": "Հետադարձ կապ", + "FrmSettings.Toolbar._AddCustomButton": "Add a custom button…", + "FrmCrop.BtnQuickSelect._Tooltip": "Quick select…", + "FrmMain.MnuCutFile._Success": "Cut {0} file(s).", + "FrmSettings._ZoomSpeed": "Zoom speed", + "FrmMain.MnuToggleTopMost._Disable": "Disabled window always on top", + "FrmSettings._ShouldUseExplorerSortOrder": "Use Explorer sort order if possible", + "_.ImageInterpolation._Antisotropic": "Antisotropic", + "FrmMain._ReachedFirstImage": "Հասել ենք առաջին պատկերին", + "_._UnhandledException": "Unhandled exception", + "FrmResize.LblNewSize": "New Size:", + "FrmMain._ClipboardImage": "Clipboard image", + "FrmMain.MnuExportFrames": "Export image frames…", + "FrmMain.MnuFile": "Նիշք", + "_._Close": "Փակել", + "FrmMain.MnuMain": "Գլխավոր ցանկ", + "_._ResetToDefault": "Վերակագնել լռելյայնը", + "FrmSettings.Nav._Gallery": "Պատկերասրահ", + "FrmMain.MnuSetDefaultPhotoViewer._Success": "You have successfully set ImageGlass as default photo viewer.", + "FrmSettings._HideGalleryInFullscreen": "Hide gallery in Full Screen mode", + "FrmSettings._AvailableImageInfoTags": "Available tags:", + "FrmExportFrames._Exporting": "Exporting {0}/{1} frames \r\n{2}…", + "_._Argument": "Argument", + "FrmSettings._ImageEditQuality": "Image quality", + "_._ID": "ID", + "FrmSettings._UserConfigFile": "User settings file (igconfig.json)", + "FrmMain.MnuLoadingOrders": "Loading orders", + "FrmSettings._OpenSaveAsDialogInTheCurrentImageDir": "Open the Save As dialog in the current image directory", + "_.MouseWheelEvent._ShiftAndScroll": "Hold Shift and scroll", + "FrmSettings._UseSmoothZooming": "Use smooth zooming", + "FrmSettings._Theme": "Ոճ", + "FrmSettings._ImageBoosterCacheMaxDimension": "Maximum image dimension to be cached (in pixels)", + "FrmMain.MnuScaleToHeight": "Համապատասխանեցնել բարձրությամբ", + "_.Metadata._FileLastWriteTime": "Date modified", + "FrmSettings._Author": "Հեղինակ", + "FrmSettings._Others": "Այլ", + "_.MouseWheelAction._PanVertically": "Pan up / down", + "FrmSettings._MouseWheelAction": "Mouse wheel action", + "FrmSettings.Nav._Tools": "Գործիքներ", + "FrmMain.MnuSetDesktopBackground._Error": "Could not set the viewing image as desktop background", + "FrmSettings.Toolbar._Errors._ButtonExecutableRequired": "Button executable required.", + "_.ImageOrderBy._DateAccessed": "Date accessed", + "FrmSettings._ThumbnailSize": "Thumbnail size (in pixels)", + "FrmSettings._FileFormats": "Ֆայլի ձևաչափը", + "FrmMain.MnuReloadImageList": "Վերաբերռնել պատկերների ցանկը", + "FrmSettings._UseWebview2ForSvg": "Use Webview2 for viewing SVG format", + "FrmCrop.BtnCopy": "Պատճենել", + "FrmSettings._CurrentMonitorProfile._Description": "ImageGlass does not auto-update the color when moving its window between monitors", + "FrmMain.PicMain._ErrorText": "Could not open this image", + "FrmSettings.Tools._AddNewTool": "Add an external tool", + "FrmMain.MnuRename": "Անվանափոխել պատկերը…", + "FrmMain.MnuViewLastFrame": "View last frame", + "_._Webview2._NotFound": "Please install WebView2 Runtime to access full features of ImageGlass.", + "FrmMain.MnuGetMoreTools": "Get more tools…", + "FrmSettings.Nav._Appearance": "Appearance", + "FrmSettings._SlideshowInterval": "Slideshow interval:", + "_.ImageInterpolation._HighQualityBicubic": "High quality bicubic", + "FrmColorPickerSettings.ChkShowHsvA": "Use HSV format with alpha value", + "FrmSettings.Tools._EditTool": "Edit external tool", + "_._Error": "Սխալ", + "FrmSettings._ImageBoosterCacheMaxFileSizeInMb": "Maximum image file size to be cached (in megabytes)", + "_._UnhandledException._Description": "Unhandled exception has occurred. If you click Continue, the application will ignore this error and attempt to continue. If you click Quit, the application will close immediately.", + "_.Metadata._FileSize": "Ֆայլի չափը", + "FrmSettings.Toolbar._ButtonJson": "Button JSON", + "FrmQuickSetup._SetDefaultViewer._Description": "You can reset it in the app settings > File type associations tab.", + "FrmSettings.Nav._Edit": "Խմբագրել", + "FrmMain.MnuToggleGallery": "Gallery panel", + "_._IgCommandExe._DefaultError._Description": "Make sure you pass the correct commands!\r\nThis executable file contains command-line functions for ImageGlass software.\r\n\r\nTo explore all command lines, please visit:\r\n{0}", + "FrmMain.MnuLosslessCompression._Compressing": "Performing lossless compression…", + "FrmSettings._ShouldGroupImagesByDirectory": "Խմբավորել պատկերները ըստ պանակների", + "FrmMain.MnuPanToRightSide": "Pan image to right edge", + "_.Metadata._ExifRatingPercent": "Rating", + "FrmSettings._PanSpeed": "Panning speed", + "_._CheckForUpdate": "Ստուգել թարմացումները…", + "FrmSettings.Layout._ToolbarContext": "Contextual toolbar", + "_.ImageInfo._FrameCount": "{0} frame(s)", + "FrmMain.MnuLayout": "Դասավորություն", + "_._Website": "Կայք", + "FrmMain.MnuPasteImage": "Paste image", + "FrmSettings._ShowGalleryScrollbars": "Show gallery scrollbars" + } +} \ No newline at end of file diff --git a/Setup/Assets/Language/Bulgarian.iglang.json b/Setup/Assets/Language/Bulgarian.iglang.json new file mode 100644 index 000000000..fd16d1232 --- /dev/null +++ b/Setup/Assets/Language/Bulgarian.iglang.json @@ -0,0 +1,504 @@ +{ + "_Metadata": { + "Code": "bg-BG", + "EnglishName": "Bulgarian", + "LocalName": "Български", + "Author": "Стоян Димитров", + "MinVersion": "9.3" + }, + "Items": { + "FrmCrop.SelectionAspectRatio._Original": "Original", + "FrmMain.MnuShare._Error": "Could not open Share dialog.", + "_.Metadata._FileLastAccessTime": "Date accessed", + "FrmAbout._License": "Software license", + "FrmSettings.Toolbar._Errors._ButtonIdDuplicated": "A button with the ID '{0}' has already been defined. Please choose a different and unique ID for your button to avoid conflicts.", + "FrmMain.MnuSave._Confirm": "Are you sure you want to override this image?", + "FrmSettings._OpenDefaultAppsSetting": "Open Default apps setting", + "FrmMain.MnuCopyPath": "Копирай пътя до изображението", + "FrmCropSettings.DefaultSelectionType._SelectNone": "Select none", + "_.MouseWheelAction._PanHorizontally": "Pan left / right", + "FrmMain.MnuPrint": "Разпечатване…", + "FrmSettings.Toolbar._ToolbarButtons": "Toolbar buttons", + "FrmResize.LblResample": "Resample:", + "_.ImageOrderBy._Extension": "Разширение", + "FrmSettings.Nav._Viewer": "Разглеждач", + "FrmSettings.EditAppDialog._EditApp": "Edit app", + "FrmCrop.BtnReset._Tooltip": "Reset selection", + "FrmMain.MnuRename._Description": "Enter a new filename:", + "_._No": "Не", + "FrmSlideshow.MnuToggleCountdown": "Показване на обратен брояч на презентацията", + "FrmSettings._OpenStartupAppsSetting": "Open Startup apps setting", + "FrmMain.MnuViewPreviousFrame": "View previous frame", + "_.ImageOrderBy._DateModified": "Date modified", + "FrmMain.MnuViewNextFrame": "View next frame", + "FrmMain.MnuUnload": "Unload image", + "FrmSettings.Toolbar._HideToolbarInFullscreen": "Hide toolbar in Full Screen mode", + "_.ImageOrderType._Desc": "Низходящ", + "_._Update": "Update", + "FrmSettings._EnableImageAsyncLoading": "Enable image asynchronous loading", + "FrmSettings._DefaultPhotoViewer._Description": "Register the supported formats of ImageGlass with Windows. You might need to open the Default apps settings and manually select ImageGlass from the list for it to take effect.", + "_.MouseWheelAction._BrowseImages": "View next / previous Image", + "FrmSettings._EditApps": "Image editing apps", + "FrmColorPickerSettings.ChkShowCIELabA": "Use CIELAB format with alpha value", + "_._GetHelp": "Get help", + "FrmQuickSetup._SkipQuickSetup": "Skip this and launch ImageGlass", + "FrmColorPickerSettings._Title": "Color picker settings", + "_._Copy": "Копиране", + "FrmSettings._ImageBoosterCacheCount": "Number of images cached by Image Booster (one direction)", + "FrmMain.MnuPanToBottom": "Pan image to bottom", + "FrmMain.MnuZoom": "Мащабиране", + "FrmCropSettings.ChkCloseToolAfterSaving": "Close Crop tool after saving", + "FrmSettings._ShowWelcomeImage": "Show welcome image", + "FrmSettings._ColorProfile": "Цветови профил", + "FrmSettings._Theme._UninstallTheme": "Uninstall a theme pack", + "FrmMain._OpenWith": "Open with {0}", + "FrmMain.MnuRemoveDefaultPhotoViewer": "Remove default photo viewer", + "_.AfterEditAppAction._Nothing": "Нищо", + "FrmCrop.BtnSave": "Съхрани", + "FrmMain.MnuScaleToFit": "Разтегни, за да пасне", + "FrmToolNotFound.LblDownloadToolText": "You can download more tools for ImageGlass at:", + "_._LearnMore": "Научете повече…", + "FrmCrop.LblAspectRatio": "Aspect ratio:", + "FrmExportFrames._FileNotExist": "Image file does not exist", + "FrmSettings._LightTheme": "Light", + "FrmSettings.Nav._Slideshow": "Презентация", + "_._Continue": "Продължаване", + "_._AddHotkey": "Add hotkey…", + "FrmMain.MnuSetDesktopBackground": "Задай като фон на Работния плот", + "FrmMain.MnuReload": "Презареди изображението", + "FrmSlideshow.MnuExitSlideshow": "Изход от презентацията", + "FrmMain.MnuAutoZoom": "Автоматично мащабиране", + "FrmSettings._ShowImagePreview": "Display image preview while it's being loaded", + "FrmCrop.BtnCopy._Tooltip": "Copy the selection to clipboard", + "FrmSettings.Nav._Toolbar": "Инструментална лента", + "FrmMain.MnuSave._Error": "Could not save the image", + "FrmSettings._AfterEditingAction": "След отваряне на приложението за редакция", + "FrmSettings._ShouldUseColorProfileForAll": "Приложи и за изображения без вграден цветови профил", + "FrmCropSettings.DefaultSelectionType._UseTheLastSelection": "Use the last selection", + "FrmSettings._SlideshowInterval._From": "From", + "FrmSettings._ImageInterpolation": "Image interpolation", + "FrmQuickSetup._StepInfo": "Стъпка {0}", + "FrmMain.MnuColorPicker": "Цветови избирач", + "FrmCrop.SelectionAspectRatio._FreeRatio": "Free ratio", + "FrmSettings._ResetSettings": "Reset settings", + "FrmSettings._Startup": "Startup", + "_.BackdropStyle._None": "Никакъв", + "FrmSettings._LoadDefaultZoomLevels": "Load default zoom levels", + "FrmColorPicker.BtnSettings._Tooltip": "Open Color picker settings…", + "FrmSettings._UseThemeForDarkMode": "Use this theme for dark mode", + "FrmSettings._ShowDeleteConfirmation": "Show confirmation dialog when deleting file", + "FrmSettings._ShowAppIcon": "Show app icon on the title bar", + "_._InvalidAction": "Invalid action", + "FrmQuickSetup._SelectProfile": "Select a profile", + "_.Metadata._FileCreationTime": "Date created", + "FrmSettings._SlideshowImagesToNotifySound": "Number of images to trigger a notification sound", + "FrmSettings._BackgroundColor": "Viewer background color", + "FrmSettings._RealTimeFileUpdate": "Real-time file update", + "_.ColorProfileOption._CurrentMonitorProfile": "Current monitor profile", + "FrmSettings._EnableCutMultipleFiles": "Enable the cutting of multiple files at once", + "FrmSettings._AutoUpdate": "Проверявай автоматично за обновления", + "FrmCropSettings.LblDefaultSelection": "Default selection", + "FrmSettings._UseThemeForLightMode": "Use this theme for light mode", + "FrmSettings._ZoomLevels": "Нива на мащабиране", + "FrmMain.MnuSetLockScreen._Success": "Lock screen image is updated", + "FrmSettings._ShowGalleryFileName": "Show thumbnail filename", + "FrmSettings.Layout._Order": "Order", + "FrmCropSettings.ChkAutoCenterSelection": "Auto-center selection", + "FrmSettings.Nav._FileTypeAssociations": "File type associations", + "_._Back": "Назад", + "FrmMain.MnuSetDesktopBackground._Success": "Desktop background is updated", + "FrmSettings._ShouldAutoOpenNewAddedImage": "Open the new added image automatically", + "FrmCrop.SelectionAspectRatio._Custom": "Персонализиран…", + "FrmMain.MnuCopyPath._Success": "Copied the current image path.", + "FrmSettings._StartupBoost._Error": "Could not change Startup Boost setting", + "FrmToolNotFound.LblDescription": "ImageGlass was unable to locate the path to the '{0}' executable. To resolve this issue, please update the path to the '{0}' as necessary.", + "FrmMain.MnuClearClipboard": "Изчисти буфера", + "FrmSettings._ColorManagement": "Управление на цветовете", + "FrmMain._ReachedLastLast": "Стигни до последното изображение", + "FrmMain.MnuPanUp": "Pan image up", + "FrmMain.MnuRemoveDefaultPhotoViewer._Success": "ImageGlass is no longer the default photo viewer.", + "FrmSettings._GetMoreLanguagePacks": "Вземи още езикови пакети…", + "FrmAbout._Privacy": "Privacy policy", + "FrmSettings._EnableRecursiveLoading": "Load images in subfolders", + "_._UserAction._MethodArgumentNotSupported": "The argument type of method '{0}' is not supported", + "FrmSettings._FileExtensionIcons._Description": "For customizing file extension icons, download an icon pack, place all .ICO files in the extension icon folder, and click the '{0}' button. This will also set ImageGlass as default photo viewer.", + "_.ImageOrderType._Asc": "Възходящ", + "FrmExportFrames._Title": "Export image frames", + "_._Install": "Инсталирай…", + "FrmMain.MnuFlipHorizontal": "Обърни Хоризонтално", + "FrmSettings._OpenExtensionIconFolder": "Open extension icon folder", + "FrmAbout._Collaborator": "Collaborator:", + "FrmQuickSetup._ConfirmCloseProcess": "Before applying the new settings, it's essential to close all ImageGlass processes. Are you ready to proceed?", + "FrmExportFrames._ExportDone": "Exported {0} frames successfully to \r\n{1}", + "FrmCrop.BtnSaveAs._Tooltip": "Save as a copy…", + "FrmMain.MnuOpenFile": "Отвори файл…", + "FrmColorPickerSettings.ChkShowRgbA": "Use RGB format with alpha value", + "_.ImageInfo._ListCount": "{0} file(s)", + "FrmMain.MnuGoToLast": "Go to last image", + "FrmSettings._EditApps._AppName": "Име на приложението", + "FrmSettings._SlideshowBackgroundColor": "Slideshow background color", + "FrmAbout._Email": "Email:", + "_.MouseWheelAction._DoNothing": "Не прави нищо", + "FrmMain.MnuSaveAs": "Съхрани като…", + "FrmMain._Loading": "Loading…", + "_._Browse": "Преглед…", + "FrmMain.MnuSetDefaultPhotoViewer._Error": "Could not set ImageGlass as default photo viewer.", + "FrmSettings.Nav._Language": "Език", + "FrmQuickSetup._SeeWhatNew": "See what's new in this version…", + "FrmSettings._ImageInterpolation._ScaleUp": "When zoom > 100%", + "FrmSettings.Layout._ToolbarContextPosition": "Contextual toolbar position", + "FrmMain.MnuDeleteFromHardDisk": "Delete permanently", + "FrmSettings._EmbeddedThumbnail": "Embedded thumbnail", + "FrmMain.MnuDeleteFromHardDisk._Description": "Are you sure you want to permanently delete this file?", + "FrmMain.MnuScaleToFill": "Разтегни за запълване", + "FrmCrop.BtnCrop": "Crop", + "_.AfterEditAppAction._Minimize": "Минимизирай", + "FrmMain.MnuInvertColors": "Invert colors", + "FrmSettings._StartupBoost": "Startup Boost", + "FrmMain.MnuViewFirstFrame": "View first frame", + "_.MouseWheelEvent._CtrlAndScroll": "Hold Ctrl and scroll", + "FrmSettings._HideMainWindowInSlideshow": "Automatically hide main window", + "_.Metadata._FrameCount": "Frames", + "FrmSettings._EnableCopyMultipleFiles": "Enable the copying of multiple files at once", + "FrmMain.MnuFrameless._EnableDescription": "Hold Shift key to move the window.", + "_.ImageOrderBy._ExifDateTaken": "EXIF: Date taken", + "FrmAbout._Credits": "Credits", + "FrmSettings._AddNewFileExtension": "Add new file extension", + "FrmMain.MnuQuickSetup": "Open ImageGlass Quick Setup", + "FrmMain.MnuSave._Success": "Image is saved", + "FrmMain.MnuPanLeft": "Pan image left", + "FrmUpdate._StatusChecking": "Checking for update…", + "FrmSettings.Nav._Layout": "Оформление", + "FrmMain.MnuOpenWith": "Отвори с…", + "FrmAbout._Thanks": "Special thanks to", + "_._Warning": "Внимание", + "FrmSettings.Nav._Keyboard": "Клавиатура", + "FrmSlideshow._PauseSlideshow": "Презентацията е на пауза.", + "_._Add+": "Добавяне…", + "_._Email": "Email", + "FrmMain.MnuPanDown": "Pan image down", + "_._Cancel": "Отказ", + "_._OK": "Добре", + "FrmMain.MnuPanRight": "Pan image right", + "_.Position._Right": "Right", + "_._Icon": "Icon", + "FrmSettings._ShouldLoadHiddenImages": "Load hidden images", + "_._InvalidAction._Transformation": "ImageGlass does not support rotation, flipping for this image.", + "FrmSettings._MakeDefault": "Make default", + "FrmMain.MnuCopyImageData._Copying": "Copying the image data. It's going to take a while…", + "FrmSettings._UseEmbeddedThumbnailRawFormats": "Load only the embedded thumbnail for RAW formats", + "_.ImageInterpolation._Linear": "Linear", + "FrmSettings._ImageInfoTags": "Image information tags", + "FrmSettings._FileExtensionIcons": "File extension icons", + "FrmMain.MnuEdit._AppNotFound": "Could not find the associated app for editing. You can assign an app for editing this format in ImageGlass Settings > Edit.", + "_.ColorProfileOption._None": "Никакъв", + "FrmSettings._TotalSupportedFormats": "Total supported formats: {0}", + "FrmSettings._Clipboard": "Буфер", + "_._UserAction._Win32ExeError": "Cannot execute command '{0}'. Make sure the name is correct.", + "FrmCropSettings.DefaultSelectionType._SelectX": "Select {0}", + "_.AfterEditAppAction._Close": "Затвори", + "FrmAbout._LogoDesigner": "Logo designer:", + "_.ImageOrderBy._Name": "Име (по подразбиране)", + "FrmMain.MnuRemoveDefaultPhotoViewer._Error": "Could not remove ImageGlass as the default photo viewer.", + "FrmExportFrames._FolderPickerTitle": "Select output folder for exporting image frames", + "FrmAbout._Donate": "Donate", + "FrmMain.MnuFrameNav": "Придвижване в рамка", + "FrmMain.MnuSetLockScreen": "Задай като изображение на заключващия екран", + "_._Delete": "Изтриване", + "FrmMain.MnuViewPrevious": "Виж предишното изображение", + "_.Position._Top": "На върха", + "FrmSettings.Toolbar._CurrentButtons": "Current buttons:", + "FrmMain.MnuAbout": "Относно", + "FrmSettings._RemoveDefault": "Remove default", + "_._Description": "Описание", + "FrmMain.MnuPasteImage._Error": "Could not find image data in the Clipboard", + "FrmMain.MnuSettings": "Настройки", + "FrmCropSettings._Title": "Crop settings", + "FrmSettings.Toolbar._ToolbarIconHeight": "Размер на иконата на инструменталната лента", + "FrmSettings._SlideshowInterval._To": "To", + "FrmSettings.Layout._ToolbarPosition": "Позиция на инструменталната лента", + "FrmUpdate._StatusUpdated": "You are using the latest version!", + "FrmMain.MnuExit": "Изход", + "_._Webview2._Outdated": "Your WebView2 Runtime is not supported. Please update to version {0} or later.", + "_._Yes": "Да", + "FrmMain.MnuRotateLeft": "Завърти наляво", + "FrmSettings._EnableStartupBoost": "Enable Startup Boost", + "_.ImageOrderBy._ExifRating": "EXIF: Rating", + "FrmMain.MnuZoomIn": "Приближаване", + "_.Metadata._ColorSpace": "Color space", + "FrmAbout._Version": "Версия:", + "FrmMain.MnuToggleTopMost._Enable": "Enabled window always on top", + "FrmSettings.Toolbar._AvailableButtons": "Available buttons:", + "FrmMain.MnuSave._Saving": "Saving image…", + "FrmQuickSetup._StandardUser": "Standard user", + "FrmMain.MnuSetLockScreen._Error": "Could not set the viewing image as lock screen image", + "FrmSettings.Nav._Image": "Изображение", + "FrmSettings._Theme._InstallTheme": "Install theme packs", + "FrmSettings._EnableMultiInstances": "Разреши да работят няколко копия на програмата", + "FrmMain.MnuCropTool": "Crop image", + "_._IgCommandExe._DefaultError._Heading": "Invalid commands", + "_._Refresh": "Опресни", + "FrmMain.MnuLosslessCompression._Description": "This tool uses Magick.NET library for lossless compression, optimizing file size. Overwrites only if the compressed file is smaller than the original.", + "_._MoveDown": "Move down", + "FrmSettings._GetExtensionIconPacks": "Get extension icon packs…", + "FrmSettings._InAppMessageDuration": "In-app message duration (milliseconds)", + "FrmMain.MnuFrameless": "Без рамка", + "_._Reset": "Нулиране", + "FrmSettings._ConfigDir": "Configuration location", + "FrmQuickSetup._SettingsWillBeApplied": "Settings will be applied:", + "FrmSettings._UnmanagedSettingReminder": "This setting is not managed by ImageGlass. Don't forget to disable it before you remove or relocate the app because ImageGlass does not handle this automatically.", + "FrmMain.MnuClipboard": "Буфер", + "FrmMain.MnuCustomZoom": "Мащабиране по избор…", + "FrmSettings._DisplayLanguage": "Display language", + "FrmMain.MnuPrint._Error": "Could not print the viewing image", + "FrmSettings._ShouldPreserveModifiedDate": "Запазване на дата на промяна на изображението при съхраняване", + "FrmSettings._ShowSaveOverrideConfirmation": "Show confirmation dialog when overriding file", + "FrmColorPickerSettings.ChkShowHexA": "Use HEX format with alpha value", + "FrmMain.MnuFullScreen": "Full Screen", + "FrmSettings._StartupDir": "Startup location", + "FrmSettings._ShowCheckerboardOnlyImageRegion": "Show checkerboard only within the image region", + "FrmMain.MnuClearClipboard._Success": "Cleared clipboard.", + "FrmQuickSetup._Text": "ImageGlass Quick Setup", + "FrmMain.MnuLosslessCompression._Done": "Done lossless compression.\r\nThe new file size is {0}, saved {1}.", + "FrmMain.MnuLosslessCompression": "Magick.NET Lossless Compression", + "FrmResize.RadResizeByPercentage": "Percentage", + "FrmSettings._StartupBoost._Disabled": "Startup Boost is disabled", + "FrmMain.MnuToggleCheckerboard": "Шахматен фон", + "FrmSettings._MinEmbeddedThumbnailSize._Height": "Височина", + "FrmSettings.Nav._General": "Общи", + "FrmSettings._ImageLoading": "Зареждане на изображение", + "FrmSettings._ShowSlideshowCountdown": "Показване на обратен брояч на презентацията", + "FrmMain.MnuSave": "Съхрани", + "FrmMain.MnuMoveToRecycleBin": "Move to the Recycle Bin", + "FrmMain.MnuRefresh": "Опресни", + "FrmToolNotFound.LblHeading": "'{0}' is not found!", + "FrmMain.MnuReportIssue": "Докладвай проблем…", + "FrmMain.MnuCopyImageData": "Копирай данните на изображението", + "FrmMain.MnuCheckForUpdate._NewVersion": "Има нова версия!", + "_._Empty": "(празно)", + "FrmSettings._Zooming": "Мащабиране", + "FrmMain.MnuCutFile": "Cut file", + "FrmHotkeyPicker.LblHotkey": "Press hotkeys", + "FrmSettings.Layout._Gallery": "Gallery", + "FrmMain.MnuNewWindow": "Отвори в нов прозорец", + "FrmMain.MnuMoveToRecycleBin._Description": "Do you want to move this file to the Recycle bin?", + "FrmSettings._DefaultPhotoViewer": "Default photo viewer", + "_.Metadata._ExifDateTimeOriginal": "EXIF: DateTimeOriginal", + "FrmMain.MnuRotateRight": "Завърти надясно", + "FrmSettings._MinEmbeddedThumbnailSize": "Minimum size of the embedded thumbnail to be loaded", + "FrmMain.MnuSetDefaultPhotoViewer": "Set default photo viewer", + "FrmMain.MnuImageProperties": "Свойства на изображението", + "FrmSettings._EnableNavigationButtons": "Show navigation arrow buttons", + "_._Edit": "Променяне", + "FrmSettings._ImageBooster": "Image Booster", + "FrmSettings.Tools._IntegratedWith": "Integrated with {0}", + "_._Next": "Напред", + "FrmExportFrames._OpenOutputFolder": "Open output folder", + "FrmMain.MnuOpenLocation": "Отвори местоположението на изображението", + "FrmMain.MnuLockZoom": "Заключи коефициента на мащабиране", + "FrmSettings._StartupBoost._Description": "Preload and run ImageGlass in the background for a few seconds during Windows startup to accelerate the first launch.", + "FrmSettings._WindowBackdrop": "Window backdrop", + "FrmSettings._EnableRealTimeFileUpdate": "Monitor file changes in the viewing folder and update in realtime", + "_._NotSupported": "Unsupported format", + "FrmSettings._Theme._GetMoreThemes": "Get more theme packs…", + "FrmMain.MnuNewWindow._Error": "Cannot open new window because only one instance is allowed", + "FrmMain.MnuZoomOut": "Отдалечаване", + "FrmSettings.Toolbar._EditButton": "Edit toolbar button", + "FrmMain.MnuCustomZoom._Description": "Въведи нова стойност на мащаба", + "FrmResize.RadResizeByPixels": "Pixels", + "FrmMain.MnuEdit": "Редактирай изображението {0}…", + "FrmSettings.Layout._GalleryPosition": "Gallery position", + "FrmMain.MnuWindowFit": "Window Fit", + "FrmMain._OpenFileDialog": "Всички поддържани файлове", + "FrmSettings._UseRandomIntervalForSlideshow": "Използване на произволен интервал", + "_.Position._Left": "Left", + "FrmSettings._ShouldOpenLastSeenImage": "Open the last seen image", + "_.Position._Bottom": "В дъното", + "FrmResize.ChkKeepRatio": "Keep ratio propotional", + "FrmMain.MnuGoTo": "Отиди на…", + "FrmSlideshow.MnuPauseResumeSlideshow": "Pause/resume slideshow", + "FrmSettings.Tools._Integrated": "Integrated", + "FrmSettings._Contributors": "Contributors", + "_.MouseWheelAction._Zoom": "Zoom in / out", + "_._CommandPreview": "Визуализиране на командата", + "FrmSettings._DarkTheme": "Dark", + "_._Hotkeys": "Hotkeys", + "_.Metadata._ExifDateTime": "EXIF: DateTime", + "FrmSettings.Toolbar._Errors._ButtonIdRequired": "Button ID required.", + "FrmSettings._MinEmbeddedThumbnailSize._Width": "Ширина", + "_._Executable": "Executable", + "_.ImageInterpolation._MultiSampleLinear": "Многоточково линейно", + "_._Separator": "Разделител", + "FrmQuickSetup._ProfessionalUser": "Professional user", + "FrmMain.MnuFlipVertical": "Обърни Вертикално", + "FrmSlideshow._ResumeSlideshow": "Презентацията е възобновена.", + "FrmCropSettings.DefaultSelectionType._CustomArea": "Custom area…", + "FrmMain.MnuActualSize": "Реален размер", + "FrmCrop.BtnSaveAs": "Съхрани като…", + "FrmSettings._InstallNewLanguagePack": "Install new language packs…", + "FrmSlideshow.MnuZoomModes": "Zoom modes", + "FrmMain.MnuTools": "Инструменти", + "_.ImageInterpolation._Cubic": "Cubic", + "FrmUpdate._LatestVersion": "The latest version: {0}", + "FrmMain.MnuViewNext": "Виж следващото изображение", + "_.MouseWheelEvent._AltAndScroll": "Hold Alt and scroll", + "FrmToolNotFound._Title": "Tool not found", + "FrmCrop.BtnCrop._Tooltip": "Crop the image only", + "FrmSettings.EditAppDialog._AddApp": "Add an app for editing", + "FrmMain.MnuPanning": "Панорамиране", + "_._MoveUp": "Move up", + "FrmCropSettings.DefaultSelectionType._SelectAll": "Select all", + "_._Name": "Име", + "FrmColorPickerSettings.ChkShowHslA": "Use HSL format with alpha value", + "FrmMain.MnuToggleImageAnimation": "Start / stop animating image", + "FrmSettings._DisableStartupBoost": "Disable Startup Boost", + "FrmMain.MnuCopyFile._Success": "Копиран(и) {0} файл(а).", + "FrmMain.MnuSave._ConfirmDescription": "ImageGlass is not a professional photo editor, please be aware of losing the quality, metadata, layers,… when saving your image.", + "FrmToolNotFound.BtnSelectExecutable": "Select…", + "FrmUpdate._StatusOutdated": "A new update is available!", + "_.ImageOrderBy._Random": "Случаен", + "FrmResize.LblCurrentSize": "Current Size:", + "_._Apply": "Прилагане", + "FrmAbout._Slogan": "Лека, многофункционална програма за преглед на изображения", + "FrmMain.MnuPanToTop": "Pan image to top", + "FrmSettings.Toolbar._AddNewButton": "Add a custom toolbar button", + "FrmCrop.LblSize": "Size:", + "FrmSettings._ImageInterpolation._ScaleDown": "При мащабиране < 100%", + "_._CreatingFileError": "Could not create temporary image file", + "FrmMain.MnuGoTo._Description": "Enter the image index to view, and then press ENTER", + "FrmSettings.Toolbar._EnableCenterToolbar": "Use center alignment for toolbar", + "FrmMain.MnuResizeTool": "Resize image", + "FrmSettings.Layout._Toolbar": "Инструментална лента", + "FrmMain.MnuHelp": "Помощ", + "_.ImageOrderBy._FileSize": "File size", + "FrmSettings._Theme._OpenThemeFolder": "Отвори папката с темите", + "FrmMain.MnuNavigation": "Навигация", + "_._Save": "Запазване", + "FrmQuickSetup._SettingProfileDescription": "To modify these settings, simply access app settings.", + "_._UserAction._MenuNotFound": "Cannot find menu '{0}' to invoke the action", + "FrmMain.MnuPanToLeftSide": "Pan image to left edge", + "FrmUpdate._CurrentVersion": "Current version: {0}", + "FrmCrop.BtnSettings._Tooltip": "Open Crop tool settings", + "_.ColorProfileOption._Custom": "Персонализиран…", + "FrmSettings._UseEmbeddedThumbnailOtherFormats": "Load only the embedded thumbnail for other formats", + "FrmMain.MnuGoToFirst": "Go to first image", + "FrmSettings._ExportLanguagePack": "Export language pack…", + "FrmSettings.Nav._Mouse": "Mouse", + "_.ImageOrderBy._DateCreated": "Date created", + "FrmSettings._EnableFullscreenSlideshow": "Start slideshow in Full Screen mode", + "FrmAbout._Homepage": "Homepage:", + "FrmSettings._GalleryCacheSizeInMb": "Maximum gallery cache size (in megabytes)", + "FrmMain.MnuCopyImageData._Success": "Copied the current image data.", + "FrmSettings._EnableLoopBackNavigation": "Loop back to the first image when reaching the end of the image list", + "_.MouseWheelEvent._Scroll": "Scroll", + "FrmCrop.BtnSave._Tooltip": "Съхрани изображението", + "FrmMain.MnuSlideshow": "Презентация", + "FrmMain.MnuShare": "Сподели…", + "FrmSettings._SlideshowNotification": "Slideshow notification", + "FrmMain.MnuViewChannels": "Виж каналите", + "FrmSettings._Refresh": "Опресни", + "_._UserAction._MethodNotFound": "Cannot find method '{0}' to invoke the action", + "FrmMain.MnuCopyFile": "Copy file", + "_._CreatingFile": "Creating a temporary image file…", + "FrmMain.MnuToggleTopMost": "Дръж прозореца винаги отгоре", + "FrmMain.MnuLosslessCompression._Confirm": "Are you sure you want to proceed?", + "FrmMain.MnuImage": "Изображение", + "FrmSettings._StartupBoost._Enabled": "Startup Boost is enabled", + "FrmQuickSetup._SetDefaultViewer": "Do you want to set ImageGlass as the default photo viewer?", + "FrmMain.MnuScaleToWidth": "Притегляне по ширина", + "_._FileExtension": "Разширение на файла", + "FrmUpdate._PublishedDate": "Published date: {0}", + "_._DoNotShowThisMessageAgain": "Do not show this message again", + "_.ImageInterpolation._NearestNeighbor": "Nearest neighbor", + "FrmCrop.LblLocation": "Location:", + "_._Download": "Изтегляне", + "_.Metadata._ColorProfile": "Цветови профил", + "FrmSettings._CenterWindowFit": "Automatically center the window in Window Fit mode", + "FrmSettings._ImageLoadingOrder": "Ред за зареждане на изображения", + "FrmSettings._GalleryColumns": "Number of thumbnail columns in vertical gallery layout", + "_._Quit": "Изход", + "_._Add": "Добавяне", + "FrmMain.MnuChangeBackgroundColor": "Change background color…", + "FrmMain.MnuToggleToolbar": "Инструментална лента", + "FrmAbout._Contact": "Контакт", + "FrmSettings.Toolbar._AddCustomButton": "Add a custom button…", + "FrmCrop.BtnQuickSelect._Tooltip": "Quick select…", + "FrmMain.MnuCutFile._Success": "Изрязан(и) {0} файл(а).", + "FrmSettings._ZoomSpeed": "Zoom speed", + "FrmMain.MnuToggleTopMost._Disable": "Disabled window always on top", + "FrmSettings._ShouldUseExplorerSortOrder": "Use Explorer sort order if possible", + "_.ImageInterpolation._Antisotropic": "Antisotropic", + "FrmMain._ReachedFirstImage": "Стигни до първото изображение", + "_._UnhandledException": "Unhandled exception", + "FrmResize.LblNewSize": "New Size:", + "FrmMain._ClipboardImage": "Clipboard image", + "FrmMain.MnuExportFrames": "Export image frames…", + "FrmMain.MnuFile": "Файл", + "_._Close": "Затваряне", + "FrmMain.MnuMain": "Главно меню", + "_._ResetToDefault": "Нулирай до подразбиране", + "FrmSettings.Nav._Gallery": "Gallery", + "FrmMain.MnuSetDefaultPhotoViewer._Success": "You have successfully set ImageGlass as default photo viewer.", + "FrmSettings._HideGalleryInFullscreen": "Hide gallery in Full Screen mode", + "FrmSettings._AvailableImageInfoTags": "Налични етикети:", + "FrmExportFrames._Exporting": "Exporting {0}/{1} frames \r\n{2}…", + "_._Argument": "Argument", + "FrmSettings._ImageEditQuality": "Качество на изображението", + "_._ID": "ID", + "FrmSettings._UserConfigFile": "User settings file (igconfig.json)", + "FrmMain.MnuLoadingOrders": "Loading orders", + "FrmSettings._OpenSaveAsDialogInTheCurrentImageDir": "Open the Save As dialog in the current image directory", + "_.MouseWheelEvent._ShiftAndScroll": "Hold Shift and scroll", + "FrmSettings._UseSmoothZooming": "Use smooth zooming", + "FrmSettings._Theme": "Тема", + "FrmSettings._ImageBoosterCacheMaxDimension": "Maximum image dimension to be cached (in pixels)", + "FrmMain.MnuScaleToHeight": "Притегляне по височина", + "_.Metadata._FileLastWriteTime": "Date modified", + "FrmSettings._Author": "Автор", + "FrmSettings._Others": "Други", + "_.MouseWheelAction._PanVertically": "Pan up / down", + "FrmSettings._MouseWheelAction": "Mouse wheel action", + "FrmSettings.Nav._Tools": "Инструменти", + "FrmMain.MnuSetDesktopBackground._Error": "Could not set the viewing image as desktop background", + "FrmSettings.Toolbar._Errors._ButtonExecutableRequired": "Button executable required.", + "_.ImageOrderBy._DateAccessed": "Date accessed", + "FrmSettings._ThumbnailSize": "Thumbnail size (in pixels)", + "FrmSettings._FileFormats": "File formats", + "FrmMain.MnuReloadImageList": "Презареди списъка с изображения", + "FrmSettings._UseWebview2ForSvg": "Use Webview2 for viewing SVG format", + "FrmCrop.BtnCopy": "Копирай", + "FrmSettings._CurrentMonitorProfile._Description": "При преместване на друг монитор ImageGlass не променя цвета автоматично", + "FrmMain.PicMain._ErrorText": "Could not open this image", + "FrmSettings.Tools._AddNewTool": "Add an external tool", + "FrmMain.MnuRename": "Преименувай изображението…", + "FrmMain.MnuViewLastFrame": "View last frame", + "_._Webview2._NotFound": "Please install WebView2 Runtime to access full features of ImageGlass.", + "FrmMain.MnuGetMoreTools": "Get more tools…", + "FrmSettings.Nav._Appearance": "Appearance", + "FrmSettings._SlideshowInterval": "Интервал на презентацията:", + "_.ImageInterpolation._HighQualityBicubic": "High quality bicubic", + "FrmColorPickerSettings.ChkShowHsvA": "Use HSV format with alpha value", + "FrmSettings.Tools._EditTool": "Edit external tool", + "_._Error": "Грешка", + "FrmSettings._ImageBoosterCacheMaxFileSizeInMb": "Maximum image file size to be cached (in megabytes)", + "_._UnhandledException._Description": "Unhandled exception has occurred. If you click Continue, the application will ignore this error and attempt to continue. If you click Quit, the application will close immediately.", + "_.Metadata._FileSize": "File size", + "FrmSettings.Toolbar._ButtonJson": "Button JSON", + "FrmQuickSetup._SetDefaultViewer._Description": "You can reset it in the app settings > File type associations tab.", + "FrmSettings.Nav._Edit": "Промяна на разширенията", + "FrmMain.MnuToggleGallery": "Gallery panel", + "_._IgCommandExe._DefaultError._Description": "Make sure you pass the correct commands!\r\nThis executable file contains command-line functions for ImageGlass software.\r\n\r\nTo explore all command lines, please visit:\r\n{0}", + "FrmMain.MnuLosslessCompression._Compressing": "Performing lossless compression…", + "FrmSettings._ShouldGroupImagesByDirectory": "Групиране на изображения по папка", + "FrmMain.MnuPanToRightSide": "Pan image to right edge", + "_.Metadata._ExifRatingPercent": "Rating", + "FrmSettings._PanSpeed": "Panning speed", + "_._CheckForUpdate": "Провери за обновления…", + "FrmSettings.Layout._ToolbarContext": "Contextual toolbar", + "_.ImageInfo._FrameCount": "{0} frame(s)", + "FrmMain.MnuLayout": "Оформление", + "_._Website": "Уеб сайт", + "FrmMain.MnuPasteImage": "Paste image", + "FrmSettings._ShowGalleryScrollbars": "Show gallery scrollbars" + } +} \ No newline at end of file diff --git a/Setup/Assets/Language/Catalan.iglang.json b/Setup/Assets/Language/Catalan.iglang.json new file mode 100644 index 000000000..c47040f11 --- /dev/null +++ b/Setup/Assets/Language/Catalan.iglang.json @@ -0,0 +1,504 @@ +{ + "_Metadata": { + "Code": "ca-ES", + "EnglishName": "Catalan", + "LocalName": "Català", + "Author": "Arnau Mora", + "MinVersion": "9.3" + }, + "Items": { + "FrmCrop.SelectionAspectRatio._Original": "Original", + "FrmMain.MnuShare._Error": "No s'hi ha pogut obrir el diàleg de Compartir.", + "_.Metadata._FileLastAccessTime": "Data d'accés", + "FrmAbout._License": "Llicència de programari", + "FrmSettings.Toolbar._Errors._ButtonIdDuplicated": "Un botó amb la ID '{0}' ja ha estat definit. Si us plau, escolliu una ID única i diferent per aquest botó per evitar conflictes.", + "FrmMain.MnuSave._Confirm": "Estàs segur que vols sobreescriure aquesta imatge?", + "FrmSettings._OpenDefaultAppsSetting": "Obre la configuració per aplicacions predeterminades", + "FrmMain.MnuCopyPath": "Copia l'adreça de la imatge", + "FrmCropSettings.DefaultSelectionType._SelectNone": "No en seleccionis cap", + "_.MouseWheelAction._PanHorizontally": "Mou esquerra /dreta", + "FrmMain.MnuPrint": "Imprimeix…", + "FrmSettings.Toolbar._ToolbarButtons": "Botons a la barra d’eines", + "FrmResize.LblResample": "Remostreja:", + "_.ImageOrderBy._Extension": "Extensió", + "FrmSettings.Nav._Viewer": "Visor", + "FrmSettings.EditAppDialog._EditApp": "Edita l'aplicació", + "FrmCrop.BtnReset._Tooltip": "Reinicia la selecció:", + "FrmMain.MnuRename._Description": "Introdueix un nom nou d'arxiu:", + "_._No": "No", + "FrmSlideshow.MnuToggleCountdown": "Mostra compte enrere de la presentació", + "FrmSettings._OpenStartupAppsSetting": "Obre la configuració per aplicacions d'inici", + "FrmMain.MnuViewPreviousFrame": "Veure fotograma anterior", + "_.ImageOrderBy._DateModified": "Data de modificació", + "FrmMain.MnuViewNextFrame": "Veure fotograma següent", + "FrmMain.MnuUnload": "No carregar la imatge", + "FrmSettings.Toolbar._HideToolbarInFullscreen": "Oculta barra d'eines al mode de pantalla sencera", + "_.ImageOrderType._Desc": "Descendent", + "_._Update": "Actualitza", + "FrmSettings._EnableImageAsyncLoading": "Habilita la càrrega asincrònica d'imatges", + "FrmSettings._DefaultPhotoViewer._Description": "Registra els formats compatibles d'ImageGlass amb Windows. Pot ser que hagis d'obrir la configuració d'aplicacions predeterminades i seleccionar manualment ImageGlass al llistat per fer efecte.", + "_.MouseWheelAction._BrowseImages": "Veure imatge següent / anterior", + "FrmSettings._EditApps": "Aplicacions d'edició d'imatges", + "FrmColorPickerSettings.ChkShowCIELabA": "Utilitza el format CIELAB amb valor alfa", + "_._GetHelp": "Obteniu ajuda", + "FrmQuickSetup._SkipQuickSetup": "Salta-ho i inicia ImageGlass", + "FrmColorPickerSettings._Title": "Configuració del selector de color", + "_._Copy": "Copia", + "FrmSettings._ImageBoosterCacheCount": "Nombre d'imatges desades al memòria cau per Image Booster (unidireccional)", + "FrmMain.MnuPanToBottom": "Mou imatge a la part inferior", + "FrmMain.MnuZoom": "Zoom", + "FrmCropSettings.ChkCloseToolAfterSaving": "Tanca l'eina Tallar després de desar", + "FrmSettings._ShowWelcomeImage": "Mostra la imatge de benvinguda", + "FrmSettings._ColorProfile": "Perfil de color", + "FrmSettings._Theme._UninstallTheme": "Desinstal·la un paquet de temaris", + "FrmMain._OpenWith": "Obrir amb {0}", + "FrmMain.MnuRemoveDefaultPhotoViewer": "Esborra el visor d'imatges predeterminat", + "_.AfterEditAppAction._Nothing": "Res", + "FrmCrop.BtnSave": "Desa", + "FrmMain.MnuScaleToFit": "Escalar fins encaixar", + "FrmToolNotFound.LblDownloadToolText": "Pot descarregar més eines per ImageGlass a:", + "_._LearnMore": "Saber-ne més...…", + "FrmCrop.LblAspectRatio": "Relació d'aspecte:", + "FrmExportFrames._FileNotExist": "L'arxiu d'imatge no existeix", + "FrmSettings._LightTheme": "Clar", + "FrmSettings.Nav._Slideshow": "Presentació", + "_._Continue": "Continua", + "_._AddHotkey": "Afegeix una drecera de teclat...", + "FrmMain.MnuSetDesktopBackground": "Establir com a fons de pantalla", + "FrmMain.MnuReload": "Recarrega la imatge", + "FrmSlideshow.MnuExitSlideshow": "Surt de la presentació", + "FrmMain.MnuAutoZoom": "Zoom automàtic", + "FrmSettings._ShowImagePreview": "Mostra vista prèvia de la imatge mentre estigui sent carregada", + "FrmCrop.BtnCopy._Tooltip": "Copia selecció al porta-retalls", + "FrmSettings.Nav._Toolbar": "Barra d'eines", + "FrmMain.MnuSave._Error": "No s'ha pogut desar la imatge", + "FrmSettings._AfterEditingAction": "Després d'obrir l'aplicació d'edició", + "FrmSettings._ShouldUseColorProfileForAll": "Aplica també a les imatges sense un perfil de color incrustat", + "FrmCropSettings.DefaultSelectionType._UseTheLastSelection": "Utilitza l'última selecció", + "FrmSettings._SlideshowInterval._From": "Des de", + "FrmSettings._ImageInterpolation": "Interpolació de la imatge", + "FrmQuickSetup._StepInfo": "Pas {0}", + "FrmMain.MnuColorPicker": "Selector de color", + "FrmCrop.SelectionAspectRatio._FreeRatio": "Relació lliure", + "FrmSettings._ResetSettings": "Restableix la configuració", + "FrmSettings._Startup": "Inici", + "_.BackdropStyle._None": "Cap", + "FrmSettings._LoadDefaultZoomLevels": "Carrega nivells de zoom per defecte", + "FrmColorPicker.BtnSettings._Tooltip": "Obrir configuració del selector de colors…", + "FrmSettings._UseThemeForDarkMode": "Utilitza aquest temari pel mode fosc", + "FrmSettings._ShowDeleteConfirmation": "Mostra el diàleg de confirmació en suprimir un arxiu", + "FrmSettings._ShowAppIcon": "Mostra la icona de l'aplicació a la barra de títol", + "_._InvalidAction": "Acció invalida", + "FrmQuickSetup._SelectProfile": "Selecciona un perfil", + "_.Metadata._FileCreationTime": "Data de creació", + "FrmSettings._SlideshowImagesToNotifySound": "Nombre d'imatges para reproduir un so de notificació", + "FrmSettings._BackgroundColor": "Color de fons del visor", + "FrmSettings._RealTimeFileUpdate": "Actualització d'arxius a temps real", + "_.ColorProfileOption._CurrentMonitorProfile": "Perfil actual del monitor", + "FrmSettings._EnableCutMultipleFiles": "Habilitar el tall de diversos arxius a la vegada", + "FrmSettings._AutoUpdate": "Comprova actualitzacions automàticament", + "FrmCropSettings.LblDefaultSelection": "Selecció per defecte", + "FrmSettings._UseThemeForLightMode": "Utilitza aquest temari pel mode clar", + "FrmSettings._ZoomLevels": "Nivells de Zoom", + "FrmMain.MnuSetLockScreen._Success": "Imatge de pantalla de bloqueig actualitzada", + "FrmSettings._ShowGalleryFileName": "Mostra el nom de l'arxiu de miniatura", + "FrmSettings.Layout._Order": "Ordre", + "FrmCropSettings.ChkAutoCenterSelection": "Centra selecció automàticament", + "FrmSettings.Nav._FileTypeAssociations": "Associacions de tipus d'imatge", + "_._Back": "Enrere", + "FrmMain.MnuSetDesktopBackground._Success": "Fons d'escriptori actualitzat", + "FrmSettings._ShouldAutoOpenNewAddedImage": "Obrir automàticament la nova imatge afegida", + "FrmCrop.SelectionAspectRatio._Custom": "Personalitzat…", + "FrmMain.MnuCopyPath._Success": "S'ha copiat la ruta de la imatge actual.", + "FrmSettings._StartupBoost._Error": "No s'ha pogut canviar la configuració d'Inici accelerat", + "FrmToolNotFound.LblDescription": "ImageGlass no ha pogut localitzar la ruta a l'executable '{0}'. Per resoldre aquest problema, actualitzeu la ruta a '{0}' segons calgui.", + "FrmMain.MnuClearClipboard": "Buida el portapapers", + "FrmSettings._ColorManagement": "Gestió de color", + "FrmMain._ReachedLastLast": "No es poden modificar imatge animades", + "FrmMain.MnuPanUp": "Mou imatge a dalt", + "FrmMain.MnuRemoveDefaultPhotoViewer._Success": "ImageGlass ja no és el visor de fotografies predeterminat.", + "FrmSettings._GetMoreLanguagePacks": "Obté més paquets d'idioma…", + "FrmAbout._Privacy": "Política de privacitat", + "FrmSettings._EnableRecursiveLoading": "Carrega imatges de subcarpetes", + "_._UserAction._MethodArgumentNotSupported": "El tipus d'argument del mètode '{0}' no és compatible", + "FrmSettings._FileExtensionIcons._Description": "Per personalitzar les icones d'extensions de fitxers, descarregueu un paquet d'icones, col·loqueu tots els fitxers .ICO a la carpeta d'icones d'extensions i feu clic al botó '{0}'. Això també establirà ImageGlass com visor de fotografies per defecte.", + "_.ImageOrderType._Asc": "Ascendent", + "FrmExportFrames._Title": "Exporta fotogrames d'imatge", + "_._Install": "Instal·lar…", + "FrmMain.MnuFlipHorizontal": "Inverteix Horitzontalment", + "FrmSettings._OpenExtensionIconFolder": "Obrir carpeta d'icones d'extensió", + "FrmAbout._Collaborator": "Col·laborador:", + "FrmQuickSetup._ConfirmCloseProcess": "Abans d'aplicar els ajustaments nous, és essencial tancar tots els processos d'ImageGlass. Estàs llest per continuar?", + "FrmExportFrames._ExportDone": "S'han exportat {0} fotogrames correctament a \n{1}", + "FrmCrop.BtnSaveAs._Tooltip": "Guardar una còpia...", + "FrmMain.MnuOpenFile": "Obrir fitxer…", + "FrmColorPickerSettings.ChkShowRgbA": "Empra el format RGB amb transparència", + "_.ImageInfo._ListCount": "{0} fitxer(s)", + "FrmMain.MnuGoToLast": "Ves a la darrera imatge", + "FrmSettings._EditApps._AppName": "Nom de l'aplicació", + "FrmSettings._SlideshowBackgroundColor": "Color de fons de diapositives", + "FrmAbout._Email": "Correu electrònic:", + "_.MouseWheelAction._DoNothing": "No facis res", + "FrmMain.MnuSaveAs": "Anomena i desa…", + "FrmMain._Loading": "Carregant...", + "_._Browse": "Cerca…", + "FrmMain.MnuSetDefaultPhotoViewer._Error": "No s'ha pogut establir ImageGlass com a visor de fotografies per defecte.", + "FrmSettings.Nav._Language": "Llenguatge", + "FrmQuickSetup._SeeWhatNew": "Veure què hi ha de nou en aquesta versió…", + "FrmSettings._ImageInterpolation._ScaleUp": "Quan el zoom > 100%", + "FrmSettings.Layout._ToolbarContextPosition": "Posició de la barra d'eines contextual", + "FrmMain.MnuDeleteFromHardDisk": "Elimina permanentment", + "FrmSettings._EmbeddedThumbnail": "Miniatura incrustada", + "FrmMain.MnuDeleteFromHardDisk._Description": "Esteu segur que voleu esborrar permanentment aquest fitxer?", + "FrmMain.MnuScaleToFill": "Escalar fins emplenar", + "FrmCrop.BtnCrop": "Retalla", + "_.AfterEditAppAction._Minimize": "Minimitzar", + "FrmMain.MnuInvertColors": "Inverteix els colors", + "FrmSettings._StartupBoost": "Inici accelerat", + "FrmMain.MnuViewFirstFrame": "Veure el primer fotograma", + "_.MouseWheelEvent._CtrlAndScroll": "Manté Ctrl i desplaçat", + "FrmSettings._HideMainWindowInSlideshow": "Oculta automàticament la finestra principal", + "_.Metadata._FrameCount": "Fotogrames", + "FrmSettings._EnableCopyMultipleFiles": "Habilita la còpia de diversos arxius a la vegada", + "FrmMain.MnuFrameless._EnableDescription": "Manté Shift per a moure la finestra.", + "_.ImageOrderBy._ExifDateTaken": "EXIF: Data de captura", + "FrmAbout._Credits": "Crèdits", + "FrmSettings._AddNewFileExtension": "Afegeix una nova extensió d'arxiu", + "FrmMain.MnuQuickSetup": "Obrir la configuració ràpida d'ImageGlass", + "FrmMain.MnuSave._Success": "Imatge desada", + "FrmMain.MnuPanLeft": "Mou la imatge a l'esquerra", + "FrmUpdate._StatusChecking": "Comprovant actualitzacions…", + "FrmSettings.Nav._Layout": "Distribució", + "FrmMain.MnuOpenWith": "Obre amb…", + "FrmAbout._Thanks": "Agraïments especials a", + "_._Warning": "Advertència", + "FrmSettings.Nav._Keyboard": "Teclat", + "FrmSlideshow._PauseSlideshow": "Presentació pausada.", + "_._Add+": "Afegeix…", + "_._Email": "Correu electrònic", + "FrmMain.MnuPanDown": "Mou la imatge avall", + "_._Cancel": "Cancel·la", + "_._OK": "OK", + "FrmMain.MnuPanRight": "Mou la imatge a la dreta", + "_.Position._Right": "Dreta", + "_._Icon": "Icona", + "FrmSettings._ShouldLoadHiddenImages": "Carrega imatges ocultes", + "_._InvalidAction._Transformation": "ImageGlass no admet ni la rotació ni el voltejat d'aquesta imatge.", + "FrmSettings._MakeDefault": "Estableix com a predeterminat", + "FrmMain.MnuCopyImageData._Copying": "Copiant les dades de la imatge. Trigarà una estona…", + "FrmSettings._UseEmbeddedThumbnailRawFormats": "Només carrega la miniatura incrustada per als formats RAW", + "_.ImageInterpolation._Linear": "Lineal", + "FrmSettings._ImageInfoTags": "Etiquetes d'informació d'imatge", + "FrmSettings._FileExtensionIcons": "Icones d'extensió del fitxer", + "FrmMain.MnuEdit._AppNotFound": "No s'ha pogut trobar l'aplicació associada per editar. Pots assignar una aplicació per editar aquest format a Configuració d'ImageGlass > Editar.", + "_.ColorProfileOption._None": "Cap", + "FrmSettings._TotalSupportedFormats": "Total de formats suportats: {0}", + "FrmSettings._Clipboard": "Portapapers", + "_._UserAction._Win32ExeError": "No es pot executar el comandament «{0}». Fes compta que el nom sigui correcte.", + "FrmCropSettings.DefaultSelectionType._SelectX": "Selecciona {0}", + "_.AfterEditAppAction._Close": "Tanca", + "FrmAbout._LogoDesigner": "Dissenyador de logo:", + "_.ImageOrderBy._Name": "Nom (per defecte)", + "FrmMain.MnuRemoveDefaultPhotoViewer._Error": "No s'ha pogut eliminar ImageGlass com el visor de fotografies per defecte.", + "FrmExportFrames._FolderPickerTitle": "Selecciona la carpeta de destinació dels fotogrames d'imatge", + "FrmAbout._Donate": "Donar", + "FrmMain.MnuFrameNav": "Navegació de Marc", + "FrmMain.MnuSetLockScreen": "Establir com a pantalla de bloqueig", + "_._Delete": "Elimina", + "FrmMain.MnuViewPrevious": "Veure la imatge prèvia", + "_.Position._Top": "Superior", + "FrmSettings.Toolbar._CurrentButtons": "Botons actuals:", + "FrmMain.MnuAbout": "A sobre de", + "FrmSettings._RemoveDefault": "Esborra per defecte", + "_._Description": "Descripció", + "FrmMain.MnuPasteImage._Error": "No s'han pogut trobar dades d'imatge al porta-retalls", + "FrmMain.MnuSettings": "Configuració", + "FrmCropSettings._Title": "Configuracions de retall", + "FrmSettings.Toolbar._ToolbarIconHeight": "Tamany de les icones de la barra d'eines", + "FrmSettings._SlideshowInterval._To": "A", + "FrmSettings.Layout._ToolbarPosition": "Posició de la barra d'eines", + "FrmUpdate._StatusUpdated": "Fas servir l'última versió!", + "FrmMain.MnuExit": "Sortir", + "_._Webview2._Outdated": "Your WebView2 Runtime is not supported. Please update to version {0} or later.", + "_._Yes": "Sí", + "FrmMain.MnuRotateLeft": "Rotar a l'esquerra", + "FrmSettings._EnableStartupBoost": "Enable Startup Boost", + "_.ImageOrderBy._ExifRating": "EXIF: Rating", + "FrmMain.MnuZoomIn": "Més Zoom", + "_.Metadata._ColorSpace": "Color space", + "FrmAbout._Version": "Versió:", + "FrmMain.MnuToggleTopMost._Enable": "Enabled window always on top", + "FrmSettings.Toolbar._AvailableButtons": "Available buttons:", + "FrmMain.MnuSave._Saving": "Saving image…", + "FrmQuickSetup._StandardUser": "Standard user", + "FrmMain.MnuSetLockScreen._Error": "Could not set the viewing image as lock screen image", + "FrmSettings.Nav._Image": "Imatge", + "FrmSettings._Theme._InstallTheme": "Install theme packs", + "FrmSettings._EnableMultiInstances": "Permet varies instàncies del programa", + "FrmMain.MnuCropTool": "Crop image", + "_._IgCommandExe._DefaultError._Heading": "Invalid commands", + "_._Refresh": "Actualitzar", + "FrmMain.MnuLosslessCompression._Description": "This tool uses Magick.NET library for lossless compression, optimizing file size. Overwrites only if the compressed file is smaller than the original.", + "_._MoveDown": "Move down", + "FrmSettings._GetExtensionIconPacks": "Get extension icon packs…", + "FrmSettings._InAppMessageDuration": "In-app message duration (milliseconds)", + "FrmMain.MnuFrameless": "Sense bordes", + "_._Reset": "Reinicia", + "FrmSettings._ConfigDir": "Configuration location", + "FrmQuickSetup._SettingsWillBeApplied": "Settings will be applied:", + "FrmSettings._UnmanagedSettingReminder": "This setting is not managed by ImageGlass. Don't forget to disable it before you remove or relocate the app because ImageGlass does not handle this automatically.", + "FrmMain.MnuClipboard": "Portapapers", + "FrmMain.MnuCustomZoom": "Zoom propi…", + "FrmSettings._DisplayLanguage": "Display language", + "FrmMain.MnuPrint._Error": "Could not print the viewing image", + "FrmSettings._ShouldPreserveModifiedDate": "Manté la data de modificació de la imatge al desar", + "FrmSettings._ShowSaveOverrideConfirmation": "Show confirmation dialog when overriding file", + "FrmColorPickerSettings.ChkShowHexA": "Use HEX format with alpha value", + "FrmMain.MnuFullScreen": "Full Screen", + "FrmSettings._StartupDir": "Startup location", + "FrmSettings._ShowCheckerboardOnlyImageRegion": "Show checkerboard only within the image region", + "FrmMain.MnuClearClipboard._Success": "Cleared clipboard.", + "FrmQuickSetup._Text": "ImageGlass Quick Setup", + "FrmMain.MnuLosslessCompression._Done": "Done lossless compression.\r\nThe new file size is {0}, saved {1}.", + "FrmMain.MnuLosslessCompression": "Magick.NET Lossless Compression", + "FrmResize.RadResizeByPercentage": "Percentage", + "FrmSettings._StartupBoost._Disabled": "Startup Boost is disabled", + "FrmMain.MnuToggleCheckerboard": "Fons d'escacs", + "FrmSettings._MinEmbeddedThumbnailSize._Height": "Alçada", + "FrmSettings.Nav._General": "General", + "FrmSettings._ImageLoading": "Càrrega d'imatges", + "FrmSettings._ShowSlideshowCountdown": "Mostra compte enrere de la presentació", + "FrmMain.MnuSave": "Desa", + "FrmMain.MnuMoveToRecycleBin": "Move to the Recycle Bin", + "FrmMain.MnuRefresh": "Actualitzar", + "FrmToolNotFound.LblHeading": "'{0}' is not found!", + "FrmMain.MnuReportIssue": "Informar d'un error…", + "FrmMain.MnuCopyImageData": "Copia les dades d'imatge", + "FrmMain.MnuCheckForUpdate._NewVersion": "Hi ha una nova versió disponible!", + "_._Empty": "(empty)", + "FrmSettings._Zooming": "Zoom", + "FrmMain.MnuCutFile": "Cut file", + "FrmHotkeyPicker.LblHotkey": "Press hotkeys", + "FrmSettings.Layout._Gallery": "Gallery", + "FrmMain.MnuNewWindow": "Obre una nova finestra", + "FrmMain.MnuMoveToRecycleBin._Description": "Do you want to move this file to the Recycle bin?", + "FrmSettings._DefaultPhotoViewer": "Default photo viewer", + "_.Metadata._ExifDateTimeOriginal": "EXIF: DateTimeOriginal", + "FrmMain.MnuRotateRight": "Rotar a la dreta", + "FrmSettings._MinEmbeddedThumbnailSize": "Minimum size of the embedded thumbnail to be loaded", + "FrmMain.MnuSetDefaultPhotoViewer": "Set default photo viewer", + "FrmMain.MnuImageProperties": "Propietats de la imatge", + "FrmSettings._EnableNavigationButtons": "Show navigation arrow buttons", + "_._Edit": "Editar", + "FrmSettings._ImageBooster": "Image Booster", + "FrmSettings.Tools._IntegratedWith": "Integrated with {0}", + "_._Next": "Següent", + "FrmExportFrames._OpenOutputFolder": "Open output folder", + "FrmMain.MnuOpenLocation": "Obre la ubicació de la imatge", + "FrmMain.MnuLockZoom": "Bloqueja el ratio de zoom", + "FrmSettings._StartupBoost._Description": "Preload and run ImageGlass in the background for a few seconds during Windows startup to accelerate the first launch.", + "FrmSettings._WindowBackdrop": "Window backdrop", + "FrmSettings._EnableRealTimeFileUpdate": "Monitor file changes in the viewing folder and update in realtime", + "_._NotSupported": "Unsupported format", + "FrmSettings._Theme._GetMoreThemes": "Get more theme packs…", + "FrmMain.MnuNewWindow._Error": "Cannot open new window because only one instance is allowed", + "FrmMain.MnuZoomOut": "Menys Zoom", + "FrmSettings.Toolbar._EditButton": "Edit toolbar button", + "FrmMain.MnuCustomZoom._Description": "Introdueix un valor de zoom", + "FrmResize.RadResizeByPixels": "Pixels", + "FrmMain.MnuEdit": "Edita la imatge {0}…", + "FrmSettings.Layout._GalleryPosition": "Gallery position", + "FrmMain.MnuWindowFit": "Window Fit", + "FrmMain._OpenFileDialog": "Tots els formats suportats", + "FrmSettings._UseRandomIntervalForSlideshow": "Utilitza un interval aleatori", + "_.Position._Left": "Left", + "FrmSettings._ShouldOpenLastSeenImage": "Open the last seen image", + "_.Position._Bottom": "Inferior", + "FrmResize.ChkKeepRatio": "Keep ratio propotional", + "FrmMain.MnuGoTo": "Ves a…", + "FrmSlideshow.MnuPauseResumeSlideshow": "Pause/resume slideshow", + "FrmSettings.Tools._Integrated": "Integrated", + "FrmSettings._Contributors": "Contributors", + "_.MouseWheelAction._Zoom": "Zoom in / out", + "_._CommandPreview": "Previsualització del comandament", + "FrmSettings._DarkTheme": "Dark", + "_._Hotkeys": "Hotkeys", + "_.Metadata._ExifDateTime": "EXIF: DateTime", + "FrmSettings.Toolbar._Errors._ButtonIdRequired": "Button ID required.", + "FrmSettings._MinEmbeddedThumbnailSize._Width": "Amplada", + "_._Executable": "Executable", + "_.ImageInterpolation._MultiSampleLinear": "Multi-sample linear", + "_._Separator": "Separador", + "FrmQuickSetup._ProfessionalUser": "Professional user", + "FrmMain.MnuFlipVertical": "Inverteix Verticalment", + "FrmSlideshow._ResumeSlideshow": "Presentació represa.", + "FrmCropSettings.DefaultSelectionType._CustomArea": "Custom area…", + "FrmMain.MnuActualSize": "Tamany real", + "FrmCrop.BtnSaveAs": "Anomena i desa…", + "FrmSettings._InstallNewLanguagePack": "Install new language packs…", + "FrmSlideshow.MnuZoomModes": "Zoom modes", + "FrmMain.MnuTools": "Eines", + "_.ImageInterpolation._Cubic": "Cubic", + "FrmUpdate._LatestVersion": "The latest version: {0}", + "FrmMain.MnuViewNext": "Veure la imatge següent", + "_.MouseWheelEvent._AltAndScroll": "Hold Alt and scroll", + "FrmToolNotFound._Title": "Tool not found", + "FrmCrop.BtnCrop._Tooltip": "Crop the image only", + "FrmSettings.EditAppDialog._AddApp": "Add an app for editing", + "FrmMain.MnuPanning": "Desplaçament", + "_._MoveUp": "Move up", + "FrmCropSettings.DefaultSelectionType._SelectAll": "Select all", + "_._Name": "Nom", + "FrmColorPickerSettings.ChkShowHslA": "Use HSL format with alpha value", + "FrmMain.MnuToggleImageAnimation": "Start / stop animating image", + "FrmSettings._DisableStartupBoost": "Disable Startup Boost", + "FrmMain.MnuCopyFile._Success": "S'han copiat {0} fitxer(s).", + "FrmMain.MnuSave._ConfirmDescription": "ImageGlass is not a professional photo editor, please be aware of losing the quality, metadata, layers,… when saving your image.", + "FrmToolNotFound.BtnSelectExecutable": "Select…", + "FrmUpdate._StatusOutdated": "A new update is available!", + "_.ImageOrderBy._Random": "Aleatori", + "FrmResize.LblCurrentSize": "Current Size:", + "_._Apply": "Aplica", + "FrmAbout._Slogan": "Un visor d'imatges lleuger i flexible", + "FrmMain.MnuPanToTop": "Pan image to top", + "FrmSettings.Toolbar._AddNewButton": "Add a custom toolbar button", + "FrmCrop.LblSize": "Size:", + "FrmSettings._ImageInterpolation._ScaleDown": "Quan el zoom < 100%", + "_._CreatingFileError": "Could not create temporary image file", + "FrmMain.MnuGoTo._Description": "Enter the image index to view, and then press ENTER", + "FrmSettings.Toolbar._EnableCenterToolbar": "Use center alignment for toolbar", + "FrmMain.MnuResizeTool": "Resize image", + "FrmSettings.Layout._Toolbar": "Barra d'eines", + "FrmMain.MnuHelp": "Ajuda", + "_.ImageOrderBy._FileSize": "File size", + "FrmSettings._Theme._OpenThemeFolder": "Obre la carpeta del tema", + "FrmMain.MnuNavigation": "Navegació", + "_._Save": "Desa", + "FrmQuickSetup._SettingProfileDescription": "To modify these settings, simply access app settings.", + "_._UserAction._MenuNotFound": "Cannot find menu '{0}' to invoke the action", + "FrmMain.MnuPanToLeftSide": "Pan image to left edge", + "FrmUpdate._CurrentVersion": "Current version: {0}", + "FrmCrop.BtnSettings._Tooltip": "Open Crop tool settings", + "_.ColorProfileOption._Custom": "Personalitzat…", + "FrmSettings._UseEmbeddedThumbnailOtherFormats": "Load only the embedded thumbnail for other formats", + "FrmMain.MnuGoToFirst": "Go to first image", + "FrmSettings._ExportLanguagePack": "Export language pack…", + "FrmSettings.Nav._Mouse": "Mouse", + "_.ImageOrderBy._DateCreated": "Data de creació", + "FrmSettings._EnableFullscreenSlideshow": "Start slideshow in Full Screen mode", + "FrmAbout._Homepage": "Homepage:", + "FrmSettings._GalleryCacheSizeInMb": "Maximum gallery cache size (in megabytes)", + "FrmMain.MnuCopyImageData._Success": "Copied the current image data.", + "FrmSettings._EnableLoopBackNavigation": "Loop back to the first image when reaching the end of the image list", + "_.MouseWheelEvent._Scroll": "Scroll", + "FrmCrop.BtnSave._Tooltip": "Desa la imatge", + "FrmMain.MnuSlideshow": "Presentació", + "FrmMain.MnuShare": "Compartir…", + "FrmSettings._SlideshowNotification": "Slideshow notification", + "FrmMain.MnuViewChannels": "Veure canals", + "FrmSettings._Refresh": "Actualitzar", + "_._UserAction._MethodNotFound": "Cannot find method '{0}' to invoke the action", + "FrmMain.MnuCopyFile": "Copy file", + "_._CreatingFile": "Creating a temporary image file…", + "FrmMain.MnuToggleTopMost": "Mantè la finestra sempre en primer pla", + "FrmMain.MnuLosslessCompression._Confirm": "Are you sure you want to proceed?", + "FrmMain.MnuImage": "Imatge", + "FrmSettings._StartupBoost._Enabled": "Startup Boost is enabled", + "FrmQuickSetup._SetDefaultViewer": "Do you want to set ImageGlass as the default photo viewer?", + "FrmMain.MnuScaleToWidth": "Escalar a l'ample", + "_._FileExtension": "Extensió del fitxer", + "FrmUpdate._PublishedDate": "Published date: {0}", + "_._DoNotShowThisMessageAgain": "Do not show this message again", + "_.ImageInterpolation._NearestNeighbor": "Nearest neighbor", + "FrmCrop.LblLocation": "Location:", + "_._Download": "Download", + "_.Metadata._ColorProfile": "Perfil de color", + "FrmSettings._CenterWindowFit": "Automatically center the window in Window Fit mode", + "FrmSettings._ImageLoadingOrder": "Ordre de càrrega d'imatges", + "FrmSettings._GalleryColumns": "Number of thumbnail columns in vertical gallery layout", + "_._Quit": "Quit", + "_._Add": "Afegeix", + "FrmMain.MnuChangeBackgroundColor": "Change background color…", + "FrmMain.MnuToggleToolbar": "Barra d'eines", + "FrmAbout._Contact": "Contacte", + "FrmSettings.Toolbar._AddCustomButton": "Add a custom button…", + "FrmCrop.BtnQuickSelect._Tooltip": "Quick select…", + "FrmMain.MnuCutFile._Success": "S'han retallat {0} fitxer(s).", + "FrmSettings._ZoomSpeed": "Zoom speed", + "FrmMain.MnuToggleTopMost._Disable": "Disabled window always on top", + "FrmSettings._ShouldUseExplorerSortOrder": "Use Explorer sort order if possible", + "_.ImageInterpolation._Antisotropic": "Antisotropic", + "FrmMain._ReachedFirstImage": "Està a l'última imatge", + "_._UnhandledException": "Unhandled exception", + "FrmResize.LblNewSize": "New Size:", + "FrmMain._ClipboardImage": "Clipboard image", + "FrmMain.MnuExportFrames": "Export image frames…", + "FrmMain.MnuFile": "Fitxer", + "_._Close": "Tanca", + "FrmMain.MnuMain": "Menú principal", + "_._ResetToDefault": "Restableix els valors per defecte", + "FrmSettings.Nav._Gallery": "Gallery", + "FrmMain.MnuSetDefaultPhotoViewer._Success": "You have successfully set ImageGlass as default photo viewer.", + "FrmSettings._HideGalleryInFullscreen": "Hide gallery in Full Screen mode", + "FrmSettings._AvailableImageInfoTags": "Available tags:", + "FrmExportFrames._Exporting": "Exporting {0}/{1} frames \r\n{2}…", + "_._Argument": "Argument", + "FrmSettings._ImageEditQuality": "Qualitat d'imatge", + "_._ID": "ID", + "FrmSettings._UserConfigFile": "User settings file (igconfig.json)", + "FrmMain.MnuLoadingOrders": "Loading orders", + "FrmSettings._OpenSaveAsDialogInTheCurrentImageDir": "Open the Save As dialog in the current image directory", + "_.MouseWheelEvent._ShiftAndScroll": "Hold Shift and scroll", + "FrmSettings._UseSmoothZooming": "Use smooth zooming", + "FrmSettings._Theme": "Tema", + "FrmSettings._ImageBoosterCacheMaxDimension": "Maximum image dimension to be cached (in pixels)", + "FrmMain.MnuScaleToHeight": "Escalar a l'alt", + "_.Metadata._FileLastWriteTime": "Date modified", + "FrmSettings._Author": "Autor", + "FrmSettings._Others": "Altres", + "_.MouseWheelAction._PanVertically": "Pan up / down", + "FrmSettings._MouseWheelAction": "Mouse wheel action", + "FrmSettings.Nav._Tools": "Eines", + "FrmMain.MnuSetDesktopBackground._Error": "Could not set the viewing image as desktop background", + "FrmSettings.Toolbar._Errors._ButtonExecutableRequired": "Button executable required.", + "_.ImageOrderBy._DateAccessed": "Data d'accés", + "FrmSettings._ThumbnailSize": "Thumbnail size (in pixels)", + "FrmSettings._FileFormats": "File formats", + "FrmMain.MnuReloadImageList": "Recarrega la llista d'imatges", + "FrmSettings._UseWebview2ForSvg": "Use Webview2 for viewing SVG format", + "FrmCrop.BtnCopy": "Copia", + "FrmSettings._CurrentMonitorProfile._Description": "ImageGlass no actualitza el color automàticament al moure la finestra entre monitors", + "FrmMain.PicMain._ErrorText": "Could not open this image", + "FrmSettings.Tools._AddNewTool": "Add an external tool", + "FrmMain.MnuRename": "Renombrar la imatge…", + "FrmMain.MnuViewLastFrame": "View last frame", + "_._Webview2._NotFound": "Please install WebView2 Runtime to access full features of ImageGlass.", + "FrmMain.MnuGetMoreTools": "Get more tools…", + "FrmSettings.Nav._Appearance": "Appearance", + "FrmSettings._SlideshowInterval": "Interval de la presentació:", + "_.ImageInterpolation._HighQualityBicubic": "High quality bicubic", + "FrmColorPickerSettings.ChkShowHsvA": "Use HSV format with alpha value", + "FrmSettings.Tools._EditTool": "Edit external tool", + "_._Error": "Error", + "FrmSettings._ImageBoosterCacheMaxFileSizeInMb": "Maximum image file size to be cached (in megabytes)", + "_._UnhandledException._Description": "Unhandled exception has occurred. If you click Continue, the application will ignore this error and attempt to continue. If you click Quit, the application will close immediately.", + "_.Metadata._FileSize": "File size", + "FrmSettings.Toolbar._ButtonJson": "Button JSON", + "FrmQuickSetup._SetDefaultViewer._Description": "You can reset it in the app settings > File type associations tab.", + "FrmSettings.Nav._Edit": "Editar", + "FrmMain.MnuToggleGallery": "Gallery panel", + "_._IgCommandExe._DefaultError._Description": "Make sure you pass the correct commands!\r\nThis executable file contains command-line functions for ImageGlass software.\r\n\r\nTo explore all command lines, please visit:\r\n{0}", + "FrmMain.MnuLosslessCompression._Compressing": "Performing lossless compression…", + "FrmSettings._ShouldGroupImagesByDirectory": "Agrupa les imatges per directori", + "FrmMain.MnuPanToRightSide": "Pan image to right edge", + "_.Metadata._ExifRatingPercent": "Rating", + "FrmSettings._PanSpeed": "Panning speed", + "_._CheckForUpdate": "Comprovar actualitzacions…", + "FrmSettings.Layout._ToolbarContext": "Contextual toolbar", + "_.ImageInfo._FrameCount": "{0} frame(s)", + "FrmMain.MnuLayout": "Distribució", + "_._Website": "Lloc web", + "FrmMain.MnuPasteImage": "Paste image", + "FrmSettings._ShowGalleryScrollbars": "Show gallery scrollbars" + } +} \ No newline at end of file diff --git a/Setup/Assets/Language/Chinese Simplified.iglang.json b/Setup/Assets/Language/Chinese Simplified.iglang.json new file mode 100644 index 000000000..2f7435aeb --- /dev/null +++ b/Setup/Assets/Language/Chinese Simplified.iglang.json @@ -0,0 +1,504 @@ +{ + "_Metadata": { + "Code": "zh-CN", + "EnglishName": "Chinese (Simplified)", + "LocalName": "简体中文", + "Author": "小恐龙", + "MinVersion": "9.3" + }, + "Items": { + "FrmCrop.SelectionAspectRatio._Original": "原版", + "FrmMain.MnuShare._Error": "无法打开共享对话框。", + "_.Metadata._FileLastAccessTime": "访问日期", + "FrmAbout._License": "软件许可证", + "FrmSettings.Toolbar._Errors._ButtonIdDuplicated": "已存在 ID '{0}'的按钮。 请为按钮选择一个不同和唯一的ID来避免冲突。", + "FrmMain.MnuSave._Confirm": "您确定要覆盖此图像吗?", + "FrmSettings._OpenDefaultAppsSetting": "打开默认应用设置", + "FrmMain.MnuCopyPath": "复制图像路径", + "FrmCropSettings.DefaultSelectionType._SelectNone": "不选", + "_.MouseWheelAction._PanHorizontally": "向左/向右平移", + "FrmMain.MnuPrint": "打印...", + "FrmSettings.Toolbar._ToolbarButtons": "工具栏按钮", + "FrmResize.LblResample": "重采样:", + "_.ImageOrderBy._Extension": "扩展名", + "FrmSettings.Nav._Viewer": "查看器", + "FrmSettings.EditAppDialog._EditApp": "编辑应用", + "FrmCrop.BtnReset._Tooltip": "重置选区", + "FrmMain.MnuRename._Description": "输入新文件名:", + "_._No": "否", + "FrmSlideshow.MnuToggleCountdown": "显示每页幻灯片播放倒计时", + "FrmSettings._OpenStartupAppsSetting": "打开启动应用设置", + "FrmMain.MnuViewPreviousFrame": "查看上一帧", + "_.ImageOrderBy._DateModified": "修改日期", + "FrmMain.MnuViewNextFrame": "查看下一帧", + "FrmMain.MnuUnload": "卸载图像", + "FrmSettings.Toolbar._HideToolbarInFullscreen": "全屏模式隐藏工具栏", + "_.ImageOrderType._Desc": "降序", + "_._Update": "更新", + "FrmSettings._EnableImageAsyncLoading": "启用图像异步加载", + "FrmSettings._DefaultPhotoViewer._Description": "在 Windows 中注册 ImageGlass 支持的格式。 您可能需要打开默认应用设置并手动从列表中选择 ImageGlass 才能生效。", + "_.MouseWheelAction._BrowseImages": "查看下一张/上一张图片", + "FrmSettings._EditApps": "图像编辑应用", + "FrmColorPickerSettings.ChkShowCIELabA": "使用含 Alpha 值的 CIELAB 格式", + "_._GetHelp": "获取帮助", + "FrmQuickSetup._SkipQuickSetup": "跳过并启动 ImageGlass", + "FrmColorPickerSettings._Title": "拾色器设置", + "_._Copy": "复制", + "FrmSettings._ImageBoosterCacheCount": "图像加速器缓存的图像数量 (单向)", + "FrmMain.MnuPanToBottom": "平移图像至底部", + "FrmMain.MnuZoom": "缩放", + "FrmCropSettings.ChkCloseToolAfterSaving": "保存后关闭裁剪工具", + "FrmSettings._ShowWelcomeImage": "显示欢迎图像", + "FrmSettings._ColorProfile": "色彩配置文件", + "FrmSettings._Theme._UninstallTheme": "卸载主题包", + "FrmMain._OpenWith": "使用 {0} 打开", + "FrmMain.MnuRemoveDefaultPhotoViewer": "移除默认照片查看器", + "_.AfterEditAppAction._Nothing": "无", + "FrmCrop.BtnSave": "保存", + "FrmMain.MnuScaleToFit": "适配窗口", + "FrmToolNotFound.LblDownloadToolText": "您可以在 ImageGlass 下载更多工具:", + "_._LearnMore": "了解更多…", + "FrmCrop.LblAspectRatio": "长宽比:", + "FrmExportFrames._FileNotExist": "图像文件不存在", + "FrmSettings._LightTheme": "浅色", + "FrmSettings.Nav._Slideshow": "幻灯片", + "_._Continue": "继续", + "_._AddHotkey": "添加热键…", + "FrmMain.MnuSetDesktopBackground": "设置为桌面背景", + "FrmMain.MnuReload": "重新加载图像", + "FrmSlideshow.MnuExitSlideshow": "退出幻灯片播放", + "FrmMain.MnuAutoZoom": "自动缩放", + "FrmSettings._ShowImagePreview": "加载时显示图像预览", + "FrmCrop.BtnCopy._Tooltip": "复制所选区域到剪贴板", + "FrmSettings.Nav._Toolbar": "工具栏", + "FrmMain.MnuSave._Error": "无法保存图像", + "FrmSettings._AfterEditingAction": "打开编辑软件后", + "FrmSettings._ShouldUseColorProfileForAll": "对无内嵌颜色配置文件的图像启用", + "FrmCropSettings.DefaultSelectionType._UseTheLastSelection": "使用上次选择", + "FrmSettings._SlideshowInterval._From": "从", + "FrmSettings._ImageInterpolation": "图像插值", + "FrmQuickSetup._StepInfo": "步骤 {0}", + "FrmMain.MnuColorPicker": "取色工具", + "FrmCrop.SelectionAspectRatio._FreeRatio": "自由比例", + "FrmSettings._ResetSettings": "重置设置", + "FrmSettings._Startup": "启动", + "_.BackdropStyle._None": "无", + "FrmSettings._LoadDefaultZoomLevels": "载入默认缩放级别", + "FrmColorPicker.BtnSettings._Tooltip": "打开拾色器设置…", + "FrmSettings._UseThemeForDarkMode": "将此主题用于深色模式", + "FrmSettings._ShowDeleteConfirmation": "删除文件时显示确认对话框", + "FrmSettings._ShowAppIcon": "在标题栏上显示应用图标", + "_._InvalidAction": "无效操作", + "FrmQuickSetup._SelectProfile": "选择一个配置文件", + "_.Metadata._FileCreationTime": "创建日期", + "FrmSettings._SlideshowImagesToNotifySound": "触发通知声音的图像数量", + "FrmSettings._BackgroundColor": "查看器背景色", + "FrmSettings._RealTimeFileUpdate": "实时文件更新", + "_.ColorProfileOption._CurrentMonitorProfile": "当前显示器配置文件", + "FrmSettings._EnableCutMultipleFiles": "允许一次剪切多个文件", + "FrmSettings._AutoUpdate": "自动检查更新", + "FrmCropSettings.LblDefaultSelection": "默认选择设置", + "FrmSettings._UseThemeForLightMode": "将此主题用于浅色模式", + "FrmSettings._ZoomLevels": "缩放等级", + "FrmMain.MnuSetLockScreen._Success": "锁屏图像已更新", + "FrmSettings._ShowGalleryFileName": "显示缩略图文件名", + "FrmSettings.Layout._Order": "顺序", + "FrmCropSettings.ChkAutoCenterSelection": "自动中心选择", + "FrmSettings.Nav._FileTypeAssociations": "关联格式", + "_._Back": "返回", + "FrmMain.MnuSetDesktopBackground._Success": "桌面背景已更新", + "FrmSettings._ShouldAutoOpenNewAddedImage": "自动打开新添加的图像", + "FrmCrop.SelectionAspectRatio._Custom": "自定义...", + "FrmMain.MnuCopyPath._Success": "已复制当前图像路径。", + "FrmSettings._StartupBoost._Error": "无法更改自启动设置", + "FrmToolNotFound.LblDescription": "ImageGlass 无法定位可执行文件 '{0}' 的路径。 要解决这个问题,请按需更新 '{0}' 的路径。", + "FrmMain.MnuClearClipboard": "清空剪贴板", + "FrmSettings._ColorManagement": "色彩管理", + "FrmMain._ReachedLastLast": "已到达最后一个图像", + "FrmMain.MnuPanUp": "向上平移图像", + "FrmMain.MnuRemoveDefaultPhotoViewer._Success": "ImageGlass 现已不再是默认的照片查看器。", + "FrmSettings._GetMoreLanguagePacks": "获取更多语言包…", + "FrmAbout._Privacy": "隐私政策", + "FrmSettings._EnableRecursiveLoading": "加载子文件夹中的图像", + "_._UserAction._MethodArgumentNotSupported": "不支持\"{0}\"方法的参数类型", + "FrmSettings._FileExtensionIcons._Description": "为了自定义文件扩展图标,下载图标包,将所有.ICO 文件放置在扩展图标文件夹中,然后单击'{0}' 按钮。 这将设置 ImageGlass 为默认照片查看器。", + "_.ImageOrderType._Asc": "升序", + "FrmExportFrames._Title": "导出图像帧", + "_._Install": "安装...", + "FrmMain.MnuFlipHorizontal": "水平翻转", + "FrmSettings._OpenExtensionIconFolder": "打开扩展图标文件夹", + "FrmAbout._Collaborator": "合作者:", + "FrmQuickSetup._ConfirmCloseProcess": "在应用新设置之前,我们需要关闭所有 ImageGlass 进程。 您准备继续吗?", + "FrmExportFrames._ExportDone": "已成功导出 {0} 帧到 \n{1}", + "FrmCrop.BtnSaveAs._Tooltip": "保存为副本...", + "FrmMain.MnuOpenFile": "打开...", + "FrmColorPickerSettings.ChkShowRgbA": "使用含 Alpha 值的 RGB 格式", + "_.ImageInfo._ListCount": "{0} 个文件", + "FrmMain.MnuGoToLast": "跳转到最后一张图像", + "FrmSettings._EditApps._AppName": "应用程序名称", + "FrmSettings._SlideshowBackgroundColor": "幻灯片背景颜色", + "FrmAbout._Email": "电子邮箱:", + "_.MouseWheelAction._DoNothing": "不采取任何操作", + "FrmMain.MnuSaveAs": "另存为...", + "FrmMain._Loading": "正在加载…", + "_._Browse": "浏览...", + "FrmMain.MnuSetDefaultPhotoViewer._Error": "无法设置 ImageGlass 为默认照片查看器。", + "FrmSettings.Nav._Language": "语言", + "FrmQuickSetup._SeeWhatNew": "查看该版本更新内容...", + "FrmSettings._ImageInterpolation._ScaleUp": "当缩放> 100%", + "FrmSettings.Layout._ToolbarContextPosition": "上下文工具栏位置", + "FrmMain.MnuDeleteFromHardDisk": "永久删除", + "FrmSettings._EmbeddedThumbnail": "内嵌缩略图", + "FrmMain.MnuDeleteFromHardDisk._Description": "您确定要永久删除此文件吗?", + "FrmMain.MnuScaleToFill": "填满窗口", + "FrmCrop.BtnCrop": "裁剪", + "_.AfterEditAppAction._Minimize": "最小化", + "FrmMain.MnuInvertColors": "反色", + "FrmSettings._StartupBoost": "自启动", + "FrmMain.MnuViewFirstFrame": "查看第一帧", + "_.MouseWheelEvent._CtrlAndScroll": "按住 Ctrl 滚动", + "FrmSettings._HideMainWindowInSlideshow": "自动隐藏主窗口", + "_.Metadata._FrameCount": "帧数", + "FrmSettings._EnableCopyMultipleFiles": "允许一次复制多个文件", + "FrmMain.MnuFrameless._EnableDescription": "按住 Shift 键移动窗口。", + "_.ImageOrderBy._ExifDateTaken": "EXIF:日期已使用", + "FrmAbout._Credits": "致谢", + "FrmSettings._AddNewFileExtension": "添加新文件扩展名", + "FrmMain.MnuQuickSetup": "打开 ImageGlass 快速设置", + "FrmMain.MnuSave._Success": "图片已保存", + "FrmMain.MnuPanLeft": "向左平移图像", + "FrmUpdate._StatusChecking": "正在检查更新…", + "FrmSettings.Nav._Layout": "布局", + "FrmMain.MnuOpenWith": "打开方式...", + "FrmAbout._Thanks": "特别致谢:", + "_._Warning": "警告", + "FrmSettings.Nav._Keyboard": "热键", + "FrmSlideshow._PauseSlideshow": "幻灯片已暂停。", + "_._Add+": "添加...", + "_._Email": "电子邮箱", + "FrmMain.MnuPanDown": "向下平移图像", + "_._Cancel": "取消", + "_._OK": "确认", + "FrmMain.MnuPanRight": "向右平移图像", + "_.Position._Right": "右侧", + "_._Icon": "图标", + "FrmSettings._ShouldLoadHiddenImages": "加载隐藏图像", + "_._InvalidAction._Transformation": "ImageGlass 不支持旋转、翻转该图像。", + "FrmSettings._MakeDefault": "设为默认", + "FrmMain.MnuCopyImageData._Copying": "正在复制图像数据。 这需要一些时间…", + "FrmSettings._UseEmbeddedThumbnailRawFormats": "仅为RAW格式加载缩略图", + "_.ImageInterpolation._Linear": "线性", + "FrmSettings._ImageInfoTags": "图像信息标签", + "FrmSettings._FileExtensionIcons": "文件扩展图标", + "FrmMain.MnuEdit._AppNotFound": "找不到关联的编辑器。 您可以在 ImageGlass 设置 > 编辑 中选择程序来编辑此格式的图像。", + "_.ColorProfileOption._None": "无", + "FrmSettings._TotalSupportedFormats": "支持的格式总数: {0}", + "FrmSettings._Clipboard": "剪贴板", + "_._UserAction._Win32ExeError": "无法执行命令“{0}”。 请确保名称正确。", + "FrmCropSettings.DefaultSelectionType._SelectX": "选择{0}", + "_.AfterEditAppAction._Close": "关闭", + "FrmAbout._LogoDesigner": "Logo 设计师:", + "_.ImageOrderBy._Name": "文件名(默认)", + "FrmMain.MnuRemoveDefaultPhotoViewer._Error": "无法移除 ImageGlass 为默认照片查看器。", + "FrmExportFrames._FolderPickerTitle": "为导出图像帧选择输出文件夹", + "FrmAbout._Donate": "捐赠", + "FrmMain.MnuFrameNav": "帧导航", + "FrmMain.MnuSetLockScreen": "设置为锁屏背景", + "_._Delete": "删除", + "FrmMain.MnuViewPrevious": "查看上一张图像", + "_.Position._Top": "顶部", + "FrmSettings.Toolbar._CurrentButtons": "当前按钮:", + "FrmMain.MnuAbout": "关于", + "FrmSettings._RemoveDefault": "移除默认", + "_._Description": "说明", + "FrmMain.MnuPasteImage._Error": "在剪贴板中找不到图像数据", + "FrmMain.MnuSettings": "设置", + "FrmCropSettings._Title": "裁剪设置", + "FrmSettings.Toolbar._ToolbarIconHeight": "工具栏图标大小", + "FrmSettings._SlideshowInterval._To": "到", + "FrmSettings.Layout._ToolbarPosition": "工具栏位置", + "FrmUpdate._StatusUpdated": "您正在使用最新版本!", + "FrmMain.MnuExit": "退出", + "_._Webview2._Outdated": "您的 WebView2 运行时不受支持。 请更新到版本 {0} 或更高版本。", + "_._Yes": "是", + "FrmMain.MnuRotateLeft": "向左旋转", + "FrmSettings._EnableStartupBoost": "启用自启动", + "_.ImageOrderBy._ExifRating": "EXIF:评分", + "FrmMain.MnuZoomIn": "放大", + "_.Metadata._ColorSpace": "色彩空间", + "FrmAbout._Version": "版本:", + "FrmMain.MnuToggleTopMost._Enable": "窗口置顶已启用", + "FrmSettings.Toolbar._AvailableButtons": "可用按钮:", + "FrmMain.MnuSave._Saving": "正在保存图像...", + "FrmQuickSetup._StandardUser": "标准用户", + "FrmMain.MnuSetLockScreen._Error": "无法将当前图像设置为锁屏", + "FrmSettings.Nav._Image": "图像", + "FrmSettings._Theme._InstallTheme": "安装主题包", + "FrmSettings._EnableMultiInstances": "允许运行多个实例", + "FrmMain.MnuCropTool": "裁剪图像", + "_._IgCommandExe._DefaultError._Heading": "无效命令", + "_._Refresh": "刷新", + "FrmMain.MnuLosslessCompression._Description": "此工具使用 Magick.NET 库进行无损压缩,优化文件大小。 仅在压缩文件小于原始文件时覆盖。", + "_._MoveDown": "下移", + "FrmSettings._GetExtensionIconPacks": "获取扩展图标包...", + "FrmSettings._InAppMessageDuration": "应用内消息持续时间 (毫秒)", + "FrmMain.MnuFrameless": "无边框模式", + "_._Reset": "重置", + "FrmSettings._ConfigDir": "配置文件位置", + "FrmQuickSetup._SettingsWillBeApplied": "以下设置将被应用:", + "FrmSettings._UnmanagedSettingReminder": "此设置不由 ImageGlass 管理。 请在您删除或移动应用之前禁用它,因为ImageGlass 不会自动处理。", + "FrmMain.MnuClipboard": "剪贴板", + "FrmMain.MnuCustomZoom": "自定义缩放...", + "FrmSettings._DisplayLanguage": "显示语言", + "FrmMain.MnuPrint._Error": "无法打印此图像", + "FrmSettings._ShouldPreserveModifiedDate": "保存时保留图像原始修改日期", + "FrmSettings._ShowSaveOverrideConfirmation": "覆盖文件时显示确认对话框", + "FrmColorPickerSettings.ChkShowHexA": "使用含 Alpha 值的 HEX 格式", + "FrmMain.MnuFullScreen": "全屏", + "FrmSettings._StartupDir": "启动位置", + "FrmSettings._ShowCheckerboardOnlyImageRegion": "仅在图像区域内显示棋盘格", + "FrmMain.MnuClearClipboard._Success": "清除剪贴板。", + "FrmQuickSetup._Text": "ImageGlass 快速设置", + "FrmMain.MnuLosslessCompression._Done": "无损压缩完成\r\n新文件大小为 {0},已保存 {1}。", + "FrmMain.MnuLosslessCompression": "Magick.NET 无损压缩", + "FrmResize.RadResizeByPercentage": "百分比", + "FrmSettings._StartupBoost._Disabled": "自启动已禁用", + "FrmMain.MnuToggleCheckerboard": "启用网格背景", + "FrmSettings._MinEmbeddedThumbnailSize._Height": "高度", + "FrmSettings.Nav._General": "一般", + "FrmSettings._ImageLoading": "图像加载", + "FrmSettings._ShowSlideshowCountdown": "显示每页幻灯片播放倒计时", + "FrmMain.MnuSave": "保存", + "FrmMain.MnuMoveToRecycleBin": "移入回收站", + "FrmMain.MnuRefresh": "刷新", + "FrmToolNotFound.LblHeading": "'{0}' 未找到!", + "FrmMain.MnuReportIssue": "问题反馈", + "FrmMain.MnuCopyImageData": "复制图像数据", + "FrmMain.MnuCheckForUpdate._NewVersion": "有新的版本可用!", + "_._Empty": "(空)", + "FrmSettings._Zooming": "缩放", + "FrmMain.MnuCutFile": "剪切文件", + "FrmHotkeyPicker.LblHotkey": "按下热键", + "FrmSettings.Layout._Gallery": "相册", + "FrmMain.MnuNewWindow": "新建窗口", + "FrmMain.MnuMoveToRecycleBin._Description": "您想要将此文件移动到回收站吗?", + "FrmSettings._DefaultPhotoViewer": "默认照片查看器", + "_.Metadata._ExifDateTimeOriginal": "EXIF: DateTimeOriginal", + "FrmMain.MnuRotateRight": "向右旋转", + "FrmSettings._MinEmbeddedThumbnailSize": "要加载的嵌入缩略图最小尺寸", + "FrmMain.MnuSetDefaultPhotoViewer": "设为默认照片查看器", + "FrmMain.MnuImageProperties": "图像属性", + "FrmSettings._EnableNavigationButtons": "显示导航箭头按钮", + "_._Edit": "编辑", + "FrmSettings._ImageBooster": "图像加速器", + "FrmSettings.Tools._IntegratedWith": "与 {0} 集成", + "_._Next": "下一步", + "FrmExportFrames._OpenOutputFolder": "打开输出文件夹", + "FrmMain.MnuOpenLocation": "打开图片所在位置", + "FrmMain.MnuLockZoom": "锁定缩放比例", + "FrmSettings._StartupBoost._Description": "在 Windows 启动时预加载并短暂后台运行以加速 ImageGlass 的首次启动。", + "FrmSettings._WindowBackdrop": "窗口背景", + "FrmSettings._EnableRealTimeFileUpdate": "监控文件夹中的文件更改并实时更新", + "_._NotSupported": "不支持的格式", + "FrmSettings._Theme._GetMoreThemes": "获取更多主题包…", + "FrmMain.MnuNewWindow._Error": "无法打开新窗口,因为只允许一个实例", + "FrmMain.MnuZoomOut": "缩小", + "FrmSettings.Toolbar._EditButton": "编辑工具栏按钮", + "FrmMain.MnuCustomZoom._Description": "输入一个新的缩放值", + "FrmResize.RadResizeByPixels": "像素", + "FrmMain.MnuEdit": "编辑图像 {0}", + "FrmSettings.Layout._GalleryPosition": "相册位置", + "FrmMain.MnuWindowFit": "窗口适配", + "FrmMain._OpenFileDialog": "所有支持的文件", + "FrmSettings._UseRandomIntervalForSlideshow": "使用随机切换间隔", + "_.Position._Left": "左侧", + "FrmSettings._ShouldOpenLastSeenImage": "打开上次查看过的图像", + "_.Position._Bottom": "底部", + "FrmResize.ChkKeepRatio": "保持比例", + "FrmMain.MnuGoTo": "跳转到...", + "FrmSlideshow.MnuPauseResumeSlideshow": "暂停/恢复幻灯片", + "FrmSettings.Tools._Integrated": "集成", + "FrmSettings._Contributors": "贡献者", + "_.MouseWheelAction._Zoom": "放大 / 缩小", + "_._CommandPreview": "命令预览", + "FrmSettings._DarkTheme": "深色", + "_._Hotkeys": "热键", + "_.Metadata._ExifDateTime": "EXIF: DateTime", + "FrmSettings.Toolbar._Errors._ButtonIdRequired": "需要按钮 ID。", + "FrmSettings._MinEmbeddedThumbnailSize._Width": "宽度", + "_._Executable": "可执行文件", + "_.ImageInterpolation._MultiSampleLinear": "多重采样(线性)", + "_._Separator": "分隔符", + "FrmQuickSetup._ProfessionalUser": "专业用户", + "FrmMain.MnuFlipVertical": "垂直翻转", + "FrmSlideshow._ResumeSlideshow": "幻灯片已恢复。", + "FrmCropSettings.DefaultSelectionType._CustomArea": "自定义区域…", + "FrmMain.MnuActualSize": "实际大小", + "FrmCrop.BtnSaveAs": "另存为...", + "FrmSettings._InstallNewLanguagePack": "安装新的语言包…", + "FrmSlideshow.MnuZoomModes": "缩放模式", + "FrmMain.MnuTools": "工具", + "_.ImageInterpolation._Cubic": "三次插值", + "FrmUpdate._LatestVersion": "最新版本: {0}", + "FrmMain.MnuViewNext": "查看下一张图像", + "_.MouseWheelEvent._AltAndScroll": "按住 Alt 滚动", + "FrmToolNotFound._Title": "工具未找到", + "FrmCrop.BtnCrop._Tooltip": "仅裁剪图像", + "FrmSettings.EditAppDialog._AddApp": "添加一个应用程序进行编辑", + "FrmMain.MnuPanning": "移动", + "_._MoveUp": "上移", + "FrmCropSettings.DefaultSelectionType._SelectAll": "全选", + "_._Name": "名称", + "FrmColorPickerSettings.ChkShowHslA": "使用含 Alpha 值的 HSL 格式", + "FrmMain.MnuToggleImageAnimation": "开始/停止图像动画", + "FrmSettings._DisableStartupBoost": "禁用自启动", + "FrmMain.MnuCopyFile._Success": "已复制 {0} 个文件。", + "FrmMain.MnuSave._ConfirmDescription": "ImageGlass 并非专业照片编辑器,请注意在保存图像时,质量、元数据、图层等信息可能丢失。", + "FrmToolNotFound.BtnSelectExecutable": "选择…", + "FrmUpdate._StatusOutdated": "发现新版本!", + "_.ImageOrderBy._Random": "随机", + "FrmResize.LblCurrentSize": "当前大小:", + "_._Apply": "应用", + "FrmAbout._Slogan": "一个轻量的、通用的图像查看器", + "FrmMain.MnuPanToTop": "平移图像至顶部", + "FrmSettings.Toolbar._AddNewButton": "添加自定义工具栏按钮", + "FrmCrop.LblSize": "大小:", + "FrmSettings._ImageInterpolation._ScaleDown": "缩放比例 < 100% 时", + "_._CreatingFileError": "无法创建临时图像文件", + "FrmMain.MnuGoTo._Description": "输入图像序号,并按 Enter 以查看", + "FrmSettings.Toolbar._EnableCenterToolbar": "工具栏居中", + "FrmMain.MnuResizeTool": "缩放图片", + "FrmSettings.Layout._Toolbar": "工具栏", + "FrmMain.MnuHelp": "帮助", + "_.ImageOrderBy._FileSize": "文件大小", + "FrmSettings._Theme._OpenThemeFolder": "打开主题目录...", + "FrmMain.MnuNavigation": "导航", + "_._Save": "保存", + "FrmQuickSetup._SettingProfileDescription": "要修改这些设置,只需访问应用设置。", + "_._UserAction._MenuNotFound": "找不到要调用的菜单{0}'", + "FrmMain.MnuPanToLeftSide": "平移图像至左侧", + "FrmUpdate._CurrentVersion": "当前版本: {0}", + "FrmCrop.BtnSettings._Tooltip": "打开裁剪工具设置", + "_.ColorProfileOption._Custom": "自定义...", + "FrmSettings._UseEmbeddedThumbnailOtherFormats": "仅为其他格式加载缩略图", + "FrmMain.MnuGoToFirst": "跳转到第一张图像", + "FrmSettings._ExportLanguagePack": "导出语言包...", + "FrmSettings.Nav._Mouse": "鼠标", + "_.ImageOrderBy._DateCreated": "创建日期", + "FrmSettings._EnableFullscreenSlideshow": "以全屏模式启动幻灯片", + "FrmAbout._Homepage": "主页:", + "FrmSettings._GalleryCacheSizeInMb": "相册最大缓存(MB)", + "FrmMain.MnuCopyImageData._Success": "当前图像数据已复制。", + "FrmSettings._EnableLoopBackNavigation": "到达图像列表末尾时循环到第一张图像", + "_.MouseWheelEvent._Scroll": "滚动", + "FrmCrop.BtnSave._Tooltip": "保存图像", + "FrmMain.MnuSlideshow": "幻灯片", + "FrmMain.MnuShare": "分享到...", + "FrmSettings._SlideshowNotification": "幻灯片通知", + "FrmMain.MnuViewChannels": "查看图像通道", + "FrmSettings._Refresh": "刷新", + "_._UserAction._MethodNotFound": "找不到方法 '{0}' 来调用操作", + "FrmMain.MnuCopyFile": "复制文件", + "_._CreatingFile": "创建临时图像文件…", + "FrmMain.MnuToggleTopMost": "保持窗口最前", + "FrmMain.MnuLosslessCompression._Confirm": "您确定要操作吗?", + "FrmMain.MnuImage": "图像", + "FrmSettings._StartupBoost._Enabled": "自启动已启用", + "FrmQuickSetup._SetDefaultViewer": "您要设置 ImageGlass 为默认的照片查看器吗?", + "FrmMain.MnuScaleToWidth": "适配宽度", + "_._FileExtension": "文件扩展名", + "FrmUpdate._PublishedDate": "发布日期: {0}", + "_._DoNotShowThisMessageAgain": "不再显示此消息", + "_.ImageInterpolation._NearestNeighbor": "邻点插值法", + "FrmCrop.LblLocation": "位置:", + "_._Download": "下载", + "_.Metadata._ColorProfile": "色彩配置文件", + "FrmSettings._CenterWindowFit": "启用窗口适应图像实际大小模式时,自动将窗口居于屏幕正中", + "FrmSettings._ImageLoadingOrder": "图像加载顺序", + "FrmSettings._GalleryColumns": "垂直相册布局中缩略图的列数", + "_._Quit": "退出", + "_._Add": "添加", + "FrmMain.MnuChangeBackgroundColor": "更改背景色…", + "FrmMain.MnuToggleToolbar": "工具栏", + "FrmAbout._Contact": "联系方式", + "FrmSettings.Toolbar._AddCustomButton": "添加自定义按钮…", + "FrmCrop.BtnQuickSelect._Tooltip": "快速选择…", + "FrmMain.MnuCutFile._Success": "已剪切 {0} 个文件。", + "FrmSettings._ZoomSpeed": "缩放速度", + "FrmMain.MnuToggleTopMost._Disable": "窗口置顶已禁用", + "FrmSettings._ShouldUseExplorerSortOrder": "如可用,使用资源管理器的排序", + "_.ImageInterpolation._Antisotropic": "各向异性抗性", + "FrmMain._ReachedFirstImage": "已到达第一个图像", + "_._UnhandledException": "未处理的异常", + "FrmResize.LblNewSize": "新的大小:", + "FrmMain._ClipboardImage": "剪贴板图像", + "FrmMain.MnuExportFrames": "导出图像帧…", + "FrmMain.MnuFile": "文件", + "_._Close": "关闭", + "FrmMain.MnuMain": "主菜单", + "_._ResetToDefault": "恢复默认值", + "FrmSettings.Nav._Gallery": "相册", + "FrmMain.MnuSetDefaultPhotoViewer._Success": "您已成功设置 ImageGlass 为默认照片查看器。", + "FrmSettings._HideGalleryInFullscreen": "全屏模式隐藏相册", + "FrmSettings._AvailableImageInfoTags": "可用标签:", + "FrmExportFrames._Exporting": "正在导出 {0}/{1} 帧 \n{2}...", + "_._Argument": "参数", + "FrmSettings._ImageEditQuality": "图像质量", + "_._ID": "ID", + "FrmSettings._UserConfigFile": "用户设置文件(igconfig.json)", + "FrmMain.MnuLoadingOrders": "加载顺序", + "FrmSettings._OpenSaveAsDialogInTheCurrentImageDir": "在当前图像目录中打开另存为对话框", + "_.MouseWheelEvent._ShiftAndScroll": "按住 Shift 滚动", + "FrmSettings._UseSmoothZooming": "使用平滑缩放", + "FrmSettings._Theme": "主题", + "FrmSettings._ImageBoosterCacheMaxDimension": "要缓存的最大图像尺寸 (像素)", + "FrmMain.MnuScaleToHeight": "适配高度", + "_.Metadata._FileLastWriteTime": "修改日期", + "FrmSettings._Author": "作者", + "FrmSettings._Others": "其它", + "_.MouseWheelAction._PanVertically": "向上/向下平移", + "FrmSettings._MouseWheelAction": "鼠标滚轮动作", + "FrmSettings.Nav._Tools": "工具", + "FrmMain.MnuSetDesktopBackground._Error": "无法将当前图片设置为桌面", + "FrmSettings.Toolbar._Errors._ButtonExecutableRequired": "需要可执行的按钮。", + "_.ImageOrderBy._DateAccessed": "访问日期", + "FrmSettings._ThumbnailSize": "缩略图大小(像素)", + "FrmSettings._FileFormats": "文件格式", + "FrmMain.MnuReloadImageList": "重新加载图像列表", + "FrmSettings._UseWebview2ForSvg": "使用 Webview2 查看 SVG 格式", + "FrmCrop.BtnCopy": "复制", + "FrmSettings._CurrentMonitorProfile._Description": "ImageGlass 窗口在不同显示器间移动时,不会自动更新颜色配置文件", + "FrmMain.PicMain._ErrorText": "无法打开此图像", + "FrmSettings.Tools._AddNewTool": "添加外部工具", + "FrmMain.MnuRename": "重命名图像...", + "FrmMain.MnuViewLastFrame": "查看最后一帧", + "_._Webview2._NotFound": "请安装 WebView2 运行时的最新版本。", + "FrmMain.MnuGetMoreTools": "获取更多工具…", + "FrmSettings.Nav._Appearance": "外观", + "FrmSettings._SlideshowInterval": "幻灯片放映间隔:", + "_.ImageInterpolation._HighQualityBicubic": "高质量双立方", + "FrmColorPickerSettings.ChkShowHsvA": "使用含 Alpha 值的 HSV 格式", + "FrmSettings.Tools._EditTool": "编辑外部工具", + "_._Error": "错误", + "FrmSettings._ImageBoosterCacheMaxFileSizeInMb": "要缓存的最大图像文件大小(MB)", + "_._UnhandledException._Description": "发生了无法处理的异常。 如果点击继续,应用程序将忽略此错误并尝试继续。 如果点击退出,应用程序将立即关闭。", + "_.Metadata._FileSize": "文件大小", + "FrmSettings.Toolbar._ButtonJson": "JSON 按钮", + "FrmQuickSetup._SetDefaultViewer._Description": "您可以在应用程序设置 > 文件类型关联选项卡中重置它。", + "FrmSettings.Nav._Edit": "编辑", + "FrmMain.MnuToggleGallery": "相册面板", + "_._IgCommandExe._DefaultError._Description": "请确保您输入了正确的命令!\r\n该可执行文件包含 ImageGlass 软件的命令行功能。\r\n\r\n要探索所有命令行, 请访问:\n{0}", + "FrmMain.MnuLosslessCompression._Compressing": "无损压缩中…", + "FrmSettings._ShouldGroupImagesByDirectory": "按目录分组图像", + "FrmMain.MnuPanToRightSide": "平移图像至右侧", + "_.Metadata._ExifRatingPercent": "评级", + "FrmSettings._PanSpeed": "平移速度", + "_._CheckForUpdate": "检查更新...", + "FrmSettings.Layout._ToolbarContext": "上下文工具栏", + "_.ImageInfo._FrameCount": "{0} frame(s)", + "FrmMain.MnuLayout": "布局", + "_._Website": "网站", + "FrmMain.MnuPasteImage": "粘贴图像", + "FrmSettings._ShowGalleryScrollbars": "显示相册滚动条" + } +} \ No newline at end of file diff --git a/Setup/Assets/Language/Chinese Traditional.iglang.json b/Setup/Assets/Language/Chinese Traditional.iglang.json new file mode 100644 index 000000000..bbf80940f --- /dev/null +++ b/Setup/Assets/Language/Chinese Traditional.iglang.json @@ -0,0 +1,504 @@ +{ + "_Metadata": { + "Code": "zh-TW", + "EnglishName": "Taiwanese Mandarin", + "LocalName": "正體中文", + "Author": "Jeff", + "MinVersion": "9.3" + }, + "Items": { + "FrmCrop.SelectionAspectRatio._Original": "原始", + "FrmMain.MnuShare._Error": "無法開啟分享對話方塊。", + "_.Metadata._FileLastAccessTime": "存取日期", + "FrmAbout._License": "軟體授權條款", + "FrmSettings.Toolbar._Errors._ButtonIdDuplicated": "ID 為「{0}」的按鈕已定義。 請為您的按鈕選擇不同且獨一無二的 ID 以避免衝突。", + "FrmMain.MnuSave._Confirm": "您確定要覆蓋此圖片嗎?", + "FrmSettings._OpenDefaultAppsSetting": "開啟預設應用程式設定", + "FrmMain.MnuCopyPath": "複製圖片路徑", + "FrmCropSettings.DefaultSelectionType._SelectNone": "取消選擇", + "_.MouseWheelAction._PanHorizontally": "向左/右平移", + "FrmMain.MnuPrint": "列印…", + "FrmSettings.Toolbar._ToolbarButtons": "工具列按鈕", + "FrmResize.LblResample": "重新採樣:", + "_.ImageOrderBy._Extension": "副檔名", + "FrmSettings.Nav._Viewer": "檢視器", + "FrmSettings.EditAppDialog._EditApp": "編輯應用程式", + "FrmCrop.BtnReset._Tooltip": "重設選取", + "FrmMain.MnuRename._Description": "輸入新檔案名稱:", + "_._No": "No", + "FrmSlideshow.MnuToggleCountdown": "顯示幻燈片倒數", + "FrmSettings._OpenStartupAppsSetting": "開啟「啟動應用程式」", + "FrmMain.MnuViewPreviousFrame": "檢視上一個框架", + "_.ImageOrderBy._DateModified": "修改日期", + "FrmMain.MnuViewNextFrame": "檢視下一個框架", + "FrmMain.MnuUnload": "重新載入影像", + "FrmSettings.Toolbar._HideToolbarInFullscreen": "全螢幕模式下隱藏工具列", + "_.ImageOrderType._Desc": "降冪排序", + "_._Update": "更新", + "FrmSettings._EnableImageAsyncLoading": "啟用影像非同步載入", + "FrmSettings._DefaultPhotoViewer._Description": "向 Windows 註冊 ImageGlass 支援的格式。 您可能需要開啟「預設應用程式」設定並手動從清單中選取 ImageGlass 才能生效。", + "_.MouseWheelAction._BrowseImages": "檢視下一個/上一個影像", + "FrmSettings._EditApps": "影像編輯應用程式", + "FrmColorPickerSettings.ChkShowCIELabA": "使用帶有 alpha 值的 CIELAB 格式", + "_._GetHelp": "取得協助", + "FrmQuickSetup._SkipQuickSetup": "略過此步驟並啟動 ImageGlass", + "FrmColorPickerSettings._Title": "色彩挑選器設定", + "_._Copy": "複製", + "FrmSettings._ImageBoosterCacheCount": "影像加速器快取的影像數量(單向)", + "FrmMain.MnuPanToBottom": "將影像平移至底部", + "FrmMain.MnuZoom": "縮放", + "FrmCropSettings.ChkCloseToolAfterSaving": "儲存後關閉裁剪工具", + "FrmSettings._ShowWelcomeImage": "顯示歡迎影像", + "FrmSettings._ColorProfile": "色彩設定檔", + "FrmSettings._Theme._UninstallTheme": "解除安裝佈景主題包", + "FrmMain._OpenWith": "使用 {0} 開啟", + "FrmMain.MnuRemoveDefaultPhotoViewer": "移除預設的照片檢視程式", + "_.AfterEditAppAction._Nothing": "沒動作", + "FrmCrop.BtnSave": "儲存", + "FrmMain.MnuScaleToFit": "縮放到適合的大小", + "FrmToolNotFound.LblDownloadToolText": "您可以在以下位置為 ImageGlass 下載更多工具:", + "_._LearnMore": "取得更多資訊……", + "FrmCrop.LblAspectRatio": "長寬比:", + "FrmExportFrames._FileNotExist": "影像檔不存在", + "FrmSettings._LightTheme": "淺色", + "FrmSettings.Nav._Slideshow": "幻燈片", + "_._Continue": "繼續", + "_._AddHotkey": "新增快捷鍵……", + "FrmMain.MnuSetDesktopBackground": "設定為桌面背景", + "FrmMain.MnuReload": "重新載入圖片", + "FrmSlideshow.MnuExitSlideshow": "結束幻燈片放映", + "FrmMain.MnuAutoZoom": "自動縮放", + "FrmSettings._ShowImagePreview": "載入時顯示影像預覽", + "FrmCrop.BtnCopy._Tooltip": "將選取區複製到剪貼簿中", + "FrmSettings.Nav._Toolbar": "工具列", + "FrmMain.MnuSave._Error": "無法儲存影像", + "FrmSettings._AfterEditingAction": "在開啟編輯應用程式後", + "FrmSettings._ShouldUseColorProfileForAll": "也會套用至沒有內嵌色彩描述檔的圖片", + "FrmCropSettings.DefaultSelectionType._UseTheLastSelection": "使用最後的選取", + "FrmSettings._SlideshowInterval._From": "來自", + "FrmSettings._ImageInterpolation": "影像插值", + "FrmQuickSetup._StepInfo": "步驟 {0}", + "FrmMain.MnuColorPicker": "顏色選擇器", + "FrmCrop.SelectionAspectRatio._FreeRatio": "自由比例", + "FrmSettings._ResetSettings": "重設設定", + "FrmSettings._Startup": "啟動", + "_.BackdropStyle._None": "無", + "FrmSettings._LoadDefaultZoomLevels": "載入預設縮放層級", + "FrmColorPicker.BtnSettings._Tooltip": "開啟色彩挑選器設定……", + "FrmSettings._UseThemeForDarkMode": "為深色模式使用此佈景主題", + "FrmSettings._ShowDeleteConfirmation": "刪除檔案時顯示確認訊息框", + "FrmSettings._ShowAppIcon": "在標題列上顯示應用程式圖示", + "_._InvalidAction": "無效動作", + "FrmQuickSetup._SelectProfile": "選取設定檔", + "_.Metadata._FileCreationTime": "建立日期", + "FrmSettings._SlideshowImagesToNotifySound": "觸發聲音通知的影像數量", + "FrmSettings._BackgroundColor": "檢視程式背景色彩", + "FrmSettings._RealTimeFileUpdate": "即時檔案更新", + "_.ColorProfileOption._CurrentMonitorProfile": "複製螢幕設定檔", + "FrmSettings._EnableCutMultipleFiles": "啟用一次剪下多個檔案", + "FrmSettings._AutoUpdate": "自動檢查更新", + "FrmCropSettings.LblDefaultSelection": "預設選取區設定", + "FrmSettings._UseThemeForLightMode": "為淺色模式使用此佈景主題", + "FrmSettings._ZoomLevels": "縮放等級", + "FrmMain.MnuSetLockScreen._Success": "鎖定畫面影像已更新", + "FrmSettings._ShowGalleryFileName": "顯示縮圖檔案名稱", + "FrmSettings.Layout._Order": "順序", + "FrmCropSettings.ChkAutoCenterSelection": "自動置中選取區", + "FrmSettings.Nav._FileTypeAssociations": "檔案類型關聯", + "_._Back": "上一步", + "FrmMain.MnuSetDesktopBackground._Success": "桌面背景已更新", + "FrmSettings._ShouldAutoOpenNewAddedImage": "自動開啟新增的影像", + "FrmCrop.SelectionAspectRatio._Custom": "自訂…", + "FrmMain.MnuCopyPath._Success": "已複製目前的影像路徑。", + "FrmSettings._StartupBoost._Error": "無法變更「啟動加速」設定", + "FrmToolNotFound.LblDescription": "ImageGlass 找不到「{0}」可執行檔的路徑。 要解決此問題,請根據需要更新「{0}」的路徑。", + "FrmMain.MnuClearClipboard": "清除剪貼簿", + "FrmSettings._ColorManagement": "色彩管理", + "FrmMain._ReachedLastLast": "到達最後一張圖片", + "FrmMain.MnuPanUp": "向上平移影像", + "FrmMain.MnuRemoveDefaultPhotoViewer._Success": "ImageGlass 不再是預設的照片檢視程式。", + "FrmSettings._GetMoreLanguagePacks": "取得更多語言包…", + "FrmAbout._Privacy": "隱私權政策", + "FrmSettings._EnableRecursiveLoading": "載入子資料夾中的影像", + "_._UserAction._MethodArgumentNotSupported": "不支援方法「{0}」的引數類型", + "FrmSettings._FileExtensionIcons._Description": "若要自訂檔案副檔名圖示,請下載圖示包,將所有 .ICO 檔案放入副檔名圖示資料夾中,然後按一下「{0}」按鈕。 這將會把 ImageGlass 設定為預設的照片檢視程式。", + "_.ImageOrderType._Asc": "昇冪排序", + "FrmExportFrames._Title": "匯出影像框架", + "_._Install": "安裝…", + "FrmMain.MnuFlipHorizontal": "水平翻轉", + "FrmSettings._OpenExtensionIconFolder": "開啟副檔名圖示資料夾", + "FrmAbout._Collaborator": "協作者:", + "FrmQuickSetup._ConfirmCloseProcess": "在套用新設定之前,必須關閉所有 ImageGlass 處理程序。 準備好繼續了嗎?", + "FrmExportFrames._ExportDone": "已成功匯出 {0} 個框架到 \n{1}", + "FrmCrop.BtnSaveAs._Tooltip": "另存為副本……", + "FrmMain.MnuOpenFile": "開啟檔案…", + "FrmColorPickerSettings.ChkShowRgbA": "使用帶有 alpha 值的 RGB 格式", + "_.ImageInfo._ListCount": "{0} 個檔案", + "FrmMain.MnuGoToLast": "跳到最後一張影像", + "FrmSettings._EditApps._AppName": "應用程式名稱", + "FrmSettings._SlideshowBackgroundColor": "投影片放映背景色彩", + "FrmAbout._Email": "電子郵件:", + "_.MouseWheelAction._DoNothing": "什麼也不做", + "FrmMain.MnuSaveAs": "另存為…", + "FrmMain._Loading": "正在載入……", + "_._Browse": "瀏覽…", + "FrmMain.MnuSetDefaultPhotoViewer._Error": "無法將 ImageGlass 設定為預設的照片檢視程式。", + "FrmSettings.Nav._Language": "語言", + "FrmQuickSetup._SeeWhatNew": "看看這個版本有什麼新功能……", + "FrmSettings._ImageInterpolation._ScaleUp": "當縮放 > 100%", + "FrmSettings.Layout._ToolbarContextPosition": "情境工具列位置", + "FrmMain.MnuDeleteFromHardDisk": "永久刪除", + "FrmSettings._EmbeddedThumbnail": "內嵌的縮圖", + "FrmMain.MnuDeleteFromHardDisk._Description": "您確定要永久刪除此檔案嗎?", + "FrmMain.MnuScaleToFill": "縮放到填滿", + "FrmCrop.BtnCrop": "裁剪", + "_.AfterEditAppAction._Minimize": "最小化", + "FrmMain.MnuInvertColors": "反轉色彩", + "FrmSettings._StartupBoost": "啟動加速", + "FrmMain.MnuViewFirstFrame": "檢視第一個框架", + "_.MouseWheelEvent._CtrlAndScroll": "按住 Ctrl 並捲動", + "FrmSettings._HideMainWindowInSlideshow": "自動隱藏主視窗", + "_.Metadata._FrameCount": "框架", + "FrmSettings._EnableCopyMultipleFiles": "啟用一次複製多個檔案", + "FrmMain.MnuFrameless._EnableDescription": "按住 Shift 鍵以移動視窗。", + "_.ImageOrderBy._ExifDateTaken": "EXIF:拍攝日期", + "FrmAbout._Credits": "感謝名單", + "FrmSettings._AddNewFileExtension": "新增副檔名", + "FrmMain.MnuQuickSetup": "開啟 ImageGlass 快速設定", + "FrmMain.MnuSave._Success": "影像已儲存", + "FrmMain.MnuPanLeft": "向左平移影像", + "FrmUpdate._StatusChecking": "正在檢查更新……", + "FrmSettings.Nav._Layout": "佈局", + "FrmMain.MnuOpenWith": "開啟用…", + "FrmAbout._Thanks": "特別感謝:", + "_._Warning": "警告", + "FrmSettings.Nav._Keyboard": "鍵盤", + "FrmSlideshow._PauseSlideshow": "投影片放映已暫停。", + "_._Add+": "新增…", + "_._Email": "電子郵件", + "FrmMain.MnuPanDown": "向下平移影像", + "_._Cancel": "取消", + "_._OK": "確定", + "FrmMain.MnuPanRight": "向右平移影像", + "_.Position._Right": "右", + "_._Icon": "圖示", + "FrmSettings._ShouldLoadHiddenImages": "載入隱藏的影像", + "_._InvalidAction._Transformation": "ImageGlass 不支援旋轉、翻轉此影像。", + "FrmSettings._MakeDefault": "設為預設值", + "FrmMain.MnuCopyImageData._Copying": "正在複製影像資料。 這需要一點時間……", + "FrmSettings._UseEmbeddedThumbnailRawFormats": "僅為 RAW 格式載入內嵌縮圖", + "_.ImageInterpolation._Linear": "線性", + "FrmSettings._ImageInfoTags": "影像資訊標籤", + "FrmSettings._FileExtensionIcons": "檔案副檔名圖示", + "FrmMain.MnuEdit._AppNotFound": "找不到用於編輯的關聯應用程式。 您可以在 ImageGlass「設定」→「編輯」中指定一個應用程式來編輯此格式。", + "_.ColorProfileOption._None": "無", + "FrmSettings._TotalSupportedFormats": "支援的格式總數:{0}", + "FrmSettings._Clipboard": "剪貼簿", + "_._UserAction._Win32ExeError": "無法執行命令「{0}」。 確保名稱正確。", + "FrmCropSettings.DefaultSelectionType._SelectX": "選擇 {0}", + "_.AfterEditAppAction._Close": "關閉", + "FrmAbout._LogoDesigner": "標誌設計師:", + "_.ImageOrderBy._Name": "名稱(預設)", + "FrmMain.MnuRemoveDefaultPhotoViewer._Error": "無法移除 ImageGlass 作為預設照片檢視程式的地位。", + "FrmExportFrames._FolderPickerTitle": "選取供匯出影像框架的輸出資料夾", + "FrmAbout._Donate": "捐款", + "FrmMain.MnuFrameNav": "畫面導覽", + "FrmMain.MnuSetLockScreen": "設定為鎖定畫面圖片", + "_._Delete": "刪除", + "FrmMain.MnuViewPrevious": "檢視前一張圖片", + "_.Position._Top": "頂部", + "FrmSettings.Toolbar._CurrentButtons": "目前按鈕:", + "FrmMain.MnuAbout": "關於", + "FrmSettings._RemoveDefault": "移除預設值", + "_._Description": "描述", + "FrmMain.MnuPasteImage._Error": "剪貼簿中找不到影像資料", + "FrmMain.MnuSettings": "設定", + "FrmCropSettings._Title": "裁剪設定", + "FrmSettings.Toolbar._ToolbarIconHeight": "工具列圖示大小", + "FrmSettings._SlideshowInterval._To": "至", + "FrmSettings.Layout._ToolbarPosition": "工具列位置", + "FrmUpdate._StatusUpdated": "您目前使用的是最新版本!", + "FrmMain.MnuExit": "離開", + "_._Webview2._Outdated": "不支援您的 WebView2 執行時期。 請更新至版本 {0} 或更新。", + "_._Yes": "是", + "FrmMain.MnuRotateLeft": "向左旋轉", + "FrmSettings._EnableStartupBoost": "啟用啟動加速", + "_.ImageOrderBy._ExifRating": "EXIF:評分", + "FrmMain.MnuZoomIn": "放大", + "_.Metadata._ColorSpace": "色彩空間", + "FrmAbout._Version": "版本:", + "FrmMain.MnuToggleTopMost._Enable": "視窗一律在頂部已啟用", + "FrmSettings.Toolbar._AvailableButtons": "可用按鈕:", + "FrmMain.MnuSave._Saving": "正在儲存影像……", + "FrmQuickSetup._StandardUser": "標準使用者", + "FrmMain.MnuSetLockScreen._Error": "無法將正在檢視的影像設定會鎖定畫面影像", + "FrmSettings.Nav._Image": "圖片", + "FrmSettings._Theme._InstallTheme": "安裝佈景主題包", + "FrmSettings._EnableMultiInstances": "允許程式執行多個實體", + "FrmMain.MnuCropTool": "裁剪影像", + "_._IgCommandExe._DefaultError._Heading": "無效的命令", + "_._Refresh": "重新整理", + "FrmMain.MnuLosslessCompression._Description": "此工具使用 Magick.NET 函式庫進行無損壓縮與最佳化檔案大小。 僅當壓縮檔案比原始檔案小時才覆寫。", + "_._MoveDown": "往下移動", + "FrmSettings._GetExtensionIconPacks": "取得副檔名圖示包……", + "FrmSettings._InAppMessageDuration": "應用程式內訊息持續時間(毫秒)", + "FrmMain.MnuFrameless": "無邊框", + "_._Reset": "重設", + "FrmSettings._ConfigDir": "設定位置", + "FrmQuickSetup._SettingsWillBeApplied": "將會套用的設定:", + "FrmSettings._UnmanagedSettingReminder": "此設定不受 ImageGlass 管理。 不要忘記在刪除或變更應用程式位置前停用它,因為 ImageGlass 不會自動處理此問題。", + "FrmMain.MnuClipboard": "剪貼簿", + "FrmMain.MnuCustomZoom": "自訂縮放…", + "FrmSettings._DisplayLanguage": "顯示語言", + "FrmMain.MnuPrint._Error": "無法列印正在檢視的影像", + "FrmSettings._ShouldPreserveModifiedDate": "儲存圖片的修改日期", + "FrmSettings._ShowSaveOverrideConfirmation": "覆寫檔案時顯示確認訊息框", + "FrmColorPickerSettings.ChkShowHexA": "使用帶有 alpha 值的 HEX 格式", + "FrmMain.MnuFullScreen": "全畫面", + "FrmSettings._StartupDir": "啟動位置", + "FrmSettings._ShowCheckerboardOnlyImageRegion": "僅在影像區域內顯示棋盤格", + "FrmMain.MnuClearClipboard._Success": "已清除剪貼簿。", + "FrmQuickSetup._Text": "ImageGlass 快速設定", + "FrmMain.MnuLosslessCompression._Done": "完成無損壓縮。\r\n新檔案大小為 {0},已節省 {1}。", + "FrmMain.MnuLosslessCompression": "Magick.NET 無損壓縮", + "FrmResize.RadResizeByPercentage": "百分比", + "FrmSettings._StartupBoost._Disabled": "已停用啟動加速", + "FrmMain.MnuToggleCheckerboard": "棋盤格紋背景", + "FrmSettings._MinEmbeddedThumbnailSize._Height": "高度", + "FrmSettings.Nav._General": "一般", + "FrmSettings._ImageLoading": "圖片載入", + "FrmSettings._ShowSlideshowCountdown": "顯示幻燈片倒數", + "FrmMain.MnuSave": "儲存", + "FrmMain.MnuMoveToRecycleBin": "移動至資源回收筒", + "FrmMain.MnuRefresh": "重新整理", + "FrmToolNotFound.LblHeading": "找不到「{0}」!", + "FrmMain.MnuReportIssue": "問題回報…", + "FrmMain.MnuCopyImageData": "複製圖片資料", + "FrmMain.MnuCheckForUpdate._NewVersion": "有可用的新版本!", + "_._Empty": "(空)", + "FrmSettings._Zooming": "縮放", + "FrmMain.MnuCutFile": "剪下檔案", + "FrmHotkeyPicker.LblHotkey": "按下快捷鍵", + "FrmSettings.Layout._Gallery": "圖庫", + "FrmMain.MnuNewWindow": "開啟新視窗", + "FrmMain.MnuMoveToRecycleBin._Description": "您真的想要移動此檔案至資源回收筒?", + "FrmSettings._DefaultPhotoViewer": "預設照片檢視程式", + "_.Metadata._ExifDateTimeOriginal": "EXIF: DateTimeOriginal", + "FrmMain.MnuRotateRight": "向右旋轉", + "FrmSettings._MinEmbeddedThumbnailSize": "要載入的內嵌縮圖最小大小", + "FrmMain.MnuSetDefaultPhotoViewer": "設定預設照片檢視程式", + "FrmMain.MnuImageProperties": "圖片屬性", + "FrmSettings._EnableNavigationButtons": "顯示導航箭頭按鈕", + "_._Edit": "編輯", + "FrmSettings._ImageBooster": "影像加速器", + "FrmSettings.Tools._IntegratedWith": "與 {0} 整合", + "_._Next": "下一步", + "FrmExportFrames._OpenOutputFolder": "開啟輸出資料夾", + "FrmMain.MnuOpenLocation": "開啟圖片位置", + "FrmMain.MnuLockZoom": "鎖定縮放比例", + "FrmSettings._StartupBoost._Description": "在 Windows 啟動期間在背景預先載入並執行 ImageGlass 幾秒鐘,以加速首次啟動。", + "FrmSettings._WindowBackdrop": "視窗背景", + "FrmSettings._EnableRealTimeFileUpdate": "監視正在檢視的資料夾中的檔案變更並即時更新", + "_._NotSupported": "不支援的格式", + "FrmSettings._Theme._GetMoreThemes": "取得更多佈景主題包……", + "FrmMain.MnuNewWindow._Error": "因為僅允許一個實體,所以無法開啟新視窗", + "FrmMain.MnuZoomOut": "縮小", + "FrmSettings.Toolbar._EditButton": "編輯工具列按鈕", + "FrmMain.MnuCustomZoom._Description": "輸入新的縮放值", + "FrmResize.RadResizeByPixels": "畫素", + "FrmMain.MnuEdit": "編輯圖片 {0}…", + "FrmSettings.Layout._GalleryPosition": "圖庫位置", + "FrmMain.MnuWindowFit": "適合視窗", + "FrmMain._OpenFileDialog": "所有支援的檔案", + "FrmSettings._UseRandomIntervalForSlideshow": "使用隨機間隔", + "_.Position._Left": "左", + "FrmSettings._ShouldOpenLastSeenImage": "開啟上次檢視的影像", + "_.Position._Bottom": "底部", + "FrmResize.ChkKeepRatio": "維持比例", + "FrmMain.MnuGoTo": "跳至…", + "FrmSlideshow.MnuPauseResumeSlideshow": "暫停/恢復投影片放映", + "FrmSettings.Tools._Integrated": "整合", + "FrmSettings._Contributors": "貢獻者", + "_.MouseWheelAction._Zoom": "放大/縮小", + "_._CommandPreview": "指令預覽", + "FrmSettings._DarkTheme": "深色", + "_._Hotkeys": "快捷鍵", + "_.Metadata._ExifDateTime": "EXIF: DateTime", + "FrmSettings.Toolbar._Errors._ButtonIdRequired": "需要按鈕 ID。", + "FrmSettings._MinEmbeddedThumbnailSize._Width": "寬度", + "_._Executable": "可執行檔", + "_.ImageInterpolation._MultiSampleLinear": "多重採樣線性", + "_._Separator": "分隔符號", + "FrmQuickSetup._ProfessionalUser": "專業使用者", + "FrmMain.MnuFlipVertical": "垂直翻轉", + "FrmSlideshow._ResumeSlideshow": "投影片放映已恢復。", + "FrmCropSettings.DefaultSelectionType._CustomArea": "自訂區域……", + "FrmMain.MnuActualSize": "實際大小", + "FrmCrop.BtnSaveAs": "另存為…", + "FrmSettings._InstallNewLanguagePack": "安裝新語言包……", + "FrmSlideshow.MnuZoomModes": "縮放模式", + "FrmMain.MnuTools": "工具", + "_.ImageInterpolation._Cubic": "立方", + "FrmUpdate._LatestVersion": "最新版本:{0}", + "FrmMain.MnuViewNext": "檢視下一張圖片", + "_.MouseWheelEvent._AltAndScroll": "按住 Alt 並捲動", + "FrmToolNotFound._Title": "找不到工具", + "FrmCrop.BtnCrop._Tooltip": "僅裁剪影像", + "FrmSettings.EditAppDialog._AddApp": "新增用於編輯的應用程式", + "FrmMain.MnuPanning": "平移", + "_._MoveUp": "往上移動", + "FrmCropSettings.DefaultSelectionType._SelectAll": "選取全部", + "_._Name": "名稱", + "FrmColorPickerSettings.ChkShowHslA": "使用帶有 alpha 值的 HSL 格式", + "FrmMain.MnuToggleImageAnimation": "開始/停止動畫影像", + "FrmSettings._DisableStartupBoost": "停用啟動加速", + "FrmMain.MnuCopyFile._Success": "已複製 {0} 個檔案。", + "FrmMain.MnuSave._ConfirmDescription": "ImageGlass 並不是專業照片編輯器,請注意,在您儲存圖片時會遺失品質、詮釋資料、圖層等等。", + "FrmToolNotFound.BtnSelectExecutable": "選取……", + "FrmUpdate._StatusOutdated": "有可用的更新!", + "_.ImageOrderBy._Random": "隨機", + "FrmResize.LblCurrentSize": "目前大小:", + "_._Apply": "套用", + "FrmAbout._Slogan": "輕巧快速且多功能的圖片檢視器", + "FrmMain.MnuPanToTop": "將影像平移至頂部", + "FrmSettings.Toolbar._AddNewButton": "新增自訂工具列按鈕", + "FrmCrop.LblSize": "大小:", + "FrmSettings._ImageInterpolation._ScaleDown": "當縮放 < 100%", + "_._CreatingFileError": "無法建立暫存影像檔", + "FrmMain.MnuGoTo._Description": "輸入要檢視的影像索引,然後按下 ENTER", + "FrmSettings.Toolbar._EnableCenterToolbar": "工具列使用置中對齊", + "FrmMain.MnuResizeTool": "調整圖片大小", + "FrmSettings.Layout._Toolbar": "工具列", + "FrmMain.MnuHelp": "說明", + "_.ImageOrderBy._FileSize": "檔案大小", + "FrmSettings._Theme._OpenThemeFolder": "開啟佈景主題資料夾", + "FrmMain.MnuNavigation": "導航", + "_._Save": "儲存", + "FrmQuickSetup._SettingProfileDescription": "要修改這些設定,只要造訪應用程式設定。", + "_._UserAction._MenuNotFound": "找不到選單「{0}」來呼叫動作", + "FrmMain.MnuPanToLeftSide": "將影像平移至左側", + "FrmUpdate._CurrentVersion": "目前版本:{0}", + "FrmCrop.BtnSettings._Tooltip": "開啟裁剪工具設定", + "_.ColorProfileOption._Custom": "自訂…", + "FrmSettings._UseEmbeddedThumbnailOtherFormats": "僅為其他格式載入內嵌縮圖", + "FrmMain.MnuGoToFirst": "跳到第一張影像", + "FrmSettings._ExportLanguagePack": "匯出語言包……", + "FrmSettings.Nav._Mouse": "滑鼠", + "_.ImageOrderBy._DateCreated": "建立日期", + "FrmSettings._EnableFullscreenSlideshow": "在全螢幕模式開始投影片放映", + "FrmAbout._Homepage": "首頁:", + "FrmSettings._GalleryCacheSizeInMb": "最大圖庫快取大小(以 MB 為單位)", + "FrmMain.MnuCopyImageData._Success": "已複製目前的影像資料。", + "FrmSettings._EnableLoopBackNavigation": "在到達影像清單結尾時循環回到第一張影像", + "_.MouseWheelEvent._Scroll": "捲動", + "FrmCrop.BtnSave._Tooltip": "儲存圖片", + "FrmMain.MnuSlideshow": "幻燈片", + "FrmMain.MnuShare": "分享…", + "FrmSettings._SlideshowNotification": "投影片放映通知", + "FrmMain.MnuViewChannels": "檢視頻道", + "FrmSettings._Refresh": "重新整理", + "_._UserAction._MethodNotFound": "找不到方法「{0}」來呼叫動作", + "FrmMain.MnuCopyFile": "複製檔案", + "_._CreatingFile": "建立暫存影像檔……", + "FrmMain.MnuToggleTopMost": "將視窗永遠置於最上層", + "FrmMain.MnuLosslessCompression._Confirm": "您確定要繼續嗎?", + "FrmMain.MnuImage": "圖片", + "FrmSettings._StartupBoost._Enabled": "已啟用啟動加速", + "FrmQuickSetup._SetDefaultViewer": "您想要將 ImageGlass 設定為預設照片檢視程式?", + "FrmMain.MnuScaleToWidth": "縮放至與寬度相符", + "_._FileExtension": "副檔名", + "FrmUpdate._PublishedDate": "發佈日期:{0}", + "_._DoNotShowThisMessageAgain": "不要再顯示此訊息", + "_.ImageInterpolation._NearestNeighbor": "最接近像素", + "FrmCrop.LblLocation": "位置:", + "_._Download": "下載", + "_.Metadata._ColorProfile": "色彩設定檔", + "FrmSettings._CenterWindowFit": "在調整視窗大小模式中自動將視窗置中", + "FrmSettings._ImageLoadingOrder": "圖片載入順序", + "FrmSettings._GalleryColumns": "垂直圖庫佈局中縮圖列的數量", + "_._Quit": "離開", + "_._Add": "新增", + "FrmMain.MnuChangeBackgroundColor": "變更背景色彩……", + "FrmMain.MnuToggleToolbar": "工具列", + "FrmAbout._Contact": "連絡", + "FrmSettings.Toolbar._AddCustomButton": "新增自訂按鈕……", + "FrmCrop.BtnQuickSelect._Tooltip": "快速選取……", + "FrmMain.MnuCutFile._Success": "已複製 {0} 個檔案。", + "FrmSettings._ZoomSpeed": "縮放速度", + "FrmMain.MnuToggleTopMost._Disable": "已停用視窗一律在頂部", + "FrmSettings._ShouldUseExplorerSortOrder": "若可能,請使用檔案總管排序順序", + "_.ImageInterpolation._Antisotropic": "非均向性", + "FrmMain._ReachedFirstImage": "到達第一張圖片", + "_._UnhandledException": "未處理的異常", + "FrmResize.LblNewSize": "新的大小:", + "FrmMain._ClipboardImage": "剪貼簿影像", + "FrmMain.MnuExportFrames": "匯出影像框架……", + "FrmMain.MnuFile": "檔案", + "_._Close": "關閉", + "FrmMain.MnuMain": "主選單", + "_._ResetToDefault": "重設為預設值", + "FrmSettings.Nav._Gallery": "圖庫", + "FrmMain.MnuSetDefaultPhotoViewer._Success": "您已成功將 ImageGlass 設定為預設的照片檢視程式。", + "FrmSettings._HideGalleryInFullscreen": "全螢幕模式下隱藏圖庫", + "FrmSettings._AvailableImageInfoTags": "可用的標籤:", + "FrmExportFrames._Exporting": "正在匯出 {0}/{1} 個框架 \n{2}……", + "_._Argument": "引述", + "FrmSettings._ImageEditQuality": "影像品質", + "_._ID": "ID", + "FrmSettings._UserConfigFile": "使用者設定檔 (igconfig.json)", + "FrmMain.MnuLoadingOrders": "正在載入順序", + "FrmSettings._OpenSaveAsDialogInTheCurrentImageDir": "在目前影像目錄中開啟「另存為」對話方塊", + "_.MouseWheelEvent._ShiftAndScroll": "按住 Shift 並捲動", + "FrmSettings._UseSmoothZooming": "使用平滑縮放", + "FrmSettings._Theme": "佈景主題", + "FrmSettings._ImageBoosterCacheMaxDimension": "要快取的最大影像尺寸(以畫素為單位)", + "FrmMain.MnuScaleToHeight": "縮放至與高度相符", + "_.Metadata._FileLastWriteTime": "修改日期", + "FrmSettings._Author": "作者", + "FrmSettings._Others": "其他", + "_.MouseWheelAction._PanVertically": "向上/下平移", + "FrmSettings._MouseWheelAction": "滑鼠滾輪動作", + "FrmSettings.Nav._Tools": "工具", + "FrmMain.MnuSetDesktopBackground._Error": "無法將正在檢視的影像設定為桌面背景", + "FrmSettings.Toolbar._Errors._ButtonExecutableRequired": "需要按鈕可執行檔。", + "_.ImageOrderBy._DateAccessed": "存取日期", + "FrmSettings._ThumbnailSize": "縮圖大小(以畫素為單位)", + "FrmSettings._FileFormats": "檔案格式", + "FrmMain.MnuReloadImageList": "重新載入圖片清單", + "FrmSettings._UseWebview2ForSvg": "使用 Webview2 以檢視 SVG 格式", + "FrmCrop.BtnCopy": "複製", + "FrmSettings._CurrentMonitorProfile._Description": "在螢幕間移動視窗時,ImageGlass 不會自動更新色彩", + "FrmMain.PicMain._ErrorText": "無法開啟此影像", + "FrmSettings.Tools._AddNewTool": "新增外部工具", + "FrmMain.MnuRename": "圖片更名為…", + "FrmMain.MnuViewLastFrame": "檢視最後一個框架", + "_._Webview2._NotFound": "請安裝 WebView2 執行時期的最新版本。", + "FrmMain.MnuGetMoreTools": "取得更多工具……", + "FrmSettings.Nav._Appearance": "外觀", + "FrmSettings._SlideshowInterval": "投影片放映間隔:", + "_.ImageInterpolation._HighQualityBicubic": "高品質雙三次", + "FrmColorPickerSettings.ChkShowHsvA": "使用帶有 alpha 值的 HSV 格式", + "FrmSettings.Tools._EditTool": "編輯外部工具", + "_._Error": "錯誤", + "FrmSettings._ImageBoosterCacheMaxFileSizeInMb": "要快取的最大影像檔案大小(以 MB 為單位)", + "_._UnhandledException._Description": "遇到未處理的例外。 若您點擊繼續,應用程式將會忽略此錯誤並嘗試繼續。 若按一下離開,應用程式將會立刻關閉。", + "_.Metadata._FileSize": "檔案大小", + "FrmSettings.Toolbar._ButtonJson": "按鈕 JSON", + "FrmQuickSetup._SetDefaultViewer._Description": "您可以在應用程式設定→「檔案類型關聯」分頁中重設。", + "FrmSettings.Nav._Edit": "編輯", + "FrmMain.MnuToggleGallery": "圖庫面板", + "_._IgCommandExe._DefaultError._Description": "確保您傳遞了正確的命令!\r\n此可執行檔包含 ImageGlass 軟體的命令列函式。\r\n\r\n要探索所有命令列,請造訪:\n{0}", + "FrmMain.MnuLosslessCompression._Compressing": "正在執行無損壓縮……", + "FrmSettings._ShouldGroupImagesByDirectory": "按目錄將圖片分組", + "FrmMain.MnuPanToRightSide": "將影像平移至右側", + "_.Metadata._ExifRatingPercent": "評分", + "FrmSettings._PanSpeed": "平移速度", + "_._CheckForUpdate": "檢查更新…", + "FrmSettings.Layout._ToolbarContext": "情境工具列", + "_.ImageInfo._FrameCount": "{0} 個框架", + "FrmMain.MnuLayout": "佈局", + "_._Website": "網頁", + "FrmMain.MnuPasteImage": "貼上影像", + "FrmSettings._ShowGalleryScrollbars": "顯示圖庫捲軸" + } +} \ No newline at end of file diff --git a/Setup/Assets/Language/Croatian.iglang.json b/Setup/Assets/Language/Croatian.iglang.json new file mode 100644 index 000000000..951f4e2dd --- /dev/null +++ b/Setup/Assets/Language/Croatian.iglang.json @@ -0,0 +1,504 @@ +{ + "_Metadata": { + "Code": "hr-HR", + "EnglishName": "Croatian", + "LocalName": "Hrvatski", + "Author": "Krešimir Jurić", + "MinVersion": "9.3" + }, + "Items": { + "FrmCrop.SelectionAspectRatio._Original": "Izvornik", + "FrmMain.MnuShare._Error": "Ne mogu otvoriti Dijeli dijalog.", + "_.Metadata._FileLastAccessTime": "Datum pristupa", + "FrmAbout._License": "Licence za softver", + "FrmSettings.Toolbar._Errors._ButtonIdDuplicated": "Gumb s ID '{0}' je već definiran. Molim odabrati jedinstven drugi ID za vaš gumb kako bi izbjegli sukobe.", + "FrmMain.MnuSave._Confirm": "Jeste li sigurni da želite nadpisati ovu sliku?", + "FrmSettings._OpenDefaultAppsSetting": "Otvori postavke zadanih aplikacija", + "FrmMain.MnuCopyPath": "Kopiraj putanju slike", + "FrmCropSettings.DefaultSelectionType._SelectNone": "Označi ništa", + "_.MouseWheelAction._PanHorizontally": "Pomakni lijevo / desno", + "FrmMain.MnuPrint": "Ispiši…", + "FrmSettings.Toolbar._ToolbarButtons": "Gumbi alatne trake", + "FrmResize.LblResample": "Resample:", + "_.ImageOrderBy._Extension": "Nastavak", + "FrmSettings.Nav._Viewer": "Preglednik", + "FrmSettings.EditAppDialog._EditApp": "Uredi aplikaciju", + "FrmCrop.BtnReset._Tooltip": "Presloži odabir", + "FrmMain.MnuRename._Description": "Unesite novi naziv datoteke:", + "_._No": "No", + "FrmSlideshow.MnuToggleCountdown": "Prikaži odbrojavanje dijaprojekcije", + "FrmSettings._OpenStartupAppsSetting": "Open Startup apps setting", + "FrmMain.MnuViewPreviousFrame": "Vidi prijašnju sličicu", + "_.ImageOrderBy._DateModified": "Datum izmjene", + "FrmMain.MnuViewNextFrame": "Vidi sljedeću sličicu", + "FrmMain.MnuUnload": "Isprazni sliku", + "FrmSettings.Toolbar._HideToolbarInFullscreen": "Sakrij alatnu traku u prikazu Punog zaslona", + "_.ImageOrderType._Desc": "Silazno", + "_._Update": "Update", + "FrmSettings._EnableImageAsyncLoading": "Enable image asynchronous loading", + "FrmSettings._DefaultPhotoViewer._Description": "Register the supported formats of ImageGlass with Windows. You might need to open the Default apps settings and manually select ImageGlass from the list for it to take effect.", + "_.MouseWheelAction._BrowseImages": "Prikaži sljedeću / prethodnu sliku", + "FrmSettings._EditApps": "Aplikacije uređivanja slika", + "FrmColorPickerSettings.ChkShowCIELabA": "Koristi CIELAB format s Alfa vrijednosti", + "_._GetHelp": "Zatraži pomoć", + "FrmQuickSetup._SkipQuickSetup": "Preskoči i pokreni ImageGlass", + "FrmColorPickerSettings._Title": "Postavke birača boja", + "_._Copy": "Kopiraj", + "FrmSettings._ImageBoosterCacheCount": "Broj slika predmemoriranih Image Boosterom (jednosmjerno)", + "FrmMain.MnuPanToBottom": "Pomakni sliku do dna", + "FrmMain.MnuZoom": "Uvećanje", + "FrmCropSettings.ChkCloseToolAfterSaving": "Zatvori obrezivanje po spremanju", + "FrmSettings._ShowWelcomeImage": "Prikaži pozdravnu sliku", + "FrmSettings._ColorProfile": "Profila boja", + "FrmSettings._Theme._UninstallTheme": "Makni temu", + "FrmMain._OpenWith": "Otvori s {0}", + "FrmMain.MnuRemoveDefaultPhotoViewer": "Makni postavke zadanog foto preglednika", + "_.AfterEditAppAction._Nothing": "Ništa", + "FrmCrop.BtnSave": "Spremi", + "FrmMain.MnuScaleToFit": "Prilagodi zaslonu", + "FrmToolNotFound.LblDownloadToolText": "Možete skinuto dodatne alate za ImageGlass sa:", + "_._LearnMore": "Više o...", + "FrmCrop.LblAspectRatio": "Omjer:", + "FrmExportFrames._FileNotExist": "Slikovna datoteka ne postoji", + "FrmSettings._LightTheme": "Svijetlo", + "FrmSettings.Nav._Slideshow": "Dijaprojekcija", + "_._Continue": "Nastavi", + "_._AddHotkey": "Dodaj prečac...", + "FrmMain.MnuSetDesktopBackground": "Postavi kao pozadinu radne površine", + "FrmMain.MnuReload": "Ponovno učitaj", + "FrmSlideshow.MnuExitSlideshow": "Zatvori prezentaciju", + "FrmMain.MnuAutoZoom": "Automatsko uvećanje", + "FrmSettings._ShowImagePreview": "Prikaži pretpregled slike pri učitavanju", + "FrmCrop.BtnCopy._Tooltip": "Kopiraj odabrano u međuspremnik", + "FrmSettings.Nav._Toolbar": "Alatna traka", + "FrmMain.MnuSave._Error": "Ne mogu spremiti sliku", + "FrmSettings._AfterEditingAction": "Nakon otvaranja aplikacije za uređivanje", + "FrmSettings._ShouldUseColorProfileForAll": "Koristi i za slike bez ugrađenog profila boja", + "FrmCropSettings.DefaultSelectionType._UseTheLastSelection": "Koristi zadnji odabir", + "FrmSettings._SlideshowInterval._From": "Od", + "FrmSettings._ImageInterpolation": "Interpolacija slike", + "FrmQuickSetup._StepInfo": "Korak {0}", + "FrmMain.MnuColorPicker": "Birač boja", + "FrmCrop.SelectionAspectRatio._FreeRatio": "Slobodni omjer", + "FrmSettings._ResetSettings": "Reset settings", + "FrmSettings._Startup": "Pokretanje", + "_.BackdropStyle._None": "Nijedan", + "FrmSettings._LoadDefaultZoomLevels": "Učitaj zadane razine uvećavanja", + "FrmColorPicker.BtnSettings._Tooltip": "Otvori postavke birača boja…", + "FrmSettings._UseThemeForDarkMode": "Koristi ovu temu za tamni način", + "FrmSettings._ShowDeleteConfirmation": "Prikaz dijaloga potvrde brisanja datoteke", + "FrmSettings._ShowAppIcon": "Prikaži ikonu aplikacije u naslovnoj traci", + "_._InvalidAction": "Invalid action", + "FrmQuickSetup._SelectProfile": "Odaberite profil", + "_.Metadata._FileCreationTime": "Datum izrade", + "FrmSettings._SlideshowImagesToNotifySound": "Broj slika za do zvuka obavijesti", + "FrmSettings._BackgroundColor": "Pozadinska boja preglednika", + "FrmSettings._RealTimeFileUpdate": "Ažuriranje datoteke u realnom vremenu", + "_.ColorProfileOption._CurrentMonitorProfile": "Trenutni profil monitora", + "FrmSettings._EnableCutMultipleFiles": "Omogući izrezivanje više datoteka odjednom", + "FrmSettings._AutoUpdate": "Automatski provjeri nadogradnje", + "FrmCropSettings.LblDefaultSelection": "Zadani odabir", + "FrmSettings._UseThemeForLightMode": "Koristi ovu temu za svijetli način", + "FrmSettings._ZoomLevels": "Razine uvećanja", + "FrmMain.MnuSetLockScreen._Success": "Pozadina zaključanog zaslona je ažurirana", + "FrmSettings._ShowGalleryFileName": "Prikaži naziv datoteka minijatura", + "FrmSettings.Layout._Order": "Poredak", + "FrmCropSettings.ChkAutoCenterSelection": "Centriraj odabir", + "FrmSettings.Nav._FileTypeAssociations": "Asocijacije vrste datoteke", + "_._Back": "Natrag", + "FrmMain.MnuSetDesktopBackground._Success": "Pozadina radne površine je ažurirana", + "FrmSettings._ShouldAutoOpenNewAddedImage": "Automatski otvori novo dodanu sliku", + "FrmCrop.SelectionAspectRatio._Custom": "Prilagođeno…", + "FrmMain.MnuCopyPath._Success": "Kopirana putanja trenutne slike.", + "FrmSettings._StartupBoost._Error": "Could not change Startup Boost setting", + "FrmToolNotFound.LblDescription": "ImageGlass nije mogao naći putanju do '{0}' izvršne datoteke. Za rješavanje problema, molimo upište ispravnu putanju do '{0}'.", + "FrmMain.MnuClearClipboard": "Očisti međuspremnik", + "FrmSettings._ColorManagement": "Upravljanje bojama", + "FrmMain._ReachedLastLast": "Dosegnuta zadnja slika", + "FrmMain.MnuPanUp": "Pomakni sliku gore", + "FrmMain.MnuRemoveDefaultPhotoViewer._Success": "ImageGlass više nije zadani foto preglednik.", + "FrmSettings._GetMoreLanguagePacks": "Dohvati više jezičnih paketa…", + "FrmAbout._Privacy": "Pravila privatnosti", + "FrmSettings._EnableRecursiveLoading": "Učitaj slike iz podmapa", + "_._UserAction._MethodArgumentNotSupported": "Vrsta argumenta metode '{0}' nije podržana", + "FrmSettings._FileExtensionIcons._Description": "Za prilagodbu ikona datotečnih nastavaka, skinite paket ikona, stavite sve .ICO datoteke u mapu ikona datotečnih nastavaka te kliknite '{0}' gumb. Ovo će također postaviti ImageGlass kao zadani foto preglednik.", + "_.ImageOrderType._Asc": "Uzlazno", + "FrmExportFrames._Title": "Izvezi sličice", + "_._Install": "Instaliraj…", + "FrmMain.MnuFlipHorizontal": "Vodoravno zrcaljenje", + "FrmSettings._OpenExtensionIconFolder": "Otvori mapu ikona nastavaka", + "FrmAbout._Collaborator": "Suradnik:", + "FrmQuickSetup._ConfirmCloseProcess": "Prije primjene novih postavki, nužno je ugasiti sve ImegeGlass procese. Jeste li spremni nastaviti?", + "FrmExportFrames._ExportDone": "Uspješno izvezeno {0} sličica u \n{1}", + "FrmCrop.BtnSaveAs._Tooltip": "Spremi kao kopiju…", + "FrmMain.MnuOpenFile": "Otvori datoteku…", + "FrmColorPickerSettings.ChkShowRgbA": "Koristi RGB format s Alfa vrijednosti", + "_.ImageInfo._ListCount": "{0} datoteka", + "FrmMain.MnuGoToLast": "Idi na zadnju sliku", + "FrmSettings._EditApps._AppName": "Ime aplikacije", + "FrmSettings._SlideshowBackgroundColor": "Pozadinska boja projekcije", + "FrmAbout._Email": "E-mail:", + "_.MouseWheelAction._DoNothing": "Ne čini ništa", + "FrmMain.MnuSaveAs": "Spremi k&ao…", + "FrmMain._Loading": "Učitavanje…", + "_._Browse": "Pretraži…", + "FrmMain.MnuSetDefaultPhotoViewer._Error": "ImageGlass nije postavljen kao zadani foto preglednik.", + "FrmSettings.Nav._Language": "Jezik", + "FrmQuickSetup._SeeWhatNew": "Novosti u ovoj inačici…", + "FrmSettings._ImageInterpolation._ScaleUp": "Pri uvećanju > 100%", + "FrmSettings.Layout._ToolbarContextPosition": "Kontekstualni položaj alatne trake", + "FrmMain.MnuDeleteFromHardDisk": "Trajno izbriši", + "FrmSettings._EmbeddedThumbnail": "Ugrađena minijatura", + "FrmMain.MnuDeleteFromHardDisk._Description": "Sigurno želite trajno izbrisati ovu datoteku?", + "FrmMain.MnuScaleToFill": "Popuni zaslon", + "FrmCrop.BtnCrop": "Obreži", + "_.AfterEditAppAction._Minimize": "Minimiziraj", + "FrmMain.MnuInvertColors": "Invert colors", + "FrmSettings._StartupBoost": "Startup Boost", + "FrmMain.MnuViewFirstFrame": "Vidi prvu sličicu", + "_.MouseWheelEvent._CtrlAndScroll": "Drži Ctrl i pomiči", + "FrmSettings._HideMainWindowInSlideshow": "Automatski sakrij glavni prozor", + "_.Metadata._FrameCount": "Sličice", + "FrmSettings._EnableCopyMultipleFiles": "Omogući kopiranje više datoteka odjednom", + "FrmMain.MnuFrameless._EnableDescription": "Držite SHIFT za pomicanje prozora.", + "_.ImageOrderBy._ExifDateTaken": "EXIF: Date taken", + "FrmAbout._Credits": "Zahvale", + "FrmSettings._AddNewFileExtension": "Dodaj novi datotečni nastavak", + "FrmMain.MnuQuickSetup": "Otvori Brze Postavke ImageGlassa", + "FrmMain.MnuSave._Success": "Slika je spremljena", + "FrmMain.MnuPanLeft": "Pomakni sliku ulijevo", + "FrmUpdate._StatusChecking": "Provjera ažuriranja…", + "FrmSettings.Nav._Layout": "Raspored", + "FrmMain.MnuOpenWith": "Otvori s…", + "FrmAbout._Thanks": "Posebne zahvale:", + "_._Warning": "Upozorenje", + "FrmSettings.Nav._Keyboard": "Tipkovnica", + "FrmSlideshow._PauseSlideshow": "Prezentacija je pauzirana.", + "_._Add+": "Dodaj…", + "_._Email": "E-mail", + "FrmMain.MnuPanDown": "Pomakni sliku dolje", + "_._Cancel": "Zatvori", + "_._OK": "U redu", + "FrmMain.MnuPanRight": "Pomakni sliku udesno", + "_.Position._Right": "Desno", + "_._Icon": "Ikona", + "FrmSettings._ShouldLoadHiddenImages": "Učitaj skrivene slike", + "_._InvalidAction._Transformation": "ImageGlass does not support rotation, flipping for this image.", + "FrmSettings._MakeDefault": "Učini zadanim", + "FrmMain.MnuCopyImageData._Copying": "Kopiranje podataka slike. Ponešto će trajati…", + "FrmSettings._UseEmbeddedThumbnailRawFormats": "Učitaj ugrađenu minijaturu samo za RAW format", + "_.ImageInterpolation._Linear": "Linearno", + "FrmSettings._ImageInfoTags": "Informacijske oznake slike", + "FrmSettings._FileExtensionIcons": "Ikone datotečnih nastavaka", + "FrmMain.MnuEdit._AppNotFound": "Ne mogu naći aplikaciju za uređivanje. Možete zadati aplikaciju za uređivanje ovog formata u ImageGlass Postavke > Uredi.", + "_.ColorProfileOption._None": "Nijedan", + "FrmSettings._TotalSupportedFormats": "Podržani formati: {0}", + "FrmSettings._Clipboard": "Međuspremnik", + "_._UserAction._Win32ExeError": "Ne mogu izvršiti naredbu '{0}'. Provjerite ispravnost naziva.", + "FrmCropSettings.DefaultSelectionType._SelectX": "Odaberi {0}", + "_.AfterEditAppAction._Close": "Zatvori", + "FrmAbout._LogoDesigner": "Dizajner loga:", + "_.ImageOrderBy._Name": "Naziv (zadano)", + "FrmMain.MnuRemoveDefaultPhotoViewer._Error": "Nisam uspio poništiti ImageGlass kao zadani foto preglednik.", + "FrmExportFrames._FolderPickerTitle": "Odaberi odredišnu mapu za izvoz sličica", + "FrmAbout._Donate": "Donirajte", + "FrmMain.MnuFrameNav": "Navigacija po sličicama", + "FrmMain.MnuSetLockScreen": "Postavi kao pozadinu zaključanog zaslona", + "_._Delete": "Izbriši", + "FrmMain.MnuViewPrevious": "Pogledaj prijašnju sliku", + "_.Position._Top": "Vrh", + "FrmSettings.Toolbar._CurrentButtons": "Trenutni gumbi:", + "FrmMain.MnuAbout": "O aplikaciji", + "FrmSettings._RemoveDefault": "Makni zadano", + "_._Description": "Opis", + "FrmMain.MnuPasteImage._Error": "Slika nije pronađena u međuspremniku", + "FrmMain.MnuSettings": "Postavke", + "FrmCropSettings._Title": "Postavke obrezivanja", + "FrmSettings.Toolbar._ToolbarIconHeight": "Veličina ikona alatne trake", + "FrmSettings._SlideshowInterval._To": "Do", + "FrmSettings.Layout._ToolbarPosition": "Pozicija alatne trake", + "FrmUpdate._StatusUpdated": "Koristite zadnju inačicu!", + "FrmMain.MnuExit": "Izlaz", + "_._Webview2._Outdated": "Your WebView2 Runtime is not supported. Please update to version {0} or later.", + "_._Yes": "Da", + "FrmMain.MnuRotateLeft": "Zakreni ulijevo", + "FrmSettings._EnableStartupBoost": "Enable Startup Boost", + "_.ImageOrderBy._ExifRating": "EXIF: Rating", + "FrmMain.MnuZoomIn": "Uvećaj", + "_.Metadata._ColorSpace": "Raspon boja", + "FrmAbout._Version": "Verzija:", + "FrmMain.MnuToggleTopMost._Enable": "Omogući prozor uvijek na vrhu", + "FrmSettings.Toolbar._AvailableButtons": "Dostupni gumbi:", + "FrmMain.MnuSave._Saving": "Snimanje slike…", + "FrmQuickSetup._StandardUser": "Standardni korisnik", + "FrmMain.MnuSetLockScreen._Error": "Nisam postavio sliku kao pozadinu zaključanog zaslona", + "FrmSettings.Nav._Image": "Slika", + "FrmSettings._Theme._InstallTheme": "Instaliraj teme", + "FrmSettings._EnableMultiInstances": "Dozvoli više istovremenih instanci programa", + "FrmMain.MnuCropTool": "Obreži sliku", + "_._IgCommandExe._DefaultError._Heading": "Nevažeća naredba", + "_._Refresh": "Osvježi", + "FrmMain.MnuLosslessCompression._Description": "This tool uses Magick.NET library for lossless compression, optimizing file size. Overwrites only if the compressed file is smaller than the original.", + "_._MoveDown": "Pomak dolje", + "FrmSettings._GetExtensionIconPacks": "Pribavi pakete ikona nastavaka…", + "FrmSettings._InAppMessageDuration": "Trajanje obavijesti aplikacije (milisekunde)", + "FrmMain.MnuFrameless": "Bez okvira", + "_._Reset": "Resetiraj", + "FrmSettings._ConfigDir": "Lokacija konfiguracije", + "FrmQuickSetup._SettingsWillBeApplied": "Postavke koje će se primijeniti:", + "FrmSettings._UnmanagedSettingReminder": "This setting is not managed by ImageGlass. Don't forget to disable it before you remove or relocate the app because ImageGlass does not handle this automatically.", + "FrmMain.MnuClipboard": "Međuspremnik", + "FrmMain.MnuCustomZoom": "Prilagođeno uvećanje…", + "FrmSettings._DisplayLanguage": "Jezik prikaza", + "FrmMain.MnuPrint._Error": "Ne mogu ispisati pregledavanu sliku", + "FrmSettings._ShouldPreserveModifiedDate": "Sačuvaj datum izmjene slike pri spremanju", + "FrmSettings._ShowSaveOverrideConfirmation": "Prikaz dijaloga potvrde pri nadpisivanju datoteke", + "FrmColorPickerSettings.ChkShowHexA": "Koristi HEX format s Alfa vrijednosti", + "FrmMain.MnuFullScreen": "Cijeli zaslon", + "FrmSettings._StartupDir": "Početna lokacija", + "FrmSettings._ShowCheckerboardOnlyImageRegion": "Prikaži šahovnicu samo u području slike", + "FrmMain.MnuClearClipboard._Success": "Očišćen međuspremnik.", + "FrmQuickSetup._Text": "Brze postavke ImageGlassa", + "FrmMain.MnuLosslessCompression._Done": "Done lossless compression.\r\nThe new file size is {0}, saved {1}.", + "FrmMain.MnuLosslessCompression": "Magick.NET Lossless Compression", + "FrmResize.RadResizeByPercentage": "Percentage", + "FrmSettings._StartupBoost._Disabled": "Startup Boost is disabled", + "FrmMain.MnuToggleCheckerboard": "Pozadinska šahovnica", + "FrmSettings._MinEmbeddedThumbnailSize._Height": "Visina", + "FrmSettings.Nav._General": "Općenito", + "FrmSettings._ImageLoading": "Slika se učitava", + "FrmSettings._ShowSlideshowCountdown": "Prikaži odbrojavanje dijaprojekcije", + "FrmMain.MnuSave": "Spremi", + "FrmMain.MnuMoveToRecycleBin": "Premjesti u koš za smeće", + "FrmMain.MnuRefresh": "Osvježi", + "FrmToolNotFound.LblHeading": "'{0}' nije nađen!", + "FrmMain.MnuReportIssue": "Prijavite problem…", + "FrmMain.MnuCopyImageData": "Kopiraj podatke slike", + "FrmMain.MnuCheckForUpdate._NewVersion": "Dostupna nadogradnja!", + "_._Empty": "(prazno)", + "FrmSettings._Zooming": "Uvećavanje", + "FrmMain.MnuCutFile": "Izreži datoteku", + "FrmHotkeyPicker.LblHotkey": "Stisnite prečace", + "FrmSettings.Layout._Gallery": "Galerija", + "FrmMain.MnuNewWindow": "Otvori novi prozor", + "FrmMain.MnuMoveToRecycleBin._Description": "Želite li premjestiti ovu datoteku u koš za smeće?", + "FrmSettings._DefaultPhotoViewer": "Zadani foto preglednik", + "_.Metadata._ExifDateTimeOriginal": "EXIF: DateTimeOriginal", + "FrmMain.MnuRotateRight": "Zakreni udesno", + "FrmSettings._MinEmbeddedThumbnailSize": "Najmanja veličina ugrađene minijature za učitati", + "FrmMain.MnuSetDefaultPhotoViewer": "Postavi kao zadani preglednik slika", + "FrmMain.MnuImageProperties": "Svojstva slike", + "FrmSettings._EnableNavigationButtons": "Prikaži tipke navigacijskih strelica", + "_._Edit": "Uredi", + "FrmSettings._ImageBooster": "Image Booster", + "FrmSettings.Tools._IntegratedWith": "Integriran s {0}", + "_._Next": "Sljedeće", + "FrmExportFrames._OpenOutputFolder": "Otvori odredišnu mapu", + "FrmMain.MnuOpenLocation": "Otvori lokaciju slike", + "FrmMain.MnuLockZoom": "Zaključaj uvećanje", + "FrmSettings._StartupBoost._Description": "Preload and run ImageGlass in the background for a few seconds during Windows startup to accelerate the first launch.", + "FrmSettings._WindowBackdrop": "Pozadina prozora", + "FrmSettings._EnableRealTimeFileUpdate": "Nadziri izmjene datoteka u gledanoj mapi o ažuriraj u realnom vremenu", + "_._NotSupported": "Nepodržan format", + "FrmSettings._Theme._GetMoreThemes": "Dohvati više tema…", + "FrmMain.MnuNewWindow._Error": "Ne mogu otvoriti novi prozor, samo jedna instanca dozvoljena", + "FrmMain.MnuZoomOut": "Umanji", + "FrmSettings.Toolbar._EditButton": "Uredi gumb alatne trake", + "FrmMain.MnuCustomZoom._Description": "Unesi novu vrijednost uvećanja", + "FrmResize.RadResizeByPixels": "Pixels", + "FrmMain.MnuEdit": "Uredi sliku {0}…", + "FrmSettings.Layout._GalleryPosition": "Položaj galerije", + "FrmMain.MnuWindowFit": "Prilagodi prozoru", + "FrmMain._OpenFileDialog": "Sve podržane datoteke", + "FrmSettings._UseRandomIntervalForSlideshow": "Koristi nasumični interval", + "_.Position._Left": "Lijevo", + "FrmSettings._ShouldOpenLastSeenImage": "Otvori zadnju gledanu sliku", + "_.Position._Bottom": "Dno", + "FrmResize.ChkKeepRatio": "Keep ratio propotional", + "FrmMain.MnuGoTo": "Idi na…", + "FrmSlideshow.MnuPauseResumeSlideshow": "Prekini/nastavi dijaprojekciju", + "FrmSettings.Tools._Integrated": "Integriran", + "FrmSettings._Contributors": "Suradnici", + "_.MouseWheelAction._Zoom": "Povećaj / umanji", + "_._CommandPreview": "Pregled naredbe", + "FrmSettings._DarkTheme": "Tamno", + "_._Hotkeys": "Prečaci", + "_.Metadata._ExifDateTime": "EXIF: DateTime", + "FrmSettings.Toolbar._Errors._ButtonIdRequired": "Nužan ID gumba.", + "FrmSettings._MinEmbeddedThumbnailSize._Width": "Širina", + "_._Executable": "Izvršna", + "_.ImageInterpolation._MultiSampleLinear": "Više-uzorkovno linearno", + "_._Separator": "Razdjelnik", + "FrmQuickSetup._ProfessionalUser": "Profesionalni korisnik", + "FrmMain.MnuFlipVertical": "Okomito zrcaljenje", + "FrmSlideshow._ResumeSlideshow": "Prezentacija nastavljena.", + "FrmCropSettings.DefaultSelectionType._CustomArea": "Prilgođeno područje…", + "FrmMain.MnuActualSize": "Stvarna veličina", + "FrmCrop.BtnSaveAs": "Spremi k&ao…", + "FrmSettings._InstallNewLanguagePack": "Dodaj nove jezične pakete…", + "FrmSlideshow.MnuZoomModes": "Načini uvećavanja", + "FrmMain.MnuTools": "Alati", + "_.ImageInterpolation._Cubic": "Kubično", + "FrmUpdate._LatestVersion": "Zadnja inačica: {0}", + "FrmMain.MnuViewNext": "Pogledaj sljedeću sliku", + "_.MouseWheelEvent._AltAndScroll": "Drži Alt i pomiči", + "FrmToolNotFound._Title": "Alat nije nađen", + "FrmCrop.BtnCrop._Tooltip": "Obreži samo sliku", + "FrmSettings.EditAppDialog._AddApp": "Dodaj aplikaciju za uređivanje", + "FrmMain.MnuPanning": "Pomicanje", + "_._MoveUp": "Pomak gore", + "FrmCropSettings.DefaultSelectionType._SelectAll": "Odaberi sve", + "_._Name": "Naziv", + "FrmColorPickerSettings.ChkShowHslA": "Koristi HSL format s Alfa vrijednosti", + "FrmMain.MnuToggleImageAnimation": "Pokreni / zaustavi animaciju", + "FrmSettings._DisableStartupBoost": "Disable Startup Boost", + "FrmMain.MnuCopyFile._Success": "Kopirano {0} datoteka.", + "FrmMain.MnuSave._ConfirmDescription": "ImageGlass NIJE profesionalni uređivač slika, budite svjesni gubitka kvalitete, metapodataka, slojeva... pri snimanju slike.", + "FrmToolNotFound.BtnSelectExecutable": "Odaberi…", + "FrmUpdate._StatusOutdated": "Dostupna nova nadogradnja!", + "_.ImageOrderBy._Random": "Nasumično", + "FrmResize.LblCurrentSize": "Current Size:", + "_._Apply": "Primijeni", + "FrmAbout._Slogan": "Lagan, svestran preglednik slika", + "FrmMain.MnuPanToTop": "Pomakni sliku do vrha", + "FrmSettings.Toolbar._AddNewButton": "Dodaj prilagođen gumb alatnoj traci", + "FrmCrop.LblSize": "Veličina:", + "FrmSettings._ImageInterpolation._ScaleDown": "Pri uvećanju < 100%", + "_._CreatingFileError": "Nije moguće stvoriti privremenu slikovnu datoteku", + "FrmMain.MnuGoTo._Description": "Unesi indek slike za pregled, pa stisni ENTER", + "FrmSettings.Toolbar._EnableCenterToolbar": "Središnje poravnanje alatne trake", + "FrmMain.MnuResizeTool": "Resize image", + "FrmSettings.Layout._Toolbar": "Alatna traka", + "FrmMain.MnuHelp": "Pomoć", + "_.ImageOrderBy._FileSize": "Veličina datoteke", + "FrmSettings._Theme._OpenThemeFolder": "Otvori mapu s temama", + "FrmMain.MnuNavigation": "Navigacija", + "_._Save": "Spremi", + "FrmQuickSetup._SettingProfileDescription": "Za izmjenu, samo otvorite postavke aplikacije.", + "_._UserAction._MenuNotFound": "Nema izbornika '{0}' za pozivanje radnje", + "FrmMain.MnuPanToLeftSide": "Pomakni sliku do lijevog ruba", + "FrmUpdate._CurrentVersion": "Trenutna inačica: {0}", + "FrmCrop.BtnSettings._Tooltip": "Otvori postavke obrezivanja", + "_.ColorProfileOption._Custom": "Prilagođeno…", + "FrmSettings._UseEmbeddedThumbnailOtherFormats": "Učitaj ugrađenu minijaturu samo za druge formate", + "FrmMain.MnuGoToFirst": "Idi na prvu sliku", + "FrmSettings._ExportLanguagePack": "Izvezi jezični paket…", + "FrmSettings.Nav._Mouse": "Miš", + "_.ImageOrderBy._DateCreated": "Datum izrade", + "FrmSettings._EnableFullscreenSlideshow": "Pokreni projekciju preko punog zaslona", + "FrmAbout._Homepage": "Naslovna stranica:", + "FrmSettings._GalleryCacheSizeInMb": "Najveća veličina predmemorije galerije (u megabajtima)", + "FrmMain.MnuCopyImageData._Success": "Kopirani podaci trenutne slike.", + "FrmSettings._EnableLoopBackNavigation": "Skoči na prvu sliku kada dosegneš kraj popisa", + "_.MouseWheelEvent._Scroll": "Pomicanje", + "FrmCrop.BtnSave._Tooltip": "Spremi sliku", + "FrmMain.MnuSlideshow": "Dijaprojekcija", + "FrmMain.MnuShare": "Podijeli…", + "FrmSettings._SlideshowNotification": "Obavijest projekcije", + "FrmMain.MnuViewChannels": "Prikaz kanala", + "FrmSettings._Refresh": "Osvježi", + "_._UserAction._MethodNotFound": "Nema načina '{0}' za pozivanje radnje", + "FrmMain.MnuCopyFile": "Kopiraj datoteku", + "_._CreatingFile": "Stvori privremenu slikovnu datoteku...", + "FrmMain.MnuToggleTopMost": "Drži prozor uvijek na vrhu", + "FrmMain.MnuLosslessCompression._Confirm": "Are you sure you want to proceed?", + "FrmMain.MnuImage": "Slika", + "FrmSettings._StartupBoost._Enabled": "Startup Boost is enabled", + "FrmQuickSetup._SetDefaultViewer": "Želite postaviti ImageGlass kao zadani foto preglednik?", + "FrmMain.MnuScaleToWidth": "Prilagodi širini", + "_._FileExtension": "Datotečni nastavak", + "FrmUpdate._PublishedDate": "Datum objave: {0}", + "_._DoNotShowThisMessageAgain": "Ne prikazuj ponovno ovu poruku", + "_.ImageInterpolation._NearestNeighbor": "Najbliži-susjed", + "FrmCrop.LblLocation": "Lokacija:", + "_._Download": "Preuzimanje", + "_.Metadata._ColorProfile": "Profila boja", + "FrmSettings._CenterWindowFit": "Centriraj prozor u modu Prilagođenog prozora", + "FrmSettings._ImageLoadingOrder": "Redoslijed učitavanja slika", + "FrmSettings._GalleryColumns": "Broj stupaca minijatura u okomitom prikazu galerije", + "_._Quit": "Završi", + "_._Add": "Dodaj", + "FrmMain.MnuChangeBackgroundColor": "Promijeni pozadinsku boju…", + "FrmMain.MnuToggleToolbar": "Alatna traka", + "FrmAbout._Contact": "Kontakt", + "FrmSettings.Toolbar._AddCustomButton": "Dodaj prilagođen gumb…", + "FrmCrop.BtnQuickSelect._Tooltip": "Brzi izbor…", + "FrmMain.MnuCutFile._Success": "Izrezano {0} datoteka.", + "FrmSettings._ZoomSpeed": "Brzina uvećanja", + "FrmMain.MnuToggleTopMost._Disable": "Onemogući prozor uvijek na vrhu", + "FrmSettings._ShouldUseExplorerSortOrder": "Koristi sortiranje Windows File Explorera ako je moguće", + "_.ImageInterpolation._Antisotropic": "Anizotropski", + "FrmMain._ReachedFirstImage": "Dosegnuta početna slika", + "_._UnhandledException": "Neočekivana iznimka", + "FrmResize.LblNewSize": "New Size:", + "FrmMain._ClipboardImage": "Slika u međuspremniku", + "FrmMain.MnuExportFrames": "Izvezi sličice…", + "FrmMain.MnuFile": "Datoteka", + "_._Close": "Zatvori", + "FrmMain.MnuMain": "Glavni izbornik", + "_._ResetToDefault": "Vrati na zadano", + "FrmSettings.Nav._Gallery": "Galerija", + "FrmMain.MnuSetDefaultPhotoViewer._Success": "ImageGlass uspješno postavljen kao zadani foto preglednik.", + "FrmSettings._HideGalleryInFullscreen": "Sakrij Galeriju u prikazu Punog zaslona", + "FrmSettings._AvailableImageInfoTags": "Dostupne oznake:", + "FrmExportFrames._Exporting": "Izvoz {0}/{1} sličica\n{2}…", + "_._Argument": "Dokaz", + "FrmSettings._ImageEditQuality": "Kvaliteta slike", + "_._ID": "Iskaznica", + "FrmSettings._UserConfigFile": "Datoteka korisničkih postavki (igconfig.json)", + "FrmMain.MnuLoadingOrders": "Učitavanje naloga", + "FrmSettings._OpenSaveAsDialogInTheCurrentImageDir": "Open the Save As dialog in the current image directory", + "_.MouseWheelEvent._ShiftAndScroll": "Drži Shift i pomiči", + "FrmSettings._UseSmoothZooming": "Koristi glatko uvećavanje", + "FrmSettings._Theme": "Teme", + "FrmSettings._ImageBoosterCacheMaxDimension": "Najveća veličina za predmemoriju (pikseli)", + "FrmMain.MnuScaleToHeight": "Prilagodi visini", + "_.Metadata._FileLastWriteTime": "Datum izmjene", + "FrmSettings._Author": "Autor", + "FrmSettings._Others": "Ostalo", + "_.MouseWheelAction._PanVertically": "Pomakni gore / dolje", + "FrmSettings._MouseWheelAction": "Radnje kotačića miša", + "FrmSettings.Nav._Tools": "Alati", + "FrmMain.MnuSetDesktopBackground._Error": "Nisam uspio postaviti sliku kao pozadinu radne površine", + "FrmSettings.Toolbar._Errors._ButtonExecutableRequired": "Potrebna izvršna datoteka gumba.", + "_.ImageOrderBy._DateAccessed": "Datum pristupa", + "FrmSettings._ThumbnailSize": "Dimenzija minijature (piksel)", + "FrmSettings._FileFormats": "Formati datoteka", + "FrmMain.MnuReloadImageList": "Ponovno učitaj popis", + "FrmSettings._UseWebview2ForSvg": "Koristi Webview2 za prikaz SVG formata", + "FrmCrop.BtnCopy": "Kopiraj", + "FrmSettings._CurrentMonitorProfile._Description": "ImageGlass me osvježava boju pri micanju slike među monitorima", + "FrmMain.PicMain._ErrorText": "Ne mogu otvoriti ovu sliku", + "FrmSettings.Tools._AddNewTool": "Dodaj vanjski alat", + "FrmMain.MnuRename": "Preimenuj sliku…", + "FrmMain.MnuViewLastFrame": "Vidi zadnju sličicu", + "_._Webview2._NotFound": "Please install WebView2 Runtime to access full features of ImageGlass.", + "FrmMain.MnuGetMoreTools": "Dohvati još alata…", + "FrmSettings.Nav._Appearance": "Izgled", + "FrmSettings._SlideshowInterval": "Zastanak prezentacije:", + "_.ImageInterpolation._HighQualityBicubic": "Bikubično visoke kvalitete", + "FrmColorPickerSettings.ChkShowHsvA": "Koristi HSV format s Alfa vrijednosti", + "FrmSettings.Tools._EditTool": "Uredi vanjski alat", + "_._Error": "Greška", + "FrmSettings._ImageBoosterCacheMaxFileSizeInMb": "Najveća veličina za predmemoriju (megabajti)", + "_._UnhandledException._Description": "Došlo je do neočekivane iznimke. Ako odaberete Nastavi, aplikacija će zanemariti ovu grešku i pokušati nastaviti. Ako odaberete Završi, aplikacija će odmah završiti.", + "_.Metadata._FileSize": "Veličina datoteke", + "FrmSettings.Toolbar._ButtonJson": "JSON gumb", + "FrmQuickSetup._SetDefaultViewer._Description": "Možete presložiti u postavkama aplikacije > kartica Pridruživanje tipa datoteka.", + "FrmSettings.Nav._Edit": "Uredi", + "FrmMain.MnuToggleGallery": "Tabla galerije", + "_._IgCommandExe._DefaultError._Description": "Pazite da izdate ispravne naredbe!\r\nOva izvršna datoteka sadrži funkcije naredbenog retka za ImageGlass softver.\r\n\r\nZa istraživanje svih naredbi, posjetite:\n{0}", + "FrmMain.MnuLosslessCompression._Compressing": "Performing lossless compression…", + "FrmSettings._ShouldGroupImagesByDirectory": "Grupiraj slike po direktoriju", + "FrmMain.MnuPanToRightSide": "Pomakni sliku do desnog ruba", + "_.Metadata._ExifRatingPercent": "Ocjene", + "FrmSettings._PanSpeed": "Brzina pomaka", + "_._CheckForUpdate": "Provjeri nadogradnje…", + "FrmSettings.Layout._ToolbarContext": "Kontekstualna alatna traka", + "_.ImageInfo._FrameCount": "{0} sličica", + "FrmMain.MnuLayout": "Raspored", + "_._Website": "Web stranica", + "FrmMain.MnuPasteImage": "Zalijepi sliku", + "FrmSettings._ShowGalleryScrollbars": "Prikaži trake za pomicanje galerije" + } +} \ No newline at end of file diff --git a/Setup/Assets/Language/Czech.iglang.json b/Setup/Assets/Language/Czech.iglang.json new file mode 100644 index 000000000..f1ce87194 --- /dev/null +++ b/Setup/Assets/Language/Czech.iglang.json @@ -0,0 +1,504 @@ +{ + "_Metadata": { + "Code": "cs-CZ", + "EnglishName": "Czech", + "LocalName": "Čeština", + "Author": "Opicka", + "MinVersion": "9.3" + }, + "Items": { + "FrmCrop.SelectionAspectRatio._Original": "Originál", + "FrmMain.MnuShare._Error": "Nelze otevřít dialogové okno Sdílení.", + "_.Metadata._FileLastAccessTime": "Datum přístupu", + "FrmAbout._License": "Softwarová licence", + "FrmSettings.Toolbar._Errors._ButtonIdDuplicated": "Tlačítko s ID '{0}' již bylo definováno. Zvolte prosím jiné a jedinečné ID tlačítka, abyste předešli konfliktům.", + "FrmMain.MnuSave._Confirm": "Opravdu chcete přepsat tento obrázek?", + "FrmSettings._OpenDefaultAppsSetting": "Otevřít nastavení Výchozích aplikací", + "FrmMain.MnuCopyPath": "Kopírovat cestu k souboru", + "FrmCropSettings.DefaultSelectionType._SelectNone": "Nevybrat nic", + "_.MouseWheelAction._PanHorizontally": "Posunout vlevo / vpravo", + "FrmMain.MnuPrint": "Tisk…", + "FrmSettings.Toolbar._ToolbarButtons": "Tlačítka na panelu nástrojů", + "FrmResize.LblResample": "Převzorkovat:", + "_.ImageOrderBy._Extension": "Rozšíření", + "FrmSettings.Nav._Viewer": "Prohlížeč", + "FrmSettings.EditAppDialog._EditApp": "Upravit aplikaci", + "FrmCrop.BtnReset._Tooltip": "Resetovat výběr", + "FrmMain.MnuRename._Description": "Zadejte nový název souboru:", + "_._No": "Ne", + "FrmSlideshow.MnuToggleCountdown": "Ukaž odpočet času ve slideshow", + "FrmSettings._OpenStartupAppsSetting": "Otevřít nastavení aplikací po spuštění", + "FrmMain.MnuViewPreviousFrame": "Zobrazit předchozí snímek", + "_.ImageOrderBy._DateModified": "Datum změny", + "FrmMain.MnuViewNextFrame": "Zobrazit další snímek", + "FrmMain.MnuUnload": "Uvolnit obrázek", + "FrmSettings.Toolbar._HideToolbarInFullscreen": "Skrýt panel nástrojů v režimu celé obrazovky", + "_.ImageOrderType._Desc": "Sestupně", + "_._Update": "Aktualizovat", + "FrmSettings._EnableImageAsyncLoading": "Povolit asynchronní načítání obrázků", + "FrmSettings._DefaultPhotoViewer._Description": "Zaregistrujte podporované formáty ImageGlass ve Windows. Možná budete muset otevřít nastavení Výchozích aplikací a ručně vybrat ImageGlass ze seznamu, aby se změna projevila.", + "_.MouseWheelAction._BrowseImages": "Zobrazit další / předchozí obrázek", + "FrmSettings._EditApps": "Aplikace pro úpravu obrázků", + "FrmColorPickerSettings.ChkShowCIELabA": "Použít HSL formát s hodnotou Alpha", + "_._GetHelp": "Získat nápovědu", + "FrmQuickSetup._SkipQuickSetup": "Přeskočit a spustit ImageGlass", + "FrmColorPickerSettings._Title": "Nastavení výběru barev", + "_._Copy": "Kopírovat", + "FrmSettings._ImageBoosterCacheCount": "Počet obrázků v mezipaměti Image Booster (jeden směr)", + "FrmMain.MnuPanToBottom": "Posunout k dolnímu okraji", + "FrmMain.MnuZoom": "Zvětšení", + "FrmCropSettings.ChkCloseToolAfterSaving": "Zavřít nástroj ořezu po uložení", + "FrmSettings._ShowWelcomeImage": "Zobrazit uvítací obrázek", + "FrmSettings._ColorProfile": "Barevný profil", + "FrmSettings._Theme._UninstallTheme": "Odinstalovat balíček vzhledu", + "FrmMain._OpenWith": "Otevřít v aplikaci {0}", + "FrmMain.MnuRemoveDefaultPhotoViewer": "Odebrat jako výchozí prohlížeč fotek", + "_.AfterEditAppAction._Nothing": "Nedělat nic", + "FrmCrop.BtnSave": "Uložit", + "FrmMain.MnuScaleToFit": "Zobrazit vše", + "FrmToolNotFound.LblDownloadToolText": "Další nástroje pro ImageGlass si můžete stáhnout na:", + "_._LearnMore": "Více informací…", + "FrmCrop.LblAspectRatio": "Poměr stran:", + "FrmExportFrames._FileNotExist": "Obrázek neexistuje", + "FrmSettings._LightTheme": "Světlý", + "FrmSettings.Nav._Slideshow": "Prezentace", + "_._Continue": "Pokračovat", + "_._AddHotkey": "Přidat klávesovou zkratku…", + "FrmMain.MnuSetDesktopBackground": "Nastavit jako obrázek pozadí", + "FrmMain.MnuReload": "Znovu načíst obrázek", + "FrmSlideshow.MnuExitSlideshow": "Konec prezentace", + "FrmMain.MnuAutoZoom": "Automatické přiblížení", + "FrmSettings._ShowImagePreview": "Zobrazit náhled obrázku během načítání", + "FrmCrop.BtnCopy._Tooltip": "Zkopírovat výběr do schránky", + "FrmSettings.Nav._Toolbar": "Panel nástrojů", + "FrmMain.MnuSave._Error": "Obrázek se nepodařilo uložit", + "FrmSettings._AfterEditingAction": "Po otevření pro úpravy v externí aplikaci", + "FrmSettings._ShouldUseColorProfileForAll": "Použít také pro snímky bez vloženého barevného profilu", + "FrmCropSettings.DefaultSelectionType._UseTheLastSelection": "Použít poslední výběr", + "FrmSettings._SlideshowInterval._From": "Od", + "FrmSettings._ImageInterpolation": "Interpolace obrázku", + "FrmQuickSetup._StepInfo": "Krok {0}", + "FrmMain.MnuColorPicker": "Výběr barvy", + "FrmCrop.SelectionAspectRatio._FreeRatio": "Volný poměr", + "FrmSettings._ResetSettings": "Resetovat nastavení", + "FrmSettings._Startup": "Spuštění", + "_.BackdropStyle._None": "Žádný", + "FrmSettings._LoadDefaultZoomLevels": "Načíst výchozí úrovně přiblížení", + "FrmColorPicker.BtnSettings._Tooltip": "Otevřít nastavení výběru barev…", + "FrmSettings._UseThemeForDarkMode": "Použít tento motiv pro tmavý režim", + "FrmSettings._ShowDeleteConfirmation": "Zobrazit potvrzovací dialog při mazání souboru", + "FrmSettings._ShowAppIcon": "Zobrazit ikonu aplikace v záhlaví okna", + "_._InvalidAction": "Neplatná akce", + "FrmQuickSetup._SelectProfile": "Vybrat profil", + "_.Metadata._FileCreationTime": "Datum vytvoření", + "FrmSettings._SlideshowImagesToNotifySound": "Počet obrázků pro přehrání zvuku upozornění", + "FrmSettings._BackgroundColor": "Barva pozadí prohlížeče", + "FrmSettings._RealTimeFileUpdate": "Aktualizace souboru v reálném čase", + "_.ColorProfileOption._CurrentMonitorProfile": "Aktuální profil monitoru", + "FrmSettings._EnableCutMultipleFiles": "Povolit vyjmutí více souborů najednou", + "FrmSettings._AutoUpdate": "Automatická kontrola aktualizací", + "FrmCropSettings.LblDefaultSelection": "Výchozí výběr", + "FrmSettings._UseThemeForLightMode": "Použít tento motiv pro světlý režim", + "FrmSettings._ZoomLevels": "Úrovně přiblížení", + "FrmMain.MnuSetLockScreen._Success": "Obrázek zamykací obrazovky byl aktualizován", + "FrmSettings._ShowGalleryFileName": "Zobrazit název souboru u miniatury", + "FrmSettings.Layout._Order": "Pořadí", + "FrmCropSettings.ChkAutoCenterSelection": "Automaticky vycentrovat výběr", + "FrmSettings.Nav._FileTypeAssociations": "Asociace typů souborů", + "_._Back": "Zpět", + "FrmMain.MnuSetDesktopBackground._Success": "Pozadí plochy bylo aktualizováno", + "FrmSettings._ShouldAutoOpenNewAddedImage": "Automaticky otevřít nově přidaný obrázek", + "FrmCrop.SelectionAspectRatio._Custom": "Vlastní…", + "FrmMain.MnuCopyPath._Success": "Cesta k obrázku byla zkopírována.", + "FrmSettings._StartupBoost._Error": "Nelze změnit nastavení Startup Boost", + "FrmToolNotFound.LblDescription": "ImageGlass nemohl najít cestu ke spustitelnému souboru '{0}'. Chcete-li tento problém vyřešit, aktualizujte prosím cestu k '{0}'.", + "FrmMain.MnuClearClipboard": "Vyčistit schránku", + "FrmSettings._ColorManagement": "Správa barev", + "FrmMain._ReachedLastLast": "Dosaženo posledního obrázku", + "FrmMain.MnuPanUp": "Posunout nahoru", + "FrmMain.MnuRemoveDefaultPhotoViewer._Success": "ImageGlass již není výchozím prohlížečem fotografií.", + "FrmSettings._GetMoreLanguagePacks": "Získat další jazykové sady…", + "FrmAbout._Privacy": "Zásady ochrany osobních údajů", + "FrmSettings._EnableRecursiveLoading": "Načítat obrázky v podsložkách", + "_._UserAction._MethodArgumentNotSupported": "Typ argumentu metody '{0}' není podporován", + "FrmSettings._FileExtensionIcons._Description": "Chcete-li přizpůsobit ikony přípon souborů, stáhněte si balíček ikon, umístěte všechny soubory .ICO do složky ikon přípon a klikněte na tlačítko '{0}'. Tímto se také nastaví ImageGlass jako výchozí prohlížeč fotografií.", + "_.ImageOrderType._Asc": "Vzestupně", + "FrmExportFrames._Title": "Exportovat snímky obrázku", + "_._Install": "Nainstalovat…", + "FrmMain.MnuFlipHorizontal": "Překlopit horizontálně", + "FrmSettings._OpenExtensionIconFolder": "Otevřít složku ikon přípon", + "FrmAbout._Collaborator": "Spolupracovník:", + "FrmQuickSetup._ConfirmCloseProcess": "Před použitím nových nastavení je nutné ukončit všechny procesy ImageGlass. Jste připraveni pokračovat?", + "FrmExportFrames._ExportDone": "Úspěšně exportováno {0} snímků do \r\n{1}", + "FrmCrop.BtnSaveAs._Tooltip": "Uložit jako kopii…", + "FrmMain.MnuOpenFile": "Otevřít soubor…", + "FrmColorPickerSettings.ChkShowRgbA": "Použít RGB formát s hodnotou Alpha", + "_.ImageInfo._ListCount": "{0} soubor(ů)", + "FrmMain.MnuGoToLast": "Přejít na poslední obrázek", + "FrmSettings._EditApps._AppName": "Název aplikace", + "FrmSettings._SlideshowBackgroundColor": "Barva pozadí prezentace", + "FrmAbout._Email": "Email:", + "_.MouseWheelAction._DoNothing": "Bez funkce", + "FrmMain.MnuSaveAs": "Uložit jako…", + "FrmMain._Loading": "Načítání…", + "_._Browse": "Procházet…", + "FrmMain.MnuSetDefaultPhotoViewer._Error": "Nelze nastavit ImageGlass jako výchozí prohlížeč fotografií.", + "FrmSettings.Nav._Language": "Jazyk", + "FrmQuickSetup._SeeWhatNew": "Podívejte se, co je nového v této verzi…", + "FrmSettings._ImageInterpolation._ScaleUp": "Při přiblížení > 100%", + "FrmSettings.Layout._ToolbarContextPosition": "Pozice kontextového panelu nástrojů", + "FrmMain.MnuDeleteFromHardDisk": "Trvale odstranit", + "FrmSettings._EmbeddedThumbnail": "Vložená miniatura", + "FrmMain.MnuDeleteFromHardDisk._Description": "Opravdu chcete tento soubor trvale odstranit?", + "FrmMain.MnuScaleToFill": "Vyplnit", + "FrmCrop.BtnCrop": "Oříznout", + "_.AfterEditAppAction._Minimize": "Minimalizovat", + "FrmMain.MnuInvertColors": "Invert colors", + "FrmSettings._StartupBoost": "Startup Boost", + "FrmMain.MnuViewFirstFrame": "Zobrazit první snímek", + "_.MouseWheelEvent._CtrlAndScroll": "Držet Ctrl a rolovat", + "FrmSettings._HideMainWindowInSlideshow": "Automaticky skrýt hlavní okno", + "_.Metadata._FrameCount": "Snímky", + "FrmSettings._EnableCopyMultipleFiles": "Povolit kopírování více souborů najednou", + "FrmMain.MnuFrameless._EnableDescription": "Pro přesun okna podržte klávesu Shift.", + "_.ImageOrderBy._ExifDateTaken": "EXIF: Datum pořízení", + "FrmAbout._Credits": "Autoři", + "FrmSettings._AddNewFileExtension": "Přidat novou příponu souboru", + "FrmMain.MnuQuickSetup": "Otevřít Rychlé nastavení ImageGlass", + "FrmMain.MnuSave._Success": "Obrázek byl uložen", + "FrmMain.MnuPanLeft": "Posunout vlevo", + "FrmUpdate._StatusChecking": "Kontrola aktualizací…", + "FrmSettings.Nav._Layout": "Rozložení", + "FrmMain.MnuOpenWith": "Otevřít pomocí aplikace…", + "FrmAbout._Thanks": "Zvláštní poděkování patří:", + "_._Warning": "Varování", + "FrmSettings.Nav._Keyboard": "Klávesnice", + "FrmSlideshow._PauseSlideshow": "Prezentace je pozastavena.", + "_._Add+": "Přidat…", + "_._Email": "E-mail", + "FrmMain.MnuPanDown": "Posunout dolů", + "_._Cancel": "Zrušit", + "_._OK": "OK", + "FrmMain.MnuPanRight": "Posunout vpravo", + "_.Position._Right": "Vpravo", + "_._Icon": "Ikona", + "FrmSettings._ShouldLoadHiddenImages": "Načíst skryté obrázky", + "_._InvalidAction._Transformation": "ImageGlass pro tento obrázek nepodporuje otáčení ani překlápění.", + "FrmSettings._MakeDefault": "Nastavit jako výchozí", + "FrmMain.MnuCopyImageData._Copying": "Kopírování dat obrázku. Chvíli to potrvá…", + "FrmSettings._UseEmbeddedThumbnailRawFormats": "Načítat pouze vložené miniatury pro formáty RAW", + "_.ImageInterpolation._Linear": "Lineární", + "FrmSettings._ImageInfoTags": "Štítky informací o obrázku", + "FrmSettings._FileExtensionIcons": "Ikony přípon souborů", + "FrmMain.MnuEdit._AppNotFound": "Nelze nalézt přidruženou aplikaci pro úpravy. Aplikaci pro úpravu tohoto formátu můžete přiřadit v Nastavení ImageGlass > Upravit.", + "_.ColorProfileOption._None": "Žádný", + "FrmSettings._TotalSupportedFormats": "Celkem podporovaných formátů: {0}", + "FrmSettings._Clipboard": "Schránka", + "_._UserAction._Win32ExeError": "Nelze spustit příkaz '{0}'. Ujistěte se, že je název správný.", + "FrmCropSettings.DefaultSelectionType._SelectX": "Vybrat {0}", + "_.AfterEditAppAction._Close": "Ukončit ImageGlass", + "FrmAbout._LogoDesigner": "Logo designer:", + "_.ImageOrderBy._Name": "Název (výchozí)", + "FrmMain.MnuRemoveDefaultPhotoViewer._Error": "Nelze odebrat ImageGlass jako výchozí prohlížeč fotografií.", + "FrmExportFrames._FolderPickerTitle": "Vyberte výstupní složku pro export obrázkových snímků", + "FrmAbout._Donate": "Přispět", + "FrmMain.MnuFrameNav": "Navigace snímků", + "FrmMain.MnuSetLockScreen": "Nastavit jako obrázek zamykací obrazovky", + "_._Delete": "Odstranit", + "FrmMain.MnuViewPrevious": "Zobrazit předchozí obrázek", + "_.Position._Top": "Nahoru", + "FrmSettings.Toolbar._CurrentButtons": "Aktuální tlačítka:", + "FrmMain.MnuAbout": "O aplikaci", + "FrmSettings._RemoveDefault": "Odebrat výchozí", + "_._Description": "Popis", + "FrmMain.MnuPasteImage._Error": "Nelze najít data obrázku ve schránce", + "FrmMain.MnuSettings": "Nastavení", + "FrmCropSettings._Title": "Crop settings", + "FrmSettings.Toolbar._ToolbarIconHeight": "Velikost ikon panelu nástrojů", + "FrmSettings._SlideshowInterval._To": "Do", + "FrmSettings.Layout._ToolbarPosition": "Pozice panelu nástrojů", + "FrmUpdate._StatusUpdated": "Používáte nejnovější verzi!", + "FrmMain.MnuExit": "Ukončit", + "_._Webview2._Outdated": "Vaše verze WebView2 Runtime není podporována. Aktualizujte prosím na verzi {0} nebo novější.", + "_._Yes": "Ano", + "FrmMain.MnuRotateLeft": "Otočit vlevo", + "FrmSettings._EnableStartupBoost": "Povolit Startup Boost", + "_.ImageOrderBy._ExifRating": "EXIF: Hodnocení", + "FrmMain.MnuZoomIn": "Přiblížit", + "_.Metadata._ColorSpace": "Barevný prostor", + "FrmAbout._Version": "Verze:", + "FrmMain.MnuToggleTopMost._Enable": "Povoleno okno vždy nahoře", + "FrmSettings.Toolbar._AvailableButtons": "Dostupné tlačítka:", + "FrmMain.MnuSave._Saving": "Ukládání obrázku…", + "FrmQuickSetup._StandardUser": "Standardní uživatel", + "FrmMain.MnuSetLockScreen._Error": "Nelze nastavit prohlížený obrázek jako zamykací obrazovku", + "FrmSettings.Nav._Image": "Obrázek", + "FrmSettings._Theme._InstallTheme": "Nainstalovat balíčky vzhledu", + "FrmSettings._EnableMultiInstances": "Povolit více instancí programu", + "FrmMain.MnuCropTool": "Oříznout obrázek", + "_._IgCommandExe._DefaultError._Heading": "Neplatný příkaz", + "_._Refresh": "Obnovit", + "FrmMain.MnuLosslessCompression._Description": "Tento nástroj používá knihovnu Magick.NET pro bezeztrátovou kompresi a optimalizaci velikosti souboru. Přepíše soubor pouze v případě, že je komprimovaný soubor menší než originál.", + "_._MoveDown": "Přesunout dolů", + "FrmSettings._GetExtensionIconPacks": "Získat sady ikon přípon…", + "FrmSettings._InAppMessageDuration": "Délka zobrazení zprávy v aplikaci (milisekundy)", + "FrmMain.MnuFrameless": "Bez rámečků", + "_._Reset": "Výchozí", + "FrmSettings._ConfigDir": "Umístění konfigurace", + "FrmQuickSetup._SettingsWillBeApplied": "Nastavení bude použito:", + "FrmSettings._UnmanagedSettingReminder": "Toto nastavení není spravováno aplikací ImageGlass. Nezapomeňte jej před odstraněním nebo přemístěním aplikace vypnout, protože ImageGlass to automaticky neřeší.", + "FrmMain.MnuClipboard": "Schránka", + "FrmMain.MnuCustomZoom": "Vlastní přiblížení…", + "FrmSettings._DisplayLanguage": "Zobrazit jazyk", + "FrmMain.MnuPrint._Error": "Nelze vytisknout prohlížený obrázek", + "FrmSettings._ShouldPreserveModifiedDate": "Při ukládání obrázku zachovat datum poslední změny", + "FrmSettings._ShowSaveOverrideConfirmation": "Zobrazit potvrzovací dialog při přepisování souboru", + "FrmColorPickerSettings.ChkShowHexA": "Použít HEX formát s hodnotou Alpha", + "FrmMain.MnuFullScreen": "Celá obrazovka", + "FrmSettings._StartupDir": "Umístění při spuštění", + "FrmSettings._ShowCheckerboardOnlyImageRegion": "Zobrazit šachovnici pouze v oblasti obrázku", + "FrmMain.MnuClearClipboard._Success": "Schránka vyčištěna.", + "FrmQuickSetup._Text": "Rychlé nastavení ImageGlass", + "FrmMain.MnuLosslessCompression._Done": "Bezeztrátová komprese dokončena.\r\nNová velikost souboru je {0}, ušetřeno {1}.", + "FrmMain.MnuLosslessCompression": "Magick.NET Bezeztrátová komprese", + "FrmResize.RadResizeByPercentage": "Procenta", + "FrmSettings._StartupBoost._Disabled": "Startup Boost je zakázán", + "FrmMain.MnuToggleCheckerboard": "Šachovnicové pozadí", + "FrmSettings._MinEmbeddedThumbnailSize._Height": "Výška", + "FrmSettings.Nav._General": "Obecné", + "FrmSettings._ImageLoading": "Načítání obrázku", + "FrmSettings._ShowSlideshowCountdown": "Ukaž odpočet času ve slideshow", + "FrmMain.MnuSave": "Uložit", + "FrmMain.MnuMoveToRecycleBin": "Přesunout do Koše", + "FrmMain.MnuRefresh": "Obnovit", + "FrmToolNotFound.LblHeading": "'{0}' nebyl nalezen!", + "FrmMain.MnuReportIssue": "Nahlásit chybu…", + "FrmMain.MnuCopyImageData": "Kopírovat data obrázku", + "FrmMain.MnuCheckForUpdate._NewVersion": "Nová verze je k dispozici!", + "_._Empty": "(prázdný)", + "FrmSettings._Zooming": "Zvětšení/zmenšení", + "FrmMain.MnuCutFile": "Vyjmout soubor", + "FrmHotkeyPicker.LblHotkey": "Stiskněte klávesovou zkratku", + "FrmSettings.Layout._Gallery": "Galerie", + "FrmMain.MnuNewWindow": "Otevřít v novém okně", + "FrmMain.MnuMoveToRecycleBin._Description": "Chcete přesunout tento soubor do koše?", + "FrmSettings._DefaultPhotoViewer": "Výchozí prohlížeč fotografií", + "_.Metadata._ExifDateTimeOriginal": "EXIF: Datum a čas originálu", + "FrmMain.MnuRotateRight": "Otočit vpravo", + "FrmSettings._MinEmbeddedThumbnailSize": "Minimální velikost načítané vložené miniatury", + "FrmMain.MnuSetDefaultPhotoViewer": "Nastavit výchozí prohlížeč fotografií", + "FrmMain.MnuImageProperties": "Vlastnosti obrazu", + "FrmSettings._EnableNavigationButtons": "Zobrazit navigační tlačítka se šipkami", + "_._Edit": "Upravit", + "FrmSettings._ImageBooster": "Image Booster", + "FrmSettings.Tools._IntegratedWith": "Integrováno s {0}", + "_._Next": "Další", + "FrmExportFrames._OpenOutputFolder": "Otevřít výstupní složku", + "FrmMain.MnuOpenLocation": "Otevřít umístění obrázku", + "FrmMain.MnuLockZoom": "Zamknout poměr přiblížení", + "FrmSettings._StartupBoost._Description": "Přednačíst a spustit ImageGlass na pozadí po dobu několika sekund během startu Windows pro zrychlení prvního spuštění.", + "FrmSettings._WindowBackdrop": "Pozadí okna", + "FrmSettings._EnableRealTimeFileUpdate": "Sledovat změny souborů v prohlížené složce a aktualizovat v reálném čase", + "_._NotSupported": "Nepodporovaný formát", + "FrmSettings._Theme._GetMoreThemes": "Získat další balíčky vzhledu…", + "FrmMain.MnuNewWindow._Error": "Nelze otevřít nové okno, protože je povolena pouze jedna instance", + "FrmMain.MnuZoomOut": "Oddálit", + "FrmSettings.Toolbar._EditButton": "Upravit tlačítko panelu nástrojů", + "FrmMain.MnuCustomZoom._Description": "Zadejte novou hodnotu přiblížení", + "FrmResize.RadResizeByPixels": "Pixely", + "FrmMain.MnuEdit": "Upravit obrázek {0}…", + "FrmSettings.Layout._GalleryPosition": "Pozice galerie", + "FrmMain.MnuWindowFit": "Přizpůsobit oknu", + "FrmMain._OpenFileDialog": "Všechny podporované soubory", + "FrmSettings._UseRandomIntervalForSlideshow": "Použít náhodný interval", + "_.Position._Left": "Vlevo", + "FrmSettings._ShouldOpenLastSeenImage": "Otevřít naposledy zobrazený obrázek", + "_.Position._Bottom": "Dolů", + "FrmResize.ChkKeepRatio": "Zachovat poměr stran", + "FrmMain.MnuGoTo": "Přejít na…", + "FrmSlideshow.MnuPauseResumeSlideshow": "Pozastavit/obnovit prezentaci", + "FrmSettings.Tools._Integrated": "Integrovaný", + "FrmSettings._Contributors": "Přispěvatelé", + "_.MouseWheelAction._Zoom": "Přiblížit / Oddálit", + "_._CommandPreview": "Náhled příkazu", + "FrmSettings._DarkTheme": "Tmavý", + "_._Hotkeys": "Klávesové zkratky", + "_.Metadata._ExifDateTime": "EXIF: DateTime", + "FrmSettings.Toolbar._Errors._ButtonIdRequired": "ID tlačítka je povinné.", + "FrmSettings._MinEmbeddedThumbnailSize._Width": "Šířka", + "_._Executable": "Spustitelný", + "_.ImageInterpolation._MultiSampleLinear": "Multi-sample lineární", + "_._Separator": "Oddělovač", + "FrmQuickSetup._ProfessionalUser": "Profesionální uživatel", + "FrmMain.MnuFlipVertical": "Překlopit vertikálně", + "FrmSlideshow._ResumeSlideshow": "Prezentace je obnovena.", + "FrmCropSettings.DefaultSelectionType._CustomArea": "Vlastní oblast…", + "FrmMain.MnuActualSize": "Skutečná velikost", + "FrmCrop.BtnSaveAs": "Uložit jako…", + "FrmSettings._InstallNewLanguagePack": "Nainstalovat nové jazykové sady…", + "FrmSlideshow.MnuZoomModes": "Režimy přiblížení", + "FrmMain.MnuTools": "Nástroje", + "_.ImageInterpolation._Cubic": "Krychlový", + "FrmUpdate._LatestVersion": "Nejnovější verze: {0}", + "FrmMain.MnuViewNext": "Zobrazit další obrázek", + "_.MouseWheelEvent._AltAndScroll": "Držet Alt a rolovat", + "FrmToolNotFound._Title": "Nástroj nebyl nalezen", + "FrmCrop.BtnCrop._Tooltip": "Oříznout pouze obrázek", + "FrmSettings.EditAppDialog._AddApp": "Přidat aplikaci pro úpravy", + "FrmMain.MnuPanning": "Posouvání", + "_._MoveUp": "Přesunout nahoru", + "FrmCropSettings.DefaultSelectionType._SelectAll": "Vybrat vše", + "_._Name": "Název", + "FrmColorPickerSettings.ChkShowHslA": "Použít HSL formát s hodnotou Alpha", + "FrmMain.MnuToggleImageAnimation": "Spustit / zastavit animaci obrázku", + "FrmSettings._DisableStartupBoost": "Zakázat Startup Boost", + "FrmMain.MnuCopyFile._Success": "Soubor(y) {0} byly zkopírovány.", + "FrmMain.MnuSave._ConfirmDescription": "ImageGlass není profesionální fotoeditor, mějte prosím na paměti možnou ztrátu kvality, metadat, vrstev... při ukládání obrázku.", + "FrmToolNotFound.BtnSelectExecutable": "Vybrat…", + "FrmUpdate._StatusOutdated": "Nalezena nová aktualizace!", + "_.ImageOrderBy._Random": "Náhodně", + "FrmResize.LblCurrentSize": "Aktuální velikost:", + "_._Apply": "Použít", + "FrmAbout._Slogan": "Lehký, univerzální prohlížeč obrázků", + "FrmMain.MnuPanToTop": "Posunout k hornímu okraji", + "FrmSettings.Toolbar._AddNewButton": "Přidat vlastní tlačítko panelu nástrojů", + "FrmCrop.LblSize": "Velikost:", + "FrmSettings._ImageInterpolation._ScaleDown": "Při zmenšení < 100%", + "_._CreatingFileError": "Nelze vytvořit dočasný soubor obrázku", + "FrmMain.MnuGoTo._Description": "Zadejte index obrázku pro zobrazení a stiskněte ENTER", + "FrmSettings.Toolbar._EnableCenterToolbar": "Zarovnať panel nástrojů na střed", + "FrmMain.MnuResizeTool": "Změnit velikost obrázku", + "FrmSettings.Layout._Toolbar": "Panel nástrojů", + "FrmMain.MnuHelp": "Pomoc", + "_.ImageOrderBy._FileSize": "Velikost souboru", + "FrmSettings._Theme._OpenThemeFolder": "Otevřít složku vzhledů", + "FrmMain.MnuNavigation": "Navigace", + "_._Save": "Uložit", + "FrmQuickSetup._SettingProfileDescription": "Chcete-li tato nastavení změnit, jednoduše přejděte do nastavení aplikace.", + "_._UserAction._MenuNotFound": "Nelze nalézt nabídku '{0}' pro vyvolání akce", + "FrmMain.MnuPanToLeftSide": "Posunout k levému okraji", + "FrmUpdate._CurrentVersion": "Aktuální verze: {0}", + "FrmCrop.BtnSettings._Tooltip": "Otevřít nastavení nástroje ořezu", + "_.ColorProfileOption._Custom": "Vlastní…", + "FrmSettings._UseEmbeddedThumbnailOtherFormats": "Načítat pouze vložené miniatury pro ostatní formáty", + "FrmMain.MnuGoToFirst": "Přejít na první obrázek", + "FrmSettings._ExportLanguagePack": "Exportovat jazykovou sadu…", + "FrmSettings.Nav._Mouse": "Myš", + "_.ImageOrderBy._DateCreated": "Datum vytvoření", + "FrmSettings._EnableFullscreenSlideshow": "Spustit prezentaci v režimu celé obrazovky", + "FrmAbout._Homepage": "Domovská stránka:", + "FrmSettings._GalleryCacheSizeInMb": "Maximální velikost mezipaměti galerie (v megabajtech)", + "FrmMain.MnuCopyImageData._Success": "Data aktuálního obrázku zkopírována.", + "FrmSettings._EnableLoopBackNavigation": "Po dosažení konce seznamu se vrátit na první obrázek", + "_.MouseWheelEvent._Scroll": "Rolovat", + "FrmCrop.BtnSave._Tooltip": "Uložit obrázek", + "FrmMain.MnuSlideshow": "Prezentace", + "FrmMain.MnuShare": "Sdílet…", + "FrmSettings._SlideshowNotification": "Upozornění prezentace", + "FrmMain.MnuViewChannels": "Zobrazit kanály", + "FrmSettings._Refresh": "Obnovit", + "_._UserAction._MethodNotFound": "Nelze nalézt metodu '{0}' pro vyvolání akce", + "FrmMain.MnuCopyFile": "Zkopírovat soubor", + "_._CreatingFile": "Vytváření dočasného souboru obrázku…", + "FrmMain.MnuToggleTopMost": "Ponechat okno vždy nahoře", + "FrmMain.MnuLosslessCompression._Confirm": "Opravdu chcete pokračovat?", + "FrmMain.MnuImage": "Obrázek", + "FrmSettings._StartupBoost._Enabled": "Startup Boost je povolen", + "FrmQuickSetup._SetDefaultViewer": "Chcete nastavit ImageGlass jako výchozí prohlížeč fotografií?", + "FrmMain.MnuScaleToWidth": "Přizpůsobit šířce okna", + "_._FileExtension": "Přípona souboru", + "FrmUpdate._PublishedDate": "Datum zveřejnění: {0}", + "_._DoNotShowThisMessageAgain": "Tuto zprávu již příště nezobrazovat", + "_.ImageInterpolation._NearestNeighbor": "Nejbližší soused", + "FrmCrop.LblLocation": "Poloha:", + "_._Download": "Stáhnout", + "_.Metadata._ColorProfile": "Barevný profil", + "FrmSettings._CenterWindowFit": "Automaticky vycentrovat okno v režimu Přizpůsobit oknu", + "FrmSettings._ImageLoadingOrder": "Pořadí načítání obrázků", + "FrmSettings._GalleryColumns": "Počet sloupců miniatur ve vertikálním rozložení galerie", + "_._Quit": "Ukončit", + "_._Add": "Přidat", + "FrmMain.MnuChangeBackgroundColor": "Změnit barvu pozadí…", + "FrmMain.MnuToggleToolbar": "Panel nástrojů", + "FrmAbout._Contact": "Kontakt", + "FrmSettings.Toolbar._AddCustomButton": "Přidat vlastní tlačítko…", + "FrmCrop.BtnQuickSelect._Tooltip": "Rychlý výběr…", + "FrmMain.MnuCutFile._Success": "Vyjmuto {0} soubor(ů).", + "FrmSettings._ZoomSpeed": "Rychlost přiblížení", + "FrmMain.MnuToggleTopMost._Disable": "Zakázáno okno vždy nahoře", + "FrmSettings._ShouldUseExplorerSortOrder": "Použít řazení Průzkumníka, pokud je to možné", + "_.ImageInterpolation._Antisotropic": "Anizotropní", + "FrmMain._ReachedFirstImage": "Dosaženo prvního obrázku", + "_._UnhandledException": "Neošetřená výjimka", + "FrmResize.LblNewSize": "Nová velikost:", + "FrmMain._ClipboardImage": "Obrázek ze schránky", + "FrmMain.MnuExportFrames": "Exportovat snímky obrázku…", + "FrmMain.MnuFile": "Soubor", + "_._Close": "Ukončit ImageGlass", + "FrmMain.MnuMain": "Hlavní nabídka", + "_._ResetToDefault": "Obnovit výchozí", + "FrmSettings.Nav._Gallery": "Galerie", + "FrmMain.MnuSetDefaultPhotoViewer._Success": "Úspěšně jste nastavili ImageGlass jako výchozí prohlížeč fotografií.", + "FrmSettings._HideGalleryInFullscreen": "Skrýt galerii v režimu celé obrazovky", + "FrmSettings._AvailableImageInfoTags": "Dostupné štítky:", + "FrmExportFrames._Exporting": "Exportování {0}/{1} snímků \r\n{2}…", + "_._Argument": "Argument", + "FrmSettings._ImageEditQuality": "Kvalita obrázku", + "_._ID": "ID", + "FrmSettings._UserConfigFile": "Soubor uživatelského nastavení (igconfig.json)", + "FrmMain.MnuLoadingOrders": "Pořadí načítání", + "FrmSettings._OpenSaveAsDialogInTheCurrentImageDir": "Otevřít dialog Uložit jako v adresáři aktuálního obrázku", + "_.MouseWheelEvent._ShiftAndScroll": "Držet Shift a rolovat", + "FrmSettings._UseSmoothZooming": "Použít hladké přiblížení", + "FrmSettings._Theme": "Vzhled", + "FrmSettings._ImageBoosterCacheMaxDimension": "Maximální rozměr obrázku v mezipaměti (v pixelech)", + "FrmMain.MnuScaleToHeight": "Přizpůsobit výšce okna", + "_.Metadata._FileLastWriteTime": "Datum změny", + "FrmSettings._Author": "Autor", + "FrmSettings._Others": "Ostatní", + "_.MouseWheelAction._PanVertically": "Posunout nahoru / dolů", + "FrmSettings._MouseWheelAction": "Akce kolečka myši", + "FrmSettings.Nav._Tools": "Nástroje", + "FrmMain.MnuSetDesktopBackground._Error": "Nelze nastavit prohlížený obrázek jako pozadí plochy", + "FrmSettings.Toolbar._Errors._ButtonExecutableRequired": "Spustitelný soubor tlačítka je vyžadován.", + "_.ImageOrderBy._DateAccessed": "Datum přístupu", + "FrmSettings._ThumbnailSize": "Velikost miniatury (v pixelech)", + "FrmSettings._FileFormats": "Formáty souborů", + "FrmMain.MnuReloadImageList": "Znovu načíst seznam obrázků", + "FrmSettings._UseWebview2ForSvg": "Použít Webview2 pro zobrazení formátu SVG", + "FrmCrop.BtnCopy": "Kopírovat", + "FrmSettings._CurrentMonitorProfile._Description": "ImageGlass neaktualizuje barvy automaticky při přesunu okna mezi monitory", + "FrmMain.PicMain._ErrorText": "Tento obrázek se nepodařilo otevřít", + "FrmSettings.Tools._AddNewTool": "Přidat nový externí nástroj", + "FrmMain.MnuRename": "Přejmenovat obrázek…", + "FrmMain.MnuViewLastFrame": "Zobrazit poslední snímek", + "_._Webview2._NotFound": "Pro přístup ke všem funkcím ImageGlass nainstalujte prosím WebView2 Runtime.", + "FrmMain.MnuGetMoreTools": "Získejte více nástrojů…", + "FrmSettings.Nav._Appearance": "Vzhled", + "FrmSettings._SlideshowInterval": "Interval promítání slideshow:", + "_.ImageInterpolation._HighQualityBicubic": "Vysoká kvalita bikubická", + "FrmColorPickerSettings.ChkShowHsvA": "Použít HSL formát s hodnotou Alpha", + "FrmSettings.Tools._EditTool": "Upravit externí nástroj", + "_._Error": "Chyba", + "FrmSettings._ImageBoosterCacheMaxFileSizeInMb": "Maximální velikost souboru obrázku v mezipaměti (v megabajtech)", + "_._UnhandledException._Description": "Došlo k neošetřené výjimce. Pokud klepnete na tlačítko Pokračovat, aplikace tuto chybu ignoruje a pokusí se pokračovat. Pokud klepnete na tlačítko Ukončit aplikaci, okamžitě se zavře.", + "_.Metadata._FileSize": "Velikost souboru", + "FrmSettings.Toolbar._ButtonJson": "JSON tlačítka", + "FrmQuickSetup._SetDefaultViewer._Description": "Můžete to resetovat v nastavení aplikace > karta Asociace typů souborů.", + "FrmSettings.Nav._Edit": "Upravit", + "FrmMain.MnuToggleGallery": "Panel galerie", + "_._IgCommandExe._DefaultError._Description": "Ujistěte se, že zadáváte správné příkazy!\r\nTento spustitelný soubor obsahuje funkce příkazového řádku pro software ImageGlass.\r\n\r\nPro prozkoumání všech příkazových řádků navštivte prosím:\n{0}", + "FrmMain.MnuLosslessCompression._Compressing": "Provádění bezeztrátové komprese…", + "FrmSettings._ShouldGroupImagesByDirectory": "Seskupit obrázky podle adresáře", + "FrmMain.MnuPanToRightSide": "Posunout obrázek k pravému okraji", + "_.Metadata._ExifRatingPercent": "Hodnocení", + "FrmSettings._PanSpeed": "Rychlost posouvání", + "_._CheckForUpdate": "Kontrola aktualizací…", + "FrmSettings.Layout._ToolbarContext": "Kontextový panel nástrojů", + "_.ImageInfo._FrameCount": "{0} snímků", + "FrmMain.MnuLayout": "Rozložení", + "_._Website": "Webová stránka", + "FrmMain.MnuPasteImage": "Vložit obrázek", + "FrmSettings._ShowGalleryScrollbars": "Zobrazit posuvníky galerie" + } +} \ No newline at end of file diff --git a/Setup/Assets/Language/Danish.iglang.json b/Setup/Assets/Language/Danish.iglang.json new file mode 100644 index 000000000..63b988ae4 --- /dev/null +++ b/Setup/Assets/Language/Danish.iglang.json @@ -0,0 +1,504 @@ +{ + "_Metadata": { + "Code": "da-DK", + "EnglishName": "Danish", + "LocalName": "Dansk", + "Author": "Kevin Ringsborg Neergaard, Magnus Schatz-Jakobsen", + "MinVersion": "9.3" + }, + "Items": { + "FrmCrop.SelectionAspectRatio._Original": "Original", + "FrmMain.MnuShare._Error": "Could not open Share dialog.", + "_.Metadata._FileLastAccessTime": "Date accessed", + "FrmAbout._License": "Software license", + "FrmSettings.Toolbar._Errors._ButtonIdDuplicated": "A button with the ID '{0}' has already been defined. Please choose a different and unique ID for your button to avoid conflicts.", + "FrmMain.MnuSave._Confirm": "Are you sure you want to override this image?", + "FrmSettings._OpenDefaultAppsSetting": "Open Default apps setting", + "FrmMain.MnuCopyPath": "Kopier filsti", + "FrmCropSettings.DefaultSelectionType._SelectNone": "Select none", + "_.MouseWheelAction._PanHorizontally": "Pan left / right", + "FrmMain.MnuPrint": "Udskriv…", + "FrmSettings.Toolbar._ToolbarButtons": "Toolbar buttons", + "FrmResize.LblResample": "Resample:", + "_.ImageOrderBy._Extension": "Tilføjelser", + "FrmSettings.Nav._Viewer": "Fremviser", + "FrmSettings.EditAppDialog._EditApp": "Edit app", + "FrmCrop.BtnReset._Tooltip": "Reset selection", + "FrmMain.MnuRename._Description": "Enter a new filename:", + "_._No": "Yes", + "FrmSlideshow.MnuToggleCountdown": "Vis nedtælling af diasshow", + "FrmSettings._OpenStartupAppsSetting": "Open Startup apps setting", + "FrmMain.MnuViewPreviousFrame": "View previous frame", + "_.ImageOrderBy._DateModified": "Date modified", + "FrmMain.MnuViewNextFrame": "View next frame", + "FrmMain.MnuUnload": "Unload image", + "FrmSettings.Toolbar._HideToolbarInFullscreen": "Hide toolbar in Full Screen mode", + "_.ImageOrderType._Desc": "Faldende", + "_._Update": "Update", + "FrmSettings._EnableImageAsyncLoading": "Enable image asynchronous loading", + "FrmSettings._DefaultPhotoViewer._Description": "Register the supported formats of ImageGlass with Windows. You might need to open the Default apps settings and manually select ImageGlass from the list for it to take effect.", + "_.MouseWheelAction._BrowseImages": "View next / previous Image", + "FrmSettings._EditApps": "Image editing apps", + "FrmColorPickerSettings.ChkShowCIELabA": "Use CIELAB format with alpha value", + "_._GetHelp": "Get help", + "FrmQuickSetup._SkipQuickSetup": "Skip this and launch ImageGlass", + "FrmColorPickerSettings._Title": "Color picker settings", + "_._Copy": "Kopier", + "FrmSettings._ImageBoosterCacheCount": "Number of images cached by Image Booster (one direction)", + "FrmMain.MnuPanToBottom": "Pan image to bottom", + "FrmMain.MnuZoom": "Zoom", + "FrmCropSettings.ChkCloseToolAfterSaving": "Close Crop tool after saving", + "FrmSettings._ShowWelcomeImage": "Show welcome image", + "FrmSettings._ColorProfile": "Color profile", + "FrmSettings._Theme._UninstallTheme": "Uninstall a theme pack", + "FrmMain._OpenWith": "Open with {0}", + "FrmMain.MnuRemoveDefaultPhotoViewer": "Remove default photo viewer", + "_.AfterEditAppAction._Nothing": "Ingen", + "FrmCrop.BtnSave": "Gem", + "FrmMain.MnuScaleToFit": "Tilpas størrelse", + "FrmToolNotFound.LblDownloadToolText": "You can download more tools for ImageGlass at:", + "_._LearnMore": "Learn more…", + "FrmCrop.LblAspectRatio": "Aspect ratio:", + "FrmExportFrames._FileNotExist": "Image file does not exist", + "FrmSettings._LightTheme": "Light", + "FrmSettings.Nav._Slideshow": "Slideshow", + "_._Continue": "Continue", + "_._AddHotkey": "Add hotkey…", + "FrmMain.MnuSetDesktopBackground": "Anvend som skrivebordsbaggrund", + "FrmMain.MnuReload": "Opdater billede", + "FrmSlideshow.MnuExitSlideshow": "Exit slideshow", + "FrmMain.MnuAutoZoom": "Auto zoom", + "FrmSettings._ShowImagePreview": "Display image preview while it's being loaded", + "FrmCrop.BtnCopy._Tooltip": "Copy the selection to clipboard", + "FrmSettings.Nav._Toolbar": "Værktøjslinje", + "FrmMain.MnuSave._Error": "Could not save the image", + "FrmSettings._AfterEditingAction": "Efter åbning redigering app", + "FrmSettings._ShouldUseColorProfileForAll": "Anvend også til billeder uden indlejret farveprofil", + "FrmCropSettings.DefaultSelectionType._UseTheLastSelection": "Use the last selection", + "FrmSettings._SlideshowInterval._From": "From", + "FrmSettings._ImageInterpolation": "Image interpolation", + "FrmQuickSetup._StepInfo": "Step {0}", + "FrmMain.MnuColorPicker": "Pipette", + "FrmCrop.SelectionAspectRatio._FreeRatio": "Free ratio", + "FrmSettings._ResetSettings": "Reset settings", + "FrmSettings._Startup": "Startup", + "_.BackdropStyle._None": "Ingen", + "FrmSettings._LoadDefaultZoomLevels": "Load default zoom levels", + "FrmColorPicker.BtnSettings._Tooltip": "Open Color picker settings…", + "FrmSettings._UseThemeForDarkMode": "Use this theme for dark mode", + "FrmSettings._ShowDeleteConfirmation": "Show confirmation dialog when deleting file", + "FrmSettings._ShowAppIcon": "Show app icon on the title bar", + "_._InvalidAction": "Invalid action", + "FrmQuickSetup._SelectProfile": "Select a profile", + "_.Metadata._FileCreationTime": "Date created", + "FrmSettings._SlideshowImagesToNotifySound": "Number of images to trigger a notification sound", + "FrmSettings._BackgroundColor": "Viewer background color", + "FrmSettings._RealTimeFileUpdate": "Real-time file update", + "_.ColorProfileOption._CurrentMonitorProfile": "Current monitor profile", + "FrmSettings._EnableCutMultipleFiles": "Enable the cutting of multiple files at once", + "FrmSettings._AutoUpdate": "Tjek for opdatering automatisk", + "FrmCropSettings.LblDefaultSelection": "Default selection", + "FrmSettings._UseThemeForLightMode": "Use this theme for light mode", + "FrmSettings._ZoomLevels": "Zoom niveau", + "FrmMain.MnuSetLockScreen._Success": "Lock screen image is updated", + "FrmSettings._ShowGalleryFileName": "Show thumbnail filename", + "FrmSettings.Layout._Order": "Order", + "FrmCropSettings.ChkAutoCenterSelection": "Auto-center selection", + "FrmSettings.Nav._FileTypeAssociations": "File type associations", + "_._Back": "Back", + "FrmMain.MnuSetDesktopBackground._Success": "Desktop background is updated", + "FrmSettings._ShouldAutoOpenNewAddedImage": "Open the new added image automatically", + "FrmCrop.SelectionAspectRatio._Custom": "Brugerdefineret…", + "FrmMain.MnuCopyPath._Success": "Copied the current image path.", + "FrmSettings._StartupBoost._Error": "Could not change Startup Boost setting", + "FrmToolNotFound.LblDescription": "ImageGlass was unable to locate the path to the '{0}' executable. To resolve this issue, please update the path to the '{0}' as necessary.", + "FrmMain.MnuClearClipboard": "Fjern udklip", + "FrmSettings._ColorManagement": "Farvestyring", + "FrmMain._ReachedLastLast": "Nået det sidste billede", + "FrmMain.MnuPanUp": "Pan image up", + "FrmMain.MnuRemoveDefaultPhotoViewer._Success": "ImageGlass is no longer the default photo viewer.", + "FrmSettings._GetMoreLanguagePacks": "Få flere sprogpakker…", + "FrmAbout._Privacy": "Privacy policy", + "FrmSettings._EnableRecursiveLoading": "Load images in subfolders", + "_._UserAction._MethodArgumentNotSupported": "The argument type of method '{0}' is not supported", + "FrmSettings._FileExtensionIcons._Description": "For customizing file extension icons, download an icon pack, place all .ICO files in the extension icon folder, and click the '{0}' button. This will also set ImageGlass as default photo viewer.", + "_.ImageOrderType._Asc": "Stigende", + "FrmExportFrames._Title": "Export image frames", + "_._Install": "Installer…", + "FrmMain.MnuFlipHorizontal": "Vend Vandret", + "FrmSettings._OpenExtensionIconFolder": "Open extension icon folder", + "FrmAbout._Collaborator": "Collaborator:", + "FrmQuickSetup._ConfirmCloseProcess": "Before applying the new settings, it's essential to close all ImageGlass processes. Are you ready to proceed?", + "FrmExportFrames._ExportDone": "Exported {0} frames successfully to \r\n{1}", + "FrmCrop.BtnSaveAs._Tooltip": "Save as a copy…", + "FrmMain.MnuOpenFile": "Åbn fil…", + "FrmColorPickerSettings.ChkShowRgbA": "Use RGB format with alpha value", + "_.ImageInfo._ListCount": "{0} file(s)", + "FrmMain.MnuGoToLast": "Go to last image", + "FrmSettings._EditApps._AppName": "App navn", + "FrmSettings._SlideshowBackgroundColor": "Slideshow background color", + "FrmAbout._Email": "Email:", + "_.MouseWheelAction._DoNothing": "Gør ingenting", + "FrmMain.MnuSaveAs": "Gem som…", + "FrmMain._Loading": "Loading…", + "_._Browse": "Gennemse…", + "FrmMain.MnuSetDefaultPhotoViewer._Error": "Could not set ImageGlass as default photo viewer.", + "FrmSettings.Nav._Language": "Sprog", + "FrmQuickSetup._SeeWhatNew": "See what's new in this version…", + "FrmSettings._ImageInterpolation._ScaleUp": "When zoom > 100%", + "FrmSettings.Layout._ToolbarContextPosition": "Contextual toolbar position", + "FrmMain.MnuDeleteFromHardDisk": "Delete permanently", + "FrmSettings._EmbeddedThumbnail": "Embedded thumbnail", + "FrmMain.MnuDeleteFromHardDisk._Description": "Are you sure you want to permanently delete this file?", + "FrmMain.MnuScaleToFill": "Tilpas fuld størrelse", + "FrmCrop.BtnCrop": "Crop", + "_.AfterEditAppAction._Minimize": "Minimer", + "FrmMain.MnuInvertColors": "Invert colors", + "FrmSettings._StartupBoost": "Startup Boost", + "FrmMain.MnuViewFirstFrame": "View first frame", + "_.MouseWheelEvent._CtrlAndScroll": "Hold Ctrl and scroll", + "FrmSettings._HideMainWindowInSlideshow": "Automatically hide main window", + "_.Metadata._FrameCount": "Frames", + "FrmSettings._EnableCopyMultipleFiles": "Enable the copying of multiple files at once", + "FrmMain.MnuFrameless._EnableDescription": "Hold Shift key to move the window.", + "_.ImageOrderBy._ExifDateTaken": "EXIF: Date taken", + "FrmAbout._Credits": "Credits", + "FrmSettings._AddNewFileExtension": "Add new file extension", + "FrmMain.MnuQuickSetup": "Open ImageGlass Quick Setup", + "FrmMain.MnuSave._Success": "Image is saved", + "FrmMain.MnuPanLeft": "Pan image left", + "FrmUpdate._StatusChecking": "Checking for update…", + "FrmSettings.Nav._Layout": "Layout", + "FrmMain.MnuOpenWith": "Åbn med…", + "FrmAbout._Thanks": "Special thanks to", + "_._Warning": "Warning", + "FrmSettings.Nav._Keyboard": "Tastatur", + "FrmSlideshow._PauseSlideshow": "Slideshow is paused.", + "_._Add+": "Tilføj…", + "_._Email": "Email", + "FrmMain.MnuPanDown": "Pan image down", + "_._Cancel": "Annuller", + "_._OK": "OK", + "FrmMain.MnuPanRight": "Pan image right", + "_.Position._Right": "Right", + "_._Icon": "Icon", + "FrmSettings._ShouldLoadHiddenImages": "Load hidden images", + "_._InvalidAction._Transformation": "ImageGlass does not support rotation, flipping for this image.", + "FrmSettings._MakeDefault": "Make default", + "FrmMain.MnuCopyImageData._Copying": "Copying the image data. It's going to take a while…", + "FrmSettings._UseEmbeddedThumbnailRawFormats": "Load only the embedded thumbnail for RAW formats", + "_.ImageInterpolation._Linear": "Linear", + "FrmSettings._ImageInfoTags": "Image information tags", + "FrmSettings._FileExtensionIcons": "File extension icons", + "FrmMain.MnuEdit._AppNotFound": "Could not find the associated app for editing. You can assign an app for editing this format in ImageGlass Settings > Edit.", + "_.ColorProfileOption._None": "Ingen", + "FrmSettings._TotalSupportedFormats": "Total supported formats: {0}", + "FrmSettings._Clipboard": "Udklip holder", + "_._UserAction._Win32ExeError": "Cannot execute command '{0}'. Make sure the name is correct.", + "FrmCropSettings.DefaultSelectionType._SelectX": "Select {0}", + "_.AfterEditAppAction._Close": "Luk", + "FrmAbout._LogoDesigner": "Logo designer:", + "_.ImageOrderBy._Name": "Navn (standard)", + "FrmMain.MnuRemoveDefaultPhotoViewer._Error": "Could not remove ImageGlass as the default photo viewer.", + "FrmExportFrames._FolderPickerTitle": "Select output folder for exporting image frames", + "FrmAbout._Donate": "Donate", + "FrmMain.MnuFrameNav": "Frame navigation", + "FrmMain.MnuSetLockScreen": "Anvend som låseskærmsbillede", + "_._Delete": "Slet", + "FrmMain.MnuViewPrevious": "Vis forrige billede", + "_.Position._Top": "Top", + "FrmSettings.Toolbar._CurrentButtons": "Current buttons:", + "FrmMain.MnuAbout": "Om", + "FrmSettings._RemoveDefault": "Remove default", + "_._Description": "Beskrivelse", + "FrmMain.MnuPasteImage._Error": "Could not find image data in the Clipboard", + "FrmMain.MnuSettings": "Indstillinger", + "FrmCropSettings._Title": "Crop settings", + "FrmSettings.Toolbar._ToolbarIconHeight": "Værktøjslinjens ikonstørrelse", + "FrmSettings._SlideshowInterval._To": "To", + "FrmSettings.Layout._ToolbarPosition": "Toolbar position", + "FrmUpdate._StatusUpdated": "You are using the latest version!", + "FrmMain.MnuExit": "Afslut", + "_._Webview2._Outdated": "Your WebView2 Runtime is not supported. Please update to version {0} or later.", + "_._Yes": "Ja", + "FrmMain.MnuRotateLeft": "Rotér venstre om", + "FrmSettings._EnableStartupBoost": "Enable Startup Boost", + "_.ImageOrderBy._ExifRating": "EXIF: Rating", + "FrmMain.MnuZoomIn": "Zoom ind", + "_.Metadata._ColorSpace": "Color space", + "FrmAbout._Version": "Version:", + "FrmMain.MnuToggleTopMost._Enable": "Enabled window always on top", + "FrmSettings.Toolbar._AvailableButtons": "Available buttons:", + "FrmMain.MnuSave._Saving": "Saving image…", + "FrmQuickSetup._StandardUser": "Standard user", + "FrmMain.MnuSetLockScreen._Error": "Could not set the viewing image as lock screen image", + "FrmSettings.Nav._Image": "Billede", + "FrmSettings._Theme._InstallTheme": "Install theme packs", + "FrmSettings._EnableMultiInstances": "Tillad flere instanser af programmet", + "FrmMain.MnuCropTool": "Crop image", + "_._IgCommandExe._DefaultError._Heading": "Invalid commands", + "_._Refresh": "Opdater", + "FrmMain.MnuLosslessCompression._Description": "This tool uses Magick.NET library for lossless compression, optimizing file size. Overwrites only if the compressed file is smaller than the original.", + "_._MoveDown": "Move down", + "FrmSettings._GetExtensionIconPacks": "Get extension icon packs…", + "FrmSettings._InAppMessageDuration": "In-app message duration (milliseconds)", + "FrmMain.MnuFrameless": "Uden ramme", + "_._Reset": "Nulstil", + "FrmSettings._ConfigDir": "Configuration location", + "FrmQuickSetup._SettingsWillBeApplied": "Settings will be applied:", + "FrmSettings._UnmanagedSettingReminder": "This setting is not managed by ImageGlass. Don't forget to disable it before you remove or relocate the app because ImageGlass does not handle this automatically.", + "FrmMain.MnuClipboard": "Udklip holder", + "FrmMain.MnuCustomZoom": "Tilpasset zoom…", + "FrmSettings._DisplayLanguage": "Display language", + "FrmMain.MnuPrint._Error": "Could not print the viewing image", + "FrmSettings._ShouldPreserveModifiedDate": "Bevar billedets ændrede dato ved gemning", + "FrmSettings._ShowSaveOverrideConfirmation": "Show confirmation dialog when overriding file", + "FrmColorPickerSettings.ChkShowHexA": "Use HEX format with alpha value", + "FrmMain.MnuFullScreen": "Full Screen", + "FrmSettings._StartupDir": "Startup location", + "FrmSettings._ShowCheckerboardOnlyImageRegion": "Show checkerboard only within the image region", + "FrmMain.MnuClearClipboard._Success": "Cleared clipboard.", + "FrmQuickSetup._Text": "ImageGlass Quick Setup", + "FrmMain.MnuLosslessCompression._Done": "Done lossless compression.\r\nThe new file size is {0}, saved {1}.", + "FrmMain.MnuLosslessCompression": "Magick.NET Lossless Compression", + "FrmResize.RadResizeByPercentage": "Percentage", + "FrmSettings._StartupBoost._Disabled": "Startup Boost is disabled", + "FrmMain.MnuToggleCheckerboard": "Ternet baggrund", + "FrmSettings._MinEmbeddedThumbnailSize._Height": "Højde", + "FrmSettings.Nav._General": "Generelt", + "FrmSettings._ImageLoading": "Indlæser billede", + "FrmSettings._ShowSlideshowCountdown": "Vis nedtælling af diasshow", + "FrmMain.MnuSave": "Gem", + "FrmMain.MnuMoveToRecycleBin": "Move to the Recycle Bin", + "FrmMain.MnuRefresh": "Opdater", + "FrmToolNotFound.LblHeading": "'{0}' is not found!", + "FrmMain.MnuReportIssue": "Rapportér et problem…", + "FrmMain.MnuCopyImageData": "Kopier billede data", + "FrmMain.MnuCheckForUpdate._NewVersion": "Opdatering tilgængelig!", + "_._Empty": "(empty)", + "FrmSettings._Zooming": "Zooming", + "FrmMain.MnuCutFile": "Cut file", + "FrmHotkeyPicker.LblHotkey": "Press hotkeys", + "FrmSettings.Layout._Gallery": "Gallery", + "FrmMain.MnuNewWindow": "Åben nyt vindue", + "FrmMain.MnuMoveToRecycleBin._Description": "Do you want to move this file to the Recycle bin?", + "FrmSettings._DefaultPhotoViewer": "Default photo viewer", + "_.Metadata._ExifDateTimeOriginal": "EXIF: DateTimeOriginal", + "FrmMain.MnuRotateRight": "Rotér højre om", + "FrmSettings._MinEmbeddedThumbnailSize": "Minimum size of the embedded thumbnail to be loaded", + "FrmMain.MnuSetDefaultPhotoViewer": "Set default photo viewer", + "FrmMain.MnuImageProperties": "Billede engenskaber", + "FrmSettings._EnableNavigationButtons": "Show navigation arrow buttons", + "_._Edit": "Rediger", + "FrmSettings._ImageBooster": "Image Booster", + "FrmSettings.Tools._IntegratedWith": "Integrated with {0}", + "_._Next": "Næste", + "FrmExportFrames._OpenOutputFolder": "Open output folder", + "FrmMain.MnuOpenLocation": "Åben billedplacering", + "FrmMain.MnuLockZoom": "Lås Zoom ratio", + "FrmSettings._StartupBoost._Description": "Preload and run ImageGlass in the background for a few seconds during Windows startup to accelerate the first launch.", + "FrmSettings._WindowBackdrop": "Window backdrop", + "FrmSettings._EnableRealTimeFileUpdate": "Monitor file changes in the viewing folder and update in realtime", + "_._NotSupported": "Unsupported format", + "FrmSettings._Theme._GetMoreThemes": "Get more theme packs…", + "FrmMain.MnuNewWindow._Error": "Cannot open new window because only one instance is allowed", + "FrmMain.MnuZoomOut": "Zoom ud", + "FrmSettings.Toolbar._EditButton": "Edit toolbar button", + "FrmMain.MnuCustomZoom._Description": "Angiv en ny zoomværdi", + "FrmResize.RadResizeByPixels": "Pixels", + "FrmMain.MnuEdit": "Rediger billede {0}…", + "FrmSettings.Layout._GalleryPosition": "Gallery position", + "FrmMain.MnuWindowFit": "Window Fit", + "FrmMain._OpenFileDialog": "Alle understøttede filer", + "FrmSettings._UseRandomIntervalForSlideshow": "Brug tilfældigt interval", + "_.Position._Left": "Left", + "FrmSettings._ShouldOpenLastSeenImage": "Open the last seen image", + "_.Position._Bottom": "Bund", + "FrmResize.ChkKeepRatio": "Keep ratio propotional", + "FrmMain.MnuGoTo": "Gå til…", + "FrmSlideshow.MnuPauseResumeSlideshow": "Pause/resume slideshow", + "FrmSettings.Tools._Integrated": "Integrated", + "FrmSettings._Contributors": "Contributors", + "_.MouseWheelAction._Zoom": "Zoom in / out", + "_._CommandPreview": "Kommando forhåndsvisning", + "FrmSettings._DarkTheme": "Dark", + "_._Hotkeys": "Hotkeys", + "_.Metadata._ExifDateTime": "EXIF: DateTime", + "FrmSettings.Toolbar._Errors._ButtonIdRequired": "Button ID required.", + "FrmSettings._MinEmbeddedThumbnailSize._Width": "Bredde", + "_._Executable": "Executable", + "_.ImageInterpolation._MultiSampleLinear": "Multi-sample linear", + "_._Separator": "Mellemrum", + "FrmQuickSetup._ProfessionalUser": "Professional user", + "FrmMain.MnuFlipVertical": "Vend Lodret", + "FrmSlideshow._ResumeSlideshow": "Slideshow is resumed.", + "FrmCropSettings.DefaultSelectionType._CustomArea": "Custom area…", + "FrmMain.MnuActualSize": "Akutelle størrelse", + "FrmCrop.BtnSaveAs": "Gem som…", + "FrmSettings._InstallNewLanguagePack": "Install new language packs…", + "FrmSlideshow.MnuZoomModes": "Zoom modes", + "FrmMain.MnuTools": "Værktøj", + "_.ImageInterpolation._Cubic": "Cubic", + "FrmUpdate._LatestVersion": "The latest version: {0}", + "FrmMain.MnuViewNext": "Vis næste billede", + "_.MouseWheelEvent._AltAndScroll": "Hold Alt and scroll", + "FrmToolNotFound._Title": "Tool not found", + "FrmCrop.BtnCrop._Tooltip": "Crop the image only", + "FrmSettings.EditAppDialog._AddApp": "Add an app for editing", + "FrmMain.MnuPanning": "Panorering", + "_._MoveUp": "Move up", + "FrmCropSettings.DefaultSelectionType._SelectAll": "Select all", + "_._Name": "Navn", + "FrmColorPickerSettings.ChkShowHslA": "Use HSL format with alpha value", + "FrmMain.MnuToggleImageAnimation": "Start / stop animating image", + "FrmSettings._DisableStartupBoost": "Disable Startup Boost", + "FrmMain.MnuCopyFile._Success": "Copied {0} file(s).", + "FrmMain.MnuSave._ConfirmDescription": "ImageGlass is not a professional photo editor, please be aware of losing the quality, metadata, layers,… when saving your image.", + "FrmToolNotFound.BtnSelectExecutable": "Select…", + "FrmUpdate._StatusOutdated": "A new update is available!", + "_.ImageOrderBy._Random": "Tilfældig", + "FrmResize.LblCurrentSize": "Current Size:", + "_._Apply": "Anvend", + "FrmAbout._Slogan": "En let, alsidig billedfremviser", + "FrmMain.MnuPanToTop": "Pan image to top", + "FrmSettings.Toolbar._AddNewButton": "Add a custom toolbar button", + "FrmCrop.LblSize": "Size:", + "FrmSettings._ImageInterpolation._ScaleDown": "When zoom < 100%", + "_._CreatingFileError": "Could not create temporary image file", + "FrmMain.MnuGoTo._Description": "Enter the image index to view, and then press ENTER", + "FrmSettings.Toolbar._EnableCenterToolbar": "Use center alignment for toolbar", + "FrmMain.MnuResizeTool": "Resize image", + "FrmSettings.Layout._Toolbar": "Værktøjslinje", + "FrmMain.MnuHelp": "Hjælp", + "_.ImageOrderBy._FileSize": "File size", + "FrmSettings._Theme._OpenThemeFolder": "Åbn temamappe", + "FrmMain.MnuNavigation": "Navigation", + "_._Save": "Gem", + "FrmQuickSetup._SettingProfileDescription": "To modify these settings, simply access app settings.", + "_._UserAction._MenuNotFound": "Cannot find menu '{0}' to invoke the action", + "FrmMain.MnuPanToLeftSide": "Pan image to left edge", + "FrmUpdate._CurrentVersion": "Current version: {0}", + "FrmCrop.BtnSettings._Tooltip": "Open Crop tool settings", + "_.ColorProfileOption._Custom": "Brugerdefineret…", + "FrmSettings._UseEmbeddedThumbnailOtherFormats": "Load only the embedded thumbnail for other formats", + "FrmMain.MnuGoToFirst": "Go to first image", + "FrmSettings._ExportLanguagePack": "Export language pack…", + "FrmSettings.Nav._Mouse": "Mouse", + "_.ImageOrderBy._DateCreated": "Date created", + "FrmSettings._EnableFullscreenSlideshow": "Start slideshow in Full Screen mode", + "FrmAbout._Homepage": "Homepage:", + "FrmSettings._GalleryCacheSizeInMb": "Maximum gallery cache size (in megabytes)", + "FrmMain.MnuCopyImageData._Success": "Copied the current image data.", + "FrmSettings._EnableLoopBackNavigation": "Loop back to the first image when reaching the end of the image list", + "_.MouseWheelEvent._Scroll": "Scroll", + "FrmCrop.BtnSave._Tooltip": "Gem billede", + "FrmMain.MnuSlideshow": "Slideshow", + "FrmMain.MnuShare": "Del…", + "FrmSettings._SlideshowNotification": "Slideshow notification", + "FrmMain.MnuViewChannels": "Vis kanaler", + "FrmSettings._Refresh": "Opdater", + "_._UserAction._MethodNotFound": "Cannot find method '{0}' to invoke the action", + "FrmMain.MnuCopyFile": "Copy file", + "_._CreatingFile": "Creating a temporary image file…", + "FrmMain.MnuToggleTopMost": "Vis altid vindue øverst", + "FrmMain.MnuLosslessCompression._Confirm": "Are you sure you want to proceed?", + "FrmMain.MnuImage": "Billede", + "FrmSettings._StartupBoost._Enabled": "Startup Boost is enabled", + "FrmQuickSetup._SetDefaultViewer": "Do you want to set ImageGlass as the default photo viewer?", + "FrmMain.MnuScaleToWidth": "Scalér til bredde", + "_._FileExtension": "Filtypenavn", + "FrmUpdate._PublishedDate": "Published date: {0}", + "_._DoNotShowThisMessageAgain": "Do not show this message again", + "_.ImageInterpolation._NearestNeighbor": "Nearest neighbor", + "FrmCrop.LblLocation": "Location:", + "_._Download": "Download", + "_.Metadata._ColorProfile": "Color profile", + "FrmSettings._CenterWindowFit": "Automatically center the window in Window Fit mode", + "FrmSettings._ImageLoadingOrder": "Indlæsningsfejl af billede", + "FrmSettings._GalleryColumns": "Number of thumbnail columns in vertical gallery layout", + "_._Quit": "Quit", + "_._Add": "Tilføj", + "FrmMain.MnuChangeBackgroundColor": "Change background color…", + "FrmMain.MnuToggleToolbar": "Værktøjslinje", + "FrmAbout._Contact": "Kontakt", + "FrmSettings.Toolbar._AddCustomButton": "Add a custom button…", + "FrmCrop.BtnQuickSelect._Tooltip": "Quick select…", + "FrmMain.MnuCutFile._Success": "Cut {0} file(s).", + "FrmSettings._ZoomSpeed": "Zoom speed", + "FrmMain.MnuToggleTopMost._Disable": "Disabled window always on top", + "FrmSettings._ShouldUseExplorerSortOrder": "Use Explorer sort order if possible", + "_.ImageInterpolation._Antisotropic": "Antisotropic", + "FrmMain._ReachedFirstImage": "Nået det første billede", + "_._UnhandledException": "Unhandled exception", + "FrmResize.LblNewSize": "New Size:", + "FrmMain._ClipboardImage": "Clipboard image", + "FrmMain.MnuExportFrames": "Export image frames…", + "FrmMain.MnuFile": "Fil", + "_._Close": "Luk", + "FrmMain.MnuMain": "Hovedmenu", + "_._ResetToDefault": "Nulstil til standard", + "FrmSettings.Nav._Gallery": "Gallery", + "FrmMain.MnuSetDefaultPhotoViewer._Success": "You have successfully set ImageGlass as default photo viewer.", + "FrmSettings._HideGalleryInFullscreen": "Hide gallery in Full Screen mode", + "FrmSettings._AvailableImageInfoTags": "Available tags:", + "FrmExportFrames._Exporting": "Exporting {0}/{1} frames \r\n{2}…", + "_._Argument": "Argument", + "FrmSettings._ImageEditQuality": "Billede kvalitet", + "_._ID": "ID", + "FrmSettings._UserConfigFile": "User settings file (igconfig.json)", + "FrmMain.MnuLoadingOrders": "Loading orders", + "FrmSettings._OpenSaveAsDialogInTheCurrentImageDir": "Open the Save As dialog in the current image directory", + "_.MouseWheelEvent._ShiftAndScroll": "Hold Shift and scroll", + "FrmSettings._UseSmoothZooming": "Use smooth zooming", + "FrmSettings._Theme": "Tema", + "FrmSettings._ImageBoosterCacheMaxDimension": "Maximum image dimension to be cached (in pixels)", + "FrmMain.MnuScaleToHeight": "Scalér til højde", + "_.Metadata._FileLastWriteTime": "Date modified", + "FrmSettings._Author": "Udvikler", + "FrmSettings._Others": "Andet", + "_.MouseWheelAction._PanVertically": "Pan up / down", + "FrmSettings._MouseWheelAction": "Mouse wheel action", + "FrmSettings.Nav._Tools": "Værktøj", + "FrmMain.MnuSetDesktopBackground._Error": "Could not set the viewing image as desktop background", + "FrmSettings.Toolbar._Errors._ButtonExecutableRequired": "Button executable required.", + "_.ImageOrderBy._DateAccessed": "Date accessed", + "FrmSettings._ThumbnailSize": "Thumbnail size (in pixels)", + "FrmSettings._FileFormats": "File formats", + "FrmMain.MnuReloadImageList": "Opdater billedliste", + "FrmSettings._UseWebview2ForSvg": "Use Webview2 for viewing SVG format", + "FrmCrop.BtnCopy": "Kopier", + "FrmSettings._CurrentMonitorProfile._Description": "ImageGlass does not auto-update the color when moving its window between monitors", + "FrmMain.PicMain._ErrorText": "Could not open this image", + "FrmSettings.Tools._AddNewTool": "Add an external tool", + "FrmMain.MnuRename": "Omdøb billede…", + "FrmMain.MnuViewLastFrame": "View last frame", + "_._Webview2._NotFound": "Please install WebView2 Runtime to access full features of ImageGlass.", + "FrmMain.MnuGetMoreTools": "Get more tools…", + "FrmSettings.Nav._Appearance": "Appearance", + "FrmSettings._SlideshowInterval": "Diasshow interval:", + "_.ImageInterpolation._HighQualityBicubic": "High quality bicubic", + "FrmColorPickerSettings.ChkShowHsvA": "Use HSV format with alpha value", + "FrmSettings.Tools._EditTool": "Edit external tool", + "_._Error": "Error", + "FrmSettings._ImageBoosterCacheMaxFileSizeInMb": "Maximum image file size to be cached (in megabytes)", + "_._UnhandledException._Description": "Unhandled exception has occurred. If you click Continue, the application will ignore this error and attempt to continue. If you click Quit, the application will close immediately.", + "_.Metadata._FileSize": "File size", + "FrmSettings.Toolbar._ButtonJson": "Button JSON", + "FrmQuickSetup._SetDefaultViewer._Description": "You can reset it in the app settings > File type associations tab.", + "FrmSettings.Nav._Edit": "Rediger", + "FrmMain.MnuToggleGallery": "Gallery panel", + "_._IgCommandExe._DefaultError._Description": "Make sure you pass the correct commands!\r\nThis executable file contains command-line functions for ImageGlass software.\r\n\r\nTo explore all command lines, please visit:\r\n{0}", + "FrmMain.MnuLosslessCompression._Compressing": "Performing lossless compression…", + "FrmSettings._ShouldGroupImagesByDirectory": "Gruppér billeder efter mappe", + "FrmMain.MnuPanToRightSide": "Pan image to right edge", + "_.Metadata._ExifRatingPercent": "Rating", + "FrmSettings._PanSpeed": "Panning speed", + "_._CheckForUpdate": "Søg efter opdateringer…", + "FrmSettings.Layout._ToolbarContext": "Contextual toolbar", + "_.ImageInfo._FrameCount": "{0} frame(s)", + "FrmMain.MnuLayout": "Layout", + "_._Website": "Hjemmeside", + "FrmMain.MnuPasteImage": "Paste image", + "FrmSettings._ShowGalleryScrollbars": "Show gallery scrollbars" + } +} \ No newline at end of file diff --git a/Setup/Assets/Language/Dutch.iglang.json b/Setup/Assets/Language/Dutch.iglang.json new file mode 100644 index 000000000..391a1600a --- /dev/null +++ b/Setup/Assets/Language/Dutch.iglang.json @@ -0,0 +1,504 @@ +{ + "_Metadata": { + "Code": "nl-NL", + "EnglishName": "Dutch", + "LocalName": "Nederlands", + "Author": "S.Paternotte, emup, BudsieBuds", + "MinVersion": "9.3" + }, + "Items": { + "FrmCrop.SelectionAspectRatio._Original": "Origineel", + "FrmMain.MnuShare._Error": "De dialoog Delen kon niet worden geopend.", + "_.Metadata._FileLastAccessTime": "Datum laatst geopend", + "FrmAbout._License": "Softwarelicentie", + "FrmSettings.Toolbar._Errors._ButtonIdDuplicated": "Een knop met ID '{0}' is al gedefinieerd. Kies een ander en uniek ID voor uw knop om conflicten te voorkomen.", + "FrmMain.MnuSave._Confirm": "Weet u zeker dat u deze afbeelding wilt overschrijven?", + "FrmSettings._OpenDefaultAppsSetting": "Windows standaard-apps instellingen openen", + "FrmMain.MnuCopyPath": "Pad naar afbeelding kopiëren", + "FrmCropSettings.DefaultSelectionType._SelectNone": "Niets geselecteerd", + "_.MouseWheelAction._PanHorizontally": "Pan links/rechts", + "FrmMain.MnuPrint": "Afdrukken…", + "FrmSettings.Toolbar._ToolbarButtons": "Werkbalkknoppen", + "FrmResize.LblResample": "Opnieuw bemonsteren:", + "_.ImageOrderBy._Extension": "Extensie", + "FrmSettings.Nav._Viewer": "Weergave", + "FrmSettings.EditAppDialog._EditApp": "Bewerk app", + "FrmCrop.BtnReset._Tooltip": "Selectie herstellen", + "FrmMain.MnuRename._Description": "Voer een nieuwe bestandsnaam in:", + "_._No": "Nee", + "FrmSlideshow.MnuToggleCountdown": "Toon aftellen van diavoorstellingen", + "FrmSettings._OpenStartupAppsSetting": "Instellingen Opstart-apps openen", + "FrmMain.MnuViewPreviousFrame": "Vorige frame", + "_.ImageOrderBy._DateModified": "Datum gewijzigd", + "FrmMain.MnuViewNextFrame": "Volgende frame", + "FrmMain.MnuUnload": "Afbeelding wissen", + "FrmSettings.Toolbar._HideToolbarInFullscreen": "Werkbalk in volledig scherm verbergen", + "_.ImageOrderType._Desc": "Aflopend", + "_._Update": "Bijwerken", + "FrmSettings._EnableImageAsyncLoading": "Asynchroon laden van afbeeldingen inschakelen", + "FrmSettings._DefaultPhotoViewer._Description": "Ondersteunde formaten van ImageGlass registreren bij Windows. Mogelijk moet u de instellingen van de standaardapps openen en ImageGlass handmatig in de lijst selecteren om deze in werking te laten treden.", + "_.MouseWheelAction._BrowseImages": "Volgende/vorige afbeelding", + "FrmSettings._EditApps": "Apps voor de bewerking van afbeeldingen", + "FrmColorPickerSettings.ChkShowCIELabA": "CIELAB-formaat met transparantie gebruiken", + "_._GetHelp": "Hulp vragen", + "FrmQuickSetup._SkipQuickSetup": "Dit overslaan en ImageGlass starten", + "FrmColorPickerSettings._Title": "Kleurenkiezer instellingen", + "_._Copy": "Kopiëren", + "FrmSettings._ImageBoosterCacheCount": "Aantal afbeeldingen in de cache opgeslagen door Image Booster (één richting)", + "FrmMain.MnuPanToBottom": "Pan afbeelding naar onderkant", + "FrmMain.MnuZoom": "Zoomen", + "FrmCropSettings.ChkCloseToolAfterSaving": "Bijsnijden sluiten na opslaan", + "FrmSettings._ShowWelcomeImage": "Welkomstafbeelding weergeven", + "FrmSettings._ColorProfile": "Kleurprofiel", + "FrmSettings._Theme._UninstallTheme": "Themapakket verwijderen", + "FrmMain._OpenWith": "Openen met {0}", + "FrmMain.MnuRemoveDefaultPhotoViewer": "Standaard fotoviewer terugzetten", + "_.AfterEditAppAction._Nothing": "Niets", + "FrmCrop.BtnSave": "Opslaan", + "FrmMain.MnuScaleToFit": "Passend", + "FrmToolNotFound.LblDownloadToolText": "U kunt meer hulpmiddelen voor ImageGlass downloaden van:", + "_._LearnMore": "Meer informatie…", + "FrmCrop.LblAspectRatio": "Aspect verhouding:", + "FrmExportFrames._FileNotExist": "Afbeeldingsbestand bestaat niet", + "FrmSettings._LightTheme": "Licht", + "FrmSettings.Nav._Slideshow": "Diavoorstelling", + "_._Continue": "Doorgaan", + "_._AddHotkey": "Sneltoets toevoegen…", + "FrmMain.MnuSetDesktopBackground": "Als bureaubladachtergrond gebruiken", + "FrmMain.MnuReload": "Afbeelding opnieuw laden", + "FrmSlideshow.MnuExitSlideshow": "Diavoorstelling afsluiten", + "FrmMain.MnuAutoZoom": "Automatisch zoomen", + "FrmSettings._ShowImagePreview": "Afbeeldingsvoorbeeld weergeven tijdens het laden", + "FrmCrop.BtnCopy._Tooltip": "Selectie kopiëren naar klembord", + "FrmSettings.Nav._Toolbar": "Werkbalk", + "FrmMain.MnuSave._Error": "Afbeelding is niet opgeslagen", + "FrmSettings._AfterEditingAction": "Na het openen van de bewerkingsapp", + "FrmSettings._ShouldUseColorProfileForAll": "Toepassen op afbeeldingen zonder ingesloten kleurprofiel", + "FrmCropSettings.DefaultSelectionType._UseTheLastSelection": "Laatste selectie gebruiken", + "FrmSettings._SlideshowInterval._From": "Van", + "FrmSettings._ImageInterpolation": "Beeldinterpolatie", + "FrmQuickSetup._StepInfo": "Stap {0}", + "FrmMain.MnuColorPicker": "Kleurenkiezer", + "FrmCrop.SelectionAspectRatio._FreeRatio": "Vrije ratio", + "FrmSettings._ResetSettings": "Instellingen herstellen", + "FrmSettings._Startup": "Opstarten", + "_.BackdropStyle._None": "Geen", + "FrmSettings._LoadDefaultZoomLevels": "Standaard zoomniveaus laden", + "FrmColorPicker.BtnSettings._Tooltip": "Instellingen voor kleurenkiezer openen…", + "FrmSettings._UseThemeForDarkMode": "Dit thema voor donkere modus gebruiken", + "FrmSettings._ShowDeleteConfirmation": "Toon bevestigingsvenster bij het verwijderen van bestanden", + "FrmSettings._ShowAppIcon": "App pictogram in de titelbalk weergeven", + "_._InvalidAction": "Ongeldige actie", + "FrmQuickSetup._SelectProfile": "Profiel selecteren", + "_.Metadata._FileCreationTime": "Datum aangemaakt", + "FrmSettings._SlideshowImagesToNotifySound": "Aantal afbeeldingen om een geluidseffect af te spelen", + "FrmSettings._BackgroundColor": "Achtergrondkleur", + "FrmSettings._RealTimeFileUpdate": "Realtime bestandsupdate", + "_.ColorProfileOption._CurrentMonitorProfile": "Huidig beeldschermprofiel", + "FrmSettings._EnableCutMultipleFiles": "Het tegelijkertijd knippen van meerdere bestanden inschakelen", + "FrmSettings._AutoUpdate": "Automatisch op updates controleren", + "FrmCropSettings.LblDefaultSelection": "Standaardselectie", + "FrmSettings._UseThemeForLightMode": "Dit thema voor lichte modus gebruiken", + "FrmSettings._ZoomLevels": "Zoomniveaus", + "FrmMain.MnuSetLockScreen._Success": "Afbeelding van het vergrendelingsscherm is bijgewerkt", + "FrmSettings._ShowGalleryFileName": "Miniatuur bestandsnaam weergeven", + "FrmSettings.Layout._Order": "Volgorde", + "FrmCropSettings.ChkAutoCenterSelection": "Selectie automatisch centreren", + "FrmSettings.Nav._FileTypeAssociations": "Bestandsassociaties", + "_._Back": "Terug", + "FrmMain.MnuSetDesktopBackground._Success": "Bureaubladachtergrond is bijgewerkt", + "FrmSettings._ShouldAutoOpenNewAddedImage": "Nieuw toegevoegde afbeelding automatisch openen", + "FrmCrop.SelectionAspectRatio._Custom": "Aangepast…", + "FrmMain.MnuCopyPath._Success": "Het huidige pad van de afbeelding is gekopieerd.", + "FrmSettings._StartupBoost._Error": "Kan de instelling Snel opstarten niet wijzigen", + "FrmToolNotFound.LblDescription": "ImageGlass kon het pad naar het uitvoerbare bestand '{0}' niet vinden. Om dit probleem op te lossen, dient u het pad naar de '{0}' bij te werken.", + "FrmMain.MnuClearClipboard": "Klembord wissen", + "FrmSettings._ColorManagement": "Kleurbeheer", + "FrmMain._ReachedLastLast": "Laatste afbeelding bereikt", + "FrmMain.MnuPanUp": "Pan afbeelding omhoog", + "FrmMain.MnuRemoveDefaultPhotoViewer._Success": "ImageGlass is niet langer de standaard fotoviewer.", + "FrmSettings._GetMoreLanguagePacks": "Meer taalpakketten downloaden…", + "FrmAbout._Privacy": "Privacybeleid", + "FrmSettings._EnableRecursiveLoading": "Afbeeldingen in submappen laden", + "_._UserAction._MethodArgumentNotSupported": "Het argumenttype van methode '{0}' wordt niet ondersteund", + "FrmSettings._FileExtensionIcons._Description": "Voor het aanpassen van de extensiepictogrammen, download een pictogrammenpakket, plaats alle .ICO bestanden in de map met extensiepictogrammen en klik op de knop '{0}'. Dit zal ImageGlass ook instellen als standaard fotoviewer.", + "_.ImageOrderType._Asc": "Oplopend", + "FrmExportFrames._Title": "Afbeeldingsframes exporteren", + "_._Install": "Installeren…", + "FrmMain.MnuFlipHorizontal": "Horizontaal spiegelen", + "FrmSettings._OpenExtensionIconFolder": "Map met extensiepictogrammen openen", + "FrmAbout._Collaborator": "Medewerker:", + "FrmQuickSetup._ConfirmCloseProcess": "Voordat de nieuwe instellingen worden toegepast, is het essentieel om alle ImageGlass-processen te sluiten. Klaar om verder te gaan?", + "FrmExportFrames._ExportDone": "{0} frames geëxporteerd naar\n{1}", + "FrmCrop.BtnSaveAs._Tooltip": "Opslaan als kopie…", + "FrmMain.MnuOpenFile": "Bestand openen…", + "FrmColorPickerSettings.ChkShowRgbA": "RGB-formaat met transparantie gebruiken", + "_.ImageInfo._ListCount": "{0} bestand(en)", + "FrmMain.MnuGoToLast": "Ga naar laatste afbeelding", + "FrmSettings._EditApps._AppName": "Toepassingsnaam", + "FrmSettings._SlideshowBackgroundColor": "Achtergrondkleur", + "FrmAbout._Email": "E-mail:", + "_.MouseWheelAction._DoNothing": "Niets doen", + "FrmMain.MnuSaveAs": "Opslaan als…", + "FrmMain._Loading": "Laden…", + "_._Browse": "Bladeren…", + "FrmMain.MnuSetDefaultPhotoViewer._Error": "ImageGlass kon niet worden ingesteld als standaard fotoviewer.", + "FrmSettings.Nav._Language": "Taal", + "FrmQuickSetup._SeeWhatNew": "Nieuw in deze versie…", + "FrmSettings._ImageInterpolation._ScaleUp": "Bij zoom > 100%", + "FrmSettings.Layout._ToolbarContextPosition": "Positie Contextuele werkbalk", + "FrmMain.MnuDeleteFromHardDisk": "Definitief verwijderen", + "FrmSettings._EmbeddedThumbnail": "Ingesloten miniatuur", + "FrmMain.MnuDeleteFromHardDisk._Description": "Weet u zeker dat u dit bestand definitief wilt verwijderen?", + "FrmMain.MnuScaleToFill": "Vullend", + "FrmCrop.BtnCrop": "Bijsnijden", + "_.AfterEditAppAction._Minimize": "Minimaliseren", + "FrmMain.MnuInvertColors": "Invert colors", + "FrmSettings._StartupBoost": "Snel opstarten", + "FrmMain.MnuViewFirstFrame": "Eerste frame", + "_.MouseWheelEvent._CtrlAndScroll": "Ctrl-scrollen", + "FrmSettings._HideMainWindowInSlideshow": "Hoofdvenster automatisch verbergen", + "_.Metadata._FrameCount": "Frames", + "FrmSettings._EnableCopyMultipleFiles": "Het tegelijkertijd kopiëren van meerdere bestanden inschakelen", + "FrmMain.MnuFrameless._EnableDescription": "Houd de Shift-toets ingedrukt om het venster te verplaatsen.", + "_.ImageOrderBy._ExifDateTaken": "EXIF: Datum opname", + "FrmAbout._Credits": "Credits", + "FrmSettings._AddNewFileExtension": "Nieuwe bestandsextensie toevoegen", + "FrmMain.MnuQuickSetup": "ImageGlass Snelle instellingen openen", + "FrmMain.MnuSave._Success": "Afbeelding opgeslagen", + "FrmMain.MnuPanLeft": "Pan afbeelding links", + "FrmUpdate._StatusChecking": "Controleren op update…", + "FrmSettings.Nav._Layout": "Indeling", + "FrmMain.MnuOpenWith": "Openen met…", + "FrmAbout._Thanks": "Speciale dank aan:", + "_._Warning": "Waarschuwing", + "FrmSettings.Nav._Keyboard": "Toetsenbord", + "FrmSlideshow._PauseSlideshow": "Diavoorstelling is gepauzeerd.", + "_._Add+": "Toevoegen…", + "_._Email": "E-mail", + "FrmMain.MnuPanDown": "Pan afbeelding omlaag", + "_._Cancel": "Annuleren", + "_._OK": "OK", + "FrmMain.MnuPanRight": "Pan afbeelding rechts", + "_.Position._Right": "Rechts", + "_._Icon": "Pictogram", + "FrmSettings._ShouldLoadHiddenImages": "Verborgen afbeeldingen laden", + "_._InvalidAction._Transformation": "ImageGlass ondersteunt voor deze afbeelding geen rotatie of spiegelen.", + "FrmSettings._MakeDefault": "Instellen als standaard", + "FrmMain.MnuCopyImageData._Copying": "De afbeeldingsgegevens worden gekopieerd. Dit kan even duren…", + "FrmSettings._UseEmbeddedThumbnailRawFormats": "Laad alleen de ingesloten miniatuur voor RAW-formaten", + "_.ImageInterpolation._Linear": "Lineair", + "FrmSettings._ImageInfoTags": "Informatielabels", + "FrmSettings._FileExtensionIcons": "Bestandsextensie-pictogrammen", + "FrmMain.MnuEdit._AppNotFound": "Bijbehorende bewerkingsapp is niet aangetroffen. U kunt een app toewijzen om dit formaat te bewerken in ImageGlass Instellingen > Bewerken.", + "_.ColorProfileOption._None": "Geen", + "FrmSettings._TotalSupportedFormats": "Aantal ondersteunde formaten: {0}", + "FrmSettings._Clipboard": "Klembord", + "_._UserAction._Win32ExeError": "Kan opdracht '{0}' niet uitvoeren. Zorg ervoor dat de naam correct is.", + "FrmCropSettings.DefaultSelectionType._SelectX": "{0} geselecteerd", + "_.AfterEditAppAction._Close": "Sluiten", + "FrmAbout._LogoDesigner": "Logo ontwerper:", + "_.ImageOrderBy._Name": "Naam (standaard)", + "FrmMain.MnuRemoveDefaultPhotoViewer._Error": "ImageGlass kon niet worden verwijderd als standaard fotoviewer.", + "FrmExportFrames._FolderPickerTitle": "Uitvoermap selecteren voor het exporteren van afbeeldingsframes", + "FrmAbout._Donate": "Doneren", + "FrmMain.MnuFrameNav": "Framenavigatie", + "FrmMain.MnuSetLockScreen": "Als achtergrond vergrendelingsscherm gebruiken", + "_._Delete": "Verwijderen", + "FrmMain.MnuViewPrevious": "Vorige afbeelding", + "_.Position._Top": "Bovenaan", + "FrmSettings.Toolbar._CurrentButtons": "Huidige knoppen:", + "FrmMain.MnuAbout": "Over", + "FrmSettings._RemoveDefault": "Verwijderen als standaard", + "_._Description": "Beschrijving", + "FrmMain.MnuPasteImage._Error": "Geen afbeeldingsgegevens aangetroffen in het klembord", + "FrmMain.MnuSettings": "Instellingen", + "FrmCropSettings._Title": "Instellingen bijsnijden", + "FrmSettings.Toolbar._ToolbarIconHeight": "Pictogramgrootte werkbalk", + "FrmSettings._SlideshowInterval._To": "Tot", + "FrmSettings.Layout._ToolbarPosition": "Positie werkbalk", + "FrmUpdate._StatusUpdated": "Dit is de meest recente versie!", + "FrmMain.MnuExit": "Afsluiten", + "_._Webview2._Outdated": "Jouw WebView2 Runtime wordt niet ondersteund. Werk deze bij naar versie {0} of hoger.", + "_._Yes": "Ja", + "FrmMain.MnuRotateLeft": "Linksom draaien", + "FrmSettings._EnableStartupBoost": "Snel opstarten inschakelen", + "_.ImageOrderBy._ExifRating": "EXIF: Waardering", + "FrmMain.MnuZoomIn": "Inzoomen", + "_.Metadata._ColorSpace": "Kleurruimte", + "FrmAbout._Version": "Versie:", + "FrmMain.MnuToggleTopMost._Enable": "Venster altijd op de voorgrond ingeschakeld", + "FrmSettings.Toolbar._AvailableButtons": "Beschikbare knoppen:", + "FrmMain.MnuSave._Saving": "Afbeelding opslaan…", + "FrmQuickSetup._StandardUser": "Standaardgebruiker", + "FrmMain.MnuSetLockScreen._Error": "De weergaveafbeelding is niet ingesteld als afbeelding voor het vergrendelscherm", + "FrmSettings.Nav._Image": "Afbeelding", + "FrmSettings._Theme._InstallTheme": "Themapaketten installeren", + "FrmSettings._EnableMultiInstances": "Meerdere instanties van het programma toestaan", + "FrmMain.MnuCropTool": "Afbeelding bijsnijden", + "_._IgCommandExe._DefaultError._Heading": "Ongeldige opdrachten", + "_._Refresh": "Vernieuwen", + "FrmMain.MnuLosslessCompression._Description": "Dit hulpmiddel gebruikt Magick.NET-bibliotheek voor verliesloze compressie, waarmee de bestandsgrootte wordt geoptimaliseerd. Overschrijft alleen als het gecomprimeerde bestand kleiner is dan het origineel.", + "_._MoveDown": "Omlaag veplaatsen", + "FrmSettings._GetExtensionIconPacks": "Extensiepictogrampakketten…", + "FrmSettings._InAppMessageDuration": "In-app berichtduur (milliseconden)", + "FrmMain.MnuFrameless": "Zonder rand", + "_._Reset": "Herstellen", + "FrmSettings._ConfigDir": "Configuratiemap", + "FrmQuickSetup._SettingsWillBeApplied": "De volgende instellingen worden toegepast:", + "FrmSettings._UnmanagedSettingReminder": "Deze instelling wordt niet beheerd door ImageGlass. Vergeet niet om dit uit te schakelen voordat u de app verwijdert of verplaatst, want ImageGlass doet dit niet automatisch.", + "FrmMain.MnuClipboard": "Klembord", + "FrmMain.MnuCustomZoom": "Aangepaste zoom…", + "FrmSettings._DisplayLanguage": "Weergavetaal", + "FrmMain.MnuPrint._Error": "Weergegeven afbeelding is niet afgedrukt", + "FrmSettings._ShouldPreserveModifiedDate": "Gewijzigde datum van de afbeelding behouden bij opslaan", + "FrmSettings._ShowSaveOverrideConfirmation": "Toon bevestigingsvenster bij het overschrijven van bestanden", + "FrmColorPickerSettings.ChkShowHexA": "HEX-formaat met transparantie gebruiken", + "FrmMain.MnuFullScreen": "Volledig scherm", + "FrmSettings._StartupDir": "Opstartlocatie", + "FrmSettings._ShowCheckerboardOnlyImageRegion": "Dambordpatroon alleen binnen de regio van de afbeelding tonen", + "FrmMain.MnuClearClipboard._Success": "Klembord gewist.", + "FrmQuickSetup._Text": "ImageGlass Snelle installatie", + "FrmMain.MnuLosslessCompression._Done": "Verliesloze compressie uitgevoerd.\r\nDe nieuwe bestandsgrootte is {0}, opgeslagen {1}.", + "FrmMain.MnuLosslessCompression": "Magick.NET Verliesloze compressie", + "FrmResize.RadResizeByPercentage": "Percentage", + "FrmSettings._StartupBoost._Disabled": "Snel opstarten is uitgeschakeld", + "FrmMain.MnuToggleCheckerboard": "Dambordpatroon achtergrond", + "FrmSettings._MinEmbeddedThumbnailSize._Height": "Hoogte", + "FrmSettings.Nav._General": "Algemeen", + "FrmSettings._ImageLoading": "Afbeelding laden", + "FrmSettings._ShowSlideshowCountdown": "Toon aftellen van diavoorstellingen", + "FrmMain.MnuSave": "Opslaan", + "FrmMain.MnuMoveToRecycleBin": "Naar de prullenbak verplaatsen", + "FrmMain.MnuRefresh": "Vernieuwen", + "FrmToolNotFound.LblHeading": "'{0}' is niet gevonden!", + "FrmMain.MnuReportIssue": "Een probleem melden…", + "FrmMain.MnuCopyImageData": "Afbeeldingsgegevens kopiëren", + "FrmMain.MnuCheckForUpdate._NewVersion": "Een nieuwe versie is beschikbaar!", + "_._Empty": "(leeg)", + "FrmSettings._Zooming": "Zoomen", + "FrmMain.MnuCutFile": "Bestand knippen", + "FrmHotkeyPicker.LblHotkey": "Druk op sneltoetsen", + "FrmSettings.Layout._Gallery": "Galerie", + "FrmMain.MnuNewWindow": "Nieuw venster openen", + "FrmMain.MnuMoveToRecycleBin._Description": "Wilt u dit bestand naar de Prullenbak verplaatsen?", + "FrmSettings._DefaultPhotoViewer": "Standaard fotoviewer", + "_.Metadata._ExifDateTimeOriginal": "EXIF: DateTimeOriginal", + "FrmMain.MnuRotateRight": "Rechtsom draaien", + "FrmSettings._MinEmbeddedThumbnailSize": "Minimale grootte van de ingesloten miniatuur die moet worden geladen", + "FrmMain.MnuSetDefaultPhotoViewer": "Standaard fotoviewer instellen", + "FrmMain.MnuImageProperties": "Eigenschappen van afbeelding", + "FrmSettings._EnableNavigationButtons": "Navigatiepijlen weergeven", + "_._Edit": "Bewerken", + "FrmSettings._ImageBooster": "Image Booster", + "FrmSettings.Tools._IntegratedWith": "Geïntegreerd met {0}", + "_._Next": "Volgende", + "FrmExportFrames._OpenOutputFolder": "Uitvoermap openen", + "FrmMain.MnuOpenLocation": "Afbeeldingslocatie openen", + "FrmMain.MnuLockZoom": "Zoomverhouding vergrendelen", + "FrmSettings._StartupBoost._Description": "Start tijdens het opstarten van Windows ImageGlass voor een paar seconden in de achtergrond ter ondersteuning van een snelle start.", + "FrmSettings._WindowBackdrop": "Achtergrondafbeelding", + "FrmSettings._EnableRealTimeFileUpdate": "Bestandswijzigingen in de bekeken map bijhouden en in realtime bijwerken", + "_._NotSupported": "Formaat niet ondersteund", + "FrmSettings._Theme._GetMoreThemes": "Meer themapaketten downloaden…", + "FrmMain.MnuNewWindow._Error": "Kan geen nieuw venster openen omdat slechts één instantie is toegestaan", + "FrmMain.MnuZoomOut": "Uitzoomen", + "FrmSettings.Toolbar._EditButton": "Werkbalkknop bewerken", + "FrmMain.MnuCustomZoom._Description": "Nieuwe zoomwaarde invoeren", + "FrmResize.RadResizeByPixels": "Pixels", + "FrmMain.MnuEdit": "Afbeelding bewerken {0}…", + "FrmSettings.Layout._GalleryPosition": "Positie Galerie", + "FrmMain.MnuWindowFit": "Passend in venster", + "FrmMain._OpenFileDialog": "Alle ondersteunde bestanden", + "FrmSettings._UseRandomIntervalForSlideshow": "Willekeurig interval gebruiken", + "_.Position._Left": "Links", + "FrmSettings._ShouldOpenLastSeenImage": "De laatst bekeken afbeelding openen", + "_.Position._Bottom": "Onderaan", + "FrmResize.ChkKeepRatio": "Verhoudingen behouden", + "FrmMain.MnuGoTo": "Ga naar…", + "FrmSlideshow.MnuPauseResumeSlideshow": "Diavoorstelling pauzeren/hervatten", + "FrmSettings.Tools._Integrated": "Geïntegreerd", + "FrmSettings._Contributors": "Bijdragen van", + "_.MouseWheelAction._Zoom": "Zoom in/uit", + "_._CommandPreview": "Opdrachtregel voorbeeld", + "FrmSettings._DarkTheme": "Donker", + "_._Hotkeys": "Sneltoetsen", + "_.Metadata._ExifDateTime": "EXIF: DateTime", + "FrmSettings.Toolbar._Errors._ButtonIdRequired": "Knop-ID vereist.", + "FrmSettings._MinEmbeddedThumbnailSize._Width": "Breedte", + "_._Executable": "Uitvoerbaar bestand", + "_.ImageInterpolation._MultiSampleLinear": "Multi-sample lineair", + "_._Separator": "Scheidingsteken", + "FrmQuickSetup._ProfessionalUser": "Professionele gebruiker", + "FrmMain.MnuFlipVertical": "Verticaal spiegelen", + "FrmSlideshow._ResumeSlideshow": "Diavoorstelling wordt hervat.", + "FrmCropSettings.DefaultSelectionType._CustomArea": "Aangepast gebied…", + "FrmMain.MnuActualSize": "Ware grootte", + "FrmCrop.BtnSaveAs": "Opslaan als…", + "FrmSettings._InstallNewLanguagePack": "Nieuwe taalpaketten installeren…", + "FrmSlideshow.MnuZoomModes": "Zoommodi", + "FrmMain.MnuTools": "Hulpmiddelen", + "_.ImageInterpolation._Cubic": "Cubisch", + "FrmUpdate._LatestVersion": "Meest recente versie: {0}", + "FrmMain.MnuViewNext": "Volgende afbeelding", + "_.MouseWheelEvent._AltAndScroll": "Alt-scrollen", + "FrmToolNotFound._Title": "Hulpmiddel niet gevonden", + "FrmCrop.BtnCrop._Tooltip": "Alleen de afbeelding bijsnijden", + "FrmSettings.EditAppDialog._AddApp": "Een app om te bewerken oevoegen", + "FrmMain.MnuPanning": "Pannen", + "_._MoveUp": "Omhoog verplaatsen", + "FrmCropSettings.DefaultSelectionType._SelectAll": "Alles geselecteerd", + "_._Name": "Naam", + "FrmColorPickerSettings.ChkShowHslA": "HSL-formaat met transparantie gebruiken", + "FrmMain.MnuToggleImageAnimation": "Start/stop animatie van afbeelding", + "FrmSettings._DisableStartupBoost": "Snel opstarten uitschakelen", + "FrmMain.MnuCopyFile._Success": "{0} bestand(en) gekopieerd.", + "FrmMain.MnuSave._ConfirmDescription": "ImageGlass is geen professionele fotobewerker, wees bewust van het mogelijke verlies van de kwaliteit, metadata, lagen,… bij het opslaan van uw afbeelding.", + "FrmToolNotFound.BtnSelectExecutable": "Selecteren…", + "FrmUpdate._StatusOutdated": "Een nieuwe update is beschikbaar!", + "_.ImageOrderBy._Random": "Willekeurig", + "FrmResize.LblCurrentSize": "Huidige grootte:", + "_._Apply": "Toepassen", + "FrmAbout._Slogan": "Een lichtgewicht, veelzijdige afbeeldingsviewer", + "FrmMain.MnuPanToTop": "Pan afbeelding naar bovenkant", + "FrmSettings.Toolbar._AddNewButton": "Aangepaste werkbalkknop toevoegen", + "FrmCrop.LblSize": "Grootte:", + "FrmSettings._ImageInterpolation._ScaleDown": "Bij zoom < 100%", + "_._CreatingFileError": "Tijdelijk afbeeldingsbestand niet aangemaakt", + "FrmMain.MnuGoTo._Description": "Voer de weer te geven afbeeldingsindex in en druk op ENTER", + "FrmSettings.Toolbar._EnableCenterToolbar": "Werkbalk centrerern", + "FrmMain.MnuResizeTool": "Afbeeldingsgrootte aanpassen", + "FrmSettings.Layout._Toolbar": "Werkbalk", + "FrmMain.MnuHelp": "Help", + "_.ImageOrderBy._FileSize": "Bestandsgrootte", + "FrmSettings._Theme._OpenThemeFolder": "Themamap openen", + "FrmMain.MnuNavigation": "Navigatie", + "_._Save": "Opslaan", + "FrmQuickSetup._SettingProfileDescription": "Om deze instellingen te wijzigen, open eenvoudig de app-instellingen.", + "_._UserAction._MenuNotFound": "Kan menu '{0}' niet vinden om de actie aan te roepen", + "FrmMain.MnuPanToLeftSide": "Pan afbeelding naar linkerrand", + "FrmUpdate._CurrentVersion": "Huidige versie: {0}", + "FrmCrop.BtnSettings._Tooltip": "Instellingen voor bijsnijden openen", + "_.ColorProfileOption._Custom": "Aangepast…", + "FrmSettings._UseEmbeddedThumbnailOtherFormats": "Laad alleen de ingesloten miniatuur voor andere formaten", + "FrmMain.MnuGoToFirst": "Ga naar eerste afbeelding", + "FrmSettings._ExportLanguagePack": "Taalpakket exporteren…", + "FrmSettings.Nav._Mouse": "Muis", + "_.ImageOrderBy._DateCreated": "Datum aangemaakt", + "FrmSettings._EnableFullscreenSlideshow": "Diavoorstelling in volledig scherm starten", + "FrmAbout._Homepage": "Website:", + "FrmSettings._GalleryCacheSizeInMb": "Maximale cachegrootte van de galerie (in megabytes)", + "FrmMain.MnuCopyImageData._Success": "Huidige afbeeldingsgegevens zijn gekopieerd.", + "FrmSettings._EnableLoopBackNavigation": "Herhaal de eerste afbeelding bij het bereiken van het einde van de afbeeldingslijst", + "_.MouseWheelEvent._Scroll": "Scrollen", + "FrmCrop.BtnSave._Tooltip": "Afbeelding opslaan", + "FrmMain.MnuSlideshow": "Diavoorstelling", + "FrmMain.MnuShare": "Delen…", + "FrmSettings._SlideshowNotification": "Notificatiegeluid", + "FrmMain.MnuViewChannels": "Kleurkanalen weergeven", + "FrmSettings._Refresh": "Vernieuwen", + "_._UserAction._MethodNotFound": "Kan methode '{0}' niet vinden om de actie aan te roepen", + "FrmMain.MnuCopyFile": "Bestand kopiëren", + "_._CreatingFile": "Tijdelijk afbeeldingsbestand aanmaken…", + "FrmMain.MnuToggleTopMost": "Venster altijd op voorgrond weergeven", + "FrmMain.MnuLosslessCompression._Confirm": "Weet u zeker dat u verder wilt gaan?", + "FrmMain.MnuImage": "Afbeelding", + "FrmSettings._StartupBoost._Enabled": "Snel opstarten is ingeschakeld", + "FrmQuickSetup._SetDefaultViewer": "Wilt u ImageGlass instellen als standaard fotoviewer?", + "FrmMain.MnuScaleToWidth": "Breedte passend", + "_._FileExtension": "Bestandsextensie", + "FrmUpdate._PublishedDate": "Publicatiedatum: {0}", + "_._DoNotShowThisMessageAgain": "Dit bericht niet meer weergeven", + "_.ImageInterpolation._NearestNeighbor": "Naaste buur", + "FrmCrop.LblLocation": "Positie:", + "_._Download": "Downloaden", + "_.Metadata._ColorProfile": "Kleurprofiel", + "FrmSettings._CenterWindowFit": "Het venster automatisch centreren in de passend in venstermodus", + "FrmSettings._ImageLoadingOrder": "Laadvolgorde afbeeldingen", + "FrmSettings._GalleryColumns": "Aantal kolommen met miniaturen in verticale galerie-indeling", + "_._Quit": "Afsluiten", + "_._Add": "Toevoegen", + "FrmMain.MnuChangeBackgroundColor": "Achtergrondkleur wijzigen…", + "FrmMain.MnuToggleToolbar": "Werkbalk", + "FrmAbout._Contact": "Contact", + "FrmSettings.Toolbar._AddCustomButton": "Aangepaste knop toevoegen…", + "FrmCrop.BtnQuickSelect._Tooltip": "Snel selecteren…", + "FrmMain.MnuCutFile._Success": "{0} bestand(en) geknipt.", + "FrmSettings._ZoomSpeed": "Zoomsnelheid", + "FrmMain.MnuToggleTopMost._Disable": "Venster altijd op de voorgrond uitgeschakeld", + "FrmSettings._ShouldUseExplorerSortOrder": "Sorteervolgorde van Windows Verkenner gebruiken (indien mogelijk)", + "_.ImageInterpolation._Antisotropic": "Anisotroop", + "FrmMain._ReachedFirstImage": "Eerste afbeelding bereikt", + "_._UnhandledException": "Onafgehandelde uitzondering", + "FrmResize.LblNewSize": "Nieuwe grootte:", + "FrmMain._ClipboardImage": "Klembordafbeelding", + "FrmMain.MnuExportFrames": "Afbeeldingsframes exporteren…", + "FrmMain.MnuFile": "Bestand", + "_._Close": "Sluiten", + "FrmMain.MnuMain": "Hoofdmenu", + "_._ResetToDefault": "Standaardinstellingen terugzetten", + "FrmSettings.Nav._Gallery": "Galerie", + "FrmMain.MnuSetDefaultPhotoViewer._Success": "ImageGlass is met succes ingesteld als standaard fotoviewer.", + "FrmSettings._HideGalleryInFullscreen": "Galerie verbergen bij volledig scherm", + "FrmSettings._AvailableImageInfoTags": "Beschikbare labels:", + "FrmExportFrames._Exporting": "{0}/{1} frames exporteren\n{2}…", + "_._Argument": "Argument", + "FrmSettings._ImageEditQuality": "Afbeeldingskwaliteit", + "_._ID": "ID", + "FrmSettings._UserConfigFile": "Bestand met gebruikersinstellingen (igconfig.json)", + "FrmMain.MnuLoadingOrders": "Volgorde", + "FrmSettings._OpenSaveAsDialogInTheCurrentImageDir": "Dialoogvenster Opslaan als… openen in de huidige afbeeldingenmap", + "_.MouseWheelEvent._ShiftAndScroll": "Shift-scrollen", + "FrmSettings._UseSmoothZooming": "Vloeiend zoomen", + "FrmSettings._Theme": "Thema", + "FrmSettings._ImageBoosterCacheMaxDimension": "Maximale afbeeldingsdimensie in de cache (in pixels)", + "FrmMain.MnuScaleToHeight": "Hoogte passend", + "_.Metadata._FileLastWriteTime": "Datum gewijzigd", + "FrmSettings._Author": "Auteur", + "FrmSettings._Others": "Overig", + "_.MouseWheelAction._PanVertically": "Pan omhoog/omlaag", + "FrmSettings._MouseWheelAction": "Muiswielactie", + "FrmSettings.Nav._Tools": "Hulpmiddelen", + "FrmMain.MnuSetDesktopBackground._Error": "De weergaveafbeelding is niet ingesteld als bureaubladachtergrond", + "FrmSettings.Toolbar._Errors._ButtonExecutableRequired": "Uitvoerbaar bestand bij knop vereist.", + "_.ImageOrderBy._DateAccessed": "Datum laatst geopend", + "FrmSettings._ThumbnailSize": "Miniatuur grootte (in pixels)", + "FrmSettings._FileFormats": "Bestandsindelingen", + "FrmMain.MnuReloadImageList": "Afbeeldinglijst opnieuw laden", + "FrmSettings._UseWebview2ForSvg": "WebView2 gebruiken voor weergave van SVG", + "FrmCrop.BtnCopy": "Kopiëren", + "FrmSettings._CurrentMonitorProfile._Description": "ImageGlass werkt de kleur niet automatisch bij wanneer het venster tussen monitoren wordt verplaatst", + "FrmMain.PicMain._ErrorText": "Deze afbeelding kon niet worden geopend", + "FrmSettings.Tools._AddNewTool": "Externe functie toevoegen", + "FrmMain.MnuRename": "Naam afbeelding wijzigen…", + "FrmMain.MnuViewLastFrame": "Laatste frame", + "_._Webview2._NotFound": "Installeer de nieuwste versie van WebView2 Runtime.", + "FrmMain.MnuGetMoreTools": "Meer hulpmiddelen…", + "FrmSettings.Nav._Appearance": "Uiterlijk", + "FrmSettings._SlideshowInterval": "Interval:", + "_.ImageInterpolation._HighQualityBicubic": "Hoge kwaliteit bicubisch", + "FrmColorPickerSettings.ChkShowHsvA": "HSV-formaat met transparantie gebruiken", + "FrmSettings.Tools._EditTool": "Externe functie bewerken", + "_._Error": "Fout", + "FrmSettings._ImageBoosterCacheMaxFileSizeInMb": "Maximale afbeeldingsbestandsgrootte in de cache (in megabytes)", + "_._UnhandledException._Description": "Onafgehandelde uitzondering is opgetreden. Als u op Doorgaan klikt, zal de applicatie deze fout negeren en proberen door te gaan. Als u op Afsluiten klikt, wordt de applicatie direct afgesloten.", + "_.Metadata._FileSize": "Bestandsgrootte", + "FrmSettings.Toolbar._ButtonJson": "JSON-knop", + "FrmQuickSetup._SetDefaultViewer._Description": "U kunt dit herstellen via Instellingen > Bestandsassociatie.", + "FrmSettings.Nav._Edit": "Bewerken", + "FrmMain.MnuToggleGallery": "Galeriepaneel", + "_._IgCommandExe._DefaultError._Description": "Zorg ervoor dat u de juiste opdrachten geeft!\r\nDit uitvoerbare bestand bevat opdrachtregelfuncties voor ImageGlass software.\r\n\r\nOm alle opdrachtregels te verkennen, ga naar:\n{0}", + "FrmMain.MnuLosslessCompression._Compressing": "Verliesloze compressie uitvoeren…", + "FrmSettings._ShouldGroupImagesByDirectory": "Afbeeldingen groeperen op map", + "FrmMain.MnuPanToRightSide": "Pan afbeelding naar rechterrand", + "_.Metadata._ExifRatingPercent": "Beoordeling", + "FrmSettings._PanSpeed": "Pan-snelheid", + "_._CheckForUpdate": "Controleren op update…", + "FrmSettings.Layout._ToolbarContext": "Contextuele werkbalk", + "_.ImageInfo._FrameCount": "{0} frame(s)", + "FrmMain.MnuLayout": "Indeling", + "_._Website": "Website", + "FrmMain.MnuPasteImage": "Afbeelding plakken", + "FrmSettings._ShowGalleryScrollbars": "Galerie-scrollbars tonen" + } +} \ No newline at end of file diff --git a/Setup/Assets/Language/Finnish.iglang.json b/Setup/Assets/Language/Finnish.iglang.json new file mode 100644 index 000000000..a28e85ed8 --- /dev/null +++ b/Setup/Assets/Language/Finnish.iglang.json @@ -0,0 +1,504 @@ +{ + "_Metadata": { + "Code": "fi-FI", + "EnglishName": "Finnish", + "LocalName": "Suomi", + "Author": "Bradon (linguistian)", + "MinVersion": "9.3" + }, + "Items": { + "FrmCrop.SelectionAspectRatio._Original": "Alkuperäinen", + "FrmMain.MnuShare._Error": "Jaa-valintaikkunaa ei voitu avata.", + "_.Metadata._FileLastAccessTime": "Käytetty", + "FrmAbout._License": "Ohjelmiston lisenssi", + "FrmSettings.Toolbar._Errors._ButtonIdDuplicated": "Painike ID:llä '{0}' on jo määritetty. Valitse painikkeellesi erilainen ja yksilöllinen tunnus, jotta vältät tunnusten väliset ristiriidat.", + "FrmMain.MnuSave._Confirm": "Haluatko varmasti korvata tämän kuvan?", + "FrmSettings._OpenDefaultAppsSetting": "Avaa oletussovellukset järjestelmäasetuksista", + "FrmMain.MnuCopyPath": "Kopioi kuvan polku", + "FrmCropSettings.DefaultSelectionType._SelectNone": "Tyhjennä valinnat", + "_.MouseWheelAction._PanHorizontally": "Panoroi vasemmalla / oikealla", + "FrmMain.MnuPrint": "Tulosta…", + "FrmSettings.Toolbar._ToolbarButtons": "Työkalupalkin painikkeet", + "FrmResize.LblResample": "Resample:", + "_.ImageOrderBy._Extension": "Tunniste", + "FrmSettings.Nav._Viewer": "Katselin", + "FrmSettings.EditAppDialog._EditApp": "Muokkaa sovellusta", + "FrmCrop.BtnReset._Tooltip": "Nollaa valinta", + "FrmMain.MnuRename._Description": "Anna uusi tiedostonimi:", + "_._No": "No", + "FrmSlideshow.MnuToggleCountdown": "Näytä diaesityksen määrä", + "FrmSettings._OpenStartupAppsSetting": "Avaa Käynnistysohjelmien asetus", + "FrmMain.MnuViewPreviousFrame": "Näytä edellinen kehys", + "_.ImageOrderBy._DateModified": "Muokattu", + "FrmMain.MnuViewNextFrame": "Näytä seuraava kehys", + "FrmMain.MnuUnload": "Poista kuva ladattuna", + "FrmSettings.Toolbar._HideToolbarInFullscreen": "Hide toolbar in Full Screen mode", + "_.ImageOrderType._Desc": "Laskeva", + "_._Update": "Update", + "FrmSettings._EnableImageAsyncLoading": "Enable image asynchronous loading", + "FrmSettings._DefaultPhotoViewer._Description": "Register the supported formats of ImageGlass with Windows. You might need to open the Default apps settings and manually select ImageGlass from the list for it to take effect.", + "_.MouseWheelAction._BrowseImages": "View next / previous Image", + "FrmSettings._EditApps": "Image editing apps", + "FrmColorPickerSettings.ChkShowCIELabA": "Use CIELAB format with alpha value", + "_._GetHelp": "Apua", + "FrmQuickSetup._SkipQuickSetup": "Skip this and launch ImageGlass", + "FrmColorPickerSettings._Title": "Color picker settings", + "_._Copy": "Kopioi", + "FrmSettings._ImageBoosterCacheCount": "Number of images cached by Image Booster (one direction)", + "FrmMain.MnuPanToBottom": "Pan image to bottom", + "FrmMain.MnuZoom": "Zoomaa", + "FrmCropSettings.ChkCloseToolAfterSaving": "Close Crop tool after saving", + "FrmSettings._ShowWelcomeImage": "Show welcome image", + "FrmSettings._ColorProfile": "Väriprofiili", + "FrmSettings._Theme._UninstallTheme": "Uninstall a theme pack", + "FrmMain._OpenWith": "Open with {0}", + "FrmMain.MnuRemoveDefaultPhotoViewer": "Remove default photo viewer", + "_.AfterEditAppAction._Nothing": "Ei mitään", + "FrmCrop.BtnSave": "Tallenna", + "FrmMain.MnuScaleToFit": "Skaalaa näyttöön sopivaksi", + "FrmToolNotFound.LblDownloadToolText": "You can download more tools for ImageGlass at:", + "_._LearnMore": "Lisätietoja…", + "FrmCrop.LblAspectRatio": "Aspect ratio:", + "FrmExportFrames._FileNotExist": "Image file does not exist", + "FrmSettings._LightTheme": "Vaalea", + "FrmSettings.Nav._Slideshow": "Diaesitys", + "_._Continue": "Jatka", + "_._AddHotkey": "Lisää pikanäppäin…", + "FrmMain.MnuSetDesktopBackground": "Aseta työpöydän taustakuvaksi", + "FrmMain.MnuReload": "Lataa kuva", + "FrmSlideshow.MnuExitSlideshow": "Poistu diaesityksestä", + "FrmMain.MnuAutoZoom": "Automaattinen zoomaus", + "FrmSettings._ShowImagePreview": "Display image preview while it's being loaded", + "FrmCrop.BtnCopy._Tooltip": "Copy the selection to clipboard", + "FrmSettings.Nav._Toolbar": "Työkalupalkki", + "FrmMain.MnuSave._Error": "Kuvaa ei voitu tallentaa", + "FrmSettings._AfterEditingAction": "Muokkausohjelman avaamisen jälkeen", + "FrmSettings._ShouldUseColorProfileForAll": "Hyväksy myös kuviin ilman upotettua väriprofiilia", + "FrmCropSettings.DefaultSelectionType._UseTheLastSelection": "Use the last selection", + "FrmSettings._SlideshowInterval._From": "From", + "FrmSettings._ImageInterpolation": "Image interpolation", + "FrmQuickSetup._StepInfo": "Step {0}", + "FrmMain.MnuColorPicker": "Värin valinta", + "FrmCrop.SelectionAspectRatio._FreeRatio": "Free ratio", + "FrmSettings._ResetSettings": "Reset settings", + "FrmSettings._Startup": "Startup", + "_.BackdropStyle._None": "Ei mitään", + "FrmSettings._LoadDefaultZoomLevels": "Load default zoom levels", + "FrmColorPicker.BtnSettings._Tooltip": "Open Color picker settings…", + "FrmSettings._UseThemeForDarkMode": "Use this theme for dark mode", + "FrmSettings._ShowDeleteConfirmation": "Show confirmation dialog when deleting file", + "FrmSettings._ShowAppIcon": "Show app icon on the title bar", + "_._InvalidAction": "Invalid action", + "FrmQuickSetup._SelectProfile": "Select a profile", + "_.Metadata._FileCreationTime": "Luotu", + "FrmSettings._SlideshowImagesToNotifySound": "Number of images to trigger a notification sound", + "FrmSettings._BackgroundColor": "Viewer background color", + "FrmSettings._RealTimeFileUpdate": "Real-time file update", + "_.ColorProfileOption._CurrentMonitorProfile": "Current monitor profile", + "FrmSettings._EnableCutMultipleFiles": "Enable the cutting of multiple files at once", + "FrmSettings._AutoUpdate": "Tarkista päivitykset automaattisesti", + "FrmCropSettings.LblDefaultSelection": "Default selection", + "FrmSettings._UseThemeForLightMode": "Use this theme for light mode", + "FrmSettings._ZoomLevels": "Zoomaustasot", + "FrmMain.MnuSetLockScreen._Success": "Lock screen image is updated", + "FrmSettings._ShowGalleryFileName": "Show thumbnail filename", + "FrmSettings.Layout._Order": "Order", + "FrmCropSettings.ChkAutoCenterSelection": "Auto-center selection", + "FrmSettings.Nav._FileTypeAssociations": "File type associations", + "_._Back": "Takaisin", + "FrmMain.MnuSetDesktopBackground._Success": "Desktop background is updated", + "FrmSettings._ShouldAutoOpenNewAddedImage": "Open the new added image automatically", + "FrmCrop.SelectionAspectRatio._Custom": "Muokattu…", + "FrmMain.MnuCopyPath._Success": "Copied the current image path.", + "FrmSettings._StartupBoost._Error": "Could not change Startup Boost setting", + "FrmToolNotFound.LblDescription": "ImageGlass was unable to locate the path to the '{0}' executable. To resolve this issue, please update the path to the '{0}' as necessary.", + "FrmMain.MnuClearClipboard": "Tyhjennä leikepöytä", + "FrmSettings._ColorManagement": "Värihallinta", + "FrmMain._ReachedLastLast": "Viimeinen kuva saavutettiin", + "FrmMain.MnuPanUp": "Pan image up", + "FrmMain.MnuRemoveDefaultPhotoViewer._Success": "ImageGlass is no longer the default photo viewer.", + "FrmSettings._GetMoreLanguagePacks": "Hanki lisää kielipaketteja…", + "FrmAbout._Privacy": "Privacy policy", + "FrmSettings._EnableRecursiveLoading": "Load images in subfolders", + "_._UserAction._MethodArgumentNotSupported": "The argument type of method '{0}' is not supported", + "FrmSettings._FileExtensionIcons._Description": "For customizing file extension icons, download an icon pack, place all .ICO files in the extension icon folder, and click the '{0}' button. This will also set ImageGlass as default photo viewer.", + "_.ImageOrderType._Asc": "Nouseva", + "FrmExportFrames._Title": "Export image frames", + "_._Install": "Asenna…", + "FrmMain.MnuFlipHorizontal": "Peilaa vaakatasossa", + "FrmSettings._OpenExtensionIconFolder": "Open extension icon folder", + "FrmAbout._Collaborator": "Collaborator:", + "FrmQuickSetup._ConfirmCloseProcess": "Before applying the new settings, it's essential to close all ImageGlass processes. Are you ready to proceed?", + "FrmExportFrames._ExportDone": "Exported {0} frames successfully to \r\n{1}", + "FrmCrop.BtnSaveAs._Tooltip": "Tallenna kopiona…", + "FrmMain.MnuOpenFile": "Avaa tiedosto…", + "FrmColorPickerSettings.ChkShowRgbA": "Use RGB format with alpha value", + "_.ImageInfo._ListCount": "{0} tiedosto(a)", + "FrmMain.MnuGoToLast": "Go to last image", + "FrmSettings._EditApps._AppName": "Sovelluksen nimi", + "FrmSettings._SlideshowBackgroundColor": "Slideshow background color", + "FrmAbout._Email": "Sähköposti:", + "_.MouseWheelAction._DoNothing": "Älä tee mitään", + "FrmMain.MnuSaveAs": "Tallenna nimellä…", + "FrmMain._Loading": "Ladataan…", + "_._Browse": "Selaa…", + "FrmMain.MnuSetDefaultPhotoViewer._Error": "Could not set ImageGlass as default photo viewer.", + "FrmSettings.Nav._Language": "Kieli", + "FrmQuickSetup._SeeWhatNew": "See what's new in this version…", + "FrmSettings._ImageInterpolation._ScaleUp": "When zoom > 100%", + "FrmSettings.Layout._ToolbarContextPosition": "Contextual toolbar position", + "FrmMain.MnuDeleteFromHardDisk": "Poista pysyvästi", + "FrmSettings._EmbeddedThumbnail": "Embedded thumbnail", + "FrmMain.MnuDeleteFromHardDisk._Description": "Haluatko varmasti poistaa tämän tiedoston pysyvästi?", + "FrmMain.MnuScaleToFill": "Täytä", + "FrmCrop.BtnCrop": "Rajaa", + "_.AfterEditAppAction._Minimize": "Pienennä", + "FrmMain.MnuInvertColors": "Invert colors", + "FrmSettings._StartupBoost": "Startup Boost", + "FrmMain.MnuViewFirstFrame": "View first frame", + "_.MouseWheelEvent._CtrlAndScroll": "Hold Ctrl and scroll", + "FrmSettings._HideMainWindowInSlideshow": "Automatically hide main window", + "_.Metadata._FrameCount": "Ruudut", + "FrmSettings._EnableCopyMultipleFiles": "Enable the copying of multiple files at once", + "FrmMain.MnuFrameless._EnableDescription": "Hold Shift key to move the window.", + "_.ImageOrderBy._ExifDateTaken": "EXIF: Date taken", + "FrmAbout._Credits": "Credits", + "FrmSettings._AddNewFileExtension": "Add new file extension", + "FrmMain.MnuQuickSetup": "Open ImageGlass Quick Setup", + "FrmMain.MnuSave._Success": "Kuva tallennettu", + "FrmMain.MnuPanLeft": "Pan image left", + "FrmUpdate._StatusChecking": "Etsitään päivityksiä…", + "FrmSettings.Nav._Layout": "Näytä", + "FrmMain.MnuOpenWith": "Avaa…", + "FrmAbout._Thanks": "Special thanks to", + "_._Warning": "Varoitus", + "FrmSettings.Nav._Keyboard": "Näppäimistö", + "FrmSlideshow._PauseSlideshow": "Diaesitys tauotettu.", + "_._Add+": "Lisää…", + "_._Email": "Sähköposti", + "FrmMain.MnuPanDown": "Pan image down", + "_._Cancel": "Peruuta", + "_._OK": "OK", + "FrmMain.MnuPanRight": "Pan image right", + "_.Position._Right": "Oikea", + "_._Icon": "Kuvake", + "FrmSettings._ShouldLoadHiddenImages": "Load hidden images", + "_._InvalidAction._Transformation": "ImageGlass does not support rotation, flipping for this image.", + "FrmSettings._MakeDefault": "Make default", + "FrmMain.MnuCopyImageData._Copying": "Copying the image data. It's going to take a while…", + "FrmSettings._UseEmbeddedThumbnailRawFormats": "Load only the embedded thumbnail for RAW formats", + "_.ImageInterpolation._Linear": "Linear", + "FrmSettings._ImageInfoTags": "Image information tags", + "FrmSettings._FileExtensionIcons": "File extension icons", + "FrmMain.MnuEdit._AppNotFound": "Could not find the associated app for editing. You can assign an app for editing this format in ImageGlass Settings > Edit.", + "_.ColorProfileOption._None": "Ei mitään", + "FrmSettings._TotalSupportedFormats": "Total supported formats: {0}", + "FrmSettings._Clipboard": "Leikepöytä", + "_._UserAction._Win32ExeError": "Cannot execute command '{0}'. Make sure the name is correct.", + "FrmCropSettings.DefaultSelectionType._SelectX": "Select {0}", + "_.AfterEditAppAction._Close": "Sulje", + "FrmAbout._LogoDesigner": "Logo designer:", + "_.ImageOrderBy._Name": "Nimi (Oletus)", + "FrmMain.MnuRemoveDefaultPhotoViewer._Error": "Could not remove ImageGlass as the default photo viewer.", + "FrmExportFrames._FolderPickerTitle": "Select output folder for exporting image frames", + "FrmAbout._Donate": "Donate", + "FrmMain.MnuFrameNav": "Frame navigation", + "FrmMain.MnuSetLockScreen": "Aseta lukitusnäytön kuvaksi", + "_._Delete": "Poista", + "FrmMain.MnuViewPrevious": "Katso edellinen kuva", + "_.Position._Top": "Ylhäällä", + "FrmSettings.Toolbar._CurrentButtons": "Current buttons:", + "FrmMain.MnuAbout": "Tietoja", + "FrmSettings._RemoveDefault": "Remove default", + "_._Description": "Kuvaus", + "FrmMain.MnuPasteImage._Error": "Leikepöydältä ei löytynyt kuvaa", + "FrmMain.MnuSettings": "Asetukset", + "FrmCropSettings._Title": "Crop settings", + "FrmSettings.Toolbar._ToolbarIconHeight": "Työkalupalkin kuvakkeen koko", + "FrmSettings._SlideshowInterval._To": "To", + "FrmSettings.Layout._ToolbarPosition": "Työkalupalkin sijainti", + "FrmUpdate._StatusUpdated": "Käytössäsi on uusin versio!", + "FrmMain.MnuExit": "Poistu", + "_._Webview2._Outdated": "Your WebView2 Runtime is not supported. Please update to version {0} or later.", + "_._Yes": "Kyllä", + "FrmMain.MnuRotateLeft": "Kierrä vasemmalle", + "FrmSettings._EnableStartupBoost": "Enable Startup Boost", + "_.ImageOrderBy._ExifRating": "EXIF: Rating", + "FrmMain.MnuZoomIn": "Lähennä", + "_.Metadata._ColorSpace": "Väriavaruus", + "FrmAbout._Version": "Versio:", + "FrmMain.MnuToggleTopMost._Enable": "Enabled window always on top", + "FrmSettings.Toolbar._AvailableButtons": "Available buttons:", + "FrmMain.MnuSave._Saving": "Tallennetaan kuvaa…", + "FrmQuickSetup._StandardUser": "Standard user", + "FrmMain.MnuSetLockScreen._Error": "Could not set the viewing image as lock screen image", + "FrmSettings.Nav._Image": "Kuva", + "FrmSettings._Theme._InstallTheme": "Install theme packs", + "FrmSettings._EnableMultiInstances": "Salli monia käynnistyksiä sovelluksesta samanaikaisesti", + "FrmMain.MnuCropTool": "Rajaa kuvaa", + "_._IgCommandExe._DefaultError._Heading": "Invalid commands", + "_._Refresh": "Päivitä", + "FrmMain.MnuLosslessCompression._Description": "This tool uses Magick.NET library for lossless compression, optimizing file size. Overwrites only if the compressed file is smaller than the original.", + "_._MoveDown": "Siirrä alas", + "FrmSettings._GetExtensionIconPacks": "Get extension icon packs…", + "FrmSettings._InAppMessageDuration": "In-app message duration (milliseconds)", + "FrmMain.MnuFrameless": "Kehyksetön", + "_._Reset": "Palauta", + "FrmSettings._ConfigDir": "Configuration location", + "FrmQuickSetup._SettingsWillBeApplied": "Settings will be applied:", + "FrmSettings._UnmanagedSettingReminder": "This setting is not managed by ImageGlass. Don't forget to disable it before you remove or relocate the app because ImageGlass does not handle this automatically.", + "FrmMain.MnuClipboard": "Leikepöytä", + "FrmMain.MnuCustomZoom": "Zoomaa arvolla…", + "FrmSettings._DisplayLanguage": "Display language", + "FrmMain.MnuPrint._Error": "Could not print the viewing image", + "FrmSettings._ShouldPreserveModifiedDate": "Suojaa kuvan muokkauspäivämäärä tallennettaessa", + "FrmSettings._ShowSaveOverrideConfirmation": "Show confirmation dialog when overriding file", + "FrmColorPickerSettings.ChkShowHexA": "Use HEX format with alpha value", + "FrmMain.MnuFullScreen": "Koko näyttö", + "FrmSettings._StartupDir": "Startup location", + "FrmSettings._ShowCheckerboardOnlyImageRegion": "Show checkerboard only within the image region", + "FrmMain.MnuClearClipboard._Success": "Leikepöytä tyhjennetty.", + "FrmQuickSetup._Text": "ImageGlass Quick Setup", + "FrmMain.MnuLosslessCompression._Done": "Done lossless compression.\r\nThe new file size is {0}, saved {1}.", + "FrmMain.MnuLosslessCompression": "Magick.NET Lossless Compression", + "FrmResize.RadResizeByPercentage": "Percentage", + "FrmSettings._StartupBoost._Disabled": "Startup Boost is disabled", + "FrmMain.MnuToggleCheckerboard": "Ruutukuvioitu tausta", + "FrmSettings._MinEmbeddedThumbnailSize._Height": "Korkeus", + "FrmSettings.Nav._General": "Yleiset", + "FrmSettings._ImageLoading": "Kuvia ladattaessa", + "FrmSettings._ShowSlideshowCountdown": "Näytä diaesityksen määrä", + "FrmMain.MnuSave": "Tallenna", + "FrmMain.MnuMoveToRecycleBin": "Siirrä roskakoriin", + "FrmMain.MnuRefresh": "Päivitä", + "FrmToolNotFound.LblHeading": "'{0}' is not found!", + "FrmMain.MnuReportIssue": "Ilmoita ongelmasta…", + "FrmMain.MnuCopyImageData": "Kopioi kuvan data", + "FrmMain.MnuCheckForUpdate._NewVersion": "Uusi versio saatavilla!", + "_._Empty": "(empty)", + "FrmSettings._Zooming": "Zoomataan", + "FrmMain.MnuCutFile": "Leikkaa tiedosto", + "FrmHotkeyPicker.LblHotkey": "Press hotkeys", + "FrmSettings.Layout._Gallery": "Gallery", + "FrmMain.MnuNewWindow": "Avaa uusi ikkuna", + "FrmMain.MnuMoveToRecycleBin._Description": "Haluatko siirtää tämän tiedoston roskakoriin?", + "FrmSettings._DefaultPhotoViewer": "Default photo viewer", + "_.Metadata._ExifDateTimeOriginal": "EXIF: DateTimeOriginal", + "FrmMain.MnuRotateRight": "Kierrä oikealle", + "FrmSettings._MinEmbeddedThumbnailSize": "Minimum size of the embedded thumbnail to be loaded", + "FrmMain.MnuSetDefaultPhotoViewer": "Set default photo viewer", + "FrmMain.MnuImageProperties": "Kuvan ominaisuudet", + "FrmSettings._EnableNavigationButtons": "Show navigation arrow buttons", + "_._Edit": "Muokkaa", + "FrmSettings._ImageBooster": "Image Booster", + "FrmSettings.Tools._IntegratedWith": "Integrated with {0}", + "_._Next": "Seuraava", + "FrmExportFrames._OpenOutputFolder": "Open output folder", + "FrmMain.MnuOpenLocation": "Avaa kuvan sijainti", + "FrmMain.MnuLockZoom": "Lukitse zoomauksen kuvasuhde", + "FrmSettings._StartupBoost._Description": "Preload and run ImageGlass in the background for a few seconds during Windows startup to accelerate the first launch.", + "FrmSettings._WindowBackdrop": "Window backdrop", + "FrmSettings._EnableRealTimeFileUpdate": "Monitor file changes in the viewing folder and update in realtime", + "_._NotSupported": "Tiedostomuotoa ei tueta", + "FrmSettings._Theme._GetMoreThemes": "Get more theme packs…", + "FrmMain.MnuNewWindow._Error": "Cannot open new window because only one instance is allowed", + "FrmMain.MnuZoomOut": "Loitonna", + "FrmSettings.Toolbar._EditButton": "Edit toolbar button", + "FrmMain.MnuCustomZoom._Description": "Syötä uusi zoomausarvo", + "FrmResize.RadResizeByPixels": "Pixels", + "FrmMain.MnuEdit": "Muokkaa kuvaa {0}…", + "FrmSettings.Layout._GalleryPosition": "Gallery position", + "FrmMain.MnuWindowFit": "Sovita ikkunaan", + "FrmMain._OpenFileDialog": "Kaikki tuetut tiedostot", + "FrmSettings._UseRandomIntervalForSlideshow": "Käytä satunnaista aikaväliä", + "_.Position._Left": "Vasen", + "FrmSettings._ShouldOpenLastSeenImage": "Open the last seen image", + "_.Position._Bottom": "Alhaalla", + "FrmResize.ChkKeepRatio": "Keep ratio propotional", + "FrmMain.MnuGoTo": "Siirry…", + "FrmSlideshow.MnuPauseResumeSlideshow": "Pause/resume slideshow", + "FrmSettings.Tools._Integrated": "Integrated", + "FrmSettings._Contributors": "Contributors", + "_.MouseWheelAction._Zoom": "Zoom in / out", + "_._CommandPreview": "Komennon esikatselu", + "FrmSettings._DarkTheme": "Tumma", + "_._Hotkeys": "Pikanäppäimet", + "_.Metadata._ExifDateTime": "EXIF: DateTime", + "FrmSettings.Toolbar._Errors._ButtonIdRequired": "Button ID required.", + "FrmSettings._MinEmbeddedThumbnailSize._Width": "Leveys", + "_._Executable": "Executable", + "_.ImageInterpolation._MultiSampleLinear": "Multi-sample linear", + "_._Separator": "Erotin", + "FrmQuickSetup._ProfessionalUser": "Professional user", + "FrmMain.MnuFlipVertical": "Käännä pystysuunnassa", + "FrmSlideshow._ResumeSlideshow": "Diaesitys jatkuu.", + "FrmCropSettings.DefaultSelectionType._CustomArea": "Custom area…", + "FrmMain.MnuActualSize": "Alkuperäinen koko", + "FrmCrop.BtnSaveAs": "Tallenna nimellä…", + "FrmSettings._InstallNewLanguagePack": "Install new language packs…", + "FrmSlideshow.MnuZoomModes": "Zoom modes", + "FrmMain.MnuTools": "Työkalut", + "_.ImageInterpolation._Cubic": "Cubic", + "FrmUpdate._LatestVersion": "The latest version: {0}", + "FrmMain.MnuViewNext": "Katso seuraava kuva", + "_.MouseWheelEvent._AltAndScroll": "Hold Alt and scroll", + "FrmToolNotFound._Title": "Tool not found", + "FrmCrop.BtnCrop._Tooltip": "Crop the image only", + "FrmSettings.EditAppDialog._AddApp": "Add an app for editing", + "FrmMain.MnuPanning": "Panning", + "_._MoveUp": "Siirrä ylös", + "FrmCropSettings.DefaultSelectionType._SelectAll": "Select all", + "_._Name": "Nimi", + "FrmColorPickerSettings.ChkShowHslA": "Use HSL format with alpha value", + "FrmMain.MnuToggleImageAnimation": "Start / stop animating image", + "FrmSettings._DisableStartupBoost": "Disable Startup Boost", + "FrmMain.MnuCopyFile._Success": "Kopioitu {0} tiedosto(a).", + "FrmMain.MnuSave._ConfirmDescription": "ImageGlass is not a professional photo editor, please be aware of losing the quality, metadata, layers,… when saving your image.", + "FrmToolNotFound.BtnSelectExecutable": "Select…", + "FrmUpdate._StatusOutdated": "Uusi päivitys saatavilla!", + "_.ImageOrderBy._Random": "Satunnainen", + "FrmResize.LblCurrentSize": "Current Size:", + "_._Apply": "Käytä", + "FrmAbout._Slogan": "Kevyt ja monipuolinen kuvankatselusovellus", + "FrmMain.MnuPanToTop": "Pan image to top", + "FrmSettings.Toolbar._AddNewButton": "Add a custom toolbar button", + "FrmCrop.LblSize": "Koko:", + "FrmSettings._ImageInterpolation._ScaleDown": "When zoom < 100%", + "_._CreatingFileError": "Could not create temporary image file", + "FrmMain.MnuGoTo._Description": "Enter the image index to view, and then press ENTER", + "FrmSettings.Toolbar._EnableCenterToolbar": "Use center alignment for toolbar", + "FrmMain.MnuResizeTool": "Resize image", + "FrmSettings.Layout._Toolbar": "Työkalupalkki", + "FrmMain.MnuHelp": "Apua", + "_.ImageOrderBy._FileSize": "Tiedostokoko", + "FrmSettings._Theme._OpenThemeFolder": "Avaa teemakansio", + "FrmMain.MnuNavigation": "Navigointi", + "_._Save": "Tallenna", + "FrmQuickSetup._SettingProfileDescription": "To modify these settings, simply access app settings.", + "_._UserAction._MenuNotFound": "Cannot find menu '{0}' to invoke the action", + "FrmMain.MnuPanToLeftSide": "Pan image to left edge", + "FrmUpdate._CurrentVersion": "Current version: {0}", + "FrmCrop.BtnSettings._Tooltip": "Open Crop tool settings", + "_.ColorProfileOption._Custom": "Muokattu…", + "FrmSettings._UseEmbeddedThumbnailOtherFormats": "Load only the embedded thumbnail for other formats", + "FrmMain.MnuGoToFirst": "Go to first image", + "FrmSettings._ExportLanguagePack": "Export language pack…", + "FrmSettings.Nav._Mouse": "Mouse", + "_.ImageOrderBy._DateCreated": "Luotu", + "FrmSettings._EnableFullscreenSlideshow": "Start slideshow in Full Screen mode", + "FrmAbout._Homepage": "Homepage:", + "FrmSettings._GalleryCacheSizeInMb": "Maximum gallery cache size (in megabytes)", + "FrmMain.MnuCopyImageData._Success": "Copied the current image data.", + "FrmSettings._EnableLoopBackNavigation": "Loop back to the first image when reaching the end of the image list", + "_.MouseWheelEvent._Scroll": "Scroll", + "FrmCrop.BtnSave._Tooltip": "Tallenna kuva", + "FrmMain.MnuSlideshow": "Diaesitys", + "FrmMain.MnuShare": "Jaa…", + "FrmSettings._SlideshowNotification": "Slideshow notification", + "FrmMain.MnuViewChannels": "Näytä kanavat", + "FrmSettings._Refresh": "Päivitä", + "_._UserAction._MethodNotFound": "Cannot find method '{0}' to invoke the action", + "FrmMain.MnuCopyFile": "Kopioi tiedosto", + "_._CreatingFile": "Creating a temporary image file…", + "FrmMain.MnuToggleTopMost": "Pidä ikkuna aina päällimmäisenä", + "FrmMain.MnuLosslessCompression._Confirm": "Are you sure you want to proceed?", + "FrmMain.MnuImage": "Kuva", + "FrmSettings._StartupBoost._Enabled": "Startup Boost is enabled", + "FrmQuickSetup._SetDefaultViewer": "Do you want to set ImageGlass as the default photo viewer?", + "FrmMain.MnuScaleToWidth": "Skaalaa sopivaksi leveyssuunnassa", + "_._FileExtension": "Tiedostotunnisteet", + "FrmUpdate._PublishedDate": "Published date: {0}", + "_._DoNotShowThisMessageAgain": "Älä näytä tätä ilmoitusta uudelleen", + "_.ImageInterpolation._NearestNeighbor": "Nearest neighbor", + "FrmCrop.LblLocation": "Sijainti:", + "_._Download": "Lataa", + "_.Metadata._ColorProfile": "Väriprofiili", + "FrmSettings._CenterWindowFit": "Automatically center the window in Window Fit mode", + "FrmSettings._ImageLoadingOrder": "Kuvien latausjärjestys", + "FrmSettings._GalleryColumns": "Number of thumbnail columns in vertical gallery layout", + "_._Quit": "Lopeta", + "_._Add": "Lisää", + "FrmMain.MnuChangeBackgroundColor": "Change background color…", + "FrmMain.MnuToggleToolbar": "Työkalupalkki", + "FrmAbout._Contact": "Ota yhteyttä tekijään", + "FrmSettings.Toolbar._AddCustomButton": "Add a custom button…", + "FrmCrop.BtnQuickSelect._Tooltip": "Pikavalinta…", + "FrmMain.MnuCutFile._Success": "Leikkaa {0} tiedosto(a).", + "FrmSettings._ZoomSpeed": "Zoom speed", + "FrmMain.MnuToggleTopMost._Disable": "Disabled window always on top", + "FrmSettings._ShouldUseExplorerSortOrder": "Use Explorer sort order if possible", + "_.ImageInterpolation._Antisotropic": "Antisotropic", + "FrmMain._ReachedFirstImage": "Ensimmäinen kuva saavutettiin", + "_._UnhandledException": "Unhandled exception", + "FrmResize.LblNewSize": "New Size:", + "FrmMain._ClipboardImage": "Clipboard image", + "FrmMain.MnuExportFrames": "Export image frames…", + "FrmMain.MnuFile": "Tiedosto", + "_._Close": "Sulje", + "FrmMain.MnuMain": "Päävalikko", + "_._ResetToDefault": "Palauta oletukseksi", + "FrmSettings.Nav._Gallery": "Gallery", + "FrmMain.MnuSetDefaultPhotoViewer._Success": "You have successfully set ImageGlass as default photo viewer.", + "FrmSettings._HideGalleryInFullscreen": "Hide gallery in Full Screen mode", + "FrmSettings._AvailableImageInfoTags": "Available tags:", + "FrmExportFrames._Exporting": "Exporting {0}/{1} frames \r\n{2}…", + "_._Argument": "Argument", + "FrmSettings._ImageEditQuality": "Kuvanlaatu", + "_._ID": "ID", + "FrmSettings._UserConfigFile": "User settings file (igconfig.json)", + "FrmMain.MnuLoadingOrders": "Loading orders", + "FrmSettings._OpenSaveAsDialogInTheCurrentImageDir": "Open the Save As dialog in the current image directory", + "_.MouseWheelEvent._ShiftAndScroll": "Hold Shift and scroll", + "FrmSettings._UseSmoothZooming": "Use smooth zooming", + "FrmSettings._Theme": "Teema", + "FrmSettings._ImageBoosterCacheMaxDimension": "Maximum image dimension to be cached (in pixels)", + "FrmMain.MnuScaleToHeight": "Skaalaa sopivaksi korkeussuunnassa", + "_.Metadata._FileLastWriteTime": "Muokattu", + "FrmSettings._Author": "Tekijä", + "FrmSettings._Others": "Muut", + "_.MouseWheelAction._PanVertically": "Pan up / down", + "FrmSettings._MouseWheelAction": "Mouse wheel action", + "FrmSettings.Nav._Tools": "Työkalut", + "FrmMain.MnuSetDesktopBackground._Error": "Could not set the viewing image as desktop background", + "FrmSettings.Toolbar._Errors._ButtonExecutableRequired": "Button executable required.", + "_.ImageOrderBy._DateAccessed": "Käytetty", + "FrmSettings._ThumbnailSize": "Thumbnail size (in pixels)", + "FrmSettings._FileFormats": "File formats", + "FrmMain.MnuReloadImageList": "Lataa kuvalista", + "FrmSettings._UseWebview2ForSvg": "Use Webview2 for viewing SVG format", + "FrmCrop.BtnCopy": "Kopioi", + "FrmSettings._CurrentMonitorProfile._Description": "ImageGlass does not auto-update the color when moving its window between monitors", + "FrmMain.PicMain._ErrorText": "Kuvaa ei voitu avata", + "FrmSettings.Tools._AddNewTool": "Add an external tool", + "FrmMain.MnuRename": "Uudelleennimeä kuva…", + "FrmMain.MnuViewLastFrame": "View last frame", + "_._Webview2._NotFound": "Please install WebView2 Runtime to access full features of ImageGlass.", + "FrmMain.MnuGetMoreTools": "Hanki työkaluja…", + "FrmSettings.Nav._Appearance": "Appearance", + "FrmSettings._SlideshowInterval": "Vaihtoviive:", + "_.ImageInterpolation._HighQualityBicubic": "High quality bicubic", + "FrmColorPickerSettings.ChkShowHsvA": "Use HSV format with alpha value", + "FrmSettings.Tools._EditTool": "Edit external tool", + "_._Error": "Virhe", + "FrmSettings._ImageBoosterCacheMaxFileSizeInMb": "Maximum image file size to be cached (in megabytes)", + "_._UnhandledException._Description": "Unhandled exception has occurred. If you click Continue, the application will ignore this error and attempt to continue. If you click Quit, the application will close immediately.", + "_.Metadata._FileSize": "Tiedostokoko", + "FrmSettings.Toolbar._ButtonJson": "Button JSON", + "FrmQuickSetup._SetDefaultViewer._Description": "You can reset it in the app settings > File type associations tab.", + "FrmSettings.Nav._Edit": "Muokkaa", + "FrmMain.MnuToggleGallery": "Gallery panel", + "_._IgCommandExe._DefaultError._Description": "Make sure you pass the correct commands!\r\nThis executable file contains command-line functions for ImageGlass software.\r\n\r\nTo explore all command lines, please visit:\r\n{0}", + "FrmMain.MnuLosslessCompression._Compressing": "Performing lossless compression…", + "FrmSettings._ShouldGroupImagesByDirectory": "Ryhmitä kuvat kansion mukaan", + "FrmMain.MnuPanToRightSide": "Pan image to right edge", + "_.Metadata._ExifRatingPercent": "Arvio", + "FrmSettings._PanSpeed": "Panning speed", + "_._CheckForUpdate": "Tarkista päivitykset…", + "FrmSettings.Layout._ToolbarContext": "Contextual toolbar", + "_.ImageInfo._FrameCount": "{0} ruutu(a)", + "FrmMain.MnuLayout": "Näytä", + "_._Website": "Verkkosivusto", + "FrmMain.MnuPasteImage": "Liitä kuva", + "FrmSettings._ShowGalleryScrollbars": "Show gallery scrollbars" + } +} \ No newline at end of file diff --git a/Setup/Assets/Language/French.iglang.json b/Setup/Assets/Language/French.iglang.json new file mode 100644 index 000000000..98477ac19 --- /dev/null +++ b/Setup/Assets/Language/French.iglang.json @@ -0,0 +1,504 @@ +{ + "_Metadata": { + "Code": "fr-FR", + "EnglishName": "French", + "LocalName": "Français", + "Author": "Jonas Boumediene", + "MinVersion": "9.3" + }, + "Items": { + "FrmCrop.SelectionAspectRatio._Original": "Original", + "FrmMain.MnuShare._Error": "Impossible d'ouvrir la boîte de dialogue de partage.", + "_.Metadata._FileLastAccessTime": "Date d'accès", + "FrmAbout._License": "Licence du logiciel", + "FrmSettings.Toolbar._Errors._ButtonIdDuplicated": "Un bouton avec l'ID '{0}' a déjà été défini. Veuillez choisir un ID différent et unique pour votre bouton afin d'éviter les conflits.", + "FrmMain.MnuSave._Confirm": "Êtes-vous sûr de vouloir écraser cette image ?", + "FrmSettings._OpenDefaultAppsSetting": "Ouvrir les paramètres des applications par défaut", + "FrmMain.MnuCopyPath": "Copier le chemin de l'image", + "FrmCropSettings.DefaultSelectionType._SelectNone": "Tout désélectionner", + "_.MouseWheelAction._PanHorizontally": "Déplacer vers la gauche / droite", + "FrmMain.MnuPrint": "Imprimer…", + "FrmSettings.Toolbar._ToolbarButtons": "Boutons de la barre d'outils", + "FrmResize.LblResample": "Rééchantillonner :", + "_.ImageOrderBy._Extension": "Extension", + "FrmSettings.Nav._Viewer": "Lecteur", + "FrmSettings.EditAppDialog._EditApp": "Modifier l'application", + "FrmCrop.BtnReset._Tooltip": "Réinitialiser la sélection", + "FrmMain.MnuRename._Description": "Entrez un nouveau nom de fichier :", + "_._No": "No", + "FrmSlideshow.MnuToggleCountdown": "Montrer le compte à rebours du diaporama", + "FrmSettings._OpenStartupAppsSetting": "Ouvrir les paramètres des applications de démarrage", + "FrmMain.MnuViewPreviousFrame": "Voir la page précédente", + "_.ImageOrderBy._DateModified": "Date de modification", + "FrmMain.MnuViewNextFrame": "Voir la page suivante", + "FrmMain.MnuUnload": "Décharger l'image", + "FrmSettings.Toolbar._HideToolbarInFullscreen": "Masquer la barre d'outils en mode plein écran", + "_.ImageOrderType._Desc": "Décroissant", + "_._Update": "Mise à jour", + "FrmSettings._EnableImageAsyncLoading": "Activer le chargement asynchrone des images", + "FrmSettings._DefaultPhotoViewer._Description": "Enregistrer les formats pris en charge par ImageGlass avec Windows. Vous devrez peut-être ouvrir les paramètres des applications par défaut et sélectionner manuellement ImageGlass dans la liste pour que cela prenne effet.", + "_.MouseWheelAction._BrowseImages": "Voir l'image suivante / précédente", + "FrmSettings._EditApps": "Applications d'édition d'images", + "FrmColorPickerSettings.ChkShowCIELabA": "Utiliser le format CIELAB avec un canal alpha", + "_._GetHelp": "Obtenir de l'aide", + "FrmQuickSetup._SkipQuickSetup": "Ignorer ceci et lancer ImageGlass", + "FrmColorPickerSettings._Title": "Paramètres du sélecteur de couleurs", + "_._Copy": "Copier", + "FrmSettings._ImageBoosterCacheCount": "Nombre d'images mises en cache par le Booster d'image (une direction)", + "FrmMain.MnuPanToBottom": "Déplacer l'image tout en bas", + "FrmMain.MnuZoom": "Zoom", + "FrmCropSettings.ChkCloseToolAfterSaving": "Fermez l'outil de rognage après l'enregistrement", + "FrmSettings._ShowWelcomeImage": "Afficher l'image d'accueil", + "FrmSettings._ColorProfile": "Profil colorimétrique", + "FrmSettings._Theme._UninstallTheme": "Désinstaller un pack de thème", + "FrmMain._OpenWith": "Ouvrir avec {0}", + "FrmMain.MnuRemoveDefaultPhotoViewer": "Supprimer la visionneuse de photos par défaut", + "_.AfterEditAppAction._Nothing": "Ne rien faire", + "FrmCrop.BtnSave": "Sauvegarder", + "FrmMain.MnuScaleToFit": "Redimensionner à l'échelle", + "FrmToolNotFound.LblDownloadToolText": "Vous pouvez télécharger plus d'outils pour ImageGlass sur :", + "_._LearnMore": "En savoir plus…", + "FrmCrop.LblAspectRatio": "Format de l'image :", + "FrmExportFrames._FileNotExist": "Le fichier d'image n'existe pas", + "FrmSettings._LightTheme": "Clair", + "FrmSettings.Nav._Slideshow": "Diaporama", + "_._Continue": "Continuer", + "_._AddHotkey": "Ajouter un raccourci clavier…", + "FrmMain.MnuSetDesktopBackground": "Définir comme fond d'écran", + "FrmMain.MnuReload": "Recharger l'image", + "FrmSlideshow.MnuExitSlideshow": "Quitter le diaporama", + "FrmMain.MnuAutoZoom": "Zoom automatique", + "FrmSettings._ShowImagePreview": "Afficher l'aperçu de l'image pendant son chargement", + "FrmCrop.BtnCopy._Tooltip": "Copier la sélection dans le presse-papiers", + "FrmSettings.Nav._Toolbar": "Barre d'outils", + "FrmMain.MnuSave._Error": "Impossible d'enregistrer l'image", + "FrmSettings._AfterEditingAction": "Après l'ouverture de l'application d'édition", + "FrmSettings._ShouldUseColorProfileForAll": "Applique aussi pour les images sans profil de couleur intégré", + "FrmCropSettings.DefaultSelectionType._UseTheLastSelection": "Utiliser la dernière sélection", + "FrmSettings._SlideshowInterval._From": "De", + "FrmSettings._ImageInterpolation": "Interpolation de l'image", + "FrmQuickSetup._StepInfo": "Étape {0}", + "FrmMain.MnuColorPicker": "Sélecteur de couleurs", + "FrmCrop.SelectionAspectRatio._FreeRatio": "Format libre", + "FrmSettings._ResetSettings": "Réinitialiser les paramètres", + "FrmSettings._Startup": "Démarrage", + "_.BackdropStyle._None": "Aucun", + "FrmSettings._LoadDefaultZoomLevels": "Charger les niveaux de zoom par défaut", + "FrmColorPicker.BtnSettings._Tooltip": "Ouvrir les paramètres du sélecteur de couleurs…", + "FrmSettings._UseThemeForDarkMode": "Utiliser ce thème pour le mode sombre", + "FrmSettings._ShowDeleteConfirmation": "Afficher une fenêtre de confirmation lorsqu'un fichier est supprimé", + "FrmSettings._ShowAppIcon": "Afficher l'icône de l'application dans la barre de titre", + "_._InvalidAction": "Action non valide", + "FrmQuickSetup._SelectProfile": "Sélectionner un profil", + "_.Metadata._FileCreationTime": "Date de création", + "FrmSettings._SlideshowImagesToNotifySound": "Nombre d'images pour déclencher une notification sonore", + "FrmSettings._BackgroundColor": "Couleur d'arrière-plan de la visionneuse", + "FrmSettings._RealTimeFileUpdate": "Mise à jour des fichiers en temps réel", + "_.ColorProfileOption._CurrentMonitorProfile": "Profil actuel du moniteur", + "FrmSettings._EnableCutMultipleFiles": "Possibilité de couper plusieurs fichiers à la fois", + "FrmSettings._AutoUpdate": "Rechercher les mises à jour automatiquement", + "FrmCropSettings.LblDefaultSelection": "Paramètres de sélection par défaut", + "FrmSettings._UseThemeForLightMode": "Utiliser ce thème pour le mode clair", + "FrmSettings._ZoomLevels": "Niveaux de zoom", + "FrmMain.MnuSetLockScreen._Success": "L'image de l'écran de verrouillage est mise à jour", + "FrmSettings._ShowGalleryFileName": "Afficher le nom de fichier de la vignette", + "FrmSettings.Layout._Order": "Ordre", + "FrmCropSettings.ChkAutoCenterSelection": "Centrer automatiquement la sélection", + "FrmSettings.Nav._FileTypeAssociations": "Associations de types de fichiers", + "_._Back": "Précédent", + "FrmMain.MnuSetDesktopBackground._Success": "L'arrière-plan du bureau est mis à jour", + "FrmSettings._ShouldAutoOpenNewAddedImage": "Ouvrir automatiquement les images ajoutées", + "FrmCrop.SelectionAspectRatio._Custom": "Personnalisé…", + "FrmMain.MnuCopyPath._Success": "Chemin de l'image copié.", + "FrmSettings._StartupBoost._Error": "Impossible de modifier le paramètre Démarrage Rapide", + "FrmToolNotFound.LblDescription": "ImageGlass n'a pas pu localiser le chemin d'accès vers l'exécutable '{0}'. Pour résoudre ce problème, veuillez mettre à jour le chemin d'accès vers '{0}' si nécessaire.", + "FrmMain.MnuClearClipboard": "Vider le presse-papiers", + "FrmSettings._ColorManagement": "Gestion des couleurs", + "FrmMain._ReachedLastLast": "Dernière image atteinte", + "FrmMain.MnuPanUp": "Déplacer l'image vers le haut", + "FrmMain.MnuRemoveDefaultPhotoViewer._Success": "ImageGlass n'est plus la visionneuse de photos par défaut.", + "FrmSettings._GetMoreLanguagePacks": "Obtenir plus de packs de langues…", + "FrmAbout._Privacy": "Politique de confidentialité", + "FrmSettings._EnableRecursiveLoading": "Charger les images dans les sous-dossiers", + "_._UserAction._MethodArgumentNotSupported": "Le type d'argument de la méthode '{0}' n'est pas pris en charge", + "FrmSettings._FileExtensionIcons._Description": "Pour personnaliser les icônes des extensions de fichiers, téléchargez un pack d'icônes, placez tous les fichiers .ICO dans le répertoire d'extension d'icônes et cliquez sur le bouton '{0}'. Cela définira également ImageGlass comme visionneuse de photos par défaut.", + "_.ImageOrderType._Asc": "Croissant", + "FrmExportFrames._Title": "Exporter des pages de l'image", + "_._Install": "Installer…", + "FrmMain.MnuFlipHorizontal": "Inverser horizontalement", + "FrmSettings._OpenExtensionIconFolder": "Ouvrir le répertoire d'extension d'icônes", + "FrmAbout._Collaborator": "Collaborateur :", + "FrmQuickSetup._ConfirmCloseProcess": "Avant d'appliquer les nouveaux paramètres, il est essentiel de fermer tous les processus ImageGlass. Êtes-vous sûr de vouloir continuer ?", + "FrmExportFrames._ExportDone": "{0} pages ont été exportées avec succès vers \n{1}", + "FrmCrop.BtnSaveAs._Tooltip": "Enregistrer en tant que copie…", + "FrmMain.MnuOpenFile": "Ouvrir un fichier…", + "FrmColorPickerSettings.ChkShowRgbA": "Utiliser le format RVB avec un canal alpha", + "_.ImageInfo._ListCount": "{0} fichier(s)", + "FrmMain.MnuGoToLast": "Aller à la dernière image", + "FrmSettings._EditApps._AppName": "Nom de l'application", + "FrmSettings._SlideshowBackgroundColor": "Couleur d’arrière-plan du diaporama", + "FrmAbout._Email": "Email :", + "_.MouseWheelAction._DoNothing": "Ne rien faire", + "FrmMain.MnuSaveAs": "Sauvegarder sous…", + "FrmMain._Loading": "Chargement…", + "_._Browse": "Parcourir…", + "FrmMain.MnuSetDefaultPhotoViewer._Error": "Impossible de définir ImageGlass comme visionneuse de photos par défaut.", + "FrmSettings.Nav._Language": "Langue", + "FrmQuickSetup._SeeWhatNew": "Voir les nouveautés de cette version…", + "FrmSettings._ImageInterpolation._ScaleUp": "Lorsque zoom > 100%", + "FrmSettings.Layout._ToolbarContextPosition": "Position de la barre d'outils contextuelle", + "FrmMain.MnuDeleteFromHardDisk": "Supprimer définitivement", + "FrmSettings._EmbeddedThumbnail": "Vignette intégrée", + "FrmMain.MnuDeleteFromHardDisk._Description": "Êtes-vous sûr de vouloir supprimer définitivement ce fichier ?", + "FrmMain.MnuScaleToFill": "Redimensionner pour remplir", + "FrmCrop.BtnCrop": "Rogner", + "_.AfterEditAppAction._Minimize": "Réduire", + "FrmMain.MnuInvertColors": "Inverser les couleurs", + "FrmSettings._StartupBoost": "Démarrage Rapide", + "FrmMain.MnuViewFirstFrame": "Voir la première page", + "_.MouseWheelEvent._CtrlAndScroll": "Maintenir Ctrl et faire défiler", + "FrmSettings._HideMainWindowInSlideshow": "Masquer automatiquement la fenêtre principale", + "_.Metadata._FrameCount": "Pages", + "FrmSettings._EnableCopyMultipleFiles": "Possibilité de copier plusieurs fichiers à la fois", + "FrmMain.MnuFrameless._EnableDescription": "Maintenez Maj pour déplacer la fenêtre.", + "_.ImageOrderBy._ExifDateTaken": "EXIF : Date de prise de vue", + "FrmAbout._Credits": "Crédits", + "FrmSettings._AddNewFileExtension": "Ajouter une nouvelle extension de fichier", + "FrmMain.MnuQuickSetup": "Configuration rapide de ImageGlass", + "FrmMain.MnuSave._Success": "L'image est enregistrée", + "FrmMain.MnuPanLeft": "Déplacer l'image vers la gauche", + "FrmUpdate._StatusChecking": "Recherche des mises à jour…", + "FrmSettings.Nav._Layout": "Mise en forme", + "FrmMain.MnuOpenWith": "Ouvrir avec…", + "FrmAbout._Thanks": "Remerciements à :", + "_._Warning": "Avertissement", + "FrmSettings.Nav._Keyboard": "Clavier", + "FrmSlideshow._PauseSlideshow": "Le diaporama est mis en pause.", + "_._Add+": "Ajouter…", + "_._Email": "Email", + "FrmMain.MnuPanDown": "Déplacer l'image vers le bas", + "_._Cancel": "Annuler", + "_._OK": "OK", + "FrmMain.MnuPanRight": "Déplacer l'image vers la droite", + "_.Position._Right": "Droite", + "_._Icon": "Icône", + "FrmSettings._ShouldLoadHiddenImages": "Charger les images cachées", + "_._InvalidAction._Transformation": "ImageGlass ne prend pas en charge la rotation ou la symétrie pour cette image.", + "FrmSettings._MakeDefault": "Définir par défaut", + "FrmMain.MnuCopyImageData._Copying": "Copie des données de l'image. Cela va prendre un certain temps…", + "FrmSettings._UseEmbeddedThumbnailRawFormats": "Charger uniquement la vignette intégrée pour les formats RAW", + "_.ImageInterpolation._Linear": "Linéaire", + "FrmSettings._ImageInfoTags": "Balises d'information de l'image", + "FrmSettings._FileExtensionIcons": "Icônes d'extension de fichier", + "FrmMain.MnuEdit._AppNotFound": "Impossible de trouver l'application associée pour l'édition. Vous pouvez choisir une application pour modifier ce format dans les paramètres ImageGlass > Editer.", + "_.ColorProfileOption._None": "Aucun", + "FrmSettings._TotalSupportedFormats": "Nombre de formats pris en charge : {0}", + "FrmSettings._Clipboard": "Presse-papiers", + "_._UserAction._Win32ExeError": "Impossible d'exécuter la commande '{0}'. Assurez-vous que le nom soit correct.", + "FrmCropSettings.DefaultSelectionType._SelectX": "Sélectionner {0}", + "_.AfterEditAppAction._Close": "Fermer", + "FrmAbout._LogoDesigner": "Concepteur du logo :", + "_.ImageOrderBy._Name": "Nom (par défaut)", + "FrmMain.MnuRemoveDefaultPhotoViewer._Error": "Impossible d'enlever ImageGlass comme visionneuse de photos par défaut.", + "FrmExportFrames._FolderPickerTitle": "Sélectionner le répertoire de destination pour l'exportation des pages", + "FrmAbout._Donate": "Donation", + "FrmMain.MnuFrameNav": "Navigation par pages", + "FrmMain.MnuSetLockScreen": "Définir comme fond d'écran de verrouillage", + "_._Delete": "Supprimer", + "FrmMain.MnuViewPrevious": "Voir l'image précédente", + "_.Position._Top": "Haut", + "FrmSettings.Toolbar._CurrentButtons": "Boutons actuels :", + "FrmMain.MnuAbout": "A propos", + "FrmSettings._RemoveDefault": "Retirer par défaut", + "_._Description": "Description", + "FrmMain.MnuPasteImage._Error": "Impossible de trouver des données d'image dans le presse-papiers", + "FrmMain.MnuSettings": "Paramètres", + "FrmCropSettings._Title": "Paramètres de rognage", + "FrmSettings.Toolbar._ToolbarIconHeight": "Taille des icônes de la barre d'outils", + "FrmSettings._SlideshowInterval._To": "À", + "FrmSettings.Layout._ToolbarPosition": "Position de la barre d'outils", + "FrmUpdate._StatusUpdated": "Vous utilisez la dernière version !", + "FrmMain.MnuExit": "Quitter", + "_._Webview2._Outdated": "Votre WebView2 Runtime n'est pas pris en charge. Veuillez mettre à jour vers la version {0} ou ultérieure.", + "_._Yes": "Oui", + "FrmMain.MnuRotateLeft": "Pivoter à gauche", + "FrmSettings._EnableStartupBoost": "Activer le Démarrage Rapide", + "_.ImageOrderBy._ExifRating": "EXIF : Notation", + "FrmMain.MnuZoomIn": "Zoomer", + "_.Metadata._ColorSpace": "Espace de couleurs", + "FrmAbout._Version": "Version :", + "FrmMain.MnuToggleTopMost._Enable": "Fenêtre toujours premier plan activé", + "FrmSettings.Toolbar._AvailableButtons": "Boutons disponibles :", + "FrmMain.MnuSave._Saving": "Enregistrement de l'image…", + "FrmQuickSetup._StandardUser": "Utilisateur standard", + "FrmMain.MnuSetLockScreen._Error": "Impossible de définir l'image en tant qu'image de l'écran de verrouillage", + "FrmSettings.Nav._Image": "Image", + "FrmSettings._Theme._InstallTheme": "Installer les packs de thème", + "FrmSettings._EnableMultiInstances": "Autoriser plusieurs instances du programme", + "FrmMain.MnuCropTool": "Rogner l’image", + "_._IgCommandExe._DefaultError._Heading": "Commande invalide", + "_._Refresh": "Rafraichir", + "FrmMain.MnuLosslessCompression._Description": "Cet outil utilise la bibliothèque Magick.NET pour la compression sans perte, optimisant la taille des fichiers. Écrase uniquement si le fichier compressé est plus petit que l'original.", + "_._MoveDown": "Déplacer vers le bas", + "FrmSettings._GetExtensionIconPacks": "Obtenir des packs d'extension d'icônes…", + "FrmSettings._InAppMessageDuration": "Durée des messages dans l'application (en millisecondes)", + "FrmMain.MnuFrameless": "Sans bordure", + "_._Reset": "Réinitialiser", + "FrmSettings._ConfigDir": "Emplacement des fichiers de configuration", + "FrmQuickSetup._SettingsWillBeApplied": "Les paramètres seront appliqués :", + "FrmSettings._UnmanagedSettingReminder": "Ce paramètre n'est pas géré par ImageGlass. N'oubliez pas de le désactiver avant de supprimer ou de déplacer l'application, car ImageGlass ne le gère pas automatiquement.", + "FrmMain.MnuClipboard": "Presse-papiers", + "FrmMain.MnuCustomZoom": "Zoom personnalisé…", + "FrmSettings._DisplayLanguage": "Langue d'affichage", + "FrmMain.MnuPrint._Error": "Impossible d'imprimer l'image de visualisation", + "FrmSettings._ShouldPreserveModifiedDate": "Conserver la date de modification de l'image lors de la sauvegarde", + "FrmSettings._ShowSaveOverrideConfirmation": "Afficher une fenêtre de confirmation lorsqu'un fichier est écrasé", + "FrmColorPickerSettings.ChkShowHexA": "Utiliser le format HEX avec un canal alpha", + "FrmMain.MnuFullScreen": "Plein écran", + "FrmSettings._StartupDir": "Emplacement de démarrage", + "FrmSettings._ShowCheckerboardOnlyImageRegion": "Afficher le damier uniquement dans la zone de l'image", + "FrmMain.MnuClearClipboard._Success": "Presse-papiers effacé.", + "FrmQuickSetup._Text": "Configuration rapide de ImageGlass", + "FrmMain.MnuLosslessCompression._Done": "Compression sans perte effectuée.\r\nLa nouvelle taille de fichier est {0}, {1} sauvegardé.", + "FrmMain.MnuLosslessCompression": "Compression sans perte Magick.NET", + "FrmResize.RadResizeByPercentage": "Pourcentage", + "FrmSettings._StartupBoost._Disabled": "Le Démarrage Rapide est désactivé", + "FrmMain.MnuToggleCheckerboard": "Fond en damier", + "FrmSettings._MinEmbeddedThumbnailSize._Height": "Hauteur", + "FrmSettings.Nav._General": "Général", + "FrmSettings._ImageLoading": "Chargement de l'image", + "FrmSettings._ShowSlideshowCountdown": "Montrer le compte à rebours du diaporama", + "FrmMain.MnuSave": "Sauvegarder", + "FrmMain.MnuMoveToRecycleBin": "Déplacer dans la corbeille", + "FrmMain.MnuRefresh": "Rafraichir", + "FrmToolNotFound.LblHeading": "'{0}' est introuvable !", + "FrmMain.MnuReportIssue": "Signaler un problème…", + "FrmMain.MnuCopyImageData": "Copier les données de l'image", + "FrmMain.MnuCheckForUpdate._NewVersion": "Une nouvelle version est disponible !", + "_._Empty": "(vide)", + "FrmSettings._Zooming": "Zoomer", + "FrmMain.MnuCutFile": "Couper le fichier", + "FrmHotkeyPicker.LblHotkey": "Appuyer sur les touches de raccourci", + "FrmSettings.Layout._Gallery": "Galerie", + "FrmMain.MnuNewWindow": "Ouvrir une nouvelle fenêtre", + "FrmMain.MnuMoveToRecycleBin._Description": "Voulez-vous déplacer ce fichier dans la corbeille ?", + "FrmSettings._DefaultPhotoViewer": "Visionneuse de photos par défaut", + "_.Metadata._ExifDateTimeOriginal": "EXIF: DateTimeOriginal", + "FrmMain.MnuRotateRight": "Pivoter à droite", + "FrmSettings._MinEmbeddedThumbnailSize": "Taille minimale de la vignette intégrée à charger", + "FrmMain.MnuSetDefaultPhotoViewer": "Définir la visionneuse de photos par défaut", + "FrmMain.MnuImageProperties": "Propriétés de l'image", + "FrmSettings._EnableNavigationButtons": "Afficher les flèches de navigation", + "_._Edit": "Editer", + "FrmSettings._ImageBooster": "Booster d'image", + "FrmSettings.Tools._IntegratedWith": "Intégré à {0}", + "_._Next": "Suivant", + "FrmExportFrames._OpenOutputFolder": "Ouvrir le répertoire de destination", + "FrmMain.MnuOpenLocation": "Ouvrir l'emplacement de l'image", + "FrmMain.MnuLockZoom": "Bloquer le zoom", + "FrmSettings._StartupBoost._Description": "Précharger et exécuter ImageGlass en arrière-plan pendant quelques secondes au démarrage de Windows pour accélérer le premier lancement.", + "FrmSettings._WindowBackdrop": "Arrière-plan de la fenêtre", + "FrmSettings._EnableRealTimeFileUpdate": "Surveiller les modifications de fichiers dans le dossier en cours et mettre à jour en temps réel", + "_._NotSupported": "Format non supporté", + "FrmSettings._Theme._GetMoreThemes": "Obtenez plus de packs de thème…", + "FrmMain.MnuNewWindow._Error": "Impossible d'ouvrir une nouvelle fenêtre, car seulement une seule instance est autorisée", + "FrmMain.MnuZoomOut": "Dézoomer", + "FrmSettings.Toolbar._EditButton": "Modifier le bouton de la barre d'outils", + "FrmMain.MnuCustomZoom._Description": "Entrez une nouvelle valeur de zoom", + "FrmResize.RadResizeByPixels": "Pixels", + "FrmMain.MnuEdit": "Modifier l'image {0}…", + "FrmSettings.Layout._GalleryPosition": "Position de la galerie", + "FrmMain.MnuWindowFit": "Ajustement à la fenêtre", + "FrmMain._OpenFileDialog": "Fichiers pris en charge", + "FrmSettings._UseRandomIntervalForSlideshow": "Utiliser un intervalle aléatoire", + "_.Position._Left": "Gauche", + "FrmSettings._ShouldOpenLastSeenImage": "Ouvrir la dernière image visionnée", + "_.Position._Bottom": "Bas", + "FrmResize.ChkKeepRatio": "Garder le ratio proportionnel", + "FrmMain.MnuGoTo": "Aller à…", + "FrmSlideshow.MnuPauseResumeSlideshow": "Pause/reprendre le diaporama", + "FrmSettings.Tools._Integrated": "Intégré", + "FrmSettings._Contributors": "Contributeurs", + "_.MouseWheelAction._Zoom": "Zoom avant / arrière", + "_._CommandPreview": "Aperçu de la commande", + "FrmSettings._DarkTheme": "Sombre", + "_._Hotkeys": "Raccourcis clavier", + "_.Metadata._ExifDateTime": "EXIF: DateTime", + "FrmSettings.Toolbar._Errors._ButtonIdRequired": "ID du bouton requis.", + "FrmSettings._MinEmbeddedThumbnailSize._Width": "Largeur", + "_._Executable": "Exécutable", + "_.ImageInterpolation._MultiSampleLinear": "Linéaire multi-échantillons", + "_._Separator": "Séparateur", + "FrmQuickSetup._ProfessionalUser": "Utilisateur professionnel", + "FrmMain.MnuFlipVertical": "Inverser verticalement", + "FrmSlideshow._ResumeSlideshow": "Le diaporama a repris.", + "FrmCropSettings.DefaultSelectionType._CustomArea": "Zone personnalisée…", + "FrmMain.MnuActualSize": "Taille réelle", + "FrmCrop.BtnSaveAs": "Sauvegarder sous…", + "FrmSettings._InstallNewLanguagePack": "Installer de nouveaux packs de langue…", + "FrmSlideshow.MnuZoomModes": "Modes de zoom", + "FrmMain.MnuTools": "Outils", + "_.ImageInterpolation._Cubic": "Cubique", + "FrmUpdate._LatestVersion": "La dernière version : {0}", + "FrmMain.MnuViewNext": "Voir l'image suivante", + "_.MouseWheelEvent._AltAndScroll": "Maintenir Alt et faire défiler", + "FrmToolNotFound._Title": "Outil introuvable", + "FrmCrop.BtnCrop._Tooltip": "Rogner uniquement l'image", + "FrmSettings.EditAppDialog._AddApp": "Ajouter une application pour l'édition", + "FrmMain.MnuPanning": "Panoramique", + "_._MoveUp": "Déplacer vers le haut", + "FrmCropSettings.DefaultSelectionType._SelectAll": "Tout sélectionner", + "_._Name": "Nom", + "FrmColorPickerSettings.ChkShowHslA": "Utiliser le format TSL avec un canal alpha", + "FrmMain.MnuToggleImageAnimation": "Démarrer/arrêter l'animation de l'image", + "FrmSettings._DisableStartupBoost": "Désactiver le Démarrage Rapide", + "FrmMain.MnuCopyFile._Success": "{0} fichier(s) copié(s).", + "FrmMain.MnuSave._ConfirmDescription": "ImageGlass n'est pas un éditeur de photo professionnel, il est possible que la qualité, métadonnées, calques etc peuvent être perdues lors de l'enregistrement de l'image.", + "FrmToolNotFound.BtnSelectExecutable": "Sélectionner…", + "FrmUpdate._StatusOutdated": "Une nouvelle mise à jour est disponible !", + "_.ImageOrderBy._Random": "Aléatoire", + "FrmResize.LblCurrentSize": "Taille actuelle :", + "_._Apply": "Appliquer", + "FrmAbout._Slogan": "Une visionneuse d’images légère et polyvalente", + "FrmMain.MnuPanToTop": "Déplacer l'image tout en haut", + "FrmSettings.Toolbar._AddNewButton": "Ajouter un bouton personnalisé à la barre d'outils", + "FrmCrop.LblSize": "Taille :", + "FrmSettings._ImageInterpolation._ScaleDown": "Lorsque le zoom < 100 %", + "_._CreatingFileError": "Impossible de créer le fichier image temporaire", + "FrmMain.MnuGoTo._Description": "Entrez le numéro de l'image à afficher, puis appuyez sur ENTRÉE", + "FrmSettings.Toolbar._EnableCenterToolbar": "Centrer la barre d'outils", + "FrmMain.MnuResizeTool": "Redimensionner l'image", + "FrmSettings.Layout._Toolbar": "Barre d'outils", + "FrmMain.MnuHelp": "Aide", + "_.ImageOrderBy._FileSize": "Taille du fichier", + "FrmSettings._Theme._OpenThemeFolder": "Ouvrir le dossier du thème", + "FrmMain.MnuNavigation": "Navigation", + "_._Save": "Sauvegarder", + "FrmQuickSetup._SettingProfileDescription": "Pour modifier ces paramètres, accédez aux paramètres de l'application.", + "_._UserAction._MenuNotFound": "Impossible de trouver le menu '{0}' pour l'action souhaitée", + "FrmMain.MnuPanToLeftSide": "Déplacer l'image du côté gauche", + "FrmUpdate._CurrentVersion": "Version actuelle : {0}", + "FrmCrop.BtnSettings._Tooltip": "Ouvrir les paramètres de l'outil de rognage", + "_.ColorProfileOption._Custom": "Personnalisé…", + "FrmSettings._UseEmbeddedThumbnailOtherFormats": "Charger uniquement la vignette intégrée pour les autres formats", + "FrmMain.MnuGoToFirst": "Aller à la première image", + "FrmSettings._ExportLanguagePack": "Exporter le pack de langue…", + "FrmSettings.Nav._Mouse": "Souris", + "_.ImageOrderBy._DateCreated": "Date de création", + "FrmSettings._EnableFullscreenSlideshow": "Lancer le diaporama en mode plein écran", + "FrmAbout._Homepage": "Accueil :", + "FrmSettings._GalleryCacheSizeInMb": "Taille maximale du cache de la galerie (en mégaoctets)", + "FrmMain.MnuCopyImageData._Success": "Les données de l'image actuelle sont copiées.", + "FrmSettings._EnableLoopBackNavigation": "Revenir à la première image lorsque la fin de la liste d'images est atteinte", + "_.MouseWheelEvent._Scroll": "Défilement", + "FrmCrop.BtnSave._Tooltip": "Sauvegarder l'image", + "FrmMain.MnuSlideshow": "Diaporama", + "FrmMain.MnuShare": "Partager…", + "FrmSettings._SlideshowNotification": "Notification du diaporama", + "FrmMain.MnuViewChannels": "Voir les canaux", + "FrmSettings._Refresh": "Rafraichir", + "_._UserAction._MethodNotFound": "Impossible de trouver la méthode '{0}' pour l'action souhaitée", + "FrmMain.MnuCopyFile": "Copier le fichier", + "_._CreatingFile": "Création d'un fichier image temporaire…", + "FrmMain.MnuToggleTopMost": "Garder la fenêtre au premier plan", + "FrmMain.MnuLosslessCompression._Confirm": "Êtes-vous sûr de vouloir continuer ?", + "FrmMain.MnuImage": "Image", + "FrmSettings._StartupBoost._Enabled": "Le Démarrage Rapide est activé", + "FrmQuickSetup._SetDefaultViewer": "Voulez-vous définir ImageGlass en tant que visionneuse de photos par défaut ?", + "FrmMain.MnuScaleToWidth": "Mettre à l'échelle de la largeur", + "_._FileExtension": "Extension de fichier", + "FrmUpdate._PublishedDate": "Date de publication : {0}", + "_._DoNotShowThisMessageAgain": "Ne plus afficher ce message", + "_.ImageInterpolation._NearestNeighbor": "Au plus proche", + "FrmCrop.LblLocation": "Emplacement :", + "_._Download": "Télécharger", + "_.Metadata._ColorProfile": "Profil colorimétrique", + "FrmSettings._CenterWindowFit": "Centrer automatiquement la fenêtre en mode Ajustement à la fenêtre", + "FrmSettings._ImageLoadingOrder": "Ordre de chargement d'image", + "FrmSettings._GalleryColumns": "Nombre de colonnes de vignettes dans la disposition verticale de la galerie", + "_._Quit": "Quitter", + "_._Add": "Ajouter", + "FrmMain.MnuChangeBackgroundColor": "Changer la couleur de fond…", + "FrmMain.MnuToggleToolbar": "Barre d'outils", + "FrmAbout._Contact": "Contact", + "FrmSettings.Toolbar._AddCustomButton": "Ajouter un bouton personnalisé…", + "FrmCrop.BtnQuickSelect._Tooltip": "Sélection rapide…", + "FrmMain.MnuCutFile._Success": "{0} fichier(s) coupé(s).", + "FrmSettings._ZoomSpeed": "Vitesse de zoom", + "FrmMain.MnuToggleTopMost._Disable": "Fenêtre toujours premier plan désactivé", + "FrmSettings._ShouldUseExplorerSortOrder": "Utiliser l'ordre de tri de l'Explorateur si possible", + "_.ImageInterpolation._Antisotropic": "Anisotropique", + "FrmMain._ReachedFirstImage": "Première image atteinte", + "_._UnhandledException": "Exception non gérée", + "FrmResize.LblNewSize": "Nouvelle taille :", + "FrmMain._ClipboardImage": "Image du Presse-papiers", + "FrmMain.MnuExportFrames": "Exporter des pages de l'image…", + "FrmMain.MnuFile": "Fichier", + "_._Close": "Fermer", + "FrmMain.MnuMain": "Menu principal", + "_._ResetToDefault": "Réinitialiser", + "FrmSettings.Nav._Gallery": "Galerie", + "FrmMain.MnuSetDefaultPhotoViewer._Success": "Vous avez défini ImageGlass comme visionneuse de photos par défaut.", + "FrmSettings._HideGalleryInFullscreen": "Masquer la galerie en mode plein écran", + "FrmSettings._AvailableImageInfoTags": "Mots-clés disponibles :", + "FrmExportFrames._Exporting": "Exportation des pages {0}/{1} \n{2}…", + "_._Argument": "Argument", + "FrmSettings._ImageEditQuality": "Qualité d'image", + "_._ID": "ID", + "FrmSettings._UserConfigFile": "Fichier de paramètres utilisateur (igconfig.json)", + "FrmMain.MnuLoadingOrders": "Ordre de chargement", + "FrmSettings._OpenSaveAsDialogInTheCurrentImageDir": "Ouvrir la boîte de dialogue Enregistrer sous dans le répertoire d'images actuel", + "_.MouseWheelEvent._ShiftAndScroll": "Maintenir Maj et faire défiler", + "FrmSettings._UseSmoothZooming": "Utiliser un zoom fluide", + "FrmSettings._Theme": "Thème", + "FrmSettings._ImageBoosterCacheMaxDimension": "Dimension maximale de l'image à mettre en cache (en pixels)", + "FrmMain.MnuScaleToHeight": "Mettre à l'échelle de la hauteur", + "_.Metadata._FileLastWriteTime": "Date de modification", + "FrmSettings._Author": "Auteur", + "FrmSettings._Others": "Autres", + "_.MouseWheelAction._PanVertically": "Déplacer vers le haut/bas", + "FrmSettings._MouseWheelAction": "Action de la molette de la souris", + "FrmSettings.Nav._Tools": "Outils", + "FrmMain.MnuSetDesktopBackground._Error": "Impossible de définir l'image de visualisation comme fond de bureau", + "FrmSettings.Toolbar._Errors._ButtonExecutableRequired": "Bouton exécutable requis.", + "_.ImageOrderBy._DateAccessed": "Date d'accès", + "FrmSettings._ThumbnailSize": "Taille de la miniature (en pixels)", + "FrmSettings._FileFormats": "Formats de fichier", + "FrmMain.MnuReloadImageList": "Recharger la liste d'images", + "FrmSettings._UseWebview2ForSvg": "Utiliser Webview2 pour afficher le format SVG", + "FrmCrop.BtnCopy": "Copier", + "FrmSettings._CurrentMonitorProfile._Description": "ImageGlass ne met pas automatiquement à jour la couleur lorsque sa fenêtre est déplacée vers un autre écran", + "FrmMain.PicMain._ErrorText": "Impossible d'ouvrir cette image", + "FrmSettings.Tools._AddNewTool": "Ajouter un outil externe", + "FrmMain.MnuRename": "Renommer l'image…", + "FrmMain.MnuViewLastFrame": "Voir la dernière page", + "_._Webview2._NotFound": "Veuillez installer la dernière version du runtime WebView2.", + "FrmMain.MnuGetMoreTools": "Obtenez plus d'outils…", + "FrmSettings.Nav._Appearance": "Apparence", + "FrmSettings._SlideshowInterval": "Intervalle du diaporama :", + "_.ImageInterpolation._HighQualityBicubic": "Haute qualité bicubique", + "FrmColorPickerSettings.ChkShowHsvA": "Utiliser le format TSV avec un canal alpha", + "FrmSettings.Tools._EditTool": "Éditer un outil externe", + "_._Error": "Erreur", + "FrmSettings._ImageBoosterCacheMaxFileSizeInMb": "Taille maximale du fichier image à mettre en cache (en mégaoctets)", + "_._UnhandledException._Description": "Une exception non gérée s'est produite. Si vous cliquez sur continuer, l'application ignorera cette erreur et essaiera de continuer. Si vous cliquez sur quitter, l'application se fermera immédiatement.", + "_.Metadata._FileSize": "Taille du fichier", + "FrmSettings.Toolbar._ButtonJson": "Bouton JSON", + "FrmQuickSetup._SetDefaultViewer._Description": "Vous pouvez le réinitialiser dans l'onglet Paramètres > Associations de types de fichiers.", + "FrmSettings.Nav._Edit": "Editer", + "FrmMain.MnuToggleGallery": "Panneau de galerie", + "_._IgCommandExe._DefaultError._Description": "Assurez-vous d'entrer les bonnes commandes !\r\nCe fichier exécutable contient des fonctionnalités en ligne de commande pour le logiciel ImageGlass.\r\n\r\nPour explorer toutes les lignes de commande, veuillez visiter :\n{0}", + "FrmMain.MnuLosslessCompression._Compressing": "Exécution de la compression sans perte…", + "FrmSettings._ShouldGroupImagesByDirectory": "Regrouper les images par répertoire", + "FrmMain.MnuPanToRightSide": "Déplacer l'image du côté droit", + "_.Metadata._ExifRatingPercent": "Note", + "FrmSettings._PanSpeed": "Vitesse de mouvement panoramique", + "_._CheckForUpdate": "Vérifier les mises à jour…", + "FrmSettings.Layout._ToolbarContext": "Barre d'outils contextuelle", + "_.ImageInfo._FrameCount": "{0} pages(s)", + "FrmMain.MnuLayout": "Mise en forme", + "_._Website": "Site Web", + "FrmMain.MnuPasteImage": "Coller l'image", + "FrmSettings._ShowGalleryScrollbars": "Afficher les barres de défilement de la galerie" + } +} \ No newline at end of file diff --git a/Setup/Assets/Language/German.iglang.json b/Setup/Assets/Language/German.iglang.json new file mode 100644 index 000000000..20a9d5653 --- /dev/null +++ b/Setup/Assets/Language/German.iglang.json @@ -0,0 +1,504 @@ +{ + "_Metadata": { + "Code": "de-DE", + "EnglishName": "German", + "LocalName": "Deutsch", + "Author": "Marcel Veronetzki (DasOni)", + "MinVersion": "9.3" + }, + "Items": { + "FrmCrop.SelectionAspectRatio._Original": "Original", + "FrmMain.MnuShare._Error": "Konnte Teilendialog nicht öffnen.", + "_.Metadata._FileLastAccessTime": "Zugriffsdatum", + "FrmAbout._License": "Softwarelizenz", + "FrmSettings.Toolbar._Errors._ButtonIdDuplicated": "Eine Schaltfläche mit der ID '{0}' wurde bereits definiert. Bitte wählen Sie eine andere und eindeutige ID für Ihre Schaltfläche aus, um Konflikte zu vermeiden.", + "FrmMain.MnuSave._Confirm": "Sind Sie sicher, dass Sie dieses Bild überschreiben möchten?", + "FrmSettings._OpenDefaultAppsSetting": "Standard-App-Einstellungen öffnen", + "FrmMain.MnuCopyPath": "Bildpfad kopieren", + "FrmCropSettings.DefaultSelectionType._SelectNone": "Nichts auswählen", + "_.MouseWheelAction._PanHorizontally": "Nach links / rechts", + "FrmMain.MnuPrint": "Drucken…", + "FrmSettings.Toolbar._ToolbarButtons": "Symbolleisten-Schaltflächen", + "FrmResize.LblResample": "Pixelneuberechnung:", + "_.ImageOrderBy._Extension": "Dateiendung", + "FrmSettings.Nav._Viewer": "Betrachter", + "FrmSettings.EditAppDialog._EditApp": "App bearbeiten", + "FrmCrop.BtnReset._Tooltip": "Auswahl zurücksetzen", + "FrmMain.MnuRename._Description": "Neuen Dateiname eingeben:", + "_._No": "No", + "FrmSlideshow.MnuToggleCountdown": "Zeige Diashow-Countdown", + "FrmSettings._OpenStartupAppsSetting": "Start App-Einstellungen öffnen", + "FrmMain.MnuViewPreviousFrame": "Voriges Bild anzeigen", + "_.ImageOrderBy._DateModified": "Änderungsdatum", + "FrmMain.MnuViewNextFrame": "Nächstes Bild anzeigen", + "FrmMain.MnuUnload": "Bild entladen", + "FrmSettings.Toolbar._HideToolbarInFullscreen": "Symbolleiste im Vollbildmodus ausblenden", + "_.ImageOrderType._Desc": "Absteigend", + "_._Update": "Aktualisieren", + "FrmSettings._EnableImageAsyncLoading": "Asynchrones Laden von Bildern aktivieren", + "FrmSettings._DefaultPhotoViewer._Description": "Registrieren Sie die unterstützten Formate von ImageGlass mit Windows. Möglicherweise müssen Sie die Standard-App-Einstellungen öffnen und ImageGlass manuell aus der Liste auswählen, damit es wirksam wird.", + "_.MouseWheelAction._BrowseImages": "Nächstes / vorheriges Bild anzeigen", + "FrmSettings._EditApps": "Bildbearbeitungs-Apps", + "FrmColorPickerSettings.ChkShowCIELabA": "CIELAB-Format mit Alpha-Wert verwenden", + "_._GetHelp": "Hilfe", + "FrmQuickSetup._SkipQuickSetup": "Überspringen und ImageGlass starten", + "FrmColorPickerSettings._Title": "Farbwähler Einstellungen", + "_._Copy": "Kopieren", + "FrmSettings._ImageBoosterCacheCount": "Anzahl der von Bild-Booster zwischengespeicherten Bilder (eine Richtung)", + "FrmMain.MnuPanToBottom": "Bildausschnitt zum unteren Rand schieben", + "FrmMain.MnuZoom": "Vergrößerung", + "FrmCropSettings.ChkCloseToolAfterSaving": "Zuschneiden-Werkzeug nach dem Speichern schließen", + "FrmSettings._ShowWelcomeImage": "Willkommensbild anzeigen", + "FrmSettings._ColorProfile": "Farbprofil", + "FrmSettings._Theme._UninstallTheme": "Ein Theme-Paket deinstallieren", + "FrmMain._OpenWith": "Offen mit {0}", + "FrmMain.MnuRemoveDefaultPhotoViewer": "Standard-Bildbetrachter entfernen", + "_.AfterEditAppAction._Nothing": "Nichts", + "FrmCrop.BtnSave": "Speichern", + "FrmMain.MnuScaleToFit": "Fenster auf Bildgröße skalieren", + "FrmToolNotFound.LblDownloadToolText": "Weitere Tools für ImageGlass können Sie hier herunterladen:", + "_._LearnMore": "Mehr erfahren...", + "FrmCrop.LblAspectRatio": "Seitenverhältnis:", + "FrmExportFrames._FileNotExist": "Bilddatei existiert nicht", + "FrmSettings._LightTheme": "Hell", + "FrmSettings.Nav._Slideshow": "Diashow", + "_._Continue": "Weiter", + "_._AddHotkey": "Tastaturkürzel hinzufügen...", + "FrmMain.MnuSetDesktopBackground": "Als Hintergrundbild festlegen", + "FrmMain.MnuReload": "Bild neu laden", + "FrmSlideshow.MnuExitSlideshow": "Diashow beenden", + "FrmMain.MnuAutoZoom": "Automatischer Zoom", + "FrmSettings._ShowImagePreview": "Bildvorschau anzeigen, während das Bild geladen wird", + "FrmCrop.BtnCopy._Tooltip": "Auswahl in Zwischenablage kopieren", + "FrmSettings.Nav._Toolbar": "Symbolleiste", + "FrmMain.MnuSave._Error": "Bild konnte nicht gespeichert werden", + "FrmSettings._AfterEditingAction": "Nach dem Öffnen der App", + "FrmSettings._ShouldUseColorProfileForAll": "Auch für Bilder ohne eingebettetes Farbprofil anwenden", + "FrmCropSettings.DefaultSelectionType._UseTheLastSelection": "Letzte Auswahl verwenden", + "FrmSettings._SlideshowInterval._From": "Von", + "FrmSettings._ImageInterpolation": "Bildinterpolation", + "FrmQuickSetup._StepInfo": "Schritt {0}", + "FrmMain.MnuColorPicker": "Farbpipette", + "FrmCrop.SelectionAspectRatio._FreeRatio": "Freies Verhältnis", + "FrmSettings._ResetSettings": "Einstellungen zurücksetzen", + "FrmSettings._Startup": "Beim Start", + "_.BackdropStyle._None": "Kein", + "FrmSettings._LoadDefaultZoomLevels": "Standard-Zoomstufen laden", + "FrmColorPicker.BtnSettings._Tooltip": "Farbwähler Einstellungen öffnen...", + "FrmSettings._UseThemeForDarkMode": "Dieses Theme für den dunklen Modus verwenden", + "FrmSettings._ShowDeleteConfirmation": "Bestätigungsdialog beim Löschen von Dateien anzeigen", + "FrmSettings._ShowAppIcon": "Das Anwendungssymbol in der Titelleiste anzeigen", + "_._InvalidAction": "Ungültige Aktion", + "FrmQuickSetup._SelectProfile": "Ein Profil auswählen", + "_.Metadata._FileCreationTime": "Erstelldatum", + "FrmSettings._SlideshowImagesToNotifySound": "Anzahl der Bilder, die einen Benachrichtigungston auslösen", + "FrmSettings._BackgroundColor": "Hintergrundfarbe des Betrachters", + "FrmSettings._RealTimeFileUpdate": "Echtzeit-Aktualisierung der Dateien", + "_.ColorProfileOption._CurrentMonitorProfile": "Aktuelles Monitorprofil", + "FrmSettings._EnableCutMultipleFiles": "Aktiviere das Schneiden mehrerer Dateien auf einmal", + "FrmSettings._AutoUpdate": "Automatisch nach Aktualisierungen suchen", + "FrmCropSettings.LblDefaultSelection": "Standardauswahl", + "FrmSettings._UseThemeForLightMode": "Dieses Theme für den hellen Modus verwenden", + "FrmSettings._ZoomLevels": "Zoomstufe", + "FrmMain.MnuSetLockScreen._Success": "Das Hintergrundbild des Sperrbildschirms wurde aktualisiert.", + "FrmSettings._ShowGalleryFileName": "Vorschaubild-Dateiname anzeigen", + "FrmSettings.Layout._Order": "Sortierung", + "FrmCropSettings.ChkAutoCenterSelection": "Auswahl automatisch zentrieren", + "FrmSettings.Nav._FileTypeAssociations": "Dateityp-Verknüpfungen", + "_._Back": "Zurück", + "FrmMain.MnuSetDesktopBackground._Success": "Der Desktop-Hintergrund wurde aktualisiert.", + "FrmSettings._ShouldAutoOpenNewAddedImage": "Das neu hinzugefügte Bild automatisch öffnen", + "FrmCrop.SelectionAspectRatio._Custom": "Benutzerdefiniert…", + "FrmMain.MnuCopyPath._Success": "Kopierte den aktuellen Bildpfad.", + "FrmSettings._StartupBoost._Error": "Start-Boost-Einstellung konnte nicht geändert werden", + "FrmToolNotFound.LblDescription": "ImageGlass konnte den Pfad zur ausführbaren Datei '{0}' nicht finden. Um dieses Problem zu beheben, aktualisieren Sie bitte den Pfad zu '{0}'.", + "FrmMain.MnuClearClipboard": "Zwischenablage leeren", + "FrmSettings._ColorManagement": "Farbmanagement", + "FrmMain._ReachedLastLast": "Letztes Bild erreicht", + "FrmMain.MnuPanUp": "Bildausschnitt nach oben schieben", + "FrmMain.MnuRemoveDefaultPhotoViewer._Success": "ImageGlass ist nicht mehr der Standard-Bildbetrachter.", + "FrmSettings._GetMoreLanguagePacks": "Mehr Sprachpakete erhalten…", + "FrmAbout._Privacy": "Datenschutzrichtlinie", + "FrmSettings._EnableRecursiveLoading": "Bilder in Unterordner laden", + "_._UserAction._MethodArgumentNotSupported": "Der Argumenttyp der Methode '{0}' wird nicht unterstützt", + "FrmSettings._FileExtensionIcons._Description": "Um die Icons der Dateiendung anzupassen, laden Sie ein Icon-Paket herunter, legen Sie alle .ICO-Dateien in den Ordner der Endung und klicken Sie auf die '{0}' Schaltfläche. Dies setzt ImageGlass als Standard-Bildbetrachter.", + "_.ImageOrderType._Asc": "Aufsteigend", + "FrmExportFrames._Title": "Einzelbilder exportieren", + "_._Install": "Installieren…", + "FrmMain.MnuFlipHorizontal": "Horizontal spiegeln", + "FrmSettings._OpenExtensionIconFolder": "Erweiterungs-Icon-Ordner öffnen", + "FrmAbout._Collaborator": "Mitarbeiter:", + "FrmQuickSetup._ConfirmCloseProcess": "Vor der Anwendung der neuen Einstellungen müssen alle ImageGlass Prozesse geschlossen werden. Sind Sie bereit fortzufahren?", + "FrmExportFrames._ExportDone": "{0} Einzelbilder erfolgreich exportiert nach \n{1}", + "FrmCrop.BtnSaveAs._Tooltip": "Als Kopie speichern...", + "FrmMain.MnuOpenFile": "Datei öffnen…", + "FrmColorPickerSettings.ChkShowRgbA": "RGB-Format mit Alpha-Wert verwenden", + "_.ImageInfo._ListCount": "{0} Datei(en)", + "FrmMain.MnuGoToLast": "Zum letzten Bild gehen", + "FrmSettings._EditApps._AppName": "Programmname", + "FrmSettings._SlideshowBackgroundColor": "Diashow Hintergrundfarbe", + "FrmAbout._Email": "E-Mail:", + "_.MouseWheelAction._DoNothing": "Nichts tun", + "FrmMain.MnuSaveAs": "Speichern als…", + "FrmMain._Loading": "Wird geladen …", + "_._Browse": "Durchsuchen…", + "FrmMain.MnuSetDefaultPhotoViewer._Error": "ImageGlass konnte nicht als Standard-Bildbetrachter gesetzt werden.", + "FrmSettings.Nav._Language": "Sprache", + "FrmQuickSetup._SeeWhatNew": "Sehen Sie, was in dieser Version neu ist…", + "FrmSettings._ImageInterpolation._ScaleUp": "Bei Zoom > 100%", + "FrmSettings.Layout._ToolbarContextPosition": "Position der Kontextuellen Werkzeugleiste", + "FrmMain.MnuDeleteFromHardDisk": "Permanent löschen", + "FrmSettings._EmbeddedThumbnail": "Eingebettetes Miniaturbild", + "FrmMain.MnuDeleteFromHardDisk._Description": "Sind Sie sicher, dass Sie die Datei dauerhaft löschen möchten?", + "FrmMain.MnuScaleToFill": "Bild auf Fenstergröße skalieren", + "FrmCrop.BtnCrop": "Zuschneiden", + "_.AfterEditAppAction._Minimize": "Minimieren", + "FrmMain.MnuInvertColors": "Farben umkehren", + "FrmSettings._StartupBoost": "Start-Boost", + "FrmMain.MnuViewFirstFrame": "Erstes Bild anzeigen", + "_.MouseWheelEvent._CtrlAndScroll": "Strg halten und scrollen", + "FrmSettings._HideMainWindowInSlideshow": "Hauptfenster automatisch ausblenden", + "_.Metadata._FrameCount": "Bilder", + "FrmSettings._EnableCopyMultipleFiles": "Aktiviere das Kopieren mehrerer Dateien auf einmal", + "FrmMain.MnuFrameless._EnableDescription": "Halten Sie die Umschalt-Taste gedrückt, um das Fenster zu verschieben.", + "_.ImageOrderBy._ExifDateTaken": "EXIF: Datum der Aufnahme", + "FrmAbout._Credits": "Mitwirkende", + "FrmSettings._AddNewFileExtension": "Neue Dateiendung hinzufügen", + "FrmMain.MnuQuickSetup": "Imageglass Schnelleinstellungen öffnen", + "FrmMain.MnuSave._Success": "Bild ist gespeichert", + "FrmMain.MnuPanLeft": "Bildausschnitt nach links schieben", + "FrmUpdate._StatusChecking": "Überprüfe auf Updates…", + "FrmSettings.Nav._Layout": "Ansicht", + "FrmMain.MnuOpenWith": "Öffnen mit…", + "FrmAbout._Thanks": "Besonderen Dank an:", + "_._Warning": "Warnung", + "FrmSettings.Nav._Keyboard": "Tastatur", + "FrmSlideshow._PauseSlideshow": "Diashow ist pausiert.", + "_._Add+": "Hinzufügen…", + "_._Email": "E-Mail", + "FrmMain.MnuPanDown": "Bildausschnitt nach unten schieben", + "_._Cancel": "Abbrechen", + "_._OK": "OK", + "FrmMain.MnuPanRight": "Bildausschnitt nach rechts schieben", + "_.Position._Right": "Rechts", + "_._Icon": "Icon", + "FrmSettings._ShouldLoadHiddenImages": "Ausgeblendete Bilder laden", + "_._InvalidAction._Transformation": "ImageGlass unterstützt Drehen und Spiegeln für dieses Bild nicht.", + "FrmSettings._MakeDefault": "Als Standard festlegen", + "FrmMain.MnuCopyImageData._Copying": "Kopieren der Bilddaten... Dies wird einige Zeit in Anspruch nehmen…", + "FrmSettings._UseEmbeddedThumbnailRawFormats": "Bei RAW-Formaten nur das eingebettete Miniaturbild laden", + "_.ImageInterpolation._Linear": "Linear", + "FrmSettings._ImageInfoTags": "Bildinformations-Tags", + "FrmSettings._FileExtensionIcons": "Icons für Dateiendung", + "FrmMain.MnuEdit._AppNotFound": "Die zugehörige App zum Bearbeiten konnte nicht gefunden werden. Sie können eine App zum Bearbeiten dieses Formats unter ImageGlass Einstellungen > Bearbeiten zuweisen.", + "_.ColorProfileOption._None": "Kein", + "FrmSettings._TotalSupportedFormats": "Insgesamt unterstützte Formate: {0}", + "FrmSettings._Clipboard": "Zwischenablage", + "_._UserAction._Win32ExeError": "Befehl '{0} ' kann nicht ausgeführt werden. Stellen Sie sicher, dass der Name korrekt ist.", + "FrmCropSettings.DefaultSelectionType._SelectX": "Wählen Sie {0}", + "_.AfterEditAppAction._Close": "Schließen", + "FrmAbout._LogoDesigner": "Logo Designer:", + "_.ImageOrderBy._Name": "Name (Standard)", + "FrmMain.MnuRemoveDefaultPhotoViewer._Error": "ImageGlass konnte nicht als Standard-Bildbetrachter entfernt werden.", + "FrmExportFrames._FolderPickerTitle": "Ausgabeordner auswählen für den Export der Einzelbilder", + "FrmAbout._Donate": "Spenden", + "FrmMain.MnuFrameNav": "Bild-Navigation", + "FrmMain.MnuSetLockScreen": "Als Sperrbildschirm festlegen", + "_._Delete": "Löschen", + "FrmMain.MnuViewPrevious": "Vorheriges Bild anzeigen", + "_.Position._Top": "Oben", + "FrmSettings.Toolbar._CurrentButtons": "Aktuelle Schaltflächen:", + "FrmMain.MnuAbout": "Über", + "FrmSettings._RemoveDefault": "Standard entfernen", + "_._Description": "Beschreibung", + "FrmMain.MnuPasteImage._Error": "Konnte die Bilddaten in der Zwischenablage nicht finden", + "FrmMain.MnuSettings": "Einstellungen", + "FrmCropSettings._Title": "Zuschneide-Einstellungen", + "FrmSettings.Toolbar._ToolbarIconHeight": "Symbolleiste Symbolgröße", + "FrmSettings._SlideshowInterval._To": "Bis", + "FrmSettings.Layout._ToolbarPosition": "Symbolleistenposition", + "FrmUpdate._StatusUpdated": "Sie benutzen die aktuellste Version.", + "FrmMain.MnuExit": "Beenden", + "_._Webview2._Outdated": "Ihre WebView2 Laufzeit wird nicht unterstützt. Bitte aktualisieren Sie auf Version {0} oder höher.", + "_._Yes": "Ja", + "FrmMain.MnuRotateLeft": "Nach links drehen", + "FrmSettings._EnableStartupBoost": "Start-Boost aktivieren", + "_.ImageOrderBy._ExifRating": "EXIF: Bewertung", + "FrmMain.MnuZoomIn": "Vergrößern", + "_.Metadata._ColorSpace": "Farbraum", + "FrmAbout._Version": "Version:", + "FrmMain.MnuToggleTopMost._Enable": "Aktiviertes Fenster immer oben", + "FrmSettings.Toolbar._AvailableButtons": "Verfügbare Schaltflächen:", + "FrmMain.MnuSave._Saving": "Speichere Bild…", + "FrmQuickSetup._StandardUser": "Standard Benutzer", + "FrmMain.MnuSetLockScreen._Error": "Das angezeigte Bild konnte nicht als Hintergrundbild für den Sperrbildschirm eingerichtet werden.", + "FrmSettings.Nav._Image": "Bild", + "FrmSettings._Theme._InstallTheme": "Theme-Pakete installieren", + "FrmSettings._EnableMultiInstances": "Mehrere Programminstanzen erlauben", + "FrmMain.MnuCropTool": "Bild zuschneiden", + "_._IgCommandExe._DefaultError._Heading": "Ungültige Befehle", + "_._Refresh": "Aktualisieren", + "FrmMain.MnuLosslessCompression._Description": "Dieses Tool verwendet die Magick.NET Bibliothek für verlustfreie Komprimierung, um die Dateigröße zu optimieren. Überschreibt nur, wenn die komprimierte Datei kleiner als das Original ist.", + "_._MoveDown": "Nach unten bewegen", + "FrmSettings._GetExtensionIconPacks": "Erweiterungs-Icon-Pakete erhalten...", + "FrmSettings._InAppMessageDuration": "Dauer der In-App-Nachricht (Millisekunden)", + "FrmMain.MnuFrameless": "Rahmenlos", + "_._Reset": "Zurücksetzen", + "FrmSettings._ConfigDir": "Standort der Konfiguration", + "FrmQuickSetup._SettingsWillBeApplied": "Einstellungen angewendet:", + "FrmSettings._UnmanagedSettingReminder": "Diese Einstellung wird nicht von ImageGlass verwaltet. Vergessen Sie nicht, es zu deaktivieren, bevor Sie die Anwendung entfernen oder verlagern, da ImageGlass dies nicht automatisch erledigt.", + "FrmMain.MnuClipboard": "Zwischenablage", + "FrmMain.MnuCustomZoom": "Eigener Zoom…", + "FrmSettings._DisplayLanguage": "Anzeigesprache", + "FrmMain.MnuPrint._Error": "Das Bild konnte nicht gedruckt werden", + "FrmSettings._ShouldPreserveModifiedDate": "Das geänderte Datum des Bildes beim Speichern beibehalten", + "FrmSettings._ShowSaveOverrideConfirmation": "Bestätigungsdialog beim Überschreiben einer Datei anzeigen", + "FrmColorPickerSettings.ChkShowHexA": "HEX-Format mit Alpha-Wert verwenden", + "FrmMain.MnuFullScreen": "Vollbild", + "FrmSettings._StartupDir": "Startort", + "FrmSettings._ShowCheckerboardOnlyImageRegion": "Schachbrett nur innerhalb des Bildbereichs anzeigen", + "FrmMain.MnuClearClipboard._Success": "Zwischenablage geleert.", + "FrmQuickSetup._Text": "ImageGlass Schnelleinstellung", + "FrmMain.MnuLosslessCompression._Done": "Komprimierung ohne Verlust durchgeführt.\r\nDie neue Dateigröße ist {0}, gespeichert {1}.", + "FrmMain.MnuLosslessCompression": "Magick.NET verlustfreie Kompression", + "FrmResize.RadResizeByPercentage": "Prozent", + "FrmSettings._StartupBoost._Disabled": "Start-Boost ist deaktiviert", + "FrmMain.MnuToggleCheckerboard": "Schachbrett-Hintergrund", + "FrmSettings._MinEmbeddedThumbnailSize._Height": "Höhe", + "FrmSettings.Nav._General": "Allgemein", + "FrmSettings._ImageLoading": "Bild lädt", + "FrmSettings._ShowSlideshowCountdown": "Zeige Diashow-Countdown", + "FrmMain.MnuSave": "Speichern", + "FrmMain.MnuMoveToRecycleBin": "In den Papierkorb verschieben", + "FrmMain.MnuRefresh": "Aktualisieren", + "FrmToolNotFound.LblHeading": "'{0}' wurde nicht gefunden!", + "FrmMain.MnuReportIssue": "Einen Fehler melden…", + "FrmMain.MnuCopyImageData": "Bildinformationen kopieren", + "FrmMain.MnuCheckForUpdate._NewVersion": "Eine neue Version ist verfügbar!", + "_._Empty": "(Leer)", + "FrmSettings._Zooming": "Vergrößern", + "FrmMain.MnuCutFile": "Datei ausschneiden", + "FrmHotkeyPicker.LblHotkey": "Tastaturkürzel drücken", + "FrmSettings.Layout._Gallery": "Galerie", + "FrmMain.MnuNewWindow": "Neues Fenster öffnen", + "FrmMain.MnuMoveToRecycleBin._Description": "Möchten Sie diese Datei in den Papierkorb verschieben?", + "FrmSettings._DefaultPhotoViewer": "Standard Bildbetrachter", + "_.Metadata._ExifDateTimeOriginal": "EXIF: DateTimeOriginal", + "FrmMain.MnuRotateRight": "Nach rechts drehen", + "FrmSettings._MinEmbeddedThumbnailSize": "Mindestgröße des zu ladenden eingebetteten Miniaturbildes", + "FrmMain.MnuSetDefaultPhotoViewer": "Standard-Bildbetrachter festlegen", + "FrmMain.MnuImageProperties": "Bildeigenschaften", + "FrmSettings._EnableNavigationButtons": "Navigationspfeiltasten anzeigen", + "_._Edit": "Bearbeiten", + "FrmSettings._ImageBooster": "Bild-Booster", + "FrmSettings.Tools._IntegratedWith": "Integriert mit {0}", + "_._Next": "Weiter", + "FrmExportFrames._OpenOutputFolder": "Ausgabeordner öffnen", + "FrmMain.MnuOpenLocation": "Bildpfad öffnen", + "FrmMain.MnuLockZoom": "Seitenverhältnis beibehalten", + "FrmSettings._StartupBoost._Description": "Laden Sie ImageGlass vor und lassen Sie es während des Windows-Starts einige Sekunden lang im Hintergrund laufen, um den ersten Start zu beschleunigen.", + "FrmSettings._WindowBackdrop": "Fensterhintergrund", + "FrmSettings._EnableRealTimeFileUpdate": "Dateiänderungen im Ansichtsordner überwachen und in Echtzeit aktualisieren", + "_._NotSupported": "Nicht unterstütztes Format", + "FrmSettings._Theme._GetMoreThemes": "Weitere Theme-Pakete erhalten…", + "FrmMain.MnuNewWindow._Error": "Neues Fenster kann nicht geöffnet werden, da nur eine Instanz erlaubt ist", + "FrmMain.MnuZoomOut": "Verkleinern", + "FrmSettings.Toolbar._EditButton": "Werkzeugleisten-Taste bearbeiten", + "FrmMain.MnuCustomZoom._Description": "Neuen Zoomwert eingeben", + "FrmResize.RadResizeByPixels": "Pixel", + "FrmMain.MnuEdit": "Bild {0} bearbeiten…", + "FrmSettings.Layout._GalleryPosition": "Position der Galerie", + "FrmMain.MnuWindowFit": "Fenster anpassen", + "FrmMain._OpenFileDialog": "Alle unterstützten Dateitypen", + "FrmSettings._UseRandomIntervalForSlideshow": "Zufallsintervall verwenden", + "_.Position._Left": "Links", + "FrmSettings._ShouldOpenLastSeenImage": "Das zuletzt betrachtete Bild öffnen", + "_.Position._Bottom": "Unten", + "FrmResize.ChkKeepRatio": "Verhältnis beibehalten", + "FrmMain.MnuGoTo": "Gehe zu…", + "FrmSlideshow.MnuPauseResumeSlideshow": "Diashow pausieren/fortsetzen", + "FrmSettings.Tools._Integrated": "Integriert", + "FrmSettings._Contributors": "Mitwirkende", + "_.MouseWheelAction._Zoom": "Vergrößern / Verkleinern", + "_._CommandPreview": "Befehlsvorschau", + "FrmSettings._DarkTheme": "Dunkel", + "_._Hotkeys": "Tastaturkürzel", + "_.Metadata._ExifDateTime": "EXIF: DateTime", + "FrmSettings.Toolbar._Errors._ButtonIdRequired": "Schaltflächen ID erforderlich.", + "FrmSettings._MinEmbeddedThumbnailSize._Width": "Breite", + "_._Executable": "Ausführbar", + "_.ImageInterpolation._MultiSampleLinear": "Multisample-Linear", + "_._Separator": "Separator", + "FrmQuickSetup._ProfessionalUser": "Professioneller Benutzer", + "FrmMain.MnuFlipVertical": "Vertikal spiegeln", + "FrmSlideshow._ResumeSlideshow": "Diashow wird fortgesetzt.", + "FrmCropSettings.DefaultSelectionType._CustomArea": "Benutzerdefinierter Bereich...", + "FrmMain.MnuActualSize": "Originalgröße", + "FrmCrop.BtnSaveAs": "Speichern als…", + "FrmSettings._InstallNewLanguagePack": "Neue Sprachpakete installieren…", + "FrmSlideshow.MnuZoomModes": "Zoom-Modus", + "FrmMain.MnuTools": "Extras", + "_.ImageInterpolation._Cubic": "Kubisch", + "FrmUpdate._LatestVersion": "Die neueste Version: {0}", + "FrmMain.MnuViewNext": "Nächstes Bild anzeigen", + "_.MouseWheelEvent._AltAndScroll": "Alt halten und scrollen", + "FrmToolNotFound._Title": "Tool nicht gefunden", + "FrmCrop.BtnCrop._Tooltip": "Nur das Bild zuschneiden", + "FrmSettings.EditAppDialog._AddApp": "App zum Bearbeiten hinzufügen", + "FrmMain.MnuPanning": "Schwenken", + "_._MoveUp": "Nach oben bewegen", + "FrmCropSettings.DefaultSelectionType._SelectAll": "Alles auswählen", + "_._Name": "Name", + "FrmColorPickerSettings.ChkShowHslA": "HSL-Format mit Alpha-Wert verwenden", + "FrmMain.MnuToggleImageAnimation": "Bildanimation starten / stoppen", + "FrmSettings._DisableStartupBoost": "Start-Boost deaktivieren", + "FrmMain.MnuCopyFile._Success": "{0} Datei(en) kopiert.", + "FrmMain.MnuSave._ConfirmDescription": "ImageGlass ist kein professionelles Bildbearbeitungsprogramm. Bitte beachten Sie, dass Qualität, Metadaten, Ebenen u.a. beim Speichern des Bildes verloren gehen können.", + "FrmToolNotFound.BtnSelectExecutable": "Wählen Sie…", + "FrmUpdate._StatusOutdated": "Eine neue Version ist verfügbar!", + "_.ImageOrderBy._Random": "Zufällig", + "FrmResize.LblCurrentSize": "Aktuelle Größe:", + "_._Apply": "Übernehmen", + "FrmAbout._Slogan": "Ein schlanker, vielseitiger Bildbetrachter", + "FrmMain.MnuPanToTop": "Bildausschnitt zum oberen Rand schieben", + "FrmSettings.Toolbar._AddNewButton": "Eigene Wekrzeitleisten-Taste hinzufügen", + "FrmCrop.LblSize": "Größe:", + "FrmSettings._ImageInterpolation._ScaleDown": "Wenn Zoom < 100%", + "_._CreatingFileError": "Konnte temporäre Bilddatei nicht erstellen", + "FrmMain.MnuGoTo._Description": "Geben Sie den anzuzeigenden Bildindex ein und drücken Sie dann ENTER", + "FrmSettings.Toolbar._EnableCenterToolbar": "Zentrierte Ausrichtung für die Werkzeugleiste verwenden", + "FrmMain.MnuResizeTool": "Bildgröße ändern", + "FrmSettings.Layout._Toolbar": "Symbolleiste", + "FrmMain.MnuHelp": "Hilfe", + "_.ImageOrderBy._FileSize": "Dateigröße", + "FrmSettings._Theme._OpenThemeFolder": "Theme-Ordner öffnen", + "FrmMain.MnuNavigation": "Navigation", + "_._Save": "Speichern", + "FrmQuickSetup._SettingProfileDescription": "Um diese Einstellungen zu ändern, greifen Sie einfach in die App-Einstellungen.", + "_._UserAction._MenuNotFound": "Menü '{0}' zum Aufruf der Aktion nicht gefunden", + "FrmMain.MnuPanToLeftSide": "Bildausschnitt zum linken Rand schieben", + "FrmUpdate._CurrentVersion": "Aktuelle Version: {0}", + "FrmCrop.BtnSettings._Tooltip": "Zuschneiden Einstellungen öffnen", + "_.ColorProfileOption._Custom": "Benutzerdefiniert…", + "FrmSettings._UseEmbeddedThumbnailOtherFormats": "Bei anderen Formaten nur das eingebettete Miniaturbild laden", + "FrmMain.MnuGoToFirst": "Zum ersten Bild gehen", + "FrmSettings._ExportLanguagePack": "Sprachpaket exportieren…", + "FrmSettings.Nav._Mouse": "Maus", + "_.ImageOrderBy._DateCreated": "Erstelldatum", + "FrmSettings._EnableFullscreenSlideshow": "Diashow im Vollbildmodus starten", + "FrmAbout._Homepage": "Homepage:", + "FrmSettings._GalleryCacheSizeInMb": "Maximale Größe des Galerie-Cache (in Megabytes)", + "FrmMain.MnuCopyImageData._Success": "Aktuelle Bilddaten wurden kopiert.", + "FrmSettings._EnableLoopBackNavigation": "Zurück zum ersten Bild, wenn das Ende der Bildliste erreicht ist", + "_.MouseWheelEvent._Scroll": "Scrollen", + "FrmCrop.BtnSave._Tooltip": "Bild speichern", + "FrmMain.MnuSlideshow": "Diashow", + "FrmMain.MnuShare": "Teilen…", + "FrmSettings._SlideshowNotification": "Diashow Benachrichtigung", + "FrmMain.MnuViewChannels": "Kanäle anzeigen", + "FrmSettings._Refresh": "Aktualisieren", + "_._UserAction._MethodNotFound": "Kann keine Methode '{0}' zum Aufruf der Aktion finden", + "FrmMain.MnuCopyFile": "Datei kopieren", + "_._CreatingFile": "Erstellen einer temporären Bilddatei…", + "FrmMain.MnuToggleTopMost": "Fenster immer im Vordergrund halten", + "FrmMain.MnuLosslessCompression._Confirm": "Sind Sie sicher, dass Sie fortfahren wollen?", + "FrmMain.MnuImage": "Bild", + "FrmSettings._StartupBoost._Enabled": "Start-Boost ist aktiviert", + "FrmQuickSetup._SetDefaultViewer": "Möchten Sie ImageGlass als Standard-Bildbetrachter festlegen?", + "FrmMain.MnuScaleToWidth": "Auf Breite skalieren", + "_._FileExtension": "Dateierweiterung", + "FrmUpdate._PublishedDate": "Veröffentlichtes Datum: {0}", + "_._DoNotShowThisMessageAgain": "Diese Nachricht nicht mehr anzeigen", + "_.ImageInterpolation._NearestNeighbor": "Nächster Nachbar", + "FrmCrop.LblLocation": "Ort:", + "_._Download": "Herunterladen", + "_.Metadata._ColorProfile": "Farbprofil", + "FrmSettings._CenterWindowFit": "Automatisch zentrieren des Fensters im Fenster-Anpassungsmodus", + "FrmSettings._ImageLoadingOrder": "Bildersortierung beim Laden", + "FrmSettings._GalleryColumns": "Anzahl der Vorschaubilder im vertikalen Galerielayout", + "_._Quit": "Beenden", + "_._Add": "Hinzufügen", + "FrmMain.MnuChangeBackgroundColor": "Hintergrundfarbe ändern...", + "FrmMain.MnuToggleToolbar": "Symbolleiste", + "FrmAbout._Contact": "Kontakt", + "FrmSettings.Toolbar._AddCustomButton": "Eigene Schaltfläche hinzufügen...", + "FrmCrop.BtnQuickSelect._Tooltip": "Schnellauswahl…", + "FrmMain.MnuCutFile._Success": "{0} Datei(en) schneiden.", + "FrmSettings._ZoomSpeed": "Zoomgeschwindigkeit", + "FrmMain.MnuToggleTopMost._Disable": "Fenster immer oben deaktiviert", + "FrmSettings._ShouldUseExplorerSortOrder": "Explorer-Sortierreihenfolge verwenden, wenn möglich", + "_.ImageInterpolation._Antisotropic": "Antisotropisch", + "FrmMain._ReachedFirstImage": "Erstes Bild erreicht", + "_._UnhandledException": "Unbehandelte Ausnahme", + "FrmResize.LblNewSize": "Neue Größe:", + "FrmMain._ClipboardImage": "Zwischenablage Bild", + "FrmMain.MnuExportFrames": "Einzelbilder exportieren…", + "FrmMain.MnuFile": "Datei", + "_._Close": "Schließen", + "FrmMain.MnuMain": "Hauptmenü", + "_._ResetToDefault": "Auf Standard zurücksetzen", + "FrmSettings.Nav._Gallery": "Galerie", + "FrmMain.MnuSetDefaultPhotoViewer._Success": "Sie haben ImageGlass erfolgreich als Standard-Bildbetrachter festgelegt.", + "FrmSettings._HideGalleryInFullscreen": "Galerie im Vollbildmodus ausblenden", + "FrmSettings._AvailableImageInfoTags": "Verfügbare Tags:", + "FrmExportFrames._Exporting": "Exportiere {0}/{1} Einzelbilder \n{2}…", + "_._Argument": "Argument", + "FrmSettings._ImageEditQuality": "Bildqualität", + "_._ID": "ID", + "FrmSettings._UserConfigFile": "Benutzereinstellungen (igconfig.json)", + "FrmMain.MnuLoadingOrders": "Ladereihenfolge", + "FrmSettings._OpenSaveAsDialogInTheCurrentImageDir": "Öffnen Sie den Dialog \"Speichern unter\" im aktuellen Bildverzeichnis", + "_.MouseWheelEvent._ShiftAndScroll": "Shift halten und scrollen", + "FrmSettings._UseSmoothZooming": "Glattes Zoomen verwenden", + "FrmSettings._Theme": "Thema", + "FrmSettings._ImageBoosterCacheMaxDimension": "Maximale Bildgröße, die zwischengespeichert werden soll (in Pixel)", + "FrmMain.MnuScaleToHeight": "Auf Höhe skalieren", + "_.Metadata._FileLastWriteTime": "Änderungsdatum", + "FrmSettings._Author": "Autor", + "FrmSettings._Others": "Andere", + "_.MouseWheelAction._PanVertically": "Nach oben / unten", + "FrmSettings._MouseWheelAction": "Mausrad Aktion", + "FrmSettings.Nav._Tools": "Extras", + "FrmMain.MnuSetDesktopBackground._Error": "Das angezeigte Bild konnte nicht als Desktop-Hintergrund eingerichtet werden.", + "FrmSettings.Toolbar._Errors._ButtonExecutableRequired": "Schaltflächen-Programmdatei erforderlich.", + "_.ImageOrderBy._DateAccessed": "Zugriffsdatum", + "FrmSettings._ThumbnailSize": "Größe der Vorschaubilder (in Pixeln)", + "FrmSettings._FileFormats": "Dateiformate", + "FrmMain.MnuReloadImageList": "Bildliste neu laden", + "FrmSettings._UseWebview2ForSvg": "Webview2 zum Anzeigen des SVG-Formats verwenden", + "FrmCrop.BtnCopy": "Kopieren", + "FrmSettings._CurrentMonitorProfile._Description": "ImageGlass aktualisiert die Farbe nicht automatisch, wenn das Fenster zwischen Monitoren verschoben wird", + "FrmMain.PicMain._ErrorText": "Bild konnte nicht geöffnet werden", + "FrmSettings.Tools._AddNewTool": "Ein externes Werkzeug hinzufügen", + "FrmMain.MnuRename": "Bild umbenennen…", + "FrmMain.MnuViewLastFrame": "Letztes Bild anzeigen", + "_._Webview2._NotFound": "Bitte installieren Sie die neueste Version von WebView2 Runtime.", + "FrmMain.MnuGetMoreTools": "Weitere Tools erhalten…", + "FrmSettings.Nav._Appearance": "Darstellung", + "FrmSettings._SlideshowInterval": "Diashow-Intervall:", + "_.ImageInterpolation._HighQualityBicubic": "Hohe Qualität bikubisch", + "FrmColorPickerSettings.ChkShowHsvA": "HSV-Format mit Alpha-Wert verwenden", + "FrmSettings.Tools._EditTool": "Externes Werkzeug bearbeiten", + "_._Error": "Fehler", + "FrmSettings._ImageBoosterCacheMaxFileSizeInMb": "Maximale Größe der Bilddatei, die zwischengespeichert werden soll (in Megabyte)", + "_._UnhandledException._Description": "Unbehandelte Ausnahme ist aufgetreten. Wenn Sie auf Weiter klicken, wird die Anwendung diesen Fehler ignorieren und versuchen fortzufahren. Wenn Sie auf Beenden klicken, wird die Anwendung sofort geschlossen.", + "_.Metadata._FileSize": "Dateigröße", + "FrmSettings.Toolbar._ButtonJson": "Schaltfläche JSON", + "FrmQuickSetup._SetDefaultViewer._Description": "Sie können es in den App-Einstellungen > Dateityp Assoziationen Tab zurücksetzen.", + "FrmSettings.Nav._Edit": "Bearbeiten", + "FrmMain.MnuToggleGallery": "Galerie-Schaubild", + "_._IgCommandExe._DefaultError._Description": "Stellen Sie sicher, dass Sie die richtigen Befehle übergeben!\r\nDiese Datei enthält Kommandozeilenfunktionen für ImageGlass Software.\r\n\r\nUm alle Kommandozeilen zu erkunden, besuchen Sie bitte:\n{0}", + "FrmMain.MnuLosslessCompression._Compressing": "Verlustfreie Komprimierung durchführen...", + "FrmSettings._ShouldGroupImagesByDirectory": "Bilder nach Verzeichnis gruppieren", + "FrmMain.MnuPanToRightSide": "Bildausschnitt zum rechten Rand schieben", + "_.Metadata._ExifRatingPercent": "Bewertung", + "FrmSettings._PanSpeed": "Schwenkgeschwindigkeit", + "_._CheckForUpdate": "Suche nach Aktualisierungen…", + "FrmSettings.Layout._ToolbarContext": "Kontextuelle Symbolleiste", + "_.ImageInfo._FrameCount": "{0} Bilder", + "FrmMain.MnuLayout": "Ansicht", + "_._Website": "Webseite", + "FrmMain.MnuPasteImage": "Bild einfügen", + "FrmSettings._ShowGalleryScrollbars": "Galerie-Scrollbars anzeigen" + } +} \ No newline at end of file diff --git a/Setup/Assets/Language/Greek.iglang.json b/Setup/Assets/Language/Greek.iglang.json new file mode 100644 index 000000000..df9c3ec46 --- /dev/null +++ b/Setup/Assets/Language/Greek.iglang.json @@ -0,0 +1,504 @@ +{ + "_Metadata": { + "Code": "el-GR", + "EnglishName": "Greek", + "LocalName": "Ελληνικά", + "Author": "Theodoros Asimakopoulos (theoasima@gmail.com), Retrial, Nikolas Spiridakis", + "MinVersion": "9.1" + }, + "Items": { + "FrmCrop.SelectionAspectRatio._Original": "Αρχική", + "FrmMain.MnuShare._Error": "Δεν ήταν δυνατό το άνοιγμα του πλαισίου διαλόγου κοινοποίησης.", + "_.Metadata._FileLastAccessTime": "Ημερομηνία πρόσβασης", + "FrmAbout._License": "Άδεια χρήσης λογισμικού", + "FrmSettings.Toolbar._Errors._ButtonIdDuplicated": "Ένα κουμπί με το αναγνωριστικό \"{0}\" έχει ήδη οριστεί. Παρακαλώ επιλέξτε ένα διαφορετικό και μοναδικό αναγνωριστικό για το κουμπί σας για αποφυγή διενέξεων.", + "FrmMain.MnuSave._Confirm": "Είστε βέβαιοι ότι θέλετε να αντικαταστήσετε αυτήν την εικόνα;", + "FrmSettings._OpenDefaultAppsSetting": "Ανοίξτε τη ρύθμιση προεπιλεγμένων εφαρμογών", + "FrmMain.MnuCopyPath": "Αντιγραφή διαδρομής εικόνας", + "FrmCropSettings.DefaultSelectionType._SelectNone": "Επιλογή κανενός", + "_.MouseWheelAction._PanHorizontally": "Μετατόπιση αριστερά / δεξιά", + "FrmMain.MnuPrint": "Εκτύπωση…", + "FrmSettings.Toolbar._ToolbarButtons": "Κουμπιά γραμμής εργαλείων", + "FrmResize.LblResample": "Επαναδειγματοληψία:", + "_.ImageOrderBy._Extension": "Επέκταση", + "FrmSettings.Nav._Viewer": "Πρόγραμμα προβολής", + "FrmSettings.EditAppDialog._EditApp": "Εφαρμογή επεξεργασίας", + "FrmCrop.BtnReset._Tooltip": "Επαναφορά επιλογής", + "FrmMain.MnuRename._Description": "Εισάγετε ένα νέο όνομα αρχείου:", + "_._No": "'Οχι", + "FrmSlideshow.MnuToggleCountdown": "Εμφάνιση αντίστροφης μέτρησης προβολής παρουσίασης", + "FrmSettings._OpenStartupAppsSetting": "Ανοίξτε τη ρύθμιση εφαρμογών εκκίνησης", + "FrmMain.MnuViewPreviousFrame": "Προβολή προηγούμενου καρέ", + "_.ImageOrderBy._DateModified": "Ημερομηνία τροποποίησης", + "FrmMain.MnuViewNextFrame": "Προβολή επόμενου καρέ", + "FrmMain.MnuUnload": "Αποφόρτωση εικόνας", + "FrmSettings.Toolbar._HideToolbarInFullscreen": "Απόκρυψη γραμμής εργαλείων σε λειτουργία πλήρους οθόνης", + "_.ImageOrderType._Desc": "Φθίνουσα", + "_._Update": "Ενημέρωση", + "FrmSettings._EnableImageAsyncLoading": "Ενεργοποίηση ασύγχρονης φόρτωσης εικόνας", + "FrmSettings._DefaultPhotoViewer._Description": "Καταχωρίστε τις υποστηριζόμενες μορφές του ImageGlass στα Windows. Ίσως χρειαστεί να ανοίξετε τις ρυθμίσεις Προεπιλεγμένων εφαρμογών και να επιλέξετε χειροκίνητα το ImageGlass από τη λίστα για να τεθεί σε ισχύ.", + "_.MouseWheelAction._BrowseImages": "Προβολή επόμενης / προηγούμενης εικόνας", + "FrmSettings._EditApps": "Εφαρμογές επεξεργασίας εικόνων", + "FrmColorPickerSettings.ChkShowCIELabA": "Χρήση μορφής CIELAB με τιμή άλφα", + "_._GetHelp": "Λήψη βοήθειας", + "FrmQuickSetup._SkipQuickSetup": "Παράλειψη αυτού και εκκίνηση του ImageGlass", + "FrmColorPickerSettings._Title": "Ρυθμίσεις επιλογέα χρώματος", + "_._Copy": "Αντιγραφή", + "FrmSettings._ImageBoosterCacheCount": "Αριθμός εικόνων που αποθηκεύτηκαν προσωρινά από το Image Booster (μία κατεύθυνση)", + "FrmMain.MnuPanToBottom": "Μετατόπιση εικόνας προς τα κάτω", + "FrmMain.MnuZoom": "Ζουμ", + "FrmCropSettings.ChkCloseToolAfterSaving": "Κλείσιμο του εργαλείου περικοπής μετά την αποθήκευση", + "FrmSettings._ShowWelcomeImage": "Εμφάνιση εικόνας καλωσορίσματος", + "FrmSettings._ColorProfile": "Προφίλ χρωμάτων", + "FrmSettings._Theme._UninstallTheme": "Απεγκατάσταση πακέτου θέματος", + "FrmMain._OpenWith": "Άνοιγμα με {0}", + "FrmMain.MnuRemoveDefaultPhotoViewer": "Κατάργηση προεπιλεγμένου προγράμματος προβολής φωτογραφιών", + "_.AfterEditAppAction._Nothing": "Καμία ενέργεια", + "FrmCrop.BtnSave": "Αποθήκευση", + "FrmMain.MnuScaleToFit": "Προσαρμογή στο παράθυρο", + "FrmToolNotFound.LblDownloadToolText": "Μπορείτε να κάντε λήψη περισσότερων εργαλείων για το ImageGlass στη διεύθυνση:", + "_._LearnMore": "Μάθετε περισσότερα…", + "FrmCrop.LblAspectRatio": "Αναλογία διαστάσεων:", + "FrmExportFrames._FileNotExist": "Το αρχείο εικόνας δεν υπάρχει", + "FrmSettings._LightTheme": "Φωτεινό", + "FrmSettings.Nav._Slideshow": "Προβολή παρουσίασης", + "_._Continue": "Συνέχεια", + "_._AddHotkey": "Προσθήκη πλήκτρου πρόσβασης…", + "FrmMain.MnuSetDesktopBackground": "Ορισμός ως φόντο επιφάνειας εργασίας", + "FrmMain.MnuReload": "Επαναφόρτωση εικόνας", + "FrmSlideshow.MnuExitSlideshow": "Έξοδος από την προβολή παρουσίασης", + "FrmMain.MnuAutoZoom": "Αυτόματο ζουμ", + "FrmSettings._ShowImagePreview": "Εμφάνιση προεπισκόπησης εικόνας όσο φορτώνεται", + "FrmCrop.BtnCopy._Tooltip": "Αντιγραφή της επιλογής στο πρόχειρο", + "FrmSettings.Nav._Toolbar": "Γραμμή εργαλείων", + "FrmMain.MnuSave._Error": "Δεν ήταν δυνατή η αποθήκευση της εικόνας", + "FrmSettings._AfterEditingAction": "Μετά το άνοιγμα εφαρμογής επεξεργασίας", + "FrmSettings._ShouldUseColorProfileForAll": "Εφαρμογή και για εικόνες χωρίς ενσωματωμένο προφίλ χρωμάτων", + "FrmCropSettings.DefaultSelectionType._UseTheLastSelection": "Χρήση της τελευταίας επιλογής", + "FrmSettings._SlideshowInterval._From": "Από", + "FrmSettings._ImageInterpolation": "Παρεμβολή εικόνας", + "FrmQuickSetup._StepInfo": "Βήμα {0}", + "FrmMain.MnuColorPicker": "Επιλογέας χρώματος", + "FrmCrop.SelectionAspectRatio._FreeRatio": "Ελεύθερη αναλογία", + "FrmSettings._ResetSettings": "Επαναφορά ρυθμίσεων", + "FrmSettings._Startup": "Εκκίνηση", + "_.BackdropStyle._None": "Κανένα", + "FrmSettings._LoadDefaultZoomLevels": "Φόρτωση προεπιλεγμένων επιπέδων ζουμ", + "FrmColorPicker.BtnSettings._Tooltip": "Άνοιγμα ρυθμίσεων επιλογέα χρώματος…", + "FrmSettings._UseThemeForDarkMode": "Χρησιμοποιήστε αυτό το θέμα για σκοτεινή λειτουργία", + "FrmSettings._ShowDeleteConfirmation": "Εμφάνιση διαλόγου επιβεβαίωσης κατά τη διαγραφή αρχείου", + "FrmSettings._ShowAppIcon": "Εμφάνιση εικονιδίου εφαρμογής στη γραμμή τίτλου", + "_._InvalidAction": "Μη έγκυρη ενέργεια", + "FrmQuickSetup._SelectProfile": "Επιλέξτε ένα προφίλ", + "_.Metadata._FileCreationTime": "Ημερομηνία δημιουργίας", + "FrmSettings._SlideshowImagesToNotifySound": "Αριθμός εικόνων για την ενεργοποίηση ενός ήχου ειδοποίησης", + "FrmSettings._BackgroundColor": "Χρώμα φόντου προγράμματος προβολής", + "FrmSettings._RealTimeFileUpdate": "Ενημέρωση αρχείων σε πραγματικό χρόνο", + "_.ColorProfileOption._CurrentMonitorProfile": "Τρέχον προφίλ οθόνης", + "FrmSettings._EnableCutMultipleFiles": "Ενεργοποίηση της αποκοπής πολλαπλών αρχείων ταυτόχρονα", + "FrmSettings._AutoUpdate": "Αυτόματος έλεγχος για ενημέρωση", + "FrmCropSettings.LblDefaultSelection": "Προεπιλεγμένη επιλογή", + "FrmSettings._UseThemeForLightMode": "Χρήση αυτού του θέματος για φωτεινή λειτουργία", + "FrmSettings._ZoomLevels": "Επίπεδα ζουμ", + "FrmMain.MnuSetLockScreen._Success": "Η εικόνα κλειδώματος οθόνης ενημερώθηκε", + "FrmSettings._ShowGalleryFileName": "Εμφάνιση ονόματος αρχείου μικρογραφίας", + "FrmSettings.Layout._Order": "Σειρά", + "FrmCropSettings.ChkAutoCenterSelection": "Αυτόματο κεντράρισμα επιλογής", + "FrmSettings.Nav._FileTypeAssociations": "Συσχετίσεις τύπων αρχείων", + "_._Back": "Πίσω", + "FrmMain.MnuSetDesktopBackground._Success": "Το φόντο της επιφάνειας εργασίας ενημερώθηκε", + "FrmSettings._ShouldAutoOpenNewAddedImage": "Αυτόματο άνοιγμα της νέας εικόνας που προστέθηκε πρόσφατα", + "FrmCrop.SelectionAspectRatio._Custom": "Προσαρμοσμένη…", + "FrmMain.MnuCopyPath._Success": "Αντιγράφηκε η τρέχουσα διαδρομή εικόνας.", + "FrmSettings._StartupBoost._Error": "Αδυναμία αλλαγής της ρύθμισης ενίσχυσης εκκίνησης", + "FrmToolNotFound.LblDescription": "Το ImageGlass δεν μπόρεσε να εντοπίσει τη διαδρομή προς το εκτελέσιμο αρχείο \"{0}\". Για να επιλύσετε αυτό το πρόβλημα, παρακαλούμε ενημερώστε τη διαδρομή προς το '{0}' όπως απαιτείται.", + "FrmMain.MnuClearClipboard": "Εκκαθάριση προχείρου", + "FrmSettings._ColorManagement": "Διαχείριση χρωμάτων", + "FrmMain._ReachedLastLast": "Φτάσατε στην τελευταία εικόνα", + "FrmMain.MnuPanUp": "Μετατόπιση εικόνας επάνω", + "FrmMain.MnuRemoveDefaultPhotoViewer._Success": "Το ImageGlass δεν είναι πλέον το προεπιλεγμένο πρόγραμμα προβολής φωτογραφιών.", + "FrmSettings._GetMoreLanguagePacks": "Λήψη περισσότερων πακέτων γλώσσας…", + "FrmAbout._Privacy": "Πολιτική απορρήτου", + "FrmSettings._EnableRecursiveLoading": "Φόρτωση εικόνων σε υποφακέλους", + "_._UserAction._MethodArgumentNotSupported": "Ο τύπος παραμέτρων της μεθόδου '{0}' δεν υποστηρίζεται", + "FrmSettings._FileExtensionIcons._Description": "Για προσαρμογή εικονιδίων επέκτασης αρχείου, κάντε λήψη ενός πακέτου εικονιδίων, τοποθετήστε όλα τα αρχεία .ICO στο φάκελο εικονιδίων επέκτασης και κάντε κλικ στο κουμπί '{0}'. Αυτό θα ορίσει επίσης το ImageGlass ως προεπιλεγμένο πρόγραμμα προβολής φωτογραφιών.", + "_.ImageOrderType._Asc": "Αύξουσα", + "FrmExportFrames._Title": "Εξαγωγή καρέ εικόνας", + "_._Install": "Εγκατάσταση…", + "FrmMain.MnuFlipHorizontal": "Οριζόντια αναστροφή", + "FrmSettings._OpenExtensionIconFolder": "Άνοιγμα φακέλου εικονιδίων επεκτάσεων", + "FrmAbout._Collaborator": "Συνεργάτης:", + "FrmQuickSetup._ConfirmCloseProcess": "Πριν από την εφαρμογή των νέων ρυθμίσεων, είναι απαραίτητο να κλείσετε όλες τις διεργασίες του ImageGlass. Είστε έτοιμοι να προχωρήσετε;", + "FrmExportFrames._ExportDone": "Εξήχθησαν {0} καρέ με επιτυχία στο \n{1}", + "FrmCrop.BtnSaveAs._Tooltip": "Αποθήκευση ως αντίγραφο…", + "FrmMain.MnuOpenFile": "Άνοιγμα αρχείου…", + "FrmColorPickerSettings.ChkShowRgbA": "Χρήση μορφής RGB με τιμή άλφα", + "_.ImageInfo._ListCount": "{0} αρχείο(α)", + "FrmMain.MnuGoToLast": "Μετάβαση στην τελευταία εικόνα", + "FrmSettings._EditApps._AppName": "Όνομα εφαρμογής", + "FrmSettings._SlideshowBackgroundColor": "Χρώμα φόντου προβολής παρουσίασης", + "FrmAbout._Email": "Email:", + "_.MouseWheelAction._DoNothing": "Καμία ενέργεια", + "FrmMain.MnuSaveAs": "Αποθήκευση ως…", + "FrmMain._Loading": "Φόρτωση…", + "_._Browse": "Εξερεύνηση…", + "FrmMain.MnuSetDefaultPhotoViewer._Error": "Δεν ήταν δυνατός ο ορισμός του ImageGlass ως προεπιλεγμένου προγράμματος προβολής φωτογραφιών.", + "FrmSettings.Nav._Language": "Γλώσσα", + "FrmQuickSetup._SeeWhatNew": "Δείτε τι νέο υπάρχει σε αυτήν την έκδοση…", + "FrmSettings._ImageInterpolation._ScaleUp": "Όταν το ζουμ είναι > 100%", + "FrmSettings.Layout._ToolbarContextPosition": "Θέση της σχετικής γραμμής εργαλείων", + "FrmMain.MnuDeleteFromHardDisk": "Διαγραφή οριστικά", + "FrmSettings._EmbeddedThumbnail": "Ενσωματωμένη μικρογραφία", + "FrmMain.MnuDeleteFromHardDisk._Description": "Είστε βέβαιοι ότι θέλετε να διαγράψετε οριστικά αυτό το αρχείο;", + "FrmMain.MnuScaleToFill": "Πλήρης προσαρμογή", + "FrmCrop.BtnCrop": "Περικοπή", + "_.AfterEditAppAction._Minimize": "Ελαχιστοποίηση", + "FrmMain.MnuInvertColors": "Αντιστροφή χρωμάτων", + "FrmSettings._StartupBoost": "Ενίσχυση εκκίνησης", + "FrmMain.MnuViewFirstFrame": "Προβολή του πρώτου καρέ", + "_.MouseWheelEvent._CtrlAndScroll": "Κρατήστε πατημένο το Ctrl και κάντε κύλιση", + "FrmSettings._HideMainWindowInSlideshow": "Αυτόματη απόκρυψη κύριου μενού", + "_.Metadata._FrameCount": "Καρέ", + "FrmSettings._EnableCopyMultipleFiles": "Ενεργοποίηση της αντιγραφής πολλαπλών αρχείων ταυτόχρονα", + "FrmMain.MnuFrameless._EnableDescription": "Κρατήστε πατημένο το πλήκτρο Shift για να μετακινήσετε το παράθυρο.", + "_.ImageOrderBy._ExifDateTaken": "EXIF: Ημερομηνία λήψης", + "FrmAbout._Credits": "Εύσημα", + "FrmSettings._AddNewFileExtension": "Προσθήκη νέας επέκτασης αρχείου", + "FrmMain.MnuQuickSetup": "Άνοιγμα γρήγορης ρύθμισης ImageGlass", + "FrmMain.MnuSave._Success": "Η εικόνα αποθηκεύτηκε", + "FrmMain.MnuPanLeft": "Μετατόπιση εικόνας αριστερά", + "FrmUpdate._StatusChecking": "Έλεγχος για ενημέρωση…", + "FrmSettings.Nav._Layout": "Διάταξη", + "FrmMain.MnuOpenWith": "Άνοιγμα με…", + "FrmAbout._Thanks": "Ιδιαίτερες ευχαριστίες προς:", + "_._Warning": "Προειδοποίηση", + "FrmSettings.Nav._Keyboard": "Πληκτρολόγιο", + "FrmSlideshow._PauseSlideshow": "Η προβολή παρουσίασης είναι σε παύση.", + "_._Add+": "Προσθήκη…", + "_._Email": "Email", + "FrmMain.MnuPanDown": "Μετατόπιση εικόνας κάτω", + "_._Cancel": "Άκυρο", + "_._OK": "Εντάξει", + "FrmMain.MnuPanRight": "Μετατόπιση εικόνας δεξιά", + "_.Position._Right": "Δεξιά", + "_._Icon": "Εικονίδιο", + "FrmSettings._ShouldLoadHiddenImages": "Φόρτωση κρυφών εικόνων", + "_._InvalidAction._Transformation": "Το ImageGlass δεν υποστηρίζει περιστροφή, αναστροφή για αυτήν την εικόνα.", + "FrmSettings._MakeDefault": "Ορισμός προεπιλογής", + "FrmMain.MnuCopyImageData._Copying": "Αντιγραφή δεδομένων εικόνας. Πρόκειται να πάρει λίγο χρόνο…", + "FrmSettings._UseEmbeddedThumbnailRawFormats": "Φόρτωση μόνο της ενσωματωμένης μικρογραφίας για μορφές RAW", + "_.ImageInterpolation._Linear": "Γραμμικό", + "FrmSettings._ImageInfoTags": "Ετικέτες πληροφοριών εικόνας", + "FrmSettings._FileExtensionIcons": "Εικονίδια επέκτασης αρχείου", + "FrmMain.MnuEdit._AppNotFound": "Δεν ήταν δυνατή η εύρεση της συσχετισμένης εφαρμογής για επεξεργασία. Μπορείτε να αντιστοιχίσετε μια εφαρμογή για την επεξεργασία αυτής της μορφής στις Ρυθμίσεις ImageGlass > Επεξεργασία.", + "_.ColorProfileOption._None": "Κανένα", + "FrmSettings._TotalSupportedFormats": "Συνολικές υποστηριζόμενες μορφές: {0}", + "FrmSettings._Clipboard": "Πρόχειρο", + "_._UserAction._Win32ExeError": "Δεν είναι δυνατή η εκτέλεση της εντολής '{0}'. Βεβαιωθείτε ότι το όνομα είναι σωστό.", + "FrmCropSettings.DefaultSelectionType._SelectX": "Επιλογή {0}", + "_.AfterEditAppAction._Close": "Κλείσιμο", + "FrmAbout._LogoDesigner": "Σχεδιαστής λογοτύπου:", + "_.ImageOrderBy._Name": "Όνομα (προεπιλογή)", + "FrmMain.MnuRemoveDefaultPhotoViewer._Error": "Δεν ήταν δυνατή η κατάργηση του ImageGlass ως του προεπιλεγμένου προγράμματος προβολής φωτογραφιών.", + "FrmExportFrames._FolderPickerTitle": "Επιλογή φακέλου εξόδου για εξαγωγή καρέ εικόνας", + "FrmAbout._Donate": "Δωρεά", + "FrmMain.MnuFrameNav": "Πλοήγηση πλαισίου", + "FrmMain.MnuSetLockScreen": "Ορισμός ως εικόνα οθόνης κλειδώματος", + "_._Delete": "Διαγραφή", + "FrmMain.MnuViewPrevious": "Προβολή προηγούμενης εικόνας", + "_.Position._Top": "Επάνω", + "FrmSettings.Toolbar._CurrentButtons": "Τρέχοντα κουμπιά:", + "FrmMain.MnuAbout": "Σχετικά", + "FrmSettings._RemoveDefault": "Κατάργηση προεπιλογής", + "_._Description": "Περιγραφή", + "FrmMain.MnuPasteImage._Error": "Δεν ήταν δυνατή η εύρεση δεδομένων εικόνας στο πρόχειρο", + "FrmMain.MnuSettings": "Ρυθμίσεις", + "FrmCropSettings._Title": "Ρυθμίσεις περικοπής", + "FrmSettings.Toolbar._ToolbarIconHeight": "Μέγεθος εικονιδιών γραμμής εργαλείων", + "FrmSettings._SlideshowInterval._To": "Προς", + "FrmSettings.Layout._ToolbarPosition": "Θέση γραμμής εργαλείων", + "FrmUpdate._StatusUpdated": "Χρησιμοποιείτε την τελευταία έκδοση!", + "FrmMain.MnuExit": "Έξοδος", + "_._Webview2._Outdated": "Το WebView2 Runtime σας, δεν υποστηρίζεται.\n Παρακαλώ κάντε ενημέρωση στην έκδοση {0} ή σε νεότερη.", + "_._Yes": "Ναι", + "FrmMain.MnuRotateLeft": "Περιστροφή αριστερά", + "FrmSettings._EnableStartupBoost": "Ενεργοποίηση Ενίσχυσης Εκκίνησης", + "_.ImageOrderBy._ExifRating": "EXIF: Αξιολόγηση", + "FrmMain.MnuZoomIn": "Μεγέθυνση", + "_.Metadata._ColorSpace": "Χρωματικός χώρος", + "FrmAbout._Version": "Έκδοση:", + "FrmMain.MnuToggleTopMost._Enable": "Ενεργοποιημένο παράθυρο πάντα σε πρώτο πλάνο", + "FrmSettings.Toolbar._AvailableButtons": "Διαθέσιμα κουμπιά:", + "FrmMain.MnuSave._Saving": "Αποθήκευση εικόνας…", + "FrmQuickSetup._StandardUser": "Τυπικός χρήστης", + "FrmMain.MnuSetLockScreen._Error": "Δεν ήταν δυνατός ο ορισμός της προβαλλόμενης εικόνας ως εικόνας οθόνης κλειδώματος", + "FrmSettings.Nav._Image": "Εικόνα", + "FrmSettings._Theme._InstallTheme": "Εγκατάσταση πακέτων θεμάτων", + "FrmSettings._EnableMultiInstances": "Να επιτρέπονται πολλαπλές εμφανίσεις του προγράμματος", + "FrmMain.MnuCropTool": "Περικοπή εικόνας", + "_._IgCommandExe._DefaultError._Heading": "Μη έγκυρες εντολές", + "_._Refresh": "Ανανέωση", + "FrmMain.MnuLosslessCompression._Description": "Αυτό το εργαλείο χρησιμοποιεί τη βιβλιοθήκη Magick.NET για συμπίεση χωρίς απώλειες, βελτιστοποιώντας το μέγεθος του αρχείου. Αντικαθιστά μόνο εάν το συμπιεσμένο αρχείο είναι μικρότερο από το πρωτότυπο.", + "_._MoveDown": "Μετακίνηση προς τα κάτω", + "FrmSettings._GetExtensionIconPacks": "Λήψη πακέτων εικονιδίων επεκτάσεων…", + "FrmSettings._InAppMessageDuration": "Διάρκεια μηνύματος εντός εφαρμογής (χιλιοστά του δευτερολέπτου)", + "FrmMain.MnuFrameless": "Χωρίς πλαίσιο", + "_._Reset": "Επαναφορά", + "FrmSettings._ConfigDir": "Τοποθεσία διαμόρφωσης", + "FrmQuickSetup._SettingsWillBeApplied": "Θα εφαρμοστούν οι ρυθμίσεις:", + "FrmSettings._UnmanagedSettingReminder": "Αυτή η ρύθμιση δεν διαχειρίζεται από το ImageGlass. Μην ξεχάσετε να την απενεργοποιήσετε πριν αφαιρέσετε ή μετακινήσετε την εφαρμογή, επειδή το ImageGlass δεν το χειρίζεται αυτόματα.", + "FrmMain.MnuClipboard": "Πρόχειρο", + "FrmMain.MnuCustomZoom": "Προσαρμοσμένο ζουμ…", + "FrmSettings._DisplayLanguage": "Γλώσσα εμφάνισης", + "FrmMain.MnuPrint._Error": "Δεν ήταν δυνατή η εκτύπωση της εικόνας προβολής", + "FrmSettings._ShouldPreserveModifiedDate": "Διατήρηση ημερομηνίας τροποποίησης της εικόνας κατά την αποθήκευση", + "FrmSettings._ShowSaveOverrideConfirmation": "Εμφάνιση πλαισίου διαλόγου επιβεβαίωσης κατά την αντικατάσταση αρχείου", + "FrmColorPickerSettings.ChkShowHexA": "Χρήση μορφής HEX με τιμή άλφα", + "FrmMain.MnuFullScreen": "Πλήρης οθόνη", + "FrmSettings._StartupDir": "Τοποθεσία εκκίνησης", + "FrmSettings._ShowCheckerboardOnlyImageRegion": "Εμφάνιση σχεδίου σκακιέρας μόνο εντός της περιοχής εικόνας", + "FrmMain.MnuClearClipboard._Success": "Το πρόχειρο καθαρίστηκε.", + "FrmQuickSetup._Text": "Γρήγορη ρύθμιση του ImageGlass", + "FrmMain.MnuLosslessCompression._Done": "Πραγματοποιήθηκε συμπίεση χωρίς απώλειες.\r\nΤο νέο μέγεθος αρχείου είναι {0}, αποθηκεύτηκε {1}.", + "FrmMain.MnuLosslessCompression": "Magick.NET Συμπίεση χωρίς απώλειες", + "FrmResize.RadResizeByPercentage": "Ποσοστό", + "FrmSettings._StartupBoost._Disabled": "Η ενίσχυση εκκίνησης είναι απενεργοποιημένη", + "FrmMain.MnuToggleCheckerboard": "Διαφανές φόντο", + "FrmSettings._MinEmbeddedThumbnailSize._Height": "Ύψος", + "FrmSettings.Nav._General": "Γενικά", + "FrmSettings._ImageLoading": "Φόρτωση εικόνας", + "FrmSettings._ShowSlideshowCountdown": "Εμφάνιση αντίστροφης μέτρησης προβολής παρουσίασης", + "FrmMain.MnuSave": "Αποθήκευση", + "FrmMain.MnuMoveToRecycleBin": "Μετακίνηση στον Κάδο Ανακύκλωσης", + "FrmMain.MnuRefresh": "Ανανέωση", + "FrmToolNotFound.LblHeading": "Το '{0}' δεν βρέθηκε!", + "FrmMain.MnuReportIssue": "Αναφορά προβλήματος…", + "FrmMain.MnuCopyImageData": "Αντιγραφή δεδομένων εικόνας", + "FrmMain.MnuCheckForUpdate._NewVersion": "Μια νέα έκδοση είναι διαθέσιμη!", + "_._Empty": "(κενό)", + "FrmSettings._Zooming": "Ζουμ", + "FrmMain.MnuCutFile": "Αποκοπή αρχείου", + "FrmHotkeyPicker.LblHotkey": "Πατήστε πλήκτρα πρόσβασης", + "FrmSettings.Layout._Gallery": "Συλλογή", + "FrmMain.MnuNewWindow": "Άνοιγμα νέου παραθύρου", + "FrmMain.MnuMoveToRecycleBin._Description": "Θέλετε να μετακινήσετε αυτό το αρχείο στον Κάδο Ανακύκλωσης;", + "FrmSettings._DefaultPhotoViewer": "Προεπιλεγμένο πρόγραμμα προβολής φωτογραφιών", + "_.Metadata._ExifDateTimeOriginal": "EXIF: DateTimeOriginal", + "FrmMain.MnuRotateRight": "Περιστροφή δεξιά", + "FrmSettings._MinEmbeddedThumbnailSize": "Ελάχιστο μέγεθος της ενσωματωμένης μικρογραφίας που θα φορτωθεί", + "FrmMain.MnuSetDefaultPhotoViewer": "Ορισμός προεπιλεγμένου προγράμματος προβολής φωτογραφιών", + "FrmMain.MnuImageProperties": "Ιδιότητες εικόνας", + "FrmSettings._EnableNavigationButtons": "Εμφάνιση κουμπιών βέλους πλοήγησης", + "_._Edit": "Επεξεργασία", + "FrmSettings._ImageBooster": "Image Booster", + "FrmSettings.Tools._IntegratedWith": "Ενσωματωμένο με το {0}", + "_._Next": "Επόμενο", + "FrmExportFrames._OpenOutputFolder": "Άνοιγμα φακέλου εξόδου", + "FrmMain.MnuOpenLocation": "Άνοιγμα τοποθεσίας εικόνας", + "FrmMain.MnuLockZoom": "Κλείδωμα αναλογίας ζουμ", + "FrmSettings._StartupBoost._Description": "Προφόρτωση και εκτέλεση του ImageGlass στο παρασκήνιο για μερικά δευτερόλεπτα κατά την εκκίνηση των Windows για να επιταχύνει την πρώτη εκκίνηση.", + "FrmSettings._WindowBackdrop": "Φόντο παραθύρου", + "FrmSettings._EnableRealTimeFileUpdate": "Παρακολούθηση αλλαγών αρχείων στο φάκελο προβολής και ενημέρωση σε πραγματικό χρόνο", + "_._NotSupported": "Μη υποστηριζόμενη μορφή", + "FrmSettings._Theme._GetMoreThemes": "Λήψη περισσότερων πακέτων θεμάτων…", + "FrmMain.MnuNewWindow._Error": "Δεν είναι δυνατό το άνοιγμα νέου παραθύρου γιατί επιτρέπεται μόνο μία διεργασία", + "FrmMain.MnuZoomOut": "Σμίκρυνση", + "FrmSettings.Toolbar._EditButton": "Επεξεργασία πλήκτρου γραμμής εργαλείων", + "FrmMain.MnuCustomZoom._Description": "Εισάγετε μια νέα τιμή ζουμ", + "FrmResize.RadResizeByPixels": "Πίξελ", + "FrmMain.MnuEdit": "Επεξεργασία της εικόνας {0}…", + "FrmSettings.Layout._GalleryPosition": "Θέση συλλογής", + "FrmMain.MnuWindowFit": "Προσαρμογή παραθύρου", + "FrmMain._OpenFileDialog": "Όλα τα υποστηριζόμενα αρχεία", + "FrmSettings._UseRandomIntervalForSlideshow": "Χρήση τυχαίου διαστήματος", + "_.Position._Left": "Αριστερά", + "FrmSettings._ShouldOpenLastSeenImage": "Άνοιγμα της τελευταίας εικόνας", + "_.Position._Bottom": "Κάτω", + "FrmResize.ChkKeepRatio": "Διατήρηση αναλογικής αναλογίας", + "FrmMain.MnuGoTo": "Μετάβαση σε…", + "FrmSlideshow.MnuPauseResumeSlideshow": "Παύση/Συνέχιση προβολής παρουσίασης", + "FrmSettings.Tools._Integrated": "Ενσωματωμένο", + "FrmSettings._Contributors": "Συντελεστές", + "_.MouseWheelAction._Zoom": "Μεγέθυνση / Σμίκρυνση", + "_._CommandPreview": "Προεπισκόπηση εντολής", + "FrmSettings._DarkTheme": "Σκοτεινό", + "_._Hotkeys": "Πλήκτρα συντόμευσης", + "_.Metadata._ExifDateTime": "EXIF: DateTime", + "FrmSettings.Toolbar._Errors._ButtonIdRequired": "Απαιτείται αναγνωριστικό κουμπιού.", + "FrmSettings._MinEmbeddedThumbnailSize._Width": "Πλάτος", + "_._Executable": "Εκτελέσιμο", + "_.ImageInterpolation._MultiSampleLinear": "Γραμμικό πολλαπλού δείγματος", + "_._Separator": "Διαχωριστικό", + "FrmQuickSetup._ProfessionalUser": "Επαγγελματίας χρήστης", + "FrmMain.MnuFlipVertical": "Κατακόρυφη αναστροφή", + "FrmSlideshow._ResumeSlideshow": "Η προβολή παρουσίασης συνεχίζεται.", + "FrmCropSettings.DefaultSelectionType._CustomArea": "Προσαρμοσμένη περιοχή…", + "FrmMain.MnuActualSize": "Πραγματικό μέγεθος", + "FrmCrop.BtnSaveAs": "Αποθήκευση ως…", + "FrmSettings._InstallNewLanguagePack": "Εγκατάσταση νέων πακέτων γλωσσών…", + "FrmSlideshow.MnuZoomModes": "Λειτουργίες ζουμ", + "FrmMain.MnuTools": "Εργαλεία", + "_.ImageInterpolation._Cubic": "Κυβικό", + "FrmUpdate._LatestVersion": "Η τελευταία έκδοση: {0}", + "FrmMain.MnuViewNext": "Προβολή επόμενης εικόνας", + "_.MouseWheelEvent._AltAndScroll": "Κρατήστε πατημένο το Alt και κάντε κύλιση", + "FrmToolNotFound._Title": "Το εργαλείο δεν βρέθηκε", + "FrmCrop.BtnCrop._Tooltip": "Περικοπή μόνο της εικόνας", + "FrmSettings.EditAppDialog._AddApp": "Προσθήκη εφαρμογής για επεξεργασία", + "FrmMain.MnuPanning": "Μετατόπιση", + "_._MoveUp": "Μετακίνηση προς τα επάνω", + "FrmCropSettings.DefaultSelectionType._SelectAll": "Επιλογή όλων", + "_._Name": "Όνομα", + "FrmColorPickerSettings.ChkShowHslA": "Χρήση μορφής HSL με τιμή άλφα", + "FrmMain.MnuToggleImageAnimation": "Έναρξη / διακοπή κινούμενης εικόνας", + "FrmSettings._DisableStartupBoost": "Απενεργοποίηση Ενίσχυσης Εκκίνησης", + "FrmMain.MnuCopyFile._Success": "Αντιγράφηκαν {0} αρχείο(α).", + "FrmMain.MnuSave._ConfirmDescription": "Το ImageGlass δεν είναι ένα επαγγελματικό πρόγραμμα επεξεργασίας φωτογραφιών, παρακαλώ να έχετε υπόψη την απώλεια ποιότητας, μεταδεδομένων, επιπέδων,... κατά την αποθήκευση της εικόνας σας.", + "FrmToolNotFound.BtnSelectExecutable": "Επιλογή…", + "FrmUpdate._StatusOutdated": "Μια νέα ενημέρωση είναι διαθέσιμη!", + "_.ImageOrderBy._Random": "Τυχαία", + "FrmResize.LblCurrentSize": "Τρέχον Μέγεθος:", + "_._Apply": "Εφαρμογή", + "FrmAbout._Slogan": "Ένα ελαφρύ και ευέλικτο πρόγραμμα προβολής εικόνων", + "FrmMain.MnuPanToTop": "Μετατόπιση εικόνας προς τα πάνω", + "FrmSettings.Toolbar._AddNewButton": "Προσθήκη προσαρμοσμένου κουμπιού γραμμής εργαλείων", + "FrmCrop.LblSize": "Μέγεθος:", + "FrmSettings._ImageInterpolation._ScaleDown": "Όταν το ζουμ είναι < 100%", + "_._CreatingFileError": "Δεν ήταν δυνατή η δημιουργία προσωρινού αρχείου εικόνας", + "FrmMain.MnuGoTo._Description": "Εισάγετε το ευρετήριο εικόνας για προβολή, και στη συνέχεια πατήστε ENTER", + "FrmSettings.Toolbar._EnableCenterToolbar": "Χρησιμοποιήστε τη στοίχιση στο κέντρο για τη γραμμή εργαλείων", + "FrmMain.MnuResizeTool": "Αλλαγή μεγέθους εικόνας", + "FrmSettings.Layout._Toolbar": "Γραμμή εργαλείων", + "FrmMain.MnuHelp": "Βοήθεια", + "_.ImageOrderBy._FileSize": "Μέγεθος αρχείου", + "FrmSettings._Theme._OpenThemeFolder": "Άνοιγμα φακέλου θεμάτων", + "FrmMain.MnuNavigation": "Πλοήγηση", + "_._Save": "Αποθήκευση", + "FrmQuickSetup._SettingProfileDescription": "Για να τροποποιήσετε αυτές τις ρυθμίσεις, απλά πηγαίνετε πρόσβαση στις ρυθμίσεις της εφαρμογής.", + "_._UserAction._MenuNotFound": "Δεν είναι δυνατή η εύρεση του μενού '{0}' για επίκληση της ενέργειας", + "FrmMain.MnuPanToLeftSide": "Μετατόπιση εικόνας στην αριστερή πλευρά", + "FrmUpdate._CurrentVersion": "Τρέχουσα έκδοση: {0}", + "FrmCrop.BtnSettings._Tooltip": "Άνοιγμα ρυθμίσεων εργαλείου περικοπής", + "_.ColorProfileOption._Custom": "Προσαρμοσμένο…", + "FrmSettings._UseEmbeddedThumbnailOtherFormats": "Φόρτωση μόνο της ενσωματωμένης μικρογραφίας για άλλες μορφές", + "FrmMain.MnuGoToFirst": "Μετάβαση στην πρώτη εικόνα", + "FrmSettings._ExportLanguagePack": "Εξαγωγή πακέτου γλώσσας…", + "FrmSettings.Nav._Mouse": "Ποντίκι", + "_.ImageOrderBy._DateCreated": "Ημερομηνία δημιουργίας", + "FrmSettings._EnableFullscreenSlideshow": "Έναρξη προβολής παρουσίασης σε λειτουργία πλήρους οθόνης", + "FrmAbout._Homepage": "Αρχική Σελίδα:", + "FrmSettings._GalleryCacheSizeInMb": "Μέγιστο μέγεθος προσωρινής μνήμης γκαλερί (σε megabyte)", + "FrmMain.MnuCopyImageData._Success": "Αντιγράφηκαν τα τρέχοντα δεδομένα εικόνας.", + "FrmSettings._EnableLoopBackNavigation": "Επιστρέψτε στην πρώτη εικόνα όταν φτάσετε στο τέλος της λίστας εικόνων", + "_.MouseWheelEvent._Scroll": "Κύλιση", + "FrmCrop.BtnSave._Tooltip": "Αποθήκευση εικόνας", + "FrmMain.MnuSlideshow": "Προβολή παρουσίασης", + "FrmMain.MnuShare": "Κοινοποίηση…", + "FrmSettings._SlideshowNotification": "Ειδοποίηση προβολής παρουσίασης", + "FrmMain.MnuViewChannels": "Προβολή καναλιών", + "FrmSettings._Refresh": "Ανανέωση", + "_._UserAction._MethodNotFound": "Δεν είναι δυνατή η εύρεση της μεθόδου '{0}' για επίκληση της ενέργειας", + "FrmMain.MnuCopyFile": "Αντιγραφή αρχείου", + "_._CreatingFile": "Δημιουργία ενός προσωρινού αρχείου εικόνας…", + "FrmMain.MnuToggleTopMost": "Διατήρηση παραθύρου πάντα σε πρώτο πλάνο", + "FrmMain.MnuLosslessCompression._Confirm": "Είστε βέβαιοι ότι θέλετε να συνεχίσετε;", + "FrmMain.MnuImage": "Εικόνα", + "FrmSettings._StartupBoost._Enabled": "Η ενίσχυση εκκίνησης είναι ενεργοποιημένη", + "FrmQuickSetup._SetDefaultViewer": "Θέλετε να ορίσετε το ImageGlass ως το προεπιλεγμένο πρόγραμμα προβολής φωτογραφιών;", + "FrmMain.MnuScaleToWidth": "Προσαρμογή στο πλάτος", + "_._FileExtension": "Επέκταση αρχείου", + "FrmUpdate._PublishedDate": "Ημερομηνία δημοσίευσης: {0}", + "_._DoNotShowThisMessageAgain": "Να μην εμφανιστεί ξανά αυτό το μήνυμα", + "_.ImageInterpolation._NearestNeighbor": "Πλησιέστερο γειτονικό", + "FrmCrop.LblLocation": "Τοποθεσία:", + "_._Download": "Λήψη", + "_.Metadata._ColorProfile": "Προφίλ χρωμάτων", + "FrmSettings._CenterWindowFit": "Αυτόματο κεντράρισμα παραθύρου στη λειτουργία Προσαρμογής Παραθύρου", + "FrmSettings._ImageLoadingOrder": "Σειρά φόρτωσης εικόνων", + "FrmSettings._GalleryColumns": "Αριθμός στηλών μικρογραφιών σε κάθετη διάταξη γκαλερί", + "_._Quit": "Έξοδος", + "_._Add": "Προσθήκη", + "FrmMain.MnuChangeBackgroundColor": "Αλλαγή χρώματος φόντου…", + "FrmMain.MnuToggleToolbar": "Γραμμή εργαλείων", + "FrmAbout._Contact": "Επικοινωνία", + "FrmSettings.Toolbar._AddCustomButton": "Προσθήκη προσαρμοσμένου κουμπιού…", + "FrmCrop.BtnQuickSelect._Tooltip": "Γρήγορη επιλογή…", + "FrmMain.MnuCutFile._Success": "Αποκόπηκαν {0} αρχείο(α).", + "FrmSettings._ZoomSpeed": "Ταχύτητα ζουμ", + "FrmMain.MnuToggleTopMost._Disable": "Απενεργοποιημένο παράθυρο πάντα σε πρώτο πλάνο", + "FrmSettings._ShouldUseExplorerSortOrder": "Χρήση σειράς ταξινόμησης της Εξερεύνησης αρχείων των Windows εάν είναι δυνατόν", + "_.ImageInterpolation._Antisotropic": "Ανισοτροπία", + "FrmMain._ReachedFirstImage": "Φτάσατε στην πρώτη εικόνα", + "_._UnhandledException": "Ανεπίλυτη εξαίρεση", + "FrmResize.LblNewSize": "Νέο Μέγεθος:", + "FrmMain._ClipboardImage": "Εικόνα πρόχειρου", + "FrmMain.MnuExportFrames": "Εξαγωγή πλαισίων εικόνων…", + "FrmMain.MnuFile": "Αρχείο", + "_._Close": "Κλείσιμο", + "FrmMain.MnuMain": "Κύριο μενού", + "_._ResetToDefault": "Επαναφορά προεπιλογών", + "FrmSettings.Nav._Gallery": "Συλλογή", + "FrmMain.MnuSetDefaultPhotoViewer._Success": "Έχετε ορίσει με επιτυχία το ImageGlass ως προεπιλεγμένο πρόγραμμα προβολής φωτογραφιών.", + "FrmSettings._HideGalleryInFullscreen": "Απόκρυψη συλλογής σε λειτουργία πλήρους οθόνης", + "FrmSettings._AvailableImageInfoTags": "Διαθέσιμες ετικέτες:", + "FrmExportFrames._Exporting": "Εξαγωγή {0}/{1} καρέ \n{2}…", + "_._Argument": "Παράμετρος", + "FrmSettings._ImageEditQuality": "Ποιότητα εικόνας", + "_._ID": "Αναγνωριστικό", + "FrmSettings._UserConfigFile": "Αρχείο ρυθμίσεων χρήστη (igconfig.json)", + "FrmMain.MnuLoadingOrders": "Φόρτωση εντολών", + "FrmSettings._OpenSaveAsDialogInTheCurrentImageDir": "Ανοίξτε το παράθυρο διαλόγου Αποθήκευση ως στον τρέχοντα κατάλογο εικόνων", + "_.MouseWheelEvent._ShiftAndScroll": "Κρατήστε πατημένο το Shift και κάντε κύλιση", + "FrmSettings._UseSmoothZooming": "Χρήση ομαλού ζουμ", + "FrmSettings._Theme": "Θέμα", + "FrmSettings._ImageBoosterCacheMaxDimension": "Μέγιστη διάσταση εικόνας προς αποθήκευση (σε pixels)", + "FrmMain.MnuScaleToHeight": "Προσαρμογή στο ύψος", + "_.Metadata._FileLastWriteTime": "Ημερομηνία τροποποίησης", + "FrmSettings._Author": "Δημιουργός", + "FrmSettings._Others": "Άλλες", + "_.MouseWheelAction._PanVertically": "Μετατόπιση επάνω / κάτω", + "FrmSettings._MouseWheelAction": "Ενέργεια τροχού ποντικιού", + "FrmSettings.Nav._Tools": "Εργαλεία", + "FrmMain.MnuSetDesktopBackground._Error": "Δεν ήταν δυνατός ο ορισμός της προβαλλόμενης εικόνας ως φόντο επιφάνειας εργασίας", + "FrmSettings.Toolbar._Errors._ButtonExecutableRequired": "Απαιτείται εκτελέσιμο κουμπί.", + "_.ImageOrderBy._DateAccessed": "Ημερομηνία πρόσβασης", + "FrmSettings._ThumbnailSize": "Μέγεθος μικρογραφίας (σε pixel)", + "FrmSettings._FileFormats": "Μορφές αρχείων", + "FrmMain.MnuReloadImageList": "Επαναφόρτωση λίστας εικόνων", + "FrmSettings._UseWebview2ForSvg": "Χρήση Webview2 για προβολή μορφής SVG", + "FrmCrop.BtnCopy": "Αντιγραφή", + "FrmSettings._CurrentMonitorProfile._Description": "Το ImageGlass δεν ενημερώνει αυτόματα το χρώμα κατά τη μετακίνηση του παραθύρου του μεταξύ οθονών", + "FrmMain.PicMain._ErrorText": "Δεν ήταν δυνατό το άνοιγμα αυτής της εικόνας", + "FrmSettings.Tools._AddNewTool": "Προσθήκη εξωτερικού εργαλείου", + "FrmMain.MnuRename": "Μετονομασία εικόνας…", + "FrmMain.MnuViewLastFrame": "Προβολή του τελευταίου καρέ", + "_._Webview2._NotFound": "Παρακαλώ εγκαταστήστε την τελευταία έκδοση του WebView2 Runtime.", + "FrmMain.MnuGetMoreTools": "Λήψη περισσότερων εργαλείων…", + "FrmSettings.Nav._Appearance": "Εμφάνιση", + "FrmSettings._SlideshowInterval": "Μεσοδιάστημα προβολής παρουσίασης:", + "_.ImageInterpolation._HighQualityBicubic": "Υψηλή ποιότητα, δικυβική", + "FrmColorPickerSettings.ChkShowHsvA": "Χρήση μορφής HSV με τιμή άλφα", + "FrmSettings.Tools._EditTool": "Επεξεργασία εξωτερικού εργαλείου", + "_._Error": "Σφάλμα", + "FrmSettings._ImageBoosterCacheMaxFileSizeInMb": "Μέγιστο μέγεθος αρχείου εικόνας προς αποθήκευση (σε megabytes)", + "_._UnhandledException._Description": "Παρουσιάστηκε μια ανεπίλυτη εξαίρεση. Εάν κάνετε κλικ στο Συνέχεια, η εφαρμογή θα παραβλέψει αυτό το σφάλμα και θα προσπαθήσει να συνεχίσει. Εάν κάνετε κλικ στο Έξοδος, η εφαρμογή θα κλείσει αμέσως.", + "_.Metadata._FileSize": "Μέγεθος αρχείου", + "FrmSettings.Toolbar._ButtonJson": "Κουμπί JSON", + "FrmQuickSetup._SetDefaultViewer._Description": "Μπορείτε να το επαναφέρετε στις ρυθμίσεις της εφαρμογής > Καρτέλα Συσχετίσεις τύπων αρχείων.", + "FrmSettings.Nav._Edit": "Επεξεργασία", + "FrmMain.MnuToggleGallery": "Πίνακας συλλογής", + "_._IgCommandExe._DefaultError._Description": "Βεβαιωθείτε ότι δίνετε τις σωστές εντολές!\r\nΑυτό το εκτελέσιμο αρχείο περιέχει λειτουργίες γραμμής εντολών για το λογισμικό ImageGlass.\r\n\r\nΓια να εξερευνήσετε όλες τις γραμμές εντολών, παρακαλώ επισκεφθείτε τη διεύθυνση:\n{0}", + "FrmMain.MnuLosslessCompression._Compressing": "Εκτέλεση συμπίεσης χωρίς απώλειες…", + "FrmSettings._ShouldGroupImagesByDirectory": "Ομαδοποίηση εικόνων ανά φάκελο", + "FrmMain.MnuPanToRightSide": "Μετατόπιση εικόνας στη δεξιά πλευρά", + "_.Metadata._ExifRatingPercent": "Αξιολόγηση", + "FrmSettings._PanSpeed": "Ταχύτητα μετατόπισης", + "_._CheckForUpdate": "Έλεγχος για ενημέρωση…", + "FrmSettings.Layout._ToolbarContext": "Σχετική γραμμή εργαλείων", + "_.ImageInfo._FrameCount": "{0} καρέ", + "FrmMain.MnuLayout": "Διάταξη", + "_._Website": "Ιστοσελίδα", + "FrmMain.MnuPasteImage": "Επικόλληση εικόνας", + "FrmSettings._ShowGalleryScrollbars": "Εμφάνιση γραμμών κύλισης συλλογής" + } +} \ No newline at end of file diff --git a/Setup/Assets/Language/Hebrew.iglang.json b/Setup/Assets/Language/Hebrew.iglang.json new file mode 100644 index 000000000..72299dd1a --- /dev/null +++ b/Setup/Assets/Language/Hebrew.iglang.json @@ -0,0 +1,504 @@ +{ + "_Metadata": { + "Code": "he-IL", + "EnglishName": "Hebrew", + "LocalName": "עברית", + "Author": "Joe Shachaf, Ronen Nisanov", + "MinVersion": "9.1" + }, + "Items": { + "FrmCrop.SelectionAspectRatio._Original": "מקורי", + "FrmMain.MnuShare._Error": "Could not open Share dialog.", + "_.Metadata._FileLastAccessTime": "Date accessed", + "FrmAbout._License": "רישיון תוכנה", + "FrmSettings.Toolbar._Errors._ButtonIdDuplicated": "כפתור עם המזהה '{0}' כבר הוגדר. אנא בחר מזהה שונה וייחודי עבור הלחצן שלך, כדי למנוע התנגשויות.", + "FrmMain.MnuSave._Confirm": "Are you sure you want to override this image?", + "FrmSettings._OpenDefaultAppsSetting": "Open Default apps setting", + "FrmMain.MnuCopyPath": "העתק מיקום תמונה בדיסק", + "FrmCropSettings.DefaultSelectionType._SelectNone": "לא נבחר", + "_.MouseWheelAction._PanHorizontally": "Pan left / right", + "FrmMain.MnuPrint": "הדפסה…", + "FrmSettings.Toolbar._ToolbarButtons": "Toolbar buttons", + "FrmResize.LblResample": "דגום מחדש:", + "_.ImageOrderBy._Extension": "סיומת", + "FrmSettings.Nav._Viewer": "צפיין", + "FrmSettings.EditAppDialog._EditApp": "Edit app", + "FrmCrop.BtnReset._Tooltip": "Reset selection", + "FrmMain.MnuRename._Description": "Enter a new filename:", + "_._No": "כן", + "FrmSlideshow.MnuToggleCountdown": "הצג ספירה לאחור במצגת שקפים", + "FrmSettings._OpenStartupAppsSetting": "Open Startup apps setting", + "FrmMain.MnuViewPreviousFrame": "View previous frame", + "_.ImageOrderBy._DateModified": "תאריך שינוי", + "FrmMain.MnuViewNextFrame": "View next frame", + "FrmMain.MnuUnload": "צא מהתמונה", + "FrmSettings.Toolbar._HideToolbarInFullscreen": "Hide toolbar in Full Screen mode", + "_.ImageOrderType._Desc": "סדר יורד", + "_._Update": "Update", + "FrmSettings._EnableImageAsyncLoading": "Enable image asynchronous loading", + "FrmSettings._DefaultPhotoViewer._Description": "רשום את הפורמטים התומכים של ImageGlass ב- Windows. ייתכן שיהיה עליך להכנס אל 'הגדרות אפליקציות ברירת המחדל' ולבחור באופן ידני את ImageGlass מהרשימה, כדי שההגדרה תיכנס לתוקף.", + "_.MouseWheelAction._BrowseImages": "View next / previous Image", + "FrmSettings._EditApps": "Image editing apps", + "FrmColorPickerSettings.ChkShowCIELabA": "Use CIELAB format with alpha value", + "_._GetHelp": "Get help", + "FrmQuickSetup._SkipQuickSetup": "Skip this and launch ImageGlass", + "FrmColorPickerSettings._Title": "Color picker settings", + "_._Copy": "העתק", + "FrmSettings._ImageBoosterCacheCount": "Number of images cached by Image Booster (one direction)", + "FrmMain.MnuPanToBottom": "Pan image to bottom", + "FrmMain.MnuZoom": "תקריב", + "FrmCropSettings.ChkCloseToolAfterSaving": "Close Crop tool after saving", + "FrmSettings._ShowWelcomeImage": "Show welcome image", + "FrmSettings._ColorProfile": "פרופיל צבע", + "FrmSettings._Theme._UninstallTheme": "Uninstall a theme pack", + "FrmMain._OpenWith": "פתח באמצעות {0}", + "FrmMain.MnuRemoveDefaultPhotoViewer": "Remove default photo viewer", + "_.AfterEditAppAction._Nothing": "כלום", + "FrmCrop.BtnSave": "שמור", + "FrmMain.MnuScaleToFit": "התאם לגודל מסך", + "FrmToolNotFound.LblDownloadToolText": "באפשרותך להוריד כלים נוספים עבור ImageGlass ב:", + "_._LearnMore": "למד עוד…", + "FrmCrop.LblAspectRatio": "Aspect ratio:", + "FrmExportFrames._FileNotExist": "Image file does not exist", + "FrmSettings._LightTheme": "בהיר", + "FrmSettings.Nav._Slideshow": "מצגת שקופיות", + "_._Continue": "המשך", + "_._AddHotkey": "הוסף קיצור מקשים…", + "FrmMain.MnuSetDesktopBackground": "קבע כרקע שולחן עבודה", + "FrmMain.MnuReload": "טען תמונה מחדש", + "FrmSlideshow.MnuExitSlideshow": "צא ממצגת השקופיות", + "FrmMain.MnuAutoZoom": "זום אוטומטי", + "FrmSettings._ShowImagePreview": "Display image preview while it's being loaded", + "FrmCrop.BtnCopy._Tooltip": "העתק אתהבחירה ללוח", + "FrmSettings.Nav._Toolbar": "סרגל כלים", + "FrmMain.MnuSave._Error": "לא היתה אפשרות לשמור את התמונה", + "FrmSettings._AfterEditingAction": "לאחר פתיחת תוכנית עריכה", + "FrmSettings._ShouldUseColorProfileForAll": "החל גם על תמונות ללא פרופיל צבע מוטמע", + "FrmCropSettings.DefaultSelectionType._UseTheLastSelection": "Use the last selection", + "FrmSettings._SlideshowInterval._From": "From", + "FrmSettings._ImageInterpolation": "Image interpolation", + "FrmQuickSetup._StepInfo": "שלב {0}", + "FrmMain.MnuColorPicker": "דוגם הצבע", + "FrmCrop.SelectionAspectRatio._FreeRatio": "Free ratio", + "FrmSettings._ResetSettings": "אפס הגדרות", + "FrmSettings._Startup": "הפעלה אוטומטית", + "_.BackdropStyle._None": "ללא", + "FrmSettings._LoadDefaultZoomLevels": "Load default zoom levels", + "FrmColorPicker.BtnSettings._Tooltip": "Open Color picker settings…", + "FrmSettings._UseThemeForDarkMode": "Use this theme for dark mode", + "FrmSettings._ShowDeleteConfirmation": "Show confirmation dialog when deleting file", + "FrmSettings._ShowAppIcon": "Show app icon on the title bar", + "_._InvalidAction": "פעולה לא חוקית", + "FrmQuickSetup._SelectProfile": "בחר פרופיל", + "_.Metadata._FileCreationTime": "Date created", + "FrmSettings._SlideshowImagesToNotifySound": "Number of images to trigger a notification sound", + "FrmSettings._BackgroundColor": "Viewer background color", + "FrmSettings._RealTimeFileUpdate": "Real-time file update", + "_.ColorProfileOption._CurrentMonitorProfile": "Current monitor profile", + "FrmSettings._EnableCutMultipleFiles": "Enable the cutting of multiple files at once", + "FrmSettings._AutoUpdate": "בדוק עדכונים אוטומטית", + "FrmCropSettings.LblDefaultSelection": "Default selection", + "FrmSettings._UseThemeForLightMode": "Use this theme for light mode", + "FrmSettings._ZoomLevels": "רמות תקריב", + "FrmMain.MnuSetLockScreen._Success": "Lock screen image is updated", + "FrmSettings._ShowGalleryFileName": "Show thumbnail filename", + "FrmSettings.Layout._Order": "סדר", + "FrmCropSettings.ChkAutoCenterSelection": "Auto-center selection", + "FrmSettings.Nav._FileTypeAssociations": "File type associations", + "_._Back": "חזור", + "FrmMain.MnuSetDesktopBackground._Success": "Desktop background is updated", + "FrmSettings._ShouldAutoOpenNewAddedImage": "Open the new added image automatically", + "FrmCrop.SelectionAspectRatio._Custom": "התאמה אישית…", + "FrmMain.MnuCopyPath._Success": "העתקת נתיב התמונה הנוכחי.", + "FrmSettings._StartupBoost._Error": "Could not change Startup Boost setting", + "FrmToolNotFound.LblDescription": "ImageGlass לא הצליח לאתר את הנתיב לקובץ ההפעלה '{0}'. כדי לפתור בעיה זו, אנא עדכן את הנתיב אל '{0}' לפי הצורך.", + "FrmMain.MnuClearClipboard": "נקה לוח גזירים", + "FrmSettings._ColorManagement": "ניהול צבעים", + "FrmMain._ReachedLastLast": "הגעת לתמונה האחרונה", + "FrmMain.MnuPanUp": "Pan image up", + "FrmMain.MnuRemoveDefaultPhotoViewer._Success": "ImageGlass is no longer the default photo viewer.", + "FrmSettings._GetMoreLanguagePacks": "מצא עוד ערכות שפה…", + "FrmAbout._Privacy": "מדיניות פרטיות", + "FrmSettings._EnableRecursiveLoading": "Load images in subfolders", + "_._UserAction._MethodArgumentNotSupported": "The argument type of method '{0}' is not supported", + "FrmSettings._FileExtensionIcons._Description": "להתאמה אישית של סמלי סיומות קבצים, הורד ערכת אייקונים, הצב את כל הקבצים בסיומת ico. בתיקיית סמל ההרחבה ולחץ על הלחצן '{0}'. זה גם יגדיר את ImageGlass כמציג תמונות ברירת מחדל.", + "_.ImageOrderType._Asc": "סדר עולה", + "FrmExportFrames._Title": "Export image frames", + "_._Install": "התקן…", + "FrmMain.MnuFlipHorizontal": "הפוך אופקית", + "FrmSettings._OpenExtensionIconFolder": "Open extension icon folder", + "FrmAbout._Collaborator": "Collaborator:", + "FrmQuickSetup._ConfirmCloseProcess": "לפני החלת ההגדרות החדשות, חובה לסגור את כל תהליכי ImageGlass. האם אתה רוצה להמשיך?", + "FrmExportFrames._ExportDone": "Exported {0} frames successfully to \r\n{1}", + "FrmCrop.BtnSaveAs._Tooltip": "Save as a copy…", + "FrmMain.MnuOpenFile": "פתח קובץ…", + "FrmColorPickerSettings.ChkShowRgbA": "Use RGB format with alpha value", + "_.ImageInfo._ListCount": "{0} קבצים", + "FrmMain.MnuGoToLast": "Go to last image", + "FrmSettings._EditApps._AppName": "שם היישום", + "FrmSettings._SlideshowBackgroundColor": "Slideshow background color", + "FrmAbout._Email": "דוא\"ל:", + "_.MouseWheelAction._DoNothing": "אל תעשה דבר", + "FrmMain.MnuSaveAs": "שמירה בשם…", + "FrmMain._Loading": "טוען…", + "_._Browse": "דפדף…", + "FrmMain.MnuSetDefaultPhotoViewer._Error": "Could not set ImageGlass as default photo viewer.", + "FrmSettings.Nav._Language": "שפה", + "FrmQuickSetup._SeeWhatNew": "ראה מה חדש בגירסה זו…", + "FrmSettings._ImageInterpolation._ScaleUp": "When zoom > 100%", + "FrmSettings.Layout._ToolbarContextPosition": "Contextual toolbar position", + "FrmMain.MnuDeleteFromHardDisk": "מחק לצמיתות", + "FrmSettings._EmbeddedThumbnail": "Embedded thumbnail", + "FrmMain.MnuDeleteFromHardDisk._Description": "Are you sure you want to permanently delete this file?", + "FrmMain.MnuScaleToFill": "התאם למילוי המסך", + "FrmCrop.BtnCrop": "חתוך", + "_.AfterEditAppAction._Minimize": "מזער", + "FrmMain.MnuInvertColors": "היפוך צבעים", + "FrmSettings._StartupBoost": "Startup Boost", + "FrmMain.MnuViewFirstFrame": "View first frame", + "_.MouseWheelEvent._CtrlAndScroll": "Hold Ctrl and scroll", + "FrmSettings._HideMainWindowInSlideshow": "Automatically hide main window", + "_.Metadata._FrameCount": "Frames", + "FrmSettings._EnableCopyMultipleFiles": "Enable the copying of multiple files at once", + "FrmMain.MnuFrameless._EnableDescription": "Hold Shift key to move the window.", + "_.ImageOrderBy._ExifDateTaken": "EXIF: Date taken", + "FrmAbout._Credits": "קרדיטים", + "FrmSettings._AddNewFileExtension": "הוסף סיומת קובץ חדשה", + "FrmMain.MnuQuickSetup": "Open ImageGlass Quick Setup", + "FrmMain.MnuSave._Success": "התמונה נשמרה", + "FrmMain.MnuPanLeft": "Pan image left", + "FrmUpdate._StatusChecking": "בודק עדכונים…", + "FrmSettings.Nav._Layout": "פריסה", + "FrmMain.MnuOpenWith": "פתח באמצעות…", + "FrmAbout._Thanks": "תודה מיוחדת ל", + "_._Warning": "אזהרה", + "FrmSettings.Nav._Keyboard": "לוח מקשים", + "FrmSlideshow._PauseSlideshow": "Slideshow is paused.", + "_._Add+": "הוספה…", + "_._Email": "דוא\"ל", + "FrmMain.MnuPanDown": "Pan image down", + "_._Cancel": "ביטול", + "_._OK": "אישור", + "FrmMain.MnuPanRight": "Pan image right", + "_.Position._Right": "ימין", + "_._Icon": "אייקון", + "FrmSettings._ShouldLoadHiddenImages": "Load hidden images", + "_._InvalidAction._Transformation": "ImageGlass does not support rotation, flipping for this image.", + "FrmSettings._MakeDefault": "Make default", + "FrmMain.MnuCopyImageData._Copying": "מעתיק נתוני התמונה. זה ייקח זמן…", + "FrmSettings._UseEmbeddedThumbnailRawFormats": "Load only the embedded thumbnail for RAW formats", + "_.ImageInterpolation._Linear": "Linear", + "FrmSettings._ImageInfoTags": "Image information tags", + "FrmSettings._FileExtensionIcons": "File extension icons", + "FrmMain.MnuEdit._AppNotFound": "לא ניתן היה למצוא את האפליקציה המשויכת לעריכה. אתה יכול להגדיר אפליקציה לעריכת פורמט זה, בהגדרות ImageGlass > עריכה.", + "_.ColorProfileOption._None": "ללא", + "FrmSettings._TotalSupportedFormats": "Total supported formats: {0}", + "FrmSettings._Clipboard": "לוח העתקה", + "_._UserAction._Win32ExeError": "לא ניתן לבצע את הפקודה '{0}'. ודא שהשם נכון.", + "FrmCropSettings.DefaultSelectionType._SelectX": "Select {0}", + "_.AfterEditAppAction._Close": "סגור", + "FrmAbout._LogoDesigner": "מעצב לוגו:", + "_.ImageOrderBy._Name": "שם (ברירת מחדל)", + "FrmMain.MnuRemoveDefaultPhotoViewer._Error": "Could not remove ImageGlass as the default photo viewer.", + "FrmExportFrames._FolderPickerTitle": "Select output folder for exporting image frames", + "FrmAbout._Donate": "תרום", + "FrmMain.MnuFrameNav": "Frame navigation", + "FrmMain.MnuSetLockScreen": "הגדר כרקע למסך הנעילה", + "_._Delete": "מחק", + "FrmMain.MnuViewPrevious": "צפה בתמונה הקודמת", + "_.Position._Top": "למעלה", + "FrmSettings.Toolbar._CurrentButtons": "Current buttons:", + "FrmMain.MnuAbout": "אודות", + "FrmSettings._RemoveDefault": "Remove default", + "_._Description": "תיאור", + "FrmMain.MnuPasteImage._Error": "Could not find image data in the Clipboard", + "FrmMain.MnuSettings": "הגדרות", + "FrmCropSettings._Title": "Crop settings", + "FrmSettings.Toolbar._ToolbarIconHeight": "גודל סימלון בסרגל הכלים", + "FrmSettings._SlideshowInterval._To": "To", + "FrmSettings.Layout._ToolbarPosition": "Toolbar position", + "FrmUpdate._StatusUpdated": "You are using the latest version!", + "FrmMain.MnuExit": "יציאה", + "_._Webview2._Outdated": "WebView2 Runtime שלך ​​אינו נתמך. אנא עדכן לגרסה {0} ואילך.", + "_._Yes": "כן", + "FrmMain.MnuRotateLeft": "סובב שמאלה", + "FrmSettings._EnableStartupBoost": "Enable Startup Boost", + "_.ImageOrderBy._ExifRating": "EXIF: Rating", + "FrmMain.MnuZoomIn": "התקרבות", + "_.Metadata._ColorSpace": "Color space", + "FrmAbout._Version": "גרסה:", + "FrmMain.MnuToggleTopMost._Enable": "Enabled window always on top", + "FrmSettings.Toolbar._AvailableButtons": "Available buttons:", + "FrmMain.MnuSave._Saving": "Saving image…", + "FrmQuickSetup._StandardUser": "Standard user", + "FrmMain.MnuSetLockScreen._Error": "Could not set the viewing image as lock screen image", + "FrmSettings.Nav._Image": "תמונה", + "FrmSettings._Theme._InstallTheme": "Install theme packs", + "FrmSettings._EnableMultiInstances": "אפשר עותקים מרובים של התוכנה", + "FrmMain.MnuCropTool": "חתוך תמונה", + "_._IgCommandExe._DefaultError._Heading": "Invalid commands", + "_._Refresh": "רענן", + "FrmMain.MnuLosslessCompression._Description": "כלי זה משתמש בספריית Magick.NET עבור דחיסה ללא אובדן נתונים, אופטימיזציה של גודל הקובץ. יחליף רק אם הקובץ הדחוס קטן יותר מהמקור.", + "_._MoveDown": "Move down", + "FrmSettings._GetExtensionIconPacks": "Get extension icon packs…", + "FrmSettings._InAppMessageDuration": "In-app message duration (milliseconds)", + "FrmMain.MnuFrameless": "ללא מסגרת", + "_._Reset": "איפוס", + "FrmSettings._ConfigDir": "Configuration location", + "FrmQuickSetup._SettingsWillBeApplied": "Settings will be applied:", + "FrmSettings._UnmanagedSettingReminder": "הגדרה זו אינה מנוהלת על ידי ImageGlass. אל תשכח להשבית אותו לפני שאתה מסיר או מעביר את האפליקציה מכיוון ש-ImageGlass אינו מטפל בזה אוטומטית.", + "FrmMain.MnuClipboard": "לוח העתקה", + "FrmMain.MnuCustomZoom": "זום מותאם אישית…", + "FrmSettings._DisplayLanguage": "Display language", + "FrmMain.MnuPrint._Error": "Could not print the viewing image", + "FrmSettings._ShouldPreserveModifiedDate": "שמר את תאריך שינוי התמונה בעת שמירה", + "FrmSettings._ShowSaveOverrideConfirmation": "Show confirmation dialog when overriding file", + "FrmColorPickerSettings.ChkShowHexA": "Use HEX format with alpha value", + "FrmMain.MnuFullScreen": "מסך מלא", + "FrmSettings._StartupDir": "Startup location", + "FrmSettings._ShowCheckerboardOnlyImageRegion": "Show checkerboard only within the image region", + "FrmMain.MnuClearClipboard._Success": "Cleared clipboard.", + "FrmQuickSetup._Text": "ImageGlass Quick Setup", + "FrmMain.MnuLosslessCompression._Done": "בוצעה דחיסה ללא אובדן.\r\nגודל הקובץ החדש הוא {0}, נשמר {1}.", + "FrmMain.MnuLosslessCompression": "Magick.NET Lossless Compression", + "FrmResize.RadResizeByPercentage": "אחוז", + "FrmSettings._StartupBoost._Disabled": "Startup Boost is disabled", + "FrmMain.MnuToggleCheckerboard": "רקע משובץ", + "FrmSettings._MinEmbeddedThumbnailSize._Height": "גובה", + "FrmSettings.Nav._General": "כללי", + "FrmSettings._ImageLoading": "תמונה נטענת", + "FrmSettings._ShowSlideshowCountdown": "הצג ספירה לאחור במצגת שקפים", + "FrmMain.MnuSave": "שמור", + "FrmMain.MnuMoveToRecycleBin": "Move to the Recycle Bin", + "FrmMain.MnuRefresh": "רענן", + "FrmToolNotFound.LblHeading": "'{0}' is not found!", + "FrmMain.MnuReportIssue": "דווח על בעיה…", + "FrmMain.MnuCopyImageData": "העתק ללוח", + "FrmMain.MnuCheckForUpdate._NewVersion": "!קיימת גירסה חדשה", + "_._Empty": "(empty)", + "FrmSettings._Zooming": "התקרבות", + "FrmMain.MnuCutFile": "Cut file", + "FrmHotkeyPicker.LblHotkey": "Press hotkeys", + "FrmSettings.Layout._Gallery": "גלריה", + "FrmMain.MnuNewWindow": "פתח חלון חדש", + "FrmMain.MnuMoveToRecycleBin._Description": "Do you want to move this file to the Recycle bin?", + "FrmSettings._DefaultPhotoViewer": "Default photo viewer", + "_.Metadata._ExifDateTimeOriginal": "EXIF: DateTimeOriginal", + "FrmMain.MnuRotateRight": "סובב ימינה", + "FrmSettings._MinEmbeddedThumbnailSize": "Minimum size of the embedded thumbnail to be loaded", + "FrmMain.MnuSetDefaultPhotoViewer": "Set default photo viewer", + "FrmMain.MnuImageProperties": "מאפייני תמונה", + "FrmSettings._EnableNavigationButtons": "Show navigation arrow buttons", + "_._Edit": "ערוך", + "FrmSettings._ImageBooster": "Image Booster", + "FrmSettings.Tools._IntegratedWith": "Integrated with {0}", + "_._Next": "הבא", + "FrmExportFrames._OpenOutputFolder": "פתח תיקיית הפלט", + "FrmMain.MnuOpenLocation": "פתח מיקום תמונה", + "FrmMain.MnuLockZoom": "נעל יחס תקריב", + "FrmSettings._StartupBoost._Description": "Preload and run ImageGlass in the background for a few seconds during Windows startup to accelerate the first launch.", + "FrmSettings._WindowBackdrop": "רקע חלון", + "FrmSettings._EnableRealTimeFileUpdate": "Monitor file changes in the viewing folder and update in realtime", + "_._NotSupported": "Unsupported format", + "FrmSettings._Theme._GetMoreThemes": "Get more theme packs…", + "FrmMain.MnuNewWindow._Error": "Cannot open new window because only one instance is allowed", + "FrmMain.MnuZoomOut": "התרחקות", + "FrmSettings.Toolbar._EditButton": "Edit toolbar button", + "FrmMain.MnuCustomZoom._Description": "הזן ערך זום חדש", + "FrmResize.RadResizeByPixels": "פיקסלים", + "FrmMain.MnuEdit": "ערוך את התמונה {0}…", + "FrmSettings.Layout._GalleryPosition": "Gallery position", + "FrmMain.MnuWindowFit": "Window Fit", + "FrmMain._OpenFileDialog": "כל הקבצים הנתמכים", + "FrmSettings._UseRandomIntervalForSlideshow": "השתמש במרווח רנדומלי", + "_.Position._Left": "שמאל", + "FrmSettings._ShouldOpenLastSeenImage": "פתח את התמונה האחרונה", + "_.Position._Bottom": "למטה", + "FrmResize.ChkKeepRatio": "שמר יחס פרופורציונלי", + "FrmMain.MnuGoTo": "לך אל…", + "FrmSlideshow.MnuPauseResumeSlideshow": "Pause/resume slideshow", + "FrmSettings.Tools._Integrated": "משולב", + "FrmSettings._Contributors": "Contributors", + "_.MouseWheelAction._Zoom": "Zoom in / out", + "_._CommandPreview": "תצוגה מקדימה של פקודה", + "FrmSettings._DarkTheme": "כהה", + "_._Hotkeys": "קיצורי מקשים", + "_.Metadata._ExifDateTime": "EXIF: DateTime", + "FrmSettings.Toolbar._Errors._ButtonIdRequired": "Button ID required.", + "FrmSettings._MinEmbeddedThumbnailSize._Width": "רוחב", + "_._Executable": "Executable", + "_.ImageInterpolation._MultiSampleLinear": "Multi-sample linear", + "_._Separator": "מפריד", + "FrmQuickSetup._ProfessionalUser": "משתמש מקצועי", + "FrmMain.MnuFlipVertical": "הפוך אנכית", + "FrmSlideshow._ResumeSlideshow": "Slideshow is resumed.", + "FrmCropSettings.DefaultSelectionType._CustomArea": "Custom area…", + "FrmMain.MnuActualSize": "גודל אמיתי", + "FrmCrop.BtnSaveAs": "שמירה בשם…", + "FrmSettings._InstallNewLanguagePack": "Install new language packs…", + "FrmSlideshow.MnuZoomModes": "Zoom modes", + "FrmMain.MnuTools": "כלים", + "_.ImageInterpolation._Cubic": "Cubic", + "FrmUpdate._LatestVersion": "The latest version: {0}", + "FrmMain.MnuViewNext": "צפה בתמונה הבאה", + "_.MouseWheelEvent._AltAndScroll": "Hold Alt and scroll", + "FrmToolNotFound._Title": "Tool not found", + "FrmCrop.BtnCrop._Tooltip": "Crop the image only", + "FrmSettings.EditAppDialog._AddApp": "Add an app for editing", + "FrmMain.MnuPanning": "סיבוב", + "_._MoveUp": "Move up", + "FrmCropSettings.DefaultSelectionType._SelectAll": "בחר הכל", + "_._Name": "שם", + "FrmColorPickerSettings.ChkShowHslA": "Use HSL format with alpha value", + "FrmMain.MnuToggleImageAnimation": "Start / stop animating image", + "FrmSettings._DisableStartupBoost": "Disable Startup Boost", + "FrmMain.MnuCopyFile._Success": "Copied {0} file(s).", + "FrmMain.MnuSave._ConfirmDescription": "ImageGlass is not a professional photo editor, please be aware of losing the quality, metadata, layers,… when saving your image.", + "FrmToolNotFound.BtnSelectExecutable": "בחר…", + "FrmUpdate._StatusOutdated": "עדכון חדש זמין!", + "_.ImageOrderBy._Random": "אקראי", + "FrmResize.LblCurrentSize": "גודל נוכחי:", + "_._Apply": "החל", + "FrmAbout._Slogan": "צפין תמונות קל משקל ומגוון", + "FrmMain.MnuPanToTop": "Pan image to top", + "FrmSettings.Toolbar._AddNewButton": "Add a custom toolbar button", + "FrmCrop.LblSize": "גודל:", + "FrmSettings._ImageInterpolation._ScaleDown": "When zoom < 100%", + "_._CreatingFileError": "Could not create temporary image file", + "FrmMain.MnuGoTo._Description": "Enter the image index to view, and then press ENTER", + "FrmSettings.Toolbar._EnableCenterToolbar": "Use center alignment for toolbar", + "FrmMain.MnuResizeTool": "שנה גודל תמונה", + "FrmSettings.Layout._Toolbar": "סרגל כלים", + "FrmMain.MnuHelp": "עזרה", + "_.ImageOrderBy._FileSize": "File size", + "FrmSettings._Theme._OpenThemeFolder": "פתח תיקית ערכות נושא", + "FrmMain.MnuNavigation": "ניווט", + "_._Save": "שמור", + "FrmQuickSetup._SettingProfileDescription": "To modify these settings, simply access app settings.", + "_._UserAction._MenuNotFound": "Cannot find menu '{0}' to invoke the action", + "FrmMain.MnuPanToLeftSide": "Pan image to left edge", + "FrmUpdate._CurrentVersion": "Current version: {0}", + "FrmCrop.BtnSettings._Tooltip": "Open Crop tool settings", + "_.ColorProfileOption._Custom": "התאמה אישית…", + "FrmSettings._UseEmbeddedThumbnailOtherFormats": "Load only the embedded thumbnail for other formats", + "FrmMain.MnuGoToFirst": "Go to first image", + "FrmSettings._ExportLanguagePack": "Export language pack…", + "FrmSettings.Nav._Mouse": "עכבר", + "_.ImageOrderBy._DateCreated": "Date created", + "FrmSettings._EnableFullscreenSlideshow": "Start slideshow in Full Screen mode", + "FrmAbout._Homepage": "דף הבית:", + "FrmSettings._GalleryCacheSizeInMb": "Maximum gallery cache size (in megabytes)", + "FrmMain.MnuCopyImageData._Success": "Copied the current image data.", + "FrmSettings._EnableLoopBackNavigation": "Loop back to the first image when reaching the end of the image list", + "_.MouseWheelEvent._Scroll": "Scroll", + "FrmCrop.BtnSave._Tooltip": "שמור תמונה", + "FrmMain.MnuSlideshow": "מצגת שקופיות", + "FrmMain.MnuShare": "שתף…", + "FrmSettings._SlideshowNotification": "Slideshow notification", + "FrmMain.MnuViewChannels": "הצג ערוצים", + "FrmSettings._Refresh": "רענן", + "_._UserAction._MethodNotFound": "Cannot find method '{0}' to invoke the action", + "FrmMain.MnuCopyFile": "העתק קובץ", + "_._CreatingFile": "Creating a temporary image file…", + "FrmMain.MnuToggleTopMost": "השאר חלון מעל כל החלונות", + "FrmMain.MnuLosslessCompression._Confirm": "Are you sure you want to proceed?", + "FrmMain.MnuImage": "תמונה", + "FrmSettings._StartupBoost._Enabled": "Startup Boost is enabled", + "FrmQuickSetup._SetDefaultViewer": "Do you want to set ImageGlass as the default photo viewer?", + "FrmMain.MnuScaleToWidth": "התאם גודל לפי רוחב", + "_._FileExtension": "סיומת קובץ", + "FrmUpdate._PublishedDate": "Published date: {0}", + "_._DoNotShowThisMessageAgain": "Do not show this message again", + "_.ImageInterpolation._NearestNeighbor": "Nearest neighbor", + "FrmCrop.LblLocation": "מיקום:", + "_._Download": "הורדה", + "_.Metadata._ColorProfile": "פרופיל צבע", + "FrmSettings._CenterWindowFit": "Automatically center the window in Window Fit mode", + "FrmSettings._ImageLoadingOrder": "סדר טעינת התמונות", + "FrmSettings._GalleryColumns": "Number of thumbnail columns in vertical gallery layout", + "_._Quit": "צא", + "_._Add": "הוספה", + "FrmMain.MnuChangeBackgroundColor": "שנה צבע רקע…", + "FrmMain.MnuToggleToolbar": "סרגל כלים", + "FrmAbout._Contact": "צור קשר", + "FrmSettings.Toolbar._AddCustomButton": "Add a custom button…", + "FrmCrop.BtnQuickSelect._Tooltip": "צא מהבחירה…", + "FrmMain.MnuCutFile._Success": "גזור {0} קבצים.", + "FrmSettings._ZoomSpeed": "Zoom speed", + "FrmMain.MnuToggleTopMost._Disable": "Disabled window always on top", + "FrmSettings._ShouldUseExplorerSortOrder": "השתמש בסדר המיון של סייר הקבצים אם אפשר", + "_.ImageInterpolation._Antisotropic": "Antisotropic", + "FrmMain._ReachedFirstImage": "הגעת לתמונה הראשונה", + "_._UnhandledException": "Unhandled exception", + "FrmResize.LblNewSize": "גודל חדש:", + "FrmMain._ClipboardImage": "Clipboard image", + "FrmMain.MnuExportFrames": "Export image frames…", + "FrmMain.MnuFile": "קובץ", + "_._Close": "סגור", + "FrmMain.MnuMain": "תפריט ראשי", + "_._ResetToDefault": "אפס לברירת מחדל", + "FrmSettings.Nav._Gallery": "גלריה", + "FrmMain.MnuSetDefaultPhotoViewer._Success": "You have successfully set ImageGlass as default photo viewer.", + "FrmSettings._HideGalleryInFullscreen": "הסתר גלריה במצב מסך מלא", + "FrmSettings._AvailableImageInfoTags": "Available tags:", + "FrmExportFrames._Exporting": "Exporting {0}/{1} frames \r\n{2}…", + "_._Argument": "Argument", + "FrmSettings._ImageEditQuality": "איכות תמונה", + "_._ID": "ID", + "FrmSettings._UserConfigFile": "User settings file (igconfig.json)", + "FrmMain.MnuLoadingOrders": "Loading orders", + "FrmSettings._OpenSaveAsDialogInTheCurrentImageDir": "Open the Save As dialog in the current image directory", + "_.MouseWheelEvent._ShiftAndScroll": "Hold Shift and scroll", + "FrmSettings._UseSmoothZooming": "Use smooth zooming", + "FrmSettings._Theme": "ערכת נושא", + "FrmSettings._ImageBoosterCacheMaxDimension": "Maximum image dimension to be cached (in pixels)", + "FrmMain.MnuScaleToHeight": "התאם גודל לפי גובה", + "_.Metadata._FileLastWriteTime": "תאריך שינוי", + "FrmSettings._Author": "מחבר", + "FrmSettings._Others": "אחרים", + "_.MouseWheelAction._PanVertically": "Pan up / down", + "FrmSettings._MouseWheelAction": "פעולת גלגל עכבר", + "FrmSettings.Nav._Tools": "כלים", + "FrmMain.MnuSetDesktopBackground._Error": "Could not set the viewing image as desktop background", + "FrmSettings.Toolbar._Errors._ButtonExecutableRequired": "Button executable required.", + "_.ImageOrderBy._DateAccessed": "Date accessed", + "FrmSettings._ThumbnailSize": "Thumbnail size (in pixels)", + "FrmSettings._FileFormats": "File formats", + "FrmMain.MnuReloadImageList": "טען רשימת תמונות מחדש", + "FrmSettings._UseWebview2ForSvg": "Use Webview2 for viewing SVG format", + "FrmCrop.BtnCopy": "העתק", + "FrmSettings._CurrentMonitorProfile._Description": "ImageGlass does not auto-update the color when moving its window between monitors", + "FrmMain.PicMain._ErrorText": "Could not open this image", + "FrmSettings.Tools._AddNewTool": "Add an external tool", + "FrmMain.MnuRename": "שנה שם תמונה…", + "FrmMain.MnuViewLastFrame": "View last frame", + "_._Webview2._NotFound": "אנא התקן את הגרסה האחרונה של WebView2 Runtime.", + "FrmMain.MnuGetMoreTools": "קבל כלים נוספים…", + "FrmSettings.Nav._Appearance": "Appearance", + "FrmSettings._SlideshowInterval": "Slideshow interval:", + "_.ImageInterpolation._HighQualityBicubic": "High quality bicubic", + "FrmColorPickerSettings.ChkShowHsvA": "Use HSV format with alpha value", + "FrmSettings.Tools._EditTool": "Edit external tool", + "_._Error": "שגיאה", + "FrmSettings._ImageBoosterCacheMaxFileSizeInMb": "Maximum image file size to be cached (in megabytes)", + "_._UnhandledException._Description": "אירעה חריגה שלא טופלה. אם תלחץ על המשך, היישום יתעלם משגיאה זו ותנסה להמשיך. אם תלחץ על 'צא', היישום ייסגר מיד.", + "_.Metadata._FileSize": "File size", + "FrmSettings.Toolbar._ButtonJson": "Button JSON", + "FrmQuickSetup._SetDefaultViewer._Description": "You can reset it in the app settings > File type associations tab.", + "FrmSettings.Nav._Edit": "ערוך", + "FrmMain.MnuToggleGallery": "פאנל גלריה", + "_._IgCommandExe._DefaultError._Description": "ודא שאתה מעביר את הפקודות הנכונות!\r\nקובץ ההפעלה הזה מכיל פונקציות שורת פקודה עבור תוכנת ImageGlass.\r\n\r\nכדי להכיר את כל אפשרויות שורת הפקודה, בקר בכתובת:\n{0}", + "FrmMain.MnuLosslessCompression._Compressing": "Performing lossless compression…", + "FrmSettings._ShouldGroupImagesByDirectory": "קבץ תמונות לפי ספריה", + "FrmMain.MnuPanToRightSide": "Pan image to right edge", + "_.Metadata._ExifRatingPercent": "Rating", + "FrmSettings._PanSpeed": "Panning speed", + "_._CheckForUpdate": "בדוק אם יש עדכונים…", + "FrmSettings.Layout._ToolbarContext": "Contextual toolbar", + "_.ImageInfo._FrameCount": "{0} frame(s)", + "FrmMain.MnuLayout": "פריסה", + "_._Website": "אתר", + "FrmMain.MnuPasteImage": "Paste image", + "FrmSettings._ShowGalleryScrollbars": "הצג את סרגלי הגלילה של הגלריה" + } +} \ No newline at end of file diff --git a/Setup/Assets/Language/Hungarian.iglang.json b/Setup/Assets/Language/Hungarian.iglang.json new file mode 100644 index 000000000..cb2db38f6 --- /dev/null +++ b/Setup/Assets/Language/Hungarian.iglang.json @@ -0,0 +1,504 @@ +{ + "_Metadata": { + "Code": "hu-HU", + "EnglishName": "Hungarian", + "LocalName": "Magyar", + "Author": "John Fowler", + "MinVersion": "9.3" + }, + "Items": { + "FrmCrop.SelectionAspectRatio._Original": "Eredeti", + "FrmMain.MnuShare._Error": "Nem sikerült megnyitni a Megosztás párbeszédpanelt.", + "_.Metadata._FileLastAccessTime": "Hozzáférés ideje", + "FrmAbout._License": "Szoftver licenc", + "FrmSettings.Toolbar._Errors._ButtonIdDuplicated": "'{0}' azonosítóval rendelkező gomb már definiálva lett. Kérjük, válasszon egy másik és egyedi azonosítót a gombhoz, hogy elkerülje az ütközéseket.", + "FrmMain.MnuSave._Confirm": "Biztos benne, hogy felül akarja írni ezt a képet?", + "FrmSettings._OpenDefaultAppsSetting": "Nyissa meg az Alapértelmezett alkalmazások beállítást", + "FrmMain.MnuCopyPath": "Kép útvonalának másolása", + "FrmCropSettings.DefaultSelectionType._SelectNone": "Nincs kiválasztás", + "_.MouseWheelAction._PanHorizontally": "Pásztázás balra/jobbra", + "FrmMain.MnuPrint": "Nyomtatás…", + "FrmSettings.Toolbar._ToolbarButtons": "Eszköztár gombok", + "FrmResize.LblResample": "Újra mintavételezés:", + "_.ImageOrderBy._Extension": "Kiterjesztés", + "FrmSettings.Nav._Viewer": "Nézegető", + "FrmSettings.EditAppDialog._EditApp": "Alkalmazás szerkesztése", + "FrmCrop.BtnReset._Tooltip": "Kiválasztás visszaállítása", + "FrmMain.MnuRename._Description": "Írjon be egy új fájlnevet:", + "_._No": "Nem", + "FrmSlideshow.MnuToggleCountdown": "Bemutató-visszaszámlálás mutatása", + "FrmSettings._OpenStartupAppsSetting": "Nyissa meg az Indítóalkalmazások beállítását", + "FrmMain.MnuViewPreviousFrame": "Előző képkocka megtekintése", + "_.ImageOrderBy._DateModified": "Módosítás dátuma", + "FrmMain.MnuViewNextFrame": "Következő képkocka megtekintése", + "FrmMain.MnuUnload": "Kép eltávolítása", + "FrmSettings.Toolbar._HideToolbarInFullscreen": "Eszköztár elrejtése teljes képernyős módban", + "_.ImageOrderType._Desc": "Csökkenő", + "_._Update": "Frissítés", + "FrmSettings._EnableImageAsyncLoading": "Kép aszinkron betöltésének engedélyezése", + "FrmSettings._DefaultPhotoViewer._Description": "Regisztrálja az ImageGlass támogatott formátumait a Windows rendszerben. Előfordulhat, hogy meg kell nyitnia az Alapértelmezett alkalmazások beállításait, és manuálisan kell kiválasztania az ImageGlass-t a listából, hogy érvénybe lépjen.", + "_.MouseWheelAction._BrowseImages": "Következő / előző kép megtekintése", + "FrmSettings._EditApps": "Képszerkesztő alkalmazások", + "FrmColorPickerSettings.ChkShowCIELabA": "CIELAB formátum használata alfa értékkel", + "_._GetHelp": "Segítség kérése", + "FrmQuickSetup._SkipQuickSetup": "Hagyja ki, és indítsa el az ImageGlass-t", + "FrmColorPickerSettings._Title": "Színválasztó beállításai", + "_._Copy": "Másolás", + "FrmSettings._ImageBoosterCacheCount": "Az Képnövelő által gyorsítótárazott képek száma (egy irányban)", + "FrmMain.MnuPanToBottom": "Képpásztázás lentre", + "FrmMain.MnuZoom": "Nagyítás", + "FrmCropSettings.ChkCloseToolAfterSaving": "Zárja be a Vágás eszközt mentés után", + "FrmSettings._ShowWelcomeImage": "Üdvözlő kép megjelenítése", + "FrmSettings._ColorProfile": "Színprofil", + "FrmSettings._Theme._UninstallTheme": "Témacsomag eltávolítása", + "FrmMain._OpenWith": "{0} megnyitása", + "FrmMain.MnuRemoveDefaultPhotoViewer": "Távolítsa el az alapértelmezett fotónézegetőt", + "_.AfterEditAppAction._Nothing": "Semmi", + "FrmCrop.BtnSave": "Mentés", + "FrmMain.MnuScaleToFit": "Méretre igazítás", + "FrmToolNotFound.LblDownloadToolText": "Az ImageGlass további eszközeit a következő címről töltheti le:", + "_._LearnMore": "Tudj meg többet…", + "FrmCrop.LblAspectRatio": "Képarány:", + "FrmExportFrames._FileNotExist": "A képfájl nem létezik", + "FrmSettings._LightTheme": "Világos", + "FrmSettings.Nav._Slideshow": "Diavetítés", + "_._Continue": "Folytatás", + "_._AddHotkey": "Gyorsbillentyű hozzáadása…", + "FrmMain.MnuSetDesktopBackground": "Beállítás asztal hátterképnek", + "FrmMain.MnuReload": "Kép újratöltése", + "FrmSlideshow.MnuExitSlideshow": "Kilépés a diavetítésből", + "FrmMain.MnuAutoZoom": "Automatikus nagyítás", + "FrmSettings._ShowImagePreview": "A kép előnézetének megjelenítése betöltés közben", + "FrmCrop.BtnCopy._Tooltip": "Másolja a kijelölést a vágólapra", + "FrmSettings.Nav._Toolbar": "Eszköztár", + "FrmMain.MnuSave._Error": "Nem sikerült menteni a képet", + "FrmSettings._AfterEditingAction": "Szerkesztő alkalmazás megnyitása után", + "FrmSettings._ShouldUseColorProfileForAll": "Alkalmazza a színprofil nélkül beágyazott képekre is", + "FrmCropSettings.DefaultSelectionType._UseTheLastSelection": "Az utolsó kiválasztás használata", + "FrmSettings._SlideshowInterval._From": "Ettől", + "FrmSettings._ImageInterpolation": "Kép interpoláció", + "FrmQuickSetup._StepInfo": "{0} lépés", + "FrmMain.MnuColorPicker": "Színválasztó", + "FrmCrop.SelectionAspectRatio._FreeRatio": "Szabad arány", + "FrmSettings._ResetSettings": "Beállítások visszaállítása", + "FrmSettings._Startup": "Indítás", + "_.BackdropStyle._None": "Egyik sem", + "FrmSettings._LoadDefaultZoomLevels": "Alapértelmezett nagyítási szintek betöltése", + "FrmColorPicker.BtnSettings._Tooltip": "Nyissa meg a Színválasztó beállításait…", + "FrmSettings._UseThemeForDarkMode": "Használja ezt a témát sötét módban", + "FrmSettings._ShowDeleteConfirmation": "Megerősítő párbeszédpanel megjelenítése fájl törlésekor", + "FrmSettings._ShowAppIcon": "Alkalmazás ikon megjelenítése a címsorban", + "_._InvalidAction": "Érvénytelen művelet", + "FrmQuickSetup._SelectProfile": "Profil kiválasztása", + "_.Metadata._FileCreationTime": "Létrehozás dátuma", + "FrmSettings._SlideshowImagesToNotifySound": "Az értesítési hangot kiváltó képek száma", + "FrmSettings._BackgroundColor": "Néző háttérszíne", + "FrmSettings._RealTimeFileUpdate": "Valós idejű fájlfrissítés", + "_.ColorProfileOption._CurrentMonitorProfile": "Aktuális monitor profil", + "FrmSettings._EnableCutMultipleFiles": "Engedélyezze több fájl egyidejű kivágását", + "FrmSettings._AutoUpdate": "Frissítés automatikus ellenőrzése", + "FrmCropSettings.LblDefaultSelection": "Alapértelmezett kiválasztás", + "FrmSettings._UseThemeForLightMode": "Használja ezt a témát a világos módhoz", + "FrmSettings._ZoomLevels": "Nagyítási szintek", + "FrmMain.MnuSetLockScreen._Success": "A zárolási képernyő képe frissült", + "FrmSettings._ShowGalleryFileName": "Miniatűr fájlnév megjelenítése", + "FrmSettings.Layout._Order": "Rendelés", + "FrmCropSettings.ChkAutoCenterSelection": "Automatikus középre helyezés", + "FrmSettings.Nav._FileTypeAssociations": "Fájltípus-társítások", + "_._Back": "Előző", + "FrmMain.MnuSetDesktopBackground._Success": "Az asztal háttere frissült", + "FrmSettings._ShouldAutoOpenNewAddedImage": "Az új hozzáadott kép automatikus megnyitása", + "FrmCrop.SelectionAspectRatio._Custom": "Egyéni…", + "FrmMain.MnuCopyPath._Success": "Kimásolta az aktuális képútvonalat.", + "FrmSettings._StartupBoost._Error": "Nem sikerült módosítani az Indítási gyorsítás beállítást", + "FrmToolNotFound.LblDescription": "'{0}' futtatható fájl elérési útvonalát az ImageGlass nem tudta megtalálni. '{0}' elérési útvonalát szükség szerint frissítse a probléma megoldásához.", + "FrmMain.MnuClearClipboard": "Vágólap törlése", + "FrmSettings._ColorManagement": "Színkezelő", + "FrmMain._ReachedLastLast": "Elérte az utolsó képet", + "FrmMain.MnuPanUp": "Képpásztázó fent", + "FrmMain.MnuRemoveDefaultPhotoViewer._Success": "Az ImageGlass már nem az alapértelmezett fényképnézegető.", + "FrmSettings._GetMoreLanguagePacks": "További nyelvi csomagok beszerzése…", + "FrmAbout._Privacy": "Adatvédelem", + "FrmSettings._EnableRecursiveLoading": "Képek betöltése almappákból", + "_._UserAction._MethodArgumentNotSupported": "A(z) '{0}' metódus argumentum típusa nem támogatott", + "FrmSettings._FileExtensionIcons._Description": "A fájlkiterjesztés ikonjainak testreszabásához töltsön le egy ikoncsomagot, helyezze az összes .ICO fájlt a kiterjesztés ikonjainak mappájába, és kattintson a '{0}' gombra. Ez az ImageGlass-t is beállítja alapértelmezett fényképnézegetőnek.", + "_.ImageOrderType._Asc": "Növekvő", + "FrmExportFrames._Title": "Képkockák exportálása", + "_._Install": "Telepítés…", + "FrmMain.MnuFlipHorizontal": "Vízszintes tükrözés", + "FrmSettings._OpenExtensionIconFolder": "Bővítmény ikon mappa megnyitása", + "FrmAbout._Collaborator": "Közreműködő:", + "FrmQuickSetup._ConfirmCloseProcess": "Az új beállítások alkalmazása előtt elengedhetetlen az összes ImageGlass folyamat bezárása. Készen áll a folytatásra?", + "FrmExportFrames._ExportDone": "Sikeresen exportált {0} képkockát a \n{1}", + "FrmCrop.BtnSaveAs._Tooltip": "Mentés másolatként…", + "FrmMain.MnuOpenFile": "Fájl megnyitása…", + "FrmColorPickerSettings.ChkShowRgbA": "Használjon RGB formátumot Alfa értékkel", + "_.ImageInfo._ListCount": "{0} fájl", + "FrmMain.MnuGoToLast": "Ugrás az utolsó képre", + "FrmSettings._EditApps._AppName": "Alkalmazás neve", + "FrmSettings._SlideshowBackgroundColor": "Diavetítés háttérszíne", + "FrmAbout._Email": "E-mail:", + "_.MouseWheelAction._DoNothing": "Ne csináljon semmit", + "FrmMain.MnuSaveAs": "Mentés másként…", + "FrmMain._Loading": "Betöltés…", + "_._Browse": "Böngészés…", + "FrmMain.MnuSetDefaultPhotoViewer._Error": "Nem sikerült beállítani az Imageglass-t alapértelmezett fotónézőként.", + "FrmSettings.Nav._Language": "Nyelv", + "FrmQuickSetup._SeeWhatNew": "A verzió újdonságai…", + "FrmSettings._ImageInterpolation._ScaleUp": "Ha a nagyítás > 100%", + "FrmSettings.Layout._ToolbarContextPosition": "Környezetfüggő eszköztár pozíciója", + "FrmMain.MnuDeleteFromHardDisk": "Végleges törlés", + "FrmSettings._EmbeddedThumbnail": "Beágyazott miniatűr", + "FrmMain.MnuDeleteFromHardDisk._Description": "Biztosan törölni szeretné ezt a fájlt?", + "FrmMain.MnuScaleToFill": "Méretezés a kitöltéshez", + "FrmCrop.BtnCrop": "Vágás", + "_.AfterEditAppAction._Minimize": "Minimalizálás", + "FrmMain.MnuInvertColors": "Színek megfordítása", + "FrmSettings._StartupBoost": "Indítási támogatás", + "FrmMain.MnuViewFirstFrame": "Első képkocka megtekintése", + "_.MouseWheelEvent._CtrlAndScroll": "Tartsa lenyomva a Ctrl billentyűt, és görgessen", + "FrmSettings._HideMainWindowInSlideshow": "Főablak automatikus elrejtése", + "_.Metadata._FrameCount": "Képkockák", + "FrmSettings._EnableCopyMultipleFiles": "Engedélyezze több fájl másolását egyszerre", + "FrmMain.MnuFrameless._EnableDescription": "Tartsa lenyomva a Shift billentyűt az ablak mozgatásához.", + "_.ImageOrderBy._ExifDateTaken": "EXIF: Felvétel dátuma", + "FrmAbout._Credits": "Kreditek", + "FrmSettings._AddNewFileExtension": "Új fájlkiterjesztés hozzáadása", + "FrmMain.MnuQuickSetup": "Az ImageGlass gyors beállításának megnyitása", + "FrmMain.MnuSave._Success": "A kép elmentésre kerül", + "FrmMain.MnuPanLeft": "Kép pásztázása balra", + "FrmUpdate._StatusChecking": "Frissítés keresése…", + "FrmSettings.Nav._Layout": "Elrendezés", + "FrmMain.MnuOpenWith": "Megnyitás ezzel…", + "FrmAbout._Thanks": "Külön köszönet", + "_._Warning": "Figyelmeztetés", + "FrmSettings.Nav._Keyboard": "Billentyűzet", + "FrmSlideshow._PauseSlideshow": "A diavetítés szünetel.", + "_._Add+": "Hozzáadás…", + "_._Email": "E-mail", + "FrmMain.MnuPanDown": "Kép pásztázása lefelé", + "_._Cancel": "Mégse", + "_._OK": "OK", + "FrmMain.MnuPanRight": "Kép pásztázása jobbra", + "_.Position._Right": "Jobb", + "_._Icon": "Ikon", + "FrmSettings._ShouldLoadHiddenImages": "Rejtett képek betöltése", + "_._InvalidAction._Transformation": "Az ImageGlass nem támogatja a kép elforgatását, tükrözését.", + "FrmSettings._MakeDefault": "Legyen alapértelmezett", + "FrmMain.MnuCopyImageData._Copying": "A képadatok másolása. Eltart egy ideig…", + "FrmSettings._UseEmbeddedThumbnailRawFormats": "Csak a beágyazott bélyegkép betöltése RAW formátumokhoz", + "_.ImageInterpolation._Linear": "Lineáris", + "FrmSettings._ImageInfoTags": "Képinformációs címkék", + "FrmSettings._FileExtensionIcons": "Fájlkiterjesztési ikonok", + "FrmMain.MnuEdit._AppNotFound": "Nem található a kapcsolódó alkalmazás szerkesztéshez. A formátum szerkesztéséhez az ImageGlass beállításaiban > a Szerkesztésben rendelhet hozzá egy alkalmazást.", + "_.ColorProfileOption._None": "Nincs", + "FrmSettings._TotalSupportedFormats": "Összes támogatott formátum: {0}", + "FrmSettings._Clipboard": "Vágólap", + "_._UserAction._Win32ExeError": "'{0}' parancs nem hajtható végre. Győződjön meg róla, hogy helyes nevet adott meg.", + "FrmCropSettings.DefaultSelectionType._SelectX": "{0} kiválasztás", + "_.AfterEditAppAction._Close": "Bezárás", + "FrmAbout._LogoDesigner": "Logótervező:", + "_.ImageOrderBy._Name": "Név (alapértelmezett)", + "FrmMain.MnuRemoveDefaultPhotoViewer._Error": "Nem sikerült eltávolítani az ImageGlass-t alapértelmezett fényképnézegetőként.", + "FrmExportFrames._FolderPickerTitle": "Válassza ki a kimeneti mappát a képkeretek exportálásához", + "FrmAbout._Donate": "Támogatás", + "FrmMain.MnuFrameNav": "Keret navigáció", + "FrmMain.MnuSetLockScreen": "Beállítás zárolási képernyő képként", + "_._Delete": "Törlés", + "FrmMain.MnuViewPrevious": "Előző kép megtekintése", + "_.Position._Top": "Fent", + "FrmSettings.Toolbar._CurrentButtons": "Jelenlegi gombok:", + "FrmMain.MnuAbout": "Névjegy", + "FrmSettings._RemoveDefault": "Alapértelmezett eltávolítása", + "_._Description": "Leírás", + "FrmMain.MnuPasteImage._Error": "Nem található képadat a vágólapon", + "FrmMain.MnuSettings": "Beállítások", + "FrmCropSettings._Title": "Vágási beállítások", + "FrmSettings.Toolbar._ToolbarIconHeight": "Eszköztár ikon mérete", + "FrmSettings._SlideshowInterval._To": "Eddig", + "FrmSettings.Layout._ToolbarPosition": "Eszköztár helyzete", + "FrmUpdate._StatusUpdated": "A legújabb verziót használja!", + "FrmMain.MnuExit": "Kilépés az alkalmazásból", + "_._Webview2._Outdated": "Az Ön WebView2 futtatókörnyezete nem támogatott. Kérjük, frissítse {0} vagy újabb verzióra.", + "_._Yes": "Igen", + "FrmMain.MnuRotateLeft": "Forgatás balra", + "FrmSettings._EnableStartupBoost": "Indítási támogatás engedélyezése", + "_.ImageOrderBy._ExifRating": "EXIF: Értékelés", + "FrmMain.MnuZoomIn": "Nagyítás", + "_.Metadata._ColorSpace": "Színtér", + "FrmAbout._Version": "Verzió:", + "FrmMain.MnuToggleTopMost._Enable": "Ablak mindig felül van engedélyezése", + "FrmSettings.Toolbar._AvailableButtons": "Elérhető gombok:", + "FrmMain.MnuSave._Saving": "Kép mentése…", + "FrmQuickSetup._StandardUser": "Általános jogú felhasználó", + "FrmMain.MnuSetLockScreen._Error": "Nem tudta beállítani a képet a képernyő zárolásának képeként", + "FrmSettings.Nav._Image": "Kép", + "FrmSettings._Theme._InstallTheme": "Témacsomagok telepítése", + "FrmSettings._EnableMultiInstances": "Alkalmazás több példányban is futhat", + "FrmMain.MnuCropTool": "Kép vágása", + "_._IgCommandExe._DefaultError._Heading": "Érvénytelen parancsok", + "_._Refresh": "Frissítés", + "FrmMain.MnuLosslessCompression._Description": "Ez az eszköz Magick.NET könyvtárat használ a veszteségmentes tömörítéshez, optimalizálva a fájlméretet. Csak akkor írja felül, ha a tömörített fájl kisebb, mint az eredeti.", + "_._MoveDown": "Lejjebb", + "FrmSettings._GetExtensionIconPacks": "Ikoncsomagok bővítmények beszerzése…", + "FrmSettings._InAppMessageDuration": "Az alkalmazáson belüli üzenet időtartama (milliszekundum)", + "FrmMain.MnuFrameless": "Keret nélkül", + "_._Reset": "Visszaállítás", + "FrmSettings._ConfigDir": "Beállítás helye", + "FrmQuickSetup._SettingsWillBeApplied": "A beállítások a következők lesznek alkalmazva:", + "FrmSettings._UnmanagedSettingReminder": "Ezt a beállítást az ImageGlass nem kezeli. Ne felejtse el letiltani, mielőtt eltávolítja vagy áthelyezi az alkalmazást, mert az ImageGlass ezt nem kezeli automatikusan.", + "FrmMain.MnuClipboard": "Vágólap", + "FrmMain.MnuCustomZoom": "Egyéni nagyítás…", + "FrmSettings._DisplayLanguage": "Megjelenítés nyelve", + "FrmMain.MnuPrint._Error": "Nem sikerült kinyomtatni a nézett képet", + "FrmSettings._ShouldPreserveModifiedDate": "Őrizd meg a kép módosítási dátumát mentéskor", + "FrmSettings._ShowSaveOverrideConfirmation": "Megerősítő párbeszédpanel megjelenítése a fájl felülírásakor", + "FrmColorPickerSettings.ChkShowHexA": "Használja a HEX formátumot alfa értékkel", + "FrmMain.MnuFullScreen": "Teljes képernyő", + "FrmSettings._StartupDir": "Indítás helye", + "FrmSettings._ShowCheckerboardOnlyImageRegion": "A sakktábla megjelenítése csak a kép régióján belül", + "FrmMain.MnuClearClipboard._Success": "A vágólap kitisztítva.", + "FrmQuickSetup._Text": "ImageGlass gyors beállítás", + "FrmMain.MnuLosslessCompression._Done": "Veszteségmentes tömörítés kész.\r\nAz új fájl mérete {0}, mentve {1}.", + "FrmMain.MnuLosslessCompression": "Magick.NET veszteségmentes tömörítés", + "FrmResize.RadResizeByPercentage": "Százalék", + "FrmSettings._StartupBoost._Disabled": "Indítás támogatás letiltva", + "FrmMain.MnuToggleCheckerboard": "Sakkmintás háttér", + "FrmSettings._MinEmbeddedThumbnailSize._Height": "Magasság", + "FrmSettings.Nav._General": "Általános", + "FrmSettings._ImageLoading": "Kép betöltése", + "FrmSettings._ShowSlideshowCountdown": "Diavetítés visszaszámláló megjelenítése", + "FrmMain.MnuSave": "Mentés", + "FrmMain.MnuMoveToRecycleBin": "Áthelyezés a Lomtárba", + "FrmMain.MnuRefresh": "Frissítés", + "FrmToolNotFound.LblHeading": "'{0}' nem található!", + "FrmMain.MnuReportIssue": "Probléma jelentése…", + "FrmMain.MnuCopyImageData": "Kép adatainak másolása", + "FrmMain.MnuCheckForUpdate._NewVersion": "Új verzió elérhető!", + "_._Empty": "(üres)", + "FrmSettings._Zooming": "Nagyítás", + "FrmMain.MnuCutFile": "Fájl vágása", + "FrmHotkeyPicker.LblHotkey": "Nyomja meg a gyorsbillentyűket", + "FrmSettings.Layout._Gallery": "Galéria", + "FrmMain.MnuNewWindow": "Új ablak megnyitása", + "FrmMain.MnuMoveToRecycleBin._Description": "Szeretné áthelyezni ezt a fájlt a Lomtárba?", + "FrmSettings._DefaultPhotoViewer": "Alapértelmezett fényképnézegető", + "_.Metadata._ExifDateTimeOriginal": "EXIF: DateTimeOriginal", + "FrmMain.MnuRotateRight": "Forgatás jobbra", + "FrmSettings._MinEmbeddedThumbnailSize": "A betöltendő beágyazott miniatűrkép minimális mérete", + "FrmMain.MnuSetDefaultPhotoViewer": "Alapértelmezett fényképnézegető beállítása", + "FrmMain.MnuImageProperties": "Kép tulajdonságok", + "FrmSettings._EnableNavigationButtons": "Navigációs nyílgombok megjelenítése", + "_._Edit": "Szerkesztés", + "FrmSettings._ImageBooster": "Képtámogatás", + "FrmSettings.Tools._IntegratedWith": "Integrálva {0}", + "_._Next": "Következő", + "FrmExportFrames._OpenOutputFolder": "Kimeneti mappa megnyitása", + "FrmMain.MnuOpenLocation": "Kép helyének megnyitása", + "FrmMain.MnuLockZoom": "Nagyítási arány rögzítése", + "FrmSettings._StartupBoost._Description": "Az ImageGlass előretöltése és futtatása a háttérben néhány másodpercig a Windows indításakor, hogy felgyorsítsa az első indítást.", + "FrmSettings._WindowBackdrop": "Ablak háttere", + "FrmSettings._EnableRealTimeFileUpdate": "Fájlváltozások figyelése a megtekintő mappában és valós idejű frissítés", + "_._NotSupported": "Nem támogatott formátum", + "FrmSettings._Theme._GetMoreThemes": "További témacsomagok beszerzése…", + "FrmMain.MnuNewWindow._Error": "Nem lehet új ablakot nyitni, mert csak egy példány engedélyezett", + "FrmMain.MnuZoomOut": "Kicsinyítés", + "FrmSettings.Toolbar._EditButton": "Eszköztár gomb szerkesztése", + "FrmMain.MnuCustomZoom._Description": "Új nagyítási érték megadása", + "FrmResize.RadResizeByPixels": "Képpontok", + "FrmMain.MnuEdit": "Kép {0} szerkesztése…", + "FrmSettings.Layout._GalleryPosition": "Galéria helyzete", + "FrmMain.MnuWindowFit": "Ablak illesztés", + "FrmMain._OpenFileDialog": "Minden támogatott fájl", + "FrmSettings._UseRandomIntervalForSlideshow": "Véletlenszerű intervallum használata", + "_.Position._Left": "Bal", + "FrmSettings._ShouldOpenLastSeenImage": "Az utoljára nézett kép megnyitása", + "_.Position._Bottom": "Lent", + "FrmResize.ChkKeepRatio": "Tartsa meg az arányt", + "FrmMain.MnuGoTo": "Ugrás…", + "FrmSlideshow.MnuPauseResumeSlideshow": "Diavetítés szüneteltetése/folytatása", + "FrmSettings.Tools._Integrated": "Integrált", + "FrmSettings._Contributors": "Közreműködők", + "_.MouseWheelAction._Zoom": "Nagyítás / kicsinyítés", + "_._CommandPreview": "Parancs előnézet", + "FrmSettings._DarkTheme": "Sötét", + "_._Hotkeys": "Gyorsbillentyűk", + "_.Metadata._ExifDateTime": "EXIF: DateTime", + "FrmSettings.Toolbar._Errors._ButtonIdRequired": "Gombazonosító szükséges.", + "FrmSettings._MinEmbeddedThumbnailSize._Width": "Szélesség", + "_._Executable": "Futtatható", + "_.ImageInterpolation._MultiSampleLinear": "Több mintás lineáris", + "_._Separator": "Elválasztó", + "FrmQuickSetup._ProfessionalUser": "Professzionális felhasználó", + "FrmMain.MnuFlipVertical": "Függőleges tükrözés", + "FrmSlideshow._ResumeSlideshow": "A diavetítés folytatódik.", + "FrmCropSettings.DefaultSelectionType._CustomArea": "Egyéni terület…", + "FrmMain.MnuActualSize": "Jelenlegi méret", + "FrmCrop.BtnSaveAs": "Mentés másként…", + "FrmSettings._InstallNewLanguagePack": "Új nyelvi csomagok telepítése…", + "FrmSlideshow.MnuZoomModes": "Nagyítási módok", + "FrmMain.MnuTools": "Eszközök", + "_.ImageInterpolation._Cubic": "Cubic", + "FrmUpdate._LatestVersion": "A legújabb verzió: {0}", + "FrmMain.MnuViewNext": "Következő kép megtekintése", + "_.MouseWheelEvent._AltAndScroll": "Tartsa lenyomva az Alt billentyűt és görgessen", + "FrmToolNotFound._Title": "Az eszköz nem található", + "FrmCrop.BtnCrop._Tooltip": "Csak a kép körülvágása", + "FrmSettings.EditAppDialog._AddApp": "Alkalmazás hozzáadása szerkesztéshez", + "FrmMain.MnuPanning": "Pásztázás", + "_._MoveUp": "Feljebb", + "FrmCropSettings.DefaultSelectionType._SelectAll": "Az összes kijelölése", + "_._Name": "Név", + "FrmColorPickerSettings.ChkShowHslA": "HSL formátum használata alfa értékkel", + "FrmMain.MnuToggleImageAnimation": "Kép animálásának indítása/leállítása", + "FrmSettings._DisableStartupBoost": "Indítási támogatás kikapcsolása", + "FrmMain.MnuCopyFile._Success": "{0} fájl(ok) másolása.", + "FrmMain.MnuSave._ConfirmDescription": "Az ImageGlass nem egy professzionális képszerkesztő program, kérjük, vegye figyelembe, hogy a kép mentésekor elveszíti a minőséget, metaadatokat, rétegeket…", + "FrmToolNotFound.BtnSelectExecutable": "Kiválaszt…", + "FrmUpdate._StatusOutdated": "Új frissítés érhető el!", + "_.ImageOrderBy._Random": "Véletlenszerű", + "FrmResize.LblCurrentSize": "Jelenlegi méret:", + "_._Apply": "Alkalmaz", + "FrmAbout._Slogan": "Egy könnyű, sokoldalú képnézegető", + "FrmMain.MnuPanToTop": "Pásztázás a kép tetejére", + "FrmSettings.Toolbar._AddNewButton": "Egyéni eszköztárgomb hozzáadása", + "FrmCrop.LblSize": "Méret:", + "FrmSettings._ImageInterpolation._ScaleDown": "Amikor a nagyítás < 100%", + "_._CreatingFileError": "Nem sikerült az ideiglenes file létrehozása", + "FrmMain.MnuGoTo._Description": "Adja meg a megtekinteni kívánt képindexet, majd nyomja le az ENTER billentyűt", + "FrmSettings.Toolbar._EnableCenterToolbar": "Eszköztár középre igazítása", + "FrmMain.MnuResizeTool": "Kép átméretezése", + "FrmSettings.Layout._Toolbar": "Eszköztár", + "FrmMain.MnuHelp": "Súgó", + "_.ImageOrderBy._FileSize": "Fájlméret", + "FrmSettings._Theme._OpenThemeFolder": "Téma könyvtár megnyitása", + "FrmMain.MnuNavigation": "Navigáció", + "_._Save": "Mentés", + "FrmQuickSetup._SettingProfileDescription": "A beállítások módosításához egyszerűen nyissa meg az alkalmazás beállításait.", + "_._UserAction._MenuNotFound": "'{0}' menü nem található a feladat végrehajtásához", + "FrmMain.MnuPanToLeftSide": "Kép pásztázása a bal szélére", + "FrmUpdate._CurrentVersion": "Jelenlegi verzió: {0}", + "FrmCrop.BtnSettings._Tooltip": "A Vágás eszköz beállításainak megnyitása", + "_.ColorProfileOption._Custom": "Egyéni…", + "FrmSettings._UseEmbeddedThumbnailOtherFormats": "Csak a beágyazott bélyegkép betöltése más formátumokhoz", + "FrmMain.MnuGoToFirst": "Ugrás az első képre", + "FrmSettings._ExportLanguagePack": "Nyelvi csomag exportálása…", + "FrmSettings.Nav._Mouse": "Egér", + "_.ImageOrderBy._DateCreated": "Létrehozás dátuma", + "FrmSettings._EnableFullscreenSlideshow": "Diavetítés indítása teljes képernyős módban", + "FrmAbout._Homepage": "Honlap:", + "FrmSettings._GalleryCacheSizeInMb": "A galéria gyorsítótárának maximális mérete (megabájtban)", + "FrmMain.MnuCopyImageData._Success": "Kimásolta az aktuális képadatokat.", + "FrmSettings._EnableLoopBackNavigation": "Visszalépés az első képre, amikor eléri a képlista végét", + "_.MouseWheelEvent._Scroll": "Görgetés", + "FrmCrop.BtnSave._Tooltip": "Kép mentése", + "FrmMain.MnuSlideshow": "Diavetítés", + "FrmMain.MnuShare": "Megosztás…", + "FrmSettings._SlideshowNotification": "Diavetítés értesítés", + "FrmMain.MnuViewChannels": "Csatornák megmutatása", + "FrmSettings._Refresh": "Frissítés", + "_._UserAction._MethodNotFound": "'{0}' metódus nem található a feladat végrehajtásához", + "FrmMain.MnuCopyFile": "Fájl másolása", + "_._CreatingFile": "Ideiglenes file létrehozása…", + "FrmMain.MnuToggleTopMost": "Ez az ablak mindig legyen előtérben", + "FrmMain.MnuLosslessCompression._Confirm": "Biztos benne, hogy folytatni akarja?", + "FrmMain.MnuImage": "Kép", + "FrmSettings._StartupBoost._Enabled": "Indítási támogatás engedélyezve", + "FrmQuickSetup._SetDefaultViewer": "Szeretné beállítani az ImageGlass-t alapértelmezett fotónézegetőként?", + "FrmMain.MnuScaleToWidth": "Méretezés a szélességhez", + "_._FileExtension": "Fájlkiterjesztés", + "FrmUpdate._PublishedDate": "Közzététel dátuma: {0}", + "_._DoNotShowThisMessageAgain": "Ne jelenjen meg ismét ez az üzenet", + "_.ImageInterpolation._NearestNeighbor": "Legközelebbi szomszéd", + "FrmCrop.LblLocation": "Hely:", + "_._Download": "Letöltés", + "_.Metadata._ColorProfile": "Színprofil", + "FrmSettings._CenterWindowFit": "Az ablak automatikus középre igazítása Ablakillesztés módban", + "FrmSettings._ImageLoadingOrder": "Kép betöltési sorrend", + "FrmSettings._GalleryColumns": "A függőleges galéria elrendezésben a miniatűr oszlopok száma", + "_._Quit": "Bezárás", + "_._Add": "Hozzáadás", + "FrmMain.MnuChangeBackgroundColor": "Háttérszín módosítása…", + "FrmMain.MnuToggleToolbar": "Eszköztár", + "FrmAbout._Contact": "Kapcsolat", + "FrmSettings.Toolbar._AddCustomButton": "Egyéni gomb hozzáadása…", + "FrmCrop.BtnQuickSelect._Tooltip": "Gyors kiválasztás…", + "FrmMain.MnuCutFile._Success": "{0} fájl kivágása.", + "FrmSettings._ZoomSpeed": "Nagyítás sebessége", + "FrmMain.MnuToggleTopMost._Disable": "Ablak mindig előtérben letiltása", + "FrmSettings._ShouldUseExplorerSortOrder": "Ha lehetséges, használja az Intéző rendezési sorrendjét", + "_.ImageInterpolation._Antisotropic": "Antiszotropikus", + "FrmMain._ReachedFirstImage": "Elérte az első képet", + "_._UnhandledException": "Váratlan kivétel", + "FrmResize.LblNewSize": "Új méret:", + "FrmMain._ClipboardImage": "Vágólap kép", + "FrmMain.MnuExportFrames": "Képkeretek exportálása…", + "FrmMain.MnuFile": "Fájl", + "_._Close": "Bezárás", + "FrmMain.MnuMain": "Főmenü", + "_._ResetToDefault": "Alapbeállítások visszaállítása", + "FrmSettings.Nav._Gallery": "Galéria", + "FrmMain.MnuSetDefaultPhotoViewer._Success": "Sikeresen beállította az ImageGlass-t alapértelmezett fotónézegetőként.", + "FrmSettings._HideGalleryInFullscreen": "Galéria elrejtése teljes képernyős módban", + "FrmSettings._AvailableImageInfoTags": "Elérhető címkék:", + "FrmExportFrames._Exporting": "{0}/{1} képkockák exportálása\n{2}…", + "_._Argument": "Argumentum", + "FrmSettings._ImageEditQuality": "Képminőség", + "_._ID": "ID", + "FrmSettings._UserConfigFile": "Felhasználói beállítások fájlja (igconfig.json)", + "FrmMain.MnuLoadingOrders": "Rendezés betöltéskor", + "FrmSettings._OpenSaveAsDialogInTheCurrentImageDir": "Nyissa meg a Mentés másként párbeszédpanelt az aktuális képkönyvtárban", + "_.MouseWheelEvent._ShiftAndScroll": "Tartsa lenyomva a Shift gombot és görgessen", + "FrmSettings._UseSmoothZooming": "Sima nagyítás használata", + "FrmSettings._Theme": "Téma", + "FrmSettings._ImageBoosterCacheMaxDimension": "A gyorsítótárazandó kép maximális mérete (képpontban)", + "FrmMain.MnuScaleToHeight": "Magasság igazítás", + "_.Metadata._FileLastWriteTime": "Módosítás dátuma", + "FrmSettings._Author": "Szerző", + "FrmSettings._Others": "Egyebek", + "_.MouseWheelAction._PanVertically": "Pásztázás fel / le", + "FrmSettings._MouseWheelAction": "Egérkerék művelet", + "FrmSettings.Nav._Tools": "Eszközök", + "FrmMain.MnuSetDesktopBackground._Error": "Nem tudta beállítani a megjelenített képet asztali háttérként", + "FrmSettings.Toolbar._Errors._ButtonExecutableRequired": "A gomb futtatható programja szükséges.", + "_.ImageOrderBy._DateAccessed": "Hozzáférés ideje", + "FrmSettings._ThumbnailSize": "Miniatűr mérete (képpontban)", + "FrmSettings._FileFormats": "Fájlformátumok", + "FrmMain.MnuReloadImageList": "Képlista újratöltése", + "FrmSettings._UseWebview2ForSvg": "A Webview2 használata az SVG formátum megtekintéséhez", + "FrmCrop.BtnCopy": "Másolás", + "FrmSettings._CurrentMonitorProfile._Description": "ImageGlass nem változtatja magától a színt, amikor az ablaka másik monitorra kerül", + "FrmMain.PicMain._ErrorText": "Nem sikerült megnyitni ezt a képet", + "FrmSettings.Tools._AddNewTool": "Külső eszköz hozzáadása", + "FrmMain.MnuRename": "Kép átnevezése…", + "FrmMain.MnuViewLastFrame": "Utolsó képkocka megtekintése", + "_._Webview2._NotFound": "Kérjük, telepítse a WebView2 futtatókörnyezetet az ImageGlass összes funkciójának eléréséhez.", + "FrmMain.MnuGetMoreTools": "További eszközök beszerzése…", + "FrmSettings.Nav._Appearance": "Megjelenés", + "FrmSettings._SlideshowInterval": "Diavetítés időköze:", + "_.ImageInterpolation._HighQualityBicubic": "Kiváló minőségű bikubikus", + "FrmColorPickerSettings.ChkShowHsvA": "HSV formátum használata alfa értékkel", + "FrmSettings.Tools._EditTool": "Külső eszköz szerkesztése", + "_._Error": "Hiba", + "FrmSettings._ImageBoosterCacheMaxFileSizeInMb": "A gyorsítótárazandó képfájl maximális mérete (megabájtban)", + "_._UnhandledException._Description": "Váratlan kivétel történt. Ha a folytatásra kattint, az alkalmazás figyelmen kívül hagyja a hibát és megpróbálja folytatni a műveletet. Ha a Kilépésre kattint, az alkalmazás azonnal kilép.", + "_.Metadata._FileSize": "Fájlméret", + "FrmSettings.Toolbar._ButtonJson": "JSON gomb", + "FrmQuickSetup._SetDefaultViewer._Description": "Visszaállíthatja az alkalmazásbeállításokban > Fájltípus-társítások lapon.", + "FrmSettings.Nav._Edit": "Szerkesztés", + "FrmMain.MnuToggleGallery": "Galéria panel", + "_._IgCommandExe._DefaultError._Description": "Győződjön meg róla, hogy a megfelelő parancsokat adja át!\r\nEz a futtatható fájl parancssori függvényeket tartalmaz az ImageGlass szoftverhez.\r\n\r\nAz összes parancssor felfedezéséhez látogasson el a következő oldalra:\n{0}", + "FrmMain.MnuLosslessCompression._Compressing": "Veszteségmentes tömörítés végrehajtása…", + "FrmSettings._ShouldGroupImagesByDirectory": "Képek csoportosítása könyvtár szerint", + "FrmMain.MnuPanToRightSide": "Kép pásztázása a jobb szélére", + "_.Metadata._ExifRatingPercent": "Értékelés", + "FrmSettings._PanSpeed": "Pásztázási sebesség", + "_._CheckForUpdate": "Frissítések keresése…", + "FrmSettings.Layout._ToolbarContext": "Környezetfüggő eszköztár", + "_.ImageInfo._FrameCount": "{0} képkocka", + "FrmMain.MnuLayout": "Elrendezés", + "_._Website": "Honlap", + "FrmMain.MnuPasteImage": "Kép beillesztése", + "FrmSettings._ShowGalleryScrollbars": "Galéria görgetősávjainak megjelenítése" + } +} \ No newline at end of file diff --git a/Setup/Assets/Language/Indonesian.iglang.json b/Setup/Assets/Language/Indonesian.iglang.json new file mode 100644 index 000000000..735e1fb32 --- /dev/null +++ b/Setup/Assets/Language/Indonesian.iglang.json @@ -0,0 +1,504 @@ +{ + "_Metadata": { + "Code": "id-ID", + "EnglishName": "Indonesian", + "LocalName": "Bahasa Indonesia", + "Author": "Nicedward (dayat219onlyme)", + "MinVersion": "9.3" + }, + "Items": { + "FrmCrop.SelectionAspectRatio._Original": "Original", + "FrmMain.MnuShare._Error": "Could not open Share dialog.", + "_.Metadata._FileLastAccessTime": "Date accessed", + "FrmAbout._License": "Software license", + "FrmSettings.Toolbar._Errors._ButtonIdDuplicated": "A button with the ID '{0}' has already been defined. Please choose a different and unique ID for your button to avoid conflicts.", + "FrmMain.MnuSave._Confirm": "Are you sure you want to override this image?", + "FrmSettings._OpenDefaultAppsSetting": "Open Default apps setting", + "FrmMain.MnuCopyPath": "Salin jalur gambar", + "FrmCropSettings.DefaultSelectionType._SelectNone": "Select none", + "_.MouseWheelAction._PanHorizontally": "Pan left / right", + "FrmMain.MnuPrint": "Cetak…", + "FrmSettings.Toolbar._ToolbarButtons": "Toolbar buttons", + "FrmResize.LblResample": "Resample:", + "_.ImageOrderBy._Extension": "Ekstensi", + "FrmSettings.Nav._Viewer": "Penampil", + "FrmSettings.EditAppDialog._EditApp": "Edit app", + "FrmCrop.BtnReset._Tooltip": "Reset selection", + "FrmMain.MnuRename._Description": "Enter a new filename:", + "_._No": "No", + "FrmSlideshow.MnuToggleCountdown": "Tampilkan hitung mundur slideshow", + "FrmSettings._OpenStartupAppsSetting": "Open Startup apps setting", + "FrmMain.MnuViewPreviousFrame": "View previous frame", + "_.ImageOrderBy._DateModified": "Date modified", + "FrmMain.MnuViewNextFrame": "View next frame", + "FrmMain.MnuUnload": "Unload image", + "FrmSettings.Toolbar._HideToolbarInFullscreen": "Hide toolbar in Full Screen mode", + "_.ImageOrderType._Desc": "Sortir turun", + "_._Update": "Update", + "FrmSettings._EnableImageAsyncLoading": "Enable image asynchronous loading", + "FrmSettings._DefaultPhotoViewer._Description": "Register the supported formats of ImageGlass with Windows. You might need to open the Default apps settings and manually select ImageGlass from the list for it to take effect.", + "_.MouseWheelAction._BrowseImages": "View next / previous Image", + "FrmSettings._EditApps": "Image editing apps", + "FrmColorPickerSettings.ChkShowCIELabA": "Use CIELAB format with alpha value", + "_._GetHelp": "Get help", + "FrmQuickSetup._SkipQuickSetup": "Skip this and launch ImageGlass", + "FrmColorPickerSettings._Title": "Color picker settings", + "_._Copy": "Salin", + "FrmSettings._ImageBoosterCacheCount": "Number of images cached by Image Booster (one direction)", + "FrmMain.MnuPanToBottom": "Pan image to bottom", + "FrmMain.MnuZoom": "Perbesaran", + "FrmCropSettings.ChkCloseToolAfterSaving": "Close Crop tool after saving", + "FrmSettings._ShowWelcomeImage": "Show welcome image", + "FrmSettings._ColorProfile": "Color profile", + "FrmSettings._Theme._UninstallTheme": "Uninstall a theme pack", + "FrmMain._OpenWith": "Open with {0}", + "FrmMain.MnuRemoveDefaultPhotoViewer": "Remove default photo viewer", + "_.AfterEditAppAction._Nothing": "Tidak ada", + "FrmCrop.BtnSave": "Simpan", + "FrmMain.MnuScaleToFit": "Skala ke pas", + "FrmToolNotFound.LblDownloadToolText": "You can download more tools for ImageGlass at:", + "_._LearnMore": "Learn more…", + "FrmCrop.LblAspectRatio": "Aspect ratio:", + "FrmExportFrames._FileNotExist": "Image file does not exist", + "FrmSettings._LightTheme": "Light", + "FrmSettings.Nav._Slideshow": "Slideshow", + "_._Continue": "Continue", + "_._AddHotkey": "Add hotkey…", + "FrmMain.MnuSetDesktopBackground": "Tetapkan sebagai latar belakang", + "FrmMain.MnuReload": "Muat ulang gambar", + "FrmSlideshow.MnuExitSlideshow": "Keluar slideshow", + "FrmMain.MnuAutoZoom": "Perbesaran otomatis", + "FrmSettings._ShowImagePreview": "Display image preview while it's being loaded", + "FrmCrop.BtnCopy._Tooltip": "Copy the selection to clipboard", + "FrmSettings.Nav._Toolbar": "Tampilkan palang alat", + "FrmMain.MnuSave._Error": "Could not save the image", + "FrmSettings._AfterEditingAction": "Setelah membuka aplikasi pengeditan", + "FrmSettings._ShouldUseColorProfileForAll": "Terpakan juga untuk gambar tanpa profil warna tersendiri", + "FrmCropSettings.DefaultSelectionType._UseTheLastSelection": "Use the last selection", + "FrmSettings._SlideshowInterval._From": "From", + "FrmSettings._ImageInterpolation": "Image interpolation", + "FrmQuickSetup._StepInfo": "Step {0}", + "FrmMain.MnuColorPicker": "Pemilih warna", + "FrmCrop.SelectionAspectRatio._FreeRatio": "Free ratio", + "FrmSettings._ResetSettings": "Reset settings", + "FrmSettings._Startup": "Startup", + "_.BackdropStyle._None": "Tak ada", + "FrmSettings._LoadDefaultZoomLevels": "Load default zoom levels", + "FrmColorPicker.BtnSettings._Tooltip": "Open Color picker settings…", + "FrmSettings._UseThemeForDarkMode": "Use this theme for dark mode", + "FrmSettings._ShowDeleteConfirmation": "Show confirmation dialog when deleting file", + "FrmSettings._ShowAppIcon": "Show app icon on the title bar", + "_._InvalidAction": "Invalid action", + "FrmQuickSetup._SelectProfile": "Select a profile", + "_.Metadata._FileCreationTime": "Date created", + "FrmSettings._SlideshowImagesToNotifySound": "Number of images to trigger a notification sound", + "FrmSettings._BackgroundColor": "Viewer background color", + "FrmSettings._RealTimeFileUpdate": "Real-time file update", + "_.ColorProfileOption._CurrentMonitorProfile": "Current monitor profile", + "FrmSettings._EnableCutMultipleFiles": "Enable the cutting of multiple files at once", + "FrmSettings._AutoUpdate": "Periksa pembaruan secara otomatis", + "FrmCropSettings.LblDefaultSelection": "Default selection", + "FrmSettings._UseThemeForLightMode": "Use this theme for light mode", + "FrmSettings._ZoomLevels": "Tingkat zoom", + "FrmMain.MnuSetLockScreen._Success": "Lock screen image is updated", + "FrmSettings._ShowGalleryFileName": "Show thumbnail filename", + "FrmSettings.Layout._Order": "Order", + "FrmCropSettings.ChkAutoCenterSelection": "Auto-center selection", + "FrmSettings.Nav._FileTypeAssociations": "File type associations", + "_._Back": "Back", + "FrmMain.MnuSetDesktopBackground._Success": "Desktop background is updated", + "FrmSettings._ShouldAutoOpenNewAddedImage": "Open the new added image automatically", + "FrmCrop.SelectionAspectRatio._Custom": "Kostum…", + "FrmMain.MnuCopyPath._Success": "Copied the current image path.", + "FrmSettings._StartupBoost._Error": "Could not change Startup Boost setting", + "FrmToolNotFound.LblDescription": "ImageGlass was unable to locate the path to the '{0}' executable. To resolve this issue, please update the path to the '{0}' as necessary.", + "FrmMain.MnuClearClipboard": "Hapus clipboard", + "FrmSettings._ColorManagement": "Manajemen warna", + "FrmMain._ReachedLastLast": "Mencapai gambar terakhir", + "FrmMain.MnuPanUp": "Pan image up", + "FrmMain.MnuRemoveDefaultPhotoViewer._Success": "ImageGlass is no longer the default photo viewer.", + "FrmSettings._GetMoreLanguagePacks": "Dapatkan lebih banyak paket bahasa…", + "FrmAbout._Privacy": "Privacy policy", + "FrmSettings._EnableRecursiveLoading": "Load images in subfolders", + "_._UserAction._MethodArgumentNotSupported": "The argument type of method '{0}' is not supported", + "FrmSettings._FileExtensionIcons._Description": "For customizing file extension icons, download an icon pack, place all .ICO files in the extension icon folder, and click the '{0}' button. This will also set ImageGlass as default photo viewer.", + "_.ImageOrderType._Asc": "Sortir naik", + "FrmExportFrames._Title": "Export image frames", + "_._Install": "Pasang…", + "FrmMain.MnuFlipHorizontal": "Berbalik Horizontal", + "FrmSettings._OpenExtensionIconFolder": "Open extension icon folder", + "FrmAbout._Collaborator": "Collaborator:", + "FrmQuickSetup._ConfirmCloseProcess": "Before applying the new settings, it's essential to close all ImageGlass processes. Are you ready to proceed?", + "FrmExportFrames._ExportDone": "Exported {0} frames successfully to \r\n{1}", + "FrmCrop.BtnSaveAs._Tooltip": "Save as a copy…", + "FrmMain.MnuOpenFile": "Buka berkas…", + "FrmColorPickerSettings.ChkShowRgbA": "Use RGB format with alpha value", + "_.ImageInfo._ListCount": "{0} file(s)", + "FrmMain.MnuGoToLast": "Go to last image", + "FrmSettings._EditApps._AppName": "Nama aplikasi", + "FrmSettings._SlideshowBackgroundColor": "Slideshow background color", + "FrmAbout._Email": "Email:", + "_.MouseWheelAction._DoNothing": "Diam saja", + "FrmMain.MnuSaveAs": "Simpan sebagai…", + "FrmMain._Loading": "Loading…", + "_._Browse": "Telusuri…", + "FrmMain.MnuSetDefaultPhotoViewer._Error": "Could not set ImageGlass as default photo viewer.", + "FrmSettings.Nav._Language": "Bahasa", + "FrmQuickSetup._SeeWhatNew": "See what's new in this version…", + "FrmSettings._ImageInterpolation._ScaleUp": "When zoom > 100%", + "FrmSettings.Layout._ToolbarContextPosition": "Contextual toolbar position", + "FrmMain.MnuDeleteFromHardDisk": "Delete permanently", + "FrmSettings._EmbeddedThumbnail": "Embedded thumbnail", + "FrmMain.MnuDeleteFromHardDisk._Description": "Are you sure you want to permanently delete this file?", + "FrmMain.MnuScaleToFill": "Skala ke penuh", + "FrmCrop.BtnCrop": "Crop", + "_.AfterEditAppAction._Minimize": "Minimalkan", + "FrmMain.MnuInvertColors": "Invert colors", + "FrmSettings._StartupBoost": "Startup Boost", + "FrmMain.MnuViewFirstFrame": "View first frame", + "_.MouseWheelEvent._CtrlAndScroll": "Hold Ctrl and scroll", + "FrmSettings._HideMainWindowInSlideshow": "Automatically hide main window", + "_.Metadata._FrameCount": "Frames", + "FrmSettings._EnableCopyMultipleFiles": "Enable the copying of multiple files at once", + "FrmMain.MnuFrameless._EnableDescription": "Hold Shift key to move the window.", + "_.ImageOrderBy._ExifDateTaken": "EXIF: Date taken", + "FrmAbout._Credits": "Credits", + "FrmSettings._AddNewFileExtension": "Add new file extension", + "FrmMain.MnuQuickSetup": "Open ImageGlass Quick Setup", + "FrmMain.MnuSave._Success": "Image is saved", + "FrmMain.MnuPanLeft": "Pan image left", + "FrmUpdate._StatusChecking": "Checking for update…", + "FrmSettings.Nav._Layout": "Tata letak", + "FrmMain.MnuOpenWith": "Buka dengan…", + "FrmAbout._Thanks": "Special thanks to", + "_._Warning": "Warning", + "FrmSettings.Nav._Keyboard": "Papan ketik", + "FrmSlideshow._PauseSlideshow": "Slideshow is paused.", + "_._Add+": "Tambah…", + "_._Email": "Email", + "FrmMain.MnuPanDown": "Pan image down", + "_._Cancel": "Batal", + "_._OK": "Oke", + "FrmMain.MnuPanRight": "Pan image right", + "_.Position._Right": "Right", + "_._Icon": "Icon", + "FrmSettings._ShouldLoadHiddenImages": "Load hidden images", + "_._InvalidAction._Transformation": "ImageGlass does not support rotation, flipping for this image.", + "FrmSettings._MakeDefault": "Make default", + "FrmMain.MnuCopyImageData._Copying": "Copying the image data. It's going to take a while…", + "FrmSettings._UseEmbeddedThumbnailRawFormats": "Load only the embedded thumbnail for RAW formats", + "_.ImageInterpolation._Linear": "Linear", + "FrmSettings._ImageInfoTags": "Image information tags", + "FrmSettings._FileExtensionIcons": "File extension icons", + "FrmMain.MnuEdit._AppNotFound": "Could not find the associated app for editing. You can assign an app for editing this format in ImageGlass Settings > Edit.", + "_.ColorProfileOption._None": "Tak ada", + "FrmSettings._TotalSupportedFormats": "Total supported formats: {0}", + "FrmSettings._Clipboard": "Clipboard", + "_._UserAction._Win32ExeError": "Cannot execute command '{0}'. Make sure the name is correct.", + "FrmCropSettings.DefaultSelectionType._SelectX": "Select {0}", + "_.AfterEditAppAction._Close": "Tutup", + "FrmAbout._LogoDesigner": "Logo designer:", + "_.ImageOrderBy._Name": "Nama (default)", + "FrmMain.MnuRemoveDefaultPhotoViewer._Error": "Could not remove ImageGlass as the default photo viewer.", + "FrmExportFrames._FolderPickerTitle": "Select output folder for exporting image frames", + "FrmAbout._Donate": "Donate", + "FrmMain.MnuFrameNav": "Frame navigation", + "FrmMain.MnuSetLockScreen": "Tetapkan sebagai gambar Layar kunci", + "_._Delete": "Hapus", + "FrmMain.MnuViewPrevious": "Lihat gambar sebelumnya", + "_.Position._Top": "Atas", + "FrmSettings.Toolbar._CurrentButtons": "Current buttons:", + "FrmMain.MnuAbout": "Tentang", + "FrmSettings._RemoveDefault": "Remove default", + "_._Description": "Deskripsi", + "FrmMain.MnuPasteImage._Error": "Could not find image data in the Clipboard", + "FrmMain.MnuSettings": "Pengaturan", + "FrmCropSettings._Title": "Crop settings", + "FrmSettings.Toolbar._ToolbarIconHeight": "Ukuran ikon bilah alat", + "FrmSettings._SlideshowInterval._To": "To", + "FrmSettings.Layout._ToolbarPosition": "Posisi Toolbar", + "FrmUpdate._StatusUpdated": "You are using the latest version!", + "FrmMain.MnuExit": "Keluar", + "_._Webview2._Outdated": "Your WebView2 Runtime is not supported. Please update to version {0} or later.", + "_._Yes": "Ya", + "FrmMain.MnuRotateLeft": "Putar ke kiri", + "FrmSettings._EnableStartupBoost": "Enable Startup Boost", + "_.ImageOrderBy._ExifRating": "EXIF: Rating", + "FrmMain.MnuZoomIn": "Perbesar", + "_.Metadata._ColorSpace": "Color space", + "FrmAbout._Version": "Version:", + "FrmMain.MnuToggleTopMost._Enable": "Enabled window always on top", + "FrmSettings.Toolbar._AvailableButtons": "Available buttons:", + "FrmMain.MnuSave._Saving": "Saving image…", + "FrmQuickSetup._StandardUser": "Standard user", + "FrmMain.MnuSetLockScreen._Error": "Could not set the viewing image as lock screen image", + "FrmSettings.Nav._Image": "Gambar", + "FrmSettings._Theme._InstallTheme": "Install theme packs", + "FrmSettings._EnableMultiInstances": "Izinkan beberapa contoh program", + "FrmMain.MnuCropTool": "Crop image", + "_._IgCommandExe._DefaultError._Heading": "Invalid commands", + "_._Refresh": "Segarkan", + "FrmMain.MnuLosslessCompression._Description": "This tool uses Magick.NET library for lossless compression, optimizing file size. Overwrites only if the compressed file is smaller than the original.", + "_._MoveDown": "Move down", + "FrmSettings._GetExtensionIconPacks": "Get extension icon packs…", + "FrmSettings._InAppMessageDuration": "In-app message duration (milliseconds)", + "FrmMain.MnuFrameless": "Tanpa bingkai", + "_._Reset": "Setel ulang", + "FrmSettings._ConfigDir": "Configuration location", + "FrmQuickSetup._SettingsWillBeApplied": "Settings will be applied:", + "FrmSettings._UnmanagedSettingReminder": "This setting is not managed by ImageGlass. Don't forget to disable it before you remove or relocate the app because ImageGlass does not handle this automatically.", + "FrmMain.MnuClipboard": "Clipboard", + "FrmMain.MnuCustomZoom": "Perbesaran khusus…", + "FrmSettings._DisplayLanguage": "Display language", + "FrmMain.MnuPrint._Error": "Could not print the viewing image", + "FrmSettings._ShouldPreserveModifiedDate": "Pertahankan tanggal modifikasi gambar saat disimpan", + "FrmSettings._ShowSaveOverrideConfirmation": "Show confirmation dialog when overriding file", + "FrmColorPickerSettings.ChkShowHexA": "Use HEX format with alpha value", + "FrmMain.MnuFullScreen": "Full Screen", + "FrmSettings._StartupDir": "Startup location", + "FrmSettings._ShowCheckerboardOnlyImageRegion": "Show checkerboard only within the image region", + "FrmMain.MnuClearClipboard._Success": "Cleared clipboard.", + "FrmQuickSetup._Text": "ImageGlass Quick Setup", + "FrmMain.MnuLosslessCompression._Done": "Done lossless compression.\r\nThe new file size is {0}, saved {1}.", + "FrmMain.MnuLosslessCompression": "Magick.NET Lossless Compression", + "FrmResize.RadResizeByPercentage": "Percentage", + "FrmSettings._StartupBoost._Disabled": "Startup Boost is disabled", + "FrmMain.MnuToggleCheckerboard": "Latar kotak-kotak", + "FrmSettings._MinEmbeddedThumbnailSize._Height": "Tinggi", + "FrmSettings.Nav._General": "Umum", + "FrmSettings._ImageLoading": " Pemuatan gambar", + "FrmSettings._ShowSlideshowCountdown": "Tampilkan hitung mundur slideshow", + "FrmMain.MnuSave": "Simpan", + "FrmMain.MnuMoveToRecycleBin": "Move to the Recycle Bin", + "FrmMain.MnuRefresh": "Segarkan", + "FrmToolNotFound.LblHeading": "'{0}' is not found!", + "FrmMain.MnuReportIssue": "Laporkan masalah…", + "FrmMain.MnuCopyImageData": "Salin data gambar", + "FrmMain.MnuCheckForUpdate._NewVersion": "Versi baru tersedia!", + "_._Empty": "(empty)", + "FrmSettings._Zooming": "Memperbesar", + "FrmMain.MnuCutFile": "Cut file", + "FrmHotkeyPicker.LblHotkey": "Press hotkeys", + "FrmSettings.Layout._Gallery": "Gallery", + "FrmMain.MnuNewWindow": "Buka jendela baru", + "FrmMain.MnuMoveToRecycleBin._Description": "Do you want to move this file to the Recycle bin?", + "FrmSettings._DefaultPhotoViewer": "Default photo viewer", + "_.Metadata._ExifDateTimeOriginal": "EXIF: DateTimeOriginal", + "FrmMain.MnuRotateRight": "Putar ke kanan", + "FrmSettings._MinEmbeddedThumbnailSize": "Minimum size of the embedded thumbnail to be loaded", + "FrmMain.MnuSetDefaultPhotoViewer": "Set default photo viewer", + "FrmMain.MnuImageProperties": "Properti gambar", + "FrmSettings._EnableNavigationButtons": "Show navigation arrow buttons", + "_._Edit": "Sunting", + "FrmSettings._ImageBooster": "Image Booster", + "FrmSettings.Tools._IntegratedWith": "Integrated with {0}", + "_._Next": "Lanjut", + "FrmExportFrames._OpenOutputFolder": "Open output folder", + "FrmMain.MnuOpenLocation": "Buka lokasi gambar", + "FrmMain.MnuLockZoom": "Rasio pengunci tombol", + "FrmSettings._StartupBoost._Description": "Preload and run ImageGlass in the background for a few seconds during Windows startup to accelerate the first launch.", + "FrmSettings._WindowBackdrop": "Window backdrop", + "FrmSettings._EnableRealTimeFileUpdate": "Monitor file changes in the viewing folder and update in realtime", + "_._NotSupported": "Unsupported format", + "FrmSettings._Theme._GetMoreThemes": "Get more theme packs…", + "FrmMain.MnuNewWindow._Error": "Cannot open new window because only one instance is allowed", + "FrmMain.MnuZoomOut": "Perkecil", + "FrmSettings.Toolbar._EditButton": "Edit toolbar button", + "FrmMain.MnuCustomZoom._Description": "Masukkan nilai perbesaran", + "FrmResize.RadResizeByPixels": "Pixels", + "FrmMain.MnuEdit": "Sunting gambar {0}…", + "FrmSettings.Layout._GalleryPosition": "Gallery position", + "FrmMain.MnuWindowFit": "Window Fit", + "FrmMain._OpenFileDialog": "Semua file yang didukung", + "FrmSettings._UseRandomIntervalForSlideshow": "Gunakan interval acak", + "_.Position._Left": "Left", + "FrmSettings._ShouldOpenLastSeenImage": "Open the last seen image", + "_.Position._Bottom": "Bawah", + "FrmResize.ChkKeepRatio": "Keep ratio propotional", + "FrmMain.MnuGoTo": "Pergi ke…", + "FrmSlideshow.MnuPauseResumeSlideshow": "Pause/resume slideshow", + "FrmSettings.Tools._Integrated": "Integrated", + "FrmSettings._Contributors": "Contributors", + "_.MouseWheelAction._Zoom": "Zoom in / out", + "_._CommandPreview": "Pratinjau perintah", + "FrmSettings._DarkTheme": "Dark", + "_._Hotkeys": "Hotkeys", + "_.Metadata._ExifDateTime": "EXIF: DateTime", + "FrmSettings.Toolbar._Errors._ButtonIdRequired": "Button ID required.", + "FrmSettings._MinEmbeddedThumbnailSize._Width": "Lebar", + "_._Executable": "Executable", + "_.ImageInterpolation._MultiSampleLinear": "Multi-sample linear", + "_._Separator": "Pemisah", + "FrmQuickSetup._ProfessionalUser": "Professional user", + "FrmMain.MnuFlipVertical": "Berbalik Vertikal", + "FrmSlideshow._ResumeSlideshow": "Slideshow is resumed.", + "FrmCropSettings.DefaultSelectionType._CustomArea": "Custom area…", + "FrmMain.MnuActualSize": "Ukuran sebenarnya", + "FrmCrop.BtnSaveAs": "Simpan sebagai…", + "FrmSettings._InstallNewLanguagePack": "Install new language packs…", + "FrmSlideshow.MnuZoomModes": "Zoom modes", + "FrmMain.MnuTools": "Alat", + "_.ImageInterpolation._Cubic": "Cubic", + "FrmUpdate._LatestVersion": "The latest version: {0}", + "FrmMain.MnuViewNext": "Lihat gambar berikutnya", + "_.MouseWheelEvent._AltAndScroll": "Hold Alt and scroll", + "FrmToolNotFound._Title": "Tool not found", + "FrmCrop.BtnCrop._Tooltip": "Crop the image only", + "FrmSettings.EditAppDialog._AddApp": "Add an app for editing", + "FrmMain.MnuPanning": "Geser", + "_._MoveUp": "Move up", + "FrmCropSettings.DefaultSelectionType._SelectAll": "Select all", + "_._Name": "Nama", + "FrmColorPickerSettings.ChkShowHslA": "Use HSL format with alpha value", + "FrmMain.MnuToggleImageAnimation": "Start / stop animating image", + "FrmSettings._DisableStartupBoost": "Disable Startup Boost", + "FrmMain.MnuCopyFile._Success": "Copied {0} file(s).", + "FrmMain.MnuSave._ConfirmDescription": "ImageGlass is not a professional photo editor, please be aware of losing the quality, metadata, layers,… when saving your image.", + "FrmToolNotFound.BtnSelectExecutable": "Select…", + "FrmUpdate._StatusOutdated": "A new update is available!", + "_.ImageOrderBy._Random": "Acak", + "FrmResize.LblCurrentSize": "Current Size:", + "_._Apply": "Menerapkan", + "FrmAbout._Slogan": "Penampil gambar yang ringan dan serbaguna", + "FrmMain.MnuPanToTop": "Pan image to top", + "FrmSettings.Toolbar._AddNewButton": "Add a custom toolbar button", + "FrmCrop.LblSize": "Size:", + "FrmSettings._ImageInterpolation._ScaleDown": "When zoom < 100%", + "_._CreatingFileError": "Could not create temporary image file", + "FrmMain.MnuGoTo._Description": "Enter the image index to view, and then press ENTER", + "FrmSettings.Toolbar._EnableCenterToolbar": "Use center alignment for toolbar", + "FrmMain.MnuResizeTool": "Resize image", + "FrmSettings.Layout._Toolbar": "Tampilkan palang alat", + "FrmMain.MnuHelp": "Bantuan", + "_.ImageOrderBy._FileSize": "File size", + "FrmSettings._Theme._OpenThemeFolder": "Buka folder tema", + "FrmMain.MnuNavigation": "Navigasi", + "_._Save": "Simpan", + "FrmQuickSetup._SettingProfileDescription": "To modify these settings, simply access app settings.", + "_._UserAction._MenuNotFound": "Cannot find menu '{0}' to invoke the action", + "FrmMain.MnuPanToLeftSide": "Pan image to left edge", + "FrmUpdate._CurrentVersion": "Current version: {0}", + "FrmCrop.BtnSettings._Tooltip": "Open Crop tool settings", + "_.ColorProfileOption._Custom": "Kostum…", + "FrmSettings._UseEmbeddedThumbnailOtherFormats": "Load only the embedded thumbnail for other formats", + "FrmMain.MnuGoToFirst": "Go to first image", + "FrmSettings._ExportLanguagePack": "Export language pack…", + "FrmSettings.Nav._Mouse": "Mouse", + "_.ImageOrderBy._DateCreated": "Date created", + "FrmSettings._EnableFullscreenSlideshow": "Start slideshow in Full Screen mode", + "FrmAbout._Homepage": "Homepage:", + "FrmSettings._GalleryCacheSizeInMb": "Maximum gallery cache size (in megabytes)", + "FrmMain.MnuCopyImageData._Success": "Copied the current image data.", + "FrmSettings._EnableLoopBackNavigation": "Loop back to the first image when reaching the end of the image list", + "_.MouseWheelEvent._Scroll": "Scroll", + "FrmCrop.BtnSave._Tooltip": "Simpan gambar", + "FrmMain.MnuSlideshow": "Slideshow", + "FrmMain.MnuShare": "Bagikan…", + "FrmSettings._SlideshowNotification": "Slideshow notification", + "FrmMain.MnuViewChannels": "Lihat kanal warna", + "FrmSettings._Refresh": "Segarkan", + "_._UserAction._MethodNotFound": "Cannot find method '{0}' to invoke the action", + "FrmMain.MnuCopyFile": "Copy file", + "_._CreatingFile": "Creating a temporary image file…", + "FrmMain.MnuToggleTopMost": "Jaga jendela selalu di atas", + "FrmMain.MnuLosslessCompression._Confirm": "Are you sure you want to proceed?", + "FrmMain.MnuImage": "Gambar", + "FrmSettings._StartupBoost._Enabled": "Startup Boost is enabled", + "FrmQuickSetup._SetDefaultViewer": "Do you want to set ImageGlass as the default photo viewer?", + "FrmMain.MnuScaleToWidth": "Skala ke lebar", + "_._FileExtension": "Ekstensi file", + "FrmUpdate._PublishedDate": "Published date: {0}", + "_._DoNotShowThisMessageAgain": "Do not show this message again", + "_.ImageInterpolation._NearestNeighbor": "Nearest neighbor", + "FrmCrop.LblLocation": "Location:", + "_._Download": "Download", + "_.Metadata._ColorProfile": "Color profile", + "FrmSettings._CenterWindowFit": "Automatically center the window in Window Fit mode", + "FrmSettings._ImageLoadingOrder": "Urutan pemuatan gambar", + "FrmSettings._GalleryColumns": "Number of thumbnail columns in vertical gallery layout", + "_._Quit": "Quit", + "_._Add": "Tambah", + "FrmMain.MnuChangeBackgroundColor": "Change background color…", + "FrmMain.MnuToggleToolbar": "Tampilkan palang alat", + "FrmAbout._Contact": "Kontak", + "FrmSettings.Toolbar._AddCustomButton": "Add a custom button…", + "FrmCrop.BtnQuickSelect._Tooltip": "Quick select…", + "FrmMain.MnuCutFile._Success": "Cut {0} file(s).", + "FrmSettings._ZoomSpeed": "Zoom speed", + "FrmMain.MnuToggleTopMost._Disable": "Disabled window always on top", + "FrmSettings._ShouldUseExplorerSortOrder": "Use Explorer sort order if possible", + "_.ImageInterpolation._Antisotropic": "Antisotropic", + "FrmMain._ReachedFirstImage": "Mencapai gambar pertama", + "_._UnhandledException": "Unhandled exception", + "FrmResize.LblNewSize": "New Size:", + "FrmMain._ClipboardImage": "Clipboard image", + "FrmMain.MnuExportFrames": "Export image frames…", + "FrmMain.MnuFile": "Berkas", + "_._Close": "Tutup", + "FrmMain.MnuMain": "Menu utama", + "_._ResetToDefault": "Atur ulang ke standar", + "FrmSettings.Nav._Gallery": "Gallery", + "FrmMain.MnuSetDefaultPhotoViewer._Success": "You have successfully set ImageGlass as default photo viewer.", + "FrmSettings._HideGalleryInFullscreen": "Hide gallery in Full Screen mode", + "FrmSettings._AvailableImageInfoTags": "Available tags:", + "FrmExportFrames._Exporting": "Exporting {0}/{1} frames \r\n{2}…", + "_._Argument": "Argument", + "FrmSettings._ImageEditQuality": "Kualitas gambar", + "_._ID": "ID", + "FrmSettings._UserConfigFile": "User settings file (igconfig.json)", + "FrmMain.MnuLoadingOrders": "Loading orders", + "FrmSettings._OpenSaveAsDialogInTheCurrentImageDir": "Open the Save As dialog in the current image directory", + "_.MouseWheelEvent._ShiftAndScroll": "Hold Shift and scroll", + "FrmSettings._UseSmoothZooming": "Use smooth zooming", + "FrmSettings._Theme": "Tema", + "FrmSettings._ImageBoosterCacheMaxDimension": "Maximum image dimension to be cached (in pixels)", + "FrmMain.MnuScaleToHeight": "Skala ke tinggi", + "_.Metadata._FileLastWriteTime": "Date modified", + "FrmSettings._Author": "Pembuat", + "FrmSettings._Others": "Lainnya", + "_.MouseWheelAction._PanVertically": "Pan up / down", + "FrmSettings._MouseWheelAction": "Mouse wheel action", + "FrmSettings.Nav._Tools": "Alat", + "FrmMain.MnuSetDesktopBackground._Error": "Could not set the viewing image as desktop background", + "FrmSettings.Toolbar._Errors._ButtonExecutableRequired": "Button executable required.", + "_.ImageOrderBy._DateAccessed": "Date accessed", + "FrmSettings._ThumbnailSize": "Thumbnail size (in pixels)", + "FrmSettings._FileFormats": "File formats", + "FrmMain.MnuReloadImageList": "Muat ulang daftar gambar", + "FrmSettings._UseWebview2ForSvg": "Use Webview2 for viewing SVG format", + "FrmCrop.BtnCopy": "Salin", + "FrmSettings._CurrentMonitorProfile._Description": "ImageGlass does not auto-update the color when moving its window between monitors", + "FrmMain.PicMain._ErrorText": "Could not open this image", + "FrmSettings.Tools._AddNewTool": "Add an external tool", + "FrmMain.MnuRename": "Ganti nama gambar…", + "FrmMain.MnuViewLastFrame": "View last frame", + "_._Webview2._NotFound": "Please install WebView2 Runtime to access full features of ImageGlass.", + "FrmMain.MnuGetMoreTools": "Get more tools…", + "FrmSettings.Nav._Appearance": "Appearance", + "FrmSettings._SlideshowInterval": "Interval slideshow:", + "_.ImageInterpolation._HighQualityBicubic": "High quality bicubic", + "FrmColorPickerSettings.ChkShowHsvA": "Use HSV format with alpha value", + "FrmSettings.Tools._EditTool": "Edit external tool", + "_._Error": "Error", + "FrmSettings._ImageBoosterCacheMaxFileSizeInMb": "Maximum image file size to be cached (in megabytes)", + "_._UnhandledException._Description": "Unhandled exception has occurred. If you click Continue, the application will ignore this error and attempt to continue. If you click Quit, the application will close immediately.", + "_.Metadata._FileSize": "File size", + "FrmSettings.Toolbar._ButtonJson": "Button JSON", + "FrmQuickSetup._SetDefaultViewer._Description": "You can reset it in the app settings > File type associations tab.", + "FrmSettings.Nav._Edit": "Sunting", + "FrmMain.MnuToggleGallery": "Gallery panel", + "_._IgCommandExe._DefaultError._Description": "Make sure you pass the correct commands!\r\nThis executable file contains command-line functions for ImageGlass software.\r\n\r\nTo explore all command lines, please visit:\r\n{0}", + "FrmMain.MnuLosslessCompression._Compressing": "Performing lossless compression…", + "FrmSettings._ShouldGroupImagesByDirectory": "Kelompokkan gambar berdasarkan direktori", + "FrmMain.MnuPanToRightSide": "Pan image to right edge", + "_.Metadata._ExifRatingPercent": "Rating", + "FrmSettings._PanSpeed": "Panning speed", + "_._CheckForUpdate": "Periksa pembaruan…", + "FrmSettings.Layout._ToolbarContext": "Contextual toolbar", + "_.ImageInfo._FrameCount": "{0} frame(s)", + "FrmMain.MnuLayout": "Tata letak", + "_._Website": "Situs Web", + "FrmMain.MnuPasteImage": "Paste image", + "FrmSettings._ShowGalleryScrollbars": "Show gallery scrollbars" + } +} \ No newline at end of file diff --git a/Setup/Assets/Language/Irish.iglang.json b/Setup/Assets/Language/Irish.iglang.json new file mode 100644 index 000000000..1738d3a8a --- /dev/null +++ b/Setup/Assets/Language/Irish.iglang.json @@ -0,0 +1,504 @@ +{ + "_Metadata": { + "Code": "ga-IE", + "EnglishName": "Irish", + "LocalName": "Gaeilge", + "Author": "Seanán Ó Coistín (seananoc)", + "MinVersion": "9.2" + }, + "Items": { + "FrmCrop.SelectionAspectRatio._Original": "Bunaidh", + "FrmMain.MnuShare._Error": "Could not open Share dialog.", + "_.Metadata._FileLastAccessTime": "Date accessed", + "FrmAbout._License": "Software license", + "FrmSettings.Toolbar._Errors._ButtonIdDuplicated": "A button with the ID '{0}' has already been defined. Please choose a different and unique ID for your button to avoid conflicts.", + "FrmMain.MnuSave._Confirm": "Are you sure you want to override this image?", + "FrmSettings._OpenDefaultAppsSetting": "Open Default apps setting", + "FrmMain.MnuCopyPath": "Cóipeáil conair na híomhá", + "FrmCropSettings.DefaultSelectionType._SelectNone": "Ná roghnaigh aon cheann acu", + "_.MouseWheelAction._PanHorizontally": "Pan left / right", + "FrmMain.MnuPrint": "Clóbhuail…", + "FrmSettings.Toolbar._ToolbarButtons": "Toolbar buttons", + "FrmResize.LblResample": "Resample:", + "_.ImageOrderBy._Extension": "Iarmhír", + "FrmSettings.Nav._Viewer": "Amharcóir", + "FrmSettings.EditAppDialog._EditApp": "Edit app", + "FrmCrop.BtnReset._Tooltip": "Reset selection", + "FrmMain.MnuRename._Description": "Enter a new filename:", + "_._No": "No", + "FrmSlideshow.MnuToggleCountdown": "Taispeáin comhaireamh anuas an taispeántais sleamhnáin", + "FrmSettings._OpenStartupAppsSetting": "Open Startup apps setting", + "FrmMain.MnuViewPreviousFrame": "View previous frame", + "_.ImageOrderBy._DateModified": "An dáta ar a mionathraíodh é", + "FrmMain.MnuViewNextFrame": "View next frame", + "FrmMain.MnuUnload": "Unload image", + "FrmSettings.Toolbar._HideToolbarInFullscreen": "Hide toolbar in Full Screen mode", + "_.ImageOrderType._Desc": "Ag titim", + "_._Update": "Nuashonraigh é", + "FrmSettings._EnableImageAsyncLoading": "Enable image asynchronous loading", + "FrmSettings._DefaultPhotoViewer._Description": "Register the supported formats of ImageGlass with Windows. You might need to open the Default apps settings and manually select ImageGlass from the list for it to take effect.", + "_.MouseWheelAction._BrowseImages": "View next / previous Image", + "FrmSettings._EditApps": "Image editing apps", + "FrmColorPickerSettings.ChkShowCIELabA": "Use CIELAB format with alpha value", + "_._GetHelp": "Faigh cabhair", + "FrmQuickSetup._SkipQuickSetup": "Léim thar seo agus tosaigh ImageGlass", + "FrmColorPickerSettings._Title": "Color picker settings", + "_._Copy": "Cóipeáil", + "FrmSettings._ImageBoosterCacheCount": "Number of images cached by Image Booster (one direction)", + "FrmMain.MnuPanToBottom": "Pan image to bottom", + "FrmMain.MnuZoom": "Gluais", + "FrmCropSettings.ChkCloseToolAfterSaving": "Close Crop tool after saving", + "FrmSettings._ShowWelcomeImage": "Taispeáin íomhá na fáilte", + "FrmSettings._ColorProfile": "Próifíl dhathanna", + "FrmSettings._Theme._UninstallTheme": "Uninstall a theme pack", + "FrmMain._OpenWith": "Oscail é le {0}", + "FrmMain.MnuRemoveDefaultPhotoViewer": "Remove default photo viewer", + "_.AfterEditAppAction._Nothing": "Dada", + "FrmCrop.BtnSave": "Cuir i dtaisce é", + "FrmMain.MnuScaleToFit": "Athraigh an scála chun é a chur in oiriúint don lch", + "FrmToolNotFound.LblDownloadToolText": "You can download more tools for ImageGlass at:", + "_._LearnMore": "Foghlaim tuilleadh…", + "FrmCrop.LblAspectRatio": "Aspect ratio:", + "FrmExportFrames._FileNotExist": "Image file does not exist", + "FrmSettings._LightTheme": "Geal", + "FrmSettings.Nav._Slideshow": "Taispeántas sleamhnáin", + "_._Continue": "Lean ar aghaidh", + "_._AddHotkey": "Add hotkey…", + "FrmMain.MnuSetDesktopBackground": "Socraigh mar chúlra", + "FrmMain.MnuReload": "Athluchtaigh an íomhá", + "FrmSlideshow.MnuExitSlideshow": "Scoir ón taispeántas sleamhnáin", + "FrmMain.MnuAutoZoom": "Gluais uathoibríoch", + "FrmSettings._ShowImagePreview": "Display image preview while it's being loaded", + "FrmCrop.BtnCopy._Tooltip": "Copy the selection to clipboard", + "FrmSettings.Nav._Toolbar": "Barra uirlisí", + "FrmMain.MnuSave._Error": "Níorbh fhéidir an íomhá a chur i dtaisce", + "FrmSettings._AfterEditingAction": "Tar éis an feidhmchlár eagarthóireachta a oscailt", + "FrmSettings._ShouldUseColorProfileForAll": "Cuir i bhfeidhm é i gcomhair íomhánna gan phróifíl leabaithe dhathanna", + "FrmCropSettings.DefaultSelectionType._UseTheLastSelection": "Use the last selection", + "FrmSettings._SlideshowInterval._From": "Ó", + "FrmSettings._ImageInterpolation": "Image interpolation", + "FrmQuickSetup._StepInfo": "Céim {0}", + "FrmMain.MnuColorPicker": "Roghnóir dathanna", + "FrmCrop.SelectionAspectRatio._FreeRatio": "Free ratio", + "FrmSettings._ResetSettings": "Athshocraigh na socruithe", + "FrmSettings._Startup": "Tosú", + "_.BackdropStyle._None": "Faic", + "FrmSettings._LoadDefaultZoomLevels": "Load default zoom levels", + "FrmColorPicker.BtnSettings._Tooltip": "Open Color picker settings…", + "FrmSettings._UseThemeForDarkMode": "Use this theme for dark mode", + "FrmSettings._ShowDeleteConfirmation": "Show confirmation dialog when deleting file", + "FrmSettings._ShowAppIcon": "Show app icon on the title bar", + "_._InvalidAction": "Gníomh neamhbhailí", + "FrmQuickSetup._SelectProfile": "Select a profile", + "_.Metadata._FileCreationTime": "Date created", + "FrmSettings._SlideshowImagesToNotifySound": "Number of images to trigger a notification sound", + "FrmSettings._BackgroundColor": "Viewer background color", + "FrmSettings._RealTimeFileUpdate": "Real-time file update", + "_.ColorProfileOption._CurrentMonitorProfile": "Current monitor profile", + "FrmSettings._EnableCutMultipleFiles": "Enable the cutting of multiple files at once", + "FrmSettings._AutoUpdate": "Lorg nuashonruithe go huathoibríoch", + "FrmCropSettings.LblDefaultSelection": "Default selection", + "FrmSettings._UseThemeForLightMode": "Use this theme for light mode", + "FrmSettings._ZoomLevels": "Leibhéil ghluaise", + "FrmMain.MnuSetLockScreen._Success": "Lock screen image is updated", + "FrmSettings._ShowGalleryFileName": "Show thumbnail filename", + "FrmSettings.Layout._Order": "Order", + "FrmCropSettings.ChkAutoCenterSelection": "Auto-center selection", + "FrmSettings.Nav._FileTypeAssociations": "File type associations", + "_._Back": "Siar", + "FrmMain.MnuSetDesktopBackground._Success": "Desktop background is updated", + "FrmSettings._ShouldAutoOpenNewAddedImage": "Open the new added image automatically", + "FrmCrop.SelectionAspectRatio._Custom": "Saincheaptha…", + "FrmMain.MnuCopyPath._Success": "Copied the current image path.", + "FrmSettings._StartupBoost._Error": "Could not change Startup Boost setting", + "FrmToolNotFound.LblDescription": "ImageGlass was unable to locate the path to the '{0}' executable. To resolve this issue, please update the path to the '{0}' as necessary.", + "FrmMain.MnuClearClipboard": "Glan an ghearrthaisce", + "FrmSettings._ColorManagement": "Bainistíocht na ndathanna", + "FrmMain._ReachedLastLast": "Sroicheadh an íomhá dheiridh", + "FrmMain.MnuPanUp": "Pan image up", + "FrmMain.MnuRemoveDefaultPhotoViewer._Success": "ImageGlass is no longer the default photo viewer.", + "FrmSettings._GetMoreLanguagePacks": "Faigh tuilleadh bearta teanga…", + "FrmAbout._Privacy": "Privacy policy", + "FrmSettings._EnableRecursiveLoading": "Load images in subfolders", + "_._UserAction._MethodArgumentNotSupported": "The argument type of method '{0}' is not supported", + "FrmSettings._FileExtensionIcons._Description": "For customizing file extension icons, download an icon pack, place all .ICO files in the extension icon folder, and click the '{0}' button. This will also set ImageGlass as default photo viewer.", + "_.ImageOrderType._Asc": "Ag éirí", + "FrmExportFrames._Title": "Export image frames", + "_._Install": "Suiteáil é…", + "FrmMain.MnuFlipHorizontal": "Smeach go cothrománach í", + "FrmSettings._OpenExtensionIconFolder": "Open extension icon folder", + "FrmAbout._Collaborator": "Collaborator:", + "FrmQuickSetup._ConfirmCloseProcess": "Before applying the new settings, it's essential to close all ImageGlass processes. Are you ready to proceed?", + "FrmExportFrames._ExportDone": "Exported {0} frames successfully to \r\n{1}", + "FrmCrop.BtnSaveAs._Tooltip": "Save as a copy…", + "FrmMain.MnuOpenFile": "Oscail comhad…", + "FrmColorPickerSettings.ChkShowRgbA": "Use RGB format with alpha value", + "_.ImageInfo._ListCount": "{0} file(s)", + "FrmMain.MnuGoToLast": "Go to last image", + "FrmSettings._EditApps._AppName": "Ainm na haipe", + "FrmSettings._SlideshowBackgroundColor": "Slideshow background color", + "FrmAbout._Email": "Seoladh ríomhphoist:", + "_.MouseWheelAction._DoNothing": "Ná déan faic", + "FrmMain.MnuSaveAs": "Cuir é i dtaisce mar…", + "FrmMain._Loading": "Loading…", + "_._Browse": "Siortaigh…", + "FrmMain.MnuSetDefaultPhotoViewer._Error": "Could not set ImageGlass as default photo viewer.", + "FrmSettings.Nav._Language": "Teanga", + "FrmQuickSetup._SeeWhatNew": "See what's new in this version…", + "FrmSettings._ImageInterpolation._ScaleUp": "When zoom > 100%", + "FrmSettings.Layout._ToolbarContextPosition": "Contextual toolbar position", + "FrmMain.MnuDeleteFromHardDisk": "Scrios go deo é", + "FrmSettings._EmbeddedThumbnail": "Embedded thumbnail", + "FrmMain.MnuDeleteFromHardDisk._Description": "Are you sure you want to permanently delete this file?", + "FrmMain.MnuScaleToFill": "Athraigh an scála chun an leathanach an líonadh", + "FrmCrop.BtnCrop": "Bearr", + "_.AfterEditAppAction._Minimize": "Íoslaghdaigh", + "FrmMain.MnuInvertColors": "Invert colors", + "FrmSettings._StartupBoost": "Startup Boost", + "FrmMain.MnuViewFirstFrame": "View first frame", + "_.MouseWheelEvent._CtrlAndScroll": "Coinnigh greim ar Ctrl agus scrollaigh", + "FrmSettings._HideMainWindowInSlideshow": "Automatically hide main window", + "_.Metadata._FrameCount": "Frames", + "FrmSettings._EnableCopyMultipleFiles": "Enable the copying of multiple files at once", + "FrmMain.MnuFrameless._EnableDescription": "Hold Shift key to move the window.", + "_.ImageOrderBy._ExifDateTaken": "EXIF: Date taken", + "FrmAbout._Credits": "Credits", + "FrmSettings._AddNewFileExtension": "Add new file extension", + "FrmMain.MnuQuickSetup": "Open ImageGlass Quick Setup", + "FrmMain.MnuSave._Success": "Image is saved", + "FrmMain.MnuPanLeft": "Pan image left", + "FrmUpdate._StatusChecking": "Checking for update…", + "FrmSettings.Nav._Layout": "Leagan amach", + "FrmMain.MnuOpenWith": "Oscail le…", + "FrmAbout._Thanks": "Special thanks to", + "_._Warning": "Rabhadh", + "FrmSettings.Nav._Keyboard": "Méarchlár", + "FrmSlideshow._PauseSlideshow": "Tá an taispeántas sleamhnáin curtha ar sos.", + "_._Add+": "Cuir leis…", + "_._Email": "Seoladh ríomhphoist", + "FrmMain.MnuPanDown": "Pan image down", + "_._Cancel": "Cealaigh", + "_._OK": "Tá go maith", + "FrmMain.MnuPanRight": "Pan image right", + "_.Position._Right": "Ar Dheis", + "_._Icon": "Icon", + "FrmSettings._ShouldLoadHiddenImages": "Load hidden images", + "_._InvalidAction._Transformation": "ImageGlass does not support rotation, flipping for this image.", + "FrmSettings._MakeDefault": "Déan mar réamhshocrú é", + "FrmMain.MnuCopyImageData._Copying": "Copying the image data. It's going to take a while…", + "FrmSettings._UseEmbeddedThumbnailRawFormats": "Load only the embedded thumbnail for RAW formats", + "_.ImageInterpolation._Linear": "Linear", + "FrmSettings._ImageInfoTags": "Image information tags", + "FrmSettings._FileExtensionIcons": "File extension icons", + "FrmMain.MnuEdit._AppNotFound": "Could not find the associated app for editing. You can assign an app for editing this format in ImageGlass Settings > Edit.", + "_.ColorProfileOption._None": "Faic", + "FrmSettings._TotalSupportedFormats": "Total supported formats: {0}", + "FrmSettings._Clipboard": "An Ghearrthaisce", + "_._UserAction._Win32ExeError": "Cannot execute command '{0}'. Make sure the name is correct.", + "FrmCropSettings.DefaultSelectionType._SelectX": "Roghnaigh {0}", + "_.AfterEditAppAction._Close": "Dún", + "FrmAbout._LogoDesigner": "Logo designer:", + "_.ImageOrderBy._Name": "Ainm (an réamhshocrú)", + "FrmMain.MnuRemoveDefaultPhotoViewer._Error": "Could not remove ImageGlass as the default photo viewer.", + "FrmExportFrames._FolderPickerTitle": "Select output folder for exporting image frames", + "FrmAbout._Donate": "Bronn airgead", + "FrmMain.MnuFrameNav": "Frame navigation", + "FrmMain.MnuSetLockScreen": "Socraigh mar íomhá do ghlasáil an scáileáin í", + "_._Delete": "Scrios", + "FrmMain.MnuViewPrevious": "Féach ar an íomhá roimhe", + "_.Position._Top": "Barr", + "FrmSettings.Toolbar._CurrentButtons": "Current buttons:", + "FrmMain.MnuAbout": "Maidir leis", + "FrmSettings._RemoveDefault": "Remove default", + "_._Description": "Cur síos", + "FrmMain.MnuPasteImage._Error": "Could not find image data in the Clipboard", + "FrmMain.MnuSettings": "Socruithe", + "FrmCropSettings._Title": "Crop settings", + "FrmSettings.Toolbar._ToolbarIconHeight": "Méid na gcnaipí sa bharra uirlisí", + "FrmSettings._SlideshowInterval._To": "Go", + "FrmSettings.Layout._ToolbarPosition": "Suíomh an bharra uirlisí", + "FrmUpdate._StatusUpdated": "You are using the latest version!", + "FrmMain.MnuExit": "Scoir", + "_._Webview2._Outdated": "Your WebView2 Runtime is not supported. Please update to version {0} or later.", + "_._Yes": "Socraigh", + "FrmMain.MnuRotateLeft": "Rothlaigh tuathalach í", + "FrmSettings._EnableStartupBoost": "Enable Startup Boost", + "_.ImageOrderBy._ExifRating": "EXIF: Rating", + "FrmMain.MnuZoomIn": "Gluais isteach", + "_.Metadata._ColorSpace": "Color space", + "FrmAbout._Version": "Leagan:", + "FrmMain.MnuToggleTopMost._Enable": "Enabled window always on top", + "FrmSettings.Toolbar._AvailableButtons": "Available buttons:", + "FrmMain.MnuSave._Saving": "Saving image…", + "FrmQuickSetup._StandardUser": "Standard user", + "FrmMain.MnuSetLockScreen._Error": "Could not set the viewing image as lock screen image", + "FrmSettings.Nav._Image": "Íomhá", + "FrmSettings._Theme._InstallTheme": "Install theme packs", + "FrmSettings._EnableMultiInstances": "Ceadaigh iliomad áisc den ríomhchlár", + "FrmMain.MnuCropTool": "Crop image", + "_._IgCommandExe._DefaultError._Heading": "Invalid commands", + "_._Refresh": "Athnuaigh é", + "FrmMain.MnuLosslessCompression._Description": "This tool uses Magick.NET library for lossless compression, optimizing file size. Overwrites only if the compressed file is smaller than the original.", + "_._MoveDown": "Bog síos", + "FrmSettings._GetExtensionIconPacks": "Get extension icon packs…", + "FrmSettings._InAppMessageDuration": "In-app message duration (milliseconds)", + "FrmMain.MnuFrameless": "Gan fráma", + "_._Reset": "Athshocraigh", + "FrmSettings._ConfigDir": "Configuration location", + "FrmQuickSetup._SettingsWillBeApplied": "Settings will be applied:", + "FrmSettings._UnmanagedSettingReminder": "This setting is not managed by ImageGlass. Don't forget to disable it before you remove or relocate the app because ImageGlass does not handle this automatically.", + "FrmMain.MnuClipboard": "An Ghearrthaisce", + "FrmMain.MnuCustomZoom": "Custom zoom…", + "FrmSettings._DisplayLanguage": "An teanga taispeána", + "FrmMain.MnuPrint._Error": "Could not print the viewing image", + "FrmSettings._ShouldPreserveModifiedDate": "Coimeád sonraí mionathraithe na híomhá nuair a dhéantar í a thaisceadh", + "FrmSettings._ShowSaveOverrideConfirmation": "Show confirmation dialog when overriding file", + "FrmColorPickerSettings.ChkShowHexA": "Use HEX format with alpha value", + "FrmMain.MnuFullScreen": "Lánscáileán", + "FrmSettings._StartupDir": "Startup location", + "FrmSettings._ShowCheckerboardOnlyImageRegion": "Show checkerboard only within the image region", + "FrmMain.MnuClearClipboard._Success": "Glanadh an ghearrthaisce.", + "FrmQuickSetup._Text": "ImageGlass Quick Setup", + "FrmMain.MnuLosslessCompression._Done": "Done lossless compression.\r\nThe new file size is {0}, saved {1}.", + "FrmMain.MnuLosslessCompression": "Magick.NET Lossless Compression", + "FrmResize.RadResizeByPercentage": "Céatadán", + "FrmSettings._StartupBoost._Disabled": "Startup Boost is disabled", + "FrmMain.MnuToggleCheckerboard": "Cúlra ar nós clár táiplise", + "FrmSettings._MinEmbeddedThumbnailSize._Height": "Airde", + "FrmSettings.Nav._General": "Coiteann", + "FrmSettings._ImageLoading": "Tá an íomhá ag luchtú", + "FrmSettings._ShowSlideshowCountdown": "Taispeáin comhaireamh anuas an taispeántais sleamhnáin", + "FrmMain.MnuSave": "Cuir i dtaisce é", + "FrmMain.MnuMoveToRecycleBin": "Bog chuig an mbosca bruscair í", + "FrmMain.MnuRefresh": "Athnuaigh é", + "FrmToolNotFound.LblHeading": "Níor aimsíodh '{0}'!", + "FrmMain.MnuReportIssue": "Tuairiscigh fadhb…", + "FrmMain.MnuCopyImageData": "Cóipeáil sonraí na híomhá", + "FrmMain.MnuCheckForUpdate._NewVersion": "Tá leagan nua de ar fáil!", + "_._Empty": "(folamh)", + "FrmSettings._Zooming": "Ag gluaiseacht", + "FrmMain.MnuCutFile": "Gearr an comhad", + "FrmHotkeyPicker.LblHotkey": "Press hotkeys", + "FrmSettings.Layout._Gallery": "Gallery", + "FrmMain.MnuNewWindow": "Oscail fuinneog nua", + "FrmMain.MnuMoveToRecycleBin._Description": "Do you want to move this file to the Recycle bin?", + "FrmSettings._DefaultPhotoViewer": "Default photo viewer", + "_.Metadata._ExifDateTimeOriginal": "EXIF: DateTimeOriginal", + "FrmMain.MnuRotateRight": "Rothlaigh deiseal í", + "FrmSettings._MinEmbeddedThumbnailSize": "Minimum size of the embedded thumbnail to be loaded", + "FrmMain.MnuSetDefaultPhotoViewer": "Set default photo viewer", + "FrmMain.MnuImageProperties": "Airíonna na híomhá", + "FrmSettings._EnableNavigationButtons": "Show navigation arrow buttons", + "_._Edit": "Eagar", + "FrmSettings._ImageBooster": "Image Booster", + "FrmSettings.Tools._IntegratedWith": "Integrated with {0}", + "_._Next": "Ar Aghaidh", + "FrmExportFrames._OpenOutputFolder": "Open output folder", + "FrmMain.MnuOpenLocation": "Oscail mar a bhfuil an íomhá lonnaithe", + "FrmMain.MnuLockZoom": "Cuir glas ar chóimheas na gluaise", + "FrmSettings._StartupBoost._Description": "Preload and run ImageGlass in the background for a few seconds during Windows startup to accelerate the first launch.", + "FrmSettings._WindowBackdrop": "Window backdrop", + "FrmSettings._EnableRealTimeFileUpdate": "Monitor file changes in the viewing folder and update in realtime", + "_._NotSupported": "Unsupported format", + "FrmSettings._Theme._GetMoreThemes": "Get more theme packs…", + "FrmMain.MnuNewWindow._Error": "Cannot open new window because only one instance is allowed", + "FrmMain.MnuZoomOut": "Gluais amach", + "FrmSettings.Toolbar._EditButton": "Edit toolbar button", + "FrmMain.MnuCustomZoom._Description": "Enter a new zoom value", + "FrmResize.RadResizeByPixels": "Pixels", + "FrmMain.MnuEdit": "Cuir an íomhá {0} in eagar…", + "FrmSettings.Layout._GalleryPosition": "Gallery position", + "FrmMain.MnuWindowFit": "Window Fit", + "FrmMain._OpenFileDialog": "Gach comhad a dtugtar tacaíocht dóibh", + "FrmSettings._UseRandomIntervalForSlideshow": "Bain feidhm as eatramh fánach", + "_.Position._Left": "Clé", + "FrmSettings._ShouldOpenLastSeenImage": "Open the last seen image", + "_.Position._Bottom": "Bun", + "FrmResize.ChkKeepRatio": "Keep ratio propotional", + "FrmMain.MnuGoTo": "Téigh chuig…", + "FrmSlideshow.MnuPauseResumeSlideshow": "Pause/resume slideshow", + "FrmSettings.Tools._Integrated": "Comhtháite", + "FrmSettings._Contributors": "Rannpháirtithe", + "_.MouseWheelAction._Zoom": "Gluais isteach / amach", + "_._CommandPreview": "Réamhamharc an ordaithe", + "FrmSettings._DarkTheme": "Dorcha", + "_._Hotkeys": "Hotkeys", + "_.Metadata._ExifDateTime": "EXIF: DateTime", + "FrmSettings.Toolbar._Errors._ButtonIdRequired": "Button ID required.", + "FrmSettings._MinEmbeddedThumbnailSize._Width": "Leithead", + "_._Executable": "Inrite", + "_.ImageInterpolation._MultiSampleLinear": "Multi-sample linear", + "_._Separator": "Deighilteoir", + "FrmQuickSetup._ProfessionalUser": "Professional user", + "FrmMain.MnuFlipVertical": "Smeach go hingearach í", + "FrmSlideshow._ResumeSlideshow": "Atosaíodh an taispeántas sleamhnáin.", + "FrmCropSettings.DefaultSelectionType._CustomArea": "Limistéar saincheaptha…", + "FrmMain.MnuActualSize": "Méid iarbhír", + "FrmCrop.BtnSaveAs": "Cuir é i dtaisce mar…", + "FrmSettings._InstallNewLanguagePack": "Install new language packs…", + "FrmSlideshow.MnuZoomModes": "Zoom modes", + "FrmMain.MnuTools": "Uirlisí", + "_.ImageInterpolation._Cubic": "Cubic", + "FrmUpdate._LatestVersion": "The latest version: {0}", + "FrmMain.MnuViewNext": "Féach ar an gcéad íomhá eile", + "_.MouseWheelEvent._AltAndScroll": "Hold Alt and scroll", + "FrmToolNotFound._Title": "Tool not found", + "FrmCrop.BtnCrop._Tooltip": "Crop the image only", + "FrmSettings.EditAppDialog._AddApp": "Add an app for editing", + "FrmMain.MnuPanning": "Panning", + "_._MoveUp": "Bog suas é", + "FrmCropSettings.DefaultSelectionType._SelectAll": "Roghnaigh uile", + "_._Name": "Ainm", + "FrmColorPickerSettings.ChkShowHslA": "Use HSL format with alpha value", + "FrmMain.MnuToggleImageAnimation": "Start / stop animating image", + "FrmSettings._DisableStartupBoost": "Disable Startup Boost", + "FrmMain.MnuCopyFile._Success": "Copied {0} file(s).", + "FrmMain.MnuSave._ConfirmDescription": "ImageGlass is not a professional photo editor, please be aware of losing the quality, metadata, layers,… when saving your image.", + "FrmToolNotFound.BtnSelectExecutable": "Roghnaigh…", + "FrmUpdate._StatusOutdated": "A new update is available!", + "_.ImageOrderBy._Random": "Go fánach", + "FrmResize.LblCurrentSize": "An méid reatha:", + "_._Apply": "Cuir i bhFeidhm", + "FrmAbout._Slogan": "Amharcóir íomhánna atá éadrom agus ilchumasach", + "FrmMain.MnuPanToTop": "Pan image to top", + "FrmSettings.Toolbar._AddNewButton": "Add a custom toolbar button", + "FrmCrop.LblSize": "An méid:", + "FrmSettings._ImageInterpolation._ScaleDown": "When zoom < 100%", + "_._CreatingFileError": "Could not create temporary image file", + "FrmMain.MnuGoTo._Description": "Enter the image index to view, and then press ENTER", + "FrmSettings.Toolbar._EnableCenterToolbar": "Use center alignment for toolbar", + "FrmMain.MnuResizeTool": "Resize image", + "FrmSettings.Layout._Toolbar": "Barra uirlisí", + "FrmMain.MnuHelp": "Cabhair", + "_.ImageOrderBy._FileSize": "Méid an chomhaid", + "FrmSettings._Theme._OpenThemeFolder": "Oscail fillteán an téama", + "FrmMain.MnuNavigation": "Nascleanúint", + "_._Save": "Cuir i dtaisce é", + "FrmQuickSetup._SettingProfileDescription": "To modify these settings, simply access app settings.", + "_._UserAction._MenuNotFound": "Cannot find menu '{0}' to invoke the action", + "FrmMain.MnuPanToLeftSide": "Pan image to left edge", + "FrmUpdate._CurrentVersion": "An leagan reatha: {0}", + "FrmCrop.BtnSettings._Tooltip": "Open Crop tool settings", + "_.ColorProfileOption._Custom": "Saincheaptha…", + "FrmSettings._UseEmbeddedThumbnailOtherFormats": "Load only the embedded thumbnail for other formats", + "FrmMain.MnuGoToFirst": "Go to first image", + "FrmSettings._ExportLanguagePack": "Export language pack…", + "FrmSettings.Nav._Mouse": "Luchóg", + "_.ImageOrderBy._DateCreated": "Date created", + "FrmSettings._EnableFullscreenSlideshow": "Start slideshow in Full Screen mode", + "FrmAbout._Homepage": "An leathanach baile:", + "FrmSettings._GalleryCacheSizeInMb": "Maximum gallery cache size (in megabytes)", + "FrmMain.MnuCopyImageData._Success": "Copied the current image data.", + "FrmSettings._EnableLoopBackNavigation": "Loop back to the first image when reaching the end of the image list", + "_.MouseWheelEvent._Scroll": "Scrollaigh", + "FrmCrop.BtnSave._Tooltip": "Cuir an íomhá i dtaisce", + "FrmMain.MnuSlideshow": "Taispeántas sleamhnáin", + "FrmMain.MnuShare": "Comhroinn…", + "FrmSettings._SlideshowNotification": "Slideshow notification", + "FrmMain.MnuViewChannels": "Féach ar na bealaí", + "FrmSettings._Refresh": "Athnuaigh é", + "_._UserAction._MethodNotFound": "Cannot find method '{0}' to invoke the action", + "FrmMain.MnuCopyFile": "Cóipeáil an comhad", + "_._CreatingFile": "Creating a temporary image file…", + "FrmMain.MnuToggleTopMost": "Coinnigh an fhuinneog ar barr i gcónaí", + "FrmMain.MnuLosslessCompression._Confirm": "An bhfuil tú cinnte gur mhaith leat dul ar aghaidh?", + "FrmMain.MnuImage": "Íomhá", + "FrmSettings._StartupBoost._Enabled": "Startup Boost is enabled", + "FrmQuickSetup._SetDefaultViewer": "Do you want to set ImageGlass as the default photo viewer?", + "FrmMain.MnuScaleToWidth": "Athraigh an scála chun é a chur in oiriúint don leithead", + "_._FileExtension": "Iarmhír an chomhaid", + "FrmUpdate._PublishedDate": "Dáta foilsithe: {0}", + "_._DoNotShowThisMessageAgain": "Ná taispeáin an teachtaireacht seo arís", + "_.ImageInterpolation._NearestNeighbor": "Nearest neighbor", + "FrmCrop.LblLocation": "Location:", + "_._Download": "Íosluchtaigh é", + "_.Metadata._ColorProfile": "Próifíl dhathanna", + "FrmSettings._CenterWindowFit": "Automatically center the window in Window Fit mode", + "FrmSettings._ImageLoadingOrder": "An t-ord ina dhéantar íomhánna a luchtú", + "FrmSettings._GalleryColumns": "Number of thumbnail columns in vertical gallery layout", + "_._Quit": "Scoir", + "_._Add": "Cuir leis", + "FrmMain.MnuChangeBackgroundColor": "Change background color…", + "FrmMain.MnuToggleToolbar": "Barra uirlisí", + "FrmAbout._Contact": "Teagmháil", + "FrmSettings.Toolbar._AddCustomButton": "Add a custom button…", + "FrmCrop.BtnQuickSelect._Tooltip": "Quick select…", + "FrmMain.MnuCutFile._Success": "Cut {0} file(s).", + "FrmSettings._ZoomSpeed": "Zoom speed", + "FrmMain.MnuToggleTopMost._Disable": "Disabled window always on top", + "FrmSettings._ShouldUseExplorerSortOrder": "Use Explorer sort order if possible", + "_.ImageInterpolation._Antisotropic": "Antisotropic", + "FrmMain._ReachedFirstImage": "Sroicheadh an chéad íomhá", + "_._UnhandledException": "Unhandled exception", + "FrmResize.LblNewSize": "Méid Nua:", + "FrmMain._ClipboardImage": "Clipboard image", + "FrmMain.MnuExportFrames": "Export image frames…", + "FrmMain.MnuFile": "Comhad", + "_._Close": "Dún", + "FrmMain.MnuMain": "Main menu", + "_._ResetToDefault": "Athshocraigh chuig an réamhshocrú é", + "FrmSettings.Nav._Gallery": "Gallery", + "FrmMain.MnuSetDefaultPhotoViewer._Success": "You have successfully set ImageGlass as default photo viewer.", + "FrmSettings._HideGalleryInFullscreen": "Hide gallery in Full Screen mode", + "FrmSettings._AvailableImageInfoTags": "Available tags:", + "FrmExportFrames._Exporting": "Exporting {0}/{1} frames \r\n{2}…", + "_._Argument": "Argument", + "FrmSettings._ImageEditQuality": "Cáilíocht na híomhá", + "_._ID": "ID", + "FrmSettings._UserConfigFile": "User settings file (igconfig.json)", + "FrmMain.MnuLoadingOrders": "Loading orders", + "FrmSettings._OpenSaveAsDialogInTheCurrentImageDir": "Open the Save As dialog in the current image directory", + "_.MouseWheelEvent._ShiftAndScroll": "Hold Shift and scroll", + "FrmSettings._UseSmoothZooming": "Use smooth zooming", + "FrmSettings._Theme": "Téama", + "FrmSettings._ImageBoosterCacheMaxDimension": "Maximum image dimension to be cached (in pixels)", + "FrmMain.MnuScaleToHeight": "Athraigh an scála chun é a chur in oiriúint don airde", + "_.Metadata._FileLastWriteTime": "Date modified", + "FrmSettings._Author": "Údar", + "FrmSettings._Others": "Eile", + "_.MouseWheelAction._PanVertically": "Pan up / down", + "FrmSettings._MouseWheelAction": "Mouse wheel action", + "FrmSettings.Nav._Tools": "Uirlisí", + "FrmMain.MnuSetDesktopBackground._Error": "Could not set the viewing image as desktop background", + "FrmSettings.Toolbar._Errors._ButtonExecutableRequired": "Button executable required.", + "_.ImageOrderBy._DateAccessed": "Date accessed", + "FrmSettings._ThumbnailSize": "Thumbnail size (in pixels)", + "FrmSettings._FileFormats": "File formats", + "FrmMain.MnuReloadImageList": "Athluchtaigh liosta na n-íomhánna", + "FrmSettings._UseWebview2ForSvg": "Use Webview2 for viewing SVG format", + "FrmCrop.BtnCopy": "Cóipeáil", + "FrmSettings._CurrentMonitorProfile._Description": "ImageGlass does not auto-update the color when moving its window between monitors", + "FrmMain.PicMain._ErrorText": "Could not open this image", + "FrmSettings.Tools._AddNewTool": "Add an external tool", + "FrmMain.MnuRename": "Athainmnigh an íomhá…", + "FrmMain.MnuViewLastFrame": "View last frame", + "_._Webview2._NotFound": "Please install WebView2 Runtime to access full features of ImageGlass.", + "FrmMain.MnuGetMoreTools": "Faigh uirlisí breise…", + "FrmSettings.Nav._Appearance": "Cuma", + "FrmSettings._SlideshowInterval": "Eatramh an taispeántais sleamhnáin:", + "_.ImageInterpolation._HighQualityBicubic": "High quality bicubic", + "FrmColorPickerSettings.ChkShowHsvA": "Use HSV format with alpha value", + "FrmSettings.Tools._EditTool": "Edit external tool", + "_._Error": "Earráid", + "FrmSettings._ImageBoosterCacheMaxFileSizeInMb": "Maximum image file size to be cached (in megabytes)", + "_._UnhandledException._Description": "Unhandled exception has occurred. If you click Continue, the application will ignore this error and attempt to continue. If you click Quit, the application will close immediately.", + "_.Metadata._FileSize": "Méid an chomhaid", + "FrmSettings.Toolbar._ButtonJson": "Button JSON", + "FrmQuickSetup._SetDefaultViewer._Description": "You can reset it in the app settings > File type associations tab.", + "FrmSettings.Nav._Edit": "Eagar", + "FrmMain.MnuToggleGallery": "Gallery panel", + "_._IgCommandExe._DefaultError._Description": "Make sure you pass the correct commands!\r\nThis executable file contains command-line functions for ImageGlass software.\r\n\r\nTo explore all command lines, please visit:\r\n{0}", + "FrmMain.MnuLosslessCompression._Compressing": "Performing lossless compression…", + "FrmSettings._ShouldGroupImagesByDirectory": "Cruinnigh íomhánna de réir comhadlainne", + "FrmMain.MnuPanToRightSide": "Pan image to right edge", + "_.Metadata._ExifRatingPercent": "Measúnú", + "FrmSettings._PanSpeed": "Panning speed", + "_._CheckForUpdate": "Lorg nuashonrú…", + "FrmSettings.Layout._ToolbarContext": "Contextual toolbar", + "_.ImageInfo._FrameCount": "{0} frame(s)", + "FrmMain.MnuLayout": "Leagan amach", + "_._Website": "Suíomh Gréasáin", + "FrmMain.MnuPasteImage": "Greamaigh an íomhá", + "FrmSettings._ShowGalleryScrollbars": "Show gallery scrollbars" + } +} \ No newline at end of file diff --git a/Setup/Assets/Language/Italian.iglang.json b/Setup/Assets/Language/Italian.iglang.json new file mode 100644 index 000000000..e618a408c --- /dev/null +++ b/Setup/Assets/Language/Italian.iglang.json @@ -0,0 +1,504 @@ +{ + "_Metadata": { + "Code": "it-IT", + "EnglishName": "Italian", + "LocalName": "Italiano", + "Author": "StarFang208", + "MinVersion": "9.3" + }, + "Items": { + "FrmCrop.SelectionAspectRatio._Original": "Originale", + "FrmMain.MnuShare._Error": "Impossibile aprire la finestra di condivisione", + "_.Metadata._FileLastAccessTime": "Data di accesso", + "FrmAbout._License": "Licenza software", + "FrmSettings.Toolbar._Errors._ButtonIdDuplicated": "Un pulsante con l'ID '{0}' è già stato definito. Scegli un ID diverso e univoco per il tuo pulsante per evitare conflitti.", + "FrmMain.MnuSave._Confirm": "Sei sicuro di voler sovrascrivere questa immagine?", + "FrmSettings._OpenDefaultAppsSetting": "Apri impostazioni app predefinite", + "FrmMain.MnuCopyPath": "Copia percorso immagine", + "FrmCropSettings.DefaultSelectionType._SelectNone": "Seleziona nessuno", + "_.MouseWheelAction._PanHorizontally": "Pan sinistra / destra", + "FrmMain.MnuPrint": "Stampa…", + "FrmSettings.Toolbar._ToolbarButtons": "Pulsanti barra strumenti", + "FrmResize.LblResample": "Riamplifica:", + "_.ImageOrderBy._Extension": "Estensione", + "FrmSettings.Nav._Viewer": "Visualizzatore", + "FrmSettings.EditAppDialog._EditApp": "Modifica app", + "FrmCrop.BtnReset._Tooltip": "Reimposta selezione", + "FrmMain.MnuRename._Description": "Inserisci nome del nuovo file:", + "_._No": "No", + "FrmSlideshow.MnuToggleCountdown": "Mostra conto alla rovescia presentazione", + "FrmSettings._OpenStartupAppsSetting": "Apri impostazioni app di avvio", + "FrmMain.MnuViewPreviousFrame": "Visualizza fotogramma precedente", + "_.ImageOrderBy._DateModified": "Data di modifica", + "FrmMain.MnuViewNextFrame": "Visualizza fotogramma successivo", + "FrmMain.MnuUnload": "Scarica immagine", + "FrmSettings.Toolbar._HideToolbarInFullscreen": "Nascondi la barra degli strumenti in modalità schermo intero", + "_.ImageOrderType._Desc": "Ordine decrescente", + "_._Update": "Aggiorna", + "FrmSettings._EnableImageAsyncLoading": "Abilita il caricamento asincrono dell'immagine", + "FrmSettings._DefaultPhotoViewer._Description": "Registra i formati supportati. Potrebbe essere necessario aprire le impostazioni delle app predefinite e selezionare manualmente ImageGlass dall'elenco.", + "_.MouseWheelAction._BrowseImages": "Visualizza immagine successiva / precedente", + "FrmSettings._EditApps": "App per la modifica di immagini", + "FrmColorPickerSettings.ChkShowCIELabA": "Usa il formato CIELAB con valore alfa", + "_._GetHelp": "Ricevi aiuto", + "FrmQuickSetup._SkipQuickSetup": "Salta questo e avvia ImageGlass", + "FrmColorPickerSettings._Title": "Impostazioni selettore colori", + "_._Copy": "Copia", + "FrmSettings._ImageBoosterCacheCount": "Numero di immagini nella cache di Image Booster (una direzione)", + "FrmMain.MnuPanToBottom": "Pan sul lato in basso", + "FrmMain.MnuZoom": "Zoom", + "FrmCropSettings.ChkCloseToolAfterSaving": "Chiudi strumento ritaglio dopo il salvataggio", + "FrmSettings._ShowWelcomeImage": "Mostra immagine di benvenuto", + "FrmSettings._ColorProfile": "Profilo colore", + "FrmSettings._Theme._UninstallTheme": "Disinstalla un pacchetto tema", + "FrmMain._OpenWith": "Apri con {0}", + "FrmMain.MnuRemoveDefaultPhotoViewer": "Rimuovi visualizzatore predefinito", + "_.AfterEditAppAction._Nothing": "Niente", + "FrmCrop.BtnSave": "Salva", + "FrmMain.MnuScaleToFit": "Adatta senza ritagliare", + "FrmToolNotFound.LblDownloadToolText": "È possibile scaricare altri strumenti per ImageGlass su:", + "_._LearnMore": "Scopri di più…", + "FrmCrop.LblAspectRatio": "Rapporto dimensioni:", + "FrmExportFrames._FileNotExist": "Il file immagine non esiste", + "FrmSettings._LightTheme": "Chiaro", + "FrmSettings.Nav._Slideshow": "Slideshow", + "_._Continue": "Continua", + "_._AddHotkey": "Aggiungi scorciatoia…", + "FrmMain.MnuSetDesktopBackground": "Imposta come sfondo del desktop", + "FrmMain.MnuReload": "Aggiorna immagine", + "FrmSlideshow.MnuExitSlideshow": "Uscita slideshow", + "FrmMain.MnuAutoZoom": "Zoom automatico", + "FrmSettings._ShowImagePreview": "Visualizza l'anteprima dell'immagine durante il caricamento", + "FrmCrop.BtnCopy._Tooltip": "Copia la selezione negli appunti", + "FrmSettings.Nav._Toolbar": "Barra degli strumenti", + "FrmMain.MnuSave._Error": "Impossibile salvare l'immagine", + "FrmSettings._AfterEditingAction": "Dopo aver aperto l'app di modifica", + "FrmSettings._ShouldUseColorProfileForAll": "Applicare anche per immagini senza profilo colore incorporato", + "FrmCropSettings.DefaultSelectionType._UseTheLastSelection": "Usa l'ultima selezione", + "FrmSettings._SlideshowInterval._From": "Da", + "FrmSettings._ImageInterpolation": "Interpolazione immagine", + "FrmQuickSetup._StepInfo": "Passo {0}", + "FrmMain.MnuColorPicker": "Selettore colori", + "FrmCrop.SelectionAspectRatio._FreeRatio": "Libero", + "FrmSettings._ResetSettings": "Ripristina impostazioni", + "FrmSettings._Startup": "Startup", + "_.BackdropStyle._None": "Nessuno", + "FrmSettings._LoadDefaultZoomLevels": "Carica livelli di zoom predefiniti", + "FrmColorPicker.BtnSettings._Tooltip": "Apri impostazioni selettore colore…", + "FrmSettings._UseThemeForDarkMode": "Usa questo tema per la modalità scura", + "FrmSettings._ShowDeleteConfirmation": "Mostra la finestra di conferma quando si elimina il file", + "FrmSettings._ShowAppIcon": "Mostra l'icona dell'app sulla barra del titolo", + "_._InvalidAction": "Azione non valida", + "FrmQuickSetup._SelectProfile": "Seleziona un profilo", + "_.Metadata._FileCreationTime": "Data creazione", + "FrmSettings._SlideshowImagesToNotifySound": "Numero di immagini per attivare un suono di notifica", + "FrmSettings._BackgroundColor": "Colore di sfondo", + "FrmSettings._RealTimeFileUpdate": "Aggiornamento file in tempo reale", + "_.ColorProfileOption._CurrentMonitorProfile": "Profilo monitor corrente", + "FrmSettings._EnableCutMultipleFiles": "Abilita il taglio di più file contemporaneamente", + "FrmSettings._AutoUpdate": "Controlla aggiornamenti automaticamente", + "FrmCropSettings.LblDefaultSelection": "Impostazioni di selezione predefinite", + "FrmSettings._UseThemeForLightMode": "Usa questo tema per la modalità chiara", + "FrmSettings._ZoomLevels": "Livelli di zoom", + "FrmMain.MnuSetLockScreen._Success": "Immagine della schermata di blocco aggiornata", + "FrmSettings._ShowGalleryFileName": "Mostra nome file miniatura", + "FrmSettings.Layout._Order": "Ordine", + "FrmCropSettings.ChkAutoCenterSelection": "Centra automaticamente la selezione", + "FrmSettings.Nav._FileTypeAssociations": "Associazioni file", + "_._Back": "Indietro", + "FrmMain.MnuSetDesktopBackground._Success": "Sfondo del desktop aggiornato", + "FrmSettings._ShouldAutoOpenNewAddedImage": "Apri automaticamente la nuova immagine aggiunta", + "FrmCrop.SelectionAspectRatio._Custom": "Personalizzato…", + "FrmMain.MnuCopyPath._Success": "Copiato il percorso dell'immagine corrente", + "FrmSettings._StartupBoost._Error": "Impossibile modificare l'impostazione di Startup Boost", + "FrmToolNotFound.LblDescription": "ImageGlass non è stato in grado di individuare il percorso dell'eseguibile '{0}'. Per risolvere questo problema, si prega di aggiornare il percorso al '{0}' se necessario.", + "FrmMain.MnuClearClipboard": "Cancella appunti", + "FrmSettings._ColorManagement": "Gestione colore", + "FrmMain._ReachedLastLast": "Raggiunta l'ultima immagine", + "FrmMain.MnuPanUp": "Pan immagine su", + "FrmMain.MnuRemoveDefaultPhotoViewer._Success": "ImageGlass non è più il visualizzatore predefinito", + "FrmSettings._GetMoreLanguagePacks": "Ottieni altri pacchetti lingua…", + "FrmAbout._Privacy": "Informativa sulla privacy", + "FrmSettings._EnableRecursiveLoading": "Carica immagini nelle sottocartelle", + "_._UserAction._MethodArgumentNotSupported": "Il tipo di argomento del metodo '{0}' non è supportato", + "FrmSettings._FileExtensionIcons._Description": "Per personalizzare le icone delle estensioni dei file, scarica un pacchetto di icone, posiziona tutti i file .ICO nella cartella Ext-Icons e fai clic sul pulsante '{0}'. Questo imposterà anche ImageGlass come visualizzatore predefinito.", + "_.ImageOrderType._Asc": "Successivo", + "FrmExportFrames._Title": "Esporta quadri immagine", + "_._Install": "Installa…", + "FrmMain.MnuFlipHorizontal": "Rifletti in orizzontale", + "FrmSettings._OpenExtensionIconFolder": "Apri cartella Ext-Icons", + "FrmAbout._Collaborator": "Collaboratore:", + "FrmQuickSetup._ConfirmCloseProcess": "Prima di applicare le nuove impostazioni, è essenziale chiudere tutti i processi di ImageGlass. Sei pronto a procedere?", + "FrmExportFrames._ExportDone": "Hai esportato con successo i frame {0} in \n{1}", + "FrmCrop.BtnSaveAs._Tooltip": "Salva come copia…", + "FrmMain.MnuOpenFile": "Apri file…", + "FrmColorPickerSettings.ChkShowRgbA": "Usa formato RGB con valore alfa", + "_.ImageInfo._ListCount": "File {0}", + "FrmMain.MnuGoToLast": "Va all'ultima immagine", + "FrmSettings._EditApps._AppName": "Nome App", + "FrmSettings._SlideshowBackgroundColor": "Colore di sfondo presentazione", + "FrmAbout._Email": "E-mail:", + "_.MouseWheelAction._DoNothing": "Non fare nulla", + "FrmMain.MnuSaveAs": "Salva come…", + "FrmMain._Loading": "Caricamento…", + "_._Browse": "Sfoglia…", + "FrmMain.MnuSetDefaultPhotoViewer._Error": "Impossibile impostare ImageGlass come visualizzatore predefinito", + "FrmSettings.Nav._Language": "Lingua", + "FrmQuickSetup._SeeWhatNew": "Scopri cosa c'è di nuovo in questa versione…", + "FrmSettings._ImageInterpolation._ScaleUp": "Quando zoom > 100%", + "FrmSettings.Layout._ToolbarContextPosition": "Posizione della barra contestuale", + "FrmMain.MnuDeleteFromHardDisk": "Elimina definitivamente", + "FrmSettings._EmbeddedThumbnail": "Miniatura integrata", + "FrmMain.MnuDeleteFromHardDisk._Description": "Sei sicuro di voler eliminare definitivamente questo file?", + "FrmMain.MnuScaleToFill": "Espandi con ritaglio", + "FrmCrop.BtnCrop": "Ritaglia", + "_.AfterEditAppAction._Minimize": "Minimizza", + "FrmMain.MnuInvertColors": "Inverti colori", + "FrmSettings._StartupBoost": "Startup Boost", + "FrmMain.MnuViewFirstFrame": "Visualizza il primo fotogramma", + "_.MouseWheelEvent._CtrlAndScroll": "Tieni premuto Ctrl e scorri", + "FrmSettings._HideMainWindowInSlideshow": "Nascondi automaticamente la finestra principale", + "_.Metadata._FrameCount": "Fotogrammi", + "FrmSettings._EnableCopyMultipleFiles": "Abilita la copia di più file contemporaneamente", + "FrmMain.MnuFrameless._EnableDescription": "Tieni premuto il tasto Maiusc per spostare la finestra", + "_.ImageOrderBy._ExifDateTaken": "EXIF: Data di scatto", + "FrmAbout._Credits": "Riconoscimenti", + "FrmSettings._AddNewFileExtension": "Aggiungi una nuova estensione", + "FrmMain.MnuQuickSetup": "Apri Configurazione rapida ImageGlass", + "FrmMain.MnuSave._Success": "Immagine salvata", + "FrmMain.MnuPanLeft": "Pan a sinistra", + "FrmUpdate._StatusChecking": "Controllo aggiornamenti…", + "FrmSettings.Nav._Layout": "Layout", + "FrmMain.MnuOpenWith": "Apri con…", + "FrmAbout._Thanks": "Ringraziamenti speciali a:", + "_._Warning": "Avviso", + "FrmSettings.Nav._Keyboard": "Tastiera", + "FrmSlideshow._PauseSlideshow": "La presentazione è in pausa", + "_._Add+": "Aggiungi…", + "_._Email": "Email", + "FrmMain.MnuPanDown": "Pan in basso", + "_._Cancel": "Annulla", + "_._OK": "OK", + "FrmMain.MnuPanRight": "Pan a destra", + "_.Position._Right": "Destra", + "_._Icon": "Icona", + "FrmSettings._ShouldLoadHiddenImages": "Carica immagini nascoste", + "_._InvalidAction._Transformation": "ImageGlass non supporta rotazione e capovolgimento di questa immagine", + "FrmSettings._MakeDefault": "Rendi predefinito", + "FrmMain.MnuCopyImageData._Copying": "Copia dei dati dell'immagine. Ci vorrà un po' di tempo…", + "FrmSettings._UseEmbeddedThumbnailRawFormats": "Carica solo la miniatura incorporata per formati RAW", + "_.ImageInterpolation._Linear": "Lineare", + "FrmSettings._ImageInfoTags": "Etichette informazioni immagine", + "FrmSettings._FileExtensionIcons": "Icone di estensione file", + "FrmMain.MnuEdit._AppNotFound": "Impossibile trovare l'app associata per la modifica. È possibile assegnare un'app per modificare questo formato in Impostazioni > Modifica", + "_.ColorProfileOption._None": "Nessuno", + "FrmSettings._TotalSupportedFormats": "Totale formati supportati: {0}", + "FrmSettings._Clipboard": "Appunti", + "_._UserAction._Win32ExeError": "Impossibile eseguire il comando '{0}'. Assicurarsi che il nome sia corretto", + "FrmCropSettings.DefaultSelectionType._SelectX": "Seleziona {0}", + "_.AfterEditAppAction._Close": "Chiudi", + "FrmAbout._LogoDesigner": "Logo designer:", + "_.ImageOrderBy._Name": "Nome (impostazione predefinita)", + "FrmMain.MnuRemoveDefaultPhotoViewer._Error": "Impossibile rimuovere ImageGlass come visualizzatore predefinito", + "FrmExportFrames._FolderPickerTitle": "Seleziona la cartella di output per esportare i quadri immagine", + "FrmAbout._Donate": "Dona", + "FrmMain.MnuFrameNav": "Navigazione per pagina", + "FrmMain.MnuSetLockScreen": "Imposta nella schermata di blocco", + "_._Delete": "Elimina", + "FrmMain.MnuViewPrevious": "Visualizza l'immagine precedente", + "_.Position._Top": "Sopra", + "FrmSettings.Toolbar._CurrentButtons": "Pulsanti attuali:", + "FrmMain.MnuAbout": "Informazioni", + "FrmSettings._RemoveDefault": "Rimuovi predefinito", + "_._Description": "Descrizione", + "FrmMain.MnuPasteImage._Error": "Impossibile trovare i dati dell'immagine negli appunti", + "FrmMain.MnuSettings": "Impostazioni", + "FrmCropSettings._Title": "Impostazioni di ritaglio", + "FrmSettings.Toolbar._ToolbarIconHeight": "Dimensione icone nella barra strumenti", + "FrmSettings._SlideshowInterval._To": "A", + "FrmSettings.Layout._ToolbarPosition": "Posizione barra strumenti", + "FrmUpdate._StatusUpdated": "Stai usando l'ultima versione!", + "FrmMain.MnuExit": "Esci", + "_._Webview2._Outdated": "Il tuo WebView2 Runtime non è supportato. Si prega di aggiornare alla versione {0} o successiva", + "_._Yes": "Sì", + "FrmMain.MnuRotateLeft": "Ruota a sinistra", + "FrmSettings._EnableStartupBoost": "Abilita Startup Boost", + "_.ImageOrderBy._ExifRating": "EXIF: Valutazione", + "FrmMain.MnuZoomIn": "Ingrandisci", + "_.Metadata._ColorSpace": "Spazio colore", + "FrmAbout._Version": "Versione:", + "FrmMain.MnuToggleTopMost._Enable": "Finestra abilitata sempre in alto", + "FrmSettings.Toolbar._AvailableButtons": "Pulsanti disponibili:", + "FrmMain.MnuSave._Saving": "Salvataggio immagine…", + "FrmQuickSetup._StandardUser": "Utente Standard", + "FrmMain.MnuSetLockScreen._Error": "Impossibile impostare l'immagine di visualizzazione come immagine di blocco schermo", + "FrmSettings.Nav._Image": "Immagine", + "FrmSettings._Theme._InstallTheme": "Installa pacchetti tema", + "FrmSettings._EnableMultiInstances": "Consentire più istanze del programma", + "FrmMain.MnuCropTool": "Ritaglia immagine", + "_._IgCommandExe._DefaultError._Heading": "Comandi non validi", + "_._Refresh": "Aggiorna", + "FrmMain.MnuLosslessCompression._Description": "Questo strumento utilizza la libreria Magick.net per la compressione senza perdita, ottimizzando la dimensione del file. Sovrascrive solo se il file compresso è più piccolo dell'originale.", + "_._MoveDown": "Sposta giù", + "FrmSettings._GetExtensionIconPacks": "Ottieni pacchetti icone estensioni…", + "FrmSettings._InAppMessageDuration": "Durata del messaggio in-app (millisecondi)", + "FrmMain.MnuFrameless": "Senza cornice", + "_._Reset": "Reset", + "FrmSettings._ConfigDir": "Posizione di configurazione", + "FrmQuickSetup._SettingsWillBeApplied": "Le impostazioni verranno applicate:", + "FrmSettings._UnmanagedSettingReminder": "Questa impostazione non è gestita da ImageGlass. Non dimenticare di disabilitarla prima di rimuovere o trasferire l'app perché ImageGlass non la gestisce automaticamente.", + "FrmMain.MnuClipboard": "Appunti", + "FrmMain.MnuCustomZoom": "Zoom personalizzato…", + "FrmSettings._DisplayLanguage": "Visualizza lingua", + "FrmMain.MnuPrint._Error": "Impossibile stampare l'immagine", + "FrmSettings._ShouldPreserveModifiedDate": "Conserva la data modificata dell'immagine al salvataggio", + "FrmSettings._ShowSaveOverrideConfirmation": "Mostra la finestra di conferma quando sovrascrivi il file", + "FrmColorPickerSettings.ChkShowHexA": "Usa il formato HEX con valore alfa", + "FrmMain.MnuFullScreen": "Schermo Intero", + "FrmSettings._StartupDir": "Posizione di avvio", + "FrmSettings._ShowCheckerboardOnlyImageRegion": "Mostra la scacchiera solo nella regione dell'immagine", + "FrmMain.MnuClearClipboard._Success": "Appunti cancellati", + "FrmQuickSetup._Text": "Configurazione rapida ImageGlass", + "FrmMain.MnuLosslessCompression._Done": "Eseguita compressione lossless.\r\nLa nuova dimensione è {0}, salvato {1}", + "FrmMain.MnuLosslessCompression": "Magick.NET compressione lossless", + "FrmResize.RadResizeByPercentage": "Percentuale", + "FrmSettings._StartupBoost._Disabled": "Startup Boost è disabilitato", + "FrmMain.MnuToggleCheckerboard": "Sfondo selezionato", + "FrmSettings._MinEmbeddedThumbnailSize._Height": "Altezza", + "FrmSettings.Nav._General": "Generale", + "FrmSettings._ImageLoading": "Caricamento immagine", + "FrmSettings._ShowSlideshowCountdown": "Mostra conto alla rovescia presentazione", + "FrmMain.MnuSave": "Salva", + "FrmMain.MnuMoveToRecycleBin": "Sposta nel Cestino", + "FrmMain.MnuRefresh": "Aggiorna", + "FrmToolNotFound.LblHeading": "'{0}' non è stato trovato!", + "FrmMain.MnuReportIssue": "Segnala un problema…", + "FrmMain.MnuCopyImageData": "Copia dati immagine", + "FrmMain.MnuCheckForUpdate._NewVersion": "È disponibile una nuova versione!", + "_._Empty": "(vuoto)", + "FrmSettings._Zooming": "Ridimensiona", + "FrmMain.MnuCutFile": "Taglia file", + "FrmHotkeyPicker.LblHotkey": "Premere i tasti", + "FrmSettings.Layout._Gallery": "Galleria", + "FrmMain.MnuNewWindow": "Apri nuova finestra", + "FrmMain.MnuMoveToRecycleBin._Description": "Vuoi spostare questo file nel cestino?", + "FrmSettings._DefaultPhotoViewer": "Visualizzatore predefinito", + "_.Metadata._ExifDateTimeOriginal": "EXIF: DateTimeOriginal", + "FrmMain.MnuRotateRight": "Ruota a destra", + "FrmSettings._MinEmbeddedThumbnailSize": "Dimensione minima della miniatura incorporata da caricare", + "FrmMain.MnuSetDefaultPhotoViewer": "Imposta visualizzatore predefinito", + "FrmMain.MnuImageProperties": "Proprietà dell'immagine", + "FrmSettings._EnableNavigationButtons": "Mostra pulsanti freccia di navigazione", + "_._Edit": "Modifica", + "FrmSettings._ImageBooster": "Booster immagine", + "FrmSettings.Tools._IntegratedWith": "Integrato con {0}", + "_._Next": "Successivo", + "FrmExportFrames._OpenOutputFolder": "Apri cartella di output", + "FrmMain.MnuOpenLocation": "Apri la cartella del file", + "FrmMain.MnuLockZoom": "Blocca ingrandimento", + "FrmSettings._StartupBoost._Description": "Precarica e avvia ImageGlass in background per alcuni secondi durante l'avvio di Windows per accelerare il primo avvio.", + "FrmSettings._WindowBackdrop": "Sfondo finestra", + "FrmSettings._EnableRealTimeFileUpdate": "Monitora le modifiche dei file nella cartella di visualizzazione e aggiorna in tempo reale", + "_._NotSupported": "Formato non supportato", + "FrmSettings._Theme._GetMoreThemes": "Ottieni altri pacchetti di temi…", + "FrmMain.MnuNewWindow._Error": "Impossibile aprire la nuova finestra perché è consentita una sola istanza", + "FrmMain.MnuZoomOut": "Ridimensiona:", + "FrmSettings.Toolbar._EditButton": "Modifica pulsante barra strumenti", + "FrmMain.MnuCustomZoom._Description": "Inserisci un nuovo valore di zoom", + "FrmResize.RadResizeByPixels": "Pixel", + "FrmMain.MnuEdit": "Modifica immagine {0}…", + "FrmSettings.Layout._GalleryPosition": "Posizione galleria", + "FrmMain.MnuWindowFit": "Adatta finestra", + "FrmMain._OpenFileDialog": "Tutti i formati di file supportati", + "FrmSettings._UseRandomIntervalForSlideshow": "Usa intervallo casuale", + "_.Position._Left": "Sinistra", + "FrmSettings._ShouldOpenLastSeenImage": "Apre l'ultima immagine vista", + "_.Position._Bottom": "Sotto", + "FrmResize.ChkKeepRatio": "Mantieni proporzioni", + "FrmMain.MnuGoTo": "Vai a…", + "FrmSlideshow.MnuPauseResumeSlideshow": "Pausa / ripresa slideshow", + "FrmSettings.Tools._Integrated": "Integrato", + "FrmSettings._Contributors": "Collaboratori", + "_.MouseWheelAction._Zoom": "Ingrandisci / rimpicciolisci", + "_._CommandPreview": "Anteprima del comando", + "FrmSettings._DarkTheme": "Scuro", + "_._Hotkeys": "Tasti di scelta rapida", + "_.Metadata._ExifDateTime": "EXIF: DateTime", + "FrmSettings.Toolbar._Errors._ButtonIdRequired": "ID pulsante richiesto", + "FrmSettings._MinEmbeddedThumbnailSize._Width": "Larghezza", + "_._Executable": "Eseguibile", + "_.ImageInterpolation._MultiSampleLinear": "Multi-campione lineare", + "_._Separator": "Separatore", + "FrmQuickSetup._ProfessionalUser": "Utente professionale", + "FrmMain.MnuFlipVertical": "Rifletti in verticale", + "FrmSlideshow._ResumeSlideshow": "La presentazione è ripresa", + "FrmCropSettings.DefaultSelectionType._CustomArea": "Area personalizzata…", + "FrmMain.MnuActualSize": "Dimensione effettiva", + "FrmCrop.BtnSaveAs": "Salva come…", + "FrmSettings._InstallNewLanguagePack": "Installa nuovi pacchetti linguistici…", + "FrmSlideshow.MnuZoomModes": "Modalità Zoom", + "FrmMain.MnuTools": "Strumenti", + "_.ImageInterpolation._Cubic": "Cubico", + "FrmUpdate._LatestVersion": "L'ultima versione: {0}", + "FrmMain.MnuViewNext": "Visualizza l'immagine successiva", + "_.MouseWheelEvent._AltAndScroll": "Tieni premuto Alt e scorri", + "FrmToolNotFound._Title": "Strumento non trovato", + "FrmCrop.BtnCrop._Tooltip": "Ritaglia solo l'immagine", + "FrmSettings.EditAppDialog._AddApp": "Aggiungi un'app per la modifica", + "FrmMain.MnuPanning": "Panoramica", + "_._MoveUp": "Sposta su", + "FrmCropSettings.DefaultSelectionType._SelectAll": "Seleziona tutto", + "_._Name": "Nome", + "FrmColorPickerSettings.ChkShowHslA": "Usa formato HSL con valore alfa", + "FrmMain.MnuToggleImageAnimation": "Avvia / ferma l'animazione dell'immagine", + "FrmSettings._DisableStartupBoost": "Disabilita Startup Boost", + "FrmMain.MnuCopyFile._Success": "File {0} copiati", + "FrmMain.MnuSave._ConfirmDescription": "ImageGlass non è un editor fotografico professionale. Il salvataggio dell'immagine comporta la perdita di qualità, metadati e livelli.", + "FrmToolNotFound.BtnSelectExecutable": "Seleziona…", + "FrmUpdate._StatusOutdated": "Un nuovo aggiornamento è disponibile!", + "_.ImageOrderBy._Random": "Casuale", + "FrmResize.LblCurrentSize": "Dimensione attuale:", + "_._Apply": "Applica", + "FrmAbout._Slogan": "Un visualizzatore di immagini leggero, versatile", + "FrmMain.MnuPanToTop": "Pan sul lato in alto", + "FrmSettings.Toolbar._AddNewButton": "Aggiungi un pulsante personalizzato nella barra degli strumenti", + "FrmCrop.LblSize": "Dimensione:", + "FrmSettings._ImageInterpolation._ScaleDown": "Quando zoom < 100%", + "_._CreatingFileError": "Impossibile creare il file immagine temporaneo", + "FrmMain.MnuGoTo._Description": "Inserire l'indice dell'immagine da visualizzare, quindi premere INVIO", + "FrmSettings.Toolbar._EnableCenterToolbar": "Usa l'allineamento centrale per la barra degli strumenti", + "FrmMain.MnuResizeTool": "Ridimensiona immagine", + "FrmSettings.Layout._Toolbar": "Barra degli strumenti", + "FrmMain.MnuHelp": "Aiuto", + "_.ImageOrderBy._FileSize": "Dimensione file", + "FrmSettings._Theme._OpenThemeFolder": "Apri cartella tema", + "FrmMain.MnuNavigation": "Navigazione", + "_._Save": "Salva", + "FrmQuickSetup._SettingProfileDescription": "Per modificare queste impostazioni, basta accedere a Impostazioni dell'app", + "_._UserAction._MenuNotFound": "Impossibile trovare il menu '{0}' per invocare l'azione", + "FrmMain.MnuPanToLeftSide": "Pan sul lato sinistro", + "FrmUpdate._CurrentVersion": "Versione attuale: {0}", + "FrmCrop.BtnSettings._Tooltip": "Apri le impostazioni dello strumento ritaglio", + "_.ColorProfileOption._Custom": "Personalizzato…", + "FrmSettings._UseEmbeddedThumbnailOtherFormats": "Carica solo la miniatura incorporata per altri formati", + "FrmMain.MnuGoToFirst": "Vai alla prima immagine", + "FrmSettings._ExportLanguagePack": "Esporta pacchetto lingua…", + "FrmSettings.Nav._Mouse": "Mouse", + "_.ImageOrderBy._DateCreated": "Data creazione", + "FrmSettings._EnableFullscreenSlideshow": "Avvia Slideshow a schermo intero", + "FrmAbout._Homepage": "Homepage:", + "FrmSettings._GalleryCacheSizeInMb": "Dimensione massima cache della galleria (in megabyte)", + "FrmMain.MnuCopyImageData._Success": "Copiato i dati dell'immagine corrente", + "FrmSettings._EnableLoopBackNavigation": "Ritornare alla prima immagine quando si raggiunge la fine dell'elenco immagini", + "_.MouseWheelEvent._Scroll": "Scrolla", + "FrmCrop.BtnSave._Tooltip": "Salva immagine", + "FrmMain.MnuSlideshow": "Slideshow", + "FrmMain.MnuShare": "Condividi…", + "FrmSettings._SlideshowNotification": "Notifica presentazione", + "FrmMain.MnuViewChannels": "Vedi canali", + "FrmSettings._Refresh": "Aggiorna", + "_._UserAction._MethodNotFound": "Impossibile trovare il metodo '{0}' per invocare l'azione", + "FrmMain.MnuCopyFile": "Copia file", + "_._CreatingFile": "Creazione di un file immagine temporaneo…", + "FrmMain.MnuToggleTopMost": "Manteni la finestra in primo piano", + "FrmMain.MnuLosslessCompression._Confirm": "Sei sicuro di voler procedere?", + "FrmMain.MnuImage": "Immagine", + "FrmSettings._StartupBoost._Enabled": "Startup Boost è abilitato", + "FrmQuickSetup._SetDefaultViewer": "Vuoi impostare ImageGlass come visualizzatore predefinito?", + "FrmMain.MnuScaleToWidth": "Adatta alla larghezza", + "_._FileExtension": "Estensioni file", + "FrmUpdate._PublishedDate": "Data di pubblicazione: {0}", + "_._DoNotShowThisMessageAgain": "Non mostrare più questo messaggio", + "_.ImageInterpolation._NearestNeighbor": "Vicino più vicino", + "FrmCrop.LblLocation": "Posizione:", + "_._Download": "Scarica", + "_.Metadata._ColorProfile": "Profilo colore", + "FrmSettings._CenterWindowFit": "Centra automaticamente la finestra in modalità Adatta finestra", + "FrmSettings._ImageLoadingOrder": "Ordina per:", + "FrmSettings._GalleryColumns": "Numero di colonne delle miniature nel layout verticale della galleria", + "_._Quit": "Esci", + "_._Add": "Aggiungi", + "FrmMain.MnuChangeBackgroundColor": "Cambia colore di sfondo…", + "FrmMain.MnuToggleToolbar": "Barra degli strumenti", + "FrmAbout._Contact": "Contatti", + "FrmSettings.Toolbar._AddCustomButton": "Aggiungi un pulsante personalizzato…", + "FrmCrop.BtnQuickSelect._Tooltip": "Selezione rapida…", + "FrmMain.MnuCutFile._Success": "Taglia file {0}", + "FrmSettings._ZoomSpeed": "Velocità ingrandimento", + "FrmMain.MnuToggleTopMost._Disable": "Disabilitato Finestra in primo piano", + "FrmSettings._ShouldUseExplorerSortOrder": "Usa l'ordine di Windows File Explorer se possibile", + "_.ImageInterpolation._Antisotropic": "Anisotropico", + "FrmMain._ReachedFirstImage": "Raggiunta la prima immagine", + "_._UnhandledException": "Eccezione non gestita", + "FrmResize.LblNewSize": "Nuova dimensione:", + "FrmMain._ClipboardImage": "Immagine appunti", + "FrmMain.MnuExportFrames": "Esporta quadri immagine…", + "FrmMain.MnuFile": "File", + "_._Close": "Chiudi", + "FrmMain.MnuMain": "Menu principale", + "_._ResetToDefault": "Ripristina impostazioni predefinite", + "FrmSettings.Nav._Gallery": "Galleria", + "FrmMain.MnuSetDefaultPhotoViewer._Success": "Hai impostato con successo ImageGlass come visualizzatore predefinito", + "FrmSettings._HideGalleryInFullscreen": "Nascondi la galleria in modalità schermo intero", + "FrmSettings._AvailableImageInfoTags": "Etichette disponibili:", + "FrmExportFrames._Exporting": "Esportazione {0}/{1} frame \n{2}…", + "_._Argument": "Argomento", + "FrmSettings._ImageEditQuality": "Qualità dell'immagine", + "_._ID": "ID", + "FrmSettings._UserConfigFile": "File impostazioni utente (igconfig.json)", + "FrmMain.MnuLoadingOrders": "Ordina per", + "FrmSettings._OpenSaveAsDialogInTheCurrentImageDir": "Apri la finestra 'Salva come…' nella directory dell'immagine corrente", + "_.MouseWheelEvent._ShiftAndScroll": "Tieni premuto Maiusc e scorri", + "FrmSettings._UseSmoothZooming": "Usa zoom regolare", + "FrmSettings._Theme": "Tema", + "FrmSettings._ImageBoosterCacheMaxDimension": "Dimensione massima dell'immagine da inserire nella cache (in pixel)", + "FrmMain.MnuScaleToHeight": "Adatta all'altezza", + "_.Metadata._FileLastWriteTime": "Data di modifica", + "FrmSettings._Author": "Autore", + "FrmSettings._Others": "Altri", + "_.MouseWheelAction._PanVertically": "Pan su / giù", + "FrmSettings._MouseWheelAction": "Opzioni rotella di scorrimento", + "FrmSettings.Nav._Tools": "Strumenti", + "FrmMain.MnuSetDesktopBackground._Error": "Impossibile impostare l'immagine come sfondo del desktop", + "FrmSettings.Toolbar._Errors._ButtonExecutableRequired": "Eseguibile richiesto", + "_.ImageOrderBy._DateAccessed": "Data di accesso", + "FrmSettings._ThumbnailSize": "Dimensione miniatura (in pixel)", + "FrmSettings._FileFormats": "Formati file", + "FrmMain.MnuReloadImageList": "Ricarica lista immagini", + "FrmSettings._UseWebview2ForSvg": "Usa Webview2 per visualizzare il formato SVG", + "FrmCrop.BtnCopy": "Copia", + "FrmSettings._CurrentMonitorProfile._Description": "ImageGlass non aggiorna automaticamente il colore quando si sposta la sua finestra tra i monitor", + "FrmMain.PicMain._ErrorText": "Impossibile aprire questa immagine", + "FrmSettings.Tools._AddNewTool": "Aggiunge uno strumento esterno", + "FrmMain.MnuRename": "Rinomina immagine…", + "FrmMain.MnuViewLastFrame": "Visualizza l'ultimo fotogramma", + "_._Webview2._NotFound": "Si prega di installare l'ultima versione di WebView2 Runtime.", + "FrmMain.MnuGetMoreTools": "Ottieni altri strumenti…", + "FrmSettings.Nav._Appearance": "Aspetto", + "FrmSettings._SlideshowInterval": "Intervallo fra le immagini:", + "_.ImageInterpolation._HighQualityBicubic": "Bicubico di alta qualità", + "FrmColorPickerSettings.ChkShowHsvA": "Usa formato HSV con valore alfa", + "FrmSettings.Tools._EditTool": "Modifica strumento esterno", + "_._Error": "Errore", + "FrmSettings._ImageBoosterCacheMaxFileSizeInMb": "Dimensione massima del file da memorizzare nella cache (in megabyte)", + "_._UnhandledException._Description": "Eccezione non gestita. Se si fa clic su Continua, l'applicazione ignorerà questo errore e tenterà di continuare. Se fai clic su Esci, l'applicazione si chiuderà immediatamente.", + "_.Metadata._FileSize": "Dimensione file", + "FrmSettings.Toolbar._ButtonJson": "Pulsante JSON", + "FrmQuickSetup._SetDefaultViewer._Description": "È possibile reimpostarlo in Impostazioni > Associazioni file", + "FrmSettings.Nav._Edit": "Modifica", + "FrmMain.MnuToggleGallery": "Pannello galleria", + "_._IgCommandExe._DefaultError._Description": "Assicurati di passare i comandi corretti!\r\nQuesto file eseguibile contiene funzioni da riga di comando per il software ImageGlass.\r\n\r\nPer esplorare tutte le linee di comando, visitare:\n{0}", + "FrmMain.MnuLosslessCompression._Compressing": "Compressione senza perdita in corso…", + "FrmSettings._ShouldGroupImagesByDirectory": "Raggruppa le immagini per directory", + "FrmMain.MnuPanToRightSide": "Pan sul lato destro", + "_.Metadata._ExifRatingPercent": "Valutazione", + "FrmSettings._PanSpeed": "Velocità di panning", + "_._CheckForUpdate": "Controlla gli aggiornamenti…", + "FrmSettings.Layout._ToolbarContext": "Barra contestuale", + "_.ImageInfo._FrameCount": "Frame {0}", + "FrmMain.MnuLayout": "Layout", + "_._Website": "Sito web", + "FrmMain.MnuPasteImage": "Incolla immagine", + "FrmSettings._ShowGalleryScrollbars": "Mostra barre di scorrimento galleria" + } +} \ No newline at end of file diff --git a/Setup/Assets/Language/Japanese.iglang.json b/Setup/Assets/Language/Japanese.iglang.json new file mode 100644 index 000000000..9927c51d2 --- /dev/null +++ b/Setup/Assets/Language/Japanese.iglang.json @@ -0,0 +1,504 @@ +{ + "_Metadata": { + "Code": "ja-JP", + "EnglishName": "Japanese", + "LocalName": "日本語", + "Author": "Cue, KAWASAKICHIRO, Dice K, AdiXZ01, 片山朋和, tena4, wikeaka, tam330", + "MinVersion": "9.3" + }, + "Items": { + "FrmCrop.SelectionAspectRatio._Original": "オリジナル", + "FrmMain.MnuShare._Error": "共有ダイアログを開けませんでした。", + "_.Metadata._FileLastAccessTime": "アクセス日時", + "FrmAbout._License": "ソフトウェアライセンス", + "FrmSettings.Toolbar._Errors._ButtonIdDuplicated": "ボタンID「{0}」は既に使用されています 異なるユニークなIDを指定してください。", + "FrmMain.MnuSave._Confirm": "この画像を上書きしてもよろしいですか?", + "FrmSettings._OpenDefaultAppsSetting": "既定のアプリ設定を開く", + "FrmMain.MnuCopyPath": "画像のパス(場所)をコピー", + "FrmCropSettings.DefaultSelectionType._SelectNone": "選択を解除", + "_.MouseWheelAction._PanHorizontally": "表示範囲を移動(左右)", + "FrmMain.MnuPrint": "印刷…", + "FrmSettings.Toolbar._ToolbarButtons": "ツールバーのボタン", + "FrmResize.LblResample": "リサンプル:", + "_.ImageOrderBy._Extension": "拡張子", + "FrmSettings.Nav._Viewer": "ビューア", + "FrmSettings.EditAppDialog._EditApp": "アプリを編集", + "FrmCrop.BtnReset._Tooltip": "選択をリセット", + "FrmMain.MnuRename._Description": "新しいファイル名を入力:", + "_._No": "いいえ", + "FrmSlideshow.MnuToggleCountdown": "スライドショーの残り枚数を表示する", + "FrmSettings._OpenStartupAppsSetting": "起動設定を開く", + "FrmMain.MnuViewPreviousFrame": "前のフレームを見る", + "_.ImageOrderBy._DateModified": "更新日時", + "FrmMain.MnuViewNextFrame": "次のフレームを見る", + "FrmMain.MnuUnload": "画像を閉じる", + "FrmSettings.Toolbar._HideToolbarInFullscreen": "フルスクリーンモードでツールバーを隠す", + "_.ImageOrderType._Desc": "降順", + "_._Update": "アップデート", + "FrmSettings._EnableImageAsyncLoading": "画像の非同期読み込みを有効にする", + "FrmSettings._DefaultPhotoViewer._Description": "WindowsにImageGlassでサポートされているファイルフォーマットを登録します。 自動設定が上手く機能しない場合、「既定のアプリ」の設定で手動でImageGlassを指定する必要があります。", + "_.MouseWheelAction._BrowseImages": "次/前の画像を表示", + "FrmSettings._EditApps": "画像編集アプリ", + "FrmColorPickerSettings.ChkShowCIELabA": "アルファ値付きのCIELAB形式を使用", + "_._GetHelp": "ヘルプ", + "FrmQuickSetup._SkipQuickSetup": "スキップしてImageGlassを起動", + "FrmColorPickerSettings._Title": "カラーピッカーの設定", + "_._Copy": "コピー", + "FrmSettings._ImageBoosterCacheCount": "キャッシュする画像の数 (単方向)", + "FrmMain.MnuPanToBottom": "下端に寄せて表示", + "FrmMain.MnuZoom": "拡大/縮小", + "FrmCropSettings.ChkCloseToolAfterSaving": "保存後にトリミングツールを閉じる", + "FrmSettings._ShowWelcomeImage": "ウェルカム画像を表示", + "FrmSettings._ColorProfile": "カラープロファイル", + "FrmSettings._Theme._UninstallTheme": "テーマパックをアンインストール", + "FrmMain._OpenWith": "{0}で開く", + "FrmMain.MnuRemoveDefaultPhotoViewer": "既定のフォトビューアから削除", + "_.AfterEditAppAction._Nothing": "何もしない", + "FrmCrop.BtnSave": "保存", + "FrmMain.MnuScaleToFit": "ウィンドウサイズに合わせる", + "FrmToolNotFound.LblDownloadToolText": "ImageGlass用の追加ツールをダウンロードすることができます:", + "_._LearnMore": "詳細", + "FrmCrop.LblAspectRatio": "アスペクト比:", + "FrmExportFrames._FileNotExist": "画像ファイルが存在しません", + "FrmSettings._LightTheme": "ライト", + "FrmSettings.Nav._Slideshow": "スライドショー", + "_._Continue": "続行", + "_._AddHotkey": "ホットキーを追加", + "FrmMain.MnuSetDesktopBackground": "デスクトップの背景に設定", + "FrmMain.MnuReload": "画像の再読み込み", + "FrmSlideshow.MnuExitSlideshow": "スライドショーを終了", + "FrmMain.MnuAutoZoom": "自動ズーム倍率", + "FrmSettings._ShowImagePreview": "読み込み中に画像プレビューを表示する", + "FrmCrop.BtnCopy._Tooltip": "選択範囲をクリップボードにコピー", + "FrmSettings.Nav._Toolbar": "ツールバー", + "FrmMain.MnuSave._Error": "画像を保存できませんでした", + "FrmSettings._AfterEditingAction": "画像編集用のアプリを開いた後の動作", + "FrmSettings._ShouldUseColorProfileForAll": "カラープロファイルが埋め込まれていない画像にも適用する", + "FrmCropSettings.DefaultSelectionType._UseTheLastSelection": "最後の選択を使用", + "FrmSettings._SlideshowInterval._From": "から", + "FrmSettings._ImageInterpolation": "画像の補間", + "FrmQuickSetup._StepInfo": "ステップ {0}", + "FrmMain.MnuColorPicker": "カラーピッカー", + "FrmCrop.SelectionAspectRatio._FreeRatio": "自由倍率", + "FrmSettings._ResetSettings": "設定をリセット", + "FrmSettings._Startup": "スタートアップ", + "_.BackdropStyle._None": "無し", + "FrmSettings._LoadDefaultZoomLevels": "既定のズーム率で読み込む", + "FrmColorPicker.BtnSettings._Tooltip": "カラーピッカーの設定を開く", + "FrmSettings._UseThemeForDarkMode": "ダークモードにこのテーマを使用する", + "FrmSettings._ShowDeleteConfirmation": "ファイル削除時に確認ダイアログを表示する", + "FrmSettings._ShowAppIcon": "タイトルバーにアプリのアイコンを表示する", + "_._InvalidAction": "無効な操作", + "FrmQuickSetup._SelectProfile": "プロファイルを選択", + "_.Metadata._FileCreationTime": "作成日時", + "FrmSettings._SlideshowImagesToNotifySound": "指定した表示数で通知音を鳴らす", + "FrmSettings._BackgroundColor": "ビューアの背景色", + "FrmSettings._RealTimeFileUpdate": "リアルタイム更新", + "_.ColorProfileOption._CurrentMonitorProfile": "現在のモニタープロファイル", + "FrmSettings._EnableCutMultipleFiles": "複数ファイルの切り取りを有効にする", + "FrmSettings._AutoUpdate": "アップデートを自動的に確認", + "FrmCropSettings.LblDefaultSelection": "デフォルトの選択", + "FrmSettings._UseThemeForLightMode": "ライトモードにこのテーマを使用する", + "FrmSettings._ZoomLevels": "ズーム率", + "FrmMain.MnuSetLockScreen._Success": "ロック画面の画像が更新されました", + "FrmSettings._ShowGalleryFileName": "サムネイルのファイル名を表示", + "FrmSettings.Layout._Order": "順序", + "FrmCropSettings.ChkAutoCenterSelection": "自動的に中央を選択", + "FrmSettings.Nav._FileTypeAssociations": "ファイルの関連付け", + "_._Back": "戻る", + "FrmMain.MnuSetDesktopBackground._Success": "デスクトップの背景を更新しました", + "FrmSettings._ShouldAutoOpenNewAddedImage": "追加された画像を自動的に開く", + "FrmCrop.SelectionAspectRatio._Custom": "カスタム…", + "FrmMain.MnuCopyPath._Success": "現在の画像のファイルパスをコピーしました。", + "FrmSettings._StartupBoost._Error": "スタートアップブーストの設定を変更できませんでした", + "FrmToolNotFound.LblDescription": "ImageGlass は '{0}' の実行ファイルへのパスを見つけることができませんでした。 この問題を解決するには、必要に応じて「{0}」のパスを更新してください。", + "FrmMain.MnuClearClipboard": "クリップボードをクリア", + "FrmSettings._ColorManagement": "カラーマネジメント", + "FrmMain._ReachedLastLast": "最後の画像に到達しました。", + "FrmMain.MnuPanUp": "表示範囲を上に", + "FrmMain.MnuRemoveDefaultPhotoViewer._Success": "ImageGlass は既定のフォトビューアーではなくなりました。", + "FrmSettings._GetMoreLanguagePacks": "追加の言語パックを入手…", + "FrmAbout._Privacy": "プライバシーポリシー", + "FrmSettings._EnableRecursiveLoading": "サブフォルダ内の画像を読み込む", + "_._UserAction._MethodArgumentNotSupported": "メソッド '{0}' の引数型はサポートされていません", + "FrmSettings._FileExtensionIcons._Description": "拡張子アイコンをカスタマイズするには、アイコンパックをダウンロードし、iconフォルダにすべての.ICOファイルを配置し、「{0}」ボタンをクリックします。 ImageGlass を既定のフォトビューアとして設定します。", + "_.ImageOrderType._Asc": "昇順", + "FrmExportFrames._Title": "フレームをエクスポート...", + "_._Install": "インストール…", + "FrmMain.MnuFlipHorizontal": "水平方向に反転", + "FrmSettings._OpenExtensionIconFolder": "拡張子アイコンフォルダを開く", + "FrmAbout._Collaborator": "コラボレーター:", + "FrmQuickSetup._ConfirmCloseProcess": "新しい設定を適用するために、すべてのImageGlassを閉じてください。 続行してよろしいですか?", + "FrmExportFrames._ExportDone": "{0} フレームを {1} にエクスポートしました", + "FrmCrop.BtnSaveAs._Tooltip": "コピーとして保存...", + "FrmMain.MnuOpenFile": "ファイルを開く…", + "FrmColorPickerSettings.ChkShowRgbA": "アルファ値付きのRGB形式を使用", + "_.ImageInfo._ListCount": "{0} 個のファイル", + "FrmMain.MnuGoToLast": "最後の画像に移動", + "FrmSettings._EditApps._AppName": "アプリ名", + "FrmSettings._SlideshowBackgroundColor": "スライドショーの背景色", + "FrmAbout._Email": "Eメール:", + "_.MouseWheelAction._DoNothing": "何もしない", + "FrmMain.MnuSaveAs": "名前を付けて保存…", + "FrmMain._Loading": "読み込み中…", + "_._Browse": "ブラウズ…", + "FrmMain.MnuSetDefaultPhotoViewer._Error": "ImageGlass を既定のフォトビューアに設定できませんでした。", + "FrmSettings.Nav._Language": "言語", + "FrmQuickSetup._SeeWhatNew": "更新情報を見る...", + "FrmSettings._ImageInterpolation._ScaleUp": "ズーム率 > 100%", + "FrmSettings.Layout._ToolbarContextPosition": "コンテキストツールバーの位置", + "FrmMain.MnuDeleteFromHardDisk": "完全に削除する", + "FrmSettings._EmbeddedThumbnail": "埋め込みサムネイル", + "FrmMain.MnuDeleteFromHardDisk._Description": "このファイルを完全に削除しますか?", + "FrmMain.MnuScaleToFill": "ウィンドウいっぱいに表示する", + "FrmCrop.BtnCrop": "トリミング", + "_.AfterEditAppAction._Minimize": "最小化する", + "FrmMain.MnuInvertColors": "色を反転させる", + "FrmSettings._StartupBoost": "スタートアップブースト", + "FrmMain.MnuViewFirstFrame": "最初のフレームを見る", + "_.MouseWheelEvent._CtrlAndScroll": "Ctrl キーを押しながらスクロール", + "FrmSettings._HideMainWindowInSlideshow": "メインウィンドウを自動的に隠す", + "_.Metadata._FrameCount": "フレーム", + "FrmSettings._EnableCopyMultipleFiles": "複数ファイルのコピーを有効にする", + "FrmMain.MnuFrameless._EnableDescription": "Shiftキーを押したままウィンドウを移動します。", + "_.ImageOrderBy._ExifDateTaken": "EXIF: 撮影日", + "FrmAbout._Credits": "クレジット", + "FrmSettings._AddNewFileExtension": "新しいファイル拡張子を追加", + "FrmMain.MnuQuickSetup": "クイックセットアップを開く", + "FrmMain.MnuSave._Success": "画像が保存されました", + "FrmMain.MnuPanLeft": "表示範囲を左に", + "FrmUpdate._StatusChecking": "アップデートをチェック…", + "FrmSettings.Nav._Layout": "レイアウト", + "FrmMain.MnuOpenWith": "別のアプリで開く…", + "FrmAbout._Thanks": "スペシャルサンクス:", + "_._Warning": "警告", + "FrmSettings.Nav._Keyboard": "キーボード", + "FrmSlideshow._PauseSlideshow": "スライドショーは一時停止しています。", + "_._Add+": "追加…", + "_._Email": "メールアドレス", + "FrmMain.MnuPanDown": "表示範囲を下に", + "_._Cancel": "キャンセル", + "_._OK": "OK", + "FrmMain.MnuPanRight": "表示範囲を右に", + "_.Position._Right": "右", + "_._Icon": "アイコン", + "FrmSettings._ShouldLoadHiddenImages": "隠し画像を読み込む", + "_._InvalidAction._Transformation": "ImageGlass は、この画像の反転、回転をサポートしていません。", + "FrmSettings._MakeDefault": "既定に設定", + "FrmMain.MnuCopyImageData._Copying": "画像データをコピー中。 しばらくお待ちください...", + "FrmSettings._UseEmbeddedThumbnailRawFormats": "RAW形式の埋め込みサムネイルのみを読み込みます", + "_.ImageInterpolation._Linear": "リニア", + "FrmSettings._ImageInfoTags": "タイトルバーに表示する画像情報タグ", + "FrmSettings._FileExtensionIcons": "拡張子のアイコン", + "FrmMain.MnuEdit._AppNotFound": "編集用として関連付けされたアプリが見つかりませんでした。 ImageGlass の設定 > 編集 でこのフォーマットを編集するためのアプリを割り当てることができます。", + "_.ColorProfileOption._None": "無し", + "FrmSettings._TotalSupportedFormats": "サポートしているファイル形式: {0}", + "FrmSettings._Clipboard": "クリップボード", + "_._UserAction._Win32ExeError": "コマンド '{0}' を実行できません。 名前が正しいことを確認してください。", + "FrmCropSettings.DefaultSelectionType._SelectX": "{0}を選択", + "_.AfterEditAppAction._Close": "閉じる", + "FrmAbout._LogoDesigner": "ロゴデザイナー:", + "_.ImageOrderBy._Name": "ファイル名 (デフォルト)", + "FrmMain.MnuRemoveDefaultPhotoViewer._Error": "既定のフォトビューアからImageGlassを削除できませんでした。", + "FrmExportFrames._FolderPickerTitle": "フレームをエクスポートする出力フォルダを選択", + "FrmAbout._Donate": "寄付", + "FrmMain.MnuFrameNav": "フレーム操作", + "FrmMain.MnuSetLockScreen": "ロック画面の画像に設定", + "_._Delete": "削除", + "FrmMain.MnuViewPrevious": "前の画像を表示", + "_.Position._Top": "上部", + "FrmSettings.Toolbar._CurrentButtons": "利用中のボタン:", + "FrmMain.MnuAbout": "ImageGlassについて", + "FrmSettings._RemoveDefault": "既定から削除", + "_._Description": "説明", + "FrmMain.MnuPasteImage._Error": "クリップボードに画像データが見つかりません", + "FrmMain.MnuSettings": "設定", + "FrmCropSettings._Title": "トリミング設定", + "FrmSettings.Toolbar._ToolbarIconHeight": "ツールバーアイコンのサイズ", + "FrmSettings._SlideshowInterval._To": "へ", + "FrmSettings.Layout._ToolbarPosition": "ツールバーの位置", + "FrmUpdate._StatusUpdated": "最新バージョンを使用中です", + "FrmMain.MnuExit": "終了", + "_._Webview2._Outdated": "この WebView2 ランタイムはサポートされていません。 バージョン {0} 以降にアップデートしてください。", + "_._Yes": "はい", + "FrmMain.MnuRotateLeft": "左に回転", + "FrmSettings._EnableStartupBoost": "スタートアップブーストを有効にする", + "_.ImageOrderBy._ExifRating": "EXIF: レーティング", + "FrmMain.MnuZoomIn": "ズームイン", + "_.Metadata._ColorSpace": "色空間", + "FrmAbout._Version": "バージョン:", + "FrmMain.MnuToggleTopMost._Enable": "最前面表示を有効にする", + "FrmSettings.Toolbar._AvailableButtons": "利用可能なボタン:", + "FrmMain.MnuSave._Saving": "画像を保存中...", + "FrmQuickSetup._StandardUser": "一般ユーザー", + "FrmMain.MnuSetLockScreen._Error": "表示画像をロック画面の画像として設定できませんでした", + "FrmSettings.Nav._Image": "画像", + "FrmSettings._Theme._InstallTheme": "テーマパックをインストール", + "FrmSettings._EnableMultiInstances": "アプリの複数起動を許可", + "FrmMain.MnuCropTool": "画像のトリミング", + "_._IgCommandExe._DefaultError._Heading": "無効なコマンド", + "_._Refresh": "再読み込み", + "FrmMain.MnuLosslessCompression._Description": "このツールは、ロスレス圧縮、ファイルサイズの最適化のためにMagick.NETライブラリを使用します。 圧縮されたファイルがオリジナルより小さい場合にのみ上書きされます。", + "_._MoveDown": "下に移動", + "FrmSettings._GetExtensionIconPacks": "拡張子アイコンパックを取得...", + "FrmSettings._InAppMessageDuration": "アプリ内メッセージの表示時間(ミリ秒)", + "FrmMain.MnuFrameless": "フチ無し", + "_._Reset": "リセット", + "FrmSettings._ConfigDir": "設定ファイルの場所", + "FrmQuickSetup._SettingsWillBeApplied": "設定を適用:", + "FrmSettings._UnmanagedSettingReminder": "この設定は ImageGlass では管理されていません。 ImageGlass は自動的にこれを処理しないため、アプリを削除または再導入する前に手動で無効にしてください。", + "FrmMain.MnuClipboard": "クリップボード", + "FrmMain.MnuCustomZoom": "倍率指定ズーム", + "FrmSettings._DisplayLanguage": "表示言語", + "FrmMain.MnuPrint._Error": "表示中の画像を印刷できませんでした", + "FrmSettings._ShouldPreserveModifiedDate": "保存時に画像の更新日を保持する", + "FrmSettings._ShowSaveOverrideConfirmation": "ファイル上書き時に確認ダイアログを表示する", + "FrmColorPickerSettings.ChkShowHexA": "アルファ値付きのHEX形式を使用", + "FrmMain.MnuFullScreen": "フルスクリーン", + "FrmSettings._StartupDir": "スタートアップの場所", + "FrmSettings._ShowCheckerboardOnlyImageRegion": "画像領域内でのみ市松模様を表示する", + "FrmMain.MnuClearClipboard._Success": "クリップボードをクリアしました。", + "FrmQuickSetup._Text": "クイックセットアップ", + "FrmMain.MnuLosslessCompression._Done": "ロスレス圧縮を完了しました。\r\n新しいファイルサイズ {0} で、{1} を保存しました。", + "FrmMain.MnuLosslessCompression": "Magick.NET ロスレス圧縮", + "FrmResize.RadResizeByPercentage": "割合(%)", + "FrmSettings._StartupBoost._Disabled": "スタートアップブーストは無効です", + "FrmMain.MnuToggleCheckerboard": "背景を市松模様にする", + "FrmSettings._MinEmbeddedThumbnailSize._Height": "高さ", + "FrmSettings.Nav._General": "全般", + "FrmSettings._ImageLoading": "画像の読み込み", + "FrmSettings._ShowSlideshowCountdown": "スライドショーの残り枚数を表示する", + "FrmMain.MnuSave": "保存", + "FrmMain.MnuMoveToRecycleBin": "ゴミ箱に移動する", + "FrmMain.MnuRefresh": "再読み込み", + "FrmToolNotFound.LblHeading": "「{0}」が見つかりません!", + "FrmMain.MnuReportIssue": "問題を報告…", + "FrmMain.MnuCopyImageData": "画像データのコピー", + "FrmMain.MnuCheckForUpdate._NewVersion": "新しいバージョンが利用可能です!", + "_._Empty": "(空)", + "FrmSettings._Zooming": "ズーム", + "FrmMain.MnuCutFile": "ファイルを切り取り", + "FrmHotkeyPicker.LblHotkey": "ホットキーを押す", + "FrmSettings.Layout._Gallery": "ギャラリー", + "FrmMain.MnuNewWindow": "新しいウィンドウを開く", + "FrmMain.MnuMoveToRecycleBin._Description": "このファイルをごみ箱に移動しますか?", + "FrmSettings._DefaultPhotoViewer": "既定のフォトビューアー", + "_.Metadata._ExifDateTimeOriginal": "EXIF: DateTimeOriginal", + "FrmMain.MnuRotateRight": "右に回転", + "FrmSettings._MinEmbeddedThumbnailSize": "読み込むサムネイルの最小サイズ", + "FrmMain.MnuSetDefaultPhotoViewer": "既定のフォトビューアに設定", + "FrmMain.MnuImageProperties": "画像のプロパティ", + "FrmSettings._EnableNavigationButtons": "ナビゲーションを表示", + "_._Edit": "編集", + "FrmSettings._ImageBooster": "イメージブースター", + "FrmSettings.Tools._IntegratedWith": "{0}と結合", + "_._Next": "次へ", + "FrmExportFrames._OpenOutputFolder": "出力フォルダを開く", + "FrmMain.MnuOpenLocation": "画像ファイルの場所を開く", + "FrmMain.MnuLockZoom": "ズーム倍率を固定", + "FrmSettings._StartupBoost._Description": "Windowsの起動時にImageGlassをプリロードし、起動を高速化します。", + "FrmSettings._WindowBackdrop": "ウィンドウの背景", + "FrmSettings._EnableRealTimeFileUpdate": "表示フォルダ内のファイルの変更を監視し、リアルタイムで更新します", + "_._NotSupported": "サポートされていないフォーマット", + "FrmSettings._Theme._GetMoreThemes": "追加のテーマパックを入手…", + "FrmMain.MnuNewWindow._Error": "1つのインスタンスのみ許可されているため、新しいウィンドウを開くことができません", + "FrmMain.MnuZoomOut": "ズームアウト", + "FrmSettings.Toolbar._EditButton": "ツールバーボタンの編集", + "FrmMain.MnuCustomZoom._Description": "ズーム倍率を入力してください", + "FrmResize.RadResizeByPixels": "ピクセル", + "FrmMain.MnuEdit": "画像を編集 {0}…", + "FrmSettings.Layout._GalleryPosition": "ギャラリーの位置", + "FrmMain.MnuWindowFit": "ウィンドウを画像サイズに合わせる", + "FrmMain._OpenFileDialog": "サポートされている全ての形式", + "FrmSettings._UseRandomIntervalForSlideshow": "ランダムなインターバルを用いる", + "_.Position._Left": "左", + "FrmSettings._ShouldOpenLastSeenImage": "最後に見た画像を開く", + "_.Position._Bottom": "下部", + "FrmResize.ChkKeepRatio": "縦横比を維持", + "FrmMain.MnuGoTo": "ジャンプ…", + "FrmSlideshow.MnuPauseResumeSlideshow": "スライドショーを一時停止/再開", + "FrmSettings.Tools._Integrated": "結合", + "FrmSettings._Contributors": "コントリビュータ", + "_.MouseWheelAction._Zoom": "ズームイン/アウト", + "_._CommandPreview": "コマンドプレビュー", + "FrmSettings._DarkTheme": "ダーク", + "_._Hotkeys": "ホットキー", + "_.Metadata._ExifDateTime": "EXIF: DateTime", + "FrmSettings.Toolbar._Errors._ButtonIdRequired": "ボタンのIDは必須です。", + "FrmSettings._MinEmbeddedThumbnailSize._Width": "幅", + "_._Executable": "実行可能", + "_.ImageInterpolation._MultiSampleLinear": "マルチサンプルリニア", + "_._Separator": "区切り", + "FrmQuickSetup._ProfessionalUser": "熟練ユーザー", + "FrmMain.MnuFlipVertical": "垂直方向に反転", + "FrmSlideshow._ResumeSlideshow": "スライドショーが再開されます。", + "FrmCropSettings.DefaultSelectionType._CustomArea": "カスタムエリア…", + "FrmMain.MnuActualSize": "実際のサイズで表示", + "FrmCrop.BtnSaveAs": "名前を付けて保存…", + "FrmSettings._InstallNewLanguagePack": "新しい言語パックをインストール…", + "FrmSlideshow.MnuZoomModes": "ズームモード", + "FrmMain.MnuTools": "ツール", + "_.ImageInterpolation._Cubic": "キュービック", + "FrmUpdate._LatestVersion": "最新のバージョン: {0}", + "FrmMain.MnuViewNext": "次の画像を表示", + "_.MouseWheelEvent._AltAndScroll": "Altを押しながらスクロール", + "FrmToolNotFound._Title": "ツールが見つかりません", + "FrmCrop.BtnCrop._Tooltip": "画像のみをトリミング", + "FrmSettings.EditAppDialog._AddApp": "編集用のアプリを追加", + "FrmMain.MnuPanning": "表示範囲", + "_._MoveUp": "上に移動", + "FrmCropSettings.DefaultSelectionType._SelectAll": "すべてを選択", + "_._Name": "名前", + "FrmColorPickerSettings.ChkShowHslA": "アルファ値付きのHSL形式を使用", + "FrmMain.MnuToggleImageAnimation": "アニメーションの開始/停止", + "FrmSettings._DisableStartupBoost": "スタートアップブーストを無効にする", + "FrmMain.MnuCopyFile._Success": "{0} ファイルをコピーしました。", + "FrmMain.MnuSave._ConfirmDescription": "ImageGlassは高度な画像編集ソフトではありません。画像を保存する際に画質、メタデータ、レイヤー等を失うことに注意してください。", + "FrmToolNotFound.BtnSelectExecutable": "選択...", + "FrmUpdate._StatusOutdated": "新しいアップデートが利用可能です!", + "_.ImageOrderBy._Random": "ランダム", + "FrmResize.LblCurrentSize": "現在のサイズ:", + "_._Apply": "適用", + "FrmAbout._Slogan": "軽くて多機能な画像ビューア", + "FrmMain.MnuPanToTop": "上端に寄せて表示", + "FrmSettings.Toolbar._AddNewButton": "カスタムボタンを追加", + "FrmCrop.LblSize": "サイズ:", + "FrmSettings._ImageInterpolation._ScaleDown": "ズーム率 < 100%", + "_._CreatingFileError": "一時ファイルを作成できませんでした", + "FrmMain.MnuGoTo._Description": "表示する画像のインデックスを入力し、ENTERを押します", + "FrmSettings.Toolbar._EnableCenterToolbar": "ツールバーを中心に配置する", + "FrmMain.MnuResizeTool": "画像サイズの変更", + "FrmSettings.Layout._Toolbar": "ツールバー", + "FrmMain.MnuHelp": "ヘルプ", + "_.ImageOrderBy._FileSize": "ファイルサイズ", + "FrmSettings._Theme._OpenThemeFolder": "テーマのフォルダを開く", + "FrmMain.MnuNavigation": "ナビゲーション", + "_._Save": "保存", + "FrmQuickSetup._SettingProfileDescription": "これらの設定を変更したい場合、アプリの設定を開いてください。", + "_._UserAction._MenuNotFound": "アクションを呼び出すためのメニュー '{0}' が見つかりません", + "FrmMain.MnuPanToLeftSide": "左端に寄せて表示", + "FrmUpdate._CurrentVersion": "現在のバージョン: {0}", + "FrmCrop.BtnSettings._Tooltip": "トリミングツールの設定を開く", + "_.ColorProfileOption._Custom": "カスタム…", + "FrmSettings._UseEmbeddedThumbnailOtherFormats": "他の形式の埋め込みサムネイルのみを読み込みます", + "FrmMain.MnuGoToFirst": "最初の画像に移動", + "FrmSettings._ExportLanguagePack": "言語パックをエクスポート...", + "FrmSettings.Nav._Mouse": "マウス", + "_.ImageOrderBy._DateCreated": "作成日時", + "FrmSettings._EnableFullscreenSlideshow": "フルスクリーンモードでスライドショーを開始", + "FrmAbout._Homepage": "ホームページ:", + "FrmSettings._GalleryCacheSizeInMb": "ギャラリーの最大キャッシュサイズ(MB単位)", + "FrmMain.MnuCopyImageData._Success": "現在の画像データをコピーしました。", + "FrmSettings._EnableLoopBackNavigation": "画像リストの末尾に到達したときに、最初の画像にループバックします", + "_.MouseWheelEvent._Scroll": "スクロール", + "FrmCrop.BtnSave._Tooltip": "画像を保存する", + "FrmMain.MnuSlideshow": "スライドショー", + "FrmMain.MnuShare": "共有…", + "FrmSettings._SlideshowNotification": "スライドショーの通知", + "FrmMain.MnuViewChannels": "表示チャンネル", + "FrmSettings._Refresh": "再読み込み", + "_._UserAction._MethodNotFound": "アクションを呼び出すメソッド '{0}' が見つかりません", + "FrmMain.MnuCopyFile": "ファイルをコピー", + "_._CreatingFile": "一時ファイルを作成...", + "FrmMain.MnuToggleTopMost": "ウィンドウを常に最前面に表示", + "FrmMain.MnuLosslessCompression._Confirm": "本当に続行しますか?", + "FrmMain.MnuImage": "画像", + "FrmSettings._StartupBoost._Enabled": "スタートアップブーストは有効です", + "FrmQuickSetup._SetDefaultViewer": "ImageGlassを既定のフォトビューアに設定しますか?", + "FrmMain.MnuScaleToWidth": "ウィンドウの幅に合わせる", + "_._FileExtension": "ファイルの拡張子", + "FrmUpdate._PublishedDate": "公開日: {0}", + "_._DoNotShowThisMessageAgain": "今後このメッセージを表示しない", + "_.ImageInterpolation._NearestNeighbor": "近傍法", + "FrmCrop.LblLocation": "位置:", + "_._Download": "ダウンロード", + "_.Metadata._ColorProfile": "カラープロファイル", + "FrmSettings._CenterWindowFit": "画像サイズに合わせる時にウィンドウを画面中央に表示する", + "FrmSettings._ImageLoadingOrder": "画像の読み込み順序", + "FrmSettings._GalleryColumns": "レイアウトでギャラリーの位置を左右にした際のサムネイルの列数", + "_._Quit": "終了", + "_._Add": "追加", + "FrmMain.MnuChangeBackgroundColor": "背景色の変更...", + "FrmMain.MnuToggleToolbar": "ツールバー", + "FrmAbout._Contact": "お問い合わせ", + "FrmSettings.Toolbar._AddCustomButton": "カスタムボタンを追加...", + "FrmCrop.BtnQuickSelect._Tooltip": "クイック選択...", + "FrmMain.MnuCutFile._Success": "{0} ファイルを切り取りました。", + "FrmSettings._ZoomSpeed": "ズーム速度", + "FrmMain.MnuToggleTopMost._Disable": "最前面表示を無効にする", + "FrmSettings._ShouldUseExplorerSortOrder": "可能な場合はエクスプローラの並び順を使用する", + "_.ImageInterpolation._Antisotropic": "異方性", + "FrmMain._ReachedFirstImage": "最初の画像に到達しました。", + "_._UnhandledException": "例外エラー(Unhandled exception)", + "FrmResize.LblNewSize": "新しいサイズ:", + "FrmMain._ClipboardImage": "クリップボードの画像", + "FrmMain.MnuExportFrames": "フレームをエクスポート...", + "FrmMain.MnuFile": "ファイル", + "_._Close": "閉じる", + "FrmMain.MnuMain": "メインメニュー", + "_._ResetToDefault": "デフォルトに戻す", + "FrmSettings.Nav._Gallery": "ギャラリー", + "FrmMain.MnuSetDefaultPhotoViewer._Success": "ImageGlass を既定のフォトビューアとして正常に設定しました。", + "FrmSettings._HideGalleryInFullscreen": "フルスクリーンモードでギャラリーを隠す", + "FrmSettings._AvailableImageInfoTags": "利用可能なタグ:", + "FrmExportFrames._Exporting": "{0}/{1} フレームをエクスポート {2}...", + "_._Argument": "引数", + "FrmSettings._ImageEditQuality": "画質", + "_._ID": "ID", + "FrmSettings._UserConfigFile": "ユーザー設定ファイル (igconfig.json)", + "FrmMain.MnuLoadingOrders": "読み込み順", + "FrmSettings._OpenSaveAsDialogInTheCurrentImageDir": "現在の画像ディレクトリで保存ダイアログを開きます。", + "_.MouseWheelEvent._ShiftAndScroll": "Shiftを押しながらスクロール", + "FrmSettings._UseSmoothZooming": "スムーズなズームを使用", + "FrmSettings._Theme": "テーマ", + "FrmSettings._ImageBoosterCacheMaxDimension": "キャッシュする画像の最大画素数(ピクセル単位)", + "FrmMain.MnuScaleToHeight": "ウィンドウの高さに合わせる", + "_.Metadata._FileLastWriteTime": "更新日時", + "FrmSettings._Author": "作者", + "FrmSettings._Others": "その他", + "_.MouseWheelAction._PanVertically": "表示範囲を移動(上下)", + "FrmSettings._MouseWheelAction": "マウスホイールの動作", + "FrmSettings.Nav._Tools": "ツール", + "FrmMain.MnuSetDesktopBackground._Error": "表示画像をデスクトップの背景として設定できませんでした", + "FrmSettings.Toolbar._Errors._ButtonExecutableRequired": "Executableの指定が必要です。", + "_.ImageOrderBy._DateAccessed": "アクセス日時", + "FrmSettings._ThumbnailSize": "サムネイルのサイズ(ピクセル単位)", + "FrmSettings._FileFormats": "ファイル形式", + "FrmMain.MnuReloadImageList": "画像一覧の再読み込み", + "FrmSettings._UseWebview2ForSvg": "Webview2を使用してSVG形式を表示する", + "FrmCrop.BtnCopy": "コピー", + "FrmSettings._CurrentMonitorProfile._Description": "ImageGlass はウィンドウを異なるモニター間で移動する際に色を自動的に更新しません", + "FrmMain.PicMain._ErrorText": "この画像を開けません", + "FrmSettings.Tools._AddNewTool": "外部ツールの追加", + "FrmMain.MnuRename": "画像の名前を変更…", + "FrmMain.MnuViewLastFrame": "最後のフレームを見る", + "_._Webview2._NotFound": "WebView2 ランタイムの最新バージョンをインストールしてください。", + "FrmMain.MnuGetMoreTools": "ツールを追加...", + "FrmSettings.Nav._Appearance": "表示設定", + "FrmSettings._SlideshowInterval": "スライドショーのインターバル秒数:", + "_.ImageInterpolation._HighQualityBicubic": "高品質のバイキュービック", + "FrmColorPickerSettings.ChkShowHsvA": "アルファ値付きのHSV形式を使用", + "FrmSettings.Tools._EditTool": "外部ツールの編集", + "_._Error": "エラー", + "FrmSettings._ImageBoosterCacheMaxFileSizeInMb": "キャッシュする画像の最大サイズ(MB単位)", + "_._UnhandledException._Description": "例外エラー(Unhandled exception)が発生しました 「続行」をクリックするとこのエラーを無視します。 「終了」をクリックすると直ちに終了します。", + "_.Metadata._FileSize": "ファイルサイズ", + "FrmSettings.Toolbar._ButtonJson": "カスタムボタンの定義(JSON)", + "FrmQuickSetup._SetDefaultViewer._Description": "設定 > ファイルの関連付け でリセットできます。", + "FrmSettings.Nav._Edit": "編集", + "FrmMain.MnuToggleGallery": "ギャラリーパネル", + "_._IgCommandExe._DefaultError._Description": "正しいコマンドを指定してください!\r\nこの実行ファイルには、ImageGlass ソフトウェア用のコマンドライン機能が含まれています。\r\n\r\nすべてのコマンドラインを確認するには、以下を参照してください:\n{0}", + "FrmMain.MnuLosslessCompression._Compressing": "ロスレス圧縮の処理中...", + "FrmSettings._ShouldGroupImagesByDirectory": "ディレクトリで画像をグループ化", + "FrmMain.MnuPanToRightSide": "右端に寄せて表示", + "_.Metadata._ExifRatingPercent": "レーティング", + "FrmSettings._PanSpeed": "表示範囲の移動速度", + "_._CheckForUpdate": "アップデートをチェック…", + "FrmSettings.Layout._ToolbarContext": "コンテキストツールバー", + "_.ImageInfo._FrameCount": "{0} フレーム", + "FrmMain.MnuLayout": "レイアウト", + "_._Website": "ウェブサイト", + "FrmMain.MnuPasteImage": "画像データを貼り付け", + "FrmSettings._ShowGalleryScrollbars": "ギャラリーのスクロールバーを表示" + } +} \ No newline at end of file diff --git a/Setup/Assets/Language/Korean.iglang.json b/Setup/Assets/Language/Korean.iglang.json new file mode 100644 index 000000000..64b4be2a5 --- /dev/null +++ b/Setup/Assets/Language/Korean.iglang.json @@ -0,0 +1,504 @@ +{ + "_Metadata": { + "Code": "ko-KR", + "EnglishName": "Korean", + "LocalName": "한국어", + "Author": "VᴇɴᴜꜱGɪʀʟ-비너스걸💗", + "MinVersion": "9.1" + }, + "Items": { + "FrmCrop.SelectionAspectRatio._Original": "원본", + "FrmMain.MnuShare._Error": "공유 대화 상자를 열 수 없습니다.", + "_.Metadata._FileLastAccessTime": "접근 날짜", + "FrmAbout._License": "소프트웨어 라이선스", + "FrmSettings.Toolbar._Errors._ButtonIdDuplicated": "ID가 '{0}'인 버튼이 이미 정의되어 있습니다. 충돌을 피하기 위해 버튼에 다른 고유 ID를 선택해 주세요.", + "FrmMain.MnuSave._Confirm": "이 이미지를 재정의하시겠습니까?", + "FrmSettings._OpenDefaultAppsSetting": "기본 앱 설정 열기", + "FrmMain.MnuCopyPath": "이미지 경로 복사", + "FrmCropSettings.DefaultSelectionType._SelectNone": "선택 안 함", + "_.MouseWheelAction._PanHorizontally": "왼쪽 / 오른쪽 이동", + "FrmMain.MnuPrint": "인쇄…", + "FrmSettings.Toolbar._ToolbarButtons": "도구 모음 버튼", + "FrmResize.LblResample": "리샘플링:", + "_.ImageOrderBy._Extension": "확장자", + "FrmSettings.Nav._Viewer": "뷰어", + "FrmSettings.EditAppDialog._EditApp": "앱 편집", + "FrmCrop.BtnReset._Tooltip": "선택 재설정", + "FrmMain.MnuRename._Description": "새 파일 이름 입력:", + "_._No": "아니오", + "FrmSlideshow.MnuToggleCountdown": "슬라이드쇼 카운트다운 표시", + "FrmSettings._OpenStartupAppsSetting": "기본 앱 설정 열기", + "FrmMain.MnuViewPreviousFrame": "이전 프레임 보기", + "_.ImageOrderBy._DateModified": "수정 날짜", + "FrmMain.MnuViewNextFrame": "다음 프레임 보기", + "FrmMain.MnuUnload": "이미지 불러오기 해제", + "FrmSettings.Toolbar._HideToolbarInFullscreen": "전체 화면 모드에서 도구 모음 숨기기", + "_.ImageOrderType._Desc": "내림차순", + "_._Update": "업데이트", + "FrmSettings._EnableImageAsyncLoading": "이미지 비동기 로드 사용", + "FrmSettings._DefaultPhotoViewer._Description": "Windows에 ImageGlass의 지원되는 형식을 등록합니다. 적용하려면 기본 앱 설정을 열고 목록에서 ImageGlass를 수동으로 선택해야 할 수도 있습니다.", + "_.MouseWheelAction._BrowseImages": "다음 / 이전 이미지 보기", + "FrmSettings._EditApps": "이미지 편집 앱", + "FrmColorPickerSettings.ChkShowCIELabA": "알파 값에 CIELAB 형식 사용", + "_._GetHelp": "도움말 얻기", + "FrmQuickSetup._SkipQuickSetup": "이 단계을 건너뛰고 ImageGlass 실행", + "FrmColorPickerSettings._Title": "색상 선택기 설정", + "_._Copy": "복사", + "FrmSettings._ImageBoosterCacheCount": "이미지 부스터에서 캐시한 이미지 수 (단방향)", + "FrmMain.MnuPanToBottom": "이미지를 아래쪽으로 이동", + "FrmMain.MnuZoom": "확대/축소", + "FrmCropSettings.ChkCloseToolAfterSaving": "저장 후 자르기 도구 닫기", + "FrmSettings._ShowWelcomeImage": "환영 이미지 표시", + "FrmSettings._ColorProfile": "색상 프로필", + "FrmSettings._Theme._UninstallTheme": "테마 팩 설치 제거", + "FrmMain._OpenWith": "{0}(으)로 열기", + "FrmMain.MnuRemoveDefaultPhotoViewer": "기본 사진 뷰어 제거", + "_.AfterEditAppAction._Nothing": "아무 것도 안함", + "FrmCrop.BtnSave": "저장", + "FrmMain.MnuScaleToFit": "비율 맞춤", + "FrmToolNotFound.LblDownloadToolText": "ImageGlass용 도구를 다운로드할 수 있는 위치는 다음과 같습니다:", + "_._LearnMore": "더 알아보기", + "FrmCrop.LblAspectRatio": "가로세로 비율:", + "FrmExportFrames._FileNotExist": "이미지 파일이 존재하지 않습니다", + "FrmSettings._LightTheme": "밝은", + "FrmSettings.Nav._Slideshow": "슬라이드쇼", + "_._Continue": "계속", + "_._AddHotkey": "단축키 추가…", + "FrmMain.MnuSetDesktopBackground": "바탕 화면 배경으로 설정", + "FrmMain.MnuReload": "이미지 다시 불러오기", + "FrmSlideshow.MnuExitSlideshow": "슬라이드쇼 종료", + "FrmMain.MnuAutoZoom": "자동 확대/축소", + "FrmSettings._ShowImagePreview": "로드되는 동안 이미지 미리보기 표시", + "FrmCrop.BtnCopy._Tooltip": "선택 항목을 클립보드에 복사", + "FrmSettings.Nav._Toolbar": "도구 모음", + "FrmMain.MnuSave._Error": "이미지를 저장할 수 없음", + "FrmSettings._AfterEditingAction": "편집 앱을 연 후", + "FrmSettings._ShouldUseColorProfileForAll": "내장된 색상 프로필이 없는 이미지에도 적용", + "FrmCropSettings.DefaultSelectionType._UseTheLastSelection": "마지막 선택 사용", + "FrmSettings._SlideshowInterval._From": "시작", + "FrmSettings._ImageInterpolation": "이미지 보간", + "FrmQuickSetup._StepInfo": "{0} 단계", + "FrmMain.MnuColorPicker": "색상 선택기", + "FrmCrop.SelectionAspectRatio._FreeRatio": "자유 비율", + "FrmSettings._ResetSettings": "설정 초기화", + "FrmSettings._Startup": "시작", + "_.BackdropStyle._None": "없음", + "FrmSettings._LoadDefaultZoomLevels": "기본 확대/축소 수준 로드", + "FrmColorPicker.BtnSettings._Tooltip": "색상 선택기 설정 열기...", + "FrmSettings._UseThemeForDarkMode": "어두운 모드의 경우 이 테마 사용", + "FrmSettings._ShowDeleteConfirmation": "파일 삭제 시 확인 대화 상자 표시", + "FrmSettings._ShowAppIcon": "제목 표시줄에 앱 아이콘 표시", + "_._InvalidAction": "잘못된 동작", + "FrmQuickSetup._SelectProfile": "프로필 선택", + "_.Metadata._FileCreationTime": "만든 날짜", + "FrmSettings._SlideshowImagesToNotifySound": "알림음을 트리거할 영상 수", + "FrmSettings._BackgroundColor": "뷰어 배경 색상", + "FrmSettings._RealTimeFileUpdate": "실시간 파일 업데이트", + "_.ColorProfileOption._CurrentMonitorProfile": "현재 모니터 프로필", + "FrmSettings._EnableCutMultipleFiles": "여러 파일을 한 번에 잘라내기 사용함", + "FrmSettings._AutoUpdate": "업데이트 자동 확인", + "FrmCropSettings.LblDefaultSelection": "기본 선택 설정", + "FrmSettings._UseThemeForLightMode": "밝은 모드의 경우 이 테마 사용", + "FrmSettings._ZoomLevels": "확대/축소 수준", + "FrmMain.MnuSetLockScreen._Success": "잠금 화면 이미지가 업데이트되었습니다", + "FrmSettings._ShowGalleryFileName": "썸네일 파일 이름 표시", + "FrmSettings.Layout._Order": "순서", + "FrmCropSettings.ChkAutoCenterSelection": "자동 중심 선택", + "FrmSettings.Nav._FileTypeAssociations": "파일 유형 연결", + "_._Back": "뒤로", + "FrmMain.MnuSetDesktopBackground._Success": "바탕 화면 배경이 업데이트됨", + "FrmSettings._ShouldAutoOpenNewAddedImage": "새로 추가된 이미지 자동으로 열기", + "FrmCrop.SelectionAspectRatio._Custom": "사용자 지정…", + "FrmMain.MnuCopyPath._Success": "현재 이미지 경로를 복사했습니다.", + "FrmSettings._StartupBoost._Error": "시작 부스트 설정을 변경할 수 없습니다", + "FrmToolNotFound.LblDescription": "ImageGlass에서 '{0}' 실행 파일의 경로를 찾을 수 없습니다. 이 문제를 해결하려면 필요에 따라 '{0}' 경로를 업데이트하십시오.", + "FrmMain.MnuClearClipboard": "클립보드 지우기", + "FrmSettings._ColorManagement": "색상 관리", + "FrmMain._ReachedLastLast": "마지막 이미지에 도달했습니다.", + "FrmMain.MnuPanUp": "이미지 위쪽으로 이동", + "FrmMain.MnuRemoveDefaultPhotoViewer._Success": "ImageGlass는 더 이상 기본 사진 뷰어가 아닙니다.", + "FrmSettings._GetMoreLanguagePacks": "더 많은 언어 팩 받기…", + "FrmAbout._Privacy": "개인정보 보호정책", + "FrmSettings._EnableRecursiveLoading": "하위 폴더에서 이미지 불러오기", + "_._UserAction._MethodArgumentNotSupported": "메서드 '{0}'의 인수 유형이 지원되지 않습니다", + "FrmSettings._FileExtensionIcons._Description": "파일 확장자 아이콘을 사용자 지정하려면 아이콘 팩을 다운로드하고 모든 .ICO 파일을 확장자 아이콘 폴더에 넣은 다음 '{0}' 버튼을 클릭합니다. 이렇게 하면 ImageGlass가 기본 사진 뷰어로 설정됩니다.", + "_.ImageOrderType._Asc": "오름차순", + "FrmExportFrames._Title": "이미지 프레임 내보내기", + "_._Install": "설치…", + "FrmMain.MnuFlipHorizontal": "가로 뒤집기", + "FrmSettings._OpenExtensionIconFolder": "확장자 아이콘 폴더 열기", + "FrmAbout._Collaborator": "공동 작업자:", + "FrmQuickSetup._ConfirmCloseProcess": "새 설정을 적용하기 전에 모든 ImageGlass 프로세스를 닫아야 합니다. 진행할 준비가 되셨나요?", + "FrmExportFrames._ExportDone": "{0} 프레임을 에 내보냈습니다\n{1}", + "FrmCrop.BtnSaveAs._Tooltip": "사본으로 저장...", + "FrmMain.MnuOpenFile": "파일 열기…", + "FrmColorPickerSettings.ChkShowRgbA": "알파 값과 함께 RGB 형식 사용", + "_.ImageInfo._ListCount": "{0} 파일", + "FrmMain.MnuGoToLast": "마지막 이미지로 이동", + "FrmSettings._EditApps._AppName": "앱 이름", + "FrmSettings._SlideshowBackgroundColor": "슬라이드쇼 배경 색상", + "FrmAbout._Email": "이메일:", + "_.MouseWheelAction._DoNothing": "동작 없음", + "FrmMain.MnuSaveAs": "따로 저장…", + "FrmMain._Loading": "로딩 중...", + "_._Browse": "찾아보기…", + "FrmMain.MnuSetDefaultPhotoViewer._Error": "ImageGlass를 기본 사진 뷰어로 설정할 수 없습니다.", + "FrmSettings.Nav._Language": "언어", + "FrmQuickSetup._SeeWhatNew": "이 버전의 새로운 기능 보기...", + "FrmSettings._ImageInterpolation._ScaleUp": "확대/축소가 > 100% 인 경우", + "FrmSettings.Layout._ToolbarContextPosition": "상황별 도구 모음 위치", + "FrmMain.MnuDeleteFromHardDisk": "영구 삭제", + "FrmSettings._EmbeddedThumbnail": "내장된 썸네일", + "FrmMain.MnuDeleteFromHardDisk._Description": "이 파일을 완전히 삭제하시겠습니까?", + "FrmMain.MnuScaleToFill": "비율 채움", + "FrmCrop.BtnCrop": "자르기", + "_.AfterEditAppAction._Minimize": "최소화", + "FrmMain.MnuInvertColors": "색상 반전", + "FrmSettings._StartupBoost": "시작 부스트", + "FrmMain.MnuViewFirstFrame": "첫 번째 프레임 보기", + "_.MouseWheelEvent._CtrlAndScroll": "Ctrl을 누르고 스크롤", + "FrmSettings._HideMainWindowInSlideshow": "기본 창 자동 숨기기", + "_.Metadata._FrameCount": "프레임", + "FrmSettings._EnableCopyMultipleFiles": "여러 파일을 한 번에 복사 사용함", + "FrmMain.MnuFrameless._EnableDescription": "Shift 키를 누른 채로 창을 이동합니다.", + "_.ImageOrderBy._ExifDateTaken": "EXIF: 촬영 날짜", + "FrmAbout._Credits": "제작진", + "FrmSettings._AddNewFileExtension": "새 파일 확장자 추가", + "FrmMain.MnuQuickSetup": "ImageGlass 빠른 설정 열기", + "FrmMain.MnuSave._Success": "이미지가 저장됨", + "FrmMain.MnuPanLeft": "이미지 왼쪽으로 이동", + "FrmUpdate._StatusChecking": "업데이트 확인 중...", + "FrmSettings.Nav._Layout": "레이아웃", + "FrmMain.MnuOpenWith": "다른 프로그램으로 열기…", + "FrmAbout._Thanks": "특별히 감사드립니다: ", + "_._Warning": "경고", + "FrmSettings.Nav._Keyboard": "키보드", + "FrmSlideshow._PauseSlideshow": "슬라이드쇼가 일시 중지됩니다.", + "_._Add+": "추가…", + "_._Email": "이메일", + "FrmMain.MnuPanDown": "이미지 아래쪽으로 이동", + "_._Cancel": "최소", + "_._OK": "확인", + "FrmMain.MnuPanRight": "이미지 오른쪽으로 이동", + "_.Position._Right": "오른쪽", + "_._Icon": "아이콘", + "FrmSettings._ShouldLoadHiddenImages": "숨김 이미지 불러오기", + "_._InvalidAction._Transformation": "ImageGlass는 이 이미지에 대한 회전, 뒤집기를 지원하지 않습니다.", + "FrmSettings._MakeDefault": "기본값 만들기", + "FrmMain.MnuCopyImageData._Copying": "이미지 데이터를 복사하는 중입니다. 시간이 좀 걸리겠지만...", + "FrmSettings._UseEmbeddedThumbnailRawFormats": "RAW 형식의 내장된 썸네일만 불러오기", + "_.ImageInterpolation._Linear": "선형", + "FrmSettings._ImageInfoTags": "이미지 정보 태그", + "FrmSettings._FileExtensionIcons": "파일 확장자 아이콘", + "FrmMain.MnuEdit._AppNotFound": "편집할 연결 앱을 찾을 수 없습니다. ImageGlass 설정 > 편집에서 이 형식을 편집할 앱을 지정할 수 있습니다.", + "_.ColorProfileOption._None": "없음", + "FrmSettings._TotalSupportedFormats": "지원되는 전체 형식: {0}", + "FrmSettings._Clipboard": "클립보드", + "_._UserAction._Win32ExeError": "'{0}' 명령을 실행할 수 없습니다. 이름이 올바른지 확인합니다.", + "FrmCropSettings.DefaultSelectionType._SelectX": "{0} 선택", + "_.AfterEditAppAction._Close": "닫기", + "FrmAbout._LogoDesigner": "로고 디자이너:", + "_.ImageOrderBy._Name": "이름 (기본값)", + "FrmMain.MnuRemoveDefaultPhotoViewer._Error": "기본 사진 뷰어에서 ImageGlass를 제거할 수 없습니다.", + "FrmExportFrames._FolderPickerTitle": "이미지 프레임을 내보낼 출력 폴더 선택", + "FrmAbout._Donate": "기부하기", + "FrmMain.MnuFrameNav": "프레임 탐색", + "FrmMain.MnuSetLockScreen": "잠금 화면 이미지로 설정", + "_._Delete": "삭제", + "FrmMain.MnuViewPrevious": "이전 이미지 보기", + "_.Position._Top": "상단", + "FrmSettings.Toolbar._CurrentButtons": "현재 버튼:", + "FrmMain.MnuAbout": "프로그램 정보", + "FrmSettings._RemoveDefault": "기본값 제거", + "_._Description": "설명", + "FrmMain.MnuPasteImage._Error": "클립보드에서 이미지 데이터를 찾을 수 없습니다", + "FrmMain.MnuSettings": "설정", + "FrmCropSettings._Title": "자르기 설정", + "FrmSettings.Toolbar._ToolbarIconHeight": "도구 모음 아이콘 크기", + "FrmSettings._SlideshowInterval._To": "까지", + "FrmSettings.Layout._ToolbarPosition": "도구 모음 위치", + "FrmUpdate._StatusUpdated": "최신 버전을 사용 중입니다!", + "FrmMain.MnuExit": "종료", + "_._Webview2._Outdated": "WebView2 런타임은 지원되지 않습니다. 버전 {0} 이상으로 업데이트해 주세요.", + "_._Yes": "예", + "FrmMain.MnuRotateLeft": "왼쪽으로 회전", + "FrmSettings._EnableStartupBoost": "시작 부스트 사용", + "_.ImageOrderBy._ExifRating": "EXIF: 등급", + "FrmMain.MnuZoomIn": "확대", + "_.Metadata._ColorSpace": "색 공간", + "FrmAbout._Version": "버전:", + "FrmMain.MnuToggleTopMost._Enable": "항상 창을 맨 위에 사용함", + "FrmSettings.Toolbar._AvailableButtons": "사용 가능한 버튼:", + "FrmMain.MnuSave._Saving": "이미지 저장 중...", + "FrmQuickSetup._StandardUser": "표준 사용자 ", + "FrmMain.MnuSetLockScreen._Error": "보기 이미지를 잠금 화면 이미지로 설정할 수 없습니다", + "FrmSettings.Nav._Image": "이미지", + "FrmSettings._Theme._InstallTheme": "테마 팩 설치", + "FrmSettings._EnableMultiInstances": "프로그램의 다중 인스턴스 허용", + "FrmMain.MnuCropTool": "이미지 자르기", + "_._IgCommandExe._DefaultError._Heading": "잘못된 명령", + "_._Refresh": "새로 고침", + "FrmMain.MnuLosslessCompression._Description": "이 도구는 무손실 압축을 위해 Magick.NET 라이브러리를 사용하여 파일 크기를 최적화합니다. 압축된 파일이 원본보다 작은 경우에만 덮어씁니다.", + "_._MoveDown": "아래로 이동", + "FrmSettings._GetExtensionIconPacks": "확장자 아이콘 팩 받기...", + "FrmSettings._InAppMessageDuration": "앱 내 메시지 지속 시간 (밀리초)", + "FrmMain.MnuFrameless": "제목 표시줄 숨기기", + "_._Reset": "재설정", + "FrmSettings._ConfigDir": "구성 위치", + "FrmQuickSetup._SettingsWillBeApplied": "설정이 적용됩니다:", + "FrmSettings._UnmanagedSettingReminder": "이 설정은 ImageGlass에서 관리하지 않습니다. ImageGlass는 이 작업을 자동으로 처리하지 않으므로 앱을 제거하거나 재배치하기 전에 비활성화하는 것을 잊지 마세요.", + "FrmMain.MnuClipboard": "클립보드", + "FrmMain.MnuCustomZoom": "확대/축소 사용자 지정...", + "FrmSettings._DisplayLanguage": "표시 언어", + "FrmMain.MnuPrint._Error": "보기 이미지를 인쇄할 수 없음", + "FrmSettings._ShouldPreserveModifiedDate": "저장할 때 이미지의 수정한 날짜 유지", + "FrmSettings._ShowSaveOverrideConfirmation": "파일 재정의 시 확인 대화 상자 표시", + "FrmColorPickerSettings.ChkShowHexA": "알파 값에 HEX 형식 사용", + "FrmMain.MnuFullScreen": "전체 화면", + "FrmSettings._StartupDir": "시작 위치", + "FrmSettings._ShowCheckerboardOnlyImageRegion": "이미지 영역 내에서만 바둑판 표시", + "FrmMain.MnuClearClipboard._Success": "클립보드를 지웠습니다.", + "FrmQuickSetup._Text": "ImageGlass 빠른 설정", + "FrmMain.MnuLosslessCompression._Done": "무손실 압축을 완료했습니다.\r\n새 파일 크기는 {0}이고 {1}을(를) 저장했습니다.", + "FrmMain.MnuLosslessCompression": "Magick.NET 무손실 압축", + "FrmResize.RadResizeByPercentage": "퍼센트", + "FrmSettings._StartupBoost._Disabled": "시작 부스트가 비활성화됨", + "FrmMain.MnuToggleCheckerboard": "바둑판 배경", + "FrmSettings._MinEmbeddedThumbnailSize._Height": "높이", + "FrmSettings.Nav._General": "일반", + "FrmSettings._ImageLoading": "이미지 불러오기", + "FrmSettings._ShowSlideshowCountdown": "슬라이드쇼 카운트다운 표시", + "FrmMain.MnuSave": "저장", + "FrmMain.MnuMoveToRecycleBin": "휴지통으로 이동", + "FrmMain.MnuRefresh": "새로 고침", + "FrmToolNotFound.LblHeading": "{0}'을(를) 찾을 수 없습니다!", + "FrmMain.MnuReportIssue": "문제 보고...", + "FrmMain.MnuCopyImageData": "이미지 데이터 복사", + "FrmMain.MnuCheckForUpdate._NewVersion": "새 버전을 사용할 수 있습니다!", + "_._Empty": "(비어 있음)", + "FrmSettings._Zooming": "확대/축소", + "FrmMain.MnuCutFile": "파일 자르기", + "FrmHotkeyPicker.LblHotkey": "단축키 누르기", + "FrmSettings.Layout._Gallery": "갤러리", + "FrmMain.MnuNewWindow": "새 창 열기", + "FrmMain.MnuMoveToRecycleBin._Description": "이 파일을 휴지통으로 이동하시겠습니까?", + "FrmSettings._DefaultPhotoViewer": "기본 사진 뷰어", + "_.Metadata._ExifDateTimeOriginal": "EXIF: 원본 날짜/시간", + "FrmMain.MnuRotateRight": "오른쪽으로 회전", + "FrmSettings._MinEmbeddedThumbnailSize": "로드할 내장된 썸네일의 최소 크기", + "FrmMain.MnuSetDefaultPhotoViewer": "기본 사진 뷰어 설정", + "FrmMain.MnuImageProperties": "이미지 속성", + "FrmSettings._EnableNavigationButtons": "탐색 화살표 버튼 표시", + "_._Edit": "편집", + "FrmSettings._ImageBooster": "이미지 부스터", + "FrmSettings.Tools._IntegratedWith": "{0}과(와) 통합됨", + "_._Next": "다음", + "FrmExportFrames._OpenOutputFolder": "출력 폴더 열기", + "FrmMain.MnuOpenLocation": "이미지 위치 열기", + "FrmMain.MnuLockZoom": "확대/축소 비율 잠금", + "FrmSettings._StartupBoost._Description": "Windows 시작 시 몇 초 동안 백그라운드에서 ImageGlass를 미리 로드하고 실행하여 첫 실행 속도를 높입니다.", + "FrmSettings._WindowBackdrop": "창 배경", + "FrmSettings._EnableRealTimeFileUpdate": "보기 폴더의 파일 변경 사항 모니터링 및 실시간 업데이트", + "_._NotSupported": "지원되지 않는 형식", + "FrmSettings._Theme._GetMoreThemes": "더 많은 테마 팩 가져오기...", + "FrmMain.MnuNewWindow._Error": "인스턴스가 하나만 허용되므로 새 창을 열 수 없습니다", + "FrmMain.MnuZoomOut": "축소", + "FrmSettings.Toolbar._EditButton": "도구 모음 버튼 편집", + "FrmMain.MnuCustomZoom._Description": "새 확대/축소 값 입력", + "FrmResize.RadResizeByPixels": "픽셀", + "FrmMain.MnuEdit": "이미지 편집 {0}…", + "FrmSettings.Layout._GalleryPosition": "갤러리 위치", + "FrmMain.MnuWindowFit": "창 맞춤", + "FrmMain._OpenFileDialog": "지원되는 모든 파일", + "FrmSettings._UseRandomIntervalForSlideshow": "임의 간격 사용", + "_.Position._Left": "왼쪽", + "FrmSettings._ShouldOpenLastSeenImage": "마지막으로 본 이미지 열기", + "_.Position._Bottom": "하단", + "FrmResize.ChkKeepRatio": "프로모션 비율 유지", + "FrmMain.MnuGoTo": "이동…", + "FrmSlideshow.MnuPauseResumeSlideshow": "슬라이드쇼 일시 중지/재개", + "FrmSettings.Tools._Integrated": "통합", + "FrmSettings._Contributors": "기여자", + "_.MouseWheelAction._Zoom": "확대 / 축소", + "_._CommandPreview": "명령 미리 보기", + "FrmSettings._DarkTheme": "어두운", + "_._Hotkeys": "단축키", + "_.Metadata._ExifDateTime": "EXIF: 날짜 시간", + "FrmSettings.Toolbar._Errors._ButtonIdRequired": "버튼 ID가 필요합니다.", + "FrmSettings._MinEmbeddedThumbnailSize._Width": "너비", + "_._Executable": "실행 파일", + "_.ImageInterpolation._MultiSampleLinear": "다중 샘플 선형", + "_._Separator": "구분자", + "FrmQuickSetup._ProfessionalUser": "전문 사용자", + "FrmMain.MnuFlipVertical": "세로 뒤집기", + "FrmSlideshow._ResumeSlideshow": "슬라이드쇼가 다시 시작됩니다.", + "FrmCropSettings.DefaultSelectionType._CustomArea": "사용자 지정 영역...", + "FrmMain.MnuActualSize": "실제 크기", + "FrmCrop.BtnSaveAs": "따로 저장…", + "FrmSettings._InstallNewLanguagePack": "새 언어 팩 설치...", + "FrmSlideshow.MnuZoomModes": "확대/축소 모드", + "FrmMain.MnuTools": "도구", + "_.ImageInterpolation._Cubic": "입방체", + "FrmUpdate._LatestVersion": "최신 버전: {0}", + "FrmMain.MnuViewNext": "다음 이미지 보기", + "_.MouseWheelEvent._AltAndScroll": "Alt를 누르고 스크롤", + "FrmToolNotFound._Title": "도구를 찾을 수 없습니다", + "FrmCrop.BtnCrop._Tooltip": "이미지만 자르기", + "FrmSettings.EditAppDialog._AddApp": "편집을 위해 앱 추가", + "FrmMain.MnuPanning": "이동", + "_._MoveUp": "위로 이동", + "FrmCropSettings.DefaultSelectionType._SelectAll": "모두 선택", + "_._Name": "이름", + "FrmColorPickerSettings.ChkShowHslA": "알파 값에 HSL 형식 사용", + "FrmMain.MnuToggleImageAnimation": "이미지 애니메이션 시작/중지", + "FrmSettings._DisableStartupBoost": "시작 부스트 사용 안 함", + "FrmMain.MnuCopyFile._Success": "{0} 파일 복사됨", + "FrmMain.MnuSave._ConfirmDescription": "ImageGlass는 전문적인 사진 편집기가 아니므로 이미지를 저장할 때 품질, 메타데이터, 레이어 등이 손실된다는 점에 유의하시기 바랍니다.", + "FrmToolNotFound.BtnSelectExecutable": " 선택…", + "FrmUpdate._StatusOutdated": "새 업데이트를 이용할 수 있습니다!", + "_.ImageOrderBy._Random": "무작위", + "FrmResize.LblCurrentSize": "현재 크기:", + "_._Apply": "적용", + "FrmAbout._Slogan": "가벼운 다용도 이미지 뷰어", + "FrmMain.MnuPanToTop": "이미지를 위쪽으로 이동", + "FrmSettings.Toolbar._AddNewButton": "사용자 지정 도구 모음 버튼 추가", + "FrmCrop.LblSize": "크기:", + "FrmSettings._ImageInterpolation._ScaleDown": "확대/축소가 < 100% 인 경우", + "_._CreatingFileError": "임시 이미지 파일을 만들 수 없습니다", + "FrmMain.MnuGoTo._Description": "보려는 이미지 인덱스를 입력한 다음 ENTER 키를 누릅니다.", + "FrmSettings.Toolbar._EnableCenterToolbar": "도구 모음에 가운데 정렬 사용", + "FrmMain.MnuResizeTool": "이미지 크기 조정", + "FrmSettings.Layout._Toolbar": "도구 모음", + "FrmMain.MnuHelp": "도움말", + "_.ImageOrderBy._FileSize": "파일 크기", + "FrmSettings._Theme._OpenThemeFolder": "테마 폴더 열기", + "FrmMain.MnuNavigation": "탐색", + "_._Save": "저장", + "FrmQuickSetup._SettingProfileDescription": "이러한 설정을 수정하려면 앱 설정에 액세스하기만 하면 됩니다.", + "_._UserAction._MenuNotFound": "작업을 호출할 '{0}' 메뉴를 찾을 수 없습니다", + "FrmMain.MnuPanToLeftSide": "이미지를 왼쪽으로 이동", + "FrmUpdate._CurrentVersion": "현재 버전: {0}", + "FrmCrop.BtnSettings._Tooltip": "자르기 도구 설정 열기", + "_.ColorProfileOption._Custom": "사용자 지정…", + "FrmSettings._UseEmbeddedThumbnailOtherFormats": "다른 형식의 내장된 썸네일만 불러오기", + "FrmMain.MnuGoToFirst": "첫번째 이미지로 이동", + "FrmSettings._ExportLanguagePack": "언어 팩 내보내기...", + "FrmSettings.Nav._Mouse": "마우스", + "_.ImageOrderBy._DateCreated": "만든 날짜", + "FrmSettings._EnableFullscreenSlideshow": "슬라이드쇼를 전체 화면 모드로 시작", + "FrmAbout._Homepage": "홈페이지:", + "FrmSettings._GalleryCacheSizeInMb": "최대 갤러리 캐시 크기 (메가바이트)", + "FrmMain.MnuCopyImageData._Success": "현재 이미지 데이터를 복사했습니다.", + "FrmSettings._EnableLoopBackNavigation": "이미지 목록의 끝에 도달하면 첫 번째 이미지로 돌아가기", + "_.MouseWheelEvent._Scroll": "스크롤", + "FrmCrop.BtnSave._Tooltip": "이미지 저장", + "FrmMain.MnuSlideshow": "슬라이드쇼", + "FrmMain.MnuShare": "공유…", + "FrmSettings._SlideshowNotification": "슬라이드쇼 알림", + "FrmMain.MnuViewChannels": "채널 보기", + "FrmSettings._Refresh": "새로 고침", + "_._UserAction._MethodNotFound": "작업을 호출할 메서드 '{0}'을(를) 찾을 수 없습니다", + "FrmMain.MnuCopyFile": "파일 복사", + "_._CreatingFile": "임시 이미지 파일을 만드는 중...", + "FrmMain.MnuToggleTopMost": "항상 창을 맨 위에 유지", + "FrmMain.MnuLosslessCompression._Confirm": "계속 진행하시겠습니까?", + "FrmMain.MnuImage": "이미지", + "FrmSettings._StartupBoost._Enabled": "시작 부스트가 활성화됨", + "FrmQuickSetup._SetDefaultViewer": "ImageGlass를 기본 사진 뷰어로 설정하시겠습니까?", + "FrmMain.MnuScaleToWidth": "너비에 맞춤", + "_._FileExtension": "파일 확장자", + "FrmUpdate._PublishedDate": "게시 날짜: {0}", + "_._DoNotShowThisMessageAgain": "이 메시지를 다시 표시 안 함", + "_.ImageInterpolation._NearestNeighbor": "최근접 이웃", + "FrmCrop.LblLocation": "위치:", + "_._Download": "다운로드", + "_.Metadata._ColorProfile": "색상 프로필", + "FrmSettings._CenterWindowFit": "창 맞춤 모드에서 창 자동 가운데 맞춤", + "FrmSettings._ImageLoadingOrder": "이미지 정렬 기준", + "FrmSettings._GalleryColumns": "세로 갤러리 레이아웃의 썸네일 열 수", + "_._Quit": "종료", + "_._Add": "추가", + "FrmMain.MnuChangeBackgroundColor": "배경 색상 변경…", + "FrmMain.MnuToggleToolbar": "도구 모음", + "FrmAbout._Contact": "연락처", + "FrmSettings.Toolbar._AddCustomButton": "사용자 지정 버튼 추가...", + "FrmCrop.BtnQuickSelect._Tooltip": "빠른 선택...", + "FrmMain.MnuCutFile._Success": "{0} 개의 파일을 자릅니다.", + "FrmSettings._ZoomSpeed": "확대/축소 속도", + "FrmMain.MnuToggleTopMost._Disable": "항상 창을 맨 위에 사용 안 함", + "FrmSettings._ShouldUseExplorerSortOrder": "가능하면 탐색기 정렬 순서 사용", + "_.ImageInterpolation._Antisotropic": "반등방성", + "FrmMain._ReachedFirstImage": "첫 번째 이미지에 도달했습니다.", + "_._UnhandledException": "처리되지 않은 예외", + "FrmResize.LblNewSize": "새 크기:", + "FrmMain._ClipboardImage": "클립보드 이미지", + "FrmMain.MnuExportFrames": "이 파일을 완전히 삭제하시겠습니까? 이미지 프레임 내보내기...", + "FrmMain.MnuFile": "파일", + "_._Close": "닫기", + "FrmMain.MnuMain": "기본 메뉴", + "_._ResetToDefault": "기본값으로 재설정", + "FrmSettings.Nav._Gallery": "갤러리", + "FrmMain.MnuSetDefaultPhotoViewer._Success": "ImageGlass를 기본 사진 뷰어로 성공적으로 설정했습니다.", + "FrmSettings._HideGalleryInFullscreen": "전체 화면 모드에서 갤러리 숨기기", + "FrmSettings._AvailableImageInfoTags": "사용 가능한 태그:", + "FrmExportFrames._Exporting": "{0}/{1} 프레임 내보내는 중\n{2}…", + "_._Argument": "인수", + "FrmSettings._ImageEditQuality": "이미지 품질", + "_._ID": "ID", + "FrmSettings._UserConfigFile": "사용자 설정 파일 (igconfig.json)", + "FrmMain.MnuLoadingOrders": "로딩 순서", + "FrmSettings._OpenSaveAsDialogInTheCurrentImageDir": "현재 이미지 디렉터리에서 다른 이름으로 저장 대화 상자를 엽니다.", + "_.MouseWheelEvent._ShiftAndScroll": "Shift를 누르고 스크롤", + "FrmSettings._UseSmoothZooming": "부드러운 확대/축소 사용", + "FrmSettings._Theme": "테마", + "FrmSettings._ImageBoosterCacheMaxDimension": "캐시할 최대 이미지 치수 (픽셀)", + "FrmMain.MnuScaleToHeight": "높이에 맞춤", + "_.Metadata._FileLastWriteTime": "수정 날짜", + "FrmSettings._Author": "저작자", + "FrmSettings._Others": "기타", + "_.MouseWheelAction._PanVertically": "위 / 아래로 이동", + "FrmSettings._MouseWheelAction": "마우스 휠 동작", + "FrmSettings.Nav._Tools": "도구", + "FrmMain.MnuSetDesktopBackground._Error": "보기 이미지를 바탕 화면 배경으로 설정할 수 없습니다", + "FrmSettings.Toolbar._Errors._ButtonExecutableRequired": "버튼 실행 파일이 필요합니다.", + "_.ImageOrderBy._DateAccessed": "접근 날짜", + "FrmSettings._ThumbnailSize": "썸네일 크기 (픽셀 단위)", + "FrmSettings._FileFormats": "파일 형식", + "FrmMain.MnuReloadImageList": "이미지 목록 다시 불러오기", + "FrmSettings._UseWebview2ForSvg": "SVG 형식 보기에 Webview2 사용", + "FrmCrop.BtnCopy": "복사", + "FrmSettings._CurrentMonitorProfile._Description": "모니터 간에 창을 이동할 때 ImageGlass가 색상을 자동으로 업데이트하지 않음", + "FrmMain.PicMain._ErrorText": "이 이미지를 열 수 없습니다.", + "FrmSettings.Tools._AddNewTool": "외부 도구 추가", + "FrmMain.MnuRename": "이미지 이름 바꾸기…", + "FrmMain.MnuViewLastFrame": "마지막 프레임 보기", + "_._Webview2._NotFound": "최신 버전의 WebView2 런타임을 설치하세요.", + "FrmMain.MnuGetMoreTools": "더 많은 도구...", + "FrmSettings.Nav._Appearance": "모양", + "FrmSettings._SlideshowInterval": "슬라이드쇼 간격:", + "_.ImageInterpolation._HighQualityBicubic": "고품질 쌍입방", + "FrmColorPickerSettings.ChkShowHsvA": "알파 값에 HSV 형식 사용", + "FrmSettings.Tools._EditTool": "외부 도구 편집", + "_._Error": "오류", + "FrmSettings._ImageBoosterCacheMaxFileSizeInMb": "캐시할 최대 이미지 파일 크기 (메가바이트)", + "_._UnhandledException._Description": "처리되지 않은 예외가 발생했습니다. 계속을 클릭하면 응용 프로그램이 이 오류를 무시하고 계속하려고 시도합니다. 종료를 클릭하면 응용프로그램이 즉시 닫힙니다.", + "_.Metadata._FileSize": "파일 크기", + "FrmSettings.Toolbar._ButtonJson": "JSON 버튼", + "FrmQuickSetup._SetDefaultViewer._Description": "앱 설정 > 파일 유형 연결 탭에서 재설정할 수 있습니다.", + "FrmSettings.Nav._Edit": "편집", + "FrmMain.MnuToggleGallery": "갤러리 패널", + "_._IgCommandExe._DefaultError._Description": "정확한 명령을 전달해야 합니다!\r\n이 실행 파일에는 ImageGlass 소프트웨어의 명령줄 기능이 포함되어 있습니다.\r\n\r\n모든 명령줄을 탐색하려면 다음 사이트를 방문하십시오:\n{0}", + "FrmMain.MnuLosslessCompression._Compressing": "무손실 압축 수행…", + "FrmSettings._ShouldGroupImagesByDirectory": "디렉터리별 이미지 그룹화", + "FrmMain.MnuPanToRightSide": "이미지를 오른쪽으로 이동", + "_.Metadata._ExifRatingPercent": "등급", + "FrmSettings._PanSpeed": "이동 속도", + "_._CheckForUpdate": "업데이트 확인…", + "FrmSettings.Layout._ToolbarContext": "상황별 도구 모음", + "_.ImageInfo._FrameCount": "{0} 프레임", + "FrmMain.MnuLayout": "레이아웃", + "_._Website": "웹사이트", + "FrmMain.MnuPasteImage": "이미지 붙여넣기", + "FrmSettings._ShowGalleryScrollbars": "갤러리 스크롤 막대 표시" + } +} \ No newline at end of file diff --git a/Setup/Assets/Language/Kurmanji (Kurdish).iglang.json b/Setup/Assets/Language/Kurmanji (Kurdish).iglang.json new file mode 100644 index 000000000..84094a208 --- /dev/null +++ b/Setup/Assets/Language/Kurmanji (Kurdish).iglang.json @@ -0,0 +1,504 @@ +{ + "_Metadata": { + "Code": "ku-KU", + "EnglishName": "Kurdish", + "LocalName": "Kurdî", + "Author": "Cyax", + "MinVersion": "9.3" + }, + "Items": { + "FrmCrop.SelectionAspectRatio._Original": "Resen", + "FrmMain.MnuShare._Error": "Could not open Share dialog.", + "_.Metadata._FileLastAccessTime": "Dîroka gihiştinê", + "FrmAbout._License": "Software license", + "FrmSettings.Toolbar._Errors._ButtonIdDuplicated": "A button with the ID '{0}' has already been defined. Please choose a different and unique ID for your button to avoid conflicts.", + "FrmMain.MnuSave._Confirm": "Are you sure you want to override this image?", + "FrmSettings._OpenDefaultAppsSetting": "Open Default apps setting", + "FrmMain.MnuCopyPath": "Riya wêneyê jê bigire", + "FrmCropSettings.DefaultSelectionType._SelectNone": "Select none", + "_.MouseWheelAction._PanHorizontally": "Kaş çep / rast bike", + "FrmMain.MnuPrint": "Çap bike…", + "FrmSettings.Toolbar._ToolbarButtons": "Toolbar buttons", + "FrmResize.LblResample": "Resample:", + "_.ImageOrderBy._Extension": "Pêvek", + "FrmSettings.Nav._Viewer": "Nîşandar", + "FrmSettings.EditAppDialog._EditApp": "Sepanê serrast bike", + "FrmCrop.BtnReset._Tooltip": "Reset selection", + "FrmMain.MnuRename._Description": "Enter a new filename:", + "_._No": "No", + "FrmSlideshow.MnuToggleCountdown": "Jimartina pêşandana pêşeker nîşan bide", + "FrmSettings._OpenStartupAppsSetting": "Open Startup apps setting", + "FrmMain.MnuViewPreviousFrame": "Çarçoveya paş nîşan bide", + "_.ImageOrderBy._DateModified": "Dîroka guhertinê", + "FrmMain.MnuViewNextFrame": "Çarçoveya pêş nîşan bide", + "FrmMain.MnuUnload": "Wêneyê rake", + "FrmSettings.Toolbar._HideToolbarInFullscreen": "Hide toolbar in Full Screen mode", + "_.ImageOrderType._Desc": "Berjêr", + "_._Update": "Rojane bike", + "FrmSettings._EnableImageAsyncLoading": "Enable image asynchronous loading", + "FrmSettings._DefaultPhotoViewer._Description": "Register the supported formats of ImageGlass with Windows. You might need to open the Default apps settings and manually select ImageGlass from the list for it to take effect.", + "_.MouseWheelAction._BrowseImages": "Wêneya pêş / paş nîşan bide", + "FrmSettings._EditApps": "Sepanên serrastkirinê wêneyan", + "FrmColorPickerSettings.ChkShowCIELabA": "Formata CIELAB bi kar bîne ligel nirxê Alfa", + "_._GetHelp": "Daxwaza alîkariyê bike", + "FrmQuickSetup._SkipQuickSetup": "Vê derbas bike û ImageGlass bide destpêkirin", + "FrmColorPickerSettings._Title": "Color picker settings", + "_._Copy": "Jê bigire", + "FrmSettings._ImageBoosterCacheCount": "Number of images cached by Image Booster (one direction)", + "FrmMain.MnuPanToBottom": "Pan image to bottom", + "FrmMain.MnuZoom": "Mezinkirin", + "FrmCropSettings.ChkCloseToolAfterSaving": "Close Crop tool after saving", + "FrmSettings._ShowWelcomeImage": "Rûpela pêşwaziyê nîşan bide", + "FrmSettings._ColorProfile": "Profîla rengan", + "FrmSettings._Theme._UninstallTheme": "Uninstall a theme pack", + "FrmMain._OpenWith": "Open with {0}", + "FrmMain.MnuRemoveDefaultPhotoViewer": "Remove default photo viewer", + "_.AfterEditAppAction._Nothing": "Ne tişt", + "FrmCrop.BtnSave": "Tomar bike", + "FrmMain.MnuScaleToFit": "Bo lihevhatinê bipîve", + "FrmToolNotFound.LblDownloadToolText": "You can download more tools for ImageGlass at:", + "_._LearnMore": "Bêtir fêr bibe…", + "FrmCrop.LblAspectRatio": "Aspect ratio:", + "FrmExportFrames._FileNotExist": "Image file does not exist", + "FrmSettings._LightTheme": "Ronî", + "FrmSettings.Nav._Slideshow": "Pêşandana pêşekerî", + "_._Continue": "Bidomîne", + "_._AddHotkey": "Bişkoka kurterê tevlî bike…", + "FrmMain.MnuSetDesktopBackground": "Wekî paşrûyê sermaseyê saz bike", + "FrmMain.MnuReload": "Wêneyê ji nû ve bar bike", + "FrmSlideshow.MnuExitSlideshow": "Ji pêşandana pêşekerî derkeve", + "FrmMain.MnuAutoZoom": "Mezinkirina xweber", + "FrmSettings._ShowImagePreview": "Display image preview while it's being loaded", + "FrmCrop.BtnCopy._Tooltip": "Copy the selection to clipboard", + "FrmSettings.Nav._Toolbar": "Alavbend", + "FrmMain.MnuSave._Error": "Nikare wêneyê tomar bikê", + "FrmSettings._AfterEditingAction": "Piştî vekirina sepana serrastkirinê", + "FrmSettings._ShouldUseColorProfileForAll": "Bêyî profîla rengan a veşartî ji bo wêneyan jî bisepîne", + "FrmCropSettings.DefaultSelectionType._UseTheLastSelection": "Use the last selection", + "FrmSettings._SlideshowInterval._From": "Ji", + "FrmSettings._ImageInterpolation": "Image interpolation", + "FrmQuickSetup._StepInfo": "Gav {0}", + "FrmMain.MnuColorPicker": "Hilbijêrê rengan", + "FrmCrop.SelectionAspectRatio._FreeRatio": "Free ratio", + "FrmSettings._ResetSettings": "Reset settings", + "FrmSettings._Startup": "Destpêk", + "_.BackdropStyle._None": "Ne yek", + "FrmSettings._LoadDefaultZoomLevels": "Load default zoom levels", + "FrmColorPicker.BtnSettings._Tooltip": "Open Color picker settings…", + "FrmSettings._UseThemeForDarkMode": "Use this theme for dark mode", + "FrmSettings._ShowDeleteConfirmation": "Show confirmation dialog when deleting file", + "FrmSettings._ShowAppIcon": "Show app icon on the title bar", + "_._InvalidAction": "Invalid action", + "FrmQuickSetup._SelectProfile": "Profîlekê hilbijêre", + "_.Metadata._FileCreationTime": "Dîroka afirandinê", + "FrmSettings._SlideshowImagesToNotifySound": "Number of images to trigger a notification sound", + "FrmSettings._BackgroundColor": "Viewer background color", + "FrmSettings._RealTimeFileUpdate": "Rojanekirin pelê ya rastîn-dem", + "_.ColorProfileOption._CurrentMonitorProfile": "Profîla dîmendera heyî", + "FrmSettings._EnableCutMultipleFiles": "Enable the cutting of multiple files at once", + "FrmSettings._AutoUpdate": "Ji bo rojanekirinê bixweber kontrol bike", + "FrmCropSettings.LblDefaultSelection": "Default selection", + "FrmSettings._UseThemeForLightMode": "Use this theme for light mode", + "FrmSettings._ZoomLevels": "Astên mizinkirinê", + "FrmMain.MnuSetLockScreen._Success": "Lock screen image is updated", + "FrmSettings._ShowGalleryFileName": "Show thumbnail filename", + "FrmSettings.Layout._Order": "Rêz", + "FrmCropSettings.ChkAutoCenterSelection": "Auto-center selection", + "FrmSettings.Nav._FileTypeAssociations": "File type associations", + "_._Back": "Vegere", + "FrmMain.MnuSetDesktopBackground._Success": "Desktop background is updated", + "FrmSettings._ShouldAutoOpenNewAddedImage": "Open the new added image automatically", + "FrmCrop.SelectionAspectRatio._Custom": "Kesanekirî…", + "FrmMain.MnuCopyPath._Success": "Rêgeha wêneyê heyî hate jêgirtin.", + "FrmSettings._StartupBoost._Error": "Could not change Startup Boost setting", + "FrmToolNotFound.LblDescription": "ImageGlass was unable to locate the path to the '{0}' executable. To resolve this issue, please update the path to the '{0}' as necessary.", + "FrmMain.MnuClearClipboard": "Tûrikê pak bike", + "FrmSettings._ColorManagement": "Rêveberiya rengan", + "FrmMain._ReachedLastLast": "Gihîşt wêneyê dawî", + "FrmMain.MnuPanUp": "Pan image up", + "FrmMain.MnuRemoveDefaultPhotoViewer._Success": "ImageGlass is no longer the default photo viewer.", + "FrmSettings._GetMoreLanguagePacks": "Bêtir pakêtên ziman bistîne…", + "FrmAbout._Privacy": "Politîka taybetiyê", + "FrmSettings._EnableRecursiveLoading": "Load images in subfolders", + "_._UserAction._MethodArgumentNotSupported": "The argument type of method '{0}' is not supported", + "FrmSettings._FileExtensionIcons._Description": "For customizing file extension icons, download an icon pack, place all .ICO files in the extension icon folder, and click the '{0}' button. This will also set ImageGlass as default photo viewer.", + "_.ImageOrderType._Asc": "Berjor", + "FrmExportFrames._Title": "Export image frames", + "_._Install": "Saz bike…", + "FrmMain.MnuFlipHorizontal": "Asoyî bizivrîne", + "FrmSettings._OpenExtensionIconFolder": "Open extension icon folder", + "FrmAbout._Collaborator": "Hevkar:", + "FrmQuickSetup._ConfirmCloseProcess": "Before applying the new settings, it's essential to close all ImageGlass processes. Tu amede ye bo ku bidomînî?", + "FrmExportFrames._ExportDone": "Exported {0} frames successfully to \r\n{1}", + "FrmCrop.BtnSaveAs._Tooltip": "Wekî jêgiritinkê tomar bike…", + "FrmMain.MnuOpenFile": "Pelê veke…", + "FrmColorPickerSettings.ChkShowRgbA": "Formata RGB bi kar bîne ligel nirxê alfa", + "_.ImageInfo._ListCount": "{0} pel", + "FrmMain.MnuGoToLast": "Biçe wêneya dawî", + "FrmSettings._EditApps._AppName": "Navê sepanê", + "FrmSettings._SlideshowBackgroundColor": "Slideshow background color", + "FrmAbout._Email": "E-name:", + "_.MouseWheelAction._DoNothing": "Tiştekî neke", + "FrmMain.MnuSaveAs": "Tomar bike wekî…", + "FrmMain._Loading": "Tê barkirin…", + "_._Browse": "Binêre…", + "FrmMain.MnuSetDefaultPhotoViewer._Error": "Could not set ImageGlass as default photo viewer.", + "FrmSettings.Nav._Language": "Ziman", + "FrmQuickSetup._SeeWhatNew": "Binêre çi nû ye di vê guhertoyê de…", + "FrmSettings._ImageInterpolation._ScaleUp": "When zoom > 100%", + "FrmSettings.Layout._ToolbarContextPosition": "Contextual toolbar position", + "FrmMain.MnuDeleteFromHardDisk": "Delete permanently", + "FrmSettings._EmbeddedThumbnail": "Embedded thumbnail", + "FrmMain.MnuDeleteFromHardDisk._Description": "Are you sure you want to permanently delete this file?", + "FrmMain.MnuScaleToFill": "Bo tijîkirinê bipîve", + "FrmCrop.BtnCrop": "Qut bike", + "_.AfterEditAppAction._Minimize": "Biçûk bike", + "FrmMain.MnuInvertColors": "Invert colors", + "FrmSettings._StartupBoost": "Startup Boost", + "FrmMain.MnuViewFirstFrame": "Çarçoveya yekem nîşan bide", + "_.MouseWheelEvent._CtrlAndScroll": "Ctrl bitikîne û bişemtîne", + "FrmSettings._HideMainWindowInSlideshow": "Automatically hide main window", + "_.Metadata._FrameCount": "Çarçove", + "FrmSettings._EnableCopyMultipleFiles": "Enable the copying of multiple files at once", + "FrmMain.MnuFrameless._EnableDescription": "Hold Shift key to move the window.", + "_.ImageOrderBy._ExifDateTaken": "EXIF: Date taken", + "FrmAbout._Credits": "Credits", + "FrmSettings._AddNewFileExtension": "Add new file extension", + "FrmMain.MnuQuickSetup": "Open ImageGlass Quick Setup", + "FrmMain.MnuSave._Success": "Wêne hate tomarkirin", + "FrmMain.MnuPanLeft": "Pan image left", + "FrmUpdate._StatusChecking": "Checking for update…", + "FrmSettings.Nav._Layout": "Rêkxistin", + "FrmMain.MnuOpenWith": "Veke bi…", + "FrmAbout._Thanks": "Spasiyên taybet bo:", + "_._Warning": "Hişyarî", + "FrmSettings.Nav._Keyboard": "Klavye", + "FrmSlideshow._PauseSlideshow": "Pêşandana pêşeker rawestiya.", + "_._Add+": "Tevlî bike…", + "_._Email": "E-name", + "FrmMain.MnuPanDown": "Pan image down", + "_._Cancel": "Dev jê berde", + "_._OK": "BAŞ E", + "FrmMain.MnuPanRight": "Pan image right", + "_.Position._Right": "Rast", + "_._Icon": "Sembol", + "FrmSettings._ShouldLoadHiddenImages": "Load hidden images", + "_._InvalidAction._Transformation": "ImageGlass does not support rotation, flipping for this image.", + "FrmSettings._MakeDefault": "Bike berdest", + "FrmMain.MnuCopyImageData._Copying": "Copying the image data. Wê hinek dem bistîne…", + "FrmSettings._UseEmbeddedThumbnailRawFormats": "Load only the embedded thumbnail for RAW formats", + "_.ImageInterpolation._Linear": "Xezikî", + "FrmSettings._ImageInfoTags": "Image information tags", + "FrmSettings._FileExtensionIcons": "File extension icons", + "FrmMain.MnuEdit._AppNotFound": "Could not find the associated app for editing. You can assign an app for editing this format in ImageGlass Settings > Edit.", + "_.ColorProfileOption._None": "Ne yek", + "FrmSettings._TotalSupportedFormats": "Tevahiya formatên piştgirî: {0}", + "FrmSettings._Clipboard": "Tûrik", + "_._UserAction._Win32ExeError": "Cannot execute command '{0}'. Make sure the name is correct.", + "FrmCropSettings.DefaultSelectionType._SelectX": "{0} hilbijêre", + "_.AfterEditAppAction._Close": "Bigire", + "FrmAbout._LogoDesigner": "Çêkirê Logo:", + "_.ImageOrderBy._Name": "Nav (berdest)", + "FrmMain.MnuRemoveDefaultPhotoViewer._Error": "Could not remove ImageGlass as the default photo viewer.", + "FrmExportFrames._FolderPickerTitle": "Select output folder for exporting image frames", + "FrmAbout._Donate": "Bexş bike", + "FrmMain.MnuFrameNav": "Frame navigation", + "FrmMain.MnuSetLockScreen": "Wekî dîmendera kilîtê saz bike", + "_._Delete": "Jê bibe", + "FrmMain.MnuViewPrevious": "Wêneya paş nîşan bide", + "_.Position._Top": "Jor", + "FrmSettings.Toolbar._CurrentButtons": "Current buttons:", + "FrmMain.MnuAbout": "Derbar", + "FrmSettings._RemoveDefault": "Remove default", + "_._Description": "Danasîn", + "FrmMain.MnuPasteImage._Error": "Nikarê zanyariyên wêneyê di bîrdankê de bibe", + "FrmMain.MnuSettings": "Sazkarî", + "FrmCropSettings._Title": "Crop settings", + "FrmSettings.Toolbar._ToolbarIconHeight": "Mezinahiya sembola alavbendê", + "FrmSettings._SlideshowInterval._To": "To", + "FrmSettings.Layout._ToolbarPosition": "Cihê alavbendê", + "FrmUpdate._StatusUpdated": "You are using the latest version!", + "FrmMain.MnuExit": "Derkeve", + "_._Webview2._Outdated": "Your WebView2 Runtime is not supported. Please update to version {0} or later.", + "_._Yes": "Erê", + "FrmMain.MnuRotateLeft": "Bizîvirîne çepê", + "FrmSettings._EnableStartupBoost": "Enable Startup Boost", + "_.ImageOrderBy._ExifRating": "EXIF: Rating", + "FrmMain.MnuZoomIn": "Nêzîk bike", + "_.Metadata._ColorSpace": "Qada rengê", + "FrmAbout._Version": "Guherto:", + "FrmMain.MnuToggleTopMost._Enable": "Enabled window always on top", + "FrmSettings.Toolbar._AvailableButtons": "Available buttons:", + "FrmMain.MnuSave._Saving": "Wêne tê tomarkirin…", + "FrmQuickSetup._StandardUser": "Bikarhênera standart", + "FrmMain.MnuSetLockScreen._Error": "Could not set the viewing image as lock screen image", + "FrmSettings.Nav._Image": "Wêne", + "FrmSettings._Theme._InstallTheme": "Install theme packs", + "FrmSettings._EnableMultiInstances": "Mafê bide gelek mînakên bernameyê", + "FrmMain.MnuCropTool": "Crop image", + "_._IgCommandExe._DefaultError._Heading": "Invalid commands", + "_._Refresh": "Nû bike", + "FrmMain.MnuLosslessCompression._Description": "This tool uses Magick.NET library for lossless compression, optimizing file size. Overwrites only if the compressed file is smaller than the original.", + "_._MoveDown": "Bilivîne jêr", + "FrmSettings._GetExtensionIconPacks": "Get extension icon packs…", + "FrmSettings._InAppMessageDuration": "In-app message duration (milliseconds)", + "FrmMain.MnuFrameless": "Bêtarik", + "_._Reset": "Ji nû ve saz bike", + "FrmSettings._ConfigDir": "Configuration location", + "FrmQuickSetup._SettingsWillBeApplied": "Settings will be applied:", + "FrmSettings._UnmanagedSettingReminder": "This setting is not managed by ImageGlass. Don't forget to disable it before you remove or relocate the app because ImageGlass does not handle this automatically.", + "FrmMain.MnuClipboard": "Tûrik", + "FrmMain.MnuCustomZoom": "Mezinkirinê kesane bike…", + "FrmSettings._DisplayLanguage": "Display language", + "FrmMain.MnuPrint._Error": "Could not print the viewing image", + "FrmSettings._ShouldPreserveModifiedDate": "Dîroka guherandina wêneyê di tomarkirinê de tomar bike", + "FrmSettings._ShowSaveOverrideConfirmation": "Show confirmation dialog when overriding file", + "FrmColorPickerSettings.ChkShowHexA": "Formata HEX bi kar bîne ligel nirxê alfa", + "FrmMain.MnuFullScreen": "Dîmendera tijî", + "FrmSettings._StartupDir": "Cihê destpêkê", + "FrmSettings._ShowCheckerboardOnlyImageRegion": "Show checkerboard only within the image region", + "FrmMain.MnuClearClipboard._Success": "Cleared clipboard.", + "FrmQuickSetup._Text": "Sazkirina bilez a ImageGlass", + "FrmMain.MnuLosslessCompression._Done": "Done lossless compression.\r\nThe new file size is {0}, saved {1}.", + "FrmMain.MnuLosslessCompression": "Magick.NET Lossless Compression", + "FrmResize.RadResizeByPercentage": "Percentage", + "FrmSettings._StartupBoost._Disabled": "Startup Boost is disabled", + "FrmMain.MnuToggleCheckerboard": "Paşrûyê destgeha kontrolê", + "FrmSettings._MinEmbeddedThumbnailSize._Height": "Bilindî", + "FrmSettings.Nav._General": "Giştî", + "FrmSettings._ImageLoading": "Barkirina wêneyê", + "FrmSettings._ShowSlideshowCountdown": "Jimartina pêşandana pêşeker nîşan bide", + "FrmMain.MnuSave": "Tomar bike", + "FrmMain.MnuMoveToRecycleBin": "Move to the Recycle Bin", + "FrmMain.MnuRefresh": "Nû bike", + "FrmToolNotFound.LblHeading": "'{0}' nehate dîtin!", + "FrmMain.MnuReportIssue": "Pirsgirêkê ragehîne…", + "FrmMain.MnuCopyImageData": "Daneyên wêneyê jê bigire", + "FrmMain.MnuCheckForUpdate._NewVersion": "Guhertoyeke nû heye!", + "_._Empty": "(vala)", + "FrmSettings._Zooming": "Mezinkirin", + "FrmMain.MnuCutFile": "Pelê jê bike", + "FrmHotkeyPicker.LblHotkey": "Press hotkeys", + "FrmSettings.Layout._Gallery": "Wênedank", + "FrmMain.MnuNewWindow": "Çarçoveya nû veke", + "FrmMain.MnuMoveToRecycleBin._Description": "Do you want to move this file to the Recycle bin?", + "FrmSettings._DefaultPhotoViewer": "Nîşanderê wêneya berdest", + "_.Metadata._ExifDateTimeOriginal": "EXIF: DateTimeOriginal", + "FrmMain.MnuRotateRight": "Bizîvirîne rastê", + "FrmSettings._MinEmbeddedThumbnailSize": "Minimum size of the embedded thumbnail to be loaded", + "FrmMain.MnuSetDefaultPhotoViewer": "Set default photo viewer", + "FrmMain.MnuImageProperties": "Taybetiyên wêneyê", + "FrmSettings._EnableNavigationButtons": "Show navigation arrow buttons", + "_._Edit": "Serrast bike", + "FrmSettings._ImageBooster": "Image Booster", + "FrmSettings.Tools._IntegratedWith": "Integrated with {0}", + "_._Next": "Pêş", + "FrmExportFrames._OpenOutputFolder": "Open output folder", + "FrmMain.MnuOpenLocation": "Cihê wêneyê veke", + "FrmMain.MnuLockZoom": "Rêjeya mezinkirinê kilît bike", + "FrmSettings._StartupBoost._Description": "Preload and run ImageGlass in the background for a few seconds during Windows startup to accelerate the first launch.", + "FrmSettings._WindowBackdrop": "Window backdrop", + "FrmSettings._EnableRealTimeFileUpdate": "Monitor file changes in the viewing folder and update in realtime", + "_._NotSupported": "Unsupported format", + "FrmSettings._Theme._GetMoreThemes": "Get more theme packs…", + "FrmMain.MnuNewWindow._Error": "Cannot open new window because only one instance is allowed", + "FrmMain.MnuZoomOut": "Dûr bixe", + "FrmSettings.Toolbar._EditButton": "Edit toolbar button", + "FrmMain.MnuCustomZoom._Description": "Nirxeke mezinkirinê binivisîne", + "FrmResize.RadResizeByPixels": "Pixel", + "FrmMain.MnuEdit": "Wêneyê serrast bike {0}…", + "FrmSettings.Layout._GalleryPosition": "Gallery position", + "FrmMain.MnuWindowFit": "Window Fit", + "FrmMain._OpenFileDialog": "Hemû pelên piştgirî", + "FrmSettings._UseRandomIntervalForSlideshow": "Navbereke rasthatî bi kar bîne", + "_.Position._Left": "Çep", + "FrmSettings._ShouldOpenLastSeenImage": "Wêneyê herî dawî yê hatiye dîtin veke", + "_.Position._Bottom": "Jêr", + "FrmResize.ChkKeepRatio": "Keep ratio propotional", + "FrmMain.MnuGoTo": "Biçe bo…", + "FrmSlideshow.MnuPauseResumeSlideshow": "Pause/resume slideshow", + "FrmSettings.Tools._Integrated": "Integrated", + "FrmSettings._Contributors": "Contributors", + "_.MouseWheelAction._Zoom": "Nêzîk bike / Dûr bixe", + "_._CommandPreview": "Pêşdîtina fermanê", + "FrmSettings._DarkTheme": "Dark", + "_._Hotkeys": "Bişkokên kurterê", + "_.Metadata._ExifDateTime": "EXIF: DateTime", + "FrmSettings.Toolbar._Errors._ButtonIdRequired": "Button ID required.", + "FrmSettings._MinEmbeddedThumbnailSize._Width": "Pahnî", + "_._Executable": "Executable", + "_.ImageInterpolation._MultiSampleLinear": "Multi-sample linear", + "_._Separator": "Dabeşker", + "FrmQuickSetup._ProfessionalUser": "Bikarhênera profîşiyonal", + "FrmMain.MnuFlipVertical": "Stûnî bizivrîne", + "FrmSlideshow._ResumeSlideshow": "Pêşandana pêşeker didome.", + "FrmCropSettings.DefaultSelectionType._CustomArea": "Custom area…", + "FrmMain.MnuActualSize": "Mezinahiya rastîn", + "FrmCrop.BtnSaveAs": "Tomar bike wekî…", + "FrmSettings._InstallNewLanguagePack": "Install new language packs…", + "FrmSlideshow.MnuZoomModes": "Zoom modes", + "FrmMain.MnuTools": "Alav", + "_.ImageInterpolation._Cubic": "Cubic", + "FrmUpdate._LatestVersion": "Guhertoya herî dawî: {0}", + "FrmMain.MnuViewNext": "Wêneya pêş nîşan bide", + "_.MouseWheelEvent._AltAndScroll": "Alt bitikîne û bişemtîne", + "FrmToolNotFound._Title": "Alav nehate dîtin", + "FrmCrop.BtnCrop._Tooltip": "Crop the image only", + "FrmSettings.EditAppDialog._AddApp": "Sepankê tevlî bike bo serrastkirinê", + "FrmMain.MnuPanning": "Zivirandin", + "_._MoveUp": "Bilivîne jor", + "FrmCropSettings.DefaultSelectionType._SelectAll": "Select all", + "_._Name": "Nav", + "FrmColorPickerSettings.ChkShowHslA": "Formata HSL bi kar bîne ligel nirxên alfa", + "FrmMain.MnuToggleImageAnimation": "Start / stop animating image", + "FrmSettings._DisableStartupBoost": "Disable Startup Boost", + "FrmMain.MnuCopyFile._Success": "Copied {0} file(s).", + "FrmMain.MnuSave._ConfirmDescription": "ImageGlass is not a professional photo editor, please be aware of losing the quality, metadata, layers,… when saving your image.", + "FrmToolNotFound.BtnSelectExecutable": "Hilbijêre…", + "FrmUpdate._StatusOutdated": "A new update is available!", + "_.ImageOrderBy._Random": "Rastehatî", + "FrmResize.LblCurrentSize": "Current Size:", + "_._Apply": "Bisepîne", + "FrmAbout._Slogan": "Dîmenderek wêneyê sivik, pir alî", + "FrmMain.MnuPanToTop": "Pan image to top", + "FrmSettings.Toolbar._AddNewButton": "Add a custom toolbar button", + "FrmCrop.LblSize": "Size:", + "FrmSettings._ImageInterpolation._ScaleDown": "When zoom < 100%", + "_._CreatingFileError": "Could not create temporary image file", + "FrmMain.MnuGoTo._Description": "Enter the image index to view, and then press ENTER", + "FrmSettings.Toolbar._EnableCenterToolbar": "Use center alignment for toolbar", + "FrmMain.MnuResizeTool": "Resize image", + "FrmSettings.Layout._Toolbar": "Alavbend", + "FrmMain.MnuHelp": "Alîkarî", + "_.ImageOrderBy._FileSize": "Mezinahiya pelê", + "FrmSettings._Theme._OpenThemeFolder": "Pelê rûkar veke", + "FrmMain.MnuNavigation": "Rêgeh", + "_._Save": "Tomar bike", + "FrmQuickSetup._SettingProfileDescription": "To modify these settings, simply access app settings.", + "_._UserAction._MenuNotFound": "Cannot find menu '{0}' to invoke the action", + "FrmMain.MnuPanToLeftSide": "Pan image to left edge", + "FrmUpdate._CurrentVersion": "Guhertoya heyî: {0}", + "FrmCrop.BtnSettings._Tooltip": "Open Crop tool settings", + "_.ColorProfileOption._Custom": "Kesanekirî…", + "FrmSettings._UseEmbeddedThumbnailOtherFormats": "Load only the embedded thumbnail for other formats", + "FrmMain.MnuGoToFirst": "Go to first image", + "FrmSettings._ExportLanguagePack": "Export language pack…", + "FrmSettings.Nav._Mouse": "Mişk", + "_.ImageOrderBy._DateCreated": "Dîroka afirandinê", + "FrmSettings._EnableFullscreenSlideshow": "Start slideshow in Full Screen mode", + "FrmAbout._Homepage": "Rûpela destpêkê:", + "FrmSettings._GalleryCacheSizeInMb": "Maximum gallery cache size (in megabytes)", + "FrmMain.MnuCopyImageData._Success": "Zanyariyên wêneyê heyî hatin jêgirtin.", + "FrmSettings._EnableLoopBackNavigation": "Loop back to the first image when reaching the end of the image list", + "_.MouseWheelEvent._Scroll": "Şemitandin", + "FrmCrop.BtnSave._Tooltip": "Wêneyê tomar bike", + "FrmMain.MnuSlideshow": "Pêşandana pêşekerî", + "FrmMain.MnuShare": "Parve bike…", + "FrmSettings._SlideshowNotification": "Slideshow notification", + "FrmMain.MnuViewChannels": "Kanalan nîşan bide", + "FrmSettings._Refresh": "Nû bike", + "_._UserAction._MethodNotFound": "Cannot find method '{0}' to invoke the action", + "FrmMain.MnuCopyFile": "Copy file", + "_._CreatingFile": "Creating a temporary image file…", + "FrmMain.MnuToggleTopMost": "Çarçoveyê her dem li jor bihêle", + "FrmMain.MnuLosslessCompression._Confirm": "Are you sure you want to proceed?", + "FrmMain.MnuImage": "Wêne", + "FrmSettings._StartupBoost._Enabled": "Startup Boost is enabled", + "FrmQuickSetup._SetDefaultViewer": "Do you want to set ImageGlass as the default photo viewer?", + "FrmMain.MnuScaleToWidth": "Bo pehnî bipîve", + "_._FileExtension": "Pêvekên pelê", + "FrmUpdate._PublishedDate": "Dîroka weşanê: {0}", + "_._DoNotShowThisMessageAgain": "Do not show this message again", + "_.ImageInterpolation._NearestNeighbor": "Cînara herî nêzîk", + "FrmCrop.LblLocation": "Location:", + "_._Download": "Daxistin", + "_.Metadata._ColorProfile": "Profîla rengan", + "FrmSettings._CenterWindowFit": "Automatically center the window in Window Fit mode", + "FrmSettings._ImageLoadingOrder": "Fermana barkirina wêneyê", + "FrmSettings._GalleryColumns": "Number of thumbnail columns in vertical gallery layout", + "_._Quit": "Derkeve", + "_._Add": "Tevlî bike", + "FrmMain.MnuChangeBackgroundColor": "Change background color…", + "FrmMain.MnuToggleToolbar": "Alavbend", + "FrmAbout._Contact": "Têkelî", + "FrmSettings.Toolbar._AddCustomButton": "Add a custom button…", + "FrmCrop.BtnQuickSelect._Tooltip": "Quick select…", + "FrmMain.MnuCutFile._Success": "{0} pêl jê bike.", + "FrmSettings._ZoomSpeed": "Zoom speed", + "FrmMain.MnuToggleTopMost._Disable": "Disabled window always on top", + "FrmSettings._ShouldUseExplorerSortOrder": "Use Explorer sort order if possible", + "_.ImageInterpolation._Antisotropic": "Antisotropic", + "FrmMain._ReachedFirstImage": "Gihîşt wêneyê yekem", + "_._UnhandledException": "Unhandled exception", + "FrmResize.LblNewSize": "Mezinahia nû:", + "FrmMain._ClipboardImage": "Clipboard image", + "FrmMain.MnuExportFrames": "Export image frames…", + "FrmMain.MnuFile": "Pel", + "_._Close": "Bigire", + "FrmMain.MnuMain": "Kulîna sereke", + "_._ResetToDefault": "Bîne rewşa berdestî", + "FrmSettings.Nav._Gallery": "Wênedank", + "FrmMain.MnuSetDefaultPhotoViewer._Success": "You have successfully set ImageGlass as default photo viewer.", + "FrmSettings._HideGalleryInFullscreen": "Hide gallery in Full Screen mode", + "FrmSettings._AvailableImageInfoTags": "Available tags:", + "FrmExportFrames._Exporting": "Exporting {0}/{1} frames \r\n{2}…", + "_._Argument": "Argument", + "FrmSettings._ImageEditQuality": "Kalîteya wêneyê", + "_._ID": "ID", + "FrmSettings._UserConfigFile": "Pela sazkariyên bikarhêner (igconfig.json)", + "FrmMain.MnuLoadingOrders": "Loading orders", + "FrmSettings._OpenSaveAsDialogInTheCurrentImageDir": "Open the Save As dialog in the current image directory", + "_.MouseWheelEvent._ShiftAndScroll": "Shift bitikîne û bişemtîne", + "FrmSettings._UseSmoothZooming": "Use smooth zooming", + "FrmSettings._Theme": "Rûkar", + "FrmSettings._ImageBoosterCacheMaxDimension": "Maximum image dimension to be cached (in pixels)", + "FrmMain.MnuScaleToHeight": "Bo bilindî bipîve", + "_.Metadata._FileLastWriteTime": "Dîroka guhertinê", + "FrmSettings._Author": "Nivîskar", + "FrmSettings._Others": "Ên din", + "_.MouseWheelAction._PanVertically": "Kaş jor / jêr bike", + "FrmSettings._MouseWheelAction": "Çalakiyên tekera mişkê", + "FrmSettings.Nav._Tools": "Alav", + "FrmMain.MnuSetDesktopBackground._Error": "Could not set the viewing image as desktop background", + "FrmSettings.Toolbar._Errors._ButtonExecutableRequired": "Button executable required.", + "_.ImageOrderBy._DateAccessed": "Dîroka gihiştinê", + "FrmSettings._ThumbnailSize": "Mezinahiya wêneyên biçûk (Pixel)", + "FrmSettings._FileFormats": "Formata pelê", + "FrmMain.MnuReloadImageList": "Rêzoka wêneyê ji nû ve bar bike", + "FrmSettings._UseWebview2ForSvg": "Use Webview2 for viewing SVG format", + "FrmCrop.BtnCopy": "Jê bigire", + "FrmSettings._CurrentMonitorProfile._Description": "ImageGlass does not auto-update the color when moving its window between monitors", + "FrmMain.PicMain._ErrorText": "Could not open this image", + "FrmSettings.Tools._AddNewTool": "Add an external tool", + "FrmMain.MnuRename": "Wêneyê ji nû ve bi nav bike…", + "FrmMain.MnuViewLastFrame": "Çarçoveya dawî nîşan bide", + "_._Webview2._NotFound": "Please install WebView2 Runtime to access full features of ImageGlass.", + "FrmMain.MnuGetMoreTools": "Get more tools…", + "FrmSettings.Nav._Appearance": "Xuyang", + "FrmSettings._SlideshowInterval": "Navbera pêşandana pêşeker:", + "_.ImageInterpolation._HighQualityBicubic": "High quality bicubic", + "FrmColorPickerSettings.ChkShowHsvA": "Formata HSV bi kar bîne ligel nirxê alfa", + "FrmSettings.Tools._EditTool": "Edit external tool", + "_._Error": "Çewtî", + "FrmSettings._ImageBoosterCacheMaxFileSizeInMb": "Maximum image file size to be cached (in megabytes)", + "_._UnhandledException._Description": "Unhandled exception has occurred. If you click Continue, the application will ignore this error and attempt to continue. If you click Quit, the application will close immediately.", + "_.Metadata._FileSize": "Mezinahiya pelê", + "FrmSettings.Toolbar._ButtonJson": "Button JSON", + "FrmQuickSetup._SetDefaultViewer._Description": "You can reset it in the app settings > File type associations tab.", + "FrmSettings.Nav._Edit": "Serrast bike", + "FrmMain.MnuToggleGallery": "Destgeha paşengehê", + "_._IgCommandExe._DefaultError._Description": "Make sure you pass the correct commands!\r\nThis executable file contains command-line functions for ImageGlass software.\r\n\r\nTo explore all command lines, please visit:\r\n{0}", + "FrmMain.MnuLosslessCompression._Compressing": "Performing lossless compression…", + "FrmSettings._ShouldGroupImagesByDirectory": "Wêneyan bi ya rêgehê kom bike", + "FrmMain.MnuPanToRightSide": "Pan image to right edge", + "_.Metadata._ExifRatingPercent": "Nirxandin", + "FrmSettings._PanSpeed": "Panning speed", + "_._CheckForUpdate": "Ji bo rojanekirinê kontrol bike…", + "FrmSettings.Layout._ToolbarContext": "Contextual toolbar", + "_.ImageInfo._FrameCount": "{0} tarik", + "FrmMain.MnuLayout": "Rêkxistin", + "_._Website": "Malper", + "FrmMain.MnuPasteImage": "Wêneyê pê ve bike", + "FrmSettings._ShowGalleryScrollbars": "Show gallery scrollbars" + } +} \ No newline at end of file diff --git a/Setup/Assets/Language/Kyrgyz.iglang.json b/Setup/Assets/Language/Kyrgyz.iglang.json new file mode 100644 index 000000000..e51c53806 --- /dev/null +++ b/Setup/Assets/Language/Kyrgyz.iglang.json @@ -0,0 +1,504 @@ +{ + "_Metadata": { + "Code": "ky-KG", + "EnglishName": "KyrGyz", + "LocalName": "Кыргызча", + "Author": "Ravidin Tursunkulov", + "MinVersion": "9.3" + }, + "Items": { + "FrmCrop.SelectionAspectRatio._Original": "Түпнуска", + "FrmMain.MnuShare._Error": "Could not open Share dialog.", + "_.Metadata._FileLastAccessTime": "Date accessed", + "FrmAbout._License": "Software license", + "FrmSettings.Toolbar._Errors._ButtonIdDuplicated": "A button with the ID '{0}' has already been defined. Please choose a different and unique ID for your button to avoid conflicts.", + "FrmMain.MnuSave._Confirm": "Are you sure you want to override this image?", + "FrmSettings._OpenDefaultAppsSetting": "Open Default apps setting", + "FrmMain.MnuCopyPath": "Файлдын жолун көчүрүү", + "FrmCropSettings.DefaultSelectionType._SelectNone": "Select none", + "_.MouseWheelAction._PanHorizontally": "Pan left / right", + "FrmMain.MnuPrint": "Басып чыгаруу…", + "FrmSettings.Toolbar._ToolbarButtons": "Toolbar buttons", + "FrmResize.LblResample": "Resample:", + "_.ImageOrderBy._Extension": "Түрү", + "FrmSettings.Nav._Viewer": "Орнотууларды көрүү", + "FrmSettings.EditAppDialog._EditApp": "Edit app", + "FrmCrop.BtnReset._Tooltip": "Reset selection", + "FrmMain.MnuRename._Description": "Enter a new filename:", + "_._No": "No", + "FrmSlideshow.MnuToggleCountdown": "Слайд көрсөтүү режиминде тескери саноону көрсөтүү", + "FrmSettings._OpenStartupAppsSetting": "Open Startup apps setting", + "FrmMain.MnuViewPreviousFrame": "View previous frame", + "_.ImageOrderBy._DateModified": "Date modified", + "FrmMain.MnuViewNextFrame": "View next frame", + "FrmMain.MnuUnload": "Unload image", + "FrmSettings.Toolbar._HideToolbarInFullscreen": "Hide toolbar in Full Screen mode", + "_.ImageOrderType._Desc": "Кемүү боюнча", + "_._Update": "Жаңылоо", + "FrmSettings._EnableImageAsyncLoading": "Enable image asynchronous loading", + "FrmSettings._DefaultPhotoViewer._Description": "Register the supported formats of ImageGlass with Windows. You might need to open the Default apps settings and manually select ImageGlass from the list for it to take effect.", + "_.MouseWheelAction._BrowseImages": "View next / previous Image", + "FrmSettings._EditApps": "Image editing apps", + "FrmColorPickerSettings.ChkShowCIELabA": "Use CIELAB format with alpha value", + "_._GetHelp": "Get help", + "FrmQuickSetup._SkipQuickSetup": "Skip this and launch ImageGlass", + "FrmColorPickerSettings._Title": "Color picker settings", + "_._Copy": "Көчүрүү", + "FrmSettings._ImageBoosterCacheCount": "Number of images cached by Image Booster (one direction)", + "FrmMain.MnuPanToBottom": "Pan image to bottom", + "FrmMain.MnuZoom": "Масштабдоо", + "FrmCropSettings.ChkCloseToolAfterSaving": "Close Crop tool after saving", + "FrmSettings._ShowWelcomeImage": "Show welcome image", + "FrmSettings._ColorProfile": "Түс профили", + "FrmSettings._Theme._UninstallTheme": "Uninstall a theme pack", + "FrmMain._OpenWith": "Open with {0}", + "FrmMain.MnuRemoveDefaultPhotoViewer": "Remove default photo viewer", + "_.AfterEditAppAction._Nothing": "Калтыруу", + "FrmCrop.BtnSave": "Сактоо", + "FrmMain.MnuScaleToFit": "Сүрөт терезенин өлчөмү боюнча", + "FrmToolNotFound.LblDownloadToolText": "You can download more tools for ImageGlass at:", + "_._LearnMore": "Кененирээк...", + "FrmCrop.LblAspectRatio": "Aspect ratio:", + "FrmExportFrames._FileNotExist": "Image file does not exist", + "FrmSettings._LightTheme": "Ачык", + "FrmSettings.Nav._Slideshow": "Слайд көрсөтүү", + "_._Continue": "Дагы", + "_._AddHotkey": "Add hotkey…", + "FrmMain.MnuSetDesktopBackground": "Жумуш үстөлүнүн фонуна орнотуңуз", + "FrmMain.MnuReload": "Сүрөттү жаңылоо", + "FrmSlideshow.MnuExitSlideshow": "Слайд көрсөтүү режиминен Чыгуу", + "FrmMain.MnuAutoZoom": "Автоматтык масштабдоо", + "FrmSettings._ShowImagePreview": "Display image preview while it's being loaded", + "FrmCrop.BtnCopy._Tooltip": "Copy the selection to clipboard", + "FrmSettings.Nav._Toolbar": "Аспаптар панели", + "FrmMain.MnuSave._Error": "Could not save the image", + "FrmSettings._AfterEditingAction": "Редактордо ачылгандан кийин", + "FrmSettings._ShouldUseColorProfileForAll": "Кыналган түстүү профили жок сүрөттөргө колдонуңуз", + "FrmCropSettings.DefaultSelectionType._UseTheLastSelection": "Use the last selection", + "FrmSettings._SlideshowInterval._From": "From", + "FrmSettings._ImageInterpolation": "Image interpolation", + "FrmQuickSetup._StepInfo": "Step {0}", + "FrmMain.MnuColorPicker": "Түс тандоо", + "FrmCrop.SelectionAspectRatio._FreeRatio": "Free ratio", + "FrmSettings._ResetSettings": "Reset settings", + "FrmSettings._Startup": "Startup", + "_.BackdropStyle._None": "Жок", + "FrmSettings._LoadDefaultZoomLevels": "Load default zoom levels", + "FrmColorPicker.BtnSettings._Tooltip": "Open Color picker settings…", + "FrmSettings._UseThemeForDarkMode": "Use this theme for dark mode", + "FrmSettings._ShowDeleteConfirmation": "Show confirmation dialog when deleting file", + "FrmSettings._ShowAppIcon": "Show app icon on the title bar", + "_._InvalidAction": "Invalid action", + "FrmQuickSetup._SelectProfile": "Select a profile", + "_.Metadata._FileCreationTime": "Date created", + "FrmSettings._SlideshowImagesToNotifySound": "Number of images to trigger a notification sound", + "FrmSettings._BackgroundColor": "Viewer background color", + "FrmSettings._RealTimeFileUpdate": "Real-time file update", + "_.ColorProfileOption._CurrentMonitorProfile": "Current monitor profile", + "FrmSettings._EnableCutMultipleFiles": "Enable the cutting of multiple files at once", + "FrmSettings._AutoUpdate": "Автоматтык түрдө жаңыртууларды текшериңиз", + "FrmCropSettings.LblDefaultSelection": "Default selection", + "FrmSettings._UseThemeForLightMode": "Use this theme for light mode", + "FrmSettings._ZoomLevels": "Масштабдын деңгээли", + "FrmMain.MnuSetLockScreen._Success": "Lock screen image is updated", + "FrmSettings._ShowGalleryFileName": "Show thumbnail filename", + "FrmSettings.Layout._Order": "Тартиби", + "FrmCropSettings.ChkAutoCenterSelection": "Auto-center selection", + "FrmSettings.Nav._FileTypeAssociations": "File type associations", + "_._Back": "Артка", + "FrmMain.MnuSetDesktopBackground._Success": "Desktop background is updated", + "FrmSettings._ShouldAutoOpenNewAddedImage": "Open the new added image automatically", + "FrmCrop.SelectionAspectRatio._Custom": "Түзөтүү…", + "FrmMain.MnuCopyPath._Success": "Copied the current image path.", + "FrmSettings._StartupBoost._Error": "Could not change Startup Boost setting", + "FrmToolNotFound.LblDescription": "ImageGlass was unable to locate the path to the '{0}' executable. To resolve this issue, please update the path to the '{0}' as necessary.", + "FrmMain.MnuClearClipboard": "Алмашуу буферин тазалоо", + "FrmSettings._ColorManagement": "Түстөрдү башкаруу", + "FrmMain._ReachedLastLast": "Акыркы сүрөткө өтүңүз", + "FrmMain.MnuPanUp": "Pan image up", + "FrmMain.MnuRemoveDefaultPhotoViewer._Success": "ImageGlass is no longer the default photo viewer.", + "FrmSettings._GetMoreLanguagePacks": "Get more language packs…", + "FrmAbout._Privacy": "Privacy policy", + "FrmSettings._EnableRecursiveLoading": "Load images in subfolders", + "_._UserAction._MethodArgumentNotSupported": "The argument type of method '{0}' is not supported", + "FrmSettings._FileExtensionIcons._Description": "For customizing file extension icons, download an icon pack, place all .ICO files in the extension icon folder, and click the '{0}' button. This will also set ImageGlass as default photo viewer.", + "_.ImageOrderType._Asc": "Өсүү боюнча", + "FrmExportFrames._Title": "Export image frames", + "_._Install": "Орнотуу…", + "FrmMain.MnuFlipHorizontal": "Туурасынан чагылдыруу", + "FrmSettings._OpenExtensionIconFolder": "Open extension icon folder", + "FrmAbout._Collaborator": "Collaborator:", + "FrmQuickSetup._ConfirmCloseProcess": "Before applying the new settings, it's essential to close all ImageGlass processes. Are you ready to proceed?", + "FrmExportFrames._ExportDone": "Exported {0} frames successfully to \r\n{1}", + "FrmCrop.BtnSaveAs._Tooltip": "Save as a copy…", + "FrmMain.MnuOpenFile": "Файлды ачыңыз…", + "FrmColorPickerSettings.ChkShowRgbA": "Use RGB format with alpha value", + "_.ImageInfo._ListCount": "{0} file(s)", + "FrmMain.MnuGoToLast": "Go to last image", + "FrmSettings._EditApps._AppName": "Колдонмонун аталышы", + "FrmSettings._SlideshowBackgroundColor": "Slideshow background color", + "FrmAbout._Email": "Email:", + "_.MouseWheelAction._DoNothing": "Эч аракет жок", + "FrmMain.MnuSaveAs": "Кантип сактоо керек…", + "FrmMain._Loading": "Жүктөлүүдө ...", + "_._Browse": "Сереп салуу…", + "FrmMain.MnuSetDefaultPhotoViewer._Error": "Could not set ImageGlass as default photo viewer.", + "FrmSettings.Nav._Language": "Тил", + "FrmQuickSetup._SeeWhatNew": "See what's new in this version…", + "FrmSettings._ImageInterpolation._ScaleUp": "When zoom > 100%", + "FrmSettings.Layout._ToolbarContextPosition": "Contextual toolbar position", + "FrmMain.MnuDeleteFromHardDisk": "Delete permanently", + "FrmSettings._EmbeddedThumbnail": "Embedded thumbnail", + "FrmMain.MnuDeleteFromHardDisk._Description": "Are you sure you want to permanently delete this file?", + "FrmMain.MnuScaleToFill": "Терезени толтуруу", + "FrmCrop.BtnCrop": "Crop", + "_.AfterEditAppAction._Minimize": "Кичирейтүү", + "FrmMain.MnuInvertColors": "Invert colors", + "FrmSettings._StartupBoost": "Startup Boost", + "FrmMain.MnuViewFirstFrame": "View first frame", + "_.MouseWheelEvent._CtrlAndScroll": "Hold Ctrl and scroll", + "FrmSettings._HideMainWindowInSlideshow": "Automatically hide main window", + "_.Metadata._FrameCount": "Барактар", + "FrmSettings._EnableCopyMultipleFiles": "Enable the copying of multiple files at once", + "FrmMain.MnuFrameless._EnableDescription": "Hold Shift key to move the window.", + "_.ImageOrderBy._ExifDateTaken": "EXIF: Date taken", + "FrmAbout._Credits": "Credits", + "FrmSettings._AddNewFileExtension": "Add new file extension", + "FrmMain.MnuQuickSetup": "Open ImageGlass Quick Setup", + "FrmMain.MnuSave._Success": "Image is saved", + "FrmMain.MnuPanLeft": "Pan image left", + "FrmUpdate._StatusChecking": "Checking for update…", + "FrmSettings.Nav._Layout": "Башкаруу элементтери", + "FrmMain.MnuOpenWith": "Жардамы менен ачуу…", + "FrmAbout._Thanks": "Special thanks to", + "_._Warning": "Көңүл бургула", + "FrmSettings.Nav._Keyboard": "Баскычтоп", + "FrmSlideshow._PauseSlideshow": "Көрсөтүүнү тындыруу.", + "_._Add+": "Кошуу…", + "_._Email": "Email", + "FrmMain.MnuPanDown": "Pan image down", + "_._Cancel": "Токтотуу", + "_._OK": "Макул", + "FrmMain.MnuPanRight": "Pan image right", + "_.Position._Right": "Оңго", + "_._Icon": "Сүрөтчө", + "FrmSettings._ShouldLoadHiddenImages": "Load hidden images", + "_._InvalidAction._Transformation": "ImageGlass does not support rotation, flipping for this image.", + "FrmSettings._MakeDefault": "Make default", + "FrmMain.MnuCopyImageData._Copying": "Copying the image data. It's going to take a while…", + "FrmSettings._UseEmbeddedThumbnailRawFormats": "Load only the embedded thumbnail for RAW formats", + "_.ImageInterpolation._Linear": "Linear", + "FrmSettings._ImageInfoTags": "Image information tags", + "FrmSettings._FileExtensionIcons": "File extension icons", + "FrmMain.MnuEdit._AppNotFound": "Could not find the associated app for editing. You can assign an app for editing this format in ImageGlass Settings > Edit.", + "_.ColorProfileOption._None": "Жок", + "FrmSettings._TotalSupportedFormats": "Total supported formats: {0}", + "FrmSettings._Clipboard": "Алмашуу буфери", + "_._UserAction._Win32ExeError": "Cannot execute command '{0}'. Make sure the name is correct.", + "FrmCropSettings.DefaultSelectionType._SelectX": "Select {0}", + "_.AfterEditAppAction._Close": "Жабык", + "FrmAbout._LogoDesigner": "Logo designer:", + "_.ImageOrderBy._Name": "Аты (баштапкы абалда)", + "FrmMain.MnuRemoveDefaultPhotoViewer._Error": "Could not remove ImageGlass as the default photo viewer.", + "FrmExportFrames._FolderPickerTitle": "Select output folder for exporting image frames", + "FrmAbout._Donate": "Donate", + "FrmMain.MnuFrameNav": "Frame navigation", + "FrmMain.MnuSetLockScreen": "Кулпуланган экран фону катары орнотуу", + "_._Delete": "Өчүрүү", + "FrmMain.MnuViewPrevious": "Мурунку сүрөт", + "_.Position._Top": "Өйдөгө", + "FrmSettings.Toolbar._CurrentButtons": "Current buttons:", + "FrmMain.MnuAbout": "Программа жөнүндө", + "FrmSettings._RemoveDefault": "Remove default", + "_._Description": "Баяндамасы", + "FrmMain.MnuPasteImage._Error": "Could not find image data in the Clipboard", + "FrmMain.MnuSettings": "Орнотуулар", + "FrmCropSettings._Title": "Crop settings", + "FrmSettings.Toolbar._ToolbarIconHeight": "Куралдар панелинин сөлөкөтүнүн өлчөмү", + "FrmSettings._SlideshowInterval._To": "To", + "FrmSettings.Layout._ToolbarPosition": "Куралдар панелинин абалы", + "FrmUpdate._StatusUpdated": "You are using the latest version!", + "FrmMain.MnuExit": "Чыгуу", + "_._Webview2._Outdated": "Your WebView2 Runtime is not supported. Please update to version {0} or later.", + "_._Yes": "Ооба", + "FrmMain.MnuRotateLeft": "Саат жебесине каршы буруу", + "FrmSettings._EnableStartupBoost": "Enable Startup Boost", + "_.ImageOrderBy._ExifRating": "EXIF: Rating", + "FrmMain.MnuZoomIn": "Жакындатуу", + "_.Metadata._ColorSpace": "Color space", + "FrmAbout._Version": "Нускасы:", + "FrmMain.MnuToggleTopMost._Enable": "Enabled window always on top", + "FrmSettings.Toolbar._AvailableButtons": "Available buttons:", + "FrmMain.MnuSave._Saving": "Saving image…", + "FrmQuickSetup._StandardUser": "Standard user", + "FrmMain.MnuSetLockScreen._Error": "Could not set the viewing image as lock screen image", + "FrmSettings.Nav._Image": "Сүрөт", + "FrmSettings._Theme._InstallTheme": "Install theme packs", + "FrmSettings._EnableMultiInstances": "Программанын бир нече нускаларына уруксат берүү", + "FrmMain.MnuCropTool": "Crop image", + "_._IgCommandExe._DefaultError._Heading": "Invalid commands", + "_._Refresh": "Жаңылоо", + "FrmMain.MnuLosslessCompression._Description": "This tool uses Magick.NET library for lossless compression, optimizing file size. Overwrites only if the compressed file is smaller than the original.", + "_._MoveDown": "Move down", + "FrmSettings._GetExtensionIconPacks": "Get extension icon packs…", + "FrmSettings._InAppMessageDuration": "In-app message duration (milliseconds)", + "FrmMain.MnuFrameless": "Терезенин аталышын жана алкагын жашыруу", + "_._Reset": "Кайра баштоо", + "FrmSettings._ConfigDir": "Configuration location", + "FrmQuickSetup._SettingsWillBeApplied": "Settings will be applied:", + "FrmSettings._UnmanagedSettingReminder": "This setting is not managed by ImageGlass. Don't forget to disable it before you remove or relocate the app because ImageGlass does not handle this automatically.", + "FrmMain.MnuClipboard": "Алмашуу буфери", + "FrmMain.MnuCustomZoom": "Колдонуучунун масштабы…", + "FrmSettings._DisplayLanguage": "Display language", + "FrmMain.MnuPrint._Error": "Could not print the viewing image", + "FrmSettings._ShouldPreserveModifiedDate": "Сүрөттү сактоодо өзгөртүлгөн күндү сактаңыз", + "FrmSettings._ShowSaveOverrideConfirmation": "Show confirmation dialog when overriding file", + "FrmColorPickerSettings.ChkShowHexA": "Use HEX format with alpha value", + "FrmMain.MnuFullScreen": "Full Screen", + "FrmSettings._StartupDir": "Startup location", + "FrmSettings._ShowCheckerboardOnlyImageRegion": "Show checkerboard only within the image region", + "FrmMain.MnuClearClipboard._Success": "Cleared clipboard.", + "FrmQuickSetup._Text": "ImageGlass Quick Setup", + "FrmMain.MnuLosslessCompression._Done": "Done lossless compression.\r\nThe new file size is {0}, saved {1}.", + "FrmMain.MnuLosslessCompression": "Magick.NET Lossless Compression", + "FrmResize.RadResizeByPercentage": "Percentage", + "FrmSettings._StartupBoost._Disabled": "Startup Boost is disabled", + "FrmMain.MnuToggleCheckerboard": "Фон (туташ / тунук)", + "FrmSettings._MinEmbeddedThumbnailSize._Height": "Бийиктиги", + "FrmSettings.Nav._General": "Негизги орнотуулар", + "FrmSettings._ImageLoading": "Сүрөт жүктөө параметрлери", + "FrmSettings._ShowSlideshowCountdown": "Слайд көрсөтүү режиминде тескери саноону көрсөтүү", + "FrmMain.MnuSave": "Сактоо", + "FrmMain.MnuMoveToRecycleBin": "Move to the Recycle Bin", + "FrmMain.MnuRefresh": "Жаңылоо", + "FrmToolNotFound.LblHeading": "'{0}' is not found!", + "FrmMain.MnuReportIssue": "Көйгөй жөнүндө кабарлоо…", + "FrmMain.MnuCopyImageData": "Сүрөттү көчүрүү", + "FrmMain.MnuCheckForUpdate._NewVersion": "Жаңы нускасы жеткиликтүү!", + "_._Empty": "(бош)", + "FrmSettings._Zooming": "Жакындатуу (алыстатуу)", + "FrmMain.MnuCutFile": "Cut file", + "FrmHotkeyPicker.LblHotkey": "Press hotkeys", + "FrmSettings.Layout._Gallery": "Gallery", + "FrmMain.MnuNewWindow": "Жаңы терезени ачыңыз", + "FrmMain.MnuMoveToRecycleBin._Description": "Do you want to move this file to the Recycle bin?", + "FrmSettings._DefaultPhotoViewer": "Default photo viewer", + "_.Metadata._ExifDateTimeOriginal": "EXIF: DateTimeOriginal", + "FrmMain.MnuRotateRight": "Сааттын жебеси боюнча буруу", + "FrmSettings._MinEmbeddedThumbnailSize": "Minimum size of the embedded thumbnail to be loaded", + "FrmMain.MnuSetDefaultPhotoViewer": "Set default photo viewer", + "FrmMain.MnuImageProperties": "Файлдын касиеттери", + "FrmSettings._EnableNavigationButtons": "Show navigation arrow buttons", + "_._Edit": "Оңдоо", + "FrmSettings._ImageBooster": "Image Booster", + "FrmSettings.Tools._IntegratedWith": "Integrated with {0}", + "_._Next": "Кененирээк", + "FrmExportFrames._OpenOutputFolder": "Open output folder", + "FrmMain.MnuOpenLocation": "Файл сактагыч жайгашкан жерди ачыңыз", + "FrmMain.MnuLockZoom": "Масштабда белгилөө", + "FrmSettings._StartupBoost._Description": "Preload and run ImageGlass in the background for a few seconds during Windows startup to accelerate the first launch.", + "FrmSettings._WindowBackdrop": "Window backdrop", + "FrmSettings._EnableRealTimeFileUpdate": "Monitor file changes in the viewing folder and update in realtime", + "_._NotSupported": "Unsupported format", + "FrmSettings._Theme._GetMoreThemes": "Get more theme packs…", + "FrmMain.MnuNewWindow._Error": "Cannot open new window because only one instance is allowed", + "FrmMain.MnuZoomOut": "Алыстатуу", + "FrmSettings.Toolbar._EditButton": "Edit toolbar button", + "FrmMain.MnuCustomZoom._Description": "Жаңы масштабдын маанисин киргизиңиз", + "FrmResize.RadResizeByPixels": "Pixels", + "FrmMain.MnuEdit": "Сүрөттү түзөтүү {0}…", + "FrmSettings.Layout._GalleryPosition": "Gallery position", + "FrmMain.MnuWindowFit": "Window Fit", + "FrmMain._OpenFileDialog": "Бардык колдоого алынган форматтар", + "FrmSettings._UseRandomIntervalForSlideshow": "Кокус аралыкты колдонуңуз", + "_.Position._Left": "Солго", + "FrmSettings._ShouldOpenLastSeenImage": "Open the last seen image", + "_.Position._Bottom": "Ылдыйга", + "FrmResize.ChkKeepRatio": "Keep ratio propotional", + "FrmMain.MnuGoTo": "Өтүү…", + "FrmSlideshow.MnuPauseResumeSlideshow": "Pause/resume slideshow", + "FrmSettings.Tools._Integrated": "Integrated", + "FrmSettings._Contributors": "Contributors", + "_.MouseWheelAction._Zoom": "Zoom in / out", + "_._CommandPreview": "Алдын ала көрүү", + "FrmSettings._DarkTheme": "Караңгы", + "_._Hotkeys": "Hotkeys", + "_.Metadata._ExifDateTime": "EXIF: DateTime", + "FrmSettings.Toolbar._Errors._ButtonIdRequired": "Button ID required.", + "FrmSettings._MinEmbeddedThumbnailSize._Width": "Туурасы", + "_._Executable": "Executable", + "_.ImageInterpolation._MultiSampleLinear": "Multi-sample linear", + "_._Separator": "Бөлүүчү", + "FrmQuickSetup._ProfessionalUser": "Professional user", + "FrmMain.MnuFlipVertical": "Тигинен чагылдыруу", + "FrmSlideshow._ResumeSlideshow": "Көрсөтүүнү улантуу.", + "FrmCropSettings.DefaultSelectionType._CustomArea": "Custom area…", + "FrmMain.MnuActualSize": "Масштабы 100%", + "FrmCrop.BtnSaveAs": "Кантип сактоо керек…", + "FrmSettings._InstallNewLanguagePack": "Install new language packs…", + "FrmSlideshow.MnuZoomModes": "Zoom modes", + "FrmMain.MnuTools": "Аспаптар", + "_.ImageInterpolation._Cubic": "Cubic", + "FrmUpdate._LatestVersion": "The latest version: {0}", + "FrmMain.MnuViewNext": "Кийинки сүрөт", + "_.MouseWheelEvent._AltAndScroll": "Hold Alt and scroll", + "FrmToolNotFound._Title": "Tool not found", + "FrmCrop.BtnCrop._Tooltip": "Crop the image only", + "FrmSettings.EditAppDialog._AddApp": "Add an app for editing", + "FrmMain.MnuPanning": "Панорамдоо (сүрөттү жылдыруу ылдамдыгы, ар бир баскычты басуудагы пикселдердин саны боюнча)", + "_._MoveUp": "Move up", + "FrmCropSettings.DefaultSelectionType._SelectAll": "Баары", + "_._Name": "Аталышы", + "FrmColorPickerSettings.ChkShowHslA": "Use HSL format with alpha value", + "FrmMain.MnuToggleImageAnimation": "Start / stop animating image", + "FrmSettings._DisableStartupBoost": "Disable Startup Boost", + "FrmMain.MnuCopyFile._Success": "Copied {0} file(s).", + "FrmMain.MnuSave._ConfirmDescription": "ImageGlass is not a professional photo editor, please be aware of losing the quality, metadata, layers,… when saving your image.", + "FrmToolNotFound.BtnSelectExecutable": "Тандоо…", + "FrmUpdate._StatusOutdated": "A new update is available!", + "_.ImageOrderBy._Random": "Туш келди", + "FrmResize.LblCurrentSize": "Current Size:", + "_._Apply": "Колдонуу", + "FrmAbout._Slogan": "Оңой, ар тараптуу сүрөттөрдү көрүү каражаты", + "FrmMain.MnuPanToTop": "Pan image to top", + "FrmSettings.Toolbar._AddNewButton": "Add a custom toolbar button", + "FrmCrop.LblSize": "Size:", + "FrmSettings._ImageInterpolation._ScaleDown": "When zoom < 100%", + "_._CreatingFileError": "Could not create temporary image file", + "FrmMain.MnuGoTo._Description": "Enter the image index to view, and then press ENTER", + "FrmSettings.Toolbar._EnableCenterToolbar": "Use center alignment for toolbar", + "FrmMain.MnuResizeTool": "Resize image", + "FrmSettings.Layout._Toolbar": "Аспаптар панели", + "FrmMain.MnuHelp": "Жардам", + "_.ImageOrderBy._FileSize": "File size", + "FrmSettings._Theme._OpenThemeFolder": "Тема папкасын ачыңыз", + "FrmMain.MnuNavigation": "Багыттоо баскычтары", + "_._Save": "Сактоо", + "FrmQuickSetup._SettingProfileDescription": "To modify these settings, simply access app settings.", + "_._UserAction._MenuNotFound": "Cannot find menu '{0}' to invoke the action", + "FrmMain.MnuPanToLeftSide": "Pan image to left edge", + "FrmUpdate._CurrentVersion": "Current version: {0}", + "FrmCrop.BtnSettings._Tooltip": "Open Crop tool settings", + "_.ColorProfileOption._Custom": "Түзөтүү…", + "FrmSettings._UseEmbeddedThumbnailOtherFormats": "Load only the embedded thumbnail for other formats", + "FrmMain.MnuGoToFirst": "Go to first image", + "FrmSettings._ExportLanguagePack": "Export language pack…", + "FrmSettings.Nav._Mouse": "Mouse", + "_.ImageOrderBy._DateCreated": "Date created", + "FrmSettings._EnableFullscreenSlideshow": "Start slideshow in Full Screen mode", + "FrmAbout._Homepage": "Homepage:", + "FrmSettings._GalleryCacheSizeInMb": "Maximum gallery cache size (in megabytes)", + "FrmMain.MnuCopyImageData._Success": "Copied the current image data.", + "FrmSettings._EnableLoopBackNavigation": "Loop back to the first image when reaching the end of the image list", + "_.MouseWheelEvent._Scroll": "Scroll", + "FrmCrop.BtnSave._Tooltip": "Сүрөттү сактоо", + "FrmMain.MnuSlideshow": "Слайд көрсөтүү", + "FrmMain.MnuShare": "Бөлүшүү…", + "FrmSettings._SlideshowNotification": "Slideshow notification", + "FrmMain.MnuViewChannels": "Каналдарды көрүү", + "FrmSettings._Refresh": "Жаңылоо", + "_._UserAction._MethodNotFound": "Cannot find method '{0}' to invoke the action", + "FrmMain.MnuCopyFile": "Copy file", + "_._CreatingFile": "Creating a temporary image file…", + "FrmMain.MnuToggleTopMost": "Бардык терезелердин үстүнө орнотуңуз", + "FrmMain.MnuLosslessCompression._Confirm": "Are you sure you want to proceed?", + "FrmMain.MnuImage": "Сүрөт", + "FrmSettings._StartupBoost._Enabled": "Startup Boost is enabled", + "FrmQuickSetup._SetDefaultViewer": "Do you want to set ImageGlass as the default photo viewer?", + "FrmMain.MnuScaleToWidth": "Туурасы боюнча масштабы", + "_._FileExtension": "Файлды кеңейтүүсү", + "FrmUpdate._PublishedDate": "Published date: {0}", + "_._DoNotShowThisMessageAgain": "Do not show this message again", + "_.ImageInterpolation._NearestNeighbor": "Nearest neighbor", + "FrmCrop.LblLocation": "Location:", + "_._Download": "Download", + "_.Metadata._ColorProfile": "Түс профили", + "FrmSettings._CenterWindowFit": "Automatically center the window in Window Fit mode", + "FrmSettings._ImageLoadingOrder": "Файлды окуу тартиби", + "FrmSettings._GalleryColumns": "Number of thumbnail columns in vertical gallery layout", + "_._Quit": "Quit", + "_._Add": "Кошуу", + "FrmMain.MnuChangeBackgroundColor": "Change background color…", + "FrmMain.MnuToggleToolbar": "Аспаптар панели", + "FrmAbout._Contact": "Байланышуу", + "FrmSettings.Toolbar._AddCustomButton": "Add a custom button…", + "FrmCrop.BtnQuickSelect._Tooltip": "Quick select…", + "FrmMain.MnuCutFile._Success": "Cut {0} file(s).", + "FrmSettings._ZoomSpeed": "Zoom speed", + "FrmMain.MnuToggleTopMost._Disable": "Disabled window always on top", + "FrmSettings._ShouldUseExplorerSortOrder": "Use Explorer sort order if possible", + "_.ImageInterpolation._Antisotropic": "Antisotropic", + "FrmMain._ReachedFirstImage": "Биринчи сүрөткө өтүңүз", + "_._UnhandledException": "Unhandled exception", + "FrmResize.LblNewSize": "New Size:", + "FrmMain._ClipboardImage": "Clipboard image", + "FrmMain.MnuExportFrames": "Export image frames…", + "FrmMain.MnuFile": "Файл", + "_._Close": "Жабык", + "FrmMain.MnuMain": "Башкы меню", + "_._ResetToDefault": "Орнотууларды кайтаруу", + "FrmSettings.Nav._Gallery": "Gallery", + "FrmMain.MnuSetDefaultPhotoViewer._Success": "You have successfully set ImageGlass as default photo viewer.", + "FrmSettings._HideGalleryInFullscreen": "Hide gallery in Full Screen mode", + "FrmSettings._AvailableImageInfoTags": "Available tags:", + "FrmExportFrames._Exporting": "Exporting {0}/{1} frames \r\n{2}…", + "_._Argument": "Argument", + "FrmSettings._ImageEditQuality": "Сүрөттүн сапаты", + "_._ID": "ID", + "FrmSettings._UserConfigFile": "User settings file (igconfig.json)", + "FrmMain.MnuLoadingOrders": "Loading orders", + "FrmSettings._OpenSaveAsDialogInTheCurrentImageDir": "Open the Save As dialog in the current image directory", + "_.MouseWheelEvent._ShiftAndScroll": "Hold Shift and scroll", + "FrmSettings._UseSmoothZooming": "Use smooth zooming", + "FrmSettings._Theme": "Тема", + "FrmSettings._ImageBoosterCacheMaxDimension": "Maximum image dimension to be cached (in pixels)", + "FrmMain.MnuScaleToHeight": "Бийиктиги боюнча масштабы", + "_.Metadata._FileLastWriteTime": "Date modified", + "FrmSettings._Author": "Автору", + "FrmSettings._Others": "Башка орнотуулар", + "_.MouseWheelAction._PanVertically": "Pan up / down", + "FrmSettings._MouseWheelAction": "Mouse wheel action", + "FrmSettings.Nav._Tools": "Аспаптар", + "FrmMain.MnuSetDesktopBackground._Error": "Could not set the viewing image as desktop background", + "FrmSettings.Toolbar._Errors._ButtonExecutableRequired": "Button executable required.", + "_.ImageOrderBy._DateAccessed": "Date accessed", + "FrmSettings._ThumbnailSize": "Thumbnail size (in pixels)", + "FrmSettings._FileFormats": "File formats", + "FrmMain.MnuReloadImageList": "Сүрөттөр тизмесин кайра жүктөө", + "FrmSettings._UseWebview2ForSvg": "Use Webview2 for viewing SVG format", + "FrmCrop.BtnCopy": "Көчүрүү", + "FrmSettings._CurrentMonitorProfile._Description": "ImageGlass does not auto-update the color when moving its window between monitors", + "FrmMain.PicMain._ErrorText": "Could not open this image", + "FrmSettings.Tools._AddNewTool": "Add an external tool", + "FrmMain.MnuRename": "Сүрөттүн атын өзгөртүү…", + "FrmMain.MnuViewLastFrame": "View last frame", + "_._Webview2._NotFound": "Please install WebView2 Runtime to access full features of ImageGlass.", + "FrmMain.MnuGetMoreTools": "Get more tools…", + "FrmSettings.Nav._Appearance": "Appearance", + "FrmSettings._SlideshowInterval": "Сүрөттөрдү көрсөтүү убактысы:", + "_.ImageInterpolation._HighQualityBicubic": "High quality bicubic", + "FrmColorPickerSettings.ChkShowHsvA": "Use HSV format with alpha value", + "FrmSettings.Tools._EditTool": "Edit external tool", + "_._Error": "Error", + "FrmSettings._ImageBoosterCacheMaxFileSizeInMb": "Maximum image file size to be cached (in megabytes)", + "_._UnhandledException._Description": "Unhandled exception has occurred. If you click Continue, the application will ignore this error and attempt to continue. If you click Quit, the application will close immediately.", + "_.Metadata._FileSize": "File size", + "FrmSettings.Toolbar._ButtonJson": "Button JSON", + "FrmQuickSetup._SetDefaultViewer._Description": "You can reset it in the app settings > File type associations tab.", + "FrmSettings.Nav._Edit": "Оңдоо", + "FrmMain.MnuToggleGallery": "Gallery panel", + "_._IgCommandExe._DefaultError._Description": "Make sure you pass the correct commands!\r\nThis executable file contains command-line functions for ImageGlass software.\r\n\r\nTo explore all command lines, please visit:\r\n{0}", + "FrmMain.MnuLosslessCompression._Compressing": "Performing lossless compression…", + "FrmSettings._ShouldGroupImagesByDirectory": "Сүрөттөрдү папка боюнча топтоо", + "FrmMain.MnuPanToRightSide": "Pan image to right edge", + "_.Metadata._ExifRatingPercent": "Rating", + "FrmSettings._PanSpeed": "Panning speed", + "_._CheckForUpdate": "Жаңыртууларды текшериңиз…", + "FrmSettings.Layout._ToolbarContext": "Contextual toolbar", + "_.ImageInfo._FrameCount": "{0} frame(s)", + "FrmMain.MnuLayout": "Башкаруу элементтери", + "_._Website": "Сайт", + "FrmMain.MnuPasteImage": "Paste image", + "FrmSettings._ShowGalleryScrollbars": "Show gallery scrollbars" + } +} \ No newline at end of file diff --git a/Setup/Assets/Language/Lithuanian.iglang.json b/Setup/Assets/Language/Lithuanian.iglang.json new file mode 100644 index 000000000..fb6581b3e --- /dev/null +++ b/Setup/Assets/Language/Lithuanian.iglang.json @@ -0,0 +1,504 @@ +{ + "_Metadata": { + "Code": "lt-LT", + "EnglishName": "Lithuanian", + "LocalName": "Lietuvių", + "Author": "Džiugas Januševičius", + "MinVersion": "9.1" + }, + "Items": { + "FrmCrop.SelectionAspectRatio._Original": "Originalus", + "FrmMain.MnuShare._Error": "Nepavyko atidaryti „Bendrinti“ lango.", + "_.Metadata._FileLastAccessTime": "Pasiekimo data", + "FrmAbout._License": "Programinės įrangos licencija", + "FrmSettings.Toolbar._Errors._ButtonIdDuplicated": "Mygtukas su ID – „{0}“, jau buvo nustatytas. Prašome pasirinkti kitokį ir unikalų ID, savo mygtukui, norint išvengti konfliktų (Programiniai).", + "FrmMain.MnuSave._Confirm": "Ar jūs esate tikri/-a, kad norite perrašyti šį paveikslą/nuotrauką/vaizdą?", + "FrmSettings._OpenDefaultAppsSetting": "Atidaryti numatytų programų nustatymų puslapį", + "FrmMain.MnuCopyPath": "Kopijuoti paveikslo/nuotraukos/vaizdo vietovę", + "FrmCropSettings.DefaultSelectionType._SelectNone": "Nieko nepasirinkti", + "_.MouseWheelAction._PanHorizontally": "Pajundinti į kairę / dešinę", + "FrmMain.MnuPrint": "Spausdinti…", + "FrmSettings.Toolbar._ToolbarButtons": "Įrankių juostos mygtukai", + "FrmResize.LblResample": "(Su-/De-)skaitmeninizuoti:", + "_.ImageOrderBy._Extension": "Papildinys/Plėtinys", + "FrmSettings.Nav._Viewer": "Žiūrovas", + "FrmSettings.EditAppDialog._EditApp": "Redaguoti programėlę", + "FrmCrop.BtnReset._Tooltip": "Atstatyti pasirinkimą", + "FrmMain.MnuRename._Description": "Įveskite naują failo pavadinimą:", + "_._No": "No", + "FrmSlideshow.MnuToggleCountdown": "Rodyti skaidrių demonstravimo laikmatį", + "FrmSettings._OpenStartupAppsSetting": "Atidaryti paleidžiamųjų programų nustatymų puslapį", + "FrmMain.MnuViewPreviousFrame": "Rodyti praeitą kadrą", + "_.ImageOrderBy._DateModified": "Modifikavimo data", + "FrmMain.MnuViewNextFrame": "Rodyti kitą kadrą", + "FrmMain.MnuUnload": "Iškrauti paveikslą/nuotrauką/vaizdą", + "FrmSettings.Toolbar._HideToolbarInFullscreen": "Slėpti įrankių juostą, kai esate pilno ekrano režime", + "_.ImageOrderType._Desc": "Mažėjančia tvarka", + "_._Update": "Atnaujinti", + "FrmSettings._EnableImageAsyncLoading": "Įgalinti paveikslo/nuotraukos/vaizdo asinchroniška krovimą", + "FrmSettings._DefaultPhotoViewer._Description": "Registruoti palaikomus „ImageGlass“ formatus su „Windows“. Jums galimai reikės atidaryti numatytų programų nustatymų puslapį savo operacinėje sistemoje ir rankiniu būdu pasirinkti „ImageGlass“ iš to sąrašo, kad šis veiksmas būtų atliktas.", + "_.MouseWheelAction._BrowseImages": "Rodyti kitą / praeitą paveikslą/nuotrauką/vaizdą", + "FrmSettings._EditApps": "Paveikslų/Nuotraukų/Vaizdų redagavimo/retušavimo programos", + "FrmColorPickerSettings.ChkShowCIELabA": "Naudoti „CIELAB“ formatą su „Alpha“ skaitmenimis", + "_._GetHelp": "Pagalba", + "FrmQuickSetup._SkipQuickSetup": "Praleisti šitą, ir paleisti „ImageGlass“", + "FrmColorPickerSettings._Title": "Spalvų parinkėjo nustatymai", + "_._Copy": "Kopijuoti", + "FrmSettings._ImageBoosterCacheCount": "Paveikslų/Nuotraukų/Vaizdų skaičius, kurie yra „Image Booster“ talpykloje (vien pusėj)", + "FrmMain.MnuPanToBottom": "Pakreipti paveikslą/nuotrauką/vaizdą žemyn", + "FrmMain.MnuZoom": "Didinimas", + "FrmCropSettings.ChkCloseToolAfterSaving": "Uždaryti apkarpymo įrankį, po išsaugojimo", + "FrmSettings._ShowWelcomeImage": "Rodyti „Sveiki!“ ekraną, pajungime", + "FrmSettings._ColorProfile": "Spalvų profilis", + "FrmSettings._Theme._UninstallTheme": "Išdiegti temų paketą", + "FrmMain._OpenWith": "Atidaryti su {0}", + "FrmMain.MnuRemoveDefaultPhotoViewer": "Pašalinti numatytąjį paveikslų/nuotraukų/vaizdų žiūrovą", + "_.AfterEditAppAction._Nothing": "Niekas", + "FrmCrop.BtnSave": "Išsaugoti", + "FrmMain.MnuScaleToFit": "Keisti mastelį, kad tilptų", + "FrmToolNotFound.LblDownloadToolText": "Galite atsisiųsti daugiau įrankių, kurie skirti „ImageGlass“ šiuo adresu:", + "_._LearnMore": "Sužinokite daugiau…", + "FrmCrop.LblAspectRatio": "Proporcijos (santykis):", + "FrmExportFrames._FileNotExist": "Paveikslo/Nuotraukos/Vaizdo failas neegzistuoja", + "FrmSettings._LightTheme": "Šviesus", + "FrmSettings.Nav._Slideshow": "Skaidrių demonstracija", + "_._Continue": "Tęsti", + "_._AddHotkey": "Pridėti spartųjį klavišą…", + "FrmMain.MnuSetDesktopBackground": "Nustatyti kaip darbalaukio fona", + "FrmMain.MnuReload": "Perleisti iš naujo paveikslą/nuotrauką/vaizdą", + "FrmSlideshow.MnuExitSlideshow": "Išeiti iš skaidrių demonstravimo", + "FrmMain.MnuAutoZoom": "Automatiškai didinti", + "FrmSettings._ShowImagePreview": "Rodyti paveikslo/nuotraukos/vaizdo peržiūrą, kol jis kraunasi", + "FrmCrop.BtnCopy._Tooltip": "Kopijuoti pasirinkimą į iškarpinę", + "FrmSettings.Nav._Toolbar": "Įrankių juosta", + "FrmMain.MnuSave._Error": "Nebuvo galima išsaugoti paveikslo/nuotraukos/vaizdo", + "FrmSettings._AfterEditingAction": "Po atidarant redagavimo programą", + "FrmSettings._ShouldUseColorProfileForAll": "Pritaikyti irgi, nuotraukom kuriuos neturi įrašytos spalvų profilio", + "FrmCropSettings.DefaultSelectionType._UseTheLastSelection": "Naudoti paskutinį pasirinkimą", + "FrmSettings._SlideshowInterval._From": "Nuo", + "FrmSettings._ImageInterpolation": "Nuotraukos/Paveikslo/Vaizdo interpoliacija", + "FrmQuickSetup._StepInfo": "Žingsnis {0}", + "FrmMain.MnuColorPicker": "Spalvų rinkiklis", + "FrmCrop.SelectionAspectRatio._FreeRatio": "Laisvų proporcijų", + "FrmSettings._ResetSettings": "Atstatyti nustatymus", + "FrmSettings._Startup": "Paleistis", + "_.BackdropStyle._None": "Nėra", + "FrmSettings._LoadDefaultZoomLevels": "Pakrauti numatytus priartinimo lygius", + "FrmColorPicker.BtnSettings._Tooltip": "Atidaryti spalvų parinkėjo nustatymus…", + "FrmSettings._UseThemeForDarkMode": "Naudoti šią temą, tamsiam režimui", + "FrmSettings._ShowDeleteConfirmation": "Rodyti patvirtinimo langą, kai bandote ištrinti failą", + "FrmSettings._ShowAppIcon": "Rodyti programos piktogramą lango juostoje", + "_._InvalidAction": "Negalimas veiksmas", + "FrmQuickSetup._SelectProfile": "Pasirinkite profilį", + "_.Metadata._FileCreationTime": "Sukūrimo data", + "FrmSettings._SlideshowImagesToNotifySound": "Nuotraukų/Paveikslų/Vaizdų skaičius, reikalingas norint gauti pranešimo garsą", + "FrmSettings._BackgroundColor": "Žiūrovo fono spalva", + "FrmSettings._RealTimeFileUpdate": "Tikro laiko failų atnaujinimai", + "_.ColorProfileOption._CurrentMonitorProfile": "Dabartinis monitoriaus profilis", + "FrmSettings._EnableCutMultipleFiles": "Įgalinti daugumos failų iškarpimų, vienu metu", + "FrmSettings._AutoUpdate": "Savaime/Automatiškai tikrinti, ar yra naujinių", + "FrmCropSettings.LblDefaultSelection": "Numatyti pasirinkimo nustatymai", + "FrmSettings._UseThemeForLightMode": "Naudoti šią temą, šviesiam režimui", + "FrmSettings._ZoomLevels": "Priartinimo/Nutolinimo lygiai", + "FrmMain.MnuSetLockScreen._Success": "Užrakinimo ekrano paveikslas/nuotrauka/vaizdas yra atnaujintas", + "FrmSettings._ShowGalleryFileName": "Rodyti miniatiūros failo pavadinimą", + "FrmSettings.Layout._Order": "Rikiavimas", + "FrmCropSettings.ChkAutoCenterSelection": "Automatiškai centruoti pasirinkimą", + "FrmSettings.Nav._FileTypeAssociations": "Failo tipo/-ų asociacija/-os", + "_._Back": "Atgal", + "FrmMain.MnuSetDesktopBackground._Success": "Darbalaukio fonas yra atnaujintas", + "FrmSettings._ShouldAutoOpenNewAddedImage": "Atidaryti naujai pridėtą paveikslą/nuotrauką/vaizdą automatiškai", + "FrmCrop.SelectionAspectRatio._Custom": "Pasirinktinis…", + "FrmMain.MnuCopyPath._Success": "Nukopijuotos paveikslo/nuotraukos/vaizdo vietovės katalogas.", + "FrmSettings._StartupBoost._Error": "Nebuvo galima pakeisti paleidimo spartinimo nustatymo", + "FrmToolNotFound.LblDescription": "„ImageGlass“ nepavyko rasti kelio (vietovės) į „{0}“ paleidžiamąjį. Norint išspręsti šią problemą, prašome atnaujinti kelio (vietovės) į „{0}“ adresą.", + "FrmMain.MnuClearClipboard": "Ištuštinti iškarpinę", + "FrmSettings._ColorManagement": "Spalvų tvarkymas", + "FrmMain._ReachedLastLast": "Pasiekta paskutinė/-is paveikslas/nuotrauką/vaizdas", + "FrmMain.MnuPanUp": "Pakreipti paveikslą/nuotrauką/vaizdą į viršų", + "FrmMain.MnuRemoveDefaultPhotoViewer._Success": "„ImageGlass“ nebėra numatytas paveikslų/nuotraukų/vaizdų žiūrovas.", + "FrmSettings._GetMoreLanguagePacks": "Gauti daugiau kalbos paketų…", + "FrmAbout._Privacy": "Privatumo politika", + "FrmSettings._EnableRecursiveLoading": "Krauti paveikslus/nuotraukas/vaizdus po-aplankuose", + "_._UserAction._MethodArgumentNotSupported": "Argumento tipo metodas „{0}“ nėra palaikomas", + "FrmSettings._FileExtensionIcons._Description": "Norint redaguoti failų plėtinių piktogramas, atsisiųskite piktogramų paketą, įkelkite visus „*.ICO“ failus į papildinių-piktogramų aplankalą ir spauskite – „{0}“. Šis nustatys „ImageGlass“ kaip numatytąjį paveikslų/nuotraukų/vaizdų žiūrovą.", + "_.ImageOrderType._Asc": "Didėjančia tvarka", + "FrmExportFrames._Title": "Eksportuoti paveikslų/nuotraukų/vaizdų kadrus", + "_._Install": "Įdiegti…", + "FrmMain.MnuFlipHorizontal": "Pasukti Horizontaliai", + "FrmSettings._OpenExtensionIconFolder": "Atidaryti plėtinių piktogramų aplankalą", + "FrmAbout._Collaborator": "Bendradarbiautojai:", + "FrmQuickSetup._ConfirmCloseProcess": "Prieš įgalinant naujus nustatymus, būtina uždaryti visus „ImageGlass“ užduotis (procesus). Ar esate pasiruošęs tęsti?", + "FrmExportFrames._ExportDone": "Eksportuoti {0} kadrai sėkmingai į \n{1}", + "FrmCrop.BtnSaveAs._Tooltip": "Išsaugoti kaip kopiją…", + "FrmMain.MnuOpenFile": "Atidaryti Failą…", + "FrmColorPickerSettings.ChkShowRgbA": "Naudoti „RGB“ formatą su „Alpha“ skaitmenimis", + "_.ImageInfo._ListCount": "{0} failas/-ų", + "FrmMain.MnuGoToLast": "Eiti į paskutinį/-ąją paveikslą/nuotrauką/vaizdą", + "FrmSettings._EditApps._AppName": "Programos pavadinimas", + "FrmSettings._SlideshowBackgroundColor": "Skaidrių pristatymo fono spalva", + "FrmAbout._Email": "El. paštas:", + "_.MouseWheelAction._DoNothing": "Daryti nieko", + "FrmMain.MnuSaveAs": "Išsaugoti kaip…", + "FrmMain._Loading": "Kraunama…", + "_._Browse": "Naršyti…", + "FrmMain.MnuSetDefaultPhotoViewer._Error": "Nepavyko nustatyti „ImageGlass“ kaip numatytąjį paveikslų/nuotraukų/vaizdų žiūrovą.", + "FrmSettings.Nav._Language": "Kalba", + "FrmQuickSetup._SeeWhatNew": "Pamatyti kas naujo šioje versijoje…", + "FrmSettings._ImageInterpolation._ScaleUp": "Kai priartinimas > 100%", + "FrmSettings.Layout._ToolbarContextPosition": "Kontekstinės įrankių juostos poziciją", + "FrmMain.MnuDeleteFromHardDisk": "Ištrinti negrįžtamai", + "FrmSettings._EmbeddedThumbnail": "Įterpta miniatiūra", + "FrmMain.MnuDeleteFromHardDisk._Description": "Ar tikrai norite visam laikui ištrinti šį failą?", + "FrmMain.MnuScaleToFill": "Keisti mastelį, kad užpildytų", + "FrmCrop.BtnCrop": "Apkarpyti", + "_.AfterEditAppAction._Minimize": "Minimizuoti", + "FrmMain.MnuInvertColors": "Apversti spalvas", + "FrmSettings._StartupBoost": "Paleidimo spartinimas", + "FrmMain.MnuViewFirstFrame": "Rodyti pirmąjį kadrą", + "_.MouseWheelEvent._CtrlAndScroll": "Laikyti Vald. ir slinkti", + "FrmSettings._HideMainWindowInSlideshow": "Automatiškai slėpti pagrindinį langą", + "_.Metadata._FrameCount": "Kadrai", + "FrmSettings._EnableCopyMultipleFiles": "Įgalinti daugumos failų kopijavimų, vienu metu", + "FrmMain.MnuFrameless._EnableDescription": "Laikyti Vald2 mygtuką, kad judintumėte langą.", + "_.ImageOrderBy._ExifDateTaken": "„EXIF“: Data paimta", + "FrmAbout._Credits": "Kreditai", + "FrmSettings._AddNewFileExtension": "Pridėti naują failo plėtinį", + "FrmMain.MnuQuickSetup": "Atidaryti „ImageGlass“ greitąją sąranką", + "FrmMain.MnuSave._Success": "Paveikslas/nuotrauka/vaizdas yra išsaugotas", + "FrmMain.MnuPanLeft": "Pakreipti paveikslą/nuotrauką/vaizdą į kairę", + "FrmUpdate._StatusChecking": "Tikrinama ar yra atnaujinimų…", + "FrmSettings.Nav._Layout": "Išvaizda", + "FrmMain.MnuOpenWith": "Atidaryti naudojant…", + "FrmAbout._Thanks": "Ypatinga padėka šiems žmonėms:", + "_._Warning": "Įspėjimas", + "FrmSettings.Nav._Keyboard": "Klaviatūra", + "FrmSlideshow._PauseSlideshow": "Skaidrių demonstravimas yra pristabdytas.", + "_._Add+": "Pridėti…", + "_._Email": "El. paštas", + "FrmMain.MnuPanDown": "Pakreipti paveikslą/nuotrauką/vaizdą į apačią", + "_._Cancel": "Atšaukti", + "_._OK": "Gerai", + "FrmMain.MnuPanRight": "Pakreipti paveikslą/nuotrauką/vaizdą į dešinę", + "_.Position._Right": "Dešinė", + "_._Icon": "Piktograma", + "FrmSettings._ShouldLoadHiddenImages": "Rodyti paslėptus paveikslus", + "_._InvalidAction._Transformation": "„ImageGlass“ nepalaiko sukimų, apvertimų šiam/-ai vaizdui/nuotraukai/paveikslui.", + "FrmSettings._MakeDefault": "Padaryti numatytuoju", + "FrmMain.MnuCopyImageData._Copying": "Kopijuojama paveikslo/nuotraukos/vaizdo duomenys. Tai gali užtrukti…", + "FrmSettings._UseEmbeddedThumbnailRawFormats": "Krauti tik įterptas miniatiūras „RAW“ formatams", + "_.ImageInterpolation._Linear": "Tiesinė interpeliacija", + "FrmSettings._ImageInfoTags": "Paveikslo/Nuotraukos/Vaizdo informacijos žymės", + "FrmSettings._FileExtensionIcons": "Failo plėtinio piktogramos", + "FrmMain.MnuEdit._AppNotFound": "Nebuvo galima surasti bendradarbiaujančios programos redagavimui/retušavimui. Jūs galite priskirti programą redaguoti/retušuoti šį formatą „ImageGlass“ nustatymuose > Redaguoti.", + "_.ColorProfileOption._None": "Nėra", + "FrmSettings._TotalSupportedFormats": "Iš viso palaikomi formatai: {0}", + "FrmSettings._Clipboard": "Iškarpinė", + "_._UserAction._Win32ExeError": "Negalima įvykdyti šios komandos – „{0}“. Patikrinkite, kad pavadinimas yra teisingas.", + "FrmCropSettings.DefaultSelectionType._SelectX": "Pasirinkti {0}", + "_.AfterEditAppAction._Close": "Uždaryti", + "FrmAbout._LogoDesigner": "Logotipo kūrėjas:", + "_.ImageOrderBy._Name": "Pavadinimas (default)", + "FrmMain.MnuRemoveDefaultPhotoViewer._Error": "Nepavyko pašalinti „ImageGlass“ kaip numatytąjį paveikslų/nuotraukų/vaizdų žiūrovą.", + "FrmExportFrames._FolderPickerTitle": "Pasirinkti išvesties aplankalą, kurį naudosite eksportuoti nuotraukų/paveikslų/vaizdų kadrus", + "FrmAbout._Donate": "Paremti", + "FrmMain.MnuFrameNav": "Kadro navigacija", + "FrmMain.MnuSetLockScreen": "Nustatyti kaip „Windows“ įjungimo paveikslą/nuotrauką/vaizdą", + "_._Delete": "Ištrinti", + "FrmMain.MnuViewPrevious": "Rodyti praeitą paveikslą/nuotrauką/vaizdą", + "_.Position._Top": "Viršus", + "FrmSettings.Toolbar._CurrentButtons": "Dabartiniai mygtukai:", + "FrmMain.MnuAbout": "Apie", + "FrmSettings._RemoveDefault": "Pašalinti numatytąjį", + "_._Description": "Apibūdinimas", + "FrmMain.MnuPasteImage._Error": "Nebuvo galima rasti paveikslo/nuotraukos/vaizdo duomenų iškarpinėje", + "FrmMain.MnuSettings": "Nustatymai", + "FrmCropSettings._Title": "Apkarpymo nustatymai", + "FrmSettings.Toolbar._ToolbarIconHeight": "Įrankių juostos piktogramos dydis", + "FrmSettings._SlideshowInterval._To": "Iki", + "FrmSettings.Layout._ToolbarPosition": "Įrankių juostos vietovė", + "FrmUpdate._StatusUpdated": "Jūs naudojate naujausią versiją!", + "FrmMain.MnuExit": "Išeiti", + "_._Webview2._Outdated": "Jūsų „WebView2“ vykdantysis yra nepalaikomas. Prašome atsinaujinti į versiją – {0} ar naujesnę.", + "_._Yes": "Taip", + "FrmMain.MnuRotateLeft": "Pasukti kairėn", + "FrmSettings._EnableStartupBoost": "Įgalinti paleidimo spartinimą", + "_.ImageOrderBy._ExifRating": "„EXIF“: Reitingas", + "FrmMain.MnuZoomIn": "Priartinti", + "_.Metadata._ColorSpace": "Spalvų laukas", + "FrmAbout._Version": "Versija:", + "FrmMain.MnuToggleTopMost._Enable": "Įgalinti, kad langas visada būti ant viršaus", + "FrmSettings.Toolbar._AvailableButtons": "Galimi mygtukai:", + "FrmMain.MnuSave._Saving": "Išsaugomas paveikslas/nuotrauka/vaizdas…", + "FrmQuickSetup._StandardUser": "Paprastas vartotojas", + "FrmMain.MnuSetLockScreen._Error": "Nebuvo galima nustatyti žiūrimo paveikslo/nuotraukos/vaizdo, kaip užrakinimo ekrano fono", + "FrmSettings.Nav._Image": "Paveikslas/Nuotrauka/Vaizdas", + "FrmSettings._Theme._InstallTheme": "Įdiegti temų paketus", + "FrmSettings._EnableMultiInstances": "Leisti daugumai programos procesų", + "FrmMain.MnuCropTool": "Apkirpti nuotrauką/paveikslą/vaizdą", + "_._IgCommandExe._DefaultError._Heading": "Negalimos komandos", + "_._Refresh": "Įkelti iš naujo", + "FrmMain.MnuLosslessCompression._Description": "Šis įrankis naudoja „Magick.NET“ biblioteką, skirtą nenuostoli̇̀ngam glaũdinimui, optimizuojant failo dydį. Perrašo tik tada, jei suglaudintas failas yra mažesnis negu originalas.", + "_._MoveDown": "Perkelti žemyn", + "FrmSettings._GetExtensionIconPacks": "Gauti plėtinių piktogramų paketų…", + "FrmSettings._InAppMessageDuration": "Programos pranešimų laikotarpis (milisekundėmis)", + "FrmMain.MnuFrameless": "Be rėmų „Frameless“", + "_._Reset": "Atstatyti", + "FrmSettings._ConfigDir": "Konfigūracijos vietovė", + "FrmQuickSetup._SettingsWillBeApplied": "Nustatymai bus pritaikyti:", + "FrmSettings._UnmanagedSettingReminder": "Šis nustatymas nėra valdomas „ImageGlass“. Nepamirškite išjungti šį prieš tai, kai Jūs pašalinsite ar perkelsite programą/-ėlę, nes „ImageGlass“ šios funkcijos neatlieka automatiškai.", + "FrmMain.MnuClipboard": "Iškarpinė", + "FrmMain.MnuCustomZoom": "Redaguoti mastelį…", + "FrmSettings._DisplayLanguage": "Rodoma kalba", + "FrmMain.MnuPrint._Error": "Nepavyko išspausdinti rodomo/-s paveikslo/nuotraukos/vaizdo", + "FrmSettings._ShouldPreserveModifiedDate": "Išlaikyti nuotraukos modifikacijos data, po išsaugojimo", + "FrmSettings._ShowSaveOverrideConfirmation": "Rodyti patvirtinimo langą, kai bandote perrašyti failą", + "FrmColorPickerSettings.ChkShowHexA": "Naudoti „HEX“ formatą su „Alpha“ skaitmenimis", + "FrmMain.MnuFullScreen": "Visas ekranas", + "FrmSettings._StartupDir": "Paleidimo vietovė", + "FrmSettings._ShowCheckerboardOnlyImageRegion": "Rodyti šaškių lentos, tik paveikslo/nuotraukos/vaizdo regiono viduje", + "FrmMain.MnuClearClipboard._Success": "Ištuštinta iškarpinė.", + "FrmQuickSetup._Text": "„ImageGlass“ greitoji sąranka", + "FrmMain.MnuLosslessCompression._Done": "Baigtas nenuostoli̇̀ngasis glaũdinimas.\r\nNaujas failo dydis yra – {0}, išsaugota/-s – {1}.", + "FrmMain.MnuLosslessCompression": "„Magick.NET“ nenuostoli̇̀ngasis glaũdinimas", + "FrmResize.RadResizeByPercentage": "Procentas/-ai", + "FrmSettings._StartupBoost._Disabled": "Paleidimo spartinimas yra išjungtas", + "FrmMain.MnuToggleCheckerboard": "Šaškinis fonas", + "FrmSettings._MinEmbeddedThumbnailSize._Height": "Aukštis", + "FrmSettings.Nav._General": "Bendra", + "FrmSettings._ImageLoading": "Paveikslas/Nuotrauka/Vaizdas kraunasi", + "FrmSettings._ShowSlideshowCountdown": "Rodyti skaidrių demonstravimo laikmatį", + "FrmMain.MnuSave": "Išsaugoti", + "FrmMain.MnuMoveToRecycleBin": "Perkelti į šiukšlinę", + "FrmMain.MnuRefresh": "Įkelti iš naujo", + "FrmToolNotFound.LblHeading": "„{0}“ nėra rastas!", + "FrmMain.MnuReportIssue": "Pranešti apie problemą…", + "FrmMain.MnuCopyImageData": "Kopijuoti Paveikslėlio/Nuotraukos/Vaizdo informacija", + "FrmMain.MnuCheckForUpdate._NewVersion": "Naują versiją aptikta!", + "_._Empty": "(tuščia)", + "FrmSettings._Zooming": "Priartinimas/Nutolinimas", + "FrmMain.MnuCutFile": "Iškirpti failą", + "FrmHotkeyPicker.LblHotkey": "Spausti spartieji klavišai", + "FrmSettings.Layout._Gallery": "Galerija", + "FrmMain.MnuNewWindow": "Atidaryti nauja langą", + "FrmMain.MnuMoveToRecycleBin._Description": "Ar Jūs norite perkelti šį failą į šiukšlinę?", + "FrmSettings._DefaultPhotoViewer": "Numatytas paveikslų/nuotraukų/vaizdų žiūrovas", + "_.Metadata._ExifDateTimeOriginal": "EXIF: DateTimeOriginal", + "FrmMain.MnuRotateRight": "Pasukti dešinėn", + "FrmSettings._MinEmbeddedThumbnailSize": "Mažiausias galimas dydis įterptoms miniatiūroms, norint jas krauti", + "FrmMain.MnuSetDefaultPhotoViewer": "Nustatyti, kaip numatytąjį paveikslų/nuotraukų/vaizdų žiūrovą", + "FrmMain.MnuImageProperties": "Paveikslo/Nuotraukos/Vaizdo ypatybės", + "FrmSettings._EnableNavigationButtons": "Rodyti navigacijos „rodyklių“ mygtukus", + "_._Edit": "Pakeisti", + "FrmSettings._ImageBooster": "„Image Booster“", + "FrmSettings.Tools._IntegratedWith": "Integruotas su {0}", + "_._Next": "Kitas", + "FrmExportFrames._OpenOutputFolder": "Atidaryti išvesties aplankalą", + "FrmMain.MnuOpenLocation": "Atidaryti failo vietovę", + "FrmMain.MnuLockZoom": "Užrakinti didinimą", + "FrmSettings._StartupBoost._Description": "Iš anksto įkrauti ir paleisti „ImageGlass“ fono procesuose keliom sekundėm per „Windows“ paleidimą, siekiant paspartinti pirmąjį paleidimą.", + "FrmSettings._WindowBackdrop": "Lango išorinis fonas", + "FrmSettings._EnableRealTimeFileUpdate": "Monitoriaus failas pasikeičia žiūrimam aplanke, ir atsinaujina realiu laiku", + "_._NotSupported": "Nepalaikomas formatas", + "FrmSettings._Theme._GetMoreThemes": "Gauti daugiau temų paketų…", + "FrmMain.MnuNewWindow._Error": "Negalima atidaryti naujo lango, nes tik vienas yra leidžiamas", + "FrmMain.MnuZoomOut": "Nutolinti", + "FrmSettings.Toolbar._EditButton": "Redaguoti įrankių juostos mygtuką", + "FrmMain.MnuCustomZoom._Description": "Įvesti naują mastelio skaičių", + "FrmResize.RadResizeByPixels": "Pikseliai", + "FrmMain.MnuEdit": "Redaguoti paveikslą/nuotrauką/vaizdą {0}…", + "FrmSettings.Layout._GalleryPosition": "Galerijos pozicija", + "FrmMain.MnuWindowFit": "„Lango“ talpinti", + "FrmMain._OpenFileDialog": "Visi palaikomi failo formatai", + "FrmSettings._UseRandomIntervalForSlideshow": "Naudoti belekokį intervalą", + "_.Position._Left": "Kairė", + "FrmSettings._ShouldOpenLastSeenImage": "Atidaryti paskutinį matytą paveikslą/nuotrauką/vaizdą", + "_.Position._Bottom": "Apačia", + "FrmResize.ChkKeepRatio": "Išlaikyti santykį proporcingu", + "FrmMain.MnuGoTo": "Eiti į…", + "FrmSlideshow.MnuPauseResumeSlideshow": "Sustabdyti/Tęsti skaidrių demonstravimą", + "FrmSettings.Tools._Integrated": "Integruotas", + "FrmSettings._Contributors": "Talkininkai", + "_.MouseWheelAction._Zoom": "Priartinti / nutolinti", + "_._CommandPreview": "Komandų peržiūra", + "FrmSettings._DarkTheme": "Tamsus", + "_._Hotkeys": "Spartieji klavišai", + "_.Metadata._ExifDateTime": "EXIF: DateTime", + "FrmSettings.Toolbar._Errors._ButtonIdRequired": "Mygtukų ID reikalingi.", + "FrmSettings._MinEmbeddedThumbnailSize._Width": "Plotis", + "_._Executable": "Paleidžiamasis", + "_.ImageInterpolation._MultiSampleLinear": "Kelių-imčių linijinis (interpoliacija)", + "_._Separator": "Skirtukas", + "FrmQuickSetup._ProfessionalUser": "Profesionalus vartotojas", + "FrmMain.MnuFlipVertical": "Pasukti Vertikaliai", + "FrmSlideshow._ResumeSlideshow": "Skaidrių demonstravimas yra tęsiamas.", + "FrmCropSettings.DefaultSelectionType._CustomArea": "Pasirinktinis plotas…", + "FrmMain.MnuActualSize": "Tikras dydis", + "FrmCrop.BtnSaveAs": "Išsaugoti kaip…", + "FrmSettings._InstallNewLanguagePack": "Įdiegti naujus kalbos paketus…", + "FrmSlideshow.MnuZoomModes": "Priartinimo režimai", + "FrmMain.MnuTools": "Įrankiai", + "_.ImageInterpolation._Cubic": "Kubinė interpeliacija", + "FrmUpdate._LatestVersion": "Naujausia versija: {0}", + "FrmMain.MnuViewNext": "Rodyti kitą paveikslą/nuotrauką/vaizdą", + "_.MouseWheelEvent._AltAndScroll": "Laikyti Alt ir slinkti", + "FrmToolNotFound._Title": "Įrankis nerastas", + "FrmCrop.BtnCrop._Tooltip": "Tik apkirpti šį nuotrauką/paveikslą/vaizdą", + "FrmSettings.EditAppDialog._AddApp": "Pridėti programą redagavimui/retušavimui", + "FrmMain.MnuPanning": "Vaizdo peržiūra (perkelimas) konfiguriaciją", + "_._MoveUp": "Perkelti viršun", + "FrmCropSettings.DefaultSelectionType._SelectAll": "Pasirinkti viską", + "_._Name": "Vardas", + "FrmColorPickerSettings.ChkShowHslA": "Naudoti „HSL“ formatą su „Alpha“ skaitmenimis", + "FrmMain.MnuToggleImageAnimation": "Pradėti / Sustabdyti animuoti paveikslą/nuotrauką/vaizdą", + "FrmSettings._DisableStartupBoost": "Išjungti paleidimo spartinimą", + "FrmMain.MnuCopyFile._Success": "Nukopijuota/-s {0} failas(-ų).", + "FrmMain.MnuSave._ConfirmDescription": "„ImageGlass“ nėra profesionalus fotografų retušatorius, būkite atidūs kokybės praradimu, „metadatos“, sluoksnių,… kai išsaugote pakeitimus.", + "FrmToolNotFound.BtnSelectExecutable": "Pasirinkti…", + "FrmUpdate._StatusOutdated": "Pasiekiamas naujas atnaujinimas!", + "_.ImageOrderBy._Random": "Atsitiktinai", + "FrmResize.LblCurrentSize": "Dabartinis dydis:", + "_._Apply": "Patvirtinti", + "FrmAbout._Slogan": "„Lengva, universali nuotraukų/vaizdų/paveikslų žiūrovas/-ę“", + "FrmMain.MnuPanToTop": "Pakreipti paveikslą/nuotrauką/vaizdą viršun", + "FrmSettings.Toolbar._AddNewButton": "Pridėti pasirinktinį įrankių juostos mygtuką", + "FrmCrop.LblSize": "Dydis:", + "FrmSettings._ImageInterpolation._ScaleDown": "Kai priartinimas < 100%", + "_._CreatingFileError": "Nepavyko sukurti laikino paveikslo/nuotraukos/vaizdo failo", + "FrmMain.MnuGoTo._Description": "Įveskite paveikslo/nuotraukos/vaizdo indeksą ir spauskite „Enter/Tęsti“", + "FrmSettings.Toolbar._EnableCenterToolbar": "Naudoti centruotą lygiuotę, įrankių juostai", + "FrmMain.MnuResizeTool": "Pakeisti paveikslo/nuotraukos/vaizdo dydį", + "FrmSettings.Layout._Toolbar": "Įrankių juosta", + "FrmMain.MnuHelp": "Pagalba", + "_.ImageOrderBy._FileSize": "Failo dydis", + "FrmSettings._Theme._OpenThemeFolder": "Atidaryti temų aplankala", + "FrmMain.MnuNavigation": "Navigacija", + "_._Save": "Išsaugoti", + "FrmQuickSetup._SettingProfileDescription": "Norint pakeisti šiuos nustatymus, nueikite į prieigos programos nustatymus.", + "_._UserAction._MenuNotFound": "Negalima rasti meniu „{0}“, norint įvykdyti veiksmą", + "FrmMain.MnuPanToLeftSide": "Pakreipti paveikslą/nuotrauką/vaizdą kairėn", + "FrmUpdate._CurrentVersion": "Dabartinė versija: {0}", + "FrmCrop.BtnSettings._Tooltip": "Atidaryti apkarpymo įrankio nustatymus", + "_.ColorProfileOption._Custom": "Pasirinktinis…", + "FrmSettings._UseEmbeddedThumbnailOtherFormats": "Krauti tik įterptas miniatiūras kitiems formatams", + "FrmMain.MnuGoToFirst": "Eiti į pirmąjį/-ąją paveikslą/nuotrauką/vaizdą", + "FrmSettings._ExportLanguagePack": "Eksportuoti kalbos paketą…", + "FrmSettings.Nav._Mouse": "Pelė", + "_.ImageOrderBy._DateCreated": "Sukūrimo data", + "FrmSettings._EnableFullscreenSlideshow": "Pradėti skaidrių pristatymą pilno ekrano režime", + "FrmAbout._Homepage": "Namų tinklapio puslapis:", + "FrmSettings._GalleryCacheSizeInMb": "Maksimalus galerijos talpyklos dydis (megabaitais)", + "FrmMain.MnuCopyImageData._Success": "Nukopijuotos paveikslo/nuotraukos/vaizdo duomenys.", + "FrmSettings._EnableLoopBackNavigation": "Grįžti į pirmąją/-į paveikslą/nuotrauką/vaizdą, kai per žiūrovą pasiekta pabaiga", + "_.MouseWheelEvent._Scroll": "Slinkti", + "FrmCrop.BtnSave._Tooltip": "Išsaugoti nuotrauką", + "FrmMain.MnuSlideshow": "Skaidrių demonstracija", + "FrmMain.MnuShare": "Bendrinti…", + "FrmSettings._SlideshowNotification": "Skaidrių pristatymo pranešimas", + "FrmMain.MnuViewChannels": "Rodyti kanalus", + "FrmSettings._Refresh": "Įkelti iš naujo", + "_._UserAction._MethodNotFound": "Negalima rasti būdo „{0}“, norint įvykdyti veiksmą", + "FrmMain.MnuCopyFile": "Kopijuoti failą", + "_._CreatingFile": "Kuriamas laikinas paveikslo/nuotraukos/vaizdo failas…", + "FrmMain.MnuToggleTopMost": "Laikyti visada virš kitų programų", + "FrmMain.MnuLosslessCompression._Confirm": "Ar Jūs esate tikrai įsitikinę, kad norite tęsti?", + "FrmMain.MnuImage": "Paveikslas/Nuotrauka/Vaizdas", + "FrmSettings._StartupBoost._Enabled": "Paleidimo spartinimas yra įgalintas", + "FrmQuickSetup._SetDefaultViewer": "Ar Jūs norėtumėte nustatyti „ImageGlass“ kaip numatytąjį paveikslų/nuotraukų/vaizdų žiūrovą?", + "FrmMain.MnuScaleToWidth": "Didinti iki storio", + "_._FileExtension": "Failo plėtinys", + "FrmUpdate._PublishedDate": "Išleidimo data: {0}", + "_._DoNotShowThisMessageAgain": "Daugiau neberodyti šio pranešimo", + "_.ImageInterpolation._NearestNeighbor": "Pakopinė interpoliacija „artimiausio kaimyno“", + "FrmCrop.LblLocation": "Vieta:", + "_._Download": "Atsisiųsti", + "_.Metadata._ColorProfile": "Spalvų profilis", + "FrmSettings._CenterWindowFit": "Automatiškai centruoti langą, naudojant „Talpinti“ režimą", + "FrmSettings._ImageLoadingOrder": "Paveikslo kraunama tvarka", + "FrmSettings._GalleryColumns": "Miniatiūrų skaičius lygiuotėje, esant vertikalaus galerijos režime", + "_._Quit": "Išeiti", + "_._Add": "Pridėti", + "FrmMain.MnuChangeBackgroundColor": "Pakeisti fono spalvą…", + "FrmMain.MnuToggleToolbar": "Įrankių juosta", + "FrmAbout._Contact": "Kontaktai", + "FrmSettings.Toolbar._AddCustomButton": "Pridėti pasirinktinį mygtuką…", + "FrmCrop.BtnQuickSelect._Tooltip": "Greitas pasirinkimas…", + "FrmMain.MnuCutFile._Success": "Iškirpta/-s {0} failas(-ų).", + "FrmSettings._ZoomSpeed": "Priartinimo/Nutolinimo greitis", + "FrmMain.MnuToggleTopMost._Disable": "Išjungti, kad langas visada būti ant viršaus", + "FrmSettings._ShouldUseExplorerSortOrder": "Naudoti „Windows“ failų naršyklės rikiavimą, jei įmanoma", + "_.ImageInterpolation._Antisotropic": "Anizotropinė interpeliacija", + "FrmMain._ReachedFirstImage": "Pasiekta pirmoji/-asis paveikslas/nuotrauką/vaizdas", + "_._UnhandledException": "Nesuvaldoma išimtis", + "FrmResize.LblNewSize": "Naujas dydis:", + "FrmMain._ClipboardImage": "Iškarpinės paveikslas/nuotrauka/vaizdas", + "FrmMain.MnuExportFrames": "Eksportuoti paveikslų/nuotraukų/vaizdų kadrus…", + "FrmMain.MnuFile": "Failas", + "_._Close": "Uždaryti", + "FrmMain.MnuMain": "Pagrindinis meniu", + "_._ResetToDefault": "Atkurti į numatytuosius", + "FrmSettings.Nav._Gallery": "Galerija", + "FrmMain.MnuSetDefaultPhotoViewer._Success": "Jūs sėkmingai nustatėte „ImageGlass“ kaip numatytąjį paveikslų/nuotraukų/vaizdų žiūrovą.", + "FrmSettings._HideGalleryInFullscreen": "Slėpti galeriją, kai esate pilno ekrano režime", + "FrmSettings._AvailableImageInfoTags": "Galimos žymės:", + "FrmExportFrames._Exporting": "Eksportuojami {0}/{1} kadrai \n{2}…", + "_._Argument": "Argumentas", + "FrmSettings._ImageEditQuality": "Paveikslo/Nuotraukos/Vaizdo kokybė", + "_._ID": "ID", + "FrmSettings._UserConfigFile": "Vartotojo nustatymų failas („igconfig.json“)", + "FrmMain.MnuLoadingOrders": "Kraunama tvarka", + "FrmSettings._OpenSaveAsDialogInTheCurrentImageDir": "Atidaryti – „Išsaugoti kaip“ langą dabartinėje/-iame vaizdo/nuotraukos/paveikslo kataloge/vietovėje", + "_.MouseWheelEvent._ShiftAndScroll": "Laikyti Lyg2 ir slinkti", + "FrmSettings._UseSmoothZooming": "Naudoti „švelnų“ priartinimą/nutolinimą", + "FrmSettings._Theme": "Tema", + "FrmSettings._ImageBoosterCacheMaxDimension": "Maksimali nuotraukos/paveikslo/vaizdo matmuo reikiamas, norint laikyti talpykloje (pikseliais)", + "FrmMain.MnuScaleToHeight": "Dididinti iki aukščio", + "_.Metadata._FileLastWriteTime": "Modifikavimo data", + "FrmSettings._Author": "Autorius", + "FrmSettings._Others": "Kiti", + "_.MouseWheelAction._PanVertically": "Pajundinti į viršų / apačią", + "FrmSettings._MouseWheelAction": "Pelės slinkimo veiksmas", + "FrmSettings.Nav._Tools": "Įrankiai", + "FrmMain.MnuSetDesktopBackground._Error": "Nebuvo galima nustatyti žiūrimo paveikslo/nuotraukos/vaizdo, kaip darbalaukio fono", + "FrmSettings.Toolbar._Errors._ButtonExecutableRequired": "Mygtuko paleidimas (veiksmas) reikalingas.", + "_.ImageOrderBy._DateAccessed": "Pasiekimo data", + "FrmSettings._ThumbnailSize": "Miniatiūros dydis (Pikseliais)", + "FrmSettings._FileFormats": "Failų formatai", + "FrmMain.MnuReloadImageList": "Atnaujinti paveikslų/nuotraukų/vaizdų sąrašą", + "FrmSettings._UseWebview2ForSvg": "Naudoti „Webview2“, žiūrint „SVG“ formatą", + "FrmCrop.BtnCopy": "Kopijuoti", + "FrmSettings._CurrentMonitorProfile._Description": "„ImageGlass“ automatiškai neatnaujina spalvos, kai judinate jo ekraną tarp monitorių", + "FrmMain.PicMain._ErrorText": "Nebuvo galima atidaryti šio/-s paveikslo/nuotraukos/vaizdo", + "FrmSettings.Tools._AddNewTool": "Pridėti išorinį įrankį", + "FrmMain.MnuRename": "Pervadinti paveikslą/nuotrauką/vaizdą…", + "FrmMain.MnuViewLastFrame": "Rodyti paskutinį kadrą", + "_._Webview2._NotFound": "Prašome įdiegti naujausią „WebView2 Runtime“.", + "FrmMain.MnuGetMoreTools": "Gauti daugiau įrankių…", + "FrmSettings.Nav._Appearance": "Išvaizda", + "FrmSettings._SlideshowInterval": "Skaidrių demonstravimo intervalas:", + "_.ImageInterpolation._HighQualityBicubic": "Aukštos kokybės, bikubinė interpeliacija", + "FrmColorPickerSettings.ChkShowHsvA": "Naudoti „HSV“ formatą su „Alpha“ skaitmenimis", + "FrmSettings.Tools._EditTool": "Keisti/Redaguoti išorinį įrankį", + "_._Error": "Klaida", + "FrmSettings._ImageBoosterCacheMaxFileSizeInMb": "Maksimali nuotraukos/paveikslo/vaizdo failo dydis, norint laikyti talpykloje (megabaitais)", + "_._UnhandledException._Description": "Įvyko nesuvaldoma išimtis. Jeigu spausite – „Tęsti“, programa ignoruos šią klaidą ir mėgins tęsti savo veiklą. Jeigu paspausite – „Išeiti“, programa išsijungs iš karto.", + "_.Metadata._FileSize": "Failo dydis", + "FrmSettings.Toolbar._ButtonJson": "Mygtuko „JSON“", + "FrmQuickSetup._SetDefaultViewer._Description": "Jūs galite atkurti į pradinę būseną programos nustatymuose > Failo tipų asociacijos skirtuke.", + "FrmSettings.Nav._Edit": "Pakeisti", + "FrmMain.MnuToggleGallery": "Galerijos skydelis", + "_._IgCommandExe._DefaultError._Description": "Patikrinkite, kad įvykdote tinkamas komandas!\r\nŠis failas turi komandinės eilutes funkcijas „ImageGlass“ taikomai programai.\r\n\r\nNorint sužinoti visas komandines eilutes, prašome apsilankyti:\n{0}", + "FrmMain.MnuLosslessCompression._Compressing": "Vykdomas nenuostoli̇̀ngasis glaũdinimas…", + "FrmSettings._ShouldGroupImagesByDirectory": "Grupuoti paveikslus, pagal vietovę", + "FrmMain.MnuPanToRightSide": "Pakreipti paveikslą/nuotrauką/vaizdą dešinėn", + "_.Metadata._ExifRatingPercent": "Įvertinimas", + "FrmSettings._PanSpeed": "Pakreipimo greitis", + "_._CheckForUpdate": "Tikrinti ar yra atnaujinimų…", + "FrmSettings.Layout._ToolbarContext": "Kontekstinė įrankių juostą", + "_.ImageInfo._FrameCount": "{0} kadras/-ų", + "FrmMain.MnuLayout": "Išvaizda", + "_._Website": "Tinklapis", + "FrmMain.MnuPasteImage": "Įklijuoti paveikslą/nuotrauką/vaizdą", + "FrmSettings._ShowGalleryScrollbars": "Rodyti galerijoje, slinkimo juostas" + } +} \ No newline at end of file diff --git a/Setup/Assets/Language/Malay.iglang.json b/Setup/Assets/Language/Malay.iglang.json new file mode 100644 index 000000000..2462923dc --- /dev/null +++ b/Setup/Assets/Language/Malay.iglang.json @@ -0,0 +1,504 @@ +{ + "_Metadata": { + "Code": "ms-MY", + "EnglishName": "Malay", + "LocalName": "Bahasa Melayu", + "Author": "Abuyop", + "MinVersion": "" + }, + "Items": { + "FrmCrop.SelectionAspectRatio._Original": "Asal", + "FrmMain.MnuShare._Error": "Tidak dapat membuka dialog Kongsi.", + "_.Metadata._FileLastAccessTime": "Tarikh dicapai", + "FrmAbout._License": "Lesen perisian", + "FrmSettings.Toolbar._Errors._ButtonIdDuplicated": "Satu butang dengan ID '{0}' sudah ditakrif. Sila pilih ID unik dan berbeza untuk butang anda bagi menghindari konflik.", + "FrmMain.MnuSave._Confirm": "Anda pasti mahu menindih imej ini?", + "FrmSettings._OpenDefaultAppsSetting": "Buka tetapan apl Lalai", + "FrmMain.MnuCopyPath": "Salin laluan imej", + "FrmCropSettings.DefaultSelectionType._SelectNone": "Pilih tiada", + "_.MouseWheelAction._PanHorizontally": "Lata kiri / kanan", + "FrmMain.MnuPrint": "Cetak…", + "FrmSettings.Toolbar._ToolbarButtons": "Butang palang alat", + "FrmResize.LblResample": "Resample:", + "_.ImageOrderBy._Extension": "Sambungan", + "FrmSettings.Nav._Viewer": "Pelihat", + "FrmSettings.EditAppDialog._EditApp": "Sunting apl", + "FrmCrop.BtnReset._Tooltip": "Tetap semula pemilihan", + "FrmMain.MnuRename._Description": "Masukkan nama fail baharu:", + "_._No": "No", + "FrmSlideshow.MnuToggleCountdown": "Tunjuk kiraan mengundur tayangan slaid", + "FrmSettings._OpenStartupAppsSetting": "Buka tetapan apl Permulaan", + "FrmMain.MnuViewPreviousFrame": "Lihat bingkai terdahulu", + "_.ImageOrderBy._DateModified": "Tarikh diubah suai", + "FrmMain.MnuViewNextFrame": "Lihat bingkai berikutnya", + "FrmMain.MnuUnload": "Nyahmuat imej", + "FrmSettings.Toolbar._HideToolbarInFullscreen": "Sembunyi palang alat dalam mod skrin penuh", + "_.ImageOrderType._Desc": "Menurun", + "_._Update": "Kemas kini", + "FrmSettings._EnableImageAsyncLoading": "Dayakan memuat turun imej segerak", + "FrmSettings._DefaultPhotoViewer._Description": "Daftar format disokong ImageGlass dalam Windows. Anda mungkin perlu membuka tetapan apl Lalai dan pilih ImageGlass secara manual melalui senarai supaya ia berkesan.", + "_.MouseWheelAction._BrowseImages": "Lihat Imej berikutnya / terdahulu", + "FrmSettings._EditApps": "Apl penyuntingan imej", + "FrmColorPickerSettings.ChkShowCIELabA": "Guna format CIELAB dengan nilai alfa", + "_._GetHelp": "Dapatkan bantuan", + "FrmQuickSetup._SkipQuickSetup": "Langkau ini dan lancarkan ImageGlass", + "FrmColorPickerSettings._Title": "Tetapan pemilih warna", + "_._Copy": "Salin", + "FrmSettings._ImageBoosterCacheCount": "Bilangan imej dicache oleh ImageBooter (satu arah)", + "FrmMain.MnuPanToBottom": "Lata imej ke bawah", + "FrmMain.MnuZoom": "Zum", + "FrmCropSettings.ChkCloseToolAfterSaving": "Tutup alat Kerat selepas menyimpan", + "FrmSettings._ShowWelcomeImage": "Tunjuk imej aluan", + "FrmSettings._ColorProfile": "Profil warna", + "FrmSettings._Theme._UninstallTheme": "Nyahpasang pek tema", + "FrmMain._OpenWith": "Buka dengan {0}", + "FrmMain.MnuRemoveDefaultPhotoViewer": "Buang pelihat foto lalai", + "_.AfterEditAppAction._Nothing": "Tiada apa-apa", + "FrmCrop.BtnSave": "Simpan", + "FrmMain.MnuScaleToFit": "Skala suai muat", + "FrmToolNotFound.LblDownloadToolText": "Anda boleh muat turun lebih banyak alat untuk ImageGlass di:", + "_._LearnMore": "Ketahui lebih lanjut…", + "FrmCrop.LblAspectRatio": "Nisbah bidang:", + "FrmExportFrames._FileNotExist": "Fail imej tidak wujud", + "FrmSettings._LightTheme": "Cerah", + "FrmSettings.Nav._Slideshow": "Tayangan Slaid", + "_._Continue": "Seterusnya", + "_._AddHotkey": "Tambah kekunci pantas…", + "FrmMain.MnuSetDesktopBackground": "Tetapkan sebagai latar belakang Atas Meja", + "FrmMain.MnuReload": "Muat semula imej", + "FrmSlideshow.MnuExitSlideshow": "Keluar dari tayangan slaid", + "FrmMain.MnuAutoZoom": "Auto zum", + "FrmSettings._ShowImagePreview": "Papar pratonton imej ketika ia dimuatkan", + "FrmCrop.BtnCopy._Tooltip": "Salin pemilihan ke papan keratan", + "FrmSettings.Nav._Toolbar": "Palang Alat", + "FrmMain.MnuSave._Error": "Tidak dapat menyimpan imej", + "FrmSettings._AfterEditingAction": "Selepas membuka apl penyuntingan", + "FrmSettings._ShouldUseColorProfileForAll": "Terap juga imej tanpa profil warna terbenam", + "FrmCropSettings.DefaultSelectionType._UseTheLastSelection": "Guna pemilihan terakhir", + "FrmSettings._SlideshowInterval._From": "Dari", + "FrmSettings._ImageInterpolation": "Interpolasi imej", + "FrmQuickSetup._StepInfo": "Langkah {0}", + "FrmMain.MnuColorPicker": "Pemilih warna", + "FrmCrop.SelectionAspectRatio._FreeRatio": "Nisbah bebas", + "FrmSettings._ResetSettings": "Tetap semula tetapan", + "FrmSettings._Startup": "Permulaan", + "_.BackdropStyle._None": "Tiada", + "FrmSettings._LoadDefaultZoomLevels": "Muat aras zum lalai", + "FrmColorPicker.BtnSettings._Tooltip": "Buka tetapan Pemilih warna…", + "FrmSettings._UseThemeForDarkMode": "Guna tema ini untuk mod gelap", + "FrmSettings._ShowDeleteConfirmation": "Tunjuk dialog pengesahan ketika memadam fail", + "FrmSettings._ShowAppIcon": "Tunjuk ikon apl di atas palang tajuk", + "_._InvalidAction": "Tindakan tidak sah", + "FrmQuickSetup._SelectProfile": "Pilih satu profil", + "_.Metadata._FileCreationTime": "Tarikh dicipta", + "FrmSettings._SlideshowImagesToNotifySound": "Bilangan imej yang memicu bunyi pemberitahuan", + "FrmSettings._BackgroundColor": "Warna latar belakang pelihat", + "FrmSettings._RealTimeFileUpdate": "Kemas kini fail masa nyata", + "_.ColorProfileOption._CurrentMonitorProfile": "Profil monitor semasa", + "FrmSettings._EnableCutMultipleFiles": "Dayakan pemotongan fail berbilang serentak", + "FrmSettings._AutoUpdate": "Periksa kemas kini secara automatik", + "FrmCropSettings.LblDefaultSelection": "Tetapan pemilihan lalai", + "FrmSettings._UseThemeForLightMode": "Guna tema ini untuk mod cerah", + "FrmSettings._ZoomLevels": "Aras zum", + "FrmMain.MnuSetLockScreen._Success": "Imej skrin kunci sudah dikemaskinikan", + "FrmSettings._ShowGalleryFileName": "Tunjuk nama fail imej kenit", + "FrmSettings.Layout._Order": "Urutan", + "FrmCropSettings.ChkAutoCenterSelection": "Pemilihan auto-pusat", + "FrmSettings.Nav._FileTypeAssociations": "Perkaitan jenis fail", + "_._Back": "Undur", + "FrmMain.MnuSetDesktopBackground._Success": "Latar belakang atas meja sudah dikemaskinikan", + "FrmSettings._ShouldAutoOpenNewAddedImage": "Buka imej baharu ditambah secara automatik", + "FrmCrop.SelectionAspectRatio._Custom": "Suai…", + "FrmMain.MnuCopyPath._Success": "Laluan imej semasa disalin.", + "FrmSettings._StartupBoost._Error": "Tidak dapat mengubah tetapan Galak Permulaan", + "FrmToolNotFound.LblDescription": "ImageGlass gagal mencari laluan ke boleh laku '{0}'. Untuk menyelesaikan isu ini, sila kemas kini laluan ke '{0}' sebagai penting.", + "FrmMain.MnuClearClipboard": "Kosongkan papan keratan", + "FrmSettings._ColorManagement": "Pengurusan warna", + "FrmMain._ReachedLastLast": "Pada imej terakhir", + "FrmMain.MnuPanUp": "Lata imej ke atas", + "FrmMain.MnuRemoveDefaultPhotoViewer._Success": "ImageGlass tidak lagi menjadi pelihat foto lalai.", + "FrmSettings._GetMoreLanguagePacks": "Dapatkan lagi banyak pek bahasa…", + "FrmAbout._Privacy": "Dasar kerahsiaan", + "FrmSettings._EnableRecursiveLoading": "Muat imej dalam subfolder", + "_._UserAction._MethodArgumentNotSupported": "Jenis argumen bagi kaedah '{0}' tidak disokong", + "FrmSettings._FileExtensionIcons._Description": "Untuk penyuaian ikon sambungan fail, muat turun satu pek ikon, letak semua fail .ICO di dalam folder ikon sambungan, kemudian klik butang '{0}'. Tindakan ini juga menetapkan ImageGlass sebagai pelihat foto lalai.", + "_.ImageOrderType._Asc": "Menaik", + "FrmExportFrames._Title": "Eksport bingkai imej", + "_._Install": "Pasang…", + "FrmMain.MnuFlipHorizontal": "Kalih Mengufuk", + "FrmSettings._OpenExtensionIconFolder": "Buka folder ikon sambungan", + "FrmAbout._Collaborator": "Rakan usaha sama:", + "FrmQuickSetup._ConfirmCloseProcess": "Sebelum menerapkan tetapan baharu, perlu menutup semua proses ImageGlass. Sudah sedia?", + "FrmExportFrames._ExportDone": "{0} bingkai berjaya dieksport kepada \n{1}", + "FrmCrop.BtnSaveAs._Tooltip": "Simpan sebagai satu salinan…", + "FrmMain.MnuOpenFile": "Buka fail…", + "FrmColorPickerSettings.ChkShowRgbA": "Guna format RGB dengan nilai alfa", + "_.ImageInfo._ListCount": "{0} fail(s)", + "FrmMain.MnuGoToLast": "Pergi ke imej terakhir", + "FrmSettings._EditApps._AppName": "Nama apl", + "FrmSettings._SlideshowBackgroundColor": "Warna latar belakang tayangan slaid", + "FrmAbout._Email": "Emel:", + "_.MouseWheelAction._DoNothing": "Jangan buat apa-apa", + "FrmMain.MnuSaveAs": "Simpan sebagai…", + "FrmMain._Loading": "Memuatkan…", + "_._Browse": "Layar…", + "FrmMain.MnuSetDefaultPhotoViewer._Error": "Tidak dapat menetapkan ImageGlass sebagai pelihat foto lalai.", + "FrmSettings.Nav._Language": "Bahasa", + "FrmQuickSetup._SeeWhatNew": "Baca perkara baharu dalam versi ini…", + "FrmSettings._ImageInterpolation._ScaleUp": "Bila zum > 100%", + "FrmSettings.Layout._ToolbarContextPosition": "Kedudukan palang alat konteksual", + "FrmMain.MnuDeleteFromHardDisk": "Padam secara kekal", + "FrmSettings._EmbeddedThumbnail": "Imej kenit terbenam", + "FrmMain.MnuDeleteFromHardDisk._Description": "Anda pasti ingin memadam fail ini secara kekal?", + "FrmMain.MnuScaleToFill": "Skala dipenuhi", + "FrmCrop.BtnCrop": "Kerat", + "_.AfterEditAppAction._Minimize": "Minimumkan", + "FrmMain.MnuInvertColors": "Invert colors", + "FrmSettings._StartupBoost": "Galak Permulaan", + "FrmMain.MnuViewFirstFrame": "Lihat bingkai pertama", + "_.MouseWheelEvent._CtrlAndScroll": "Tahan Ctrl dan tatal", + "FrmSettings._HideMainWindowInSlideshow": "Sembunyi tetingkap utama secara automatik", + "_.Metadata._FrameCount": "Bingkai", + "FrmSettings._EnableCopyMultipleFiles": "Dayakan penyalinan fail berbilang serentak", + "FrmMain.MnuFrameless._EnableDescription": "Tahan kekunci Shift untuk menggerakkan tetingkap.", + "_.ImageOrderBy._ExifDateTaken": "EXIF: Tarikh ditangkap", + "FrmAbout._Credits": "Penghargaan", + "FrmSettings._AddNewFileExtension": "Tambah sambungan fail baharu", + "FrmMain.MnuQuickSetup": "Buka Persediaan Pantas ImageGlass", + "FrmMain.MnuSave._Success": "Imej disimpan", + "FrmMain.MnuPanLeft": "Lata imej ke kiri", + "FrmUpdate._StatusChecking": "Menyemak kemas kini…", + "FrmSettings.Nav._Layout": "Bentangan", + "FrmMain.MnuOpenWith": "Buka dengan…", + "FrmAbout._Thanks": "Terima kasih kepada:", + "_._Warning": "Amaran", + "FrmSettings.Nav._Keyboard": "Papan Kekunci", + "FrmSlideshow._PauseSlideshow": "Tayangan slaid dijeda.", + "_._Add+": "Tambah…", + "_._Email": "Emel", + "FrmMain.MnuPanDown": "Lata imej ke bawah", + "_._Cancel": "Batal", + "_._OK": "OK", + "FrmMain.MnuPanRight": "Lata imej ke kanan", + "_.Position._Right": "Kanan", + "_._Icon": "Ikon", + "FrmSettings._ShouldLoadHiddenImages": "Muat imej tersembunyi", + "_._InvalidAction._Transformation": "ImageGlass tidak menyokong putar, kalih untuk imej ini.", + "FrmSettings._MakeDefault": "Jadikan lalai", + "FrmMain.MnuCopyImageData._Copying": "Menyalin data imej. Tunggu sebentar…", + "FrmSettings._UseEmbeddedThumbnailRawFormats": "Hanya muat imej kenit terbenam untuk format RAW", + "_.ImageInterpolation._Linear": "Linear", + "FrmSettings._ImageInfoTags": "Tag maklumat imej", + "FrmSettings._FileExtensionIcons": "Ikon sambungan fail", + "FrmMain.MnuEdit._AppNotFound": "Tidak dapat mencari apl berkaitan untuk penyuntingan. Anda boleh tugaskan satu apl untuk menyunting format ini dalam Tetapan ImageGlass > Sunting.", + "_.ColorProfileOption._None": "Tiada", + "FrmSettings._TotalSupportedFormats": "Jumlah format disokong: {0}", + "FrmSettings._Clipboard": "Papan keratan", + "_._UserAction._Win32ExeError": "Tidak dapat melakukan perintah '{0}'. Pastikan nama adalah betul.", + "FrmCropSettings.DefaultSelectionType._SelectX": "Pilih {0}", + "_.AfterEditAppAction._Close": "Tutup", + "FrmAbout._LogoDesigner": "Pereka logo:", + "_.ImageOrderBy._Name": "Nama (lalai)", + "FrmMain.MnuRemoveDefaultPhotoViewer._Error": "Tidak dapat membuang ImageGlass sebagai pelihat foto lalai.", + "FrmExportFrames._FolderPickerTitle": "Pilih folder output untuk mengeksport bingkai imej", + "FrmAbout._Donate": "Derma", + "FrmMain.MnuFrameNav": "Pengemudian bingkai", + "FrmMain.MnuSetLockScreen": "Tetapkan sebagai imej skrin kunci", + "_._Delete": "Padam", + "FrmMain.MnuViewPrevious": "Lihat imej terdahulu", + "_.Position._Top": "Atas", + "FrmSettings.Toolbar._CurrentButtons": "Butang semasa:", + "FrmMain.MnuAbout": "Perihal", + "FrmSettings._RemoveDefault": "Buang lalai", + "_._Description": "Keterangan", + "FrmMain.MnuPasteImage._Error": "Tidak dapat mencari data imej dalam Papan keratan", + "FrmMain.MnuSettings": "Tetapan", + "FrmCropSettings._Title": "Tetapan kerat", + "FrmSettings.Toolbar._ToolbarIconHeight": "Saiz ikon palang alat", + "FrmSettings._SlideshowInterval._To": "Ke", + "FrmSettings.Layout._ToolbarPosition": "Kedudukan palang alat", + "FrmUpdate._StatusUpdated": "Anda sudah menggunakan versi terkini!", + "FrmMain.MnuExit": "Keluar", + "_._Webview2._Outdated": "Your WebView2 Runtime is not supported. Please update to version {0} or later.", + "_._Yes": "Ya", + "FrmMain.MnuRotateLeft": "Putar kiri", + "FrmSettings._EnableStartupBoost": "Dayakan Galak Permulaan", + "_.ImageOrderBy._ExifRating": "EXIF: Penarafan", + "FrmMain.MnuZoomIn": "Zum masuk", + "_.Metadata._ColorSpace": "Ruang warna", + "FrmAbout._Version": "Versi:", + "FrmMain.MnuToggleTopMost._Enable": "Tetingkap sentiasa di atas didayakan", + "FrmSettings.Toolbar._AvailableButtons": "Butang tersedia:", + "FrmMain.MnuSave._Saving": "Menyimpan imej…", + "FrmQuickSetup._StandardUser": "Pengguna biasa", + "FrmMain.MnuSetLockScreen._Error": "Tidak dapat menetapkan imej yang dilihat sebagai imej skrin kunci", + "FrmSettings.Nav._Image": "Imej", + "FrmSettings._Theme._InstallTheme": "Pasang pek tema", + "FrmSettings._EnableMultiInstances": "Dayakan kejadian berbilang program", + "FrmMain.MnuCropTool": "Kerat imej", + "_._IgCommandExe._DefaultError._Heading": "Perintah tidak sah", + "_._Refresh": "Segar semula", + "FrmMain.MnuLosslessCompression._Description": "Alat ini menggunakan pustaka Magick.NET untuk mampatan tak hilang, justeru dapat mengoptimumkan saiz fail. Tulis ganti hanya fail termampat lebih kecil daripada yang asal.", + "_._MoveDown": "Alih ke bawah", + "FrmSettings._GetExtensionIconPacks": "Dapatkan pek ikon sambungan…", + "FrmSettings._InAppMessageDuration": "Tempoh mesej dalam-apl (milisaat)", + "FrmMain.MnuFrameless": "Tanpa bingkai", + "_._Reset": "Tetap semula", + "FrmSettings._ConfigDir": "Lokasi konfigurasi", + "FrmQuickSetup._SettingsWillBeApplied": "Tetapan yang akan diterapkan:", + "FrmSettings._UnmanagedSettingReminder": "Tetapan ini tidak diurus oleh ImageGlass. Jangan lupa melumpuhkannya sebelum anda buang atau tempat-semula apl kerana ImageGlass tidak kendalinya secara automatik.", + "FrmMain.MnuClipboard": "Papan keratan", + "FrmMain.MnuCustomZoom": "Zum suai…", + "FrmSettings._DisplayLanguage": "Bahasa paparan", + "FrmMain.MnuPrint._Error": "Tidak dapat mencetak imej yang dilihat", + "FrmSettings._ShouldPreserveModifiedDate": "Kekalkan tarikh ubah suai imej ketika menyimpan", + "FrmSettings._ShowSaveOverrideConfirmation": "Tunjuk dialog pengesahan ketika menindih fail", + "FrmColorPickerSettings.ChkShowHexA": "Guna format HEX dengan nilai alfa", + "FrmMain.MnuFullScreen": "Skrin Penuh", + "FrmSettings._StartupDir": "Lokasi permulaan", + "FrmSettings._ShowCheckerboardOnlyImageRegion": "Tunjuk papan dam sahaja dalam kawasan imej", + "FrmMain.MnuClearClipboard._Success": "Papan keratan dikosongkan.", + "FrmQuickSetup._Text": "Persediaan Pantas ImageGlass", + "FrmMain.MnuLosslessCompression._Done": "Mampatan tidak hilang selesai.\r\nSaiz fail baharu ialah {0}, berjaya disimpan {1}.", + "FrmMain.MnuLosslessCompression": "Mampatan Tak Hilang Magick.NET", + "FrmResize.RadResizeByPercentage": "Percentage", + "FrmSettings._StartupBoost._Disabled": "Galak Permulaan dilumpuhkan", + "FrmMain.MnuToggleCheckerboard": "Latar belakang papan dam", + "FrmSettings._MinEmbeddedThumbnailSize._Height": "Tinggi", + "FrmSettings.Nav._General": "Am", + "FrmSettings._ImageLoading": "Imej dimuatkan", + "FrmSettings._ShowSlideshowCountdown": "Tunjuk kiraan mengundur tayangan slaid", + "FrmMain.MnuSave": "Simpan", + "FrmMain.MnuMoveToRecycleBin": "Buang ke dalam Tong Sampah", + "FrmMain.MnuRefresh": "Segar semula", + "FrmToolNotFound.LblHeading": "'{0}' tidak ditemui!", + "FrmMain.MnuReportIssue": "Lapor sebagai isu…", + "FrmMain.MnuCopyImageData": "Salin data imej", + "FrmMain.MnuCheckForUpdate._NewVersion": "Satu versi baharu sudah tersedia!", + "_._Empty": "(kosong)", + "FrmSettings._Zooming": "Pengezuman", + "FrmMain.MnuCutFile": "Potong fail", + "FrmHotkeyPicker.LblHotkey": "Tekan kekunci pantas", + "FrmSettings.Layout._Gallery": "Galeri", + "FrmMain.MnuNewWindow": "Buka tetingkap baharu", + "FrmMain.MnuMoveToRecycleBin._Description": "Anda pasti mahu membuang fail ini ke dalam Tong sampah?", + "FrmSettings._DefaultPhotoViewer": "Pelihat foto lalai", + "_.Metadata._ExifDateTimeOriginal": "EXIF: DateTimeOriginal", + "FrmMain.MnuRotateRight": "Putar kanan", + "FrmSettings._MinEmbeddedThumbnailSize": "Saiz minimum imej kenit terbenam yang dimuatkan", + "FrmMain.MnuSetDefaultPhotoViewer": "Tetapkan pelihat foto Lalai", + "FrmMain.MnuImageProperties": "Sifat imej", + "FrmSettings._EnableNavigationButtons": "Tunjuk butang anak panah pengemudian", + "_._Edit": "Sunting", + "FrmSettings._ImageBooster": "Image Booster", + "FrmSettings.Tools._IntegratedWith": "Disepadu dengan {0}", + "_._Next": "Berikutnya", + "FrmExportFrames._OpenOutputFolder": "Buka folder output", + "FrmMain.MnuOpenLocation": "Buka lokasi imej", + "FrmMain.MnuLockZoom": "Kunci nisbah zum", + "FrmSettings._StartupBoost._Description": "Muat semula dan jalankan ImageGlass di balik tabir selama beberapa saat ketika permulaan Windows untuk melajukan perlancaran pertama.", + "FrmSettings._WindowBackdrop": "Latar belakang tetingkap", + "FrmSettings._EnableRealTimeFileUpdate": "Pantau perubahan fail ketika melihat folder dan kemas kini dalam masa nyata", + "_._NotSupported": "Format tidak disokong", + "FrmSettings._Theme._GetMoreThemes": "Dapatkan lagi pek tema…", + "FrmMain.MnuNewWindow._Error": "Tidak dapat buka tetingkap baharu kerana hanya satu kejadian dibenarkan", + "FrmMain.MnuZoomOut": "Zum keluar", + "FrmSettings.Toolbar._EditButton": "Sunting butang palang alat", + "FrmMain.MnuCustomZoom._Description": "Masukkan satu nilai zum baharu", + "FrmResize.RadResizeByPixels": "Pixels", + "FrmMain.MnuEdit": "Sunting imej {0}…", + "FrmSettings.Layout._GalleryPosition": "Kedudukan galeri", + "FrmMain.MnuWindowFit": "Suai Nuat Tetingkap", + "FrmMain._OpenFileDialog": "Semua fail disokong", + "FrmSettings._UseRandomIntervalForSlideshow": "Guna sela rawak", + "_.Position._Left": "Kiri", + "FrmSettings._ShouldOpenLastSeenImage": "Buka imej terakhir yang dilihat", + "_.Position._Bottom": "Bawah", + "FrmResize.ChkKeepRatio": "Keep ratio propotional", + "FrmMain.MnuGoTo": "Pergi ke…", + "FrmSlideshow.MnuPauseResumeSlideshow": "Jeda/sambung semula tayangan slaid", + "FrmSettings.Tools._Integrated": "Disepadu", + "FrmSettings._Contributors": "Penyumbang", + "_.MouseWheelAction._Zoom": "Zum masuk / keluar", + "_._CommandPreview": "Pratonton perintah", + "FrmSettings._DarkTheme": "Gelap", + "_._Hotkeys": "Kekunci pantas", + "_.Metadata._ExifDateTime": "EXIF: DateTime", + "FrmSettings.Toolbar._Errors._ButtonIdRequired": "ID butang diperlukan.", + "FrmSettings._MinEmbeddedThumbnailSize._Width": "Lebar", + "_._Executable": "Boleh laku", + "_.ImageInterpolation._MultiSampleLinear": "Linear sampel-berbilang", + "_._Separator": "Pemisah", + "FrmQuickSetup._ProfessionalUser": "Pengguna profesional", + "FrmMain.MnuFlipVertical": "Kalih Menegak", + "FrmSlideshow._ResumeSlideshow": "Tayangan slaid disambung semula.", + "FrmCropSettings.DefaultSelectionType._CustomArea": "Kawasan suai…", + "FrmMain.MnuActualSize": "Saiz sebenar", + "FrmCrop.BtnSaveAs": "Simpan sebagai…", + "FrmSettings._InstallNewLanguagePack": "Pasang pek bahasa baharu…", + "FrmSlideshow.MnuZoomModes": "Mod zum", + "FrmMain.MnuTools": "Alatan", + "_.ImageInterpolation._Cubic": "Kubik", + "FrmUpdate._LatestVersion": "Versi terkini: {0}", + "FrmMain.MnuViewNext": "Lihat imej berikutnya", + "_.MouseWheelEvent._AltAndScroll": "Tahan Alt dan tatal", + "FrmToolNotFound._Title": "Alat tidak ditemui", + "FrmCrop.BtnCrop._Tooltip": "Kerat imej sahaja", + "FrmSettings.EditAppDialog._AddApp": "Tambah satu apl untuk menyunting", + "FrmMain.MnuPanning": "Penataan", + "_._MoveUp": "Alihkan ke atas", + "FrmCropSettings.DefaultSelectionType._SelectAll": "Pilih semua", + "_._Name": "Nama", + "FrmColorPickerSettings.ChkShowHslA": "Guna format HSL dengan nilai alfa", + "FrmMain.MnuToggleImageAnimation": "Mula / henti imej beranimasi", + "FrmSettings._DisableStartupBoost": "Lumpuhkan Galak Permulaan", + "FrmMain.MnuCopyFile._Success": "{0} fail(s) disalin.", + "FrmMain.MnuSave._ConfirmDescription": "ImageGlass bukan sebuah penyunting foto bertaraf profesional, berkemungkinan akan berlaku kehilangan kualiti, metadata, lapisan,… ketika menyimpan imej anda.", + "FrmToolNotFound.BtnSelectExecutable": "Pilih…", + "FrmUpdate._StatusOutdated": "Satu kemas kini baharu sudah tersedia!", + "_.ImageOrderBy._Random": "Rawak", + "FrmResize.LblCurrentSize": "Current Size:", + "_._Apply": "Terap", + "FrmAbout._Slogan": "Sebuah pelihat imej yang ringan, pantas, dan serba-boleh", + "FrmMain.MnuPanToTop": "Lata imej ke atas", + "FrmSettings.Toolbar._AddNewButton": "Tambah butang palang alat suai", + "FrmCrop.LblSize": "Saiz:", + "FrmSettings._ImageInterpolation._ScaleDown": "Bila zum < 100%", + "_._CreatingFileError": "Tidak dapat mencipta fail imej sementara", + "FrmMain.MnuGoTo._Description": "Masukkan indeks imej untuk melihatnya. kemudian tekan ENTER", + "FrmSettings.Toolbar._EnableCenterToolbar": "Guna jajaran tengah untuk palang alat", + "FrmMain.MnuResizeTool": "Resize image", + "FrmSettings.Layout._Toolbar": "Palang Alat", + "FrmMain.MnuHelp": "Bantuan", + "_.ImageOrderBy._FileSize": "Saiz fail", + "FrmSettings._Theme._OpenThemeFolder": "Buka folder tema", + "FrmMain.MnuNavigation": "Pengemudian", + "_._Save": "Simpan", + "FrmQuickSetup._SettingProfileDescription": "Untuk mengubah suai tetapan ini, hanya akses tetapan apl.", + "_._UserAction._MenuNotFound": "Tidak dapat mencari menu '{0}' yang menimbulkan tindakan itu", + "FrmMain.MnuPanToLeftSide": "Lata imej ke sisi kiri", + "FrmUpdate._CurrentVersion": "Versi semasa: {0}", + "FrmCrop.BtnSettings._Tooltip": "Buka tetapan alat Kerat", + "_.ColorProfileOption._Custom": "Suai…", + "FrmSettings._UseEmbeddedThumbnailOtherFormats": "Hanya muat imej kenit terbenam untuk format lain", + "FrmMain.MnuGoToFirst": "Pergi ke imej pertama", + "FrmSettings._ExportLanguagePack": "Eksport pek bahasa…", + "FrmSettings.Nav._Mouse": "Tetikus", + "_.ImageOrderBy._DateCreated": "Tarikh dicipta", + "FrmSettings._EnableFullscreenSlideshow": "Hanya muat tayangan slaid dalam mod skrin penuh", + "FrmAbout._Homepage": "Laman utama:", + "FrmSettings._GalleryCacheSizeInMb": "Saiz maksimum cache galeri (dalam megabait)", + "FrmMain.MnuCopyImageData._Success": "Data imej semasa disalin.", + "FrmSettings._EnableLoopBackNavigation": "Ulang balik pelihat ke imej pertama sekiranya telah mencapai penghujung senarai imej", + "_.MouseWheelEvent._Scroll": "Tatal", + "FrmCrop.BtnSave._Tooltip": "Simpan imej", + "FrmMain.MnuSlideshow": "Tayangan Slaid", + "FrmMain.MnuShare": "Kongsi…", + "FrmSettings._SlideshowNotification": "Pemberitahuan tayangan slaid", + "FrmMain.MnuViewChannels": "Lihat saluran", + "FrmSettings._Refresh": "Segar semula", + "_._UserAction._MethodNotFound": "Tidak dapat mencari kaedah '{0}' yang menimbulkan tindakan itu", + "FrmMain.MnuCopyFile": "Salin fail", + "_._CreatingFile": "Mencipta satu fail imej sementara…", + "FrmMain.MnuToggleTopMost": "Kekal tetingkap sentiasa di atas", + "FrmMain.MnuLosslessCompression._Confirm": "Anda pasti mahu teruskan?", + "FrmMain.MnuImage": "Imej", + "FrmSettings._StartupBoost._Enabled": "Galak Permulaan didayakan", + "FrmQuickSetup._SetDefaultViewer": "Anda pasti mahu menetapkan ImageGlass sebagai pelihat foto lalai?", + "FrmMain.MnuScaleToWidth": "Skala ikut lebar", + "_._FileExtension": "Sambungan fail", + "FrmUpdate._PublishedDate": "Tarikh diterbitkan: {0}", + "_._DoNotShowThisMessageAgain": "Jangan tunjukkan mesej ini lagi", + "_.ImageInterpolation._NearestNeighbor": "Kejiranan terhampir", + "FrmCrop.LblLocation": "Lokasi:", + "_._Download": "Muat turun", + "_.Metadata._ColorProfile": "Profil warna", + "FrmSettings._CenterWindowFit": "Tengahkan tetingkap secara automatik dalam mod Suai Muat Tetingkap", + "FrmSettings._ImageLoadingOrder": "Tertib memuatkan imej", + "FrmSettings._GalleryColumns": "Bilangan lajur imej kenit dalam bentangan galeri menegak", + "_._Quit": "Keluar", + "_._Add": "Tambah", + "FrmMain.MnuChangeBackgroundColor": "Ubah warna latar belakang…", + "FrmMain.MnuToggleToolbar": "Palang Alat", + "FrmAbout._Contact": "Hubungan", + "FrmSettings.Toolbar._AddCustomButton": "Tambah satu butang suai…", + "FrmCrop.BtnQuickSelect._Tooltip": "Pilih pantas…", + "FrmMain.MnuCutFile._Success": "Potong {0} fail(s).", + "FrmSettings._ZoomSpeed": "Kelajuan zum", + "FrmMain.MnuToggleTopMost._Disable": "Tetingkap sentiasa di atas dilumpuhkan", + "FrmSettings._ShouldUseExplorerSortOrder": "Use Explorer sort order if possible", + "_.ImageInterpolation._Antisotropic": "Antisotropic", + "FrmMain._ReachedFirstImage": "Pada imej pertama", + "_._UnhandledException": "Pengecualian tidak dikendali", + "FrmResize.LblNewSize": "New Size:", + "FrmMain._ClipboardImage": "Imej papan keratan", + "FrmMain.MnuExportFrames": "Eksport bingkai imej…", + "FrmMain.MnuFile": "Fail", + "_._Close": "Tutup", + "FrmMain.MnuMain": "Menu utama", + "_._ResetToDefault": "Tetap semula ke lalai", + "FrmSettings.Nav._Gallery": "Galeri", + "FrmMain.MnuSetDefaultPhotoViewer._Success": "Anda berjaya menetapkan ImageGlass sebagai pelihat foto lalai.", + "FrmSettings._HideGalleryInFullscreen": "Sembunyi galeri dalam mod skrin penuh", + "FrmSettings._AvailableImageInfoTags": "Tag tersedia:", + "FrmExportFrames._Exporting": "Mengeksport {0}/{1} bingkai \n{2}…", + "_._Argument": "Argumen", + "FrmSettings._ImageEditQuality": "Kualiti imej", + "_._ID": "ID", + "FrmSettings._UserConfigFile": "Fail tetapan pengguna (igconfig.json)", + "FrmMain.MnuLoadingOrders": "Memuatkan urutan", + "FrmSettings._OpenSaveAsDialogInTheCurrentImageDir": "Buka dialog Simpan Sebagai dalam direktori imej semasa", + "_.MouseWheelEvent._ShiftAndScroll": "Tahan Shift dan tatal", + "FrmSettings._UseSmoothZooming": "Guna pengezuman licin", + "FrmSettings._Theme": "Tema", + "FrmSettings._ImageBoosterCacheMaxDimension": "Dimensi maksimum imej yang dicache (dalam piksel)", + "FrmMain.MnuScaleToHeight": "Skala ikut tinggi", + "_.Metadata._FileLastWriteTime": "Tarikh diubah suai", + "FrmSettings._Author": "Pengarang", + "FrmSettings._Others": "Lain-lain", + "_.MouseWheelAction._PanVertically": "Lata atas / bawah", + "FrmSettings._MouseWheelAction": "Tindakan roda tetikus", + "FrmSettings.Nav._Tools": "Alatan", + "FrmMain.MnuSetDesktopBackground._Error": "Tidak dapat menetapkan imej yang dilihat sebagai latar belakang atas meja", + "FrmSettings.Toolbar._Errors._ButtonExecutableRequired": "Boleh laku butang diperlukan.", + "_.ImageOrderBy._DateAccessed": "Tarikh dicapai", + "FrmSettings._ThumbnailSize": "Saiz imej kenit (dalam piksel)", + "FrmSettings._FileFormats": "Format fail", + "FrmMain.MnuReloadImageList": "Muat semula senarai imej", + "FrmSettings._UseWebview2ForSvg": "Guna Webview2 untuk melihat format SVG", + "FrmCrop.BtnCopy": "Salin", + "FrmSettings._CurrentMonitorProfile._Description": "ImageGlass tidak auto-kemas kini warna ketika bergerak antara monitor", + "FrmMain.PicMain._ErrorText": "Tidak dapat membuka imej ini", + "FrmSettings.Tools._AddNewTool": "Tambah satu alat luar", + "FrmMain.MnuRename": "Nama semula imej…", + "FrmMain.MnuViewLastFrame": "Lihat bingkai terakhir", + "_._Webview2._NotFound": "Sila pasang versi terkini Masa Jalan WebView2.", + "FrmMain.MnuGetMoreTools": "Dapatkan lagi alatan…", + "FrmSettings.Nav._Appearance": "Penampilan", + "FrmSettings._SlideshowInterval": "Sela tayangan slaid:", + "_.ImageInterpolation._HighQualityBicubic": "Dwikuib kualiti tinggi", + "FrmColorPickerSettings.ChkShowHsvA": "Guna format HSV dengan nilai alfa", + "FrmSettings.Tools._EditTool": "Sunting alat luar", + "_._Error": "Ralat", + "FrmSettings._ImageBoosterCacheMaxFileSizeInMb": "Saiz fail imej maksimum yang dicache (dalam megabait)", + "_._UnhandledException._Description": "Pengecualian tidak dikendali berlaku. Jika anda klik Teruskan, aplikasi akan abaikan ralat ini dan cuba teruskan. Jika anda klik Keluar, aplikasi akan ditutup serta-merta.", + "_.Metadata._FileSize": "Saiz fail", + "FrmSettings.Toolbar._ButtonJson": "JSON butang", + "FrmQuickSetup._SetDefaultViewer._Description": "Anda boleh menetap semulanya di dalam tetapan apl > tab Perkaitan jenis fail.", + "FrmSettings.Nav._Edit": "Sunting", + "FrmMain.MnuToggleGallery": "Panel galeri", + "_._IgCommandExe._DefaultError._Description": "Pastikan anda sudah luluskan perintah yang betul!\r\nFail boleh laku ini mengandungi fungsi baris-perintah untuk perisian ImageGlass.\r\n\r\nUntuk mengetahui semua baris perintah, sila rujuk:\n{0}", + "FrmMain.MnuLosslessCompression._Compressing": "Melakukan mampatan tak hilang…", + "FrmSettings._ShouldGroupImagesByDirectory": "Kelompok imej mengikut direktori", + "FrmMain.MnuPanToRightSide": "Lata imej ke sisi kanan", + "_.Metadata._ExifRatingPercent": "Penarafan", + "FrmSettings._PanSpeed": "Kelajuan penataan", + "_._CheckForUpdate": "Periksa kemas kini…", + "FrmSettings.Layout._ToolbarContext": "Palang alat konteksual", + "_.ImageInfo._FrameCount": "{0} bingkai(s)", + "FrmMain.MnuLayout": "Bentangan", + "_._Website": "Tapak Sesawang", + "FrmMain.MnuPasteImage": "Tampal imej", + "FrmSettings._ShowGalleryScrollbars": "Tunjuk palang tatal galeri" + } +} \ No newline at end of file diff --git a/Setup/Assets/Language/Norwegian Bokmal.iglang.json b/Setup/Assets/Language/Norwegian Bokmal.iglang.json new file mode 100644 index 000000000..40eda46d9 --- /dev/null +++ b/Setup/Assets/Language/Norwegian Bokmal.iglang.json @@ -0,0 +1,504 @@ +{ + "_Metadata": { + "Code": "nb-NO", + "EnglishName": "Norwegian Bokmål", + "LocalName": "Norsk bokmål", + "Author": "baardisk, rubberfork", + "MinVersion": "9.3" + }, + "Items": { + "FrmCrop.SelectionAspectRatio._Original": "Opprinnelig", + "FrmMain.MnuShare._Error": "Dialogvinduet for deling kunne ikke åpnes.", + "_.Metadata._FileLastAccessTime": "Lastet", + "FrmAbout._License": "Programvarelisens", + "FrmSettings.Toolbar._Errors._ButtonIdDuplicated": "En knapp med ID '{0}' er allerede definert. ID-en brukes av en annen knapp. Opprett en unik ID for å hindre konflikter.", + "FrmMain.MnuSave._Confirm": "Er du sikker på at du vil overskrive dette bildet?", + "FrmSettings._OpenDefaultAppsSetting": "Åpne innstillinger for standardapper i Windows", + "FrmMain.MnuCopyPath": "Kopier filbane", + "FrmCropSettings.DefaultSelectionType._SelectNone": "Ingen utvalg", + "_.MouseWheelAction._PanHorizontally": "Panorer venstre / høyre", + "FrmMain.MnuPrint": "Skriv ut…", + "FrmSettings.Toolbar._ToolbarButtons": "Knapper for verktøylinje", + "FrmResize.LblResample": "Omsample", + "_.ImageOrderBy._Extension": "Filtype", + "FrmSettings.Nav._Viewer": "Fremviser", + "FrmSettings.EditAppDialog._EditApp": "Legg til et program for redigering", + "FrmCrop.BtnReset._Tooltip": "Tilbakestill utvalg", + "FrmMain.MnuRename._Description": "Angi et nytt filnavn:", + "_._No": "No", + "FrmSlideshow.MnuToggleCountdown": "Vis nedtelling for lysbildefremvisning", + "FrmSettings._OpenStartupAppsSetting": "Åpne innstillinger for oppstartsapper", + "FrmMain.MnuViewPreviousFrame": "Vis forrige bilderute", + "_.ImageOrderBy._DateModified": "Endret", + "FrmMain.MnuViewNextFrame": "Vis neste bilderute", + "FrmMain.MnuUnload": "Slutt å vise bildet", + "FrmSettings.Toolbar._HideToolbarInFullscreen": "Hide toolbar in Full Screen mode", + "_.ImageOrderType._Desc": "Synkende", + "_._Update": "Update", + "FrmSettings._EnableImageAsyncLoading": "Enable image asynchronous loading", + "FrmSettings._DefaultPhotoViewer._Description": "Register the supported formats of ImageGlass with Windows. You might need to open the Default apps settings and manually select ImageGlass from the list for it to take effect.", + "_.MouseWheelAction._BrowseImages": "View next / previous Image", + "FrmSettings._EditApps": "Programmer for bilderedigering", + "FrmColorPickerSettings.ChkShowCIELabA": "Use CIELAB format with alpha value", + "_._GetHelp": "Få hjelp", + "FrmQuickSetup._SkipQuickSetup": "Skip this and launch ImageGlass", + "FrmColorPickerSettings._Title": "Color picker settings", + "_._Copy": "Kopier", + "FrmSettings._ImageBoosterCacheCount": "Antall bilder forhåndslastet av Bildebooster (én retning)", + "FrmMain.MnuPanToBottom": "Panorer til bunnen", + "FrmMain.MnuZoom": "Zoom", + "FrmCropSettings.ChkCloseToolAfterSaving": "Close Crop tool after saving", + "FrmSettings._ShowWelcomeImage": "Vis velkomstbilde", + "FrmSettings._ColorProfile": "Fargeprofil", + "FrmSettings._Theme._UninstallTheme": "Uninstall a theme pack", + "FrmMain._OpenWith": "Åpne med {0}", + "FrmMain.MnuRemoveDefaultPhotoViewer": "Fjern standard bildevisningsprogram", + "_.AfterEditAppAction._Nothing": "Ingenting", + "FrmCrop.BtnSave": "Lagre", + "FrmMain.MnuScaleToFit": "Skaler til å passe", + "FrmToolNotFound.LblDownloadToolText": "You can download more tools for ImageGlass at:", + "_._LearnMore": "Lær mer…", + "FrmCrop.LblAspectRatio": "Visningsforhold:", + "FrmExportFrames._FileNotExist": "Image file does not exist", + "FrmSettings._LightTheme": "Light", + "FrmSettings.Nav._Slideshow": "Lysbildefremvisning", + "_._Continue": "Fortsett", + "_._AddHotkey": "Legg til hurtigtast…", + "FrmMain.MnuSetDesktopBackground": "Angi som skrivebordsbakgrunn", + "FrmMain.MnuReload": "Last inn bilde på nytt", + "FrmSlideshow.MnuExitSlideshow": "Avslutt lysbildefremvisning", + "FrmMain.MnuAutoZoom": "Autozoom", + "FrmSettings._ShowImagePreview": "Vis forhåndsvisning av bilde mens det lastes", + "FrmCrop.BtnCopy._Tooltip": "Copy the selection to clipboard", + "FrmSettings.Nav._Toolbar": "Verktøylinje", + "FrmMain.MnuSave._Error": "Kunne ikke lagre bildet", + "FrmSettings._AfterEditingAction": "Etter åpning av redigeringsapplikasjon", + "FrmSettings._ShouldUseColorProfileForAll": "Bruk også for bilder uten innebygd fargeprofil", + "FrmCropSettings.DefaultSelectionType._UseTheLastSelection": "Use the last selection", + "FrmSettings._SlideshowInterval._From": "Fra", + "FrmSettings._ImageInterpolation": "Image interpolation", + "FrmQuickSetup._StepInfo": "Step {0}", + "FrmMain.MnuColorPicker": "Fargevelger", + "FrmCrop.SelectionAspectRatio._FreeRatio": "Free ratio", + "FrmSettings._ResetSettings": "Reset settings", + "FrmSettings._Startup": "Oppstart", + "_.BackdropStyle._None": "Ingen", + "FrmSettings._LoadDefaultZoomLevels": "Load default zoom levels", + "FrmColorPicker.BtnSettings._Tooltip": "Open Color picker settings…", + "FrmSettings._UseThemeForDarkMode": "Use this theme for dark mode", + "FrmSettings._ShowDeleteConfirmation": "Vis bekreftelsesdialog ved sletting av fil", + "FrmSettings._ShowAppIcon": "Vise programikonet i tittellinjen", + "_._InvalidAction": "Invalid action", + "FrmQuickSetup._SelectProfile": "Velg profil", + "_.Metadata._FileCreationTime": "Date created", + "FrmSettings._SlideshowImagesToNotifySound": "Antall bilder for å utløse en varsellyd", + "FrmSettings._BackgroundColor": "Viewer background color", + "FrmSettings._RealTimeFileUpdate": "Sanntidsoppdatering av filer", + "_.ColorProfileOption._CurrentMonitorProfile": "Current monitor profile", + "FrmSettings._EnableCutMultipleFiles": "Tillat utklipping av flere filer samtidig", + "FrmSettings._AutoUpdate": "Se etter oppdateringer automatisk", + "FrmCropSettings.LblDefaultSelection": "Default selection", + "FrmSettings._UseThemeForLightMode": "Bruk dette som lyst tema", + "FrmSettings._ZoomLevels": "Forstørrelsesnivåer", + "FrmMain.MnuSetLockScreen._Success": "Lock screen image is updated", + "FrmSettings._ShowGalleryFileName": "Show thumbnail filename", + "FrmSettings.Layout._Order": "Order", + "FrmCropSettings.ChkAutoCenterSelection": "Auto-center selection", + "FrmSettings.Nav._FileTypeAssociations": "Filassosiasjoner", + "_._Back": "Tilbake", + "FrmMain.MnuSetDesktopBackground._Success": "Desktop background is updated", + "FrmSettings._ShouldAutoOpenNewAddedImage": "Åpne nytillagte bilder automatisk", + "FrmCrop.SelectionAspectRatio._Custom": "Tilpasning…", + "FrmMain.MnuCopyPath._Success": "Copied the current image path.", + "FrmSettings._StartupBoost._Error": "Could not change Startup Boost setting", + "FrmToolNotFound.LblDescription": "ImageGlass was unable to locate the path to the '{0}' executable. To resolve this issue, please update the path to the '{0}' as necessary.", + "FrmMain.MnuClearClipboard": "Tøm utklippstavlen", + "FrmSettings._ColorManagement": "Fargebehandling", + "FrmMain._ReachedLastLast": "Det siste bildet er nådd", + "FrmMain.MnuPanUp": "Panorer oppover", + "FrmMain.MnuRemoveDefaultPhotoViewer._Success": "ImageGlass er ikke lenger standard bildeviser.", + "FrmSettings._GetMoreLanguagePacks": "Skaff flere språkpakker…", + "FrmAbout._Privacy": "Privacy policy", + "FrmSettings._EnableRecursiveLoading": "Last bilder i undermapper", + "_._UserAction._MethodArgumentNotSupported": "Argumenttypen for metoden '{0}' støttes ikke", + "FrmSettings._FileExtensionIcons._Description": "For customizing file extension icons, download an icon pack, place all .ICO files in the extension icon folder, and click the '{0}' button. This will also set ImageGlass as default photo viewer.", + "_.ImageOrderType._Asc": "Stigende", + "FrmExportFrames._Title": "Export image frames", + "_._Install": "Installer…", + "FrmMain.MnuFlipHorizontal": "Vend horisontalt", + "FrmSettings._OpenExtensionIconFolder": "Open extension icon folder", + "FrmAbout._Collaborator": "Samarbeidspartner:", + "FrmQuickSetup._ConfirmCloseProcess": "Before applying the new settings, it's essential to close all ImageGlass processes. Ønsker du å fortsette?", + "FrmExportFrames._ExportDone": "Exported {0} frames successfully to \r\n{1}", + "FrmCrop.BtnSaveAs._Tooltip": "Save as a copy…", + "FrmMain.MnuOpenFile": "Åpne fil…", + "FrmColorPickerSettings.ChkShowRgbA": "Use RGB format with alpha value", + "_.ImageInfo._ListCount": "{0} fil(er)", + "FrmMain.MnuGoToLast": "Gå til siste bilde", + "FrmSettings._EditApps._AppName": "Applikasjonsnavn", + "FrmSettings._SlideshowBackgroundColor": "Bakgrunnsfarge for bildefremvisning", + "FrmAbout._Email": "E-post:", + "_.MouseWheelAction._DoNothing": "Ikke gjør noe", + "FrmMain.MnuSaveAs": "Lagre som…", + "FrmMain._Loading": "Laster…", + "_._Browse": "Bla gjennom…", + "FrmMain.MnuSetDefaultPhotoViewer._Error": "Could not set ImageGlass as default photo viewer.", + "FrmSettings.Nav._Language": "Språk", + "FrmQuickSetup._SeeWhatNew": "See what's new in this version…", + "FrmSettings._ImageInterpolation._ScaleUp": "When zoom > 100%", + "FrmSettings.Layout._ToolbarContextPosition": "Contextual toolbar position", + "FrmMain.MnuDeleteFromHardDisk": "Permanent sletting", + "FrmSettings._EmbeddedThumbnail": "Innebygget miniatyrbilde", + "FrmMain.MnuDeleteFromHardDisk._Description": "Vil du slette denne filen for godt?", + "FrmMain.MnuScaleToFill": "Skaler til å fylle", + "FrmCrop.BtnCrop": "Crop", + "_.AfterEditAppAction._Minimize": "Minimer", + "FrmMain.MnuInvertColors": "Invert colors", + "FrmSettings._StartupBoost": "Startup Boost", + "FrmMain.MnuViewFirstFrame": "Vis første bilderute", + "_.MouseWheelEvent._CtrlAndScroll": "Hold Ctrl and scroll", + "FrmSettings._HideMainWindowInSlideshow": "Skjul hovedvinduet automatisk", + "_.Metadata._FrameCount": "Bilder", + "FrmSettings._EnableCopyMultipleFiles": "Tillat kopiering av flere filer samtidig", + "FrmMain.MnuFrameless._EnableDescription": "Hold Shift key to move the window.", + "_.ImageOrderBy._ExifDateTaken": "EXIF: Date taken", + "FrmAbout._Credits": "Medvirkende", + "FrmSettings._AddNewFileExtension": "Add new file extension", + "FrmMain.MnuQuickSetup": "Open ImageGlass Quick Setup", + "FrmMain.MnuSave._Success": "Bildet ble lagret", + "FrmMain.MnuPanLeft": "Panorer til venstre", + "FrmUpdate._StatusChecking": "Checking for update…", + "FrmSettings.Nav._Layout": "Sideoppsett", + "FrmMain.MnuOpenWith": "Åpne med…", + "FrmAbout._Thanks": "Spesiell takk til:", + "_._Warning": "Advarsel", + "FrmSettings.Nav._Keyboard": "Tastatur", + "FrmSlideshow._PauseSlideshow": "Lysbildevisning er satt på pause.", + "_._Add+": "Legg til…", + "_._Email": "E-post", + "FrmMain.MnuPanDown": "Panorer nedover", + "_._Cancel": "Avbryt", + "_._OK": "OK", + "FrmMain.MnuPanRight": "Panorer til høyre", + "_.Position._Right": "Høyre", + "_._Icon": "Ikon", + "FrmSettings._ShouldLoadHiddenImages": "Last skjulte bilder", + "_._InvalidAction._Transformation": "ImageGlass does not support rotation, flipping for this image.", + "FrmSettings._MakeDefault": "Make default", + "FrmMain.MnuCopyImageData._Copying": "Kopierer bildedata. Dette vil ta litt tid…", + "FrmSettings._UseEmbeddedThumbnailRawFormats": "Last kun inn innebygde miniatyrbilder for RAW-format", + "_.ImageInterpolation._Linear": "Linear", + "FrmSettings._ImageInfoTags": "Image information tags", + "FrmSettings._FileExtensionIcons": "File extension icons", + "FrmMain.MnuEdit._AppNotFound": "Kunne ikke finne det valgte bildebehandlingsprogrammet. Angi et bildebehandlingsprogram for å redigere denne filtypen i Imageglass innstillinger > Redigere.", + "_.ColorProfileOption._None": "Ingen", + "FrmSettings._TotalSupportedFormats": "Total supported formats: {0}", + "FrmSettings._Clipboard": "Utklippstavle", + "_._UserAction._Win32ExeError": "Kan ikke kjøre kommandoen '{0}'. Sjekk at navnet stemmer.", + "FrmCropSettings.DefaultSelectionType._SelectX": "Select {0}", + "_.AfterEditAppAction._Close": "Lukk", + "FrmAbout._LogoDesigner": "Logodesign:", + "_.ImageOrderBy._Name": "Navn (standard)", + "FrmMain.MnuRemoveDefaultPhotoViewer._Error": "Kunne ikke fjerne ImageGlass som standard bildeviser.", + "FrmExportFrames._FolderPickerTitle": "Select output folder for exporting image frames", + "FrmAbout._Donate": "Donere", + "FrmMain.MnuFrameNav": "Frame navigation", + "FrmMain.MnuSetLockScreen": "Angi som låseskjermbilde", + "_._Delete": "Slett", + "FrmMain.MnuViewPrevious": "Vis forrige side", + "_.Position._Top": "Topp", + "FrmSettings.Toolbar._CurrentButtons": "Current buttons:", + "FrmMain.MnuAbout": "Om", + "FrmSettings._RemoveDefault": "Remove default", + "_._Description": "Beskrivelse", + "FrmMain.MnuPasteImage._Error": "Could not find image data in the Clipboard", + "FrmMain.MnuSettings": "Innstillinger", + "FrmCropSettings._Title": "Crop settings", + "FrmSettings.Toolbar._ToolbarIconHeight": "Ikonstørrelse på verktøylinje", + "FrmSettings._SlideshowInterval._To": "Til", + "FrmSettings.Layout._ToolbarPosition": "Plassering av verktøylinje", + "FrmUpdate._StatusUpdated": "You are using the latest version!", + "FrmMain.MnuExit": "Avslutt", + "_._Webview2._Outdated": "Your WebView2 Runtime is not supported. Please update to version {0} or later.", + "_._Yes": "Ja", + "FrmMain.MnuRotateLeft": "Roter mot venstre", + "FrmSettings._EnableStartupBoost": "Enable Startup Boost", + "_.ImageOrderBy._ExifRating": "EXIF: Rating", + "FrmMain.MnuZoomIn": "Zoom inn", + "_.Metadata._ColorSpace": "Fargerom", + "FrmAbout._Version": "Versjon:", + "FrmMain.MnuToggleTopMost._Enable": "Enabled window always on top", + "FrmSettings.Toolbar._AvailableButtons": "Available buttons:", + "FrmMain.MnuSave._Saving": "Lagrer bildet…", + "FrmQuickSetup._StandardUser": "Standardbruker", + "FrmMain.MnuSetLockScreen._Error": "Could not set the viewing image as lock screen image", + "FrmSettings.Nav._Image": "Bilde", + "FrmSettings._Theme._InstallTheme": "Install theme packs", + "FrmSettings._EnableMultiInstances": "Tillat flere forekomster av programmet", + "FrmMain.MnuCropTool": "Crop image", + "_._IgCommandExe._DefaultError._Heading": "Invalid commands", + "_._Refresh": "Oppdater", + "FrmMain.MnuLosslessCompression._Description": "This tool uses Magick.NET library for lossless compression, optimizing file size. Overwrites only if the compressed file is smaller than the original.", + "_._MoveDown": "Flytt ned", + "FrmSettings._GetExtensionIconPacks": "Get extension icon packs…", + "FrmSettings._InAppMessageDuration": "Varighet på programbeskjeder (millisekunder)", + "FrmMain.MnuFrameless": "Rammeløs", + "_._Reset": "Tilbakestill", + "FrmSettings._ConfigDir": "Configuration location", + "FrmQuickSetup._SettingsWillBeApplied": "Settings will be applied:", + "FrmSettings._UnmanagedSettingReminder": "This setting is not managed by ImageGlass. Don't forget to disable it before you remove or relocate the app because ImageGlass does not handle this automatically.", + "FrmMain.MnuClipboard": "Utklippstavle", + "FrmMain.MnuCustomZoom": "Tilpasset zoom…", + "FrmSettings._DisplayLanguage": "Display language", + "FrmMain.MnuPrint._Error": "Utskrift av bildet feilet", + "FrmSettings._ShouldPreserveModifiedDate": "Behold bildets endringsdato ved lagring", + "FrmSettings._ShowSaveOverrideConfirmation": "Vis bekreftelsesdialog ved overskriving av fil", + "FrmColorPickerSettings.ChkShowHexA": "Use HEX format with alpha value", + "FrmMain.MnuFullScreen": "Full Screen", + "FrmSettings._StartupDir": "Startup location", + "FrmSettings._ShowCheckerboardOnlyImageRegion": "Show checkerboard only within the image region", + "FrmMain.MnuClearClipboard._Success": "Cleared clipboard.", + "FrmQuickSetup._Text": "ImageGlass Quick Setup", + "FrmMain.MnuLosslessCompression._Done": "Done lossless compression.\r\nThe new file size is {0}, saved {1}.", + "FrmMain.MnuLosslessCompression": "Magick.NET Lossless Compression", + "FrmResize.RadResizeByPercentage": "Percentage", + "FrmSettings._StartupBoost._Disabled": "Startup Boost is disabled", + "FrmMain.MnuToggleCheckerboard": "Sjakkmønstret bakgrunn", + "FrmSettings._MinEmbeddedThumbnailSize._Height": "Høyde", + "FrmSettings.Nav._General": "Generelt", + "FrmSettings._ImageLoading": "Bildet laster", + "FrmSettings._ShowSlideshowCountdown": "Vis nedtelling for lysbildefremvisning", + "FrmMain.MnuSave": "Lagre", + "FrmMain.MnuMoveToRecycleBin": "Flytt til papirkurven", + "FrmMain.MnuRefresh": "Oppdater", + "FrmToolNotFound.LblHeading": "'{0}' is not found!", + "FrmMain.MnuReportIssue": "Rapporter et problem…", + "FrmMain.MnuCopyImageData": "Kopier bildedata", + "FrmMain.MnuCheckForUpdate._NewVersion": "En ny versjon er tilgjengelig!", + "_._Empty": "(tom)", + "FrmSettings._Zooming": "Forstørrelse", + "FrmMain.MnuCutFile": "Cut file", + "FrmHotkeyPicker.LblHotkey": "Press hotkeys", + "FrmSettings.Layout._Gallery": "Galleri", + "FrmMain.MnuNewWindow": "Åpne nytt vindu", + "FrmMain.MnuMoveToRecycleBin._Description": "Ønsker du å flytte denne filen til papirkurven?", + "FrmSettings._DefaultPhotoViewer": "Default photo viewer", + "_.Metadata._ExifDateTimeOriginal": "EXIF: DateTimeOriginal", + "FrmMain.MnuRotateRight": "Roter mot høyre", + "FrmSettings._MinEmbeddedThumbnailSize": "Minimum størrelse på miniatyrbilder som lastes inn", + "FrmMain.MnuSetDefaultPhotoViewer": "Set default photo viewer", + "FrmMain.MnuImageProperties": "Bildeegenskaper", + "FrmSettings._EnableNavigationButtons": "Show navigation arrow buttons", + "_._Edit": "Rediger", + "FrmSettings._ImageBooster": "Bildebooster", + "FrmSettings.Tools._IntegratedWith": "Integrated with {0}", + "_._Next": "Neste", + "FrmExportFrames._OpenOutputFolder": "Open output folder", + "FrmMain.MnuOpenLocation": "Åpne bildeplassering", + "FrmMain.MnuLockZoom": "Lås forstørrelsesforhold", + "FrmSettings._StartupBoost._Description": "Preload and run ImageGlass in the background for a few seconds during Windows startup to accelerate the first launch.", + "FrmSettings._WindowBackdrop": "Window backdrop", + "FrmSettings._EnableRealTimeFileUpdate": "Se etter endringer og oppdater visningsmappen i sanntid", + "_._NotSupported": "Formatet støttes ikke", + "FrmSettings._Theme._GetMoreThemes": "Get more theme packs…", + "FrmMain.MnuNewWindow._Error": "Kan ikke åpne nytt vindu, kun én instans er tillatt", + "FrmMain.MnuZoomOut": "Zoom ut", + "FrmSettings.Toolbar._EditButton": "Edit toolbar button", + "FrmMain.MnuCustomZoom._Description": "Skriv inn ny zoom verdi", + "FrmResize.RadResizeByPixels": "Pixels", + "FrmMain.MnuEdit": "Rediger bilde {0}…", + "FrmSettings.Layout._GalleryPosition": "Gallery position", + "FrmMain.MnuWindowFit": "Window Fit", + "FrmMain._OpenFileDialog": "Alle støttede filer", + "FrmSettings._UseRandomIntervalForSlideshow": "Bruk tilfeldig intervall", + "_.Position._Left": "Venstre", + "FrmSettings._ShouldOpenLastSeenImage": "Åpne sist viste bilde", + "_.Position._Bottom": "Nederst", + "FrmResize.ChkKeepRatio": "Keep ratio propotional", + "FrmMain.MnuGoTo": "Gå til…", + "FrmSlideshow.MnuPauseResumeSlideshow": "Pause/resume slideshow", + "FrmSettings.Tools._Integrated": "Integrated", + "FrmSettings._Contributors": "Contributors", + "_.MouseWheelAction._Zoom": "Zoom in / out", + "_._CommandPreview": "Forhåndsvisning av kommando", + "FrmSettings._DarkTheme": "Dark", + "_._Hotkeys": "Hurtigtaster", + "_.Metadata._ExifDateTime": "EXIF: DateTime", + "FrmSettings.Toolbar._Errors._ButtonIdRequired": "Button ID required.", + "FrmSettings._MinEmbeddedThumbnailSize._Width": "Bredde", + "_._Executable": "Kjørbar fil", + "_.ImageInterpolation._MultiSampleLinear": "Multi-sample linear", + "_._Separator": "Skilletegn", + "FrmQuickSetup._ProfessionalUser": "Professional user", + "FrmMain.MnuFlipVertical": "Vend vertikalt", + "FrmSlideshow._ResumeSlideshow": "Lysbildefremvisningen er gjenopptatt.", + "FrmCropSettings.DefaultSelectionType._CustomArea": "Custom area…", + "FrmMain.MnuActualSize": "Faktisk størrelse", + "FrmCrop.BtnSaveAs": "Lagre som…", + "FrmSettings._InstallNewLanguagePack": "Install new language packs…", + "FrmSlideshow.MnuZoomModes": "Zoom modes", + "FrmMain.MnuTools": "Verktøy", + "_.ImageInterpolation._Cubic": "Cubic", + "FrmUpdate._LatestVersion": "The latest version: {0}", + "FrmMain.MnuViewNext": "Vis neste bilde", + "_.MouseWheelEvent._AltAndScroll": "Hold Alt and scroll", + "FrmToolNotFound._Title": "Tool not found", + "FrmCrop.BtnCrop._Tooltip": "Crop the image only", + "FrmSettings.EditAppDialog._AddApp": "Legg til et program for redigering", + "FrmMain.MnuPanning": "Panorering", + "_._MoveUp": "Flytt opp", + "FrmCropSettings.DefaultSelectionType._SelectAll": "Select all", + "_._Name": "Navn", + "FrmColorPickerSettings.ChkShowHslA": "Use HSL format with alpha value", + "FrmMain.MnuToggleImageAnimation": "Start / stopp animering av bilde", + "FrmSettings._DisableStartupBoost": "Disable Startup Boost", + "FrmMain.MnuCopyFile._Success": "Kopierte {0} fil(er).", + "FrmMain.MnuSave._ConfirmDescription": "ImageGlass er ikke en profesjonell bildebehandler, vær klar over at kvalitet, metadata, lag,… kan gå tapt ved lagring av bilder.", + "FrmToolNotFound.BtnSelectExecutable": "Select…", + "FrmUpdate._StatusOutdated": "A new update is available!", + "_.ImageOrderBy._Random": "Tilfeldig", + "FrmResize.LblCurrentSize": "Current Size:", + "_._Apply": "Bruk", + "FrmAbout._Slogan": "Et lettvektig, allsidig bildevisningsprogram", + "FrmMain.MnuPanToTop": "Panorer til toppen", + "FrmSettings.Toolbar._AddNewButton": "Add a custom toolbar button", + "FrmCrop.LblSize": "Størrelse:", + "FrmSettings._ImageInterpolation._ScaleDown": "When zoom < 100%", + "_._CreatingFileError": "Kunne ikke opprette midlertidig bildefil", + "FrmMain.MnuGoTo._Description": "Angi bildenummer og trykk deretter på Enter", + "FrmSettings.Toolbar._EnableCenterToolbar": "Use center alignment for toolbar", + "FrmMain.MnuResizeTool": "Resize image", + "FrmSettings.Layout._Toolbar": "Verktøylinje", + "FrmMain.MnuHelp": "Hjelp", + "_.ImageOrderBy._FileSize": "Filstørrelse", + "FrmSettings._Theme._OpenThemeFolder": "Åpne temamappe", + "FrmMain.MnuNavigation": "Naviger", + "_._Save": "Lagre", + "FrmQuickSetup._SettingProfileDescription": "To modify these settings, simply access app settings.", + "_._UserAction._MenuNotFound": "Menyalternativet \"{0}\" ble ikke funnet og kan ikke utføres", + "FrmMain.MnuPanToLeftSide": "Panorer helt til venstre", + "FrmUpdate._CurrentVersion": "Current version: {0}", + "FrmCrop.BtnSettings._Tooltip": "Open Crop tool settings", + "_.ColorProfileOption._Custom": "Tilpasning…", + "FrmSettings._UseEmbeddedThumbnailOtherFormats": "Last kun inn innebygde miniatyrbilder for øvrige formater", + "FrmMain.MnuGoToFirst": "Gå til første bilde", + "FrmSettings._ExportLanguagePack": "Export language pack…", + "FrmSettings.Nav._Mouse": "Mus", + "_.ImageOrderBy._DateCreated": "Date created", + "FrmSettings._EnableFullscreenSlideshow": "Start lysbildefremvisning i fullskjerm", + "FrmAbout._Homepage": "Hjemmeside:", + "FrmSettings._GalleryCacheSizeInMb": "Maximum gallery cache size (in megabytes)", + "FrmMain.MnuCopyImageData._Success": "Kopierte gjeldende bildedata.", + "FrmSettings._EnableLoopBackNavigation": "Gå tilbake til første bilde etter siste bildet i listen", + "_.MouseWheelEvent._Scroll": "Scroll", + "FrmCrop.BtnSave._Tooltip": "Lagre bilde", + "FrmMain.MnuSlideshow": "Lysbildefremvisning", + "FrmMain.MnuShare": "Del…", + "FrmSettings._SlideshowNotification": "Varsel om lysbildefremvisning", + "FrmMain.MnuViewChannels": "Vis kanaler", + "FrmSettings._Refresh": "Oppdater", + "_._UserAction._MethodNotFound": "Metoden '{0}' ble ikke funnet og kan ikke utføres", + "FrmMain.MnuCopyFile": "Kopier fil", + "_._CreatingFile": "Oppretter en midlertidig bildefil…", + "FrmMain.MnuToggleTopMost": "Hold vinduet alltid øverst", + "FrmMain.MnuLosslessCompression._Confirm": "Are you sure you want to proceed?", + "FrmMain.MnuImage": "Bilde", + "FrmSettings._StartupBoost._Enabled": "Startup Boost is enabled", + "FrmQuickSetup._SetDefaultViewer": "Do you want to set ImageGlass as the default photo viewer?", + "FrmMain.MnuScaleToWidth": "Skaler til bredde", + "_._FileExtension": "Filendelse", + "FrmUpdate._PublishedDate": "Published date: {0}", + "_._DoNotShowThisMessageAgain": "Ikke vis denne meldingen igjen", + "_.ImageInterpolation._NearestNeighbor": "Nearest neighbor", + "FrmCrop.LblLocation": "Sted:", + "_._Download": "Last ned", + "_.Metadata._ColorProfile": "Fargeprofil", + "FrmSettings._CenterWindowFit": "Automatically center the window in Window Fit mode", + "FrmSettings._ImageLoadingOrder": "Bildelasterekkefølge", + "FrmSettings._GalleryColumns": "Number of thumbnail columns in vertical gallery layout", + "_._Quit": "Avslutt", + "_._Add": "Legg til", + "FrmMain.MnuChangeBackgroundColor": "Change background color…", + "FrmMain.MnuToggleToolbar": "Verktøylinje", + "FrmAbout._Contact": "Kontakt", + "FrmSettings.Toolbar._AddCustomButton": "Add a custom button…", + "FrmCrop.BtnQuickSelect._Tooltip": "Quick select…", + "FrmMain.MnuCutFile._Success": "Klipp ut {0} fil(er).", + "FrmSettings._ZoomSpeed": "Zoom speed", + "FrmMain.MnuToggleTopMost._Disable": "Disabled window always on top", + "FrmSettings._ShouldUseExplorerSortOrder": "Use Explorer sort order if possible", + "_.ImageInterpolation._Antisotropic": "Anisotropisk", + "FrmMain._ReachedFirstImage": "Det første bildet er nådd", + "_._UnhandledException": "Ukjent feil", + "FrmResize.LblNewSize": "New Size:", + "FrmMain._ClipboardImage": "Clipboard image", + "FrmMain.MnuExportFrames": "Export image frames…", + "FrmMain.MnuFile": "Fil", + "_._Close": "Lukk", + "FrmMain.MnuMain": "Hovedmeny", + "_._ResetToDefault": "Nullstill", + "FrmSettings.Nav._Gallery": "Galleri", + "FrmMain.MnuSetDefaultPhotoViewer._Success": "You have successfully set ImageGlass as default photo viewer.", + "FrmSettings._HideGalleryInFullscreen": "Hide gallery in Full Screen mode", + "FrmSettings._AvailableImageInfoTags": "Available tags:", + "FrmExportFrames._Exporting": "Exporting {0}/{1} frames \r\n{2}…", + "_._Argument": "Argument", + "FrmSettings._ImageEditQuality": "Bildekvalitet", + "_._ID": "ID", + "FrmSettings._UserConfigFile": "Fil for brukerinnstillinger (igconfig.json)", + "FrmMain.MnuLoadingOrders": "Loading orders", + "FrmSettings._OpenSaveAsDialogInTheCurrentImageDir": "Open the Save As dialog in the current image directory", + "_.MouseWheelEvent._ShiftAndScroll": "Hold Shift and scroll", + "FrmSettings._UseSmoothZooming": "Use smooth zooming", + "FrmSettings._Theme": "Tema", + "FrmSettings._ImageBoosterCacheMaxDimension": "Høyeste bildeoppløsning som skal forhåndsinnleses (i pixler)", + "FrmMain.MnuScaleToHeight": "Skaler til høyde", + "_.Metadata._FileLastWriteTime": "Date modified", + "FrmSettings._Author": "Forfatter", + "FrmSettings._Others": "Andre", + "_.MouseWheelAction._PanVertically": "Pan up / down", + "FrmSettings._MouseWheelAction": "Mouse wheel action", + "FrmSettings.Nav._Tools": "Verktøy", + "FrmMain.MnuSetDesktopBackground._Error": "Could not set the viewing image as desktop background", + "FrmSettings.Toolbar._Errors._ButtonExecutableRequired": "Button executable required.", + "_.ImageOrderBy._DateAccessed": "Lastet", + "FrmSettings._ThumbnailSize": "Thumbnail size (in pixels)", + "FrmSettings._FileFormats": "File formats", + "FrmMain.MnuReloadImageList": "Last in bildeliste", + "FrmSettings._UseWebview2ForSvg": "Use Webview2 for viewing SVG format", + "FrmCrop.BtnCopy": "Kopier", + "FrmSettings._CurrentMonitorProfile._Description": "ImageGlass bytter ikke fargeprofil automatisk når vinduet flyttes mellom skjermer", + "FrmMain.PicMain._ErrorText": "Kunne ikke åpne dette bildet", + "FrmSettings.Tools._AddNewTool": "Add an external tool", + "FrmMain.MnuRename": "Endre navn på bilde…", + "FrmMain.MnuViewLastFrame": "Vis siste bilderute", + "_._Webview2._NotFound": "Please install WebView2 Runtime to access full features of ImageGlass.", + "FrmMain.MnuGetMoreTools": "Get more tools…", + "FrmSettings.Nav._Appearance": "Utseende", + "FrmSettings._SlideshowInterval": "Intervall for lysbildefremvisning:", + "_.ImageInterpolation._HighQualityBicubic": "Bikubisk (høy kvalitet)", + "FrmColorPickerSettings.ChkShowHsvA": "Use HSV format with alpha value", + "FrmSettings.Tools._EditTool": "Edit external tool", + "_._Error": "Feil", + "FrmSettings._ImageBoosterCacheMaxFileSizeInMb": "Maks størrelse på bilder som skal forhåndsinnleses (i megabyte)", + "_._UnhandledException._Description": "En ukjent feil har oppstått. Klikk på Fortsett for å ignorere feilen og prøve å gå videre. Klikk på Avslutt for å lukke programmet ummidelbart.", + "_.Metadata._FileSize": "Filstørrelse", + "FrmSettings.Toolbar._ButtonJson": "Button JSON", + "FrmQuickSetup._SetDefaultViewer._Description": "You can reset it in the app settings > File type associations tab.", + "FrmSettings.Nav._Edit": "Rediger", + "FrmMain.MnuToggleGallery": "Gallery panel", + "_._IgCommandExe._DefaultError._Description": "Make sure you pass the correct commands!\r\nDenne kjørbare filen inneholder kommandolinje-funksjoner for ImageGlass.\r\n\r\nTo explore all command lines, please visit:\r\n{0}", + "FrmMain.MnuLosslessCompression._Compressing": "Performing lossless compression…", + "FrmSettings._ShouldGroupImagesByDirectory": "Grupper bilder etter katalog", + "FrmMain.MnuPanToRightSide": "Panorer helt til høyre", + "_.Metadata._ExifRatingPercent": "Vurdering", + "FrmSettings._PanSpeed": "Panning speed", + "_._CheckForUpdate": "Se etter oppdatering…", + "FrmSettings.Layout._ToolbarContext": "Contextual toolbar", + "_.ImageInfo._FrameCount": "{0} bilde(r)", + "FrmMain.MnuLayout": "Sideoppsett", + "_._Website": "Nettside", + "FrmMain.MnuPasteImage": "Paste image", + "FrmSettings._ShowGalleryScrollbars": "Show gallery scrollbars" + } +} \ No newline at end of file diff --git a/Setup/Assets/Language/Persian.iglang.json b/Setup/Assets/Language/Persian.iglang.json new file mode 100644 index 000000000..bfd487ab0 --- /dev/null +++ b/Setup/Assets/Language/Persian.iglang.json @@ -0,0 +1,504 @@ +{ + "_Metadata": { + "Code": "fa-IR", + "EnglishName": "Persian", + "LocalName": "فارسی", + "Author": "Surena", + "MinVersion": "9.3" + }, + "Items": { + "FrmCrop.SelectionAspectRatio._Original": "اصلی", + "FrmMain.MnuShare._Error": "کادر گفت‌و‌گوی هم‌رسانی باز نمی‌شود.", + "_.Metadata._FileLastAccessTime": "تاريخ دسترسي", + "FrmAbout._License": "مجوز نرم‌افزار", + "FrmSettings.Toolbar._Errors._ButtonIdDuplicated": "یک دکمه با شناسه '{0}' پیشتر تعریف شده است. لطفا برای جلوگیری از تداخل، یک شناسه متفاوت و منحصر‌به‌فرد برای دکمه خود انتخاب کنید.", + "FrmMain.MnuSave._Confirm": "آیا مطمئنید که می‌خواهید این تصویر را رونویسی کنید؟\n", + "FrmSettings._OpenDefaultAppsSetting": "تنظیم برنامه‌های پیش‌فرض باز شود", + "FrmMain.MnuCopyPath": "روگرفت مسیر تصویر", + "FrmCropSettings.DefaultSelectionType._SelectNone": "انتخاب هیچ‌کدام", + "_.MouseWheelAction._PanHorizontally": "حرکت به چپ / راست", + "FrmMain.MnuPrint": "چاپ…", + "FrmSettings.Toolbar._ToolbarButtons": "دکمه‌های نوار ابزار", + "FrmResize.LblResample": "نمونه گیری مجدد:", + "_.ImageOrderBy._Extension": "افزونه", + "FrmSettings.Nav._Viewer": "نمایش‌گر", + "FrmSettings.EditAppDialog._EditApp": "برنامه ویرایش", + "FrmCrop.BtnReset._Tooltip": "بازنشانی انتخاب", + "FrmMain.MnuRename._Description": "یک نام فایل جدید وارد کنید:", + "_._No": "خیر", + "FrmSlideshow.MnuToggleCountdown": "نمایش شمارش معکوس اسلاید", + "FrmSettings._OpenStartupAppsSetting": "برنامه‌های راه‌انداز را در تنظیمات باز‌کنید", + "FrmMain.MnuViewPreviousFrame": "نمایش قاب قبلی", + "_.ImageOrderBy._DateModified": "تاریخ اصلاح\n", + "FrmMain.MnuViewNextFrame": "مشاهده قاب بعدی", + "FrmMain.MnuUnload": "عدم بارگزاری تصویر", + "FrmSettings.Toolbar._HideToolbarInFullscreen": "نوار ابزار در حالت تمام صفحه پنهان شود", + "_.ImageOrderType._Desc": "نزولی", + "_._Update": "بروزرسانی", + "FrmSettings._EnableImageAsyncLoading": "فعال کردن بارگذاری غیرهمزمان تصاویر", + "FrmSettings._DefaultPhotoViewer._Description": "فرمت های پشتیبانی شده ImageGlass را در ویندوز ثبت کنید. ممکن است لازم باشد تنظیمات برنامه های پیش فرض را باز کنید و ImageGlass را به صورت دستی از لیست انتخاب کنید تا اعمال شود.", + "_.MouseWheelAction._BrowseImages": "مشاهده تصویر بعدی / قبلی", + "FrmSettings._EditApps": "برنامه‌های ویرایش تصویر", + "FrmColorPickerSettings.ChkShowCIELabA": "استفاده از قالب CIELAB همراه با مقدار آلفا", + "_._GetHelp": "کمک دریافت کنید", + "FrmQuickSetup._SkipQuickSetup": "از این گذر کرده و ImageGlass اجرا شود", + "FrmColorPickerSettings._Title": "تنظیمات انتخاب‌گر رنگ", + "_._Copy": "روگرفت", + "FrmSettings._ImageBoosterCacheCount": "تعداد تصاویر ذخیره شده توسط شتاب‌دهنده تصویر (یک طرفه)", + "FrmMain.MnuPanToBottom": "حرکت تصویر به زیر", + "FrmMain.MnuZoom": "بزرگ‌نمایی", + "FrmCropSettings.ChkCloseToolAfterSaving": "ابزار چینش پس از ذخیره بسته شود", + "FrmSettings._ShowWelcomeImage": "نمایش تصویر خوش آمد گویی", + "FrmSettings._ColorProfile": "نمایه رنگ", + "FrmSettings._Theme._UninstallTheme": "حذف یک بسته پوسته", + "FrmMain._OpenWith": "بازنمایی با {0}", + "FrmMain.MnuRemoveDefaultPhotoViewer": "حذف مشاهده‌گر عکس پیش‌فرض", + "_.AfterEditAppAction._Nothing": "هیچ", + "FrmCrop.BtnSave": "ذخیره", + "FrmMain.MnuScaleToFit": "به نسبت ابعاد", + "FrmToolNotFound.LblDownloadToolText": "شما می‌توانید ابزارهای بیشتری برای ImageGlass بارگیری کنید در:", + "_._LearnMore": "بیشتر بدانید…", + "FrmCrop.LblAspectRatio": "نسبت ابعاد:", + "FrmExportFrames._FileNotExist": "فایل تصویر وجود ندارد", + "FrmSettings._LightTheme": "روشن", + "FrmSettings.Nav._Slideshow": "نمایش نمابرگ", + "_._Continue": "ادامه", + "_._AddHotkey": "افزودن کلید میانبر…", + "FrmMain.MnuSetDesktopBackground": "استفاده به‌عنوان تصویر پس‌زمینه", + "FrmMain.MnuReload": "بارگذاری مجدد تصویر", + "FrmSlideshow.MnuExitSlideshow": "خروج از نمایش نمابرگ", + "FrmMain.MnuAutoZoom": "بزرگ‌نمایی خودکار", + "FrmSettings._ShowImagePreview": "پیش‌نمایش تصویر در حین بارگیری نمایش داده شود", + "FrmCrop.BtnCopy._Tooltip": "روگرفت انتخابی به بریده‌دان", + "FrmSettings.Nav._Toolbar": "نوار ابزار", + "FrmMain.MnuSave._Error": "تصویر ذخیره نشد", + "FrmSettings._AfterEditingAction": "بعد از بازنمایی اپ ویرایش", + "FrmSettings._ShouldUseColorProfileForAll": "برای تصاویر بدون نمایه رنگ داخلی هم اعمال شود", + "FrmCropSettings.DefaultSelectionType._UseTheLastSelection": "از آخرین انتخاب استفاده شود", + "FrmSettings._SlideshowInterval._From": "از", + "FrmSettings._ImageInterpolation": "درون‌یابی تصویر", + "FrmQuickSetup._StepInfo": "گام {0}", + "FrmMain.MnuColorPicker": "انتخابگر رنگ", + "FrmCrop.SelectionAspectRatio._FreeRatio": "نسبت آزاد", + "FrmSettings._ResetSettings": "بازنشانی تنظیمات", + "FrmSettings._Startup": "راه‌اندازی", + "_.BackdropStyle._None": "هیچ کدام", + "FrmSettings._LoadDefaultZoomLevels": "سطوح بزرگ‌نمایی پیش‌فرض بارگیری شود", + "FrmColorPicker.BtnSettings._Tooltip": "بازنمایی تنظیمات انتخاب‌گر رنگ…", + "FrmSettings._UseThemeForDarkMode": "از این پوسته برای حالت تیره استفاده شود", + "FrmSettings._ShowDeleteConfirmation": "کادر گفت‌و‌گوی تایید هنگام حذف فایل نمایش داده شود", + "FrmSettings._ShowAppIcon": "شمایل برنامه روی نوار عنوان نمایش داده شود", + "_._InvalidAction": "اقدام نامعتبر است", + "FrmQuickSetup._SelectProfile": "یک نمایه انتخاب کنید", + "_.Metadata._FileCreationTime": "تاریخ ایجاد", + "FrmSettings._SlideshowImagesToNotifySound": "تعداد تصاویر برای ایجاد صدای اعلان", + "FrmSettings._BackgroundColor": "رنگ پس‌زمینه مشاهده‌گر", + "FrmSettings._RealTimeFileUpdate": "به‌روز‌رسانی بی‌درنگ فایل", + "_.ColorProfileOption._CurrentMonitorProfile": "نمایه نمایشگر کنونی", + "FrmSettings._EnableCutMultipleFiles": "برش چندین فایل در آن واحد فعال شود", + "FrmSettings._AutoUpdate": "بررسی خودکار به‌روزرسانی‌ها", + "FrmCropSettings.LblDefaultSelection": "انتخاب پیش‌فرض", + "FrmSettings._UseThemeForLightMode": "از این پوسته برای حالت روشن استفاده شود", + "FrmSettings._ZoomLevels": "سطح‌های بزرگنمایی", + "FrmMain.MnuSetLockScreen._Success": "تصویر قفل صفحه به‌روز شد", + "FrmSettings._ShowGalleryFileName": "نمایش نام فایل ریزعکس", + "FrmSettings.Layout._Order": "ترتیب", + "FrmCropSettings.ChkAutoCenterSelection": "انتخاب میانه‌خودکار", + "FrmSettings.Nav._FileTypeAssociations": "پیوستگی‌های نوع فایل", + "_._Back": "بازگشت", + "FrmMain.MnuSetDesktopBackground._Success": "پس‌زمینه دسکتاپ به‌روز شد", + "FrmSettings._ShouldAutoOpenNewAddedImage": "تصویر جدید اضافه شده به‌صورت خودکار باز شود", + "FrmCrop.SelectionAspectRatio._Custom": "دلخواه…", + "FrmMain.MnuCopyPath._Success": "مسیر تصویر کنونی روگرفت شد.", + "FrmSettings._StartupBoost._Error": "تنظیمات تقویت کننده راه انداز قابل تغییر نیست", + "FrmToolNotFound.LblDescription": "ImageGlass نتوانست مسیر اجرایی '{0}' را بیابد. برای حل این مشکل، لطفا مسیر '{0}' را در صورت لزوم به‌روز کنید.", + "FrmMain.MnuClearClipboard": "پاک‌سازی بریده‌دان", + "FrmSettings._ColorManagement": "مدیریت رنگ", + "FrmMain._ReachedLastLast": "به آخرین تصویر رسید", + "FrmMain.MnuPanUp": "حرکت تصویر به بالا", + "FrmMain.MnuRemoveDefaultPhotoViewer._Success": "ImageGlass دیگر مشاهده‌گر عکس پیش‌فرض نیست.", + "FrmSettings._GetMoreLanguagePacks": "دریافت بسته‌های زبان بیشتر…", + "FrmAbout._Privacy": "حریم خصوصی", + "FrmSettings._EnableRecursiveLoading": "بارگیری تصاویر در زیر پوشه‌ها", + "_._UserAction._MethodArgumentNotSupported": "نوع استدلال روش '{0}' پشتیبانی نمی‌شود", + "FrmSettings._FileExtensionIcons._Description": "برای سفارشی‌سازی شمایل قالب فایل، یک بسته شمایل بارگیری کرده، همه فایل‌های .ICO را در پوشه شمایل قالب قرار داده و روی دکمه '{0}' کلیک کنید. این کار ImageGlass را به‌عنوان مشاهده‌گر عکس پیش‌فرض تعیین خواهد کرد.", + "_.ImageOrderType._Asc": "صعودی", + "FrmExportFrames._Title": "برون‌برد قاب‌های تصویر", + "_._Install": "نصب…", + "FrmMain.MnuFlipHorizontal": "چرخش افقی", + "FrmSettings._OpenExtensionIconFolder": "بازنمایی پوشه شمایل قالب", + "FrmAbout._Collaborator": "همکار:", + "FrmQuickSetup._ConfirmCloseProcess": "قبل از اعمال تنظیمات جدید، بستن تمام فرایندهای ImageGlass ضروری است. آیا برای ادامه کار آماده هستید؟", + "FrmExportFrames._ExportDone": "{0} قاب با موفقیت برون‌برد شد به \n{1}", + "FrmCrop.BtnSaveAs._Tooltip": "ذخیره به‌عنوان یک روگرفت…", + "FrmMain.MnuOpenFile": "بازنمایی فایل…", + "FrmColorPickerSettings.ChkShowRgbA": "استفاده از قالب RGB همراه با مقدار آلفا", + "_.ImageInfo._ListCount": "{0} فایل", + "FrmMain.MnuGoToLast": "برو به تصویر آخر", + "FrmSettings._EditApps._AppName": "نام برنامه", + "FrmSettings._SlideshowBackgroundColor": "رنگ پس‌زمینه نمایش نمابرگ", + "FrmAbout._Email": "رایانامه:", + "_.MouseWheelAction._DoNothing": "کاری انجام نشود", + "FrmMain.MnuSaveAs": "ذخیره به‌عنوان…", + "FrmMain._Loading": "در حال بارگیری…", + "_._Browse": "مرور…", + "FrmMain.MnuSetDefaultPhotoViewer._Error": "ImageGlass به‌عنوان مشاهده‌گر عکس پیش‌فرض تعیین نشد.", + "FrmSettings.Nav._Language": "زبان", + "FrmQuickSetup._SeeWhatNew": "ببینید چه چیزی در این نسخه جدید است…", + "FrmSettings._ImageInterpolation._ScaleUp": "هنگامی که بزرگ‌نمایی بیشتر از ۱۰۰% است", + "FrmSettings.Layout._ToolbarContextPosition": "موقعیت نوار ابزار زمینه‌ای", + "FrmMain.MnuDeleteFromHardDisk": "حذف دائمی", + "FrmSettings._EmbeddedThumbnail": "ریزعکس جاسازی‌شده", + "FrmMain.MnuDeleteFromHardDisk._Description": "آیا مطمئنید که می‌خواهید این فایل را برای همیشه حذف کنید؟", + "FrmMain.MnuScaleToFill": "به نسبت صفحه", + "FrmCrop.BtnCrop": "چینش", + "_.AfterEditAppAction._Minimize": "کمینه‌سازی", + "FrmMain.MnuInvertColors": "معکوس کردن رنگها", + "FrmSettings._StartupBoost": "سریع شدن شروع", + "FrmMain.MnuViewFirstFrame": "مشاهده قاب نخست", + "_.MouseWheelEvent._CtrlAndScroll": "Ctrl و scroll را نگه دارید", + "FrmSettings._HideMainWindowInSlideshow": "پنهان‌سازی خودکار پنجره اصلی", + "_.Metadata._FrameCount": "قاب‌ها", + "FrmSettings._EnableCopyMultipleFiles": "روگرفت چندین فایل در آن واحد فعال شود", + "FrmMain.MnuFrameless._EnableDescription": "برای جابجایی پنجره کلید SHIFT را نگه دارید.", + "_.ImageOrderBy._ExifDateTaken": "ExIf: تاریخ انتخابی", + "FrmAbout._Credits": "سازندگان", + "FrmSettings._AddNewFileExtension": "افزودن قالب فایل جدید", + "FrmMain.MnuQuickSetup": "بازنمایی راه‌اندازی سریع ImageGlass", + "FrmMain.MnuSave._Success": "تصویر ذخیره شد", + "FrmMain.MnuPanLeft": "حرکت تصویر به چپ", + "FrmUpdate._StatusChecking": "درحال بررسی به‌روزرسانی…", + "FrmSettings.Nav._Layout": "چیدمان", + "FrmMain.MnuOpenWith": "بازنمایی با…", + "FrmAbout._Thanks": "با تشکر ویژه از:", + "_._Warning": "هشدار", + "FrmSettings.Nav._Keyboard": "صفحه کلید", + "FrmSlideshow._PauseSlideshow": "نمایش اسلاید متوقف است.", + "_._Add+": "افزودن…", + "_._Email": "رایانامه", + "FrmMain.MnuPanDown": "حرکت تصویر به پایین", + "_._Cancel": "لغو", + "_._OK": "تاييد", + "FrmMain.MnuPanRight": "حرکت تصویر به راست", + "_.Position._Right": "Right", + "_._Icon": "شمایل", + "FrmSettings._ShouldLoadHiddenImages": "بارگیری تصاویر پنهان", + "_._InvalidAction._Transformation": "ImageGlass از چرخش و برگرداندن برای این تصویر پشتیبانی نمی‌کند.", + "FrmSettings._MakeDefault": "تنظیم به‌عنوان پیش‌فرض", + "FrmMain.MnuCopyImageData._Copying": "در حال روگرفت داده‌های تصویر. ممکن است مدتی طول بکشد…", + "FrmSettings._UseEmbeddedThumbnailRawFormats": "فقط بارگیری ریزعکس جاسازی‌شده برای قالب‌های خام", + "_.ImageInterpolation._Linear": "خطی", + "FrmSettings._ImageInfoTags": "برچسب‌های اطلاعات تصویر", + "FrmSettings._FileExtensionIcons": "شمایل قالب فایل", + "FrmMain.MnuEdit._AppNotFound": "برنامه مرتبط برای ویرایش یافت نشد. شما می‌توانید یک برنامه برای ویرایش این قالب در تنظیمات ImageGlass > ویرایش اختصاص دهید.", + "_.ColorProfileOption._None": "هیچ کدام", + "FrmSettings._TotalSupportedFormats": "مجموع قالب‌های پشتیبانی شده: {0}", + "FrmSettings._Clipboard": "بریده‌دان", + "_._UserAction._Win32ExeError": "فرمان '{0}' قابل اجرا نیست. مطمئن شوید که نام صحیح است.", + "FrmCropSettings.DefaultSelectionType._SelectX": "انتخاب {0}", + "_.AfterEditAppAction._Close": "بستن", + "FrmAbout._LogoDesigner": "طراح نشان‌واره:", + "_.ImageOrderBy._Name": "نام (پیش‌فرض)", + "FrmMain.MnuRemoveDefaultPhotoViewer._Error": "حذف ImageGlass به‌عنوان مشاهده‌گر عکس پیش‌فرض انجام نشد.", + "FrmExportFrames._FolderPickerTitle": "پوشه خروجی را برای برون‌برد قاب‌های تصویر انتخاب کنید", + "FrmAbout._Donate": "کمک مالی", + "FrmMain.MnuFrameNav": "پیمایش قاب", + "FrmMain.MnuSetLockScreen": "تنظیم به‌عنوان تصویر قفل صفحه", + "_._Delete": "حذف", + "FrmMain.MnuViewPrevious": "نمایش تصویر قبلی", + "_.Position._Top": "بالا", + "FrmSettings.Toolbar._CurrentButtons": "دکمه‌های فعلی:", + "FrmMain.MnuAbout": "درباره", + "FrmSettings._RemoveDefault": "حذف پیش‌فرض", + "_._Description": "توضیحات", + "FrmMain.MnuPasteImage._Error": "داده‌های تصویر در بریده‌دان یافت نشد", + "FrmMain.MnuSettings": "تنظیمات", + "FrmCropSettings._Title": "تنظیمات چینش", + "FrmSettings.Toolbar._ToolbarIconHeight": "اندازه آیکون نوار ابزار", + "FrmSettings._SlideshowInterval._To": "به", + "FrmSettings.Layout._ToolbarPosition": "موقعیت نوار ابزار", + "FrmUpdate._StatusUpdated": "شما در حال استفاده از آخرین نسخه هستید!", + "FrmMain.MnuExit": "خروج", + "_._Webview2._Outdated": "WebView2 Runtime شما پشتیبانی نمی‌شود. لطفا به نسخه {0} یا جدیدتر ارتقا دهید.", + "_._Yes": "بلی", + "FrmMain.MnuRotateLeft": "چرخش به چپ", + "FrmSettings._EnableStartupBoost": "فعال کردن سریع سازی شروع", + "_.ImageOrderBy._ExifRating": "EXIF: امتیاز", + "FrmMain.MnuZoomIn": "افزایش بزرگ‌نمایی", + "_.Metadata._ColorSpace": "فضای رنگی", + "FrmAbout._Version": "نسخه:", + "FrmMain.MnuToggleTopMost._Enable": "پنجره فعال همیشه در بالا", + "FrmSettings.Toolbar._AvailableButtons": "دکمه‌های موجود:", + "FrmMain.MnuSave._Saving": "در حال ذخیره تصویر…\n", + "FrmQuickSetup._StandardUser": "کاربر معمولی", + "FrmMain.MnuSetLockScreen._Error": "نمی‌توان تصویر در حال مشاهده را به‌عنوان تصویر قفل صفحه تعیین کرد", + "FrmSettings.Nav._Image": "تصویر", + "FrmSettings._Theme._InstallTheme": "نصب بسته‌های پوسته", + "FrmSettings._EnableMultiInstances": "اجازه چند مورد از برنامه", + "FrmMain.MnuCropTool": "چینش تصویر", + "_._IgCommandExe._DefaultError._Heading": "فرامین نامعتبر است", + "_._Refresh": "تازه‌سازی", + "FrmMain.MnuLosslessCompression._Description": "این ابزار از کتابخانه Magick.NET برای فشرده‌سازی بدون افت کیفیت و بهینه‌سازی حجم فایل استفاده می‌کند. فقط زمانی که فایل فشرده کوچکتر از فایل اصلی باشد جایگزین شود.", + "_._MoveDown": "انتقال به پایین", + "FrmSettings._GetExtensionIconPacks": "دریافت بسته‌های شمایل قالب…", + "FrmSettings._InAppMessageDuration": "مدت زمان پیام درون‌برنامه (میلی‌ثانیه)", + "FrmMain.MnuFrameless": "بدون فریم", + "_._Reset": "بازنشانی", + "FrmSettings._ConfigDir": "محل پیکربندی", + "FrmQuickSetup._SettingsWillBeApplied": "تنظیمات اعمال خواهند شد:", + "FrmSettings._UnmanagedSettingReminder": "این تنظیم توسط ImageGlass مدیریت نمی‌شود. فراموش نکنید که قبل از حذف یا انتقال برنامه، آن را غیرفعال کنید زیرا این کار به‌طور خودکار توسط ImageGlass انجام نمی‌شود.", + "FrmMain.MnuClipboard": "بریده‌دان", + "FrmMain.MnuCustomZoom": "بزرگ‌نمایی دلخواه…", + "FrmSettings._DisplayLanguage": "زبان نمایشی", + "FrmMain.MnuPrint._Error": "تصویر در حال مشاهده چاپ نشد", + "FrmSettings._ShouldPreserveModifiedDate": "حفظ تاریخ اصلاح تصویر هنگام ذخیره‌سازی", + "FrmSettings._ShowSaveOverrideConfirmation": "کادر گفت‌و‌گوی تایید هنگام رونویسی فایل نمایش داده شود", + "FrmColorPickerSettings.ChkShowHexA": "استفاده از قالب HEX همراه با مقدار آلفا", + "FrmMain.MnuFullScreen": "تمام صفحه", + "FrmSettings._StartupDir": "محل راه‌اندازی", + "FrmSettings._ShowCheckerboardOnlyImageRegion": "نمایش صفحه شطرنجی فقط درون منطقه تصویر", + "FrmMain.MnuClearClipboard._Success": "بریده‌دان پاک‌سازی شده.", + "FrmQuickSetup._Text": "راه‌اندازی سریع ImageGlass", + "FrmMain.MnuLosslessCompression._Done": "فشرده‌سازی بدون افت کیفیت انجام شد.\r\nحجم فایل جدید {0} است، {1} فشرده‌سازی شد.", + "FrmMain.MnuLosslessCompression": "Magick.NET فشرده سازی بدون افت کیفیت", + "FrmResize.RadResizeByPercentage": "درصد", + "FrmSettings._StartupBoost._Disabled": "سریع سازی شروع، غیر فعال شد", + "FrmMain.MnuToggleCheckerboard": "پس‌زمینه شطرنجی", + "FrmSettings._MinEmbeddedThumbnailSize._Height": "ارتفاع", + "FrmSettings.Nav._General": "عمومی", + "FrmSettings._ImageLoading": "بارگیری تصویر", + "FrmSettings._ShowSlideshowCountdown": "نمایش شمارش معکوس اسلاید", + "FrmMain.MnuSave": "ذخیره", + "FrmMain.MnuMoveToRecycleBin": "انتقال به سطل بازیافت", + "FrmMain.MnuRefresh": "تازه‌سازی", + "FrmToolNotFound.LblHeading": "'{0}' یافت نشد!", + "FrmMain.MnuReportIssue": "گزارش مشکل…", + "FrmMain.MnuCopyImageData": "روگرفت داده تصویر", + "FrmMain.MnuCheckForUpdate._NewVersion": "نسخه جدید در دسترس است!", + "_._Empty": "(خالی)", + "FrmSettings._Zooming": "در حال بزرگنمایی", + "FrmMain.MnuCutFile": "برش فایل", + "FrmHotkeyPicker.LblHotkey": "کلیدهای میانبر را فشار دهید", + "FrmSettings.Layout._Gallery": "نگارکده", + "FrmMain.MnuNewWindow": "بازنمایی پنجره جدید", + "FrmMain.MnuMoveToRecycleBin._Description": "آیا می‌خواهید این فایل را به سطل بازیافت منتقل کنید؟", + "FrmSettings._DefaultPhotoViewer": "مشاهده‌گر عکس پیش‌فرض", + "_.Metadata._ExifDateTimeOriginal": "EXIF: DateTimeOriginal", + "FrmMain.MnuRotateRight": "چرخش به راست", + "FrmSettings._MinEmbeddedThumbnailSize": "کمینه اندازه ریزعکس جاسازی‌شده برای بارگیری", + "FrmMain.MnuSetDefaultPhotoViewer": "تنظیم مشاهده‌گر عکس پیش‌فرض", + "FrmMain.MnuImageProperties": "مشخصات تصویر", + "FrmSettings._EnableNavigationButtons": "نمایش دکمه‌های پیکان پیمایشی", + "_._Edit": "ویرایش", + "FrmSettings._ImageBooster": "شتاب‌دهنده تصویر", + "FrmSettings.Tools._IntegratedWith": "یکپارچه شده با {0}", + "_._Next": "بعدی", + "FrmExportFrames._OpenOutputFolder": "بازنمایی پوشه خروجی", + "FrmMain.MnuOpenLocation": "بازنمایی مکان تصویر", + "FrmMain.MnuLockZoom": "قفل کردن نسبت بزرگ‌نمایی", + "FrmSettings._StartupBoost._Description": "برنامه ImageGlass را در پس زمینه برای چند ثانیه در حین بالا آمدن ویندوز پیش بارگذاری کنید تا اولین ورود با سرعت بیشتری انجام شود.", + "FrmSettings._WindowBackdrop": "پس‌آویز پنجره", + "FrmSettings._EnableRealTimeFileUpdate": "نظارت بر تغییرات فایل در پوشه در حال مشاهده و به‌روز‌رسانی بی‌درنگ", + "_._NotSupported": "قالب پشتیبانی نشده", + "FrmSettings._Theme._GetMoreThemes": "دریافت بسته‌های پوسته بیشتر…", + "FrmMain.MnuNewWindow._Error": "پنجره جدید باز نمی‌شود زیرا فقط یک مورد مجاز است", + "FrmMain.MnuZoomOut": "کاهش بزرگ‌نمایی", + "FrmSettings.Toolbar._EditButton": "ویرایش دکمه نوار ابزار", + "FrmMain.MnuCustomZoom._Description": "یک مقدار بزرگ‌نمایی دلخواه وارد کنید", + "FrmResize.RadResizeByPixels": "پیکسل", + "FrmMain.MnuEdit": "ویرایش تصویر {0}…", + "FrmSettings.Layout._GalleryPosition": "موقعیت نگارکده", + "FrmMain.MnuWindowFit": "متناسب پنچره", + "FrmMain._OpenFileDialog": "همه فایل‌های پشتیبانی شده", + "FrmSettings._UseRandomIntervalForSlideshow": "استفاده از فاصله تصادفی", + "_.Position._Left": "چپ", + "FrmSettings._ShouldOpenLastSeenImage": "بازنمایی آخرین تصویر دیده شده", + "_.Position._Bottom": "پایین", + "FrmResize.ChkKeepRatio": "حفظ تناسب اندازه", + "FrmMain.MnuGoTo": "برو به…", + "FrmSlideshow.MnuPauseResumeSlideshow": "مکث / از سرگیری نمایش نمابرگ", + "FrmSettings.Tools._Integrated": "یکپارچه", + "FrmSettings._Contributors": "مشارکت‌کنندگان", + "_.MouseWheelAction._Zoom": "بزرگ / کوچک نمایی", + "_._CommandPreview": "پیشنمایش فرمان", + "FrmSettings._DarkTheme": "تیره", + "_._Hotkeys": "کلیدهای میانبر", + "_.Metadata._ExifDateTime": "EXIF: DateTime", + "FrmSettings.Toolbar._Errors._ButtonIdRequired": "شناسه دکمه ضروری است.", + "FrmSettings._MinEmbeddedThumbnailSize._Width": "پهنا", + "_._Executable": "اجراپذیر", + "_.ImageInterpolation._MultiSampleLinear": "چند‌نمونه خطی", + "_._Separator": "جدا کننده", + "FrmQuickSetup._ProfessionalUser": "کاربر حرفه‌ای", + "FrmMain.MnuFlipVertical": "چرخش عمودی", + "FrmSlideshow._ResumeSlideshow": "نمایش اسلاید از سر گرفته شد.", + "FrmCropSettings.DefaultSelectionType._CustomArea": "ناحیه سفارشی…", + "FrmMain.MnuActualSize": "اندازه واقعی", + "FrmCrop.BtnSaveAs": "ذخیره به‌عنوان…", + "FrmSettings._InstallNewLanguagePack": "نصب بسته‌های زبان جدید…", + "FrmSlideshow.MnuZoomModes": "حالت‌های بزرگ‌نمایی", + "FrmMain.MnuTools": "ابزارها", + "_.ImageInterpolation._Cubic": "مکعبی", + "FrmUpdate._LatestVersion": "آخرین نسخه: {0}", + "FrmMain.MnuViewNext": "مشاهده تصویر بعدی", + "_.MouseWheelEvent._AltAndScroll": "Alt و scroll را نگه دارید", + "FrmToolNotFound._Title": "ابزار یافت نشد", + "FrmCrop.BtnCrop._Tooltip": "فقط چینش تصویر", + "FrmSettings.EditAppDialog._AddApp": "افزودن یک برنامه برای ویرایش", + "FrmMain.MnuPanning": "حرکت", + "_._MoveUp": "انتقال به بالا", + "FrmCropSettings.DefaultSelectionType._SelectAll": "انتخاب همه", + "_._Name": "نام", + "FrmColorPickerSettings.ChkShowHslA": "استفاده از قالب HSL همراه با مقدار آلفا", + "FrmMain.MnuToggleImageAnimation": "شروع / توقف تصویر متحرک", + "FrmSettings._DisableStartupBoost": "غیرفعال کردن شروع سریع", + "FrmMain.MnuCopyFile._Success": "{0} فایل روگرفت شد.", + "FrmMain.MnuSave._ConfirmDescription": "ImageGlass یک ویرایشگر عکس حرفه‌ای نیست، لطفا افت کیفیت، فرادادگان، لایه‌ها و… را هنگام ذخیره تصویر خود در نظر داشته باشید.", + "FrmToolNotFound.BtnSelectExecutable": "انتخاب…", + "FrmUpdate._StatusOutdated": "یک به‌روزرسانی جدید دردسترس است!", + "_.ImageOrderBy._Random": "تصادفی", + "FrmResize.LblCurrentSize": "اندازه کنونی", + "_._Apply": "اعمال", + "FrmAbout._Slogan": "یک نمایش‌گر تصویر سبک و روان", + "FrmMain.MnuPanToTop": "حرکت تصویر به روی", + "FrmSettings.Toolbar._AddNewButton": "افزودن یک دکمه نوار ابزار سفارشی", + "FrmCrop.LblSize": "اندازه:", + "FrmSettings._ImageInterpolation._ScaleDown": "هنگامی که بزرگ‌نمایی کمتر از ۱۰۰% است", + "_._CreatingFileError": "فایل تصویری موقت ایجاد نشد", + "FrmMain.MnuGoTo._Description": "برای مشاهده، نمایه تصویر را وارد کرده و سپس ENTER را فشار دهید", + "FrmSettings.Toolbar._EnableCenterToolbar": "از تراز وسط برای نوار ابزار استفاده شود", + "FrmMain.MnuResizeTool": "تغییر اندازه تصویر", + "FrmSettings.Layout._Toolbar": "نوار ابزار", + "FrmMain.MnuHelp": "راهنما", + "_.ImageOrderBy._FileSize": "اندازه فایل", + "FrmSettings._Theme._OpenThemeFolder": "بازکردن پوشه پوسته", + "FrmMain.MnuNavigation": "پیمایش", + "_._Save": "ذخیره", + "FrmQuickSetup._SettingProfileDescription": "برای اصلاح این تنظیمات، به‌سادگی به تنظیمات برنامه مراجعه کنید.", + "_._UserAction._MenuNotFound": "منوی '{0}' برای فراخوانی عمل یافت نشد", + "FrmMain.MnuPanToLeftSide": "حرکت تصویر به گوشه چپ", + "FrmUpdate._CurrentVersion": "نسخه کنونی: {0}", + "FrmCrop.BtnSettings._Tooltip": "بازنمایی تنظیمات ابزار چینش", + "_.ColorProfileOption._Custom": "دلخواه…", + "FrmSettings._UseEmbeddedThumbnailOtherFormats": "فقط بارگیری ریزعکس جاسازی‌شده برای دیگر قالب‌ها", + "FrmMain.MnuGoToFirst": "برو به تصویر نخست", + "FrmSettings._ExportLanguagePack": "برون‌برد بسته زبان…", + "FrmSettings.Nav._Mouse": "موشواره", + "_.ImageOrderBy._DateCreated": "تاریخ ایجاد", + "FrmSettings._EnableFullscreenSlideshow": "آغاز نمایش نمابرگ در حالت تمام صفحه", + "FrmAbout._Homepage": "صفحه اصلی:", + "FrmSettings._GalleryCacheSizeInMb": "بیشینه اندازه حافظه پنهانی گالری (به مگابایت)", + "FrmMain.MnuCopyImageData._Success": "داده‌های تصویر کنونی روگرفت شد.", + "FrmSettings._EnableLoopBackNavigation": "بازگشت به تصویر اول هنگام رسیدن به آخر فهرست تصویر", + "_.MouseWheelEvent._Scroll": "پیمایش", + "FrmCrop.BtnSave._Tooltip": "ذخیره تصویر", + "FrmMain.MnuSlideshow": "نمایش نمابرگ", + "FrmMain.MnuShare": "هم‌رسانی…", + "FrmSettings._SlideshowNotification": "اعلان نمایش نمابرگ", + "FrmMain.MnuViewChannels": "مشاهده کانال‌ها", + "FrmSettings._Refresh": "تازه‌سازی", + "_._UserAction._MethodNotFound": "روش '{0}' برای فراخوانی عمل یافت نشد", + "FrmMain.MnuCopyFile": "روگرفت فایل", + "_._CreatingFile": "در حال ایجاد یک فایل تصویری موقت…", + "FrmMain.MnuToggleTopMost": "حفظ پنجره همیشه در بالا", + "FrmMain.MnuLosslessCompression._Confirm": "آیا مطمئن هستید که می‌خواهید ادامه دهید؟\n", + "FrmMain.MnuImage": "تصویر", + "FrmSettings._StartupBoost._Enabled": "سریع شدن شروع فعال است", + "FrmQuickSetup._SetDefaultViewer": "آیا می‌خواهید ImageGlass را به‌عنوان مشاهده‌گر عکس پیش‌فرض تعیین کنید؟", + "FrmMain.MnuScaleToWidth": "به نسبت پهنا", + "_._FileExtension": "پسوند فایل", + "FrmUpdate._PublishedDate": "تاریخ انتشار: {0}", + "_._DoNotShowThisMessageAgain": "این پیام دیگر نشان داده نشود", + "_.ImageInterpolation._NearestNeighbor": "نزدیک‌ترین همسایگی", + "FrmCrop.LblLocation": "مکان:‏", + "_._Download": "بارگیری", + "_.Metadata._ColorProfile": "نمایه رنگ", + "FrmSettings._CenterWindowFit": "میانه خودکار پنجره در حالت متناسب پنچره", + "FrmSettings._ImageLoadingOrder": "ترتیب بارگیری تصویر", + "FrmSettings._GalleryColumns": "تعداد ستون‌های ریزعکس در طرح‌بندی عمودی نگارکده", + "_._Quit": "خروج", + "_._Add": "افزودن", + "FrmMain.MnuChangeBackgroundColor": "تغییر رنگ پس‌زمینه…", + "FrmMain.MnuToggleToolbar": "نوار ابزار", + "FrmAbout._Contact": "راه ارتباطی", + "FrmSettings.Toolbar._AddCustomButton": "یک دکمه سفارشی اضافه کنید…", + "FrmCrop.BtnQuickSelect._Tooltip": "انتخاب سریع…", + "FrmMain.MnuCutFile._Success": "{0} فایل بریده شد.", + "FrmSettings._ZoomSpeed": "سرعت بزرگ‌نمایی", + "FrmMain.MnuToggleTopMost._Disable": "پنجره غیرفعال همیشه در بالا", + "FrmSettings._ShouldUseExplorerSortOrder": "مرتب کردن ترتیب کاوشگر درصورت امکان", + "_.ImageInterpolation._Antisotropic": "ناهمسان‌گردی", + "FrmMain._ReachedFirstImage": "به اولین تصویر رسید", + "_._UnhandledException": "استثناء کنترل نشده", + "FrmResize.LblNewSize": "اندازه جدید:", + "FrmMain._ClipboardImage": "تصویر بریده‌دان", + "FrmMain.MnuExportFrames": "برون‌برد قاب‌های تصویر…", + "FrmMain.MnuFile": "فایل", + "_._Close": "بستن", + "FrmMain.MnuMain": "گزینه‌های اصلی", + "_._ResetToDefault": "بازگشت به تنظیمات پیشفرض", + "FrmSettings.Nav._Gallery": "نگارکده", + "FrmMain.MnuSetDefaultPhotoViewer._Success": "شما با موفقیت ImageGlass را به‌عنوان مشاهده‌گر عکس پیش‌فرض تعیین کردید.", + "FrmSettings._HideGalleryInFullscreen": "نگارکده در حالت تمام صفحه پنهان شود", + "FrmSettings._AvailableImageInfoTags": "برچسب‌های موجود:", + "FrmExportFrames._Exporting": "در حال برون‌برد {0}/{1} قاب \n{2}…", + "_._Argument": "استدلال", + "FrmSettings._ImageEditQuality": "کیفیت تصویر", + "_._ID": "شناسه", + "FrmSettings._UserConfigFile": "فایل تنظیمات کاربر (igconfig.json)", + "FrmMain.MnuLoadingOrders": "ترتیب‌های بارگیری", + "FrmSettings._OpenSaveAsDialogInTheCurrentImageDir": "باز کردن پنجره ذخیره با نام جدید در پوشه تصاویر جاری", + "_.MouseWheelEvent._ShiftAndScroll": "Shift و scroll را نگه دارید", + "FrmSettings._UseSmoothZooming": "از بزرگ‌نمایی روان استفاده شود", + "FrmSettings._Theme": "پوسته", + "FrmSettings._ImageBoosterCacheMaxDimension": "بیشینه ابعاد تصویری که باید ذخیره شود (به پیکسل)", + "FrmMain.MnuScaleToHeight": "به نسبت ارتفاع", + "_.Metadata._FileLastWriteTime": "تاریخ اصلاح\n", + "FrmSettings._Author": "سازنده", + "FrmSettings._Others": "سایر", + "_.MouseWheelAction._PanVertically": "حرکت به بالا / پایین", + "FrmSettings._MouseWheelAction": "کارکرد چرخ موشواره", + "FrmSettings.Nav._Tools": "ابزارها", + "FrmMain.MnuSetDesktopBackground._Error": "نمی‌توان تصویر در حال مشاهده را به‌عنوان پس‌زمینه دسکتاپ تعیین کرد", + "FrmSettings.Toolbar._Errors._ButtonExecutableRequired": "دکمه اجراپذیر نیاز است.", + "_.ImageOrderBy._DateAccessed": "تاريخ دسترسي", + "FrmSettings._ThumbnailSize": "ابعاد ریزعکس (به پیکسل)", + "FrmSettings._FileFormats": "قالب‌های فایل", + "FrmMain.MnuReloadImageList": "بارگذاری مجدد فهرست تصویر", + "FrmSettings._UseWebview2ForSvg": "از Webview2 برای مشاهده قالب SVG استفاده شود", + "FrmCrop.BtnCopy": "روگرفت", + "FrmSettings._CurrentMonitorProfile._Description": "ImageGlass هنگام انتقال پنجره‌اش بین نمایشگرها به‌طور خودکار رنگ را به‌روز‌رسانی نمی‌کند", + "FrmMain.PicMain._ErrorText": "این تصویر باز نشد", + "FrmSettings.Tools._AddNewTool": "افزودن یک ابزار خارجی", + "FrmMain.MnuRename": "تغییر نام تصویر…", + "FrmMain.MnuViewLastFrame": "مشاهده قاب آخر", + "_._Webview2._NotFound": "برای دسترسی به تمام ویژگی‌های ImageGlass، لطفا WebView2 Runtime را نصب کنید.", + "FrmMain.MnuGetMoreTools": "ابزارهای بیشتری دریافت کنید…", + "FrmSettings.Nav._Appearance": "ظاهر", + "FrmSettings._SlideshowInterval": "وقفه اسلاید:", + "_.ImageInterpolation._HighQualityBicubic": "دومکعبی با کیفیت بالا", + "FrmColorPickerSettings.ChkShowHsvA": "استفاده از قالب HSV همراه با مقدار آلفا", + "FrmSettings.Tools._EditTool": "ویرایش ابزار خارجی", + "_._Error": "خطا", + "FrmSettings._ImageBoosterCacheMaxFileSizeInMb": "بیشینه اندازه تصویری که باید ذخیره شود (به مگابایت)", + "_._UnhandledException._Description": "استثناء کنترل نشده رخ داده است. اگر روی ادامه کلیک کنید، برنامه این خطا را نادیده گرفته و سعی می‌کند ادامه دهد. اگر روی خروج کلیک کنید، برنامه بلافاصله بسته خواهد شد.", + "_.Metadata._FileSize": "اندازه فایل", + "FrmSettings.Toolbar._ButtonJson": "دکمه JSON", + "FrmQuickSetup._SetDefaultViewer._Description": "شما می‌توانید آن را در تنظیمات > زبانه پیوستگی‌های نوع فایل بازنشانی کنید.", + "FrmSettings.Nav._Edit": "ویرایش", + "FrmMain.MnuToggleGallery": "صفحه نگارکده", + "_._IgCommandExe._DefaultError._Description": "مطمئن شوید که دستورهای صحیح را وضع می‌کنید!\r\nاین فایل اجرایی شامل توابع خط‌فرمان برای نرم‌افزار ImageGlass می‌باشد.\r\n\r\nبرای کاوش همه خطوط فرمان، لطفا ببینید:\n{0}", + "FrmMain.MnuLosslessCompression._Compressing": "در حال اجرای فشرده‌سازی بدون افت کیفیت…", + "FrmSettings._ShouldGroupImagesByDirectory": "گروه‌بندی تصاویر بر اساس فهرست راهنما", + "FrmMain.MnuPanToRightSide": "حرکت تصویر به گوشه راست", + "_.Metadata._ExifRatingPercent": "امتیازدهی", + "FrmSettings._PanSpeed": "سرعت حرکت", + "_._CheckForUpdate": "بررسی به‌روزرسانی…", + "FrmSettings.Layout._ToolbarContext": "نوار ابزار زمینه‌ای", + "_.ImageInfo._FrameCount": "{0} قاب", + "FrmMain.MnuLayout": "چیدمان", + "_._Website": "تارنما", + "FrmMain.MnuPasteImage": "الصاق تصویر", + "FrmSettings._ShowGalleryScrollbars": "نمایش نوار نوردهای نگارکده" + } +} \ No newline at end of file diff --git a/Setup/Assets/Language/Polish.iglang.json b/Setup/Assets/Language/Polish.iglang.json new file mode 100644 index 000000000..e23a93619 --- /dev/null +++ b/Setup/Assets/Language/Polish.iglang.json @@ -0,0 +1,504 @@ +{ + "_Metadata": { + "Code": "pl-PL", + "EnglishName": "Polish", + "LocalName": "Polski", + "Author": "Daniel Wróblewski, Marek Koteluk, BestiaPL", + "MinVersion": "9.3" + }, + "Items": { + "FrmCrop.SelectionAspectRatio._Original": "Oryginalny", + "FrmMain.MnuShare._Error": "Nie można otworzyć okna dialogowego Udostępniania.", + "_.Metadata._FileLastAccessTime": "Data dostępu", + "FrmAbout._License": "Licencja oprogramowania", + "FrmSettings.Toolbar._Errors._ButtonIdDuplicated": "Przycisk z ID '{0}' został już zdefiniowany. Wybierz inny i unikalny identyfikator przycisku, aby uniknąć konfliktów.", + "FrmMain.MnuSave._Confirm": "Czy na pewno chcesz zastąpić ten obrazek?", + "FrmSettings._OpenDefaultAppsSetting": "Otwórz domyślne ustawienia aplikacji", + "FrmMain.MnuCopyPath": "Kopiuj ścieżkę obrazu", + "FrmCropSettings.DefaultSelectionType._SelectNone": "Odznacz wszystko", + "_.MouseWheelAction._PanHorizontally": "Przesuń w lewo / w prawo", + "FrmMain.MnuPrint": "Drukuj…", + "FrmSettings.Toolbar._ToolbarButtons": "Przyciski paska narzędzi", + "FrmResize.LblResample": "Resample:", + "_.ImageOrderBy._Extension": "Rozszerzenie", + "FrmSettings.Nav._Viewer": "Przeglądarka", + "FrmSettings.EditAppDialog._EditApp": "Edytuj aplikację", + "FrmCrop.BtnReset._Tooltip": "Zresetuj wybór", + "FrmMain.MnuRename._Description": "Wprowadź nową nazwę pliku:", + "_._No": "No", + "FrmSlideshow.MnuToggleCountdown": "Wyświetlaj odliczanie na pokazie slajdów", + "FrmSettings._OpenStartupAppsSetting": "Open Startup apps setting", + "FrmMain.MnuViewPreviousFrame": "Zobacz poprzednią ramkę", + "_.ImageOrderBy._DateModified": "Data modyfikacji", + "FrmMain.MnuViewNextFrame": "Zobacz następną ramkę", + "FrmMain.MnuUnload": "Zamknij obraz", + "FrmSettings.Toolbar._HideToolbarInFullscreen": "Ukryj pasek narzędzi w trybie pełnoekranowym", + "_.ImageOrderType._Desc": "Malejąco", + "_._Update": "Update", + "FrmSettings._EnableImageAsyncLoading": "Enable image asynchronous loading", + "FrmSettings._DefaultPhotoViewer._Description": "Register the supported formats of ImageGlass with Windows. You might need to open the Default apps settings and manually select ImageGlass from the list for it to take effect.", + "_.MouseWheelAction._BrowseImages": "Zobacz następny / poprzedni obraz", + "FrmSettings._EditApps": "Aplikacje do edycji obrazów", + "FrmColorPickerSettings.ChkShowCIELabA": "Użyj formatu CIELAB z wartością alfa", + "_._GetHelp": "Uzyskaj pomoc", + "FrmQuickSetup._SkipQuickSetup": "Pomiń to i uruchom ImageGlass", + "FrmColorPickerSettings._Title": "Ustawienia selektora kolorów", + "_._Copy": "Kopiuj", + "FrmSettings._ImageBoosterCacheCount": "Liczba obrazów zapisanych w buforze ImageBooster (w jednym kierunku)", + "FrmMain.MnuPanToBottom": "Przesuń obraz w dół", + "FrmMain.MnuZoom": "Powiększenie", + "FrmCropSettings.ChkCloseToolAfterSaving": "Zamknij narzędzie Przycinania po zapisie", + "FrmSettings._ShowWelcomeImage": "Pokaż obraz powitalny", + "FrmSettings._ColorProfile": "Profil kolorów", + "FrmSettings._Theme._UninstallTheme": "Odinstaluj pakiet motywu", + "FrmMain._OpenWith": "Otwórz z {0}", + "FrmMain.MnuRemoveDefaultPhotoViewer": "Usuń domyślną przeglądarkę zdjęć", + "_.AfterEditAppAction._Nothing": "Nic nie rób", + "FrmCrop.BtnSave": "Zapisz", + "FrmMain.MnuScaleToFit": "Dopasuj", + "FrmToolNotFound.LblDownloadToolText": "Możesz pobrać więcej narzędzi do ImageGlass na:", + "_._LearnMore": "Dowiedz się więcej…", + "FrmCrop.LblAspectRatio": "Współczynnik proporcji:", + "FrmExportFrames._FileNotExist": "Plik obrazu nie istnieje", + "FrmSettings._LightTheme": "Jasny", + "FrmSettings.Nav._Slideshow": "Pokaz slajdów", + "_._Continue": "Kontynuuj", + "_._AddHotkey": "Dodaj klawisz skrótu…", + "FrmMain.MnuSetDesktopBackground": "Ustaw jako tło pulpitu", + "FrmMain.MnuReload": "Wczytaj obraz ponownie", + "FrmSlideshow.MnuExitSlideshow": "Wyjdź z pokazu slajdów", + "FrmMain.MnuAutoZoom": "Automatyczne powiększenie", + "FrmSettings._ShowImagePreview": "Wyświetl podgląd obrazka podczas ładowania", + "FrmCrop.BtnCopy._Tooltip": "Skopiuj zaznaczenie do schowka", + "FrmSettings.Nav._Toolbar": "Pasek narzędzi", + "FrmMain.MnuSave._Error": "Nie można zapisać obrazu", + "FrmSettings._AfterEditingAction": "Po otworzeniu aplikacji do edycji", + "FrmSettings._ShouldUseColorProfileForAll": "Zastosuj do obrazów bez wbudowanego profilu kolorów", + "FrmCropSettings.DefaultSelectionType._UseTheLastSelection": "Użyj ostatniego wyboru", + "FrmSettings._SlideshowInterval._From": "Od", + "FrmSettings._ImageInterpolation": "Interpolacja obrazu", + "FrmQuickSetup._StepInfo": "Krok {0}", + "FrmMain.MnuColorPicker": "Próbnik kolorów", + "FrmCrop.SelectionAspectRatio._FreeRatio": "Dowolne proporcje", + "FrmSettings._ResetSettings": "Reset settings", + "FrmSettings._Startup": "Startowe", + "_.BackdropStyle._None": "Brak", + "FrmSettings._LoadDefaultZoomLevels": "Załaduj domyślne poziomy powiększenia", + "FrmColorPicker.BtnSettings._Tooltip": "Otwórz ustawienia selektora kolorów…", + "FrmSettings._UseThemeForDarkMode": "Użyj tego motywu dla trybu ciemnego", + "FrmSettings._ShowDeleteConfirmation": "Pokaż okno dialogowe potwierdzenia podczas usuwania pliku", + "FrmSettings._ShowAppIcon": "Pokaż ikonę aplikacji na pasku tytułu", + "_._InvalidAction": "Invalid action", + "FrmQuickSetup._SelectProfile": "Wybierz profil", + "_.Metadata._FileCreationTime": "Data utworzenia", + "FrmSettings._SlideshowImagesToNotifySound": "Liczba zdjęć do wyzwalania dźwięku powiadomień", + "FrmSettings._BackgroundColor": "Kolor tła przeglądarki", + "FrmSettings._RealTimeFileUpdate": "Aktualizacja pliku w czasie rzeczywistym", + "_.ColorProfileOption._CurrentMonitorProfile": "Bieżący profil monitora", + "FrmSettings._EnableCutMultipleFiles": "Włącz wycinanie wielu plików na raz", + "FrmSettings._AutoUpdate": "Automatycznie sprawdzaj dostępność aktualizacji", + "FrmCropSettings.LblDefaultSelection": "Domyślne ustawienia wyboru", + "FrmSettings._UseThemeForLightMode": "Użyj tego motywu dla trybu jasnego", + "FrmSettings._ZoomLevels": "Poziomy powiększenia", + "FrmMain.MnuSetLockScreen._Success": "Tło ekranu blokady zostało zaktualizowane", + "FrmSettings._ShowGalleryFileName": "Pokaż nazwę pliku miniatur", + "FrmSettings.Layout._Order": "Kolejność", + "FrmCropSettings.ChkAutoCenterSelection": "Automatycznie wyśrodkuj wybór", + "FrmSettings.Nav._FileTypeAssociations": "Skojarzenia plików", + "_._Back": "Cofnij", + "FrmMain.MnuSetDesktopBackground._Success": "Tło pulpitu zostało zaktualizowane", + "FrmSettings._ShouldAutoOpenNewAddedImage": "Otwórz nowo dodany obraz automatycznie", + "FrmCrop.SelectionAspectRatio._Custom": "Własne…", + "FrmMain.MnuCopyPath._Success": "Skopiowano bieżącą ścieżkę obrazu.", + "FrmSettings._StartupBoost._Error": "Could not change Startup Boost setting", + "FrmToolNotFound.LblDescription": "ImageGlass nie był w stanie zlokalizować ścieżki do pliku wykonywalnego '{0}'. Aby rozwiązać ten problem, zaktualizuj ścieżkę do '{0}' w razie potrzeby.", + "FrmMain.MnuClearClipboard": "Wyczyść schowek", + "FrmSettings._ColorManagement": "Zarządzanie kolorami", + "FrmMain._ReachedLastLast": "Nastąpiło przejście do ostatniego obrazu w serii", + "FrmMain.MnuPanUp": "Przesuń obraz w górę", + "FrmMain.MnuRemoveDefaultPhotoViewer._Success": "ImageGlass nie jest już domyślną przeglądarką zdjęć.", + "FrmSettings._GetMoreLanguagePacks": "Pobierz więcej pakietów językowych…", + "FrmAbout._Privacy": "Polityka prywatności", + "FrmSettings._EnableRecursiveLoading": "Załaduj obrazy w podfolderach", + "_._UserAction._MethodArgumentNotSupported": "Typ argumentu metody '{0}' nie jest obsługiwany", + "FrmSettings._FileExtensionIcons._Description": "Aby dostosować ikony rozszerzenia pliku, pobierz pakiet ikon, umieść wszystkie pliki .ICO w folderze ikony rozszerzenia i kliknij przycisk '{0}'. To również ustawi ImageGlass jako domyślną przeglądarkę zdjęć.", + "_.ImageOrderType._Asc": "Rosnąco", + "FrmExportFrames._Title": "Eksportuj ramki obrazów", + "_._Install": "Zainstaluj…", + "FrmMain.MnuFlipHorizontal": "Przerzuć w poziomie", + "FrmSettings._OpenExtensionIconFolder": "Otwórz folder rozszerzeń ikon", + "FrmAbout._Collaborator": "Współpracownik:", + "FrmQuickSetup._ConfirmCloseProcess": "Przed zastosowaniem nowych ustawień, konieczne jest zamknięcie wszystkich procesów ImageGlass. Czy jesteś gotowy, aby kontynuować?", + "FrmExportFrames._ExportDone": "Wyeksportowano {0} ramki do \n{1}", + "FrmCrop.BtnSaveAs._Tooltip": "Zapisz jako kopię…", + "FrmMain.MnuOpenFile": "Otwórz plik…", + "FrmColorPickerSettings.ChkShowRgbA": "Użyj formatu RGB z wartością alfa", + "_.ImageInfo._ListCount": "{0} plik(ów)", + "FrmMain.MnuGoToLast": "Przejdź do ostatniego zdjęcia", + "FrmSettings._EditApps._AppName": "Nazwa aplikacji", + "FrmSettings._SlideshowBackgroundColor": "Kolor tła pokazu slajdów", + "FrmAbout._Email": "E-mail:", + "_.MouseWheelAction._DoNothing": "Nic nie rób", + "FrmMain.MnuSaveAs": "Zapisz jako…", + "FrmMain._Loading": "Ładowanie…", + "_._Browse": "Przeglądaj…", + "FrmMain.MnuSetDefaultPhotoViewer._Error": "Nie można ustawić ImageGlass jako domyślnej przeglądarki zdjęć.", + "FrmSettings.Nav._Language": "Język", + "FrmQuickSetup._SeeWhatNew": "Zobacz, co nowego w tej wersji…", + "FrmSettings._ImageInterpolation._ScaleUp": "Kiedy powiększenie > 100%", + "FrmSettings.Layout._ToolbarContextPosition": "Pozycja kontekstowego paska narzędzi", + "FrmMain.MnuDeleteFromHardDisk": "Usuń trwale", + "FrmSettings._EmbeddedThumbnail": "Zaszyta miniatura obrazu", + "FrmMain.MnuDeleteFromHardDisk._Description": "Czy na pewno chcesz trwale usunąć ten plik?", + "FrmMain.MnuScaleToFill": "Wypełnij", + "FrmCrop.BtnCrop": "Przytnij", + "_.AfterEditAppAction._Minimize": "Minimalizuj", + "FrmMain.MnuInvertColors": "Invert colors", + "FrmSettings._StartupBoost": "Startup Boost", + "FrmMain.MnuViewFirstFrame": "Zobacz pierwszą ramkę", + "_.MouseWheelEvent._CtrlAndScroll": "Przytrzymaj Ctrl i przewiń", + "FrmSettings._HideMainWindowInSlideshow": "Automatycznie ukryj główne okno", + "_.Metadata._FrameCount": "Ramki", + "FrmSettings._EnableCopyMultipleFiles": "Włącz kopiowanie wielu plików na raz", + "FrmMain.MnuFrameless._EnableDescription": "Przytrzymaj klawisz Shift, aby przesunąć okno.", + "_.ImageOrderBy._ExifDateTaken": "EXIF: Date taken", + "FrmAbout._Credits": "Podziękowania", + "FrmSettings._AddNewFileExtension": "Dodaj nowe rozszerzenie pliku", + "FrmMain.MnuQuickSetup": "Otwórz szybką konfigurację ImageGlass", + "FrmMain.MnuSave._Success": "Obraz został zapisany", + "FrmMain.MnuPanLeft": "Przesuń obraz w lewo", + "FrmUpdate._StatusChecking": "Szukam aktualizacji…", + "FrmSettings.Nav._Layout": "Układ", + "FrmMain.MnuOpenWith": "Otwórz za pomocą…", + "FrmAbout._Thanks": "Specjalne podziękowania dla:", + "_._Warning": "Ostrzeżenie", + "FrmSettings.Nav._Keyboard": "Klawiatura", + "FrmSlideshow._PauseSlideshow": "Wstrzymano pokaz slajdów.", + "_._Add+": "Dodaj…", + "_._Email": "E-mail", + "FrmMain.MnuPanDown": "Przesuń obraz w dół", + "_._Cancel": "Anuluj", + "_._OK": "OK", + "FrmMain.MnuPanRight": "Przesuń obraz w prawo", + "_.Position._Right": "Z prawej", + "_._Icon": "Ikona", + "FrmSettings._ShouldLoadHiddenImages": "Załaduj ukryte obrazy", + "_._InvalidAction._Transformation": "ImageGlass does not support rotation, flipping for this image.", + "FrmSettings._MakeDefault": "Ustaw domyślne", + "FrmMain.MnuCopyImageData._Copying": "Kopiowanie danych obrazu. To zajmie chwilę…", + "FrmSettings._UseEmbeddedThumbnailRawFormats": "Załaduj tylko wbudowane miniaturki dla formatów RAW", + "_.ImageInterpolation._Linear": "Liniowy", + "FrmSettings._ImageInfoTags": "Znaczniki informacji o obrazach", + "FrmSettings._FileExtensionIcons": "Ikony rozszerzenia pliku", + "FrmMain.MnuEdit._AppNotFound": "Nie można znaleźć powiązanej aplikacji do edycji. Możesz przypisać aplikację do edycji tego formatu w ustawieniach ImageGlass > Edytuj.", + "_.ColorProfileOption._None": "Brak", + "FrmSettings._TotalSupportedFormats": "Łącznie obsługiwane formaty: {0}", + "FrmSettings._Clipboard": "Schowek", + "_._UserAction._Win32ExeError": "Nie można wykonać polecenia '{0}'. Upewnij się, że nazwa jest poprawna.", + "FrmCropSettings.DefaultSelectionType._SelectX": "Zaznacz {0}", + "_.AfterEditAppAction._Close": "Zamknij", + "FrmAbout._LogoDesigner": "Projektant Logo:", + "_.ImageOrderBy._Name": "Nazwa (domyślna)", + "FrmMain.MnuRemoveDefaultPhotoViewer._Error": "Nie można usunąć ImageGlass jako domyślnej przeglądarki zdjęć.", + "FrmExportFrames._FolderPickerTitle": "Wybierz folder wyjściowy do eksportu ramek obrazu", + "FrmAbout._Donate": "Wspomóż", + "FrmMain.MnuFrameNav": "Rozmieszczenie ramki", + "FrmMain.MnuSetLockScreen": "Ustaw jako tło ekranu blokady", + "_._Delete": "Usuń", + "FrmMain.MnuViewPrevious": "Wyświetl poprzedni obraz", + "_.Position._Top": "Góra", + "FrmSettings.Toolbar._CurrentButtons": "Bieżące przyciski:", + "FrmMain.MnuAbout": "O programie", + "FrmSettings._RemoveDefault": "Usuń domyślne", + "_._Description": "Opis", + "FrmMain.MnuPasteImage._Error": "Nie można znaleźć danych obrazu w schowku", + "FrmMain.MnuSettings": "Ustawienia", + "FrmCropSettings._Title": "Ustawienia przycinania", + "FrmSettings.Toolbar._ToolbarIconHeight": "Rozmiar ikony paska narzędzi", + "FrmSettings._SlideshowInterval._To": "Do", + "FrmSettings.Layout._ToolbarPosition": "Pozycja paska narzędzi", + "FrmUpdate._StatusUpdated": "Używasz najnowszej wersji!", + "FrmMain.MnuExit": "Wyjdź", + "_._Webview2._Outdated": "Your WebView2 Runtime is not supported. Proszę zaktualizować do wersji {0} lub nowszej.", + "_._Yes": "Tak", + "FrmMain.MnuRotateLeft": "Obróć w lewo", + "FrmSettings._EnableStartupBoost": "Enable Startup Boost", + "_.ImageOrderBy._ExifRating": "EXIF: Rating", + "FrmMain.MnuZoomIn": "Powiększ", + "_.Metadata._ColorSpace": "Przestrzeń kolorów", + "FrmAbout._Version": "Wersja:", + "FrmMain.MnuToggleTopMost._Enable": "Włączone okno zawsze na górze", + "FrmSettings.Toolbar._AvailableButtons": "Dostępne przyciski:", + "FrmMain.MnuSave._Saving": "Zapisywanie obrazu…", + "FrmQuickSetup._StandardUser": "Standardowy użytkownik", + "FrmMain.MnuSetLockScreen._Error": "Nie można ustawić wyświetlanego obrazu jako tła ekranu blokady", + "FrmSettings.Nav._Image": "Obraz", + "FrmSettings._Theme._InstallTheme": "Zainstaluj paczki motywów", + "FrmSettings._EnableMultiInstances": "Zezwól na działanie wielu instancji programu jednocześnie", + "FrmMain.MnuCropTool": "Przytnij obraz", + "_._IgCommandExe._DefaultError._Heading": "Nieprawidłowe polecenia", + "_._Refresh": "Odśwież", + "FrmMain.MnuLosslessCompression._Description": "This tool uses Magick.NET library for lossless compression, optimizing file size. Overwrites only if the compressed file is smaller than the original.", + "_._MoveDown": "Przenieś w dół", + "FrmSettings._GetExtensionIconPacks": "Pobierz pakiety rozszerzeń ikon…", + "FrmSettings._InAppMessageDuration": "Czas trwania wiadomości w aplikacji (w milisekundach)", + "FrmMain.MnuFrameless": "Bez ramki", + "_._Reset": "Przywróć", + "FrmSettings._ConfigDir": "Lokalizacja konfiguracji", + "FrmQuickSetup._SettingsWillBeApplied": "Ustawienia zostaną zastosowane:", + "FrmSettings._UnmanagedSettingReminder": "This setting is not managed by ImageGlass. Don't forget to disable it before you remove or relocate the app because ImageGlass does not handle this automatically.", + "FrmMain.MnuClipboard": "Schowek", + "FrmMain.MnuCustomZoom": "Powiększenie…", + "FrmSettings._DisplayLanguage": "Język wyświetlania", + "FrmMain.MnuPrint._Error": "Nie można wydrukować oglądanego obrazu", + "FrmSettings._ShouldPreserveModifiedDate": "Zachowaj datę modyfikacji pliku przy zapisywaniu", + "FrmSettings._ShowSaveOverrideConfirmation": "Pokaż okno dialogowe potwierdzenia podczas nadpisywania pliku", + "FrmColorPickerSettings.ChkShowHexA": "Użyj formatu HEX z wartością alfa", + "FrmMain.MnuFullScreen": "Pełny ekran", + "FrmSettings._StartupDir": "Lokalizacja startowa", + "FrmSettings._ShowCheckerboardOnlyImageRegion": "Wyświetl tło (szachownicę) tylko na obszarze obrazu", + "FrmMain.MnuClearClipboard._Success": "Schowek wyczyszczony.", + "FrmQuickSetup._Text": "Szybka konfiguracja ImageGlass", + "FrmMain.MnuLosslessCompression._Done": "Done lossless compression.\r\nThe new file size is {0}, saved {1}.", + "FrmMain.MnuLosslessCompression": "Magick.NET Lossless Compression", + "FrmResize.RadResizeByPercentage": "Percentage", + "FrmSettings._StartupBoost._Disabled": "Startup Boost is disabled", + "FrmMain.MnuToggleCheckerboard": "Tło - szachownica", + "FrmSettings._MinEmbeddedThumbnailSize._Height": "Wysokość", + "FrmSettings.Nav._General": "Ogólne", + "FrmSettings._ImageLoading": "Wczytywanie obrazu", + "FrmSettings._ShowSlideshowCountdown": "Wyświetlaj odliczanie na pokazie slajdów", + "FrmMain.MnuSave": "Zapisz", + "FrmMain.MnuMoveToRecycleBin": "Przenieś do Kosza", + "FrmMain.MnuRefresh": "Odśwież", + "FrmToolNotFound.LblHeading": "'{0}' nie znaleziony!", + "FrmMain.MnuReportIssue": "Zgłoś problem…", + "FrmMain.MnuCopyImageData": "Kopiuj dane obrazu", + "FrmMain.MnuCheckForUpdate._NewVersion": "Nowa wersja jest dostępna!", + "_._Empty": "(pusty)", + "FrmSettings._Zooming": "Powiększanie", + "FrmMain.MnuCutFile": "Wytnij plik", + "FrmHotkeyPicker.LblHotkey": "Naciśnij klawisze skrótów", + "FrmSettings.Layout._Gallery": "Galeria", + "FrmMain.MnuNewWindow": "Otwórz nowe okno", + "FrmMain.MnuMoveToRecycleBin._Description": "Czy chcesz przenieść ten plik do kosza?", + "FrmSettings._DefaultPhotoViewer": "Domyślna przeglądarka zdjęć", + "_.Metadata._ExifDateTimeOriginal": "EXIF: DateTimeOriginal", + "FrmMain.MnuRotateRight": "Obróć w prawo", + "FrmSettings._MinEmbeddedThumbnailSize": "Minimalny rozmiar osadzonej miniatury do załadowania", + "FrmMain.MnuSetDefaultPhotoViewer": "Ustaw domyślną przeglądarkę zdjęć", + "FrmMain.MnuImageProperties": "Właściwości obrazu", + "FrmSettings._EnableNavigationButtons": "Pokaż przyciski strzałek nawigacyjnych", + "_._Edit": "Edycja", + "FrmSettings._ImageBooster": "Wzmocnienie obrazu", + "FrmSettings.Tools._IntegratedWith": "Zintegrowane z {0}", + "_._Next": "Dalej", + "FrmExportFrames._OpenOutputFolder": "Otwórz folder wyjściowy", + "FrmMain.MnuOpenLocation": "Otwórz lokalizację obrazu", + "FrmMain.MnuLockZoom": "Zablokuj współczynnik powiększenia", + "FrmSettings._StartupBoost._Description": "Preload and run ImageGlass in the background for a few seconds during Windows startup to accelerate the first launch.", + "FrmSettings._WindowBackdrop": "Tło okna", + "FrmSettings._EnableRealTimeFileUpdate": "Monitoruj zmiany plików w folderze przeglądania i aktualizuj w czasie rzeczywistym", + "_._NotSupported": "Nieobsługiwany format", + "FrmSettings._Theme._GetMoreThemes": "Uzyskaj więcej pakietów motywów…", + "FrmMain.MnuNewWindow._Error": "Nie można otworzyć nowego okna ponieważ tylko jedna instancja jest dozwolona", + "FrmMain.MnuZoomOut": "Zmniejsz", + "FrmSettings.Toolbar._EditButton": "Przycisk edycji paska narzędzi", + "FrmMain.MnuCustomZoom._Description": "Podaj nową wartość powiększenia", + "FrmResize.RadResizeByPixels": "Pixels", + "FrmMain.MnuEdit": "Edytuj obraz {0}…", + "FrmSettings.Layout._GalleryPosition": "Pozycja galerii", + "FrmMain.MnuWindowFit": "Dopasuj okno do obrazu", + "FrmMain._OpenFileDialog": "Wszystkie obsługiwane formaty", + "FrmSettings._UseRandomIntervalForSlideshow": "Użyj losowego czasu zmiany slajdu", + "_.Position._Left": "Z lewej", + "FrmSettings._ShouldOpenLastSeenImage": "Otwórz ostatnio wyświetlany obraz", + "_.Position._Bottom": "Dół", + "FrmResize.ChkKeepRatio": "Keep ratio propotional", + "FrmMain.MnuGoTo": "Przejdź do…", + "FrmSlideshow.MnuPauseResumeSlideshow": "Wstrzymaj/wznów pokaz slajdów", + "FrmSettings.Tools._Integrated": "Zintegrowane", + "FrmSettings._Contributors": "Współtwórcy", + "_.MouseWheelAction._Zoom": "Powiększ / Pomniejsz", + "_._CommandPreview": "Podgląd polecenia", + "FrmSettings._DarkTheme": "Ciemny", + "_._Hotkeys": "Skróty klaw.", + "_.Metadata._ExifDateTime": "EXIF: DateTime", + "FrmSettings.Toolbar._Errors._ButtonIdRequired": "Wymagane ID przycisku.", + "FrmSettings._MinEmbeddedThumbnailSize._Width": "Szerokość", + "_._Executable": "Wykonywalny", + "_.ImageInterpolation._MultiSampleLinear": "Wielopróbkowy liniowy", + "_._Separator": "Separator", + "FrmQuickSetup._ProfessionalUser": "Profesjonalny użytkownik", + "FrmMain.MnuFlipVertical": "Przerzuć w pionie", + "FrmSlideshow._ResumeSlideshow": "Wznowiono pokaz slajdów.", + "FrmCropSettings.DefaultSelectionType._CustomArea": "Niestandardowy obszar…", + "FrmMain.MnuActualSize": "Rozmiar rzeczywisty", + "FrmCrop.BtnSaveAs": "Zapisz jako…", + "FrmSettings._InstallNewLanguagePack": "Zainstaluj nowe pakiety językowe…", + "FrmSlideshow.MnuZoomModes": "Tryby powiększania", + "FrmMain.MnuTools": "Narzędzia", + "_.ImageInterpolation._Cubic": "Sześcienny", + "FrmUpdate._LatestVersion": "Najnowsza wersja: {0}", + "FrmMain.MnuViewNext": "Wyświetl następny obraz", + "_.MouseWheelEvent._AltAndScroll": "Przytrzymaj Alt i przewiń", + "FrmToolNotFound._Title": "Narzędzie nie znalezione", + "FrmCrop.BtnCrop._Tooltip": "Przytnij tylko obraz", + "FrmSettings.EditAppDialog._AddApp": "Dodaj aplikację do edycji", + "FrmMain.MnuPanning": "Panoramowanie", + "_._MoveUp": "Przenieś do góry", + "FrmCropSettings.DefaultSelectionType._SelectAll": "Zaznacz wszystko", + "_._Name": "Nazwa", + "FrmColorPickerSettings.ChkShowHslA": "Użyj formatu HSL z wartością alfa", + "FrmMain.MnuToggleImageAnimation": "Włącz/Wyłącz animację obrazu", + "FrmSettings._DisableStartupBoost": "Disable Startup Boost", + "FrmMain.MnuCopyFile._Success": "Skopiowano {0} plik(ów).", + "FrmMain.MnuSave._ConfirmDescription": "ImageGlass nie jest profesjonalnym edytorem zdjęć, bądź świadomy utraty jakości, metadanych, warstw,… podczas zapisywania obrazu.", + "FrmToolNotFound.BtnSelectExecutable": "Wybierz…", + "FrmUpdate._StatusOutdated": "Nowa aktualizacja jest dostępna!", + "_.ImageOrderBy._Random": "Losowo", + "FrmResize.LblCurrentSize": "Current Size:", + "_._Apply": "Zastosuj", + "FrmAbout._Slogan": "Lekka i wszechstronna przeglądarka obrazów", + "FrmMain.MnuPanToTop": "Przesuń obraz do góry", + "FrmSettings.Toolbar._AddNewButton": "Dodaj niestandardowy przycisk paska narzędzi", + "FrmCrop.LblSize": "Rozmiar:", + "FrmSettings._ImageInterpolation._ScaleDown": "Kiedy powiększenie < 100%", + "_._CreatingFileError": "Nie można utworzyć tymczasowego pliku obrazu", + "FrmMain.MnuGoTo._Description": "Proszę podać indeks obrazu, a następnie nacisnąć ENTER", + "FrmSettings.Toolbar._EnableCenterToolbar": "Użyj wyrównania środkowego paska narzędzi", + "FrmMain.MnuResizeTool": "Resize image", + "FrmSettings.Layout._Toolbar": "Pasek narzędzi", + "FrmMain.MnuHelp": "Pomoc", + "_.ImageOrderBy._FileSize": "Rozmiar pliku", + "FrmSettings._Theme._OpenThemeFolder": "Otwórz folder z motywami", + "FrmMain.MnuNavigation": "Nawigacja", + "_._Save": "Zapisz", + "FrmQuickSetup._SettingProfileDescription": "Aby zmodyfikować te ustawienia, wejdź do ustawień aplikacji.", + "_._UserAction._MenuNotFound": "Nie można znaleźć menu '{0}' aby wywołać akcję", + "FrmMain.MnuPanToLeftSide": "Przesuń obraz do lewej", + "FrmUpdate._CurrentVersion": "Bieżąca wersja: {0}", + "FrmCrop.BtnSettings._Tooltip": "Otwórz ustawienia narzędzia Przycinania", + "_.ColorProfileOption._Custom": "Własne…", + "FrmSettings._UseEmbeddedThumbnailOtherFormats": "Załaduj tylko osadzone miniaturki dla innych formatów", + "FrmMain.MnuGoToFirst": "Przejdź do pierwszego zdjęcia", + "FrmSettings._ExportLanguagePack": "Eksportuj pakiet językowy…", + "FrmSettings.Nav._Mouse": "Mysz", + "_.ImageOrderBy._DateCreated": "Data utworzenia", + "FrmSettings._EnableFullscreenSlideshow": "Uruchom pokaz slajdów w trybie pełnoekranowym", + "FrmAbout._Homepage": "Strona główna:", + "FrmSettings._GalleryCacheSizeInMb": "Maksymalny rozmiar pamięci podręcznej galerii (w megabajtach)", + "FrmMain.MnuCopyImageData._Success": "Skopiowano aktualne dane obrazu.", + "FrmSettings._EnableLoopBackNavigation": "Wróć do pierwszego obrazu po osiągnięciu końca listy przeglądanych obrazów", + "_.MouseWheelEvent._Scroll": "Przewiń", + "FrmCrop.BtnSave._Tooltip": "Zapisz obraz", + "FrmMain.MnuSlideshow": "Pokaz slajdów", + "FrmMain.MnuShare": "Udostępnij…", + "FrmSettings._SlideshowNotification": "Powiadomienie o pokazie slajdów", + "FrmMain.MnuViewChannels": "Wyświetl kanały", + "FrmSettings._Refresh": "Odśwież", + "_._UserAction._MethodNotFound": "Nie można znaleźć metody '{0}' do wywołania akcji", + "FrmMain.MnuCopyFile": "Kopiuj plik", + "_._CreatingFile": "Tworzenie tymczasowego pliku obrazu…", + "FrmMain.MnuToggleTopMost": "Utrzymuj okno zawsze na wierzchu", + "FrmMain.MnuLosslessCompression._Confirm": "Are you sure you want to proceed?", + "FrmMain.MnuImage": "Obraz", + "FrmSettings._StartupBoost._Enabled": "Startup Boost is enabled", + "FrmQuickSetup._SetDefaultViewer": "Czy chcesz ustawić ImageGlass jako domyślną przeglądarkę zdjęć?", + "FrmMain.MnuScaleToWidth": "Dopasuj do szerokości", + "_._FileExtension": "Rozszerzenie pliku", + "FrmUpdate._PublishedDate": "Data publikacji: {0}", + "_._DoNotShowThisMessageAgain": "Nie pokazuj ponownie tego komunikatu", + "_.ImageInterpolation._NearestNeighbor": "Najbliższy sąsiad", + "FrmCrop.LblLocation": "Lokalizacja:", + "_._Download": "Pobierz", + "_.Metadata._ColorProfile": "Profil kolorów", + "FrmSettings._CenterWindowFit": "Wyśrodkuj okno w trybie dopasowania do okna", + "FrmSettings._ImageLoadingOrder": "Porządek wczytywania obrazów", + "FrmSettings._GalleryColumns": "Liczba kolumn miniatur w pionowym układzie galerii", + "_._Quit": "Wyjście", + "_._Add": "Dodaj", + "FrmMain.MnuChangeBackgroundColor": "Zmień kolor tła…", + "FrmMain.MnuToggleToolbar": "Pasek narzędzi", + "FrmAbout._Contact": "Kontakt", + "FrmSettings.Toolbar._AddCustomButton": "Dodaj niestandardowy przycisk…", + "FrmCrop.BtnQuickSelect._Tooltip": "Szybki wybór…", + "FrmMain.MnuCutFile._Success": "Wycięto {0} plik(ów).", + "FrmSettings._ZoomSpeed": "Prędkość powiększania", + "FrmMain.MnuToggleTopMost._Disable": "Wyłączone okno zawsze na górze", + "FrmSettings._ShouldUseExplorerSortOrder": "Use Explorer sort order if possible", + "_.ImageInterpolation._Antisotropic": "Antyzotropowy", + "FrmMain._ReachedFirstImage": "Nastąpiło przejście do pierwszego obrazu w serii", + "_._UnhandledException": "Nieobsługiwany wyjątek", + "FrmResize.LblNewSize": "New Size:", + "FrmMain._ClipboardImage": "Obraz ze schowka", + "FrmMain.MnuExportFrames": "Eksportuj ramki obrazu…", + "FrmMain.MnuFile": "Plik", + "_._Close": "Zamknij", + "FrmMain.MnuMain": "Menu główne", + "_._ResetToDefault": "Przywróć domyślne", + "FrmSettings.Nav._Gallery": "Galeria", + "FrmMain.MnuSetDefaultPhotoViewer._Success": "Pomyślnie ustawiłeś ImageGlass jako domyślną przeglądarkę zdjęć.", + "FrmSettings._HideGalleryInFullscreen": "Ukryj galerię w trybie pełnoekranowym", + "FrmSettings._AvailableImageInfoTags": "Dostępne tagi:", + "FrmExportFrames._Exporting": "Eksportowanie ramek {0}/{1} \n{2}…", + "_._Argument": "Argument", + "FrmSettings._ImageEditQuality": "Jakość obrazu", + "_._ID": "ID", + "FrmSettings._UserConfigFile": "Plik ustawień użytkownika (igconfig.json)", + "FrmMain.MnuLoadingOrders": "Kolejność wyświetlania", + "FrmSettings._OpenSaveAsDialogInTheCurrentImageDir": "Open the Save As dialog in the current image directory", + "_.MouseWheelEvent._ShiftAndScroll": "Przytrzymaj Shift i przewiń", + "FrmSettings._UseSmoothZooming": "Użyj płynnego powiększenia", + "FrmSettings._Theme": "Motyw", + "FrmSettings._ImageBoosterCacheMaxDimension": "Maksymalny wymiar obrazu w pamięci podręcznej (w pikselach)", + "FrmMain.MnuScaleToHeight": "Dopasuj do wysokości", + "_.Metadata._FileLastWriteTime": "Data modyfikacji", + "FrmSettings._Author": "Autor", + "FrmSettings._Others": "Inne", + "_.MouseWheelAction._PanVertically": "Przesuń w górę / w dół", + "FrmSettings._MouseWheelAction": "Akcja kółka myszy", + "FrmSettings.Nav._Tools": "Narzędzia", + "FrmMain.MnuSetDesktopBackground._Error": "Nie można ustawić wyświetlanego obrazu jako tło pulpitu", + "FrmSettings.Toolbar._Errors._ButtonExecutableRequired": "Wymagany plik wykonywalny.", + "_.ImageOrderBy._DateAccessed": "Data dostępu", + "FrmSettings._ThumbnailSize": "Rozmiar minuatury (w pikselach)", + "FrmSettings._FileFormats": "Formaty plików", + "FrmMain.MnuReloadImageList": "Przeładuj listę obrazów", + "FrmSettings._UseWebview2ForSvg": "Użyj Webview2 do przeglądania formatu SVG", + "FrmCrop.BtnCopy": "Kopiuj", + "FrmSettings._CurrentMonitorProfile._Description": "ImageGlass nie aktualizuje automatycznie koloru podczas przenoszenia okna między monitorami", + "FrmMain.PicMain._ErrorText": "Nie można otworzyć tego obrazu", + "FrmSettings.Tools._AddNewTool": "Dodaj zewnętrzne narzędzie", + "FrmMain.MnuRename": "Zmień nazwę obrazu…", + "FrmMain.MnuViewLastFrame": "Zobacz ostatnią ramkę", + "_._Webview2._NotFound": "Please install WebView2 Runtime to access full features of ImageGlass.", + "FrmMain.MnuGetMoreTools": "Uzyskaj więcej narzędzi…", + "FrmSettings.Nav._Appearance": "Wygląd", + "FrmSettings._SlideshowInterval": "Interwał pokazu slajdów:", + "_.ImageInterpolation._HighQualityBicubic": "Wysoka jakość, dwusześcienny", + "FrmColorPickerSettings.ChkShowHsvA": "Użyj formatu HSV z wartością alfa", + "FrmSettings.Tools._EditTool": "Edytuj zewnętrzne narzędzie", + "_._Error": "Błąd", + "FrmSettings._ImageBoosterCacheMaxFileSizeInMb": "Maksymalny rozmiar pliku obrazu w pamięci podręcznej (w megabajtach)", + "_._UnhandledException._Description": "Wystąpił nieobsługiwany wyjątek. Jeśli klikniesz Kontynuuj, aplikacja zignoruje ten błąd i spróbuje kontynuować. Jeśli klikniesz przycisk Zakończ, aplikacja zostanie natychmiast zamknięta.", + "_.Metadata._FileSize": "Rozmiar pliku", + "FrmSettings.Toolbar._ButtonJson": "Przycisk JSON", + "FrmQuickSetup._SetDefaultViewer._Description": "Możesz to zresetować w ustawieniach aplikacji > Zakładka Powiązania typów plików.", + "FrmSettings.Nav._Edit": "Edycja", + "FrmMain.MnuToggleGallery": "Panel galerii", + "_._IgCommandExe._DefaultError._Description": "Upewnij się, że podałeś poprawne polecenia!\r\nTen plik wykonywalny zawiera funkcje wiersza poleceń dla oprogramowania ImageGlass.\r\n\r\nAby zapoznać się ze wszystkimi wierszami poleceń, odwiedź stronę:\n{0}", + "FrmMain.MnuLosslessCompression._Compressing": "Performing lossless compression…", + "FrmSettings._ShouldGroupImagesByDirectory": "Grupuj obrazy według katalogu", + "FrmMain.MnuPanToRightSide": "Przesuń obraz do prawej", + "_.Metadata._ExifRatingPercent": "Ocena", + "FrmSettings._PanSpeed": "Prędkość zmiany obrazów", + "_._CheckForUpdate": "Sprawdź dostępność aktualizacji…", + "FrmSettings.Layout._ToolbarContext": "Kontekstowy pasek narzędzi", + "_.ImageInfo._FrameCount": "{0} ramka(ek)", + "FrmMain.MnuLayout": "Układ", + "_._Website": "Strona WWW", + "FrmMain.MnuPasteImage": "Wklej obraz", + "FrmSettings._ShowGalleryScrollbars": "Pokaż paski przewijania galerii" + } +} \ No newline at end of file diff --git a/Setup/Assets/Language/Portuguese, Brazilian.iglang.json b/Setup/Assets/Language/Portuguese, Brazilian.iglang.json new file mode 100644 index 000000000..3579654f4 --- /dev/null +++ b/Setup/Assets/Language/Portuguese, Brazilian.iglang.json @@ -0,0 +1,504 @@ +{ + "_Metadata": { + "Code": "pt-BR", + "EnglishName": "Brazilian Portuguese", + "LocalName": "Português Brasileiro", + "Author": "Filipe Hajdu", + "MinVersion": "9.1" + }, + "Items": { + "FrmCrop.SelectionAspectRatio._Original": "Original", + "FrmMain.MnuShare._Error": "Não foi possível abrir a caixa de diálogo Compartilhar.", + "_.Metadata._FileLastAccessTime": "Último Acesso", + "FrmAbout._License": "Licenças de software", + "FrmSettings.Toolbar._Errors._ButtonIdDuplicated": "Um botão com o ID '{0}' já foi definido. Por favor, escolha um ID diferente e único para o seu botão para evitar conflitos.", + "FrmMain.MnuSave._Confirm": "Tem certeza de que deseja substituir esta imagem?", + "FrmSettings._OpenDefaultAppsSetting": "Abrir configurações padrão do aplicativo", + "FrmMain.MnuCopyPath": "Copiar caminho da imagem", + "FrmCropSettings.DefaultSelectionType._SelectNone": "Selecionar nenhum", + "_.MouseWheelAction._PanHorizontally": "Mover para Esquerda / Direita", + "FrmMain.MnuPrint": "Imprimir…", + "FrmSettings.Toolbar._ToolbarButtons": "Botões da barra de ferramentas", + "FrmResize.LblResample": "Reamostrar:", + "_.ImageOrderBy._Extension": "Extensão", + "FrmSettings.Nav._Viewer": "Visualizador", + "FrmSettings.EditAppDialog._EditApp": "Editar aplicativo", + "FrmCrop.BtnReset._Tooltip": "Redefinir seleção", + "FrmMain.MnuRename._Description": "Insira um novo nome do arquivo:", + "_._No": "Não", + "FrmSlideshow.MnuToggleCountdown": "Mostrar contagem regressiva da apresentação", + "FrmSettings._OpenStartupAppsSetting": "Abrir a configuração de aplicativos de inicialização", + "FrmMain.MnuViewPreviousFrame": "Ver quadro anterior", + "_.ImageOrderBy._DateModified": "Data de modificação", + "FrmMain.MnuViewNextFrame": "Ver próximo quadro", + "FrmMain.MnuUnload": "Descarregar imagem", + "FrmSettings.Toolbar._HideToolbarInFullscreen": "Ocultar barra de ferramentas no modo de tela cheia", + "_.ImageOrderType._Desc": "Decrescente", + "_._Update": "Atualizar", + "FrmSettings._EnableImageAsyncLoading": "Ativar o carregamento assíncrono de imagens", + "FrmSettings._DefaultPhotoViewer._Description": "Registrar os formatos suportados do ImageGlass com o Windows. Talvez você precise abrir as configurações de apps padrão e selecionar manualmente o ImageGlass na lista para que ele tenha efeito.", + "_.MouseWheelAction._BrowseImages": "Ver próxima / Imagem anterior", + "FrmSettings._EditApps": "Aplicativos para edição de imagens", + "FrmColorPickerSettings.ChkShowCIELabA": "Use o formato CIELAB com valor alfa", + "_._GetHelp": "Obter ajuda", + "FrmQuickSetup._SkipQuickSetup": "Ignore isso e iniciar o ImageGlass", + "FrmColorPickerSettings._Title": "Configurações do seletor de cor", + "_._Copy": "Copiar", + "FrmSettings._ImageBoosterCacheCount": "Número de imagens armazenadas em cache pelo Image Booster (uma direção)", + "FrmMain.MnuPanToBottom": "Deslocar a imagem para baixo", + "FrmMain.MnuZoom": "Ampliação", + "FrmCropSettings.ChkCloseToolAfterSaving": "Fechar ferramenta de recortar após salvar", + "FrmSettings._ShowWelcomeImage": "Mostrar página de boas-vindas", + "FrmSettings._ColorProfile": "Perfil de cor", + "FrmSettings._Theme._UninstallTheme": "Desinstalar um pacote de temas", + "FrmMain._OpenWith": "Abrir com {0}", + "FrmMain.MnuRemoveDefaultPhotoViewer": "Remover visualizador de fotos padrão", + "_.AfterEditAppAction._Nothing": "Nada", + "FrmCrop.BtnSave": "Salvar", + "FrmMain.MnuScaleToFit": "Redimensionar para caber", + "FrmToolNotFound.LblDownloadToolText": "Você pode baixar mais ferramentas para o ImageGlass em:", + "_._LearnMore": "Saiba mais…", + "FrmCrop.LblAspectRatio": "Taxa de proporção:", + "FrmExportFrames._FileNotExist": "O arquivo de imagem não existe", + "FrmSettings._LightTheme": "Claro", + "FrmSettings.Nav._Slideshow": "Apresentação", + "_._Continue": "Continuar", + "_._AddHotkey": "Adicionar atalho…", + "FrmMain.MnuSetDesktopBackground": "Definir como tela de fundo da área de trabalho", + "FrmMain.MnuReload": "Recarregar imagem", + "FrmSlideshow.MnuExitSlideshow": "Sair da apresentação", + "FrmMain.MnuAutoZoom": "Ampliação automática", + "FrmSettings._ShowImagePreview": "Exibir pré-visualização de imagem enquanto estiver sendo carregado", + "FrmCrop.BtnCopy._Tooltip": "Copiar seleção para área de transferência", + "FrmSettings.Nav._Toolbar": "Barra de ferramentas", + "FrmMain.MnuSave._Error": "Não foi possível salvar a imagem", + "FrmSettings._AfterEditingAction": "Após abrir o aplicativo de edição", + "FrmSettings._ShouldUseColorProfileForAll": "Aplicar também para imagens sem perfil de cor incorporado", + "FrmCropSettings.DefaultSelectionType._UseTheLastSelection": "Usar a última seleção", + "FrmSettings._SlideshowInterval._From": "De", + "FrmSettings._ImageInterpolation": "Interpolação da imagem", + "FrmQuickSetup._StepInfo": "Etapa {0}", + "FrmMain.MnuColorPicker": "Seletor de cores", + "FrmCrop.SelectionAspectRatio._FreeRatio": "Proporção livre", + "FrmSettings._ResetSettings": "Redefinir as configurações", + "FrmSettings._Startup": "Inicialização", + "_.BackdropStyle._None": "Nenhum", + "FrmSettings._LoadDefaultZoomLevels": "Carregar níveis de zoom padrão", + "FrmColorPicker.BtnSettings._Tooltip": "Abrir configurações de seleção de cores…", + "FrmSettings._UseThemeForDarkMode": "Usar esse tema para o modo escuro", + "FrmSettings._ShowDeleteConfirmation": "Mostrar diálogo de confirmação ao excluir arquivo", + "FrmSettings._ShowAppIcon": "Mostrar ícone do aplicativo na barra de título", + "_._InvalidAction": "A ação é inválida", + "FrmQuickSetup._SelectProfile": "Selecione um perfil", + "_.Metadata._FileCreationTime": "Data de criação", + "FrmSettings._SlideshowImagesToNotifySound": "Número de imagens para disparar um som de notificação", + "FrmSettings._BackgroundColor": "Cor de fundo do visualizador", + "FrmSettings._RealTimeFileUpdate": "Atualização de arquivo em tempo real", + "_.ColorProfileOption._CurrentMonitorProfile": "Perfil de monitor atual", + "FrmSettings._EnableCutMultipleFiles": "Ativar o recorte de vários arquivos de uma vez", + "FrmSettings._AutoUpdate": "Verificar atualizações automaticamente", + "FrmCropSettings.LblDefaultSelection": "Seleção padrão", + "FrmSettings._UseThemeForLightMode": "Use esse tema para o modo claro", + "FrmSettings._ZoomLevels": "Níveis de ampliação", + "FrmMain.MnuSetLockScreen._Success": "Imagem da tela de bloqueio atualizada", + "FrmSettings._ShowGalleryFileName": "Mostrar nome do arquivo em miniatura", + "FrmSettings.Layout._Order": "Ordem", + "FrmCropSettings.ChkAutoCenterSelection": "Seleção Auto-centralizada", + "FrmSettings.Nav._FileTypeAssociations": "Associações de tipo de arquivo", + "_._Back": "Voltar", + "FrmMain.MnuSetDesktopBackground._Success": "Fundo da área de trabalho atualizado", + "FrmSettings._ShouldAutoOpenNewAddedImage": "Abrir a nova imagem adicionada automaticamente", + "FrmCrop.SelectionAspectRatio._Custom": "Personalizado…", + "FrmMain.MnuCopyPath._Success": "Foi copiado o caminho da imagem atual.", + "FrmSettings._StartupBoost._Error": "Não é possível alterar a configuração de Impulso de Inicialização", + "FrmToolNotFound.LblDescription": "ImageGlass não foi possível localizar o caminho para o executável '{0}'. Para resolver esse problema, por favor, atualize o caminho para '{0}' conforme necessário.", + "FrmMain.MnuClearClipboard": "Limpar área de transferência", + "FrmSettings._ColorManagement": "Gerenciamento de cor", + "FrmMain._ReachedLastLast": "Atingiu a última imagem", + "FrmMain.MnuPanUp": "Deslocar imagem acima", + "FrmMain.MnuRemoveDefaultPhotoViewer._Success": "ImageGlass não é mais o visualizador de fotos padrão.", + "FrmSettings._GetMoreLanguagePacks": "Obter mais pacotes de idioma…", + "FrmAbout._Privacy": "Política de privacidade", + "FrmSettings._EnableRecursiveLoading": "Carregar imagens em subpastas", + "_._UserAction._MethodArgumentNotSupported": "O tipo de argumento do método '{0}' não é suportado", + "FrmSettings._FileExtensionIcons._Description": "Para personalizar os ícones de extensão de arquivo, baixe um pacote de ícones, coloque todos os arquivos .ICO na pasta de ícone de extensão, e clique no botão '{0}'. Isso também irá definir o ImageGlass como visualizador de fotos padrão.", + "_.ImageOrderType._Asc": "Crescente", + "FrmExportFrames._Title": "Exportar quadros de imagens", + "_._Install": "Instalar…", + "FrmMain.MnuFlipHorizontal": "Girar Horizontal", + "FrmSettings._OpenExtensionIconFolder": "Abrir pasta do ícone de extensão", + "FrmAbout._Collaborator": "Colaboradores:", + "FrmQuickSetup._ConfirmCloseProcess": "Antes de aplicar novas configurações, é essencial fechar todos os processos do ImageGlass. Deseja continuar?", + "FrmExportFrames._ExportDone": "Quadros {0} exportados com sucesso para \n{1}", + "FrmCrop.BtnSaveAs._Tooltip": "Salvar como uma cópia…", + "FrmMain.MnuOpenFile": "Abrir arquivo…", + "FrmColorPickerSettings.ChkShowRgbA": "Usar o formato RGB com o valor alfa", + "_.ImageInfo._ListCount": "({0} arquivos)", + "FrmMain.MnuGoToLast": "Ir para última imagem", + "FrmSettings._EditApps._AppName": "Nome do aplicativo", + "FrmSettings._SlideshowBackgroundColor": "Cor de fundo da apresentação de slides", + "FrmAbout._Email": "E-mail:", + "_.MouseWheelAction._DoNothing": "Nenhuma alteração", + "FrmMain.MnuSaveAs": "Salvar como…", + "FrmMain._Loading": "Carregando…", + "_._Browse": "Explorar…", + "FrmMain.MnuSetDefaultPhotoViewer._Error": "Não foi possível definir o ImageGlass como visualizador de fotos padrão.", + "FrmSettings.Nav._Language": "Idioma", + "FrmQuickSetup._SeeWhatNew": "Veja o que há de novo nessa versão…", + "FrmSettings._ImageInterpolation._ScaleUp": "Quando o zoom < 100%", + "FrmSettings.Layout._ToolbarContextPosition": "Posição da barra de ferramentas contextual", + "FrmMain.MnuDeleteFromHardDisk": "Excluir permanentemente", + "FrmSettings._EmbeddedThumbnail": "Miniatura incorporada", + "FrmMain.MnuDeleteFromHardDisk._Description": "Tem certeza que quer excluir permanentemente este arquivo?", + "FrmMain.MnuScaleToFill": "Redimensionar para preencher", + "FrmCrop.BtnCrop": "Recortar", + "_.AfterEditAppAction._Minimize": "Minimizar", + "FrmMain.MnuInvertColors": "Inverter cores", + "FrmSettings._StartupBoost": "Impulso de Inicialização", + "FrmMain.MnuViewFirstFrame": "Ver o primeiro quadro", + "_.MouseWheelEvent._CtrlAndScroll": "Pressione Ctrl e role", + "FrmSettings._HideMainWindowInSlideshow": "Ocultar automaticamente a janela principal", + "_.Metadata._FrameCount": "Molduras", + "FrmSettings._EnableCopyMultipleFiles": "Ativar a cópia de vários arquivos de uma vez", + "FrmMain.MnuFrameless._EnableDescription": "Pressione a tecla Shift para mover a janela.", + "_.ImageOrderBy._ExifDateTaken": "EXIF: Data tirada", + "FrmAbout._Credits": "Créditos", + "FrmSettings._AddNewFileExtension": "Adicionar nova extensão de arquivo", + "FrmMain.MnuQuickSetup": "Abrir Configuração rápida do ImageGlass", + "FrmMain.MnuSave._Success": "A imagem foi salva", + "FrmMain.MnuPanLeft": "Deslocar a imagem a esquerda", + "FrmUpdate._StatusChecking": "Procurando por atualizações…", + "FrmSettings.Nav._Layout": "Interface", + "FrmMain.MnuOpenWith": "Abrir com…", + "FrmAbout._Thanks": "Agradecimentos especiais para", + "_._Warning": "Aviso", + "FrmSettings.Nav._Keyboard": "Teclado", + "FrmSlideshow._PauseSlideshow": "Apresentação pausada.", + "_._Add+": "Adicionar…", + "_._Email": "E-mail", + "FrmMain.MnuPanDown": "Deslocar a imagem para baixo", + "_._Cancel": "Cancelar", + "_._OK": "OK", + "FrmMain.MnuPanRight": "Deslocar a imagem para direita", + "_.Position._Right": "Direita", + "_._Icon": "Ícone", + "FrmSettings._ShouldLoadHiddenImages": "Carregar imagens ocultas", + "_._InvalidAction._Transformation": "O ImageGlass não suporta rotação, virar para esta imagem.", + "FrmSettings._MakeDefault": "Tornar padrão", + "FrmMain.MnuCopyImageData._Copying": "Copiando os dados da imagem. Vai demorar um pouco…", + "FrmSettings._UseEmbeddedThumbnailRawFormats": "Carregar apenas a miniatura incorporada para formatos RAW", + "_.ImageInterpolation._Linear": "Linear", + "FrmSettings._ImageInfoTags": "Etiquetas para informações da imagem", + "FrmSettings._FileExtensionIcons": "Ícones da extensão do arquivo", + "FrmMain.MnuEdit._AppNotFound": "Não foi possível encontrar o aplicativo relacionado para edição. Você pode atribuir um aplicativo para editar este formato em Configurações do ImageGlass > Editar.", + "_.ColorProfileOption._None": "Nenhum", + "FrmSettings._TotalSupportedFormats": "Total de formatos suportados: {0}", + "FrmSettings._Clipboard": "Área de transferência", + "_._UserAction._Win32ExeError": "Não foi possível executar o comando '{0}'. Certifique-se de que o nome esteja correto.", + "FrmCropSettings.DefaultSelectionType._SelectX": "Selecionar {0}", + "_.AfterEditAppAction._Close": "Fechar", + "FrmAbout._LogoDesigner": "Designer do logo:", + "_.ImageOrderBy._Name": "Nome (padrão)", + "FrmMain.MnuRemoveDefaultPhotoViewer._Error": "Não foi possível remover o ImageGlass como o visualizador de fotos padrão.", + "FrmExportFrames._FolderPickerTitle": "Selecionar pasta de saída para exportar quadros de imagens", + "FrmAbout._Donate": "Doar", + "FrmMain.MnuFrameNav": "Navegação de quadros", + "FrmMain.MnuSetLockScreen": "Definir como imagem da tela de bloqueio", + "_._Delete": "Apagar", + "FrmMain.MnuViewPrevious": "Ver imagem anterior", + "_.Position._Top": "No topo", + "FrmSettings.Toolbar._CurrentButtons": "Botões Atuais:", + "FrmMain.MnuAbout": "Sobre", + "FrmSettings._RemoveDefault": "Remover padrão", + "_._Description": "Descrição", + "FrmMain.MnuPasteImage._Error": "Não foi possível encontrar dados de imagem na Área de Transferência", + "FrmMain.MnuSettings": "Configurações", + "FrmCropSettings._Title": "Configurações de recorte", + "FrmSettings.Toolbar._ToolbarIconHeight": "Tamanho do ícone na barra de ferramentas", + "FrmSettings._SlideshowInterval._To": "Para", + "FrmSettings.Layout._ToolbarPosition": "Posição da barra de ferramentas", + "FrmUpdate._StatusUpdated": "Você está usando a versão mais recente!", + "FrmMain.MnuExit": "Sair", + "_._Webview2._Outdated": "Seu runtime WebView2 não é suportado. Por favor, atualize para a versão {0} ou mais tarde.", + "_._Yes": "Sim", + "FrmMain.MnuRotateLeft": "Girar para esquerda", + "FrmSettings._EnableStartupBoost": "Habilitar o Impulso de Inicialização", + "_.ImageOrderBy._ExifRating": "EXIF: Classificação", + "FrmMain.MnuZoomIn": "Ampliar", + "_.Metadata._ColorSpace": "Espaço de cor", + "FrmAbout._Version": "Versão:", + "FrmMain.MnuToggleTopMost._Enable": "Janela ativada como sempre visível", + "FrmSettings.Toolbar._AvailableButtons": "Botões disponíveis:", + "FrmMain.MnuSave._Saving": "Salvando imagem…", + "FrmQuickSetup._StandardUser": "Usuário padrão", + "FrmMain.MnuSetLockScreen._Error": "Não foi possível definir a imagem de visualização como imagem da tela de bloqueio", + "FrmSettings.Nav._Image": "Imagem", + "FrmSettings._Theme._InstallTheme": "Instalar pacotes de temas", + "FrmSettings._EnableMultiInstances": "Permitir várias instâncias do programa", + "FrmMain.MnuCropTool": "Recortar imagem", + "_._IgCommandExe._DefaultError._Heading": "Comando inválido", + "_._Refresh": "Atualizar", + "FrmMain.MnuLosslessCompression._Description": "Esta ferramenta usa a biblioteca Magick.NET para compressão sem perdas, otimizando o tamanho do arquivo. Sobrescreve somente se o arquivo compactado for menor que o original.", + "_._MoveDown": "Mover para baixo", + "FrmSettings._GetExtensionIconPacks": "Obter pacotes de ícone de extensão…", + "FrmSettings._InAppMessageDuration": "Duração da mensagem no aplicativo (milissegundos)", + "FrmMain.MnuFrameless": "Sem bordas", + "_._Reset": "Redefinir", + "FrmSettings._ConfigDir": "Localização de configuração", + "FrmQuickSetup._SettingsWillBeApplied": "As configurações serão aplicadas:", + "FrmSettings._UnmanagedSettingReminder": "Esta configuração não é gerenciada pelo ImageGlass. Não se esqueça de desabilitá-lo antes de remover ou realocar o aplicativo porque o ImageGlass não lida com isso automaticamente.", + "FrmMain.MnuClipboard": "Área de transferência", + "FrmMain.MnuCustomZoom": "Zoom personalizado…", + "FrmSettings._DisplayLanguage": "Idioma de exibição", + "FrmMain.MnuPrint._Error": "Não foi possível imprimir a imagem de visualização", + "FrmSettings._ShouldPreserveModifiedDate": "Preservar data de modificação da imagem ao salvar", + "FrmSettings._ShowSaveOverrideConfirmation": "Mostrar diálogo de confirmação ao substituir o arquivo", + "FrmColorPickerSettings.ChkShowHexA": "Usar o formato HEX com o valor alfa", + "FrmMain.MnuFullScreen": "Tela Cheia", + "FrmSettings._StartupDir": "Localização de inicialização", + "FrmSettings._ShowCheckerboardOnlyImageRegion": "Mostrar tabuleiro apenas dentro da região da imagem", + "FrmMain.MnuClearClipboard._Success": "Área de transferência limpa.", + "FrmQuickSetup._Text": "Configuração rápida do ImageGlass", + "FrmMain.MnuLosslessCompression._Done": "Compressão sem perdas.\r\nO novo tamanho do arquivo é {0}, salvo {1}.", + "FrmMain.MnuLosslessCompression": "Compressão Magick.NET sem perdas", + "FrmResize.RadResizeByPercentage": "Porcentagem", + "FrmSettings._StartupBoost._Disabled": "O impulso de Inicialização foi desabilitado", + "FrmMain.MnuToggleCheckerboard": "Fundo quadriculado", + "FrmSettings._MinEmbeddedThumbnailSize._Height": "Altura", + "FrmSettings.Nav._General": "Geral", + "FrmSettings._ImageLoading": "Carregando imagem", + "FrmSettings._ShowSlideshowCountdown": "Mostrar contagem regressiva da apresentação", + "FrmMain.MnuSave": "Salvar", + "FrmMain.MnuMoveToRecycleBin": "Mover para Lixeira", + "FrmMain.MnuRefresh": "Atualizar", + "FrmToolNotFound.LblHeading": "'{0}' não foi encontrado!", + "FrmMain.MnuReportIssue": "Relatar um problema…", + "FrmMain.MnuCopyImageData": "Copiar dados da imagem", + "FrmMain.MnuCheckForUpdate._NewVersion": "Uma nova versão está disponível!", + "_._Empty": "(vazio)", + "FrmSettings._Zooming": "Ampliação", + "FrmMain.MnuCutFile": "Recortar arquivo", + "FrmHotkeyPicker.LblHotkey": "Pressione teclas de atalho", + "FrmSettings.Layout._Gallery": "Galeria", + "FrmMain.MnuNewWindow": "Abrir nova janela", + "FrmMain.MnuMoveToRecycleBin._Description": "Você quer mover esse arquivo para a Lixeira?", + "FrmSettings._DefaultPhotoViewer": "Visualizador padrão de fotos", + "_.Metadata._ExifDateTimeOriginal": "EXIF: DataHoraOriginal", + "FrmMain.MnuRotateRight": "Girar para direita", + "FrmSettings._MinEmbeddedThumbnailSize": "Tamanho mínimo da miniatura incorporada a ser carregada", + "FrmMain.MnuSetDefaultPhotoViewer": "Definir como visualizador de fotos padrão", + "FrmMain.MnuImageProperties": "Propriedades da imagem", + "FrmSettings._EnableNavigationButtons": "Mostrar botões de seta de navegação", + "_._Edit": "Editar", + "FrmSettings._ImageBooster": "Melhorar Imagem", + "FrmSettings.Tools._IntegratedWith": "Integrado com {0}", + "_._Next": "Avançar", + "FrmExportFrames._OpenOutputFolder": "Abrir pasta de saída", + "FrmMain.MnuOpenLocation": "Abrir local da imagem", + "FrmMain.MnuLockZoom": "Bloquear taxa de ampliação", + "FrmSettings._StartupBoost._Description": "Pré-carregar e executar o ImageGlass em segundo plano por alguns segundos durante a inicialização do Windows para acelerar o primeiro lançamento.", + "FrmSettings._WindowBackdrop": "Fundo da janela", + "FrmSettings._EnableRealTimeFileUpdate": "Monitorar alterações de arquivo na pasta de visualização e atualizar em tempo real", + "_._NotSupported": "Formato não suportado", + "FrmSettings._Theme._GetMoreThemes": "Obter mais pacotes de temas…", + "FrmMain.MnuNewWindow._Error": "Não foi possível abrir nova janela porque apenas uma instância é permitida", + "FrmMain.MnuZoomOut": "Reduzir", + "FrmSettings.Toolbar._EditButton": "Editar botão da barra de ferramentas", + "FrmMain.MnuCustomZoom._Description": "Insira um novo valor de zoom", + "FrmResize.RadResizeByPixels": "Pixels", + "FrmMain.MnuEdit": "Editar imagem {0}…", + "FrmSettings.Layout._GalleryPosition": "Posição da galeria", + "FrmMain.MnuWindowFit": "Ajustar à janela", + "FrmMain._OpenFileDialog": "Todos arquivos suportados", + "FrmSettings._UseRandomIntervalForSlideshow": "Usar intervalo aleatório", + "_.Position._Left": "Esquerda", + "FrmSettings._ShouldOpenLastSeenImage": "Abrir a última imagem vista", + "_.Position._Bottom": "No rodapé", + "FrmResize.ChkKeepRatio": "Manter taxa de proporção", + "FrmMain.MnuGoTo": "Ir para…", + "FrmSlideshow.MnuPauseResumeSlideshow": "Pausar/retomar slideshow", + "FrmSettings.Tools._Integrated": "Integrado", + "FrmSettings._Contributors": "Colaboradores", + "_.MouseWheelAction._Zoom": "Aumentar / diminuir zoom", + "_._CommandPreview": "Prévia do comando", + "FrmSettings._DarkTheme": "Escuro", + "_._Hotkeys": "Atalhos", + "_.Metadata._ExifDateTime": "EXIF: DataHora", + "FrmSettings.Toolbar._Errors._ButtonIdRequired": "ID do botão necessário.", + "FrmSettings._MinEmbeddedThumbnailSize._Width": "Largura", + "_._Executable": "Executável", + "_.ImageInterpolation._MultiSampleLinear": "Linguagem multi-amostra", + "_._Separator": "Separador", + "FrmQuickSetup._ProfessionalUser": "Usuário profissional", + "FrmMain.MnuFlipVertical": "Girar Vertical", + "FrmSlideshow._ResumeSlideshow": "Apresentação retomada.", + "FrmCropSettings.DefaultSelectionType._CustomArea": "Área personalizada…", + "FrmMain.MnuActualSize": "Tamanho atual", + "FrmCrop.BtnSaveAs": "Salvar como…", + "FrmSettings._InstallNewLanguagePack": "Instalar novos pacotes de idioma…", + "FrmSlideshow.MnuZoomModes": "Modo de zoom", + "FrmMain.MnuTools": "Ferramentas", + "_.ImageInterpolation._Cubic": "Cúbica", + "FrmUpdate._LatestVersion": "A versão mais recente: {0}", + "FrmMain.MnuViewNext": "Ver próxima imagem", + "_.MouseWheelEvent._AltAndScroll": "Segure Alt e role", + "FrmToolNotFound._Title": "Ferramenta não encontrada", + "FrmCrop.BtnCrop._Tooltip": "Recortar somente a imagem", + "FrmSettings.EditAppDialog._AddApp": "Adicionar um aplicativo para edição", + "FrmMain.MnuPanning": "Panorâmica", + "_._MoveUp": "Mover para cima", + "FrmCropSettings.DefaultSelectionType._SelectAll": "Selecionar todos", + "_._Name": "Nome", + "FrmColorPickerSettings.ChkShowHslA": "Usar o formato HSL com o valor alfa", + "FrmMain.MnuToggleImageAnimation": "Iniciar / parar animação da imagem", + "FrmSettings._DisableStartupBoost": "Desabilitar o Impulso de Inicialização", + "FrmMain.MnuCopyFile._Success": "Copiado(s) {0} arquivo(s).", + "FrmMain.MnuSave._ConfirmDescription": "ImageGlass não é um editor de fotos profissional, por favor, esteja ciente de perder a qualidade, metadados, camadas,... quando salvar sua imagem.", + "FrmToolNotFound.BtnSelectExecutable": "Selecionar…", + "FrmUpdate._StatusOutdated": "Uma nova atualização está disponível!", + "_.ImageOrderBy._Random": "Aleatório", + "FrmResize.LblCurrentSize": "Tamanho Atual:", + "_._Apply": "Aplicar", + "FrmAbout._Slogan": "Um visualizador de imagem versátil e leve", + "FrmMain.MnuPanToTop": "Deslocar a imagem para cima", + "FrmSettings.Toolbar._AddNewButton": "Adicionar um botão de barra de ferramentas personalizado", + "FrmCrop.LblSize": "Size:", + "FrmSettings._ImageInterpolation._ScaleDown": "Quando o zoom < 100%", + "_._CreatingFileError": "Não foi possível criar arquivo de imagem temporário", + "FrmMain.MnuGoTo._Description": "Insira o índice da imagem para vê-la. Pressione ENTER", + "FrmSettings.Toolbar._EnableCenterToolbar": "Usar alinhamento central para a barra de ferramentas", + "FrmMain.MnuResizeTool": "Redimensionar imagem", + "FrmSettings.Layout._Toolbar": "Barra de ferramentas", + "FrmMain.MnuHelp": "Ajuda", + "_.ImageOrderBy._FileSize": "Tamanho do arquivo", + "FrmSettings._Theme._OpenThemeFolder": "Abrir pasta de temas", + "FrmMain.MnuNavigation": "Navegação", + "_._Save": "Salvar", + "FrmQuickSetup._SettingProfileDescription": "Para modificar essas configurações, basta acessar as configurações do aplicativo.", + "_._UserAction._MenuNotFound": "Não foi possível encontrar o menu '{0}' para invocar a ação", + "FrmMain.MnuPanToLeftSide": "Deslocar imagem para a borda esquerda", + "FrmUpdate._CurrentVersion": "Versão atual: {0}", + "FrmCrop.BtnSettings._Tooltip": "Abrir configurações da ferramenta de recorte", + "_.ColorProfileOption._Custom": "Personalizado…", + "FrmSettings._UseEmbeddedThumbnailOtherFormats": "Carregar apenas a miniatura incorporada para outros formatos", + "FrmMain.MnuGoToFirst": "Ir para primeira imagem", + "FrmSettings._ExportLanguagePack": "Exportar pacote de idioma…", + "FrmSettings.Nav._Mouse": "Mouse", + "_.ImageOrderBy._DateCreated": "Data de criação", + "FrmSettings._EnableFullscreenSlideshow": "Iniciar a apresentação em modo de tela cheia", + "FrmAbout._Homepage": "Página inicial:", + "FrmSettings._GalleryCacheSizeInMb": "Tamanho máximo do cache da galeria (em megabytes)", + "FrmMain.MnuCopyImageData._Success": "Copiou os dados da imagem atual.", + "FrmSettings._EnableLoopBackNavigation": "Volte para a primeira imagem quando chegar ao final da lista de imagens", + "_.MouseWheelEvent._Scroll": "Rolar", + "FrmCrop.BtnSave._Tooltip": "Salvar imagem", + "FrmMain.MnuSlideshow": "Apresentação", + "FrmMain.MnuShare": "Compartilhar…", + "FrmSettings._SlideshowNotification": "Notificação do slideshow", + "FrmMain.MnuViewChannels": "Ver canais", + "FrmSettings._Refresh": "Atualizar", + "_._UserAction._MethodNotFound": "Não foi possível encontrar o método '{0}' para invocar a ação", + "FrmMain.MnuCopyFile": "Copiar arquivo", + "_._CreatingFile": "Criando um arquivo de imagem temporário…", + "FrmMain.MnuToggleTopMost": "Manter janela sempre no topo", + "FrmMain.MnuLosslessCompression._Confirm": "Voce quer mesmo continuar?", + "FrmMain.MnuImage": "Imagem", + "FrmSettings._StartupBoost._Enabled": "O Impulso de Inicialização foi habilitado", + "FrmQuickSetup._SetDefaultViewer": "Deseja definir o ImageGlass como o visualizador de fotos padrão?", + "FrmMain.MnuScaleToWidth": "Ajustar à largura", + "_._FileExtension": "Extensão do arquivo", + "FrmUpdate._PublishedDate": "Data de publicação: {0}", + "_._DoNotShowThisMessageAgain": "Não exibir esta mensagem novamente", + "_.ImageInterpolation._NearestNeighbor": "Vizinho mais próximo", + "FrmCrop.LblLocation": "Localização:", + "_._Download": "Download", + "_.Metadata._ColorProfile": "Perfil de cor", + "FrmSettings._CenterWindowFit": "Centralizar automaticamente a janela no Modo Ajuste de Janela", + "FrmSettings._ImageLoadingOrder": "Ordem de carregamento da imagem", + "FrmSettings._GalleryColumns": "Número de colunas da miniatura no layout da galeria vertical", + "_._Quit": "Sair", + "_._Add": "Adicionar", + "FrmMain.MnuChangeBackgroundColor": "Alterar a cor de fundo…", + "FrmMain.MnuToggleToolbar": "Barra de ferramentas", + "FrmAbout._Contact": "Contato", + "FrmSettings.Toolbar._AddCustomButton": "Adicionar um botão personalizado…", + "FrmCrop.BtnQuickSelect._Tooltip": "Seleção rápida…", + "FrmMain.MnuCutFile._Success": "Recortado(s) {0} arquivo(s).", + "FrmSettings._ZoomSpeed": "Velocidade do zoom", + "FrmMain.MnuToggleTopMost._Disable": "Desativar a janela sempre visível", + "FrmSettings._ShouldUseExplorerSortOrder": "Usar ordem de classificação do Explorador, se possível", + "_.ImageInterpolation._Antisotropic": "Antisotrópico", + "FrmMain._ReachedFirstImage": "Atingiu a primeira imagem", + "_._UnhandledException": "Exceção não tratada", + "FrmResize.LblNewSize": "Novo Tamanho:", + "FrmMain._ClipboardImage": "Imagem da área de transferência", + "FrmMain.MnuExportFrames": "Exportar quadros de imagens…", + "FrmMain.MnuFile": "Arquivo", + "_._Close": "Fechar", + "FrmMain.MnuMain": "Menu principal", + "_._ResetToDefault": "Redefinir ao padrão", + "FrmSettings.Nav._Gallery": "Galeria", + "FrmMain.MnuSetDefaultPhotoViewer._Success": "Você definiu com sucesso o ImageGlass como visualizador de fotos padrão.", + "FrmSettings._HideGalleryInFullscreen": "Ocultar barra de ferramentas no modo de tela cheia", + "FrmSettings._AvailableImageInfoTags": "Tags disponíveis:", + "FrmExportFrames._Exporting": "Exportando quadros {0}/{1} \n{2}…", + "_._Argument": "Argumento", + "FrmSettings._ImageEditQuality": "Qualidade das imagens", + "_._ID": "ID", + "FrmSettings._UserConfigFile": "Arquivo de configurações do usuário (igconfig.json)", + "FrmMain.MnuLoadingOrders": "Ordem de carregamento", + "FrmSettings._OpenSaveAsDialogInTheCurrentImageDir": "Abrir o diálogo Salvar Como no diretório de imagens atual", + "_.MouseWheelEvent._ShiftAndScroll": "Pressione shift e role", + "FrmSettings._UseSmoothZooming": "Usar zoom suave", + "FrmSettings._Theme": "Tema", + "FrmSettings._ImageBoosterCacheMaxDimension": "Dimensão máxima da imagem a ser armazenada em cache (em pixels)", + "FrmMain.MnuScaleToHeight": "Ajustar à altura", + "_.Metadata._FileLastWriteTime": "Data de modificação", + "FrmSettings._Author": "Autor", + "FrmSettings._Others": "Mais", + "_.MouseWheelAction._PanVertically": "Mover para Cima / Baixo", + "FrmSettings._MouseWheelAction": "Ações da roda do mouse", + "FrmSettings.Nav._Tools": "Ferramentas", + "FrmMain.MnuSetDesktopBackground._Error": "Não foi possível definir a imagem de visualização como papel de parede da área de trabalho", + "FrmSettings.Toolbar._Errors._ButtonExecutableRequired": "Botão executável exigido.", + "_.ImageOrderBy._DateAccessed": "Último Acesso", + "FrmSettings._ThumbnailSize": "Tamanho das miniaturas (em pixeis)", + "FrmSettings._FileFormats": "Formatos de arquivo", + "FrmMain.MnuReloadImageList": "Recarregar lista de imagens", + "FrmSettings._UseWebview2ForSvg": "Use Webview2 para visualizar o formato SVG", + "FrmCrop.BtnCopy": "Copiar", + "FrmSettings._CurrentMonitorProfile._Description": "ImageGlass não atualiza a cor automaticamente quando move sua janela entre os monitores", + "FrmMain.PicMain._ErrorText": "Não foi possível abrir essa imagem", + "FrmSettings.Tools._AddNewTool": "Adicionar uma ferramenta externa", + "FrmMain.MnuRename": "Renomear imagem…", + "FrmMain.MnuViewLastFrame": "Ver último quadro", + "_._Webview2._NotFound": "Por favor, instale a versão mais recente do Runtime WebView2.", + "FrmMain.MnuGetMoreTools": "Obtenha mais ferramentas…", + "FrmSettings.Nav._Appearance": "Aparência", + "FrmSettings._SlideshowInterval": "Intervalo da apresentação:", + "_.ImageInterpolation._HighQualityBicubic": "Bicúbico de alta qualidade", + "FrmColorPickerSettings.ChkShowHsvA": "Usar o formato HSV com o valor alfa", + "FrmSettings.Tools._EditTool": "Editar ferramenta externa", + "_._Error": "Erro", + "FrmSettings._ImageBoosterCacheMaxFileSizeInMb": "Tamanho máximo da imagem armazenada em cache (em egabytes)", + "_._UnhandledException._Description": "Ocorreu uma exceção não tratada. Se você clicar em Continuar, o aplicativo irá ignorar esse erro e tentará continuar. Se você clicar em Sair, o aplicativo será fechado imediatamente.", + "_.Metadata._FileSize": "Tamanho do arquivo", + "FrmSettings.Toolbar._ButtonJson": "Botão JSON", + "FrmQuickSetup._SetDefaultViewer._Description": "Você pode redefini-la nas configurações do aplicativo > aba associações de tipo de arquivo.", + "FrmSettings.Nav._Edit": "Editar", + "FrmMain.MnuToggleGallery": "Painel da galeria", + "_._IgCommandExe._DefaultError._Description": "Certifique-se de passar os comandos corretos!\r\nEsse arquivo executável contém funções de linha de comando para software do ImageGlass.\r\n\r\nPara explorar todas as linhas de comando, visite:\n{0}", + "FrmMain.MnuLosslessCompression._Compressing": "Executando a compressão sem perdas…", + "FrmSettings._ShouldGroupImagesByDirectory": "Agrupar imagens por diretório", + "FrmMain.MnuPanToRightSide": "Deslocamento de imagem para a borda direita", + "_.Metadata._ExifRatingPercent": "Classificação", + "FrmSettings._PanSpeed": "Velocidade da Movimentação", + "_._CheckForUpdate": "Procurar atualizações…", + "FrmSettings.Layout._ToolbarContext": "Barra de ferramentas contextual", + "_.ImageInfo._FrameCount": "{0} quadro(s)", + "FrmMain.MnuLayout": "Interface", + "_._Website": "Site", + "FrmMain.MnuPasteImage": "Colar imagem", + "FrmSettings._ShowGalleryScrollbars": "Mostrar barras de rolagem da galeria" + } +} \ No newline at end of file diff --git a/Setup/Assets/Language/Portuguese.iglang.json b/Setup/Assets/Language/Portuguese.iglang.json new file mode 100644 index 000000000..40e4964fa --- /dev/null +++ b/Setup/Assets/Language/Portuguese.iglang.json @@ -0,0 +1,504 @@ +{ + "_Metadata": { + "Code": "pt-PT", + "EnglishName": "Portuguese", + "LocalName": "Português", + "Author": "Sérgio Marques", + "MinVersion": "9.1" + }, + "Items": { + "FrmCrop.SelectionAspectRatio._Original": "Original", + "FrmMain.MnuShare._Error": "Não foi possível abrir o diálogo para partilhar", + "_.Metadata._FileLastAccessTime": "Data de acesso", + "FrmAbout._License": "Licença", + "FrmSettings.Toolbar._Errors._ButtonIdDuplicated": "Já foi definido um botão com o ID '{0}'. Para evitar conflitos, escolha um ID diferente e único para o seu botão.", + "FrmMain.MnuSave._Confirm": "Tem certeza de que pretende substituir esta imagem?", + "FrmSettings._OpenDefaultAppsSetting": "Abrir as definições das aplicações predefinidas", + "FrmMain.MnuCopyPath": "Copiar caminho da imagem", + "FrmCropSettings.DefaultSelectionType._SelectNone": "Desselecionar", + "_.MouseWheelAction._PanHorizontally": "Mover para esquerda/direita", + "FrmMain.MnuPrint": "Imprimir…", + "FrmSettings.Toolbar._ToolbarButtons": "Botões da barra de ferramentas", + "FrmResize.LblResample": "Amostragem:", + "_.ImageOrderBy._Extension": "Extensão", + "FrmSettings.Nav._Viewer": "Visualizador", + "FrmSettings.EditAppDialog._EditApp": "Editar aplicação", + "FrmCrop.BtnReset._Tooltip": "Redefinir seleção", + "FrmMain.MnuRename._Description": "Introduza o novo nome do ficheiro:", + "_._No": "Não", + "FrmSlideshow.MnuToggleCountdown": "Mostrar contagem regressiva nas apresentações", + "FrmSettings._OpenStartupAppsSetting": "Abrir definição \"Aplicações de arranque\"", + "FrmMain.MnuViewPreviousFrame": "Fotograma anterior", + "_.ImageOrderBy._DateModified": "Data de modificação", + "FrmMain.MnuViewNextFrame": "Fotograma seguinte", + "FrmMain.MnuUnload": "Remover imagem", + "FrmSettings.Toolbar._HideToolbarInFullscreen": "Ocultar a barra de ferramentas no modo de ecrã inteiro", + "_.ImageOrderType._Desc": "Descendente", + "_._Update": "Atualizar", + "FrmSettings._EnableImageAsyncLoading": "Aticar carregamento assíncrono de images ", + "FrmSettings._DefaultPhotoViewer._Description": "Registar os formatos suportados pelo ImageGlass no Windows. Pode ser preciso abrir a definição \"Aplicações predefinidas\" e selecionar ImageGlass na lista para produzir efeito.", + "_.MouseWheelAction._BrowseImages": "Ir para a imagem anterior/seguinte", + "FrmSettings._EditApps": "Aplicações de edição de imagem", + "FrmColorPickerSettings.ChkShowCIELabA": "Usar modo CIELAB com valor alfa", + "_._GetHelp": "Obter ajuda", + "FrmQuickSetup._SkipQuickSetup": "Ignorar e iniciar ImageGlass", + "FrmColorPickerSettings._Title": "Configuração do seletor de cor", + "_._Copy": "Copiar", + "FrmSettings._ImageBoosterCacheCount": "Número de imagens colocadas em cache (unidirecional)", + "FrmMain.MnuPanToBottom": "Mover imagem para a base", + "FrmMain.MnuZoom": "Ampliação", + "FrmCropSettings.ChkCloseToolAfterSaving": "Fechar ferramenta de recorte após gravação", + "FrmSettings._ShowWelcomeImage": "Mostrar imagem de boas vindas", + "FrmSettings._ColorProfile": "Perfil de cores", + "FrmSettings._Theme._UninstallTheme": "Desinstalar pacote de tema", + "FrmMain._OpenWith": "Abrir com {0}", + "FrmMain.MnuRemoveDefaultPhotoViewer": "Remover como visualizador de imagens predefinido", + "_.AfterEditAppAction._Nothing": "Nada fazer", + "FrmCrop.BtnSave": "Guardar", + "FrmMain.MnuScaleToFit": "Ajustar para caber", + "FrmToolNotFound.LblDownloadToolText": "Pode descarregar mais ferramentas em:", + "_._LearnMore": "Saber mais…", + "FrmCrop.LblAspectRatio": "Proporção:", + "FrmExportFrames._FileNotExist": "O ficheiro não existe", + "FrmSettings._LightTheme": "Claro", + "FrmSettings.Nav._Slideshow": "Apresentação", + "_._Continue": "Continuar", + "_._AddHotkey": "Adicionar tecla de atalho…", + "FrmMain.MnuSetDesktopBackground": "Definir como fundo do ambiente de trabalho", + "FrmMain.MnuReload": "Recarregar imagem", + "FrmSlideshow.MnuExitSlideshow": "Sair da apresentação", + "FrmMain.MnuAutoZoom": "Tamanho automático", + "FrmSettings._ShowImagePreview": "Mostrar a pré-visualização da imagem enquanto esta é carregada", + "FrmCrop.BtnCopy._Tooltip": "Copiar seleção para a área de transferência", + "FrmSettings.Nav._Toolbar": "Barra de ferramentas", + "FrmMain.MnuSave._Error": "Não foi possível guardar a imagem", + "FrmSettings._AfterEditingAction": "Depois de abrir a aplicação de dição", + "FrmSettings._ShouldUseColorProfileForAll": "Aplicar também para imagens com perfil de cor incorporado", + "FrmCropSettings.DefaultSelectionType._UseTheLastSelection": "Usar a última seleção", + "FrmSettings._SlideshowInterval._From": "De", + "FrmSettings._ImageInterpolation": "Interpolação da imagem", + "FrmQuickSetup._StepInfo": "Etapa {0}", + "FrmMain.MnuColorPicker": "Seletor de cores", + "FrmCrop.SelectionAspectRatio._FreeRatio": "Livre", + "FrmSettings._ResetSettings": "Repor definições", + "FrmSettings._Startup": "Arranque", + "_.BackdropStyle._None": "Não aplicável", + "FrmSettings._LoadDefaultZoomLevels": "Carregar níveis de zoom predefinidos", + "FrmColorPicker.BtnSettings._Tooltip": "Abrir configuração do seletor de cor…", + "FrmSettings._UseThemeForDarkMode": "Utilizar esta tema para o modo escuro", + "FrmSettings._ShowDeleteConfirmation": "Mostrar um diálogo de confirmação ao eliminar um ficheiro", + "FrmSettings._ShowAppIcon": "Mostrar ícone da aplicação na barra de título", + "_._InvalidAction": "Ação inválida", + "FrmQuickSetup._SelectProfile": "Selecione um perfil", + "_.Metadata._FileCreationTime": "Data de criação", + "FrmSettings._SlideshowImagesToNotifySound": "Número de imagens para acionar um som de notificação", + "FrmSettings._BackgroundColor": "Cor de fundo do visualizador", + "FrmSettings._RealTimeFileUpdate": "Atualização em tempo real", + "_.ColorProfileOption._CurrentMonitorProfile": "Perfil do monitor atual", + "FrmSettings._EnableCutMultipleFiles": "Permitir o corte de ficheiros em simultâneo", + "FrmSettings._AutoUpdate": "Verificar se há atualizações automaticamente", + "FrmCropSettings.LblDefaultSelection": "Configuração predefinida da seleção", + "FrmSettings._UseThemeForLightMode": "Utilizar esta tema para o modo claro", + "FrmSettings._ZoomLevels": "Níveis de ampliação", + "FrmMain.MnuSetLockScreen._Success": "Ecrã de bloqueio atualizado", + "FrmSettings._ShowGalleryFileName": "Mostrar nome das miniaturas", + "FrmSettings.Layout._Order": "Ordenar", + "FrmCropSettings.ChkAutoCenterSelection": "Centrar automaticamente a seleção", + "FrmSettings.Nav._FileTypeAssociations": "Associação dos tipos de ficheiro", + "_._Back": "Recuar", + "FrmMain.MnuSetDesktopBackground._Success": "Imagem de fundo atualizada", + "FrmSettings._ShouldAutoOpenNewAddedImage": "Abrir automaticamente a nova imagem adicionada", + "FrmCrop.SelectionAspectRatio._Custom": "Personalizar…", + "FrmMain.MnuCopyPath._Success": "Caminho da imagem copiado com sucesso", + "FrmSettings._StartupBoost._Error": "Não foi possível alterar a definição \"Otimização de arranque\"", + "FrmToolNotFound.LblDescription": "ImageGlass não conseguiu localizar o caminho para o executável '{0}'. Para resolver este problema, por favor atualize o caminho para o '{0}' em conformidade.", + "FrmMain.MnuClearClipboard": "Limpar área de transferência", + "FrmSettings._ColorManagement": "Gestão de cores", + "FrmMain._ReachedLastLast": "Chegou à última imagem", + "FrmMain.MnuPanUp": "Mover imagem para cima", + "FrmMain.MnuRemoveDefaultPhotoViewer._Success": "ImageGlass já não é o visualizador de imagens predefinido.", + "FrmSettings._GetMoreLanguagePacks": "Obter mais pacotes de idioma…", + "FrmAbout._Privacy": "Política de privacidade", + "FrmSettings._EnableRecursiveLoading": "Carregar imagens em subpastas", + "_._UserAction._MethodArgumentNotSupported": "O tipo de argumento para o método '{0}' não é suportado", + "FrmSettings._FileExtensionIcons._Description": "Para personalizar os ícones das extensões de ficheiros, transfira um pacote de ícones, coloque todos os ficheiros .ICO na pasta de ícones das extensões e clique no botão '{0}'. Isto também predefinirá o ImageGlass como visualizador de fotografias.", + "_.ImageOrderType._Asc": "Ascendente", + "FrmExportFrames._Title": "Exportar fotogramas da imagem", + "_._Install": "Instalar…", + "FrmMain.MnuFlipHorizontal": "Inverter na horizontal", + "FrmSettings._OpenExtensionIconFolder": "Abrir a pasta dos ícones das extensões", + "FrmAbout._Collaborator": "Colaborador:", + "FrmQuickSetup._ConfirmCloseProcess": "Antes de aplicar as definições, deve fechar todos os processo ImageGlass. Continuar?", + "FrmExportFrames._ExportDone": "{0} molduras exportadas com\nsucesso para {1}", + "FrmCrop.BtnSaveAs._Tooltip": "Salvar como cópia…", + "FrmMain.MnuOpenFile": "Abrir ficheiro…", + "FrmColorPickerSettings.ChkShowRgbA": "Usar modo RGB com valor alfa", + "_.ImageInfo._ListCount": "{0} ficheiro(s)", + "FrmMain.MnuGoToLast": "Ir para a última imagem", + "FrmSettings._EditApps._AppName": "Nome da aplicação", + "FrmSettings._SlideshowBackgroundColor": "Cor de fundo da apresentação", + "FrmAbout._Email": "E-mail:", + "_.MouseWheelAction._DoNothing": "Nada fazer", + "FrmMain.MnuSaveAs": "Guardar como…", + "FrmMain._Loading": "A carregar…", + "_._Browse": "Explorar…", + "FrmMain.MnuSetDefaultPhotoViewer._Error": "Não foi possível definir ImageGlass como visualizador de imagens predefinido.", + "FrmSettings.Nav._Language": "Idioma", + "FrmQuickSetup._SeeWhatNew": "Ver novidades desta versão…", + "FrmSettings._ImageInterpolation._ScaleUp": "Quando o zoom for > 100%", + "FrmSettings.Layout._ToolbarContextPosition": "Posição da barra de ferramentas contextual", + "FrmMain.MnuDeleteFromHardDisk": "Eliminar permanentemente", + "FrmSettings._EmbeddedThumbnail": "Miniatura integrada", + "FrmMain.MnuDeleteFromHardDisk._Description": "Tem a certeza de que pretende eliminar permanentemente este ficheiro?", + "FrmMain.MnuScaleToFill": "Ajustar para preencher", + "FrmCrop.BtnCrop": "Recortar", + "_.AfterEditAppAction._Minimize": "Minimizar", + "FrmMain.MnuInvertColors": "Inverter cores", + "FrmSettings._StartupBoost": "Otimização de arranque", + "FrmMain.MnuViewFirstFrame": "Ir para o primeiro fotograma", + "_.MouseWheelEvent._CtrlAndScroll": "Ctrl + Roda do rato", + "FrmSettings._HideMainWindowInSlideshow": "Ocultar automaticamente a janela principal", + "_.Metadata._FrameCount": "Fotogramas", + "FrmSettings._EnableCopyMultipleFiles": "Permitir a cópia de ficheiros em simultâneo", + "FrmMain.MnuFrameless._EnableDescription": "Prima Shift para mover a janela", + "_.ImageOrderBy._ExifDateTaken": "EXIF: Data de captura", + "FrmAbout._Credits": "Créditos", + "FrmSettings._AddNewFileExtension": "Adicionar nova extensão de ficheiro", + "FrmMain.MnuQuickSetup": "Iniciar configuração rápida ImageGlass", + "FrmMain.MnuSave._Success": "Imagem guardada", + "FrmMain.MnuPanLeft": "Mover imagem para a esquerda", + "FrmUpdate._StatusChecking": "A verificar se há atualizações…", + "FrmSettings.Nav._Layout": "Esquema", + "FrmMain.MnuOpenWith": "Abrir com…", + "FrmAbout._Thanks": "Agradecimentos:", + "_._Warning": "Aviso", + "FrmSettings.Nav._Keyboard": "Teclado", + "FrmSlideshow._PauseSlideshow": "Apresentação pausada.", + "_._Add+": "Adicionar…", + "_._Email": "E-mail", + "FrmMain.MnuPanDown": "Mover imagem para baixo", + "_._Cancel": "Cancelar", + "_._OK": "OK", + "FrmMain.MnuPanRight": "Mover imagem para a direita", + "_.Position._Right": "Direita", + "_._Icon": "Ícone", + "FrmSettings._ShouldLoadHiddenImages": "Carregar imagens ocultas", + "_._InvalidAction._Transformation": "ImageGlass não consegue rodar nem inverter esta imagem.", + "FrmSettings._MakeDefault": "Predefinir", + "FrmMain.MnuCopyImageData._Copying": "A copiar os dados da imagem Pode demorar algum tempo…", + "FrmSettings._UseEmbeddedThumbnailRawFormats": "Apenas carregar a miniatura integrada nos formatos RAW", + "_.ImageInterpolation._Linear": "Linear", + "FrmSettings._ImageInfoTags": "Etiqueta de informação da imagem", + "FrmSettings._FileExtensionIcons": "Ícones de extensões dos ficheiros", + "FrmMain.MnuEdit._AppNotFound": "Não foi possível encontrar a aplicação para editar Para editar este formato com outra aplicação, especifique-a nas definições.", + "_.ColorProfileOption._None": "Não aplicável", + "FrmSettings._TotalSupportedFormats": "Total de formatos suportados: {0}", + "FrmSettings._Clipboard": "Área de transferência", + "_._UserAction._Win32ExeError": "Não foi possível executar o comando '{0}' Certifique-se de que o nome está correto", + "FrmCropSettings.DefaultSelectionType._SelectX": "Selecionar {0}", + "_.AfterEditAppAction._Close": "Fechar", + "FrmAbout._LogoDesigner": "Criador do logo:", + "_.ImageOrderBy._Name": "Nome (predefinido)", + "FrmMain.MnuRemoveDefaultPhotoViewer._Error": "Não foi possível remover ImageGlass como visualizador de imagens predefinido.", + "FrmExportFrames._FolderPickerTitle": "Selecione a pasta para onde exportar as molduras", + "FrmAbout._Donate": "Donativos", + "FrmMain.MnuFrameNav": "Navegação entre molduras", + "FrmMain.MnuSetLockScreen": "Definir como ecrã de bloqueio", + "_._Delete": "Eliminar", + "FrmMain.MnuViewPrevious": "Imagem anterior", + "_.Position._Top": "Cima", + "FrmSettings.Toolbar._CurrentButtons": "Botões atuais:", + "FrmMain.MnuAbout": "Acerca", + "FrmSettings._RemoveDefault": "Remover a predefinição", + "_._Description": "Descrição", + "FrmMain.MnuPasteImage._Error": "Não existem dados na área de transferência", + "FrmMain.MnuSettings": "Definições", + "FrmCropSettings._Title": "Definições de recorte", + "FrmSettings.Toolbar._ToolbarIconHeight": "Tamanho dos ícones na barra de ferramentas", + "FrmSettings._SlideshowInterval._To": "Até", + "FrmSettings.Layout._ToolbarPosition": "Posição da barra de ferramentas", + "FrmUpdate._StatusUpdated": "Está a utilizar a versão mais recente!", + "FrmMain.MnuExit": "Sair", + "_._Webview2._Outdated": "A versão WebView2 Runtime não é suportada. Atualize para a versão {0} ou mais recente.", + "_._Yes": "Sim", + "FrmMain.MnuRotateLeft": "Rodar à esquerda", + "FrmSettings._EnableStartupBoost": "Ativar \"Otimização de arranque\"", + "_.ImageOrderBy._ExifRating": "EXIF: Classificação", + "FrmMain.MnuZoomIn": "Ampliar", + "_.Metadata._ColorSpace": "Espaço de cores", + "FrmAbout._Version": "Versão:", + "FrmMain.MnuToggleTopMost._Enable": "Opção \"Mostrar janela sempre na frente\" ativada", + "FrmSettings.Toolbar._AvailableButtons": "Botões disponíveis:", + "FrmMain.MnuSave._Saving": "A guardar imagem…", + "FrmQuickSetup._StandardUser": "Utilizador predefinido", + "FrmMain.MnuSetLockScreen._Error": "Não foi possível definir a imagem escolhida como ecrã de bloqueio", + "FrmSettings.Nav._Image": "Imagem", + "FrmSettings._Theme._InstallTheme": "Instalar pacote de tema", + "FrmSettings._EnableMultiInstances": "Permitir várias instâncias da aplicação", + "FrmMain.MnuCropTool": "Recortar imagem", + "_._IgCommandExe._DefaultError._Heading": "Comando inválido", + "_._Refresh": "Recarregar", + "FrmMain.MnuLosslessCompression._Description": "Esta ferramenta utiliza a biblioteca Magick.NET para a compressão e otimiza o tamanho do ficheiro. Apenas substituir se o tamanho final for inferior ao original.", + "_._MoveDown": "Mover para baixo", + "FrmSettings._GetExtensionIconPacks": "Obter pacote de ícones…", + "FrmSettings._InAppMessageDuration": "Duração da mensagem na aplicação (milissegundos)", + "FrmMain.MnuFrameless": "Sem contorno", + "_._Reset": "Repor", + "FrmSettings._ConfigDir": "Diretório de configuração", + "FrmQuickSetup._SettingsWillBeApplied": "Definições aplicadas:", + "FrmSettings._UnmanagedSettingReminder": "Esta definição não é gerida por ImageGlass. Não se esqueça de desativar antes de remover ou mover a aplicação. ImagGlass não consegue gerir esta definição automaticamente.", + "FrmMain.MnuClipboard": "Área de transferência", + "FrmMain.MnuCustomZoom": "Personalizado…", + "FrmSettings._DisplayLanguage": "Idioma", + "FrmMain.MnuPrint._Error": "Não foi possível imprimir a imagem", + "FrmSettings._ShouldPreserveModifiedDate": "Não alterar data da última modificação ao guardar", + "FrmSettings._ShowSaveOverrideConfirmation": "Mostrar um diálogo de confirmação ao substituir um ficheiro", + "FrmColorPickerSettings.ChkShowHexA": "Usar modo HEX com valor alfa", + "FrmMain.MnuFullScreen": "Ecrã completo", + "FrmSettings._StartupDir": "Diretório inicial", + "FrmSettings._ShowCheckerboardOnlyImageRegion": "Mostrar grelha apenas na região da imagem", + "FrmMain.MnuClearClipboard._Success": "Dados da área de transferência eliminados com sucesso.", + "FrmQuickSetup._Text": "ImageGlass - Configuração rápida", + "FrmMain.MnuLosslessCompression._Done": "Compressão efetuada.\r\nO novo tamanho é {0} e poupou {1}.", + "FrmMain.MnuLosslessCompression": "Compressão Magick.NET Lossless", + "FrmResize.RadResizeByPercentage": "Percentagem", + "FrmSettings._StartupBoost._Disabled": "A \"Otimização de arranque\" está desativada.", + "FrmMain.MnuToggleCheckerboard": "Fundo em grelha", + "FrmSettings._MinEmbeddedThumbnailSize._Height": "Altura", + "FrmSettings.Nav._General": "Geral", + "FrmSettings._ImageLoading": "Carregamento de imagens", + "FrmSettings._ShowSlideshowCountdown": "Mostrar contagem regressiva nas apresentações", + "FrmMain.MnuSave": "Guardar", + "FrmMain.MnuMoveToRecycleBin": "Mover para a Reciclagem", + "FrmMain.MnuRefresh": "Recarregar", + "FrmToolNotFound.LblHeading": "'{0}' não encontrado!", + "FrmMain.MnuReportIssue": "Reportar um erro…", + "FrmMain.MnuCopyImageData": "Copiar dados da imagem", + "FrmMain.MnuCheckForUpdate._NewVersion": "Está disponível uma nova versão!", + "_._Empty": "(vazio)", + "FrmSettings._Zooming": "Ampliação", + "FrmMain.MnuCutFile": "Cortar ficheiro", + "FrmHotkeyPicker.LblHotkey": "Prima as teclas", + "FrmSettings.Layout._Gallery": "Galeria", + "FrmMain.MnuNewWindow": "Abrir nova janela", + "FrmMain.MnuMoveToRecycleBin._Description": "Tem a certeza de que pretende mover o ficheiro para a Reciclagem?", + "FrmSettings._DefaultPhotoViewer": "Visualizador de imagens predefinido", + "_.Metadata._ExifDateTimeOriginal": "EXIF: DataHoraOriginal", + "FrmMain.MnuRotateRight": "Rodar à direita", + "FrmSettings._MinEmbeddedThumbnailSize": "Tamanho mínimo da miniatura integrada a ser carregada", + "FrmMain.MnuSetDefaultPhotoViewer": "Definir como visualizador de imagens predefinido", + "FrmMain.MnuImageProperties": "Propriedades da imagem", + "FrmSettings._EnableNavigationButtons": "Mostrar setas de navegação", + "_._Edit": "Editar", + "FrmSettings._ImageBooster": "Acelerador de imagens", + "FrmSettings.Tools._IntegratedWith": "Integrado com {0}", + "_._Next": "Avançar", + "FrmExportFrames._OpenOutputFolder": "Abrir pasta de destino", + "FrmMain.MnuOpenLocation": "Abrir pasta da imagem", + "FrmMain.MnuLockZoom": "Bloquear tamanho", + "FrmSettings._StartupBoost._Description": "Abrir e executar ImageGlass em segundo plano ao iniciar o Windows para otimizar o tempo de abertura da aplicação.", + "FrmSettings._WindowBackdrop": "Fundo da janela", + "FrmSettings._EnableRealTimeFileUpdate": "Monitorizar alterações aos ficheiros e atualizar imagens em tempo real", + "_._NotSupported": "Formato não suportado", + "FrmSettings._Theme._GetMoreThemes": "Obter mais temas…", + "FrmMain.MnuNewWindow._Error": "Não foi possível abrir uma nova janela porque apenas é permitida uma instância", + "FrmMain.MnuZoomOut": "Reduzir", + "FrmSettings.Toolbar._EditButton": "Modificar botão da barra de ferramentas", + "FrmMain.MnuCustomZoom._Description": "Introduza um novo valor de zoom", + "FrmResize.RadResizeByPixels": "Pixeis", + "FrmMain.MnuEdit": "Editar {0}…", + "FrmSettings.Layout._GalleryPosition": "Posição da galeria", + "FrmMain.MnuWindowFit": "Ajustar à janela", + "FrmMain._OpenFileDialog": "Todos os formatos suportados", + "FrmSettings._UseRandomIntervalForSlideshow": "Intervalo aleatório", + "_.Position._Left": "Esquerda", + "FrmSettings._ShouldOpenLastSeenImage": "Abrir última imagem visualizada", + "_.Position._Bottom": "Baixo", + "FrmResize.ChkKeepRatio": "Manter proporção", + "FrmMain.MnuGoTo": "Ir para…", + "FrmSlideshow.MnuPauseResumeSlideshow": "Pausar/retomar apresentação", + "FrmSettings.Tools._Integrated": "Integrado", + "FrmSettings._Contributors": "Colaboradores", + "_.MouseWheelAction._Zoom": "Ampliar/reduzir", + "_._CommandPreview": "Pré-visualização do comando", + "FrmSettings._DarkTheme": "Escuro", + "_._Hotkeys": "Teclas de atalho", + "_.Metadata._ExifDateTime": "EXIF: DataHora", + "FrmSettings.Toolbar._Errors._ButtonIdRequired": "Requer ID do botão", + "FrmSettings._MinEmbeddedThumbnailSize._Width": "Largura", + "_._Executable": "Executável", + "_.ImageInterpolation._MultiSampleLinear": "Multi-amostra linear", + "_._Separator": "Separador", + "FrmQuickSetup._ProfessionalUser": "Profissional", + "FrmMain.MnuFlipVertical": "Inverter na vertical", + "FrmSlideshow._ResumeSlideshow": "Apresentação retomada.", + "FrmCropSettings.DefaultSelectionType._CustomArea": "Área personalizada…", + "FrmMain.MnuActualSize": "Tamanho real", + "FrmCrop.BtnSaveAs": "Guardar como…", + "FrmSettings._InstallNewLanguagePack": "Instalar pacote de idioma…", + "FrmSlideshow.MnuZoomModes": "Modos de ampliação", + "FrmMain.MnuTools": "Ferramentas", + "_.ImageInterpolation._Cubic": "Cúbica", + "FrmUpdate._LatestVersion": "Versão atualizada: {0}", + "FrmMain.MnuViewNext": "Imagem seguinte", + "_.MouseWheelEvent._AltAndScroll": "Alt + Roda do rato", + "FrmToolNotFound._Title": "Ferramenta não encontrada", + "FrmCrop.BtnCrop._Tooltip": "Recortar apenas imagem", + "FrmSettings.EditAppDialog._AddApp": "Adicionar aplicação de edição", + "FrmMain.MnuPanning": "Panorâmico", + "_._MoveUp": "Mover para cima", + "FrmCropSettings.DefaultSelectionType._SelectAll": "Selecionar todos", + "_._Name": "Nome", + "FrmColorPickerSettings.ChkShowHslA": "Usar modo HSL com valor alfa", + "FrmMain.MnuToggleImageAnimation": "Iniciar/parar animação", + "FrmSettings._DisableStartupBoost": "Desativar \"Otimização de arranque\"", + "FrmMain.MnuCopyFile._Success": "{0} ficheiro(s) copiado(s).", + "FrmMain.MnuSave._ConfirmDescription": "Tenha em atenção de que ImageGlass não é um editor de fotos profissional e, ao guardar a imagem, pode perder qualidade, dados, camadas…", + "FrmToolNotFound.BtnSelectExecutable": "Selecionar…", + "FrmUpdate._StatusOutdated": "Está disponível uma atualização!", + "_.ImageOrderBy._Random": "Aleatória", + "FrmResize.LblCurrentSize": "Tamanho atual:", + "_._Apply": "Aplicar", + "FrmAbout._Slogan": "Um visualizador de imagem simples e versátil", + "FrmMain.MnuPanToTop": "Mover imagem para o topo", + "FrmSettings.Toolbar._AddNewButton": "Adicionar botão personalizado à barra de ferramentas", + "FrmCrop.LblSize": "Tamanho:", + "FrmSettings._ImageInterpolation._ScaleDown": "Se ampliação < 100%", + "_._CreatingFileError": "Não foi possível criar o ficheiro temporário", + "FrmMain.MnuGoTo._Description": "Indique o número da imagem a visualizar e prima Enter", + "FrmSettings.Toolbar._EnableCenterToolbar": "Centrar a barra de ferramentas", + "FrmMain.MnuResizeTool": "Redimensionar", + "FrmSettings.Layout._Toolbar": "Barra de ferramentas", + "FrmMain.MnuHelp": "Ajuda", + "_.ImageOrderBy._FileSize": "Tamanho do ficheiro", + "FrmSettings._Theme._OpenThemeFolder": "Abrir pasta do tema", + "FrmMain.MnuNavigation": "Navegação", + "_._Save": "Guardar", + "FrmQuickSetup._SettingProfileDescription": "Para alterar estas opções, aceda às definições da aplicação.", + "_._UserAction._MenuNotFound": "Não foi possível encontrar o menu '{0}' para invocar a ação", + "FrmMain.MnuPanToLeftSide": "Mover imagem para o lado esquerdo", + "FrmUpdate._CurrentVersion": "Versão atual: {0}", + "FrmCrop.BtnSettings._Tooltip": "Abrir definições de recorte", + "_.ColorProfileOption._Custom": "Personalizar…", + "FrmSettings._UseEmbeddedThumbnailOtherFormats": "Apenas carregar a miniatura integrada nos outros formatos", + "FrmMain.MnuGoToFirst": "Ir para a primeira imagem", + "FrmSettings._ExportLanguagePack": "Exportar pacote de idioma…", + "FrmSettings.Nav._Mouse": "Rato", + "_.ImageOrderBy._DateCreated": "Data de criação", + "FrmSettings._EnableFullscreenSlideshow": "Iniciar a apresentação no modo de ecrã inteiro", + "FrmAbout._Homepage": "Site:", + "FrmSettings._GalleryCacheSizeInMb": "Tamanho máximo da cache da galeria (em megabytes)", + "FrmMain.MnuCopyImageData._Success": "Dados da imagem copiados com sucesso", + "FrmSettings._EnableLoopBackNavigation": "Voltar à primeira imagem, quando chegar ao fim da lista de imagens", + "_.MouseWheelEvent._Scroll": "Deslocar", + "FrmCrop.BtnSave._Tooltip": "Guardar imagem", + "FrmMain.MnuSlideshow": "Apresentação", + "FrmMain.MnuShare": "Partilhar…", + "FrmSettings._SlideshowNotification": "Notificação da apresentação", + "FrmMain.MnuViewChannels": "Ver canais", + "FrmSettings._Refresh": "Recarregar", + "_._UserAction._MethodNotFound": "Não foi possível encontrar o método '{0}' para invocar a ação", + "FrmMain.MnuCopyFile": "Copiar ficheiro", + "_._CreatingFile": "Estamos a criar um ficheiro temporário…", + "FrmMain.MnuToggleTopMost": "Manter janela sempre na frente", + "FrmMain.MnuLosslessCompression._Confirm": "Tem certeza de que deseja deseja continuar?", + "FrmMain.MnuImage": "Imagem", + "FrmSettings._StartupBoost._Enabled": "A \"Otimização de arranque\" está ativada.", + "FrmQuickSetup._SetDefaultViewer": "Deseja tornar ImageGlass o visualizador de imagens predefinido do sistema?", + "FrmMain.MnuScaleToWidth": "Ajustar à largura", + "_._FileExtension": "Extensão do ficheiro", + "FrmUpdate._PublishedDate": "Data de publicação: {0}", + "_._DoNotShowThisMessageAgain": "Não mostrar esta mensagem novamente", + "_.ImageInterpolation._NearestNeighbor": "Vizinho mais próximo", + "FrmCrop.LblLocation": "Localização:", + "_._Download": "Descarregar", + "_.Metadata._ColorProfile": "Perfil de cores", + "FrmSettings._CenterWindowFit": "Centrar automaticamente a janela no modo Ajuste da Janela", + "FrmSettings._ImageLoadingOrder": "Ordem de carregamento", + "FrmSettings._GalleryColumns": "Número de colunas de miniaturas na disposição vertical da galeria", + "_._Quit": "Sair", + "_._Add": "Adicionar", + "FrmMain.MnuChangeBackgroundColor": "Alterar a cor de fundo…", + "FrmMain.MnuToggleToolbar": "Barra de ferramentas", + "FrmAbout._Contact": "Contacto", + "FrmSettings.Toolbar._AddCustomButton": "Adicionar um botão…", + "FrmCrop.BtnQuickSelect._Tooltip": "Seleção rápida…", + "FrmMain.MnuCutFile._Success": "{0} ficheiro(s) cortados", + "FrmSettings._ZoomSpeed": "Velocidade do zoom", + "FrmMain.MnuToggleTopMost._Disable": "Opção \"Mostrar janela sempre na frente\" desativada", + "FrmSettings._ShouldUseExplorerSortOrder": "Utilizar a ordem de ordenação do Explorador, se possível", + "_.ImageInterpolation._Antisotropic": "Anisotrópico", + "FrmMain._ReachedFirstImage": "Chegou à primeira imagem", + "_._UnhandledException": "Exceção não tratada", + "FrmResize.LblNewSize": "Novo tamanho:", + "FrmMain._ClipboardImage": "Imagem da área de transferência", + "FrmMain.MnuExportFrames": "Exportar fotogramas da imagem…", + "FrmMain.MnuFile": "Ficheiro", + "_._Close": "Fechar", + "FrmMain.MnuMain": "Menu principal", + "_._ResetToDefault": "Repor predefinições", + "FrmSettings.Nav._Gallery": "Galeria", + "FrmMain.MnuSetDefaultPhotoViewer._Success": "ImageGlass foi definido como o visualizador de imagens predefinido.", + "FrmSettings._HideGalleryInFullscreen": "Ocultar galeria no modo de ecrã completo", + "FrmSettings._AvailableImageInfoTags": "Etiquetas disponíveis:", + "FrmExportFrames._Exporting": "A exportar {0} de {1} molduras\n{2}…", + "_._Argument": "Argumento", + "FrmSettings._ImageEditQuality": "Qualidade da imagem", + "_._ID": "ID", + "FrmSettings._UserConfigFile": "Ficheiro de definições (igconfig.json)", + "FrmMain.MnuLoadingOrders": "Ordem de carregamento", + "FrmSettings._OpenSaveAsDialogInTheCurrentImageDir": "Abrir caixa de diálogo \"Guardar como\" na pasta da imagem atual", + "_.MouseWheelEvent._ShiftAndScroll": "Shift + Roda do rato", + "FrmSettings._UseSmoothZooming": "Usar zoom suave", + "FrmSettings._Theme": "Tema", + "FrmSettings._ImageBoosterCacheMaxDimension": "Dimensão máxima da imagem a ser armazenada em cache (em píxeis)", + "FrmMain.MnuScaleToHeight": "Ajustar à altura", + "_.Metadata._FileLastWriteTime": "Data de modificação", + "FrmSettings._Author": "Autor", + "FrmSettings._Others": "Outras", + "_.MouseWheelAction._PanVertically": "Mover para cima/baixo", + "FrmSettings._MouseWheelAction": "Ação com a roda do rato", + "FrmSettings.Nav._Tools": "Ferramentas", + "FrmMain.MnuSetDesktopBackground._Error": "Não foi possível definir a imagem de visualização como fundo do ambiente de trabalho", + "FrmSettings.Toolbar._Errors._ButtonExecutableRequired": "Requer executável do botão", + "_.ImageOrderBy._DateAccessed": "Data de acesso", + "FrmSettings._ThumbnailSize": "Tamanho das miniaturas (em pixeis)", + "FrmSettings._FileFormats": "Formato dos ficheiros", + "FrmMain.MnuReloadImageList": "Recarregar lista de imagens", + "FrmSettings._UseWebview2ForSvg": "Usar o Webview2 para visualizar o formato SVG", + "FrmCrop.BtnCopy": "Copiar", + "FrmSettings._CurrentMonitorProfile._Description": "ImageGlass não atualiza automaticamente a cor se estiver a mover a janela entre monitores", + "FrmMain.PicMain._ErrorText": "Não foi possível abrir a imagem", + "FrmSettings.Tools._AddNewTool": "Adicionar uma ferramenta externa", + "FrmMain.MnuRename": "Mudar o nome…", + "FrmMain.MnuViewLastFrame": "Ir para o último fotograma", + "_._Webview2._NotFound": "Por favor instale a versão mais recente de WebView2 Runtime.", + "FrmMain.MnuGetMoreTools": "Obter mais ferramentas…", + "FrmSettings.Nav._Appearance": "Aspeto", + "FrmSettings._SlideshowInterval": "Tempo entre imagens:", + "_.ImageInterpolation._HighQualityBicubic": "Alta qualidade, bicúbica", + "FrmColorPickerSettings.ChkShowHsvA": "Usar modo HSV com valor alfa", + "FrmSettings.Tools._EditTool": "Editar ferramentas externa", + "_._Error": "Erro", + "FrmSettings._ImageBoosterCacheMaxFileSizeInMb": "Tamanho máximo da imagem a ser armazenada em cache (em megabytes)", + "_._UnhandledException._Description": "Ocorreu uma exceção que não pôde ser tratada Se clicar em Continuar, a aplicação irá ignorar o erro e tentará continuar Se clicar em Sair, a aplicação será fechada imediatamente", + "_.Metadata._FileSize": "Tamanho do ficheiro", + "FrmSettings.Toolbar._ButtonJson": "Botão JSON", + "FrmQuickSetup._SetDefaultViewer._Description": "Pode restaurar as definições da aplicação em Definições -> Associação dos tipos de ficheiro.", + "FrmSettings.Nav._Edit": "Editar", + "FrmMain.MnuToggleGallery": "Painel da galeria", + "_._IgCommandExe._DefaultError._Description": "Certifique-se que passas os comandos corretos!\r\nEste ficheiro executável contém funções de linha de comando para o software ImageGlass.\r\n\r\nPara explorar todas as linhas de comando, visite:\n{0}", + "FrmMain.MnuLosslessCompression._Compressing": "A executar compressão sem perdas…", + "FrmSettings._ShouldGroupImagesByDirectory": "Agrupar imagens por pasta", + "FrmMain.MnuPanToRightSide": "Mover imagem para o lado direito", + "_.Metadata._ExifRatingPercent": "Classificação", + "FrmSettings._PanSpeed": "Velocidade de deslocação", + "_._CheckForUpdate": "Verificar se há atualizações…", + "FrmSettings.Layout._ToolbarContext": "Barra de ferramentas contextual", + "_.ImageInfo._FrameCount": "{0} fotograma(s)", + "FrmMain.MnuLayout": "Disposição", + "_._Website": "Site", + "FrmMain.MnuPasteImage": "Colar imagem", + "FrmSettings._ShowGalleryScrollbars": "Mostrar barra de deslocação na galeria" + } +} \ No newline at end of file diff --git a/Setup/Assets/Language/Romanian.iglang.json b/Setup/Assets/Language/Romanian.iglang.json new file mode 100644 index 000000000..69aaacab0 --- /dev/null +++ b/Setup/Assets/Language/Romanian.iglang.json @@ -0,0 +1,504 @@ +{ + "_Metadata": { + "Code": "ro-RO", + "EnglishName": "Romanian", + "LocalName": "Română", + "Author": "RazvanS", + "MinVersion": "9.3" + }, + "Items": { + "FrmCrop.SelectionAspectRatio._Original": "Original", + "FrmMain.MnuShare._Error": "Could not open Share dialog.", + "_.Metadata._FileLastAccessTime": "Date accessed", + "FrmAbout._License": "Software license", + "FrmSettings.Toolbar._Errors._ButtonIdDuplicated": "A button with the ID '{0}' has already been defined. Please choose a different and unique ID for your button to avoid conflicts.", + "FrmMain.MnuSave._Confirm": "Are you sure you want to override this image?", + "FrmSettings._OpenDefaultAppsSetting": "Open Default apps setting", + "FrmMain.MnuCopyPath": "Copiază calea imaginii", + "FrmCropSettings.DefaultSelectionType._SelectNone": "Select none", + "_.MouseWheelAction._PanHorizontally": "Pan left / right", + "FrmMain.MnuPrint": "Tipărește…", + "FrmSettings.Toolbar._ToolbarButtons": "Toolbar buttons", + "FrmResize.LblResample": "Resample:", + "_.ImageOrderBy._Extension": "Extensie", + "FrmSettings.Nav._Viewer": "Vizualizator", + "FrmSettings.EditAppDialog._EditApp": "Edit app", + "FrmCrop.BtnReset._Tooltip": "Reset selection", + "FrmMain.MnuRename._Description": "Enter a new filename:", + "_._No": "No", + "FrmSlideshow.MnuToggleCountdown": "Arată numărătoarea inversă slideshow", + "FrmSettings._OpenStartupAppsSetting": "Open Startup apps setting", + "FrmMain.MnuViewPreviousFrame": "View previous frame", + "_.ImageOrderBy._DateModified": "Date modified", + "FrmMain.MnuViewNextFrame": "View next frame", + "FrmMain.MnuUnload": "Unload image", + "FrmSettings.Toolbar._HideToolbarInFullscreen": "Hide toolbar in Full Screen mode", + "_.ImageOrderType._Desc": "Descrescător", + "_._Update": "Update", + "FrmSettings._EnableImageAsyncLoading": "Enable image asynchronous loading", + "FrmSettings._DefaultPhotoViewer._Description": "Register the supported formats of ImageGlass with Windows. You might need to open the Default apps settings and manually select ImageGlass from the list for it to take effect.", + "_.MouseWheelAction._BrowseImages": "View next / previous Image", + "FrmSettings._EditApps": "Image editing apps", + "FrmColorPickerSettings.ChkShowCIELabA": "Use CIELAB format with alpha value", + "_._GetHelp": "Get help", + "FrmQuickSetup._SkipQuickSetup": "Skip this and launch ImageGlass", + "FrmColorPickerSettings._Title": "Color picker settings", + "_._Copy": "Copiază", + "FrmSettings._ImageBoosterCacheCount": "Number of images cached by Image Booster (one direction)", + "FrmMain.MnuPanToBottom": "Pan image to bottom", + "FrmMain.MnuZoom": "Lupă", + "FrmCropSettings.ChkCloseToolAfterSaving": "Close Crop tool after saving", + "FrmSettings._ShowWelcomeImage": "Show welcome image", + "FrmSettings._ColorProfile": "Color profile", + "FrmSettings._Theme._UninstallTheme": "Uninstall a theme pack", + "FrmMain._OpenWith": "Open with {0}", + "FrmMain.MnuRemoveDefaultPhotoViewer": "Remove default photo viewer", + "_.AfterEditAppAction._Nothing": "Nimic", + "FrmCrop.BtnSave": "Salvează", + "FrmMain.MnuScaleToFit": "Scalează să încapă", + "FrmToolNotFound.LblDownloadToolText": "You can download more tools for ImageGlass at:", + "_._LearnMore": "Aflați mai multe…", + "FrmCrop.LblAspectRatio": "Aspect ratio:", + "FrmExportFrames._FileNotExist": "Image file does not exist", + "FrmSettings._LightTheme": "Light", + "FrmSettings.Nav._Slideshow": "Prezentare", + "_._Continue": "Continuă", + "_._AddHotkey": "Add hotkey…", + "FrmMain.MnuSetDesktopBackground": "Plasează ca imagine de fundal", + "FrmMain.MnuReload": "Reîncarcă imaginea", + "FrmSlideshow.MnuExitSlideshow": "Părăsire prezentare", + "FrmMain.MnuAutoZoom": "Zoom automat", + "FrmSettings._ShowImagePreview": "Display image preview while it's being loaded", + "FrmCrop.BtnCopy._Tooltip": "Copy the selection to clipboard", + "FrmSettings.Nav._Toolbar": "Bara de unelte", + "FrmMain.MnuSave._Error": "Could not save the image", + "FrmSettings._AfterEditingAction": "După deschiderea aplicației de editare", + "FrmSettings._ShouldUseColorProfileForAll": "Aplică și pentru imaginile fără profilul de culoare încorporat", + "FrmCropSettings.DefaultSelectionType._UseTheLastSelection": "Use the last selection", + "FrmSettings._SlideshowInterval._From": "From", + "FrmSettings._ImageInterpolation": "Image interpolation", + "FrmQuickSetup._StepInfo": "Step {0}", + "FrmMain.MnuColorPicker": "Selector culoare", + "FrmCrop.SelectionAspectRatio._FreeRatio": "Free ratio", + "FrmSettings._ResetSettings": "Reset settings", + "FrmSettings._Startup": "Startup", + "_.BackdropStyle._None": "Nimic", + "FrmSettings._LoadDefaultZoomLevels": "Load default zoom levels", + "FrmColorPicker.BtnSettings._Tooltip": "Open Color picker settings…", + "FrmSettings._UseThemeForDarkMode": "Use this theme for dark mode", + "FrmSettings._ShowDeleteConfirmation": "Show confirmation dialog when deleting file", + "FrmSettings._ShowAppIcon": "Show app icon on the title bar", + "_._InvalidAction": "Invalid action", + "FrmQuickSetup._SelectProfile": "Select a profile", + "_.Metadata._FileCreationTime": "Date created", + "FrmSettings._SlideshowImagesToNotifySound": "Number of images to trigger a notification sound", + "FrmSettings._BackgroundColor": "Viewer background color", + "FrmSettings._RealTimeFileUpdate": "Real-time file update", + "_.ColorProfileOption._CurrentMonitorProfile": "Current monitor profile", + "FrmSettings._EnableCutMultipleFiles": "Enable the cutting of multiple files at once", + "FrmSettings._AutoUpdate": "Caută automat actualizări", + "FrmCropSettings.LblDefaultSelection": "Default selection", + "FrmSettings._UseThemeForLightMode": "Use this theme for light mode", + "FrmSettings._ZoomLevels": "Nivel mărire", + "FrmMain.MnuSetLockScreen._Success": "Lock screen image is updated", + "FrmSettings._ShowGalleryFileName": "Show thumbnail filename", + "FrmSettings.Layout._Order": "Order", + "FrmCropSettings.ChkAutoCenterSelection": "Auto-center selection", + "FrmSettings.Nav._FileTypeAssociations": "File type associations", + "_._Back": "Înapoi", + "FrmMain.MnuSetDesktopBackground._Success": "Desktop background is updated", + "FrmSettings._ShouldAutoOpenNewAddedImage": "Open the new added image automatically", + "FrmCrop.SelectionAspectRatio._Custom": "Personalizat…", + "FrmMain.MnuCopyPath._Success": "Copied the current image path.", + "FrmSettings._StartupBoost._Error": "Could not change Startup Boost setting", + "FrmToolNotFound.LblDescription": "ImageGlass was unable to locate the path to the '{0}' executable. To resolve this issue, please update the path to the '{0}' as necessary.", + "FrmMain.MnuClearClipboard": "Golește clipboard", + "FrmSettings._ColorManagement": "Gestionare culori", + "FrmMain._ReachedLastLast": "Am ajuns la ultima imagine", + "FrmMain.MnuPanUp": "Pan image up", + "FrmMain.MnuRemoveDefaultPhotoViewer._Success": "ImageGlass is no longer the default photo viewer.", + "FrmSettings._GetMoreLanguagePacks": "Obține mai multe pachete de limbă…", + "FrmAbout._Privacy": "Privacy policy", + "FrmSettings._EnableRecursiveLoading": "Load images in subfolders", + "_._UserAction._MethodArgumentNotSupported": "The argument type of method '{0}' is not supported", + "FrmSettings._FileExtensionIcons._Description": "For customizing file extension icons, download an icon pack, place all .ICO files in the extension icon folder, and click the '{0}' button. This will also set ImageGlass as default photo viewer.", + "_.ImageOrderType._Asc": "Crescător", + "FrmExportFrames._Title": "Export image frames", + "_._Install": "Instalează…", + "FrmMain.MnuFlipHorizontal": "Rotește pe orizontală", + "FrmSettings._OpenExtensionIconFolder": "Open extension icon folder", + "FrmAbout._Collaborator": "Collaborator:", + "FrmQuickSetup._ConfirmCloseProcess": "Before applying the new settings, it's essential to close all ImageGlass processes. Are you ready to proceed?", + "FrmExportFrames._ExportDone": "Exported {0} frames successfully to \r\n{1}", + "FrmCrop.BtnSaveAs._Tooltip": "Save as a copy…", + "FrmMain.MnuOpenFile": "Deschide fişier…", + "FrmColorPickerSettings.ChkShowRgbA": "Use RGB format with alpha value", + "_.ImageInfo._ListCount": "{0} file(s)", + "FrmMain.MnuGoToLast": "Go to last image", + "FrmSettings._EditApps._AppName": "Numele aplicației", + "FrmSettings._SlideshowBackgroundColor": "Slideshow background color", + "FrmAbout._Email": "Email:", + "_.MouseWheelAction._DoNothing": "Nicio acțiune", + "FrmMain.MnuSaveAs": "Salvează ca…", + "FrmMain._Loading": "Loading…", + "_._Browse": "Răsfoiește…", + "FrmMain.MnuSetDefaultPhotoViewer._Error": "Could not set ImageGlass as default photo viewer.", + "FrmSettings.Nav._Language": "Limba", + "FrmQuickSetup._SeeWhatNew": "See what's new in this version…", + "FrmSettings._ImageInterpolation._ScaleUp": "When zoom > 100%", + "FrmSettings.Layout._ToolbarContextPosition": "Contextual toolbar position", + "FrmMain.MnuDeleteFromHardDisk": "Delete permanently", + "FrmSettings._EmbeddedThumbnail": "Embedded thumbnail", + "FrmMain.MnuDeleteFromHardDisk._Description": "Are you sure you want to permanently delete this file?", + "FrmMain.MnuScaleToFill": "Scalează să umple", + "FrmCrop.BtnCrop": "Crop", + "_.AfterEditAppAction._Minimize": "Micşorează", + "FrmMain.MnuInvertColors": "Invert colors", + "FrmSettings._StartupBoost": "Startup Boost", + "FrmMain.MnuViewFirstFrame": "View first frame", + "_.MouseWheelEvent._CtrlAndScroll": "Hold Ctrl and scroll", + "FrmSettings._HideMainWindowInSlideshow": "Automatically hide main window", + "_.Metadata._FrameCount": "Frames", + "FrmSettings._EnableCopyMultipleFiles": "Enable the copying of multiple files at once", + "FrmMain.MnuFrameless._EnableDescription": "Hold Shift key to move the window.", + "_.ImageOrderBy._ExifDateTaken": "EXIF: Date taken", + "FrmAbout._Credits": "Credits", + "FrmSettings._AddNewFileExtension": "Add new file extension", + "FrmMain.MnuQuickSetup": "Open ImageGlass Quick Setup", + "FrmMain.MnuSave._Success": "Image is saved", + "FrmMain.MnuPanLeft": "Pan image left", + "FrmUpdate._StatusChecking": "Checking for update…", + "FrmSettings.Nav._Layout": "Dispunere", + "FrmMain.MnuOpenWith": "Deschide cu…", + "FrmAbout._Thanks": "Special thanks to", + "_._Warning": "Warning", + "FrmSettings.Nav._Keyboard": "Tastatură", + "FrmSlideshow._PauseSlideshow": "Slideshow is paused.", + "_._Add+": "Adaugă…", + "_._Email": "E-mail", + "FrmMain.MnuPanDown": "Pan image down", + "_._Cancel": "Anulează", + "_._OK": "Ok", + "FrmMain.MnuPanRight": "Pan image right", + "_.Position._Right": "Right", + "_._Icon": "Icon", + "FrmSettings._ShouldLoadHiddenImages": "Load hidden images", + "_._InvalidAction._Transformation": "ImageGlass does not support rotation, flipping for this image.", + "FrmSettings._MakeDefault": "Make default", + "FrmMain.MnuCopyImageData._Copying": "Copying the image data. It's going to take a while…", + "FrmSettings._UseEmbeddedThumbnailRawFormats": "Load only the embedded thumbnail for RAW formats", + "_.ImageInterpolation._Linear": "Linear", + "FrmSettings._ImageInfoTags": "Image information tags", + "FrmSettings._FileExtensionIcons": "File extension icons", + "FrmMain.MnuEdit._AppNotFound": "Could not find the associated app for editing. You can assign an app for editing this format in ImageGlass Settings > Edit.", + "_.ColorProfileOption._None": "Nimic", + "FrmSettings._TotalSupportedFormats": "Total supported formats: {0}", + "FrmSettings._Clipboard": "Clipboard", + "_._UserAction._Win32ExeError": "Cannot execute command '{0}'. Make sure the name is correct.", + "FrmCropSettings.DefaultSelectionType._SelectX": "Select {0}", + "_.AfterEditAppAction._Close": "Închidere", + "FrmAbout._LogoDesigner": "Logo designer:", + "_.ImageOrderBy._Name": "Nume (implicit)", + "FrmMain.MnuRemoveDefaultPhotoViewer._Error": "Could not remove ImageGlass as the default photo viewer.", + "FrmExportFrames._FolderPickerTitle": "Select output folder for exporting image frames", + "FrmAbout._Donate": "Donate", + "FrmMain.MnuFrameNav": "Frame navigation", + "FrmMain.MnuSetLockScreen": "Setează ca fundal pentru lockscreen", + "_._Delete": "Șterge", + "FrmMain.MnuViewPrevious": "Vezi imaginea anterioară", + "_.Position._Top": "Sus", + "FrmSettings.Toolbar._CurrentButtons": "Current buttons:", + "FrmMain.MnuAbout": "Despre", + "FrmSettings._RemoveDefault": "Remove default", + "_._Description": "Descriere", + "FrmMain.MnuPasteImage._Error": "Could not find image data in the Clipboard", + "FrmMain.MnuSettings": "Configurări", + "FrmCropSettings._Title": "Crop settings", + "FrmSettings.Toolbar._ToolbarIconHeight": "Dimensiunea pictogramei din bara de instrumente", + "FrmSettings._SlideshowInterval._To": "To", + "FrmSettings.Layout._ToolbarPosition": "Poziție bară de instrumente", + "FrmUpdate._StatusUpdated": "You are using the latest version!", + "FrmMain.MnuExit": "Ieșire", + "_._Webview2._Outdated": "Your WebView2 Runtime is not supported. Please update to version {0} or later.", + "_._Yes": "Da", + "FrmMain.MnuRotateLeft": "Rotire la stânga", + "FrmSettings._EnableStartupBoost": "Enable Startup Boost", + "_.ImageOrderBy._ExifRating": "EXIF: Rating", + "FrmMain.MnuZoomIn": "Mărire", + "_.Metadata._ColorSpace": "Color space", + "FrmAbout._Version": "Version:", + "FrmMain.MnuToggleTopMost._Enable": "Enabled window always on top", + "FrmSettings.Toolbar._AvailableButtons": "Available buttons:", + "FrmMain.MnuSave._Saving": "Saving image…", + "FrmQuickSetup._StandardUser": "Standard user", + "FrmMain.MnuSetLockScreen._Error": "Could not set the viewing image as lock screen image", + "FrmSettings.Nav._Image": "Imagine", + "FrmSettings._Theme._InstallTheme": "Install theme packs", + "FrmSettings._EnableMultiInstances": "Permite mai multe instanțe ale programului", + "FrmMain.MnuCropTool": "Crop image", + "_._IgCommandExe._DefaultError._Heading": "Invalid commands", + "_._Refresh": "Reîmprospătare", + "FrmMain.MnuLosslessCompression._Description": "This tool uses Magick.NET library for lossless compression, optimizing file size. Overwrites only if the compressed file is smaller than the original.", + "_._MoveDown": "Move down", + "FrmSettings._GetExtensionIconPacks": "Get extension icon packs…", + "FrmSettings._InAppMessageDuration": "In-app message duration (milliseconds)", + "FrmMain.MnuFrameless": "Fară ramă", + "_._Reset": "Resetează", + "FrmSettings._ConfigDir": "Configuration location", + "FrmQuickSetup._SettingsWillBeApplied": "Settings will be applied:", + "FrmSettings._UnmanagedSettingReminder": "This setting is not managed by ImageGlass. Don't forget to disable it before you remove or relocate the app because ImageGlass does not handle this automatically.", + "FrmMain.MnuClipboard": "Clipboard", + "FrmMain.MnuCustomZoom": "Zoom personalizat…", + "FrmSettings._DisplayLanguage": "Display language", + "FrmMain.MnuPrint._Error": "Could not print the viewing image", + "FrmSettings._ShouldPreserveModifiedDate": "Păstrează data modificării imaginii la salvare", + "FrmSettings._ShowSaveOverrideConfirmation": "Show confirmation dialog when overriding file", + "FrmColorPickerSettings.ChkShowHexA": "Use HEX format with alpha value", + "FrmMain.MnuFullScreen": "Full Screen", + "FrmSettings._StartupDir": "Startup location", + "FrmSettings._ShowCheckerboardOnlyImageRegion": "Show checkerboard only within the image region", + "FrmMain.MnuClearClipboard._Success": "Cleared clipboard.", + "FrmQuickSetup._Text": "ImageGlass Quick Setup", + "FrmMain.MnuLosslessCompression._Done": "Done lossless compression.\r\nThe new file size is {0}, saved {1}.", + "FrmMain.MnuLosslessCompression": "Magick.NET Lossless Compression", + "FrmResize.RadResizeByPercentage": "Percentage", + "FrmSettings._StartupBoost._Disabled": "Startup Boost is disabled", + "FrmMain.MnuToggleCheckerboard": "Fundal caroiat", + "FrmSettings._MinEmbeddedThumbnailSize._Height": "Înălţime", + "FrmSettings.Nav._General": "General", + "FrmSettings._ImageLoading": "Imaginea se încarcă", + "FrmSettings._ShowSlideshowCountdown": "Arată numărătoarea inversă slideshow", + "FrmMain.MnuSave": "Salvează", + "FrmMain.MnuMoveToRecycleBin": "Move to the Recycle Bin", + "FrmMain.MnuRefresh": "Reîmprospătare", + "FrmToolNotFound.LblHeading": "'{0}' is not found!", + "FrmMain.MnuReportIssue": "Raportează o problemă…", + "FrmMain.MnuCopyImageData": "Copiează date imagine", + "FrmMain.MnuCheckForUpdate._NewVersion": "O nouă versiune este disponibilă!", + "_._Empty": "(empty)", + "FrmSettings._Zooming": "Nivel zoom", + "FrmMain.MnuCutFile": "Cut file", + "FrmHotkeyPicker.LblHotkey": "Press hotkeys", + "FrmSettings.Layout._Gallery": "Gallery", + "FrmMain.MnuNewWindow": "Deschide o nouă fereastră", + "FrmMain.MnuMoveToRecycleBin._Description": "Do you want to move this file to the Recycle bin?", + "FrmSettings._DefaultPhotoViewer": "Default photo viewer", + "_.Metadata._ExifDateTimeOriginal": "EXIF: DateTimeOriginal", + "FrmMain.MnuRotateRight": "Rotire la dreapta", + "FrmSettings._MinEmbeddedThumbnailSize": "Minimum size of the embedded thumbnail to be loaded", + "FrmMain.MnuSetDefaultPhotoViewer": "Set default photo viewer", + "FrmMain.MnuImageProperties": "Proprietăți imagine", + "FrmSettings._EnableNavigationButtons": "Show navigation arrow buttons", + "_._Edit": "Editează", + "FrmSettings._ImageBooster": "Image Booster", + "FrmSettings.Tools._IntegratedWith": "Integrated with {0}", + "_._Next": "Următorul", + "FrmExportFrames._OpenOutputFolder": "Open output folder", + "FrmMain.MnuOpenLocation": "Deschidere localizare imagine", + "FrmMain.MnuLockZoom": "Blocare aspect", + "FrmSettings._StartupBoost._Description": "Preload and run ImageGlass in the background for a few seconds during Windows startup to accelerate the first launch.", + "FrmSettings._WindowBackdrop": "Window backdrop", + "FrmSettings._EnableRealTimeFileUpdate": "Monitor file changes in the viewing folder and update in realtime", + "_._NotSupported": "Unsupported format", + "FrmSettings._Theme._GetMoreThemes": "Get more theme packs…", + "FrmMain.MnuNewWindow._Error": "Cannot open new window because only one instance is allowed", + "FrmMain.MnuZoomOut": "Micșorare", + "FrmSettings.Toolbar._EditButton": "Edit toolbar button", + "FrmMain.MnuCustomZoom._Description": "Introduceți o nouă valoare de zoom", + "FrmResize.RadResizeByPixels": "Pixels", + "FrmMain.MnuEdit": "Editează imaginea {0}…", + "FrmSettings.Layout._GalleryPosition": "Gallery position", + "FrmMain.MnuWindowFit": "Window Fit", + "FrmMain._OpenFileDialog": "Toate tipurile de fișiere suportate", + "FrmSettings._UseRandomIntervalForSlideshow": "Folosește interval aleatoriu", + "_.Position._Left": "Left", + "FrmSettings._ShouldOpenLastSeenImage": "Open the last seen image", + "_.Position._Bottom": "Jos", + "FrmResize.ChkKeepRatio": "Keep ratio propotional", + "FrmMain.MnuGoTo": "Mergi la…", + "FrmSlideshow.MnuPauseResumeSlideshow": "Pause/resume slideshow", + "FrmSettings.Tools._Integrated": "Integrated", + "FrmSettings._Contributors": "Contributors", + "_.MouseWheelAction._Zoom": "Zoom in / out", + "_._CommandPreview": "Previzualizare comandă", + "FrmSettings._DarkTheme": "Dark", + "_._Hotkeys": "Hotkeys", + "_.Metadata._ExifDateTime": "EXIF: DateTime", + "FrmSettings.Toolbar._Errors._ButtonIdRequired": "Button ID required.", + "FrmSettings._MinEmbeddedThumbnailSize._Width": "Lățime", + "_._Executable": "Executable", + "_.ImageInterpolation._MultiSampleLinear": "Multi-sample linear", + "_._Separator": "Separator", + "FrmQuickSetup._ProfessionalUser": "Professional user", + "FrmMain.MnuFlipVertical": "Rotește pe verticală", + "FrmSlideshow._ResumeSlideshow": "Slideshow is resumed.", + "FrmCropSettings.DefaultSelectionType._CustomArea": "Custom area…", + "FrmMain.MnuActualSize": "Dimensiune reală", + "FrmCrop.BtnSaveAs": "Salvează ca…", + "FrmSettings._InstallNewLanguagePack": "Install new language packs…", + "FrmSlideshow.MnuZoomModes": "Zoom modes", + "FrmMain.MnuTools": "Unelte", + "_.ImageInterpolation._Cubic": "Cubic", + "FrmUpdate._LatestVersion": "The latest version: {0}", + "FrmMain.MnuViewNext": "Vezi imaginea urmatoare", + "_.MouseWheelEvent._AltAndScroll": "Hold Alt and scroll", + "FrmToolNotFound._Title": "Tool not found", + "FrmCrop.BtnCrop._Tooltip": "Crop the image only", + "FrmSettings.EditAppDialog._AddApp": "Add an app for editing", + "FrmMain.MnuPanning": "Panoramare", + "_._MoveUp": "Move up", + "FrmCropSettings.DefaultSelectionType._SelectAll": "Select all", + "_._Name": "Nume", + "FrmColorPickerSettings.ChkShowHslA": "Use HSL format with alpha value", + "FrmMain.MnuToggleImageAnimation": "Start / stop animating image", + "FrmSettings._DisableStartupBoost": "Disable Startup Boost", + "FrmMain.MnuCopyFile._Success": "Copied {0} file(s).", + "FrmMain.MnuSave._ConfirmDescription": "ImageGlass is not a professional photo editor, please be aware of losing the quality, metadata, layers,… when saving your image.", + "FrmToolNotFound.BtnSelectExecutable": "Select…", + "FrmUpdate._StatusOutdated": "A new update is available!", + "_.ImageOrderBy._Random": "Aleator", + "FrmResize.LblCurrentSize": "Current Size:", + "_._Apply": "Aplică", + "FrmAbout._Slogan": "Un vizualizator de imagini ușor, versatil", + "FrmMain.MnuPanToTop": "Pan image to top", + "FrmSettings.Toolbar._AddNewButton": "Add a custom toolbar button", + "FrmCrop.LblSize": "Size:", + "FrmSettings._ImageInterpolation._ScaleDown": "When zoom < 100%", + "_._CreatingFileError": "Could not create temporary image file", + "FrmMain.MnuGoTo._Description": "Enter the image index to view, and then press ENTER", + "FrmSettings.Toolbar._EnableCenterToolbar": "Use center alignment for toolbar", + "FrmMain.MnuResizeTool": "Resize image", + "FrmSettings.Layout._Toolbar": "Bara de unelte", + "FrmMain.MnuHelp": "Ajutor", + "_.ImageOrderBy._FileSize": "File size", + "FrmSettings._Theme._OpenThemeFolder": "Deschide dosarul cu teme", + "FrmMain.MnuNavigation": "Navigare", + "_._Save": "Salvează", + "FrmQuickSetup._SettingProfileDescription": "To modify these settings, simply access app settings.", + "_._UserAction._MenuNotFound": "Cannot find menu '{0}' to invoke the action", + "FrmMain.MnuPanToLeftSide": "Pan image to left edge", + "FrmUpdate._CurrentVersion": "Current version: {0}", + "FrmCrop.BtnSettings._Tooltip": "Open Crop tool settings", + "_.ColorProfileOption._Custom": "Personalizat…", + "FrmSettings._UseEmbeddedThumbnailOtherFormats": "Load only the embedded thumbnail for other formats", + "FrmMain.MnuGoToFirst": "Go to first image", + "FrmSettings._ExportLanguagePack": "Export language pack…", + "FrmSettings.Nav._Mouse": "Mouse", + "_.ImageOrderBy._DateCreated": "Date created", + "FrmSettings._EnableFullscreenSlideshow": "Start slideshow in Full Screen mode", + "FrmAbout._Homepage": "Homepage:", + "FrmSettings._GalleryCacheSizeInMb": "Maximum gallery cache size (in megabytes)", + "FrmMain.MnuCopyImageData._Success": "Copied the current image data.", + "FrmSettings._EnableLoopBackNavigation": "Loop back to the first image when reaching the end of the image list", + "_.MouseWheelEvent._Scroll": "Scroll", + "FrmCrop.BtnSave._Tooltip": "Salvează imaginea", + "FrmMain.MnuSlideshow": "Prezentare", + "FrmMain.MnuShare": "Distribuie…", + "FrmSettings._SlideshowNotification": "Slideshow notification", + "FrmMain.MnuViewChannels": "Vizualizare canale", + "FrmSettings._Refresh": "Reîmprospătare", + "_._UserAction._MethodNotFound": "Cannot find method '{0}' to invoke the action", + "FrmMain.MnuCopyFile": "Copy file", + "_._CreatingFile": "Creating a temporary image file…", + "FrmMain.MnuToggleTopMost": "Păstrează fereastra deasupra", + "FrmMain.MnuLosslessCompression._Confirm": "Are you sure you want to proceed?", + "FrmMain.MnuImage": "Imagine", + "FrmSettings._StartupBoost._Enabled": "Startup Boost is enabled", + "FrmQuickSetup._SetDefaultViewer": "Do you want to set ImageGlass as the default photo viewer?", + "FrmMain.MnuScaleToWidth": "Scalare după lățime", + "_._FileExtension": "Extensie fișier", + "FrmUpdate._PublishedDate": "Published date: {0}", + "_._DoNotShowThisMessageAgain": "Do not show this message again", + "_.ImageInterpolation._NearestNeighbor": "Nearest neighbor", + "FrmCrop.LblLocation": "Location:", + "_._Download": "Download", + "_.Metadata._ColorProfile": "Color profile", + "FrmSettings._CenterWindowFit": "Automatically center the window in Window Fit mode", + "FrmSettings._ImageLoadingOrder": "Ordine încărcare imagine", + "FrmSettings._GalleryColumns": "Number of thumbnail columns in vertical gallery layout", + "_._Quit": "Ieșire", + "_._Add": "Adaugă", + "FrmMain.MnuChangeBackgroundColor": "Change background color…", + "FrmMain.MnuToggleToolbar": "Bara de unelte", + "FrmAbout._Contact": "Contact", + "FrmSettings.Toolbar._AddCustomButton": "Add a custom button…", + "FrmCrop.BtnQuickSelect._Tooltip": "Quick select…", + "FrmMain.MnuCutFile._Success": "Cut {0} file(s).", + "FrmSettings._ZoomSpeed": "Zoom speed", + "FrmMain.MnuToggleTopMost._Disable": "Disabled window always on top", + "FrmSettings._ShouldUseExplorerSortOrder": "Use Explorer sort order if possible", + "_.ImageInterpolation._Antisotropic": "Antisotropic", + "FrmMain._ReachedFirstImage": "Am ajuns la prima imagine", + "_._UnhandledException": "Unhandled exception", + "FrmResize.LblNewSize": "New Size:", + "FrmMain._ClipboardImage": "Clipboard image", + "FrmMain.MnuExportFrames": "Export image frames…", + "FrmMain.MnuFile": "Fișier", + "_._Close": "Închidere", + "FrmMain.MnuMain": "Meniu principal", + "_._ResetToDefault": "Resetare la valorile implicite", + "FrmSettings.Nav._Gallery": "Gallery", + "FrmMain.MnuSetDefaultPhotoViewer._Success": "You have successfully set ImageGlass as default photo viewer.", + "FrmSettings._HideGalleryInFullscreen": "Hide gallery in Full Screen mode", + "FrmSettings._AvailableImageInfoTags": "Available tags:", + "FrmExportFrames._Exporting": "Exporting {0}/{1} frames \r\n{2}…", + "_._Argument": "Argument", + "FrmSettings._ImageEditQuality": "Calitatea imaginii", + "_._ID": "ID", + "FrmSettings._UserConfigFile": "User settings file (igconfig.json)", + "FrmMain.MnuLoadingOrders": "Loading orders", + "FrmSettings._OpenSaveAsDialogInTheCurrentImageDir": "Open the Save As dialog in the current image directory", + "_.MouseWheelEvent._ShiftAndScroll": "Hold Shift and scroll", + "FrmSettings._UseSmoothZooming": "Use smooth zooming", + "FrmSettings._Theme": "Tema", + "FrmSettings._ImageBoosterCacheMaxDimension": "Maximum image dimension to be cached (in pixels)", + "FrmMain.MnuScaleToHeight": "Scalare după înălțime", + "_.Metadata._FileLastWriteTime": "Date modified", + "FrmSettings._Author": "Autor", + "FrmSettings._Others": "Altele", + "_.MouseWheelAction._PanVertically": "Pan up / down", + "FrmSettings._MouseWheelAction": "Mouse wheel action", + "FrmSettings.Nav._Tools": "Unelte", + "FrmMain.MnuSetDesktopBackground._Error": "Could not set the viewing image as desktop background", + "FrmSettings.Toolbar._Errors._ButtonExecutableRequired": "Button executable required.", + "_.ImageOrderBy._DateAccessed": "Date accessed", + "FrmSettings._ThumbnailSize": "Thumbnail size (in pixels)", + "FrmSettings._FileFormats": "File formats", + "FrmMain.MnuReloadImageList": "Reîncarcă lista de imagini", + "FrmSettings._UseWebview2ForSvg": "Use Webview2 for viewing SVG format", + "FrmCrop.BtnCopy": "Copiază", + "FrmSettings._CurrentMonitorProfile._Description": "ImageGlass does not auto-update the color when moving its window between monitors", + "FrmMain.PicMain._ErrorText": "Could not open this image", + "FrmSettings.Tools._AddNewTool": "Add an external tool", + "FrmMain.MnuRename": "Redenumește imaginea…", + "FrmMain.MnuViewLastFrame": "View last frame", + "_._Webview2._NotFound": "Please install WebView2 Runtime to access full features of ImageGlass.", + "FrmMain.MnuGetMoreTools": "Get more tools…", + "FrmSettings.Nav._Appearance": "Appearance", + "FrmSettings._SlideshowInterval": "Interval diapozitiv:", + "_.ImageInterpolation._HighQualityBicubic": "High quality bicubic", + "FrmColorPickerSettings.ChkShowHsvA": "Use HSV format with alpha value", + "FrmSettings.Tools._EditTool": "Edit external tool", + "_._Error": "Error", + "FrmSettings._ImageBoosterCacheMaxFileSizeInMb": "Maximum image file size to be cached (in megabytes)", + "_._UnhandledException._Description": "Unhandled exception has occurred. If you click Continue, the application will ignore this error and attempt to continue. If you click Quit, the application will close immediately.", + "_.Metadata._FileSize": "File size", + "FrmSettings.Toolbar._ButtonJson": "Button JSON", + "FrmQuickSetup._SetDefaultViewer._Description": "You can reset it in the app settings > File type associations tab.", + "FrmSettings.Nav._Edit": "Editează", + "FrmMain.MnuToggleGallery": "Gallery panel", + "_._IgCommandExe._DefaultError._Description": "Make sure you pass the correct commands!\r\nThis executable file contains command-line functions for ImageGlass software.\r\n\r\nTo explore all command lines, please visit:\r\n{0}", + "FrmMain.MnuLosslessCompression._Compressing": "Performing lossless compression…", + "FrmSettings._ShouldGroupImagesByDirectory": "Grupează imaginile după director", + "FrmMain.MnuPanToRightSide": "Pan image to right edge", + "_.Metadata._ExifRatingPercent": "Rating", + "FrmSettings._PanSpeed": "Panning speed", + "_._CheckForUpdate": "Verificați dacă există actualizări…", + "FrmSettings.Layout._ToolbarContext": "Contextual toolbar", + "_.ImageInfo._FrameCount": "{0} frame(s)", + "FrmMain.MnuLayout": "Dispunere", + "_._Website": "Site web", + "FrmMain.MnuPasteImage": "Paste image", + "FrmSettings._ShowGalleryScrollbars": "Show gallery scrollbars" + } +} \ No newline at end of file diff --git a/Setup/Assets/Language/Russian.iglang.json b/Setup/Assets/Language/Russian.iglang.json new file mode 100644 index 000000000..e50a9ba4a --- /dev/null +++ b/Setup/Assets/Language/Russian.iglang.json @@ -0,0 +1,504 @@ +{ + "_Metadata": { + "Code": "ru-RU", + "EnglishName": "Russian", + "LocalName": "Русский", + "Author": "DEHNCKA (Denis Velikanov), inkrimit (Вынгилев Алексей), DanRotaru (DanRotaru), zelyc81 (Гапоненко Евгений), Dimmimix (Dimmimix), Blueberry (Blueberryy), mak7im01 (mak7im01)", + "MinVersion": "9.3" + }, + "Items": { + "FrmCrop.SelectionAspectRatio._Original": "Исходное", + "FrmMain.MnuShare._Error": "Не удалось открыть диалоговое окно \"Поделиться\"", + "_.Metadata._FileLastAccessTime": "Дата доступа", + "FrmAbout._License": "Лицензия", + "FrmSettings.Toolbar._Errors._ButtonIdDuplicated": "Кнопка с идентификатором \"{0}\" уже есть. Пожалуйста, выберите другое уникальное имя идентификатора для вашей кнопки во избежание конфликтов.", + "FrmMain.MnuSave._Confirm": "Вы уверены, что хотите заменить это изображение?", + "FrmSettings._OpenDefaultAppsSetting": "→ Приложения по умолчанию …", + "FrmMain.MnuCopyPath": "Копировать путь к изображению", + "FrmCropSettings.DefaultSelectionType._SelectNone": "Ничего", + "_.MouseWheelAction._PanHorizontally": "Горизонтальная прокрутка", + "FrmMain.MnuPrint": "Печать ...", + "FrmSettings.Toolbar._ToolbarButtons": "Кнопки панели инструментов", + "FrmResize.LblResample": "Перерисовка:", + "_.ImageOrderBy._Extension": "Тип", + "FrmSettings.Nav._Viewer": "Настройки просмотра", + "FrmSettings.EditAppDialog._EditApp": "Изменение приложения", + "FrmCrop.BtnReset._Tooltip": "Отменить выбор", + "FrmMain.MnuRename._Description": "Введите новое имя файла:", + "_._No": "Нет", + "FrmSlideshow.MnuToggleCountdown": "Показывать обратный отсчёт времени в режиме показа презентации", + "FrmSettings._OpenStartupAppsSetting": "Открыть настройки автозагрузки приложений", + "FrmMain.MnuViewPreviousFrame": "Предыдущая страница", + "_.ImageOrderBy._DateModified": "Дата изменения", + "FrmMain.MnuViewNextFrame": "Следующая страница", + "FrmMain.MnuUnload": "Выгрузить изображение", + "FrmSettings.Toolbar._HideToolbarInFullscreen": "Скрывать панель инструментов в полноэкранном режиме", + "_.ImageOrderType._Desc": "По убыванию", + "_._Update": "Обновление", + "FrmSettings._EnableImageAsyncLoading": "Включить асинхронную загрузку изображений", + "FrmSettings._DefaultPhotoViewer._Description": "Зарегистрируйте поддерживаемые форматы ImageGlass с Windows. Возможно, вам придется открыть настройки приложений по умолчанию и вручную выбрать ImageGlass из списка, чтобы изменения вступили в силу.", + "_.MouseWheelAction._BrowseImages": "Предыдущее / следующее", + "FrmSettings._EditApps": "Укажите свои приложения для редактирования изображений", + "FrmColorPickerSettings.ChkShowCIELabA": "Использовать \"CIELAB\" формат с α-каналом", + "_._GetHelp": "Справка", + "FrmQuickSetup._SkipQuickSetup": "Пропустить и начать использовать ImageGlass", + "FrmColorPickerSettings._Title": "Параметры инструмента \"Пипетка\"", + "_._Copy": "Копировать", + "FrmSettings._ImageBoosterCacheCount": "Количество файлов, загружаемых ускорителем изображений (в одной директории)", + "FrmMain.MnuPanToBottom": "К нижнему краю", + "FrmMain.MnuZoom": "Масштабирование", + "FrmCropSettings.ChkCloseToolAfterSaving": "Закрывать после сохранения", + "FrmSettings._ShowWelcomeImage": "Показывать приветственное изображение", + "FrmSettings._ColorProfile": "Цветовой профиль", + "FrmSettings._Theme._UninstallTheme": "Удалить тему", + "FrmMain._OpenWith": "Открыть с помощью {0}", + "FrmMain.MnuRemoveDefaultPhotoViewer": "Отменить регистрацию расширений", + "_.AfterEditAppAction._Nothing": "Оставить ImageGlass", + "FrmCrop.BtnSave": "Сохранить", + "FrmMain.MnuScaleToFit": "Изображение по размеру окна", + "FrmToolNotFound.LblDownloadToolText": "Вы можете скачать больше инструментов для ImageGlass тут:", + "_._LearnMore": "Подробнее …", + "FrmCrop.LblAspectRatio": "Соотношение сторон:", + "FrmExportFrames._FileNotExist": "Файл изображения не найден", + "FrmSettings._LightTheme": "Светло", + "FrmSettings.Nav._Slideshow": "Презентация", + "_._Continue": "Далее", + "_._AddHotkey": "Добавить горячую клавишу …", + "FrmMain.MnuSetDesktopBackground": "Сделать фоновым изображением рабочего стола", + "FrmMain.MnuReload": "Обновить изображение", + "FrmSlideshow.MnuExitSlideshow": "Покинуть режим презентации", + "FrmMain.MnuAutoZoom": "Автоматическое масштабирование", + "FrmSettings._ShowImagePreview": "Показывать эскиз изображения пока оно загружается", + "FrmCrop.BtnCopy._Tooltip": "Копировать выделенное в буфер обмена", + "FrmSettings.Nav._Toolbar": "Панель инструментов", + "FrmMain.MnuSave._Error": "Не удалось сохранить изображение", + "FrmSettings._AfterEditingAction": "После открытия в редакторе", + "FrmSettings._ShouldUseColorProfileForAll": "Применять и для изображений без внедрённого цветового профиля", + "FrmCropSettings.DefaultSelectionType._UseTheLastSelection": "Последний вариант", + "FrmSettings._SlideshowInterval._From": "С", + "FrmSettings._ImageInterpolation": "Интерполяция изображения", + "FrmQuickSetup._StepInfo": "Шаг {0}", + "FrmMain.MnuColorPicker": "Пипетка", + "FrmCrop.SelectionAspectRatio._FreeRatio": "Свободное", + "FrmSettings._ResetSettings": "Сбросить настройки", + "FrmSettings._Startup": "При запуске", + "_.BackdropStyle._None": "Отсутствует", + "FrmSettings._LoadDefaultZoomLevels": "Загрузить стандартные настройки уровней масштабирования", + "FrmColorPicker.BtnSettings._Tooltip": "Открыть настройки инструмента \"Пипетка\" …", + "FrmSettings._UseThemeForDarkMode": "Использовать эту тему для тёмного режима", + "FrmSettings._ShowDeleteConfirmation": "Запрашивать подтверждение на удаление файла", + "FrmSettings._ShowAppIcon": "Показывать логотип ImageGlass в заголовке окна", + "_._InvalidAction": "Недопустимое действие", + "FrmQuickSetup._SelectProfile": "Выберите профиль", + "_.Metadata._FileCreationTime": "Дата создания", + "FrmSettings._SlideshowImagesToNotifySound": "Период подачи сигнала при показе презентации (в количестве изображений)", + "FrmSettings._BackgroundColor": "Цвет подложки", + "FrmSettings._RealTimeFileUpdate": "Обновление файлов в реальном времени", + "_.ColorProfileOption._CurrentMonitorProfile": "Текущий профиль монитора", + "FrmSettings._EnableCutMultipleFiles": "Включить пакетное вырезание", + "FrmSettings._AutoUpdate": "Проверять обновления автоматически", + "FrmCropSettings.LblDefaultSelection": "Выделять по умолчанию", + "FrmSettings._UseThemeForLightMode": "Использовать эту тему для светлого режима", + "FrmSettings._ZoomLevels": "Уровни масштабирования", + "FrmMain.MnuSetLockScreen._Success": "Изображение успешно установлено в качестве фона экрана блокировки", + "FrmSettings._ShowGalleryFileName": "Показывать имя файла эскиза", + "FrmSettings.Layout._Order": "Порядок", + "FrmCropSettings.ChkAutoCenterSelection": "Автоцентрирование", + "FrmSettings.Nav._FileTypeAssociations": "Ассоциации файлов", + "_._Back": "Назад", + "FrmMain.MnuSetDesktopBackground._Success": "Изображение успешно установлено в качестве фона рабочего стола", + "FrmSettings._ShouldAutoOpenNewAddedImage": "Автоматически открывать новое добавленное изображение", + "FrmCrop.SelectionAspectRatio._Custom": "Своё", + "FrmMain.MnuCopyPath._Success": "Текущий путь к изображению скопирован", + "FrmSettings._StartupBoost._Error": "Не удалось изменить настройку \"Быстрого запуска\"", + "FrmToolNotFound.LblDescription": "ImageGlass не удалось найти путь к исполняемому файлу \"{0}\". Чтобы решить эту проблему, пожалуйста, обновите путь к \"{0}\" при необходимости.", + "FrmMain.MnuClearClipboard": "Очистить буфер обмена", + "FrmSettings._ColorManagement": "Управление цветом", + "FrmMain._ReachedLastLast": "Перейти к последнему изображению", + "FrmMain.MnuPanUp": "Шаг вверх", + "FrmMain.MnuRemoveDefaultPhotoViewer._Success": "ImageGlass больше не является средством просмотра фотографий по умолчанию.", + "FrmSettings._GetMoreLanguagePacks": "→ Скачать языковые пакеты …", + "FrmAbout._Privacy": "Политика конфиденциальности", + "FrmSettings._EnableRecursiveLoading": "Искать изображения во вложенных папках", + "_._UserAction._MethodArgumentNotSupported": "Тип аргумента метода \"{0}\" не поддерживается", + "FrmSettings._FileExtensionIcons._Description": "Чтобы изменить иконки расширений файлов, загрузите пакет иконок, поместите все файлы *.ICO в папку иконок и нажмите кнопку \"{0}\". Это также сделает ImageGlass средством просмотра фотографий по умолчанию.", + "_.ImageOrderType._Asc": "По возрастанию", + "FrmExportFrames._Title": "Извлечь страницы файла", + "_._Install": "Установить ...", + "FrmMain.MnuFlipHorizontal": "Перевернуть по горизонтали", + "FrmSettings._OpenExtensionIconFolder": "Открыть папку с иконками расширений", + "FrmAbout._Collaborator": "Соавтор:", + "FrmQuickSetup._ConfirmCloseProcess": "Перед применением новых настроек потребуется закрыть все процессы ImageGlass. Вы готовы продолжить?", + "FrmExportFrames._ExportDone": "Успешно экспортировано {0} стр. из \n{1}", + "FrmCrop.BtnSaveAs._Tooltip": "Сохранить копию …", + "FrmMain.MnuOpenFile": "Открыть файл ...", + "FrmColorPickerSettings.ChkShowRgbA": "Использовать \"RGB\" формат с α-каналом", + "_.ImageInfo._ListCount": "{0} ф.", + "FrmMain.MnuGoToLast": "К последнему изображению", + "FrmSettings._EditApps._AppName": "Имя приложения", + "FrmSettings._SlideshowBackgroundColor": "Цвет фона в режиме презентации:", + "FrmAbout._Email": "Электронная почта:", + "_.MouseWheelAction._DoNothing": "Без действия", + "FrmMain.MnuSaveAs": "Сохранить как ...", + "FrmMain._Loading": "Загрузка …", + "_._Browse": "Обзор ...", + "FrmMain.MnuSetDefaultPhotoViewer._Error": "Не удалось установить ImageGlass как средство просмотра фотографий по умолчанию.", + "FrmSettings.Nav._Language": "Язык", + "FrmQuickSetup._SeeWhatNew": "→ Посмотреть что нового в этой версии …", + "FrmSettings._ImageInterpolation._ScaleUp": "Когда масштаб > 100%", + "FrmSettings.Layout._ToolbarContextPosition": "Положение контекстной панели", + "FrmMain.MnuDeleteFromHardDisk": "Удалить безвозвратно", + "FrmSettings._EmbeddedThumbnail": "Встроенные эскизы", + "FrmMain.MnuDeleteFromHardDisk._Description": "Вы действительно хотите безвозвратно удалить этот файл?", + "FrmMain.MnuScaleToFill": "Заполнить окно", + "FrmCrop.BtnCrop": "Обрезать", + "_.AfterEditAppAction._Minimize": "Свернуть ImageGlass", + "FrmMain.MnuInvertColors": "Инвертировать цвета", + "FrmSettings._StartupBoost": "Быстрый запуск", + "FrmMain.MnuViewFirstFrame": "К первой странице", + "_.MouseWheelEvent._CtrlAndScroll": "\"Ctrl\" + колесо мыши", + "FrmSettings._HideMainWindowInSlideshow": "Автоматически скрывать главное окно", + "_.Metadata._FrameCount": "Страницы", + "FrmSettings._EnableCopyMultipleFiles": "Включить пакетное копирование", + "FrmMain.MnuFrameless._EnableDescription": "Удерживайте клавишу \"Shift\" чтобы переместить окно.", + "_.ImageOrderBy._ExifDateTaken": "EXIF: Дата выбрана", + "FrmAbout._Credits": "Авторские права", + "FrmSettings._AddNewFileExtension": "Добавить …", + "FrmMain.MnuQuickSetup": "Конфигуратор первичных настроек …", + "FrmMain.MnuSave._Success": "Изображение сохранено", + "FrmMain.MnuPanLeft": "Шаг влево", + "FrmUpdate._StatusChecking": "Проверить обновления ...", + "FrmSettings.Nav._Layout": "Внешний вид", + "FrmMain.MnuOpenWith": "Открыть с помощью ...", + "FrmAbout._Thanks": "Отдельные благодарности:", + "_._Warning": "Внимание", + "FrmSettings.Nav._Keyboard": "Клавиатура", + "FrmSlideshow._PauseSlideshow": "Показ приостановлен.", + "_._Add+": "Добавить ...", + "_._Email": "Электронная почта", + "FrmMain.MnuPanDown": "Шаг вниз", + "_._Cancel": "Отмена", + "_._OK": "OK", + "FrmMain.MnuPanRight": "Шаг вправо", + "_.Position._Right": "Справа", + "_._Icon": "Иконка", + "FrmSettings._ShouldLoadHiddenImages": "Загружать скрытые изображения", + "_._InvalidAction._Transformation": "ImageGlass не поддерживает вращение и переворачивание данного изображения.", + "FrmSettings._MakeDefault": "Использовать по умолчанию", + "FrmMain.MnuCopyImageData._Copying": "Копирование данных изображения Это займёт некоторое время …", + "FrmSettings._UseEmbeddedThumbnailRawFormats": "Загружать только встроенный эскиз для \"RAW\" форматов", + "_.ImageInterpolation._Linear": "Билинейный метод", + "FrmSettings._ImageInfoTags": "Теги информации об изображении", + "FrmSettings._FileExtensionIcons": "Иконки расширений файлов", + "FrmMain.MnuEdit._AppNotFound": "Не удалось найти приложение для редактирования. Вы можете назначить приложение для редактирования этого формата в настройках ImageGlass → Редактирование", + "_.ColorProfileOption._None": "Отсутствует", + "FrmSettings._TotalSupportedFormats": "Поддерживаемые форматы: {0}", + "FrmSettings._Clipboard": "Буфер обмена", + "_._UserAction._Win32ExeError": "Невозможно выполнить команду \"{0}\". Убедитесь, что имя правильное.", + "FrmCropSettings.DefaultSelectionType._SelectX": "{0}", + "_.AfterEditAppAction._Close": "Закрыть ImageGlass", + "FrmAbout._LogoDesigner": "Дизайн логотипа:", + "_.ImageOrderBy._Name": "Имя (по умолчанию)", + "FrmMain.MnuRemoveDefaultPhotoViewer._Error": "Не удалось удалить ImageGlass как средство просмотра фотографий по умолчанию.", + "FrmExportFrames._FolderPickerTitle": "Выберите выходную папку для экспорта страниц изображения", + "FrmAbout._Donate": "Пожертвовать", + "FrmMain.MnuFrameNav": "Навигатор кадров", + "FrmMain.MnuSetLockScreen": "Сделать фоновым изображением экрана блокировки", + "_._Delete": "Удалить", + "FrmMain.MnuViewPrevious": "Предыдущее изображение", + "_.Position._Top": "Вверху", + "FrmSettings.Toolbar._CurrentButtons": "Текущие кнопки:", + "FrmMain.MnuAbout": "О программе", + "FrmSettings._RemoveDefault": "Вернуть настройки", + "_._Description": "Описание", + "FrmMain.MnuPasteImage._Error": "Не удалось найти данные изображения в буфере обмена", + "FrmMain.MnuSettings": "Настройки", + "FrmCropSettings._Title": "Параметры инструмента \"Обрезка\"", + "FrmSettings.Toolbar._ToolbarIconHeight": "Размер иконок панели инструментов", + "FrmSettings._SlideshowInterval._To": "По", + "FrmSettings.Layout._ToolbarPosition": "Положение панели инструментов", + "FrmUpdate._StatusUpdated": "Вы используете последнюю версию!", + "FrmMain.MnuExit": "Выход", + "_._Webview2._Outdated": "Ваша версия WebView2 Runtime не поддерживается. Пожалуйста, обновитесь до версии {0} или выше.", + "_._Yes": "Да", + "FrmMain.MnuRotateLeft": "Повернуть против часовой стрелки", + "FrmSettings._EnableStartupBoost": "Включить \"Быстрый запуск\"", + "_.ImageOrderBy._ExifRating": "EXIF: Оценка", + "FrmMain.MnuZoomIn": "Увеличить", + "_.Metadata._ColorSpace": "Цветовой профиль", + "FrmAbout._Version": "Версия:", + "FrmMain.MnuToggleTopMost._Enable": "Режим «Поверх всех окон» включен", + "FrmSettings.Toolbar._AvailableButtons": "Доступные кнопки:", + "FrmMain.MnuSave._Saving": "Сохранение изображения …", + "FrmQuickSetup._StandardUser": "Обычный пользователь", + "FrmMain.MnuSetLockScreen._Error": "Не удалось установить изображение в качестве фона экрана блокировки", + "FrmSettings.Nav._Image": "Изображение", + "FrmSettings._Theme._InstallTheme": "Установка пакетов тем", + "FrmSettings._EnableMultiInstances": "Разрешить несколько экземпляров программы", + "FrmMain.MnuCropTool": "Обрезка", + "_._IgCommandExe._DefaultError._Heading": "Недопустимая команда", + "_._Refresh": "Обновить список", + "FrmMain.MnuLosslessCompression._Description": "Этот инструмент использует библиотеку Magick.NET для сжатия без потерь, оптимизируя размер файла. Перезаписывает, только если сжатый файл меньше исходника.", + "_._MoveDown": "Переместить ниже", + "FrmSettings._GetExtensionIconPacks": "→ Скачать другие пакеты иконок расширений …", + "FrmSettings._InAppMessageDuration": "Время отображения сообщений в приложении (в миллисекундах)", + "FrmMain.MnuFrameless": "Без заголовка и рамки окна", + "_._Reset": "Сброс", + "FrmSettings._ConfigDir": "Папка с конфигурационными файлами", + "FrmQuickSetup._SettingsWillBeApplied": "Эти настройки будут применены:", + "FrmSettings._UnmanagedSettingReminder": "ImageGlass не управляет этим параметром. Не забудьте отключить эту функцию перед удалением или перемещением приложения, поскольку ImageGlass не делает это автоматически.", + "FrmMain.MnuClipboard": "Буфер обмена", + "FrmMain.MnuCustomZoom": "Пользовательский масштаб …", + "FrmSettings._DisplayLanguage": "Выберите язык", + "FrmMain.MnuPrint._Error": "Не удалось распечатать изображение", + "FrmSettings._ShouldPreserveModifiedDate": "Перезаписывать дату изменения изображения при сохранении", + "FrmSettings._ShowSaveOverrideConfirmation": "Запрашивать подтверждение на изменение файла", + "FrmColorPickerSettings.ChkShowHexA": "Использовать \"HEX\" формат с α-каналом", + "FrmMain.MnuFullScreen": "Во весь экран", + "FrmSettings._StartupDir": "Папка запуска", + "FrmSettings._ShowCheckerboardOnlyImageRegion": "Отображать фон прозрачности (α-канал) только в границах изображения", + "FrmMain.MnuClearClipboard._Success": "Буфер обмена очищен", + "FrmQuickSetup._Text": "Конфигуратор первичных настроек", + "FrmMain.MnuLosslessCompression._Done": "Выполнено сжатие без потерь.\r\nНовый размер файла {0}, сохранено {1}.", + "FrmMain.MnuLosslessCompression": "Сжатие без потерь Magick.NET", + "FrmResize.RadResizeByPercentage": "Процент", + "FrmSettings._StartupBoost._Disabled": "\"Быстрый запуск\" отключен", + "FrmMain.MnuToggleCheckerboard": "Сетка прозрачности", + "FrmSettings._MinEmbeddedThumbnailSize._Height": "Высота", + "FrmSettings.Nav._General": "Общее", + "FrmSettings._ImageLoading": "Параметры загрузки изображений", + "FrmSettings._ShowSlideshowCountdown": "Показывать обратный отсчёт времени в режиме показа презентации", + "FrmMain.MnuSave": "Сохранить", + "FrmMain.MnuMoveToRecycleBin": "Удалить в корзину", + "FrmMain.MnuRefresh": "Обновить", + "FrmToolNotFound.LblHeading": "\"{0}\" не найден!", + "FrmMain.MnuReportIssue": "→ Сообщить о проблеме …", + "FrmMain.MnuCopyImageData": "Копировать данные изображения", + "FrmMain.MnuCheckForUpdate._NewVersion": "Доступна новая версия!", + "_._Empty": "(пусто)", + "FrmSettings._Zooming": "Масштабирование", + "FrmMain.MnuCutFile": "Вырезать файл", + "FrmHotkeyPicker.LblHotkey": "Нажмите горячие клавиши", + "FrmSettings.Layout._Gallery": "Панель эскизов", + "FrmMain.MnuNewWindow": "Открыть новое окно", + "FrmMain.MnuMoveToRecycleBin._Description": "Вы хотите удалить этот файл в корзину?", + "FrmSettings._DefaultPhotoViewer": "Средство просмотра фотографий по умолчанию", + "_.Metadata._ExifDateTimeOriginal": "EXIF: DateTimeOriginal", + "FrmMain.MnuRotateRight": "Повернуть по часовой стрелке", + "FrmSettings._MinEmbeddedThumbnailSize": "Минимальный размер встроенного эскиза для загрузки", + "FrmMain.MnuSetDefaultPhotoViewer": "Использовать по умолчанию", + "FrmMain.MnuImageProperties": "Свойства файла", + "FrmSettings._EnableNavigationButtons": "Отображать вторые кнопки навигации влево / вправо", + "_._Edit": "Изменить", + "FrmSettings._ImageBooster": "Ускоритель изображений", + "FrmSettings.Tools._IntegratedWith": "Встроенный в {0}", + "_._Next": "Далее", + "FrmExportFrames._OpenOutputFolder": "Открыть выходную папку", + "FrmMain.MnuOpenLocation": "Открыть место хранения файла", + "FrmMain.MnuLockZoom": "Зафиксировать масштаб", + "FrmSettings._StartupBoost._Description": "Предварительно загружает и запускает ImageGlass при загрузке Windows для более быстрого первого запуска.", + "FrmSettings._WindowBackdrop": "Фон окна", + "FrmSettings._EnableRealTimeFileUpdate": "Отслеживать изменения файлов в папке просмотра и обновлять их в режиме реального времени", + "_._NotSupported": "Неподдерживаемый формат", + "FrmSettings._Theme._GetMoreThemes": "→ Скачать ещё темы …", + "FrmMain.MnuNewWindow._Error": "Невозможно открыть новое окно, так как разрешён только один экземпляр программы", + "FrmMain.MnuZoomOut": "Уменьшить", + "FrmSettings.Toolbar._EditButton": "Редактирование кнопки", + "FrmMain.MnuCustomZoom._Description": "Введите новое значение масштаба", + "FrmResize.RadResizeByPixels": "Пиксели", + "FrmMain.MnuEdit": "Редактировать изображение ...", + "FrmSettings.Layout._GalleryPosition": "Положение панели эскизов", + "FrmMain.MnuWindowFit": "По размеру окна", + "FrmMain._OpenFileDialog": "Все поддерживаемые форматы", + "FrmSettings._UseRandomIntervalForSlideshow": "Использовать случайный интервал", + "_.Position._Left": "Слева", + "FrmSettings._ShouldOpenLastSeenImage": "Показывать последний открытый файл", + "_.Position._Bottom": "Внизу", + "FrmResize.ChkKeepRatio": "Сохранять пропорции", + "FrmMain.MnuGoTo": "Перейти к ...", + "FrmSlideshow.MnuPauseResumeSlideshow": "Приостановить / возобновить презентацию", + "FrmSettings.Tools._Integrated": "Встроенный", + "FrmSettings._Contributors": "Соавторы", + "_.MouseWheelAction._Zoom": "Масштабирование", + "_._CommandPreview": "Предпросмотр", + "FrmSettings._DarkTheme": "Темно", + "_._Hotkeys": "Горячие клавиши", + "_.Metadata._ExifDateTime": "EXIF: DateTime", + "FrmSettings.Toolbar._Errors._ButtonIdRequired": "Требуется идентификатор кнопки.", + "FrmSettings._MinEmbeddedThumbnailSize._Width": "Ширина", + "_._Executable": "Исполняемый файл", + "_.ImageInterpolation._MultiSampleLinear": "Мультилинеарный", + "_._Separator": "Разделитель", + "FrmQuickSetup._ProfessionalUser": "Опытный пользователь", + "FrmMain.MnuFlipVertical": "Перевернуть по вертикали", + "FrmSlideshow._ResumeSlideshow": "Показ возобновлён.", + "FrmCropSettings.DefaultSelectionType._CustomArea": "Свой вариант", + "FrmMain.MnuActualSize": "Масштаб 100%", + "FrmCrop.BtnSaveAs": "Сохранить …", + "FrmSettings._InstallNewLanguagePack": "Установить языковой пакет (*.iglang) …", + "FrmSlideshow.MnuZoomModes": "Режимы масштабирования", + "FrmMain.MnuTools": "Инструменты", + "_.ImageInterpolation._Cubic": "Бикубический метод", + "FrmUpdate._LatestVersion": "Последняя версия: {0}", + "FrmMain.MnuViewNext": "Следующее изображение", + "_.MouseWheelEvent._AltAndScroll": "\"Alt\" + колесо мыши", + "FrmToolNotFound._Title": "Инструмент не найден", + "FrmCrop.BtnCrop._Tooltip": "Обрезать изображение", + "FrmSettings.EditAppDialog._AddApp": "Добавление приложения", + "FrmMain.MnuPanning": "Перемещение", + "_._MoveUp": "Переместить выше", + "FrmCropSettings.DefaultSelectionType._SelectAll": "Всё", + "_._Name": "Название", + "FrmColorPickerSettings.ChkShowHslA": "Использовать \"HSL\" формат с α-каналом", + "FrmMain.MnuToggleImageAnimation": "Начать / остановить анимацию изображения", + "FrmSettings._DisableStartupBoost": "Отключить \"Быстрый запуск\"", + "FrmMain.MnuCopyFile._Success": "Файлов скопировано {0} в буфер обмена.", + "FrmMain.MnuSave._ConfirmDescription": "ImageGlass не является профессиональным фоторедактором, пожалуйста, помните о возможной потере качества, метаданных, слоёв ... при сохранении изображения.", + "FrmToolNotFound.BtnSelectExecutable": "Выбрать …", + "FrmUpdate._StatusOutdated": "Доступна новая версия!", + "_.ImageOrderBy._Random": "Случайный", + "FrmResize.LblCurrentSize": "Текущий размер:", + "_._Apply": "Применить", + "FrmAbout._Slogan": "Лёгкое универсальное средство просмотра изображений", + "FrmMain.MnuPanToTop": "К верхнему краю", + "FrmSettings.Toolbar._AddNewButton": "Добавить свою кнопку на панель инструментов", + "FrmCrop.LblSize": "Размер:", + "FrmSettings._ImageInterpolation._ScaleDown": "Когда масштаб < 100%", + "_._CreatingFileError": "Не удалось создать временный файл изображения", + "FrmMain.MnuGoTo._Description": "Введите индекс изображения для просмотра,\nзатем нажмите \"Enter\"", + "FrmSettings.Toolbar._EnableCenterToolbar": "Центрировать панель инструментов относительно окна", + "FrmMain.MnuResizeTool": "Изменить размер изображения", + "FrmSettings.Layout._Toolbar": "Панель инструментов", + "FrmMain.MnuHelp": "Помощь", + "_.ImageOrderBy._FileSize": "Размер", + "FrmSettings._Theme._OpenThemeFolder": "Открыть папку с темами", + "FrmMain.MnuNavigation": "Навигация", + "_._Save": "Сохранить", + "FrmQuickSetup._SettingProfileDescription": "Чтобы изменить эти параметры, просто зайдите в настройки приложения.", + "_._UserAction._MenuNotFound": "Не удается найти меню \"{0}\" для вызова действия", + "FrmMain.MnuPanToLeftSide": "К левому краю", + "FrmUpdate._CurrentVersion": "Текущая версия: {0}", + "FrmCrop.BtnSettings._Tooltip": "Открыть настройки обрезки", + "_.ColorProfileOption._Custom": "Настроить ...", + "FrmSettings._UseEmbeddedThumbnailOtherFormats": "Загружать только встроенный эскиз для остальных форматов", + "FrmMain.MnuGoToFirst": "К первому изображению", + "FrmSettings._ExportLanguagePack": "Экспортировать языковой пакет …", + "FrmSettings.Nav._Mouse": "Мышь", + "_.ImageOrderBy._DateCreated": "Дата создания", + "FrmSettings._EnableFullscreenSlideshow": "Запускать презентацию в полноэкранном режиме", + "FrmAbout._Homepage": "Сайт:", + "FrmSettings._GalleryCacheSizeInMb": "Максимальный размер буфера для панели эскизов (в мегабайтах)", + "FrmMain.MnuCopyImageData._Success": "Текущие данные изображения скопированы", + "FrmSettings._EnableLoopBackNavigation": "Повторять просмотр с первого файла при достижении конца", + "_.MouseWheelEvent._Scroll": "Колесо мыши", + "FrmCrop.BtnSave._Tooltip": "Сохранить изображение", + "FrmMain.MnuSlideshow": "Презентация", + "FrmMain.MnuShare": "Поделиться ...", + "FrmSettings._SlideshowNotification": "Сигнал по истечении периода", + "FrmMain.MnuViewChannels": "Просмотр каналов", + "FrmSettings._Refresh": "Обновить список", + "_._UserAction._MethodNotFound": "Не удается найти метод \"{0}\", чтобы вызвать действие", + "FrmMain.MnuCopyFile": "Копировать файл", + "_._CreatingFile": "Создание временного файла изображения …", + "FrmMain.MnuToggleTopMost": "Поверх окон", + "FrmMain.MnuLosslessCompression._Confirm": "Вы уверены, что хотите продолжить?", + "FrmMain.MnuImage": "Изображение", + "FrmSettings._StartupBoost._Enabled": "\"Быстрый запуск\" включен", + "FrmQuickSetup._SetDefaultViewer": "Установить ImageGlass как средство просмотра по умолчанию?", + "FrmMain.MnuScaleToWidth": "Масштаб по ширине", + "_._FileExtension": "Расширение файла", + "FrmUpdate._PublishedDate": "Дата публикации: {0}", + "_._DoNotShowThisMessageAgain": "Больше не показывать это сообщение", + "_.ImageInterpolation._NearestNeighbor": "Метод ближайшего соседа", + "FrmCrop.LblLocation": "Координаты:", + "_._Download": "Скачать", + "_.Metadata._ColorProfile": "Цветовой профиль", + "FrmSettings._CenterWindowFit": "Автоматически центрировать окно в режиме «По размеру окна»", + "FrmSettings._ImageLoadingOrder": "Порядок чтения файлов", + "FrmSettings._GalleryColumns": "Количество колонок в вертикальном виде панели эскизов", + "_._Quit": "Выйти", + "_._Add": "Добавить", + "FrmMain.MnuChangeBackgroundColor": "Изменить цвет фона …", + "FrmMain.MnuToggleToolbar": "Панель инструментов", + "FrmAbout._Contact": "Обратная связь", + "FrmSettings.Toolbar._AddCustomButton": "Добавить свою кнопку …", + "FrmCrop.BtnQuickSelect._Tooltip": "Быстрый выбор …", + "FrmMain.MnuCutFile._Success": "Файлов вырезано {0} в буфер обмена.", + "FrmSettings._ZoomSpeed": "Скорость масштабирования", + "FrmMain.MnuToggleTopMost._Disable": "Режим «Поверх всех окон» выключен", + "FrmSettings._ShouldUseExplorerSortOrder": "По возможности использовать порядок сортировки такой же, как и в проводнике", + "_.ImageInterpolation._Antisotropic": "Анизотропия", + "FrmMain._ReachedFirstImage": "Перейти к первому изображению", + "_._UnhandledException": "Ошибка.", + "FrmResize.LblNewSize": "Новый размер:", + "FrmMain._ClipboardImage": "Открыть изображение из буфера обмена", + "FrmMain.MnuExportFrames": "Экспорт страниц изображения …", + "FrmMain.MnuFile": "Файл", + "_._Close": "Закрыть", + "FrmMain.MnuMain": "Главное меню", + "_._ResetToDefault": "Вернуть настройки", + "FrmSettings.Nav._Gallery": "Панель эскизов", + "FrmMain.MnuSetDefaultPhotoViewer._Success": "Вы успешно установили ImageGlass как средство просмотра фотографий по умолчанию.", + "FrmSettings._HideGalleryInFullscreen": "Скрывать панель эскизов в полноэкранном режиме", + "FrmSettings._AvailableImageInfoTags": "Доступные теги:", + "FrmExportFrames._Exporting": "Экспортировано кадров {0} из {1} \n{2} …", + "_._Argument": "Аргумент", + "FrmSettings._ImageEditQuality": "Качество изображения", + "_._ID": "Идентификатор", + "FrmSettings._UserConfigFile": "Файл настроек пользователя (igconfig.json)", + "FrmMain.MnuLoadingOrders": "Порядок просмотра", + "FrmSettings._OpenSaveAsDialogInTheCurrentImageDir": "Открывает диалоговое окно «Сохранить как» в текущем каталоге изображений", + "_.MouseWheelEvent._ShiftAndScroll": "\"Shift\" + колесо мыши", + "FrmSettings._UseSmoothZooming": "Использовать плавное масштабирование", + "FrmSettings._Theme": "Тема", + "FrmSettings._ImageBoosterCacheMaxDimension": "Максимальное разрешение изображения для запоминания (в пикселях)", + "FrmMain.MnuScaleToHeight": "Масштаб по высоте", + "_.Metadata._FileLastWriteTime": "Дата изменения", + "FrmSettings._Author": "Автор", + "FrmSettings._Others": "Другие настройки", + "_.MouseWheelAction._PanVertically": "Вертикальная прокрутка", + "FrmSettings._MouseWheelAction": "Действия при прокрутке колеса мыши", + "FrmSettings.Nav._Tools": "Инструменты", + "FrmMain.MnuSetDesktopBackground._Error": "Не удалось установить изображение в качестве фона рабочего стола", + "FrmSettings.Toolbar._Errors._ButtonExecutableRequired": "Требуется исполняемый файл для кнопки.", + "_.ImageOrderBy._DateAccessed": "Дата доступа", + "FrmSettings._ThumbnailSize": "Размер эскиза (в пикселях)", + "FrmSettings._FileFormats": "Форматы файлов", + "FrmMain.MnuReloadImageList": "Перезагрузить список изображений", + "FrmSettings._UseWebview2ForSvg": "Использовать WebView2 для просмотра \"SVG\" формата", + "FrmCrop.BtnCopy": "Копировать", + "FrmSettings._CurrentMonitorProfile._Description": "ImageGlass автоматически не обновляет цвета при перемещении окна между мониторами", + "FrmMain.PicMain._ErrorText": "Не удалось открыть изображение", + "FrmSettings.Tools._AddNewTool": "Добавить инструмент", + "FrmMain.MnuRename": "Переименовать изображение …", + "FrmMain.MnuViewLastFrame": "К последней странице", + "_._Webview2._NotFound": "Чтобы получить доступ к полным возможностям ImageGlass, установите WebView2 Runtime.", + "FrmMain.MnuGetMoreTools": "→ Больше инструментов …", + "FrmSettings.Nav._Appearance": "Оформление", + "FrmSettings._SlideshowInterval": "Временной интервал показа изображений:", + "_.ImageInterpolation._HighQualityBicubic": "Высококачественный бикубический метод", + "FrmColorPickerSettings.ChkShowHsvA": "Использовать \"HSV\" формат с α-каналом", + "FrmSettings.Tools._EditTool": "Редактировать внешний инструмент", + "_._Error": "Ошибка.", + "FrmSettings._ImageBoosterCacheMaxFileSizeInMb": "Максимальный размер изображения для запоминания (в мегабайтах)", + "_._UnhandledException._Description": "Ошибка. Если вы нажмёте \"Далее\", приложение будет игнорировать эту ошибку и попытается продолжить работу. Если вы нажмете \"Выйти\", приложение немедленно закроется.", + "_.Metadata._FileSize": "Размер", + "FrmSettings.Toolbar._ButtonJson": "\"JSON\" кнопка", + "FrmQuickSetup._SetDefaultViewer._Description": "Вы сможете сбросить это в настройках приложения в разделе \"Ассоциации файлов\".", + "FrmSettings.Nav._Edit": "Редактирование", + "FrmMain.MnuToggleGallery": "Панель эскизов", + "_._IgCommandExe._DefaultError._Description": "Убедитесь, что вы передаете допустимые команды!\r\nЭтот исполняемый файл содержит функции командной строки для программного обеспечения ImageGlass.\r\n\r\nЧтобы изучить все функции командной строки,\nпожалуйста, посетите: {0}", + "FrmMain.MnuLosslessCompression._Compressing": "Выполнение сжатия без потерь…", + "FrmSettings._ShouldGroupImagesByDirectory": "Группировать изображения по папкам", + "FrmMain.MnuPanToRightSide": "К правому краю", + "_.Metadata._ExifRatingPercent": "Оценка", + "FrmSettings._PanSpeed": "Скорость прокрутки", + "_._CheckForUpdate": "Проверить обновления ...", + "FrmSettings.Layout._ToolbarContext": "Контекстная панель инструментов", + "_.ImageInfo._FrameCount": "{0} стр.", + "FrmMain.MnuLayout": "Внешний вид", + "_._Website": "Сайт", + "FrmMain.MnuPasteImage": "Вставить изображение", + "FrmSettings._ShowGalleryScrollbars": "Показывать полосу прокрутки панели эскизов" + } +} \ No newline at end of file diff --git a/Setup/Assets/Language/Serbian (Cyrillic).iglang.json b/Setup/Assets/Language/Serbian (Cyrillic).iglang.json new file mode 100644 index 000000000..c8ad781c8 --- /dev/null +++ b/Setup/Assets/Language/Serbian (Cyrillic).iglang.json @@ -0,0 +1,504 @@ +{ + "_Metadata": { + "Code": "sr-RS", + "EnglishName": "Serbian (Cyrillic)", + "LocalName": "Српски", + "Author": "Ђорђе Васиљевић", + "MinVersion": "9.3" + }, + "Items": { + "FrmCrop.SelectionAspectRatio._Original": "Оригинална", + "FrmMain.MnuShare._Error": "Није могуће отворити дијалог за дељење.", + "_.Metadata._FileLastAccessTime": "Датум приступа", + "FrmAbout._License": "Лиценца", + "FrmSettings.Toolbar._Errors._ButtonIdDuplicated": "Дугме са ID-јем „{0}” већ постоји. Изаберите јединствени ID да бисте избегли конфликте.", + "FrmMain.MnuSave._Confirm": "Желите ли заиста да замените ову слику?", + "FrmSettings._OpenDefaultAppsSetting": "Отвори подешавања подразумеваних апликација", + "FrmMain.MnuCopyPath": "Копирај путању до слике", + "FrmCropSettings.DefaultSelectionType._SelectNone": "Поништи избор свега", + "_.MouseWheelAction._PanHorizontally": "Помери улево/удесно", + "FrmMain.MnuPrint": "Одштампај…", + "FrmSettings.Toolbar._ToolbarButtons": "Дугмад на траци са алаткама", + "FrmResize.LblResample": "Узорковање:", + "_.ImageOrderBy._Extension": "Екстензија", + "FrmSettings.Nav._Viewer": "Приказивач", + "FrmSettings.EditAppDialog._EditApp": "Уређивање програма", + "FrmCrop.BtnReset._Tooltip": "Ресетуј избор", + "FrmMain.MnuRename._Description": "Унесите нови назив фајла:", + "_._No": "Не", + "FrmSlideshow.MnuToggleCountdown": "Одбројавање", + "FrmSettings._OpenStartupAppsSetting": "Отвори подешавања покретања апликација", + "FrmMain.MnuViewPreviousFrame": "Претходни кадар", + "_.ImageOrderBy._DateModified": "Датум измене", + "FrmMain.MnuViewNextFrame": "Следећи кадар", + "FrmMain.MnuUnload": "Затвори слику", + "FrmSettings.Toolbar._HideToolbarInFullscreen": "Сакриј траку у режиму целог екрана", + "_.ImageOrderType._Desc": "Опадајуће", + "_._Update": "Ажурирај", + "FrmSettings._EnableImageAsyncLoading": "Асинхроно учитавање слика", + "FrmSettings._DefaultPhotoViewer._Description": "Региструјте формате које ImageGlass подржава са Windows-ом. Можда ћете морати да отворите подешавања подразумеваних апликација и ручно изаберете ImageGlass са листе како би измене ступиле на снагу.", + "_.MouseWheelAction._BrowseImages": "Прикажи следећу/претходну слику", + "FrmSettings._EditApps": "Програми за уређивање слика", + "FrmColorPickerSettings.ChkShowCIELabA": "CIELAB формат са алфа каналом", + "_._GetHelp": "Помоћ", + "FrmQuickSetup._SkipQuickSetup": "Прескочи и покрени ImageGlass", + "FrmColorPickerSettings._Title": "Подешавања бирача боја", + "_._Copy": "Копирај", + "FrmSettings._ImageBoosterCacheCount": "Број кешираних слика (у једном смеру)", + "FrmMain.MnuPanToBottom": "Помери слику на дно", + "FrmMain.MnuZoom": "Зумирање", + "FrmCropSettings.ChkCloseToolAfterSaving": "Затвори након чувања", + "FrmSettings._ShowWelcomeImage": "Прикажи слику добродошлице", + "FrmSettings._ColorProfile": "Профил боја", + "FrmSettings._Theme._UninstallTheme": "Деинсталирање теме", + "FrmMain._OpenWith": "Отвори помоћу {0}", + "FrmMain.MnuRemoveDefaultPhotoViewer": "Уклони подразумевани приказивач слика", + "_.AfterEditAppAction._Nothing": "Не ради ништа", + "FrmCrop.BtnSave": "Сачувај", + "FrmMain.MnuScaleToFit": "Размера према прозору", + "FrmToolNotFound.LblDownloadToolText": "Више алатки за ImageGlass можете да преузмете на:", + "_._LearnMore": "Сазнајте више…", + "FrmCrop.LblAspectRatio": "Размера:", + "FrmExportFrames._FileNotExist": "Фајл слике не постоји", + "FrmSettings._LightTheme": "Светла", + "FrmSettings.Nav._Slideshow": "Пројекција слајдова", + "_._Continue": "Настави", + "_._AddHotkey": "Додај пречицу…", + "FrmMain.MnuSetDesktopBackground": "Постави као позадину радне површине", + "FrmMain.MnuReload": "Поново учитај слику", + "FrmSlideshow.MnuExitSlideshow": "Изађи из пројекције слајдова", + "FrmMain.MnuAutoZoom": "Аутоматско зумирање", + "FrmSettings._ShowImagePreview": "Прикажи преглед слике док се учитава", + "FrmCrop.BtnCopy._Tooltip": "Копирај избор у привремену меморију", + "FrmSettings.Nav._Toolbar": "Трака са алаткама", + "FrmMain.MnuSave._Error": "Није могуће сачувати слику", + "FrmSettings._AfterEditingAction": "Након отварања у уређивачу", + "FrmSettings._ShouldUseColorProfileForAll": "Примени и на слике без уграђеног профила боја", + "FrmCropSettings.DefaultSelectionType._UseTheLastSelection": "Користи последњи избор", + "FrmSettings._SlideshowInterval._From": "Од", + "FrmSettings._ImageInterpolation": "Интерполација слика", + "FrmQuickSetup._StepInfo": "Корак {0}", + "FrmMain.MnuColorPicker": "Бирач боја", + "FrmCrop.SelectionAspectRatio._FreeRatio": "Слободни режим", + "FrmSettings._ResetSettings": "Ресетуј подешавања", + "FrmSettings._Startup": "Покретање", + "_.BackdropStyle._None": "Нема", + "FrmSettings._LoadDefaultZoomLevels": "Учитај подразумеване факторе зумирања", + "FrmColorPicker.BtnSettings._Tooltip": "Отвори подешавања бирача боја…", + "FrmSettings._UseThemeForDarkMode": "Користи ову тему у тамном режиму", + "FrmSettings._ShowDeleteConfirmation": "Дијалог о потврди при брисању фајла", + "FrmSettings._ShowAppIcon": "Икона апликације у насловној траци", + "_._InvalidAction": "Неважећа радња", + "FrmQuickSetup._SelectProfile": "Изаберите профил", + "_.Metadata._FileCreationTime": "Датум настанка", + "FrmSettings._SlideshowImagesToNotifySound": "Број слика за активирање звука обавештења", + "FrmSettings._BackgroundColor": "Позадинска боја приказивача", + "FrmSettings._RealTimeFileUpdate": "Освежавање фајлова у реалном времену", + "_.ColorProfileOption._CurrentMonitorProfile": "Профил тренутног екрана", + "FrmSettings._EnableCutMultipleFiles": "Исецање више фајлова одједном", + "FrmSettings._AutoUpdate": "Аутоматски тражи ажурирања", + "FrmCropSettings.LblDefaultSelection": "Подразумевани избор", + "FrmSettings._UseThemeForLightMode": "Користи ову тему у светлом режиму", + "FrmSettings._ZoomLevels": "Фактори зумирања", + "FrmMain.MnuSetLockScreen._Success": "Позадина закључаног екрана је промењена", + "FrmSettings._ShowGalleryFileName": "Назив фајла испод сличица", + "FrmSettings.Layout._Order": "Редослед", + "FrmCropSettings.ChkAutoCenterSelection": "Центрирај избор", + "FrmSettings.Nav._FileTypeAssociations": "Формати", + "_._Back": "Назад", + "FrmMain.MnuSetDesktopBackground._Success": "Позадина радне површине је промењена", + "FrmSettings._ShouldAutoOpenNewAddedImage": "Аутоматски отвори управо додату слику", + "FrmCrop.SelectionAspectRatio._Custom": "Прилагођена", + "FrmMain.MnuCopyPath._Success": "Путања до слике је копирана.", + "FrmSettings._StartupBoost._Error": "Није могуће променити оптимизацију покретања", + "FrmToolNotFound.LblDescription": "ImageGlass не може да пронађе извршни фајл алатке {0}. Промените путању до ње испод.", + "FrmMain.MnuClearClipboard": "Обриши привремену меморију", + "FrmSettings._ColorManagement": "Управљање бојама", + "FrmMain._ReachedLastLast": "Дошли сте до последње слике", + "FrmMain.MnuPanUp": "Помери слику нагоре", + "FrmMain.MnuRemoveDefaultPhotoViewer._Success": "ImageGlass више није подразумевани приказивач слика.", + "FrmSettings._GetMoreLanguagePacks": "Преузмите још језичких пакета", + "FrmAbout._Privacy": "Политика приватности", + "FrmSettings._EnableRecursiveLoading": "Учитавај слике у потфолдерима", + "_._UserAction._MethodArgumentNotSupported": "Тип аргумента методе „{0}” није подржан", + "FrmSettings._FileExtensionIcons._Description": "Да бисте прилагодили иконе за екстензије фајлова, преузмите пакет икона, сместите све ICO фајлове у фолдер са иконама и кликните на дугме „{0}”. Овим ћете и подесити ImageGlass као подразумевани приказивач слика.", + "_.ImageOrderType._Asc": "Растуће", + "FrmExportFrames._Title": "Извоз кадрова из слике", + "_._Install": "Инсталирај…", + "FrmMain.MnuFlipHorizontal": "Обрни хоризонтално", + "FrmSettings._OpenExtensionIconFolder": "Отвори фолдер", + "FrmAbout._Collaborator": "Сарадник:", + "FrmQuickSetup._ConfirmCloseProcess": "Потребно је затворити све процесе ImageGlass-а пре примене нових подешавања. Желите ли да наставите?", + "FrmExportFrames._ExportDone": "Извезено је {0} кадрова у \n{1}", + "FrmCrop.BtnSaveAs._Tooltip": "Сачувај као копију…", + "FrmMain.MnuOpenFile": "Отвори фајл…", + "FrmColorPickerSettings.ChkShowRgbA": "RGB формат са алфа каналом", + "_.ImageInfo._ListCount": "Број фајлова: {0}", + "FrmMain.MnuGoToLast": "Последња слика", + "FrmSettings._EditApps._AppName": "Назив програма", + "FrmSettings._SlideshowBackgroundColor": "Позадинска боја пројекције слајдова", + "FrmAbout._Email": "Имејл:", + "_.MouseWheelAction._DoNothing": "Не ради ништа", + "FrmMain.MnuSaveAs": "Сачувај као…", + "FrmMain._Loading": "Учитава се…", + "_._Browse": "Прегледај…", + "FrmMain.MnuSetDefaultPhotoViewer._Error": "Није могуће поставити ImageGlass као подразумевани приказивач слика.", + "FrmSettings.Nav._Language": "Језик", + "FrmQuickSetup._SeeWhatNew": "Евиденција промена", + "FrmSettings._ImageInterpolation._ScaleUp": "Када је зум већи од 100%", + "FrmSettings.Layout._ToolbarContextPosition": "Положај контекстуалне траке", + "FrmMain.MnuDeleteFromHardDisk": "Избриши трајно", + "FrmSettings._EmbeddedThumbnail": "Уграђена сличица", + "FrmMain.MnuDeleteFromHardDisk._Description": "Желите ли да трајно избришете овај фајл?", + "FrmMain.MnuScaleToFill": "Попуни прозор", + "FrmCrop.BtnCrop": "Опсеци", + "_.AfterEditAppAction._Minimize": "Умањи", + "FrmMain.MnuInvertColors": "Обрни боје", + "FrmSettings._StartupBoost": "Оптимизација покретања", + "FrmMain.MnuViewFirstFrame": "Први кадар", + "_.MouseWheelEvent._CtrlAndScroll": "Ctrl + точкић миша", + "FrmSettings._HideMainWindowInSlideshow": "Аутоматски сакриј главни прозор", + "_.Metadata._FrameCount": "Кадрови", + "FrmSettings._EnableCopyMultipleFiles": "Копирање више фајлова одједном", + "FrmMain.MnuFrameless._EnableDescription": "Држите Shift да бисте померали прозор.", + "_.ImageOrderBy._ExifDateTaken": "Датум настанка (EXIF)", + "FrmAbout._Credits": "Заслуге", + "FrmSettings._AddNewFileExtension": "Додавање нове екстензије фајла", + "FrmMain.MnuQuickSetup": "Брзо подешавање ImageGlass-а", + "FrmMain.MnuSave._Success": "Слика је сачувана", + "FrmMain.MnuPanLeft": "Помери слику улево", + "FrmUpdate._StatusChecking": "Тражи се ажурирање…", + "FrmSettings.Nav._Layout": "Распоред", + "FrmMain.MnuOpenWith": "Отвори помоћу…", + "FrmAbout._Thanks": "Посебна захвалност:", + "_._Warning": "Упозорење", + "FrmSettings.Nav._Keyboard": "Тастатура", + "FrmSlideshow._PauseSlideshow": "Пројекција слајдова је паузирана.", + "_._Add+": "Додај…", + "_._Email": "Имејл", + "FrmMain.MnuPanDown": "Помери слику надоле", + "_._Cancel": "Откажи", + "_._OK": "У реду", + "FrmMain.MnuPanRight": "Помери слику удесно", + "_.Position._Right": "Десно", + "_._Icon": "Икона", + "FrmSettings._ShouldLoadHiddenImages": "Учитавај сакривене слике", + "_._InvalidAction._Transformation": "ImageGlass не подржава ротирање ни окретање ове слике.", + "FrmSettings._MakeDefault": "Подеси", + "FrmMain.MnuCopyImageData._Copying": "Слика се копира. Потрајаће неко време…", + "FrmSettings._UseEmbeddedThumbnailRawFormats": "Учитај само уграђену сличицу за RAW формате", + "_.ImageInterpolation._Linear": "Линеарна", + "FrmSettings._ImageInfoTags": "Информације о сликама", + "FrmSettings._FileExtensionIcons": "Иконе за екстензије фајлова", + "FrmMain.MnuEdit._AppNotFound": "Није могуће пронаћи апликацију за уређивање. Можете да доделите апликацију за уређивање овог формата у одељку Подешавања → Уређивање.", + "_.ColorProfileOption._None": "Ниједан", + "FrmSettings._TotalSupportedFormats": "Укупно подржаних формата: {0}", + "FrmSettings._Clipboard": "Привремена меморија", + "_._UserAction._Win32ExeError": "Није могуће извршити команду „{0}”. Проверите да ли је назив исправан.", + "FrmCropSettings.DefaultSelectionType._SelectX": "Изабери {0}", + "_.AfterEditAppAction._Close": "Затвори", + "FrmAbout._LogoDesigner": "Дизајн логотипа:", + "_.ImageOrderBy._Name": "Назив (подразумевано)", + "FrmMain.MnuRemoveDefaultPhotoViewer._Error": "Није могуће уклонити ImageGlass као подразумевани приказивач слика.", + "FrmExportFrames._FolderPickerTitle": "Избор одредишног фолдера за извоз кадрова из слике", + "FrmAbout._Donate": "Донирајте", + "FrmMain.MnuFrameNav": "Навигација по кадровима", + "FrmMain.MnuSetLockScreen": "Постави као позадину закључаног екрана", + "_._Delete": "Избриши", + "FrmMain.MnuViewPrevious": "Претходна слика", + "_.Position._Top": "На врху", + "FrmSettings.Toolbar._CurrentButtons": "Тренутна дугмад:", + "FrmMain.MnuAbout": "О програму", + "FrmSettings._RemoveDefault": "Ресетуј", + "_._Description": "Опис", + "FrmMain.MnuPasteImage._Error": "Није могуће пронаћи слику у привременој меморији", + "FrmMain.MnuSettings": "Подешавања", + "FrmCropSettings._Title": "Подешавања опсецања", + "FrmSettings.Toolbar._ToolbarIconHeight": "Величина икона", + "FrmSettings._SlideshowInterval._To": "До", + "FrmSettings.Layout._ToolbarPosition": "Положај траке са алаткама", + "FrmUpdate._StatusUpdated": "Користите најновију верзију!", + "FrmMain.MnuExit": "Изађи", + "_._Webview2._Outdated": "Ваша верзија WebView2 Runtime-а није подржана. Ажурирајте на верзију {0} или новију.", + "_._Yes": "Да", + "FrmMain.MnuRotateLeft": "Ротирај улево", + "FrmSettings._EnableStartupBoost": "Омогући оптимизацију", + "_.ImageOrderBy._ExifRating": "Оцена (EXIF)", + "FrmMain.MnuZoomIn": "Увећај", + "_.Metadata._ColorSpace": "Опсег боја", + "FrmAbout._Version": "Верзија:", + "FrmMain.MnuToggleTopMost._Enable": "Фиксирање изнад свих прозора је омогућено", + "FrmSettings.Toolbar._AvailableButtons": "Доступна дугмад:", + "FrmMain.MnuSave._Saving": "Чува се слика…", + "FrmQuickSetup._StandardUser": "Просечан корисник", + "FrmMain.MnuSetLockScreen._Error": "Није могуће поставити слику као позадину закључаног екрана", + "FrmSettings.Nav._Image": "Слика", + "FrmSettings._Theme._InstallTheme": "Инсталирање теме", + "FrmSettings._EnableMultiInstances": "Више инстанци програма", + "FrmMain.MnuCropTool": "Опсецање слике", + "_._IgCommandExe._DefaultError._Heading": "Неважеће команде", + "_._Refresh": "Освежи", + "FrmMain.MnuLosslessCompression._Description": "Ова алатка користи библиотеку Magick.NET за компримовање, оптимизујући тиме величину фајлова. Замењује само ако је компримовани фајл мањи од оригинала.", + "_._MoveDown": "Помери надоле", + "FrmSettings._GetExtensionIconPacks": "Преузмите иконе екстензија", + "FrmSettings._InAppMessageDuration": "Трајање поруке у апликацији (у милисекундама)", + "FrmMain.MnuFrameless": "Прозор без оквира", + "_._Reset": "Ресетуј", + "FrmSettings._ConfigDir": "Фолдер са конфигурационим фајловима", + "FrmQuickSetup._SettingsWillBeApplied": "Ова подешавања ће се применити:", + "FrmSettings._UnmanagedSettingReminder": "ImageGlass не управља овим подешавањем. Не заборавите да га онемогућите пре него што уклоните или преместите апликацију, јер ImageGlass то не ради аутоматски.", + "FrmMain.MnuClipboard": "Привремена меморија", + "FrmMain.MnuCustomZoom": "Прилагођено зумирање…", + "FrmSettings._DisplayLanguage": "Језик интерфејса", + "FrmMain.MnuPrint._Error": "Није могуће одштампати слику", + "FrmSettings._ShouldPreserveModifiedDate": "Не мењај датум измене при чувању слике", + "FrmSettings._ShowSaveOverrideConfirmation": "Дијалог о потврди при замењивању фајла", + "FrmColorPickerSettings.ChkShowHexA": "HEX формат са алфа каналом", + "FrmMain.MnuFullScreen": "Преко целог екрана", + "FrmSettings._StartupDir": "Фолдер са извршним фајлом", + "FrmSettings._ShowCheckerboardOnlyImageRegion": "Позадина прозирности само у границама слике", + "FrmMain.MnuClearClipboard._Success": "Привремена меморија је обрисана.", + "FrmQuickSetup._Text": "Брзо подешавање ImageGlass-а", + "FrmMain.MnuLosslessCompression._Done": "Компримовање без губитака је завршено.\r\nНова величина фајла – {0}, сачувано – {1}.", + "FrmMain.MnuLosslessCompression": "Magick.NET компресија без губитака", + "FrmResize.RadResizeByPercentage": "Проценат", + "FrmSettings._StartupBoost._Disabled": "Оптимизација покретања је онемогућена", + "FrmMain.MnuToggleCheckerboard": "Позадина прозирности", + "FrmSettings._MinEmbeddedThumbnailSize._Height": "Висина", + "FrmSettings.Nav._General": "Опште", + "FrmSettings._ImageLoading": "Учитавање слика", + "FrmSettings._ShowSlideshowCountdown": "Одбројавање", + "FrmMain.MnuSave": "Сачувај", + "FrmMain.MnuMoveToRecycleBin": "Премести у канту за отпатке", + "FrmMain.MnuRefresh": "Освежи", + "FrmToolNotFound.LblHeading": "Алатка {0} није пронађена", + "FrmMain.MnuReportIssue": "Пријавите проблем", + "FrmMain.MnuCopyImageData": "Копирај слику", + "FrmMain.MnuCheckForUpdate._NewVersion": "Доступна је нова верзија!", + "_._Empty": "(празно)", + "FrmSettings._Zooming": "Зумирање", + "FrmMain.MnuCutFile": "Исеци фајл", + "FrmHotkeyPicker.LblHotkey": "Притисните комбинацију тастера", + "FrmSettings.Layout._Gallery": "Галерија", + "FrmMain.MnuNewWindow": "Отвори нови прозор", + "FrmMain.MnuMoveToRecycleBin._Description": "Желите ли да преместите овај фајл у канту за отпатке?", + "FrmSettings._DefaultPhotoViewer": "Подразумевани приказивач слика", + "_.Metadata._ExifDateTimeOriginal": "EXIF: DateTimeOriginal", + "FrmMain.MnuRotateRight": "Ротирај удесно", + "FrmSettings._MinEmbeddedThumbnailSize": "Минимална величина уграђене сличице за учитавање", + "FrmMain.MnuSetDefaultPhotoViewer": "Подешавање подразумеваног приказивача слика", + "FrmMain.MnuImageProperties": "Својства слике", + "FrmSettings._EnableNavigationButtons": "Стрелице за навигацију", + "_._Edit": "Уреди", + "FrmSettings._ImageBooster": "Кеширање слика", + "FrmSettings.Tools._IntegratedWith": "Интегрисано помоћу {0}-а", + "_._Next": "Следеће", + "FrmExportFrames._OpenOutputFolder": "Отвори фолдер", + "FrmMain.MnuOpenLocation": "Отвори локацију слике", + "FrmMain.MnuLockZoom": "Закључај фактор зумирања", + "FrmSettings._StartupBoost._Description": "Унапред учитава и покреће ImageGlass са системом како би убрзао прво покретање.", + "FrmSettings._WindowBackdrop": "Позадина прозора", + "FrmSettings._EnableRealTimeFileUpdate": "Надгледај промене фајлова у тренутном фолдеру и примени их", + "_._NotSupported": "Неподржани формат", + "FrmSettings._Theme._GetMoreThemes": "Преузмите још тема", + "FrmMain.MnuNewWindow._Error": "Није могуће отворити нови прозор јер је дозвољена само једна инстанца програма", + "FrmMain.MnuZoomOut": "Умањи", + "FrmSettings.Toolbar._EditButton": "Уређивање дугмета на траци са алаткама", + "FrmMain.MnuCustomZoom._Description": "Унесите фактор зумирања", + "FrmResize.RadResizeByPixels": "Пиксели", + "FrmMain.MnuEdit": "Уреди слику {0}…", + "FrmSettings.Layout._GalleryPosition": "Положај галерије", + "FrmMain.MnuWindowFit": "Прилагоди прозор слици", + "FrmMain._OpenFileDialog": "Сви подржани фајлови", + "FrmSettings._UseRandomIntervalForSlideshow": "Насумични интервал", + "_.Position._Left": "Лево", + "FrmSettings._ShouldOpenLastSeenImage": "Отвори последње приказану слику", + "_.Position._Bottom": "На дну", + "FrmResize.ChkKeepRatio": "Задржи пропорције", + "FrmMain.MnuGoTo": "Иди на…", + "FrmSlideshow.MnuPauseResumeSlideshow": "Паузирај/настави пројекцију слајдова", + "FrmSettings.Tools._Integrated": "Интегрисано", + "FrmSettings._Contributors": "Сарадници", + "_.MouseWheelAction._Zoom": "Увећај/умањи", + "_._CommandPreview": "Преглед команде", + "FrmSettings._DarkTheme": "Тамна", + "_._Hotkeys": "Пречице", + "_.Metadata._ExifDateTime": "EXIF: DateTime", + "FrmSettings.Toolbar._Errors._ButtonIdRequired": "ID дугмета је обавезан.", + "FrmSettings._MinEmbeddedThumbnailSize._Width": "Ширина", + "_._Executable": "Извршни фајл", + "_.ImageInterpolation._MultiSampleLinear": "Линеарна са више узорака", + "_._Separator": "Сепаратор", + "FrmQuickSetup._ProfessionalUser": "Искусан корисник", + "FrmMain.MnuFlipVertical": "Обрни вертикално", + "FrmSlideshow._ResumeSlideshow": "Пројекција слајдова је настављена.", + "FrmCropSettings.DefaultSelectionType._CustomArea": "Прилагођено", + "FrmMain.MnuActualSize": "Оригинална величина", + "FrmCrop.BtnSaveAs": "Сачувај као…", + "FrmSettings._InstallNewLanguagePack": "Инсталирај нови језички пакет…", + "FrmSlideshow.MnuZoomModes": "Режими зумирања", + "FrmMain.MnuTools": "Алатке", + "_.ImageInterpolation._Cubic": "Кубна", + "FrmUpdate._LatestVersion": "Најновија верзија: {0}", + "FrmMain.MnuViewNext": "Следећа слика", + "_.MouseWheelEvent._AltAndScroll": "Alt + тошкић миша", + "FrmToolNotFound._Title": "Алатка није пронађена", + "FrmCrop.BtnCrop._Tooltip": "Опсеци слику", + "FrmSettings.EditAppDialog._AddApp": "Додавање програма за уређивање", + "FrmMain.MnuPanning": "Померање", + "_._MoveUp": "Помери нагоре", + "FrmCropSettings.DefaultSelectionType._SelectAll": "Изабери све", + "_._Name": "Назив", + "FrmColorPickerSettings.ChkShowHslA": "HSL формат са алфа каналом", + "FrmMain.MnuToggleImageAnimation": "Покрени/заустави анимацију", + "FrmSettings._DisableStartupBoost": "Онемогући оптимизацију", + "FrmMain.MnuCopyFile._Success": "Копираних фајлова: {0}", + "FrmMain.MnuSave._ConfirmDescription": "ImageGlass није професионални уређивач слика. Могућ је губитак квалитета, метаподатака или слојева при њиховом чувању.", + "FrmToolNotFound.BtnSelectExecutable": "Изабери…", + "FrmUpdate._StatusOutdated": "Доступна је нова верзија!", + "_.ImageOrderBy._Random": "Насумично", + "FrmResize.LblCurrentSize": "Тренутна величина:", + "_._Apply": "Примени", + "FrmAbout._Slogan": "Једноставан и универзалан приказивач слика", + "FrmMain.MnuPanToTop": "Помери слику на врх", + "FrmSettings.Toolbar._AddNewButton": "Додавање дугмета на траку са алаткама", + "FrmCrop.LblSize": "Величина:", + "FrmSettings._ImageInterpolation._ScaleDown": "Када је зум мањи од 100%", + "_._CreatingFileError": "Није могуће направити привремени фајл слике", + "FrmMain.MnuGoTo._Description": "Унесите индекс слике и притисните Enter", + "FrmSettings.Toolbar._EnableCenterToolbar": "Централно поравнање", + "FrmMain.MnuResizeTool": "Промена величине слике", + "FrmSettings.Layout._Toolbar": "Трака са алаткама", + "FrmMain.MnuHelp": "Помоћ", + "_.ImageOrderBy._FileSize": "Величина фајла", + "FrmSettings._Theme._OpenThemeFolder": "Отвори фолдер", + "FrmMain.MnuNavigation": "Навигација", + "_._Save": "Сачувај", + "FrmQuickSetup._SettingProfileDescription": "Да бисте их променили, отворите подешавања програма.", + "_._UserAction._MenuNotFound": "Није могуће пронаћи мени „{0}” за позивање радње", + "FrmMain.MnuPanToLeftSide": "Помери слику на леви крај", + "FrmUpdate._CurrentVersion": "Тренутна верзија: {0}", + "FrmCrop.BtnSettings._Tooltip": "Подешавања алатке за опсецање", + "_.ColorProfileOption._Custom": "Прилагођени", + "FrmSettings._UseEmbeddedThumbnailOtherFormats": "Учитај само уграђену сличицу за друге формате", + "FrmMain.MnuGoToFirst": "Прва слика", + "FrmSettings._ExportLanguagePack": "Извези језички пакет…", + "FrmSettings.Nav._Mouse": "Миш", + "_.ImageOrderBy._DateCreated": "Датум настанка", + "FrmSettings._EnableFullscreenSlideshow": "Покрећи пројекцију слајдова у режиму целог екрана", + "FrmAbout._Homepage": "Сајт:", + "FrmSettings._GalleryCacheSizeInMb": "Максимална величина кеша галерије (у мегабајтима)", + "FrmMain.MnuCopyImageData._Success": "Слика је копирана.", + "FrmSettings._EnableLoopBackNavigation": "Врати на прву слику када се достигне крај листе", + "_.MouseWheelEvent._Scroll": "Точкић миша", + "FrmCrop.BtnSave._Tooltip": "Сачувај слику", + "FrmMain.MnuSlideshow": "Пројекција слајдова", + "FrmMain.MnuShare": "Дели…", + "FrmSettings._SlideshowNotification": "Обавештење о пројекцији слајдова", + "FrmMain.MnuViewChannels": "Приказ канала", + "FrmSettings._Refresh": "Освежи", + "_._UserAction._MethodNotFound": "Није могуће пронаћи методу „{0}” за позивање радње", + "FrmMain.MnuCopyFile": "Копирај фајл", + "_._CreatingFile": "Прави се привремени фајл слике…", + "FrmMain.MnuToggleTopMost": "Фиксирај изнад свих прозора", + "FrmMain.MnuLosslessCompression._Confirm": "Желите ли заиста да наставите?", + "FrmMain.MnuImage": "Слика", + "FrmSettings._StartupBoost._Enabled": "Оптимизација покретања је омогућена", + "FrmQuickSetup._SetDefaultViewer": "Желите ли да подесите ImageGlass као подразумевани приказивач слика?", + "FrmMain.MnuScaleToWidth": "Размера према ширини", + "_._FileExtension": "Екстензија фајла", + "FrmUpdate._PublishedDate": "Датум издавања: {0}", + "_._DoNotShowThisMessageAgain": "Не приказуј поново", + "_.ImageInterpolation._NearestNeighbor": "По суседном пикселу", + "FrmCrop.LblLocation": "Локација:", + "_._Download": "Преузми", + "_.Metadata._ColorProfile": "Профил боја", + "FrmSettings._CenterWindowFit": "Центрирај прозор у режиму „Прилагоди прозор слици”", + "FrmSettings._ImageLoadingOrder": "Редослед учитавања слика", + "FrmSettings._GalleryColumns": "Број колона са сличицама у вертикалном распореду галерије", + "_._Quit": "Изађи", + "_._Add": "Додај", + "FrmMain.MnuChangeBackgroundColor": "Промени боју позадине…", + "FrmMain.MnuToggleToolbar": "Трака са алаткама", + "FrmAbout._Contact": "Контакт", + "FrmSettings.Toolbar._AddCustomButton": "Додај дугме…", + "FrmCrop.BtnQuickSelect._Tooltip": "Брзо изабери…", + "FrmMain.MnuCutFile._Success": "Исечених фајлова: {0}", + "FrmSettings._ZoomSpeed": "Брзина зумирања", + "FrmMain.MnuToggleTopMost._Disable": "Фиксирање изнад свих прозора је онемогућено", + "FrmSettings._ShouldUseExplorerSortOrder": "Сортирај према Windows-овом истраживачу датотека", + "_.ImageInterpolation._Antisotropic": "Анизотропна", + "FrmMain._ReachedFirstImage": "Дошли сте до прве слике", + "_._UnhandledException": "Неочекивана грешка", + "FrmResize.LblNewSize": "Нова величина:", + "FrmMain._ClipboardImage": "Слика из привремене меморије", + "FrmMain.MnuExportFrames": "Извези кадрове из слике…", + "FrmMain.MnuFile": "Фајл", + "_._Close": "Затвори", + "FrmMain.MnuMain": "Главни мени", + "_._ResetToDefault": "Ресетуј", + "FrmSettings.Nav._Gallery": "Галерија", + "FrmMain.MnuSetDefaultPhotoViewer._Success": "Успешно сте подесили ImageGlass као подразумевани приказивач слика.", + "FrmSettings._HideGalleryInFullscreen": "Сакриј галерију у режиму целог екрана", + "FrmSettings._AvailableImageInfoTags": "Доступне ознаке:", + "FrmExportFrames._Exporting": "Извози се кадар {0} од {1} \n{2}…", + "_._Argument": "Аргумент", + "FrmSettings._ImageEditQuality": "Квалитет слике", + "_._ID": "ID", + "FrmSettings._UserConfigFile": "Фајл са подешавањима корисника", + "FrmMain.MnuLoadingOrders": "Редослед учитавања", + "FrmSettings._OpenSaveAsDialogInTheCurrentImageDir": "Отвори дијалог „Сачувај као” у тренутном фолдеру слике", + "_.MouseWheelEvent._ShiftAndScroll": "Shift + точкић миша", + "FrmSettings._UseSmoothZooming": "Глатко зумирање", + "FrmSettings._Theme": "Тема", + "FrmSettings._ImageBoosterCacheMaxDimension": "Максималне димензије за кеширање (у пикселима)", + "FrmMain.MnuScaleToHeight": "Размера према висини", + "_.Metadata._FileLastWriteTime": "Датум измене", + "FrmSettings._Author": "Аутор", + "FrmSettings._Others": "Друго", + "_.MouseWheelAction._PanVertically": "Помери нагоре/надоле", + "FrmSettings._MouseWheelAction": "Радња точкићем миша", + "FrmSettings.Nav._Tools": "Алатке", + "FrmMain.MnuSetDesktopBackground._Error": "Није могуће поставити слику као позадину радне површине", + "FrmSettings.Toolbar._Errors._ButtonExecutableRequired": "Извршни фајл дугмета је обавезан.", + "_.ImageOrderBy._DateAccessed": "Датум приступа", + "FrmSettings._ThumbnailSize": "Величина сличица (у пикселима)", + "FrmSettings._FileFormats": "Формати фајлова", + "FrmMain.MnuReloadImageList": "Поново учитај листу слика", + "FrmSettings._UseWebview2ForSvg": "WebView2 за приказ SVG формата", + "FrmCrop.BtnCopy": "Копирај", + "FrmSettings._CurrentMonitorProfile._Description": "ImageGlass не ажурира боју аутоматски када померите његов прозор на други екран", + "FrmMain.PicMain._ErrorText": "Није могуће отворити слику", + "FrmSettings.Tools._AddNewTool": "Додавање спољашње алатке", + "FrmMain.MnuRename": "Преименуј слику…", + "FrmMain.MnuViewLastFrame": "Последњи кадар", + "_._Webview2._NotFound": "Инсталирајте WebView2 Runtime да бисте приступили свим функцијама ImageGlass-а.", + "FrmMain.MnuGetMoreTools": "Преузмите још алатки", + "FrmSettings.Nav._Appearance": "Изглед", + "FrmSettings._SlideshowInterval": "Интервал за промену слајдова:", + "_.ImageInterpolation._HighQualityBicubic": "Бикубна (висок квалитет)", + "FrmColorPickerSettings.ChkShowHsvA": "HSV формат са алфа каналом", + "FrmSettings.Tools._EditTool": "Уређивање спољашње алатке", + "_._Error": "Грешка", + "FrmSettings._ImageBoosterCacheMaxFileSizeInMb": "Максимална величина слика за кеширање (у мегабајтима)", + "_._UnhandledException._Description": "Дошло је до неочекиване грешке. Ако кликнете на „Настави”, апликација ће игнорисати ову грешку и покушати да настави са радом. Ако кликнете на „Изађи”, апликација ће се одмах затворити.", + "_.Metadata._FileSize": "Величина фајла", + "FrmSettings.Toolbar._ButtonJson": "JSON дугме", + "FrmQuickSetup._SetDefaultViewer._Description": "Можете то да ресетујете у одељку Подешавања → Формати.", + "FrmSettings.Nav._Edit": "Уређивање", + "FrmMain.MnuToggleGallery": "Галерија", + "_._IgCommandExe._DefaultError._Description": "Проверите да ли прослеђујете исправне команде.\r\nОвај извршни фајл садржи функције командне линије за ImageGlass.\r\n\r\nДа бисте истражили све функције, посетите:\n{0}", + "FrmMain.MnuLosslessCompression._Compressing": "Компримује се без губитака…", + "FrmSettings._ShouldGroupImagesByDirectory": "Групиши слике према фолдерима", + "FrmMain.MnuPanToRightSide": "Помери слику на десни крај", + "_.Metadata._ExifRatingPercent": "Оцена", + "FrmSettings._PanSpeed": "Брзина померања", + "_._CheckForUpdate": "Потражи ажурирање", + "FrmSettings.Layout._ToolbarContext": "Контекстуална трака са алаткама", + "_.ImageInfo._FrameCount": "Број кадрова: {0}", + "FrmMain.MnuLayout": "Распоред", + "_._Website": "Сајт", + "FrmMain.MnuPasteImage": "Налепи слику", + "FrmSettings._ShowGalleryScrollbars": "Трака за померање у галерији" + } +} \ No newline at end of file diff --git a/Setup/Assets/Language/Serbian (Latin).iglang.json b/Setup/Assets/Language/Serbian (Latin).iglang.json new file mode 100644 index 000000000..56682e636 --- /dev/null +++ b/Setup/Assets/Language/Serbian (Latin).iglang.json @@ -0,0 +1,504 @@ +{ + "_Metadata": { + "Code": "sr-Latn-RS", + "EnglishName": "Serbian (Latin)", + "LocalName": "Srpski", + "Author": "Đorđe Vasiljević", + "MinVersion": "9.3" + }, + "Items": { + "FrmCrop.SelectionAspectRatio._Original": "Originalna", + "FrmMain.MnuShare._Error": "Nije moguće otvoriti dijalog za deljenje.", + "_.Metadata._FileLastAccessTime": "Datum pristupa", + "FrmAbout._License": "Licenca", + "FrmSettings.Toolbar._Errors._ButtonIdDuplicated": "Dugme sa ID-jem „{0}” već postoji. Izaberite jedinstveni ID da biste izbegli konflikte.", + "FrmMain.MnuSave._Confirm": "Želite li zaista da zamenite ovu sliku?", + "FrmSettings._OpenDefaultAppsSetting": "Otvori podešavanja podrazumevanih aplikacija", + "FrmMain.MnuCopyPath": "Kopiraj putanju do slike", + "FrmCropSettings.DefaultSelectionType._SelectNone": "Poništi izbor svega", + "_.MouseWheelAction._PanHorizontally": "Pomeri ulevo/udesno", + "FrmMain.MnuPrint": "Odštampaj…", + "FrmSettings.Toolbar._ToolbarButtons": "Dugmad na traci sa alatkama", + "FrmResize.LblResample": "Uzorkovanje:", + "_.ImageOrderBy._Extension": "Ekstenzija", + "FrmSettings.Nav._Viewer": "Prikazivač", + "FrmSettings.EditAppDialog._EditApp": "Uređivanje programa", + "FrmCrop.BtnReset._Tooltip": "Resetuj izbor", + "FrmMain.MnuRename._Description": "Unesite novi naziv fajla:", + "_._No": "Ne", + "FrmSlideshow.MnuToggleCountdown": "Odbrojavanje", + "FrmSettings._OpenStartupAppsSetting": "Otvori podešavanja pokretanja aplikacija", + "FrmMain.MnuViewPreviousFrame": "Prethodni kadar", + "_.ImageOrderBy._DateModified": "Datum izmene", + "FrmMain.MnuViewNextFrame": "Sledeći kadar", + "FrmMain.MnuUnload": "Zatvori sliku", + "FrmSettings.Toolbar._HideToolbarInFullscreen": "Sakrij traku u režimu celog ekrana", + "_.ImageOrderType._Desc": "Opadajuće", + "_._Update": "Ažuriraj", + "FrmSettings._EnableImageAsyncLoading": "Asinhrono učitavanje slika", + "FrmSettings._DefaultPhotoViewer._Description": "Registrujte formate koje ImageGlass podržava sa Windowsom. Možda ćete morati da otvorite podešavanja podrazumevanih aplikacija i ručno izaberete ImageGlass sa liste kako bi izmene stupile na snagu.", + "_.MouseWheelAction._BrowseImages": "Prikaži sledeću/prethodnu sliku", + "FrmSettings._EditApps": "Programi za uređivanje slika", + "FrmColorPickerSettings.ChkShowCIELabA": "CIELAB format sa alfa kanalom", + "_._GetHelp": "Pomoć", + "FrmQuickSetup._SkipQuickSetup": "Preskoči i pokreni ImageGlass", + "FrmColorPickerSettings._Title": "Podešavanja birača boja", + "_._Copy": "Kopiraj", + "FrmSettings._ImageBoosterCacheCount": "Broj keširanih slika (u jednom smeru)", + "FrmMain.MnuPanToBottom": "Pomeri sliku na dno", + "FrmMain.MnuZoom": "Zumiranje", + "FrmCropSettings.ChkCloseToolAfterSaving": "Zatvori nakon čuvanja", + "FrmSettings._ShowWelcomeImage": "Prikaži sliku dobrodošlice", + "FrmSettings._ColorProfile": "Profil boja", + "FrmSettings._Theme._UninstallTheme": "Deinstaliranje teme", + "FrmMain._OpenWith": "Otvori pomoću {0}", + "FrmMain.MnuRemoveDefaultPhotoViewer": "Ukloni podrazumevani prikazivač slika", + "_.AfterEditAppAction._Nothing": "Ne radi ništa", + "FrmCrop.BtnSave": "Sačuvaj", + "FrmMain.MnuScaleToFit": "Razmera prema prozoru", + "FrmToolNotFound.LblDownloadToolText": "Više alatki za ImageGlass možete da preuzmete na:", + "_._LearnMore": "Saznajte više…", + "FrmCrop.LblAspectRatio": "Razmera:", + "FrmExportFrames._FileNotExist": "Fajl slike ne postoji", + "FrmSettings._LightTheme": "Svetla", + "FrmSettings.Nav._Slideshow": "Projekcija slajdova", + "_._Continue": "Nastavi", + "_._AddHotkey": "Dodaj prečicu…", + "FrmMain.MnuSetDesktopBackground": "Postavi kao pozadinu radne površine", + "FrmMain.MnuReload": "Ponovo učitaj sliku", + "FrmSlideshow.MnuExitSlideshow": "Izađi iz projekcije slajdova", + "FrmMain.MnuAutoZoom": "Automatsko zumiranje", + "FrmSettings._ShowImagePreview": "Prikaži pregled slike dok se učitava", + "FrmCrop.BtnCopy._Tooltip": "Kopiraj izbor u privremenu memoriju", + "FrmSettings.Nav._Toolbar": "Traka sa alatkama", + "FrmMain.MnuSave._Error": "Nije moguće sačuvati sliku", + "FrmSettings._AfterEditingAction": "Nakon otvaranja u uređivaču", + "FrmSettings._ShouldUseColorProfileForAll": "Primeni i na slike bez ugrađenog profila boja", + "FrmCropSettings.DefaultSelectionType._UseTheLastSelection": "Koristi poslednji izbor", + "FrmSettings._SlideshowInterval._From": "Od", + "FrmSettings._ImageInterpolation": "Interpolacija slika", + "FrmQuickSetup._StepInfo": "Korak {0}", + "FrmMain.MnuColorPicker": "Birač boja", + "FrmCrop.SelectionAspectRatio._FreeRatio": "Slobodni režim", + "FrmSettings._ResetSettings": "Resetuj podešavanja", + "FrmSettings._Startup": "Pokretanje", + "_.BackdropStyle._None": "Nema", + "FrmSettings._LoadDefaultZoomLevels": "Učitaj podrazumevane faktore zumiranja", + "FrmColorPicker.BtnSettings._Tooltip": "Otvori podešavanja birača boja…", + "FrmSettings._UseThemeForDarkMode": "Koristi ovu temu u tamnom režimu", + "FrmSettings._ShowDeleteConfirmation": "Dijalog o potvrdi pri brisanju fajla", + "FrmSettings._ShowAppIcon": "Ikona aplikacije u naslovnoj traci", + "_._InvalidAction": "Nevažeća radnja", + "FrmQuickSetup._SelectProfile": "Izaberite profil", + "_.Metadata._FileCreationTime": "Datum nastanka", + "FrmSettings._SlideshowImagesToNotifySound": "Broj slika za aktiviranje zvuka obaveštenja", + "FrmSettings._BackgroundColor": "Pozadinska boja prikazivača", + "FrmSettings._RealTimeFileUpdate": "Osvežavanje fajlova u realnom vremenu", + "_.ColorProfileOption._CurrentMonitorProfile": "Profil trenutnog ekrana", + "FrmSettings._EnableCutMultipleFiles": "Isecanje više fajlova odjednom", + "FrmSettings._AutoUpdate": "Automatski traži ažuriranja", + "FrmCropSettings.LblDefaultSelection": "Podrazumevani izbor", + "FrmSettings._UseThemeForLightMode": "Koristi ovu temu u svetlom režimu", + "FrmSettings._ZoomLevels": "Faktori zumiranja", + "FrmMain.MnuSetLockScreen._Success": "Pozadina zaključanog ekrana je promenjena", + "FrmSettings._ShowGalleryFileName": "Naziv fajla ispod sličica", + "FrmSettings.Layout._Order": "Redosled", + "FrmCropSettings.ChkAutoCenterSelection": "Centriraj izbor", + "FrmSettings.Nav._FileTypeAssociations": "Formati", + "_._Back": "Nazad", + "FrmMain.MnuSetDesktopBackground._Success": "Pozadina radne površine je promenjena", + "FrmSettings._ShouldAutoOpenNewAddedImage": "Automatski otvori upravo dodatu sliku", + "FrmCrop.SelectionAspectRatio._Custom": "Prilagođena", + "FrmMain.MnuCopyPath._Success": "Putanja do slike je kopirana.", + "FrmSettings._StartupBoost._Error": "Nije moguće promeniti optimizaciju pokretanja", + "FrmToolNotFound.LblDescription": "ImageGlass ne može da pronađe izvršni fajl alatke {0}. Promenite putanju do nje ispod.", + "FrmMain.MnuClearClipboard": "Obriši privremenu memoriju", + "FrmSettings._ColorManagement": "Upravljanje bojama", + "FrmMain._ReachedLastLast": "Došli ste do poslednje slike", + "FrmMain.MnuPanUp": "Pomeri sliku nagore", + "FrmMain.MnuRemoveDefaultPhotoViewer._Success": "ImageGlass više nije podrazumevani prikazivač slika.", + "FrmSettings._GetMoreLanguagePacks": "Preuzmite još jezičkih paketa", + "FrmAbout._Privacy": "Politika privatnosti", + "FrmSettings._EnableRecursiveLoading": "Učitavaj slike u potfolderima", + "_._UserAction._MethodArgumentNotSupported": "Tip argumenta metode „{0}” nije podržan", + "FrmSettings._FileExtensionIcons._Description": "Da biste prilagodili ikone za ekstenzije fajlova, preuzmite paket ikona, smestite sve ICO fajlove u folder sa ikonama i kliknite na dugme „{0}”. Ovim ćete i podesiti ImageGlass kao podrazumevani prikazivač slika.", + "_.ImageOrderType._Asc": "Rastuće", + "FrmExportFrames._Title": "Izvoz kadrova iz slike", + "_._Install": "Instaliraj…", + "FrmMain.MnuFlipHorizontal": "Obrni horizontalno", + "FrmSettings._OpenExtensionIconFolder": "Otvori folder", + "FrmAbout._Collaborator": "Saradnik:", + "FrmQuickSetup._ConfirmCloseProcess": "Potrebno je zatvoriti sve procese ImageGlassa pre primene novih podešavanja. Želite li da nastavite?", + "FrmExportFrames._ExportDone": "Izvezeno je {0} kadrova u \n{1}", + "FrmCrop.BtnSaveAs._Tooltip": "Sačuvaj kao kopiju…", + "FrmMain.MnuOpenFile": "Otvori fajl…", + "FrmColorPickerSettings.ChkShowRgbA": "RGB format sa alfa kanalom", + "_.ImageInfo._ListCount": "Broj fajlova: {0}", + "FrmMain.MnuGoToLast": "Poslednja slika", + "FrmSettings._EditApps._AppName": "Naziv programa", + "FrmSettings._SlideshowBackgroundColor": "Pozadinska boja projekcije slajdova", + "FrmAbout._Email": "Imejl:", + "_.MouseWheelAction._DoNothing": "Ne radi ništa", + "FrmMain.MnuSaveAs": "Sačuvaj kao…", + "FrmMain._Loading": "Učitava se…", + "_._Browse": "Pregledaj…", + "FrmMain.MnuSetDefaultPhotoViewer._Error": "Nije moguće postaviti ImageGlass kao podrazumevani prikazivač slika.", + "FrmSettings.Nav._Language": "Jezik", + "FrmQuickSetup._SeeWhatNew": "Evidencija promena", + "FrmSettings._ImageInterpolation._ScaleUp": "Kada je zum veći od 100%", + "FrmSettings.Layout._ToolbarContextPosition": "Položaj kontekstualne trake", + "FrmMain.MnuDeleteFromHardDisk": "Izbriši trajno", + "FrmSettings._EmbeddedThumbnail": "Ugrađena sličica", + "FrmMain.MnuDeleteFromHardDisk._Description": "Želite li da trajno izbrišete ovaj fajl?", + "FrmMain.MnuScaleToFill": "Popuni prozor", + "FrmCrop.BtnCrop": "Opseci", + "_.AfterEditAppAction._Minimize": "Umanji", + "FrmMain.MnuInvertColors": "Obrni boje", + "FrmSettings._StartupBoost": "Optimizacija pokretanja", + "FrmMain.MnuViewFirstFrame": "Prvi kadar", + "_.MouseWheelEvent._CtrlAndScroll": "Ctrl + točkić miša", + "FrmSettings._HideMainWindowInSlideshow": "Automatski sakrij glavni prozor", + "_.Metadata._FrameCount": "Kadrovi", + "FrmSettings._EnableCopyMultipleFiles": "Kopiranje više fajlova odjednom", + "FrmMain.MnuFrameless._EnableDescription": "Držite Shift da biste pomerali prozor.", + "_.ImageOrderBy._ExifDateTaken": "Datum nastanka (EXIF)", + "FrmAbout._Credits": "Zasluge", + "FrmSettings._AddNewFileExtension": "Dodavanje nove ekstenzije fajla", + "FrmMain.MnuQuickSetup": "Brzo podešavanje ImageGlassa", + "FrmMain.MnuSave._Success": "Slika je sačuvana", + "FrmMain.MnuPanLeft": "Pomeri sliku ulevo", + "FrmUpdate._StatusChecking": "Traži se ažuriranje…", + "FrmSettings.Nav._Layout": "Raspored", + "FrmMain.MnuOpenWith": "Otvori pomoću…", + "FrmAbout._Thanks": "Posebna zahvalnost:", + "_._Warning": "Upozorenje", + "FrmSettings.Nav._Keyboard": "Tastatura", + "FrmSlideshow._PauseSlideshow": "Projekcija slajdova je pauzirana.", + "_._Add+": "Dodaj…", + "_._Email": "Imejl", + "FrmMain.MnuPanDown": "Pomeri sliku nadole", + "_._Cancel": "Otkaži", + "_._OK": "U redu", + "FrmMain.MnuPanRight": "Pomeri sliku udesno", + "_.Position._Right": "Desno", + "_._Icon": "Ikona", + "FrmSettings._ShouldLoadHiddenImages": "Učitavaj sakrivene slike", + "_._InvalidAction._Transformation": "ImageGlass ne podržava rotiranje ni okretanje ove slike.", + "FrmSettings._MakeDefault": "Podesi", + "FrmMain.MnuCopyImageData._Copying": "Slika se kopira. Potrajaće neko vreme…", + "FrmSettings._UseEmbeddedThumbnailRawFormats": "Učitaj samo ugrađenu sličicu za RAW formate", + "_.ImageInterpolation._Linear": "Linearna", + "FrmSettings._ImageInfoTags": "Informacije o slikama", + "FrmSettings._FileExtensionIcons": "Ikone za ekstenzije fajlova", + "FrmMain.MnuEdit._AppNotFound": "Nije moguće pronaći aplikaciju za uređivanje. Možete da dodelite aplikaciju za uređivanje ovog formata u odeljku Podešavanja → Uređivanje.", + "_.ColorProfileOption._None": "Nijedan", + "FrmSettings._TotalSupportedFormats": "Ukupno podržanih formata: {0}", + "FrmSettings._Clipboard": "Privremena memorija", + "_._UserAction._Win32ExeError": "Nije moguće izvršiti komandu „{0}”. Proverite da li je naziv ispravan.", + "FrmCropSettings.DefaultSelectionType._SelectX": "Izaberi {0}", + "_.AfterEditAppAction._Close": "Zatvori", + "FrmAbout._LogoDesigner": "Dizajn logotipa:", + "_.ImageOrderBy._Name": "Naziv (podrazumevano)", + "FrmMain.MnuRemoveDefaultPhotoViewer._Error": "Nije moguće ukloniti ImageGlass kao podrazumevani prikazivač slika.", + "FrmExportFrames._FolderPickerTitle": "Izbor odredišnog foldera za izvoz kadrova iz slike", + "FrmAbout._Donate": "Donirajte", + "FrmMain.MnuFrameNav": "Navigacija po kadrovima", + "FrmMain.MnuSetLockScreen": "Postavi kao pozadinu zaključanog ekrana", + "_._Delete": "Izbriši", + "FrmMain.MnuViewPrevious": "Prethodna slika", + "_.Position._Top": "Na vrhu", + "FrmSettings.Toolbar._CurrentButtons": "Trenutna dugmad:", + "FrmMain.MnuAbout": "O programu", + "FrmSettings._RemoveDefault": "Resetuj", + "_._Description": "Opis", + "FrmMain.MnuPasteImage._Error": "Nije moguće pronaći sliku u privremenoj memoriji", + "FrmMain.MnuSettings": "Podešavanja", + "FrmCropSettings._Title": "Podešavanja opsecanja", + "FrmSettings.Toolbar._ToolbarIconHeight": "Veličina ikona", + "FrmSettings._SlideshowInterval._To": "Do", + "FrmSettings.Layout._ToolbarPosition": "Položaj trake sa alatkama", + "FrmUpdate._StatusUpdated": "Koristite najnoviju verziju!", + "FrmMain.MnuExit": "Izađi", + "_._Webview2._Outdated": "Vaša verzija WebView2 Runtimea nije podržana. Ažurirajte na verziju {0} ili noviju.", + "_._Yes": "Da", + "FrmMain.MnuRotateLeft": "Rotiraj ulevo", + "FrmSettings._EnableStartupBoost": "Omogući optimizaciju", + "_.ImageOrderBy._ExifRating": "Ocena (EXIF)", + "FrmMain.MnuZoomIn": "Uvećaj", + "_.Metadata._ColorSpace": "Opseg boja", + "FrmAbout._Version": "Verzija:", + "FrmMain.MnuToggleTopMost._Enable": "Fiksiranje iznad svih prozora je omogućeno", + "FrmSettings.Toolbar._AvailableButtons": "Dostupna dugmad:", + "FrmMain.MnuSave._Saving": "Čuva se slika…", + "FrmQuickSetup._StandardUser": "Prosečan korisnik", + "FrmMain.MnuSetLockScreen._Error": "Nije moguće postaviti sliku kao pozadinu zaključanog ekrana", + "FrmSettings.Nav._Image": "Slika", + "FrmSettings._Theme._InstallTheme": "Instaliranje teme", + "FrmSettings._EnableMultiInstances": "Više instanci programa", + "FrmMain.MnuCropTool": "Opsecanje slike", + "_._IgCommandExe._DefaultError._Heading": "Nevažeće komande", + "_._Refresh": "Osveži", + "FrmMain.MnuLosslessCompression._Description": "Ova alatka koristi biblioteku Magick.NET za komprimovanje, optimizujući time veličinu fajlova. Zamenjuje samo ako je komprimovani fajl manji od originala.", + "_._MoveDown": "Pomeri nadole", + "FrmSettings._GetExtensionIconPacks": "Preuzmite ikone ekstenzija", + "FrmSettings._InAppMessageDuration": "Trajanje poruke u aplikaciji (u milisekundama)", + "FrmMain.MnuFrameless": "Prozor bez okvira", + "_._Reset": "Resetuj", + "FrmSettings._ConfigDir": "Folder sa konfiguracionim fajlovima", + "FrmQuickSetup._SettingsWillBeApplied": "Ova podešavanja će se primeniti:", + "FrmSettings._UnmanagedSettingReminder": "ImageGlass ne upravlja ovim podešavanjem. Ne zaboravite da ga onemogućite pre nego što uklonite ili premestite aplikaciju, jer ImageGlass to ne radi automatski.", + "FrmMain.MnuClipboard": "Privremena memorija", + "FrmMain.MnuCustomZoom": "Prilagođeno zumiranje…", + "FrmSettings._DisplayLanguage": "Jezik interfejsa", + "FrmMain.MnuPrint._Error": "Nije moguće odštampati sliku", + "FrmSettings._ShouldPreserveModifiedDate": "Ne menjaj datum izmene pri čuvanju slike", + "FrmSettings._ShowSaveOverrideConfirmation": "Dijalog o potvrdi pri zamenjivanju fajla", + "FrmColorPickerSettings.ChkShowHexA": "HEX format sa alfa kanalom", + "FrmMain.MnuFullScreen": "Preko celog ekrana", + "FrmSettings._StartupDir": "Folder sa izvršnim fajlom", + "FrmSettings._ShowCheckerboardOnlyImageRegion": "Pozadina prozirnosti samo u granicama slike", + "FrmMain.MnuClearClipboard._Success": "Privremena memorija je obrisana.", + "FrmQuickSetup._Text": "Brzo podešavanje ImageGlassa", + "FrmMain.MnuLosslessCompression._Done": "Komprimovanje bez gubitaka je završeno.\r\nNova veličina fajla – {0}, sačuvano – {1}.", + "FrmMain.MnuLosslessCompression": "Magick.NET kompresija bez gubitaka", + "FrmResize.RadResizeByPercentage": "Procenat", + "FrmSettings._StartupBoost._Disabled": "Optimizacija pokretanja je onemogućena", + "FrmMain.MnuToggleCheckerboard": "Pozadina prozirnosti", + "FrmSettings._MinEmbeddedThumbnailSize._Height": "Visina", + "FrmSettings.Nav._General": "Opšte", + "FrmSettings._ImageLoading": "Učitavanje slika", + "FrmSettings._ShowSlideshowCountdown": "Odbrojavanje", + "FrmMain.MnuSave": "Sačuvaj", + "FrmMain.MnuMoveToRecycleBin": "Premesti u kantu za otpatke", + "FrmMain.MnuRefresh": "Osveži", + "FrmToolNotFound.LblHeading": "Alatka {0} nije pronađena", + "FrmMain.MnuReportIssue": "Prijavite problem", + "FrmMain.MnuCopyImageData": "Kopiraj sliku", + "FrmMain.MnuCheckForUpdate._NewVersion": "Dostupna je nova verzija!", + "_._Empty": "(prazno)", + "FrmSettings._Zooming": "Zumiranje", + "FrmMain.MnuCutFile": "Iseci fajl", + "FrmHotkeyPicker.LblHotkey": "Pritisnite kombinaciju tastera", + "FrmSettings.Layout._Gallery": "Galerija", + "FrmMain.MnuNewWindow": "Otvori novi prozor", + "FrmMain.MnuMoveToRecycleBin._Description": "Želite li da premestite ovaj fajl u kantu za otpatke?", + "FrmSettings._DefaultPhotoViewer": "Podrazumevani prikazivač slika", + "_.Metadata._ExifDateTimeOriginal": "EXIF: DateTimeOriginal", + "FrmMain.MnuRotateRight": "Rotiraj udesno", + "FrmSettings._MinEmbeddedThumbnailSize": "Minimalna veličina ugrađene sličice za učitavanje", + "FrmMain.MnuSetDefaultPhotoViewer": "Podešavanje podrazumevanog prikazivača slika", + "FrmMain.MnuImageProperties": "Svojstva slike", + "FrmSettings._EnableNavigationButtons": "Strelice za navigaciju", + "_._Edit": "Uredi", + "FrmSettings._ImageBooster": "Keširanje slika", + "FrmSettings.Tools._IntegratedWith": "Integrisano pomoću {0}a", + "_._Next": "Sledeće", + "FrmExportFrames._OpenOutputFolder": "Otvori folder", + "FrmMain.MnuOpenLocation": "Otvori lokaciju slike", + "FrmMain.MnuLockZoom": "Zaključaj faktor zumiranja", + "FrmSettings._StartupBoost._Description": "Unapred učitava i pokreće ImageGlass sa sistemom kako bi ubrzao prvo pokretanje.", + "FrmSettings._WindowBackdrop": "Pozadina prozora", + "FrmSettings._EnableRealTimeFileUpdate": "Nadgledaj promene fajlova u trenutnom folderu i primeni ih", + "_._NotSupported": "Nepodržani format", + "FrmSettings._Theme._GetMoreThemes": "Preuzmite još tema", + "FrmMain.MnuNewWindow._Error": "Nije moguće otvoriti novi prozor jer je dozvoljena samo jedna instanca programa", + "FrmMain.MnuZoomOut": "Umanji", + "FrmSettings.Toolbar._EditButton": "Uređivanje dugmeta na traci sa alatkama", + "FrmMain.MnuCustomZoom._Description": "Unesite faktor zumiranja", + "FrmResize.RadResizeByPixels": "Pikseli", + "FrmMain.MnuEdit": "Uredi sliku {0}…", + "FrmSettings.Layout._GalleryPosition": "Položaj galerije", + "FrmMain.MnuWindowFit": "Prilagodi prozor slici", + "FrmMain._OpenFileDialog": "Svi podržani fajlovi", + "FrmSettings._UseRandomIntervalForSlideshow": "Nasumični interval", + "_.Position._Left": "Levo", + "FrmSettings._ShouldOpenLastSeenImage": "Otvori poslednje prikazanu sliku", + "_.Position._Bottom": "Na dnu", + "FrmResize.ChkKeepRatio": "Zadrži proporcije", + "FrmMain.MnuGoTo": "Idi na…", + "FrmSlideshow.MnuPauseResumeSlideshow": "Pauziraj/nastavi projekciju slajdova", + "FrmSettings.Tools._Integrated": "Integrisano", + "FrmSettings._Contributors": "Saradnici", + "_.MouseWheelAction._Zoom": "Uvećaj/umanji", + "_._CommandPreview": "Pregled komande", + "FrmSettings._DarkTheme": "Tamna", + "_._Hotkeys": "Prečice", + "_.Metadata._ExifDateTime": "EXIF: DateTime", + "FrmSettings.Toolbar._Errors._ButtonIdRequired": "ID dugmeta je obavezan.", + "FrmSettings._MinEmbeddedThumbnailSize._Width": "Širina", + "_._Executable": "Izvršni fajl", + "_.ImageInterpolation._MultiSampleLinear": "Linearna sa više uzoraka", + "_._Separator": "Separator", + "FrmQuickSetup._ProfessionalUser": "Iskusan korisnik", + "FrmMain.MnuFlipVertical": "Obrni vertikalno", + "FrmSlideshow._ResumeSlideshow": "Projekcija slajdova je nastavljena.", + "FrmCropSettings.DefaultSelectionType._CustomArea": "Prilagođeno", + "FrmMain.MnuActualSize": "Originalna veličina", + "FrmCrop.BtnSaveAs": "Sačuvaj kao…", + "FrmSettings._InstallNewLanguagePack": "Instaliraj novi jezički paket…", + "FrmSlideshow.MnuZoomModes": "Režimi zumiranja", + "FrmMain.MnuTools": "Alatke", + "_.ImageInterpolation._Cubic": "Kubna", + "FrmUpdate._LatestVersion": "Najnovija verzija: {0}", + "FrmMain.MnuViewNext": "Sledeća slika", + "_.MouseWheelEvent._AltAndScroll": "Alt + toškić miša", + "FrmToolNotFound._Title": "Alatka nije pronađena", + "FrmCrop.BtnCrop._Tooltip": "Opseci sliku", + "FrmSettings.EditAppDialog._AddApp": "Dodavanje programa za uređivanje", + "FrmMain.MnuPanning": "Pomeranje", + "_._MoveUp": "Pomeri nagore", + "FrmCropSettings.DefaultSelectionType._SelectAll": "Izaberi sve", + "_._Name": "Naziv", + "FrmColorPickerSettings.ChkShowHslA": "HSL format sa alfa kanalom", + "FrmMain.MnuToggleImageAnimation": "Pokreni/zaustavi animaciju", + "FrmSettings._DisableStartupBoost": "Onemogući optimizaciju", + "FrmMain.MnuCopyFile._Success": "Kopiranih fajlova: {0}", + "FrmMain.MnuSave._ConfirmDescription": "ImageGlass nije profesionalni uređivač slika. Moguć je gubitak kvaliteta, metapodataka ili slojeva pri njihovom čuvanju.", + "FrmToolNotFound.BtnSelectExecutable": "Izaberi…", + "FrmUpdate._StatusOutdated": "Dostupna je nova verzija!", + "_.ImageOrderBy._Random": "Nasumično", + "FrmResize.LblCurrentSize": "Trenutna veličina:", + "_._Apply": "Primeni", + "FrmAbout._Slogan": "Jednostavan i univerzalan prikazivač slika", + "FrmMain.MnuPanToTop": "Pomeri sliku na vrh", + "FrmSettings.Toolbar._AddNewButton": "Dodavanje dugmeta na traku sa alatkama", + "FrmCrop.LblSize": "Veličina:", + "FrmSettings._ImageInterpolation._ScaleDown": "Kada je zum manji od 100%", + "_._CreatingFileError": "Nije moguće napraviti privremeni fajl slike", + "FrmMain.MnuGoTo._Description": "Unesite indeks slike i pritisnite Enter", + "FrmSettings.Toolbar._EnableCenterToolbar": "Centralno poravnanje", + "FrmMain.MnuResizeTool": "Promena veličine slike", + "FrmSettings.Layout._Toolbar": "Traka sa alatkama", + "FrmMain.MnuHelp": "Pomoć", + "_.ImageOrderBy._FileSize": "Veličina fajla", + "FrmSettings._Theme._OpenThemeFolder": "Otvori folder", + "FrmMain.MnuNavigation": "Navigacija", + "_._Save": "Sačuvaj", + "FrmQuickSetup._SettingProfileDescription": "Da biste ih promenili, otvorite podešavanja programa.", + "_._UserAction._MenuNotFound": "Nije moguće pronaći meni „{0}” za pozivanje radnje", + "FrmMain.MnuPanToLeftSide": "Pomeri sliku na levi kraj", + "FrmUpdate._CurrentVersion": "Trenutna verzija: {0}", + "FrmCrop.BtnSettings._Tooltip": "Podešavanja alatke za opsecanje", + "_.ColorProfileOption._Custom": "Prilagođeni", + "FrmSettings._UseEmbeddedThumbnailOtherFormats": "Učitaj samo ugrađenu sličicu za druge formate", + "FrmMain.MnuGoToFirst": "Prva slika", + "FrmSettings._ExportLanguagePack": "Izvezi jezički paket…", + "FrmSettings.Nav._Mouse": "Miš", + "_.ImageOrderBy._DateCreated": "Datum nastanka", + "FrmSettings._EnableFullscreenSlideshow": "Pokreći projekciju slajdova u režimu celog ekrana", + "FrmAbout._Homepage": "Sajt:", + "FrmSettings._GalleryCacheSizeInMb": "Maksimalna veličina keša galerije (u megabajtima)", + "FrmMain.MnuCopyImageData._Success": "Slika je kopirana.", + "FrmSettings._EnableLoopBackNavigation": "Vrati na prvu sliku kada se dostigne kraj liste", + "_.MouseWheelEvent._Scroll": "Točkić miša", + "FrmCrop.BtnSave._Tooltip": "Sačuvaj sliku", + "FrmMain.MnuSlideshow": "Projekcija slajdova", + "FrmMain.MnuShare": "Deli…", + "FrmSettings._SlideshowNotification": "Obaveštenje o projekciji slajdova", + "FrmMain.MnuViewChannels": "Prikaz kanala", + "FrmSettings._Refresh": "Osveži", + "_._UserAction._MethodNotFound": "Nije moguće pronaći metodu „{0}” za pozivanje radnje", + "FrmMain.MnuCopyFile": "Kopiraj fajl", + "_._CreatingFile": "Pravi se privremeni fajl slike…", + "FrmMain.MnuToggleTopMost": "Fiksiraj iznad svih prozora", + "FrmMain.MnuLosslessCompression._Confirm": "Želite li zaista da nastavite?", + "FrmMain.MnuImage": "Slika", + "FrmSettings._StartupBoost._Enabled": "Optimizacija pokretanja je omogućena", + "FrmQuickSetup._SetDefaultViewer": "Želite li da podesite ImageGlass kao podrazumevani prikazivač slika?", + "FrmMain.MnuScaleToWidth": "Razmera prema širini", + "_._FileExtension": "Ekstenzija fajla", + "FrmUpdate._PublishedDate": "Datum izdavanja: {0}", + "_._DoNotShowThisMessageAgain": "Ne prikazuj ponovo", + "_.ImageInterpolation._NearestNeighbor": "Po susednom pikselu", + "FrmCrop.LblLocation": "Lokacija:", + "_._Download": "Preuzmi", + "_.Metadata._ColorProfile": "Profil boja", + "FrmSettings._CenterWindowFit": "Centriraj prozor u režimu „Prilagodi prozor slici”", + "FrmSettings._ImageLoadingOrder": "Redosled učitavanja slika", + "FrmSettings._GalleryColumns": "Broj kolona sa sličicama u vertikalnom rasporedu galerije", + "_._Quit": "Izađi", + "_._Add": "Dodaj", + "FrmMain.MnuChangeBackgroundColor": "Promeni boju pozadine…", + "FrmMain.MnuToggleToolbar": "Traka sa alatkama", + "FrmAbout._Contact": "Kontakt", + "FrmSettings.Toolbar._AddCustomButton": "Dodaj dugme…", + "FrmCrop.BtnQuickSelect._Tooltip": "Brzo izaberi…", + "FrmMain.MnuCutFile._Success": "Isečenih fajlova: {0}", + "FrmSettings._ZoomSpeed": "Brzina zumiranja", + "FrmMain.MnuToggleTopMost._Disable": "Fiksiranje iznad svih prozora je onemogućeno", + "FrmSettings._ShouldUseExplorerSortOrder": "Sortiraj prema Windowsovom istraživaču datoteka", + "_.ImageInterpolation._Antisotropic": "Anizotropna", + "FrmMain._ReachedFirstImage": "Došli ste do prve slike", + "_._UnhandledException": "Neočekivana greška", + "FrmResize.LblNewSize": "Nova veličina:", + "FrmMain._ClipboardImage": "Slika iz privremene memorije", + "FrmMain.MnuExportFrames": "Izvezi kadrove iz slike…", + "FrmMain.MnuFile": "Fajl", + "_._Close": "Zatvori", + "FrmMain.MnuMain": "Glavni meni", + "_._ResetToDefault": "Resetuj", + "FrmSettings.Nav._Gallery": "Galerija", + "FrmMain.MnuSetDefaultPhotoViewer._Success": "Uspešno ste podesili ImageGlass kao podrazumevani prikazivač slika.", + "FrmSettings._HideGalleryInFullscreen": "Sakrij galeriju u režimu celog ekrana", + "FrmSettings._AvailableImageInfoTags": "Dostupne oznake:", + "FrmExportFrames._Exporting": "Izvozi se kadar {0} od {1} \n{2}…", + "_._Argument": "Argument", + "FrmSettings._ImageEditQuality": "Kvalitet slike", + "_._ID": "ID", + "FrmSettings._UserConfigFile": "Fajl sa podešavanjima korisnika", + "FrmMain.MnuLoadingOrders": "Redosled učitavanja", + "FrmSettings._OpenSaveAsDialogInTheCurrentImageDir": "Otvori dijalog „Sačuvaj kao” u trenutnom folderu slike", + "_.MouseWheelEvent._ShiftAndScroll": "Shift + točkić miša", + "FrmSettings._UseSmoothZooming": "Glatko zumiranje", + "FrmSettings._Theme": "Tema", + "FrmSettings._ImageBoosterCacheMaxDimension": "Maksimalne dimenzije za keširanje (u pikselima)", + "FrmMain.MnuScaleToHeight": "Razmera prema visini", + "_.Metadata._FileLastWriteTime": "Datum izmene", + "FrmSettings._Author": "Autor", + "FrmSettings._Others": "Drugo", + "_.MouseWheelAction._PanVertically": "Pomeri nagore/nadole", + "FrmSettings._MouseWheelAction": "Radnja točkićem miša", + "FrmSettings.Nav._Tools": "Alatke", + "FrmMain.MnuSetDesktopBackground._Error": "Nije moguće postaviti sliku kao pozadinu radne površine", + "FrmSettings.Toolbar._Errors._ButtonExecutableRequired": "Izvršni fajl dugmeta je obavezan.", + "_.ImageOrderBy._DateAccessed": "Datum pristupa", + "FrmSettings._ThumbnailSize": "Veličina sličica (u pikselima)", + "FrmSettings._FileFormats": "Formati fajlova", + "FrmMain.MnuReloadImageList": "Ponovo učitaj listu slika", + "FrmSettings._UseWebview2ForSvg": "WebView2 za prikaz SVG formata", + "FrmCrop.BtnCopy": "Kopiraj", + "FrmSettings._CurrentMonitorProfile._Description": "ImageGlass ne ažurira boju automatski kada pomerite njegov prozor na drugi ekran", + "FrmMain.PicMain._ErrorText": "Nije moguće otvoriti sliku", + "FrmSettings.Tools._AddNewTool": "Dodavanje spoljašnje alatke", + "FrmMain.MnuRename": "Preimenuj sliku…", + "FrmMain.MnuViewLastFrame": "Poslednji kadar", + "_._Webview2._NotFound": "Instalirajte WebView2 Runtime da biste pristupili svim funkcijama ImageGlassa.", + "FrmMain.MnuGetMoreTools": "Preuzmite još alatki", + "FrmSettings.Nav._Appearance": "Izgled", + "FrmSettings._SlideshowInterval": "Interval za promenu slajdova:", + "_.ImageInterpolation._HighQualityBicubic": "Bikubna (visok kvalitet)", + "FrmColorPickerSettings.ChkShowHsvA": "HSV format sa alfa kanalom", + "FrmSettings.Tools._EditTool": "Uređivanje spoljašnje alatke", + "_._Error": "Greška", + "FrmSettings._ImageBoosterCacheMaxFileSizeInMb": "Maksimalna veličina slika za keširanje (u megabajtima)", + "_._UnhandledException._Description": "Došlo je do neočekivane greške. Ako kliknete na „Nastavi”, aplikacija će ignorisati ovu grešku i pokušati da nastavi sa radom. Ako kliknete na „Izađi”, aplikacija će se odmah zatvoriti.", + "_.Metadata._FileSize": "Veličina fajla", + "FrmSettings.Toolbar._ButtonJson": "JSON dugme", + "FrmQuickSetup._SetDefaultViewer._Description": "Možete to da resetujete u odeljku Podešavanja → Formati.", + "FrmSettings.Nav._Edit": "Uređivanje", + "FrmMain.MnuToggleGallery": "Galerija", + "_._IgCommandExe._DefaultError._Description": "Proverite da li prosleđujete ispravne komande.\r\nOvaj izvršni fajl sadrži funkcije komandne linije za ImageGlass.\r\n\r\nDa biste istražili sve funkcije, posetite:\n{0}", + "FrmMain.MnuLosslessCompression._Compressing": "Komprimuje se bez gubitaka…", + "FrmSettings._ShouldGroupImagesByDirectory": "Grupiši slike prema folderima", + "FrmMain.MnuPanToRightSide": "Pomeri sliku na desni kraj", + "_.Metadata._ExifRatingPercent": "Ocena", + "FrmSettings._PanSpeed": "Brzina pomeranja", + "_._CheckForUpdate": "Potraži ažuriranje", + "FrmSettings.Layout._ToolbarContext": "Kontekstualna traka sa alatkama", + "_.ImageInfo._FrameCount": "Broj kadrova: {0}", + "FrmMain.MnuLayout": "Raspored", + "_._Website": "Sajt", + "FrmMain.MnuPasteImage": "Nalepi sliku", + "FrmSettings._ShowGalleryScrollbars": "Traka za pomeranje u galeriji" + } +} \ No newline at end of file diff --git a/Setup/Assets/Language/Slovak.iglang.json b/Setup/Assets/Language/Slovak.iglang.json new file mode 100644 index 000000000..de734114b --- /dev/null +++ b/Setup/Assets/Language/Slovak.iglang.json @@ -0,0 +1,504 @@ +{ + "_Metadata": { + "Code": "sk-SK", + "EnglishName": "Slovak", + "LocalName": "Slovenčina", + "Author": "Michal Pavlík", + "MinVersion": "9.1" + }, + "Items": { + "FrmCrop.SelectionAspectRatio._Original": "Originál", + "FrmMain.MnuShare._Error": "Nepodarilo sa otvoriť dialógové okno Zdieľať.", + "_.Metadata._FileLastAccessTime": "Dátum prístupu", + "FrmAbout._License": "Softvérová licencia", + "FrmSettings.Toolbar._Errors._ButtonIdDuplicated": "Tlačidlo s ID '{0}' už bolo definované. Aby ste predišli konfliktom, vyberte pre svoje tlačidlo iné a jedinečné ID.", + "FrmMain.MnuSave._Confirm": "Naozaj chcete prepísať tento obrázok?", + "FrmSettings._OpenDefaultAppsSetting": "Otvoriť predvolené nastavenie aplikácie", + "FrmMain.MnuCopyPath": "Kopírovať cestu k súboru", + "FrmCropSettings.DefaultSelectionType._SelectNone": "Zrušiť výber", + "_.MouseWheelAction._PanHorizontally": "Posúvanie Doľava / Doprava", + "FrmMain.MnuPrint": "Tlačiť…", + "FrmSettings.Toolbar._ToolbarButtons": "Tlačidlá na paneli nástrojov", + "FrmResize.LblResample": "Vzorkovanie:", + "_.ImageOrderBy._Extension": "Rozšírenia", + "FrmSettings.Nav._Viewer": "Prehliadač", + "FrmSettings.EditAppDialog._EditApp": "Upraviť aplikáciu", + "FrmCrop.BtnReset._Tooltip": "Obnoviť výber", + "FrmMain.MnuRename._Description": "Zadajte nový názov súboru:", + "_._No": "No", + "FrmSlideshow.MnuToggleCountdown": "Zobraziť odpočítavanie prezentácie", + "FrmSettings._OpenStartupAppsSetting": "Otvoriť nastavenia spustenia aplikácie", + "FrmMain.MnuViewPreviousFrame": "Zobraziť predchádzajúcu snímku", + "_.ImageOrderBy._DateModified": "Dátum úpravy", + "FrmMain.MnuViewNextFrame": "Zobraziť ďalší snímok", + "FrmMain.MnuUnload": "Uvoľniť obrázok", + "FrmSettings.Toolbar._HideToolbarInFullscreen": "Skryť panel nástrojov v režime celej obrazovky", + "_.ImageOrderType._Desc": "Zostupne", + "_._Update": "Aktualizovať", + "FrmSettings._EnableImageAsyncLoading": "Povoliť asynchrónne načítavanie obrázkov", + "FrmSettings._DefaultPhotoViewer._Description": "Registrovať podporované formáty ImageGlass v systéme Windows. Možno budete musieť otvoriť nastavenia predvolených aplikácií a manuálne vybrať ImageGlass zo zoznamu, aby sa to prejavilo.", + "_.MouseWheelAction._BrowseImages": "Zobraziť nasledujúci / predchádzajúci obrázok", + "FrmSettings._EditApps": "Aplikácia na úpravu obrázkov", + "FrmColorPickerSettings.ChkShowCIELabA": "Použitie formátu CIELAB s hodnotou alfa", + "_._GetHelp": "Získať pomoc", + "FrmQuickSetup._SkipQuickSetup": "Preskočte tento krok a spustite aplikáciu ImageGlass", + "FrmColorPickerSettings._Title": "Nastavenia výberu farieb", + "_._Copy": "Kopírovať", + "FrmSettings._ImageBoosterCacheCount": "Počet obrázkov uložených do vyrovnávacej pamäte nástroja Image Booster (jeden smer)", + "FrmMain.MnuPanToBottom": "Posunúť obrázok k spodnému okraju", + "FrmMain.MnuZoom": "Priblíženie", + "FrmCropSettings.ChkCloseToolAfterSaving": "Zatvoriť nástroj Orezať po uložení", + "FrmSettings._ShowWelcomeImage": "Zobraziť uvítací obrázok", + "FrmSettings._ColorProfile": "Farebný profil", + "FrmSettings._Theme._UninstallTheme": "Odinštalovanie balíka s motívmi aplikácie", + "FrmMain._OpenWith": "Otvoriť v {0}", + "FrmMain.MnuRemoveDefaultPhotoViewer": "Odstránenie predvoleného prehliadača fotografií", + "_.AfterEditAppAction._Nothing": "Nič", + "FrmCrop.BtnSave": "Uložiť", + "FrmMain.MnuScaleToFit": "Prispôsobiť veľkost", + "FrmToolNotFound.LblDownloadToolText": "Ďalšie nástroje pre ImageGlass si môžete stiahnuť na adrese:", + "_._LearnMore": "Dozvedieť sa viac…", + "FrmCrop.LblAspectRatio": "Pomer strán:", + "FrmExportFrames._FileNotExist": "Súbor s obrázkom neexistuje", + "FrmSettings._LightTheme": "Svetlý", + "FrmSettings.Nav._Slideshow": "Prezentácia", + "_._Continue": "Pokračovať", + "_._AddHotkey": "Pridať klávesovú skratku…", + "FrmMain.MnuSetDesktopBackground": "Nastaviť ako pozadie pracovnej plochy", + "FrmMain.MnuReload": "Znova načítať obrázok", + "FrmSlideshow.MnuExitSlideshow": "Ukončiť prezentáciu", + "FrmMain.MnuAutoZoom": "Automatické zväčšenie", + "FrmSettings._ShowImagePreview": "Zobrazenie náhľadu obrázka počas jeho načítavania", + "FrmCrop.BtnCopy._Tooltip": "Kopírovanie výberu do schránky", + "FrmSettings.Nav._Toolbar": "Panel nástrojov", + "FrmMain.MnuSave._Error": "Obrázok sa nepodarilo uložiť", + "FrmSettings._AfterEditingAction": "Po otvorení aplikácie na úpravy", + "FrmSettings._ShouldUseColorProfileForAll": "Použiť aj pre obrázky bez vloženého farebného profilu", + "FrmCropSettings.DefaultSelectionType._UseTheLastSelection": "Použiť posledný výber", + "FrmSettings._SlideshowInterval._From": "Od", + "FrmSettings._ImageInterpolation": "Interpolácia obrazu", + "FrmQuickSetup._StepInfo": "Krok {0}", + "FrmMain.MnuColorPicker": "Výber farby", + "FrmCrop.SelectionAspectRatio._FreeRatio": "Voľný pomer", + "FrmSettings._ResetSettings": "Obnoviť nastavenia", + "FrmSettings._Startup": "Spustenie", + "_.BackdropStyle._None": "Žiadne", + "FrmSettings._LoadDefaultZoomLevels": "Načítanie predvolených úrovní priblíženia", + "FrmColorPicker.BtnSettings._Tooltip": "Otvoriť nastavenie výberu farieb…", + "FrmSettings._UseThemeForDarkMode": "Použiť tému pre tmavý režim", + "FrmSettings._ShowDeleteConfirmation": "Zobrazenie dialógového okna s potvrdením pri odstraňovaní súboru", + "FrmSettings._ShowAppIcon": "Zobrazenie ikony aplikácie na titulkovom riadku", + "_._InvalidAction": "Neplatná akcia", + "FrmQuickSetup._SelectProfile": "Vybrať profil", + "_.Metadata._FileCreationTime": "Dátum vytvorenia", + "FrmSettings._SlideshowImagesToNotifySound": "Počet obrázkov na spustenie zvuku upozornenia", + "FrmSettings._BackgroundColor": "Farba pozadia prehliadača", + "FrmSettings._RealTimeFileUpdate": "Aktualizácia súborov v reálnom čase", + "_.ColorProfileOption._CurrentMonitorProfile": "Aktuálny profil monitora", + "FrmSettings._EnableCutMultipleFiles": "Povoliť orezanie viacerých súborov naraz", + "FrmSettings._AutoUpdate": "Automaticky kontrolovať dostupnosť aktualizácií", + "FrmCropSettings.LblDefaultSelection": "Predvolený výber", + "FrmSettings._UseThemeForLightMode": "Použiť tému pre svetelný režim", + "FrmSettings._ZoomLevels": "Úroveň priblíženia", + "FrmMain.MnuSetLockScreen._Success": "Obraz uzamknutej obrazovky sa aktualizoval", + "FrmSettings._ShowGalleryFileName": "Zobrazenie názvu miniatúry", + "FrmSettings.Layout._Order": "Poradie", + "FrmCropSettings.ChkAutoCenterSelection": "Výber automatického centrovania", + "FrmSettings.Nav._FileTypeAssociations": "Asociácia typov súborov", + "_._Back": "Späť", + "FrmMain.MnuSetDesktopBackground._Success": "Pozadie pracovnej plochy sa aktualizovalo", + "FrmSettings._ShouldAutoOpenNewAddedImage": "Automatické otvorenie nového pridaného obrázka", + "FrmCrop.SelectionAspectRatio._Custom": "Vlastné…", + "FrmMain.MnuCopyPath._Success": "Skopírovať aktuálnu cestu k obrázku.", + "FrmSettings._StartupBoost._Error": "Nepodarilo sa zmeniť nastavenie zrýchlenia štartu", + "FrmToolNotFound.LblDescription": "ImageGlass nedokázal nájsť cestu k spustiteľnému súboru '{0}'. Ak chcete tento problém vyriešiť aktualizujte cestu k '{0}'.", + "FrmMain.MnuClearClipboard": "Vymazať schránku", + "FrmSettings._ColorManagement": "Správca farieb", + "FrmMain._ReachedLastLast": "Dosiahnuté posledného obrázku", + "FrmMain.MnuPanUp": "Posunúť obrázok hore", + "FrmMain.MnuRemoveDefaultPhotoViewer._Success": "ImageGlass už nie je predvoleným prehliadačom fotografií.", + "FrmSettings._GetMoreLanguagePacks": "Získajte ďalšie jazykové balíčky…", + "FrmAbout._Privacy": "Zásady ochrany osobných údajov", + "FrmSettings._EnableRecursiveLoading": "Načítanie obrázkov v podpriečinkoch", + "_._UserAction._MethodArgumentNotSupported": "Typ argumentu metódy '{0}' nie je podporovaný", + "FrmSettings._FileExtensionIcons._Description": "Ak chcete prispôsobiť ikony prípon súborov, stiahnite si balík ikon, umiestnite všetky súbory .ICO do priečinka s ikonami prípon a kliknite na tlačidlo '{0}'. Tým sa tiež nastaví ImageGlass ako predvolený prehliadač fotografií.", + "_.ImageOrderType._Asc": "Vzostupne", + "FrmExportFrames._Title": "Exportujte snímky obrázkov", + "_._Install": "Nainštalovať…", + "FrmMain.MnuFlipHorizontal": "Prevrátiť vodorovne", + "FrmSettings._OpenExtensionIconFolder": "Otvoriť priečinok s ikonou rozšírenia", + "FrmAbout._Collaborator": "Spolupracovník:", + "FrmQuickSetup._ConfirmCloseProcess": "Pred použitím nových nastavení je nevyhnutné ukončiť všetky procesy aplikácie ImageGlass. Ste pripravení pokračovať?", + "FrmExportFrames._ExportDone": "Úspešne exportované {0} snímok do\n{1}", + "FrmCrop.BtnSaveAs._Tooltip": "Uložiť ako kópiu…", + "FrmMain.MnuOpenFile": "Otvoriť súbor…", + "FrmColorPickerSettings.ChkShowRgbA": "Použitie formátu RGB s hodnotou alfa", + "_.ImageInfo._ListCount": "{0} súbor(y)", + "FrmMain.MnuGoToLast": "Prejdite na posledný obrázok", + "FrmSettings._EditApps._AppName": "Názov aplikácie", + "FrmSettings._SlideshowBackgroundColor": "Farba pozadia prezentácie", + "FrmAbout._Email": "E-mail:", + "_.MouseWheelAction._DoNothing": "Neurobiť nič", + "FrmMain.MnuSaveAs": "Uložiť ako…", + "FrmMain._Loading": "Načítava sa…", + "_._Browse": "Prechádzať…", + "FrmMain.MnuSetDefaultPhotoViewer._Error": "Nepodarilo sa nastaviť ImageGlass ako predvolený prehliadač fotografií.", + "FrmSettings.Nav._Language": "Jazyk", + "FrmQuickSetup._SeeWhatNew": "Pozrite si, čo je v tejto verzii nové…", + "FrmSettings._ImageInterpolation._ScaleUp": "Pri priblížení > 100 %", + "FrmSettings.Layout._ToolbarContextPosition": "Kontextová poloha panela nástrojov", + "FrmMain.MnuDeleteFromHardDisk": "Odstrániť natrvalo", + "FrmSettings._EmbeddedThumbnail": "Vložená miniatúra", + "FrmMain.MnuDeleteFromHardDisk._Description": "Naozaj chcete natrvalo odstrániť tento súbor?", + "FrmMain.MnuScaleToFill": "Prispôsobiť veľkost", + "FrmCrop.BtnCrop": "Orezať", + "_.AfterEditAppAction._Minimize": "Minimalizovať", + "FrmMain.MnuInvertColors": "Invertovať farby", + "FrmSettings._StartupBoost": "Zrýchlenie štartu", + "FrmMain.MnuViewFirstFrame": "Zobraziť prvú snímku", + "_.MouseWheelEvent._CtrlAndScroll": "Podržte Ctrl a posúvajte", + "FrmSettings._HideMainWindowInSlideshow": "Automaticky skryť hlavné okno", + "_.Metadata._FrameCount": "Snímky", + "FrmSettings._EnableCopyMultipleFiles": "Povoliť kopírovanie viacerých súborov naraz", + "FrmMain.MnuFrameless._EnableDescription": "Ak chcete okno presunúť, podržte kláves Shift.", + "_.ImageOrderBy._ExifDateTaken": "EXIF: Dátum zhotovenia", + "FrmAbout._Credits": "Poďakovanie", + "FrmSettings._AddNewFileExtension": "Pridať novú príponu súboru", + "FrmMain.MnuQuickSetup": "Otvoriť rýchle nastavenie aplikácie ImageGlass", + "FrmMain.MnuSave._Success": "Obrázok sa uložil", + "FrmMain.MnuPanLeft": "Posunúť obrázok doľava", + "FrmUpdate._StatusChecking": "Kontrola aktualizácie…", + "FrmSettings.Nav._Layout": "Rozloženie", + "FrmMain.MnuOpenWith": "Otvoriť s…", + "FrmAbout._Thanks": "Osobitné poďakovanie patrí", + "_._Warning": "Upozornenie", + "FrmSettings.Nav._Keyboard": "Klávesnica", + "FrmSlideshow._PauseSlideshow": "Prezentácia je pozastavená.", + "_._Add+": "Pridať…", + "_._Email": "E-mail", + "FrmMain.MnuPanDown": "Posunúť obrázok dole", + "_._Cancel": "Zrušiť", + "_._OK": "OK", + "FrmMain.MnuPanRight": "Posunúť obrázok doprava", + "_.Position._Right": "Vpravo", + "_._Icon": "Ikona", + "FrmSettings._ShouldLoadHiddenImages": "Načítanie skrytých obrázkov", + "_._InvalidAction._Transformation": "ImageGlass nepodporuje otáčanie, preklápanie pre tento obrázok.", + "FrmSettings._MakeDefault": "Nastaviť ako predvolené", + "FrmMain.MnuCopyImageData._Copying": "Kopírovanie obrazových údajov. Chvíľu to potrvá…", + "FrmSettings._UseEmbeddedThumbnailRawFormats": "Načítanie iba vloženej miniatúry pre formáty RAW", + "_.ImageInterpolation._Linear": "Lineárny", + "FrmSettings._ImageInfoTags": "Informačné štítky k obrázkom", + "FrmSettings._FileExtensionIcons": "Ikony prípon súborov", + "FrmMain.MnuEdit._AppNotFound": "Nepodarilo sa nájsť priradenú aplikáciu na úpravu. Aplikáciu na úpravu tohto formátu môžete priradiť v časti ImageGlass Nastavenia > Editácia.", + "_.ColorProfileOption._None": "Žiadne", + "FrmSettings._TotalSupportedFormats": "Celkovo podporované formáty: {0}", + "FrmSettings._Clipboard": "Schránka", + "_._UserAction._Win32ExeError": "Nie je možné vykonať príkaz '{0}'. Uistite sa, že názov je správny.", + "FrmCropSettings.DefaultSelectionType._SelectX": "Vybrať {0}", + "_.AfterEditAppAction._Close": "Zatvoriť", + "FrmAbout._LogoDesigner": "Návrhár loga:", + "_.ImageOrderBy._Name": "Podľa mena (predvolené)", + "FrmMain.MnuRemoveDefaultPhotoViewer._Error": "Nepodarilo sa odstrániť ImageGlass ako predvolený prehliadač fotografií.", + "FrmExportFrames._FolderPickerTitle": "Výber výstupného priečinka na exportovanie snímok", + "FrmAbout._Donate": "Prispieť", + "FrmMain.MnuFrameNav": "Navigácia v snímkoch", + "FrmMain.MnuSetLockScreen": "Nastaviť ako obrázok uzamknutej obrazovky", + "_._Delete": "Vymazať", + "FrmMain.MnuViewPrevious": "Zobraziť predchádzajúci obrázok", + "_.Position._Top": "Vrch", + "FrmSettings.Toolbar._CurrentButtons": "Aktuálne tlačidlá:", + "FrmMain.MnuAbout": "O aplikácii", + "FrmSettings._RemoveDefault": "Odstránenie predvoleného nastavenia", + "_._Description": "Popis", + "FrmMain.MnuPasteImage._Error": "V schránke sa nepodarilo nájsť údaje o obrázku", + "FrmMain.MnuSettings": "Nastavenie", + "FrmCropSettings._Title": "Nastavenia orezávania", + "FrmSettings.Toolbar._ToolbarIconHeight": "Veľkosť ikony panela s nástrojmi", + "FrmSettings._SlideshowInterval._To": "Do", + "FrmSettings.Layout._ToolbarPosition": "Pozícia panela s nástrojmi", + "FrmUpdate._StatusUpdated": "Používate najnovšiu verziu!", + "FrmMain.MnuExit": "Ukončiť", + "_._Webview2._Outdated": "Váš WebView2 Runtime nie je podporovaný. Aktualizujte na verziu {0} alebo novšiu.", + "_._Yes": "Áno", + "FrmMain.MnuRotateLeft": "Otočiť doľava", + "FrmSettings._EnableStartupBoost": "Zapnutie zrýchleného štartu", + "_.ImageOrderBy._ExifRating": "EXIF: Hodnotenie", + "FrmMain.MnuZoomIn": "Priblížiť", + "_.Metadata._ColorSpace": "Farebný priestor", + "FrmAbout._Version": "Verzia:", + "FrmMain.MnuToggleTopMost._Enable": "Povoliť okno vždy v popredí", + "FrmSettings.Toolbar._AvailableButtons": "Dostupné tlačidlá:", + "FrmMain.MnuSave._Saving": "Ukladá sa obrázok…", + "FrmQuickSetup._StandardUser": "Štandardný používateľ", + "FrmMain.MnuSetLockScreen._Error": "Nie je možné zobrazený obrázok, ako pozadie zamknutej obrazovky", + "FrmSettings.Nav._Image": "Obrázok", + "FrmSettings._Theme._InstallTheme": "Inštalácia balíkov tém", + "FrmSettings._EnableMultiInstances": "Povoliť viac inštancií programu", + "FrmMain.MnuCropTool": "Orezať obrázok", + "_._IgCommandExe._DefaultError._Heading": "Neplatný príkaz", + "_._Refresh": "Obnoviť", + "FrmMain.MnuLosslessCompression._Description": "Tento nástroj využíva knižnicu Magick.NET na bezstratovú kompresiu a optimalizuje veľkosť súboru. Prepíše len vtedy, ak je komprimovaný súbor menší ako originál.", + "_._MoveDown": "Posunúť dole", + "FrmSettings._GetExtensionIconPacks": "Získajte balíky rozšírení ikon…", + "FrmSettings._InAppMessageDuration": "Trvanie správy v aplikácii (milisekundy)", + "FrmMain.MnuFrameless": "Bez rámčekov", + "_._Reset": "Resetovať", + "FrmSettings._ConfigDir": "Umiestnenie konfigurácie", + "FrmQuickSetup._SettingsWillBeApplied": "Použijú sa nastavenia:", + "FrmSettings._UnmanagedSettingReminder": "Toto nastavenie nespravuje ImageGlass. Pred odstránením alebo premiestnením aplikácie ju nezabudnite deaktivovať, pretože ImageGlass to nespracuje automaticky.", + "FrmMain.MnuClipboard": "Schránka", + "FrmMain.MnuCustomZoom": "Vlastné priblíženie…", + "FrmSettings._DisplayLanguage": "Zobraziť jazyk", + "FrmMain.MnuPrint._Error": "Prezeraný obrázok sa nepodarilo vytlačiť", + "FrmSettings._ShouldPreserveModifiedDate": "Pri uložení zachovať zmenený dátum obrázka", + "FrmSettings._ShowSaveOverrideConfirmation": "Zobrazenie dialógového okna s potvrdením pri prepisovaní súboru", + "FrmColorPickerSettings.ChkShowHexA": "Použitie formátu HEX s hodnotou alfa", + "FrmMain.MnuFullScreen": "Celá obrazovka", + "FrmSettings._StartupDir": "Umiestnenie pri spustení", + "FrmSettings._ShowCheckerboardOnlyImageRegion": "Zobrazenie šachovnice len v rámci oblasti obrazu", + "FrmMain.MnuClearClipboard._Success": "Vymazaná schránka.", + "FrmQuickSetup._Text": "Rýchle nastavenie aplikácie ImageGlass", + "FrmMain.MnuLosslessCompression._Done": "Vykonaná bezstratová kompresia.\r\nNová veľkosť súboru je {0}, uložená {1}.", + "FrmMain.MnuLosslessCompression": "Magick.NET Bezstratová kompresia", + "FrmResize.RadResizeByPercentage": "Percento", + "FrmSettings._StartupBoost._Disabled": "Zrýchlenie štartu je vypnuté", + "FrmMain.MnuToggleCheckerboard": "Šachovnicové pozadie", + "FrmSettings._MinEmbeddedThumbnailSize._Height": "Výška", + "FrmSettings.Nav._General": "Všeobecné", + "FrmSettings._ImageLoading": "Načítava sa obrázok", + "FrmSettings._ShowSlideshowCountdown": "Zobraziť odpočítavanie prezentácie", + "FrmMain.MnuSave": "Uložiť", + "FrmMain.MnuMoveToRecycleBin": "Presunúť do koša", + "FrmMain.MnuRefresh": "Obnoviť", + "FrmToolNotFound.LblHeading": "'{0}' nebol nájdený!", + "FrmMain.MnuReportIssue": "Nahlásiť problém…", + "FrmMain.MnuCopyImageData": "Kopírovať obrazové údaje", + "FrmMain.MnuCheckForUpdate._NewVersion": "Nová verzia je k dispozícii!", + "_._Empty": "(prázdny)", + "FrmSettings._Zooming": "Približovanie", + "FrmMain.MnuCutFile": "Vystrihnutý súbor", + "FrmHotkeyPicker.LblHotkey": "Stlačte klávesovú skratku", + "FrmSettings.Layout._Gallery": "Galéria", + "FrmMain.MnuNewWindow": "Otvoriť v novom okne", + "FrmMain.MnuMoveToRecycleBin._Description": "Chcete tento súbor presunúť do koša?", + "FrmSettings._DefaultPhotoViewer": "Predvolený prehliadač fotografií", + "_.Metadata._ExifDateTimeOriginal": "EXIF: DateTimeOriginal", + "FrmMain.MnuRotateRight": "Otočiť doprava", + "FrmSettings._MinEmbeddedThumbnailSize": "Minimálna veľkosť vloženej miniatúry, ktorá sa má načítať", + "FrmMain.MnuSetDefaultPhotoViewer": "Nastavenie predvoleného prehliadača fotografií", + "FrmMain.MnuImageProperties": "Vlastnosti obrázka", + "FrmSettings._EnableNavigationButtons": "Zobraziť tlačidlá navigačných šípok", + "_._Edit": "Upraviť", + "FrmSettings._ImageBooster": "Image Booster", + "FrmSettings.Tools._IntegratedWith": "Integrované s {0}", + "_._Next": "Ďalej", + "FrmExportFrames._OpenOutputFolder": "Otvoriť výstupný priečinok", + "FrmMain.MnuOpenLocation": "Otvoriť umiestnenie súboru", + "FrmMain.MnuLockZoom": "Uzamknúť pomer zväčšenia", + "FrmSettings._StartupBoost._Description": "Načítanie a spustenie ImageGlass na pozadí na niekoľko sekúnd počas spúšťania systému Windows, aby ste urýchlili prvé spustenie.", + "FrmSettings._WindowBackdrop": "Pozadie okna", + "FrmSettings._EnableRealTimeFileUpdate": "Sledovanie zmien súborov v priečinku a aktualizácia v reálnom čase", + "_._NotSupported": "Nepodporovaný formát", + "FrmSettings._Theme._GetMoreThemes": "Získajte ďalšie tematické balíky…", + "FrmMain.MnuNewWindow._Error": "Nové okno nemožno otvoriť, pretože je povolená iba jedna inštancia", + "FrmMain.MnuZoomOut": "Oddialiť", + "FrmSettings.Toolbar._EditButton": "Tlačidlo na paneli nástrojov Upraviť", + "FrmMain.MnuCustomZoom._Description": "Vložte novú hodnotu priblíženia", + "FrmResize.RadResizeByPixels": "Pixely", + "FrmMain.MnuEdit": "Upraviť obrázok {0}…", + "FrmSettings.Layout._GalleryPosition": "Pozícia v galérii", + "FrmMain.MnuWindowFit": "Prispôsobiť oknu", + "FrmMain._OpenFileDialog": "Všetky podporované súbory", + "FrmSettings._UseRandomIntervalForSlideshow": "Použiť náhodný interval", + "_.Position._Left": "Vľavo", + "FrmSettings._ShouldOpenLastSeenImage": "Otvoriť naposledy zobrazený obrázok", + "_.Position._Bottom": "Spodok", + "FrmResize.ChkKeepRatio": "Zachovanie pomerov", + "FrmMain.MnuGoTo": "Ísť do…", + "FrmSlideshow.MnuPauseResumeSlideshow": "Pozastaviť/obnoviť prezentáciu", + "FrmSettings.Tools._Integrated": "Integrovaný", + "FrmSettings._Contributors": "Prispievatelia", + "_.MouseWheelAction._Zoom": "Priblíženie / oddialenie", + "_._CommandPreview": "Ukážka príkazu", + "FrmSettings._DarkTheme": "Tmavý", + "_._Hotkeys": "Klávesové skratky", + "_.Metadata._ExifDateTime": "EXIF: DateTime", + "FrmSettings.Toolbar._Errors._ButtonIdRequired": "Požaduje sa ID tlačidla.", + "FrmSettings._MinEmbeddedThumbnailSize._Width": "Šírka", + "_._Executable": "Spustiteľný súbor", + "_.ImageInterpolation._MultiSampleLinear": "Viacnásobné vzorkovanie (lineárne)", + "_._Separator": "Oddeľovač", + "FrmQuickSetup._ProfessionalUser": "Profesionálny používateľ", + "FrmMain.MnuFlipVertical": "Prevrátiť zvislo", + "FrmSlideshow._ResumeSlideshow": "Prezentácia je pozastavená.", + "FrmCropSettings.DefaultSelectionType._CustomArea": "Vlastná plocha…", + "FrmMain.MnuActualSize": "Skutočná veľkosť", + "FrmCrop.BtnSaveAs": "Uložiť ako…", + "FrmSettings._InstallNewLanguagePack": "Inštalácia nových jazykových balíkov…", + "FrmSlideshow.MnuZoomModes": "Režimy priblíženia", + "FrmMain.MnuTools": "Nástroje", + "_.ImageInterpolation._Cubic": "Kubický", + "FrmUpdate._LatestVersion": "Najnovšia verzia: {0}", + "FrmMain.MnuViewNext": "Zobraziť ďalší obrázok", + "_.MouseWheelEvent._AltAndScroll": "Podržte Alt a posúvajte", + "FrmToolNotFound._Title": "Nástroj nebol nájdený", + "FrmCrop.BtnCrop._Tooltip": "Iba orezanie obrázka", + "FrmSettings.EditAppDialog._AddApp": "Pridanie aplikácie na úpravu", + "FrmMain.MnuPanning": "Posúvanie", + "_._MoveUp": "Presunúť hore", + "FrmCropSettings.DefaultSelectionType._SelectAll": "Vybrať všetko", + "_._Name": "Meno", + "FrmColorPickerSettings.ChkShowHslA": "Použitie formátu HSL s hodnotou alfa", + "FrmMain.MnuToggleImageAnimation": "Spustenie / zastavenie animácie obrázka", + "FrmSettings._DisableStartupBoost": "Vypnutie zrýchleného štartu", + "FrmMain.MnuCopyFile._Success": "Skopírovaný(é) {0} súbor(ov).", + "FrmMain.MnuSave._ConfirmDescription": "ImageGlass nie je profesionálny editor fotografií, pamätajte na stratu kvality, metadát, vrstiev,… pri ukladaní obrázka.", + "FrmToolNotFound.BtnSelectExecutable": "Vybrať…", + "FrmUpdate._StatusOutdated": "K dispozícii je nová aktualizácia!", + "_.ImageOrderBy._Random": "Náhodne", + "FrmResize.LblCurrentSize": "Aktuálna veľkosť:", + "_._Apply": "Použiť", + "FrmAbout._Slogan": "Ľahký a všestranný prehliadač obrázkov", + "FrmMain.MnuPanToTop": "Posunúť obrázok k hornému okraju", + "FrmSettings.Toolbar._AddNewButton": "Pridanie vlastného tlačidla na paneli nástrojov", + "FrmCrop.LblSize": "Veľkosť:", + "FrmSettings._ImageInterpolation._ScaleDown": "Pri priblížení < 100 %", + "_._CreatingFileError": "Nepodarilo sa vytvoriť dočasný súbor obrázka", + "FrmMain.MnuGoTo._Description": "Zadajte index obrázka pre jeho zobrazenie, a potom stlačte ENTER", + "FrmSettings.Toolbar._EnableCenterToolbar": "Použiť zarovnania na stred pre panel nástrojov", + "FrmMain.MnuResizeTool": "Zmeniť veľkosť obrázka", + "FrmSettings.Layout._Toolbar": "Panel nástrojov", + "FrmMain.MnuHelp": "Pomoc", + "_.ImageOrderBy._FileSize": "Veľkosť súboru", + "FrmSettings._Theme._OpenThemeFolder": "Otvoriť priečinok vzhľadov", + "FrmMain.MnuNavigation": "Navigácia", + "_._Save": "Uložiť", + "FrmQuickSetup._SettingProfileDescription": "Ak chcete tieto nastavenia upraviť, jednoducho vstúpte do nastavení aplikácie.", + "_._UserAction._MenuNotFound": "Nemožno nájsť ponuku '{0}' na vyvolanie akcie", + "FrmMain.MnuPanToLeftSide": "Posunúť obrázok k ľavému okraju", + "FrmUpdate._CurrentVersion": "Aktuálna verzia: {0}", + "FrmCrop.BtnSettings._Tooltip": "Otvoriť nastavenia nástroja Orezať", + "_.ColorProfileOption._Custom": "Vlastné…", + "FrmSettings._UseEmbeddedThumbnailOtherFormats": "Načítanie iba vloženej miniatúry pre iné formáty", + "FrmMain.MnuGoToFirst": "Prejdite na prvý obrázok", + "FrmSettings._ExportLanguagePack": "Export jazykového balíka…", + "FrmSettings.Nav._Mouse": "Myš", + "_.ImageOrderBy._DateCreated": "Dátum vytvorenia", + "FrmSettings._EnableFullscreenSlideshow": "Spustenie prezentácie v režime celej obrazovky", + "FrmAbout._Homepage": "Domovská stránka:", + "FrmSettings._GalleryCacheSizeInMb": "Maximálna veľkosť vyrovnávacej pamäte galérie (v megabajtoch)", + "FrmMain.MnuCopyImageData._Success": "Skopírovať aktuálne údaje o obrázku.", + "FrmSettings._EnableLoopBackNavigation": "Návrat na prvý obrázok po dosiahnutí konca zoznamu obrázkov", + "_.MouseWheelEvent._Scroll": "Posúvanie", + "FrmCrop.BtnSave._Tooltip": "Uložiť obrázok", + "FrmMain.MnuSlideshow": "Prezentácia", + "FrmMain.MnuShare": "Zdieľať…", + "FrmSettings._SlideshowNotification": "Upozornenie na prezentáciu", + "FrmMain.MnuViewChannels": "Zobraziť kanály", + "FrmSettings._Refresh": "Obnoviť", + "_._UserAction._MethodNotFound": "Nemožno nájsť metódu '{0}' na vyvolanie akcie", + "FrmMain.MnuCopyFile": "Kopírovať súbor", + "_._CreatingFile": "Vytvára sa dočasný súbor obrázka…", + "FrmMain.MnuToggleTopMost": "Ponechať okno vždy navrchu", + "FrmMain.MnuLosslessCompression._Confirm": "Ste si istý/á, že chcete pokračovať?", + "FrmMain.MnuImage": "Obrázok", + "FrmSettings._StartupBoost._Enabled": "Zrýchlenie štartu je zapnuté", + "FrmQuickSetup._SetDefaultViewer": "Chcete nastaviť ImageGlass ako predvolený prehliadač fotografií?", + "FrmMain.MnuScaleToWidth": "Prispôsobiť na šírku", + "_._FileExtension": "Prípona súboru", + "FrmUpdate._PublishedDate": "Dátum uverejnenia: {0}", + "_._DoNotShowThisMessageAgain": "Túto správu už viac nezobrazovať", + "_.ImageInterpolation._NearestNeighbor": "Najbližšia-hranica", + "FrmCrop.LblLocation": "Umiestnenie:", + "_._Download": "Stiahnuť", + "_.Metadata._ColorProfile": "Farebný profil", + "FrmSettings._CenterWindowFit": "Automatické vycentrovanie okna v režime prispôsobenia oknu", + "FrmSettings._ImageLoadingOrder": "Poradie načítania obrázka", + "FrmSettings._GalleryColumns": "Počet stĺpcov miniatúr vo vertikálnom rozložení galérie", + "_._Quit": "Ukončiť", + "_._Add": "Pridať", + "FrmMain.MnuChangeBackgroundColor": "Zmeniť farbu pozadia…", + "FrmMain.MnuToggleToolbar": "Panel nástrojov", + "FrmAbout._Contact": "Kontakt", + "FrmSettings.Toolbar._AddCustomButton": "Pridanie vlastného tlačidla…", + "FrmCrop.BtnQuickSelect._Tooltip": "Rýchly výber…", + "FrmMain.MnuCutFile._Success": "Vyňať {0} súbor(ov).", + "FrmSettings._ZoomSpeed": "Rýchlosť priblíženia", + "FrmMain.MnuToggleTopMost._Disable": "Zakázať okno vždy v popredí", + "FrmSettings._ShouldUseExplorerSortOrder": "Ak je to možné, použite zoradenie v Prieskumníkovi", + "_.ImageInterpolation._Antisotropic": "Anizotropný", + "FrmMain._ReachedFirstImage": "Dosiahnuté prvého obrázku", + "_._UnhandledException": "Nespracovaná výnimka", + "FrmResize.LblNewSize": "Nová veľkosť:", + "FrmMain._ClipboardImage": "Obrázok zo schránky", + "FrmMain.MnuExportFrames": "Exportujte snímky obrázkov…", + "FrmMain.MnuFile": "Súbor", + "_._Close": "Zatvoriť", + "FrmMain.MnuMain": "Hlavné menu", + "_._ResetToDefault": "Obnoviť predvolené", + "FrmSettings.Nav._Gallery": "Galéria", + "FrmMain.MnuSetDefaultPhotoViewer._Success": "Úspešne ste nastavili ImageGlass ako predvolený prehliadač fotografií.", + "FrmSettings._HideGalleryInFullscreen": "Skryť galériu v režime celej obrazovky", + "FrmSettings._AvailableImageInfoTags": "Dostupné značky:", + "FrmExportFrames._Exporting": "Exportovanie {0}/{1} snímok\n{2}…", + "_._Argument": "Argument", + "FrmSettings._ImageEditQuality": "Kvalita obrázku", + "_._ID": "ID", + "FrmSettings._UserConfigFile": "Súbor s nastaveniami používateľa (igconfig.json)", + "FrmMain.MnuLoadingOrders": "Načítanie poradia", + "FrmSettings._OpenSaveAsDialogInTheCurrentImageDir": "Otvorte dialógové okno Uložiť ako v aktuálnom adresári obrázkov", + "_.MouseWheelEvent._ShiftAndScroll": "Podržte Shift a posúvajte", + "FrmSettings._UseSmoothZooming": "Použiť plynulé priblíženie", + "FrmSettings._Theme": "Motív", + "FrmSettings._ImageBoosterCacheMaxDimension": "Maximálny rozmer obrázka, ktorý sa má uložiť do vyrovnávacej pamäte (v pixeloch)", + "FrmMain.MnuScaleToHeight": "Prispôsobiť na výšku", + "_.Metadata._FileLastWriteTime": "Dátum úpravy", + "FrmSettings._Author": "Autor", + "FrmSettings._Others": "Iné", + "_.MouseWheelAction._PanVertically": "Posun Nahor / Nadol", + "FrmSettings._MouseWheelAction": "Akcia kolieska myši", + "FrmSettings.Nav._Tools": "Nástroje", + "FrmMain.MnuSetDesktopBackground._Error": "Nie je možné zobrazený obrázok, ako pozadie pracovnej plochy", + "FrmSettings.Toolbar._Errors._ButtonExecutableRequired": "Vyžaduje sa spúšťacie tlačidlo.", + "_.ImageOrderBy._DateAccessed": "Dátum prístupu", + "FrmSettings._ThumbnailSize": "Veľkosť miniatúry (v pixeloch)", + "FrmSettings._FileFormats": "Formáty súborov", + "FrmMain.MnuReloadImageList": "Znova načítať zoznam obrázkov", + "FrmSettings._UseWebview2ForSvg": "Použiť Webview2 na zobrazenie formátu SVG", + "FrmCrop.BtnCopy": "Kopírovať", + "FrmSettings._CurrentMonitorProfile._Description": "ImageGlass automaticky neaktualizuje farbu pri presúvaní okna medzi monitormi", + "FrmMain.PicMain._ErrorText": "Tento obrázok sa nepodarilo otvoriť", + "FrmSettings.Tools._AddNewTool": "Pridanie externého nástroja", + "FrmMain.MnuRename": "Premenovať obrázok…", + "FrmMain.MnuViewLastFrame": "Zobraziť poslednú snímku", + "_._Webview2._NotFound": "Prosím nainštalujte si najnovšiu verziu WebView2 Runtime.", + "FrmMain.MnuGetMoreTools": "Získajte ďalšie nástroje…", + "FrmSettings.Nav._Appearance": "Vzhľad", + "FrmSettings._SlideshowInterval": "Interval prezentácie:", + "_.ImageInterpolation._HighQualityBicubic": "Vysoká kvalita, bikubický", + "FrmColorPickerSettings.ChkShowHsvA": "Použitie formátu HSV s hodnotou alfa", + "FrmSettings.Tools._EditTool": "Upraviť externý nástroj", + "_._Error": "Chyba", + "FrmSettings._ImageBoosterCacheMaxFileSizeInMb": "Maximálna veľkosť súboru obrázka, ktorý sa má uložiť do vyrovnávacej pamäte (v megabajtoch)", + "_._UnhandledException._Description": "Došlo k neočakávanej chybe. Ak kliknete na Pokračovať, aplikácia bude túto chybu ignorovať a pokúsi sa pokračovať. Ak kliknete na tlačidlo Ukončiť, aplikácia sa okamžite ukončí.", + "_.Metadata._FileSize": "Veľkosť súboru", + "FrmSettings.Toolbar._ButtonJson": "Tlačidlo JSON", + "FrmQuickSetup._SetDefaultViewer._Description": "Môžete ho obnoviť v nastaveniach aplikácie > karta Asociácia typov súborov.", + "FrmSettings.Nav._Edit": "Upraviť", + "FrmMain.MnuToggleGallery": "Panel galérie", + "_._IgCommandExe._DefaultError._Description": "Uistite sa, že ste odovzdali správne príkazy!\r\nTento spustiteľný súbor obsahuje funkcie príkazového riadka pre softvér ImageGlass.\r\n\r\nAk chcete preskúmať všetky príkazové riadky, navštívte stránku:\n{0}", + "FrmMain.MnuLosslessCompression._Compressing": "Vykonávam bezstratovú kompresiu…", + "FrmSettings._ShouldGroupImagesByDirectory": "Zoskupte obrázky podľa adresára", + "FrmMain.MnuPanToRightSide": "Posunúť obrázok k pravému okraju", + "_.Metadata._ExifRatingPercent": "Hodnotenie", + "FrmSettings._PanSpeed": "Rýchlosť otáčania", + "_._CheckForUpdate": "Skontrolovať aktualizácie…", + "FrmSettings.Layout._ToolbarContext": "Kontextový panel nástrojov", + "_.ImageInfo._FrameCount": "{0} snímka(y)", + "FrmMain.MnuLayout": "Rozloženie", + "_._Website": "Webová stránka", + "FrmMain.MnuPasteImage": "Vložiť obrázok", + "FrmSettings._ShowGalleryScrollbars": "Zobraziť posuvníky galérie" + } +} \ No newline at end of file diff --git a/Setup/Assets/Language/Slovenian.iglang.json b/Setup/Assets/Language/Slovenian.iglang.json new file mode 100644 index 000000000..f3c834a92 --- /dev/null +++ b/Setup/Assets/Language/Slovenian.iglang.json @@ -0,0 +1,504 @@ +{ + "_Metadata": { + "Code": "sl-SI", + "EnglishName": "Slovenian", + "LocalName": "Slovenščina", + "Author": "Matevž Kristan", + "MinVersion": "9.1" + }, + "Items": { + "FrmCrop.SelectionAspectRatio._Original": "Izvirnik", + "FrmMain.MnuShare._Error": "Ni bilo mogoče odpreti pogovornega okna za skupno rabo.", + "_.Metadata._FileLastAccessTime": "Datum dostopa", + "FrmAbout._License": "Licenca programske opreme", + "FrmSettings.Toolbar._Errors._ButtonIdDuplicated": "Gumb z oznako '{0}' je že definiran. Prosimo izberite drugo in edinstveno oznako za svoj gumb, da se izognete sporom.", + "FrmMain.MnuSave._Confirm": "Ali ste prepričani, da želite prepisati to shranjeno sliko?", + "FrmSettings._OpenDefaultAppsSetting": "Odprite nastavitev privzetih aplikacij", + "FrmMain.MnuCopyPath": "Kopiraj pot slike", + "FrmCropSettings.DefaultSelectionType._SelectNone": "Nič ne izberite", + "_.MouseWheelAction._PanHorizontally": "Premikanje levo / desno", + "FrmMain.MnuPrint": "Natisni…", + "FrmSettings.Toolbar._ToolbarButtons": "Gumbi orodne vrstice", + "FrmResize.LblResample": "Resample:", + "_.ImageOrderBy._Extension": "Končnica", + "FrmSettings.Nav._Viewer": "Pregledovalnik", + "FrmSettings.EditAppDialog._EditApp": "Uredi aplikacijo", + "FrmCrop.BtnReset._Tooltip": "Ponastavi izbor", + "FrmMain.MnuRename._Description": "Vnesite novo ime datoteke:", + "_._No": "No", + "FrmSlideshow.MnuToggleCountdown": "Prikaži odštevanje predstavitve", + "FrmSettings._OpenStartupAppsSetting": "Open Startup apps setting", + "FrmMain.MnuViewPreviousFrame": "Prikaz prejšnjega okvirja", + "_.ImageOrderBy._DateModified": "Datum zadnje spremembe", + "FrmMain.MnuViewNextFrame": "Prikaz naslednjega okvirja", + "FrmMain.MnuUnload": "Razbremenite sliko", + "FrmSettings.Toolbar._HideToolbarInFullscreen": "Skrij orodno vrstico v celozaslonskem načinu", + "_.ImageOrderType._Desc": "Padajoče", + "_._Update": "Update", + "FrmSettings._EnableImageAsyncLoading": "Enable image asynchronous loading", + "FrmSettings._DefaultPhotoViewer._Description": "Register the supported formats of ImageGlass with Windows. You might need to open the Default apps settings and manually select ImageGlass from the list for it to take effect.", + "_.MouseWheelAction._BrowseImages": "Poglej naslednjo / prejšnjo sliko", + "FrmSettings._EditApps": "Aplikacije za urejanje slik", + "FrmColorPickerSettings.ChkShowCIELabA": "Uporabi format CIELAB z vrednostjo Alpha", + "_._GetHelp": "Pomoč", + "FrmQuickSetup._SkipQuickSetup": "Preskočite in zaženite ImageGlass", + "FrmColorPickerSettings._Title": "Nastavitve izbirnika barv", + "_._Copy": "Kopiraj", + "FrmSettings._ImageBoosterCacheCount": "Število slik v predpomnilniku ojačevalca slik (enosmerno)", + "FrmMain.MnuPanToBottom": "Pomakni sliko na dno", + "FrmMain.MnuZoom": "Povečava", + "FrmCropSettings.ChkCloseToolAfterSaving": "Po shranjevanju zaprite orodje za obrezovanje", + "FrmSettings._ShowWelcomeImage": "Prikaži pozdravno sliko", + "FrmSettings._ColorProfile": "Barvni profil", + "FrmSettings._Theme._UninstallTheme": "Odstranite tematski paket", + "FrmMain._OpenWith": "Odpri z {0}", + "FrmMain.MnuRemoveDefaultPhotoViewer": "Odstranite privzeti pregledovalnik fotografij", + "_.AfterEditAppAction._Nothing": "Ničesar", + "FrmCrop.BtnSave": "Shrani", + "FrmMain.MnuScaleToFit": "Prilagodi na merilo", + "FrmToolNotFound.LblDownloadToolText": "Več orodij za ImageGlass lahko prenesete na:", + "_._LearnMore": "Več o tem…", + "FrmCrop.LblAspectRatio": "Razmerje slike:", + "FrmExportFrames._FileNotExist": "Slikovna datoteka ne obstaja", + "FrmSettings._LightTheme": "Svetla", + "FrmSettings.Nav._Slideshow": "Predstavitev", + "_._Continue": "Nadaljuj", + "_._AddHotkey": "Dodaj bližnjico…", + "FrmMain.MnuSetDesktopBackground": "Nastavi ozadje Namizja", + "FrmMain.MnuReload": "Ponovno naloži sliko", + "FrmSlideshow.MnuExitSlideshow": "Zapri predstavitev", + "FrmMain.MnuAutoZoom": "Samodejna povečava", + "FrmSettings._ShowImagePreview": "Prikaži predogled slike, medtem ko se nalaga", + "FrmCrop.BtnCopy._Tooltip": "Kopirajte izbor v odložišče", + "FrmSettings.Nav._Toolbar": "Orodna vrstica", + "FrmMain.MnuSave._Error": "Slike ni bilo mogoče shraniti", + "FrmSettings._AfterEditingAction": "Po odprtju aplikacije za urejanje", + "FrmSettings._ShouldUseColorProfileForAll": "Uporabi tudi za slike brez vgrajenega barvnega profila", + "FrmCropSettings.DefaultSelectionType._UseTheLastSelection": "Uporabite zadnjo izbiro", + "FrmSettings._SlideshowInterval._From": "Od", + "FrmSettings._ImageInterpolation": "Interpolacija slike", + "FrmQuickSetup._StepInfo": "Korak {0}", + "FrmMain.MnuColorPicker": "Izbor barve", + "FrmCrop.SelectionAspectRatio._FreeRatio": "Prosto razmerje", + "FrmSettings._ResetSettings": "Reset settings", + "FrmSettings._Startup": "Zagon", + "_.BackdropStyle._None": "Brez", + "FrmSettings._LoadDefaultZoomLevels": "Naloži privzete stopnje povečave", + "FrmColorPicker.BtnSettings._Tooltip": "Odpri nastavitve izbirnika barv…", + "FrmSettings._UseThemeForDarkMode": "Uporabite to temo za temni način", + "FrmSettings._ShowDeleteConfirmation": "Prikaži potrditveno pogovorno okno pri brisanju datoteke", + "FrmSettings._ShowAppIcon": "Pokaži ikono aplikacije v naslovni vrstici", + "_._InvalidAction": "Invalid action", + "FrmQuickSetup._SelectProfile": "Izberite profil", + "_.Metadata._FileCreationTime": "Datum nastanka", + "FrmSettings._SlideshowImagesToNotifySound": "Število slik, ki sprožijo zvok obvestila", + "FrmSettings._BackgroundColor": "Barva ozadja pregledovalnika", + "FrmSettings._RealTimeFileUpdate": "Posodobitev datoteke v realnem času", + "_.ColorProfileOption._CurrentMonitorProfile": "Uporabi profil trenutnega zaslona", + "FrmSettings._EnableCutMultipleFiles": "Omogoči rezanje več datotek hkrati", + "FrmSettings._AutoUpdate": "Samodejno preverjaj posodobitev", + "FrmCropSettings.LblDefaultSelection": "Privzete nastavitve izbire", + "FrmSettings._UseThemeForLightMode": "Uporabite to temo za svetli način", + "FrmSettings._ZoomLevels": "Stopnje povečave", + "FrmMain.MnuSetLockScreen._Success": "Slika zaklenjenega zaslona je posodobljena", + "FrmSettings._ShowGalleryFileName": "Prikaži ime datoteke s sličicami", + "FrmSettings.Layout._Order": "Vrstni red", + "FrmCropSettings.ChkAutoCenterSelection": "Izbira samodejnega središča", + "FrmSettings.Nav._FileTypeAssociations": "Povezave z vrstami datotek", + "_._Back": "Nazaj", + "FrmMain.MnuSetDesktopBackground._Success": "Ozadje namizja je posodobljeno", + "FrmSettings._ShouldAutoOpenNewAddedImage": "Samodejno odprite novo dodano sliko", + "FrmCrop.SelectionAspectRatio._Custom": "Po meri…", + "FrmMain.MnuCopyPath._Success": "Kopirana trenutna pot slike.", + "FrmSettings._StartupBoost._Error": "Could not change Startup Boost setting", + "FrmToolNotFound.LblDescription": "ImageGlass ni mogel najti poti do izvedljive datoteke '{0}'. Če želite odpraviti to težavo, posodobite pot do '{0}'.", + "FrmMain.MnuClearClipboard": "Počisti odložišče", + "FrmSettings._ColorManagement": "Upravljanje barv", + "FrmMain._ReachedLastLast": "Dosežena zadnja slika", + "FrmMain.MnuPanUp": "Pomakni sliko gor", + "FrmMain.MnuRemoveDefaultPhotoViewer._Success": "ImageGlass ni več privzeti pregledovalnik fotografij.", + "FrmSettings._GetMoreLanguagePacks": "Dobi več jezikovnih paketov…", + "FrmAbout._Privacy": "Pravilnik o zasebnosti", + "FrmSettings._EnableRecursiveLoading": "Naloži slike v podmapah", + "_._UserAction._MethodArgumentNotSupported": "Vrsta argumenta metode '{0}' ni podprta", + "FrmSettings._FileExtensionIcons._Description": "Za prilagajanje ikon pripon datotek prenesite paket ikon, postavite vse datoteke .ICO v mapo z ikonami pripon in kliknite gumb {0}. S tem bo ImageGlass nastavljen tudi kot privzeti pregledovalnik fotografij.", + "_.ImageOrderType._Asc": "Naraščajoče", + "FrmExportFrames._Title": "Izvoz okvirjev slik", + "_._Install": "Namesti…", + "FrmMain.MnuFlipHorizontal": "Zasuči vodoravno", + "FrmSettings._OpenExtensionIconFolder": "Odpri mapo z ikonami pripon", + "FrmAbout._Collaborator": "Sodelavec:", + "FrmQuickSetup._ConfirmCloseProcess": "Pred uporabo novih nastavitev je nujno, da zaprete vse procese ImageGlass. Ste pripravljeni nadaljevati?", + "FrmExportFrames._ExportDone": "Uspešno izvoženih {0} okvirjev v\n{1}", + "FrmCrop.BtnSaveAs._Tooltip": "Shrani kot kopijo…", + "FrmMain.MnuOpenFile": "Odpri datoteko…", + "FrmColorPickerSettings.ChkShowRgbA": "Uporabi format RGB z vrednostjo Alpha", + "_.ImageInfo._ListCount": "Št. datotek: {0}", + "FrmMain.MnuGoToLast": "Pojdi na zadnjo sliko", + "FrmSettings._EditApps._AppName": "Ime aplikacije", + "FrmSettings._SlideshowBackgroundColor": "Barva ozadja diaprojekcije", + "FrmAbout._Email": "E-pošta:", + "_.MouseWheelAction._DoNothing": "Ne naredi ničesar", + "FrmMain.MnuSaveAs": "Shrani kot…", + "FrmMain._Loading": "Nalaganje…", + "_._Browse": "Prebrskaj…", + "FrmMain.MnuSetDefaultPhotoViewer._Error": "ImageGlass ni bilo mogoče nastaviti kot privzeti pregledovalnik fotografij.", + "FrmSettings.Nav._Language": "Jezik", + "FrmQuickSetup._SeeWhatNew": "Oglejte si, kaj je novega v tej različici…", + "FrmSettings._ImageInterpolation._ScaleUp": "Ko je povečava > 100%", + "FrmSettings.Layout._ToolbarContextPosition": "Položaj kontekstne orodne vrstice", + "FrmMain.MnuDeleteFromHardDisk": "Trajno izbriši", + "FrmSettings._EmbeddedThumbnail": "Vdelana sličica", + "FrmMain.MnuDeleteFromHardDisk._Description": "Ali ste prepričani, da želite trajno izbrisati to datoteko?", + "FrmMain.MnuScaleToFill": "Prilagodi na zapolnitev", + "FrmCrop.BtnCrop": "Obreži", + "_.AfterEditAppAction._Minimize": "Pomanjšaj", + "FrmMain.MnuInvertColors": "Invert colors", + "FrmSettings._StartupBoost": "Startup Boost", + "FrmMain.MnuViewFirstFrame": "Prikaz prvega okvirja", + "_.MouseWheelEvent._CtrlAndScroll": "Držite Ctrl in se pomikajte", + "FrmSettings._HideMainWindowInSlideshow": "Samodejno skrij glavno okno", + "_.Metadata._FrameCount": "Okvirji", + "FrmSettings._EnableCopyMultipleFiles": "Omogoči kopiranje več datotek hkrati", + "FrmMain.MnuFrameless._EnableDescription": "Za premikanje okna pridržite tipko Shift.", + "_.ImageOrderBy._ExifDateTaken": "EXIF: Date taken", + "FrmAbout._Credits": "Zasluge", + "FrmSettings._AddNewFileExtension": "Dodajte novo pripono datoteke", + "FrmMain.MnuQuickSetup": "Odprite hitro nastavitev za ImageGlass", + "FrmMain.MnuSave._Success": "Slika je shranjena", + "FrmMain.MnuPanLeft": "Pomakni sliko levo", + "FrmUpdate._StatusChecking": "Preverjanje za posodobitve…", + "FrmSettings.Nav._Layout": "Postavitev", + "FrmMain.MnuOpenWith": "Odpri z…", + "FrmAbout._Thanks": "Posebne zahvale:", + "_._Warning": "Opozorilo", + "FrmSettings.Nav._Keyboard": "Tipkovnica", + "FrmSlideshow._PauseSlideshow": "Predstavitev je začasno ustavljena.", + "_._Add+": "Dodaj…", + "_._Email": "E-pošta", + "FrmMain.MnuPanDown": "Pomakni sliko dol", + "_._Cancel": "Prekliči", + "_._OK": "Vredu", + "FrmMain.MnuPanRight": "Pomakni sliko desno", + "_.Position._Right": "Desno", + "_._Icon": "Ikona", + "FrmSettings._ShouldLoadHiddenImages": "Naloži skrite slike", + "_._InvalidAction._Transformation": "ImageGlass does not support rotation, flipping for this image.", + "FrmSettings._MakeDefault": "Nastavi za privzeto", + "FrmMain.MnuCopyImageData._Copying": "Kopiranje slikovnih podatkov. Nekaj časa bo trajalo…", + "FrmSettings._UseEmbeddedThumbnailRawFormats": "Naloži samo vdelano sličico za formate RAW", + "_.ImageInterpolation._Linear": "Linearno", + "FrmSettings._ImageInfoTags": "Oznake informacij o slikah", + "FrmSettings._FileExtensionIcons": "Ikone pripon datotek", + "FrmMain.MnuEdit._AppNotFound": "Ni bilo mogoče najti povezane aplikacije za urejanje. Aplikacijo za urejanje tega formata lahko dodelite v ImageGlass Nastavitve > Urejanje.", + "_.ColorProfileOption._None": "Brez", + "FrmSettings._TotalSupportedFormats": "Skupno število podprtih oblik: {0}", + "FrmSettings._Clipboard": "Odložišče", + "_._UserAction._Win32ExeError": "Ni mogoče izvesti ukaza '{0}'. Prepričajte se, da je ime pravilno.", + "FrmCropSettings.DefaultSelectionType._SelectX": "Izberite {0}", + "_.AfterEditAppAction._Close": "Zapri", + "FrmAbout._LogoDesigner": "Oblikovalec logotipa:", + "_.ImageOrderBy._Name": "Ime (privzeto)", + "FrmMain.MnuRemoveDefaultPhotoViewer._Error": "ImageGlass kot privzetega pregledovalnika fotografij ni bilo mogoče odstraniti.", + "FrmExportFrames._FolderPickerTitle": "Izberite izhodno mapo za izvoz slikovnih okvirjev", + "FrmAbout._Donate": "Donirajte", + "FrmMain.MnuFrameNav": "Krmarjenje po okvirjih", + "FrmMain.MnuSetLockScreen": "Nastavi kot zaklenjen zaslon", + "_._Delete": "Izbriši", + "FrmMain.MnuViewPrevious": "Prikaz prejšnje strani", + "_.Position._Top": "Zgoraj", + "FrmSettings.Toolbar._CurrentButtons": "Trenutni gumbi:", + "FrmMain.MnuAbout": "Vizitka", + "FrmSettings._RemoveDefault": "Odstrani privzeto", + "_._Description": "Opis", + "FrmMain.MnuPasteImage._Error": "V odložišču ni bilo mogoče najti slikovnih podatkov", + "FrmMain.MnuSettings": "Nastavitve", + "FrmCropSettings._Title": "Nastavitve obrezovanja", + "FrmSettings.Toolbar._ToolbarIconHeight": "Velikost orodne vrstice z ikonami", + "FrmSettings._SlideshowInterval._To": "Do", + "FrmSettings.Layout._ToolbarPosition": "Položaj orodne vrstice", + "FrmUpdate._StatusUpdated": "Uporabljate najnovejšo različico!", + "FrmMain.MnuExit": "Izhod", + "_._Webview2._Outdated": "Your WebView2 Runtime is not supported. Please update to version {0} or later.", + "_._Yes": "Da", + "FrmMain.MnuRotateLeft": "Obrni v levo", + "FrmSettings._EnableStartupBoost": "Enable Startup Boost", + "_.ImageOrderBy._ExifRating": "EXIF: Rating", + "FrmMain.MnuZoomIn": "Povečaj", + "_.Metadata._ColorSpace": "Barvni prostor", + "FrmAbout._Version": "Različica:", + "FrmMain.MnuToggleTopMost._Enable": "Omogočeno okno je vedno na vrhu", + "FrmSettings.Toolbar._AvailableButtons": "Razpoložljivi gumbi:", + "FrmMain.MnuSave._Saving": "Shranjevanje slike…", + "FrmQuickSetup._StandardUser": "Standardni uporabnik", + "FrmMain.MnuSetLockScreen._Error": "Ogledovane slike ni bilo mogoče nastaviti kot sliko zaklenjenega zaslona", + "FrmSettings.Nav._Image": "Slika", + "FrmSettings._Theme._InstallTheme": "Namestite tematske pakete", + "FrmSettings._EnableMultiInstances": "Dovoli več primerkov programa", + "FrmMain.MnuCropTool": "Obreži sliko", + "_._IgCommandExe._DefaultError._Heading": "Neveljavni ukazi", + "_._Refresh": "Osveži", + "FrmMain.MnuLosslessCompression._Description": "This tool uses Magick.NET library for lossless compression, optimizing file size. Overwrites only if the compressed file is smaller than the original.", + "_._MoveDown": "Premakni dol", + "FrmSettings._GetExtensionIconPacks": "Pridobite pakete ikon pripon…", + "FrmSettings._InAppMessageDuration": "Trajanje sporočila v aplikaciji (milisekunde)", + "FrmMain.MnuFrameless": "Brez okvirja", + "_._Reset": "Ponastavi", + "FrmSettings._ConfigDir": "Lokacija konfiguracije", + "FrmQuickSetup._SettingsWillBeApplied": "Uporabljene bodo nastavitve:", + "FrmSettings._UnmanagedSettingReminder": "This setting is not managed by ImageGlass. Don't forget to disable it before you remove or relocate the app because ImageGlass does not handle this automatically.", + "FrmMain.MnuClipboard": "Odložišče", + "FrmMain.MnuCustomZoom": "Povečava po meri…", + "FrmSettings._DisplayLanguage": "Jezik uporabniškega vmesnika", + "FrmMain.MnuPrint._Error": "Ogledovane slike ni bilo mogoče natisniti", + "FrmSettings._ShouldPreserveModifiedDate": "Pri shranjevanju ohrani datum spremembe slike", + "FrmSettings._ShowSaveOverrideConfirmation": "Pokaži potrditveno pogovorno okno pri zamenjavi datoteke", + "FrmColorPickerSettings.ChkShowHexA": "Uporabi format HEX z vrednostjo Alpha", + "FrmMain.MnuFullScreen": "Celozaslonski način", + "FrmSettings._StartupDir": "Lokacija zagona", + "FrmSettings._ShowCheckerboardOnlyImageRegion": "Prikaži šahovnico samo znotraj območja slike", + "FrmMain.MnuClearClipboard._Success": "Odložišče počiščeno.", + "FrmQuickSetup._Text": "Hitra namestitev za ImageGlass", + "FrmMain.MnuLosslessCompression._Done": "Done lossless compression.\r\nThe new file size is {0}, saved {1}.", + "FrmMain.MnuLosslessCompression": "Magick.NET Lossless Compression", + "FrmResize.RadResizeByPercentage": "Percentage", + "FrmSettings._StartupBoost._Disabled": "Startup Boost is disabled", + "FrmMain.MnuToggleCheckerboard": "Ozadje šahovnice", + "FrmSettings._MinEmbeddedThumbnailSize._Height": "Višina", + "FrmSettings.Nav._General": "Splošno", + "FrmSettings._ImageLoading": "Nalaganje slike", + "FrmSettings._ShowSlideshowCountdown": "Prikaži odštevanje predstavitve", + "FrmMain.MnuSave": "Shrani", + "FrmMain.MnuMoveToRecycleBin": "Premakni v koš", + "FrmMain.MnuRefresh": "Osveži", + "FrmToolNotFound.LblHeading": "'{0}' ni najden!", + "FrmMain.MnuReportIssue": "Prijavi težavo…", + "FrmMain.MnuCopyImageData": "Kopiraj podatke o sliki", + "FrmMain.MnuCheckForUpdate._NewVersion": "Na voljo je nova različica!", + "_._Empty": "(prazno)", + "FrmSettings._Zooming": "Povečava", + "FrmMain.MnuCutFile": "Izreži datoteko", + "FrmHotkeyPicker.LblHotkey": "Pritisnite hitre tipke", + "FrmSettings.Layout._Gallery": "Galerija", + "FrmMain.MnuNewWindow": "Odpri novo okno", + "FrmMain.MnuMoveToRecycleBin._Description": "Ali želite premakniti to datotek v koš?", + "FrmSettings._DefaultPhotoViewer": "Privzeti pregledovalnik fotografij", + "_.Metadata._ExifDateTimeOriginal": "EXIF: DateTimeOriginal", + "FrmMain.MnuRotateRight": "Obrni v desno", + "FrmSettings._MinEmbeddedThumbnailSize": "Najmanjša velikost vdelane sličice, ki se naloži", + "FrmMain.MnuSetDefaultPhotoViewer": "Nastavite privzeti pregledovalnik fotografij", + "FrmMain.MnuImageProperties": "Lastnosti slike", + "FrmSettings._EnableNavigationButtons": "Prikaži puščične gumbe za krmarjenje", + "_._Edit": "Uredi", + "FrmSettings._ImageBooster": "Ojačevalec slike", + "FrmSettings.Tools._IntegratedWith": "Integrirano z {0}", + "_._Next": "Naprej", + "FrmExportFrames._OpenOutputFolder": "Odpri izhodno mapo", + "FrmMain.MnuOpenLocation": "Odpri mesto slike", + "FrmMain.MnuLockZoom": "Zakleni razmerje", + "FrmSettings._StartupBoost._Description": "Preload and run ImageGlass in the background for a few seconds during Windows startup to accelerate the first launch.", + "FrmSettings._WindowBackdrop": "Ozadje za okna", + "FrmSettings._EnableRealTimeFileUpdate": "Spremljajte spremembe datotek v mapi za ogled in posodabljajte v realnem času", + "_._NotSupported": "Nepodprt format", + "FrmSettings._Theme._GetMoreThemes": "Pridobite več tematskih paketov…", + "FrmMain.MnuNewWindow._Error": "Ni mogoče odpreti novega okna, ker je dovoljeno le eno okno", + "FrmMain.MnuZoomOut": "Pomanjšaj", + "FrmSettings.Toolbar._EditButton": "Gumb za urejanje orodne vrstice", + "FrmMain.MnuCustomZoom._Description": "Vnesite novo vrednost povečave", + "FrmResize.RadResizeByPixels": "Pixels", + "FrmMain.MnuEdit": "Uredi sliko {0}…", + "FrmSettings.Layout._GalleryPosition": "Položaj galerije", + "FrmMain.MnuWindowFit": "Prilagodi na okno", + "FrmMain._OpenFileDialog": "Vse podprte datoteke", + "FrmSettings._UseRandomIntervalForSlideshow": "Uporabi naključni interval", + "_.Position._Left": "Levo", + "FrmSettings._ShouldOpenLastSeenImage": "Odprite zadnjo ogledovano sliko", + "_.Position._Bottom": "Spodaj", + "FrmResize.ChkKeepRatio": "Keep ratio propotional", + "FrmMain.MnuGoTo": "Pojdi na…", + "FrmSlideshow.MnuPauseResumeSlideshow": "Zaustavitev / nadaljevanje diaprojekcije", + "FrmSettings.Tools._Integrated": "Integrirano", + "FrmSettings._Contributors": "Sodelujoči", + "_.MouseWheelAction._Zoom": "Povečajte / pomanjšajte", + "_._CommandPreview": "Predogled ukaza", + "FrmSettings._DarkTheme": "Temna", + "_._Hotkeys": "Bližnjice", + "_.Metadata._ExifDateTime": "EXIF: DateTime", + "FrmSettings.Toolbar._Errors._ButtonIdRequired": "Potreben je oznaka gumba.", + "FrmSettings._MinEmbeddedThumbnailSize._Width": "Širina", + "_._Executable": "Izvršljiva datoteka", + "_.ImageInterpolation._MultiSampleLinear": "Več-vzorčno linearno", + "_._Separator": "Ločilo", + "FrmQuickSetup._ProfessionalUser": "Profesionalni uporabnik", + "FrmMain.MnuFlipVertical": "Zasuči navpično", + "FrmSlideshow._ResumeSlideshow": "Predstavitev je nadaljevana.", + "FrmCropSettings.DefaultSelectionType._CustomArea": "Območje po meri…", + "FrmMain.MnuActualSize": "Dejanska velikost", + "FrmCrop.BtnSaveAs": "Shrani kot…", + "FrmSettings._InstallNewLanguagePack": "Namestite nov jezikovni paket…", + "FrmSlideshow.MnuZoomModes": "Načini povečave", + "FrmMain.MnuTools": "Orodja", + "_.ImageInterpolation._Cubic": "Kockasto", + "FrmUpdate._LatestVersion": "Zadnja različica je: {0}", + "FrmMain.MnuViewNext": "Prikaz naslednje slike", + "_.MouseWheelEvent._AltAndScroll": "Držite Alt in se pomikajte", + "FrmToolNotFound._Title": "Orodja ni bilo mogoče najti", + "FrmCrop.BtnCrop._Tooltip": "Obrežite samo sliko", + "FrmSettings.EditAppDialog._AddApp": "Dodajte aplikacijo za urejanje", + "FrmMain.MnuPanning": "Premikanje", + "_._MoveUp": "Premakni gor", + "FrmCropSettings.DefaultSelectionType._SelectAll": "Izberite vse", + "_._Name": "Ime", + "FrmColorPickerSettings.ChkShowHslA": "Uporabi format HSL z vrednostjo Alpha", + "FrmMain.MnuToggleImageAnimation": "Začni / ustavi animiranje slike", + "FrmSettings._DisableStartupBoost": "Disable Startup Boost", + "FrmMain.MnuCopyFile._Success": "Kopiranih {0} datotek.", + "FrmMain.MnuSave._ConfirmDescription": "ImageGlass ni profesionalni urejevalnik fotografij, zato bodite pozorni na izgubo kakovosti, metapodatkov, slojev... pri shranjevanju vaše slike.", + "FrmToolNotFound.BtnSelectExecutable": "Izberite…", + "FrmUpdate._StatusOutdated": "Na voljo je nova posodobitev!", + "_.ImageOrderBy._Random": "Nakjučno", + "FrmResize.LblCurrentSize": "Current Size:", + "_._Apply": "Uporabi", + "FrmAbout._Slogan": "Lahek, vsestranski pregledovalnik slik", + "FrmMain.MnuPanToTop": "Pomakni sliko na vrh", + "FrmSettings.Toolbar._AddNewButton": "Dodajte gumb orodne vrstice po meri", + "FrmCrop.LblSize": "Velikost:", + "FrmSettings._ImageInterpolation._ScaleDown": "Ko je povečava < 100%", + "_._CreatingFileError": "Ni bilo mogoče ustvariti začasne slikovne datoteke", + "FrmMain.MnuGoTo._Description": "Vnesite indeks slike za ogled in nato pritisnite ENTER na tipkovnici", + "FrmSettings.Toolbar._EnableCenterToolbar": "Za orodno vrstico uporabite sredinsko poravnavo", + "FrmMain.MnuResizeTool": "Resize image", + "FrmSettings.Layout._Toolbar": "Orodna vrstica", + "FrmMain.MnuHelp": "Pomoč", + "_.ImageOrderBy._FileSize": "Velikost datoteke", + "FrmSettings._Theme._OpenThemeFolder": "Odpri mapo teme", + "FrmMain.MnuNavigation": "Krmarjenje", + "_._Save": "Shrani", + "FrmQuickSetup._SettingProfileDescription": "Če želite spremeniti te nastavitve, preprosto odprite nastavitve aplikacije.", + "_._UserAction._MenuNotFound": "Ni mogoče najti menija '{0}' za priklic dejanja", + "FrmMain.MnuPanToLeftSide": "Pomakni sliko na levo stran", + "FrmUpdate._CurrentVersion": "Trenutna verzija: {0}", + "FrmCrop.BtnSettings._Tooltip": "Odprite nastavitve orodja za obrezovanje", + "_.ColorProfileOption._Custom": "Po meri…", + "FrmSettings._UseEmbeddedThumbnailOtherFormats": "Naloži samo vdelano sličico za ostale formate", + "FrmMain.MnuGoToFirst": "Pojdi na prvo sliko", + "FrmSettings._ExportLanguagePack": "Izvozi jezikovni paket…", + "FrmSettings.Nav._Mouse": "Miška", + "_.ImageOrderBy._DateCreated": "Datum nastanka", + "FrmSettings._EnableFullscreenSlideshow": "Začni diaprojekcijo v celozaslonskem načinu", + "FrmAbout._Homepage": "Spletna stran:", + "FrmSettings._GalleryCacheSizeInMb": "Največja velikost predpomnilnika galerije (v megabajtih)", + "FrmMain.MnuCopyImageData._Success": "Kopirani trenutni slikovni podatki.", + "FrmSettings._EnableLoopBackNavigation": "Po doseženem koncu seznama, predvajaj predstavitev od začetka", + "_.MouseWheelEvent._Scroll": "Pomikanje", + "FrmCrop.BtnSave._Tooltip": "Shrani sliko", + "FrmMain.MnuSlideshow": "Predstavitev", + "FrmMain.MnuShare": "Deli…", + "FrmSettings._SlideshowNotification": "Obvestila o diaprojekciji", + "FrmMain.MnuViewChannels": "Prikaz kanalov", + "FrmSettings._Refresh": "Osveži", + "_._UserAction._MethodNotFound": "Ni mogoče najti metode '{0}' za priklic dejanja", + "FrmMain.MnuCopyFile": "Kopiraj datoteko", + "_._CreatingFile": "Ustvarjanje začasne slikovne datoteke…", + "FrmMain.MnuToggleTopMost": "Obdrži okno vedno na vrhu", + "FrmMain.MnuLosslessCompression._Confirm": "Are you sure you want to proceed?", + "FrmMain.MnuImage": "Slika", + "FrmSettings._StartupBoost._Enabled": "Startup Boost is enabled", + "FrmQuickSetup._SetDefaultViewer": "Ali želite nastaviti ImageGlass kot privzeti pregledovalnik fotografij?", + "FrmMain.MnuScaleToWidth": "Prilagodi na širino", + "_._FileExtension": "Končnica datoteke", + "FrmUpdate._PublishedDate": "Datum objave: {0}", + "_._DoNotShowThisMessageAgain": "Tega sporočila ne prikaži več", + "_.ImageInterpolation._NearestNeighbor": "Najbližji sosed", + "FrmCrop.LblLocation": "Lokacija:", + "_._Download": "Prenos", + "_.Metadata._ColorProfile": "Barvni profil", + "FrmSettings._CenterWindowFit": "Samodejno centriraj okno v načinu 'Prilagodi na okno'", + "FrmSettings._ImageLoadingOrder": "Zaporedje nalaganja slike", + "FrmSettings._GalleryColumns": "Število stolpcev s sličicami v navpični postavitvi galerije", + "_._Quit": "Izhod", + "_._Add": "Dodaj", + "FrmMain.MnuChangeBackgroundColor": "Spremeni barvo ozadja…", + "FrmMain.MnuToggleToolbar": "Orodna vrstica", + "FrmAbout._Contact": "Stik", + "FrmSettings.Toolbar._AddCustomButton": "Dodajte gumb po meri…", + "FrmCrop.BtnQuickSelect._Tooltip": "Hitra izbira…", + "FrmMain.MnuCutFile._Success": "Izrezanih {0} datotek.", + "FrmSettings._ZoomSpeed": "Hitrost povečave", + "FrmMain.MnuToggleTopMost._Disable": "Onemogočeno okno je vedno na vrhu", + "FrmSettings._ShouldUseExplorerSortOrder": "Use Explorer sort order if possible", + "_.ImageInterpolation._Antisotropic": "Antizotropno", + "FrmMain._ReachedFirstImage": "Dosežena prva slika", + "_._UnhandledException": "Neobravnavana izjema", + "FrmResize.LblNewSize": "New Size:", + "FrmMain._ClipboardImage": "Slika iz odložišča", + "FrmMain.MnuExportFrames": "Izvoz okvirjev slik…", + "FrmMain.MnuFile": "Datoteka", + "_._Close": "Zapri", + "FrmMain.MnuMain": "Glavni meni", + "_._ResetToDefault": "Ponastavi na privzeto", + "FrmSettings.Nav._Gallery": "Galerija", + "FrmMain.MnuSetDefaultPhotoViewer._Success": "ImageGlass ste uspešno nastavili kot privzeti pregledovalnik fotografij.", + "FrmSettings._HideGalleryInFullscreen": "Skrij galerijo v celozaslonskem načinu", + "FrmSettings._AvailableImageInfoTags": "Razpoložljive oznake:", + "FrmExportFrames._Exporting": "Izvažanje {0}/{1} okvirjev\n{2}…", + "_._Argument": "Argument", + "FrmSettings._ImageEditQuality": "Kakovost slike", + "_._ID": "ID", + "FrmSettings._UserConfigFile": "Datoteka z uporabniškimi nastavitvami (igconfig.json)", + "FrmMain.MnuLoadingOrders": "Vrstni red nalaganja", + "FrmSettings._OpenSaveAsDialogInTheCurrentImageDir": "Open the Save As dialog in the current image directory", + "_.MouseWheelEvent._ShiftAndScroll": "Držite Shift in se pomikajte", + "FrmSettings._UseSmoothZooming": "Uporabite gladko povečavo", + "FrmSettings._Theme": "Tema", + "FrmSettings._ImageBoosterCacheMaxDimension": "Največja dimenzija slike za predpomnilnik (v slikovnih pikah)", + "FrmMain.MnuScaleToHeight": "Prilagodi na višino", + "_.Metadata._FileLastWriteTime": "Datum zadnje spremembe", + "FrmSettings._Author": "Avtor", + "FrmSettings._Others": "Drugo", + "_.MouseWheelAction._PanVertically": "Premikanje navzgor / navzdol", + "FrmSettings._MouseWheelAction": "Delovanje kolesca miške", + "FrmSettings.Nav._Tools": "Orodja", + "FrmMain.MnuSetDesktopBackground._Error": "Ogledovane slike ni bilo mogoče nastaviti kot ozadje namizja", + "FrmSettings.Toolbar._Errors._ButtonExecutableRequired": "Potrebna je izvedljiva datoteka gumba.", + "_.ImageOrderBy._DateAccessed": "Datum dostopa", + "FrmSettings._ThumbnailSize": "Velikost sličice (v slikovnih pikah)", + "FrmSettings._FileFormats": "Oblike zapisa datoteke", + "FrmMain.MnuReloadImageList": "Ponovno naloži seznam slik", + "FrmSettings._UseWebview2ForSvg": "Uporabite Webview2 za ogled formata SVG", + "FrmCrop.BtnCopy": "Kopiraj", + "FrmSettings._CurrentMonitorProfile._Description": "ImageGlass ne posodobi barv samodejno, ko okno premikate med zasloni", + "FrmMain.PicMain._ErrorText": "Te slike ni bilo mogoče odpreti", + "FrmSettings.Tools._AddNewTool": "Dodajte zunanje orodje", + "FrmMain.MnuRename": "Preimenuj sliko…", + "FrmMain.MnuViewLastFrame": "Prikaz zadnjega okvirja", + "_._Webview2._NotFound": "Please install WebView2 Runtime to access full features of ImageGlass.", + "FrmMain.MnuGetMoreTools": "Pridobite več orodij…", + "FrmSettings.Nav._Appearance": "Videz", + "FrmSettings._SlideshowInterval": "Interval predstavitve:", + "_.ImageInterpolation._HighQualityBicubic": "Visoko kakovostno, dvokubično", + "FrmColorPickerSettings.ChkShowHsvA": "Uporabi format HSV z vrednostjo Alpha", + "FrmSettings.Tools._EditTool": "Uredi zunanje orodje", + "_._Error": "Napaka", + "FrmSettings._ImageBoosterCacheMaxFileSizeInMb": "Največja velikost slikovne datoteke za predpomnilnik (v megabajtih)", + "_._UnhandledException._Description": "Prišlo je do neobravnavane izjeme. Če kliknete Nadaljuj, bo aplikacija prezrla to napako in poskušala nadaljevati. Če kliknete Izhod, se aplikacija takoj zapre.", + "_.Metadata._FileSize": "Velikost datoteke", + "FrmSettings.Toolbar._ButtonJson": "Gumb JSON", + "FrmQuickSetup._SetDefaultViewer._Description": "Ponastavite ga lahko v nastavitvah aplikacije > zavihek Povezave vrst datotek.", + "FrmSettings.Nav._Edit": "Uredi", + "FrmMain.MnuToggleGallery": "Galerija", + "_._IgCommandExe._DefaultError._Description": "Prepričajte se, da podajate pravilne ukaze!\r\nTa izvršljiva datoteka vsebuje funkcije ukazne vrstice za programsko opremo ImageGlass.\r\n\r\nČe želite raziskati vse ukazne vrstice, obiščite:\n{0}", + "FrmMain.MnuLosslessCompression._Compressing": "Performing lossless compression…", + "FrmSettings._ShouldGroupImagesByDirectory": "Združi slike po mapah", + "FrmMain.MnuPanToRightSide": "Pomakni sliko na desno stran", + "_.Metadata._ExifRatingPercent": "Ocena", + "FrmSettings._PanSpeed": "Hitrost premikanja", + "_._CheckForUpdate": "Preveri obstoj posodobitev…", + "FrmSettings.Layout._ToolbarContext": "Kontekstna orodna vrstica", + "_.ImageInfo._FrameCount": "Št. okvirjev: {0}", + "FrmMain.MnuLayout": "Postavitev", + "_._Website": "Spletna stran", + "FrmMain.MnuPasteImage": "Prilepi sliko", + "FrmSettings._ShowGalleryScrollbars": "Prikaži drsnike galerije" + } +} \ No newline at end of file diff --git a/Setup/Assets/Language/Spanish.iglang.json b/Setup/Assets/Language/Spanish.iglang.json new file mode 100644 index 000000000..ca3ce4365 --- /dev/null +++ b/Setup/Assets/Language/Spanish.iglang.json @@ -0,0 +1,504 @@ +{ + "_Metadata": { + "Code": "es-ES", + "EnglishName": "Spanish", + "LocalName": "Español", + "Author": "EnzoEmb & Miguel (anemkoe@gmail. com)", + "MinVersion": "9.1" + }, + "Items": { + "FrmCrop.SelectionAspectRatio._Original": "Original", + "FrmMain.MnuShare._Error": "No se pudo abrir el cuadro de diálogo Compartir.", + "_.Metadata._FileLastAccessTime": "Fecha de acceso", + "FrmAbout._License": "Licencia de software", + "FrmSettings.Toolbar._Errors._ButtonIdDuplicated": "Ya se ha definido un botón con el ID '{0}'. Por favor, elija un ID diferente y único para su botón para evitar conflictos.", + "FrmMain.MnuSave._Confirm": "¿Seguro que deseas sobreescribir esta imagen?", + "FrmSettings._OpenDefaultAppsSetting": "Abrir ajustes del sistema de programas predeterminados", + "FrmMain.MnuCopyPath": "Copiar ruta de la imágen", + "FrmCropSettings.DefaultSelectionType._SelectNone": "No seleccionar nada", + "_.MouseWheelAction._PanHorizontally": "Desplazar a la izquierda / derecha", + "FrmMain.MnuPrint": "Imprimir…", + "FrmSettings.Toolbar._ToolbarButtons": "Botones de la barra de herramientas", + "FrmResize.LblResample": "Remuestrear:", + "_.ImageOrderBy._Extension": "Extensión", + "FrmSettings.Nav._Viewer": "Visor", + "FrmSettings.EditAppDialog._EditApp": "Editar aplicación", + "FrmCrop.BtnReset._Tooltip": "Restablecer selección", + "FrmMain.MnuRename._Description": "Ingrese un nuevo nombre de archivo:", + "_._No": "No", + "FrmSlideshow.MnuToggleCountdown": "Mostrar cuenta de diapositivas", + "FrmSettings._OpenStartupAppsSetting": "Abrir ajustes de aplicaciones al inicio", + "FrmMain.MnuViewPreviousFrame": "Ver fotograma anterior", + "_.ImageOrderBy._DateModified": "Fecha de modificación", + "FrmMain.MnuViewNextFrame": "Ver siguiente fotograma", + "FrmMain.MnuUnload": "No cargar imagen", + "FrmSettings.Toolbar._HideToolbarInFullscreen": "Ocultar barra de herramientas en modo de pantalla completa", + "_.ImageOrderType._Desc": "Descendente", + "_._Update": "Actualización", + "FrmSettings._EnableImageAsyncLoading": "Habilitar la carga asincrónica de imágenes", + "FrmSettings._DefaultPhotoViewer._Description": "Registrar los formatos compatibles de ImageGlass con Windows. Puede que necesite abrir la configuración de aplicaciones predeterminadas y seleccionar manualmente ImageGlass en la lista para que surta efecto.", + "_.MouseWheelAction._BrowseImages": "Ver imagen siguiente / anterior", + "FrmSettings._EditApps": "Aplicaciones de edición de imágenes", + "FrmColorPickerSettings.ChkShowCIELabA": "Usar el formato CIELAB con valor alfa", + "_._GetHelp": "Obtener ayuda", + "FrmQuickSetup._SkipQuickSetup": "Saltar esto e iniciar ImageGlass", + "FrmColorPickerSettings._Title": "Configuración del selector de colores", + "_._Copy": "Copiar", + "FrmSettings._ImageBoosterCacheCount": "Número de imágenes almacenadas en caché por Acelerador de Imagen (una dirección)", + "FrmMain.MnuPanToBottom": "Desplazar imagen a la parte inferior", + "FrmMain.MnuZoom": "Zoom", + "FrmCropSettings.ChkCloseToolAfterSaving": "Cerrar herramienta Recortar tras guardar", + "FrmSettings._ShowWelcomeImage": "Mostrar imagen de bienvenida", + "FrmSettings._ColorProfile": "Perfil de color", + "FrmSettings._Theme._UninstallTheme": "Desinstalar un paquete de temas", + "FrmMain._OpenWith": "Abrir con {0}", + "FrmMain.MnuRemoveDefaultPhotoViewer": "Eliminar programa como visor de fotos por defecto", + "_.AfterEditAppAction._Nothing": "Nada", + "FrmCrop.BtnSave": "Guardar", + "FrmMain.MnuScaleToFit": "Escalar para ajustar", + "FrmToolNotFound.LblDownloadToolText": "Puede descargar más herramientas para ImageGlass en:", + "_._LearnMore": "Más información…", + "FrmCrop.LblAspectRatio": "Relación de aspecto:", + "FrmExportFrames._FileNotExist": "El archivo de imagen no existe", + "FrmSettings._LightTheme": "Claro", + "FrmSettings.Nav._Slideshow": "Presentación", + "_._Continue": "Continuar", + "_._AddHotkey": "Añadir atajo de teclado…", + "FrmMain.MnuSetDesktopBackground": "Establecer como fondo de escritorio", + "FrmMain.MnuReload": "Volver a cargar la imagen", + "FrmSlideshow.MnuExitSlideshow": "Terminar presentación", + "FrmMain.MnuAutoZoom": "Zoom automático", + "FrmSettings._ShowImagePreview": "Mostrar vista previa de la imagen mientras está siendo cargada", + "FrmCrop.BtnCopy._Tooltip": "Copiar selección en el portapapeles", + "FrmSettings.Nav._Toolbar": "Barra de herramientas", + "FrmMain.MnuSave._Error": "No se ha podido guardar la imagen", + "FrmSettings._AfterEditingAction": "Después de abrir la app de edición", + "FrmSettings._ShouldUseColorProfileForAll": "Aplicar también a imágenes sin perfil de colores incrustado", + "FrmCropSettings.DefaultSelectionType._UseTheLastSelection": "Utilizar última selección", + "FrmSettings._SlideshowInterval._From": "Desde", + "FrmSettings._ImageInterpolation": "Interpolación de imagen", + "FrmQuickSetup._StepInfo": "Paso {0}", + "FrmMain.MnuColorPicker": "Selector de color", + "FrmCrop.SelectionAspectRatio._FreeRatio": "Relación libre", + "FrmSettings._ResetSettings": "Reiniciar ajustes", + "FrmSettings._Startup": "Inicialización", + "_.BackdropStyle._None": "Ninguno", + "FrmSettings._LoadDefaultZoomLevels": "Cargar niveles de zoom por defecto", + "FrmColorPicker.BtnSettings._Tooltip": "Abrir configuración del selector de colores…", + "FrmSettings._UseThemeForDarkMode": "Usar este tema para modo oscuro", + "FrmSettings._ShowDeleteConfirmation": "Mostrar diálogo de confirmación al eliminar un archivo", + "FrmSettings._ShowAppIcon": "Mostrar icono de aplicación en la barra de título", + "_._InvalidAction": "Acción no válida", + "FrmQuickSetup._SelectProfile": "Selecciona un perfil", + "_.Metadata._FileCreationTime": "Fecha de creación", + "FrmSettings._SlideshowImagesToNotifySound": "Número de imágenes para reproducir un sonido de notificación", + "FrmSettings._BackgroundColor": "Color de fondo del visor", + "FrmSettings._RealTimeFileUpdate": "Actualización de archivos en tiempo real", + "_.ColorProfileOption._CurrentMonitorProfile": "Perfil actual del monitor", + "FrmSettings._EnableCutMultipleFiles": "Habilitar el corte de varios archivos a la vez", + "FrmSettings._AutoUpdate": "Buscar actualizaciones automáticamente", + "FrmCropSettings.LblDefaultSelection": "Configuración de selección predeterminada", + "FrmSettings._UseThemeForLightMode": "Usar este tema para el modo claro", + "FrmSettings._ZoomLevels": "Niveles de Zoom", + "FrmMain.MnuSetLockScreen._Success": "Imagen de pantalla de bloqueo actualizada", + "FrmSettings._ShowGalleryFileName": "Mostrar nombre de archivo de miniatura", + "FrmSettings.Layout._Order": "Orden", + "FrmCropSettings.ChkAutoCenterSelection": "Centrar selección automáticamente", + "FrmSettings.Nav._FileTypeAssociations": "Asociaciones de tipo de archivo", + "_._Back": "Atrás", + "FrmMain.MnuSetDesktopBackground._Success": "Fondo de escritorio actualizado", + "FrmSettings._ShouldAutoOpenNewAddedImage": "Abrir automáticamente la nueva imagen añadida", + "FrmCrop.SelectionAspectRatio._Custom": "Personalizado…", + "FrmMain.MnuCopyPath._Success": "Se copió la ruta de la imagen actual.", + "FrmSettings._StartupBoost._Error": "No se pudo cambiar la configuración de inicio acelerado", + "FrmToolNotFound.LblDescription": "ImageGlass no pudo encontrar la ruta al ejecutable «{0}». Para resolver este problema, actualice la ruta a «{0}» según sea necesario.", + "FrmMain.MnuClearClipboard": "Limpiar portapapeles", + "FrmSettings._ColorManagement": "Gestión de colores", + "FrmMain._ReachedLastLast": "Se alcanzó la última imagen", + "FrmMain.MnuPanUp": "Desplazar imagen hacia arriba", + "FrmMain.MnuRemoveDefaultPhotoViewer._Success": "ImageGlass ya no es el visor de fotos predeterminado.", + "FrmSettings._GetMoreLanguagePacks": "Obtener más paquetes de idioma…", + "FrmAbout._Privacy": "Política de privacidad", + "FrmSettings._EnableRecursiveLoading": "Cargar imágenes de subcarpetas", + "_._UserAction._MethodArgumentNotSupported": "No se admite el tipo de argumento del método «{0}»", + "FrmSettings._FileExtensionIcons._Description": "Para personalizar los íconos de extensión de archivos, descargue un paquete de íconos, coloque todos los archivos .ICO en la carpeta de íconos de extensión y haga clic en el botón '{0}'. Esto también establecerá ImageGlass como visor de fotos por defecto.", + "_.ImageOrderType._Asc": "Ascendente", + "FrmExportFrames._Title": "Exportar fotogramas de imagen", + "_._Install": "Instalar…", + "FrmMain.MnuFlipHorizontal": "Voltear horizontalmente", + "FrmSettings._OpenExtensionIconFolder": "Abrir carpeta de iconos de extensión", + "FrmAbout._Collaborator": "Colaborador:", + "FrmQuickSetup._ConfirmCloseProcess": "Antes de aplicar los nuevos ajustes, es esencial cerrar todos los procesos de ImageGlass. ¿Estás listo para continuar?", + "FrmExportFrames._ExportDone": "Se exportaron {0} fotogramas correctamente a \n{1}", + "FrmCrop.BtnSaveAs._Tooltip": "Guardar como copia…", + "FrmMain.MnuOpenFile": "Abrir archivo…", + "FrmColorPickerSettings.ChkShowRgbA": "Usar el formato RGB con valor alfa", + "_.ImageInfo._ListCount": "{0} archivo(s)", + "FrmMain.MnuGoToLast": "Ir a la última imagen", + "FrmSettings._EditApps._AppName": "Nombre de la aplicación", + "FrmSettings._SlideshowBackgroundColor": "Color de fondo de diapositivas", + "FrmAbout._Email": "Correo electrónico:", + "_.MouseWheelAction._DoNothing": "No hacer nada", + "FrmMain.MnuSaveAs": "Guardar como…", + "FrmMain._Loading": "Cargando…", + "_._Browse": "Navegar…", + "FrmMain.MnuSetDefaultPhotoViewer._Error": "No se pudo establecer ImageGlass como visor de fotos por defecto.", + "FrmSettings.Nav._Language": "Idioma", + "FrmQuickSetup._SeeWhatNew": "Ver qué hay de nuevo en esta versión…", + "FrmSettings._ImageInterpolation._ScaleUp": "Cuando el zoom > 100%", + "FrmSettings.Layout._ToolbarContextPosition": "Posición de la barra de herramientas contextual", + "FrmMain.MnuDeleteFromHardDisk": "Eliminar permanentemente", + "FrmSettings._EmbeddedThumbnail": "Miniaturas incrustadas", + "FrmMain.MnuDeleteFromHardDisk._Description": "¿Está seguro que desea eliminar permanentemente este archivo?", + "FrmMain.MnuScaleToFill": "Escalar para rellenar", + "FrmCrop.BtnCrop": "Recortar", + "_.AfterEditAppAction._Minimize": "Minimizar", + "FrmMain.MnuInvertColors": "Invertir colores", + "FrmSettings._StartupBoost": "Inicio acelerado", + "FrmMain.MnuViewFirstFrame": "Ver el primer fotograma", + "_.MouseWheelEvent._CtrlAndScroll": "Presionar Ctrl y desplazarse", + "FrmSettings._HideMainWindowInSlideshow": "Ocultar automáticamente la ventana principal", + "_.Metadata._FrameCount": "Fotogramas", + "FrmSettings._EnableCopyMultipleFiles": "Habilitar la copia de varios archivos a la vez", + "FrmMain.MnuFrameless._EnableDescription": "Mantenga pulsada la tecla Shift para mover la ventana.", + "_.ImageOrderBy._ExifDateTaken": "EXIF: fecha de captura", + "FrmAbout._Credits": "Créditos", + "FrmSettings._AddNewFileExtension": "Añadir nueva extensión de archivo", + "FrmMain.MnuQuickSetup": "Abrir configuración rápida de ImageGlass", + "FrmMain.MnuSave._Success": "Imagen guardada", + "FrmMain.MnuPanLeft": "Desplazar imagen hacia izquierda", + "FrmUpdate._StatusChecking": "Verificando actualizaciones…", + "FrmSettings.Nav._Layout": "Apariencia", + "FrmMain.MnuOpenWith": "Abrir con…", + "FrmAbout._Thanks": "Agradecimientos especiales a:", + "_._Warning": "Atención", + "FrmSettings.Nav._Keyboard": "Teclado", + "FrmSlideshow._PauseSlideshow": "Diapositivas en pausa.", + "_._Add+": "Añadir…", + "_._Email": "Correo electrónico", + "FrmMain.MnuPanDown": "Desplazar imagen hacia abajo", + "_._Cancel": "Cancelar", + "_._OK": "Aceptar", + "FrmMain.MnuPanRight": "Desplazar imagen hacia la derecha", + "_.Position._Right": "Derecha", + "_._Icon": "Icono", + "FrmSettings._ShouldLoadHiddenImages": "Cargar imágenes ocultas", + "_._InvalidAction._Transformation": "ImageGlass no admite ni la rotación ni el volteado de esta imagen.", + "FrmSettings._MakeDefault": "Establecer como predeterminado", + "FrmMain.MnuCopyImageData._Copying": "Copiando los datos de la imagen. Va a tomar un tiempo…", + "FrmSettings._UseEmbeddedThumbnailRawFormats": "Cargar sólo la miniatura incrustada para formatos RAW", + "_.ImageInterpolation._Linear": "Lineal", + "FrmSettings._ImageInfoTags": "Etiquetas de información de imagen", + "FrmSettings._FileExtensionIcons": "Iconos de extensión de archivo", + "FrmMain.MnuEdit._AppNotFound": "No se pudo encontrar la aplicación asociada para editar. Puede asignar una aplicación para editar este formato en Configuración de ImageGlass > Editar.", + "_.ColorProfileOption._None": "Ninguno", + "FrmSettings._TotalSupportedFormats": "Total de formatos soportados: {0}", + "FrmSettings._Clipboard": "Portapapeles", + "_._UserAction._Win32ExeError": "No se puede ejecutar la orden «{0}». Cerciórese de que el nombre sea correcto.", + "FrmCropSettings.DefaultSelectionType._SelectX": "Seleccionar {0}", + "_.AfterEditAppAction._Close": "Cerrar", + "FrmAbout._LogoDesigner": "Diseñador de logo:", + "_.ImageOrderBy._Name": "Nombre (por defecto)", + "FrmMain.MnuRemoveDefaultPhotoViewer._Error": "No se pudo eliminar ImageGlass como el visor de fotos por defecto.", + "FrmExportFrames._FolderPickerTitle": "Seleccione la carpeta de salida de los fotogramas de imagen", + "FrmAbout._Donate": "Donar", + "FrmMain.MnuFrameNav": "Navegación por fotogramas", + "FrmMain.MnuSetLockScreen": "Establecer como imagen de pantalla de bloqueo", + "_._Delete": "Eliminar", + "FrmMain.MnuViewPrevious": "Ver imagen anterior", + "_.Position._Top": "Arriba", + "FrmSettings.Toolbar._CurrentButtons": "Botones actuales:", + "FrmMain.MnuAbout": "Acerca de", + "FrmSettings._RemoveDefault": "Eliminar programa como predeterminado", + "_._Description": "Descripción", + "FrmMain.MnuPasteImage._Error": "No se pudieron encontrar datos de imagen en el portapapeles", + "FrmMain.MnuSettings": "Preferencias", + "FrmCropSettings._Title": "Configuración de recorte", + "FrmSettings.Toolbar._ToolbarIconHeight": "Tamaño iconos barra herramientas", + "FrmSettings._SlideshowInterval._To": "Hasta", + "FrmSettings.Layout._ToolbarPosition": "Posición de barra de herramientas", + "FrmUpdate._StatusUpdated": "¡Estás usando la última versión!", + "FrmMain.MnuExit": "Salir", + "_._Webview2._Outdated": "Su WebView2 Runtime no es compatible. Por favor actualice a la versión {0} o posterior.", + "_._Yes": "Sí", + "FrmMain.MnuRotateLeft": "Girar a la izquierda", + "FrmSettings._EnableStartupBoost": "Activar inicio acelerado", + "_.ImageOrderBy._ExifRating": "EXIF: valoración", + "FrmMain.MnuZoomIn": "Acercar", + "_.Metadata._ColorSpace": "Espacio de color", + "FrmAbout._Version": "Versión:", + "FrmMain.MnuToggleTopMost._Enable": "Ventana siempre en primer plano", + "FrmSettings.Toolbar._AvailableButtons": "Botones disponibles:", + "FrmMain.MnuSave._Saving": "Guardando imagen…", + "FrmQuickSetup._StandardUser": "Usuario estándar", + "FrmMain.MnuSetLockScreen._Error": "No se pudo configurar la imagen como pantalla de bloqueo", + "FrmSettings.Nav._Image": "Imagen", + "FrmSettings._Theme._InstallTheme": "Instalar paquetes de tema", + "FrmSettings._EnableMultiInstances": "Permitir múltiples instancias del programa", + "FrmMain.MnuCropTool": "Cortar imagen", + "_._IgCommandExe._DefaultError._Heading": "Órdenes no válidas", + "_._Refresh": "Refrescar", + "FrmMain.MnuLosslessCompression._Description": "Esta herramienta utiliza la biblioteca Magick.NET para la compresión sin pérdidas, optimizando el tamaño del archivo. Lo sobrescribe solo si el archivo comprimido es más pequeño que el original.", + "_._MoveDown": "Bajar", + "FrmSettings._GetExtensionIconPacks": "Obtener paquetes de iconos de extensión…", + "FrmSettings._InAppMessageDuration": "Duración de los mensajes en la aplicación (milisegundos)", + "FrmMain.MnuFrameless": "Sin marcos", + "_._Reset": "Restablecer", + "FrmSettings._ConfigDir": "Directorio de configuración", + "FrmQuickSetup._SettingsWillBeApplied": "Se aplicarán los ajustes:", + "FrmSettings._UnmanagedSettingReminder": "ImageGlass no gestiona esta configuración. No olvide desactivar esta opción si desinstala o reubica la aplicación, dado que ImageGlass no gestiona estos cambios de forma automática.", + "FrmMain.MnuClipboard": "Portapapeles", + "FrmMain.MnuCustomZoom": "Zoom personalizado...", + "FrmSettings._DisplayLanguage": "Idioma", + "FrmMain.MnuPrint._Error": "No se pudo imprimir la imagen de visualización", + "FrmSettings._ShouldPreserveModifiedDate": "Conservar la fecha modificada de la imagen al guardarla", + "FrmSettings._ShowSaveOverrideConfirmation": "Mostrar diálogo de confirmación al sobreescribir un archivo", + "FrmColorPickerSettings.ChkShowHexA": "Usar el formato HEX con valor alfa", + "FrmMain.MnuFullScreen": "Pantalla completa", + "FrmSettings._StartupDir": "Directorio de instalación", + "FrmSettings._ShowCheckerboardOnlyImageRegion": "Mostrar patrón de tablero sólo dentro de la región de la imagen", + "FrmMain.MnuClearClipboard._Success": "Portapapeles limpiado.", + "FrmQuickSetup._Text": "Configuración rápida de ImageGlass", + "FrmMain.MnuLosslessCompression._Done": "Realizada compresión sin pérdidas.\r\nEl tamaño nuevo del archivo es de {0}; se ahorraron {1}.", + "FrmMain.MnuLosslessCompression": "Compresión sin pérdidas de Magick.NET", + "FrmResize.RadResizeByPercentage": "Porcentaje", + "FrmSettings._StartupBoost._Disabled": "El inicio acelerado está desactivado", + "FrmMain.MnuToggleCheckerboard": "Fondo a cuadros", + "FrmSettings._MinEmbeddedThumbnailSize._Height": "Altura", + "FrmSettings.Nav._General": "General", + "FrmSettings._ImageLoading": "Carga de imagen", + "FrmSettings._ShowSlideshowCountdown": "Mostrar cuenta regresiva de diapositivas", + "FrmMain.MnuSave": "Guardar", + "FrmMain.MnuMoveToRecycleBin": "Mover a la papelera de reciclaje", + "FrmMain.MnuRefresh": "Refrescar", + "FrmToolNotFound.LblHeading": "No se encuentra «{0}».", + "FrmMain.MnuReportIssue": "Notificar un error…", + "FrmMain.MnuCopyImageData": "Copiar datos de imagen", + "FrmMain.MnuCheckForUpdate._NewVersion": "¡Está disponible una nueva versión!", + "_._Empty": "(vacío)", + "FrmSettings._Zooming": "Zooming", + "FrmMain.MnuCutFile": "Cortar archivo", + "FrmHotkeyPicker.LblHotkey": "Presione tecla rápida", + "FrmSettings.Layout._Gallery": "Galería", + "FrmMain.MnuNewWindow": "Abrir en una nueva ventana", + "FrmMain.MnuMoveToRecycleBin._Description": "¿Desea mover este archivo a la papelera?", + "FrmSettings._DefaultPhotoViewer": "Visor de fotos por defecto", + "_.Metadata._ExifDateTimeOriginal": "EXIF: Fecha original", + "FrmMain.MnuRotateRight": "Girar a la derecha", + "FrmSettings._MinEmbeddedThumbnailSize": "Tamaño mínimo de la miniatura incrustada a cargar", + "FrmMain.MnuSetDefaultPhotoViewer": "Establecer como visor de fotos predeterminado", + "FrmMain.MnuImageProperties": "Propiedades de la imagen", + "FrmSettings._EnableNavigationButtons": "Mostrar flechas de navegación", + "_._Edit": "Edición", + "FrmSettings._ImageBooster": "Acelerador de imagen", + "FrmSettings.Tools._IntegratedWith": "Integrado con {0}", + "_._Next": "Siguiente", + "FrmExportFrames._OpenOutputFolder": "Abrir carpeta de salida", + "FrmMain.MnuOpenLocation": "Abrir ubicación de la imagen", + "FrmMain.MnuLockZoom": "Fijar zoom", + "FrmSettings._StartupBoost._Description": "Precargar y ejecutar ImageGlass en segundo plano durante algunos segundos al iniciar Windows para acelerar la primera ejecución.", + "FrmSettings._WindowBackdrop": "Segundo plano de ventana", + "FrmSettings._EnableRealTimeFileUpdate": "Monitorear los cambios en la carpeta abierta y actualizar en tiempo real", + "_._NotSupported": "No se admite el formato", + "FrmSettings._Theme._GetMoreThemes": "Obtener más paquetes de temas…", + "FrmMain.MnuNewWindow._Error": "No se puede abrir una nueva ventana porque solo se permite una instancia", + "FrmMain.MnuZoomOut": "Alejar", + "FrmSettings.Toolbar._EditButton": "Editar botón de barra de herramientas", + "FrmMain.MnuCustomZoom._Description": "Introduzca un nuevo valor de zoom", + "FrmResize.RadResizeByPixels": "Pixels", + "FrmMain.MnuEdit": "Editar imagen {0}…", + "FrmSettings.Layout._GalleryPosition": "Posición de la galería", + "FrmMain.MnuWindowFit": "Ajustar a la ventana", + "FrmMain._OpenFileDialog": "Todos los archivos soportados", + "FrmSettings._UseRandomIntervalForSlideshow": "Usar intervalo aleatorio", + "_.Position._Left": "Izquierda", + "FrmSettings._ShouldOpenLastSeenImage": "Abrir la última imagen vista", + "_.Position._Bottom": "Abajo", + "FrmResize.ChkKeepRatio": "Mantener proporciones", + "FrmMain.MnuGoTo": "Ir a…", + "FrmSlideshow.MnuPauseResumeSlideshow": "Pausar/reanudar pase de diapositivas", + "FrmSettings.Tools._Integrated": "Integrado", + "FrmSettings._Contributors": "Contribuidores", + "_.MouseWheelAction._Zoom": "Acercar/Alejar", + "_._CommandPreview": "Previsualización de la orden", + "FrmSettings._DarkTheme": "Oscuro", + "_._Hotkeys": "Atajos de teclado", + "_.Metadata._ExifDateTime": "EXIF: FechaHora", + "FrmSettings.Toolbar._Errors._ButtonIdRequired": "ID del botón requerido.", + "FrmSettings._MinEmbeddedThumbnailSize._Width": "Anchura", + "_._Executable": "Ejecutable", + "_.ImageInterpolation._MultiSampleLinear": "Multi-muestra lineal", + "_._Separator": "Separador", + "FrmQuickSetup._ProfessionalUser": "Usuario profesional", + "FrmMain.MnuFlipVertical": "Voltear verticalmente", + "FrmSlideshow._ResumeSlideshow": "Se reanuda el pase de diapositivas.", + "FrmCropSettings.DefaultSelectionType._CustomArea": "Área personalizada…", + "FrmMain.MnuActualSize": "Tamaño real", + "FrmCrop.BtnSaveAs": "Guardar como…", + "FrmSettings._InstallNewLanguagePack": "Instalar nuevos paquetes de idioma…", + "FrmSlideshow.MnuZoomModes": "Modos de zum", + "FrmMain.MnuTools": "Herramientas", + "_.ImageInterpolation._Cubic": "Cúbico", + "FrmUpdate._LatestVersion": "La última versión: {0}", + "FrmMain.MnuViewNext": "Ver imagen siguiente", + "_.MouseWheelEvent._AltAndScroll": "Presionar Alt y desplazarse", + "FrmToolNotFound._Title": "Herramienta no encontrada", + "FrmCrop.BtnCrop._Tooltip": "Solo recortar la imagen", + "FrmSettings.EditAppDialog._AddApp": "Añadir una aplicación para editar", + "FrmMain.MnuPanning": "Panorámica", + "_._MoveUp": "Subir", + "FrmCropSettings.DefaultSelectionType._SelectAll": "Seleccionar todo", + "_._Name": "Nombre", + "FrmColorPickerSettings.ChkShowHslA": "Usar el formato HSL con valor alfa", + "FrmMain.MnuToggleImageAnimation": "Iniciar / detener animación", + "FrmSettings._DisableStartupBoost": "Desactivar inicio acelerado", + "FrmMain.MnuCopyFile._Success": "{0} archivos copiado(s).", + "FrmMain.MnuSave._ConfirmDescription": "ImageGlass no es un editor de fotos profesional, por favor, tenga en cuenta que se puede perder la calidad, los meta datos, las capas, etc. al guardar la imagen.", + "FrmToolNotFound.BtnSelectExecutable": "Seleccionar…", + "FrmUpdate._StatusOutdated": "¡Una nueva actualización está disponible!", + "_.ImageOrderBy._Random": "Aleatorio", + "FrmResize.LblCurrentSize": "Tamaño actual:", + "_._Apply": "Aplicar", + "FrmAbout._Slogan": "Un visor de imágenes ligero y versátil", + "FrmMain.MnuPanToTop": "Desplazar imagen a la parte superior", + "FrmSettings.Toolbar._AddNewButton": "Añadir un botón personalizado a la barra de herramientas", + "FrmCrop.LblSize": "Tamaño:", + "FrmSettings._ImageInterpolation._ScaleDown": "Cuando el Zoom sea <100%", + "_._CreatingFileError": "No se pudo crear el archivo de imagen temporal", + "FrmMain.MnuGoTo._Description": "Introduzca el índice de imagen que quiere ver y presione INTRO", + "FrmSettings.Toolbar._EnableCenterToolbar": "Centrar la barra de herramientas", + "FrmMain.MnuResizeTool": "Redimensionar Imagen", + "FrmSettings.Layout._Toolbar": "Barra de herramientas", + "FrmMain.MnuHelp": "Ayuda", + "_.ImageOrderBy._FileSize": "Tamaño del archivo", + "FrmSettings._Theme._OpenThemeFolder": "Abrir carpeta de temas", + "FrmMain.MnuNavigation": "Navegación", + "_._Save": "Guardar", + "FrmQuickSetup._SettingProfileDescription": "Para modificar estos ajustes, simplemente accede a la configuración de la aplicación.", + "_._UserAction._MenuNotFound": "No se puede encontrar el menú «{0}» para invocar la acción", + "FrmMain.MnuPanToLeftSide": "Desplazar imagen al lado izquierdo", + "FrmUpdate._CurrentVersion": "Versión actual: {0}", + "FrmCrop.BtnSettings._Tooltip": "Abrir configuración de herramienta Recortar", + "_.ColorProfileOption._Custom": "Personalizado…", + "FrmSettings._UseEmbeddedThumbnailOtherFormats": "Cargar sólo la miniatura incrustada para otros formatos", + "FrmMain.MnuGoToFirst": "Ir a la primera imagen", + "FrmSettings._ExportLanguagePack": "Exportar paquete de idioma…", + "FrmSettings.Nav._Mouse": "Ratón", + "_.ImageOrderBy._DateCreated": "Fecha de creación", + "FrmSettings._EnableFullscreenSlideshow": "Iniciar diapositivas en modo pantalla completa", + "FrmAbout._Homepage": "Sitio web:", + "FrmSettings._GalleryCacheSizeInMb": "Tamaño máximo de caché de galería (en megabytes)", + "FrmMain.MnuCopyImageData._Success": "Copiados los datos de la imagen actual.", + "FrmSettings._EnableLoopBackNavigation": "Volver a la primera imagen al llegar al final de la lista de imágenes", + "_.MouseWheelEvent._Scroll": "Desplazar", + "FrmCrop.BtnSave._Tooltip": "Guardar imagen", + "FrmMain.MnuSlideshow": "Presentación", + "FrmMain.MnuShare": "Compartir…", + "FrmSettings._SlideshowNotification": "Notificación de diapositivas", + "FrmMain.MnuViewChannels": "Ver canales", + "FrmSettings._Refresh": "Refrescar", + "_._UserAction._MethodNotFound": "No se puede encontrar el método «{0}» para invocar la acción", + "FrmMain.MnuCopyFile": "Copiar archivo", + "_._CreatingFile": "Creando un archivo de imagen temporal…", + "FrmMain.MnuToggleTopMost": "Mantener ventana siempre en primer plano", + "FrmMain.MnuLosslessCompression._Confirm": "¿Está seguro que desea continuar?", + "FrmMain.MnuImage": "Imagen", + "FrmSettings._StartupBoost._Enabled": "El inicio acelerado está activado", + "FrmQuickSetup._SetDefaultViewer": "¿Quiere establecer ImageGlass como visor de fotos por defecto?", + "FrmMain.MnuScaleToWidth": "Ajustar al ancho", + "_._FileExtension": "Extensión del archivo", + "FrmUpdate._PublishedDate": "Fecha de publicación: {0}", + "_._DoNotShowThisMessageAgain": "No volver a mostrar este mensaje", + "_.ImageInterpolation._NearestNeighbor": "Vecino más próximo", + "FrmCrop.LblLocation": "Ubicación:", + "_._Download": "Descargar", + "_.Metadata._ColorProfile": "Perfil de color", + "FrmSettings._CenterWindowFit": "Centrar automáticamente la ventana en modo Ventana Ajustada", + "FrmSettings._ImageLoadingOrder": "Orden de carga de imágenes", + "FrmSettings._GalleryColumns": "Número de columnas de miniaturas en el diseño vertical de la galería", + "_._Quit": "Salir", + "_._Add": "Añadir", + "FrmMain.MnuChangeBackgroundColor": "Cambiar color de fondo…", + "FrmMain.MnuToggleToolbar": "Barra de herramientas", + "FrmAbout._Contact": "Contacto", + "FrmSettings.Toolbar._AddCustomButton": "Añadir un botón personalizado…", + "FrmCrop.BtnQuickSelect._Tooltip": "Selección rápida…", + "FrmMain.MnuCutFile._Success": "{0} archivos cortado(s).", + "FrmSettings._ZoomSpeed": "Velocidad de zoom", + "FrmMain.MnuToggleTopMost._Disable": "Desactivada ventana siempre en primer plano", + "FrmSettings._ShouldUseExplorerSortOrder": "Usar el orden del Explorador de Windows si es posible", + "_.ImageInterpolation._Antisotropic": "Anisotrópico", + "FrmMain._ReachedFirstImage": "Se alcanzó la primera imagen", + "_._UnhandledException": "Excepción no controlada", + "FrmResize.LblNewSize": "Nuevo Tamaño:", + "FrmMain._ClipboardImage": "Imagen del portapapeles", + "FrmMain.MnuExportFrames": "Exportar fotogramas de imagen…", + "FrmMain.MnuFile": "Archivo", + "_._Close": "Cerrar", + "FrmMain.MnuMain": "Menú principal", + "_._ResetToDefault": "Restablecer valores predeterminados", + "FrmSettings.Nav._Gallery": "Galería", + "FrmMain.MnuSetDefaultPhotoViewer._Success": "Ha configurado con éxito ImageGlass como visor de fotos por defecto.", + "FrmSettings._HideGalleryInFullscreen": "Ocultar galería en modo de pantalla completa", + "FrmSettings._AvailableImageInfoTags": "Etiquetas disponibles:", + "FrmExportFrames._Exporting": "Exportando {0}/{1} fotogramas \n{2}…", + "_._Argument": "Argumento", + "FrmSettings._ImageEditQuality": "Calidad de imagen", + "_._ID": "Id.", + "FrmSettings._UserConfigFile": "Archivo de configuración de usuario (igconfig.json)", + "FrmMain.MnuLoadingOrders": "Orden de carga de las imágenes", + "FrmSettings._OpenSaveAsDialogInTheCurrentImageDir": "Abrir el cuadro de diálogo Guardar como en el directorio de imágenes actual", + "_.MouseWheelEvent._ShiftAndScroll": "Presionar Mayúscula y desplazarse", + "FrmSettings._UseSmoothZooming": "Usar zoom suave", + "FrmSettings._Theme": "Tema", + "FrmSettings._ImageBoosterCacheMaxDimension": "Dimensión máxima de la imagen a ser cacheada (en píxeles)", + "FrmMain.MnuScaleToHeight": "Ajustar a la altura", + "_.Metadata._FileLastWriteTime": "Fecha de modificación", + "FrmSettings._Author": "Autor", + "FrmSettings._Others": "Otros", + "_.MouseWheelAction._PanVertically": "Desplazar arriba/abajo", + "FrmSettings._MouseWheelAction": "Acción de la rueda del ratón", + "FrmSettings.Nav._Tools": "Herramientas", + "FrmMain.MnuSetDesktopBackground._Error": "No se pudo establecer la imagen como fondo de escritorio", + "FrmSettings.Toolbar._Errors._ButtonExecutableRequired": "Se requiere un ejecutable para el botón.", + "_.ImageOrderBy._DateAccessed": "Fecha de acceso", + "FrmSettings._ThumbnailSize": "Tamaño de miniatura (en píxeles)", + "FrmSettings._FileFormats": "Formatos de archivo", + "FrmMain.MnuReloadImageList": "Recargar lista de imágenes", + "FrmSettings._UseWebview2ForSvg": "Usar Webview2 para ver archivos SVG", + "FrmCrop.BtnCopy": "Copiar", + "FrmSettings._CurrentMonitorProfile._Description": "ImageGlass no actualiza automáticamente el color al mover su ventana entre varios monitores", + "FrmMain.PicMain._ErrorText": "No se pudo abrir esta imagen", + "FrmSettings.Tools._AddNewTool": "Añadir una herramienta externa", + "FrmMain.MnuRename": "Cambiar nombre de imagen…", + "FrmMain.MnuViewLastFrame": "Ver el último fotograma", + "_._Webview2._NotFound": "Por favor, instale la última versión de WebView2 Runtime.", + "FrmMain.MnuGetMoreTools": "Obtener más herramientas…", + "FrmSettings.Nav._Appearance": "Apariencia", + "FrmSettings._SlideshowInterval": "Intervalo de diapositivas:", + "_.ImageInterpolation._HighQualityBicubic": "Alta calidad bicúbica", + "FrmColorPickerSettings.ChkShowHsvA": "Usar el formato HSV con valor alfa", + "FrmSettings.Tools._EditTool": "Editar herramienta externa", + "_._Error": "Error", + "FrmSettings._ImageBoosterCacheMaxFileSizeInMb": "Tamaño máximo de imagen a guardar en caché (en megabytes)", + "_._UnhandledException._Description": "Ha ocurrido una excepción no controlada. Si hace clic en Continuar, la aplicación ignorará este error e intentará continuar. Si hace clic en Salir, la aplicación se cerrará inmediatamente.", + "_.Metadata._FileSize": "Tamaño del archivo", + "FrmSettings.Toolbar._ButtonJson": "JSON del botón", + "FrmQuickSetup._SetDefaultViewer._Description": "Puede restablecerlo en la configuración de la aplicación > pestaña de asociaciones de tipo de archivo.", + "FrmSettings.Nav._Edit": "Edición", + "FrmMain.MnuToggleGallery": "Panel de galería", + "_._IgCommandExe._DefaultError._Description": "Cerciórese de pasar las órdenes correctas.\r\nEste archivo ejecutable contiene funciones de consola para el programa ImageGlass.\r\n\r\nPara explorar todas las órdenes, visite:\n{0}", + "FrmMain.MnuLosslessCompression._Compressing": "Realizando una compresión sin pérdidas…", + "FrmSettings._ShouldGroupImagesByDirectory": "Agrupar imágenes por carpeta", + "FrmMain.MnuPanToRightSide": "Desplazar imagen al lado derecho", + "_.Metadata._ExifRatingPercent": "Valoración", + "FrmSettings._PanSpeed": "Velocidad de deslizamiento", + "_._CheckForUpdate": "Buscar actualizaciones…", + "FrmSettings.Layout._ToolbarContext": "Barra de herramientas contextual", + "_.ImageInfo._FrameCount": "{0} fotograma(s)", + "FrmMain.MnuLayout": "Disposición", + "_._Website": "Sitio Web", + "FrmMain.MnuPasteImage": "Pegar imagen", + "FrmSettings._ShowGalleryScrollbars": "Mostrar barras de desplazamiento de galería" + } +} \ No newline at end of file diff --git a/Setup/Assets/Language/Swedish.iglang.json b/Setup/Assets/Language/Swedish.iglang.json new file mode 100644 index 000000000..ca9227c2d --- /dev/null +++ b/Setup/Assets/Language/Swedish.iglang.json @@ -0,0 +1,504 @@ +{ + "_Metadata": { + "Code": "sv-SE", + "EnglishName": "Swedish", + "LocalName": "Svenska", + "Author": "Esciro", + "MinVersion": "9.1" + }, + "Items": { + "FrmCrop.SelectionAspectRatio._Original": "Original", + "FrmMain.MnuShare._Error": "Dialogrutan för delning kunde inte öppnas.", + "_.Metadata._FileLastAccessTime": "Senast använd", + "FrmAbout._License": "Programvarulicens", + "FrmSettings.Toolbar._Errors._ButtonIdDuplicated": "Det finns redan en knapp med ID:t \"{0}\". Se till att använda olika och unka ID för dina knappar för att undvika problem.", + "FrmMain.MnuSave._Confirm": "Vill du verkligen skriva över denna bild?", + "FrmSettings._OpenDefaultAppsSetting": "Öppna standardappar i inställningar", + "FrmMain.MnuCopyPath": "Kopiera filsökväg", + "FrmCropSettings.DefaultSelectionType._SelectNone": "Avmarkera alla", + "_.MouseWheelAction._PanHorizontally": "Panorera åt vänster eller höger", + "FrmMain.MnuPrint": "Skriv ut…", + "FrmSettings.Toolbar._ToolbarButtons": "Verktygsfältets knappar", + "FrmResize.LblResample": "Omsampla:", + "_.ImageOrderBy._Extension": "Tillägg", + "FrmSettings.Nav._Viewer": "Bildvy", + "FrmSettings.EditAppDialog._EditApp": "Ändra program", + "FrmCrop.BtnReset._Tooltip": "Återställ markering", + "FrmMain.MnuRename._Description": "Ange nytt filnamn:", + "_._No": "No", + "FrmSlideshow.MnuToggleCountdown": "Visa nedräkning för bildspel", + "FrmSettings._OpenStartupAppsSetting": "Öppna inställningarna för autostart", + "FrmMain.MnuViewPreviousFrame": "Se föregående bildruta", + "_.ImageOrderBy._DateModified": "Senast ändrad", + "FrmMain.MnuViewNextFrame": "Se nästa bildruta", + "FrmMain.MnuUnload": "Sluta visa bild", + "FrmSettings.Toolbar._HideToolbarInFullscreen": "Dölj verktygsfältet i helskärmsläge", + "_.ImageOrderType._Desc": "Fallande", + "_._Update": "Uppdatera", + "FrmSettings._EnableImageAsyncLoading": "Aktivera asynkron bildinläsning", + "FrmSettings._DefaultPhotoViewer._Description": "Ange ImageGlass som standardval för de format som stöds. Du kan behöva ange ImageGlass som standardapp manuellt i inställningar.", + "_.MouseWheelAction._BrowseImages": "Visa nästa eller föregående bild", + "FrmSettings._EditApps": "Bildbehandlingsprogram", + "FrmColorPickerSettings.ChkShowCIELabA": "Använd CIELAB-format med alfakanal", + "_._GetHelp": "Få hjälp", + "FrmQuickSetup._SkipQuickSetup": "Hoppa över detta och starta ImageGlass", + "FrmColorPickerSettings._Title": "Färgvalsinställningar", + "_._Copy": "Kopiera", + "FrmSettings._ImageBoosterCacheCount": "Antal bilder som ska cachas av bildboosten (i en riktning)", + "FrmMain.MnuPanToBottom": "Panorera till botten", + "FrmMain.MnuZoom": "Zooma", + "FrmCropSettings.ChkCloseToolAfterSaving": "Stäng beskärningsverktyget efter sparning", + "FrmSettings._ShowWelcomeImage": "Visa välkomstbild", + "FrmSettings._ColorProfile": "Färgprofil", + "FrmSettings._Theme._UninstallTheme": "Avinstallera temapaket", + "FrmMain._OpenWith": "Öppna med {0}", + "FrmMain.MnuRemoveDefaultPhotoViewer": "Ta bort som förvald bildvisare", + "_.AfterEditAppAction._Nothing": "Ingenting", + "FrmCrop.BtnSave": "Spara", + "FrmMain.MnuScaleToFit": "Anpassa till fönster", + "FrmToolNotFound.LblDownloadToolText": "Hämta fler verktyg för ImageGlass på:", + "_._LearnMore": "Mer info…", + "FrmCrop.LblAspectRatio": "Bildförhållande:", + "FrmExportFrames._FileNotExist": "Bildfilen finns inte", + "FrmSettings._LightTheme": "Ljust", + "FrmSettings.Nav._Slideshow": "Bildspel", + "_._Continue": "Fortsätt", + "_._AddHotkey": "Lägg till kortkommando…", + "FrmMain.MnuSetDesktopBackground": "Använd som skrivbordsbakgrund", + "FrmMain.MnuReload": "Uppdatera bild", + "FrmSlideshow.MnuExitSlideshow": "Avsluta bildspelet", + "FrmMain.MnuAutoZoom": "Autozoom", + "FrmSettings._ShowImagePreview": "Visa förhandsgranskning när bilden läses in", + "FrmCrop.BtnCopy._Tooltip": "Kopiera markeringen till urklipp", + "FrmSettings.Nav._Toolbar": "Verktygsfält", + "FrmMain.MnuSave._Error": "Bilden kunde inte sparas", + "FrmSettings._AfterEditingAction": "Efter att redigeringsappen har öppnats", + "FrmSettings._ShouldUseColorProfileForAll": "Tillämpa även för bilder utan inbäddad färgprofil", + "FrmCropSettings.DefaultSelectionType._UseTheLastSelection": "Använda den senaste markeringen", + "FrmSettings._SlideshowInterval._From": "Från", + "FrmSettings._ImageInterpolation": "Bildinterpolation", + "FrmQuickSetup._StepInfo": "Steg {0}", + "FrmMain.MnuColorPicker": "Pipett", + "FrmCrop.SelectionAspectRatio._FreeRatio": "Fritt bildförhållande", + "FrmSettings._ResetSettings": "Återställ inställningar", + "FrmSettings._Startup": "Uppstart", + "_.BackdropStyle._None": "Ingen", + "FrmSettings._LoadDefaultZoomLevels": "Återställ zoomnivåer", + "FrmColorPicker.BtnSettings._Tooltip": "Öppna färgvalsinställningar…", + "FrmSettings._UseThemeForDarkMode": "Använd detta som mörkt tema", + "FrmSettings._ShowDeleteConfirmation": "Visa en bekräftelseruta när filer tas bort", + "FrmSettings._ShowAppIcon": "Visa programikonen i titelraden", + "_._InvalidAction": "Ogiltig åtgärd", + "FrmQuickSetup._SelectProfile": "Välj profil", + "_.Metadata._FileCreationTime": "Skapad den", + "FrmSettings._SlideshowImagesToNotifySound": "Antal bilder tills ett aviseringsljud spelas", + "FrmSettings._BackgroundColor": "Bildvyns bakgrundsfärg", + "FrmSettings._RealTimeFileUpdate": "Realtidsuppdatering av filer", + "_.ColorProfileOption._CurrentMonitorProfile": "Nuvarande skärmprofil", + "FrmSettings._EnableCutMultipleFiles": "Tillåt utklippning av flera filer samtidigt", + "FrmSettings._AutoUpdate": "Sök efter uppdateringar automatiskt", + "FrmCropSettings.LblDefaultSelection": "Standardinställnignar för markeringar", + "FrmSettings._UseThemeForLightMode": "Använd detta som ljust tema", + "FrmSettings._ZoomLevels": "Zoomnivåer", + "FrmMain.MnuSetLockScreen._Success": "Låsskärmens bakgrundsbild har ändrats", + "FrmSettings._ShowGalleryFileName": "Visa miniatyrbilders filnamn", + "FrmSettings.Layout._Order": "Sortera efter", + "FrmCropSettings.ChkAutoCenterSelection": "Auto-centrera markering", + "FrmSettings.Nav._FileTypeAssociations": "Filassociationer", + "_._Back": "Bakåt", + "FrmMain.MnuSetDesktopBackground._Success": "Skrivbordsbakgrunden har ändrats", + "FrmSettings._ShouldAutoOpenNewAddedImage": "Öppna nyligen tillagda bilder automatiskt", + "FrmCrop.SelectionAspectRatio._Custom": "Anpassad…", + "FrmMain.MnuCopyPath._Success": "Bildens sökväg har kopierats.", + "FrmSettings._StartupBoost._Error": "Autostart-inställningarna kunde inte ändras", + "FrmToolNotFound.LblDescription": "Sökvägen till den körbara filen \"{0}\" kunde inte hittas av ImageGlass. Uppdatera sökvägen till \"{0}\" för att åtgärda problemet.", + "FrmMain.MnuClearClipboard": "Rensa urklipp", + "FrmSettings._ColorManagement": "Färghantering", + "FrmMain._ReachedLastLast": "Detta är den sista bilden i mappen", + "FrmMain.MnuPanUp": "Panorera uppåt", + "FrmMain.MnuRemoveDefaultPhotoViewer._Success": "ImageGlass är inte längre förvald bildvisare.", + "FrmSettings._GetMoreLanguagePacks": "Hämta fler språkpaket", + "FrmAbout._Privacy": "Sekretesspolicy", + "FrmSettings._EnableRecursiveLoading": "Läs in bilder i undermappar", + "_._UserAction._MethodArgumentNotSupported": "Argumenttypen för metoden \"{0}\" stöds inte", + "FrmSettings._FileExtensionIcons._Description": "Filtypsikonerna kan anpassas till valfritt utseende. Ladda hem ett ikonpaket och lägg därefter samtliga .ICO-filer i mappen för filtypsikoner. Klicka därefter på \"{0}\". Detta kommer även att göra ImageGlass till förvald bildvisare.", + "_.ImageOrderType._Asc": "Stigande", + "FrmExportFrames._Title": "Exportera bildrutor", + "_._Install": "Installera…", + "FrmMain.MnuFlipHorizontal": "Vänd horisontellt", + "FrmSettings._OpenExtensionIconFolder": "Öppna mappen med filtypsikoner", + "FrmAbout._Collaborator": "Samarbetspartner:", + "FrmQuickSetup._ConfirmCloseProcess": "Samtliga ImageGlass-processer måste avslutas för att tillämpa de nya inställningarna. Vill du fortsätta?", + "FrmExportFrames._ExportDone": "{0} bildrutor har exporterats till \n{1}", + "FrmCrop.BtnSaveAs._Tooltip": "Spara som en kopia…", + "FrmMain.MnuOpenFile": "Öppna fil…", + "FrmColorPickerSettings.ChkShowRgbA": "Använd RGB-format med alfakanal", + "_.ImageInfo._ListCount": "{0} fil(er)", + "FrmMain.MnuGoToLast": "Gå till sista bilden", + "FrmSettings._EditApps._AppName": "Appnamn", + "FrmSettings._SlideshowBackgroundColor": "Bildspelets bakgrundsfärg", + "FrmAbout._Email": "E-post:", + "_.MouseWheelAction._DoNothing": "Gör ingenting", + "FrmMain.MnuSaveAs": "Spara som…", + "FrmMain._Loading": "Läser in…", + "_._Browse": "Bläddra…", + "FrmMain.MnuSetDefaultPhotoViewer._Error": "Ett fel uppstod med att göra ImageGlass till förvald bildvisare.", + "FrmSettings.Nav._Language": "Språk", + "FrmQuickSetup._SeeWhatNew": "Se nyheter i denna version…", + "FrmSettings._ImageInterpolation._ScaleUp": "När zoomnivån > 100 %", + "FrmSettings.Layout._ToolbarContextPosition": "Kontextuella verktygsfältets position", + "FrmMain.MnuDeleteFromHardDisk": "Radera permanent", + "FrmSettings._EmbeddedThumbnail": "Inbäddade miniatyrbilder", + "FrmMain.MnuDeleteFromHardDisk._Description": "Vill du ta bort denna fil permanent?", + "FrmMain.MnuScaleToFill": "Fyll skärmen", + "FrmCrop.BtnCrop": "Beskär", + "_.AfterEditAppAction._Minimize": "Minimera", + "FrmMain.MnuInvertColors": "Invertera färger", + "FrmSettings._StartupBoost": "Autostart", + "FrmMain.MnuViewFirstFrame": "Se den första bildrutan", + "_.MouseWheelEvent._CtrlAndScroll": "Håll Ctrl och skrollhjulet", + "FrmSettings._HideMainWindowInSlideshow": "Dölj huvudfönstret automatiskt", + "_.Metadata._FrameCount": "Bildrutor", + "FrmSettings._EnableCopyMultipleFiles": "Tillåt kopiering av flera filer samtidigt", + "FrmMain.MnuFrameless._EnableDescription": "Håll ner Skift för att flytta fönstret.", + "_.ImageOrderBy._ExifDateTaken": "EXIF: Fotodatum", + "FrmAbout._Credits": "Medverkande", + "FrmSettings._AddNewFileExtension": "Lägg till ny filändelse", + "FrmMain.MnuQuickSetup": "Kör igång snabbinställningar för ImageGlass", + "FrmMain.MnuSave._Success": "Bilden har sparats", + "FrmMain.MnuPanLeft": "Panorera åt vänster", + "FrmUpdate._StatusChecking": "Söker efter uppdateringar…", + "FrmSettings.Nav._Layout": "Layout", + "FrmMain.MnuOpenWith": "Öppna med…", + "FrmAbout._Thanks": "Särskilt tack till:", + "_._Warning": "Varning", + "FrmSettings.Nav._Keyboard": "Tangentbord", + "FrmSlideshow._PauseSlideshow": "Bildspelet har pausats.", + "_._Add+": "Lägg till…", + "_._Email": "E-post", + "FrmMain.MnuPanDown": "Panorera neråt", + "_._Cancel": "Avbryt", + "_._OK": "OK", + "FrmMain.MnuPanRight": "Panorera åt höger", + "_.Position._Right": "Höger", + "_._Icon": "Ikon", + "FrmSettings._ShouldLoadHiddenImages": "Läs in dolda bilder", + "_._InvalidAction._Transformation": "ImageGlass saknar stöd för att rotera eller vända detta bildformat.", + "FrmSettings._MakeDefault": "Ställ in som standardapp", + "FrmMain.MnuCopyImageData._Copying": "Kopierar bilddata. Detta kan ta en stund…", + "FrmSettings._UseEmbeddedThumbnailRawFormats": "Läs endast in inbäddade miniatyrbilder för RAW-format", + "_.ImageInterpolation._Linear": "Linjär", + "FrmSettings._ImageInfoTags": "Bildtaggar som visas i titelraden", + "FrmSettings._FileExtensionIcons": "Filändelseikoner", + "FrmMain.MnuEdit._AppNotFound": "Bildbehandlingsprogammet kunde inte hittas. Ange ett bildbehandlingsprogram för att redigera detta format i Imageglass inställningar > Redigera.", + "_.ColorProfileOption._None": "Ingen", + "FrmSettings._TotalSupportedFormats": "Antal format som stöds: {0}", + "FrmSettings._Clipboard": "Urklipp", + "_._UserAction._Win32ExeError": "Kunde inte utföra kommandot \"{0}\". Se till att namnet stämmer.", + "FrmCropSettings.DefaultSelectionType._SelectX": "Välj {0}", + "_.AfterEditAppAction._Close": "Stäng", + "FrmAbout._LogoDesigner": "Logotypdesign:", + "_.ImageOrderBy._Name": "Namn (standard)", + "FrmMain.MnuRemoveDefaultPhotoViewer._Error": "Ett fel uppstod med att ta bort ImageGlass som förvald bildvisare.", + "FrmExportFrames._FolderPickerTitle": "Välj vilken mapp som bildrutorna ska sparas i", + "FrmAbout._Donate": "Donera", + "FrmMain.MnuFrameNav": "Bildrutenavigering", + "FrmMain.MnuSetLockScreen": "Använd som låsskärmsbild", + "_._Delete": "Radera", + "FrmMain.MnuViewPrevious": "Visa föregående bild", + "_.Position._Top": "Överst", + "FrmSettings.Toolbar._CurrentButtons": "Nuvarande knappar:", + "FrmMain.MnuAbout": "Om", + "FrmSettings._RemoveDefault": "Ta bort som standardapp", + "_._Description": "Beskrivning", + "FrmMain.MnuPasteImage._Error": "Ingen bilddata kunde hittas i urklipp", + "FrmMain.MnuSettings": "Inställningar", + "FrmCropSettings._Title": "Inställningar för beskärning", + "FrmSettings.Toolbar._ToolbarIconHeight": "Ikonstorlek för verktygsfältet", + "FrmSettings._SlideshowInterval._To": "Till", + "FrmSettings.Layout._ToolbarPosition": "Verktygsfältets position", + "FrmUpdate._StatusUpdated": "Du använder den senaste versionen!", + "FrmMain.MnuExit": "Avsluta", + "_._Webview2._Outdated": "Din version av WebView2 Runtime stöds inte längre. Vänligen uppdatera till version {0} eller senare.", + "_._Yes": "Ja", + "FrmMain.MnuRotateLeft": "Rotera åt vänster", + "FrmSettings._EnableStartupBoost": "Aktivera autostart", + "_.ImageOrderBy._ExifRating": "EXIF: Betyg", + "FrmMain.MnuZoomIn": "Förstora", + "_.Metadata._ColorSpace": "Färgrymd", + "FrmAbout._Version": "Version:", + "FrmMain.MnuToggleTopMost._Enable": "Fönstret ligger nu alltid överst", + "FrmSettings.Toolbar._AvailableButtons": "Valbara knappar:", + "FrmMain.MnuSave._Saving": "Sparar bild…", + "FrmQuickSetup._StandardUser": "Standardanvändare", + "FrmMain.MnuSetLockScreen._Error": "Ett fel uppstod med att byta låsskärmens bakgrundsbild till bilden som visas", + "FrmSettings.Nav._Image": "Bild", + "FrmSettings._Theme._InstallTheme": "Installera temapaket", + "FrmSettings._EnableMultiInstances": "Tillåt flera instanser av programmet", + "FrmMain.MnuCropTool": "Beskär bild", + "_._IgCommandExe._DefaultError._Heading": "Ogiltigt kommando", + "_._Refresh": "Uppdatera", + "FrmMain.MnuLosslessCompression._Description": "Detta optimeringsverktyg använder Magick.NET-biblioteket för förlustfri komprimering. Filer skrivs endast över om den komprimerade filen är mindre än originalet.", + "_._MoveDown": "Flytta ner", + "FrmSettings._GetExtensionIconPacks": "Hämta filtypsikoner", + "FrmSettings._InAppMessageDuration": "Längd på programmeddelanden (millisekunder)", + "FrmMain.MnuFrameless": "Utan ram", + "_._Reset": "Återställ", + "FrmSettings._ConfigDir": "Inställningarnas sökväg", + "FrmQuickSetup._SettingsWillBeApplied": "Följande inställningar kommer att tillämpas:", + "FrmSettings._UnmanagedSettingReminder": "Denna inställning hanteras inte av ImageGlass. Glöm inte att inaktivera autostart innan du tar bort eller flyttar ImageGlass då detta inte sköts automatiskt.", + "FrmMain.MnuClipboard": "Urklipp", + "FrmMain.MnuCustomZoom": "Anpassad zoom…", + "FrmSettings._DisplayLanguage": "Visningsspråk", + "FrmMain.MnuPrint._Error": "Ett fel uppstod med att skriva ut bilden", + "FrmSettings._ShouldPreserveModifiedDate": "Bevara bildens ursprungliga ändringsdatum vid sparning", + "FrmSettings._ShowSaveOverrideConfirmation": "Visa en bekräftelseruta när filer skrivs över", + "FrmColorPickerSettings.ChkShowHexA": "Använd HEX-format med alfakanal", + "FrmMain.MnuFullScreen": "Helskärm", + "FrmSettings._StartupDir": "Programmets sökväg", + "FrmSettings._ShowCheckerboardOnlyImageRegion": "Visa rutmönster endast i bildområdet", + "FrmMain.MnuClearClipboard._Success": "Rensade urklipp.", + "FrmQuickSetup._Text": "Snabbinställningar för ImageGlass", + "FrmMain.MnuLosslessCompression._Done": "Den förlustfria komprimeringen har slutförts.\r\nDen nya filstorleken är {0} och har minskats med {1}.", + "FrmMain.MnuLosslessCompression": "Förlustfri komprimering med Magick.NET", + "FrmResize.RadResizeByPercentage": "Procent", + "FrmSettings._StartupBoost._Disabled": "Autostart har inaktiverats", + "FrmMain.MnuToggleCheckerboard": "Rutig bakgrund", + "FrmSettings._MinEmbeddedThumbnailSize._Height": "Höjd", + "FrmSettings.Nav._General": "Allmänt", + "FrmSettings._ImageLoading": "Bildvisning", + "FrmSettings._ShowSlideshowCountdown": "Visa nedräkning för bildspel", + "FrmMain.MnuSave": "Spara", + "FrmMain.MnuMoveToRecycleBin": "Flytta till papperskorgen", + "FrmMain.MnuRefresh": "Uppdatera", + "FrmToolNotFound.LblHeading": "'{0}' hittades inte!", + "FrmMain.MnuReportIssue": "Rapportera ett fel…", + "FrmMain.MnuCopyImageData": "Kopiera bilddata", + "FrmMain.MnuCheckForUpdate._NewVersion": "En ny version finns tillgänglig!", + "_._Empty": "(tom)", + "FrmSettings._Zooming": "Zoomning", + "FrmMain.MnuCutFile": "Klipp ut fil", + "FrmHotkeyPicker.LblHotkey": "Tryck på kortkommando", + "FrmSettings.Layout._Gallery": "Galleri", + "FrmMain.MnuNewWindow": "Öppna nytt fönster", + "FrmMain.MnuMoveToRecycleBin._Description": "Vill du flytta denna fil till papperskorgen?", + "FrmSettings._DefaultPhotoViewer": "Standardprogram för bildvisning", + "_.Metadata._ExifDateTimeOriginal": "EXIF: DateTimeOriginal", + "FrmMain.MnuRotateRight": "Rotera åt höger", + "FrmSettings._MinEmbeddedThumbnailSize": "Minsta storleken vid inläsning av inbäddade miniatyrbilder", + "FrmMain.MnuSetDefaultPhotoViewer": "Ange som standardprogram för bildvisning", + "FrmMain.MnuImageProperties": "Egenskaper", + "FrmSettings._EnableNavigationButtons": "Visa navigeringspilar", + "_._Edit": "Redigera", + "FrmSettings._ImageBooster": "Bildboost", + "FrmSettings.Tools._IntegratedWith": "Integrerades med {0}", + "_._Next": "Nästa", + "FrmExportFrames._OpenOutputFolder": "Öppna utdatamappen", + "FrmMain.MnuOpenLocation": "Öppna filsökväg", + "FrmMain.MnuLockZoom": "Lås proportioner vid storleksändring", + "FrmSettings._StartupBoost._Description": "Läser in och kör ImageGlass i bakgrunden när Windows startar för att påskynda programmets uppstart.", + "FrmSettings._WindowBackdrop": "Fönsterbakgrund", + "FrmSettings._EnableRealTimeFileUpdate": "Håll koll på filändringar i realtid och uppdatera mappinnehåll automatiskt", + "_._NotSupported": "Formatet stöds inte", + "FrmSettings._Theme._GetMoreThemes": "Hämta fler temapaket", + "FrmMain.MnuNewWindow._Error": "Fönstret kan endast öppnas i en instans", + "FrmMain.MnuZoomOut": "Förminska", + "FrmSettings.Toolbar._EditButton": "Redigera knapp i verktygsfältet", + "FrmMain.MnuCustomZoom._Description": "Ange ett nytt zoomvärde", + "FrmResize.RadResizeByPixels": "Pixlar", + "FrmMain.MnuEdit": "Redigera bild{0}…", + "FrmSettings.Layout._GalleryPosition": "Galleriets position", + "FrmMain.MnuWindowFit": "Anpassa till skärmen", + "FrmMain._OpenFileDialog": "Alla format som stöds", + "FrmSettings._UseRandomIntervalForSlideshow": "Använd slumpmässigt intervall", + "_.Position._Left": "Vänster", + "FrmSettings._ShouldOpenLastSeenImage": "Öppna den senaste bilden", + "_.Position._Bottom": "Nederst", + "FrmResize.ChkKeepRatio": "Behåll bildproportioner", + "FrmMain.MnuGoTo": "Gå till…", + "FrmSlideshow.MnuPauseResumeSlideshow": "Pausa eller fortsätt bildspel", + "FrmSettings.Tools._Integrated": "Integrerad", + "FrmSettings._Contributors": "Medverkande", + "_.MouseWheelAction._Zoom": "Zooma in eller ut", + "_._CommandPreview": "Förhandsgranskning av kommando", + "FrmSettings._DarkTheme": "Mörkt", + "_._Hotkeys": "Kortkommandon", + "_.Metadata._ExifDateTime": "EXIF: DateTime", + "FrmSettings.Toolbar._Errors._ButtonIdRequired": "Knapp-ID krävs.", + "FrmSettings._MinEmbeddedThumbnailSize._Width": "Bredd", + "_._Executable": "Körbar fil", + "_.ImageInterpolation._MultiSampleLinear": "Multilinjär", + "_._Separator": "Avskiljare", + "FrmQuickSetup._ProfessionalUser": "Professionell användare", + "FrmMain.MnuFlipVertical": "Vänd vertikalt", + "FrmSlideshow._ResumeSlideshow": "Bildspelet återupptas.", + "FrmCropSettings.DefaultSelectionType._CustomArea": "Anpassat område…", + "FrmMain.MnuActualSize": "Originalstorlek", + "FrmCrop.BtnSaveAs": "Spara som…", + "FrmSettings._InstallNewLanguagePack": "Installera nytt språkpaket…", + "FrmSlideshow.MnuZoomModes": "Zoomlägen", + "FrmMain.MnuTools": "Verktyg", + "_.ImageInterpolation._Cubic": "Kubisk", + "FrmUpdate._LatestVersion": "Den senaste versionen: {0}", + "FrmMain.MnuViewNext": "Visa nästa bild", + "_.MouseWheelEvent._AltAndScroll": "Håll Alt och skrollhjulet", + "FrmToolNotFound._Title": "Verktyget hittades inte", + "FrmCrop.BtnCrop._Tooltip": "Beskär endast bilden", + "FrmSettings.EditAppDialog._AddApp": "Lägg till ett bildredigeringsprogram", + "FrmMain.MnuPanning": "Panorering", + "_._MoveUp": "Flytta upp", + "FrmCropSettings.DefaultSelectionType._SelectAll": "Markera alla", + "_._Name": "Namn", + "FrmColorPickerSettings.ChkShowHslA": "Använd HSL-format med alfakanal", + "FrmMain.MnuToggleImageAnimation": "Starta eller stoppa bildanimering", + "FrmSettings._DisableStartupBoost": "Inaktivera autostart", + "FrmMain.MnuCopyFile._Success": "Kopierade {0} fil(er).", + "FrmMain.MnuSave._ConfirmDescription": "ImageGlass är inget professionellt bildbehandlingsprogram. Tänk på att kvalitet, metadata och lager kan påverkas när bilden sparas.", + "FrmToolNotFound.BtnSelectExecutable": "Välj…", + "FrmUpdate._StatusOutdated": "En ny uppdatering finns tillgänglig!", + "_.ImageOrderBy._Random": "Slumpmässig", + "FrmResize.LblCurrentSize": "Nuvarande storlek:", + "_._Apply": "Verkställ", + "FrmAbout._Slogan": "En lättviktig och mångsidig bildvisare", + "FrmMain.MnuPanToTop": "Panorera till toppen", + "FrmSettings.Toolbar._AddNewButton": "Lägg till en knapp i verktygsfältet", + "FrmCrop.LblSize": "Storlek:", + "FrmSettings._ImageInterpolation._ScaleDown": "När zoomnivån < 100 %", + "_._CreatingFileError": "Misslyckades med att skapa en tillfällig bildfil", + "FrmMain.MnuGoTo._Description": "Ange bildnummer och tryck därefter på Enter", + "FrmSettings.Toolbar._EnableCenterToolbar": "Centrera verktygsfältet", + "FrmMain.MnuResizeTool": "Ändra bildstorlek", + "FrmSettings.Layout._Toolbar": "Verktygsfält", + "FrmMain.MnuHelp": "Hjälp", + "_.ImageOrderBy._FileSize": "Filstorlek", + "FrmSettings._Theme._OpenThemeFolder": "Öppna temamapp", + "FrmMain.MnuNavigation": "Navigera", + "_._Save": "Spara", + "FrmQuickSetup._SettingProfileDescription": "Dessa inställningar kan ändras senare i inställningsmenyn.", + "_._UserAction._MenuNotFound": "Menyalternativet \"{0}\" hittades inte och kunde inte utföras", + "FrmMain.MnuPanToLeftSide": "Panorera längst till vänster", + "FrmUpdate._CurrentVersion": "Nuvarande version: {0}", + "FrmCrop.BtnSettings._Tooltip": "Öppna inställningar för beskärning", + "_.ColorProfileOption._Custom": "Anpassad…", + "FrmSettings._UseEmbeddedThumbnailOtherFormats": "Läs endast in inbäddade miniatyrbilder för övriga format", + "FrmMain.MnuGoToFirst": "Gå till första bilden", + "FrmSettings._ExportLanguagePack": "Exportera språkpaket…", + "FrmSettings.Nav._Mouse": "Mus", + "_.ImageOrderBy._DateCreated": "Skapad den", + "FrmSettings._EnableFullscreenSlideshow": "Starta bildspel i helskärmsläge", + "FrmAbout._Homepage": "Hemsida:", + "FrmSettings._GalleryCacheSizeInMb": "Högsta cachestorlek för galleriet (i megabyte)", + "FrmMain.MnuCopyImageData._Success": "Bilddata har kopierats.", + "FrmSettings._EnableLoopBackNavigation": "Börja om från början efter att sista bilden har visats", + "_.MouseWheelEvent._Scroll": "Skrolla", + "FrmCrop.BtnSave._Tooltip": "Spara bild", + "FrmMain.MnuSlideshow": "Bildspel", + "FrmMain.MnuShare": "Dela…", + "FrmSettings._SlideshowNotification": "Bildspelsavisering", + "FrmMain.MnuViewChannels": "Visa kanaler", + "FrmSettings._Refresh": "Uppdatera", + "_._UserAction._MethodNotFound": "Metoden \"{0}\" hittades inte och kunde inte utföras", + "FrmMain.MnuCopyFile": "Kopiera fil", + "_._CreatingFile": "Skapar en tillfällig bildfil…", + "FrmMain.MnuToggleTopMost": "Visa alltid fönstret överst", + "FrmMain.MnuLosslessCompression._Confirm": "Är du säker på att du vill fortsätta?", + "FrmMain.MnuImage": "Bild", + "FrmSettings._StartupBoost._Enabled": "Autostart har aktiverats", + "FrmQuickSetup._SetDefaultViewer": "Vill du använda ImageGlass som standardprogram för att se bilder?", + "FrmMain.MnuScaleToWidth": "Anpassa till bredd", + "_._FileExtension": "Filändelse", + "FrmUpdate._PublishedDate": "Publiceringsdatum: {0}", + "_._DoNotShowThisMessageAgain": "Visa inte detta meddelande igen", + "_.ImageInterpolation._NearestNeighbor": "Närmaste granne", + "FrmCrop.LblLocation": "Plats:", + "_._Download": "Hämta", + "_.Metadata._ColorProfile": "Färgprofil", + "FrmSettings._CenterWindowFit": "Centrera fönstret automatiskt när fönstret anpassas till skärmen", + "FrmSettings._ImageLoadingOrder": "Sortera bilder efter", + "FrmSettings._GalleryColumns": "Antal miniatyrbildskolumner i galleriet i lodrätt läge", + "_._Quit": "Avsluta", + "_._Add": "Lägg till", + "FrmMain.MnuChangeBackgroundColor": "Ändra bakgrundsfärg…", + "FrmMain.MnuToggleToolbar": "Verktygsfält", + "FrmAbout._Contact": "Kontakt", + "FrmSettings.Toolbar._AddCustomButton": "Lägg till en anpassad knapp…", + "FrmCrop.BtnQuickSelect._Tooltip": "Snabbval…", + "FrmMain.MnuCutFile._Success": "Klippte ut {0} fil(er).", + "FrmSettings._ZoomSpeed": "Zoomhastighet", + "FrmMain.MnuToggleTopMost._Disable": "Fönstret kommer inte längre ligga överst", + "FrmSettings._ShouldUseExplorerSortOrder": "Sortera om möjligt som Utforskaren", + "_.ImageInterpolation._Antisotropic": "Anisotropisk", + "FrmMain._ReachedFirstImage": "Detta är den första bilden i mappen", + "_._UnhandledException": "Ett okänt fel", + "FrmResize.LblNewSize": "Ny storlek:", + "FrmMain._ClipboardImage": "Bild från urklipp", + "FrmMain.MnuExportFrames": "Exportera bildrutor…", + "FrmMain.MnuFile": "Arkiv", + "_._Close": "Stäng", + "FrmMain.MnuMain": "Huvudmeny", + "_._ResetToDefault": "Återställ till standard", + "FrmSettings.Nav._Gallery": "Galleri", + "FrmMain.MnuSetDefaultPhotoViewer._Success": "ImageGlass är nu förvald bildvisare.", + "FrmSettings._HideGalleryInFullscreen": "Dölj galleriet i helskärmsläge", + "FrmSettings._AvailableImageInfoTags": "Valbara taggar:", + "FrmExportFrames._Exporting": "Exporterar {0}/{1} bildrutor \n{2}…", + "_._Argument": "Argument", + "FrmSettings._ImageEditQuality": "Bildkvalitet", + "_._ID": "ID", + "FrmSettings._UserConfigFile": "Fil för användarinställningar (igconfig.json)", + "FrmMain.MnuLoadingOrders": "Inläsningsordning", + "FrmSettings._OpenSaveAsDialogInTheCurrentImageDir": "Öppna dialogrutan Spara som i den aktuella bildkatalogen", + "_.MouseWheelEvent._ShiftAndScroll": "Håll Skift och skrollhjulet", + "FrmSettings._UseSmoothZooming": "Använd mjuk rullning", + "FrmSettings._Theme": "Tema", + "FrmSettings._ImageBoosterCacheMaxDimension": "Högsta bildupplösningen som ska cachas (i pixlar)", + "FrmMain.MnuScaleToHeight": "Anpassa till höjd", + "_.Metadata._FileLastWriteTime": "Senast ändrad", + "FrmSettings._Author": "Skapare", + "FrmSettings._Others": "Annat", + "_.MouseWheelAction._PanVertically": "Panorera uppåt eller neråt", + "FrmSettings._MouseWheelAction": "Mushjulets funktion", + "FrmSettings.Nav._Tools": "Verktyg", + "FrmMain.MnuSetDesktopBackground._Error": "Ett fel uppstod med att byta bildbakgrund till bilden som visas", + "FrmSettings.Toolbar._Errors._ButtonExecutableRequired": "Knappen kräver en körbar fil.", + "_.ImageOrderBy._DateAccessed": "Senast använd", + "FrmSettings._ThumbnailSize": "Storlek på miniatyrbilder (i pixlar)", + "FrmSettings._FileFormats": "Filformat", + "FrmMain.MnuReloadImageList": "Uppdatera bildlistan", + "FrmSettings._UseWebview2ForSvg": "Använd Webview2 för SVG-format", + "FrmCrop.BtnCopy": "Kopiera", + "FrmSettings._CurrentMonitorProfile._Description": "ImageGlass byter inte färgprofil automatiskt när fönstret förflyttas mellan olika skärmar", + "FrmMain.PicMain._ErrorText": "Bilden kunde inte öppnas", + "FrmSettings.Tools._AddNewTool": "Lägg till ett externt verktyg", + "FrmMain.MnuRename": "Byt namn på bild…", + "FrmMain.MnuViewLastFrame": "Se den sista bildrutan", + "_._Webview2._NotFound": "Installera den senaste versionen av WebView2 Runtime.", + "FrmMain.MnuGetMoreTools": "Hämta fler verktyg", + "FrmSettings.Nav._Appearance": "Utseende", + "FrmSettings._SlideshowInterval": "Bildspelsintervall:", + "_.ImageInterpolation._HighQualityBicubic": "Bikubisk (hög kvalitet)", + "FrmColorPickerSettings.ChkShowHsvA": "Använd HSV-format med alfakanal", + "FrmSettings.Tools._EditTool": "Ändra externt verktyg", + "_._Error": "Fel", + "FrmSettings._ImageBoosterCacheMaxFileSizeInMb": "Högsta filstorleken som ska cachas (i megabyte)", + "_._UnhandledException._Description": "Ett okänt fel har inträffat. Klicka på Fortsätt för att ignorera felet och försök att fortsätta. Klicka på Avsluta för att genast stänga av programmet.", + "_.Metadata._FileSize": "Filstorlek", + "FrmSettings.Toolbar._ButtonJson": "JSON-knapp", + "FrmQuickSetup._SetDefaultViewer._Description": "Detta val kan återställas i Inställningar under fliken Filassociationer.", + "FrmSettings.Nav._Edit": "Redigera", + "FrmMain.MnuToggleGallery": "Galleripanel", + "_._IgCommandExe._DefaultError._Description": "Se till att du använder rätt kommandon!\r\nDenna körbara fil innehåller kommandotolksfunktioner för ImageGlass.\r\n\r\nKommandotolkens alla funktioner beskrivs på:\n{0}", + "FrmMain.MnuLosslessCompression._Compressing": "Utför förlustfri komprimering…", + "FrmSettings._ShouldGroupImagesByDirectory": "Gruppera bilder efter mapp", + "FrmMain.MnuPanToRightSide": "Panorera längst till höger", + "_.Metadata._ExifRatingPercent": "Betyg", + "FrmSettings._PanSpeed": "Panoreringshastighet", + "_._CheckForUpdate": "Sök efter uppdateringar…", + "FrmSettings.Layout._ToolbarContext": "Kontextuellt verktygsfält", + "_.ImageInfo._FrameCount": "{0} bildrutor", + "FrmMain.MnuLayout": "Visa", + "_._Website": "Webbplats", + "FrmMain.MnuPasteImage": "Klistra in bild", + "FrmSettings._ShowGalleryScrollbars": "Visa rullningslist i galleriet" + } +} \ No newline at end of file diff --git a/Setup/Assets/Language/Thai.iglang.json b/Setup/Assets/Language/Thai.iglang.json new file mode 100644 index 000000000..fa2a6a950 --- /dev/null +++ b/Setup/Assets/Language/Thai.iglang.json @@ -0,0 +1,504 @@ +{ + "_Metadata": { + "Code": "th-TH", + "EnglishName": "Thai", + "LocalName": "ภาษาไทย", + "Author": "Jiraroj Leelarattanawong, Simon Leela", + "MinVersion": "9.1" + }, + "Items": { + "FrmCrop.SelectionAspectRatio._Original": "ต้นฉบับ", + "FrmMain.MnuShare._Error": "ไม่สามารถเปิดกล่องโต้ตอบ การแบ่งปัน", + "_.Metadata._FileLastAccessTime": "วันที่เข้าถึง", + "FrmAbout._License": "ลิขสิทธิ์ซอฟต์แวร์", + "FrmSettings.Toolbar._Errors._ButtonIdDuplicated": "ปุ่มหมายเลข '{0}' มีการกำหนดค่าแล้ว กรุณาเลือกหมายเลขอื่น และไม่ซ้ำกันสำหรับปุ่มของคุณเพื่อหลีกเลี่ยงการซ้ำซ้อน", + "FrmMain.MnuSave._Confirm": "คุณแน่ใจว่าต้องการแทนที่รูปภาพนี้?", + "FrmSettings._OpenDefaultAppsSetting": "เปิดการตั้งค่าเริ่มต้นแอป", + "FrmMain.MnuCopyPath": "คัดลอกที่อยู่รูปภาพ", + "FrmCropSettings.DefaultSelectionType._SelectNone": "ยกเลิกทั้งหมด", + "_.MouseWheelAction._PanHorizontally": "แพนซ้าย / ขวา", + "FrmMain.MnuPrint": "พิมพ์...", + "FrmSettings.Toolbar._ToolbarButtons": "ปุ่มแถบเครื่องมือ", + "FrmResize.LblResample": "Resample:", + "_.ImageOrderBy._Extension": "นามสกุลไฟล์", + "FrmSettings.Nav._Viewer": "ตัวแสดงภาพ", + "FrmSettings.EditAppDialog._EditApp": "แก้ไขแอป", + "FrmCrop.BtnReset._Tooltip": "เริ่มการเลือกใหม่", + "FrmMain.MnuRename._Description": "ระบุชื่อไฟล์ใหม่:", + "_._No": "No", + "FrmSlideshow.MnuToggleCountdown": "แสดงเวลาคงเหลือสไลด์โชว์", + "FrmSettings._OpenStartupAppsSetting": "เปิดการตั้งค่าแอปเริ่มต้น", + "FrmMain.MnuViewPreviousFrame": "ดูเฟรมก่อนหน้า", + "_.ImageOrderBy._DateModified": "วันที่แก้ไข", + "FrmMain.MnuViewNextFrame": "ดูเฟรมถัดไป", + "FrmMain.MnuUnload": "ยกเลิกการโหลดภาพ", + "FrmSettings.Toolbar._HideToolbarInFullscreen": "ซ่อนแถบเครื่องมือในโหมดเต็มหน้าจอ", + "_.ImageOrderType._Desc": "มากไปน้อย", + "_._Update": "อัปเดต", + "FrmSettings._EnableImageAsyncLoading": "เปิดระบบโหลดภาพแบบแยกอิสระ", + "FrmSettings._DefaultPhotoViewer._Description": "ลงทะเบียนรูปแบบที่ ImageGlass รองรับกับ Windows คุณต้องเปิดการตั้งค่าแอปเริ่มต้น และเลือก ImageGlass จากรายการที่แสดงเพื่อเปิดการใช้งาน", + "_.MouseWheelAction._BrowseImages": "ดูรูปภาพถัดไป / ก่อนหน้า", + "FrmSettings._EditApps": "แอปแก้ไขรูปภาพ", + "FrmColorPickerSettings.ChkShowCIELabA": "ใช้รูปแบบ CIELAB พร้อมกับค่า alpha", + "_._GetHelp": "รับความช่วยเหลือ", + "FrmQuickSetup._SkipQuickSetup": "ข้ามและเปิดการใช้งาน ImageGlass", + "FrmColorPickerSettings._Title": "การตั้งค่าตัวเลือกสี", + "_._Copy": "คัดลอก", + "FrmSettings._ImageBoosterCacheCount": "จำนวนรูปภาพที่สำรองไว้โดย Image Booster (ทิศทางเดียว)", + "FrmMain.MnuPanToBottom": "แพนรูปภาพไปล่างสุด", + "FrmMain.MnuZoom": "ซูม", + "FrmCropSettings.ChkCloseToolAfterSaving": "ปิดเครื่องมือการครอบตัดหลังจากบันทึกแล้ว", + "FrmSettings._ShowWelcomeImage": "แสดงรูปภาพต้อนรับ", + "FrmSettings._ColorProfile": "โปรไฟล์สี", + "FrmSettings._Theme._UninstallTheme": "ถอนการติดตั้งธีมแพ็ค", + "FrmMain._OpenWith": "เปิดด้วย {0}", + "FrmMain.MnuRemoveDefaultPhotoViewer": "ยกเลิกโปรแกรมดูภาพเริ่มต้น", + "_.AfterEditAppAction._Nothing": "ไม่เปลี่ยนแปลง", + "FrmCrop.BtnSave": "บันทึก", + "FrmMain.MnuScaleToFit": "ปรับให้พอดี", + "FrmToolNotFound.LblDownloadToolText": "คุณสามารถดาวน์โหลดเครื่องมืออื่น ๆ สำหรับ ImageGlass ได้ที่:", + "_._LearnMore": "เรียนรู้เพิ่มเติม…", + "FrmCrop.LblAspectRatio": "อัตราส่วนภาพ:", + "FrmExportFrames._FileNotExist": "ไม่มีไฟล์รูปภาพ", + "FrmSettings._LightTheme": "สว่าง", + "FrmSettings.Nav._Slideshow": "สไลด์โชว์", + "_._Continue": "ดำเนินการต่อ", + "_._AddHotkey": "เพิ่มคีย์ด่วน...", + "FrmMain.MnuSetDesktopBackground": "ตั้งเป็นภาพพื้นหลังเดสก์ท็อป", + "FrmMain.MnuReload": "โหลดรูปภาพอีกครั้ง", + "FrmSlideshow.MnuExitSlideshow": "ออกจากสไลด์โชว์", + "FrmMain.MnuAutoZoom": "ซูมอัตโนมัติ", + "FrmSettings._ShowImagePreview": "แสดงภาพตัวอย่างขณะโหลด", + "FrmCrop.BtnCopy._Tooltip": "คัดลอกที่เลือกไปยังคลิปบอร์ด", + "FrmSettings.Nav._Toolbar": "แถบเครื่องมือ", + "FrmMain.MnuSave._Error": "ไม่สามารถบันทึกรูปภาพได้", + "FrmSettings._AfterEditingAction": "หลังจากเปิดโปรแกรมปรับแต่งรูปภาพ", + "FrmSettings._ShouldUseColorProfileForAll": "นำไปใช้กับรูปภาพโดยไม่ต้องฝังโปรไฟล์สี", + "FrmCropSettings.DefaultSelectionType._UseTheLastSelection": "ใช้การเลือกครั้งก่อน", + "FrmSettings._SlideshowInterval._From": "ตั้งแต่", + "FrmSettings._ImageInterpolation": "การแก้ไขภาพ", + "FrmQuickSetup._StepInfo": "ขั้นตอน {0}", + "FrmMain.MnuColorPicker": "ตัวดูดสี", + "FrmCrop.SelectionAspectRatio._FreeRatio": "อัตราส่วนอิสระ", + "FrmSettings._ResetSettings": "คืนการตั้งค่าใหม่", + "FrmSettings._Startup": "การเริ่มต้นทำงาน", + "_.BackdropStyle._None": "ไม่มี", + "FrmSettings._LoadDefaultZoomLevels": "โหลดระดับการซูมเริ่มต้น", + "FrmColorPicker.BtnSettings._Tooltip": "เปิดการตั้งค่าตัวเลือกสี...", + "FrmSettings._UseThemeForDarkMode": "ใช้ธีมนี้กับโหมดมืด", + "FrmSettings._ShowDeleteConfirmation": "แสดงหน้าต่างยืนยันเมื่อมีการลบไฟล์", + "FrmSettings._ShowAppIcon": "แสดงแอปไอคอนบนแถบไตเติ้ล", + "_._InvalidAction": "คำสั่งไม่ถูกต้อง", + "FrmQuickSetup._SelectProfile": "เลือกโปรไฟล์", + "_.Metadata._FileCreationTime": "วันที่สร้าง", + "FrmSettings._SlideshowImagesToNotifySound": "จำนวนรูปภาพที่ใช้กระตุ้นเสียงการแจ้งเตือน", + "FrmSettings._BackgroundColor": "สีพื้นหลังตัวแสดงภาพ", + "FrmSettings._RealTimeFileUpdate": "อัปเดตไฟล์แบบเรียลไทม์", + "_.ColorProfileOption._CurrentMonitorProfile": "โปรไฟล์มอนิเตอร์ปัจจุบัน", + "FrmSettings._EnableCutMultipleFiles": "เปิดระบบการตัดหลายไฟล์ในคราวเดียว", + "FrmSettings._AutoUpdate": "ตรวจหาอัพเดทอัตโนมัติ", + "FrmCropSettings.LblDefaultSelection": "การเลือกเริ่มต้น", + "FrmSettings._UseThemeForLightMode": "ใช้ธีมนี้สำหรับโหมดสว่าง", + "FrmSettings._ZoomLevels": "ระดับการซูม", + "FrmMain.MnuSetLockScreen._Success": "ภาพล็อกหน้าจออัปเดตแล้ว", + "FrmSettings._ShowGalleryFileName": "แสดงชื่อไฟล์ภาพขนาดย่อ", + "FrmSettings.Layout._Order": "ลำดับ", + "FrmCropSettings.ChkAutoCenterSelection": "เลือกกึ่งกลางอัตโนมัติ", + "FrmSettings.Nav._FileTypeAssociations": "ประเภทไฟล์ที่ใช้ร่วมกัน", + "_._Back": "กลับ", + "FrmMain.MnuSetDesktopBackground._Success": "ภาพพื้นหลังอัปเดทแล้ว", + "FrmSettings._ShouldAutoOpenNewAddedImage": "เปิดรูปภาพเพิ่มใหม่อัตโนมัติ", + "FrmCrop.SelectionAspectRatio._Custom": "ปรับแต่ง...", + "FrmMain.MnuCopyPath._Success": "คัดลอกตำแหน่งรูปภาพปัจจุบันแล้ว", + "FrmSettings._StartupBoost._Error": "ไม่สามารถเปลี่ยนแปลงการตั้งค่า Startup Boost", + "FrmToolNotFound.LblDescription": "ImageGlass ไม่สามารถระบุตำแหน่งไฟล์ปฏิบัติการ '{0}' ในการแก้ไขปัญหานี้, กรุณาอัปเดตตำแหน่ง '{0}' ที่จำเป็น", + "FrmMain.MnuClearClipboard": "ล้างคลิปบอร์ด", + "FrmSettings._ColorManagement": "การจัดการสี", + "FrmMain._ReachedLastLast": "ถึงรูปภาพสุดท้ายแล้ว", + "FrmMain.MnuPanUp": "แพนรูปภาพขึ้น", + "FrmMain.MnuRemoveDefaultPhotoViewer._Success": "ImageGlass ไม่ได้เป็นแอปดูภาพเริ่มต้นแล้ว", + "FrmSettings._GetMoreLanguagePacks": "รับชุดภาษาเพิ่มเติม…", + "FrmAbout._Privacy": "นโยบายความเป็นส่วนตัว", + "FrmSettings._EnableRecursiveLoading": "โหลดรูปภาพในแฟ้มย่อย", + "_._UserAction._MethodArgumentNotSupported": "ประเภทตัวแปรของวิธีการ '{0}' ไม่รองรับ", + "FrmSettings._FileExtensionIcons._Description": "ในการปรับแต่งไอคอนไฟล์ ให้ดาวน์โหลดชุดไอคอน แล้ววางไฟล์ .ICO ทั้งหมดในแฟ้มไอคอน และคลิกที่ปุ่ม '{0}' ขั้นตอนนี้จะตั้ง ImageGlass เป็นแอปดูรูปภาพเริ่มต้นด้วย", + "_.ImageOrderType._Asc": "น้อยไปมาก", + "FrmExportFrames._Title": "ส่งออกเฟรมรูปภาพ", + "_._Install": "ติดตั้ง…", + "FrmMain.MnuFlipHorizontal": "พลิกตามแนวนอน", + "FrmSettings._OpenExtensionIconFolder": "เปิดแฟ้มไอคอน", + "FrmAbout._Collaborator": "ผู้ทำงานร่วมกัน:", + "FrmQuickSetup._ConfirmCloseProcess": "ก่อนนำการตั้งค่าใหม่ไปใช้ จำเป็นต้องปิด ImageGlass ลงก่อน คุณต้องการดำเนินการ?", + "FrmExportFrames._ExportDone": "ส่งออก {0} เฟรมไปยัง \n{1} เรียบร้อยแล้ว", + "FrmCrop.BtnSaveAs._Tooltip": "บันทึกเป็นสำเนา...", + "FrmMain.MnuOpenFile": "เปิดไฟล์...", + "FrmColorPickerSettings.ChkShowRgbA": "ใช้รูปแบบ RGB ด้วยค่า alpha", + "_.ImageInfo._ListCount": "{0} ไฟล์", + "FrmMain.MnuGoToLast": "ไปยังรูปภาพสุดท้าย", + "FrmSettings._EditApps._AppName": "ชื่อแอป", + "FrmSettings._SlideshowBackgroundColor": "สีพื้นหลังสไลด์โชว์", + "FrmAbout._Email": "อีเมล:", + "_.MouseWheelAction._DoNothing": "ไม่ต้องทำอะไร", + "FrmMain.MnuSaveAs": "บันทึกเป็น…", + "FrmMain._Loading": "กำลังโหลด…", + "_._Browse": "ค้นหา...", + "FrmMain.MnuSetDefaultPhotoViewer._Error": "ไม่สามารถตั้ง ImageGlass เป็นแอปดูรูปภาพเริ่มต้น", + "FrmSettings.Nav._Language": "ภาษา", + "FrmQuickSetup._SeeWhatNew": "ดูฟีเจอร์ใหม่ในเวอร์ชั่นนี้...", + "FrmSettings._ImageInterpolation._ScaleUp": "เมื่อซูม > 100%", + "FrmSettings.Layout._ToolbarContextPosition": "ตำแหน่งแถบเครื่องมือย่อย", + "FrmMain.MnuDeleteFromHardDisk": "ลบถาวร", + "FrmSettings._EmbeddedThumbnail": "รูปภาพย่อแบบฝัง", + "FrmMain.MnuDeleteFromHardDisk._Description": "คุณแน่ใจว่าต้องการลบไฟล์นี้ถาวร?", + "FrmMain.MnuScaleToFill": "ปรับให้เต็ม", + "FrmCrop.BtnCrop": "ครอบรูป", + "_.AfterEditAppAction._Minimize": "ย่อหน้าลง", + "FrmMain.MnuInvertColors": "Invert colors", + "FrmSettings._StartupBoost": "Startup Boost", + "FrmMain.MnuViewFirstFrame": "ดูเฟรมแรกสุด", + "_.MouseWheelEvent._CtrlAndScroll": "กดปุ่ม Ctrl แล้วเลื่อน", + "FrmSettings._HideMainWindowInSlideshow": "ซ่อนหน้าต่างหลักอัตโนมัติ", + "_.Metadata._FrameCount": "เฟรม", + "FrmSettings._EnableCopyMultipleFiles": "เปิดระบบคัดลอกหลายไฟล์ในครั้งเดียว", + "FrmMain.MnuFrameless._EnableDescription": "กดปุ่ม Shift ค้างไว้เพื่อเคลื่อนย้ายหน้าต่าง", + "_.ImageOrderBy._ExifDateTaken": "EXIF: Date taken", + "FrmAbout._Credits": "เครดิต", + "FrmSettings._AddNewFileExtension": "เพิ่มส่วนขยายไฟล์ใหม่", + "FrmMain.MnuQuickSetup": "เปิดการตั้งค่าด่วน ImageGlass", + "FrmMain.MnuSave._Success": "บันทึกรูปภาพแล้ว", + "FrmMain.MnuPanLeft": "แพนรูปภาพไปทางซ้าย", + "FrmUpdate._StatusChecking": "ตรวจสอบการอัปเดต...", + "FrmSettings.Nav._Layout": "แผนผัง", + "FrmMain.MnuOpenWith": "เปิดด้วย...", + "FrmAbout._Thanks": "ขอขอบคุณเป็นพิเศษกับ", + "_._Warning": "คำเตือน", + "FrmSettings.Nav._Keyboard": "คีย์บอร์ด", + "FrmSlideshow._PauseSlideshow": "สไลด์โชว์หยุดชั่วคราว.", + "_._Add+": "เพิ่ม…", + "_._Email": "อีเมล", + "FrmMain.MnuPanDown": "แพนรูปภาพลงด้านล่าง", + "_._Cancel": "ยกเลิก", + "_._OK": "ตกลง", + "FrmMain.MnuPanRight": "แพนรูปภาพไปทางขวา", + "_.Position._Right": "ขวา", + "_._Icon": "ไอคอน", + "FrmSettings._ShouldLoadHiddenImages": "โหลดรูปภาพซ่อน", + "_._InvalidAction._Transformation": "ImageGlass ไม่รองรับการหมุน การพลิกรูปภาพนี้", + "FrmSettings._MakeDefault": "ทำให้เป็นค่าเริ่มต้น", + "FrmMain.MnuCopyImageData._Copying": "กำลังคัดลอกข้อมูลรูปภาพ ขั้นตอนนี้ต้องรอสักพัก...", + "FrmSettings._UseEmbeddedThumbnailRawFormats": "โหลดรูปภาพย่อแบบฝังสำหรับรูปภาพ RAW", + "_.ImageInterpolation._Linear": "เชิงเส้น", + "FrmSettings._ImageInfoTags": "แท็กข้อมูลรูปภาพ", + "FrmSettings._FileExtensionIcons": "ไอคอนส่วนขยายไฟล์", + "FrmMain.MnuEdit._AppNotFound": "ไม่พบโปรแกรมใช้ร่วมกันในการแก้ไขรูปภาพ คุณสามารถระบุโปรแกรมแก้ไขรูปภาพสำหรับไฟล์ประเภทนี้ใน การตั้งค่า ImageGlass > แก้ไข", + "_.ColorProfileOption._None": "ไม่มี", + "FrmSettings._TotalSupportedFormats": "รูปแบบที่รองรับทั้งหมด: {0}", + "FrmSettings._Clipboard": "คลิปบอร์ด", + "_._UserAction._Win32ExeError": "ไม่สามารถรันคำสั่ง '{0}' ได้ ให้แน่ใจว่าชื่อถูกต้อง", + "FrmCropSettings.DefaultSelectionType._SelectX": "เลือก {0}", + "_.AfterEditAppAction._Close": "ปิด", + "FrmAbout._LogoDesigner": "โลโก้ผู้ออกแบบ:", + "_.ImageOrderBy._Name": "ชื่อ (ค่าเริ่มต้น)", + "FrmMain.MnuRemoveDefaultPhotoViewer._Error": "ไม่สามารถยกเลิก imageGlass จากแอปดูรูปภาพเริ่มต้นได้", + "FrmExportFrames._FolderPickerTitle": "เลือกแฟ้มปลายทางเพื่อส่งออกเฟรมรูปภาพ", + "FrmAbout._Donate": "บริจาค", + "FrmMain.MnuFrameNav": "สำรวจเฟรมรูปภาพ", + "FrmMain.MnuSetLockScreen": "ตั้งเป็นภาพล็อกหน้าจอ", + "_._Delete": "ลบ", + "FrmMain.MnuViewPrevious": "ดูรูปภาพก่อนหน้า", + "_.Position._Top": "บน", + "FrmSettings.Toolbar._CurrentButtons": "ปุ่มปัจจุบัน:", + "FrmMain.MnuAbout": "เกี่ยวกับ", + "FrmSettings._RemoveDefault": "ยกเลิกค่าเริ่มต้น", + "_._Description": "รายละเอียด", + "FrmMain.MnuPasteImage._Error": "ไม่พบข้อมูลรูปภาพในคลิปบอร์ด", + "FrmMain.MnuSettings": "การตั้งค่า", + "FrmCropSettings._Title": "การตั้งค่าครอบตัด", + "FrmSettings.Toolbar._ToolbarIconHeight": "ขนาดไอคอนแถบเครื่องมือ", + "FrmSettings._SlideshowInterval._To": "ถึง", + "FrmSettings.Layout._ToolbarPosition": "ตำแหน่งแถบเครื่องมือ", + "FrmUpdate._StatusUpdated": "คุณใช้เวอร์ชั่นล่าสุดแล้ว!", + "FrmMain.MnuExit": "ออก", + "_._Webview2._Outdated": "Your WebView2 Runtime is not supported. Please update to version {0} or later.", + "_._Yes": "ใช่", + "FrmMain.MnuRotateLeft": "หมุนซ้าย", + "FrmSettings._EnableStartupBoost": "เปิดระบบการเริ่มต้นด่วน", + "_.ImageOrderBy._ExifRating": "EXIF: Rating", + "FrmMain.MnuZoomIn": "ซูมเข้า", + "_.Metadata._ColorSpace": "พื้นที่สี", + "FrmAbout._Version": "เวอร์ชั่น:", + "FrmMain.MnuToggleTopMost._Enable": "เปิดระบบหน้าต่างอยู่บนสุดตลอดเวลาแล้ว", + "FrmSettings.Toolbar._AvailableButtons": "ปุ่มที่มี:", + "FrmMain.MnuSave._Saving": "กำลังบันทึกรูปภาพ...", + "FrmQuickSetup._StandardUser": "ผู้ใช้ทั่วไป", + "FrmMain.MnuSetLockScreen._Error": "ไม่สามารถตั้งรูปภาพนี้เป็นภาพล็อกหน้าจอ", + "FrmSettings.Nav._Image": "รูปภาพ", + "FrmSettings._Theme._InstallTheme": "ติดตั้งธีมแพ็ค", + "FrmSettings._EnableMultiInstances": "อนุญาตให้เปิดโปรแกรมหลายหน้าต่าง", + "FrmMain.MnuCropTool": "ครอบตัดรูปภาพ", + "_._IgCommandExe._DefaultError._Heading": "คำสั่งไม่ถูกต้อง", + "_._Refresh": "รีเฟรช", + "FrmMain.MnuLosslessCompression._Description": "เครื่องมือนี้ใช้ไลบรารี Magick.NET สำหรับการบีบอัดแบบไม่สูญเสีย และการปรับขนาดไฟล์ เขียนทับได้ก็ต่อเมื่อไฟล์บีบอัดมีขนาดเล็กกว่าต้นฉบับ", + "_._MoveDown": "เลื่อนลง", + "FrmSettings._GetExtensionIconPacks": "รับส่วนขยายไอคอน", + "FrmSettings._InAppMessageDuration": "ระยะเวลาแสดงข้อความในแอป (มิลลิวินาที)", + "FrmMain.MnuFrameless": "ไร้กรอบ", + "_._Reset": "รีเซ็ต", + "FrmSettings._ConfigDir": "ตำแหน่งการตั้งค่า", + "FrmQuickSetup._SettingsWillBeApplied": "การตั้งค่าที่จะนำไปใช้:", + "FrmSettings._UnmanagedSettingReminder": "การตั้งค่านี้ไม่ได้ถูกจัดการโดย ImageGlass ปิดระบบนี้ก่อนที่คุณลบหรือย้ายแอป เพราะ ImageGlass ไม่ได้จัดการเรื่องนี้อัตโนมัติ", + "FrmMain.MnuClipboard": "คลิปบอร์ด", + "FrmMain.MnuCustomZoom": "กำหนดค่าการซูม…", + "FrmSettings._DisplayLanguage": "ภาษาที่แสดง", + "FrmMain.MnuPrint._Error": "ไม่สามารถพิมพ์รูปภาพที่กำลังดูอยู่", + "FrmSettings._ShouldPreserveModifiedDate": "คงรักษาวันที่ของรูปภาพที่แก้ไขเมื่อบันทึก", + "FrmSettings._ShowSaveOverrideConfirmation": "แสดงหน้าต่างยืนยันเมื่อมีการเขียนทับไฟล์", + "FrmColorPickerSettings.ChkShowHexA": "ใช้รูปแบบ HEX ด้วยค่า alpha", + "FrmMain.MnuFullScreen": "เต็มหน้าจอ", + "FrmSettings._StartupDir": "ตำแหน่งเริ่มต้น", + "FrmSettings._ShowCheckerboardOnlyImageRegion": "แสดงลายกระดานหมากรุกภายในพื้นที่รูปภาพ", + "FrmMain.MnuClearClipboard._Success": "ล้างคลิปบอร์ดแล้ว", + "FrmQuickSetup._Text": "ตั้งค่า ImageGlass ด่วน", + "FrmMain.MnuLosslessCompression._Done": "บีบอัดแบบไม่สูญเสียเรียบร้อย\r\nขนาดไฟล์ใหม่ คือ {0}, บันทึกแล้ว {1}", + "FrmMain.MnuLosslessCompression": "การบีบอัด Magick.NET Lossless", + "FrmResize.RadResizeByPercentage": "Percentage", + "FrmSettings._StartupBoost._Disabled": "การเริ่มต้นด่วนถูกปิดอยู่", + "FrmMain.MnuToggleCheckerboard": "พื้นหลังลายกระดานหมากรุก", + "FrmSettings._MinEmbeddedThumbnailSize._Height": "ความสูง", + "FrmSettings.Nav._General": "ทั่วไป", + "FrmSettings._ImageLoading": "กำลังโหลดรูปภาพ", + "FrmSettings._ShowSlideshowCountdown": "แสดงเวลาคงเหลือสไลด์โชว์", + "FrmMain.MnuSave": "บันทึก", + "FrmMain.MnuMoveToRecycleBin": "ย้ายไปถังขยะ", + "FrmMain.MnuRefresh": "รีเฟรช", + "FrmToolNotFound.LblHeading": "ไม่พบ '{0}'!", + "FrmMain.MnuReportIssue": "รายงานปัญหา...", + "FrmMain.MnuCopyImageData": "คัดลอกข้อมูลรูปภาพ", + "FrmMain.MnuCheckForUpdate._NewVersion": "พบเวอร์ชั่นใหม่!", + "_._Empty": "(ว่าง)", + "FrmSettings._Zooming": "การซูม", + "FrmMain.MnuCutFile": "ตัดไฟล์", + "FrmHotkeyPicker.LblHotkey": "กดปุ่มคีย์ด่วน", + "FrmSettings.Layout._Gallery": "คลังภาพ", + "FrmMain.MnuNewWindow": "เปิดหน้าต่างใหม่", + "FrmMain.MnuMoveToRecycleBin._Description": "คุณต้องการย้ายไฟล์นี้ไปถังขยะใช่หรือไม่?", + "FrmSettings._DefaultPhotoViewer": "แอปแสดงรูปเริ่มต้น", + "_.Metadata._ExifDateTimeOriginal": "EXIF: DateTimeOriginal", + "FrmMain.MnuRotateRight": "หมุนขวา", + "FrmSettings._MinEmbeddedThumbnailSize": "ขนาดเล็กสุดของรูปภาพย่อแบบฝังที่ต้องโหลด", + "FrmMain.MnuSetDefaultPhotoViewer": "ตั้งแอปดูรูปภาพเริ่มต้น", + "FrmMain.MnuImageProperties": "คุณสมบัติรูปภาพ", + "FrmSettings._EnableNavigationButtons": "แสดงปุ่มทิศทาง", + "_._Edit": "แก้ไข", + "FrmSettings._ImageBooster": "Image Booster", + "FrmSettings.Tools._IntegratedWith": "ผนวกกับ {0}", + "_._Next": "ถัดไป", + "FrmExportFrames._OpenOutputFolder": "เปิดแฟ้มปลายทาง", + "FrmMain.MnuOpenLocation": "เปิดตำแหน่งที่อยู่รูปภาพ", + "FrmMain.MnuLockZoom": "ล็อกขนาดซูม", + "FrmSettings._StartupBoost._Description": "โหลดล่วงหน้าและเปิด ImageGlass เบื้องหลังก่อนในระหว่างเริ่มต้น Windows เพื่อเร่งการทำงานในครั้งแรก", + "FrmSettings._WindowBackdrop": "ฉากหลังหน้าต่าง", + "FrmSettings._EnableRealTimeFileUpdate": "เฝ้าดูการเปลี่ยนแปลงในแฟ้มดูภาพและอัปเดตเรียลไทม์", + "_._NotSupported": "ไม่รองรับไฟล์ประเภทนี้", + "FrmSettings._Theme._GetMoreThemes": "รับธีมแพ็คเพิ่มเติม...", + "FrmMain.MnuNewWindow._Error": "ไม่สามารถเปิดหน้าต่างใหม่ได้เพราะสามารถได้ทีละหน้าต่าง", + "FrmMain.MnuZoomOut": "ซูมออก", + "FrmSettings.Toolbar._EditButton": "แก้ไขปุ่มแถบเครื่องมือ", + "FrmMain.MnuCustomZoom._Description": "กรอกค่าการซูมใหม่", + "FrmResize.RadResizeByPixels": "Pixels", + "FrmMain.MnuEdit": "แก้ไขรูปภาพ {0}", + "FrmSettings.Layout._GalleryPosition": "ตำแหน่งแกลลอรี่", + "FrmMain.MnuWindowFit": "พอดีหน้าต่าง", + "FrmMain._OpenFileDialog": "ไฟล์ที่รองรับทั้งหมด", + "FrmSettings._UseRandomIntervalForSlideshow": "หน่วงเวลาแบบสุ่ม", + "_.Position._Left": "ซ้าย", + "FrmSettings._ShouldOpenLastSeenImage": "เปิดรูปภาพครั้งก่อน", + "_.Position._Bottom": "ล่าง", + "FrmResize.ChkKeepRatio": "Keep ratio propotional", + "FrmMain.MnuGoTo": "ไปยัง...", + "FrmSlideshow.MnuPauseResumeSlideshow": "หยุดชั่วคราว/เล่นต่อ สไลด์โชว์", + "FrmSettings.Tools._Integrated": "ผนวกแล้ว", + "FrmSettings._Contributors": "ผู้ร่วมสนับสนุน", + "_.MouseWheelAction._Zoom": "ซูมเข้า / ออก", + "_._CommandPreview": "ตัวอย่างคำสั่ง", + "FrmSettings._DarkTheme": "เข้ม", + "_._Hotkeys": "คีย์ด่วน", + "_.Metadata._ExifDateTime": "EXIF: DateTime", + "FrmSettings.Toolbar._Errors._ButtonIdRequired": "ปุ่มจำเป็นต้องมีหมายเลข", + "FrmSettings._MinEmbeddedThumbnailSize._Width": "ความกว้าง", + "_._Executable": "ดำเนินการได้", + "_.ImageInterpolation._MultiSampleLinear": "ตัวอย่างหลากหลายเชิงเส้น", + "_._Separator": "ตัวแบ่ง", + "FrmQuickSetup._ProfessionalUser": "ผู้ใช้มืออาชีพ", + "FrmMain.MnuFlipVertical": "พลิกตามแนวตั้ง", + "FrmSlideshow._ResumeSlideshow": "สไลด์โชว์เล่นต่อ.", + "FrmCropSettings.DefaultSelectionType._CustomArea": "พื้นที่ปรับแต่ง...", + "FrmMain.MnuActualSize": "ขนาดจริง", + "FrmCrop.BtnSaveAs": "บันทึกเป็น…", + "FrmSettings._InstallNewLanguagePack": "ติดตั้งชุดภาษาใหม่...", + "FrmSlideshow.MnuZoomModes": "โหมดการซูม", + "FrmMain.MnuTools": "เครื่องมือ", + "_.ImageInterpolation._Cubic": "ลูกบาศก์", + "FrmUpdate._LatestVersion": "เวอร์ชั่นล่าสุด: {0}", + "FrmMain.MnuViewNext": "ดูรูปภาพถัดไป", + "_.MouseWheelEvent._AltAndScroll": "กดปุ่ม Alt แล้วเลื่อน", + "FrmToolNotFound._Title": "ไม่พบเครื่องมือ", + "FrmCrop.BtnCrop._Tooltip": "ครอบเฉพาะรูปภาพ", + "FrmSettings.EditAppDialog._AddApp": "เพิ่มแอปสำหรับการแก้ไข", + "FrmMain.MnuPanning": "การแพนภาพ", + "_._MoveUp": "เลื่อนขึ้น", + "FrmCropSettings.DefaultSelectionType._SelectAll": "เลือกทั้งหมด", + "_._Name": "ชื่อ", + "FrmColorPickerSettings.ChkShowHslA": "ใช้รูปแบบ HSL ด้วยค่า alpha", + "FrmMain.MnuToggleImageAnimation": "เล่น / หยุดภาพเคลื่อนไหว", + "FrmSettings._DisableStartupBoost": "ปิด Startup Boost", + "FrmMain.MnuCopyFile._Success": "คัดลอก {0} ไฟล์(s).", + "FrmMain.MnuSave._ConfirmDescription": "ImageGlass ไม่ใช่โปรแกรมแก้ไขรูปภาพมืออาชีพ กรุณาพึงระวังการสูญเสียคุณภาพ, ข้อมูลรูปภาพ, เลเยอร์,... เมื่อทำการบันทึกรูปภาพ", + "FrmToolNotFound.BtnSelectExecutable": "เลือก...", + "FrmUpdate._StatusOutdated": "มีเวอร์ชั่นใหม่!", + "_.ImageOrderBy._Random": "สุ่ม", + "FrmResize.LblCurrentSize": "Current Size:", + "_._Apply": "นำไปใช้", + "FrmAbout._Slogan": "โปรแกรมดูภาพขนาดเบา และอเนกประสงค์", + "FrmMain.MnuPanToTop": "แพนรูปภาพไปบนสุด", + "FrmSettings.Toolbar._AddNewButton": "เพิ่มปุ่มแถบเครื่องมือสร้างเอง", + "FrmCrop.LblSize": "ขนาด:", + "FrmSettings._ImageInterpolation._ScaleDown": "เมื่อซูม < 100%", + "_._CreatingFileError": "ไม่สามารถสร้างไฟล์รูปภาพชั่วคราวได้", + "FrmMain.MnuGoTo._Description": "ระบุเลขรูปภาพเพื่อแสดง แล้วกดปุ่ม ENTER", + "FrmSettings.Toolbar._EnableCenterToolbar": "ใช้การวางกึ่งกลางสำหรับแถบเครื่องมือ", + "FrmMain.MnuResizeTool": "Resize image", + "FrmSettings.Layout._Toolbar": "แถบเครื่องมือ", + "FrmMain.MnuHelp": "ช่วยเหลือ", + "_.ImageOrderBy._FileSize": "ขนาดไฟล์", + "FrmSettings._Theme._OpenThemeFolder": "เปิดแฟ้มธีม", + "FrmMain.MnuNavigation": "นำไปยัง", + "_._Save": "บันทึก", + "FrmQuickSetup._SettingProfileDescription": "ในการแก้ไขการตั้งค่าเหล่านี้ เพียงเข้าไปที่การตั้งค่าแอป", + "_._UserAction._MenuNotFound": "ไม่พบเมนู '{0}' เพื่อเรียกคืนคำสั่ง", + "FrmMain.MnuPanToLeftSide": "แพนรูปภาพไปทางฝั่งซ้าย", + "FrmUpdate._CurrentVersion": "เวอร์ชั่นปัจจุบัน: {0}", + "FrmCrop.BtnSettings._Tooltip": "เปิดการตั้งค่าครอบรูป", + "_.ColorProfileOption._Custom": "ปรับแต่ง...", + "FrmSettings._UseEmbeddedThumbnailOtherFormats": "โหลดเฉพาะรูปภาพย่อแบบฝังสำหรับรูปแบบอื่น", + "FrmMain.MnuGoToFirst": "ไปรูปภาพแรก", + "FrmSettings._ExportLanguagePack": "ส่งออกชุดภาษา...", + "FrmSettings.Nav._Mouse": "เมาส์", + "_.ImageOrderBy._DateCreated": "วันที่สร้าง", + "FrmSettings._EnableFullscreenSlideshow": "เริ่มสไลด์โชว์แบบเต็มหน้าจอ", + "FrmAbout._Homepage": "โฮมเพจ:", + "FrmSettings._GalleryCacheSizeInMb": "ขนาดสำรองแกลลอรี่สูงสุด (เป็นเมกะไบต์)", + "FrmMain.MnuCopyImageData._Success": "คัดลอกข้อมูลรูปภาพปัจจุบันแล้ว", + "FrmSettings._EnableLoopBackNavigation": "วนกลับไปรูปภาพแรกเมื่อถึงรูปภาพสุดท้ายของรายการ", + "_.MouseWheelEvent._Scroll": "เลื่อน", + "FrmCrop.BtnSave._Tooltip": "บันทึกรูปภาพ", + "FrmMain.MnuSlideshow": "สไลด์โชว์", + "FrmMain.MnuShare": "แชร์...", + "FrmSettings._SlideshowNotification": "การแจ้งเตือนสไลด์โชว์", + "FrmMain.MnuViewChannels": "ดูโหมดสี", + "FrmSettings._Refresh": "รีเฟรช", + "_._UserAction._MethodNotFound": "ไม่พบวิธีการ '{0}' เพื่อเรียกคืนคำสั่ง", + "FrmMain.MnuCopyFile": "คัดลอกไฟล์", + "_._CreatingFile": "กำลังสร้างไฟล์รูปภาพชั่วคราว...", + "FrmMain.MnuToggleTopMost": "หน้าต่างอยู่บนสุดเสมอ", + "FrmMain.MnuLosslessCompression._Confirm": "คุณต้องการดำเนินการ?", + "FrmMain.MnuImage": "รูปภาพ", + "FrmSettings._StartupBoost._Enabled": "เปิดระบบ Startup Boost แล้ว", + "FrmQuickSetup._SetDefaultViewer": "คุณต้องการตั้ง ImageGlass เป็นแอปดูรูปภาพเริ่มต้น?", + "FrmMain.MnuScaleToWidth": "ปรับพอดีความกว้าง", + "_._FileExtension": "นามสกุลไฟล์", + "FrmUpdate._PublishedDate": "เผยแพร่เมื่อ: {0}", + "_._DoNotShowThisMessageAgain": "ไม่ต้องแสดงข้อความนี้อีก", + "_.ImageInterpolation._NearestNeighbor": "กลุ่มที่ใกล้ที่สุด", + "FrmCrop.LblLocation": "ตำแหน่ง:", + "_._Download": "ดาวน์โหลด", + "_.Metadata._ColorProfile": "โปรไฟล์สี", + "FrmSettings._CenterWindowFit": "จัดกึ่งกลางหน้าต่างอัตโนมัติในโหมดพอดีหน้าจอ", + "FrmSettings._ImageLoadingOrder": "ลำดับการโหลดรูปภาพ", + "FrmSettings._GalleryColumns": "จำนวนคอลัมภ์รูปภาพย่อสำหรับผังแกลเลอรีแนวตั้ง", + "_._Quit": "ออก", + "_._Add": "เพิ่ม", + "FrmMain.MnuChangeBackgroundColor": "เปลี่ยนสีพื้นหลัง...", + "FrmMain.MnuToggleToolbar": "แถบเครื่องมือ", + "FrmAbout._Contact": "ติดต่อ", + "FrmSettings.Toolbar._AddCustomButton": "เพิ่มปุ่มปรับแต่งเอง...", + "FrmCrop.BtnQuickSelect._Tooltip": "เลือกด่วน...", + "FrmMain.MnuCutFile._Success": "ตัด {0} ไฟล์(s).", + "FrmSettings._ZoomSpeed": "ความเร็วในการซูม", + "FrmMain.MnuToggleTopMost._Disable": "ยกเลิกหน้าต่างอยู่บนสุดเสมอ", + "FrmSettings._ShouldUseExplorerSortOrder": "Use Explorer sort order if possible", + "_.ImageInterpolation._Antisotropic": "Antisotropic", + "FrmMain._ReachedFirstImage": "ถึงรูปภาพแรกแล้ว", + "_._UnhandledException": "ข้อยกเว้นที่ไม่สามารถจัดการได้", + "FrmResize.LblNewSize": "New Size:", + "FrmMain._ClipboardImage": "รูปภาพในคลิปบอร์ด", + "FrmMain.MnuExportFrames": "ส่งออกเฟรมรูปภาพ...", + "FrmMain.MnuFile": "ไฟล์", + "_._Close": "ปิด", + "FrmMain.MnuMain": "เมนูหลัก", + "_._ResetToDefault": "กลับสู่ค่าเริ่มต้น", + "FrmSettings.Nav._Gallery": "คลังภาพ", + "FrmMain.MnuSetDefaultPhotoViewer._Success": "คุณตั้ง ImageGlass เป็นแอปดูรูปภาพเริ่มต้นเรียบร้อยแล้ว", + "FrmSettings._HideGalleryInFullscreen": "ซ่อนแกลลอรีในโหมดเต็มหน้าจอ", + "FrmSettings._AvailableImageInfoTags": "แท็กที่มี:", + "FrmExportFrames._Exporting": "กำลังส่งออก {0}/{1} เฟรม \n{2}…", + "_._Argument": "ชุดตัวแปร", + "FrmSettings._ImageEditQuality": "คุณภาพของรูปภาพ", + "_._ID": "รหัสประจำตัว", + "FrmSettings._UserConfigFile": "ไฟล์การตั้งค่าผู้ใช้ (igconfig.json)", + "FrmMain.MnuLoadingOrders": "กำลังโหลดคำสั่ง", + "FrmSettings._OpenSaveAsDialogInTheCurrentImageDir": "เปิดหน้าต่างบันทึกเป็นในไดเรกทอรีรูปภาพปัจจุบัน", + "_.MouseWheelEvent._ShiftAndScroll": "กดปุ่ม Shift และเลื่อน", + "FrmSettings._UseSmoothZooming": "ใช้การซูมแบบลื่นไหล", + "FrmSettings._Theme": "ธีม", + "FrmSettings._ImageBoosterCacheMaxDimension": "มิติภาพสูงสุดที่สำรองได้ (เป็นพิกเซล)", + "FrmMain.MnuScaleToHeight": "ปรับพอดีความสูง", + "_.Metadata._FileLastWriteTime": "วันที่แก้ไข", + "FrmSettings._Author": "ผู้สร้าง", + "FrmSettings._Others": "อื่น ๆ", + "_.MouseWheelAction._PanVertically": "แพนขึ้น / ลง", + "FrmSettings._MouseWheelAction": "การทำงานของลูกกลิ้งเม้าส์", + "FrmSettings.Nav._Tools": "เครื่องมือ", + "FrmMain.MnuSetDesktopBackground._Error": "ไม่สามารถตั้งรูปภาพนี้เป็นภาพพื้นหลัง", + "FrmSettings.Toolbar._Errors._ButtonExecutableRequired": "จำเป็นต้องมีปุ่มปฏิบัติการ", + "_.ImageOrderBy._DateAccessed": "วันที่เข้าถึง", + "FrmSettings._ThumbnailSize": "ขนาดรูปภาพย่อ (เป็นพิกเซล)", + "FrmSettings._FileFormats": "รูปแบบไฟล์", + "FrmMain.MnuReloadImageList": "โหลดรายการรูปภาพอีกครั้ง", + "FrmSettings._UseWebview2ForSvg": "ใช้ Webview2 สำหรับการดูรูปภาพ SVG", + "FrmCrop.BtnCopy": "คัดลอก", + "FrmSettings._CurrentMonitorProfile._Description": "ImageGlass ไม่อัปเดตสีอัตโนมัติเมื่อมีการย้ายหน้าต่างระหว่างจอ", + "FrmMain.PicMain._ErrorText": "ไม่สามารถเปิดรูปภาพนี้ได้", + "FrmSettings.Tools._AddNewTool": "เพิ่มเครื่องมือภายนอก", + "FrmMain.MnuRename": "เปลี่ยนชื่อรูปภาพ...", + "FrmMain.MnuViewLastFrame": "ดูเฟรมสุดท้าย", + "_._Webview2._NotFound": "กรุณาติดตั้ง Webview2 เวอร์ชั่นล่าสุด", + "FrmMain.MnuGetMoreTools": "รับเครื่องมืออื่น ๆ...", + "FrmSettings.Nav._Appearance": "ลักษณะ", + "FrmSettings._SlideshowInterval": "เวลาหน่วงสไลด์โชว์:", + "_.ImageInterpolation._HighQualityBicubic": "ไบคิวบิกคุณภาพสูง", + "FrmColorPickerSettings.ChkShowHsvA": "ใช้รูปแบบ HSV ด้วยค่า alpha", + "FrmSettings.Tools._EditTool": "แก้ไขเครื่องมือภายนอก", + "_._Error": "ข้อผิดพลาด", + "FrmSettings._ImageBoosterCacheMaxFileSizeInMb": "ขนาดไฟล์รูปภาพสูงสุดในการสำรอง (เป็นเมกะไบต์)", + "_._UnhandledException._Description": "พบข้อยกเว้นที่ไม่สามารถจัดการได้ หากท่านคลิก ดำเนินการต่อ, โปรแกรมจะเพิกเฉยข้อผิดพลาดนี้ และพยายามดำเนินการต่อ หากท่านคลิก ออก, โปรแกรมจะปิดตัวลงทันที", + "_.Metadata._FileSize": "ขนาดไฟล์", + "FrmSettings.Toolbar._ButtonJson": "ปุ่ม JSON", + "FrmQuickSetup._SetDefaultViewer._Description": "คุณสามารถตั้งค่าใหม่ได้ในการตั้งค่าแอป > แถบประเภทไฟล์ที่ใช้ร่วมกัน", + "FrmSettings.Nav._Edit": "แก้ไข", + "FrmMain.MnuToggleGallery": "แผงแกลลอรี", + "_._IgCommandExe._DefaultError._Description": "ให้แน่ใจว่าคุณระบุคำสั่งที่ถูกต้อง!\r\nไฟล์ปฏิบัติการนี้ประกอบด้วยฟังก์ชันคำสั่งตัวอักษรสำหรับโปรแกรม ImageGlass\r\n\r\nดูคำสั่งทั้งหมด, โปรดไปที่:\n{0}", + "FrmMain.MnuLosslessCompression._Compressing": "กำลังดำเนินการบีบอัดแบบไม่สูญเสีย", + "FrmSettings._ShouldGroupImagesByDirectory": "จัดกลุ่มรูปภาพตามแฟ้มที่เก็บ", + "FrmMain.MnuPanToRightSide": "แพนรูปภาพไปทางฝั่งขวา", + "_.Metadata._ExifRatingPercent": "การให้คะแนน", + "FrmSettings._PanSpeed": "ความเร็วการแพนภาพ", + "_._CheckForUpdate": "ตรวจสอบการอัพเดท...", + "FrmSettings.Layout._ToolbarContext": "แถบเครื่องมือย่อย", + "_.ImageInfo._FrameCount": "{0} เฟรม", + "FrmMain.MnuLayout": "แผนผัง", + "_._Website": "เว็บไซต์", + "FrmMain.MnuPasteImage": "วางรูปภาพ", + "FrmSettings._ShowGalleryScrollbars": "แสดงแถบเลื่อนแกลลอรี" + } +} \ No newline at end of file diff --git a/Setup/Assets/Language/Turkish.iglang.json b/Setup/Assets/Language/Turkish.iglang.json new file mode 100644 index 000000000..7562b25e2 --- /dev/null +++ b/Setup/Assets/Language/Turkish.iglang.json @@ -0,0 +1,504 @@ +{ + "_Metadata": { + "Code": "tr-TR", + "EnglishName": "Turkish", + "LocalName": "Türkçe", + "Author": "Snn1452", + "MinVersion": "9.1" + }, + "Items": { + "FrmCrop.SelectionAspectRatio._Original": "Orijinal", + "FrmMain.MnuShare._Error": "Paylaş iletişim kutusu açılamadı.", + "_.Metadata._FileLastAccessTime": "Erişim tarihi", + "FrmAbout._License": "Yazılım lisansı", + "FrmSettings.Toolbar._Errors._ButtonIdDuplicated": "'{0}' kimliğine sahip bir düğme zaten tanımlanmış. Çakışmaları önlemek için lütfen düğmeniz için farklı ve benzersiz bir kimlik seçin.", + "FrmMain.MnuSave._Confirm": "Bu resmi geçersiz kılmak istediğinizden emin misiniz?", + "FrmSettings._OpenDefaultAppsSetting": "Varsayılan uygulamalar ayarını aç", + "FrmMain.MnuCopyPath": "Resim yolunu kopyala", + "FrmCropSettings.DefaultSelectionType._SelectNone": "Hiçbirini seçme", + "_.MouseWheelAction._PanHorizontally": "Sola / sağa kaydır", + "FrmMain.MnuPrint": "Yazdır…", + "FrmSettings.Toolbar._ToolbarButtons": "Araç çubuğu düğmeleri", + "FrmResize.LblResample": "Yeniden örneklendir:", + "_.ImageOrderBy._Extension": "Uzantı", + "FrmSettings.Nav._Viewer": "Görüntüleyici", + "FrmSettings.EditAppDialog._EditApp": "Uygulamayı düzenle", + "FrmCrop.BtnReset._Tooltip": "Seçimi sıfırla", + "FrmMain.MnuRename._Description": "Yeni bir dosya adı girin:", + "_._No": "No", + "FrmSlideshow.MnuToggleCountdown": "Slayt gösterisi geri sayımını göster", + "FrmSettings._OpenStartupAppsSetting": "Open Startup apps setting", + "FrmMain.MnuViewPreviousFrame": "Önceki çerçerveyi görüntüle", + "_.ImageOrderBy._DateModified": "Değiştirilme tarihi", + "FrmMain.MnuViewNextFrame": "Sonraki çerçeveyi görüntüle", + "FrmMain.MnuUnload": "Resmi kaldır", + "FrmSettings.Toolbar._HideToolbarInFullscreen": "Tam Ekran modunda araç çubuğunu gizle", + "_.ImageOrderType._Desc": "Azalan", + "_._Update": "Güncelle", + "FrmSettings._EnableImageAsyncLoading": "Enable image asynchronous loading", + "FrmSettings._DefaultPhotoViewer._Description": "Register the supported formats of ImageGlass with Windows. You might need to open the Default apps settings and manually select ImageGlass from the list for it to take effect.", + "_.MouseWheelAction._BrowseImages": "Sonraki / önceki Resmi görüntüle", + "FrmSettings._EditApps": "Resim düzenleme uygulamaları", + "FrmColorPickerSettings.ChkShowCIELabA": "CIELAB formatını alfa değeriyle kullan", + "_._GetHelp": "Yardım al", + "FrmQuickSetup._SkipQuickSetup": "Bunu atlayın ve ImageGlass'ı başlatın", + "FrmColorPickerSettings._Title": "Renk seçici ayarları", + "_._Copy": "Kopyala", + "FrmSettings._ImageBoosterCacheCount": "Resim Güçlendirici tarafından önbelleğe alınan görsellerin sayısı (tek yön)", + "FrmMain.MnuPanToBottom": "Resmi en alta kaydır", + "FrmMain.MnuZoom": "Yakınlaştırma", + "FrmCropSettings.ChkCloseToolAfterSaving": "Kaydettikten sonra Kırpma aracını kapat", + "FrmSettings._ShowWelcomeImage": "Hoş geldiniz resmini göster", + "FrmSettings._ColorProfile": "Renk profili", + "FrmSettings._Theme._UninstallTheme": "Tema paketini kaldır", + "FrmMain._OpenWith": "{0} ile aç", + "FrmMain.MnuRemoveDefaultPhotoViewer": "Varsayılan fotoğraf görüntüleyiciyi kaldır", + "_.AfterEditAppAction._Nothing": "Hiçbir şey", + "FrmCrop.BtnSave": "Kaydet", + "FrmMain.MnuScaleToFit": "Ekrana sığdır", + "FrmToolNotFound.LblDownloadToolText": "ImageGlass için daha fazla aracı şu adresten indirebilirsiniz:", + "_._LearnMore": "Daha fazla bilgi edin…", + "FrmCrop.LblAspectRatio": "En boy oranı:", + "FrmExportFrames._FileNotExist": "Resim dosyası mevcut değil", + "FrmSettings._LightTheme": "Açık", + "FrmSettings.Nav._Slideshow": "Slayt gösterisi", + "_._Continue": "Devam et", + "_._AddHotkey": "Kısayol tuşu ekle…", + "FrmMain.MnuSetDesktopBackground": "Masaüstü arka planı olarak ayarla", + "FrmMain.MnuReload": "Resmi yeniden yükle", + "FrmSlideshow.MnuExitSlideshow": "Slayt gösterisinden çık", + "FrmMain.MnuAutoZoom": "Otomatik yakınlaştır", + "FrmSettings._ShowImagePreview": "Yüklenirken resim önizlemesini görüntüle", + "FrmCrop.BtnCopy._Tooltip": "Seçimi panoya kopyala", + "FrmSettings.Nav._Toolbar": "Araç çubuğu", + "FrmMain.MnuSave._Error": "Resim kaydedilemedi", + "FrmSettings._AfterEditingAction": "Düzenleme uygulamasını açtıktan sonra", + "FrmSettings._ShouldUseColorProfileForAll": "Gömülü renk profili olmayan resimlere de uygula", + "FrmCropSettings.DefaultSelectionType._UseTheLastSelection": "Son seçimi kullan", + "FrmSettings._SlideshowInterval._From": "İtibaren", + "FrmSettings._ImageInterpolation": "Resim interpolasyonu", + "FrmQuickSetup._StepInfo": "Adım {0}", + "FrmMain.MnuColorPicker": "Renk seçici", + "FrmCrop.SelectionAspectRatio._FreeRatio": "Serbest oran", + "FrmSettings._ResetSettings": "Reset settings", + "FrmSettings._Startup": "Başlangıç", + "_.BackdropStyle._None": "Yok", + "FrmSettings._LoadDefaultZoomLevels": "Varsayılan yakınlaştırma düzeylerini yükle", + "FrmColorPicker.BtnSettings._Tooltip": "Renk seçici ayarlarını açın…", + "FrmSettings._UseThemeForDarkMode": "Koyu mod için bu temayı kullanın", + "FrmSettings._ShowDeleteConfirmation": "Dosyayı silerken onay iletişim kutusunu göster", + "FrmSettings._ShowAppIcon": "Başlık çubuğunda uygulama simgesini göster", + "_._InvalidAction": "Invalid action", + "FrmQuickSetup._SelectProfile": "Bir profil seçin", + "_.Metadata._FileCreationTime": "Oluşturma tarihi", + "FrmSettings._SlideshowImagesToNotifySound": "Bildirim sesini tetikleyecek resim sayısı", + "FrmSettings._BackgroundColor": "Görüntüleyicinin arka plan rengi", + "FrmSettings._RealTimeFileUpdate": "Gerçek zamanlı dosya güncellemesi", + "_.ColorProfileOption._CurrentMonitorProfile": "Geçerli monitör profili", + "FrmSettings._EnableCutMultipleFiles": "Aynı anda birden fazla dosyanın kesilmesini etkinleştir", + "FrmSettings._AutoUpdate": "Güncellemeyi otomatik olarak kontrol et", + "FrmCropSettings.LblDefaultSelection": "Varsayılan seçim", + "FrmSettings._UseThemeForLightMode": "Açık mod için bu temayı kullanın", + "FrmSettings._ZoomLevels": "Yakınlaştırma düzeyleri", + "FrmMain.MnuSetLockScreen._Success": "Kilit ekranı görüntüsü güncellendi", + "FrmSettings._ShowGalleryFileName": "Küçük resim dosya adını göster", + "FrmSettings.Layout._Order": "Sıra", + "FrmCropSettings.ChkAutoCenterSelection": "Seçimi otomatik ortala", + "FrmSettings.Nav._FileTypeAssociations": "Dosya türü ilişkileri", + "_._Back": "Geri", + "FrmMain.MnuSetDesktopBackground._Success": "Masaüstü arka planı güncellendi", + "FrmSettings._ShouldAutoOpenNewAddedImage": "Yeni eklenen resmi otomatik olarak aç", + "FrmCrop.SelectionAspectRatio._Custom": "Özel…", + "FrmMain.MnuCopyPath._Success": "Geçerli resim yolu kopyalandı.", + "FrmSettings._StartupBoost._Error": "Could not change Startup Boost setting", + "FrmToolNotFound.LblDescription": "ImageGlass '{0}' yürütülebilir dosyasının yolunu bulamadı. Bu sorunu çözmek için lütfen '{0}' yolunu gerektiği şekilde güncelleyin.", + "FrmMain.MnuClearClipboard": "Panoyu temizle", + "FrmSettings._ColorManagement": "Renk yönetimi", + "FrmMain._ReachedLastLast": "Son resme ulaşıldı", + "FrmMain.MnuPanUp": "Resmi yukarı kaydır", + "FrmMain.MnuRemoveDefaultPhotoViewer._Success": "ImageGlass artık varsayılan fotoğraf görüntüleyici değil.", + "FrmSettings._GetMoreLanguagePacks": "Daha fazla dil paketi edinin…", + "FrmAbout._Privacy": "Gizlilik politikası", + "FrmSettings._EnableRecursiveLoading": "Alt klasörlerdeki resimleri yükle", + "_._UserAction._MethodArgumentNotSupported": "'{0}' yönteminin bağımsız değişken türü desteklenmiyor", + "FrmSettings._FileExtensionIcons._Description": "Dosya uzantısı simgelerini özelleştirmek için bir simge paketi indirin, tüm .ICO dosyalarını uzantı simgesi klasörüne yerleştirin ve '{0}' düğmesini tıklayın. Bu aynı zamanda ImageGlass'ı varsayılan fotoğraf görüntüleyici olarak ayarlayacaktır.", + "_.ImageOrderType._Asc": "Artan", + "FrmExportFrames._Title": "Resim çerçevelerini dışa aktar", + "_._Install": "Yükle…", + "FrmMain.MnuFlipHorizontal": "Yatay Çevir", + "FrmSettings._OpenExtensionIconFolder": "Uzantı simgesi klasörünü aç", + "FrmAbout._Collaborator": "İşbirlikçi:", + "FrmQuickSetup._ConfirmCloseProcess": "Yeni ayarları uygulamadan önce tüm ImageGlass işlemlerinin kapatılması gereklidir. Devam etmeye hazır mısın?", + "FrmExportFrames._ExportDone": "{0} kare başarıyla şuraya aktarıldı:\n{1}", + "FrmCrop.BtnSaveAs._Tooltip": "Kopya olarak kaydet…", + "FrmMain.MnuOpenFile": "Dosya aç…", + "FrmColorPickerSettings.ChkShowRgbA": "RGB formatını alfa değeriyle kullan", + "_.ImageInfo._ListCount": "{0} dosya", + "FrmMain.MnuGoToLast": "Son resme git", + "FrmSettings._EditApps._AppName": "Uygulama Adı", + "FrmSettings._SlideshowBackgroundColor": "Slayt gösterisi arka plan rengi", + "FrmAbout._Email": "E-posta:", + "_.MouseWheelAction._DoNothing": "Hiçbir şey yapma", + "FrmMain.MnuSaveAs": "Farklı kaydet…", + "FrmMain._Loading": "Yükleniyor…", + "_._Browse": "Göz at…", + "FrmMain.MnuSetDefaultPhotoViewer._Error": "ImageGlass varsayılan fotoğraf görüntüleyici olarak ayarlanamadı.", + "FrmSettings.Nav._Language": "Dil", + "FrmQuickSetup._SeeWhatNew": "Bu sürümdeki yeniliklere bakın…", + "FrmSettings._ImageInterpolation._ScaleUp": "Yakınlaştırma > %100 olduğunda", + "FrmSettings.Layout._ToolbarContextPosition": "Bağlamsal araç çubuğu konumu", + "FrmMain.MnuDeleteFromHardDisk": "Kalıcı olarak sil", + "FrmSettings._EmbeddedThumbnail": "Gömülü küçük resim", + "FrmMain.MnuDeleteFromHardDisk._Description": "Bu dosyayı kalıcı olarak silmek istediğinizden emin misiniz?", + "FrmMain.MnuScaleToFill": "Ekranı doldur", + "FrmCrop.BtnCrop": "Kırp", + "_.AfterEditAppAction._Minimize": "Küçült", + "FrmMain.MnuInvertColors": "Renkleri tersine çevir", + "FrmSettings._StartupBoost": "Startup Boost", + "FrmMain.MnuViewFirstFrame": "İlk çerçeveyi görüntüle", + "_.MouseWheelEvent._CtrlAndScroll": "Ctrl'yi basılı tut ve kaydır", + "FrmSettings._HideMainWindowInSlideshow": "Ana pencereyi otomatik olarak gizle", + "_.Metadata._FrameCount": "Çerçeveler", + "FrmSettings._EnableCopyMultipleFiles": "Aynı anda birden fazla dosyanın kopyalanmasını etkinleştir", + "FrmMain.MnuFrameless._EnableDescription": "Pencereyi taşımak için Shift tuşunu basılı tutun.", + "_.ImageOrderBy._ExifDateTaken": "EXIF: Date taken", + "FrmAbout._Credits": "Katkılar", + "FrmSettings._AddNewFileExtension": "Yeni dosya uzantısı ekle", + "FrmMain.MnuQuickSetup": "ImageGlass Hızlı Kurulum'u aç", + "FrmMain.MnuSave._Success": "Resim kaydedildi", + "FrmMain.MnuPanLeft": "Resmi sola kaydır", + "FrmUpdate._StatusChecking": "Güncellemeler kontrol ediliyor…", + "FrmSettings.Nav._Layout": "Düzen", + "FrmMain.MnuOpenWith": "Birlikte aç…", + "FrmAbout._Thanks": "Özel teşekkürler:", + "_._Warning": "Uyarı", + "FrmSettings.Nav._Keyboard": "Klavye", + "FrmSlideshow._PauseSlideshow": "Slayt gösterisi duraklatıldı.", + "_._Add+": "Ekle…", + "_._Email": "E-posta", + "FrmMain.MnuPanDown": "Resmi aşağı kaydır", + "_._Cancel": "İptal", + "_._OK": "TAMAM", + "FrmMain.MnuPanRight": "Resmi sağa kaydır", + "_.Position._Right": "Sağ", + "_._Icon": "Simge", + "FrmSettings._ShouldLoadHiddenImages": "Gizli resimleri yükle", + "_._InvalidAction._Transformation": "ImageGlass does not support rotation, flipping for this image.", + "FrmSettings._MakeDefault": "Varsayılan yap", + "FrmMain.MnuCopyImageData._Copying": "Resim verileri kopyalanıyor. Biraz zaman alacak…", + "FrmSettings._UseEmbeddedThumbnailRawFormats": "RAW formatları için yalnızca gömülü küçük resmi yükle", + "_.ImageInterpolation._Linear": "Doğrusal", + "FrmSettings._ImageInfoTags": "Resim bilgi etiketleri", + "FrmSettings._FileExtensionIcons": "Dosya uzantısı simgeleri", + "FrmMain.MnuEdit._AppNotFound": "Düzenleme için ilgili uygulama bulunamadı. ImageGlass Ayarları > Düzenle'de bu formatı düzenlemek için bir uygulama atayabilirsiniz.", + "_.ColorProfileOption._None": "Yok", + "FrmSettings._TotalSupportedFormats": "Toplam desteklenen biçimler: {0}", + "FrmSettings._Clipboard": "Pano", + "_._UserAction._Win32ExeError": "'{0}' komutu yürütülemiyor. Adın doğru olduğundan emin olun.", + "FrmCropSettings.DefaultSelectionType._SelectX": "{0}'ı seçin", + "_.AfterEditAppAction._Close": "Kapat", + "FrmAbout._LogoDesigner": "Logo tasarımcısı:", + "_.ImageOrderBy._Name": "Adı (varsayılan)", + "FrmMain.MnuRemoveDefaultPhotoViewer._Error": "ImageGlass varsayılan fotoğraf görüntüleyici olarak kaldırılamadı.", + "FrmExportFrames._FolderPickerTitle": "Resim çerçevelerini dışa aktarmak için çıktı klasörünü seçin", + "FrmAbout._Donate": "Bağış yap", + "FrmMain.MnuFrameNav": "Çerçevede gezinme", + "FrmMain.MnuSetLockScreen": "Kilit ekranı görüntüsü olarak ayarla", + "_._Delete": "Sil", + "FrmMain.MnuViewPrevious": "Önceki resmi görüntüle", + "_.Position._Top": "Üst", + "FrmSettings.Toolbar._CurrentButtons": "Mevcut düğmeler:", + "FrmMain.MnuAbout": "Hakkında", + "FrmSettings._RemoveDefault": "Varsayılanı Kaldır", + "_._Description": "Açıklama", + "FrmMain.MnuPasteImage._Error": "Panoda resim verileri bulunamadı", + "FrmMain.MnuSettings": "Ayarlar", + "FrmCropSettings._Title": "Kırpma ayarları", + "FrmSettings.Toolbar._ToolbarIconHeight": "Araç çubuğu simge boyutu", + "FrmSettings._SlideshowInterval._To": "Kadar", + "FrmSettings.Layout._ToolbarPosition": "Araç çubuğu konumu", + "FrmUpdate._StatusUpdated": "En son sürümü kullanıyorsunuz!", + "FrmMain.MnuExit": "Çıkış", + "_._Webview2._Outdated": "Your WebView2 Runtime is not supported. Please update to version {0} or later.", + "_._Yes": "Evet", + "FrmMain.MnuRotateLeft": "Sola döndür", + "FrmSettings._EnableStartupBoost": "Enable Startup Boost", + "_.ImageOrderBy._ExifRating": "EXIF: Rating", + "FrmMain.MnuZoomIn": "Yakınlaştır", + "_.Metadata._ColorSpace": "Renk alanı", + "FrmAbout._Version": "Sürüm:", + "FrmMain.MnuToggleTopMost._Enable": "Pencere'yi her zaman üstte tut etkinleştirildi", + "FrmSettings.Toolbar._AvailableButtons": "Kullanılabilir düğmeler:", + "FrmMain.MnuSave._Saving": "Resim kaydediliyor…", + "FrmQuickSetup._StandardUser": "Standart kullanıcı", + "FrmMain.MnuSetLockScreen._Error": "Görüntülenen resim kilit ekranı görüntüsü olarak ayarlanamadı", + "FrmSettings.Nav._Image": "Resim", + "FrmSettings._Theme._InstallTheme": "Tema paketi yükle", + "FrmSettings._EnableMultiInstances": "Programın birden çok örneğine izin ver", + "FrmMain.MnuCropTool": "Resmi kırp", + "_._IgCommandExe._DefaultError._Heading": "Geçersiz komutlar", + "_._Refresh": "Yenile", + "FrmMain.MnuLosslessCompression._Description": "This tool uses Magick.NET library for lossless compression, optimizing file size. Overwrites only if the compressed file is smaller than the original.", + "_._MoveDown": "Aşağı taşı", + "FrmSettings._GetExtensionIconPacks": "Uzantı simge paketlerini edinin…", + "FrmSettings._InAppMessageDuration": "Uygulama içi mesaj süresi (milisaniye)", + "FrmMain.MnuFrameless": "Çerçevesiz", + "_._Reset": "Sıfırla", + "FrmSettings._ConfigDir": "Yapılandırma konumu", + "FrmQuickSetup._SettingsWillBeApplied": "Ayarlar uygulanacaktır:", + "FrmSettings._UnmanagedSettingReminder": "This setting is not managed by ImageGlass. Don't forget to disable it before you remove or relocate the app because ImageGlass does not handle this automatically.", + "FrmMain.MnuClipboard": "Pano", + "FrmMain.MnuCustomZoom": "Özel yakınlaştırma…", + "FrmSettings._DisplayLanguage": "Görüntüleme dili", + "FrmMain.MnuPrint._Error": "Görüntülenen resim yazdırılamadı", + "FrmSettings._ShouldPreserveModifiedDate": "Kaydetme sırasında resmin değiştirilme tarihini koru", + "FrmSettings._ShowSaveOverrideConfirmation": "Dosyayı geçersiz kılarken onay iletişim kutusunu göster", + "FrmColorPickerSettings.ChkShowHexA": "HEX formatını alfa değeriyle kullan", + "FrmMain.MnuFullScreen": "Tam Ekran", + "FrmSettings._StartupDir": "Başlangıç ​​konumu", + "FrmSettings._ShowCheckerboardOnlyImageRegion": "Dama tahtasını yalnızca resim bölgesinde göster", + "FrmMain.MnuClearClipboard._Success": "Pano temizlendi.", + "FrmQuickSetup._Text": "ImageGlass Hızlı Kurulum", + "FrmMain.MnuLosslessCompression._Done": "Done lossless compression.\r\nThe new file size is {0}, saved {1}.", + "FrmMain.MnuLosslessCompression": "Magick.NET Lossless Compression", + "FrmResize.RadResizeByPercentage": "Yüzde", + "FrmSettings._StartupBoost._Disabled": "Startup Boost is disabled", + "FrmMain.MnuToggleCheckerboard": "Renk tahtası arkaplanı", + "FrmSettings._MinEmbeddedThumbnailSize._Height": "Yükseklik", + "FrmSettings.Nav._General": "Genel", + "FrmSettings._ImageLoading": "Resim yükleme", + "FrmSettings._ShowSlideshowCountdown": "Slayt gösterisi geri sayımını göster", + "FrmMain.MnuSave": "Kaydet", + "FrmMain.MnuMoveToRecycleBin": "Geri Dönüşüm Kutusu'na taşı", + "FrmMain.MnuRefresh": "Yenile", + "FrmToolNotFound.LblHeading": "'{0}' bulunamadı!", + "FrmMain.MnuReportIssue": "Sorun bildir…", + "FrmMain.MnuCopyImageData": "Resim verilerini kopyala", + "FrmMain.MnuCheckForUpdate._NewVersion": "Yeni sürüm indirilebilir!", + "_._Empty": "(boş)", + "FrmSettings._Zooming": "Yakınlaştırma", + "FrmMain.MnuCutFile": "Dosyayı kes", + "FrmHotkeyPicker.LblHotkey": "Kısayol tuşuna basın", + "FrmSettings.Layout._Gallery": "Galeri", + "FrmMain.MnuNewWindow": "Yeni pencere aç", + "FrmMain.MnuMoveToRecycleBin._Description": "Bu dosyayı Geri Dönüşüm Kutusu'na taşımak istiyor musunuz?", + "FrmSettings._DefaultPhotoViewer": "Varsayılan fotoğraf görüntüleyici", + "_.Metadata._ExifDateTimeOriginal": "EXIF: DateTimeOriginal", + "FrmMain.MnuRotateRight": "Sağa döndür", + "FrmSettings._MinEmbeddedThumbnailSize": "Yüklenecek gömülü küçük resmin minimum boyutu", + "FrmMain.MnuSetDefaultPhotoViewer": "Varsayılan fotoğraf görüntüleyiciyi ayarla", + "FrmMain.MnuImageProperties": "Resim özellikleri", + "FrmSettings._EnableNavigationButtons": "Gezinme ok düğmelerini göster", + "_._Edit": "Düzenle", + "FrmSettings._ImageBooster": "Resim Güçlendirici", + "FrmSettings.Tools._IntegratedWith": "{0} ile eklendi", + "_._Next": "İleri", + "FrmExportFrames._OpenOutputFolder": "Çıkış klasörünü aç", + "FrmMain.MnuOpenLocation": "Resim konumunu aç", + "FrmMain.MnuLockZoom": "Yakınlaştırma oranını kilitle", + "FrmSettings._StartupBoost._Description": "Preload and run ImageGlass in the background for a few seconds during Windows startup to accelerate the first launch.", + "FrmSettings._WindowBackdrop": "Pencere arka planı", + "FrmSettings._EnableRealTimeFileUpdate": "Görüntüleme klasöründeki dosya değişikliklerini izle ve gerçek zamanlı olarak güncelle", + "_._NotSupported": "Desteklenmeyen format", + "FrmSettings._Theme._GetMoreThemes": "Daha fazla tema paketi edinin…", + "FrmMain.MnuNewWindow._Error": "Yalnızca bir örneğe izin verildiğinden yeni pencere açılamıyor", + "FrmMain.MnuZoomOut": "Uzaklaştır", + "FrmSettings.Toolbar._EditButton": "Araç çubuğu düğmesini düzenle", + "FrmMain.MnuCustomZoom._Description": "Yeni bir yakınlaştırma değeri gir", + "FrmResize.RadResizeByPixels": "Piksel", + "FrmMain.MnuEdit": "{0} resmini düzenle…", + "FrmSettings.Layout._GalleryPosition": "Galeri konumu", + "FrmMain.MnuWindowFit": "Pencereye Sığdır", + "FrmMain._OpenFileDialog": "Desteklenen tüm dosyalar", + "FrmSettings._UseRandomIntervalForSlideshow": "Rastgele aralık kullan", + "_.Position._Left": "Sol", + "FrmSettings._ShouldOpenLastSeenImage": "Son görülen resmi aç", + "_.Position._Bottom": "Alt", + "FrmResize.ChkKeepRatio": "Oranı sabit tut", + "FrmMain.MnuGoTo": "Git…", + "FrmSlideshow.MnuPauseResumeSlideshow": "Slayt gösterisini duraklat/devam ettir", + "FrmSettings.Tools._Integrated": "Eklendi", + "FrmSettings._Contributors": "Katkıda bulunanlar", + "_.MouseWheelAction._Zoom": "Yakınlaştır / uzaklaştır", + "_._CommandPreview": "Komut önizlemesi", + "FrmSettings._DarkTheme": "Koyu", + "_._Hotkeys": "Kısayol tuşları", + "_.Metadata._ExifDateTime": "EXIF: DateTime", + "FrmSettings.Toolbar._Errors._ButtonIdRequired": "Düğme Kimliği gerekli.", + "FrmSettings._MinEmbeddedThumbnailSize._Width": "Genişlik", + "_._Executable": "Yürütülebilir dosya", + "_.ImageInterpolation._MultiSampleLinear": "Çoklu örnek doğrusal", + "_._Separator": "Ayraç", + "FrmQuickSetup._ProfessionalUser": "Profesyonel kullanıcı", + "FrmMain.MnuFlipVertical": "Dikey Çevir", + "FrmSlideshow._ResumeSlideshow": "Slayt gösterisi devam ettirildi.", + "FrmCropSettings.DefaultSelectionType._CustomArea": "Özel alan…", + "FrmMain.MnuActualSize": "Gerçek boyut", + "FrmCrop.BtnSaveAs": "Farklı kaydet…", + "FrmSettings._InstallNewLanguagePack": "Yeni dil paketlerini yükleyin…", + "FrmSlideshow.MnuZoomModes": "Yakınlaştırma modları", + "FrmMain.MnuTools": "Araçlar", + "_.ImageInterpolation._Cubic": "Kübik", + "FrmUpdate._LatestVersion": "En son sürüm: {0}", + "FrmMain.MnuViewNext": "Sonraki resmi görüntüle", + "_.MouseWheelEvent._AltAndScroll": "Alt'ı basılı tut ve kaydır", + "FrmToolNotFound._Title": "Araç bulunamadı", + "FrmCrop.BtnCrop._Tooltip": "Yalnızca resmi kırp", + "FrmSettings.EditAppDialog._AddApp": "Düzenlemek için bir uygulama ekle", + "FrmMain.MnuPanning": "Kaydırma", + "_._MoveUp": "Yukarı taşı", + "FrmCropSettings.DefaultSelectionType._SelectAll": "Tümünü seç", + "_._Name": "Ad", + "FrmColorPickerSettings.ChkShowHslA": "HSL formatını alfa değeriyle kullan", + "FrmMain.MnuToggleImageAnimation": "Animasyonlu görüntüyü başlat / durdur", + "FrmSettings._DisableStartupBoost": "Disable Startup Boost", + "FrmMain.MnuCopyFile._Success": "{0} dosya kopyalandı.", + "FrmMain.MnuSave._ConfirmDescription": "ImageGlass profesyonel bir fotoğraf editörü değildir; lütfen resminizi kaydederken kaliteyi, meta verileri, katmanları vb. kaybedebileceğinizin farkında olun.", + "FrmToolNotFound.BtnSelectExecutable": "Seç…", + "FrmUpdate._StatusOutdated": "Yeni bir güncelleme mevcut!", + "_.ImageOrderBy._Random": "Rasgele", + "FrmResize.LblCurrentSize": "Mevcut Boyut:", + "_._Apply": "Uygula", + "FrmAbout._Slogan": "Hafif, çok yönlü bir resim görüntüleyici", + "FrmMain.MnuPanToTop": "Resmi en üste kaydır", + "FrmSettings.Toolbar._AddNewButton": "Özel bir araç çubuğu düğmesi ekle", + "FrmCrop.LblSize": "Boyut:", + "FrmSettings._ImageInterpolation._ScaleDown": "Yakınlaştırma < %100 olduğunda", + "_._CreatingFileError": "Geçici resim dosyası oluşturulamadı", + "FrmMain.MnuGoTo._Description": "Görüntülenecek resim dizinini girin ve ardından ENTER tuşuna basın", + "FrmSettings.Toolbar._EnableCenterToolbar": "Araç çubuğu için merkez hizalaması kullan", + "FrmMain.MnuResizeTool": "Görüntüyü yeniden boyutlandır", + "FrmSettings.Layout._Toolbar": "Araç çubuğu", + "FrmMain.MnuHelp": "Yardım", + "_.ImageOrderBy._FileSize": "Dosya boyutu", + "FrmSettings._Theme._OpenThemeFolder": "Tema klasörünü aç", + "FrmMain.MnuNavigation": "Gezinme", + "_._Save": "Kaydet", + "FrmQuickSetup._SettingProfileDescription": "Bu ayarları değiştirmek için uygulama ayarlarına erişmeniz yeterlidir.", + "_._UserAction._MenuNotFound": "Eylemi çağırmak için '{0}' menüsü bulunamıyor", + "FrmMain.MnuPanToLeftSide": "Resmi sol kenara kaydır", + "FrmUpdate._CurrentVersion": "Mevcut sürüm: {0}", + "FrmCrop.BtnSettings._Tooltip": "Kırpma aracı ayarlarını aç", + "_.ColorProfileOption._Custom": "Özel…", + "FrmSettings._UseEmbeddedThumbnailOtherFormats": "Diğer formatlar için yalnızca gömülü küçük resmi yükle", + "FrmMain.MnuGoToFirst": "İlk resme git", + "FrmSettings._ExportLanguagePack": "Dil paketini dışa aktar…", + "FrmSettings.Nav._Mouse": "Fare", + "_.ImageOrderBy._DateCreated": "Oluşturma tarihi", + "FrmSettings._EnableFullscreenSlideshow": "Slayt gösterisini Tam Ekran modunda başlat", + "FrmAbout._Homepage": "Ana sayfa:", + "FrmSettings._GalleryCacheSizeInMb": "Maksimum galeri önbellek boyutu (megabayt olarak)", + "FrmMain.MnuCopyImageData._Success": "Geçerli resim verileri kopyalandı.", + "FrmSettings._EnableLoopBackNavigation": "Resim listesinin sonuna ulaşıldığında ilk resme geri dön", + "_.MouseWheelEvent._Scroll": "Kaydırma", + "FrmCrop.BtnSave._Tooltip": "Resmi Kaydet", + "FrmMain.MnuSlideshow": "Slayt Gösterisi", + "FrmMain.MnuShare": "Paylaş…", + "FrmSettings._SlideshowNotification": "Slayt gösterisi bildirimi", + "FrmMain.MnuViewChannels": "Kanalları görüntüle", + "FrmSettings._Refresh": "Yenile", + "_._UserAction._MethodNotFound": "Eylemi çağırmak için '{0}' yöntemi bulunamıyor", + "FrmMain.MnuCopyFile": "Dosyayı kopyala", + "_._CreatingFile": "Geçici bir resim dosyası oluşturuluyor…", + "FrmMain.MnuToggleTopMost": "Pencereyi her zaman üstte tut", + "FrmMain.MnuLosslessCompression._Confirm": "Are you sure you want to proceed?", + "FrmMain.MnuImage": "Resim", + "FrmSettings._StartupBoost._Enabled": "Startup Boost is enabled", + "FrmQuickSetup._SetDefaultViewer": "ImageGlass'ı varsayılan fotoğraf görüntüleyici olarak ayarlamak ister misiniz?", + "FrmMain.MnuScaleToWidth": "Genişliğe göre ölçeklendir", + "_._FileExtension": "Dosya uzantısı", + "FrmUpdate._PublishedDate": "Yayınlanma tarihi: {0}", + "_._DoNotShowThisMessageAgain": "Bu mesajı bir daha gösterme", + "_.ImageInterpolation._NearestNeighbor": "En yakın komşu", + "FrmCrop.LblLocation": "Konum:", + "_._Download": "İndir", + "_.Metadata._ColorProfile": "Renk profili", + "FrmSettings._CenterWindowFit": "Pencereyi Pencereye Sığdır modunda otomatik olarak ortala", + "FrmSettings._ImageLoadingOrder": "Resim yükleme sırası", + "FrmSettings._GalleryColumns": "Dikey galeri düzenindeki küçük resim sütunlarının sayısı", + "_._Quit": "Çık", + "_._Add": "Ekle", + "FrmMain.MnuChangeBackgroundColor": "Arka plan rengini değiştir…", + "FrmMain.MnuToggleToolbar": "Araç çubuğu", + "FrmAbout._Contact": "İletişim", + "FrmSettings.Toolbar._AddCustomButton": "Özel bir düğme ekleyin…", + "FrmCrop.BtnQuickSelect._Tooltip": "Hızlı seçim…", + "FrmMain.MnuCutFile._Success": "{0} dosya kesildi.", + "FrmSettings._ZoomSpeed": "Yakınlaştırma hızı", + "FrmMain.MnuToggleTopMost._Disable": "Pencere'yi her zaman üstte tut devre dışı bırakıldı", + "FrmSettings._ShouldUseExplorerSortOrder": "Mümkünse Windows Dosya Gezgini sıralama düzenini kullan", + "_.ImageInterpolation._Antisotropic": "Antisotropik", + "FrmMain._ReachedFirstImage": "İlk resme ulaşıldı", + "_._UnhandledException": "İşlenmemiş istisna", + "FrmResize.LblNewSize": "Yeni Boyut:", + "FrmMain._ClipboardImage": "Pano resmi", + "FrmMain.MnuExportFrames": "Resim çerçevelerini dışa aktar…", + "FrmMain.MnuFile": "Dosya", + "_._Close": "Kapat", + "FrmMain.MnuMain": "Ana menü", + "_._ResetToDefault": "Varsayılana sıfırla", + "FrmSettings.Nav._Gallery": "Galeri", + "FrmMain.MnuSetDefaultPhotoViewer._Success": "ImageGlass'ı başarıyla varsayılan fotoğraf görüntüleyici olarak ayarladınız.", + "FrmSettings._HideGalleryInFullscreen": "Tam Ekran modunda galeriyi gizle", + "FrmSettings._AvailableImageInfoTags": "Mevcut etiketler:", + "FrmExportFrames._Exporting": "{1}/{0} kare dışa aktarılıyor\n{2}…", + "_._Argument": "Değişken", + "FrmSettings._ImageEditQuality": "Görsel kalitesi", + "_._ID": "Kimlik", + "FrmSettings._UserConfigFile": "Kullanıcı ayarları dosyası (igconfig.json)", + "FrmMain.MnuLoadingOrders": "Yüklenme sırası", + "FrmSettings._OpenSaveAsDialogInTheCurrentImageDir": "Geçerli görüntü dizininde Farklı Kaydet iletişim kutusunu açın", + "_.MouseWheelEvent._ShiftAndScroll": "Shift'i basılı tut ve kaydır", + "FrmSettings._UseSmoothZooming": "Pürüzsüz yakınlaştırmayı kullan", + "FrmSettings._Theme": "Tema", + "FrmSettings._ImageBoosterCacheMaxDimension": "Önbelleğe alınacak maksimum görüntü boyutu (piksel cinsinden)", + "FrmMain.MnuScaleToHeight": "Yüksekliğe göre ölçeklendir", + "_.Metadata._FileLastWriteTime": "Değiştirilme tarihi", + "FrmSettings._Author": "Yazar", + "FrmSettings._Others": "Diğerleri", + "_.MouseWheelAction._PanVertically": "Yukarı / aşağı kaydır", + "FrmSettings._MouseWheelAction": "Fare tekerleği eylemi", + "FrmSettings.Nav._Tools": "Araçlar", + "FrmMain.MnuSetDesktopBackground._Error": "Görüntülenen resim masaüstü arka planı olarak ayarlanamadı", + "FrmSettings.Toolbar._Errors._ButtonExecutableRequired": "Çalıştırılabilir düğme gerekli.", + "_.ImageOrderBy._DateAccessed": "Erişim tarihi", + "FrmSettings._ThumbnailSize": "Küçük resim boyutu (pixel olarak)", + "FrmSettings._FileFormats": "Dosya biçimleri", + "FrmMain.MnuReloadImageList": "Resim listesini yeniden yükle", + "FrmSettings._UseWebview2ForSvg": "SVG formatını görüntülemek için WebView2'yi kullan", + "FrmCrop.BtnCopy": "Kopyala", + "FrmSettings._CurrentMonitorProfile._Description": "ImageGlass, penceresini monitörler arasında taşırken rengi otomatik olarak güncellemiyor", + "FrmMain.PicMain._ErrorText": "Bu resim açılamadı", + "FrmSettings.Tools._AddNewTool": "Harici bir araç ekle", + "FrmMain.MnuRename": "Resmi yeniden adlandır…", + "FrmMain.MnuViewLastFrame": "Son çerçeveyi görüntüle", + "_._Webview2._NotFound": "Please install WebView2 Runtime to access full features of ImageGlass.", + "FrmMain.MnuGetMoreTools": "Daha fazla araç edinin…", + "FrmSettings.Nav._Appearance": "Görünüm", + "FrmSettings._SlideshowInterval": "Slayt gösterisi aralığı:", + "_.ImageInterpolation._HighQualityBicubic": "Yüksek kaliteli bikübik", + "FrmColorPickerSettings.ChkShowHsvA": "HSV formatını alfa değeriyle kullan", + "FrmSettings.Tools._EditTool": "Harici aracı düzenle", + "_._Error": "Hata", + "FrmSettings._ImageBoosterCacheMaxFileSizeInMb": "Önbelleğe alınacak maksimum resim dosyası boyutu (megabayt cinsinden)", + "_._UnhandledException._Description": "İşlenmeyen özel durum oluştu. Devam'ı tıklarsanız uygulama bu hatayı yok sayar ve devam etmeye çalışır. Çık'a tıklarsanız uygulama hemen kapanacaktır.", + "_.Metadata._FileSize": "Dosya boyutu", + "FrmSettings.Toolbar._ButtonJson": "JSON düğmesi", + "FrmQuickSetup._SetDefaultViewer._Description": "Uygulama ayarları > Dosya türü ilişkileri sekmesinden sıfırlayabilirsiniz.", + "FrmSettings.Nav._Edit": "Düzenle", + "FrmMain.MnuToggleGallery": "Galeri paneli", + "_._IgCommandExe._DefaultError._Description": "Doğru komutları ilettiğinizden emin olun!\r\nBu yürütülebilir dosya, ImageGlass yazılımı için komut satırı işlevlerini içerir.\r\n\r\nTüm komut satırlarını keşfetmek için lütfen şu adresi ziyaret edin:\n{0}", + "FrmMain.MnuLosslessCompression._Compressing": "Performing lossless compression…", + "FrmSettings._ShouldGroupImagesByDirectory": "Resimleri dizine göre grupla", + "FrmMain.MnuPanToRightSide": "Resmi sağ kenara kaydır", + "_.Metadata._ExifRatingPercent": "Derecelendirme", + "FrmSettings._PanSpeed": "Kaydırma hızı", + "_._CheckForUpdate": "Güncellemeleri kontrol et…", + "FrmSettings.Layout._ToolbarContext": "Bağlamsal araç çubuğu", + "_.ImageInfo._FrameCount": "{0} çerçeve", + "FrmMain.MnuLayout": "Görünüm", + "_._Website": "Web sitesi", + "FrmMain.MnuPasteImage": "Resmi yapıştır", + "FrmSettings._ShowGalleryScrollbars": "Galeri kaydırma çubuklarını göster" + } +} \ No newline at end of file diff --git a/Setup/Assets/Language/Ukrainian.iglang.json b/Setup/Assets/Language/Ukrainian.iglang.json new file mode 100644 index 000000000..2c89e8b8e --- /dev/null +++ b/Setup/Assets/Language/Ukrainian.iglang.json @@ -0,0 +1,504 @@ +{ + "_Metadata": { + "Code": "uk-UA", + "EnglishName": "Ukrainian", + "LocalName": "Українська", + "Author": "Valentin Gonsharuk", + "MinVersion": "9.3" + }, + "Items": { + "FrmCrop.SelectionAspectRatio._Original": "Оригінал", + "FrmMain.MnuShare._Error": "Не вдалося відкрити вікно поширення.", + "_.Metadata._FileLastAccessTime": "Дата доступу", + "FrmAbout._License": "Ліцензія", + "FrmSettings.Toolbar._Errors._ButtonIdDuplicated": "Кнопка з ID '{0}' вже була визначена. Будь ласка, виберіть інший унікальний ідентифікатор для вашої кнопки, щоб уникнути конфліктів.", + "FrmMain.MnuSave._Confirm": "Ви впевнені, що хочете перезаписати це зображення?", + "FrmSettings._OpenDefaultAppsSetting": "Відкрити налаштування програм за замовчуванням", + "FrmMain.MnuCopyPath": "Копіювати шлях файлу", + "FrmCropSettings.DefaultSelectionType._SelectNone": "Не вибирати", + "_.MouseWheelAction._PanHorizontally": "Прокручування вліво / вправо", + "FrmMain.MnuPrint": "Друкувати…", + "FrmSettings.Toolbar._ToolbarButtons": "Кнопки панелі інструментів", + "FrmResize.LblResample": "Resample:", + "_.ImageOrderBy._Extension": "Розширення", + "FrmSettings.Nav._Viewer": "Переглядач", + "FrmSettings.EditAppDialog._EditApp": "Редагувати додаток", + "FrmCrop.BtnReset._Tooltip": "Скасувати вибір", + "FrmMain.MnuRename._Description": "Введіть ім'я нового файлу:", + "_._No": "Ні", + "FrmSlideshow.MnuToggleCountdown": "Показувати відлік слайд-шоу", + "FrmSettings._OpenStartupAppsSetting": "Open Startup apps setting", + "FrmMain.MnuViewPreviousFrame": "Переглянути попередній фрейм", + "_.ImageOrderBy._DateModified": "Дата зміни", + "FrmMain.MnuViewNextFrame": "Переглянути наступний фрейм", + "FrmMain.MnuUnload": "Вивантажити зображення", + "FrmSettings.Toolbar._HideToolbarInFullscreen": "Приховати панель інструментів у повноекранному режимі", + "_.ImageOrderType._Desc": "За спаданням", + "_._Update": "Update", + "FrmSettings._EnableImageAsyncLoading": "Enable image asynchronous loading", + "FrmSettings._DefaultPhotoViewer._Description": "Register the supported formats of ImageGlass with Windows. You might need to open the Default apps settings and manually select ImageGlass from the list for it to take effect.", + "_.MouseWheelAction._BrowseImages": "Переглядати наступне / попереднє зображення", + "FrmSettings._EditApps": "Програми для редагування зображень", + "FrmColorPickerSettings.ChkShowCIELabA": "Використовувати CIELAB формат з альфа-значенням", + "_._GetHelp": "Отримати допомогу", + "FrmQuickSetup._SkipQuickSetup": "Пропустити і запустити ImageGlass", + "FrmColorPickerSettings._Title": "Налаштування вибору кольору", + "_._Copy": "Копіювати", + "FrmSettings._ImageBoosterCacheCount": "Кількість зображень, кешованих прискорювачем зображень (один напрямок)", + "FrmMain.MnuPanToBottom": "Панорама зображення до нижнього краю", + "FrmMain.MnuZoom": "Масштабування", + "FrmCropSettings.ChkCloseToolAfterSaving": "Закрити після збереження", + "FrmSettings._ShowWelcomeImage": "Показати зображення привітання", + "FrmSettings._ColorProfile": "Профіль кольорів", + "FrmSettings._Theme._UninstallTheme": "Видалити пакет тем", + "FrmMain._OpenWith": "Відкрити в {0}", + "FrmMain.MnuRemoveDefaultPhotoViewer": "Вилучити основний переглядач фотографій", + "_.AfterEditAppAction._Nothing": "Нічого не робити", + "FrmCrop.BtnSave": "Зберегти", + "FrmMain.MnuScaleToFit": "Підганяти розмір", + "FrmToolNotFound.LblDownloadToolText": "Ви можете завантажити більше інструментів для ImageGlass на:", + "_._LearnMore": "Дізнатися більше…", + "FrmCrop.LblAspectRatio": "Співвідношення сторін:", + "FrmExportFrames._FileNotExist": "Файл зображення не існує", + "FrmSettings._LightTheme": "Світла тема", + "FrmSettings.Nav._Slideshow": "Слайд-шоу", + "_._Continue": "Продовжити", + "_._AddHotkey": "Додати гарячу клавішу…", + "FrmMain.MnuSetDesktopBackground": "Встановити як тло робочого столу", + "FrmMain.MnuReload": "Перезавантажити зображення", + "FrmSlideshow.MnuExitSlideshow": "Вихід зі слайд-шоу", + "FrmMain.MnuAutoZoom": "Автоматичне масштабування", + "FrmSettings._ShowImagePreview": "Показувати попередній перегляд зображення під час завантаження", + "FrmCrop.BtnCopy._Tooltip": "Скопіювати вибране в буфер обміну", + "FrmSettings.Nav._Toolbar": "Панель інструментів", + "FrmMain.MnuSave._Error": "Не вдалося зберегти зображення", + "FrmSettings._AfterEditingAction": "Після відкриття редактора", + "FrmSettings._ShouldUseColorProfileForAll": "Застосувати також для зображень без вбудованого колірного профілю", + "FrmCropSettings.DefaultSelectionType._UseTheLastSelection": "Використовувати останній вибір", + "FrmSettings._SlideshowInterval._From": "Від", + "FrmSettings._ImageInterpolation": "Інтерполяція зображення", + "FrmQuickSetup._StepInfo": "Крок {0}", + "FrmMain.MnuColorPicker": "Вибір кольору", + "FrmCrop.SelectionAspectRatio._FreeRatio": "Вільне співвідношення", + "FrmSettings._ResetSettings": "Reset settings", + "FrmSettings._Startup": "Автозавантаження", + "_.BackdropStyle._None": "Жоден", + "FrmSettings._LoadDefaultZoomLevels": "Завантажити стандартний рівень масштабування", + "FrmColorPicker.BtnSettings._Tooltip": "Відкрийте налаштування інструмента Вибір кольорів…", + "FrmSettings._UseThemeForDarkMode": "Використовувати цю тему для темного режиму", + "FrmSettings._ShowDeleteConfirmation": "Показувати діалог підтвердження під час видалення файлу", + "FrmSettings._ShowAppIcon": "Показувати логотип ImageGlass у заголовку вікна", + "_._InvalidAction": "Invalid action", + "FrmQuickSetup._SelectProfile": "Вибрати профіль", + "_.Metadata._FileCreationTime": "Дата створення", + "FrmSettings._SlideshowImagesToNotifySound": "Кількість зображень для запуску звуку сповіщення", + "FrmSettings._BackgroundColor": "Колір фону засобу перегляду", + "FrmSettings._RealTimeFileUpdate": "Оновлення файлу в реальному часі", + "_.ColorProfileOption._CurrentMonitorProfile": "Поточний профіль монітора", + "FrmSettings._EnableCutMultipleFiles": "Увімкнути вирізання кількох файлів одночасно", + "FrmSettings._AutoUpdate": "Перевіряти наявність оновлень автоматично", + "FrmCropSettings.LblDefaultSelection": "Вибір за замовчуванням", + "FrmSettings._UseThemeForLightMode": "Використовувати цю тему для світлого режиму", + "FrmSettings._ZoomLevels": "Рівні масштабування", + "FrmMain.MnuSetLockScreen._Success": "Зображення екрану блокування оновлено", + "FrmSettings._ShowGalleryFileName": "Показувати ім'я файлу мініатюри", + "FrmSettings.Layout._Order": "Порядок", + "FrmCropSettings.ChkAutoCenterSelection": "Автоматичний вибір центру", + "FrmSettings.Nav._FileTypeAssociations": "Асоціації файлів", + "_._Back": "Назад", + "FrmMain.MnuSetDesktopBackground._Success": "Фон робочого столу оновлено", + "FrmSettings._ShouldAutoOpenNewAddedImage": "Автоматично відкривати нове додане зображення", + "FrmCrop.SelectionAspectRatio._Custom": "Налаштувати…", + "FrmMain.MnuCopyPath._Success": "Скопійовано поточний шлях зображення.", + "FrmSettings._StartupBoost._Error": "Could not change Startup Boost setting", + "FrmToolNotFound.LblDescription": "ImageGlass не вдалося знайти шлях до виконуваного файлу '{0}'. Щоб вирішити цю проблему, оновіть шлях до '{0}' за необхідності.", + "FrmMain.MnuClearClipboard": "Очистити буфер обміну", + "FrmSettings._ColorManagement": "Керування кольором", + "FrmMain._ReachedLastLast": "Досягнуто останнє зображення", + "FrmMain.MnuPanUp": "Панорама зображення вгору", + "FrmMain.MnuRemoveDefaultPhotoViewer._Success": "ImageGlass більше не є основним переглядачем фотографій.", + "FrmSettings._GetMoreLanguagePacks": "Редагувати обраний мовний пакет…", + "FrmAbout._Privacy": "Політика конфіденційності", + "FrmSettings._EnableRecursiveLoading": "Шукати зображення у вкладених папках", + "_._UserAction._MethodArgumentNotSupported": "Тип аргументу методу '{0}' не підтримується", + "FrmSettings._FileExtensionIcons._Description": "Для налаштування іконок розширень файлів завантажте пакунок іконок, помістіть всі файли з розширенням .ICO в папку іконок розширень та натисніть кнопку '{0}'. Це також встановить ImageGlass як переглядач фотографій за замовчуванням.", + "_.ImageOrderType._Asc": "За зростанням", + "FrmExportFrames._Title": "Експорт сторінок зображень", + "_._Install": "Встановити…", + "FrmMain.MnuFlipHorizontal": "Віддзеркалити по горизонталі", + "FrmSettings._OpenExtensionIconFolder": "Відкрити папку іконок розширень", + "FrmAbout._Collaborator": "Співавтор:", + "FrmQuickSetup._ConfirmCloseProcess": "Перед застосуванням нових налаштувань важливо закрити всі процеси ImageGlass. Ви готові продовжити?", + "FrmExportFrames._ExportDone": "{0} сторінок експортовано в\n{1}", + "FrmCrop.BtnSaveAs._Tooltip": "Зберегти як копію…", + "FrmMain.MnuOpenFile": "Відкрити файл…", + "FrmColorPickerSettings.ChkShowRgbA": "Використовувати RGB формат з альфа-значенням", + "_.ImageInfo._ListCount": "файл(ів): {0}", + "FrmMain.MnuGoToLast": "Перейти до останнього зображення", + "FrmSettings._EditApps._AppName": "Назва застосунка", + "FrmSettings._SlideshowBackgroundColor": "Колір фону слайд-шоу", + "FrmAbout._Email": "Електронна пошта:", + "_.MouseWheelAction._DoNothing": "Нічого не робити", + "FrmMain.MnuSaveAs": "Зберегти як…", + "FrmMain._Loading": "Завантаження…", + "_._Browse": "Огляд…", + "FrmMain.MnuSetDefaultPhotoViewer._Error": "Не вдалося встановити ImageGlass як основний переглядач фотографій.", + "FrmSettings.Nav._Language": "Мова", + "FrmQuickSetup._SeeWhatNew": "Переглянути, що нового у цій версії…", + "FrmSettings._ImageInterpolation._ScaleUp": "Коли масштаб > 100%", + "FrmSettings.Layout._ToolbarContextPosition": "Положення контекстної панелі інструментів", + "FrmMain.MnuDeleteFromHardDisk": "Видалити остаточно", + "FrmSettings._EmbeddedThumbnail": "Вбудовані мініатюри", + "FrmMain.MnuDeleteFromHardDisk._Description": "Ви впевнені, що хочете остаточно видалити цей файл?", + "FrmMain.MnuScaleToFill": "Заповнювати", + "FrmCrop.BtnCrop": "Обрізати", + "_.AfterEditAppAction._Minimize": "Згорнути", + "FrmMain.MnuInvertColors": "Invert colors", + "FrmSettings._StartupBoost": "Startup Boost", + "FrmMain.MnuViewFirstFrame": "Переглянути перший фрейм", + "_.MouseWheelEvent._CtrlAndScroll": "Утримуйте Ctrl і прокрутіть", + "FrmSettings._HideMainWindowInSlideshow": "Автоматично приховувати головне вікно", + "_.Metadata._FrameCount": "Кадри", + "FrmSettings._EnableCopyMultipleFiles": "Увімкнути копіювання кількох файлів одночасно", + "FrmMain.MnuFrameless._EnableDescription": "Утримуйте клавішу Shift, щоб перемістити вікно.", + "_.ImageOrderBy._ExifDateTaken": "EXIF: Date taken", + "FrmAbout._Credits": "Подяка", + "FrmSettings._AddNewFileExtension": "Додати нове розширення файлу", + "FrmMain.MnuQuickSetup": "Відкрити ImageGlass швидке налаштування", + "FrmMain.MnuSave._Success": "Зображення збережено", + "FrmMain.MnuPanLeft": "Панорама зображення ліворуч", + "FrmUpdate._StatusChecking": "Перевірка наявності оновлень…", + "FrmSettings.Nav._Layout": "Зовнішній вигляд", + "FrmMain.MnuOpenWith": "Відкрити за допомогою…", + "FrmAbout._Thanks": "Особлива подяка:", + "_._Warning": "Попередження", + "FrmSettings.Nav._Keyboard": "Клавіатура", + "FrmSlideshow._PauseSlideshow": "Слайд-шоу призупинено.", + "_._Add+": "Додати…", + "_._Email": "Ел. пошта", + "FrmMain.MnuPanDown": "Панорама зображення вниз", + "_._Cancel": "Скасувати", + "_._OK": "ОК", + "FrmMain.MnuPanRight": "Панорама зображення праворуч", + "_.Position._Right": "Праворуч", + "_._Icon": "Іконка", + "FrmSettings._ShouldLoadHiddenImages": "Завантажити приховані зображення", + "_._InvalidAction._Transformation": "ImageGlass does not support rotation, flipping for this image.", + "FrmSettings._MakeDefault": "Використовувати за замовчуванням", + "FrmMain.MnuCopyImageData._Copying": "Копіювання даних зображення. Це займе деякий час…", + "FrmSettings._UseEmbeddedThumbnailRawFormats": "Завантажити лише вбудовані мініатюри для форматів RAW", + "_.ImageInterpolation._Linear": "Лінійний", + "FrmSettings._ImageInfoTags": "Теги інформації про зображення", + "FrmSettings._FileExtensionIcons": "Іконки розширень файлів", + "FrmMain.MnuEdit._AppNotFound": "Не вдалося знайти пов'язану програму для редагування. Ви можете призначити додаток для редагування цього формату у налаштуваннях ImageGlass > Редагувати.", + "_.ColorProfileOption._None": "Жоден", + "FrmSettings._TotalSupportedFormats": "Загальна кількість підтримуваних форматів: {0}", + "FrmSettings._Clipboard": "Буфер обміну", + "_._UserAction._Win32ExeError": "Не вдалося виконати команду '{0}'. Переконайтеся, що ім'я правильне.", + "FrmCropSettings.DefaultSelectionType._SelectX": "Вибрати {0}", + "_.AfterEditAppAction._Close": "Закрити", + "FrmAbout._LogoDesigner": "Дизайнер логотипу:", + "_.ImageOrderBy._Name": "Назва файлу (за замовчуванням)", + "FrmMain.MnuRemoveDefaultPhotoViewer._Error": "Не вдалося вилучити ImageGlass як основний переглядач фотографій.", + "FrmExportFrames._FolderPickerTitle": "Виберіть папку призначення для експорту сторінок", + "FrmAbout._Donate": "Пожертвувати", + "FrmMain.MnuFrameNav": "Рамкова навігація", + "FrmMain.MnuSetLockScreen": "Встановити зображенням екрану блокування", + "_._Delete": "Видалити", + "FrmMain.MnuViewPrevious": "Попереднє зображення", + "_.Position._Top": "Вгорі", + "FrmSettings.Toolbar._CurrentButtons": "Поточні кнопки:", + "FrmMain.MnuAbout": "Про застосунок", + "FrmSettings._RemoveDefault": "Вилучити за замовчуванням", + "_._Description": "Опис", + "FrmMain.MnuPasteImage._Error": "Не вдалося знайти дані зображення в буфері обміну", + "FrmMain.MnuSettings": "Налаштування", + "FrmCropSettings._Title": "Налаштування інструменту 'Обрізати'", + "FrmSettings.Toolbar._ToolbarIconHeight": "Розмір піктограм", + "FrmSettings._SlideshowInterval._To": "До", + "FrmSettings.Layout._ToolbarPosition": "Позиція панелі інструментів", + "FrmUpdate._StatusUpdated": "Ви використовуєте останню версію!", + "FrmMain.MnuExit": "Вийти", + "_._Webview2._Outdated": "Your WebView2 Runtime is not supported. Please update to version {0} or later.", + "_._Yes": "Так", + "FrmMain.MnuRotateLeft": "Повернути вліво", + "FrmSettings._EnableStartupBoost": "Enable Startup Boost", + "_.ImageOrderBy._ExifRating": "EXIF: Rating", + "FrmMain.MnuZoomIn": "Збільшити", + "_.Metadata._ColorSpace": "Колірний простір", + "FrmAbout._Version": "Версія:", + "FrmMain.MnuToggleTopMost._Enable": "Увімкнено: завжди поверх усіх вікон", + "FrmSettings.Toolbar._AvailableButtons": "Доступні кнопки:", + "FrmMain.MnuSave._Saving": "Збереження зображення…", + "FrmQuickSetup._StandardUser": "Стандартний користувач", + "FrmMain.MnuSetLockScreen._Error": "Не вдалося встановити зображення як фон екрана блокування", + "FrmSettings.Nav._Image": "Зображення", + "FrmSettings._Theme._InstallTheme": "Встановити пакети тем", + "FrmSettings._EnableMultiInstances": "Дозволити декілька екземплярів застосунку", + "FrmMain.MnuCropTool": "Обрізати зображення", + "_._IgCommandExe._DefaultError._Heading": "Некоректна команда", + "_._Refresh": "Оновити", + "FrmMain.MnuLosslessCompression._Description": "This tool uses Magick.NET library for lossless compression, optimizing file size. Overwrites only if the compressed file is smaller than the original.", + "_._MoveDown": "Перемістити вниз", + "FrmSettings._GetExtensionIconPacks": "Отримати пакунки іконок розширень…", + "FrmSettings._InAppMessageDuration": "Час відображення повідомлень у програмі (у мілісекундах)", + "FrmMain.MnuFrameless": "Без рамок", + "_._Reset": "Скинути", + "FrmSettings._ConfigDir": "Місцезнаходження конфігурації", + "FrmQuickSetup._SettingsWillBeApplied": "Налаштування будуть застосовані:", + "FrmSettings._UnmanagedSettingReminder": "This setting is not managed by ImageGlass. Don't forget to disable it before you remove or relocate the app because ImageGlass does not handle this automatically.", + "FrmMain.MnuClipboard": "Буфер обміну", + "FrmMain.MnuCustomZoom": "Довільне масштабування…", + "FrmSettings._DisplayLanguage": "Мова інтерфейсу", + "FrmMain.MnuPrint._Error": "Не вдалося надрукувати зображення", + "FrmSettings._ShouldPreserveModifiedDate": "Зафіксувати дату модифікації зображення при зберіганні", + "FrmSettings._ShowSaveOverrideConfirmation": "Показувати діалогове вікно підтвердження під час перезапису файлу", + "FrmColorPickerSettings.ChkShowHexA": "Використовувати HEX формат з альфа-значенням", + "FrmMain.MnuFullScreen": "На весь екран", + "FrmSettings._StartupDir": "Місце запуску", + "FrmSettings._ShowCheckerboardOnlyImageRegion": "Відображення фону (шахової дошки) лише в області зображення", + "FrmMain.MnuClearClipboard._Success": "Буфер обміну очищено.", + "FrmQuickSetup._Text": "Швидке налаштування ImageGlass", + "FrmMain.MnuLosslessCompression._Done": "Done lossless compression.\r\nThe new file size is {0}, saved {1}.", + "FrmMain.MnuLosslessCompression": "Magick.NET Lossless Compression", + "FrmResize.RadResizeByPercentage": "Percentage", + "FrmSettings._StartupBoost._Disabled": "Startup Boost is disabled", + "FrmMain.MnuToggleCheckerboard": "Прозорий фон", + "FrmSettings._MinEmbeddedThumbnailSize._Height": "Висота", + "FrmSettings.Nav._General": "Загальні", + "FrmSettings._ImageLoading": "Завантаження зображення", + "FrmSettings._ShowSlideshowCountdown": "Показувати відлік слайд-шоу", + "FrmMain.MnuSave": "Зберегти", + "FrmMain.MnuMoveToRecycleBin": "Перемістити до кошика", + "FrmMain.MnuRefresh": "Оновити", + "FrmToolNotFound.LblHeading": "'{0}' не знайдено!", + "FrmMain.MnuReportIssue": "Повідомити про проблему…", + "FrmMain.MnuCopyImageData": "Копіювати зображення", + "FrmMain.MnuCheckForUpdate._NewVersion": "Доступна нова версія!", + "_._Empty": "(порожній)", + "FrmSettings._Zooming": "Масштабування", + "FrmMain.MnuCutFile": "Вирізати файл", + "FrmHotkeyPicker.LblHotkey": "Натисніть клавіші швидкого доступу", + "FrmSettings.Layout._Gallery": "Галерея", + "FrmMain.MnuNewWindow": "Відкрити нове вікно", + "FrmMain.MnuMoveToRecycleBin._Description": "Ви хочете перемістити цей файл в кошик?", + "FrmSettings._DefaultPhotoViewer": "Перегляд фотографій за умовчанням", + "_.Metadata._ExifDateTimeOriginal": "EXIF: DateTimeOriginal", + "FrmMain.MnuRotateRight": "Повернути вправо", + "FrmSettings._MinEmbeddedThumbnailSize": "Мінімальний розмір вбудованої мініатюри для завантаження", + "FrmMain.MnuSetDefaultPhotoViewer": "Встановити ImageGlass як основний переглядач фотографій", + "FrmMain.MnuImageProperties": "Властивості зображення", + "FrmSettings._EnableNavigationButtons": "Показати кнопки зі стрілками навігації", + "_._Edit": "Редагувати", + "FrmSettings._ImageBooster": "Прискорювач зображень", + "FrmSettings.Tools._IntegratedWith": "Інтегровано з {0}", + "_._Next": "Далі", + "FrmExportFrames._OpenOutputFolder": "Відкрийте вихідну папку", + "FrmMain.MnuOpenLocation": "Відкрити місце розташування зображення", + "FrmMain.MnuLockZoom": "Закріпити масштаб", + "FrmSettings._StartupBoost._Description": "Preload and run ImageGlass in the background for a few seconds during Windows startup to accelerate the first launch.", + "FrmSettings._WindowBackdrop": "Фон вікна", + "FrmSettings._EnableRealTimeFileUpdate": "Слідкувати за змінами файлу в папці перегляду і оновлювати в реальному часі", + "_._NotSupported": "Непідтримуваний формат", + "FrmSettings._Theme._GetMoreThemes": "Отримати додаткові пакети тем…", + "FrmMain.MnuNewWindow._Error": "Неможливо відкрити нове вікно, тому що дозволено лише один екземпляр", + "FrmMain.MnuZoomOut": "Зменшити", + "FrmSettings.Toolbar._EditButton": "Редагувати кнопку панелі інструментів", + "FrmMain.MnuCustomZoom._Description": "Введіть нове значення масштабування", + "FrmResize.RadResizeByPixels": "Pixels", + "FrmMain.MnuEdit": "Редагування зображення {0}…", + "FrmSettings.Layout._GalleryPosition": "Розташування галереї", + "FrmMain.MnuWindowFit": "Відповідно до вікна", + "FrmMain._OpenFileDialog": "Всі підтримувані файли", + "FrmSettings._UseRandomIntervalForSlideshow": "Використовувати випадковий інтервал", + "_.Position._Left": "Ліворуч", + "FrmSettings._ShouldOpenLastSeenImage": "Відкрити останнє переглянуте зображення", + "_.Position._Bottom": "Внизу", + "FrmResize.ChkKeepRatio": "Keep ratio propotional", + "FrmMain.MnuGoTo": "Перейти до…", + "FrmSlideshow.MnuPauseResumeSlideshow": "Призупинити / відновити слайд-шоу", + "FrmSettings.Tools._Integrated": "Інтегрований", + "FrmSettings._Contributors": "Учасники", + "_.MouseWheelAction._Zoom": "Збільшити / зменшити", + "_._CommandPreview": "Попередній перегляд", + "FrmSettings._DarkTheme": "Темна тема", + "_._Hotkeys": "Гарячі клавіші", + "_.Metadata._ExifDateTime": "EXIF: DateTime", + "FrmSettings.Toolbar._Errors._ButtonIdRequired": "Необхідно вказати ID кнопки.", + "FrmSettings._MinEmbeddedThumbnailSize._Width": "Ширина", + "_._Executable": "Виконуваний файл", + "_.ImageInterpolation._MultiSampleLinear": "Багатовибірковий лінійний", + "_._Separator": "Розділювач", + "FrmQuickSetup._ProfessionalUser": "Професійний користувач", + "FrmMain.MnuFlipVertical": "Віддзеркалити по вертикалі", + "FrmSlideshow._ResumeSlideshow": "Слайд-шоу відновлено.", + "FrmCropSettings.DefaultSelectionType._CustomArea": "Свій варіант…", + "FrmMain.MnuActualSize": "Фактичний розмір", + "FrmCrop.BtnSaveAs": "Зберегти як…", + "FrmSettings._InstallNewLanguagePack": "Встановити нові мовні пакети…", + "FrmSlideshow.MnuZoomModes": "Режими масштабування", + "FrmMain.MnuTools": "Інструменти", + "_.ImageInterpolation._Cubic": "Кубічний", + "FrmUpdate._LatestVersion": "Остання версія: {0}", + "FrmMain.MnuViewNext": "Наступне зображення", + "_.MouseWheelEvent._AltAndScroll": "Утримуйте Alt і прокрутіть", + "FrmToolNotFound._Title": "Інструмент не знайдено", + "FrmCrop.BtnCrop._Tooltip": "Обрізати зображення", + "FrmSettings.EditAppDialog._AddApp": "Додайте додаток для редагування", + "FrmMain.MnuPanning": "Панорамування", + "_._MoveUp": "Перемістити вгору", + "FrmCropSettings.DefaultSelectionType._SelectAll": "Вибрати все", + "_._Name": "Назва", + "FrmColorPickerSettings.ChkShowHslA": "Використовувати HSL формат з альфа-значенням", + "FrmMain.MnuToggleImageAnimation": "Почати / зупинити анімацію зображення", + "FrmSettings._DisableStartupBoost": "Disable Startup Boost", + "FrmMain.MnuCopyFile._Success": "Скопійовано файл(ів): {0}.", + "FrmMain.MnuSave._ConfirmDescription": "ImageGlass не є професійним фоторедактором. Будь ласка, враховуйте можливість втрати якості, метаданих, шарів… під час збереження вашого зображення.", + "FrmToolNotFound.BtnSelectExecutable": "Вибрати…", + "FrmUpdate._StatusOutdated": "Доступне нове оновлення!", + "_.ImageOrderBy._Random": "Випадковий", + "FrmResize.LblCurrentSize": "Current Size:", + "_._Apply": "Застосувати", + "FrmAbout._Slogan": "Легкий, універсальний переглядач зображень", + "FrmMain.MnuPanToTop": "Панорама зображення до верхнього краю", + "FrmSettings.Toolbar._AddNewButton": "Додати власну кнопку панелі інструментів", + "FrmCrop.LblSize": "Розмір:", + "FrmSettings._ImageInterpolation._ScaleDown": "Коли масштаб < 100%", + "_._CreatingFileError": "Не вдалося створити тимчасовий файл зображення", + "FrmMain.MnuGoTo._Description": "Введіть індекс зображення для перегляду, а потім натисніть ENTER", + "FrmSettings.Toolbar._EnableCenterToolbar": "Використовуйте вирівнювання по центру для панелі інструментів", + "FrmMain.MnuResizeTool": "Resize image", + "FrmSettings.Layout._Toolbar": "Панель інструментів", + "FrmMain.MnuHelp": "Допомога", + "_.ImageOrderBy._FileSize": "Розмір файлу", + "FrmSettings._Theme._OpenThemeFolder": "Відкрити теку з темою", + "FrmMain.MnuNavigation": "Навігація", + "_._Save": "Зберегти", + "FrmQuickSetup._SettingProfileDescription": "Щоб змінити ці параметри, просто зайдіть у налаштування додатку.", + "_._UserAction._MenuNotFound": "Не вдалося знайти меню '{0}', щоб викликати дію", + "FrmMain.MnuPanToLeftSide": "Панорама зображення до лівого краю", + "FrmUpdate._CurrentVersion": "Поточна версія: {0}", + "FrmCrop.BtnSettings._Tooltip": "Відкрити налаштування обрізання", + "_.ColorProfileOption._Custom": "Налаштувати…", + "FrmSettings._UseEmbeddedThumbnailOtherFormats": "Завантажити лише вбудовані мініатюри для інших форматів", + "FrmMain.MnuGoToFirst": "Перейти до першого зображення", + "FrmSettings._ExportLanguagePack": "Експорт мовного пакету…", + "FrmSettings.Nav._Mouse": "Миша", + "_.ImageOrderBy._DateCreated": "Дата створення", + "FrmSettings._EnableFullscreenSlideshow": "Почати слайд-шоу в повноекранному режимі", + "FrmAbout._Homepage": "Домашня сторінка:", + "FrmSettings._GalleryCacheSizeInMb": "Максимальний розмір кешу галереї (у мегабайтах)", + "FrmMain.MnuCopyImageData._Success": "Скопійовано поточні дані зображення.", + "FrmSettings._EnableLoopBackNavigation": "Повертатися до першого зображення, коли досягнете кінця списку зображень", + "_.MouseWheelEvent._Scroll": "Прокрутити", + "FrmCrop.BtnSave._Tooltip": "Зберегти зображення", + "FrmMain.MnuSlideshow": "Слайд-шоу", + "FrmMain.MnuShare": "Поділитися…", + "FrmSettings._SlideshowNotification": "Сповіщення про слайд-шоу", + "FrmMain.MnuViewChannels": "Перегляд каналів", + "FrmSettings._Refresh": "Оновити", + "_._UserAction._MethodNotFound": "Не вдалося знайти метод '{0}', щоб викликати дію", + "FrmMain.MnuCopyFile": "Копіювати файл", + "_._CreatingFile": "Створити тимчасовий файл зображення…", + "FrmMain.MnuToggleTopMost": "Закріпити вікно поверх інших", + "FrmMain.MnuLosslessCompression._Confirm": "Are you sure you want to proceed?", + "FrmMain.MnuImage": "Зображення", + "FrmSettings._StartupBoost._Enabled": "Startup Boost is enabled", + "FrmQuickSetup._SetDefaultViewer": "Ви хочете встановити ImageGlass як переглядач фотографій за замовчуванням?", + "FrmMain.MnuScaleToWidth": "Масштаб за шириною", + "_._FileExtension": "Розширення файлу", + "FrmUpdate._PublishedDate": "Дата публікації: {0}", + "_._DoNotShowThisMessageAgain": "Не показувати це повідомлення знову", + "_.ImageInterpolation._NearestNeighbor": "Метод сусідніх пікселів", + "FrmCrop.LblLocation": "Розташування:", + "_._Download": "Завантажити", + "_.Metadata._ColorProfile": "Профіль кольорів", + "FrmSettings._CenterWindowFit": "Автоматичне центрування вікна в режимі «За розміром вікна»", + "FrmSettings._ImageLoadingOrder": "Порядок завантаження зображень", + "FrmSettings._GalleryColumns": "Кількість стовпців мініатюр у вертикальному розташуванні галереї", + "_._Quit": "Вийти", + "_._Add": "Додати", + "FrmMain.MnuChangeBackgroundColor": "Змінити колір фону…", + "FrmMain.MnuToggleToolbar": "Панель інструментів", + "FrmAbout._Contact": "Контакти", + "FrmSettings.Toolbar._AddCustomButton": "Додати власну кнопку…", + "FrmCrop.BtnQuickSelect._Tooltip": "Швидкий вибір…", + "FrmMain.MnuCutFile._Success": "Файл(ів) вирізано: {0}.", + "FrmSettings._ZoomSpeed": "Швидкість масштабування", + "FrmMain.MnuToggleTopMost._Disable": "Вимкнено: завжди поверх усіх вікон", + "FrmSettings._ShouldUseExplorerSortOrder": "Use Explorer sort order if possible", + "_.ImageInterpolation._Antisotropic": "Анізотропний", + "FrmMain._ReachedFirstImage": "Досягнуто перше зображення", + "_._UnhandledException": "Необроблена помилка", + "FrmResize.LblNewSize": "New Size:", + "FrmMain._ClipboardImage": "Зображення в буфері обміну", + "FrmMain.MnuExportFrames": "Експортер сторінок зображень…", + "FrmMain.MnuFile": "Файл", + "_._Close": "Закрити", + "FrmMain.MnuMain": "Головне меню", + "_._ResetToDefault": "Скинути до типових", + "FrmSettings.Nav._Gallery": "Галерея", + "FrmMain.MnuSetDefaultPhotoViewer._Success": "Ви успішно встановили ImageGlass як основний переглядач фотографій.", + "FrmSettings._HideGalleryInFullscreen": "Приховати галерею в повноекранному режимі", + "FrmSettings._AvailableImageInfoTags": "Доступні теги:", + "FrmExportFrames._Exporting": "Експорт сторінок: {0}/{1}\n{2}…", + "_._Argument": "Аргумент", + "FrmSettings._ImageEditQuality": "Якість зображення", + "_._ID": "ID", + "FrmSettings._UserConfigFile": "Файл налаштувань користувача (igconfig.json)", + "FrmMain.MnuLoadingOrders": "За порядком завантаження", + "FrmSettings._OpenSaveAsDialogInTheCurrentImageDir": "Open the Save As dialog in the current image directory", + "_.MouseWheelEvent._ShiftAndScroll": "Утримуйте Shift і прокрутіть", + "FrmSettings._UseSmoothZooming": "Використовувати плавне масштабування", + "FrmSettings._Theme": "Тема", + "FrmSettings._ImageBoosterCacheMaxDimension": "Максимальний розмір зображення для кешування (у пікселях)", + "FrmMain.MnuScaleToHeight": "Масштаб за висотою", + "_.Metadata._FileLastWriteTime": "Дата зміни", + "FrmSettings._Author": "Автор", + "FrmSettings._Others": "Інше", + "_.MouseWheelAction._PanVertically": "Прокручування вгору / вниз", + "FrmSettings._MouseWheelAction": "Дія колеса миші", + "FrmSettings.Nav._Tools": "Інструменти", + "FrmMain.MnuSetDesktopBackground._Error": "Не вдалося встановити зображення як фон робочого столу", + "FrmSettings.Toolbar._Errors._ButtonExecutableRequired": "Потрібно вказати виконуваний файл кнопки.", + "_.ImageOrderBy._DateAccessed": "Дата доступу", + "FrmSettings._ThumbnailSize": "Розмір мініатюри (в пікселях)", + "FrmSettings._FileFormats": "Формати файлів", + "FrmMain.MnuReloadImageList": "Перезавантажити список зображень", + "FrmSettings._UseWebview2ForSvg": "Використовувати Webview2 для перегляду формату SVG", + "FrmCrop.BtnCopy": "Копіювати", + "FrmSettings._CurrentMonitorProfile._Description": "ImageGlass не оновлює колір при переміщенні вікна між моніторами", + "FrmMain.PicMain._ErrorText": "Не вдалося відкрити це зображення", + "FrmSettings.Tools._AddNewTool": "Додати зовнішній інструмент", + "FrmMain.MnuRename": "Перейменувати зображення…", + "FrmMain.MnuViewLastFrame": "Переглянути останній фрейм", + "_._Webview2._NotFound": "Please install WebView2 Runtime to access full features of ImageGlass.", + "FrmMain.MnuGetMoreTools": "Отримати більше інструментів…", + "FrmSettings.Nav._Appearance": "Вигляд", + "FrmSettings._SlideshowInterval": "Інтервал зміни слайдів:", + "_.ImageInterpolation._HighQualityBicubic": "Висока якість, бікубічна", + "FrmColorPickerSettings.ChkShowHsvA": "Використовувати HSV формат з альфа-значенням", + "FrmSettings.Tools._EditTool": "Редагувати зовнішній інструмент", + "_._Error": "Помилка", + "FrmSettings._ImageBoosterCacheMaxFileSizeInMb": "Максимальний розмір файлу зображення для кешування (в мегабайтах)", + "_._UnhandledException._Description": "Виникла необроблена помилка. Якщо натиснути Продовжити, програма проігнорує цю помилку та спробує продовжити. Якщо натиснути Вийти, програма негайно закриється.", + "_.Metadata._FileSize": "Розмір файлу", + "FrmSettings.Toolbar._ButtonJson": "Кнопка JSON", + "FrmQuickSetup._SetDefaultViewer._Description": "Ви можете скинути його в налаштуваннях програми > на вкладці Асоціації файлів.", + "FrmSettings.Nav._Edit": "Редагувати", + "FrmMain.MnuToggleGallery": "Панель галереї", + "_._IgCommandExe._DefaultError._Description": "Переконайтеся, що ви передаєте правильні команди!\r\nЦей виконуваний файл містить функції командного рядка для програми ImageGlass.\r\n\r\nЩоб вивчити всі функції командного рядка,\nбудь ласка, відвідайте: {0}", + "FrmMain.MnuLosslessCompression._Compressing": "Performing lossless compression…", + "FrmSettings._ShouldGroupImagesByDirectory": "Групувати зображення за текою", + "FrmMain.MnuPanToRightSide": "Панорама зображення до правого краю", + "_.Metadata._ExifRatingPercent": "Рейтинг", + "FrmSettings._PanSpeed": "Швидкість прокручування", + "_._CheckForUpdate": "Перевірити наявність оновлень…", + "FrmSettings.Layout._ToolbarContext": "Контекстна панель інструментів", + "_.ImageInfo._FrameCount": "кадр(ів): {0}", + "FrmMain.MnuLayout": "Зовнішній вигляд", + "_._Website": "Веб-сайт", + "FrmMain.MnuPasteImage": "Вставити зображення", + "FrmSettings._ShowGalleryScrollbars": "Показувати полоси прокрутки для галереї" + } +} \ No newline at end of file diff --git a/Setup/Assets/Language/Vietnamese.iglang.json b/Setup/Assets/Language/Vietnamese.iglang.json new file mode 100644 index 000000000..a9fe987b0 --- /dev/null +++ b/Setup/Assets/Language/Vietnamese.iglang.json @@ -0,0 +1,504 @@ +{ + "_Metadata": { + "Code": "vi-VN", + "EnglishName": "Vietnamese", + "LocalName": "Tiếng Việt", + "Author": "Dương Diệu Pháp", + "MinVersion": "9.3" + }, + "Items": { + "FrmCrop.SelectionAspectRatio._Original": "Gốc", + "FrmMain.MnuShare._Error": "Không thể mở hộp thoại Chia sẻ.", + "_.Metadata._FileLastAccessTime": "Ngày truy cập", + "FrmAbout._License": "Bản quyền phần mềm", + "FrmSettings.Toolbar._Errors._ButtonIdDuplicated": "Nút với ID '{0}' đã có sẵn. Vui lòng chọn một ID khác cho nút của bạn.", + "FrmMain.MnuSave._Confirm": "Bạn có chắc chắn muốn lưu đè lên ảnh này?", + "FrmSettings._OpenDefaultAppsSetting": "Mở cài đặt Ứng dụng mặc định", + "FrmMain.MnuCopyPath": "Sao chép đường dẫn hình ảnh", + "FrmCropSettings.DefaultSelectionType._SelectNone": "Không chọn gì cả", + "_.MouseWheelAction._PanHorizontally": "Lia ảnh trái / phải", + "FrmMain.MnuPrint": "In…", + "FrmSettings.Toolbar._ToolbarButtons": "Nút trên thanh công cụ", + "FrmResize.LblResample": "Resample:", + "_.ImageOrderBy._Extension": "Phần mở rộng", + "FrmSettings.Nav._Viewer": "Vùng xem ảnh", + "FrmSettings.EditAppDialog._EditApp": "Chỉnh sửa ứng dụng", + "FrmCrop.BtnReset._Tooltip": "Cài đặt lại vùng chọn", + "FrmMain.MnuRename._Description": "Nhập một tên mới:", + "_._No": "Không", + "FrmSlideshow.MnuToggleCountdown": "Hiển thị đồng hồ đếm ngược trong chế độ Trình chiếu ảnh", + "FrmSettings._OpenStartupAppsSetting": "Mở cài đặt Startup apps", + "FrmMain.MnuViewPreviousFrame": "Xem khung hình trước đó", + "_.ImageOrderBy._DateModified": "Ngày chỉnh sửa", + "FrmMain.MnuViewNextFrame": "Xem khung hình tiếp theo", + "FrmMain.MnuUnload": "Giải phóng ảnh từ bộ nhớ", + "FrmSettings.Toolbar._HideToolbarInFullscreen": "Ẩn thanh công cụ trong chế độ Toàn màn hình", + "_.ImageOrderType._Desc": "Giảm dần", + "_._Update": "Cập nhật", + "FrmSettings._EnableImageAsyncLoading": "Cho phép tải ảnh không đồng bộ", + "FrmSettings._DefaultPhotoViewer._Description": "Đăng ký các định dạng mà ImageGlass hỗ trợ với Windows. Bạn có thể cần mở cài đặt Default apps và chọn ImageGlass từ danh sách ứng dụng để nó có hiệu lực.", + "_.MouseWheelAction._BrowseImages": "Xem ảnh tiếp theo / trước đó", + "FrmSettings._EditApps": "Ứng dụng chỉnh sửa ảnh", + "FrmColorPickerSettings.ChkShowCIELabA": "Sử dụng định dạng CIELAB với giá trị alpha", + "_._GetHelp": "Trợ giúp", + "FrmQuickSetup._SkipQuickSetup": "Bỏ qua và khởi chạy ImageGlass", + "FrmColorPickerSettings._Title": "Cài đặt công cụ Chọn màu", + "_._Copy": "Sao chép", + "FrmSettings._ImageBoosterCacheCount": "Số lượng tập tin ảnh được nạp trước vào bộ nhớ bởi Image Booster (một chiều)", + "FrmMain.MnuPanToBottom": "Lia ảnh tới góc dưới cùng", + "FrmMain.MnuZoom": "Phóng to / Thu nhỏ", + "FrmCropSettings.ChkCloseToolAfterSaving": "Đóng công cụ Cắt ảnh sau khi lưu", + "FrmSettings._ShowWelcomeImage": "Hiển thị ảnh chào mừng", + "FrmSettings._ColorProfile": "Cấu hình màu", + "FrmSettings._Theme._UninstallTheme": "Gỡ bỏ gói chủ đề", + "FrmMain._OpenWith": "Mở với {0}", + "FrmMain.MnuRemoveDefaultPhotoViewer": "Huỷ làm trình xem ảnh mặc định", + "_.AfterEditAppAction._Nothing": "Không làm gì", + "FrmCrop.BtnSave": "Lưu", + "FrmMain.MnuScaleToFit": "Co dãn hình ảnh vừa khít", + "FrmToolNotFound.LblDownloadToolText": "Bạn có thể tải thêm công cụ cho ImageGlass tại:", + "_._LearnMore": "Tìm hiểu thêm…", + "FrmCrop.LblAspectRatio": "Tỷ lệ khung hình:", + "FrmExportFrames._FileNotExist": "Tập tin không tồn tại", + "FrmSettings._LightTheme": "Sáng", + "FrmSettings.Nav._Slideshow": "Trình chiếu ảnh", + "_._Continue": "Tiếp tục", + "_._AddHotkey": "Thêm phím tắt…", + "FrmMain.MnuSetDesktopBackground": "Đặt ảnh đang xem làm hình nền", + "FrmMain.MnuReload": "Tải lại ảnh", + "FrmSlideshow.MnuExitSlideshow": "Thoát khỏi trình chiếu ảnh", + "FrmMain.MnuAutoZoom": "Thu phóng tự động", + "FrmSettings._ShowImagePreview": "Hiển thị ảnh xem trước khi ảnh đang được tải vào bộ nhớ", + "FrmCrop.BtnCopy._Tooltip": "Sao chép vùng chọn vào Bộ nhớ tạm", + "FrmSettings.Nav._Toolbar": "Thanh công cụ", + "FrmMain.MnuSave._Error": "Không thể lưu ảnh", + "FrmSettings._AfterEditingAction": "Sau khi mở ứng dụng chỉnh sửa", + "FrmSettings._ShouldUseColorProfileForAll": "Áp dụng luôn cho ảnh không có Cấu hình màu", + "FrmCropSettings.DefaultSelectionType._UseTheLastSelection": "Sử dụng vùng chọn lần trước", + "FrmSettings._SlideshowInterval._From": "Từ", + "FrmSettings._ImageInterpolation": "Chế độ nội suy hình ảnh", + "FrmQuickSetup._StepInfo": "Bước {0}", + "FrmMain.MnuColorPicker": "Công cụ chọn màu", + "FrmCrop.SelectionAspectRatio._FreeRatio": "Tỷ lệ tự do", + "FrmSettings._ResetSettings": "Thiết lập lại cài đặt", + "FrmSettings._Startup": "Khởi động", + "_.BackdropStyle._None": "Không", + "FrmSettings._LoadDefaultZoomLevels": "Tải giá trị mặc định", + "FrmColorPicker.BtnSettings._Tooltip": "Mở cài đặt công cụ Chọn màu…", + "FrmSettings._UseThemeForDarkMode": "Sử dụng gói chủ đề này cho chế độ tối", + "FrmSettings._ShowDeleteConfirmation": "Hiển thị hộp thoái xác nhận khi xoá tập tin", + "FrmSettings._ShowAppIcon": "Hiển thị logo ứng dụng trên thanh tiêu đề", + "_._InvalidAction": "Thao tác không hợp lệ", + "FrmQuickSetup._SelectProfile": "Chọn cấu hình", + "_.Metadata._FileCreationTime": "Ngày tạo", + "FrmSettings._SlideshowImagesToNotifySound": "Số lượng ảnh để phát thông báo âm thanh", + "FrmSettings._BackgroundColor": "Màu nền", + "FrmSettings._RealTimeFileUpdate": "Cập nhật tập tin trong thời gian thực", + "_.ColorProfileOption._CurrentMonitorProfile": "Sử dụng cấu hình màu của màn hình", + "FrmSettings._EnableCutMultipleFiles": "Bật tính năng cắt nhiều tập tin cùng một lúc", + "FrmSettings._AutoUpdate": "Tự động kiểm tra phiên bản mới", + "FrmCropSettings.LblDefaultSelection": "Cài đặt vùng chọn mặc định", + "FrmSettings._UseThemeForLightMode": "Sử dụng gói chủ đề này cho chế độ sáng", + "FrmSettings._ZoomLevels": "Cấp độ phóng to thu nhỏ", + "FrmMain.MnuSetLockScreen._Success": "Đã cập nhật ảnh màn hình khoá", + "FrmSettings._ShowGalleryFileName": "Hiển thị tên tập tin ảnh", + "FrmSettings.Layout._Order": "Thứ tự", + "FrmCropSettings.ChkAutoCenterSelection": "Tự động căn giữa vùng chọn", + "FrmSettings.Nav._FileTypeAssociations": "Liên kết loại tập tin", + "_._Back": "Quay lại", + "FrmMain.MnuSetDesktopBackground._Success": "Đã cập nhật hình nền mày tính", + "FrmSettings._ShouldAutoOpenNewAddedImage": "Tự động mở ảnh vừa được thêm vào", + "FrmCrop.SelectionAspectRatio._Custom": "Tuỳ chọn…", + "FrmMain.MnuCopyPath._Success": "Đã sao chép đường dẫn của ảnh.", + "FrmSettings._StartupBoost._Error": "Không thể thay đổi cài đặt Tăng tốc khởi động", + "FrmToolNotFound.LblDescription": "ImageGlass không thể tìm thấy đường dẫn đến phần thực thi của '{0}'. Vui lòng cập nhật lại đường dẫn chính xác của '{0}'.", + "FrmMain.MnuClearClipboard": "Xoá Bộ nhớ tạm", + "FrmSettings._ColorManagement": "Quản lý màu sắc", + "FrmMain._ReachedLastLast": "Đã đến cuối danh sách", + "FrmMain.MnuPanUp": "Lia ảnh lên trên", + "FrmMain.MnuRemoveDefaultPhotoViewer._Success": "ImageGlass không còn là trình xem ảnh mặc định nữa.", + "FrmSettings._GetMoreLanguagePacks": "Tải về gói ngôn ngữ khác…", + "FrmAbout._Privacy": "Chính sách bảo mật", + "FrmSettings._EnableRecursiveLoading": "Tải ảnh trong các thư mục con", + "_._UserAction._MethodArgumentNotSupported": "Loại tham số của phương thức '{0}' không được hỗ trợ", + "FrmSettings._FileExtensionIcons._Description": "Để tùy chỉnh các biểu tượng tiện ích mở rộng tệp, hãy tải xuống gói biểu tượng, đặt tất cả các tập tin .ICO vào thư mục Biểu tượng tập tin và nhấp vào nút '{0}'. Thao tác này cũng đặt ImageGlass làm trình xem ảnh mặc định.", + "_.ImageOrderType._Asc": "Tăng dần", + "FrmExportFrames._Title": "Xuất khung hình", + "_._Install": "Cài đặt…", + "FrmMain.MnuFlipHorizontal": "Lật theo chiều ngang", + "FrmSettings._OpenExtensionIconFolder": "Mở thư mục biểu tượng tập tin", + "FrmAbout._Collaborator": "Cộng tác viên:", + "FrmQuickSetup._ConfirmCloseProcess": "Trước khi áp dụng các cài đặt mới, tất cả các cửa sổ đang chạy khác của ImageGlass cần phải đóng. Bạn có sẵn sàng để tiến hành?", + "FrmExportFrames._ExportDone": "Đã xuất {0} khung hình thành công \n{1}", + "FrmCrop.BtnSaveAs._Tooltip": "Lưu thành bản sao…", + "FrmMain.MnuOpenFile": "Mở tập tin…", + "FrmColorPickerSettings.ChkShowRgbA": "Sử dụng định dạng RGB với giá trị alpha", + "_.ImageInfo._ListCount": "{0} tập tin", + "FrmMain.MnuGoToLast": "Đi đến hình ảnh cuối cùng", + "FrmSettings._EditApps._AppName": "Tên ứng dụng", + "FrmSettings._SlideshowBackgroundColor": "Màu nền của chế độ trình chiếu", + "FrmAbout._Email": "Email:", + "_.MouseWheelAction._DoNothing": "Không làm gì cả", + "FrmMain.MnuSaveAs": "Lưu thành…", + "FrmMain._Loading": "Đang tải…", + "_._Browse": "Duyệt…", + "FrmMain.MnuSetDefaultPhotoViewer._Error": "Không thể đặt ImageGlass làm trình xem ảnh mặc định.", + "FrmSettings.Nav._Language": "Ngôn ngữ", + "FrmQuickSetup._SeeWhatNew": "Xem có gì mới trong phiên bản này…", + "FrmSettings._ImageInterpolation._ScaleUp": "Khi tỷ lệ phóng to ảnh > 100%", + "FrmSettings.Layout._ToolbarContextPosition": "Vị trí của Thanh công cụ ngữ cảnh", + "FrmMain.MnuDeleteFromHardDisk": "Xóa vĩnh viễn", + "FrmSettings._EmbeddedThumbnail": "Hình thu nhỏ nhúng trong ảnh", + "FrmMain.MnuDeleteFromHardDisk._Description": "Bạn có chắc là muốn xóa vĩnh viễn các ảnh này?", + "FrmMain.MnuScaleToFill": "Co dãn hình ảnh lấp đầy", + "FrmCrop.BtnCrop": "Cắt", + "_.AfterEditAppAction._Minimize": "Thu nhỏ cửa sổ", + "FrmMain.MnuInvertColors": "Đảo màu", + "FrmSettings._StartupBoost": "Tăng tốc khởi động", + "FrmMain.MnuViewFirstFrame": "Xem khung hình đầu tiên", + "_.MouseWheelEvent._CtrlAndScroll": "Giữ phím Ctrl và cuộn chuột", + "FrmSettings._HideMainWindowInSlideshow": "Tự động ẩn cửa sổ chính", + "_.Metadata._FrameCount": "Khung hình", + "FrmSettings._EnableCopyMultipleFiles": "Bật tính năng sao chép nhiều tập tin cùng một lúc", + "FrmMain.MnuFrameless._EnableDescription": "Nhấn và giữ phím Shift để di chuyển cửa sổ.", + "_.ImageOrderBy._ExifDateTaken": "EXIF: Ngày chụp", + "FrmAbout._Credits": "Đóng góp", + "FrmSettings._AddNewFileExtension": "Thêm một định dạng", + "FrmMain.MnuQuickSetup": "Mở Cài đặt nhanh ImageGlass", + "FrmMain.MnuSave._Success": "Đã lưu ảnh", + "FrmMain.MnuPanLeft": "Lia ảnh qua trái", + "FrmUpdate._StatusChecking": "Đang kiểm tra bản cập nhật…", + "FrmSettings.Nav._Layout": "Bố cục", + "FrmMain.MnuOpenWith": "Mở với ứng dụng…", + "FrmAbout._Thanks": "Đặc biệt cảm ơn đến:", + "_._Warning": "Cảnh báo", + "FrmSettings.Nav._Keyboard": "Bàn phím", + "FrmSlideshow._PauseSlideshow": "Tạm dừng trình chiếu ảnh.", + "_._Add+": "Thêm…", + "_._Email": "Email", + "FrmMain.MnuPanDown": "Lia ảnh xuống dưới", + "_._Cancel": "Hủy bỏ", + "_._OK": "Đồng ý", + "FrmMain.MnuPanRight": "Lia ảnh qua phải", + "_.Position._Right": "Bên phải", + "_._Icon": "Biểu tượng", + "FrmSettings._ShouldLoadHiddenImages": "Tải ảnh ẩn", + "_._InvalidAction._Transformation": "ImageGlass không hỗ trợ thao tác xoay, lật đối với ảnh này.", + "FrmSettings._MakeDefault": "Đặt làm mặc định", + "FrmMain.MnuCopyImageData._Copying": "Đang sao chép dữ liệu ảnh. Có lẽ sẽ mất thêm một khoảng thời gian để hoàn thành…", + "FrmSettings._UseEmbeddedThumbnailRawFormats": "Chỉ hiển thị hình thu nhỏ được nhúng trong ảnh định dạng RAW", + "_.ImageInterpolation._Linear": "Thuật toán Linear", + "FrmSettings._ImageInfoTags": "Thẻ thông tin ảnh", + "FrmSettings._FileExtensionIcons": "Biểu tượng tập tin", + "FrmMain.MnuEdit._AppNotFound": "Không thể tìm thấy ứng dụng chỉnh sửa ảnh. Bạn có thể liên kết một ứng dụng để chỉnh sửa định dạng này trong Cài đặt > Chỉnh sửa.", + "_.ColorProfileOption._None": "Không", + "FrmSettings._TotalSupportedFormats": "Tổng định dạng hỗ trợ: {0}", + "FrmSettings._Clipboard": "Vùng nhớ đệm", + "_._UserAction._Win32ExeError": "Không thể thực thi lệnh '{0}'. Kiểm tra chắc chắn giá trị tên là chính xác.", + "FrmCropSettings.DefaultSelectionType._SelectX": "Chọn {0}", + "_.AfterEditAppAction._Close": "Đóng", + "FrmAbout._LogoDesigner": "Người thiết kế logo:", + "_.ImageOrderBy._Name": "Tên (mặc định)", + "FrmMain.MnuRemoveDefaultPhotoViewer._Error": "Không thể huỷ ImageGlass làm trình xem ảnh mặc định.", + "FrmExportFrames._FolderPickerTitle": "Chọn thư mục lưu trữ cho các tập tin khung hình", + "FrmAbout._Donate": "Ủng hộ", + "FrmMain.MnuFrameNav": "Điều hướng khung hình", + "FrmMain.MnuSetLockScreen": "Đặt ảnh đang xem làm màn hình khoá", + "_._Delete": "Xoá", + "FrmMain.MnuViewPrevious": "Xem ảnh trước đó", + "_.Position._Top": "Ở trên", + "FrmSettings.Toolbar._CurrentButtons": "Các nút hiện tại:", + "FrmMain.MnuAbout": "Thông tin phần mềm", + "FrmSettings._RemoveDefault": "Huỷ bỏ mặc định", + "_._Description": "Mô tả", + "FrmMain.MnuPasteImage._Error": "Không thể tìm thấy dữ liệu ảnh trong Bộ nhớ tạm", + "FrmMain.MnuSettings": "Cài đặt", + "FrmCropSettings._Title": "Cài đặt Cắt ảnh", + "FrmSettings.Toolbar._ToolbarIconHeight": "Kích thước biểu tượng của thanh công cụ", + "FrmSettings._SlideshowInterval._To": "Đến", + "FrmSettings.Layout._ToolbarPosition": "Vị trí của thanh công cụ", + "FrmUpdate._StatusUpdated": "Bạn đang sử dụng phiên bản mới nhất!", + "FrmMain.MnuExit": "Thoát", + "_._Webview2._Outdated": "Phiên bản WebView2 Runtime không được hỗ trợ. Vui lòng cập nhật lên phiên bản {0} hoặc mới hơn.", + "_._Yes": "Đồng ý", + "FrmMain.MnuRotateLeft": "Xoay trái", + "FrmSettings._EnableStartupBoost": "Bật Tăng tốc khởi động", + "_.ImageOrderBy._ExifRating": "EXIF: Xếp hạng", + "FrmMain.MnuZoomIn": "Phóng to", + "_.Metadata._ColorSpace": "Không gian màu", + "FrmAbout._Version": "Phiên bản:", + "FrmMain.MnuToggleTopMost._Enable": "Đã bật chế độ Cửa sổ trên cùng", + "FrmSettings.Toolbar._AvailableButtons": "Các nút có sẵn:", + "FrmMain.MnuSave._Saving": "Đang lưu ảnh…", + "FrmQuickSetup._StandardUser": "Người dùng chuẩn", + "FrmMain.MnuSetLockScreen._Error": "Không thể đặt ảnh đang xem làm ảnh màn hình khoá", + "FrmSettings.Nav._Image": "Hình ảnh", + "FrmSettings._Theme._InstallTheme": "Cài gói chủ đề", + "FrmSettings._EnableMultiInstances": "Cho phép nhiều cửa sổ chương trình mở cùng lúc", + "FrmMain.MnuCropTool": "Cắt ảnh", + "_._IgCommandExe._DefaultError._Heading": "Tham số không hợp lệ", + "_._Refresh": "Cập nhật lại", + "FrmMain.MnuLosslessCompression._Description": "Công cụ này sử dụng thư viện Magick.NET để nén và tối ưu hoá kích thước tập tin ảnh mà không làm giảm đi chất lượng. Ảnh được lưu chỉ khi tập tin ảnh mới nhỏ hơn ảnh ban đầu.", + "_._MoveDown": "Chuyển xuống", + "FrmSettings._GetExtensionIconPacks": "Tải thêm các gói biểu tượng tập tin…", + "FrmSettings._InAppMessageDuration": "Thời gian hiển thị thông báo trong ứng dụng (mili giây)", + "FrmMain.MnuFrameless": "Không viền", + "_._Reset": "Thiết lập lại", + "FrmSettings._ConfigDir": "Thư mục cài đặt", + "FrmQuickSetup._SettingsWillBeApplied": "Các cài đặt sẽ được áp dụng:", + "FrmSettings._UnmanagedSettingReminder": "Cài đặt này không được quản lý bởi ImageGlass. Đừng quên tắt nó trước khi bạn xoá hoặc di chuyển ứng dụng vì ImageGlass không tự động thực hiện việc này.", + "FrmMain.MnuClipboard": "Bộ nhớ tạm", + "FrmMain.MnuCustomZoom": "Tuỳ chỉnh phóng to / thu nhỏ", + "FrmSettings._DisplayLanguage": "Ngôn ngữ hiển thị", + "FrmMain.MnuPrint._Error": "Không thể in ảnh", + "FrmSettings._ShouldPreserveModifiedDate": "Giữ nguyên Ngày sửa đổi của hình ảnh khi lưu", + "FrmSettings._ShowSaveOverrideConfirmation": "Hiển thị hộp thoại xác nhận khi lưu đè tập tin", + "FrmColorPickerSettings.ChkShowHexA": "Sử dụng định dạng HEX với giá trị alpha", + "FrmMain.MnuFullScreen": "Toàn màn hình", + "FrmSettings._StartupDir": "Thư mục khởi động", + "FrmSettings._ShowCheckerboardOnlyImageRegion": "Hiển thị nền caro chỉ trong vùng ảnh", + "FrmMain.MnuClearClipboard._Success": "Đã xoá Bộ nhớ tạm.", + "FrmQuickSetup._Text": "Cài đặt nhanh ImageGlass", + "FrmMain.MnuLosslessCompression._Done": "Quá trình nén ảnh chất lượng cao đã hoàn tất.\r\nKích thước tập tin mới {0}, đã tiết kiệm được {1}.", + "FrmMain.MnuLosslessCompression": "Nén ảnh chất lượng cao với Magick.NET", + "FrmResize.RadResizeByPercentage": "Tỉ lệ phần trăm", + "FrmSettings._StartupBoost._Disabled": "Tăng tốc khởi động đã được tắt", + "FrmMain.MnuToggleCheckerboard": "Nền ca rô", + "FrmSettings._MinEmbeddedThumbnailSize._Height": "Cao", + "FrmSettings.Nav._General": "Cài đặt chung", + "FrmSettings._ImageLoading": "Tải hình ảnh", + "FrmSettings._ShowSlideshowCountdown": "Hiển thị đồng hồ đếm ngược trong chế độ Trình chiếu ảnh", + "FrmMain.MnuSave": "Lưu", + "FrmMain.MnuMoveToRecycleBin": "Di chuyển vào thùng rác", + "FrmMain.MnuRefresh": "Cập nhật lại", + "FrmToolNotFound.LblHeading": "Không tìm thấy '{0}'!", + "FrmMain.MnuReportIssue": "Báo cáo một vấn đề…", + "FrmMain.MnuCopyImageData": "Sao chép dữ liệu hình ảnh", + "FrmMain.MnuCheckForUpdate._NewVersion": "Một phiên bản mới đã có sẵn!", + "_._Empty": "(trống)", + "FrmSettings._Zooming": "Phóng to / thu nhỏ", + "FrmMain.MnuCutFile": "Cắt tập tin", + "FrmHotkeyPicker.LblHotkey": "Nhấn phím tắt", + "FrmSettings.Layout._Gallery": "Thư viện ảnh", + "FrmMain.MnuNewWindow": "Mở cửa sổ mới", + "FrmMain.MnuMoveToRecycleBin._Description": "Bạn có muốn di chuyển tấm ảnh này vào thùng rác?", + "FrmSettings._DefaultPhotoViewer": "Trình xem ảnh mặc định", + "_.Metadata._ExifDateTimeOriginal": "EXIF: DateTimeOriginal", + "FrmMain.MnuRotateRight": "Xoay phải", + "FrmSettings._MinEmbeddedThumbnailSize": "Kích thước tổi thiểu để tải hình thu nhỏ", + "FrmMain.MnuSetDefaultPhotoViewer": "Đặt làm trình xem ảnh mặc định", + "FrmMain.MnuImageProperties": "Thuộc tính hình ảnh", + "FrmSettings._EnableNavigationButtons": "Hiển thị nút mũi tên điều hướng", + "_._Edit": "Chỉnh sửa", + "FrmSettings._ImageBooster": "Image Booster", + "FrmSettings.Tools._IntegratedWith": "Tích hợp với {0}", + "_._Next": "Tiếp theo", + "FrmExportFrames._OpenOutputFolder": "Mở thư mục xuất ra", + "FrmMain.MnuOpenLocation": "Tìm vị trí hình ảnh", + "FrmMain.MnuLockZoom": "Khoá tỉ lệ phóng to / thu nhỏ", + "FrmSettings._StartupBoost._Description": "Tải trước và chạy ImageGlass ở chế độ nền trong vài giây trong quá trình khởi động Windows để tăng tốc lần khởi chạy đầu tiên.", + "FrmSettings._WindowBackdrop": "Chế độ phông nền cửa sổ", + "FrmSettings._EnableRealTimeFileUpdate": "Theo dõi các thay đổi trong thư mục và cập nhật theo thời gian thực", + "_._NotSupported": "Định dạng không được hỗ trợ", + "FrmSettings._Theme._GetMoreThemes": "Tải thêm gói chủ đề…", + "FrmMain.MnuNewWindow._Error": "Không thể mở cửa sổ mới vì cài đặt hiện tại chỉ cho phép 1 cửa sổ", + "FrmMain.MnuZoomOut": "Thu nhỏ", + "FrmSettings.Toolbar._EditButton": "Chỉnh sửa nút trên thanh công cụ", + "FrmMain.MnuCustomZoom._Description": "Nhập một giá trị mới", + "FrmResize.RadResizeByPixels": "Pixels", + "FrmMain.MnuEdit": "Chỉnh sửa ảnh {0}…", + "FrmSettings.Layout._GalleryPosition": "Vị trí của Thư viện ảnh", + "FrmMain.MnuWindowFit": "Cửa sổ vừa khít", + "FrmMain._OpenFileDialog": "Tất cả các tập tin hỗ trợ", + "FrmSettings._UseRandomIntervalForSlideshow": "Sử dụng thời gian trình chiếu ngẫu nhiên", + "_.Position._Left": "Bên trái", + "FrmSettings._ShouldOpenLastSeenImage": "Mở ảnh của lần xem gần nhất", + "_.Position._Bottom": "Ở dưới", + "FrmResize.ChkKeepRatio": "Giữ tỷ lệ", + "FrmMain.MnuGoTo": "Đi đến…", + "FrmSlideshow.MnuPauseResumeSlideshow": "Tạm dừng / khôi phục trình chiếu ảnh", + "FrmSettings.Tools._Integrated": "Tích hợp", + "FrmSettings._Contributors": "Người dịch", + "_.MouseWheelAction._Zoom": "Phóng to / thu nhỏ", + "_._CommandPreview": "Xem trước", + "FrmSettings._DarkTheme": "Tối", + "_._Hotkeys": "Phím tắt", + "_.Metadata._ExifDateTime": "EXIF: DateTime", + "FrmSettings.Toolbar._Errors._ButtonIdRequired": "'ID' của nút không được bỏ trống.", + "FrmSettings._MinEmbeddedThumbnailSize._Width": "Rộng", + "_._Executable": "File thực thi", + "_.ImageInterpolation._MultiSampleLinear": "Thuật toán Multi-sample linear", + "_._Separator": "Phân cách", + "FrmQuickSetup._ProfessionalUser": "Người dùng chuyên nghiệp", + "FrmMain.MnuFlipVertical": "Lật theo chiều dọc", + "FrmSlideshow._ResumeSlideshow": "Khôi phục trình chiếu ảnh.", + "FrmCropSettings.DefaultSelectionType._CustomArea": "Vùng tuỳ chỉnh…", + "FrmMain.MnuActualSize": "Kích thước thực tế", + "FrmCrop.BtnSaveAs": "Lưu thành…", + "FrmSettings._InstallNewLanguagePack": "Cài đặt gói ngôn ngữ mới…", + "FrmSlideshow.MnuZoomModes": "Chế độ thu phóng", + "FrmMain.MnuTools": "Công cụ", + "_.ImageInterpolation._Cubic": "Thuật toán Cubic", + "FrmUpdate._LatestVersion": "Phiên bản mới nhất: {0}", + "FrmMain.MnuViewNext": "Xem hình ảnh kế tiếp", + "_.MouseWheelEvent._AltAndScroll": "Giữ phím Alt và cuộn chuột", + "FrmToolNotFound._Title": "Không tìm thấy công cụ", + "FrmCrop.BtnCrop._Tooltip": "Chỉ cắt ảnh", + "FrmSettings.EditAppDialog._AddApp": "Thêm một ứng dụng chỉnh sửa", + "FrmMain.MnuPanning": "Lia ảnh", + "_._MoveUp": "Chuyển lên trên", + "FrmCropSettings.DefaultSelectionType._SelectAll": "Chọn tất cả", + "_._Name": "Tên", + "FrmColorPickerSettings.ChkShowHslA": "Sử dụng định dạng HSL với giá trị alpha", + "FrmMain.MnuToggleImageAnimation": "Bắt đầu / dừng chơi ảnh động", + "FrmSettings._DisableStartupBoost": "Tắt Tăng tốc khởi động", + "FrmMain.MnuCopyFile._Success": "Đã sao chép {0} tập tin.", + "FrmMain.MnuSave._ConfirmDescription": "Xin lưu ý: ImageGlass không phải là trình chỉnh sửa ảnh chuyên nghiệp. Trong quá trình lưu, chất lượng ảnh, metadata, layer,… có thể bị giảm.", + "FrmToolNotFound.BtnSelectExecutable": "Chọn…", + "FrmUpdate._StatusOutdated": "Có một bản cập nhật mới!", + "_.ImageOrderBy._Random": "Ngẫu nhiên", + "FrmResize.LblCurrentSize": "Kích thước hiện tại:", + "_._Apply": "Áp dụng", + "FrmAbout._Slogan": "Phần mềm xem ảnh gọn nhẹ, tiện dụng", + "FrmMain.MnuPanToTop": "Lia ảnh tới góc trên cùng", + "FrmSettings.Toolbar._AddNewButton": "Thêm một nút tuỳ chỉnh", + "FrmCrop.LblSize": "Kích thước:", + "FrmSettings._ImageInterpolation._ScaleDown": "Khi tỷ lệ phóng to ảnh < 100%", + "_._CreatingFileError": "Không thể tạo một tập tin ảnh tạm thời", + "FrmMain.MnuGoTo._Description": "Nhập chỉ mục ảnh để xem, sau đó nhấn ENTER", + "FrmSettings.Toolbar._EnableCenterToolbar": "Tự động căn giữa các nút của thành công cụ", + "FrmMain.MnuResizeTool": "Thay đổi kích thước ảnh", + "FrmSettings.Layout._Toolbar": "Thanh công cụ", + "FrmMain.MnuHelp": "Trợ giúp", + "_.ImageOrderBy._FileSize": "Kích thước tập tin", + "FrmSettings._Theme._OpenThemeFolder": "Mở thư mục chủ đề", + "FrmMain.MnuNavigation": "Điều hướng", + "_._Save": "Lưu", + "FrmQuickSetup._SettingProfileDescription": "Truy cập Cài đặt của ứng dụng để thay đổi những thiết lập này.", + "_._UserAction._MenuNotFound": "Không thể tìm thấy menu '{0}' để thực thi hành động", + "FrmMain.MnuPanToLeftSide": "Lia ảnh tới góc trái", + "FrmUpdate._CurrentVersion": "Phiên bản hiện tại: {0}", + "FrmCrop.BtnSettings._Tooltip": "Mở cài đặt Công cụ Cắt ảnh", + "_.ColorProfileOption._Custom": "Tuỳ chọn…", + "FrmSettings._UseEmbeddedThumbnailOtherFormats": "Chỉ hiển thị hình thu nhỏ được nhúng trong các định dạng khác", + "FrmMain.MnuGoToFirst": "Đi đến hình ảnh đầu tiên", + "FrmSettings._ExportLanguagePack": "Xuất gói ngôn ngữ…", + "FrmSettings.Nav._Mouse": "Chuột", + "_.ImageOrderBy._DateCreated": "Ngày tạo", + "FrmSettings._EnableFullscreenSlideshow": "Chạy trình chiếu trong chế độ Toàn màn hình", + "FrmAbout._Homepage": "Trang chủ:", + "FrmSettings._GalleryCacheSizeInMb": "Giới hạn kích thước tối đa để cache Thư viện ảnh (megabyte)", + "FrmMain.MnuCopyImageData._Success": "Đã sao chép dữ liệu ảnh.", + "FrmSettings._EnableLoopBackNavigation": "Quay trở lại ảnh đầu tiên khi xem hết ảnh trong danh sách", + "_.MouseWheelEvent._Scroll": "Cuộn chuột ", + "FrmCrop.BtnSave._Tooltip": "Lưu ảnh", + "FrmMain.MnuSlideshow": "Trình chiếu ảnh", + "FrmMain.MnuShare": "Chia sẻ…", + "FrmSettings._SlideshowNotification": "Thông báo của chế độ trình chiếu", + "FrmMain.MnuViewChannels": "Xem kênh màu", + "FrmSettings._Refresh": "Cập nhật lại", + "_._UserAction._MethodNotFound": "Không thể tìm thấy phương thức '{0}' để thực thi hành động", + "FrmMain.MnuCopyFile": "Sao chép tập tin", + "_._CreatingFile": "Đang tạo một tập tin ảnh tạm thời…", + "FrmMain.MnuToggleTopMost": "Giữ cửa sổ luôn ở trên cùng", + "FrmMain.MnuLosslessCompression._Confirm": "Bạn có chắc muốn tiếp tục?", + "FrmMain.MnuImage": "Hình ảnh", + "FrmSettings._StartupBoost._Enabled": "Đã bật Tăng tốc khởi động", + "FrmQuickSetup._SetDefaultViewer": "Bạn có muốn đặt ImageGlass làm trình xem ảnh mặc định?", + "FrmMain.MnuScaleToWidth": "Co dãn hình ảnh theo chiều rộng", + "_._FileExtension": "Loại tập tin", + "FrmUpdate._PublishedDate": "Ngày phát hành: {0}", + "_._DoNotShowThisMessageAgain": "Không hiện lại thông báo này nữa", + "_.ImageInterpolation._NearestNeighbor": "Thuật toán Nearest neighbor", + "FrmCrop.LblLocation": "Vị trí:", + "_._Download": "Tải về", + "_.Metadata._ColorProfile": "Cấu hình màu", + "FrmSettings._CenterWindowFit": "Tự động căn giữa cửa sổ trong chế độ Cửa sổ vừa khit", + "FrmSettings._ImageLoadingOrder": "Thứ tự tải hình ảnh", + "FrmSettings._GalleryColumns": "Số lượng ảnh trên một hàng trong bố cục Thư viện ảnh dọc", + "_._Quit": "Thoát", + "_._Add": "Thêm", + "FrmMain.MnuChangeBackgroundColor": "Thay đổi màu nền…", + "FrmMain.MnuToggleToolbar": "Thanh công cụ", + "FrmAbout._Contact": "Liên hệ", + "FrmSettings.Toolbar._AddCustomButton": "Thêm một nút tuỳ chỉnh…", + "FrmCrop.BtnQuickSelect._Tooltip": "Chọn nhanh…", + "FrmMain.MnuCutFile._Success": "Đã cắt {0} tập tin.", + "FrmSettings._ZoomSpeed": "Tốc độ phóng to / thu nhỏ", + "FrmMain.MnuToggleTopMost._Disable": "Đã tắt chế độ Cửa sổ trên cùng", + "FrmSettings._ShouldUseExplorerSortOrder": "Sử dụng thứ tự sắp xếp của Explorer nếu khả thi", + "_.ImageInterpolation._Antisotropic": "Thuật toán Antisotropic", + "FrmMain._ReachedFirstImage": "Đã ở đầu danh sách", + "_._UnhandledException": "Lỗi ngoài ý muốn", + "FrmResize.LblNewSize": "Kích thước mới:", + "FrmMain._ClipboardImage": "Ảnh trong Bộ nhớ tạm", + "FrmMain.MnuExportFrames": "Xuất khung hình…", + "FrmMain.MnuFile": "Tập tin", + "_._Close": "Đóng", + "FrmMain.MnuMain": "Menu chính", + "_._ResetToDefault": "Đặt lại về mặc định", + "FrmSettings.Nav._Gallery": "Thư viện ảnh", + "FrmMain.MnuSetDefaultPhotoViewer._Success": "Bạn đã đặt ImageGlass làm trình xem ảnh mặc định thành công.", + "FrmSettings._HideGalleryInFullscreen": "Ẩn Thư viện ảnh trong chế độ Toàn màn hình", + "FrmSettings._AvailableImageInfoTags": "Thẻ có sẵn:", + "FrmExportFrames._Exporting": "Đang xuất {0}/{1} khung hình \n{2}…", + "_._Argument": "Tham số", + "FrmSettings._ImageEditQuality": "Chất lượng hình ảnh", + "_._ID": "ID", + "FrmSettings._UserConfigFile": "Tập tin lưu cài đặt người dùng (igconfig.json)", + "FrmMain.MnuLoadingOrders": "Thứ tự tải hình ảnh", + "FrmSettings._OpenSaveAsDialogInTheCurrentImageDir": "Đặt thư mục ảnh hiện tại làm đường dẫn mặc định khi mở hộp thoại Lưu ảnh", + "_.MouseWheelEvent._ShiftAndScroll": "Giữ phím Shift và cuộn chuột", + "FrmSettings._UseSmoothZooming": "Sử dụng chế độ phóng to / thu nhỏ mượt mà", + "FrmSettings._Theme": "Chủ đề", + "FrmSettings._ImageBoosterCacheMaxDimension": "Giới hạn kích thước ảnh tối đa để nạp trước ảnh vào bộ nhớ (pixel)", + "FrmMain.MnuScaleToHeight": "Co dãn hình ảnh theo chiều cao", + "_.Metadata._FileLastWriteTime": "Ngày chỉnh sửa", + "FrmSettings._Author": "Tác giả", + "FrmSettings._Others": "Khác", + "_.MouseWheelAction._PanVertically": "Lia ảnh lên / xuống", + "FrmSettings._MouseWheelAction": "Thao tác lăn chuột", + "FrmSettings.Nav._Tools": "Công cụ", + "FrmMain.MnuSetDesktopBackground._Error": "Không thể đặt ảnh đang xem thành hình nền máy tình", + "FrmSettings.Toolbar._Errors._ButtonExecutableRequired": "Mục 'Executable' không được bỏ trống.", + "_.ImageOrderBy._DateAccessed": "Ngày truy cập", + "FrmSettings._ThumbnailSize": "Kích thước hình thu nhỏ (pixel)", + "FrmSettings._FileFormats": "Định dạng tập tin", + "FrmMain.MnuReloadImageList": "Tải lại danh sách ảnh", + "FrmSettings._UseWebview2ForSvg": "Sử dụng thư viện Webview2 để xem định dạng SVG", + "FrmCrop.BtnCopy": "Sao chép", + "FrmSettings._CurrentMonitorProfile._Description": "ImageGlass không tự động cập nhật cấu hình màu khi di chuyển cửa sổ giữa các màn hình", + "FrmMain.PicMain._ErrorText": "Không thể mở ảnh này", + "FrmSettings.Tools._AddNewTool": "Thêm một công cụ", + "FrmMain.MnuRename": "Đổi tên…", + "FrmMain.MnuViewLastFrame": "Xem khung hình cuối cùng", + "_._Webview2._NotFound": "Vui lòng cài đặt phiên bản mới nhất của WebView2 Runtime.", + "FrmMain.MnuGetMoreTools": "Tải thêm công cụ…", + "FrmSettings.Nav._Appearance": "Giao diện", + "FrmSettings._SlideshowInterval": "Thời gian trình chiếu:", + "_.ImageInterpolation._HighQualityBicubic": "Thuật toán High quality bicubic", + "FrmColorPickerSettings.ChkShowHsvA": "Sử dụng định dạng HSV với giá trị alpha", + "FrmSettings.Tools._EditTool": "Chỉnh sửa công cụ", + "_._Error": "Lỗi", + "FrmSettings._ImageBoosterCacheMaxFileSizeInMb": "Giới hạn kích thước tập tin tối đa để nạp trước vào bộ nhớ (megabyte)", + "_._UnhandledException._Description": "Lỗi ngoài ý muốn đã xảy ra. Nếu bạn nhấn Tiếp tục, ứng dụng sẽ bỏ qua lỗi này và cố gắng tiếp tục chạy. Nếu bạn nhấn Thoát, ứng dụng sẽ thoát ngay lập tức.", + "_.Metadata._FileSize": "Kích thước tập tin", + "FrmSettings.Toolbar._ButtonJson": "Cài đặt nút (định dạng JSON)", + "FrmQuickSetup._SetDefaultViewer._Description": "Bạn có thể thiết lập lại trong Cài đặt của ứng dụng, thẻ Liên kết phần mở rộng.", + "FrmSettings.Nav._Edit": "Chỉnh sửa", + "FrmMain.MnuToggleGallery": "Thư viện ảnh", + "_._IgCommandExe._DefaultError._Description": "Hãy chắc chắn bạn đã truyền đúng tham số!\r\nTập tin thực thi này chưa các hàm dòng lệnh cho ứng dụng ImageGlass.\r\n\r\nĐể khám phá tất cả các lệnh, vui lòng truy cập:\n{0}", + "FrmMain.MnuLosslessCompression._Compressing": "Đang thực hiện tác vụ nén ảnh chất lượng cao…", + "FrmSettings._ShouldGroupImagesByDirectory": "Nhóm hình ảnh theo thư mục", + "FrmMain.MnuPanToRightSide": "Lia ảnh tới góc phải", + "_.Metadata._ExifRatingPercent": "Xếp hạng", + "FrmSettings._PanSpeed": "Tốc độ lia ảnh", + "_._CheckForUpdate": "Kiểm tra phiên bản mới…", + "FrmSettings.Layout._ToolbarContext": "Thanh công cụ ngữ cảnh", + "_.ImageInfo._FrameCount": "{0} khung hình", + "FrmMain.MnuLayout": "Bố cục", + "_._Website": "Trang web", + "FrmMain.MnuPasteImage": "Dán ảnh", + "FrmSettings._ShowGalleryScrollbars": "Hiển thị thanh cuộn cho Thư viện ảnh" + } +} \ No newline at end of file diff --git a/Setup/Assets/Languages/Chinese Traditional.iglang b/Setup/Assets/Languages/Chinese Traditional.iglang deleted file mode 100644 index 3c3155750..000000000 --- a/Setup/Assets/Languages/Chinese Traditional.iglang +++ /dev/null @@ -1,318 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Setup/Assets/Languages/Czech.iglang b/Setup/Assets/Languages/Czech.iglang deleted file mode 100644 index cb73790de..000000000 --- a/Setup/Assets/Languages/Czech.iglang +++ /dev/null @@ -1,318 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Setup/Assets/Languages/Greek.iglang b/Setup/Assets/Languages/Greek.iglang deleted file mode 100644 index bf434bd09..000000000 --- a/Setup/Assets/Languages/Greek.iglang +++ /dev/null @@ -1,318 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Setup/Assets/Languages/Hungarian.iglang b/Setup/Assets/Languages/Hungarian.iglang deleted file mode 100644 index 131ad2f30..000000000 --- a/Setup/Assets/Languages/Hungarian.iglang +++ /dev/null @@ -1,318 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Setup/Assets/Languages/Polish.iglang b/Setup/Assets/Languages/Polish.iglang deleted file mode 100644 index c5c295081..000000000 --- a/Setup/Assets/Languages/Polish.iglang +++ /dev/null @@ -1,318 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Setup/Assets/Languages/Portuguese, Brazilian.iglang b/Setup/Assets/Languages/Portuguese, Brazilian.iglang deleted file mode 100644 index 37d151972..000000000 --- a/Setup/Assets/Languages/Portuguese, Brazilian.iglang +++ /dev/null @@ -1,318 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Setup/Assets/Languages/Portuguese.iglang b/Setup/Assets/Languages/Portuguese.iglang deleted file mode 100644 index 05125c1e1..000000000 --- a/Setup/Assets/Languages/Portuguese.iglang +++ /dev/null @@ -1,318 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Setup/Assets/Languages/Russian.iglang b/Setup/Assets/Languages/Russian.iglang deleted file mode 100644 index 814c4e348..000000000 --- a/Setup/Assets/Languages/Russian.iglang +++ /dev/null @@ -1,318 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Setup/Assets/Languages/Slovenian.iglang b/Setup/Assets/Languages/Slovenian.iglang deleted file mode 100644 index 22cb4b5b6..000000000 --- a/Setup/Assets/Languages/Slovenian.iglang +++ /dev/null @@ -1,318 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Setup/Assets/Languages/Spanish.iglang b/Setup/Assets/Languages/Spanish.iglang deleted file mode 100644 index fae28c67a..000000000 --- a/Setup/Assets/Languages/Spanish.iglang +++ /dev/null @@ -1,318 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Setup/Assets/Languages/Swedish.iglang b/Setup/Assets/Languages/Swedish.iglang deleted file mode 100644 index ec070e5ec..000000000 --- a/Setup/Assets/Languages/Swedish.iglang +++ /dev/null @@ -1,318 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Setup/Assets/Languages/Thai.iglang b/Setup/Assets/Languages/Thai.iglang deleted file mode 100644 index d8259ee70..000000000 --- a/Setup/Assets/Languages/Thai.iglang +++ /dev/null @@ -1,318 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Setup/Assets/Languages/Ukrainian.iglang b/Setup/Assets/Languages/Ukrainian.iglang deleted file mode 100644 index a9ce7d859..000000000 --- a/Setup/Assets/Languages/Ukrainian.iglang +++ /dev/null @@ -1,318 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Setup/Assets/Languages/Vietnamese.iglang b/Setup/Assets/Languages/Vietnamese.iglang deleted file mode 100644 index ef585e52b..000000000 --- a/Setup/Assets/Languages/Vietnamese.iglang +++ /dev/null @@ -1,318 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Setup/Assets/ReadMe.rtf b/Setup/Assets/ReadMe.rtf new file mode 100644 index 000000000..2a640de58 Binary files /dev/null and b/Setup/Assets/ReadMe.rtf differ diff --git a/Setup/Assets/Themes/Kobe-Light/ActualSize.svg b/Setup/Assets/Themes/Kobe-Light/ActualSize.svg new file mode 100644 index 000000000..09518477b --- /dev/null +++ b/Setup/Assets/Themes/Kobe-Light/ActualSize.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/Setup/Assets/Themes/Kobe-Light/AutoZoom.svg b/Setup/Assets/Themes/Kobe-Light/AutoZoom.svg new file mode 100644 index 000000000..3904f6d0b --- /dev/null +++ b/Setup/Assets/Themes/Kobe-Light/AutoZoom.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/Setup/Assets/Themes/Kobe-Light/Checkerboard.svg b/Setup/Assets/Themes/Kobe-Light/Checkerboard.svg new file mode 100644 index 000000000..f7940fdda --- /dev/null +++ b/Setup/Assets/Themes/Kobe-Light/Checkerboard.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/Setup/Assets/Themes/Kobe-Light/ColorPicker.svg b/Setup/Assets/Themes/Kobe-Light/ColorPicker.svg new file mode 100644 index 000000000..ceec78a08 --- /dev/null +++ b/Setup/Assets/Themes/Kobe-Light/ColorPicker.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/Setup/Assets/Themes/Kobe-Light/Crop.svg b/Setup/Assets/Themes/Kobe-Light/Crop.svg new file mode 100644 index 000000000..1c57a8857 --- /dev/null +++ b/Setup/Assets/Themes/Kobe-Light/Crop.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/Setup/Assets/Themes/Kobe-Light/Delete.svg b/Setup/Assets/Themes/Kobe-Light/Delete.svg new file mode 100644 index 000000000..10e36b7a9 --- /dev/null +++ b/Setup/Assets/Themes/Kobe-Light/Delete.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/Setup/Assets/Themes/Kobe-Light/Edit.svg b/Setup/Assets/Themes/Kobe-Light/Edit.svg new file mode 100644 index 000000000..cd2462553 --- /dev/null +++ b/Setup/Assets/Themes/Kobe-Light/Edit.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/Setup/Assets/Themes/Kobe-Light/Exit.svg b/Setup/Assets/Themes/Kobe-Light/Exit.svg new file mode 100644 index 000000000..20e4b81f9 --- /dev/null +++ b/Setup/Assets/Themes/Kobe-Light/Exit.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/Setup/Assets/Themes/Kobe-Light/Export.svg b/Setup/Assets/Themes/Kobe-Light/Export.svg new file mode 100644 index 000000000..86501ba34 --- /dev/null +++ b/Setup/Assets/Themes/Kobe-Light/Export.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/Setup/Assets/Themes/Kobe-Light/FlipHorz.svg b/Setup/Assets/Themes/Kobe-Light/FlipHorz.svg new file mode 100644 index 000000000..3ab3e3a4e --- /dev/null +++ b/Setup/Assets/Themes/Kobe-Light/FlipHorz.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/Setup/Assets/Themes/Kobe-Light/FlipVert.svg b/Setup/Assets/Themes/Kobe-Light/FlipVert.svg new file mode 100644 index 000000000..27b7a33a7 --- /dev/null +++ b/Setup/Assets/Themes/Kobe-Light/FlipVert.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/Setup/Assets/Themes/Kobe-Light/FullScreen.svg b/Setup/Assets/Themes/Kobe-Light/FullScreen.svg new file mode 100644 index 000000000..991f5bed9 --- /dev/null +++ b/Setup/Assets/Themes/Kobe-Light/FullScreen.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/Setup/Assets/Themes/Kobe-Light/Gallery.svg b/Setup/Assets/Themes/Kobe-Light/Gallery.svg new file mode 100644 index 000000000..b52a78d69 --- /dev/null +++ b/Setup/Assets/Themes/Kobe-Light/Gallery.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/Setup/Assets/Themes/Kobe-Light/LockZoom.svg b/Setup/Assets/Themes/Kobe-Light/LockZoom.svg new file mode 100644 index 000000000..ae5f66efa --- /dev/null +++ b/Setup/Assets/Themes/Kobe-Light/LockZoom.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/Setup/Assets/Themes/Kobe-Light/Logo.svg b/Setup/Assets/Themes/Kobe-Light/Logo.svg new file mode 100644 index 000000000..a587c3c70 --- /dev/null +++ b/Setup/Assets/Themes/Kobe-Light/Logo.svg @@ -0,0 +1,90 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Setup/Assets/Themes/Kobe-Light/MainMenu.svg b/Setup/Assets/Themes/Kobe-Light/MainMenu.svg new file mode 100644 index 000000000..ba7cc691f --- /dev/null +++ b/Setup/Assets/Themes/Kobe-Light/MainMenu.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/Setup/Assets/Themes/Kobe-Light/OpenFile.svg b/Setup/Assets/Themes/Kobe-Light/OpenFile.svg new file mode 100644 index 000000000..f16c63cc8 --- /dev/null +++ b/Setup/Assets/Themes/Kobe-Light/OpenFile.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/Setup/Assets/Themes/Kobe-Light/Pause.svg b/Setup/Assets/Themes/Kobe-Light/Pause.svg new file mode 100644 index 000000000..89346fa28 --- /dev/null +++ b/Setup/Assets/Themes/Kobe-Light/Pause.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/Setup/Assets/Themes/Kobe-Light/Play.svg b/Setup/Assets/Themes/Kobe-Light/Play.svg new file mode 100644 index 000000000..734dc67b8 --- /dev/null +++ b/Setup/Assets/Themes/Kobe-Light/Play.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/Setup/Assets/Themes/Kobe-Light/Print.svg b/Setup/Assets/Themes/Kobe-Light/Print.svg new file mode 100644 index 000000000..031954cc2 --- /dev/null +++ b/Setup/Assets/Themes/Kobe-Light/Print.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/Setup/Assets/Themes/Kobe-Light/Refresh.svg b/Setup/Assets/Themes/Kobe-Light/Refresh.svg new file mode 100644 index 000000000..d77e533a8 --- /dev/null +++ b/Setup/Assets/Themes/Kobe-Light/Refresh.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/Setup/Assets/Themes/Kobe-Light/RotateLeft.svg b/Setup/Assets/Themes/Kobe-Light/RotateLeft.svg new file mode 100644 index 000000000..552969381 --- /dev/null +++ b/Setup/Assets/Themes/Kobe-Light/RotateLeft.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/Setup/Assets/Themes/Kobe-Light/RotateRight.svg b/Setup/Assets/Themes/Kobe-Light/RotateRight.svg new file mode 100644 index 000000000..04cd220f9 --- /dev/null +++ b/Setup/Assets/Themes/Kobe-Light/RotateRight.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/Setup/Assets/Themes/Kobe-Light/Save.svg b/Setup/Assets/Themes/Kobe-Light/Save.svg new file mode 100644 index 000000000..1a100681c --- /dev/null +++ b/Setup/Assets/Themes/Kobe-Light/Save.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/Setup/Assets/Themes/Kobe-Light/ScaleToFill.svg b/Setup/Assets/Themes/Kobe-Light/ScaleToFill.svg new file mode 100644 index 000000000..365e664c9 --- /dev/null +++ b/Setup/Assets/Themes/Kobe-Light/ScaleToFill.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/Setup/Assets/Themes/Kobe-Light/ScaleToFit.svg b/Setup/Assets/Themes/Kobe-Light/ScaleToFit.svg new file mode 100644 index 000000000..384d8d945 --- /dev/null +++ b/Setup/Assets/Themes/Kobe-Light/ScaleToFit.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/Setup/Assets/Themes/Kobe-Light/ScaleToHeight.svg b/Setup/Assets/Themes/Kobe-Light/ScaleToHeight.svg new file mode 100644 index 000000000..0878c013b --- /dev/null +++ b/Setup/Assets/Themes/Kobe-Light/ScaleToHeight.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/Setup/Assets/Themes/Kobe-Light/ScaleToWidth.svg b/Setup/Assets/Themes/Kobe-Light/ScaleToWidth.svg new file mode 100644 index 000000000..b4f552d99 --- /dev/null +++ b/Setup/Assets/Themes/Kobe-Light/ScaleToWidth.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/Setup/Assets/Themes/Kobe-Light/Slideshow.svg b/Setup/Assets/Themes/Kobe-Light/Slideshow.svg new file mode 100644 index 000000000..0820d7072 --- /dev/null +++ b/Setup/Assets/Themes/Kobe-Light/Slideshow.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/Setup/Assets/Themes/Kobe-Light/ViewFirstImage.svg b/Setup/Assets/Themes/Kobe-Light/ViewFirstImage.svg new file mode 100644 index 000000000..9edd80648 --- /dev/null +++ b/Setup/Assets/Themes/Kobe-Light/ViewFirstImage.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/Setup/Assets/Themes/Kobe-Light/ViewLastImage.svg b/Setup/Assets/Themes/Kobe-Light/ViewLastImage.svg new file mode 100644 index 000000000..edffa20b2 --- /dev/null +++ b/Setup/Assets/Themes/Kobe-Light/ViewLastImage.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/Setup/Assets/Themes/Kobe-Light/ViewNextImage.svg b/Setup/Assets/Themes/Kobe-Light/ViewNextImage.svg new file mode 100644 index 000000000..4af5a2fdd --- /dev/null +++ b/Setup/Assets/Themes/Kobe-Light/ViewNextImage.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/Setup/Assets/Themes/Kobe-Light/ViewPreviousImage.svg b/Setup/Assets/Themes/Kobe-Light/ViewPreviousImage.svg new file mode 100644 index 000000000..37b537744 --- /dev/null +++ b/Setup/Assets/Themes/Kobe-Light/ViewPreviousImage.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/Setup/Assets/Themes/Kobe-Light/WindowFit.svg b/Setup/Assets/Themes/Kobe-Light/WindowFit.svg new file mode 100644 index 000000000..ba60de876 --- /dev/null +++ b/Setup/Assets/Themes/Kobe-Light/WindowFit.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/Setup/Assets/Themes/Kobe-Light/ZoomIn.svg b/Setup/Assets/Themes/Kobe-Light/ZoomIn.svg new file mode 100644 index 000000000..f3ab294a5 --- /dev/null +++ b/Setup/Assets/Themes/Kobe-Light/ZoomIn.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/Setup/Assets/Themes/Kobe-Light/ZoomOut.svg b/Setup/Assets/Themes/Kobe-Light/ZoomOut.svg new file mode 100644 index 000000000..1310f2821 --- /dev/null +++ b/Setup/Assets/Themes/Kobe-Light/ZoomOut.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/Setup/Assets/Themes/Kobe-Light/igtheme.json b/Setup/Assets/Themes/Kobe-Light/igtheme.json new file mode 100644 index 000000000..c63acb547 --- /dev/null +++ b/Setup/Assets/Themes/Kobe-Light/igtheme.json @@ -0,0 +1,83 @@ +{ + "_Metadata": { + "Description": "ImageGlass theme configuration file", + "Version": "9.0" + }, + "Info": { + "Name": "Kobe - Light", + "Author": "Dương Diệu Pháp", + "Email": "phap@imageglass.org", + "Website": "https://imageglass.org", + "Description": "ImageGlass Kobe theme", + "Version": "9.0" + }, + "Settings": { + "IsDarkMode": false, + "IsShowTitlebarLogo": true, + "NavButtonLeft": "ViewPreviousImage.svg", + "NavButtonRight": "ViewNextImage.svg", + "PreviewImage": "preview.webp", + "AppLogo": "Logo.svg" + }, + "Colors": { + "BgColor": "#ffffff00", + "TextColor": "#000", + + "ToolbarBgColor": "#F5F6F700", + "ToolbarTextColor": "#000", + "ToolbarItemHoverColor": "accent:70", + "ToolbarItemActiveColor": "accent:120", + "ToolbarItemSelectedColor": "accent:100", + + "GalleryBgColor": "#F5F6F700", + "GalleryTextColor": "#000", + "GalleryItemHoverColor": "accent:70", + "GalleryItemActiveColor": "accent:120", + "GalleryItemSelectedColor": "accent:100", + + "MenuBgColor": "#F5F6F7", + "MenuBgHoverColor": "accent:120", + "MenuTextColor": "#000", + "MenuTextHoverColor": "#000", + + "NavigationButtonColor": "accent:70" + }, + "ToolbarIcons": { + "ActualSize": "ActualSize.svg", + "AutoZoom": "AutoZoom.svg", + "Checkerboard": "Checkerboard.svg", + "ColorPicker": "ColorPicker.svg", + "Crop": "Crop.svg", + "Delete": "Delete.svg", + "Edit": "Edit.svg", + "FlipHorz": "FlipHorz.svg", + "FlipVert": "FlipVert.svg", + "FullScreen": "FullScreen.svg", + "GoToImage": "GoToImage.svg", + "LockZoom": "LockZoom.svg", + "MainMenu": "MainMenu.svg", + "OpenFile": "OpenFile.svg", + "Print": "Print.svg", + "Refresh": "Refresh.svg", + "RotateLeft": "RotateLeft.svg", + "RotateRight": "RotateRight.svg", + "Save": "Save.svg", + "ScaleToFill": "ScaleToFill.svg", + "ScaleToFit": "ScaleToFit.svg", + "ScaleToHeight": "ScaleToHeight.svg", + "ScaleToWidth": "ScaleToWidth.svg", + "Slideshow": "Slideshow.svg", + "Gallery": "Gallery.svg", + "ViewFirstImage": "ViewFirstImage.svg", + "ViewLastImage": "ViewLastImage.svg", + "ViewNextImage": "ViewNextImage.svg", + "ViewPreviousImage": "ViewPreviousImage.svg", + "WindowFit": "WindowFit.svg", + "ZoomIn": "ZoomIn.svg", + "ZoomOut": "ZoomOut.svg", + "Play": "Play.svg", + "Pause": "Pause.svg", + "Export": "Export.svg", + "Exit": "Exit.svg" + } +} \ No newline at end of file diff --git a/Setup/Assets/Themes/Kobe-Light/preview.webp b/Setup/Assets/Themes/Kobe-Light/preview.webp new file mode 100644 index 000000000..2bc106022 Binary files /dev/null and b/Setup/Assets/Themes/Kobe-Light/preview.webp differ diff --git a/Setup/Assets/Themes/Kobe/ActualSize.svg b/Setup/Assets/Themes/Kobe/ActualSize.svg new file mode 100644 index 000000000..66f36cdfd --- /dev/null +++ b/Setup/Assets/Themes/Kobe/ActualSize.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/Setup/Assets/Themes/Kobe/AutoZoom.svg b/Setup/Assets/Themes/Kobe/AutoZoom.svg new file mode 100644 index 000000000..62e341e91 --- /dev/null +++ b/Setup/Assets/Themes/Kobe/AutoZoom.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/Setup/Assets/Themes/Kobe/Checkerboard.svg b/Setup/Assets/Themes/Kobe/Checkerboard.svg new file mode 100644 index 000000000..40e1c72a1 --- /dev/null +++ b/Setup/Assets/Themes/Kobe/Checkerboard.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/Setup/Assets/Themes/Kobe/ColorPicker.svg b/Setup/Assets/Themes/Kobe/ColorPicker.svg new file mode 100644 index 000000000..54f8eebee --- /dev/null +++ b/Setup/Assets/Themes/Kobe/ColorPicker.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/Setup/Assets/Themes/Kobe/Crop.svg b/Setup/Assets/Themes/Kobe/Crop.svg new file mode 100644 index 000000000..3311646f9 --- /dev/null +++ b/Setup/Assets/Themes/Kobe/Crop.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/Setup/Assets/Themes/Kobe/Delete.svg b/Setup/Assets/Themes/Kobe/Delete.svg new file mode 100644 index 000000000..cfd1ca6cc --- /dev/null +++ b/Setup/Assets/Themes/Kobe/Delete.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/Setup/Assets/Themes/Kobe/Edit.svg b/Setup/Assets/Themes/Kobe/Edit.svg new file mode 100644 index 000000000..e7747086f --- /dev/null +++ b/Setup/Assets/Themes/Kobe/Edit.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/Setup/Assets/Themes/Kobe/Exit.svg b/Setup/Assets/Themes/Kobe/Exit.svg new file mode 100644 index 000000000..22a8498d1 --- /dev/null +++ b/Setup/Assets/Themes/Kobe/Exit.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/Setup/Assets/Themes/Kobe/Export.svg b/Setup/Assets/Themes/Kobe/Export.svg new file mode 100644 index 000000000..02d9d9914 --- /dev/null +++ b/Setup/Assets/Themes/Kobe/Export.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/Setup/Assets/Themes/Kobe/FlipHorz.svg b/Setup/Assets/Themes/Kobe/FlipHorz.svg new file mode 100644 index 000000000..08108a94f --- /dev/null +++ b/Setup/Assets/Themes/Kobe/FlipHorz.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/Setup/Assets/Themes/Kobe/FlipVert.svg b/Setup/Assets/Themes/Kobe/FlipVert.svg new file mode 100644 index 000000000..0d744d1c0 --- /dev/null +++ b/Setup/Assets/Themes/Kobe/FlipVert.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/Setup/Assets/Themes/Kobe/FullScreen.svg b/Setup/Assets/Themes/Kobe/FullScreen.svg new file mode 100644 index 000000000..494493b5d --- /dev/null +++ b/Setup/Assets/Themes/Kobe/FullScreen.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/Setup/Assets/Themes/Kobe/Gallery.svg b/Setup/Assets/Themes/Kobe/Gallery.svg new file mode 100644 index 000000000..bc89b9b5e --- /dev/null +++ b/Setup/Assets/Themes/Kobe/Gallery.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/Setup/Assets/Themes/Kobe/LockZoom.svg b/Setup/Assets/Themes/Kobe/LockZoom.svg new file mode 100644 index 000000000..876333437 --- /dev/null +++ b/Setup/Assets/Themes/Kobe/LockZoom.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/Setup/Assets/Themes/Kobe/MainMenu.svg b/Setup/Assets/Themes/Kobe/MainMenu.svg new file mode 100644 index 000000000..fefa202bc --- /dev/null +++ b/Setup/Assets/Themes/Kobe/MainMenu.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/Setup/Assets/Themes/Kobe/OpenFile.svg b/Setup/Assets/Themes/Kobe/OpenFile.svg new file mode 100644 index 000000000..e0bc354f7 --- /dev/null +++ b/Setup/Assets/Themes/Kobe/OpenFile.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/Setup/Assets/Themes/Kobe/Pause.svg b/Setup/Assets/Themes/Kobe/Pause.svg new file mode 100644 index 000000000..b60c3ff2d --- /dev/null +++ b/Setup/Assets/Themes/Kobe/Pause.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/Setup/Assets/Themes/Kobe/Play.svg b/Setup/Assets/Themes/Kobe/Play.svg new file mode 100644 index 000000000..d94c78de5 --- /dev/null +++ b/Setup/Assets/Themes/Kobe/Play.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/Setup/Assets/Themes/Kobe/Print.svg b/Setup/Assets/Themes/Kobe/Print.svg new file mode 100644 index 000000000..30bc57cf6 --- /dev/null +++ b/Setup/Assets/Themes/Kobe/Print.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/Setup/Assets/Themes/Kobe/Refresh.svg b/Setup/Assets/Themes/Kobe/Refresh.svg new file mode 100644 index 000000000..abf79cfcb --- /dev/null +++ b/Setup/Assets/Themes/Kobe/Refresh.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/Setup/Assets/Themes/Kobe/RotateLeft.svg b/Setup/Assets/Themes/Kobe/RotateLeft.svg new file mode 100644 index 000000000..b32bcb6e0 --- /dev/null +++ b/Setup/Assets/Themes/Kobe/RotateLeft.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/Setup/Assets/Themes/Kobe/RotateRight.svg b/Setup/Assets/Themes/Kobe/RotateRight.svg new file mode 100644 index 000000000..afecfe9bf --- /dev/null +++ b/Setup/Assets/Themes/Kobe/RotateRight.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/Setup/Assets/Themes/Kobe/Save.svg b/Setup/Assets/Themes/Kobe/Save.svg new file mode 100644 index 000000000..55b389c47 --- /dev/null +++ b/Setup/Assets/Themes/Kobe/Save.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/Setup/Assets/Themes/Kobe/ScaleToFill.svg b/Setup/Assets/Themes/Kobe/ScaleToFill.svg new file mode 100644 index 000000000..91b8f2cdb --- /dev/null +++ b/Setup/Assets/Themes/Kobe/ScaleToFill.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/Setup/Assets/Themes/Kobe/ScaleToFit.svg b/Setup/Assets/Themes/Kobe/ScaleToFit.svg new file mode 100644 index 000000000..bbbe8487c --- /dev/null +++ b/Setup/Assets/Themes/Kobe/ScaleToFit.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/Setup/Assets/Themes/Kobe/ScaleToHeight.svg b/Setup/Assets/Themes/Kobe/ScaleToHeight.svg new file mode 100644 index 000000000..38a508836 --- /dev/null +++ b/Setup/Assets/Themes/Kobe/ScaleToHeight.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/Setup/Assets/Themes/Kobe/ScaleToWidth.svg b/Setup/Assets/Themes/Kobe/ScaleToWidth.svg new file mode 100644 index 000000000..55b3aaf86 --- /dev/null +++ b/Setup/Assets/Themes/Kobe/ScaleToWidth.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/Setup/Assets/Themes/Kobe/Slideshow.svg b/Setup/Assets/Themes/Kobe/Slideshow.svg new file mode 100644 index 000000000..5c91b9277 --- /dev/null +++ b/Setup/Assets/Themes/Kobe/Slideshow.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/Setup/Assets/Themes/Kobe/ViewFirstImage.svg b/Setup/Assets/Themes/Kobe/ViewFirstImage.svg new file mode 100644 index 000000000..ad174a4ba --- /dev/null +++ b/Setup/Assets/Themes/Kobe/ViewFirstImage.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/Setup/Assets/Themes/Kobe/ViewLastImage.svg b/Setup/Assets/Themes/Kobe/ViewLastImage.svg new file mode 100644 index 000000000..089c53426 --- /dev/null +++ b/Setup/Assets/Themes/Kobe/ViewLastImage.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/Setup/Assets/Themes/Kobe/ViewNextImage.svg b/Setup/Assets/Themes/Kobe/ViewNextImage.svg new file mode 100644 index 000000000..289e4c67c --- /dev/null +++ b/Setup/Assets/Themes/Kobe/ViewNextImage.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/Setup/Assets/Themes/Kobe/ViewPreviousImage.svg b/Setup/Assets/Themes/Kobe/ViewPreviousImage.svg new file mode 100644 index 000000000..d0c2f2c66 --- /dev/null +++ b/Setup/Assets/Themes/Kobe/ViewPreviousImage.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/Setup/Assets/Themes/Kobe/WindowFit.svg b/Setup/Assets/Themes/Kobe/WindowFit.svg new file mode 100644 index 000000000..27549dd82 --- /dev/null +++ b/Setup/Assets/Themes/Kobe/WindowFit.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/Setup/Assets/Themes/Kobe/ZoomIn.svg b/Setup/Assets/Themes/Kobe/ZoomIn.svg new file mode 100644 index 000000000..61a1ea83a --- /dev/null +++ b/Setup/Assets/Themes/Kobe/ZoomIn.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/Setup/Assets/Themes/Kobe/ZoomOut.svg b/Setup/Assets/Themes/Kobe/ZoomOut.svg new file mode 100644 index 000000000..304a3b31c --- /dev/null +++ b/Setup/Assets/Themes/Kobe/ZoomOut.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/Setup/Assets/Themes/Kobe/igtheme.json b/Setup/Assets/Themes/Kobe/igtheme.json new file mode 100644 index 000000000..6bae91244 --- /dev/null +++ b/Setup/Assets/Themes/Kobe/igtheme.json @@ -0,0 +1,73 @@ +{ + "_Metadata": { + "Description": "ImageGlass theme configuration file", + "Version": "9.0" + }, + "Info": { + "Name": "Kobe", + "Author": "Dương Diệu Pháp", + "Email": "phap@imageglass.org", + "Website": "https://imageglass.org", + "Description": "ImageGlass Kobe theme", + "Version": "9.0" + }, + "Settings": { + "IsDarkMode": true, + "IsShowTitlebarLogo": true, + "NavButtonLeft": "ViewPreviousImage.svg", + "NavButtonRight": "ViewNextImage.svg", + "PreviewImage": "preview.webp", + "AppLogo": "Logo.svg" + }, + "Colors": { + "MenuBgHoverColor": "accent:50", + + "ToolbarItemHoverColor": "accent:140", + "ToolbarItemActiveColor": "accent:80", + "ToolbarItemSelectedColor": "accent:100", + + "GalleryItemHoverColor": "accent:140", + "GalleryItemActiveColor": "accent:80", + "GalleryItemSelectedColor": "accent:100", + + "NavigationButtonColor": "accent:140" + }, + "ToolbarIcons": { + "ActualSize": "ActualSize.svg", + "AutoZoom": "AutoZoom.svg", + "Checkerboard": "Checkerboard.svg", + "ColorPicker": "ColorPicker.svg", + "Crop": "Crop.svg", + "Delete": "Delete.svg", + "Edit": "Edit.svg", + "FlipHorz": "FlipHorz.svg", + "FlipVert": "FlipVert.svg", + "FullScreen": "FullScreen.svg", + "GoToImage": "GoToImage.svg", + "LockZoom": "LockZoom.svg", + "MainMenu": "MainMenu.svg", + "OpenFile": "OpenFile.svg", + "Print": "Print.svg", + "Refresh": "Refresh.svg", + "RotateLeft": "RotateLeft.svg", + "RotateRight": "RotateRight.svg", + "Save": "Save.svg", + "ScaleToFill": "ScaleToFill.svg", + "ScaleToFit": "ScaleToFit.svg", + "ScaleToHeight": "ScaleToHeight.svg", + "ScaleToWidth": "ScaleToWidth.svg", + "Slideshow": "Slideshow.svg", + "Gallery": "Gallery.svg", + "ViewFirstImage": "ViewFirstImage.svg", + "ViewLastImage": "ViewLastImage.svg", + "ViewNextImage": "ViewNextImage.svg", + "ViewPreviousImage": "ViewPreviousImage.svg", + "WindowFit": "WindowFit.svg", + "ZoomIn": "ZoomIn.svg", + "ZoomOut": "ZoomOut.svg", + "Play": "Play.svg", + "Pause": "Pause.svg", + "Export": "Export.svg", + "Exit": "Exit.svg" + } +} \ No newline at end of file diff --git a/Setup/Assets/Themes/Kobe/logo.svg b/Setup/Assets/Themes/Kobe/logo.svg new file mode 100644 index 000000000..a587c3c70 --- /dev/null +++ b/Setup/Assets/Themes/Kobe/logo.svg @@ -0,0 +1,90 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Setup/Assets/Themes/Kobe/preview.webp b/Setup/Assets/Themes/Kobe/preview.webp new file mode 100644 index 000000000..00ff66836 Binary files /dev/null and b/Setup/Assets/Themes/Kobe/preview.webp differ diff --git a/Setup/Assets/default.jpg b/Setup/Assets/default.jpg deleted file mode 100644 index 5e69af63a..000000000 Binary files a/Setup/Assets/default.jpg and /dev/null differ diff --git a/Setup/Assets/default.webp b/Setup/Assets/default.webp new file mode 100644 index 000000000..a4e9973b7 Binary files /dev/null and b/Setup/Assets/default.webp differ diff --git a/Setup/Settings/Logo.svg b/Setup/Settings/Logo.svg new file mode 100644 index 000000000..107bc0191 --- /dev/null +++ b/Setup/Settings/Logo.svg @@ -0,0 +1,117 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Setup/Settings/igconfig.default.json b/Setup/Settings/igconfig.default.json new file mode 100644 index 000000000..aeb861a52 --- /dev/null +++ b/Setup/Settings/igconfig.default.json @@ -0,0 +1,7 @@ +{ + "_Metadata": { + "Description": "ImageGlass configuration file", + "Version": 9.1 + }, + "AutoUpdate": "0" +} \ No newline at end of file diff --git a/Source/.editorconfig b/Source/.editorconfig new file mode 100644 index 000000000..c36c19508 --- /dev/null +++ b/Source/.editorconfig @@ -0,0 +1,164 @@ +[*.cs] + +# CS8603: Possible null reference return. +dotnet_diagnostic.CS8603.severity = none + +# CS8604: Possible null reference argument. +dotnet_diagnostic.CS8604.severity = none + +# CS8602: Dereference of a possibly null reference. +dotnet_diagnostic.CS8602.severity = none + +# CS8618: Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. +dotnet_diagnostic.CS8618.severity = none + +# Default severity for analyzer diagnostics with category 'Usage' +dotnet_analyzer_diagnostic.category-Usage.severity = none + +# Default severity for analyzer diagnostics with category 'Style' +dotnet_analyzer_diagnostic.category-Style.severity = none + +# CA1707: Identifiers should not contain underscores +dotnet_diagnostic.CA1707.severity = none +csharp_using_directive_placement = outside_namespace:silent +csharp_prefer_simple_using_statement = true:suggestion +csharp_prefer_braces = false:silent +csharp_style_namespace_declarations = file_scoped:silent +csharp_style_prefer_method_group_conversion = true:silent +csharp_style_prefer_top_level_statements = true:silent +csharp_style_prefer_primary_constructors = true:suggestion +csharp_style_expression_bodied_methods = false:silent +csharp_style_expression_bodied_constructors = false:silent +csharp_style_expression_bodied_operators = false:silent +csharp_style_expression_bodied_properties = true:silent +csharp_style_expression_bodied_indexers = true:silent +csharp_style_expression_bodied_accessors = true:silent +csharp_style_expression_bodied_lambdas = true:silent +csharp_style_expression_bodied_local_functions = false:silent +csharp_indent_labels = one_less_than_current +csharp_style_throw_expression = true:suggestion +csharp_style_prefer_null_check_over_type_check = true:suggestion + +# CA1305: Specify IFormatProvider +dotnet_diagnostic.CA1305.severity = none + +# CA2211: Non-constant fields should not be visible +dotnet_diagnostic.CA2211.severity = none + +# IDE0008: Use explicit type +dotnet_diagnostic.IDE0008.severity = none +csharp_prefer_system_threading_lock = true:suggestion +csharp_style_inlined_variable_declaration = true:suggestion +csharp_style_deconstructed_variable_declaration = false:suggestion +csharp_style_var_for_built_in_types = false:silent +csharp_style_var_when_type_is_apparent = false:silent +csharp_style_var_elsewhere = false:silent +csharp_prefer_static_local_function = true:suggestion +csharp_prefer_static_anonymous_function = true:suggestion +csharp_style_prefer_readonly_struct = true:suggestion +csharp_style_prefer_readonly_struct_member = true:suggestion +csharp_style_allow_blank_lines_between_consecutive_braces_experimental = true:silent +csharp_prefer_simple_default_expression = true:suggestion +csharp_style_prefer_local_over_anonymous_function = true:suggestion +csharp_style_prefer_index_operator = true:suggestion +csharp_style_prefer_range_operator = true:suggestion +csharp_style_implicit_object_creation_when_type_is_apparent = true:suggestion +csharp_style_prefer_tuple_swap = true:suggestion +csharp_style_prefer_utf8_string_literals = true:suggestion +csharp_style_unused_value_assignment_preference = discard_variable:suggestion +csharp_style_unused_value_expression_statement_preference = discard_variable:silent +csharp_style_allow_embedded_statements_on_same_line_experimental = true:silent +csharp_style_allow_blank_line_after_colon_in_constructor_initializer_experimental = true:silent +csharp_style_allow_blank_line_after_token_in_conditional_expression_experimental = true:silent +csharp_style_allow_blank_line_after_token_in_arrow_expression_clause_experimental = true:silent +csharp_style_conditional_delegate_call = true:suggestion +csharp_style_prefer_switch_expression = true:suggestion +csharp_style_pattern_matching_over_is_with_cast_check = true:suggestion +csharp_style_prefer_pattern_matching = true:silent +csharp_style_prefer_not_pattern = true:suggestion +csharp_style_pattern_matching_over_as_with_null_check = true:suggestion +csharp_style_prefer_extended_property_pattern = true:suggestion +dotnet_diagnostic.VSTHRD011.severity = silent + +[*.{cs,vb}] +#### Naming styles #### + +# Naming rules + +dotnet_naming_rule.interface_should_be_begins_with_i.severity = suggestion +dotnet_naming_rule.interface_should_be_begins_with_i.symbols = interface +dotnet_naming_rule.interface_should_be_begins_with_i.style = begins_with_i + +dotnet_naming_rule.types_should_be_pascal_case.severity = suggestion +dotnet_naming_rule.types_should_be_pascal_case.symbols = types +dotnet_naming_rule.types_should_be_pascal_case.style = pascal_case + +dotnet_naming_rule.non_field_members_should_be_pascal_case.severity = suggestion +dotnet_naming_rule.non_field_members_should_be_pascal_case.symbols = non_field_members +dotnet_naming_rule.non_field_members_should_be_pascal_case.style = pascal_case + +# Symbol specifications + +dotnet_naming_symbols.interface.applicable_kinds = interface +dotnet_naming_symbols.interface.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected +dotnet_naming_symbols.interface.required_modifiers = + +dotnet_naming_symbols.types.applicable_kinds = class, struct, interface, enum +dotnet_naming_symbols.types.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected +dotnet_naming_symbols.types.required_modifiers = + +dotnet_naming_symbols.non_field_members.applicable_kinds = property, event, method +dotnet_naming_symbols.non_field_members.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected +dotnet_naming_symbols.non_field_members.required_modifiers = + +# Naming styles + +dotnet_naming_style.begins_with_i.required_prefix = I +dotnet_naming_style.begins_with_i.required_suffix = +dotnet_naming_style.begins_with_i.word_separator = +dotnet_naming_style.begins_with_i.capitalization = pascal_case + +dotnet_naming_style.pascal_case.required_prefix = +dotnet_naming_style.pascal_case.required_suffix = +dotnet_naming_style.pascal_case.word_separator = +dotnet_naming_style.pascal_case.capitalization = pascal_case + +dotnet_naming_style.pascal_case.required_prefix = +dotnet_naming_style.pascal_case.required_suffix = +dotnet_naming_style.pascal_case.word_separator = +dotnet_naming_style.pascal_case.capitalization = pascal_case +dotnet_style_coalesce_expression = true:suggestion +dotnet_style_null_propagation = true:suggestion +dotnet_style_prefer_is_null_check_over_reference_equality_method = true:suggestion +dotnet_style_prefer_auto_properties = true:silent +dotnet_style_object_initializer = true:suggestion +dotnet_style_operator_placement_when_wrapping = beginning_of_line +tab_width = 4 +indent_size = 4 +end_of_line = crlf +dotnet_style_prefer_collection_expression = when_types_loosely_match:suggestion +dotnet_style_collection_initializer = true:suggestion +dotnet_style_prefer_simplified_boolean_expressions = true:suggestion +dotnet_style_prefer_conditional_expression_over_assignment = false:silent +dotnet_style_prefer_conditional_expression_over_return = false:silent +dotnet_style_explicit_tuple_names = true:suggestion +dotnet_style_prefer_inferred_tuple_names = true:suggestion +dotnet_style_prefer_inferred_anonymous_type_member_names = true:suggestion +dotnet_style_prefer_compound_assignment = true:suggestion +dotnet_style_prefer_simplified_interpolation = true:suggestion +dotnet_style_namespace_match_folder = true:suggestion +dotnet_style_require_accessibility_modifiers = for_non_interface_members:silent +dotnet_style_qualification_for_field = false:silent +dotnet_style_qualification_for_property = false:silent +dotnet_style_qualification_for_method = false:silent +dotnet_style_qualification_for_event = false:silent +dotnet_style_readonly_field = true:suggestion +dotnet_style_predefined_type_for_locals_parameters_members = true:silent +dotnet_style_predefined_type_for_member_access = true:silent +dotnet_style_allow_multiple_blank_lines_experimental = true:silent +dotnet_style_allow_statement_immediately_after_block_experimental = true:silent +dotnet_code_quality_unused_parameters = all:suggestion +dotnet_style_parentheses_in_other_binary_operators = always_for_clarity:silent +dotnet_style_parentheses_in_arithmetic_binary_operators = always_for_clarity:silent +dotnet_style_parentheses_in_other_operators = never_if_unnecessary:silent +dotnet_style_parentheses_in_relational_binary_operators = always_for_clarity:silent diff --git a/Source/Components/ImageGlass.Base/Actions/SingleAction.cs b/Source/Components/ImageGlass.Base/Actions/SingleAction.cs new file mode 100644 index 000000000..385f4587b --- /dev/null +++ b/Source/Components/ImageGlass.Base/Actions/SingleAction.cs @@ -0,0 +1,65 @@ +/* +ImageGlass Project - Image viewer for Windows +Copyright (C) 2010 - 2026 DUONG DIEU PHAP +Project homepage: https://imageglass.org + +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 . +*/ + +namespace ImageGlass.Base.Actions; + + +/// +/// Defines user single action +/// +public class SingleAction(string executable = "", object?[]? arguments = null, SingleAction? nextAction = null) +{ + /// + /// Executable action, its value can be: + /// + /// + /// Name of a menu item of MnuMain in FrmMain.cs. + /// For example: MnuPrint + /// + /// + /// Name of IG_ methods defined in FrmMain.IGMethods.cs. + /// For example: IG_Print + /// + /// + /// Path of executable file / command. + /// For example: cmd.exe + /// + /// + /// + public string Executable { get; set; } = executable.Trim(); + + + /// + /// Arguments to pass to the . + /// + public object?[] Arguments { get; set; } = arguments ?? []; + + + /// + /// Next action to execute after running . + /// + public SingleAction? NextAction { get; set; } = nextAction; + + + + public override string ToString() + { + return Executable; + } +} diff --git a/Source/Components/ImageGlass.Base/Actions/ToggleAction.cs b/Source/Components/ImageGlass.Base/Actions/ToggleAction.cs new file mode 100644 index 000000000..2e60e6890 --- /dev/null +++ b/Source/Components/ImageGlass.Base/Actions/ToggleAction.cs @@ -0,0 +1,86 @@ +/* +ImageGlass Project - Image viewer for Windows +Copyright (C) 2010 - 2026 DUONG DIEU PHAP +Project homepage: https://imageglass.org + +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 . +*/ +using System.Text.Json.Serialization; + +namespace ImageGlass.Base.Actions; + + +/// +/// Defines user toggling action +/// +public class ToggleAction(SingleAction? toggleOn = null) +{ + /// + /// Gets the ToggleAction manager to check whether the + /// toggling value is on (true) or off (false). + /// + private static readonly Dictionary _manager = []; + + + /// + /// Gets the id of the action for toggling. + /// + [JsonIgnore] + public Guid Id { get; init; } = Guid.NewGuid(); + + + /// + /// Action to run when toggling on. + /// + public SingleAction? ToggleOn { get; set; } = toggleOn; + + + /// + /// Action to run when toggling off. + /// + public SingleAction? ToggleOff { get; set; } = null; + + + /// + /// Checks if the given action is toggle off action + /// + public static bool IsToggleOff(Guid actionId) + { + if (_manager.TryGetValue(actionId, out var isToggled)) + { + return isToggled; + } + + return false; + } + + + /// + /// Sets the toggling value of the given action + /// + public static void SetToggleValue(Guid actionId, bool isToggled) + { + if (!_manager.TryAdd(actionId, isToggled)) + { + _manager[actionId] = isToggled; + } + } + + + public override string ToString() + { + return $"{ToggleOn?.ToString() ?? ""} | {ToggleOff?.ToString() ?? ""}"; + } +} + diff --git a/Source/Components/ImageGlass.Base/App.cs b/Source/Components/ImageGlass.Base/App.cs index 7e25d0b39..5da7299ba 100644 --- a/Source/Components/ImageGlass.Base/App.cs +++ b/Source/Components/ImageGlass.Base/App.cs @@ -1,6 +1,6 @@ /* ImageGlass Project - Image viewer for Windows -Copyright (C) 2020 DUONG DIEU PHAP +Copyright (C) 2010 - 2026 DUONG DIEU PHAP Project homepage: https://imageglass.org This program is free software: you can redistribute it and/or modify @@ -16,149 +16,139 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the You should have received a copy of the GNU General Public License along with this program. If not, see . */ +using Microsoft.Win32; +using System.Diagnostics; +using System.Security.Principal; -using System; -using System.Drawing; -using System.IO; -using System.Linq; -using System.Windows.Forms; +namespace ImageGlass.Base; -namespace ImageGlass.Base +public class App { /// - /// The base information of ImageGlass app + /// Gets the application executable path /// - public static class App - { - /// - /// Gets the application version - /// - public static string Version { get => Application.ProductVersion; } + public static string IGExePath => StartUpDir("ImageGlass.exe"); - /// - /// Gets the application version - /// - public static string IGExePath { get => StartUpDir("ImageGlass.exe"); } + /// + /// Gets the application name + /// + public static string AppName => FileVersionInfo.GetVersionInfo(IGExePath).ProductName; - /// - /// Gets value of Portable mode if the startup dir is writtable - /// - public static bool IsPortable { get => Helpers.CheckPathWritable(StartUpDir()); } + /// + /// Gets the product version + /// + public static string Version => FileVersionInfo.GetVersionInfo(IGExePath).FileVersion ?? ""; - /// - /// Get the path based on the startup folder of ImageGlass. - /// - /// - /// - public static string StartUpDir(params string[] paths) - { - var path = Application.StartupPath; + /// + /// Checks if the current user is administator + /// + public static bool IsAdmin => new WindowsPrincipal(WindowsIdentity.GetCurrent()) + .IsInRole(WindowsBuiltInRole.Administrator); - var newPaths = paths.ToList(); - newPaths.Insert(0, path); - return Path.Combine(newPaths.ToArray()); - } + /// + /// Gets value of Portable mode if the startup dir is writable + /// + public static bool IsPortable => BHelper.CheckPathWritable(PathType.Dir, StartUpDir()); - /// - /// Returns the path based on the configuration folder of ImageGlass. - /// For portable mode, ConfigDir = Installed Dir, else %appdata%\ImageGlass - /// - /// - /// - public static string ConfigDir(params string[] paths) - { - // use StartUp dir if it's writable - var startUpDir = StartUpDir(paths); - if (Helpers.CheckPathWritable(startUpDir)) - { - return startUpDir; - } + /// + /// Gets the path based on the startup folder of ImageGlass. + /// + public static string StartUpDir(params string[] paths) + { + var newPaths = paths.ToList(); + newPaths.Insert(0, Application.StartupPath); + + return Path.Combine([.. newPaths]); + } - // else, use AppData dir - var igAppDataDir = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), @"ImageGlass"); - var newPaths = paths.ToList(); - newPaths.Insert(0, igAppDataDir); - igAppDataDir = Path.Combine(newPaths.ToArray()); + /// + /// Returns the path based on the configuration folder of ImageGlass. + /// For portable mode, ConfigDir = InstalledDir, else %LocalAppData%\ImageGlass + /// + /// Indicates if the given path is either file or directory + public static string ConfigDir(PathType type, params string[] paths) + { + // use StartUp dir if it's writable + var startUpPath = StartUpDir(paths); - return igAppDataDir; + if (BHelper.CheckPathWritable(type, startUpPath)) + { + return startUpPath; } + // else, use AppData dir + var appDataDir = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), AppName); - /// - /// Parse string to absolute path - /// - /// The relative/absolute path of file/folder; or a URI Scheme - /// - public static string ToAbsolutePath(string inputPath) - { - var path = inputPath; - var protocol = Constants.URI_SCHEME + ":"; + // create the directory if not exists + Directory.CreateDirectory(appDataDir); - // If inputPath is URI Scheme - if (path.StartsWith(protocol)) - { - // Retrieve the real path - path = Uri.UnescapeDataString(path).Remove(0, protocol.Length); - } + var newPaths = paths.ToList(); + newPaths.Insert(0, appDataDir); + appDataDir = Path.Combine([.. newPaths]); + + return appDataDir; + } - // Parse environment vars to absolute path - path = Environment.ExpandEnvironmentVariables(path); - return path; - } + + /// + /// Checks if ImageGlass starts with OS + /// + public static bool CheckStartWithOs() + { + const string APP_NAME = "ImageGlass"; + var regAppPath = @"SOFTWARE\Microsoft\Windows\CurrentVersion\Run"; - /// - /// Center the given form to the current screen. - /// Note***: The method Form.CenterToScreen() contains a bug: - /// https://stackoverflow.com/a/6837499/2856887 - /// - /// The form to center - public static void CenterFormToScreen(Form form) + try { - var screen = Screen.FromControl(form); + using var key = Registry.CurrentUser.OpenSubKey(regAppPath); + var keyValue = key?.GetValue(APP_NAME)?.ToString(); - var workingArea = screen.WorkingArea; - form.Location = new Point() - { - X = Math.Max(workingArea.X, workingArea.X + (workingArea.Width - form.Width) / 2), - Y = Math.Max(workingArea.Y, workingArea.Y + (workingArea.Height - form.Height) / 2) - }; + var isEnabled = !string.IsNullOrWhiteSpace(keyValue); + + return isEnabled; } + catch { } + return false; + } - /// - /// Write log in DEBUG mode - /// - /// - public static void LogIt(string msg) + + /// + /// Sets or unsets ImageGlass to start with OS in mode. + /// Returns null if successful. + /// + public static Exception? SetStartWithOs(bool enable) + { + Exception? error = null; + const string APP_NAME = "ImageGlass"; + var regAppPath = @"SOFTWARE\Microsoft\Windows\CurrentVersion\Run"; + + try { -#if DEBUG - try + using var key = Registry.CurrentUser.OpenSubKey(regAppPath, true); + + if (enable) { - var tempDir = App.ConfigDir(Dir.Log); - if (!Directory.Exists(tempDir)) - { - Directory.CreateDirectory(tempDir); - } - var path = Path.Combine(tempDir, "iglog.log"); - - using (TextWriter tw = new StreamWriter(path, append: true)) - { - tw.WriteLine(msg); - tw.Flush(); - tw.Close(); - } + key?.SetValue(APP_NAME, $"\"{App.IGExePath}\" {IgCommands.STARTUP_BOOST}"); + } + else + { + key?.DeleteValue(APP_NAME); } - catch { } -#endif } + catch (Exception ex) { error = ex; } + + return error; } + + } diff --git a/Source/Components/ImageGlass.Base/BHelper/Extensions/BitmapExtensions.cs b/Source/Components/ImageGlass.Base/BHelper/Extensions/BitmapExtensions.cs new file mode 100644 index 000000000..bcf82c055 --- /dev/null +++ b/Source/Components/ImageGlass.Base/BHelper/Extensions/BitmapExtensions.cs @@ -0,0 +1,72 @@ +/* +ImageGlass Project - Image viewer for Windows +Copyright (C) 2010 - 2026 DUONG DIEU PHAP +Project homepage: https://imageglass.org + +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 . +*/ + +using System.Drawing.Imaging; + +namespace ImageGlass.Base; + +public static class BitmapExtensions +{ + /// + /// Gets pixel color. + /// + /// + /// if the is null. + /// + public static Color GetPixelColor(this Bitmap? bmp, int x, int y) + { + if (bmp == null) return Color.Transparent; + + unsafe + { + var bitmapData = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadOnly, bmp.PixelFormat); + + var firstPixelPtr = (byte*)bitmapData.Scan0; + var position = (bitmapData.Stride * y) + (x * 4); + + var color = Color.FromArgb( + firstPixelPtr[position + 3], + firstPixelPtr[position + 2], + firstPixelPtr[position + 1], + firstPixelPtr[position + 0]); + + bmp.UnlockBits(bitmapData); + + return color; + } + } + + + /// + /// Sets the active frame of the bitmap using . + /// + public static void SetActiveTimeFrame(this Bitmap? bmp, int frameIndex) + { + if (bmp == null || frameIndex < 0) return; + + var frameCount = bmp.GetFrameCount(FrameDimension.Time); + + // Check if frame index is greater than upper limit + if (frameIndex >= frameCount) return; + + // Set active frame index + bmp.SelectActiveFrame(FrameDimension.Time, frameIndex); + } + +} diff --git a/Source/Components/ImageGlass.Base/BHelper/Extensions/ColorExtensions.cs b/Source/Components/ImageGlass.Base/BHelper/Extensions/ColorExtensions.cs new file mode 100644 index 000000000..2800a078e --- /dev/null +++ b/Source/Components/ImageGlass.Base/BHelper/Extensions/ColorExtensions.cs @@ -0,0 +1,276 @@ +/* +ImageGlass Project - Image viewer for Windows +Copyright (C) 2010 - 2026 DUONG DIEU PHAP +Project homepage: https://imageglass.org + +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 . +*/ + +using Cysharp.Text; + +namespace ImageGlass.Base; + +public static class ColorExtensions +{ + /// + /// Creates a new color with corrected brightness. + /// + /// Color to correct. + /// The brightness correction factor. + /// Must be between -1 and 1. + /// Negative values produce darker colors. + public static Color WithBrightness(this Color color, float brightnessFactor) + { + if (brightnessFactor == 0) return color; + + float red = color.R; + float green = color.G; + float blue = color.B; + + if (brightnessFactor < 0) + { + brightnessFactor = 1 + brightnessFactor; + red *= brightnessFactor; + green *= brightnessFactor; + blue *= brightnessFactor; + } + else + { + red = (255 - red) * brightnessFactor + red; + green = (255 - green) * brightnessFactor + green; + blue = (255 - blue) * brightnessFactor + blue; + } + + return Color.FromArgb(color.A, (byte)red, (byte)green, (byte)blue); + } + + + /// + /// Creates a new color structure with the input alpha. + /// + public static Color WithAlpha(this Color c, int alpha = 255) + { + return Color.FromArgb(alpha, c); + } + + + /// + /// Creates a new color structure without alpha value. + /// + public static Color NoAlpha(this Color c) + { + return c.WithAlpha(255); + } + + + /// Blends the specified colors together. + /// Color to blend onto the background color. + /// Color to blend the other color onto. + /// How much of the original color to keep, + /// “on top of” . + /// A new blended color. + public static Color Blend(this Color c, Color blendColor, double amount = 0.5f, int alpha = 255) + { + byte r = (byte)(c.R * amount + blendColor.R * (1 - amount)); + byte g = (byte)(c.G * amount + blendColor.G * (1 - amount)); + byte b = (byte)(c.B * amount + blendColor.B * (1 - amount)); + + return Color.FromArgb(alpha, r, g, b); + } + + + /// + /// Returns if the input color's brightness is greater than 0.5, otherwise returns . + /// + public static Color BlackOrWhite(this Color c, int alpha = 255) + { + if (c.GetBrightness() >= 0.5f) + { + return Color.White.WithAlpha(alpha); + } + + return Color.Black.WithAlpha(alpha); + } + + + /// + /// Returns if the input color's brightness is greater than 0.5, otherwise returns . + /// + public static Color InvertBlackOrWhite(this Color c, int alpha = 255) + { + if (c.GetBrightness() > 0.5f) + { + return Color.Black.WithAlpha(alpha); + } + + return Color.White.WithAlpha(alpha); + } + + + /// + /// Creates a from DWORD value. + /// + public static Color FromDWORD(this Color c, int dColor) + { + int a = (dColor >> 24) & 0xFF, + r = (dColor >> 0) & 0xFF, + g = (dColor >> 8) & 0xFF, + b = (dColor >> 16) & 0xFF; + + return Color.FromArgb(a, r, g, b); + } + + + /// + /// Converts this color to COLORREF (Win32). + /// + public static uint ToCOLORREF(this Color c) + { + return (uint)(ColorTranslator.ToWin32(c)); + } + + + /// + /// Converts this color to RGBA array. + /// + public static byte[] ToRgbaArray(this Color c) + { + return [c.R, c.G, c.B, c.A]; + } + + + /// + /// Converts this color to CMYK values. + /// + public static int[] ToCmyk(this Color c) + { + if (c.R == 0 && c.G == 0 && c.B == 0) + { + return [0, 0, 0, 1]; + } + + var black = Math.Min(1.0 - (c.R / 255.0), Math.Min(1.0 - (c.G / 255.0), 1.0 - (c.B / 255.0))); + var cyan = (1.0 - (c.R / 255.0) - black) / (1.0 - black); + var magenta = (1.0 - (c.G / 255.0) - black) / (1.0 - black); + var yellow = (1.0 - (c.B / 255.0) - black) / (1.0 - black); + + return [ + (int)Math.Round(cyan * 100), + (int)Math.Round(magenta * 100), + (int)Math.Round(yellow * 100), + (int)Math.Round(black * 100) + ]; + } + + + /// + /// Converts this color to HSLA values. + /// + public static float[] ToHsla(this Color c) + { + var h = (float)Math.Round(c.GetHue()); + var s = (float)Math.Round(c.GetSaturation() * 100); + var l = (float)Math.Round(c.GetBrightness() * 100); + var a = (float)Math.Round(c.A / 255.0, 3); + + return [h, s, l, a]; + } + + + /// + /// Converts this color to HSVA values. + /// + public static float[] ToHsva(this Color c) + { + int max = Math.Max(c.R, Math.Max(c.G, c.B)); + int min = Math.Min(c.R, Math.Min(c.G, c.B)); + + var hue = (float)Math.Round(c.GetHue()); + var saturation = (float)Math.Round(100 * ((max == 0) ? 0 : 1f - (1f * min / max))); + var value = (float)Math.Round(max * 100f / 255); + var alpha = (float)Math.Round(c.A / 255.0, 3); + + return [hue, saturation, value, alpha]; + } + + + /// + /// Converts this color to HEXA values. + /// + /// + public static string ToHex(this Color c, bool skipAlpha = false) + { + if (skipAlpha) + { + return ZString.Format("#{0:X2}{1:X2}{2:X2}", c.R, c.G, c.B); + } + + return ZString.Format("#{0:X2}{1:X2}{2:X2}{3:X2}", c.R, c.G, c.B, c.A); + } + + + /// + /// Converts this color to CIELAB. + /// + public static (float L, float A, float B, float Alpha) ToCIELAB(this Color c) + { + var xyz = new double[3]; + var rgb = new double[3] { c.R / 255d, c.G / 255d, c.B / 255d }; + var alpha = (float)Math.Round(c.A / 255f, 2); + + + if (rgb[0] > .04045f) rgb[0] = Math.Pow((rgb[0] + 0.055) / 1.055, 2.4); + else rgb[0] = rgb[0] / 12.92f; + + if (rgb[1] > .04045f) rgb[1] = Math.Pow((rgb[1] + 0.055) / 1.055, 2.4); + else rgb[1] = rgb[1] / 12.92f; + + if (rgb[2] > .04045f) rgb[2] = Math.Pow((rgb[2] + 0.055) / 1.055, 2.4); + else rgb[2] = rgb[2] / 12.92f; + + + rgb[0] = rgb[0] * 100.0f; + rgb[1] = rgb[1] * 100.0f; + rgb[2] = rgb[2] * 100.0f; + + + xyz[0] = ((rgb[0] * 0.412453f) + (rgb[1] * 0.357580f) + (rgb[2] * 0.180423f)); + xyz[1] = ((rgb[0] * 0.212671f) + (rgb[1] * 0.715160f) + (rgb[2] * 0.072169f)); + xyz[2] = ((rgb[0] * 0.019334f) + (rgb[1] * 0.119193f) + (rgb[2] * 0.950227f)); + + + xyz[0] = xyz[0] / 95.047f; + xyz[1] = xyz[1] / 100.0f; + xyz[2] = xyz[2] / 108.883f; + + + if (xyz[0] > .008856f) xyz[0] = (float)Math.Pow(xyz[0], (1.0 / 3.0)); + else xyz[0] = (xyz[0] * 7.787f) + (16.0f / 116.0f); + + if (xyz[1] > .008856f) xyz[1] = (float)Math.Pow(xyz[1], 1.0 / 3.0); + else xyz[1] = (xyz[1] * 7.787f) + (16.0f / 116.0f); + + if (xyz[2] > .008856f) xyz[2] = (float)Math.Pow(xyz[2], 1.0 / 3.0); + else xyz[2] = (xyz[2] * 7.787f) + (16.0f / 116.0f); + + + var l = (float)Math.Round((116.0f * xyz[1]) - 16.0f, 2); + var a = (float)Math.Round(500.0f * (xyz[0] - xyz[1]), 2); + var b = (float)Math.Round(200.0f * (xyz[1] - xyz[2]), 2); + + + return (l, a, b, alpha); + } + +} diff --git a/Source/Components/ImageGlass.Base/BHelper/Extensions/ControlExtensions.cs b/Source/Components/ImageGlass.Base/BHelper/Extensions/ControlExtensions.cs new file mode 100644 index 000000000..96a798d03 --- /dev/null +++ b/Source/Components/ImageGlass.Base/BHelper/Extensions/ControlExtensions.cs @@ -0,0 +1,130 @@ +/* +ImageGlass Project - Image viewer for Windows +Copyright (C) 2010 - 2026 DUONG DIEU PHAP +Project homepage: https://imageglass.org + +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 . +*/ + +namespace ImageGlass.Base; + +public static class ControlExtensions +{ + /// + /// Scales the given number to the current control's DPI. + /// + public static T ScaleToDpi(this Control control, T number) + { + float floatValue; + try + { + var fNum = (float?)Convert.ChangeType(number, typeof(float)); + if (fNum == null) return number; + + floatValue = fNum.Value; + } + catch { return number; } + + + var dpiScale = control.DeviceDpi / 96f; + var scaledValue = floatValue * dpiScale; + var type = typeof(T); + + return (T)Convert.ChangeType(scaledValue, type); + } + + + /// + /// Scales the given point to the current control's DPI. + /// + public static PointF ScaleToDpi(this Control control, PointF point) + { + var x = control.ScaleToDpi(point.X); + var y = control.ScaleToDpi(point.Y); + + return new PointF(x, y); + } + + + /// + /// Scales the given point to the current control's DPI. + /// + public static Point ScaleToDpi(this Control control, Point point) + { + var x = control.ScaleToDpi(point.X); + var y = control.ScaleToDpi(point.Y); + + return new Point(x, y); + } + + + /// + /// Scales the given size to the current control's DPI. + /// + public static SizeF ScaleToDpi(this Control control, SizeF size) + { + var w = control.ScaleToDpi(size.Width); + var h = control.ScaleToDpi(size.Height); + + return new SizeF(w, h); + } + + + /// + /// Scales the given size to the current control's DPI. + /// + public static Size ScaleToDpi(this Control control, Size size) + { + var w = control.ScaleToDpi(size.Width); + var h = control.ScaleToDpi(size.Height); + + return new Size(w, h); + } + + + /// + /// Scales the given padding to the current control's DPI. + /// + public static Padding ScaleToDpi(this Control control, Padding padding) + { + return new Padding( + control.ScaleToDpi(padding.Left), + control.ScaleToDpi(padding.Top), + control.ScaleToDpi(padding.Right), + control.ScaleToDpi(padding.Bottom)); + } + + + /// + /// Scales the given rectangle to the current control's DPI. + /// + public static Rectangle ScaleToDpi(this Control control, Rectangle rect) + { + return new Rectangle(rect.X, rect.Y, + control.ScaleToDpi(rect.Width), + control.ScaleToDpi(rect.Height)); + } + + + /// + /// Scales the given rectangle to the current control's DPI. + /// + public static RectangleF ScaleToDpi(this Control control, RectangleF rect) + { + return new RectangleF(rect.X, rect.Y, + control.ScaleToDpi(rect.Width), + control.ScaleToDpi(rect.Height)); + } + +} diff --git a/Source/Components/ImageGlass.Base/BHelper/Extensions/DateTimeExtensions.cs b/Source/Components/ImageGlass.Base/BHelper/Extensions/DateTimeExtensions.cs new file mode 100644 index 000000000..99731e6ee --- /dev/null +++ b/Source/Components/ImageGlass.Base/BHelper/Extensions/DateTimeExtensions.cs @@ -0,0 +1,33 @@ +/* +ImageGlass Project - Image viewer for Windows +Copyright (C) 2010 - 2026 DUONG DIEU PHAP +Project homepage: https://imageglass.org + +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 . +*/ +using System.Globalization; + +namespace ImageGlass.Base; + +public static class DateTimeExtensions +{ + /// + /// Convert the current value of to string in ISO 8601 date format. + /// + public static string ToISO8601String(this DateTime thisDT) + { + return thisDT.ToString("O", CultureInfo.InvariantCulture); + } + +} diff --git a/Source/Components/ImageGlass.Base/BHelper/Extensions/ExpandoObjectExtensions.cs b/Source/Components/ImageGlass.Base/BHelper/Extensions/ExpandoObjectExtensions.cs new file mode 100644 index 000000000..bd5e490a7 --- /dev/null +++ b/Source/Components/ImageGlass.Base/BHelper/Extensions/ExpandoObjectExtensions.cs @@ -0,0 +1,113 @@ +/* +ImageGlass Project - Image viewer for Windows +Copyright (C) 2010 - 2026 DUONG DIEU PHAP +Project homepage: https://imageglass.org + +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 . +*/ + +using Microsoft.CSharp.RuntimeBinder; +using System.Dynamic; + +namespace ImageGlass.Base; + +public static class ExpandoObjectExtensions +{ + /// + /// Gets value from the . + /// + public static T GetValue(this ExpandoObject? expObj, string keyName, T defaultValue) + { + if (expObj == null) return defaultValue; + var dict = expObj as IDictionary; + + try + { + _ = dict.TryGetValue(keyName, out var result); + + return BHelper.ConvertType(result) ?? defaultValue; + } + catch (RuntimeBinderException) { } + + return defaultValue; + } + + + /// + /// Gets value from the . + /// + public static object? GetValue(this ExpandoObject? expObj, string keyName) + { + if (expObj == null) return null; + var dict = expObj as IDictionary; + + try + { + _ = dict.TryGetValue(keyName, out var result); + + return result; + } + catch (RuntimeBinderException) { } + + return null; + } + + + /// + /// Removes an item in . + /// + public static bool Remove(this ExpandoObject? expObj, string keyName) + { + if (expObj == null) return false; + var dict = expObj as IDictionary; + + return dict.Remove(keyName); + } + + + /// + /// Sets value to . + /// + public static void Set(this ExpandoObject? expObj, string keyName, object value) + { + if (expObj == null) return; + var dict = expObj as IDictionary; + + if (dict.ContainsKey(keyName)) + { + dict[keyName] = value; + } + else + { + _ = dict.TryAdd(keyName, value); + } + } + + + /// + /// Converts to . + /// + public static ExpandoObject ToExpandoObject(this T obj) + { + var expObj = new ExpandoObject(); + + foreach (var propertyInfo in typeof(T).GetProperties()) + { + var currentValue = propertyInfo.GetValue(obj); + _ = expObj.TryAdd(propertyInfo.Name, currentValue); + } + + return expObj; + } +} diff --git a/Source/Components/ImageGlass.Base/BHelper/Extensions/GraphicsExtensions.cs b/Source/Components/ImageGlass.Base/BHelper/Extensions/GraphicsExtensions.cs new file mode 100644 index 000000000..004181ad9 --- /dev/null +++ b/Source/Components/ImageGlass.Base/BHelper/Extensions/GraphicsExtensions.cs @@ -0,0 +1,43 @@ +/* +ImageGlass Project - Image viewer for Windows +Copyright (C) 2010 - 2026 DUONG DIEU PHAP +Project homepage: https://imageglass.org + +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 . +*/ + +namespace ImageGlass.Base; + +public static class GraphicsExtensions +{ + /// + /// Fills rounded rectangle. + /// + public static void FillRoundedRectangle(this Graphics g, Brush brush, RectangleF rect, float radius, bool flatBottom = false, int bottomOffset = 0, bool flatTop = false) + { + using var path = BHelper.GetRoundRectanglePath(rect, radius, flatBottom, bottomOffset, flatTop); + g.FillPath(brush, path); + } + + + /// + /// Draws rounded rectangle. + /// + public static void DrawRoundedRectangle(this Graphics g, Pen pen, RectangleF rect, float radius, bool flatBottom = false, int bottomOffset = 0, bool flatTop = false) + { + using var path = BHelper.GetRoundRectanglePath(rect, radius, flatBottom, bottomOffset, flatTop); + g.DrawPath(pen, path); + } + +} diff --git a/Source/Components/ImageGlass.Base/BHelper/Extensions/ID2D1Bitmap1Extensions.cs b/Source/Components/ImageGlass.Base/BHelper/Extensions/ID2D1Bitmap1Extensions.cs new file mode 100644 index 000000000..165c02597 --- /dev/null +++ b/Source/Components/ImageGlass.Base/BHelper/Extensions/ID2D1Bitmap1Extensions.cs @@ -0,0 +1,193 @@ +/* +ImageGlass Project - Image viewer for Windows +Copyright (C) 2010 - 2026 DUONG DIEU PHAP +Project homepage: https://imageglass.org + +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 . +*/ +using DirectN; +using System.Runtime.InteropServices; +using WicNet; + +namespace ImageGlass.Base; + +public static class ID2D1Bitmap1Extensions +{ + /// + /// Create bitmap for CPU Read only. + /// + public static IComObject? CreateCpuReadBitmap( + this IComObject? srcBitmap1, + IComObject? dc) + { + if (srcBitmap1 == null || dc == null) return null; + + var bmpProps = new D2D1_BITMAP_PROPERTIES1() + { + bitmapOptions = D2D1_BITMAP_OPTIONS.D2D1_BITMAP_OPTIONS_CANNOT_DRAW | D2D1_BITMAP_OPTIONS.D2D1_BITMAP_OPTIONS_CPU_READ, + pixelFormat = new D2D1_PIXEL_FORMAT() + { + alphaMode = D2D1_ALPHA_MODE.D2D1_ALPHA_MODE_PREMULTIPLIED, + format = DXGI_FORMAT.DXGI_FORMAT_B8G8R8A8_UNORM, + }, + dpiX = 96.0f, + dpiY = 96.0f, + }; + + + // get bitmap size + var dsize = srcBitmap1.GetSize().ToD2D_SIZE_U(); + + + // create CPU-read bitmap + var bitmapCpu = dc.CreateBitmap(dsize, bmpProps); + bitmapCpu.CopyFromBitmap(srcBitmap1); + + return bitmapCpu; + } + + + /// + /// Gets pixel data of bitmap. + /// + public static (byte[] Pixels, Size Size, int Stripe) GetBitmapData( + this IComObject? srcBitmap1, + IComObject? dc) + { + var pixels = Span.Empty; + var size = new Size(); + var stripe = 0; + + if (srcBitmap1 == null || dc == null) return (pixels.ToArray(), size, stripe); + + + // get bitmap size + var dsize = srcBitmap1.GetSize(); + size = new((int)dsize.width, (int)dsize.height); + + // create CPU-read bitmap + using var bitmapCpu = srcBitmap1.CreateCpuReadBitmap(dc); + + // copy all raw pixel data + var map = bitmapCpu.Map(D2D1_MAP_OPTIONS.D2D1_MAP_OPTIONS_READ); + stripe = (int)map.pitch; + var totalDataSize = size.Height * stripe; + + var bytes = new byte[totalDataSize]; + Marshal.Copy(map.bits, bytes, 0, totalDataSize); + bitmapCpu.Unmap(); + + + // process raw pixel data + // since pixel data is D2D1_ALPHA_MODE_PREMULTIPLIED, + // we need to re-calculate the color values + pixels = bytes.AsSpan(); + for (int i = 0; i < pixels.Length; i += 4) + { + var a = pixels[i + 3]; + var alphaPremultiplied = a / 255f; + + pixels[i + 2] = (byte)(pixels[i + 2] / alphaPremultiplied); // r + pixels[i + 1] = (byte)(pixels[i + 1] / alphaPremultiplied); // g + pixels[i] = (byte)(pixels[i] / alphaPremultiplied); // b + } + + return (pixels.ToArray(), size, stripe); + } + + + /// + /// Converts to + /// + public static WicBitmapSource? ToWicBitmapSource(this IComObject? srcBitmap1, IComObject? dc) + { + var data = srcBitmap1.GetBitmapData(dc); + if (data.Pixels.Length == 0) return null; + + var bmp = WicBitmapSource.FromMemory(data.Size.Width, data.Size.Height, + WicPixelFormat.GUID_WICPixelFormat32bppPBGRA, data.Stripe, data.Pixels); + + return bmp; + } + + + /// + /// Clones . + /// + public static IComObject? Clone(this IComObject? srcBitmap1, IComObject? dc) + { + if (srcBitmap1 == null) return null; + + + var bmpProps = new D2D1_BITMAP_PROPERTIES1() + { + bitmapOptions = D2D1_BITMAP_OPTIONS.D2D1_BITMAP_OPTIONS_TARGET, + pixelFormat = new D2D1_PIXEL_FORMAT() + { + alphaMode = D2D1_ALPHA_MODE.D2D1_ALPHA_MODE_PREMULTIPLIED, + format = DXGI_FORMAT.DXGI_FORMAT_B8G8R8A8_UNORM, + }, + dpiX = 96.0f, + dpiY = 96.0f, + }; + + // create an empty bitmap + dc.Object.GetImageLocalBounds(srcBitmap1.Object, out var outputRect); + var newD2dBitmap = dc.CreateBitmap(outputRect.SizeU, bmpProps); + + // copy bitmap source + newD2dBitmap.CopyFromBitmap(srcBitmap1); + + return newD2dBitmap; + } + + + /// + /// Gets pixel color. + /// + /// + /// if + /// or is null. + /// + public static Color GetPixelColor(this IComObject? srcBitmap1, + IComObject? dc, int x, int y) + { + if (srcBitmap1 == null || dc == null) return Color.Transparent; + + // create CPU-read bitmap + using var bitmapCpu = srcBitmap1.CreateCpuReadBitmap(dc); + var map = bitmapCpu.Map(D2D1_MAP_OPTIONS.D2D1_MAP_OPTIONS_READ); + var startIndex = (y * map.pitch) + (x * 4); + + var bytes = new byte[4]; + Marshal.Copy((nint)(map.bits + startIndex), bytes, 0, bytes.Length); + bitmapCpu.Unmap(); + + + // since pixel data is D2D1_ALPHA_MODE_PREMULTIPLIED, + // we need to re-calculate the color values + var a = bytes[3]; + var alphaPremultiplied = a / 255f; + + var r = (byte)(bytes[2] / alphaPremultiplied); + var g = (byte)(bytes[1] / alphaPremultiplied); + var b = (byte)(bytes[0] / alphaPremultiplied); + + + var color = Color.FromArgb(a, r, g, b); + + return color; + } + +} diff --git a/Source/Components/ImageGlass.Base/BHelper/Extensions/ID2D1EffectExtensions.cs b/Source/Components/ImageGlass.Base/BHelper/Extensions/ID2D1EffectExtensions.cs new file mode 100644 index 000000000..78a8f0d35 --- /dev/null +++ b/Source/Components/ImageGlass.Base/BHelper/Extensions/ID2D1EffectExtensions.cs @@ -0,0 +1,79 @@ +/* +ImageGlass Project - Image viewer for Windows +Copyright (C) 2010 - 2026 DUONG DIEU PHAP +Project homepage: https://imageglass.org + +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 . +*/ +using DirectN; + +namespace ImageGlass.Base; + +public static class ID2D1EffectExtensions +{ + + /// + /// Gets from . + /// + public static IComObject GetD2D1Bitmap1(this IComObject effect, IComObject? dc, bool ignoreAlpha = false) + { + var bmpProps = new D2D1_BITMAP_PROPERTIES1() + { + bitmapOptions = D2D1_BITMAP_OPTIONS.D2D1_BITMAP_OPTIONS_TARGET, + pixelFormat = new D2D1_PIXEL_FORMAT() + { + alphaMode = D2D1_ALPHA_MODE.D2D1_ALPHA_MODE_PREMULTIPLIED, + format = DXGI_FORMAT.DXGI_FORMAT_B8G8R8A8_UNORM, + }, + dpiX = 96.0f, + dpiY = 96.0f, + }; + + + // create empty bitmap from the effect output + var effectOutputImage = effect.GetOutput(); + dc.Object.GetImageLocalBounds(effectOutputImage.Object, out var outputRect); + var newD2dBitmap = dc.CreateBitmap(outputRect.SizeU, bmpProps); + + + // save current Target, replace by ID2D1Bitmap + dc.Object.GetTarget(out var oldTarget); + var oldTargetObj = new ComObject(oldTarget); + dc.SetTarget(newD2dBitmap); + + + // draw Image on Target + dc.BeginDraw(); + dc.Clear(); + if (ignoreAlpha) + { + // fill back background if alpha is ignored + using var brush = dc.CreateSolidColorBrush(_D3DCOLORVALUE.Black); + dc.FillRectangle(outputRect, brush); + } + dc.DrawImage(effectOutputImage, D2D1_INTERPOLATION_MODE.D2D1_INTERPOLATION_MODE_NEAREST_NEIGHBOR, D2D1_COMPOSITE_MODE.D2D1_COMPOSITE_MODE_SOURCE_OVER); + dc.EndDraw(); + + + // set previous Target + dc.SetTarget(oldTargetObj); + + + // release resources + oldTargetObj.Dispose(); + effectOutputImage.Dispose(); + + return newD2dBitmap; + } +} diff --git a/Source/Components/ImageGlass.Base/BHelper/Extensions/NumberExtensions.cs b/Source/Components/ImageGlass.Base/BHelper/Extensions/NumberExtensions.cs new file mode 100644 index 000000000..03cdf975f --- /dev/null +++ b/Source/Components/ImageGlass.Base/BHelper/Extensions/NumberExtensions.cs @@ -0,0 +1,46 @@ +/* +ImageGlass Project - Image viewer for Windows +Copyright (C) 2010 - 2026 DUONG DIEU PHAP +Project homepage: https://imageglass.org + +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 . +*/ +namespace ImageGlass.Base; + +public static class NumberExtensions +{ + public static PointF ToPointF(this Point p) + { + return new PointF(p.X, p.Y); + } + + + public static Point ToPoint(this PointF p) + { + return new Point((int)p.X, (int)p.Y); + } + + + public static RectangleF ToRectangleF(this Rectangle rect) + { + return new RectangleF((float)rect.X, (float)rect.Y, (float)rect.Width, (float)rect.Height); + } + + + public static Rectangle ToRectangle(this RectangleF rect) + { + return new Rectangle((int)rect.X, (int)rect.Y, (int)rect.Width, (int)rect.Height); + } + +} diff --git a/Source/Components/ImageGlass.Base/BHelper/Extensions/StringExtensions.cs b/Source/Components/ImageGlass.Base/BHelper/Extensions/StringExtensions.cs new file mode 100644 index 000000000..8780a35d7 --- /dev/null +++ b/Source/Components/ImageGlass.Base/BHelper/Extensions/StringExtensions.cs @@ -0,0 +1,57 @@ +/* +ImageGlass Project - Image viewer for Windows +Copyright (C) 2010 - 2026 DUONG DIEU PHAP +Project homepage: https://imageglass.org + +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 . +*/ +using Cysharp.Text; +using System.Globalization; +using System.Text; + +namespace ImageGlass.Base; + +public static class StringExtensions +{ + /// + /// Capitalizes the first letter of the string. + /// + public static string? CapitalizeFirst(this string? thisString, CultureInfo? culture = null) + { + if (string.IsNullOrEmpty(thisString)) + return null; + + if (culture == null) + return char.ToUpper(thisString[0]) + thisString.Substring(1); + + return char.ToUpper(thisString[0], culture) + thisString.Substring(1); + } + + + /// + /// Replaces string. + /// + public static string ReplaceMultiple(this string value, IEnumerable<(string Variable, string Value)> toReplace) + { + using var result = ZString.CreateStringBuilder(); + result.Append(value); + + foreach (var item in toReplace) + { + result.Replace(item.Variable, item.Value); + } + + return result.ToString(); + } +} diff --git a/Source/Components/ImageGlass.Base/BHelper/Format.cs b/Source/Components/ImageGlass.Base/BHelper/Format.cs new file mode 100644 index 000000000..2a6ae73f2 --- /dev/null +++ b/Source/Components/ImageGlass.Base/BHelper/Format.cs @@ -0,0 +1,178 @@ +/* +ImageGlass Project - Image viewer for Windows +Copyright (C) 2010 - 2026 DUONG DIEU PHAP +Project homepage: https://imageglass.org + +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 . +*/ + +using Cysharp.Text; +using System.Globalization; + +namespace ImageGlass.Base; + +public partial class BHelper +{ + /// + /// Formats the given file size as a human readable string. + /// + /// File size in bytes. + /// The formatted string. + public static string FormatSize(long size) + { + var mod = 1024d; + var sized = size * 1d; + + var units = new string[] { "bytes", "KB", "MB", "GB", "TB", "PB" }; + int i; + for (i = 0; sized > mod; i++) + { + sized /= mod; + } + + return ZString.Format("{0} {1}", Math.Round(sized, 2), units[i]); + } + + /// + /// Formats date time string to string + /// + /// + /// + public static string FormatDateTime(string? str, bool includeTime = true) + { + var dt = ConvertDateTime(str); + + return FormatDateTime(dt, includeTime); + } + + /// + /// Formats to string + /// + /// + /// + /// + public static string FormatDateTime(DateTime? dt, bool includeTime = true) + { + if (dt != null) + { + return dt.Value.ToString(includeTime ? Const.DATETIME_FORMAT : Const.DATE_FORMAT); + } + + return string.Empty; + } + + /// + /// Convert date time string to + /// + /// + /// + public static DateTime? ConvertDateTime(string? dt) + { + if (DateTime.TryParseExact(dt, + "yyyy:MM:dd HH:mm:ss", + CultureInfo.CurrentCulture, + DateTimeStyles.None, + out var dateTaken)) + { + return dateTaken; + } + + return null; + } + + + /// + /// Formats the 0-99 rating to the simple rating (0-5). + /// + public static int FormatStarRating(int rating) + { + var star = 0; + + if (rating >= 1 && rating <= 12) + star = 1; + else if (rating >= 13 && rating <= 37) + star = 2; + else if (rating >= 38 && rating <= 62) + star = 3; + else if (rating >= 63 && rating <= 87) + star = 4; + else if (rating >= 88 && rating <= 99) + star = 5; + + return star; + } + + + /// + /// Formats the rating as stars. + /// + public static string FormatStarRatingText(int rating) + { + var star = FormatStarRating(rating); + var ratingText = star > 0 + ? "".PadRight(star, '⭐').PadRight(5, '-').Replace("-", " -") + : string.Empty; + + return ratingText; + } + + + /// + /// Ellipses the given text. + /// + public static string EllipsisText(string text, Font font, float containerWidth, Graphics g) + { + var textSize = g.MeasureString(text, font); + var avgCharW = textSize.Width / text.Length; + var maxCharsPerSide = (int)Math.Floor(containerWidth / avgCharW / 2d); + + var truncated = string.Concat( + text.AsSpan(0, maxCharsPerSide), + "…", + text.AsSpan(text.Length - maxCharsPerSide, maxCharsPerSide)); + + return truncated; + } + + + /// + /// Simplifies the fractions. + /// + public static int[] SimplifyFractions(params int[] numbers) + { + // get the greatest common divisor of the input numbers + var gcd = numbers.Aggregate((currentGcd, arg) => CalculateGcd(currentGcd, arg)); + + for (int i = 0; i < numbers.Length; i++) + { + numbers[i] /= gcd; + } + + return numbers; + + + int CalculateGcd(int a, int b) + { + while (b > 0) + { + int rem = a % b; + a = b; + b = rem; + } + return a; + } + } + + +} \ No newline at end of file diff --git a/Source/Components/ImageGlass.Base/BHelper/General.cs b/Source/Components/ImageGlass.Base/BHelper/General.cs new file mode 100644 index 000000000..7289b2378 --- /dev/null +++ b/Source/Components/ImageGlass.Base/BHelper/General.cs @@ -0,0 +1,254 @@ +/* +ImageGlass Project - Image viewer for Windows +Copyright (C) 2010 - 2026 DUONG DIEU PHAP +Project homepage: https://imageglass.org + +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 . +*/ + +using Cysharp.Text; +using System.Security.Cryptography; +using System.Text; +using System.Windows.Input; + +namespace ImageGlass.Base; + +public partial class BHelper +{ + /// + /// Center the given rectangle to the rectangle. + /// + /// + /// + /// + public static Rectangle CenterRectToRect(Rectangle rect1, Rectangle rect2, bool limitRect1Size = false) + { + var x = rect2.X + ((rect2.Width - rect1.Width) / 2); + var y = rect2.Y + ((rect2.Height - rect1.Height) / 2); + var width = rect1.Width; + var height = rect1.Height; + + if (limitRect1Size) + { + x = Math.Max(rect2.X, x); + y = Math.Max(rect2.Y, y); + width = Math.Min(rect1.Width, rect2.Width); + height = Math.Min(rect1.Height, rect2.Height); + } + + return new Rectangle(x, y, width, height); + } + + + /// + /// Get all controls by type + /// + public static IEnumerable GetAllControls(Control control, Type type) + { + var controls = control.Controls.Cast(); + + return controls.SelectMany(ctrl => GetAllControls(ctrl, type)) + .Concat(controls) + .Where(c => c.GetType() == type); + } + + + /// + /// Checks if the given rectangle is visible on any screen + /// + public static bool IsVisibleOnAnyScreen(Rectangle rect) + { + return Screen.AllScreens.Any(i => i.WorkingArea.IntersectsWith(rect)); + } + + + /// + /// Checks if the given Windows version is matched. + /// + public static bool IsOS(WindowsOS ver) + { + if (ver == WindowsOS.Win11_22H2_OrLater) + { + return Environment.OSVersion.Version.Major >= 10 + && Environment.OSVersion.Version.Build >= 22621; + } + + if (ver == WindowsOS.Win11OrLater) + { + return Environment.OSVersion.Version.Major >= 10 + && Environment.OSVersion.Version.Build >= 22000; + } + + if (ver == WindowsOS.Win10) + { + return Environment.OSVersion.Version.Major == 10 + && Environment.OSVersion.Version.Build < 22000; + } + + if (ver == WindowsOS.Win10OrLater) + { + return Environment.OSVersion.Version.Major >= 10; + } + + + return false; + } + + + /// + /// Checks if the OS is Windows 10 or greater or equals the given build number. + /// + /// Build number of Windows. + public static bool IsOSBuildOrGreater(int build) + { + return Environment.OSVersion.Version.Major >= 10 + && Environment.OSVersion.Version.Build >= build; + } + + + /// + /// Gets selection rectangle from 2 points. + /// + /// The first point + /// The second point + /// Aspect ratio + /// The rectangle to limit the selection + public static RectangleF GetSelection(PointF? point1, PointF? point2, + SizeF aspectRatio, float srcWidth, float srcHeight, + RectangleF limitRect) + { + var selectedArea = new RectangleF(); + var fromPoint = point1 ?? new PointF(); + var toPoint = point2 ?? new PointF(); + + if (fromPoint.IsEmpty || toPoint.IsEmpty) return selectedArea; + + // swap fromPoint and toPoint value if toPoint is less than fromPoint + if (toPoint.X < fromPoint.X) + { + var tempX = fromPoint.X; + fromPoint.X = toPoint.X; + toPoint.X = tempX; + } + if (toPoint.Y < fromPoint.Y) + { + var tempY = fromPoint.Y; + fromPoint.Y = toPoint.Y; + toPoint.Y = tempY; + } + + float width = Math.Abs(fromPoint.X - toPoint.X); + float height = Math.Abs(fromPoint.Y - toPoint.Y); + + selectedArea.X = fromPoint.X; + selectedArea.Y = fromPoint.Y; + selectedArea.Width = width; + selectedArea.Height = height; + + // limit the selected area to the limitRect + selectedArea.Intersect(limitRect); + + + // free aspect ratio + if (aspectRatio.Width <= 0 || aspectRatio.Height <= 0) + return selectedArea; + + + var wRatio = aspectRatio.Width / aspectRatio.Height; + var hRatio = aspectRatio.Height / aspectRatio.Width; + + // update selection size according to the ratio + if (wRatio > hRatio) + { + selectedArea.Height = selectedArea.Width / wRatio; + + if (selectedArea.Bottom >= limitRect.Bottom) + { + var maxHeight = limitRect.Bottom - selectedArea.Y; + selectedArea.Width = maxHeight * wRatio; + selectedArea.Height = maxHeight; + } + } + else + { + selectedArea.Width = selectedArea.Height / hRatio; + + if (selectedArea.Right >= limitRect.Right) + { + var maxWidth = limitRect.Right - selectedArea.X; ; + selectedArea.Width = maxWidth; + selectedArea.Height = maxWidth * hRatio; + } + } + + + return selectedArea; + } + + + /// + /// Opens ImageGlass site om Microsoft Store. + /// + public static void OpenImageGlassMsStore() + { + var campaignId = $"IgInAppBadgeV{App.Version}"; + var source = "AboutWindow"; + + try + { + var url = $"ms-windows-store://pdp/?productid={Const.MS_APPSTORE_ID}&cid={campaignId}&referrer=appbadge&source={source}"; + + _ = BHelper.OpenUrlAsync(url); + } + catch + { + try + { + var url = $"https://www.microsoft.com/store/productId/{Const.MS_APPSTORE_ID}?cid={campaignId}&referrer=appbadge&source={source}"; + + _ = BHelper.OpenUrlAsync(url); + } + catch { } + } + } + + + /// + /// Create an unique key for the input file. + /// + public static string CreateUniqueFileKey(string filePath, Size? size = null) + { + var fi = new FileInfo(filePath); + using var sb = ZString.CreateStringBuilder(); + + sb.Append(filePath); + sb.Append(':'); + sb.Append(fi.LastWriteTimeUtc.ToBinary()); + + // Thumbnail size + if (size is Size s) + { + sb.Append(':'); + sb.Append(s.Width); + sb.Append(','); + sb.Append(s.Height); + } + + + var hash = MD5.HashData(Encoding.ASCII.GetBytes(sb.ToString())); + + return Convert.ToHexString(hash).ToLowerInvariant(); + } + +} \ No newline at end of file diff --git a/Source/Components/ImageGlass.Base/BHelper/JsonEx.cs b/Source/Components/ImageGlass.Base/BHelper/JsonEx.cs new file mode 100644 index 000000000..da820044e --- /dev/null +++ b/Source/Components/ImageGlass.Base/BHelper/JsonEx.cs @@ -0,0 +1,117 @@ +/* +ImageGlass Project - Image viewer for Windows +Copyright (C) 2010 - 2026 DUONG DIEU PHAP +Project homepage: https://imageglass.org + +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 . +*/ + +using System.Text; +using System.Text.Encodings.Web; +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace ImageGlass.Base; + +public partial class BHelper +{ + private static JsonSerializerOptions JsonOptions { get; } = new() + { + PropertyNameCaseInsensitive = true, + AllowTrailingCommas = true, + WriteIndented = true, + Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping, + NumberHandling = JsonNumberHandling.AllowReadingFromString | JsonNumberHandling.AllowNamedFloatingPointLiterals, + + Converters = + { + // Write enum value as string + new JsonStringEnumConverter(), + + new CustomDateTimeConverter(Const.DATETIME_FORMAT), + }, + + // ignoring policy + DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingDefault | JsonIgnoreCondition.WhenWritingNull, + IgnoreReadOnlyProperties = true, + IgnoreReadOnlyFields = true, + }; + + + /// + /// Parse JSON string to object + /// + public static T? ParseJson(string? json) + { + if (json == null) return default(T); + + return JsonSerializer.Deserialize(json, JsonOptions); + } + + + /// + /// Parse object to JSON string + /// + public static string ToJson(T obj) + { + return JsonSerializer.Serialize(obj, typeof(T), JsonOptions); + } + + + /// + /// Parse JSON from a stream + /// + public static async Task ParseJson(Stream stream) + { + return await JsonSerializer.DeserializeAsync(stream, JsonOptions); + } + + + /// + /// Reads JSON file and parses to object + /// + public static T? ReadJson(string jsonFilePath) + { + using var stream = File.OpenRead(jsonFilePath); + + return JsonSerializer.Deserialize(stream, JsonOptions); + } + + + /// + /// Writes an object value to JSON file + /// + public static async Task WriteJsonAsync(string jsonFilePath, object? value, CancellationToken token = default) + { + var json = JsonSerializer.Serialize(value, JsonOptions); + + await File.WriteAllTextAsync(jsonFilePath, json, Encoding.UTF8, token); + } +} + + +public class CustomDateTimeConverter(string format) : JsonConverter +{ + private readonly string Format = format; + + public override void Write(Utf8JsonWriter writer, DateTime date, JsonSerializerOptions options) + { + writer.WriteStringValue(date.ToString(Format)); + } + + public override DateTime Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + return DateTime.ParseExact(reader.GetString(), Format, null); + } +} \ No newline at end of file diff --git a/Source/Components/ImageGlass.Base/BHelper/Path.cs b/Source/Components/ImageGlass.Base/BHelper/Path.cs new file mode 100644 index 000000000..b35d620fc --- /dev/null +++ b/Source/Components/ImageGlass.Base/BHelper/Path.cs @@ -0,0 +1,491 @@ +/* +ImageGlass Project - Image viewer for Windows +Copyright (C) 2010 - 2026 DUONG DIEU PHAP +Project homepage: https://imageglass.org + +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 . +*/ +using ImageGlass.Base.FileSystem; +using ImageGlass.Base.Photoing.Codecs; +using ImageGlass.Base.WinApi; +using Microsoft.VisualBasic.FileIO; +using System.Diagnostics; +using System.Web; +using Windows.System; + +namespace ImageGlass.Base; + + +public partial class BHelper +{ + /// + /// Check if the given path (file or directory) is writable. + /// + /// Indicates if the given path is either file or directory + /// Full path of file or directory + public static bool CheckPathWritable(PathType type, string path) + { + try + { + // If path is file + if (type == PathType.File) + { + using (File.OpenWrite(path)) { } + } + + // if path is directory + else + { + var isDirExist = Directory.Exists(path); + + if (!isDirExist) + { + Directory.CreateDirectory(path); + } + + var sampleFile = Path.Combine(path, "test_write_file.temp"); + + using (File.Create(sampleFile)) { } + File.Delete(sampleFile); + + if (!isDirExist) + { + Directory.Delete(path, true); + } + } + + + return true; + } + catch + { + return false; + } + } + + + /// + /// Get distinct directories list from paths list. + /// + public static List GetDistinctDirsFromPaths(IEnumerable pathList) + { + if (!pathList.Any()) return []; + + var hashedDirsList = new HashSet(); + + foreach (var path in pathList) + { + var pathType = CheckPath(path); + if (pathType == PathType.Unknown) continue; + + if (pathType == PathType.Dir) + { + hashedDirsList.Add(path); + } + else + { + string dir; + if (string.Equals(Path.GetExtension(path), ".lnk", StringComparison.CurrentCultureIgnoreCase)) + { + var shortcutPath = FileShortcutApi.GetTargetPathFromShortcut(path); + var shortcutPathType = CheckPath(shortcutPath); + if (shortcutPathType == PathType.Unknown) continue; + + // get the DIR path of shortcut target + if (shortcutPathType == PathType.Dir) + { + dir = shortcutPath; + } + else + { + dir = Path.GetDirectoryName(shortcutPath) ?? ""; + } + } + else + { + dir = Path.GetDirectoryName(path) ?? ""; + } + + hashedDirsList.Add(dir); + } + } + + return [.. hashedDirsList]; + } + + + + /// + /// Checks type of the path. + /// + public static PathType CheckPath(string path) + { + try + { + var attrs = File.GetAttributes(path); + + if (attrs.HasFlag(FileAttributes.Directory)) + { + return PathType.Dir; + } + + return PathType.File; + } + catch { } + + return PathType.Unknown; + } + + + /// + /// Resolves a relative/protocol/link path to absolute path + /// + /// A path + /// + public static string ResolvePath(string? inputPath) + { + if (string.IsNullOrEmpty(inputPath)) + return inputPath ?? ""; + + var path = inputPath; + const string protocol = Const.APP_PROTOCOL + ":"; + + // If inputPath is URI Scheme + if (path.StartsWith(protocol)) + { + // Retrieve the real path + path = Uri.UnescapeDataString(path).Remove(0, protocol.Length); + } + + // Parse environment vars to absolute path + path = Environment.ExpandEnvironmentVariables(path); + + if (string.Equals(Path.GetExtension(inputPath), ".lnk", StringComparison.CurrentCultureIgnoreCase)) + { + path = FileShortcutApi.GetTargetPathFromShortcut(path); + } + + return path; + } + + + /// + /// Open URL in the default browser. + /// + public static async Task OpenUrlAsync(string? url, string campaign = "from_unknown") + { + if (string.IsNullOrWhiteSpace(url)) return; + + try + { + var ub = new UriBuilder(url); + var queries = HttpUtility.ParseQueryString(ub.Query); + queries["utm_source"] = "app_" + App.Version; + queries["utm_medium"] = "app_click"; + queries["utm_campaign"] = campaign; + + ub.Query = queries.ToString(); + + _ = await Launcher.LaunchUriAsync(ub.Uri); + } + catch { } + } + + + /// + /// Opens file path in Explorer and selects it. + /// + public static void OpenFilePath(string? filePath) + { + if (string.IsNullOrWhiteSpace(filePath)) return; + + try + { + ExplorerApi.OpenFolderAndSelectItem(filePath); + } + catch + { + using var proc = Process.Start("explorer.exe", $"/select,\"{filePath}\""); + } + } + + + /// + /// Opens the folder path in Explorer, creates the fodler path if not existed. + /// + public static void OpenFolderPath(string? dirPath) + { + if (string.IsNullOrWhiteSpace(dirPath)) return; + + try + { + Directory.CreateDirectory(dirPath); + } + catch { } + + try + { + using var proc = Process.Start("explorer.exe", $"\"{dirPath}\""); + } + catch { } + } + + + /// + /// Delete a file + /// + /// Full file path to delete + /// true: Move to Recycle bin; false: Delete permanently + public static void DeleteFile(string filePath, bool moveToRecycleBin = true) + { + var option = moveToRecycleBin ? RecycleOption.SendToRecycleBin : RecycleOption.DeletePermanently; + + try + { + Microsoft.VisualBasic.FileIO.FileSystem.DeleteFile(filePath, UIOption.OnlyErrorDialogs, option); + } + catch (OperationCanceledException) { } + } + + + + /// + /// Finds all files in the given directories. + /// + public static IEnumerable FindFiles(IEnumerable rootDirs, + bool searchAllDirectories, + bool includeHidden, + Predicate? filterFn = null, + Func, IEnumerable>? postProcessFn = null) + { + var results = Enumerable.Empty(); + + Parallel.For(0, rootDirs.Count(), i => + { + var filePaths = FindFiles(rootDirs.ElementAt(i), + searchAllDirectories, + includeHidden, + filterFn); // skip postProcessFn + + results = Enumerable.Concat(results, filePaths); + }); + + + // post processing + if (postProcessFn != null) results = postProcessFn(results); + + return results; + } + + + /// + /// Finds all files in the given directory. + /// + public static IEnumerable FindFiles(string rootDir, + bool searchAllDirectories, + bool includeHidden, + Predicate? filterFn = null, + Func, IEnumerable>? postProcessFn = null) + { + // check attributes to skip + var skipAttrs = FileAttributes.System; + if (!includeHidden) skipAttrs |= FileAttributes.Hidden; + + + var filePaths = Directory.EnumerateFiles(rootDir, "*", new EnumerationOptions() + { + IgnoreInaccessible = true, + AttributesToSkip = skipAttrs, + RecurseSubdirectories = searchAllDirectories, + }).Where(path => filterFn == null ? true : filterFn(path)); + + + // post processing + if (postProcessFn != null) filePaths = postProcessFn(filePaths); + + return filePaths; + } + + + /// + /// Sort image list. + /// + public static IEnumerable SortFilePathList(IEnumerable fileList, + ImageOrderBy orderBy, ImageOrderType orderType, bool groupByDir) + { + // KBR 20190605 + // Fix observed limitation: to more closely match the Windows Explorer's sort + // order, we must sort by the target column, then by name. + var filePathComparer = new StringNaturalComparer(orderType == ImageOrderType.Asc, true); + + // initiate directory sorter to a comparer that does nothing + // if user wants to group by directory, we initiate the real comparer + var identityComparer = (IComparer)Comparer.Create((a, b) => 0); + var dirPathComparer = groupByDir + ? new StringNaturalComparer(orderType == ImageOrderType.Asc, true) + : identityComparer; + + // KBR 20190605 Fix observed discrepancy: using UTC for create, + // but not for write/access times + + // Sort image file + if (orderBy == ImageOrderBy.FileSize) + { + if (orderType == ImageOrderType.Desc) + { + return fileList.AsParallel() + .OrderBy(f => Path.GetDirectoryName(f), dirPathComparer) + .ThenByDescending(f => new FileInfo(f).Length) + .ThenBy(f => Path.GetFileName(f), filePathComparer); + } + else + { + return fileList.AsParallel() + .OrderBy(f => Path.GetDirectoryName(f), dirPathComparer) + .ThenBy(f => new FileInfo(f).Length) + .ThenBy(f => Path.GetFileName(f), filePathComparer); + } + } + + // sort by CreationTime + if (orderBy == ImageOrderBy.DateCreated) + { + if (orderType == ImageOrderType.Desc) + { + return fileList.AsParallel() + .OrderBy(f => Path.GetDirectoryName(f), dirPathComparer) + .ThenByDescending(f => new FileInfo(f).CreationTimeUtc) + .ThenBy(f => Path.GetFileName(f), filePathComparer); + } + else + { + return fileList.AsParallel() + .OrderBy(f => Path.GetDirectoryName(f), dirPathComparer) + .ThenBy(f => new FileInfo(f).CreationTimeUtc) + .ThenBy(f => Path.GetFileName(f), filePathComparer); + } + } + + // sort by Extension + if (orderBy == ImageOrderBy.Extension) + { + if (orderType == ImageOrderType.Desc) + { + return fileList.AsParallel() + .OrderBy(f => Path.GetDirectoryName(f), dirPathComparer) + .ThenByDescending(f => new FileInfo(f).Extension.ToLowerInvariant()) + .ThenBy(f => Path.GetFileName(f), filePathComparer); + } + else + { + return fileList.AsParallel() + .OrderBy(f => Path.GetDirectoryName(f), dirPathComparer) + .ThenBy(f => new FileInfo(f).Extension.ToLowerInvariant()) + .ThenBy(f => Path.GetFileName(f), filePathComparer); + } + } + + // sort by LastAccessTime + if (orderBy == ImageOrderBy.DateAccessed) + { + if (orderType == ImageOrderType.Desc) + { + return fileList.AsParallel() + .OrderBy(f => Path.GetDirectoryName(f), dirPathComparer) + .ThenByDescending(f => new FileInfo(f).LastAccessTimeUtc) + .ThenBy(f => Path.GetFileName(f), filePathComparer); + } + else + { + return fileList.AsParallel() + .OrderBy(f => Path.GetDirectoryName(f), dirPathComparer) + .ThenBy(f => new FileInfo(f).LastAccessTimeUtc) + .ThenBy(f => Path.GetFileName(f), filePathComparer); + } + } + + // sort by LastWriteTime + if (orderBy == ImageOrderBy.DateModified) + { + if (orderType == ImageOrderType.Desc) + { + return fileList.AsParallel() + .OrderBy(f => Path.GetDirectoryName(f), dirPathComparer) + .ThenByDescending(f => new FileInfo(f).LastWriteTimeUtc) + .ThenBy(f => Path.GetFileName(f), filePathComparer); + } + else + { + return fileList.AsParallel() + .OrderBy(f => Path.GetDirectoryName(f), dirPathComparer) + .ThenBy(f => new FileInfo(f).LastWriteTimeUtc) + .ThenBy(f => Path.GetFileName(f), filePathComparer); + } + } + + // sort by Random + if (orderBy == ImageOrderBy.Random) + { + // NOTE: ignoring the 'descending order' setting + return fileList.AsParallel() + .OrderBy(f => Path.GetDirectoryName(f), dirPathComparer) + .ThenBy(_ => Guid.NewGuid()); + } + + // sort by DateTaken + if (orderBy == ImageOrderBy.ExifDateTaken) + { + if (orderType == ImageOrderType.Desc) + { + return fileList + .OrderBy(f => Path.GetDirectoryName(f), dirPathComparer) + .ThenByDescending(f => PhotoCodec.LoadMetadata(f).ExifDateTimeOriginal) + .ThenBy(f => Path.GetFileName(f), new StringNaturalComparer()); // always by ASC + } + else + { + return fileList + .OrderBy(f => Path.GetDirectoryName(f), dirPathComparer) + .ThenBy(f => PhotoCodec.LoadMetadata(f).ExifDateTimeOriginal) + .ThenBy(f => Path.GetFileName(f), filePathComparer); + } + } + + // sort by Rating + if (orderBy == ImageOrderBy.ExifRating) + { + if (orderType == ImageOrderType.Desc) + { + return fileList + .OrderBy(f => Path.GetDirectoryName(f), dirPathComparer) + .ThenByDescending(f => PhotoCodec.LoadMetadata(f).ExifRatingPercent) + .ThenBy(f => Path.GetFileName(f), new StringNaturalComparer()); // always by ASC + } + else + { + return fileList + .OrderBy(f => Path.GetDirectoryName(f), dirPathComparer) + .ThenBy(f => PhotoCodec.LoadMetadata(f).ExifRatingPercent) + .ThenBy(f => Path.GetFileName(f), filePathComparer); + } + } + + + // sort by Name (default) + return fileList.AsParallel() + .OrderBy(f => Path.GetDirectoryName(f), dirPathComparer) + .ThenBy(f => Path.GetFileName(f), filePathComparer); + } + +} diff --git a/Source/Components/ImageGlass.Base/BHelper/Photoing.cs b/Source/Components/ImageGlass.Base/BHelper/Photoing.cs new file mode 100644 index 000000000..281dc42d9 --- /dev/null +++ b/Source/Components/ImageGlass.Base/BHelper/Photoing.cs @@ -0,0 +1,841 @@ +/* +ImageGlass Project - Image viewer for Windows +Copyright (C) 2010 - 2026 DUONG DIEU PHAP +Project homepage: https://imageglass.org + +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 . +*/ +using ImageGlass.Base.Photoing.Codecs; +using ImageGlass.Base.WinApi; +using ImageMagick; +using Microsoft.Win32.SafeHandles; +using PhotoSauce.MagicScaler; +using System.Diagnostics; +using System.Drawing.Imaging; +using System.Reflection; +using System.Runtime.InteropServices; +using System.Text.RegularExpressions; +using System.Windows; +using System.Windows.Media.Imaging; +using WicNet; +using Windows.Graphics.Imaging; +using Windows.Media.FaceAnalysis; +using Windows.Media.Ocr; +using Windows.Win32; +using ColorProfile = ImageMagick.ColorProfile; + +namespace ImageGlass.Base; + + +public partial class BHelper +{ + /// + /// Converts to object. + /// + public static WicBitmapSource? ToWicBitmapSource(BitmapSource? bmp, bool hasAlpha = true) + { + if (bmp == null) + return null; + + var prop = bmp.GetType().GetProperty("WicSourceHandle", + BindingFlags.NonPublic | BindingFlags.Instance); + + var srcHandle = (SafeHandleZeroOrMinusOneIsInvalid?)prop?.GetValue(bmp); + if (srcHandle == null) return null; + + + var obj = Marshal.GetObjectForIUnknown(srcHandle.DangerousGetHandle()); + + var wicSrc = new WicBitmapSource(obj); + try + { + wicSrc.ConvertTo(hasAlpha + ? WicPixelFormat.GUID_WICPixelFormat32bppPBGRA + : WicPixelFormat.GUID_WICPixelFormat32bppBGR); + } + catch (InvalidOperationException) + { + // cannot convert format + return null; + } + + return wicSrc; + } + + + /// + /// Converts to . + /// + public static WicBitmapSource? ToWicBitmapSource(Bitmap? bmp) + { + if (bmp == null) return null; + + WicBitmapSource? wicSrc = null; + var hBitmap = new IntPtr(); + + try + { + hBitmap = bmp.GetHbitmap(); + wicSrc = WicBitmapSource.FromHBitmap(hBitmap); + wicSrc.ConvertTo(WicPixelFormat.GUID_WICPixelFormat32bppPBGRA); + } + catch (ArgumentException) + { + // ignore: bmp is disposed + } + catch (InvalidOperationException) + { + // cannot convert format + } + finally + { + PInvoke.DeleteObject(new Windows.Win32.Graphics.Gdi.HGDIOBJ(hBitmap)); + } + + return wicSrc; + } + + + /// + /// Converts to . + /// + public static WicBitmapSource? ToWicBitmapSource(Image? img) + { + if (img == null) return null; + + using var bmp = new Bitmap(img); + return ToWicBitmapSource(bmp); + } + + + /// + /// Converts to . + /// + public static WicBitmapSource? ToWicBitmapSource(Stream? stream) + { + if (stream == null) return null; + + var wicSrc = WicBitmapSource.Load(stream); + try + { + wicSrc.ConvertTo(WicPixelFormat.GUID_WICPixelFormat32bppPBGRA); + } + catch (InvalidOperationException) + { + // cannot convert format + return null; + } + + return wicSrc; + } + + + /// + /// Converts base64 string to . + /// + /// Base64 string + public static WicBitmapSource? ToWicBitmapSource(string base64) + { + var (MimeType, ByteData) = ConvertBase64ToBytes(base64); + if (string.IsNullOrEmpty(MimeType)) return null; + + // supported MIME types: + // https://www.iana.org/assignments/media-types/media-types.xhtml#image + var settings = new MagickReadSettings + { + Format = MimeTypeToMagickFormat(MimeType) + }; + + if (settings.Format == MagickFormat.Rsvg) + { + settings.BackgroundColor = MagickColors.Transparent; + } + + + WicBitmapSource? src = null; + switch (settings.Format) + { + case MagickFormat.Gif: + case MagickFormat.Gif87: + case MagickFormat.Tif: + case MagickFormat.Tiff64: + case MagickFormat.Tiff: + case MagickFormat.Ico: + case MagickFormat.Icon: + using (var ms = new MemoryStream(ByteData) { Position = 0 }) + { + using var bitm = new Bitmap(ms, true); + var hBitmap = new IntPtr(); + + try + { + hBitmap = bitm.GetHbitmap(); + src = WicBitmapSource.FromHBitmap(hBitmap); + } + catch (ArgumentException) + { + // ignore: bmp is disposed + } + finally + { + PInvoke.DeleteObject(new Windows.Win32.Graphics.Gdi.HGDIOBJ(hBitmap)); + } + } + break; + + default: + using (var imgM = new MagickImage(ByteData, settings)) + { + var bmp = imgM.ToBitmapSource(); + src = BHelper.ToWicBitmapSource(bmp, imgM.HasAlpha); + } + break; + } + + if (src == null) return null; + + try + { + src.ConvertTo(WicPixelFormat.GUID_WICPixelFormat32bppPBGRA); + } + catch (InvalidOperationException) + { + // cannot convert format + return null; + } + return src; + } + + + /// + /// Convert to . + /// + public static MemoryStream? ToMemoryStream(WicBitmapSource? wicSrc) + { + if (wicSrc == null) return null; + + // convert to stream + var ms = new MemoryStream(); + wicSrc?.Save(ms, WicEncoder.GUID_ContainerFormatPng); + ms.Position = 0; + + return ms; + } + + /// + /// Converts to . + /// + public static async Task ToSoftwareBitmapAsync(WicBitmapSource? wicSrc) + { + using var ms = new Windows.Storage.Streams.InMemoryRandomAccessStream(); + using var stream = ms.AsStream(); + + try + { + // convert to stream + wicSrc.Save(stream, WicEncoder.GUID_ContainerFormatPng); + + // create SoftwareBitmap from stream + var bmpDecoder = await Windows.Graphics.Imaging.BitmapDecoder.CreateAsync(ms); + var softwareBmp = await bmpDecoder.GetSoftwareBitmapAsync(); + + return softwareBmp; + } + catch { } + + return null; + } + + + /// + /// Converts to . + /// https://stackoverflow.com/a/2897325/2856887 + /// + public static Bitmap? ToGdiPlusBitmap(WicBitmapSource? source) + { + if (source == null) + return null; + + var bmp = new Bitmap( + source.Width, + source.Height, + PixelFormat.Format32bppPArgb); + + var data = bmp.LockBits( + new Rectangle(new(0, 0), bmp.Size), + ImageLockMode.WriteOnly, + PixelFormat.Format32bppPArgb); + + source.CopyPixels((uint)(data.Height * data.Stride), data.Scan0, data.Stride); + + bmp.UnlockBits(data); + + return bmp; + } + + + /// + /// Converts to . + /// https://stackoverflow.com/a/2897325/2856887 + /// + public static Bitmap? ToGdiPlusBitmap(BitmapSource? source) + { + if (source == null) + return null; + + var bmp = new Bitmap( + (int)source.Width, + (int)source.Height, + PixelFormat.Format32bppPArgb); + + var data = bmp.LockBits( + new Rectangle(new(0, 0), bmp.Size), + ImageLockMode.WriteOnly, + PixelFormat.Format32bppPArgb); + + source.CopyPixels(Int32Rect.Empty, data.Scan0, data.Height * data.Stride, data.Stride); + + bmp.UnlockBits(data); + + return bmp; + } + + + /// + /// Loads from file. + /// + /// Full file path. + /// Use color profile. + public static Bitmap ToGdiPlusBitmap(string filePath, bool useICM = true) + { + using var fs = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite); + var ms = new MemoryStream(); + fs.CopyTo(ms); + ms.Position = 0; + + return new Bitmap(ms, useICM); + } + + + /// + /// Converts base64 string to . + /// + public static Bitmap? ToGdiPlusBitmapFromBase64(string? content) + { + var (MimeType, ByteData) = ConvertBase64ToBytes(content); + if (string.IsNullOrEmpty(MimeType)) return null; + + // supported MIME types: + // https://www.iana.org/assignments/media-types/media-types.xhtml#image + var settings = new MagickReadSettings + { + Format = MimeTypeToMagickFormat(MimeType) + }; + + if (settings.Format == MagickFormat.Rsvg) + { + settings.BackgroundColor = MagickColors.Transparent; + } + + + Bitmap? bmp = null; + switch (settings.Format) + { + case MagickFormat.Gif: + case MagickFormat.Gif87: + case MagickFormat.Tif: + case MagickFormat.Tiff64: + case MagickFormat.Tiff: + case MagickFormat.Ico: + case MagickFormat.Icon: + bmp = new Bitmap(new MemoryStream(ByteData) + { + Position = 0 + }, true); + + break; + + default: + using (var imgM = new MagickImage(ByteData, settings)) + { + bmp = imgM.ToBitmap(); + } + break; + } + + return bmp; + } + + + /// + /// Loads and process the SVG file, replaces #000 or #fff + /// by the corresponding hex color value of the . + /// + public static Bitmap? ToGdiPlusBitmapFromSvg(string? svgFilePath, bool darkMode, uint? width = null, uint? height = null) + { + if (string.IsNullOrEmpty(svgFilePath)) return null; + + using var imgM = BHelper.RunSync(() => PhotoCodec.ReadSvgWithMagickAsync(svgFilePath, darkMode, width, height)); + + return imgM.ToBitmap(ImageFormat.Png); + } + + + /// + /// Converts Bitmap to base64 PNG format. + /// + public static string? ToBase64Png(Bitmap? bmp) + { + using var ms = new MemoryStream(); + bmp.Save(ms, ImageFormat.Png); + var base64 = Convert.ToBase64String(ms.ToArray()); + + return base64; + } + + + + [GeneratedRegex(@"(^data\:(?image\/[a-z\+\-]*);base64,)?(?[a-zA-Z0-9\+\/\=]+)$", RegexOptions.IgnoreCase | RegexOptions.ExplicitCapture | RegexOptions.Compiled, "en-US")] + private static partial Regex Base64DataUriRegex(); + + + /// + /// Converts base64 string to byte array, returns MIME type and raw data in byte array. + /// + /// Base64 string + /// + public static (string MimeType, byte[] ByteData) ConvertBase64ToBytes(string? content) + { + if (string.IsNullOrWhiteSpace(content)) + { + throw new ArgumentNullException(nameof(content)); + } + + // data:image/svg-xml;base64,xxxxxxxx + // type is optional + var base64DataUri = Base64DataUriRegex(); + + var match = base64DataUri.Match(content); + if (!match.Success) + { + throw new FormatException("The base64 content is invalid."); + } + + + var base64Data = match.Groups["data"].Value; + var byteData = Convert.FromBase64String(base64Data); + var mimeType = match.Groups["type"].Value.ToLowerInvariant(); + + if (mimeType.Length == 0) + { + // use default PNG MIME type + mimeType = "image/png"; + } + + return (mimeType, byteData); + } + + + /// + /// Get the correct color profile name + /// + /// Name or Full path of color profile + /// + public static string GetCorrectColorProfileName(string name) + { + // current mornitor profile + var currentMonitorProfile = nameof(ColorProfileOption.CurrentMonitorProfile); + if (name.Equals(currentMonitorProfile, StringComparison.InvariantCultureIgnoreCase)) + { + return currentMonitorProfile; + } + + + // custom color profile + if (File.Exists(name)) return name; + + + // built-in color profiles + var nonBuiltInProfiles = new string[] { + nameof(ColorProfileOption.None), + nameof(ColorProfileOption.CurrentMonitorProfile), + nameof(ColorProfileOption.Custom), + }; + var builtInProfiles = Enum.GetNames(typeof(ColorProfileOption)) + .Where(i => !nonBuiltInProfiles.Contains(i)); + + var profileName = builtInProfiles.FirstOrDefault(i => string.Equals(i, name, StringComparison.InvariantCultureIgnoreCase)) ?? string.Empty; + + if (string.IsNullOrWhiteSpace(profileName)) + { + profileName = ColorProfileOption.None.ToString(); + } + + return profileName; + } + + + /// + /// Get ColorProfile + /// + /// Name or Full path of color profile + /// + public static ColorProfile? GetColorProfile(string name) + { + var currentMonitorProfile = nameof(ColorProfileOption.CurrentMonitorProfile); + + if (name.Equals(currentMonitorProfile, StringComparison.InvariantCultureIgnoreCase)) + { + var winHandle = Process.GetCurrentProcess().MainWindowHandle; + var colorProfilePath = DisplayApi.GetMonitorColorProfileFromWindow(winHandle); + + if (string.IsNullOrEmpty(colorProfilePath)) + { + return ColorProfiles.SRGB; + } + + return new ColorProfile(colorProfilePath); + } + else if (File.Exists(name)) + { + return new ColorProfile(name); + } + else + { + // get all profile names in Magick.NET + var profiles = typeof(ColorProfile).GetProperties(); + var result = Array.Find(profiles, i => string.Equals(i.Name, name, StringComparison.InvariantCultureIgnoreCase)); + + if (result != null) + { + try + { + return (ColorProfile?)result.GetValue(result); + } + catch (Exception) + { + return null; + } + } + } + + return null; + } + + + /// + /// Gets image MIME type from the input extension. + /// Returns image/png if the format is not supported. + /// + /// The extension, example: .png + public static string GetMIMEType(string? ext) + { + var mimeType = ext?.ToUpperInvariant() switch + { + ".GIF" => "image/gif", + ".BMP" => "image/bmp", + ".PNG" => "image/png", + ".WEBP" => "image/webp", + ".SVG" => "image/svg+xml", + ".JPG" or ".JPEG" or ".JFIF" or ".JP2" => "image/jpeg", + ".JXL" => "image/jxl", + ".TIF" or ".TIFF" or ".FAX" => "image/tiff", + ".ICO" or ".ICON" => "image/x-icon", + _ => "image/png", + }; + + return mimeType; + } + + + /// + /// Gets image MIME type from the input . + /// Returns if the format is not supported. + /// + /// Image format + public static string GetMIMEType(ImageFormat? format = null, string defaultValue = "image/png") + { + if (format == null) + { + return defaultValue; + } + + if (format.Equals(ImageFormat.Gif)) + { + return "image/gif"; + } + + if (format.Equals(ImageFormat.Bmp)) + { + return "image/bmp"; + } + + if (format.Equals(ImageFormat.Jpeg)) + { + return "image/jpeg"; + } + + if (format.Equals(ImageFormat.Png)) + { + return "image/png"; + } + + if (format.Equals(ImageFormat.Tiff)) + { + return "image/tiff"; + } + + if (format.Equals(ImageFormat.Icon)) + { + return "image/x-icon"; + } + + return defaultValue; + } + + + /// + /// Gets WIC container format from the input extension. + /// Default value is + /// + /// The extension, example: .png + public static Guid GetWicContainerFormatFromExtension(string ext) + { + if (ext.Equals(".gif", StringComparison.OrdinalIgnoreCase)) + { + return WicCodec.GUID_ContainerFormatGif; + } + + if (ext.Equals(".bmp", StringComparison.OrdinalIgnoreCase)) + { + return WicCodec.GUID_ContainerFormatBmp; + } + + if (ext.Equals(".jpg", StringComparison.OrdinalIgnoreCase) + || ext.Equals(".jpe", StringComparison.OrdinalIgnoreCase) + || ext.Equals(".jpeg", StringComparison.OrdinalIgnoreCase) + || ext.Equals(".jp2", StringComparison.OrdinalIgnoreCase) + || ext.Equals(".jxl", StringComparison.OrdinalIgnoreCase)) + { + return WicCodec.GUID_ContainerFormatJpeg; + } + + if (ext.Equals(".tiff", StringComparison.OrdinalIgnoreCase) + || ext.Equals(".tif", StringComparison.OrdinalIgnoreCase) + || ext.Equals(".fax", StringComparison.OrdinalIgnoreCase)) + { + return WicCodec.GUID_ContainerFormatTiff; + } + + if (ext.Equals(".ico", StringComparison.OrdinalIgnoreCase)) + { + return WicCodec.GUID_ContainerFormatIco; + } + + if (ext.Equals(".webp", StringComparison.OrdinalIgnoreCase)) + { + return WicCodec.GUID_ContainerFormatWebp; + } + + + return WicCodec.GUID_ContainerFormatPng; + } + + + /// + /// Gets from mime type. + /// + private static MagickFormat MimeTypeToMagickFormat(string? mimeType) + { + return mimeType switch + { + "image/avif" => MagickFormat.Avif, + "image/bmp" => MagickFormat.Bmp, + "image/gif" => MagickFormat.Gif, + "image/tiff" => MagickFormat.Tiff, + "image/jpeg" => MagickFormat.Jpeg, + "image/svg+xml" => MagickFormat.Rsvg, + "image/x-icon" => MagickFormat.Ico, + "image/x-portable-anymap" => MagickFormat.Pnm, + "image/x-portable-bitmap" => MagickFormat.Pbm, + "image/x-portable-graymap" => MagickFormat.Pgm, + "image/x-portable-pixmap" => MagickFormat.Ppm, + "image/x-xbitmap" => MagickFormat.Xbm, + "image/x-xpixmap" => MagickFormat.Xpm, + "image/x-cmu-raster" => MagickFormat.Ras, + _ => MagickFormat.Png + }; + } + + + /// + /// Crops the image. + /// + public static WicBitmapSource? CropImage(WicBitmapSource? img, RectangleF srcSelection) + { + if (img == null) return null; + + var width = (int)srcSelection.Width; + var height = (int)srcSelection.Height; + + if (width == 0 || height == 0) return null; + + var x = (int)srcSelection.X; + var y = (int)srcSelection.Y; + + return WicBitmapSource.FromSourceRect(img, x, y, width, height); + } + + + /// + /// Resizes image. + /// + public static async Task ResizeImageAsync(WicBitmapSource? wicSrc, + int width, int height, + ImageResamplingMethod resample = ImageResamplingMethod.Auto) + { + // convert to stream + using var inputMs = ToMemoryStream(wicSrc); + if (inputMs == null) return null; + + + // build settings + var outputMs = new MemoryStream(); // cannot use `using` here + var settings = new ProcessImageSettings() + { + Width = width, + Height = height, + ResizeMode = CropScaleMode.Stretch, + HybridMode = HybridScaleMode.Turbo, + ColorProfileMode = ColorProfileMode.Preserve, + }; + + InterpolationSettings? interpolation = resample switch + { + ImageResamplingMethod.Average => InterpolationSettings.Average, + ImageResamplingMethod.CatmullRom => InterpolationSettings.CatmullRom, + ImageResamplingMethod.Cubic => InterpolationSettings.Cubic, + ImageResamplingMethod.CubicSmoother => InterpolationSettings.CubicSmoother, + ImageResamplingMethod.Hermite => InterpolationSettings.Hermite, + ImageResamplingMethod.Lanczos => InterpolationSettings.Lanczos, + ImageResamplingMethod.Linear => InterpolationSettings.Linear, + ImageResamplingMethod.Mitchell => InterpolationSettings.Mitchell, + ImageResamplingMethod.NearestNeighbor => InterpolationSettings.NearestNeighbor, + ImageResamplingMethod.Quadratic => InterpolationSettings.Quadratic, + ImageResamplingMethod.Spline36 => InterpolationSettings.Spline36, + _ => null, + }; + + if (interpolation != null) + { + settings.Interpolation = interpolation.Value; + } + + + // perform resizing + await Task.Run(() => + { + _ = MagicImageProcessor.ProcessImage(inputMs, outputMs, settings); + outputMs.Position = 0; + }); + + + return ToWicBitmapSource(outputMs); + } + + + /// + /// Gets the embedded video stream from the motion/live image. + /// + public static async Task GetLiveVideoAsync(string path, CancellationToken? token = default) + { + // only check for jpg/jpeg + if (!path.EndsWith(".jpg", StringComparison.InvariantCultureIgnoreCase) + && !path.EndsWith(".jpeg", StringComparison.InvariantCultureIgnoreCase)) + { + return null; + } + + + var startIndex = -1; + byte[] bytes = []; + + try + { + bytes = await File.ReadAllBytesAsync(path, token ?? default); + } + catch { } + + + // find the start index of the video data + for (int i = 0; i < bytes.Length - 7; i++) + { + if (bytes[i + 4] == 0x66 + && bytes[i + 5] == 0x74 + && bytes[i + 6] == 0x79 + && bytes[i + 7] == 0x70) + { + startIndex = i; + break; + } + } + if (startIndex == -1) return null; + + // get video binary data + var videoBytes = bytes[startIndex..bytes.Length]; + + return videoBytes; + } + + + /// + /// Gets text from image using Optical character recognition (OCR). + /// + public static async Task GetTextFromImageAsync(WicBitmapSource? wicSrc) + { + using var softwareBmp = await BHelper.ToSoftwareBitmapAsync(wicSrc); + + var ocrEngine = OcrEngine.TryCreateFromUserProfileLanguages(); + var ocrResult = await ocrEngine.RecognizeAsync(softwareBmp); + + return ocrResult; + } + + + /// + /// Detects faces from the image. + /// + public static async Task> DetectFacesFromImageAsync(WicBitmapSource? wicSrc) + { + using var softwareBmp = await BHelper.ToSoftwareBitmapAsync(wicSrc); + using var bmp = FaceDetector.IsBitmapPixelFormatSupported(softwareBmp.BitmapPixelFormat) + ? softwareBmp + : SoftwareBitmap.Convert(softwareBmp, BitmapPixelFormat.Gray8); + + var fd = await Windows.Media.FaceAnalysis.FaceDetector.CreateAsync(); + + try + { + var result = await fd.DetectFacesAsync(bmp); + + return result ?? []; + } + catch { } + + return []; + } + + +} + diff --git a/Source/Components/ImageGlass.Base/BHelper/ProcessHelper.cs b/Source/Components/ImageGlass.Base/BHelper/ProcessHelper.cs new file mode 100644 index 000000000..f19d07f1d --- /dev/null +++ b/Source/Components/ImageGlass.Base/BHelper/ProcessHelper.cs @@ -0,0 +1,228 @@ +/* +ImageGlass Project - Image viewer for Windows +Copyright (C) 2010 - 2026 DUONG DIEU PHAP +Project homepage: https://imageglass.org + +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 . +*/ + +// Source: +// https://github.com/aspnet/AspNetIdentity/blob/b7826741279450c58b230ece98bd04b4815beabf/src/Microsoft.AspNet.Identity.Core/AsyncHelper.cs + +using ImageGlass.Base.QueuedWorker; +using System.Diagnostics; +using System.Globalization; +using Windows.ApplicationModel; + +namespace ImageGlass.Base; + +public partial class BHelper +{ + private static readonly TaskFactory _myTaskFactory = new( + CancellationToken.None, TaskCreationOptions.None, + TaskContinuationOptions.None, TaskScheduler.Default); + + private static DebounceDispatcher? _debouncer = null; + + + /// + /// Runs an async function synchronous. + /// Source: + /// + public static TResult RunSync(Func> func) + { + var cultureUi = CultureInfo.CurrentUICulture; + var culture = CultureInfo.CurrentCulture; + + return _myTaskFactory.StartNew(() => + { + Thread.CurrentThread.CurrentCulture = culture; + Thread.CurrentThread.CurrentUICulture = cultureUi; + return func(); + }).Unwrap().GetAwaiter().GetResult(); + } + + + /// + /// Runs an async function synchronous. + /// Source: + /// + public static void RunSync(Func func) + { + var cultureUi = CultureInfo.CurrentUICulture; + var culture = CultureInfo.CurrentCulture; + + _myTaskFactory.StartNew(() => + { + Thread.CurrentThread.CurrentCulture = culture; + Thread.CurrentThread.CurrentUICulture = cultureUi; + return func(); + }).Unwrap().GetAwaiter().GetResult(); + } + + + /// + /// Runs a function in a new thread + /// + public static Thread RunAsThread(ThreadStart func, ApartmentState thState = ApartmentState.Unknown) + { + var th = new Thread(func) + { + IsBackground = true, + }; + + th.SetApartmentState(thState); + th.Start(); + + return th; + } + + + /// + /// Runs as admin + /// + public static async Task RunExeAsync(string filename, string args, bool asAdmin = false, bool waitForExit = false, bool showError = false) + { + var proc = new Process(); + + // filename is an app protocal + if (filename.EndsWith(':')) + { + var url = $"{filename}{args}"; + proc.StartInfo.FileName = url; + } + // filename is a path + else + { + proc.StartInfo.FileName = filename; + proc.StartInfo.Arguments = args; + } + + proc.StartInfo.Verb = asAdmin ? "runas" : ""; + proc.StartInfo.UseShellExecute = true; + proc.StartInfo.ErrorDialog = showError; + + try + { + proc.Start(); + + if (waitForExit) + { + await proc.WaitForExitAsync(); + + return proc.ExitCode; + } + + return (int)IgExitCode.Done; + } + catch (Exception ex) + { + if (ex.Message.Contains("system cannot find the file", StringComparison.InvariantCultureIgnoreCase)) + { + return (int)IgExitCode.Error_FileNotFound; + } + + return (int)IgExitCode.Error; + } + } + + + /// + /// Run a command, supports auto-elevating process privilege + /// if admin permission is required. + /// + public static async Task RunExeCmd(string exePath, string args, bool waitForExit = true, bool appendIgArgs = true, bool showError = false) + { + IgExitCode code; + + try + { + if (appendIgArgs) + { + args += $" {IgCommands.HIDE_ADMIN_REQUIRED_ERROR_UI}"; + } + + code = (IgExitCode)await RunExeAsync(exePath, args, false, waitForExit, showError); + + + // If that fails due to privs error, re-attempt with admin privs. + if (code == IgExitCode.AdminRequired) + { + code = (IgExitCode)await RunExeAsync( + exePath, + args, + asAdmin: true, + waitForExit: waitForExit); + } + } + catch + { + code = IgExitCode.Error; + } + + return code; + } + + + /// + /// Checks if ImageGlass process is running as UWP app. + /// + public static bool IsRunningAsUwp() + { + try + { + return !string.IsNullOrWhiteSpace(Package.Current.Id.FullName); + } + catch { } + + return false; + } + + + /// + /// Builds correct file path for executable and app protocol. + /// + public static (string Executable, string Args) BuildExeArgs(string executable, string arguments, string currentFilePath = "") + { + var exe = executable.Trim(); + var isAppProtocol = exe.EndsWith(':'); + + // exclude the double quotes if the executable is app protocol + var filePath = isAppProtocol ? currentFilePath : $"\"{currentFilePath}\""; + + var args = arguments.Replace(Const.FILE_MACRO, filePath); + + return (Executable: exe, Args: args); + } + + + /// + /// Takes the last called action, delays the execution after a certain amount of time has passed. + /// + public static void Debounce(int delayMs, Action action) + { + Debounce(delayMs, (object? param) => action()); + } + + + /// + /// Takes the last called action, delays the execution after a certain amount of time has passed. + /// + public static void Debounce(int delayMs, Action action, T? param = default) + { + _debouncer ??= new(); + _debouncer.Debounce(delayMs, action, param); + } + +} diff --git a/Source/Components/ImageGlass.Base/BHelper/ThemeUtils.cs b/Source/Components/ImageGlass.Base/BHelper/ThemeUtils.cs new file mode 100644 index 000000000..2953d8736 --- /dev/null +++ b/Source/Components/ImageGlass.Base/BHelper/ThemeUtils.cs @@ -0,0 +1,205 @@ +/* +ImageGlass Project - Image viewer for Windows +Copyright (C) 2010 - 2026 DUONG DIEU PHAP +Project homepage: https://imageglass.org + +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 . +*/ + +using System.Drawing.Drawing2D; +using System.Drawing.Text; +using System.Globalization; + +namespace ImageGlass.Base; + +public partial class BHelper +{ + /// + /// Gets the background color for the input status. + /// + public static Color GetBackgroundColorForStatus(ColorStatusType status, bool darkMode = true, int alpha = 255) + { + var colors = GetThemeColorPalatte(darkMode); + + return status switch + { + ColorStatusType.Info => colors.BgInfo.WithAlpha(alpha), + ColorStatusType.Success => colors.BgSuccess.WithAlpha(alpha), + ColorStatusType.Warning => colors.BgWarning.WithAlpha(alpha), + ColorStatusType.Danger => colors.BgDanger.WithAlpha(alpha), + _ => colors.BgNeutral.WithAlpha(alpha), + }; + } + + + /// + /// Gets theme color palatte + /// + public static IColors GetThemeColorPalatte(bool darkMode, bool designMode = false) + { + return darkMode + ? new DarkColors(designMode) + : new LightColors(designMode); + } + + + /// + /// Creates a new from the given hex color string (with alpha). + /// Returns if is invalid. + /// + public static Color ColorFromHex(string hex, bool skipAlpha = false) + { + try + { + // Remove # if present + if (hex.StartsWith('#')) + { + hex = hex.Substring(1); + } + + var red = 0; + var green = 0; + var blue = 0; + var alpha = 255; + + if (hex.Length == 8) + { + // #RRGGBBAA + red = byte.Parse(hex.AsSpan(0, 2), NumberStyles.AllowHexSpecifier); + green = byte.Parse(hex.AsSpan(2, 2), NumberStyles.AllowHexSpecifier); + blue = byte.Parse(hex.AsSpan(4, 2), NumberStyles.AllowHexSpecifier); + alpha = byte.Parse(hex.AsSpan(6, 2), NumberStyles.AllowHexSpecifier); + } + else if (hex.Length == 6) + { + // #RRGGBB + red = byte.Parse(hex.AsSpan(0, 2), NumberStyles.AllowHexSpecifier); + green = byte.Parse(hex.AsSpan(2, 2), NumberStyles.AllowHexSpecifier); + blue = byte.Parse(hex.AsSpan(4, 2), NumberStyles.AllowHexSpecifier); + } + else if (hex.Length == 4) + { + // #RGBA + red = byte.Parse($"{hex[0]}{hex[0]}", NumberStyles.AllowHexSpecifier); + green = byte.Parse($"{hex[1]}{hex[1]}", NumberStyles.AllowHexSpecifier); + blue = byte.Parse($"{hex[2]}{hex[2]}", NumberStyles.AllowHexSpecifier); + alpha = byte.Parse($"{hex[3]}{hex[3]}", NumberStyles.AllowHexSpecifier); + } + else if (hex.Length == 3) + { + // #RGB + red = byte.Parse($"{hex[0]}{hex[0]}", NumberStyles.AllowHexSpecifier); + green = byte.Parse($"{hex[1]}{hex[1]}", NumberStyles.AllowHexSpecifier); + blue = byte.Parse($"{hex[2]}{hex[2]}", NumberStyles.AllowHexSpecifier); + } + else + { + return Color.Empty; + } + + if (skipAlpha) alpha = 255; + + return Color.FromArgb(alpha, red, green, blue); + } + catch + { + return Color.Empty; + } + } + + + /// + /// Validates if the input hex color string is a valid color. + /// + public static bool IsValidHex(string hex) + { + if (hex.StartsWith("#")) + { + return hex.Length == 9 || hex.Length == 7 || hex.Length == 5 || hex.Length == 4; + } + + return false; + } + + + /// + /// Creates image from text. + /// + public static Image CreateImageFromText(string text, Font font, Color textColor, Color? backColor = null) + { + // fix dpi scaling + var fontSize = FontPixelToPoint(font.Height); + + var path = new GraphicsPath(); + path.AddString(text, font.FontFamily, (int)font.Style, fontSize, new Point(0, 0), StringFormat.GenericTypographic); + + var pathRect = path.GetBounds(); + var br = new RectangleF(pathRect.X, pathRect.Y, pathRect.Width, pathRect.Height); + if (br.IsEmpty) + { + br.Width = 1; + br.Height = 1; + } + + var img = new Bitmap((int)Math.Ceiling(br.Width) + 1, (int)Math.Ceiling(br.Height)); + + using var textBrush = new SolidBrush(textColor); + using var g = Graphics.FromImage(img); + g.TextRenderingHint = TextRenderingHint.AntiAliasGridFit; + g.SmoothingMode = SmoothingMode.HighQuality; + g.Clear(backColor ?? Color.Transparent); + + g.TranslateTransform( + (img.Width - br.Width) / 2 - br.X, + (float)Math.Floor((img.Height - br.Height) / 2 - br.Y)); + g.FillPath(textBrush, path); + g.Save(); + + + return img; + } + + + /// + /// Converts font size in point to pixel. + /// + /// Font size in point + public static float FontPointToPixel(int pt) + { + // 16px = 12pt + return pt * 16f / 12f; + } + + + /// + /// Converts font size in pixel to point. + /// + /// Font size in pixel + public static float FontPixelToPoint(float px) + { + // 16px = 12pt + return px * 12f / 16f; + } + +} + + +public enum ColorStatusType +{ + Neutral, + Info, + Success, + Warning, + Danger, +} diff --git a/Source/Components/ImageGlass.Base/BHelper/TypeConversion.cs b/Source/Components/ImageGlass.Base/BHelper/TypeConversion.cs new file mode 100644 index 000000000..898f0fb3b --- /dev/null +++ b/Source/Components/ImageGlass.Base/BHelper/TypeConversion.cs @@ -0,0 +1,63 @@ +/* +ImageGlass Project - Image viewer for Windows +Copyright (C) 2010 - 2026 DUONG DIEU PHAP +Project homepage: https://imageglass.org + +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 . +*/ +namespace ImageGlass.Base; + +public partial class BHelper +{ + /// + /// Convert the given object to Enum type + /// + /// Enum type + /// Value + /// + public static T ParseEnum(object value) + { + return (T)Enum.Parse(typeof(T), value.ToString(), true); + } + + + /// + /// Convert the given value to specific type + /// + /// Type + /// Value + /// + /// Returns default value of the type if the + /// is not convertable or null. + /// + public static T? ConvertType(object? value, T? defaultValue = default) + { + if (value == null) return defaultValue; + var type = typeof(T); + + try + { + if (type.IsEnum) + { + return ParseEnum(value); + } + + return (T)Convert.ChangeType(value, type); + } + catch (Exception) + { + return defaultValue; + } + } +} diff --git a/Source/Components/ImageGlass.Base/BHelper/Visual.cs b/Source/Components/ImageGlass.Base/BHelper/Visual.cs new file mode 100644 index 000000000..a919d0735 --- /dev/null +++ b/Source/Components/ImageGlass.Base/BHelper/Visual.cs @@ -0,0 +1,151 @@ +/* +ImageGlass Project - Image viewer for Windows +Copyright (C) 2010 - 2026 DUONG DIEU PHAP +Project homepage: https://imageglass.org + +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 . +*/ +using System.Drawing.Drawing2D; +using System.Drawing.Text; + +namespace ImageGlass.Base; + +public static partial class BHelper +{ + + /// + /// Gets menu item border radius + /// + public static float GetItemBorderRadius(int itemHeight, int defaultItemHeight) + { + if (IsOS(WindowsOS.Win10)) + { + return 0; + } + + var radius = (itemHeight * 1.3f / defaultItemHeight * 3f); + + // min border radius = 4 + return Math.Max(radius, 4); + } + + + /// + /// Gets rounded rectangle graphic path + /// + /// Input rectangle + /// Border radius + public static GraphicsPath GetRoundRectanglePath(RectangleF bounds, float radius, bool flatBottom = false, int bottomOffset = 0, bool flatTop = false) + { + var diameter = radius * 2; + var size = new SizeF(diameter, diameter); + var arc = new RectangleF(bounds.Location, size); + var path = new GraphicsPath(); + + if (radius == 0 || flatBottom && flatTop) + { + path.AddRectangle(bounds); + return path; + } + + if (flatTop) + { + // top + PointF tr = new PointF(bounds.Right, bounds.Top); + PointF tl = new PointF(bounds.Left, bounds.Top); + path.AddLine(tl, tr); + arc.X = bounds.Right - diameter; + } + else + { + // top left arc + path.AddArc(arc, 180, 90); + + // top right arc + arc.X = bounds.Right - diameter; + path.AddArc(arc, 270, 90); + } + + if (flatBottom) + { + // bottom line + PointF br = new PointF(bounds.Right, bounds.Bottom + bottomOffset); + PointF bl = new PointF(bounds.Left, bounds.Bottom + bottomOffset); + path.AddLine(br, bl); + } + else + { + // bottom right arc + arc.Y = bounds.Bottom - diameter; + path.AddArc(arc, 0, 90); + + // bottom left arc + arc.X = bounds.Left; + path.AddArc(arc, 90, 90); + } + + path.CloseFigure(); + return path; + } + + + /// + /// Creates default toolbar icon. + /// + public static Bitmap CreateDefaultToolbarIcon(uint iconSize, bool darkMode) + { + var size = (int)iconSize; + var bmp = new Bitmap(size, size); + + var g = Graphics.FromImage(bmp); + g.SmoothingMode = SmoothingMode.HighQuality; + g.CompositingQuality = CompositingQuality.HighQuality; + g.TextRenderingHint = TextRenderingHint.AntiAlias; + + using var brush = new SolidBrush(darkMode ? Color.White.WithAlpha(100) : Color.Black.WithAlpha(100)); + + var rect = new Rectangle(0, 0, size - 1, size - 1); + g.FillEllipse(brush, rect); + + return bmp; + } + + + /// + /// Creates checkerboard tile texture brush. + /// + public static TextureBrush CreateCheckerboardTileBrush(float cellSize, Color cellColor1, Color cellColor2) + { + // draw the tile + var width = cellSize * 2; + var height = cellSize * 2; + var tileImg = new Bitmap((int)width, (int)height); + + using var g = Graphics.FromImage(tileImg); + using (Brush brush = new SolidBrush(cellColor1)) + { + g.FillRectangle(brush, new RectangleF(0, 0, cellSize, cellSize)); + g.FillRectangle(brush, new RectangleF(cellSize, cellSize, cellSize, cellSize)); + } + + using (Brush brush = new SolidBrush(cellColor2)) + { + g.FillRectangle(brush, new RectangleF(cellSize, 0, cellSize, cellSize)); + g.FillRectangle(brush, new RectangleF(0, cellSize, cellSize, cellSize)); + } + + return new TextureBrush(tileImg); + } + +} diff --git a/Source/Components/ImageGlass.Base/Cache/DiskCache.cs b/Source/Components/ImageGlass.Base/Cache/DiskCache.cs new file mode 100644 index 000000000..502b4bb9e --- /dev/null +++ b/Source/Components/ImageGlass.Base/Cache/DiskCache.cs @@ -0,0 +1,324 @@ +/* +ImageGlass Project - Image viewer for Windows +Copyright (C) 2010 - 2026 DUONG DIEU PHAP +Project homepage: https://imageglass.org + +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 . +*/ +using System.Security.Cryptography; +using System.Text; + +namespace ImageGlass.Base.Cache; + + +/// +/// Represents a collection of items on disk that can be read +/// and written by multiple threads. +/// +public class DiskCache +{ + #region Member Variables + + private string _dirName = string.Empty; + private long _cacheSize = 0; + private long _currentCacheSize = 0; + private readonly object _lockObject = new(); + + #endregion + + + #region Properties + + /// + /// Gets or sets the cache directory. + /// + public string DirectoryName + { + get + { + lock (_lockObject) + { + return _dirName; + } + } + set + { + lock (_lockObject) + { + _dirName = value; + CalculateSize(); + } + } + } + + /// + /// Gets or sets the cache size in bytes. + /// + public long CacheSize + { + get + { + lock (_lockObject) + { + return _cacheSize; + } + } + set + { + lock (_lockObject) + { + _cacheSize = value; + } + } + } + + #endregion + + + #region Constructor + + /// + /// Initializes a new instance of the class. + /// + /// The path to the cache file. + /// Cache size in bytes. + public DiskCache(string directoryName, long size) + { + _cacheSize = size; + _dirName = directoryName.Trim(); + + if (!string.IsNullOrEmpty(_dirName)) + { + if (!Directory.Exists(_dirName)) + { + Directory.CreateDirectory(_dirName); + } + + lock (_lockObject) + { + CalculateSize(); + } + } + } + + /// + /// Initializes a new instance of the class. + /// + public DiskCache() : this(string.Empty, 0) { } + + #endregion + + + #region Instance Methods + + /// + /// Reads an item from the cache. + /// + /// Item identifier. + /// A stream holding item data. + public Stream Read(string id) + { + lock (_lockObject) + { + var ms = new MemoryStream(); + if (string.IsNullOrEmpty(_dirName)) return ms; + + id = MakeKey(id); + var filename = Path.Combine(_dirName, id); + if (!File.Exists(filename)) return ms; + + using var fs = new FileStream(filename, FileMode.Open, FileAccess.Read); + var read = 0; + var buffer = new byte[4096]; + + while ((read = fs.Read(buffer, 0, 4096)) > 0) + { + ms.Write(buffer, 0, read); + } + + return ms; + } + } + + /// + /// Writes an item to the cache. + /// + /// Item identifier. If an item with this identifier already + /// exists, it will be overwritten. + /// Item data. + public void Write(string id, Stream data) + { + lock (_lockObject) + { + if (string.IsNullOrEmpty(_dirName)) return; + + id = MakeKey(id); + var filename = Path.Combine(_dirName, id); + var bytesWritten = 0L; + var read = 0; + var buffer = new byte[4096]; + + using var fs = new FileStream(filename, FileMode.Create, FileAccess.Write); + data.Seek(0, SeekOrigin.Begin); + + while ((read = data.Read(buffer, 0, 4096)) > 0) + { + fs.Write(buffer, 0, read); + bytesWritten += read; + } + + _currentCacheSize += bytesWritten; + + if (_currentCacheSize > _cacheSize) + { + PurgeCache(); + } + } + } + + /// + /// Removes an item from the cache. + /// + /// Item identifier. + public void Remove(string id) + { + lock (_lockObject) + { + if (string.IsNullOrEmpty(_dirName)) return; + + id = MakeKey(id); + + string filename = Path.Combine(_dirName, id); + if (!File.Exists(filename)) return; + + var fi = new FileInfo(filename); + _currentCacheSize -= fi.Length; + + if (_currentCacheSize < 0) _currentCacheSize = 0; + File.Delete(filename); + } + } + + /// + /// Removes all items from the cache. + /// + public void Clear() + { + lock (_lockObject) + { + if (string.IsNullOrEmpty(_dirName)) return; + + foreach (var file in Directory.GetFiles(_dirName)) + { + File.Delete(file); + } + + _currentCacheSize = 0; + } + } + + /// + /// Converts the given string to an item key. + /// + /// Input string. + /// Item key. + private static string MakeKey(string key) + { + var hash = MD5.HashData(Encoding.ASCII.GetBytes(key)); + + return Convert.ToHexString(hash).ToLowerInvariant(); + } + + /// + /// Calculates the size of the cache. + /// + private void CalculateSize() + { + lock (_lockObject) + { + _currentCacheSize = 0; + + if (string.IsNullOrEmpty(_dirName)) return; + + Directory.CreateDirectory(_dirName); + + foreach (FileInfo file in new DirectoryInfo(_dirName).GetFiles()) + { + _currentCacheSize += file.Length; + } + } + } + + /// + /// Removes old items from the cache. + /// + private void PurgeCache() + { + lock (_lockObject) + { + if (string.IsNullOrEmpty(_dirName)) return; + if (_cacheSize == 0) return; + if (_currentCacheSize <= _cacheSize) return; + + var files = new DirectoryInfo(_dirName).GetFiles(); + if (files.Length == 0) return; + + // sort creation time ascending + Array.Sort(files, (f1, f2) => + { + var d1 = f1.CreationTime; + var d2 = f2.CreationTime; + return (d1 < d2 ? -1 : (d2 > d1 ? 1 : 0)); + }); + + // Reduce the cache to 50% of its maximum size. This way we prevent excessive + // purge operations when new items are subsequently added to the cache. + var maxPurgedSize = _cacheSize / 2; + + foreach (var f in files) + { + if (!f.Exists) continue; + + var length = f.Length; + + if (TryDeleteFile(f)) + { + _currentCacheSize -= length; + if (_currentCacheSize <= maxPurgedSize) break; + } + } + + if (_currentCacheSize < 0) _currentCacheSize = 0; + } + } + + private bool TryDeleteFile(FileInfo fi) + { + try + { + fi.Delete(); + return true; + } + catch + { + // perhaps no access or IO exception + } + + return false; + } + + #endregion + +} + diff --git a/Source/Components/ImageGlass.Base/Cache/StringCache.cs b/Source/Components/ImageGlass.Base/Cache/StringCache.cs new file mode 100644 index 000000000..5005b55b2 --- /dev/null +++ b/Source/Components/ImageGlass.Base/Cache/StringCache.cs @@ -0,0 +1,116 @@ +/* +ImageGlass Project - Image viewer for Windows +Copyright (C) 2010 - 2026 DUONG DIEU PHAP +Project homepage: https://imageglass.org + +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 . + +Author: Kevin Routley (aka fire-eggs) +*/ + +using System.Collections.Concurrent; + +namespace ImageGlass.Base.Cache; + + +/// +/// A string cache. +/// +public class StringCache +{ + /// + /// A comparator is necessary because just using vanilla char[] will result in + /// a different hash for each *instance*. This comparator works on the contents. + /// + private class TagComparer : IEqualityComparer + { + public bool Equals(char[]? x, char[]? y) + { + if (x == null && y == null) return true; + if (x == null || y == null) return false; + if (x.Length != y.Length) return false; + + for (int i = 0; i < x.Length; i++) + { + if (x[i] != y[i]) return false; + } + + return true; + } + + public int GetHashCode(char[] obj) + { + if (obj.Length == 0) return 0; + + var hashCode = 0; + for (var i = 0; i < obj.Length; i++) + { + var bytes = BitConverter.GetBytes(obj[i]); + + // Rotate by 3 bits and XOR the new value. + for (var j = 0; j < bytes.Length; j++) + { + hashCode = (hashCode << 3) | (hashCode >> (29)) ^ bytes[j]; + } + } + + return hashCode; + } + } + + /// + /// Concurrent dictionary used for parallelism + /// + private readonly ConcurrentDictionary _stringCache; + + /// + /// Create a basic string cache. + /// + public StringCache() + { + _stringCache = new(new TagComparer()); + } + + /// + /// Fetch or add a string from the cache. + /// + /// Input string to be cached. + /// The string from the cache. + public string GetFromCache(string str) + { + return GetFromCache(str.ToCharArray()); + } + + /// + /// Fetch or add a string from the cache. + /// + /// Input string to be cached. + /// + private string GetFromCache(char[] str) + { + if (!_stringCache.TryGetValue(str, out var result)) + { + result = new string(str); + + try + { + _ = _stringCache.TryAdd(str, result); + } + catch { } + } + + return result; + } +} + diff --git a/Source/Components/ImageGlass.Base/Colors/DarkColors.cs b/Source/Components/ImageGlass.Base/Colors/DarkColors.cs new file mode 100644 index 000000000..8af63e934 --- /dev/null +++ b/Source/Components/ImageGlass.Base/Colors/DarkColors.cs @@ -0,0 +1,62 @@ +/* +ImageGlass Project - Image viewer for Windows +Copyright (C) 2010 - 2026 DUONG DIEU PHAP +Project homepage: https://imageglass.org + +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 . + +--------------------- +DarkColors is based on DarkUI +Url: https://github.com/RobinPerris/DarkUI +License: MIT, https://github.com/RobinPerris/DarkUI/blob/master/LICENSE +--------------------- +*/ + +using ImageGlass.Base.WinApi; + +namespace ImageGlass.Base; + + +public class DarkColors(bool designMode = false) : IColors +{ + private bool _designMode = designMode; + + + public Color AppBg => Color.FromArgb(20, 25, 28); + public Color AppText => Color.FromArgb(210, 210, 210); // Normal Text + public Color AppTextDisabled => Color.FromArgb(140, 140, 140); // Disabled Text + public Color Accent => _designMode ? Color.FromArgb(0, 120, 212) : WinColorsApi.GetAccentColor(true); + + + public Color ControlBg => Color.FromArgb(69, 73, 74); // Control Color + public Color ControlBgHover => Color.FromArgb(95, 101, 102); // Control Hover + public Color ControlBgPressed => Color.FromArgb(43, 43, 43); // Control Clicked + public Color ControlBgPressed2 => Color.FromArgb(49, 51, 53); // Control Clicked 2 + public Color ControlBgDisabled => Color.FromArgb(82, 82, 82); + public Color ControlBgAccent => ControlBg.Blend(Accent, 0.8f); + public Color ControlBgAccentHover => ControlBgHover.Blend(Accent, 0.7f); + + + public Color ControlBorder => Color.FromArgb(92, 92, 92); // Control Border + public Color ControlBorderAccent => Accent.WithBrightness(0.2f); // Accent Border + + + // status background color + public Color BgNeutral => Color.FromArgb(32, 38, 43); + public Color BgInfo => Color.FromArgb(20, 44, 59); + public Color BgSuccess => Color.FromArgb(34, 59, 42); + public Color BgWarning => Color.FromArgb(59, 40, 10); + public Color BgDanger => Color.FromArgb(59, 20, 19); + +} diff --git a/Source/Components/ImageGlass.Base/Colors/IColors.cs b/Source/Components/ImageGlass.Base/Colors/IColors.cs new file mode 100644 index 000000000..ecb7b0585 --- /dev/null +++ b/Source/Components/ImageGlass.Base/Colors/IColors.cs @@ -0,0 +1,48 @@ +/* +ImageGlass Project - Image viewer for Windows +Copyright (C) 2010 - 2026 DUONG DIEU PHAP +Project homepage: https://imageglass.org + +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 . +*/ + +namespace ImageGlass.Base; + +public interface IColors +{ + Color AppBg { get; } + Color AppText { get; } + Color AppTextDisabled { get; } + Color Accent { get; } + + + Color ControlBg { get; } + Color ControlBgHover { get; } + Color ControlBgPressed { get; } + Color ControlBgPressed2 { get; } + Color ControlBgDisabled { get; } + Color ControlBgAccent { get; } + Color ControlBgAccentHover { get; } + + + Color ControlBorder { get; } + Color ControlBorderAccent { get; } + + + Color BgNeutral { get; } + Color BgInfo { get; } + Color BgSuccess { get; } + Color BgWarning { get; } + Color BgDanger { get; } +} diff --git a/Source/Components/ImageGlass.Base/Colors/LightColors.cs b/Source/Components/ImageGlass.Base/Colors/LightColors.cs new file mode 100644 index 000000000..cc26fc2e8 --- /dev/null +++ b/Source/Components/ImageGlass.Base/Colors/LightColors.cs @@ -0,0 +1,60 @@ +/* +ImageGlass Project - Image viewer for Windows +Copyright (C) 2010 - 2026 DUONG DIEU PHAP +Project homepage: https://imageglass.org + +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 . + +--------------------- +DarkColors is based on DarkUI +Url: https://github.com/RobinPerris/DarkUI +License: MIT, https://github.com/RobinPerris/DarkUI/blob/master/LICENSE +--------------------- +*/ + +using ImageGlass.Base.WinApi; + +namespace ImageGlass.Base; + +public class LightColors(bool designMode = false) : IColors +{ + private bool _designMode = designMode; + + public Color AppBg => Color.White; + public Color AppText => Color.FromArgb(30, 30, 30); // Normal Text + public Color AppTextDisabled => Color.FromArgb(113, 113, 113); // Disabled Text + public Color Accent => _designMode ? Color.FromArgb(0, 120, 212) : WinColorsApi.GetAccentColor(true); + + + public Color ControlBg => Color.FromArgb(245, 245, 250); // Control Color + public Color ControlBgHover => Color.FromArgb(235, 235, 240); // Control Hover + public Color ControlBgPressed => Color.FromArgb(220, 220, 220); // Control Clicked + public Color ControlBgPressed2 => Color.FromArgb(230, 231, 234); // Control Clicked 2 + public Color ControlBgDisabled => Color.FromArgb(202, 202, 202); + public Color ControlBgAccent => ControlBg.Blend(Accent, 0.92f); + public Color ControlBgAccentHover => ControlBgHover.Blend(Accent, 0.88f); + + + public Color ControlBorder => Color.FromArgb(204, 206, 219); // Control Border + public Color ControlBorderAccent => Accent.WithBrightness(0.2f); // Accent Border + + + // status background color + public Color BgNeutral => Color.FromArgb(242, 242, 242); + public Color BgInfo => Color.FromArgb(199, 238, 255); + public Color BgSuccess => Color.FromArgb(219, 255, 242); + public Color BgWarning => Color.FromArgb(255, 239, 219); + public Color BgDanger => Color.FromArgb(255, 222, 222); + +} diff --git a/Source/Components/ImageGlass.Base/EditApps/AfterEditAppAction.cs b/Source/Components/ImageGlass.Base/EditApps/AfterEditAppAction.cs new file mode 100644 index 000000000..ac6fb7b0d --- /dev/null +++ b/Source/Components/ImageGlass.Base/EditApps/AfterEditAppAction.cs @@ -0,0 +1,32 @@ +/* +ImageGlass Project - Image viewer for Windows +Copyright (C) 2010 - 2026 DUONG DIEU PHAP +Project homepage: https://imageglass.org + +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 . +*/ + +namespace ImageGlass.Base; + + +/// +/// Actions after opening editing app +/// +public enum AfterEditAppAction +{ + Nothing = 0, + Minimize = 1, + Close = 2, +} + diff --git a/Source/Components/ImageGlass.Base/EditApps/EditApp.cs b/Source/Components/ImageGlass.Base/EditApps/EditApp.cs new file mode 100644 index 000000000..e1dee8905 --- /dev/null +++ b/Source/Components/ImageGlass.Base/EditApps/EditApp.cs @@ -0,0 +1,47 @@ +/* +ImageGlass Project - Image viewer for Windows +Copyright (C) 2010 - 2026 DUONG DIEU PHAP +Project homepage: https://imageglass.org + +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 . +*/ + +namespace ImageGlass.Base; + +/// +/// Contains app information for editing the viewing image. +/// +/// Friendly app name. +/// Executable command. Ex: C:\app\app.exe +/// Argument to pass to the . Ex: --help +public class EditApp(string appName = "", string executable = "", string argument = "") +{ + /// + /// Gets, sets friendly app name. + /// + public string AppName { get; set; } = appName; + + + /// + /// Gets, sets full path of app. + /// + public string Executable { get; set; } = executable; + + + /// + /// Gets, sets argument of app. + /// + public string Argument { get; set; } = argument; + +} diff --git a/Source/Components/ImageGlass.Base/FileSystem/FileFinder.cs b/Source/Components/ImageGlass.Base/FileSystem/FileFinder.cs new file mode 100644 index 000000000..0beaf6cae --- /dev/null +++ b/Source/Components/ImageGlass.Base/FileSystem/FileFinder.cs @@ -0,0 +1,319 @@ +/* +ImageGlass Project - Image viewer for Windows +Copyright (C) 2010 - 2026 DUONG DIEU PHAP +Project homepage: https://imageglass.org + +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 . +*/ +using D2Phap; +using System.Runtime.InteropServices; + +namespace ImageGlass.Base.FileSystem; + + +public class FileFinder +{ + /// + /// Occurs when the host is being panned. + /// + public event EventHandler? FilesEnumerated; + + + /// + /// Gets or sets a value indicating whether to use the Explorer sort order. + /// + public bool UseExplorerSortOrder { get; set; } = true; + + + /// + /// Starts finding files. + /// + /// If is not null, + /// it will get files from the foreground window, + /// otherwise from the given directories . + /// + /// Use the event to get results. + /// + /// The Shell object + /// List of directories to search for files + /// Option to search in sub-directories + /// Option to include the hidden files + /// Function to apply path filter + /// Function to apply path sorting when Explorer file order is not detected + /// 🔴 NOTE: Must run on UI thread. + public void StartFindingFiles( + ExplorerView? foregroundShell, + IEnumerable dirs, + bool searchSubDirectories, + bool includeHidden, + Predicate? filterFn = null, + Func, IEnumerable>? nonShellSortFn = null) + { + // 1. get files from the foreground window + if (foregroundShell != null && UseExplorerSortOrder) + { + try + { + StartFindingFiles(foregroundShell, searchSubDirectories, includeHidden, filterFn, nonShellSortFn); + + return; + } + catch (COMException) { } + } + + + // 2. get files from the given directories + StartFindingFiles(dirs, searchSubDirectories, includeHidden, filterFn, nonShellSortFn); + } + + + // Private Methods + #region Private Methods + + /// + /// Finds files in the given directories. + /// + /// 🔴 NOTE: Must run on UI thread. + private void StartFindingFiles( + IEnumerable dirs, + bool searchSubDirectories, + bool includeHidden, + Predicate? filterFn = null, + Func, IEnumerable>? nonShellSortFn = null) + { + // get files from the given directories + foreach (var dirPath in dirs) + { + var folderShellView = UseExplorerSortOrder + ? GetShellFolderView(dirPath, null).View + : null; + + // with shell + if (folderShellView != null) + { + StartFindingFiles_WithShell(folderShellView, + dirPath, + searchSubDirectories, + includeHidden, + filterFn, + nonShellSortFn); + + // dispose shell object + folderShellView.Dispose(); + } + + // without shell + else + { + StartFindingFiles_WithDotNet(dirPath, searchSubDirectories, includeHidden, filterFn, nonShellSortFn); + } + } + } + + + /// + /// Finds files from the given foreground shell object. + /// + /// 🔴 NOTE: Must run on UI thread. + /// + private void StartFindingFiles( + ExplorerView? foregroundShell, + bool searchSubDirectories, + bool includeHidden, + Predicate? filterFn = null, + Func, IEnumerable>? nonShellSortFn = null) + { + if (foregroundShell == null) return; + + var folderShell = GetShellFolderView(null, foregroundShell); + + StartFindingFiles_WithShell(folderShell.View, + folderShell.DirPath, + searchSubDirectories, + includeHidden, + filterFn, + nonShellSortFn); + } + + + /// + /// Finds files in the given . + /// Use the event to get results. + /// + /// 🔴 NOTE: Must run on UI thread. + private void StartFindingFiles_WithShell(ExplorerFolderView? fv, + string? rootDir, + bool searchSubDirectories, + bool includeHidden, + Predicate? filterFn = null, + Func, IEnumerable>? nonShellSortFn = null) + { + // no folder view + if (fv is null) + { + if (!string.IsNullOrWhiteSpace(rootDir)) + { + StartFindingFiles_WithDotNet(rootDir, searchSubDirectories, includeHidden, filterFn, nonShellSortFn); + } + return; + } + + + // has folder view + var filePaths = fv.GetItems(FolderItemViewOptions.SVGIO_FLAG_VIEWORDER) + .Where(path => + { + // ignore special folders + if (path.StartsWith(EggShell.SPECIAL_DIR_PREFIX, StringComparison.InvariantCultureIgnoreCase)) return false; + + try + { + // get path attributes + var attrs = File.GetAttributes(path); + + // path is dir + if (attrs.HasFlag(FileAttributes.Directory)) return false; + + // path is hidden + if (!includeHidden && attrs.HasFlag(FileAttributes.Hidden)) return false; + } + catch + { + return false; + } + + // custom filter + if (filterFn != null) return filterFn(path); + + return true; + }); + + + // emits results + FilesEnumerated?.Invoke(this, new FilesEnumeratedEventArgs(filePaths)); + + + // search all sub-directories if root dir is not empty + if (searchSubDirectories && !string.IsNullOrWhiteSpace(rootDir)) + { + // search files for the sub dirs + // get sub folders + var subDirList = Directory.EnumerateDirectories(rootDir, "*", new EnumerationOptions() + { + IgnoreInaccessible = true, + AttributesToSkip = includeHidden + ? FileAttributes.System + : FileAttributes.System | FileAttributes.Hidden, + RecurseSubdirectories = false, + }); + + // find files in sub folders + StartFindingFiles(subDirList, searchSubDirectories, includeHidden, filterFn, nonShellSortFn); + } + } + + + /// + /// Gets the from the given dir path. + /// + /// 🔴 NOTE: Must run on UI thread. + /// + private static (ExplorerFolderView? View, string DirPath) GetShellFolderView(string? rootDir, ExplorerView? foregroundShell) + { + var folderPath = ""; + ExplorerFolderView? folderView = null; + using var shell = new EggShell(); + + + // if no dir path, get the explorer's folder view where the application opened from + if (string.IsNullOrWhiteSpace(rootDir)) + { + if (foregroundShell?.GetTabFolderView() is ExplorerFolderView fv) + { + folderPath = foregroundShell.GetTabViewPath(); + folderView = fv; + } + } + else if (!Path.EndsInDirectorySeparator(rootDir)) + { + rootDir += Path.DirectorySeparatorChar; + } + + + rootDir ??= ""; + + // find the folder view from the opening explorer windows + if (folderView == null) + { + // find the explorer's folder view for each directory + shell.WithOpeningWindows(ev => + { + var windowPath = ev.GetTabViewPath(); + if (!Path.EndsInDirectorySeparator(windowPath)) + { + windowPath += Path.DirectorySeparatorChar; + } + + // get the folder view for the input dir + if (rootDir.Equals(windowPath, StringComparison.InvariantCultureIgnoreCase) + && ev.GetTabFolderView() is ExplorerFolderView fv) + { + folderPath = windowPath; + folderView = fv; + return true; + } + + return false; + }, true); + } + + + return (folderView, folderPath); + } + + + /// + /// Finds files in the given directory with .NET support. + /// Use the event to get results. + /// + private void StartFindingFiles_WithDotNet(string rootDir, + bool searchSubDirectories, + bool includeHidden, + Predicate? filterFn = null, + Func, IEnumerable>? sortFn = null) + { + // check attributes to skip + var skipAttrs = FileAttributes.System; + if (!includeHidden) skipAttrs |= FileAttributes.Hidden; + + var filePaths = Directory.EnumerateFiles(rootDir, "*", new EnumerationOptions() + { + IgnoreInaccessible = true, + AttributesToSkip = skipAttrs, + RecurseSubdirectories = searchSubDirectories, + }).Where(path => filterFn == null || filterFn(path)); + + + // sort list + if (sortFn != null) filePaths = sortFn(filePaths); + + + // emits results + FilesEnumerated?.Invoke(this, new FilesEnumeratedEventArgs(filePaths)); + } + + + #endregion // Private Methods + +} diff --git a/Source/Components/ImageGlass.Base/FileSystem/FilesEnumeratedEventArgs.cs b/Source/Components/ImageGlass.Base/FileSystem/FilesEnumeratedEventArgs.cs new file mode 100644 index 000000000..b5b1d6832 --- /dev/null +++ b/Source/Components/ImageGlass.Base/FileSystem/FilesEnumeratedEventArgs.cs @@ -0,0 +1,39 @@ +/* +ImageGlass Project - Image viewer for Windows +Copyright (C) 2010 - 2026 DUONG DIEU PHAP +Project homepage: https://imageglass.org + +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 . +*/ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace ImageGlass.Base.FileSystem; + + +/// +/// Event arguments for the event. +/// +public class FilesEnumeratedEventArgs(IEnumerable filePaths) : EventArgs +{ + /// + /// Gets the file paths that have been enumerated. + /// + public IEnumerable FilePaths { get; } = filePaths; + +} diff --git a/Source/Components/ImageGlass.Base/FileSystem/StringNaturalComparer.cs b/Source/Components/ImageGlass.Base/FileSystem/StringNaturalComparer.cs new file mode 100644 index 000000000..ed200f2e8 --- /dev/null +++ b/Source/Components/ImageGlass.Base/FileSystem/StringNaturalComparer.cs @@ -0,0 +1,47 @@ +/* +ImageGlass Project - Image viewer for Windows +Copyright (C) 2010 - 2026 DUONG DIEU PHAP +Project homepage: https://imageglass.org + +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 . +*/ +using Windows.Win32; + +namespace ImageGlass.Base.FileSystem; + + +public class StringNaturalComparer(bool orderByAsc = true, bool ignoreCase = false) : IComparer +{ + public bool OrderByAsc { get; set; } = orderByAsc; + public bool IgnoreCase { get; set; } = ignoreCase; + + public int Compare(string? str1, string? str2) + { + str1 ??= ""; + str2 ??= ""; + + if (IgnoreCase) + { + str1 = str1.ToLowerInvariant(); + str2 = str2.ToLowerInvariant(); + } + + if (OrderByAsc) + { + return PInvoke.StrCmpLogical(str1, str2); + } + + return PInvoke.StrCmpLogical(str2, str1); + } +} diff --git a/Source/Components/ImageGlass.Base/Helpers.cs b/Source/Components/ImageGlass.Base/Helpers.cs deleted file mode 100644 index 77501b8fd..000000000 --- a/Source/Components/ImageGlass.Base/Helpers.cs +++ /dev/null @@ -1,150 +0,0 @@ -/* -ImageGlass Project - Image viewer for Windows -Copyright (C) 2020 DUONG DIEU PHAP -Project homepage: https://imageglass.org - -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 . -*/ - -using System; -using System.Collections.Generic; -using System.Drawing; -using System.IO; -using System.Linq; - -namespace ImageGlass.Base -{ - /// - /// The helper functions used globaly - /// - public static class Helpers - { - /// - /// Check if the given path (file or directory) is writable. - /// Note**: This function does not handle the directory name that contains '.' - /// E.g. C:\dir\new.dir will be treated as a File! - /// - /// Full path of file or directory - /// - public static bool CheckPathWritable(string path) - { - try - { - // If path is file - if (Path.HasExtension(path)) - { - using (File.OpenWrite(path)) { } - } - // if path is directory - else - { - var isDirExist = Directory.Exists(path); - - if (!isDirExist) - { - Directory.CreateDirectory(path); - } - - - var sampleFile = Path.Combine(path, "test_write_file.temp"); - - using (File.Create(sampleFile)) { } - File.Delete(sampleFile); - - if (!isDirExist) - { - Directory.Delete(path, true); - } - } - - return true; - } - catch (Exception ex) - { - return false; - } - } - - - /// - /// Convert string to int array - /// - /// Input string. E.g. "12, -40, 50" - /// - public static int[] StringToIntArray(string str, bool unsignedOnly = false, bool distinct = false) - { - var args = str.Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries); - var numbers = new List(); - - foreach (var item in args) - { - var num = int.Parse(item, Constants.NumberFormat); - if (unsignedOnly && num < 0) - { - continue; - } - - numbers.Add(num); - } - - if (distinct) - { - numbers = numbers.Distinct().ToList(); - } - - return numbers.ToArray(); - } - - - /// - /// Convert int array to string - /// - /// Input int array - /// - public static string IntArrayToString(int[] array) - { - return string.Join(";", array); - } - - - /// - /// Convert string to Rectangle - /// - /// Input string. E.g. "12, 40, 50" - /// - public static Rectangle StringToRect(string str) - { - var args = StringToIntArray(str); - - if (args.Count() == 4) - { - return new Rectangle(args[0], args[1], args[2], args[3]); - } - - return new Rectangle(); - } - - - /// - /// Convert Rectangle to String - /// - /// - /// - public static string RectToString(Rectangle rc) - { - return rc.Left + ";" + rc.Top + ";" + rc.Width + ";" + rc.Height; - } - - } -} diff --git a/Source/Components/ImageGlass.Base/IgTool.cs b/Source/Components/ImageGlass.Base/IgTool.cs new file mode 100644 index 000000000..1473722ab --- /dev/null +++ b/Source/Components/ImageGlass.Base/IgTool.cs @@ -0,0 +1,109 @@ +/* +ImageGlass Project - Image viewer for Windows +Copyright (C) 2010 - 2026 DUONG DIEU PHAP +Project homepage: https://imageglass.org + +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 . +*/ +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace ImageGlass.Base; + +public class IgTool +{ + /// + /// Id of the tool. + /// + public string ToolId { get; set; } = string.Empty; + + + /// + /// Name of the tool. + /// + public string ToolName { get; set; } = string.Empty; + + + /// + /// Executable file / command to launch the tool. + /// + public string Executable { get; set; } = string.Empty; + + + /// + /// Argument to pass to the . + /// + public string? Argument { get; set; } = string.Empty; + + + /// + /// Gets, sets value indicates that the tool is integrated with ImageGlass.Tools. + /// + public bool? IsIntegrated { get; set; } = false; + + + /// + /// Gets, sets tool hotkeys. + /// + [JsonConverter(typeof(HotkeyListJsonConverter))] + public List Hotkeys { get; set; } = []; + + + /// + /// Checks if the current instance is empty. + /// + public bool IsEmpty => string.IsNullOrEmpty(ToolId) || string.IsNullOrEmpty(Executable); + +} + + +/// +/// Converts to and vice versa. +/// +public class HotkeyListJsonConverter : JsonConverter> +{ + public override List? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + if (reader.TokenType != JsonTokenType.StartArray) return null; + + reader.Read(); + + var elements = new Stack(); + while (reader.TokenType != JsonTokenType.EndArray) + { + elements.Push(JsonSerializer.Deserialize(ref reader, options)!); + reader.Read(); + } + + return elements.Distinct(StringComparer.OrdinalIgnoreCase) + .Select(i => new Hotkey(i)) + .ToList(); + } + + + public override void Write(Utf8JsonWriter writer, List value, JsonSerializerOptions options) + { + writer.WriteStartArray(); + + var reversed = new Stack(value); + + foreach (var item in reversed) + { + JsonSerializer.Serialize(writer, item.ToString(), options); + } + + writer.WriteEndArray(); + } +} + diff --git a/Source/Components/ImageGlass.Base/ImageGlass.Base.csproj b/Source/Components/ImageGlass.Base/ImageGlass.Base.csproj index ccc3f2513..f9d82d19a 100644 --- a/Source/Components/ImageGlass.Base/ImageGlass.Base.csproj +++ b/Source/Components/ImageGlass.Base/ImageGlass.Base.csproj @@ -1,96 +1,110 @@ - - - - - Debug - AnyCPU - {6CC96A70-6773-41B5-9FCA-4F0AB6FAD8CA} - Library - Properties - ImageGlass.Base - ImageGlass.Base - v4.7.1 - 512 - true - - - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - - - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - - - true - bin\x86\Debug\ - DEBUG;TRACE - full - x86 - 7.3 - prompt - MinimumRecommendedRules.ruleset - - - bin\x86\Release\ - TRACE - true - pdbonly - x86 - 7.3 - prompt - MinimumRecommendedRules.ruleset - - - true - bin\x64\Debug\ - DEBUG;TRACE - full - x64 - 7.3 - prompt - MinimumRecommendedRules.ruleset - - - bin\x64\Release\ - TRACE - true - pdbonly - x64 - 7.3 - prompt - MinimumRecommendedRules.ruleset - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file + + + + net10.0-windows10.0.17763.0 + enable + true + enable + true + x64;ARM64 + 9.4.1.11 + $(Version) + Copyright © 2010 - 2026 Duong Dieu Phap + Debug;Release;Publish_Release + + latest + true + en + + + + embedded + + + + embedded + + + + embedded + + + + embedded + + + + embedded + + + + embedded + + + + embedded + + + + embedded + + + + embedded + + + + embedded + + + + embedded + + + + embedded + + + + + tlbimp + 0 + 1 + f935dc20-1cf0-11d0-adb9-00c04fd58a0b + 0 + false + true + + + + + + Component + + + + + + + + + + + + + + + all + + + + + + + + + + + + + diff --git a/Source/Components/ImageGlass.Base/ImageInfo/ImageInfo.cs b/Source/Components/ImageGlass.Base/ImageInfo/ImageInfo.cs new file mode 100644 index 000000000..20b4f3fe4 --- /dev/null +++ b/Source/Components/ImageGlass.Base/ImageInfo/ImageInfo.cs @@ -0,0 +1,112 @@ +/* +ImageGlass Project - Image viewer for Windows +Copyright (C) 2010 - 2026 DUONG DIEU PHAP +Project homepage: https://imageglass.org + +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 . +*/ +using Cysharp.Text; +using System.Text; + +namespace ImageGlass.Base; + +public static class ImageInfo +{ + public static string? AppName { get; set; } = null; + public static string? Name { get; set; } = null; + public static string? Path { get; set; } = null; + public static string? FileSize { get; set; } = null; + public static string? Dimension { get; set; } = null; + public static string? FrameCount { get; set; } = null; + public static string? ListCount { get; set; } = null; + public static string? Zoom { get; set; } = null; + public static string? ModifiedDateTime { get; set; } = null; + + public static string? ExifRating { get; set; } = null; + public static string? ExifDateTime { get; set; } = null; + public static string? ExifDateTimeOriginal { get; set; } = null; + + public static string? DateTimeAuto { get; set; } = null; + public static string? ColorSpace { get; set; } = null; + + + public static bool IsNull => AppName == null + && Name == null + && Path == null + && FileSize == null + && Dimension == null + && FrameCount == null + && ListCount == null + && Zoom == null + + && DateTimeAuto == null + && ModifiedDateTime == null + && ExifDateTime == null + && ExifDateTimeOriginal == null + + && ExifRating == null + && ColorSpace == null; + + + /// + /// Gets complete information string in order + /// + public static string ToString(List infoTags, bool isVirtualImage, string clipboardImageText = "") + { + using var strBuilder = ZString.CreateStringBuilder(); + int count = 0; + + // remove unsupported tags for virtual image + if (isVirtualImage) + { + ListCount = + Name = + Path = + FileSize = + FrameCount = + ModifiedDateTime = + ExifRating = + ExifDateTime = + ExifDateTimeOriginal = + DateTimeAuto = + ColorSpace = null; + + if (!string.IsNullOrEmpty(clipboardImageText)) + { + strBuilder.Append(clipboardImageText); + count++; + } + } + + foreach (var tag in infoTags) + { + // get the property using name + var str = typeof(ImageInfo).GetProperty(tag)?.GetValue(null)?.ToString(); + + if (!string.IsNullOrEmpty(str)) + { + if (count > 0) + { + strBuilder.Append(" ︱ "); + } + + strBuilder.Append(str); + count++; + } + } + + return strBuilder.ToString(); + } + +} diff --git a/Source/Components/ImageGlass.Base/ImageInfo/ImageInfoUpdateTypes.cs b/Source/Components/ImageGlass.Base/ImageInfo/ImageInfoUpdateTypes.cs new file mode 100644 index 000000000..35e246419 --- /dev/null +++ b/Source/Components/ImageGlass.Base/ImageInfo/ImageInfoUpdateTypes.cs @@ -0,0 +1,44 @@ +/* +ImageGlass Project - Image viewer for Windows +Copyright (C) 2010 - 2026 DUONG DIEU PHAP +Project homepage: https://imageglass.org + +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 . +*/ + +namespace ImageGlass.Base; + +/// +/// Types of image infomation update request +/// +[Flags] +public enum ImageInfoUpdateTypes +{ + AppName = 1 << 1, + Name = 1 << 2, + Path = 1 << 3, + FileSize = 1 << 4, + Dimension = 1 << 5, + ListCount = 1 << 6, + Zoom = 1 << 7, + FrameCount = 1 << 8, + + DateTimeAuto = 1 << 9, + ModifiedDateTime = 1 << 10, + ExifDateTime = 1 << 11, + ExifDateTimeOriginal = 1 << 12, + + ExifRating = 1 << 13, + ColorSpace = 1 << 14, +} diff --git a/Source/Components/ImageGlass.Services/InstanceManagement/ArgumentsReceivedEventArgs.cs b/Source/Components/ImageGlass.Base/InstanceManagement/ArgsReceivedEventArgs.cs similarity index 65% rename from Source/Components/ImageGlass.Services/InstanceManagement/ArgumentsReceivedEventArgs.cs rename to Source/Components/ImageGlass.Base/InstanceManagement/ArgsReceivedEventArgs.cs index 1bdae1557..4ec8bd82b 100644 --- a/Source/Components/ImageGlass.Services/InstanceManagement/ArgumentsReceivedEventArgs.cs +++ b/Source/Components/ImageGlass.Base/InstanceManagement/ArgsReceivedEventArgs.cs @@ -1,7 +1,7 @@ /* ImageGlass Project - Image viewer for Windows -Copyright (C) 2020 DUONG DIEU PHAP -Project homepage: http://imageglass.org +Copyright (C) 2010 - 2026 DUONG DIEU PHAP +Project homepage: https://imageglass.org 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 @@ -17,15 +17,13 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -using System; -namespace ImageGlass.Services.InstanceManagement +namespace ImageGlass.Base.InstanceManagement; + +/// +/// Holds a list of arguments given to an application at startup. +/// +public class ArgsReceivedEventArgs : EventArgs { - /// - /// Holds a list of arguments given to an application at startup. - /// - public class ArgumentsReceivedEventArgs : EventArgs - { - public String[] Args { get; set; } - } + public string[] Arguments { get; set; } = []; } diff --git a/Source/Components/ImageGlass.Base/InstanceManagement/SingleInstance.cs b/Source/Components/ImageGlass.Base/InstanceManagement/SingleInstance.cs new file mode 100644 index 000000000..d98e015ab --- /dev/null +++ b/Source/Components/ImageGlass.Base/InstanceManagement/SingleInstance.cs @@ -0,0 +1,186 @@ +/* +ImageGlass Project - Image viewer for Windows +Copyright (C) 2010 - 2026 DUONG DIEU PHAP +Project homepage: https://imageglass.org + +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 . +*/ + +using System.IO.Pipes; + +namespace ImageGlass.Base.InstanceManagement; + +/// +/// Enforces single instance for an application. +/// +public class SingleInstance : IDisposable +{ + + #region IDisposable + private bool disposed; + + protected virtual void Dispose(bool disposing) + { + if (!disposed) + { + if (_mutex != null && _ownsMutex) + { + _mutex.ReleaseMutex(); + _mutex = null; + } + disposed = true; + } + } + + ~SingleInstance() => Dispose(false); + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + #endregion + + + private Mutex? _mutex; + private readonly bool _ownsMutex; + private readonly string _id = string.Empty; + + + /// + /// Indicates whether this is the first instance of this application. + /// + public bool IsFirstInstance => _ownsMutex; + + + /// + /// Event raised when arguments are received from successive instances. + /// + public event EventHandler? ArgsReceived; + + + /// + /// Enforces single instance for an application. + /// + /// An identifier unique to this application. + public SingleInstance(string id) + { + _id = id; + _mutex = new Mutex(true, id, out _ownsMutex); + } + + + /// + /// Passes the given arguments to the first running instance of the application. + /// + /// The arguments to pass. + /// Return true if the operation succeded, false otherwise. + public async Task PassArgsToFirstInstanceAsync(string[] args) + { + // cannot pass to itself + if (IsFirstInstance) return false; + + try + { + using var client = new NamedPipeClientStream(_id); + using var writer = new StreamWriter(client); + + await client.ConnectAsync(200).ConfigureAwait(false); + foreach (var arg in args) + { + await writer.WriteLineAsync(arg).ConfigureAwait(false); + } + + return true; + } + catch (TimeoutException) { } // Couldn't connect to server + catch (IOException) { } // Pipe was broken + + return false; + } + + + /// + /// Listens for arguments being passed from successive instances of the application. + /// + public void ListenForArgsFromChildInstances() + { + // only the first instance can listen to its child instances + if (!IsFirstInstance) return; + + ThreadPool.QueueUserWorkItem(new WaitCallback(ListenForArgs)); + } + + + /// + /// Listens for arguments on a named pipe. + /// + /// + /// State object required by delegate. + /// + private void ListenForArgs(object? state) + { + try + { + using var server = new NamedPipeServerStream(_id); + using var reader = new StreamReader(server); + server.WaitForConnection(); + + var args = new List(); + while (server.IsConnected) + { + var arg = reader.ReadLine(); + + if (arg != null) + { + args.Add(arg); + } + } + + ThreadPool.QueueUserWorkItem(CallOnArgsReceived, args.ToArray()); + } + catch (IOException) { } // Pipe was broken + finally + { + ListenForArgs(null); + } + } + + + /// + /// Calls the method casting + /// the state to . + /// + /// The arguments to pass. + private void CallOnArgsReceived(object? state) + { + OnArgumentsReceived((string[]?)state); + } + + + /// + /// Fires the event. + /// + /// + /// The arguments to pass with the . + /// + private void OnArgumentsReceived(string[]? args) + { + ArgsReceived?.Invoke(this, new() + { + Arguments = args ?? [], + }); + } + +} diff --git a/Source/Components/ImageGlass.Base/Language/IgLang.cs b/Source/Components/ImageGlass.Base/Language/IgLang.cs new file mode 100644 index 000000000..5d2cd2fd3 --- /dev/null +++ b/Source/Components/ImageGlass.Base/Language/IgLang.cs @@ -0,0 +1,998 @@ +/* +ImageGlass Project - Image viewer for Windows +Copyright (C) 2010 - 2026 DUONG DIEU PHAP +Project homepage: https://imageglass.org + +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 . +*/ +using ImageGlass.Base.PhotoBox; +using ImageGlass.Base.Photoing.Codecs; +using System.Collections; +using System.Collections.Frozen; +using System.Diagnostics.CodeAnalysis; + +namespace ImageGlass.Base; + + +/// +/// ImageGlass language pack (*.iglang.json) +/// +public class IgLang : IDictionary +{ + private FrozenDictionary _dict = FrozenDictionary.Empty; + + + // IDictionary interface implementation + #region IDictionary interface implementation + public string this[string key] + { + get => _dict[key]; + + [Obsolete("Cannot change an item in a readonly Dictionary", true)] + set { } + } + + public ICollection Keys => _dict.Keys; + + public ICollection Values => _dict.Values; + + public int Count => _dict.Count; + + public bool IsReadOnly => true; + + public void Add(string key, string value) + { + _ = _dict.TryAdd(key, value); + } + + public void Add(KeyValuePair item) + { + _ = _dict.TryAdd(item.Key, item.Value); + } + + public bool TryAdd(string key, string value) + { + return _dict.TryAdd(key, value); + } + + public bool TryAdd(KeyValuePair item) + { + return _dict.TryAdd(item.Key, item.Value); + } + + public void Clear() + { + _dict = FrozenDictionary.Empty; + } + + public bool Contains(KeyValuePair item) + { + return _dict.Contains(item); + } + + public bool ContainsKey(string key) + { + return _dict.ContainsKey(key); + } + + public void CopyTo(KeyValuePair[] array, int arrayIndex) + { + _dict.CopyTo(array, arrayIndex); + } + + public IEnumerator> GetEnumerator() + { + return _dict.GetEnumerator(); + } + + [Obsolete("Cannot remove an item in a readonly Dictionary", true)] + public bool Remove(string key) + { + return false; + } + + [Obsolete("Cannot remove an item in a readonly Dictionary", true)] + public bool Remove(KeyValuePair item) + { + return false; + } + + public bool TryGetValue(string key, [MaybeNullWhen(false)] out string value) + { + return _dict.TryGetValue(key, out value); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return _dict.GetEnumerator(); + } + #endregion // IDictionary interface implementation + + + + /// + /// Gets the path of language file. + /// Example: C:\ImageGlass\Languages\Vietnameses.iglang.json + /// + private string FilePath { get; set; } = "English"; + + /// + /// Gets the name of language file. + /// Example: Vietnameses.iglang.json + /// + public string FileName => Path.GetFileName(FilePath); + + /// + /// Language information + /// + public IgLangMetadata Metadata { get; set; } = new(); + + + + /// + /// Initializes default language + /// + public IgLang() + { + _dict = InitDefaultLanguage().ToFrozenDictionary(); + } + + + /// + /// Initializes language with filename + /// + /// E.g. Vietnamese.iglang.json + /// The directory path contains language file (for relative filename) + public IgLang(string fileName, string dirPath = "") + { + var defaultLang = InitDefaultLanguage(); + var filePath = Path.Combine(dirPath, fileName); + + if (File.Exists(filePath)) + { + FilePath = filePath; + ReadFromFile(ref defaultLang); + } + + _dict = defaultLang.ToFrozenDictionary(); + } + + + /// + /// Loads language strings from JSON file + /// + public void ReadFromFile(ref Dictionary defaultLang) + { + var model = BHelper.ReadJson(FilePath); + if (model == null) return; + + Metadata = model._Metadata; + + // import language items + foreach (var item in model.Items) + { + if (string.IsNullOrEmpty(item.Value)) continue; + + if (defaultLang.ContainsKey(item.Key)) + { + defaultLang[item.Key] = item.Value; + } + else + { + _ = defaultLang.TryAdd(item.Key, item.Value); + } + } + } + + + /// + /// Saves current language to JSON file + /// + public async Task SaveAsFileAsync(string filePath) + { + var model = new IgLangJsonModel(Metadata, _dict); + + if (Metadata.EnglishName.Equals("English", StringComparison.OrdinalIgnoreCase)) + { + model._Metadata.EnglishName = ""; + model._Metadata.LocalName = ""; + model._Metadata.Author = ""; + } + + await BHelper.WriteJsonAsync(filePath, model); + } + + + /// + /// Initialize default language + /// + public Dictionary InitDefaultLanguage() + { + return new() + { + #region General + { "_._OK", "OK" }, // v9.0 + { "_._Cancel", "Cancel" }, // v9.0 + { "_._Apply", "Apply" }, // v9.0 + { "_._Close", "Close" }, // v9.0 + { "_._Yes", "Yes" }, // v9.0 + { "_._No", "No" }, // v9.0 + { "_._LearnMore", "Learn more…" }, // v9.0 + { "_._Continue", "Continue" }, // v9.0 + { "_._Quit", "Quit" }, // v9.0 + { "_._Back", "Back" }, // v9.0 + { "_._Next", "Next" }, // v9.0 + { "_._Save", "Save" }, // v9.0 + { "_._Error", "Error" }, // v9.0 + { "_._Warning", "Warning" }, // v9.0 + { "_._Copy", "Copy" }, //v9.0 + { "_._Browse", "Browse…" }, //v9.0 + { "_._Reset", "Reset" }, //v9.0 + { "_._ResetToDefault", "Reset to default" }, //v9.0 + { "_._CheckForUpdate", "Check for update…" }, //v5.0 + { "_._Download", "Download" }, //v9.0 + { "_._Update", "Update" }, //v9.0 + { "_._Website", "Website" }, //v9.0 + { "_._Email", "Email" }, //v9.0 + { "_._Install", "Install…" }, + { "_._Refresh", "Refresh" }, + { "_._Delete", "Delete" }, + { "_._Add", "Add" }, + { "_._Add+", "Add…" }, + { "_._Edit", "Edit" }, + { "_._ID", "ID" }, + { "_._Name", "Name" }, + { "_._Hotkeys", "Hotkeys" }, + { "_._AddHotkey", "Add hotkey…" }, + { "_._Executable", "Executable" }, + { "_._Argument", "Argument" }, + { "_._CommandPreview", "Command preview" }, + { "_._FileExtension", "File extension" }, + { "_._Empty", "(empty)" }, + { "_._MoveUp", "Move up" }, + { "_._MoveDown", "Move down" }, + { "_._Separator", "Separator" }, + { "_._Icon", "Icon" }, + { "_._Description", "Description" }, + { "_._GetHelp", "Get help" }, + + { "_._UnhandledException", "Unhandled exception" }, // v9.0 + { "_._UnhandledException._Description", "Unhandled exception has occurred. If you click Continue, the application will ignore this error and attempt to continue. If you click Quit, the application will close immediately." }, // v9.0 + { "_._DoNotShowThisMessageAgain", "Do not show this message again" }, // v9.0 + { $"_._CreatingFile", "Creating a temporary image file…" }, //v9.0 + { $"_._CreatingFileError", "Could not create temporary image file" }, //v9.0 + { $"_._NotSupported", "Unsupported format" }, //v9.0 + + { $"_._InvalidAction", "Invalid action" }, //v9.0 + { $"_._InvalidAction._Transformation", "ImageGlass does not support rotation, flipping for this image." }, //v9.0 + + + { "_._UserAction._MenuNotFound", "Cannot find menu '{0}' to invoke the action" }, // v9.0 + { "_._UserAction._MethodNotFound", "Cannot find method '{0}' to invoke the action" }, // v9.0 + { "_._UserAction._MethodArgumentNotSupported", "The argument type of method '{0}' is not supported" }, // v9.0 + { "_._UserAction._Win32ExeError", "Cannot execute command '{0}'. Make sure the name is correct." }, // v9.0 + + { "_._Webview2._NotFound", "Please install WebView2 Runtime to access full features of ImageGlass." }, // 9.2 + { "_._Webview2._Outdated", "Your WebView2 Runtime is not supported. Please update to version {0} or later." }, // 9.2 + + // Gallery tooltip + { $"_.Metadata._{nameof(IgMetadata.FileSize)}", "File size" }, //v9.0 + { $"_.Metadata._{nameof(IgMetadata.FileCreationTime)}", "Date created" }, //v9.0 + { $"_.Metadata._{nameof(IgMetadata.FileLastAccessTime)}", "Date accessed" }, //v9.0 + { $"_.Metadata._{nameof(IgMetadata.FileLastWriteTime)}", "Date modified" }, //v9.0 + { $"_.Metadata._{nameof(IgMetadata.FrameCount)}", "Frames" }, //v9.0 + { $"_.Metadata._{nameof(IgMetadata.ExifRatingPercent)}", "Rating" }, //v9.0 + { $"_.Metadata._{nameof(IgMetadata.ColorSpace)}", "Color space" }, //v9.0 + { $"_.Metadata._{nameof(IgMetadata.ColorProfile)}", "Color profile" }, //v9.0 + { $"_.Metadata._{nameof(IgMetadata.ExifDateTime)}", "EXIF: DateTime" }, //v9.0 + { $"_.Metadata._{nameof(IgMetadata.ExifDateTimeOriginal)}", "EXIF: DateTimeOriginal" }, //v9.0 + + // image info + { $"_.{nameof(ImageInfo)}._{nameof(ImageInfo.ListCount)}", "{0} file(s)" }, //v9.0 + { $"_.{nameof(ImageInfo)}._{nameof(ImageInfo.FrameCount)}", "{0} frame(s)" }, //v9.0 + + // layout position + { $"_.Position._Left", "Left" }, + { $"_.Position._Right", "Right" }, + { $"_.Position._Top", "Top" }, + { $"_.Position._Bottom", "Bottom" }, + + #endregion // General + + + #region Enums + + // ImageOrderBy + { $"_.{nameof(ImageOrderBy)}._{nameof(ImageOrderBy.Name)}", "Name (default)" }, //v8.0 + { $"_.{nameof(ImageOrderBy)}._{nameof(ImageOrderBy.Random)}", "Random" }, //v8.0 + { $"_.{nameof(ImageOrderBy)}._{nameof(ImageOrderBy.FileSize)}", "File size" }, //v8.0 + { $"_.{nameof(ImageOrderBy)}._{nameof(ImageOrderBy.Extension)}", "Extension" }, //v8.0 + { $"_.{nameof(ImageOrderBy)}._{nameof(ImageOrderBy.DateCreated)}", "Date created" }, //v8.0 + { $"_.{nameof(ImageOrderBy)}._{nameof(ImageOrderBy.DateAccessed)}", "Date accessed" }, //v8.0 + { $"_.{nameof(ImageOrderBy)}._{nameof(ImageOrderBy.DateModified)}", "Date modified" }, //v8.0 + { $"_.{nameof(ImageOrderBy)}._{nameof(ImageOrderBy.ExifDateTaken)}", "EXIF: Date taken" }, //v9.0 + { $"_.{nameof(ImageOrderBy)}._{nameof(ImageOrderBy.ExifRating)}", "EXIF: Rating" }, //v9.0 + + + // ImageOrderType + { $"_.{nameof(ImageOrderType)}._{nameof(ImageOrderType.Asc)}", "Ascending" }, //v8.0 + { $"_.{nameof(ImageOrderType)}._{nameof(ImageOrderType.Desc)}", "Descending" }, //v8.0 + + // AfterEditAppAction + { $"_.{nameof(AfterEditAppAction)}._{nameof(AfterEditAppAction.Nothing)}", "Nothing" }, //v8.0 + { $"_.{nameof(AfterEditAppAction)}._{nameof(AfterEditAppAction.Minimize)}", "Minimize" }, //v8.0 + { $"_.{nameof(AfterEditAppAction)}._{nameof(AfterEditAppAction.Close)}", "Close" }, //v8.0 + + // ColorProfileOption + { $"_.{nameof(ColorProfileOption)}._{nameof(ColorProfileOption.None)}", "None" }, + { $"_.{nameof(ColorProfileOption)}._{nameof(ColorProfileOption.CurrentMonitorProfile)}", "Current monitor profile" }, + { $"_.{nameof(ColorProfileOption)}._{nameof(ColorProfileOption.Custom)}", "Custom…" }, + + // BackdropStyle + { $"_.{nameof(BackdropStyle)}._{nameof(BackdropStyle.None)}", "None" }, + + // MouseWheelEvent + { $"_.{nameof(MouseWheelEvent)}._{nameof(MouseWheelEvent.Scroll)}", "Scroll" }, + { $"_.{nameof(MouseWheelEvent)}._{nameof(MouseWheelEvent.CtrlAndScroll)}", "Hold Ctrl and scroll" }, + { $"_.{nameof(MouseWheelEvent)}._{nameof(MouseWheelEvent.ShiftAndScroll)}", "Hold Shift and scroll" }, + { $"_.{nameof(MouseWheelEvent)}._{nameof(MouseWheelEvent.AltAndScroll)}", "Hold Alt and scroll" }, + + // MouseWheelAction + { $"_.{nameof(MouseWheelAction)}._{nameof(MouseWheelAction.DoNothing)}", "Do nothing" }, + { $"_.{nameof(MouseWheelAction)}._{nameof(MouseWheelAction.Zoom)}", "Zoom in / out" }, + { $"_.{nameof(MouseWheelAction)}._{nameof(MouseWheelAction.PanVertically)}", "Pan up / down" }, + { $"_.{nameof(MouseWheelAction)}._{nameof(MouseWheelAction.PanHorizontally)}", "Pan left / right" }, + { $"_.{nameof(MouseWheelAction)}._{nameof(MouseWheelAction.BrowseImages)}", "View next / previous Image" }, + + // ImageInterpolation + { $"_.{nameof(ImageInterpolation)}._{nameof(ImageInterpolation.NearestNeighbor)}", "Nearest neighbor" }, + { $"_.{nameof(ImageInterpolation)}._{nameof(ImageInterpolation.Linear)}", "Linear" }, + { $"_.{nameof(ImageInterpolation)}._{nameof(ImageInterpolation.Cubic)}", "Cubic" }, + { $"_.{nameof(ImageInterpolation)}._{nameof(ImageInterpolation.MultiSampleLinear)}", "Multi-sample linear" }, + { $"_.{nameof(ImageInterpolation)}._{nameof(ImageInterpolation.Anisotropic)}", "Anisotropic" }, + { $"_.{nameof(ImageInterpolation)}._{nameof(ImageInterpolation.HighQualityBicubic)}", "High quality bicubic" }, + + #endregion // Enums + + + #region FrmMain + + #region Main menu + + #region File + { "FrmMain.MnuFile", "File" }, //v7.0 + { "FrmMain.MnuOpenFile", "Open file…" }, //v3.0 + { "FrmMain.MnuNewWindow", "Open new window" }, //v7.0 + { "FrmMain.MnuNewWindow._Error", "Cannot open new window because only one instance is allowed" }, //v7.0 + { "FrmMain.MnuSave", "Save" }, //v8.1 + { "FrmMain.MnuSave._Confirm", "Are you sure you want to override this image?" }, //v9.0 + { "FrmMain.MnuSave._ConfirmDescription", "ImageGlass is not a professional photo editor, please be aware of losing the quality, metadata, layers,… when saving your image." }, //v9.0 + { "FrmMain.MnuSave._Saving", "Saving image…" }, //v9.0 + { "FrmMain.MnuSave._Success", "Image is saved" }, //v9.0 + { "FrmMain.MnuSave._Error", "Could not save the image" }, //v9.0 + { "FrmMain.MnuSaveAs", "Save as…" }, //v3.0 + { "FrmMain.MnuRefresh", "Refresh" }, //v3.0 + { "FrmMain.MnuReload", "Reload image" }, //v5.5 + { "FrmMain.MnuReloadImageList", "Reload image list" }, //v7.0 + { "FrmMain.MnuUnload", "Unload image" }, //v9.0 + { "FrmMain.MnuOpenWith", "Open with…" }, //v7.6 + { "FrmMain.MnuEdit", "Edit image {0}…" }, //v3.0, + { "FrmMain.MnuEdit._AppNotFound", "Could not find the associated app for editing. You can assign an app for editing this format in ImageGlass Settings > Edit." }, //v9.0 + { "FrmMain.MnuPrint", "Print…" }, //v3.0 + { "FrmMain.MnuPrint._Error", "Could not print the viewing image" }, //v9.0 + { "FrmMain.MnuShare", "Share…" }, //v8.6 + { "FrmMain.MnuShare._Error", "Could not open Share dialog." }, //v9.0 + #endregion + + #region Navigation + { "FrmMain.MnuNavigation", "Navigation" }, //v3.0 + { "FrmMain.MnuViewNext", "View next image" }, //v3.0 + { "FrmMain.MnuViewPrevious", "View previous image" }, //v3.0 + + { "FrmMain.MnuGoTo", "Go to…" }, //v3.0 + { "FrmMain.MnuGoTo._Description", "Enter the image index to view, and then press ENTER" }, + { "FrmMain.MnuGoToFirst", "Go to first image" }, //v3.0 + { "FrmMain.MnuGoToLast", "Go to last image" }, //v3.0 + + { "FrmMain.MnuViewNextFrame", "View next frame" }, //v7.5 + { "FrmMain.MnuViewPreviousFrame", "View previous frame" }, //v7.5 + { "FrmMain.MnuViewFirstFrame", "View first frame" }, //v7.5 + { "FrmMain.MnuViewLastFrame", "View last frame" }, //v7.5 + #endregion // Navigation + + #region Zoom + { "FrmMain.MnuZoom", "Zoom" }, //v7.0 + { "FrmMain.MnuZoomIn", "Zoom in" }, //v3.0 + { "FrmMain.MnuZoomOut", "Zoom out" }, //v3.0 + { "FrmMain.MnuCustomZoom", "Custom zoom…" }, // v8.3 + { "FrmMain.MnuCustomZoom._Description", "Enter a new zoom value" }, // v8.3 + { "FrmMain.MnuScaleToFit", "Scale to fit" }, //v3.5 + { "FrmMain.MnuScaleToFill", "Scale to fill" }, //v7.5 + { "FrmMain.MnuActualSize", "Actual size" }, //v3.0 + { "FrmMain.MnuLockZoom", "Lock zoom ratio" }, //v3.0 + { "FrmMain.MnuAutoZoom", "Auto zoom" }, //v5.5 + { "FrmMain.MnuScaleToWidth", "Scale to width" }, //v3.0 + { "FrmMain.MnuScaleToHeight", "Scale to height" }, //v3.0 + #endregion + + #region Panning + { "FrmMain.MnuPanning", "Panning" }, //v9.0 + + { "FrmMain.MnuPanLeft", "Pan image left" }, //v9.0 + { "FrmMain.MnuPanRight", "Pan image right" }, //v9.0 + { "FrmMain.MnuPanUp", "Pan image up" }, //v9.0 + { "FrmMain.MnuPanDown", "Pan image down" }, //v9.0 + + { "FrmMain.MnuPanToLeftSide", "Pan image to left edge" }, //v9.0 + { "FrmMain.MnuPanToRightSide", "Pan image to right edge" }, //v9.0 + { "FrmMain.MnuPanToTop", "Pan image to top" }, //v9.0 + { "FrmMain.MnuPanToBottom", "Pan image to bottom" }, //v9.0 + #endregion // Panning + + #region Image + { "FrmMain.MnuImage", "Image" }, //v7.0 + + { "FrmMain.MnuViewChannels", "View channels" }, //v7.0 + { "FrmMain.MnuLoadingOrders", "Loading orders" }, //v8.0 + + { "FrmMain.MnuInvertColors", "Invert colors" }, // v9.3 + { "FrmMain.MnuRotateLeft", "Rotate left" }, //v7.5 + { "FrmMain.MnuRotateRight", "Rotate right" }, //v7.5 + { "FrmMain.MnuFlipHorizontal", "Flip Horizontal" }, // V6.0 + { "FrmMain.MnuFlipVertical", "Flip Vertical" }, // V6.0 + { "FrmMain.MnuRename", "Rename image…" }, //v3.0 + { "FrmMain.MnuRename._Description", "Enter a new filename:" }, // v9.0 + { "FrmMain.MnuMoveToRecycleBin", "Move to the Recycle Bin" }, //v3.0 + { "FrmMain.MnuMoveToRecycleBin._Description", "Do you want to move this file to the Recycle bin?" }, //v3.0 + { "FrmMain.MnuDeleteFromHardDisk", "Delete permanently" }, //v3.0 + { "FrmMain.MnuDeleteFromHardDisk._Description", "Are you sure you want to permanently delete this file?" }, //v3.0 + { "FrmMain.MnuExportFrames", "Export image frames…" }, //v7.5 + { "FrmMain.MnuToggleImageAnimation", "Start / stop animating image" }, //v3.0 + { "FrmMain.MnuSetDesktopBackground", "Set as Desktop background" }, //v3.0 + { "FrmMain.MnuSetDesktopBackground._Error", "Could not set the viewing image as desktop background" }, // v6.0 + { "FrmMain.MnuSetDesktopBackground._Success", "Desktop background is updated" }, // v6.0 + { "FrmMain.MnuSetLockScreen", "Set as Lock screen image" }, // V6.0 + { "FrmMain.MnuSetLockScreen._Error", "Could not set the viewing image as lock screen image" }, // v6.0 + { "FrmMain.MnuSetLockScreen._Success", "Lock screen image is updated" }, // v6.0 + { "FrmMain.MnuOpenLocation", "Open image location" }, //v3.0 + { "FrmMain.MnuImageProperties", "Image properties" }, //v3.0 + #endregion // Image + + #region Clipboard + { "FrmMain.MnuClipboard", "Clipboard" }, //v3.0 + { "FrmMain.MnuCopyFile", "Copy file" }, //v3.0 + { "FrmMain.MnuCopyFile._Success", "Copied {0} file(s)." }, // v2.0 final + { "FrmMain.MnuCopyImageData", "Copy image data" }, //v5.0 + { "FrmMain.MnuCopyImageData._Copying", "Copying the image data. It's going to take a while…" }, // v9.0 + { "FrmMain.MnuCopyImageData._Success", "Copied the current image data." }, // v5.0 + { "FrmMain.MnuCutFile", "Cut file" }, //v3.0 + { "FrmMain.MnuCutFile._Success", "Cut {0} file(s)." }, // v2.0 final + { "FrmMain.MnuCopyPath", "Copy image path" }, //v3.0 + { "FrmMain.MnuCopyPath._Success", "Copied the current image path." }, // v9.0 + { "FrmMain.MnuPasteImage", "Paste image" }, //v3.0 + { "FrmMain.MnuPasteImage._Error", "Could not find image data in the Clipboard" }, // v8.0 + { "FrmMain.MnuClearClipboard", "Clear clipboard" }, //v3.0 + { "FrmMain.MnuClearClipboard._Success", "Cleared clipboard." }, // v2.0 final + + #endregion + + { "FrmMain.MnuWindowFit", "Window Fit" }, //v7.5 + { "FrmMain.MnuFullScreen", "Full Screen" }, //v3.0 + + { "FrmMain.MnuFrameless", "Frameless" }, //v7.5 + { "FrmMain.MnuFrameless._EnableDescription", "Hold Shift key to move the window." }, // v7.5 + + { "FrmMain.MnuSlideshow", "Slideshow" }, //v3.0 + + #region Layout + { "FrmMain.MnuLayout", "Layout" }, //v3.0 + { "FrmMain.MnuToggleToolbar", "Toolbar" }, //v3.0 + { "FrmMain.MnuToggleGallery", "Gallery panel" }, //v3.0 + { "FrmMain.MnuToggleCheckerboard", "Checkerboard background" }, //v3.0, updated v5.0 + { "FrmMain.MnuToggleTopMost", "Keep window always on top" }, //v3.2 + { "FrmMain.MnuToggleTopMost._Enable", "Enabled window always on top" }, // v9.0 + { "FrmMain.MnuToggleTopMost._Disable", "Disabled window always on top" }, // v9.0 + { "FrmMain.MnuChangeBackgroundColor", "Change background color…" }, // v9.0 + #endregion // Layout + + #region Tools + { "FrmMain.MnuTools", "Tools" }, //v3.0 + { "FrmMain.MnuColorPicker", "Color picker" }, //v5.0 + { "FrmMain.MnuCropTool", "Crop image" }, // v7.6 + { "FrmMain.MnuResizeTool", "Resize image" }, // v9.2 + { "FrmMain.MnuFrameNav", "Frame navigation" }, // v7.5 + { "FrmMain.MnuGetMoreTools", "Get more tools…" }, // v9.0 + + { "FrmMain.MnuLosslessCompression", "Magick.NET Lossless Compression" }, // v9.1 + { "FrmMain.MnuLosslessCompression._Confirm", "Are you sure you want to proceed?" }, // v9.1 + { "FrmMain.MnuLosslessCompression._Description", "This tool uses Magick.NET library for lossless compression, optimizing file size. Overwrites only if the compressed file is smaller than the original." }, // v9.1 + { "FrmMain.MnuLosslessCompression._Compressing", "Performing lossless compression…" }, // v9.1 + { "FrmMain.MnuLosslessCompression._Done", "Done lossless compression.\r\nThe new file size is {0}, saved {1}." }, // v9.1 + + #endregion + + { "FrmMain.MnuSettings", "Settings" }, // v3.0 + + #region Help + { "FrmMain.MnuHelp", "Help" }, //v7.0 + { "FrmMain.MnuAbout", "About" }, //v3.0 + { "FrmMain.MnuQuickSetup", "Open ImageGlass Quick Setup" }, //v9.0 + { "FrmMain.MnuCheckForUpdate._NewVersion", "A new version is available!" }, //v5.0 + { "FrmMain.MnuReportIssue", "Report an issue…" }, //v3.0 + + { "FrmMain.MnuSetDefaultPhotoViewer", "Set default photo viewer" }, //v9.0 + { "FrmMain.MnuSetDefaultPhotoViewer._Success", "You have successfully set ImageGlass as default photo viewer." }, //v9.0 + { "FrmMain.MnuSetDefaultPhotoViewer._Error", "Could not set ImageGlass as default photo viewer." }, //v9.0 + + { "FrmMain.MnuRemoveDefaultPhotoViewer", "Remove default photo viewer" }, //v9.0 + { "FrmMain.MnuRemoveDefaultPhotoViewer._Success", "ImageGlass is no longer the default photo viewer." }, //v9.0 + { "FrmMain.MnuRemoveDefaultPhotoViewer._Error", "Could not remove ImageGlass as the default photo viewer." }, //v9.0 + + #endregion + + { "FrmMain.MnuExit", "Exit" }, //v7.0 + + #endregion + + + #region Form message texts + { "FrmMain.PicMain._ErrorText", "Could not open this image" }, // v2.0 beta, updated 4.0, 9.0 + { "FrmMain.MnuMain", "Main menu" }, // v3.0 + + { "FrmMain._OpenFileDialog", "All supported files" }, + { "FrmMain._Loading", "Loading…" }, // v3.0 + { "FrmMain._OpenWith", "Open with {0}" }, //v9.0 + { "FrmMain._ReachedFirstImage", "Reached the first image" }, // v4.0 + { "FrmMain._ReachedLastLast", "Reached the last image" }, // v4.0 + { "FrmMain._ClipboardImage", "Clipboard image" }, //v9.0 + + #endregion + + + #endregion + + + #region FrmAbout + { "FrmAbout._Slogan", "A lightweight, versatile image viewer" }, + { "FrmAbout._Version", "Version:" }, + { "FrmAbout._License", "Software license" }, + { "FrmAbout._Privacy", "Privacy policy" }, + { "FrmAbout._Thanks", "Special thanks to" }, + { "FrmAbout._LogoDesigner", "Logo designer:" }, + { "FrmAbout._Collaborator", "Collaborator:" }, + { "FrmAbout._Contact", "Contact" }, + { "FrmAbout._Homepage", "Homepage:" }, + { "FrmAbout._Email", "Email:" }, + { "FrmAbout._Credits", "Credits" }, + { "FrmAbout._Donate", "Donate" }, + #endregion + + + #region FrmSettings + + { "FrmSettings._ResetSettings", "Reset settings" }, // v9.1 + { "FrmSettings._UnmanagedSettingReminder", "This setting is not managed by ImageGlass. Don't forget to disable it before you remove or relocate the app because ImageGlass does not handle this automatically." }, // v9.1 + + + #region Nav bar + { "FrmSettings.Nav._General", "General" }, + { "FrmSettings.Nav._Image", "Image" }, + { "FrmSettings.Nav._Slideshow", "Slideshow" }, + { "FrmSettings.Nav._Edit", "Edit" }, + { "FrmSettings.Nav._Viewer", "Viewer" }, + { "FrmSettings.Nav._Toolbar", "Toolbar" }, + { "FrmSettings.Nav._Gallery", "Gallery" }, + { "FrmSettings.Nav._Layout", "Layout" }, + { "FrmSettings.Nav._Mouse", "Mouse" }, + { "FrmSettings.Nav._Keyboard", "Keyboard" }, + { "FrmSettings.Nav._FileTypeAssociations", "File type associations" }, + { "FrmSettings.Nav._Tools", "Tools" }, + { "FrmSettings.Nav._Language", "Language" }, + { "FrmSettings.Nav._Appearance", "Appearance" }, + #endregion // Nav bar + + + #region Tab General + // General > General + { "FrmSettings._StartupDir", "Startup location" }, + { "FrmSettings._ConfigDir", "Configuration location" }, + { "FrmSettings._UserConfigFile", "User settings file (igconfig.json)" }, + + // General > Startup + { "FrmSettings._Startup", "Startup" }, + { "FrmSettings._ShowWelcomeImage", "Show welcome image" }, + { "FrmSettings._ShouldOpenLastSeenImage", "Open the last seen image" }, + + { "FrmSettings._StartupBoost", "Startup Boost" }, // v9.1 + { "FrmSettings._StartupBoost._Description", "Preload and run ImageGlass in the background for a few seconds during Windows startup to accelerate the first launch." }, // v9.1 + { "FrmSettings._StartupBoost._Enabled", "Startup Boost is enabled" }, // v9.1 + { "FrmSettings._StartupBoost._Disabled", "Startup Boost is disabled" }, // v9.1 + { "FrmSettings._StartupBoost._Error", "Could not change Startup Boost setting" }, // v9.1 + { "FrmSettings._EnableStartupBoost", "Enable Startup Boost" }, // v9.1 + { "FrmSettings._DisableStartupBoost", "Disable Startup Boost" }, // v9.1 + { "FrmSettings._OpenStartupAppsSetting", "Open Startup apps setting" }, // v9.1 + + // General > Real-time update + { "FrmSettings._RealTimeFileUpdate", "Real-time file update" }, + { "FrmSettings._EnableRealTimeFileUpdate", "Monitor file changes in the viewing folder and update in realtime" }, + { "FrmSettings._ShouldAutoOpenNewAddedImage", "Open the new added image automatically" }, + + // General > Others + { "FrmSettings._Others", "Others" }, + { "FrmSettings._AutoUpdate", "Check for update automatically" }, + { "FrmSettings._EnableMultiInstances", "Allow multiple instances of the program" }, + { "FrmSettings._ShowAppIcon", "Show app icon on the title bar" }, + { "FrmSettings._InAppMessageDuration", "In-app message duration (milliseconds)" }, + { "FrmSettings._ImageInfoTags", "Image information tags" }, + { "FrmSettings._AvailableImageInfoTags", "Available tags:" }, + #endregion // Tab General + + + #region Tab Image + // Image > Image loading + { "FrmSettings._ImageLoading", "Image loading" }, + { "FrmSettings._ImageLoadingOrder", "Image loading order" }, + { "FrmSettings._ShouldUseExplorerSortOrder", "Use Explorer sort order if possible" }, + { "FrmSettings._EnableRecursiveLoading", "Load images in subfolders" }, + { "FrmSettings._ShouldGroupImagesByDirectory", "Group images by directory" }, + { "FrmSettings._ShouldLoadHiddenImages", "Load hidden images" }, + { "FrmSettings._EnableLoopBackNavigation", "Loop back to the first image when reaching the end of the image list" }, + { "FrmSettings._ShowImagePreview", "Display image preview while it's being loaded" }, + { "FrmSettings._EnableImageAsyncLoading", "Enable image asynchronous loading" }, + + { "FrmSettings._EmbeddedThumbnail", "Embedded thumbnail" }, + { "FrmSettings._UseEmbeddedThumbnailRawFormats", "Load only the embedded thumbnail for RAW formats" }, + { "FrmSettings._UseEmbeddedThumbnailOtherFormats", "Load only the embedded thumbnail for other formats" }, + { "FrmSettings._MinEmbeddedThumbnailSize", "Minimum size of the embedded thumbnail to be loaded" }, + { "FrmSettings._MinEmbeddedThumbnailSize._Width", "Width" }, + { "FrmSettings._MinEmbeddedThumbnailSize._Height", "Height" }, + + // Image > Image Booster + { "FrmSettings._ImageBooster", "Image Booster" }, + { "FrmSettings._ImageBoosterCacheCount", "Number of images cached by Image Booster (one direction)" }, + { "FrmSettings._ImageBoosterCacheMaxDimension", "Maximum image dimension to be cached (in pixels)" }, + { "FrmSettings._ImageBoosterCacheMaxFileSizeInMb", "Maximum image file size to be cached (in megabytes)" }, + + // Image > Color management + { "FrmSettings._ColorManagement", "Color management" }, + { "FrmSettings._ShouldUseColorProfileForAll", "Apply also for images without embedded color profile" }, + { "FrmSettings._ColorProfile", "Color profile" }, + { "FrmSettings._CurrentMonitorProfile._Description", "ImageGlass does not auto-update the color when moving its window between monitors" }, + #endregion // Tab Image + + + #region Tab Slideshow + // Slideshow > Slideshow + { "FrmSettings._HideMainWindowInSlideshow", "Automatically hide main window" }, + { "FrmSettings._ShowSlideshowCountdown", "Show slideshow countdown" }, + { "FrmSettings._EnableFullscreenSlideshow", "Start slideshow in Full Screen mode" }, + { "FrmSettings._UseRandomIntervalForSlideshow", "Use random interval" }, + { "FrmSettings._SlideshowInterval", "Slideshow interval:" }, + { "FrmSettings._SlideshowInterval._From", "From" }, + { "FrmSettings._SlideshowInterval._To", "To" }, + { "FrmSettings._SlideshowBackgroundColor", "Slideshow background color" }, + + // Slideshow > Slideshow notification + { "FrmSettings._SlideshowNotification", "Slideshow notification" }, + { "FrmSettings._SlideshowImagesToNotifySound", "Number of images to trigger a notification sound" }, + #endregion // Tab Slideshow + + + #region Tab Edit + // Edit > Edit + { "FrmSettings._ShowDeleteConfirmation", "Show confirmation dialog when deleting file" }, + { "FrmSettings._ShowSaveOverrideConfirmation", "Show confirmation dialog when overriding file" }, + { "FrmSettings._ShouldPreserveModifiedDate", "Preserve the image's modified date on save" }, + { "FrmSettings._OpenSaveAsDialogInTheCurrentImageDir", "Open the Save As dialog in the current image directory" }, // v9.1 + { "FrmSettings._ImageEditQuality", "Image quality" }, + { "FrmSettings._AfterEditingAction", "After opening editing app" }, + + // Edit > Clipboard + { "FrmSettings._Clipboard", "Clipboard" }, + { "FrmSettings._EnableCopyMultipleFiles", "Enable the copying of multiple files at once" }, + { "FrmSettings._EnableCutMultipleFiles", "Enable the cutting of multiple files at once" }, + + // Edit > Image editing apps + { "FrmSettings._EditApps", "Image editing apps" }, + { "FrmSettings._EditApps._AppName", "App name" }, + { "FrmSettings.EditAppDialog._AddApp", "Add an app for editing" }, + { "FrmSettings.EditAppDialog._EditApp", "Edit app" }, + + #endregion // Tab Edit + + + #region Tab Layout + // Layout > Layout + { "FrmSettings.Layout._Order", "Order" }, + { "FrmSettings.Layout._Toolbar", "Toolbar" }, + { "FrmSettings.Layout._ToolbarContext", "Contextual toolbar" }, + { "FrmSettings.Layout._Gallery", "Gallery" }, + { "FrmSettings.Layout._ToolbarPosition", "Toolbar position" }, + { "FrmSettings.Layout._ToolbarContextPosition", "Contextual toolbar position" }, + { "FrmSettings.Layout._GalleryPosition", "Gallery position" }, + #endregion // Tab Layout + + + #region Tab Viewer + // Viewer > Viewer + { "FrmSettings._ShowCheckerboardOnlyImageRegion", "Show checkerboard only within the image region" }, + { "FrmSettings._EnableNavigationButtons", "Show navigation arrow buttons" }, + { "FrmSettings._CenterWindowFit", "Automatically center the window in Window Fit mode" }, + { "FrmSettings._UseWebview2ForSvg", "Use Webview2 for viewing SVG format" }, + { "FrmSettings._PanSpeed", "Panning speed" }, + + // Viewer > Zooming + { "FrmSettings._Zooming", "Zooming" }, + { "FrmSettings._ImageInterpolation", "Image interpolation" }, + { "FrmSettings._ImageInterpolation._ScaleDown", "When zoom < 100%" }, + { "FrmSettings._ImageInterpolation._ScaleUp", "When zoom > 100%" }, + { "FrmSettings._ZoomSpeed", "Zoom speed" }, + { "FrmSettings._ZoomLevels", "Zoom levels" }, + { "FrmSettings._UseSmoothZooming", "Use smooth zooming" }, + { "FrmSettings._LoadDefaultZoomLevels", "Load default zoom levels" }, + #endregion // Tab Viewer + + + #region Tab Toolbar + // Toolbar > Toolbar + { "FrmSettings.Toolbar._HideToolbarInFullscreen", "Hide toolbar in Full Screen mode" }, + { "FrmSettings.Toolbar._EnableCenterToolbar", "Use center alignment for toolbar" }, + { "FrmSettings.Toolbar._ToolbarIconHeight", "Toolbar icon size" }, + + { "FrmSettings.Toolbar._AddNewButton", "Add a custom toolbar button" }, + { "FrmSettings.Toolbar._EditButton", "Edit toolbar button" }, + { "FrmSettings.Toolbar._ButtonJson", "Button JSON" }, + + + { "FrmSettings.Toolbar._ToolbarButtons", "Toolbar buttons" }, + { "FrmSettings.Toolbar._AddCustomButton", "Add a custom button…" }, + { "FrmSettings.Toolbar._AvailableButtons", "Available buttons:" }, + { "FrmSettings.Toolbar._CurrentButtons", "Current buttons:" }, + { "FrmSettings.Toolbar._Errors._ButtonIdRequired", "Button ID required." }, + { "FrmSettings.Toolbar._Errors._ButtonIdDuplicated", "A button with the ID '{0}' has already been defined. Please choose a different and unique ID for your button to avoid conflicts." }, + { "FrmSettings.Toolbar._Errors._ButtonExecutableRequired", "Button executable required." }, + + #endregion // TAB Toolbar + + + #region Tab Gallery + // Gallery > Gallery + { "FrmSettings._HideGalleryInFullscreen", "Hide gallery in Full Screen mode" }, + { "FrmSettings._ShowGalleryScrollbars", "Show gallery scrollbars" }, + { "FrmSettings._ShowGalleryFileName", "Show thumbnail filename" }, + { "FrmSettings._ThumbnailSize", "Thumbnail size (in pixels)" }, + { "FrmSettings._GalleryCacheSizeInMb", "Maximum gallery cache size (in megabytes)" }, + { "FrmSettings._GalleryColumns", "Number of thumbnail columns in vertical gallery layout" }, + #endregion // Tab Gallery + + + #region Tab Mouse + // Mouse > Mouse wheel action + { "FrmSettings._MouseWheelAction", "Mouse wheel action" }, + #endregion // Tab Mouse + + + #region Tab Keyboard + + #endregion // Tab Mouse & Keyboard + + + #region Tab File type associations + // File type associations > File extension icons + { "FrmSettings._FileExtensionIcons", "File extension icons" }, + { "FrmSettings._FileExtensionIcons._Description", "For customizing file extension icons, download an icon pack, place all .ICO files in the extension icon folder, and click the '{0}' button. This will also set ImageGlass as default photo viewer." }, + { "FrmSettings._OpenExtensionIconFolder", "Open extension icon folder" }, + { "FrmSettings._GetExtensionIconPacks", "Get extension icon packs…" }, + + // File type associations > Default photo viewer + { "FrmSettings._DefaultPhotoViewer", "Default photo viewer" }, + { "FrmSettings._DefaultPhotoViewer._Description", "Register the supported formats of ImageGlass with Windows. You might need to open the Default apps settings and manually select ImageGlass from the list for it to take effect." }, + { "FrmSettings._MakeDefault", "Make default" }, + { "FrmSettings._RemoveDefault", "Remove default" }, + { "FrmSettings._OpenDefaultAppsSetting", "Open Default apps setting" }, + + // File type associations > File formats + { "FrmSettings._FileFormats", "File formats" }, + { "FrmSettings._TotalSupportedFormats", "Total supported formats: {0}" }, + { "FrmSettings._AddNewFileExtension", "Add new file extension" }, + + #endregion // Tab File type associations + + + #region Tab Tools + // Tools > Tools + { "FrmSettings.Tools._AddNewTool", "Add an external tool" }, + { "FrmSettings.Tools._EditTool", "Edit external tool" }, + { "FrmSettings.Tools._Integrated", "Integrated" }, + { "FrmSettings.Tools._IntegratedWith", "Integrated with {0}" }, + #endregion // Tab Tools + + + #region Tab Language + // Language > Language + { "FrmSettings._DisplayLanguage", "Display language" }, + { "FrmSettings._Refresh", "Refresh" }, + { "FrmSettings._InstallNewLanguagePack", "Install new language packs…" }, + { "FrmSettings._GetMoreLanguagePacks", "Get more language packs…" }, + { "FrmSettings._ExportLanguagePack", "Export language pack…" }, + { "FrmSettings._Contributors", "Contributors" }, + #endregion // Tab Language + + + #region Tab Appearance + // Appearance > Appearance + { "FrmSettings._WindowBackdrop", "Window backdrop" }, + { "FrmSettings._BackgroundColor", "Viewer background color" }, + + // Appearance > Theme + { "FrmSettings._Theme", "Theme" }, + { "FrmSettings._DarkTheme", "Dark" }, + { "FrmSettings._LightTheme", "Light" }, + { "FrmSettings._Author", "Author" }, + { "FrmSettings._Theme._OpenThemeFolder", "Open theme folder" }, + { "FrmSettings._Theme._GetMoreThemes", "Get more theme packs…" }, + { "FrmSettings._Theme._InstallTheme", "Install theme packs" }, + { "FrmSettings._Theme._UninstallTheme", "Uninstall a theme pack" }, + + { "FrmSettings._UseThemeForDarkMode", "Use this theme for dark mode" }, + { "FrmSettings._UseThemeForLightMode", "Use this theme for light mode" }, + #endregion // Tab Appearance + + #endregion // FrmSettings + + + #region FrmCrop + { "FrmCrop.LblAspectRatio", "Aspect ratio:" }, //v9.0 + { "FrmCrop.LblLocation", "Location:" }, //v9.0 + { "FrmCrop.LblSize", "Size:" }, //v9.0 + + { "FrmCrop.SelectionAspectRatio._FreeRatio", "Free ratio" }, //v9.0 + { "FrmCrop.SelectionAspectRatio._Custom", "Custom…" }, //v9.0 + { "FrmCrop.SelectionAspectRatio._Original", "Original" }, //v9.0 + + { "FrmCrop.BtnQuickSelect._Tooltip", "Quick select…" }, //v9.0 + { "FrmCrop.BtnReset._Tooltip", "Reset selection" }, //v9.0 + { "FrmCrop.BtnSettings._Tooltip", "Open Crop tool settings" }, //v9.0 + + { "FrmCrop.BtnSave", "Save" }, //v9.0 + { "FrmCrop.BtnSave._Tooltip", "Save image" }, //v9.0 + { "FrmCrop.BtnSaveAs", "Save as…" }, //v9.0 + { "FrmCrop.BtnSaveAs._Tooltip", "Save as a copy…" }, //v9.0 + { "FrmCrop.BtnCrop", "Crop" }, //v9.0 + { "FrmCrop.BtnCrop._Tooltip", "Crop the image only" }, //v9.0 + { "FrmCrop.BtnCopy", "Copy" }, //v9.0 + { "FrmCrop.BtnCopy._Tooltip", "Copy the selection to clipboard" }, //v9.0 + + + // Crop settings + { "FrmCropSettings._Title", "Crop settings" }, //v9.0 + { "FrmCropSettings.ChkCloseToolAfterSaving", "Close Crop tool after saving" }, //v9.0 + { "FrmCropSettings.LblDefaultSelection", "Default selection" }, //v9.0 + { "FrmCropSettings.ChkAutoCenterSelection", "Auto-center selection" }, //v9.0 + + { "FrmCropSettings.DefaultSelectionType._UseTheLastSelection", "Use the last selection" }, //v9.0 + { "FrmCropSettings.DefaultSelectionType._SelectNone", "Select none" }, //v9.0 + { "FrmCropSettings.DefaultSelectionType._SelectX", "Select {0}" }, //v9.0 + { "FrmCropSettings.DefaultSelectionType._SelectAll", "Select all" }, //v9.0 + { "FrmCropSettings.DefaultSelectionType._CustomArea", "Custom area…" }, //v9.0 + + #endregion // FrmCrop + + + #region FrmColorPicker + + { "FrmColorPicker.BtnSettings._Tooltip", "Open Color picker settings…" }, //v9.0 + + // Color picker settings + { "FrmColorPickerSettings._Title", "Color picker settings" }, //v9.0 + { "FrmColorPickerSettings.ChkShowRgbA", "Use RGB format with alpha value" }, //v5.0 + { "FrmColorPickerSettings.ChkShowHexA", "Use HEX format with alpha value" }, //v5.0 + { "FrmColorPickerSettings.ChkShowHslA", "Use HSL format with alpha value" }, //v5.0 + { "FrmColorPickerSettings.ChkShowHsvA", "Use HSV format with alpha value" }, //v8.0 + { "FrmColorPickerSettings.ChkShowCIELabA", "Use CIELAB format with alpha value" }, //v9.0 + + #endregion + + + #region FrmToolNotFound + { "FrmToolNotFound._Title", "Tool not found" }, // v9.0 + { "FrmToolNotFound.BtnSelectExecutable", "Select…" }, // v9.0 + { "FrmToolNotFound.LblHeading", "'{0}' is not found!" }, // v9.0 + { "FrmToolNotFound.LblDescription", "ImageGlass was unable to locate the path to the '{0}' executable. To resolve this issue, please update the path to the '{0}' as necessary." }, // v9.0 + { "FrmToolNotFound.LblDownloadToolText", "You can download more tools for ImageGlass at:" }, // v9.0 + #endregion // FrmToolNotFound + + + #region FrmHotkeyPicker + { "FrmHotkeyPicker.LblHotkey", "Press hotkeys" }, // v9.0 + #endregion // FrmHotkeyPicker + + + #region FrmResize + { "FrmResize.RadResizeByPixels", "Pixels" }, // v9.2 + { "FrmResize.RadResizeByPercentage", "Percentage" }, // v9.2 + { "FrmResize.ChkKeepRatio", "Keep ratio propotional" }, // v9.2 + { "FrmResize.LblResample", "Resample:" }, // v9.2 + { "FrmResize.LblCurrentSize", "Current Size:" }, // v9.2 + { "FrmResize.LblNewSize", "New Size:" }, // v9.2 + #endregion // FrmResize + + + #region igcmd.exe + + { "_._IgCommandExe._DefaultError._Heading", "Invalid commands" }, //v9.0 + { "_._IgCommandExe._DefaultError._Description", "Make sure you pass the correct commands!\r\nThis executable file contains command-line functions for ImageGlass software.\r\n\r\nTo explore all command lines, please visit:\r\n{0}" }, //v9.0 + + + #region FrmSlideshow + + { "FrmSlideshow._PauseSlideshow", "Slideshow is paused." }, // v9.0 + { "FrmSlideshow._ResumeSlideshow", "Slideshow is resumed." }, // v9.0 + + // menu + { "FrmSlideshow.MnuPauseResumeSlideshow", "Pause/resume slideshow" }, // v9.0 + { "FrmSlideshow.MnuExitSlideshow", "Exit slideshow" }, // v9.0 + + { "FrmSlideshow.MnuToggleCountdown", "Show slideshow countdown" }, // v9.0 + { "FrmSlideshow.MnuZoomModes", "Zoom modes" }, // v9.0 + + #endregion + + + #region FrmExportFrames + { "FrmExportFrames._Title", "Export image frames" }, //v9.0 + { "FrmExportFrames._FileNotExist", "Image file does not exist" }, //v7.5 + { "FrmExportFrames._FolderPickerTitle", "Select output folder for exporting image frames" }, //v9.0 + { "FrmExportFrames._Exporting", "Exporting {0}/{1} frames \r\n{2}…" }, //v9.0 + { "FrmExportFrames._ExportDone", "Exported {0} frames successfully to \r\n{1}" }, //v9.0 + { "FrmExportFrames._OpenOutputFolder", "Open output folder" }, //v9.0 + #endregion + + + #region FrmUpdate + { "FrmUpdate._StatusChecking", "Checking for update…" }, //v9.0 + { "FrmUpdate._StatusUpdated", "You are using the latest version!" }, //v9.0 + { "FrmUpdate._StatusOutdated", "A new update is available!" }, //v9.0 + { "FrmUpdate._CurrentVersion", "Current version: {0}" }, //v9.0 + { "FrmUpdate._LatestVersion", "The latest version: {0}" }, //v9.0 + { "FrmUpdate._PublishedDate", "Published date: {0}" }, //v9.0 + #endregion + + + #region FrmQuickSetup + + { "FrmQuickSetup._Text", "ImageGlass Quick Setup" }, //v9.0 + { "FrmQuickSetup._StepInfo", "Step {0}" }, //v9.0 + { "FrmQuickSetup._SkipQuickSetup", "Skip this and launch ImageGlass" }, //v9.0 + + { "FrmQuickSetup._SeeWhatNew", "See what's new in this version…" }, // v9.0 + { "FrmQuickSetup._SelectProfile", "Select a profile" }, //v9.0 + { "FrmQuickSetup._StandardUser", "Standard user" }, //v9.0 + { "FrmQuickSetup._ProfessionalUser", "Professional user" }, //v9.0 + { "FrmQuickSetup._SettingProfileDescription", "To modify these settings, simply access app settings." }, // v9.0 + + { "FrmQuickSetup._SettingsWillBeApplied", "Settings will be applied:" }, //v9.0 + { "FrmQuickSetup._SetDefaultViewer", "Do you want to set ImageGlass as the default photo viewer?" }, //v9.0 + { "FrmQuickSetup._SetDefaultViewer._Description", "You can reset it in the app settings > File type associations tab." }, //v9.0 + + { "FrmQuickSetup._ConfirmCloseProcess", "Before applying the new settings, it's essential to close all ImageGlass processes. Are you ready to proceed?" }, //v7.5 + + #endregion + + #endregion // igcmd.exe + + }; + } + +} \ No newline at end of file diff --git a/Source/Components/ImageGlass.Base/Language/IgLangModels.cs b/Source/Components/ImageGlass.Base/Language/IgLangModels.cs new file mode 100644 index 000000000..917f2e780 --- /dev/null +++ b/Source/Components/ImageGlass.Base/Language/IgLangModels.cs @@ -0,0 +1,41 @@ +/* +ImageGlass Project - Image viewer for Windows +Copyright (C) 2010 - 2026 DUONG DIEU PHAP +Project homepage: https://imageglass.org + +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 . +*/ + +namespace ImageGlass.Base; + + +/// +/// Language information +/// +public record IgLangMetadata +{ + public string Code { get; set; } = "en-US"; + public string EnglishName { get; set; } = "English"; + public string LocalName { get; set; } = "English"; + public string Author { get; set; } = "Duong Dieu Phap"; + public string MinVersion { get; set; } = "9.3"; +} + + +/// +/// JSON model for IgLang file +/// +/// +/// +public record IgLangJsonModel(IgLangMetadata _Metadata, IDictionary Items) { } diff --git a/Source/Components/ImageGlass.Base/LocalEvents.cs b/Source/Components/ImageGlass.Base/LocalEvents.cs new file mode 100644 index 000000000..d5f7f533c --- /dev/null +++ b/Source/Components/ImageGlass.Base/LocalEvents.cs @@ -0,0 +1,132 @@ +/* +ImageGlass Project - Image viewer for Windows +Copyright (C) 2010 - 2026 DUONG DIEU PHAP +Project homepage: https://imageglass.org + +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 . +*/ + +using ImageGlass.Base.Photoing.Codecs; + +namespace ImageGlass.Base; + + +public class ImageEventArgs : EventArgs +{ + /// + /// Gets the current viewing image's index. + /// + public int Index { get; init; } + + /// + /// Gets the current viewing image's path. + /// + public string? FilePath { get; init; } +} + +public class ImageLoadingEventArgs : ImageEventArgs +{ + /// + /// Gets the loading image's index. + /// + public int NewIndex { get; init; } + + /// + /// Gets the loading image frame index. + /// + public uint FrameIndex { get; init; } + + /// + /// Gets the value indicates that the image is being viewed as a separate frame. + /// + public bool IsViewingSeparateFrame { get; init; } + + /// + /// Gets the value indicates that we will use Webview2 to render the image. + /// + public bool UseWebview2 { get; init; } +} + +public class ImageLoadedEventArgs : ImageEventArgs +{ + /// + /// Gets the loaded image frame index. + /// + public uint FrameIndex { get; init; } + + /// + /// Gets the loaded image data. + /// + public IgPhoto? Data { get; init; } + + /// + /// Gets, sets the loaded image error. + /// + public Exception? Error { get; set; } + + /// + /// Gets the value indicating that the viewer should reset zoom value. + /// + public bool ResetZoom { get; init; } + + /// + /// Gets the value indicating that the image is being viewed as a separate frame. + /// + public bool IsViewingSeparateFrame { get; init; } + + /// + /// Gets the value indicates that we will use Webview2 to render the image. + /// + public bool UseWebview2 { get; init; } +} + +public class EmbeddedVideoCheckedEventArgs : EventArgs +{ + public IgPhoto Photo { get; init; } +} + + +public class ImageListLoadedEventArgs : EventArgs +{ + public string? InitFilePath { get; init; } +} + + +public class SlideshowWindowClosedEventArgs(int slideshowIndex) : EventArgs +{ + public int SlideshowIndex { get; init; } = slideshowIndex; +} + + +public class ImageSaveEventArgs(string srcFilePath, string destFilePath, ImageSaveSource saveSource) : EventArgs +{ + public string SrcFilePath { get; init; } = srcFilePath; + public string DestFilePath { get; init; } = destFilePath; + public bool IsSaveAsNewFile => !SrcFilePath.Equals(DestFilePath, StringComparison.OrdinalIgnoreCase); + public ImageSaveSource SaveSource { get; init; } = saveSource; +} + + +public class UpdateRequestEventArgs : EventArgs +{ + /// + /// Gets the update requests + /// + public UpdateRequests Requests { get; init; } + + /// + /// Gets the action to execute after update requests made + /// + public Action? OnUpdated { get; init; } +} diff --git a/Source/Components/ImageGlass.Base/NativeMethods.txt b/Source/Components/ImageGlass.Base/NativeMethods.txt new file mode 100644 index 000000000..7ddcec29f --- /dev/null +++ b/Source/Components/ImageGlass.Base/NativeMethods.txt @@ -0,0 +1,34 @@ + +DwmSetWindowAttribute +SystemParametersInfo +DwmIsCompositionEnabled +DwmExtendFrameIntoClientArea +SaveDC +ReleaseDC +DeleteDC +CreateCompatibleDC +SelectObject +DeleteObject +BitBlt +CreateDIBSection +SetErrorMode +SendInput +ShowWindow +ReleaseCapture +SendMessage +GetSystemMetrics +SetWindowTheme +SetWindowPos +MonitorFromPoint +GetDpiForMonitor +SHChangeNotify +SHGetStockIconInfo +SetThreadExecutionState +timeBeginPeriod +timeEndPeriod +timeGetDevCaps +ShellExecuteEx +StrCmpLogicalW +GetWindowPlacement +MapVirtualKey +VkKeyScanEx diff --git a/Source/Components/ImageGlass.Base/Photoing/Animators/AnimatedImgAnimator.cs b/Source/Components/ImageGlass.Base/Photoing/Animators/AnimatedImgAnimator.cs new file mode 100644 index 000000000..9cde1927c --- /dev/null +++ b/Source/Components/ImageGlass.Base/Photoing/Animators/AnimatedImgAnimator.cs @@ -0,0 +1,83 @@ +/* +ImageGlass Project - Image viewer for Windows +Copyright (C) 2010 - 2026 DUONG DIEU PHAP +Project homepage: https://imageglass.org + +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 . +*/ +using ImageGlass.Base.Photoing.Codecs; + +namespace ImageGlass.Base.Photoing.Animators; + +public class AnimatedImgAnimator : ImgAnimator +{ + private AnimatedImg _frames; + + + /// + /// Initialize new instance of . + /// + public AnimatedImgAnimator(AnimatedImg frames) + { + lock (frames) + { + _frames = frames; + _frameCount = frames.FrameCount; + } + } + + + // Protected virtual methods + #region Protected virtual methods + + protected override bool CanAnimate() + { + return _frames != null; + } + + + protected override TimeSpan GetFrameDelay(int frameIndex) + { + if (GetFrame(_frameIndex) is AnimatedImgFrame frame) + { + return frame.Duration; + } + + return TimeSpan.Zero; + } + + + protected override void UpdateFrame(int frameIndex) + { + lock (_frames) + { + var frame = GetFrame(_frameIndex); + if (frame != null) + { + TriggerFrameChangedEvent(frame.Bitmap); + } + } + } + + #endregion // Protected virtual methods + + + /// + /// Gets image frame data. + /// + private AnimatedImgFrame? GetFrame(int frameIndex) + { + return _frames.GetFrame(frameIndex); + } +} diff --git a/Source/Components/ImageGlass.Base/Photoing/Animators/GifAnimator.cs b/Source/Components/ImageGlass.Base/Photoing/Animators/GifAnimator.cs new file mode 100644 index 000000000..ddd5dadaa --- /dev/null +++ b/Source/Components/ImageGlass.Base/Photoing/Animators/GifAnimator.cs @@ -0,0 +1,121 @@ +/* +ImageGlass Project - Image viewer for Windows +Copyright (C) 2017-2019 DUONG DIEU PHAP +Project homepage: https://imageglass.org + +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 . +*/ +using System.Drawing.Imaging; + +namespace ImageGlass.Base.Photoing.Animators; + +public class GifAnimator : ImgAnimator +{ + + private readonly Bitmap? _bitmap; + private int[] _frameDelays; // in millisecond + + private readonly int FRAME_DELAY_TAG = 0x5100; + private readonly int LOOP_COUNT_TAG = 20737; + + + /// + /// Initialize new instance of . + /// + public GifAnimator(Bitmap bmp) + { + lock (bmp) + { + _bitmap = bmp; + LoadGifMetadata(); + } + } + + + + // Protected virtual methods + #region Protected virtual methods + + protected override bool CanAnimate() + { + return _bitmap != null; + } + + + protected override TimeSpan GetFrameDelay(int frameIndex) + { + return TimeSpan.FromMilliseconds(_frameDelays[_frameIndex]); + } + + + protected override void UpdateFrame(int frameIndex) + { + lock (_bitmap) + { + // update frame + _bitmap.SetActiveTimeFrame(_frameIndex); + + TriggerFrameChangedEvent(_bitmap); + } + } + + + protected override void OnDisposing() + { + base.OnDisposing(); + + Array.Clear(_frameDelays); + } + + #endregion // Protected virtual methods + + + /// + /// Loads GIF metadata. + /// + private void LoadGifMetadata() + { + if (_bitmap == null) return; + + _frameCount = _bitmap.GetFrameCount(FrameDimension.Time); + _maxLoopCount = BitConverter.ToInt16(_bitmap.GetPropertyItem(LOOP_COUNT_TAG).Value, 0); + + var frameDelayData = _bitmap.GetPropertyItem(FRAME_DELAY_TAG)?.Value; + _frameDelays = new int[_frameCount]; + + for (int i = 0; i < _frameCount; i++) + { + // in millisecond + _frameDelays[i] = BitConverter.ToInt32(frameDelayData, i * 4) * 10; + + // Sometimes gifs have a zero frame delay, erroneously? + // These gifs seem to play differently depending on the program. + // I'll give them a default delay, as most gifs with 0 delay seem + // wayyyy to fast compared to other programs. + // + // 0.1 seconds appears to be chromes default setting... I'll use that + // + // KBR 20181009 Older GIF editors could set the delay to 0, relying on the behavior + // of Netscape Navigator to provide the default minimum of 10ms. On Windows 7, it + // appears necessary to enforce this same default minimum, with no negative impact + // on Windows 10. + // KBR 20181127 10ms is only if the image has a delay of 0. Other delays should not + // be modified (issue #458). + if (_frameDelays[i] < 1) + _frameDelays[i] = 100; + } + } + +} + diff --git a/Source/Components/ImageGlass.Base/Photoing/Animators/ImgAnimator.cs b/Source/Components/ImageGlass.Base/Photoing/Animators/ImgAnimator.cs new file mode 100644 index 000000000..ac01b3854 --- /dev/null +++ b/Source/Components/ImageGlass.Base/Photoing/Animators/ImgAnimator.cs @@ -0,0 +1,281 @@ +/* +ImageGlass Project - Image viewer for Windows +Copyright (C) 2010 - 2026 DUONG DIEU PHAP +Project homepage: https://imageglass.org + +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 . +*/ + +using ImageGlass.Base.WinApi; +using System.Runtime.InteropServices; + +namespace ImageGlass.Base.Photoing.Animators; + +/// +/// Image animator +/// +public class ImgAnimator : IDisposable +{ + + #region IDisposable Disposing + + public bool IsDisposed = false; + + protected virtual void Dispose(bool disposing) + { + if (IsDisposed) + return; + + if (disposing) + { + // Free any other managed objects here. + _enable = false; + + _frameIndex = 0; + _frameCount = 0; + _maxLoopCount = 0; + _loopIndex = 0; + + OnDisposing(); + } + + // Free any unmanaged objects here. + IsDisposed = true; + } + + public virtual void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + ~ImgAnimator() + { + Dispose(false); + } + + #endregion + + + protected int _frameCount = 0; + protected int _frameIndex = 0; + protected int _maxLoopCount = 0; // 0 - infinite loop + protected int _loopIndex = 0; + + protected bool _enable = false; + protected TimeSpan _minTickTimeInMillisecond = TimeSpan.FromMilliseconds(20); + + + /// + /// Occurs when the image frame is changed. The sender object contains the frame resource. + /// + public event EventHandler FrameChanged; + + + /// + /// Initialize new instance of . + /// + public ImgAnimator() + { + // request for high resolution gif animation + if (!TimerApi.HasRequestedRateAtLeastAsFastAs(10) && TimerApi.TimeBeginPeriod(10)) + { + SetTickTimeInMilliseconds(10); + } + } + + + // Public methods + #region Public methods + + /// + /// Starts animating the image frames. + /// + public void Animate() + { + if (!CanAnimate()) return; + + _enable = true; + + var _thHeartBeat = new Thread(HandleThreadHeartBeatTicked) + { + IsBackground = true, + Name = "heartbeat - ImageAnimator" + }; + _thHeartBeat.Start(); + } + + + /// + /// Stops image animation. + /// + public void StopAnimate() + { + _enable = false; + } + + #endregion // Public methods + + + // Protected virtual methods + #region Protected virtual methods + + /// + /// Verifies the animated source before calling . + /// + /// If false, does not proceed to call + protected virtual bool CanAnimate() + { + return true; + } + + + /// + /// Gets delay time of frame. + /// This function needs to be re-implemented in the inherited class. + /// + /// + protected virtual TimeSpan GetFrameDelay(int frameIndex) + { + throw new NotImplementedException(); + } + + + /// + /// Occurs when the thread of image frames ticked. + /// This function needs to be re-implemented in the inherited class. + /// + /// This is where to get and update image frame. + /// + /// + /// The frame index + /// + protected virtual void UpdateFrame(int frameIndex) + { + throw new NotImplementedException(); + } + + + /// + /// Occurs when the instance is being disposed. + /// + protected virtual void OnDisposing() + { + // + } + + #endregion // Protected virtual methods + + + // Private / Protected methods + #region Private / Protected methods + + /// + /// Process image frame tick. + /// + private void HandleThreadHeartBeatTicked() + { + var initSleepTime = GetSleepAmountInMilliseconds(GetFrameDelay(_frameIndex)); + Thread.Sleep(initSleepTime); + + while (_enable) + { + try + { + UpdateFrame(_frameIndex); + + var sleepTime = GetSleepAmountInMilliseconds(GetFrameDelay(_frameIndex)); + Thread.Sleep(sleepTime); + } + catch (ArgumentException) + { + // ignore errors that occur due to the image being disposed + } + catch (OutOfMemoryException) + { + // also ignore errors that occur due to running out of memory + } + catch (ExternalException) + { + // ignore + } + catch (InvalidOperationException) + { + // issue #373: a race condition caused this exception: deleting + // the image from underneath us could cause a collision in + // HighResolutionGif_animator. I've not been able to repro; + // hopefully this is the correct response. + + // ignore + } + + _frameIndex++; + if (_frameIndex >= _frameCount) + { + _frameIndex = 0; + _loopIndex++; + + if (_maxLoopCount > 0 && _loopIndex >= _maxLoopCount) + { + _enable = false; + return; + } + } + } + } + + + /// + /// Emits the event . + /// It passes to as a sender. + /// + /// Frame bitmap object + protected void TriggerFrameChangedEvent(object? frameBitmapObj) + { + FrameChanged?.Invoke(frameBitmapObj, EventArgs.Empty); + } + + + /// + /// Sets the tick for the animation thread. The thread may use a lower tick to ensure + /// the passed value is divisible by 10 (the gif format operates in units of 10 ms). + /// + /// Ideally should be a multiple of 10. + /// The actual tick value that will be used + private void SetTickTimeInMilliseconds(int value) + { + // 10 is the minimum value, as a GIF's lowest tick rate is 10ms + // + var newTickValue = Math.Max(10, (value / 10) * 10); + _minTickTimeInMillisecond = TimeSpan.FromMilliseconds(newTickValue); + } + + + /// + /// Given a delay amount, return either the minimum tick or delay, whichever is greater. + /// + /// the time to sleep during a tick in milliseconds + private TimeSpan GetSleepAmountInMilliseconds(TimeSpan delay) + { + if (delay > _minTickTimeInMillisecond) + { + return delay; + } + + return _minTickTimeInMillisecond; + } + + #endregion // Private / Protected methods + +} \ No newline at end of file diff --git a/Source/Components/ImageGlass.Base/Photoing/Codecs/AnimatedImg.cs b/Source/Components/ImageGlass.Base/Photoing/Codecs/AnimatedImg.cs new file mode 100644 index 000000000..a9670145a --- /dev/null +++ b/Source/Components/ImageGlass.Base/Photoing/Codecs/AnimatedImg.cs @@ -0,0 +1,86 @@ +/* +ImageGlass Project - Image viewer for Windows +Copyright (C) 2010 - 2026 DUONG DIEU PHAP +Project homepage: https://imageglass.org + +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 . +*/ +namespace ImageGlass.Base.Photoing.Codecs; + +/// +/// Initialize new instance of . +/// +public class AnimatedImg(IEnumerable frames, int? frameCount) : IDisposable +{ + + #region IDisposable Disposing + + public bool IsDisposed = false; + + protected virtual void Dispose(bool disposing) + { + if (IsDisposed) + return; + + if (disposing) + { + // Free any other managed objects here. + FrameCount = 0; + Frames = []; + } + + // Free any unmanaged objects here. + IsDisposed = true; + } + + public virtual void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + ~AnimatedImg() + { + Dispose(false); + } + + #endregion + + + /// + /// Gets frames list. + /// + public IEnumerable Frames { get; private set; } = frames; + + /// + /// Gets frams count. + /// + public int FrameCount { get; private set; } = frameCount ?? frames.Count(); + + + /// + /// Gets frame data. + /// + public AnimatedImgFrame? GetFrame(int frameIndex) + { + try + { + return Frames.ElementAtOrDefault(frameIndex); + } + catch { } + + return null; + } +} + diff --git a/Source/Components/ImageGlass.Base/Photoing/Codecs/AnimatedImgFrame.cs b/Source/Components/ImageGlass.Base/Photoing/Codecs/AnimatedImgFrame.cs new file mode 100644 index 000000000..23e5b6890 --- /dev/null +++ b/Source/Components/ImageGlass.Base/Photoing/Codecs/AnimatedImgFrame.cs @@ -0,0 +1,93 @@ +/* +ImageGlass Project - Image viewer for Windows +Copyright (C) 2010 - 2026 DUONG DIEU PHAP +Project homepage: https://imageglass.org + +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 . +*/ +namespace ImageGlass.Base.Photoing.Codecs; + +public class AnimatedImgFrame : IDisposable +{ + + #region IDisposable Disposing + + public bool IsDisposed = false; + + protected virtual void Dispose(bool disposing) + { + if (IsDisposed) + return; + + if (disposing) + { + // Free any other managed objects here. + Duration = TimeSpan.Zero; + + Bitmap?.Dispose(); + Bitmap = null; + } + + // Free any unmanaged objects here. + IsDisposed = true; + } + + public virtual void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + ~AnimatedImgFrame() + { + Dispose(false); + } + + #endregion + + + /// + /// Gets frame bitmap. + /// + public IDisposable? Bitmap { get; private set; } + + + /// + /// Gets frame duration in millisecond. + /// + public TimeSpan Duration { get; private set; } + + + /// + /// Initialize new instance of . + /// + /// + /// + public AnimatedImgFrame(IDisposable? bmpSrc, uint duration) + { + Bitmap = bmpSrc; + Duration = TimeSpan.FromMilliseconds(duration); + } + + /// + /// Initialize new instance of . + /// + /// + /// + public AnimatedImgFrame(IDisposable? bmpSrc, TimeSpan duration) + { + Bitmap = bmpSrc; + Duration = duration; + } +} diff --git a/Source/Components/ImageGlass.Base/Photoing/Codecs/CodecReadOptions.cs b/Source/Components/ImageGlass.Base/Photoing/Codecs/CodecReadOptions.cs new file mode 100644 index 000000000..5d2d9f949 --- /dev/null +++ b/Source/Components/ImageGlass.Base/Photoing/Codecs/CodecReadOptions.cs @@ -0,0 +1,109 @@ +/* +ImageGlass Project - Image viewer for Windows +Copyright (C) 2010 - 2026 DUONG DIEU PHAP +Project homepage: https://imageglass.org + +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 . +*/ +namespace ImageGlass.Base.Photoing.Codecs; + + +/// +/// Settings for loading image +/// +public record CodecReadOptions +{ + /// + /// Gets, sets the requested width of the image. + /// + public uint Width { get; set; } = 0; + + /// + /// Gets, sets the requested height of the image. + /// + public uint Height { get; set; } = 0; + + /// + /// Gets, sets the value indicates whether the color profile should be ignored. + /// + public bool IgnoreColorProfile { get; set; } = false; + + /// + /// Gets sets ColorProfile name of path + /// + public string ColorProfileName { get; set; } = nameof(ColorProfileOption.CurrentMonitorProfile); + + /// + /// Gets, sets the value indicates if the + /// should apply to all image files + /// + public bool ApplyColorProfileForAll { get; set; } = false; + + /// + /// Gets, sets the value indicates the embedded thumbnail of the RAW formats should be returned (if found). + /// + public bool UseEmbeddedThumbnailRawFormats { get; set; } = true; + + /// + /// Gets, sets the value indicates the embedded thumbnail of the non-RAW formats should be returned (if found). + /// + public bool UseEmbeddedThumbnailOtherFormats { get; set; } = false; + + /// + /// Gets, sets the minimum width of the embedded thumbnail to use for displaying + /// image when the setting or is true. + /// + public int EmbeddedThumbnailMinWidth { get; set; } = 0; + + /// + /// Gets, sets the minimum height of the embedded thumbnail to use for displaying + /// image when the setting or is true. + /// + public int EmbeddedThumbnailMinHeight { get; set; } = 0; + + /// + /// Gets, sets the value indicates that the incorrect rotation should be fixed + /// + public bool CorrectRotation { get; set; } = true; + + /// + /// Gets, sets the value indicates that the first frame of the image should be returned. + /// If it's null, the coder will decide. + /// + public bool? FirstFrameOnly { get; set; } = null; + + /// + /// Gets, sets the requested image frame index for metadata reading. + /// + public int? FrameIndex { get; set; } = null; + + /// + /// Gets, sets the value indicates that if the image dimension exceeds the supported value, + /// it will be scale down to value. + /// + public bool AutoScaleDownLargeImage { get; set; } = false; + + /// + /// Gets, sets the minimum image dimension to user WIC decoder if the format is supported. + /// + public int MinDimensionToUseWIC { get; set; } = int.MaxValue; + + + /// + /// Initializes instance. + /// + public CodecReadOptions() + { + } +} diff --git a/Source/Components/ImageGlass.Base/Photoing/Codecs/IgImgData.cs b/Source/Components/ImageGlass.Base/Photoing/Codecs/IgImgData.cs new file mode 100644 index 000000000..cb9e3c70b --- /dev/null +++ b/Source/Components/ImageGlass.Base/Photoing/Codecs/IgImgData.cs @@ -0,0 +1,154 @@ +/* +ImageGlass Project - Image viewer for Windows +Copyright (C) 2010 - 2026 DUONG DIEU PHAP +Project homepage: https://imageglass.org + +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 . +*/ +using ImageMagick; +using WicNet; + +namespace ImageGlass.Base.Photoing.Codecs; + + +/// +/// Contains image data and metadata to pass to frontend. +/// +public class IgImgData : IDisposable +{ + + #region IDisposable Disposing + + public bool IsDisposed = false; + + protected virtual void Dispose(bool disposing) + { + if (IsDisposed) + return; + + if (disposing) + { + // Free any other managed objects here. + Image?.Dispose(); + Image = null; + + if (Source is Bitmap bmp) + { + bmp.Dispose(); + } + else if (Source is WicBitmapDecoder decoder) + { + decoder.Dispose(); + } + else if (Source is AnimatedImg animatedImg) + { + foreach (var frame in animatedImg.Frames) + { + frame.Dispose(); + } + animatedImg.Dispose(); + } + Source = null; + + FrameCount = 0; + HasAlpha = false; + CanAnimate = false; + } + + // Free any unmanaged objects here. + IsDisposed = true; + } + + public virtual void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + ~IgImgData() + { + Dispose(false); + } + + #endregion + + + public WicBitmapSource? Image { get; set; } = null; + + /// + /// Represent other type of image source. + /// + public object? Source { get; set; } = null; + + /// + /// Checks if both and are null; + /// + public bool IsImageNull => Image == null && Source == null; + public int FrameCount { get; set; } = 0; + public bool HasAlpha { get; set; } = false; + public bool CanAnimate { get; set; } = false; + + + public IgImgData() { } + + + /// + /// Initializes instance with value. + /// + public IgImgData(IgMagickReadData data) + { + FrameCount = data.FrameCount; + + // multi-frames + if (data.MultiFrameImage != null) + { + HasAlpha = data.MultiFrameImage.Any(imgM => imgM.HasAlpha); + CanAnimate = data.CanAnimate; + + if (CanAnimate) + { + // fall back to use Magick.NET + data.MultiFrameImage.Coalesce(); + var frames = data.MultiFrameImage.AsEnumerable().Select(frame => + { + var duration = frame.AnimationDelay > 0 ? frame.AnimationDelay : 10; + duration = duration * 1000 / (uint)frame.AnimationTicksPerSecond; + + return new AnimatedImgFrame(frame.ToBitmap(), duration); + }); + + Source = new AnimatedImg(frames, data.FrameCount); + } + else + { + var bytes = data.MultiFrameImage.ToByteArray(MagickFormat.Tiff); + Source = WicBitmapDecoder.Load(new MemoryStream(bytes) { Position = 0 }); + } + } + // single frame: WIC bitmap source + else if (data.SingleFrameSource != null) + { + HasAlpha = true; // assume the image source has alpha + Image = data.SingleFrameSource; + } + // single frame: ImageMagick source + else + { + HasAlpha = data.SingleFrameImage?.HasAlpha ?? false; + + var bmpSrc = data.SingleFrameImage?.ToBitmapSource(); + Image = BHelper.ToWicBitmapSource(bmpSrc, HasAlpha); + } + } +} diff --git a/Source/Components/ImageGlass.Base/Photoing/Codecs/IgMagickReadData.cs b/Source/Components/ImageGlass.Base/Photoing/Codecs/IgMagickReadData.cs new file mode 100644 index 000000000..c3bf1ae72 --- /dev/null +++ b/Source/Components/ImageGlass.Base/Photoing/Codecs/IgMagickReadData.cs @@ -0,0 +1,81 @@ +/* +ImageGlass Project - Image viewer for Windows +Copyright (C) 2010 - 2026 DUONG DIEU PHAP +Project homepage: https://imageglass.org + +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 . +*/ +using ImageMagick; +using WicNet; + +namespace ImageGlass.Base.Photoing.Codecs; + + +/// +/// Contains Magick.NET data after the image file loaded. +/// +public class IgMagickReadData : IDisposable +{ + + #region IDisposable Disposing + + private bool _isDisposed = false; + + protected virtual void Dispose(bool disposing) + { + if (_isDisposed) + return; + + if (disposing) + { + // Free any other managed objects here. + MultiFrameImage?.Dispose(); + SingleFrameImage?.Dispose(); + + ExifProfile = null; + ColorProfile = null; + Extension = string.Empty; + } + + // Free any unmanaged objects here. + _isDisposed = true; + } + + public virtual void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + ~IgMagickReadData() + { + Dispose(false); + } + + #endregion + + + public int FrameCount { get; set; } = 0; + public string Extension { get; set; } = string.Empty; + + public bool CanAnimate { get; set; } = false; + + public MagickImageCollection? MultiFrameImage { get; set; } = null; + public MagickImage? SingleFrameImage { get; set; } = null; + public WicBitmapSource? SingleFrameSource { get; set; } = null; + + public IColorProfile? ColorProfile { get; set; } = null; + public IExifProfile? ExifProfile { get; set; } = null; + +} diff --git a/Source/Components/ImageGlass.Base/Photoing/Codecs/IgMetadata.cs b/Source/Components/ImageGlass.Base/Photoing/Codecs/IgMetadata.cs new file mode 100644 index 000000000..8152a708c --- /dev/null +++ b/Source/Components/ImageGlass.Base/Photoing/Codecs/IgMetadata.cs @@ -0,0 +1,81 @@ +/* +ImageGlass Project - Image viewer for Windows +Copyright (C) 2010 - 2026 DUONG DIEU PHAP +Project homepage: https://imageglass.org + +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 . +*/ +namespace ImageGlass.Base.Photoing.Codecs; + + +public class IgMetadata +{ + // File metadata + public string FilePath { get; set; } = string.Empty; + public string FileName { get; set; } = string.Empty; + public string FileExtension { get; set; } = string.Empty; + public string FolderPath { get; set; } = string.Empty; + public string FolderName { get; set; } = string.Empty; + + public DateTime FileCreationTime { get; set; } // local time + public DateTime FileLastAccessTime { get; set; } // local time + public DateTime FileLastWriteTime { get; set; } // local time + public string FileCreationTimeFormated => BHelper.FormatDateTime(FileCreationTime); + public string FileLastAccessTimeFormated => BHelper.FormatDateTime(FileLastAccessTime); + public string FileLastWriteTimeFormated => BHelper.FormatDateTime(FileLastWriteTime); + + /// + /// File size in bytes. + /// + public long FileSize { get; set; } = 0; + + /// + /// The formated file size. E.g. 32.09 MB. + /// + public string FileSizeFormated => BHelper.FormatSize(FileSize); + + + // Image data + public uint OriginalWidth { get; set; } = 0; + public uint OriginalHeight { get; set; } = 0; + public uint RenderedWidth { get; set; } = 0; + public uint RenderedHeight { get; set; } = 0; + + /// + /// Gets the frame index of this metadata. + /// + public uint FrameIndex { get; set; } = 0; + public int FrameCount { get; set; } = 0; + public bool HasAlpha { get; set; } = false; + public bool CanAnimate { get; set; } = false; + + public string ColorSpace { get; set; } = string.Empty; + public string ColorProfile { get; set; } = string.Empty; + + + // EXIF metadata + public int ExifRatingPercent { get; set; } = 0; + public DateTime? ExifDateTimeOriginal { get; set; } = null; // local time + public DateTime? ExifDateTime { get; set; } = null; // local time + public string? ExifImageDescription { get; set; } = null; + public string? ExifModel { get; set; } = null; + public string? ExifArtist { get; set; } = null; + public string? ExifCopyright { get; set; } = null; + public string? ExifSoftware { get; set; } = null; + public float? ExifExposureTime { get; set; } = null; + public float? ExifFNumber { get; set; } = null; + public int? ExifISOSpeed { get; set; } = null; + public float? ExifFocalLength { get; set; } = null; + +} diff --git a/Source/Components/ImageGlass.Base/Photoing/Codecs/IgPhoto.cs b/Source/Components/ImageGlass.Base/Photoing/Codecs/IgPhoto.cs new file mode 100644 index 000000000..3e6de50e3 --- /dev/null +++ b/Source/Components/ImageGlass.Base/Photoing/Codecs/IgPhoto.cs @@ -0,0 +1,279 @@ +/* +ImageGlass Project - Image viewer for Windows +Copyright (C) 2010 - 2026 DUONG DIEU PHAP +Project homepage: https://imageglass.org + +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 . +*/ + +using System.Diagnostics; + +namespace ImageGlass.Base.Photoing.Codecs; + +/// +/// Initialize instance +/// +/// +public class IgPhoto(string filePath) : IDisposable +{ + #region IDisposable Disposing + + public bool IsDisposed { get; private set; } = false; + + protected virtual void Dispose(bool disposing) + { + if (IsDisposed) + return; + + if (disposing) + { + // Free any other managed objects here. + Unload(); + } + + // Free any unmanaged objects here. + IsDisposed = true; + } + + public virtual void Dispose() + { + CancelLoading(); + Dispose(true); + GC.SuppressFinalize(this); + } + + ~IgPhoto() + { + Dispose(false); + } + + #endregion + + + private CancellationTokenSource? _tokenSrc; + + + #region Public properties + + /// + /// Gets, sets working file path. + /// + public string FilePath { get; set; } = filePath; + + /// + /// Gets file extension. E.g: .png. + /// + public string Extension => Path.GetExtension(FilePath); + + /// + /// Gets the error details + /// + public Exception? Error { get; private set; } = null; + + /// + /// Gets the value indicates that image loading is done. + /// + public bool IsDone { get; private set; } = false; + + /// + /// Gets, sets number of image frames. + /// + public int FrameCount { get; set; } = 0; + + /// + /// Gets the image data. + /// + public IgImgData ImgData { get; internal set; } = new(); + + /// + /// Gets, sets image metadata + /// + public IgMetadata? Metadata { get; set; } + + /// + /// Gets, sets the embedded video data. + /// If value is null (not cached), calling will load the video file. + /// + public byte[]? EmbeddedVideo { get; set; } + + /// + /// Gets, sets the hash key of the image. + /// + public string HashKey => BHelper.CreateUniqueFileKey(FilePath); + + #endregion + + + #region Public functions + + + /// + /// Load the photo. + /// + /// + /// + private async Task LoadImageAsync(CodecReadOptions? options = null) + { + // reset dispose status + IsDisposed = false; + + // reset done status + IsDone = false; + + // reset error + Error = null; + + options ??= new(); + + try + { + // load image data + Metadata ??= PhotoCodec.LoadMetadata(FilePath, options); + FrameCount = Metadata?.FrameCount ?? 0; + + if (options.FirstFrameOnly == null) + { + options = options with + { + FirstFrameOnly = FrameCount < 2, + }; + } + + // cancel if requested + if (_tokenSrc is not null && _tokenSrc.IsCancellationRequested) + { + _tokenSrc.Token.ThrowIfCancellationRequested(); + } + + // load image + ImgData = await PhotoCodec.LoadAsync(FilePath, options, null, _tokenSrc?.Token); + + // update metadata for JXR format + if (Metadata.FileExtension == ".JXR" + || Metadata.FileExtension == ".HDP" + || Metadata.FileExtension == ".WDP") + { + Metadata.RenderedWidth = Metadata.OriginalWidth = (uint)(ImgData.Image?.Width ?? 0); + Metadata.RenderedHeight = Metadata.OriginalHeight = (uint)(ImgData.Image?.Height ?? 0); + } + + // cancel if requested + if (_tokenSrc is not null && _tokenSrc.IsCancellationRequested) + { + _tokenSrc.Token.ThrowIfCancellationRequested(); + } + + // done loading + IsDone = true; + } + catch (Exception ex) when (ex is ObjectDisposedException or OperationCanceledException) + { + Unload(); + Dispose(); + } + catch (Exception ex) + { + // save the error + Error = ex; + + // done loading + IsDone = true; + } + } + + + /// + /// Read and load image into memory. + /// + public async Task LoadAsync( + CodecReadOptions? options = null, + CancellationTokenSource? tokenSrc = null) + { + _tokenSrc = tokenSrc ?? new(); + + await LoadImageAsync(options); + } + + /// + /// Load the embedded video. + /// + public async Task LoadEmbeddedVideoAsync(CancellationTokenSource? tokenSrc = null) + { + if (EmbeddedVideo is not null) return; + + // load the video data + EmbeddedVideo = await BHelper.GetLiveVideoAsync(FilePath, tokenSrc?.Token); + } + + + /// + /// Open the embedded video file. + /// + public async Task OpenEmbeddedVideoFileAsync(CancellationTokenSource? tokenSrc = null) + { + await LoadEmbeddedVideoAsync(tokenSrc); + + + // save the video file to temporary directory + var fileName = Path.GetFileNameWithoutExtension(FilePath); + var tempDir = App.ConfigDir(PathType.Dir, Dir.Temporary); + Directory.CreateDirectory(tempDir); + + var destFile = Path.Combine(tempDir, $"{fileName}_live-{HashKey}.mp4"); + if (!File.Exists(destFile)) + { + await File.WriteAllBytesAsync(destFile, EmbeddedVideo); + } + + + // open the video file + using var proc = Process.Start(new ProcessStartInfo() + { + FileName = destFile, + UseShellExecute = true, + }); + } + + + /// + /// Unload the image and reset the relevant info + /// + public void Unload() + { + // reset info + IsDone = false; + Error = null; + FrameCount = 0; + EmbeddedVideo = null; + + // unload image + ImgData?.Dispose(); + } + + + /// + /// Cancels image loading. + /// + public void CancelLoading() + { + try + { + _tokenSrc?.Cancel(); + } + catch (ObjectDisposedException) { } + } + + #endregion + +} diff --git a/Source/Components/ImageGlass.Base/Photoing/Codecs/ImgTransform.cs b/Source/Components/ImageGlass.Base/Photoing/Codecs/ImgTransform.cs new file mode 100644 index 000000000..5ff612845 --- /dev/null +++ b/Source/Components/ImageGlass.Base/Photoing/Codecs/ImgTransform.cs @@ -0,0 +1,114 @@ +/* +ImageGlass Project - Image viewer for Windows +Copyright (C) 2010 - 2026 DUONG DIEU PHAP +Project homepage: https://imageglass.org + +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 . +*/ +namespace ImageGlass.Base.Photoing.Codecs; + +public class ImgTransform +{ + private float _rotation = 0; + private FlipOptions _flipOptions = FlipOptions.None; + private bool _isColorInverted = false; + + + /// + /// Gets or sets the flip options, triggers the event when changed. + /// + public FlipOptions Flips + { + get => _flipOptions; + set + { + if (_flipOptions != value) + { + _flipOptions = value; + Changed?.Invoke(this, EventArgs.Empty); + } + } + } + + + /// + /// Gets or sets the rotation value, triggers the event when changed. + /// + public float Rotation + { + get => _rotation; + set + { + if (_rotation != value) + { + _rotation = value; + Changed?.Invoke(this, EventArgs.Empty); + } + } + } + + + /// + /// Gets or sets a value indicating whether the color is inverted. + /// Triggers the event when changed. + /// + public bool IsColorInverted + { + get => _isColorInverted; + set + { + if (_isColorInverted != value) + { + _isColorInverted = value; + Changed?.Invoke(this, EventArgs.Empty); + } + } + } + + + /// + /// Gets, sets frame index to apply the transformation to. + /// Use -1 to apply to all frames. + /// Default value is -1. + /// + public int FrameIndex { get; set; } = -1; + + + /// + /// Checks if there are changes. + /// + public bool HasChanges => Flips != FlipOptions.None + || Rotation != 0 + || IsColorInverted; + + + /// + /// Occurs when there is a change. + /// + public event EventHandler? Changed; + + + /// + /// Clears all pending changes. + /// + public void Clear() + { + _flipOptions = FlipOptions.None; + _rotation = 0; + _isColorInverted = false; + FrameIndex = -1; + + Changed?.Invoke(this, EventArgs.Empty); + } +} diff --git a/Source/Components/ImageGlass.Base/Photoing/Codecs/PhotoCodec.cs b/Source/Components/ImageGlass.Base/Photoing/Codecs/PhotoCodec.cs new file mode 100644 index 000000000..4daf11d4a --- /dev/null +++ b/Source/Components/ImageGlass.Base/Photoing/Codecs/PhotoCodec.cs @@ -0,0 +1,1563 @@ +/* +ImageGlass Project - Image viewer for Windows +Copyright (C) 2010 - 2026 DUONG DIEU PHAP +Project homepage: https://imageglass.org + +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 . +*/ +using DirectN; +using ImageGlass.WebP; +using ImageMagick; +using ImageMagick.Formats; +using PhotoSauce.MagicScaler; +using System.Runtime.CompilerServices; +using System.Text; +using WicNet; + +namespace ImageGlass.Base.Photoing.Codecs; + + +/// +/// Handles reading and writing image file formats. +/// +public static class PhotoCodec +{ + + #region Public functions + + /// + /// Loads metadata from file. + /// + /// Full path of the file + public static IgMetadata? LoadMetadata(string? filePath, CodecReadOptions? options = null) + { + FileInfo? fi = null; + var meta = new IgMetadata() { FilePath = filePath ?? string.Empty }; + + try + { + fi = new FileInfo(filePath); + } + catch { } + if (fi == null) return meta; + var ext = fi.Extension.ToUpperInvariant(); + + meta.FileName = fi.Name; + meta.FileExtension = ext; + meta.FolderPath = fi.DirectoryName ?? string.Empty; + meta.FolderName = Path.GetFileName(meta.FolderPath); + + meta.FileSize = fi.Length; + meta.FileCreationTime = fi.CreationTime; + meta.FileLastWriteTime = fi.LastWriteTime; + meta.FileLastAccessTime = fi.LastAccessTime; + + try + { + var settings = ParseSettings(options, false, filePath); + using var imgC = new MagickImageCollection(); + + if (filePath.Length > 260) + { + var allBytes = File.ReadAllBytes(filePath); + + imgC.Ping(allBytes, settings); + } + else + { + imgC.Ping(filePath, settings); + } + + meta.FrameIndex = 0; + meta.FrameCount = imgC.Count; + + if (imgC.Count > 0) + { + var frameIndex = options?.FrameIndex ?? 0; + + // Check if frame index is greater than upper limit + if (frameIndex >= imgC.Count) + frameIndex = 0; + + // Check if frame index is less than lower limit + else if (frameIndex < 0) + frameIndex = imgC.Count - 1; + + meta.FrameIndex = (uint)frameIndex; + using var imgM = imgC[frameIndex]; + + + // image size + meta.OriginalWidth = imgM.BaseWidth; + meta.OriginalHeight = imgM.BaseHeight; + + if (options?.AutoScaleDownLargeImage == true) + { + var newSize = GetMaxImageRenderSize(imgM.BaseWidth, imgM.BaseHeight); + + meta.RenderedWidth = (uint)newSize.Width; + meta.RenderedHeight = (uint)newSize.Height; + } + else + { + meta.RenderedWidth = imgM.Width; + meta.RenderedHeight = imgM.Height; + } + + + // image color + meta.HasAlpha = imgC.Any(i => i.HasAlpha); + meta.ColorSpace = imgM.ColorSpace.ToString(); + meta.CanAnimate = CheckAnimatedFormat(imgC, ext); + + + // EXIF profile + if (imgM.GetExifProfile() is IExifProfile exifProfile) + { + // ExifRatingPercent + meta.ExifRatingPercent = GetExifValue(exifProfile, ExifTag.RatingPercent); + + // ExifDateTimeOriginal + var dt = GetExifValue(exifProfile, ExifTag.DateTimeOriginal); + meta.ExifDateTimeOriginal = BHelper.ConvertDateTime(dt); + + // ExifDateTime + dt = GetExifValue(exifProfile, ExifTag.DateTime); + meta.ExifDateTime = BHelper.ConvertDateTime(dt); + + meta.ExifArtist = GetExifValue(exifProfile, ExifTag.Artist); + meta.ExifCopyright = GetExifValue(exifProfile, ExifTag.Copyright); + meta.ExifSoftware = GetExifValue(exifProfile, ExifTag.Software); + meta.ExifImageDescription = GetExifValue(exifProfile, ExifTag.ImageDescription); + meta.ExifModel = GetExifValue(exifProfile, ExifTag.Model); + meta.ExifISOSpeed = (int?)GetExifValue(exifProfile, ExifTag.ISOSpeed); + + var rational = GetExifValue(exifProfile, ExifTag.ExposureTime); + meta.ExifExposureTime = rational.Denominator == 0 + ? null + : rational.Numerator / rational.Denominator; + + rational = GetExifValue(exifProfile, ExifTag.FNumber); + meta.ExifFNumber = rational.Denominator == 0 + ? null + : rational.Numerator / rational.Denominator; + + rational = GetExifValue(exifProfile, ExifTag.FocalLength); + meta.ExifFocalLength = rational.Denominator == 0 + ? null + : rational.Numerator / rational.Denominator; + } + else + { + try + { + using var fs = File.OpenRead(filePath); + using var img = Image.FromStream(fs, false, false); + var enc = new ASCIIEncoding(); + + var EXIF_DateTimeOriginal = 0x9003; //36867 + var EXIF_DateTime = 0x0132; + + try + { + // get EXIF_DateTimeOriginal + var pi = img.GetPropertyItem(EXIF_DateTimeOriginal); + var dateTimeText = enc.GetString(pi.Value, 0, pi.Len - 1); + + if (DateTime.TryParseExact(dateTimeText, "yyyy:MM:dd HH:mm:ss", null, System.Globalization.DateTimeStyles.None, out var exifDateTimeOriginal)) + { + meta.ExifDateTimeOriginal = exifDateTimeOriginal; + } + } + catch { } + + + try + { + // get EXIF_DateTime + var pi = img.GetPropertyItem(EXIF_DateTime); + var dateTimeText = enc.GetString(pi.Value, 0, pi.Len - 1); + + if (DateTime.TryParseExact(dateTimeText, "yyyy:MM:dd HH:mm:ss", null, System.Globalization.DateTimeStyles.None, out var exifDateTime)) + { + meta.ExifDateTime = exifDateTime; + } + } + catch { } + } + catch { } + } + + + // Color profile + if (imgM.GetColorProfile() is IColorProfile colorProfile) + { + meta.ColorProfile = colorProfile.ColorSpace.ToString(); + + if (!string.IsNullOrWhiteSpace(colorProfile.Description)) + { + meta.ColorProfile = $"{colorProfile.Description} ({meta.ColorProfile})"; + } + } + } + } + catch { } + + return meta; + } + + + /// + /// Loads image file async. + /// + /// Full path of the file + /// Loading options + /// Cancellation token + public static async Task LoadAsync(string filePath, + CodecReadOptions? options = null, ImgTransform? transform = null, + CancellationToken? token = null) + { + options ??= new(); + var cancelToken = token ?? default; + + try + { + var (loadSuccessful, result, ext, settings) = ReadWithStream(filePath, options, transform); + + if (!loadSuccessful) + { + result = await LoadWithMagickImageAsync(filePath, ext, settings, options, transform, cancelToken); + } + + return result; + } + catch (OperationCanceledException) { } + + return new IgImgData(); + } + + + /// + /// Gets thumbnail from image. + /// + public static async Task GetThumbnailAsync(string filePath, uint width, uint height) + { + if (string.IsNullOrEmpty(filePath) || width == 0 || height == 0) return null; + + + var options = new CodecReadOptions() + { + Width = width, + Height = height, + MinDimensionToUseWIC = 0, + FirstFrameOnly = true, + UseEmbeddedThumbnailRawFormats = true, + UseEmbeddedThumbnailOtherFormats = true, + ApplyColorProfileForAll = false, + }; + var settings = ParseSettings(options, false, filePath); + var ext = Path.GetExtension(filePath).ToLowerInvariant(); + + + var imgData = await ReadMagickImageAsync(filePath, ext, settings, options, null, new()); + + if (imgData?.SingleFrameImage != null) + { + return imgData.SingleFrameImage.ToBitmap(); + } + + return null; + } + + + /// + /// Gets thumbnail from image. + /// + public static Bitmap? GetThumbnail(string filePath, uint width, uint height) + { + return BHelper.RunSync(() => GetThumbnailAsync(filePath, width, height)); + } + + + /// + /// Gets embedded thumbnail. + /// + public static WicBitmapSource? GetEmbeddedThumbnail(string filePath, bool rawThumbnail = true, bool exifThumbnail = true, CancellationToken token = default) + { + if (string.IsNullOrEmpty(filePath)) return null; + + try + { + token.ThrowIfCancellationRequested(); + } + catch (OperationCanceledException) { return null; } + + var settings = ParseSettings(new() { FirstFrameOnly = true }, false, filePath); + WicBitmapSource? result = null; + + using var imgM = new MagickImage(); + imgM.Ping(filePath, settings); + + + // get RAW embedded thumbnail + if (rawThumbnail) + { + try + { + token.ThrowIfCancellationRequested(); + + // try to get thumbnail + if (imgM.GetProfile("dng:thumbnail") is IImageProfile profile + && profile.ToReadOnlySpan() is ReadOnlySpan thumbnailData) + { + imgM.Read(thumbnailData, settings); + imgM.AutoOrient(); + result = BHelper.ToWicBitmapSource(imgM.ToBitmapSource(), imgM.HasAlpha); + } + } + catch (OperationCanceledException) { return null; } + catch { } + } + + + + // Use JPEG embedded thumbnail + if (exifThumbnail && result == null) + { + try + { + token.ThrowIfCancellationRequested(); + var exifProfile = imgM.GetExifProfile(); + + // Fetch the embedded thumbnail + using var thumbM = exifProfile?.CreateThumbnail(); + + if (thumbM != null) + { + thumbM.AutoOrient(); + result = BHelper.ToWicBitmapSource(thumbM.ToBitmapSource(), thumbM.HasAlpha); + } + } + catch (OperationCanceledException) { return null; } + catch { } + } + + return result; + } + + + /// + /// Gets base64 thumbnail from image + /// + public static string GetThumbnailBase64(string filePath, uint width, uint height) + { + var thumbnail = GetThumbnail(filePath, width, height); + + if (thumbnail != null) + { + using var imgM = new MagickImage(); + imgM.Read(thumbnail); + + return "data:image/png;charset=utf-8;base64," + imgM.ToBase64(MagickFormat.Png); + } + + return string.Empty; + } + + + /// + /// Reads and processes the SVG file, replaces #000 or #fff + /// by the corresponding hex color value of the . + /// + public static async Task ReadSvgWithMagickAsync(string svgFilePath, bool? darkMode, uint? width, uint? height, CancellationToken token = default) + { + // set up Magick settings + var settings = ParseSettings(new CodecReadOptions() + { + Width = width ?? 0, + Height = height ?? 0, + }, false, svgFilePath); + + var imgM = new MagickImage(); + + + // change SVG icon color if requested + if (darkMode != null) + { + // preprocess SVG content + using var fs = new StreamReader(svgFilePath); + var svg = await fs.ReadToEndAsync(token); + + if (darkMode.Value) + { + svg = svg.Replace("#000", "#fff"); + } + else + { + svg = svg.Replace("#fff", "#000"); + } + + using var ms = new MemoryStream(Encoding.UTF8.GetBytes(svg)); + imgM.Read(ms, settings); + } + else + { + await imgM.ReadAsync(svgFilePath, settings, token); + } + + + return imgM; + } + + + /// + /// Checks if the format can be written. + /// + public static bool CheckSupportFormatForSaving(string destFilePath) + { + return MagickFormatInfo.Create(destFilePath).SupportsWriting; + } + + + /// + /// Save as image file, use Magick.NET. + /// + /// Source filename to save + /// Destination filename + /// Options for reading image file + /// Changes for writing image file + /// Quality + /// + public static async Task SaveAsync(string srcFileName, string destFilePath, CodecReadOptions readOptions, ImgTransform? transform = null, uint quality = 100, CancellationToken token = default) + { + var ext = Path.GetExtension(destFilePath).ToUpperInvariant(); + + try + { + if (!CheckSupportFormatForSaving(destFilePath)) + { + throw new FileFormatException("IGE_001: Unsupported image format."); + } + + var settings = ParseSettings(readOptions, true, srcFileName); + + + using var imgData = await ReadMagickImageAsync( + srcFileName, + Path.GetExtension(srcFileName), + settings, + readOptions with + { + // Magick.NET auto-corrects the rotation when saving, + // so we don't need to correct it manually. + CorrectRotation = false, + }, transform, token); + + if (imgData.MultiFrameImage != null) + { + await imgData.MultiFrameImage.WriteAsync(destFilePath, token); + } + else if (imgData.SingleFrameImage != null) + { + imgData.SingleFrameImage.Quality = quality; + + // resize ICO file if it's larger than 256 + if (ext == ".ICO") + { + var imgW = imgData.SingleFrameImage.Width; + var imgH = imgData.SingleFrameImage.Height; + const int MAX_ICON_SIZE = 256; + + if (imgW > MAX_ICON_SIZE || imgH > MAX_ICON_SIZE) + { + var iconSize = GetMaxImageRenderSize(imgW, imgH, MAX_ICON_SIZE); + imgData.SingleFrameImage.Scale((uint)iconSize.Width, (uint)iconSize.Height); + } + } + + await imgData.SingleFrameImage.WriteAsync(destFilePath, token); + } + } + catch (OperationCanceledException) { } + } + + + /// + /// Save image file, use WIC if it supports, otherwise use Magick.NET. + /// + /// Source bitmap to save + /// Destination file path + /// Image transformation + /// JPEG/MIFF/PNG compression level + /// New image format + public static async Task SaveAsync(WicBitmapSource? srcBitmap, string destFilePath, ImgTransform? transform = null, uint quality = 100, MagickFormat format = MagickFormat.Unknown, CancellationToken token = default) + { + if (srcBitmap == null) return; + + try + { + token.ThrowIfCancellationRequested(); + + // transform image + srcBitmap = TransformImage(srcBitmap, transform); + + // get WIC encoder for the dest format + var encoder = WicEncoder.FromFileExtension(Path.GetExtension(destFilePath)); + + // if WIC supports this format + if (encoder != null) + { + srcBitmap.Save(destFilePath, encoder.ContainerFormat); + } + // use Magick.NET to save + else + { + // convert to Bitmap + using var bitmap = BHelper.ToGdiPlusBitmap(srcBitmap); + if (bitmap == null) return; + + // convert to MagickImage + using var imgM = new MagickImage(); + await Task.Run(() => + { + imgM.Read(bitmap); + imgM.Quality = quality; + }, token); + + + // write image data to file + token.ThrowIfCancellationRequested(); + if (format != MagickFormat.Unknown) + { + await imgM.WriteAsync(destFilePath, format, token); + } + else + { + await imgM.WriteAsync(destFilePath, token); + } + } + } + catch (OperationCanceledException) { } + } + + + /// + /// Exports image frames to files, using Magick.NET + /// + /// The full path of source file + /// The destination folder to save to + public static async IAsyncEnumerable<(int FrameNumber, string FileName)> SaveFramesAsync(string srcFilePath, string destFolder, [EnumeratorCancellation] CancellationToken token = default) + { + // create dirs unless it does not exist + Directory.CreateDirectory(destFolder); + + using var imgColl = new MagickImageCollection(srcFilePath); + var index = 0; + + foreach (var imgM in imgColl) + { + index++; + imgM.Quality = 100; + var newFilename = string.Empty; + + try + { + newFilename = Path.GetFileNameWithoutExtension(srcFilePath) + + " - " + index.ToString($"D{imgColl.Count.ToString().Length}") + + ".png"; + var destFilePath = Path.Combine(destFolder, newFilename); + + await imgM.WriteAsync(destFilePath, MagickFormat.Png, token); + } + catch (OperationCanceledException) { break; } + catch { } + + yield return (index, newFilename); + } + } + + + /// + /// Saves source bitmap image as base64 using Stream. + /// + /// Source bitmap + /// Source file extension, example: .png + /// Destination file + public static async Task SaveAsBase64Async(WicBitmapSource? srcBitmap, string srcExt, string destFilePath, ImgTransform? transform = null, CancellationToken token = default) + { + if (srcBitmap == null) return; + + var mimeType = BHelper.GetMIMEType(srcExt); + var header = $"data:{mimeType};base64,"; + var srcFormat = BHelper.GetWicContainerFormatFromExtension(srcExt); + + try + { + token.ThrowIfCancellationRequested(); + srcBitmap = TransformImage(srcBitmap, transform); + + token.ThrowIfCancellationRequested(); + + // convert bitmap to base64 + using var ms = new MemoryStream(); + srcBitmap.Save(ms, srcFormat); + var base64 = Convert.ToBase64String(ms.ToArray()); + + token.ThrowIfCancellationRequested(); + + // write base64 file + using var sw = new StreamWriter(destFilePath); + await sw.WriteAsync(header + base64).ConfigureAwait(false); + await sw.FlushAsync(token).ConfigureAwait(false); + sw.Close(); + } + catch (OperationCanceledException) { } + } + + + /// + /// Saves image file as base64. Uses Magick.NET if + /// has changes. Uses Stream if the format is supported, else uses Magick.NET. + /// + /// Source file path + /// Destination file path + public static async Task SaveAsBase64Async(string srcFilePath, string destFilePath, CodecReadOptions readOptions, ImgTransform? transform = null, CancellationToken token = default) + { + if (transform.HasChanges) + { + using var imgC = new MagickImageCollection(); + imgC.Ping(srcFilePath); + + if (imgC.Count == 1) + { + using var imgM = imgC[0]; + TransformImage(imgM, transform); + + using var wicSrc = BHelper.ToWicBitmapSource(imgM.ToBitmapSource(), imgM.HasAlpha); + var ext = Path.GetExtension(srcFilePath); + + await SaveAsBase64Async(wicSrc, ext, destFilePath, null, token); + return; + } + } + + + var srcExt = Path.GetExtension(srcFilePath).ToLowerInvariant(); + var mimeType = BHelper.GetMIMEType(srcExt); + + try + { + token.ThrowIfCancellationRequested(); + + // for basic MIME formats + if (!string.IsNullOrEmpty(mimeType)) + { + // read source file content + using var fs = new FileStream(srcFilePath, FileMode.Open, FileAccess.Read); + var data = new byte[fs.Length]; + await fs.ReadExactlyAsync(data.AsMemory(0, (int)fs.Length), token); + fs.Close(); + + token.ThrowIfCancellationRequested(); + + // convert bitmap to base64 + var header = $"data:{mimeType};base64,"; + var base64 = Convert.ToBase64String(data); + + token.ThrowIfCancellationRequested(); + + // write base64 file + using var sw = new StreamWriter(destFilePath); + await sw.WriteAsync(header + base64); + await sw.FlushAsync(token).ConfigureAwait(false); + sw.Close(); + + return; + } + + + // for not supported formats + var bmp = await LoadAsync(srcFilePath, readOptions, transform, token); + await SaveAsBase64Async(bmp.Image, srcExt, destFilePath, null, token); + } + catch (OperationCanceledException) { } + } + + + /// + /// Applies changes from . + /// + public static WicBitmapSource? TransformImage(WicBitmapSource? bmpSrc, ImgTransform? transform) + { + if (bmpSrc == null || transform == null) return bmpSrc; + + // list of flips + var flips = new List(); + if (transform.Flips.HasFlag(FlipOptions.Horizontal)) + { + flips.Add(WICBitmapTransformOptions.WICBitmapTransformFlipHorizontal); + } + if (transform.Flips.HasFlag(FlipOptions.Vertical)) + { + flips.Add(WICBitmapTransformOptions.WICBitmapTransformFlipVertical); + } + + + // apply flips + foreach (var flip in flips) + { + bmpSrc.FlipRotate(flip); + } + + + // rotate + var rotate = transform.Rotation switch + { + 90 => WICBitmapTransformOptions.WICBitmapTransformRotate90, + -270 => WICBitmapTransformOptions.WICBitmapTransformRotate90, + + -90 => WICBitmapTransformOptions.WICBitmapTransformRotate270, + 270 => WICBitmapTransformOptions.WICBitmapTransformRotate270, + + 180 => WICBitmapTransformOptions.WICBitmapTransformRotate180, + -180 => WICBitmapTransformOptions.WICBitmapTransformRotate180, + + _ => WICBitmapTransformOptions.WICBitmapTransformRotate0, + }; + + if (rotate != WICBitmapTransformOptions.WICBitmapTransformRotate0) + { + bmpSrc.FlipRotate(rotate); + } + + + // invert color + if (transform.IsColorInverted) + { + var newBmp = new WicBitmapSource( + bmpSrc.Width, bmpSrc.Height, + WicPixelFormat.GUID_WICPixelFormat32bppPRGBA); + + using var dc = newBmp.CreateDeviceContext(); + using var effect = dc.CreateEffect(Direct2DEffects.CLSID_D2D1Invert); + + using var cb = dc.CreateBitmapFromWicBitmap(bmpSrc.ComObject); + { + effect.SetInput(cb, 0); + dc.BeginDraw(); + dc.DrawImage(effect); + dc.EndDraw(); + } + + bmpSrc.Dispose(); + bmpSrc = newBmp; + } + + return bmpSrc; + } + + + /// + /// Initialize Magick.NET. + /// + public static void InitMagickNET() + { + OpenCL.IsEnabled = true; + ResourceLimits.LimitMemory(new Percentage(75)); + } + + + /// + /// Checks if the supplied file name is supported for lossless compression using Magick.NET. + /// + public static bool IsLosslessCompressSupported(string? filePath) + { + var opt = new ImageOptimizer() + { + OptimalCompression = true, + }; + + return opt.IsSupported(filePath); + } + + /// + /// Performs lossless compression on the specified file using Magick.NET. + /// If the new file size is not smaller, the file won't be overwritten. + /// + /// True when the image could be compressed otherwise false. + /// + public static bool LosslessCompress(string? filePath) + { + if (string.IsNullOrWhiteSpace(filePath)) return false; + + var fi = new FileInfo(filePath); + var opt = new ImageOptimizer() + { + OptimalCompression = true, + }; + + // check if the format is supported + if (!opt.IsSupported(fi)) throw new NotSupportedException("IGE_002: Unsupported image format."); + + return opt.LosslessCompress(fi); + } + + #endregion // Public functions + + + + #region Private functions + + /// + /// Checks if the image data is animated format. + /// + /// + /// File extension, e.g: .gif + private static bool CheckAnimatedFormat(MagickImageCollection imgC, string? ext) + { + var isAnimatedExtension = ext == ".GIF" || ext == ".GIFV" || ext == ".WEBP" || ext == ".JXL"; + + var canAnimate = imgC.Count > 1 + && (isAnimatedExtension || imgC.Any(i => i.GifDisposeMethod != GifDisposeMethod.Undefined)); + + return canAnimate; + } + + + /// + /// Read image file using stream + /// + private static (bool loadSuccessful, IgImgData result, string ext, MagickReadSettings settings) ReadWithStream(string filePath, CodecReadOptions? options = null, ImgTransform? transform = null, IgMetadata? metadata = null) + { + options ??= new(); + var loadSuccessful = true; + + metadata ??= LoadMetadata(filePath, options); + var ext = Path.GetExtension(filePath).ToUpperInvariant(); + var settings = ParseSettings(options, false, filePath); + + var result = new IgImgData() + { + FrameCount = metadata?.FrameCount ?? 0, + HasAlpha = metadata?.HasAlpha ?? false, + CanAnimate = metadata?.CanAnimate ?? false, + }; + + + #region Read image data + switch (ext) + { + case ".TXT": // base64 string + case ".B64": + var base64Content = string.Empty; + using (var fs = new StreamReader(filePath)) + { + base64Content = fs.ReadToEnd(); + } + + if (result.CanAnimate) + { + result.Source = BHelper.ToGdiPlusBitmapFromBase64(base64Content); + } + else + { + result.Image = BHelper.ToWicBitmapSource(base64Content); + + if (result.FrameCount == 1) + { + result.Image = TransformImage(result.Image, transform); + } + } + break; + + case ".GIF": + case ".GIFV": + case ".FAX": + try + { + // Note: Using WIC is much faster than using MagickImageCollection + if (result.CanAnimate) + { + result.Source = BHelper.ToGdiPlusBitmap(filePath); + } + // multiple frame + else if (result.FrameCount > 0) + { + result.Source = WicBitmapDecoder.Load(filePath); + } + // single frame + else + { + result.Image = WicBitmapSource.Load(filePath); + } + } + catch + { + loadSuccessful = false; + } + break; + + case ".WEBP": + try + { + using var webp = new WebPWrapper(); + + if (result.CanAnimate) + { + var aniWebP = webp.AnimLoad(filePath); + var frames = aniWebP.Select(frame => + { + var duration = frame.Duration > 0 ? frame.Duration : 100; + return new AnimatedImgFrame(frame.Bitmap, (uint)duration); + }); + + result.Source = new AnimatedImg(frames, result.FrameCount); + } + else + { + using var webpBmp = webp.Load(filePath); + result.Image = BHelper.ToWicBitmapSource(webpBmp); + } + } + catch + { + loadSuccessful = false; + } + break; + + case ".JXR": + case ".HDP": + case ".WDP": + try + { + var wic = WicBitmapSource.Load(filePath); + + if (options.IgnoreColorProfile) + { + result.Image = wic; + } + else + { + var ms = BHelper.ToMemoryStream(wic); + + var imgM = new MagickImage(ms); + var profiles = GetProfiles(imgM); + var thumbM = ProcessMagickImageAndReturnThumbnail(imgM, options, ext, true, profiles.ColorProfile, profiles.ExifProfile); + + if (thumbM != null) + { + imgM?.Dispose(); + imgM = thumbM; + } + + + // apply final changes + TransformImage(imgM, transform); + result.Image = BHelper.ToWicBitmapSource(imgM.ToBitmapSource()); + } + } + catch + { + loadSuccessful = false; + } + break; + + default: + loadSuccessful = false; + + break; + } + #endregion + + + // apply size setting + if (options.Width > 0 && options.Height > 0) + { + using var imgM = new MagickImage(); + + if (result.Image != null) + { + if (result.Image.Width > options.Width || result.Image.Height > options.Height) + { + imgM.Read(result.Image.CopyPixels(0, 0, result.Image.Width, result.Image.Height)); + + ApplySizeSettings(imgM, options); + + result.Image = BHelper.ToWicBitmapSource(imgM.ToBitmapSource(), imgM.HasAlpha); + } + } + else if (result.Source is Bitmap bmp) + { + if (bmp.Width > options.Width || bmp.Height > options.Height) + { + imgM.Read(bmp); + + ApplySizeSettings(imgM, options); + + result.Source = imgM.ToBitmap(); + } + } + } + + + return (loadSuccessful, result, ext, settings); + } + + + /// + /// Loads image file with Magick.NET + /// + private static async Task LoadWithMagickImageAsync(string filename, string ext, + MagickReadSettings settings, CodecReadOptions options, ImgTransform? transform, CancellationToken cancelToken) + { + var data = await ReadMagickImageAsync(filename, ext, settings, options, transform, cancelToken); + var result = new IgImgData(data); + + return result; + } + + + /// + /// Reads and processes image file with Magick.NET. + /// + private static async Task ReadMagickImageAsync( + string filePath, string ext, MagickReadSettings settings, CodecReadOptions options, + ImgTransform? transform, CancellationToken cancelToken) + { + var result = new IgMagickReadData() { Extension = ext }; + var imgColl = new MagickImageCollection(); + imgColl.Ping(filePath, settings); + + // standardize first frame reading option + result.FrameCount = imgColl.Count; + result.CanAnimate = CheckAnimatedFormat(imgColl, ext); + bool readFirstFrameOnly; + + if (options.FirstFrameOnly == null) + { + readFirstFrameOnly = imgColl.Count < 2; + } + else + { + readFirstFrameOnly = options.FirstFrameOnly.Value; + } + + + // read all frames + if (imgColl.Count > 1 && readFirstFrameOnly is false) + { + await imgColl.ReadAsync(filePath, settings, cancelToken); + + var i = 0; + foreach (var imgFrameM in imgColl) + { + using var imgThumbFrameM = ProcessMagickImageAndReturnThumbnail((MagickImage)imgFrameM, options, ext, false, null, null); + + // apply transformation + if (i == transform?.FrameIndex || transform?.FrameIndex == -1) + { + TransformImage(imgFrameM, transform); + } + + i++; + } + + result.MultiFrameImage = imgColl; + return result; + } + + + // read a single frame only + var imgM = new MagickImage(); + var hasRequestedThumbnail = false; + + // get image profiles + var profiles = GetProfiles(imgColl[0]); + result.ColorProfile = profiles.ColorProfile; + result.ExifProfile = profiles.ExifProfile; + + + if (options.UseEmbeddedThumbnailRawFormats is true) + { + var profile = imgColl[0].GetProfile("dng:thumbnail"); + + try + { + // try to get thumbnail + if (profile != null + && profile.ToByteArray() is byte[] thumbnailData) + { + imgM.Ping(thumbnailData); + + // check min size + if (imgM.Width > options.EmbeddedThumbnailMinWidth + && imgM.Height > options.EmbeddedThumbnailMinHeight) + { + imgM.Read(thumbnailData, settings); + hasRequestedThumbnail = true; + } + } + } + catch { } + } + + if (!hasRequestedThumbnail) + { + imgM.Dispose(); + imgM = null; + + // check if the image size is not huge + var imgWidth = imgColl[0].BaseWidth; + var imgHeight = imgColl[0].BaseHeight; + var isHuge = imgWidth >= options.MinDimensionToUseWIC + || imgHeight >= options.MinDimensionToUseWIC; + var canOpenWithWIC = WicDecoder.SupportsFileExtensionForDecoding(ext); + + // use WIC to load huge image + if (isHuge && canOpenWithWIC) + { + // we will open with WIC later + } + else + { + imgM = (MagickImage)await InitializeSingleMagickImageAsync(filePath, + imgWidth, imgHeight, settings, options, cancelToken); + } + } + + if (imgM != null) + { + // process image + var thumbM = ProcessMagickImageAndReturnThumbnail(imgM, options, ext, true, result.ColorProfile, result.ExifProfile); + if (thumbM != null) + { + imgM.Dispose(); + imgM = thumbM; + } + + // apply final changes + TransformImage(imgM, transform); + + result.SingleFrameImage = imgM; + } + // use WIC to load huge image + else + { + var bmpSrc = WicBitmapSource.Load(filePath); + + // apply final changes + TransformImage(bmpSrc, transform); + + result.SingleFrameSource = bmpSrc; + } + + + imgColl.Dispose(); + + return result; + } + + + /// + /// Initialize the single-frame , + /// quickly resize the image to fit the + /// according to the . + /// + public static async Task InitializeSingleMagickImageAsync( + string srcFilePath, uint srcWidth, uint srcHeight, + MagickReadSettings settings, CodecReadOptions options, CancellationToken cancelToken) + { + var imgM = new MagickImage(); + + // the image is larger than the supported dimension + var isSizeTooLarge = srcWidth > Const.MAX_IMAGE_DIMENSION + || srcHeight > Const.MAX_IMAGE_DIMENSION; + + if (!isSizeTooLarge || !options.AutoScaleDownLargeImage) + { + await imgM.ReadAsync(srcFilePath, settings, cancelToken); + return imgM; + } + + + // try to use MagicScaler for better performance + #region Resize with MagicScaler + + FileStream? fs = null; + var tempFilePath = Path.Combine(Path.GetTempPath(), + $"temp_{DateTime.UtcNow:yyyy-MM-dd-hh-mm-ss}{Path.GetExtension(srcFilePath)}"); + + try + { + var resizerSettings = new ProcessImageSettings() + { + ColorProfileMode = ColorProfileMode.Preserve, + OrientationMode = OrientationMode.Preserve, + ResizeMode = CropScaleMode.Contain, + Width = Const.MAX_IMAGE_DIMENSION, + Height = Const.MAX_IMAGE_DIMENSION, + HybridMode = HybridScaleMode.Turbo, + }; + + + fs = File.Open(tempFilePath, FileMode.Create); + + + // perform resizing + await Task.Run(() => + { + _ = MagicImageProcessor.ProcessImage(srcFilePath, fs, resizerSettings); + }, cancelToken); + + + // reset stream position + fs.Position = 0; + } + catch { } + + + // successfully resized with MagicScaler + if (fs != null) + { + await imgM.ReadAsync(fs, settings, cancelToken); + await fs.DisposeAsync(); + + // delete the temp file + File.Delete(tempFilePath); + + return imgM; + } + #endregion // Resize with MagicScaler + + + // switch to Magick.NET if MagicScaler does not support + #region Resize with Magick.NET + + // load full image data + await imgM.ReadAsync(srcFilePath, settings, cancelToken); + + var newSize = GetMaxImageRenderSize(imgM.BaseWidth, imgM.BaseHeight); + imgM.Scale((uint)newSize.Width, (uint)newSize.Height); + + return imgM; + + #endregion // Resize with Magick.NET + + } + + + /// + /// Gets maximum image dimention. + /// + private static Size GetMaxImageRenderSize(uint srcWidth, uint srcHeight, uint maxSize = Const.MAX_IMAGE_DIMENSION) + { + var widthScale = 1f; + var heightScale = 1f; + + if (srcWidth > maxSize) + { + widthScale = 1f * maxSize / srcWidth; + } + + if (srcHeight > maxSize) + { + heightScale = 1f * maxSize / srcHeight; + } + + var scale = Math.Min(widthScale, heightScale); + var newW = (int)(srcWidth * scale); + var newH = (int)(srcHeight * scale); + + return new Size(newW, newH); + } + + + /// + /// Gets Color profile & Exif profile. + /// + public static (IColorProfile? ColorProfile, IExifProfile? ExifProfile) GetProfiles(IMagickImage imgM) + { + IColorProfile? colorProfile = null; + IExifProfile? exifProfile = null; + + try + { + // get the color profile of image + colorProfile = imgM.GetColorProfile(); + + // Get Exif information + exifProfile = imgM.GetExifProfile(); + } + catch { } + + return (colorProfile, exifProfile); + } + + + /// + /// Processes single-frame Magick image + /// + /// Input Magick image to process + private static MagickImage? ProcessMagickImageAndReturnThumbnail(MagickImage refImgM, + CodecReadOptions options, string ext, bool requestThumbnail, + IColorProfile? colorProfile, IExifProfile? exifProfile) + { + IMagickImage? thumbM = null; + + // preprocess image, read embedded thumbnail if any + refImgM.Quality = 100; + + // Use embedded thumbnails if specified + if (requestThumbnail && exifProfile != null && options.UseEmbeddedThumbnailOtherFormats) + { + // Fetch the embedded thumbnail + thumbM = exifProfile.CreateThumbnail(); + if (thumbM != null + && thumbM.Width > options.EmbeddedThumbnailMinWidth + && thumbM.Height > options.EmbeddedThumbnailMinHeight) + { + if (options.CorrectRotation) thumbM.AutoOrient(); + + ApplySizeSettings(thumbM, options); + } + else + { + thumbM?.Dispose(); + thumbM = null; + } + } + + // Revert to source image if an embedded thumbnail with required size was not found. + if (!requestThumbnail || thumbM == null) + { + // resize the image + ApplySizeSettings(refImgM, options); + + // for HEIC/HEIF, PreserveOrientation must be false + // see https://github.com/d2phap/ImageGlass/issues/1928 + if (options.CorrectRotation) refImgM.AutoOrient(); + + // if always apply color profile + // or only apply color profile if there is an embedded profile + if (options.ApplyColorProfileForAll || colorProfile != null) + { + var imgColor = BHelper.GetColorProfile(options.ColorProfileName); + + if (imgColor != null) + { + refImgM.TransformColorSpace( + //set default color profile to sRGB + colorProfile ?? ColorProfiles.SRGB, + imgColor); + } + } + + + // make sure the output color space is not CMYK + if (refImgM.ColorSpace == ColorSpace.CMYK) + { + refImgM.ColorSpace = ColorSpace.sRGB; + } + } + + + return (MagickImage?)thumbM; + } + + + /// + /// Applies the size settings + /// + private static void ApplySizeSettings(IMagickImage imgM, CodecReadOptions options) + { + if (options.Width > 0 && options.Height > 0) + { + if (imgM.BaseWidth > options.Width || imgM.BaseHeight > options.Height) + { + imgM.Thumbnail(options.Width, options.Height); + } + } + } + + + /// + /// Applies changes from . + /// + private static void TransformImage(IMagickImage imgM, ImgTransform? transform = null) + { + if (transform == null) return; + + // rotate + if (transform.Rotation != 0) + { + imgM.Rotate(transform.Rotation); + } + + // flip + if (transform.Flips.HasFlag(FlipOptions.Horizontal)) + { + imgM.Flop(); + } + if (transform.Flips.HasFlag(FlipOptions.Vertical)) + { + imgM.Flip(); + } + + // invert color + if (transform.IsColorInverted) + { + imgM.Negate(Channels.RGB); + } + } + + + /// + /// Parse to + /// + private static MagickReadSettings ParseSettings(CodecReadOptions? options, bool writePurpose, string filename = "") + { + options ??= new(); + + var ext = Path.GetExtension(filename).ToUpperInvariant(); + var settings = new MagickReadSettings + { + // https://github.com/dlemstra/Magick.NET/issues/1077 + SyncImageWithExifProfile = true, + SyncImageWithTiffProperties = true, + }; + + if (ext.Equals(".SVG", StringComparison.OrdinalIgnoreCase)) + { + settings.SetDefine("svg:xml-parse-huge", "true"); + settings.Format = MagickFormat.Rsvg; + settings.BackgroundColor = MagickColors.Transparent; + } + else if (ext.Equals(".SVGZ", StringComparison.OrdinalIgnoreCase)) + { + settings.Format = MagickFormat.Svgz; + settings.BackgroundColor = MagickColors.Transparent; + } + else if (ext.Equals(".HEIC", StringComparison.OrdinalIgnoreCase)) + { + settings.SetDefines(new HeicReadDefines() + { + MaxChildrenPerBox = 500, + }); + } + else if (ext.Equals(".JP2", StringComparison.OrdinalIgnoreCase)) + { + settings.SetDefines(new Jp2ReadDefines + { + QualityLayers = 100, + }); + } + else if (ext.Equals(".TIF", StringComparison.OrdinalIgnoreCase) + || ext.Equals(".TIFF", StringComparison.OrdinalIgnoreCase)) + { + settings.SetDefines(new TiffReadDefines + { + IgnoreTags = [ + // Issue https://github.com/d2phap/ImageGlass/issues/1454 + "34022", // ColorTable + "34025", // ImageColorValue + "34026", // BackgroundColorValue + + // Issue https://github.com/d2phap/ImageGlass/issues/1181 + "32928", + + // Issue https://github.com/d2phap/ImageGlass/issues/1583 + "32932", // Wang Annotation + // Issue https://github.com/d2phap/ImageGlass/issues/1617 + "34031", // TrapIndicator + ], + }); + } + else if (ext.Equals(".APNG", StringComparison.OrdinalIgnoreCase)) + { + settings.Format = MagickFormat.APng; + } + + if (options.Width > 0 && options.Height > 0) + { + settings.Width = options.Width; + settings.Height = options.Height; + + if (ext == ".JPG" || ext == ".JPEG" || ext == ".JPE" || ext == ".JFIF") + { + settings.SetDefines(new JpegReadDefines() + { + Size = new MagickGeometry(options.Width, options.Height), + }); + } + } + + // Fixed #708: length and filesize do not match + settings.SetDefines(new BmpReadDefines + { + IgnoreFileSize = true, + }); + + // Fix RAW color + settings.SetDefines(new DngReadDefines() + { + UseCameraWhiteBalance = true, + OutputColor = DngOutputColor.SRGB, + ReadThumbnail = true, + }); + + + + if (writePurpose) + { + if (ext == ".TIF" || ext == ".TIFF") + { + settings.SetDefines(new TiffWriteDefines + { + WriteLayers = true, + PreserveCompression = true, + }); + } + else if (ext == ".WEBP") + { + settings.SetDefines(new WebPWriteDefines + { + Lossless = true, + ThreadLevel = true, + AlphaQuality = 100, + }); + } + } + + return settings; + } + + + /// + /// Get EXIF value + /// + private static T? GetExifValue(IExifProfile? profile, ExifTag tag, T? defaultValue = default) + { + if (profile == null) return default; + + var exifValue = profile.GetValue(tag); + if (exifValue == null) return defaultValue; + + return exifValue.Value; + } + + + #endregion // Private functions + + +} diff --git a/Source/Components/ImageGlass.Base/Photoing/Services/ImageBooster.cs b/Source/Components/ImageGlass.Base/Photoing/Services/ImageBooster.cs new file mode 100644 index 000000000..84724449a --- /dev/null +++ b/Source/Components/ImageGlass.Base/Photoing/Services/ImageBooster.cs @@ -0,0 +1,651 @@ +/* +ImageGlass Project - Image viewer for Windows +Copyright (C) 2010 - 2026 DUONG DIEU PHAP +Project homepage: https://imageglass.org + +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 . +*/ + +using ImageGlass.Base.Photoing.Codecs; +using System.ComponentModel; + +namespace ImageGlass.Base.Services; + + +/// +/// Image booster service. +/// +public class ImageBooster : IDisposable +{ + #region IDisposable Disposing + + private bool _disposed = false; + + protected virtual void Dispose(bool disposing) + { + if (_disposed) + return; + + if (disposing) + { + // stop the worker + IsRunWorker = false; + + // Free any other managed objects here. + // clear list and release resources + Reset(); + + Worker?.Dispose(); + } + + // Free any unmanaged objects here. + _disposed = true; + } + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + ~ImageBooster() + { + Dispose(false); + } + + #endregion + + + #region PRIVATE PROPERTIES + + /// + /// Image booster background service + /// + private readonly BackgroundWorker Worker = new(); + + /// + /// Controls worker state + /// + private bool IsRunWorker { get; set; } = false; + + /// + /// The list of Imgs + /// + private List ImgList { get; } = []; + + /// + /// The list of image index that waiting for loading + /// + private List QueuedList { get; } = []; + + /// + /// The list of image index that waiting for releasing resource + /// + private List FreeList { get; } = []; + + + #endregion + + + #region PUBLIC PROPERTIES + + /// + /// Gets, sets codec read options + /// + public CodecReadOptions ReadOptions { get; set; } = new(); + + /// + /// Gets, sets the distinct directories list + /// + public List DistinctDirs { get; set; } = []; + + /// + /// Gets length of Img list + /// + public int Length => ImgList.Count; + + /// + /// Get file paths list + /// + public List FilePaths => ImgList.Select(i => i.FilePath).ToList(); + + /// + /// Gets, sets the list of formats that only load the first page forcefully. + /// + public HashSet SingleFrameFormats { get; set; } = []; + + /// + /// Gets, sets the number of maximum items in queue list for 1 direction (Next or Back navigation). + /// The maximum number of items in queue list is 2x + 1. + /// + public int MaxQueue { get; set; } = 1; + + /// + /// Gets, sets the maximum image dimension to cache. + /// If this value is less than or equals 0, the option will be ignored. + /// + public int MaxImageDimensionToCache { get; set; } = 0; + + /// + /// Gets, sets the maximum image file size (in MB) to cache. + /// If this value is less than or equals 0, the option will be ignored. + /// + public float MaxFileSizeInMbToCache { get; set; } = 0f; + + + /// + /// Occurs when the image is loaded. + /// + public event EventHandler? OnFinishLoadingImage; + + #endregion + + + /// + /// Initializes instance. + /// + /// + public ImageBooster(IEnumerable? list = null) + { + if (list != null) + { + Add(list); + } + + // background worker + IsRunWorker = true; + Worker.RunWorkerAsync(RunBackgroundWorker()); + } + + + #region PRIVATE FUNCTIONS + + /// + /// Preloads the images in . + /// + private async Task RunBackgroundWorker() + { + while (IsRunWorker) + { + if (QueuedList.Count > 0) + { + // pop out the first item + var index = QueuedList[0]; + var img = ImgList[index]; + QueuedList.RemoveAt(0); + + + if (!img.IsDone) + { + // start loading image file + await img.LoadAsync(ReadOptions with + { + FirstFrameOnly = SingleFrameFormats.Contains(img.Extension), + }).ConfigureAwait(false); + } + } + + await Task.Delay(10).ConfigureAwait(false); + } + } + + + /// + /// Add index of the image to queue list + /// + /// Current index of image list + /// Include current index in the queue list + private List GetQueueList(int index, bool includeCurrentIndex) + { + // check valid index + if (index < 0 || index >= ImgList.Count) return []; + + var list = new HashSet(); + if (includeCurrentIndex) + { + list.Add(index); + } + + var maxCachedItems = (MaxQueue * 2) + 1; + var iRight = index; + var iLeft = index; + + // add index in the range in order: index -> right -> left -> ... + for (var i = 0; list.Count < maxCachedItems && list.Count < ImgList.Count; i++) + { + // if i is even number + if ((i & 1) == 0) + { + // add right item: [index + 1; ...; to] + iRight++; + + if (iRight < ImgList.Count) + { + list.Add(iRight); + } + else + { + list.Add(iRight - ImgList.Count); + } + } + // if i is odd number + else + { + // add left item: [index - 1; ...; from] + iLeft--; + + if (iLeft >= 0) + { + list.Add(iLeft); + } + else + { + list.Add(ImgList.Count + iLeft); + } + } + } + + // release the resources + var freeListCloned = new List(FreeList); + foreach (var itemIndex in freeListCloned) + { + if (!list.Contains(itemIndex) && itemIndex >= 0 && itemIndex < ImgList.Count) + { + ImgList[itemIndex].Dispose(); + FreeList.Remove(itemIndex); + } + } + + // update new index of free list + FreeList.AddRange(list); + + // get new queue list + var newQueueList = new List(); + + foreach (var itemIndex in list) + { + try + { + // use cache metadata + var metadata = ImgList[itemIndex].Metadata; + metadata ??= PhotoCodec.LoadMetadata(ImgList[itemIndex].FilePath); + + // check image dimension + var notExceedDimension = MaxImageDimensionToCache <= 0 + || (metadata.RenderedWidth <= MaxImageDimensionToCache + && metadata.RenderedHeight <= MaxImageDimensionToCache); + + // check file size + var notExceedFileSize = MaxFileSizeInMbToCache <= 0 + || (metadata.FileSize / 1024f / 1024f <= MaxFileSizeInMbToCache); + + // only put the index to the queue if it does not exceed the size limit + if (ImgList[itemIndex].IsDone || (notExceedDimension && notExceedFileSize)) + { + newQueueList.Add(itemIndex); + } + } + catch { } + } + + return newQueueList; + } + + #endregion + + + #region PUBLIC FUNCTIONS + + + /// + /// Cancels loading process of a . + /// + /// Item index + public void CancelLoading(int index) + { + if (0 <= index && index < ImgList.Count) + { + ImgList[index].CancelLoading(); + } + } + + + /// + /// Gets image metadata. + /// + /// Image index. + /// Frame index, if value is null, it will load the first frame. + public IgMetadata? GetMetadata(int index, int? frameIndex) + { + try + { + if (ImgList[index].Metadata == null + || ImgList[index].Metadata.FrameIndex != frameIndex) + { + ImgList[index].Metadata = PhotoCodec.LoadMetadata( + ImgList[index].FilePath, + ReadOptions with + { + FrameIndex = frameIndex, + }); + } + + return ImgList[index].Metadata; + } + catch (ArgumentOutOfRangeException) { } + + return null; + } + + + /// + /// Get Img data + /// + /// image index + /// + public async Task GetAsync( + int index, + bool useCache = true, + CancellationTokenSource? tokenSrc = null) + { + // reload fresh new image data + if (!useCache) + { + await ImgList[index].LoadAsync(ReadOptions with + { + FirstFrameOnly = SingleFrameFormats.Contains(ImgList[index].Extension), + }, tokenSrc).ConfigureAwait(false); + } + + // get image data from cache + else + { + // get queue list according to index + var queueItems = GetQueueList(index, true); + + if (!queueItems.Contains(index)) + { + await ImgList[index].LoadAsync(ReadOptions with + { + FirstFrameOnly = SingleFrameFormats.Contains(ImgList[index].Extension), + }, tokenSrc).ConfigureAwait(false); + } + else + { + QueuedList.Clear(); + QueuedList.AddRange(queueItems); + } + } + + // wait until the image loading is done + if (ImgList.Count > 0) + { + while (!ImgList[index].IsDone) + { + await Task.Delay(10).ConfigureAwait(false); + } + } + + // Trigger event OnFinishLoadingImage + OnFinishLoadingImage?.Invoke(this, EventArgs.Empty); + + // if there is no error + if (ImgList.Count > 0) + { + return ImgList[index]; + } + + return null; + } + + + /// + /// Start caching images. + /// + /// Current index of image list + /// Include current index in the queue list + public void StartCaching(int index, bool includeCurrentIndex) + { + // get queue list according to index + var queueItems = GetQueueList(index, includeCurrentIndex); + + QueuedList.Clear(); + QueuedList.AddRange(queueItems); + } + + + /// + /// Adds a file path + /// + public void Add(string filePath, int index = -1) + { + if (index < 0) + { + ImgList.Add(new IgPhoto(filePath)); + } + else + { + ImgList.Insert(index, new IgPhoto(filePath)); + } + } + + + /// + /// Adds multiple file paths. + /// + public void Add(IEnumerable filePaths, int index = -1) + { + var items = filePaths.Select(i => new IgPhoto(i)); + + if (index < 0) + { + ImgList.AddRange(items); + } + else + { + ImgList.InsertRange(index, items); + } + } + + + /// + /// Checks if the image is cached. + /// + public bool IsCached(int index) + { + try + { + if (ImgList.Count > 0 && ImgList[index] != null) + { + return ImgList[index].ImgData.IsImageNull == false; + } + } + catch (ArgumentOutOfRangeException) // force reload of empty list + { } + + return false; + } + + + /// + /// Get filename with the given index + /// + /// + /// Returns filename or empty string + public string GetFilePath(int index) + { + try + { + if (ImgList.Count > 0 && ImgList[index] != null) + { + return ImgList[index].FilePath; + } + } + catch (ArgumentOutOfRangeException) + { } + + return string.Empty; + } + + + /// + /// Set filename + /// + /// + /// Image filename + public void SetFileName(int index, string filename) + { + if (ImgList[index] != null) + { + ImgList[index].FilePath = filename; + } + } + + + /// + /// Gets file extension. Ex: .jpg + /// + /// + /// + public string GetFileExtension(int index) + { + var filename = GetFilePath(index); + + return Path.GetExtension(filename); + } + + + /// + /// Find index with the given filename + /// + /// Image filename + /// + public int IndexOf(string filename) + { + if (string.IsNullOrEmpty(filename.Trim())) + { + return -1; + } + + // case sensitivity, esp. if filename passed on command line + return ImgList.FindIndex(item => string.Equals(item.FilePath, filename, StringComparison.InvariantCultureIgnoreCase)); + } + + + /// + /// Unload and release resources of item with the given index + /// + public void Unload(int index) + { + try + { + ImgList[index]?.Dispose(); + } + catch (ArgumentOutOfRangeException) { } + } + + + /// + /// Remove an item in the list with the given index + /// + /// Item index + public void Remove(int index) + { + Unload(index); + ImgList.RemoveAt(index); + } + + + /// + /// Clears and resets all resources + /// + public void Reset() + { + // clear list and release resources + Clear(); + + // Clear lists + FilePaths.Clear(); + QueuedList.Clear(); + FreeList.Clear(); + } + + + /// + /// Empty and release resource of the list + /// + public void Clear() + { + // release the resources of the img list + ClearCache(); + ImgList.Clear(); + } + + + /// + /// Clear all cached images and release resource of the list + /// + public void ClearCache() + { + // release the resources of the img list + foreach (var item in ImgList) + { + item.Dispose(); + } + + QueuedList.Clear(); + } + + + /// + /// Update cached images + /// + public void UpdateCache() + { + // clear current queue list + QueuedList.Clear(); + + var cachedIndexList = ImgList + .Select((item, index) => new { ImgItem = item, Index = index }) + .Where(item => item.ImgItem.IsDone) + .Select(item => item.Index) + .ToList(); + + // release the cached images + foreach (var index in cachedIndexList) + { + ImgList[index].Dispose(); + } + + // add to queue list + QueuedList.AddRange(cachedIndexList); + } + + + /// + /// Check if the folder path of input filename exists in the list + /// + public bool ContainsDirPathOf(string filename) + { + var target = Path.GetDirectoryName(filename)?.ToUpperInvariant(); + + var index = ImgList.FindIndex(item => Path.GetDirectoryName(item.FilePath)?.ToUpperInvariant() == target); + + return index != -1; + } + + #endregion + + +} diff --git a/Source/Components/ImageGlass.Base/Properties/AssemblyInfo.cs b/Source/Components/ImageGlass.Base/Properties/AssemblyInfo.cs deleted file mode 100644 index 546e4a4dd..000000000 --- a/Source/Components/ImageGlass.Base/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,35 +0,0 @@ -using System.Reflection; -using System.Runtime.InteropServices; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyTitle("ImageGlass.Base")] -[assembly: AssemblyDescription("The base information of ImageGlass")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("Duong Dieu Phap")] -[assembly: AssemblyProduct("ImageGlass.Base")] -[assembly: AssemblyCopyright("Copyright © 2020 Duong Dieu Phap")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. -[assembly: ComVisible(false)] - -// The following GUID is for the ID of the typelib if this project is exposed to COM -[assembly: Guid("6cc96a70-6773-41b5-9fca-4f0ab6fad8ca")] - -// Version information for an assembly consists of the following four values: -// -// Major Version -// Minor Version -// Build Number -// Revision -// -// You can specify all the values or you can default the Build and Revision Numbers -// by using the '*' as shown below: -// [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.0.0.0")] -//[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/Source/Components/ImageGlass.Base/QueuedWorker/DebounceDispatcher.cs b/Source/Components/ImageGlass.Base/QueuedWorker/DebounceDispatcher.cs new file mode 100644 index 000000000..7b4ef96d3 --- /dev/null +++ b/Source/Components/ImageGlass.Base/QueuedWorker/DebounceDispatcher.cs @@ -0,0 +1,115 @@ +/* +ImageGlass Project - Image viewer for Windows +Copyright (C) 2010 - 2026 DUONG DIEU PHAP +Project homepage: https://imageglass.org + +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 . +*/ +using System.Windows.Threading; + +namespace ImageGlass.Base.QueuedWorker; + + +/// +/// Source: +///
+/// Author: Rick Strahl. +///
+public class DebounceDispatcher +{ + private DispatcherTimer? _timer; + private DateTime _timerStarted = DateTime.UtcNow.AddYears(-1); + + + /// + /// Takes the last called action, delays the execution after a certain amount of time has passed. + /// + /// Timeout in Milliseconds + /// Action to fire when debounced event fires + /// optional parameter + /// optional priorty for the dispatcher + /// optional dispatcher. If not passed or null CurrentDispatcher is used. + public void Debounce(int interval, Action action, T? param = default, + DispatcherPriority priority = DispatcherPriority.ApplicationIdle, + Dispatcher? disp = null) + { + // kill pending timer and pending ticks + _timer?.Stop(); + _timer = null; + + if (disp == null) + disp = Dispatcher.CurrentDispatcher; + + // timer is recreated for each event and effectively + // resets the timeout. Action only fires after timeout has fully + // elapsed without other events firing in between + _timer = new DispatcherTimer(TimeSpan.FromMilliseconds(interval), priority, (s, e) => + { + if (_timer == null) return; + + _timer?.Stop(); + _timer = null; + + action.Invoke(param); + }, disp); + + _timer.Start(); + } + + + /// + /// Throttles events by allowing only 1 event to fire for the given + /// timeout period. Only the last event fired is handled - all others are ignored. + /// Throttle will fire events every timeout ms even if additional events are pending. + /// + /// Timeout in Milliseconds + /// Action to fire when debounced event fires + /// optional parameter + /// optional priorty for the dispatcher + /// optional dispatcher. If not passed or null CurrentDispatcher is used. + public void Throttle(int interval, Action action, T? param = default, + DispatcherPriority priority = DispatcherPriority.ApplicationIdle, + Dispatcher? disp = null) + { + // kill pending timer and pending ticks + _timer?.Stop(); + _timer = null; + + if (disp == null) + disp = Dispatcher.CurrentDispatcher; + + var curTime = DateTime.UtcNow; + + // if timeout is not up yet - adjust timeout to fire + // with potentially new Action parameters + if (curTime.Subtract(_timerStarted).TotalMilliseconds < interval) + { + interval -= (int)curTime.Subtract(_timerStarted).TotalMilliseconds; + } + + _timer = new DispatcherTimer(TimeSpan.FromMilliseconds(interval), priority, (s, e) => + { + if (_timer == null) + return; + + _timer?.Stop(); + _timer = null; + + action.Invoke(param); + }, disp); + + _timer.Start(); + _timerStarted = curTime; + } +} diff --git a/Source/Components/ImageGlass.Base/QueuedWorker/Events/QueuedWorkerCompletedEventArgs.cs b/Source/Components/ImageGlass.Base/QueuedWorker/Events/QueuedWorkerCompletedEventArgs.cs new file mode 100644 index 000000000..daaa110c3 --- /dev/null +++ b/Source/Components/ImageGlass.Base/QueuedWorker/Events/QueuedWorkerCompletedEventArgs.cs @@ -0,0 +1,62 @@ +/* +ImageGlass Project - Image viewer for Windows +Copyright (C) 2010 - 2026 DUONG DIEU PHAP +Project homepage: https://imageglass.org + +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 . +*/ +using System.ComponentModel; + +namespace ImageGlass.Base.QueuedWorker; + + +/// +/// Represents the method that will handle the RunWorkerCompleted event. +/// +/// The object that is the source of the event. +/// A that contains event data. +public delegate void RunQueuedWorkerCompletedEventHandler(object? sender, QueuedWorkerCompletedEventArgs e); + + + +/// +/// Represents the event arguments of the RunWorkerCompleted event. +/// +public class QueuedWorkerCompletedEventArgs : AsyncCompletedEventArgs +{ + /// + /// Gets a value that represents the result of an asynchronous operation. + /// + public object? Result { get; private set; } + + /// + /// Gets the priority of this item. + /// + public int Priority { get; private set; } + + /// + /// Initializes a new instance of the QueuedWorkerCompletedEventArgs class. + /// + /// The argument of an asynchronous operation. + /// The result of an asynchronous operation. + /// A value between 0 and 5 indicating the priority of this item. + /// The error that occurred while loading the image. + /// A value indicating whether the asynchronous operation was canceled. + public QueuedWorkerCompletedEventArgs(object argument, object? result, int priority, Exception? error, bool cancelled) + : base(error, cancelled, argument) + { + Result = result; + Priority = priority; + } +} diff --git a/Source/Components/ImageGlass.Base/QueuedWorker/Events/QueuedWorkerDoWorkEventArgs.cs b/Source/Components/ImageGlass.Base/QueuedWorker/Events/QueuedWorkerDoWorkEventArgs.cs new file mode 100644 index 000000000..89094df6a --- /dev/null +++ b/Source/Components/ImageGlass.Base/QueuedWorker/Events/QueuedWorkerDoWorkEventArgs.cs @@ -0,0 +1,55 @@ +/* +ImageGlass Project - Image viewer for Windows +Copyright (C) 2010 - 2026 DUONG DIEU PHAP +Project homepage: https://imageglass.org + +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 . +*/ + +using System.ComponentModel; + +namespace ImageGlass.Base.QueuedWorker; + + + +/// +/// Represents the method that will handle the DoWork event. +/// +/// The object that is the source of the event. +/// An that contains event data. +[EditorBrowsable(EditorBrowsableState.Never)] +public delegate void QueuedWorkerDoWorkEventHandler(object? sender, QueuedWorkerDoWorkEventArgs e); + + +/// +/// Represents the event arguments of the DoWork event. +/// +public class QueuedWorkerDoWorkEventArgs : DoWorkEventArgs +{ + /// + /// Gets the priority of this item. + /// + public int Priority { get; private set; } + + /// + /// Initializes a new instance of the QueuedWorkerDoWorkEventArgs class. + /// + /// The argument of an asynchronous operation. + /// A value between 0 and 5 indicating the priority of this item. + public QueuedWorkerDoWorkEventArgs(object argument, int priority) + : base(argument) + { + Priority = priority; + } +} diff --git a/Source/Components/ImageGlass.Base/QueuedWorker/ProcessingModeEnum.cs b/Source/Components/ImageGlass.Base/QueuedWorker/ProcessingModeEnum.cs new file mode 100644 index 000000000..bce338e2c --- /dev/null +++ b/Source/Components/ImageGlass.Base/QueuedWorker/ProcessingModeEnum.cs @@ -0,0 +1,35 @@ +/* +ImageGlass Project - Image viewer for Windows +Copyright (C) 2010 - 2026 DUONG DIEU PHAP +Project homepage: https://imageglass.org + +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 . +*/ + +namespace ImageGlass.Base.QueuedWorker; + +/// +/// Represents the mode in which the work items of are processed. +/// +public enum ProcessingMode +{ + /// + /// Items are processed in the order they are received. + /// + FIFO, + /// + /// Items are processed in reverse order. + /// + LIFO, +} diff --git a/Source/Components/ImageGlass.Base/QueuedWorker/QueuedWorker.cs b/Source/Components/ImageGlass.Base/QueuedWorker/QueuedWorker.cs new file mode 100644 index 000000000..e9563c8ee --- /dev/null +++ b/Source/Components/ImageGlass.Base/QueuedWorker/QueuedWorker.cs @@ -0,0 +1,684 @@ +/* +ImageGlass Project - Image viewer for Windows +Copyright (C) 2010 - 2026 DUONG DIEU PHAP +Project homepage: https://imageglass.org + +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 . +*/ +using System.ComponentModel; + +namespace ImageGlass.Base.QueuedWorker; + + +/// +/// A background worker with a work queue. +/// +public class QueuedWorker : Component +{ + + #region Member Variables + + private bool _isDisposed = false; + private readonly object _lockObject = new(); + + private Thread[] _threads = []; + private ProcessingMode _processingMode = ProcessingMode.FIFO; + private int _threadCount = 5; + private string _threadName = string.Empty; + + private bool _isStopping = false; + private bool _isStarted = false; + private bool _isPaused = false; + + private int _priorityQueues = 5; + private LinkedList[] _items = []; + private AsyncOperation?[] _singleItems = []; + private readonly Dictionary _cancelledItems = []; + + private readonly SendOrPostCallback _workCompletedCallback; + + #endregion + + + #region Properties + + /// + /// Represents the mode in which the work items are processed. + /// Processing mode cannot be changed after any work is added to the work queue. + /// + [Browsable(true), Category("Behaviour"), DefaultValue(typeof(ProcessingMode), "FIFO")] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public ProcessingMode ProcessingMode + { + get => _processingMode; + set + { + if (_isStarted) + throw new ThreadStateException("The thread has already been started."); + + _processingMode = value; + BuildWorkQueue(); + } + } + + /// + /// Gets or sets the number of priority queues. Number of queues + /// cannot be changed after any work is added to the work queue. + /// + [Browsable(true), Category("Behaviour"), DefaultValue(5)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public int PriorityQueues + { + get => _priorityQueues; + set + { + if (_isStarted) + throw new ThreadStateException("The thread has already been started."); + + _priorityQueues = value; + BuildWorkQueue(); + } + } + + /// + /// Determines whether the started working. + /// + [Browsable(false), Category("Behavior")] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public bool Started => _isStarted; + + /// + /// Gets or sets a value indicating whether or not the worker thread is a background thread. + /// + [Browsable(true), Category("Behavior")] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public bool IsBackground + { + get => _threads[0].IsBackground; + set + { + for (int i = 0; i < _threadCount; i++) + _threads[i].IsBackground = value; + } + } + + /// + /// Determines whether the is paused. + /// + private bool Paused + { + get + { + lock (_lockObject) + { + return _isPaused; + } + } + } + + /// + /// Determines whether the is being stopped. + /// + private bool Stopping + { + get + { + lock (_lockObject) + { + return _isStopping; + } + } + } + + /// + /// Gets or sets the number of worker threads. Number of threads + /// cannot be changed after any work is added to the work queue. + /// + [Browsable(true), Category("Behaviour"), DefaultValue(5)] + public int Threads + { + get => _threadCount; + set + { + if (_isStarted) + throw new ThreadStateException("The thread has already been started."); + + _threadCount = value; + CreateThreads(); + } + } + + /// + /// Represents the name of the worker threads. + /// + [Browsable(true), Category("Behaviour"), DefaultValue("")] + public string ThreadName + { + get => _threadName; + set + { + if (_isStarted) + throw new ThreadStateException("The thread has already been started."); + + _threadName = value; + CreateThreads(); + } + } + + #endregion + + + #region Public Events + + /// + /// Occurs when the background operation of an item has completed, + /// has been canceled, or has raised an exception. + /// + public event RunQueuedWorkerCompletedEventHandler? RunWorkerCompleted; + + /// + /// Occurs when is called. + /// + public event QueuedWorkerDoWorkEventHandler? DoWork; + + #endregion + + + #region Constructor + /// + /// Initializes a new instance of the class. + /// + public QueuedWorker() + { + // Threads + CreateThreads(); + + // Work items + BuildWorkQueue(); + + // The loader complete callback + _workCompletedCallback = new SendOrPostCallback(RunWorkerCompletedCallback); + } + + #endregion + + + #region Public Methods + + /// + /// Starts processing a new background operation. + /// + /// The argument of an asynchronous operation. + /// A value between 0 and indicating the priority of this item. + /// An item with a higher priority will be processed before items with lower priority. + /// true to run this operation without waiting for queued items; otherwise + /// false to add this operatino to th queue. + public void RunWorkerAsync(object? argument, int priority, bool single) + { + if (priority < 0 || priority >= _priorityQueues) + throw new ArgumentException("priority must be between 0 and " + (_priorityQueues - 1).ToString() + " inclusive.", nameof(priority)); + + // Start the worker threads + if (!_isStarted) + { + // Start the thread + for (int i = 0; i < _threadCount; i++) + { + _threads[i].Start(); + while (!_threads[i].IsAlive) { } + } + + _isStarted = true; + } + + lock (_lockObject) + { + AddWork(argument, priority, single); + Monitor.Pulse(_lockObject); + } + } + + /// + /// Starts processing a new background operation. + /// + /// The argument of an asynchronous operation. + /// A value between 0 and indicating the priority of this item. + /// An item with a higher priority will be processed before items with lower priority. + public void RunWorkerAsync(object argument, int priority) + { + RunWorkerAsync(argument, priority, false); + } + + /// + /// Starts processing a new background operation. + /// + /// The argument of an asynchronous operation. + public void RunWorkerAsync(object argument) + { + RunWorkerAsync(argument, 0, false); + } + + /// + /// Starts processing a new background operation. + /// + public void RunWorkerAsync() + { + RunWorkerAsync(null, 0, false); + } + + /// + /// Pauses the worker. + /// + public void Pause() + { + lock (_lockObject) + { + _isPaused = true; + Monitor.Pulse(_lockObject); + } + } + + /// + /// Resumes processing pending operations in the work queue. + /// + public void Resume() + { + lock (_lockObject) + { + _isPaused = false; + Monitor.Pulse(_lockObject); + } + } + + /// + /// Cancels all pending operations in all queues. + /// + public void CancelAsync() + { + lock (_lockObject) + { + ClearWorkQueue(); + Monitor.Pulse(_lockObject); + } + } + + /// + /// Cancels all pending operations in the given queue. + /// + /// A value between 0 and + /// indicating the priority queue to cancel. + public void CancelAsync(int priority) + { + if (priority < 0 || priority >= _priorityQueues) + throw new ArgumentException("priority must be between 0 and " + (_priorityQueues - 1).ToString() + " inclusive.", nameof(priority)); + + lock (_lockObject) + { + ClearWorkQueue(priority); + Monitor.Pulse(_lockObject); + } + } + + /// + /// Cancels processing the item with the given key. + /// + /// The argument of an asynchronous operation. + public void CancelAsync(object argument) + { + lock (_lockObject) + { + if (_cancelledItems.TryAdd(argument, false)) + { + Monitor.Pulse(_lockObject); + } + } + } + + /// + /// Gets the apartment state of worker threads. + /// + /// The apartment state of worker threads. + public ApartmentState GetApartmentState() + { + return _threads[0].GetApartmentState(); + } + + /// + /// Sets the apartment state of worker threads. The apartment state + /// cannot be changed after any work is added to the work queue. + /// + /// The new state of worker threads. + public void SetApartmentState(ApartmentState state) + { + for (int i = 0; i < _threadCount; i++) + _threads[i].SetApartmentState(state); + } + + #endregion + + + #region Private Methods + + /// + /// Determines if the work queue is empty. + /// This method must be called from inside a lock. + /// + /// true if the work queue is empty; otherwise false. + private bool IsWorkQueueEmpty() + { + foreach (var asyncOp in _singleItems) + { + if (asyncOp != null) return false; + } + + foreach (LinkedList queue in _items) + { + if (queue.Count > 0) return false; + } + + return true; + } + + /// + /// Adds the operation to the work queue. + /// This method must be called from inside a lock. + /// + /// The argument of an asynchronous operation. + /// A value between 0 and indicating the priority of this item. + /// An item with a higher priority will be processed before items with lower priority. + /// true to run this operation without waiting for queued items; otherwise + /// false to add this operatino to th queue. + private void AddWork(object? argument, int priority, bool single) + { + // Create an async operation for this work item + var asyncOp = AsyncOperationManager.CreateOperation(argument); + + if (single) + { + var currentOp = _singleItems[priority]; + currentOp?.OperationCompleted(); + + _singleItems[priority] = asyncOp; + } + else if (_processingMode == ProcessingMode.FIFO) + { + _items[priority].AddLast(asyncOp); + } + else + { + _items[priority].AddFirst(asyncOp); + } + } + + /// + /// Gets a pending operation from the work queue. + /// This method must be called from inside a lock. + /// + /// A 2-tuple whose first component is the the pending operation with + /// the highest priority from the work queue and the second component is the + /// priority. + private Tuple GetWork() + { + AsyncOperation? request = null; + var priority = 0; + + for (int i = _priorityQueues - 1; i >= 0; i--) + { + request = _singleItems[i]; + if (request != null) + { + _singleItems[i] = null; + priority = i; + break; + } + } + + if (request == null) + { + for (int i = _priorityQueues - 1; i >= 0; i--) + { + if (_items[i].Count > 0) + { + priority = i; + request = _items[i]?.First?.Value; + _items[i].RemoveFirst(); + break; + } + } + } + + return Tuple.Create(request, priority); + } + + /// + /// Rebuilds the work queue. + /// This method must be called from inside a lock. + /// + private void BuildWorkQueue() + { + _singleItems = new AsyncOperation[_priorityQueues]; + _items = new LinkedList[_priorityQueues]; + + for (int i = 0; i < _priorityQueues; i++) + { + _items[i] = new LinkedList(); + } + } + + /// + /// Clears all work queues. + /// This method must be called from inside a lock. + /// + private void ClearWorkQueue() + { + for (int i = 0; i < _priorityQueues; i++) + ClearWorkQueue(i); + } + + /// + /// Clears the work queue with the given priority. + /// This method must be called from inside a lock. + /// + /// A value between 0 and + /// indicating the priority queue to cancel. + private void ClearWorkQueue(int priority) + { + var singleOp = _singleItems[priority]; + + if (singleOp != null) + { + singleOp.OperationCompleted(); + _singleItems[priority] = null; + } + + while (_items[priority].Count > 0) + { + var asyncOp = _items[priority]?.First?.Value; + + asyncOp?.OperationCompleted(); + _items[priority].RemoveFirst(); + } + } + + /// + /// Creates the thread array. + /// + private void CreateThreads() + { + _threads = new Thread[_threadCount]; + + for (int i = 0; i < _threadCount; i++) + { + _threads[i] = new Thread(new ThreadStart(Run)) + { + Name = _threadName + " " + (i + 1).ToString(), + IsBackground = true + }; + } + } + + /// + /// Used to call by the synchronization context. + /// + /// The argument. + private void RunWorkerCompletedCallback(object? arg) + { + if (arg is null) return; + + OnRunWorkerCompleted((QueuedWorkerCompletedEventArgs)arg); + } + + /// + /// Used by the worker thread to process items. + /// + private void Run() + { + while (!Stopping) + { + lock (_lockObject) + { + // Wait until we have pending work items + if (_isPaused || IsWorkQueueEmpty()) + Monitor.Wait(_lockObject); + } + + // Loop until we exhaust the queue + var queueFull = true; + while (queueFull && !Stopping && !Paused) + { + // Get an item from the queue + AsyncOperation? asyncOp = null; + object? request = null; + var priority = 0; + + lock (_lockObject) + { + // Check queues + var work = GetWork(); + asyncOp = work.Item1; + priority = work.Item2; + + if (asyncOp != null) + request = asyncOp.UserSuppliedState; + + // Check if the item was removed + if (request != null && _cancelledItems.ContainsKey(request)) + request = null; + } + + if (request != null) + { + Exception? error = null; + object? result = null; + var cancel = false; + + // Start the work + try + { + // Raise the do work event + var doWorkArg = new QueuedWorkerDoWorkEventArgs(request, priority); + OnDoWork(doWorkArg); + + result = doWorkArg.Result; + cancel = doWorkArg.Cancel; + } + catch (Exception e) + { + error = e; + } + + // Raise the work complete event + var workCompletedArg = new QueuedWorkerCompletedEventArgs(request, result, priority, error, cancel); + + if (!Stopping) + asyncOp?.PostOperationCompleted(_workCompletedCallback, workCompletedArg); + } + else + { + asyncOp?.OperationCompleted(); + } + + // Check if the cache is exhausted + lock (_lockObject) + { + queueFull = !IsWorkQueueEmpty(); + } + } + } + } + + #endregion + + + #region Virtual Methods + + /// + /// Raises the RunWorkerCompleted event. + /// + /// A that contains event data. + protected virtual void OnRunWorkerCompleted(QueuedWorkerCompletedEventArgs e) + { + try + { + RunWorkerCompleted?.Invoke(this, e); + } + catch { } + } + + /// + /// Raises the DoWork event. + /// + /// A that contains event data. + protected virtual void OnDoWork(QueuedWorkerDoWorkEventArgs e) + { + DoWork?.Invoke(this, e); + } + + #endregion + + + #region Dispose + + /// + /// Releases the unmanaged resources used by the + /// and optionally releases the managed resources. + /// + /// true to release both managed and unmanaged resources; + /// false to release only unmanaged resources. + protected override void Dispose(bool disposing) + { + base.Dispose(disposing); + + if (_isDisposed) + return; + + lock (_lockObject) + { + if (!_isStopping) + { + _isStopping = true; + ClearWorkQueue(); + + _cancelledItems.Clear(); + Monitor.PulseAll(_lockObject); + } + } + + _isDisposed = true; + } + + #endregion + +} + diff --git a/Source/Components/ImageGlass.Base/Types/Const.cs b/Source/Components/ImageGlass.Base/Types/Const.cs new file mode 100644 index 000000000..c9649cc9e --- /dev/null +++ b/Source/Components/ImageGlass.Base/Types/Const.cs @@ -0,0 +1,90 @@ +/* +ImageGlass Project - Image viewer for Windows +Copyright (C) 2010 - 2026 DUONG DIEU PHAP +Project homepage: https://imageglass.org + +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 . +*/ + +namespace ImageGlass.Base; + + +/// +/// Constants list of the app +/// +public static class Const +{ + public const string UPDATE_CHANNEL = "stable"; // stable or beta + public const int MENU_ICON_HEIGHT = 24; + public const float VIEWER_GRID_SIZE = 9f; + public const int TOOLBAR_ICON_HEIGHT = 24; + public const int THUMBNAIL_HEIGHT = 70; + public const string CONFIG_CMD_PREFIX = "/"; + public const string DATETIME_FORMAT = "yyyy/MM/dd HH:mm:ss"; + public const string DATE_FORMAT = "yyyy/MM/dd"; + public const string APP_PROTOCOL = "imageglass"; + public const string APP_CODE = "2026"; + public const string MS_APPSTORE_ID = "9N33VZK3C7TH"; + public const int MAX_IMAGE_DIMENSION = 16_384; + + /// + /// A file macro to replace with the current viewing image file path in double quotes. + /// Example: "C:\my\photo.jpg" + /// + public const string FILE_MACRO = ""; + + public const string THEME_SYSTEM_ACCENT_COLOR = "accent"; + + // predefined built-in tool names + public const string IGTOOL_EXIFTOOL = "Tool_ExifGlass"; + public const string IGTOOL_SLIDESHOW = "Tool_Slideshow"; + + public const string FRAME_NAV_TOOLBAR_FRAME_INFO = "Lbl_FrameNav_FrameInfo"; + public const string FRAME_NAV_TOOLBAR_TOGGLE_ANIMATION = "Btn_FrameNav_ToggleFrameAnimation"; + + + /// + /// Gets the aspect ratio value. + /// + public static Dictionary AspectRatioValue => new(9) + { + { SelectionAspectRatio.Ratio1_1, [1, 1] }, + { SelectionAspectRatio.Ratio1_2, [1, 2] }, + { SelectionAspectRatio.Ratio2_1, [2, 1] }, + { SelectionAspectRatio.Ratio2_3, [2, 3] }, + { SelectionAspectRatio.Ratio3_2, [3, 2] }, + { SelectionAspectRatio.Ratio3_4, [3, 4] }, + { SelectionAspectRatio.Ratio4_3, [4, 3] }, + { SelectionAspectRatio.Ratio9_16, [9, 16] }, + { SelectionAspectRatio.Ratio16_9, [16, 9] }, + }; + + /// + /// Quick setup version constant. + /// If the value read from config file is less than this value, + /// the Quick setup dialog will be opened. + /// + public const float QUICK_SETUP_VERSION = 9f; + + /// + /// The default theme pack + /// + public const string DEFAULT_THEME = "Kobe"; + + /// + /// Gets built-in image formats + /// + public const string IMAGE_FORMATS = ".3fr;.apng;.ari;.arw;.avif;.b64;.bay;.bmp;.cap;.cr2;.cr3;.crw;.cur;.cut;.dcr;.dcs;.dds;.dib;.dng;.drf;.eip;.emf;.erf;.exif;.exr;.fff;.fits;.flif;.gif;.gifv;.gpr;.hdp;.hdr;.heic;.heif;.hif;.ico;.iiq;.jfif;.jp2;.jpe;.jpeg;.jpg;.jxl;.jxr;.k25;.kdc;.mdc;.mef;.mjpeg;.mos;.mrw;.nef;.nrw;.obm;.orf;.pbm;.pcx;.pef;.pgm;.png;.ppm;.psb;.psd;.ptx;.pxn;.qoi;.r3d;.raf;.raw;.rw2;.rwl;.rwz;.sr2;.srf;.srw;.svg;.tga;.tif;.tiff;.viff;.wdp;.webp;.wmf;.wpg;.x3f;.xbm;.xpm;.xv"; + +} \ No newline at end of file diff --git a/Source/Components/ImageGlass.Base/Types/Constants.cs b/Source/Components/ImageGlass.Base/Types/Constants.cs deleted file mode 100644 index b310f96a5..000000000 --- a/Source/Components/ImageGlass.Base/Types/Constants.cs +++ /dev/null @@ -1,123 +0,0 @@ -/* -ImageGlass Project - Image viewer for Windows -Copyright (C) 2019 DUONG DIEU PHAP -Project homepage: https://imageglass.org - -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 . -*/ - -using System.Collections.Generic; -using System.Globalization; - -namespace ImageGlass.Base -{ - /// - /// Constants list of the app - /// - public static class Constants - { - public const int MENU_ICON_HEIGHT = 21; - public const int TOOLBAR_ICON_HEIGHT = 20; - public const int TOOLBAR_HEIGHT = 40; - public const int VIEWER_GRID_SIZE = 8; - - /// - /// First launch version constant. - /// If the value read from config file is less than this value, - /// the First-Launch Configs screen will be launched. - /// - public const int FIRST_LAUNCH_VERSION = 5; - - - /// - /// The URI Scheme to register web-to-app linking - /// - public const string URI_SCHEME = "imageglass"; - - - /// - /// Gets built-in image formats - /// - public const string IMAGE_FORMATS = "*.bmp;*.cur;*.cut;*.dds;*.dib;*.emf;*.exif;*.gif;*.heic;*.ico;*.jfif;*.jpe;*.jpeg;*.jpg;*.pbm;*.pcx;*.pgm;*.png;*.ppm;*.psb;*.svg;*.tif;*.tiff;*.webp;*.wmf;*.wpg;*.xbm;*.xpm;*.exr;*.hdr;*.psd;*.tga;*.3fr;*.ari;*.arw;*.bay;*.crw;*.cr2;*.cap;*.dcs;*.dcr;*.dng;*.drf;*.eip;*.erf;*.fff;*.gpr;*.iiq;*.k25;*.kdc;*.mdc;*.mef;*.mos;*.mrw;*.nef;*.nrw;*.obm;*.orf;*.pef;*.ptx;*.pxn;*.r3d;*.raf;*.raw;*.rwl;*.rw2;*.rwz;*.sr2;*.srf;*.srw;*.x3f"; - - - /// - /// Number format to use for save/restore ImageGlass settings - /// - public static NumberFormatInfo NumberFormat - { - get => new NumberFormatInfo - { - NegativeSign = "-" - }; - } - - - /// - /// Gets the default set of keycombo actions - /// - public static Dictionary DefaultKeycomboActions - { - get => new Dictionary - { - { KeyCombos.LeftRight, AssignableActions.PrevNextImage }, - { KeyCombos.PageUpDown, AssignableActions.PrevNextImage }, - { KeyCombos.SpaceBack, AssignableActions.PauseSlideshow }, - { KeyCombos.UpDown, AssignableActions.PauseSlideshow } - }; - } - - - /// - /// Gets the default set of toolbar buttons - /// - public static List DefaultToolbarButtons - { - get => new List - { - ToolbarButton.btnBack, - ToolbarButton.btnNext, - ToolbarButton.Separator, - - ToolbarButton.btnRotateLeft, - ToolbarButton.btnRotateRight, - ToolbarButton.btnFlipHorz, - ToolbarButton.btnFlipVert, - ToolbarButton.Separator, - - ToolbarButton.btnAutoZoom, - ToolbarButton.btnScaletoWidth, - ToolbarButton.btnScaletoHeight, - ToolbarButton.btnScaleToFit, - ToolbarButton.btnScaleToFill, - ToolbarButton.btnZoomLock, - ToolbarButton.Separator, - - ToolbarButton.btnOpen, - ToolbarButton.btnRefresh, - ToolbarButton.btnGoto, - ToolbarButton.Separator, - - ToolbarButton.btnWindowFit, - ToolbarButton.btnFullScreen, - ToolbarButton.btnSlideShow, - ToolbarButton.Separator, - - ToolbarButton.btnThumb, - ToolbarButton.btnCheckedBackground, - ToolbarButton.btnDelete, - }; - } - } -} diff --git a/Source/Components/ImageGlass.Base/Types/Dir.cs b/Source/Components/ImageGlass.Base/Types/Dir.cs index 3992d689d..63efa5b5f 100644 --- a/Source/Components/ImageGlass.Base/Types/Dir.cs +++ b/Source/Components/ImageGlass.Base/Types/Dir.cs @@ -1,55 +1,61 @@ -/* -ImageGlass Project - Image viewer for Windows -Copyright (C) 2019 DUONG DIEU PHAP -Project homepage: https://imageglass.org - -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 . -*/ - -namespace ImageGlass.Base + +namespace ImageGlass.Base; + +/// +/// Directory name constants +/// +public static class Dir { /// - /// The directory name constants + /// Gets the Themes folder name + /// + public static string Themes => "Themes"; + + /// + /// Gets the Icons folder name + /// + public static string Icons => "Icons"; + + /// + /// Gets the Ext-Icons folder name + /// + public static string ExtIcons => "Ext-Icons"; + + /// + /// Gets the Languages folder name + /// + public static string Language => "Language"; + + /// + /// Gets the WebUI folder name + /// + public static string WebUI => "WebUI"; + + /// + /// Gets the WebView2_Runtime folder. /// - public static class Dir - { - /// - /// Gets the Themes folder name - /// - public static string Themes { get; } = "Themes"; + public static string WebView2Runtime => "WebView2_Runtime"; - /// - /// Gets the default theme folder name - /// - public static string DefaultTheme { get; } = "DefaultTheme"; + /// + /// Gets the cached thumbnails folder name + /// + public static string ThumbnailsCache => "ThumbnailsCache"; - /// - /// Gets the Languages folder name - /// - public static string Languages { get; } = "Languages"; + /// + /// Gets the License folder name + /// + public static string License => "License"; - /// - /// Gets the temporary folder name - /// - public static string Temporary { get; } = "Temp"; + /// + /// Gets the temporary folder name + /// + public static string Temporary => "Temp"; #if DEBUG - /// - /// Logging should not be to the temporary folder, as it is deleted on shutdown - /// - public static string Log { get; } = "Log"; + /// + /// Logging should not be to the temporary folder, as it is deleted on shutdown + /// + public static string Log => "Log"; #endif - } } diff --git a/Source/Components/ImageGlass.Base/Types/EditApp.cs b/Source/Components/ImageGlass.Base/Types/EditApp.cs deleted file mode 100644 index 00d32e404..000000000 --- a/Source/Components/ImageGlass.Base/Types/EditApp.cs +++ /dev/null @@ -1,109 +0,0 @@ -/* -ImageGlass Project - Image viewer for Windows -Copyright (C) 2019 DUONG DIEU PHAP -Project homepage: http://imageglass.org - -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 . -*/ -using System; - -namespace ImageGlass.Base -{ - /// - /// Contains the information of the editing associated app - /// - public class EditApp - { - /// - /// Gets, sets extension. Ex: .png - /// - public string Extension { get; set; } - - /// - /// Gets, sets friendly app name. - /// - public string AppName { get; set; } - - /// - /// Gets, sets full path of app. - /// - public string AppPath { get; set; } - - /// - /// Gets, sets arguments of app. - /// - public string AppArguments { get; set; } - - - /// - /// Gets the macro string - /// - public static string FileMacro { get; } = ""; - - - /// - /// Initial Image Editing App - /// - public EditApp() - { - Extension = string.Empty; - AppName = string.Empty; - AppPath = string.Empty; - AppArguments = string.Empty; - } - - /// - /// Initial EditApp - /// - /// Extension. Ex: .png - /// Friendly app name. - /// Full path and arguments of app. Ex: C:\app\app.exe --help - public EditApp(string extension, string appName, string appPath, string arguments = "") - { - Extension = extension.ToLower(); - AppName = appName; - AppPath = appPath; - AppArguments = arguments; - } - - /// - /// Initial Image Editing Association. - /// Throw InvalidCastException if @mixString is invalid - /// - /// EditApp string. Ex: .jpg|MS Paint|C:\app\mspaint.exe - public EditApp(string mixString) - { - var itemArray = mixString.Split("|".ToCharArray()); - - if (itemArray.Length != 4) - { - throw new InvalidCastException("Invalid EditApp string format."); - } - - Extension = itemArray[0].ToLower(); - AppName = itemArray[1]; - AppPath = itemArray[2]; - AppArguments = itemArray[3]; - } - - /// - /// Convert ImageEditingAssociation object to string. - /// - /// ImageEditingAssociation string - public override string ToString() - { - return $"{Extension}|{AppName}|{AppPath}|{AppArguments}"; - } - } -} diff --git a/Source/Components/ImageGlass.Base/Types/Enums.cs b/Source/Components/ImageGlass.Base/Types/Enums.cs index 62a725b75..70dee542e 100644 --- a/Source/Components/ImageGlass.Base/Types/Enums.cs +++ b/Source/Components/ImageGlass.Base/Types/Enums.cs @@ -1,6 +1,6 @@ /* ImageGlass Project - Image viewer for Windows -Copyright (C) 2019 DUONG DIEU PHAP +Copyright (C) 2010 - 2026 DUONG DIEU PHAP Project homepage: https://imageglass.org This program is free software: you can redistribute it and/or modify @@ -14,235 +14,249 @@ 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 . +along with this program. If not, see . */ -using System; -namespace ImageGlass.Base +namespace ImageGlass.Base; + + +/// +/// Define the flags to tell FrmMain update the UI +/// +[Flags] +public enum UpdateRequests { - /// - /// The loading order list. - /// **If we need to rename, we MUST update the language string too. - /// Because the name is also language keyword! - /// - public enum ImageOrderBy - { - Name = 0, - Length = 1, - CreationTime = 2, - Extension = 3, - LastAccessTime = 4, - LastWriteTime = 5, - Random = 6 - } + #pragma warning disable format - /// - /// The loading order types list - /// **If we need to rename, we MUST update the language string too. - /// Because the name is also language keyword! - /// - public enum ImageOrderType - { - Asc = 0, - Desc = 1 - } + None = 0, + Language = 1 << 1, - /// - /// The list of Zoom Optimization. - /// **If we need to rename, have to update the language string too. - /// Because the name is also language keyword! - /// - public enum ZoomOptimizationMethods - { - Auto = 0, - SmoothPixels = 1, - ClearPixels = 2 - } + MouseActions = 1 << 3, + RealTimeFileUpdate = 1 << 4, + MenuHotkeys = 1 << 5, + ReloadImage = 1 << 6, + ReloadImageList = 1 << 7, + Slideshow = 1 << 8, - /// - /// The list of mousewheel actions. - /// **If we need to rename, have to update the language string too. - /// Because the name is also language keyword! - /// - public enum MouseWheelActions - { - DoNothing = 0, - Zoom = 1, - ScrollVertically = 2, - ScrollHorizontally = 3, - BrowseImages = 4 - } + ToolbarAlignment = 1 << 9, + ToolbarIcons = 1 << 10, + ToolbarButtons = 1 << 11, + Gallery = 1 << 12, + Layout = 1 << 13, - /// - /// Define the flags to tell frmMain update the UI - /// - [Flags] - public enum ForceUpdateActions - { - NONE = 0, - OTHER_SETTINGS = 1, - THEME = 2, - LANGUAGE = 4, - THUMBNAIL_BAR = 8, - THUMBNAIL_ITEMS = 16, - TOOLBAR = 32, - TOOLBAR_POSITION = 64, - IMAGE_LIST = 128, - IMAGE_LIST_NO_RECURSIVE = 256, - COLOR_PICKER_MENU = 512, - PAGE_NAV_MENU = 1024 - } + Appearance = 1 << 14, + Theme = 1 << 15, + #pragma warning restore format +} - /// - /// The list of layout mode. - /// **If we need to rename, have to update the language string too. - /// Because the name is also language keyword! - /// - public enum LayoutMode - { - Standard = 0, - Designer = 1 - } +/// +/// Color profile options. +/// +public enum ColorProfileOption +{ + None, + Custom, + CurrentMonitorProfile, + + // ImageMagick's profiles + AdobeRGB1998, + AppleRGB, + CoatedFOGRA39, + ColorMatchRGB, + sRGB, + USWebCoatedSWOP, +} - /// - /// All the supported toolbar buttons. NOTE: the names here MUST match the field - /// name in frmMain! Reflection is used to fetch the image and string from the - /// frmMain field. - /// - /// The integer value of the enum is used for storing the config info. - /// - public enum ToolbarButton - { - Separator = -1, - btnBack = 0, - btnNext = 1, - btnRotateLeft = 2, - btnRotateRight = 3, - btnZoomIn = 4, - btnZoomOut = 5, - btnScaleToFit = 6, - btnActualSize = 7, - btnZoomLock = 8, - btnScaletoWidth = 9, - btnScaletoHeight = 10, - btnWindowFit = 11, - btnOpen = 12, - btnRefresh = 13, - btnGoto = 14, - btnThumb = 15, - btnCheckedBackground = 16, - btnFullScreen = 17, - btnSlideShow = 18, - btnConvert = 19, - btnPrintImage = 20, - btnDelete = 21, - btnAutoZoom = 22, - btnFlipHorz = 23, - btnFlipVert = 24, - btnScaleToFill = 25, - btnEdit = 26, - - MAX // DO NOT ADD ANYTHING AFTER THIS - } +/// +/// Types of path +/// +public enum PathType +{ + File, + Dir, + Unknown, +} + +/// +/// Determines Windows OS requirement +/// +public enum WindowsOS +{ /// - /// Zooming modes. + /// Build 22621 /// - public enum ZoomMode - { - AutoZoom = 0, - ScaleToFit = 1, - ScaleToWidth = 2, - ScaleToHeight = 4, - LockZoomRatio = 8, - ScaleToFill = 16, - } + Win11_22H2_OrLater, /// - /// Toolbar position + /// Build 22000 /// - public enum ToolbarPosition - { - Top = 0, - Bottom = 1 - } + Win11OrLater, + Win10, + Win10OrLater, +} - /// - /// Color channels of image, the value should be same as MagickImage.Channels enum - /// - public enum ColorChannels - { - All = -1, // not applicable +/// +/// Exit codes of ImageGlass ultilities +/// +public enum IgExitCode : int +{ + Done = 0, + AdminRequired = 1, + Error = 2, + Error_FileNotFound = 3, +} + + +/// +/// Flip options. +/// +[Flags] +public enum FlipOptions +{ + None = 0, + Horizontal = 1 << 1, + Vertical = 1 << 2, +} + + +/// +/// Rotate option. +/// +public enum RotateOption +{ + Left = 0, + Right = 1, +} + + +/// +/// Color channels +/// +[Flags] +public enum ColorChannels +{ + R = 1 << 1, + G = 1 << 2, + B = 1 << 3, + A = 1 << 4, - Red = 1, - Green = 2, - Blue = 4, - Black = 8, - Alpha = 16, - } + RGB = R | G | B, + RGBA = RGB | A, +} + + +/// +/// Selection aspect ratio. +/// +public enum SelectionAspectRatio +{ + FreeRatio = 0, + Custom = 1, + Original = 2, + Ratio1_1 = 3, + Ratio1_2 = 4, + Ratio2_1 = 5, + Ratio2_3 = 6, + Ratio3_2 = 7, + Ratio3_4 = 8, + Ratio4_3 = 9, + Ratio9_16 = 10, + Ratio16_9 = 11, +} +/// +/// Window backdrop effect. +/// +public enum BackdropStyle +{ /// - /// Actions the user can assign to keys + /// Use default setting of Windows. /// - public enum AssignableActions - { - DoNothing = -1, // error case - PrevNextImage = 0, // previous/next image in list - PanLeftRight, // pan current image left/right - PanUpDown, // pan current image up/down - ZoomInOut, // zoom current image in/out - PauseSlideshow, // placeholder for V6 space key behavior - - } + None = 0, /// - /// User customizable key pairs + /// Mica effect. /// - public enum KeyCombos - { - LeftRight = 0, // left/right arrow keys - UpDown, // up/down arrow keys - PageUpDown, // pageup/pagedown keys - SpaceBack, // space, backspace keys - } + Mica = 2, /// - /// Supported actions which can be assigned to mouse click + /// Acrylic effect. /// - public enum MouseAction - { - ToggleZoomFit = 0, // switch between 100% and fit-to-window - ZoomIn, // zoom in by zoom step - ZoomOut, // zoom out by zoom step - NextImage, // next image in list - PrevImage, // previous image in list - ToggleFullScreen, // toggle full-screen mode - PopupMenu, // bring up the popup menu - ColorPick, // select color under mouse cursor - ZoomInToMouse, // zoom in by zoom step, centered on mouse position - ZoomOutToAuto, // zoom out to Auto-zoom level - } + Acrylic = 3, /// - /// Supported customizable mouse click + /// Draw the backdrop material effect corresponding to a window with a tabbed title bar. /// - public enum MouseClick - { - Button1, // Left single - Button1Dbl, - Button2, // Right single - Button2Dbl, - Button3, // Middle - Button3Dbl, - Button4, // X1 - Button4Dbl, - Button5, // X2 - Button5Dbl, - } + MicaAlt = 4, +} + + +/// +/// Options indicate what source of image is saved. +/// +public enum ImageSaveSource +{ + Undefined, + SelectedArea, + Clipboard, + CurrentFile, +} + + +/// +/// Options for resampling methods. +/// +public enum ImageResamplingMethod : int +{ + Auto = 0, + Average, + CatmullRom, + Cubic, + CubicSmoother, + Hermite, + Lanczos, + Linear, + Mitchell, + NearestNeighbor, + Quadratic, + Spline36, +} + + +/// +/// The loading order list. +/// **If we need to rename, we MUST update the language string too. +/// Because the name is also language keyword! +/// +public enum ImageOrderBy +{ + Name = 0, + Random, + FileSize, + Extension, + DateCreated, + DateAccessed, + DateModified, + ExifDateTaken, + ExifRating, +} + + +/// +/// The loading order types list +/// **If we need to rename, we MUST update the language string too. +/// Because the name is also language keyword! +/// +public enum ImageOrderType +{ + Asc = 0, + Desc = 1, } + diff --git a/Source/Components/ImageGlass.Base/Types/HotKey.cs b/Source/Components/ImageGlass.Base/Types/HotKey.cs new file mode 100644 index 000000000..27d1d34f4 --- /dev/null +++ b/Source/Components/ImageGlass.Base/Types/HotKey.cs @@ -0,0 +1,191 @@ +/* +ImageGlass Project - Image viewer for Windows +Copyright (C) 2010 - 2026 DUONG DIEU PHAP +Project homepage: https://imageglass.org + +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 . +*/ +using ImageGlass.Base.WinApi; + +namespace ImageGlass.Base; + +public class Hotkey +{ + public bool Control { get; set; } = false; + public bool Shift { get; set; } = false; + public bool Alt { get; set; } = false; + public Keys KeyData { get; set; } = Keys.None; + public Keys Modifiers { get; set; } = Keys.None; + public Keys KeyCode { get; set; } = Keys.None; + public int KeyValue { get; set; } = -1; + public string KeyStr + { + get + { + var str = KeyCode == Keys.None ? string.Empty : KeyCode.ToString(); + + if (str.Equals(nameof(Keys.Next))) + { + str = "PageDown"; + } + else if (str.StartsWith("Oem") + || (str.StartsWith('D') && str.Length == 2) // D0 -> D9 + ) + { + var unicode = KeyboardApi.KeyCodeToChar(KeyCode, false).ToString(); + + if (!string.IsNullOrEmpty(unicode)) + { + str = unicode; + } + } + + return str; + } + } + + + public Hotkey() + { + ParseFrom(Keys.None); + } + + public Hotkey(string s) + { + ParseFrom(s); + } + + public Hotkey(Keys keys) + { + ParseFrom(keys); + } + + + /// + /// Parses hotkey from string + /// + /// + public void ParseFrom(string s) + { + var hotkey = Keys.None; + + try + { + + var keyStrings = s.ToLowerInvariant().Split('+', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries); + + foreach (var str in keyStrings) + { + if (str.Equals("ctrl")) + { + hotkey |= Keys.Control; + } + else if (str.Equals("shift")) + { + hotkey |= Keys.Shift; + } + else if (str.Equals("alt")) + { + hotkey |= Keys.Alt; + } + else + { + if (str.Length == 1) + { + hotkey |= KeyboardApi.CharToKeyCode(str[0]); + } + else + { + Keys? key = null; + try + { + var kc = new KeysConverter(); + key = (Keys?)kc.ConvertFromInvariantString(str); + } + catch (ArgumentException) + { + key = BHelper.ParseEnum(str); + } + + if (key is not null) + { + hotkey |= key.Value; + } + } + } + } + } + catch { } + + + if (hotkey != Keys.None) + { + ParseFrom(hotkey); + } + } + + + /// + /// Parses hotkey from keys + /// + public void ParseFrom(Keys keys) + { + var ka = new KeyEventArgs(keys); + + Control = ka.Control; + Shift = ka.Shift; + Alt = ka.Alt; + Modifiers = ka.Modifiers; + KeyCode = ka.KeyCode; + KeyData = ka.KeyData; + KeyValue = ka.KeyValue; + } + + + /// + /// Converts hotkey to string + /// + public override string ToString() + { + var modifiers = new List(4); + + if (Control) modifiers.Add("Ctrl"); + if (Shift) modifiers.Add("Shift"); + if (Alt) modifiers.Add("Alt"); + + + var ignoredKeys = new List() { + nameof(Keys.ControlKey), + nameof(Keys.ShiftKey), + nameof(Keys.Menu), + nameof(Keys.LWin), + nameof(Keys.RWin), + nameof(Keys.Capital), + }; + + + if (KeyStr.Length == 1) + { + modifiers.Add(KeyStr.ToUpperInvariant()); + } + else if (!ignoredKeys.Contains(KeyStr)) + { + modifiers.Add(KeyStr); + } + + + return string.Join('+', modifiers); // do not use ZString here + } + +} diff --git a/Source/Components/ImageGlass.Base/Types/IgCommands.cs b/Source/Components/ImageGlass.Base/Types/IgCommands.cs new file mode 100644 index 000000000..00c96c0f6 --- /dev/null +++ b/Source/Components/ImageGlass.Base/Types/IgCommands.cs @@ -0,0 +1,49 @@ +/* +ImageGlass Project - Image viewer for Windows +Copyright (C) 2010 - 2026 DUONG DIEU PHAP +Project homepage: https://imageglass.org + +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 . +*/ + +namespace ImageGlass.Base; + +public static class IgCommands +{ + // UI result options + public static string SHOW_UI => "--ui"; + public static string HIDE_ADMIN_REQUIRED_ERROR_UI => "--hide-admin-error-ui"; + public static string PER_MACHINE => "--per-machine"; + public static string STARTUP_BOOST => "--startup-boost"; + + + // igcmd.exe + public static string SET_WALLPAPER => "set-wallpaper"; + public static string SET_LOCK_SCREEN => "set-lock-screen"; + public static string SET_DEFAULT_PHOTO_VIEWER => "set-default-viewer"; + public static string REMOVE_DEFAULT_PHOTO_VIEWER => "remove-default-viewer"; + public static string START_SLIDESHOW => "start-slideshow"; + public static string EXPORT_FRAMES => "export-frames"; + public static string LOSSLESS_COMPRESS => "lossless-compress"; + public static string SET_STARTUP_BOOST => "set-startup-boost"; + public static string REMOVE_STARTUP_BOOST => "remove-startup-boost"; + + + public static string QUICK_SETUP => "quick-setup"; + public static string CHECK_FOR_UPDATE => "check-for-update"; + public static string INSTALL_LANGUAGES => "install-languages"; + public static string INSTALL_THEMES => "install-themes"; + public static string UNINSTALL_THEME => "uninstall-theme"; + +} diff --git a/Source/Components/ImageGlass.Base/Types/MouseEvent.cs b/Source/Components/ImageGlass.Base/Types/MouseEvent.cs new file mode 100644 index 000000000..0be283dca --- /dev/null +++ b/Source/Components/ImageGlass.Base/Types/MouseEvent.cs @@ -0,0 +1,63 @@ +/* +ImageGlass Project - Image viewer for Windows +Copyright (C) 2010 - 2026 DUONG DIEU PHAP +Project homepage: https://imageglass.org + +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 . +*/ + +namespace ImageGlass.Base; + + +/// +/// List of MouseClick / MouseDoubleClick events +/// +public enum MouseClickEvent +{ + LeftClick = 1, + LeftDoubleClick = 2, + + RightClick = 3, + RightDoubleClick = 4, + + XButton1Click = 5, + XButton2Click = 6, + + WheelClick = 7, +} + + +/// +/// List of MouseWheel events +/// +public enum MouseWheelEvent +{ + Scroll = 1, + CtrlAndScroll = 2, + ShiftAndScroll = 3, + AltAndScroll = 4, +} + + +/// +/// List of mouse wheel action for the +/// +public enum MouseWheelAction +{ + DoNothing = 0, + Zoom = 1, + PanVertically = 2, + PanHorizontally = 3, + BrowseImages = 4 +} diff --git a/Source/Components/ImageGlass.Base/Types/PhotoBox.cs b/Source/Components/ImageGlass.Base/Types/PhotoBox.cs new file mode 100644 index 000000000..7f3b96916 --- /dev/null +++ b/Source/Components/ImageGlass.Base/Types/PhotoBox.cs @@ -0,0 +1,106 @@ +/* +ImageGlass Project - Image viewer for Windows +Copyright (C) 2010 - 2026 DUONG DIEU PHAP +Project homepage: https://imageglass.org + +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 . +*/ + +namespace ImageGlass.Base.PhotoBox; + + +/// +/// Zoom modes +/// +public enum ZoomMode +{ + AutoZoom = 1, + LockZoom = 2, + ScaleToWidth = 3, + ScaleToHeight = 4, + ScaleToFit = 5, + ScaleToFill = 6, +} + + +/// +/// Interpolation modes. +/// These values are based on . +/// +public enum ImageInterpolation : int +{ + /// + /// Pixelated scaling down (poor quality) and up. + /// + NearestNeighbor = 0, + + /// + /// Pixelated scaling down (poor quality), smooth scaling up (normal quality). + /// + Linear = 1, + + /// + /// Pixelated scaling down (poor quality), smooth scaling up (better quality). + /// + Cubic = 2, + + /// + /// Smooth scaling down (the best), smooth scaling up (normal quality). + /// + MultiSampleLinear = 3, + + /// + /// Smooth scaling down (normal quality) and up (normal quality). + /// + Anisotropic = 4, + + /// + /// Smooth scaling down (normal quality) and up (better quality). + /// + HighQualityBicubic = 5, +} + + +/// +/// Specifies the display styles for the background texture grid +/// +public enum CheckerboardMode +{ + /// + /// No background. + /// + None = 0, + + /// + /// Background is displayed in the control's client area. + /// + Client = 1, + + /// + /// Background is displayed only in the image region. + /// + Image = 2, +} + + +/// +/// Specifies the display styles for navigation button +/// +public enum NavButtonDisplay +{ + None = 0, + Both = 1, + Left = 2, + Right = 3, +} diff --git a/Source/Components/ImageGlass.Base/Types/ProgressReporterEventArgs.cs b/Source/Components/ImageGlass.Base/Types/ProgressReporterEventArgs.cs new file mode 100644 index 000000000..c9e836bc7 --- /dev/null +++ b/Source/Components/ImageGlass.Base/Types/ProgressReporterEventArgs.cs @@ -0,0 +1,35 @@ +/* +ImageGlass Project - Image viewer for Windows +Copyright (C) 2010 - 2026 DUONG DIEU PHAP +Project homepage: https://imageglass.org + +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 . +*/ +namespace ImageGlass.Base; + +public class ProgressReporterEventArgs(T data, string type = "") : EventArgs +{ + /// + /// The type of the event. + /// + public string Type { get; init; } = type; + + /// + /// Event data. + /// + public T Data { get; init; } = data; +} + + +public class ProgressReporterEventArgs(EventArgs data, string type = "") : ProgressReporterEventArgs(data, type) { } diff --git a/Source/Components/ImageGlass.Base/Types/SavingExts.cs b/Source/Components/ImageGlass.Base/Types/SavingExts.cs new file mode 100644 index 000000000..aafc4c3f0 --- /dev/null +++ b/Source/Components/ImageGlass.Base/Types/SavingExts.cs @@ -0,0 +1,98 @@ +/* +ImageGlass Project - Image viewer for Windows +Copyright (C) 2010 - 2026 DUONG DIEU PHAP +Project homepage: https://imageglass.org + +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 . +*/ +using Cysharp.Text; +using System.Text; + +namespace ImageGlass.Base; + +public static class SavingExts +{ + /// + /// Gets the supported extensions for saving in a pair of (.extension, description) + /// + public static List SupportedExts => [ + // the order here matters + new SavingExt { Ext = ".avif", Description = "AVIF" }, + new SavingExt { Ext = ".bmp", Description = "BMP" }, + new SavingExt { Ext = ".gif", Description = "GIF" }, + new SavingExt { Ext = ".jpg", Description = "JPG" }, + new SavingExt { Ext = ".jxl", Description = "JXL" }, + new SavingExt { Ext = ".png", Description = "PNG" }, + new SavingExt { Ext = ".tiff", Description = "TIFF" }, + new SavingExt { Ext = ".webp", Description = "WEBP" }, + + new SavingExt { Ext = ".emf", Description = "EMF" }, + new SavingExt { Ext = ".exif", Description = "EXIF" }, + new SavingExt { Ext = ".ico", Description = "ICO" }, + new SavingExt { Ext = ".wmf", Description = "WMF" }, + new SavingExt { Ext = ".b64", Description = "Base64" }, + new SavingExt { Ext = ".txt", Description = "Base64 text" }, + ]; + + + /// + /// Returns file extension filter string for . + /// + public static string GetFilterStringForSaveDialog() + { + using var sb = ZString.CreateStringBuilder(); + + for (int i = 0; i < SupportedExts.Count; i++) + { + var item = SupportedExts[i]; + + sb.Append($"{item.Description} (*{item.Ext})|*{item.Ext}"); + + if (i < SupportedExts.Count - 1) + { + sb.Append('|'); + } + } + + return sb.ToString(); + } + + + /// + /// Finds index of the input extension. + /// + /// An extension, example: .png + public static int IndexOf(string ext) + { + ext = ext.ToLowerInvariant(); + + for (int i = 0; i < SupportedExts.Count; i++) + { + if (SupportedExts[i].Ext == ext) + { + return i; + } + } + + return -1; + } +} + + + +public record SavingExt +{ + public string Ext { get; set; } = ""; + public string Description { get; set; } = ""; +} diff --git a/Source/Components/ImageGlass.Base/Types/ThumbnailItemInfo.cs b/Source/Components/ImageGlass.Base/Types/ThumbnailItemInfo.cs deleted file mode 100644 index 3f26850d2..000000000 --- a/Source/Components/ImageGlass.Base/Types/ThumbnailItemInfo.cs +++ /dev/null @@ -1,97 +0,0 @@ -/* -ImageGlass Project - Image viewer for Windows -Copyright (C) 2019 DUONG DIEU PHAP -Project homepage: http://imageglass.org - -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 . -*/ - - -namespace ImageGlass.Base -{ - /// - /// Contains the information of thumbnail item in thumbnail bar - /// - public class ThumbnailItemInfo - { - /// - /// Gets actual thumbnail dimension - /// - public uint Dimension { get; } - - /// - /// Gets extra space to adapt minimum width / height of thumbnail bar - /// - public uint ExtraSpace { get; } - - /// - /// Get total dimension - /// - /// - public uint GetTotalDimension() - { - return Dimension + ExtraSpace; - } - - /// - /// Thumbnail item information - /// - /// Thumbnail size - /// Horizontal or Verticle view - public ThumbnailItemInfo(uint dimension, bool isHorizontalView) - { - if (isHorizontalView) - { - Dimension = dimension; - //ExtraSpace = 58; - } - else - { - switch (dimension) - { - case 32: - Dimension = 32; - //ExtraSpace = 48; - break; - - case 48: - Dimension = 48; - //ExtraSpace = 52; - break; - - case 64: - Dimension = 64; - //ExtraSpace = 57; - break; - - case 96: - Dimension = 96; - //ExtraSpace = 69; - break; - - case 128: - Dimension = 128; - //ExtraSpace = 79; - break; - - default: - Dimension = 48; - //ExtraSpace = 57; - break; - } - } - ExtraSpace = 0; - } - } -} diff --git a/Source/Components/ImageGlass.Base/Types/ToolbarItemModel.cs b/Source/Components/ImageGlass.Base/Types/ToolbarItemModel.cs new file mode 100644 index 000000000..b9f1c8ccf --- /dev/null +++ b/Source/Components/ImageGlass.Base/Types/ToolbarItemModel.cs @@ -0,0 +1,69 @@ +/* +ImageGlass Project - Image viewer for Windows +Copyright (C) 2010 - 2026 DUONG DIEU PHAP +Project homepage: https://imageglass.org + +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 . +*/ +using ImageGlass.Base.Actions; +using System.Text.Json.Serialization; + +namespace ImageGlass.Base; + + +/// +/// Toolbar item model +/// +public record ToolbarItemModel +{ + public ToolbarItemModelType Type { get; set; } = ToolbarItemModelType.Button; + + public string Id { get; set; } = string.Empty; + public string Text { get; set; } = string.Empty; + + public ToolStripItemDisplayStyle DisplayStyle { get; set; } = ToolStripItemDisplayStyle.Image; + public string CheckableConfigBinding { get; set; } = string.Empty; + public ToolStripItemAlignment Alignment { get; set; } = ToolStripItemAlignment.Left; + + public string Image { get; set; } = string.Empty; + public SingleAction OnClick { get; set; } = new(); + + /// + /// Gets, sets hotkeys. + /// + [JsonConverter(typeof(HotkeyListJsonConverter))] + public List Hotkeys { get; set; } = []; +} + +public enum ToolbarItemModelType +{ + Button, + Separator, +} + +public record ToolbarItemTagModel +{ + public SingleAction OnClick { get; set; } = new(); + public string Image { get; set; } = string.Empty; + public string CheckableConfigBinding { get; set; } = string.Empty; +} + + +public enum ToolbarAddItemResult +{ + Success, + ItemExists, + InvalidModel, + ThemeIsNull, +} diff --git a/Source/Components/ImageGlass.Base/Update/UpdateModel.cs b/Source/Components/ImageGlass.Base/Update/UpdateModel.cs new file mode 100644 index 000000000..a35ec895f --- /dev/null +++ b/Source/Components/ImageGlass.Base/Update/UpdateModel.cs @@ -0,0 +1,55 @@ +/* +ImageGlass Project - Image viewer for Windows +Copyright (C) 2010 - 2026 DUONG DIEU PHAP +Project homepage: https://imageglass.org + +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 . +*/ +#nullable disable +using System.ComponentModel.DataAnnotations; + +namespace ImageGlass.Base.Update; + +public class UpdateModel +{ + public float ApiVersion { get; set; } = 1; + + public Dictionary Releases { get; set; } = new(); + +} + + +public class ReleaseModel +{ + public string Version { get; set; } = ""; + public string Title { get; set; } = ""; + public string Description { get; set; } = ""; + + [DataType(DataType.Url)] + public Uri ChangelogUrl { get; set; } + + [DataType(DataType.DateTime)] + public DateTime PublishedDate { get; set; } + +} + +public class DownloadModel +{ + public string Architecture { get; set; } = ""; + public string Extension { get; set; } = ""; + public string HashCode { get; set; } = ""; + + [DataType(DataType.Url)] + public Uri Url { get; set; } +} diff --git a/Source/Components/ImageGlass.Base/Update/UpdateService.cs b/Source/Components/ImageGlass.Base/Update/UpdateService.cs new file mode 100644 index 000000000..a542e972a --- /dev/null +++ b/Source/Components/ImageGlass.Base/Update/UpdateService.cs @@ -0,0 +1,89 @@ +/* +ImageGlass Project - Image viewer for Windows +Copyright (C) 2010 - 2026 DUONG DIEU PHAP +Project homepage: https://imageglass.org + +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 . +*/ + +namespace ImageGlass.Base.Update; + +public class UpdateService +{ + /// + /// Gets the update information + /// + public UpdateModel? UpdateInfo { get; private set; } + + + /// + /// Gets current release information + /// + public ReleaseModel? CurrentReleaseInfo + { + get + { + if (UpdateInfo is null) return null; + + if (UpdateInfo.Releases.ContainsKey(Const.UPDATE_CHANNEL)) + { + return UpdateInfo.Releases[Const.UPDATE_CHANNEL]; + } + + return null; + } + } + + + /// + /// Gets the value indicates that the current app has a new update + /// + public bool HasNewUpdate + { + get + { + if (CurrentReleaseInfo == null) + { + return false; + } + + var newVersion = new Version(CurrentReleaseInfo.Version); + var currentVersion = new Version(App.Version); + + return newVersion > currentVersion; + } + } + + + /// + /// Gets the latest updates + /// + /// + public async Task GetUpdatesAsync() + { + var url = $"https://imageglass.org/url/update?channel={Const.UPDATE_CHANNEL}&version={App.Version}"; + + + using var httpClient = new HttpClient(); + var response = await httpClient.GetAsync(url); + + if (!response.IsSuccessStatusCode) + { + return; + } + + using var stream = await response.Content.ReadAsStreamAsync(); + UpdateInfo = await BHelper.ParseJson(stream); + } +} diff --git a/Source/Components/ImageGlass.Base/Webview2/Events.cs b/Source/Components/ImageGlass.Base/Webview2/Events.cs new file mode 100644 index 000000000..513cccbe4 --- /dev/null +++ b/Source/Components/ImageGlass.Base/Webview2/Events.cs @@ -0,0 +1,40 @@ +/* +ImageGlass Project - Image viewer for Windows +Copyright (C) 2010 - 2026 DUONG DIEU PHAP +Project homepage: https://imageglass.org + +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 . +*/ + +using System.Collections.ObjectModel; + +namespace ImageGlass.Base; + +public class Web2MessageReceivedEventArgs(string? name, string? data, IReadOnlyList? additionalObjects) : EventArgs +{ + /// + /// Gets the name of the message. + /// + public string Name { get; init; } = name ?? string.Empty; + + /// + /// Gets the data of the message. + /// + public string Data { get; init; } = data ?? string.Empty; + + /// + /// Gets the additional received WebMessage objects. + /// + public IReadOnlyList AdditionalObjects { get; init; } = additionalObjects ?? []; +} diff --git a/Source/Components/ImageGlass.Base/Webview2/Web2.cs b/Source/Components/ImageGlass.Base/Webview2/Web2.cs new file mode 100644 index 000000000..0ee5a34a0 --- /dev/null +++ b/Source/Components/ImageGlass.Base/Webview2/Web2.cs @@ -0,0 +1,628 @@ +/* +ImageGlass Project - Image viewer for Windows +Copyright (C) 2010 - 2026 DUONG DIEU PHAP +Project homepage: https://imageglass.org + +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 . +*/ +using Microsoft.Web.WebView2.Core; +using Microsoft.Web.WebView2.WinForms; +using System.ComponentModel; + +namespace ImageGlass.Base; + +/// +/// A wrapper of control. +/// +public class Web2 : WebView2 +{ + public static readonly Version MIN_VERSION = new Version(119, 0, 2151); + + private bool _darkMode = true; + private Color _accentColor = Color.FromArgb(28, 146, 255); + + + // Properties + #region Properties + + /// + /// Enables or disables debug mode. + /// + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public bool EnableDebug { get; set; } = false; + + /// + /// Gets, sets dark mode of . + /// + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public bool DarkMode + { + get => _darkMode; + set + { + _darkMode = value; + _ = SetWeb2DarkModeAsync(value); + } + } + + /// + /// Gets, sets accent color of . + /// + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public Color AccentColor + { + get => _accentColor; + set + { + _accentColor = value; + _ = SetWeb2AccentColorAsync(value); + } + } + + /// + /// Gets, sets campaign for hyperlink url. + /// + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public string PageName { get; set; } = "unknown"; + + /// + /// Gets value indicates that is ready to use. + /// + public bool IsWeb2Ready => this.CoreWebView2 != null; + + + /// + /// Gets the path of WebView2 Runtime fixed version. + /// If not found, return null. + /// + public static string? WebView2RuntimeFixedVersionDirPath + { + get + { + var dir = App.StartUpDir(Dir.WebView2Runtime); + + if (Directory.Exists(dir)) return dir; + + return null; + } + } + + + /// + /// Gets version of runtime, + /// returns null if runtime is not installed. + /// + public static Version? Webview2Version + { + get + { + try + { + var version = CoreWebView2Environment.GetAvailableBrowserVersionString(WebView2RuntimeFixedVersionDirPath); + return new Version(version); + } + catch (WebView2RuntimeNotFoundException) { } + + return null; + } + } + + #endregion // Properties + + + + // Public events + #region Public events + + /// + /// Occurs when is ready to use. + /// + public event EventHandler Web2Ready; + + /// + /// Occurs when navigation is completed + /// + public event EventHandler Web2NavigationCompleted; + + /// + /// Occurs when receives a message from web view. + /// + public event EventHandler Web2MessageReceived; + + /// + /// Occurs when receives keydown. + /// + public event EventHandler Web2KeyDown; + + /// + /// Occurs when receives keyup. + /// + public event EventHandler Web2KeyUp; + + /// + /// Occurs when is opening context menu. + /// + public event EventHandler Web2ContextMenuRequested; + + #endregion // Public events + + + + /// + /// Initializes new instance of . + /// + public Web2() + { + this.DefaultBackgroundColor = Color.Transparent; + + this.WebMessageReceived += Web2_WebMessageReceived; + this.NavigationCompleted += Web2_NavigationCompleted; + } + + + + // Override/ virtual methods + #region Override/ virtual methods + + protected override void Dispose(bool disposing) + { + if (this.CoreWebView2 != null) + { + this.CoreWebView2.NewWindowRequested -= CoreWebView2_NewWindowRequested; + } + + this.WebMessageReceived -= Web2_WebMessageReceived; + this.NavigationCompleted -= Web2_NavigationCompleted; + + base.Dispose(disposing); + } + + + /// + /// Occurs when the control is ready. + /// + protected virtual async Task OnWeb2ReadyAsync() + { + if (InvokeRequired) + { + await Invoke(OnWeb2ReadyAsync); + return; + } + + Web2Ready?.Invoke(this, EventArgs.Empty); + await Task.CompletedTask; + } + + + /// + /// Occurs when the navigation is completed. + /// + protected virtual async Task OnWeb2NavigationCompleted() + { + if (InvokeRequired) + { + await Invoke(OnWeb2NavigationCompleted); + return; + } + + Web2NavigationCompleted?.Invoke(this, EventArgs.Empty); + await Task.CompletedTask; + } + + + /// + /// Triggers event. + /// + protected virtual async Task OnWeb2MessageReceivedAsync(Web2MessageReceivedEventArgs e) + { + if (InvokeRequired) + { + await Invoke(async delegate + { + await OnWeb2MessageReceivedAsync(e); + }); + return; + } + + Web2MessageReceived?.Invoke(this, e); + await Task.CompletedTask; + } + + + /// + /// Triggers event. + /// + protected virtual async Task OnWeb2KeyDownAsync(KeyEventArgs e) + { + if (InvokeRequired) + { + await Invoke(async delegate + { + await OnWeb2KeyDownAsync(e); + }); + return; + } + + Web2KeyDown?.Invoke(this, e); + await Task.CompletedTask; + } + + + /// + /// Triggers event. + /// + protected virtual async Task OnWeb2KeyUpAsync(KeyEventArgs e) + { + if (InvokeRequired) + { + await Invoke(async delegate + { + await OnWeb2KeyUpAsync(e); + }); + return; + } + + Web2KeyUp?.Invoke(this, e); + await Task.CompletedTask; + } + + + /// + /// Triggers event. + /// + protected virtual async Task OnWeb2ContextMenuRequested(CoreWebView2ContextMenuRequestedEventArgs e) + { + if (InvokeRequired) + { + await Invoke(async delegate + { + await OnWeb2ContextMenuRequested(e); + }); + return; + } + + Web2ContextMenuRequested?.Invoke(this, e); + await Task.CompletedTask; + } + + #endregion // Override/ virtual methods + + + + // Public methods + #region Public methods + + /// + /// Ensures is ready to work. + /// + public async Task EnsureWeb2Async() + { + // if WebView2 runtime is not installed + if (!Web2.CheckWebview2Installed()) + { + MessageBox.Show($"{nameof(Web2)}: WebView2 Runtime 64-bit is not found", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); + + return; + } + + + var options = new CoreWebView2EnvironmentOptions + { + AdditionalBrowserArguments = "--disable-web-security --allow-file-access-from-files --allow-file-access", + }; + + try + { + // use AppData dir + // %LocalAppData%\ImageGlass\WebView2_Data + var appDataDir = Path.Combine( + Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), + App.AppName, + "WebView2_Data"); + + // create the directory if not exists + Directory.CreateDirectory(appDataDir); + + var env = await CoreWebView2Environment.CreateAsync( + browserExecutableFolder: WebView2RuntimeFixedVersionDirPath, + userDataFolder: appDataDir, + options: options); + + await this.EnsureCoreWebView2Async(env).ConfigureAwait(true); + + this.CoreWebView2.Settings.IsZoomControlEnabled = false; + this.CoreWebView2.Settings.IsStatusBarEnabled = false; + this.CoreWebView2.Settings.IsBuiltInErrorPageEnabled = false; + this.CoreWebView2.Settings.IsGeneralAutofillEnabled = false; + this.CoreWebView2.Settings.IsPasswordAutosaveEnabled = false; + this.CoreWebView2.Settings.IsPinchZoomEnabled = false; + this.CoreWebView2.Settings.IsSwipeNavigationEnabled = false; + this.CoreWebView2.Settings.AreDefaultScriptDialogsEnabled = false; + this.CoreWebView2.Settings.AreDefaultContextMenusEnabled = true; + this.CoreWebView2.Settings.AreBrowserAcceleratorKeysEnabled = false; + + // DevTools + this.CoreWebView2.Settings.AreDevToolsEnabled = true; + + this.CoreWebView2.NewWindowRequested += CoreWebView2_NewWindowRequested; + this.CoreWebView2.ContextMenuRequested += CoreWebView2_ContextMenuRequested; + + + await OnWeb2ReadyAsync(); + } + catch (Exception ex) + { + // Operation aborted (0x80004004 (E_ABORT)) + if (ex.HResult == -2147467260) + { + // ignore + } + else + { + MessageBox.Show($"{nameof(Web2)}: Failed to initialize Webview2!\r\n\r\n" + + $"{ex.Message}\r\n\r\n" + + $"at {nameof(EnsureWeb2Async)}() method", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); + } + } + } + + + /// + /// Checks if runtime is installed. + /// + public static bool CheckWebview2Installed() + { + return Web2.Webview2Version != null && Web2.Webview2Version >= MIN_VERSION; + } + + + /// + /// Sets accent color to content. Example: + /// + /// html style="--Accent: 255 0 0" + /// + /// + public async Task SetWeb2AccentColorAsync(Color accent) + { + if (!this.IsWeb2Ready) return; + + var rgb = $"{accent.R} {accent.G} {accent.B}"; + await this.ExecuteScriptAsync($""" + document.documentElement.style.setProperty('--Accent', '{rgb}'); + """); + } + + + /// + /// Sets dark mode for content. Example: + /// + /// html color-mode="light" + /// + /// + public async Task SetWeb2DarkModeAsync(bool darkMode) + { + if (!this.IsWeb2Ready) return; + + var colorMode = darkMode ? "dark" : "light"; + await this.ExecuteScriptAsync($""" + document.documentElement.setAttribute('color-mode', '{colorMode}'); + """); + } + + + /// + /// Sets focus mode for content. Example: + /// + /// html window-focus="true" + /// + /// + public async Task SetWeb2WindowFocusAsync(bool focus) + { + if (!this.IsWeb2Ready) return; + + await this.ExecuteScriptAsync($""" + document.documentElement.setAttribute('window-focus', '{focus.ToString().ToLowerInvariant()}'); + """); + } + + + /// + /// Sets the visibility of . + /// If the is false, + /// the will be also suspended to consume less memory. + /// + public async Task SetWeb2VisibilityAsync(bool visible) + { + this.Visible = visible; + + if (!visible) + { + await TrySuspendWeb2Async(); + } + } + + + /// + /// Tries to suspend the instance to consume less memory. + /// + public async Task TrySuspendWeb2Async(int delayMs = 1000) + { + await Task.Delay(delayMs); + if (!this.IsWeb2Ready) return; + + try + { + _ = this.CoreWebView2.TrySuspendAsync(); + } + catch (InvalidOperationException) { } + } + + + /// + /// Post a message to web view. + /// + /// Name of the message + /// Message data + /// + public void PostWeb2Message(string name, string dataJson) + { + if (!this.IsWeb2Ready) return; + + + var json = @$" +{{ + ""Name"": ""{name}"", + ""Data"": {dataJson} +}}"; + + try + { + this.CoreWebView2.PostWebMessageAsJson(json); + } + catch (Exception ex) + { + throw new ArgumentException( + $"{ex}\r\n" + + $"JSON data:\r\n{json}\r\n\r\n" + + $"Error detail:\r\n", ex); + } + } + + #endregion // Public methods + + + + // Webview2 Events + #region Webview2 Events + + private void Web2_WebMessageReceived(object? sender, CoreWebView2WebMessageReceivedEventArgs e) + { + var msg = BHelper.ParseJson(e.WebMessageAsJson); + + if (msg.Name.Equals("KEYUP") && !string.IsNullOrWhiteSpace(msg.Data)) + { + var hotkey = new Hotkey(msg.Data); + SafeRunUi(async () => + { + await OnWeb2KeyUpAsync(new KeyEventArgs(hotkey.KeyData)); + }); + } + else if (msg.Name.Equals("KEYDOWN") && !string.IsNullOrWhiteSpace(msg.Data)) + { + if (EnableDebug && msg.Data == "ctrl+shift+i") + { + this.CoreWebView2.OpenDevToolsWindow(); + return; + } + + var hotkey = new Hotkey(msg.Data); + SafeRunUi(async () => + { + await OnWeb2KeyDownAsync(new KeyEventArgs(hotkey.KeyData)); + }); + } + else + { + SafeRunUi(async () => + { + var args = new Web2MessageReceivedEventArgs( + msg.Name.Trim(), + msg.Data?.Trim(), + e.AdditionalObjects + ); + await OnWeb2MessageReceivedAsync(args); + }); + } + } + + + private async void Web2_NavigationCompleted(object? sender, CoreWebView2NavigationCompletedEventArgs e) + { + if (this.Source.AbsoluteUri == "about:blank") return; + + var logTask = Task.CompletedTask; + + // disable console.log if not debug mode + if (!EnableDebug) + { + logTask = this.ExecuteScriptAsync($""" + console.log = () => undefined; + console.info = () => undefined; + """); + } + + // update border radius + var borderRadiusTask = Task.CompletedTask; + if (BHelper.IsOS(WindowsOS.Win10)) + { + borderRadiusTask = this.ExecuteScriptAsync($""" + document.documentElement.style.setProperty('--baseBorderRadius', '0'); + """); + } + + // update font size + const float defaultSystemFontSize = 9f; + var fontSizeTask = Task.CompletedTask; + if (Font.Size != defaultSystemFontSize) + { + const float defaultWebFontSize = 12.5f; + var newWebFontSize = Math.Round(Font.Size / defaultSystemFontSize * defaultWebFontSize, 2); + + fontSizeTask = this.ExecuteScriptAsync($""" + document.documentElement.style.setProperty('--fontSize', '{newWebFontSize}'); + """); + } + + // update color mode + var darkModeTask = SetWeb2DarkModeAsync(DarkMode); + var accentColorTask = SetWeb2AccentColorAsync(AccentColor); + + await Task.WhenAll(logTask, borderRadiusTask, fontSizeTask, darkModeTask, accentColorTask); + await OnWeb2NavigationCompleted(); + } + + + private void CoreWebView2_NewWindowRequested(object? sender, CoreWebView2NewWindowRequestedEventArgs e) + { + e.Handled = true; + _ = BHelper.OpenUrlAsync(e.Uri, $"app_{PageName}"); + } + + + private void CoreWebView2_ContextMenuRequested(object? sender, CoreWebView2ContextMenuRequestedEventArgs e) + { + // block the default context menu + e.Handled = true; + + _ = OnWeb2ContextMenuRequested(e); + } + + + /// + /// Safely run the action after the current event handler is completed, + /// to avoid potential reentrancy caused by running a nested message loop + /// in the WebView2 event handler. + /// Source: + /// + private static void SafeRunUi(Action action) + { + SynchronizationContext.Current.Post((_) => + { + action(); + }, null); + } + + #endregion // Webview2 Events + +} diff --git a/Source/Components/ImageGlass.Base/WinApi/ClipboardEx.cs b/Source/Components/ImageGlass.Base/WinApi/ClipboardEx.cs new file mode 100644 index 000000000..02d0add41 --- /dev/null +++ b/Source/Components/ImageGlass.Base/WinApi/ClipboardEx.cs @@ -0,0 +1,148 @@ +/* +ImageGlass Project - Image viewer for Windows +Copyright (C) 2010 - 2026 DUONG DIEU PHAP +Project homepage: https://imageglass.org + +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 . +*/ + +using System.Runtime.InteropServices; +using WicNet; + +namespace ImageGlass.Base.WinApi; + +/// +/// Support copy and paste transparent bitmap: +/// https://stackoverflow.com/a/46424800/2856887 +/// +public static class ClipboardEx +{ + + /// + /// Copies the given image to the clipboard as PNG, DIB and standard Bitmap format. + /// + /// Image to put on the clipboard. + /// + /// Optional specifically nontransparent version of the image to put on the clipboard. + /// + /// + /// Clipboard data object to put the image into. Might already contain other stuff. + /// Leave null to create a new one. + /// + public static void SetClipboardImage(WicBitmapSource? img, WicBitmapSource? nonAlphaImg = null, DataObject? data = null) + { + // https://stackoverflow.com/a/17762059/2856887 + BHelper.RunAsThread(() => + { + try + { + Clipboard.Clear(); + } + // Requested Clipboard operation did not succeed + catch (ExternalException) { } + + }, ApartmentState.STA).Join(); + + var clonedImg = img?.Clone(); + if (clonedImg == null) return; + + data ??= new DataObject(); + nonAlphaImg ??= clonedImg; + + + // As standard bitmap, without transparency support + data.SetData(DataFormats.Bitmap, true, BHelper.ToGdiPlusBitmap(nonAlphaImg)); + + // As PNG. Gimp will prefer this over the other two. + using var pngMemStream = new MemoryStream(); + clonedImg.Save(pngMemStream, WicCodec.GUID_ContainerFormatPng); + data.SetData("PNG", false, pngMemStream); + + // The 'copy=true' argument means the MemoryStreams can be safely disposed + // after the operation. + BHelper.RunAsThread(() => + { + try + { + Clipboard.SetDataObject(data, true); + } + // Requested Clipboard operation did not succeed + catch (ExternalException) { } + + }, ApartmentState.STA).Join(); + } + + + /// + /// Retrieves an image from the given clipboard data object, + /// in the order PNG, DIB, Bitmap, Image object. + /// + /// The clipboard data. + /// The extracted image, or null if no supported image type was found. + public static WicBitmapSource? GetClipboardImage() + { + var dataObj = Clipboard.GetDataObject(); + if (dataObj == null) return null; + + WicBitmapSource? clipboardImage = null; + + // Order: try PNG, move on to try 32-bit ARGB DIB, then try the normal + // Bitmap and Image types. + if (dataObj.GetDataPresent("PNG", false)) + { + if (dataObj.GetData("PNG", false) is MemoryStream pngStream) + { + using var wicBmp = BHelper.ToWicBitmapSource(pngStream); + clipboardImage = wicBmp?.Clone(); + } + } + + if (clipboardImage == null && dataObj.GetDataPresent(DataFormats.Bitmap)) + { + if (dataObj.GetData(DataFormats.Bitmap) is Image img) + { + clipboardImage = BHelper.ToWicBitmapSource(img); + } + } + + if (clipboardImage == null && dataObj.GetDataPresent(typeof(Image))) + { + if (dataObj.GetData(typeof(Image)) is Image img) + { + clipboardImage = BHelper.ToWicBitmapSource(img); + } + } + + return clipboardImage; + } + + + /// + /// Indicates whether the clipboard contains an image. + /// + public static bool ContainsImage() + { + var dataObj = Clipboard.GetDataObject(); + if (dataObj == null) return false; + + // Order: try PNG, move on to try 32-bit ARGB DIB, then try the normal + // Bitmap and Image types. + var hasPng = dataObj.GetDataPresent("PNG", false); + var hasBitmap = Clipboard.ContainsImage(); + var hasImage = dataObj.GetDataPresent(typeof(Image)); + + return hasPng || hasBitmap || hasImage; + } + +} diff --git a/Source/Components/ImageGlass.Base/WinApi/DesktopApi.cs b/Source/Components/ImageGlass.Base/WinApi/DesktopApi.cs new file mode 100644 index 000000000..0d44f4a33 --- /dev/null +++ b/Source/Components/ImageGlass.Base/WinApi/DesktopApi.cs @@ -0,0 +1,97 @@ +/* +ImageGlass Project - Image viewer for Windows +Copyright (C) 2010 - 2026 DUONG DIEU PHAP +Project homepage: https://imageglass.org + +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 . +*/ +using Microsoft.Win32; +using Windows.Win32; +using Windows.Win32.UI.WindowsAndMessaging; + +namespace ImageGlass.Base.WinApi; + + +public enum WallpaperStyle : int +{ + /// + /// Current windows wallpaper style + /// + Current = -1, + Centered = 0, + Stretched = 1, + Tiled = 2, +} + + +public static partial class DesktopApi +{ + /// + /// Set the desktop wallpaper. + /// + /// BMP image file path + /// Style of wallpaper + /// Success/failure indication. + public static unsafe Exception? SetWallpaper(string bmpPath, WallpaperStyle style) + { + try + { + using var key = Registry.CurrentUser.OpenSubKey(@"Control Panel\Desktop", true); + + if (key == null) + { + throw new Exception($"Cannot open registry key: {key}"); + } + + var tileVal = "0"; // default not-tiled + var winStyle = "1"; // default centered + + switch (style) + { + case WallpaperStyle.Tiled: + tileVal = "1"; + break; + + case WallpaperStyle.Stretched: + winStyle = "2"; + break; + + case WallpaperStyle.Current: + tileVal = key.GetValue("TileWallpaper")?.ToString() ?? ""; + winStyle = key.GetValue("WallpaperStyle")?.ToString() ?? ""; + break; + } + + key.SetValue("TileWallpaper", tileVal); + key.SetValue("WallpaperStyle", winStyle); + key.SetValue("Wallpaper", bmpPath); + + + fixed (char* pathPtr = bmpPath) + { + _ = PInvoke.SystemParametersInfo( + SYSTEM_PARAMETERS_INFO_ACTION.SPI_SETDESKWALLPAPER, + 0, pathPtr, + SYSTEM_PARAMETERS_INFO_UPDATE_FLAGS.SPIF_UPDATEINIFILE | SYSTEM_PARAMETERS_INFO_UPDATE_FLAGS.SPIF_SENDWININICHANGE); + } + } + catch (Exception ex) + { + return ex; + } + + return null; + } + +} diff --git a/Source/Components/ImageGlass.Base/WinApi/DisplayApi.cs b/Source/Components/ImageGlass.Base/WinApi/DisplayApi.cs new file mode 100644 index 000000000..37324eb95 --- /dev/null +++ b/Source/Components/ImageGlass.Base/WinApi/DisplayApi.cs @@ -0,0 +1,193 @@ +/* +ImageGlass Project - Image viewer for Windows +Copyright (C) 2010 - 2026 DUONG DIEU PHAP +Project homepage: https://imageglass.org + +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 . +*/ +using System.Runtime.InteropServices; +using System.Text; + +namespace ImageGlass.Base.WinApi; + + +public class DisplayApi +{ + [DllImport("mscms.dll", CharSet = CharSet.Unicode)] + static extern bool GetColorDirectory( + [MarshalAs(UnmanagedType.LPWStr)] string? pMachineName, + StringBuilder pBuffer, + ref uint pdwSize); + + [DllImport("mscms.dll", CharSet = CharSet.Auto)] + static extern bool WcsGetUsePerUserProfiles( + [MarshalAs(UnmanagedType.LPWStr)] string deviceName, + uint deviceClass, + out bool usePerUserProfiles); + + [DllImport("mscms.dll", CharSet = CharSet.Auto)] + static extern bool WcsGetDefaultColorProfileSize( + WcsProfileManagementScope scope, + [MarshalAs(UnmanagedType.LPWStr)] string deviceName, + ColorProfileType colorProfileType, + ColorProfileSubtype colorProfileSubType, + uint dwProfileID, + out uint cbProfileName); + + [DllImport("mscms.dll", CharSet = CharSet.Unicode)] + static extern bool WcsGetDefaultColorProfile( + WcsProfileManagementScope scope, + [MarshalAs(UnmanagedType.LPWStr)] string deviceName, + ColorProfileType colorProfileType, + ColorProfileSubtype colorProfileSubType, + uint dwProfileID, + uint cbProfileName, + StringBuilder pProfileName); + + enum WcsProfileManagementScope + { + SYSTEM_WIDE, + CURRENT_USER + } + enum ColorProfileType + { + ICC, + DMP, + CAMP, + GMMP + }; + + enum ColorProfileSubtype + { + PERCEPTUAL, + RELATIVE_COLORIMETRIC, + SATURATION, + ABSOLUTE_COLORIMETRIC, + NONE, + RGB_WORKING_SPACE, + CUSTOM_WORKING_SPACE, + STANDARD_DISPLAY_COLOR_MODE, + EXTENDED_DISPLAY_COLOR_MODE + }; + + const uint CLASS_MONITOR = 0x6d6e7472; //'mntr' + const uint CLASS_PRINTER = 0x70727472; //'prtr' + const uint CLASS_SCANNER = 0x73636e72; //'scnr' + + + + + + [DllImport("user32.dll")] + static extern IntPtr MonitorFromWindow(IntPtr hWnd, MonitorDefaults dwFlags); + + [DllImport("user32.dll")] + extern static bool GetMonitorInfo(IntPtr hMonitor, ref MONITORINFOEX lpmi); + + [DllImport("user32.dll", CharSet = CharSet.Unicode)] + static extern bool EnumDisplayDevices(string lpDevice, uint iDevNum, ref DISPLAYDEVICE lpDisplayDevice, uint dwFlags); + + enum MonitorDefaults + { + TONULL = 0, + TOPRIMARY = 1, + TONEAREST = 2 + } + + [StructLayout(LayoutKind.Sequential)] + struct MONITORINFOEX + { + public uint cbSize; + public RECT rcMonitor; + public RECT rcWork; + public uint dwFlags; + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)] + public string szDevice; + } + + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] + struct DISPLAYDEVICE + { + public uint cb; + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)] + public string DeviceName; + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)] + public string DeviceString; + public uint StateFlags; + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)] + public string DeviceID; + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)] + public string DeviceKey; + } + + [StructLayout(LayoutKind.Sequential)] + struct RECT + { + public int Left; + public int Top; + public int Right; + public int Bottom; + } + + + + /// + /// Gets color profile file path from window. + /// + /// Window handle + /// Full file path of the color profile file. + public static string? GetMonitorColorProfileFromWindow(IntPtr windowHandle) + { + try + { + var hMonitor = MonitorFromWindow(windowHandle, MonitorDefaults.TONEAREST); + + return GetMonitorColorProfile(hMonitor); + } + catch { } + + return string.Empty; + } + + + private static string? GetMonitorColorProfile(IntPtr hMonitor) + { + var profileDir = new StringBuilder(255); + var pDirSize = (uint)profileDir.Capacity; + GetColorDirectory(null, profileDir, ref pDirSize); + + var mInfo = new MONITORINFOEX(); + mInfo.cbSize = (uint)Marshal.SizeOf(mInfo); + if (!GetMonitorInfo(hMonitor, ref mInfo)) + return null; + + var dd = new DISPLAYDEVICE(); + dd.cb = (uint)Marshal.SizeOf(dd); + if (!EnumDisplayDevices(mInfo.szDevice, 0, ref dd, 0)) + return null; + + WcsGetUsePerUserProfiles(dd.DeviceKey, CLASS_MONITOR, out var usePerUserProfiles); + var scope = usePerUserProfiles ? WcsProfileManagementScope.CURRENT_USER : WcsProfileManagementScope.SYSTEM_WIDE; + + if (!WcsGetDefaultColorProfileSize(scope, dd.DeviceKey, ColorProfileType.ICC, ColorProfileSubtype.NONE, 0, out var size)) + return null; + + var profileName = new StringBuilder((int)size); + if (!WcsGetDefaultColorProfile(scope, dd.DeviceKey, ColorProfileType.ICC, ColorProfileSubtype.NONE, 0, size, profileName)) + return null; + + return Path.Combine(profileDir.ToString(), profileName.ToString()); + } + +} diff --git a/Source/Components/ImageGlass.Base/WinApi/DpiApi.cs b/Source/Components/ImageGlass.Base/WinApi/DpiApi.cs new file mode 100644 index 000000000..9bece96fe --- /dev/null +++ b/Source/Components/ImageGlass.Base/WinApi/DpiApi.cs @@ -0,0 +1,121 @@ +/* +ImageGlass Project - Image viewer for Windows +Copyright (C) 2010 - 2026 DUONG DIEU PHAP +Project homepage: https://imageglass.org + +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 . +*/ + +using Windows.Win32; +using Windows.Win32.Graphics.Gdi; +using Windows.Win32.UI.HiDpi; + +namespace ImageGlass.Base.WinApi; + +public static class DpiApi +{ + private static int _currentDpi = DPI_DEFAULT; + + public const int WM_DPICHANGED = 0x02E0; + public const int DPI_DEFAULT = 96; + + /// + /// Occurs when the is changed. + /// + public static event DpiChangedHandler? OnDpiChanged = null; + public delegate void DpiChangedHandler(); + + + /// + /// Gets, sets current DPI scaling value + /// + public static int CurrentDpi + { + get => _currentDpi; + set + { + _currentDpi = value; + OnDpiChanged?.Invoke(); + } + } + + + /// + /// Get DPI Scale factor. + /// + public static float DpiScale => (float)CurrentDpi / DPI_DEFAULT; + + + /// + /// Scales a number after applying + /// + public static T Scale(T num, float? dpiScale = null) + { + dpiScale ??= DpiScale; + + var type = typeof(T); + var value = float.Parse(num.ToString()) * dpiScale; + + return (T)Convert.ChangeType(value, type); + } + + + /// + /// Scales padding after applying + /// + public static Padding Scale(Padding padding, float? dpiScale = null) + { + return new Padding( + Scale(padding.Left, dpiScale), + Scale(padding.Top, dpiScale), + Scale(padding.Right, dpiScale), + Scale(padding.Bottom, dpiScale)); + } + + + /// + /// Scales padding after applying + /// + public static SizeF Scale(SizeF size, float? dpiScale = null) + { + return new SizeF(Scale(size.Width, dpiScale), Scale(size.Height, dpiScale)); + } + + + + /// + /// Gets DPI scale from a screen. + /// + public static float GetDpiScale(this Screen screen) + { + var point = new Point(screen.Bounds.Left + 1, screen.Bounds.Top + 1); + + return GetDpiScale(point); + } + + + /// + /// Gets DPI scale from a point on the screen. + /// + public static float GetDpiScale(Point screenPoint) + { + var hMonitor = PInvoke.MonitorFromPoint(screenPoint, MONITOR_FROM_FLAGS.MONITOR_DEFAULTTONEAREST); + _ = PInvoke.GetDpiForMonitor(hMonitor, MONITOR_DPI_TYPE.MDT_EFFECTIVE_DPI, out var dpiX, out _); + + + return (float)dpiX / DPI_DEFAULT; + } + +} + diff --git a/Source/Components/ImageGlass.Base/WinApi/ExplorerApi.cs b/Source/Components/ImageGlass.Base/WinApi/ExplorerApi.cs new file mode 100644 index 000000000..705950ebc --- /dev/null +++ b/Source/Components/ImageGlass.Base/WinApi/ExplorerApi.cs @@ -0,0 +1,585 @@ +/* +ImageGlass Project - Image viewer for Windows +Copyright (C) 2010 - 2026 DUONG DIEU PHAP +Project homepage: https://imageglass.org + +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 . +*/ + +using Microsoft.Win32; +using System.Runtime.InteropServices; +using System.Text; +using Windows.Win32; +using Windows.Win32.Foundation; +using Windows.Win32.UI.Shell; + +namespace ImageGlass.Base.WinApi; +public static class ExplorerApi +{ + #region COM and WinAPI + + + [DllImport("shell32.dll", SetLastError = true)] + private static extern int SHOpenFolderAndSelectItems(IntPtr pidlFolder, + uint cidl, [In, MarshalAs(UnmanagedType.LPArray)] IntPtr[] apidl, uint dwFlags); + + [DllImport("shell32.dll", SetLastError = true)] + private static extern void SHParseDisplayName( + [MarshalAs(UnmanagedType.LPWStr)] string name, IntPtr bindingContext, + [Out] out IntPtr pidl, uint sfgaoIn, [Out] out uint psfgaoOut); + + [DllImport("shell32.dll", SetLastError = true, CharSet = CharSet.Unicode)] + private static extern bool SHGetPathFromIDList(IntPtr pidl, StringBuilder pszPath); + + + internal static readonly Guid SID_STopLevelBrowser = new( + 0x4C96BE40, 0x915C, 0x11CF, 0x99, 0xD3, 0x00, 0xAA, 0x00, 0x4A, 0xE8, 0x37); + internal static readonly Guid SID_ShellWindows = new( + 0x9BA05972, 0xF6A8, 0x11CF, 0xA4, 0x42, 0x00, 0xA0, 0xC9, 0x0A, 0x8F, 0x39); + + [InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("6D5140C1-7436-11CE-8034-00AA006009FA")] + internal interface IServiceProvider + { + void QueryService( + [MarshalAs(UnmanagedType.LPStruct)] Guid guidService, + [MarshalAs(UnmanagedType.LPStruct)] Guid riid, + [MarshalAs(UnmanagedType.IUnknown)] out object ppvObject); + } + + [InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("1AC3D9F0-175C-11d1-95BE-00609797EA4F")] + internal interface IPersistFolder2 + { + void GetClassID(out Guid pClassID); + void Initialize(IntPtr pidl); + void GetCurFolder(out IntPtr pidl); + } + + [InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("000214E2-0000-0000-C000-000000000046")] + internal interface IShellBrowser + { + void _VtblGap0_12(); // skip 12 members + void QueryActiveShellView([MarshalAs(UnmanagedType.IUnknown)] out object ppshv); + + // the rest is not defined + } + + [InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("cde725b0-ccc9-4519-917e-325d72fab4ce")] + internal interface IFolderView + { + void _VtblGap0_2(); // skip 2 members + void GetFolder( + [MarshalAs(UnmanagedType.LPStruct)] Guid riid, + [MarshalAs(UnmanagedType.IUnknown)] out object ppv); + + // the rest is not defined + } + + #endregion + + + /// + /// Open folder and select an item. + /// + /// + /// will not always find the correct folder. If the user + /// has a folder open that is rooted in their user folder (e.g. the desktop, + /// Dropbox/Mega/Nextcloud folder), this won't match the folder reference + /// returned by if given the actual path + /// of the same folder. This will result in opening a duplicate folder. + /// + /// So instead, we iterate through open folder windows for a path match first, + /// then use the old method if one is not found. + /// + /// Full path to a file to highlight in Explorer + public static void OpenFolderAndSelectItem(string filePath) + { + var folderPath = Path.GetDirectoryName(filePath); + bool opened = false; + + var shellWindowsType = Type.GetTypeFromCLSID(SID_ShellWindows); + var shellWindows = (dynamic?)Activator.CreateInstance(shellWindowsType); + + try + { + foreach (IServiceProvider sp in shellWindows) + { + var pidl = IntPtr.Zero; + var nativeFile = IntPtr.Zero; + + try + { + sp.QueryService(SID_STopLevelBrowser, typeof(IShellBrowser).GUID, out object sb); + IShellBrowser shellBrowser = (IShellBrowser)sb; + + shellBrowser.QueryActiveShellView(out object sv); + + if (sv is IFolderView fv) + { + // only folder implementation support this (IE windows do not for example) + fv.GetFolder(typeof(IPersistFolder2).GUID, out object pf); + IPersistFolder2 persistFolder = (IPersistFolder2)pf; + + // get current folder pidl + persistFolder.GetCurFolder(out pidl); + + var path = new StringBuilder(1024); + if (SHGetPathFromIDList(pidl, path)) + { + if (string.Equals(path.ToString(), folderPath, StringComparison.InvariantCultureIgnoreCase)) + { + SHParseDisplayName(Path.Combine(folderPath, filePath), IntPtr.Zero, out nativeFile, 0, out _); + + IntPtr[] fileArray; + if (nativeFile == IntPtr.Zero) + { + // Open the folder without the file selected + // if we can't find the file + fileArray = []; + } + else + { + fileArray = [nativeFile]; + } + + _ = SHOpenFolderAndSelectItems(pidl, (uint)fileArray.Length, fileArray, 0); + opened = true; + + break; + } + } + } + } + finally + { + if (nativeFile != IntPtr.Zero) + { + Marshal.FreeCoTaskMem(nativeFile); + } + + if (pidl != IntPtr.Zero) + { + Marshal.FreeCoTaskMem(pidl); + } + + Marshal.ReleaseComObject(sp); + } + } + } + finally + { + Marshal.FinalReleaseComObject(shellWindows); + } + + if (!opened) + { + SHParseDisplayName(folderPath, IntPtr.Zero, out IntPtr nativeFolder, 0, out _); + + if (nativeFolder == IntPtr.Zero) + { + // Log error, can't find folder + return; + } + + SHParseDisplayName(Path.Combine(folderPath, filePath), IntPtr.Zero, out IntPtr nativeFile, 0, out _); + + IntPtr[] fileArray; + if (nativeFile == IntPtr.Zero) + { + // Open the folder without the file selected if we can't find the file + fileArray = []; + } + else + { + fileArray = [nativeFile]; + } + + _ = SHOpenFolderAndSelectItems(nativeFolder, (uint)fileArray.Length, fileArray, 0); + + Marshal.FreeCoTaskMem(nativeFolder); + if (nativeFile != IntPtr.Zero) + { + Marshal.FreeCoTaskMem(nativeFile); + } + } + } + + + /// + /// Show file property dialog + /// + /// Full file path + /// Form handle + public static unsafe void DisplayFileProperties(string filePath, IntPtr hwnd) + { + const int SEE_MASK_INVOKEIDLIST = 0xc; + const int SW_SHOW = 5; + var shInfo = new SHELLEXECUTEINFOW(); + + fixed (char* pFilePath = filePath) + { + fixed (char* pVerb = "properties") + { + fixed (char* pParams = "Details") + { + shInfo.cbSize = (uint)Marshal.SizeOf(shInfo); + shInfo.lpFile = pFilePath; + shInfo.nShow = SW_SHOW; + shInfo.fMask = SEE_MASK_INVOKEIDLIST; + shInfo.lpVerb = pVerb; + shInfo.lpParameters = pParams; + shInfo.hwnd = new HWND(hwnd); + } + } + } + + _ = PInvoke.ShellExecuteEx(ref shInfo); + } + + + /// + /// Apply system theme to control. + /// + public static bool SetWindowTheme(IntPtr handle, string subIdList = "", bool darkMode = true) + { + return SetWindowTheme(handle, darkMode ? "DarkMode_Explorer" : "Explorer", subIdList); + } + + + /// + /// Apply system theme to control. + /// + public static bool SetWindowTheme(IntPtr handle, string subAppName, string subIdList = "") + { + var result = PInvoke.SetWindowTheme(new HWND(handle), subAppName, subIdList); + + return result.Succeeded; + } + + + // File type associations & App protocol + #region File type associations & App protocol + + /// + /// Register file type associations and app capabilities to registry + /// + /// Extension string, ex: .png;.svg; + /// + /// If true, uses HKEY_LOCAL_MACHINE, + /// otherwise uses HKEY_CURRENT_USER + /// + public static Exception? RegisterAppAndExtensions(string extensions, bool perMachine = false) + { + _ = UnregisterAppAndExtensions(extensions); + + const string APP_NAME = "ImageGlass"; + var capabilitiesPath = $@"Software\{APP_NAME}\Capabilities"; + using var BASE_KEY = perMachine ? Registry.LocalMachine : Registry.CurrentUser; + + try + { + // register the application: + // HKEY_XXX\SOFTWARE\RegisteredApplications -------------------------------- + const string regAppPath = @"Software\RegisteredApplications"; + using (var key = BASE_KEY.OpenSubKey(regAppPath, true)) + { + key?.SetValue(APP_NAME, capabilitiesPath); + } + + + // register application information: + // HKEY_XXX\SOFTWARE\ImageGlass\Capabilities ------------------------------- + using (var key = BASE_KEY.CreateSubKey(capabilitiesPath, true)) + { + key?.SetValue("ApplicationName", App.AppName); + key?.SetValue("ApplicationIcon", $"\"{App.IGExePath}\", 0"); + key?.SetValue("ApplicationDescription", "A lightweight, versatile image viewer"); + + + // Register application's file type associations: + // HKEY_XXX\SOFTWARE\ImageGlass\Capabilities\FileAssociations ---------- + using (var faKey = key?.CreateSubKey("FileAssociations", true)) + { + var exts = extensions.Split(";", StringSplitOptions.RemoveEmptyEntries); + + foreach (var ext in exts) + { + var extNoDot = ext[1..].ToUpperInvariant(); + var extAssocKey = $"{APP_NAME}.AssocFile.{extNoDot}"; + var extAssocPath = $@"Software\Classes\{extAssocKey}"; + + // register supported extension + faKey?.SetValue(ext, extAssocKey); + + + // write extension info + // HKEY_XXX\SOFTWARE\Classes\ImageGlass.AssocFile. + using (var extRootKey = BASE_KEY.CreateSubKey(extAssocPath, true)) + { + // DefaultIcon ------------------------------------------------------- + // get extension icon + var extDir = App.ConfigDir(PathType.Dir, Dir.ExtIcons); + var iconPath = Path.Combine(extDir, $"{extNoDot}.ico"); + if (!File.Exists(iconPath)) + { + iconPath = App.StartUpDir(Dir.ExtIcons, $"{extNoDot}.ico"); + + if (!File.Exists(iconPath)) + { + iconPath = string.Empty; + } + } + + + // set extension icon + if (!string.IsNullOrEmpty(iconPath)) + { + using (var faIconKey = extRootKey?.CreateSubKey("DefaultIcon", true)) + { + faIconKey?.SetValue("", iconPath); + } + } + + + // shell/open -------------------------------------------------------- + using (var shellOpenKey = extRootKey?.CreateSubKey(@"shell\open", true)) + { + shellOpenKey?.SetValue("FriendlyAppName", App.AppName); + + + // shell/open/command -------------------------------------------- + using var shellOpenCmdKey = shellOpenKey?.CreateSubKey("command", true); + shellOpenCmdKey?.SetValue("", $"\"{App.IGExePath}\" \"%1\""); + } + } + } + } + } + + + // register app protocol + _ = RegisterAppProtocol(); + + + unsafe + { + // notify system change + PInvoke.SHChangeNotify(SHCNE_ID.SHCNE_ASSOCCHANGED, SHCNF_FLAGS.SHCNF_IDLIST, (byte*)IntPtr.Zero, (byte*)IntPtr.Zero); + } + } + catch (Exception ex) + { + return ex; + } + + return null; + } + + + /// + /// Unregister file type associations and app information from registry + /// + /// Extensions string to delete. Ex: .png;.svg; + /// + /// If true, uses HKEY_LOCAL_MACHINE, + /// otherwise uses HKEY_CURRENT_USER + /// + public static Exception? UnregisterAppAndExtensions(string extensions, bool perMachine = false) + { + // remove registry of ImageGlass v8 + _ = UnregisterAppAndExtensionsLegacy(extensions); + + const string APP_NAME = "ImageGlass"; + using var BASE_KEY = perMachine ? Registry.LocalMachine : Registry.CurrentUser; + + try + { + // Unregister the application: + // HKEY_XXX\SOFTWARE\RegisteredApplications -------------------------------- + const string regAppPath = @"Software\RegisteredApplications"; + using (var key = BASE_KEY.OpenSubKey(regAppPath, true)) + { + if (key.OpenSubKey(APP_NAME, true) != null) + { + key?.DeleteValue(APP_NAME); + } + } + + + // Delete application information: + // HKEY_XXX\SOFTWARE\ImageGlass -------------------------------------------- + using (var key = BASE_KEY.OpenSubKey("Software", true)) + { + key?.DeleteSubKeyTree(APP_NAME, false); + } + + + // Delete file type associations + // HKEY_XXX\Software\Classes\ImageGlass.AssocFile. + var exts = extensions.Split(";", StringSplitOptions.RemoveEmptyEntries); + foreach (var ext in exts) + { + var extNoDot = ext[1..].ToUpperInvariant(); + var extAssocPath = $@"Software\Classes\{APP_NAME}.AssocFile.{extNoDot}"; + + BASE_KEY.DeleteSubKeyTree(extAssocPath, false); + } + + + // Delete app protocol + _ = UnregisterAppProtocol(); + + + unsafe + { + // notify system change + PInvoke.SHChangeNotify(SHCNE_ID.SHCNE_ASSOCCHANGED, SHCNF_FLAGS.SHCNF_IDLIST, (byte*)IntPtr.Zero, (byte*)IntPtr.Zero); + } + } + catch (Exception ex) + { + return ex; + } + + return null; + } + + + /// + /// Unregister file type associations and app information from registry for ImageGlass v8. + /// + /// Extensions string to delete. Ex: .png;.svg; + public static Exception? UnregisterAppAndExtensionsLegacy(string extensions) + { + const string APP_NAME = "ImageGlass"; + + try + { + // Unregister the application: + // HKEY_LOCAL_MACHINE\SOFTWARE\RegisteredApplications -------------------------------- + const string regAppPath = @"Software\RegisteredApplications"; + using (var key = Registry.LocalMachine.OpenSubKey(regAppPath, true)) + { + if (key.OpenSubKey(APP_NAME, true) != null) + { + key?.DeleteValue(APP_NAME); + } + } + + + // Delete application information: + // HKEY_LOCAL_MACHINE\SOFTWARE\ImageGlass -------------------------------------------- + using (var key = Registry.LocalMachine.OpenSubKey("Software", true)) + { + key?.DeleteSubKeyTree(APP_NAME, false); + } + + + // Delete file type associations + // HKEY_CLASSES_ROOT\ImageGlass.AssocFile. + var exts = extensions.Split(";", StringSplitOptions.RemoveEmptyEntries); + foreach (var ext in exts) + { + var extNoDot = ext[1..].ToUpperInvariant(); + var extAssocKey = $"{APP_NAME}.AssocFile.{extNoDot}"; + + Registry.ClassesRoot.DeleteSubKeyTree(extAssocKey, false); + } + } + catch (Exception ex) + { + return ex; + } + + return null; + } + + + /// + /// Register app protocol to registry. + /// + /// If true, uses HKEY_LOCAL_MACHINE, + /// otherwise uses HKEY_CURRENT_USER + /// + /// + public static Exception? RegisterAppProtocol(bool perMachine = false) + { + using var BASE_KEY = perMachine ? Registry.LocalMachine : Registry.CurrentUser; + + try + { + // HKEY_CURRENT_USER\Software\Classes\ -------------------------------- + const string protocolPath = $@"Software\Classes\{Const.APP_PROTOCOL}"; + using (var key = BASE_KEY.CreateSubKey(protocolPath, true)) + { + key?.SetValue("", $"URL: {App.AppName} Protocol"); + key?.SetValue("URL Protocol", ""); + + // set protocol icon + // HKEY_CURRENT_USER\Software\Classes\\DefaultIcon ---------------- + using (var subKey = key.CreateSubKey(@"DefaultIcon", true)) + { + subKey?.SetValue("", $"\"{App.IGExePath}\", 0"); + } + + // set protocol command + // HKEY_CURRENT_USER\Software\Classes\\shell\open\command --------- + using (var subKey = key.CreateSubKey(@"shell\open\command", true)) + { + subKey?.SetValue("", $"\"{App.IGExePath}\" \"%1\""); + } + } + } + catch (Exception ex) + { + return ex; + } + + return null; + } + + + /// + /// Delete app protocol from registry. + /// + /// If true, uses HKEY_LOCAL_MACHINE, + /// otherwise uses HKEY_CURRENT_USER + /// + /// + public static Exception? UnregisterAppProtocol(bool perMachine = false) + { + using var BASE_KEY = perMachine ? Registry.LocalMachine : Registry.CurrentUser; + + try + { + // HKEY_CURRENT_USER\Software\Classes ----------------------------------------------- + const string protocolPath = $@"Software\Classes"; + using (var key = BASE_KEY.OpenSubKey(protocolPath, true)) + { + // delete tree: + // HKEY_CURRENT_USER\Software\Classes\ ---------------------------- + key?.DeleteSubKeyTree(Const.APP_PROTOCOL, false); + } + } + catch (Exception ex) + { + return ex; + } + + return null; + } + + #endregion // File type associations & App protocol + + +} diff --git a/Source/Components/ImageGlass.Base/WinApi/FileShortcutApi.cs b/Source/Components/ImageGlass.Base/WinApi/FileShortcutApi.cs new file mode 100644 index 000000000..9f22f5d74 --- /dev/null +++ b/Source/Components/ImageGlass.Base/WinApi/FileShortcutApi.cs @@ -0,0 +1,80 @@ +/* +ImageGlass Project - Image viewer for Windows +Copyright (C) 2010 - 2026 DUONG DIEU PHAP +Project homepage: https://imageglass.org + +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 . +*/ +namespace ImageGlass.Base.WinApi; + +public static class FileShortcutApi +{ + public enum ShortcutWindowStyle + { + Normal = 4, + Maximized = 3, + Minimized = 7, + } + + + /// + /// Get the target path from shortcut (*.lnk) + /// + /// Path of shortcut (*.lnk) + /// + public static string GetTargetPathFromShortcut(string shortcutPath) + { + var shell = new IWshRuntimeLibrary.WshShell(); + + try + { + var shortcut = (IWshRuntimeLibrary.IWshShortcut)shell.CreateShortcut(shortcutPath); + + return shortcut.TargetPath ?? ""; + } + catch // (COMException) + { + // A COMException is thrown if the file is not a valid shortcut (.lnk) file + return ""; + } + } + + + /// + /// Create shortcut file + /// + /// + /// + /// + /// + public static void CreateShortcut(string shortcutPath, + string targetPath, + string args = "", + ShortcutWindowStyle windowStyle = ShortcutWindowStyle.Normal) + { + var shell = new IWshRuntimeLibrary.WshShell(); + + try + { + var shortcut = (IWshRuntimeLibrary.IWshShortcut)shell.CreateShortcut(shortcutPath); + + shortcut.TargetPath = targetPath; + shortcut.IconLocation = targetPath; + shortcut.Arguments = args; + shortcut.WindowStyle = (int)windowStyle; + shortcut.Save(); + } + catch { } + } +} diff --git a/Source/Components/ImageGlass.Services/InstanceManagement/NativeMethods.cs b/Source/Components/ImageGlass.Base/WinApi/FormIconApi.cs similarity index 53% rename from Source/Components/ImageGlass.Services/InstanceManagement/NativeMethods.cs rename to Source/Components/ImageGlass.Base/WinApi/FormIconApi.cs index 9e80531b0..122da472a 100644 --- a/Source/Components/ImageGlass.Services/InstanceManagement/NativeMethods.cs +++ b/Source/Components/ImageGlass.Base/WinApi/FormIconApi.cs @@ -1,7 +1,7 @@ /* ImageGlass Project - Image viewer for Windows -Copyright (C) 2020 DUONG DIEU PHAP -Project homepage: http://imageglass.org +Copyright (C) 2010 - 2026 DUONG DIEU PHAP +Project homepage: https://imageglass.org 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 @@ -17,21 +17,24 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -using System; -using System.Runtime.InteropServices; +using Windows.Win32; +using Windows.Win32.Foundation; -namespace ImageGlass.Services.InstanceManagement -{ - public class NativeMethods - { - [DllImport("user32")] - public static extern bool PostMessage(IntPtr hwnd, int msg, IntPtr wparam, IntPtr lparam); +namespace ImageGlass.Base.WinApi; +public static class FormIconApi +{ + private const uint WM_SETICON = 0x80u; + private const int ICON_BIG = 1; - [DllImport("user32", CharSet = CharSet.Unicode)] - public static extern int RegisterWindowMessage(string message); - public const int HWND_BROADCAST = 0xffff; - public static readonly int WM_SHOWME = RegisterWindowMessage("WM_SHOWME"); + /// + /// Sets icon to taskbar + /// + /// Form + /// Icon handler + public static void SetTaskbarIcon(Form frm, IntPtr iconPointer) + { + _ = PInvoke.SendMessage(new HWND(frm.Handle), WM_SETICON, ICON_BIG, iconPointer); } -} +} \ No newline at end of file diff --git a/Source/Components/ImageGlass.Base/WinApi/KeyboardApi.cs b/Source/Components/ImageGlass.Base/WinApi/KeyboardApi.cs new file mode 100644 index 000000000..d5237a863 --- /dev/null +++ b/Source/Components/ImageGlass.Base/WinApi/KeyboardApi.cs @@ -0,0 +1,103 @@ +/* +ImageGlass Project - Image viewer for Windows +Copyright (C) 2010 - 2026 DUONG DIEU PHAP +Project homepage: https://imageglass.org + +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 . +*/ +using System.Runtime.InteropServices; +using Windows.Win32; +using Windows.Win32.UI.Input.KeyboardAndMouse; + +namespace ImageGlass.Base.WinApi; + +public class KeyboardApi +{ + + [DllImport("user32.dll")] + private static extern bool ToAsciiEx(int virtualKey, int scanCode, byte[] lpKeyState, ref uint lpChar, int uFlags, IntPtr dwhkl); + + + + /// + /// Converts virtual key to string. + /// + public static unsafe char KeyCodeToChar(Keys key, bool withShiftKey) + { + var lpChar = 0u; + var lpKeyState = new byte[256]; + + if (withShiftKey) + { + foreach (Keys sKey in Enum.GetValues(typeof(Keys))) + { + if (sKey.HasFlag(Keys.ShiftKey)) + { + lpKeyState[(int)sKey] = 0x80; + } + } + } + + // always use en-US keyboard layout + nint langHandle; + try + { + var culture = new System.Globalization.CultureInfo("en-US"); + langHandle = InputLanguage.FromCulture(culture).Handle; + } + catch + { + langHandle = InputLanguage.DefaultInputLanguage.Handle; + } + + var keyboardLayoutPtr = new HKL(langHandle); + var virtualKeyCode = (uint)key; + var scanCode = PInvoke.MapVirtualKey(virtualKeyCode, MAP_VIRTUAL_KEY_TYPE.MAPVK_VK_TO_VSC); + + _ = ToAsciiEx((int)key, (int)scanCode, lpKeyState, ref lpChar, 0, keyboardLayoutPtr); + + return (char)lpChar; + } + + + /// + /// Convert character to virtual key + /// + public static Keys CharToKeyCode(char c) + { + // always use en-US keyboard layout + nint langHandle; + try + { + var culture = new System.Globalization.CultureInfo("en-US"); + langHandle = InputLanguage.FromCulture(culture).Handle; + } + catch + { + langHandle = InputLanguage.DefaultInputLanguage.Handle; + } + + var keyboardLayoutPtr = new HKL(langHandle); + var vkey = PInvoke.VkKeyScanEx(c, keyboardLayoutPtr); + var keys = (Keys)(vkey & 0xff); + var modifiers = vkey >> 8; + + if ((modifiers & 1) != 0) keys |= Keys.Shift; + if ((modifiers & 2) != 0) keys |= Keys.Control; + if ((modifiers & 4) != 0) keys |= Keys.Alt; + + return keys; + } + +} diff --git a/Source/Components/ImageGlass.Base/WinApi/PrintService.cs b/Source/Components/ImageGlass.Base/WinApi/PrintService.cs new file mode 100644 index 000000000..7f07ec4e4 --- /dev/null +++ b/Source/Components/ImageGlass.Base/WinApi/PrintService.cs @@ -0,0 +1,71 @@ +/* +ImageGlass Project - Image viewer for Windows +Copyright (C) 2010 - 2026 DUONG DIEU PHAP +Project homepage: https://imageglass.org + +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 . +*/ +using System.Runtime.InteropServices; + + +namespace ImageGlass.Library.WinAPI; + +public static class PrintService +{ + [ComImport] + [Guid("00000122-0000-0000-C000-000000000046")] + [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] + private interface IDropTarget + { + int DragEnter( + [In] System.Runtime.InteropServices.ComTypes.IDataObject pDataObj, + [In] int grfKeyState, + [In] Point pt, + [In, Out] ref int pdwEffect); + + int DragOver( + [In] int grfKeyState, + [In] Point pt, + [In, Out] ref int pdwEffect); + + int DragLeave(); + + int Drop( + [In] System.Runtime.InteropServices.ComTypes.IDataObject pDataObj, + [In] int grfKeyState, + [In] Point pt, + [In, Out] ref int pdwEffect); + } + + + /// + /// Open Print Pictures dialog + /// + /// File to print + public static void OpenPrintPictures(string filename) + { + var dataObj = new DataObject(DataFormats.FileDrop, new string[] { filename }); + var memoryStream = new MemoryStream(4); + var buffer = new byte[] { 5, 0, 0, 0 }; + + memoryStream.Write(buffer, 0, buffer.Length); + dataObj.SetData("Preferred DropEffect", memoryStream); + + var CLSID_PrintPhotosDropTarget = new Guid("60fd46de-f830-4894-a628-6fa81bc0190d"); + var dropTargetType = Type.GetTypeFromCLSID(CLSID_PrintPhotosDropTarget, true); + var dropTarget = (IDropTarget?)Activator.CreateInstance(dropTargetType); + + dropTarget?.Drop(dataObj, 0, new Point(), 0); + } +} diff --git a/Source/Components/ImageGlass.Base/WinApi/ShellThumbnailApi.cs b/Source/Components/ImageGlass.Base/WinApi/ShellThumbnailApi.cs new file mode 100644 index 000000000..00df8b5c3 --- /dev/null +++ b/Source/Components/ImageGlass.Base/WinApi/ShellThumbnailApi.cs @@ -0,0 +1,338 @@ +/* +ImageGlass Project - Image viewer for Windows +Copyright (C) 2010 - 2026 DUONG DIEU PHAP +Project homepage: https://imageglass.org + +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 . + + +Credit to Daniel Peñalba: +https://stackoverflow.com/questions/21751747/extract-thumbnail-for-any-file-in-windows +*/ + +using System.Drawing.Imaging; +using System.Runtime.InteropServices; + +namespace ImageGlass.Base; + + +public static class ShellThumbnailApi +{ + // Shell interface and structs + #region Shell interface and structs + + private const string IShellItem2Guid = "7E9FB0D3-919F-4307-AB2E-9B1860310C93"; + + + [DllImport("shell32.dll", CharSet = CharSet.Unicode, SetLastError = true)] + private static extern int SHCreateItemFromParsingName( + [MarshalAs(UnmanagedType.LPWStr)] string path, + // The following parameter is not used - binding context. + IntPtr pbc, + ref Guid riid, + [MarshalAs(UnmanagedType.Interface)] out IShellItem shellItem); + + + [DllImport("gdi32.dll")] + [return: MarshalAs(UnmanagedType.Bool)] + private static extern bool DeleteObject(IntPtr hObject); + + + [DllImport("msvcrt.dll", CallingConvention = CallingConvention.Cdecl)] + private static extern unsafe IntPtr memcpy(void* dst, void* src, UIntPtr count); + + + + [ComImport] + [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] + [Guid("43826d1e-e718-42ee-bc55-a1e261c37bfe")] + private interface IShellItem + { + void BindToHandler(IntPtr pbc, + [MarshalAs(UnmanagedType.LPStruct)] Guid bhid, + [MarshalAs(UnmanagedType.LPStruct)] Guid riid, + out IntPtr ppv); + + void GetParent(out IShellItem ppsi); + void GetDisplayName(SIGDN sigdnName, out IntPtr ppszName); + void GetAttributes(uint sfgaoMask, out uint psfgaoAttribs); + void Compare(IShellItem psi, uint hint, out int piOrder); + } + + + private enum SIGDN : uint + { + NORMALDISPLAY = 0, + PARENTRELATIVEPARSING = 0x80018001, + PARENTRELATIVEFORADDRESSBAR = 0x8001c001, + DESKTOPABSOLUTEPARSING = 0x80028000, + PARENTRELATIVEEDITING = 0x80031001, + DESKTOPABSOLUTEEDITING = 0x8004c000, + FILESYSPATH = 0x80058000, + URL = 0x80068000 + } + + + private enum HResult + { + Ok = 0x0000, + False = 0x0001, + InvalidArguments = unchecked((int)0x80070057), + OutOfMemory = unchecked((int)0x8007000E), + NoInterface = unchecked((int)0x80004002), + Fail = unchecked((int)0x80004005), + ElementNotFound = unchecked((int)0x80070490), + TypeElementNotFound = unchecked((int)0x8002802B), + NoObject = unchecked((int)0x800401E5), + Win32ErrorCanceled = 1223, + Canceled = unchecked((int)0x800704C7), + ResourceInUse = unchecked((int)0x800700AA), + AccessDenied = unchecked((int)0x80030005) + } + + + [ComImport] + [Guid("bcc18b79-ba16-442f-80c4-8a59c30c463b")] + [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] + private interface IShellItemImageFactory + { + [PreserveSig] + HResult GetImage( + [In, MarshalAs(UnmanagedType.Struct)] NativeSize size, + [In] ShellThumbnailOptions flags, + [Out] out IntPtr phbm); + } + + + [StructLayout(LayoutKind.Sequential)] + private struct NativeSize + { + private int width; + private int height; + + public int Width + { + set { width = value; } + } + + public int Height + { + set { height = value; } + } + } + + + [StructLayout(LayoutKind.Sequential)] + private struct RGBQUAD + { + public byte rgbBlue; + public byte rgbGreen; + public byte rgbRed; + public byte rgbReserved; + } + + + #endregion // Shell interface and structs + + + /// + /// Gets thumbnail from file. + /// + public static Bitmap? GetThumbnail(string fileName, int width, int height, ShellThumbnailOptions options) + { + if (!File.Exists(fileName)) return null; + + Bitmap? clonedBitmap = null; + var hBitmap = new IntPtr(); + + try + { + hBitmap = GetHBitmap(Path.GetFullPath(fileName), width, height, options); + + // Original code returned the bitmap directly: + // return GetBitmapFromHBitmap( hBitmap ); + // I'm making a clone first, so I can dispose of the original bitmap. + // The returned clone should be managed and not need disposing of. (I think...) + var thumbnail = GetBitmapFromHBitmap(hBitmap); + clonedBitmap = thumbnail.Clone() as Bitmap; + thumbnail.Dispose(); + } + catch (System.Runtime.InteropServices.COMException ex) + { + if (ex.ErrorCode == -2147175936 && options.HasFlag(ShellThumbnailOptions.ThumbnailOnly)) // -2147175936 == 0x8004B200 + { + clonedBitmap = null; + } + else + { + throw; + } + } + finally + { + // delete HBitmap to avoid memory leaks + DeleteObject(hBitmap); + } + + return clonedBitmap; + } + + + // Private methods + #region Private methods + + private static Bitmap? GetBitmapFromHBitmap(IntPtr nativeHBitmap) + { + var bmp = Image.FromHbitmap(nativeHBitmap); + + if (Image.GetPixelFormatSize(bmp.PixelFormat) < 32) + return bmp; + + return CreateAlphaBitmap(bmp, PixelFormat.Format32bppArgb); + } + + + private static unsafe Bitmap? CreateAlphaBitmap(Bitmap srcBitmap, PixelFormat targetPixelFormat) + { + var result = new Bitmap(srcBitmap.Width, srcBitmap.Height, targetPixelFormat); + + var bmpBounds = new Rectangle(0, 0, srcBitmap.Width, srcBitmap.Height); + var srcData = srcBitmap.LockBits(bmpBounds, ImageLockMode.ReadOnly, srcBitmap.PixelFormat); + var destData = result.LockBits(bmpBounds, ImageLockMode.ReadOnly, targetPixelFormat); + + var srcDataPtr = (byte*)srcData.Scan0; + var destDataPtr = (byte*)destData.Scan0; + + try + { + for (int y = 0; y <= srcData.Height - 1; y++) + { + for (int x = 0; x <= srcData.Width - 1; x++) + { + //this is really important because one stride may be positive and the other negative + var position = srcData.Stride * y + 4 * x; + var position2 = destData.Stride * y + 4 * x; + + memcpy(destDataPtr + position2, srcDataPtr + position, (UIntPtr)4); + } + } + } + finally + { + srcBitmap.UnlockBits(srcData); + result.UnlockBits(destData); + } + + using (srcBitmap) + return result; + } + + + private static IntPtr GetHBitmap(string fileName, int width, int height, ShellThumbnailOptions options) + { + IShellItem nativeShellItem; + var shellItem2Guid = new Guid(IShellItem2Guid); + int retCode = SHCreateItemFromParsingName(fileName, IntPtr.Zero, ref shellItem2Guid, out nativeShellItem); + + if (retCode != 0) + throw Marshal.GetExceptionForHR(retCode) ?? new Exception($"Error with code: {retCode}"); + + var nativeSize = new NativeSize + { + Width = width, + Height = height + }; + + IntPtr hBitmap; + HResult hr = ((IShellItemImageFactory)nativeShellItem).GetImage(nativeSize, options, out hBitmap); + + Marshal.ReleaseComObject(nativeShellItem); + + if (hr == HResult.Ok) return hBitmap; + + throw Marshal.GetExceptionForHR((int)hr) ?? new Exception($"Error with code: {(int)hr}"); + } + + #endregion // Private methods + +} + + + +/// +/// SIIGBF Flags: +/// +[Flags] +public enum ShellThumbnailOptions +{ + /// + /// SIIGBF_RESIZETOFITc>: Shrink the bitmap as necessary to fit, preserving its aspect ratio. Returns thumbnail if available, else icon. + /// + None = 0x00, + + + /// + /// SIIGBF_BIGGERSIZEOK: Passed by callers if they want to stretch the returned image themselves. For example, if the caller passes an icon size of 80x80, a 96x96 thumbnail could be returned. This action can be used as a performance optimization if the caller expects that they will need to stretch the image. Note that the Shell implementation of IShellItemImageFactory performs a GDI stretch blit. If the caller wants a higher quality image stretch than provided through that mechanism, they should pass this flag and perform the stretch themselves. + /// + BiggerSizeOk = 0x01, + + + /// + /// SIIGBF_MEMORYONLY: Return the item only if it is already in memory. Do not access the disk even if the item is cached. Note that this only returns an already-cached icon and can fall back to a per-class icon if an item has a per-instance icon that has not been cached. Retrieving a thumbnail, even if it is cached, always requires the disk to be accessed, so GetImage should not be called from the UI thread without passing SIIGBF_MEMORYONLY. + /// + InMemoryOnly = 0x02, + + + /// + /// SIIGBF_ICONONLY: Return only the icon, never the thumbnail. + /// + IconOnly = 0x04, + + + /// + /// SIIGBF_THUMBNAILONLY: Return only the thumbnail, never the icon. Note that not all items have thumbnails, so SIIGBF_THUMBNAILONLY will cause the method to fail in these cases. + /// + ThumbnailOnly = 0x08, + + + /// + /// SIIGBF_INCACHEONLY: Allows access to the disk, but only to retrieve a cached item. This returns a cached thumbnail if it is available. If no cached thumbnail is available, it returns a cached per-instance icon but does not extract a thumbnail or icon. + /// + InCacheOnly = 0x10, + + + /// + /// SIIGBF_CROPTOSQUARE: Introduced in Windows 8. If necessary, crop the bitmap to a square. + /// + Win8CropToSquare = 0x20, + + + /// + /// SIIGBF_WIDETHUMBNAILS: Introduced in Windows 8. Stretch and crop the bitmap to a 0.7 aspect ratio. + /// + Win8WideThumbnails = 0x40, + + + /// + /// SIIGBF_ICONBACKGROUND: Introduced in Windows 8. If returning an icon, paint a background using the associated app's registered background color. + /// + Win8IconBackground = 0x80, + + + /// + /// SIIGBF_SCALEUP: Introduced in Windows 8. If necessary, stretch the bitmap so that the height and width fit the given size. + /// + Win8ScaleUp = 0x100, +} + diff --git a/Source/Components/ImageGlass.Base/WinApi/SysExecutionState.cs b/Source/Components/ImageGlass.Base/WinApi/SysExecutionState.cs new file mode 100644 index 000000000..487258c54 --- /dev/null +++ b/Source/Components/ImageGlass.Base/WinApi/SysExecutionState.cs @@ -0,0 +1,49 @@ +/* +ImageGlass Project - Image viewer for Windows +Copyright (C) 2010 - 2026 DUONG DIEU PHAP +Project homepage: https://imageglass.org + +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 . +*/ +using Windows.Win32; +using Windows.Win32.System.Power; + +namespace ImageGlass.Base.WinApi; + + +/// +/// Enables an application to inform the system that it is in use, thereby preventing the system from entering sleep or turning off the display while the application is running. +/// Ref: https://docs.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-setthreadexecutionstate +/// +public static class SysExecutionState +{ + /// + /// Prevents the system from entering sleep or turning off the display while the application is running. + /// + public static void PreventSleep() + { + _ = PInvoke.SetThreadExecutionState(EXECUTION_STATE.ES_CONTINUOUS + | EXECUTION_STATE.ES_SYSTEM_REQUIRED + | EXECUTION_STATE.ES_DISPLAY_REQUIRED); + } + + + /// + /// Allow the system to enter sleep or turn off the display while the application is running. + /// + public static void AllowSleep() + { + _ = PInvoke.SetThreadExecutionState(EXECUTION_STATE.ES_CONTINUOUS); + } +} diff --git a/Source/Components/ImageGlass.UI/Enums.cs b/Source/Components/ImageGlass.Base/WinApi/SystemIconApi.cs similarity index 52% rename from Source/Components/ImageGlass.UI/Enums.cs rename to Source/Components/ImageGlass.Base/WinApi/SystemIconApi.cs index d06610026..533db7fc6 100644 --- a/Source/Components/ImageGlass.UI/Enums.cs +++ b/Source/Components/ImageGlass.Base/WinApi/SystemIconApi.cs @@ -1,7 +1,7 @@ /* ImageGlass Project - Image viewer for Windows -Copyright (C) 2020 DUONG DIEU PHAP -Project homepage: http://imageglass.org +Copyright (C) 2010 - 2026 DUONG DIEU PHAP +Project homepage: https://imageglass.org 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 @@ -14,32 +14,24 @@ 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 . +along with this program. If not, see . */ +namespace ImageGlass.Base.WinApi; -namespace ImageGlass.UI + +public static class SystemIconApi { - public enum ThemeUninstallingResult + /// + /// Gets the system icon. + /// + public static Bitmap? GetSystemIcon(StockIconId? iconId, bool useLargeIcon = true) { - SUCCESS = 0, - ERROR = 1, - ERROR_THEME_NOT_FOUND = 2 - } + if (iconId is null) return null; - public enum ThemeInstallingResult { - UNKNOWN = -1, - SUCCESS = 0, - ERROR = 1 - } + using var icon = SystemIcons.GetStockIcon(iconId.Value); - public enum ThemePackingResult - { - SUCCESS = 0, - ERROR = 1 + return icon?.ToBitmap(); } - public enum ToolbarAlignment { - LEFT = 0, - CENTER = 1, - } } + diff --git a/Source/Components/ImageGlass.Base/WinApi/TimerApi.cs b/Source/Components/ImageGlass.Base/WinApi/TimerApi.cs new file mode 100644 index 000000000..ce97d5ccd --- /dev/null +++ b/Source/Components/ImageGlass.Base/WinApi/TimerApi.cs @@ -0,0 +1,129 @@ + +/* +ImageGlass Project - Image viewer for Windows +Copyright (C) 2010 - 2026 DUONG DIEU PHAP +Project homepage: https://imageglass.org + +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 . +*/ + +/****************************************** +* THANKS [Meowski] FOR THIS CONTRIBUTION +*******************************************/ + +using Windows.Win32; + +namespace ImageGlass.Base.WinApi; + +/// +/// Used to make requests for obtaining and setting timer resolution. +/// This is a global request shared by all processes on the computer. All +/// requests are revoked when this process ends. +/// +public static class TimerApi +{ + // locks ourCurRequests + private static readonly object _lock = new(); + + private static readonly uint _minPeriod; + private static readonly uint _maxPeriod; + private static readonly List _curRequests; + + + static TimerApi() + { + PInvoke.timeGetDevCaps(out var tc); + + _minPeriod = tc.wPeriodMin; + _maxPeriod = tc.wPeriodMax; + _curRequests = []; + } + + + /// + /// Request a rate from the system clock. + /// + /// the time in milliseconds + /// true if we succesfully acquired a clock of + /// the given rate, otherwise returns false. + public static bool TimeBeginPeriod(int timeInMilliseconds) + { + if (timeInMilliseconds < _minPeriod || timeInMilliseconds > _maxPeriod) + { + return false; + } + + bool successfullyRequestedPeriod; + lock (_lock) + { + successfullyRequestedPeriod = PInvoke.timeBeginPeriod((uint)timeInMilliseconds) == 0; + if (successfullyRequestedPeriod) + { + _curRequests.Add(timeInMilliseconds); + } + } + + return successfullyRequestedPeriod; + } + + + /// + /// Revoke request for a rate from the system clock. + /// + /// the time in milliseconds + /// true if we revoked a previous request, otherwise returns false + public static bool TimeEndPeriod(int timeInMilliseconds) + { + bool successfullyEndedPeriod; + lock (_lock) + { + successfullyEndedPeriod = _curRequests.Remove(timeInMilliseconds) + && PInvoke.timeEndPeriod((uint)timeInMilliseconds) == 0; + } + + return successfullyEndedPeriod; + } + + + /// + /// Determines whether the current rate has already been requested. + /// + /// the time in milliseconds + public static bool HasRequestedRateAlready(int timeInMilliseconds) + { + bool hasRequestedAlready; + lock (_lock) + { + hasRequestedAlready = _curRequests.Contains(timeInMilliseconds); + } + + return hasRequestedAlready; + } + + + /// + /// Determines whether a rate at least as fast as the given has been requested + /// + /// the time in milliseconds + public static bool HasRequestedRateAtLeastAsFastAs(int timeInMilliseconds) + { + bool result; + lock (_lock) + { + result = _curRequests.Exists(elt => elt <= timeInMilliseconds); + } + + return result; + } +} \ No newline at end of file diff --git a/Source/Components/ImageGlass.Base/WinApi/WinColorsApi.cs b/Source/Components/ImageGlass.Base/WinApi/WinColorsApi.cs new file mode 100644 index 000000000..8b98f9529 --- /dev/null +++ b/Source/Components/ImageGlass.Base/WinApi/WinColorsApi.cs @@ -0,0 +1,106 @@ +/* +ImageGlass Project - Image viewer for Windows +Copyright (C) 2010 - 2026 DUONG DIEU PHAP +Project homepage: https://imageglass.org + +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 . +*/ +using Microsoft.Win32; +using Windows.UI.ViewManagement; + +namespace ImageGlass.Base.WinApi; + +public class WinColorsApi +{ + /// + /// Gets system accent color. + /// + public static Color GetAccentColor(bool includeAlpha) + { + var ui = new UISettings(); + var accent = ui.GetColorValue(UIColorType.Accent); + + var alpha = includeAlpha ? accent.A : (byte)255; + var color = Color.FromArgb(alpha, accent.R, accent.G, accent.B); + + return color; + } + + + /// + /// Checks if the system transparency is enabled. + /// + public static bool IsTransparencyEnabled + { + get + { + const string regPath = @"Software\Microsoft\Windows\CurrentVersion\Themes\Personalize"; + const string regKey = "EnableTransparency"; + var enabled = true; + + try + { + using var key = Registry.CurrentUser.OpenSubKey(regPath); + var regValue = key?.GetValue(regKey); + + if (regValue != null) + { + var themeValue = (int)regValue; + + if (themeValue == 0) + { + enabled = false; + } + } + } + catch { } + + return enabled; + } + } + + + /// + /// Checks if the app color mode is dark (default). + /// + public static bool IsDarkMode + { + get + { + const string regPath = @"Software\Microsoft\Windows\CurrentVersion\Themes\Personalize"; + const string regKey = "AppsUseLightTheme"; + var darkMode = true; + + try + { + using var key = Registry.CurrentUser.OpenSubKey(regPath); + var regValue = key?.GetValue(regKey); + + if (regValue != null) + { + var themeValue = (int)regValue; + + if (themeValue > 0) + { + darkMode = false; + } + } + } + catch { } + + return darkMode; + } + } + +} diff --git a/Source/Components/ImageGlass.Base/WinApi/WindowApi.cs b/Source/Components/ImageGlass.Base/WinApi/WindowApi.cs new file mode 100644 index 000000000..d300c7b9c --- /dev/null +++ b/Source/Components/ImageGlass.Base/WinApi/WindowApi.cs @@ -0,0 +1,538 @@ +/* +ImageGlass Project - Image viewer for Windows +Copyright (C) 2010 - 2026 DUONG DIEU PHAP +Project homepage: https://imageglass.org + +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 . +*/ +using System.Runtime.InteropServices; +using System.Windows.Forms; +using Windows.Win32; +using Windows.Win32.Foundation; +using Windows.Win32.Graphics.Dwm; +using Windows.Win32.Graphics.Gdi; +using Windows.Win32.System.Diagnostics.Debug; +using Windows.Win32.UI.Controls; +using Windows.Win32.UI.Input.KeyboardAndMouse; +using Windows.Win32.UI.WindowsAndMessaging; + +namespace ImageGlass.Base.WinApi; + +public class WindowApi +{ + [DllImport("gdi32.dll", ExactSpelling = true, SetLastError = true)] + private static extern IntPtr CreateDIBSection(IntPtr hdc, ref BITMAPINFO pbmi, uint iUsage, int ppvBits, IntPtr hSection, uint dwOffset); + + + [DllImport("dwmapi.dll")] + private static extern int DwmSetWindowAttribute(IntPtr hwnd, int attr, ref bool attrValue, int attrSize); + + + + /// + /// Issue #360: IG periodically searching for dismounted device. + /// + /// Controls whether the system will handle the specified types of serious errors + /// or whether the process will handle them. + /// + /// + /// Best practice is that all applications call the process-wide SetErrorMode + /// function with a parameter of SEM_FAILCRITICALERRORS at startup. This is to + /// prevent error mode dialogs from hanging the application. + /// + /// Ref: + /// + public static void SetAppErrorMode() + { + _ = PInvoke.SetErrorMode(THREAD_ERROR_MODE.SEM_FAILCRITICALERRORS); + } + + + /// + /// Sets window state. + /// + public static void ShowAppWindow(IntPtr wndHandle, SHOW_WINDOW_CMD cmd) + { + _ = PInvoke.ShowWindow(new HWND(wndHandle), (Windows.Win32.UI.WindowsAndMessaging.SHOW_WINDOW_CMD)cmd); + } + + + /// + /// Simulates left mouse click on a window + /// + /// + /// + public static void ClickOnWindow(IntPtr wndHandle, Point clientPoint) + { + var cliPoint = new Point() + { + X = clientPoint.X, + Y = clientPoint.Y, + }; + var oldPos = Cursor.Position; + + // set cursor on coords, and press mouse + Cursor.Position = new Point(clientPoint.X, clientPoint.Y); + + // left button down data + var inputMouseDown = new INPUT + { + type = 0, + Anonymous = new INPUT._Anonymous_e__Union() + { + mi = new MOUSEINPUT() + { + dwFlags = MOUSE_EVENT_FLAGS.MOUSEEVENTF_LEFTDOWN, + }, + }, + }; + + // left button up data + var inputMouseUp = new INPUT + { + type = 0, + Anonymous = new INPUT._Anonymous_e__Union() + { + mi = new MOUSEINPUT() + { + dwFlags = MOUSE_EVENT_FLAGS.MOUSEEVENTF_LEFTUP, + }, + }, + }; + + var inputs = new INPUT[] { inputMouseDown, inputMouseUp }; + PInvoke.SendInput(inputs.AsSpan(), Marshal.SizeOf(typeof(INPUT))); + + // return mouse + Cursor.Position = oldPos; + } + + + /// + /// Sets dark mode for window title bar. + /// + public static void SetImmersiveDarkMode(IntPtr wndHandle, bool enabled) + { + // ~< 20H1 + if (!BHelper.IsOSBuildOrGreater(18985)) return; + + unsafe + { + _ = PInvoke.DwmSetWindowAttribute(new HWND(wndHandle), + DWMWINDOWATTRIBUTE.DWMWA_USE_IMMERSIVE_DARK_MODE, + &enabled, sizeof(uint)); + } + } + + + /// + /// Sets round corner option for Windows 11. + /// + /// Window's handle. + /// true to make the corner round, false to use square. + /// Returns true if succeeded, else false. + public static bool SetRoundCorner(IntPtr wndHandle, WindowCorner style = WindowCorner.Round) + { + if (!BHelper.IsOS(WindowsOS.Win11OrLater)) return false; + + HRESULT result; + unsafe + { + result = PInvoke.DwmSetWindowAttribute(new HWND(wndHandle), + DWMWINDOWATTRIBUTE.DWMWA_WINDOW_CORNER_PREFERENCE, + &style, sizeof(uint)); + } + + return result.Succeeded; + } + + + + /// + /// Sets background and text color for window title bar. + /// + /// + /// + /// Specifying null will reset the caption background color back to using the system's default value. + /// + /// + /// Specifying null will reset the caption text color back to using the system's default value. + /// + public static void SetTitleBar(IntPtr wndHandle, Color? bgColor, Color? textColor) + { + // ~< 20H1 + if (!BHelper.IsOS(WindowsOS.Win11OrLater)) return; + + const uint DWMWA_COLOR_DEFAULT = 0xFFFFFFFF; + var bg = DWMWA_COLOR_DEFAULT; + var text = DWMWA_COLOR_DEFAULT; + + if (bgColor != null) bg = bgColor.Value.ToCOLORREF(); + if (textColor != null) text = textColor.Value.ToCOLORREF(); + + unsafe + { + _ = PInvoke.DwmSetWindowAttribute(new HWND(wndHandle), + DWMWINDOWATTRIBUTE.DWMWA_CAPTION_COLOR, + &bg, sizeof(uint)); + + _ = PInvoke.DwmSetWindowAttribute(new HWND(wndHandle), + DWMWINDOWATTRIBUTE.DWMWA_TEXT_COLOR, + &text, sizeof(uint)); + } + } + + + + /// + /// Sets windows backdrop. + /// + /// Returns true if succeeded, else false. + public static bool SetWindowBackdrop(IntPtr wndHandle, DWM_SYSTEMBACKDROP_TYPE type = DWM_SYSTEMBACKDROP_TYPE.DWMSBT_NONE) + { + if (!BHelper.IsOS(WindowsOS.Win11OrLater)) return false; + + HRESULT result; + unsafe + { + if (BHelper.IsOS(WindowsOS.Win11_22H2_OrLater)) + { + var attr = DWMWINDOWATTRIBUTE_UNDOCUMENTED.DWMWA_SYSTEMBACKDROP_TYPE; + + result = PInvoke.DwmSetWindowAttribute(new HWND(wndHandle), + (DWMWINDOWATTRIBUTE)attr, + &type, sizeof(uint)); + } + else + { + var attr = DWMWINDOWATTRIBUTE_UNDOCUMENTED.DWMWA_MICA_EFFECT; + var preference = 1; + + result = PInvoke.DwmSetWindowAttribute(new HWND(wndHandle), + (DWMWINDOWATTRIBUTE)attr, + &preference, sizeof(uint)); + } + } + + return result.Succeeded; + } + + + /// + /// Check if the composition is enabled. + /// + public static bool IsCompositionEnabled() + { + if (Environment.OSVersion.Version.Major < 6) + return false; + + var result = PInvoke.DwmIsCompositionEnabled(out var compositionEnabled); + + return result.Succeeded && compositionEnabled > 0; + } + + + /// + /// Extends the window frame to the client area. + /// + /// Returns true if succeeded, else false. + public static bool SetWindowFrame(IntPtr wndHandle, Padding? margin = null) + { + if (!IsCompositionEnabled()) return false; + + margin ??= new Padding(0); + var mg = new MARGINS + { + cyTopHeight = margin.Value.Top, + cxLeftWidth = margin.Value.Left, + + cxRightWidth = margin.Value.Right, + cyBottomHeight = margin.Value.Bottom, + }; + + + var result = PInvoke.DwmExtendFrameIntoClientArea(new HWND(wndHandle), mg); + + return result.Succeeded; + } + + + /// + /// Sets the control's black background transparent. + /// + /// Note**: The control's BackColor must be set to . + /// + public static void SetTransparentBlackBackground(Control control, Rectangle rect) + { + using var g = control.CreateGraphics(); + SetTransparentBlackBackground(g, rect); + } + + + /// + /// Sets the control's black background transparent. + /// + /// Note**: The control's BackColor must be set to . + /// + public static unsafe void SetTransparentBlackBackground(Graphics g, Rectangle destRect) + { + var destDc = g.GetHdc(); + var memoryDc = PInvoke.CreateCompatibleDC(new HDC(destDc)); + var bitmapOld = new HGDIOBJ(IntPtr.Zero); + var bitmapGdiObj = new HGDIOBJ(IntPtr.Zero); + + var dib = new BITMAPINFO(); + dib.bmiHeader.biHeight = -(destRect.Height); + dib.bmiHeader.biWidth = destRect.Width; + dib.bmiHeader.biPlanes = 1; + dib.bmiHeader.biSize = (uint)Marshal.SizeOf(typeof(BITMAPINFOHEADER)); + dib.bmiHeader.biBitCount = 32; + dib.bmiHeader.biCompression = 0; // BI_RGB + + if (!(PInvoke.SaveDC(memoryDc) == 0)) + { + var bitmapPtr = CreateDIBSection(memoryDc, ref dib, (int)DIB_USAGE.DIB_RGB_COLORS, 0, IntPtr.Zero, 0); + bitmapGdiObj = new HGDIOBJ(bitmapPtr); + + if (!bitmapGdiObj.IsNull) + { + bitmapOld = PInvoke.SelectObject(memoryDc, bitmapGdiObj); + + PInvoke.BitBlt(new HDC(destDc), destRect.Left, destRect.Top, destRect.Width, destRect.Height, memoryDc, 0, 0, ROP_CODE.SRCCOPY); + } + + // Remember to clean up + _ = PInvoke.SelectObject(memoryDc, bitmapOld); + + _ = PInvoke.DeleteObject(bitmapGdiObj); + _ = PInvoke.ReleaseDC(new HWND(memoryDc.Value), memoryDc); // (IntPtr, -1) + _ = PInvoke.DeleteDC(memoryDc); + } + + g.ReleaseHdc(); + } + + + /// + /// Checks if this is a touch device. + /// + public static bool IsTouchDevice() + { + var numberOfTouches = PInvoke.GetSystemMetrics(SYSTEM_METRICS_INDEX.SM_MAXIMUMTOUCHES); + + return numberOfTouches > 0; + } + + + /// + /// Makes control resizable. This should be called in MouseDown event. + /// + public static void SetResizerOnMouseDown(IntPtr handle, ResizerType type) + { + if (type == ResizerType.None) return; + + const int WM_NCLBUTTONDOWN = 0x00A1; + var typePtr = new IntPtr((int)type); + + // Release current mouse capture + _ = PInvoke.ReleaseCapture(); + + // Tell the OS that you want to drag the window. + _ = PInvoke.SendMessage(new HWND(handle), WM_NCLBUTTONDOWN, + new WPARAM((uint)typePtr), new LPARAM()); + } + + + /// + /// Sets window top most. + /// + public static void SetWindowTopMost(IntPtr handle, bool enable) + { + var topMost = enable ? new HWND(new IntPtr(-1)) : new HWND(new IntPtr(-2)); + _ = PInvoke.SetWindowPos(new HWND(handle), topMost, 0, 0, 0, 0, + SET_WINDOW_POS_FLAGS.SWP_NOMOVE | SET_WINDOW_POS_FLAGS.SWP_NOSIZE); + } + + + /// + /// Gets window bounds and state. + /// + public static (Rectangle Bounds, FormWindowState State) GetWindowPlacement(Form frm) + { + var bounds = new Rectangle(); + var state = FormWindowState.Normal; + var wp = new WINDOWPLACEMENT(); + + if (frm.WindowState == FormWindowState.Normal) + { + bounds = frm.Bounds; + } + else if (PInvoke.GetWindowPlacement(new(frm.Handle), ref wp)) + { + if (wp.showCmd == Windows.Win32.UI.WindowsAndMessaging.SHOW_WINDOW_CMD.SW_MAXIMIZE) + { + state = FormWindowState.Maximized; + } + + bounds = new( + wp.rcNormalPosition.X, + wp.rcNormalPosition.Y, + wp.rcNormalPosition.Width, + wp.rcNormalPosition.Height); + } + + return (bounds, state); + } +} + + +/// +/// https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-showwindow +/// +public enum SHOW_WINDOW_CMD : uint +{ + SW_HIDE = 0, + /// + /// Activates and displays a window. If the window is minimized or maximized, + /// the system restores it to its original size and position. An application + /// should specify this flag when displaying the window for the first time. + /// + SW_SHOWNORMAL = 1, + /// + /// Activates the window and displays it as a minimized window. + /// + SW_SHOWMINIMIZED = 2, + /// + /// Activates the window and displays it as a maximized window. + /// + SW_SHOWMAXIMIZED = 3, + /// + /// Displays a window in its most recent size and position. This value is similar + /// to SW_SHOWNORMAL, except that the window is not activated. + /// + SW_SHOWNOACTIVATE = 4, + /// + /// Activates the window and displays it in its current size and position. + /// + SW_SHOW = 5, + /// + /// Minimizes the specified window and activates the next top-level window in + /// the Z order. + /// + SW_MINIMIZE = 6, + /// + /// Displays the window as a minimized window. This value is similar to + /// SW_SHOWMINIMIZED, except the window is not activated. + /// + SW_SHOWMINNOACTIVE = 7, + /// + /// Displays the window in its current size and position. This value is similar + /// to SW_SHOW, except that the window is not activated. + /// + SW_SHOWNA = 8, + /// + /// Activates and displays the window. If the window is minimized or maximized, + /// the system restores it to its original size and position. + /// An application should specify this flag when restoring a minimized window. + /// + SW_RESTORE = 9, + /// + /// Sets the show state based on the SW_ value specified in the STARTUPINFO structure + /// passed to the CreateProcess function by the program that started the application. + /// + SW_SHOWDEFAULT = 10, + /// + /// Minimizes a window, even if the thread that owns the window is not responding. + /// This flag should only be used when minimizing windows from a different thread. + /// + SW_FORCEMINIMIZE = 11, +} + + +/// +/// The DWM_WINDOW_CORNER_PREFERENCE enum for DwmSetWindowAttribute's third parameter, +/// which tells the function what value of the enum to set. +/// +public enum WindowCorner +{ + // DWMWCP_DEFAULT + Default = 0, + + /// + /// DWMWCP_DONOTROUND + /// + DoNotRound = 1, + + /// + /// DWMWCP_ROUND + /// + Round = 2, + + /// + /// DWMWCP_ROUNDSMALL + /// + RoundSmall = 3, +} + +internal enum DWMWINDOWATTRIBUTE_UNDOCUMENTED +{ + DWMWA_SYSTEMBACKDROP_TYPE = 38, + DWMWA_MICA_EFFECT = 1029, +} + + +public enum DWM_SYSTEMBACKDROP_TYPE +{ + /// + /// Let OS decides. + /// + DWMSBT_AUTO = 0, + + /// + /// No effect. + /// + DWMSBT_NONE = 1, + + /// + /// Mica effect. + /// + DWMSBT_MAINWINDOW = 2, + + /// + /// Acrylic effect. + /// + DWMSBT_TRANSIENTWINDOW = 3, + + /// + /// Draw the backdrop material effect corresponding to a window with a tabbed title bar. + /// + DWMSBT_TABBEDWINDOW = 4, +} + + +public enum ResizerType : int +{ + None = -1, + + HTTOP = 12, + HTTOPLEFT = 13, + HTTOPRIGHT = 14, + + HTBOTTOM = 15, + HTBOTTOMLEFT = 16, + HTBOTTOMRIGHT = 17, + + HTLEFT = 10, + HTRIGHT = 11, +} diff --git a/Source/Components/ImageGlass.Gallery/Cache/ShellInfoCacheManager.cs b/Source/Components/ImageGlass.Gallery/Cache/ShellInfoCacheManager.cs new file mode 100644 index 000000000..2c0f99854 --- /dev/null +++ b/Source/Components/ImageGlass.Gallery/Cache/ShellInfoCacheManager.cs @@ -0,0 +1,527 @@ +/* +ImageGlass Project - Image viewer for Windows +Copyright (C) 2010 - 2026 DUONG DIEU PHAP +Project homepage: https://imageglass.org + +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 . + +--------------------- +ImageGlass.Gallery is based on ImageListView v13.8.2: +Url: https://github.com/oozcitak/imagelistview +License: Apache License Version 2.0, http://www.apache.org/licenses/ +--------------------- +*/ +using ImageGlass.Base.QueuedWorker; + +namespace ImageGlass.Gallery; + + +/// +/// Represents the cache manager responsible for asynchronously loading +/// shell info. +/// +internal class ShellInfoCacheManager : IDisposable +{ + #region Member Variables + private QueuedWorker bw; + private SynchronizationContext? context; + private readonly SendOrPostCallback checkProcessingCallback; + + private ImageGallery _imageGallery; + + private Dictionary shellCache; + private Dictionary processing; + + private bool disposed; + #endregion + + + #region CacheItem Class + /// + /// Represents an item in the cache. + /// + private class CacheItem : IDisposable + { + private bool disposed; + + /// + /// Gets the file extension. + /// + public string Extension { get; private set; } + + /// + /// Gets the small shell icon. + /// + public Image? SmallIcon { get; private set; } + + /// + /// Gets the large shell icon. + /// + public Image? LargeIcon { get; private set; } + + /// + /// Gets the shell file type. + /// + public string FileType { get; private set; } + + /// + /// Gets or sets the state of the cache item. + /// + public CacheState State { get; set; } + + /// + /// Initializes a new instance of the class. + /// + /// The file extension. + /// The small shell icon. + /// The large shell icon. + /// The shell file type. + /// The cache state of the item. + public CacheItem(string extension, Image smallIcon, Image largeIcon, string filetype, CacheState state) + { + Extension = extension; + SmallIcon = smallIcon; + LargeIcon = largeIcon; + FileType = filetype; + State = state; + disposed = false; + } + + /// + /// Performs application-defined tasks associated with + /// freeing, releasing, or resetting unmanaged resources. + /// + public void Dispose() + { + if (!disposed) + { + if (SmallIcon != null) + { + SmallIcon.Dispose(); + SmallIcon = null; + } + if (LargeIcon != null) + { + LargeIcon.Dispose(); + LargeIcon = null; + } + + disposed = true; + GC.SuppressFinalize(this); + } + } + +#if DEBUG + /// + /// Releases unmanaged resources and performs other cleanup operations before the + /// CacheItem is reclaimed by garbage collection. + /// + ~CacheItem() + { + if (SmallIcon != null || LargeIcon != null) + System.Diagnostics.Debug.Print("Finalizer of {0} called for non-empty cache item.", GetType()); + Dispose(); + } + +#endif + } + #endregion + + + #region CanContinueProcessingEventArgs + /// + /// Represents the event arguments for the callback. + /// + private class CanContinueProcessingEventArgs : EventArgs + { + /// + /// Gets the file extension of the request. + /// + public string Extension { get; private set; } + + /// + /// Gets whether this item should be processed. + /// + public bool ContinueProcessing { get; set; } + + /// + /// Initializes a new instance of the class. + /// + /// The file extension of the request. + public CanContinueProcessingEventArgs(string extension) + { + Extension = extension; + ContinueProcessing = true; + } + + } + #endregion + + + #region Properties + /// + /// Determines whether the cache manager retries loading items on errors. + /// + public bool RetryOnError { get; internal set; } + + #endregion + + + #region Constructor + /// + /// Initializes a new instance of the class. + /// + /// The owner control. + public ShellInfoCacheManager(ImageGallery owner) + { + context = null; + bw = new QueuedWorker + { + Threads = 1, + IsBackground = true, + ThreadName = "Shell Info Cache Worker Thread" + }; + bw.DoWork += Bw_DoWork; + bw.RunWorkerCompleted += Bw_RunWorkerCompleted; + + checkProcessingCallback = new SendOrPostCallback(CanContinueProcessing); + + _imageGallery = owner; + RetryOnError = false; + + shellCache = new Dictionary(); + processing = new Dictionary(); + + disposed = false; + } + + #endregion + + + #region Context Callbacks + /// + /// Determines if the item should be processed. + /// + /// The file extension to check. + /// true if the item should be processed; otherwise false. + private bool OnCanContinueProcessing(string extension) + { + var arg = new CanContinueProcessingEventArgs(extension); + context?.Send(checkProcessingCallback, arg); + + return arg.ContinueProcessing; + } + + /// + /// Determines if the item should be processed. + /// + /// The event argument. + /// true if the item should be processed; otherwise false. + private void CanContinueProcessing(object? argument) + { + var arg = argument as CanContinueProcessingEventArgs; + if (arg is null) return; + + bool canProcess = true; + + // Is it already cached? + if (shellCache.TryGetValue(arg.Extension, out CacheItem? existing)) + { + if (existing.SmallIcon != null && existing.LargeIcon != null) + canProcess = false; + } + + arg.ContinueProcessing = canProcess; + } + + #endregion + + + #region QueuedBackgroundWorker Events + /// + /// Handles the RunWorkerCompleted event of the queued background worker. + /// + /// The source of the event. + /// The + /// instance containing the event data. + private void Bw_RunWorkerCompleted(object? sender, QueuedWorkerCompletedEventArgs e) + { + var result = e.Result as CacheItem; + + // Add to cache + if (result != null) + { + // We are done processing + processing.Remove(result.Extension); + + if (shellCache.TryGetValue(result.Extension, out CacheItem? existing)) + { + existing.Dispose(); + shellCache.Remove(result.Extension); + } + shellCache.Add(result.Extension, result); + } + + // Refresh the control lazily + if (result != null && _imageGallery != null) + _imageGallery.Refresh(false, true); + + // Raise the ShellInfoCached event + if (result != null && _imageGallery != null) + _imageGallery.OnShellInfoCached(new ShellInfoCachedEventArgs(result.Extension, result.SmallIcon, result.LargeIcon, result.FileType)); + + // Raise the CacheError event + if (e.Error != null && _imageGallery != null) + _imageGallery.OnCacheErrorInternal(e.Error, CacheThread.ShellInfo); + } + + /// + /// Handles the DoWork event of the queued background worker. + /// + /// The source of the event. + /// The instance + /// containing the event data. + private void Bw_DoWork(object? sender, QueuedWorkerDoWorkEventArgs e) + { + var extension = e.Argument as string; + + // Should we continue processing this item? + // The callback checks if the item is already cached. + if (!OnCanContinueProcessing(extension)) + { + e.Cancel = true; + return; + } + + // Read shell info + var info = Extractor.Current.GetShellInfo(extension); + + // Return the info + CacheItem result; + if ((info.SmallIcon == null || info.LargeIcon == null) && !RetryOnError) + result = new CacheItem(extension, info.SmallIcon, info.LargeIcon, info.FileType, CacheState.Error); + else + result = new CacheItem(extension, info.SmallIcon, info.LargeIcon, info.FileType, CacheState.Cached); + + e.Result = result; + } + + #endregion + + + #region Instance Methods + /// + /// Pauses the cache threads. + /// + public void Pause() + { + bw.Pause(); + } + + /// + /// Resumes the cache threads. + /// + public void Resume() + { + bw.Resume(); + } + + /// + /// Gets the cache state of the specified item. + /// + /// File extension. + public CacheState GetCacheState(string extension) + { + if (string.IsNullOrEmpty(extension)) + throw new ArgumentException("extension cannot be null", nameof(extension)); + + if (shellCache.TryGetValue(extension, out CacheItem? item)) + return item.State; + + return CacheState.Unknown; + } + + /// + /// Rebuilds the cache. + /// Old items will be kept until they are overwritten + /// by new ones. + /// + public void Rebuild() + { + foreach (CacheItem item in shellCache.Values) + item.State = CacheState.Unknown; + } + + /// + /// Clears the cache. + /// + public void Clear() + { + foreach (CacheItem item in shellCache.Values) + item.Dispose(); + + shellCache.Clear(); + processing.Clear(); + } + + /// + /// Removes the given item from the cache. + /// + /// File extension. + public void Remove(string extension) + { + if (string.IsNullOrEmpty(extension)) + throw new ArgumentException("extension cannot be null", nameof(extension)); + + if (shellCache.TryGetValue(extension, out CacheItem? item)) + { + item.Dispose(); + shellCache.Remove(extension); + } + } + + /// + /// Adds the item to the cache queue. + /// + /// File extension. + public void Add(string extension) + { + if (string.IsNullOrEmpty(extension)) + throw new ArgumentException("extension cannot be null", nameof(extension)); + + // Already cached? + if (shellCache.TryGetValue(extension, out _)) + return; + + // Add to cache queue + RunWorker(extension); + } + + /// + /// Gets the small shell icon for the given file extension from the cache. + /// If the item is not cached, null will be returned. + /// + /// File extension. + public Image? GetSmallIcon(string extension) + { + if (string.IsNullOrEmpty(extension)) + throw new ArgumentException("extension cannot be null", nameof(extension)); + + if (shellCache.TryGetValue(extension, out CacheItem? item)) + { + return item.SmallIcon; + } + return null; + } + + /// + /// Gets the large shell icon for the given file extension from the cache. + /// If the item is not cached, null will be returned. + /// + /// File extension. + public Image? GetLargeIcon(string extension) + { + if (string.IsNullOrEmpty(extension)) + throw new ArgumentException("extension cannot be null", nameof(extension)); + + if (shellCache.TryGetValue(extension, out CacheItem? item)) + { + return item.LargeIcon; + } + return null; + } + + /// + /// Gets the shell file type for the given file extension from the cache. + /// If the item is not cached, null will be returned. + /// + /// File extension. + public string GetFileType(string extension) + { + if (string.IsNullOrEmpty(extension)) + throw new ArgumentException("extension cannot be null", nameof(extension)); + + if (shellCache.TryGetValue(extension, out CacheItem? item)) + { + return item.FileType; + } + return string.Empty; + } + + #endregion + + + #region RunWorker + /// + /// Pushes the given item to the worker queue. + /// + /// File extension. + private void RunWorker(string extension) + { + // Get the current synchronization context + if (context == null) + context = SynchronizationContext.Current; + + // Already being processed? + if (processing.ContainsKey(extension)) + return; + else + processing.Add(extension, false); + + // Raise the ShellInfoCaching event + if (_imageGallery != null) + _imageGallery.OnShellInfoCaching(new ShellInfoCachingEventArgs(extension)); + + // Add the item to the queue for processing + bw.RunWorkerAsync(extension); + } + + #endregion + + + #region Dispose + /// + /// Performs application-defined tasks associated with freeing, + /// releasing, or resetting unmanaged resources. + /// + public void Dispose() + { + if (!disposed) + { + bw.DoWork -= Bw_DoWork; + bw.RunWorkerCompleted -= Bw_RunWorkerCompleted; + + Clear(); + bw.Dispose(); + + disposed = true; + + GC.SuppressFinalize(this); + } + } + +#if DEBUG + /// + /// Releases unmanaged resources and performs other cleanup operations before the + /// is reclaimed by garbage collection. + /// + ~ShellInfoCacheManager() + { + System.Diagnostics.Debug.Print("Finalizer of {0} called.", GetType()); + Dispose(); + } + +#endif + #endregion +} diff --git a/Source/Components/ImageGlass.Gallery/Cache/ThumbnailCacheManager.cs b/Source/Components/ImageGlass.Gallery/Cache/ThumbnailCacheManager.cs new file mode 100644 index 000000000..6b93eda97 --- /dev/null +++ b/Source/Components/ImageGlass.Gallery/Cache/ThumbnailCacheManager.cs @@ -0,0 +1,1137 @@ +/* +ImageGlass Project - Image viewer for Windows +Copyright (C) 2010 - 2026 DUONG DIEU PHAP +Project homepage: https://imageglass.org + +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 . + +--------------------- +ImageGlass.Gallery is based on ImageListView v13.8.2: +Url: https://github.com/oozcitak/imagelistview +License: Apache License Version 2.0, http://www.apache.org/licenses/ +--------------------- +*/ +using ImageGlass.Base.Cache; +using ImageGlass.Base.QueuedWorker; + +namespace ImageGlass.Gallery; + +/// +/// Represents the cache manager responsible for asynchronously loading +/// item thumbnails. +/// +internal class ThumbnailCacheManager : IDisposable +{ + #region Member Variables + private readonly QueuedWorker _bw = new() + { + ProcessingMode = ProcessingMode.LIFO, + IsBackground = true, + ThreadName = "Thumbnail cache worker thread", + }; + private SynchronizationContext? _context = null; + private readonly SendOrPostCallback _checkProcessingCallback; + + internal DiskCache _diskCache = new() + { + CacheSize = 100 * 1024 * 1024, // 100 MB disk cache + }; + private readonly Dictionary _thumbCache = []; + private readonly Dictionary _processing = []; + private readonly Dictionary _editCache = []; + private readonly List _removedItems = []; + + private Guid _processingRendererItem = Guid.Empty; + private Guid _processingGalleryItem = Guid.Empty; + private CacheItem? _rendererItem = null; + private CacheItem? _galleryItem = null; + + private readonly ImageGallery _imageGallery; + private bool _isDisposed = false; + + #endregion + + + #region RequestType Enum + private enum RequestType + { + /// + /// This is a thumbnail request. + /// + Thumbnail, + + /// + /// [TODO] This is a large image request for use in Gallery or Pane view modes. + /// + Gallery, + + /// + /// This is a renderer request. + /// + Renderer + } + #endregion + + + #region CacheRequest Class + /// + /// Represents a cache request. + /// + private class CacheRequest + { + /// + /// Gets the guid of the item. + /// + public Guid Guid { get; private set; } + /// + /// Gets the adaptor of this item. + /// + public IAdaptor Adaptor { get; private set; } + /// + /// Gets the public key for the virtual item. + /// + public string VirtualKey { get; private set; } + /// + /// Gets the size of the requested thumbnail. + /// + public Size Size { get; private set; } + /// + /// Gets embedded thumbnail extraction behavior. + /// + public UseEmbeddedThumbnails UseEmbeddedThumbnails { get; private set; } + /// + /// Gets Exif rotation behavior. + /// + public bool AutoRotate { get; private set; } + /// + /// Gets the type of this request. + /// + public RequestType RequestType { get; private set; } + + /// + /// Initializes a new instance of the class + /// for use with a virtual item. + /// + /// The guid of the . + /// The adaptor of this item. + /// The file path for item. + /// The size of the requested thumbnail. + /// UseEmbeddedThumbnails property of the owner control. + /// AutoRotate property of the owner control. + /// Type of this request. + public CacheRequest(Guid guid, IAdaptor adaptor, string filePath, Size size, UseEmbeddedThumbnails useEmbeddedThumbnails, bool autoRotate, RequestType requestType) + { + Guid = guid; + VirtualKey = filePath; + Adaptor = adaptor; + Size = size; + UseEmbeddedThumbnails = useEmbeddedThumbnails; + AutoRotate = autoRotate; + RequestType = requestType; + } + + /// + /// Returns a that represents this instance. + /// + public override string ToString() + { + return "CacheRequest (" + VirtualKey.ToString() + ")"; + } + } + #endregion + + + #region CacheItem Class + /// + /// Represents an item in the thumbnail cache. + /// + private class CacheItem : IDisposable + { + private bool _isDisposed; + + /// + /// Gets the guid of the item. + /// + public Guid Guid { get; private set; } + + /// + /// Gets the size of the requested thumbnail. + /// + public Size Size { get; private set; } + + /// + /// Gets the cached image. + /// + public Image? Image { get; private set; } + + /// + /// Gets or sets the state of the cache item. + /// + public CacheState State { get; set; } + + /// + /// Gets embedded thumbnail extraction behavior. + /// + public UseEmbeddedThumbnails UseEmbeddedThumbnails { get; private set; } + + /// + /// Gets Exif rotation behavior. + /// + public bool AutoRotate { get; private set; } + + /// + /// Initializes a new instance of the class + /// for use with a virtual item. + /// + /// The guid of the . + /// The size of the requested thumbnail. + /// The thumbnail image. + /// The cache state of the item. + /// UseEmbeddedThumbnails property of the owner control. + /// AutoRotate property of the owner control. + public CacheItem(Guid guid, Size size, Image? image, CacheState state, UseEmbeddedThumbnails useEmbeddedThumbnails, bool autoRotate) + { + Guid = guid; + Size = size; + Image = image; + State = state; + UseEmbeddedThumbnails = useEmbeddedThumbnails; + AutoRotate = autoRotate; + _isDisposed = false; + } + + /// + /// Performs application-defined tasks associated with + /// freeing, releasing, or resetting unmanaged resources. + /// + public void Dispose() + { + if (!_isDisposed) + { + if (Image != null) + { + Image.Dispose(); + Image = null; + } + + _isDisposed = true; + GC.SuppressFinalize(this); + } + } + +#if DEBUG + /// + /// Releases unmanaged resources and performs other cleanup operations before the + /// class is reclaimed by garbage collection. + /// + ~CacheItem() + { + if (Image != null) + System.Diagnostics.Debug.Print("Finalizer of {0} called for non-empty cache item.", GetType()); + Dispose(); + } +#endif + + } + #endregion + + + #region CanContinueProcessingEventArgs + /// + /// Represents the event arguments for the callback. + /// + private class CanContinueProcessingEventArgs : EventArgs + { + /// + /// Gets the request. + /// + public CacheRequest Request { get; private set; } + + /// + /// Gets whether this item should be processed. + /// + public bool ContinueProcessing { get; set; } + + /// + /// Initializes a new instance of the class. + /// + /// The cache request. + public CanContinueProcessingEventArgs(CacheRequest request) + { + Request = request; + ContinueProcessing = true; + } + } + + #endregion + + + #region Properties + /// + /// Determines whether the cache manager retries loading items on errors. + /// + public bool RetryOnError { get; internal set; } = false; + + /// + /// Gets or sets the cache mode. + /// + public CacheMode CacheMode { get; internal set; } = CacheMode.OnDemand; + + /// + /// Gets or sets the cache limit as count of items. + /// + public int CacheLimitAsItemCount { get; internal set; } = 0; + + /// + /// Gets or sets the cache limit as allocated memory in MB. + /// + public long CacheLimitAsMemory { get; internal set; } = 20 * 1024 * 1024; + + /// + /// Gets the approximate amount of memory used by the cache. + /// + public long MemoryUsed { get; private set; } = 0; + + /// + /// Gets the approximate amount of memory used by removed items in the cache. + /// This memory can be reclaimed by calling . + /// + public long MemoryUsedByRemoved { get; private set; } = 0; + + /// + /// Returns the count of items in the cache. + /// + public long CacheSize => _thumbCache.Count; + + #endregion + + + #region Constructor + /// + /// Initializes a new instance of the class. + /// + /// The owner control. + public ThumbnailCacheManager(ImageGallery owner) + { + _bw.DoWork += Bw_DoWork; + _bw.RunWorkerCompleted += Bw_RunWorkerCompleted; + + _checkProcessingCallback = new SendOrPostCallback(CanContinueProcessing); + _imageGallery = owner; + } + + #endregion + + + #region Context Callbacks + + /// + /// Determines if the item should be processed. + /// + /// The to check. + /// true if the item should be processed; otherwise false. + private bool OnCanContinueProcessing(CacheRequest? item) + { + if (item is null) return false; + + var arg = new CanContinueProcessingEventArgs(item); + _context?.Send(_checkProcessingCallback, arg); + + return arg.ContinueProcessing; + } + + /// + /// Determines if the item should be processed. + /// + /// The event argument. + /// true if the item should be processed; otherwise false. + private void CanContinueProcessing(object? argument) + { + var arg = argument as CanContinueProcessingEventArgs; + if (arg is null) return; + + var request = arg.Request; + if (request is null) return; + + var canProcess = true; + + // Is it in the edit cache? + if (canProcess && _editCache.ContainsKey(request.Guid)) + canProcess = false; + + // Is it already cached? + if (canProcess && (request?.RequestType == RequestType.Thumbnail)) + { + _thumbCache.TryGetValue(request.Guid, out CacheItem? existing); + if (existing != null + && existing.Size == request.Size + && existing.UseEmbeddedThumbnails == request.UseEmbeddedThumbnails + && existing.AutoRotate == request.AutoRotate) + canProcess = false; + + // Is it outside the visible area? + if (canProcess + && CacheMode == CacheMode.OnDemand + && _imageGallery != null + && !_imageGallery.IsItemVisible(request.Guid)) + canProcess = false; + } + else if (canProcess && (request?.RequestType == RequestType.Gallery)) + { + var existing = _galleryItem; + if (existing != null + && existing.Guid == request.Guid + && existing.Size == request.Size + && existing.UseEmbeddedThumbnails == request.UseEmbeddedThumbnails + && existing.AutoRotate == request.AutoRotate) + canProcess = false; + } + else if (canProcess && (request?.RequestType == RequestType.Renderer)) + { + var existing = _rendererItem; + if (existing != null + && existing.Guid == request.Guid + && existing.Size == request.Size + && existing.UseEmbeddedThumbnails == request.UseEmbeddedThumbnails + && existing.AutoRotate == request.AutoRotate) + canProcess = false; + } + + arg.ContinueProcessing = canProcess; + } + + #endregion + + + #region QueuedBackgroundWorker Events + /// + /// Handles the RunWorkerCompleted event of the queued background worker. + /// + /// The source of the event. + /// The + /// instance containing the event data. + private void Bw_RunWorkerCompleted(object? sender, QueuedWorkerCompletedEventArgs e) + { + var request = e.UserState as CacheRequest; + if (request is null) return; + + var result = e.Result as CacheItem; + + // We are done processing + if (request.RequestType == RequestType.Renderer) + _processingRendererItem = Guid.Empty; + else if (request.RequestType == RequestType.Gallery) + _processingGalleryItem = Guid.Empty; + else + _processing.Remove(request.Guid); + + // Do not process the result if the cache operation was cancelled. + if (e.Cancelled) return; + + // Dispose old item and add to cache + if (request.RequestType == RequestType.Renderer) + { + _rendererItem?.Dispose(); + _rendererItem = result; + } + else if (request.RequestType == RequestType.Gallery) + { + _galleryItem?.Dispose(); + _galleryItem = result; + } + else if (result != null) + { + if (_thumbCache.TryGetValue(result.Guid, out CacheItem? existing)) + { + existing.Dispose(); + _thumbCache.Remove(result.Guid); + } + _thumbCache.Add(result.Guid, result); + + if (result.Image != null) + { + // Did the thumbnail size change while we were + // creating the thumbnail? + if (result.Size != _imageGallery.ThumbnailSize) + result.State = CacheState.Unknown; + + // Purge invisible items if we exceeded the cache limit + MemoryUsed += GetImageMemorySize(result.Image); + if (IsCacheLimitExceeded()) + PurgeInvisible(true); + } + } + + // Refresh the control + if (_imageGallery != null) + { + if (request.RequestType != RequestType.Thumbnail || _imageGallery.IsItemVisible(request.Guid)) + _imageGallery.Refresh(false, true); + } + + // Raise the ThumbnailCached event + if (result != null && _imageGallery != null) + _imageGallery.OnThumbnailCachedInternal(result.Guid, result.Image, result.Size, request.RequestType == RequestType.Thumbnail); + + // Raise the CacheError event + if (e.Error != null && _imageGallery != null) + _imageGallery.OnCacheErrorInternal(request.Guid, e.Error, CacheThread.Thumbnail); + } + + /// + /// Handles the DoWork event of the queued background worker. + /// + /// The source of the event. + /// The instance + /// containing the event data. + private void Bw_DoWork(object? sender, QueuedWorkerDoWorkEventArgs e) + { + var request = e.Argument as CacheRequest; + if (request is null) return; + + // Should we continue processing this item? + // The callback checks the following and returns false if + // the item is already cached -OR- + // the item is in the edit cache -OR- + // the item is outside the visible area (only if the CacheMode is OnDemand). + if (!OnCanContinueProcessing(request)) + { + e.Cancel = true; + return; + } + + Image? thumb = null; + var diskCacheKey = request.Adaptor.GetUniqueIdentifier(request.VirtualKey, request.Size, request.UseEmbeddedThumbnails, request.AutoRotate); + + // Check the disk cache + using var cs = _diskCache.Read(diskCacheKey); + if (cs.Length > 0) + { + thumb = new Bitmap(cs); + } + + + // Extract the thumbnail from the source image. + if (thumb == null) + { + try + { + thumb = request.Adaptor.GetThumbnail(request.VirtualKey, request.Size, request.UseEmbeddedThumbnails, request.AutoRotate); + } + // fix infinite re-cache when throwing error + catch { } + + // Save to disk cache + if (thumb != null) + { + using var ms = new MemoryStream(); + thumb.Save(ms, System.Drawing.Imaging.ImageFormat.Png); + _diskCache.Write(diskCacheKey, ms); + } + } + + // Return the thumbnail + CacheItem? result; + if (thumb == null && !RetryOnError) + { + result = new CacheItem(request.Guid, request.Size, null, CacheState.Error, request.UseEmbeddedThumbnails, request.AutoRotate); + } + else + { + result = new CacheItem(request.Guid, request.Size, thumb, CacheState.Cached, request.UseEmbeddedThumbnails, request.AutoRotate); + } + + e.Result = result; + } + + #endregion + + + #region Instance Methods + /// + /// Pauses the cache threads. + /// + public void Pause() + { + _bw.Pause(); + } + + /// + /// Resumes the cache threads. + /// + public void Resume() + { + _bw.Resume(); + } + + /// + /// Starts editing an item. While items are edited, + /// the cache thread will not work on them to prevent collisions. + /// + /// The guid representing the item + public void BeginItemEdit(Guid guid) + { + try + { + _ = _editCache.TryAdd(guid, false); + } + catch { } + } + + /// + /// Ends editing an item. After this call, item + /// image will be continued to be fetched by the thread. + /// + /// The guid representing the item. + public void EndItemEdit(Guid guid) + { + _ = _editCache.Remove(guid); + } + + /// + /// Rebuilds the thumbnail cache. + /// Old thumbnails will be kept until they are overwritten + /// by new ones. + /// + public void Rebuild() + { + foreach (var item in _thumbCache.Values) + item.State = CacheState.Unknown; + + if (_galleryItem != null) + _galleryItem.State = CacheState.Unknown; + + _diskCache.Clear(); + } + + /// + /// Clears the thumbnail cache. + /// + public void Clear() + { + foreach (var item in _thumbCache.Values) + { + item.Dispose(); + } + _thumbCache.Clear(); + + _galleryItem?.Dispose(); + _galleryItem = null; + + _rendererItem?.Dispose(); + _rendererItem = null; + + _bw.CancelAsync(); + + MemoryUsed = 0; + MemoryUsedByRemoved = 0; + _removedItems.Clear(); + _processing.Clear(); + _processingRendererItem = Guid.Empty; + + + // Empty persistent cache + if (!_imageGallery.DoNotDeletePersistentCache) + { + _diskCache.Clear(); + } + } + + /// + /// Removes the given item from the cache. + /// + /// The guid of the item to remove. + public void Remove(Guid guid) + { + Remove(guid, false); + } + + /// + /// Removes the given item from the cache. + /// + /// The guid of the item to remove. + /// true to remove the item now; false to remove the + /// item later when the cache is purged. + public void Remove(Guid guid, bool removeNow) + { + if (!_thumbCache.TryGetValue(guid, out CacheItem? cacheItem)) + return; + + if (removeNow) + { + MemoryUsed -= GetImageMemorySize(cacheItem.Size.Width, cacheItem.Size.Height); + cacheItem.Dispose(); + _thumbCache.Remove(guid); + + if (_galleryItem != null && _galleryItem.Guid == guid) + { + _galleryItem.Dispose(); + _galleryItem = null; + } + } + else + { + MemoryUsedByRemoved += GetImageMemorySize(cacheItem.Size.Width, cacheItem.Size.Height); + _removedItems.Add(guid); + + Purge(); + } + + // Remove from disk cache + if (_imageGallery != null && _imageGallery.Items.TryGetValue(guid, out ImageGalleryItem? item)) + { + if (item != null) + { + var diskCacheKey = item.Adaptor.GetUniqueIdentifier( + item.VirtualKey, + cacheItem.Size, + cacheItem.UseEmbeddedThumbnails, + cacheItem.AutoRotate); + _diskCache.Remove(diskCacheKey); + } + } + } + + /// + /// Purges removed items from the cache. + /// + /// true to purge the cache now, regardless of + /// memory usage; otherwise false to automatically purge the cache + /// depending on memory usage. + public void Purge(bool force) + { + // Remove items now if we can free more than 25% of the cache limit + if (force || IsPurgeNeeded()) + { + foreach (var guid in _removedItems) + { + if (_thumbCache.TryGetValue(guid, out CacheItem? item)) + { + item?.Dispose(); + _thumbCache.Remove(guid); + } + + if (_galleryItem != null && _galleryItem.Guid == guid) + { + _galleryItem.Dispose(); + _galleryItem = null; + } + } + + _removedItems.Clear(); + MemoryUsed -= MemoryUsedByRemoved; + MemoryUsedByRemoved = 0; + } + } + + /// + /// Purges removed items from the cache automatically + /// depending on memory usage. + /// + public void Purge() + { + Purge(false); + } + + /// + /// Purges invisible items from the cache. + /// + /// true to purge the cache now, regardless of + /// memory usage; otherwise false to automatically purge the cache + /// depending on memory usage. + public void PurgeInvisible(bool force) + { + if (_imageGallery == null) return; + + var visible = _imageGallery.GetVisibleItems(); + if (visible.Count == 0) return; + + foreach (var item in _thumbCache) + { + if (!visible.ContainsKey(item.Key)) + { + _removedItems.Add(item.Key); + MemoryUsedByRemoved += GetImageMemorySize(item.Value.Image); + } + } + + Purge(force); + } + + /// + /// Determines if removed items need to be purged. Removed items are purged + /// if they take up more than 25% of the cache limit. + /// + /// true if removed items need to be purged; otherwise false. + private bool IsPurgeNeeded() + { + return (CacheLimitAsMemory != 0 && MemoryUsedByRemoved > CacheLimitAsMemory / 4) + || (CacheLimitAsItemCount != 0 && _removedItems.Count > CacheLimitAsItemCount / 4); + } + + /// + /// Determines if the cache limit is exceeded. + /// + /// true if the cache limit is exceeded; otherwise false. + private bool IsCacheLimitExceeded() + { + return (CacheLimitAsMemory != 0 && MemoryUsedByRemoved > CacheLimitAsMemory) + || (CacheLimitAsItemCount != 0 && _removedItems.Count > CacheLimitAsItemCount); + } + + /// + /// Returns the memory usage of an image. + /// + /// A image. + /// Memory size of the image. + private static int GetImageMemorySize(Image? image) + { + if (image != null) + return GetImageMemorySize(image.Width, image.Height); + else + return 0; + } + + /// + /// Returns the memory usage of an image in of given dimensions. + /// The value is calculated aproximately as (Width * Height * BitsPerPixel / 8) + /// + /// Image width. + /// Image height. + /// Memory size of the image. + private static int GetImageMemorySize(int width, int height) + { + return width * height * 24 / 8; + } + + /// + /// Adds a virtual item to the cache queue. + /// + /// The guid representing this item. + /// he adaptor for this item. + /// The file path of this item. + /// Requested thumbnail size. + /// UseEmbeddedThumbnails property of the owner control. + /// AutoRotate property of the owner control. + public void Add(Guid guid, IAdaptor adaptor, string filePath, Size thumbSize, UseEmbeddedThumbnails useEmbeddedThumbnails, bool autoRotate) + { + // Already cached? + if (_thumbCache.TryGetValue(guid, out CacheItem? item)) + { + if (item.Size == thumbSize && item.UseEmbeddedThumbnails == useEmbeddedThumbnails) + return; + } + + // Add to cache queue + RunWorker(new CacheRequest(guid, adaptor, filePath, thumbSize, useEmbeddedThumbnails, autoRotate, RequestType.Thumbnail)); + } + + /// + /// Adds a virtual item to the cache. + /// + /// The guid representing this item. + /// The adaptor for this item. + /// The file path of this item. + /// Requested thumbnail size. + /// Thumbnail image to add to cache. + /// UseEmbeddedThumbnails property of the owner control. + /// AutoRotate property of the owner control. + public void Add(Guid guid, IAdaptor adaptor, string filePath, Size thumbSize, Image? thumb, UseEmbeddedThumbnails useEmbeddedThumbnails, bool autoRotate) + { + // Already cached? + if (_thumbCache.TryGetValue(guid, out CacheItem? item)) + { + if (item.Size == thumbSize && item.UseEmbeddedThumbnails == useEmbeddedThumbnails) + return; + } + + // Resize + thumb = Extractor.Current.GetThumbnail(thumb, thumbSize, useEmbeddedThumbnails, autoRotate); + + // Add to cache + _thumbCache.Add(guid, new CacheItem(guid, thumbSize, thumb, CacheState.Cached, useEmbeddedThumbnails, autoRotate)); + + // Add to disk cache + using var stream = new MemoryStream(); + var diskCacheKey = adaptor.GetUniqueIdentifier(filePath, thumbSize, useEmbeddedThumbnails, autoRotate); + thumb.Save(stream, System.Drawing.Imaging.ImageFormat.Png); + _diskCache.Write(diskCacheKey, stream); + + + // Raise the cache events + if (_imageGallery != null) + { + _imageGallery.OnThumbnailCachedInternal(guid, thumb, thumbSize, true); + _imageGallery.Refresh(); + } + } + + /// + /// Adds the virtual item image to the gallery cache queue. + /// + /// The guid representing this item. + /// The adaptor for this item. + /// The file path of this item. + /// Requested thumbnail size. + /// UseEmbeddedThumbnails property of the owner control. + /// AutoRotate property of the owner control. + public void AddToGalleryCache(Guid guid, IAdaptor adaptor, string filePath, Size thumbSize, UseEmbeddedThumbnails useEmbeddedThumbnails, bool autoRotate) + { + // Already cached? + if (_galleryItem != null + && _galleryItem.Guid == guid + && _galleryItem.Image != null + && _galleryItem.Size == thumbSize + && _galleryItem.UseEmbeddedThumbnails == useEmbeddedThumbnails + && _galleryItem.AutoRotate == autoRotate) + return; + + // Add to cache queue + RunWorker(new CacheRequest(guid, adaptor, filePath, thumbSize, useEmbeddedThumbnails, autoRotate, RequestType.Gallery), 2); + } + + /// + /// Adds the virtual item image to the renderer cache queue. + /// + /// The guid representing this item. + /// The adaptor of this item. + /// The file path of this item. + /// Requested thumbnail size. + /// UseEmbeddedThumbnails property of the owner control. + /// AutoRotate property of the owner control. + public void AddToRendererCache(Guid guid, IAdaptor adaptor, string filePath, Size thumbSize, UseEmbeddedThumbnails useEmbeddedThumbnails, bool autoRotate) + { + // Already cached? + if (_rendererItem != null + && _rendererItem.Guid == guid + && _rendererItem.Image != null + && _rendererItem.Size == thumbSize + && _rendererItem.UseEmbeddedThumbnails == useEmbeddedThumbnails + && _rendererItem.AutoRotate == autoRotate) + return; + + // Add to cache queue + RunWorker(new CacheRequest(guid, adaptor, filePath, thumbSize, useEmbeddedThumbnails, autoRotate, RequestType.Renderer), 1); + } + + /// + /// Gets the image from the renderer cache. If the image is not cached, + /// null will be returned. + /// + /// The guid representing this item. + /// Requested thumbnail size. + /// UseEmbeddedThumbnails property of the owner control. + /// AutoRotate property of the owner control. + public Image? GetRendererImage(Guid guid, Size thumbSize, UseEmbeddedThumbnails useEmbeddedThumbnails, bool autoRotate) + { + if (_rendererItem != null + && _rendererItem.Guid == guid + && _rendererItem.Image != null + && _rendererItem.Size == thumbSize + && _rendererItem.UseEmbeddedThumbnails == useEmbeddedThumbnails + && _rendererItem.AutoRotate == autoRotate) + return _rendererItem.Image; + else + return null; + } + + /// + /// Gets the image from the gallery cache. If the image is not cached, + /// null will be returned. + /// + /// The guid representing this item. + /// Requested thumbnail size. + /// UseEmbeddedThumbnails property of the owner control. + /// AutoRotate property of the owner control. + public Image? GetGalleryImage(Guid guid, Size thumbSize, UseEmbeddedThumbnails useEmbeddedThumbnails, bool autoRotate) + { + if (_galleryItem != null + && _galleryItem.Guid == guid + && _galleryItem.Image != null + && _galleryItem.Size == thumbSize + && _galleryItem.UseEmbeddedThumbnails == useEmbeddedThumbnails + && _galleryItem.AutoRotate == autoRotate) + return _galleryItem.Image; + else + return null; + } + + /// + /// Gets the image from the thumbnail cache. If the image is not cached, + /// null will be returned. + /// + /// The guid representing this item. + /// The adaptor of this item. + /// The key of this item. + /// Requested thumbnail size. + /// UseEmbeddedThumbnails property of the owner control. + /// AutoRotate property of the owner control. + /// true to return a clone of the cached image; otherwise false. + public Image? GetImage(Guid guid, IAdaptor adaptor, string filePath, Size thumbSize, UseEmbeddedThumbnails useEmbeddedThumbnails, bool autoRotate, bool clone) + { + if (_thumbCache.TryGetValue(guid, out CacheItem? item) + && item != null + && item.Image != null + && item.Size == thumbSize + && item.UseEmbeddedThumbnails == useEmbeddedThumbnails + && item.AutoRotate == autoRotate) + { + if (clone) + { + lock (item.Image) + { + return (Image?)item.Image.Clone(); + } + } + return item.Image; + } + else + { + var fi = new FileInfo(filePath.ToString()); + var diskCacheKey = adaptor.GetUniqueIdentifier(filePath, thumbSize, useEmbeddedThumbnails, autoRotate); + + try + { + // Check the disk cache + using var stream = _diskCache.Read(diskCacheKey); + + if (stream.Length > 0) + { + return new Bitmap(stream); + } + } + catch { } + + return null; + } + } + + /// + /// Gets the cache state of the specified item. + /// + /// The guid representing the item. + /// Requested thumbnail size. + /// UseEmbeddedThumbnails property of the owner control. + /// AutoRotate property of the owner control. + public CacheState GetCacheState(Guid guid, Size thumbSize, UseEmbeddedThumbnails useEmbeddedThumbnails, bool autoRotate) + { + if (_thumbCache.TryGetValue(guid, out CacheItem? item) + && item != null + && item.Size == thumbSize + && item.UseEmbeddedThumbnails == useEmbeddedThumbnails + && item.AutoRotate == autoRotate) + return item.State; + + return CacheState.Unknown; + } + + #endregion + + + #region RunWorker + /// + /// Pushes the given item to the worker queue. Items with high priority are renderer + /// or gallery items, ie. large images in gallery and pane views and images requested + /// by custom renderers. Items with 0 priority are regular thumbnails. + /// + /// The item to add to the worker queue. + /// Priority of the item in the queue. + private void RunWorker(CacheRequest item, int priority) + { + // Get the current synchronization context + _context ??= SynchronizationContext.Current; + + // Already being processed? + if (item.RequestType == RequestType.Thumbnail) + { + if (!_processing.TryAdd(item.Guid, false)) + return; + } + else if (item.RequestType == RequestType.Renderer) + { + if (_processingRendererItem == item.Guid) + return; + else + { + _bw.CancelAsync(priority); + _processingRendererItem = item.Guid; + } + } + else if (item.RequestType == RequestType.Gallery) + { + if (_processingGalleryItem == item.Guid) + return; + else + { + _bw.CancelAsync(priority); + _processingGalleryItem = item.Guid; + } + } + + // Raise the ThumbnailCaching event + _imageGallery?.OnThumbnailCachingInternal(item.Guid, item.Size); + + // Add the item to the queue for processing + _bw.RunWorkerAsync(item, priority, item.RequestType != RequestType.Thumbnail); + } + + /// + /// Pushes the given item to the worker queue. + /// + /// The item to add to the worker queue. + private void RunWorker(CacheRequest item) + { + RunWorker(item, 0); + } + + #endregion + + + #region Dispose + /// + /// Performs application-defined tasks associated with freeing, + /// releasing, or resetting unmanaged resources. + /// + public void Dispose() + { + if (!_isDisposed) + { + _bw.DoWork -= Bw_DoWork; + _bw.RunWorkerCompleted -= Bw_RunWorkerCompleted; + + Clear(); + _bw.Dispose(); + + _isDisposed = true; + + GC.SuppressFinalize(this); + } + } +#if DEBUG + /// + /// Releases unmanaged resources and performs other cleanup operations before the + /// is reclaimed by garbage collection. + /// + ~ThumbnailCacheManager() + { + System.Diagnostics.Debug.Print("Finalizer of {0} called.", GetType()); + Dispose(); + } + +#endif + + #endregion + +} + diff --git a/Source/Components/ImageGlass.Gallery/Enums.cs b/Source/Components/ImageGlass.Gallery/Enums.cs new file mode 100644 index 000000000..3ee3a68f3 --- /dev/null +++ b/Source/Components/ImageGlass.Gallery/Enums.cs @@ -0,0 +1,435 @@ +/* +ImageGlass Project - Image viewer for Windows +Copyright (C) 2010 - 2026 DUONG DIEU PHAP +Project homepage: https://imageglass.org + +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 . + +--------------------- +ImageGlass.Gallery is based on ImageListView v13.8.2: +Url: https://github.com/oozcitak/imagelistview +License: Apache License Version 2.0, http://www.apache.org/licenses/ +--------------------- +*/ +namespace ImageGlass.Gallery; + + +#region Public Enums + +/// +/// Represents the cache mode. +/// +public enum CacheMode +{ + /// + /// Item thumbnails will be generated only when requested. + /// + OnDemand, + + /// + /// Item thumbnails will be continuously generated. Setting + /// the CacheMode to Continuous disables the CacheLimit. + /// + Continuous, +} + +/// +/// Represents the type of image in the cache manager. +/// +public enum CachedImageType +{ + /// + /// Thumbnail image. + /// + Thumbnail, + + /// + /// Small shell icon. + /// + SmallIcon, + + /// + /// Large shell icon. + /// + LargeIcon, +} + +/// +/// Represents the cache state of a thumbnail image. +/// +public enum CacheState +{ + /// + /// The item is either not cached or it is in the cache queue. + /// + Unknown, + + /// + /// Item thumbnail is cached. + /// + Cached, + + /// + /// An error occurred while creating the item thumbnail. + /// + Error, +} + +/// +/// Represents the cache thread. +/// +public enum CacheThread +{ + /// + /// The cache thread responsible for generating item image thumbnails. + /// + Thumbnail, + + /// + /// The cache thread responsible for generating item details. + /// + Details, + + /// + /// The cache thread responsible for generating shell information. + /// + ShellInfo, +} + + +/// +/// Represents the type of information displayed in a column. +/// +public enum ColumnType +{ + + /// + /// A custom text column. + /// + Custom, + + /// + /// The text of the item, defaults to filename if + /// the text is not provided. + /// + Name, + + /// + /// The last access date. + /// + DateAccessed, + + /// + /// The creation date. + /// + DateCreated, + + /// + /// The last modification date. + /// + DateModified, + + /// + /// Mime type of the file. + /// + FileType, + + /// + /// The full path to the file. + /// + FileName, + + /// + /// The path to the folder containing the file. + /// + FolderPath, + + /// + /// The name of the folder containing the file. + /// + FolderName, + + /// + /// The size of the file. + /// + FileSize, + + /// + /// Image dimensions in pixels. + /// + Dimensions, + + /// + /// Image resolution if dpi. + /// + Resolution, + + /// + /// Image description (Exif tag). + /// + ImageDescription, + + /// + /// The equipment model (Exif tag). + /// + EquipmentModel, + + /// + /// The date image was taken (Exif tag). + /// + DateTaken, + + /// + /// The artist taking the image (Exif tag). + /// + Artist, + + /// + /// Image copyright information (Exif tag). + /// + Copyright, + + /// + /// Exposure time in seconds (Exif tag). + /// + ExposureTime, + + /// + /// The F number (Exif tag). + /// + FNumber, + + /// + /// ISO speed (Exif tag). + /// + ISOSpeed, + + /// + /// User comment (Exif tag). + /// + UserComment, + + /// + /// Rating (Windows Exif tag). + /// + Rating, + + /// + /// Software (Exif tag). + /// + Software, + + /// + /// Focal length (Exif tag). + /// + FocalLength, +} + +/// +/// Represents the order by which items are drawn. +/// +public enum ItemDrawOrder +{ + /// + /// Draw order is determined by item insertion index. + /// + ItemIndex, + + /// + /// Draw order is determined by the ZOrder properties of items. + /// + ZOrder, + + /// + /// Hovered items are drawn first, followed by normal items and selected items. + /// + HoveredNormalSelected, + + /// + /// Hovered items are drawn first, followed by selected items and normal items. + /// + HoveredSelectedNormal, + + /// + /// Normal items are drawn first, followed by hovered items and selected items. + /// + NormalHoveredSelected, + + /// + /// Normal items are drawn first, followed by selected items and hovered items. + /// + NormalSelectedHovered, + + /// + /// Selected items are drawn first, followed by hovered items and normal items. + /// + SelectedHoveredNormal, + + /// + /// Selected items are drawn first, followed by normal items and hovered items. + /// + SelectedNormalHovered, +} + +/// +/// Represents the visual state of an . +/// +[Flags] +public enum ItemState +{ + /// + /// The item is neither selected nor hovered. + /// + None = 0, + + /// + /// The item is selected. + /// + Selected = 1, + + /// + /// The item has the input focus. + /// + Focused = 2, + + /// + /// Mouse cursor is over the item. + /// + Hovered = 4, + + /// + /// The item is pressed. + /// + Pressed = 8, + + /// + /// The item is disabled. + /// + Disabled = 16, +} + +/// +/// Determines the visibility of an item. +/// +public enum ItemVisibility +{ + /// + /// The item is not visible. + /// + NotVisible, + + /// + /// The item is partially visible. + /// + PartiallyVisible, + + /// + /// The item is fully visible. + /// + Visible, +} + +/// +/// Represents the embedded thumbnail extraction behavior. +/// +public enum UseEmbeddedThumbnails +{ + /// + /// Always creates the thumbnail from the embedded thumbnail. + /// + Always = 0, + + /// + /// Creates the thumbnail from the embedded thumbnail when possible, + /// reverts to the source image otherwise. + /// + Auto = 1, + + /// + /// Always creates the thumbnail from the source image. + /// + Never = 2, +} + +/// +/// Represents the view mode of the . +/// +public enum View +{ + /// + /// Displays thumbnails laid out in a grid. The view can be + /// scrolled vertically. + /// + Thumbnails, + + /// + /// Displays a single row of thumbnails. + /// The view can be scrolled horizontally. + /// + HorizontalStrip, + + /// + /// Displays a single column of thumbnails. + /// The view can be scrolled vertically. + /// + VerticalStrip, +} + +/// +/// Represents the direction of the . +/// +public enum TooltipDirection +{ + Top, + Bottom, +} + + +/// +/// Represents the mouse state of . +/// +public enum MouseState +{ + Normal, + Hovered, + Pressed, +} + +#endregion + + +#region Internal Enums +/// +/// Represents the item highlight state during mouse selection. +/// +internal enum ItemHighlightState +{ + /// + /// Item is not highlighted. + /// + NotHighlighted, + + /// + /// Item is highlighted and will be removed from the selection set. + /// + HighlightedAndUnSelected, + + /// + /// Item is highlighted and will be added to the selection set. + /// + HighlightedAndSelected, +} + +#endregion + diff --git a/Source/Components/ImageGlass.Gallery/Events.cs b/Source/Components/ImageGlass.Gallery/Events.cs new file mode 100644 index 000000000..4754d6dfb --- /dev/null +++ b/Source/Components/ImageGlass.Gallery/Events.cs @@ -0,0 +1,628 @@ +/* +ImageGlass Project - Image viewer for Windows +Copyright (C) 2010 - 2026 DUONG DIEU PHAP +Project homepage: https://imageglass.org + +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 . + +--------------------- +ImageGlass.Gallery is based on ImageListView v13.8.2: +Url: https://github.com/oozcitak/imagelistview +License: Apache License Version 2.0, http://www.apache.org/licenses/ +--------------------- +*/ + +using System.ComponentModel; +using System.Runtime.InteropServices; + +namespace ImageGlass.Gallery; + + +#region Event Delegates +/// +/// Represents the method that will handle the CacheError event. +/// +/// The object that is the source of the event. +/// A CacheErrorEventArgs that contains event data. +[EditorBrowsable(EditorBrowsableState.Never)] +public delegate void CacheErrorEventHandler(object sender, CacheErrorEventArgs e); + +/// +/// Represents the method that will handle the DropFiles event. +/// +/// The object that is the source of the event. +/// A DropFileEventArgs that contains event data. +[EditorBrowsable(EditorBrowsableState.Never)] +public delegate void DropFilesEventHandler(object sender, DropFileEventArgs e); + +/// +/// Represents the method that will handle the DropItems event. +/// +/// The object that is the source of the event. +/// A DropItemEventArgs that contains event data. +[EditorBrowsable(EditorBrowsableState.Never)] +public delegate void DropItemsEventHandler(object sender, DropItemEventArgs e); + +/// +/// Represents the method that will handle the DropComplete event. +/// +/// The object that is the source of the event. +/// A DropCompleteEventArgs that contains event data. +[EditorBrowsable(EditorBrowsableState.Never)] +public delegate void DropCompleteEventHandler(object sender, DropCompleteEventArgs e); + +/// +/// Represents the method that will handle the ItemClick event. +/// +/// The object that is the source of the event. +/// A ItemClickEventArgs that contains event data. +[EditorBrowsable(EditorBrowsableState.Never)] +public delegate void ItemClickEventHandler(object sender, ItemClickEventArgs e); + +/// +/// Represents the method that will handle the ItemCheckBoxClick event. +/// +/// The object that is the source of the event. +/// A ItemEventArgs that contains event data. +[EditorBrowsable(EditorBrowsableState.Never)] +public delegate void ItemCheckBoxClickEventHandler(object sender, ItemEventArgs e); + +/// +/// Represents the method that will handle the ItemHover event. +/// +/// The object that is the source of the event. +/// A ItemHoverEventArgs that contains event data. +[EditorBrowsable(EditorBrowsableState.Never)] +public delegate void ItemHoverEventHandler(object sender, ItemHoverEventArgs e); + +/// +/// Represents the method that will handle the ItemDoubleClick event. +/// +/// The object that is the source of the event. +/// An ItemClickEventArgs that contains event data. +[EditorBrowsable(EditorBrowsableState.Never)] +public delegate void ItemDoubleClickEventHandler(object sender, ItemClickEventArgs e); + +/// +/// Represents the method that will handle the ThumbnailCaching event. +/// +/// The object that is the source of the event. +/// A ThumbnailCachingEventArgs that contains event data. +[EditorBrowsable(EditorBrowsableState.Never)] +public delegate void ThumbnailCachingEventHandler(object sender, ThumbnailCachingEventArgs e); + +/// +/// Represents the method that will handle the ThumbnailCached event. +/// +/// The object that is the source of the event. +/// A ThumbnailCachedEventArgs that contains event data. +[EditorBrowsable(EditorBrowsableState.Never)] +public delegate void ThumbnailCachedEventHandler(object sender, ThumbnailCachedEventArgs e); + +/// +/// Represents the method that will handle the DetailsCaching event. +/// +/// The object that is the source of the event. +/// An ItemEventArgs that contains event data. +[EditorBrowsable(EditorBrowsableState.Never)] +public delegate void DetailsCachingEventHandler(object sender, ItemEventArgs e); + +/// +/// Represents the method that will handle the DetailsCached event. +/// +/// The object that is the source of the event. +/// An ItemEventArgs that contains event data. +[EditorBrowsable(EditorBrowsableState.Never)] +public delegate void DetailsCachedEventHandler(object sender, ItemEventArgs e); + +/// +/// Represents the method that will handle the ShellInfoCachingEventHandler event. +/// +/// The object that is the source of the event. +/// A ShellInfoCachingEventArgs that contains event data. +[EditorBrowsable(EditorBrowsableState.Never)] +public delegate void ShellInfoCachingEventHandler(object sender, ShellInfoCachingEventArgs e); + +/// +/// Represents the method that will handle the ShellInfoCachedEventHandler event. +/// +/// The object that is the source of the event. +/// A ShellInfoCachedEventArgs that contains event data. +[EditorBrowsable(EditorBrowsableState.Never)] +public delegate void ShellInfoCachedEventHandler(object sender, ShellInfoCachedEventArgs e); + +/// +/// Refreshes the owner control. +/// +[EditorBrowsable(EditorBrowsableState.Never)] +internal delegate void RefreshDelegateInternal(); + +/// +/// Represents the method that will handle the ItemCollectionChanged event. +/// +/// The object that is the source of the event. +/// A ItemCollectionChangedEventArgs that contains event data. +[EditorBrowsable(EditorBrowsableState.Never)] +public delegate void ItemCollectionChangedEventHandler(object sender, ItemCollectionChangedEventArgs e); + +#endregion + + +#region Event Arguments +/// +/// Represents the event arguments for errors during cache operations. +/// +[Serializable, ComVisible(true)] +public class CacheErrorEventArgs : EventArgs +{ + /// + /// Gets the that is associated with this error. + /// This parameter can be null. + /// + public ImageGalleryItem? Item { get; private set; } + /// + /// Gets a value indicating which error occurred during an asynchronous operation. + /// + public Exception Error { get; private set; } + /// + /// Gets the thread raising the error. + /// + public CacheThread CacheThread { get; private set; } + + /// + /// Initializes a new instance of the CacheErrorEventArgs class. + /// + /// The that is associated with this error. + /// The error that occurred during an asynchronous operation. + /// The thread raising the error. + public CacheErrorEventArgs(ImageGalleryItem? item, Exception error, CacheThread cacheThread) + { + Item = item; + Error = error; + CacheThread = cacheThread; + } +} + +/// +/// Represents the event arguments for external drag drop events. +/// +[Serializable, ComVisible(true)] +public class DropFileEventArgs : EventArgs +{ + /// + /// Gets or sets whether default event code will be processed. + /// When set to true, the control will automatically insert the new items. + /// Otherwise, the control will not process the dropped files. + /// + public bool Cancel { get; set; } + + /// + /// Gets the position of the insertion caret. + /// This determines where the new items will be inserted. + /// + public int Index { get; private set; } + + /// + /// Gets the array of filenames droppped on the control. + /// + public string[] FileNames { get; private set; } + + + /// + /// Initializes a new instance of the DropFileEventArgs class. + /// + /// The position of the insertion caret. + /// The array of filenames droppped on the control. + public DropFileEventArgs(int index, string[] fileNames) + { + Cancel = false; + Index = index; + FileNames = fileNames; + } + +} + +/// +/// Represents the event arguments for internal drag drop events. +/// +[Serializable, ComVisible(true)] +public class DropItemEventArgs : EventArgs +{ + /// + /// Gets or sets whether default event code will be processed. + /// When set to true, the control will automatically insert the new items. + /// Otherwise, the control will not process the dropped items. + /// + public bool Cancel { get; set; } + + /// + /// Gets the position of the insertion caret. + /// This determines where the new items will be inserted. + /// + public int Index { get; private set; } + + /// + /// Gets the array of items droppped on the control. + /// + public ImageGalleryItem[] Items { get; private set; } + + + /// + /// Initializes a new instance of the DropItemEventArgs class. + /// + /// The position of the insertion caret. + /// The array of items droppped on the control. + public DropItemEventArgs(int index, ImageGalleryItem[] items) + { + Cancel = false; + Index = index; + Items = items; + } +} + +/// +/// Represents the event arguments for drag drop event completion. +/// +[Serializable, ComVisible(true)] +public class DropCompleteEventArgs : EventArgs +{ + /// + /// Gets the array of items droppped on the control. + /// + public ImageGalleryItem[] Items { get; private set; } + + /// + /// Gets if the drag operation is internal or external to the control. + /// In an internal drag operation, own items of the control are reordered. + /// + public bool InternalDrag { get; private set; } + + /// + /// Initializes a new instance of the DropCompleteEventArgs class. + /// + /// The array of items droppped on the control. + /// true if a drop event occurred after an internal reordering of items, + /// otherwise false if image files were externally dropped onto the control. + public DropCompleteEventArgs(ImageGalleryItem[] items, bool internalDrag) + { + Items = items; + InternalDrag = internalDrag; + } +} + +/// +/// Represents the event arguments for item related events. +/// +[Serializable, ComVisible(true)] +public class ItemEventArgs : EventArgs +{ + /// + /// Gets the that is the target of the event. + /// + public ImageGalleryItem? Item { get; private set; } + + /// + /// Initializes a new instance of the ItemEventArgs class. + /// + /// The item that is the target of this event. + public ItemEventArgs(ImageGalleryItem? item) + { + Item = item; + } +} + +/// +/// Represents the event arguments for item click related events. +/// +[Serializable, ComVisible(true)] +public class ItemClickEventArgs : EventArgs +{ + /// + /// Gets the that is the target of the event. + /// + public ImageGalleryItem Item { get; private set; } + + /// + /// Gets the coordinates of the cursor. + /// + public Point Location { get; private set; } + + /// + /// Gets the x-coordinates of the cursor. + /// + public int X => Location.X; + + /// + /// Gets the y-coordinates of the cursor. + /// + public int Y => Location.Y; + + /// + /// Gets the state of the mouse buttons. + /// + public MouseButtons Buttons { get; private set; } + + /// + /// Initializes a new instance of the ItemClickEventArgs class. + /// + /// The item that is the target of this event. + /// The location of the mouse. + /// One of the System.Windows.Forms.MouseButtons values + /// indicating which mouse button was pressed. + public ItemClickEventArgs(ImageGalleryItem item, Point location, MouseButtons buttons) + { + Item = item; + Location = location; + Buttons = buttons; + } +} + +/// +/// Represents the event arguments for item hover related events. +/// +[Serializable, ComVisible(true)] +public class ItemHoverEventArgs : EventArgs +{ + /// + /// Gets the that was previously hovered. + /// Returns null if there was no previously hovered item. + /// + public ImageGalleryItem? PreviousItem { get; private set; } + + /// + /// Gets the currently hovered . + /// Returns null if there is no hovered item. + /// + public ImageGalleryItem? Item { get; private set; } + + + /// + /// Initializes a new instance of the ItemEventArgs class. + /// + /// The currently hovered item. + /// The previously hovered item. + public ItemHoverEventArgs(ImageGalleryItem? item, ImageGalleryItem? previousItem) + { + Item = item; + PreviousItem = previousItem; + } +} + +/// +/// Represents the event arguments related to control layout. +/// +[Serializable, ComVisible(true)] +public class LayoutEventArgs : EventArgs +{ + /// + /// Gets or sets the rectangle bounding the item area. + /// + public Rectangle ItemAreaBounds { get; set; } + + /// + /// Initializes a new instance of the LayoutEventArgs class. + /// + /// The rectangle bounding the item area. + public LayoutEventArgs(Rectangle itemAreaBounds) + { + ItemAreaBounds = itemAreaBounds; + } +} + +/// +/// Represents the event arguments for the thumbnail caching event. +/// +[Serializable, ComVisible(true)] +public class ThumbnailCachingEventArgs : EventArgs +{ + /// + /// Gets the that is the target of the event. + /// + public ImageGalleryItem? Item { get; private set; } + + /// + /// Gets the size of the thumbnail request. + /// + public Size Size { get; private set; } + + /// + /// Initializes a new instance of the ThumbnailCachingEventArgs class. + /// + /// The item that is the target of this event. + /// The size of the thumbnail request. + public ThumbnailCachingEventArgs(ImageGalleryItem? item, Size size) + { + Item = item; + Size = size; + } +} + +/// +/// Represents the event arguments for the thumbnail cached event. +/// +[Serializable, ComVisible(true)] +public class ThumbnailCachedEventArgs : EventArgs +{ + /// + /// Gets the that is the target of the event. + /// + public ImageGalleryItem? Item { get; private set; } + + /// + /// Gets the size of the thumbnail request. + /// + public Size Size { get; private set; } + + /// + /// Gets the cached thumbnail image. + /// + public Image? Thumbnail { get; private set; } + + /// + /// Gets whether the cached image is a thumbnail image or + /// a large image for gallery or pane views. + /// + public bool IsThumbnail { get; private set; } + + /// + /// Initializes a new instance of the ThumbnailCachedEventArgs class. + /// + /// The item that is the target of this event. + /// The cached thumbnail image. + /// The size of the thumbnail request. + /// true if the cached image is a thumbnail image; otherwise false + /// if the image is a large image for gallery or pane views. + public ThumbnailCachedEventArgs(ImageGalleryItem? item, Image? thumbnail, Size size, bool thumbnailImage) + { + Item = item; + Thumbnail = thumbnail; + Size = size; + IsThumbnail = thumbnailImage; + } +} + +/// +/// Represents the event arguments for the shell info caching event. +/// +[Serializable, ComVisible(true)] +public class ShellInfoCachingEventArgs : EventArgs +{ + /// + /// Gets the file extension for which the shell info is requested. + /// + public string Extension { get; private set; } + + /// + /// Initializes a new instance of the ShellInfoCachingEventArgs class. + /// + /// The file extension for which the shell info is requested. + public ShellInfoCachingEventArgs(string extension) + { + Extension = extension; + } +} + +/// +/// Represents the event arguments for the shell info cached event. +/// +[Serializable, ComVisible(true)] +public class ShellInfoCachedEventArgs : EventArgs +{ + /// + /// Gets the file extension for which the shell info is requested. + /// + public string Extension { get; private set; } + + /// + /// Gets the small shell icon. + /// + public Image SmallIcon { get; private set; } + + /// + /// Gets the large shell icon. + /// + public Image LargeIcon { get; private set; } + + /// + /// Gets the shell file type. + /// + public string FileType { get; private set; } + + + /// + /// Initializes a new instance of the class. + /// + /// The file extension for which the shell info is requested. + /// The small shell icon. + /// The large shell icon. + /// The shell file type. + public ShellInfoCachedEventArgs(string extension, Image smallIcon, Image largeIcon, string filetype) + { + Extension = extension; + SmallIcon = smallIcon; + LargeIcon = largeIcon; + FileType = filetype; + } +} + +/// +/// Represents the event arguments for item collection related events. +/// +[Serializable, ComVisible(true)] +public class ItemCollectionChangedEventArgs : EventArgs +{ + /// + /// Gets the type of action causing the change. + /// + public CollectionChangeAction Action { get; private set; } + + /// + /// Gets the that is the target of the event. + /// + public ImageGalleryItem? Item { get; private set; } + + /// + /// Initializes a new instance of the ItemCollectionChangedEventArgs class. + /// + /// The type of action causing the change. + /// The item that is the target of this event. This parameter will be null + /// if the collection is cleared. + public ItemCollectionChangedEventArgs(CollectionChangeAction action, ImageGalleryItem? item) + { + Action = action; + Item = item; + } + +} + + +/// +/// Represents the event arguments for item tooltip showing events. +/// +[Serializable, ComVisible(true)] +public class ItemTooltipShowingEventArgs : EventArgs +{ + /// + /// Gets, sets the tooltip title. + /// + public string TooltipTitle { get; set; } = string.Empty; + + /// + /// Gets, sets the tooltip content. + /// + public string TooltipContent { get; set; } = string.Empty; + + /// + /// Gets, sets the tooltip size. + /// + public Size? TooltipSize { get; set; } = null; + + /// + /// Gets the thumbnail item. + /// + public ImageGalleryItem Item { get; init; } + + + /// + /// Initialize the new instance of . + /// + /// + public ItemTooltipShowingEventArgs(ImageGalleryItem item) + { + Item = item; + } +} + +#endregion // Event arguments + diff --git a/Source/Components/ImageGlass.Library/Comparer/NumericComparer.cs b/Source/Components/ImageGlass.Gallery/Extractor/Extractor.cs similarity index 52% rename from Source/Components/ImageGlass.Library/Comparer/NumericComparer.cs rename to Source/Components/ImageGlass.Gallery/Extractor/Extractor.cs index f3b68c994..7abcb6d9e 100644 --- a/Source/Components/ImageGlass.Library/Comparer/NumericComparer.cs +++ b/Source/Components/ImageGlass.Gallery/Extractor/Extractor.cs @@ -1,7 +1,7 @@ -/* +/* ImageGlass Project - Image viewer for Windows -Copyright (C) 2013 DUONG DIEU PHAP -Project homepage: http://imageglass.org +Copyright (C) 2010 - 2026 DUONG DIEU PHAP +Project homepage: https://imageglass.org 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 @@ -14,30 +14,30 @@ 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 . +along with this program. If not, see . */ -// (c) Vasian Cepa 2005 -// Version 2 +namespace ImageGlass.Gallery; -using System.Collections; // required for NumericComparer : IComparer only -namespace ImageGlass.Library.Comparer +/// +/// Extracts thumbnails from images. +/// +internal static class Extractor { + private static IExtractor _extractor = new GDIExtractor(); - public class NumericComparer : IComparer + public static IExtractor Current { - public NumericComparer() - { } - - public int Compare(object x, object y) + get { - if ((x is string) && (y is string)) + if (_extractor == null) { - return StringLogicalComparer.Compare((string)x, (string)y); + throw new ArgumentNullException(nameof(_extractor)); } - return -1; + + return _extractor; } - }//EOC + } +} -} \ No newline at end of file diff --git a/Source/Components/ImageGlass.Gallery/Extractor/GDIMetadataExtractor.cs b/Source/Components/ImageGlass.Gallery/Extractor/GDIMetadataExtractor.cs new file mode 100644 index 000000000..f3bad90d5 --- /dev/null +++ b/Source/Components/ImageGlass.Gallery/Extractor/GDIMetadataExtractor.cs @@ -0,0 +1,207 @@ +/* +ImageGlass Project - Image viewer for Windows +Copyright (C) 2010 - 2026 DUONG DIEU PHAP +Project homepage: https://imageglass.org + +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 . + +--------------------- +ImageGlass.Gallery is based on ImageListView v13.8.2: +Url: https://github.com/oozcitak/imagelistview +License: Apache License Version 2.0, http://www.apache.org/licenses/ +--------------------- +*/ +using ImageGlass.Base.Photoing.Codecs; +using System.Text; + +namespace ImageGlass.Gallery; + + +/// +/// Read metadata. +/// +public partial class GDIExtractor : IExtractor +{ + #region Properties + /// + /// Gets the name of this extractor. + /// + public virtual string Name => "GDI Thumbnail Extractor"; + + #endregion + + + #region Exif Tag IDs + private const int TagImageDescription = 0x010E; + private const int TagEquipmentModel = 0x0110; + private const int TagDateTimeOriginal = 0x9003; + private const int TagArtist = 0x013B; + private const int TagCopyright = 0x8298; + private const int TagExposureTime = 0x829A; + private const int TagFNumber = 0x829D; + private const int TagISOSpeed = 0x8827; + private const int TagUserComment = 0x9286; + private const int TagRating = 0x4746; + private const int TagRatingPercent = 0x4749; + private const int TagEquipmentManufacturer = 0x010F; + private const int TagFocalLength = 0x920A; + private const int TagSoftware = 0x0131; + + #endregion + + + #region Exif Format Conversion + /// + /// Converts the given Exif data to an ASCII encoded string. + /// + /// Exif data as a byte array. + private static string ExifAscii(byte[] value) + { + if (value == null || value.Length == 0) + return string.Empty; + + var str = Encoding.ASCII.GetString(value).Trim('\0'); + + return str; + } + + /// + /// Converts the given Exif data to DateTime. + /// + /// Exif data as a byte array. + private static DateTime ExifDateTime(byte[] value) + { + return ExifDateTime(ExifAscii(value)); + } + + /// + /// Converts the given Exif data to DateTime. + /// Value must be formatted as yyyy:MM:dd HH:mm:ss. + /// + /// Exif data as a string. + private static DateTime ExifDateTime(string value) + { + var parts = value.Split(new char[] { ':', ' ' }); + try + { + if (parts.Length == 6) + { + // yyyy:MM:dd HH:mm:ss + // This is the expected format though some cameras + // can use single digits. See Issue 21. + return new DateTime(int.Parse(parts[0]), int.Parse(parts[1]), int.Parse(parts[2]), int.Parse(parts[3]), int.Parse(parts[4]), int.Parse(parts[5])); + } + else if (parts.Length == 3) + { + // yyyy:MM:dd + return new DateTime(int.Parse(parts[0]), int.Parse(parts[1]), int.Parse(parts[2])); + } + else + { + return DateTime.MinValue; + } + } + catch + { + return DateTime.MinValue; + } + } + + /// + /// Converts the given Exif data to an 16-bit unsigned integer. + /// The value must have 2 bytes. + /// + /// Exif data as a byte array. + private static ushort ExifUShort(byte[] value) + { + return BitConverter.ToUInt16(value, 0); + } + + /// + /// Converts the given Exif data to an 32-bit unsigned integer. + /// The value must have 4 bytes. + /// + /// Exif data as a byte array. + private static uint ExifUInt(byte[] value) + { + return BitConverter.ToUInt32(value, 0); + } + + /// + /// Converts the given Exif data to an 32-bit signed integer. + /// The value must have 4 bytes. + /// + /// Exif data as a byte array. + private static int ExifInt(byte[] value) + { + return BitConverter.ToInt32(value, 0); + } + + /// + /// Converts the given Exif data to an unsigned rational value + /// represented as a string. + /// The value must have 8 bytes. + /// + /// Exif data as a byte array. + private static string ExifURational(byte[] value) + { + return BitConverter.ToUInt32(value, 0).ToString() + "/" + + BitConverter.ToUInt32(value, 4).ToString(); + } + + /// + /// Converts the given Exif data to a signed rational value + /// represented as a string. + /// The value must have 8 bytes. + /// + /// Exif data as a byte array. + private static string ExifRational(byte[] value) + { + return BitConverter.ToInt32(value, 0).ToString() + "/" + + BitConverter.ToInt32(value, 4).ToString(); + } + + /// + /// Converts the given Exif data to a double number. + /// The value must have 8 bytes. + /// + /// Exif data as a byte array. + private static double ExifDouble(byte[] value) + { + var num = BitConverter.ToUInt32(value, 0); + var den = BitConverter.ToUInt32(value, 4); + + if (den == 0) + return 0.0; + else + return num / (double)den; + } + + #endregion + + + #region Public Methods + + /// + /// Returns image metadata. + /// + /// Filepath of image + public virtual IgMetadata GetMetadata(string path) + { + return PhotoCodec.LoadMetadata(path); + } + + #endregion +} + diff --git a/Source/Components/ImageGlass.Gallery/Extractor/GDIShellInfoExtractor.cs b/Source/Components/ImageGlass.Gallery/Extractor/GDIShellInfoExtractor.cs new file mode 100644 index 000000000..785bdfb36 --- /dev/null +++ b/Source/Components/ImageGlass.Gallery/Extractor/GDIShellInfoExtractor.cs @@ -0,0 +1,187 @@ +/* +ImageGlass Project - Image viewer for Windows +Copyright (C) 2010 - 2026 DUONG DIEU PHAP +Project homepage: https://imageglass.org + +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 . + +--------------------- +ImageGlass.Gallery is based on ImageListView v13.8.2: +Url: https://github.com/oozcitak/imagelistview +License: Apache License Version 2.0, http://www.apache.org/licenses/ +--------------------- +*/ +using System.Runtime.InteropServices; + +namespace ImageGlass.Gallery; + + +/// +/// Reads shell icons and shell file types. +/// +public partial class GDIExtractor : IExtractor +{ + #region Platform Invoke + + // GetFileAttributesEx + [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)] + [return: MarshalAs(UnmanagedType.Bool)] + private static extern bool GetFileAttributesEx(string lpFileName, + GET_FILEEX_INFO_LEVELS fInfoLevelId, out WIN32_FILE_ATTRIBUTE_DATA fileData); + + private enum GET_FILEEX_INFO_LEVELS + { + GetFileExInfoStandard, + GetFileExMaxInfoLevel + } + + [StructLayout(LayoutKind.Sequential)] + private struct WIN32_FILE_ATTRIBUTE_DATA + { + public FileAttributes dwFileAttributes; + public FILETIME ftCreationTime; + public FILETIME ftLastAccessTime; + public FILETIME ftLastWriteTime; + public uint nFileSizeHigh; + public uint nFileSizeLow; + } + + [StructLayout(LayoutKind.Sequential)] + private struct FILETIME + { + public uint dwLowDateTime; + public uint dwHighDateTime; + + public DateTime Value + { + get + { + long longTime = (((long)dwHighDateTime) << 32) | dwLowDateTime; + return DateTime.FromFileTimeUtc(longTime); + } + } + } + + // DestroyIcon + [DllImport("user32.dll", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + private static extern bool DestroyIcon(IntPtr hIcon); + + // SHGetFileInfo + [DllImport("shell32.dll", CharSet = CharSet.Auto)] + private static extern IntPtr SHGetFileInfo(string pszPath, FileAttributes dwFileAttributes, out SHFILEINFO psfi, uint cbFileInfo, SHGFI uFlags); + + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] + private struct SHFILEINFO + { + public IntPtr hIcon; + public int iIcon; + public uint dwAttributes; + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = MAX_PATH)] + public string szDisplayName; + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = MAX_TYPE)] + public string szTypeName; + }; + + private const int MAX_PATH = 260; + private const int MAX_TYPE = 80; + + [Flags] + private enum SHGFI : uint + { + Icon = 0x000000100, + DisplayName = 0x000000200, + TypeName = 0x000000400, + Attributes = 0x000000800, + IconLocation = 0x000001000, + ExeType = 0x000002000, + SysIconIndex = 0x000004000, + LinkOverlay = 0x000008000, + Selected = 0x000010000, + Attr_Specified = 0x000020000, + LargeIcon = 0x000000000, + SmallIcon = 0x000000001, + OpenIcon = 0x000000002, + ShellIconSize = 0x000000004, + PIDL = 0x000000008, + UseFileAttributes = 0x000000010, + AddOverlays = 0x000000020, + OverlayIndex = 0x000000040, + } + + #endregion + + + #region Public Methods + + /// + /// Returns shell info. + /// + /// Filepath of image + public virtual ShellInfo GetShellInfo(string path) + { + var info = new ShellInfo(); + + try + { + var shinfo = new SHFILEINFO(); + var structSize = (uint)Marshal.SizeOf(shinfo); + var flags = SHGFI.Icon | SHGFI.SmallIcon | SHGFI.TypeName | SHGFI.UseFileAttributes; + + // Get the small icon and shell file type + var hImg = SHGetFileInfo(path, FileAttributes.Normal, out shinfo, structSize, flags); + + // Get mime type + info.FileType = shinfo.szTypeName; + + // Get small icon + if (hImg != IntPtr.Zero && shinfo.hIcon != IntPtr.Zero) + { + using var newIcon = Icon.FromHandle(shinfo.hIcon); + info.SmallIcon = newIcon.ToBitmap(); + + DestroyIcon(shinfo.hIcon); + } + else + { + info.Error = new Exception("Error reading shell icon"); + } + + // Get large icon + hImg = SHGetFileInfo(path, FileAttributes.Normal, out shinfo, structSize, SHGFI.Icon | SHGFI.LargeIcon | SHGFI.UseFileAttributes); + + if (hImg != IntPtr.Zero && shinfo.hIcon != IntPtr.Zero) + { + using var newIcon = Icon.FromHandle(shinfo.hIcon); + info.LargeIcon = newIcon.ToBitmap(); + + DestroyIcon(shinfo.hIcon); + } + else + { + info.Error = new Exception("Error reading shell icon"); + } + } + catch (Exception e) + { + info.Error = e; + } + + return info; + } + + #endregion + +} + diff --git a/Source/Components/ImageGlass.Gallery/Extractor/GDIThumbnailExtractor.cs b/Source/Components/ImageGlass.Gallery/Extractor/GDIThumbnailExtractor.cs new file mode 100644 index 000000000..32aec9382 --- /dev/null +++ b/Source/Components/ImageGlass.Gallery/Extractor/GDIThumbnailExtractor.cs @@ -0,0 +1,286 @@ +/* +ImageGlass Project - Image viewer for Windows +Copyright (C) 2010 - 2026 DUONG DIEU PHAP +Project homepage: https://imageglass.org + +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 . + +--------------------- +ImageGlass.Gallery is based on ImageListView v13.8.2: +Url: https://github.com/oozcitak/imagelistview +License: Apache License Version 2.0, http://www.apache.org/licenses/ +--------------------- +*/ +using ImageGlass.Base; +using ImageGlass.Base.Photoing.Codecs; +using System.Drawing.Drawing2D; + +namespace ImageGlass.Gallery; + + +/// +/// Extracts thumbnails from images. +/// +public partial class GDIExtractor : IExtractor +{ + // Exif Tag IDs + private const int TagOrientation = 0x0112; + + + #region Constructor + /// + /// Initializes a new instance of the GDIExtractor class. + /// + public GDIExtractor() + { + } + + #endregion + + + #region Public Methods + + /// + /// Creates a thumbnail from the given image. + /// + /// The source image. + /// Requested image size. + /// Embedded thumbnail usage. + /// true to automatically rotate images based on Exif orientation; otherwise false. + /// The thumbnail image from the given image or null if an error occurs. + public virtual Image? GetThumbnail(Image image, Size size, UseEmbeddedThumbnails useEmbeddedThumbnails, bool useExifOrientation) + { + if (size.Width <= 0 || size.Height <= 0) return null; + + return GetThumbnailBmp(image, size, useExifOrientation ? GetRotation(image) : 0); + } + + + /// + /// Creates a thumbnail from the given image file. + /// + /// The filename pointing to an image. + /// Requested image size. + /// Embedded thumbnail usage. + /// true to automatically rotate images based on Exif orientation; otherwise false. + /// The thumbnail image from the given file or null if an error occurs. + public virtual Image? GetThumbnail(string filename, Size size, UseEmbeddedThumbnails useEmbeddedThumbnails, bool useExifOrientation) + { + if (string.IsNullOrEmpty(filename)) return null; + if (size.Width <= 0 || size.Height <= 0) return null; + + return GetThumbnailBmp(filename, size, useEmbeddedThumbnails, + useExifOrientation ? GetRotation(filename) : 0); + } + + #endregion + + + #region Helper Methods + + /// + /// Creates a thumbnail from the given image. + /// + /// The source image. + /// Requested image size. + /// Rotation angle. + /// The image from the given file or null if an error occurs. + internal static Image? GetThumbnailBmp(Image image, Size size, int rotate) + { + if (size.Width <= 0 || size.Height <= 0) return null; + + Image? thumb = null; + try + { + double scale; + if (rotate % 180 != 0) + { + scale = Math.Min(size.Height / (double)image.Width, + size.Width / (double)image.Height); + } + else + { + scale = Math.Min(size.Width / (double)image.Width, + size.Height / (double)image.Height); + } + + thumb = ScaleDownRotateBitmap(image, scale, rotate); + } + catch + { + thumb?.Dispose(); + thumb = null; + } + + return thumb; + } + + + /// + /// Creates a thumbnail from the given image file. + /// + /// The filename pointing to an image. + /// Requested image size. + /// Embedded thumbnail usage. + /// Rotation angle. + /// The image from the given file or null if an error occurs. + internal Image? GetThumbnailBmp(string filename, Size size, UseEmbeddedThumbnails useEmbeddedThumbnails, int rotate) + { + if (size.Width <= 0 || size.Height <= 0) return null; + + Image? thumb = null; + + // extrack thumbnail from shell + if (useEmbeddedThumbnails == UseEmbeddedThumbnails.Always) + { + thumb = ShellThumbnailApi.GetThumbnail(filename, size.Width, size.Height, ShellThumbnailOptions.ThumbnailOnly | ShellThumbnailOptions.BiggerSizeOk); + } + + // get thumbnail from source file + else if (useEmbeddedThumbnails == UseEmbeddedThumbnails.Never) + { + thumb = PhotoCodec.GetThumbnail(filename, (uint)size.Width, (uint)size.Height); + } + else + { + thumb = ShellThumbnailApi.GetThumbnail(filename, size.Width, size.Height, ShellThumbnailOptions.ThumbnailOnly | ShellThumbnailOptions.BiggerSizeOk); + + if (thumb == null) + { + thumb = PhotoCodec.GetThumbnail(filename, (uint)size.Width, (uint)size.Height); + } + } + + return thumb; + } + + + /// + /// Returns Exif rotation in degrees. Returns 0 if the metadata + /// does not exist or could not be read. A negative value means + /// the image needs to be mirrored about the vertical axis. + /// + /// Image. + private static int GetRotation(Image img) + { + try + { + foreach (var prop in img.PropertyItems) + { + if (prop.Id == TagOrientation && prop.Value != null) + { + var orientationFlag = BitConverter.ToUInt16(prop.Value, 0); + if (orientationFlag == 1) + return 0; + else if (orientationFlag == 2) + return -360; + else if (orientationFlag == 3) + return 180; + else if (orientationFlag == 4) + return -180; + else if (orientationFlag == 5) + return -90; + else if (orientationFlag == 6) + return 90; + else if (orientationFlag == 7) + return -270; + else if (orientationFlag == 8) + return 270; + } + } + } + catch { } + + return 0; + } + + + /// + /// Returns Exif rotation in degrees. Returns 0 if the metadata + /// does not exist or could not be read. A negative value means + /// the image needs to be mirrored about the vertical axis. + /// + /// Image. + private static int GetRotation(string filename) + { + try + { + using var stream = new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.Read); + using var img = Image.FromStream(stream, false, false); + + return GetRotation(img); + } + catch { } + + return 0; + } + + + /// + /// Scales down and rotates an image. + /// + /// Original image + /// Uniform scaling factor + /// Rotation angle + /// Scaled and rotated image + private static Image? ScaleDownRotateBitmap(Image source, double scale, int angle) + { + if (angle % 90 != 0) + { + throw new ArgumentException("Rotation angle should be a multiple of 90 degrees.", nameof(angle)); + } + + // Do not upscale and no rotation. + if ((float)scale >= 1.0f && angle == 0) + { + return new Bitmap(source); + } + + var sourceWidth = source.Width; + var sourceHeight = source.Height; + + // Scale + var xScale = Math.Min(1.0, Math.Max(1.0 / sourceWidth, scale)); + var yScale = Math.Min(1.0, Math.Max(1.0 / sourceHeight, scale)); + + var width = (int)(sourceWidth * xScale); + var height = (int)(sourceHeight * yScale); + var thumbWidth = Math.Abs(angle) % 180 == 0 ? width : height; + var thumbHeight = Math.Abs(angle) % 180 == 0 ? height : width; + + var thumb = new Bitmap(thumbWidth, thumbHeight); + thumb.SetResolution(source.HorizontalResolution, source.VerticalResolution); + + using var g = Graphics.FromImage(thumb); + g.PixelOffsetMode = PixelOffsetMode.None; + g.InterpolationMode = InterpolationMode.HighQualityBicubic; + g.Clear(Color.Transparent); + + g.TranslateTransform(-sourceWidth / 2, -sourceHeight / 2, MatrixOrder.Append); + if (Math.Abs(angle) % 360 != 0) + g.RotateTransform(Math.Abs(angle), MatrixOrder.Append); + if (angle < 0) + xScale = -xScale; + g.ScaleTransform((float)xScale, (float)yScale, MatrixOrder.Append); + g.TranslateTransform(thumbWidth / 2, thumbHeight / 2, MatrixOrder.Append); + + g.DrawImage(source, 0, 0); + + + return thumb; + } + + + #endregion +} diff --git a/Source/Components/ImageGlass.Gallery/Extractor/IExtractor.cs b/Source/Components/ImageGlass.Gallery/Extractor/IExtractor.cs new file mode 100644 index 000000000..e2c13c93e --- /dev/null +++ b/Source/Components/ImageGlass.Gallery/Extractor/IExtractor.cs @@ -0,0 +1,71 @@ +/* +ImageGlass Project - Image viewer for Windows +Copyright (C) 2010 - 2026 DUONG DIEU PHAP +Project homepage: https://imageglass.org + +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 . + +--------------------- +ImageGlass.Gallery is based on ImageListView v13.8.2: +Url: https://github.com/oozcitak/imagelistview +License: Apache License Version 2.0, http://www.apache.org/licenses/ +--------------------- +*/ + +using ImageGlass.Base.Photoing.Codecs; + +namespace ImageGlass.Gallery; + +/// +/// Interface for thumbnail, metadata and shell info extractors. +/// +public interface IExtractor +{ + /// + /// Gets the name of this extractor. + /// + string Name { get; } + + /// + /// Returns image metadata. + /// + /// Filepath of image + IgMetadata GetMetadata(string path); + + /// + /// Creates a thumbnail from the given image file. + /// + /// The filename pointing to an image. + /// Requested image size. + /// Embedded thumbnail usage. + /// true to automatically rotate images based on Exif orientation; otherwise false. + /// The thumbnail image from the given file or null if an error occurs. + Image? GetThumbnail(string filename, Size size, UseEmbeddedThumbnails useEmbeddedThumbnails, bool useExifOrientation); + + /// + /// Creates a thumbnail from the given image. + /// + /// The source image. + /// Requested image size. + /// Embedded thumbnail usage. + /// true to automatically rotate images based on Exif orientation; otherwise false. + /// The thumbnail image from the given image or null if an error occurs. + Image? GetThumbnail(Image image, Size size, UseEmbeddedThumbnails useEmbeddedThumbnails, bool useExifOrientation); + + /// + /// Returns shell info. + /// + /// Filepath of image + ShellInfo GetShellInfo(string path); +} diff --git a/Source/Components/ImageGlass.Gallery/Extractor/ShellInfo.cs b/Source/Components/ImageGlass.Gallery/Extractor/ShellInfo.cs new file mode 100644 index 000000000..88f66dd09 --- /dev/null +++ b/Source/Components/ImageGlass.Gallery/Extractor/ShellInfo.cs @@ -0,0 +1,53 @@ +/* +ImageGlass Project - Image viewer for Windows +Copyright (C) 2010 - 2026 DUONG DIEU PHAP +Project homepage: https://imageglass.org + +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 . + +--------------------- +ImageGlass.Gallery is based on ImageListView v13.8.2: +Url: https://github.com/oozcitak/imagelistview +License: Apache License Version 2.0, http://www.apache.org/licenses/ +--------------------- +*/ +namespace ImageGlass.Gallery; + + +/// +/// Contains shell icons and shell file type. +/// +public class ShellInfo +{ + /// + /// Error. + /// + public Exception? Error = null; + + /// + /// Mime type. + /// + public string? FileType = null; + + /// + /// Small shell icon. + /// + public Image? SmallIcon = null; + + /// + /// Large shell icon. + /// + public Image? LargeIcon = null; + +} diff --git a/Source/Components/ImageGlass.Gallery/ImageGallery.cs b/Source/Components/ImageGlass.Gallery/ImageGallery.cs new file mode 100644 index 000000000..194738e4b --- /dev/null +++ b/Source/Components/ImageGlass.Gallery/ImageGallery.cs @@ -0,0 +1,2326 @@ +/* +ImageGlass Project - Image viewer for Windows +Copyright (C) 2010 - 2026 DUONG DIEU PHAP +Project homepage: https://imageglass.org + +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 . + +--------------------- +ImageGlass.Gallery is based on ImageListView v13.8.2: +Url: https://github.com/oozcitak/imagelistview +License: Apache License Version 2.0, http://www.apache.org/licenses/ +--------------------- +*/ + +using ImageGlass.Base; +using ImageGlass.Base.WinApi; +using ImageGlass.WinTouch; +using System.ComponentModel; + +namespace ImageGlass.Gallery; + +/// +/// Represents a listview control for image files. +/// +[ToolboxBitmap(typeof(ImageGallery))] +[DefaultEvent("ItemClick")] +[DefaultProperty("Items")] +[Docking(DockingBehavior.Ask)] +public partial class ImageGallery : Control, IComponent +{ + #region Member Variables + + // Set when properties change + private bool mDefaultImageChanged = false; + private bool mErrorImageChanged = false; + + // Properties + private BorderStyle mBorderStyle = BorderStyle.None; + private CacheMode mCacheMode = CacheMode.OnDemand; + private int mCacheLimitAsItemCount = 0; + private long mCacheLimitAsMemory = 20 * 1024 * 1024; // 20MB + private Image? mDefaultImage; + private Image? mErrorImage; + private bool mIntegralScroll = false; + private ItemCollection mItems; + private bool mRetryOnError = false; + internal SelectedItemCollection mSelectedItems; + internal CheckedItemCollection mCheckedItems; + private bool mShowFileIcons = false; + private bool mShowCheckBoxes = false; + private ContentAlignment mIconAlignment = ContentAlignment.TopRight; + private Size mIconPadding = new(2, 2); + private ContentAlignment mCheckBoxAlignment = ContentAlignment.BottomRight; + private Size mCheckBoxPadding = new(2, 2); + private Size mThumbnailSize = new(80, 80); + private UseEmbeddedThumbnails mUseEmbeddedThumbnails = UseEmbeddedThumbnails.Auto; + private View mView = View.Thumbnails; + private Point mViewOffset = new(); + private bool mShowScrollBars = false; + private bool mShowItemText = false; + private ToolTip? mTooltip = new(); + private CancellationTokenSource _tooltipTokenSrc = new(); + + // Renderer variables + internal StyleRenderer mRenderer = new(); + private bool controlSuspended = false; + private int rendererSuspendCount = 0; + private bool rendererNeedsPaint = true; + private readonly System.Timers.Timer lazyRefreshTimer = new() + { + Interval = StyleRenderer.LazyRefreshInterval, + Enabled = false, + }; + private readonly RefreshDelegateInternal lazyRefreshCallback; + + // Layout variables + internal HScrollBar hScrollBar = new() { Visible = false }; + internal VScrollBar vScrollBar = new() { Visible = false }; + internal LayoutManager layoutManager; + private bool _isDisposed = false; + + // Interaction variables + internal NavigationManager navigationManager; + + // Cache threads + internal ThumbnailCacheManager thumbnailCache; + internal ShellInfoCacheManager shellInfoCache; + internal FileSystemAdaptor defaultAdaptor = new(); + + #endregion + + + #region Properties + + /// + /// Gets current style renderer. + /// + public StyleRenderer Renderer => mRenderer; + + /// + /// Gets, set tooltip. + /// + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public ToolTip? Tooltip + { + get => mTooltip; + set + { + mTooltip?.Dispose(); + mTooltip = value; + } + } + + /// + /// Enable transparent background. + /// + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public bool EnableTransparent { get; set; } = true; + + /// + /// Gets, sets resizer. + /// + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public ResizerType Resizer { get; set; } = ResizerType.None; + + /// + /// Gets, sets the size of . Default is 4px. + /// + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public int ResizerSize { get; set; } = 8; + + /// + /// Gets resizer bound. + /// + public Rectangle ResizerBound + { + get + { + var resizerSize = this.ScaleToDpi(ResizerSize); + if (Resizer == ResizerType.HTBOTTOM && HScrollBar.Visible) + { + resizerSize += HScrollBar.Height; + } + else if (Resizer == ResizerType.HTRIGHT && VScrollBar.Visible) + { + resizerSize += VScrollBar.Width; + } + + // get resizer bound + var resizerRect = ClientRectangle; + if (Resizer == ResizerType.HTTOP) + { + resizerRect.Height = resizerSize; + } + else if (Resizer == ResizerType.HTBOTTOM) + { + resizerRect.Y = ClientRectangle.Height - resizerSize; + resizerRect.Height = resizerSize; + } + else if (Resizer == ResizerType.HTLEFT) + { + resizerRect.Width = resizerSize; + } + else if (Resizer == ResizerType.HTRIGHT) + { + resizerRect.X = ClientRectangle.Width - resizerSize; + resizerRect.Width = resizerSize; + } + else + { + resizerRect = Rectangle.Empty; + } + + return resizerRect; + } + } + + /// + /// Gets the maximum number of columns that can be displayed. + /// + public int MaxColumns => layoutManager.Cols; + + /// + /// Gets or sets whether thumbnail images are automatically rotated. + /// + [Category("Behavior"), DefaultValue(true)] + public bool AutoRotateThumbnails { get; set; } = true; + + /// + /// Gets or sets whether checkboxes respond to mouse clicks. + /// + [Category("Behavior"), DefaultValue(true)] + public bool AllowCheckBoxClick { get; set; } = true; + + /// + /// Gets or sets whether the user can reorder items by moving them. + /// + [Category("Behavior"), DefaultValue(false)] + public bool AllowItemReorder { get; set; } = false; + + /// + /// Gets or sets whether items can be dragged out of the control to start a drag and drop operation. + /// + [Category("Behavior"), DefaultValue(true)] + public bool AllowDrag { get; set; } = true; + + + /// + /// Gets or sets the border style of the control. + /// + [Category("Appearance"), DefaultValue(typeof(BorderStyle), "None")] + public BorderStyle BorderStyle + { + get => mBorderStyle; + set + { + mBorderStyle = value; + UpdateStyles(); + } + } + + /// + /// Gets or sets the cache mode. Setting the the CacheMode to Continuous disables the CacheLimit. + /// + [Category("Behavior"), DefaultValue(typeof(CacheMode), "OnDemand"), RefreshProperties(RefreshProperties.All)] + public CacheMode CacheMode + { + get => mCacheMode; + set + { + if (mCacheMode != value) + { + mCacheMode = value; + + if (thumbnailCache != null) + thumbnailCache.CacheMode = mCacheMode; + + if (mCacheMode == CacheMode.Continuous) + { + mCacheLimitAsItemCount = 0; + mCacheLimitAsMemory = 0; + if (thumbnailCache != null) + { + thumbnailCache.CacheLimitAsItemCount = 0; + thumbnailCache.CacheLimitAsMemory = 0; + thumbnailCache._diskCache.CacheSize = 0; + } + // Rebuild the cache + ClearThumbnailCache(); + } + } + } + } + + /// + /// Should the cache files still be saved for next time load or be deleted. + /// + [Category("Behavior"), DefaultValue(true)] + public bool DoNotDeletePersistentCache { get; set; } = true; + + /// + /// Gets or sets the cache limit as either the count of thumbnail images or the memory allocated for cache (e.g. 10MB). + /// + [Category("Behavior"), DefaultValue("20MB"), RefreshProperties(RefreshProperties.All)] + public string CacheLimit + { + get + { + if (mCacheLimitAsMemory != 0) + return (mCacheLimitAsMemory / 1024 / 1024).ToString() + "MB"; + else + return mCacheLimitAsItemCount.ToString(); + } + set + { + var slimit = value; + mCacheMode = CacheMode.OnDemand; + + // cache by memory + if ((slimit.EndsWith("MB", StringComparison.OrdinalIgnoreCase) + && int.TryParse(slimit[0..^2].Trim(), out int limit)) + || (slimit.EndsWith("MiB", StringComparison.OrdinalIgnoreCase) + && int.TryParse(slimit[0..^3].Trim(), out limit))) + { + mCacheLimitAsItemCount = 0; + mCacheLimitAsMemory = limit * 1024 * 1024; + if (thumbnailCache != null) + { + thumbnailCache.CacheLimitAsItemCount = 0; + thumbnailCache.CacheLimitAsMemory = mCacheLimitAsMemory; + } + } + // cache my item count + else if (int.TryParse(slimit, out limit)) + { + mCacheLimitAsMemory = 0; + mCacheLimitAsItemCount = limit; + if (thumbnailCache != null) + { + thumbnailCache.CacheLimitAsMemory = 0; + thumbnailCache.CacheLimitAsItemCount = mCacheLimitAsItemCount; + } + } + else + { + throw new ArgumentException("Cache limit must be specified as either the count of thumbnail images or the memory allocated for cache (eg 10MB)", nameof(value)); + } + } + } + + /// + /// Gets or sets the path to the persistent cache file. + /// + [Category("Behavior"), Browsable(false)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public string PersistentCacheDirectory + { + get => thumbnailCache._diskCache.DirectoryName; + set + { + thumbnailCache._diskCache.DirectoryName = value; + } + } + + /// + /// Gets or sets the size of the persistent cache file in MB. + /// + [Category("Behavior"), Browsable(false)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public long PersistentCacheSize + { + get + { + if (mCacheMode == CacheMode.Continuous) + return 0; + + if (thumbnailCache != null) + return thumbnailCache._diskCache.CacheSize / 1024 / 1024; + else + return 0; + } + set + { + if (thumbnailCache != null) + thumbnailCache._diskCache.CacheSize = value * 1024 * 1024; + } + } + + + /// + /// Gets or sets the placeholder image. + /// + [Category("Appearance")] + public Image? DefaultImage + { + get => mDefaultImage; + set + { + mDefaultImageChanged = true; + mDefaultImage = value; + Refresh(); + } + } + + /// + /// Gets the rectangle that represents the display area of the control. + /// + [Category("Appearance"), Browsable(false)] + public override Rectangle DisplayRectangle + { + get + { + if (layoutManager == null) + return base.DisplayRectangle; + else + return layoutManager.ClientArea; + } + } + + /// + /// Gets or sets a value indicating whether the control can respond to user interaction. + /// Cache threads are paused while the control is disabled and resumed when the control is + /// enabled. + /// + [Category("Behavior"), DefaultValue(true)] + public new bool Enabled + { + get => base.Enabled; + set + { + base.Enabled = value; + if (value) + { + thumbnailCache.Resume(); + shellInfoCache.Resume(); + } + else + { + thumbnailCache.Pause(); + shellInfoCache.Pause(); + } + } + } + + /// + /// Gets or sets whether Key Navigation is enabled. + /// + [Category("Behavior")] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public bool EnableKeyNavigation { get; set; } = true; + + /// + /// Gets or sets the error image. + /// + [Category("Appearance")] + public Image? ErrorImage + { + get => mErrorImage; + set + { + mErrorImageChanged = true; + mErrorImage = value; + Refresh(); + } + } + + /// + /// Gets or sets whether scrollbars scroll by an amount which is a multiple of item height. + /// + [Category("Behavior"), DefaultValue(false)] + public bool IntegralScroll + { + get => mIntegralScroll; + set + { + if (mIntegralScroll != value) + { + mIntegralScroll = value; + Refresh(); + } + } + } + + /// + /// Gets the collection of items contained in the image list view. + /// + [Category("Behavior")] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public ItemCollection Items + { + get => mItems; + internal set + { + mItems = value; + Refresh(); + } + } + + /// + /// Gets or sets whether multiple items can be selected. + /// + [Category("Behavior"), DefaultValue(false)] + public bool MultiSelect { get; set; } = false; + + /// + /// Gets or sets whether the control will retry loading thumbnails on an error. + /// + [Category("Behavior"), DefaultValue(true)] + public bool RetryOnError + { + get => mRetryOnError; + set + { + mRetryOnError = value; + if (thumbnailCache != null) + thumbnailCache.RetryOnError = mRetryOnError; + if (shellInfoCache != null) + shellInfoCache.RetryOnError = mRetryOnError; + } + } + + /// + /// Gets or sets whether the scrollbars should be shown. + /// + [Category("Appearance"), DefaultValue(false)] + public bool ScrollBars + { + get => mShowScrollBars; + set + { + mShowScrollBars = value; + Refresh(); + } + } + + /// + /// Gets horizontal scrollbar. + /// + public HScrollBar HScrollBar => hScrollBar; + + /// + /// Gets verticle scrollbar. + /// + public VScrollBar VScrollBar => vScrollBar; + + /// + /// Gets or sets whether item's text should be shown. + /// + [Category("Appearance"), DefaultValue(false)] + public bool ShowItemText + { + get => mShowItemText; + set + { + mShowItemText = value; + Refresh(); + } + } + + /// + /// Gets, sets tooltip direction + /// + [Category("Appearance"), DefaultValue(typeof(TooltipDirection), "Top")] + public TooltipDirection TooltipDirection { get; set; } = TooltipDirection.Top; + + /// + /// Gets the collection of selected items contained in the image list view. + /// + [Category("Behavior"), Browsable(false)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)] + public SelectedItemCollection SelectedItems => mSelectedItems; + + /// + /// Gets the collection of checked items contained in the image list view. + /// + [Category("Behavior"), Browsable(false)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)] + public CheckedItemCollection CheckedItems => mCheckedItems; + + /// + /// Gets or sets whether shell icons are displayed for non-image files. + /// + [Category("Behavior"), Browsable(false), DefaultValue(true)] + public bool ShellIconFallback { get; set; } = true; + + /// + /// Gets or sets whether shell icons are extracted from the contents of icon and executable files. + /// When set to false, the generic shell icon for the filename extension is extracted. + /// + [Category("Behavior"), Browsable(false), DefaultValue(true)] + public bool ShellIconFromFileContent { get; set; } = true; + + /// + /// Gets or sets whether to display the file icons. + /// + [Category("Appearance"), DefaultValue(false)] + public bool ShowFileIcons + { + get => mShowFileIcons; + set + { + mShowFileIcons = value; + Refresh(); + } + } + + /// + /// Gets or sets whether to display the item checkboxes. + /// + [Category("Appearance"), DefaultValue(false)] + public bool ShowCheckBoxes + { + get => mShowCheckBoxes; + set + { + mShowCheckBoxes = value; + Refresh(); + } + } + + /// + /// Gets or sets alignment of file icons. + /// + [Category("Appearance"), DefaultValue(ContentAlignment.TopRight)] + public ContentAlignment IconAlignment + { + get => mIconAlignment; + set + { + mIconAlignment = value; + Refresh(); + } + } + + /// + /// Gets or sets file icon padding. + /// + [Category("Appearance"), DefaultValue(typeof(Size), "2,2")] + public Size IconPadding + { + get => mIconPadding; + set + { + mIconPadding = value; + Refresh(); + } + } + + /// + /// Gets or sets alignment of item checkboxes. + /// + [Category("Appearance"), DefaultValue(ContentAlignment.BottomRight)] + public ContentAlignment CheckBoxAlignment + { + get => mCheckBoxAlignment; + set + { + mCheckBoxAlignment = value; + Refresh(); + } + } + + /// + /// Gets or sets item checkbox padding. + /// + [Category("Appearance"), DefaultValue(typeof(Size), "2,2")] + public Size CheckBoxPadding + { + get => mCheckBoxPadding; + set + { + mCheckBoxPadding = value; + Refresh(); + } + } + + /// + /// This property is not relevant for this class. + /// + [EditorBrowsable(EditorBrowsableState.Never), Browsable(false), Bindable(false), DefaultValue(""), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] +#pragma warning disable CS8765 // Nullability of type of parameter doesn't match overridden member (possibly because of nullability attributes). + public override string Text { get; set; } = string.Empty; +#pragma warning restore CS8765 // Nullability of type of parameter doesn't match overridden member (possibly because of nullability attributes). + + /// + /// Gets or sets the size of image thumbnails. + /// + [Category("Appearance"), DefaultValue(typeof(Size), "80,80")] + public Size ThumbnailSize + { + get => mThumbnailSize; + set + { + if (mThumbnailSize != value) + { + mThumbnailSize = value; + Refresh(); + } + } + } + + /// + /// Gets or sets the embedded thumbnails extraction behavior. + /// + [Category("Behavior"), DefaultValue(typeof(UseEmbeddedThumbnails), "Auto")] + public UseEmbeddedThumbnails UseEmbeddedThumbnails + { + get => mUseEmbeddedThumbnails; + set + { + if (mUseEmbeddedThumbnails != value) + { + mUseEmbeddedThumbnails = value; + Refresh(); + } + } + } + + /// + /// Gets or sets the view mode of the image list view. + /// + [Category("Appearance"), DefaultValue(typeof(View), "Thumbnails")] + public View View + { + get { return mView; } + set + { + if (mView != value) + { + int current = layoutManager.FirstPartiallyVisible; + mView = value; + Refresh(); + ScrollToIndex(current); + } + } + } + + /// + /// Gets or sets the scroll offset. + /// + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + internal Point ViewOffset + { + get { return mViewOffset; } + set { mViewOffset = value; } + } + + /// + /// Gets the scroll orientation. + /// + internal ScrollOrientation ScrollOrientation => mView == View.HorizontalStrip ? ScrollOrientation.HorizontalScroll : ScrollOrientation.VerticalScroll; + + #endregion + + + #region Custom Property Serializers + + /// + /// Determines if the default image should be serialized. + /// + /// true if the designer should serialize + /// the property; otherwise false. + public bool ShouldSerializeDefaultImage() + { + return mDefaultImageChanged; + } + + /// + /// Resets the default image to its default value. + /// + public void ResetDefaultImage() + { + DefaultImage = null; + mDefaultImageChanged = false; + } + + /// + /// Determines if the error image should be serialized. + /// + /// true if the designer should serialize + /// the property; otherwise false. + public bool ShouldSerializeErrorImage() + { + return mErrorImageChanged; + } + + /// + /// Resets the error image to its default value. + /// + public void ResetErrorImage() + { + ErrorImage = null; + mErrorImageChanged = false; + } + + #endregion + + + #region Constructor + /// + /// Initializes a new instance of the class. + /// + public ImageGallery() + { + SetRenderer(new SystemRenderer()); + + // Property defaults + mItems = new ItemCollection(this); + mSelectedItems = new SelectedItemCollection(this); + mCheckedItems = new CheckedItemCollection(this); + + SetStyle(ControlStyles.AllPaintingInWmPaint | ControlStyles.UserPaint | ControlStyles.Opaque | ControlStyles.Selectable | ControlStyles.UserMouse | ControlStyles.SupportsTransparentBackColor | ControlStyles.OptimizedDoubleBuffer, true); + + Size = new Size(120, 100); + + // Child controls + hScrollBar.Scroll += HScrollBar_Scroll; + vScrollBar.Scroll += VScrollBar_Scroll; + + Controls.Add(hScrollBar); + Controls.Add(vScrollBar); + + // Lazy refresh timer + lazyRefreshTimer.Elapsed += LazyRefreshTimer_Tick; + lazyRefreshCallback = new RefreshDelegateInternal(Refresh); + + // Helpers + layoutManager = new LayoutManager(this); + navigationManager = new NavigationManager(this); + + // Cache managers + thumbnailCache = new ThumbnailCacheManager(this); + shellInfoCache = new ShellInfoCacheManager(this); + + // enable touch gesture support + InitializeTouchGesture(); + } + #endregion + + + #region Touch gesture support + + private GestureListener? _gesture; + + + private void InitializeTouchGesture() + { + // initialize touch support + if (WindowApi.IsTouchDevice()) + { + _gesture = new GestureListener(this); + _gesture.Pan += Gesture_Pan; + } + } + + + private void Gesture_Pan(object? sender, PanEventArgs e) + { + if (e.Begin) return; + + ScrollVerticalDelta(e.PanOffset.Y); + ScrollHorizontalDelta(e.PanOffset.X); + } + #endregion // Touch support + + + #region Select/Check + /// + /// Marks all items as selected. + /// + public void SelectAll() + { + SuspendPaint(); + + foreach (ImageGalleryItem item in Items) + item.mSelected = true; + + OnSelectionChangedInternal(); + + Refresh(); + ResumePaint(); + } + + /// + /// Marks all items as unselected. + /// + public void ClearSelection() + { + SuspendPaint(); + mSelectedItems.Clear(); + Refresh(); + ResumePaint(); + } + + /// + /// Reverses the selection state of all items. + /// + public void InvertSelection() + { + SuspendPaint(); + + foreach (ImageGalleryItem item in Items) + item.mSelected = !item.mSelected; + + OnSelectionChangedInternal(); + + Refresh(); + ResumePaint(); + } + + /// + /// Marks all items that satisfy a condition as selected. + /// + public void SelectWhere(Func predicate) + { + foreach (ImageGalleryItem item in Items.Where(predicate)) + item.mSelected = true; + + OnSelectionChangedInternal(); + + Refresh(); + ResumePaint(); + } + + /// + /// Marks all items that satisfy a condition as unselected. + /// + public void UnselectWhere(Func predicate) + { + foreach (ImageGalleryItem item in Items.Where(predicate)) + item.mSelected = false; + + OnSelectionChangedInternal(); + + Refresh(); + ResumePaint(); + } + + /// + /// Marks all items as checked. + /// + public void CheckAll() + { + SuspendPaint(); + + foreach (ImageGalleryItem item in Items) + { + item.mChecked = true; + OnItemCheckBoxClickInternal(item); + } + + Refresh(); + ResumePaint(); + } + + /// + /// Marks all items as unchecked. + /// + public void UncheckAll() + { + SuspendPaint(); + mCheckedItems.Clear(); + Refresh(); + ResumePaint(); + } + + /// + /// Reverses the check state of all items. + /// + public void InvertCheckState() + { + SuspendPaint(); + + foreach (ImageGalleryItem item in Items) + { + item.mChecked = !item.mChecked; + OnItemCheckBoxClickInternal(item); + } + + Refresh(); + ResumePaint(); + } + + /// + /// Marks all items that satisfy a condition as checked. + /// + public void CheckWhere(Func predicate) + { + SuspendPaint(); + + foreach (ImageGalleryItem item in Items.Where(predicate)) + { + item.mChecked = true; + OnItemCheckBoxClickInternal(item); + } + + Refresh(); + ResumePaint(); + } + + /// + /// Marks all items that satisfy a condition as unchecked. + /// + public void UncheckWhere(Func predicate) + { + SuspendPaint(); + + foreach (ImageGalleryItem item in Items.Where(predicate)) + { + item.mChecked = false; + OnItemCheckBoxClickInternal(item); + } + + Refresh(); + ResumePaint(); + } + + /// + /// Marks all items as enabled. + /// + public void EnableAll() + { + SuspendPaint(); + + foreach (ImageGalleryItem item in Items) + item.mEnabled = true; + + Refresh(); + ResumePaint(); + } + + /// + /// Marks all items as disabled. + /// + public void DisableAll() + { + SuspendPaint(); + + foreach (ImageGalleryItem item in Items) + item.mEnabled = false; + + Refresh(); + ResumePaint(); + } + + /// + /// Marks all items that satisfy a condition as enabled. + /// + public void EnableWhere(Func predicate) + { + SuspendPaint(); + + foreach (ImageGalleryItem item in Items.Where(predicate)) + item.mEnabled = true; + + Refresh(); + ResumePaint(); + } + + /// + /// Marks all items that satisfy a condition as disabled. + /// + public void DisableWhere(Func predicate) + { + SuspendPaint(); + + foreach (ImageGalleryItem item in Items.Where(predicate)) + item.mEnabled = false; + + Refresh(); + ResumePaint(); + } + + #endregion + + + #region Instance Methods + /// + /// Clears the thumbnail cache. + /// + public void ClearThumbnailCache() + { + if (thumbnailCache != null) + { + thumbnailCache.Clear(); + if (CacheMode == CacheMode.Continuous) + { + foreach (ImageGalleryItem item in mItems) + { + thumbnailCache.Add(item.Guid, item.Adaptor, item.VirtualKey, mThumbnailSize, mUseEmbeddedThumbnails, AutoRotateThumbnails); + } + } + Refresh(); + } + } + + /// + /// Temporarily suspends the layout logic for the control. + /// + public new void SuspendLayout() + { + if (controlSuspended) + return; + + controlSuspended = true; + base.SuspendLayout(); + SuspendPaint(); + } + + /// + /// Resumes usual layout logic. + /// + public new void ResumeLayout() + { + ResumeLayout(false); + } + + /// + /// Resumes usual layout logic, optionally forcing an immediate layout of pending layout requests. + /// + /// true to execute pending layout requests; otherwise, false. + public new void ResumeLayout(bool performLayout) + { + if (!controlSuspended) + return; + + controlSuspended = false; + base.ResumeLayout(performLayout); + if (performLayout) + Refresh(); + ResumePaint(); + } + + /// + /// Sets the renderer for this instance. + /// + /// An to assign to the control. + public void SetRenderer(StyleRenderer renderer) + { + var oldRenderer = mRenderer; + + mRenderer = renderer ?? throw new ArgumentNullException(nameof(renderer)); + mRenderer.ImageGalleryOwner = this; + + oldRenderer?.Dispose(); + + if (layoutManager != null) + layoutManager.Update(true); + + Refresh(); + } + + /// + /// Determines the image list view element under the specified coordinates. + /// + /// The client coordinates of the point to be tested. + /// Details of the hit test. + public void HitTest(Point pt, out HitInfo hitInfo) + { + var itemIndex = -1; + var checkBoxHit = false; + var fileIconHit = false; + var resizerHit = false; + + if (pt.X < 0 || pt.Y < 0) + { + hitInfo = new HitInfo(itemIndex, checkBoxHit, fileIconHit, resizerHit); + return; + } + + + // Normalize to item area coordinates + pt.X -= layoutManager.ItemAreaBounds.Left; + pt.Y -= layoutManager.ItemAreaBounds.Top; + + // resizer hit test + resizerHit = ResizerBound.Contains(pt); + + + if (!resizerHit && pt.X > 0 && pt.Y > 0) + { + var startGap = 0; + + // add extra gap for hit test because the items are centered + if (View == View.HorizontalStrip + && Items.Count <= layoutManager.Cols) + { + var currentItemsWidth = layoutManager.ItemSizeWithMargin.Width * Items.Count; + startGap = layoutManager.ItemAreaBounds.Width / 2 - currentItemsWidth / 2; + } + + var col = (pt.X + mViewOffset.X - startGap) / layoutManager.ItemSizeWithMargin.Width; + var row = (pt.Y + mViewOffset.Y) / layoutManager.ItemSizeWithMargin.Height; + + + if (ScrollOrientation == ScrollOrientation.HorizontalScroll + || (ScrollOrientation == ScrollOrientation.VerticalScroll && col <= layoutManager.Cols)) + { + int index = row * layoutManager.Cols + col; + + if (index >= 0 && index <= Items.Count - 1) + { + var bounds = layoutManager.GetItemBounds(index); + if (bounds.Contains(pt.X + layoutManager.ItemAreaBounds.Left, pt.Y + layoutManager.ItemAreaBounds.Top)) + itemIndex = index; + + if (ShowCheckBoxes) + { + var checkBoxBounds = layoutManager.GetCheckBoxBounds(index); + if (checkBoxBounds.Contains(pt.X + layoutManager.ItemAreaBounds.Left, pt.Y + layoutManager.ItemAreaBounds.Top)) + checkBoxHit = true; + } + + if (ShowFileIcons) + { + var fileIconBounds = layoutManager.GetIconBounds(index); + if (fileIconBounds.Contains(pt.X + layoutManager.ItemAreaBounds.Left, pt.Y + layoutManager.ItemAreaBounds.Top)) + fileIconHit = true; + } + } + } + } + + + hitInfo = new HitInfo(itemIndex, checkBoxHit, fileIconHit, resizerHit); + } + + + /// + /// Scrolls the image list view to place the item with the specified + /// index as close to the center of the visible area as possible. + /// + /// The index of the item to scroll to. + /// true if the scroll position was changed; otherwise false + /// (item is already centered or the image list view is empty). + public bool ScrollToIndex(int itemIndex) + { + if (Items.Count == 0 || itemIndex < 0 || itemIndex > Items.Count - 1) + return false; + + var bounds = layoutManager.ItemAreaBounds; + var itemBounds = layoutManager.GetItemBounds(itemIndex); + + // Align center of the element with center of visible area. + if (ScrollOrientation == ScrollOrientation.HorizontalScroll) + { + int delta = (bounds.Left + bounds.Right) / 2 - (itemBounds.Left + itemBounds.Right) / 2; + return ScrollHorizontalDelta(delta); + } + else + { + int delta = (bounds.Bottom + bounds.Top) / 2 - (itemBounds.Bottom + itemBounds.Top) / 2; + return ScrollVerticalDelta(delta); + } + } + + /// + /// Scrolls horizontal scrollbar by delta. Checks that scrolling is within + /// allowed range. Calls Refresh() if scrolling position was changed. + /// + /// Delta to move scrolling. + /// true if scroll position was changed; false otherwise + private bool ScrollHorizontalDelta(int delta) + { + int newXOffset = mViewOffset.X - delta; + + if (newXOffset > hScrollBar.Maximum - hScrollBar.LargeChange + 1) + newXOffset = hScrollBar.Maximum - hScrollBar.LargeChange + 1; + if (newXOffset < hScrollBar.Minimum) + newXOffset = hScrollBar.Minimum; + if (newXOffset == mViewOffset.X) + return false; + + mViewOffset.X = newXOffset; + mViewOffset.Y = 0; + hScrollBar.Value = newXOffset; + vScrollBar.Value = 0; + + Refresh(); + + return true; + } + + /// + /// Scrolls vertical scrollbar by delta. Checks that scrolling is within + /// allowed range. Calls Refresh() if scrolling position was changed. + /// + /// Delta to move scrolling. + /// true if scroll position was changed; false otherwise + private bool ScrollVerticalDelta(int delta) + { + int newYOffset = mViewOffset.Y - delta; + + if (newYOffset > vScrollBar.Maximum - vScrollBar.LargeChange + 1) + newYOffset = vScrollBar.Maximum - vScrollBar.LargeChange + 1; + if (newYOffset < vScrollBar.Minimum) + newYOffset = vScrollBar.Minimum; + if (newYOffset == mViewOffset.Y) + return false; + + mViewOffset.X = 0; + mViewOffset.Y = newYOffset; + hScrollBar.Value = 0; + vScrollBar.Value = newYOffset; + + Refresh(); + + return true; + } + + /// + /// Determines whether the specified item is visible on the screen. + /// + /// The item to test. + /// An ItemVisibility value. + public ItemVisibility IsItemVisible(ImageGalleryItem item) + { + return IsItemVisible(item.Index); + } + + /// + /// Finds the first item that starts with the specified string. + /// + /// The text to search for. + /// + /// The zero-based index of the first item found; or -1 if no match is found. + /// + public int FindString(string s) + { + return FindString(s, 0); + } + + /// + /// Finds the first item that starts with the specified string. + /// + /// The text to search for. + /// The zero-based index of the first + /// item to be searched. Set to zero to search from the + /// beginning of the control. + /// + /// The zero-based index of the first item found; or -1 if no match is found. + /// + public int FindString(string s, int startIndex) + { + for (int i = startIndex; i < mItems.Count; i++) + { + ImageGalleryItem item = mItems[i]; + if (item.Text.StartsWith(s, StringComparison.InvariantCultureIgnoreCase)) + { + return item.Index; + } + } + + return -1; + } + + /// + /// Hide item's tooltip + /// + public void HideItemTooltip() + { + _tooltipTokenSrc.Cancel(); + mTooltip?.Hide(this); + } + + /// + /// Shows item tooltip + /// + public async void ShowItemTooltip(ImageGalleryItem? item, + int duration = -1, int delay = 400) + { + _tooltipTokenSrc?.Cancel(); + _tooltipTokenSrc = new(); + mTooltip?.Hide(this); + + if (mTooltip is null || item is null) return; + + try + { + // delay + await Task.Delay(delay, _tooltipTokenSrc.Token); + + // emit event + var args = new ItemTooltipShowingEventArgs(item); + ItemTooltipShowing?.Invoke(mTooltip, args); + + // calculate tooltip position + var tooltipPosY = 0; + var GAP = Font.Height / 2; + var bounds = layoutManager.GetItemBounds(item.Index); + var tooltipHeight = 0; + + // measure tooltip content height + if (args.TooltipSize == null) + { + var g = CreateGraphics(); + using var titleFont = new Font(Font, FontStyle.Bold); + var titleSize = g.MeasureString(args.TooltipTitle, titleFont); + var contentSize = g.MeasureString(args.TooltipContent, Font); + tooltipHeight = (int)(titleSize.Height + contentSize.Height); + } + else + { + tooltipHeight = args.TooltipSize.Value.Height; + } + + + // tooltip direction + if (TooltipDirection == TooltipDirection.Top) + { + tooltipPosY = bounds.Y - GAP - tooltipHeight; + } + else if (TooltipDirection == TooltipDirection.Bottom) + { + var screenLoc = PointToScreen(bounds.Location); + var workingArea = Screen.FromPoint(screenLoc)?.WorkingArea ?? new(); + + var posY = bounds.Bottom + GAP; + var screenPosY = PointToScreen(new Point(0, posY)).Y; + + // if tooltip cover the current thumbnail + if (screenPosY + tooltipHeight > workingArea.Bottom) + { + // forced to direction to top + tooltipPosY = bounds.Y - GAP - tooltipHeight; + } + else + { + tooltipPosY = posY; + } + } + + + // show tooltip + mTooltip.ToolTipTitle = args.TooltipTitle; + mTooltip.Show(args.TooltipContent, this, Math.Max(0, bounds.X), tooltipPosY); + + + // duration + await Task.Delay(duration, _tooltipTokenSrc.Token); + } + catch { } + + if (duration >= 0) + { + mTooltip.Hide(this); + } + } + + #endregion + + + #region Rendering Methods + /// + /// Refreshes the control. + /// + /// Forces a refresh even if the renderer is suspended. + /// Refreshes the control only if a set amount of time + /// has passed since the last refresh. + public void Refresh(bool force, bool lazy) + { + if (force) + base.Refresh(); + else if (lazy) + { + rendererNeedsPaint = true; + lazyRefreshTimer.Start(); + } + else if (CanPaint()) + base.Refresh(); + else + rendererNeedsPaint = true; + } + + /// + /// Redraws the owner control. + /// + /// If true, forces an immediate update, even if + /// the renderer is suspended by a SuspendPaint call. + private void Refresh(bool force) + { + Refresh(force, false); + } + + /// + /// Redraws the owner control. + /// + private new void Refresh() + { + Refresh(false, false); + } + + /// + /// Suspends painting until a matching ResumePaint call is made. + /// + public void SuspendPaint() + { + if (rendererSuspendCount == 0) + rendererNeedsPaint = false; + rendererSuspendCount++; + } + + /// + /// Resumes painting. This call must be matched by a prior SuspendPaint call. + /// + public void ResumePaint() + { + System.Diagnostics.Debug.Assert(rendererSuspendCount > 0, "Suspend count does not match resume count.", "ResumePaint() must be matched by a prior SuspendPaint() call."); + + rendererSuspendCount--; + if (rendererNeedsPaint) + Refresh(); + } + + /// + /// Determines if the control can be painted. + /// + private bool CanPaint() + { + if (mRenderer == null) + return false; + if (controlSuspended || rendererSuspendCount != 0) + return false; + else + return true; + } + + #endregion + + + #region Helper Methods + /// + /// Determines whether the specified item is visible on the screen. + /// + /// The Guid of the item to test. + /// true if the item is visible or partially visible; otherwise false. + internal bool IsItemVisible(Guid guid) + { + return layoutManager.IsItemVisible(guid); + } + + /// + /// Determines whether the specified item is modified. + /// + /// The Guid of the item to test. + /// true if the item is modified; otherwise false. + internal bool IsItemDirty(Guid guid) + { + if (mItems.TryGetValue(guid, out ImageGalleryItem? item)) + return item?.isDirty ?? false; + + return false; + } + + /// + /// Determines whether the specified item is visible on the screen. + /// + /// The index of the item to test. + /// An ItemVisibility value. + internal ItemVisibility IsItemVisible(int itemIndex) + { + if (mItems.Count == 0) + return ItemVisibility.NotVisible; + if (itemIndex < 0 || itemIndex > mItems.Count - 1) + return ItemVisibility.NotVisible; + + if (itemIndex < layoutManager.FirstPartiallyVisible || itemIndex > layoutManager.LastPartiallyVisible) + return ItemVisibility.NotVisible; + else if (itemIndex >= layoutManager.FirstVisible && itemIndex <= layoutManager.LastVisible) + return ItemVisibility.Visible; + else + return ItemVisibility.PartiallyVisible; + } + + /// + /// Gets the guids of visible items. + /// + internal Dictionary GetVisibleItems() + { + var visible = new Dictionary(); + + if (layoutManager.FirstPartiallyVisible != -1 && layoutManager.LastPartiallyVisible != -1) + { + int start = layoutManager.FirstPartiallyVisible; + int end = layoutManager.LastPartiallyVisible; + + start -= layoutManager.Cols * layoutManager.Rows; + end += layoutManager.Cols * layoutManager.Rows; + + start = Math.Min(mItems.Count - 1, Math.Max(0, start)); + end = Math.Min(mItems.Count - 1, Math.Max(0, end)); + + for (int i = start; i <= end; i++) + visible.Add(mItems[i].Guid, false); + } + return visible; + } + #endregion + + + #region Event Handlers + + /// + /// Handles the DragOver event. + /// + /// A that contains the event data. + protected override void OnDragOver(DragEventArgs e) + { + navigationManager.DragOver(e); + base.OnDragOver(e); + } + + /// + /// Handles the DragEnter event. + /// + /// A that contains the event data. + protected override void OnDragEnter(DragEventArgs e) + { + navigationManager.DragEnter(e); + base.OnDragEnter(e); + } + + /// + /// Handles the DragLeave event. + /// + /// An that contains the event data. + protected override void OnDragLeave(EventArgs e) + { + navigationManager.DragLeave(); + base.OnDragLeave(e); + } + + /// + /// Handles the DragDrop event. + /// + /// A that contains the event data. + protected override void OnDragDrop(DragEventArgs e) + { + navigationManager.DragDrop(e); + base.OnDragDrop(e); + } + + /// + /// Handles the Scroll event of the vScrollBar control. + /// + /// The source of the event. + /// The instance containing the event data. + private void VScrollBar_Scroll(object? sender, ScrollEventArgs e) + { + mViewOffset.Y = e.NewValue; + Refresh(); + } + + /// + /// Handles the Scroll event of the hScrollBar control. + /// + /// The source of the event. + /// The instance containing the event data. + private void HScrollBar_Scroll(object? sender, ScrollEventArgs e) + { + mViewOffset.X = e.NewValue; + Refresh(); + } + + /// + /// Handles the Tick event of the lazyRefreshTimer control. + /// + /// The source of the event. + /// The instance containing the event data. + private void LazyRefreshTimer_Tick(object? sender, EventArgs e) + { + try + { + if (IsHandleCreated && !IsDisposed) + BeginInvoke(lazyRefreshCallback); + lazyRefreshTimer.Stop(); + } + finally { } + } + + /// + /// Handles the Resize event. + /// + /// An that contains the event data. + protected override void OnResize(EventArgs e) + { + base.OnResize(e); + + if (!_isDisposed && mRenderer != null) + mRenderer.ClearBuffer(); + + if (hScrollBar != null && layoutManager != null) + layoutManager.Update(); + + Refresh(); + } + + /// + /// Handles the Paint event. + /// + /// A that contains the event data. + protected override void OnPaint(PaintEventArgs e) + { + if (!_isDisposed && mRenderer != null) + mRenderer.Render(e.Graphics); + rendererNeedsPaint = false; + } + + + /// + /// Handles the MouseDown event. + /// + /// A that contains the event data. + protected override void OnMouseDown(MouseEventArgs e) + { + // Capture focus if right clicked + if (!Focused && (e.Button & MouseButtons.Right) == MouseButtons.Right) + Focus(); + + navigationManager.MouseDown(e); + + // hide tooltip + HideItemTooltip(); + + base.OnMouseDown(e); + } + + /// + /// Handles the MouseUp event. + /// + /// A that contains the event data. + protected override void OnMouseUp(MouseEventArgs e) + { + navigationManager.MouseUp(e); + base.OnMouseUp(e); + } + + /// + /// Handles the MouseMove event. + /// + /// A that contains the event data. + protected override void OnMouseMove(MouseEventArgs e) + { + navigationManager.MouseMove(e); + base.OnMouseMove(e); + } + + /// + /// Handles the MouseWheel event. + /// + /// A that contains the event data. + protected override void OnMouseWheel(MouseEventArgs e) + { + SuspendPaint(); + + var speed = e.Delta / (100f + Math.Abs(e.Delta)); + + if (ScrollOrientation == ScrollOrientation.VerticalScroll) + { + int newYOffset = mViewOffset.Y - (int)(speed * vScrollBar.SmallChange); + if (newYOffset > vScrollBar.Maximum - vScrollBar.LargeChange + 1) + newYOffset = vScrollBar.Maximum - vScrollBar.LargeChange + 1; + if (newYOffset < 0) + newYOffset = 0; + if (newYOffset < vScrollBar.Minimum) + newYOffset = vScrollBar.Minimum; + if (newYOffset > vScrollBar.Maximum) + newYOffset = vScrollBar.Maximum; + + mViewOffset.Y = newYOffset; + vScrollBar.Value = newYOffset; + } + else + { + int newXOffset = mViewOffset.X - (int)(speed * hScrollBar.SmallChange); + if (newXOffset > hScrollBar.Maximum - hScrollBar.LargeChange + 1) + newXOffset = hScrollBar.Maximum - hScrollBar.LargeChange + 1; + if (newXOffset < 0) + newXOffset = 0; + if (newXOffset < hScrollBar.Minimum) + newXOffset = hScrollBar.Minimum; + if (newXOffset > hScrollBar.Maximum) + newXOffset = hScrollBar.Maximum; + + mViewOffset.X = newXOffset; + hScrollBar.Value = newXOffset; + } + + OnMouseMove(e); + Refresh(true); + ResumePaint(); + + base.OnMouseWheel(e); + } + + /// + /// Handles the MouseLeave event. + /// + /// An that contains the event data. + protected override void OnMouseLeave(EventArgs e) + { + HideItemTooltip(); + + navigationManager.MouseLeave(); + base.OnMouseLeave(e); + } + + /// + /// Handles the MouseDoubleClick event. + /// + /// An that contains the event data. + protected override void OnMouseDoubleClick(MouseEventArgs e) + { + navigationManager.MouseDoubleClick(e); + base.OnMouseDoubleClick(e); + } + + /// + /// Handles the IsInputKey event. + /// + /// One of the values. + /// + /// true if the specified key is a regular input key; otherwise, false. + /// + protected override bool IsInputKey(Keys keyData) + { + if ((keyData & Keys.Left) == Keys.Left || (keyData & Keys.Right) == Keys.Right || (keyData & Keys.Up) == Keys.Up || (keyData & Keys.Down) == Keys.Down) + return true; + else + return base.IsInputKey(keyData); + } + + /// + /// Handles the KeyDown event. + /// + /// A that contains the event data. + protected override void OnKeyDown(KeyEventArgs e) + { + navigationManager.KeyDown(e); + base.OnKeyDown(e); + } + + /// + /// Handles the KeyUp event. + /// + /// A that contains the event data. + protected override void OnKeyUp(KeyEventArgs e) + { + navigationManager.KeyUp(e); + base.OnKeyUp(e); + } + + /// + /// Handles the GotFocus event. + /// + /// An that contains the event data. + protected override void OnGotFocus(EventArgs e) + { + base.OnGotFocus(e); + Refresh(); + } + + /// + /// Handles the LostFocus event. + /// + /// An that contains the event data. + protected override void OnLostFocus(EventArgs e) + { + base.OnLostFocus(e); + Refresh(); + } + + /// + /// Releases the unmanaged resources used by the control and its child controls + /// and optionally releases the managed resources. + /// + /// true to release both managed and unmanaged resources; + /// false to release only unmanaged resources. + protected override void Dispose(bool disposing) + { + if (!_isDisposed) + { + if (disposing) + { + // Events + hScrollBar.Scroll -= HScrollBar_Scroll; + vScrollBar.Scroll -= VScrollBar_Scroll; + lazyRefreshTimer.Elapsed -= LazyRefreshTimer_Tick; + + // Resources + if (mDefaultImage != null) + mDefaultImage.Dispose(); + if (mErrorImage != null) + mErrorImage.Dispose(); + + // Child controls + if (hScrollBar != null && hScrollBar.IsHandleCreated && !hScrollBar.IsDisposed) + hScrollBar.Dispose(); + if (vScrollBar != null && vScrollBar.IsHandleCreated && !vScrollBar.IsDisposed) + vScrollBar.Dispose(); + + mTooltip?.Dispose(); + _tooltipTokenSrc.Dispose(); + lazyRefreshTimer?.Dispose(); + + // internal classes + defaultAdaptor?.Dispose(); + thumbnailCache?.Dispose(); + shellInfoCache?.Dispose(); + navigationManager?.Dispose(); + mRenderer?.Dispose(); + } + + _isDisposed = true; + } + + if (IsHandleCreated && !IsDisposed && !InvokeRequired) + base.Dispose(disposing); + } + #endregion + + + #region Virtual Functions + /// + /// Raises the CacheError event. + /// + /// A CacheErrorEventArgs that contains event data. + protected virtual void OnCacheError(CacheErrorEventArgs e) + { + CacheError?.Invoke(this, e); + } + + /// + /// Raises the DropFiles event. + /// + /// A DropFileEventArgs that contains event data. + protected virtual void OnDropFiles(DropFileEventArgs e) + { + DropFiles?.Invoke(this, e); + + if (e.Cancel) + return; + + int index = e.Index; + int firstItemIndex = 0; + mSelectedItems.Clear(false); + + // Add items + bool first = true; + var items = new List(); + + foreach (string filename in e.FileNames) + { + var item = new ImageGalleryItem(filename); + if (first || MultiSelect) + { + item.mSelected = true; + first = false; + } + + if (mItems.InsertInternal(index, item, defaultAdaptor)) + { + if (firstItemIndex == 0) + firstItemIndex = item.Index; + + items.Add(item); + index++; + } + } + + ScrollToIndex(firstItemIndex); + OnSelectionChangedInternal(); + + OnDropComplete(new DropCompleteEventArgs(items.ToArray(), false)); + } + + /// + /// Raises the DropItems event. + /// + /// A DropItemEventArgs that contains event data. + protected virtual void OnDropItems(DropItemEventArgs e) + { + DropItems?.Invoke(this, e); + + if (e.Cancel) + return; + + int index = e.Index; + mSelectedItems.Clear(false); + + foreach (var item in e.Items) + { + if (item.Index < index) index--; + Items.RemoveInternal(item, false); + } + + if (index < 0) index = 0; + if (index > Items.Count) index = Items.Count; + + // Add items + bool first = true; + var items = new List(); + + foreach (var item in e.Items) + { + if (first || MultiSelect) + { + item.mSelected = true; + first = false; + } + + if (Items.InsertInternal(index, item, item.Adaptor)) + { + items.Add(item); + index++; + } + } + + OnSelectionChangedInternal(); + + OnDropComplete(new DropCompleteEventArgs(items.ToArray(), true)); + } + + /// + /// Raises the DropComplete event. + /// + /// A DropCompleteEventArgs that contains event data. + protected virtual void OnDropComplete(DropCompleteEventArgs e) + { + DropComplete?.Invoke(this, e); + } + + /// + /// Raises the ItemClick event. + /// + /// A ItemClickEventArgs that contains event data. + protected virtual void OnItemClick(ItemClickEventArgs e) + { + if (layoutManager.IsItemPartialyVisible(e.Item.Index)) + { + ScrollToIndex(e.Item.Index); + } + + ItemClick?.Invoke(this, e); + } + + /// + /// Raises the ItemCheckBoxClick event. + /// + /// A ItemEventArgs that contains event data. + protected virtual void OnItemCheckBoxClick(ItemEventArgs e) + { + ItemCheckBoxClick?.Invoke(this, e); + } + + /// + /// Raises the ItemCheckBoxClick event. + /// + /// The checked item. + internal virtual void OnItemCheckBoxClickInternal(ImageGalleryItem item) + { + OnItemCheckBoxClick(new ItemEventArgs(item)); + } + + /// + /// Raises the ItemHover event. + /// + /// A ItemClickEventArgs that contains event data. + protected virtual void OnItemHover(ItemHoverEventArgs e) + { + ItemHover?.Invoke(this, e); + + // Tooltip + ShowItemTooltip(e.Item); + } + + /// + /// Raises the ItemDoubleClick event. + /// + /// A ItemClickEventArgs that contains event data. + protected virtual void OnItemDoubleClick(ItemClickEventArgs e) + { + ItemDoubleClick?.Invoke(this, e); + } + + /// + /// Raises the SelectionChanged event. + /// + /// A EventArgs that contains event data. + protected virtual void OnSelectionChanged(EventArgs e) + { + SelectionChanged?.Invoke(this, e); + } + + /// + /// Raises the SelectionChanged event. + /// + internal void OnSelectionChangedInternal() + { + OnSelectionChanged(new EventArgs()); + } + + /// + /// Raises the ThumbnailCached event. + /// + /// A ThumbnailCachedEventArgs that contains event data. + protected virtual void OnThumbnailCached(ThumbnailCachedEventArgs e) + { + ThumbnailCached?.Invoke(this, e); + } + + /// + /// Raises the DetailsCaching event. + /// + /// An ItemEventArgs that contains event data. + protected virtual void OnDetailsCaching(ItemEventArgs e) + { + DetailsCaching?.Invoke(this, e); + } + + /// + /// Raises the DetailsCached event. + /// + /// An ItemEventArgs that contains event data. + protected virtual void OnDetailsCached(ItemEventArgs e) + { + DetailsCached?.Invoke(this, e); + } + + /// + /// Raises the DetailsCaching event. + /// This method is invoked from the thumbnail thread. + /// + internal virtual void OnDetailsCachingInternal(Guid guid) + { + if (mItems.TryGetValue(guid, out ImageGalleryItem? item)) + OnDetailsCaching(new ItemEventArgs(item)); + } + + /// + /// Raises the DetailsCached event. + /// This method is invoked from the thumbnail thread. + /// + internal virtual void OnDetailsCachedInternal(Guid guid) + { + if (mItems.TryGetValue(guid, out ImageGalleryItem? item)) + OnDetailsCached(new ItemEventArgs(item)); + } + + /// + /// Raises the ShellInfoCaching event. + /// + /// A ShellInfoCachingEventArgs that contains event data. + protected internal virtual void OnShellInfoCaching(ShellInfoCachingEventArgs e) + { + ShellInfoCaching?.Invoke(this, e); + } + + /// + /// Raises the ShellInfoCached event. + /// + /// A ShellInfoCachedEventArgs that contains event data. + protected internal virtual void OnShellInfoCached(ShellInfoCachedEventArgs e) + { + ShellInfoCached?.Invoke(this, e); + } + + /// + /// Raises the CacheError event. + /// This method is invoked from the thumbnail thread. + /// + /// The Guid of the that is associated with this error. + /// This parameter can be null. + /// The error that occurred during an asynchronous operation. + /// The thread raising the error. + internal void OnCacheErrorInternal(Guid guid, Exception error, CacheThread cacheThread) + { + mItems.TryGetValue(guid, out ImageGalleryItem? item); + OnCacheError(new CacheErrorEventArgs(item, error, cacheThread)); + } + + /// + /// Raises the CacheError event. + /// This method is invoked from the thumbnail thread. + /// + /// The error that occurred during an asynchronous operation. + /// The thread raising the error. + internal void OnCacheErrorInternal(Exception error, CacheThread cacheThread) + { + OnCacheError(new CacheErrorEventArgs(null, error, cacheThread)); + } + + /// + /// Raises the ThumbnailCached event. + /// This method is invoked from the thumbnail thread. + /// + /// The guid of the item whose thumbnail is cached. + /// The cached image. + /// Requested thumbnail size. + /// true if the cached image is a thumbnail image; otherwise false + /// if the image is a large image for gallery or pane views. + internal void OnThumbnailCachedInternal(Guid guid, Image? thumbnail, Size size, bool thumbnailImage) + { + if (mItems.TryGetValue(guid, out ImageGalleryItem? item)) + OnThumbnailCached(new ThumbnailCachedEventArgs(item, thumbnail, size, thumbnailImage)); + } + + /// + /// Raises the ThumbnailCaching event. + /// This method is invoked from the thumbnail thread. + /// + /// The guid of the item whose thumbnail is cached. + /// Requested thumbnail size. + internal void OnThumbnailCachingInternal(Guid guid, Size size) + { + if (mItems.TryGetValue(guid, out ImageGalleryItem? item)) + OnThumbnailCaching(new ThumbnailCachingEventArgs(item, size)); + } + + /// + /// Raises the ThumbnailCaching event. + /// + /// A ThumbnailCachingEventArgs that contains event data. + protected virtual void OnThumbnailCaching(ThumbnailCachingEventArgs e) + { + ThumbnailCaching?.Invoke(this, e); + } + + /// + /// Raises the ItemCollectionChanged event. + /// + /// A ItemCollectionChangedEventArgs that contains event data. + protected virtual void OnItemCollectionChanged(ItemCollectionChangedEventArgs e) + { + ItemCollectionChanged?.Invoke(this, e); + } + + #endregion + + + #region Public Events + + /// + /// Occurs when an error occurs during an asynchronous cache operation. + /// + [Category("Behavior")] + public event CacheErrorEventHandler? CacheError; + + /// + /// Occurs after the user drops files on to the control. + /// + [Category("Drag Drop")] + public event DropFilesEventHandler? DropFiles; + + /// + /// Occurs after the user drops items on to the control. + /// + [Category("Drag Drop")] + public event DropItemsEventHandler? DropItems; + + /// + /// Occurs after items are dropped successfully. + /// + [Category("Drag Drop")] + public event DropCompleteEventHandler? DropComplete; + + /// + /// Occurs when the user clicks an item. + /// + [Category("Action")] + public event ItemClickEventHandler? ItemClick; + + /// + /// Occurs when the user clicks an item checkbox. + /// + [Category("Action")] + public event ItemCheckBoxClickEventHandler? ItemCheckBoxClick; + + /// + /// Occurs when the user moves the mouse over (and out of) an item. + /// + [Category("Action")] + public event ItemHoverEventHandler? ItemHover; + + /// + /// Occurs when the user double-clicks an item. + /// + [Category("Action")] + public event ItemDoubleClickEventHandler? ItemDoubleClick; + + /// + /// Occurs when the selected items collection changes. + /// + [Category("Behavior")] + public event EventHandler? SelectionChanged; + + /// + /// Occurs after an item thumbnail is cached. + /// + [Category("Behavior")] + public event ThumbnailCachedEventHandler? ThumbnailCached; + + /// + /// Occurs before an item thumbnail is cached. + /// + [Category("Behavior")] + public event ThumbnailCachingEventHandler? ThumbnailCaching; + + /// + /// Occurs after the item collection is changed. + /// + [Category("Behavior")] + public event ItemCollectionChangedEventHandler? ItemCollectionChanged; + + /// + /// Occurs before an item details is cached. + /// + [Category("Behavior")] + public event DetailsCachingEventHandler? DetailsCaching; + + /// + /// Occurs after an item details is cached. + /// + [Category("Behavior")] + public event DetailsCachedEventHandler? DetailsCached; + + /// + /// Occurs before shell info for a file extension is cached. + /// + [Category("Behavior")] + public event ShellInfoCachingEventHandler? ShellInfoCaching; + + /// + /// Occurs after shell info for a file extension is cached. + /// + [Category("Behavior")] + public event ShellInfoCachedEventHandler? ShellInfoCached; + + /// + /// Occurs before the tooltip is shown. + /// + [Category("Behavior")] + public event EventHandler? ItemTooltipShowing; + + /// + /// Occurs when is resized by . + /// + [Category("Behavior")] + public event EventHandler? ResizedByResizer; + + #endregion +} + + + diff --git a/Source/Components/ImageGlass.Gallery/ImageGlass.Gallery.csproj b/Source/Components/ImageGlass.Gallery/ImageGlass.Gallery.csproj new file mode 100644 index 000000000..d713172c4 --- /dev/null +++ b/Source/Components/ImageGlass.Gallery/ImageGlass.Gallery.csproj @@ -0,0 +1,70 @@ + + + + net10.0-windows10.0.17763.0 + enable + true + enable + 9.4.0.1120 + $(Version) + Copyright © 2010 - 2026 Duong Dieu Phap + x64;ARM64 + Debug;Release;Publish_Release + latest + en + + + + embedded + + + + embedded + + + + embedded + + + + embedded + + + + embedded + + + + embedded + + + + embedded + + + + embedded + + + + embedded + + + + embedded + + + + embedded + + + + embedded + + + + + + + + diff --git a/Source/Components/ImageGlass.Gallery/Item/Adaptor/FileSystemAdaptor.cs b/Source/Components/ImageGlass.Gallery/Item/Adaptor/FileSystemAdaptor.cs new file mode 100644 index 000000000..8e61909e7 --- /dev/null +++ b/Source/Components/ImageGlass.Gallery/Item/Adaptor/FileSystemAdaptor.cs @@ -0,0 +1,131 @@ +/* +ImageGlass Project - Image viewer for Windows +Copyright (C) 2010 - 2026 DUONG DIEU PHAP +Project homepage: https://imageglass.org + +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 . + +--------------------- +ImageGlass.Gallery is based on ImageListView v13.8.2: +Url: https://github.com/oozcitak/imagelistview +License: Apache License Version 2.0, http://www.apache.org/licenses/ +--------------------- +*/ +using Cysharp.Text; +using ImageGlass.Base.Cache; +using ImageGlass.Base.Photoing.Codecs; +using System.Text; + +namespace ImageGlass.Gallery; + + +/// +/// Represents a file system adaptor. +/// +public class FileSystemAdaptor : IAdaptor +{ + // Use a cache for commonly repeated strings + private static readonly StringCache _stringCache = new(); + + private bool _isDisposed = false; + + /// + /// Initializes a new instance of the class. + /// + public FileSystemAdaptor() { } + + /// + /// Returns the thumbnail image for the given item. + /// + /// Item key. + /// Requested image size. + /// Embedded thumbnail usage. + /// true to automatically rotate images based on Exif orientation; otherwise false. + /// The thumbnail image from the given item or null if an error occurs. + public override Image? GetThumbnail(string filePath, Size size, UseEmbeddedThumbnails useEmbeddedThumbnails, bool useExifOrientation) + { + if (_isDisposed) return null; + + + try + { + return Extractor.Current.GetThumbnail(filePath, size, useEmbeddedThumbnails, useExifOrientation); + } + catch (Exception) + { + return null; + } + } + + /// + /// Returns a unique identifier for this thumbnail to be used in persistent + /// caching. + /// + /// Item key. + /// Requested image size. + /// Embedded thumbnail usage. + /// true to automatically rotate images based on Exif orientation; otherwise false. + /// A unique identifier string for the thumnail. + public override string GetUniqueIdentifier(string filePath, Size size, UseEmbeddedThumbnails useEmbeddedThumbnails, bool useExifOrientation) + { + var fi = new FileInfo(filePath); + using var sb = ZString.CreateStringBuilder(); + + sb.Append(filePath); + sb.Append(':'); + sb.Append(fi.LastWriteTimeUtc.ToBinary()); + sb.Append(':'); + sb.Append(size.Width); // Thumbnail size + sb.Append(','); + sb.Append(size.Height); + sb.Append(':'); + sb.Append(useEmbeddedThumbnails); + sb.Append(':'); + sb.Append(useExifOrientation); + + return sb.ToString(); + } + + /// + /// Returns the path to the source image for use in drag operations. + /// + /// Item key. + /// The path to the source image. + public override string GetSourceImage(string filePath) + { + if (_isDisposed) return string.Empty; + + return filePath; + } + + /// + /// Returns the details for the given item. + /// + /// Item key. + /// An array of tuples containing item details or null if an error occurs. + public override IgMetadata GetDetails(string filePath) + { + if (_isDisposed) return new IgMetadata(); + + return PhotoCodec.LoadMetadata(filePath); + } + + /// + /// Performs application-defined tasks associated with freeing, + /// releasing, or resetting unmanaged resources. + /// + public override void Dispose() => _isDisposed = true; + +} + diff --git a/Source/Components/ImageGlass.Gallery/Item/Adaptor/IAdaptor.cs b/Source/Components/ImageGlass.Gallery/Item/Adaptor/IAdaptor.cs new file mode 100644 index 000000000..687e4be5e --- /dev/null +++ b/Source/Components/ImageGlass.Gallery/Item/Adaptor/IAdaptor.cs @@ -0,0 +1,79 @@ +/* +ImageGlass Project - Image viewer for Windows +Copyright (C) 2010 - 2026 DUONG DIEU PHAP +Project homepage: https://imageglass.org + +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 . + +--------------------- +ImageGlass.Gallery is based on ImageListView v13.8.2: +Url: https://github.com/oozcitak/imagelistview +License: Apache License Version 2.0, http://www.apache.org/licenses/ +--------------------- +*/ +using ImageGlass.Base.Photoing.Codecs; + +namespace ImageGlass.Gallery; + + +/// +/// Represents the abstract case class for adaptors. +/// +public abstract class IAdaptor : IDisposable +{ + #region Abstract Methods + + /// + /// Returns the thumbnail image for the given item. + /// + /// Item file path. + /// Requested image size. + /// Embedded thumbnail usage. + /// true to automatically rotate images based on Exif orientation; otherwise false. + /// The thumbnail image from the given item or null if an error occurs. + public abstract Image? GetThumbnail(string filePath, Size size, UseEmbeddedThumbnails useEmbeddedThumbnails, bool useExifOrientation); + + /// + /// Returns a unique identifier for this thumbnail to be used in persistent + /// caching. + /// + /// Item file path. + /// Requested image size. + /// Embedded thumbnail usage. + /// true to automatically rotate images based on Exif orientation; otherwise false. + /// A unique identifier string for the thumnail. + public abstract string GetUniqueIdentifier(string filePath, Size size, UseEmbeddedThumbnails useEmbeddedThumbnails, bool useExifOrientation); + + /// + /// Returns the path to the source image for use in drag operations. + /// + /// Item file path. + /// The path to the source image. + public abstract string GetSourceImage(string filePath); + + /// + /// Returns the details for the given item. + /// + /// Item file path. + public abstract IgMetadata GetDetails(string filePath); + + /// + /// Performs application-defined tasks associated with freeing, + /// releasing, or resetting unmanaged resources. + /// + public abstract void Dispose(); + + #endregion +} + diff --git a/Source/Components/ImageGlass.Gallery/Item/CheckedItemCollection.cs b/Source/Components/ImageGlass.Gallery/Item/CheckedItemCollection.cs new file mode 100644 index 000000000..aa79eef19 --- /dev/null +++ b/Source/Components/ImageGlass.Gallery/Item/CheckedItemCollection.cs @@ -0,0 +1,355 @@ +/* +ImageGlass Project - Image viewer for Windows +Copyright (C) 2010 - 2026 DUONG DIEU PHAP +Project homepage: https://imageglass.org + +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 . + +--------------------- +ImageGlass.Gallery is based on ImageListView v13.8.2: +Url: https://github.com/oozcitak/imagelistview +License: Apache License Version 2.0, http://www.apache.org/licenses/ +--------------------- +*/ +using System.Collections; +using System.ComponentModel; + +namespace ImageGlass.Gallery; + +public partial class ImageGallery +{ + + /// + /// Represents the collection of checked items in the image list view. + /// + public class CheckedItemCollection : IList + { + #region Member Variables + internal ImageGallery _imageGallery; + #endregion + + #region Constructors + /// + /// Initializes a new instance of the class. + /// + /// The owning this collection. + internal CheckedItemCollection(ImageGallery owner) + { + _imageGallery = owner; + } + #endregion + + #region Properties + + /// + /// Gets the number of elements contained in the . + /// + [Category("Behavior"), Browsable(true), Description("Gets the number of elements contained in the collection.")] + public int Count + { + get + { + int count = 0; + foreach (ImageGalleryItem item in _imageGallery.Items) + if (item.Checked) count++; + return count; + } + } /// + /// Gets a value indicating whether the is read-only. + /// + [Category("Behavior"), Browsable(false), Description("Gets a value indicating whether the collection is read-only.")] + public bool IsReadOnly => true; + + /// + /// Gets the owning this collection. + /// + [Category("Behavior"), Browsable(false), Description("Gets the ImageGallery owning this collection.")] + public ImageGallery ImageGalleryOwner => _imageGallery; + + /// + /// Gets or sets the at the specified index. + /// + [Category("Behavior"), Browsable(false), Description("Gets or sets the item at the specified index")] + public ImageGalleryItem this[int index] + { + get + { + int i = 0; + foreach (ImageGalleryItem item in this) + { + if (i == index) + return item; + i++; + } + throw new ArgumentException("No item with the given index exists.", nameof(index)); + } + } + + #endregion + + #region Instance Methods + + /// + /// Determines whether the contains a specific value. + /// + /// The to locate + /// in the . + /// + /// true if is found in the + /// ; otherwise, false. + /// + public bool Contains(ImageGalleryItem item) + { + return item.Checked && _imageGallery.Items.Contains(item); + } + + /// + /// Returns an enumerator that iterates through the collection. + /// + /// + /// A that can be used to iterate through the collection. + /// + public IEnumerator GetEnumerator() + { + return new CheckedItemEnumerator(_imageGallery.Items); + } + + #endregion + + #region Helper Methods + /// + /// Removes all items from the collection. + /// + internal void Clear() + { + Clear(true); + } + + /// + /// Removes all items from the collection. + /// + internal void Clear(bool raiseEvent) + { + foreach (ImageGalleryItem item in this) + { + item.mChecked = false; + if (raiseEvent && _imageGallery != null) + _imageGallery.OnItemCheckBoxClickInternal(item); + } + } + + #endregion + + + #region Unsupported Interface + /// + /// Adds an item to the . + /// + /// The object to add to the . + /// + /// The is read-only. + /// + void ICollection.Add(ImageGalleryItem item) + { + throw new NotSupportedException(); + } + /// + /// Removes all items from the . + /// + void ICollection.Clear() + { + throw new NotSupportedException(); + } + /// + /// Copies the elements of the to an , starting at a particular index. + /// + /// The one-dimensional that is the destination of the elements copied from . The must have zero-based indexing. + /// The zero-based index in at which copying begins. + void ICollection.CopyTo(ImageGalleryItem[] array, int arrayIndex) + { + throw new NotSupportedException(); + } + /// + /// Determines the index of a specific item in the . + /// + /// The object to locate in the . + /// + /// The index of if found in the list; otherwise, -1. + /// + [Obsolete("Use ImageGallleryItem.Index property instead.")] + int IList.IndexOf(ImageGalleryItem item) + { + throw new NotSupportedException(); + } + /// + /// Inserts an item to the at the specified index. + /// + /// The zero-based index at which should be inserted. + /// The object to insert into the . + void IList.Insert(int index, ImageGalleryItem item) + { + throw new NotSupportedException(); + } + /// + /// Removes the first occurrence of a specific object from the . + /// + /// The object to remove from the . + /// + /// true if was successfully removed from the ; otherwise, false. This method also returns false if is not found in the original . + /// + bool ICollection.Remove(ImageGalleryItem item) + { + throw new NotSupportedException(); + } + /// + /// Removes the item at the specified index. + /// + /// The zero-based index of the item to remove. + void IList.RemoveAt(int index) + { + throw new NotSupportedException(); + } + /// + /// Gets or sets the item at the specified index. + /// + ImageGalleryItem IList.this[int index] + { + get + { + throw new NotSupportedException(); + } + set + { + throw new NotSupportedException(); + } + } + /// + /// Returns an enumerator that iterates through a collection. + /// + /// + /// An object that can be used to iterate through the collection. + /// + System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + #endregion + + + #region Internal Classes + /// + /// Represents an enumerator to walk though the checked items. + /// + internal class CheckedItemEnumerator : IEnumerator + { + #region Member Variables + private ItemCollection owner; + private int current; + private Guid lastItem; + #endregion + + #region Constructor + + public CheckedItemEnumerator(ItemCollection collection) + { + owner = collection; + current = -1; + lastItem = Guid.Empty; + } + #endregion + + #region Properties + + /// + /// Gets the element in the collection at the current position of the enumerator. + /// + public ImageGalleryItem Current + { + get + { + if (current == -1 || current > owner.Count - 1) + throw new InvalidOperationException(); + return owner[current]; + } + } + + /// + /// Gets the element in the collection at the current position of the enumerator. + /// + object IEnumerator.Current + { + get { return Current; } + } + + #endregion + + #region Instance Methods + /// + /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. + /// + public void Dispose() + { + ; + } + + /// + /// Advances the enumerator to the next element of the collection. + /// + public bool MoveNext() + { + // Did we reach the end? + if (current > owner.Count - 1) + { + lastItem = Guid.Empty; + return false; + } + + // Move to the next item if: + // 1. We are before the first item. - OR - + // 2. The current item is the same as the one we enumerated before. + // The current item may have differed if the user for example + // removed the current item between MoveNext calls. - OR - + // 3. The current item is not checked. + while (current == -1 || + owner[current].Guid == lastItem || + owner[current].Checked == false) + { + current++; + if (current > owner.Count - 1) + { + lastItem = Guid.Empty; + return false; + } + } + + // Cache the last item + lastItem = owner[current].Guid; + return true; + } + + /// + /// Sets the enumerator to its initial position, which is before the first element in the collection. + /// + public void Reset() + { + current = -1; + lastItem = Guid.Empty; + } + + #endregion + } + #endregion + } + +} diff --git a/Source/Components/ImageGlass.Gallery/Item/ImageGalleryItem.cs b/Source/Components/ImageGlass.Gallery/Item/ImageGalleryItem.cs new file mode 100644 index 000000000..271f0f14b --- /dev/null +++ b/Source/Components/ImageGlass.Gallery/Item/ImageGalleryItem.cs @@ -0,0 +1,653 @@ +/* +ImageGlass Project - Image viewer for Windows +Copyright (C) 2010 - 2026 DUONG DIEU PHAP +Project homepage: https://imageglass.org + +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 . + +--------------------- +ImageGlass.Gallery is based on ImageListView v13.8.2: +Url: https://github.com/oozcitak/imagelistview +License: Apache License Version 2.0, http://www.apache.org/licenses/ +--------------------- +*/ + +using ImageGlass.Base.Cache; +using ImageGlass.Base.Photoing.Codecs; +using System.ComponentModel; +using static ImageGlass.Gallery.ImageGallery; + +namespace ImageGlass.Gallery; + +/// +/// Represents an item in the image list view. +/// +public class ImageGalleryItem : ICloneable +{ + #region Member Variables + + private static readonly StringCache _stringCache = new(); + + // Property backing fields + internal int mIndex = -1; + internal bool mChecked = false; + internal bool mSelected = false; + internal bool mPressed = false; + internal bool mEnabled = true; + private string mText = string.Empty; + private int mZOrder = 0; + + // File info + private IgMetadata? _details = null; + internal string extension = string.Empty; + internal string mFilePath = string.Empty; + + // Adaptor + internal string mVirtualKey; + internal IAdaptor? mAdaptor = null; + + // Used for cloned items + internal Image? clonedThumbnail; + + internal ItemCollection? owner = null; + internal bool isDirty = true; + #endregion + + + #region Properties + /// + /// Gets the cache state of the item thumbnail. + /// + [Category("Behavior"), Browsable(false)] + public CacheState ThumbnailCacheState + { + get + { + if (ImageGalleryOwner is null) + { + return CacheState.Unknown; + } + + return ImageGalleryOwner.thumbnailCache.GetCacheState( + Guid, + ImageGalleryOwner.ThumbnailSize, + ImageGalleryOwner.UseEmbeddedThumbnails, + ImageGalleryOwner.AutoRotateThumbnails); + } + } + /// + /// Gets a value determining if the item is focused. + /// + [Category("Appearance"), Browsable(false)] + public bool Focused + { + get + { + if (owner == null || owner.FocusedItem == null) return false; + return (this == owner.FocusedItem); + } + set + { + if (owner != null) + owner.FocusedItem = this; + } + } + /// + /// Gets a value determining if the item is enabled. + /// + [Category("Appearance")] + public bool Enabled + { + get => mEnabled; + set + { + mEnabled = value; + if (!mEnabled && mSelected) + { + mSelected = false; + if (ImageGalleryOwner != null) + ImageGalleryOwner.OnSelectionChangedInternal(); + } + if (ImageGalleryOwner != null && ImageGalleryOwner.IsItemVisible(Guid)) + ImageGalleryOwner.Refresh(); + } + } + + /// + /// Gets image details. + /// + [Browsable(false)] + public IgMetadata Details + { + get + { + if (_details is null) + { + UpdateDetails(); + } + + return _details ?? new(); + } + } + + /// + /// Gets the unique identifier for this item. + /// + [Category("Behavior"), Browsable(false)] + internal Guid Guid { get; private set; } = Guid.NewGuid(); + + /// + /// Gets the adaptor of this item. + /// + [Category("Behavior"), Browsable(false)] + public IAdaptor? Adaptor => mAdaptor; + + /// + /// Gets the virtual item key associated with this item. + /// + [Category("Behavior"), Browsable(false)] + public string VirtualKey => mVirtualKey; + + /// + /// Gets the ImageListView owning this item. + /// + [Category("Behavior"), Browsable(false)] + public ImageGallery? ImageGalleryOwner { get; internal set; } = null; + + /// + /// Gets the index of the item. + /// + [Category("Behavior"), Browsable(false), EditorBrowsable(EditorBrowsableState.Advanced)] + public int Index => mIndex; + + /// + /// Gets or sets a value determining if the item is checked. + /// + [Category("Appearance"), DefaultValue(false)] + public bool Checked + { + get => mChecked; + set + { + if (value != mChecked) + { + mChecked = value; + if (ImageGalleryOwner != null) + ImageGalleryOwner.OnItemCheckBoxClickInternal(this); + } + } + } + + /// + /// Gets or sets a value determining if the item is selected. + /// + [Category("Appearance"), Browsable(false), DefaultValue(false)] + public bool Selected + { + get => mSelected; + set + { + if (value != mSelected && mEnabled) + { + mSelected = value; + if (ImageGalleryOwner != null) + { + ImageGalleryOwner.OnSelectionChangedInternal(); + if (ImageGalleryOwner.IsItemVisible(Guid)) + ImageGalleryOwner.Refresh(); + } + } + } + } + + /// + /// Gets or sets a value determining if the item is pressed. + /// + public bool Pressed + { + get => mPressed; + set + { + if (value != mPressed && mEnabled) + { + mPressed = value; + if (ImageGalleryOwner != null) + { + if (ImageGalleryOwner.IsItemVisible(Guid)) + ImageGalleryOwner.Refresh(); + } + } + } + } + + /// + /// Gets or sets the user-defined data associated with the item. + /// + [Category("Data"), TypeConverter(typeof(StringConverter))] + public object? Tag { get; set; } = null; + + /// + /// Gets or sets the text associated with this item. If left blank, item Text + /// reverts to the name of the image file. + /// + [Category("Appearance")] + public string Text + { + get => mText; + set + { + mText = value; + if (ImageGalleryOwner != null && ImageGalleryOwner.IsItemVisible(Guid)) + ImageGalleryOwner.Refresh(); + } + } + + /// + /// Gets or sets the file path of the image file represented by this item. + /// + [Category("File Properties")] + public string FilePath + { + get => mFilePath; + set + { + if (string.IsNullOrEmpty(value)) + throw new ArgumentException("File path cannot be null"); + + if (mFilePath != value) + { + mFilePath = value; + mVirtualKey = mFilePath; + extension = _stringCache.GetFromCache(Path.GetExtension(mFilePath)); + + isDirty = true; + if (ImageGalleryOwner != null) + { + ImageGalleryOwner.thumbnailCache.Remove(Guid, true); + + if (ImageGalleryOwner.IsItemVisible(Guid)) + ImageGalleryOwner.Refresh(); + } + } + } + } + + /// + /// Gets the thumbnail image. If the thumbnail image is not cached, it will be + /// added to the cache queue and null will be returned. The returned image needs + /// to be disposed by the caller. + /// + [Category("Appearance"), Browsable(false)] + public Image? ThumbnailImage + { + get + { + if (ImageGalleryOwner == null) + throw new InvalidOperationException("Owner control is null."); + + if (ThumbnailCacheState != CacheState.Cached) + { + ImageGalleryOwner.thumbnailCache.Add(Guid, mAdaptor, mVirtualKey, ImageGalleryOwner.ThumbnailSize, + ImageGalleryOwner.UseEmbeddedThumbnails, ImageGalleryOwner.AutoRotateThumbnails); + } + + return ImageGalleryOwner.thumbnailCache.GetImage(Guid, mAdaptor, mVirtualKey, ImageGalleryOwner.ThumbnailSize, ImageGalleryOwner.UseEmbeddedThumbnails, + ImageGalleryOwner.AutoRotateThumbnails, true); + } + } + + /// + /// Gets or sets the draw order of the item. + /// + [Category("Appearance"), DefaultValue(0)] + public int ZOrder + { + get => mZOrder; set + { + mZOrder = value; + } + } + + #endregion + + + #region Shell Properties + /// + /// Gets the small shell icon of the image file represented by this item. + /// If the icon image is not cached, it will be added to the cache queue and null will be returned. + /// + [Category("Appearance"), Browsable(false)] + public Image? SmallIcon + { + get + { + if (ImageGalleryOwner == null) + throw new InvalidOperationException("Owner control is null."); + + var iconPath = PathForShellIcon(); + var state = ImageGalleryOwner.shellInfoCache.GetCacheState(iconPath); + if (state == CacheState.Cached) + { + return ImageGalleryOwner.shellInfoCache.GetSmallIcon(iconPath); + } + else if (state == CacheState.Error) + { + if (ImageGalleryOwner.RetryOnError) + { + ImageGalleryOwner.shellInfoCache.Remove(iconPath); + ImageGalleryOwner.shellInfoCache.Add(iconPath); + } + return null; + } + else + { + ImageGalleryOwner.shellInfoCache.Add(iconPath); + return null; + } + } + } + + /// + /// Gets the large shell icon of the image file represented by this item. + /// If the icon image is not cached, it will be added to the cache queue and null will be returned. + /// + [Category("Appearance"), Browsable(false)] + public Image? LargeIcon + { + get + { + if (ImageGalleryOwner == null) + throw new InvalidOperationException("Owner control is null."); + + var iconPath = PathForShellIcon(); + var state = ImageGalleryOwner.shellInfoCache.GetCacheState(iconPath); + if (state == CacheState.Cached) + { + return ImageGalleryOwner.shellInfoCache.GetLargeIcon(iconPath); + } + else if (state == CacheState.Error) + { + if (ImageGalleryOwner.RetryOnError) + { + ImageGalleryOwner.shellInfoCache.Remove(iconPath); + ImageGalleryOwner.shellInfoCache.Add(iconPath); + } + return null; + } + else + { + ImageGalleryOwner.shellInfoCache.Add(iconPath); + return null; + } + } + } + + /// + /// Gets the shell type of the image file represented by this item. + /// + [Category("File Properties")] + public string FileType + { + get + { + if (ImageGalleryOwner == null) + throw new InvalidOperationException("Owner control is null."); + + var iconPath = PathForShellIcon(); + var state = ImageGalleryOwner.shellInfoCache.GetCacheState(iconPath); + if (state == CacheState.Cached) + { + return ImageGalleryOwner.shellInfoCache.GetFileType(iconPath); + } + else if (state == CacheState.Error) + { + if (ImageGalleryOwner.RetryOnError) + { + ImageGalleryOwner.shellInfoCache.Remove(iconPath); + ImageGalleryOwner.shellInfoCache.Add(iconPath); + } + return string.Empty; + } + else + { + ImageGalleryOwner.shellInfoCache.Add(iconPath); + return string.Empty; + } + } + } + + #endregion + + + #region Constructors + /// + /// Initializes a new instance of the class. + /// + /// The image filename representing the item. + /// Item text + public ImageGalleryItem(string filename, string text = "") + { + // important! to make it load faster using virtual items + mVirtualKey = filename; + + mFilePath = filename; + mText = string.IsNullOrEmpty(text) ? Path.GetFileName(filename) : text; + extension = _stringCache.GetFromCache(Path.GetExtension(filename)); + } + + #endregion + + + #region Helper Methods + + /// + /// Gets an image from the cache manager. + /// If the thumbnail image is not cached, it will be + /// added to the cache queue and DefaultImage of the owner image list view will + /// be returned. If the thumbnail could not be cached ErrorImage of the owner + /// image list view will be returned. + /// + /// Type of cached image to return. + /// Requested thumbnail or icon. + public Image? GetCachedImage(CachedImageType imageType) + { + if (ImageGalleryOwner == null) + throw new InvalidOperationException("Owner control is null."); + + string iconPath = PathForShellIcon(); + + if (imageType == CachedImageType.SmallIcon || imageType == CachedImageType.LargeIcon) + { + if (string.IsNullOrEmpty(iconPath)) + return ImageGalleryOwner.DefaultImage; + + CacheState state = ImageGalleryOwner.shellInfoCache.GetCacheState(iconPath); + if (state == CacheState.Cached) + { + if (imageType == CachedImageType.SmallIcon) + return ImageGalleryOwner.shellInfoCache.GetSmallIcon(iconPath); + else + return ImageGalleryOwner.shellInfoCache.GetLargeIcon(iconPath); + } + else if (state == CacheState.Error) + { + if (ImageGalleryOwner.RetryOnError) + { + ImageGalleryOwner.shellInfoCache.Remove(iconPath); + ImageGalleryOwner.shellInfoCache.Add(iconPath); + } + return ImageGalleryOwner.ErrorImage; + } + else + { + ImageGalleryOwner.shellInfoCache.Add(iconPath); + return ImageGalleryOwner.DefaultImage; + } + } + else + { + Image? img = null; + CacheState state = ThumbnailCacheState; + + if (state == CacheState.Error) + { + if (ImageGalleryOwner.ShellIconFallback && !string.IsNullOrEmpty(iconPath)) + { + CacheState iconstate = ImageGalleryOwner.shellInfoCache.GetCacheState(iconPath); + if (iconstate == CacheState.Cached) + { + if (ImageGalleryOwner.ThumbnailSize.Width > 32 && ImageGalleryOwner.ThumbnailSize.Height > 32) + img = ImageGalleryOwner.shellInfoCache.GetLargeIcon(iconPath); + else + img = ImageGalleryOwner.shellInfoCache.GetSmallIcon(iconPath); + } + else if (iconstate == CacheState.Error) + { + if (ImageGalleryOwner.RetryOnError) + { + ImageGalleryOwner.shellInfoCache.Remove(iconPath); + ImageGalleryOwner.shellInfoCache.Add(iconPath); + } + } + else + { + ImageGalleryOwner.shellInfoCache.Add(iconPath); + } + } + + if (img == null) + img = ImageGalleryOwner.ErrorImage; + return img; + } + + img = ImageGalleryOwner.thumbnailCache.GetImage(Guid, mAdaptor, mVirtualKey, ImageGalleryOwner.ThumbnailSize, ImageGalleryOwner.UseEmbeddedThumbnails, + ImageGalleryOwner.AutoRotateThumbnails, false); + + if (state == CacheState.Cached) + return img; + + ImageGalleryOwner.thumbnailCache.Add(Guid, mAdaptor, mVirtualKey, ImageGalleryOwner.ThumbnailSize, + ImageGalleryOwner.UseEmbeddedThumbnails, ImageGalleryOwner.AutoRotateThumbnails); + + if (img == null && string.IsNullOrEmpty(iconPath)) + return ImageGalleryOwner.DefaultImage; + + if (img == null && ImageGalleryOwner.ShellIconFallback && ImageGalleryOwner.ThumbnailSize.Width > 16 && ImageGalleryOwner.ThumbnailSize.Height > 16) + img = ImageGalleryOwner.shellInfoCache.GetLargeIcon(iconPath); + if (img == null && ImageGalleryOwner.ShellIconFallback) + img = ImageGalleryOwner.shellInfoCache.GetSmallIcon(iconPath); + if (img == null) + img = ImageGalleryOwner.DefaultImage; + + return img; + } + } + + /// + /// Fetch file info for the image file represented by this item, + /// then update the property. + /// + /// Force to fetch details from file. + public void UpdateDetails(bool force = false) + { + if (!isDirty + || Adaptor == null + || ImageGalleryOwner == null + || mVirtualKey == null) return; + + if (force || _details == null) + { + _details = Adaptor.GetDetails(mVirtualKey); + } + } + + /// + /// Removes the current thumbnail and requests to update it. + /// + public void UpdateThumbnail() + { + isDirty = true; + if (ImageGalleryOwner != null) + { + ImageGalleryOwner.thumbnailCache.Remove(Guid, true); + + if (ImageGalleryOwner.IsItemVisible(Guid)) + ImageGalleryOwner.Refresh(); + } + } + + /// + /// Updates file path of thumbnail and its related metadata. + /// + public void Rename(string newFilePath) + { + try + { + FilePath = newFilePath; + Text = Path.GetFileName(newFilePath); + UpdateDetails(true); + } + catch { } + } + + /// + /// Returns a path string to be used for extracting the shell icon + /// of the item. Returns the filename for icon files and executables, + /// file extension for other files. + /// + private string PathForShellIcon() + { + if (ImageGalleryOwner != null && ImageGalleryOwner.ShellIconFromFileContent && + (string.Compare(extension, ".ico", StringComparison.OrdinalIgnoreCase) == 0 || string.Compare(extension, ".exe", StringComparison.OrdinalIgnoreCase) == 0)) + return mFilePath; + else + return extension; + } + + #endregion + + + #region ICloneable Members + /// + /// Creates a new object that is a copy of the current instance. + /// + /// + /// A new object that is a copy of this instance. + /// + public object Clone() + { + var item = new ImageGalleryItem(mFilePath, mText) + { + // File info + extension = extension, + _details = _details, + + // Virtual item properties + mAdaptor = mAdaptor, + }; + + // Current thumbnail + if (ImageGalleryOwner != null && mAdaptor != null) + { + item.clonedThumbnail = ImageGalleryOwner.thumbnailCache.GetImage(Guid, mAdaptor, mVirtualKey, ImageGalleryOwner.ThumbnailSize, + ImageGalleryOwner.UseEmbeddedThumbnails, ImageGalleryOwner.AutoRotateThumbnails, true); + } + + return item; + } + #endregion + +} + + diff --git a/Source/Components/ImageGlass.Gallery/Item/ItemCollection.cs b/Source/Components/ImageGlass.Gallery/Item/ItemCollection.cs new file mode 100644 index 000000000..6603eb763 --- /dev/null +++ b/Source/Components/ImageGlass.Gallery/Item/ItemCollection.cs @@ -0,0 +1,747 @@ +/* +ImageGlass Project - Image viewer for Windows +Copyright (C) 2010 - 2026 DUONG DIEU PHAP +Project homepage: https://imageglass.org + +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 . + +--------------------- +ImageGlass.Gallery is based on ImageListView v13.8.2: +Url: https://github.com/oozcitak/imagelistview +License: Apache License Version 2.0, http://www.apache.org/licenses/ +--------------------- +*/ +using System.Collections; +using System.ComponentModel; + +namespace ImageGlass.Gallery; + + +public partial class ImageGallery +{ + /// + /// Represents the collection of items in the image list view. + /// + public class ItemCollection : IList, ICollection, IList, IEnumerable + { + + #region Member Variables + private readonly List mItems = new(); + private ImageGalleryItem? mFocused = null; + private Dictionary lookUp = new(); + + internal bool collectionModified = true; + internal ImageGallery _imageGallery; + #endregion + + + #region Constructors + /// + /// Initializes a new instance of the class. + /// + /// The owning this collection. + internal ItemCollection(ImageGallery owner) + { + _imageGallery = owner; + } + + #endregion + + + #region Properties + + /// + /// Gets the number of elements contained in + /// the . + /// + public int Count => mItems.Count; + + /// + /// Gets a value indicating whether the is read-only. + /// + public bool IsReadOnly => false; + + /// + /// Gets or sets the focused item. + /// + public ImageGalleryItem? FocusedItem + { + get => mFocused; + set + { + var oldFocusedItem = mFocused; + mFocused = value; + + // Refresh items + if (oldFocusedItem != mFocused && _imageGallery != null) + _imageGallery.Refresh(); + } + } + + /// + /// Gets the owning this collection. + /// + [Browsable(false)] + public ImageGallery ImageGalleryOwner => _imageGallery; + + /// + /// Gets or sets the at the specified index. + /// + [Browsable(false)] + public ImageGalleryItem this[int index] + { + get => mItems[index]; + set + { + var item = value; + var oldItem = mItems[index]; + + if (mItems[index] == mFocused) + { + mFocused = item; + } + + var oldSelected = mItems[index].Selected; + item.mIndex = index; + + if (_imageGallery != null) + { + item.ImageGalleryOwner = _imageGallery; + } + + item.owner = this; + mItems[index] = item; + lookUp.Remove(oldItem.Guid); + lookUp.Add(item.Guid, item); + collectionModified = true; + + if (_imageGallery != null) + { + _imageGallery.thumbnailCache.Remove(oldItem.Guid); + + if (_imageGallery.CacheMode == CacheMode.Continuous) + { + _imageGallery.thumbnailCache.Add( + item.Guid, + item.Adaptor, + item.VirtualKey, + _imageGallery.ThumbnailSize, + _imageGallery.UseEmbeddedThumbnails, + _imageGallery.AutoRotateThumbnails); + } + + if (item.Selected != oldSelected) + { + _imageGallery.OnSelectionChanged(new EventArgs()); + } + } + } + } + + /// + /// Gets the with the specified Guid. + /// + [Browsable(false)] + internal ImageGalleryItem this[Guid guid] => lookUp[guid]; + + #endregion + + + #region Instance Methods + + /// + /// Adds an item to the . + /// + /// The to add to the . + /// The adaptor associated with this item. + public void Add(ImageGalleryItem item, IAdaptor adaptor) + { + AddInternal(item, adaptor); + + if (_imageGallery != null) + { + if (item.Selected) + _imageGallery.OnSelectionChangedInternal(); + _imageGallery.Refresh(); + } + } + + /// + /// Adds an item to the . + /// + /// The to add to the . + public void Add(ImageGalleryItem item) + { + Add(item, _imageGallery.defaultAdaptor); + } + + /// + /// Adds an item to the . + /// + /// The to add to the . + /// The initial thumbnail image for the item. + /// The adaptor associated with this item. + public void Add(ImageGalleryItem item, Image initialThumbnail, IAdaptor adaptor) + { + item.clonedThumbnail = initialThumbnail; + Add(item, adaptor); + } + + /// + /// Adds an item to the . + /// + /// The to add to the . + /// The initial thumbnail image for the item. + public void Add(ImageGalleryItem item, Image initialThumbnail) + { + Add(item, initialThumbnail, _imageGallery.defaultAdaptor); + } + + /// + /// Adds an item to the . + /// + /// The name of the image file. + public void Add(string filename) + { + Add(filename, null); + } + + /// + /// Adds an item to the . + /// + /// The name of the image file. + /// The initial thumbnail image for the item. + public void Add(string filename, Image? initialThumbnail) + { + var item = new ImageGalleryItem(filename) + { + mAdaptor = _imageGallery.defaultAdaptor, + clonedThumbnail = initialThumbnail, + }; + + Add(item); + } + + /// + /// Adds a range of items to the . + /// + /// An array of + /// to add to the . + /// The adaptor associated with this item. + public void AddRange(ImageGalleryItem[] items, IAdaptor adaptor) + { + if (_imageGallery != null) + { + _imageGallery.SuspendPaint(); + } + + foreach (ImageGalleryItem item in items) + { + Add(item, adaptor); + } + + if (_imageGallery != null) + { + _imageGallery.Refresh(); + _imageGallery.ResumePaint(); + } + } + + /// + /// Adds a range of items to the . + /// + /// An array of + /// to add to the . + public void AddRange(ImageGalleryItem[] items) + { + AddRange(items, _imageGallery.defaultAdaptor); + } + + /// + /// Adds a range of items to the . + /// + /// The names or the image files. + public void AddRange(string[] filenames) + { + var items = new ImageGalleryItem[filenames.Length]; + + for (int i = 0; i < filenames.Length; i++) + { + items[i] = new ImageGalleryItem(filenames[i]); + } + + AddRange(items); + } + + /// + /// Removes all items from the . + /// + public void Clear() + { + mItems.Clear(); + mFocused = null; + lookUp = new(); + collectionModified = true; + + if (_imageGallery != null) + { + _imageGallery.thumbnailCache.Clear(); + _imageGallery.SelectedItems.Clear(); + + _imageGallery.Refresh(); + + // Raise the clear event + _imageGallery.OnItemCollectionChanged(new ItemCollectionChangedEventArgs(CollectionChangeAction.Refresh, null)); + } + } + + /// + /// Determines whether the + /// contains a specific value. + /// + /// The object to locate in the + /// . + /// + /// true if is found in the + /// ; otherwise, false. + /// + public bool Contains(ImageGalleryItem item) + { + return mItems.Contains(item); + } + + /// + /// Returns an enumerator that iterates through the collection. + /// + /// + /// A + /// that can be used to iterate through the collection. + /// + public IEnumerator GetEnumerator() + { + return mItems.GetEnumerator(); + } + + /// + /// Inserts an item to the at the specified index. + /// + /// The zero-based index at which should be inserted. + /// The to + /// insert into the . + /// The adaptor associated with this item. + public void Insert(int index, ImageGalleryItem item, IAdaptor adaptor) + { + InsertInternal(index, item, adaptor); + + if (_imageGallery != null) + { + if (item.Selected) + _imageGallery.OnSelectionChangedInternal(); + _imageGallery.Refresh(); + } + } + + /// + /// Inserts an item to the + /// at the specified index. + /// + /// The zero-based index at which + /// should be inserted. + /// The to + /// insert into the . + public void Insert(int index, ImageGalleryItem item) + { + Insert(index, item, _imageGallery.defaultAdaptor); + } + + /// + /// Inserts an item to the + /// at the specified index. + /// + /// The zero-based index at which the new item + /// should be inserted. + /// The name of the image file. + public void Insert(int index, string filename) + { + Insert(index, new ImageGalleryItem(filename)); + } + + /// + /// Inserts an item to the at + /// the specified index. + /// + /// The zero-based index at which the new item should + /// be inserted. + /// The name of the image file. + /// The initial thumbnail image for the item. + public void Insert(int index, string filename, Image initialThumbnail) + { + var item = new ImageGalleryItem(filename) + { + clonedThumbnail = initialThumbnail + }; + + Insert(index, item); + } + + /// + /// Removes the first occurrence of a specific object + /// from the . + /// + /// The to remove + /// from the . + /// + /// true if was successfully removed from the + /// ; otherwise, false. This method also + /// returns false if is not found in the original + /// . + /// + public bool Remove(ImageGalleryItem item) + { + bool ret = RemoveInternal(item, true); + + if (_imageGallery != null) + { + if (item.Selected) + { + _imageGallery.OnSelectionChangedInternal(); + } + + _imageGallery.Refresh(); + } + + return ret; + } + + /// + /// Removes the at the specified index. + /// + /// The zero-based index of the item to remove. + public void RemoveAt(int index) + { + Remove(mItems[index]); + } + + #endregion + + + #region Helper Methods + /// + /// Determines whether the collection contains the given key. + /// + /// The key of the item. + /// true if the collection contains the given key; otherwise false. + internal bool ContainsKey(Guid guid) + { + return lookUp.ContainsKey(guid); + } + + /// + /// Gets the value associated with the specified key. + /// + /// The key of the item. + /// the value associated with the specified key, + /// if the key is found; otherwise, the default value for the type + /// of the value parameter. This parameter is passed uninitialized. + /// true if the collection contains the given key; otherwise false. + internal bool TryGetValue(Guid guid, out ImageGalleryItem? item) + { + return lookUp.TryGetValue(guid, out item); + } + + /// + /// Adds the given item without raising a selection changed event. + /// + /// The to add. + /// The adaptor associated with this item. + /// true if the item was added; otherwise false. + internal bool AddInternal(ImageGalleryItem item, IAdaptor adaptor) + { + return InsertInternal(-1, item, adaptor); + } + + /// + /// Inserts the given item without raising a selection changed event. + /// + /// Insertion index. If index is -1 the item is added to the end of the list. + /// The to add. + /// The adaptor associated with this item. + /// true if the item was added; otherwise false. + internal bool InsertInternal(int index, ImageGalleryItem item, IAdaptor adaptor) + { + if (_imageGallery == null) + return false; + + item.owner = this; + item.mAdaptor = adaptor; + + if (index == -1) + { + item.mIndex = mItems.Count; + mItems.Add(item); + } + else + { + item.mIndex = index; + for (int i = index; i < mItems.Count; i++) + mItems[i].mIndex++; + mItems.Insert(index, item); + } + + lookUp.Add(item.Guid, item); + collectionModified = true; + + item.ImageGalleryOwner = _imageGallery; + + // Add current thumbnail to cache + if (item.clonedThumbnail != null) + { + _imageGallery.thumbnailCache.Add(item.Guid, item.Adaptor, item.VirtualKey, _imageGallery.ThumbnailSize, + item.clonedThumbnail, _imageGallery.UseEmbeddedThumbnails, _imageGallery.AutoRotateThumbnails); + item.clonedThumbnail = null; + } + + // Add to thumbnail cache + if (_imageGallery.CacheMode == CacheMode.Continuous) + { + _imageGallery.thumbnailCache.Add(item.Guid, item.Adaptor, item.VirtualKey, + _imageGallery.ThumbnailSize, _imageGallery.UseEmbeddedThumbnails, _imageGallery.AutoRotateThumbnails); + } + + // Add to shell info cache + var extension = item.extension; + if (!string.IsNullOrEmpty(extension)) + { + var state = _imageGallery.shellInfoCache.GetCacheState(extension); + if (state == CacheState.Error && _imageGallery.RetryOnError == true) + { + _imageGallery.shellInfoCache.Remove(extension); + _imageGallery.shellInfoCache.Add(extension); + } + else if (state == CacheState.Unknown) + _imageGallery.shellInfoCache.Add(extension); + } + + // Raise the add event + _imageGallery.OnItemCollectionChanged(new ItemCollectionChangedEventArgs(CollectionChangeAction.Add, item)); + + return true; + } + + /// + /// Removes the given item without raising a selection changed event. + /// + /// The item to remove. + internal void RemoveInternal(ImageGalleryItem item) + { + RemoveInternal(item, true); + } + + /// + /// Removes the given item without raising a selection changed event. + /// + /// The item to remove. + /// true to remove item image from cache; otherwise false. + internal bool RemoveInternal(ImageGalleryItem item, bool removeFromCache) + { + for (int i = item.mIndex + 1; i < mItems.Count; i++) + mItems[i].mIndex--; + + if (item == mFocused) mFocused = null; + if (removeFromCache && _imageGallery != null) + { + _imageGallery.thumbnailCache.Remove(item.Guid); + } + + var ret = mItems.Remove(item); + lookUp.Remove(item.Guid); + collectionModified = true; + + if (_imageGallery != null) + { + // Raise the remove event + _imageGallery.OnItemCollectionChanged(new ItemCollectionChangedEventArgs(CollectionChangeAction.Remove, item)); + } + + return ret; + } + + /// + /// Returns the index of the specified item. + /// + internal static int IndexOf(ImageGalleryItem item) + { + return item.Index; + } + + /// + /// Returns the index of the item with the specified Guid. + /// + internal int IndexOf(Guid guid) + { + if (lookUp.TryGetValue(guid, out ImageGalleryItem? item)) + return item.Index; + return -1; + } + + #endregion + + + #region Unsupported Interface + /// + /// Copies the elements of the to an , starting at a particular index. + /// + void ICollection.CopyTo(ImageGalleryItem[] array, int arrayIndex) + { + mItems.CopyTo(array, arrayIndex); + } + + /// + /// Determines the index of a specific item in the . + /// + [Obsolete("Use ImageGalleryItem.Index property instead.")] + int IList.IndexOf(ImageGalleryItem item) + { + return mItems.IndexOf(item); + } + + /// + /// Copies the elements of the to an , starting at a particular index. + /// + void ICollection.CopyTo(Array array, int index) + { + if (array is not ImageGalleryItem[]) + throw new ArgumentException("An array of ImageGalleryItem is required.", nameof(array)); + mItems.CopyTo((ImageGalleryItem[])array, index); + } + + /// + /// Gets the number of elements contained in the . + /// + int ICollection.Count + { + get { return mItems.Count; } + } + + /// + /// Gets a value indicating whether access to the is synchronized (thread safe). + /// + bool ICollection.IsSynchronized + { + get { return false; } + } + + /// + /// Gets an object that can be used to synchronize access to the . + /// + object ICollection.SyncRoot + { + get { throw new NotSupportedException(); } + } + + /// + /// Adds an item to the . + /// + int IList.Add(object? value) + { + if (value is not ImageGalleryItem) + throw new ArgumentException($"An object of type {nameof(ImageGalleryItem)} is required.", nameof(value)); + + var item = (ImageGalleryItem)value; + Add(item); + + return mItems.IndexOf(item); + } + + /// + /// Determines whether the contains a specific value. + /// + bool IList.Contains(object? value) + { + if (value is not ImageGalleryItem) + throw new ArgumentException($"An object of type {nameof(ImageGalleryItem)} is required.", nameof(value)); + return mItems.Contains((ImageGalleryItem)value); + } + + /// + /// Returns an enumerator that iterates through a collection. + /// + /// + /// An object that can be used to iterate through the collection. + /// + IEnumerator IEnumerable.GetEnumerator() + { + return mItems.GetEnumerator(); + } + + /// + /// Determines the index of a specific item in the . + /// + int IList.IndexOf(object? value) + { + if (value is not ImageGalleryItem) + throw new ArgumentException($"An object of type {nameof(ImageGalleryItem)} is required.", nameof(value)); + return IndexOf((ImageGalleryItem)value); + } + + /// + /// Inserts an item to the at the specified index. + /// + void IList.Insert(int index, object? value) + { + if (value is not ImageGalleryItem) + throw new ArgumentException($"An object of type {nameof(ImageGalleryItem)} is required.", nameof(value)); + Insert(index, (ImageGalleryItem)value); + } + + /// + /// Gets a value indicating whether the has a fixed size. + /// + bool IList.IsFixedSize + { + get { return false; } + } + + /// + /// Removes the first occurrence of a specific object from the . + /// + void IList.Remove(object? value) + { + if (value is not ImageGalleryItem) + throw new ArgumentException($"An object of type {nameof(ImageGalleryItem)} is required.", nameof(value)); + + var item = (ImageGalleryItem)value; + Remove(item); + } + + /// + /// Gets or sets the at the specified index. + /// + object? IList.this[int index] + { + get + { + return this[index]; + } + set + { + if (value is not ImageGalleryItem) + throw new ArgumentException($"An object of type {nameof(ImageGalleryItem)} is required.", nameof(value)); + this[index] = (ImageGalleryItem)value; + } + } + #endregion + + } +} diff --git a/Source/Components/ImageGlass.Gallery/Item/SelectedItemCollection.cs b/Source/Components/ImageGlass.Gallery/Item/SelectedItemCollection.cs new file mode 100644 index 000000000..f68326d7d --- /dev/null +++ b/Source/Components/ImageGlass.Gallery/Item/SelectedItemCollection.cs @@ -0,0 +1,349 @@ +/* +ImageGlass Project - Image viewer for Windows +Copyright (C) 2010 - 2026 DUONG DIEU PHAP +Project homepage: https://imageglass.org + +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 . + +--------------------- +ImageGlass.Gallery is based on ImageListView v13.8.2: +Url: https://github.com/oozcitak/imagelistview +License: Apache License Version 2.0, http://www.apache.org/licenses/ +--------------------- +*/ +using System.Collections; +using System.ComponentModel; + +namespace ImageGlass.Gallery; + + +public partial class ImageGallery +{ + /// + /// Represents the collection of selected items in the image list view. + /// + public class SelectedItemCollection : IList + { + #region Member Variables + internal ImageGallery _imageGallery; + #endregion + + #region Constructors + /// + /// Initializes a new instance of the class. + /// + /// The owning this collection. + internal SelectedItemCollection(ImageGallery owner) + { + _imageGallery = owner; + } + + #endregion + + #region Properties + /// + /// Gets the number of elements contained in the . + /// + [Category("Behavior"), Browsable(true), Description("Gets the number of elements contained in the collection.")] + public int Count + { + get + { + int count = 0; + foreach (ImageGalleryItem item in _imageGallery.Items) + if (item.Selected && item.Enabled) count++; + return count; + } + } + + /// + /// Gets a value indicating whether the is read-only. + /// + [Category("Behavior"), Browsable(false), Description("Gets a value indicating whether the collection is read-only.")] + public bool IsReadOnly => true; + + /// + /// Gets the owning this collection. + /// + [Category("Behavior"), Browsable(false), Description($"Gets the {nameof(ImageGallery)} owning this collection.")] + public ImageGallery ImageGalleryOwner => _imageGallery; + + /// + /// Gets or sets the at the specified index. + /// + [Category("Behavior"), Browsable(false), Description("Gets or sets the item at the specified index")] + public ImageGalleryItem this[int index] + { + get + { + int i = 0; + foreach (ImageGalleryItem item in this) + { + if (i == index) + return item; + i++; + } + throw new ArgumentException("No item with the given index exists.", nameof(index)); + } + } + + #endregion + + #region Instance Methods + /// + /// Determines whether the contains a specific value. + /// + /// The to locate in the . + /// + /// true if is found in the ; otherwise, false. + /// + public bool Contains(ImageGalleryItem item) + { + return item.Selected && item.Enabled && _imageGallery.Items.Contains(item); + } + + /// + /// Returns an enumerator that iterates through the collection. + /// + /// + /// A that can be used to iterate through the collection. + /// + public IEnumerator GetEnumerator() + { + return new SelectedItemEnumerator(_imageGallery.Items); + } + + #endregion + + #region Helper Methods + /// + /// Removes all items from the collection. + /// + internal void Clear() + { + Clear(true); + } + + /// + /// Removes all items from the collection. + /// + internal void Clear(bool raiseEvent) + { + foreach (ImageGalleryItem item in this) + item.mSelected = false; + if (raiseEvent && _imageGallery != null) + _imageGallery.OnSelectionChangedInternal(); + } + + #endregion + + + #region Unsupported Interface + /// + /// Adds an item to the . + /// + /// The object to add to the . + void ICollection.Add(ImageGalleryItem item) + { + throw new NotSupportedException(); + } + /// + /// Removes all items from the . + /// + void ICollection.Clear() + { + throw new NotSupportedException(); + } + /// + /// Copies the elements of the to an , starting at a particular index. + /// + /// The one-dimensional that is the destination of the elements copied from . The must have zero-based indexing. + /// The zero-based index in at which copying begins. + void ICollection.CopyTo(ImageGalleryItem[] array, int arrayIndex) + { + throw new NotSupportedException(); + } + /// + /// Determines the index of a specific item in the . + /// + /// The object to locate in the . + /// + /// The index of if found in the list; otherwise, -1. + /// + [Obsolete($"Use {nameof(ImageGalleryItem.Index)} property instead.")] + int IList.IndexOf(ImageGalleryItem item) + { + throw new NotSupportedException(); + } + /// + /// Inserts an item to the at the specified index. + /// + /// The zero-based index at which should be inserted. + /// The object to insert into the . + void IList.Insert(int index, ImageGalleryItem item) + { + throw new NotSupportedException(); + } + /// + /// Removes the first occurrence of a specific object from the . + /// + /// The object to remove from the . + /// + /// true if was successfully removed from the ; otherwise, false. This method also returns false if is not found in the original . + /// + bool ICollection.Remove(ImageGalleryItem item) + { + throw new NotSupportedException(); + } + /// + /// Removes the item at the specified index. + /// + /// The zero-based index of the item to remove. + void IList.RemoveAt(int index) + { + throw new NotSupportedException(); + } + /// + /// Gets or sets the item at the specified index. + /// + ImageGalleryItem IList.this[int index] + { + get + { + throw new NotSupportedException(); + } + set + { + throw new NotSupportedException(); + } + } + /// + /// Returns an enumerator that iterates through a collection. + /// + /// + /// An object that can be used to iterate through the collection. + /// + System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + #endregion + + + #region Internal Classes + /// + /// Represents an enumerator to walk though the selected items. + /// + internal class SelectedItemEnumerator : IEnumerator + { + #region Member Variables + private ItemCollection owner; + private int current; + private Guid lastItem; + #endregion + + #region Constructor + public SelectedItemEnumerator(ItemCollection collection) + { + owner = collection; + current = -1; + lastItem = Guid.Empty; + } + #endregion + + #region Properties + /// + /// Gets the element in the collection at the current position of the enumerator. + /// + public ImageGalleryItem Current + { + get + { + if (current == -1 || current > owner.Count - 1) + throw new InvalidOperationException(); + return owner[current]; + } + } + + /// + /// Gets the element in the collection at the current position of the enumerator. + /// + object IEnumerator.Current + { + get { return Current; } + } + + #endregion + + #region Instance Methods + /// + /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. + /// + public void Dispose() + { + ; + } + + /// + /// Advances the enumerator to the next element of the collection. + /// + public bool MoveNext() + { + // Did we reach the end? + if (current > owner.Count - 1) + { + lastItem = Guid.Empty; + return false; + } + + // Move to the next item if: + // 1. We are before the first item. - OR - + // 2. The current item is the same as the one we enumerated before. + // The current item may have differed if the user for example + // removed the current item between MoveNext calls. - OR - + // 3. The current item is not selected. + // 3. The current item is not enabled. + while (current == -1 || + owner[current].Guid == lastItem || + owner[current].Selected == false || + owner[current].Enabled == false) + { + current++; + if (current > owner.Count - 1) + { + lastItem = Guid.Empty; + return false; + } + } + + // Cache the last item + lastItem = owner[current].Guid; + return true; + } + + /// + /// Sets the enumerator to its initial position, which is before the first element in the collection. + /// + public void Reset() + { + current = -1; + lastItem = Guid.Empty; + } + + #endregion + } + #endregion + } + +} diff --git a/Source/Components/ImageGlass.Gallery/Managers/HitInfo.cs b/Source/Components/ImageGlass.Gallery/Managers/HitInfo.cs new file mode 100644 index 000000000..cd55d55b6 --- /dev/null +++ b/Source/Components/ImageGlass.Gallery/Managers/HitInfo.cs @@ -0,0 +1,97 @@ +/* +ImageGlass Project - Image viewer for Windows +Copyright (C) 2010 - 2026 DUONG DIEU PHAP +Project homepage: https://imageglass.org + +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 . + +--------------------- +ImageGlass.Gallery is based on ImageListView v13.8.2: +Url: https://github.com/oozcitak/imagelistview +License: Apache License Version 2.0, http://www.apache.org/licenses/ +--------------------- +*/ +namespace ImageGlass.Gallery; + + +/// +/// Represents the details of a mouse hit test. +/// +public class HitInfo +{ + + #region Properties + /// + /// Gets whether an item is under the hit point. + /// + public bool IsItemHit => ItemIndex != -1; + + /// + /// Gets whether an item checkbox is under the hit point. + /// + public bool IsCheckBoxHit { get; private set; } + + /// + /// Gets whether the file icon is under the hit point. + /// + public bool IsFileIconHit { get; private set; } + + /// + /// Gets the index of the item under the hit point. + /// + public int ItemIndex { get; private set; } + + /// + /// Gets whether the hit point is inside the item area. + /// + public bool IsInItemArea { get; private set; } + + /// + /// Gets the rectange bound of resizer. + /// + public bool IsResizerHit { get; private set; } = false; + + #endregion + + + #region Constructor + /// + /// Initializes a new instance of the HitInfo class. + /// + /// Index of the item. + /// if set to true the mouse cursor is over a checkbox. + /// if set to true the mouse cursor is over a file icon. + /// if set to true the mouse is in the item area. + private HitInfo(int itemIndex, bool checkBoxHit, bool fileIconHit, bool inItemArea, bool resizerHit) + { + ItemIndex = itemIndex; + IsCheckBoxHit = checkBoxHit; + IsFileIconHit = fileIconHit; + + IsInItemArea = inItemArea; + IsResizerHit = resizerHit; + } + + /// + /// Initializes a new instance of the HitInfo class. + /// + /// Index of the item. + /// if set to true the mouse cursor is over a checkbox. + /// if set to true the mouse cursor is over a file icon. + internal HitInfo(int itemIndex, bool checkBoxHit, bool fileIconHit, bool resizerHit) + : this(itemIndex, checkBoxHit, fileIconHit, true, resizerHit) { } + + #endregion + +} diff --git a/Source/Components/ImageGlass.Gallery/Managers/LayoutManager.cs b/Source/Components/ImageGlass.Gallery/Managers/LayoutManager.cs new file mode 100644 index 000000000..a473598a6 --- /dev/null +++ b/Source/Components/ImageGlass.Gallery/Managers/LayoutManager.cs @@ -0,0 +1,678 @@ +/* +ImageGlass Project - Image viewer for Windows +Copyright (C) 2010 - 2026 DUONG DIEU PHAP +Project homepage: https://imageglass.org + +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 . + +--------------------- +ImageGlass.Gallery is based on ImageListView v13.8.2: +Url: https://github.com/oozcitak/imagelistview +License: Apache License Version 2.0, http://www.apache.org/licenses/ +--------------------- +*/ + +namespace ImageGlass.Gallery; + + +/// +/// Represents the layout of the image list view drawing area. +/// +internal class LayoutManager +{ + #region Member Variables + private Rectangle mClientArea; + private ImageGallery _imageGallery; + private Rectangle mItemAreaBounds; + private Size mItemSize; + private Size mItemSizeWithMargin; + private int mDisplayedCols; + private int mDisplayedRows; + private int mItemCols; + private int mItemRows; + private int mFirstPartiallyVisible; + private int mLastPartiallyVisible; + private int mFirstVisible; + private int mLastVisible; + + private View cachedView; + private Point cachedViewOffset; + private Size cachedSize; + private int cachedItemCount; + private Size cachedItemSize; + private bool cachedIntegralScroll; + private Size cachedItemMargin; + private bool cachedScrollBars; + private readonly Dictionary cachedVisibleItems = new(); + + private bool vScrollVisible = false; + private bool hScrollVisible = false; + + // Size required to display all items (i.e. scroll range) + private int totalWidth; + private int totalHeight; + #endregion + + + #region Properties + /// + /// Gets the bounds of the entire client area. + /// + public Rectangle ClientArea => mClientArea; + + /// + /// Gets the owner image list view. + /// + public ImageGallery ImageGalleryOwner => _imageGallery; + + /// + /// Gets the extends of the item area. + /// + public Rectangle ItemAreaBounds => mItemAreaBounds; + + /// + /// Gets the items size. + /// + public Size ItemSize => mItemSize; + + /// + /// Gets the items size including the margin around the item. + /// + public Size ItemSizeWithMargin => mItemSizeWithMargin; + + /// + /// Gets the maximum number of columns that can be displayed. + /// + public int Cols => mDisplayedCols; + + /// + /// Gets the maximum number of rows that can be displayed. + /// + public int Rows => mDisplayedRows; + + /// + /// Gets the index of the first partially visible item. + /// + public int FirstPartiallyVisible => mFirstPartiallyVisible; + + /// + /// Gets the index of the last partially visible item. + /// + public int LastPartiallyVisible => mLastPartiallyVisible; + + /// + /// Gets the index of the first fully visible item. + /// + public int FirstVisible => mFirstVisible; + + /// + /// Gets the index of the last fully visible item. + /// + public int LastVisible => mLastVisible; + + /// + /// Determines whether an update is required. + /// + public bool UpdateRequired + { + get + { + if (_imageGallery.View != cachedView) + return true; + else if (_imageGallery.ViewOffset != cachedViewOffset) + return true; + else if (_imageGallery.ClientSize != cachedSize) + return true; + else if (_imageGallery.Items.Count != cachedItemCount) + return true; + else if (_imageGallery.mRenderer.MeasureItem(_imageGallery.View) != cachedItemSize) + return true; + else if (_imageGallery.mRenderer.MeasureItemMargin(_imageGallery.View) != cachedItemMargin) + return true; + else if (_imageGallery.ScrollBars != cachedScrollBars) + return true; + else if (_imageGallery.IntegralScroll != cachedIntegralScroll) + return true; + else if (_imageGallery.Items.collectionModified) + return true; + else + return false; + } + } + + #endregion + + + #region Constructor + /// + /// Initializes a new instance. + /// + /// The owner control. + public LayoutManager(ImageGallery owner) + { + _imageGallery = owner; + + Update(); + } + + #endregion + + + #region Instance Methods + /// + /// Determines whether the item with the given guid is + /// (partially) visible. + /// + /// The guid of the item to check. + public bool IsItemVisible(Guid guid) + { + return cachedVisibleItems.ContainsKey(guid); + } + + /// + /// Determines whether the item with the given guid is partially visible. + /// + /// The index of the item to check. + /// + public bool IsItemPartialyVisible(int index) + { + return index == FirstPartiallyVisible || index == LastPartiallyVisible; + } + + /// + /// Returns the bounds of the item with the specified index. + /// + public Rectangle GetItemBounds(int itemIndex) + { + var location = mItemAreaBounds.Location; + location.X += cachedItemMargin.Width / 2 - _imageGallery.ViewOffset.X; + location.Y += cachedItemMargin.Height / 2 - _imageGallery.ViewOffset.Y + ImageGalleryOwner.Padding.Top; + + if (ImageGalleryOwner.View == View.HorizontalStrip) + { + var startGap = 0; + + // center the items + if (ImageGalleryOwner.Items.Count <= mDisplayedCols) + { + var currentItemsWidth = mItemSizeWithMargin.Width * ImageGalleryOwner.Items.Count; + startGap = mItemAreaBounds.Width / 2 - currentItemsWidth / 2; + } + + location.X += (itemIndex * mItemSizeWithMargin.Width) + startGap; + } + else + { + location.X += (itemIndex % mDisplayedCols) * mItemSizeWithMargin.Width; + location.Y += (itemIndex / mDisplayedCols) * mItemSizeWithMargin.Height; + } + + return new Rectangle(location, mItemSize); + } + + /// + /// Returns the bounds of the item with the specified index, + /// including the margin around the item. + /// + public Rectangle GetItemBoundsWithMargin(int itemIndex) + { + Rectangle rec = GetItemBounds(itemIndex); + rec.Inflate(cachedItemMargin.Width / 2, cachedItemMargin.Height / 2); + return rec; + } + + /// + /// Returns the item checkbox bounds. + /// This method assumes a checkbox icon size of 16x16 + /// + public Rectangle GetCheckBoxBounds(int itemIndex) + { + var bounds = GetWidgetBounds(GetItemBounds(itemIndex), new Size(16, 16), + _imageGallery.CheckBoxPadding, _imageGallery.CheckBoxAlignment); + + // If the checkbox and the icon have the same alignment, + // move the checkbox horizontally away from the icon + if (_imageGallery.CheckBoxAlignment == _imageGallery.IconAlignment + && _imageGallery.ShowCheckBoxes + && _imageGallery.ShowFileIcons) + { + var alignment = _imageGallery.CheckBoxAlignment; + if (alignment == ContentAlignment.BottomCenter + || alignment == ContentAlignment.MiddleCenter + || alignment == ContentAlignment.TopCenter) + { + bounds.X -= 8 + _imageGallery.IconPadding.Width / 2; + } + else if (alignment == ContentAlignment.BottomRight + || alignment == ContentAlignment.MiddleRight + || alignment == ContentAlignment.TopRight) + { + bounds.X -= 16 + _imageGallery.IconPadding.Width; + } + } + + return bounds; + } + + /// + /// Returns the item icon bounds. + /// This method assumes an icon size of 16x16 + /// + public Rectangle GetIconBounds(int itemIndex) + { + var bounds = GetWidgetBounds(GetItemBounds(itemIndex), new Size(16, 16), + _imageGallery.IconPadding, _imageGallery.IconAlignment); + + // If the checkbox and the icon have the same alignment, + // or in details view move the icon horizontally away from the checkbox + if (_imageGallery.ShowCheckBoxes && _imageGallery.ShowFileIcons) + { + bounds.X += 16 + 2; + } + else if (_imageGallery.CheckBoxAlignment == _imageGallery.IconAlignment + && _imageGallery.ShowCheckBoxes + && _imageGallery.ShowFileIcons) + { + var alignment = _imageGallery.CheckBoxAlignment; + if (alignment == ContentAlignment.BottomLeft + || alignment == ContentAlignment.MiddleLeft + || alignment == ContentAlignment.TopLeft) + { + bounds.X += 16 + _imageGallery.IconPadding.Width; + } + else if (alignment == ContentAlignment.BottomCenter + || alignment == ContentAlignment.MiddleCenter + || alignment == ContentAlignment.TopCenter) + { + bounds.X += 8 + _imageGallery.IconPadding.Width / 2; + } + } + + return bounds; + } + + /// + /// Returns the bounds of a widget. + /// Used to calculate the bounds of checkboxes and icons. + /// + private Rectangle GetWidgetBounds(Rectangle bounds, Size size, Size padding, ContentAlignment alignment) + { + // Apply padding + bounds.Inflate(-padding.Width, -padding.Height); + + int x; + if (alignment == ContentAlignment.BottomLeft + || alignment == ContentAlignment.MiddleLeft + || alignment == ContentAlignment.TopLeft) + { + x = bounds.Left; + } + else if (alignment == ContentAlignment.BottomCenter + || alignment == ContentAlignment.MiddleCenter + || alignment == ContentAlignment.TopCenter) + { + x = bounds.Left + bounds.Width / 2 - size.Width / 2; + } + else // if (alignment == ContentAlignment.BottomRight || alignment == ContentAlignment.MiddleRight || alignment == ContentAlignment.TopRight) + { + x = bounds.Right - size.Width; + } + + int y; + if (alignment == ContentAlignment.BottomLeft + || alignment == ContentAlignment.BottomCenter + || alignment == ContentAlignment.BottomRight) + { + y = bounds.Bottom - size.Height; + } + else if (alignment == ContentAlignment.MiddleLeft + || alignment == ContentAlignment.MiddleCenter + || alignment == ContentAlignment.MiddleRight) + { + y = bounds.Top + bounds.Height / 2 - size.Height / 2; + } + else // if (alignment == ContentAlignment.TopLeft || alignment == ContentAlignment.TopCenter || alignment == ContentAlignment.TopRight) + { + y = bounds.Top; + } + + return new Rectangle(x, y, size.Width, size.Height); + } + + /// + /// Recalculates the control layout. + /// + public void Update() + { + Update(false); + } + + /// + /// Recalculates the control layout. + /// true to force an update; otherwise false. + /// + public void Update(bool forceUpdate) + { + if (_imageGallery.ClientRectangle.Width == 0 + || _imageGallery.ClientRectangle.Height == 0) + return; + + // If only item order is changed, just update visible items. + if (!forceUpdate && !UpdateRequired && _imageGallery.Items.collectionModified) + { + UpdateVisibleItems(); + return; + } + + if (!forceUpdate && !UpdateRequired) + return; + + // Get the item size from the renderer + mItemSize = _imageGallery.mRenderer.MeasureItem(_imageGallery.View); + cachedItemMargin = _imageGallery.mRenderer.MeasureItemMargin(_imageGallery.View).ToSize(); + mItemSizeWithMargin = mItemSize + cachedItemMargin; + + // Cache current properties to determine if we will need an update later + var viewChanged = cachedView != _imageGallery.View; + cachedView = _imageGallery.View; + cachedViewOffset = _imageGallery.ViewOffset; + cachedSize = _imageGallery.ClientSize; + cachedItemCount = _imageGallery.Items.Count; + cachedIntegralScroll = _imageGallery.IntegralScroll; + cachedItemSize = mItemSize; + cachedScrollBars = _imageGallery.ScrollBars; + _imageGallery.Items.collectionModified = false; + + // Calculate item area bounds + if (!UpdateItemArea()) + return; + + // Let the calculated bounds modified by the renderer + var eLayout = new LayoutEventArgs(mItemAreaBounds); + _imageGallery.mRenderer.OnLayout(eLayout); + mItemAreaBounds = eLayout.ItemAreaBounds; + if (mItemAreaBounds.Width <= 0 || mItemAreaBounds.Height <= 0) + return; + + // Calculate the number of rows and columns + CalculateGrid(); + + // Check if we need the scroll bars. + // Recalculate the layout if scroll bar visibility changes. + if (CheckScrollBars()) + { + Update(true); + return; + } + + // Update scroll range + UpdateScrollBars(); + + // Cache visible items + UpdateVisibleItems(); + + // Recalculate the layout if view mode was changed + if (viewChanged) + Update(); + } + + /// + /// Calculates the maximum number of rows and columns + /// that can be fully displayed. + /// + private void CalculateGrid() + { + // Number of rows and columns shown on screen + mDisplayedRows = (int)Math.Floor(mItemAreaBounds.Height / (float)mItemSizeWithMargin.Height); + mDisplayedCols = (int) + Math.Floor(mItemAreaBounds.Width / (float)mItemSizeWithMargin.Width); + + if (_imageGallery.View == View.VerticalStrip) mDisplayedCols = 1; + if (_imageGallery.View == View.HorizontalStrip) mDisplayedRows = 1; + if (mDisplayedCols < 1) mDisplayedCols = 1; + if (mDisplayedRows < 1) mDisplayedRows = 1; + + // Number of rows and columns to enclose all items + if (_imageGallery.View == View.HorizontalStrip) + { + mItemRows = mDisplayedRows; + mItemCols = (int)Math.Ceiling(_imageGallery.Items.Count / (float)mDisplayedRows); + } + else + { + mItemCols = mDisplayedCols; + mItemRows = (int)Math.Ceiling(_imageGallery.Items.Count / (float)mDisplayedCols); + } + + totalWidth = mItemCols * mItemSizeWithMargin.Width; + totalHeight = mItemRows * mItemSizeWithMargin.Height; + } + + /// + /// Calculates the item area. + /// + /// true if the item area is not empty (both width and height + /// greater than zero); otherwise false. + private bool UpdateItemArea() + { + // Calculate drawing area + mClientArea = _imageGallery.ClientRectangle; + if (_imageGallery.BorderStyle != BorderStyle.None) + { + mClientArea.Inflate(-1, -1); + } + + mItemAreaBounds = mClientArea; + + // Allocate space for scrollbars + if (_imageGallery.hScrollBar.Visible) + { + mClientArea.Height -= _imageGallery.hScrollBar.Height; + mItemAreaBounds.Height -= _imageGallery.hScrollBar.Height; + } + + if (_imageGallery.vScrollBar.Visible) + { + mClientArea.Width -= _imageGallery.vScrollBar.Width; + mItemAreaBounds.Width -= _imageGallery.vScrollBar.Width; + } + + return mItemAreaBounds.Width > 0 && mItemAreaBounds.Height > 0; + } + + /// + /// Shows or hides the scroll bars. + /// Returns true if the layout needs to be recalculated; otherwise false. + /// + /// + private bool CheckScrollBars() + { + // Horizontal scroll bar + var hScrollRequired = false; + var hScrollChanged = false; + if (_imageGallery.ScrollBars) + { + hScrollRequired = (_imageGallery.Items.Count > 0) && (mItemAreaBounds.Width < totalWidth); + } + + if (hScrollRequired != hScrollVisible) + { + hScrollVisible = hScrollRequired; + _imageGallery.hScrollBar.Visible = hScrollRequired; + hScrollChanged = true; + } + + // Vertical scroll bar + var vScrollRequired = false; + var vScrollChanged = false; + if (_imageGallery.ScrollBars) + { + vScrollRequired = (_imageGallery.Items.Count > 0) && (mItemAreaBounds.Height < totalHeight); + } + + if (vScrollRequired != vScrollVisible) + { + vScrollVisible = vScrollRequired; + _imageGallery.vScrollBar.Visible = vScrollRequired; + vScrollChanged = true; + } + + // Determine if the layout needs to be recalculated + return hScrollChanged || vScrollChanged; + } + + /// + /// Updates scroll bar parameters. + /// + private void UpdateScrollBars() + { + // Set scroll range + if (_imageGallery.Items.Count != 0) + { + // Horizontal scroll range + if (_imageGallery.ScrollOrientation == ScrollOrientation.HorizontalScroll) + { + _imageGallery.hScrollBar.Minimum = 0; + _imageGallery.hScrollBar.Maximum = Math.Max(0, totalWidth - 1); + + if (!_imageGallery.IntegralScroll) + { + _imageGallery.hScrollBar.LargeChange = mItemAreaBounds.Width; + } + else + { + _imageGallery.hScrollBar.LargeChange = mItemSizeWithMargin.Width * mDisplayedCols; + } + _imageGallery.hScrollBar.SmallChange = mItemSizeWithMargin.Width; + } + else + { + _imageGallery.hScrollBar.Minimum = 0; + _imageGallery.hScrollBar.Maximum = mDisplayedCols * mItemSizeWithMargin.Width; + _imageGallery.hScrollBar.LargeChange = mItemAreaBounds.Width; + _imageGallery.hScrollBar.SmallChange = 1; + } + if (_imageGallery.ViewOffset.X > _imageGallery.hScrollBar.Maximum - _imageGallery.hScrollBar.LargeChange + 1) + { + _imageGallery.hScrollBar.Value = _imageGallery.hScrollBar.Maximum - _imageGallery.hScrollBar.LargeChange + 1; + _imageGallery.ViewOffset = new Point(_imageGallery.hScrollBar.Value, _imageGallery.ViewOffset.Y); + } + + // Vertical scroll range + if (_imageGallery.ScrollOrientation == ScrollOrientation.HorizontalScroll) + { + _imageGallery.vScrollBar.Minimum = 0; + _imageGallery.vScrollBar.Maximum = mDisplayedRows * mItemSizeWithMargin.Height; + _imageGallery.vScrollBar.LargeChange = mItemAreaBounds.Height; + _imageGallery.vScrollBar.SmallChange = 1; + } + else + { + _imageGallery.vScrollBar.Minimum = 0; + _imageGallery.vScrollBar.Maximum = Math.Max(0, totalHeight - 1); + if (!_imageGallery.IntegralScroll) + { + _imageGallery.vScrollBar.LargeChange = mItemAreaBounds.Height; + } + else + { + _imageGallery.vScrollBar.LargeChange = mItemSizeWithMargin.Height * mDisplayedRows; + } + _imageGallery.vScrollBar.SmallChange = mItemSizeWithMargin.Height; + } + if (_imageGallery.ViewOffset.Y > _imageGallery.vScrollBar.Maximum - _imageGallery.vScrollBar.LargeChange + 1) + { + _imageGallery.vScrollBar.Value = _imageGallery.vScrollBar.Maximum - _imageGallery.vScrollBar.LargeChange + 1; + _imageGallery.ViewOffset = new Point(_imageGallery.ViewOffset.X, _imageGallery.vScrollBar.Value); + } + } + else // if (mImageListView.Items.Count == 0) + { + // Zero out the scrollbars if we don't have any items + _imageGallery.hScrollBar.Minimum = 0; + _imageGallery.hScrollBar.Maximum = 0; + _imageGallery.hScrollBar.Value = 0; + _imageGallery.vScrollBar.Minimum = 0; + _imageGallery.vScrollBar.Maximum = 0; + _imageGallery.vScrollBar.Value = 0; + _imageGallery.ViewOffset = new Point(0, 0); + } + + var bounds = _imageGallery.ClientRectangle; + if (_imageGallery.BorderStyle != BorderStyle.None) + bounds.Inflate(-1, -1); + + // Horizontal scrollbar position + _imageGallery.hScrollBar.Left = bounds.Left; + _imageGallery.hScrollBar.Top = bounds.Bottom - _imageGallery.hScrollBar.Height; + _imageGallery.hScrollBar.Width = bounds.Width - (_imageGallery.vScrollBar.Visible ? _imageGallery.vScrollBar.Width : 0); + + // Vertical scrollbar position + _imageGallery.vScrollBar.Left = bounds.Right - _imageGallery.vScrollBar.Width; + _imageGallery.vScrollBar.Top = bounds.Top; + _imageGallery.vScrollBar.Height = bounds.Height - (_imageGallery.hScrollBar.Visible ? _imageGallery.hScrollBar.Height : 0); + } + + /// + /// Updates the dictionary of visible items. + /// + private void UpdateVisibleItems() + { + // Find the first and last visible items + if (_imageGallery.View == View.HorizontalStrip) + { + mFirstPartiallyVisible = (int)Math.Floor(_imageGallery.ViewOffset.X / (float)mItemSizeWithMargin.Width) * mDisplayedRows; + mLastPartiallyVisible = (int)Math.Ceiling((_imageGallery.ViewOffset.X + mItemAreaBounds.Width) / (float)mItemSizeWithMargin.Width) * mDisplayedRows - 1; + mFirstVisible = (int)Math.Ceiling(_imageGallery.ViewOffset.X / (float)mItemSizeWithMargin.Width) * mDisplayedRows; + mLastVisible = (int)Math.Floor((_imageGallery.ViewOffset.X + mItemAreaBounds.Width) / (float)mItemSizeWithMargin.Width) * mDisplayedRows - 1; + } + else + { + mFirstPartiallyVisible = (int)Math.Floor(_imageGallery.ViewOffset.Y / (float)mItemSizeWithMargin.Height) * mDisplayedCols; + mLastPartiallyVisible = (int)Math.Ceiling((_imageGallery.ViewOffset.Y + mItemAreaBounds.Height) / (float)mItemSizeWithMargin.Height) * mDisplayedCols - 1; + mFirstVisible = (int)Math.Ceiling(_imageGallery.ViewOffset.Y / (float)mItemSizeWithMargin.Height) * mDisplayedCols; + mLastVisible = (int)Math.Floor((_imageGallery.ViewOffset.Y + mItemAreaBounds.Height) / (float)mItemSizeWithMargin.Height) * mDisplayedCols - 1; + } + + // Bounds check + if (mFirstPartiallyVisible < 0) mFirstPartiallyVisible = 0; + if (mFirstPartiallyVisible > _imageGallery.Items.Count - 1) mFirstPartiallyVisible = _imageGallery.Items.Count - 1; + if (mLastPartiallyVisible < 0) mLastPartiallyVisible = 0; + if (mLastPartiallyVisible > _imageGallery.Items.Count - 1) mLastPartiallyVisible = _imageGallery.Items.Count - 1; + if (mFirstVisible < 0) mFirstVisible = 0; + if (mFirstVisible > _imageGallery.Items.Count - 1) mFirstVisible = _imageGallery.Items.Count - 1; + if (mLastVisible < 0) mLastVisible = 0; + if (mLastVisible > _imageGallery.Items.Count - 1) mLastVisible = _imageGallery.Items.Count - 1; + + // Cache visible items + cachedVisibleItems.Clear(); + + if (mFirstPartiallyVisible >= 0 + && mLastPartiallyVisible >= 0 + && mFirstPartiallyVisible <= _imageGallery.Items.Count - 1 + && mLastPartiallyVisible <= _imageGallery.Items.Count - 1) + { + for (int i = mFirstPartiallyVisible; i <= mLastPartiallyVisible; i++) + { + cachedVisibleItems.Add(_imageGallery.Items[i].Guid, false); + } + } + + // Current item state processed + _imageGallery.Items.collectionModified = false; + } + + #endregion +} + diff --git a/Source/Components/ImageGlass.Gallery/Managers/NavigationManager.cs b/Source/Components/ImageGlass.Gallery/Managers/NavigationManager.cs new file mode 100644 index 000000000..909f1213f --- /dev/null +++ b/Source/Components/ImageGlass.Gallery/Managers/NavigationManager.cs @@ -0,0 +1,1064 @@ +/* +ImageGlass Project - Image viewer for Windows +Copyright (C) 2010 - 2026 DUONG DIEU PHAP +Project homepage: https://imageglass.org + +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 . + +--------------------- +ImageGlass.Gallery is based on ImageListView v13.8.2: +Url: https://github.com/oozcitak/imagelistview +License: Apache License Version 2.0, http://www.apache.org/licenses/ +--------------------- +*/ +using ImageGlass.Base.WinApi; + +namespace ImageGlass.Gallery; + + +public partial class ImageGallery +{ + /// + /// Represents details of keyboard and mouse navigation events. + /// + internal class NavigationManager : IDisposable + { + + #region Member Variables + private readonly ImageGallery _imageGallery; + + private bool inItemArea = false; + private bool overCheckBox = false; + + private Point lastViewOffset = new(); + private Point lastMouseDownLocation = new(); + private readonly Dictionary highlightedItems = new(); + + private bool lastMouseDownInItemArea = false; + private bool lastMouseDownOverItem = false; + private bool lastMouseDownOverCheckBox = false; + + private bool selfDragging = false; + + private readonly System.Windows.Forms.Timer scrollTimer = new() + { + Interval = 100, + Enabled = false, + }; + + #endregion + + + #region Properties + /// + /// Gets whether the left mouse button is down. + /// + public bool LeftButton { get; private set; } = false; + + /// + /// Gets whether the right mouse button is down. + /// + public bool RightButton { get; private set; } = false; + + /// + /// Gets whether the shift key is down. + /// + public bool ShiftKey { get; private set; } = false; + + /// + /// Gets whether the control key is down. + /// + public bool ControlKey { get; private set; } = false; + + /// + /// Gets the item under the mouse. + /// + public ImageGalleryItem? HoveredItem { get; private set; } = null; + + /// + /// Gets whether a mouse selection is in progress. + /// + public bool MouseSelecting { get; private set; } = false; + + /// + /// Gets the target item for a drop operation. + /// + public ImageGalleryItem? DropTarget { get; private set; } = null; + + /// + /// Gets whether drop target is to the right of the item. + /// + public bool DropToRight { get; private set; } = false; + + /// + /// Gets the selection rectangle. + /// + public Rectangle SelectionRectangle { get; private set; } = new(); + + /// + /// Gets the resizer bound. + /// + public bool IsResizerHit { get; private set; } = false; + + /// + /// Gets the mouse state. + /// + public MouseState MouseState { get; private set; } = MouseState.Normal; + + #endregion + + + #region Constructor + /// + /// Initializes a new instance of the class. + /// + /// The owner control. + public NavigationManager(ImageGallery owner) + { + _imageGallery = owner; + scrollTimer.Tick += new EventHandler(ScrollTimer_Tick); + } + + #endregion + + + #region Instance Methods + /// + /// Determines whether the item is highlighted. + /// + public ItemHighlightState HighlightState(ImageGalleryItem item) + { + if (highlightedItems.TryGetValue(item, out bool highlighted)) + { + if (highlighted) + return ItemHighlightState.HighlightedAndSelected; + else + return ItemHighlightState.HighlightedAndUnSelected; + } + return ItemHighlightState.NotHighlighted; + } + + /// + /// Performs application-defined tasks associated with freeing, + /// releasing, or resetting unmanaged resources. + /// + public void Dispose() + { + scrollTimer.Dispose(); + } + + #endregion + + + #region Mouse Event Handlers + + /// + /// Handles control's MouseDown event. + /// + public void MouseDown(MouseEventArgs e) + { + MouseState = MouseState.Pressed; + DoHitTest(e.Location); + + if (HoveredItem != null) + { + HoveredItem.Pressed = true; + } + + if (e.Button.HasFlag(MouseButtons.Middle)) return; + if (e.Button.HasFlag(MouseButtons.Left)) + LeftButton = true; + if (e.Button.HasFlag(MouseButtons.Right)) + RightButton = true; + + + lastMouseDownInItemArea = inItemArea; + lastMouseDownOverItem = HoveredItem != null; + lastMouseDownOverCheckBox = overCheckBox; + + lastViewOffset = _imageGallery.ViewOffset; + lastMouseDownLocation = e.Location; + + + if (_imageGallery.Resizer != ResizerType.None) + { + _imageGallery.Refresh(); + UpdateCursor(); + + if (!IsResizerHit) return; + + // Tell the OS that you want to drag the window. + WindowApi.SetResizerOnMouseDown(_imageGallery.Handle, _imageGallery.Resizer); + + // calling WindowApi.SetResizer() also releases the mouse capture, + // so the mouse state here is mouse up + MouseState = MouseState.Normal; + + _imageGallery.ResizedByResizer?.Invoke(_imageGallery, new EventArgs()); + } + } + + /// + /// Handles control's MouseMove event. + /// + public void MouseMove(MouseEventArgs e) + { + if (MouseState == MouseState.Normal) + { + MouseState = MouseState.Hovered; + } + + var oldHoveredItem = HoveredItem; + DoHitTest(e.Location); + + + // deselect old item that is clicked by middle mouse + if (e.Button == MouseButtons.Middle && oldHoveredItem != null) + { + oldHoveredItem.mPressed = false; + oldHoveredItem.mSelected = false; + } + + _imageGallery.SuspendPaint(); + + // Do we need to scroll the view? + if (MouseSelecting && _imageGallery.ScrollOrientation == ScrollOrientation.VerticalScroll && !scrollTimer.Enabled) + { + if (e.Y > _imageGallery.ClientRectangle.Bottom) + { + scrollTimer.Tag = -SystemInformation.MouseWheelScrollDelta; + scrollTimer.Enabled = true; + } + else if (e.Y < _imageGallery.ClientRectangle.Top) + { + scrollTimer.Tag = SystemInformation.MouseWheelScrollDelta; + scrollTimer.Enabled = true; + } + } + else if (MouseSelecting && _imageGallery.ScrollOrientation == ScrollOrientation.HorizontalScroll && !scrollTimer.Enabled) + { + if (e.X > _imageGallery.ClientRectangle.Right) + { + scrollTimer.Tag = -SystemInformation.MouseWheelScrollDelta; + scrollTimer.Enabled = true; + } + else if (e.X < _imageGallery.ClientRectangle.Left) + { + scrollTimer.Tag = SystemInformation.MouseWheelScrollDelta; + scrollTimer.Enabled = true; + } + } + else if (scrollTimer.Enabled && _imageGallery.ClientRectangle.Contains(e.Location)) + { + scrollTimer.Enabled = false; + } + + + if (MouseSelecting) + { + if (!ShiftKey && !ControlKey) + _imageGallery.SelectedItems.Clear(false); + + // Create the selection rectangle + var viewOffset = _imageGallery.ViewOffset; + var pt1 = new Point( + lastMouseDownLocation.X - (viewOffset.X - lastViewOffset.X), + lastMouseDownLocation.Y - (viewOffset.Y - lastViewOffset.Y)); + var pt2 = new Point(e.Location.X, e.Location.Y); + SelectionRectangle = new Rectangle(Math.Min(pt1.X, pt2.X), Math.Min(pt1.Y, pt2.Y), Math.Abs(pt1.X - pt2.X), Math.Abs(pt1.Y - pt2.Y)); + + // Determine which items are highlighted + highlightedItems.Clear(); + + // Normalize to item area coordinates + pt1 = new Point(SelectionRectangle.Left, SelectionRectangle.Top); + pt2 = new Point(SelectionRectangle.Right, SelectionRectangle.Bottom); + var itemAreaOffset = new Point( + -_imageGallery.layoutManager.ItemAreaBounds.Left, + -_imageGallery.layoutManager.ItemAreaBounds.Top); + pt1.Offset(itemAreaOffset); + pt2.Offset(itemAreaOffset); + + var startRow = (int)Math.Floor((Math.Min(pt1.Y, pt2.Y) + viewOffset.Y) / + (float)_imageGallery.layoutManager.ItemSizeWithMargin.Height); + var endRow = (int)Math.Floor((Math.Max(pt1.Y, pt2.Y) + viewOffset.Y) / + (float)_imageGallery.layoutManager.ItemSizeWithMargin.Height); + var startCol = (int)Math.Floor((Math.Min(pt1.X, pt2.X) + viewOffset.X) / + (float)_imageGallery.layoutManager.ItemSizeWithMargin.Width); + var endCol = (int)Math.Floor((Math.Max(pt1.X, pt2.X) + viewOffset.X) / + (float)_imageGallery.layoutManager.ItemSizeWithMargin.Width); + + if (_imageGallery.ScrollOrientation == ScrollOrientation.HorizontalScroll + && (startRow >= 0 || endRow >= 0)) + { + for (int i = startCol; i <= endCol; i++) + { + if (i >= 0 + && i <= _imageGallery.Items.Count - 1 + && !highlightedItems.ContainsKey(_imageGallery.Items[i]) + && _imageGallery.Items[i].Enabled) + { + highlightedItems.Add( + _imageGallery.Items[i], + !ControlKey || !_imageGallery.Items[i].Selected); + } + } + } + else if (_imageGallery.ScrollOrientation == ScrollOrientation.VerticalScroll + && (startCol >= 0 || endCol >= 0) + && (startRow >= 0 || endRow >= 0) + && (startCol <= _imageGallery.layoutManager.Cols - 1 || endCol <= _imageGallery.layoutManager.Cols - 1)) + { + startCol = Math.Min(_imageGallery.layoutManager.Cols - 1, Math.Max(0, startCol)); + endCol = Math.Min(_imageGallery.layoutManager.Cols - 1, Math.Max(0, endCol)); + + for (int row = startRow; row <= endRow; row++) + { + for (int col = startCol; col <= endCol; col++) + { + int i = row * _imageGallery.layoutManager.Cols + col; + if (i >= 0 + && i <= _imageGallery.Items.Count - 1 + && !highlightedItems.ContainsKey(_imageGallery.Items[i]) + && _imageGallery.Items[i].Enabled) + { + highlightedItems.Add( + _imageGallery.Items[i], + !ControlKey || !_imageGallery.Items[i].Selected); + } + } + } + } + + + _imageGallery.Refresh(); + } + else if (!MouseSelecting + && inItemArea + && lastMouseDownInItemArea + && (LeftButton || RightButton) + && (Math.Abs(e.Location.X - lastMouseDownLocation.X) > SystemInformation.DragSize.Width + || Math.Abs(e.Location.Y - lastMouseDownLocation.Y) > SystemInformation.DragSize.Height)) + { + if (_imageGallery.MultiSelect && !lastMouseDownOverItem && HoveredItem == null) + { + // Start mouse selection + MouseSelecting = true; + SelectionRectangle = new Rectangle(lastMouseDownLocation, new Size(0, 0)); + _imageGallery.Refresh(); + } + else if (lastMouseDownOverItem && HoveredItem != null + && (_imageGallery.AllowItemReorder || _imageGallery.AllowDrag)) + { + // Start drag&drop + if (!HoveredItem.Selected) + { + _imageGallery.SelectedItems.Clear(false); + HoveredItem.mSelected = true; + _imageGallery.OnSelectionChangedInternal(); + DropTarget = null; + _imageGallery.Refresh(true); + } + + DropTarget = null; + selfDragging = true; + var oldAllowDrop = _imageGallery.AllowDrop; + _imageGallery.AllowDrop = true; + + if (_imageGallery.AllowDrag) + { + // Set drag data + var filenames = new List(); + foreach (var item in _imageGallery.SelectedItems) + { + // Get the source image + var sourceFile = item.Adaptor.GetSourceImage(item.VirtualKey); + if (!string.IsNullOrEmpty(sourceFile)) + filenames.Add(sourceFile); + } + var data = new DataObject(DataFormats.FileDrop, filenames.ToArray()); + _imageGallery.DoDragDrop(data, DragDropEffects.All); + } + else + { + _imageGallery.DoDragDrop(new object(), DragDropEffects.Move); + } + _imageGallery.AllowDrop = oldAllowDrop; + selfDragging = false; + + + // Since the MouseUp event will be eaten by DoDragDrop we will not receive + // the MouseUp event. We need to manually update mouse button flags after + // the drop. + if ((MouseButtons & MouseButtons.Left) == MouseButtons.None) + LeftButton = false; + if ((MouseButtons & MouseButtons.Right) == MouseButtons.None) + RightButton = false; + } + } + + else if (!ReferenceEquals(HoveredItem, oldHoveredItem)) + { + // Hovered item changed + if (!ReferenceEquals(HoveredItem, oldHoveredItem)) + _imageGallery.OnItemHover(new ItemHoverEventArgs(HoveredItem, oldHoveredItem)); + + _imageGallery.Refresh(); + } + + + // unselect the dragged items + _imageGallery.SelectedItems.Clear(); + _imageGallery.Refresh(); + + // set cursor for resizer + if (_imageGallery.Resizer != ResizerType.None) + { + _imageGallery.Refresh(); + UpdateCursor(); + } + + _imageGallery.ResumePaint(); + } + + /// + /// Handles control's MouseUp event. + /// + public void MouseUp(MouseEventArgs e) + { + MouseState = MouseState.Hovered; + + DoHitTest(e.Location); + _imageGallery.SuspendPaint(); + + // Stop if we are scrolling + if (scrollTimer.Enabled) + scrollTimer.Enabled = false; + + if (MouseSelecting) + { + // Apply highlighted items + if (highlightedItems.Count != 0) + { + foreach (KeyValuePair pair in highlightedItems) + { + if (pair.Key.Enabled) + pair.Key.mSelected = pair.Value; + } + highlightedItems.Clear(); + } + + _imageGallery.OnSelectionChangedInternal(); + + MouseSelecting = false; + _imageGallery.Refresh(); + } + else if (_imageGallery.AllowCheckBoxClick + && lastMouseDownInItemArea + && lastMouseDownOverCheckBox + && HoveredItem != null + && overCheckBox + && LeftButton) + { + if (HoveredItem.Selected) + { + // if multiple items selected and Hovered item among selected, + // then give all selected check state !HoveredItem.Checked + bool check = !HoveredItem.Checked; + foreach (ImageGalleryItem item in _imageGallery.Items) + { + if (item.Selected) + item.Checked = check; + } + } + else + { + // if multiple items selected and HoveredItem NOT among selected, + // or if only HoveredItem selected or hovered + // then toggle HoveredItem.Checked + HoveredItem.Checked = !HoveredItem.Checked; + } + _imageGallery.Refresh(); + } + else if (lastMouseDownInItemArea + && lastMouseDownOverItem + && HoveredItem != null + && LeftButton) + { + // Select the item under the cursor + if (!_imageGallery.MultiSelect && ControlKey) + { + bool oldSelected = HoveredItem.Selected; + _imageGallery.SelectedItems.Clear(false); + HoveredItem.mSelected = !oldSelected; + } + else if (!_imageGallery.MultiSelect) + { + _imageGallery.SelectedItems.Clear(false); + HoveredItem.mSelected = true; + } + else if (ControlKey) + { + HoveredItem.mSelected = !HoveredItem.mSelected; + } + else if (ShiftKey) + { + var startIndex = 0; + if (_imageGallery.SelectedItems.Count != 0) + { + startIndex = _imageGallery.SelectedItems[0].Index; + _imageGallery.SelectedItems.Clear(false); + } + + var endIndex = HoveredItem.Index; + if (_imageGallery.ScrollOrientation == ScrollOrientation.VerticalScroll) + { + var startRow = Math.Min(startIndex, endIndex) / _imageGallery.layoutManager.Cols; + var endRow = Math.Max(startIndex, endIndex) / _imageGallery.layoutManager.Cols; + var startCol = Math.Min(startIndex, endIndex) % _imageGallery.layoutManager.Cols; + var endCol = Math.Max(startIndex, endIndex) % _imageGallery.layoutManager.Cols; + + for (var row = startRow; row <= endRow; row++) + { + for (var col = startCol; col <= endCol; col++) + { + var index = row * _imageGallery.layoutManager.Cols + col; + _imageGallery.Items[index].mSelected = true; + } + } + } + else + { + for (var i = Math.Min(startIndex, endIndex); i <= Math.Max(startIndex, endIndex); i++) + { + _imageGallery.Items[i].mSelected = true; + } + } + } + else + { + _imageGallery.SelectedItems.Clear(false); + HoveredItem.mSelected = true; + } + + // Raise the selection change event + _imageGallery.OnSelectionChangedInternal(); + + // Set the item as the focused item + _imageGallery.Items.FocusedItem = HoveredItem; + + _imageGallery.Refresh(); + } + else if (lastMouseDownInItemArea + && lastMouseDownOverItem + && HoveredItem != null + && RightButton) + { + if (!ControlKey && !HoveredItem.Selected) + { + // Clear the selection if Control key is not pressed + _imageGallery.SelectedItems.Clear(false); + HoveredItem.mSelected = true; + _imageGallery.OnSelectionChangedInternal(); + } + } + else if (lastMouseDownInItemArea + && inItemArea + && HoveredItem == null + && (LeftButton || RightButton)) + { + // Clear selection if clicked in empty space + _imageGallery.SelectedItems.Clear(); + _imageGallery.Refresh(); + } + + if (HoveredItem != null) + { + HoveredItem.Pressed = false; + _imageGallery.OnItemClick(new ItemClickEventArgs(HoveredItem, e.Location, e.Button)); + } + + if ((e.Button & MouseButtons.Left) != MouseButtons.None) + LeftButton = false; + if ((e.Button & MouseButtons.Right) != MouseButtons.None) + RightButton = false; + + + if (e.Button.HasFlag(MouseButtons.Middle)) + { + // unselect the dragged items + _imageGallery.SelectedItems.Clear(); + _imageGallery.Refresh(); + } + + _imageGallery.ResumePaint(); + } + + /// + /// Handles control's MouseDoubleClick event. + /// + public void MouseDoubleClick(MouseEventArgs e) + { + if (e.Button == MouseButtons.Middle) return; + if (lastMouseDownInItemArea && lastMouseDownOverItem && HoveredItem != null) + { + _imageGallery.OnItemDoubleClick(new ItemClickEventArgs(HoveredItem, e.Location, e.Button)); + } + } + + /// + /// Handles control's MouseLeave event. + /// + public void MouseLeave() + { + MouseState = MouseState.Normal; + + if (HoveredItem != null) + { + if (HoveredItem != null) + { + _imageGallery.OnItemHover(new ItemHoverEventArgs(null, HoveredItem)); + HoveredItem.Pressed = false; + } + + HoveredItem = null; + _imageGallery.Refresh(); + } + + if (_imageGallery.Resizer != ResizerType.None) + { + IsResizerHit = false; + _imageGallery.Refresh(); + UpdateCursor(); + } + } + + #endregion + + + #region Key Event Handlers + /// + /// Handles control's KeyDown event. + /// + public void KeyDown(KeyEventArgs e) + { + if (!_imageGallery.EnableKeyNavigation) + { + return; + } + + ShiftKey = (e.Modifiers & Keys.Shift) == Keys.Shift; + ControlKey = (e.Modifiers & Keys.Control) == Keys.Control; + + _imageGallery.SuspendPaint(); + + // If the shift key or the control key is pressed and there is no focused item + // set the first item as the focused item. + if ((ShiftKey || ControlKey) + && _imageGallery.Items.Count != 0 + && _imageGallery.Items.FocusedItem == null) + { + _imageGallery.Items.FocusedItem = _imageGallery.Items[0]; + _imageGallery.Refresh(); + } + + if (_imageGallery.Items.Count != 0) + { + var index = 0; + if (_imageGallery.Items.FocusedItem != null) + index = _imageGallery.Items.FocusedItem.Index; + + var newindex = ApplyNavKey(index, e.KeyCode); + if (index != newindex) + { + if (ControlKey) + { + // Just move the focus + } + else if (_imageGallery.MultiSelect && ShiftKey) + { + var startIndex = 0; + var endIndex = 0; + var selCount = _imageGallery.SelectedItems.Count; + if (selCount != 0) + { + startIndex = _imageGallery.SelectedItems[0].Index; + endIndex = _imageGallery.SelectedItems[selCount - 1].Index; + _imageGallery.SelectedItems.Clear(false); + } + + if (newindex > index) // Moving right or down + { + if (newindex > endIndex) + endIndex = newindex; + else + startIndex = newindex; + } + else // Moving left or up + { + if (newindex < startIndex) + startIndex = newindex; + else + endIndex = newindex; + } + + for (var i = Math.Min(startIndex, endIndex); i <= Math.Max(startIndex, endIndex); i++) + { + if (_imageGallery.Items[i].mEnabled) + _imageGallery.Items[i].mSelected = true; + } + _imageGallery.OnSelectionChangedInternal(); + } + else if (_imageGallery.Items[newindex].mEnabled) + { + _imageGallery.SelectedItems.Clear(false); + _imageGallery.Items[newindex].mSelected = true; + _imageGallery.OnSelectionChangedInternal(); + } + _imageGallery.Items.FocusedItem = _imageGallery.Items[newindex]; + _imageGallery.ScrollToIndex(newindex); + _imageGallery.Refresh(); + } + } + + _imageGallery.ResumePaint(); + } + + /// + /// Handles control's KeyUp event. + /// + public void KeyUp(KeyEventArgs e) + { + ShiftKey = (e.Modifiers & Keys.Shift) == Keys.Shift; + ControlKey = (e.Modifiers & Keys.Control) == Keys.Control; + } + + #endregion + + + #region Drag and Drop Event Handlers + /// + /// Handles control's DragDrop event. + /// + public void DragDrop(DragEventArgs e) + { + _imageGallery.SuspendPaint(); + + if (selfDragging) + { + int index = -1; + if (DropTarget != null) index = DropTarget.Index; + if (DropToRight) index++; + if (index > _imageGallery.Items.Count) + { + index = _imageGallery.Items.Count; + } + + if (index != -1) + { + var i = 0; + var draggedItems = new ImageGalleryItem[_imageGallery.SelectedItems.Count]; + foreach (var item in _imageGallery.SelectedItems) + { + draggedItems[i] = item; + i++; + } + + _imageGallery.OnDropItems(new DropItemEventArgs(index, draggedItems)); + } + } + else + { + var index = _imageGallery.Items.Count; + if (DropTarget != null) index = DropTarget.Index; + if (DropToRight) index++; + if (index > _imageGallery.Items.Count) + index = _imageGallery.Items.Count; + + if (index != -1) + { + if (e.Data != null && e.Data.GetDataPresent(DataFormats.FileDrop)) + { + var filenames = (string[]?)e.Data.GetData(DataFormats.FileDrop); + + _imageGallery.OnDropFiles(new DropFileEventArgs(index, filenames ?? [])); + } + } + } + + DropTarget = null; + selfDragging = false; + + _imageGallery.Refresh(); + _imageGallery.ResumePaint(); + } + + /// + /// Handles control's DragEnter event. + /// + public void DragEnter(DragEventArgs e) + { + if (selfDragging) + e.Effect = DragDropEffects.Move; + else if (e.Data != null && e.Data.GetDataPresent(DataFormats.FileDrop)) + e.Effect = DragDropEffects.Copy; + else + e.Effect = DragDropEffects.None; + } + + /// + /// Handles control's DragOver event. + /// + public void DragOver(DragEventArgs e) + { + if ((selfDragging && _imageGallery.AllowItemReorder) + || (!selfDragging + && _imageGallery.AllowDrop + && e.Data != null + && e.Data.GetDataPresent(DataFormats.FileDrop))) + { + if (_imageGallery.Items.Count == 0) + { + if (selfDragging) + e.Effect = DragDropEffects.None; + else + e.Effect = DragDropEffects.Copy; + } + else if (_imageGallery.AllowItemReorder) + { + // Calculate the location of the insertion cursor + var pt = new Point(e.X, e.Y); + pt = _imageGallery.PointToClient(pt); + + // Do we need to scroll the view? + if (_imageGallery.ScrollOrientation == ScrollOrientation.VerticalScroll && + pt.Y > _imageGallery.ClientRectangle.Bottom - 20) + { + scrollTimer.Tag = -SystemInformation.MouseWheelScrollDelta; + scrollTimer.Enabled = true; + } + else if (_imageGallery.ScrollOrientation == ScrollOrientation.VerticalScroll + && pt.Y < _imageGallery.ClientRectangle.Top + 20) + { + scrollTimer.Tag = SystemInformation.MouseWheelScrollDelta; + scrollTimer.Enabled = true; + } + else if (_imageGallery.ScrollOrientation == ScrollOrientation.HorizontalScroll + && pt.X > _imageGallery.ClientRectangle.Right - 20) + { + scrollTimer.Tag = -SystemInformation.MouseWheelScrollDelta; + scrollTimer.Enabled = true; + } + else if (_imageGallery.ScrollOrientation == ScrollOrientation.HorizontalScroll + && pt.X < _imageGallery.ClientRectangle.Left + 20) + { + scrollTimer.Tag = SystemInformation.MouseWheelScrollDelta; + scrollTimer.Enabled = true; + } + else + { + scrollTimer.Enabled = false; + } + + // Normalize to item area coordinates + pt.X -= _imageGallery.layoutManager.ItemAreaBounds.Left; + pt.Y -= _imageGallery.layoutManager.ItemAreaBounds.Top; + + // Row and column mouse is over + bool dragCaretOnRight = false; + int index; + + if (_imageGallery.ScrollOrientation == ScrollOrientation.HorizontalScroll) + { + index = (pt.X + _imageGallery.ViewOffset.X) / _imageGallery.layoutManager.ItemSizeWithMargin.Width; + } + else + { + int col = pt.X / _imageGallery.layoutManager.ItemSizeWithMargin.Width; + int row = (pt.Y + _imageGallery.ViewOffset.Y) / _imageGallery.layoutManager.ItemSizeWithMargin.Height; + if (col > _imageGallery.layoutManager.Cols - 1) + { + col = _imageGallery.layoutManager.Cols - 1; + dragCaretOnRight = true; + } + index = row * _imageGallery.layoutManager.Cols + col; + } + + if (index < 0) index = 0; + if (index > _imageGallery.Items.Count - 1) + { + index = _imageGallery.Items.Count - 1; + dragCaretOnRight = true; + } + + var dragDropTarget = _imageGallery.Items[index]; + + if (selfDragging && (dragDropTarget.Selected || + (!dragCaretOnRight && index > 0 && _imageGallery.Items[index - 1].Selected) || + (dragCaretOnRight && index < _imageGallery.Items.Count - 1 && _imageGallery.Items[index + 1].Selected))) + { + e.Effect = DragDropEffects.None; + + dragDropTarget = null; + } + else if (selfDragging) + e.Effect = DragDropEffects.Move; + else + e.Effect = DragDropEffects.Copy; + + if (!ReferenceEquals(dragDropTarget, DropTarget) || dragCaretOnRight != DropToRight) + { + DropTarget = dragDropTarget; + DropToRight = dragCaretOnRight; + _imageGallery.Refresh(true); + } + } + else + { + e.Effect = DragDropEffects.Copy; + } + } + else + e.Effect = DragDropEffects.None; + } + + /// + /// Handles control's DragLeave event. + /// + public void DragLeave() + { + DropTarget = null; + _imageGallery.Refresh(true); + + if (scrollTimer.Enabled) + scrollTimer.Enabled = false; + } + + #endregion + + + #region Helper Methods + /// + /// Performs a hit test. + /// + private void DoHitTest(Point pt) + { + _imageGallery.HitTest(pt, out HitInfo h); + + if (h.IsItemHit && _imageGallery.Items[h.ItemIndex].Enabled) + { + HoveredItem = _imageGallery.Items[h.ItemIndex]; + } + else + { + HoveredItem = null; + } + + inItemArea = h.IsInItemArea; + overCheckBox = h.IsCheckBoxHit; + IsResizerHit = h.IsResizerHit; + } + + /// + /// Returns the item index after applying the given navigation key. + /// + private int ApplyNavKey(int index, Keys key) + { + if (_imageGallery.ScrollOrientation == ScrollOrientation.VerticalScroll) + { + if (key == Keys.Up && index >= _imageGallery.layoutManager.Cols) + index -= _imageGallery.layoutManager.Cols; + else if (key == Keys.Down && index < _imageGallery.Items.Count - _imageGallery.layoutManager.Cols) + index += _imageGallery.layoutManager.Cols; + else if (key == Keys.Left && index > 0) + index--; + else if (key == Keys.Right && index < _imageGallery.Items.Count - 1) + index++; + else if (key == Keys.PageUp && index >= _imageGallery.layoutManager.Cols * (_imageGallery.layoutManager.Rows - 1)) + index -= _imageGallery.layoutManager.Cols * (_imageGallery.layoutManager.Rows - 1); + else if (key == Keys.PageDown && index < _imageGallery.Items.Count - _imageGallery.layoutManager.Cols * (_imageGallery.layoutManager.Rows - 1)) + index += _imageGallery.layoutManager.Cols * (_imageGallery.layoutManager.Rows - 1); + else if (key == Keys.Home) + index = 0; + else if (key == Keys.End) + index = _imageGallery.Items.Count - 1; + } + else + { + if (key == Keys.Left && index > 0) + index--; + else if (key == Keys.Right && index < _imageGallery.Items.Count - 1) + index++; + else if (key == Keys.PageUp && index >= _imageGallery.layoutManager.Cols) + index -= _imageGallery.layoutManager.Cols; + else if (key == Keys.PageDown && index < _imageGallery.Items.Count - _imageGallery.layoutManager.Cols) + index += _imageGallery.layoutManager.Cols; + else if (key == Keys.Home) + index = 0; + else if (key == Keys.End) + index = _imageGallery.Items.Count - 1; + } + + if (index < 0) + index = 0; + else if (index > _imageGallery.Items.Count - 1) + index = _imageGallery.Items.Count - 1; + + return index; + } + + + private void UpdateCursor() + { + if (!IsResizerHit) _imageGallery.Cursor = Cursors.Default; + else + { + if (_imageGallery.Resizer == ResizerType.HTTOP + || _imageGallery.Resizer == ResizerType.HTBOTTOM) + { + _imageGallery.Cursor = Cursors.SizeNS; + } + else if (_imageGallery.Resizer == ResizerType.HTLEFT + || _imageGallery.Resizer == ResizerType.HTRIGHT) + { + _imageGallery.Cursor = Cursors.SizeWE; + } + else + { + _imageGallery.Cursor = Cursors.Arrow; + } + } + } + + #endregion + + + #region Scroll Timer + /// + /// Handles the Tick event of the scrollTimer control. + /// + private void ScrollTimer_Tick(object? sender, EventArgs e) + { + var delta = (int?)scrollTimer.Tag ?? SystemInformation.MouseWheelScrollDelta; + var location = _imageGallery.PointToClient(MousePosition); + + _imageGallery.OnMouseMove(new(MouseButtons, 0, location.X, location.Y, 0)); + _imageGallery.OnMouseWheel(new(MouseButtons.None, 0, location.X, location.Y, delta)); + } + + #endregion + + } + +} \ No newline at end of file diff --git a/Source/Components/ImageGlass.Gallery/Renderer/Renderers.cs b/Source/Components/ImageGlass.Gallery/Renderer/Renderers.cs new file mode 100644 index 000000000..a61cce337 --- /dev/null +++ b/Source/Components/ImageGlass.Gallery/Renderer/Renderers.cs @@ -0,0 +1,289 @@ +/* +ImageGlass Project - Image viewer for Windows +Copyright (C) 2010 - 2026 DUONG DIEU PHAP +Project homepage: https://imageglass.org + +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 . + +--------------------- +ImageGlass.Gallery is based on ImageListView v13.8.2: +Url: https://github.com/oozcitak/imagelistview +License: Apache License Version 2.0, http://www.apache.org/licenses/ +--------------------- +*/ +using System.Windows.Forms.VisualStyles; + +namespace ImageGlass.Gallery; + + +#region DefaultRenderer +/// +/// The default renderer. +/// +public class DefaultRenderer : StyleRenderer +{ + /// + /// Initializes a new instance of the DefaultRenderer class. + /// + public DefaultRenderer() { } +} +#endregion + + +#region SystemRenderer +/// +/// Displays the control in the current system theme. +/// This renderer cannot be themed. +/// +public class SystemRenderer : StyleRenderer +{ + // Check boxes + private readonly VisualStyleRenderer? rCheckedNormal = null; + private readonly VisualStyleRenderer? rUncheckedNormal = null; + private readonly VisualStyleRenderer? rCheckedDisabled = null; + private readonly VisualStyleRenderer? rUncheckedDisabled = null; + + // File icons + private VisualStyleRenderer? rFileIcon = null; + + // Items + private readonly VisualStyleRenderer? rItemNormal = null; + private readonly VisualStyleRenderer? rItemHovered = null; + private readonly VisualStyleRenderer? rItemPressed = null; + private readonly VisualStyleRenderer? rItemSelected = null; + private readonly VisualStyleRenderer? rItemHoveredSelected = null; + private readonly VisualStyleRenderer? rItemSelectedHidden = null; + private readonly VisualStyleRenderer? rItemDisabled = null; + + /// + /// Gets whether visual styles are supported. + /// + public bool VisualStylesEnabled { get; private set; } + + /// + /// Gets a value indicating whether this renderer can apply custom colors. + /// + /// + public override bool CanApplyColors { get { return false; } } + + /// + /// Initializes a new instance of the ThemeRenderer class. + /// + public SystemRenderer() + { + VisualStylesEnabled = Application.RenderWithVisualStyles; + + // Create renderers + if (VisualStylesEnabled) + { + // See https://docs.microsoft.com/en-us/windows/win32/controls/parts-and-states + // for part and state codes used below. + + // Check boxes + rCheckedNormal = GetRenderer(VisualStyleElement.Button.CheckBox.CheckedNormal); + rUncheckedNormal = GetRenderer(VisualStyleElement.Button.CheckBox.UncheckedNormal); + rCheckedDisabled = GetRenderer(VisualStyleElement.Button.CheckBox.CheckedDisabled); + rUncheckedDisabled = GetRenderer(VisualStyleElement.Button.CheckBox.UncheckedDisabled); + + // File icons + rFileIcon = GetRenderer(VisualStyleElement.Button.PushButton.Normal); + + // Items + rItemNormal = GetRenderer("Explorer::ListView", 1, 1); + rItemHovered = GetRenderer("Explorer::ListView", 1, 2); + rItemPressed = GetRenderer("Explorer::ListView", 1, 3); + rItemSelected = GetRenderer("Explorer::ListView", 1, 3); + rItemHoveredSelected = GetRenderer("Explorer::ListView", 1, 6); + rItemSelectedHidden = GetRenderer("Explorer::ListView", 1, 5); + rItemDisabled = GetRenderer("Explorer::ListView", 1, 4); + } + } + + /// + /// Returns a renderer for the given element. + /// + private static VisualStyleRenderer? GetRenderer(VisualStyleElement e) + { + if (VisualStyleRenderer.IsElementDefined(e)) + return new VisualStyleRenderer(e); + else + return null; + } + + /// + /// Returns a renderer for the given element. + /// + private static VisualStyleRenderer? GetRenderer(string className, int part, int state) + { + var e = VisualStyleElement.CreateElement(className, part, state); + if (VisualStyleRenderer.IsElementDefined(e)) + return new VisualStyleRenderer(e); + else + return null; + } + + /// + /// Draws the checkbox icon for the specified item on the given graphics. + /// + /// The System.Drawing.Graphics to draw on. + /// The to draw. + /// The bounding rectangle of the checkbox in client coordinates. + public override void DrawCheckBox(Graphics g, ImageGalleryItem item, Rectangle bounds) + { + VisualStyleRenderer? renderer; + if (item.Enabled) + { + if (item.Checked) + renderer = rCheckedNormal; + else + renderer = rUncheckedNormal; + } + else + { + if (item.Checked) + renderer = rCheckedDisabled; + else + renderer = rUncheckedDisabled; + } + + if (VisualStylesEnabled && renderer != null) + renderer.DrawBackground(g, bounds, bounds); + else + base.DrawCheckBox(g, item, bounds); + } + + /// + /// Draws the file icon for the specified item on the given graphics. + /// + /// The System.Drawing.Graphics to draw on. + /// The to draw. + /// The bounding rectangle of the file icon in client coordinates. + public override void DrawFileIcon(Graphics g, ImageGalleryItem item, Rectangle bounds) + { + var icon = item.GetCachedImage(CachedImageType.SmallIcon); + + if (icon != null && VisualStylesEnabled && rFileIcon != null) + rFileIcon.DrawImage(g, bounds, icon); + else + base.DrawFileIcon(g, item, bounds); + } + + + /// + /// [IG_CHANGE] Returns item size for the given view mode. + /// + /// The view mode for which the measurement should be made. + /// The item size. + public override Size MeasureItem(View view) + { + Size sz = base.MeasureItem(view); + + //sz.Width += 6; + //sz.Height += 6; + int textHeight = ImageGalleryOwner.Font.Height; + + sz.Width += textHeight * 2 / 5; + sz.Height -= textHeight / 2; + + return sz; + } + + /// + /// [IG_CHANGE] Draws the specified item on the given graphics. + /// + /// The System.Drawing.Graphics to draw on. + /// The to draw. + /// The current view state of item. + /// The bounding rectangle of item in client coordinates. + public override void DrawItem(Graphics g, ImageGalleryItem item, ItemState state, Rectangle bounds) + { + VisualStyleRenderer? rBack; + + if (!ImageGalleryOwner.Enabled) + { + rBack = rItemSelectedHidden; + } + + if ((state & ItemState.Disabled) != ItemState.None) + { + rBack = rItemDisabled; + } + else if (!ImageGalleryOwner.Focused && ((state & ItemState.Selected) != ItemState.None)) + { + rBack = rItemSelectedHidden; + } + else if (((state & ItemState.Selected) != ItemState.None) && ((state & ItemState.Hovered) != ItemState.None)) + { + rBack = rItemHoveredSelected; + } + else if ((state & ItemState.Selected) != ItemState.None) + { + rBack = rItemSelected; + } + else if ((state & ItemState.Pressed) != ItemState.None) + { + rBack = rItemPressed; + } + else if ((state & ItemState.Hovered) != ItemState.None) + { + rBack = rItemHovered; + } + else + { + rBack = rItemNormal; + } + + if (VisualStylesEnabled && rBack != null) + { + // Do not draw the background of normal items + if (((state & ItemState.Hovered) != ItemState.None) || ((state & ItemState.Selected) != ItemState.None)) + rBack.DrawBackground(g, bounds, bounds); + + // Size itemPadding = new Size(7, 7); + var itemPadding = new Size(5, 5); + + // Draw the image + var img = item.GetCachedImage(CachedImageType.Thumbnail); + if (img != null) + { + var pos = Utility.GetSizedImageBounds(img, + new Rectangle(bounds.Location + itemPadding, + new Size(bounds.Width - 2 * itemPadding.Width, bounds.Height - 2 * itemPadding.Width))); + + // Image background + var imgback = pos; + imgback.Inflate(3, 3); + + // Image + g.DrawImage(img, pos); + } + + // Focus rectangle + if (ImageGalleryOwner.Focused && ((state & ItemState.Focused) != ItemState.None)) + { + Rectangle focusBounds = bounds; + focusBounds.Inflate(-2, -2); + ControlPaint.DrawFocusRectangle(g, focusBounds); + } + + } + else + { + base.DrawItem(g, item, state, bounds); + } + } + +} +#endregion + diff --git a/Source/Components/ImageGlass.Gallery/Renderer/StyleRenderer.cs b/Source/Components/ImageGlass.Gallery/Renderer/StyleRenderer.cs new file mode 100644 index 000000000..72281d7ff --- /dev/null +++ b/Source/Components/ImageGlass.Gallery/Renderer/StyleRenderer.cs @@ -0,0 +1,1113 @@ +/* +ImageGlass Project - Image viewer for Windows +Copyright (C) 2010 - 2026 DUONG DIEU PHAP +Project homepage: https://imageglass.org + +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 . + +--------------------- +ImageGlass.Gallery is based on ImageListView v13.8.2: +Url: https://github.com/oozcitak/imagelistview +License: Apache License Version 2.0, http://www.apache.org/licenses/ +--------------------- +*/ +using ImageGlass.Base; +using ImageGlass.Base.WinApi; +using System.Drawing.Drawing2D; +using System.Windows.Forms.VisualStyles; + +namespace ImageGlass.Gallery; + + +/// +/// Represents an overridable class for image list view renderers. +/// +public class StyleRenderer : IDisposable +{ + #region Constants + /// + /// Represents the time in milliseconds after which the control deems to be needing a refresh. + /// + internal const int LazyRefreshInterval = 100; + #endregion + + + #region Member Variables + private BufferedGraphics? bufferGraphics; + private bool disposed; + private bool creatingGraphics; + private DateTime lastRenderTime; + #endregion + + + #region Properties + /// + /// Gets the owning this item. + /// + public ImageGallery ImageGalleryOwner { get; internal set; } + + /// + /// Gets or sets whether the graphics is clipped to the bounds of + /// drawing elements. + /// + public bool Clip { get; set; } + + /// + /// Gets or sets the order by which items are drawn. + /// + public ItemDrawOrder ItemDrawOrder { get; set; } + + /// + /// Gets or sets whether items are drawn before of after headers and the gallery images. + /// + public bool ItemsDrawnFirst { get; set; } + + /// + /// Gets the rectangle bounding the client area of the control without the scroll bars. + /// + public Rectangle ClientBounds { get { return ImageGalleryOwner.layoutManager.ClientArea; } } + + /// + /// Gets the rectangle bounding the item display area. + /// + public Rectangle ItemAreaBounds { get { return ImageGalleryOwner.layoutManager.ItemAreaBounds; } } + + /// + /// Gets a value indicating whether this renderer can apply custom colors. + /// + public virtual bool CanApplyColors { get { return true; } } + + /// + /// Gets whether the lazy refresh interval is exceeded. + /// + internal bool LazyRefreshIntervalExceeded { get { return ((int)(DateTime.UtcNow - lastRenderTime).TotalMilliseconds > LazyRefreshInterval); } } + + #endregion + + + #region Constructor + /// + /// Initializes a new instance of the class. + /// + public StyleRenderer() + { + creatingGraphics = false; + disposed = false; + Clip = true; + ItemsDrawnFirst = false; + ItemDrawOrder = ItemDrawOrder.ItemIndex; + lastRenderTime = DateTime.MinValue; + } + + #endregion + + + #region DrawItemParams + /// + /// Represents the paramaters required to draw an item. + /// + private struct DrawItemParams + { + public ImageGalleryItem Item; + public ItemState State; + public Rectangle Bounds; + + public DrawItemParams(ImageGalleryItem item, ItemState state, Rectangle bounds) + { + Item = item; + State = state; + Bounds = bounds; + } + + } + + #endregion + + + #region ItemDrawOrderComparer + /// + /// Compares items by the draw order. + /// + private class ItemDrawOrderComparer : IComparer + { + private readonly ItemDrawOrder mDrawOrder; + + public ItemDrawOrderComparer(ItemDrawOrder drawOrder) + { + mDrawOrder = drawOrder; + } + + /// + /// Compares items by the draw order. + /// + /// First item to compare. + /// Second item to compare. + /// 1 if the first item should be drawn first, + /// -1 if the second item should be drawn first, + /// 0 if the two items can be drawn in any order. + public int Compare(DrawItemParams param1, DrawItemParams param2) + { + if (param1.Equals(param2)) + return 0; + if (ReferenceEquals(param1.Item, param2.Item)) + return 0; + + int comparison; + + if (mDrawOrder == ItemDrawOrder.ItemIndex) + { + return CompareByIndex(param1, param2); + } + else if (mDrawOrder == ItemDrawOrder.ZOrder) + { + return CompareByZOrder(param1, param2); + } + else if (mDrawOrder == ItemDrawOrder.NormalSelectedHovered) + { + comparison = -CompareByHovered(param1, param2); + if (comparison != 0) return comparison; + comparison = -CompareBySelected(param1, param2); + if (comparison != 0) return comparison; + comparison = -CompareByNormal(param1, param2); + if (comparison != 0) return comparison; + } + else if (mDrawOrder == ItemDrawOrder.NormalHoveredSelected) + { + comparison = -CompareBySelected(param1, param2); + if (comparison != 0) return comparison; + comparison = -CompareByHovered(param1, param2); + if (comparison != 0) return comparison; + comparison = -CompareByNormal(param1, param2); + if (comparison != 0) return comparison; + } + else if (mDrawOrder == ItemDrawOrder.SelectedNormalHovered) + { + comparison = -CompareByHovered(param1, param2); + if (comparison != 0) return comparison; + comparison = -CompareByNormal(param1, param2); + if (comparison != 0) return comparison; + comparison = -CompareBySelected(param1, param2); + if (comparison != 0) return comparison; + } + else if (mDrawOrder == ItemDrawOrder.SelectedHoveredNormal) + { + comparison = -CompareByNormal(param1, param2); + if (comparison != 0) return comparison; + comparison = -CompareByHovered(param1, param2); + if (comparison != 0) return comparison; + comparison = -CompareBySelected(param1, param2); + if (comparison != 0) return comparison; + } + else if (mDrawOrder == ItemDrawOrder.HoveredNormalSelected) + { + comparison = -CompareBySelected(param1, param2); + if (comparison != 0) return comparison; + comparison = -CompareByNormal(param1, param2); + if (comparison != 0) return comparison; + comparison = -CompareByHovered(param1, param2); + if (comparison != 0) return comparison; + } + else if (mDrawOrder == ItemDrawOrder.HoveredSelectedNormal) + { + comparison = -CompareByNormal(param1, param2); + if (comparison != 0) return comparison; + comparison = -CompareBySelected(param1, param2); + if (comparison != 0) return comparison; + comparison = -CompareByHovered(param1, param2); + if (comparison != 0) return comparison; + } + + // Compare by zorder + comparison = CompareByZOrder(param1, param2); + if (comparison != 0) return comparison; + + // Finally compare by index + comparison = CompareByIndex(param1, param2); + return comparison; + } + + /// + /// Compares items by their index property. + /// + private static int CompareByIndex(DrawItemParams param1, DrawItemParams param2) + { + if (param1.Item.Index < param2.Item.Index) + return -1; + else if (param1.Item.Index > param2.Item.Index) + return 1; + else + return 0; + } + + /// + /// Compares items by their zorder property. + /// + private static int CompareByZOrder(DrawItemParams param1, DrawItemParams param2) + { + if (param1.Item.ZOrder < param2.Item.ZOrder) + return -1; + else if (param1.Item.ZOrder > param2.Item.ZOrder) + return 1; + else + return 0; + } + + /// + /// Compares items by their neutral state. + /// + private static int CompareByNormal(DrawItemParams param1, DrawItemParams param2) + { + if (param1.State == ItemState.None && param2.State != ItemState.None) + return -1; + else if (param1.State != ItemState.None && param2.State == ItemState.None) + return 1; + else + return 0; + } + + /// + /// Compares items by their selected state. + /// + private static int CompareBySelected(DrawItemParams param1, DrawItemParams param2) + { + if ((param1.State & ItemState.Selected) == ItemState.Selected && + (param2.State & ItemState.Selected) != ItemState.Selected) + return -1; + else if ((param1.State & ItemState.Selected) != ItemState.Selected && + (param2.State & ItemState.Selected) == ItemState.Selected) + return 1; + else + return 0; + } + + /// + /// Compares items by their hovered state. + /// + private static int CompareByHovered(DrawItemParams param1, DrawItemParams param2) + { + if ((param1.State & ItemState.Hovered) == ItemState.Hovered) + return -1; + else if ((param2.State & ItemState.Hovered) == ItemState.Hovered) + return 1; + else + return 0; + } + + /// + /// Compares items by their focused state. + /// + private int CompareByFocused(DrawItemParams param1, DrawItemParams param2) + { + if ((param1.State & ItemState.Focused) == ItemState.Focused) + return -1; + else if ((param2.State & ItemState.Focused) == ItemState.Focused) + return 1; + else + return 0; + } + } + #endregion + + + #region Instance Methods + /// + /// Reads and returns the image for the given item. + /// + /// The item to read. + /// The size of the requested image.. + /// Item thumbnail of requested size. + public Image? GetImageAsync(ImageGalleryItem item, Size size) + { + var img = ImageGalleryOwner.thumbnailCache.GetRendererImage(item.Guid, size, ImageGalleryOwner.UseEmbeddedThumbnails, + ImageGalleryOwner.AutoRotateThumbnails); + + if (img == null) + { + ImageGalleryOwner.thumbnailCache.AddToRendererCache(item.Guid, item.mAdaptor, item.VirtualKey, + size, ImageGalleryOwner.UseEmbeddedThumbnails, ImageGalleryOwner.AutoRotateThumbnails); + } + + return img; + } + + #endregion + + + #region Internal Methods + /// + /// Renders the border of the control. + /// + /// The graphics to draw on. + private void RenderBorder(Graphics g) + { + // Background + g.ResetClip(); + DrawBorder(g, new Rectangle(0, 0, ImageGalleryOwner.Width, ImageGalleryOwner.Height)); + } + + /// + /// Renders the background of the control. + /// + /// The graphics to draw on. + private void RenderBackground(Graphics g) + { + // Background + g.SetClip(ImageGalleryOwner.layoutManager.ClientArea); + DrawBackground(g, ImageGalleryOwner.layoutManager.ClientArea); + } + + /// + /// Renders the items. + /// + /// The graphics to draw on. + private void RenderItems(Graphics g) + { + // Is the control empty? + if (ImageGalleryOwner.Items.Count == 0) + return; + + // No items visible? + if (ImageGalleryOwner.layoutManager.FirstPartiallyVisible == -1 || + ImageGalleryOwner.layoutManager.LastPartiallyVisible == -1) + return; + + // get items bounds + var drawItemParams = new List(); + for (int i = ImageGalleryOwner.layoutManager.FirstPartiallyVisible; i <= ImageGalleryOwner.layoutManager.LastPartiallyVisible; i++) + { + var item = ImageGalleryOwner.Items[i]; + + // Determine item state + var state = ItemState.None; + var highlightState = ImageGalleryOwner.navigationManager.HighlightState(item); + + if (highlightState == ItemHighlightState.HighlightedAndSelected || + (highlightState == ItemHighlightState.NotHighlighted && item.Selected)) + state |= ItemState.Selected; + + if (ReferenceEquals(ImageGalleryOwner.navigationManager.HoveredItem, item) && + ImageGalleryOwner.navigationManager.MouseSelecting == false) + state |= ItemState.Hovered; + + if (item.Pressed) + state |= ItemState.Pressed; + + if (item.Focused) + state |= ItemState.Focused; + + if (!item.Enabled) + state |= ItemState.Disabled; + + // Get item bounds + var bounds = ImageGalleryOwner.layoutManager.GetItemBounds(i); + + // Add to params to be sorted and drawn + drawItemParams.Add(new DrawItemParams(item, state, bounds)); + } + + // Sort items by draw order + drawItemParams.Sort(new ItemDrawOrderComparer(ItemDrawOrder)); + + // Draw items + foreach (var param in drawItemParams) + { + if (Clip) + { + Rectangle clip = Rectangle.Intersect(param.Bounds, ImageGalleryOwner.layoutManager.ItemAreaBounds); + g.SetClip(clip); + } + else + g.SetClip(ImageGalleryOwner.layoutManager.ClientArea); + + // Draw the item + DrawItem(g, param.Item, param.State, param.Bounds); + + + // Draw the checkbox and file icon + if (ImageGalleryOwner.ShowCheckBoxes) + { + var cBounds = ImageGalleryOwner.layoutManager.GetCheckBoxBounds(param.Item.Index); + if (Clip) + { + var clip = Rectangle.Intersect(cBounds, ImageGalleryOwner.layoutManager.ItemAreaBounds); + g.SetClip(clip); + } + else + g.SetClip(ImageGalleryOwner.layoutManager.ClientArea); + + DrawCheckBox(g, param.Item, cBounds); + } + + if (ImageGalleryOwner.ShowFileIcons) + { + var cBounds = ImageGalleryOwner.layoutManager.GetIconBounds(param.Item.Index); + if (Clip) + { + var clip = Rectangle.Intersect(cBounds, ImageGalleryOwner.layoutManager.ItemAreaBounds); + g.SetClip(clip); + } + else + g.SetClip(ImageGalleryOwner.layoutManager.ClientArea); + + DrawFileIcon(g, param.Item, cBounds); + } + } + } + + /// + /// Renders the overlay. + /// + /// The graphics to draw on. + private void RenderOverlay(Graphics g) + { + g.SetClip(ImageGalleryOwner.layoutManager.ClientArea); + DrawOverlay(g, ImageGalleryOwner.layoutManager.ClientArea); + } + + /// + /// Renders the drag-drop insertion caret. + /// + /// The graphics to draw on. + private void RenderInsertionCaret(Graphics g) + { + if (ImageGalleryOwner.navigationManager.DropTarget == null) + return; + + var bounds = ImageGalleryOwner.layoutManager.GetItemBounds(ImageGalleryOwner.navigationManager.DropTarget.Index); + if (ImageGalleryOwner.View == View.VerticalStrip) + { + if (ImageGalleryOwner.navigationManager.DropToRight) + bounds.Offset(0, ImageGalleryOwner.layoutManager.ItemSizeWithMargin.Height); + + var itemMargin = MeasureItemMargin(ImageGalleryOwner.View); + bounds.Offset(0, -((int)itemMargin.Height - 2) / 2 - 2); + bounds.Height = 2; + } + else + { + if (ImageGalleryOwner.navigationManager.DropToRight) + bounds.Offset(ImageGalleryOwner.layoutManager.ItemSizeWithMargin.Width, 0); + + var itemMargin = MeasureItemMargin(ImageGalleryOwner.View); + bounds.Offset(-((int)itemMargin.Width - 2) / 2 - 2, 0); + bounds.Width = 2; + } + + if (Clip) + g.SetClip(bounds); + else + g.SetClip(ImageGalleryOwner.layoutManager.ClientArea); + + DrawInsertionCaret(g, bounds); + } + + /// + /// Renders the selection rectangle. + /// + /// The graphics to draw on. + private void RenderSelectionRectangle(Graphics g) + { + if (!ImageGalleryOwner.navigationManager.MouseSelecting) + return; + + var sel = ImageGalleryOwner.navigationManager.SelectionRectangle; + if (sel.Height > 0 && sel.Width > 0) + { + g.SetClip(ImageGalleryOwner.layoutManager.ClientArea); + if (Clip) + { + var selclip = new Rectangle(sel.Left, sel.Top, sel.Width + 1, sel.Height + 1); + g.IntersectClip(selclip); + } + + DrawSelectionRectangle(g, sel); + } + } + + /// + /// Renders the resizer. + /// + private void RenderResizer(Graphics g) + { + if (ImageGalleryOwner.Resizer == ResizerType.None) return; + if (!ImageGalleryOwner.navigationManager.IsResizerHit) return; + //g.SetClip(ImageGalleryOwner.layoutManager.ClientArea); + + + // draw resizer bar + var opacity = ImageGalleryOwner.navigationManager.MouseState == MouseState.Pressed + ? 70 + : 35; + var color = ImageGalleryOwner.BackColor.InvertBlackOrWhite(opacity); + using var brush = new SolidBrush(color); + g.FillRectangle(brush, ImageGalleryOwner.ResizerBound); + + + // draw resizer indicator + brush.Color = ImageGalleryOwner.BackColor.WithAlpha(255); + var dotSize = ImageGalleryOwner.ScaleToDpi(ImageGalleryOwner.ResizerSize) * 0.6f; + var dotX = ImageGalleryOwner.ResizerBound.X + ImageGalleryOwner.ResizerBound.Width / 2f - dotSize / 2f; + var dotY = ImageGalleryOwner.ResizerBound.Y + ImageGalleryOwner.ResizerBound.Height / 2f - dotSize / 2f; + + if (ImageGalleryOwner.Resizer == ResizerType.HTBOTTOM && ImageGalleryOwner.HScrollBar.Visible) + { + dotY -= ImageGalleryOwner.HScrollBar.Height / 2; + } + else if (ImageGalleryOwner.Resizer == ResizerType.HTRIGHT && ImageGalleryOwner.VScrollBar.Visible) + { + dotX -= ImageGalleryOwner.VScrollBar.Width / 2; + } + + var dotRect = new RectangleF(dotX, dotY, dotSize, dotSize); + g.FillEllipse(brush, dotRect); + + // horizontal + if (ImageGalleryOwner.ResizerBound.Width > ImageGalleryOwner.ResizerBound.Height) + { + dotRect.Offset(-dotSize * 2, 0); + g.FillEllipse(brush, dotRect); + + dotRect.Offset(dotSize * 4, 0); + g.FillEllipse(brush, dotRect); + } + // vertical + else + { + dotRect.Offset(0, -dotSize * 2); + g.FillEllipse(brush, dotRect); + + dotRect.Offset(0, dotSize * 4); + g.FillEllipse(brush, dotRect); + } + } + + + /// + /// Renders the control. + /// + /// The graphics to draw on. + internal void Render(Graphics graphics) + { + if (disposed) return; + + if (bufferGraphics == null) + { + if (!RecreateBuffer(graphics)) return; + } + + // Save the timne of this render for lazy refreshes + lastRenderTime = DateTime.UtcNow; + + // Update the layout + ImageGalleryOwner.layoutManager.Update(); + + // Set drawing area + var g = bufferGraphics.Graphics; + g.ResetClip(); + + // Draw control border + RenderBorder(g); + + // Draw background + RenderBackground(g); + + + // Draw items if they should be drawn first + bool itemsDrawn = false; + if (ItemsDrawnFirst) + { + RenderItems(g); + itemsDrawn = true; + } + + // Draw items if they should be drawn last. + if (!itemsDrawn) + RenderItems(g); + + // Draw the overlay image + RenderOverlay(g); + + // Draw the selection rectangle + RenderSelectionRectangle(g); + + // Draw the insertion caret + RenderInsertionCaret(g); + + // Scrollbar filler + RenderScrollbarFiller(g); + + // resizer + RenderResizer(g); + + // Draw on to the control + bufferGraphics.Render(graphics); + } + + /// + /// Loads and returns the large gallery image for the given item. + /// + private Image GetGalleryImageAsync(ImageGalleryItem item, Size size) + { + var img = ImageGalleryOwner.thumbnailCache.GetGalleryImage(item.Guid, size, ImageGalleryOwner.UseEmbeddedThumbnails, + ImageGalleryOwner.AutoRotateThumbnails); + + if (img == null) + { + ImageGalleryOwner.thumbnailCache.AddToGalleryCache(item.Guid, item.mAdaptor, item.VirtualKey, + size, ImageGalleryOwner.UseEmbeddedThumbnails, ImageGalleryOwner.AutoRotateThumbnails); + } + + return img; + } + + /// + /// Clears the graphics buffer objects. + /// + internal void ClearBuffer() + { + if (bufferGraphics != null) + bufferGraphics.Dispose(); + bufferGraphics = null; + } + + /// + /// Destroys the current buffer and creates a new buffered graphics + /// sized to the client area of the owner control. + /// + /// The Graphics to match the pixel format to. + internal bool RecreateBuffer(Graphics graphics) + { + if (creatingGraphics) return false; + + creatingGraphics = true; + + var bufferContext = BufferedGraphicsManager.Current; + + if (disposed) + throw new ObjectDisposedException(nameof(bufferContext)); + + var width = Math.Max(ImageGalleryOwner.Width, 1); + var height = Math.Max(ImageGalleryOwner.Height, 1); + + bufferContext.MaximumBuffer = new Size(width, height); + ClearBuffer(); + + bufferGraphics = bufferContext.Allocate(graphics, new Rectangle(0, 0, width, height)); + creatingGraphics = false; + + InitializeGraphics(bufferGraphics.Graphics); + + return true; + } + + /// + /// Releases buffered graphics objects. + /// + void IDisposable.Dispose() + { + if (!disposed) + { + ClearBuffer(); + + disposed = true; + GC.SuppressFinalize(this); + } + } + +#if DEBUG + /// + /// Releases unmanaged resources and performs other cleanup operations before the + /// is reclaimed by garbage collection. + /// + ~StyleRenderer() + { + System.Diagnostics.Debug.Print("Finalizer of {0} called.", GetType()); + Dispose(); + } + +#endif + + #endregion + + + #region Virtual Methods + + /// + /// Initializes the System.Drawing.Graphics used to draw + /// control elements. + /// + /// The System.Drawing.Graphics to draw on. + public virtual void InitializeGraphics(Graphics g) + { + g.PixelOffsetMode = PixelOffsetMode.None; + g.SmoothingMode = SmoothingMode.HighQuality; + g.InterpolationMode = InterpolationMode.HighQualityBicubic; + } + + /// + /// Renders the area between scrollbars. + /// + /// The graphics to draw on. + public virtual void RenderScrollbarFiller(Graphics g) + { + if (!ImageGalleryOwner.hScrollBar.Visible || !ImageGalleryOwner.vScrollBar.Visible) + return; + + var bounds = ImageGalleryOwner.layoutManager.ClientArea; + var filler = new Rectangle(bounds.Right, bounds.Bottom, ImageGalleryOwner.vScrollBar.Width, ImageGalleryOwner.hScrollBar.Height); + + g.SetClip(filler); + + using var brush = new SolidBrush(ImageGalleryOwner.BackColor); + g.FillRectangle(brush, filler); + } + + /// + /// Returns the spacing between items for the given view mode. + /// + /// The view mode for which the measurement should be made. + /// The spacing between items. + public virtual SizeF MeasureItemMargin(View view) + { + return ImageGalleryOwner.ScaleToDpi(new SizeF(4, 4)); + } + + /// + /// Returns item size for the given view mode. + /// + /// The view mode for which the measurement should be made. + /// The item size. + public virtual Size MeasureItem(View view) + { + // Reference text height + int textHeight = ImageGalleryOwner.Font.Height; + + var itemPadding = MeasureItemMargin(view); + var itemSize = ImageGalleryOwner.ThumbnailSize + itemPadding + itemPadding; + itemSize.Height += textHeight + Math.Max(4, textHeight / 3); // textHeight / 3 = vertical space between thumbnail and text + + return itemSize.ToSize(); + } + + /// + /// Draws the border of the control. + /// + /// The System.Drawing.Graphics to draw on. + /// The coordinates of the border. + public virtual void DrawBorder(Graphics g, Rectangle bounds) + { + if (ImageGalleryOwner.BorderStyle != BorderStyle.None) + { + var style = (ImageGalleryOwner.BorderStyle == BorderStyle.FixedSingle) ? Border3DStyle.Flat : Border3DStyle.SunkenInner; + + ControlPaint.DrawBorder3D(g, bounds, style); + } + } + + /// + /// Draws the background of the control. + /// + /// The System.Drawing.Graphics to draw on. + /// The client coordinates of the item area. + public virtual void DrawBackground(Graphics g, Rectangle bounds) + { + // transparent background + if (ImageGalleryOwner.EnableTransparent) + { + // Clear the background + g.Clear(ImageGalleryOwner.BackColor); + } + else + { + g.Clear(ImageGalleryOwner.TopLevelControl.BackColor); + + using var bgBrush = new SolidBrush(ImageGalleryOwner.BackColor); + g.FillRectangle(bgBrush, bounds); + } + + + // Draw the background image + if (ImageGalleryOwner.BackgroundImage != null) + { + var img = ImageGalleryOwner.BackgroundImage; + + if (ImageGalleryOwner.BackgroundImageLayout == ImageLayout.None) + { + g.DrawImageUnscaled(img, ImageGalleryOwner.layoutManager.ItemAreaBounds.Location); + } + else if (ImageGalleryOwner.BackgroundImageLayout == ImageLayout.Center) + { + var x = bounds.Left + (bounds.Width - img.Width) / 2; + var y = bounds.Top + (bounds.Height - img.Height) / 2; + g.DrawImageUnscaled(img, x, y); + } + else if (ImageGalleryOwner.BackgroundImageLayout == ImageLayout.Stretch) + { + g.DrawImage(img, bounds); + } + else if (ImageGalleryOwner.BackgroundImageLayout == ImageLayout.Tile) + { + using var imgBrush = new TextureBrush(img, WrapMode.Tile); + g.FillRectangle(imgBrush, bounds); + } + else if (ImageGalleryOwner.BackgroundImageLayout == ImageLayout.Zoom) + { + var xscale = bounds.Width / (float)img.Width; + var yscale = bounds.Height / (float)img.Height; + var scale = Math.Min(xscale, yscale); + + var width = (int)(img.Width * scale); + var height = (int)(img.Height * scale); + var x = bounds.Left + (bounds.Width - width) / 2; + var y = bounds.Top + (bounds.Height - height) / 2; + + g.DrawImage(img, x, y, width, height); + } + } + } + + /// + /// Draws the selection rectangle. + /// + /// The System.Drawing.Graphics to draw on. + /// The client coordinates of the selection rectangle. + public virtual void DrawSelectionRectangle(Graphics g, Rectangle selection) + { + using var brush = new SolidBrush(Color.FromArgb(170, SystemColors.Highlight)); + using var pen = new Pen(SystemColors.Highlight); + + g.FillRectangle(brush, selection); + g.DrawRectangle(pen, selection); + } + + /// + /// Draws the specified item on the given graphics. + /// + /// The System.Drawing.Graphics to draw on. + /// The ImageListViewItem to draw. + /// The current view state of item. + /// The bounding rectangle of item in client coordinates. + public virtual void DrawItem(Graphics g, ImageGalleryItem item, ItemState state, Rectangle bounds) + { + var itemPadding = new Size(4, 4); + var alternate = item.Index % 2 == 1; + + // Paint background Disabled + if ((state & ItemState.Disabled) != ItemState.None) + { + //using var bDisabled = new LinearGradientBrush(bounds, ImageListView.Colors.DisabledColor1, ImageListView.Colors.DisabledColor2, LinearGradientMode.Vertical); + //Utility.FillRoundedRectangle(g, bDisabled, bounds, 4); + } + + // Paint background Selected + else if ((ImageGalleryOwner.Focused && ((state & ItemState.Selected) != ItemState.None)) || + (!ImageGalleryOwner.Focused && ((state & ItemState.Selected) != ItemState.None) && ((state & ItemState.Hovered) != ItemState.None))) + { + //using var bSelected = new LinearGradientBrush(bounds, ImageListView.Colors.SelectedColor1, ImageListView.Colors.SelectedColor2, LinearGradientMode.Vertical); + //Utility.FillRoundedRectangle(g, bSelected, bounds, 4); + } + + // Paint background unfocused + else if (!ImageGalleryOwner.Focused && ((state & ItemState.Selected) != ItemState.None)) + { + //using var bGray64 = new LinearGradientBrush(bounds, ImageListView.Colors.UnFocusedColor1, ImageListView.Colors.UnFocusedColor2, LinearGradientMode.Vertical); + //Utility.FillRoundedRectangle(g, bGray64, bounds, 4); + } + + // Paint background Pressed + if ((state & ItemState.Pressed) != ItemState.None) + { + //using var bHovered = new LinearGradientBrush(bounds, ImageListView.Colors.PressedColor2, ImageListView.Colors.PressedColor2, LinearGradientMode.Vertical); + //Utility.FillRoundedRectangle(g, bHovered, bounds, 4); + } + // Paint background Hover + else if ((state & ItemState.Hovered) != ItemState.None) + { + //using var bHovered = new LinearGradientBrush(bounds, ImageListView.Colors.HoverColor1, ImageListView.Colors.HoverColor2, LinearGradientMode.Vertical); + //Utility.FillRoundedRectangle(g, bHovered, bounds, 4); + } + + + // Draw the image + var img = item.GetCachedImage(CachedImageType.Thumbnail); + if (img != null) + { + var pos = Utility.GetSizedImageBounds(img, new Rectangle(bounds.Location + itemPadding, ImageGalleryOwner.ThumbnailSize)); + g.DrawImage(img, pos); + + // Draw image border + if (Math.Min(pos.Width, pos.Height) > 32) + { + //using var pOuterBorder = new Pen(ImageListView.Colors.ImageOuterBorderColor); + //g.DrawRectangle(pOuterBorder, pos); + + //if (Math.Min(ImageListView.ThumbnailSize.Width, ImageListView.ThumbnailSize.Height) > 32) + //{ + // using var pInnerBorder = new Pen(ImageListView.Colors.ImageInnerBorderColor); + // g.DrawRectangle(pInnerBorder, Rectangle.Inflate(pos, -1, -1)); + //} + } + } + + //// Draw item text + //var foreColor = ImageListView.Colors.ForeColor; + //if ((state & ItemState.Disabled) != ItemState.None) + //{ + // foreColor = ImageListView.Colors.DisabledForeColor; + //} + //else if ((state & ItemState.Pressed) != ItemState.None) + //{ + // foreColor = ImageListView.Colors.PressedForeColor; + //} + //else if ((state & ItemState.Selected) != ItemState.None) + //{ + // if (ImageListView.Focused) + // foreColor = ImageListView.Colors.SelectedForeColor; + // else + // foreColor = ImageListView.Colors.UnFocusedForeColor; + //} + + //var szt = TextRenderer.MeasureText(item.Text, ImageListView.Font); + //var rt = new Rectangle(bounds.Left + itemPadding.Width, bounds.Top + 2 * itemPadding.Height + ImageListView.ThumbnailSize.Height, ImageListView.ThumbnailSize.Width, szt.Height); + + //TextRenderer.DrawText(g, item.Text, ImageListView.Font, rt, foreColor, + // TextFormatFlags.EndEllipsis | TextFormatFlags.HorizontalCenter | TextFormatFlags.VerticalCenter | TextFormatFlags.SingleLine | TextFormatFlags.NoPrefix); + + + //// Item border + //using var pWhite128 = new Pen(Color.FromArgb(128, ImageListView.Colors.ControlBackColor)); + //Utility.DrawRoundedRectangle(g, pWhite128, bounds.Left + 1, bounds.Top + 1, bounds.Width - 3, bounds.Height - 3, 4); + + //if ((state & ItemState.Disabled) != ItemState.None) + //{ + // using var pHighlight128 = new Pen(ImageListView.Colors.DisabledBorderColor); + // Utility.DrawRoundedRectangle(g, pHighlight128, bounds.Left, bounds.Top, bounds.Width - 1, bounds.Height - 1, 4); + //} + //else if (ImageListView.Focused && ((state & ItemState.Selected) != ItemState.None)) + //{ + // using var pHighlight128 = new Pen(ImageListView.Colors.SelectedBorderColor); + // Utility.DrawRoundedRectangle(g, pHighlight128, bounds.Left, bounds.Top, bounds.Width - 1, bounds.Height - 1, 4); + //} + //else if (!ImageListView.Focused && ((state & ItemState.Selected) != ItemState.None)) + //{ + // using var pGray128 = new Pen(ImageListView.Colors.UnFocusedBorderColor); + // Utility.DrawRoundedRectangle(g, pGray128, bounds.Left, bounds.Top, bounds.Width - 1, bounds.Height - 1, 4); + //} + //else if ((state & ItemState.Pressed) == ItemState.None) + //{ + // using var pGray64 = new Pen(ImageListView.Colors.PressedBorderColor); + // Utility.DrawRoundedRectangle(g, pGray64, bounds.Left, bounds.Top, bounds.Width - 1, bounds.Height - 1, 4); + //} + //else if ((state & ItemState.Selected) == ItemState.None) + //{ + // using var pGray64 = new Pen(ImageListView.Colors.BorderColor); + // Utility.DrawRoundedRectangle(g, pGray64, bounds.Left, bounds.Top, bounds.Width - 1, bounds.Height - 1, 4); + //} + + //if (ImageListView.Focused && ((state & ItemState.Hovered) != ItemState.None)) + //{ + // using var pHighlight64 = new Pen(ImageListView.Colors.HoverBorderColor); + // Utility.DrawRoundedRectangle(g, pHighlight64, bounds.Left, bounds.Top, bounds.Width - 1, bounds.Height - 1, 4); + //} + + // Focus rectangle + if (ImageGalleryOwner.Focused && ((state & ItemState.Focused) != ItemState.None)) + { + ControlPaint.DrawFocusRectangle(g, bounds); + } + } + + /// + /// Draws the checkbox icon for the specified item on the given graphics. + /// + /// The System.Drawing.Graphics to draw on. + /// The ImageListViewItem to draw. + /// The bounding rectangle of the checkbox in client coordinates. + public virtual void DrawCheckBox(Graphics g, ImageGalleryItem item, Rectangle bounds) + { + var size = CheckBoxRenderer.GetGlyphSize(g, CheckBoxState.CheckedNormal); + var pt = new PointF(bounds.X + (bounds.Width - (float)size.Width) / 2.0f, + bounds.Y + (bounds.Height - (float)size.Height) / 2.0f); + CheckBoxState state; + + if (item.Enabled) + state = item.Checked ? CheckBoxState.CheckedNormal : CheckBoxState.UncheckedNormal; + else + state = item.Checked ? CheckBoxState.CheckedDisabled : CheckBoxState.UncheckedDisabled; + + CheckBoxRenderer.DrawCheckBox(g, Point.Round(pt), state); + } + + /// + /// Draws the file icon for the specified item on the given graphics. + /// + /// The System.Drawing.Graphics to draw on. + /// The ImageListViewItem to draw. + /// The bounding rectangle of the file icon in client coordinates. + public virtual void DrawFileIcon(Graphics g, ImageGalleryItem item, Rectangle bounds) + { + var icon = item.GetCachedImage(CachedImageType.SmallIcon); + if (icon != null) + { + var size = icon.Size; + var ptf = new PointF(bounds.X + (bounds.Width - (float)size.Width) / 2.0f, + bounds.Y + (bounds.Height - (float)size.Height) / 2.0f); + var pt = Point.Round(ptf); + + g.DrawImage(icon, pt.X, pt.Y); + } + } + + + /// + /// Draws the insertion caret for drag and drop operations. + /// + /// The System.Drawing.Graphics to draw on. + /// The bounding rectangle of the insertion caret. + public virtual void DrawInsertionCaret(Graphics g, Rectangle bounds) + { + using var b = new SolidBrush(SystemColors.Highlight); + g.FillRectangle(b, bounds); + } + + /// + /// Draws an overlay image over the client area. + /// + /// The System.Drawing.Graphics to draw on. + /// The bounding rectangle of the client area. + public virtual void DrawOverlay(Graphics g, Rectangle bounds) + { + + } + + /// + /// Releases managed resources. + /// + public virtual void Dispose() + { + ((IDisposable)this).Dispose(); + } + + /// + /// Sets the layout of the control. + /// + /// A LayoutEventArgs that contains event data. + public virtual void OnLayout(LayoutEventArgs e) + { + + } + #endregion + +} + diff --git a/Source/Components/ImageGlass.Gallery/Utility.cs b/Source/Components/ImageGlass.Gallery/Utility.cs new file mode 100644 index 000000000..c875fe552 --- /dev/null +++ b/Source/Components/ImageGlass.Gallery/Utility.cs @@ -0,0 +1,223 @@ +/* +ImageGlass Project - Image viewer for Windows +Copyright (C) 2010 - 2026 DUONG DIEU PHAP +Project homepage: https://imageglass.org + +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 . + +--------------------- +ImageGlass.Gallery is based on ImageListView v13.8.2: +Url: https://github.com/oozcitak/imagelistview +License: Apache License Version 2.0, http://www.apache.org/licenses/ +--------------------- +*/ +using System.Drawing.Drawing2D; +using System.Text; + +namespace ImageGlass.Gallery; + + +/// +/// Contains utility functions. +/// +public static class Utility +{ + #region Graphics Utilities + /// + /// Checks the stream header if it matches with + /// any of the supported image file types. + /// + /// An open stream pointing to an image file. + /// true if the stream is an image file (BMP, TIFF, PNG, GIF, JPEG, WMF, EMF, ICO, CUR); + /// false otherwise. + internal static bool IsImage(Stream stream) + { + // Sniff some bytes from the start of the stream + // and check against magic numbers of supported + // image file formats + var header = new byte[8]; + stream.Seek(0, SeekOrigin.Begin); + if (stream.Read(header, 0, header.Length) != header.Length) + return false; + + // BMP + var bmpHeader = Encoding.ASCII.GetString(header, 0, 2); + if (bmpHeader == "BM") // BM - Windows bitmap + return true; + else if (bmpHeader == "BA") // BA - Bitmap array + return true; + else if (bmpHeader == "CI") // CI - Color Icon + return true; + else if (bmpHeader == "CP") // CP - Color Pointer + return true; + else if (bmpHeader == "IC") // IC - Icon + return true; + else if (bmpHeader == "PT") // PI - Pointer + return true; + + // TIFF + var tiffHeader = Encoding.ASCII.GetString(header, 0, 4); + if (tiffHeader == "MM\x00\x2a") // Big-endian + return true; + else if (tiffHeader == "II\x2a\x00") // Little-endian + return true; + + // PNG + if (header[0] == 0x89 && header[1] == 0x50 && header[2] == 0x4E && header[3] == 0x47 && + header[4] == 0x0D && header[5] == 0x0A && header[6] == 0x1A && header[7] == 0x0A) + return true; + + // GIF + string gifHeader = Encoding.ASCII.GetString(header, 0, 4); + if (gifHeader == "GIF8") + return true; + + // JPEG + if (header[0] == 0xFF && header[1] == 0xD8) + return true; + + // WMF + if (header[0] == 0xD7 && header[1] == 0xCD && header[2] == 0xC6 && header[3] == 0x9A) + return true; + + // EMF + if (header[0] == 0x01 && header[1] == 0x00 && header[2] == 0x00 && header[3] == 0x00) + return true; + + // Windows Icons + if (header[0] == 0x00 && header[1] == 0x00 && header[2] == 0x01 && header[3] == 0x00) // ICO + return true; + else if (header[0] == 0x00 && header[1] == 0x00 && header[2] == 0x02 && header[3] == 0x00) // CUR + return true; + + return false; + } + + /// + /// Gets the scaled size of an image required to fit + /// in to the given size keeping the image aspect ratio. + /// + /// The source image. + /// The size to fit in to. + /// New image size. + internal static Size GetSizedImageBounds(Image image, Size fit) + { + var f = Math.Max(1f * image.Width / fit.Width, 1f * image.Height / fit.Height); + if (f < 1.0f) f = 1.0f; // Do not upsize small images + + var width = (int)Math.Round(image.Width / f); + var height = (int)Math.Round(image.Height / f); + + return new Size(width, height); + } + + /// + /// Gets the bounding rectangle of an image required to fit + /// in to the given rectangle keeping the image aspect ratio. + /// + /// The source image. + /// The rectangle to fit in to. + /// Horizontal image aligment in percent. + /// Vertical image aligment in percent. + /// New image size. + public static Rectangle GetSizedImageBounds(Image image, Rectangle fit, float hAlign, float vAlign) + { + if (hAlign < 0 || hAlign > 100.0f) + throw new ArgumentException("hAlign must be between 0.0 and 100.0 (inclusive).", nameof(hAlign)); + + if (vAlign < 0 || vAlign > 100.0f) + throw new ArgumentException("vAlign must be between 0.0 and 100.0 (inclusive).", nameof(vAlign)); + + var scaled = GetSizedImageBounds(image, fit.Size); + var x = fit.Left + (int)(hAlign / 100.0f * (fit.Width - scaled.Width)); + var y = fit.Top + (int)(vAlign / 100.0f * (fit.Height - scaled.Height)); + + return new Rectangle(x, y, scaled.Width, scaled.Height); + } + + /// + /// Gets the bounding rectangle of an image required to fit + /// in to the given rectangle keeping the image aspect ratio. + /// The image will be centered in the fit box. + /// + /// The source image. + /// The rectangle to fit in to. + /// New image size. + public static Rectangle GetSizedImageBounds(Image image, Rectangle fit) + { + return GetSizedImageBounds(image, fit, 50.0f, 50.0f); + } + + /// + /// Gets a path representing a rounded rectangle. + /// + private static GraphicsPath GetRoundedRectanglePath(int x, int y, int width, int height, int radius) + { + var path = new GraphicsPath(); + path.AddLine(x + radius, y, x + width - radius, y); + + if (radius > 0) + path.AddArc(x + width - 2 * radius, y, 2 * radius, 2 * radius, 270.0f, 90.0f); + path.AddLine(x + width, y + radius, x + width, y + height - radius); + + if (radius > 0) + path.AddArc(x + width - 2 * radius, y + height - 2 * radius, 2 * radius, 2 * radius, 0.0f, 90.0f); + path.AddLine(x + width - radius, y + height, x + radius, y + height); + + if (radius > 0) + path.AddArc(x, y + height - 2 * radius, 2 * radius, 2 * radius, 90.0f, 90.0f); + path.AddLine(x, y + height - radius, x, y + radius); + + if (radius > 0) + path.AddArc(x, y, 2 * radius, 2 * radius, 180.0f, 90.0f); + + return path; + } + + /// + /// Fills the interior of a rounded rectangle. + /// + /// The graphics to draw on. + /// The brush to use to fill the rectangle. + /// The x-coordinate of the upper-left corner of the rectangle to draw. + /// The y-coordinate of the upper-left corner of the rectangle to draw. + /// Width of the rectangle to draw. + /// Height of the rectangle to draw. + /// The radius of rounded corners. + public static void FillRoundedRectangle(Graphics graphics, Brush brush, int x, int y, int width, int height, int radius) + { + using GraphicsPath path = GetRoundedRectanglePath(x, y, width, height, radius); + graphics.FillPath(brush, path); + } + + /// + /// Draws the outline of a rounded rectangle. + /// + /// The graphics to draw on. + /// The pen to use to draw the rectangle. + /// The x-coordinate of the upper-left corner of the rectangle to draw. + /// The y-coordinate of the upper-left corner of the rectangle to draw. + /// Width of the rectangle to draw. + /// Height of the rectangle to draw. + /// The radius of rounded corners. + public static void DrawRoundedRectangle(Graphics graphics, Pen pen, int x, int y, int width, int height, int radius) + { + using GraphicsPath path = GetRoundedRectanglePath(x, y, width, height, radius); + graphics.DrawPath(pen, path); + } + + #endregion + + +} diff --git a/Source/Components/ImageGlass.Heart/BitmapBooster.cs b/Source/Components/ImageGlass.Heart/BitmapBooster.cs deleted file mode 100644 index 4ad1babe5..000000000 --- a/Source/Components/ImageGlass.Heart/BitmapBooster.cs +++ /dev/null @@ -1,103 +0,0 @@ -/* -ImageGlass Project - Image viewer for Windows -Copyright (C) 2020 DUONG DIEU PHAP -Project homepage: https://imageglass.org - -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 . -*/ - -using System; -using System.Drawing; -using System.Drawing.Imaging; - -namespace ImageGlass.Heart -{ - public class BitmapBooster - { - - Bitmap src; - BitmapData bd; - IntPtr dst; - int str; - - public BitmapBooster(Bitmap src) - { - this.src = src; - bd = src.LockBits(new Rectangle(Point.Empty, src.Size), ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb); - dst = bd.Scan0; - str = bd.Stride; - } - - public void Dispose() - { - src.UnlockBits(bd); - } - - public Color Get(int x, int y) - { - unsafe - { - byte* o = (byte*)dst; - int ofs = str * y + x * 4; - - return Color.FromArgb( - o[ofs + 3], - o[ofs + 2], - o[ofs + 1], - o[ofs + 0]); - } - } - - public void Set(int x, int y, Color c) - { - unsafe - { - byte* o = (byte*)dst; - int ofs = str * y + x * 4; - o[ofs + 3] = c.A; - o[ofs + 2] = c.R; - o[ofs + 1] = c.G; - o[ofs + 0] = c.B; - } - } - - public void Set(int x, int y, byte alpha) - { - unsafe - { - ((byte*)dst)[str * y + x * 4 + 3] = alpha; - } - } - - public static int Min(params int[] values) - { - int ret = values[0]; - for (int a = 1; a < values.Length; a++) - { - ret = Math.Min(ret, values[a]); - } - return ret; - } - public static int Max(params int[] values) - { - int ret = values[0]; - for (int a = 1; a < values.Length; a++) - { - ret = Math.Max(ret, values[a]); - } - return ret; - } - - } -} diff --git a/Source/Components/ImageGlass.Heart/Factory.cs b/Source/Components/ImageGlass.Heart/Factory.cs deleted file mode 100644 index e1df0c94c..000000000 --- a/Source/Components/ImageGlass.Heart/Factory.cs +++ /dev/null @@ -1,490 +0,0 @@ -/* -ImageGlass Project - Image viewer for Windows -Copyright (C) 2020 DUONG DIEU PHAP -Project homepage: https://imageglass.org - -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 . -*/ - - -using System; -using System.Collections.Generic; -using System.Diagnostics.CodeAnalysis; -using System.Drawing; -using System.IO; -using System.Linq; -using System.Threading.Tasks; - -namespace ImageGlass.Heart -{ - public class Factory : IDisposable - { - - #region PRIVATE PROPERTIES - - /// - /// The list of Imgs - /// - private List ImgList { get; set; } = new List(); - - - /// - /// The list of image index that waiting for loading - /// - private List QueuedList { get; set; } = new List(); - - - /// - /// The list of image index that waiting for releasing resource - /// - private List FreeList { get; set; } = new List(); - - private bool IsRunWorker { get; set; } = false; - - #endregion - - - - #region PUBLIC PROPERTIES - - /// - /// Gets length of Img list - /// - public int Length => this.ImgList.Count; - - - /// - /// Gets, sets image size - /// - public Size ImgSize { get; set; } = new Size(); - - - /// - /// Gets sets ColorProfile name of path - /// - public string ColorProfileName { get; set; } = "sRGB"; - - - /// - /// Gets, sets the value indicates if the ColorProfileName should apply to all image files - /// - public bool IsApplyColorProfileForAll { get; set; } = false; - - - /// - /// Gets, sets the value of ImageMagick.Channels to apply to the entire image list - /// - public int Channels { get; set; } = -1; - - - /// - /// Get filenames list - /// - public List FileNames - { - get - { - var list = new List(); - foreach (var item in this.ImgList) - { - list.Add(item.Filename); - } - - return list; - } - } - - - /// - /// Gets, sets the number of maximum items in queue list for 1 direction (Next or Back navigation). - /// The maximum number of items in queue list is 2x + 1. - /// - public uint MaxQueue { get; set; } = 1; - - - /// - /// Gets, sests the value indicates that returns the embedded thumbnail if found. - /// - public bool UseEmbeddedThumbnail { get; set; } = false; - - - public delegate void FinishLoadingImageHandler(object sender, EventArgs e); - public event FinishLoadingImageHandler OnFinishLoadingImage; - - #endregion - - - - public Factory() { } - - - /// - /// The ImageBooster Factory - /// - /// List of filenames - public Factory(IList filenames) - { - // import filenames to the list - foreach (var filename in filenames) - { - this.ImgList.Add(new Img(filename)); - } - - - // start background service worker - this.IsRunWorker = true; - StartImageBooster(); - } - - - - #region PRIVATE FUNCTIONS - - /// - /// Add index of the image to queue list - /// - /// Current index of image list - private void UpdateQueueList(int index) - { - // check valid index - if (index < 0 || index >= this.ImgList.Count) return; - - var list = new HashSet - { - index - }; - - - var maxCachedItems = this.MaxQueue * 2 + 1; - var iRight = index; - var iLeft = index; - - - // add index in the range in order: index -> right -> left -> ... - for (int i = 0; list.Count < maxCachedItems && list.Count < this.ImgList.Count; i++) - { - // if i is even number - if ((i & 1) == 0) - { - // add right item: [index + 1; ...; to] - iRight += 1; - - if (iRight < this.ImgList.Count) - { - list.Add(iRight); - } - else - { - list.Add(iRight - this.ImgList.Count); - } - } - // if i is odd number - else - { - // add left item: [index - 1; ...; from] - iLeft -= 1; - - if (iLeft >= 0) - { - list.Add(iLeft); - } - else - { - list.Add(this.ImgList.Count + iLeft); - } - } - } - - - // release the resources - foreach (var indexItem in this.FreeList) - { - if (!list.Contains(indexItem) && indexItem >= 0 && indexItem < this.ImgList.Count) - { - this.ImgList[indexItem].Dispose(); - } - } - - - // update new index of free list - this.FreeList.Clear(); - this.FreeList.AddRange(list); - - // update queue list - this.QueuedList.Clear(); - this.QueuedList.AddRange(list); - } - - #endregion - - - - #region PUBLIC FUNCTIONS - - /// - /// Start ImageBooster thread - /// - public async void StartImageBooster() - { - while (this.IsRunWorker) - { - if (this.QueuedList.Count > 0) - { - // pop out the first item - var index = this.QueuedList[0]; - var img = this.ImgList[index]; - QueuedList.RemoveAt(0); - - - if (!img.IsDone) - { - // start loading image file - await img.LoadAsync( - size: this.ImgSize, - colorProfileName: this.ColorProfileName, - isApplyColorProfileForAll: this.IsApplyColorProfileForAll, - channel: this.Channels, - useEmbeddedThumbnail: this.UseEmbeddedThumbnail - ); - } - } - - await Task.Delay(10); - } - } - - - /// - /// Releases all resources of the Factory and Stop ImageBooster thread - /// - public void Dispose() - { - // stop the worker - this.IsRunWorker = false; - - // clear list and release resources - this.Clear(); - } - - - /// - /// Add a filename to the list - /// - /// Image filename - public void Add(string filename) - { - this.ImgList.Add(new Img(filename)); - } - - - /// - /// Get Img data - /// - /// image index - /// - /// The index of image page to display (if it's multi-page) - /// - public async Task GetImgAsync(int index, bool isSkipCache = false, int pageIndex = 0) - { - // reload fresh new image data - if (isSkipCache) - { - await this.ImgList[index].LoadAsync( - size: this.ImgSize, - colorProfileName: this.ColorProfileName, - isApplyColorProfileForAll: this.IsApplyColorProfileForAll, - channel: this.Channels, - useEmbeddedThumbnail: this.UseEmbeddedThumbnail - ); - } - // get image data from cache - else - { - // update queue list according to index - UpdateQueueList(index); - } - - - // wait until the image loading is done - if (ImgList.Count > 0) - { - while (!this.ImgList[index].IsDone) - { - await Task.Delay(1); - } - } - - // Trigger event OnFinishLoadingImage - OnFinishLoadingImage?.Invoke(this, new EventArgs()); - - // if there is no error - if (ImgList.Count > 0) - { - if (ImgList[index].Error == null) - { - ImgList[index].SetActivePage(pageIndex); - } - - return ImgList[index]; - } - - return null; - } - - - /// - /// Get filename with the given index - /// - /// - /// Returns filename or empty string - public string GetFileName(int index) - { - try - { - if (ImgList.Count > 0 && ImgList[index] != null) - { - return this.ImgList[index].Filename; - } - } - catch (ArgumentOutOfRangeException) // force reload of empty list - { - return string.Empty; - } - - return string.Empty; - } - - - /// - /// Set filename - /// - /// - /// Image filename - public void SetFileName(int index, string filename) - { - if (this.ImgList[index] != null) - { - this.ImgList[index].Filename = filename; - } - } - - - - /// - /// Find index with the given filename - /// - /// Image filename - /// - public int IndexOf(string filename) - { - // case sensitivity, esp. if filename passed on command line - return this.ImgList.FindIndex(item => item.Filename.ToUpperInvariant() == filename.ToUpperInvariant()); - } - - - /// - /// Unload and release resources of item with the given index - /// - /// - public void Unload(int index) - { - if (this.ImgList[index] != null) - { - this.ImgList[index].Dispose(); - } - } - - - /// - /// Remove an item in the list with the given index - /// - /// - public void Remove(int index) - { - this.Unload(index); - this.ImgList.RemoveAt(index); - } - - - /// - /// Empty and release resource of the list - /// - public void Clear() - { - // release the resources of the img list - this.ClearCache(); - this.ImgList.Clear(); - } - - - /// - /// Clear all cached images and release resource of the list - /// - public void ClearCache() - { - // release the resources of the img list - foreach (var item in this.ImgList) - { - item.Dispose(); - } - - this.QueuedList.Clear(); - } - - - /// - /// Update cached images - /// - public void UpdateCache() - { - // clear current queue list - this.QueuedList.Clear(); - - var cachedIndexList = this.ImgList - .Select((item, index) => new { ImgItem = item, Index = index }) - .Where(item => item.ImgItem.IsDone) - .Select(item => item.Index) - .ToList(); - - // release the cachced images - foreach (var index in cachedIndexList) - { - this.ImgList[index].Dispose(); - } - - // add to queue list - this.QueuedList.AddRange(cachedIndexList); - } - - - /// - /// Check if the folder path of input filename exists in the list - /// - /// - /// - public bool ContainsDirPathOf(string filename) - { - var target = Path.GetDirectoryName(filename).ToUpperInvariant(); - - var index = this.ImgList.FindIndex(item => Path.GetDirectoryName(item.Filename).ToUpperInvariant() == target); - - return index != -1; - } - - #endregion - - - - } -} diff --git a/Source/Components/ImageGlass.Heart/Helpers.cs b/Source/Components/ImageGlass.Heart/Helpers.cs deleted file mode 100644 index 1fd65aea8..000000000 --- a/Source/Components/ImageGlass.Heart/Helpers.cs +++ /dev/null @@ -1,173 +0,0 @@ -/* -ImageGlass Project - Image viewer for Windows -Copyright (C) 2020 DUONG DIEU PHAP -Project homepage: https://imageglass.org - -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 . -*/ - - -using ImageMagick; -using System; -using System.IO; -using System.Linq; - -namespace ImageGlass.Heart -{ - public class Helpers - { - - /// - /// Get built-in color profiles - /// - /// - public static string[] GetBuiltInColorProfiles() - { - return new string[] - { - "AdobeRGB1998", - "AppleRGB", - "CoatedFOGRA39", - "ColorMatchRGB", - "sRGB", - "USWebCoatedSWOP", - }; - } - - - /// - /// Get the correct color profile name - /// - /// Name or Full path of color profile - /// - public static string GetCorrectColorProfileName(string name) - { - var profileName = ""; - - if (File.Exists(name)) - { - return name; - } - else - { - var builtInProfiles = GetBuiltInColorProfiles(); - var result = builtInProfiles.FirstOrDefault(i => i.ToUpperInvariant() == name.ToUpperInvariant()); - - if (result != null) - { - profileName = result; - } - else - { - return string.Empty; - } - } - - return profileName; - } - - - - /// - /// Get ColorProfile - /// - /// Name or Full path of color profile - /// - public static ColorProfile GetColorProfile(string name) - { - if (File.Exists(name)) - { - return new ColorProfile(name); - } - else - { - // get all profile names in Magick.NET - var profiles = typeof(ColorProfile).GetProperties(); - var result = profiles.FirstOrDefault(i => i.Name.ToUpperInvariant() == name.ToUpperInvariant()); - - if (result != null) - { - try - { - return (ColorProfile)result.GetValue(result); - } - catch (Exception) - { - return null; - } - } - } - - return null; - } - - - - /// - /// Returns Exif rotation in degrees. Returns 0 if the metadata - /// does not exist or could not be read. A negative value means - /// the image needs to be mirrored about the vertical axis. - /// - /// Orientation Flag - /// - public static int GetOrientationDegree(int orientationFlag) - { - if (orientationFlag == 1) - return 0; - else if (orientationFlag == 2) - return -360; - else if (orientationFlag == 3) - return 180; - else if (orientationFlag == 4) - return -180; - else if (orientationFlag == 5) - return -90; - else if (orientationFlag == 6) - return 90; - else if (orientationFlag == 7) - return -270; - else if (orientationFlag == 8) - return 270; - - return 0; - } - - - private static string LONG_PATH_PREFIX = @"\\?\"; - - /// - /// Fallout from Issue #530. To handle a long path name (i.e. a file path - /// longer than MAX_PATH), a magic prefix is sometimes necessary. - /// - public static string PrefixLongPath(string path) - { - if (path.Length > 255 && !path.StartsWith(LONG_PATH_PREFIX)) - return LONG_PATH_PREFIX + path; - return path; - } - - /// - /// Fallout from Issue #530. Specific functions (currently FileWatch) - /// fail if provided a prefixed file path. In this case, strip the prefix - /// (see PrefixLongPath above). - /// - public static string DePrefixLongPath(string path) - { - if (path.StartsWith(LONG_PATH_PREFIX)) - return path.Substring(LONG_PATH_PREFIX.Length); - return path; - } - - } -} diff --git a/Source/Components/ImageGlass.Heart/ImageGlass.Heart.csproj b/Source/Components/ImageGlass.Heart/ImageGlass.Heart.csproj deleted file mode 100644 index 7956db4e2..000000000 --- a/Source/Components/ImageGlass.Heart/ImageGlass.Heart.csproj +++ /dev/null @@ -1,107 +0,0 @@ - - - - - Debug - AnyCPU - {51493B09-7A0E-461F-BE18-A6CF629A8FAB} - Library - Properties - ImageGlass.Heart - ImageGlass.Heart - v4.7.1 - 512 - true - - - - - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - true - - - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - true - - - true - bin\x86\Debug\ - DEBUG;TRACE - true - full - x86 - 7.3 - prompt - MinimumRecommendedRules.ruleset - - - bin\x86\Release\ - TRACE - true - true - pdbonly - x86 - 7.3 - prompt - MinimumRecommendedRules.ruleset - - - true - bin\x64\Debug\ - DEBUG;TRACE - true - full - x64 - 7.3 - prompt - MinimumRecommendedRules.ruleset - - - bin\x64\Release\ - TRACE - true - true - pdbonly - x64 - 7.3 - prompt - MinimumRecommendedRules.ruleset - - - - ..\..\packages\Magick.NET-Q16-AnyCPU.7.15.0\lib\net40\Magick.NET-Q16-AnyCPU.dll - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/Source/Components/ImageGlass.Heart/Img.cs b/Source/Components/ImageGlass.Heart/Img.cs deleted file mode 100644 index 89a820f4d..000000000 --- a/Source/Components/ImageGlass.Heart/Img.cs +++ /dev/null @@ -1,190 +0,0 @@ -/* -ImageGlass Project - Image viewer for Windows -Copyright (C) 2020 DUONG DIEU PHAP -Project homepage: https://imageglass.org - -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 . -*/ - -using System; -using System.Drawing; -using System.Drawing.Imaging; -using System.Threading.Tasks; - -namespace ImageGlass.Heart -{ - public class Img: IDisposable - { - - #region PUBLIC PROPERTIES - - /// - /// Gets the error details - /// - public Exception Error { get; private set; } = null; - - - /// - /// Gets the value indicates that image loading is done - /// - public bool IsDone { get; private set; } = false; - - - /// - /// Gets, sets filename of Img - /// - public string Filename { get; set; } = string.Empty; - - - /// - /// Gets, sets Bitmap data - /// - public Bitmap Image { get; set; } = null; - - - /// - /// Gets, sets number of image pages - /// - public int PageCount { get; private set; } = 0; - - - /// - /// Gets, sets the active page index - /// - public int ActivePageIndex { get; private set; } = 0; - - #endregion - - - - /// - /// The Img class contain image data - /// - /// Image filename - public Img(string filename) - { - this.Filename = filename; - } - - - #region PUBLIC FUNCTIONS - - /// - /// Release all resources of Img - /// - public void Dispose() - { - this.IsDone = false; - this.Error = null; - this.PageCount = 0; - - if (this.Image != null) - { - this.Image.Dispose(); - } - } - - - /// - /// Load the image - /// - /// A custom size of image - /// Name or Full path of color profile - /// If FALSE, only the images with embedded profile will be applied - /// MagickImage.Channel value - /// Use the embeded thumbnail if found - public async Task LoadAsync(Size size = new Size(), string colorProfileName = "", bool isApplyColorProfileForAll = false, int channel = -1, bool useEmbeddedThumbnail = false) - { - // reset done status - this.IsDone = false; - - // reset error - this.Error = null; - - try - { - // load image data - this.Image = await Photo.LoadAsync( - filename: this.Filename, - size: size, - colorProfileName: colorProfileName, - isApplyColorProfileForAll: isApplyColorProfileForAll, - channel: channel, - useEmbeddedThumbnail: useEmbeddedThumbnail - ); - - // Get page count - var dim = new FrameDimension(this.Image.FrameDimensionsList[0]); - this.PageCount = this.Image.GetFrameCount(dim); - } - catch (Exception ex) - { - // save the error - this.Error = ex; - } - - - // done loading - this.IsDone = true; - } - - - /// - /// Get thumbnail - /// - /// A custom size of thumbnail - /// Return the embedded thumbnail if required size was not found. - /// - public async Task GetThumbnailAsync(Size size, bool useEmbeddedThumbnail = true) - { - return await Photo.GetThumbnailAsync(this.Filename, size, useEmbeddedThumbnail); - } - - - /// - /// Sets active page index - /// - /// Page index - public void SetActivePage(int index) - { - // Check if page index is greater than upper limit - if (index >= this.PageCount) - index = 0; - - // Check if page index is less than lower limit - if (index < 0) - index = this.PageCount - 1; - - this.ActivePageIndex = index; - - // Set active page index - FrameDimension dim = new FrameDimension(this.Image.FrameDimensionsList[0]); - this.Image.SelectActiveFrame(dim, this.ActivePageIndex); - } - - - /// - /// Save image pages to files - /// - /// The destination folder to save to - /// - public async Task SaveImagePages(string destFolder) - { - await Photo.SaveImagePagesAsync(this.Filename, destFolder); - } - - #endregion - - } -} diff --git a/Source/Components/ImageGlass.Heart/Photo.cs b/Source/Components/ImageGlass.Heart/Photo.cs deleted file mode 100644 index 5c59fe888..000000000 --- a/Source/Components/ImageGlass.Heart/Photo.cs +++ /dev/null @@ -1,539 +0,0 @@ -/* -ImageGlass Project - Image viewer for Windows -Copyright (C) 2020 DUONG DIEU PHAP -Project homepage: https://imageglass.org - -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 . -*/ - - -using System.Drawing; -using System.IO; -using System.Threading.Tasks; -using ImageMagick; -using System.Linq; - -namespace ImageGlass.Heart -{ - public static class Photo - { - - #region Load image / thumbnail - - /// - /// Load image from file - /// - /// Full path of image file - /// A custom size of image - /// Name or Full path of color profile - /// If FALSE, only the images with embedded profile will be applied - /// Image quality - /// MagickImage.Channel value - /// Return the embedded thumbnail if required size was not found. - /// Bitmap - public static Bitmap Load( - string filename, - Size size = new Size(), - string colorProfileName = "sRGB", - bool isApplyColorProfileForAll = false, - int quality = 100, - int channel = -1, - bool useEmbeddedThumbnails = false - ) - { - Bitmap bitmap = null; - var ext = Path.GetExtension(filename).ToUpperInvariant(); - var settings = new MagickReadSettings(); - - #region Settings - if (ext == ".SVG") - { - settings.BackgroundColor = MagickColors.Transparent; - } - - if (size.Width > 0 && size.Height > 0) - { - settings.Width = size.Width; - settings.Height = size.Height; - } - #endregion - - - #region Read image data - switch (ext) - { - case ".GIF": - // Note: Using FileStream is much faster than using MagickImageCollection - using (FileStream fs = new FileStream(filename, FileMode.Open, FileAccess.Read)) - { - var ms = new MemoryStream(); - fs.CopyTo(ms); - ms.Position = 0; - - bitmap = new Bitmap(ms, true); - } - break; - - case ".ICO": - case ".TIF": - case ".WEBP": - try - { - using (var imgColl = new MagickImageCollection(filename, settings)) - { - bitmap = imgColl.ToBitmap(); - } - } - catch - { - // Issue #637: MagickImageCollection falls over with certain images, fallback to MagickImage - ReadWithMagickImage(); - } - break; - - default: - ReadWithMagickImage(); - - break; - } - #endregion - - - #region Internal Functions - - // Preprocess magick image - void PreprocesMagickImage(MagickImage imgM, bool checkRotation = true) - { - imgM.Quality = quality; - - - // Get Exif information - var profile = imgM.GetExifProfile(); - - // Use embedded thumbnails if specified - if (profile != null && useEmbeddedThumbnails) - { - // Fetch the embedded thumbnail - var thumbM = profile.CreateThumbnail(); - if (thumbM != null) - { - bitmap = thumbM.ToBitmap(); - } - } - - - // Revert to source image if an embedded thumbnail with required size was not found. - if (bitmap == null) - { - if (profile != null && checkRotation) - { - // Get Orientation Flag - var exifRotationTag = profile.GetValue(ExifTag.Orientation); - - if (exifRotationTag != null) - { - if (int.TryParse(exifRotationTag.Value.ToString(), out var orientationFlag)) - { - var orientationDegree = Helpers.GetOrientationDegree(orientationFlag); - if (orientationDegree != 0) - { - //Rotate image accordingly - imgM.Rotate(orientationDegree); - } - } - } - } - - - // get the color profile of image - var imgColorProfile = imgM.GetColorProfile(); - - - // if always apply color profile - // or only apply color profile if there is an embedded profile - if (isApplyColorProfileForAll || imgColorProfile != null) - { - if (imgColorProfile != null) - { - // correct the image color space - imgM.ColorSpace = imgColorProfile.ColorSpace; - } - else - { - // set default color profile and color space - imgM.AddProfile(ColorProfile.SRGB); - imgM.ColorSpace = ColorProfile.SRGB.ColorSpace; - } - - var colorProfile = Helpers.GetColorProfile(colorProfileName); - if (colorProfile != null) - { - imgM.AddProfile(colorProfile); - imgM.ColorSpace = colorProfile.ColorSpace; - } - } - } - - } - - - // Separate color channel - MagickImage ApplyColorChannel(MagickImage imgM) - { - // separate color channel - if (channel != -1) - { - var magickChannel = (Channels)channel; - var channelImgM = (MagickImage)imgM.Separate(magickChannel).First(); - - if (imgM.HasAlpha && magickChannel != Channels.Alpha) - { - using (var alpha = imgM.Separate(Channels.Alpha).First()) - { - channelImgM.Composite(alpha, CompositeOperator.CopyAlpha); - } - } - - - return channelImgM; - } - - return imgM; - } - - - void ReadWithMagickImage() - { - // Issue #530: ImageMagick falls over if the file path is longer than the (old) - // windows limit of 260 characters. Workaround is to read the file bytes, but - // that requires using the "long path name" prefix to succeed. - - //filename = Helpers.PrefixLongPath(filename); - //var allBytes = File.ReadAllBytes(filename); - - // TODO: there is a bug of using bytes[]: - // https://github.com/dlemstra/Magick.NET/issues/538 - using (var imgM = new MagickImage(filename, settings)) - { - var checkRotation = ext != ".HEIC"; - PreprocesMagickImage(imgM, checkRotation); - - using (var channelImgM = ApplyColorChannel(imgM)) - { - bitmap = channelImgM.ToBitmap(); - } - } - } - #endregion - - - return bitmap; - } - - - /// - /// Load image from file - /// - /// Full path of image file - /// A custom size of image - /// Name or Full path of color profile - /// If FALSE, only the images with embedded profile will be applied - /// Image quality - /// MagickImage.Channel value - /// Use embeded thumbnail if found - /// - public static async Task LoadAsync(string filename, Size size = new Size(), string colorProfileName = "sRGB", bool isApplyColorProfileForAll = false, int quality = 100, int channel = -1, bool useEmbeddedThumbnail = false) - { - Bitmap bitmap = null; - - await Task.Run(() => - { - bitmap = Load( - filename, - size, - colorProfileName, - isApplyColorProfileForAll, - quality, - channel: channel, - useEmbeddedThumbnail - ); - }).ConfigureAwait(false); - - - return bitmap; - } - - - - /// - /// Get thumbnail image - /// - /// Full path of image file - /// A custom size of thumbnail - /// Return the embedded thumbnail if required size was not found. - /// - public static Bitmap GetThumbnail(string filename, Size size, bool useEmbeddedThumbnails = true) - { - Bitmap bmp = Load(filename, - size: size, - quality: 75, - useEmbeddedThumbnails: useEmbeddedThumbnails); - - return bmp; - } - - - /// - /// Get thumbnail image - /// - /// Full path of image file - /// A custom size of thumbnail - /// Return the embedded thumbnail if required size was not found. - /// - public static async Task GetThumbnailAsync(string filename, Size size, bool useEmbeddedThumbnails = true) - { - Bitmap bmp = null; - - await Task.Run(() => - { - bmp = Load(filename, - size: size, - quality: 75, - useEmbeddedThumbnails: useEmbeddedThumbnails); - - }).ConfigureAwait(false); - - return bmp; - } - - #endregion - - - #region Save image as file - - /// - /// Save as image file - /// - /// Source filename to save - /// Destination filename - /// New image format - /// JPEG/MIFF/PNG compression level - public static async Task SaveImageAsync(string srcFileName, string destFileName, MagickFormat format = MagickFormat.Unknown, int quality = 100) - { - await Task.Run(() => - { - using (var imgM = new MagickImage(srcFileName)) - { - imgM.Quality = quality; - imgM.Write(destFileName, format); - } - }).ConfigureAwait(false); - } - - - /// - /// Save as image file - /// - /// Source bitmap to save - /// Destination filename - /// New image format - /// JPEG/MIFF/PNG compression level - public static void SaveImage(Bitmap srcBitmap, string destFileName, int format = (int)MagickFormat.Unknown, int quality = 100) - { - using (var imgM = new MagickImage(srcBitmap)) - { - imgM.Quality = quality; - - if (format != (int)MagickFormat.Unknown) - { - imgM.Write(destFileName, (MagickFormat)format); - } - else - { - imgM.Write(destFileName); - } - } - } - - - /// - /// Save image pages to files - /// - /// The full path of source file - /// The destination folder to save to - public static async Task SaveImagePagesAsync(string filename, string destFolder) - { - await Task.Run(() => - { - // create dirs unless it does not exist - Directory.CreateDirectory(destFolder); - - using (var imgColl = new MagickImageCollection(filename)) - { - var index = 0; - foreach (var imgM in imgColl) - { - index++; - imgM.Quality = 100; - - try - { - var newFilename = Path.GetFileNameWithoutExtension(filename) + " - " + - index.ToString($"D{imgColl.Count.ToString().Length}") + ".png"; - var destFilePath = Path.Combine(destFolder, newFilename); - - imgM.Write(destFilePath, MagickFormat.Png); - } - catch { } - } - } - }); - } - - - #endregion - - - #region Rotate image - - /// - /// Rotate image - /// - /// Source filename - /// Degrees to rotate - /// - public static async Task RotateImage(string srcFileName, int degrees) - { - Bitmap bitmap = null; - - await Task.Run(() => - { - using (var imgM = new MagickImage(srcFileName)) - { - imgM.Rotate(degrees); - imgM.Quality = 100; - - bitmap = imgM.ToBitmap(); - } - }); - - return bitmap; - } - - /// - /// Rotate image - /// - /// Source bitmap - /// Degrees to rotate - /// - public static async Task RotateImage(Bitmap srcBitmap, int degrees) - { - Bitmap bitmap = null; - - await Task.Run(() => - { - using (var imgM = new MagickImage(srcBitmap)) - { - imgM.Rotate(degrees); - imgM.Quality = 100; - - bitmap = imgM.ToBitmap(); - } - }); - - return bitmap; - } - - #endregion - - - #region Flip / flop - - /// - /// Flip / flop an image - /// - /// Source filename - /// Reflect each scanline in the horizontal/vertical direction - /// - public static async Task Flip(string srcFileName, bool isHorzontal) - { - Bitmap bitmap = null; - - await Task.Run(() => - { - using (var imgM = new MagickImage(srcFileName)) - { - bitmap = Flip(imgM, isHorzontal); - } - }); - - return bitmap; - } - - - /// - /// Flip / flop an image - /// - /// Source bitmap - /// Reflect each scanline in the horizontal/vertical direction - /// - public static async Task Flip(Bitmap srcBitmap, bool isHorzontal) - { - Bitmap bitmap = null; - - await Task.Run(() => - { - using (var imgM = new MagickImage(srcBitmap)) - { - bitmap = Flip(imgM, isHorzontal); - } - }); - - return bitmap; - } - - #endregion - - - - - - - #region PRIVATE FUCTIONS - - /// - /// Flip / flop MagickImage - /// - /// - /// - /// - private static Bitmap Flip(MagickImage imgM, bool isHorzontal) - { - if (isHorzontal) - { - imgM.Flop(); - } - else - { - imgM.Flip(); - } - - imgM.Quality = 100; - - return imgM.ToBitmap(); - } - - #endregion - } -} diff --git a/Source/Components/ImageGlass.Heart/Properties/AssemblyInfo.cs b/Source/Components/ImageGlass.Heart/Properties/AssemblyInfo.cs deleted file mode 100644 index 62b5d7c8d..000000000 --- a/Source/Components/ImageGlass.Heart/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,35 +0,0 @@ -using System.Reflection; -using System.Runtime.InteropServices; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyTitle("ImageGlass.Heart")] -[assembly: AssemblyDescription("Heart of ImageGlass")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("Duong Dieu Phap")] -[assembly: AssemblyProduct("ImageGlass.Heart")] -[assembly: AssemblyCopyright("Copyright © 2019-2020 Duong Dieu Phap")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. -[assembly: ComVisible(false)] - -// The following GUID is for the ID of the typelib if this project is exposed to COM -[assembly: Guid("51493b09-7a0e-461f-be18-a6cf629a8fab")] - -// Version information for an assembly consists of the following four values: -// -// Major Version -// Minor Version -// Build Number -// Revision -// -// You can specify all the values or you can default the Build and Revision Numbers -// by using the '*' as shown below: -// [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("7.5.0.0")] -[assembly: AssemblyFileVersion("7.5.0.0")] diff --git a/Source/Components/ImageGlass.Heart/packages.config b/Source/Components/ImageGlass.Heart/packages.config deleted file mode 100644 index 69832c7e6..000000000 --- a/Source/Components/ImageGlass.Heart/packages.config +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/Source/Components/ImageGlass.ImageBox/DefaultGifAnimator.cs b/Source/Components/ImageGlass.ImageBox/DefaultGifAnimator.cs deleted file mode 100755 index 316905876..000000000 --- a/Source/Components/ImageGlass.ImageBox/DefaultGifAnimator.cs +++ /dev/null @@ -1,69 +0,0 @@ -/* -ImageGlass Project - Image viewer for Windows -Copyright (C) 2017 DUONG DIEU PHAP -Project homepage: http://imageglass.org - -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 . -*/ - - -/****************************************** -* THANKS [Meowski] FOR THIS CONTRIBUTION -*******************************************/ - -using System; -using System.Drawing; - -namespace ImageGlass { - /// - /// This is a wrapper for the original System.Drawing animator. See . - /// - public class DefaultGifAnimator : GifAnimator { - - /// - /// Updates the time frame for this image. - /// - /// - public void UpdateFrames(Image image) { - ImageAnimator.UpdateFrames(image); - } - - /// - /// Stops updating frames for the given image. - /// - /// - /// - public void StopAnimate(Image image, EventHandler eventHandler) { - ImageAnimator.StopAnimate(image, eventHandler); - } - - /// - /// Animates the given image. - /// - /// - /// - public void Animate(Image image, EventHandler eventHandler) { - ImageAnimator.Animate(image, eventHandler); - } - - /// - /// Determines whether an image can be animated. - /// - /// - /// - public bool CanAnimate(Image image) { - return ImageAnimator.CanAnimate(image); - } - } -} \ No newline at end of file diff --git a/Source/Components/ImageGlass.ImageBox/GifAnimator.cs b/Source/Components/ImageGlass.ImageBox/GifAnimator.cs deleted file mode 100755 index c24c90460..000000000 --- a/Source/Components/ImageGlass.ImageBox/GifAnimator.cs +++ /dev/null @@ -1,56 +0,0 @@ -/* -ImageGlass Project - Image viewer for Windows -Copyright (C) 2017 DUONG DIEU PHAP -Project homepage: http://imageglass.org - -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 . -*/ - - -/****************************************** -* THANKS [Meowski] FOR THIS CONTRIBUTION -*******************************************/ - -using System; -using System.Drawing; - -namespace ImageGlass -{ - /// - /// Used to animate gifs. - /// - public interface GifAnimator - { - /// - /// Updates the time frame for this image. - /// - void UpdateFrames(Image image); - - /// - /// Stops updating frames for the given image. - /// - void StopAnimate(Image image, EventHandler eventHandler); - - /// - /// Animates the given image. - /// - void Animate(Image image, EventHandler onFrameChangedHandler); - - /// - /// Determines whether an image can be animated. - /// - /// true if the given image can be animated, otherwise false. - bool CanAnimate(Image image); - } -} diff --git a/Source/Components/ImageGlass.ImageBox/HighResolutionGifAnimator.cs b/Source/Components/ImageGlass.ImageBox/HighResolutionGifAnimator.cs deleted file mode 100755 index 2c890030e..000000000 --- a/Source/Components/ImageGlass.ImageBox/HighResolutionGifAnimator.cs +++ /dev/null @@ -1,287 +0,0 @@ -/* -ImageGlass Project - Image viewer for Windows -Copyright (C) 2017-2019 DUONG DIEU PHAP -Project homepage: https://imageglass.org - -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 . -*/ - - -/****************************************** -* THANKS [Meowski] FOR THIS CONTRIBUTION -*******************************************/ - -using System; -using System.Collections.Concurrent; -using System.Drawing; -using System.Drawing.Imaging; -using System.Threading; - -namespace ImageGlass { - - /// - ///

Implements GifAnimator with the potential to offer a timer resolution of 10ms, - /// the fastest a GIF can animate.

- ///

Each animated image is given its own thread - /// which is torn down with a corresponding call to StopAnimate or when the spawning - /// process dies. The default resolution is 20ms, as windows timers are by default limited - /// to a resolution of 15ms. Call setTickInMilliseconds to ask for a different rate, which - /// sets the fastest tick allowed for all HighResolutionAnimators.

- ///
- public class HighResolutionGifAnimator : GifAnimator { - #region STATIC - private static int ourMinTickTimeInMilliseconds; - private static readonly ConcurrentDictionary ourImageState; - - /// - /// Sets the tick for the animation thread. The thread may use a lower tick to ensure - /// the passed value is divisible by 10 (the gif format operates in units of 10 ms). - /// - /// Ideally should be a multiple of 10. - /// The actual tick value that will be used - public static int SetTickTimeInMilliseconds(int value) { - // 10 is the minimum value, as a GIF's lowest tick rate is 10ms - // - int newTickValue = Math.Max(10, (value / 10) * 10); - ourMinTickTimeInMilliseconds = newTickValue; - return newTickValue; - } - - public static int GetTickTimeInMilliseconds() { - return ourMinTickTimeInMilliseconds; - } - - /// - /// Given a delay amount, return either the minimum tick or delay, whichever is greater. - /// - /// the time to sleep during a tick in milliseconds - private static int getSleepAmountInMilliseconds(int delayInMilliseconds) { - return Math.Max(ourMinTickTimeInMilliseconds, delayInMilliseconds); - } - - static HighResolutionGifAnimator() { - ourMinTickTimeInMilliseconds = 20; - ourImageState = new ConcurrentDictionary(); - } - #endregion - - /// - /// Animates the given image. - /// - /// - /// - public void Animate(Image image, EventHandler onFrameChangedHandler) { - - if (!CanAnimate(image)) - return; - - if (ourImageState.ContainsKey(image)) - return; - - // AddOrUpdate has a race condition that could allow us to erroneously - // create multiple animation threads per image. To combat that - // we manually try to add entries ourself, and if it fails we - // kill the thread. - // - GifImageData toAdd = AddFactory(image, onFrameChangedHandler); - if (!ourImageState.TryAdd(image, toAdd)) - Interlocked.Exchange(ref toAdd.myIsThreadDead, 1); - } - - private GifImageData AddFactory(Image image, EventHandler eventHandler) { - GifImageData data; - lock (image) { - data = new GifImageData(image, eventHandler); - } - - Thread heartbeat = new Thread(() => { - int sleepTime = getSleepAmountInMilliseconds(data.GetCurrentDelayInMilliseconds()); - Thread.Sleep(sleepTime); - while (data.ThreadIsNotDead()) { - data.HandleUpdateTick(); - sleepTime = getSleepAmountInMilliseconds(data.GetCurrentDelayInMilliseconds()); - Thread.Sleep(sleepTime); - } - }); - heartbeat.IsBackground = true; - heartbeat.Name = "heartbeat - HighResolutionAnimator"; - heartbeat.Start(); - return data; - } - - /// - /// Updates the time frame for this image. - /// - /// - public void UpdateFrames(Image image) { - if (image == null) - return; - - GifImageData outData; - if (!ourImageState.TryGetValue(image, out outData)) - return; - - if (!outData.myIsDirty) - return; - - lock (image) { - outData.UpdateFrame(); - } - } - - /// - /// Stops updating frames for the given image. - /// - /// - /// - public void StopAnimate(Image image, EventHandler eventHandler) { - if (image == null) - return; - - GifImageData outData; - if (ourImageState.TryRemove(image, out outData)) - Interlocked.Exchange(ref outData.myIsThreadDead, 1); - } - - // See if we have more than one frame in the time dimension. - // - /// - /// Determines whether an image can be animated. - /// - /// - /// - public bool CanAnimate(Image image) { - if (image == null) - return false; - - lock (image) { - return ImageHasTimeFrames(image); - } - } - - // image lock should be held - // - private bool ImageHasTimeFrames(Image image) - { - try - { - foreach (Guid guid in image.FrameDimensionsList) - { - if (guid == FrameDimension.Time.Guid) - return image.GetFrameCount(FrameDimension.Time) > 1; - } - } - catch - { - // fire-eggs 20191114 fix observed issue: if pounding heavily CTRL+Space (to - // toggle GIF animation) _while_ playing a slideshow, there is a window of - // time where the image could be invalid. This manifested as an exception here. - } - - return false; - } - - private class GifImageData { - private static readonly int FrameDelayTag = 0x5100; - private static readonly int LoopCountTag = 20737; - - // image is used for identification in map - // - public int myIsThreadDead; - - private readonly Image myImage; - private readonly EventHandler myOnFrameChangedHandler; - private readonly int myNumFrames; - private readonly int[] myFrameDelaysInCentiseconds; - public bool myIsDirty; - private int myCurrentFrame; - - // KBR 20190614 respect the GIF loop count value - private int maxLoopCount; - private int currentLoopCount; - - // image should be locked by caller - // - public GifImageData(Image image, EventHandler onFrameChangedHandler) - { - myIsThreadDead = 0; - myImage = image; - // We should only be called if we already know we can be animated. Therefore this - // call is valid. - // - myNumFrames = image.GetFrameCount(FrameDimension.Time); - myFrameDelaysInCentiseconds = new int[myNumFrames]; - PopulateFrameDelays(image); - myCurrentFrame = 0; - myIsDirty = false; - myOnFrameChangedHandler = onFrameChangedHandler; - maxLoopCount = BitConverter.ToInt16(image.GetPropertyItem(LoopCountTag).Value, 0); - currentLoopCount = 0; - } - - public bool ThreadIsNotDead() { - return myIsThreadDead == 0; - } - - public void HandleUpdateTick() - { - // KBR 20190614 Loop through frames, respecting the max loop count - myCurrentFrame++; - if (myCurrentFrame >= myNumFrames) - { - myCurrentFrame = 0; - currentLoopCount++; - - if (maxLoopCount > 0 && currentLoopCount >= maxLoopCount) - { - myIsThreadDead = 1; - return; - } - } - myIsDirty = true; - myOnFrameChangedHandler(myImage, EventArgs.Empty); - } - - public int GetCurrentDelayInMilliseconds() { - return myFrameDelaysInCentiseconds[myCurrentFrame] * 10; - } - - public void UpdateFrame() { - myImage.SelectActiveFrame(FrameDimension.Time, myCurrentFrame); - } - - private void PopulateFrameDelays(Image image) { - byte[] frameDelays = image.GetPropertyItem(FrameDelayTag).Value; - for (int i = 0; i < myNumFrames; i++) { - myFrameDelaysInCentiseconds[i] = BitConverter.ToInt32(frameDelays, i * 4); - // Sometimes gifs have a zero frame delay, erroneously? - // These gifs seem to play differently depending on the program. - // I'll give them a default delay, as most gifs with 0 delay seem - // wayyyy to fast compared to other programs. - // - // 0.1 seconds appears to be chromes default setting... I'll use that - // - // KBR 20181009 Older GIF editors could set the delay to 0, relying on the behavior - // of Netscape Navigator to provide the default minimum of 10ms. On Windows 7, it - // appears necessary to enforce this same default minimum, with no negative impact - // on Windows 10. - // KBR 20181127 10ms is only if the image has a delay of 0. Other delays should not - // be modified (issue #458). - if (myFrameDelaysInCentiseconds[i] < 1) - myFrameDelaysInCentiseconds[i] = 10; - } - } - } - } -} \ No newline at end of file diff --git a/Source/Components/ImageGlass.ImageBox/ImageBox.bmp b/Source/Components/ImageGlass.ImageBox/ImageBox.bmp deleted file mode 100644 index f781ccf47..000000000 Binary files a/Source/Components/ImageGlass.ImageBox/ImageBox.bmp and /dev/null differ diff --git a/Source/Components/ImageGlass.ImageBox/ImageBox.cs b/Source/Components/ImageGlass.ImageBox/ImageBox.cs deleted file mode 100644 index 8daa77555..000000000 --- a/Source/Components/ImageGlass.ImageBox/ImageBox.cs +++ /dev/null @@ -1,5302 +0,0 @@ -using System; -using System.ComponentModel; -//using System.Diagnostics; -using System.Drawing; -using System.Drawing.Drawing2D; -using System.Runtime.InteropServices; -using System.Windows.Forms; - -namespace ImageGlass -{ - // Cyotek ImageBox - // Copyright (c) 2010-2015 Cyotek Ltd. - // http://cyotek.com - // http://cyotek.com/blog/tag/imagebox - - // Licensed under the MIT License. See license.txt for the full text. - - // If you use this control in your applications, attribution, donations or contributions are welcome. - - /// - /// Component for displaying images with support for scrolling and zooming. - /// - [DefaultProperty("Image")] - [ToolboxBitmap(typeof(ImageBox), "ImageBox.bmp")] - [ToolboxItem(true)] - /* [Designer("ImageGlass.ImageBox.Design.ImageBoxDesigner", ImageGlass.ImageBox.ImageBox.Design.dll, PublicKeyToken=58daa28b0b2de221")] */ - public class ImageBox : Control - { - #region Instance Fields - - private BorderStyle _borderStyle; - - #endregion - - #region Events - - /// - /// Occurs when the BorderStyle property is changed - /// - [Category("Property Changed")] - public event EventHandler BorderStyleChanged; - - #endregion - - #region Overridden Properties - - /// - /// Gets the required creation parameters when the control handle is created. - /// - protected override CreateParams CreateParams - { - get - { - CreateParams createParams; - - createParams = base.CreateParams; - - switch (_borderStyle) - { - case BorderStyle.FixedSingle: - createParams.Style |= NativeMethods.WS_BORDER; - break; - case BorderStyle.Fixed3D: - createParams.ExStyle |= NativeMethods.WS_EX_CLIENTEDGE; - break; - } - - return createParams; - } - } - - #endregion - - #region Public Properties - - /// - /// Indicates the border style for the control. - /// - [Category("Appearance")] - [DefaultValue(typeof(BorderStyle), "Fixed3D")] - public virtual BorderStyle BorderStyle - { - get { return _borderStyle; } - set - { - if (BorderStyle != value) - { - _borderStyle = value; - - OnBorderStyleChanged(EventArgs.Empty); - } - } - } - - /// - /// [IG_CHANGE] Gets value whether the image can animate or not - /// - public bool CanAnimate - { - get { return Animator.CanAnimate(Image); } - } - - #endregion - - #region Protected Members - - /// - /// Raises the event. - /// - /// - /// An that contains the event data. - /// - protected virtual void OnBorderStyleChanged(EventArgs e) - { - EventHandler handler; - - base.UpdateStyles(); - - handler = BorderStyleChanged; - - if (handler != null) - { - handler(this, e); - } - } - - #endregion - - #region Constants - - private const int MaxZoom = 3500; - - private const int MinZoom = 1; - - private const int SelectionDeadZone = 5; - - #endregion - - #region Instance Fields - - private bool _allowClickZoom; - - private bool _allowDoubleClick; - - /// - /// [IG_CHANGE] - /// - private GifAnimator _animator; - - private bool _autoCenter; - - private bool _autoPan; - - private int _dropShadowSize; - - private int _gridCellSize; - - private Color _gridColor; - - private Color _gridColorAlternate; - - private ImageBoxGridDisplayMode _gridDisplayMode; - - private ImageBoxGridScale _gridScale; - - private Bitmap _gridTile; - - private Image _image; - - private Color _imageBorderColor; - - private ImageBoxBorderStyle _imageBorderStyle; - - private InterpolationMode _interpolationMode; - - private bool _invertMouse; - - private bool _isPanning; - - private bool _limitSelectionToImage; - - private Color _pixelGridColor; - - private int _pixelGridThreshold; - - private bool _scaleText; - - private Color _selectionColor; - - private ImageBoxSelectionMode _selectionMode; - - private RectangleF _selectionRegion; - - private bool _shortcutsEnabled; - - private bool _showPixelGrid; - - private ImageBoxSizeMode _sizeMode; - - private Point _startMousePosition; - - private Point _startScrollPosition; - - private ContentAlignment _textAlign; - - private Color _textBackColor; - - private ImageBoxGridDisplayMode _textDisplayMode; - - private Padding _textPadding; - - private Brush _texture; - - private int _updateCount; - - private bool _virtualMode; - - private Size _virtualSize; - - /// - /// [IG_CHANGE] Zoom value changed to double - /// - private double _zoom; - - private ImageBoxZoomLevelCollection _zoomLevels; - - #endregion - - #region Public Constructors - - /// - /// [IG_CHANGE] Initializes a new instance of the class. - /// - public ImageBox() - { - SetStyle(ControlStyles.AllPaintingInWmPaint | ControlStyles.UserPaint | ControlStyles.OptimizedDoubleBuffer | ControlStyles.ResizeRedraw, true); - - // [IG_CHANGE] double click event - // Enable - //SetStyle(ControlStyles.StandardDoubleClick, false); - - //[IG_CHANGE] - _animator = new DefaultGifAnimator(); - - _vScrollBar = new VScrollBar - { - Visible = false - }; - // ReSharper disable once HeapView.DelegateAllocation - _vScrollBar.Scroll += ScrollBarScrollHandler; - - _hScrollBar = new HScrollBar - { - Visible = false - }; - // ReSharper disable once HeapView.DelegateAllocation - _hScrollBar.Scroll += ScrollBarScrollHandler; - - Controls.Add(_vScrollBar); - Controls.Add(_hScrollBar); - - HorizontalScroll = new ImageBoxScrollProperties(_hScrollBar); - VerticalScroll = new ImageBoxScrollProperties(_vScrollBar); - - // ReSharper disable DoNotCallOverridableMethodsInConstructor - BorderStyle = BorderStyle.Fixed3D; - LimitSelectionToImage = true; - DropShadowSize = 3; - ImageBorderStyle = ImageBoxBorderStyle.None; - BackColor = Color.White; - AutoSize = false; - GridScale = ImageBoxGridScale.Small; - GridDisplayMode = ImageBoxGridDisplayMode.Client; - GridColor = Color.Gainsboro; - GridColorAlternate = Color.White; - GridCellSize = 8; - AutoPan = true; - InterpolationMode = InterpolationMode.NearestNeighbor; - AutoCenter = true; - SelectionColor = SystemColors.Highlight; - ActualSize(); - ShortcutsEnabled = true; - ZoomLevels = ImageBoxZoomLevelCollection.Default; - ImageBorderColor = SystemColors.ControlDark; - PixelGridColor = Color.DimGray; - PixelGridThreshold = 5; - TextAlign = ContentAlignment.MiddleCenter; - TextBackColor = Color.Transparent; - TextDisplayMode = ImageBoxGridDisplayMode.Client; - // ReSharper restore DoNotCallOverridableMethodsInConstructor - } - - #endregion - - #region Events - - /// - /// Occurs when the AllowClickZoom property is changed. - /// - [Category("Property Changed")] - public event EventHandler AllowClickZoomChanged; - - /// - /// Occurs when the AllowDoubleClick property value changes - /// - [Category("Property Changed")] - public event EventHandler AllowDoubleClickChanged; - - /// - /// Occurs when the AllowZoom property is changed. - /// - [Category("Property Changed")] - public event EventHandler AllowZoomChanged; - - /// - /// Occurs when the AutoCenter property is changed. - /// - [Category("Property Changed")] - public event EventHandler AutoCenterChanged; - - /// - /// Occurs when the AutoPan property is changed. - /// - [Category("Property Changed")] - public event EventHandler AutoPanChanged; - - /// - /// Occurs when the DropShadowSize property is changed. - /// - [Category("Property Changed")] - public event EventHandler DropShadowSizeChanged; - - /// - /// Occurs when the GridSizeCell property is changed. - /// - [Category("Property Changed")] - public event EventHandler GridCellSizeChanged; - - /// - /// Occurs when the GridColorAlternate property is changed. - /// - [Category("Property Changed")] - public event EventHandler GridColorAlternateChanged; - - /// - /// Occurs when the GridColor property is changed. - /// - [Category("Property Changed")] - public event EventHandler GridColorChanged; - - /// - /// Occurs when the GridDisplayMode property is changed. - /// - [Category("Property Changed")] - public event EventHandler GridDisplayModeChanged; - - /// - /// Occurs when the GridScale property is changed. - /// - [Category("Property Changed")] - public event EventHandler GridScaleChanged; - - /// - /// Occurs when the ImageBorderColor property value changes - /// - [Category("Property Changed")] - public event EventHandler ImageBorderColorChanged; - - /// - /// Occurs when the ImageBorderStyle property is changed. - /// - [Category("Property Changed")] - public event EventHandler ImageBorderStyleChanged; - - /// - /// Occurs when the Image property is changed. - /// - [Category("Property Changed")] - public event EventHandler ImageChanged; - - /// - /// Occurs when the InterpolationMode property is changed. - /// - [Category("Property Changed")] - public event EventHandler InterpolationModeChanged; - - /// - /// Occurs when the InvertMouse property is changed. - /// - [Category("Property Changed")] - public event EventHandler InvertMouseChanged; - - /// - /// Occurs when the LimitSelectionToImage property is changed. - /// - [Category("Property Changed")] - public event EventHandler LimitSelectionToImageChanged; - - /// - /// Occurs when panning the control completes. - /// - [Category("Action")] - public event EventHandler PanEnd; - - /// - /// Occurs when panning the control starts. - /// - [Category("Action")] - public event EventHandler PanStart; - - /// - /// Occurs when the PixelGridColor property value changes - /// - [Category("Property Changed")] - public event EventHandler PixelGridColorChanged; - - /// - /// Occurs when the PixelGridThreshold property value changes - /// - [Category("Property Changed")] - public event EventHandler PixelGridThresholdChanged; - - /// - /// Occurs when the ScaleText property value changes - /// - [Category("Property Changed")] - public event EventHandler ScaleTextChanged; - - /// - /// Occurs when a selection region has been defined - /// - [Category("Action")] - public event EventHandler Selected; - - /// - /// Occurs when the user starts to define a selection region. - /// - [Category("Action")] - public event EventHandler Selecting; - - /// - /// Occurs when the SelectionColor property is changed. - /// - [Category("Property Changed")] - public event EventHandler SelectionColorChanged; - - /// - /// Occurs when the SelectionMode property is changed. - /// - [Category("Property Changed")] - public event EventHandler SelectionModeChanged; - - /// - /// Occurs when the SelectionRegion property is changed. - /// - [Category("Property Changed")] - public event EventHandler SelectionRegionChanged; - - /// - /// Occurs when the ShortcutsEnabled property value changes - /// - [Category("Property Changed")] - public event EventHandler ShortcutsEnabledChanged; - - /// - /// Occurs when the ShowPixelGrid property value changes - /// - [Category("Property Changed")] - public event EventHandler ShowPixelGridChanged; - - /// - /// Occurs when the SizeMode property value changes - /// - [Category("Property Changed")] - public event EventHandler SizeModeChanged; - - /// - /// Occurs when the SizeToFit property is changed. - /// - [Category("Property Changed")] - public event EventHandler SizeToFitChanged; - - /// - /// Occurs when the TextAlign property value changes - /// - [Category("Property Changed")] - public event EventHandler TextAlignChanged; - - /// - /// Occurs when the TextBackColor property value changes - /// - [Category("Property Changed")] - public event EventHandler TextBackColorChanged; - - /// - /// Occurs when the TextDisplayMode property value changes - /// - [Category("Property Changed")] - public event EventHandler TextDisplayModeChanged; - - /// - /// Occurs when the TextPadding property value changes - /// - [Category("Property Changed")] - public event EventHandler TextPaddingChanged; - - /// - /// Occurs when virtual painting should occur - /// - [Category("Appearance")] - public event PaintEventHandler VirtualDraw; - - /// - /// Occurs when the VirtualMode property value changes - /// - [Category("Property Changed")] - public event EventHandler VirtualModeChanged; - - /// - /// Occurs when the VirtualSize property value changes - /// - [Category("Property Changed")] - public event EventHandler VirtualSizeChanged; - - /// - /// Occurs when the Zoom property is changed. - /// - [Category("Property Changed")] - public event EventHandler ZoomChanged; - - /// - /// Occurs when the ZoomLevels property is changed - /// - [Category("Property Changed")] - public event EventHandler ZoomLevelsChanged; - - /// - /// Occurs when then a zoom action is performed. - /// - [Category("Action")] - public event EventHandler Zoomed; - - #endregion - - #region Public Class Members - - /// - /// Creates a bitmap image containing a 2x2 grid using the specified cell size and colors. - /// - /// Size of the cell. - /// Cell color. - /// Alternate cell color. - /// - public static Bitmap CreateCheckerBoxTile(int cellSize, Color cellColor, Color alternateCellColor) - { - Bitmap result; - int width; - int height; - - // draw the tile - width = cellSize * 2; - height = cellSize * 2; - result = new Bitmap(width, height); - - using (Graphics g = Graphics.FromImage(result)) - { - using (Brush brush = new SolidBrush(cellColor)) - { - g.FillRectangle(brush, new Rectangle(cellSize, 0, cellSize, cellSize)); - g.FillRectangle(brush, new Rectangle(0, cellSize, cellSize, cellSize)); - } - - using (Brush brush = new SolidBrush(alternateCellColor)) - { - g.FillRectangle(brush, new Rectangle(0, 0, cellSize, cellSize)); - g.FillRectangle(brush, new Rectangle(cellSize, cellSize, cellSize, cellSize)); - } - } - - return result; - } - - /// - /// Creates a checked tile texture using default values. - /// - /// - public static Bitmap CreateCheckerBoxTile() - { - return ImageBox.CreateCheckerBoxTile(8, Color.Gainsboro, Color.WhiteSmoke); - } - - /// - /// Use mouse wheel to scroll the image vertically (by default) or horizontally - /// - /// - /// - public void ScrollWithMouseWheel(int delta, bool horizontal = false) - { - Size clientSize; - clientSize = GetInsideViewPort(true).Size; - if (horizontal) - { - if (ScaledImageWidth > clientSize.Width) - { - AdjustScroll(-delta, 0); - } - } - else - { - if (ScaledImageHeight > clientSize.Height) - { - AdjustScroll(0, -delta); - } - } - } - - /// - /// Use mouse wheel to zoom the image - /// - /// - /// - public void ZoomWithMouseWheel(int delta, Point cursorPosition) - { - if (SizeMode == ImageBoxSizeMode.Normal) - { - int spins; - // The MouseWheel event can contain multiple "spins" of the wheel so we need to adjust accordingly - spins = Math.Abs(delta / SystemInformation.MouseWheelScrollDelta); - // TODO: Really should update the source method to handle multiple increments rather than calling it multiple times - for (int i = 0; i < spins; i++) - { - ProcessMouseZoom(delta > 0, cursorPosition); - } - } - } - - #endregion - - #region Overridden Properties - - /// - /// Specifies if the control should auto size to fit the image contents. - /// - /// - /// - /// true if enabled; otherwise, false - /// - [Browsable(true)] - [EditorBrowsable(EditorBrowsableState.Always)] - [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] - [DefaultValue(false)] - public override bool AutoSize - { - get { return base.AutoSize; } - set - { - if (base.AutoSize != value) - { - base.AutoSize = value; - - AdjustLayout(); - } - } - } - - /// - /// Gets or sets the background color for the control. - /// - /// - /// - /// A that represents the background color of the control. The default is the value of the - /// - /// property. - /// - [DefaultValue(typeof(Color), "White")] - public override Color BackColor - { - get { return base.BackColor; } - set { base.BackColor = value; } - } - - /// - /// Gets or sets the background image displayed in the control. - /// - /// - /// - /// An that represents the image to display in the background of the control. - /// - [Browsable(false)] - [EditorBrowsable(EditorBrowsableState.Never)] - [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] - public override Image BackgroundImage - { - get { return base.BackgroundImage; } - set { base.BackgroundImage = value; } - } - - /// - /// Gets or sets the background image layout as defined in the enumeration. - /// - /// The background image layout. - /// - /// One of the values of ( - /// - /// , , - /// - /// , , or - /// - /// ). is the default value. - /// - [Browsable(false)] - [EditorBrowsable(EditorBrowsableState.Never)] - [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] - public override ImageLayout BackgroundImageLayout - { - get { return base.BackgroundImageLayout; } - set { base.BackgroundImageLayout = value; } - } - - #endregion - - #region Overridden Methods - - /// - /// Retrieves the size of a rectangular area into which a control can be fitted. - /// - /// The custom-sized area for a control. - /// - /// An ordered pair of type representing the width and height of a rectangle. - /// - public override Size GetPreferredSize(Size proposedSize) - { - Size size; - - if (!ViewSize.IsEmpty) - { - int width; - int height; - - // get the size of the image - width = ScaledImageWidth; - height = ScaledImageHeight; - - // add an offset based on padding - width += Padding.Horizontal; - height += Padding.Vertical; - - // add an offset based on the border style - width += GetImageBorderOffset(); - height += GetImageBorderOffset(); - - size = new Size(width, height); - } - else - { - size = base.GetPreferredSize(proposedSize); - } - - return size; - } - - /// - /// Clean up any resources being used. - /// - /// true if managed resources should be disposed; otherwise, false. - protected override void Dispose(bool disposing) - { - if (disposing) - { - if (IsAnimating) - { - // ReSharper disable once HeapView.DelegateAllocation - Animator.StopAnimate(Image, OnFrameChangedHandler); - } - - if (_hScrollBar != null) - { - Controls.Remove(_hScrollBar); - // ReSharper disable once HeapView.DelegateAllocation - _hScrollBar.Scroll -= ScrollBarScrollHandler; - _hScrollBar.Dispose(); - } - - if (_vScrollBar != null) - { - Controls.Remove(_vScrollBar); - // ReSharper disable once HeapView.DelegateAllocation - _vScrollBar.Scroll -= ScrollBarScrollHandler; - _vScrollBar.Dispose(); - } - - if (_texture != null) - { - _texture.Dispose(); - _texture = null; - } - - if (_gridTile != null) - { - _gridTile.Dispose(); - _gridTile = null; - } - } - - base.Dispose(disposing); - } - - /// - /// Determines whether the specified key is a regular input key or a special key that requires preprocessing. - /// - /// - /// One of the values. - /// - /// - /// true if the specified key is a regular input key; otherwise, false. - /// - protected override bool IsInputKey(Keys keyData) - { - bool result; - - if ((keyData & Keys.Right) == Keys.Right | (keyData & Keys.Left) == Keys.Left | (keyData & Keys.Up) == Keys.Up | (keyData & Keys.Down) == Keys.Down) - { - result = true; - } - else - { - result = base.IsInputKey(keyData); - } - - return result; - } - - /// - /// Raises the event. - /// - /// - /// An that contains the event data. - /// - protected override void OnBackColorChanged(EventArgs e) - { - base.OnBackColorChanged(e); - - Invalidate(); - } - - /// - /// Raises the event. - /// - /// - /// An that contains the event data. - /// - protected override void OnDockChanged(EventArgs e) - { - base.OnDockChanged(e); - - if (Dock != DockStyle.None) - { - AutoSize = false; - } - } - - /// - /// Raises the event. - /// - /// An that contains the event data. - protected override void OnFontChanged(EventArgs e) - { - base.OnFontChanged(e); - - Invalidate(); - } - - /// - /// Raises the event. - /// - /// An that contains the event data. - protected override void OnForeColorChanged(EventArgs e) - { - base.OnForeColorChanged(e); - - Invalidate(); - } - - /// - /// Raises the event. - /// - /// - /// A that contains the event data. - /// - protected override void OnKeyDown(KeyEventArgs e) - { - base.OnKeyDown(e); - - ProcessScrollingShortcuts(e); - - if (ShortcutsEnabled && SizeMode == ImageBoxSizeMode.Normal) - { - ProcessImageShortcuts(e); - } - } - - /// - /// Raises the event. - /// - /// - /// A that contains the event data. - /// - protected override void OnMouseDown(MouseEventArgs e) - { - base.OnMouseDown(e); - - if (!Focused) - { - Focus(); - } - } - - /// - /// Raises the event. - /// - /// - /// A that contains the event data. - /// - protected override void OnMouseMove(MouseEventArgs e) - { - base.OnMouseMove(e); - - if (e.Button == MouseButtons.Left) - { - ProcessPanning(e); - ProcessSelection(e); - } - } - - /// - /// Raises the event. - /// - /// - /// A that contains the event data. - /// - protected override void OnMouseUp(MouseEventArgs e) - { - bool doNotProcessClick; - - base.OnMouseUp(e); - - doNotProcessClick = IsPanning || IsSelecting; - - if (IsPanning) - { - IsPanning = false; - } - - if (IsSelecting) - { - EndDrag(); - } - WasDragCancelled = false; - - if (!doNotProcessClick && AllowClickZoom && !IsPanning && SizeMode == ImageBoxSizeMode.Normal) - { - if (e.Button == MouseButtons.Left && ModifierKeys == Keys.None) - { - ProcessMouseZoom(true, e.Location); - } - else if (e.Button == MouseButtons.Right || (e.Button == MouseButtons.Left && ModifierKeys != Keys.None)) - { - ProcessMouseZoom(false, e.Location); - } - } - } - - /// - /// Raises the event. - /// - /// - /// A that contains the event data. - /// - protected override void OnMouseWheel(MouseEventArgs e) - { - base.OnMouseWheel(e); - } - - /// - /// Raises the event. - /// - /// - /// An that contains the event data. - /// - protected override void OnPaddingChanged(EventArgs e) - { - base.OnPaddingChanged(e); - AdjustLayout(); - } - - /// - /// Raises the event. - /// - /// - /// A that contains the event data. - /// - protected override void OnPaint(PaintEventArgs e) - { - if (AllowPainting) - { - // draw the background - DrawBackground(e); - - // draw the image - if (!ViewSize.IsEmpty) - { - DrawImageBorder(e.Graphics); - } - if (VirtualMode) - { - OnVirtualDraw(e); - } - else if (Image != null) - { - DrawImage(e.Graphics); - } - - // draw the grid - if (ShowPixelGrid && !VirtualMode) - { - DrawPixelGrid(e.Graphics); - } - - // draw the selection - if (SelectionRegion != Rectangle.Empty) - { - DrawSelection(e); - } - - // text - if (!string.IsNullOrEmpty(Text) && TextDisplayMode != ImageBoxGridDisplayMode.None) - { - DrawText(e); - } - - // scrollbar corners - if (HorizontalScroll.Visible && VerticalScroll.Visible) - { - int x; - int y; - int w; - int h; - Size clientSize; - - clientSize = ClientSize; - w = _vScrollBar.Width; - h = _hScrollBar.Height; - x = clientSize.Width - w; - y = clientSize.Height - h; - - e.Graphics.FillRectangle(SystemBrushes.Control, x, y, w, h); - } - - base.OnPaint(e); - } - } - - /// - /// Raises the event. - /// - /// - /// An that contains the event data. - /// - protected override void OnParentChanged(EventArgs e) - { - base.OnParentChanged(e); - AdjustLayout(); - } - - /// - /// Raises the event. - /// - /// - /// An that contains the event data. - /// - protected override void OnResize(EventArgs e) - { - AdjustLayout(); - - base.OnResize(e); - } - - /// - /// Raises the event. - /// - /// An that contains the event data. - protected override void OnTextChanged(EventArgs e) - { - base.OnTextChanged(e); - - Invalidate(); - } - - #endregion - - #region Public Properties - - /// - /// Gets or sets a value indicating whether clicking the control with the mouse will automatically zoom in or out. - /// - /// - /// true if clicking the control allows zooming; otherwise, false. - /// - [DefaultValue(false)] - [Category("Behavior")] - public virtual bool AllowClickZoom - { - get { return _allowClickZoom; } - set - { - if (_allowClickZoom != value) - { - _allowClickZoom = value; - OnAllowClickZoomChanged(EventArgs.Empty); - } - } - } - - /// - /// Gets or sets a value indicating whether the DoubleClick event can be raised. - /// - /// true if the DoubleClick event can be raised; otherwise, false. - [Category("Behavior")] - [DefaultValue(false)] - public virtual bool AllowDoubleClick - { - get { return _allowDoubleClick; } - set - { - if (AllowDoubleClick != value) - { - _allowDoubleClick = value; - - OnAllowDoubleClickChanged(EventArgs.Empty); - } - } - } - - - /// - /// [IG_CHANGE] Handles animating gif images - /// - public GifAnimator Animator { - set { - if (Image != null && IsAnimating) { - StopAnimating(); - } - _animator = value; - // Mimick Image property behavior - OnImageChanged(EventArgs.Empty); - } - - get { return _animator; } - } - - /// - /// Gets or sets a value indicating whether the image is centered where possible. - /// - /// - /// true if the image should be centered where possible; otherwise, false. - /// - [DefaultValue(true)] - [Category("Appearance")] - public virtual bool AutoCenter - { - get { return _autoCenter; } - set - { - if (_autoCenter != value) - { - _autoCenter = value; - OnAutoCenterChanged(EventArgs.Empty); - } - } - } - - /// - /// Gets or sets if the mouse can be used to pan the control. - /// - /// - /// true if the control can be auto panned; otherwise, false. - /// - /// If this property is set, the SizeToFit property cannot be used. - [DefaultValue(true)] - [Category("Behavior")] - public virtual bool AutoPan - { - get { return _autoPan; } - set - { - if (_autoPan != value) - { - _autoPan = value; - OnAutoPanChanged(EventArgs.Empty); - } - } - } - - /// - /// Gets the point at the center of the currently displayed image viewport. - /// - /// The point at the center of the current image viewport. - [Browsable(false)] - public Point CenterPoint - { - get - { - Rectangle viewport; - - viewport = GetImageViewPort(); - - return new Point(viewport.Width / 2, viewport.Height / 2); - } - } - - /// - /// Gets or sets the size of the drop shadow. - /// - /// The size of the drop shadow. - [Category("Appearance")] - [DefaultValue(3)] - public virtual int DropShadowSize - { - get { return _dropShadowSize; } - set - { - if (DropShadowSize != value) - { - _dropShadowSize = value; - - OnDropShadowSizeChanged(EventArgs.Empty); - } - } - } - - /// - /// Gets or sets the size of the grid cells. - /// - /// The size of the grid cells. - [Category("Appearance")] - [DefaultValue(8)] - public virtual int GridCellSize - { - get { return _gridCellSize; } - set - { - if (_gridCellSize != value) - { - _gridCellSize = value; - OnGridCellSizeChanged(EventArgs.Empty); - } - } - } - - /// - /// Gets or sets the color of primary cells in the grid. - /// - /// The color of primary cells in the grid. - [Category("Appearance")] - [DefaultValue(typeof(Color), "Gainsboro")] - public virtual Color GridColor - { - get { return _gridColor; } - set - { - if (_gridColor != value) - { - _gridColor = value; - OnGridColorChanged(EventArgs.Empty); - } - } - } - - /// - /// Gets or sets the color of alternate cells in the grid. - /// - /// The color of alternate cells in the grid. - [Category("Appearance")] - [DefaultValue(typeof(Color), "White")] - public virtual Color GridColorAlternate - { - get { return _gridColorAlternate; } - set - { - if (_gridColorAlternate != value) - { - _gridColorAlternate = value; - OnGridColorAlternateChanged(EventArgs.Empty); - } - } - } - - /// - /// Gets or sets the grid display mode. - /// - /// The grid display mode. - [DefaultValue(ImageBoxGridDisplayMode.Client)] - [Category("Appearance")] - public virtual ImageBoxGridDisplayMode GridDisplayMode - { - get { return _gridDisplayMode; } - set - { - if (_gridDisplayMode != value) - { - _gridDisplayMode = value; - OnGridDisplayModeChanged(EventArgs.Empty); - } - } - } - - /// - /// Gets or sets the grid scale. - /// - /// The grid scale. - [DefaultValue(typeof(ImageBoxGridScale), "Small")] - [Category("Appearance")] - public virtual ImageBoxGridScale GridScale - { - get { return _gridScale; } - set - { - if (_gridScale != value) - { - _gridScale = value; - OnGridScaleChanged(EventArgs.Empty); - } - } - } - - /// - /// Gets or sets the image. - /// - /// The image. - [Category("Appearance")] - [DefaultValue(null)] - public virtual Image Image - { - get { return _image; } - set - { - if (_image != value) - { - // disable animations - if (IsAnimating) - { - Animator.StopAnimate(Image, OnFrameChangedHandler); - } - - _image = value; - OnImageChanged(EventArgs.Empty); - } - } - } - - /// - /// Gets or sets the color of the image border. - /// - /// The color of the image border. - [Category("Appearance")] - [DefaultValue(typeof(Color), "ControlDark")] - public virtual Color ImageBorderColor - { - get { return _imageBorderColor; } - set - { - if (ImageBorderColor != value) - { - _imageBorderColor = value; - - OnImageBorderColorChanged(EventArgs.Empty); - } - } - } - - /// - /// Gets or sets the image border style. - /// - /// The image border style. - [Category("Appearance")] - [DefaultValue(typeof(ImageBoxBorderStyle), "None")] - public virtual ImageBoxBorderStyle ImageBorderStyle - { - get { return _imageBorderStyle; } - set - { - if (ImageBorderStyle != value) - { - _imageBorderStyle = value; - - OnImageBorderStyleChanged(EventArgs.Empty); - } - } - } - - /// - /// Gets or sets the interpolation mode. - /// - /// The interpolation mode. - [Category("Appearance")] - [DefaultValue(InterpolationMode.NearestNeighbor)] - public virtual InterpolationMode InterpolationMode - { - get { return _interpolationMode; } - set - { - if (value == InterpolationMode.Invalid) - { - value = InterpolationMode.Default; - } - - if (_interpolationMode != value) - { - _interpolationMode = value; - OnInterpolationModeChanged(EventArgs.Empty); - } - } - } - - /// - /// Gets or sets a value indicating whether the mouse should be inverted when panning the control. - /// - /// - /// true if the mouse should be inverted when panning the control; otherwise, false. - /// - [DefaultValue(false)] - [Category("Behavior")] - public virtual bool InvertMouse - { - get { return _invertMouse; } - set - { - if (_invertMouse != value) - { - _invertMouse = value; - OnInvertMouseChanged(EventArgs.Empty); - } - } - } - - /// - /// Gets a value indicating whether the image is currently being displayed at 100% zoom - /// - /// true if the image is currently being displayed at 100% zoom; otherwise, false. - [Browsable(false)] - public virtual bool IsActualSize - { - get { return Zoom == 100; } - } - - /// - /// Gets a value indicating whether this control is panning. - /// - /// - /// true if this control is panning; otherwise, false. - /// - [DefaultValue(false)] - [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] - [Browsable(false)] - public virtual bool IsPanning - { - get { return _isPanning; } - protected set - { - if (_isPanning != value) - { - CancelEventArgs args; - - args = new CancelEventArgs(); - - if (value) - { - OnPanStart(args); - } - else - { - OnPanEnd(EventArgs.Empty); - } - - if (!args.Cancel) - { - _isPanning = value; - - if (value) - { - _startScrollPosition = AutoScrollPosition; - Cursor = Cursors.SizeAll; - } - else - { - Cursor = Cursors.Default; - } - } - } - } - } - - /// - /// Gets or sets a value indicating whether this a selection region is currently being drawn. - /// - /// - /// true if a selection region is currently being drawn; otherwise, false. - /// - [Browsable(false)] - [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] - public virtual bool IsSelecting { get; protected set; } - - /// - /// Gets or sets a value indicating whether selection regions should be limited to the image boundaries. - /// - /// - /// true if selection regions should be limited to image boundaries; otherwise, false. - /// - [Category("Behavior")] - [DefaultValue(true)] - public virtual bool LimitSelectionToImage - { - get { return _limitSelectionToImage; } - set - { - if (LimitSelectionToImage != value) - { - _limitSelectionToImage = value; - - OnLimitSelectionToImageChanged(EventArgs.Empty); - } - } - } - - /// - /// Gets or sets the color of the pixel grid. - /// - /// The color of the pixel grid. - [Category("Appearance")] - [DefaultValue(typeof(Color), "DimGray")] - public virtual Color PixelGridColor - { - get { return _pixelGridColor; } - set - { - if (PixelGridColor != value) - { - _pixelGridColor = value; - - OnPixelGridColorChanged(EventArgs.Empty); - } - } - } - - /// - /// Gets or sets the minimum size of zoomed pixel's before the pixel grid will be drawn - /// - /// The pixel grid threshold. - [Category("Behavior")] - [DefaultValue(5)] - public virtual int PixelGridThreshold - { - get { return _pixelGridThreshold; } - set - { - if (PixelGridThreshold != value) - { - _pixelGridThreshold = value; - - OnPixelGridThresholdChanged(EventArgs.Empty); - } - } - } - - /// - /// Gets or sets a value indicating whether the font size of text is scaled according to the current zoom level. - /// - /// true if the size of text is scaled according to the current zoom level; otherwise, false. - [Category("Appearance")] - [DefaultValue(false)] - public virtual bool ScaleText - { - get { return _scaleText; } - set - { - if (ScaleText != value) - { - _scaleText = value; - - OnScaleTextChanged(EventArgs.Empty); - } - } - } - - /// - /// Gets or sets the color of selection regions. - /// - /// - /// The color of selection regions. - /// - [Category("Appearance")] - [DefaultValue(typeof(Color), "Highlight")] - public virtual Color SelectionColor - { - get { return _selectionColor; } - set - { - if (SelectionColor != value) - { - _selectionColor = value; - - OnSelectionColorChanged(EventArgs.Empty); - } - } - } - - /// - /// Gets or sets the selection mode. - /// - /// - /// The selection mode. - /// - [Category("Behavior")] - [DefaultValue(typeof(ImageBoxSelectionMode), "None")] - public virtual ImageBoxSelectionMode SelectionMode - { - get { return _selectionMode; } - set - { - if (SelectionMode != value) - { - _selectionMode = value; - - OnSelectionModeChanged(EventArgs.Empty); - } - } - } - - /// - /// Gets or sets the selection region. - /// - /// - /// The selection region. - /// - [Browsable(false)] - [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] - public virtual RectangleF SelectionRegion - { - get { return _selectionRegion; } - set - { - if (SelectionRegion != value) - { - _selectionRegion = value; - - OnSelectionRegionChanged(EventArgs.Empty); - } - } - } - - /// - /// Gets or sets a value indicating whether the defined shortcuts are enabled. - /// - /// - /// true to enable the shortcuts; otherwise, false. - /// - [Category("Behavior")] - [DefaultValue(true)] - public virtual bool ShortcutsEnabled - { - get { return _shortcutsEnabled; } - set - { - if (ShortcutsEnabled != value) - { - _shortcutsEnabled = value; - - OnShortcutsEnabledChanged(EventArgs.Empty); - } - } - } - - /// - /// Gets or sets a value indicating whether a pixel grid is displayed when the control is zoomed. - /// - /// true if a pixel grid is displayed when the control is zoomed; otherwise, false. - [Category("Appearance")] - [DefaultValue(false)] - public virtual bool ShowPixelGrid - { - get { return _showPixelGrid; } - set - { - if (ShowPixelGrid != value) - { - _showPixelGrid = value; - - OnShowPixelGridChanged(EventArgs.Empty); - } - } - } - - /// - /// Gets or sets the size mode of images hosted in the control. - /// - /// The size mode. - [Category("Behavior")] - [DefaultValue(typeof(ImageBoxSizeMode), "Normal")] - public virtual ImageBoxSizeMode SizeMode - { - get { return _sizeMode; } - set - { - if (SizeMode != value) - { - _sizeMode = value; - - OnSizeModeChanged(EventArgs.Empty); - } - } - } - - /// - /// Gets or sets a value indicating whether the control should automatically size to fit the image contents. - /// - /// - /// true if the control should size to fit the image contents; otherwise, false. - /// - [DefaultValue(false)] - [Category("Appearance")] - [Browsable(false)] - [EditorBrowsable(EditorBrowsableState.Never)] - [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] - [Obsolete("This property is deprecated and will be removed in a future version of the component. Implementors should use the SizeMode property instead.")] - public virtual bool SizeToFit - { - get { return SizeMode == ImageBoxSizeMode.Fit; } - set - { - if ((SizeMode == ImageBoxSizeMode.Fit) != value) - { - SizeMode = value ? ImageBoxSizeMode.Fit : ImageBoxSizeMode.Normal; - OnSizeToFitChanged(EventArgs.Empty); - - if (value) - { - AutoPan = false; - } - else - { - ActualSize(); - } - } - } - } - - /// - /// Gets or sets the alignment of the text on the control. - /// - /// One of the values. The default is MiddleCenter. - [Category("Appearance")] - [DefaultValue(typeof(ContentAlignment), "MiddleCenter")] - public virtual ContentAlignment TextAlign - { - get { return _textAlign; } - set - { - if (TextAlign != value) - { - _textAlign = value; - - OnTextAlignChanged(EventArgs.Empty); - } - } - } - - /// - /// Gets or sets the color of the text background. - /// - /// The color of the text background. - [Category("Appearance")] - [DefaultValue(typeof(Color), "Transparent")] - public virtual Color TextBackColor - { - get { return _textBackColor; } - set - { - if (TextBackColor != value) - { - _textBackColor = value; - - OnTextBackColorChanged(EventArgs.Empty); - } - } - } - - /// - /// Gets or sets the text display mode. - /// - /// The text display mode. - [Category("Appearance")] - [DefaultValue(typeof(ImageBoxGridDisplayMode), "Client")] - public virtual ImageBoxGridDisplayMode TextDisplayMode - { - get { return _textDisplayMode; } - set - { - if (TextDisplayMode != value) - { - _textDisplayMode = value; - - OnTextDisplayModeChanged(EventArgs.Empty); - } - } - } - - /// - /// Gets or sets padding of text within the control. - /// - [Category("Appearance")] - [DefaultValue(typeof(Padding), "0, 0, 0, 0")] - public virtual Padding TextPadding - { - get { return _textPadding; } - set - { - if (TextPadding != value) - { - _textPadding = value; - - OnTextPaddingChanged(EventArgs.Empty); - } - } - } - - /// - /// Gets or sets a value indicating whether the control acts as a virtual image box. - /// - /// - /// true if the control acts as a virtual image box; otherwise, false. - /// - /// - /// When this property is set to true, the Image property is ignored in favor of the VirtualSize property. In addition, the VirtualDraw event is raised to allow custom painting of the image area. - /// - [Category("Behavior")] - [DefaultValue(false)] - public virtual bool VirtualMode - { - get { return _virtualMode; } - set - { - if (VirtualMode != value) - { - _virtualMode = value; - - OnVirtualModeChanged(EventArgs.Empty); - } - } - } - - /// - /// Gets or sets the size of the virtual image. - /// - /// The size of the virtual image. - [Category("Appearance")] - [DefaultValue(typeof(Size), "0, 0")] - public virtual Size VirtualSize - { - get { return _virtualSize; } - set - { - if (VirtualSize != value) - { - _virtualSize = value; - - OnVirtualSizeChanged(EventArgs.Empty); - } - } - } - - /// - /// Gets or sets the zoom. - /// [IG_CHANGE] Zoom value changed to double - /// - /// The zoom. - [DefaultValue(100)] - [Category("Appearance")] - public virtual double Zoom - { - get { return _zoom; } - set { SetZoom(value, value > Zoom ? ImageBoxZoomActions.ZoomIn : ImageBoxZoomActions.ZoomOut, ImageBoxActionSources.Unknown); } - } - - /// - /// Gets the zoom factor. - /// [IG_CHANGE] Zoom value changed to double - /// - /// The zoom factor. - [Browsable(false)] - [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] - public virtual double ZoomFactor - { - get { return (double)Zoom / 100; } - } - - /// - /// Gets or sets the zoom levels. - /// - /// The zoom levels. - [Browsable(false) /*Category("Behavior"), DefaultValue(typeof(ZoomLevelCollection), "7, 10, 15, 20, 25, 30, 50, 70, 100, 150, 200, 300, 400, 500, 600, 700, 800, 1200, 1600, 2000, 2500, 3000, 3500")*/] - [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] - public virtual ImageBoxZoomLevelCollection ZoomLevels - { - get { return _zoomLevels; } - set - { - if (ZoomLevels != value) - { - _zoomLevels = value; - - OnZoomLevelsChanged(EventArgs.Empty); - } - } - } - - #endregion - - #region Protected Properties - - /// - /// Gets a value indicating whether painting of the control is allowed. - /// - /// - /// true if painting of the control is allowed; otherwise, false. - /// - protected virtual bool AllowPainting - { - get { return _updateCount == 0; } - } - - /// - /// [IG_CHANGE] Gets or sets a value indicating whether the current image is animated. - /// - /// true if the current image is animated; otherwise, false. - public bool IsAnimating { get; protected set; } - - /// - /// Gets the height of the scaled image. - /// - /// The height of the scaled image. - protected virtual int ScaledImageHeight - { - get { return Scale(ViewSize.Height); } - } - - /// - /// Gets the width of the scaled image. - /// - /// The width of the scaled image. - protected virtual int ScaledImageWidth - { - get { return Scale(ViewSize.Width); } - } - - /// - /// Scales the specified integer according to the current zoom factor. - /// - /// The value to scale. - /// The specified value scaled by the current zoom factor. - protected int Scale(int value) - { - return Convert.ToInt32(value * ZoomFactor); - } - - /// - /// Gets the size of the view. - /// - /// The size of the view. - protected virtual Size ViewSize - { - get { return _viewSize; } - } - - private Size _viewSize; - - /// - /// Gets or sets a value indicating whether a drag operation was cancelled. - /// - /// true if the drag operation was cancelled; otherwise, false. - protected bool WasDragCancelled { get; set; } - - #endregion - - #region Public Members - - /// - /// Resets the zoom to 100%. - /// - public virtual void ActualSize() - { - PerformActualSize(ImageBoxActionSources.Unknown); - } - - /// - /// Disables any redrawing of the image box - /// - public virtual void BeginUpdate() - { - _updateCount++; - } - - /// - /// Stop animating - /// - public void StopAnimating() - { - if (!IsAnimating) - return; - Animator.StopAnimate(Image, OnFrameChangedHandler); - IsAnimating = false; - } - - /// - /// Start animating - /// - public void StartAnimating() - { - if (IsAnimating || !CanAnimate) - return; - - try - { - Animator.Animate(Image, OnFrameChangedHandler); - IsAnimating = true; - } - catch (Exception) { } - } - - /// - /// Centers the given point in the image in the center of the control - /// - /// The point of the image to attempt to center. - public virtual void CenterAt(Point imageLocation) - { - ScrollTo(imageLocation, RelativeCenterPoint); - } - - /// - /// Returns the point in the center of the control based on the current zoom level - /// - private Point RelativeCenterPoint - { get { return new Point((ScaledImageWidth - ClientSize.Width) / 2, (ScaledImageHeight - ClientSize.Height) / 2); } } - - /// - /// Centers the given point in the image in the center of the control - /// - /// The X co-ordinate of the point to center. - /// The Y co-ordinate of the point to center. - public void CenterAt(int x, int y) - { - CenterAt(new Point(x, y)); - } - - /// - /// Centers the given point in the image in the center of the control - /// - /// The X co-ordinate of the point to center. - /// The Y co-ordinate of the point to center. - public void CenterAt(float x, float y) - { - CenterAt(new Point((int)x, (int)y)); - } - - /// - /// Resets the viewport to show the center of the image. - /// - public virtual void CenterToImage() - { - AutoScrollPosition = RelativeCenterPoint; - } - - /// - /// Enables the redrawing of the image box - /// - public virtual void EndUpdate() - { - if (_updateCount > 0) - { - _updateCount--; - } - - if (AllowPainting) - { - Invalidate(); - } - } - - /// - /// Fits a given to match image boundaries - /// - /// The rectangle. - /// - /// A structure remapped to fit the image boundaries - /// - public Rectangle FitRectangle(Rectangle rectangle) - { - int x; - int y; - int w; - int h; - - x = rectangle.X; - y = rectangle.Y; - w = rectangle.Width; - h = rectangle.Height; - - if (x < 0) - { - x = 0; - } - - if (y < 0) - { - y = 0; - } - - if (x + w > ViewSize.Width) - { - w = ViewSize.Width - x; - } - - if (y + h > ViewSize.Height) - { - h = ViewSize.Height - y; - } - - return new Rectangle(x, y, w, h); - } - - /// - /// Fits a given to match image boundaries - /// - /// The rectangle. - /// - /// A structure remapped to fit the image boundaries - /// - public RectangleF FitRectangle(RectangleF rectangle) - { - float x; - float y; - float w; - float h; - - x = rectangle.X; - y = rectangle.Y; - w = rectangle.Width; - h = rectangle.Height; - - if (x < 0) - { - w -= -x; - x = 0; - } - - if (y < 0) - { - h -= -y; - y = 0; - } - - if (x + w > ViewSize.Width) - { - w = ViewSize.Width - x; - } - - if (y + h > ViewSize.Height) - { - h = ViewSize.Height - y; - } - - return new RectangleF(x, y, w, h); - } - - /// - /// Gets the image view port. - /// - /// - public virtual Rectangle GetImageViewPort() - { - Rectangle viewPort; - - if (!ViewSize.IsEmpty) - { - Rectangle innerRectangle; - Point offset; - int width; - int height; - bool hScroll; - bool vScroll; - - innerRectangle = GetInsideViewPort(true); - - hScroll = HScroll; - vScroll = VScroll; - - if (!hScroll && !vScroll) // if no scrolling is present, tinker the view port so that the image and any applicable borders all fit inside - { - innerRectangle.Inflate(-GetImageBorderOffset(), -GetImageBorderOffset()); - } - - if (SizeMode != ImageBoxSizeMode.Stretch) - { - if (AutoCenter) - { - int x; - int y; - - x = !hScroll ? (innerRectangle.Width - (ScaledImageWidth + Padding.Horizontal)) / 2 : 0; - y = !vScroll ? (innerRectangle.Height - (ScaledImageHeight + Padding.Vertical)) / 2 : 0; - - offset = new Point(x, y); - } - else - { - offset = Point.Empty; - } - - width = Math.Min(ScaledImageWidth - Math.Abs(AutoScrollPosition.X), innerRectangle.Width); - height = Math.Min(ScaledImageHeight - Math.Abs(AutoScrollPosition.Y), innerRectangle.Height); - } - else - { - offset = Point.Empty; - width = innerRectangle.Width; - height = innerRectangle.Height; - } - - viewPort = new Rectangle(offset.X + innerRectangle.Left, offset.Y + innerRectangle.Top, width, height); - } - else - { - viewPort = Rectangle.Empty; - } - - return viewPort; - } - - /// - /// Gets the inside view port, excluding any padding. - /// - /// - public Rectangle GetInsideViewPort() - { - return GetInsideViewPort(false); - } - - /// - /// Gets the inside view port. - /// - /// - /// if set to true [include padding]. - /// - /// - public virtual Rectangle GetInsideViewPort(bool includePadding) - { - int left; - int top; - int width; - int height; - Size clientSize; - - clientSize = ClientSize; - left = 0; - top = 0; - width = clientSize.Width; - height = clientSize.Height; - - if (VerticalScroll.Visible) - { - width -= _vScrollBar.Width; - } - - if (HorizontalScroll.Visible) - { - height -= _hScrollBar.Height; - } - - if (includePadding) - { - Padding padding; - - padding = Padding; - left += padding.Left; - top += padding.Top; - width -= padding.Horizontal; - height -= padding.Vertical; - } - - return new Rectangle(left, top, width, height); - } - - /// - /// Returns the source repositioned to include the current image offset and scaled by the current zoom level - /// - /// The source to offset. - /// A which has been repositioned to match the current zoom level and image offset - public virtual Point GetOffsetPoint(Point source) - { - PointF offset; - - offset = GetOffsetPoint(new PointF(source.X, source.Y)); - - return new Point((int)offset.X, (int)offset.Y); - } - - /// - /// Returns the source co-ordinates repositioned to include the current image offset and scaled by the current zoom level - /// - /// The source X co-ordinate. - /// The source Y co-ordinate. - /// A which has been repositioned to match the current zoom level and image offset - public Point GetOffsetPoint(int x, int y) - { - return GetOffsetPoint(new Point(x, y)); - } - - /// - /// Returns the source co-ordinates repositioned to include the current image offset and scaled by the current zoom level - /// - /// The source X co-ordinate. - /// The source Y co-ordinate. - /// A which has been repositioned to match the current zoom level and image offset - public PointF GetOffsetPoint(float x, float y) - { - return GetOffsetPoint(new PointF(x, y)); - } - - /// - /// Returns the source repositioned to include the current image offset and scaled by the current zoom level - /// - /// The source to offset. - /// A which has been repositioned to match the current zoom level and image offset - public virtual PointF GetOffsetPoint(PointF source) - { - Rectangle viewport; - PointF scaled; - int offsetX; - int offsetY; - - viewport = GetImageViewPort(); - scaled = GetScaledPoint(source); - offsetX = viewport.Left + Padding.Left + AutoScrollPosition.X; - offsetY = viewport.Top + Padding.Top + AutoScrollPosition.Y; - - return new PointF(scaled.X + offsetX, scaled.Y + offsetY); - } - - /// - /// Returns the source scaled according to the current zoom level and repositioned to include the current image offset - /// - /// The source to offset. - /// A which has been resized and repositioned to match the current zoom level and image offset - public virtual RectangleF GetOffsetRectangle(RectangleF source) - { - RectangleF viewport; - RectangleF scaled; - float offsetX; - float offsetY; - - viewport = GetImageViewPort(); - scaled = GetScaledRectangle(source); - offsetX = viewport.Left + Padding.Left + AutoScrollPosition.X; - offsetY = viewport.Top + Padding.Top + AutoScrollPosition.Y; - - return new RectangleF(new PointF(scaled.Left + offsetX, scaled.Top + offsetY), scaled.Size); - } - - /// - /// Returns the source rectangle scaled according to the current zoom level and repositioned to include the current image offset - /// - /// The X co-ordinate of the source rectangle. - /// The Y co-ordinate of the source rectangle. - /// The width of the rectangle. - /// The height of the rectangle. - /// A which has been resized and repositioned to match the current zoom level and image offset - public Rectangle GetOffsetRectangle(int x, int y, int width, int height) - { - return GetOffsetRectangle(new Rectangle(x, y, width, height)); - } - - /// - /// Returns the source rectangle scaled according to the current zoom level and repositioned to include the current image offset - /// - /// The X co-ordinate of the source rectangle. - /// The Y co-ordinate of the source rectangle. - /// The width of the rectangle. - /// The height of the rectangle. - /// A which has been resized and repositioned to match the current zoom level and image offset - public RectangleF GetOffsetRectangle(float x, float y, float width, float height) - { - return GetOffsetRectangle(new RectangleF(x, y, width, height)); - } - - /// - /// Returns the source scaled according to the current zoom level and repositioned to include the current image offset - /// - /// The source to offset. - /// A which has been resized and repositioned to match the current zoom level and image offset - public virtual Rectangle GetOffsetRectangle(Rectangle source) - { - Rectangle viewport; - Rectangle scaled; - int offsetX; - int offsetY; - - viewport = GetImageViewPort(); - scaled = GetScaledRectangle(source); - offsetX = viewport.Left + Padding.Left + AutoScrollPosition.X; - offsetY = viewport.Top + Padding.Top + AutoScrollPosition.Y; - - return new Rectangle(new Point(scaled.Left + offsetX, scaled.Top + offsetY), scaled.Size); - } - - /// - /// Returns the source scaled according to the current zoom level - /// - /// The X co-ordinate of the point to scale. - /// The Y co-ordinate of the point to scale. - /// A which has been scaled to match the current zoom level - public Point GetScaledPoint(int x, int y) - { - return GetScaledPoint(new Point(x, y)); - } - - /// - /// Returns the source scaled according to the current zoom level - /// - /// The X co-ordinate of the point to scale. - /// The Y co-ordinate of the point to scale. - /// A which has been scaled to match the current zoom level - public PointF GetScaledPoint(float x, float y) - { - return GetScaledPoint(new PointF(x, y)); - } - - /// - /// Returns the source scaled according to the current zoom level - /// - /// The source to scale. - /// A which has been scaled to match the current zoom level - public virtual Point GetScaledPoint(Point source) - { - return new Point((int)(source.X * ZoomFactor), (int)(source.Y * ZoomFactor)); - } - - /// - /// Returns the source scaled according to the current zoom level - /// - /// The source to scale. - /// A which has been scaled to match the current zoom level - public virtual PointF GetScaledPoint(PointF source) - { - return new PointF((float)(source.X * ZoomFactor), (float)(source.Y * ZoomFactor)); - } - - /// - /// Returns the source rectangle scaled according to the current zoom level - /// - /// The X co-ordinate of the source rectangle. - /// The Y co-ordinate of the source rectangle. - /// The width of the rectangle. - /// The height of the rectangle. - /// A which has been scaled to match the current zoom level - public Rectangle GetScaledRectangle(int x, int y, int width, int height) - { - return GetScaledRectangle(new Rectangle(x, y, width, height)); - } - - /// - /// Returns the source rectangle scaled according to the current zoom level - /// - /// The X co-ordinate of the source rectangle. - /// The Y co-ordinate of the source rectangle. - /// The width of the rectangle. - /// The height of the rectangle. - /// A which has been scaled to match the current zoom level - public RectangleF GetScaledRectangle(float x, float y, float width, float height) - { - return GetScaledRectangle(new RectangleF(x, y, width, height)); - } - - /// - /// Returns the source rectangle scaled according to the current zoom level - /// - /// The location of the source rectangle. - /// The size of the source rectangle. - /// A which has been scaled to match the current zoom level - public Rectangle GetScaledRectangle(Point location, Size size) - { - return GetScaledRectangle(new Rectangle(location, size)); - } - - /// - /// Returns the source rectangle scaled according to the current zoom level - /// - /// The location of the source rectangle. - /// The size of the source rectangle. - /// A which has been scaled to match the current zoom level - public RectangleF GetScaledRectangle(PointF location, SizeF size) - { - return GetScaledRectangle(new RectangleF(location, size)); - } - - /// - /// Returns the source scaled according to the current zoom level - /// - /// The source to scale. - /// A which has been scaled to match the current zoom level - public virtual Rectangle GetScaledRectangle(Rectangle source) - { - return new Rectangle((int)(source.Left * ZoomFactor), (int)(source.Top * ZoomFactor), (int)(source.Width * ZoomFactor), (int)(source.Height * ZoomFactor)); - } - - /// - /// Returns the source scaled according to the current zoom level - /// - /// The source to scale. - /// A which has been scaled to match the current zoom level - public virtual RectangleF GetScaledRectangle(RectangleF source) - { - return new RectangleF((float)(source.Left * ZoomFactor), (float)(source.Top * ZoomFactor), (float)(source.Width * ZoomFactor), (float)(source.Height * ZoomFactor)); - } - - /// - /// Returns the source size scaled according to the current zoom level - /// - /// The width of the size to scale. - /// The height of the size to scale. - /// A which has been resized to match the current zoom level - public SizeF GetScaledSize(float width, float height) - { - return GetScaledSize(new SizeF(width, height)); - } - - /// - /// Returns the source size scaled according to the current zoom level - /// - /// The width of the size to scale. - /// The height of the size to scale. - /// A which has been resized to match the current zoom level - public Size GetScaledSize(int width, int height) - { - return GetScaledSize(new Size(width, height)); - } - - /// - /// Returns the source scaled according to the current zoom level - /// - /// The source to scale. - /// A which has been resized to match the current zoom level - public virtual SizeF GetScaledSize(SizeF source) - { - return new SizeF((float)(source.Width * ZoomFactor), (float)(source.Height * ZoomFactor)); - } - - /// - /// Returns the source scaled according to the current zoom level - /// - /// The source to scale. - /// A which has been resized to match the current zoom level - public virtual Size GetScaledSize(Size source) - { - return new Size((int)(source.Width * ZoomFactor), (int)(source.Height * ZoomFactor)); - } - - /// - /// Creates an image based on the current selection region - /// - /// An image containing the selection contents if a selection if present, otherwise null - /// The caller is responsible for disposing of the returned image - public Image GetSelectedImage() - { - Image result; - - result = null; - - if (!SelectionRegion.IsEmpty) - { - Rectangle rect; - - rect = FitRectangle(new Rectangle((int)SelectionRegion.X, (int)SelectionRegion.Y, (int)SelectionRegion.Width, (int)SelectionRegion.Height)); - - if (rect.Width > 0 && rect.Height > 0) - { - result = new Bitmap(rect.Width, rect.Height); - - using (Graphics g = Graphics.FromImage(result)) - { - g.DrawImage(Image, new Rectangle(Point.Empty, rect.Size), rect, GraphicsUnit.Pixel); - } - } - } - - return result; - } - - /// - /// Gets the source image region. - /// - /// - public virtual RectangleF GetSourceImageRegion() - { - RectangleF region; - - if (!ViewSize.IsEmpty) - { - if (SizeMode != ImageBoxSizeMode.Stretch) - { - float sourceLeft; - float sourceTop; - float sourceWidth; - float sourceHeight; - Rectangle viewPort; - - viewPort = GetImageViewPort(); - sourceLeft = (float)(-AutoScrollPosition.X / ZoomFactor); - sourceTop = (float)(-AutoScrollPosition.Y / ZoomFactor); - sourceWidth = (float)(viewPort.Width / ZoomFactor); - sourceHeight = (float)(viewPort.Height / ZoomFactor); - - region = new RectangleF(sourceLeft, sourceTop, sourceWidth, sourceHeight); - } - else - { - region = new RectangleF(PointF.Empty, ViewSize); - } - } - else - { - region = RectangleF.Empty; - } - - return region; - } - - /// - /// Determines whether the specified point is located within the image view port - /// - /// The point. - /// - /// true if the specified point is located within the image view port; otherwise, false. - /// - public virtual bool IsPointInImage(Point point) - { - return GetImageViewPort().Contains(point); - } - - /// - /// Determines whether the specified point is located within the image view port - /// - /// The X co-ordinate of the point to check. - /// The Y co-ordinate of the point to check. - /// - /// true if the specified point is located within the image view port; otherwise, false. - /// - public bool IsPointInImage(int x, int y) - { - return IsPointInImage(new Point(x, y)); - } - - /// - /// Determines whether the specified point is located within the image view port - /// - /// The X co-ordinate of the point to check. - /// The Y co-ordinate of the point to check. - /// - /// true if the specified point is located within the image view port; otherwise, false. - /// - public bool IsPointInImage(float x, float y) - { - return IsPointInImage(new Point((int)x, (int)y)); - } - - /// - /// Converts the given client size point to represent a coordinate on the source image. - /// - /// The source point. - /// Point.Empty if the point could not be matched to the source image, otherwise the new translated point - public Point PointToImage(Point point) - { - return PointToImage(point, false); - } - - /// - /// Converts the given client size point to represent a coordinate on the source image. - /// - /// The X co-ordinate of the point to convert. - /// The Y co-ordinate of the point to convert. - /// Point.Empty if the point could not be matched to the source image, otherwise the new translated point - public Point PointToImage(float x, float y) - { - return PointToImage(x, y, false); - } - - /// - /// Converts the given client size point to represent a coordinate on the source image. - /// - /// The X co-ordinate of the point to convert. - /// The Y co-ordinate of the point to convert. - /// - /// if set to true and the point is outside the bounds of the source image, it will be mapped to the nearest edge. - /// - /// Point.Empty if the point could not be matched to the source image, otherwise the new translated point - public Point PointToImage(float x, float y, bool fitToBounds) - { - return PointToImage(new Point((int)x, (int)y), fitToBounds); - } - - /// - /// Converts the given client size point to represent a coordinate on the source image. - /// - /// The X co-ordinate of the point to convert. - /// The Y co-ordinate of the point to convert. - /// Point.Empty if the point could not be matched to the source image, otherwise the new translated point - public Point PointToImage(int x, int y) - { - return PointToImage(x, y, false); - } - - /// - /// Converts the given client size point to represent a coordinate on the source image. - /// - /// The X co-ordinate of the point to convert. - /// The Y co-ordinate of the point to convert. - /// - /// if set to true and the point is outside the bounds of the source image, it will be mapped to the nearest edge. - /// - /// Point.Empty if the point could not be matched to the source image, otherwise the new translated point - public Point PointToImage(int x, int y, bool fitToBounds) - { - return PointToImage(new Point(x, y), fitToBounds); - } - - /// - /// Converts the given client size point to represent a coordinate on the source image. - /// - /// The source point. - /// - /// if set to true and the point is outside the bounds of the source image, it will be mapped to the nearest edge. - /// - /// Point.Empty if the point could not be matched to the source image, otherwise the new translated point - public virtual Point PointToImage(Point point, bool fitToBounds) - { - Rectangle viewport; - int x; - int y; - - viewport = GetImageViewPort(); - - if (!fitToBounds || viewport.Contains(point)) - { - if (AutoScrollPosition != Point.Empty) - { - point = new Point(point.X - AutoScrollPosition.X, point.Y - AutoScrollPosition.Y); - } - - x = (int)((point.X - viewport.X) / ZoomFactor); - y = (int)((point.Y - viewport.Y) / ZoomFactor); - - if (fitToBounds) - { - Size viewSize; - - viewSize = ViewSize; - - if (x < 0) - { - x = 0; - } - else if (x > viewSize.Width) - { - x = viewSize.Width; - } - - if (y < 0) - { - y = 0; - } - else if (y > viewSize.Height) - { - y = viewSize.Height; - } - } - } - else - { - x = 0; // Return Point.Empty if we couldn't match - y = 0; - } - - return new Point(x, y); - } - - /// - /// Scrolls the control to the given point in the image, offset at the specified display point - /// - /// The X co-ordinate of the point to scroll to. - /// The Y co-ordinate of the point to scroll to. - /// The X co-ordinate relative to the x parameter. - /// The Y co-ordinate relative to the y parameter. - public void ScrollTo(int x, int y, int relativeX, int relativeY) - { - ScrollTo(new Point(x, y), new Point(relativeX, relativeY)); - } - - /// - /// Scrolls the control to the given point in the image, offset at the specified display point - /// - /// The X co-ordinate of the point to scroll to. - /// The Y co-ordinate of the point to scroll to. - /// The X co-ordinate relative to the x parameter. - /// The Y co-ordinate relative to the y parameter. - public void ScrollTo(float x, float y, float relativeX, float relativeY) - { - ScrollTo(new Point((int)x, (int)y), new Point((int)relativeX, (int)relativeY)); - } - - /// - /// Scrolls the control to the given point in the image, offset at the specified display point - /// - /// The point of the image to attempt to scroll to. - /// The relative display point to offset scrolling by. - public virtual void ScrollTo(Point imageLocation, Point relativeDisplayPoint) - { - int x; - int y; - - x = Scale(imageLocation.X) - relativeDisplayPoint.X; - y = Scale(imageLocation.Y) - relativeDisplayPoint.Y; - - AutoScrollPosition = new Point(x, y); - } - - /// - /// Creates a selection region which encompasses the entire image - /// - /// Thrown if no image is currently set - public virtual void SelectAll() - { - SelectionRegion = new RectangleF(PointF.Empty, ViewSize); - } - - /// - /// Clears any existing selection region - /// - public virtual void SelectNone() - { - SelectionRegion = RectangleF.Empty; - } - - /// - /// Zooms into the image - /// - public virtual void ZoomIn() - { - ZoomIn(true); - } - - /// - /// Zooms into the image - /// - /// true if the current scrolling position should be preserved relative to the new zoom level, false to reset. - public virtual void ZoomIn(bool preservePosition) - { - PerformZoomIn(ImageBoxActionSources.Unknown, preservePosition); - } - - /// - /// Zooms out of the image - /// - public virtual void ZoomOut() - { - ZoomOut(true); - } - - /// - /// Zooms out of the image - /// - /// true if the current scrolling position should be preserved relative to the new zoom level, false to reset. - public virtual void ZoomOut(bool preservePosition) - { - PerformZoomOut(ImageBoxActionSources.Unknown, preservePosition); - } - /// - /// Zooms to the maximum size for displaying the entire image within the bounds of the control. - /// - public virtual void ZoomToFit() - { - if (!ViewSize.IsEmpty) - { - Rectangle innerRectangle; - double zoom; - double aspectRatio; - - innerRectangle = GetInsideViewPort(true); - - if (ViewSize.Width > ViewSize.Height) - { - aspectRatio = (double)innerRectangle.Width / ViewSize.Width; - zoom = aspectRatio * 100.0; - - if (innerRectangle.Height < ((ViewSize.Height * zoom) / 100.0)) - { - aspectRatio = (double)innerRectangle.Height / ViewSize.Height; - zoom = aspectRatio * 100.0; - } - } - else - { - aspectRatio = (double)innerRectangle.Height / ViewSize.Height; - zoom = aspectRatio * 100.0; - - if (innerRectangle.Width < ((ViewSize.Width * zoom) / 100.0)) - { - aspectRatio = (double)innerRectangle.Width / ViewSize.Width; - zoom = aspectRatio * 100.0; - } - } - - Zoom = zoom; - } - } - - /// - /// [IG_CHANGE] Zooms to the maximum size for displaying the entire image within the bounds of the control. If image size is smaller than viewer size, keep its original size. - /// - public virtual void ZoomAuto() - { - if (!ViewSize.IsEmpty) - { - Rectangle innerRectangle; - double zoom; - double aspectRatio; - - innerRectangle = GetInsideViewPort(true); - - if (ViewSize.Width <= innerRectangle.Width && ViewSize.Height <= innerRectangle.Height) - { - zoom = 100.0; - } - else - { - if (ViewSize.Width > ViewSize.Height) - { - aspectRatio = (double)innerRectangle.Width / ViewSize.Width; - zoom = aspectRatio * 100.0; - - if (innerRectangle.Height < ((ViewSize.Height * zoom) / 100.0)) - { - aspectRatio = (double)innerRectangle.Height / ViewSize.Height; - zoom = aspectRatio * 100.0; - } - } - else - { - aspectRatio = (double)innerRectangle.Height / ViewSize.Height; - zoom = aspectRatio * 100.0; - - if (innerRectangle.Width < ((ViewSize.Width * zoom) / 100.0)) - { - aspectRatio = (double)innerRectangle.Width / ViewSize.Width; - zoom = aspectRatio * 100.0; - } - } - } - - Zoom = zoom; - } - } - - - - /// - /// Adjusts the view port to fit the given region - /// - /// The X co-ordinate of the selection region. - /// The Y co-ordinate of the selection region. - /// The width of the selection region. - /// The height of the selection region. - public void ZoomToRegion(float x, float y, float width, float height) - { - ZoomToRegion(new RectangleF(x, y, width, height)); - } - - /// - /// Adjusts the view port to fit the given region - /// - /// The X co-ordinate of the selection region. - /// The Y co-ordinate of the selection region. - /// The width of the selection region. - /// The height of the selection region. - public void ZoomToRegion(int x, int y, int width, int height) - { - ZoomToRegion(new RectangleF(x, y, width, height)); - } - - /// - /// Adjusts the view port to fit the given region - /// - /// The rectangle to fit the view port to. - public virtual void ZoomToRegion(RectangleF rectangle) - { - double ratioX; - double ratioY; - double zoomFactor; - int cx; - int cy; - - ratioX = ClientSize.Width / rectangle.Width; - ratioY = ClientSize.Height / rectangle.Height; - zoomFactor = Math.Min(ratioX, ratioY); - cx = (int)(rectangle.X + (rectangle.Width / 2)); - cy = (int)(rectangle.Y + (rectangle.Height / 2)); - - Zoom = zoomFactor * 100; - CenterAt(new Point(cx, cy)); - } - - /// - /// Clamps the specified value within the given range. - /// - /// The value to clamp. - /// The minimum value allowed. - /// The maximum value allowed. - /// - private int Clamp(int value, int min, int max) - { - if (value < min) - { - value = min; - } - else if (value > max) - { - value = max; - } - - return value; - } - - #endregion - - #region Protected Members - - /// - /// Adjusts the layout. - /// - protected virtual void AdjustLayout() - { - if (AllowPainting) - { - if (AutoSize) - { - AdjustSize(); - } - else if (SizeMode != ImageBoxSizeMode.Normal) - { - ZoomToFit(); - } - - AdjustViewPort(); - Invalidate(); - } - } - - private HScrollBar _hScrollBar; - private VScrollBar _vScrollBar; - - /// - /// Adjusts the scroll. - /// - /// The x. - /// The y. - protected virtual void AdjustScroll(int x, int y) - { - Point scrollPosition; - - scrollPosition = new Point(HorizontalScroll.Value + x, VerticalScroll.Value + y); - - UpdateScrollPosition(scrollPosition); - } - - /// - /// Adjusts the size. - /// - protected virtual void AdjustSize() - { - if (AutoSize && Dock == DockStyle.None) - { - base.Size = base.PreferredSize; - } - } - - /// - /// Adjusts the view port. - /// - protected virtual void AdjustViewPort() - { - Size viewSize; - Size clientSize; - int cw; - int ch; - bool vScroll; - bool hScroll; - - viewSize = ViewSize; - clientSize = ClientSize; - - if (!viewSize.IsEmpty) - { - Size size; - - size = GetInsideViewPort(true).Size; - - hScroll = ScaledImageWidth > size.Width; - vScroll = ScaledImageHeight > size.Height; - } - else - { - hScroll = false; - vScroll = false; - } - - HScroll = hScroll; - VScroll = vScroll; - - UpdateScrollbars(); - - cw = vScroll ? clientSize.Width - _vScrollBar.Width : clientSize.Width; - ch = hScroll ? clientSize.Height - _hScrollBar.Height : clientSize.Height; - - _hScrollBar.Width = cw; - _hScrollBar.Top = clientSize.Height - _hScrollBar.Height; - - _vScrollBar.Height = ch; - _vScrollBar.Left = clientSize.Width - _vScrollBar.Width; - } - - /// - /// Creates the grid tile image. - /// - /// Size of the cell. - /// The first color. - /// Color of the second. - /// - protected virtual Bitmap CreateGridTileImage(int cellSize, Color firstColor, Color secondColor) - { - float scale; - - // rescale the cell size - switch (GridScale) - { - case ImageBoxGridScale.Medium: - scale = 1.5F; - break; - - case ImageBoxGridScale.Large: - scale = 2; - break; - - case ImageBoxGridScale.Tiny: - scale = 0.5F; - break; - - default: - scale = 1; - break; - } - - cellSize = (int)(cellSize * scale); - - return CreateCheckerBoxTile(cellSize, firstColor, secondColor); - } - - /// - /// Draws the background of the control. - /// - /// The instance containing the event data. - protected virtual void DrawBackground(PaintEventArgs e) - { - Rectangle innerRectangle; - - innerRectangle = GetInsideViewPort(); - - using (SolidBrush brush = new SolidBrush(BackColor)) - { - e.Graphics.FillRectangle(brush, innerRectangle); - } - - if (_texture != null && GridDisplayMode != ImageBoxGridDisplayMode.None) - { - switch (GridDisplayMode) - { - case ImageBoxGridDisplayMode.Image: - Rectangle fillRectangle; - - fillRectangle = GetImageViewPort(); - e.Graphics.FillRectangle(_texture, fillRectangle); - break; - - case ImageBoxGridDisplayMode.Client: - e.Graphics.FillRectangle(_texture, innerRectangle); - break; - } - } - } - - /// - /// Draws a drop shadow. - /// - /// The graphics. - /// The view port. - protected virtual void DrawDropShadow(Graphics g, Rectangle viewPort) - { - Rectangle rightEdge; - Rectangle bottomEdge; - - rightEdge = new Rectangle(viewPort.Right + 1, viewPort.Top + DropShadowSize, DropShadowSize, viewPort.Height); - bottomEdge = new Rectangle(viewPort.Left + DropShadowSize, viewPort.Bottom + 1, viewPort.Width + 1, DropShadowSize); - - using (Brush brush = new SolidBrush(ImageBorderColor)) - { - g.FillRectangles(brush, new[] - { - rightEdge, bottomEdge - }); - } - } - - /// - /// Draws a glow shadow. - /// - /// The graphics. - /// The view port. - protected virtual void DrawGlowShadow(Graphics g, Rectangle viewPort) - { - // Glow code adapted from http://www.codeproject.com/Articles/372743/gGlowBox-Create-a-glow-effect-around-a-focused-con - - g.SetClip(viewPort, CombineMode.Exclude); // make sure the inside glow doesn't appear - - using (GraphicsPath path = new GraphicsPath()) - { - int glowSize; - int feather; - - path.AddRectangle(viewPort); - glowSize = DropShadowSize * 3; - feather = 50; - - for (int i = 1; i <= glowSize; i += 2) - { - int alpha; - - alpha = feather - ((feather / glowSize) * i); - - using (Pen pen = new Pen(Color.FromArgb(alpha, ImageBorderColor), i) - { - LineJoin = LineJoin.Round - }) - { - g.DrawPath(pen, path); - } - } - } - } - - /// - /// Draws the image. - /// - /// The g. - protected virtual void DrawImage(Graphics g) - { - InterpolationMode currentInterpolationMode; - PixelOffsetMode currentPixelOffsetMode; - - currentInterpolationMode = g.InterpolationMode; - currentPixelOffsetMode = g.PixelOffsetMode; - - g.InterpolationMode = GetInterpolationMode(); - - // disable pixel offsets. Thanks to Rotem for the info. - // http://stackoverflow.com/questions/14070311/why-is-graphics-drawimage-cropping-part-of-my-image/14070372#14070372 - g.PixelOffsetMode = PixelOffsetMode.HighQuality; - - try - { - // Animation. Thanks to teamalpha5441 for the contribution - if (IsAnimating && !DesignMode) - { - Animator.UpdateFrames(Image); - } - - g.DrawImage(Image, GetImageViewPort(), GetSourceImageRegion(), GraphicsUnit.Pixel); - } - catch (ArgumentException) - { - // ignore errors that occur due to the image being disposed - } - catch (OutOfMemoryException) - { - // also ignore errors that occur due to running out of memory - } - catch (ExternalException) - { - // stop the animation and reset to the first frame. - IsAnimating = false; - Animator.StopAnimate(Image, OnFrameChangedHandler); - } - catch (InvalidOperationException) - { - // #issue #373: a race condition caused this exception: deleting the image from underneath us could - // cause a collision in HighResolutionGifAnimator. I've not been able to repro; hopefully this is - // the correct response. - - // stop the animation and reset to the first frame. - IsAnimating = false; - Animator.StopAnimate(Image, OnFrameChangedHandler); - } - - g.PixelOffsetMode = currentPixelOffsetMode; - g.InterpolationMode = currentInterpolationMode; - } - - /// - /// Draws a border around the image. - /// - /// The graphics. - protected virtual void DrawImageBorder(Graphics graphics) - { - if (ImageBorderStyle != ImageBoxBorderStyle.None) - { - Rectangle viewPort; - - graphics.SetClip(GetInsideViewPort()); // make sure the image border doesn't overwrite the control border - - viewPort = GetImageViewPort(); - viewPort = new Rectangle(viewPort.Left - 1, viewPort.Top - 1, viewPort.Width + 1, viewPort.Height + 1); - - using (Pen borderPen = new Pen(ImageBorderColor)) - { - graphics.DrawRectangle(borderPen, viewPort); - } - - switch (ImageBorderStyle) - { - case ImageBoxBorderStyle.FixedSingleDropShadow: - DrawDropShadow(graphics, viewPort); - break; - case ImageBoxBorderStyle.FixedSingleGlowShadow: - DrawGlowShadow(graphics, viewPort); - break; - } - - graphics.ResetClip(); - } - } - - /// - /// Draws the specified text within the specified bounds using the specified device context. - /// - /// The device context in which to draw the text. - /// The text to draw. - /// The that represents the bounds of the text. - protected void DrawLabel(Graphics graphics, string text, Rectangle bounds) - { - DrawLabel(graphics, text, Font, ForeColor, TextBackColor, TextAlign, bounds); - } - - /// - /// Draws the specified text within the specified bounds using the specified device context and font. - /// - /// The device context in which to draw the text. - /// The text to draw. - /// The to apply to the drawn text. - /// The that represents the bounds of the text. - protected void DrawLabel(Graphics graphics, string text, Font font, Rectangle bounds) - { - DrawLabel(graphics, text, font, ForeColor, TextBackColor, TextAlign, bounds); - } - - /// - /// Draws the specified text within the specified bounds using the specified device context, font, and color. - /// - /// The device context in which to draw the text. - /// The text to draw. - /// The to apply to the drawn text. - /// The to apply to the text. - /// The that represents the bounds of the text. - protected void DrawLabel(Graphics graphics, string text, Font font, Color foreColor, Rectangle bounds) - { - DrawLabel(graphics, text, font, foreColor, TextBackColor, TextAlign, bounds); - } - - /// - /// Draws the specified text within the specified bounds using the specified device context, font, color, and back color. - /// - /// The device context in which to draw the text. - /// The text to draw. - /// The to apply to the drawn text. - /// The to apply to the text. - /// The to apply to the area represented by bounds. - /// The that represents the bounds of the text. - protected void DrawLabel(Graphics graphics, string text, Font font, Color foreColor, Color backColor, Rectangle bounds) - { - DrawLabel(graphics, text, font, foreColor, backColor, TextAlign, bounds); - } - - /// - /// Draws the specified text within the specified bounds using the specified device context, font, color, back color, and formatting instructions. - /// - /// The device context in which to draw the text. - /// The text to draw. - /// The to apply to the drawn text. - /// The to apply to the text. - /// The to apply to the area represented by bounds. - /// The to apply to the text. - /// The that represents the bounds of the text. - protected void DrawLabel(Graphics graphics, string text, Font font, Color foreColor, Color backColor, ContentAlignment textAlign, Rectangle bounds) - { - DrawLabel(graphics, text, font, foreColor, backColor, textAlign, bounds, ScaleText); - } - - /// - /// Draws the specified text within the specified bounds using the specified device context, font, color, back color, and formatting instructions. - /// - /// The device context in which to draw the text. - /// The text to draw. - /// The to apply to the drawn text. - /// The to apply to the text. - /// The to apply to the area represented by bounds. - /// The to apply to the text. - /// The that represents the bounds of the text. - /// If set to true the font size is scaled according to the current zoom level. - protected virtual void DrawLabel(Graphics graphics, string text, Font font, Color foreColor, Color backColor, ContentAlignment textAlign, Rectangle bounds, bool scaleText) - { - DrawLabel(graphics, text, font, foreColor, backColor, textAlign, bounds, scaleText, Padding.Empty); - } - - /// - /// Draws the specified text within the specified bounds using the specified device context, font, color, back color, and formatting instructions. - /// - /// The device context in which to draw the text. - /// The text to draw. - /// The to apply to the drawn text. - /// The to apply to the text. - /// The to apply to the area represented by bounds. - /// The to apply to the text. - /// The that represents the bounds of the text. - /// If set to true the font size is scaled according to the current zoom level. - /// Padding to apply around the text - protected virtual void DrawLabel(Graphics graphics, string text, Font font, Color foreColor, Color backColor, ContentAlignment textAlign, Rectangle bounds, bool scaleText, Padding padding) - { - TextFormatFlags flags; - - if (scaleText) - { - font = new Font(font.FontFamily, (float)(font.Size * ZoomFactor), font.Style); - } - - flags = TextFormatFlags.NoPrefix | TextFormatFlags.WordEllipsis | TextFormatFlags.WordBreak | TextFormatFlags.NoPadding; - - switch (textAlign) - { - case ContentAlignment.TopLeft: - case ContentAlignment.MiddleLeft: - case ContentAlignment.BottomLeft: - flags |= TextFormatFlags.Left; - break; - case ContentAlignment.TopRight: - case ContentAlignment.MiddleRight: - case ContentAlignment.BottomRight: - flags |= TextFormatFlags.Right; - break; - default: - flags |= TextFormatFlags.HorizontalCenter; - break; - } - - switch (textAlign) - { - case ContentAlignment.TopCenter: - case ContentAlignment.TopLeft: - case ContentAlignment.TopRight: - flags |= TextFormatFlags.Top; - break; - case ContentAlignment.BottomCenter: - case ContentAlignment.BottomLeft: - case ContentAlignment.BottomRight: - flags |= TextFormatFlags.Bottom; - break; - default: - flags |= TextFormatFlags.VerticalCenter; - break; - } - - if (padding.Horizontal != 0 || padding.Vertical != 0) - { - Size size; - int x; - int y; - int width; - int height; - - size = TextRenderer.MeasureText(graphics, text, font, bounds.Size, flags); - width = size.Width; - height = size.Height; - - switch (textAlign) - { - case ContentAlignment.TopLeft: - x = bounds.Left + padding.Left; - y = bounds.Top + padding.Top; - break; - case ContentAlignment.TopCenter: - x = bounds.Left + padding.Left + (((bounds.Width - width) / 2) - padding.Right); - y = bounds.Top + padding.Top; - break; - case ContentAlignment.TopRight: - x = bounds.Right - (padding.Right + width); - y = bounds.Top + padding.Top; - break; - case ContentAlignment.MiddleLeft: - x = bounds.Left + padding.Left; - y = bounds.Top + padding.Top + ((bounds.Height - height) / 2); - break; - case ContentAlignment.MiddleCenter: - x = bounds.Left + padding.Left + (((bounds.Width - width) / 2) - padding.Right); - y = bounds.Top + padding.Top + ((bounds.Height - height) / 2); - break; - case ContentAlignment.MiddleRight: - x = bounds.Right - (padding.Right + width); - y = bounds.Top + padding.Top + ((bounds.Height - height) / 2); - break; - case ContentAlignment.BottomLeft: - x = bounds.Left + padding.Left; - y = bounds.Bottom - (padding.Bottom + height); - break; - case ContentAlignment.BottomCenter: - x = bounds.Left + padding.Left + (((bounds.Width - width) / 2) - padding.Right); - y = bounds.Bottom - (padding.Bottom + height); - break; - case ContentAlignment.BottomRight: - x = bounds.Right - (padding.Right + width); - y = bounds.Bottom - (padding.Bottom + height); - break; - default: - throw new ArgumentOutOfRangeException("textAlign"); - } - - if (backColor != Color.Empty && backColor.A > 0) - { - using (Brush brush = new SolidBrush(backColor)) - { - graphics.FillRectangle(brush, x - padding.Left, y - padding.Top, width + padding.Horizontal, height + padding.Vertical); - } - } - - bounds = new Rectangle(x, y, width, height); - - //bounds = new Rectangle(bounds.Left + padding.Left, bounds.Top + padding.Top, bounds.Width - padding.Horizontal, bounds.Height - padding.Vertical); - } - - TextRenderer.DrawText(graphics, text, font, bounds, foreColor, backColor, flags); - - if (scaleText) - { - font.Dispose(); - } - } - - /// - /// Draws a pixel grid. - /// - /// The graphics to draw the grid to. - protected virtual void DrawPixelGrid(Graphics g) - { - float pixelSize; - - pixelSize = (float)ZoomFactor; - - if (pixelSize > PixelGridThreshold) - { - Rectangle viewport; - float offsetX; - float offsetY; - - viewport = GetImageViewPort(); - offsetX = Math.Abs(AutoScrollPosition.X) % pixelSize; - offsetY = Math.Abs(AutoScrollPosition.Y) % pixelSize; - - using (Pen pen = new Pen(PixelGridColor) - { - DashStyle = DashStyle.Dot - }) - { - for (float x = viewport.Left + pixelSize - offsetX; x < viewport.Right; x += pixelSize) - { - g.DrawLine(pen, x, viewport.Top, x, viewport.Bottom); - } - - for (float y = viewport.Top + pixelSize - offsetY; y < viewport.Bottom; y += pixelSize) - { - g.DrawLine(pen, viewport.Left, y, viewport.Right, y); - } - - g.DrawRectangle(pen, viewport); - } - } - } - - /// - /// Draws the selection region. - /// - /// - /// The instance containing the event data. - /// - protected virtual void DrawSelection(PaintEventArgs e) - { - RectangleF rect; - - e.Graphics.SetClip(GetInsideViewPort(true)); - - rect = GetOffsetRectangle(SelectionRegion); - - using (Brush brush = new SolidBrush(Color.FromArgb(128, SelectionColor))) - { - e.Graphics.FillRectangle(brush, rect); - } - - using (Pen pen = new Pen(SelectionColor)) - { - e.Graphics.DrawRectangle(pen, rect.X, rect.Y, rect.Width, rect.Height); - } - - e.Graphics.ResetClip(); - } - - /// - /// Draws the text. - /// - /// The instance containing the event data. - protected virtual void DrawText(PaintEventArgs e) - { - Rectangle bounds; - - bounds = TextDisplayMode == ImageBoxGridDisplayMode.Client ? GetInsideViewPort() : GetImageViewPort(); - - DrawLabel(e.Graphics, Text, Font, ForeColor, TextBackColor, TextAlign, bounds, ScaleText, TextPadding); - } - - /// - /// Completes an ongoing selection or drag operation. - /// - protected virtual void EndDrag() - { - IsSelecting = false; - OnSelected(EventArgs.Empty); - } - - /// - /// Gets an offset based on the current image border style. - /// - /// - protected virtual int GetImageBorderOffset() - { - int offset; - - switch (ImageBorderStyle) - { - case ImageBoxBorderStyle.FixedSingle: - offset = 1; - break; - - case ImageBoxBorderStyle.FixedSingleDropShadow: - offset = (DropShadowSize + 1); - break; - default: - offset = 0; - break; - } - - return offset; - } - - /// - /// Determines a suitable interpolation mode based in the value of the and properties. - /// - /// A for rendering the image. - protected virtual InterpolationMode GetInterpolationMode() - { - InterpolationMode mode; - - mode = InterpolationMode; - - if (mode == InterpolationMode.Default) - { - // ReSharper disable once ConvertIfStatementToConditionalTernaryExpression - if (Zoom < 100) - { - // TODO: Check to see if we should cherry pick other modes depending on how much the image is actually zoomed - mode = InterpolationMode.HighQualityBicubic; - } - else - { - mode = InterpolationMode.NearestNeighbor; - } - } - - return mode; - } - - /// - /// Raises the event. - /// - /// - /// The instance containing the event data. - /// - protected virtual void OnAllowClickZoomChanged(EventArgs e) - { - EventHandler handler; - - handler = AllowClickZoomChanged; - - if (handler != null) - { - handler(this, e); - } - } - - /// - /// Raises the event. - /// - /// - /// The instance containing the event data. - /// - protected virtual void OnAllowDoubleClickChanged(EventArgs e) - { - EventHandler handler; - - SetStyle(ControlStyles.StandardDoubleClick, AllowDoubleClick); - - handler = AllowDoubleClickChanged; - - if (handler != null) - { - handler(this, e); - } - } - - /// - /// Raises the event. - /// - /// - /// The instance containing the event data. - /// - protected virtual void OnAllowZoomChanged(EventArgs e) - { - EventHandler handler; - - handler = AllowZoomChanged; - - if (handler != null) - { - handler(this, e); - } - } - - /// - /// Raises the event. - /// - /// - /// The instance containing the event data. - /// - protected virtual void OnAutoCenterChanged(EventArgs e) - { - EventHandler handler; - - Invalidate(); - - handler = AutoCenterChanged; - - if (handler != null) - { - handler(this, e); - } - } - - /// - /// Raises the event. - /// - /// - /// The instance containing the event data. - /// - protected virtual void OnAutoPanChanged(EventArgs e) - { - EventHandler handler; - - handler = AutoPanChanged; - - if (handler != null) - { - handler(this, e); - } - } - - /// - /// Raises the event. - /// - /// - /// The instance containing the event data. - /// - protected virtual void OnDropShadowSizeChanged(EventArgs e) - { - Invalidate(); - - EventHandler handler; - - handler = DropShadowSizeChanged; - - if (handler != null) - { - handler(this, e); - } - } - - /// - /// Raises the event. - /// - /// - /// The instance containing the event data. - /// - protected virtual void OnGridCellSizeChanged(EventArgs e) - { - EventHandler handler; - - InitializeGridTile(); - - handler = GridCellSizeChanged; - - if (handler != null) - { - handler(this, e); - } - } - - /// - /// Raises the event. - /// - /// - /// The instance containing the event data. - /// - protected virtual void OnGridColorAlternateChanged(EventArgs e) - { - EventHandler handler; - - InitializeGridTile(); - - handler = GridColorAlternateChanged; - - if (handler != null) - { - handler(this, e); - } - } - - /// - /// Raises the event. - /// - /// - /// The instance containing the event data. - /// - protected virtual void OnGridColorChanged(EventArgs e) - { - EventHandler handler; - - InitializeGridTile(); - - handler = GridColorChanged; - - if (handler != null) - { - handler(this, e); - } - } - - /// - /// Raises the event. - /// - /// - /// The instance containing the event data. - /// - protected virtual void OnGridDisplayModeChanged(EventArgs e) - { - EventHandler handler; - - InitializeGridTile(); - Invalidate(); - - handler = GridDisplayModeChanged; - - if (handler != null) - { - handler(this, e); - } - } - - /// - /// Raises the event. - /// - /// - /// The instance containing the event data. - /// - protected virtual void OnGridScaleChanged(EventArgs e) - { - EventHandler handler; - - InitializeGridTile(); - - handler = GridScaleChanged; - - if (handler != null) - { - handler(this, e); - } - } - - /// - /// Raises the event. - /// - /// - /// The instance containing the event data. - /// - protected virtual void OnImageBorderColorChanged(EventArgs e) - { - EventHandler handler; - - Invalidate(); - - handler = ImageBorderColorChanged; - - if (handler != null) - { - handler(this, e); - } - } - - /// - /// Raises the event. - /// - /// - /// The instance containing the event data. - /// - protected virtual void OnImageBorderStyleChanged(EventArgs e) - { - EventHandler handler; - - Invalidate(); - - handler = ImageBorderStyleChanged; - - if (handler != null) - { - handler(this, e); - } - } - - - /// - /// Raises the event. - /// - /// - /// The instance containing the event data. - /// - protected virtual void OnImageChanged(EventArgs e) - { - EventHandler handler; - - DefineViewSize(); - IsAnimating = false; - - if (Image != null) - { - //try - //{ - // this.IsAnimating = Animator.CanAnimate(this.Image); - // if (this.IsAnimating) - // { - // Animator.Animate(this.Image, this.OnFrameChangedHandler); - // } - //} - //catch (ArgumentException) - //{ - // // probably a disposed image, ignore - //} - - StartAnimating(); - } - - AdjustLayout(); - - handler = ImageChanged; - - if (handler != null) - { - handler(this, e); - } - } - - /// - /// Defines the view sized based on the current image and if the control is operating in virtual mode or not - /// - private void DefineViewSize() - { - _viewSize = VirtualMode ? VirtualSize : GetImageSize(); - - UpdateScrollbars(); - } - - /// - /// Returns if horizontal scrolling is enabled - /// - [Browsable(false)] - [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] - public bool HScroll { get; protected set; } - - /// - /// Returns if the vertical scrolling is enabled - /// - [Browsable(false)] - [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] - public bool VScroll { get; protected set; } - - /// - /// Updates all properties of the embedded scroll bar controls. - /// - private void UpdateScrollbars() - { - Size viewSize; - - viewSize = GetInsideViewPort(true).Size; - - if (viewSize.Width > 0 && viewSize.Height > 0) - { - ImageBoxScrollProperties horizontal; - ImageBoxScrollProperties vertical; - Point autoScrollPosition; - bool hScroll; - bool vScroll; - bool enabled; - - autoScrollPosition = AutoScrollPosition; - hScroll = HScroll; - vScroll = VScroll; - enabled = Enabled; - - horizontal = HorizontalScroll; - horizontal.Maximum = ScaledImageWidth; - horizontal.LargeChange = viewSize.Width; - horizontal.SmallChange = 10; - horizontal.Value = -autoScrollPosition.X; - horizontal.Visible = ShouldShowScrollbar(HorizontalScrollBarStyle, hScroll); - horizontal.Enabled = enabled && hScroll; - - vertical = VerticalScroll; - vertical.Maximum = ScaledImageHeight; - vertical.LargeChange = viewSize.Height; - vertical.SmallChange = 10; - vertical.Value = -autoScrollPosition.Y; - vertical.Visible = ShouldShowScrollbar(VerticalScrollBarStyle, vScroll); - vertical.Enabled = enabled && vScroll; - } - } - - /// - /// Determines if a scroll bar should be displayed. - /// - /// The user defined style of the scroll bar. - /// The visibility state for automatic styles. - /// true if the scroll bar should be displayed, otherwise false. - private bool ShouldShowScrollbar(ImageBoxScrollBarStyle style, bool visible) - { - bool result; - - switch (style) - { - case ImageBoxScrollBarStyle.Auto: - result = visible; - break; - case ImageBoxScrollBarStyle.Show: - result = true; - break; - case ImageBoxScrollBarStyle.Hide: - result = false; - break; - default: - throw new ArgumentOutOfRangeException("style", style, null); - } - - return result; - } - - /// - /// Raises the event. - /// - /// - /// The instance containing the event data. - /// - protected virtual void OnInterpolationModeChanged(EventArgs e) - { - EventHandler handler; - - Invalidate(); - - handler = InterpolationModeChanged; - - if (handler != null) - { - handler(this, e); - } - } - - /// - /// Raises the event. - /// - /// - /// The instance containing the event data. - /// - protected virtual void OnInvertMouseChanged(EventArgs e) - { - EventHandler handler; - - handler = InvertMouseChanged; - - if (handler != null) - { - handler(this, e); - } - } - - /// - /// Raises the event. - /// - /// - /// The instance containing the event data. - /// - protected virtual void OnLimitSelectionToImageChanged(EventArgs e) - { - EventHandler handler; - - handler = LimitSelectionToImageChanged; - - if (handler != null) - { - handler(this, e); - } - } - - /// - /// Raises the event. - /// - /// - /// The instance containing the event data. - /// - protected virtual void OnPanEnd(EventArgs e) - { - EventHandler handler; - - handler = PanEnd; - - if (handler != null) - { - handler(this, e); - } - } - - /// - /// Raises the event. - /// - /// - /// The instance containing the event data. - /// - protected virtual void OnPanStart(CancelEventArgs e) - { - EventHandler handler; - - handler = PanStart; - - if (handler != null) - { - handler(this, e); - } - } - - /// - /// Raises the event. - /// - /// - /// The instance containing the event data. - /// - protected virtual void OnPixelGridColorChanged(EventArgs e) - { - EventHandler handler; - - Invalidate(); - - handler = PixelGridColorChanged; - - if (handler != null) - { - handler(this, e); - } - } - - /// - /// Raises the event. - /// - /// The instance containing the event data. - protected virtual void OnPixelGridThresholdChanged(EventArgs e) - { - EventHandler handler; - - handler = PixelGridThresholdChanged; - - if (handler != null) - { - handler(this, e); - } - } - - /// - /// Raises the event. - /// - /// The instance containing the event data. - protected virtual void OnScaleTextChanged(EventArgs e) - { - EventHandler handler; - - Invalidate(); - - handler = ScaleTextChanged; - - if (handler != null) - { - handler(this, e); - } - } - - /// - /// Raises the event. - /// - /// - /// The instance containing the event data. - /// - protected virtual void OnSelected(EventArgs e) - { - EventHandler handler; - - switch (SelectionMode) - { - case ImageBoxSelectionMode.Zoom: - if (SelectionRegion.Width > SelectionDeadZone && SelectionRegion.Height > SelectionDeadZone) - { - ZoomToRegion(SelectionRegion); - SelectNone(); - } - break; - } - - handler = Selected; - - if (handler != null) - { - handler(this, e); - } - } - - /// - /// Raises the event. - /// - /// - /// The instance containing the event data. - /// - protected virtual void OnSelecting(ImageBoxCancelEventArgs e) - { - EventHandler handler; - - handler = Selecting; - - if (handler != null) - { - handler(this, e); - } - } - - /// - /// Raises the event. - /// - /// - /// The instance containing the event data. - /// - protected virtual void OnSelectionColorChanged(EventArgs e) - { - EventHandler handler; - - handler = SelectionColorChanged; - - if (handler != null) - { - handler(this, e); - } - } - - /// - /// Raises the event. - /// - /// - /// The instance containing the event data. - /// - protected virtual void OnSelectionModeChanged(EventArgs e) - { - EventHandler handler; - - handler = SelectionModeChanged; - - if (handler != null) - { - handler(this, e); - } - } - - /// - /// Raises the event. - /// - /// - /// The instance containing the event data. - /// - protected virtual void OnSelectionRegionChanged(EventArgs e) - { - EventHandler handler; - - Invalidate(); - - handler = SelectionRegionChanged; - - if (handler != null) - { - handler(this, e); - } - } - - /// - /// Raises the event. - /// - /// - /// The instance containing the event data. - /// - protected virtual void OnShortcutsEnabledChanged(EventArgs e) - { - EventHandler handler; - - handler = ShortcutsEnabledChanged; - - if (handler != null) - { - handler(this, e); - } - } - - /// - /// Raises the event. - /// - /// - /// The instance containing the event data. - /// - protected virtual void OnShowPixelGridChanged(EventArgs e) - { - EventHandler handler; - - Invalidate(); - - handler = ShowPixelGridChanged; - - if (handler != null) - { - handler(this, e); - } - } - - /// - /// Raises the event. - /// - /// The instance containing the event data. - protected virtual void OnSizeModeChanged(EventArgs e) - { - EventHandler handler; - - AdjustLayout(); - - handler = SizeModeChanged; - - if (handler != null) - { - handler(this, e); - } - } - - /// - /// Raises the event. - /// - /// - /// The instance containing the event data. - /// - protected virtual void OnSizeToFitChanged(EventArgs e) - { - EventHandler handler; - - AdjustLayout(); - - handler = SizeToFitChanged; - - if (handler != null) - { - handler(this, e); - } - } - - /// - /// Raises the event. - /// - /// The instance containing the event data. - protected virtual void OnTextAlignChanged(EventArgs e) - { - EventHandler handler; - - Invalidate(); - - handler = TextAlignChanged; - - if (handler != null) - { - handler(this, e); - } - } - - /// - /// Raises the event. - /// - /// The instance containing the event data. - protected virtual void OnTextBackColorChanged(EventArgs e) - { - EventHandler handler; - - Invalidate(); - - handler = TextBackColorChanged; - - if (handler != null) - { - handler(this, e); - } - } - - /// - /// Raises the event. - /// - /// The instance containing the event data. - protected virtual void OnTextDisplayModeChanged(EventArgs e) - { - EventHandler handler; - - Invalidate(); - - handler = TextDisplayModeChanged; - - if (handler != null) - { - handler(this, e); - } - } - - /// - /// Raises the event. - /// - /// The instance containing the event data. - protected virtual void OnTextPaddingChanged(EventArgs e) - { - EventHandler handler; - - handler = TextPaddingChanged; - - Invalidate(); - - if (handler != null) - { - handler(this, e); - } - } - - /// - /// Raises the event. - /// - /// - /// The instance containing the event data. - /// - protected virtual void OnVirtualDraw(PaintEventArgs e) - { - PaintEventHandler handler; - - handler = VirtualDraw; - - if (handler != null) - { - handler(this, e); - } - } - - /// - /// Raises the event. - /// - /// - /// The instance containing the event data. - /// - protected virtual void OnVirtualModeChanged(EventArgs e) - { - EventHandler handler; - - DefineViewSize(); - AdjustLayout(); - - handler = VirtualModeChanged; - - if (handler != null) - { - handler(this, e); - } - } - - /// - /// Raises the event. - /// - /// - /// The instance containing the event data. - /// - protected virtual void OnVirtualSizeChanged(EventArgs e) - { - EventHandler handler; - - AdjustLayout(); - - handler = VirtualSizeChanged; - - if (handler != null) - { - handler(this, e); - } - } - - /// - /// Raises the event. - /// - /// - /// The instance containing the event data. - /// - protected virtual void OnZoomChanged(EventArgs e) - { - EventHandler handler; - - AdjustLayout(); - - handler = ZoomChanged; - - if (handler != null) - { - handler(this, e); - } - } - - /// - /// Raises the event. - /// - /// - /// The instance containing the event data. - /// - protected virtual void OnZoomLevelsChanged(EventArgs e) - { - EventHandler handler; - - handler = ZoomLevelsChanged; - - if (handler != null) - { - handler(this, e); - } - } - - /// - /// Raises the event. - /// - /// The instance containing the event data. - protected virtual void OnZoomed(ImageBoxZoomEventArgs e) - { - EventHandler handler; - - handler = Zoomed; - - if (handler != null) - { - handler(this, e); - } - } - - /// - /// Processes shortcut keys for zooming and selection - /// - /// - /// The instance containing the event data. - /// - protected virtual void ProcessImageShortcuts(KeyEventArgs e) - { - Point currentPixel; - Point relativePoint; - - relativePoint = CenterPoint; - currentPixel = PointToImage(relativePoint); - var currentZoom = Zoom; - - switch (e.KeyCode) - { - //case Keys.Home: - // if (this.AllowZoom) - // { - // this.PerformActualSize(ImageBoxActionSources.User); - // } - // break; - - //case Keys.PageDown: - case Keys.Oemplus: - PerformZoomIn(ImageBoxActionSources.User, true); - break; - - //case Keys.PageUp: - case Keys.OemMinus: - PerformZoomOut(ImageBoxActionSources.User, true); - break; - } - - if (Zoom != currentZoom) - { - ScrollTo(currentPixel, relativePoint); - } - } - - /// - /// Processes zooming with the mouse. Attempts to keep the pre-zoom image pixel under the mouse after the zoom has completed. - /// - /// - /// if set to true zoom in, otherwise zoom out. - /// - /// The cursor position. - /// [IG_CHANGE] 20190816 Make this public so we can zoom in/out from a position via our event handlers - public virtual void ProcessMouseZoom(bool isZoomIn, Point cursorPosition) - { - PerformZoom(isZoomIn ? ImageBoxZoomActions.ZoomIn : ImageBoxZoomActions.ZoomOut, ImageBoxActionSources.User, true, cursorPosition); - } - - /// - /// Performs mouse based panning - /// - /// - /// The instance containing the event data. - /// - protected virtual void ProcessPanning(MouseEventArgs e) - { - if (AutoPan && !ViewSize.IsEmpty && SelectionMode == ImageBoxSelectionMode.None) - { - Size clientSize; - - clientSize = GetInsideViewPort(true).Size; - - if (!IsPanning && (ScaledImageWidth > clientSize.Width || ScaledImageHeight > clientSize.Height)) - { - _startMousePosition = e.Location; - IsPanning = true; - } - - if (IsPanning) - { - int x; - int y; - Point position; - - if (!InvertMouse) - { - x = -_startScrollPosition.X + (_startMousePosition.X - e.Location.X); - y = -_startScrollPosition.Y + (_startMousePosition.Y - e.Location.Y); - } - else - { - x = -(_startScrollPosition.X + (_startMousePosition.X - e.Location.X)); - y = -(_startScrollPosition.Y + (_startMousePosition.Y - e.Location.Y)); - } - - position = new Point(x, y); - - UpdateScrollPosition(position); - } - } - } - - /// - /// Processes shortcut keys for scrolling - /// - /// - /// The instance containing the event data. - /// - protected virtual void ProcessScrollingShortcuts(KeyEventArgs e) - { - switch (e.KeyCode) - { - case Keys.Left: - AdjustScroll(-(e.Modifiers == Keys.None ? HorizontalScroll.SmallChange : HorizontalScroll.LargeChange), 0); - break; - - case Keys.Right: - AdjustScroll(e.Modifiers == Keys.None ? HorizontalScroll.SmallChange : HorizontalScroll.LargeChange, 0); - break; - - case Keys.Up: - AdjustScroll(0, -(e.Modifiers == Keys.None ? VerticalScroll.SmallChange : VerticalScroll.LargeChange)); - break; - - case Keys.Down: - AdjustScroll(0, e.Modifiers == Keys.None ? VerticalScroll.SmallChange : VerticalScroll.LargeChange); - break; - } - } - - /// - /// Gets the characteristics associated with the horizontal scroll bar. - /// - [Browsable(false)] - [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] - public ImageBoxScrollProperties HorizontalScroll { get; private set; } - - /// - /// Gets the characteristics associated with the vertical scroll bar. - /// - [Browsable(false)] - [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] - public ImageBoxScrollProperties VerticalScroll { get; private set; } - - /// - /// Performs mouse based region selection - /// - /// - /// The instance containing the event data. - /// - protected virtual void ProcessSelection(MouseEventArgs e) - { - if (SelectionMode != ImageBoxSelectionMode.None && e.Button == MouseButtons.Left && !WasDragCancelled) - { - if (!IsSelecting) - { - StartDrag(e); - } - - if (IsSelecting) - { - float x; - float y; - float w; - float h; - Point imageOffset; - RectangleF selection; - - imageOffset = GetImageViewPort().Location; - - if (e.X < _startMousePosition.X) - { - x = e.X; - w = _startMousePosition.X - e.X; - } - else - { - x = _startMousePosition.X; - w = e.X - _startMousePosition.X; - } - - if (e.Y < _startMousePosition.Y) - { - y = e.Y; - h = _startMousePosition.Y - e.Y; - } - else - { - y = _startMousePosition.Y; - h = e.Y - _startMousePosition.Y; - } - - x = x - imageOffset.X - AutoScrollPosition.X; - y = y - imageOffset.Y - AutoScrollPosition.Y; - - x = x / (float)ZoomFactor; - y = y / (float)ZoomFactor; - w = w / (float)ZoomFactor; - h = h / (float)ZoomFactor; - - selection = new RectangleF(x, y, w, h); - if (LimitSelectionToImage) - { - selection = FitRectangle(selection); - } - - SelectionRegion = selection; - } - } - } - - /// - /// Resets the property whilsts retaining the original . - /// - protected void RestoreSizeMode() - { - if (SizeMode != ImageBoxSizeMode.Normal) - { - var previousZoom = Zoom; - SizeMode = ImageBoxSizeMode.Normal; - Zoom = previousZoom; // Stop the zoom getting reset to 100% before calculating the new zoom - } - } - - /// - /// Initializes a selection or drag operation. - /// - /// The instance containing the event data. - protected virtual void StartDrag(MouseEventArgs e) - { - ImageBoxCancelEventArgs args; - - args = new ImageBoxCancelEventArgs(e.Location); - - OnSelecting(args); - - WasDragCancelled = args.Cancel; - IsSelecting = !args.Cancel; - if (IsSelecting) - { - SelectNone(); - - _startMousePosition = e.Location; - } - } - - /// - /// Updates the scroll position. - /// - /// The position. - protected virtual void UpdateScrollPosition(Point position) - { - AutoScrollPosition = position; - - Invalidate(); - - OnScroll(new ScrollEventArgs(ScrollEventType.EndScroll, 0)); - } - - #endregion - - #region Private Members - - /// - /// Gets the size of the image. - /// - /// If an error occurs, for example due to the image being disposed, an empty size is returned - /// Size. - private Size GetImageSize() - { - Size result; - - // HACK: This whole thing stinks. Hey MS, how about an IsDisposed property for images? - - if (Image != null) - { - try - { - result = Image.Size; - } - catch - { - result = Size.Empty; - } - } - else - { - result = Size.Empty; - } - - return result; - } - - /// - /// Initializes the grid tile. - /// - private void InitializeGridTile() - { - if (_texture != null) - { - _texture.Dispose(); - } - - if (_gridTile != null) - { - _gridTile.Dispose(); - } - - if (GridDisplayMode != ImageBoxGridDisplayMode.None && GridCellSize != 0) - { - if (GridScale != ImageBoxGridScale.None) - { - _gridTile = CreateGridTileImage(GridCellSize, GridColor, GridColorAlternate); - _texture = new TextureBrush(_gridTile); - } - else - { - _texture = new SolidBrush(GridColor); - } - } - - Invalidate(); - } - - /// - /// Called when the animation frame changes. - /// - /// The source of the event. - /// The instance containing the event data. - private void OnFrameChangedHandler(object sender, EventArgs eventArgs) - { - Invalidate(); - } - - /// - /// Resets the zoom to 100%. - /// - /// The source that initiated the action. - private void PerformActualSize(ImageBoxActionSources source) - { - SizeMode = ImageBoxSizeMode.Normal; - SetZoom(100, ImageBoxZoomActions.ActualSize | (Zoom < 100 ? ImageBoxZoomActions.ZoomIn : ImageBoxZoomActions.ZoomOut), source); - } - - /// - /// Zooms into the image - /// - /// The source that initiated the action. - /// true if the current scrolling position should be preserved relative to the new zoom level, false to reset. - private void PerformZoomIn(ImageBoxActionSources source, bool preservePosition) - { - PerformZoom(ImageBoxZoomActions.ZoomIn, source, preservePosition); - } - - /// - /// Performs a zoom action. - /// - /// The action to perform. - /// The source that initiated the action. - /// true if the current scrolling position should be preserved relative to the new zoom level, false to reset. - private void PerformZoom(ImageBoxZoomActions action, ImageBoxActionSources source, bool preservePosition) - { - PerformZoom(action, source, preservePosition, CenterPoint); - } - - /// - /// Performs a zoom action. - /// - /// The action to perform. - /// The source that initiated the action. - /// true if the current scrolling position should be preserved relative to the new zoom level, false to reset. - /// A describing the current center of the control. - private void PerformZoom(ImageBoxZoomActions action, ImageBoxActionSources source, bool preservePosition, Point relativePoint) - { - var currentPixel = PointToImage(relativePoint); - var currentZoom = Zoom; - var newZoom = GetZoomLevel(action); - - RestoreSizeMode(); - SetZoom(newZoom, action, source); - - if (preservePosition && Zoom != currentZoom) - { - ScrollTo(currentPixel, relativePoint); - } - } - - /// - /// Returns an appropriate zoom level based on the specified action, relative to the current zoom level. - /// - /// The action to determine the zoom level. - /// Thrown if an unsupported action is specified. - private int GetZoomLevel(ImageBoxZoomActions action) - { - double result; - - switch (action) - { - case ImageBoxZoomActions.None: - result = Zoom; - break; - case ImageBoxZoomActions.ZoomIn: - result = ZoomLevels.NextZoom((int)Zoom); - break; - case ImageBoxZoomActions.ZoomOut: - result = ZoomLevels.PreviousZoom((int)Zoom); - break; - case ImageBoxZoomActions.ActualSize: - result = 100; - break; - default: - throw new ArgumentOutOfRangeException("action"); - } - - return (int)result; - } - - /// - /// Zooms out of the image - /// - /// The source that initiated the action. - /// true if the current scrolling position should be preserved relative to the new zoom level, false to reset. - private void PerformZoomOut(ImageBoxActionSources source, bool preservePosition) - { - PerformZoom(ImageBoxZoomActions.ZoomOut, source, preservePosition); - } - - /// - /// Updates the current zoom. - /// - /// The new zoom value. - /// The zoom actions that caused the value to be updated. - /// The source of the zoom operation. - private void SetZoom(double value, ImageBoxZoomActions actions, ImageBoxActionSources source) - { - var previousZoom = Zoom; - - if (value < MinZoom) - { - value = MinZoom; - } - else if (value > MaxZoom) - { - value = MaxZoom; - } - - if (_zoom != value) - { - _zoom = value; - - OnZoomChanged(EventArgs.Empty); - - OnZoomed(new ImageBoxZoomEventArgs(actions, source, previousZoom, Zoom)); - } - } - - #endregion - - private bool _allowUnfocusedMouseWheel; - - /// - /// Gets or sets a value indicating whether the control can respond to mouse wheel events regardless of if the control has focus or not. - /// - [Category("Behavior"), DefaultValue(false)] - public virtual bool AllowUnfocusedMouseWheel - { - get { return _allowUnfocusedMouseWheel; } - set - { - if (AllowUnfocusedMouseWheel != value) - { - _allowUnfocusedMouseWheel = value; - - OnAllowUnfocusedMouseWheelChanged(EventArgs.Empty); - } - } - } - - /// - /// Occurs when the AllowUnfocusedMouseWheel property value changes - /// - [Category("Property Changed")] - public event EventHandler AllowUnfocusedMouseWheelChanged; - - /// - /// Raises the event. - /// - /// The instance containing the event data. - protected virtual void OnAllowUnfocusedMouseWheelChanged(EventArgs e) - { - EventHandler handler; - - if (AllowUnfocusedMouseWheel) - { - // TODO: Not doing any reference counting so there's - // currently no way of disabling the message filter - // after the first time it has been enabled - ImageBoxMouseWheelMessageFilter.Active = true; - } - - handler = AllowUnfocusedMouseWheelChanged; - - if (handler != null) - handler(this, e); - } - - private Point _autoScrollPosition; - - private bool _updatingPosition; - - /// - /// Gets or sets the location of the auto-scroll position. - /// - [Browsable(false)] - [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] - [Category("Layout")] - public Point AutoScrollPosition - { - get { return _autoScrollPosition; } - set - { - if (!_updatingPosition) - { - try - { - int maxH; - int maxW; - - _updatingPosition = true; - - maxW = HScroll ? ScaledImageWidth - HorizontalScroll.LargeChange : 0; - maxH = VScroll ? ScaledImageHeight - VerticalScroll.LargeChange : 0; - - value = new Point(-Clamp(value.X, 0, maxW), -Clamp(value.Y, 0, maxH)); - - if (_autoScrollPosition != value) - { -// Debug.WriteLine(value); - - _autoScrollPosition = value; - - UpdateScrollbars(); - - Invalidate(); - } - } - finally - { - _updatingPosition = false; - } - } - } - } - - /// - /// Handles the Scroll event of the embedded horizontal and vertical scroll bar controls. - /// - /// The source of the event. - /// A that contains the event data. - private void ScrollBarScrollHandler(object sender, ScrollEventArgs e) - { - UpdateScrollPosition(new Point(_hScrollBar.Value, _vScrollBar.Value)); - } - - - /// - /// Occurs when the user or code scrolls through the client area. - /// - [Category("Action")] - public event ScrollEventHandler Scroll; - - /// - /// Raises the event. - /// - /// - /// The instance containing the event data. - /// - protected virtual void OnScroll(ScrollEventArgs e) - { - ScrollEventHandler handler; - - handler = Scroll; - - if (handler != null) - { - handler(this, e); - } - } - - private ImageBoxScrollBarStyle _horizontalScrollBarStyle; - - /// - /// Gets or sets the style of the horizontal scroll bar. - /// - [Category("Behavior"), DefaultValue(typeof(ImageBoxScrollBarStyle), "Auto")] - public virtual ImageBoxScrollBarStyle HorizontalScrollBarStyle - { - get { return _horizontalScrollBarStyle; } - set - { - if (HorizontalScrollBarStyle != value) - { - _horizontalScrollBarStyle = value; - - OnHorizontalScrollBarStyleChanged(EventArgs.Empty); - } - } - } - - /// - /// Occurs when the HorizontalScrollBarStyle property value changes - /// - [Category("Property Changed")] - public event EventHandler HorizontalScrollBarStyleChanged; - - /// - /// Raises the event. - /// - /// The instance containing the event data. - protected virtual void OnHorizontalScrollBarStyleChanged(EventArgs e) - { - EventHandler handler; - - AdjustViewPort(); - Invalidate(); - - handler = HorizontalScrollBarStyleChanged; - - if (handler != null) - { - handler(this, e); - } - } - - private ImageBoxScrollBarStyle _verticalScrollBarStyle; - - /// - /// Gets or sets the style of the vertical scroll bar. - /// - [Category("Behavior"), DefaultValue(typeof(ImageBoxScrollBarStyle), "Auto")] - public virtual ImageBoxScrollBarStyle VerticalScrollBarStyle - { - get { return _verticalScrollBarStyle; } - set - { - if (VerticalScrollBarStyle != value) - { - _verticalScrollBarStyle = value; - - OnVerticalScrollBarStyleChanged(EventArgs.Empty); - } - } - } - - /// - /// Occurs when the VerticalScrollBarStyle property value changes - /// - [Category("Property Changed")] - public event EventHandler VerticalScrollBarStyleChanged; - - /// - /// Raises the event. - /// - /// The instance containing the event data. - protected virtual void OnVerticalScrollBarStyleChanged(EventArgs e) - { - EventHandler handler; - - AdjustViewPort(); - Invalidate(); - - handler = VerticalScrollBarStyleChanged; - - if (handler != null) - { - handler(this, e); - } - } - - - } -} \ No newline at end of file diff --git a/Source/Components/ImageGlass.ImageBox/ImageBoxActionSources.cs b/Source/Components/ImageGlass.ImageBox/ImageBoxActionSources.cs deleted file mode 100644 index 6e08dbdb3..000000000 --- a/Source/Components/ImageGlass.ImageBox/ImageBoxActionSources.cs +++ /dev/null @@ -1,30 +0,0 @@ -using System; - -namespace ImageGlass -{ - // Cyotek ImageBox - // Copyright (c) 2010-2015 Cyotek Ltd. - // http://cyotek.com - // http://cyotek.com/blog/tag/imagebox - - // Licensed under the MIT License. See license.txt for the full text. - - // If you use this control in your applications, attribution, donations or contributions are welcome. - - /// - /// Specifies the source of an action being performed. - /// - [Flags] - public enum ImageBoxActionSources - { - /// - /// Unknown source. - /// - Unknown = 0, - - /// - /// A user initialized the action. - /// - User = 1 - } -} diff --git a/Source/Components/ImageGlass.ImageBox/ImageBoxBorderStyle.cs b/Source/Components/ImageGlass.ImageBox/ImageBoxBorderStyle.cs deleted file mode 100644 index 686174d4d..000000000 --- a/Source/Components/ImageGlass.ImageBox/ImageBoxBorderStyle.cs +++ /dev/null @@ -1,37 +0,0 @@ -namespace ImageGlass -{ - // Cyotek ImageBox - // Copyright (c) 2010-2015 Cyotek Ltd. - // http://cyotek.com - // http://cyotek.com/blog/tag/imagebox - - // Licensed under the MIT License. See license.txt for the full text. - - // If you use this control in your applications, attribution, donations or contributions are welcome. - - /// - /// Specifies the border styles of an image - /// - public enum ImageBoxBorderStyle - { - /// - /// No border. - /// - None, - - /// - /// A fixed, single-line border. - /// - FixedSingle, - - /// - /// A fixed, single-line border with a solid drop shadow. - /// - FixedSingleDropShadow, - - /// - /// A fixed, single-line border with a soft outer glow. - /// - FixedSingleGlowShadow - } -} diff --git a/Source/Components/ImageGlass.ImageBox/ImageBoxCancelEventArgs.cs b/Source/Components/ImageGlass.ImageBox/ImageBoxCancelEventArgs.cs deleted file mode 100644 index d019c1b7f..000000000 --- a/Source/Components/ImageGlass.ImageBox/ImageBoxCancelEventArgs.cs +++ /dev/null @@ -1,54 +0,0 @@ -using System.ComponentModel; -using System.Drawing; - -namespace ImageGlass -{ - // Cyotek ImageBox - // Copyright (c) 2010-2015 Cyotek Ltd. - // http://cyotek.com - // http://cyotek.com/blog/tag/imagebox - - // Licensed under the MIT License. See license.txt for the full text. - - // If you use this control in your applications, attribution, donations or contributions are welcome. - - /// - /// Provides data for a cancelable event. - /// - public class ImageBoxCancelEventArgs : CancelEventArgs - { - #region Public Constructors - - /// - /// Initializes a new instance of the class. - /// - /// The location of the action being performed. - public ImageBoxCancelEventArgs(Point location) - : this() - { - Location = location; - } - - #endregion - - #region Protected Constructors - - /// - /// Initializes a new instance of the class. - /// - protected ImageBoxCancelEventArgs() - { } - - #endregion - - #region Public Properties - - /// - /// Gets or sets the location of the action being performed. - /// - /// The location of the action being performed. - public Point Location { get; protected set; } - - #endregion - } -} diff --git a/Source/Components/ImageGlass.ImageBox/ImageBoxGridDisplayMode.cs b/Source/Components/ImageGlass.ImageBox/ImageBoxGridDisplayMode.cs deleted file mode 100644 index 0f7ea429d..000000000 --- a/Source/Components/ImageGlass.ImageBox/ImageBoxGridDisplayMode.cs +++ /dev/null @@ -1,32 +0,0 @@ -namespace ImageGlass -{ - // Cyotek ImageBox - // Copyright (c) 2010-2015 Cyotek Ltd. - // http://cyotek.com - // http://cyotek.com/blog/tag/imagebox - - // Licensed under the MIT License. See license.txt for the full text. - - // If you use this control in your applications, attribution, donations or contributions are welcome. - - /// - /// Specifies the display styles for the background texture grid - /// - public enum ImageBoxGridDisplayMode - { - /// - /// No background. - /// - None, - - /// - /// Background is displayed in the control's client area. - /// - Client, - - /// - /// Background is displayed only in the image region. - /// - Image - } -} diff --git a/Source/Components/ImageGlass.ImageBox/ImageBoxGridScale.cs b/Source/Components/ImageGlass.ImageBox/ImageBoxGridScale.cs deleted file mode 100644 index f3f7779eb..000000000 --- a/Source/Components/ImageGlass.ImageBox/ImageBoxGridScale.cs +++ /dev/null @@ -1,42 +0,0 @@ -namespace ImageGlass -{ - // Cyotek ImageBox - // Copyright (c) 2010-2015 Cyotek Ltd. - // http://cyotek.com - // http://cyotek.com/blog/tag/imagebox - - // Licensed under the MIT License. See license.txt for the full text. - - // If you use this control in your applications, attribution, donations or contributions are welcome. - - /// - /// Specifies the size of the background texture grid. - /// - public enum ImageBoxGridScale - { - /// - /// Displays a solid color - /// - None, - - /// - /// Half of the default size. - /// - Tiny, - - /// - /// Default size. - /// - Small, - - /// - /// 50% increase of default size. - /// - Medium, - - /// - /// 100% increase of default size. - /// - Large - } -} diff --git a/Source/Components/ImageGlass.ImageBox/ImageBoxMouseWheelMessageFilter.cs b/Source/Components/ImageGlass.ImageBox/ImageBoxMouseWheelMessageFilter.cs deleted file mode 100644 index 27e318ab4..000000000 --- a/Source/Components/ImageGlass.ImageBox/ImageBoxMouseWheelMessageFilter.cs +++ /dev/null @@ -1,142 +0,0 @@ -using System; -using System.Drawing; -using System.Windows.Forms; - -// Cyotek ImageBox -// Copyright (c) 2010-2015 Cyotek Ltd. -// http://cyotek.com -// http://cyotek.com/blog/tag/imagebox - -// Licensed under the MIT License. See license.txt for the full text. - -// If you use this control in your applications, attribution, donations or contributions are welcome. - -// This code is derived from http://stackoverflow.com/a/13292894/148962 and http://stackoverflow.com/a/11034674/148962 - -namespace ImageGlass -{ - /// - /// A message filter for WM_MOUSEWHEEL and WM_MOUSEHWHEEL. This class cannot be inherited. - /// - /// - internal sealed class ImageBoxMouseWheelMessageFilter : IMessageFilter - { - #region Member Declarations - - private static ImageBoxMouseWheelMessageFilter _instance; - - private static bool _active; - - #endregion - - #region Constructors - - /// - /// Constructor that prevents a default instance of this class from being created. - /// - private ImageBoxMouseWheelMessageFilter() - { } - - #endregion - - #region Static Properties - - /// - /// Gets or sets a value indicating whether the filter is active - /// - /// - /// true if the message filter is active, false if not. - /// - public static bool Active - { - get { return _active; } - set - { - if (_active != value) - { - _active = value; - - if (_active) - { - if (_instance == null) - { - _instance = new ImageBoxMouseWheelMessageFilter(); - } - Application.AddMessageFilter(_instance); - } - else - { - if (_instance != null) - { - Application.RemoveMessageFilter(_instance); - } - } - } - } - } - - #endregion - - #region IMessageFilter Interface - - /// - /// Filters out a message before it is dispatched. - /// - /// [in,out] The message to be dispatched. You cannot modify this message. - /// - /// true to filter the message and stop it from being dispatched; false to allow the message to - /// continue to the next filter or control. - /// - /// - bool IMessageFilter.PreFilterMessage(ref Message m) - { - bool result; - - switch (m.Msg) - { - case NativeMethods.WM_MOUSEWHEEL: // 0x020A - case NativeMethods.WM_MOUSEHWHEEL: // 0x020E - IntPtr hControlUnderMouse; - - hControlUnderMouse = NativeMethods.WindowFromPoint(new Point((int)m.LParam)); - if (hControlUnderMouse == m.HWnd) - { - // already headed for the right control - result = false; - } - else - { - ImageBox control; - - control = Control.FromHandle(hControlUnderMouse) as ImageBox; - - if (control == null || !control.AllowUnfocusedMouseWheel) - { - // window under the mouse either isn't managed, isn't an imagebox, - // or it is an imagebox but the unfocused whell option is disabled. - // whatever the case, do not try and handle the message - result = false; - } - else - { - // redirect the message to the control under the mouse - NativeMethods.SendMessage(hControlUnderMouse, m.Msg, m.WParam, m.LParam); - - // eat the message (otherwise it's possible two controls will scroll - // at the same time, which looks awful... and is probably confusing!) - result = true; - } - } - break; - default: - // not a message we can process, don't try and block it - result = false; - break; - } - - return result; - } - - #endregion - } -} diff --git a/Source/Components/ImageGlass.ImageBox/ImageBoxNativeMethods.cs b/Source/Components/ImageGlass.ImageBox/ImageBoxNativeMethods.cs deleted file mode 100644 index 5b09f5cad..000000000 --- a/Source/Components/ImageGlass.ImageBox/ImageBoxNativeMethods.cs +++ /dev/null @@ -1,49 +0,0 @@ -using System; -using System.Drawing; -using System.Runtime.InteropServices; - -// ReSharper disable InconsistentNaming - -namespace ImageGlass -{ - // Cyotek ImageBox - // Copyright (c) 2010-2015 Cyotek Ltd. - // http://cyotek.com - // http://cyotek.com/blog/tag/imagebox - - // Licensed under the MIT License. See license.txt for the full text. - - // If you use this control in your applications, attribution, donations or contributions are welcome. - - internal class NativeMethods - { - #region Externals - - [DllImport("user32.dll", SetLastError = false)] - internal static extern IntPtr SendMessage(IntPtr hWnd, int msg, IntPtr wParam, IntPtr lParam); - - [DllImport("user32.dll")] - internal static extern IntPtr WindowFromPoint(Point point); - - #endregion - - #region Constants - - internal const int WM_MOUSEHWHEEL = 0x20e; - - internal const int WM_MOUSEWHEEL = 0x20a; - - internal const int WS_BORDER = 0x00800000; - - internal const int WS_EX_CLIENTEDGE = 0x200; - - #endregion - - #region Constructors - - private NativeMethods() - { } - - #endregion - } -} diff --git a/Source/Components/ImageGlass.ImageBox/ImageBoxScrollBarStyle.cs b/Source/Components/ImageGlass.ImageBox/ImageBoxScrollBarStyle.cs deleted file mode 100644 index 901fd295d..000000000 --- a/Source/Components/ImageGlass.ImageBox/ImageBoxScrollBarStyle.cs +++ /dev/null @@ -1,32 +0,0 @@ -namespace ImageGlass -{ - // Cyotek ImageBox - // Copyright (c) 2010-2015 Cyotek Ltd. - // http://cyotek.com - // http://cyotek.com/blog/tag/imagebox - - // Licensed under the MIT License. See license.txt for the full text. - - // If you use this control in your applications, attribution, donations or contributions are welcome. - - /// - /// Specifies the style of a scroll bar - /// - public enum ImageBoxScrollBarStyle - { - /// - /// The scroll bar is automatically displayed when needed. - /// - Auto, - - /// - /// The scroll bar is always shown - /// - Show, - - /// - /// The scroll bar is hidden - /// - Hide - } -} diff --git a/Source/Components/ImageGlass.ImageBox/ImageBoxScrollProperties.cs b/Source/Components/ImageGlass.ImageBox/ImageBoxScrollProperties.cs deleted file mode 100644 index fe7d52855..000000000 --- a/Source/Components/ImageGlass.ImageBox/ImageBoxScrollProperties.cs +++ /dev/null @@ -1,184 +0,0 @@ -using System.ComponentModel; -using System.Windows.Forms; - -namespace ImageGlass -{ - /// - /// Encapsulates properties related to scrolling. - /// - public sealed class ImageBoxScrollProperties - { - #region Constants - - private readonly ScrollBar _scrollBar; - - #endregion - - #region Fields - - private bool _enabled; - - private int _largeChange; - - private int _maximum; - - private int _minimum; - - private int _smallChange; - - private int _value; - - private bool _visible; - - #endregion - - #region Constructors - - internal ImageBoxScrollProperties(ScrollBar scrollBar) - { - _scrollBar = scrollBar; - } - - #endregion - - #region Properties - - /// - /// Gets or sets whether the scroll bar can be used on the container. - /// - /// true if the scroll bar can be used; otherwise, false. - [DefaultValue(true)] - public bool Enabled - { - get { return _enabled; } - internal set - { - if (_enabled != value) - { - _enabled = value; - _scrollBar.Enabled = value; - } - } - } - - /// - /// Gets or sets the distance to move a scroll bar in response to a large scroll command. - /// - /// An describing how far, in pixels, to move the scroll bar in response to a large change. - [DefaultValue(10)] - public int LargeChange - { - get { return _largeChange; } - internal set - { - if (_largeChange != value) - { - _largeChange = value; - _scrollBar.LargeChange = value; - } - } - } - - /// - /// Gets or sets the upper limit of the scrollable range. - /// - /// An representing the maximum range of the scroll bar. - [DefaultValue(100)] - public int Maximum - { - get { return _maximum; } - internal set - { - if (_maximum != value) - { - _maximum = value; - _scrollBar.Maximum = value; - } - } - } - - /// - /// Gets or sets the lower limit of the scrollable range. - /// - /// An representing the lower range of the scroll bar. - [DefaultValue(0)] - public int Minimum - { - get { return _minimum; } - internal set - { - if (_minimum != value) - { - _minimum = value; - _scrollBar.Minimum = value; - } - } - } - - /// - /// Gets or sets the distance to move a scroll bar in response to a small scroll command. - /// - /// An representing how far, in pixels, to move the scroll bar. - [DefaultValue(1)] - public int SmallChange - { - get { return _smallChange; } - internal set - { - if (_smallChange != value) - { - _smallChange = value; - _scrollBar.SmallChange = value; - } - } - } - - /// - /// Gets or sets a numeric value that represents the current position of the scroll bar box. - /// - /// An representing the position of the scroll bar box, in pixels. - [Bindable(true)] - [DefaultValue(0)] - public int Value - { - get { return _value; } - internal set - { - if (value < Minimum) - { - value = Minimum; - } - else if (value > Maximum) - { - value = Maximum; - } - - if (_value != value) - { - _value = value; - _scrollBar.Value = value; - } - } - } - - /// - /// Gets or sets whether the scroll bar can be seen by the user. - /// - /// true if it can be seen; otherwise, false. - [DefaultValue(false)] - public bool Visible - { - get { return _visible; } - internal set - { - if (_visible != value) - { - _visible = value; - _scrollBar.Visible = value; - } - } - } - - #endregion - } -} diff --git a/Source/Components/ImageGlass.ImageBox/ImageBoxSelectionMode.cs b/Source/Components/ImageGlass.ImageBox/ImageBoxSelectionMode.cs deleted file mode 100644 index 79ce37e2e..000000000 --- a/Source/Components/ImageGlass.ImageBox/ImageBoxSelectionMode.cs +++ /dev/null @@ -1,32 +0,0 @@ -namespace ImageGlass -{ - // Cyotek ImageBox - // Copyright (c) 2010-2015 Cyotek Ltd. - // http://cyotek.com - // http://cyotek.com/blog/tag/imagebox - - // Licensed under the MIT License. See license.txt for the full text. - - // If you use this control in your applications, attribution, donations or contributions are welcome. - - /// - /// Specifies the selection mode. - /// - public enum ImageBoxSelectionMode - { - /// - /// No selection. - /// - None, - - /// - /// Rectangle selection. - /// - Rectangle, - - /// - /// Zoom selection. - /// - Zoom - } -} diff --git a/Source/Components/ImageGlass.ImageBox/ImageBoxSizeMode.cs b/Source/Components/ImageGlass.ImageBox/ImageBoxSizeMode.cs deleted file mode 100644 index ceb90e0ce..000000000 --- a/Source/Components/ImageGlass.ImageBox/ImageBoxSizeMode.cs +++ /dev/null @@ -1,32 +0,0 @@ -namespace ImageGlass -{ - // Cyotek ImageBox - // Copyright (c) 2010-2015 Cyotek Ltd. - // http://cyotek.com - // http://cyotek.com/blog/tag/imagebox - - // Licensed under the MIT License. See license.txt for the full text. - - // If you use this control in your applications, attribution, donations or contributions are welcome. - - /// - /// Determines the sizing mode of an image hosted in an control. - /// - public enum ImageBoxSizeMode - { - /// - /// The image is disiplayed according to current zoom and scroll properties. - /// - Normal, - - /// - /// The image is stretched to fill the client area of the control. - /// - Stretch, - - /// - /// The image is stretched to fill as much of the client area of the control as possible, whilst retaining the same aspect ratio for the width and height. - /// - Fit - } -} diff --git a/Source/Components/ImageGlass.ImageBox/ImageBoxZoomActions.cs b/Source/Components/ImageGlass.ImageBox/ImageBoxZoomActions.cs deleted file mode 100644 index cdbf16e04..000000000 --- a/Source/Components/ImageGlass.ImageBox/ImageBoxZoomActions.cs +++ /dev/null @@ -1,40 +0,0 @@ -using System; - -namespace ImageGlass -{ - // Cyotek ImageBox - // Copyright (c) 2010-2015 Cyotek Ltd. - // http://cyotek.com - // http://cyotek.com/blog/tag/imagebox - - // Licensed under the MIT License. See license.txt for the full text. - - // If you use this control in your applications, attribution, donations or contributions are welcome. - - /// - /// Describes the zoom action occuring - /// - [Flags] - public enum ImageBoxZoomActions - { - /// - /// No action. - /// - None = 0, - - /// - /// The control is increasing the zoom. - /// - ZoomIn = 1, - - /// - /// The control is decreasing the zoom. - /// - ZoomOut = 2, - - /// - /// The control zoom was reset. - /// - ActualSize = 4 - } -} diff --git a/Source/Components/ImageGlass.ImageBox/ImageBoxZoomEventArgs.cs b/Source/Components/ImageGlass.ImageBox/ImageBoxZoomEventArgs.cs deleted file mode 100644 index 0cb418407..000000000 --- a/Source/Components/ImageGlass.ImageBox/ImageBoxZoomEventArgs.cs +++ /dev/null @@ -1,77 +0,0 @@ -using System; - -namespace ImageGlass -{ - // Cyotek ImageBox - // Copyright (c) 2010-2015 Cyotek Ltd. - // http://cyotek.com - // http://cyotek.com/blog/tag/imagebox - - // Licensed under the MIT License. See license.txt for the full text. - - // If you use this control in your applications, attribution, donations or contributions are welcome. - - /// - /// Contains event data for the event. - /// - public class ImageBoxZoomEventArgs : EventArgs - { - #region Public Constructors - - /// - /// Initializes a new instance of the class. - /// - /// The zoom operation being performed. - /// The source of the operation. - /// The old zoom level. - /// The new zoom level. - public ImageBoxZoomEventArgs(ImageBoxZoomActions actions, ImageBoxActionSources source, double oldZoom, double newZoom) - : this() - { - Actions = actions; - Source = source; - OldZoom = oldZoom; - NewZoom = newZoom; - } - - #endregion - - #region Protected Constructors - - /// - /// Initializes a new instance of the class. - /// - protected ImageBoxZoomEventArgs() - { } - - #endregion - - #region Public Properties - - /// - /// Gets or sets the actions that occured. - /// - /// The zoom operation. - public ImageBoxZoomActions Actions { get; protected set; } - - /// - /// Gets or sets the new zoom level. - /// - /// The new zoom level. - public double NewZoom { get; protected set; } - - /// - /// Gets or sets the old zoom level. - /// - /// The old zoom level. - public double OldZoom { get; protected set; } - - /// - /// Gets or sets the source of the operation.. - /// - /// The source. - public ImageBoxActionSources Source { get; protected set; } - - #endregion - } -} diff --git a/Source/Components/ImageGlass.ImageBox/ImageBoxZoomLevelCollection.cs b/Source/Components/ImageGlass.ImageBox/ImageBoxZoomLevelCollection.cs deleted file mode 100644 index f40e4be55..000000000 --- a/Source/Components/ImageGlass.ImageBox/ImageBoxZoomLevelCollection.cs +++ /dev/null @@ -1,311 +0,0 @@ -using System; -using System.Collections; -using System.Collections.Generic; - -namespace ImageGlass -{ - // Cyotek ImageBox - // Copyright (c) 2010-2015 Cyotek Ltd. - // http://cyotek.com - // http://cyotek.com/blog/tag/imagebox - - // Licensed under the MIT License. See license.txt for the full text. - - // If you use this control in your applications, attribution, donations or contributions are welcome. - - /// - /// Represents available levels of zoom in an control - /// - public class ImageBoxZoomLevelCollection : IList - { - #region Public Constructors - - /// - /// Initializes a new instance of the class. - /// - public ImageBoxZoomLevelCollection() - { - List = new SortedList(); - } - - /// - /// Initializes a new instance of the class. - /// - /// The default values to populate the collection with. - /// Thrown if the collection parameter is null - public ImageBoxZoomLevelCollection(IEnumerable collection) - : this() - { - if (collection == null) - { - throw new ArgumentNullException("collection"); - } - - AddRange(collection); - } - - #endregion - - #region Public Class Properties - - /// - /// Returns the default zoom levels - /// - public static ImageBoxZoomLevelCollection Default - { - get - { - return new ImageBoxZoomLevelCollection(new[] - { - 7, 10, 15, 20, 25, 30, 50, 70, 100, 150, 200, 300, 400, 500, 600, 700, 800, 1200, 1600, 2000, 2500, 3000, 3500 - }); - } - } - - #endregion - - #region Public Properties - - /// - /// Gets the number of elements contained in the . - /// - /// - /// The number of elements contained in the . - /// - public int Count - { - get { return List.Count; } - } - - /// - /// Gets a value indicating whether the is read-only. - /// - /// true if this instance is read only; otherwise, false. - /// true if the is read-only; otherwise, false. - /// - public bool IsReadOnly - { - get { return false; } - } - - /// - /// Gets or sets the zoom level at the specified index. - /// - /// The index. - public int this[int index] - { - get { return List.Values[index]; } - set - { - List.RemoveAt(index); - Add(value); - } - } - - #endregion - - #region Protected Properties - - /// - /// Gets or sets the backing list. - /// - protected SortedList List { get; set; } - - #endregion - - #region Public Members - - /// - /// Adds an item to the . - /// - /// The object to add to the . - public void Add(int item) - { - List.Add(item, item); - } - - /// - /// Adds a range of items to the . - /// - /// The items to add to the collection. - /// Thrown if the collection parameter is null. - public void AddRange(IEnumerable collection) - { - if (collection == null) - { - throw new ArgumentNullException("collection"); - } - - foreach (int value in collection) - { - Add(value); - } - } - - /// - /// Removes all items from the . - /// - public void Clear() - { - List.Clear(); - } - - /// - /// Determines whether the contains a specific value. - /// - /// The object to locate in the . - /// true if is found in the ; otherwise, false. - public bool Contains(int item) - { - return List.ContainsKey(item); - } - - /// - /// Copies a range of elements this collection into a destination . - /// - /// The that receives the data. - /// A 64-bit integer that represents the index in the at which storing begins. - public void CopyTo(int[] array, int arrayIndex) - { - for (int i = 0; i < Count; i++) - { - array[arrayIndex + i] = List.Values[i]; - } - } - - /// - /// Finds the index of a zoom level matching or nearest to the specified value. - /// - /// The zoom level. - public int FindNearest(int zoomLevel) - { - int nearestValue = List.Values[0]; - int nearestDifference = Math.Abs(nearestValue - zoomLevel); - for (int i = 1; i < Count; i++) - { - int value = List.Values[i]; - int difference = Math.Abs(value - zoomLevel); - if (difference < nearestDifference) - { - nearestValue = value; - nearestDifference = difference; - } - } - return nearestValue; - } - - /// - /// Returns an enumerator that iterates through the collection. - /// - /// A that can be used to iterate through the collection. - public IEnumerator GetEnumerator() - { - return List.Values.GetEnumerator(); - } - - /// - /// Determines the index of a specific item in the . - /// - /// The object to locate in the . - /// The index of if found in the list; otherwise, -1. - public int IndexOf(int item) - { - return List.IndexOfKey(item); - } - - /// - /// Not implemented. - /// - /// The index. - /// The item. - /// Not implemented - public void Insert(int index, int item) - { - throw new NotImplementedException(); - } - - /// - /// Returns the next increased zoom level for the given current zoom. - /// - /// The current zoom level. - /// The next matching increased zoom level for the given current zoom if applicable, otherwise the nearest zoom. - public int NextZoom(int zoomLevel) - { - int index; - - index = IndexOf(FindNearest(zoomLevel)); - if (index < Count - 1) - { - index++; - } - - return this[index]; - } - - /// - /// Returns the next decreased zoom level for the given current zoom. - /// - /// The current zoom level. - /// The next matching decreased zoom level for the given current zoom if applicable, otherwise the nearest zoom. - public int PreviousZoom(int zoomLevel) - { - int index; - - index = IndexOf(FindNearest(zoomLevel)); - if (index > 0) - { - index--; - } - - return this[index]; - } - - /// - /// Removes the first occurrence of a specific object from the . - /// - /// The object to remove from the . - /// true if was successfully removed from the ; otherwise, false. This method also returns false if is not found in the original . - public bool Remove(int item) - { - return List.Remove(item); - } - - /// - /// Removes the element at the specified index of the . - /// - /// The zero-based index of the element to remove. - public void RemoveAt(int index) - { - List.RemoveAt(index); - } - - /// - /// Copies the elements of the to a new array. - /// - /// An array containing copies of the elements of the . - public int[] ToArray() - { - int[] results; - - results = new int[Count]; - CopyTo(results, 0); - - return results; - } - - #endregion - - #region IList Members - - /// - /// Returns an enumerator that iterates through a collection. - /// - /// An object that can be used to iterate through the collection. - IEnumerator IEnumerable.GetEnumerator() - { - return GetEnumerator(); - } - - #endregion - } -} diff --git a/Source/Components/ImageGlass.ImageBox/ImageGlass.ImageBox.csproj b/Source/Components/ImageGlass.ImageBox/ImageGlass.ImageBox.csproj deleted file mode 100644 index c8890e368..000000000 --- a/Source/Components/ImageGlass.ImageBox/ImageGlass.ImageBox.csproj +++ /dev/null @@ -1,135 +0,0 @@ - - - - - Debug - AnyCPU - {4159C8D3-C18D-4BED-8BE6-9BAD1B0CA4F6} - Library - Properties - ImageGlass - ImageGlass.ImageBox - v4.7.1 - 512 - - - - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - - - true - false - - - pdbonly - false - bin\Release\ - TRACE - prompt - 4 - bin\Release\ImageGlass.ImageBox.xml - false - - - true - - - cyopublic.snk - - - true - bin\x86\Debug\ - DEBUG;TRACE - true - full - x86 - 7.3 - prompt - MinimumRecommendedRules.ruleset - - - bin\x86\Release\ - TRACE - bin\Release\ImageGlass.ImageBox.xml - pdbonly - x86 - 7.3 - prompt - MinimumRecommendedRules.ruleset - - - true - bin\x64\Debug\ - DEBUG;TRACE - true - full - x64 - 7.3 - prompt - MinimumRecommendedRules.ruleset - - - bin\x64\Release\ - TRACE - bin\Release\ImageGlass.ImageBox.xml - pdbonly - x64 - 7.3 - prompt - MinimumRecommendedRules.ruleset - - - - - - - - - - - - Component - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/Source/Components/ImageGlass.ImageBox/Properties/AssemblyInfo.cs b/Source/Components/ImageGlass.ImageBox/Properties/AssemblyInfo.cs deleted file mode 100644 index 6ea540720..000000000 --- a/Source/Components/ImageGlass.ImageBox/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,17 +0,0 @@ -using System; -using System.Reflection; -using System.Runtime.InteropServices; - -[assembly: AssemblyTitle("ImageGlass.ImageBox")] -[assembly: AssemblyDescription("A customization ImageBox base on Cyotek ImageBox Control of Cyotek Ltd")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("Duong Dieu Phap")] -[assembly: AssemblyProduct("ImageGlass ImageBox Control")] -[assembly: AssemblyCopyright("Copyright © 2010-2015 Cyotek Ltd.")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] -[assembly: ComVisible(false)] -[assembly: Guid("d812a438-008c-47f9-926f-8415490cdda1")] -[assembly: CLSCompliant(true)] -[assembly: AssemblyVersion("7.5.*")] -//[assembly: AssemblyFileVersion("6.0.0.0")] diff --git a/Source/Components/ImageGlass.ImageBox/ZoomLevelCollectionConverter.cs b/Source/Components/ImageGlass.ImageBox/ZoomLevelCollectionConverter.cs deleted file mode 100644 index 0848d2ab9..000000000 --- a/Source/Components/ImageGlass.ImageBox/ZoomLevelCollectionConverter.cs +++ /dev/null @@ -1,111 +0,0 @@ -using System; -using System.Collections; -using System.Collections.Generic; -using System.ComponentModel; -using System.ComponentModel.Design.Serialization; -using System.Globalization; -using System.Linq; -using System.Reflection; -using System.Text; -using System.Windows.Forms; - -namespace Cyotek.Windows.Forms -{ - public class ZoomLevelCollectionConverter - : TypeConverter - { - public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType) - { - return sourceType == typeof(string) || base.CanConvertFrom(context, sourceType); - } - - public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType) - { - return destinationType == typeof(InstanceDescriptor) || base.CanConvertTo(context, destinationType); - } - - public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) - { - string data; - ZoomLevelCollection result; - - data = value as string; - if (!string.IsNullOrEmpty(data)) - { - char separator; - string[] items; - TypeConverter converter; - - if (culture == null) - culture = CultureInfo.CurrentCulture; - - result = new ZoomLevelCollection(); - separator = culture.TextInfo.ListSeparator[0]; - items = data.Split(separator); - converter = TypeDescriptor.GetConverter(typeof(int)); - - foreach (string item in items) - result.Add((int)converter.ConvertFromString(context, culture, item)); - } - else - result = null; - - return result; - } - - public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType) - { - object result; - - if (destinationType == null) - throw new ArgumentNullException("destinationType"); - - if (value is ZoomLevelCollection) - { - if (destinationType == typeof(string)) - { - ZoomLevelCollection collection; - StringBuilder data; - string separator; - TypeConverter converter; - - collection = (ZoomLevelCollection)value; - if (culture == null) - culture = CultureInfo.CurrentCulture; - separator = culture.TextInfo.ListSeparator + " "; - converter = TypeDescriptor.GetConverter(typeof(int)); - data = new StringBuilder(); - - foreach (int item in collection) - { - if (data.Length != 0) - data.Append(separator); - - data.Append(converter.ConvertToString(context, culture, item)); - } - - result = data.ToString(); - } - else if (destinationType == typeof(InstanceDescriptor)) - { - ZoomLevelCollection collection; - ConstructorInfo constructor; - - collection = (ZoomLevelCollection)value; - constructor = typeof(ZoomLevelCollection).GetConstructor(new Type[] { typeof(IList) }); - - result = new InstanceDescriptor(constructor, new object[] { collection.ToArray() }); - } - else - result = null; - } - else - result = null; - - if (result == null) - result = base.ConvertTo(context, culture, value, destinationType); - - return result; - } - } -} diff --git a/Source/Components/ImageGlass.ImageBox/cyopublic.snk b/Source/Components/ImageGlass.ImageBox/cyopublic.snk deleted file mode 100644 index 64b3ee11d..000000000 Binary files a/Source/Components/ImageGlass.ImageBox/cyopublic.snk and /dev/null differ diff --git a/Source/Components/ImageGlass.ImageListView/Contrib.txt b/Source/Components/ImageGlass.ImageListView/Contrib.txt deleted file mode 100644 index a49ed6c6b..000000000 --- a/Source/Components/ImageGlass.ImageListView/Contrib.txt +++ /dev/null @@ -1,13 +0,0 @@ -Contributors to ImageListView -============================= - - * Ozgur Ozcitak - * Robby - - Thumbnail extraction fallback with shell icons - - Theming support with the ImageListViewColor class. - - Checkboxes for imagelistview items. - - File icons for imagelistview items. - * Uwe Keim (http://uwe.co/) - - German translations - * Jens - - Thumbnail and metadata extraction via WIC. diff --git a/Source/Components/ImageGlass.ImageListView/DiskCache.cs b/Source/Components/ImageGlass.ImageListView/DiskCache.cs deleted file mode 100644 index 69a975609..000000000 --- a/Source/Components/ImageGlass.ImageListView/DiskCache.cs +++ /dev/null @@ -1,442 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Threading; -using System.Text; - -namespace ImageGlass.ImageListView -{ - /// - /// Represents a collection of items on disk that can be read - /// and written by multiple threads. - /// - internal class DiskCache : IDisposable - { - #region Enums - /// - /// Represents the synchronization behaviour. - /// - [Flags] - public enum SyncBehavior - { - /// - /// A minimal number of locking is performed. - /// Both reads and writes may result in cache misses. - /// - SyncNone = 0, - /// - /// Cache reads are synchronized. - /// - SyncReads = 1, - /// - /// Cache writes are synchronized. - /// - SyncWrites = 2, - /// - /// Both cache reads and writes are synchronized. - /// - SnycAll = SyncReads | SyncWrites - } - #endregion - - #region Member Variables - private string mFileName; - private long mSize; - private SyncBehavior mSyncBehavior; - private int mKeySize; - - private FileStream stream; - private Dictionary index; - - private readonly object lockObject; - private long writeOffset; - #endregion - - #region Properties - /// - /// Gets or sets the cache file name. - /// - public string FileName - { - get { return mFileName; } - set - { - mFileName = value; - if (stream != null) - stream.Close(); - - if (!string.IsNullOrEmpty(mFileName)) - { - stream = new FileStream(mFileName, FileMode.OpenOrCreate, FileAccess.ReadWrite); - BuildIndex(); - } - } - } - /// - /// Gets or sets the maximum size of the cache file in bytes. - /// - public long Size { get { return mSize; } set { mSize = value; } } - #endregion - - #region CacheItem class - /// - /// Represents an item in the cache. - /// - private struct CacheItem - { - /// - /// Gets the item identifier. - /// - public string ID { get; private set; } - /// - /// Gets the offset to the item in the cache file. - /// - public long Offset { get; private set; } - /// - /// Gets the size of item data in bytes. - /// - public long Length { get; private set; } - - /// - /// Initializes a new instance of the class. - /// - /// Item identifier. - /// Offset to the item in the cache file. - /// Size of item data in bytes. - public CacheItem(string id, long offset, long length) - : this() - { - ID = id; - Offset = offset; - Length = length; - } - - /// - /// Initializes a new instance of the class. - /// - /// Item identifier. - public CacheItem(string id) - : this(id, -1, -1) - { - ; - } - } - #endregion - - #region Constructor - /// - /// Initializes a new instance of the class. - /// - /// The path to the cache file. - /// Maximum cache size in bytes. When this size is exceeded, - /// old items will be overwritten. - /// The synchronization behaviour. - /// Byte length of keys. - public DiskCache(string filename, long size, SyncBehavior syncBehavior, int keySize) - { - lockObject = new object(); - writeOffset = 0; - - mKeySize = keySize; - mSyncBehavior = syncBehavior; - - index = new Dictionary(); - mFileName = filename; - mSize = size; - - if (!string.IsNullOrEmpty(mFileName)) - { - stream = new FileStream(filename, FileMode.OpenOrCreate, FileAccess.ReadWrite); - BuildIndex(); - } - } - - /// - /// Initializes a new instance of the class. - /// - /// The path to the cache file. - /// Maximum cache size in bytes. When this size is exceeded, - /// old items will be overwritten. - public DiskCache(string filename, long size) - : this(filename, size, SyncBehavior.SnycAll, 32) - { - ; - } - - /// - /// Initializes a new instance of the class with - /// a maximum file size of 100 MiB. - /// - /// The path to the cache file. - public DiskCache(string filename) - : this(filename, 100 * 1024 * 1024, SyncBehavior.SnycAll, 32) - { - ; - } - - /// - /// Initializes a new instance of the class. - /// - public DiskCache() - : this(string.Empty, 100 * 1024 * 1024, SyncBehavior.SnycAll, 32) - { - ; - } - #endregion - - #region Instance Methods - /// - /// Performs application-defined tasks associated with - /// freeing, releasing, or resetting unmanaged resources. - /// - public void Dispose() - { - if (stream != null) - stream.Close(); - } - - /// - /// Rebuilds the index of items in the cache. - /// - private void BuildIndex() - { - if (stream == null) - throw new InvalidOperationException(); - - Monitor.Enter(lockObject); - try - { - writeOffset = 0; - stream.Seek(0, SeekOrigin.Begin); - while (stream.Position < stream.Length) - { - int read; - byte[] buffer; - - buffer = new byte[mKeySize]; - read = stream.Read(buffer, 0, mKeySize); - if (read != mKeySize) - break; - string id = Encoding.ASCII.GetString(buffer); - - buffer = new byte[8]; - read = stream.Read(buffer, 0, 8); - if (read != 8) - break; - long length = BitConverter.ToInt64(buffer, 0); - - CacheItem item = new CacheItem(id, writeOffset, length); - if (index.ContainsKey(id)) - index[id] = item; - else - index.Add(id, item); - - stream.Seek(length, SeekOrigin.Current); - writeOffset += 24 + length; - } - } - finally - { - Monitor.Exit(lockObject); - } - } - - /// - /// Reads an item from the cache. - /// - /// Item identifier. - /// When this function returns, - /// will hold item data. - /// True if the item was read; otherwise false. - public bool Read(string id, Stream data) - { - if (stream == null) - return false; - id = MakeKey(id); - - if ((mSyncBehavior & SyncBehavior.SyncReads) == SyncBehavior.SyncNone) - { - if (!Monitor.TryEnter(lockObject)) - return false; - } - else - { - Monitor.Enter(lockObject); - } - - try - { - CacheItem item; - if (!index.TryGetValue(id, out item)) - return false; - - stream.Seek(item.Offset, SeekOrigin.Begin); - - int read; - byte[] buffer; - - buffer = new byte[mKeySize]; - read = stream.Read(buffer, 0, mKeySize); - if (read != mKeySize) - { - index.Remove(id); - return false; - } - string checkid = Encoding.ASCII.GetString(buffer); - if (checkid != item.ID) - { - index.Remove(id); - return false; - } - - buffer = new byte[8]; - read = stream.Read(buffer, 0, 8); - if (read != 8) - { - index.Remove(id); - return false; - } - long length = BitConverter.ToInt64(buffer, 0); - if (length != item.Length) - { - index.Remove(id); - return false; - } - - if (stream.Position + length > stream.Length) - { - index.Remove(id); - return false; - } - - data.Seek(0, SeekOrigin.Begin); - data.SetLength(length); - long totalRead = 0; - buffer = new byte[4096]; - while (totalRead < length) - { - read = stream.Read(buffer, 0, 4096); - data.Write(buffer, 0, read); - totalRead += read; - } - } - finally - { - Monitor.Exit(lockObject); - } - - return true; - } - - /// - /// Reads an item from the cache. - /// - /// Item identifier. - /// When this function returns, - /// will hold item data. - /// True if the item was read; otherwise false. - public bool Read(string id, byte[] data) - { - if (stream == null) - return false; - - using (MemoryStream dataStream = new MemoryStream(data)) - { - return Read(id, dataStream); - } - } - - /// - /// Writes an item to the cache. - /// - /// Item identifier. If an item with this identifier already - /// exists, it will be overwritten. - /// Item data. - /// True if the item was written; otherwise false. - public bool Write(string id, Stream data) - { - if (stream == null) - return false; - id = MakeKey(id); - - if ((mSyncBehavior & SyncBehavior.SyncWrites) == SyncBehavior.SyncNone) - { - if (!Monitor.TryEnter(lockObject)) - return false; - } - else - { - Monitor.Enter(lockObject); - } - - try - { - stream.Seek(writeOffset, SeekOrigin.Begin); - data.Seek(0, SeekOrigin.Begin); - - byte[] buffer; - buffer = Encoding.ASCII.GetBytes(id); - stream.Write(buffer, 0, buffer.Length); - stream.Write(BitConverter.GetBytes(data.Length), 0, 8); - - int totalRead = 0; - buffer = new byte[4096]; - - while (data.Position < data.Length) - { - int read = data.Read(buffer, 0, 4096); - stream.Write(buffer, 0, read); - totalRead += read; - } - - CacheItem item = new CacheItem(id, writeOffset, totalRead); - if (index.ContainsKey(id)) - index[id] = item; - else - index.Add(id, item); - - writeOffset += 24 + totalRead; - if (writeOffset > mSize) - writeOffset = 0; - } - finally - { - Monitor.Exit(lockObject); - } - - return true; - } - - /// - /// Writes an item to the cache. - /// - /// Item identifier. If an item with this identifier already - /// exists, it will be overwritten. - /// Item data. - /// True if the item was written; otherwise false. - public bool Write(string id, byte[] data) - { - if (stream == null) - return false; - - using (MemoryStream dataStream = new MemoryStream(data)) - { - return Write(id, dataStream); - } - } - /// - /// Converts the given string to an item key. - /// - /// Input string. - /// Item key. - private string MakeKey(string key) - { - if (key.Length > mKeySize) - key = key.Substring(0, mKeySize); - if (key.Length < mKeySize) - key = key + new string(' ', mKeySize - key.Length); - return key; - } - #endregion - } -} diff --git a/Source/Components/ImageGlass.ImageListView/Enums.cs b/Source/Components/ImageGlass.ImageListView/Enums.cs deleted file mode 100644 index 445a2ce9c..000000000 --- a/Source/Components/ImageGlass.ImageListView/Enums.cs +++ /dev/null @@ -1,429 +0,0 @@ -// ImageListView - A listview control for image files -// Copyright (C) 2009 Ozgur Ozcitak -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// Ozgur Ozcitak (ozcitak@yahoo.com) - -using System; - -namespace ImageGlass.ImageListView -{ - #region QueuedBackgroundWorker Public Enums - /// - /// Represents the mode in which the work items of are processed. - /// - public enum ProcessingMode - { - /// - /// Items are processed in the order they are received. - /// - FIFO, - /// - /// Items are processed in reverse order. - /// - LIFO, - } - #endregion - - #region ImageListView Public Enums - /// - /// Represents the cache mode. - /// - public enum CacheMode - { - /// - /// Item thumbnails will be generated only when requested. - /// - OnDemand, - /// - /// Item thumbnails will be continuously generated. Setting - /// the CacheMode to Continuous disables the CacheLimit. - /// - Continuous, - } - /// - /// Represents the cache state of a thumbnail image. - /// - public enum CacheState - { - /// - /// The item is either not cached or it is in the cache queue. - /// - Unknown, - /// - /// Item thumbnail is cached. - /// - Cached, - /// - /// An error occurred while creating the item thumbnail. - /// - Error, - } - /// - /// Represents the cache thread. - /// - public enum CacheThread - { - /// - /// The cache thread responsible for generating item image thumbnails. - /// - Thumbnail, - /// - /// The cache thread responsible for generating item details. - /// - Details, - } - /// - /// Represents the visual state of an image list column. - /// - [Flags] - public enum ColumnState - { - /// - /// The column is not hovered. - /// - None = 0, - /// - /// Mouse cursor is over the column. - /// - Hovered = 1, - /// - /// Mouse cursor is over the column separator. - /// - SeparatorHovered = 2, - /// - /// Column separator is being dragged. - /// - SeparatorSelected = 4, - /// - /// The column is the sort column. - /// - SortColumn = 8, - } - /// - /// Represents the type of information displayed in an image list view column. - /// - public enum ColumnType - { - /// - /// A custom text column. - /// - Custom, - /// - /// The text of the item, defaults to filename if - /// the text is not provided. - /// - Name, - /// - /// The last access date. - /// - DateAccessed, - /// - /// The creation date. - /// - DateCreated, - /// - /// The last modification date. - /// - DateModified, - /// - /// Mime type of the file. - /// - FileType, - /// - /// The full path to the file. - /// - FileName, - /// - /// The path to the folder containing the file. - /// - FilePath, - /// - /// The size of the file. - /// - FileSize, - /// - /// Image dimensions in pixels. - /// - Dimensions, - /// - /// Image resolution if dpi. - /// - Resolution, - /// - /// Image description (Exif tag). - /// - ImageDescription, - /// - /// The equipment model (Exif tag). - /// - EquipmentModel, - /// - /// The date image was taken (Exif tag). - /// - DateTaken, - /// - /// The artist taking the image (Exif tag). - /// - Artist, - /// - /// Image copyright information (Exif tag). - /// - Copyright, - /// - /// Exposure time in seconds (Exif tag). - /// - ExposureTime, - /// - /// The F number (Exif tag). - /// - FNumber, - /// - /// ISO speed (Exif tag). - /// - ISOSpeed, - /// - /// User comment (Exif tag). - /// - UserComment, - /// - /// Rating (Windows Exif tag). - /// - Rating, - /// - /// Software (Exif tag). - /// - Software, - /// - /// Focal length (Exif tag). - /// - FocalLength, - } - /// - /// Represents the order by which items are drawn. - /// - public enum ItemDrawOrder - { - /// - /// Draw order is determined by item insertion index. - /// - ItemIndex, - /// - /// Draw order is determined by the ZOrder properties of items. - /// - ZOrder, - /// - /// Hovered items are drawn first, followed by normal items and selected items. - /// - HoveredNormalSelected, - /// - /// Hovered items are drawn first, followed by selected items and normal items. - /// - HoveredSelectedNormal, - /// - /// Normal items are drawn first, followed by hovered items and selected items. - /// - NormalHoveredSelected, - /// - /// Normal items are drawn first, followed by selected items and hovered items. - /// - NormalSelectedHovered, - /// - /// Selected items are drawn first, followed by hovered items and normal items. - /// - SelectedHoveredNormal, - /// - /// Selected items are drawn first, followed by normal items and hovered items. - /// - SelectedNormalHovered, - } - /// - /// Represents the visual state of an image list view item. - /// - [Flags] - public enum ItemState - { - /// - /// The item is neither selected nor hovered. - /// - None = 0, - /// - /// The item is selected. - /// - Selected = 1, - /// - /// The item has the input focus. - /// - Focused = 2, - /// - /// Mouse cursor is over the item. - /// - Hovered = 4, - /// - /// The item is disabled. - /// - Disabled = 8, - } - /// - /// Determines the visibility of an item. - /// - public enum ItemVisibility - { - /// - /// The item is not visible. - /// - NotVisible, - /// - /// The item is partially visible. - /// - PartiallyVisible, - /// - /// The item is fully visible. - /// - Visible, - } - /// - /// Represents the embedded thumbnail extraction behavior. - /// - public enum UseEmbeddedThumbnails - { - /// - /// Always creates the thumbnail from the embedded thumbnail. - /// - Always = 0, - /// - /// Creates the thumbnail from the embedded thumbnail when possible, - /// reverts to the source image otherwise. - /// - Auto = 1, - /// - /// Always creates the thumbnail from the source image. - /// - Never = 2, - } - /// - /// Represents Windows Imaging Component usage option. - /// - public enum UseWIC - { - /// - /// Uses WIC if when possible. - /// - Auto, - /// - /// Never uses WIC. - /// - Never, - /// - /// Uses WIC for extracting thumbnails only. - /// - ThumbnailsOnly, - /// - /// Uses WIC for reading metadata only. - /// - DetailsOnly, - } - /// - /// Represents the view mode of the image list view. - /// - public enum View - { - /// - /// Displays columns with image details. Thumbnail images - /// are not displayed. The view can be scrolled vertically. - /// - Details, - /// - /// Displays a single row of thumbnails at the bottom. - /// The view can be scrolled horizontally. - /// - Gallery, - /// - /// Displays a pane with item details.The view can be - /// scrolled vertically. - /// - Pane, - /// - /// Displays thumbnails laid out in a grid. The view can be - /// scrolled vertically. - /// - Thumbnails, - } - /// - /// Specifies how items in a list are sorted. - /// - public enum SortOrder - { - /// - /// The items are not sorted. - /// - None = 0, - /// - /// The items are sorted in ascending order. - /// - Ascending = 1, - /// - /// The items are sorted in descending order. - /// - Descending = 2, - /// - /// The items are sorted in ascending natural order (ie. 11.jpg comes before 100.jpg). - /// - AscendingNatural = 3, - /// - /// The items are sorted in descending natural order (ie. 11.jpg comes after 100.jpg). - /// - DescendingNatural = 4, - } - #endregion - - #region Internal Enums - /// - /// Represents the type of image in the cache manager. - /// - internal enum CachedImageType - { - /// - /// Thumbnail image. - /// - Thumbnail, - /// - /// Small shell icon. - /// - SmallIcon, - /// - /// Large shell icon. - /// - LargeIcon, - } - /// - /// Represents the item highlight state during mouse selection. - /// - internal enum ItemHighlightState - { - /// - /// Item is not highlighted. - /// - NotHighlighted, - /// - /// Item is highlighted and will be removed from the selection set. - /// - HighlightedAndUnSelected, - /// - /// Item is highlighted and will be added to the selection set. - /// - HighlightedAndSelected, - } - #endregion -} diff --git a/Source/Components/ImageGlass.ImageListView/Events.cs b/Source/Components/ImageGlass.ImageListView/Events.cs deleted file mode 100644 index c054b113f..000000000 --- a/Source/Components/ImageGlass.ImageListView/Events.cs +++ /dev/null @@ -1,565 +0,0 @@ -// ImageListView - A listview control for image files -// Copyright (C) 2009 Ozgur Ozcitak -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// Ozgur Ozcitak (ozcitak@yahoo.com) - -using System; -using System.Windows.Forms; -using System.Drawing; -using System.Runtime.InteropServices; -using System.ComponentModel; - - -namespace ImageGlass.ImageListView -{ - #region Event Delegates - /// - /// Represents the method that will handle the CacheError event. - /// - /// The ImageListView object that is the source of the event. - /// A CacheErrorEventArgs that contains event data. - [EditorBrowsable(EditorBrowsableState.Never)] - public delegate void CacheErrorEventHandler(object sender, CacheErrorEventArgs e); - /// - /// Represents the method that will handle the DropFiles event. - /// - /// The ImageListView object that is the source of the event. - /// A DropFileEventArgs that contains event data. - [EditorBrowsable(EditorBrowsableState.Never)] - public delegate void DropFilesEventHandler(object sender, DropFileEventArgs e); - /// - /// Represents the method that will handle the ColumnClick event. - /// - /// The ImageListView object that is the source of the event. - /// A ColumnClickEventArgs that contains event data. - [EditorBrowsable(EditorBrowsableState.Never)] - public delegate void ColumnClickEventHandler(object sender, ColumnClickEventArgs e); - /// - /// Represents the method that will handle the ColumnHover event. - /// - /// The ImageListView object that is the source of the event. - /// A ColumnHoverEventArgs that contains event data. - [EditorBrowsable(EditorBrowsableState.Never)] - public delegate void ColumnHoverEventHandler(object sender, ColumnHoverEventArgs e); - /// - /// Represents the method that will handle the ColumnWidthChanged event. - /// - /// The ImageListView object that is the source of the event. - /// A ColumnEventArgs that contains event data. - [EditorBrowsable(EditorBrowsableState.Never)] - public delegate void ColumnWidthChangedEventHandler(object sender, ColumnEventArgs e); - /// - /// Represents the method that will handle the ItemClick event. - /// - /// The ImageListView object that is the source of the event. - /// A ItemClickEventArgs that contains event data. - [EditorBrowsable(EditorBrowsableState.Never)] - public delegate void ItemClickEventHandler(object sender, ItemClickEventArgs e); - /// - /// Represents the method that will handle the ItemCheckBoxClick event. - /// - /// The ImageListView object that is the source of the event. - /// A ItemEventArgs that contains event data. - [EditorBrowsable(EditorBrowsableState.Never)] - public delegate void ItemCheckBoxClickEventHandler(object sender, ItemEventArgs e); - /// - /// Represents the method that will handle the ItemHover event. - /// - /// The ImageListView object that is the source of the event. - /// A ItemHoverEventArgs that contains event data. - [EditorBrowsable(EditorBrowsableState.Never)] - public delegate void ItemHoverEventHandler(object sender, ItemHoverEventArgs e); - /// - /// Represents the method that will handle the ItemDoubleClick event. - /// - /// The ImageListView object that is the source of the event. - /// A ItemClickEventArgs that contains event data. - [EditorBrowsable(EditorBrowsableState.Never)] - public delegate void ItemDoubleClickEventHandler(object sender, ItemClickEventArgs e); - /// - /// Represents the method that will handle the ThumbnailCaching event. - /// - /// The ImageListView object that is the source of the event. - /// A ItemEventArgs that contains event data. - [EditorBrowsable(EditorBrowsableState.Never)] - public delegate void ThumbnailCachingEventHandler(object sender, ThumbnailCachingEventArgs e); - /// - /// Represents the method that will handle the ThumbnailCached event. - /// - /// The ImageListView object that is the source of the event. - /// A ThumbnailCachedEventArgs that contains event data. - [EditorBrowsable(EditorBrowsableState.Never)] - public delegate void ThumbnailCachedEventHandler(object sender, ThumbnailCachedEventArgs e); - /// - /// Refreshes the owner control. - /// - [EditorBrowsable(EditorBrowsableState.Never)] - internal delegate void RefreshDelegateInternal(); - /// - /// Represents the method that will handle the ItemCollectionChanged event. - /// - /// The ImageListView object that is the source of the event. - /// A ItemCollectionChangedEventArgs that contains event data. - [EditorBrowsable(EditorBrowsableState.Never)] - public delegate void ItemCollectionChangedEventHandler(object sender, ItemCollectionChangedEventArgs e); - /// - /// Represents the method that will handle the PaneResized event. - /// - /// The ImageListView object that is the source of the event. - /// A PaneResizedEventArgs that contains event data. - [EditorBrowsable(EditorBrowsableState.Never)] - public delegate void PaneResizedEventHandler(object sender, PaneResizedEventArgs e); - /// - /// Represents the method that will handle the PaneResizing event. - /// - /// The ImageListView object that is the source of the event. - /// A PaneResizingEventArgs that contains event data. - [EditorBrowsable(EditorBrowsableState.Never)] - public delegate void PaneResizingEventHandler(object sender, PaneResizingEventArgs e); - #endregion - - #region Event Arguments - /// - /// Represents the event arguments for errors during cache operations. - /// - [Serializable, ComVisible(true)] - public class CacheErrorEventArgs - { - /// - /// Gets the ImageListViewItem that is associated with this error. - /// This parameter can be null. - /// - public ImageListViewItem Item { get; private set; } - /// - /// Gets a value indicating which error occurred during an asynchronous operation. - /// - public Exception Error { get; private set; } - /// - /// Gets the thread raising the error. - /// - public CacheThread CacheThread { get; private set; } - - /// - /// Initializes a new instance of the CacheErrorEventArgs class. - /// - /// The ImageListViewItem that is associated with this error. - /// The error that occurred during an asynchronous operation. - /// The thread raising the error. - public CacheErrorEventArgs(ImageListViewItem item, Exception error, CacheThread cacheThread) - { - Item = item; - Error = error; - CacheThread = cacheThread; - } - } - /// - /// Represents the event arguments for column related events. - /// - [Serializable, ComVisible(true)] - public class DropFileEventArgs - { - /// - /// Gets or sets whether default event code will be processed. - /// When set to true, the control will automatically insert the new items. - /// Otherwise, the control will not process the dropped files. - /// - public bool Cancel { get; set; } - /// - /// Gets the position of the insertion caret. - /// This determines where the new items will be inserted. - /// - public int Index { get; private set; } - /// - /// Gets the array of filenames droppped on the control. - /// - public string[] FileNames { get; private set; } - - /// - /// Initializes a new instance of the DropFileEventArgs class. - /// - /// The position of the insertion caret. - /// The array of filenames droppped on the control. - public DropFileEventArgs(int index, string[] fileNames) - { - Cancel = false; - Index = index; - FileNames = fileNames; - } - } - /// - /// Represents the event arguments for column related events. - /// - [Serializable, ComVisible(true)] - public class ColumnEventArgs - { - /// - /// Gets the ImageListViewColumnHeader that is the target of the event. - /// - public ImageListView.ImageListViewColumnHeader Column { get; private set; } - - /// - /// Initializes a new instance of the ColumnEventArgs class. - /// - /// The column that is the target of this event. - public ColumnEventArgs(ImageListView.ImageListViewColumnHeader column) - { - Column = column; - } - } - /// - /// Represents the event arguments for column click related events. - /// - [Serializable, ComVisible(true)] - public class ColumnClickEventArgs - { - /// - /// Gets the ImageListViewColumnHeader that is the target of the event. - /// - public ImageListView.ImageListViewColumnHeader Column { get; private set; } - /// - /// Gets the coordinates of the cursor. - /// - public Point Location { get; private set; } - /// - /// Gets the x-coordinates of the cursor. - /// - public int X { get { return Location.X; } } - /// - /// Gets the y-coordinates of the cursor. - /// - public int Y { get { return Location.Y; } } - /// - /// Gets the state of the mouse buttons. - /// - public MouseButtons Buttons { get; private set; } - - /// - /// Initializes a new instance of the ColumnClickEventArgs class. - /// - /// The column that is the target of this event. - /// The location of the mouse. - /// One of the System.Windows.Forms.MouseButtons values - /// indicating which mouse button was pressed. - public ColumnClickEventArgs(ImageListView.ImageListViewColumnHeader column, Point location, MouseButtons buttons) - { - Column = column; - Location = location; - Buttons = buttons; - } - } - /// - /// Represents the event arguments for column hover related events. - /// - [Serializable, ComVisible(true)] - public class ColumnHoverEventArgs - { - /// - /// Gets the ImageListViewColumnHeader that was previously hovered. - /// Returns null if there was no previously hovered column. - /// - public ImageListView.ImageListViewColumnHeader PreviousColumn { get; private set; } - /// - /// Gets the currently hovered ImageListViewColumnHeader. - /// Returns null if there is no hovered column. - /// - public ImageListView.ImageListViewColumnHeader Column { get; private set; } - - /// - /// Initializes a new instance of the ColumnHoverEventArgs class. - /// - /// The currently hovered column. - /// The previously hovered column. - public ColumnHoverEventArgs(ImageListView.ImageListViewColumnHeader column, ImageListView.ImageListViewColumnHeader previousColumn) - { - Column = column; - PreviousColumn = previousColumn; - } - } - /// - /// Represents the event arguments for item related events. - /// - [Serializable, ComVisible(true)] - public class ItemEventArgs - { - /// - /// Gets the ImageListViewItem that is the target of the event. - /// - public ImageListViewItem Item { get; private set; } - - /// - /// Initializes a new instance of the ItemEventArgs class. - /// - /// The item that is the target of this event. - public ItemEventArgs(ImageListViewItem item) - { - Item = item; - } - } - /// - /// Represents the event arguments for item click related events. - /// - [Serializable, ComVisible(true)] - public class ItemClickEventArgs - { - /// - /// Gets the ImageListViewItem that is the target of the event. - /// - public ImageListViewItem Item { get; private set; } - /// - /// Gets the index of the sub item under the hit point. - /// The index returned is the 0-based index of the column - /// as displayed on the screen, considering column visibility - /// and display indices. - /// Returns -1 if the hit point is not over a sub item. - /// - public int SubItemIndex { get; private set; } - /// - /// Gets the coordinates of the cursor. - /// - public Point Location { get; private set; } - /// - /// Gets the x-coordinates of the cursor. - /// - public int X { get { return Location.X; } } - /// - /// Gets the y-coordinates of the cursor. - /// - public int Y { get { return Location.Y; } } - /// - /// Gets the state of the mouse buttons. - /// - public MouseButtons Buttons { get; private set; } - - /// - /// Initializes a new instance of the ItemClickEventArgs class. - /// - /// The item that is the target of this event. - /// Gets the index of the sub item under the hit point. - /// The location of the mouse. - /// One of the System.Windows.Forms.MouseButtons values - /// indicating which mouse button was pressed. - public ItemClickEventArgs(ImageListViewItem item, int subItemIndex, Point location, MouseButtons buttons) - { - Item = item; - SubItemIndex = subItemIndex; - Location = location; - Buttons = buttons; - } - } - /// - /// Represents the event arguments for item hover related events. - /// - [Serializable, ComVisible(true)] - public class ItemHoverEventArgs - { - /// - /// Gets the ImageListViewItem that was previously hovered. - /// Returns null if there was no previously hovered item. - /// - public ImageListViewItem PreviousItem { get; private set; } - /// - /// Gets the currently hovered ImageListViewItem. - /// Returns null if there is no hovered item. - /// - public ImageListViewItem Item { get; private set; } - /// - /// Gets the index of the sub item that was previously hovered. - /// The index returned is the 0-based index of the column - /// as displayed on the screen, considering column visibility - /// and display indices. - /// Returns -1 if the hit point is not over a sub item. - /// - public int PreviousSubItemIndex { get; private set; } - /// - /// Gets the index of the hovered sub item. - /// The index returned is the 0-based index of the column - /// as displayed on the screen, considering column visibility - /// and display indices. - /// Returns -1 if the hit point is not over a sub item. - /// - public int SubItemIndex { get; private set; } - - /// - /// Initializes a new instance of the ItemEventArgs class. - /// - /// The currently hovered item. - /// The index of the hovered sub item. - /// The previously hovered item. - /// The index of the sub item that was previously hovered. - public ItemHoverEventArgs(ImageListViewItem item, int subItemIndex, ImageListViewItem previousItem, int previousSubItemIndex) - { - Item = item; - SubItemIndex = subItemIndex; - - PreviousItem = previousItem; - PreviousSubItemIndex = previousSubItemIndex; - } - } - /// - /// Represents the event arguments related to control layout. - /// - [Serializable, ComVisible(true)] - public class LayoutEventArgs - { - /// - /// Gets or sets the rectangle bounding the item area. - /// - public Rectangle ItemAreaBounds { get; set; } - - /// - /// Initializes a new instance of the LayoutEventArgs class. - /// - /// The rectangle bounding the item area. - public LayoutEventArgs(Rectangle itemAreaBounds) - { - ItemAreaBounds = itemAreaBounds; - } - } - /// - /// Represents the event arguments for the thumbnail caching event. - /// - [Serializable, ComVisible(true)] - public class ThumbnailCachingEventArgs - { - /// - /// Gets the ImageListViewItem that is the target of the event. - /// - public ImageListViewItem Item { get; private set; } - /// - /// Gets the size of the thumbnail request. - /// - public Size Size { get; private set; } - - /// - /// Initializes a new instance of the ThumbnailCachingEventArgs class. - /// - /// The item that is the target of this event. - /// The size of the thumbnail request. - public ThumbnailCachingEventArgs(ImageListViewItem item, Size size) - { - Item = item; - Size = size; - } - } - /// - /// Represents the event arguments for the thumbnail cached event. - /// - [Serializable, ComVisible(true)] - public class ThumbnailCachedEventArgs - { - /// - /// Gets the ImageListViewItem that is the target of the event. - /// - public ImageListViewItem Item { get; private set; } - /// - /// Gets the size of the thumbnail request. - /// - public Size Size { get; private set; } - /// - /// Gets the cached thumbnail image. - /// - public Image Thumbnail { get; private set; } - /// - /// Gets whether the cached image is a thumbnail image or - /// a large image for gallery or pane views. - /// - public bool IsThumbnail { get; private set; } - - /// - /// Initializes a new instance of the ThumbnailCachedEventArgs class. - /// - /// The item that is the target of this event. - /// The cached thumbnail image. - /// The size of the thumbnail request. - /// true if the cached image is a thumbnail image; otherwise false - /// if the image is a large image for gallery or pane views. - public ThumbnailCachedEventArgs(ImageListViewItem item, Image thumbnail, Size size, bool thumbnailImage) - { - Item = item; - Thumbnail = thumbnail; - Size = size; - IsThumbnail = thumbnailImage; - } - } - /// - /// Represents the event arguments for the pane resized event. - /// - [Serializable, ComVisible(true)] - public class PaneResizedEventArgs - { - /// - /// Gets the width of the pane. - /// - public int PaneWidth { get; private set; } - - /// - /// Initializes a new instance of the PaneResizedEventArgs class. - /// - /// The width of the pane. - public PaneResizedEventArgs(int paneWidth) - { - PaneWidth = paneWidth; - } - } - - /// - /// Represents the event arguments for the pane resizing event. - /// - [Serializable, ComVisible(true)] - public class PaneResizingEventArgs - { - /// - /// Gets the width of the pane. - /// - public int PaneWidth { get; private set; } - - /// - /// Initializes a new instance of the PaneResizingEventArgs class. - /// - /// The width of the pane. - public PaneResizingEventArgs(int paneWidth) - { - PaneWidth = paneWidth; - } - } - /// - /// Represents the event arguments for item collection related events. - /// - [Serializable, ComVisible(true)] - public class ItemCollectionChangedEventArgs - { - /// - /// Gets the type of action causing the change. - /// - public CollectionChangeAction Action { get; private set; } - /// - /// Gets the ImageListViewItem that is the target of the event. - /// - public ImageListViewItem Item { get; private set; } - - /// - /// Initializes a new instance of the ItemCollectionChangedEventArgs class. - /// - /// The type of action causing the change. - /// The item that is the target of this event. This parameter will be null - /// if the collection is cleared. - public ItemCollectionChangedEventArgs(CollectionChangeAction action, ImageListViewItem item) - { - Action = action; - Item = item; - } - } - #endregion -} diff --git a/Source/Components/ImageGlass.ImageListView/HitInfo.cs b/Source/Components/ImageGlass.ImageListView/HitInfo.cs deleted file mode 100644 index 6d093492c..000000000 --- a/Source/Components/ImageGlass.ImageListView/HitInfo.cs +++ /dev/null @@ -1,167 +0,0 @@ -// ImageListView - A listview control for image files -// Copyright (C) 2009 Ozgur Ozcitak -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// Ozgur Ozcitak (ozcitak@yahoo.com) - -namespace ImageGlass.ImageListView -{ - public partial class ImageListView - { - /// - /// Represents the details of a mouse hit test. - /// - public class HitInfo - { - #region Properties - /// - /// Gets whether an item is under the hit point. - /// - public bool ItemHit { get { return ItemIndex != -1; } } - /// - /// Gets whether an item checkbox is under the hit point. - /// - public bool CheckBoxHit { get; private set; } - /// - /// Gets whether a column is under the hit point. - /// - public bool ColumnHit { get { return Column != null; } } - /// - /// Gets whether a column separator is under the hit point. - /// - public bool ColumnSeparatorHit { get { return ColumnSeparator != null; } } - - /// - /// Gets the index of the item under the hit point. - /// - public int ItemIndex { get; private set; } - /// - /// Gets the index of the group header under the hit point. - /// - public ImageListViewGroup Group { get; private set; } - /// - /// Gets the index of the column under the hit point. - /// - public ImageListViewColumnHeader Column { get; private set; } - /// - /// Gets the index of the column separator under the hit point. - /// - public ImageListViewColumnHeader ColumnSeparator { get; private set; } - /// - /// Gets whether the hit point is over the pane border. - /// - public bool PaneBorder { get; private set; } - - /// - /// Gets the index of the sub item under the hit point. - /// The index returned is the 0-based index of the column - /// as displayed on the screen, considering column visibility - /// and display indices. - /// Returns -1 if the hit point is not over a sub item. - /// - public int SubItemIndex { get; private set; } - - /// - /// Gets whether the hit point is inside the item area. - /// - public bool InItemArea { get; private set; } - /// - /// Gets whether the hit point is inside the column header area. - /// - public bool InHeaderArea { get; private set; } - /// - /// Gets whether the hit point is inside the left-pane area. - /// - public bool InPaneArea { get; private set; } - #endregion - - #region Constructor - /// - /// Initializes a new instance of the HitInfo class. - /// - /// Index of the item. - /// if set to true the mouse cursor is over a checkbox. - /// The group header hit. - /// The column header hit - /// The column separator. - /// Index of the sub item. - /// if set to true the mouse cursor is over the left-pane border. - /// if set to true the mouse is in the item area. - /// if set to true the mouse cursor is in the column header area. - /// if set to true the mouse cursor is in the left-pane area. - private HitInfo(int itemIndex, bool checkBoxHit, ImageListViewGroup group, ImageListViewColumnHeader column, - ImageListViewColumnHeader columnSeparator, int subItemIndex, - bool paneBorder, bool inItemArea, bool inHeaderArea, bool inPaneArea) - { - ItemIndex = itemIndex; - CheckBoxHit = checkBoxHit; - Group = group; - Column = column; - ColumnSeparator = columnSeparator; - SubItemIndex = subItemIndex; - - InItemArea = inItemArea; - InHeaderArea = inHeaderArea; - - InPaneArea = inPaneArea; - PaneBorder = paneBorder; - } - /// - /// Initializes a new instance of the HitInfo class. - /// Used when the control registered an item hit. - /// - /// Index of the item. - /// Index of the sub item. - /// if set to true the mouse cursor is over a checkbox. - internal HitInfo(int itemIndex, int subItemIndex, bool checkBoxHit) - : this(itemIndex, checkBoxHit, null, null, null, subItemIndex, false, true, false, false) - { - ; - } - /// - /// Initializes a new instance of the HitInfo class. - /// Used when the control registered a column hit. - /// - /// The group header hit. - internal HitInfo(ImageListViewGroup group) - : this(-1, false, group, null, null, -1, false, false, true, false) - { - ; - } - /// - /// Initializes a new instance of the HitInfo class. - /// Used when the control registered a column hit. - /// - /// Type column hit. - /// The column separator. - internal HitInfo(ImageListViewColumnHeader column, ImageListViewColumnHeader columnSeparator) - : this(-1, false, null, column, columnSeparator, -1, false, false, true, false) - { - ; - } - /// - /// Initializes a new instance of the HitInfo class. - /// Used when the control registered a hit in pane area. - /// - /// True if the hit point is over the left-pane - /// border, false otherwise. - internal HitInfo(bool paneBorder) - : this(-1, false, null, null, null, -1, paneBorder, false, false, true) - { - ; - } - #endregion - } - } -} \ No newline at end of file diff --git a/Source/Components/ImageGlass.ImageListView/ImageGlass.ImageListView.csproj b/Source/Components/ImageGlass.ImageListView/ImageGlass.ImageListView.csproj deleted file mode 100644 index 05e53f030..000000000 --- a/Source/Components/ImageGlass.ImageListView/ImageGlass.ImageListView.csproj +++ /dev/null @@ -1,308 +0,0 @@ - - - - Debug - AnyCPU - 9.0.30729 - 2.0 - {0C295FB8-C6C6-4A40-9F19-05A43F353A04} - Library - Properties - ImageGlass.ImageListView - ImageGlass.ImageListView - v4.7.1 - 512 - - - - - 3.5 - publish\ - true - Disk - false - Foreground - 7 - Days - false - false - true - 0 - 1.0.0.%2a - false - false - true - - - - true - full - false - bin\Debug\ - TRACE;DEBUG;BONUSPACK;USEWIC;BENCHMARK - prompt - 4 - bin\Debug\ImageGlass.ImageListView.xml - false - - - pdbonly - true - bin\Release\ - TRACE;USEWIC - prompt - 4 - false - bin\Release\ImageGlass.ImageListView.xml - false - - - bin\Release without WIC\ - TRACE - true - false - none - 4 - false - - - true - bin\DesignerDebug\ - TRACE;DEBUG;BONUSPACK;USEWIC - bin\Debug\ImageListView.XML - full - AnyCPU - prompt - 4 - false - false - - - true - bin\x86\Debug\ - TRACE;DEBUG;BONUSPACK;USEWIC;BENCHMARK - bin\Debug\ImageGlass.ImageListView.xml - full - x86 - 7.3 - prompt - MinimumRecommendedRules.ruleset - - - bin\x86\Release\ - TRACE;USEWIC - bin\Release\ImageGlass.ImageListView.xml - true - pdbonly - x86 - false - 7.3 - prompt - MinimumRecommendedRules.ruleset - - - bin\x86\Release without WIC\ - TRACE - true - x86 - false - 7.3 - MinimumRecommendedRules.ruleset - - - true - bin\x86\Debug Designer\ - TRACE;DEBUG;BONUSPACK;USEWIC - bin\Debug\ImageListView.XML - full - x86 - 7.3 - prompt - MinimumRecommendedRules.ruleset - - - true - bin\x64\Debug\ - TRACE;DEBUG;BONUSPACK;USEWIC;BENCHMARK - bin\Debug\ImageGlass.ImageListView.xml - full - x64 - 7.3 - prompt - MinimumRecommendedRules.ruleset - - - bin\x64\Release\ - TRACE;USEWIC - bin\Release\ImageGlass.ImageListView.xml - true - pdbonly - x64 - false - 7.3 - prompt - MinimumRecommendedRules.ruleset - - - bin\x64\Release without WIC\ - TRACE - true - x64 - false - 7.3 - MinimumRecommendedRules.ruleset - - - true - bin\x64\Debug Designer\ - TRACE;DEBUG;BONUSPACK;USEWIC - bin\Debug\ImageListView.XML - full - x64 - 7.3 - prompt - MinimumRecommendedRules.ruleset - - - - 3.0 - - - - 3.5 - - - - - - - - 3.0 - - - - - - component - - - component - - - - - - - - component - - - - - - - - Component - - - - - - component - - - - - - - Component - - - - component - - - component - - - - - - component - - - - - component - - - component - - - component - - - - True - True - ImageListViewResources.resx - - - - - - - - - - ResXFileCodeGenerator - ImageListViewResources.Designer.cs - Designer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - False - .NET Framework 3.5 SP1 - true - - - - - {51493b09-7a0e-461f-be18-a6cf629a8fab} - ImageGlass.Heart - - - - - \ No newline at end of file diff --git a/Source/Components/ImageGlass.ImageListView/ImageListView.bmp b/Source/Components/ImageGlass.ImageListView/ImageListView.bmp deleted file mode 100644 index a1e34e9fc..000000000 Binary files a/Source/Components/ImageGlass.ImageListView/ImageListView.bmp and /dev/null differ diff --git a/Source/Components/ImageGlass.ImageListView/ImageListView.cs b/Source/Components/ImageGlass.ImageListView/ImageListView.cs deleted file mode 100644 index 7fa3c304a..000000000 --- a/Source/Components/ImageGlass.ImageListView/ImageListView.cs +++ /dev/null @@ -1,2288 +0,0 @@ -// ImageListView - A listview control for image files -// Copyright (C) 2009 Ozgur Ozcitak -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// Ozgur Ozcitak (ozcitak@yahoo.com) - -using System; -using System.Collections.Generic; -using System.Windows.Forms; -using System.ComponentModel; -using System.Drawing; -using System.Resources; - -namespace ImageGlass.ImageListView -{ - /// - /// The ImageGlass.ImageListView namespace contains new and - /// enhanced windows forms components. - /// - internal class NamespaceDoc - { - } - - /// - /// Represents a listview control for image files. - /// - [ToolboxBitmap(typeof(ImageListView))] - [Description("Represents a listview control for image files.")] - [DefaultEvent("ItemClick")] - [DefaultProperty("Items")] - [Designer(typeof(ImageListViewDesigner))] - [Docking(DockingBehavior.Ask)] - public partial class ImageListView : Control, IComponent - { - #region Constants - /// - /// Default width of column headers in pixels. - /// - internal const int DefaultColumnWidth = 100; - /// - /// Selection tolerance for column separators. - /// - internal const int SeparatorSize = 12; - /// - /// Selection tolerance for left-pane border. - /// - internal const int PaneBorderSize = 4; - #endregion - - #region Member Variables - // Set when properties change - private bool mDefaultImageChanged = false; - private bool mErrorImageChanged = false; - private bool mRatingImageChanged = false; - private bool mEmptyRatingImageChanged = false; - // Properties - private BorderStyle mBorderStyle; - private CacheMode mCacheMode; - private int mCacheLimitAsItemCount; - private long mCacheLimitAsMemory; - private ImageListViewColor mColors; - private ImageListViewColumnHeaderCollection mColumns; - private Image mDefaultImage; - private Image mErrorImage; - private Image mRatingImage; - private Image mEmptyRatingImage; - private Font mGroupHeaderFont; - private Font mColumnHeaderFont; - private bool mIntegralScroll; - private ImageListViewItemCollection mItems; - private int mPaneWidth; - private bool mRetryOnError; - internal ImageListViewSelectedItemCollection mSelectedItems; - internal ImageListViewCheckedItemCollection mCheckedItems; - private int mSortColumn; - private int mGroupColumn; - private SortOrder mSortOrder; - private SortOrder mGroupOrder; - private bool mShowFileIcons; - private bool mShowCheckBoxes; - private ContentAlignment mIconAlignment; - private Size mIconPadding; - private ContentAlignment mCheckBoxAlignment; - private Size mCheckBoxPadding; - private Size mThumbnailSize; - private UseEmbeddedThumbnails mUseEmbeddedThumbnails; - private UseWIC mUseWIC; - private View mView; - private Point mViewOffset; - private bool mShowScrollBars; - private bool mEnableKeyNavigation; - - // Groups - internal ImageListViewGroupCollection groups; - internal bool showGroups; - - // Renderer variables - internal ImageListViewRenderer mRenderer; - private bool controlSuspended; - private int rendererSuspendCount; - private bool rendererNeedsPaint; - private System.Timers.Timer lazyRefreshTimer; - private RefreshDelegateInternal lazyRefreshCallback; - - // Layout variables - internal HScrollBar hScrollBar; - internal VScrollBar vScrollBar; - internal ImageListViewLayoutManager layoutManager; - private bool disposed; - - // Interaction variables - internal ImageListViewNavigationManager navigationManager; - - // Cache threads - internal ImageListViewCacheThumbnail thumbnailCache; - internal ImageListViewCacheShellInfo shellInfoCache; - internal ImageListViewCacheMetadata metadataCache; - internal ImageListViewItemAdaptors.FileSystemAdaptor defaultAdaptor; - - // Resource manager - private ResourceManager resources; - #endregion - - #region Properties - /// - /// Gets or sets whether thumbnail images are automatically rotated. - /// - [Category("Behavior"), Description("Gets or sets whether thumbnail images are automatically rotated."), DefaultValue(true)] - public bool AutoRotateThumbnails { get; set; } - /// - /// Gets or sets whether checkboxes respond to mouse clicks. - /// - [Category("Behavior"), Description("Gets or sets whether checkboxes respond to mouse clicks."), DefaultValue(true)] - public bool AllowCheckBoxClick { get; set; } - /// - /// Gets or sets whether column headers respond to mouse clicks. - /// - [Category("Behavior"), Description("Gets or sets whether column headers respond to mouse clicks."), DefaultValue(true)] - public bool AllowColumnClick { get; set; } - /// - /// Gets or sets whether column headers can be resized with the mouse. - /// - [Category("Behavior"), Description("Gets or sets whether column headers can be resized with the mouse."), DefaultValue(true)] - public bool AllowColumnResize { get; set; } - /// - /// Gets or sets whether the user can drag items for drag-and-drop operations. - /// - [Category("Behavior"), Description("Gets or sets whether the user can drag items for drag-and-drop operations."), DefaultValue(false)] - public bool AllowDrag { get; set; } - /// - /// Gets or sets whether duplicate items (image files pointing to the same path - /// on the file system) are allowed. - /// - [Category("Behavior"), Description("Gets or sets whether duplicate items (image files pointing to the same path on the file system) are allowed."), DefaultValue(false)] - public bool AllowDuplicateFileNames { get; set; } - /// - /// Gets or sets whether the left-pane can be resized with the mouse. - /// - [Category("Behavior"), Description("Gets or sets whether the left-pane can be resized with the mouse."), DefaultValue(true)] - public bool AllowPaneResize { get; set; } - /// - /// Gets or sets the background color of the control. - /// - [Category("Appearance"), Description("Gets or sets the background color of the control."), DefaultValue(typeof(Color), "Window")] - public override Color BackColor - { - get { return mColors.ControlBackColor; } - set - { - mColors.ControlBackColor = value; - Refresh(); - } - } - /// - /// Gets or sets the border style of the control. - /// - [Category("Appearance"), Description("Gets or sets the border style of the control."), DefaultValue(typeof(BorderStyle), "Fixed3D")] - public BorderStyle BorderStyle - { - get { return mBorderStyle; } - set - { - mBorderStyle = value; - UpdateStyles(); - } - } - /// - /// Gets or sets the cache mode. Setting the the CacheMode to Continuous disables the CacheLimit. - /// - [Category("Behavior"), Description("Gets or sets the cache mode."), DefaultValue(typeof(CacheMode), "OnDemand"), RefreshProperties(RefreshProperties.All)] - public CacheMode CacheMode - { - get { return mCacheMode; } - set - { - if (mCacheMode != value) - { - mCacheMode = value; - - if (thumbnailCache != null) - thumbnailCache.CacheMode = mCacheMode; - - if (mCacheMode == CacheMode.Continuous) - { - mCacheLimitAsItemCount = 0; - mCacheLimitAsMemory = 0; - if (thumbnailCache != null) - { - thumbnailCache.CacheLimitAsItemCount = 0; - thumbnailCache.CacheLimitAsMemory = 0; - } - // Rebuild the cache - ClearThumbnailCache(); - } - } - } - } - /// - /// Gets or sets the cache limit as either the count of thumbnail images or the memory allocated for cache (e.g. 10MB). - /// - [Category("Behavior"), Description("Gets or sets the cache limit as either the count of thumbnail images or the memory allocated for cache (e.g. 10MB)."), DefaultValue("20MB"), RefreshProperties(RefreshProperties.All)] - public string CacheLimit - { - get - { - if (mCacheLimitAsMemory != 0) - return (mCacheLimitAsMemory / 1024 / 1024).ToString() + "MB"; - else - return mCacheLimitAsItemCount.ToString(); - } - set - { - string slimit = value; - int limit = 0; - mCacheMode = CacheMode.OnDemand; - if ((slimit.EndsWith("MB", StringComparison.OrdinalIgnoreCase) && int.TryParse(slimit.Substring(0, slimit.Length - 2).Trim(), out limit)) || (slimit.EndsWith("MiB", StringComparison.OrdinalIgnoreCase) && int.TryParse(slimit.Substring(0, slimit.Length - 3).Trim(), out limit))) - { - mCacheLimitAsItemCount = 0; - mCacheLimitAsMemory = limit * 1024 * 1024; - if (thumbnailCache != null) - { - thumbnailCache.CacheLimitAsItemCount = 0; - thumbnailCache.CacheLimitAsMemory = mCacheLimitAsMemory; - } - } - else if (int.TryParse(slimit, out limit)) - { - mCacheLimitAsMemory = 0; - mCacheLimitAsItemCount = limit; - if (thumbnailCache != null) - { - thumbnailCache.CacheLimitAsMemory = 0; - thumbnailCache.CacheLimitAsItemCount = mCacheLimitAsItemCount; - } - } - else - throw new ArgumentException("Cache limit must be specified as either the count of thumbnail images or the memory allocated for cache (eg 10MB)", "value"); - } - } - /// - /// Gets or sets the path to the persistent cache file. - /// - [Category("Behavior"), Description("Gets or sets the path to the persistent cache file."), Browsable(false)] - public string PersistentCacheFile - { - get - { - return thumbnailCache.diskCache.FileName; - } - set - { - thumbnailCache.diskCache.FileName = value; - } - } - /// - /// Gets or sets the size of the persistent cache file in MB. - /// - [Category("Behavior"), Description("Gets or sets the size of the persistent cache file in MB."), Browsable(false)] - public long PersistentCacheSize - { - get - { - return thumbnailCache.diskCache.Size / 1024 / 1024; - } - set - { - thumbnailCache.diskCache.Size = value * 1024 * 1024; - } - } - /// - /// Gets or sets the color palette of the ImageListView. - /// - [Category("Appearance"), Description("Gets or sets the color palette of the ImageListView.")] - public ImageListViewColor Colors - { - get - { - if (mColors == null) - mColors = ImageListViewColor.Default; - - return mColors; - } - set - { - mColors = value; - Refresh(); - } - } - - /// - /// Gets or sets the collection of columns of the image list view. - /// - [Category("Appearance"), Description("Gets the collection of columns of the image list view.")] - [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)] - public ImageListViewColumnHeaderCollection Columns - { - get { return mColumns; } - internal set - { - mColumns = value; - Refresh(); - } - } - /// - /// Gets or sets the placeholder image. - /// - [Category("Appearance"), Description("Gets or sets the placeholder image.")] - public Image DefaultImage - { - get - { - if (mDefaultImage == null) - return resources.GetObject("DefaultImage") as Image; - else - return mDefaultImage; - } - set - { - mDefaultImageChanged = true; - mDefaultImage = value; - Refresh(); - } - } - /// - /// Gets the rectangle that represents the display area of the control. - /// - [Category("Appearance"), Browsable(false), Description("Gets the rectangle that represents the display area of the control.")] - public override Rectangle DisplayRectangle - { - get - { - if (layoutManager == null) - return base.DisplayRectangle; - else - return layoutManager.ClientArea; - } - } - /// - /// Gets or sets a value indicating whether the control can respond to user interaction. - /// Cache threads are paused while the control is disabled and resumed when the control is - /// enabled. - /// - [Category("Behavior"), Browsable(true), Description("Gets or sets a value indicating whether the control can respond to user interaction."), DefaultValue(true)] - public new bool Enabled - { - get { return base.Enabled; } - set - { - base.Enabled = value; - if (value) - { - thumbnailCache.Resume(); - shellInfoCache.Resume(); - metadataCache.Resume(); - } - else - { - thumbnailCache.Pause(); - shellInfoCache.Pause(); - metadataCache.Pause(); - } - } - } - /// - /// [Pháp] Gets or sets whether Key Navigation is enabled. - /// - [Category("Behavior"), Description("Gets or sets whether Key Navigation is enabled.")] - public bool EnableKeyNavigation - { - get { return mEnableKeyNavigation; } - set - { - mEnableKeyNavigation = value; - } - } - /// - /// Gets or sets the error image. - /// - [Category("Appearance"), Description("Gets or sets the error image.")] - public Image ErrorImage - { - get - { - if (mErrorImage == null) - return resources.GetObject("ErrorImage") as Image; - else - return mErrorImage; - } - set - { - mErrorImageChanged = true; - mErrorImage = value; - Refresh(); - } - } - /// - /// Gets or sets the font of the group headers. - /// - [Category("Appearance"), Description("Gets or sets the font of the group headers.")] - public Font GroupHeaderFont - { - get - { - if (mGroupHeaderFont == null) - { - if (Font != null) - mGroupHeaderFont = (Font)Font.Clone(); - else - mGroupHeaderFont = (Font)Control.DefaultFont.Clone(); - } - - return mGroupHeaderFont; - } - set - { - mGroupHeaderFont = value; - Refresh(); - } - } - /// - /// Gets or sets the font of the column headers. - /// - [Category("Appearance"), Description("Gets or sets the font of the column headers.")] - public Font ColumnHeaderFont - { - get - { - if (mColumnHeaderFont == null) - { - if (Font != null) - mColumnHeaderFont = (Font)Font.Clone(); - else - mColumnHeaderFont = (Font)Control.DefaultFont.Clone(); - } - - return mColumnHeaderFont; - } - set - { - mColumnHeaderFont = value; - Refresh(); - } - } - /// - /// Gets or sets whether scrollbars scroll by an amount which is a multiple of item height. - /// - [Browsable(true), Category("Behavior"), Description("Gets or sets whether scrollbars scroll by an amount which is a multiple of item height."), DefaultValue(false)] - public bool IntegralScroll - { - get { return mIntegralScroll; } - set - { - if (mIntegralScroll != value) - { - mIntegralScroll = value; - Refresh(); - } - } - } - /// - /// Gets the collection of items contained in the image list view. - /// - [Category("Behavior"), Description("Gets the collection of items contained in the image list view.")] - [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)] - public ImageListViewItemCollection Items - { - get { return mItems; } - internal set - { - mItems = value; - Refresh(); - } - } - /// - /// Gets or sets whether multiple items can be selected. - /// - [Category("Behavior"), Description("Gets or sets whether multiple items can be selected."), DefaultValue(true)] - public bool MultiSelect { get; set; } - /// - /// Gets or sets the width of the left pane. - /// - [Category("Appearance"), Description("Gets or sets the width of the left pane."), DefaultValue(240)] - public int PaneWidth - { - get { return mPaneWidth; } - set - { - if (mPaneWidth != value) - { - if (mPaneWidth < 2) - mPaneWidth = 2; - mPaneWidth = value; - Refresh(); - } - } - } - /// - /// Gets or sets the rating image. - /// - [Category("Appearance"), Description("Gets or sets the rating image.")] - public Image RatingImage - { - get - { - if (mRatingImage == null) - return resources.GetObject("RatingImage") as Image; - else - return mRatingImage; - } - set - { - mRatingImageChanged = true; - mRatingImage = value; - Refresh(); - } - } - /// - /// Gets or sets the empty rating image. - /// - [Category("Appearance"), Description("Gets or sets the empty rating image.")] - public Image EmptyRatingImage - { - get - { - if (mEmptyRatingImage == null) - return resources.GetObject("EmptyRatingImage") as Image; - else - return mEmptyRatingImage; - } - set - { - mEmptyRatingImageChanged = true; - mEmptyRatingImage = value; - Refresh(); - } - } - /// - /// Gets or sets whether the control will retry loading thumbnails on an error. - /// - [Category("Behavior"), Description("Gets or sets whether the control will retry loading thumbnails on an error."), DefaultValue(true)] - public bool RetryOnError - { - get { return mRetryOnError; } - set - { - mRetryOnError = value; - if (thumbnailCache != null) - thumbnailCache.RetryOnError = mRetryOnError; - if (shellInfoCache != null) - shellInfoCache.RetryOnError = mRetryOnError; - if (metadataCache != null) - metadataCache.RetryOnError = mRetryOnError; - } - } - /// - /// Gets or sets whether the scrollbars should be shown. - /// - [Category("Appearance"), Description("Gets or sets whether the scrollbars should be shown."), DefaultValue(true)] - public bool ScrollBars - { - get { return mShowScrollBars; } - set - { - mShowScrollBars = value; - Refresh(); - } - } - /// - /// Gets the collection of selected items contained in the image list view. - /// - [Browsable(false), Category("Behavior"), Description("Gets the collection of selected items contained in the image list view.")] - [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)] - public ImageListViewSelectedItemCollection SelectedItems - { - get { return mSelectedItems; } - } - /// - /// Gets the collection of checked items contained in the image list view. - /// - [Browsable(false), Category("Behavior"), Description("Gets the collection of checked items contained in the image list view.")] - [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)] - public ImageListViewCheckedItemCollection CheckedItems - { - get { return mCheckedItems; } - } - /// - /// Gets or sets whether shell icons are displayed for non-image files. - /// - [Browsable(false), Category("Behavior"), Description("Gets or sets whether shell icons are displayed for non-image files."), DefaultValue(true)] - public bool ShellIconFallback { get; set; } - /// - /// Gets or sets whether to display the file icons. - /// - [Category("Appearance"), Description("Gets or sets whether to display the file icons."), DefaultValue(false)] - public bool ShowFileIcons - { - get { return mShowFileIcons; } - set - { - mShowFileIcons = value; - Refresh(); - } - } - /// - /// Gets or sets whether to display the item checkboxes. - /// - [Category("Appearance"), Description("Gets or sets whether to display the item checkboxes."), DefaultValue(false)] - public bool ShowCheckBoxes - { - get { return mShowCheckBoxes; } - set - { - mShowCheckBoxes = value; - Refresh(); - } - } - /// - /// Gets or sets alignment of file icons. - /// - [Category("Appearance"), Description("Gets or sets alignment of file icons."), DefaultValue(ContentAlignment.TopRight)] - public ContentAlignment IconAlignment - { - get { return mIconAlignment; } - set - { - mIconAlignment = value; - Refresh(); - } - } - /// - /// Gets or sets file icon padding. - /// - [Category("Appearance"), Description("Gets or sets file icon padding."), DefaultValue(typeof(Size), "2,2")] - public Size IconPadding - { - get { return mIconPadding; } - set - { - mIconPadding = value; - Refresh(); - } - } - /// - /// Gets or sets alignment of item checkboxes. - /// - [Category("Appearance"), Description("Gets or sets alignment of item checkboxes."), DefaultValue(ContentAlignment.BottomRight)] - public ContentAlignment CheckBoxAlignment - { - get { return mCheckBoxAlignment; } - set - { - mCheckBoxAlignment = value; - Refresh(); - } - } - /// - /// Gets or sets item checkbox padding. - /// - [Category("Appearance"), Description("Gets or sets item checkbox padding."), DefaultValue(typeof(Size), "2,2")] - public Size CheckBoxPadding - { - get { return mCheckBoxPadding; } - set - { - mCheckBoxPadding = value; - Refresh(); - } - } - /// - /// Gets or sets the index of the sort column. - /// - [Category("Appearance"), DefaultValue(0), Description("Gets or sets the index of the sort column.")] - public int SortColumn - { - get { return mSortColumn; } - set - { - if (value != mSortColumn) - { - mSortColumn = value; - Sort(); - } - } - } - /// - /// Gets or sets the sort order. - /// - [Category("Appearance"), DefaultValue(typeof(SortOrder), "None"), Description("Gets or sets the sort order.")] - public SortOrder SortOrder - { - get { return mSortOrder; } - set - { - if (value != mSortOrder) - { - mSortOrder = value; - Sort(); - } - } - } - /// - /// Gets or sets the index of the group column. - /// - [Category("Appearance"), DefaultValue(0), Description("Gets or sets the index of the group column.")] - public int GroupColumn - { - get { return mGroupColumn; } - set - { - if (value != mGroupColumn) - { - mGroupColumn = value; - Sort(); - } - } - } - /// - /// Gets or sets the group order. - /// - [Category("Appearance"), DefaultValue(typeof(SortOrder), "None"), Description("Gets or sets the group order.")] - public SortOrder GroupOrder - { - get { return mGroupOrder; } - set - { - if (value != mGroupOrder) - { - mGroupOrder = value; - Sort(); - } - } - } - /// - /// This property is not relevant for this class. - /// - [EditorBrowsable(EditorBrowsableState.Never), Browsable(false), Bindable(false), DefaultValue(null), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] - public override string Text { get; set; } - /// - /// Gets or sets the size of image thumbnails. - /// - [Category("Appearance"), Description("Gets or sets the size of image thumbnails."), DefaultValue(typeof(Size), "96,96")] - public Size ThumbnailSize - { - get { return mThumbnailSize; } - set - { - if (mThumbnailSize != value) - { - mThumbnailSize = value; - thumbnailCache.Rebuild(); - Refresh(); - } - } - } - /// - /// Gets or sets the embedded thumbnails extraction behavior. - /// - [Category("Behavior"), Description("Gets or sets the embedded thumbnails extraction behavior."), DefaultValue(typeof(UseEmbeddedThumbnails), "Auto")] - public UseEmbeddedThumbnails UseEmbeddedThumbnails - { - get { return mUseEmbeddedThumbnails; } - set - { - if (mUseEmbeddedThumbnails != value) - { - mUseEmbeddedThumbnails = value; - Refresh(); - } - } - } - /// - /// Gets or sets whether Windows Imaging Compomnent will be used. - /// - [Browsable(false), Category("Behavior"), Description("Gets or sets whether Windows Imaging Compomnent will be used."), DefaultValue(typeof(UseWIC), "Auto")] - public UseWIC UseWIC - { - get { return mUseWIC; } - set - { - if (mUseWIC != value) - { - mUseWIC = value; - Refresh(); - } - } - } - /// - /// Gets or sets the view mode of the image list view. - /// - [Category("Appearance"), Description("Gets or sets the view mode of the image list view."), DefaultValue(typeof(View), "Thumbnails")] - public View View - { - get { return mView; } - set - { - if (mView != value) - { - int current = layoutManager.FirstPartiallyVisible; - mView = value; - Refresh(); - EnsureVisible(current); - } - } - } - /// - /// Gets whether groups are displayed. - /// - [Browsable(false), Category("Appearance"), Description("Gets whether groups are displayed.")] - public bool GroupsVisible - { - get { return showGroups; } - } - - - /// - /// Gets or sets the scroll offset. - /// - internal Point ViewOffset - { - get { return mViewOffset; } - set { mViewOffset = value; } - } - /// - /// Gets the scroll orientation. - /// - internal ScrollOrientation ScrollOrientation - { - get { return ((mView == View.Gallery) ? ScrollOrientation.HorizontalScroll : ScrollOrientation.VerticalScroll); } - } - #endregion - - #region Custom Property Serializers - /// - /// Determines if the header font should be serialized. - /// - /// true if the designer should serialize - /// the property; otherwise false. - public bool ShouldSerializeHeaderFont() - { - using (Font font = new Font("Microsoft Sans Serif", 8.25f)) - { - return !mColumnHeaderFont.Equals(font); - } - } - /// - /// Resets the header font to its default value. - /// - public void ResetHeaderFont() - { - ColumnHeaderFont = new Font("Microsoft Sans Serif", 8.25f); - } - - /// - /// Determines if the colors should be serialized. - /// - /// true if the designer should serialize - /// the property; otherwise false. - public bool ShouldSerializeColors() - { - ImageListViewColor defaultColors = ImageListViewColor.Default; - return !mColors.Equals(defaultColors); - } - /// - /// Resets the colors to their default value. - /// - public void ResetColors() - { - Colors = ImageListViewColor.Default; - } - - /// - /// Determines if the default image should be serialized. - /// - /// true if the designer should serialize - /// the property; otherwise false. - public bool ShouldSerializeDefaultImage() - { - return mDefaultImageChanged; - } - /// - /// Resets the default image to its default value. - /// - public void ResetDefaultImage() - { - DefaultImage = resources.GetObject("DefaultImage") as Image; - mDefaultImageChanged = false; - } - - /// - /// Determines if the error image should be serialized. - /// - /// true if the designer should serialize - /// the property; otherwise false. - public bool ShouldSerializeErrorImage() - { - return mErrorImageChanged; - } - /// - /// Resets the error image to its default value. - /// - public void ResetErrorImage() - { - ErrorImage = resources.GetObject("ErrorImage") as Image; - mErrorImageChanged = false; - } - - /// - /// Determines if the rating image should be serialized. - /// - /// true if the designer should serialize - /// the property; otherwise false. - public bool ShouldSerializeRatingImage() - { - return mRatingImageChanged; - } - /// - /// Resets the rating image to its default value. - /// - public void ResetRatingImage() - { - RatingImage = resources.GetObject("RatingImage") as Image; - mRatingImageChanged = false; - } - - /// - /// Determines if the empty rating image should be serialized. - /// - /// true if the designer should serialize - /// the property; otherwise false. - public bool ShouldSerializeEmptyRatingImage() - { - return mEmptyRatingImageChanged; - } - /// - /// Resets the empty rating image to its default value. - /// - public void ResetEmptyRatingImage() - { - EmptyRatingImage = resources.GetObject("EmptyRatingImage") as Image; - mEmptyRatingImageChanged = false; - } - #endregion - - #region Constructor - /// - /// Initializes a new instance of the ImageListView class. - /// - public ImageListView() - { - // Renderer parameters - controlSuspended = false; - rendererSuspendCount = 0; - rendererNeedsPaint = true; - - mColors = ImageListViewColor.Default; - SetRenderer(new ImageListViewRenderer()); - - // Property defaults - AutoRotateThumbnails = true; - AllowCheckBoxClick = true; - AllowColumnClick = true; - AllowColumnResize = true; - AllowDrag = false; - AllowDuplicateFileNames = false; - AllowPaneResize = true; - mBorderStyle = BorderStyle.Fixed3D; - mCacheMode = CacheMode.OnDemand; - mCacheLimitAsItemCount = 0; - mCacheLimitAsMemory = 20 * 1024 * 1024; - mColumns = new ImageListViewColumnHeaderCollection(this); - resources = new ResourceManager("ImageGlass.ImageListView.ImageListViewResources", typeof(ImageListView).Assembly); - mDefaultImage = resources.GetObject("DefaultImage") as Image; - mErrorImage = resources.GetObject("ErrorImage") as Image; - mRatingImage = resources.GetObject("RatingImage") as Image; - mEmptyRatingImage = resources.GetObject("EmptyRatingImage") as Image; - GroupHeaderFont = new Font("Microsoft Sans Serif", 8.25f, FontStyle.Bold); - ColumnHeaderFont = new Font("Microsoft Sans Serif", 8.25f); - mIntegralScroll = false; - mItems = new ImageListViewItemCollection(this); - MultiSelect = true; - mPaneWidth = 240; - mRetryOnError = true; - mSelectedItems = new ImageListViewSelectedItemCollection(this); - mCheckedItems = new ImageListViewCheckedItemCollection(this); - mSortColumn = 0; - mGroupColumn = 0; - mSortOrder = SortOrder.None; - mGroupOrder = SortOrder.None; - SetStyle(ControlStyles.AllPaintingInWmPaint | ControlStyles.UserPaint | ControlStyles.Opaque | ControlStyles.Selectable | ControlStyles.UserMouse, true); - ScrollBars = true; - ShellIconFallback = true; - Size = new Size(120, 100); - mShowCheckBoxes = false; - mCheckBoxAlignment = ContentAlignment.BottomRight; - mCheckBoxPadding = new Size(2, 2); - mShowFileIcons = false; - mIconAlignment = ContentAlignment.TopRight; - mIconPadding = new Size(2, 2); - Text = string.Empty; - mThumbnailSize = new Size(96, 96); - mUseEmbeddedThumbnails = UseEmbeddedThumbnails.Auto; - mUseWIC = UseWIC.Auto; - mView = View.Thumbnails; - mViewOffset = new Point(0, 0); - mShowScrollBars = true; - mEnableKeyNavigation = true; - - // Child controls - hScrollBar = new HScrollBar(); - vScrollBar = new VScrollBar(); - hScrollBar.Visible = false; - vScrollBar.Visible = false; - hScrollBar.Scroll += hScrollBar_Scroll; - vScrollBar.Scroll += vScrollBar_Scroll; - Controls.Add(hScrollBar); - Controls.Add(vScrollBar); - - // Groups - groups = new ImageListViewGroupCollection(this); - showGroups = false; - - // Lazy refresh timer - lazyRefreshTimer = new System.Timers.Timer(); - lazyRefreshTimer.Interval = ImageListViewRenderer.LazyRefreshInterval; - lazyRefreshTimer.Enabled = false; - lazyRefreshTimer.Elapsed += lazyRefreshTimer_Tick; - lazyRefreshCallback = new RefreshDelegateInternal(Refresh); - - // Helpers - layoutManager = new ImageListViewLayoutManager(this); - navigationManager = new ImageListViewNavigationManager(this); - - // Cache nabagers - defaultAdaptor = new ImageListViewItemAdaptors.FileSystemAdaptor(); - thumbnailCache = new ImageListViewCacheThumbnail(this); - shellInfoCache = new ImageListViewCacheShellInfo(this); - metadataCache = new ImageListViewCacheMetadata(this); - - disposed = false; - } - #endregion - - #region Select/Check - /// - /// Marks all items as selected. - /// - public void SelectAll() - { - SuspendPaint(); - - foreach (ImageListViewItem item in Items) - item.mSelected = true; - - OnSelectionChangedInternal(); - - Refresh(); - ResumePaint(); - } - /// - /// Marks all items as unselected. - /// - public void ClearSelection() - { - SuspendPaint(); - mSelectedItems.Clear(); - Refresh(); - ResumePaint(); - } - /// - /// Reverses the selection state of all items. - /// - public void InvertSelection() - { - SuspendPaint(); - - foreach (ImageListViewItem item in Items) - item.mSelected = !item.mSelected; - - OnSelectionChangedInternal(); - - Refresh(); - ResumePaint(); - } - /// - /// Marks all items as checked. - /// - public void CheckAll() - { - SuspendPaint(); - - foreach (ImageListViewItem item in Items) - { - item.mChecked = true; - OnItemCheckBoxClickInternal(item); - } - - Refresh(); - ResumePaint(); - } - /// - /// Marks all items as unchecked. - /// - public void UncheckAll() - { - SuspendPaint(); - mCheckedItems.Clear(); - Refresh(); - ResumePaint(); - } - /// - /// Reverses the check state of all items. - /// - public void InvertCheckState() - { - SuspendPaint(); - - foreach (ImageListViewItem item in Items) - { - item.mChecked = !item.mChecked; - OnItemCheckBoxClickInternal(item); - } - - Refresh(); - ResumePaint(); - } - /// - /// Marks all items as enabled. - /// - public void EnableAll() - { - SuspendPaint(); - - foreach (ImageListViewItem item in Items) - item.mEnabled = true; - - Refresh(); - ResumePaint(); - } - /// - /// Marks all items as disabled. - /// - public void DisableAll() - { - SuspendPaint(); - - foreach (ImageListViewItem item in Items) - item.mEnabled = false; - - Refresh(); - ResumePaint(); - } - #endregion - - #region Instance Methods - /// - /// Clears the thumbnail cache. - /// - public void ClearThumbnailCache() - { - if (thumbnailCache != null) - { - thumbnailCache.Clear(); - if (CacheMode == CacheMode.Continuous) - { - foreach (ImageListViewItem item in mItems) - { - thumbnailCache.Add(item.Guid, item.Adaptor, item.VirtualItemKey, mThumbnailSize, mUseEmbeddedThumbnails, AutoRotateThumbnails, (mUseWIC == UseWIC.Auto || mUseWIC == UseWIC.ThumbnailsOnly)); - } - } - Refresh(); - } - } - /// - /// Temporarily suspends the layout logic for the control. - /// - public new void SuspendLayout() - { - if (controlSuspended) - return; - - controlSuspended = true; - base.SuspendLayout(); - SuspendPaint(); - } - /// - /// Resumes usual layout logic. - /// - public new void ResumeLayout() - { - ResumeLayout(false); - } - /// - /// Resumes usual layout logic, optionally forcing an immediate layout of pending layout requests. - /// - /// true to execute pending layout requests; otherwise, false. - public new void ResumeLayout(bool performLayout) - { - if (!controlSuspended) - return; - - controlSuspended = false; - base.ResumeLayout(performLayout); - if (performLayout) - Refresh(); - ResumePaint(); - } - /// - /// Sets the renderer for this instance. - /// - /// An to assign to the control. - /// true to keep current colors; otherwise false. - public void SetRenderer(ImageListViewRenderer renderer, bool keepColors) - { - if (renderer == null) - throw new ArgumentNullException("renderer"); - - ImageListViewRenderer oldRenderer = mRenderer; - - mRenderer = renderer; - mRenderer.ImageListView = this; - if (!keepColors) - { - ImageListViewColor[] preferredColors = mRenderer.PreferredColors; - if (preferredColors != null) - mColors = preferredColors[0]; - else - mColors = ImageListViewColor.Default; - } - - if (oldRenderer != null) - oldRenderer.Dispose(); - - if (layoutManager != null) - layoutManager.Update(true); - - Refresh(); - } - /// - /// Sets the renderer for this instance. - /// - /// An to assign to the control. - public void SetRenderer(ImageListViewRenderer renderer) - { - SetRenderer(renderer, false); - } - /// - /// Sorts the items. - /// - public void Sort() - { - mItems.Sort(); - Refresh(); - } - /// - /// Determines the image list view element under the specified coordinates. - /// - /// The client coordinates of the point to be tested. - /// Details of the hit test. - public void HitTest(Point pt, out HitInfo hitInfo) - { - if (View == View.Details && pt.Y <= mRenderer.MeasureColumnHeaderHeight()) - { - int i = 0; - int x = layoutManager.ColumnHeaderBounds.Left; - ImageListViewColumnHeader colIndex = null; - ImageListViewColumnHeader sepIndex = null; - if (AllowColumnClick || AllowColumnResize) - { - foreach (ImageListViewColumnHeader col in Columns.GetDisplayedColumns()) - { - // Over a column? - if (pt.X >= x && pt.X < x + col.Width + SeparatorSize / 2) - colIndex = col; - - // Over a colummn separator? - if (pt.X > x + col.Width - SeparatorSize / 2 && pt.X < x + col.Width + SeparatorSize / 2) - sepIndex = col; - - if (colIndex != null) - break; - x += col.Width; - i++; - } - } - hitInfo = new HitInfo(colIndex, sepIndex); - } - else if (View == View.Pane && pt.X <= mPaneWidth) - { - bool overBorder = (pt.X >= mPaneWidth - PaneBorderSize); - hitInfo = new HitInfo(overBorder); - } - else - { - if (showGroups) - { - foreach (ImageListViewGroup @group in groups) - { - if (@group.headerBounds.Contains(pt)) - { - hitInfo = new HitInfo(@group); - return; - } - } - } - - int itemIndex = -1; - bool checkBoxHit = false; - int subItemIndex = -1; - - if (showGroups) - { - foreach (ImageListViewGroup @group in groups) - { - if (@group.itemBounds.Contains(pt)) - { - // Normalize to group item area coordinates - pt.X -= @group.itemBounds.Left; - pt.Y -= @group.itemBounds.Top; - - if (pt.X > 0 && pt.Y > 0) - { - int col = pt.X / layoutManager.ItemSizeWithMargin.Width; - int row = pt.Y / layoutManager.ItemSizeWithMargin.Height; - - int index = @group.FirstItemIndex + row * @group.itemCols + col; - if (index >= 0 && index <= Items.Count - 1) - { - Rectangle bounds = layoutManager.GetItemBounds(index); - if (bounds.Contains(pt.X + @group.itemBounds.Left, pt.Y + @group.itemBounds.Top)) - itemIndex = index; - if (ShowCheckBoxes) - { - Rectangle checkBoxBounds = layoutManager.GetCheckBoxBounds(index); - if (checkBoxBounds.Contains(pt.X + @group.itemBounds.Left, pt.Y + @group.itemBounds.Top)) - checkBoxHit = true; - } - } - - // Calculate sub item index - if (itemIndex != -1 && View == View.Details) - { - int xc1 = layoutManager.ColumnHeaderBounds.Left; - int colIndex = 0; - foreach (ImageListViewColumnHeader column in mColumns.GetDisplayedColumns()) - { - int xc2 = xc1 + column.Width; - if (pt.X >= xc1 && pt.X < xc2) - { - subItemIndex = colIndex; - break; - } - colIndex++; - xc1 = xc2; - } - } - } - - break; - } - } - } - else - { - // Normalize to item area coordinates - pt.X -= layoutManager.ItemAreaBounds.Left; - pt.Y -= layoutManager.ItemAreaBounds.Top; - - if (pt.X > 0 && pt.Y > 0) - { - int col = (pt.X + mViewOffset.X) / layoutManager.ItemSizeWithMargin.Width; - int row = (pt.Y + mViewOffset.Y) / layoutManager.ItemSizeWithMargin.Height; - - if (ScrollOrientation == ScrollOrientation.HorizontalScroll || (ScrollOrientation == ScrollOrientation.VerticalScroll && col <= layoutManager.Cols)) - { - int index = row * layoutManager.Cols + col; - if (index >= 0 && index <= Items.Count - 1) - { - Rectangle bounds = layoutManager.GetItemBounds(index); - if (bounds.Contains(pt.X + layoutManager.ItemAreaBounds.Left, pt.Y + layoutManager.ItemAreaBounds.Top)) - itemIndex = index; - if (ShowCheckBoxes) - { - Rectangle checkBoxBounds = layoutManager.GetCheckBoxBounds(index); - if (checkBoxBounds.Contains(pt.X + layoutManager.ItemAreaBounds.Left, pt.Y + layoutManager.ItemAreaBounds.Top)) - checkBoxHit = true; - } - } - } - - // Calculate sub item index - if (itemIndex != -1 && View == View.Details) - { - int xc1 = layoutManager.ColumnHeaderBounds.Left; - int colIndex = 0; - foreach (ImageListViewColumnHeader column in mColumns.GetDisplayedColumns()) - { - int xc2 = xc1 + column.Width; - if (pt.X >= xc1 && pt.X < xc2) - { - subItemIndex = colIndex; - break; - } - colIndex++; - xc1 = xc2; - } - } - } - } - - hitInfo = new HitInfo(itemIndex, subItemIndex, checkBoxHit); - } - } - /// - /// Scrolls the image list view to ensure that the item with the specified - /// index is visible on the screen. - /// - /// The index of the item to make visible. - /// true if the item was made visible; otherwise false (item is already visible or the image list view is empty). - public bool EnsureVisible(int itemIndex) - { - if (Items.Count == 0 || itemIndex < 0 || itemIndex > Items.Count - 1) - return false; - - // Already visible? - Rectangle bounds = layoutManager.ItemAreaBounds; - Rectangle itemBounds = layoutManager.GetItemBounds(itemIndex); - if (bounds.Contains(itemBounds)) - return false; - - // Scroll to item - if (ScrollOrientation == ScrollOrientation.HorizontalScroll) - { - int delta = 0; - delta = bounds.Left - itemBounds.Left; - int newXOffset = mViewOffset.X - delta; - if (newXOffset > hScrollBar.Maximum - hScrollBar.LargeChange + 1) - newXOffset = hScrollBar.Maximum - hScrollBar.LargeChange + 1; - if (newXOffset < hScrollBar.Minimum) - newXOffset = hScrollBar.Minimum; - mViewOffset.X = newXOffset; - mViewOffset.Y = 0; - hScrollBar.Value = newXOffset; - vScrollBar.Value = 0; - } - else - { - int delta = 0; - delta = bounds.Top - itemBounds.Top; - int newYOffset = mViewOffset.Y - delta; - if (newYOffset > vScrollBar.Maximum - vScrollBar.LargeChange + 1) - newYOffset = vScrollBar.Maximum - vScrollBar.LargeChange + 1; - if (newYOffset < vScrollBar.Minimum) - newYOffset = vScrollBar.Minimum; - mViewOffset.X = 0; - mViewOffset.Y = newYOffset; - hScrollBar.Value = 0; - vScrollBar.Value = newYOffset; - } - - Refresh(); - return true; - } - /// - /// Determines whether the specified item is visible on the screen. - /// - /// The item to test. - /// An ItemVisibility value. - public ItemVisibility IsItemVisible(ImageListViewItem item) - { - return IsItemVisible(item.Index); - } - /// - /// Finds the first item that starts with the specified string. - /// - /// The text to search for. - /// - /// The zero-based index of the first item found; or -1 if no match is found. - /// - public int FindString(string s) - { - return FindString(s, 0); - } - /// - /// Finds the first item that starts with the specified string. - /// - /// The text to search for. - /// The zero-based index of the first - /// item to be searched. Set to zero to search from the - /// beginning of the control. - /// - /// The zero-based index of the first item found; or -1 if no match is found. - /// - public int FindString(string s, int startIndex) - { - for (int i = startIndex; i < mItems.Count; i++) - { - ImageListViewItem item = mItems[i]; - if (item.Text.StartsWith(s, StringComparison.InvariantCultureIgnoreCase)) - { - return item.Index; - } - } - - return -1; - } - #endregion - - #region Rendering Methods - /// - /// Refreshes the control. - /// - /// Forces a refresh even if the renderer is suspended. - /// Refreshes the control only if a set amount of time - /// has passed since the last refresh. - internal void Refresh(bool force, bool lazy) - { - if (force) - base.Refresh(); - else if (lazy) - { - rendererNeedsPaint = true; - lazyRefreshTimer.Start(); - } - else if (CanPaint()) - base.Refresh(); - else - rendererNeedsPaint = true; - } - /// - /// Redraws the owner control. - /// - /// If true, forces an immediate update, even if - /// the renderer is suspended by a SuspendPaint call. - private void Refresh(bool force) - { - Refresh(force, false); - } - /// - /// Redraws the owner control. - /// - private new void Refresh() - { - Refresh(false, false); - } - /// - /// Suspends painting until a matching ResumePaint call is made. - /// - private void SuspendPaint() - { - if (rendererSuspendCount == 0) - rendererNeedsPaint = false; - rendererSuspendCount++; - } - /// - /// Resumes painting. This call must be matched by a prior SuspendPaint call. - /// - private void ResumePaint() - { - System.Diagnostics.Debug.Assert(rendererSuspendCount > 0, "Suspend count does not match resume count.", "ResumePaint() must be matched by a prior SuspendPaint() call."); - - rendererSuspendCount--; - if (rendererNeedsPaint) - Refresh(); - } - /// - /// Determines if the control can be painted. - /// - private bool CanPaint() - { - if (mRenderer == null) - return false; - if (controlSuspended || rendererSuspendCount != 0) - return false; - else - return true; - } - #endregion - - #region Helper Methods - /// - /// Determines whether the specified item is visible on the screen. - /// - /// The Guid of the item to test. - /// true if the item is visible or partially visible; otherwise false. - internal bool IsItemVisible(Guid guid) - { - return layoutManager.IsItemVisible(guid); - } - /// - /// Determines whether the specified item is modified. - /// - /// The Guid of the item to test. - /// true if the item is modified; otherwise false. - internal bool IsItemDirty(Guid guid) - { - ImageListViewItem item = null; - if (mItems.TryGetValue(guid, out item)) - return item.isDirty; - - return false; - } - /// - /// Determines whether the specified item is visible on the screen. - /// - /// The index of the item to test. - /// An ItemVisibility value. - internal ItemVisibility IsItemVisible(int itemIndex) - { - if (mItems.Count == 0) - return ItemVisibility.NotVisible; - if (itemIndex < 0 || itemIndex > mItems.Count - 1) - return ItemVisibility.NotVisible; - - if (itemIndex < layoutManager.FirstPartiallyVisible || itemIndex > layoutManager.LastPartiallyVisible) - return ItemVisibility.NotVisible; - else if (itemIndex >= layoutManager.FirstVisible && itemIndex <= layoutManager.LastVisible) - return ItemVisibility.Visible; - else - return ItemVisibility.PartiallyVisible; - } - /// - /// Gets the guids of visible items. - /// - internal Dictionary GetVisibleItems() - { - Dictionary visible = new Dictionary(); - if (layoutManager.FirstPartiallyVisible != -1 && layoutManager.LastPartiallyVisible != -1) - { - int start = layoutManager.FirstPartiallyVisible; - int end = layoutManager.LastPartiallyVisible; - - start -= layoutManager.Cols * layoutManager.Rows; - end += layoutManager.Cols * layoutManager.Rows; - - start = Math.Min(mItems.Count - 1, Math.Max(0, start)); - end = Math.Min(mItems.Count - 1, Math.Max(0, end)); - - for (int i = start; i <= end; i++) - visible.Add(mItems[i].Guid, false); - } - return visible; - } - #endregion - - #region Event Handlers - /// - /// Handles the DragOver event. - /// - /// A that contains the event data. - protected override void OnDragOver(DragEventArgs e) - { - navigationManager.DragOver(e); - base.OnDragOver(e); - } - /// - /// Handles the DragEnter event. - /// - /// A that contains the event data. - protected override void OnDragEnter(DragEventArgs e) - { - navigationManager.DragEnter(e); - base.OnDragEnter(e); - } - /// - /// Handles the DragLeave event. - /// - /// An that contains the event data. - protected override void OnDragLeave(EventArgs e) - { - navigationManager.DragLeave(); - base.OnDragLeave(e); - } - - /// - /// Handles the DragDrop event. - /// - /// A that contains the event data. - protected override void OnDragDrop(DragEventArgs e) - { - navigationManager.DragDrop(e); - base.OnDragDrop(e); - } - /// - /// Handles the Scroll event of the vScrollBar control. - /// - /// The source of the event. - /// The instance containing the event data. - private void vScrollBar_Scroll(object sender, ScrollEventArgs e) - { - mViewOffset.Y = e.NewValue; - Refresh(); - } - /// - /// Handles the Scroll event of the hScrollBar control. - /// - /// The source of the event. - /// The instance containing the event data. - private void hScrollBar_Scroll(object sender, ScrollEventArgs e) - { - mViewOffset.X = e.NewValue; - Refresh(); - } - /// - /// Handles the Tick event of the lazyRefreshTimer control. - /// - /// The source of the event. - /// The instance containing the event data. - void lazyRefreshTimer_Tick(object sender, EventArgs e) - { - try - { - if (IsHandleCreated && !IsDisposed) - BeginInvoke(lazyRefreshCallback); - lazyRefreshTimer.Stop(); - } - finally - { - ; - } - } - /// - /// Handles the Resize event. - /// - /// An that contains the event data. - protected override void OnResize(EventArgs e) - { - base.OnResize(e); - - if (!disposed && mRenderer != null) - mRenderer.ClearBuffer(); - - if (hScrollBar != null && layoutManager != null) - layoutManager.Update(); - - Refresh(); - } - /// - /// Handles the Paint event. - /// - /// A that contains the event data. - protected override void OnPaint(PaintEventArgs e) - { - if (!disposed && mRenderer != null) - mRenderer.Render(e.Graphics); - rendererNeedsPaint = false; - } - /// - /// Handles the MouseDown event. - /// - /// A that contains the event data. - protected override void OnMouseDown(MouseEventArgs e) - { - // Capture focus if right clicked - if (!Focused && (e.Button & MouseButtons.Right) == MouseButtons.Right) - Focus(); - - navigationManager.MouseDown(e); - base.OnMouseDown(e); - } - /// - /// Handles the MouseUp event. - /// - /// A that contains the event data. - protected override void OnMouseUp(MouseEventArgs e) - { - navigationManager.MouseUp(e); - base.OnMouseUp(e); - } - /// - /// Handles the MouseMove event. - /// - /// A that contains the event data. - protected override void OnMouseMove(MouseEventArgs e) - { - navigationManager.MouseMove(e); - base.OnMouseMove(e); - } - /// - /// Handles the MouseWheel event. - /// - /// A that contains the event data. - protected override void OnMouseWheel(MouseEventArgs e) - { - SuspendPaint(); - - if (ScrollOrientation == ScrollOrientation.VerticalScroll) - { - int newYOffset = mViewOffset.Y - (e.Delta / SystemInformation.MouseWheelScrollDelta) * vScrollBar.SmallChange; - if (newYOffset > vScrollBar.Maximum - vScrollBar.LargeChange + 1) - newYOffset = vScrollBar.Maximum - vScrollBar.LargeChange + 1; - if (newYOffset < 0) - newYOffset = 0; - if (newYOffset < vScrollBar.Minimum) - newYOffset = vScrollBar.Minimum; - if (newYOffset > vScrollBar.Maximum) - newYOffset = vScrollBar.Maximum; - mViewOffset.Y = newYOffset; - vScrollBar.Value = newYOffset; - } - else - { - int newXOffset = mViewOffset.X - (e.Delta / SystemInformation.MouseWheelScrollDelta) * hScrollBar.SmallChange; - if (newXOffset > hScrollBar.Maximum - hScrollBar.LargeChange + 1) - newXOffset = hScrollBar.Maximum - hScrollBar.LargeChange + 1; - if (newXOffset < 0) - newXOffset = 0; - if (newXOffset < hScrollBar.Minimum) - newXOffset = hScrollBar.Minimum; - if (newXOffset > hScrollBar.Maximum) - newXOffset = hScrollBar.Maximum; - mViewOffset.X = newXOffset; - hScrollBar.Value = newXOffset; - } - - OnMouseMove(e); - Refresh(true); - ResumePaint(); - - base.OnMouseWheel(e); - } - /// - /// Handles the MouseLeave event. - /// - /// An that contains the event data. - protected override void OnMouseLeave(EventArgs e) - { - navigationManager.MouseLeave(); - base.OnMouseLeave(e); - } - /// - /// Handles the MouseDoubleClick event. - /// - /// An that contains the event data. - protected override void OnMouseDoubleClick(MouseEventArgs e) - { - navigationManager.MouseDoubleClick(e); - base.OnMouseDoubleClick(e); - } - /// - /// Handles the IsInputKey event. - /// - /// One of the values. - /// - /// true if the specified key is a regular input key; otherwise, false. - /// - protected override bool IsInputKey(Keys keyData) - { - if ((keyData & Keys.Left) == Keys.Left || (keyData & Keys.Right) == Keys.Right || (keyData & Keys.Up) == Keys.Up || (keyData & Keys.Down) == Keys.Down) - return true; - else - return base.IsInputKey(keyData); - } - /// - /// Handles the KeyDown event. - /// - /// A that contains the event data. - protected override void OnKeyDown(KeyEventArgs e) - { - navigationManager.KeyDown(e); - base.OnKeyDown(e); - } - /// - /// Handles the KeyUp event. - /// - /// A that contains the event data. - protected override void OnKeyUp(KeyEventArgs e) - { - navigationManager.KeyUp(e); - base.OnKeyUp(e); - } - /// - /// Handles the GotFocus event. - /// - /// An that contains the event data. - protected override void OnGotFocus(EventArgs e) - { - base.OnGotFocus(e); - Refresh(); - } - /// - /// Handles the LostFocus event. - /// - /// An that contains the event data. - protected override void OnLostFocus(EventArgs e) - { - base.OnLostFocus(e); - Refresh(); - } - /// - /// Releases the unmanaged resources used by the control and its child controls - /// and optionally releases the managed resources. - /// - /// true to release both managed and unmanaged resources; - /// false to release only unmanaged resources. - protected override void Dispose(bool disposing) - { - if (!disposed) - { - if (disposing) - { - // Events - hScrollBar.Scroll -= hScrollBar_Scroll; - vScrollBar.Scroll -= vScrollBar_Scroll; - lazyRefreshTimer.Elapsed -= lazyRefreshTimer_Tick; - - // Resources - if (mDefaultImage != null) - mDefaultImage.Dispose(); - if (mErrorImage != null) - mErrorImage.Dispose(); - if (mRatingImage != null) - mRatingImage.Dispose(); - if (mEmptyRatingImage != null) - mEmptyRatingImage.Dispose(); - - // Child controls - if (hScrollBar != null && hScrollBar.IsHandleCreated && !hScrollBar.IsDisposed) - hScrollBar.Dispose(); - if (vScrollBar != null && vScrollBar.IsHandleCreated && !vScrollBar.IsDisposed) - vScrollBar.Dispose(); - if (lazyRefreshTimer != null) - lazyRefreshTimer.Dispose(); - - // internal classes - defaultAdaptor.Dispose(); - thumbnailCache.Dispose(); - shellInfoCache.Dispose(); - metadataCache.Dispose(); - navigationManager.Dispose(); - if (mRenderer != null) - mRenderer.Dispose(); - } - - disposed = true; - } - - if (IsHandleCreated && !IsDisposed && !InvokeRequired) - base.Dispose(disposing); - } - #endregion - - #region Virtual Functions - /// - /// Raises the CacheError event. - /// - /// A CacheErrorEventArgs that contains event data. - protected virtual void OnCacheError(CacheErrorEventArgs e) - { - if (CacheError != null) - CacheError(this, e); - } - /// - /// Raises the DropFiles event. - /// - /// A DropFileEventArgs that contains event data. - protected virtual void OnDropFiles(DropFileEventArgs e) - { - if (DropFiles != null) - DropFiles(this, e); - - if (e.Cancel) - return; - - int index = e.Index; - int firstItemIndex = 0; - mSelectedItems.Clear(false); - - // Add items - bool first = true; - foreach (string filename in e.FileNames) - { - ImageListViewItem item = new ImageListViewItem(filename); - if (first || MultiSelect) - { - item.mSelected = true; - first = false; - } - - bool inserted = mItems.InsertInternal(index, item, defaultAdaptor); - - if (firstItemIndex == 0) - firstItemIndex = item.Index; - - if (inserted) - index++; - } - - EnsureVisible(firstItemIndex); - OnSelectionChangedInternal(); - - } - /// - /// Raises the ColumnWidthChanged event. - /// - /// A ColumnEventArgs that contains event data. - protected virtual void OnColumnWidthChanged(ColumnEventArgs e) - { - if (ColumnWidthChanged != null) - ColumnWidthChanged(this, e); - } - /// - /// Raises the ColumnClick event. - /// - /// A ColumnClickEventArgs that contains event data. - protected virtual void OnColumnClick(ColumnClickEventArgs e) - { - if (ColumnClick != null) - ColumnClick(this, e); - } - /// - /// Raises the ColumnHover event. - /// - /// A ColumnClickEventArgs that contains event data. - protected virtual void OnColumnHover(ColumnHoverEventArgs e) - { - if (ColumnHover != null) - ColumnHover(this, e); - } - /// - /// Raises the ItemClick event. - /// - /// A ItemClickEventArgs that contains event data. - protected virtual void OnItemClick(ItemClickEventArgs e) - { - if (ItemClick != null) - ItemClick(this, e); - } - /// - /// Raises the ItemCheckBoxClick event. - /// - /// A ItemEventArgs that contains event data. - protected virtual void OnItemCheckBoxClick(ItemEventArgs e) - { - if (ItemCheckBoxClick != null) - ItemCheckBoxClick(this, e); - } - /// - /// Raises the ItemCheckBoxClick event. - /// - /// The checked item. - internal virtual void OnItemCheckBoxClickInternal(ImageListViewItem item) - { - OnItemCheckBoxClick(new ItemEventArgs(item)); - } - /// - /// Raises the ItemHover event. - /// - /// A ItemClickEventArgs that contains event data. - protected virtual void OnItemHover(ItemHoverEventArgs e) - { - if (ItemHover != null) - ItemHover(this, e); - } - /// - /// Raises the ItemDoubleClick event. - /// - /// A ItemClickEventArgs that contains event data. - protected virtual void OnItemDoubleClick(ItemClickEventArgs e) - { - if (ItemDoubleClick != null) - ItemDoubleClick(this, e); - } - /// - /// Raises the SelectionChanged event. - /// - /// A EventArgs that contains event data. - protected virtual void OnSelectionChanged(EventArgs e) - { - if (SelectionChanged != null) - SelectionChanged(this, e); - } - /// - /// Raises the SelectionChanged event. - /// - internal void OnSelectionChangedInternal() - { - OnSelectionChanged(new EventArgs()); - } - /// - /// Raises the ThumbnailCached event. - /// - /// A ThumbnailCachedEventArgs that contains event data. - protected virtual void OnThumbnailCached(ThumbnailCachedEventArgs e) - { - if (ThumbnailCached != null) - ThumbnailCached(this, e); - } - /// - /// Raises the PaneReszied event. - /// - /// A PaneResizedEventArgs that contains event data. - protected virtual void OnPaneResized(PaneResizedEventArgs e) - { - if (PaneResized != null) - PaneResized(this, e); - } - /// - /// Raises the PaneResizing event. - /// - /// A PaneResizingEventArgs that contains event data. - protected virtual void OnPaneResizing(PaneResizingEventArgs e) - { - if (PaneResizing != null) - PaneResizing(this, e); - } - /// - /// Raises the CacheError event. - /// This method is invoked from the thumbnail thread. - /// - /// The Guid of the ImageListViewItem that is associated with this error. - /// This parameter can be null. - /// The error that occurred during an asynchronous operation. - /// The thread raising the error. - internal void OnCacheErrorInternal(Guid guid, Exception error, CacheThread cacheThread) - { - ImageListViewItem item = null; - mItems.TryGetValue(guid, out item); - OnCacheError(new CacheErrorEventArgs(item, error, cacheThread)); - } - /// - /// Raises the ThumbnailCached event. - /// This method is invoked from the thumbnail thread. - /// - /// The guid of the item whose thumbnail is cached. - /// The cached image. - /// Requested thumbnail size. - /// true if the cached image is a thumbnail image; otherwise false - /// if the image is a large image for gallery or pane views. - internal void OnThumbnailCachedInternal(Guid guid, Image thumbnail, Size size, bool thumbnailImage) - { - ImageListViewItem item = null; - if (mItems.TryGetValue(guid, out item)) - OnThumbnailCached(new ThumbnailCachedEventArgs(item, thumbnail, size, thumbnailImage)); - } - /// - /// Updates item details. - /// This method is invoked from the item cache thread. - /// - /// Item guid. - /// Array of item details. - internal void UpdateItemDetailsInternal(Guid guid, Utility.Tuple[] details) - { - ImageListViewItem item = null; - if (mItems.TryGetValue(guid, out item)) - item.UpdateDetailsInternal(details); - } - /// - /// Raises the ThumbnailCaching event. - /// This method is invoked from the thumbnail thread. - /// - /// The guid of the item whose thumbnail is cached. - /// Requested thumbnail size. - internal void OnThumbnailCachingInternal(Guid guid, Size size) - { - ImageListViewItem item = null; - if (mItems.TryGetValue(guid, out item)) - OnThumbnailCaching(new ThumbnailCachingEventArgs(item, size)); - } - /// - /// Raises the ThumbnailCaching event. - /// - /// A ThumbnailCachingEventArgs that contains event data. - protected virtual void OnThumbnailCaching(ThumbnailCachingEventArgs e) - { - if (ThumbnailCaching != null) - ThumbnailCaching(this, e); - } - /// - /// Raises the ItemCollectionChanged event. - /// - /// A ItemCollectionChangedEventArgs that contains event data. - protected virtual void OnItemCollectionChanged(ItemCollectionChangedEventArgs e) - { - if (ItemCollectionChanged != null) - ItemCollectionChanged(this, e); - } - #endregion - - #region Public Events - /// - /// Occurs when an error occurs during an asynchronous cache operation. - /// - [Category("Behavior"), Browsable(true), Description("Occurs when an error occurs during an asynchronous cache operation.")] - public event CacheErrorEventHandler CacheError; - /// - /// Occurs after the user drops files on to the control. - /// - [Category("Drag Drop"), Browsable(true), Description("Occurs after the user drops files on to the control.")] - public event DropFilesEventHandler DropFiles; - /// - /// Occurs after the user successfully resized a column header. - /// - [Category("Action"), Browsable(true), Description("Occurs after the user successfully resized a column header.")] - public event ColumnWidthChangedEventHandler ColumnWidthChanged; - /// - /// Occurs when the user clicks a column header. - /// - [Category("Action"), Browsable(true), Description("Occurs when the user clicks a column header.")] - public event ColumnClickEventHandler ColumnClick; - /// - /// Occurs when the user moves the mouse over (and out of) a column header. - /// - [Category("Action"), Browsable(true), Description("Occurs when the user moves the mouse over (and out of) a column header.")] - public event ColumnHoverEventHandler ColumnHover; - /// - /// Occurs when the user clicks an item. - /// - [Category("Action"), Browsable(true), Description("Occurs when the user clicks an item.")] - public event ItemClickEventHandler ItemClick; - /// - /// Occurs when the user clicks an item checkbox. - /// - [Category("Action"), Browsable(true), Description("Occurs when the user clicks an item checkbox.")] - public event ItemCheckBoxClickEventHandler ItemCheckBoxClick; - /// - /// Occurs when the user moves the mouse over (and out of) an item. - /// - [Category("Action"), Browsable(true), Description("Occurs when the user moves the mouse over (and out of) an item.")] - public event ItemHoverEventHandler ItemHover; - /// - /// Occurs when the user double-clicks an item. - /// - [Category("Action"), Browsable(true), Description("Occurs when the user double-clicks an item.")] - public event ItemDoubleClickEventHandler ItemDoubleClick; - /// - /// Occurs when the selected items collection changes. - /// - [Category("Behavior"), Browsable(true), Description("Occurs when the selected items collection changes.")] - public event EventHandler SelectionChanged; - /// - /// Occurs after an item thumbnail is cached. - /// - [Category("Behavior"), Browsable(true), Description("Occurs after an item thumbnail is cached.")] - public event ThumbnailCachedEventHandler ThumbnailCached; - /// - /// Occurs before an item thumbnail is cached. - /// - [Category("Behavior"), Browsable(true), Description("Occurs before an item thumbnail is cached.")] - public event ThumbnailCachingEventHandler ThumbnailCaching; - /// - /// Occurs after the item collection is changed. - /// - [Category("Behavior"), Browsable(true), Description("Occurs after the item collection is changed.")] - public event ItemCollectionChangedEventHandler ItemCollectionChanged; - /// - /// Occurs after the pane is resized. - /// - [Category("Action"), Browsable(true), Description("Occurs after the pane is resized.")] - public event PaneResizedEventHandler PaneResized; - /// - /// Occurs while the pane is being resized. - /// - [Category("Action"), Browsable(true), Description("Occurs while the pane is being resized.")] - public event PaneResizingEventHandler PaneResizing; - #endregion - } -} diff --git a/Source/Components/ImageGlass.ImageListView/ImageListViewCacheMetadata.cs b/Source/Components/ImageGlass.ImageListView/ImageListViewCacheMetadata.cs deleted file mode 100644 index 30c556fac..000000000 --- a/Source/Components/ImageGlass.ImageListView/ImageListViewCacheMetadata.cs +++ /dev/null @@ -1,376 +0,0 @@ -// ImageListView - A listview control for image files -// Copyright (C) 2009 Ozgur Ozcitak -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// Ozgur Ozcitak (ozcitak@yahoo.com) - -// Dictionary<> is not thread safe if modified while being read. Launching -// ImageGlass with a filename argument in a directory with many files was -// throwing an IndexOutOfRange exception. Using a ConcrrentDictionary -// prevents that. (dnadle) - -using System; -using System.Collections.Generic; -using System.Collections.Concurrent; -using System.Threading; - -namespace ImageGlass.ImageListView -{ - /// - /// Represents the cache manager responsible for asynchronously loading - /// item metadata. - /// - internal class ImageListViewCacheMetadata : IDisposable - { - #region Member Variables - private QueuedBackgroundWorker bw; - private SynchronizationContext context; - private SendOrPostCallback checkProcessingCallback; - - private ImageListView mImageListView; - - private Dictionary editCache; - private ConcurrentDictionary processing; - private Dictionary removedItems; - - private bool disposed; - #endregion - - #region CacheRequest Class - /// - /// Represents a cache request. - /// - private class CacheRequest - { - /// - /// Gets the item guid. - /// - public Guid Guid { get; private set; } - /// - /// Gets the adaptor of this item. - /// - public ImageListView.ImageListViewItemAdaptor Adaptor { get; private set; } - /// - /// Gets the virtual item key. - /// - public object VirtualItemKey { get; private set; } - /// - /// Whether to use the Windows Imaging Component. - /// - public bool UseWIC { get; private set; } - - /// - /// Initializes a new instance of the class. - /// - /// The guid of the item. - /// The adaptor of this item. - /// The virtual item key of this item. - /// Whether to use the Windows Imaging Component. - public CacheRequest (Guid guid, ImageListView.ImageListViewItemAdaptor adaptor, object virtualItemKey, bool useWIC) - { - Guid = guid; - Adaptor = adaptor; - VirtualItemKey = virtualItemKey; - UseWIC = useWIC; - } - } - #endregion - - #region CanContinueProcessingEventArgs - /// - /// Represents the event arguments for the callback. - /// - private class CanContinueProcessingEventArgs : EventArgs - { - /// - /// Gets the cache request. - /// - public CacheRequest Request { get; private set; } - /// - /// Gets whether this item should be processed. - /// - public bool ContinueProcessing { get; set; } - - /// - /// Initializes a new instance of the class. - /// - /// The cache request. - public CanContinueProcessingEventArgs (CacheRequest request) - { - Request = request; - ContinueProcessing = true; - } - } - #endregion - - #region Properties - /// - /// Determines whether the cache manager retries loading items on errors. - /// - public bool RetryOnError { get; internal set; } - #endregion - - #region Constructor - /// - /// Initializes a new instance of the class. - /// - /// The owner control. - public ImageListViewCacheMetadata (ImageListView owner) - { - context = null; - bw = new QueuedBackgroundWorker (); - bw.IsBackground = true; - bw.DoWork += bw_DoWork; - bw.RunWorkerCompleted += bw_RunWorkerCompleted; - - checkProcessingCallback = new SendOrPostCallback (CanContinueProcessing); - - mImageListView = owner; - RetryOnError = false; - - editCache = new Dictionary (); - processing = new ConcurrentDictionary (); - removedItems = new Dictionary (); - - disposed = false; - } - #endregion - - #region Context Callbacks - /// - /// Determines if the item should be processed. - /// - /// The to check. - /// true if the item should be processed; otherwise false. - private bool OnCanContinueProcessing (CacheRequest item) - { - CanContinueProcessingEventArgs arg = new CanContinueProcessingEventArgs (item); - context.Send (checkProcessingCallback, arg); - return arg.ContinueProcessing; - } - /// - /// Determines if the item should be processed. - /// - /// The event argument. - /// true if the item should be processed; otherwise false. - private void CanContinueProcessing (object argument) - { - CanContinueProcessingEventArgs arg = argument as CanContinueProcessingEventArgs; - CacheRequest request = arg.Request; - bool canProcess = true; - - // Is it in the edit cache? - if (canProcess) { - if (editCache.ContainsKey (request.Guid)) - canProcess = false; - } - - // Was the item was updated by the UI thread? - if (canProcess) { - if (mImageListView != null && !mImageListView.IsItemDirty (request.Guid)) - canProcess = false; - } - - arg.ContinueProcessing = canProcess; - } - #endregion - - #region QueuedBackgroundWorker Events - /// - /// Handles the RunWorkerCompleted event of the queued background worker. - /// - /// The source of the event. - /// The - /// instance containing the event data. - void bw_RunWorkerCompleted (object sender, QueuedWorkerCompletedEventArgs e) - { - CacheRequest request = e.UserState as CacheRequest; - - // We are done processing - bool removedValue; - var removed = processing.TryRemove (request.Guid, out removedValue); - if (!removed && mImageListView != null) - { - var ex = new InvalidOperationException("Image already processed"); - mImageListView.OnCacheErrorInternal(request.Guid, e.Error, CacheThread.Details); - return; - } - - // Do not process the result if the cache operation - // was cancelled. - if (e.Cancelled) - return; - - // Get result - Utility.Tuple[] details = (Utility.Tuple[])e.Result; - if (details != null && mImageListView != null) - { - mImageListView.UpdateItemDetailsInternal(request.Guid, details); - } - - // Refresh the control lazily - if (mImageListView != null && mImageListView.IsItemVisible (request.Guid)) - mImageListView.Refresh (false, true); - - // Raise the CacheError event - if (e.Error != null && mImageListView != null) - mImageListView.OnCacheErrorInternal (request.Guid, e.Error, CacheThread.Details); - } - /// - /// [IG_CHANGE] Handles the DoWork event of the queued background worker. - /// - /// The source of the event. - /// The instance - /// containing the event data. - void bw_DoWork (object sender, QueuedWorkerDoWorkEventArgs e) - { - CacheRequest request = e.Argument as CacheRequest; - - // Should we continue processing this item? - // The callback checks the following and returns false if - // the item is in the edit cache -OR- - // the item was fetched by the UI thread before. - if (!OnCanContinueProcessing (request)) { - e.Cancel = true; - return; - } - - // Get item details - // Note: - // If we use WIC, it will cause Memory Leak issue: https://github.com/d2phap/ImageGlass/issues/119 - e.Result = request.Adaptor.GetDetails(request.VirtualItemKey, false);// request.UseWIC); - } - #endregion - - #region Instance Methods - /// - /// Pauses the cache threads. - /// - public void Pause () - { - bw.Pause (); - } - /// - /// Resumes the cache threads. - /// - public void Resume () - { - bw.Resume (); - } - /// - /// Starts editing an item. While items are edited, - /// the cache thread will not work on them to prevent collisions. - /// - /// The guid representing the item - public void BeginItemEdit (Guid guid) - { - if (!editCache.ContainsKey (guid)) - editCache.Add (guid, false); - } - /// - /// Ends editing an item. After this call, item - /// image will be continued to be fetched by the thread. - /// - /// The guid representing the item. - public void EndItemEdit (Guid guid) - { - editCache.Remove (guid); - } - /// - /// Removes the given item from the cache. - /// - /// The guid of the item to remove. - public void Remove (Guid guid) - { - if (!removedItems.ContainsKey (guid)) - removedItems.Add (guid, false); - } - /// - /// Clears the cache. - /// - public void Clear () - { - bw.CancelAsync (); - // [IG_CHANGE] Don't keep the fully allocated dict. from before, create an empty one - processing = new ConcurrentDictionary(); - } - /// - /// Adds the item to the cache queue. - /// - /// Item guid. - /// The adaptor for this item. - /// The virtual item key. - /// Whether to use the Windows Imaging Component. - public void Add (Guid guid, ImageListView.ImageListViewItemAdaptor adaptor, object virtualItemKey, bool useWIC) - { - // Add to cache queue - RunWorker (new CacheRequest (guid, adaptor, virtualItemKey, useWIC)); - } - #endregion - - #region RunWorker - /// - /// Pushes the given item to the worker queue. - /// [IG_CHANGE] Issue #359: dictionary is not thread-safe, Add could crash; catch exceptions - /// - /// The cache item. - private void RunWorker (CacheRequest item) - { - // Get the current synchronization context - if (context == null) - context = SynchronizationContext.Current; - - // Already being processed? - var added = processing.TryAdd (item.Guid, false); - if (!added) - return; - - // Add the item to the queue for processing - bw.RunWorkerAsync (item); - } - - #endregion - - #region Dispose - /// - /// Performs application-defined tasks associated with freeing, - /// releasing, or resetting unmanaged resources. - /// - public void Dispose () - { - if (!disposed) { - bw.DoWork -= bw_DoWork; - bw.RunWorkerCompleted -= bw_RunWorkerCompleted; - - bw.Dispose (); - - disposed = true; - - GC.SuppressFinalize (this); - } - } - #if DEBUG - /// - /// Releases unmanaged resources and performs other cleanup operations before the - /// ImageListViewCacheManager is reclaimed by garbage collection. - /// - ~ImageListViewCacheMetadata () - { - System.Diagnostics.Debug.Print ("Finalizer of {0} called.", GetType ()); - Dispose (); - } - #endif - #endregion - } -} diff --git a/Source/Components/ImageGlass.ImageListView/ImageListViewCacheShellInfo.cs b/Source/Components/ImageGlass.ImageListView/ImageListViewCacheShellInfo.cs deleted file mode 100644 index cbab138b4..000000000 --- a/Source/Components/ImageGlass.ImageListView/ImageListViewCacheShellInfo.cs +++ /dev/null @@ -1,472 +0,0 @@ -// ImageListView - A listview control for image files -// Copyright (C) 2009 Ozgur Ozcitak -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// Ozgur Ozcitak (ozcitak@yahoo.com) - -// Dictionary<> is not thread safe if modified while being read. - -using System; -using System.Collections.Generic; -using System.Collections.Concurrent; -using System.Drawing; -using System.Threading; - -namespace ImageGlass.ImageListView -{ - /// - /// Represents the cache manager responsible for asynchronously loading - /// shell info. - /// - internal class ImageListViewCacheShellInfo : IDisposable - { - #region Member Variables - private QueuedBackgroundWorker bw; - private SynchronizationContext context; - private SendOrPostCallback checkProcessingCallback; - - private ImageListView mImageListView; - - private Dictionary shellCache; - private ConcurrentDictionary processing; - - private bool disposed; - #endregion - - #region CacheItem Class - /// - /// Represents an item in the cache. - /// - private class CacheItem : IDisposable - { - private bool disposed; - - /// - /// Gets the file extension. - /// - public string Extension { get; private set; } - /// - /// Gets the small shell icon. - /// - public Image SmallIcon { get; private set; } - /// - /// Gets the large shell icon. - /// - public Image LargeIcon { get; private set; } - /// - /// Gets the shell file type. - /// - public string FileType { get; private set; } - /// - /// Gets or sets the state of the cache item. - /// - public CacheState State { get; set; } - - /// - /// Initializes a new instance of the class. - /// - /// The file extension. - /// The small shell icon. - /// The large shell icon. - /// The shell file type. - /// The cache state of the item. - public CacheItem (string extension, Image smallIcon, Image largeIcon, string filetype, CacheState state) - { - Extension = extension; - SmallIcon = smallIcon; - LargeIcon = largeIcon; - FileType = filetype; - State = state; - disposed = false; - } - - /// - /// Performs application-defined tasks associated with - /// freeing, releasing, or resetting unmanaged resources. - /// - public void Dispose () - { - if (!disposed) { - if (SmallIcon != null) { - SmallIcon.Dispose (); - SmallIcon = null; - } - if (LargeIcon != null) { - LargeIcon.Dispose (); - LargeIcon = null; - } - - disposed = true; - GC.SuppressFinalize (this); - } - } - #if DEBUG - /// - /// Releases unmanaged resources and performs other cleanup operations before the - /// CacheItem is reclaimed by garbage collection. - /// - ~CacheItem () - { - if (SmallIcon != null || LargeIcon != null) - System.Diagnostics.Debug.Print ("Finalizer of {0} called for non-empty cache item.", GetType ()); - Dispose (); - } - #endif - } - #endregion - - #region CanContinueProcessingEventArgs - /// - /// Represents the event arguments for the callback. - /// - private class CanContinueProcessingEventArgs : EventArgs - { - /// - /// Gets the file extension of the request. - /// - public string Extension { get; private set; } - /// - /// Gets whether this item should be processed. - /// - public bool ContinueProcessing { get; set; } - - /// - /// Initializes a new instance of the class. - /// - /// The file extension of the request. - public CanContinueProcessingEventArgs (string extension) - { - Extension = extension; - ContinueProcessing = true; - } - } - #endregion - - #region Properties - /// - /// Determines whether the cache manager retries loading items on errors. - /// - public bool RetryOnError { get; internal set; } - #endregion - - #region Constructor - /// - /// Initializes a new instance of the class. - /// - /// The owner control. - public ImageListViewCacheShellInfo (ImageListView owner) - { - context = null; - bw = new QueuedBackgroundWorker (); - bw.Threads = 1; - bw.IsBackground = true; - bw.DoWork += bw_DoWork; - bw.RunWorkerCompleted += bw_RunWorkerCompleted; - - checkProcessingCallback = new SendOrPostCallback (CanContinueProcessing); - - mImageListView = owner; - RetryOnError = false; - - shellCache = new Dictionary (); - processing = new ConcurrentDictionary (); - - disposed = false; - } - #endregion - - #region Context Callbacks - /// - /// Determines if the item should be processed. - /// - /// The file extension to check. - /// true if the item should be processed; otherwise false. - private bool OnCanContinueProcessing (string extension) - { - CanContinueProcessingEventArgs arg = new CanContinueProcessingEventArgs (extension); - context.Send (checkProcessingCallback, arg); - return arg.ContinueProcessing; - } - /// - /// Determines if the item should be processed. - /// - /// The event argument. - /// true if the item should be processed; otherwise false. - private void CanContinueProcessing (object argument) - { - CanContinueProcessingEventArgs arg = argument as CanContinueProcessingEventArgs; - bool canProcess = true; - - // Is it already cached? - CacheItem existing; - if (shellCache.TryGetValue (arg.Extension, out existing)) { - if (existing.SmallIcon != null && existing.LargeIcon != null) - canProcess = false; - } - - arg.ContinueProcessing = canProcess; - } - #endregion - - #region QueuedBackgroundWorker Events - /// - /// Handles the RunWorkerCompleted event of the queued background worker. - /// [IG_CHANGE] Issue #359: thread collision? leftover context? failed to check null - /// - /// The source of the event. - /// The - /// instance containing the event data. - void bw_RunWorkerCompleted (object sender, QueuedWorkerCompletedEventArgs e) - { - CacheItem result = e.Result as CacheItem; - - // Add to cache - if (result != null) { - // We are done processing - bool removedValue; - var removed = processing.TryRemove (result.Extension, out removedValue); - if (!removed) - { - throw new InvalidOperationException("processing.TryRemove failed"); - } - - CacheItem existing = null; - if (shellCache.TryGetValue (result.Extension, out existing)) { - existing.Dispose (); - shellCache.Remove (result.Extension); - } - shellCache.Add (result.Extension, result); - } - - // Refresh the control lazily - if (result != null && mImageListView != null) - mImageListView.Refresh (false, true); - } - /// - /// Handles the DoWork event of the queued background worker. - /// - /// The source of the event. - /// The instance - /// containing the event data. - void bw_DoWork (object sender, QueuedWorkerDoWorkEventArgs e) - { - string extension = e.Argument as string; - - // Should we continue processing this item? - // The callback checks if the item is already cached. - if (!OnCanContinueProcessing (extension)) { - e.Cancel = true; - return; - } - - // Read shell info - ShellInfoExtractor info = ShellInfoExtractor.FromFile (extension); - - // Return the info - CacheItem result = null; - if ((info.SmallIcon == null || info.LargeIcon == null) && !RetryOnError) - result = new CacheItem (extension, info.SmallIcon, info.LargeIcon, info.FileType, CacheState.Error); - else - result = new CacheItem (extension, info.SmallIcon, info.LargeIcon, info.FileType, CacheState.Cached); - - e.Result = result; - } - #endregion - - #region Instance Methods - /// - /// Pauses the cache threads. - /// - public void Pause () - { - bw.Pause (); - } - /// - /// Resumes the cache threads. - /// - public void Resume () - { - bw.Resume (); - } - /// - /// Gets the cache state of the specified item. - /// - /// File extension. - public CacheState GetCacheState (string extension) - { - if (string.IsNullOrEmpty (extension)) - throw new ArgumentException ("extension cannot be null", "extension"); - - CacheItem item = null; - if (shellCache.TryGetValue (extension, out item)) - return item.State; - - return CacheState.Unknown; - } - /// - /// Rebuilds the cache. - /// Old items will be kept until they are overwritten - /// by new ones. - /// - public void Rebuild () - { - foreach (CacheItem item in shellCache.Values) - item.State = CacheState.Unknown; - } - /// - /// Clears the cache. - /// - public void Clear () - { - foreach (CacheItem item in shellCache.Values) - item.Dispose (); - shellCache.Clear (); - processing.Clear (); - } - /// - /// Removes the given item from the cache. - /// - /// File extension. - public void Remove (string extension) - { - if (string.IsNullOrEmpty (extension)) - throw new ArgumentException ("extension cannot be null", "extension"); - - CacheItem item = null; - if (shellCache.TryGetValue (extension, out item)) { - item.Dispose (); - shellCache.Remove (extension); - } - } - /// - /// Adds the item to the cache queue. - /// - /// File extension. - public void Add (string extension) - { - if (string.IsNullOrEmpty (extension)) - throw new ArgumentException ("extension cannot be null", "extension"); - - // Already cached? - CacheItem item = null; - if (shellCache.TryGetValue (extension, out item)) - return; - - // Add to cache queue - RunWorker (extension); - } - /// - /// Gets the small shell icon for the given file extension from the cache. - /// If the item is not cached, null will be returned. - /// - /// File extension. - public Image GetSmallIcon (string extension) - { - if (string.IsNullOrEmpty (extension)) - throw new ArgumentException ("extension cannot be null", "extension"); - - CacheItem item = null; - if (shellCache.TryGetValue (extension, out item)) { - return item.SmallIcon; - } - return null; - } - /// - /// Gets the large shell icon for the given file extension from the cache. - /// If the item is not cached, null will be returned. - /// - /// File extension. - public Image GetLargeIcon (string extension) - { - if (string.IsNullOrEmpty (extension)) - throw new ArgumentException ("extension cannot be null", "extension"); - - CacheItem item = null; - if (shellCache.TryGetValue (extension, out item)) { - return item.LargeIcon; - } - return null; - } - /// - /// Gets the shell file type for the given file extension from the cache. - /// If the item is not cached, null will be returned. - /// - /// File extension. - public string GetFileType (string extension) - { - if (string.IsNullOrEmpty (extension)) - throw new ArgumentException ("extension cannot be null", "extension"); - - CacheItem item = null; - if (shellCache.TryGetValue (extension, out item)) { - return item.FileType; - } - return null; - } - #endregion - - #region RunWorker - /// - /// Pushes the given item to the worker queue. - /// - /// File extension. - private void RunWorker (string extension) - { - // Get the current synchronization context - if (context == null) - context = SynchronizationContext.Current; - - // Already being processed? - bool added = processing.TryAdd(extension, false); - if (!added) - return; - - // Add the item to the queue for processing - bw.RunWorkerAsync (extension); - } - #endregion - - #region Dispose - /// - /// Performs application-defined tasks associated with freeing, - /// releasing, or resetting unmanaged resources. - /// - public void Dispose () - { - if (!disposed) { - bw.DoWork -= bw_DoWork; - bw.RunWorkerCompleted -= bw_RunWorkerCompleted; - - Clear (); - bw.Dispose (); - - disposed = true; - - GC.SuppressFinalize (this); - } - } - #if DEBUG - /// - /// Releases unmanaged resources and performs other cleanup operations before the - /// ImageListViewCacheManager is reclaimed by garbage collection. - /// - ~ImageListViewCacheShellInfo () - { - System.Diagnostics.Debug.Print ("Finalizer of {0} called.", GetType ()); - Dispose (); - } - #endif - #endregion - } -} diff --git a/Source/Components/ImageGlass.ImageListView/ImageListViewCacheThumbnail.cs b/Source/Components/ImageGlass.ImageListView/ImageListViewCacheThumbnail.cs deleted file mode 100644 index e0ec32589..000000000 --- a/Source/Components/ImageGlass.ImageListView/ImageListViewCacheThumbnail.cs +++ /dev/null @@ -1,1056 +0,0 @@ -// ImageListView - A listview control for image files -// Copyright (C) 2009 Ozgur Ozcitak -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// Ozgur Ozcitak (ozcitak@yahoo.com) - -using System; -using System.Collections.Generic; -using System.Drawing; -using System.Threading; -using System.IO; -using System.Security.Cryptography; -using System.Text; - -namespace ImageGlass.ImageListView -{ - /// - /// Represents the cache manager responsible for asynchronously loading - /// item thumbnails. - /// - internal class ImageListViewCacheThumbnail : IDisposable - { - #region Member Variables - private QueuedBackgroundWorker bw; - private SynchronizationContext context; - private SendOrPostCallback checkProcessingCallback; - - private ImageListView mImageListView; - - internal DiskCache diskCache; - private Dictionary thumbCache; - private Dictionary processing; - private Guid processingRendererItem; - private Guid processingGalleryItem; - private Dictionary editCache; - private CacheItem rendererItem; - private CacheItem galleryItem; - - private List removedItems; - - private bool disposed; - #endregion - - #region RequestType Enum - private enum RequestType - { - /// - /// This is a thumbnail request. - /// - Thumbnail, - /// - /// This is a large image request for use in Gallery or Pane view modes. - /// - Gallery, - /// - /// This is a renderer request. - /// - Renderer - } - #endregion - - #region CacheRequest Class - /// - /// Represents a cache request. - /// - private class CacheRequest - { - /// - /// Gets the guid of the item. - /// - public Guid Guid { get; private set; } - /// - /// Gets the adaptor of this item. - /// - public ImageListView.ImageListViewItemAdaptor Adaptor { get; private set; } - /// - /// Gets the public key for the virtual item. - /// - public object VirtualItemKey { get; private set; } - /// - /// Gets the size of the requested thumbnail. - /// - public Size Size { get; private set; } - /// - /// Gets embedded thumbnail extraction behavior. - /// - public UseEmbeddedThumbnails UseEmbeddedThumbnails { get; private set; } - /// - /// Gets Exif rotation behavior. - /// - public bool AutoRotate { get; private set; } - /// - /// Gets whether Windows Imaging Component will be used. - /// - public bool UseWIC { get; private set; } - /// - /// Gets the type of this request. - /// - public RequestType RequestType { get; private set; } - - /// - /// Initializes a new instance of the class - /// for use with a virtual item. - /// - /// The guid of the ImageListViewItem. - /// The adaptor of this item. - /// The public key for the virtual item. - /// The size of the requested thumbnail. - /// UseEmbeddedThumbnails property of the owner control. - /// AutoRotate property of the owner control. - /// Whether to use WIC. - /// Type of this request. - public CacheRequest(Guid guid, ImageListView.ImageListViewItemAdaptor adaptor, object key, Size size, UseEmbeddedThumbnails useEmbeddedThumbnails, bool autoRotate, bool useWIC, RequestType requestType) - { - Guid = guid; - VirtualItemKey = key; - Adaptor = adaptor; - Size = size; - UseEmbeddedThumbnails = useEmbeddedThumbnails; - AutoRotate = autoRotate; - UseWIC = useWIC; - RequestType = requestType; - } - - /// - /// Returns a that represents this instance. - /// - public override string ToString() - { - return "CacheRequest (" + VirtualItemKey.ToString() + ")"; - } - } - #endregion - - #region CacheItem Class - /// - /// Represents an item in the thumbnail cache. - /// - private class CacheItem : IDisposable - { - private bool disposed; - - /// - /// Gets the guid of the item. - /// - public Guid Guid { get; private set; } - /// - /// Gets the size of the requested thumbnail. - /// - public Size Size { get; private set; } - /// - /// Gets the cached image. - /// - public Image Image { get; private set; } - /// - /// Gets or sets the state of the cache item. - /// - public CacheState State { get; set; } - /// - /// Gets embedded thumbnail extraction behavior. - /// - public UseEmbeddedThumbnails UseEmbeddedThumbnails { get; private set; } - /// - /// Gets Exif rotation behavior. - /// - public bool AutoRotate { get; private set; } - /// - /// Gets whether Windows Imaging Component will be used. - /// - public bool UseWIC { get; private set; } - - /// - /// Initializes a new instance of the class - /// for use with a virtual item. - /// - /// The guid of the ImageListViewItem. - /// The size of the requested thumbnail. - /// The thumbnail image. - /// The cache state of the item. - /// UseEmbeddedThumbnails property of the owner control. - /// AutoRotate property of the owner control. - /// Whether to use WIC. - public CacheItem(Guid guid, Size size, Image image, CacheState state, UseEmbeddedThumbnails useEmbeddedThumbnails, bool autoRotate, bool useWIC) - { - Guid = guid; - Size = size; - Image = image; - State = state; - UseEmbeddedThumbnails = useEmbeddedThumbnails; - AutoRotate = autoRotate; - UseWIC = useWIC; - disposed = false; - } - - /// - /// Performs application-defined tasks associated with - /// freeing, releasing, or resetting unmanaged resources. - /// - public void Dispose() - { - if (!disposed) - { - if (Image != null) - { - Image.Dispose(); - Image = null; - } - - disposed = true; - GC.SuppressFinalize(this); - } - } -#if DEBUG - /// - /// Releases unmanaged resources and performs other cleanup operations before the - /// class is reclaimed by garbage collection. - /// - ~CacheItem() - { - if (Image != null) - System.Diagnostics.Debug.Print("Finalizer of {0} called for non-empty cache item.", GetType()); - Dispose(); - } -#endif - } - #endregion - - #region CanContinueProcessingEventArgs - /// - /// Represents the event arguments for the callback. - /// - private class CanContinueProcessingEventArgs : EventArgs - { - /// - /// Gets the request. - /// - public CacheRequest Request { get; private set; } - /// - /// Gets whether this item should be processed. - /// - public bool ContinueProcessing { get; set; } - - /// - /// Initializes a new instance of the class. - /// - /// The cache request. - public CanContinueProcessingEventArgs(CacheRequest request) - { - Request = request; - ContinueProcessing = true; - } - } - #endregion - - #region Properties - /// - /// Determines whether the cache manager retries loading items on errors. - /// - public bool RetryOnError { get; internal set; } - /// - /// Gets or sets the cache mode. - /// - public CacheMode CacheMode { get; internal set; } - /// - /// Gets or sets the cache limit as count of items. - /// - public int CacheLimitAsItemCount { get; internal set; } - /// - /// Gets or sets the cache limit as allocated memory in MB. - /// - public long CacheLimitAsMemory { get; internal set; } - /// - /// Gets the approximate amount of memory used by the cache. - /// - public long MemoryUsed { get; private set; } - /// - /// Gets the approximate amount of memory used by removed items in the cache. - /// This memory can be reclaimed by calling . - /// - public long MemoryUsedByRemoved { get; private set; } - /// - /// Returns the count of items in the cache. - /// - public long CacheSize - { - get { return thumbCache.Count; } - } - #endregion - - #region Constructor - /// - /// Initializes a new instance of the class. - /// - /// The owner control. - public ImageListViewCacheThumbnail(ImageListView owner) - { - context = null; - bw = new QueuedBackgroundWorker(); - bw.ProcessingMode = ProcessingMode.LIFO; - bw.IsBackground = true; - bw.DoWork += bw_DoWork; - bw.RunWorkerCompleted += bw_RunWorkerCompleted; - - checkProcessingCallback = new SendOrPostCallback(CanContinueProcessing); - - mImageListView = owner; - diskCache = new DiskCache(string.Empty, 100 * 1024 * 1024, DiskCache.SyncBehavior.SyncNone, 32); - CacheMode = CacheMode.OnDemand; - CacheLimitAsItemCount = 0; - CacheLimitAsMemory = 20 * 1024 * 1024; - RetryOnError = false; - - thumbCache = new Dictionary(); - editCache = new Dictionary(); - processing = new Dictionary(); - processingRendererItem = Guid.Empty; - processingGalleryItem = Guid.Empty; - - rendererItem = null; - galleryItem = null; - - MemoryUsed = 0; - MemoryUsedByRemoved = 0; - removedItems = new List(); - - disposed = false; - } - #endregion - - #region Context Callbacks - /// - /// Determines if the item should be processed. - /// - /// The to check. - /// true if the item should be processed; otherwise false. - private bool OnCanContinueProcessing(CacheRequest item) - { - CanContinueProcessingEventArgs arg = new CanContinueProcessingEventArgs(item); - context.Send(checkProcessingCallback, arg); - return arg.ContinueProcessing; - } - /// - /// Determines if the item should be processed. - /// - /// The event argument. - /// true if the item should be processed; otherwise false. - private void CanContinueProcessing(object argument) - { - CanContinueProcessingEventArgs arg = argument as CanContinueProcessingEventArgs; - CacheRequest request = arg.Request; - bool canProcess = true; - - // Is it in the edit cache? - if (canProcess && editCache.ContainsKey(request.Guid)) - canProcess = false; - - // Is it already cached? - if (canProcess && (request.RequestType == RequestType.Thumbnail)) - { - CacheItem existing = null; - thumbCache.TryGetValue(request.Guid, out existing); - if (existing != null && existing.Size == request.Size && existing.UseEmbeddedThumbnails == request.UseEmbeddedThumbnails && existing.AutoRotate == request.AutoRotate && existing.UseWIC == request.UseWIC) - canProcess = false; - - // Is it outside the visible area? - if (canProcess && (CacheMode == CacheMode.OnDemand) && mImageListView != null && !mImageListView.IsItemVisible(request.Guid)) - canProcess = false; - } - else if (canProcess && (request.RequestType == RequestType.Gallery)) - { - CacheItem existing = galleryItem; - if (existing != null && existing.Guid == request.Guid && existing.Size == request.Size && existing.UseEmbeddedThumbnails == request.UseEmbeddedThumbnails && existing.AutoRotate == request.AutoRotate && existing.UseWIC == request.UseWIC) - canProcess = false; - } - else if (canProcess && (request.RequestType == RequestType.Renderer)) - { - CacheItem existing = rendererItem; - if (existing != null && existing.Guid == request.Guid && existing.Size == request.Size && existing.UseEmbeddedThumbnails == request.UseEmbeddedThumbnails && existing.AutoRotate == request.AutoRotate && existing.UseWIC == request.UseWIC) - canProcess = false; - } - - arg.ContinueProcessing = canProcess; - } - #endregion - - #region QueuedBackgroundWorker Events - /// - /// Handles the RunWorkerCompleted event of the queued background worker. - /// - /// The source of the event. - /// The - /// instance containing the event data. - void bw_RunWorkerCompleted(object sender, QueuedWorkerCompletedEventArgs e) - { - CacheRequest request = e.UserState as CacheRequest; - CacheItem result = e.Result as CacheItem; - - // We are done processing - if (request.RequestType == RequestType.Renderer) - processingRendererItem = Guid.Empty; - else if (request.RequestType == RequestType.Gallery) - processingGalleryItem = Guid.Empty; - else - processing.Remove(request.Guid); - - // Do not process the result if the cache operation - // was cancelled. - if (e.Cancelled) - return; - - // Dispose old item and add to cache - if (request.RequestType == RequestType.Renderer) - { - if (rendererItem != null) - rendererItem.Dispose(); - - rendererItem = result; - } - else if (request.RequestType == RequestType.Gallery) - { - if (galleryItem != null) - galleryItem.Dispose(); - - galleryItem = result; - } - else if (result != null) - { - CacheItem existing = null; - if (thumbCache.TryGetValue(result.Guid, out existing)) - { - existing.Dispose(); - thumbCache.Remove(result.Guid); - } - thumbCache.Add(result.Guid, result); - - if (result.Image != null) - { - // Did the thumbnail size change while we were - // creating the thumbnail? - if (result.Size != mImageListView.ThumbnailSize) - result.State = CacheState.Unknown; - - // Purge invisible items if we exceeded the cache limit - MemoryUsed += GetImageMemorySize(result.Image); - if (IsCacheLimitExceeded()) - PurgeInvisible(true); - } - } - - //Refresh the control - if (mImageListView != null) - { - if (request.RequestType != RequestType.Thumbnail || mImageListView.IsItemVisible(request.Guid)) - mImageListView.Refresh(false, true); - } - - // Raise the ThumbnailCached event - if (mImageListView != null) - mImageListView.OnThumbnailCachedInternal(result.Guid, result.Image, result.Size, request.RequestType == RequestType.Thumbnail); - - // Raise the CacheError event - if (e.Error != null && mImageListView != null) - mImageListView.OnCacheErrorInternal(result.Guid, e.Error, CacheThread.Thumbnail); - } - /// - /// Handles the DoWork event of the queued background worker. - /// - /// The source of the event. - /// The instance - /// containing the event data. - void bw_DoWork(object sender, QueuedWorkerDoWorkEventArgs e) - { - CacheRequest request = e.Argument as CacheRequest; - - // Should we continue processing this item? - // The callback checks the following and returns false if - // the item is already cached -OR- - // the item is in the edit cache -OR- - // the item is outside the visible area (only if the CacheMode is OnDemand). - if (!OnCanContinueProcessing(request)) - { - e.Cancel = true; - return; - } - - Image thumb = null; - string diskCacheKey = GetKey(request.Guid, request.Size, request.UseEmbeddedThumbnails, request.AutoRotate, request.UseWIC); - - // Check the disk cache - using (MemoryStream stream = new MemoryStream()) - { - if (diskCache.Read(diskCacheKey, stream)) - { - thumb = new Bitmap(stream); - } - } - - // Extract the thumbnail from the source image. - if (thumb == null) - { - thumb = request.Adaptor.GetThumbnail(request.VirtualItemKey, request.Size, request.UseEmbeddedThumbnails, request.AutoRotate, request.UseWIC); - // Save to disk cache - if (thumb != null) - { - using (MemoryStream stream = new MemoryStream()) - { - thumb.Save(stream, System.Drawing.Imaging.ImageFormat.Png); - diskCache.Write(diskCacheKey, stream); - } - } - } - - // Return the thumbnail - CacheItem result = null; - if (thumb == null && !RetryOnError) - { - result = new CacheItem(request.Guid, request.Size, null, CacheState.Error, request.UseEmbeddedThumbnails, request.AutoRotate, request.UseWIC); - } - else - { - result = new CacheItem(request.Guid, request.Size, thumb, CacheState.Cached, request.UseEmbeddedThumbnails, request.AutoRotate, request.UseWIC); - } - - e.Result = result; - } - #endregion - - #region Instance Methods - /// - /// Pauses the cache threads. - /// - public void Pause() - { - bw.Pause(); - } - /// - /// Resumes the cache threads. - /// - public void Resume() - { - bw.Resume(); - } - /// - /// Starts editing an item. While items are edited, - /// the cache thread will not work on them to prevent collisions. - /// - /// The guid representing the item - public void BeginItemEdit(Guid guid) - { - if (!editCache.ContainsKey(guid)) - { - editCache.Add(guid, false); - } - } - /// - /// Ends editing an item. After this call, item - /// image will be continued to be fetched by the thread. - /// - /// The guid representing the item. - public void EndItemEdit(Guid guid) - { - editCache.Remove(guid); - } - /// - /// Rebuilds the thumbnail cache. - /// Old thumbnails will be kept until they are overwritten - /// by new ones. - /// - public void Rebuild() - { - foreach (CacheItem item in thumbCache.Values) - item.State = CacheState.Unknown; - } - /// - /// Clears the thumbnail cache. - /// - public void Clear() - { - foreach (CacheItem item in thumbCache.Values) - { - if (item != null) - { - item.Dispose(); - } - } - - thumbCache.Clear(); - - if (rendererItem != null) - rendererItem.Dispose(); - rendererItem = null; - - bw.CancelAsync(); - - MemoryUsed = 0; - MemoryUsedByRemoved = 0; - removedItems.Clear(); - processing.Clear(); - processingRendererItem = Guid.Empty; - } - /// - /// Removes the given item from the cache. - /// - /// The guid of the item to remove. - public void Remove(Guid guid) - { - Remove(guid, false); - } - /// - /// Removes the given item from the cache. - /// - /// The guid of the item to remove. - /// true to remove the item now; false to remove the - /// item later when the cache is purged. - public void Remove(Guid guid, bool removeNow) - { - CacheItem item = null; - if (!thumbCache.TryGetValue(guid, out item)) - return; - - if (removeNow) - { - MemoryUsed -= GetImageMemorySize(item.Size.Width, item.Size.Height); - item.Dispose(); - thumbCache.Remove(guid); - } - else - { - MemoryUsedByRemoved += GetImageMemorySize(item.Size.Width, item.Size.Height); - removedItems.Add(guid); - - Purge(); - } - } - /// - /// Purges removed items from the cache. - /// - /// true to purge the cache now, regardless of - /// memory usage; otherwise false to automatically purge the cache - /// depending on memory usage. - public void Purge(bool force) - { - // Remove items now if we can free more than 25% of the cache limit - if (force || IsPurgeNeeded()) - { - foreach (Guid guid in removedItems) - { - CacheItem item = null; - if (thumbCache.TryGetValue(guid, out item)) - { - item.Dispose(); - thumbCache.Remove(guid); - } - } - removedItems.Clear(); - MemoryUsed -= MemoryUsedByRemoved; - MemoryUsedByRemoved = 0; - } - } - /// - /// Purges removed items from the cache automatically - /// depending on memory usage. - /// - public void Purge() - { - Purge(false); - } - /// - /// Purges invisible items from the cache. - /// - /// true to purge the cache now, regardless of - /// memory usage; otherwise false to automatically purge the cache - /// depending on memory usage. - public void PurgeInvisible(bool force) - { - if (mImageListView == null) - return; - - Dictionary visible = mImageListView.GetVisibleItems(); - - if (visible.Count == 0) - return; - - foreach (KeyValuePair item in thumbCache) - { - if (!visible.ContainsKey(item.Key)) - { - removedItems.Add(item.Key); - MemoryUsedByRemoved += GetImageMemorySize(item.Value.Image); - } - } - - Purge(force); - } - /// - /// Determines if removed items need to be purged. Removed items are purged - /// if they take up more than 25% of the cache limit. - /// - /// true if removed items need to be purged; otherwise false. - private bool IsPurgeNeeded() - { - return ((CacheLimitAsMemory != 0 && MemoryUsedByRemoved > CacheLimitAsMemory / 4) || (CacheLimitAsItemCount != 0 && removedItems.Count > CacheLimitAsItemCount / 4)); - } - /// - /// Determines if the cache limit is exceeded. - /// - /// true if the cache limit is exceeded; otherwise false. - private bool IsCacheLimitExceeded() - { - return ((CacheLimitAsMemory != 0 && MemoryUsedByRemoved > CacheLimitAsMemory) || (CacheLimitAsItemCount != 0 && removedItems.Count > CacheLimitAsItemCount)); - } - /// - /// Returns the memory usage of an image. - /// - /// A image. - /// Memory size of the image. - private int GetImageMemorySize(Image image) - { - if (image != null) - return GetImageMemorySize(image.Width, image.Height); - else - return 0; - } - /// - /// Returns the memory usage of an image in of given dimensions. - /// The value is calculated aproximately as (Width * Height * BitsPerPixel / 8) - /// - /// Image width. - /// Image height. - /// Memory size of the image. - private int GetImageMemorySize(int width, int height) - { - return width * height * 24 / 8; - } - /// - /// Adds a virtual item to the cache queue. - /// - /// The guid representing this item. - /// he adaptor for this item. - /// The key of this item. - /// Requested thumbnail size. - /// UseEmbeddedThumbnails property of the owner control. - /// AutoRotate property of the owner control. - /// Whether to use WIC. - public void Add(Guid guid, ImageListView.ImageListViewItemAdaptor adaptor, object key, Size thumbSize, UseEmbeddedThumbnails useEmbeddedThumbnails, bool autoRotate, bool useWIC) - { - // Already cached? - CacheItem item = null; - if (thumbCache.TryGetValue(guid, out item)) - { - if (item.Size == thumbSize && item.UseEmbeddedThumbnails == useEmbeddedThumbnails) - return; - } - - // Add to cache queue - RunWorker(new CacheRequest(guid, adaptor, key, thumbSize, useEmbeddedThumbnails, autoRotate, useWIC, RequestType.Thumbnail)); - } - /// - /// Adds a virtual item to the cache. - /// - /// The guid representing this item. - /// The adaptor for this item. - /// The key of this item. - /// Requested thumbnail size. - /// Thumbnail image to add to cache. - /// UseEmbeddedThumbnails property of the owner control. - /// AutoRotate property of the owner control. - /// Whether to use WIC. - public void Add(Guid guid, ImageListView.ImageListViewItemAdaptor adaptor, object key, Size thumbSize, Image thumb, UseEmbeddedThumbnails useEmbeddedThumbnails, bool autoRotate, bool useWIC) - { - // Already cached? - CacheItem item = null; - if (thumbCache.TryGetValue(guid, out item)) - { - if (item.Size == thumbSize && item.UseEmbeddedThumbnails == useEmbeddedThumbnails) - return; - } - - // Resize - thumb = ThumbnailExtractor.FromImage(thumb, thumbSize, useEmbeddedThumbnails, autoRotate, useWIC); - - // Add to cache - thumbCache.Add(guid, new CacheItem(guid, thumbSize, thumb, CacheState.Cached, useEmbeddedThumbnails, autoRotate, useWIC)); - - // Add to disk cache - using (MemoryStream stream = new MemoryStream()) - { - string diskCacheKey = GetKey(guid, thumbSize, useEmbeddedThumbnails, autoRotate, useWIC); - thumb.Save(stream, System.Drawing.Imaging.ImageFormat.Png); - diskCache.Write(diskCacheKey, stream); - } - - // Raise the cache events - if (mImageListView != null) - { - mImageListView.OnThumbnailCachedInternal(guid, thumb, thumbSize, true); - mImageListView.Refresh(); - } - } - /// - /// Adds the virtual item image to the gallery cache queue. - /// - /// The guid representing this item. - /// The adaptor for this item. - /// The key of this item. - /// Requested thumbnail size. - /// UseEmbeddedThumbnails property of the owner control. - /// AutoRotate property of the owner control. - /// Whether to use WIC. - public void AddToGalleryCache(Guid guid, ImageListView.ImageListViewItemAdaptor adaptor, object key, Size thumbSize, UseEmbeddedThumbnails useEmbeddedThumbnails, bool autoRotate, bool useWIC) - { - // Already cached? - if (galleryItem != null && galleryItem.Guid == guid && galleryItem.Image != null && galleryItem.Size == thumbSize && galleryItem.UseEmbeddedThumbnails == useEmbeddedThumbnails && galleryItem.AutoRotate == autoRotate && galleryItem.UseWIC == useWIC) - return; - - // Add to cache queue - RunWorker(new CacheRequest(guid, adaptor, key, thumbSize, useEmbeddedThumbnails, autoRotate, useWIC, RequestType.Gallery), 2); - } - /// - /// Adds the virtual item image to the renderer cache queue. - /// - /// The guid representing this item. - /// The adaptor of this item. - /// The key of this item. - /// Requested thumbnail size. - /// UseEmbeddedThumbnails property of the owner control. - /// AutoRotate property of the owner control. - /// Whether to use WIC. - public void AddToRendererCache(Guid guid, ImageListView.ImageListViewItemAdaptor adaptor, object key, Size thumbSize, UseEmbeddedThumbnails useEmbeddedThumbnails, bool autoRotate, bool useWIC) - { - // Already cached? - if (rendererItem != null && rendererItem.Guid == guid && rendererItem.Image != null && rendererItem.Size == thumbSize && rendererItem.UseEmbeddedThumbnails == useEmbeddedThumbnails && rendererItem.AutoRotate == autoRotate && rendererItem.UseWIC == useWIC) - return; - - // Add to cache queue - RunWorker(new CacheRequest(guid, adaptor, key, thumbSize, useEmbeddedThumbnails, autoRotate, useWIC, RequestType.Renderer), 1); - } - /// - /// Gets the image from the renderer cache. If the image is not cached, - /// null will be returned. - /// - /// The guid representing this item. - /// Requested thumbnail size. - /// UseEmbeddedThumbnails property of the owner control. - /// AutoRotate property of the owner control. - /// Whether to use WIC. - public Image GetRendererImage(Guid guid, Size thumbSize, UseEmbeddedThumbnails useEmbeddedThumbnails, bool autoRotate, bool useWIC) - { - if (rendererItem != null && rendererItem.Guid == guid && rendererItem.Image != null && rendererItem.Size == thumbSize && rendererItem.UseEmbeddedThumbnails == useEmbeddedThumbnails && rendererItem.AutoRotate == autoRotate && rendererItem.UseWIC == useWIC) - return rendererItem.Image; - else - return null; - } - /// - /// Gets the image from the gallery cache. If the image is not cached, - /// null will be returned. - /// - /// The guid representing this item. - /// Requested thumbnail size. - /// UseEmbeddedThumbnails property of the owner control. - /// AutoRotate property of the owner control. - /// Whether to use WIC. - public Image GetGalleryImage(Guid guid, Size thumbSize, UseEmbeddedThumbnails useEmbeddedThumbnails, bool autoRotate, bool useWIC) - { - if (galleryItem != null && galleryItem.Guid == guid && galleryItem.Image != null && galleryItem.Size == thumbSize && galleryItem.UseEmbeddedThumbnails == useEmbeddedThumbnails && galleryItem.AutoRotate == autoRotate && galleryItem.UseWIC == useWIC) - return galleryItem.Image; - else - return null; - } - /// - /// Gets the image from the thumbnail cache. If the image is not cached, - /// null will be returned. - /// - /// The guid representing this item. - /// Requested thumbnail size. - /// UseEmbeddedThumbnails property of the owner control. - /// AutoRotate property of the owner control. - /// Whether to use WIC. - /// true to return a clone of the cached image; otherwise false. - public Image GetImage(Guid guid, Size thumbSize, UseEmbeddedThumbnails useEmbeddedThumbnails, bool autoRotate, bool useWIC, bool clone) - { - CacheItem item = null; - if (thumbCache.TryGetValue(guid, out item) && item != null && item.Image != null && item.Size == thumbSize && item.UseEmbeddedThumbnails == useEmbeddedThumbnails && item.AutoRotate == autoRotate && item.UseWIC == useWIC) - return clone ? (Image)item.Image.Clone() : item.Image; - else - { - // Try the disk cache - using (MemoryStream stream = new MemoryStream()) - { - if (diskCache.Read(GetKey(guid, thumbSize, useEmbeddedThumbnails, autoRotate, useWIC), stream)) - { - using (Image sourceImage = Image.FromStream(stream)) - { - return new Bitmap(sourceImage); - } - } - } - return null; - } - } - /// - /// Gets the cache state of the specified item. - /// - /// The guid representing the item. - /// Requested thumbnail size. - /// UseEmbeddedThumbnails property of the owner control. - /// AutoRotate property of the owner control. - /// Whether to use WIC. - public CacheState GetCacheState(Guid guid, Size thumbSize, UseEmbeddedThumbnails useEmbeddedThumbnails, bool autoRotate, bool useWIC) - { - CacheItem item = null; - if (thumbCache.TryGetValue(guid, out item) && item != null && item.Size == thumbSize && item.UseEmbeddedThumbnails == useEmbeddedThumbnails && item.AutoRotate == autoRotate && item.UseWIC == useWIC) - return item.State; - - return CacheState.Unknown; - } - /// - /// Returns a key for an item based on its guid, size and other - /// properties. - /// - /// An string key of 32 characters. - private string GetKey(Guid guid, Size size, UseEmbeddedThumbnails useEmbeddedThumbnails, bool autoRotate, bool useWIC) - { - using (MemoryStream stream = new MemoryStream()) - { - using (BinaryWriter writer = new BinaryWriter(stream)) - { - writer.Write(guid.ToByteArray()); - writer.Write(size.Width); - writer.Write(size.Height); - writer.Write((int)useEmbeddedThumbnails); - writer.Write(autoRotate); - writer.Write(useWIC); - writer.Flush(); - - stream.Seek(0, SeekOrigin.Begin); - MD5 md5 = MD5.Create(); - byte[] result = md5.ComputeHash(stream); - - // Convert to hex string - StringBuilder sb = new StringBuilder(); - foreach (byte b in result) - { - sb.Append(b.ToString("x2")); - } - return sb.ToString(); - } - } - } - #endregion - - #region RunWorker - /// - /// Pushes the given item to the worker queue. Items with high priority are renderer - /// or gallery items, ie. large images in gallery and pane views and images requested - /// by custom renderers. Items with 0 priority are regular thumbnails. - /// - /// The item to add to the worker queue. - /// Priority of the item in the queue. - private void RunWorker(CacheRequest item, int priority) - { - // Get the current synchronization context - if (context == null) - context = SynchronizationContext.Current; - - // Already being processed? - if (item.RequestType == RequestType.Thumbnail) - { - if (processing.ContainsKey(item.Guid)) - return; - else - processing.Add(item.Guid, false); - } - else if (item.RequestType == RequestType.Renderer) - { - if (processingRendererItem == item.Guid) - return; - else - { - bw.CancelAsync(priority); - processingRendererItem = item.Guid; - } - } - else if (item.RequestType == RequestType.Gallery) - { - if (processingGalleryItem == item.Guid) - return; - else - { - bw.CancelAsync(priority); - processingGalleryItem = item.Guid; - } - } - - // Raise the ThumbnailCaching event - if (mImageListView != null) - mImageListView.OnThumbnailCachingInternal(item.Guid, item.Size); - - // Add the item to the queue for processing - bw.RunWorkerAsync(item, priority, item.RequestType != RequestType.Thumbnail); - } - /// - /// Pushes the given item to the worker queue. - /// - /// The item to add to the worker queue. - private void RunWorker(CacheRequest item) - { - RunWorker(item, 0); - } - #endregion - - #region Dispose - /// - /// Performs application-defined tasks associated with freeing, - /// releasing, or resetting unmanaged resources. - /// - public void Dispose() - { - if (!disposed) - { - bw.DoWork -= bw_DoWork; - bw.RunWorkerCompleted -= bw_RunWorkerCompleted; - - Clear(); - bw.Dispose(); - - disposed = true; - - GC.SuppressFinalize(this); - } - } -#if DEBUG - /// - /// Releases unmanaged resources and performs other cleanup operations before the - /// ImageListViewCacheManager is reclaimed by garbage collection. - /// - ~ImageListViewCacheThumbnail() - { - System.Diagnostics.Debug.Print("Finalizer of {0} called.", GetType()); - Dispose(); - } -#endif - #endregion - } -} diff --git a/Source/Components/ImageGlass.ImageListView/ImageListViewCheckedItemCollection.cs b/Source/Components/ImageGlass.ImageListView/ImageListViewCheckedItemCollection.cs deleted file mode 100644 index a35512ebc..000000000 --- a/Source/Components/ImageGlass.ImageListView/ImageListViewCheckedItemCollection.cs +++ /dev/null @@ -1,331 +0,0 @@ -// ImageListView - A listview control for image files -// Copyright (C) 2009 Ozgur Ozcitak -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// Ozgur Ozcitak (ozcitak@yahoo.com) - -using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.Collections; - -namespace ImageGlass.ImageListView -{ - public partial class ImageListView - { - /// - /// Represents the collection of checked items in the image list view. - /// - public class ImageListViewCheckedItemCollection : IList - { - #region Member Variables - internal ImageListView mImageListView; - #endregion - - #region Constructors - /// - /// Initializes a new instance of the class. - /// - /// The owning this collection. - internal ImageListViewCheckedItemCollection(ImageListView owner) - { - mImageListView = owner; - } - #endregion - - #region Properties - /// - /// Gets the number of elements contained in the . - /// - [Category("Behavior"), Browsable(true), Description("Gets the number of elements contained in the collection.")] - public int Count - { - get - { - int count = 0; - foreach (ImageListViewItem item in mImageListView.mItems) - if (item.Checked) count++; - return count; - } - } /// - /// Gets a value indicating whether the is read-only. - /// - [Category("Behavior"), Browsable(false), Description("Gets a value indicating whether the collection is read-only.")] - public bool IsReadOnly { get { return true; } } - /// - /// Gets the owning this collection. - /// - [Category("Behavior"), Browsable(false), Description("Gets the ImageListView owning this collection.")] - public ImageListView ImageListView { get { return mImageListView; } } - /// - /// Gets or sets the at the specified index. - /// - [Category("Behavior"), Browsable(false), Description("Gets or sets the item at the specified index")] - public ImageListViewItem this[int index] - { - get - { - int i = 0; - foreach (ImageListViewItem item in this) - { - if (i == index) - return item; - i++; - } - throw new ArgumentException("No item with the given index exists.", "index"); - } - } - #endregion - - #region Instance Methods - /// - /// Determines whether the contains a specific value. - /// - /// The to locate - /// in the . - /// - /// true if is found in the - /// ; otherwise, false. - /// - public bool Contains(ImageListViewItem item) - { - return (item.Checked && mImageListView.Items.Contains(item)); - } - /// - /// Returns an enumerator that iterates through the collection. - /// - /// - /// A that can be used to iterate through the collection. - /// - public IEnumerator GetEnumerator() - { - return new ImageListViewCheckedItemEnumerator(mImageListView.mItems); - } - #endregion - - #region Helper Methods - /// - /// Removes all items from the collection. - /// - internal void Clear() - { - Clear(true); - } - /// - /// Removes all items from the collection. - /// - internal void Clear(bool raiseEvent) - { - foreach (ImageListViewItem item in this) - { - item.mChecked = false; - if (raiseEvent && mImageListView != null) - mImageListView.OnItemCheckBoxClickInternal(item); - } - } - #endregion - - #region Unsupported Interface - /// - /// Adds an item to the . - /// - /// The object to add to the . - /// - /// The is read-only. - /// - void ICollection.Add(ImageListViewItem item) - { - throw new NotSupportedException(); - } - /// - /// Removes all items from the . - /// - void ICollection.Clear() - { - throw new NotSupportedException(); - } - /// - /// Copies the elements of the to an , starting at a particular index. - /// - /// The one-dimensional that is the destination of the elements copied from . The must have zero-based indexing. - /// The zero-based index in at which copying begins. - void ICollection.CopyTo(ImageListViewItem[] array, int arrayIndex) - { - throw new NotSupportedException(); - } - /// - /// Determines the index of a specific item in the . - /// - /// The object to locate in the . - /// - /// The index of if found in the list; otherwise, -1. - /// - [Obsolete("Use ImageListViewItem.Index property instead.")] - int IList.IndexOf(ImageListViewItem item) - { - throw new NotSupportedException(); - } - /// - /// Inserts an item to the at the specified index. - /// - /// The zero-based index at which should be inserted. - /// The object to insert into the . - void IList.Insert(int index, ImageListViewItem item) - { - throw new NotSupportedException(); - } - /// - /// Removes the first occurrence of a specific object from the . - /// - /// The object to remove from the . - /// - /// true if was successfully removed from the ; otherwise, false. This method also returns false if is not found in the original . - /// - bool ICollection.Remove(ImageListViewItem item) - { - throw new NotSupportedException(); - } - /// - /// Removes the item at the specified index. - /// - /// The zero-based index of the item to remove. - void IList.RemoveAt(int index) - { - throw new NotSupportedException(); - } - /// - /// Gets or sets the item at the specified index. - /// - ImageListViewItem IList.this[int index] - { - get - { - throw new NotSupportedException(); - } - set - { - throw new NotSupportedException(); - } - } - /// - /// Returns an enumerator that iterates through a collection. - /// - /// - /// An object that can be used to iterate through the collection. - /// - System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() - { - return GetEnumerator(); - } - #endregion - - #region Internal Classes - /// - /// Represents an enumerator to walk though the checked items. - /// - internal class ImageListViewCheckedItemEnumerator : IEnumerator - { - #region Member Variables - private ImageListViewItemCollection owner; - private int current; - private Guid lastItem; - #endregion - - #region Constructor - public ImageListViewCheckedItemEnumerator(ImageListViewItemCollection collection) - { - owner = collection; - current = -1; - lastItem = Guid.Empty; - } - #endregion - - #region Properties - /// - /// Gets the element in the collection at the current position of the enumerator. - /// - public ImageListViewItem Current - { - get - { - if (current == -1 || current > owner.Count - 1) - throw new InvalidOperationException(); - return owner[current]; - } - } - /// - /// Gets the element in the collection at the current position of the enumerator. - /// - object IEnumerator.Current - { - get { return Current; } - } - #endregion - - #region Instance Methods - /// - /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. - /// - public void Dispose() - { - ; - } - /// - /// Advances the enumerator to the next element of the collection. - /// - public bool MoveNext() - { - // Did we reach the end? - if (current > owner.Count - 1) - { - lastItem = Guid.Empty; - return false; - } - - // Move to the next item if: - // 1. We are before the first item. - OR - - // 2. The current item is the same as the one we enumerated before. - // The current item may have differed if the user for example - // removed the current item between MoveNext calls. - OR - - // 3. The current item is not checked. - while (current == -1 || - owner[current].Guid == lastItem || - owner[current].Checked == false) - { - current++; - if (current > owner.Count - 1) - { - lastItem = Guid.Empty; - return false; - } - } - - // Cache the last item - lastItem = owner[current].Guid; - return true; - } - /// - /// Sets the enumerator to its initial position, which is before the first element in the collection. - /// - public void Reset() - { - current = -1; - lastItem = Guid.Empty; - } - #endregion - } - #endregion - } - } -} \ No newline at end of file diff --git a/Source/Components/ImageGlass.ImageListView/ImageListViewColor.cs b/Source/Components/ImageGlass.ImageListView/ImageListViewColor.cs deleted file mode 100644 index 739963581..000000000 --- a/Source/Components/ImageGlass.ImageListView/ImageListViewColor.cs +++ /dev/null @@ -1,868 +0,0 @@ -// ImageListView - A listview control for image files -// Copyright (C) 2009 Ozgur Ozcitak -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// Ozgur Ozcitak (ozcitak@yahoo.com) -// -// Theme support coded by Robby - -using System.ComponentModel; -using System.Drawing; -using System; -using System.Reflection; -using System.Collections.Generic; - -namespace ImageGlass.ImageListView -{ - /// - /// Represents the color palette of the image list view. - /// - [TypeConverter(typeof(ImageListViewColorTypeConverter))] - public class ImageListViewColor - { - #region Member Variables - // control background color - Color mControlBackColor; - Color mDisabledBackColor; - - // item colors - Color mBackColor; - Color mBorderColor; - Color mUnFocusedColor1; - Color mUnFocusedColor2; - Color mUnFocusedBorderColor; - Color mUnFocusedForeColor; - Color mForeColor; - Color mHoverColor1; - Color mHoverColor2; - Color mHoverBorderColor; - Color mInsertionCaretColor; - Color mSelectedColor1; - Color mSelectedColor2; - Color mSelectedBorderColor; - Color mSelectedForeColor; - Color mDisabledColor1; - Color mDisabledColor2; - Color mDisabledBorderColor; - Color mDisabledForeColor; - - // thumbnail & pane - Color mImageInnerBorderColor; - Color mImageOuterBorderColor; - - // details view - Color mCellForeColor; - Color mColumnHeaderBackColor1; - Color mColumnHeaderBackColor2; - Color mColumnHeaderForeColor; - Color mColumnHeaderHoverColor1; - Color mColumnHeaderHoverColor2; - Color mColumnSelectColor; - Color mColumnSeparatorColor; - Color mAlternateBackColor; - Color mAlternateCellForeColor; - - // pane - Color mPaneBackColor; - Color mPaneSeparatorColor; - Color mPaneLabelColor; - - // selection rectangle - Color mSelectionRectangleColor1; - Color mSelectionRectangleColor2; - Color mSelectionRectangleBorderColor; - #endregion - - #region Properties - /// - /// Gets or sets the background color of the ImageListView control. - /// - [Category("Appearance"), Description("Gets or sets the background color of the ImageListView control.")] - [DefaultValue(typeof(Color), "Window")] - public Color ControlBackColor - { - get { return mControlBackColor; } - set { mControlBackColor = value; } - } - /// - /// Gets or sets the background color of the ImageListView control in its disabled state. - /// - [Category("Appearance"), Description("Gets or sets the background color of the ImageListView control in its disabled state.")] - [DefaultValue(typeof(Color), "Control")] - public Color DisabledBackColor - { - get { return mDisabledBackColor; } - set { mDisabledBackColor = value; } - } - /// - /// Gets or sets the background color of the ImageListViewItem. - /// - [Category("Appearance"), Description("Gets or sets the background color of the ImageListViewItem.")] - [DefaultValue(typeof(Color), "Window")] - public Color BackColor - { - get { return mBackColor; } - set { mBackColor = value; } - } - /// - /// Gets or sets the background color of alternating cells in Details View. - /// - [Category("Appearance Details View"), Description("Gets or sets the background color of alternating cells in Details View.")] - [DefaultValue(typeof(Color), "Window")] - public Color AlternateBackColor - { - get { return mAlternateBackColor; } - set { mAlternateBackColor = value; } - } - /// - /// Gets or sets the border color of the ImageListViewItem. - /// - [Category("Appearance"), Description("Gets or sets the border color of the ImageListViewItem.")] - [DefaultValue(typeof(Color), "64, 128, 128, 128")] - public Color BorderColor - { - get { return mBorderColor; } - set { mBorderColor = value; } - } - /// - /// Gets or sets the foreground color of the ImageListViewItem. - /// - [Category("Appearance"), Description("Gets or sets the foreground color of the ImageListViewItem.")] - [DefaultValue(typeof(Color), "ControlText")] - public Color ForeColor - { - get { return mForeColor; } - set { mForeColor = value; } - } - /// - /// Gets or sets the background gradient color1 of the ImageListViewItem if the control is not focused. - /// - [Category("Appearance"), Description("Gets or sets the background gradient color1 of the ImageListViewItem if the control is not focused.")] - [DefaultValue(typeof(Color), "16, 128, 128, 128")] - public Color UnFocusedColor1 - { - get { return mUnFocusedColor1; } - set { mUnFocusedColor1 = value; } - } - /// - /// Gets or sets the background gradient color2 of the ImageListViewItem if the control is not focused. - /// - [Category("Appearance"), Description("Gets or sets the background gradient color2 of the ImageListViewItem if the control is not focused.")] - [DefaultValue(typeof(Color), "64, 128, 128, 128")] - public Color UnFocusedColor2 - { - get { return mUnFocusedColor2; } - set { mUnFocusedColor2 = value; } - } - /// - /// Gets or sets the border color of the ImageListViewItem if the control is not focused. - /// - [Category("Appearance"), Description("Gets or sets the border color of the ImageListViewItem if the control is not focused.")] - [DefaultValue(typeof(Color), "128, 128, 128, 128")] - public Color UnFocusedBorderColor - { - get { return mUnFocusedBorderColor; } - set { mUnFocusedBorderColor = value; } - } - /// - /// Gets or sets the fore color of the ImageListViewItem if the control is not focused. - /// - [Category("Appearance"), Description("Gets or sets the fore color of the ImageListViewItem if the control is not focused.")] - [DefaultValue(typeof(Color), "ControlText")] - public Color UnFocusedForeColor - { - get { return mUnFocusedForeColor; } - set { mUnFocusedForeColor = value; } - } - /// - /// Gets or sets the background gradient color1 if the ImageListViewItem is hovered. - /// - [Category("Appearance"), Description("Gets or sets the background gradient color1 if the ImageListViewItem is hovered.")] - [DefaultValue(typeof(Color), "8, 10, 36, 106")] - public Color HoverColor1 - { - get { return mHoverColor1; } - set { mHoverColor1 = value; } - } - /// - /// Gets or sets the background gradient color2 if the ImageListViewItem is hovered. - /// - [Category("Appearance"), Description("Gets or sets the background gradient color2 if the ImageListViewItem is hovered.")] - [DefaultValue(typeof(Color), "64, 10, 36, 106")] - public Color HoverColor2 - { - get { return mHoverColor2; } - set { mHoverColor2 = value; } - } - /// - /// Gets or sets the border color of the ImageListViewItem if the item is hovered. - /// - [Category("Appearance"), Description("Gets or sets the border color of the ImageListViewItem if the item is hovered.")] - [DefaultValue(typeof(Color), "64, 10, 36, 106")] - public Color HoverBorderColor - { - get { return mHoverBorderColor; } - set { mHoverBorderColor = value; } - } - /// - /// Gets or sets the color of the insertion caret. - /// - [Category("Appearance"), Description("Gets or sets the color of the insertion caret.")] - [DefaultValue(typeof(Color), "Highlight")] - public Color InsertionCaretColor - { - get { return mInsertionCaretColor; } - set { mInsertionCaretColor = value; } - } - /// - /// Gets or sets the background gradient color1 if the ImageListViewItem is selected. - /// - [Category("Appearance"), Description("Gets or sets the background gradient color1 if the ImageListViewItem is selected.")] - [DefaultValue(typeof(Color), "16, 10, 36, 106")] - public Color SelectedColor1 - { - get { return mSelectedColor1; } - set { mSelectedColor1 = value; } - } - /// - /// Gets or sets the background gradient color2 if the ImageListViewItem is selected. - /// - [Category("Appearance"), Description("Gets or sets the background gradient color2 if the ImageListViewItem is selected.")] - [DefaultValue(typeof(Color), "128, 10, 36, 106")] - public Color SelectedColor2 - { - get { return mSelectedColor2; } - set { mSelectedColor2 = value; } - } - /// - /// Gets or sets the border color of the ImageListViewItem if the item is selected. - /// - [Category("Appearance"), Description("Gets or sets the border color of the ImageListViewItem if the item is selected.")] - [DefaultValue(typeof(Color), "128, 10, 36, 106")] - public Color SelectedBorderColor - { - get { return mSelectedBorderColor; } - set { mSelectedBorderColor = value; } - } - /// - /// Gets or sets the fore color of the ImageListViewItem if the item is selected. - /// - [Category("Appearance"), Description("Gets or sets the fore color of the ImageListViewItem if the item is selected.")] - [DefaultValue(typeof(Color), "ControlText")] - public Color SelectedForeColor - { - get { return mSelectedForeColor; } - set { mSelectedForeColor = value; } - } - /// - /// Gets or sets the background gradient color1 if the ImageListViewItem is disabled. - /// - [Category("Appearance"), Description("Gets or sets the background gradient color1 if the ImageListViewItem is disabled.")] - [DefaultValue(typeof(Color), "0, 128, 128, 128")] - public Color DisabledColor1 - { - get { return mDisabledColor1; } - set { mDisabledColor1 = value; } - } - /// - /// Gets or sets the background gradient color2 if the ImageListViewItem is disabled. - /// - [Category("Appearance"), Description("Gets or sets the background gradient color2 if the ImageListViewItem is disabled.")] - [DefaultValue(typeof(Color), "32, 128, 128, 128")] - public Color DisabledColor2 - { - get { return mDisabledColor2; } - set { mDisabledColor2 = value; } - } - /// - /// Gets or sets the border color of the ImageListViewItem if the item is disabled. - /// - [Category("Appearance"), Description("Gets or sets the border color of the ImageListViewItem if the item is disabled.")] - [DefaultValue(typeof(Color), "32, 128, 128, 128")] - public Color DisabledBorderColor - { - get { return mDisabledBorderColor; } - set { mDisabledBorderColor = value; } - } - /// - /// Gets or sets the fore color of the ImageListViewItem if the item is disabled. - /// - [Category("Appearance"), Description("Gets or sets the fore color of the ImageListViewItem if the item is disabled.")] - [DefaultValue(typeof(Color), "128, 128, 128")] - public Color DisabledForeColor - { - get { return mDisabledForeColor; } - set { mDisabledForeColor = value; } - } - /// - /// Gets or sets the background gradient color1 of the column header. - /// - [Category("Appearance Details View"), Description("Gets or sets the cells background color1 of the column header.")] - [DefaultValue(typeof(Color), "32, 212, 208, 200")] - public Color ColumnHeaderBackColor1 - { - get { return mColumnHeaderBackColor1; } - set { mColumnHeaderBackColor1 = value; } - } - /// - /// Gets or sets the background gradient color2 of the column header. - /// - [Category("Appearance Details View"), Description("Gets or sets the cells background color2 of the column header.")] - [DefaultValue(typeof(Color), "196, 212, 208, 200")] - public Color ColumnHeaderBackColor2 - { - get { return mColumnHeaderBackColor2; } - set { mColumnHeaderBackColor2 = value; } - } - /// - /// Gets or sets the background hover gradient color1 of the column header. - /// - [Category("Appearance Details View"), Description("Gets or sets the background hover color1 of the column header.")] - [DefaultValue(typeof(Color), "16, 10, 36, 106")] - public Color ColumnHeaderHoverColor1 - { - get { return mColumnHeaderHoverColor1; } - set { mColumnHeaderHoverColor1 = value; } - } - /// - /// Gets or sets the background hover gradient color2 of the column header. - /// - [Category("Appearance Details View"), Description("Gets or sets the background hover color2 of the column header.")] - [DefaultValue(typeof(Color), "64, 10, 36, 106")] - public Color ColumnHeaderHoverColor2 - { - get { return mColumnHeaderHoverColor2; } - set { mColumnHeaderHoverColor2 = value; } - } - /// - /// Gets or sets the cells foreground color of the column header text. - /// - [Category("Appearance Details View"), Description("Gets or sets the cells foreground color of the column header text.")] - [DefaultValue(typeof(Color), "WindowText")] - public Color ColumnHeaderForeColor - { - get { return mColumnHeaderForeColor; } - set { mColumnHeaderForeColor = value; } - } - /// - /// Gets or sets the cells background color if column is selected in Details View. - /// - [Category("Appearance Details View"), Description("Gets or sets the cells background color if column is selected in Details View.")] - [DefaultValue(typeof(Color), "16, 128, 128, 128")] - public Color ColumnSelectColor - { - get { return mColumnSelectColor; } - set { mColumnSelectColor = value; } - } - /// - /// Gets or sets the color of the separator in Details View. - /// - [Category("Appearance Details View"), Description("Gets or sets the color of the separator in Details View.")] - [DefaultValue(typeof(Color), "32, 128, 128, 128")] - public Color ColumnSeparatorColor - { - get { return mColumnSeparatorColor; } - set { mColumnSeparatorColor = value; } - } - /// - /// Gets or sets the foreground color of the cell text in Details View. - /// - [Category("Appearance Details View"), Description("Gets or sets the foreground color of the cell text in Details View.")] - [DefaultValue(typeof(Color), "ControlText")] - public Color CellForeColor - { - get { return mCellForeColor; } - set { mCellForeColor = value; } - } - /// - /// Gets or sets the foreground color of alternating cells text in Details View. - /// - [Category("Appearance Details View"), Description("Gets or sets the foreground color of alternating cells text in Details View.")] - [DefaultValue(typeof(Color), "ControlText")] - public Color AlternateCellForeColor - { - get { return mAlternateCellForeColor; } - set { mAlternateCellForeColor = value; } - } - /// - /// Gets or sets the background color of the image pane. - /// - [Category("Appearance Pane View"), Description("Gets or sets the background color of the image pane.")] - [DefaultValue(typeof(Color), "16, 128, 128, 128")] - public Color PaneBackColor - { - get { return mPaneBackColor; } - set { mPaneBackColor = value; } - } - /// - /// Gets or sets the separator line color between image pane and thumbnail view. - /// - [Category("Appearance Pane View"), Description("Gets or sets the separator line color between image pane and thumbnail view.")] - [DefaultValue(typeof(Color), "128, 128, 128, 128")] - public Color PaneSeparatorColor - { - get { return mPaneSeparatorColor; } - set { mPaneSeparatorColor = value; } - } - /// - /// Gets or sets the color of labels in pane view. - /// - [Category("Appearance Pane View"), Description("Gets or sets the color of labels in pane view.")] - [DefaultValue(typeof(Color), "196, 0, 0, 0")] - public Color PaneLabelColor - { - get { return mPaneLabelColor; } - set { mPaneLabelColor = value; } - } - /// - /// Gets or sets the image inner border color for thumbnails and pane. - /// - [Category("Appearance Image"), Description("Gets or sets the image inner border color for thumbnails and pane.")] - [DefaultValue(typeof(Color), "128, 255, 255, 255")] - public Color ImageInnerBorderColor - { - get { return mImageInnerBorderColor; } - set { mImageInnerBorderColor = value; } - } - /// - /// Gets or sets the image outer border color for thumbnails and pane. - /// - [Category("Appearance Image"), Description("Gets or sets the image outer border color for thumbnails and pane.")] - [DefaultValue(typeof(Color), "128, 128, 128, 128")] - public Color ImageOuterBorderColor - { - get { return mImageOuterBorderColor; } - set { mImageOuterBorderColor = value; } - } - /// - /// Gets or sets the background color1 of the selection rectangle. - /// - [Category("Appearance"), Description("Gets or sets the background color1 of the selection rectangle.")] - [DefaultValue(typeof(Color), "128, 10, 36, 106")] - public Color SelectionRectangleColor1 - { - get { return mSelectionRectangleColor1; } - set { mSelectionRectangleColor1 = value; } - } - /// - /// Gets or sets the background color2 of the selection rectangle. - /// - [Category("Appearance"), Description("Gets or sets the background color2 of the selection rectangle.")] - [DefaultValue(typeof(Color), "128, 10, 36, 106")] - public Color SelectionRectangleColor2 - { - get { return mSelectionRectangleColor2; } - set { mSelectionRectangleColor2 = value; } - } - /// - /// Gets or sets the color of the selection rectangle border. - /// - [Category("Appearance"), Description("Gets or sets the color of the selection rectangle border.")] - [DefaultValue(typeof(Color), "Highlight")] - public Color SelectionRectangleBorderColor - { - get { return mSelectionRectangleBorderColor; } - set { mSelectionRectangleBorderColor = value; } - } - #endregion - - #region Constructors - /// - /// Initializes a new instance of the ImageListViewColor class. - /// - public ImageListViewColor() - { - // control - mControlBackColor = SystemColors.Window; - mDisabledBackColor = SystemColors.Control; - - // item - mBackColor = SystemColors.Window; - mForeColor = SystemColors.ControlText; - - mBorderColor = Color.FromArgb(64, SystemColors.GrayText); - - mUnFocusedColor1 = Color.FromArgb(16, SystemColors.GrayText); - mUnFocusedColor2 = Color.FromArgb(64, SystemColors.GrayText); - mUnFocusedBorderColor = Color.FromArgb(128, SystemColors.GrayText); - mUnFocusedForeColor = SystemColors.ControlText; - - mHoverColor1 = Color.FromArgb(8, SystemColors.Highlight); - mHoverColor2 = Color.FromArgb(64, SystemColors.Highlight); - mHoverBorderColor = Color.FromArgb(64, SystemColors.Highlight); - - mSelectedColor1 = Color.FromArgb(16, SystemColors.Highlight); - mSelectedColor2 = Color.FromArgb(128, SystemColors.Highlight); - mSelectedBorderColor = Color.FromArgb(128, SystemColors.Highlight); - mSelectedForeColor = SystemColors.ControlText; - - mDisabledColor1 = Color.FromArgb(0, SystemColors.GrayText); - mDisabledColor2 = Color.FromArgb(32, SystemColors.GrayText); - mDisabledBorderColor = Color.FromArgb(32, SystemColors.GrayText); - mDisabledForeColor = Color.FromArgb(128, 128, 128); - - mInsertionCaretColor = SystemColors.Highlight; - - // thumbnails - mImageInnerBorderColor = Color.FromArgb(128, Color.White); - mImageOuterBorderColor = Color.FromArgb(128, Color.Gray); - - // details view - mColumnHeaderBackColor1 = Color.FromArgb(32, SystemColors.Control); - mColumnHeaderBackColor2 = Color.FromArgb(196, SystemColors.Control); - mColumnHeaderHoverColor1 = Color.FromArgb(16, SystemColors.Highlight); - mColumnHeaderHoverColor2 = Color.FromArgb(64, SystemColors.Highlight); - mColumnHeaderForeColor = SystemColors.WindowText; - mColumnSelectColor = Color.FromArgb(16, SystemColors.GrayText); - mColumnSeparatorColor = Color.FromArgb(32, SystemColors.GrayText); - mCellForeColor = SystemColors.ControlText; - mAlternateBackColor = SystemColors.Window; - mAlternateCellForeColor = SystemColors.ControlText; - - // image pane - mPaneBackColor = Color.FromArgb(16, SystemColors.GrayText); - mPaneSeparatorColor = Color.FromArgb(128, SystemColors.GrayText); - mPaneLabelColor = Color.FromArgb(196, Color.Black); - - // selection rectangle - mSelectionRectangleColor1 = Color.FromArgb(128, SystemColors.Highlight); - mSelectionRectangleColor2 = Color.FromArgb(128, SystemColors.Highlight); - mSelectionRectangleBorderColor = SystemColors.Highlight; - } - - /// - /// Initializes a new instance of the ImageListViewColor class - /// from its string representation. - /// - /// String representation of the object. - public ImageListViewColor(string definition) - : this() - { - try - { - // First check if the color matches a predefined color setting - foreach (MemberInfo info in typeof(ImageListViewColor).GetMembers(BindingFlags.Static | BindingFlags.Public)) - { - if (info.MemberType == MemberTypes.Property) - { - PropertyInfo propertyInfo = (PropertyInfo)info; - if (propertyInfo.PropertyType == typeof(ImageListViewColor)) - { - // If the color setting is equal to a preset value - // return the preset - if (definition == string.Format("({0})", propertyInfo.Name) || - definition == propertyInfo.Name) - { - ImageListViewColor presetValue = (ImageListViewColor)propertyInfo.GetValue(null, null); - CopyFrom(presetValue); - return; - } - } - } - } - - // Convert color values - foreach (string line in definition.Split(new string[] { ";" }, StringSplitOptions.RemoveEmptyEntries)) - { - // Read the color setting - string[] pair = line.Split(new string[] { "=" }, StringSplitOptions.RemoveEmptyEntries); - string name = pair[0].Trim(); - Color color = Color.FromName(pair[1].Trim()); - // Set the property value - PropertyInfo property = typeof(ImageListViewColor).GetProperty(name); - property.SetValue(this, color, null); - } - } - catch - { - throw new ArgumentException("Invalid string format", "definition"); - } - } - #endregion - - #region Instance Methods - /// - /// Copies color values from the given object. - /// - /// The source object. - public void CopyFrom(ImageListViewColor source) - { - foreach (PropertyInfo info in typeof(ImageListViewColor).GetProperties()) - { - // Walk through color properties - if (info.PropertyType == typeof(Color)) - { - Color color = (Color)info.GetValue(source, null); - info.SetValue(this, color, null); - } - } - } - #endregion - - #region Static Members - /// - /// Represents the default color theme. - /// - public static ImageListViewColor Default { get { return ImageListViewColor.GetDefaultTheme(); } } - /// - /// Represents the noir color theme. - /// - public static ImageListViewColor Noir { get { return ImageListViewColor.GetNoirTheme(); } } - /// - /// Represents the mandarin color theme. - /// - public static ImageListViewColor Mandarin { get { return ImageListViewColor.GetMandarinTheme(); } } - - /// - /// Sets the color palette to default colors. - /// - private static ImageListViewColor GetDefaultTheme() - { - return new ImageListViewColor(); - } - /// - /// Sets the color palette to mandarin colors. - /// - private static ImageListViewColor GetMandarinTheme() - { - ImageListViewColor c = new ImageListViewColor(); - - // control - c.ControlBackColor = Color.White; - c.DisabledBackColor = Color.FromArgb(220, 220, 220); - - // item - c.BackColor = Color.White; - c.ForeColor = Color.FromArgb(60, 60, 60); - c.BorderColor = Color.FromArgb(187, 190, 183); - - c.UnFocusedColor1 = Color.FromArgb(235, 235, 235); - c.UnFocusedColor2 = Color.FromArgb(217, 217, 217); - c.UnFocusedBorderColor = Color.FromArgb(168, 169, 161); - c.UnFocusedForeColor = Color.FromArgb(40, 40, 40); - - c.HoverColor1 = Color.Transparent; - c.HoverColor2 = Color.Transparent; - c.HoverBorderColor = Color.Transparent; - - c.SelectedColor1 = Color.FromArgb(244, 125, 77); - c.SelectedColor2 = Color.FromArgb(235, 110, 60); - c.SelectedBorderColor = Color.FromArgb(240, 119, 70); - c.SelectedForeColor = Color.White; - - c.DisabledColor1 = Color.FromArgb(217, 217, 217); - c.DisabledColor2 = Color.FromArgb(197, 197, 197); - c.DisabledBorderColor = Color.FromArgb(128, 128, 128); - c.DisabledForeColor = Color.FromArgb(128, 128, 128); - - c.InsertionCaretColor = Color.FromArgb(240, 119, 70); - - // thumbnails & pane - c.ImageInnerBorderColor = Color.Transparent; - c.ImageOuterBorderColor = Color.White; - - // details view - c.CellForeColor = Color.FromArgb(60, 60, 60); - c.ColumnHeaderBackColor1 = Color.FromArgb(247, 247, 247); - c.ColumnHeaderBackColor2 = Color.FromArgb(235, 235, 235); - c.ColumnHeaderHoverColor1 = Color.White; - c.ColumnHeaderHoverColor2 = Color.FromArgb(245, 245, 245); - c.ColumnHeaderForeColor = Color.FromArgb(60, 60, 60); - c.ColumnSelectColor = Color.FromArgb(34, 128, 128, 128); - c.ColumnSeparatorColor = Color.FromArgb(106, 128, 128, 128); - c.mAlternateBackColor = Color.FromArgb(234, 234, 234); - c.mAlternateCellForeColor = Color.FromArgb(40, 40, 40); - - // image pane - c.PaneBackColor = Color.White; - c.PaneSeparatorColor = Color.FromArgb(216, 216, 216); - c.PaneLabelColor = Color.FromArgb(156, 156, 156); - - // selection rectangle - c.SelectionRectangleColor1 = Color.FromArgb(64, 240, 116, 68); - c.SelectionRectangleColor2 = Color.FromArgb(64, 240, 116, 68); - c.SelectionRectangleBorderColor = Color.FromArgb(240, 119, 70); - - return c; - } - /// - /// Sets the color palette to noir colors. - /// - private static ImageListViewColor GetNoirTheme() - { - ImageListViewColor c = new ImageListViewColor(); - - // control - c.ControlBackColor = Color.Black; - c.DisabledBackColor = Color.Black; - - // item - c.BackColor = Color.FromArgb(0x31, 0x31, 0x31); - c.ForeColor = Color.LightGray; - - c.BorderColor = Color.DarkGray; - - c.UnFocusedColor1 = Color.FromArgb(16, SystemColors.GrayText); - c.UnFocusedColor2 = Color.FromArgb(64, SystemColors.GrayText); - c.UnFocusedBorderColor = Color.FromArgb(128, SystemColors.GrayText); - c.UnFocusedForeColor = Color.LightGray; - - c.HoverColor1 = Color.FromArgb(64, Color.White); - c.HoverColor2 = Color.FromArgb(16, Color.White); - c.HoverBorderColor = Color.FromArgb(64, SystemColors.Highlight); - - c.SelectedColor1 = Color.FromArgb(64, 96, 160); - c.SelectedColor2 = Color.FromArgb(64, 64, 96, 160); - c.SelectedBorderColor = Color.FromArgb(128, SystemColors.Highlight); - c.SelectedForeColor = Color.LightGray; - - c.DisabledColor1 = Color.FromArgb(0, SystemColors.GrayText); - c.DisabledColor2 = Color.FromArgb(32, SystemColors.GrayText); - c.DisabledBorderColor = Color.FromArgb(96, SystemColors.GrayText); - c.DisabledForeColor = Color.LightGray; - - c.InsertionCaretColor = Color.FromArgb(96, 144, 240); - - // thumbnails & pane - c.ImageInnerBorderColor = Color.FromArgb(128, Color.White); - c.ImageOuterBorderColor = Color.FromArgb(128, Color.Gray); - - // details view - c.CellForeColor = Color.WhiteSmoke; - c.ColumnHeaderBackColor1 = Color.FromArgb(32, 128, 128, 128); - c.ColumnHeaderBackColor2 = Color.FromArgb(196, 128, 128, 128); - c.ColumnHeaderHoverColor1 = Color.FromArgb(64, 96, 144, 240); - c.ColumnHeaderHoverColor2 = Color.FromArgb(196, 96, 144, 240); - c.ColumnHeaderForeColor = Color.White; - c.ColumnSelectColor = Color.FromArgb(96, 128, 128, 128); - c.ColumnSeparatorColor = Color.Gold; - c.AlternateBackColor = Color.FromArgb(0x31, 0x31, 0x31); - c.AlternateCellForeColor = Color.WhiteSmoke; - - // image pane - c.PaneBackColor = Color.FromArgb(0x31, 0x31, 0x31); - c.PaneSeparatorColor = Color.Gold; - c.PaneLabelColor = SystemColors.GrayText; - - // selection rectangke - c.SelectionRectangleColor1 = Color.FromArgb(160, 96, 144, 240); - c.SelectionRectangleColor2 = Color.FromArgb(32, 96, 144, 240); - c.SelectionRectangleBorderColor = Color.FromArgb(64, 96, 144, 240); - - return c; - } - #endregion - - #region System.Object Overrides - /// - /// Determines whether all color values of the specified - /// ImageListViewColor are equal to this instance. - /// - /// The object to compare with this instance. - /// true if the two instances have the same color values; - /// otherwise false. - public override bool Equals(object obj) - { - if (obj == null) - throw new NullReferenceException(); - - ImageListViewColor other = obj as ImageListViewColor; - if (other == null) return false; - - foreach (PropertyInfo info in typeof(ImageListViewColor).GetProperties()) - { - // Walk through color properties - if (info.PropertyType == typeof(Color)) - { - // Compare colors - Color color1 = (Color)info.GetValue(this, null); - Color color2 = (Color)info.GetValue(other, null); - - if (color1 != color2) return false; - } - } - - return true; - } - /// - /// Returns a hash code for this instance. - /// - /// - /// A hash code for this instance, suitable for use in - /// hashing algorithms and data structures like a hash table. - /// - public override int GetHashCode() - { - return base.GetHashCode(); - } - - /// - /// Returns a string that represents this instance. - /// - /// - /// A string that represents this instance. - /// - public override string ToString() - { - ImageListViewColor colors = this; - - // First check if the color matches a predefined color setting - foreach (MemberInfo info in typeof(ImageListViewColor).GetMembers(BindingFlags.Static | BindingFlags.Public)) - { - if (info.MemberType == MemberTypes.Property) - { - PropertyInfo propertyInfo = (PropertyInfo)info; - if (propertyInfo.PropertyType == typeof(ImageListViewColor)) - { - ImageListViewColor presetValue = (ImageListViewColor)propertyInfo.GetValue(null, null); - // If the color setting is equal to a preset value - // return the name of the preset - if (colors.Equals(presetValue)) - return string.Format("({0})", propertyInfo.Name); - } - } - } - - // Serialize all colors which are different from the default setting - List lines = new List(); - foreach (PropertyInfo info in typeof(ImageListViewColor).GetProperties()) - { - // Walk through color properties - if (info.PropertyType == typeof(Color)) - { - // Get property name - string name = info.Name; - // Get the current value - Color color = (Color)info.GetValue(colors, null); - // Find the default value atribute - Attribute[] attributes = (Attribute[])info.GetCustomAttributes(typeof(DefaultValueAttribute), false); - if (attributes.Length != 0) - { - // Get the default value - DefaultValueAttribute attribute = (DefaultValueAttribute)attributes[0]; - Color defaultColor = (Color)attribute.Value; - // Serialize only if colors are different - if (color != defaultColor) - { - lines.Add(string.Format("{0} = {1}", name, color.Name)); - } - } - } - } - - return string.Join("; ", lines.ToArray()); - } - #endregion - } -} diff --git a/Source/Components/ImageGlass.ImageListView/ImageListViewColorTypeConverter.cs b/Source/Components/ImageGlass.ImageListView/ImageListViewColorTypeConverter.cs deleted file mode 100644 index 3a1e5560d..000000000 --- a/Source/Components/ImageGlass.ImageListView/ImageListViewColorTypeConverter.cs +++ /dev/null @@ -1,110 +0,0 @@ -// ImageListView - A listview control for image files -// Copyright (C) 2009 Ozgur Ozcitak -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// Ozgur Ozcitak (ozcitak@yahoo.com) - -using System; -using System.Globalization; -using System.ComponentModel; -using System.Reflection; -using System.ComponentModel.Design.Serialization; - -namespace ImageGlass.ImageListView -{ - /// - /// Represents type converter for the color palette of the image list view. - /// - internal class ImageListViewColorTypeConverter : ExpandableObjectConverter - { - #region TypeConverter Overrides - /// - /// Returns whether this converter can convert the - /// object to the specified type, using the specified context. - /// - /// Format context. - /// The type you want to convert to. - /// true if this converter can perform the conversion; otherwise, false. - public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType) - { - if (destinationType == typeof(string)) - return true; - else if (destinationType == typeof(InstanceDescriptor)) - return true; - - return base.CanConvertTo(context, destinationType); - } - /// - /// Returns whether this converter can convert an object of the given type - /// to the type of this converter, using the specified context. - /// - /// Format context. - /// The type you want to convert from. - /// true if this converter can perform the conversion; otherwise, false. - public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType) - { - if (sourceType == typeof(string)) - return true; - - return base.CanConvertFrom(context, sourceType); - } - /// - /// Converts the given value object to the specified type, - /// using the specified context and culture information. - /// - /// Format context. - /// The culture info. If null is passed, the current culture is assumed. - /// The objct to convert. - /// The type to convert to. - /// An object that represents the converted value. - public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType) - { - if (value != null && value is ImageListViewColor) - { - ImageListViewColor colors = (ImageListViewColor)value; - - if (destinationType == typeof(string)) - { - return colors.ToString(); - } - else if (destinationType == typeof(InstanceDescriptor)) - { - // Used by the designer serializer - ConstructorInfo consInfo = typeof(ImageListViewColor).GetConstructor(new Type[] { typeof(string) }); - return new InstanceDescriptor(consInfo, new object[] { colors.ToString() }); - } - } - - return base.ConvertTo(context, culture, value, destinationType); - } - /// - /// Converts the given object to the type of this converter, - /// using the specified context and culture information. - /// - /// Format context. - /// The culture info to use as the current culture. - /// The object to convert. - /// An object that represents the converted value. - public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) - { - if (value != null && value is string) - { - return new ImageListViewColor((string)value); - } - - return base.ConvertFrom(context, culture, value); - } - #endregion - } -} diff --git a/Source/Components/ImageGlass.ImageListView/ImageListViewColumnHeader.cs b/Source/Components/ImageGlass.ImageListView/ImageListViewColumnHeader.cs deleted file mode 100644 index 703db53b7..000000000 --- a/Source/Components/ImageGlass.ImageListView/ImageListViewColumnHeader.cs +++ /dev/null @@ -1,386 +0,0 @@ -// ImageListView - A listview control for image files -// Copyright (C) 2009 Ozgur Ozcitak -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// Ozgur Ozcitak (ozcitak@yahoo.com) - -using System; -using System.Windows.Forms; -using System.ComponentModel; -using System.Resources; - -namespace ImageGlass.ImageListView -{ - public partial class ImageListView - { - /// - /// Represents a column header displayed in details view mode. - /// - [TypeConverter(typeof(ImageListViewColumnHeaderTypeConverter))] - public class ImageListViewColumnHeader : ICloneable - { - #region Member Variables - private Guid mGuid; - private int mDisplayIndex; - internal ImageListView mImageListView; - private string mText; - private ColumnType mType; - private bool mVisible; - private int mWidth; - - internal ImageListViewColumnHeaderCollection owner; - #endregion - - #region Properties - /// - /// Gets the unique identifier for this item. - /// - [Category("Behavior"), Browsable(false), Description("Gets the unique identifier for this item.")] - internal Guid Guid { get { return mGuid; } private set { mGuid = value; } } - /// - /// Gets the default header text for this column type. - /// - [Category("Appearance"), Browsable(false), Description("Gets the default header text for this column type."), Localizable(true)] - public virtual string DefaultText - { - get - { - return GetDefaultText(mType); - } - } - /// - /// Gets or sets the display order of the column. - /// - [Category("Appearance"), Browsable(true), Description("Gets or sets the display order of the column.")] - public int DisplayIndex - { - get - { - return mDisplayIndex; - } - set - { - if (mDisplayIndex != value) - { - mDisplayIndex = value; - - if (owner != null) - owner.updateDisplayList = true; - - if (mImageListView != null) - mImageListView.Refresh(); - } - } - } - /// - /// Gets the ImageListView owning this item. - /// - [Category("Behavior"), Browsable(false), Description("Gets the ImageListView owning this item.")] - public ImageListView ImageListView { get { return mImageListView; } } - /// - /// Gets or sets the column header text. - /// - [Category("Appearance"), Browsable(true), Description("Gets or sets the column header text.")] - public string Text - { - get - { - if (!string.IsNullOrEmpty(mText)) - return mText; - else - return DefaultText; - } - set - { - mText = value; - if (mImageListView != null) - mImageListView.Refresh(); - } - } - /// - /// Gets or sets the type of information displayed by the column. - /// - [Category("Appearance"), Browsable(true), Description("Gets or sets the type of information displayed by the column.")] - public ColumnType Type - { - get - { - return mType; - } - set - { - ColumnType oldType = mType; - - if (owner != null && oldType == ColumnType.Custom) - { - if (mImageListView == null) - throw new InvalidOperationException("Owner control is null."); - mImageListView.Items.RemoveCustomColumn(mGuid); - } - - mType = value; - - if (owner != null && mType == ColumnType.Custom) - { - if (mImageListView == null) - throw new InvalidOperationException("Owner control is null."); - mImageListView.Items.AddCustomColumn(mGuid); - } - } - } - /// - /// Gets or sets a value indicating whether the control is displayed. - /// - [Category("Appearance"), Browsable(true), Description("Gets or sets a value indicating whether the control is displayed."), DefaultValue(true)] - public bool Visible - { - get - { - return mVisible; - } - set - { - mVisible = value; - - if (owner != null) - owner.updateDisplayList = true; - - if (mImageListView != null) - mImageListView.Refresh(); - } - } - /// - /// Gets or sets the column width. - /// - [Category("Appearance"), Browsable(true), Description("Gets or sets the column width."), DefaultValue(ImageListView.DefaultColumnWidth)] - public int Width - { - get - { - return mWidth; - } - set - { - mWidth = System.Math.Max(12, value); - if (mImageListView != null) - mImageListView.Refresh(); - } - } - #endregion - - #region Custom Property Serializers - /// - /// Determines if the column text should be serialized. - /// - /// true if the designer should serialize - /// the property; otherwise false. - public bool ShouldSerializeText() - { - return Text != DefaultText; - } - /// - /// Resets the column text to its default value. - /// - public void ResetText() - { - Text = DefaultText; - } - #endregion - - #region Constructors - /// - /// Initializes a new instance of the ImageListViewColumnHeader class. - /// - /// The type of data to display in this column. - /// Text of the column header. - /// Width in pixels of the column header. - /// Display order of the column. - /// Whether the column is initially visible. - public ImageListViewColumnHeader(ColumnType type, string text, int width, int displayIndex, bool visible) - { - mImageListView = null; - owner = null; - mGuid = Guid.NewGuid(); - mText = text; - mType = type; - mWidth = width; - mVisible = visible; - mDisplayIndex = displayIndex; - } - /// - /// Initializes a new instance of the ImageListViewColumnHeader class. - /// - /// The type of data to display in this column. - /// Text of the column header. - /// Width in pixels of the column header. - /// Display order of the column. - public ImageListViewColumnHeader(ColumnType type, string text, int width, int displayIndex) - : this(type, text, width, displayIndex, true) - { - ; - } - /// - /// Initializes a new instance of the ImageListViewColumnHeader class. - /// - /// The type of data to display in this column. - /// Width in pixels of the column header. - /// Display order of the column. - public ImageListViewColumnHeader(ColumnType type, int width, int displayIndex) - : this(type, "", width, displayIndex) - { - ; - } - /// - /// Initializes a new instance of the ImageListViewColumnHeader class. - /// - /// The type of data to display in this column. - /// Text of the column header. - /// Width in pixels of the column header. - public ImageListViewColumnHeader(ColumnType type, string text, int width) - : this(type, text, width, -1) - { - ; - } - /// - /// Initializes a new instance of the ImageListViewColumnHeader class. - /// - /// The type of data to display in this column. - /// Text of the column header. - public ImageListViewColumnHeader(ColumnType type, string text) - : this(type, text, ImageListView.DefaultColumnWidth) - { - ; - } - /// - /// Initializes a new instance of the ImageListViewColumnHeader class. - /// - /// The type of data to display in this column. - /// Width in pixels of the column header. - public ImageListViewColumnHeader(ColumnType type, int width) - : this(type, "", width) - { - ; - } - /// - /// Initializes a new instance of the ImageListViewColumnHeader class. - /// - /// The type of data to display in this column. - public ImageListViewColumnHeader(ColumnType type) - : this(type, "", ImageListView.DefaultColumnWidth) - { - ; - } - /// - /// Initializes a new instance of the ImageListViewColumnHeader class. - /// - public ImageListViewColumnHeader() - : this(ColumnType.Name) - { - ; - } - #endregion - - #region Instance Methods - /// - /// Resizes the width of the column based on the length of the column content. - /// - public void AutoFit() - { - if (mImageListView == null) - throw new InvalidOperationException("Cannot calculate column width. Owner image list view is null."); - - int width = 0; - if (mType == ColumnType.Rating) - { - if (mImageListView.RatingImage != null) - width = mImageListView.RatingImage.Width * 5; - } - else if (mType == ColumnType.Custom) - { - foreach (ImageListViewItem item in mImageListView.Items) - { - int itemwidth = TextRenderer.MeasureText(item.GetSubItemText(mGuid), mImageListView.Font).Width; - width = System.Math.Max(width, itemwidth); - } - } - else - { - foreach (ImageListViewItem item in mImageListView.Items) - { - int itemwidth = TextRenderer.MeasureText(item.GetSubItemText(Type), mImageListView.Font).Width; - width = System.Math.Max(width, itemwidth); - } - } - - // Add space for checkboxes and file icon - if (mType == ColumnType.Name) - { - if (ImageListView.ShowCheckBoxes && ImageListView.ShowFileIcons) - width += 2 * 16 + 3 * 2; - else if (ImageListView.ShowCheckBoxes) - width += 16 + 2 * 2; - else if (ImageListView.ShowFileIcons) - width += 16 + 2 * 2; - } - - Width = width + 8; - mImageListView.Refresh(); - } - /// - /// Returns a that represents this instance. - /// - /// - /// A that represents this instance. - /// - public override string ToString() - { - return mType.ToString(); - } - #endregion - - #region Helper Methods - /// - /// Gets the default column header text for the given column type. - /// - [Localizable(true)] - private string GetDefaultText(ColumnType type) - { - ResourceManager manager = new ResourceManager("ImageGlass.ImageListView.ImageListViewResources", GetType().Assembly); - return manager.GetString(type.ToString()); - } - #endregion - - #region ICloneable Members - /// - /// Creates a new object that is a copy of the current instance. - /// - /// - /// A new object that is a copy of this instance. - /// - public object Clone() - { - ImageListViewColumnHeader column = new ImageListViewColumnHeader(); - - column.mDisplayIndex = mDisplayIndex; - column.mText = mText; - column.mType = mType; - column.mVisible = mVisible; - column.mWidth = mWidth; - - return column; - } - #endregion - } - } -} diff --git a/Source/Components/ImageGlass.ImageListView/ImageListViewColumnHeaderCollection.cs b/Source/Components/ImageGlass.ImageListView/ImageListViewColumnHeaderCollection.cs deleted file mode 100644 index 3c701ac90..000000000 --- a/Source/Components/ImageGlass.ImageListView/ImageListViewColumnHeaderCollection.cs +++ /dev/null @@ -1,469 +0,0 @@ -// ImageListView - A listview control for image files -// Copyright (C) 2009 Ozgur Ozcitak -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// Ozgur Ozcitak (ozcitak@yahoo.com) - -using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.Collections; - -namespace ImageGlass.ImageListView -{ - public partial class ImageListView - { - /// - /// Represents the collection of columns in an ImageListView control. - /// - public class ImageListViewColumnHeaderCollection : IList, ICollection, IList, IEnumerable - { - #region Member Variables - private ImageListView mImageListView; - private List mItems; - private List mDisplayedItems; - internal bool updateDisplayList; - #endregion - - #region Properties - /// - /// Gets the number of columns in the collection. - /// - [Category("Behavior"), Browsable(false), Description("Gets the number of columns in the collection.")] - public int Count { get { return mItems.Count; } } - /// - /// Gets the ImageListView owning this collection. - /// - [Category("Behavior"), Browsable(false), Description("Gets the ImageListView owning this collection.")] - public ImageListView ImageListView { get { return mImageListView; } } - /// - /// Gets the column at the specified index within the collection. - /// - [Category("Behavior"), Browsable(false), Description("Gets or item at the specified index within the collection.")] - public ImageListViewColumnHeader this[int index] - { - get - { - return mItems[index]; - } - set - { - ImageListViewColumnHeader oldItem = mItems[index]; - - if (oldItem.Type == ColumnType.Custom) - { - if (mImageListView == null) - throw new InvalidOperationException("Owner control is null."); - mImageListView.Items.RemoveCustomColumn(oldItem.Guid); - } - - ImageListViewColumnHeader newItem = value; - mItems[index] = newItem; - - if (newItem.Type == ColumnType.Custom) - { - if (mImageListView == null) - throw new InvalidOperationException("Owner control is null."); - mImageListView.Items.AddCustomColumn(newItem.Guid); - } - - updateDisplayList = true; - } - } - /// - /// Gets the column with the specified type within the collection. - /// - [Category("Behavior"), Browsable(false), Description("Gets or sets the item with the specified type within the collection.")] - public ImageListViewColumnHeader this[ColumnType type] - { - get - { - if (type == ColumnType.Custom) - throw new ArgumentException("Column type is ambiguous. You must access custom columns by index.", "type"); - - foreach (ImageListViewColumnHeader column in this) - if (column.Type == type) return column; - throw new ArgumentException("Unknown column type.", "type"); - } - } - /// - /// Gets a value indicating whether the Collection is read-only. - /// - [Category("Behavior"), Browsable(false), Description("Gets a value indicating whether the Collection is read-only.")] - public bool IsReadOnly - { - get { return false; } - } - #endregion - - #region Constructors - /// - /// Initializes a new instance of the ImageListViewColumnHeaderCollection class. - /// - /// The owner control. - internal ImageListViewColumnHeaderCollection(ImageListView owner) - { - mImageListView = owner; - mItems = new List(); - updateDisplayList = true; - } - #endregion - - #region Instance Methods - /// - /// Adds an item to the . - /// - /// The object to add to the . - public void Add(ImageListViewColumnHeader item) - { - if (mImageListView == null) - throw new InvalidOperationException("Owner control is null."); - - item.mImageListView = mImageListView; - item.owner = this; - if (item.DisplayIndex == -1) - item.DisplayIndex = mItems.Count; - - mItems.Add(item); - - if (item.Type == ColumnType.Custom) - mImageListView.Items.AddCustomColumn(item.Guid); - - updateDisplayList = true; - } - /// - /// Adds an item to the . - /// - /// The type of data to display in this column. - /// Text of the column header. - /// Width in pixels of the column header. - public void Add(ColumnType type, string text, int width) - { - Add(new ImageListViewColumnHeader(type, text, width)); - } - /// - /// Adds an item to the . - /// - /// The type of data to display in this column. - /// Text of the column header. - public void Add(ColumnType type, string text) - { - Add(new ImageListViewColumnHeader(type, text)); - } - /// - /// Adds an item to the . - /// - /// The type of data to display in this column. - /// Width in pixels of the column header. - public void Add(ColumnType type, int width) - { - Add(new ImageListViewColumnHeader(type, width)); - } - /// - /// Adds an item to the . - /// - /// The type of data to display in this column. - public void Add(ColumnType type) - { - Add(new ImageListViewColumnHeader(type)); - } - /// - /// Adds a range of items to the . - /// - /// The items to add to the collection. - public void AddRange(ImageListViewColumnHeader[] items) - { - if (mImageListView != null) - mImageListView.SuspendPaint(); - - foreach (ImageListViewColumnHeader item in items) - Add(item); - - if (mImageListView != null) - { - mImageListView.Refresh(); - mImageListView.ResumePaint(); - } - } - /// - /// Removes all items from the . - /// - public void Clear() - { - mItems.Clear(); - if (mImageListView != null) - mImageListView.Items.RemoveAllCustomColumns(); - updateDisplayList = true; - } - /// - /// Determines whether the contains a specific value. - /// - /// The object to locate in the . - /// - /// true if is found in the ; otherwise, false. - /// - public bool Contains(ImageListViewColumnHeader item) - { - return mItems.Contains(item); - } - /// - /// Returns an enumerator to use to iterate through columns. - /// - /// An IEnumerator<ImageListViewColumn> that represents the item collection. - public IEnumerator GetEnumerator() - { - foreach (ImageListViewColumnHeader column in mItems) - yield return column; - yield break; - } - /// - /// Determines the index of a specific item in the . - /// - /// The object to locate in the . - /// - /// The index of if found in the list; otherwise, -1. - /// - public int IndexOf(ImageListViewColumnHeader item) - { - return mItems.IndexOf(item); - } - /// - /// Inserts an item to the at the specified index. - /// - /// The zero-based index at which should be inserted. - /// The object to insert into the . - public void Insert(int index, ImageListViewColumnHeader item) - { - if (mImageListView == null) - throw new InvalidOperationException("Owner control is null."); - - item.mImageListView = mImageListView; - item.owner = this; - if (item.DisplayIndex == -1) - { - foreach (ImageListViewColumnHeader col in mItems) - if (col.DisplayIndex >= index) - col.DisplayIndex++; - item.DisplayIndex = index; - } - - mItems.Insert(index, item); - if (item.Type == ColumnType.Custom) - mImageListView.Items.AddCustomColumn(item.Guid); - - updateDisplayList = true; - } - /// - /// Removes the first occurrence of a specific object from the . - /// - /// The object to remove from the . - /// - /// true if was successfully removed from the ; otherwise, false. This method also returns false if is not found in the original . - /// - public bool Remove(ImageListViewColumnHeader item) - { - bool exists = mItems.Remove(item); - if (item.Type == ColumnType.Custom) - { - if (mImageListView == null) - throw new InvalidOperationException("Owner control is null."); - mImageListView.Items.RemoveCustomColumn(item.Guid); - } - updateDisplayList = true; - return exists; - } - /// - /// Removes the item at the specified index. - /// - /// The zero-based index of the item to remove. - public void RemoveAt(int index) - { - mItems.RemoveAt(index); - ImageListViewColumnHeader item = mItems[index]; - if (item.Type == ColumnType.Custom) - { - if (mImageListView == null) - throw new InvalidOperationException("Owner control is null."); - mImageListView.Items.RemoveCustomColumn(item.Guid); - } - updateDisplayList = true; - } - #endregion - - #region Helper Methods - /// - /// Determines whether the collection has the given column type. - /// - /// The type of column. - internal bool HasType(ColumnType type) - { - if (type == ColumnType.Custom) - throw new ArgumentException("Column type is ambiguous. You must access custom columns by index.", "type"); - - foreach (ImageListViewColumnHeader column in this) - if (column.Type == type) return true; - - return false; - } - /// - /// Gets the columns as diplayed on the UI. - /// - /// The list of of visible columns. - public List GetDisplayedColumns() - { - if (mDisplayedItems != null && !updateDisplayList) - return mDisplayedItems; - - mDisplayedItems = new List(); - foreach (ImageListViewColumnHeader column in mItems) - { - if (column.Visible) - mDisplayedItems.Add(column); - } - mDisplayedItems.Sort(ColumnCompare); - - updateDisplayList = false; - return mDisplayedItems; - } - /// - /// Compares the columns by their display index. - /// - internal static int ColumnCompare(ImageListViewColumnHeader a, ImageListViewColumnHeader b) - { - if (a.DisplayIndex < b.DisplayIndex) - return -1; - else if (a.DisplayIndex > b.DisplayIndex) - return 1; - else - return 0; - } - #endregion - - #region Unsupported Interface - /// - /// Returns an enumerator that iterates through a collection. - /// - IEnumerator IEnumerable.GetEnumerator() - { - return GetEnumerator(); - } - /// - /// Copies the elements of the to an , starting at a particular index. - /// - /// The one-dimensional that is the destination of the elements copied from . The must have zero-based indexing. - /// The zero-based index in at which copying begins. - void ICollection.CopyTo(Array array, int index) - { - if (!(array is ImageListViewColumnHeader[])) - throw new ArgumentException("An array of ImageListViewColumnHeader is required.", "array"); - mItems.CopyTo((ImageListViewColumnHeader[])array, index); - } - /// - /// Copies the elements of the to an , starting at a particular index. - /// - /// The one-dimensional that is the destination of the elements copied from . The must have zero-based indexing. - /// The zero-based index in at which copying begins. - void ICollection.CopyTo(ImageListViewColumnHeader[] array, int arrayIndex) - { - mItems.CopyTo(array, arrayIndex); - } - /// - /// Gets a value indicating whether access to the is synchronized (thread safe). - /// - bool ICollection.IsSynchronized - { - get { return false; } - } - /// - /// Gets an object that can be used to synchronize access to the . - /// - object ICollection.SyncRoot - { - get { throw new NotImplementedException(); } - } - /// - /// Adds an item to the . - /// - int IList.Add(object value) - { - if (!(value is ImageListViewColumnHeader)) - throw new ArgumentException("An object of type ImageListViewColumnHeader is required.", "value"); - ImageListViewColumnHeader item = (ImageListViewColumnHeader)value; - Add(item); - return mItems.IndexOf(item); - } - /// - /// Determines whether the contains a specific value. - /// - bool IList.Contains(object value) - { - if (!(value is ImageListViewColumnHeader)) - throw new ArgumentException("An object of type ImageListViewColumnHeader is required.", "value"); - return mItems.Contains((ImageListViewColumnHeader)value); - } - /// - /// Determines the index of a specific item in the . - /// - int IList.IndexOf(object value) - { - if (!(value is ImageListViewColumnHeader)) - throw new ArgumentException("An object of type ImageListViewColumnHeader is required.", "value"); - return IndexOf((ImageListViewColumnHeader)value); - } - /// - /// Inserts an item to the at the specified index. - /// - void IList.Insert(int index, object value) - { - if (!(value is ImageListViewColumnHeader)) - throw new ArgumentException("An object of type ImageListViewColumnHeader is required.", "value"); - Insert(index, (ImageListViewColumnHeader)value); - } - /// - /// Gets a value indicating whether the has a fixed size. - /// - bool IList.IsFixedSize - { - get { return false; } - } - /// - /// Removes the first occurrence of a specific object from the . - /// - void IList.Remove(object value) - { - if (!(value is ImageListViewColumnHeader)) - throw new ArgumentException("An object of type ImageListViewColumnHeader is required.", "value"); - Remove((ImageListViewColumnHeader)value); - } - /// - /// Gets or sets the at the specified index. - /// - object IList.this[int index] - { - get - { - return this[index]; - } - set - { - if (!(value is ImageListViewColumnHeader)) - throw new ArgumentException("An object of type ImageListViewColumnHeader is required.", "value"); - this[index] = (ImageListViewColumnHeader)value; - updateDisplayList = true; - } - } - #endregion - } - } -} \ No newline at end of file diff --git a/Source/Components/ImageGlass.ImageListView/ImageListViewColumnHeaderTypeConverter.cs b/Source/Components/ImageGlass.ImageListView/ImageListViewColumnHeaderTypeConverter.cs deleted file mode 100644 index aaf19fd36..000000000 --- a/Source/Components/ImageGlass.ImageListView/ImageListViewColumnHeaderTypeConverter.cs +++ /dev/null @@ -1,81 +0,0 @@ -// ImageListView - A listview control for image files -// Copyright (C) 2009 Ozgur Ozcitak -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// Ozgur Ozcitak (ozcitak@yahoo.com) - -using System; -using System.Globalization; -using System.ComponentModel; -using System.Reflection; -using System.ComponentModel.Design.Serialization; - -namespace ImageGlass.ImageListView -{ - /// - /// Represents the type converter for the column headers of the image list view. - /// - internal class ImageListViewColumnHeaderTypeConverter : TypeConverter - { - #region TypeConverter Overrides - /// - /// Returns whether this converter can convert the - /// object to the specified type, using the specified context. - /// - /// Format context. - /// The type you want to convert to. - /// true if this converter can perform the conversion; otherwise, false. - public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType) - { - if (destinationType == typeof(InstanceDescriptor)) - return true; - - return base.CanConvertTo(context, destinationType); - } - /// - /// Converts the given value object to the specified type, - /// using the specified context and culture information. - /// - /// Format context. - /// The culture info. If null is passed, the current culture is assumed. - /// The objct to convert. - /// The type to convert to. - /// An object that represents the converted value. - public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType) - { - if (value != null && value is ImageListView.ImageListViewColumnHeader) - { - ImageListView.ImageListViewColumnHeader column = (ImageListView.ImageListViewColumnHeader)value; - - if (destinationType == typeof(InstanceDescriptor)) - { - string text = column.Text; - // Used by the designer serializer - if (text == column.DefaultText) - text = string.Empty; - - ConstructorInfo consInfo = typeof(ImageListView.ImageListViewColumnHeader).GetConstructor(new Type[] { - typeof(ColumnType), typeof(string), typeof(int), typeof(int), typeof(bool) - }); - return new InstanceDescriptor(consInfo, new object[] { - column.Type, text, column.Width, column.DisplayIndex, column.Visible - }); - } - } - - return base.ConvertTo(context, culture, value, destinationType); - } - #endregion - } -} diff --git a/Source/Components/ImageGlass.ImageListView/ImageListViewDesigner.cs b/Source/Components/ImageGlass.ImageListView/ImageListViewDesigner.cs deleted file mode 100644 index 50e3c911e..000000000 --- a/Source/Components/ImageGlass.ImageListView/ImageListViewDesigner.cs +++ /dev/null @@ -1,281 +0,0 @@ -// ImageListView - A listview control for image files -// Copyright (C) 2009 Ozgur Ozcitak -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// Ozgur Ozcitak (ozcitak@yahoo.com) - -using System; -using System.Windows.Forms; -using System.ComponentModel; -using System.Drawing.Design; -using System.ComponentModel.Design; -using System.Windows.Forms.Design; - -namespace ImageGlass.ImageListView -{ - /// - /// Represents the designer of the image list view. - /// - internal class ImageListViewDesigner : ControlDesigner - { - #region Member Variables - private DesignerActionListCollection actionLists = null; - #endregion - - #region Designer Action Lists - /// - /// Gets the design-time action lists supported by the component associated with the designer. - /// - public override DesignerActionListCollection ActionLists - { - get - { - if (actionLists == null) - { - actionLists = base.ActionLists; - actionLists.Add(new ImageListViewActionLists(Component)); - } - return actionLists; - } - } - #endregion - } - - /// - /// Defines smart tag entries for the image list view. - /// - internal class ImageListViewActionLists : DesignerActionList, IServiceProvider, IWindowsFormsEditorService, ITypeDescriptorContext - { - #region Member Variables - private ImageListView imageListView; - private DesignerActionUIService designerService; - - private PropertyDescriptor columnProperty; - private PropertyDescriptor itemProperty; - #endregion - - #region Constructor - /// - /// Initializes a new instance of the ImageListViewActionLists class. - /// - /// A component related to the DesignerActionList. - public ImageListViewActionLists(IComponent component) - : base(component) - { - imageListView = (ImageListView)component; - - designerService = (DesignerActionUIService)GetService(typeof(DesignerActionUIService)); - } - #endregion - - #region Helper Methods - /// - /// Helper method to retrieve control properties for undo support. - /// - /// Property name. - private PropertyDescriptor GetPropertyByName(String propName) - { - PropertyDescriptor prop; - prop = TypeDescriptor.GetProperties(imageListView)[propName]; - if (prop == null) - throw new ArgumentException("Unknown property.", propName); - else - return prop; - } - #endregion - - #region Properties - /// - /// Gets or sets the sort column of the designed ImageListView. - /// - public int SortColumn - { - get { return imageListView.SortColumn; } - set { GetPropertyByName("SortColumn").SetValue(imageListView, value); } - } - /// - /// Gets or sets the sort oerder of the designed ImageListView. - /// - public SortOrder SortOrder - { - get { return imageListView.SortOrder; } - set { GetPropertyByName("SortOrder").SetValue(imageListView, value); } - } - /// - /// Gets or sets the view mode of the designed ImageListView. - /// - public View View - { - get { return imageListView.View; } - set { GetPropertyByName("View").SetValue(imageListView, value); } - } - #endregion - - #region Instance Methods - /// - /// Invokes the editor for the columns of the designed ImageListView. - /// - public void EditColumns() - { - // IComponentChangeService is used to pass change notifications to the designer - IComponentChangeService ccs = (IComponentChangeService)GetService(typeof(IComponentChangeService)); - - // Get the collection editor - columnProperty = GetPropertyByName("Columns"); - UITypeEditor editor = (UITypeEditor)columnProperty.GetEditor(typeof(UITypeEditor)); - object value = imageListView.Columns; - - // Notify the designers of the change - if (ccs != null) - ccs.OnComponentChanging(imageListView, columnProperty); - - // Edit the value - value = editor.EditValue(this, this, value); - imageListView.Columns = (ImageListView.ImageListViewColumnHeaderCollection)value; - - // Notify the designers of the change - if (ccs != null) - ccs.OnComponentChanged(imageListView, columnProperty, null, null); - - designerService.Refresh(Component); - } - /// - /// Invokes the editor for the items of the designed ImageListView. - /// - public void EditItems() - { - // IComponentChangeService is used to pass change notifications to the designer - IComponentChangeService ccs = (IComponentChangeService)GetService(typeof(IComponentChangeService)); - - // Get the collection editor - itemProperty = GetPropertyByName("Items"); - UITypeEditor editor = (UITypeEditor)itemProperty.GetEditor(typeof(UITypeEditor)); - object value = imageListView.Items; - - // Notify the designers of the change - if (ccs != null) - ccs.OnComponentChanging(imageListView, itemProperty); - - // Edit the value - value = editor.EditValue(this, this, value); - imageListView.Items = (ImageListView.ImageListViewItemCollection)value; - - // Notify the designers of the change - if (ccs != null) - ccs.OnComponentChanged(imageListView, itemProperty, null, null); - - designerService.Refresh(Component); - } - #endregion - - #region DesignerActionList Overrides - /// - /// Returns the collection of objects contained in the list. - /// - public override DesignerActionItemCollection GetSortedActionItems() - { - DesignerActionItemCollection items = new DesignerActionItemCollection(); - - items.Add(new DesignerActionMethodItem(this, "EditItems", "Edit Items", true)); - items.Add(new DesignerActionMethodItem(this, "EditColumns", "Edit Columns", true)); - - items.Add(new DesignerActionPropertyItem("View", "View")); - items.Add(new DesignerActionPropertyItem("SortColumn", "SortColumn")); - items.Add(new DesignerActionPropertyItem("SortOrder", "SortOrder")); - - return items; - } - #endregion - - #region IServiceProvider Members - /// - /// Returns an object that represents a service provided by the component - /// associated with the . - /// - object IServiceProvider.GetService(Type serviceType) - { - if (serviceType.Equals(typeof(IWindowsFormsEditorService))) - { - return this; - } - return GetService(serviceType); - } - #endregion - - #region IWindowsFormsEditorService Members - /// - /// Closes any previously opened drop down control area. - /// - void IWindowsFormsEditorService.CloseDropDown() - { - throw new NotSupportedException("Only modal dialogs are supported."); - } - /// - /// Displays the specified control in a drop down area below a value - /// field of the property grid that provides this service. - /// - void IWindowsFormsEditorService.DropDownControl(Control control) - { - throw new NotSupportedException("Only modal dialogs are supported."); - } - /// - /// Shows the specified . - /// - DialogResult IWindowsFormsEditorService.ShowDialog(Form dialog) - { - return (dialog.ShowDialog()); - } - #endregion - - #region ITypeDescriptorContext Members - /// - /// Gets the container representing this - /// request. - /// - IContainer ITypeDescriptorContext.Container - { - get { return null; } - } - /// - /// Gets the object that is connected with this type descriptor request. - /// - object ITypeDescriptorContext.Instance - { - get { return imageListView; } - } - /// - /// Raises the event. - /// - void ITypeDescriptorContext.OnComponentChanged() - { - ; - } - /// - /// Raises the event. - /// - bool ITypeDescriptorContext.OnComponentChanging() - { - return true; - } - /// - /// Gets the - /// that is associated with the given context item. - /// - PropertyDescriptor ITypeDescriptorContext.PropertyDescriptor - { - get { return columnProperty; } - } - #endregion - } -} diff --git a/Source/Components/ImageGlass.ImageListView/ImageListViewGroup.cs b/Source/Components/ImageGlass.ImageListView/ImageListViewGroup.cs deleted file mode 100644 index 30854cee3..000000000 --- a/Source/Components/ImageGlass.ImageListView/ImageListViewGroup.cs +++ /dev/null @@ -1,202 +0,0 @@ -// ImageListView - A listview control for image files -// Copyright (C) 2009 Ozgur Ozcitak -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// Ozgur Ozcitak (ozcitak@yahoo.com) - -using System; -using System.Collections.Generic; -using System.Collections; -using System.Drawing; -using System.Windows.Forms; - -namespace ImageGlass.ImageListView -{ - public partial class ImageListView - { - /// - /// Represents the collection of items in a group in an ImageListView control. - /// - public class ImageListViewGroup : IEnumerable, IEnumerable, IComparable - { - #region Member Variables - internal ImageListView mImageListView; - internal ImageListViewGroupCollection owner; - private bool mCollapsed; - // Layout variables - internal int itemCols; - internal int itemRows; - internal Rectangle itemBounds; - internal Rectangle headerBounds; - internal bool isVisible; - #endregion - - #region Properties - /// - /// Gets the name of the group. - /// - public string Name { get; private set; } - /// - /// Gets the index of the first item. - /// - public int FirstItemIndex { get; internal set; } - /// - /// Gets the index of the last item. - /// - public int LastItemIndex { get; internal set; } - /// - /// Gets or sets whether the group is collapsed. - /// - public bool Collapsed - { - get - { - return mCollapsed; - } - set - { - if (value != mCollapsed) - { - mCollapsed = value; - if (owner != null) - owner.collectionModified = true; - if (mImageListView != null) - mImageListView.Refresh(); - } - } - } - /// - /// Gets the item count. - /// - public int ItemCount { get { return LastItemIndex - FirstItemIndex + 1; } } - #endregion - - #region Constructor - /// - /// Initializes a new instance of the class. - /// - /// The name of the group. - /// The index of the first item. - /// The index of the last item. - internal ImageListViewGroup(string name, int firstItemIndex, int lastItemIndex) - { - mImageListView = null; - owner = null; - Name = name; - mCollapsed = false; - FirstItemIndex = firstItemIndex; - LastItemIndex = lastItemIndex; - } - #endregion - - #region Instance Methods - /// - /// Returns an enumerator that iterates through the collection. - /// - /// - /// A that can be used to iterate through the collection. - /// - public IEnumerator GetEnumerator() - { - for (int i = FirstItemIndex; i <= LastItemIndex; i++) - yield return mImageListView.Items[i]; - yield break; - } - /// - /// Returns an enumerator that iterates through a collection. - /// - /// - /// An object that can be used to iterate through the collection. - /// - IEnumerator IEnumerable.GetEnumerator() - { - return GetEnumerator(); - } - /// - /// Compares the current object with another object of the same type. - /// - /// An object to compare with this object. - /// - /// A 32-bit signed integer that indicates the relative order of the objects being compared. The return value has the following meanings: - /// Value - /// Meaning - /// Less than zero - /// This object is less than the parameter. - /// Zero - /// This object is equal to . - /// Greater than zero - /// This object is greater than . - /// - public int CompareTo(ImageListViewGroup other) - { - return string.Compare(Name, other.Name); - } - #endregion - - #region Helper Methods - /// - /// Determines which items in the group intersect with the given - /// selection rectangle. - /// - /// The selection rectangle. - /// Scroll orientation of the owner control. - /// The size of one item including margins. - /// List of item indices. - public List ItemIndicesInRectangle(Rectangle rec, ScrollOrientation orientation, Size itemSize) - { - List items = new List(); - if (rec.Top <= itemBounds.Bottom && rec.Bottom >= itemBounds.Top && - rec.Left <= itemBounds.Right && rec.Right >= itemBounds.Left) - { - if (orientation == ScrollOrientation.HorizontalScroll) - { - int startCol = (int)Math.Floor((float)(rec.Left - itemBounds.Left) / (float)itemSize.Width); - int endCol = (int)Math.Floor((float)(rec.Right - itemBounds.Left) / (float)itemSize.Width); - - startCol = Math.Min(itemCols, Math.Max(0, startCol)); - endCol = Math.Min(itemCols, Math.Max(0, endCol)); - - for (int i = FirstItemIndex + startCol; i <= FirstItemIndex + endCol; i++) - { - items.Add(i); - } - } - else if (orientation == ScrollOrientation.VerticalScroll) - { - int startRow = (int)Math.Floor((float)(rec.Top - itemBounds.Top) / (float)itemSize.Height); - int endRow = (int)Math.Floor((float)(rec.Bottom - itemBounds.Top) / (float)itemSize.Height); - int startCol = (int)Math.Floor((float)(rec.Left - itemBounds.Left) / (float)itemSize.Width); - int endCol = (int)Math.Floor((float)(rec.Right - itemBounds.Left) / (float)itemSize.Width); - - startRow = Math.Min(itemRows - 1, Math.Max(0, startRow)); - endRow = Math.Min(itemRows - 1, Math.Max(0, endRow)); - startCol = Math.Min(itemCols - 1, Math.Max(0, startCol)); - endCol = Math.Min(itemCols - 1, Math.Max(0, endCol)); - - for (int row = startRow; row <= endRow; row++) - { - for (int col = startCol; col <= endCol; col++) - { - int i = FirstItemIndex + row * itemCols + col; - items.Add(i); - } - } - } - } - return items; - } - #endregion - } - } -} \ No newline at end of file diff --git a/Source/Components/ImageGlass.ImageListView/ImageListViewGroupCollection.cs b/Source/Components/ImageGlass.ImageListView/ImageListViewGroupCollection.cs deleted file mode 100644 index 4b044b00a..000000000 --- a/Source/Components/ImageGlass.ImageListView/ImageListViewGroupCollection.cs +++ /dev/null @@ -1,351 +0,0 @@ -// ImageListView - A listview control for image files -// Copyright (C) 2009 Ozgur Ozcitak -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// Ozgur Ozcitak (ozcitak@yahoo.com) - -using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.Collections; - -namespace ImageGlass.ImageListView -{ - public partial class ImageListView - { - /// - /// Represents the collection of groups in an ImageListView control. - /// - internal class ImageListViewGroupCollection : IList, ICollection, IList, IEnumerable - { - #region Member Variables - private ImageListView mImageListView; - private List mItems; - internal bool collectionModified; - #endregion - - #region Properties - /// - /// Gets the number of groups in the collection. - /// - [Category("Behavior"), Browsable(false), Description("Gets the number of groups in the collection.")] - public int Count { get { return mItems.Count; } } - /// - /// Gets the ImageListView owning this collection. - /// - [Category("Behavior"), Browsable(false), Description("Gets the ImageListView owning this collection.")] - public ImageListView ImageListView { get { return mImageListView; } } - /// - /// Gets or sets the group at the specified index within the collection. - /// - [Category("Behavior"), Browsable(false), Description("Gets or sets the group at the specified index within the collection.")] - public ImageListViewGroup this[int index] - { - get - { - return mItems[index]; - } - set - { - mItems[index] = value; - collectionModified = true; - } - } - /// - /// Gets the group with the specified name within the collection. - /// - [Category("Behavior"), Browsable(false), Description("Gets the group with the specified name within the collection.")] - public ImageListViewGroup this[string name] - { - get - { - foreach (ImageListViewGroup group in this) - if (string.Compare(group.Name, name) == 0) return group; - throw new ArgumentException("Unknown group name.", "name"); - } - } - /// - /// Gets a value indicating whether the Collection is read-only. - /// - [Category("Behavior"), Browsable(false), Description("Gets a value indicating whether the Collection is read-only.")] - public bool IsReadOnly - { - get { return false; } - } - #endregion - - #region Constructor - /// - /// Initializes a new instance of the ImageListViewGroup class. - /// - /// The owner control. - internal ImageListViewGroupCollection(ImageListView owner) - { - mImageListView = owner; - mItems = new List(); - collectionModified = true; - } - #endregion - - #region Instance Methods - /// - /// Adds an item to the . - /// - /// The object to add to the . - public void Add(ImageListViewGroup item) - { - if (mImageListView == null) - throw new InvalidOperationException("Owner control is null."); - - item.mImageListView = mImageListView; - item.owner = this; - - mItems.Add(item); - - collectionModified = true; - } - /// - /// Adds an item to the . - /// - /// The name of the group. - /// The index of the first item. - /// The index of the last item. - public void Add(string name, int firstItemIndex, int lastItemIndex) - { - Add(new ImageListViewGroup(name, firstItemIndex, lastItemIndex)); - } - - /// - /// Removes all items from the . - /// - public void Clear() - { - mItems.Clear(); - - collectionModified = true; - } - /// - /// Determines whether the contains a specific value. - /// - /// The object to locate in the . - /// - /// true if is found in the ; otherwise, false. - /// - public bool Contains(ImageListViewGroup item) - { - return mItems.Contains(item); - } - /// - /// Returns an enumerator to use to iterate through columns. - /// - /// An IEnumerator<ImageListViewColumn> that represents the item collection. - public IEnumerator GetEnumerator() - { - foreach (ImageListViewGroup group in mItems) - yield return group; - yield break; - } - /// - /// Determines the index of a specific item in the . - /// - /// The object to locate in the . - /// - /// The index of if found in the list; otherwise, -1. - /// - public int IndexOf(ImageListViewGroup item) - { - return mItems.IndexOf(item); - } - /// - /// Inserts an item to the at the specified index. - /// - /// The zero-based index at which should be inserted. - /// The object to insert into the . - public void Insert(int index, ImageListViewGroup item) - { - if (mImageListView == null) - throw new InvalidOperationException("Owner control is null."); - - item.mImageListView = mImageListView; - item.owner = this; - - mItems.Insert(index, item); - - collectionModified = true; - } - /// - /// Removes the first occurrence of a specific object from the . - /// - /// The object to remove from the . - /// - /// true if was successfully removed from the ; otherwise, false. This method also returns false if is not found in the original . - /// - public bool Remove(ImageListViewGroup item) - { - bool ret = mItems.Remove(item); - collectionModified = true; - return ret; - } - /// - /// Removes the item at the specified index. - /// - /// The zero-based index of the item to remove. - public void RemoveAt(int index) - { - mItems.RemoveAt(index); - collectionModified = true; - } - /// - /// Determines whether the collection has the group with the given name. - /// - /// The name of the group. - internal bool HasName(string name) - { - foreach (ImageListViewGroup group in this) - if (string.Compare(group.Name, name) == 0) return true; - - return false; - } - /// - /// Gets the list of visible groups. - /// - internal List GetDisplayedGroups() - { - List visible = new List(); - foreach (ImageListViewGroup group in this) - { - if (group.isVisible) - visible.Add(group); - } - return visible; - } - #endregion - - #region Unsupported Interface - /// - /// Returns an enumerator that iterates through a collection. - /// - IEnumerator IEnumerable.GetEnumerator() - { - return GetEnumerator(); - } - /// - /// Copies the elements of the to an , starting at a particular index. - /// - /// The one-dimensional that is the destination of the elements copied from . The must have zero-based indexing. - /// The zero-based index in at which copying begins. - void ICollection.CopyTo(Array array, int index) - { - if (!(array is ImageListViewGroup[])) - throw new ArgumentException("An array of ImageListViewGroup is required.", "array"); - mItems.CopyTo((ImageListViewGroup[])array, index); - } - /// - /// Copies the elements of the to an , starting at a particular index. - /// - /// The one-dimensional that is the destination of the elements copied from . The must have zero-based indexing. - /// The zero-based index in at which copying begins. - void ICollection.CopyTo(ImageListViewGroup[] array, int arrayIndex) - { - mItems.CopyTo(array, arrayIndex); - } - /// - /// Gets a value indicating whether access to the is synchronized (thread safe). - /// - bool ICollection.IsSynchronized - { - get { return false; } - } - /// - /// Gets an object that can be used to synchronize access to the . - /// - object ICollection.SyncRoot - { - get { throw new NotImplementedException(); } - } - /// - /// Adds an item to the . - /// - int IList.Add(object value) - { - if (!(value is ImageListViewGroup)) - throw new ArgumentException("An object of type ImageListViewGroup is required.", "value"); - ImageListViewGroup item = (ImageListViewGroup)value; - Add(item); - return mItems.IndexOf(item); - } - /// - /// Determines whether the contains a specific value. - /// - bool IList.Contains(object value) - { - if (!(value is ImageListViewGroup)) - throw new ArgumentException("An object of type ImageListViewGroup is required.", "value"); - return mItems.Contains((ImageListViewGroup)value); - } - /// - /// Determines the index of a specific item in the . - /// - int IList.IndexOf(object value) - { - if (!(value is ImageListViewGroup)) - throw new ArgumentException("An object of type ImageListViewGroup is required.", "value"); - return IndexOf((ImageListViewGroup)value); - } - /// - /// Inserts an item to the at the specified index. - /// - void IList.Insert(int index, object value) - { - if (!(value is ImageListViewGroup)) - throw new ArgumentException("An object of type ImageListViewGroup is required.", "value"); - Insert(index, (ImageListViewGroup)value); - } - /// - /// Gets a value indicating whether the has a fixed size. - /// - bool IList.IsFixedSize - { - get { return false; } - } - /// - /// Removes the first occurrence of a specific object from the . - /// - void IList.Remove(object value) - { - if (!(value is ImageListViewGroup)) - throw new ArgumentException("An object of type ImageListViewGroup is required.", "value"); - Remove((ImageListViewGroup)value); - } - /// - /// Gets or sets the at the specified index. - /// - object IList.this[int index] - { - get - { - return this[index]; - } - set - { - if (!(value is ImageListViewGroup)) - throw new ArgumentException("An object of type ImageListViewGroup is required.", "value"); - this[index] = (ImageListViewGroup)value; - collectionModified = true; - } - } - #endregion - } - } -} \ No newline at end of file diff --git a/Source/Components/ImageGlass.ImageListView/ImageListViewItem.cs b/Source/Components/ImageGlass.ImageListView/ImageListViewItem.cs deleted file mode 100644 index 3191ec798..000000000 --- a/Source/Components/ImageGlass.ImageListView/ImageListViewItem.cs +++ /dev/null @@ -1,1229 +0,0 @@ -// ImageListView - A listview control for image files -// Copyright (C) 2009 Ozgur Ozcitak -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// Ozgur Ozcitak (ozcitak@yahoo.com) - -using System; -using System.ComponentModel; -using System.Drawing; -using System.IO; -using System.Collections.Generic; -using System.Drawing.Design; - -// ReSharper disable InconsistentNaming - -namespace ImageGlass.ImageListView -{ - /// - /// Represents an item in the image list view. - /// - [TypeConverter(typeof(ImageListViewItemTypeConverter))] - public class ImageListViewItem : ICloneable - { - // [IG_CHANGE] Cache often repeated strings, e.g. extensions, directory path - private static readonly StringCache _stringCache = new StringCache(); - - #region Member Variables - // Property backing fields - internal int mIndex; - private Guid mGuid; - internal ImageListView mImageListView; - internal bool mChecked; - internal bool mSelected; - internal bool mEnabled; - private string mText; - private int mZOrder; - // File info - internal string extension; - private DateTime mDateAccessed; - private DateTime mDateCreated; - private DateTime mDateModified; - private string mFileType; - private string mFileName; - private string mFilePath; - private long mFileSize; - private Size mDimensions; - private SizeF mResolution; - // Exif tags - private string mImageDescription; - private string mEquipmentModel; - private DateTime mDateTaken; - private string mArtist; - private string mCopyright; - private float mExposureTime; - private float mFNumber; - private ushort mISOSpeed; - private string mUserComment; - private ushort mRating; - private ushort mStarRating; - private string mSoftware; - private float mFocalLength; - // Adaptor - private object mVirtualItemKey; - internal ImageListView.ImageListViewItemAdaptor mAdaptor; - // Used for custom columns - private Dictionary subItems; - // Used for cloned items - internal Image clonedThumbnail; - // Group info - internal string group; - internal int groupOrder; - - internal ImageListView.ImageListViewItemCollection owner; - internal bool isDirty; - private bool editing; - #endregion - - #region Properties - /// - /// Gets the cache state of the item thumbnail. - /// - [Category("Behavior"), Browsable(false), Description("Gets the cache state of the item thumbnail.")] - public CacheState ThumbnailCacheState - { - get - { - return mImageListView.thumbnailCache.GetCacheState(mGuid, mImageListView.ThumbnailSize, mImageListView.UseEmbeddedThumbnails, - mImageListView.AutoRotateThumbnails, mImageListView.UseWIC == UseWIC.Auto || mImageListView.UseWIC == UseWIC.ThumbnailsOnly); - } - } - /// - /// Gets a value determining if the item is focused. - /// - [Category("Appearance"), Browsable(false), Description("Gets a value determining if the item is focused."), DefaultValue(false)] - public bool Focused - { - get - { - if (owner?.FocusedItem == null) return false; - return (this == owner.FocusedItem); - } - set - { - if (owner != null) - owner.FocusedItem = this; - } - } - /// - /// Gets a value determining if the item is enabled. - /// - [Category("Appearance"), Browsable(false), Description("Gets a value determining if the item is enabled."), DefaultValue(true)] - public bool Enabled - { - get - { - return mEnabled; - } - set - { - mEnabled = value; - if (!mEnabled && mSelected) - { - mSelected = false; - if (mImageListView != null) - mImageListView.OnSelectionChangedInternal(); - } - if (mImageListView != null && mImageListView.IsItemVisible(mGuid)) - mImageListView.Refresh(); - } - } - /// - /// Gets the unique identifier for this item. - /// - [Category("Behavior"), Browsable(false), Description("Gets the unique identifier for this item.")] - internal Guid Guid { get { return mGuid; } private set { mGuid = value; } } - /// - /// Gets the adaptor of this item. - /// - [Category("Behavior"), Browsable(false), Description("Gets the adaptor of this item.")] - public ImageListView.ImageListViewItemAdaptor Adaptor { get { return mAdaptor; } } - /// - /// Gets the virtual item key associated with this item. - /// Returns null if the item is not a virtual item. - /// - [Category("Behavior"), Browsable(false), Description("Gets the virtual item key associated with this item.")] - public object VirtualItemKey { get { return mVirtualItemKey ?? mFileName; } } // [IG_CHANGE] - /// - /// Gets the ImageListView owning this item. - /// - [Category("Behavior"), Browsable(false), Description("Gets the ImageListView owning this item.")] - public ImageListView ImageListView { get { return mImageListView; } private set { mImageListView = value; } } - /// - /// Gets the index of the item. - /// - [Category("Behavior"), Browsable(false), Description("Gets the index of the item."), EditorBrowsable(EditorBrowsableState.Advanced)] - public int Index { get { return mIndex; } } - /// - /// Gets or sets a value determining if the item is checked. - /// - [Category("Appearance"), Browsable(false), Description("Gets or sets a value determining if the item is checked."), DefaultValue(false)] - public bool Checked - { - get - { - return mChecked; - } - set - { - if (value != mChecked) - { - mChecked = value; - if (mImageListView != null) - mImageListView.OnItemCheckBoxClickInternal(this); - } - } - } - /// - /// Gets or sets a value determining if the item is selected. - /// - [Category("Appearance"), Browsable(false), Description("Gets or sets a value determining if the item is selected."), DefaultValue(false)] - public bool Selected - { - get - { - return mSelected; - } - set - { - if (value != mSelected && mEnabled) - { - mSelected = value; - if (mImageListView != null) - { - mImageListView.OnSelectionChangedInternal(); - if (mImageListView.IsItemVisible(mGuid)) - mImageListView.Refresh(); - } - } - } - } - /// - /// Gets or sets the user-defined data associated with the item. - /// - [Category("Data"), Browsable(true), Description("Gets or sets the user-defined data associated with the item."), TypeConverter(typeof(StringConverter))] - public object Tag { get; set; } - /// - /// Gets or sets the text associated with this item. If left blank, item Text - /// reverts to the name of the image file. - /// - [Category("Appearance"), Browsable(true), Description("Gets or sets the text associated with this item. If left blank, item Text reverts to the name of the image file.")] - public string Text - { - get - { - return mText ?? Path.GetFileName(mFileName); // [IG_CHANGE] - } - set - { - mText = value; - if (mImageListView != null && mImageListView.IsItemVisible(mGuid)) - mImageListView.Refresh(); - } - } - /// - /// Gets or sets the name of the image file represented by this item. - /// - [Category("File Properties"), Browsable(true), Description("Gets or sets the name of the image file represented by this item.")] - [Editor(typeof(OpenFileDialogEditor), typeof(UITypeEditor))] - public string FileName - { - get - { - return mFileName; - } - set - { - if (string.IsNullOrEmpty(value)) - throw new ArgumentException("FileName cannot be null"); - - if (mFileName != value) - { - mFileName = value; - mVirtualItemKey = null; //mFileName; [IG_CHANGE] don't duplicate the filename - - // [IG_CHANGE] - //if (string.IsNullOrEmpty(mText)) - // mText = Path.GetFileName(mFileName); - // [IG_CHANGE] use string cache - extension = _stringCache.GetFromCache(Path.GetExtension(mFileName)); - - isDirty = true; - if (mImageListView != null) - { - mImageListView.thumbnailCache.Remove(mGuid, true); - mImageListView.metadataCache.Remove(mGuid); - mImageListView.metadataCache.Add(mGuid, Adaptor, mFileName, - (mImageListView.UseWIC == UseWIC.Auto || mImageListView.UseWIC == UseWIC.DetailsOnly)); - if (mImageListView.IsItemVisible(mGuid)) - mImageListView.Refresh(); - } - } - } - } - /// - /// Gets the thumbnail image. If the thumbnail image is not cached, it will be - /// added to the cache queue and null will be returned. The returned image needs - /// to be disposed by the caller. - /// - [Category("Appearance"), Browsable(false), Description("Gets the thumbnail image.")] - public Image ThumbnailImage - { - get - { - if (mImageListView == null) - throw new InvalidOperationException("Owner control is null."); - - if (ThumbnailCacheState != CacheState.Cached) - { - mImageListView.thumbnailCache.Add(Guid, mAdaptor, VirtualItemKey, mImageListView.ThumbnailSize, - mImageListView.UseEmbeddedThumbnails, mImageListView.AutoRotateThumbnails, - (mImageListView.UseWIC == UseWIC.Auto || mImageListView.UseWIC == UseWIC.ThumbnailsOnly)); - } - - return mImageListView.thumbnailCache.GetImage(Guid, mImageListView.ThumbnailSize, mImageListView.UseEmbeddedThumbnails, - mImageListView.AutoRotateThumbnails, mImageListView.UseWIC == UseWIC.Auto || mImageListView.UseWIC == UseWIC.ThumbnailsOnly, true); - } - } - /// - /// Gets or sets the draw order of the item. - /// - [Category("Appearance"), Browsable(false), Description("Gets or sets the draw order of the item."), DefaultValue(0)] - public int ZOrder { get { return mZOrder; } set { mZOrder = value; } } - #endregion - - #region Shell Properties - /// - /// Gets the small shell icon of the image file represented by this item. - /// If the icon image is not cached, it will be added to the cache queue and null will be returned. - /// - [Category("Appearance"), Browsable(false), Description("Gets the small shell icon of the image file represented by this item.")] - public Image SmallIcon - { - get - { - if (mImageListView == null) - throw new InvalidOperationException("Owner control is null."); - - CacheState state = mImageListView.shellInfoCache.GetCacheState(extension); - if (state == CacheState.Cached) - { - return mImageListView.shellInfoCache.GetSmallIcon(extension); - } - else if (state == CacheState.Error) - { - if (mImageListView.RetryOnError) - { - mImageListView.shellInfoCache.Remove(extension); - mImageListView.shellInfoCache.Add(extension); - } - return null; - } - else - { - mImageListView.shellInfoCache.Add(extension); - return null; - } - } - } - /// - /// Gets the large shell icon of the image file represented by this item. - /// If the icon image is not cached, it will be added to the cache queue and null will be returned. - /// - [Category("Appearance"), Browsable(false), Description("Gets the large shell icon of the image file represented by this item.")] - public Image LargeIcon - { - get - { - if (mImageListView == null) - throw new InvalidOperationException("Owner control is null."); - - CacheState state = mImageListView.shellInfoCache.GetCacheState(extension); - if (state == CacheState.Cached) - { - return mImageListView.shellInfoCache.GetLargeIcon(extension); - } - else if (state == CacheState.Error) - { - if (mImageListView.RetryOnError) - { - mImageListView.shellInfoCache.Remove(extension); - mImageListView.shellInfoCache.Add(extension); - } - return null; - } - else - { - mImageListView.shellInfoCache.Add(extension); - return null; - } - } - } - /// - /// Gets the last access date of the image file represented by this item. - /// - [Category("File Properties"), Browsable(true), Description("Gets the last access date of the image file represented by this item.")] - public DateTime DateAccessed { get { UpdateFileInfo(); return mDateAccessed; } } - /// - /// Gets the creation date of the image file represented by this item. - /// - [Category("File Properties"), Browsable(true), Description("Gets the creation date of the image file represented by this item.")] - public DateTime DateCreated { get { UpdateFileInfo(); return mDateCreated; } } - /// - /// Gets the modification date of the image file represented by this item. - /// - [Category("File Properties"), Browsable(true), Description("Gets the modification date of the image file represented by this item.")] - public DateTime DateModified { get { UpdateFileInfo(); return mDateModified; } } - /// - /// Gets the shell type of the image file represented by this item. - /// - [Category("File Properties"), Browsable(true), Description("Gets the shell type of the image file represented by this item.")] - public string FileType { get { UpdateFileInfo(); return mFileType; } } - /// - /// Gets the path of the image file represented by this item. - /// - [Category("File Properties"), Browsable(true), Description("Gets the path of the image file represented by this item.")] - public string FilePath { get { UpdateFileInfo(); return mFilePath; } } - /// - /// Gets file size in bytes. - /// - [Category("File Properties"), Browsable(true), Description("Gets file size in bytes.")] - public long FileSize { get { UpdateFileInfo(); return mFileSize; } } - #endregion - - #region Exif Properties - /// - /// Gets image dimensions. - /// - [Category("Image Properties"), Browsable(true), Description("Gets image dimensions.")] - public Size Dimensions { get { UpdateFileInfo(); return mDimensions; } } - /// - /// Gets image resolution in pixels per inch. - /// - [Category("Image Properties"), Browsable(true), Description("Gets image resolution in pixels per inch.")] - public SizeF Resolution { get { UpdateFileInfo(); return mResolution; } } - /// - /// Gets image description. - /// - [Category("Image Properties"), Browsable(true), Description("Gets image description.")] - public string ImageDescription { get { UpdateFileInfo(); return mImageDescription; } } - /// - /// Gets the camera model. - /// - [Category("Camera Properties"), Browsable(true), Description("Gets the camera model.")] - public string EquipmentModel { get { UpdateFileInfo(); return mEquipmentModel; } } - /// - /// Gets the date and time the image was taken. - /// - [Category("Image Properties"), Browsable(true), Description("Gets the date and time the image was taken.")] - public DateTime DateTaken { get { UpdateFileInfo(); return mDateTaken; } } - /// - /// Gets the name of the artist. - /// - [Category("Image Properties"), Browsable(true), Description("Gets the name of the artist.")] - public string Artist { get { UpdateFileInfo(); return mArtist; } } - /// - /// Gets image copyright information. - /// - [Category("Image Properties"), Browsable(true), Description("Gets image copyright information.")] - public string Copyright { get { UpdateFileInfo(); return mCopyright; } } - /// - /// Gets the exposure time in seconds. - /// - [Category("Camera Properties"), Browsable(true), Description("Gets the exposure time in seconds.")] - public float ExposureTime { get { UpdateFileInfo(); return mExposureTime; } } - /// - /// Gets the F number. - /// - [Category("Camera Properties"), Browsable(true), Description("Gets the F number.")] - public float FNumber { get { UpdateFileInfo(); return mFNumber; } } - /// - /// Gets the ISO speed. - /// - [Category("Camera Properties"), Browsable(true), Description("Gets the ISO speed.")] - public ushort ISOSpeed { get { UpdateFileInfo(); return mISOSpeed; } } - /// - /// Gets user comments. - /// - [Category("Image Properties"), Browsable(true), Description("Gets user comments.")] - public string UserComment { get { UpdateFileInfo(); return mUserComment; } } - /// - /// Gets rating in percent between 0-99 (Windows specific). - /// - [Category("Image Properties"), Browsable(true), Description("Gets rating in percent between 0-99.")] - public ushort Rating { get { UpdateFileInfo(); return mRating; } } - /// - /// Gets the star rating between 0-5 (Windows specific). - /// - [Category("Image Properties"), Browsable(true), Description("Gets the star rating between 0-5.")] - public ushort StarRating { get { UpdateFileInfo(); return mStarRating; } } - /// - /// Gets the name of the application that created this file. - /// - [Category("Image Properties"), Browsable(true), Description("Gets the name of the application that created this file.")] - public string Software { get { UpdateFileInfo(); return mSoftware; } } - /// - /// Gets focal length of the lens in millimeters. - /// - [Category("Camera Properties"), Browsable(true), Description("Gets focal length of the lens in millimeters.")] - public float FocalLength { get { UpdateFileInfo(); return mFocalLength; } } - #endregion - - #region Constructors - /// - /// Initializes a new instance of the class. - /// - public ImageListViewItem() - { - mIndex = -1; - owner = null; - - mZOrder = 0; - - Guid = Guid.NewGuid(); - ImageListView = null; - Checked = false; - Selected = false; - Enabled = true; - - isDirty = true; - editing = false; - - mVirtualItemKey = null; - - Tag = null; - - //[IG_CHANGE] we don't use sub-items, don't alloc memory for 'em - //subItems = new Dictionary(); - - groupOrder = 0; - group = string.Empty; - } - /// - /// Initializes a new instance of the class. - /// - /// The image filename representing the item. - /// Item text - public ImageListViewItem(string filename, string text) - : this() - { - mFileName = filename; - // [IG_CHANGE] use string cache - extension = _stringCache.GetFromCache(Path.GetExtension(filename)); - if (!string.IsNullOrEmpty(text)) - // [IG_CHANGE] don't duplicate filename text = Path.GetFileName(filename); - mText = text; - mVirtualItemKey = null; //mFileName; [IG_CHANGE] don't duplicate filename - } - /// - /// Initializes a new instance of the class. - /// - /// The image filename representing the item. - public ImageListViewItem(string filename) - : this(filename, string.Empty) - { - ; - } - /// - /// Initializes a new instance of a virtual class. - /// - /// The key identifying this item. - /// Text of this item. - public ImageListViewItem(object key, string text) - : this() - { - mVirtualItemKey = key; - mText = text; - } - /// - /// Initializes a new instance of a virtual class. - /// - /// The key identifying this item. - public ImageListViewItem(object key) - : this(key, string.Empty) - { - ; - } - #endregion - - #region Instance Methods - /// - /// Begins editing the item. - /// This method must be used while editing the item - /// to prevent collisions with the cache manager. - /// - public void BeginEdit() - { - if (editing) - throw new InvalidOperationException("Already editing this item."); - - if (mImageListView == null) - throw new InvalidOperationException("Owner control is null."); - - mImageListView.thumbnailCache.BeginItemEdit(mGuid); - mImageListView.metadataCache.BeginItemEdit(mGuid); - - editing = true; - } - /// - /// Ends editing and updates the item. - /// - /// If set to true, the item will be immediately updated. - public void EndEdit(bool update) - { - if (editing == false) - throw new InvalidOperationException("This item is not being edited."); - - if (mImageListView == null) - throw new InvalidOperationException("Owner control is null."); - - mImageListView.thumbnailCache.EndItemEdit(mGuid); - mImageListView.metadataCache.EndItemEdit(mGuid); - - editing = false; - if (update) Update(); - } - /// - /// Ends editing and updates the item. - /// - public void EndEdit() - { - EndEdit(true); - } - /// - /// Updates item thumbnail and item details. - /// - public void Update() - { - isDirty = true; - if (mImageListView != null) - { - mImageListView.thumbnailCache.Remove(mGuid, true); - mImageListView.metadataCache.Remove(mGuid); - mImageListView.metadataCache.Add(mGuid, mAdaptor, VirtualItemKey, - (mImageListView.UseWIC == UseWIC.Auto || mImageListView.UseWIC == UseWIC.DetailsOnly)); - mImageListView.Refresh(); - } - } - /// - /// Returns the sub item item text corresponding to the custom column with the given index. - /// - /// Index of the custom column. - /// Sub item text text for the given custom column type. - public string GetSubItemText(int index) - { - int i = 0; - foreach (string val in subItems.Values) - { - if (i == index) - return val; - i++; - } - - throw new IndexOutOfRangeException(); - } - /// - /// Sets the sub item item text corresponding to the custom column with the given index. - /// - /// Index of the custom column. - /// New sub item text - public void SetSubItemText(int index, string text) - { - int i = 0; - Guid found = Guid.Empty; - foreach (Guid guid in subItems.Keys) - { - if (i == index) - { - found = guid; - break; - } - - i++; - } - - if (found != Guid.Empty) - { - subItems[found] = text; - if (mImageListView != null && mImageListView.IsItemVisible(mGuid)) - mImageListView.Refresh(); - } - else - throw new IndexOutOfRangeException(); - } - /// - /// Returns the sub item item text corresponding to the specified column type. - /// - /// The type of information to return. - /// Formatted text for the given column type. - internal string GetSubItemText(ColumnType type) - { - switch (type) - { - case ColumnType.Custom: - throw new ArgumentException("Column type is ambiguous. You must access custom columns by index.", "type"); - case ColumnType.Name: - return Text; - case ColumnType.FileName: - return FileName; - case ColumnType.DateAccessed: - if (mDateAccessed == DateTime.MinValue) - return ""; - else - return mDateAccessed.ToString("g"); - case ColumnType.DateCreated: - if (mDateCreated == DateTime.MinValue) - return ""; - else - return mDateCreated.ToString("g"); - case ColumnType.DateModified: - if (mDateModified == DateTime.MinValue) - return ""; - else - return mDateModified.ToString("g"); - case ColumnType.FilePath: - return mFilePath; - case ColumnType.FileSize: - if (mFileSize == 0) - return ""; - else - return Utility.FormatSize(mFileSize); - case ColumnType.FileType: - if (!string.IsNullOrEmpty(mFileType)) - return mFileType; - if (mImageListView != null) - { - if (!string.IsNullOrEmpty(extension)) - { - CacheState state = mImageListView.shellInfoCache.GetCacheState(extension); - if (state == CacheState.Cached) - { - mFileType = mImageListView.shellInfoCache.GetFileType(extension); - return mFileType; - } - else if (state == CacheState.Error) - { - mImageListView.shellInfoCache.Remove(extension); - mImageListView.shellInfoCache.Add(extension); - return ""; - } - else - { - mImageListView.shellInfoCache.Add(extension); - return ""; - } - } - return ""; - } - else - return ""; - case ColumnType.Dimensions: - if (mDimensions == Size.Empty) - return ""; - else - return string.Format("{0} x {1}", mDimensions.Width, mDimensions.Height); - case ColumnType.Resolution: - if (mResolution == SizeF.Empty) - return ""; - else - return string.Format("{0} x {1}", mResolution.Width, mResolution.Height); - case ColumnType.ImageDescription: - return mImageDescription; - case ColumnType.EquipmentModel: - return mEquipmentModel; - case ColumnType.DateTaken: - if (mDateTaken == DateTime.MinValue) - return ""; - else - return mDateTaken.ToString("g"); - case ColumnType.Artist: - return mArtist; - case ColumnType.Copyright: - return mCopyright; - case ColumnType.ExposureTime: - if (mExposureTime < double.Epsilon) - return ""; - else if (mExposureTime >= 1.0f) - return mExposureTime.ToString("f1"); - else - return string.Format("1/{0:f0}", (1.0f / mExposureTime)); - case ColumnType.FNumber: - if (mFNumber < double.Epsilon) - return ""; - else - return mFNumber.ToString("f1"); - case ColumnType.ISOSpeed: - if (mISOSpeed == 0) - return ""; - else - return mISOSpeed.ToString(); - case ColumnType.UserComment: - return mUserComment; - case ColumnType.Rating: - if (mRating == 0) - return ""; - else return mRating.ToString(); - case ColumnType.Software: - return mSoftware; - case ColumnType.FocalLength: - if (mFocalLength < double.Epsilon) - return ""; - else - return mFocalLength.ToString("f1"); - default: - throw new ArgumentException("Unknown column type", "type"); - } - } - /// - /// Returns a that represents this instance. - /// - /// - /// A that represents this instance. - /// - public override string ToString() - { - if (!string.IsNullOrEmpty(mText)) - return mText; - if (!string.IsNullOrEmpty(mFileName)) - return Path.GetFileName(mFileName); - return $"Item {mIndex}"; - } - #endregion - - #region Helper Methods - /// - /// Gets the simple rating (0-5) - /// - /// - internal ushort GetSimpleRating() - { - return mStarRating; - } - /// - /// Sets the simple rating (0-5) from rating (0-99). - /// - private void UpdateRating() - { - if (mRating >= 1 && mRating <= 12) - mStarRating = 1; - else if (mRating >= 13 && mRating <= 37) - mStarRating = 2; - else if (mRating >= 38 && mRating <= 62) - mStarRating = 3; - else if (mRating >= 63 && mRating <= 87) - mStarRating = 4; - else if (mRating >= 88 && mRating <= 99) - mStarRating = 5; - else - mStarRating = 0; - } - /// - /// Gets an image from the cache manager. - /// If the thumbnail image is not cached, it will be - /// added to the cache queue and DefaultImage of the owner image list view will - /// be returned. If the thumbnail could not be cached ErrorImage of the owner - /// image list view will be returned. - /// - /// Type of cached image to return. - /// Requested thumbnail or icon. - internal Image GetCachedImage(CachedImageType imageType) - { - if (mImageListView == null) - throw new InvalidOperationException("Owner control is null."); - - if (imageType == CachedImageType.SmallIcon || imageType == CachedImageType.LargeIcon) - { - if (string.IsNullOrEmpty(extension)) - return mImageListView.DefaultImage; - - CacheState state = mImageListView.shellInfoCache.GetCacheState(extension); - if (state == CacheState.Cached) - { - if (imageType == CachedImageType.SmallIcon) - return mImageListView.shellInfoCache.GetSmallIcon(extension); - else - return mImageListView.shellInfoCache.GetLargeIcon(extension); - } - else if (state == CacheState.Error) - { - if (mImageListView.RetryOnError) - { - mImageListView.shellInfoCache.Remove(extension); - mImageListView.shellInfoCache.Add(extension); - } - return mImageListView.ErrorImage; - } - else - { - mImageListView.shellInfoCache.Add(extension); - return mImageListView.DefaultImage; - } - } - else - { - Image img = null; - CacheState state = ThumbnailCacheState; - - if (state == CacheState.Error) - { - if (string.IsNullOrEmpty(extension)) - return mImageListView.ErrorImage; - - if (mImageListView.ShellIconFallback && mImageListView.ThumbnailSize.Width > 32 && mImageListView.ThumbnailSize.Height > 32) - img = mImageListView.shellInfoCache.GetLargeIcon(extension); - if (img == null && mImageListView.ShellIconFallback) - img = mImageListView.shellInfoCache.GetSmallIcon(extension); - if (img == null) - img = mImageListView.ErrorImage; - return img; - } - - img = mImageListView.thumbnailCache.GetImage(Guid, mImageListView.ThumbnailSize, mImageListView.UseEmbeddedThumbnails, - mImageListView.AutoRotateThumbnails, mImageListView.UseWIC == UseWIC.Auto || mImageListView.UseWIC == UseWIC.ThumbnailsOnly, false); - - if (state == CacheState.Cached) - return img; - - mImageListView.thumbnailCache.Add(Guid, mAdaptor, VirtualItemKey, mImageListView.ThumbnailSize, - mImageListView.UseEmbeddedThumbnails, mImageListView.AutoRotateThumbnails, - (mImageListView.UseWIC == UseWIC.Auto || mImageListView.UseWIC == UseWIC.ThumbnailsOnly)); - - if (img == null && string.IsNullOrEmpty(extension)) - return mImageListView.DefaultImage; - - if (img == null && mImageListView.ShellIconFallback && mImageListView.ThumbnailSize.Width > 16 && mImageListView.ThumbnailSize.Height > 16) - img = mImageListView.shellInfoCache.GetLargeIcon(extension); - if (img == null && mImageListView.ShellIconFallback) - img = mImageListView.shellInfoCache.GetSmallIcon(extension); - if (img == null) - img = mImageListView.DefaultImage; - - return img; - } - } - /// - /// Adds a new subitem for the specified custom column. - /// - /// The Guid of the custom column. - internal void AddSubItemText(Guid guid) - { - subItems.Add(guid, ""); - } - /// - /// Returns the sub item item text corresponding to the specified custom column. - /// - /// The Guid of the custom column. - /// Formatted text for the given column. - internal string GetSubItemText(Guid guid) - { - return subItems[guid]; - } - /// - /// Sets the sub item item text corresponding to the specified custom column. - /// - /// The Guid of the custom column. - /// The text of the subitem. - /// Formatted text for the given column. - internal void SetSubItemText(Guid guid, string text) - { - subItems[guid] = text; - } - /// - /// Removes the sub item item text corresponding to the specified custom column. - /// - /// The Guid of the custom column. - /// true if the item was removed; otherwise false. - internal bool RemoveSubItemText(Guid guid) - { - return subItems.Remove(guid); - } - /// - /// Removes all sub item item texts. - /// - internal void RemoveAllSubItemTexts() - { - subItems.Clear(); - } - /// - /// Updates file info for the image file represented by this item. - /// Item details will be updated synchronously without waiting for the - /// cache thread. - /// - private void UpdateFileInfo() - { - if (!isDirty) return; - - if (mImageListView != null) - { - UpdateDetailsInternal(Adaptor.GetDetails(VirtualItemKey, - (mImageListView.UseWIC == UseWIC.Auto || mImageListView.UseWIC == UseWIC.DetailsOnly))); - } - } - /// - /// Invoked by the worker thread to update item details. - /// - /// Item details. - internal void UpdateDetailsInternal(Utility.Tuple[] info) - { - if (!isDirty) return; - - // File info - foreach (Utility.Tuple item in info) - { - switch (item.Item1) - { - case ColumnType.DateAccessed: - mDateAccessed = (DateTime)item.Item3; - break; - case ColumnType.DateCreated: - mDateCreated = (DateTime)item.Item3; - break; - case ColumnType.DateModified: - mDateModified = (DateTime)item.Item3; - break; - case ColumnType.FileSize: - mFileSize = (long)item.Item3; - break; - case ColumnType.FilePath: - mFilePath = (string)item.Item3; - break; - case ColumnType.Dimensions: - mDimensions = (Size)item.Item3; - break; - case ColumnType.Resolution: - mResolution = (SizeF)item.Item3; - break; - case ColumnType.ImageDescription: - mImageDescription = (string)item.Item3; - break; - case ColumnType.EquipmentModel: - mEquipmentModel = (string)item.Item3; - break; - case ColumnType.DateTaken: - mDateTaken = (DateTime)item.Item3; - break; - case ColumnType.Artist: - mArtist = (string)item.Item3; - break; - case ColumnType.Copyright: - mCopyright = (string)item.Item3; - break; - case ColumnType.ExposureTime: - mExposureTime = (float)item.Item3; - break; - case ColumnType.FNumber: - mFNumber = (float)item.Item3; - break; - case ColumnType.ISOSpeed: - mISOSpeed = (ushort)item.Item3; - break; - case ColumnType.UserComment: - mUserComment = (string)item.Item3; - break; - case ColumnType.Rating: - mRating = (ushort)item.Item3; - break; - case ColumnType.Software: - mSoftware = (string)item.Item3; - break; - case ColumnType.FocalLength: - mFocalLength = (float)item.Item3; - break; - case ColumnType.Custom: - string label = item.Item2; - string value = (string)item.Item3; - Guid columnID = Guid.Empty; - foreach (ImageListView.ImageListViewColumnHeader column in mImageListView.Columns) - { - if (label == column.Text) - columnID = column.Guid; - } - if (columnID == Guid.Empty) - { - ImageListView.ImageListViewColumnHeader column = new ImageListView.ImageListViewColumnHeader(ColumnType.Custom, label); - columnID = column.Guid; - } - if (subItems.ContainsKey(columnID)) - subItems[columnID] = value; - else - subItems.Add(columnID, value); - break; - default: - throw new Exception("Unknown column type."); - } - } - - UpdateRating(); - - isDirty = false; - } - /// - /// Updates group order and name of the item. - /// - /// The group column. - internal void UpdateGroup(ImageListView.ImageListViewColumnHeader column) - { - if (column == null) - { - groupOrder = 0; - group = string.Empty; - return; - } - - Utility.Tuple groupInfo; - - switch (column.Type) - { - case ColumnType.DateAccessed: - groupInfo = Utility.GroupTextDate(DateAccessed); - break; - case ColumnType.DateCreated: - groupInfo = Utility.GroupTextDate(DateCreated); - break; - case ColumnType.DateModified: - groupInfo = Utility.GroupTextDate(DateModified); - break; - case ColumnType.Dimensions: - groupInfo = Utility.GroupTextDimension(Dimensions); - break; - case ColumnType.FileName: - groupInfo = Utility.GroupTextAlpha(FileName); - break; - case ColumnType.FilePath: - groupInfo = Utility.GroupTextAlpha(FilePath); - break; - case ColumnType.FileSize: - groupInfo = Utility.GroupTextFileSize(FileSize); - break; - case ColumnType.FileType: - groupInfo = Utility.GroupTextAlpha(FileType); - break; - case ColumnType.Name: - groupInfo = Utility.GroupTextAlpha(Text); - break; - case ColumnType.ImageDescription: - groupInfo = Utility.GroupTextAlpha(ImageDescription); - break; - case ColumnType.EquipmentModel: - groupInfo = Utility.GroupTextAlpha(EquipmentModel); - break; - case ColumnType.DateTaken: - groupInfo = Utility.GroupTextDate(DateTaken); - break; - case ColumnType.Artist: - groupInfo = Utility.GroupTextAlpha(Artist); - break; - case ColumnType.Copyright: - groupInfo = Utility.GroupTextAlpha(Copyright); - break; - case ColumnType.UserComment: - groupInfo = Utility.GroupTextAlpha(UserComment); - break; - case ColumnType.Software: - groupInfo = Utility.GroupTextAlpha(Software); - break; - case ColumnType.Custom: - groupInfo = Utility.GroupTextAlpha(GetSubItemText(column.Guid)); - break; - case ColumnType.ISOSpeed: - groupInfo = new Utility.Tuple(ISOSpeed, ISOSpeed.ToString()); - break; - case ColumnType.Rating: - groupInfo = new Utility.Tuple(Rating / 5, (Rating / 5).ToString()); - break; - case ColumnType.FocalLength: - groupInfo = new Utility.Tuple((int)FocalLength, FocalLength.ToString()); - break; - case ColumnType.ExposureTime: - groupInfo = new Utility.Tuple((int)ExposureTime, ExposureTime.ToString()); - break; - case ColumnType.FNumber: - groupInfo = new Utility.Tuple((int)FNumber, FNumber.ToString()); - break; - case ColumnType.Resolution: - groupInfo = new Utility.Tuple((int)Resolution.Width, Resolution.Width.ToString()); - break; - default: - groupInfo = new Utility.Tuple(0, "Unknown"); - break; - } - - groupOrder = groupInfo.Item1; - group = groupInfo.Item2; - } - #endregion - - #region ICloneable Members - /// - /// Creates a new object that is a copy of the current instance. - /// - /// - /// A new object that is a copy of this instance. - /// - public object Clone() - { - ImageListViewItem item = new ImageListViewItem(); - - item.mText = mText; - - // File info - item.extension = extension; - item.mDateAccessed = mDateAccessed; - item.mDateCreated = mDateCreated; - item.mDateModified = mDateModified; - item.mFileType = mFileType; - item.mFileName = mFileName; - item.mFilePath = mFilePath; - item.mFileSize = mFileSize; - - // Image info - item.mDimensions = mDimensions; - item.mResolution = mResolution; - - // Exif tags - item.mImageDescription = mImageDescription; - item.mEquipmentModel = mEquipmentModel; - item.mDateTaken = mDateTaken; - item.mArtist = mArtist; - item.mCopyright = mCopyright; - item.mExposureTime = mExposureTime; - item.mFNumber = mFNumber; - item.mISOSpeed = mISOSpeed; - item.mUserComment = mUserComment; - item.mRating = mRating; - item.mStarRating = mStarRating; - item.mSoftware = mSoftware; - item.mFocalLength = mFocalLength; - - // Virtual item properties - item.mAdaptor = mAdaptor; - item.mVirtualItemKey = mVirtualItemKey; - - // Sub items - foreach (KeyValuePair kv in subItems) - item.subItems.Add(kv.Key, kv.Value); - - // Current thumbnail - if (mImageListView != null) - { - item.clonedThumbnail = mImageListView.thumbnailCache.GetImage(Guid, mImageListView.ThumbnailSize, - mImageListView.UseEmbeddedThumbnails, mImageListView.AutoRotateThumbnails, - mImageListView.UseWIC == UseWIC.Auto || mImageListView.UseWIC == UseWIC.ThumbnailsOnly, true); - } - - return item; - } - #endregion - } -} diff --git a/Source/Components/ImageGlass.ImageListView/ImageListViewItemAdaptor.cs b/Source/Components/ImageGlass.ImageListView/ImageListViewItemAdaptor.cs deleted file mode 100644 index fab40cdee..000000000 --- a/Source/Components/ImageGlass.ImageListView/ImageListViewItemAdaptor.cs +++ /dev/null @@ -1,45 +0,0 @@ -using System; -using System.Drawing; - -namespace ImageGlass.ImageListView -{ - public partial class ImageListView - { - /// - /// Represents the abstract case class for adaptors. - /// - public abstract class ImageListViewItemAdaptor : IDisposable - { - #region Abstract Methods - /// - /// Returns the thumbnail image for the given item. - /// - /// Item key. - /// Requested image size. - /// Embedded thumbnail usage. - /// true to automatically rotate images based on Exif orientation; otherwise false. - /// true to use Windows Imaging Component; otherwise false. - /// The thumbnail image from the given item or null if an error occurs. - public abstract Image GetThumbnail(object key, Size size, UseEmbeddedThumbnails useEmbeddedThumbnails, bool useExifOrientation, bool useWIC); - /// - /// Returns the path to the source image for use in drag operations. - /// - /// Item key. - /// The path to the source image. - public abstract string GetSourceImage(object key); - /// - /// Returns the details for the given item. - /// - /// Item key. - /// true to use Windows Imaging Component; otherwise false. - /// An array of tuples containing item details or null if an error occurs. - public abstract Utility.Tuple[] GetDetails(object key, bool useWIC); - /// - /// Performs application-defined tasks associated with freeing, - /// releasing, or resetting unmanaged resources. - /// - public abstract void Dispose(); - #endregion - } - } -} diff --git a/Source/Components/ImageGlass.ImageListView/ImageListViewItemAdaptors.cs b/Source/Components/ImageGlass.ImageListView/ImageListViewItemAdaptors.cs deleted file mode 100644 index 8b9a9e19b..000000000 --- a/Source/Components/ImageGlass.ImageListView/ImageListViewItemAdaptors.cs +++ /dev/null @@ -1,228 +0,0 @@ -using System.Collections.Generic; -using System.Drawing; -using System.IO; -using System.Net; - -namespace ImageGlass.ImageListView -{ - /// - /// Represents the built-in adaptors. - /// - public static class ImageListViewItemAdaptors - { - #region FileSystemAdaptor - /// - /// Represents a file system adaptor. - /// - public class FileSystemAdaptor : ImageListView.ImageListViewItemAdaptor - { - // [IG_CHANGE] use a cache for commonly repeated strings - private static StringCache _stringCache = new StringCache(); - - private bool disposed; - - /// - /// Initializes a new instance of the class. - /// - public FileSystemAdaptor() - { - disposed = false; - } - - /// - /// Returns the thumbnail image for the given item. - /// - /// Item key. - /// Requested image size. - /// Embedded thumbnail usage. - /// true to automatically rotate images based on Exif orientation; otherwise false. - /// true to use Windows Imaging Component; otherwise false. - /// The thumbnail image from the given item or null if an error occurs. - public override Image GetThumbnail(object key, Size size, UseEmbeddedThumbnails useEmbeddedThumbnails, bool useExifOrientation, bool useWIC) - { - if (disposed) - return null; - - // [IG_CHANGE] - // Issue #530: thumbnails not built if long file path - string filename = Heart.Helpers.PrefixLongPath((string)key); - if (File.Exists(filename)) - return ThumbnailExtractor.FromFile(filename, size, useEmbeddedThumbnails, useExifOrientation, useWIC); - else - return null; - } - /// - /// Returns the path to the source image for use in drag operations. - /// - /// Item key. - /// The path to the source image. - public override string GetSourceImage(object key) - { - if (disposed) - return null; - - string filename = (string)key; - return filename; - } - /// - /// Returns the details for the given item. - /// - /// Item key. - /// true to use Windows Imaging Component; otherwise false. - /// An array of tuples containing item details or null if an error occurs. - public override Utility.Tuple[] GetDetails(object key, bool useWIC) - { - if (disposed) - return null; - - string filename = (string)key; - List> details = new List>(); - - // Get file info - if (File.Exists(filename)) - { - FileInfo info = new FileInfo(filename); - details.Add(new Utility.Tuple(ColumnType.DateCreated, string.Empty, info.CreationTime)); - details.Add(new Utility.Tuple(ColumnType.DateAccessed, string.Empty, info.LastAccessTime)); - details.Add(new Utility.Tuple(ColumnType.DateModified, string.Empty, info.LastWriteTime)); - details.Add(new Utility.Tuple(ColumnType.FileSize, string.Empty, info.Length)); - // [IG_CHANGE] use string cache - details.Add(new Utility.Tuple(ColumnType.FilePath, string.Empty, _stringCache.GetFromCache(info.DirectoryName) ?? "")); - - // Get metadata - MetadataExtractor metadata = MetadataExtractor.FromFile(filename, useWIC); - details.Add(new Utility.Tuple(ColumnType.Dimensions, string.Empty, new Size(metadata.Width, metadata.Height))); - details.Add(new Utility.Tuple(ColumnType.Resolution, string.Empty, new SizeF((float)metadata.DPIX, (float)metadata.DPIY))); - // [IG_CHANGE] use string cache - details.Add(new Utility.Tuple(ColumnType.ImageDescription, string.Empty, metadata.ImageDescription == null ? "" : _stringCache.GetFromCache(metadata.ImageDescription))); - details.Add(new Utility.Tuple(ColumnType.EquipmentModel, string.Empty, metadata.EquipmentModel ?? "")); - details.Add(new Utility.Tuple(ColumnType.DateTaken, string.Empty, metadata.DateTaken)); - details.Add(new Utility.Tuple(ColumnType.Artist, string.Empty, metadata.Artist ?? "")); - details.Add(new Utility.Tuple(ColumnType.Copyright, string.Empty, metadata.Copyright ?? "")); - details.Add(new Utility.Tuple(ColumnType.ExposureTime, string.Empty, (float)metadata.ExposureTime)); - details.Add(new Utility.Tuple(ColumnType.FNumber, string.Empty, (float)metadata.FNumber)); - details.Add(new Utility.Tuple(ColumnType.ISOSpeed, string.Empty, (ushort)metadata.ISOSpeed)); - details.Add(new Utility.Tuple(ColumnType.UserComment, string.Empty, metadata.Comment ?? "")); - details.Add(new Utility.Tuple(ColumnType.Rating, string.Empty, (ushort)metadata.Rating)); - details.Add(new Utility.Tuple(ColumnType.Software, string.Empty, metadata.Software ?? "")); - details.Add(new Utility.Tuple(ColumnType.FocalLength, string.Empty, (float)metadata.FocalLength)); - } - - return details.ToArray(); - } - /// - /// Performs application-defined tasks associated with freeing, - /// releasing, or resetting unmanaged resources. - /// - public override void Dispose() - { - disposed = true; - } - } - #endregion - - #region URIAdaptor - /// - /// Represents a URI adaptor. - /// - public class URIAdaptor : ImageListView.ImageListViewItemAdaptor - { - private bool disposed; - - /// - /// Initializes a new instance of the class. - /// - public URIAdaptor() - { - disposed = false; - } - - /// - /// Returns the thumbnail image for the given item. - /// - /// Item key. - /// Requested image size. - /// Embedded thumbnail usage. - /// true to automatically rotate images based on Exif orientation; otherwise false. - /// true to use Windows Imaging Component; otherwise false. - /// The thumbnail image from the given item or null if an error occurs. - public override Image GetThumbnail(object key, Size size, UseEmbeddedThumbnails useEmbeddedThumbnails, bool useExifOrientation, bool useWIC) - { - if (disposed) - return null; - - string uri = (string)key; - try - { - using (WebClient client = new WebClient()) - { - byte[] imageData = client.DownloadData(uri); - using (MemoryStream stream = new MemoryStream(imageData)) - { - using (Image sourceImage = Image.FromStream(stream)) - { - return ThumbnailExtractor.FromImage(sourceImage, size, useEmbeddedThumbnails, useExifOrientation, useWIC); - } - } - } - } - catch - { - return null; - } - } - /// - /// Returns the path to the source image for use in drag operations. - /// - /// Item key. - /// The path to the source image. - public override string GetSourceImage(object key) - { - if (disposed) - return null; - - string uri = (string)key; - try - { - string filename = Path.GetTempFileName(); - using (WebClient client = new WebClient()) - { - client.DownloadFile(uri, filename); - return filename; - } - } - catch - { - return null; - } - } - /// - /// Returns the details for the given item. - /// - /// Item key. - /// true to use Windows Imaging Component; otherwise false. - /// An array of 2-tuples containing item details or null if an error occurs. - public override Utility.Tuple[] GetDetails(object key, bool useWIC) - { - if (disposed) - return null; - - string uri = (string)key; - List> details = new List>(); - - details.Add(new Utility.Tuple(ColumnType.Custom, "URL", uri)); - - return details.ToArray(); - } - /// - /// Performs application-defined tasks associated with freeing, - /// releasing, or resetting unmanaged resources. - /// - public override void Dispose() - { - disposed = true; - } - } - #endregion - } -} diff --git a/Source/Components/ImageGlass.ImageListView/ImageListViewItemCollection.cs b/Source/Components/ImageGlass.ImageListView/ImageListViewItemCollection.cs deleted file mode 100644 index 7217beb02..000000000 --- a/Source/Components/ImageGlass.ImageListView/ImageListViewItemCollection.cs +++ /dev/null @@ -1,1119 +0,0 @@ -// ImageListView - A listview control for image files -// Copyright (C) 2009 Ozgur Ozcitak -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// Ozgur Ozcitak (ozcitak@yahoo.com) - -using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.Collections; -using System.Windows.Forms; -using System.Drawing; -using System.Text.RegularExpressions; - -namespace ImageGlass.ImageListView -{ - public partial class ImageListView - { - /// - /// Represents the collection of items in the image list view. - /// - public class ImageListViewItemCollection : IList, ICollection, IList, IEnumerable - { - #region Member Variables - private List mItems; - internal ImageListView mImageListView; - private ImageListViewItem mFocused; - private Dictionary lookUp; - internal bool collectionModified; - #endregion - - #region Constructors - /// - /// Initializes a new instance of the class. - /// - /// The owning this collection. - internal ImageListViewItemCollection(ImageListView owner) - { - mItems = new List(); - lookUp = new Dictionary(); - mFocused = null; - mImageListView = owner; - collectionModified = true; - } - #endregion - - #region Properties - /// - /// Gets the number of elements contained in the . - /// - public int Count - { - get { return mItems.Count; } - } - /// - /// Gets a value indicating whether the is read-only. - /// - public bool IsReadOnly - { - get { return false; } - } - /// - /// Gets or sets the focused item. - /// - public ImageListViewItem FocusedItem - { - get - { - return mFocused; - } - set - { - ImageListViewItem oldFocusedItem = mFocused; - mFocused = value; - // Refresh items - if (oldFocusedItem != mFocused && mImageListView != null) - mImageListView.Refresh(); - } - } - /// - /// Gets the owning this collection. - /// - [Category("Behavior"), Browsable(false), Description("Gets the ImageListView owning this collection.")] - public ImageListView ImageListView { get { return mImageListView; } } - /// - /// Gets or sets the at the specified index. - /// - [Category("Behavior"), Browsable(false), Description("Gets or sets the item at the specified index.")] - public ImageListViewItem this[int index] - { - get - { - return mItems[index]; - } - set - { - ImageListViewItem item = value; - ImageListViewItem oldItem = mItems[index]; - - if (mItems[index] == mFocused) - mFocused = item; - bool oldSelected = mItems[index].Selected; - item.mIndex = index; - if (mImageListView != null) - item.mImageListView = mImageListView; - item.owner = this; - mItems[index] = item; - lookUp.Remove(oldItem.Guid); - lookUp.Add(item.Guid, item); - collectionModified = true; - - if (mImageListView != null) - { - mImageListView.thumbnailCache.Remove(oldItem.Guid); - mImageListView.metadataCache.Remove(oldItem.Guid); - if (mImageListView.CacheMode == CacheMode.Continuous) - { - mImageListView.thumbnailCache.Add(item.Guid, item.Adaptor, item.VirtualItemKey, - mImageListView.ThumbnailSize, mImageListView.UseEmbeddedThumbnails, - mImageListView.AutoRotateThumbnails, - (mImageListView.UseWIC == UseWIC.Auto || mImageListView.UseWIC == UseWIC.ThumbnailsOnly)); - } - mImageListView.metadataCache.Add(item.Guid, item.Adaptor, item.VirtualItemKey, - (mImageListView.UseWIC == UseWIC.Auto || mImageListView.UseWIC == UseWIC.DetailsOnly)); - if (item.Selected != oldSelected) - mImageListView.OnSelectionChanged(new EventArgs()); - } - } - } - /// - /// Gets the with the specified Guid. - /// - [Category("Behavior"), Browsable(false), Description("Gets or sets the item with the specified Guid.")] - internal ImageListViewItem this[Guid guid] - { - get - { - return lookUp[guid]; - } - } - #endregion - - #region Instance Methods - /// - /// [PHAP] Adds an item to the . - /// - /// The to add to the . - /// The adaptor associated with this item. - public void Add(ImageListViewItem item, ImageListView.ImageListViewItemAdaptor adaptor) - { - AddInternal(item, adaptor); - - if (mImageListView != null) - { - if (item.Selected) - { - mImageListView.OnSelectionChangedInternal(); - } - - if (mImageListView.IsItemVisible(mItems.Count) != ItemVisibility.NotVisible) - { - mImageListView.Refresh(); - } - - } - } - /// - /// Adds an item to the . - /// - /// The to add to the . - public void Add(ImageListViewItem item) - { - Add(item, mImageListView.defaultAdaptor); - } - /// - /// Adds an item to the . - /// - /// The to add to the . - /// The initial thumbnail image for the item. - /// The adaptor associated with this item. - public void Add(ImageListViewItem item, Image initialThumbnail, ImageListView.ImageListViewItemAdaptor adaptor) - { - item.clonedThumbnail = initialThumbnail; - Add(item, adaptor); - } - /// - /// Adds an item to the . - /// - /// The to add to the . - /// The initial thumbnail image for the item. - public void Add(ImageListViewItem item, Image initialThumbnail) - { - Add(item, initialThumbnail, mImageListView.defaultAdaptor); - } - /// - /// Adds an item to the . - /// - /// The name of the image file. - public void Add(string filename) - { - Add(filename, null); - } - /// - /// Adds an item to the . - /// - /// The name of the image file. - /// The initial thumbnail image for the item. - public void Add(string filename, Image initialThumbnail) - { - ImageListViewItem item = new ImageListViewItem(filename); - item.mAdaptor = mImageListView.defaultAdaptor; - item.clonedThumbnail = initialThumbnail; - Add(item); - } - /// - /// Adds a virtual item to the . - /// - /// The key identifying the item. - /// Text of the item. - /// The adaptor associated with this item. - public void Add(object key, string text, ImageListView.ImageListViewItemAdaptor adaptor) - { - Add(key, text, null, adaptor); - } - /// - /// Adds a virtual item to the . - /// - /// The key identifying the item. - /// Text of the item. - public void Add(object key, string text) - { - Add(key, text, mImageListView.defaultAdaptor); - } - /// - /// Adds a virtual item to the . - /// - /// The key identifying the item. - /// Text of the item. - /// The initial thumbnail image for the item. - /// The adaptor associated with this item. - public void Add(object key, string text, Image initialThumbnail, ImageListView.ImageListViewItemAdaptor adaptor) - { - ImageListViewItem item = new ImageListViewItem(key, text); - item.clonedThumbnail = initialThumbnail; - Add(item, adaptor); - } - /// - /// Adds a virtual item to the . - /// - /// The key identifying the item. - /// Text of the item. - /// The initial thumbnail image for the item. - public void Add(object key, string text, Image initialThumbnail) - { - Add(key, text, initialThumbnail, mImageListView.defaultAdaptor); - } - /// - /// Adds a range of items to the . - /// - /// An array of - /// to add to the . - /// The adaptor associated with this item. - public void AddRange(ImageListViewItem[] items, ImageListView.ImageListViewItemAdaptor adaptor) - { - if (mImageListView != null) - mImageListView.SuspendPaint(); - - foreach (ImageListViewItem item in items) - Add(item, adaptor); - - if (mImageListView != null) - { - mImageListView.Refresh(); - mImageListView.ResumePaint(); - } - } - /// - /// Adds a range of items to the . - /// - /// An array of - /// to add to the . - public void AddRange(ImageListViewItem[] items) - { - AddRange(items, mImageListView.defaultAdaptor); - } - /// - /// Adds a range of items to the . - /// - /// The names or the image files. - public void AddRange(string[] filenames) - { - ImageListViewItem[] items = new ImageListViewItem[filenames.Length]; - - for (int i = 0; i < filenames.Length; i++) - { - items[i] = new ImageListViewItem(filenames[i]); - } - - AddRange(items); - } - /// - /// Removes all items from the . - /// - public void Clear() - { - mItems.Clear(); - - mFocused = null; - - // [IG_CHANGE] clear does not deallocate memory - //lookUp.Clear(); - lookUp = new Dictionary(); - - collectionModified = true; - - if (mImageListView != null) - { - mImageListView.metadataCache.Clear(); - mImageListView.thumbnailCache.Clear(); - mImageListView.SelectedItems.Clear(); - - if (mImageListView.showGroups) - Sort(); - - mImageListView.Refresh(); - } - - // Raise the clear event - mImageListView.OnItemCollectionChanged(new ItemCollectionChangedEventArgs(CollectionChangeAction.Refresh, null)); - } - /// - /// Determines whether the - /// contains a specific value. - /// - /// The object to locate in the - /// . - /// - /// true if is found in the - /// ; otherwise, false. - /// - public bool Contains(ImageListViewItem item) - { - return mItems.Contains(item); - } - /// - /// Returns an enumerator that iterates through the collection. - /// - /// - /// A - /// that can be used to iterate through the collection. - /// - public IEnumerator GetEnumerator() - { - return mItems.GetEnumerator(); - } - /// - /// Inserts an item to the at the specified index. - /// - /// The zero-based index at which should be inserted. - /// The to - /// insert into the . - /// The adaptor associated with this item. - public void Insert(int index, ImageListViewItem item, ImageListView.ImageListViewItemAdaptor adaptor) - { - InsertInternal(index, item, adaptor); - - if (mImageListView != null) - { - if (item.Selected) - mImageListView.OnSelectionChangedInternal(); - mImageListView.Refresh(); - } - } - /// - /// Inserts an item to the at the specified index. - /// - /// The zero-based index at which should be inserted. - /// The to - /// insert into the . - public void Insert(int index, ImageListViewItem item) - { - Insert(index, item, mImageListView.defaultAdaptor); - } - /// - /// Inserts an item to the at the specified index. - /// - /// The zero-based index at which the new item should be inserted. - /// The name of the image file. - public void Insert(int index, string filename) - { - Insert(index, new ImageListViewItem(filename)); - } - /// - /// Inserts an item to the at the specified index. - /// - /// The zero-based index at which the new item should be inserted. - /// The name of the image file. - /// The initial thumbnail image for the item. - public void Insert(int index, string filename, Image initialThumbnail) - { - ImageListViewItem item = new ImageListViewItem(filename); - item.clonedThumbnail = initialThumbnail; - Insert(index, item); - } - /// - /// Inserts a virtual item to the at the specified index. - /// - /// The zero-based index at which the new item should be inserted. - /// The key identifying the item. - /// Text of the item. - /// The adaptor associated with this item. - public void Insert(int index, object key, string text, ImageListView.ImageListViewItemAdaptor adaptor) - { - Insert(index, key, text, null, adaptor); - } - /// - /// Inserts a virtual item to the at the specified index. - /// - /// The zero-based index at which the new item should be inserted. - /// The key identifying the item. - /// Text of the item. - public void Insert(int index, object key, string text) - { - Insert(index, key, text, mImageListView.defaultAdaptor); - } - /// - /// Inserts a virtual item to the at the specified index. - /// - /// The zero-based index at which the new item should be inserted. - /// The key identifying the item. - /// Text of the item. - /// The initial thumbnail image for the item. - /// The adaptor associated with this item. - public void Insert(int index, object key, string text, Image initialThumbnail, ImageListView.ImageListViewItemAdaptor adaptor) - { - ImageListViewItem item = new ImageListViewItem(key, text); - item.clonedThumbnail = initialThumbnail; - Insert(index, item, adaptor); - } - /// - /// Inserts a virtual item to the at the specified index. - /// - /// The zero-based index at which the new item should be inserted. - /// The key identifying the item. - /// Text of the item. - /// The initial thumbnail image for the item. - public void Insert(int index, object key, string text, Image initialThumbnail) - { - Insert(index, key, text, initialThumbnail, mImageListView.defaultAdaptor); - } - /// - /// Removes the first occurrence of a specific object - /// from the . - /// - /// The to remove - /// from the . - /// - /// true if was successfully removed from the - /// ; otherwise, false. This method also - /// returns false if is not found in the original - /// . - /// - public bool Remove(ImageListViewItem item) - { - bool ret = RemoveInternal(item, true); - - if (mImageListView != null) - { - if (item.Selected) - mImageListView.OnSelectionChangedInternal(); - mImageListView.Refresh(); - } - - return ret; - } - /// - /// Removes the at the specified index. - /// - /// The zero-based index of the item to remove. - public void RemoveAt(int index) - { - Remove(mItems[index]); - } - #endregion - - #region Helper Methods - /// - /// Adds the (empty) subitem to each item for the given custom column. - /// - /// Custom column ID. - internal void AddCustomColumn(Guid guid) - { - foreach (ImageListViewItem item in mItems) - item.AddSubItemText(guid); - } - /// - /// Determines whether the collection contains the given key. - /// - /// The key of the item. - /// true if the collection contains the given key; otherwise false. - internal bool ContainsKey(Guid guid) - { - return lookUp.ContainsKey(guid); - } - /// - /// Gets the value associated with the specified key. - /// - /// The key of the item. - /// the value associated with the specified key, - /// if the key is found; otherwise, the default value for the type - /// of the value parameter. This parameter is passed uninitialized. - /// true if the collection contains the given key; otherwise false. - internal bool TryGetValue(Guid guid, out ImageListViewItem item) - { - return lookUp.TryGetValue(guid, out item); - } - /// - /// Removes the subitem of each item for the given custom column. - /// - /// Custom column ID. - internal void RemoveCustomColumn(Guid guid) - { - foreach (ImageListViewItem item in mItems) - item.RemoveSubItemText(guid); - } - /// - /// Removes the subitem of each item for the given custom column. - /// - internal void RemoveAllCustomColumns() - { - foreach (ImageListViewItem item in mItems) - item.RemoveAllSubItemTexts(); - } - /// - /// Adds the given item without raising a selection changed event. - /// - /// The to add. - /// The adaptor associated with this item. - /// true if the item was added; otherwise false. - internal bool AddInternal(ImageListViewItem item, ImageListView.ImageListViewItemAdaptor adaptor) - { - return InsertInternal(-1, item, adaptor); - } - /// - /// Inserts the given item without raising a selection changed event. - /// - /// Insertion index. If index is -1 the item is added to the end of the list. - /// The to add. - /// The adaptor associated with this item. - /// true if the item was added; otherwise false. - internal bool InsertInternal(int index, ImageListViewItem item, ImageListView.ImageListViewItemAdaptor adaptor) - { - if (mImageListView == null) - return false; - - // Check if the file already exists - if (!string.IsNullOrEmpty(item.FileName) && !mImageListView.AllowDuplicateFileNames) - { - if (mItems.Exists(a => string.Compare(a.FileName, item.FileName, StringComparison.OrdinalIgnoreCase) == 0)) - return false; - } - item.owner = this; - item.mAdaptor = adaptor; - if (index == -1) - { - item.mIndex = mItems.Count; - mItems.Add(item); - } - else - { - item.mIndex = index; - for (int i = index; i < mItems.Count; i++) - mItems[i].mIndex++; - mItems.Insert(index, item); - } - lookUp.Add(item.Guid, item); - collectionModified = true; - - item.mImageListView = mImageListView; - - // Create sub item texts for custom columns - foreach (ImageListViewColumnHeader header in mImageListView.Columns) - if (header.Type == ColumnType.Custom) - item.AddSubItemText(header.Guid); - - // Add current thumbnail to cache - if (item.clonedThumbnail != null) - { - mImageListView.thumbnailCache.Add(item.Guid, item.Adaptor, item.VirtualItemKey, mImageListView.ThumbnailSize, - item.clonedThumbnail, mImageListView.UseEmbeddedThumbnails, mImageListView.AutoRotateThumbnails, - (mImageListView.UseWIC == UseWIC.Auto || mImageListView.UseWIC == UseWIC.ThumbnailsOnly)); - item.clonedThumbnail = null; - } - - // Add to thumbnail cache - if (mImageListView.CacheMode == CacheMode.Continuous) - { - mImageListView.thumbnailCache.Add(item.Guid, item.Adaptor, item.VirtualItemKey, - mImageListView.ThumbnailSize, mImageListView.UseEmbeddedThumbnails, mImageListView.AutoRotateThumbnails, - (mImageListView.UseWIC == UseWIC.Auto || mImageListView.UseWIC == UseWIC.ThumbnailsOnly)); - } - - // Add to details cache - mImageListView.metadataCache.Add(item.Guid, item.Adaptor, item.VirtualItemKey, - (mImageListView.UseWIC == UseWIC.Auto || mImageListView.UseWIC == UseWIC.DetailsOnly)); - - // Add to shell info cache - string extension = item.extension; - if (!string.IsNullOrEmpty(extension)) - { - CacheState state = mImageListView.shellInfoCache.GetCacheState(extension); - if (state == CacheState.Error && mImageListView.RetryOnError == true) - { - mImageListView.shellInfoCache.Remove(extension); - mImageListView.shellInfoCache.Add(extension); - } - else if (state == CacheState.Unknown) - mImageListView.shellInfoCache.Add(extension); - } - - // Update groups - if (mImageListView.showGroups) - AddRemoveGroupItem(item.Index, true); - - // Raise the add event - mImageListView.OnItemCollectionChanged(new ItemCollectionChangedEventArgs(CollectionChangeAction.Add, item)); - - return true; - } - /// - /// Removes the given item without raising a selection changed event. - /// - /// The item to remove. - internal void RemoveInternal(ImageListViewItem item) - { - RemoveInternal(item, true); - } - /// - /// Removes the given item without raising a selection changed event. - /// - /// The item to remove. - /// true to remove item image from cache; otherwise false. - internal bool RemoveInternal(ImageListViewItem item, bool removeFromCache) - { - for (int i = item.mIndex + 1; i < mItems.Count; i++) - mItems[i].mIndex--; - if (item == mFocused) mFocused = null; - if (removeFromCache && mImageListView != null) - { - mImageListView.thumbnailCache.Remove(item.Guid); - mImageListView.metadataCache.Remove(item.Guid); - } - bool ret = mItems.Remove(item); - lookUp.Remove(item.Guid); - collectionModified = true; - - if (mImageListView != null) - { - // Raise the remove event - mImageListView.OnItemCollectionChanged(new ItemCollectionChangedEventArgs(CollectionChangeAction.Remove, item)); - - if (mImageListView.showGroups) - AddRemoveGroupItem(item.Index, false); - } - - return ret; - } - /// - /// Returns the index of the specified item. - /// - internal int IndexOf(ImageListViewItem item) - { - return item.Index; - } - /// - /// Returns the index of the item with the specified Guid. - /// - internal int IndexOf(Guid guid) - { - ImageListViewItem item = null; - if (lookUp.TryGetValue(guid, out item)) - return item.Index; - return -1; - } - /// - /// Sorts the items by the sort order and sort column of the owner. - /// - internal void Sort() - { - if (mImageListView == null) - return; - - mImageListView.showGroups = false; - mImageListView.groups.Clear(); - - if ((mImageListView.GroupOrder == SortOrder.None || mImageListView.GroupColumn < 0 || mImageListView.GroupColumn >= mImageListView.Columns.Count) && - (mImageListView.SortOrder == SortOrder.None || mImageListView.SortColumn < 0 || mImageListView.SortColumn >= mImageListView.Columns.Count)) - return; - - // Display wait cursor while sorting - Cursor cursor = mImageListView.Cursor; - mImageListView.Cursor = Cursors.WaitCursor; - - // Sort and group items - ImageListViewColumnHeader sortColumn = null; - ImageListViewColumnHeader groupColumn = null; - if (mImageListView.GroupColumn >= 0 && mImageListView.GroupColumn < mImageListView.Columns.Count) - groupColumn = mImageListView.Columns[mImageListView.GroupColumn]; - if (mImageListView.SortColumn >= 0 || mImageListView.SortColumn < mImageListView.Columns.Count) - sortColumn = mImageListView.Columns[mImageListView.SortColumn]; - if (mItems.Count == 1 && groupColumn != null) - mItems[0].UpdateGroup(groupColumn); - mItems.Sort(new ImageListViewItemComparer(groupColumn, mImageListView.GroupOrder, sortColumn, mImageListView.SortOrder)); - if (mImageListView.GroupOrder != SortOrder.None && groupColumn != null) - mImageListView.showGroups = true; - - // Update item indices and create groups - string lastGroup = string.Empty; - for (int i = 0; i < mItems.Count; i++) - { - ImageListViewItem item = mItems[i]; - item.mIndex = i; - string group = item.group; - - if (string.Compare(lastGroup, group, StringComparison.InvariantCultureIgnoreCase) != 0) - { - lastGroup = group; - mImageListView.groups.Add(group, i, i); - } - else if (mImageListView.groups.HasName(lastGroup)) - { - mImageListView.groups[lastGroup].LastItemIndex = i; - } - } - - // Restore previous cursor - mImageListView.Cursor = cursor; - collectionModified = true; - } - /// - /// Updates groups after adding or removing an item. This just updates - /// the count of items in groups, it DOES NOT re-sort the items. - /// - /// The index of the new or removed item. - /// true to add an item; false to remove a item. - private void AddRemoveGroupItem(int index, bool add) - { - if (mImageListView == null || !mImageListView.showGroups) - return; - if (mImageListView.groups.Count == 0) - { - Sort(); - return; - } - - // Special case of adding an item to the end - ImageListView.ImageListViewGroup lastGroup = mImageListView.groups[mImageListView.groups.Count - 1]; - if (add && index == lastGroup.LastItemIndex + 1) - { - lastGroup.LastItemIndex++; - return; - } - - // Insert into a group - List emptyGroups = new List(); - foreach (ImageListView.ImageListViewGroup group in mImageListView.groups) - { - if (group.LastItemIndex < index) - continue; - else if (group.FirstItemIndex <= index && group.LastItemIndex >= index) - { - if (add) - { - group.LastItemIndex++; - } - else - { - group.LastItemIndex--; - } - } - else // if (group.FirstItemIndex > index) - { - if (add) - { - group.FirstItemIndex++; - group.LastItemIndex++; - } - else - { - group.FirstItemIndex--; - group.LastItemIndex--; - } - } - - if (group.ItemCount == 0) - emptyGroups.Add(group); - } - - // Purge empty groups - foreach (ImageListView.ImageListViewGroup group in emptyGroups) - mImageListView.groups.Remove(group); - } - #endregion - - #region ImageListViewItemComparer - /// - /// Compares items by the sort order and sort column of the owner. - /// - private class ImageListViewItemComparer : IComparer - { - private ImageListViewColumnHeader mGroupColumn; - private ImageListViewColumnHeader mSortColumn; - private SortOrder mGroupOrder; - private SortOrder mSortOrder; - - public ImageListViewItemComparer(ImageListViewColumnHeader groupColumn, SortOrder groupOrder, ImageListViewColumnHeader sortColumn, SortOrder sortOrder) - { - mGroupColumn = groupColumn; - mSortColumn = sortColumn; - mGroupOrder = groupOrder; - mSortOrder = sortOrder; - } - - /// - /// Compares two strings and returns a value indicating whether one is less than, equal to, or greater than the other. - /// - private int CompareStrings(string x, string y, bool natural) - { - if (!natural) - return string.Compare(x, y, StringComparison.InvariantCultureIgnoreCase); - - // Following natural sort algorithm is taken from: - // http://www.interact-sw.co.uk/iangblog/2007/12/13/natural-sorting - string[] xparts = Regex.Split(x.Replace(" ", ""), "([0-9]+)"); - string[] yparts = Regex.Split(y.Replace(" ", ""), "([0-9]+)"); - for (int i = 0; i < Math.Max(xparts.Length, yparts.Length); i++) - { - bool hasx = (i < xparts.Length); - bool hasy = (i < yparts.Length); - - if (!(hasx || hasy)) return 0; - - if (!hasx) return -1; - if (!hasy) return 1; - - string xpart = xparts[i]; - string ypart = yparts[i]; - - int xi = 0; - int yi = 0; - int res = 0; - - if (int.TryParse(xpart, out xi) && int.TryParse(ypart, out yi)) - res = (xi < yi ? -1 : (xi > yi ? 1 : 0)); - else - res = string.Compare(xpart, ypart, StringComparison.InvariantCultureIgnoreCase); - - if (res != 0) return res; - } - return 0; - } - - /// - /// Compares two objects and returns a value indicating whether one is less than, equal to, or greater than the other. - /// - public int Compare(ImageListViewItem x, ImageListViewItem y) - { - int result = 0; - int sign = 0; - bool natural = false; - - if (mGroupOrder != SortOrder.None) - { - result = 0; - sign = ((mGroupOrder == SortOrder.Ascending || mGroupOrder == SortOrder.AscendingNatural) ? 1 : -1); - - x.UpdateGroup(mGroupColumn); - y.UpdateGroup(mGroupColumn); - result = (x.groupOrder < y.groupOrder ? -1 : (x.groupOrder > y.groupOrder ? 1 : 0)); - if (result != 0) - return sign * result; - } - - if (mSortOrder != SortOrder.None) - { - result = 0; - sign = ((mSortOrder == SortOrder.Ascending || mSortOrder == SortOrder.AscendingNatural) ? 1 : -1); - natural = (mSortOrder == SortOrder.AscendingNatural || mSortOrder == SortOrder.DescendingNatural); - if (mSortColumn != null) - { - switch (mSortColumn.Type) - { - case ColumnType.DateAccessed: - result = DateTime.Compare(x.DateAccessed, y.DateAccessed); - break; - case ColumnType.DateCreated: - result = DateTime.Compare(x.DateCreated, y.DateCreated); - break; - case ColumnType.DateModified: - result = DateTime.Compare(x.DateModified, y.DateModified); - break; - case ColumnType.Dimensions: - long ax = x.Dimensions.Width * x.Dimensions.Height; - long ay = y.Dimensions.Width * y.Dimensions.Height; - result = (ax < ay ? -1 : (ax > ay ? 1 : 0)); - break; - case ColumnType.FileName: - result = CompareStrings(x.FileName, y.FileName, natural); - break; - case ColumnType.FilePath: - result = CompareStrings(x.FilePath, y.FilePath, natural); - break; - case ColumnType.FileSize: - result = (x.FileSize < y.FileSize ? -1 : (x.FileSize > y.FileSize ? 1 : 0)); - break; - case ColumnType.FileType: - result = CompareStrings(x.FileType, y.FileType, natural); - break; - case ColumnType.Name: - result = CompareStrings(x.Text, y.Text, natural); - break; - case ColumnType.Resolution: - float rx = x.Resolution.Width * x.Resolution.Height; - float ry = y.Resolution.Width * y.Resolution.Height; - result = (rx < ry ? -1 : (rx > ry ? 1 : 0)); - break; - case ColumnType.ImageDescription: - result = CompareStrings(x.ImageDescription, y.ImageDescription, natural); - break; - case ColumnType.EquipmentModel: - result = CompareStrings(x.EquipmentModel, y.EquipmentModel, natural); - break; - case ColumnType.DateTaken: - result = DateTime.Compare(x.DateTaken, y.DateTaken); - break; - case ColumnType.Artist: - result = CompareStrings(x.Artist, y.Artist, natural); - break; - case ColumnType.Copyright: - result = CompareStrings(x.Copyright, y.Copyright, natural); - break; - case ColumnType.ExposureTime: - result = (x.ExposureTime < y.ExposureTime ? -1 : (x.ExposureTime > y.ExposureTime ? 1 : 0)); - break; - case ColumnType.FNumber: - result = (x.FNumber < y.FNumber ? -1 : (x.FNumber > y.FNumber ? 1 : 0)); - break; - case ColumnType.ISOSpeed: - result = (x.ISOSpeed < y.ISOSpeed ? -1 : (x.ISOSpeed > y.ISOSpeed ? 1 : 0)); - break; - case ColumnType.UserComment: - result = CompareStrings(x.UserComment, y.UserComment, natural); - break; - case ColumnType.Rating: - result = (x.Rating < y.Rating ? -1 : (x.Rating > y.Rating ? 1 : 0)); - break; - case ColumnType.Software: - result = CompareStrings(x.Software, y.Software, natural); - break; - case ColumnType.FocalLength: - result = (x.FocalLength < y.FocalLength ? -1 : (x.FocalLength > y.FocalLength ? 1 : 0)); - break; - case ColumnType.Custom: - result = CompareStrings(x.GetSubItemText(mSortColumn.Guid), y.GetSubItemText(mSortColumn.Guid), natural); - break; - default: - result = 0; - break; - } - } - } - - return sign * result; - } - } - #endregion - - #region Unsupported Interface - /// - /// Copies the elements of the to an , starting at a particular index. - /// - void ICollection.CopyTo(ImageListViewItem[] array, int arrayIndex) - { - mItems.CopyTo(array, arrayIndex); - } - /// - /// Determines the index of a specific item in the . - /// - [Obsolete("Use ImageListViewItem.Index property instead.")] - int IList.IndexOf(ImageListViewItem item) - { - return mItems.IndexOf(item); - } - /// - /// Copies the elements of the to an , starting at a particular index. - /// - void ICollection.CopyTo(Array array, int index) - { - if (!(array is ImageListViewItem[])) - throw new ArgumentException("An array of ImageListViewItem is required.", "array"); - mItems.CopyTo((ImageListViewItem[])array, index); - } - /// - /// Gets the number of elements contained in the . - /// - int ICollection.Count - { - get { return mItems.Count; } - } - /// - /// Gets a value indicating whether access to the is synchronized (thread safe). - /// - bool ICollection.IsSynchronized - { - get { return false; } - } - /// - /// Gets an object that can be used to synchronize access to the . - /// - object ICollection.SyncRoot - { - get { throw new NotSupportedException(); } - } - /// - /// Adds an item to the . - /// - int IList.Add(object value) - { - if (!(value is ImageListViewItem)) - throw new ArgumentException("An object of type ImageListViewItem is required.", "value"); - ImageListViewItem item = (ImageListViewItem)value; - Add(item); - return mItems.IndexOf(item); - } - /// - /// Determines whether the contains a specific value. - /// - bool IList.Contains(object value) - { - if (!(value is ImageListViewItem)) - throw new ArgumentException("An object of type ImageListViewItem is required.", "value"); - return mItems.Contains((ImageListViewItem)value); - } - /// - /// Returns an enumerator that iterates through a collection. - /// - /// - /// An object that can be used to iterate through the collection. - /// - System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() - { - return mItems.GetEnumerator(); - } - /// - /// Determines the index of a specific item in the . - /// - int IList.IndexOf(object value) - { - if (!(value is ImageListViewItem)) - throw new ArgumentException("An object of type ImageListViewItem is required.", "value"); - return IndexOf((ImageListViewItem)value); - } - /// - /// Inserts an item to the at the specified index. - /// - void IList.Insert(int index, object value) - { - if (!(value is ImageListViewItem)) - throw new ArgumentException("An object of type ImageListViewItem is required.", "value"); - Insert(index, (ImageListViewItem)value); - } - /// - /// Gets a value indicating whether the has a fixed size. - /// - bool IList.IsFixedSize - { - get { return false; } - } - /// - /// Removes the first occurrence of a specific object from the . - /// - void IList.Remove(object value) - { - if (!(value is ImageListViewItem)) - throw new ArgumentException("An object of type ImageListViewItem is required.", "value"); - ImageListViewItem item = (ImageListViewItem)value; - Remove(item); - } - /// - /// Gets or sets the at the specified index. - /// - object IList.this[int index] - { - get - { - return this[index]; - } - set - { - if (!(value is ImageListViewItem)) - throw new ArgumentException("An object of type ImageListViewItem is required.", "value"); - this[index] = (ImageListViewItem)value; - } - } - #endregion - } - } -} \ No newline at end of file diff --git a/Source/Components/ImageGlass.ImageListView/ImageListViewItemTypeConverter.cs b/Source/Components/ImageGlass.ImageListView/ImageListViewItemTypeConverter.cs deleted file mode 100644 index 5b317bf73..000000000 --- a/Source/Components/ImageGlass.ImageListView/ImageListViewItemTypeConverter.cs +++ /dev/null @@ -1,76 +0,0 @@ -// ImageListView - A listview control for image files -// Copyright (C) 2009 Ozgur Ozcitak -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// Ozgur Ozcitak (ozcitak@yahoo.com) - -using System; -using System.Globalization; -using System.ComponentModel; -using System.Reflection; -using System.ComponentModel.Design.Serialization; - -namespace ImageGlass.ImageListView -{ - /// - /// Represents the type converter for the items of the image list view. - /// - internal class ImageListViewItemTypeConverter : TypeConverter - { - #region TypeConverter Overrides - /// - /// Returns whether this converter can convert the - /// object to the specified type, using the specified context. - /// - /// Format context. - /// The type you want to convert to. - /// true if this converter can perform the conversion; otherwise, false. - public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType) - { - if (destinationType == typeof(InstanceDescriptor)) - return true; - - return base.CanConvertTo(context, destinationType); - } - /// - /// Converts the given value object to the specified type, - /// using the specified context and culture information. - /// - /// Format context. - /// The culture info. If null is passed, the current culture is assumed. - /// The objct to convert. - /// The type to convert to. - /// An object that represents the converted value. - public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType) - { - if (value != null && value is ImageListViewItem) - { - ImageListViewItem item = (ImageListViewItem)value; - - if (destinationType == typeof(InstanceDescriptor)) - { - ConstructorInfo consInfo = typeof(ImageListViewItem).GetConstructor(new Type[] { - typeof(string), typeof(string), typeof(object) - }); - return new InstanceDescriptor(consInfo, new object[] { - item.FileName, item.Text, item.Tag - }); - } - } - - return base.ConvertTo(context, culture, value, destinationType); - } - #endregion - } -} diff --git a/Source/Components/ImageGlass.ImageListView/ImageListViewLayoutManager.cs b/Source/Components/ImageGlass.ImageListView/ImageListViewLayoutManager.cs deleted file mode 100644 index d2f5bb381..000000000 --- a/Source/Components/ImageGlass.ImageListView/ImageListViewLayoutManager.cs +++ /dev/null @@ -1,774 +0,0 @@ -// ImageListView - A listview control for image files -// Copyright (C) 2009 Ozgur Ozcitak -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// Ozgur Ozcitak (ozcitak@yahoo.com) - -using System; -using System.Collections.Generic; -using System.Drawing; - -namespace ImageGlass.ImageListView -{ - /// - /// Represents the layout of the image list view drawing area. - /// - internal class ImageListViewLayoutManager - { - #region Member Variables - private Rectangle mClientArea; - private ImageListView mImageListView; - private Rectangle mItemAreaBounds; - private Rectangle mColumnHeaderBounds; - private Size mItemSize; - private Size mItemSizeWithMargin; - private int mDisplayedCols; - private int mDisplayedRows; - private int mItemCols; - private int mItemRows; - private int mFirstPartiallyVisible; - private int mLastPartiallyVisible; - private int mFirstVisible; - private int mLastVisible; - - private View cachedView; - private Point cachedViewOffset; - private Size cachedSize; - private int cachedItemCount; - private Size cachedItemSize; - private int cachedGroupHeaderHeight; - private int cachedColumnHeaderHeight; - private bool cachedIntegralScroll; - private Size cachedItemMargin; - private int cachedPaneWidth; - private bool cachedScrollBars; - private Dictionary cachedVisibleItems; - - private bool vScrollVisible; - private bool hScrollVisible; - - // Size required to display all items (i.e. scroll range) - private int totalWidth; - private int totalHeight; - #endregion - - #region Properties - /// - /// Gets the bounds of the entire client area. - /// - public Rectangle ClientArea { get { return mClientArea; } } - /// - /// Gets the owner image list view. - /// - public ImageListView ImageListView { get { return mImageListView; } } - /// - /// Gets the extends of the item area. - /// - public Rectangle ItemAreaBounds { get { return mItemAreaBounds; } } - /// - /// Gets the extents of the column header area. - /// - public Rectangle ColumnHeaderBounds { get { return mColumnHeaderBounds; } } - /// - /// Gets the items size. - /// - public Size ItemSize { get { return mItemSize; } } - /// - /// Gets the items size including the margin around the item. - /// - public Size ItemSizeWithMargin { get { return mItemSizeWithMargin; } } - /// - /// Gets the maximum number of columns that can be displayed. - /// - public int Cols { get { return mDisplayedCols; } } - /// - /// Gets the maximum number of rows that can be displayed. - /// - public int Rows { get { return mDisplayedRows; } } - /// - /// Gets the index of the first partially visible item. - /// - public int FirstPartiallyVisible { get { return mFirstPartiallyVisible; } } - /// - /// Gets the index of the last partially visible item. - /// - public int LastPartiallyVisible { get { return mLastPartiallyVisible; } } - /// - /// Gets the index of the first fully visible item. - /// - public int FirstVisible { get { return mFirstVisible; } } - /// - /// Gets the index of the last fully visible item. - /// - public int LastVisible { get { return mLastVisible; } } - /// - /// Determines whether an update is required. - /// - public bool UpdateRequired - { - get - { - if (mImageListView.View != cachedView) - return true; - else if (mImageListView.ViewOffset != cachedViewOffset) - return true; - else if (mImageListView.ClientSize != cachedSize) - return true; - else if (mImageListView.Items.Count != cachedItemCount) - return true; - else if (mImageListView.mRenderer.MeasureItem(mImageListView.View) != cachedItemSize) - return true; - else if (mImageListView.mRenderer.MeasureGroupHeaderHeight() != cachedGroupHeaderHeight) - return true; - else if (mImageListView.mRenderer.MeasureColumnHeaderHeight() != cachedColumnHeaderHeight) - return true; - else if (mImageListView.mRenderer.MeasureItemMargin(mImageListView.View) != cachedItemMargin) - return true; - else if (mImageListView.PaneWidth != cachedPaneWidth) - return true; - else if (mImageListView.ScrollBars != cachedScrollBars) - return true; - else if (mImageListView.IntegralScroll != cachedIntegralScroll) - return true; - else if (mImageListView.Items.collectionModified) - return true; - else if (mImageListView.groups.collectionModified) - return true; - else - return false; - } - } - #endregion - - #region Constructor - /// - /// Initializes a new instance of the ImageListViewLayoutManager class. - /// - /// The owner control. - public ImageListViewLayoutManager(ImageListView owner) - { - mImageListView = owner; - cachedVisibleItems = new Dictionary(); - - vScrollVisible = false; - hScrollVisible = false; - - Update(); - } - #endregion - - #region Instance Methods - /// - /// Determines whether the item with the given guid is - /// (partially) visible. - /// - /// The guid of the item to check. - public bool IsItemVisible(Guid guid) - { - return cachedVisibleItems.ContainsKey(guid); - } - /// - /// Returns the bounds of the item with the specified index. - /// - public Rectangle GetItemBounds(int itemIndex) - { - Point location = new Point(); - - if (mImageListView.showGroups) - { - foreach (ImageListView.ImageListViewGroup group in mImageListView.groups) - { - if (itemIndex >= group.FirstItemIndex && itemIndex <= group.LastItemIndex) - { - location = group.itemBounds.Location; - location.X += cachedItemMargin.Width / 2; - location.Y += cachedItemMargin.Height / 2; - - if (mImageListView.View == View.Gallery) - location.X += (itemIndex - group.FirstItemIndex) * mItemSizeWithMargin.Width; - else - { - location.X += ((itemIndex - group.FirstItemIndex) % mDisplayedCols) * mItemSizeWithMargin.Width; - location.Y += ((itemIndex - group.FirstItemIndex) / mDisplayedCols) * mItemSizeWithMargin.Height; - } - break; - } - } - } - else - { - location = mItemAreaBounds.Location; - location.X += cachedItemMargin.Width / 2 - mImageListView.ViewOffset.X; - location.Y += cachedItemMargin.Height / 2 - mImageListView.ViewOffset.Y; - - if (mImageListView.View == View.Gallery) - location.X += itemIndex * mItemSizeWithMargin.Width; - else - { - location.X += (itemIndex % mDisplayedCols) * mItemSizeWithMargin.Width; - location.Y += (itemIndex / mDisplayedCols) * mItemSizeWithMargin.Height; - } - } - - return new Rectangle(location, mItemSize); - } - /// - /// Returns the bounds of the item with the specified index, - /// including the margin around the item. - /// - public Rectangle GetItemBoundsWithMargin(int itemIndex) - { - Rectangle rec = GetItemBounds(itemIndex); - rec.Inflate(cachedItemMargin.Width / 2, cachedItemMargin.Height / 2); - return rec; - } - /// - /// Returns the item checkbox bounds. - /// This method assumes a checkbox icon size of 16x16 - /// - public Rectangle GetCheckBoxBounds(int itemIndex) - { - Rectangle bounds = GetWidgetBounds(GetItemBounds(itemIndex), new Size(16, 16), - mImageListView.CheckBoxPadding, mImageListView.CheckBoxAlignment); - - // If the checkbox and the icon have the same alignment, - // move the checkbox horizontally away from the icon - if (mImageListView.View != View.Details && mImageListView.CheckBoxAlignment == mImageListView.IconAlignment && - mImageListView.ShowCheckBoxes && mImageListView.ShowFileIcons) - { - ContentAlignment alignment = mImageListView.CheckBoxAlignment; - if (alignment == ContentAlignment.BottomCenter || alignment == ContentAlignment.MiddleCenter || alignment == ContentAlignment.TopCenter) - bounds.X -= 8 + mImageListView.IconPadding.Width / 2; - else if (alignment == ContentAlignment.BottomRight || alignment == ContentAlignment.MiddleRight || alignment == ContentAlignment.TopRight) - bounds.X -= 16 + mImageListView.IconPadding.Width; - } - - return bounds; - } - /// - /// Returns the item icon bounds. - /// This method assumes an icon size of 16x16 - /// - public Rectangle GetIconBounds(int itemIndex) - { - Rectangle bounds = GetWidgetBounds(GetItemBounds(itemIndex), new Size(16, 16), - mImageListView.IconPadding, mImageListView.IconAlignment); - - // If the checkbox and the icon have the same alignment, - // or in details view move the icon horizontally away from the checkbox - if (mImageListView.View == View.Details && mImageListView.ShowCheckBoxes && mImageListView.ShowFileIcons) - bounds.X += 16 + 2; - else if (mImageListView.CheckBoxAlignment == mImageListView.IconAlignment && - mImageListView.ShowCheckBoxes && mImageListView.ShowFileIcons) - { - ContentAlignment alignment = mImageListView.CheckBoxAlignment; - if (alignment == ContentAlignment.BottomLeft || alignment == ContentAlignment.MiddleLeft || alignment == ContentAlignment.TopLeft) - bounds.X += 16 + mImageListView.IconPadding.Width; - else if (alignment == ContentAlignment.BottomCenter || alignment == ContentAlignment.MiddleCenter || alignment == ContentAlignment.TopCenter) - bounds.X += 8 + mImageListView.IconPadding.Width / 2; - } - - return bounds; - } - /// - /// Returns the bounds of a widget. - /// Used to calculate the bounds of checkboxes and icons. - /// - private Rectangle GetWidgetBounds(Rectangle bounds, Size size, Size padding, ContentAlignment alignment) - { - // Apply padding - if (mImageListView.View == View.Details) - bounds.Inflate(-2, -2); - else - bounds.Inflate(-padding.Width, -padding.Height); - - int x = 0; - if (mImageListView.View == View.Details) - x = bounds.Left; - else if (alignment == ContentAlignment.BottomLeft || alignment == ContentAlignment.MiddleLeft || alignment == ContentAlignment.TopLeft) - x = bounds.Left; - else if (alignment == ContentAlignment.BottomCenter || alignment == ContentAlignment.MiddleCenter || alignment == ContentAlignment.TopCenter) - x = bounds.Left + bounds.Width / 2 - size.Width / 2; - else // if (alignment == ContentAlignment.BottomRight || alignment == ContentAlignment.MiddleRight || alignment == ContentAlignment.TopRight) - x = bounds.Right - size.Width; - - int y = 0; - if (mImageListView.View == View.Details) - y = bounds.Top + bounds.Height / 2 - size.Height / 2; - else if (alignment == ContentAlignment.BottomLeft || alignment == ContentAlignment.BottomCenter || alignment == ContentAlignment.BottomRight) - y = bounds.Bottom - size.Height; - else if (alignment == ContentAlignment.MiddleLeft || alignment == ContentAlignment.MiddleCenter || alignment == ContentAlignment.MiddleRight) - y = bounds.Top + bounds.Height / 2 - size.Height / 2; - else // if (alignment == ContentAlignment.TopLeft || alignment == ContentAlignment.TopCenter || alignment == ContentAlignment.TopRight) - y = bounds.Top; - - return new Rectangle(x, y, size.Width, size.Height); - } - /// - /// Recalculates the control layout. - /// - public void Update() - { - Update(false); - } - /// - /// Recalculates the control layout. - /// true to force an update; otherwise false. - /// - public void Update(bool forceUpdate) - { - if (mImageListView.ClientRectangle.Width == 0 || mImageListView.ClientRectangle.Height == 0) - return; - - // If only item order is changed, just update visible items. - if (!forceUpdate && !UpdateRequired && mImageListView.Items.collectionModified) - { - UpdateGroups(); - UpdateVisibleItems(); - return; - } - - if (!forceUpdate && !UpdateRequired) - return; - - // Get the item size from the renderer - mItemSize = mImageListView.mRenderer.MeasureItem(mImageListView.View); - cachedItemMargin = mImageListView.mRenderer.MeasureItemMargin(mImageListView.View); - mItemSizeWithMargin = mItemSize + cachedItemMargin; - - // Cache current properties to determine if we will need an update later - bool viewChanged = (cachedView != mImageListView.View); - cachedView = mImageListView.View; - cachedViewOffset = mImageListView.ViewOffset; - cachedSize = mImageListView.ClientSize; - cachedItemCount = mImageListView.Items.Count; - cachedIntegralScroll = mImageListView.IntegralScroll; - cachedItemSize = mItemSize; - cachedGroupHeaderHeight = mImageListView.mRenderer.MeasureGroupHeaderHeight(); - cachedColumnHeaderHeight = mImageListView.mRenderer.MeasureColumnHeaderHeight(); - cachedPaneWidth = mImageListView.PaneWidth; - cachedScrollBars = mImageListView.ScrollBars; - mImageListView.Items.collectionModified = false; - mImageListView.groups.collectionModified = false; - - // Calculate item area bounds - if (!UpdateItemArea()) - return; - - // Let the calculated bounds modified by the renderer - LayoutEventArgs eLayout = new LayoutEventArgs(mItemAreaBounds); - mImageListView.mRenderer.OnLayout(eLayout); - mItemAreaBounds = eLayout.ItemAreaBounds; - if (mItemAreaBounds.Width <= 0 || mItemAreaBounds.Height <= 0) - return; - - // Calculate the number of rows and columns - CalculateGrid(); - - // Update groups - UpdateGroups(); - - // Check if we need the scroll bars. - // Recalculate the layout if scroll bar visibility changes. - if (CheckScrollBars()) - { - Update(true); - return; - } - - // Update scroll range - UpdateScrollBars(); - - // Cache visible items - UpdateVisibleItems(); - - // Recalculate the layout if view mode was changed - if (viewChanged) - Update(); - } - /// - /// Calculates the maximum number of rows and columns - /// that can be fully displayed. - /// - private void CalculateGrid() - { - // Number of rows and columns shown on screen - mDisplayedRows = (int)System.Math.Floor((float)mItemAreaBounds.Height / (float)mItemSizeWithMargin.Height); - mDisplayedCols = (int)System.Math.Floor((float)mItemAreaBounds.Width / (float)mItemSizeWithMargin.Width); - - if (mImageListView.View == View.Details) mDisplayedCols = 1; - if (mImageListView.View == View.Gallery) mDisplayedRows = 1; - if (mDisplayedCols < 1) mDisplayedCols = 1; - if (mDisplayedRows < 1) mDisplayedRows = 1; - - // Number of rows and columns to enclose all items - if (mImageListView.View == View.Gallery) - { - mItemRows = mDisplayedRows; - mItemCols = (int)System.Math.Ceiling((float)mImageListView.Items.Count / (float)mDisplayedRows); - } - else - { - mItemCols = mDisplayedCols; - mItemRows = (int)System.Math.Ceiling((float)mImageListView.Items.Count / (float)mDisplayedCols); - } - - totalWidth = mItemCols * mItemSizeWithMargin.Width; - totalHeight = mItemRows * mItemSizeWithMargin.Height; - } - /// - /// Calculates the item area. - /// - /// true if the item area is not empty (both width and height - /// greater than zero); otherwise false. - private bool UpdateItemArea() - { - // Calculate drawing area - mClientArea = mImageListView.ClientRectangle; - if (mImageListView.BorderStyle != System.Windows.Forms.BorderStyle.None) - mClientArea.Inflate(-1, -1); - mItemAreaBounds = mClientArea; - - // Allocate space for scrollbars - if (mImageListView.hScrollBar.Visible) - { - mClientArea.Height -= mImageListView.hScrollBar.Height; - mItemAreaBounds.Height -= mImageListView.hScrollBar.Height; - } - if (mImageListView.vScrollBar.Visible) - { - mClientArea.Width -= mImageListView.vScrollBar.Width; - mItemAreaBounds.Width -= mImageListView.vScrollBar.Width; - } - - // Allocate space for column headers - if (mImageListView.View == View.Details) - { - int headerHeight = cachedColumnHeaderHeight; - - // Location of the column headers - mColumnHeaderBounds.X = mClientArea.Left - mImageListView.ViewOffset.X; - mColumnHeaderBounds.Y = mClientArea.Top; - mColumnHeaderBounds.Height = headerHeight; - mColumnHeaderBounds.Width = mClientArea.Width + mImageListView.ViewOffset.X; - - mItemAreaBounds.Y += headerHeight; - mItemAreaBounds.Height -= headerHeight; - } - else - { - mColumnHeaderBounds = Rectangle.Empty; - } - // Modify item area for the gallery view mode - if (mImageListView.View == View.Gallery) - { - mItemAreaBounds.Height = mItemSizeWithMargin.Height; - mItemAreaBounds.Y = mClientArea.Bottom - mItemSizeWithMargin.Height; - } - // Modify item area for the pane view mode - if (mImageListView.View == View.Pane) - { - mItemAreaBounds.Width -= cachedPaneWidth; - mItemAreaBounds.X += cachedPaneWidth; - } - - return (mItemAreaBounds.Width > 0 && mItemAreaBounds.Height > 0); - } - /// - /// Shows or hides the scroll bars. - /// Returns true if the layout needs to be recalculated; otherwise false. - /// - /// - private bool CheckScrollBars() - { - // Horizontal scroll bar - bool hScrollRequired = false; - bool hScrollChanged = false; - if (mImageListView.ScrollBars) - hScrollRequired = (mImageListView.Items.Count > 0) && (mItemAreaBounds.Width < totalWidth); - - if (hScrollRequired != hScrollVisible) - { - hScrollVisible = hScrollRequired; - mImageListView.hScrollBar.Visible = hScrollRequired; - hScrollChanged = true; - } - - // Vertical scroll bar - bool vScrollRequired = false; - bool vScrollChanged = false; - if (mImageListView.ScrollBars) - vScrollRequired = (mImageListView.Items.Count > 0) && (mItemAreaBounds.Height < totalHeight); - - if (vScrollRequired != vScrollVisible) - { - vScrollVisible = vScrollRequired; - mImageListView.vScrollBar.Visible = vScrollRequired; - vScrollChanged = true; - } - - // Determine if the layout needs to be recalculated - return (hScrollChanged || vScrollChanged); - } - /// - /// Updates scroll bar parameters. - /// - private void UpdateScrollBars() - { - // Set scroll range - if (mImageListView.Items.Count != 0) - { - // Horizontal scroll range - if (mImageListView.ScrollOrientation == System.Windows.Forms.ScrollOrientation.HorizontalScroll) - { - mImageListView.hScrollBar.Minimum = 0; - mImageListView.hScrollBar.Maximum = Math.Max(0, totalWidth - 1); - if (!mImageListView.IntegralScroll) - mImageListView.hScrollBar.LargeChange = mItemAreaBounds.Width; - else - mImageListView.hScrollBar.LargeChange = mItemSizeWithMargin.Width * mDisplayedCols; - mImageListView.hScrollBar.SmallChange = mItemSizeWithMargin.Width; - } - else - { - mImageListView.hScrollBar.Minimum = 0; - mImageListView.hScrollBar.Maximum = mDisplayedCols * mItemSizeWithMargin.Width; - mImageListView.hScrollBar.LargeChange = mItemAreaBounds.Width; - mImageListView.hScrollBar.SmallChange = 1; - } - if (mImageListView.ViewOffset.X > mImageListView.hScrollBar.Maximum - mImageListView.hScrollBar.LargeChange + 1) - { - mImageListView.hScrollBar.Value = mImageListView.hScrollBar.Maximum - mImageListView.hScrollBar.LargeChange + 1; - mImageListView.ViewOffset = new Point(mImageListView.hScrollBar.Value, mImageListView.ViewOffset.Y); - } - - // Vertical scroll range - if (mImageListView.ScrollOrientation == System.Windows.Forms.ScrollOrientation.HorizontalScroll) - { - mImageListView.vScrollBar.Minimum = 0; - mImageListView.vScrollBar.Maximum = mDisplayedRows * mItemSizeWithMargin.Height; - mImageListView.vScrollBar.LargeChange = mItemAreaBounds.Height; - mImageListView.vScrollBar.SmallChange = 1; - } - else - { - mImageListView.vScrollBar.Minimum = 0; - mImageListView.vScrollBar.Maximum = Math.Max(0, totalHeight - 1); - if (!mImageListView.IntegralScroll) - mImageListView.vScrollBar.LargeChange = mItemAreaBounds.Height; - else - mImageListView.vScrollBar.LargeChange = mItemSizeWithMargin.Height * mDisplayedRows; - mImageListView.vScrollBar.SmallChange = mItemSizeWithMargin.Height; - } - if (mImageListView.ViewOffset.Y > mImageListView.vScrollBar.Maximum - mImageListView.vScrollBar.LargeChange + 1) - { - mImageListView.vScrollBar.Value = mImageListView.vScrollBar.Maximum - mImageListView.vScrollBar.LargeChange + 1; - mImageListView.ViewOffset = new Point(mImageListView.ViewOffset.X, mImageListView.vScrollBar.Value); - } - } - else // if (mImageListView.Items.Count == 0) - { - // Zero out the scrollbars if we don't have any items - mImageListView.hScrollBar.Minimum = 0; - mImageListView.hScrollBar.Maximum = 0; - mImageListView.hScrollBar.Value = 0; - mImageListView.vScrollBar.Minimum = 0; - mImageListView.vScrollBar.Maximum = 0; - mImageListView.vScrollBar.Value = 0; - mImageListView.ViewOffset = new Point(0, 0); - } - - // Horizontal scrollbar position - mImageListView.hScrollBar.Left = 0; - mImageListView.hScrollBar.Top = mImageListView.ClientRectangle.Bottom - mImageListView.hScrollBar.Height; - mImageListView.hScrollBar.Width = mImageListView.ClientRectangle.Width - (mImageListView.vScrollBar.Visible ? mImageListView.vScrollBar.Width : 0); - // Vertical scrollbar position - mImageListView.vScrollBar.Left = mImageListView.ClientRectangle.Right - mImageListView.vScrollBar.Width; - mImageListView.vScrollBar.Top = 0; - mImageListView.vScrollBar.Height = mImageListView.ClientRectangle.Height - (mImageListView.hScrollBar.Visible ? mImageListView.hScrollBar.Height : 0); - } - /// - /// Updates the dictionary of visible items. - /// - private void UpdateVisibleItems() - { - // Find the first and last visible items - if (mImageListView.showGroups) - { - mFirstPartiallyVisible = -1; - mLastPartiallyVisible = -1; - mFirstVisible = -1; - mLastVisible = -1; - - foreach (ImageListView.ImageListViewGroup group in mImageListView.groups) - { - // Break out if we moved outside the item area - if ((mImageListView.View == View.Gallery && group.itemBounds.Left > ItemAreaBounds.Right) || - (mImageListView.View != View.Gallery && group.itemBounds.Top > ItemAreaBounds.Bottom)) - break; - - // Skip groups above (or to the left of in gallery mode) item area - if ((mImageListView.View == View.Gallery && group.itemBounds.Right < ItemAreaBounds.Left) || - (mImageListView.View != View.Gallery && group.itemBounds.Bottom < ItemAreaBounds.Top)) - continue; - - if (mFirstPartiallyVisible < 0) - { - if (mImageListView.View == View.Gallery) - { - mFirstPartiallyVisible = group.FirstItemIndex + (int)System.Math.Floor((float)(ItemAreaBounds.Left - group.itemBounds.Left) / (float)mItemSizeWithMargin.Width) * group.itemRows; - mFirstVisible = group.FirstItemIndex + (int)System.Math.Ceiling((float)(ItemAreaBounds.Left - group.itemBounds.Left) / (float)mItemSizeWithMargin.Width) * group.itemRows; - } - else - { - mFirstPartiallyVisible = group.FirstItemIndex + (int)System.Math.Floor((float)(ItemAreaBounds.Top - group.itemBounds.Top) / (float)mItemSizeWithMargin.Height) * group.itemCols; - mFirstVisible = group.FirstItemIndex + (int)System.Math.Ceiling((float)(ItemAreaBounds.Top - group.itemBounds.Top) / (float)mItemSizeWithMargin.Height) * group.itemCols; - } - } - - if (mImageListView.View == View.Gallery) - { - mLastPartiallyVisible = group.FirstItemIndex + (int)System.Math.Ceiling((float)((ItemAreaBounds.Left - group.itemBounds.Left) + mItemAreaBounds.Width) / (float)mItemSizeWithMargin.Width) * group.itemRows - 1; - mLastVisible = group.FirstItemIndex + (int)System.Math.Floor((float)((ItemAreaBounds.Left - group.itemBounds.Left) + mItemAreaBounds.Width) / (float)mItemSizeWithMargin.Width) * group.itemRows - 1; - } - else - { - mLastPartiallyVisible = group.FirstItemIndex + (int)System.Math.Ceiling((float)((ItemAreaBounds.Top - group.itemBounds.Top) + mItemAreaBounds.Height) / (float)mItemSizeWithMargin.Height) * group.itemCols - 1; - mLastVisible = group.FirstItemIndex + (int)System.Math.Floor((float)((ItemAreaBounds.Top - group.itemBounds.Top) + mItemAreaBounds.Height) / (float)mItemSizeWithMargin.Height) * group.itemCols - 1; - } - } - } - else - { - if (mImageListView.View == View.Gallery) - { - mFirstPartiallyVisible = (int)System.Math.Floor((float)mImageListView.ViewOffset.X / (float)mItemSizeWithMargin.Width) * mDisplayedRows; - mLastPartiallyVisible = (int)System.Math.Ceiling((float)(mImageListView.ViewOffset.X + mItemAreaBounds.Width) / (float)mItemSizeWithMargin.Width) * mDisplayedRows - 1; - mFirstVisible = (int)System.Math.Ceiling((float)mImageListView.ViewOffset.X / (float)mItemSizeWithMargin.Width) * mDisplayedRows; - mLastVisible = (int)System.Math.Floor((float)(mImageListView.ViewOffset.X + mItemAreaBounds.Width) / (float)mItemSizeWithMargin.Width) * mDisplayedRows - 1; - } - else - { - mFirstPartiallyVisible = (int)System.Math.Floor((float)mImageListView.ViewOffset.Y / (float)mItemSizeWithMargin.Height) * mDisplayedCols; - mLastPartiallyVisible = (int)System.Math.Ceiling((float)(mImageListView.ViewOffset.Y + mItemAreaBounds.Height) / (float)mItemSizeWithMargin.Height) * mDisplayedCols - 1; - mFirstVisible = (int)System.Math.Ceiling((float)mImageListView.ViewOffset.Y / (float)mItemSizeWithMargin.Height) * mDisplayedCols; - mLastVisible = (int)System.Math.Floor((float)(mImageListView.ViewOffset.Y + mItemAreaBounds.Height) / (float)mItemSizeWithMargin.Height) * mDisplayedCols - 1; - } - } - - // Bounds check - if (mFirstPartiallyVisible < 0) mFirstPartiallyVisible = 0; - if (mFirstPartiallyVisible > mImageListView.Items.Count - 1) mFirstPartiallyVisible = mImageListView.Items.Count - 1; - if (mLastPartiallyVisible < 0) mLastPartiallyVisible = 0; - if (mLastPartiallyVisible > mImageListView.Items.Count - 1) mLastPartiallyVisible = mImageListView.Items.Count - 1; - if (mFirstVisible < 0) mFirstVisible = 0; - if (mFirstVisible > mImageListView.Items.Count - 1) mFirstVisible = mImageListView.Items.Count - 1; - if (mLastVisible < 0) mLastVisible = 0; - if (mLastVisible > mImageListView.Items.Count - 1) mLastVisible = mImageListView.Items.Count - 1; - - // Cache visible items - cachedVisibleItems.Clear(); - - if (mFirstPartiallyVisible >= 0 && - mLastPartiallyVisible >= 0 && - mFirstPartiallyVisible <= mImageListView.Items.Count - 1 && - mLastPartiallyVisible <= mImageListView.Items.Count - 1) - { - for (int i = mFirstPartiallyVisible; i <= mLastPartiallyVisible; i++) - cachedVisibleItems.Add(mImageListView.Items[i].Guid, false); - } - - // Current item state processed - mImageListView.Items.collectionModified = false; - } - /// - /// Updates the group display properties. - /// - private void UpdateGroups() - { - if (!mImageListView.showGroups) - return; - - int x = mItemAreaBounds.Left - mImageListView.ViewOffset.X; - int y = mItemAreaBounds.Top - mImageListView.ViewOffset.Y; - - if (mImageListView.View == View.Gallery) - { - totalWidth = 0; - totalHeight = mItemAreaBounds.Height; - } - else if (mImageListView.View == View.Details) - { - totalHeight = 0; - } - else - { - totalHeight = 0; - totalWidth = mItemAreaBounds.Width; - } - - foreach (ImageListView.ImageListViewGroup group in mImageListView.groups) - { - if (mImageListView.View == View.Gallery) - { - // Number of rows and columns to enclose all items - group.itemRows = mDisplayedRows; - group.itemCols = (int)System.Math.Ceiling((float)group.ItemCount / (float)mDisplayedRows); - - // Header area - group.headerBounds = new Rectangle(x, y, cachedGroupHeaderHeight, mItemSize.Height * mDisplayedRows); - x += cachedGroupHeaderHeight; - - // Item area - group.itemBounds = new Rectangle(x, y, group.itemCols * mItemSizeWithMargin.Width, group.itemRows * mItemSizeWithMargin.Height); - if (group.Collapsed) - group.itemBounds.Width = 0; - - // Update total size - totalWidth += group.headerBounds.Width + group.itemBounds.Width; - - // Offset to next group - x += group.itemBounds.Width; - } - else - { - // Number of rows and columns to enclose all items - group.itemCols = mDisplayedCols; - group.itemRows = (int)System.Math.Ceiling((float)group.ItemCount / (float)mDisplayedCols); - - // Header area - group.headerBounds = new Rectangle(x, y, mClientArea.Width + mImageListView.ViewOffset.X, cachedGroupHeaderHeight); - y += cachedGroupHeaderHeight; - - // Item area - group.itemBounds = new Rectangle(x, y, group.itemCols * mItemSizeWithMargin.Width, group.itemRows * mItemSizeWithMargin.Height); - if (group.Collapsed) - group.itemBounds.Height = 0; - - // Update total size - totalHeight += group.headerBounds.Height + group.itemBounds.Height; - - // Offset to next group - y += group.itemBounds.Height; - } - - group.isVisible = ItemAreaBounds.IntersectsWith(group.headerBounds) || ItemAreaBounds.IntersectsWith(group.itemBounds); - } - - // Groups processed - mImageListView.groups.collectionModified = false; - } - #endregion - } -} diff --git a/Source/Components/ImageGlass.ImageListView/ImageListViewNavigationManager.cs b/Source/Components/ImageGlass.ImageListView/ImageListViewNavigationManager.cs deleted file mode 100644 index e2f160535..000000000 --- a/Source/Components/ImageGlass.ImageListView/ImageListViewNavigationManager.cs +++ /dev/null @@ -1,1107 +0,0 @@ -// ImageListView - A listview control for image files -// Copyright (C) 2009 Ozgur Ozcitak -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// Ozgur Ozcitak (ozcitak@yahoo.com) - -using System; -using System.Collections.Generic; -using System.Drawing; -using System.Windows.Forms; - -namespace ImageGlass.ImageListView -{ - public partial class ImageListView - { - /// - /// Represents details of keyboard and mouse navigation events. - /// - internal class ImageListViewNavigationManager : IDisposable - { - #region Constants - /// - /// Selection tolerance in pixels. - /// - private const int SelectionTolerance = 5; - #endregion - - #region Member Variables - private ImageListView mImageListView; - - private bool inItemArea; - private bool overCheckBox; - private bool inHeaderArea; - private bool inPaneArea; - - private Point lastViewOffset; - private Point lastSeparatorDragLocation; - private Point lastPaneResizeLocation; - private Point lastMouseDownLocation; - private Point lastMouseMoveLocation; - private Dictionary highlightedItems; - private bool suppressClick; - - private bool lastMouseDownInItemArea; - private bool lastMouseDownInColumnHeaderArea; - private bool lastMouseDownInPaneArea; - - private bool lastMouseDownOverItem; - private bool lastMouseDownOverCheckBox; - private bool lastMouseDownOverColumn; - private bool lastMouseDownOverSeparator; - private bool lastMouseDownOverPaneBorder; - - private bool selfDragging; - - private System.Windows.Forms.Timer scrollTimer; - #endregion - - #region Properties - /// - /// Gets whether the left mouse button is down. - /// - public bool LeftButton { get; private set; } - /// - /// Gets whether the right mouse button is down. - /// - public bool RightButton { get; private set; } - /// - /// Gets whether the shift key is down. - /// - public bool ShiftKey { get; private set; } - /// - /// Gets whether the control key is down. - /// - public bool ControlKey { get; private set; } - - /// - /// Gets the item under the mouse. - /// - public ImageListViewItem HoveredItem { get; private set; } - /// - /// Gets the sub item under the mouse. - /// - public int HoveredSubItem { get; private set; } - /// - /// Gets the column under the mouse. - /// - public ImageListView.ImageListViewColumnHeader HoveredColumn { get; private set; } - /// - /// Gets the column whose separator is under the mouse. - /// - public ImageListView.ImageListViewColumnHeader HoveredSeparator { get; private set; } - /// - /// Gets the column whose separator is being dragged. - /// - public ImageListView.ImageListViewColumnHeader SelectedSeparator { get; private set; } - /// - /// Gets whether the mouse is over the pane border. - /// - public bool HoveredPaneBorder { get; private set; } - - /// - /// Gets whether a mouse selection is in progress. - /// - public bool MouseSelecting { get; private set; } - /// - /// Gets whether a separator is being dragged with the mouse. - /// - public bool DraggingSeperator { get; private set; } - /// - /// Gets whether the left-pane is being resized with the mouse. - /// - public bool ResizingPane { get; private set; } - - /// - /// Gets the target item for a drop operation. - /// - public ImageListViewItem DropTarget { get; private set; } - /// - /// Gets whether drop target is to the right of the item. - /// - public bool DropToRight { get; private set; } - - /// - /// Gets the selection rectangle. - /// - public Rectangle SelectionRectangle { get; private set; } - #endregion - - #region Constructor - /// - /// Initializes a new instance of the ImageListViewNavigationManager class. - /// - /// The owner control. - public ImageListViewNavigationManager(ImageListView owner) - { - mImageListView = owner; - - DraggingSeperator = false; - ResizingPane = false; - - LeftButton = false; - RightButton = false; - ShiftKey = false; - ControlKey = false; - - HoveredItem = null; - HoveredSubItem = -1; - HoveredColumn = null; - HoveredSeparator = null; - SelectedSeparator = null; - HoveredPaneBorder = false; - - MouseSelecting = false; - - DropTarget = null; - DropToRight = false; - selfDragging = false; - - highlightedItems = new Dictionary(); - - scrollTimer = new System.Windows.Forms.Timer(); - scrollTimer.Interval = 100; - scrollTimer.Enabled = false; - scrollTimer.Tick += new EventHandler(scrollTimer_Tick); - - suppressClick = false; - } - #endregion - - #region Instance Methods - /// - /// Determines whether the item is highlighted. - /// - public ItemHighlightState HighlightState(ImageListViewItem item) - { - bool highlighted = false; - if (highlightedItems.TryGetValue(item, out highlighted)) - { - if (highlighted) - return ItemHighlightState.HighlightedAndSelected; - else - return ItemHighlightState.HighlightedAndUnSelected; - } - return ItemHighlightState.NotHighlighted; - } - /// - /// Performs application-defined tasks associated with freeing, - /// releasing, or resetting unmanaged resources. - /// - public void Dispose() - { - scrollTimer.Dispose(); - } - #endregion - - #region Mouse Event Handlers - /// - /// Handles control's MouseDown event. - /// - public void MouseDown(MouseEventArgs e) - { - if ((e.Button & MouseButtons.Left) != MouseButtons.None) - LeftButton = true; - if ((e.Button & MouseButtons.Right) != MouseButtons.None) - RightButton = true; - - DoHitTest(e.Location); - lastMouseDownInItemArea = inItemArea; - lastMouseDownInColumnHeaderArea = inHeaderArea; - lastMouseDownInPaneArea = inPaneArea; - lastMouseDownOverItem = (HoveredItem != null); - lastMouseDownOverCheckBox = overCheckBox; - lastMouseDownOverColumn = (HoveredColumn != null); - lastMouseDownOverSeparator = (HoveredSeparator != null); - lastMouseDownOverPaneBorder = HoveredPaneBorder; - - lastViewOffset = mImageListView.ViewOffset; - lastMouseDownLocation = e.Location; - } - /// - /// Handles control's MouseMove event. - /// - public void MouseMove(MouseEventArgs e) - { - ImageListViewItem oldHoveredItem = HoveredItem; - int oldHoveredSubItem = HoveredSubItem; - ImageListView.ImageListViewColumnHeader oldHoveredColumn = HoveredColumn; - ImageListView.ImageListViewColumnHeader oldHoveredSeparator = HoveredSeparator; - - DoHitTest(e.Location); - - mImageListView.SuspendPaint(); - - // Do we need to scroll the view? - if (MouseSelecting && mImageListView.ScrollOrientation == ScrollOrientation.VerticalScroll && !scrollTimer.Enabled) - { - if (e.Y > mImageListView.ClientRectangle.Bottom) - { - scrollTimer.Tag = -SystemInformation.MouseWheelScrollDelta; - scrollTimer.Enabled = true; - } - else if (e.Y < mImageListView.ClientRectangle.Top) - { - scrollTimer.Tag = SystemInformation.MouseWheelScrollDelta; - scrollTimer.Enabled = true; - } - } - else if (MouseSelecting && mImageListView.ScrollOrientation == ScrollOrientation.HorizontalScroll && !scrollTimer.Enabled) - { - if (e.X > mImageListView.ClientRectangle.Right) - { - scrollTimer.Tag = -SystemInformation.MouseWheelScrollDelta; - scrollTimer.Enabled = true; - } - else if (e.X < mImageListView.ClientRectangle.Left) - { - scrollTimer.Tag = SystemInformation.MouseWheelScrollDelta; - scrollTimer.Enabled = true; - } - } - else if (scrollTimer.Enabled && mImageListView.ClientRectangle.Contains(e.Location)) - { - scrollTimer.Enabled = false; - } - - if (DraggingSeperator) - { - int delta = e.Location.X - lastSeparatorDragLocation.X; - int colwidth = SelectedSeparator.Width + delta; - if (colwidth > 16) - lastSeparatorDragLocation = e.Location; - else - { - lastSeparatorDragLocation = new Point(e.Location.X - colwidth + 16, e.Location.Y); - colwidth = 16; - } - SelectedSeparator.Width = colwidth; - - HoveredItem = null; - HoveredColumn = SelectedSeparator; - HoveredSeparator = SelectedSeparator; - mImageListView.Refresh(); - } - else if (ResizingPane) - { - int delta = e.Location.X - lastPaneResizeLocation.X; - int width = mImageListView.mPaneWidth + delta; - if (width > 2) - lastPaneResizeLocation = e.Location; - else - { - lastPaneResizeLocation = new Point(e.Location.X - width + 2, e.Location.Y); - width = 2; - } - mImageListView.mPaneWidth = width; - - HoveredItem = null; - HoveredColumn = null; - HoveredSeparator = null; - mImageListView.Refresh(); - - mImageListView.OnPaneResizing(new PaneResizingEventArgs(width)); - } - else if (MouseSelecting) - { - if (!ShiftKey && !ControlKey) - mImageListView.SelectedItems.Clear(false); - - // Create the selection rectangle - Point viewOffset = mImageListView.ViewOffset; - Point pt1 = new Point(lastMouseDownLocation.X - (viewOffset.X - lastViewOffset.X), - lastMouseDownLocation.Y - (viewOffset.Y - lastViewOffset.Y)); - Point pt2 = new Point(e.Location.X, e.Location.Y); - SelectionRectangle = new Rectangle(Math.Min(pt1.X, pt2.X), Math.Min(pt1.Y, pt2.Y), Math.Abs(pt1.X - pt2.X), Math.Abs(pt1.Y - pt2.Y)); - - // Determine which items are highlighted - highlightedItems.Clear(); - if (mImageListView.showGroups) - { - foreach (ImageListViewGroup group in mImageListView.groups) - { - List indices = group.ItemIndicesInRectangle(SelectionRectangle, mImageListView.ScrollOrientation, mImageListView.layoutManager.ItemSizeWithMargin); - - foreach (int i in indices) - { - if (i >= 0 && i <= mImageListView.Items.Count - 1 && - !highlightedItems.ContainsKey(mImageListView.Items[i]) && - mImageListView.Items[i].Enabled) - highlightedItems.Add(mImageListView.Items[i], - (ControlKey ? !mImageListView.Items[i].Selected : true)); - } - } - } - else - { - // Normalize to item area coordinates - pt1 = new Point(SelectionRectangle.Left, SelectionRectangle.Top); - pt2 = new Point(SelectionRectangle.Right, SelectionRectangle.Bottom); - Point itemAreaOffset = new Point(-mImageListView.layoutManager.ItemAreaBounds.Left, - -mImageListView.layoutManager.ItemAreaBounds.Top); - pt1.Offset(itemAreaOffset); - pt2.Offset(itemAreaOffset); - - int startRow = (int)Math.Floor((float)(Math.Min(pt1.Y, pt2.Y) + viewOffset.Y) / - (float)mImageListView.layoutManager.ItemSizeWithMargin.Height); - int endRow = (int)Math.Floor((float)(Math.Max(pt1.Y, pt2.Y) + viewOffset.Y) / - (float)mImageListView.layoutManager.ItemSizeWithMargin.Height); - int startCol = (int)Math.Floor((float)(Math.Min(pt1.X, pt2.X) + viewOffset.X) / - (float)mImageListView.layoutManager.ItemSizeWithMargin.Width); - int endCol = (int)Math.Floor((float)(Math.Max(pt1.X, pt2.X) + viewOffset.X) / - (float)mImageListView.layoutManager.ItemSizeWithMargin.Width); - if (mImageListView.ScrollOrientation == ScrollOrientation.HorizontalScroll && - (startRow >= 0 || endRow >= 0)) - { - for (int i = startCol; i <= endCol; i++) - { - if (i >= 0 && i <= mImageListView.Items.Count - 1 && - !highlightedItems.ContainsKey(mImageListView.Items[i]) && - mImageListView.Items[i].Enabled) - highlightedItems.Add(mImageListView.Items[i], - (ControlKey ? !mImageListView.Items[i].Selected : true)); - } - } - else if (mImageListView.ScrollOrientation == ScrollOrientation.VerticalScroll && - (startCol >= 0 || endCol >= 0) && (startRow >= 0 || endRow >= 0) && - (startCol <= mImageListView.layoutManager.Cols - 1 || endCol <= mImageListView.layoutManager.Cols - 1)) - { - startCol = Math.Min(mImageListView.layoutManager.Cols - 1, Math.Max(0, startCol)); - endCol = Math.Min(mImageListView.layoutManager.Cols - 1, Math.Max(0, endCol)); - for (int row = startRow; row <= endRow; row++) - { - for (int col = startCol; col <= endCol; col++) - { - int i = row * mImageListView.layoutManager.Cols + col; - if (i >= 0 && i <= mImageListView.Items.Count - 1 && - !highlightedItems.ContainsKey(mImageListView.Items[i]) && - mImageListView.Items[i].Enabled) - highlightedItems.Add(mImageListView.Items[i], - (ControlKey ? !mImageListView.Items[i].Selected : true)); - } - } - } - } - - HoveredColumn = null; - HoveredSeparator = null; - SelectedSeparator = null; - - mImageListView.Refresh(); - } - else if (!MouseSelecting && !DraggingSeperator && !ResizingPane && - inItemArea && lastMouseDownInItemArea && - (LeftButton || RightButton) && - ((Math.Abs(e.Location.X - lastMouseDownLocation.X) > SelectionTolerance || - Math.Abs(e.Location.Y - lastMouseDownLocation.Y) > SelectionTolerance))) - { - if (mImageListView.MultiSelect && !lastMouseDownOverItem && HoveredItem == null) - { - // Start mouse selection - MouseSelecting = true; - SelectionRectangle = new Rectangle(lastMouseDownLocation, new Size(0, 0)); - mImageListView.Refresh(); - } - else if (lastMouseDownOverItem && HoveredItem != null && mImageListView.AllowDrag) - { - // Start drag&drop - if (!HoveredItem.Selected) - { - mImageListView.SelectedItems.Clear(false); - HoveredItem.mSelected = true; - mImageListView.OnSelectionChangedInternal(); - DropTarget = null; - mImageListView.Refresh(true); - } - - // Set drag data - List filenames = new List(); - foreach (ImageListViewItem item in mImageListView.SelectedItems) - { - // Get the source image - string sourceFile = item.Adaptor.GetSourceImage(item.VirtualItemKey); - if (!string.IsNullOrEmpty(sourceFile)) - filenames.Add(sourceFile); - } - DataObject data = new DataObject(DataFormats.FileDrop, filenames.ToArray()); - DropTarget = null; - selfDragging = true; - mImageListView.DoDragDrop(data, DragDropEffects.All); - selfDragging = false; - - // Since the MouseUp event will be eaten by DoDragDrop we will not receive - // the MouseUp event. We need to manually update mouse button flags after - // the drop. - if ((Control.MouseButtons & MouseButtons.Left) == MouseButtons.None) - LeftButton = false; - if ((Control.MouseButtons & MouseButtons.Right) == MouseButtons.None) - RightButton = false; - } - } - else if (!MouseSelecting && !DraggingSeperator && !ResizingPane && - inHeaderArea && lastMouseDownInColumnHeaderArea && lastMouseDownOverSeparator && LeftButton && - mImageListView.AllowColumnResize && HoveredSeparator != null) - { - // Start dragging a separator - DraggingSeperator = true; - SelectedSeparator = HoveredSeparator; - lastSeparatorDragLocation = e.Location; - } - else if (!MouseSelecting && !DraggingSeperator && !ResizingPane && - inPaneArea && lastMouseDownInPaneArea && lastMouseDownOverPaneBorder && LeftButton && - mImageListView.AllowPaneResize && HoveredPaneBorder != false) - { - // Start dragging the pane - ResizingPane = true; - lastPaneResizeLocation = e.Location; - } - else if (!ReferenceEquals(HoveredItem, oldHoveredItem) || - (HoveredSubItem != oldHoveredSubItem) || - !ReferenceEquals(HoveredColumn, oldHoveredColumn) || - !ReferenceEquals(HoveredSeparator, oldHoveredSeparator)) - { - // Hovered item changed - if (!ReferenceEquals(HoveredItem, oldHoveredItem) || (HoveredSubItem != oldHoveredSubItem)) - mImageListView.OnItemHover(new ItemHoverEventArgs(HoveredItem, HoveredSubItem, oldHoveredItem, oldHoveredSubItem)); - - if (!ReferenceEquals(HoveredColumn, oldHoveredColumn)) - mImageListView.OnColumnHover(new ColumnHoverEventArgs(HoveredColumn, oldHoveredColumn)); - - mImageListView.Refresh(); - } - - mImageListView.ResumePaint(); - - // Change to size cursor if mouse is over a column separator or pane border - if (mImageListView.Cursor != Cursors.VSplit && !MouseSelecting) - { - if ((mImageListView.AllowColumnResize && HoveredSeparator != null) || - (mImageListView.AllowPaneResize && HoveredPaneBorder != false)) - mImageListView.Cursor = Cursors.VSplit; - } - else if (mImageListView.Cursor == Cursors.VSplit) - { - if (!((inHeaderArea && (DraggingSeperator || HoveredSeparator != null)) || - (inPaneArea && (ResizingPane || HoveredPaneBorder != false)))) - mImageListView.Cursor = Cursors.Default; - } - - lastMouseMoveLocation = e.Location; - } - /// - /// Handles control's MouseUp event. - /// - public void MouseUp(MouseEventArgs e) - { - DoHitTest(e.Location); - - mImageListView.SuspendPaint(); - - // Stop if we are scrolling - if (scrollTimer.Enabled) - scrollTimer.Enabled = false; - - if (DraggingSeperator) - { - mImageListView.OnColumnWidthChanged(new ColumnEventArgs(SelectedSeparator)); - SelectedSeparator = null; - DraggingSeperator = false; - } - else if (ResizingPane) - { - ResizingPane = false; - mImageListView.OnPaneResized(new PaneResizedEventArgs(mImageListView.mPaneWidth)); - } - else if (MouseSelecting) - { - // Apply highlighted items - if (highlightedItems.Count != 0) - { - foreach (KeyValuePair pair in highlightedItems) - { - if (pair.Key.Enabled) - pair.Key.mSelected = pair.Value; - } - highlightedItems.Clear(); - } - - mImageListView.OnSelectionChangedInternal(); - - MouseSelecting = false; - - mImageListView.Refresh(); - } - else if (mImageListView.AllowCheckBoxClick && lastMouseDownInItemArea && - lastMouseDownOverCheckBox && HoveredItem != null && overCheckBox && LeftButton) - { - if (HoveredItem.Selected) - { - // if multiple items selected and Hovered item among selected, - // then give all selected check state !HoveredItem.Checked - bool check = !HoveredItem.Checked; - foreach (ImageListViewItem item in mImageListView.Items) - { - if (item.Selected) - item.Checked = check; - } - } - else - { - // if multiple items selected and HoveredItem NOT among selected, - // or if only HoveredItem selected or hovered - // then toggle HoveredItem.Checked - HoveredItem.Checked = !HoveredItem.Checked; - } - mImageListView.Refresh(); - } - else if (lastMouseDownInItemArea && lastMouseDownOverItem && HoveredItem != null && LeftButton) - { - // Select the item under the cursor - if (!mImageListView.MultiSelect && ControlKey) - { - bool oldSelected = HoveredItem.Selected; - mImageListView.SelectedItems.Clear(false); - HoveredItem.mSelected = !oldSelected; - } - else if (!mImageListView.MultiSelect) - { - mImageListView.SelectedItems.Clear(false); - HoveredItem.mSelected = true; - } - else if (ControlKey) - { - HoveredItem.mSelected = !HoveredItem.mSelected; - } - else if (ShiftKey) - { - int startIndex = 0; - if (mImageListView.SelectedItems.Count != 0) - { - startIndex = mImageListView.SelectedItems[0].Index; - mImageListView.SelectedItems.Clear(false); - } - int endIndex = HoveredItem.Index; - if (mImageListView.ScrollOrientation == ScrollOrientation.VerticalScroll) - { - int startRow = Math.Min(startIndex, endIndex) / mImageListView.layoutManager.Cols; - int endRow = Math.Max(startIndex, endIndex) / mImageListView.layoutManager.Cols; - int startCol = Math.Min(startIndex, endIndex) % mImageListView.layoutManager.Cols; - int endCol = Math.Max(startIndex, endIndex) % mImageListView.layoutManager.Cols; - - for (int row = startRow; row <= endRow; row++) - { - for (int col = startCol; col <= endCol; col++) - { - int index = row * mImageListView.layoutManager.Cols + col; - mImageListView.Items[index].mSelected = true; - } - } - } - else - { - for (int i = Math.Min(startIndex, endIndex); i <= Math.Max(startIndex, endIndex); i++) - mImageListView.Items[i].mSelected = true; - } - } - else - { - mImageListView.SelectedItems.Clear(false); - HoveredItem.mSelected = true; - } - - // Raise the selection change event - mImageListView.OnSelectionChangedInternal(); - mImageListView.OnItemClick(new ItemClickEventArgs(HoveredItem, HoveredSubItem, e.Location, e.Button)); - - // Set the item as the focused item - mImageListView.Items.FocusedItem = HoveredItem; - - mImageListView.Refresh(); - } - else if (lastMouseDownInItemArea && lastMouseDownOverItem && HoveredItem != null && RightButton) - { - if (!ControlKey && !HoveredItem.Selected) - { - // Clear the selection if Control key is not pressed - mImageListView.SelectedItems.Clear(false); - HoveredItem.mSelected = true; - mImageListView.OnSelectionChangedInternal(); - } - - mImageListView.OnItemClick(new ItemClickEventArgs(HoveredItem, HoveredSubItem, e.Location, e.Button)); - mImageListView.Items.FocusedItem = HoveredItem; - } - else if (lastMouseDownInItemArea && inItemArea && HoveredItem == null && (LeftButton || RightButton)) - { - // Clear selection if clicked in empty space - mImageListView.SelectedItems.Clear(); - mImageListView.Refresh(); - } - else if (lastMouseDownInColumnHeaderArea && lastMouseDownOverColumn && - mImageListView.AllowColumnClick && HoveredColumn != null && HoveredSeparator == null) - { - if (!suppressClick) - { - if (LeftButton) - { - // Change the sort column - if (mImageListView.Columns[mImageListView.SortColumn].Guid == HoveredColumn.Guid) - { - if (mImageListView.SortOrder == SortOrder.Descending) - mImageListView.SortOrder = SortOrder.Ascending; - else if (mImageListView.SortOrder == SortOrder.Ascending) - mImageListView.SortOrder = SortOrder.Descending; - else if (mImageListView.SortOrder == SortOrder.DescendingNatural) - mImageListView.SortOrder = SortOrder.AscendingNatural; - else - mImageListView.SortOrder = SortOrder.DescendingNatural; - } - else - { - mImageListView.mSortColumn = mImageListView.Columns.IndexOf(HoveredColumn); - mImageListView.mSortOrder = SortOrder.Ascending; - mImageListView.Sort(); - } - } - - mImageListView.OnColumnClick(new ColumnClickEventArgs(HoveredColumn, e.Location, e.Button)); - } - else - suppressClick = false; - } - - if ((e.Button & MouseButtons.Left) != MouseButtons.None) - LeftButton = false; - if ((e.Button & MouseButtons.Right) != MouseButtons.None) - RightButton = false; - - mImageListView.ResumePaint(); - } - /// - /// Handles control's MouseDoubleClick event. - /// - public void MouseDoubleClick(MouseEventArgs e) - { - if (lastMouseDownInItemArea && lastMouseDownOverItem && HoveredItem != null) - { - mImageListView.OnItemDoubleClick(new ItemClickEventArgs(HoveredItem, HoveredSubItem, e.Location, e.Button)); - } - else if (lastMouseDownInColumnHeaderArea && lastMouseDownOverSeparator && - mImageListView.AllowColumnClick && HoveredSeparator != null) - { - HoveredSeparator.AutoFit(); - mImageListView.Refresh(); - suppressClick = true; - } - } - /// - /// Handles control's MouseLeave event. - /// - public void MouseLeave() - { - if (HoveredItem != null || HoveredColumn != null || HoveredSeparator != null || HoveredPaneBorder != false) - { - if (HoveredItem != null) - mImageListView.OnItemHover(new ItemHoverEventArgs(null, -1, HoveredItem, HoveredSubItem)); - if (HoveredColumn != null) - mImageListView.OnColumnHover(new ColumnHoverEventArgs(null, HoveredColumn)); - - HoveredItem = null; - HoveredColumn = null; - HoveredSeparator = null; - HoveredPaneBorder = false; - mImageListView.Refresh(); - } - } - #endregion - - #region Key Event Handlers - /// - /// [Pháp] Handles control's KeyDown event. - /// - public void KeyDown(KeyEventArgs e) - { - //[Pháp] - if (!mImageListView.EnableKeyNavigation) - { - return; - } - - ShiftKey = (e.Modifiers & Keys.Shift) == Keys.Shift; - ControlKey = (e.Modifiers & Keys.Control) == Keys.Control; - - mImageListView.SuspendPaint(); - - // If the shift key or the control key is pressed and there is no focused item - // set the first item as the focused item. - if ((ShiftKey || ControlKey) && mImageListView.Items.Count != 0 && - mImageListView.Items.FocusedItem == null) - { - mImageListView.Items.FocusedItem = mImageListView.Items[0]; - mImageListView.Refresh(); - } - - if (mImageListView.Items.Count != 0) - { - int index = 0; - if (mImageListView.Items.FocusedItem != null) - index = mImageListView.Items.FocusedItem.Index; - - int newindex = ApplyNavKey(index, e.KeyCode); - if (index != newindex) - { - if (ControlKey) - { - // Just move the focus - } - else if (mImageListView.MultiSelect && ShiftKey) - { - int startIndex = 0; - int endIndex = 0; - int selCount = mImageListView.SelectedItems.Count; - if (selCount != 0) - { - startIndex = mImageListView.SelectedItems[0].Index; - endIndex = mImageListView.SelectedItems[selCount - 1].Index; - mImageListView.SelectedItems.Clear(false); - } - - if (newindex > index) // Moving right or down - { - if (newindex > endIndex) - endIndex = newindex; - else - startIndex = newindex; - } - else // Moving left or up - { - if (newindex < startIndex) - startIndex = newindex; - else - endIndex = newindex; - } - - for (int i = Math.Min(startIndex, endIndex); i <= Math.Max(startIndex, endIndex); i++) - { - if (mImageListView.Items[i].mEnabled) - mImageListView.Items[i].mSelected = true; - } - mImageListView.OnSelectionChangedInternal(); - } - else if (mImageListView.Items[newindex].mEnabled) - { - mImageListView.SelectedItems.Clear(false); - mImageListView.Items[newindex].mSelected = true; - mImageListView.OnSelectionChangedInternal(); - } - mImageListView.Items.FocusedItem = mImageListView.Items[newindex]; - mImageListView.EnsureVisible(newindex); - mImageListView.Refresh(); - } - } - - mImageListView.ResumePaint(); - } - /// - /// Handles control's KeyUp event. - /// - public void KeyUp(KeyEventArgs e) - { - ShiftKey = (e.Modifiers & Keys.Shift) == Keys.Shift; - ControlKey = (e.Modifiers & Keys.Control) == Keys.Control; - } - #endregion - - #region Drag and Drop Event Handlers - /// - /// Handles control's DragDrop event. - /// - public void DragDrop(DragEventArgs e) - { - mImageListView.SuspendPaint(); - - if (selfDragging) - { - // Reorder items - List draggedItems = new List(); - int i = -1; - if (DropTarget != null) i = DropTarget.Index; - foreach (ImageListViewItem item in mImageListView.SelectedItems) - { - if (item.Index <= i) i--; - draggedItems.Add(item); - mImageListView.Items.RemoveInternal(item, false); - } - if (i < 0) i = 0; - if (i > mImageListView.Items.Count - 1) i = mImageListView.Items.Count - 1; - if (DropToRight) i++; - foreach (ImageListViewItem item in draggedItems) - { - mImageListView.Items.InsertInternal(i, item, item.Adaptor); - i++; - } - mImageListView.OnSelectionChangedInternal(); - } - else - { - int index = mImageListView.Items.Count; - if (DropTarget != null) index = DropTarget.Index; - if (DropToRight) index++; - if (index > mImageListView.Items.Count) - index = mImageListView.Items.Count; - - string[] filenames = (string[])e.Data.GetData(DataFormats.FileDrop); - - mImageListView.OnDropFiles(new DropFileEventArgs(index, filenames)); - } - - DropTarget = null; - selfDragging = false; - - mImageListView.Refresh(); - mImageListView.ResumePaint(); - } - /// - /// Handles control's DragEnter event. - /// - public void DragEnter(DragEventArgs e) - { - if (!selfDragging && e.Data.GetDataPresent(DataFormats.FileDrop)) - e.Effect = DragDropEffects.Copy; - else - e.Effect = DragDropEffects.None; - } - /// - /// Handles control's DragOver event. - /// - public void DragOver(DragEventArgs e) - { - if (e.Data.GetDataPresent(DataFormats.FileDrop) && - (mImageListView.AllowDrop || (mImageListView.AllowDrag && selfDragging))) - { - if (mImageListView.Items.Count == 0) - { - if (selfDragging) - e.Effect = DragDropEffects.None; - else - e.Effect = DragDropEffects.Copy; - } - else - { - // Calculate the location of the insertion cursor - Point pt = new Point(e.X, e.Y); - pt = mImageListView.PointToClient(pt); - - // Do we need to scroll the view? - if (mImageListView.ScrollOrientation == ScrollOrientation.VerticalScroll && - pt.Y > mImageListView.ClientRectangle.Bottom - 20) - { - scrollTimer.Tag = -SystemInformation.MouseWheelScrollDelta; - scrollTimer.Enabled = true; - } - else if (mImageListView.ScrollOrientation == ScrollOrientation.VerticalScroll && - pt.Y < mImageListView.ClientRectangle.Top + 20) - { - scrollTimer.Tag = SystemInformation.MouseWheelScrollDelta; - scrollTimer.Enabled = true; - } - else if (mImageListView.ScrollOrientation == ScrollOrientation.HorizontalScroll && - pt.X > mImageListView.ClientRectangle.Right - 20) - { - scrollTimer.Tag = -SystemInformation.MouseWheelScrollDelta; - scrollTimer.Enabled = true; - } - else if (mImageListView.ScrollOrientation == ScrollOrientation.HorizontalScroll && - pt.X < mImageListView.ClientRectangle.Left + 20) - { - scrollTimer.Tag = SystemInformation.MouseWheelScrollDelta; - scrollTimer.Enabled = true; - } - else - scrollTimer.Enabled = false; - - // Normalize to item area coordinates - pt.X -= mImageListView.layoutManager.ItemAreaBounds.Left; - pt.Y -= mImageListView.layoutManager.ItemAreaBounds.Top; - - // Row and column mouse is over - bool dragCaretOnRight = false; - int index = 0; - - if (mImageListView.ScrollOrientation == ScrollOrientation.HorizontalScroll) - { - index = (pt.X + mImageListView.ViewOffset.X) / mImageListView.layoutManager.ItemSizeWithMargin.Width; - } - else - { - int col = pt.X / mImageListView.layoutManager.ItemSizeWithMargin.Width; - int row = (pt.Y + mImageListView.ViewOffset.Y) / mImageListView.layoutManager.ItemSizeWithMargin.Height; - if (col > mImageListView.layoutManager.Cols - 1) - { - col = mImageListView.layoutManager.Cols - 1; - dragCaretOnRight = true; - } - index = row * mImageListView.layoutManager.Cols + col; - } - - if (index < 0) index = 0; - if (index > mImageListView.Items.Count - 1) - { - index = mImageListView.Items.Count - 1; - dragCaretOnRight = true; - } - - ImageListViewItem dragDropTarget = mImageListView.Items[index]; - - if (selfDragging && (dragDropTarget.Selected || - (!dragCaretOnRight && index > 0 && mImageListView.Items[index - 1].Selected) || - (dragCaretOnRight && index < mImageListView.Items.Count - 1 && mImageListView.Items[index + 1].Selected))) - { - e.Effect = DragDropEffects.None; - - dragDropTarget = null; - } - else if (selfDragging) - e.Effect = DragDropEffects.Move; - else - e.Effect = DragDropEffects.Copy; - - if (!ReferenceEquals(dragDropTarget, DropTarget) || dragCaretOnRight != DropToRight) - { - DropTarget = dragDropTarget; - DropToRight = dragCaretOnRight; - mImageListView.Refresh(true); - } - } - } - else - e.Effect = DragDropEffects.None; - } - /// - /// Handles control's DragLeave event. - /// - public void DragLeave() - { - DropTarget = null; - mImageListView.Refresh(true); - - if (scrollTimer.Enabled) - scrollTimer.Enabled = false; - } - #endregion - - #region Helper Methods - /// - /// Performs a hit test. - /// - private void DoHitTest(Point pt) - { - ImageListView.HitInfo h; - mImageListView.HitTest(pt, out h); - - if (h.ItemHit && mImageListView.Items[h.ItemIndex].Enabled) - { - HoveredItem = mImageListView.Items[h.ItemIndex]; - HoveredSubItem = h.SubItemIndex; - } - else - { - HoveredItem = null; - HoveredSubItem = -1; - } - - if (h.ColumnHit) - HoveredColumn = h.Column; - else - HoveredColumn = null; - - if (h.ColumnSeparatorHit) - HoveredSeparator = h.ColumnSeparator; - else - HoveredSeparator = null; - - if (h.PaneBorder) - HoveredPaneBorder = true; - else - HoveredPaneBorder = false; - - inItemArea = h.InItemArea; - overCheckBox = h.CheckBoxHit; - inHeaderArea = h.InHeaderArea; - inPaneArea = h.InPaneArea; - } - /// - /// Returns the item index after applying the given navigation key. - /// - private int ApplyNavKey(int index, Keys key) - { - if (mImageListView.ScrollOrientation == ScrollOrientation.VerticalScroll) - { - if (key == Keys.Up && index >= mImageListView.layoutManager.Cols) - index -= mImageListView.layoutManager.Cols; - else if (key == Keys.Down && index < mImageListView.Items.Count - mImageListView.layoutManager.Cols) - index += mImageListView.layoutManager.Cols; - else if (key == Keys.Left && index > 0) - index--; - else if (key == Keys.Right && index < mImageListView.Items.Count - 1) - index++; - else if (key == Keys.PageUp && index >= mImageListView.layoutManager.Cols * (mImageListView.layoutManager.Rows - 1)) - index -= mImageListView.layoutManager.Cols * (mImageListView.layoutManager.Rows - 1); - else if (key == Keys.PageDown && index < mImageListView.Items.Count - mImageListView.layoutManager.Cols * (mImageListView.layoutManager.Rows - 1)) - index += mImageListView.layoutManager.Cols * (mImageListView.layoutManager.Rows - 1); - else if (key == Keys.Home) - index = 0; - else if (key == Keys.End) - index = mImageListView.Items.Count - 1; - } - else - { - if (key == Keys.Left && index > 0) - index--; - else if (key == Keys.Right && index < mImageListView.Items.Count - 1) - index++; - else if (key == Keys.PageUp && index >= mImageListView.layoutManager.Cols) - index -= mImageListView.layoutManager.Cols; - else if (key == Keys.PageDown && index < mImageListView.Items.Count - mImageListView.layoutManager.Cols) - index += mImageListView.layoutManager.Cols; - else if (key == Keys.Home) - index = 0; - else if (key == Keys.End) - index = mImageListView.Items.Count - 1; - } - - if (index < 0) - index = 0; - else if (index > mImageListView.Items.Count - 1) - index = mImageListView.Items.Count - 1; - - return index; - } - #endregion - - #region Scroll Timer - /// - /// Handles the Tick event of the scrollTimer control. - /// - private void scrollTimer_Tick(object sender, EventArgs e) - { - int delta = (int)scrollTimer.Tag; - Point location = mImageListView.PointToClient(Control.MousePosition); - mImageListView.OnMouseMove(new MouseEventArgs(Control.MouseButtons, 0, location.X, location.Y, 0)); - mImageListView.OnMouseWheel(new MouseEventArgs(MouseButtons.None, 0, location.X, location.Y, delta)); - } - #endregion - } - } -} \ No newline at end of file diff --git a/Source/Components/ImageGlass.ImageListView/ImageListViewRenderer.cs b/Source/Components/ImageGlass.ImageListView/ImageListViewRenderer.cs deleted file mode 100644 index 9263838d7..000000000 --- a/Source/Components/ImageGlass.ImageListView/ImageListViewRenderer.cs +++ /dev/null @@ -1,1639 +0,0 @@ -// ImageListView - A listview control for image files -// Copyright (C) 2009 Ozgur Ozcitak -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// Ozgur Ozcitak (ozcitak@yahoo.com) -// - -using System; -using System.Collections.Generic; -using System.Windows.Forms; -using System.Drawing; -using System.Drawing.Drawing2D; -using System.Windows.Forms.VisualStyles; - -namespace ImageGlass.ImageListView -{ - public partial class ImageListView - { - /// - /// Represents an overridable class for image list view renderers. - /// - public class ImageListViewRenderer : IDisposable - { - #region Constants - /// - /// Represents the time in milliseconds after which the control deems to be needing a refresh. - /// - internal const int LazyRefreshInterval = 100; - #endregion - - #region Member Variables - private BufferedGraphics bufferGraphics; - private bool disposed; - private bool creatingGraphics; - private DateTime lastRenderTime; - #endregion - - #region Properties - /// - /// Gets the ImageListView owning this item. - /// - public ImageListView ImageListView { get; internal set; } - /// - /// Gets or sets whether the graphics is clipped to the bounds of - /// drawing elements. - /// - public bool Clip { get; set; } - /// - /// Gets or sets the order by which items are drawn. - /// - public ItemDrawOrder ItemDrawOrder { get; set; } - /// - /// Gets or sets whether items are drawn before of after headers and the gallery images. - /// - public bool ItemsDrawnFirst { get; set; } - /// - /// Gets the rectangle bounding the client area of the control without the scroll bars. - /// - public Rectangle ClientBounds { get { return ImageListView.layoutManager.ClientArea; } } - /// - /// Gets the rectangle bounding the item display area. - /// - public Rectangle ItemAreaBounds { get { return ImageListView.layoutManager.ItemAreaBounds; } } - /// - /// Gets the rectangle bounding the column headers. - /// - public Rectangle ColumnHeaderBounds { get { return ImageListView.layoutManager.ColumnHeaderBounds; } } - /// - /// Gets a value indicating whether this renderer can apply custom colors. - /// - public virtual bool CanApplyColors { get { return true; } } - /// - /// Gets whether the lazy refresh interval is exceeded. - /// - internal bool LazyRefreshIntervalExceeded { get { return ((int)(DateTime.Now - lastRenderTime).TotalMilliseconds > LazyRefreshInterval); } } - /// - /// Gets a list of color themes preferred by this renderer. - /// - public virtual ImageListViewColor[] PreferredColors { get { return null; } } - #endregion - - #region Constructor - /// - /// Initializes a new instance of the ImageListViewRenderer class. - /// - public ImageListViewRenderer() - { - creatingGraphics = false; - disposed = false; - Clip = true; - ItemsDrawnFirst = false; - ItemDrawOrder = ItemDrawOrder.ItemIndex; - lastRenderTime = DateTime.MinValue; - } - #endregion - - #region DrawItemParams - /// - /// Represents the paramaters required to draw an item. - /// - private struct DrawItemParams - { - public ImageListViewItem Item; - public ItemState State; - public Rectangle Bounds; - - public DrawItemParams(ImageListViewItem item, ItemState state, Rectangle bounds) - { - Item = item; - State = state; - Bounds = bounds; - } - } - #endregion - - #region ItemDrawOrderComparer - /// - /// Compares items by the draw order. - /// - private class ItemDrawOrderComparer : IComparer - { - private ItemDrawOrder mDrawOrder; - - public ItemDrawOrderComparer(ItemDrawOrder drawOrder) - { - mDrawOrder = drawOrder; - } - - /// - /// Compares items by the draw order. - /// - /// First item to compare. - /// Second item to compare. - /// 1 if the first item should be drawn first, - /// -1 if the second item should be drawn first, - /// 0 if the two items can be drawn in any order. - public int Compare(DrawItemParams param1, DrawItemParams param2) - { - if (ReferenceEquals(param1, param2)) - return 0; - if (ReferenceEquals(param1.Item, param2.Item)) - return 0; - - int comparison = 0; - - if (mDrawOrder == ItemDrawOrder.ItemIndex) - { - return CompareByIndex(param1, param2); - } - else if (mDrawOrder == ItemDrawOrder.ZOrder) - { - return CompareByZOrder(param1, param2); - } - else if (mDrawOrder == ItemDrawOrder.NormalSelectedHovered) - { - comparison = -CompareByHovered(param1, param2); - if (comparison != 0) return comparison; - comparison = -CompareBySelected(param1, param2); - if (comparison != 0) return comparison; - comparison = -CompareByNormal(param1, param2); - if (comparison != 0) return comparison; - } - else if (mDrawOrder == ItemDrawOrder.NormalHoveredSelected) - { - comparison = -CompareBySelected(param1, param2); - if (comparison != 0) return comparison; - comparison = -CompareByHovered(param1, param2); - if (comparison != 0) return comparison; - comparison = -CompareByNormal(param1, param2); - if (comparison != 0) return comparison; - } - else if (mDrawOrder == ItemDrawOrder.SelectedNormalHovered) - { - comparison = -CompareByHovered(param1, param2); - if (comparison != 0) return comparison; - comparison = -CompareByNormal(param1, param2); - if (comparison != 0) return comparison; - comparison = -CompareBySelected(param1, param2); - if (comparison != 0) return comparison; - } - else if (mDrawOrder == ItemDrawOrder.SelectedHoveredNormal) - { - comparison = -CompareByNormal(param1, param2); - if (comparison != 0) return comparison; - comparison = -CompareByHovered(param1, param2); - if (comparison != 0) return comparison; - comparison = -CompareBySelected(param1, param2); - if (comparison != 0) return comparison; - } - else if (mDrawOrder == ItemDrawOrder.HoveredNormalSelected) - { - comparison = -CompareBySelected(param1, param2); - if (comparison != 0) return comparison; - comparison = -CompareByNormal(param1, param2); - if (comparison != 0) return comparison; - comparison = -CompareByHovered(param1, param2); - if (comparison != 0) return comparison; - } - else if (mDrawOrder == ItemDrawOrder.HoveredSelectedNormal) - { - comparison = -CompareByNormal(param1, param2); - if (comparison != 0) return comparison; - comparison = -CompareBySelected(param1, param2); - if (comparison != 0) return comparison; - comparison = -CompareByHovered(param1, param2); - if (comparison != 0) return comparison; - } - - // Compare by zorder - comparison = CompareByZOrder(param1, param2); - if (comparison != 0) return comparison; - - // Finally compare by index - comparison = CompareByIndex(param1, param2); - return comparison; - } - - /// - /// Compares items by their index property. - /// - private int CompareByIndex(DrawItemParams param1, DrawItemParams param2) - { - if (param1.Item.Index < param2.Item.Index) - return -1; - else if (param1.Item.Index > param2.Item.Index) - return 1; - else - return 0; - } - /// - /// Compares items by their zorder property. - /// - private int CompareByZOrder(DrawItemParams param1, DrawItemParams param2) - { - if (param1.Item.ZOrder < param2.Item.ZOrder) - return -1; - else if (param1.Item.ZOrder > param2.Item.ZOrder) - return 1; - else - return 0; - } - /// - /// Compares items by their neutral state. - /// - private int CompareByNormal(DrawItemParams param1, DrawItemParams param2) - { - if (param1.State == ItemState.None && param2.State != ItemState.None) - return -1; - else if (param1.State != ItemState.None && param2.State == ItemState.None) - return 1; - else - return 0; - } - /// - /// Compares items by their selected state. - /// - private int CompareBySelected(DrawItemParams param1, DrawItemParams param2) - { - if ((param1.State & ItemState.Selected) == ItemState.Selected && - (param2.State & ItemState.Selected) != ItemState.Selected) - return -1; - else if ((param1.State & ItemState.Selected) != ItemState.Selected && - (param2.State & ItemState.Selected) == ItemState.Selected) - return 1; - else - return 0; - } - /// - /// Compares items by their hovered state. - /// - private int CompareByHovered(DrawItemParams param1, DrawItemParams param2) - { - if ((param1.State & ItemState.Hovered) == ItemState.Hovered) - return -1; - else if ((param2.State & ItemState.Hovered) == ItemState.Hovered) - return 1; - else - return 0; - } - /// - /// Compares items by their focused state. - /// - private int CompareByFocused(DrawItemParams param1, DrawItemParams param2) - { - if ((param1.State & ItemState.Focused) == ItemState.Focused) - return -1; - else if ((param2.State & ItemState.Focused) == ItemState.Focused) - return 1; - else - return 0; - } - } - #endregion - - #region Instance Methods - /// - /// Reads and returns the image for the given item. - /// - /// The item to read. - /// The size of the requested image.. - /// Item thumbnail of requested size. - public Image GetImageAsync(ImageListViewItem item, Size size) - { - Image img = ImageListView.thumbnailCache.GetRendererImage(item.Guid, size, ImageListView.UseEmbeddedThumbnails, - ImageListView.AutoRotateThumbnails, ImageListView.UseWIC == UseWIC.Auto || ImageListView.UseWIC == UseWIC.ThumbnailsOnly); - - if (img == null) - { - ImageListView.thumbnailCache.AddToRendererCache(item.Guid, item.mAdaptor, item.VirtualItemKey, - size, ImageListView.UseEmbeddedThumbnails, ImageListView.AutoRotateThumbnails, - (ImageListView.UseWIC == UseWIC.Auto || ImageListView.UseWIC == UseWIC.ThumbnailsOnly)); - } - - return img; - } - #endregion - - #region Internal Methods - /// - /// Renders the border of the control. - /// - /// The graphics to draw on. - private void RenderBorder(Graphics g) - { - // Background - g.ResetClip(); - DrawBorder(g, new Rectangle(0, 0, ImageListView.Width, ImageListView.Height)); - } - /// - /// Renders the background of the control. - /// - /// The graphics to draw on. - private void RenderBackground(Graphics g) - { - // Background - g.SetClip(ImageListView.layoutManager.ClientArea); - DrawBackground(g, ImageListView.layoutManager.ClientArea); - } - /// - /// Renders the group header. - /// - /// The graphics to draw on. - private void RenderGroupHeaders(Graphics g) - { - if (!ImageListView.showGroups) - return; - - foreach (ImageListViewGroup group in ImageListView.groups.GetDisplayedGroups()) - { - if (Clip) - { - Rectangle clip = Rectangle.Intersect(group.headerBounds, ImageListView.layoutManager.ItemAreaBounds); - g.SetClip(clip); - } - else - g.SetClip(ImageListView.layoutManager.ClientArea); - - if (ImageListView.View == View.Gallery) - { - g.TranslateTransform(group.headerBounds.Left, group.headerBounds.Bottom); - g.RotateTransform(270); - DrawGroupHeader(g, group.Name, new Rectangle(0, 0, group.headerBounds.Height, group.headerBounds.Width)); - g.ResetTransform(); - } - else - DrawGroupHeader(g, group.Name, group.headerBounds); - } - } - /// - /// Renders the column header. - /// - /// The graphics to draw on. - private void RenderColumnHeaders(Graphics g) - { - if (ImageListView.View != View.Details) - return; - - int x = ImageListView.layoutManager.ColumnHeaderBounds.Left; - int y = ImageListView.layoutManager.ColumnHeaderBounds.Top; - int h = MeasureColumnHeaderHeight(); - int lastX = 0; - foreach (ImageListViewColumnHeader column in ImageListView.Columns.GetDisplayedColumns()) - { - ColumnState state = ColumnState.None; - if (ReferenceEquals(ImageListView.navigationManager.HoveredColumn, column)) - state |= ColumnState.Hovered; - if (ReferenceEquals(ImageListView.navigationManager.HoveredSeparator, column)) - state |= ColumnState.SeparatorHovered; - if (ReferenceEquals(ImageListView.navigationManager.SelectedSeparator, column)) - state |= ColumnState.SeparatorSelected; - if (ImageListView.SortColumn >= 0 && ImageListView.SortColumn < ImageListView.Columns.Count && - ImageListView.Columns[ImageListView.SortColumn].Guid == column.Guid) - state |= ColumnState.SortColumn; - - Rectangle bounds = new Rectangle(x, y, column.Width, h); - if (Clip) - { - Rectangle clip = Rectangle.Intersect(bounds, ImageListView.layoutManager.ClientArea); - g.SetClip(clip); - } - else - g.SetClip(ImageListView.layoutManager.ClientArea); - - DrawColumnHeader(g, column, state, bounds); - - x += column.Width; - lastX = bounds.Right; - } - - // Extender column - if (ImageListView.Columns.Count != 0) - { - if (lastX < ImageListView.layoutManager.ClientArea.Right) - { - Rectangle extender = new Rectangle( - lastX, - ImageListView.layoutManager.ColumnHeaderBounds.Top, - ImageListView.layoutManager.ClientArea.Right - lastX, - ImageListView.layoutManager.ColumnHeaderBounds.Height); - if (Clip) - g.SetClip(extender); - else - g.SetClip(ImageListView.layoutManager.ClientArea); - DrawColumnExtender(g, extender); - } - } - else - { - Rectangle extender = ImageListView.layoutManager.ColumnHeaderBounds; - if (Clip) - g.SetClip(extender); - else - g.SetClip(ImageListView.layoutManager.ClientArea); - DrawColumnExtender(g, extender); - } - } - /// - /// Renders the large gallery image. - /// - /// The graphics to draw on. - private void RenderGalleryImage(Graphics g) - { - if (ImageListView.View != View.Gallery) - return; - - Rectangle bounds = ImageListView.layoutManager.ClientArea; - bounds.Height -= ImageListView.layoutManager.ItemAreaBounds.Height; - - ImageListViewItem item = null; - if (ImageListView.Items.FocusedItem != null) - item = ImageListView.Items.FocusedItem; - else if (ImageListView.SelectedItems.Count != 0) - item = ImageListView.SelectedItems[0]; - else if (ImageListView.Items.Count != 0) - item = ImageListView.Items[0]; - - Image image = null; - if (item != null && bounds.Width > 4 && bounds.Height > 4) - { - image = GetGalleryImageAsync(item, bounds.Size); - if (image == null) image = item.GetCachedImage(CachedImageType.Thumbnail); - } - - if (Clip) - g.SetClip(bounds); - else - g.SetClip(ImageListView.layoutManager.ClientArea); - - DrawGalleryImage(g, item, image, bounds); - } - /// - /// Renders the pane. - /// - /// The graphics to draw on. - private void RenderPane(Graphics g) - { - if (ImageListView.View != View.Pane) - return; - - Rectangle bounds = ImageListView.layoutManager.ClientArea; - bounds.Width = ImageListView.mPaneWidth; - - ImageListViewItem item = null; - if (ImageListView.Items.FocusedItem != null) - item = ImageListView.Items.FocusedItem; - else if (ImageListView.SelectedItems.Count != 0) - item = ImageListView.SelectedItems[0]; - else if (ImageListView.Items.Count != 0) - item = ImageListView.Items[0]; - - Image image = null; - if (item != null && bounds.Width > 4 && bounds.Height > 4) - { - image = GetGalleryImageAsync(item, new Size(bounds.Width, 65535)); - if (image == null) image = item.GetCachedImage(CachedImageType.Thumbnail); - } - - if (Clip) - g.SetClip(bounds); - else - g.SetClip(ImageListView.layoutManager.ClientArea); - - DrawPane(g, item, image, bounds); - } - /// - /// Renders the items. - /// - /// The graphics to draw on. - private void RenderItems(Graphics g) - { - // Is the control empty? - if (ImageListView.Items.Count == 0) - return; - // No items visible? - if (ImageListView.layoutManager.FirstPartiallyVisible == -1 || - ImageListView.layoutManager.LastPartiallyVisible == -1) - return; - // No columns displayed? - if (ImageListView.View == View.Details && ImageListView.Columns.GetDisplayedColumns().Count == 0) - return; - - List drawItemParams = new List(); - for (int i = ImageListView.layoutManager.FirstPartiallyVisible; i <= ImageListView.layoutManager.LastPartiallyVisible; i++) - { - ImageListViewItem item = ImageListView.Items[i]; - - // Determine item state - ItemState state = ItemState.None; - ItemHighlightState highlightState = ImageListView.navigationManager.HighlightState(item); - if (highlightState == ItemHighlightState.HighlightedAndSelected || - (highlightState == ItemHighlightState.NotHighlighted && item.Selected)) - state |= ItemState.Selected; - - if (ReferenceEquals(ImageListView.navigationManager.HoveredItem, item) && - ImageListView.navigationManager.MouseSelecting == false) - state |= ItemState.Hovered; - - if (item.Focused) - state |= ItemState.Focused; - - if (!item.Enabled) - state |= ItemState.Disabled; - - // Get item bounds - Rectangle bounds = ImageListView.layoutManager.GetItemBounds(i); - - // Add to params to be sorted and drawn - drawItemParams.Add(new DrawItemParams(item, state, bounds)); - } - - // Sort items by draw order - drawItemParams.Sort(new ItemDrawOrderComparer(ItemDrawOrder)); - - // Draw items - foreach (DrawItemParams param in drawItemParams) - { - if (Clip) - { - Rectangle clip = Rectangle.Intersect(param.Bounds, ImageListView.layoutManager.ItemAreaBounds); - g.SetClip(clip); - } - else - g.SetClip(ImageListView.layoutManager.ClientArea); - - // Draw the item - DrawItem(g, param.Item, param.State, param.Bounds); - - // Draw sub item overlays - if (ImageListView.View == View.Details) - { - int xc1 = ImageListView.layoutManager.ColumnHeaderBounds.Left; - int colIndex = 0; - foreach (ImageListViewColumnHeader column in ImageListView.Columns.GetDisplayedColumns()) - { - Rectangle subBounds = new Rectangle(xc1, param.Bounds.Y, column.Width, param.Bounds.Height); - if (Clip) - { - Rectangle clip = Rectangle.Intersect(subBounds, ImageListView.layoutManager.ItemAreaBounds); - g.SetClip(clip); - } - - // Check if the mouse is over the sub item - bool subItemHovered = ((param.State & ItemState.Hovered) != ItemState.None) && - (ImageListView.navigationManager.HoveredSubItem == colIndex); - - DrawSubItemItemOverlay(g, param.Item, param.State, colIndex, subItemHovered, subBounds); - - colIndex++; - xc1 += column.Width; - } - } - - // Draw the checkbox and file icon - if (ImageListView.ShowCheckBoxes) - { - Rectangle cBounds = ImageListView.layoutManager.GetCheckBoxBounds(param.Item.Index); - if (Clip) - { - Rectangle clip = Rectangle.Intersect(cBounds, ImageListView.layoutManager.ItemAreaBounds); - g.SetClip(clip); - } - else - g.SetClip(ImageListView.layoutManager.ClientArea); - - DrawCheckBox(g, param.Item, cBounds); - } - if (ImageListView.ShowFileIcons) - { - Rectangle cBounds = ImageListView.layoutManager.GetIconBounds(param.Item.Index); - if (Clip) - { - Rectangle clip = Rectangle.Intersect(cBounds, ImageListView.layoutManager.ItemAreaBounds); - g.SetClip(clip); - } - else - g.SetClip(ImageListView.layoutManager.ClientArea); - - DrawFileIcon(g, param.Item, cBounds); - } - } - } - /// - /// Renders the overlay. - /// - /// The graphics to draw on. - private void RenderOverlay(Graphics g) - { - g.SetClip(ImageListView.layoutManager.ClientArea); - DrawOverlay(g, ImageListView.layoutManager.ClientArea); - } - /// - /// Renders the drag-drop insertion caret. - /// - /// The graphics to draw on. - private void RenderInsertionCaret(Graphics g) - { - if (ImageListView.navigationManager.DropTarget == null) - return; - - Rectangle bounds = ImageListView.layoutManager.GetItemBounds(ImageListView.navigationManager.DropTarget.Index); - if (ImageListView.View == View.Details) - { - if (ImageListView.navigationManager.DropToRight) - bounds.Offset(0, ImageListView.layoutManager.ItemSizeWithMargin.Height); - bounds.Offset(0, -1); - bounds.Height = 2; - } - else - { - if (ImageListView.navigationManager.DropToRight) - bounds.Offset(ImageListView.layoutManager.ItemSizeWithMargin.Width, 0); - Size itemMargin = MeasureItemMargin(ImageListView.View); - bounds.Offset(-(itemMargin.Width - 2) / 2 - 2, 0); - bounds.Width = 2; - } - if (Clip) - g.SetClip(bounds); - else - g.SetClip(ImageListView.layoutManager.ClientArea); - DrawInsertionCaret(g, bounds); - } - /// - /// Renders the selection rectangle. - /// - /// The graphics to draw on. - private void RenderSelectionRectangle(Graphics g) - { - if (!ImageListView.navigationManager.MouseSelecting) - return; - - Rectangle sel = ImageListView.navigationManager.SelectionRectangle; - if (sel.Height > 0 && sel.Width > 0) - { - if (Clip) - { - Rectangle selclip = new Rectangle(sel.Left, sel.Top, sel.Width + 1, sel.Height + 1); - g.SetClip(selclip); - } - else - g.SetClip(ImageListView.layoutManager.ClientArea); - g.ExcludeClip(ImageListView.layoutManager.ColumnHeaderBounds); - DrawSelectionRectangle(g, sel); - } - } - /// - /// Renders the area between scrollbars. - /// - /// The graphics to draw on. - private void RenderScrollbarFiller(Graphics g) - { - if (!ImageListView.hScrollBar.Visible || !ImageListView.vScrollBar.Visible) - return; - - Rectangle bounds = ImageListView.layoutManager.ClientArea; - Rectangle filler = new Rectangle(bounds.Right, bounds.Bottom, ImageListView.vScrollBar.Width, ImageListView.hScrollBar.Height); - g.SetClip(filler); - g.FillRectangle(SystemBrushes.Control, filler); - } - /// - /// Renders the control. - /// - /// The graphics to draw on. - internal void Render(Graphics graphics) - { - if (disposed) return; - - if (bufferGraphics == null) - { - if (!RecreateBuffer(graphics)) return; - } - - // Save the timne of this render for lazy refreshes - lastRenderTime = DateTime.Now; - - // Update the layout - ImageListView.layoutManager.Update(); - - // Set drawing area - Graphics g = bufferGraphics.Graphics; - g.ResetClip(); - - // Draw control border - RenderBorder(g); - - // Draw background - RenderBackground(g); - - // Draw group headers if visible - RenderGroupHeaders(g); - - // Draw items if they should be drawn first - bool itemsDrawn = false; - if (ItemsDrawnFirst) - { - RenderItems(g); - itemsDrawn = true; - } - - // Draw the large preview image in Gallery mode - RenderGalleryImage(g); - - // Draw the left-pane - RenderPane(g); - - // Draw column headers - RenderColumnHeaders(g); - - // Draw items if they should be drawn last. - if (!itemsDrawn) - RenderItems(g); - - // Draw the overlay image - RenderOverlay(g); - - // Draw the selection rectangle - RenderSelectionRectangle(g); - - // Draw the insertion caret - RenderInsertionCaret(g); - - // Scrollbar filler - RenderScrollbarFiller(g); - - // Draw on to the control - bufferGraphics.Render(graphics); - } - /// - /// Loads and returns the large gallery image for the given item. - /// - private Image GetGalleryImageAsync(ImageListViewItem item, Size size) - { - Image img = ImageListView.thumbnailCache.GetGalleryImage(item.Guid, size, ImageListView.UseEmbeddedThumbnails, - ImageListView.AutoRotateThumbnails, ImageListView.UseWIC == UseWIC.Auto || ImageListView.UseWIC == UseWIC.ThumbnailsOnly); - - if (img == null) - { - ImageListView.thumbnailCache.AddToGalleryCache(item.Guid, item.mAdaptor, item.VirtualItemKey, - size, ImageListView.UseEmbeddedThumbnails, ImageListView.AutoRotateThumbnails, - (ImageListView.UseWIC == UseWIC.Auto || ImageListView.UseWIC == UseWIC.ThumbnailsOnly)); - } - - return img; - } - /// - /// Clears the graphics buffer objects. - /// - internal void ClearBuffer() - { - if (bufferGraphics != null) - bufferGraphics.Dispose(); - bufferGraphics = null; - } - /// - /// Destroys the current buffer and creates a new buffered graphics - /// sized to the client area of the owner control. - /// - /// The Graphics to match the pixel format to. - internal bool RecreateBuffer(Graphics graphics) - { - if (creatingGraphics) return false; - - creatingGraphics = true; - - BufferedGraphicsContext bufferContext = BufferedGraphicsManager.Current; - - if (disposed) - throw (new ObjectDisposedException("bufferContext")); - - int width = System.Math.Max(ImageListView.Width, 1); - int height = System.Math.Max(ImageListView.Height, 1); - - bufferContext.MaximumBuffer = new Size(width, height); - - ClearBuffer(); - - bufferGraphics = bufferContext.Allocate(graphics, new Rectangle(0, 0, width, height)); - - creatingGraphics = false; - - InitializeGraphics(bufferGraphics.Graphics); - - return true; - } - /// - /// Releases buffered graphics objects. - /// - void IDisposable.Dispose() - { - if (!disposed) - { - ClearBuffer(); - - disposed = true; - GC.SuppressFinalize(this); - } - } -#if DEBUG - /// - /// Releases unmanaged resources and performs other cleanup operations before the - /// ImageListViewRenderer is reclaimed by garbage collection. - /// - ~ImageListViewRenderer() - { - System.Diagnostics.Debug.Print("Finalizer of {0} called.", GetType()); - Dispose(); - } -#endif - #endregion - - #region Virtual Methods - /// - /// Initializes the System.Drawing.Graphics used to draw - /// control elements. - /// - /// The System.Drawing.Graphics to draw on. - public virtual void InitializeGraphics(Graphics g) - { - g.PixelOffsetMode = PixelOffsetMode.None; - g.InterpolationMode = InterpolationMode.HighQualityBicubic; - } - /// - /// Returns the height of group headers. - /// - public virtual int MeasureGroupHeaderHeight() - { - if (ImageListView.disposed || ImageListView.GroupHeaderFont == null) - return 24; - else - return System.Math.Max(ImageListView.GroupHeaderFont.Height + 8, 24); - } - /// - /// Returns the height of column headers. - /// - /// The height of column headers. - public virtual int MeasureColumnHeaderHeight() - { - if (ImageListView.disposed || ImageListView.ColumnHeaderFont == null) - return 24; - else - return System.Math.Max(ImageListView.ColumnHeaderFont.Height + 4, 24); - } - /// - /// Returns the spacing between items for the given view mode. - /// - /// The view mode for which the measurement should be made. - /// The spacing between items. - public virtual Size MeasureItemMargin(View view) - { - if (view == View.Details) - return new Size(2, 0); - else - return new Size(4, 4); - } - /// - /// Returns item size for the given view mode. - /// - /// The view mode for which the measurement should be made. - /// The item size. - public virtual Size MeasureItem(View view) - { - Size itemSize = new Size(); - - // Reference text height - int textHeight = ImageListView.Font.Height; - - if (view == View.Details) - { - // Calculate total column width - int colWidth = 0; - foreach (ImageListViewColumnHeader column in ImageListView.Columns) - if (column.Visible) colWidth += column.Width; - - itemSize = new Size(colWidth, textHeight + 2 * textHeight / 6); // textHeight / 6 = vertical space between item border and text - } - else - { - Size itemPadding = new Size(4, 4); - itemSize = ImageListView.ThumbnailSize + itemPadding + itemPadding; - itemSize.Height += textHeight + System.Math.Max(4, textHeight / 3); // textHeight / 3 = vertical space between thumbnail and text - } - - return itemSize; - } - /// - /// Draws the border of the control. - /// - /// The System.Drawing.Graphics to draw on. - /// The coordinates of the border. - public virtual void DrawBorder(Graphics g, Rectangle bounds) - { - if (ImageListView.BorderStyle != BorderStyle.None) - { - Border3DStyle style = (ImageListView.BorderStyle == BorderStyle.FixedSingle) ? Border3DStyle.Flat : Border3DStyle.SunkenInner; - ControlPaint.DrawBorder3D(g, bounds, style); - } - } - /// - /// Draws the background of the control. - /// - /// The System.Drawing.Graphics to draw on. - /// The client coordinates of the item area. - public virtual void DrawBackground(Graphics g, Rectangle bounds) - { - // Clear the background - if (ImageListView.Enabled) - g.Clear(ImageListView.Colors.ControlBackColor); - else - g.Clear(ImageListView.Colors.DisabledBackColor); - - // Draw the background image - if (ImageListView.BackgroundImage != null) - { - Image img = ImageListView.BackgroundImage; - - if (ImageListView.BackgroundImageLayout == ImageLayout.None) - { - g.DrawImageUnscaled(img, ImageListView.layoutManager.ItemAreaBounds.Location); - } - else if (ImageListView.BackgroundImageLayout == ImageLayout.Center) - { - int x = bounds.Left + (bounds.Width - img.Width) / 2; - int y = bounds.Top + (bounds.Height - img.Height) / 2; - g.DrawImageUnscaled(img, x, y); - } - else if (ImageListView.BackgroundImageLayout == ImageLayout.Stretch) - { - g.DrawImage(img, bounds); - } - else if (ImageListView.BackgroundImageLayout == ImageLayout.Tile) - { - using (Brush imgBrush = new TextureBrush(img, WrapMode.Tile)) - { - g.FillRectangle(imgBrush, bounds); - } - } - else if (ImageListView.BackgroundImageLayout == ImageLayout.Zoom) - { - float xscale = (float)bounds.Width / (float)img.Width; - float yscale = (float)bounds.Height / (float)img.Height; - float scale = Math.Min(xscale, yscale); - int width = (int)(((float)img.Width) * scale); - int height = (int)(((float)img.Height) * scale); - int x = bounds.Left + (bounds.Width - width) / 2; - int y = bounds.Top + (bounds.Height - height) / 2; - g.DrawImage(img, x, y, width, height); - } - } - } - /// - /// Draws the selection rectangle. - /// - /// The System.Drawing.Graphics to draw on. - /// The client coordinates of the selection rectangle. - public virtual void DrawSelectionRectangle(Graphics g, Rectangle selection) - { - using (SolidBrush brush = new SolidBrush(ImageListView.Colors.SelectionRectangleColor1)) - using (Pen pen = new Pen(ImageListView.Colors.SelectionRectangleBorderColor)) - { - g.FillRectangle(brush, selection); - g.DrawRectangle(pen, selection); - } - } - /// - /// Draws the specified item on the given graphics. - /// - /// The System.Drawing.Graphics to draw on. - /// The ImageListViewItem to draw. - /// The current view state of item. - /// The bounding rectangle of item in client coordinates. - public virtual void DrawItem(Graphics g, ImageListViewItem item, ItemState state, Rectangle bounds) - { - Size itemPadding = new Size(4, 4); - bool alternate = (item.Index % 2 == 1); - - // Paint background - if (ImageListView.Enabled) - { - using (Brush bItemBack = new SolidBrush(alternate && ImageListView.View == View.Details ? - ImageListView.Colors.AlternateBackColor : ImageListView.Colors.BackColor)) - { - g.FillRectangle(bItemBack, bounds); - } - } - else - { - using (Brush bItemBack = new SolidBrush(ImageListView.Colors.DisabledBackColor)) - { - g.FillRectangle(bItemBack, bounds); - } - } - - // Paint background Disabled - if ((state & ItemState.Disabled) != ItemState.None) - { - using (Brush bDisabled = new LinearGradientBrush(bounds, ImageListView.Colors.DisabledColor1, ImageListView.Colors.DisabledColor2, LinearGradientMode.Vertical)) - { - Utility.FillRoundedRectangle(g, bDisabled, bounds, (ImageListView.View == View.Details ? 2 : 4)); - } - } - - // Paint background Selected - else if ((ImageListView.Focused && ((state & ItemState.Selected) != ItemState.None)) || - (!ImageListView.Focused && ((state & ItemState.Selected) != ItemState.None) && ((state & ItemState.Hovered) != ItemState.None))) - { - using (Brush bSelected = new LinearGradientBrush(bounds, ImageListView.Colors.SelectedColor1, ImageListView.Colors.SelectedColor2, LinearGradientMode.Vertical)) - { - Utility.FillRoundedRectangle(g, bSelected, bounds, (ImageListView.View == View.Details ? 2 : 4)); - } - } - - // Paint background unfocused - else if (!ImageListView.Focused && ((state & ItemState.Selected) != ItemState.None)) - { - using (Brush bGray64 = new LinearGradientBrush(bounds, ImageListView.Colors.UnFocusedColor1, ImageListView.Colors.UnFocusedColor2, LinearGradientMode.Vertical)) - { - Utility.FillRoundedRectangle(g, bGray64, bounds, (ImageListView.View == View.Details ? 2 : 4)); - } - } - - // Paint background Hovered - if ((state & ItemState.Hovered) != ItemState.None) - { - using (Brush bHovered = new LinearGradientBrush(bounds, ImageListView.Colors.HoverColor1, ImageListView.Colors.HoverColor2, LinearGradientMode.Vertical)) - { - Utility.FillRoundedRectangle(g, bHovered, bounds, (ImageListView.View == View.Details ? 2 : 4)); - } - } - - if (ImageListView.View != View.Details) - { - // Draw the image - Image img = item.GetCachedImage(CachedImageType.Thumbnail); - if (img != null) - { - Rectangle pos = Utility.GetSizedImageBounds(img, new Rectangle(bounds.Location + itemPadding, ImageListView.ThumbnailSize)); - g.DrawImage(img, pos); - // Draw image border - if (Math.Min(pos.Width, pos.Height) > 32) - { - using (Pen pOuterBorder = new Pen(ImageListView.Colors.ImageOuterBorderColor)) - { - g.DrawRectangle(pOuterBorder, pos); - } - if (System.Math.Min(ImageListView.ThumbnailSize.Width, ImageListView.ThumbnailSize.Height) > 32) - { - using (Pen pInnerBorder = new Pen(ImageListView.Colors.ImageInnerBorderColor)) - { - g.DrawRectangle(pInnerBorder, Rectangle.Inflate(pos, -1, -1)); - } - } - } - } - - // Draw item text - Color foreColor = ImageListView.Colors.ForeColor; - if ((state & ItemState.Disabled) != ItemState.None) - { - foreColor = ImageListView.Colors.DisabledForeColor; - } - else if ((state & ItemState.Selected) != ItemState.None) - { - if (ImageListView.Focused) - foreColor = ImageListView.Colors.SelectedForeColor; - else - foreColor = ImageListView.Colors.UnFocusedForeColor; - } - Size szt = TextRenderer.MeasureText(item.Text, ImageListView.Font); - Rectangle rt = new Rectangle(bounds.Left + itemPadding.Width, bounds.Top + 2 * itemPadding.Height + ImageListView.ThumbnailSize.Height, ImageListView.ThumbnailSize.Width, szt.Height); - TextRenderer.DrawText(g, item.Text, ImageListView.Font, rt, foreColor, - TextFormatFlags.EndEllipsis | TextFormatFlags.HorizontalCenter | TextFormatFlags.VerticalCenter | TextFormatFlags.SingleLine); - } - else // if (ImageListView.View == View.Details) - { - List uicolumns = ImageListView.Columns.GetDisplayedColumns(); - - // Shade sort column - int x = bounds.Left - 1; - foreach (ImageListViewColumnHeader column in uicolumns) - { - if (ImageListView.SortOrder != SortOrder.None && - ImageListView.SortColumn >= 0 && ImageListView.SortColumn < ImageListView.Columns.Count && - (state & ItemState.Hovered) == ItemState.None && (state & ItemState.Selected) == ItemState.None && - ImageListView.Columns[ImageListView.SortColumn].Guid == column.Guid) - { - Rectangle subItemBounds = bounds; - subItemBounds.X = x; - subItemBounds.Width = column.Width; - using (Brush bGray16 = new SolidBrush(ImageListView.Colors.ColumnSelectColor)) - { - g.FillRectangle(bGray16, subItemBounds); - } - break; - } - x += column.Width; - } - - // Separators - if (!ImageListView.GroupsVisible) - { - x = bounds.Left - 1; - foreach (ImageListViewColumnHeader column in uicolumns) - { - x += column.Width; - if (!ReferenceEquals(column, uicolumns[uicolumns.Count - 1])) - { - using (Pen pGray32 = new Pen(ImageListView.Colors.ColumnSeparatorColor)) - { - g.DrawLine(pGray32, x, bounds.Top, x, bounds.Bottom); - } - } - } - } - - Size offset = new Size(2, (bounds.Height - ImageListView.Font.Height) / 2); - using (StringFormat sf = new StringFormat()) - { - sf.FormatFlags = StringFormatFlags.NoWrap; - sf.Alignment = StringAlignment.Near; - sf.LineAlignment = StringAlignment.Center; - sf.Trimming = StringTrimming.EllipsisCharacter; - // Sub text - int firstWidth = 0; - if (uicolumns.Count > 0) - firstWidth = uicolumns[0].Width; - RectangleF rt = new RectangleF(bounds.Left + offset.Width, bounds.Top + offset.Height, firstWidth - 2 * offset.Width, bounds.Height - 2 * offset.Height); - foreach (ImageListViewColumnHeader column in uicolumns) - { - rt.Width = column.Width - 2 * offset.Width; - Color foreColor = ImageListView.Colors.CellForeColor; - if ((state & ItemState.Disabled) != ItemState.None) - { - foreColor = ImageListView.Colors.DisabledForeColor; - } - else if ((state & ItemState.Selected) != ItemState.None) - { - if (ImageListView.Focused) - foreColor = ImageListView.Colors.SelectedForeColor; - else - foreColor = ImageListView.Colors.UnFocusedForeColor; - } - else if (alternate) - foreColor = ImageListView.Colors.AlternateCellForeColor; - using (Brush bItemFore = new SolidBrush(foreColor)) - { - int iconOffset = 0; - if (column.Type == ColumnType.Name) - { - // Allocate space for checkbox and file icon - if (ImageListView.ShowCheckBoxes && ImageListView.ShowFileIcons) - iconOffset += 2 * 16 + 3 * 2; - else if (ImageListView.ShowCheckBoxes) - iconOffset += 16 + 2 * 2; - else if (ImageListView.ShowFileIcons) - iconOffset += 16 + 2 * 2; - } - rt.X += iconOffset; - rt.Width -= iconOffset; - // Rating stars - if (column.Type == ColumnType.Rating && ImageListView.RatingImage != null && ImageListView.EmptyRatingImage != null) - { - int rating = item.GetSimpleRating(); - if (rating > 0) - { - int w = ImageListView.RatingImage.Width; - int y = (int)(rt.Top + (rt.Height - ImageListView.RatingImage.Height) / 2.0f); - - for (int i = 1; i <= 5; i++) - { - if (rating >= i) - g.DrawImage(ImageListView.RatingImage, rt.Left + (i - 1) * w, y); - else - g.DrawImage(ImageListView.EmptyRatingImage, rt.Left + (i - 1) * w, y); - } - } - } - else if (column.Type == ColumnType.Custom) - g.DrawString(item.GetSubItemText(column.Guid), ImageListView.Font, bItemFore, rt, sf); - else - g.DrawString(item.GetSubItemText(column.Type), ImageListView.Font, bItemFore, rt, sf); - - rt.X -= iconOffset; - } - rt.X += column.Width; - } - } - } - - // Item border - if (ImageListView.View != View.Details) - { - using (Pen pWhite128 = new Pen(Color.FromArgb(128, ImageListView.Colors.ControlBackColor))) - { - Utility.DrawRoundedRectangle(g, pWhite128, bounds.Left + 1, bounds.Top + 1, bounds.Width - 3, bounds.Height - 3, (ImageListView.View == View.Details ? 2 : 4)); - } - } - if (((state & ItemState.Disabled) != ItemState.None)) - { - using (Pen pHighlight128 = new Pen(ImageListView.Colors.DisabledBorderColor)) - { - Utility.DrawRoundedRectangle(g, pHighlight128, bounds.Left, bounds.Top, bounds.Width - 1, bounds.Height - 1, (ImageListView.View == View.Details ? 2 : 4)); - } - } - else if (ImageListView.Focused && ((state & ItemState.Selected) != ItemState.None)) - { - using (Pen pHighlight128 = new Pen(ImageListView.Colors.SelectedBorderColor)) - { - Utility.DrawRoundedRectangle(g, pHighlight128, bounds.Left, bounds.Top, bounds.Width - 1, bounds.Height - 1, (ImageListView.View == View.Details ? 2 : 4)); - } - } - else if (!ImageListView.Focused && ((state & ItemState.Selected) != ItemState.None)) - { - using (Pen pGray128 = new Pen(ImageListView.Colors.UnFocusedBorderColor)) - { - Utility.DrawRoundedRectangle(g, pGray128, bounds.Left, bounds.Top, bounds.Width - 1, bounds.Height - 1, (ImageListView.View == View.Details ? 2 : 4)); - } - } - else if (ImageListView.View != View.Details && (state & ItemState.Selected) == ItemState.None) - { - using (Pen pGray64 = new Pen(ImageListView.Colors.BorderColor)) - { - Utility.DrawRoundedRectangle(g, pGray64, bounds.Left, bounds.Top, bounds.Width - 1, bounds.Height - 1, (ImageListView.View == View.Details ? 2 : 4)); - } - } - - if (ImageListView.Focused && ((state & ItemState.Hovered) != ItemState.None)) - { - using (Pen pHighlight64 = new Pen(ImageListView.Colors.HoverBorderColor)) - { - Utility.DrawRoundedRectangle(g, pHighlight64, bounds.Left, bounds.Top, bounds.Width - 1, bounds.Height - 1, (ImageListView.View == View.Details ? 2 : 4)); - } - } - - // Focus rectangle - if (ImageListView.Focused && ((state & ItemState.Focused) != ItemState.None)) - { - ControlPaint.DrawFocusRectangle(g, bounds); - } - } - /// - /// Draws the overlay graphics for the specified sub item on the given graphics. - /// - /// The System.Drawing.Graphics to draw on. - /// The ImageListViewItem to draw. - /// The current view state of item. - /// The index of the sub item. The index returned is the 0-based index of the - /// column as displayed on the screen, considering column visibility and display indices. - /// Returns -1 if the hit point is not over a sub item. - /// true if the mouse cursor is over the sub item; otherwise false. - /// The bounding rectangle of the sub item in client coordinates. - public virtual void DrawSubItemItemOverlay(Graphics g, ImageListViewItem item, ItemState state, int subItemIndex, bool subItemHovered, Rectangle bounds) - { - ; - } - /// - /// Draws the checkbox icon for the specified item on the given graphics. - /// - /// The System.Drawing.Graphics to draw on. - /// The ImageListViewItem to draw. - /// The bounding rectangle of the checkbox in client coordinates. - public virtual void DrawCheckBox(Graphics g, ImageListViewItem item, Rectangle bounds) - { - Size size = CheckBoxRenderer.GetGlyphSize(g, CheckBoxState.CheckedNormal); - PointF pt = new PointF((float)bounds.X + ((float)bounds.Width - (float)size.Width) / 2.0f, - (float)bounds.Y + ((float)bounds.Height - (float)size.Height) / 2.0f); - CheckBoxState state = CheckBoxState.UncheckedNormal; - if (item.Enabled) - state = item.Checked ? CheckBoxState.CheckedNormal : CheckBoxState.UncheckedNormal; - else - state = item.Checked ? CheckBoxState.CheckedDisabled : CheckBoxState.UncheckedDisabled; - CheckBoxRenderer.DrawCheckBox(g, Point.Round(pt), state); - } - /// - /// Draws the file icon for the specified item on the given graphics. - /// - /// The System.Drawing.Graphics to draw on. - /// The ImageListViewItem to draw. - /// The bounding rectangle of the file icon in client coordinates. - public virtual void DrawFileIcon(Graphics g, ImageListViewItem item, Rectangle bounds) - { - Image icon = item.GetCachedImage(CachedImageType.SmallIcon); - if (icon != null) - { - Size size = icon.Size; - PointF ptf = new PointF((float)bounds.X + ((float)bounds.Width - (float)size.Width) / 2.0f, - (float)bounds.Y + ((float)bounds.Height - (float)size.Height) / 2.0f); - Point pt = Point.Round(ptf); - g.DrawImage(icon, pt.X, pt.Y); - } - } - /// - /// Draws the group headers. - /// - /// The System.Drawing.Graphics to draw on. - /// The name of the group to draw. - /// The bounding rectangle of group in client coordinates. - public virtual void DrawGroupHeader(Graphics g, string name, Rectangle bounds) - { - // Bottom border - bounds.Inflate(0, -4); - using (Pen pSpep = new Pen(new LinearGradientBrush(bounds, ImageListView.Colors.ColumnSeparatorColor, Color.Transparent, LinearGradientMode.Horizontal))) - { - g.DrawLine(pSpep, bounds.Left + 1, bounds.Bottom - 1, bounds.Right - 1, bounds.Bottom - 1); - } - - // Text - if (bounds.Width > 4) - { - using (StringFormat sf = new StringFormat()) - { - sf.FormatFlags = StringFormatFlags.NoWrap; - sf.Alignment = StringAlignment.Near; - sf.LineAlignment = StringAlignment.Center; - sf.Trimming = StringTrimming.EllipsisCharacter; - using (SolidBrush bText = new SolidBrush(ImageListView.Colors.ColumnHeaderForeColor)) - { - g.DrawString(name, (ImageListView.GroupHeaderFont == null ? ImageListView.Font : ImageListView.GroupHeaderFont), bText, bounds, sf); - } - } - } - } - /// - /// Draws the column headers. - /// - /// The System.Drawing.Graphics to draw on. - /// The ImageListViewColumnHeader to draw. - /// The current view state of column. - /// The bounding rectangle of column in client coordinates. - public virtual void DrawColumnHeader(Graphics g, ImageListViewColumnHeader column, ColumnState state, Rectangle bounds) - { - // Paint background - if ((state & ColumnState.Hovered) != ColumnState.None) - { - using (Brush bHovered = new LinearGradientBrush(bounds, ImageListView.Colors.ColumnHeaderHoverColor1, ImageListView.Colors.ColumnHeaderHoverColor2, LinearGradientMode.Vertical)) - { - g.FillRectangle(bHovered, bounds); - } - } - else - { - using (Brush bNormal = new LinearGradientBrush(bounds, ImageListView.Colors.ColumnHeaderBackColor1, ImageListView.Colors.ColumnHeaderBackColor2, LinearGradientMode.Vertical)) - { - g.FillRectangle(bNormal, bounds); - } - } - using (Brush bBorder = new LinearGradientBrush(bounds, ImageListView.Colors.ColumnHeaderBackColor2, ImageListView.Colors.ColumnHeaderBackColor1, LinearGradientMode.Vertical)) - using (Pen pBorder = new Pen(bBorder)) - { - g.DrawLine(pBorder, bounds.Left, bounds.Top, bounds.Left, bounds.Bottom); - g.DrawLine(pBorder, bounds.Left, bounds.Bottom - 1, bounds.Right, bounds.Bottom - 1); - } - using (Pen pSpep = new Pen(ImageListView.Colors.ColumnHeaderBackColor1)) - { - g.DrawLine(pSpep, bounds.Left + 1, bounds.Top + 1, bounds.Left + 1, bounds.Bottom - 2); - g.DrawLine(pSpep, bounds.Right - 1, bounds.Top + 1, bounds.Right - 1, bounds.Bottom - 2); - } - - // Draw the sort arrow - int textOffset = 4; - if (ImageListView.SortOrder != SortOrder.None && ((state & ColumnState.SortColumn) != ColumnState.None)) - { - Image img = null; - if (ImageListView.SortOrder == SortOrder.Ascending || ImageListView.SortOrder == SortOrder.AscendingNatural) - img = ImageListViewResources.SortAscending; - else if (ImageListView.SortOrder == SortOrder.Descending || ImageListView.SortOrder == SortOrder.DescendingNatural) - img = ImageListViewResources.SortDescending; - if (img != null) - { - g.DrawImageUnscaled(img, bounds.X + 4, bounds.Top + (bounds.Height - img.Height) / 2); - textOffset += img.Width; - } - } - - // Text - bounds.X += textOffset; - bounds.Width -= textOffset; - if (bounds.Width > 4) - { - using (StringFormat sf = new StringFormat()) - { - sf.FormatFlags = StringFormatFlags.NoWrap; - sf.Alignment = StringAlignment.Near; - sf.LineAlignment = StringAlignment.Center; - sf.Trimming = StringTrimming.EllipsisCharacter; - using (SolidBrush bText = new SolidBrush(ImageListView.Colors.ColumnHeaderForeColor)) - { - g.DrawString(column.Text, (ImageListView.ColumnHeaderFont == null ? ImageListView.Font : ImageListView.ColumnHeaderFont), bText, bounds, sf); - } - } - } - } - /// - /// Draws the left pane in Pane view mode. - /// - /// The System.Drawing.Graphics to draw on. - /// The ImageListViewItem to draw. - /// The image to draw. - /// The bounding rectangle of the pane. - public virtual void DrawPane(Graphics g, ImageListViewItem item, Image image, Rectangle bounds) - { - // Draw pane background - using (Brush bGray16 = new SolidBrush(ImageListView.Colors.PaneBackColor)) - { - g.FillRectangle(bGray16, bounds); - } - using (Brush bBorder = new SolidBrush(ImageListView.Colors.PaneSeparatorColor)) - { - g.FillRectangle(bBorder, bounds.Right - 2, bounds.Top, 2, bounds.Height); - } - bounds.Width -= 2; - - if (item != null && image != null) - { - // Calculate image bounds - Size itemMargin = MeasureItemMargin(ImageListView.View); - Rectangle pos = Utility.GetSizedImageBounds(image, new Rectangle(bounds.Location + itemMargin, bounds.Size - itemMargin - itemMargin), 50.0f, 0.0f); - // Draw image - g.DrawImage(image, pos); - // Draw image border - if (Math.Min(pos.Width, pos.Height) > 32) - { - using (Pen pGray128 = new Pen(ImageListView.Colors.ImageOuterBorderColor)) - { - g.DrawRectangle(pGray128, pos); - } - using (Pen pWhite128 = new Pen(ImageListView.Colors.ImageInnerBorderColor)) - { - g.DrawRectangle(pWhite128, Rectangle.Inflate(pos, -1, -1)); - } - } - bounds.X += itemMargin.Width; - bounds.Width -= 2 * itemMargin.Width; - bounds.Y = pos.Height + 16; - bounds.Height -= pos.Height + 16; - - // Item text - if (ImageListView.Columns.HasType(ColumnType.Name) && ImageListView.Columns[ColumnType.Name].Visible && bounds.Height > 0) - { - string itemText = item.GetSubItemText(ColumnType.Name); - using (SolidBrush bLabel = new SolidBrush(ImageListView.Colors.PaneLabelColor)) - using (SolidBrush bText = new SolidBrush(ImageListView.Colors.ForeColor)) - { - int y = Utility.DrawStringPair(g, bounds, "", itemText, ImageListView.Font, bLabel, bText); - bounds.Y += 2 * y; - bounds.Height -= 2 * y; - } - } - - // File type - string fileType = item.GetSubItemText(ColumnType.FileType); - if (ImageListView.Columns.HasType(ColumnType.FileType) && ImageListView.Columns[ColumnType.FileType].Visible && bounds.Height > 0 && !string.IsNullOrEmpty(fileType)) - { - using (SolidBrush bLabel = new SolidBrush(ImageListView.Colors.PaneLabelColor)) - using (SolidBrush bText = new SolidBrush(ImageListView.Colors.ForeColor)) - { - int y = Utility.DrawStringPair(g, bounds, ImageListView.Columns[ColumnType.FileType].Text + ": ", - fileType, ImageListView.Font, bLabel, bText); - bounds.Y += y; - bounds.Height -= y; - } - } - - // Metatada - foreach (ImageListView.ImageListViewColumnHeader column in ImageListView.Columns) - { - if (column.Type == ColumnType.ImageDescription) - { - bounds.Y += 8; - bounds.Height -= 8; - } - - if (bounds.Height <= 0) break; - - if (column.Visible && - column.Type != ColumnType.Custom && - column.Type != ColumnType.FileType && - column.Type != ColumnType.DateAccessed && - column.Type != ColumnType.FileName && - column.Type != ColumnType.FilePath && - column.Type != ColumnType.Name) - { - string caption = column.Text; - string text = item.GetSubItemText(column.Type); - if (!string.IsNullOrEmpty(text)) - { - using (SolidBrush bLabel = new SolidBrush(ImageListView.Colors.PaneLabelColor)) - using (SolidBrush bText = new SolidBrush(ImageListView.Colors.ForeColor)) - { - int y = Utility.DrawStringPair(g, bounds, caption + ": ", text, - ImageListView.Font, bLabel, bText); - bounds.Y += y; - bounds.Height -= y; - } - } - } - } - } - } - /// - /// [PHAP - Hide preview image] Draws the large preview image of the focused item in Gallery mode. - /// - /// The System.Drawing.Graphics to draw on. - /// The ImageListViewItem to draw. - /// The image to draw. - /// The bounding rectangle of the preview area. - public virtual void DrawGalleryImage(Graphics g, ImageListViewItem item, Image image, Rectangle bounds) - { - //if (item != null && image != null) - //{ - // // Calculate image bounds - // Size itemMargin = MeasureItemMargin(ImageListView.View); - // Rectangle pos = Utility.GetSizedImageBounds(image, new Rectangle(bounds.Location + itemMargin, bounds.Size - itemMargin - itemMargin)); - // // Draw image - // g.DrawImage(image, pos); - // // Draw image border - // if (Math.Min(pos.Width, pos.Height) > 32) - // { - // using (Pen pOuterBorder = new Pen(ImageListView.Colors.ImageOuterBorderColor)) - // using (Pen pInnerBorder = new Pen(ImageListView.Colors.ImageInnerBorderColor)) - // { - // g.DrawRectangle(pOuterBorder, pos); - // g.DrawRectangle(pInnerBorder, Rectangle.Inflate(pos, -1, -1)); - // } - // } - //} - } - /// - /// Draws the extender after the last column. - /// - /// The System.Drawing.Graphics to draw on. - /// The bounding rectangle of extender column in client coordinates. - public virtual void DrawColumnExtender(Graphics g, Rectangle bounds) - { - // Paint background - using (Brush bBack = new LinearGradientBrush(bounds, ImageListView.Colors.ColumnHeaderBackColor1, ImageListView.Colors.ColumnHeaderBackColor2, LinearGradientMode.Vertical)) - { - g.FillRectangle(bBack, bounds); - } - using (Brush bBorder = new LinearGradientBrush(bounds, ImageListView.Colors.ColumnHeaderBackColor2, ImageListView.Colors.ColumnHeaderBackColor1, LinearGradientMode.Vertical)) - using (Pen pBorder = new Pen(bBorder)) - { - g.DrawLine(pBorder, bounds.Left, bounds.Top, bounds.Left, bounds.Bottom); - g.DrawLine(pBorder, bounds.Left, bounds.Bottom - 1, bounds.Right, bounds.Bottom - 1); - } - using (Pen pSpep = new Pen(ImageListView.Colors.ColumnHeaderBackColor1)) - { - g.DrawLine(pSpep, bounds.Left + 1, bounds.Top + 1, bounds.Left + 1, bounds.Bottom - 2); - } - } - /// - /// Draws the insertion caret for drag and drop operations. - /// - /// The System.Drawing.Graphics to draw on. - /// The bounding rectangle of the insertion caret. - public virtual void DrawInsertionCaret(Graphics g, Rectangle bounds) - { - using (Brush b = new SolidBrush(ImageListView.Colors.InsertionCaretColor)) - { - g.FillRectangle(b, bounds); - } - } - /// - /// Draws an overlay image over the client area. - /// - /// The System.Drawing.Graphics to draw on. - /// The bounding rectangle of the client area. - public virtual void DrawOverlay(Graphics g, Rectangle bounds) - { - ; - } - /// - /// Releases managed resources. - /// - public virtual void Dispose() - { - ((IDisposable)this).Dispose(); - } - /// - /// Sets the layout of the control. - /// - /// A LayoutEventArgs that contains event data. - public virtual void OnLayout(LayoutEventArgs e) - { - ; - } - #endregion - } - } -} diff --git a/Source/Components/ImageGlass.ImageListView/ImageListViewRenderers.cs b/Source/Components/ImageGlass.ImageListView/ImageListViewRenderers.cs deleted file mode 100644 index 4d46b237f..000000000 --- a/Source/Components/ImageGlass.ImageListView/ImageListViewRenderers.cs +++ /dev/null @@ -1,3099 +0,0 @@ -// ImageListView - A listview control for image files -// Copyright (C) 2009 Ozgur Ozcitak -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// Ozgur Ozcitak (ozcitak@yahoo.com) - -using System; -using System.Collections.Generic; -using System.Drawing; -using System.Windows.Forms; -using System.Drawing.Drawing2D; -using System.Windows.Forms.VisualStyles; -using System.Diagnostics; - -namespace ImageGlass.ImageListView -{ - /// - /// Represents the built-in renderers. - /// - public static partial class ImageListViewRenderers - { - #region DefaultRenderer - /// - /// The default renderer. - /// - public class DefaultRenderer : ImageListView.ImageListViewRenderer - { - /// - /// Initializes a new instance of the DefaultRenderer class. - /// - public DefaultRenderer() - { - ; - } - } - #endregion - - #region DebugRenderer -#if DEBUG - /// - /// Represents a renderer meant to be used for debugging purposes. - /// Included in the debug build only. - /// - public class DebugRenderer : ImageListView.ImageListViewRenderer - { - private long baseMem; - - /// - /// Initializes a new instance of the DebugRenderer class. - /// - public DebugRenderer() - { - Process p = Process.GetCurrentProcess(); - p.Refresh(); - baseMem = p.PrivateMemorySize64; - } - /// - /// Draws the specified item on the given graphics. - /// - /// The System.Drawing.Graphics to draw on. - /// The ImageListViewItem to draw. - /// The current view state of item. - /// The bounding rectangle of item in client coordinates. - public override void DrawItem(Graphics g, ImageListViewItem item, ItemState state, Rectangle bounds) - { - if (item.Index == ImageListView.layoutManager.FirstPartiallyVisible || - item.Index == ImageListView.layoutManager.LastPartiallyVisible) - { - using (Brush b = new HatchBrush(HatchStyle.BackwardDiagonal, Color.Green, Color.Transparent)) - { - g.FillRectangle(b, bounds); - } - } - if (item.Index == ImageListView.layoutManager.FirstVisible || - item.Index == ImageListView.layoutManager.LastVisible) - { - using (Brush b = new HatchBrush(HatchStyle.ForwardDiagonal, Color.Red, Color.Transparent)) - { - g.FillRectangle(b, bounds); - } - } - - base.DrawItem(g, item, state, bounds); - } - /// - /// Draws an overlay image over the client area. - /// - /// The System.Drawing.Graphics to draw on. - /// The bounding rectangle of the client area. - public override void DrawOverlay(Graphics g, Rectangle bounds) - { - // Refresh process info - Process p = Process.GetCurrentProcess(); - p.Refresh(); - long mem = Math.Max(0, p.PrivateMemorySize64 - baseMem); - - // Display memory stats - string s = string.Format("Total: {0}\r\nCache: {1}\r\nCache*: {2}", Utility.FormatSize(baseMem), Utility.FormatSize(mem), Utility.FormatSize(ImageListView.thumbnailCache.MemoryUsed)); - SizeF sz = g.MeasureString(s, ImageListView.Font); - Rectangle r = new Rectangle(ItemAreaBounds.Right - 120, ItemAreaBounds.Top + 5, 115, (int)sz.Height); - using (Brush b = new SolidBrush(Color.FromArgb(220, Color.LightGray))) - { - g.FillRectangle(b, r); - } - using (Pen pen = new Pen(Color.FromArgb(128, Color.Gray))) - { - g.DrawRectangle(pen, r); - } - g.DrawString(s, ImageListView.Font, Brushes.Black, r.Location); - - // Display navigation parameters - r = new Rectangle(ItemAreaBounds.Right - 120, ItemAreaBounds.Top + 5 + (int)sz.Height + 10, 115, 125); - using (Brush b = new SolidBrush(Color.FromArgb(220, Color.LightGray))) - { - g.FillRectangle(b, r); - } - using (Pen pen = new Pen(Color.FromArgb(128, Color.Gray))) - { - g.DrawRectangle(pen, r); - } - - // Is left button down? - r = new Rectangle(r.Left + 5, r.Top + 5, 15, 15); - if (ImageListView.navigationManager.LeftButton) - { - g.FillRectangle(Brushes.DarkGray, r); - } - g.DrawRectangle(Pens.Black, r); - r.Offset(15, 0); - r.Offset(15, 0); - - // Is right button down? - if (ImageListView.navigationManager.RightButton) - { - g.FillRectangle(Brushes.DarkGray, r); - } - g.DrawRectangle(Pens.Black, r); - r.Offset(-30, 22); - - // Is shift key down? - Color tColor = Color.Gray; - if (ImageListView.navigationManager.ShiftKey) - tColor = Color.Black; - using (Brush b = new SolidBrush(tColor)) - { - g.DrawString("Shift", ImageListView.Font, b, r.Location); - } - r.Offset(0, 12); - - // Is control key down? - tColor = Color.Gray; - if (ImageListView.navigationManager.ControlKey) - tColor = Color.Black; - using (Brush b = new SolidBrush(tColor)) - { - g.DrawString("Control", ImageListView.Font, b, r.Location); - } - r.Offset(0, 20); - - // Display hit test details for item area - ImageListView.HitInfo h = null; - ImageListView.HitTest(ImageListView.PointToClient(Control.MousePosition), out h); - - tColor = Color.Gray; - if (h.InItemArea) - tColor = Color.Black; - using (Brush b = new SolidBrush(tColor)) - { - g.DrawString("InItemArea (" + h.ItemIndex.ToString() + ")", ImageListView.Font, b, r.Location); - } - r.Offset(0, 12); - - // Display hit test details for column header area - tColor = Color.Gray; - if (h.InHeaderArea) - tColor = Color.Black; - using (Brush b = new SolidBrush(tColor)) - { - if (h.Column != null) - { - g.DrawString("InHeaderArea (" + h.Column.ToString() + ")", ImageListView.Font, b, r.Location); - } - } - r.Offset(0, 12); - - // Display hit test details for pane area - tColor = Color.Gray; - if (h.InPaneArea) - tColor = Color.Black; - using (Brush b = new SolidBrush(tColor)) - { - g.DrawString("InPaneArea " + (h.PaneBorder ? " (Border)" : ""), ImageListView.Font, b, r.Location); - } - r.Offset(0, 12); - } - } -#endif - #endregion - - #region NewYear2010Renderer - /// - /// A renderer to celebrate the new year of 2010. - /// - /// Compile with conditional compilation symbol BONUSPACK to - /// include this renderer in the assembly. - public class NewYear2010Renderer : ImageListView.ImageListViewRenderer - { - /// - /// Represents a snow flake - /// - private class SnowFlake - { - /// - /// Gets or sets the client coordinates of the snow flake. - /// - public Point Location { get; set; } - /// - /// Gets or sets the rotation angle of the snow flake in degrees. - /// - public double Rotation { get; set; } - /// - /// Gets or sets the size of the snow flake. - /// - public int Size { get; set; } - - /// - /// Initializes a new instance of the SnowFlake class. - /// - /// The size of the snow flake. - public SnowFlake(int newSize) - { - Size = newSize; - Location = new Point(0, 0); - Rotation = 0.0; - } - } - - private readonly object lockObject = new object(); - - private int maxFlakeCount = 100; - private int minFlakeSize = 4; - private int maxFlakeSize = 12; - private int flakeGeneration = 3; - private int currentGeneration = 0; - private long refreshPeriod = 50; - private int fallSpeed = 3; - private DateTime lastRedraw = DateTime.Now; - private volatile bool inTimer = false; - - private List flakes = null; - private System.Threading.Timer timer; - private Random random = new Random(); - - private Rectangle displayBounds = Rectangle.Empty; - - private GraphicsPath flake; - private GraphicsPath terrain; - - /// - /// Initializes a new instance of the NewYear2010Renderer class. - /// - public NewYear2010Renderer() - { - flake = CreateFlake(10, 3); - terrain = CreateTerrain(); - timer = new System.Threading.Timer(UpdateTimerCallback, null, 0, refreshPeriod); - } - - /// - /// Generates a snowflake from a Koch curve. - /// http://en.wikipedia.org/wiki/Koch_snowflake - /// - /// The size of the snow flake. - /// Number of iterations. Higher values - /// produce more complex curves. - private GraphicsPath CreateFlake(int size, int iterations) - { - Queue segments = new Queue(); - float h = (float)Math.Sin(Math.PI / 3.0) * (float)size; - PointF v1 = new PointF(-1.0f * (float)size / 2.0f, -h / 3.0f); - PointF v2 = new PointF((float)size / 2f, -h / 3.0f); - PointF v3 = new PointF(0.0f, h * 2.0f / 3.0f); - segments.Enqueue(v1); segments.Enqueue(v2); - segments.Enqueue(v2); segments.Enqueue(v3); - segments.Enqueue(v3); segments.Enqueue(v1); - - for (int k = 0; k < iterations - 1; k++) - { - int todivide = segments.Count / 2; - for (int i = 0; i < todivide; i++) - { - PointF p1 = segments.Dequeue(); - PointF p2 = segments.Dequeue(); - - // Trisect the segment - PointF pi1 = new PointF((p2.X - p1.X) / 3.0f + p1.X, - (p2.Y - p1.Y) / 3.0f + p1.Y); - PointF pi2 = new PointF((p2.X - p1.X) * 2.0f / 3.0f + p1.X, - (p2.Y - p1.Y) * 2.0f / 3.0f + p1.Y); - double dist = Math.Sqrt((pi1.X - pi2.X) * (pi1.X - pi2.X) + (pi1.Y - pi2.Y) * (pi1.Y - pi2.Y)); - double angle = Math.Atan2(p2.Y - p1.Y, p2.X - p1.X) - Math.PI / 3.0; - PointF pn = new PointF(pi1.X + (float)(Math.Cos(angle) * dist), - pi1.Y + (float)(Math.Sin(angle) * dist)); - - segments.Enqueue(p1); segments.Enqueue(pi1); - segments.Enqueue(pi1); segments.Enqueue(pn); - segments.Enqueue(pn); segments.Enqueue(pi2); - segments.Enqueue(pi2); segments.Enqueue(p2); - } - } - - GraphicsPath path = new GraphicsPath(); - while (segments.Count != 0) - { - PointF p1 = segments.Dequeue(); - PointF p2 = segments.Dequeue(); - path.AddLine(p1, p2); - } - - path.CloseFigure(); - return path; - } - - /// - /// Generates a random snowy terrain. - /// - private GraphicsPath CreateTerrain() - { - Random rnd = new Random(); - GraphicsPath path = new GraphicsPath(); - int width = 100; - int height = 10; - - int count = 20; - int step = width / count; - int lastx = 0, lasty = 0; - Point[] points = new Point[count]; - for (int i = 0; i < count; i++) - { - int x = i * (width + 2 * step) / count - step; - int y = rnd.Next(-height / 2, height / 2); - points[i] = new Point(x, y); - lastx = x; - lasty = y; - } - path.AddCurve(points); - - path.AddLine(lastx, lasty, width + step, 0); - path.AddLine(width + step, 0, width + step, 200); - path.AddLine(width + step, 200, -step, 200); - path.CloseFigure(); - - return path; - } - - /// - /// Updates snow flakes at each timer tick. - /// - /// Not used, null. - private void UpdateTimerCallback(object state) - { - if (inTimer) return; - inTimer = true; - - bool redraw = false; - - lock (lockObject) - { - if (displayBounds.IsEmpty) - { - inTimer = false; - return; - } - - if (flakes == null) - flakes = new List(); - - // Add new snow flakes - currentGeneration++; - if (currentGeneration == flakeGeneration) - { - currentGeneration = 0; - if (flakes.Count < maxFlakeCount) - { - SnowFlake snowFlake = new SnowFlake(random.Next(minFlakeSize, maxFlakeSize)); - snowFlake.Rotation = 360.0 * random.NextDouble(); - snowFlake.Location = new Point(random.Next(displayBounds.Left, displayBounds.Right), -20); - flakes.Add(snowFlake); - } - } - - // Move snow flakes - for (int i = flakes.Count - 1; i >= 0; i--) - { - SnowFlake snowFlake = flakes[i]; - if (snowFlake.Location.Y > displayBounds.Height) - flakes.Remove(snowFlake); - else - { - snowFlake.Location = new Point(snowFlake.Location.X, snowFlake.Location.Y + snowFlake.Size * fallSpeed / 10); - snowFlake.Rotation += 360.0 / 40.0; - if (snowFlake.Rotation > 360.0) snowFlake.Rotation -= 360.0; - } - } - - // Do we need a refresh? - if ((DateTime.Now - lastRedraw).Milliseconds > refreshPeriod) - redraw = true; - } - - if (redraw) - { - try - { - if (ImageListView != null && ImageListView.IsHandleCreated && !ImageListView.IsDisposed) - { - if (ImageListView.InvokeRequired) - ImageListView.BeginInvoke((MethodInvoker)delegate { ImageListView.Refresh(); }); - else - ImageListView.Refresh(); - } - } - catch - { - ; - } - } - - inTimer = false; - } - - /// - /// Initializes the System.Drawing.Graphics used to draw - /// control elements. - /// - /// The System.Drawing.Graphics to draw on. - public override void InitializeGraphics(Graphics g) - { - base.InitializeGraphics(g); - g.SmoothingMode = SmoothingMode.HighQuality; - } - - /// - /// Sets the layout of the control. - /// - /// A LayoutEventArgs that contains event data. - public override void OnLayout(LayoutEventArgs e) - { - base.OnLayout(e); - lock (lockObject) - { - displayBounds = ImageListView.DisplayRectangle; - } - } - - /// - /// Draws an overlay image over the client area. - /// - /// The System.Drawing.Graphics to draw on. - /// The bounding rectangle of the client area. - public override void DrawOverlay(Graphics g, Rectangle bounds) - { - lock (lockObject) - { - lastRedraw = DateTime.Now; - } - - // Draw the terrain - DrawTerrain(g); - - lock (lockObject) - { - // Draw the snow flakes - if (flakes != null) - { - foreach (SnowFlake snowFlake in flakes) - DrawSnowFlake(g, snowFlake); - } - } - - // Redraw some of the terrain over slow flakes - DrawTerrainOutline(g); - } - - /// - /// Draws a snow flake. - /// - /// The System.Drawing.Graphics to draw on. - /// The snowflake to draw. - private void DrawSnowFlake(Graphics g, SnowFlake snowFlake) - { - g.ResetTransform(); - // Tranform to upper left corner before rotating. - // This produces a nice wobbling effect. - g.TranslateTransform(-snowFlake.Size / 2, -snowFlake.Size / 2, MatrixOrder.Append); - g.ScaleTransform((float)snowFlake.Size / 6.0f, (float)snowFlake.Size / 6.0f); - g.RotateTransform((float)snowFlake.Rotation, MatrixOrder.Append); - g.TranslateTransform(snowFlake.Location.X, snowFlake.Location.Y, MatrixOrder.Append); - using (SolidBrush brush = new SolidBrush(Color.White)) - using (Pen pen = new Pen(Color.Gray)) - using (Pen glowPen = new Pen(Color.FromArgb(96, Color.White), 2.0f)) - { - g.DrawPath(glowPen, flake); - g.FillPath(brush, flake); - g.DrawPath(pen, flake); - } - - g.ResetTransform(); - } - - /// - /// Draws the terrain. - /// - /// The System.Drawing.Graphics to draw on. - private void DrawTerrain(Graphics g) - { - g.ResetTransform(); - using (SolidBrush brush = new SolidBrush(Color.White)) - using (Pen pen = new Pen(Color.Gray)) - { - Rectangle rec = ImageListView.DisplayRectangle; - g.ScaleTransform((float)rec.Width / 100.0f, 3.0f, MatrixOrder.Append); - g.TranslateTransform(0, rec.Height - 30, MatrixOrder.Append); - g.FillPath(brush, terrain); - g.DrawPath(pen, terrain); - } - g.ResetTransform(); - } - - /// - /// Draws the terrain outline. - /// - /// The System.Drawing.Graphics to draw on. - private void DrawTerrainOutline(Graphics g) - { - g.ResetTransform(); - using (SolidBrush brush = new SolidBrush(Color.White)) - { - Rectangle rec = ImageListView.DisplayRectangle; - g.ScaleTransform((float)rec.Width / 100.0f, 3.0f, MatrixOrder.Append); - g.TranslateTransform(0, rec.Height - 20, MatrixOrder.Append); - g.FillPath(brush, terrain); - } - g.ResetTransform(); - } - - /// - /// Releases managed resources. - /// - public override void Dispose() - { - base.Dispose(); - - flake.Dispose(); - terrain.Dispose(); - timer.Dispose(); - } - } - #endregion - - #region NoirRenderer - /// - /// A renderer with a dark theme. - /// This renderer cannot be themed. - /// - public class NoirRenderer : ImageListView.ImageListViewRenderer - { - private int padding; - private int mReflectionSize; - - /// - /// Gets or sets the size of image reflections. - /// - public int ReflectionSize { get { return mReflectionSize; } set { mReflectionSize = value; } } - - /// - /// Initializes a new instance of the NoirRenderer class. - /// - public NoirRenderer() - : this(20) - { - ; - } - /// - /// Initializes a new instance of the NoirRenderer class. - /// - /// Size of image reflections. - public NoirRenderer(int reflectionSize) - { - mReflectionSize = reflectionSize; - padding = 4; - } - - /// - /// Gets a value indicating whether this renderer can apply custom colors. - /// - /// - public override bool CanApplyColors { get { return false; } } - - /// - /// Draws the background of the control. - /// - /// The System.Drawing.Graphics to draw on. - /// The client coordinates of the item area. - public override void DrawBackground(Graphics g, Rectangle bounds) - { - g.Clear(Color.Black); - } - /// - /// Returns item size for the given view mode. - /// - /// The view mode for which the measurement should be made. - /// The item size. - public override Size MeasureItem(View view) - { - if (view == View.Details) - return base.MeasureItem(view); - else - return new Size(ImageListView.ThumbnailSize.Width + 2 * padding, - ImageListView.ThumbnailSize.Height + 2 * padding + mReflectionSize); - } - /// - /// Draws the specified item on the given graphics. - /// - /// The System.Drawing.Graphics to draw on. - /// The ImageListViewItem to draw. - /// The current view state of item. - /// The bounding rectangle of item in client coordinates. - public override void DrawItem(Graphics g, ImageListViewItem item, ItemState state, Rectangle bounds) - { - // Item background color - using (Brush brush = new SolidBrush(Color.Black)) - { - g.FillRectangle(brush, bounds); - } - - if (ImageListView.View == View.Details) - { - // Item background - if ((state & ItemState.Selected) == ItemState.Selected) - { - using (Brush brush = new LinearGradientBrush(bounds, - Color.FromArgb(64, 96, 160), Color.FromArgb(64, 64, 96, 160), LinearGradientMode.Horizontal)) - { - g.FillRectangle(brush, bounds); - } - } - else if ((state & ItemState.Hovered) == ItemState.Hovered) - { - using (Brush brush = new LinearGradientBrush(bounds, - Color.FromArgb(64, Color.White), Color.FromArgb(16, Color.White), LinearGradientMode.Horizontal)) - { - g.FillRectangle(brush, bounds); - } - } - - // Shade sort column - List uicolumns = ImageListView.Columns.GetDisplayedColumns(); - int x = bounds.Left - 1; - foreach (ImageListView.ImageListViewColumnHeader column in uicolumns) - { - if (ImageListView.SortColumn >= 0 && ImageListView.SortColumn < ImageListView.Columns.Count && - ImageListView.Columns[ImageListView.SortColumn].Guid == column.Guid && - ImageListView.SortOrder != SortOrder.None && - (state & ItemState.Hovered) == ItemState.None && (state & ItemState.Selected) == ItemState.None) - { - Rectangle subItemBounds = bounds; - subItemBounds.X = x; - subItemBounds.Width = column.Width; - using (Brush brush = new SolidBrush(Color.FromArgb(32, 128, 128, 128))) - { - g.FillRectangle(brush, subItemBounds); - } - break; - } - x += column.Width; - } - // Separators - x = ImageListView.layoutManager.ColumnHeaderBounds.Left; - foreach (ImageListView.ImageListViewColumnHeader column in uicolumns) - { - x += column.Width; - if (!ReferenceEquals(column, uicolumns[uicolumns.Count - 1])) - { - using (Pen pen = new Pen(Color.FromArgb(64, 128, 128, 128))) - { - g.DrawLine(pen, x, bounds.Top, x, bounds.Bottom); - } - } - } - - // Item texts - Size offset = new Size(2, (bounds.Height - ImageListView.Font.Height) / 2); - using (StringFormat sf = new StringFormat()) - { - sf.FormatFlags = StringFormatFlags.NoWrap; - sf.Alignment = StringAlignment.Near; - sf.LineAlignment = StringAlignment.Center; - sf.Trimming = StringTrimming.EllipsisCharacter; - // Sub text - RectangleF rt = new RectangleF(bounds.Left + offset.Width, bounds.Top + offset.Height, uicolumns[0].Width - 2 * offset.Width, bounds.Height - 2 * offset.Height); - foreach (ImageListView.ImageListViewColumnHeader column in uicolumns) - { - rt.Width = column.Width - 2 * offset.Width; - Color foreColor = Color.White; - if (!item.Enabled) foreColor = Color.FromArgb(128, 128, 128); - using (Brush bItemFore = new SolidBrush(foreColor)) - { - if (column.Type == ColumnType.Rating && ImageListView.RatingImage != null && ImageListView.EmptyRatingImage != null) - { - string srating = item.GetSubItemText(ColumnType.Rating); - if (!string.IsNullOrEmpty(srating)) - { - int w = ImageListView.RatingImage.Width; - int y = (int)(rt.Top + (rt.Height - ImageListView.RatingImage.Height) / 2.0f); - int rating = item.StarRating; - if (rating < 0) rating = 0; - if (rating > 5) rating = 5; - for (int i = 1; i <= rating; i++) - g.DrawImage(ImageListView.RatingImage, rt.Left + (i - 1) * w, y); - for (int i = rating + 1; i <= 5; i++) - g.DrawImage(ImageListView.EmptyRatingImage, rt.Left + (i - 1) * w, y); - } - } - else if (column.Type == ColumnType.Custom) - g.DrawString(item.GetSubItemText(column.Guid), ImageListView.Font, bItemFore, rt, sf); - else - g.DrawString(item.GetSubItemText(column.Type), ImageListView.Font, bItemFore, rt, sf); - } - rt.X += column.Width; - } - } - - // Border - if ((state & ItemState.Hovered) == ItemState.Hovered) - { - using (Pen pen = new Pen(Color.FromArgb(128, Color.White))) - { - g.DrawRectangle(pen, bounds.X, bounds.Y, bounds.Width - 1, bounds.Height - 1); - } - } - else if ((state & ItemState.Selected) == ItemState.Hovered) - { - using (Pen pen = new Pen(Color.FromArgb(96, 144, 240))) - { - g.DrawRectangle(pen, bounds.X, bounds.Y, bounds.Width - 1, bounds.Height - 1); - } - } - } - else // if (ImageListView.View != View.Details) - { - // Align images to bottom of bounds - Image img = item.GetCachedImage(CachedImageType.Thumbnail); - if (img != null) - { - Rectangle pos = Utility.GetSizedImageBounds(img, - new Rectangle(bounds.X + padding, bounds.Y + padding, bounds.Width - 2 * padding, bounds.Height - 2 * padding - mReflectionSize), - 50.0f, 100.0f); - - int x = pos.X; - int y = pos.Y; - - // Item background - if ((state & ItemState.Selected) == ItemState.Selected) - { - using (Brush brush = new LinearGradientBrush( - new Point(x - padding, y - padding), new Point(x - padding, y + pos.Height + 2 * padding), - Color.FromArgb(64, 96, 160), Color.FromArgb(16, 16, 16))) - { - g.FillRectangle(brush, x - padding, y - padding, pos.Width + 2 * padding, pos.Height + 2 * padding); - } - } - else if ((state & ItemState.Hovered) == ItemState.Hovered) - { - using (Brush brush = new LinearGradientBrush( - new Point(x - padding, y - padding), new Point(x - padding, y + pos.Height + 2 * padding), - Color.FromArgb(64, Color.White), Color.FromArgb(16, 16, 16))) - { - g.FillRectangle(brush, x - padding, y - padding, pos.Width + 2 * padding, pos.Height + 2 * padding); - } - } - - // Border - if ((state & ItemState.Hovered) == ItemState.Hovered) - { - using (Brush brush = new LinearGradientBrush( - new Point(x - padding, y - padding), new Point(x - padding, y + pos.Height + 2 * padding), - Color.FromArgb(128, Color.White), Color.FromArgb(16, 16, 16))) - using (Pen pen = new Pen(brush)) - { - g.DrawRectangle(pen, x - padding, y - padding + 1, pos.Width + 2 * padding - 1, pos.Height + 2 * padding - 1); - } - } - else if ((state & ItemState.Selected) == ItemState.Selected) - { - using (Brush brush = new LinearGradientBrush( - new Point(x - padding, y - padding), new Point(x - padding, y + pos.Height + 2 * padding), - Color.FromArgb(96, 144, 240), Color.FromArgb(16, 16, 16))) - using (Pen pen = new Pen(brush)) - { - g.DrawRectangle(pen, x - padding, y - padding + 1, pos.Width + 2 * padding - 1, pos.Height + 2 * padding - 1); - } - } - - // Draw item image - DrawImageWithReflection(g, img, pos, mReflectionSize); - - // Shade over disabled item image - if (!item.Enabled) - { - pos.Inflate(4, 4); - using (Brush brush = new LinearGradientBrush(pos, - Color.FromArgb(64, 0, 0, 0), Color.FromArgb(196, 0, 0, 0), LinearGradientMode.Vertical)) - { - g.FillRectangle(brush, pos); - } - } - - // Highlight - if (item.Enabled) - { - using (Pen pen = new Pen(Color.FromArgb(160, Color.White))) - { - g.DrawLine(pen, pos.X, pos.Y + 1, pos.X + pos.Width - 1, pos.Y + 1); - g.DrawLine(pen, pos.X, pos.Y + 1, pos.X, pos.Y + pos.Height); - } - } - } - } - } - /// - /// Draws the checkbox icon for the specified item on the given graphics. - /// - /// The System.Drawing.Graphics to draw on. - /// The ImageListViewItem to draw. - /// The bounding rectangle of the checkbox in client coordinates. - public override void DrawCheckBox(Graphics g, ImageListViewItem item, Rectangle bounds) - { - ; - } - /// - /// Draws the file icon for the specified item on the given graphics. - /// - /// The System.Drawing.Graphics to draw on. - /// The ImageListViewItem to draw. - /// The bounding rectangle of the file icon in client coordinates. - public override void DrawFileIcon(Graphics g, ImageListViewItem item, Rectangle bounds) - { - ; - } - /// - /// Draws the column headers. - /// - /// The System.Drawing.Graphics to draw on. - /// The ImageListViewColumnHeader to draw. - /// The current view state of column. - /// The bounding rectangle of column in client coordinates. - public override void DrawColumnHeader(Graphics g, ImageListView.ImageListViewColumnHeader column, ColumnState state, Rectangle bounds) - { - // Paint background - if (ImageListView.Focused && ((state & ColumnState.Hovered) == ColumnState.Hovered)) - { - using (Brush bHovered = new LinearGradientBrush(bounds, - Color.FromArgb(64, 96, 144, 240), Color.FromArgb(196, 96, 144, 240), LinearGradientMode.Vertical)) - { - g.FillRectangle(bHovered, bounds); - } - } - else - { - using (Brush bNormal = new LinearGradientBrush(bounds, - Color.FromArgb(32, 128, 128, 128), Color.FromArgb(196, 128, 128, 128), LinearGradientMode.Vertical)) - { - g.FillRectangle(bNormal, bounds); - } - } - using (Brush bBorder = new LinearGradientBrush(bounds, - Color.FromArgb(96, 128, 128, 128), Color.FromArgb(128, 128, 128), LinearGradientMode.Vertical)) - using (Pen pBorder = new Pen(bBorder)) - { - g.DrawLine(pBorder, bounds.Left, bounds.Top, bounds.Left, bounds.Bottom); - g.DrawLine(pBorder, bounds.Left, bounds.Bottom - 1, bounds.Right, bounds.Bottom - 1); - } - using (Pen pen = new Pen(Color.FromArgb(16, Color.White))) - { - g.DrawLine(pen, bounds.Left + 1, bounds.Top + 1, bounds.Left + 1, bounds.Bottom - 2); - g.DrawLine(pen, bounds.Right - 1, bounds.Top + 1, bounds.Right - 1, bounds.Bottom - 2); - } - - // Draw the sort arrow - int textOffset = 4; - if (ImageListView.SortOrder != SortOrder.None && ((state & ColumnState.SortColumn) != ColumnState.None)) - { - Image img = null; - if (ImageListView.SortOrder == SortOrder.Ascending || ImageListView.SortOrder == SortOrder.AscendingNatural) - img = ImageListViewResources.SortAscending; - else if (ImageListView.SortOrder == SortOrder.Descending || ImageListView.SortOrder == SortOrder.DescendingNatural) - img = ImageListViewResources.SortDescending; - g.DrawImageUnscaled(img, bounds.X + 4, bounds.Top + (bounds.Height - img.Height) / 2); - textOffset += img.Width; - } - - // Text - bounds.X += textOffset; - bounds.Width -= textOffset; - if (bounds.Width > 4) - { - using (StringFormat sf = new StringFormat()) - { - sf.FormatFlags = StringFormatFlags.NoWrap; - sf.Alignment = StringAlignment.Near; - sf.LineAlignment = StringAlignment.Center; - sf.Trimming = StringTrimming.EllipsisCharacter; - using (Brush brush = new SolidBrush(Color.White)) - { - g.DrawString(column.Text, - (ImageListView.ColumnHeaderFont == null ? ImageListView.Font : ImageListView.ColumnHeaderFont), - brush, bounds, sf); - } - } - } - } - /// - /// Draws the extender after the last column. - /// - /// The System.Drawing.Graphics to draw on. - /// The bounding rectangle of extender column in client coordinates. - public override void DrawColumnExtender(Graphics g, Rectangle bounds) - { - using (Brush bNormal = new LinearGradientBrush(bounds, - Color.FromArgb(32, 128, 128, 128), Color.FromArgb(196, 128, 128, 128), LinearGradientMode.Vertical)) - { - g.FillRectangle(bNormal, bounds); - } - using (Brush bBorder = new LinearGradientBrush(bounds, - Color.FromArgb(96, 128, 128, 128), Color.FromArgb(128, 128, 128), LinearGradientMode.Vertical)) - using (Pen pBorder = new Pen(bBorder)) - { - g.DrawLine(pBorder, bounds.Left, bounds.Top, bounds.Left, bounds.Bottom); - g.DrawLine(pBorder, bounds.Left, bounds.Bottom - 1, bounds.Right, bounds.Bottom - 1); - } - using (Pen pen = new Pen(Color.FromArgb(16, Color.White))) - { - g.DrawLine(pen, bounds.Left + 1, bounds.Top + 1, bounds.Left + 1, bounds.Bottom - 2); - g.DrawLine(pen, bounds.Right - 1, bounds.Top + 1, bounds.Right - 1, bounds.Bottom - 2); - } - } - /// - /// Draws the large preview image of the focused item in Gallery mode. - /// - /// The System.Drawing.Graphics to draw on. - /// The ImageListViewItem to draw. - /// The image to draw. - /// The bounding rectangle of the preview area. - public override void DrawGalleryImage(Graphics g, ImageListViewItem item, Image image, Rectangle bounds) - { - if (item != null && image != null) - { - Size itemMargin = MeasureItemMargin(ImageListView.View); - Rectangle pos = Utility.GetSizedImageBounds(image, new Rectangle(bounds.X + itemMargin.Width, bounds.Y + itemMargin.Height, bounds.Width - 2 * itemMargin.Width, bounds.Height - 2 * itemMargin.Height - mReflectionSize), 50.0f, 100.0f); - DrawImageWithReflection(g, image, pos, mReflectionSize); - } - } - /// - /// Draws the left pane in Pane view mode. - /// - /// The System.Drawing.Graphics to draw on. - /// The ImageListViewItem to draw. - /// The image to draw. - /// The bounding rectangle of the pane. - public override void DrawPane(Graphics g, ImageListViewItem item, Image image, Rectangle bounds) - { - // Draw resize handle - using (Brush bBorder = new SolidBrush(Color.FromArgb(64, 64, 64))) - { - g.FillRectangle(bBorder, bounds.Right - 2, bounds.Top, 2, bounds.Height); - } - bounds.Width -= 2; - - if (item != null && image != null) - { - // Calculate image bounds - Size itemMargin = MeasureItemMargin(ImageListView.View); - Rectangle pos = Utility.GetSizedImageBounds(image, new Rectangle(bounds.Location + itemMargin, bounds.Size - itemMargin - itemMargin), 50.0f, 0.0f); - // Draw image - g.DrawImage(image, pos); - - bounds.X += itemMargin.Width; - bounds.Width -= 2 * itemMargin.Width; - bounds.Y = pos.Height + 16; - bounds.Height -= pos.Height + 16; - - // Item text - if (ImageListView.Columns.HasType(ColumnType.Name) && ImageListView.Columns[ColumnType.Name].Visible && bounds.Height > 0) - { - string text = item.GetSubItemText(ColumnType.Name); - int y = Utility.DrawStringPair(g, bounds, "", text, ImageListView.Font, - Brushes.White, Brushes.White); - bounds.Y += 2 * y; - bounds.Height -= 2 * y; - } - - // File type - string fileType = item.GetSubItemText(ColumnType.FileType); - if (ImageListView.Columns.HasType(ColumnType.FileType) && ImageListView.Columns[ColumnType.FileType].Visible && bounds.Height > 0 && !string.IsNullOrEmpty(fileType)) - { - using (Brush bCaption = new SolidBrush(Color.FromArgb(196, 196, 196))) - using (Brush bText = new SolidBrush(Color.White)) - { - int y = Utility.DrawStringPair(g, bounds, ImageListView.Columns[ColumnType.FileType].Text + ": ", - fileType, ImageListView.Font, bCaption, bText); - bounds.Y += y; - bounds.Height -= y; - } - } - - // Metatada - foreach (ImageListView.ImageListViewColumnHeader column in ImageListView.Columns) - { - if (column.Type == ColumnType.ImageDescription) - { - bounds.Y += 8; - bounds.Height -= 8; - } - - if (bounds.Height <= 0) break; - - if (column.Visible && - column.Type != ColumnType.Custom && - column.Type != ColumnType.FileType && - column.Type != ColumnType.DateAccessed && - column.Type != ColumnType.FileName && - column.Type != ColumnType.FilePath && - column.Type != ColumnType.Name) - { - string caption = column.Text; - string text = item.GetSubItemText(column.Type); - if (!string.IsNullOrEmpty(text)) - { - using (Brush bCaption = new SolidBrush(Color.FromArgb(196, 196, 196))) - using (Brush bText = new SolidBrush(Color.White)) - { - int y = Utility.DrawStringPair(g, bounds, caption + ": ", text, - ImageListView.Font, bCaption, bText); - bounds.Y += y; - bounds.Height -= y; - } - } - } - } - } - } - /// - /// Draws the selection rectangle. - /// - /// The System.Drawing.Graphics to draw on. - /// The client coordinates of the selection rectangle. - public override void DrawSelectionRectangle(Graphics g, Rectangle selection) - { - using (Brush brush = new LinearGradientBrush(selection, - Color.FromArgb(160, 96, 144, 240), Color.FromArgb(32, 96, 144, 240), - LinearGradientMode.ForwardDiagonal)) - { - g.FillRectangle(brush, selection); - } - using (Brush brush = new LinearGradientBrush(selection, - Color.FromArgb(96, 144, 240), Color.FromArgb(128, 96, 144, 240), - LinearGradientMode.ForwardDiagonal)) - using (Pen pen = new Pen(brush)) - { - g.DrawRectangle(pen, selection); - } - } - /// - /// Draws the insertion caret for drag and drop operations. - /// - /// The System.Drawing.Graphics to draw on. - /// The bounding rectangle of the insertion caret. - public override void DrawInsertionCaret(Graphics g, Rectangle bounds) - { - using (Brush b = new SolidBrush(Color.FromArgb(96, 144, 240))) - { - g.FillRectangle(b, bounds); - } - } - /// - /// Draws the group headers. - /// - /// The System.Drawing.Graphics to draw on. - /// The name of the group to draw. - /// The bounding rectangle of group in client coordinates. - public override void DrawGroupHeader(Graphics g, string name, Rectangle bounds) - { - // Bottom border - bounds.Inflate(0, -4); - using (Pen pSpep = new Pen(Color.FromArgb(64, 64, 64))) - { - g.DrawLine(pSpep, bounds.Left + 1, bounds.Bottom - 1, bounds.Right - 1, bounds.Bottom - 1); - } - - // Text - if (bounds.Width > 4) - { - using (StringFormat sf = new StringFormat()) - { - sf.FormatFlags = StringFormatFlags.NoWrap; - sf.Alignment = StringAlignment.Near; - sf.LineAlignment = StringAlignment.Center; - sf.Trimming = StringTrimming.EllipsisCharacter; - using (SolidBrush bText = new SolidBrush(Color.White)) - { - g.DrawString(name, (ImageListView.GroupHeaderFont == null ? ImageListView.Font : ImageListView.GroupHeaderFont), bText, bounds, sf); - } - } - } - } - - /// - /// Draws an image with a reflection effect at the bottom. - /// - /// The graphics to draw on. - /// The image to draw. - /// The x coordinate of the upper left corner of the image. - /// The y coordinate of the upper left corner of the image. - /// Width of the drawn image. - /// Height of the drawn image. - /// Height of the reflection. - private void DrawImageWithReflection(Graphics g, Image img, int x, int y, int width, int height, int reflection) - { - // Draw the image - g.DrawImage(img, x, y + 1, width, height); - - // Draw the reflection - if (img.Width > 32 && img.Height > 32) - { - int reflectionHeight = height / 2; - if (reflectionHeight > reflection) reflectionHeight = reflection; - - Region prevClip = g.Clip; - g.SetClip(new Rectangle(x, y + height + 1, width, reflectionHeight)); - g.DrawImage(img, x, y + height + height / 2 + 1, width, -height / 2); - g.Clip = prevClip; - - using (Brush brush = new LinearGradientBrush( - new Point(x, y + height + 1), new Point(x, y + height + reflectionHeight + 1), - Color.FromArgb(128, 0, 0, 0), Color.Black)) - { - g.FillRectangle(brush, x, y + height + 1, width, reflectionHeight); - } - } - } - /// - /// Draws an image with a reflection effect at the bottom. - /// - /// The graphics to draw on. - /// The image to draw. - /// The target bounding rectangle. - /// Height of the reflection. - private void DrawImageWithReflection(Graphics g, Image img, Rectangle bounds, int reflection) - { - DrawImageWithReflection(g, img, bounds.X, bounds.Y, bounds.Width, bounds.Height, reflection); - } - } - #endregion - - #region TilesRenderer - /// - /// Displays items with large tiles. - /// - public class TilesRenderer : ImageListView.ImageListViewRenderer - { - private Font mCaptionFont; - private int mTileWidth; - private int mTextHeight; - - /// - /// Gets or sets the width of the tile. - /// - public int TileWidth { get { return mTileWidth; } set { mTileWidth = value; } } - - private Font CaptionFont - { - get - { - if (mCaptionFont == null) - mCaptionFont = new Font(ImageListView.Font, FontStyle.Bold); - return mCaptionFont; - } - } - - /// - /// Initializes a new instance of the TilesRenderer class. - /// - public TilesRenderer() - : this(150) - { - ; - } - - /// - /// Initializes a new instance of the TilesRenderer class. - /// - /// Width of tiles in pixels. - public TilesRenderer(int tileWidth) - { - mTileWidth = tileWidth; - } - - /// - /// Releases managed resources. - /// - public override void Dispose() - { - if (mCaptionFont != null) - mCaptionFont.Dispose(); - - base.Dispose(); - } - /// - /// Returns item size for the given view mode. - /// - /// The view mode for which the item measurement should be made. - /// The item size. - public override Size MeasureItem(ImageGlass.ImageListView.View view) - { - if (view == ImageGlass.ImageListView.View.Thumbnails) - { - Size itemSize = new Size(); - mTextHeight = (int)(5.8f * (float)CaptionFont.Height); - - // Calculate item size - Size itemPadding = new Size(4, 4); - itemSize.Width = ImageListView.ThumbnailSize.Width + 4 * itemPadding.Width + mTileWidth; - itemSize.Height = Math.Max(mTextHeight, ImageListView.ThumbnailSize.Height) + 2 * itemPadding.Height; - return itemSize; - } - else - return base.MeasureItem(view); - } - /// - /// Draws the specified item on the given graphics. - /// - /// The System.Drawing.Graphics to draw on. - /// The ImageListViewItem to draw. - /// The current view state of item. - /// The bounding rectangle of item in client coordinates. - public override void DrawItem(Graphics g, ImageListViewItem item, ItemState state, Rectangle bounds) - { - if (ImageListView.View == ImageGlass.ImageListView.View.Thumbnails) - { - Size itemPadding = new Size(4, 4); - - // Paint background - if (ImageListView.Enabled) - { - using (Brush bItemBack = new SolidBrush(ImageListView.Colors.BackColor)) - { - g.FillRectangle(bItemBack, bounds); - } - } - else - { - using (Brush bItemBack = new SolidBrush(ImageListView.Colors.DisabledBackColor)) - { - g.FillRectangle(bItemBack, bounds); - } - } - - // Paint background Disabled - if ((state & ItemState.Disabled) != ItemState.None) - { - using (Brush bDisabled = new LinearGradientBrush(bounds, ImageListView.Colors.DisabledColor1, ImageListView.Colors.DisabledColor2, LinearGradientMode.Vertical)) - { - Utility.FillRoundedRectangle(g, bDisabled, bounds, 4); - } - } - else if ((ImageListView.Focused && ((state & ItemState.Selected) != ItemState.None)) || - (!ImageListView.Focused && ((state & ItemState.Selected) != ItemState.None) && ((state & ItemState.Hovered) != ItemState.None))) - { - using (Brush bSelected = new LinearGradientBrush(bounds, ImageListView.Colors.SelectedColor1, ImageListView.Colors.SelectedColor2, LinearGradientMode.Vertical)) - { - Utility.FillRoundedRectangle(g, bSelected, bounds, 4); - } - } - else if (!ImageListView.Focused && ((state & ItemState.Selected) != ItemState.None)) - { - using (Brush bGray64 = new LinearGradientBrush(bounds, ImageListView.Colors.UnFocusedColor1, ImageListView.Colors.UnFocusedColor2, LinearGradientMode.Vertical)) - { - Utility.FillRoundedRectangle(g, bGray64, bounds, 4); - } - } - if (((state & ItemState.Hovered) != ItemState.None)) - { - using (Brush bHovered = new LinearGradientBrush(bounds, ImageListView.Colors.HoverColor1, ImageListView.Colors.HoverColor2, LinearGradientMode.Vertical)) - { - Utility.FillRoundedRectangle(g, bHovered, bounds, 4); - } - } - - // Draw the image - Image img = item.GetCachedImage(CachedImageType.Thumbnail); - if (img != null) - { - Rectangle pos = Utility.GetSizedImageBounds(img, new Rectangle(bounds.Location + itemPadding, ImageListView.ThumbnailSize), 0.0f, 50.0f); - g.DrawImage(img, pos); - // Draw image border - if (Math.Min(pos.Width, pos.Height) > 32) - { - using (Pen pOuterBorder = new Pen(ImageListView.Colors.ImageOuterBorderColor)) - { - g.DrawRectangle(pOuterBorder, pos); - } - if (System.Math.Min(ImageListView.ThumbnailSize.Width, ImageListView.ThumbnailSize.Height) > 32) - { - using (Pen pInnerBorder = new Pen(ImageListView.Colors.ImageInnerBorderColor)) - { - g.DrawRectangle(pInnerBorder, Rectangle.Inflate(pos, -1, -1)); - } - } - } - } - - // Draw item text - int lineHeight = CaptionFont.Height; - RectangleF rt; - using (StringFormat sf = new StringFormat()) - { - rt = new RectangleF(bounds.Left + 2 * itemPadding.Width + ImageListView.ThumbnailSize.Width, - bounds.Top + itemPadding.Height + (Math.Max(ImageListView.ThumbnailSize.Height, mTextHeight) - mTextHeight) / 2, - mTileWidth, lineHeight); - sf.Alignment = StringAlignment.Near; - sf.FormatFlags = StringFormatFlags.NoWrap; - sf.LineAlignment = StringAlignment.Center; - sf.Trimming = StringTrimming.EllipsisCharacter; - Color foreColor = ImageListView.Colors.ForeColor; - if ((state & ItemState.Disabled) != ItemState.None) - { - foreColor = ImageListView.Colors.DisabledForeColor; - } - using (Brush bItemFore = new SolidBrush(foreColor)) - { - g.DrawString(item.Text, CaptionFont, bItemFore, rt, sf); - } - using (Brush bItemDetails = new SolidBrush(ImageListView.Colors.PaneLabelColor)) - { - rt.Offset(0, 1.5f * lineHeight); - string fileType = item.GetSubItemText(ColumnType.FileType); - if (!string.IsNullOrEmpty(fileType)) - { - g.DrawString(fileType, ImageListView.Font, bItemDetails, rt, sf); - rt.Offset(0, 1.1f * lineHeight); - } - string dimensions = item.GetSubItemText(ColumnType.Dimensions); - string resolution = item.GetSubItemText(ColumnType.Resolution); - if (!string.IsNullOrEmpty(dimensions) || !string.IsNullOrEmpty(resolution)) - { - string text = ""; - if (!string.IsNullOrEmpty(dimensions)) - text += dimensions + " pixels "; - if (!string.IsNullOrEmpty(resolution)) - text += resolution.Split(new char[] { ' ', 'x' }, StringSplitOptions.RemoveEmptyEntries)[0] + " dpi"; - g.DrawString(text, ImageListView.Font, bItemDetails, rt, sf); - rt.Offset(0, 1.1f * lineHeight); - } - string fileSize = item.GetSubItemText(ColumnType.FileSize); - if (!string.IsNullOrEmpty(fileSize)) - { - g.DrawString(fileSize, ImageListView.Font, bItemDetails, rt, sf); - rt.Offset(0, 1.1f * lineHeight); - } - string dateModified = item.GetSubItemText(ColumnType.DateModified); - if (!string.IsNullOrEmpty(dateModified)) - { - g.DrawString(dateModified, ImageListView.Font, bItemDetails, rt, sf); - } - } - } - - // Item border - using (Pen pWhite128 = new Pen(Color.FromArgb(128, ImageListView.Colors.ControlBackColor))) - { - Utility.DrawRoundedRectangle(g, pWhite128, bounds.Left + 1, bounds.Top + 1, bounds.Width - 3, bounds.Height - 3, 4); - } - if (((state & ItemState.Disabled) != ItemState.None)) - { - using (Pen pHighlight128 = new Pen(ImageListView.Colors.DisabledBorderColor)) - { - Utility.DrawRoundedRectangle(g, pHighlight128, bounds.Left, bounds.Top, bounds.Width - 1, bounds.Height - 1, 4); - } - } - else if (ImageListView.Focused && ((state & ItemState.Selected) != ItemState.None)) - { - using (Pen pHighlight128 = new Pen(ImageListView.Colors.SelectedBorderColor)) - { - Utility.DrawRoundedRectangle(g, pHighlight128, bounds.Left, bounds.Top, bounds.Width - 1, bounds.Height - 1, 4); - } - } - else if (!ImageListView.Focused && ((state & ItemState.Selected) != ItemState.None)) - { - using (Pen pGray128 = new Pen(ImageListView.Colors.UnFocusedBorderColor)) - { - Utility.DrawRoundedRectangle(g, pGray128, bounds.Left, bounds.Top, bounds.Width - 1, bounds.Height - 1, 4); - } - } - else if ((state & ItemState.Selected) == ItemState.None) - { - using (Pen pGray64 = new Pen(ImageListView.Colors.BorderColor)) - { - Utility.DrawRoundedRectangle(g, pGray64, bounds.Left, bounds.Top, bounds.Width - 1, bounds.Height - 1, 4); - } - } - - if (ImageListView.Focused && ((state & ItemState.Hovered) != ItemState.None)) - { - using (Pen pHighlight64 = new Pen(ImageListView.Colors.HoverBorderColor)) - { - Utility.DrawRoundedRectangle(g, pHighlight64, bounds.Left, bounds.Top, bounds.Width - 1, bounds.Height - 1, 4); - } - } - - // Focus rectangle - if (ImageListView.Focused && ((state & ItemState.Focused) != ItemState.None)) - { - ControlPaint.DrawFocusRectangle(g, bounds); - } - } - else - base.DrawItem(g, item, state, bounds); - } - } - #endregion - - #region XPRenderer - /// - /// Mimics Windows XP appearance. - /// This renderer cannot be themed. - /// - public class XPRenderer : ImageListView.ImageListViewRenderer - { - /// - /// Gets a value indicating whether this renderer can apply custom colors. - /// - /// - public override bool CanApplyColors { get { return false; } } - - /// - /// Returns item size for the given view mode. - /// - /// The view mode for which the item measurement should be made. - /// The item size. - public override Size MeasureItem(ImageGlass.ImageListView.View view) - { - Size itemSize = new Size(); - - // Reference text height - int textHeight = ImageListView.Font.Height; - - if (view == ImageGlass.ImageListView.View.Details) - return base.MeasureItem(view); - else - { - // Calculate item size - Size itemPadding = new Size(4, 4); - itemSize = ImageListView.ThumbnailSize + itemPadding + itemPadding; - itemSize.Height += textHeight + System.Math.Max(4, textHeight / 3) + itemPadding.Height; // textHeight / 3 = vertical space between thumbnail and text - return itemSize; - } - } - /// - /// Draws the background of the control. - /// - /// The System.Drawing.Graphics to draw on. - /// The client coordinates of the item area. - public override void DrawBackground(Graphics g, Rectangle bounds) - { - if (ImageListView.Enabled) - g.Clear(SystemColors.Window); - else - g.Clear(SystemColors.Control); - } - /// - /// Draws the specified item on the given graphics. - /// - /// The System.Drawing.Graphics to draw on. - /// The ImageListViewItem to draw. - /// The current view state of item. - /// The bounding rectangle of item in client coordinates. - public override void DrawItem(System.Drawing.Graphics g, ImageListViewItem item, ItemState state, System.Drawing.Rectangle bounds) - { - // Paint background - if (ImageListView.Enabled || !item.Enabled) - g.FillRectangle(SystemBrushes.Window, bounds); - else - g.FillRectangle(SystemBrushes.Control, bounds); - - if (ImageListView.View != ImageGlass.ImageListView.View.Details) - { - Size itemPadding = new Size(4, 4); - - // Draw the image - Image img = item.GetCachedImage(CachedImageType.Thumbnail); - if (img != null) - { - Rectangle border = new Rectangle(bounds.Location + itemPadding, ImageListView.ThumbnailSize); - Rectangle pos = Utility.GetSizedImageBounds(img, border); - g.DrawImage(img, pos); - - // Draw image border - if (ImageListView.Focused && ((state & ItemState.Selected) != ItemState.None)) - { - using (Pen pen = new Pen(SystemColors.Highlight, 3)) - { - g.DrawRectangle(pen, border); - } - } - else if (!ImageListView.Focused && ((state & ItemState.Selected) != ItemState.None)) - { - using (Pen pen = new Pen(SystemColors.GrayText, 3)) - { - pen.Alignment = PenAlignment.Center; - g.DrawRectangle(pen, border); - } - } - else - { - using (Pen pGray128 = new Pen(Color.FromArgb(128, SystemColors.GrayText))) - { - g.DrawRectangle(pGray128, border); - } - } - } - - // Draw item text - SizeF szt = TextRenderer.MeasureText(g, item.Text, ImageListView.Font); - RectangleF rt; - using (StringFormat sf = new StringFormat()) - { - rt = new RectangleF(bounds.Left + itemPadding.Width, bounds.Top + 3 * itemPadding.Height + ImageListView.ThumbnailSize.Height, ImageListView.ThumbnailSize.Width, szt.Height); - sf.Alignment = StringAlignment.Center; - sf.FormatFlags = StringFormatFlags.NoWrap; - sf.LineAlignment = StringAlignment.Center; - sf.Trimming = StringTrimming.EllipsisCharacter; - rt.Width += 1; - rt.Inflate(1, 2); - if (ImageListView.Focused && ((state & ItemState.Focused) != ItemState.None)) - rt.Inflate(-1, -1); - if (ImageListView.Focused && ((state & ItemState.Selected) != ItemState.None)) - { - g.FillRectangle(SystemBrushes.Highlight, rt); - } - else if (!ImageListView.Focused && ((state & ItemState.Selected) != ItemState.None)) - { - g.FillRectangle(SystemBrushes.GrayText, rt); - } - if ((state & ItemState.Disabled) != ItemState.None) - { - g.DrawString(item.Text, ImageListView.Font, SystemBrushes.GrayText, rt, sf); - } - else if (((state & ItemState.Selected) != ItemState.None)) - { - g.DrawString(item.Text, ImageListView.Font, SystemBrushes.HighlightText, rt, sf); - } - else - { - g.DrawString(item.Text, ImageListView.Font, SystemBrushes.WindowText, rt, sf); - } - } - - if (ImageListView.Focused && ((state & ItemState.Focused) != ItemState.None)) - { - Rectangle fRect = Rectangle.Round(rt); - fRect.Inflate(1, 1); - ControlPaint.DrawFocusRectangle(g, fRect); - } - } - else // if (ImageListView.View == ImageGlass.ImageListView.View.Details) - { - if (ImageListView.Focused && ((state & ItemState.Selected) != ItemState.None)) - { - g.FillRectangle(SystemBrushes.Highlight, bounds); - } - else if (!ImageListView.Focused && ((state & ItemState.Selected) != ItemState.None)) - { - g.FillRectangle(SystemBrushes.GrayText, bounds); - } - - Size offset = new Size(2, (bounds.Height - ImageListView.Font.Height) / 2); - using (StringFormat sf = new StringFormat()) - { - sf.FormatFlags = StringFormatFlags.NoWrap; - sf.Alignment = StringAlignment.Near; - sf.LineAlignment = StringAlignment.Center; - sf.Trimming = StringTrimming.EllipsisCharacter; - // Sub text - List uicolumns = ImageListView.Columns.GetDisplayedColumns(); - RectangleF rt = new RectangleF(bounds.Left + offset.Width, bounds.Top + offset.Height, uicolumns[0].Width - 2 * offset.Width, bounds.Height - 2 * offset.Height); - foreach (ImageListView.ImageListViewColumnHeader column in uicolumns) - { - rt.Width = column.Width - 2 * offset.Width; - int iconOffset = 0; - if (column.Type == ColumnType.Name) - { - // Allocate space for checkbox and file icon - if (ImageListView.ShowCheckBoxes && ImageListView.ShowFileIcons) - iconOffset += 2 * 16 + 3 * 2; - else if (ImageListView.ShowCheckBoxes) - iconOffset += 16 + 2 * 2; - else if (ImageListView.ShowFileIcons) - iconOffset += 16 + 2 * 2; - } - rt.X += iconOffset; - rt.Width -= iconOffset; - - Brush forecolor = SystemBrushes.WindowText; - if ((state & ItemState.Disabled) != ItemState.None) - forecolor = SystemBrushes.GrayText; - else if ((state & ItemState.Selected) != ItemState.None) - forecolor = SystemBrushes.HighlightText; - - if (column.Type == ColumnType.Rating && ImageListView.RatingImage != null && ImageListView.EmptyRatingImage != null) - { - int w = ImageListView.RatingImage.Width; - int y = (int)(rt.Top + (rt.Height - ImageListView.RatingImage.Height) / 2.0f); - int rating = item.StarRating; - if (rating < 0) rating = 0; - if (rating > 5) rating = 5; - for (int i = 1; i <= rating; i++) - g.DrawImage(ImageListView.RatingImage, rt.Left + (i - 1) * w, y); - for (int i = rating + 1; i <= 5; i++) - g.DrawImage(ImageListView.EmptyRatingImage, rt.Left + (i - 1) * w, y); - } - else if (column.Type == ColumnType.Custom) - g.DrawString(item.GetSubItemText(column.Guid), ImageListView.Font, forecolor, rt, sf); - else - g.DrawString(item.GetSubItemText(column.Type), ImageListView.Font, forecolor, rt, sf); - - rt.X -= iconOffset; - rt.X += column.Width; - } - } - - if (ImageListView.Focused && ((state & ItemState.Focused) != ItemState.None)) - ControlPaint.DrawFocusRectangle(g, bounds); - } - } - /// - /// Draws the large preview image of the focused item in Gallery mode. - /// - /// The System.Drawing.Graphics to draw on. - /// The ImageListViewItem to draw. - /// The image to draw. - /// The bounding rectangle of the preview area. - public override void DrawGalleryImage(Graphics g, ImageListViewItem item, Image image, Rectangle bounds) - { - if (item != null && image != null) - { - // Calculate image bounds - Size itemMargin = MeasureItemMargin(ImageListView.View); - Rectangle pos = Utility.GetSizedImageBounds(image, new Rectangle(bounds.Location + itemMargin, bounds.Size - itemMargin - itemMargin)); - // Draw image - g.DrawImage(image, pos); - - // Draw image border - if (Math.Min(pos.Width, pos.Height) > 32) - { - g.DrawRectangle(SystemPens.WindowText, pos); - } - } - } - /// - /// Draws the left pane in Pane view mode. - /// - /// The System.Drawing.Graphics to draw on. - /// The ImageListViewItem to draw. - /// The image to draw. - /// The bounding rectangle of the pane. - public override void DrawPane(Graphics g, ImageListViewItem item, Image image, Rectangle bounds) - { - // Draw pane background - if (ImageListView.Enabled) - g.FillRectangle(SystemBrushes.Window, bounds); - else - g.FillRectangle(SystemBrushes.Control, bounds); - - using (Brush bBorder = new SolidBrush(Color.FromArgb(128, SystemColors.GrayText))) - { - g.FillRectangle(bBorder, bounds.Right - 2, bounds.Top, 2, bounds.Height); - } - bounds.Width -= 2; - - if (item != null && image != null) - { - // Calculate image bounds - Size itemMargin = MeasureItemMargin(ImageListView.View); - Rectangle pos = Utility.GetSizedImageBounds(image, new Rectangle(bounds.Location + itemMargin, bounds.Size - itemMargin - itemMargin), 50.0f, 0.0f); - // Draw image - g.DrawImage(image, pos); - // Draw image border - if (Math.Min(pos.Width, pos.Height) > 32) - { - using (Pen pBorder = new Pen(SystemColors.WindowText)) - { - g.DrawRectangle(pBorder, pos); - } - } - bounds.X += itemMargin.Width; - bounds.Width -= 2 * itemMargin.Width; - bounds.Y = pos.Height + 16; - bounds.Height -= pos.Height + 16; - - // Item text - if (ImageListView.Columns.HasType(ColumnType.Name) && ImageListView.Columns[ColumnType.Name].Visible && bounds.Height > 0) - { - string text = item.GetSubItemText(ColumnType.Name); - int y = Utility.DrawStringPair(g, bounds, "", text, ImageListView.Font, SystemBrushes.GrayText, SystemBrushes.WindowText); - bounds.Y += 2 * y; - bounds.Height -= 2 * y; - } - - // File type - string fileType = item.GetSubItemText(ColumnType.FileType); - if (ImageListView.Columns.HasType(ColumnType.FileType) && ImageListView.Columns[ColumnType.FileType].Visible && bounds.Height > 0 && !string.IsNullOrEmpty(fileType)) - { - int y = Utility.DrawStringPair(g, bounds, ImageListView.Columns[ColumnType.FileType].Text + ": ", - fileType, ImageListView.Font, SystemBrushes.GrayText, SystemBrushes.WindowText); - bounds.Y += y; - bounds.Height -= y; - } - - // Metatada - foreach (ImageListView.ImageListViewColumnHeader column in ImageListView.Columns) - { - if (column.Type == ColumnType.ImageDescription) - { - bounds.Y += 8; - bounds.Height -= 8; - } - - if (bounds.Height <= 0) break; - - if (column.Visible && - column.Type != ColumnType.Custom && - column.Type != ColumnType.FileType && - column.Type != ColumnType.DateAccessed && - column.Type != ColumnType.FileName && - column.Type != ColumnType.FilePath && - column.Type != ColumnType.Name) - { - string caption = column.Text; - string text = item.GetSubItemText(column.Type); - if (!string.IsNullOrEmpty(text)) - { - int y = Utility.DrawStringPair(g, bounds, caption + ": ", text, - ImageListView.Font, SystemBrushes.GrayText, SystemBrushes.WindowText); - bounds.Y += y; - bounds.Height -= y; - } - } - } - } - } - /// - /// Draws the column headers. - /// - /// The System.Drawing.Graphics to draw on. - /// The ImageListViewColumnHeader to draw. - /// The current view state of column. - /// The bounding rectangle of column in client coordinates. - public override void DrawColumnHeader(Graphics g, ImageListView.ImageListViewColumnHeader column, ColumnState state, Rectangle bounds) - { - // Paint background - if (ImageListView.Focused && ((state & ColumnState.Hovered) == ColumnState.Hovered)) - { - using (Brush bHovered = new LinearGradientBrush(bounds, Color.FromArgb(16, SystemColors.Highlight), Color.FromArgb(64, SystemColors.Highlight), LinearGradientMode.Vertical)) - { - g.FillRectangle(bHovered, bounds); - } - } - else - { - using (Brush bNormal = new LinearGradientBrush(bounds, Color.FromArgb(32, SystemColors.Control), Color.FromArgb(196, SystemColors.Control), LinearGradientMode.Vertical)) - { - g.FillRectangle(bNormal, bounds); - } - } - using (Brush bBorder = new LinearGradientBrush(bounds, Color.FromArgb(196, SystemColors.Control), Color.FromArgb(32, SystemColors.Control), LinearGradientMode.Vertical)) - using (Pen pBorder = new Pen(bBorder)) - { - g.DrawLine(pBorder, bounds.Left, bounds.Top, bounds.Left, bounds.Bottom); - g.DrawLine(pBorder, bounds.Left, bounds.Bottom - 1, bounds.Right, bounds.Bottom - 1); - } - using (Pen pSpep = new Pen(Color.FromArgb(32, SystemColors.Control))) - { - g.DrawLine(pSpep, bounds.Left + 1, bounds.Top + 1, bounds.Left + 1, bounds.Bottom - 2); - g.DrawLine(pSpep, bounds.Right - 1, bounds.Top + 1, bounds.Right - 1, bounds.Bottom - 2); - } - - // Draw the sort arrow - int textOffset = 4; - if (ImageListView.SortOrder != SortOrder.None && ((state & ColumnState.SortColumn) != ColumnState.None)) - { - Image img = null; - if (ImageListView.SortOrder == SortOrder.Ascending || ImageListView.SortOrder == SortOrder.AscendingNatural) - img = ImageListViewResources.SortAscending; - else if (ImageListView.SortOrder == SortOrder.Descending || ImageListView.SortOrder == SortOrder.DescendingNatural) - img = ImageListViewResources.SortDescending; - if (img != null) - { - g.DrawImageUnscaled(img, bounds.X + 4, bounds.Top + (bounds.Height - img.Height) / 2); - textOffset += img.Width; - } - } - - // Text - bounds.X += textOffset; - bounds.Width -= textOffset; - if (bounds.Width > 4) - { - using (StringFormat sf = new StringFormat()) - { - sf.FormatFlags = StringFormatFlags.NoWrap; - sf.Alignment = StringAlignment.Near; - sf.LineAlignment = StringAlignment.Center; - sf.Trimming = StringTrimming.EllipsisCharacter; - g.DrawString(column.Text, (ImageListView.ColumnHeaderFont == null ? ImageListView.Font : ImageListView.ColumnHeaderFont), - SystemBrushes.WindowText, bounds, sf); - } - } - } - /// - /// Draws the extender after the last column. - /// - /// The System.Drawing.Graphics to draw on. - /// The bounding rectangle of extender column in client coordinates. - public override void DrawColumnExtender(Graphics g, Rectangle bounds) - { - // Paint background - using (Brush bBack = new LinearGradientBrush(bounds, Color.FromArgb(32, SystemColors.Control), Color.FromArgb(196, SystemColors.Control), LinearGradientMode.Vertical)) - { - g.FillRectangle(bBack, bounds); - } - using (Brush bBorder = new LinearGradientBrush(bounds, Color.FromArgb(196, SystemColors.Control), Color.FromArgb(32, SystemColors.Control), LinearGradientMode.Vertical)) - using (Pen pBorder = new Pen(bBorder)) - { - g.DrawLine(pBorder, bounds.Left, bounds.Top, bounds.Left, bounds.Bottom); - g.DrawLine(pBorder, bounds.Left, bounds.Bottom - 1, bounds.Right, bounds.Bottom - 1); - } - using (Pen pSpep = new Pen(Color.FromArgb(32, SystemColors.Control))) - { - g.DrawLine(pSpep, bounds.Left + 1, bounds.Top + 1, bounds.Left + 1, bounds.Bottom - 2); - } - } - /// - /// Draws the selection rectangle. - /// - /// The System.Drawing.Graphics to draw on. - /// The client coordinates of the selection rectangle. - public override void DrawSelectionRectangle(Graphics g, Rectangle selection) - { - using (SolidBrush brush = new SolidBrush(Color.FromArgb(128, SystemColors.Highlight))) - using (Pen pen = new Pen(SystemColors.Highlight)) - { - g.FillRectangle(brush, selection); - g.DrawRectangle(pen, selection); - } - } - /// - /// Draws the insertion caret for drag and drop operations. - /// - /// The System.Drawing.Graphics to draw on. - /// The bounding rectangle of the insertion caret. - public override void DrawInsertionCaret(Graphics g, Rectangle bounds) - { - g.FillRectangle(SystemBrushes.Highlight, bounds); - } - /// - /// Draws the group headers. - /// - /// The System.Drawing.Graphics to draw on. - /// The name of the group to draw. - /// The bounding rectangle of group in client coordinates. - public override void DrawGroupHeader(Graphics g, string name, Rectangle bounds) - { - // Bottom border - bounds.Inflate(0, -4); - using (Pen pSpep = new Pen(Color.FromArgb(128, SystemColors.GrayText))) - { - g.DrawLine(pSpep, bounds.Left + 1, bounds.Bottom - 1, bounds.Right - 1, bounds.Bottom - 1); - } - - // Text - if (bounds.Width > 4) - { - using (StringFormat sf = new StringFormat()) - { - sf.FormatFlags = StringFormatFlags.NoWrap; - sf.Alignment = StringAlignment.Near; - sf.LineAlignment = StringAlignment.Center; - sf.Trimming = StringTrimming.EllipsisCharacter; - g.DrawString(name, (ImageListView.GroupHeaderFont == null ? ImageListView.Font : ImageListView.GroupHeaderFont), - SystemBrushes.WindowText, bounds, sf); - } - } - } - } - #endregion - - #region ZoomingRenderer - /// - /// Zooms items on mouse over. - /// - public class ZoomingRenderer : ImageListView.ImageListViewRenderer - { - private float mZoomRatio; - - /// - /// Gets or sets the relative zoom ratio. - /// - public float ZoomRatio - { - get - { - return mZoomRatio; - } - set - { - mZoomRatio = value; - if (mZoomRatio < 0.0f) mZoomRatio = 0.0f; - } - } - - /// - /// Initializes a new instance of the ZoomingRenderer class. - /// - public ZoomingRenderer() - : this(0.5f) - { - ; - } - - /// - /// Initializes a new instance of the ZoomingRenderer class. - /// - /// Relative zoom ratio. - public ZoomingRenderer(float zoomRatio) - { - if (zoomRatio < 0.0f) zoomRatio = 0.0f; - mZoomRatio = zoomRatio; - } - - /// - /// Initializes the System.Drawing.Graphics used to draw - /// control elements. - /// - /// The System.Drawing.Graphics to draw on. - public override void InitializeGraphics(System.Drawing.Graphics g) - { - base.InitializeGraphics(g); - - ItemDrawOrder = ItemDrawOrder.NormalSelectedHovered; - } - /// - /// Returns item size for the given view mode. - /// - /// The view mode for which the item measurement should be made. - /// The item size. - public override Size MeasureItem(ImageGlass.ImageListView.View view) - { - if (view == ImageGlass.ImageListView.View.Thumbnails) - return ImageListView.ThumbnailSize + new Size(8, 8); - else - return base.MeasureItem(view); - } - /// - /// Draws the specified item on the given graphics. - /// - /// The System.Drawing.Graphics to draw on. - /// The ImageListViewItem to draw. - /// The current view state of item. - /// The bounding rectangle of item in client coordinates. - public override void DrawItem(Graphics g, ImageListViewItem item, ItemState state, Rectangle bounds) - { - Clip = (ImageListView.View == ImageGlass.ImageListView.View.Details); - - if (ImageListView.View != ImageGlass.ImageListView.View.Details) - { - Rectangle controlBounds = ClientBounds; - - // Zoom on mouse over - if ((state & ItemState.Hovered) != ItemState.None) - { - bounds.Inflate((int)(bounds.Width * mZoomRatio), (int)(bounds.Height * mZoomRatio)); - if (bounds.Bottom > controlBounds.Bottom) - bounds.Y = controlBounds.Bottom - bounds.Height; - if (bounds.Top < controlBounds.Top) - bounds.Y = controlBounds.Top; - if (bounds.Right > controlBounds.Right) - bounds.X = controlBounds.Right - bounds.Width; - if (bounds.Left < controlBounds.Left) - bounds.X = controlBounds.Left; - } - - // Get item image - Image img = null; - if ((state & ItemState.Hovered) != ItemState.None) - img = GetImageAsync(item, new Size(bounds.Width - 8, bounds.Height - 8)); - if (img == null) img = item.GetCachedImage(CachedImageType.Thumbnail); - - int imageWidth = 0; - int imageHeight = 0; - if (img != null) - { - // Calculate image bounds - Rectangle pos = Utility.GetSizedImageBounds(img, Rectangle.Inflate(bounds, -4, -4)); - imageWidth = pos.Width; - imageHeight = pos.Height; - int imageX = pos.X; - int imageY = pos.Y; - - // Allocate space for item text - if ((state & ItemState.Hovered) != ItemState.None && - (bounds.Height - imageHeight) / 2 < ImageListView.Font.Height + 8) - { - int delta = (ImageListView.Font.Height + 8) - (bounds.Height - imageHeight) / 2; - bounds.Height += 2 * delta; - imageY += delta; - - delta = 0; - if (bounds.Bottom > controlBounds.Bottom) - delta = bounds.Y - (controlBounds.Bottom - bounds.Height); - if (bounds.Top < controlBounds.Top) - delta = bounds.Y - controlBounds.Top; - - bounds.Y -= delta; - imageY -= delta; - } - - // Paint background - if (ImageListView.Enabled) - { - using (Brush bItemBack = new SolidBrush(ImageListView.Colors.BackColor)) - { - g.FillRectangle(bItemBack, bounds); - } - } - else - { - using (Brush bItemBack = new SolidBrush(ImageListView.Colors.DisabledBackColor)) - { - g.FillRectangle(bItemBack, bounds); - } - } - - if ((state & ItemState.Disabled) != ItemState.None) - { - using (Brush bDisabled = new LinearGradientBrush(bounds, ImageListView.Colors.DisabledColor1, ImageListView.Colors.DisabledColor2, LinearGradientMode.Vertical)) - { - Utility.FillRoundedRectangle(g, bDisabled, bounds, 5); - } - } - else if ((ImageListView.Focused && ((state & ItemState.Selected) != ItemState.None)) || - (!ImageListView.Focused && ((state & ItemState.Selected) != ItemState.None) && ((state & ItemState.Hovered) != ItemState.None))) - { - using (Brush bSelected = new LinearGradientBrush(bounds, ImageListView.Colors.SelectedColor1, ImageListView.Colors.SelectedColor2, LinearGradientMode.Vertical)) - { - Utility.FillRoundedRectangle(g, bSelected, bounds, 5); - } - } - else if (!ImageListView.Focused && ((state & ItemState.Selected) != ItemState.None)) - { - using (Brush bGray64 = new LinearGradientBrush(bounds, ImageListView.Colors.UnFocusedColor1, ImageListView.Colors.UnFocusedColor2, LinearGradientMode.Vertical)) - { - Utility.FillRoundedRectangle(g, bGray64, bounds, 5); - } - } - if (((state & ItemState.Hovered) != ItemState.None)) - { - using (Brush bHovered = new LinearGradientBrush(bounds, ImageListView.Colors.HoverColor1, ImageListView.Colors.HoverColor2, LinearGradientMode.Vertical)) - { - Utility.FillRoundedRectangle(g, bHovered, bounds, 5); - } - } - - // Draw the image - g.DrawImage(img, imageX, imageY, imageWidth, imageHeight); - - // Draw image border - if (Math.Min(imageWidth, imageHeight) > 32) - { - using (Pen pOuterBorder = new Pen(ImageListView.Colors.ImageOuterBorderColor)) - { - g.DrawRectangle(pOuterBorder, imageX, imageY, imageWidth, imageHeight); - } - if (System.Math.Min(imageWidth, imageHeight) > 32) - { - using (Pen pInnerBorder = new Pen(ImageListView.Colors.ImageInnerBorderColor)) - { - g.DrawRectangle(pInnerBorder, imageX + 1, imageY + 1, imageWidth - 2, imageHeight - 2); - } - } - } - } - else - { - // Paint background - if (ImageListView.Enabled) - { - using (Brush bItemBack = new SolidBrush(ImageListView.Colors.BackColor)) - { - g.FillRectangle(bItemBack, bounds); - } - } - else - { - using (Brush bItemBack = new SolidBrush(ImageListView.Colors.DisabledBackColor)) - { - g.FillRectangle(bItemBack, bounds); - } - } - } - - // Draw item text - if ((state & ItemState.Hovered) != ItemState.None) - { - RectangleF rt; - using (StringFormat sf = new StringFormat()) - { - rt = new RectangleF(bounds.Left + 4, bounds.Top + 4, bounds.Width - 8, (bounds.Height - imageHeight) / 2 - 8); - sf.Alignment = StringAlignment.Center; - sf.FormatFlags = StringFormatFlags.NoWrap; - sf.LineAlignment = StringAlignment.Center; - sf.Trimming = StringTrimming.EllipsisCharacter; - using (Brush bItemFore = new SolidBrush(ImageListView.Colors.ForeColor)) - { - g.DrawString(item.Text, ImageListView.Font, bItemFore, rt, sf); - } - rt.Y = bounds.Bottom - (bounds.Height - imageHeight) / 2 + 4; - string details = ""; - string dimensions = item.GetSubItemText(ColumnType.Dimensions); - if (!string.IsNullOrEmpty(dimensions)) - details += dimensions + " pixels "; - string fileSize = item.GetSubItemText(ColumnType.FileSize); - if (!string.IsNullOrEmpty(fileSize)) - details += item.GetSubItemText(ColumnType.FileSize); - using (Brush bGrayText = new SolidBrush(ImageListView.Colors.PaneLabelColor)) - { - g.DrawString(details, ImageListView.Font, bGrayText, rt, sf); - } - } - } - - // Item border - using (Pen pWhite128 = new Pen(Color.FromArgb(128, ImageListView.Colors.ControlBackColor))) - { - Utility.DrawRoundedRectangle(g, pWhite128, bounds.Left + 1, bounds.Top + 1, bounds.Width - 3, bounds.Height - 3, 4); - } - if (((state & ItemState.Disabled) != ItemState.None)) - { - using (Pen pHighlight128 = new Pen(ImageListView.Colors.DisabledBorderColor)) - { - Utility.DrawRoundedRectangle(g, pHighlight128, bounds.Left, bounds.Top, bounds.Width - 1, bounds.Height - 1, 4); - } - } - else if (ImageListView.Focused && ((state & ItemState.Selected) != ItemState.None)) - { - using (Pen pHighlight128 = new Pen(ImageListView.Colors.SelectedBorderColor)) - { - Utility.DrawRoundedRectangle(g, pHighlight128, bounds.Left, bounds.Top, bounds.Width - 1, bounds.Height - 1, 4); - } - } - else if (!ImageListView.Focused && ((state & ItemState.Selected) != ItemState.None)) - { - using (Pen pGray128 = new Pen(ImageListView.Colors.UnFocusedBorderColor)) - { - Utility.DrawRoundedRectangle(g, pGray128, bounds.Left, bounds.Top, bounds.Width - 1, bounds.Height - 1, 4); - } - } - else if ((state & ItemState.Selected) == ItemState.None) - { - using (Pen pGray64 = new Pen(ImageListView.Colors.BorderColor)) - { - Utility.DrawRoundedRectangle(g, pGray64, bounds.Left, bounds.Top, bounds.Width - 1, bounds.Height - 1, 4); - } - } - - if (ImageListView.Focused && ((state & ItemState.Hovered) != ItemState.None)) - { - using (Pen pHighlight64 = new Pen(ImageListView.Colors.HoverBorderColor)) - { - Utility.DrawRoundedRectangle(g, pHighlight64, bounds.Left, bounds.Top, bounds.Width - 1, bounds.Height - 1, 4); - } - } - } - else - base.DrawItem(g, item, state, bounds); - } - /// - /// Draws the checkbox icon for the specified item on the given graphics. - /// - /// The System.Drawing.Graphics to draw on. - /// The ImageListViewItem to draw. - /// The bounding rectangle of the checkbox in client coordinates. - public override void DrawCheckBox(Graphics g, ImageListViewItem item, Rectangle bounds) - { - if (ImageListView.View == View.Details) - base.DrawCheckBox(g, item, bounds); - } - /// - /// Draws the file icon for the specified item on the given graphics. - /// - /// The System.Drawing.Graphics to draw on. - /// The ImageListViewItem to draw. - /// The bounding rectangle of the file icon in client coordinates. - public override void DrawFileIcon(Graphics g, ImageListViewItem item, Rectangle bounds) - { - if (ImageListView.View == View.Details) - base.DrawFileIcon(g, item, bounds); - } - } - #endregion - - #region ThemeRenderer - /// - /// Displays the control in the current system theme. - /// This renderer cannot be themed. - /// - public class ThemeRenderer : ImageListView.ImageListViewRenderer - { - // Check boxes - private VisualStyleRenderer rCheckedNormal = null; - private VisualStyleRenderer rUncheckedNormal = null; - private VisualStyleRenderer rCheckedDisabled = null; - private VisualStyleRenderer rUncheckedDisabled = null; - // File icons - private VisualStyleRenderer rFileIcon = null; - // Column headers - private VisualStyleRenderer rColumnNormal = null; - private VisualStyleRenderer rColumnHovered = null; - private VisualStyleRenderer rColumnSorted = null; - private VisualStyleRenderer rColumnSortedHovered = null; - private VisualStyleRenderer rSortAscending = null; - private VisualStyleRenderer rSortDescending = null; - // Items - private VisualStyleRenderer rItemNormal = null; - private VisualStyleRenderer rItemHovered = null; - private VisualStyleRenderer rItemSelected = null; - private VisualStyleRenderer rItemHoveredSelected = null; - private VisualStyleRenderer rItemSelectedHidden = null; - private VisualStyleRenderer rItemDisabled = null; - // Group headers - private VisualStyleRenderer rGroupNormal = null; - private VisualStyleRenderer rGroupLine = null; - - /// - /// Gets whether visual styles are supported. - /// - public bool VisualStylesEnabled { get; private set; } - - /// - /// Gets a value indicating whether this renderer can apply custom colors. - /// - /// - public override bool CanApplyColors { get { return false; } } - - /// - /// Initializes a new instance of the ThemeRenderer class. - /// - public ThemeRenderer() - { - VisualStylesEnabled = Application.RenderWithVisualStyles; - - // Create renderers - if (VisualStylesEnabled) - { - // See http://msdn.microsoft.com/en-us/library/bb773210(VS.85).aspx - // for part and state codes used below. - - // Check boxes - rCheckedNormal = GetRenderer(VisualStyleElement.Button.CheckBox.CheckedNormal); - rUncheckedNormal = GetRenderer(VisualStyleElement.Button.CheckBox.UncheckedNormal); - rCheckedDisabled = GetRenderer(VisualStyleElement.Button.CheckBox.CheckedDisabled); - rUncheckedDisabled = GetRenderer(VisualStyleElement.Button.CheckBox.UncheckedDisabled); - // File icons - rFileIcon = GetRenderer(VisualStyleElement.Button.PushButton.Normal); - // Column headers - rColumnNormal = GetRenderer("Header", 1, 1); - rColumnHovered = GetRenderer("Header", 1, 2); - rColumnSorted = GetRenderer("Header", 1, 4); - rColumnSortedHovered = GetRenderer("Header", 1, 5); - rSortAscending = GetRenderer(VisualStyleElement.Header.SortArrow.SortedUp); - rSortDescending = GetRenderer(VisualStyleElement.Header.SortArrow.SortedDown); - // Items - rItemNormal = GetRenderer("Explorer::ListView", 1, 1); - rItemHovered = GetRenderer("Explorer::ListView", 1, 2); - rItemSelected = GetRenderer("Explorer::ListView", 1, 3); - rItemHoveredSelected = GetRenderer("Explorer::ListView", 1, 6); - rItemSelectedHidden = GetRenderer("Explorer::ListView", 1, 5); - rItemDisabled = GetRenderer("Explorer::ListView", 1, 4); - // Groups - rGroupNormal = GetRenderer("Explorer::ListView", 6, 1); - rGroupLine = GetRenderer("Explorer::ListView", 7, 1); - } - } - - /// - /// Returns a renderer for the given element. - /// - private VisualStyleRenderer GetRenderer(VisualStyleElement e) - { - if (VisualStyleRenderer.IsElementDefined(e)) - return new VisualStyleRenderer(e); - else - return null; - } - - /// - /// Returns a renderer for the given element. - /// - private VisualStyleRenderer GetRenderer(string className, int part, int state) - { - VisualStyleElement e = VisualStyleElement.CreateElement(className, part, state); - if (VisualStyleRenderer.IsElementDefined(e)) - return new VisualStyleRenderer(e); - else - return null; - } - - /// - /// Draws the checkbox icon for the specified item on the given graphics. - /// - /// The System.Drawing.Graphics to draw on. - /// The ImageListViewItem to draw. - /// The bounding rectangle of the checkbox in client coordinates. - public override void DrawCheckBox(Graphics g, ImageListViewItem item, Rectangle bounds) - { - VisualStyleRenderer renderer; - if (item.Enabled) - { - if (item.Checked) - renderer = rCheckedNormal; - else - renderer = rUncheckedNormal; - } - else - { - if (item.Checked) - renderer = rCheckedDisabled; - else - renderer = rUncheckedDisabled; - } - - if (VisualStylesEnabled && renderer != null) - renderer.DrawBackground(g, bounds, bounds); - else - base.DrawCheckBox(g, item, bounds); - } - - /// - /// Draws the file icon for the specified item on the given graphics. - /// - /// The System.Drawing.Graphics to draw on. - /// The ImageListViewItem to draw. - /// The bounding rectangle of the file icon in client coordinates. - public override void DrawFileIcon(Graphics g, ImageListViewItem item, Rectangle bounds) - { - Image icon = item.GetCachedImage(CachedImageType.SmallIcon); - - if (icon != null && VisualStylesEnabled && rFileIcon != null) - rFileIcon.DrawImage(g, bounds, icon); - else - base.DrawFileIcon(g, item, bounds); - } - - /// - /// Draws the column headers. - /// - /// The System.Drawing.Graphics to draw on. - /// The ImageListViewColumnHeader to draw. - /// The current view state of column. - /// The bounding rectangle of column in client coordinates. - public override void DrawColumnHeader(Graphics g, ImageListView.ImageListViewColumnHeader column, ColumnState state, Rectangle bounds) - { - SortOrder order = SortOrder.None; - if (ImageListView.SortOrder != SortOrder.None && - ((state & ColumnState.SortColumn) != ColumnState.None)) - order = ImageListView.SortOrder; - - VisualStyleRenderer rBack; - if (((state & ColumnState.Hovered) == ColumnState.Hovered) && order != SortOrder.None) - rBack = rColumnSortedHovered; - else if (((state & ColumnState.Hovered) == ColumnState.Hovered) && order == SortOrder.None) - rBack = rColumnHovered; - else if (((state & ColumnState.Hovered) == ColumnState.None) && order != SortOrder.None) - rBack = rColumnSorted; - else - rBack = rColumnNormal; - - VisualStyleRenderer rSort; - if (order == SortOrder.Ascending || order == SortOrder.AscendingNatural) - rSort = rSortAscending; - else - rSort = rSortDescending; - - // Background - if (VisualStylesEnabled && rBack != null && rSort != null) - { - // Background - rBack.DrawBackground(g, bounds, bounds); - // Sort arrow - if (order != SortOrder.None) - { - Size sz = rSort.GetPartSize(g, System.Windows.Forms.VisualStyles.ThemeSizeType.True); - Rectangle sortBounds = new Rectangle(new Point(0, 0), sz); - sortBounds.Offset(bounds.X + (bounds.Width - sz.Width) / 2, 0); - rSort.DrawBackground(g, sortBounds, sortBounds); - } - - // Text - if (bounds.Width > 4) - { - Rectangle textBounds = bounds; - textBounds.Inflate(-3, 0); - TextRenderer.DrawText(g, column.Text, - SystemFonts.MenuFont, textBounds, SystemColors.ControlText, - TextFormatFlags.EndEllipsis | TextFormatFlags.VerticalCenter | TextFormatFlags.SingleLine | TextFormatFlags.PreserveGraphicsClipping); - } - } - else - base.DrawColumnHeader(g, column, state, bounds); - } - - /// - /// Draws the extender after the last column. - /// - /// The System.Drawing.Graphics to draw on. - /// The bounding rectangle of extender column in client coordinates. - public override void DrawColumnExtender(Graphics g, Rectangle bounds) - { - if (VisualStylesEnabled && rColumnNormal != null) - rColumnNormal.DrawBackground(g, bounds, bounds); - else - base.DrawColumnExtender(g, bounds); - } - - /// - /// [PHAP] Returns item size for the given view mode. - /// - /// The view mode for which the measurement should be made. - /// The item size. - public override Size MeasureItem(View view) - { - Size sz = base.MeasureItem(view); - if (VisualStylesEnabled && view != View.Details) - { - //sz.Width += 6; - //sz.Height += 6; - int textHeight = ImageListView.Font.Height; - - sz.Width += textHeight * 2 / 5; - sz.Height -= textHeight / 2; - } - return sz; - } - - /// - /// [PHAP] Draws the specified item on the given graphics. - /// - /// The System.Drawing.Graphics to draw on. - /// The ImageListViewItem to draw. - /// The current view state of item. - /// The bounding rectangle of item in client coordinates. - public override void DrawItem(Graphics g, ImageListViewItem item, ItemState state, Rectangle bounds) - { - VisualStyleRenderer rBack; - - if (!ImageListView.Enabled) - rBack = rItemSelectedHidden; - if (((state & ItemState.Disabled) != ItemState.None)) - rBack = rItemDisabled; - else if (!ImageListView.Focused && ((state & ItemState.Selected) != ItemState.None)) - rBack = rItemSelectedHidden; - else if (((state & ItemState.Selected) != ItemState.None) && ((state & ItemState.Hovered) != ItemState.None)) - rBack = rItemHoveredSelected; - else if ((state & ItemState.Selected) != ItemState.None) - rBack = rItemSelected; - else if ((state & ItemState.Hovered) != ItemState.None) - rBack = rItemHovered; - else - rBack = rItemNormal; - - if (VisualStylesEnabled && rBack != null) - { - // Do not draw the background of normal items - if (((state & ItemState.Hovered) != ItemState.None) || ((state & ItemState.Selected) != ItemState.None)) - rBack.DrawBackground(g, bounds, bounds); - - // Size itemPadding = new Size(7, 7); - Size itemPadding = new Size(5, 5); - - // Draw the image - if (ImageListView.View != View.Details) - { - Image img = item.GetCachedImage(CachedImageType.Thumbnail); - if (img != null) - { - //Rectangle pos = Utility.GetSizedImageBounds(img, new Rectangle(bounds.Location + itemPadding, ImageListView.ThumbnailSize)); - - Rectangle pos = Utility.GetSizedImageBounds(img, - new Rectangle(bounds.Location + itemPadding, - new Size(bounds.Width - 2 * itemPadding.Width, bounds.Height - 2 * itemPadding.Width))); - - // Image background - Rectangle imgback = pos; - imgback.Inflate(3, 3); - - //Fill background - //g.FillRectangle(SystemBrushes.Window, imgback); - - // Image border - //if (img.Width > 32 && img.Height > 32) - //{ - // using (Pen pen = new Pen(Color.FromArgb(224, 224, 244), 2)) - // { - // g.DrawRectangle(pen, imgback.X, imgback.Y, imgback.Width, imgback.Height); - // } - //} - - // Image - g.DrawImage(img, pos); - } - - // Draw item text - //Color foreColor = SystemColors.ControlText; - //if ((state & ItemState.Disabled) != ItemState.None) - // foreColor = SystemColors.GrayText; - //Size szt = TextRenderer.MeasureText(item.Text, ImageListView.Font); - //Rectangle rt = new Rectangle( - // bounds.Left + itemPadding.Width, bounds.Top + 2 * itemPadding.Height + ImageListView.ThumbnailSize.Height, - // ImageListView.ThumbnailSize.Width, szt.Height); - //TextRenderer.DrawText(g, item.Text, ImageListView.Font, rt, foreColor, - // TextFormatFlags.EndEllipsis | TextFormatFlags.HorizontalCenter | TextFormatFlags.VerticalCenter | TextFormatFlags.SingleLine | TextFormatFlags.PreserveGraphicsClipping); - } - else // if (ImageListView.View == View.Details) - { - List uicolumns = ImageListView.Columns.GetDisplayedColumns(); - - // Separators - int x = bounds.Left - 2; - foreach (ImageListView.ImageListViewColumnHeader column in uicolumns) - { - x += column.Width; - if (!ReferenceEquals(column, uicolumns[uicolumns.Count - 1])) - { - using (Pen pGray32 = new Pen(Color.FromArgb(32, 128, 128, 128))) - { - g.DrawLine(pGray32, x, bounds.Top, x, bounds.Bottom); - } - } - } - Size offset = new Size(2, (bounds.Height - ImageListView.Font.Height) / 2); - // Sub text - int firstWidth = 0; - if (uicolumns.Count > 0) - firstWidth = uicolumns[0].Width; - Rectangle rt = new Rectangle(bounds.Left + offset.Width, bounds.Top + offset.Height, firstWidth - 2 * offset.Width, bounds.Height - 2 * offset.Height); - Color foreColor = SystemColors.ControlText; - if ((state & ItemState.Disabled) != ItemState.None) - foreColor = SystemColors.GrayText; - foreach (ImageListView.ImageListViewColumnHeader column in uicolumns) - { - rt.Width = column.Width - 2 * offset.Width; - using (Brush bItemFore = new SolidBrush(SystemColors.ControlText)) - { - int iconOffset = 0; - if (column.Type == ColumnType.Name) - { - // Allocate space for checkbox and file icon - if (ImageListView.ShowCheckBoxes && ImageListView.ShowFileIcons) - iconOffset += 2 * 16 + 3 * 2; - else if (ImageListView.ShowCheckBoxes) - iconOffset += 16 + 2 * 2; - else if (ImageListView.ShowFileIcons) - iconOffset += 16 + 2 * 2; - } - rt.X += iconOffset; - rt.Width -= iconOffset; - // Rating stars - if (column.Type == ColumnType.Rating && ImageListView.RatingImage != null && ImageListView.EmptyRatingImage != null) - { - int rating = item.GetSimpleRating(); - if (rating > 0) - { - int w = ImageListView.RatingImage.Width; - int y = (int)(rt.Top + (rt.Height - ImageListView.RatingImage.Height) / 2.0f); - - for (int i = 1; i <= 5; i++) - { - if (rating >= i) - g.DrawImage(ImageListView.RatingImage, rt.Left + (i - 1) * w, y); - else - g.DrawImage(ImageListView.EmptyRatingImage, rt.Left + (i - 1) * w, y); - } - } - } - else if (column.Type == ColumnType.Custom) - TextRenderer.DrawText(g, item.GetSubItemText(column.Guid), ImageListView.Font, rt, foreColor, - TextFormatFlags.EndEllipsis | TextFormatFlags.VerticalCenter | TextFormatFlags.SingleLine | TextFormatFlags.PreserveGraphicsClipping); - else - TextRenderer.DrawText(g, item.GetSubItemText(column.Type), ImageListView.Font, rt, foreColor, - TextFormatFlags.EndEllipsis | TextFormatFlags.VerticalCenter | TextFormatFlags.SingleLine | TextFormatFlags.PreserveGraphicsClipping); - - rt.X -= iconOffset; - } - rt.X += column.Width; - } - } - - // Focus rectangle - if (ImageListView.Focused && ((state & ItemState.Focused) != ItemState.None)) - { - Rectangle focusBounds = bounds; - focusBounds.Inflate(-2, -2); - ControlPaint.DrawFocusRectangle(g, focusBounds); - } - - } - else - base.DrawItem(g, item, state, bounds); - } - /// - /// Draws the group headers. - /// - /// The System.Drawing.Graphics to draw on. - /// The name of the group to draw. - /// The bounding rectangle of group in client coordinates. - public override void DrawGroupHeader(Graphics g, string name, Rectangle bounds) - { - if (VisualStylesEnabled && rGroupNormal != null && rGroupLine != null) - { - bounds.Inflate(-3, 0); - - // Background - rGroupNormal.DrawBackground(g, bounds, bounds); - - // Text - TextRenderer.DrawText(g, name, - SystemFonts.MenuFont, bounds, SystemColors.ControlText, - TextFormatFlags.EndEllipsis | TextFormatFlags.VerticalCenter | TextFormatFlags.SingleLine | TextFormatFlags.PreserveGraphicsClipping); - - // Border - Rectangle lineBounds = new Rectangle(bounds.Left, bounds.Bottom - 1, bounds.Width, 1); - rGroupLine.DrawBackground(g, lineBounds, lineBounds); - } - else - base.DrawGroupHeader(g, name, bounds); - } - } - #endregion - - #region MeerkatRenderer - /// - /// A renderer to celebrate the release of Ubuntu 10.10 Maverick Meerkat. - /// - public class MeerkatRenderer : ImageListView.ImageListViewRenderer - { - /// - /// Gets a list of color themes preferred by this renderer. - /// - /// - public override ImageListViewColor[] PreferredColors - { - get { return new ImageListViewColor[] { ImageListViewColor.Mandarin }; } - } - - /// - /// Initializes the System.Drawing.Graphics used to draw - /// control elements. - /// - /// The System.Drawing.Graphics to draw on. - public override void InitializeGraphics(Graphics g) - { - g.CompositingQuality = CompositingQuality.HighQuality; - g.SmoothingMode = SmoothingMode.HighQuality; - g.InterpolationMode = InterpolationMode.HighQualityBicubic; - } - /// - /// Returns item size for the given view mode. - /// - /// The view mode for which the measurement should be made. - /// The item size. - public override Size MeasureItem(View view) - { - if (view == View.Details) - return base.MeasureItem(view); - else - { - // Reference text height - int textHeight = ImageListView.Font.Height; - - Size itemSize = new Size(); - - itemSize.Height = ImageListView.ThumbnailSize.Height + textHeight + 4 * 3; - itemSize.Width = ImageListView.ThumbnailSize.Width + 2 * 3; - - return itemSize; - } - } - /// - /// Draws the column headers. - /// - /// The System.Drawing.Graphics to draw on. - /// The ImageListViewColumnHeader to draw. - /// The current view state of column. - /// The bounding rectangle of column in client coordinates. - public override void DrawColumnHeader(Graphics g, ImageListView.ImageListViewColumnHeader column, ColumnState state, Rectangle bounds) - { - // Paint background - if ((state & ColumnState.Hovered) != ColumnState.None) - { - using (Brush bHovered = new LinearGradientBrush(bounds, ImageListView.Colors.ColumnHeaderHoverColor1, ImageListView.Colors.ColumnHeaderHoverColor2, LinearGradientMode.Vertical)) - { - g.FillRectangle(bHovered, bounds); - } - } - else - { - using (Brush bNormal = new LinearGradientBrush(bounds, ImageListView.Colors.ColumnHeaderBackColor1, ImageListView.Colors.ColumnHeaderBackColor2, LinearGradientMode.Vertical)) - { - g.FillRectangle(bNormal, bounds); - } - } - using (Pen pBorder = new Pen(ImageListView.Colors.ColumnSeparatorColor)) - { - g.DrawLine(pBorder, bounds.Left, bounds.Top, bounds.Left, bounds.Bottom); - g.DrawLine(pBorder, bounds.Left, bounds.Bottom - 1, bounds.Right, bounds.Bottom - 1); - } - using (Pen pBorder = new Pen(Color.FromArgb(252, 252, 252))) - { - g.DrawRectangle(pBorder, bounds.Left + 1, bounds.Top, bounds.Width - 2, bounds.Height - 2); - } - - // Draw the sort arrow - int offset = 4; - int width = bounds.Width - 2 * offset; - if (ImageListView.SortOrder != SortOrder.None && ((state & ColumnState.SortColumn) != ColumnState.None)) - { - Image img = null; - if (ImageListView.SortOrder == SortOrder.Ascending) - img = ImageListViewResources.SortAscending; - else if (ImageListView.SortOrder == SortOrder.Descending) - img = ImageListViewResources.SortDescending; - if (img != null) - { - g.DrawImageUnscaled(img, bounds.Right - offset - img.Width, bounds.Top + (bounds.Height - img.Height) / 2); - width -= img.Width + offset; - } - } - - // Text - bounds.X += offset; - bounds.Width = width; - if (bounds.Width > 4) - { - using (StringFormat sf = new StringFormat()) - { - sf.FormatFlags = StringFormatFlags.NoWrap; - sf.Alignment = StringAlignment.Near; - sf.LineAlignment = StringAlignment.Center; - sf.Trimming = StringTrimming.EllipsisCharacter; - using (SolidBrush bText = new SolidBrush(ImageListView.Colors.ColumnHeaderForeColor)) - { - g.DrawString(column.Text, (ImageListView.ColumnHeaderFont == null ? ImageListView.Font : ImageListView.ColumnHeaderFont), bText, bounds, sf); - } - } - } - } - /// - /// Draws the extender after the last column. - /// - /// The System.Drawing.Graphics to draw on. - /// The bounding rectangle of extender column in client coordinates. - public override void DrawColumnExtender(Graphics g, Rectangle bounds) - { - // Paint background - using (Brush bNormal = new LinearGradientBrush(bounds, ImageListView.Colors.ColumnHeaderBackColor1, ImageListView.Colors.ColumnHeaderBackColor2, LinearGradientMode.Vertical)) - { - g.FillRectangle(bNormal, bounds); - } - using (Pen pBorder = new Pen(ImageListView.Colors.ColumnSeparatorColor)) - { - g.DrawLine(pBorder, bounds.Left, bounds.Top, bounds.Left, bounds.Bottom); - g.DrawLine(pBorder, bounds.Left, bounds.Bottom - 1, bounds.Right, bounds.Bottom - 1); - } - using (Pen pBorder = new Pen(Color.FromArgb(252, 252, 252))) - { - g.DrawRectangle(pBorder, bounds.Left + 1, bounds.Top, bounds.Width - 2, bounds.Height - 2); - } - } - /// - /// Draws the specified item on the given graphics. - /// - /// The System.Drawing.Graphics to draw on. - /// The ImageListViewItem to draw. - /// The current view state of item. - /// The bounding rectangle of item in client coordinates. - public override void DrawItem(Graphics g, ImageListViewItem item, ItemState state, Rectangle bounds) - { - if (ImageListView.View == View.Details) - { - bool alternate = (item.Index % 2 == 1); - List uicolumns = ImageListView.Columns.GetDisplayedColumns(); - - // Paint background - if ((state & ItemState.Disabled) != ItemState.None) - { - // Disabled - using (Brush bItemBack = new LinearGradientBrush(bounds, ImageListView.Colors.DisabledColor1, - ImageListView.Colors.DisabledColor2, LinearGradientMode.Vertical)) - { - g.FillRectangle(bItemBack, bounds); - } - } - else if (ImageListView.Focused && ((state & ItemState.Selected) != ItemState.None)) - { - // Focused and selected - using (Brush bItemBack = new LinearGradientBrush(bounds, ImageListView.Colors.SelectedColor1, - ImageListView.Colors.SelectedColor2, LinearGradientMode.Vertical)) - { - g.FillRectangle(bItemBack, bounds); - } - } - else if (!ImageListView.Focused && ((state & ItemState.Selected) != ItemState.None)) - { - // Not focused and selected - using (Brush bItemBack = new LinearGradientBrush(bounds, ImageListView.Colors.UnFocusedColor1, - ImageListView.Colors.UnFocusedColor2, LinearGradientMode.Vertical)) - { - g.FillRectangle(bItemBack, bounds); - } - } - else - { - // Not selected - using (Brush bItemBack = new SolidBrush(alternate ? - ImageListView.Colors.AlternateBackColor : ImageListView.Colors.BackColor)) - { - g.FillRectangle(bItemBack, bounds); - } - - // Shade sort column - int x = bounds.Left - 1; - foreach (ImageListView.ImageListViewColumnHeader column in uicolumns) - { - if (ImageListView.SortOrder != SortOrder.None && - ImageListView.SortColumn >= 0 && ImageListView.SortColumn < ImageListView.Columns.Count && - ImageListView.Columns[ImageListView.SortColumn].Guid == column.Guid) - { - Rectangle subItemBounds = bounds; - subItemBounds.X = x; - subItemBounds.Width = column.Width; - using (Brush bSort = new SolidBrush(ImageListView.Colors.ColumnSelectColor)) - { - g.FillRectangle(bSort, subItemBounds); - } - break; - } - x += column.Width; - } - - } - - // Separators - int xs = bounds.Left - 1; - foreach (ImageListView.ImageListViewColumnHeader column in uicolumns) - { - xs += column.Width; - if (!ReferenceEquals(column, uicolumns[uicolumns.Count - 1])) - { - using (Pen pSep = new Pen(ImageListView.Colors.ColumnSeparatorColor)) - { - g.DrawLine(pSep, xs, bounds.Top, xs, bounds.Bottom); - } - } - } - - // Sub items - Color foreColor = ImageListView.Colors.CellForeColor; - if ((state & ItemState.Disabled) != ItemState.None) - foreColor = ImageListView.Colors.DisabledForeColor; - else if (ImageListView.Focused && (state & ItemState.Selected) != ItemState.None) - foreColor = ImageListView.Colors.SelectedForeColor; - else if (!ImageListView.Focused && (state & ItemState.Selected) != ItemState.None) - foreColor = ImageListView.Colors.UnFocusedForeColor; - else if (alternate) - foreColor = ImageListView.Colors.AlternateCellForeColor; - - int offset = 2; - int firstWidth = 0; - if (uicolumns.Count > 0) - firstWidth = uicolumns[0].Width; - Rectangle rt = new Rectangle(bounds.Left + offset, bounds.Top, firstWidth - 2 * offset, bounds.Height); - foreach (ImageListView.ImageListViewColumnHeader column in uicolumns) - { - rt.Width = column.Width - 2 * offset; - int iconOffset = 0; - if (column.Type == ColumnType.Name) - { - // Allocate space for checkbox and file icon - if (ImageListView.ShowCheckBoxes && ImageListView.ShowFileIcons) - iconOffset += 2 * 16 + 3 * 2; - else if (ImageListView.ShowCheckBoxes) - iconOffset += 16 + 2 * 2; - else if (ImageListView.ShowFileIcons) - iconOffset += 16 + 2 * 2; - } - rt.X += iconOffset; - rt.Width -= iconOffset; - // Rating stars - if (column.Type == ColumnType.Rating && ImageListView.RatingImage != null && ImageListView.EmptyRatingImage != null) - { - int rating = item.GetSimpleRating(); - if (rating > 0) - { - int w = ImageListView.RatingImage.Width; - int y = (int)(rt.Top + (rt.Height - ImageListView.RatingImage.Height) / 2.0f); - - for (int i = 1; i <= 5; i++) - { - if (rating >= i) - g.DrawImage(ImageListView.RatingImage, rt.Left + (i - 1) * w, y); - else - g.DrawImage(ImageListView.EmptyRatingImage, rt.Left + (i - 1) * w, y); - } - } - } - else if (column.Type == ColumnType.Custom) - TextRenderer.DrawText(g, item.GetSubItemText(column.Guid), ImageListView.Font, rt, foreColor, - TextFormatFlags.EndEllipsis | TextFormatFlags.VerticalCenter | TextFormatFlags.PreserveGraphicsClipping); - else - TextRenderer.DrawText(g, item.GetSubItemText(column.Type), ImageListView.Font, rt, foreColor, - TextFormatFlags.EndEllipsis | TextFormatFlags.VerticalCenter | TextFormatFlags.PreserveGraphicsClipping); - - rt.X -= iconOffset; - rt.X += column.Width; - } - - // Focus rectangle - if (ImageListView.Focused && ((state & ItemState.Focused) != ItemState.None)) - ControlPaint.DrawFocusRectangle(g, bounds); - } - else // if (ImageListView.View != View.Details) - { - // Paint background - if (ImageListView.Enabled) - { - using (Brush bItemBack = new SolidBrush(ImageListView.Colors.BackColor)) - { - g.FillRectangle(bItemBack, bounds); - } - } - else - { - using (Brush bItemBack = new SolidBrush(ImageListView.Colors.DisabledBackColor)) - { - g.FillRectangle(bItemBack, bounds); - } - } - - // Get thumbnail - Image img = item.GetCachedImage(CachedImageType.Thumbnail); - - // Reference text height - int textHeight = ImageListView.Font.Height; - - // Calculate bounds - Rectangle textBounds = new Rectangle(bounds.Left + 3, bounds.Bottom - (textHeight + 3), bounds.Width - 2 * 3, textHeight); - Rectangle imgBounds; - if (img != null) - imgBounds = new Rectangle(bounds.Left + (bounds.Width - img.Width) / 2, - bounds.Bottom - (img.Height + textHeight + 3 * 3), img.Width, img.Height); - else - imgBounds = new Rectangle(bounds.Left + 3, bounds.Top + 3, ImageListView.ThumbnailSize.Width, ImageListView.ThumbnailSize.Height); - Rectangle textOutline = Rectangle.Inflate(textBounds, 3, 3); - Rectangle imgOutline = Rectangle.Inflate(imgBounds, 3, 3); - textOutline.Width -= 1; - textOutline.Height -= 1; - - // Paint background - if ((((state & ItemState.Disabled) != ItemState.None))) - { - // Disabled - using (Brush bBack = new SolidBrush(ImageListView.Colors.DisabledColor1)) - { - Utility.FillRoundedRectangle(g, bBack, textOutline, 4); - Utility.FillRoundedRectangle(g, bBack, imgOutline, 4); - } - } - else if ((ImageListView.Focused && ((state & ItemState.Selected) != ItemState.None))) - { - // Focused and selected - using (Brush bBack = new SolidBrush(ImageListView.Colors.SelectedColor1)) - { - Utility.FillRoundedRectangle(g, bBack, textOutline, 4); - Utility.FillRoundedRectangle(g, bBack, imgOutline, 4); - } - } - else if ((!ImageListView.Focused && ((state & ItemState.Selected) != ItemState.None))) - { - // Not focused and selected - using (Brush bBack = new SolidBrush(ImageListView.Colors.UnFocusedColor1)) - { - Utility.FillRoundedRectangle(g, bBack, textOutline, 4); - Utility.FillRoundedRectangle(g, bBack, imgOutline, 4); - } - } - - // Draw image - if (img != null) - { - g.DrawImage(img, imgBounds.Location); - } - - // Image border - using (Pen pBorder = new Pen(ImageListView.Colors.BorderColor)) - { - Utility.DrawRoundedRectangle(g, pBorder, imgOutline.Left, imgOutline.Top, imgOutline.Width - 1, imgOutline.Height - 1, 3); - } - - // Hovered state - if ((state & ItemState.Hovered) != ItemState.None) - { - using (Brush bGlow = new SolidBrush(Color.FromArgb(24, Color.White))) - { - Utility.FillRoundedRectangle(g, bGlow, imgOutline, 4); - } - } - - // Item text - Color foreColor = ImageListView.Colors.ForeColor; - if ((state & ItemState.Disabled) != ItemState.None) - foreColor = ImageListView.Colors.DisabledForeColor; - else if (ImageListView.Focused && (state & ItemState.Selected) != ItemState.None) - foreColor = ImageListView.Colors.SelectedForeColor; - else if (!ImageListView.Focused && (state & ItemState.Selected) != ItemState.None) - foreColor = ImageListView.Colors.UnFocusedForeColor; - TextRenderer.DrawText(g, item.Text, ImageListView.Font, textBounds, foreColor, - TextFormatFlags.EndEllipsis | TextFormatFlags.HorizontalCenter | TextFormatFlags.VerticalCenter | TextFormatFlags.PreserveGraphicsClipping); - - // Focus rectangle - if (ImageListView.Focused && ((state & ItemState.Focused) != ItemState.None)) - { - textOutline.Offset(1, 1); - textOutline.Width -= 1; - textOutline.Height -= 1; - ControlPaint.DrawFocusRectangle(g, textOutline); - } - } - } - /// - /// Draws the large preview image of the focused item in Gallery mode. - /// - /// The System.Drawing.Graphics to draw on. - /// The ImageListViewItem to draw. - /// The image to draw. - /// The bounding rectangle of the preview area. - public override void DrawGalleryImage(Graphics g, ImageListViewItem item, Image image, Rectangle bounds) - { - if (item != null && image != null) - { - // Calculate image bounds - Size itemMargin = MeasureItemMargin(ImageListView.View); - Rectangle pos = Utility.GetSizedImageBounds(image, new Rectangle(bounds.Location + itemMargin, bounds.Size - itemMargin - itemMargin)); - // Draw image - g.DrawImage(image, pos); - // Draw image border - if (pos.Width > 32 && pos.Height > 32) - { - using (Pen pBorder = new Pen(ImageListView.Colors.BorderColor)) - { - g.DrawRectangle(pBorder, pos); - } - } - } - } - } - #endregion - } -} \ No newline at end of file diff --git a/Source/Components/ImageGlass.ImageListView/ImageListViewResources.Designer.cs b/Source/Components/ImageGlass.ImageListView/ImageListViewResources.Designer.cs deleted file mode 100644 index 0434580e2..000000000 --- a/Source/Components/ImageGlass.ImageListView/ImageListViewResources.Designer.cs +++ /dev/null @@ -1,348 +0,0 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by a tool. -// Runtime Version:4.0.30319.42000 -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -namespace ImageGlass.ImageListView { - using System; - - - /// - /// A strongly-typed resource class, for looking up localized strings, etc. - /// - // This class was auto-generated by the StronglyTypedResourceBuilder - // class via a tool like ResGen or Visual Studio. - // To add or remove a member, edit your .ResX file then rerun ResGen - // with the /str option, or rebuild your VS project. - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "15.0.0.0")] - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] - internal class ImageListViewResources { - - private static global::System.Resources.ResourceManager resourceMan; - - private static global::System.Globalization.CultureInfo resourceCulture; - - [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - internal ImageListViewResources() { - } - - /// - /// Returns the cached ResourceManager instance used by this class. - /// - [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - internal static global::System.Resources.ResourceManager ResourceManager { - get { - if (object.ReferenceEquals(resourceMan, null)) { - global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("ImageGlass.ImageListView.ImageListViewResources", typeof(ImageListViewResources).Assembly); - resourceMan = temp; - } - return resourceMan; - } - } - - /// - /// Overrides the current thread's CurrentUICulture property for all - /// resource lookups using this strongly typed resource class. - /// - [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - internal static global::System.Globalization.CultureInfo Culture { - get { - return resourceCulture; - } - set { - resourceCulture = value; - } - } - - /// - /// Looks up a localized string similar to Aperture. - /// - internal static string Aperture { - get { - return ResourceManager.GetString("Aperture", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Artist. - /// - internal static string Artist { - get { - return ResourceManager.GetString("Artist", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Copyright. - /// - internal static string Copyright { - get { - return ResourceManager.GetString("Copyright", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Custom. - /// - internal static string Custom { - get { - return ResourceManager.GetString("Custom", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Last Access. - /// - internal static string DateAccessed { - get { - return ResourceManager.GetString("DateAccessed", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Created. - /// - internal static string DateCreated { - get { - return ResourceManager.GetString("DateCreated", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Modified. - /// - internal static string DateModified { - get { - return ResourceManager.GetString("DateModified", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Taken. - /// - internal static string DateTaken { - get { - return ResourceManager.GetString("DateTaken", resourceCulture); - } - } - - /// - /// Looks up a localized resource of type System.Drawing.Bitmap. - /// - internal static System.Drawing.Bitmap DefaultImage { - get { - object obj = ResourceManager.GetObject("DefaultImage", resourceCulture); - return ((System.Drawing.Bitmap)(obj)); - } - } - - /// - /// Looks up a localized string similar to Dimensions. - /// - internal static string Dimensions { - get { - return ResourceManager.GetString("Dimensions", resourceCulture); - } - } - - /// - /// Looks up a localized resource of type System.Drawing.Bitmap. - /// - internal static System.Drawing.Bitmap EmptyRatingImage { - get { - object obj = ResourceManager.GetObject("EmptyRatingImage", resourceCulture); - return ((System.Drawing.Bitmap)(obj)); - } - } - - /// - /// Looks up a localized string similar to Camera. - /// - internal static string EquipmentModel { - get { - return ResourceManager.GetString("EquipmentModel", resourceCulture); - } - } - - /// - /// Looks up a localized resource of type System.Drawing.Bitmap. - /// - internal static System.Drawing.Bitmap ErrorImage { - get { - object obj = ResourceManager.GetObject("ErrorImage", resourceCulture); - return ((System.Drawing.Bitmap)(obj)); - } - } - - /// - /// Looks up a localized string similar to Exposure Time. - /// - internal static string ExposureTime { - get { - return ResourceManager.GetString("ExposureTime", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Filename. - /// - internal static string FileName { - get { - return ResourceManager.GetString("FileName", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Path. - /// - internal static string FilePath { - get { - return ResourceManager.GetString("FilePath", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Size. - /// - internal static string FileSize { - get { - return ResourceManager.GetString("FileSize", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Type. - /// - internal static string FileType { - get { - return ResourceManager.GetString("FileType", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to F Number. - /// - internal static string FNumber { - get { - return ResourceManager.GetString("FNumber", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Focal Length. - /// - internal static string FocalLength { - get { - return ResourceManager.GetString("FocalLength", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Description. - /// - internal static string ImageDescription { - get { - return ResourceManager.GetString("ImageDescription", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to ISO Speed. - /// - internal static string ISOSpeed { - get { - return ResourceManager.GetString("ISOSpeed", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Name. - /// - internal static string Name { - get { - return ResourceManager.GetString("Name", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Rating. - /// - internal static string Rating { - get { - return ResourceManager.GetString("Rating", resourceCulture); - } - } - - /// - /// Looks up a localized resource of type System.Drawing.Bitmap. - /// - internal static System.Drawing.Bitmap RatingImage { - get { - object obj = ResourceManager.GetObject("RatingImage", resourceCulture); - return ((System.Drawing.Bitmap)(obj)); - } - } - - /// - /// Looks up a localized string similar to Resolution. - /// - internal static string Resolution { - get { - return ResourceManager.GetString("Resolution", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Shutter Speed. - /// - internal static string ShutterSpeed { - get { - return ResourceManager.GetString("ShutterSpeed", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Software. - /// - internal static string Software { - get { - return ResourceManager.GetString("Software", resourceCulture); - } - } - - /// - /// Looks up a localized resource of type System.Drawing.Bitmap. - /// - internal static System.Drawing.Bitmap SortAscending { - get { - object obj = ResourceManager.GetObject("SortAscending", resourceCulture); - return ((System.Drawing.Bitmap)(obj)); - } - } - - /// - /// Looks up a localized resource of type System.Drawing.Bitmap. - /// - internal static System.Drawing.Bitmap SortDescending { - get { - object obj = ResourceManager.GetObject("SortDescending", resourceCulture); - return ((System.Drawing.Bitmap)(obj)); - } - } - - /// - /// Looks up a localized string similar to Comments. - /// - internal static string UserComment { - get { - return ResourceManager.GetString("UserComment", resourceCulture); - } - } - } -} diff --git a/Source/Components/ImageGlass.ImageListView/ImageListViewResources.resx b/Source/Components/ImageGlass.ImageListView/ImageListViewResources.resx deleted file mode 100644 index a5e1f9980..000000000 --- a/Source/Components/ImageGlass.ImageListView/ImageListViewResources.resx +++ /dev/null @@ -1,214 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - Aperture - - - Artist - - - Copyright - - - Last Access - - - Created - - - Modified - - - Taken - - - Dimensions - - - Camera - - - Exposure Time - - - Filename - - - Path - - - Size - - - Type - - - F Number - - - Description - - - ISO Speed - - - Name - - - Resolution - - - Shutter Speed - - - Comments - - - - Resources\DefaultImage.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a - - - Resources\ErrorImage.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a - - - Resources\SortAscending.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a - - - Resources\SortDescending.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a - - - Resources\RatingImage.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a - - - Resources\EmptyRatingImage.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a - - - Rating - - - Custom - - - Focal Length - - - Software - - \ No newline at end of file diff --git a/Source/Components/ImageGlass.ImageListView/ImageListViewSelectedItemCollection.cs b/Source/Components/ImageGlass.ImageListView/ImageListViewSelectedItemCollection.cs deleted file mode 100644 index d9d5ac2fb..000000000 --- a/Source/Components/ImageGlass.ImageListView/ImageListViewSelectedItemCollection.cs +++ /dev/null @@ -1,326 +0,0 @@ -// ImageListView - A listview control for image files -// Copyright (C) 2009 Ozgur Ozcitak -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// Ozgur Ozcitak (ozcitak@yahoo.com) - -using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.Collections; - -namespace ImageGlass.ImageListView -{ - public partial class ImageListView - { - /// - /// Represents the collection of selected items in the image list view. - /// - public class ImageListViewSelectedItemCollection : IList - { - #region Member Variables - internal ImageListView mImageListView; - #endregion - - #region Constructors - /// - /// Initializes a new instance of the class. - /// - /// The owning this collection. - internal ImageListViewSelectedItemCollection(ImageListView owner) - { - mImageListView = owner; - } - #endregion - - #region Properties - /// - /// Gets the number of elements contained in the . - /// - [Category("Behavior"), Browsable(true), Description("Gets the number of elements contained in the collection.")] - public int Count - { - get - { - int count = 0; - foreach (ImageListViewItem item in mImageListView.mItems) - if (item.Selected && item.Enabled) count++; - return count; - } - } /// - /// Gets a value indicating whether the is read-only. - /// - [Category("Behavior"), Browsable(false), Description("Gets a value indicating whether the collection is read-only.")] - public bool IsReadOnly { get { return true; } } - /// - /// Gets the owning this collection. - /// - [Category("Behavior"), Browsable(false), Description("Gets the ImageListView owning this collection.")] - public ImageListView ImageListView { get { return mImageListView; } } - /// - /// Gets or sets the at the specified index. - /// - [Category("Behavior"), Browsable(false), Description("Gets or sets the item at the specified index")] - public ImageListViewItem this[int index] - { - get - { - int i = 0; - foreach (ImageListViewItem item in this) - { - if (i == index) - return item; - i++; - } - throw new ArgumentException("No item with the given index exists.", "index"); - } - } - #endregion - - #region Instance Methods - /// - /// Determines whether the contains a specific value. - /// - /// The to locate in the . - /// - /// true if is found in the ; otherwise, false. - /// - public bool Contains(ImageListViewItem item) - { - return (item.Selected && item.Enabled && mImageListView.Items.Contains(item)); - } - /// - /// Returns an enumerator that iterates through the collection. - /// - /// - /// A that can be used to iterate through the collection. - /// - public IEnumerator GetEnumerator() - { - return new ImageListViewSelectedItemEnumerator(mImageListView.mItems); - } - #endregion - - #region Helper Methods - /// - /// Removes all items from the collection. - /// - internal void Clear() - { - Clear(true); - } - /// - /// Removes all items from the collection. - /// - internal void Clear(bool raiseEvent) - { - foreach (ImageListViewItem item in this) - item.mSelected = false; - if (raiseEvent && mImageListView != null) - mImageListView.OnSelectionChangedInternal(); - } - #endregion - - #region Unsupported Interface - /// - /// Adds an item to the . - /// - /// The object to add to the . - void ICollection.Add(ImageListViewItem item) - { - throw new NotSupportedException(); - } - /// - /// Removes all items from the . - /// - void ICollection.Clear() - { - throw new NotSupportedException(); - } - /// - /// Copies the elements of the to an , starting at a particular index. - /// - /// The one-dimensional that is the destination of the elements copied from . The must have zero-based indexing. - /// The zero-based index in at which copying begins. - void ICollection.CopyTo(ImageListViewItem[] array, int arrayIndex) - { - throw new NotSupportedException(); - } - /// - /// Determines the index of a specific item in the . - /// - /// The object to locate in the . - /// - /// The index of if found in the list; otherwise, -1. - /// - [Obsolete("Use ImageListViewItem.Index property instead.")] - int IList.IndexOf(ImageListViewItem item) - { - throw new NotSupportedException(); - } - /// - /// Inserts an item to the at the specified index. - /// - /// The zero-based index at which should be inserted. - /// The object to insert into the . - void IList.Insert(int index, ImageListViewItem item) - { - throw new NotSupportedException(); - } - /// - /// Removes the first occurrence of a specific object from the . - /// - /// The object to remove from the . - /// - /// true if was successfully removed from the ; otherwise, false. This method also returns false if is not found in the original . - /// - bool ICollection.Remove(ImageListViewItem item) - { - throw new NotSupportedException(); - } - /// - /// Removes the item at the specified index. - /// - /// The zero-based index of the item to remove. - void IList.RemoveAt(int index) - { - throw new NotSupportedException(); - } - /// - /// Gets or sets the item at the specified index. - /// - ImageListViewItem IList.this[int index] - { - get - { - throw new NotSupportedException(); - } - set - { - throw new NotSupportedException(); - } - } - /// - /// Returns an enumerator that iterates through a collection. - /// - /// - /// An object that can be used to iterate through the collection. - /// - System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() - { - return GetEnumerator(); - } - #endregion - - #region Internal Classes - /// - /// Represents an enumerator to walk though the selected items. - /// - internal class ImageListViewSelectedItemEnumerator : IEnumerator - { - #region Member Variables - private ImageListViewItemCollection owner; - private int current; - private Guid lastItem; - #endregion - - #region Constructor - public ImageListViewSelectedItemEnumerator(ImageListViewItemCollection collection) - { - owner = collection; - current = -1; - lastItem = Guid.Empty; - } - #endregion - - #region Properties - /// - /// Gets the element in the collection at the current position of the enumerator. - /// - public ImageListViewItem Current - { - get - { - if (current == -1 || current > owner.Count - 1) - throw new InvalidOperationException(); - return owner[current]; - } - } - /// - /// Gets the element in the collection at the current position of the enumerator. - /// - object IEnumerator.Current - { - get { return Current; } - } - #endregion - - #region Instance Methods - /// - /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. - /// - public void Dispose() - { - ; - } - /// - /// Advances the enumerator to the next element of the collection. - /// - public bool MoveNext() - { - // Did we reach the end? - if (current > owner.Count - 1) - { - lastItem = Guid.Empty; - return false; - } - - // Move to the next item if: - // 1. We are before the first item. - OR - - // 2. The current item is the same as the one we enumerated before. - // The current item may have differed if the user for example - // removed the current item between MoveNext calls. - OR - - // 3. The current item is not selected. - // 3. The current item is not enabled. - while (current == -1 || - owner[current].Guid == lastItem || - owner[current].Selected == false || - owner[current].Enabled == false) - { - current++; - if (current > owner.Count - 1) - { - lastItem = Guid.Empty; - return false; - } - } - - // Cache the last item - lastItem = owner[current].Guid; - return true; - } - /// - /// Sets the enumerator to its initial position, which is before the first element in the collection. - /// - public void Reset() - { - current = -1; - lastItem = Guid.Empty; - } - #endregion - } - #endregion - } - } -} \ No newline at end of file diff --git a/Source/Components/ImageGlass.ImageListView/MetadataExtractor.cs b/Source/Components/ImageGlass.ImageListView/MetadataExtractor.cs deleted file mode 100644 index 8037a440e..000000000 --- a/Source/Components/ImageGlass.ImageListView/MetadataExtractor.cs +++ /dev/null @@ -1,690 +0,0 @@ -// ImageListView - A listview control for image files -// Copyright (C) 2009 Ozgur Ozcitak -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// Ozgur Ozcitak (ozcitak@yahoo.com) -// -// WIC support coded by Jens - -using System; -using System.Text; -using System.IO; -using System.Drawing; -using System.Drawing.Imaging; -#if USEWIC -using System.Windows.Media.Imaging; -#endif - -namespace ImageGlass.ImageListView -{ - /// - /// Read metadata. - /// Only EXIF data when using .NET 2.0 methods. - /// Prioritized EXIF/XMP/ICC/etc. data when using WIC/WPF methods. - /// - internal class MetadataExtractor - { - #region Exif Tag IDs - private const int TagImageDescription = 0x010E; - private const int TagEquipmentModel = 0x0110; - private const int TagDateTimeOriginal = 0x9003; - private const int TagArtist = 0x013B; - private const int TagCopyright = 0x8298; - private const int TagExposureTime = 0x829A; - private const int TagFNumber = 0x829D; - private const int TagISOSpeed = 0x8827; - private const int TagUserComment = 0x9286; - private const int TagRating = 0x4746; - private const int TagRatingPercent = 0x4749; - private const int TagEquipmentManufacturer = 0x010F; - private const int TagFocalLength = 0x920A; - private const int TagSoftware = 0x0131; - #endregion - -#if USEWIC - #region WIC Metadata Paths - private static readonly string[] WICPathImageDescription = new string[] { "/app1/ifd/{ushort=40095}", "/app1/ifd/{ushort=270}" }; - private static readonly string[] WICPathCopyright = new string[] { "/app1/ifd/{ushort=33432}", "/app13/irb/8bimiptc/iptc/copyright notice", "/xmp/dc:rights", "/xmp/dc:rights" }; - private static readonly string[] WICPathComment = new string[] { "/app1/ifd/{ushort=40092}", "/app1/ifd/{ushort=37510}", "/xmp/exif:UserComment" }; - private static readonly string[] WICPathSoftware = new string[] { "/app1/ifd/{ushort=305}", "/xmp/xmp:CreatorTool", "/xmp/xmp:creatortool", "/xmp/tiff:Software", "/xmp/tiff:software", "/app13/irb/8bimiptc/iptc/Originating Program" }; - private static readonly string[] WICPathSimpleRating = new string[] { "/app1/ifd/{ushort=18246}", "/xmp/xmp:Rating" }; - private static readonly string[] WICPathRating = new string[] { "/app1/ifd/{ushort=18249}", "/xmp/MicrosoftPhoto:Rating" }; - private static readonly string[] WICPathArtist = new string[] { "/app1/ifd/{ushort=315}", "/app13/irb/8bimiptc/iptc/by-line", "/app1/ifd/{ushort=40093}", "/xmp/tiff:artist" }; - private static readonly string[] WICPathEquipmentManufacturer = new string[] { "/app1/ifd/{ushort=271}", "/xmp/tiff:Make", "/xmp/tiff:make" }; - private static readonly string[] WICPathEquipmentModel = new string[] { "/app1/ifd/{ushort=272}", "/xmp/tiff:Model", "/xmp/tiff:model" }; - private static readonly string[] WICPathDateTaken = new string[] { "/app1/ifd/exif/{ushort=36867}", "/app13/irb/8bimiptc/iptc/date created", "/xmp/xmp:CreateDate", "/app1/ifd/exif/{ushort=36868}", "/app13/irb/8bimiptc/iptc/date created", "/xmp/exif:DateTimeOriginal" }; - private static readonly string[] WICPathExposureTime = new string[] { "/app1/ifd/exif/{ushort=33434}", "/xmp/exif:ExposureTime" }; - private static readonly string[] WICPathFNumber = new string[] { "/app1/ifd/exif/{ushort=33437}", "/xmp/exif:FNumber" }; - private static readonly string[] WICPathISOSpeed = new string[] { "/app1/ifd/exif/{ushort=34855}", "/xmp/exif:ISOSpeedRatings", "/xmp/exif:ISOSpeed" }; - private static readonly string[] WICPathFocalLength = new string[] { "/app1/ifd/exif/{ushort=37386}", "/xmp/exif:FocalLength" }; - #endregion -#endif - - #region Exif Format Conversion - /// - /// Converts the given Exif data to an ASCII encoded string. - /// - /// Exif data as a byte array. - private static string ExifAscii(byte[] value) - { - if (value == null || value.Length == 0) - return string.Empty; - - string str = Encoding.ASCII.GetString(value); - str = str.Trim(new char[] { '\0' }); - return str; - } - /// - /// Converts the given Exif data to DateTime. - /// - /// Exif data as a byte array. - private static DateTime ExifDateTime(byte[] value) - { - return ExifDateTime(ExifAscii(value)); - } - /// - /// Converts the given Exif data to DateTime. - /// Value must be formatted as yyyy:MM:dd HH:mm:ss. - /// - /// Exif data as a string. - private static DateTime ExifDateTime(string value) - { - try - { - // Don't throw unnecessary FormatExceptions - DateTime dt; - var converted = DateTime.TryParseExact(value, - "yyyy:MM:dd HH:mm:ss", - System.Globalization.CultureInfo.InvariantCulture, - System.Globalization.DateTimeStyles.None, - out dt); - return converted ? dt : DateTime.MinValue; - //return DateTime.ParseExact(value, - // "yyyy:MM:dd HH:mm:ss", - // System.Globalization.CultureInfo.InvariantCulture); - } - catch - { - return DateTime.MinValue; - } - } - /// - /// Converts the given Exif data to an 16-bit unsigned integer. - /// The value must have 2 bytes. - /// - /// Exif data as a byte array. - private static ushort ExifUShort(byte[] value) - { - return BitConverter.ToUInt16(value, 0); - } - /// - /// Converts the given Exif data to an 32-bit unsigned integer. - /// The value must have 4 bytes. - /// - /// Exif data as a byte array. - private static uint ExifUInt(byte[] value) - { - return BitConverter.ToUInt32(value, 0); - } - /// - /// Converts the given Exif data to an 32-bit signed integer. - /// The value must have 4 bytes. - /// - /// Exif data as a byte array. - private static int ExifInt(byte[] value) - { - return BitConverter.ToInt32(value, 0); - } - /// - /// Converts the given Exif data to an unsigned rational value - /// represented as a string. - /// The value must have 8 bytes. - /// - /// Exif data as a byte array. - private static string ExifURational(byte[] value) - { - return BitConverter.ToUInt32(value, 0).ToString() + "/" + - BitConverter.ToUInt32(value, 4).ToString(); - } - /// - /// Converts the given Exif data to a signed rational value - /// represented as a string. - /// The value must have 8 bytes. - /// - /// Exif data as a byte array. - private static string ExifRational(byte[] value) - { - return BitConverter.ToInt32(value, 0).ToString() + "/" + - BitConverter.ToInt32(value, 4).ToString(); - } - /// - /// Converts the given Exif data to a double number. - /// The value must have 8 bytes. - /// - /// Exif data as a byte array. - private static double ExifDouble(byte[] value) - { - uint num = BitConverter.ToUInt32(value, 0); - uint den = BitConverter.ToUInt32(value, 4); - if (den == 0) - return 0.0; - else - return num / (double)den; - } - #endregion - - #region Metadata properties - /// - /// Error. - /// - public Exception Error = null; - /// - /// Image width. - /// - public int Width = 0; - /// - /// Image height. - /// - public int Height = 0; - /// - /// Horizontal DPI. - /// - public double DPIX = 0.0; - /// - /// Vertical DPI. - /// - public double DPIY = 0.0; - /// - /// Date taken. - /// - public DateTime DateTaken = DateTime.MinValue; - /// - /// Image description (null = not available). - /// - public string ImageDescription = null; - /// - /// Camera manufacturer (null = not available). - /// - public string EquipmentManufacturer = null; - /// - /// Camera model (null = not available). - /// - public string EquipmentModel = null; - /// - /// Image creator (null = not available). - /// - public string Artist = null; - /// - /// Iso speed rating. - /// - public int ISOSpeed = 0; - /// - /// Exposure time. - /// - public double ExposureTime = 0.0; - /// - /// F number. - /// - public double FNumber = 0.0; - /// - /// Copyright information (null = not available). - /// - public string Copyright = null; - /// - /// Rating value between 0-99. - /// - public int Rating = 0; - /// - /// User comment (null = not available). - /// - public string Comment = null; - /// - /// Software used (null = not available). - /// - public string Software = null; - /// - /// Focal length. - /// - public double FocalLength = 0.0; - #endregion - - #region Helper Methods - /// - /// Inits metadata via WIC/WPF (.NET 3.0). - /// If WIC lacks a metadata reader for this image type then fall back to .NET 2.0 method. - /// - /// Filepath of image - private void InitViaWpf(string path) - { - bool wicError = false; -#if USEWIC - try - { - using (FileStream streamWpf = File.Open(path, FileMode.Open, FileAccess.Read, FileShare.Read)) - { - BitmapFrame frameWpf = BitmapFrame.Create - (streamWpf, - BitmapCreateOptions.IgnoreColorProfile, - BitmapCacheOption.None); - InitViaWpf(frameWpf); - } - } - catch (Exception eWpf) - { - Error = eWpf; - wicError = true; - } -#else - wicError = true; -#endif - if (wicError) - { - try - { - // Fall back to .NET 2.0 method. - InitViaBmp(path); - } - catch (Exception eBmp) - { - Error = eBmp; - } - } - } -#if USEWIC - /// - /// Inits metadata via WIC/WPF (.NET 3.0). - /// - /// Opened WPF image - private void InitViaWpf(BitmapFrame frameWpf) - { - Width = frameWpf.PixelWidth; - Height = frameWpf.PixelHeight; - DPIX = frameWpf.DpiX; - DPIY = frameWpf.DpiY; - - BitmapMetadata data = frameWpf.Metadata as BitmapMetadata; - if (data != null) - InitViaWpf(data); - } -#endif - /// - /// Open image and read metadata (.NET 2.0). - /// - /// Filepath of image - private void InitViaBmp(string path) - { - using (FileStream stream = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read)) - { - if (Utility.IsImage(stream)) - { - using (Image img = Image.FromStream(stream, false, false)) - { - if (img != null) - { - InitViaBmp(img); - } - } - } - } - } - /// - /// Read metadata using .NET 2.0 methods. - /// - /// Opened image - private void InitViaBmp(Image img) - { - Width = img.Width; - Height = img.Height; - DPIX = img.HorizontalResolution; - DPIY = img.VerticalResolution; - - double dVal; - int iVal; - DateTime dateTime; - string str; - foreach (PropertyItem prop in img.PropertyItems) - { - if (prop.Value != null && prop.Value.Length != 0) - { - switch (prop.Id) - { - case TagImageDescription: - str = ExifAscii(prop.Value).Trim(); - if (str != String.Empty) - { - ImageDescription = str; - } - break; - case TagArtist: - str = ExifAscii(prop.Value).Trim(); - if (str != String.Empty) - { - Artist = str; - } - break; - case TagEquipmentManufacturer: - str = ExifAscii(prop.Value).Trim(); - if (str != String.Empty) - { - EquipmentManufacturer = str; - } - break; - case TagEquipmentModel: - str = ExifAscii(prop.Value).Trim(); - if (str != String.Empty) - { - EquipmentModel = str; - } - break; - case TagDateTimeOriginal: - dateTime = ExifDateTime(prop.Value); - if (dateTime != DateTime.MinValue) - { - DateTaken = dateTime; - } - break; - case TagExposureTime: - if (prop.Value.Length == 8) - { - dVal = ExifDouble(prop.Value); - if (dVal != 0.0) - { - ExposureTime = dVal; - } - } - break; - case TagFNumber: - if (prop.Value.Length == 8) - { - dVal = ExifDouble(prop.Value); - if (dVal != 0.0) - { - FNumber = dVal; - } - } - break; - case TagISOSpeed: - if (prop.Value.Length == 2) - { - iVal = ExifUShort(prop.Value); - if (iVal != 0) - { - ISOSpeed = iVal; - } - } - break; - case TagCopyright: - str = ExifAscii(prop.Value); - if (str != String.Empty) - { - Copyright = str; - } - break; - case TagRating: - if (Rating == 0 && prop.Value.Length == 2) - { - iVal = ExifUShort(prop.Value); - if (iVal == 1) - Rating = 1; - else if (iVal == 2) - Rating = 25; - else if (iVal == 3) - Rating = 50; - else if (iVal == 4) - Rating = 75; - else if (iVal == 5) - Rating = 99; - } - break; - case TagRatingPercent: - if (prop.Value.Length == 2) - { - iVal = ExifUShort(prop.Value); - Rating = iVal; - } - break; - case TagUserComment: - str = ExifAscii(prop.Value); - if (str != String.Empty) - { - Comment = str; - } - break; - case TagSoftware: - str = ExifAscii(prop.Value).Trim(); - if (str != String.Empty) - { - Software = str; - } - break; - case TagFocalLength: - if (prop.Value.Length == 8) - { - dVal = ExifDouble(prop.Value); - if (dVal != 0.0) - { - FocalLength = dVal; - } - } - break; - } - } - } - } - -#if USEWIC - /// - /// Read metadata via WIC/WPF. - /// - /// metadata - private void InitViaWpf(BitmapMetadata data) - { - Object val; - - // Subject - val = GetMetadataObject(data, WICPathImageDescription); - if (val != null) - ImageDescription = val as string; - // Copyright - val = GetMetadataObject(data, WICPathCopyright); - if (val != null) - Copyright = val as string; - // Comment - val = GetMetadataObject(data, WICPathComment); - if (val != null) - Comment = val as string; - // Software - val = GetMetadataObject(data, WICPathSoftware); - if (val != null) - Software = val as string; - // Simple rating - val = GetMetadataObject(data, WICPathSimpleRating); - if (val != null) - { - //ushort simpleRating = (ushort)val; - ushort simpleRating = Convert.ToUInt16(val); - - if (simpleRating == 1) - Rating = 1; - else if (simpleRating == 2) - Rating = 25; - else if (simpleRating == 3) - Rating = 50; - else if (simpleRating == 4) - Rating = 75; - else if (simpleRating == 5) - Rating = 99; - } - // Rating - val = GetMetadataObject(data, WICPathRating); - if (val != null) - { - var a = val as Array; - if (a != null) - Rating = Convert.ToInt32(a.GetValue(0)); - else - Rating = Convert.ToInt32(val); - //Rating = (int)((ushort)val); - } - // Authors - val = GetMetadataObject(data, WICPathArtist); - if (val != null) - { - if (val is string) - Artist = (string)val; - else if (val is System.Collections.Generic.IEnumerable) - { - int i = 0; - StringBuilder authors = new StringBuilder(); - foreach (string author in (System.Collections.Generic.IEnumerable)val) - { - if (i != 0) - authors.Append(";"); - authors.Append(authors); - i++; - } - Artist = authors.ToString(); - } - } - - // Camera manufacturer - val = GetMetadataObject(data, WICPathEquipmentManufacturer); - if (val != null) - EquipmentManufacturer = val as string; - // Camera model - val = GetMetadataObject(data, WICPathEquipmentModel); - if (val != null) - EquipmentModel = val as string; - - // Date taken - val = GetMetadataObject(data, WICPathDateTaken); - if (val != null) - DateTaken = ExifDateTime((string)val); - // Exposure time - val = GetMetadataObject(data, WICPathExposureTime); - if (val != null) - ExposureTime = ExifDouble(BitConverter.GetBytes((ulong)val)); - // FNumber - val = GetMetadataObject(data, WICPathFNumber); - if (val != null) - FNumber = ExifDouble(BitConverter.GetBytes((ulong)val)); - // ISOSpeed - val = GetMetadataObject(data, WICPathISOSpeed); - if (val != null) - { - var a = val as Array; - if (a != null) - ISOSpeed = Convert.ToUInt16(a.GetValue(0)); - else - ISOSpeed = Convert.ToUInt16(val); - } - // FocalLength - val = GetMetadataObject(data, WICPathFocalLength); - if (val != null) - FocalLength = ExifDouble(BitConverter.GetBytes((ulong)val)); - } - /// - /// [PHAP] Returns the metadata for the given query. - /// - /// The image metadata. - /// A list of query strings. - /// Metadata object or null if the metadata is not found. - private object GetMetadataObject(BitmapMetadata metadata, params string[] query) - { - try - { - foreach (string q in query) - { - object val = metadata.GetQuery(q); - if (val != null) - return val; - } - } - catch (Exception) - { - return null; - } - return null; - } -#endif - /// - /// Convert FileTime to DateTime. - /// - /// FileTime - /// DateTime - private DateTime ConvertFileTime(System.Runtime.InteropServices.ComTypes.FILETIME ft) - { - long longTime = (((long)ft.dwHighDateTime) << 32) | ((uint)ft.dwLowDateTime); - return DateTime.FromFileTimeUtc(longTime); // using UTC??? - } - #endregion - - #region Constructor - /// - /// Initializes a new instance of the MetadataExtractor class. - /// - private MetadataExtractor() - { - ; - } - #endregion - - #region Public Methods - /// - /// Creates an instance of the MetadataExtractor class. - /// Reads metadata via WIC/WPF (.NET 3.0). - /// If WIC lacks a metadata reader for this image type then fall back to .NET 2.0 method. - /// - /// Filepath of image - public static MetadataExtractor FromFile(string path) - { - return MetadataExtractor.FromFile(path, true); - } - /// - /// Creates an instance of the MetadataExtractor class. - /// Reads metadata via WIC/WPF (.NET 3.0). - /// If WIC lacks a metadata reader for this image type then fall back to .NET 2.0 method. - /// - /// Filepath of image - /// true to use Windows Imaging Component; otherwise false. - public static MetadataExtractor FromFile(string path, bool useWic) - { - MetadataExtractor metadata = new MetadataExtractor(); -#if USEWIC - if (useWic) - metadata.InitViaWpf(path); - else - metadata.InitViaBmp(path); -#else - metadata.InitViaBmp(path); -#endif - return metadata; - } -#if USEWIC - /// - /// Creates an instance of the MetadataExtractor class. - /// Reads metadata via WIC/WPF (.NET 3.0). - /// If WIC lacks a metadata reader for this image type then fall back to .NET 2.0 method. - /// - /// Opened WPF image - public static MetadataExtractor FromBitmap(BitmapFrame frameWpf) - { - MetadataExtractor metadata = new MetadataExtractor(); - metadata.InitViaWpf(frameWpf); - return metadata; - } -#endif - #endregion - } -} diff --git a/Source/Components/ImageGlass.ImageListView/OpenFileDialogEditor.cs b/Source/Components/ImageGlass.ImageListView/OpenFileDialogEditor.cs deleted file mode 100644 index 893745171..000000000 --- a/Source/Components/ImageGlass.ImageListView/OpenFileDialogEditor.cs +++ /dev/null @@ -1,78 +0,0 @@ -// ImageListView - A listview control for image files -// Copyright (C) 2009 Ozgur Ozcitak -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// Ozgur Ozcitak (ozcitak@yahoo.com) - -using System; -using System.Drawing.Design; -using System.Windows.Forms; -using System.ComponentModel; - -namespace ImageGlass.ImageListView -{ - /// - /// Displays a open file dialog box on the property grid. - /// - internal class OpenFileDialogEditor : UITypeEditor - { - #region UITypeEditor Overrides - /// - /// Gets the edit style. - /// - /// The context. - /// The edit style. - public override UITypeEditorEditStyle GetEditStyle(ITypeDescriptorContext context) - { - if (context != null && context.Instance != null) - return UITypeEditorEditStyle.Modal; - - return UITypeEditorEditStyle.None; - } - - //[RefreshProperties(RefreshProperties.All)] - /// - /// Edits the value. - /// - /// The context. - /// The provider. - /// The value. - /// New value. - public override object EditValue(ITypeDescriptorContext context, IServiceProvider provider, object value) - { - if (provider != null && context != null && context.Instance != null) - { - using (OpenFileDialog dlg = new OpenFileDialog()) - { - string filename = (value != null) ? (string)value : ""; - - dlg.FileName = filename; - dlg.Title = "Select " + context.PropertyDescriptor.DisplayName; - dlg.Filter = "All image files (*.bmp, *.gif, *.jpg, *.jpeg, *.jpe, *.jif, *.png, *.tif, *.tiff, *.tga)|" + - "*.bmp;*.gif;*.jpg;*.jpeg;*.jpe;*.jif;*.png;*.tif;*.tiff;*.tga|" + - "BMP (*.bmp)|*.bmp|GIF (*.gif)|*.gif|JPEG (*.jpg, *.jpeg, *.jpe, *.jif)|*.jpg;*.jpeg;*.jpe;*.jif|" + - "PNG (*.png)|*.png|TIFF (*.tif, *.tiff)|*.tif;*.tiff|TGA (*.tga)|*.tga|All files (*.*)|*.*"; - - if (dlg.ShowDialog() == DialogResult.OK) - filename = dlg.FileName; - - return filename; - } - } - - return base.EditValue(provider, value); - } - #endregion - } -} diff --git a/Source/Components/ImageGlass.ImageListView/Properties/AssemblyInfo.cs b/Source/Components/ImageGlass.ImageListView/Properties/AssemblyInfo.cs deleted file mode 100644 index 616ee3054..000000000 --- a/Source/Components/ImageGlass.ImageListView/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,52 +0,0 @@ -// ImageListView - A listview control for image files -// Copyright (C) 2009 Ozgur Ozcitak -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// Ozgur Ozcitak (ozcitak@yahoo.com) - -using System.Reflection; -using System.Runtime.InteropServices; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyTitle("ImageGlass.ImageListView")] -[assembly: AssemblyDescription("A customized listview control based on ImageListView of Ozgur Ozcitak")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("Duong Dieu Phap")] -[assembly: AssemblyProduct("ImageListView")] -[assembly: AssemblyCopyright("Copyright © 2009 Ozgur Ozcitak")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. -[assembly: ComVisible(false)] - -// The following GUID is for the ID of the typelib if this project is exposed to COM -[assembly: Guid("3eb67a8d-4c80-4c11-944d-c99ef0ec7eb9")] - -// Version information for an assembly consists of the following four values: -// -// Major Version -// Minor Version -// Build Number -// Revision -// -// You can specify all the values or you can default the Build and Revision Numbers -// by using the '*' as shown below: -// [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("11.0.0.6")] -[assembly: AssemblyFileVersion("11.0.0.6")] diff --git a/Source/Components/ImageGlass.ImageListView/QueuedBackgroundWorker.bmp b/Source/Components/ImageGlass.ImageListView/QueuedBackgroundWorker.bmp deleted file mode 100644 index 1e1dcf8ed..000000000 Binary files a/Source/Components/ImageGlass.ImageListView/QueuedBackgroundWorker.bmp and /dev/null differ diff --git a/Source/Components/ImageGlass.ImageListView/QueuedBackgroundWorker.cs b/Source/Components/ImageGlass.ImageListView/QueuedBackgroundWorker.cs deleted file mode 100644 index b350b7b61..000000000 --- a/Source/Components/ImageGlass.ImageListView/QueuedBackgroundWorker.cs +++ /dev/null @@ -1,562 +0,0 @@ -using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.Threading; -using System.Drawing; - -namespace ImageGlass.ImageListView -{ - /// - /// A background worker with a work queue. - /// - [Description("A background worker with a work queue.")] - [ToolboxBitmap(typeof(QueuedBackgroundWorker))] - [DefaultEvent("DoWork")] - public class QueuedBackgroundWorker : Component - { - #region Member Variables - private readonly object lockObject; - - private ProcessingMode processingMode; - private int threadCount; - private Thread[] threads; - private bool stopping; - private bool started; - private bool disposed; - private bool paused; - - private int priorityQueues; - private LinkedList[] items; - private AsyncOperation[] singleItems; - private Dictionary cancelledItems; - - private readonly SendOrPostCallback workCompletedCallback; - #endregion - - #region Constructor - /// - /// Initializes a new instance of the class. - /// - public QueuedBackgroundWorker () - { - lockObject = new object (); - stopping = false; - started = false; - disposed = false; - paused = false; - - // Threads - threadCount = 5; - CreateThreads (); - - // Work items - processingMode = ProcessingMode.FIFO; - priorityQueues = 5; - BuildWorkQueue (); - cancelledItems = new Dictionary (); - - // The loader complete callback - workCompletedCallback = new SendOrPostCallback (RunWorkerCompletedCallback); - } - #endregion - - #region RunWorkerAsync - /// - /// Starts processing a new background operation. - /// - /// The argument of an asynchronous operation. - /// A value between 0 and indicating the priority of this item. - /// An item with a higher priority will be processed before items with lower priority. - /// true to run this operation without waiting for queued items; otherwise - /// false to add this operatino to th queue. - public void RunWorkerAsync (object argument, int priority, bool single) - { - if (priority < 0 || priority >= priorityQueues) - throw new ArgumentException ("priority must be between 0 and " + (priorityQueues - 1).ToString () + " inclusive.", "priority"); - - // Start the worker threads - if (!started) { - // Start the thread - for (int i = 0; i < threadCount; i++) { - threads[i].Start (); - while (!threads[i].IsAlive) - ; - } - - started = true; - } - - lock (lockObject) { - AddWork (argument, priority, single); - Monitor.Pulse (lockObject); - } - } - /// - /// Starts processing a new background operation. - /// - /// The argument of an asynchronous operation. - /// A value between 0 and indicating the priority of this item. - /// An item with a higher priority will be processed before items with lower priority. - public void RunWorkerAsync (object argument, int priority) - { - RunWorkerAsync (argument, priority, false); - } - /// - /// Starts processing a new background operation. - /// - /// The argument of an asynchronous operation. - public void RunWorkerAsync (object argument) - { - RunWorkerAsync (argument, 0, false); - } - /// - /// Starts processing a new background operation. - /// - public void RunWorkerAsync () - { - RunWorkerAsync (null, 0, false); - } - #endregion - - #region Work Queue Access - /// - /// Determines if the work queue is empty. - /// This method must be called from inside a lock. - /// - /// true if the work queue is empty; otherwise false. - private bool IsWorkQueueEmpty () - { - foreach (AsyncOperation asyncOp in singleItems) { - if (asyncOp != null) - return false; - } - - foreach (LinkedList queue in items) { - if (queue.Count > 0) - return false; - } - - return true; - } - /// - /// Adds the operation to the work queue. - /// This method must be called from inside a lock. - /// - /// The argument of an asynchronous operation. - /// A value between 0 and indicating the priority of this item. - /// An item with a higher priority will be processed before items with lower priority. - /// true to run this operation without waiting for queued items; otherwise - /// false to add this operatino to th queue. - private void AddWork (object argument, int priority, bool single) - { - // Create an async operation for this work item - AsyncOperation asyncOp = AsyncOperationManager.CreateOperation (argument); - - if (single) { - AsyncOperation currentOp = singleItems[priority]; - if (currentOp != null) - currentOp.OperationCompleted (); - singleItems[priority] = asyncOp; - } else if (processingMode == ProcessingMode.FIFO) - items[priority].AddLast (asyncOp); - else - items[priority].AddFirst (asyncOp); - } - /// - /// Gets a pending operation from the work queue. - /// This method must be called from inside a lock. - /// - /// A 2-tuple whose first component is the the pending operation with - /// the highest priority from the work queue and the second component is the - /// priority. - private Utility.Tuple GetWork () - { - AsyncOperation request = null; - int priority = 0; - - for (int i = priorityQueues - 1; i >= 0; i--) { - request = singleItems[i]; - if (request != null) { - singleItems[i] = null; - priority = i; - break; - } - } - - if (request == null) { - for (int i = priorityQueues - 1; i >= 0; i--) { - if (items[i].Count > 0) { - priority = i; - request = items[i].First.Value; - items[i].RemoveFirst (); - break; - } - } - } - - return Utility.Tuple.Create (request, priority); - } - /// - /// Rebuilds the work queue. - /// This method must be called from inside a lock. - /// - private void BuildWorkQueue () - { - singleItems = new AsyncOperation[priorityQueues]; - items = new LinkedList[priorityQueues]; - for (int i = 0; i < priorityQueues; i++) - items[i] = new LinkedList (); - } - /// - /// Clears all work queues. - /// This method must be called from inside a lock. - /// - private void ClearWorkQueue () - { - for (int i = 0; i < priorityQueues; i++) - ClearWorkQueue (i); - } - /// - /// Clears the work queue with the given priority. - /// This method must be called from inside a lock. - /// - /// A value between 0 and - /// indicating the priority queue to cancel. - private void ClearWorkQueue (int priority) - { - AsyncOperation singleOp = singleItems[priority]; - if (singleOp != null) { - singleOp.OperationCompleted (); - singleItems[priority] = null; - } - - while (items[priority].Count > 0) { - AsyncOperation asyncOp = items[priority].First.Value; - asyncOp.OperationCompleted (); - items[priority].RemoveFirst (); - } - } - #endregion - - #region Worker Threads - /// - /// Creates the thread array. - /// - private void CreateThreads () - { - threads = new Thread[threadCount]; - for (int i = 0; i < threadCount; i++) { - threads[i] = new Thread (new ThreadStart (Run)); - threads[i].IsBackground = true; - } - } - #endregion - - #region Properties - /// - /// Represents the mode in which the work items are processed. - /// Processing mode cannot be changed after any work is added to the work queue. - /// - [Browsable(true), Category("Behaviour"), DefaultValue(typeof(ProcessingMode), "FIFO")] - public ProcessingMode ProcessingMode { - get { return processingMode; } - set { - if (started) - throw new System.Threading.ThreadStateException ("The thread has already been started."); - - processingMode = value; - BuildWorkQueue (); - } - } - /// - /// Gets or sets the number of priority queues. Number of queues - /// cannot be changed after any work is added to the work queue. - /// - [Browsable(true), Category("Behaviour"), DefaultValue(5)] - public int PriorityQueues { - get { return priorityQueues; } - set { - if (started) - throw new System.Threading.ThreadStateException ("The thread has already been started."); - - priorityQueues = value; - BuildWorkQueue (); - } - } - /// - /// Determines whether the started working. - /// - [Browsable(false), Description("Determines whether the QueuedBackgroundWorker started working."), Category("Behavior")] - public bool Started { - get { return started; } - } - /// - /// Gets or sets a value indicating whether or not the worker thread is a background thread. - /// - [Browsable(true), Description("Gets or sets a value indicating whether or not the worker thread is a background thread."), Category("Behavior")] - public bool IsBackground { - get { return threads[0].IsBackground; } - set { - for (int i = 0; i < threadCount; i++) - threads[i].IsBackground = value; - } - } - /// - /// Determines whether the is paused. - /// - private bool Paused { - get { - lock (lockObject) { - return paused; - } - } - } - /// - /// Determines whether the is being stopped. - /// - private bool Stopping { - get { - lock (lockObject) { - return stopping; - } - } - } - /// - /// Gets or sets the number of worker threads. Number of threads - /// cannot be changed after any work is added to the work queue. - /// - [Browsable(true), Category("Behaviour"), DefaultValue(5)] - public int Threads { - get { return threadCount; } - set { - if (started) - throw new System.Threading.ThreadStateException ("The thread has already been started."); - - threadCount = value; - CreateThreads (); - } - } - #endregion - - #region Cancel/Pause - /// - /// Pauses the worker. - /// - public void Pause () - { - lock (lockObject) { - paused = true; - Monitor.Pulse (lockObject); - } - } - /// - /// Resumes processing pending operations in the work queue. - /// - public void Resume () - { - lock (lockObject) { - paused = false; - Monitor.Pulse (lockObject); - } - } - /// - /// Cancels all pending operations in all queues. - /// - public void CancelAsync () - { - lock (lockObject) { - ClearWorkQueue (); - Monitor.Pulse (lockObject); - } - } - /// - /// Cancels all pending operations in the given queue. - /// - /// A value between 0 and - /// indicating the priority queue to cancel. - public void CancelAsync (int priority) - { - if (priority < 0 || priority >= priorityQueues) - throw new ArgumentException ("priority must be between 0 and " + (priorityQueues - 1).ToString () + " inclusive.", "priority"); - - lock (lockObject) { - ClearWorkQueue (priority); - Monitor.Pulse (lockObject); - } - } - /// - /// Cancels processing the item with the given key. - /// - /// The argument of an asynchronous operation. - public void CancelAsync (object argument) - { - lock (lockObject) { - if (!cancelledItems.ContainsKey (argument)) { - cancelledItems.Add (argument, false); - Monitor.Pulse (lockObject); - } - } - } - #endregion - - #region Delegate Callbacks - /// - /// Used to call by the synchronization context. - /// - /// The argument. - private void RunWorkerCompletedCallback (object arg) - { - OnRunWorkerCompleted ((QueuedWorkerCompletedEventArgs)arg); - } - #endregion - - #region Virtual Methods - /// - /// Raises the RunWorkerCompleted event. - /// [IG_CHANGE] Issue #359: unhandled exception could cause next invocation to crash - /// - /// A that contains event data. - protected virtual void OnRunWorkerCompleted (QueuedWorkerCompletedEventArgs e) - { - try - { - if (RunWorkerCompleted != null) - RunWorkerCompleted(this, e); - } - catch { } // [IG_CHANGE] not un-caught exceptions - - } - /// - /// Raises the DoWork event. - /// - /// A that contains event data. - protected virtual void OnDoWork (QueuedWorkerDoWorkEventArgs e) - { - if (DoWork != null) - DoWork (this, e); - } - #endregion - - #region Get/Set Apartment State - /// - /// Gets the apartment state of worker threads. - /// - /// The apartment state of worker threads. - public ApartmentState GetApartmentState () - { - return threads[0].GetApartmentState (); - } - /// - /// Sets the apartment state of worker threads. The apartment state - /// cannot be changed after any work is added to the work queue. - /// - /// The new state of worker threads. - public void SetApartmentState (ApartmentState state) - { - for (int i = 0; i < threadCount; i++) - threads[i].SetApartmentState (state); - } - #endregion - - #region Public Events - /// - /// Occurs when the background operation of an item has completed, - /// has been canceled, or has raised an exception. - /// - [Category("Behavior"), Browsable(true), Description("Occurs when the background operation of an item has completed.")] - public event RunQueuedWorkerCompletedEventHandler RunWorkerCompleted; - /// - /// Occurs when is called. - /// - [Category("Behavior"), Browsable(true), Description("Occurs when RunWorkerAsync is called.")] - public event QueuedWorkerDoWorkEventHandler DoWork; - #endregion - - #region Worker Method - /// - /// Used by the worker thread to process items. - /// - private void Run () - { - while (!Stopping) { - lock (lockObject) { - // Wait until we have pending work items - if (paused || IsWorkQueueEmpty ()) - Monitor.Wait (lockObject); - } - - // Loop until we exhaust the queue - bool queueFull = true; - while (queueFull && !Stopping && !Paused) { - // Get an item from the queue - AsyncOperation asyncOp = null; - object request = null; - int priority = 0; - lock (lockObject) { - // Check queues - Utility.Tuple work = GetWork (); - asyncOp = work.Item1; - priority = work.Item2; - if (asyncOp != null) - request = asyncOp.UserSuppliedState; - - // Check if the item was removed - if (request != null && cancelledItems.ContainsKey (request)) - request = null; - } - - if (request != null) { - Exception error = null; - // Start the work - QueuedWorkerDoWorkEventArgs doWorkArg = new QueuedWorkerDoWorkEventArgs (request, priority); - try { - // Raise the do work event - OnDoWork (doWorkArg); - } catch (Exception e) { - error = e; - } - - // Raise the work complete event - QueuedWorkerCompletedEventArgs workCompletedArg = new QueuedWorkerCompletedEventArgs (request, doWorkArg.Result, priority, error, doWorkArg.Cancel); - if (!Stopping) - asyncOp.PostOperationCompleted (workCompletedCallback, workCompletedArg); - } else if (asyncOp != null) - asyncOp.OperationCompleted (); - - // Check if the cache is exhausted - lock (lockObject) { - queueFull = !IsWorkQueueEmpty (); - } - } - } - } - #endregion - - #region Dispose - /// - /// Releases the unmanaged resources used by the - /// and optionally releases the managed resources. - /// - /// true to release both managed and unmanaged resources; - /// false to release only unmanaged resources. - protected override void Dispose (bool disposing) - { - base.Dispose (disposing); - - if (disposed) - return; - - lock (lockObject) { - if (!stopping) { - stopping = true; - ClearWorkQueue (); - cancelledItems.Clear (); - Monitor.Pulse (lockObject); - } - } - - disposed = true; - } - #endregion - } -} diff --git a/Source/Components/ImageGlass.ImageListView/QueuedBackgroundWorkerEvents.cs b/Source/Components/ImageGlass.ImageListView/QueuedBackgroundWorkerEvents.cs deleted file mode 100644 index 3b0a3d02f..000000000 --- a/Source/Components/ImageGlass.ImageListView/QueuedBackgroundWorkerEvents.cs +++ /dev/null @@ -1,75 +0,0 @@ -using System; -using System.ComponentModel; - -namespace ImageGlass.ImageListView -{ - #region Event Delegates - /// - /// Represents the method that will handle the RunWorkerCompleted event. - /// - /// The object that is the source of the event. - /// A that contains event data. - [EditorBrowsable(EditorBrowsableState.Never)] - public delegate void RunQueuedWorkerCompletedEventHandler(object sender, QueuedWorkerCompletedEventArgs e); - /// - /// Represents the method that will handle the DoWork event. - /// - /// The object that is the source of the event. - /// An that contains event data. - [EditorBrowsable(EditorBrowsableState.Never)] - public delegate void QueuedWorkerDoWorkEventHandler(object sender, QueuedWorkerDoWorkEventArgs e); - #endregion - - #region Event Arguments - /// - /// Represents the event arguments of the RunWorkerCompleted event. - /// - public class QueuedWorkerCompletedEventArgs : AsyncCompletedEventArgs - { - /// - /// Gets a value that represents the result of an asynchronous operation. - /// - public object Result { get; private set; } - /// - /// Gets the priority of this item. - /// - public int Priority { get; private set; } - - /// - /// Initializes a new instance of the QueuedWorkerCompletedEventArgs class. - /// - /// The argument of an asynchronous operation. - /// The result of an asynchronous operation. - /// A value between 0 and 5 indicating the priority of this item. - /// The error that occurred while loading the image. - /// A value indicating whether the asynchronous operation was canceled. - public QueuedWorkerCompletedEventArgs(object argument, object result, int priority, Exception error, bool cancelled) - : base(error, cancelled, argument) - { - Result = result; - Priority = priority; - } - } - /// - /// Represents the event arguments of the RunWorkerCompleted event. - /// - public class QueuedWorkerDoWorkEventArgs : DoWorkEventArgs - { - /// - /// Gets the priority of this item. - /// - public int Priority { get; private set; } - - /// - /// Initializes a new instance of the QueuedWorkerDoWorkEventArgs class. - /// - /// The argument of an asynchronous operation. - /// A value between 0 and 5 indicating the priority of this item. - public QueuedWorkerDoWorkEventArgs(object argument, int priority) - : base(argument) - { - Priority = priority; - } - } - #endregion -} diff --git a/Source/Components/ImageGlass.ImageListView/Resources/DefaultImage.png b/Source/Components/ImageGlass.ImageListView/Resources/DefaultImage.png deleted file mode 100644 index fc3c393ca..000000000 Binary files a/Source/Components/ImageGlass.ImageListView/Resources/DefaultImage.png and /dev/null differ diff --git a/Source/Components/ImageGlass.ImageListView/Resources/EmptyRatingImage.png b/Source/Components/ImageGlass.ImageListView/Resources/EmptyRatingImage.png deleted file mode 100644 index defb4ae50..000000000 Binary files a/Source/Components/ImageGlass.ImageListView/Resources/EmptyRatingImage.png and /dev/null differ diff --git a/Source/Components/ImageGlass.ImageListView/Resources/ErrorImage.png b/Source/Components/ImageGlass.ImageListView/Resources/ErrorImage.png deleted file mode 100644 index c37bd062e..000000000 Binary files a/Source/Components/ImageGlass.ImageListView/Resources/ErrorImage.png and /dev/null differ diff --git a/Source/Components/ImageGlass.ImageListView/Resources/RatingImage.png b/Source/Components/ImageGlass.ImageListView/Resources/RatingImage.png deleted file mode 100644 index b88c85789..000000000 Binary files a/Source/Components/ImageGlass.ImageListView/Resources/RatingImage.png and /dev/null differ diff --git a/Source/Components/ImageGlass.ImageListView/Resources/SortAscending.png b/Source/Components/ImageGlass.ImageListView/Resources/SortAscending.png deleted file mode 100644 index 02f525f77..000000000 Binary files a/Source/Components/ImageGlass.ImageListView/Resources/SortAscending.png and /dev/null differ diff --git a/Source/Components/ImageGlass.ImageListView/Resources/SortDescending.png b/Source/Components/ImageGlass.ImageListView/Resources/SortDescending.png deleted file mode 100644 index dd9927ca3..000000000 Binary files a/Source/Components/ImageGlass.ImageListView/Resources/SortDescending.png and /dev/null differ diff --git a/Source/Components/ImageGlass.ImageListView/ShellInfoExtractor.cs b/Source/Components/ImageGlass.ImageListView/ShellInfoExtractor.cs deleted file mode 100644 index 545522843..000000000 --- a/Source/Components/ImageGlass.ImageListView/ShellInfoExtractor.cs +++ /dev/null @@ -1,199 +0,0 @@ -// ImageListView - A listview control for image files -// Copyright (C) 2009 Ozgur Ozcitak -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// Ozgur Ozcitak (ozcitak@yahoo.com) - -using System; -using System.IO; -using System.Drawing; -using System.Runtime.InteropServices; - -namespace ImageGlass.ImageListView -{ - /// - /// Reads shell icons and shell file types. - /// - internal class ShellInfoExtractor - { - #region Platform Invoke - // GetFileAttributesEx - [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)] - [return: MarshalAs(UnmanagedType.Bool)] - private static extern bool GetFileAttributesEx(string lpFileName, - GET_FILEEX_INFO_LEVELS fInfoLevelId, - out WIN32_FILE_ATTRIBUTE_DATA fileData); - - private enum GET_FILEEX_INFO_LEVELS - { - GetFileExInfoStandard, - GetFileExMaxInfoLevel - } - [StructLayout(LayoutKind.Sequential)] - private struct WIN32_FILE_ATTRIBUTE_DATA - { - public FileAttributes dwFileAttributes; - public FILETIME ftCreationTime; - public FILETIME ftLastAccessTime; - public FILETIME ftLastWriteTime; - public uint nFileSizeHigh; - public uint nFileSizeLow; - } - [StructLayout(LayoutKind.Sequential)] - private struct FILETIME - { - public uint dwLowDateTime; - public uint dwHighDateTime; - - public DateTime Value - { - get - { - long longTime = (((long)dwHighDateTime) << 32) | ((uint)dwLowDateTime); - return DateTime.FromFileTimeUtc(longTime); - } - } - } - // DestroyIcon - [DllImport("user32.dll", SetLastError = true)] - [return: MarshalAs(UnmanagedType.Bool)] - private static extern bool DestroyIcon(IntPtr hIcon); - // SHGetFileInfo - [DllImport("shell32.dll", CharSet = CharSet.Auto)] - private static extern IntPtr SHGetFileInfo(string pszPath, FileAttributes dwFileAttributes, out SHFILEINFO psfi, uint cbFileInfo, SHGFI uFlags); - [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] - private struct SHFILEINFO - { - public IntPtr hIcon; - public int iIcon; - public uint dwAttributes; - [MarshalAs(UnmanagedType.ByValTStr, SizeConst = MAX_PATH)] - public string szDisplayName; - [MarshalAs(UnmanagedType.ByValTStr, SizeConst = MAX_TYPE)] - public string szTypeName; - }; - private const int MAX_PATH = 260; - private const int MAX_TYPE = 80; - [Flags] - private enum SHGFI : uint - { - Icon = 0x000000100, - DisplayName = 0x000000200, - TypeName = 0x000000400, - Attributes = 0x000000800, - IconLocation = 0x000001000, - ExeType = 0x000002000, - SysIconIndex = 0x000004000, - LinkOverlay = 0x000008000, - Selected = 0x000010000, - Attr_Specified = 0x000020000, - LargeIcon = 0x000000000, - SmallIcon = 0x000000001, - OpenIcon = 0x000000002, - ShellIconSize = 0x000000004, - PIDL = 0x000000008, - UseFileAttributes = 0x000000010, - AddOverlays = 0x000000020, - OverlayIndex = 0x000000040, - } - #endregion - - #region Shell Properties - /// - /// Error. - /// - public Exception Error = null; - /// - /// Mime type. - /// - public string FileType = null; - /// - /// Small shell icon. - /// - public Image SmallIcon = null; - /// - /// Large shell icon. - /// - public Image LargeIcon = null; - #endregion - - #region Constructor - /// - /// Initializes a new instance of the ShellInfoExtractor class. - /// - private ShellInfoExtractor() - { - ; - } - #endregion - - #region Public Methods - /// - /// Creates an instance of the ShellInfoExtractor class. - /// - /// Filepath of image - public static ShellInfoExtractor FromFile(string path) - { - ShellInfoExtractor info = new ShellInfoExtractor(); - - try - { - SHFILEINFO shinfo = new SHFILEINFO(); - uint structSize = (uint)Marshal.SizeOf(shinfo); - SHGFI flags = SHGFI.Icon | SHGFI.SmallIcon | SHGFI.TypeName | SHGFI.UseFileAttributes; - - // Get the small icon and shell file type - IntPtr hImg = SHGetFileInfo(path, FileAttributes.Normal, out shinfo, - structSize, flags); - - // Get mime type - info.FileType = shinfo.szTypeName; - - // Get small icon - if (hImg != IntPtr.Zero && shinfo.hIcon != IntPtr.Zero) - { - using (Icon newIcon = System.Drawing.Icon.FromHandle(shinfo.hIcon)) - { - info.SmallIcon = newIcon.ToBitmap(); - } - DestroyIcon(shinfo.hIcon); - } - else - info.Error = new Exception("Error reading shell icon"); - - // Get large icon - hImg = SHGetFileInfo(path, FileAttributes.Normal, out shinfo, - structSize, SHGFI.Icon | SHGFI.LargeIcon | SHGFI.UseFileAttributes); - - if (hImg != IntPtr.Zero && shinfo.hIcon != IntPtr.Zero) - { - using (Icon newIcon = System.Drawing.Icon.FromHandle(shinfo.hIcon)) - { - info.LargeIcon = newIcon.ToBitmap(); - } - DestroyIcon(shinfo.hIcon); - } - else - info.Error = new Exception("Error reading shell icon"); - } - catch (Exception e) - { - info.Error = e; - } - - return info; - } - #endregion - } -} diff --git a/Source/Components/ImageGlass.ImageListView/StringCache.cs b/Source/Components/ImageGlass.ImageListView/StringCache.cs deleted file mode 100644 index 474d5c9b6..000000000 --- a/Source/Components/ImageGlass.ImageListView/StringCache.cs +++ /dev/null @@ -1,102 +0,0 @@ -// A string cache -// Author: Kevin Routley -/* -ImageGlass Project - Image viewer for Windows -Copyright (C) 2019 DUONG DIEU PHAP -Project homepage: https://imageglass.org - -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 . - -Author: Kevin Routley (aka fire-eggs) -*/ - -using System; -using System.Collections.Concurrent; -using System.Collections.Generic; - -namespace ImageGlass.ImageListView -{ - /// - /// A string cache. - /// - public class StringCache - { - // A comparator is necessary because just using vanilla char[] will result in - // a different hash for each *instance*. This comparator works on the contents. - private class TagComparer : IEqualityComparer - { - public bool Equals(char[] x, char[] y) - { - if (x == null && y == null) - return true; - if (x == null || y == null) // One but not both? - return false; - if (x.Length != y.Length) - return false; - for (int i = 0; i < x.Length; i++) - if (x[i] != y[i]) - return false; - return true; - } - - public int GetHashCode(char[] obj) - { - if (obj.Length == 0) - return 0; - var hashCode = 0; - for (var i = 0; i < obj.Length; i++) - { - var bytes = BitConverter.GetBytes(obj[i]); - - // Rotate by 3 bits and XOR the new value. - for (var j = 0; j < bytes.Length; j++) - hashCode = (hashCode << 3) | (hashCode >> (29)) ^ bytes[j]; - } - return hashCode; - } - } - - // Concurrent dictionary used for parallelism - private readonly ConcurrentDictionary _stringCache; - - /// - /// Create a basic string cache. - /// - public StringCache() - { - //int numProcs = Environment.ProcessorCount; - _stringCache = new ConcurrentDictionary(new TagComparer()); - } - - /// - /// Fetch or add a string from the cache - /// - /// input string to be cached - /// the string from the cache - public string GetFromCache(string inval) - { - return GetFromCache(inval.ToCharArray()); - } - - private string GetFromCache(char[] inval) - { - if (!_stringCache.TryGetValue(inval, out var outval)) - { - outval = new string(inval); - _stringCache.TryAdd(inval, outval); - } - return outval; - } - } -} diff --git a/Source/Components/ImageGlass.ImageListView/ThumbnailExtractor.cs b/Source/Components/ImageGlass.ImageListView/ThumbnailExtractor.cs deleted file mode 100644 index 468590e86..000000000 --- a/Source/Components/ImageGlass.ImageListView/ThumbnailExtractor.cs +++ /dev/null @@ -1,660 +0,0 @@ -// ImageListView - A listview control for image files -// Copyright (C) 2009 Ozgur Ozcitak -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// Ozgur Ozcitak (ozcitak@yahoo.com) -// -// WIC support coded by Jens - -using System; -using System.IO; -using System.Drawing.Imaging; -using System.Drawing; -using System.Drawing.Drawing2D; -#if USEWIC -using System.Runtime.ExceptionServices; -using System.Windows.Media; -using System.Windows.Media.Imaging; -#endif - -namespace ImageGlass.ImageListView -{ - /// - /// Extracts thumbnails from images. - /// - internal static class ThumbnailExtractor - { - #region Exif Tag IDs - private const int TagThumbnailData = 0x501B; - private const int TagOrientation = 0x0112; - #endregion - -#if USEWIC - #region WIC Metadata Paths - private static readonly string[] WICPathOrientation = new string[] { "/app1/ifd/{ushort=274}", "/xmp/tiff:Orientation" }; - #endregion -#endif - - #region Public Methods - /// - /// Creates a thumbnail from the given image. - /// - /// The source image. - /// Requested image size. - /// Embedded thumbnail usage. - /// true to automatically rotate images based on Exif orientation; otherwise false. - /// true to use Windows Imaging Component; otherwise false. - /// The thumbnail image from the given image or null if an error occurs. - public static Image FromImage(Image image, Size size, UseEmbeddedThumbnails useEmbeddedThumbnails, bool useExifOrientation, bool useWIC) - { - if (size.Width <= 0 || size.Height <= 0) - throw new ArgumentException(); - - if (useWIC) - { -#if USEWIC - MemoryStream stream = null; - BitmapFrame frameWpf = null; - try - { - stream = new MemoryStream(); - - image.Save(stream, ImageFormat.Bmp); - // Performance vs image quality settings. - // Selecting BitmapCacheOption.None speeds up thumbnail generation of large images tremendously - // if the file contains no embedded thumbnail. The image quality is only slightly worse. - stream.Seek(0, SeekOrigin.Begin); - frameWpf = BitmapFrame.Create(stream, - BitmapCreateOptions.IgnoreColorProfile, - BitmapCacheOption.None); - } - catch - { - if (stream != null) - { - stream.Dispose(); - stream = null; - } - frameWpf = null; - } - - if (stream == null || frameWpf == null) - { - if (stream != null) - { - stream.Dispose(); - stream = null; - } - - // .Net 2.0 fallback - Image img = GetThumbnailBmp(image, size, - useExifOrientation ? GetRotation(image) : 0); - return img; - } - - Image thumb = GetThumbnail(frameWpf, size, useEmbeddedThumbnails, - useExifOrientation ? GetRotation(frameWpf) : 0); - stream.Dispose(); - return thumb; -#else - // .Net 2.0 fallback - return GetThumbnailBmp(image, size, - useExifOrientation ? GetRotation(image) : 0); -#endif - } - else - { - // .Net 2.0 fallback - return GetThumbnailBmp(image, size, - useExifOrientation ? GetRotation(image) : 0); - } - } - /// - /// Creates a thumbnail from the given image file. - /// - /// - /// This much faster .NET 3.0 method replaces the original .NET 2.0 method. - /// The image quality is slightly reduced (low filtering mode). - /// - /// The filename pointing to an image. - /// Requested image size. - /// Embedded thumbnail usage. - /// true to automatically rotate images based on Exif orientation; otherwise false. - /// true to use Windows Imaging Component; otherwise false. - /// The thumbnail image from the given file or null if an error occurs. -#if USEWIC - // KBR 20190729 BitmapFrame.Create will throw an AccessViolation exception which is treated - // as a corrupted state (and IG shutdown) _unless_ this decorator is added - [HandleProcessCorruptedStateExceptions] -#endif - public static Image FromFile(string filename, Size size, UseEmbeddedThumbnails useEmbeddedThumbnails, bool useExifOrientation, bool useWIC) - { - if (string.IsNullOrEmpty(filename)) - throw new ArgumentException("Filename cannot be empty", "filename"); - - if (size.Width <= 0 || size.Height <= 0) - throw new ArgumentException("Thumbnail size cannot be empty.", "size"); - - if (useWIC) - { -#if USEWIC - try - { - using (FileStream stream = File.Open(filename, FileMode.Open, FileAccess.Read, FileShare.Read)) - { - // Performance vs image quality settings. - // Selecting BitmapCacheOption.None speeds up thumbnail generation of large images tremendously - // if the file contains no embedded thumbnail. The image quality is only slightly worse. - BitmapFrame frameWpf = BitmapFrame.Create(stream, - BitmapCreateOptions.IgnoreColorProfile, - BitmapCacheOption.None); - return GetThumbnail(frameWpf, size, useEmbeddedThumbnails, - useExifOrientation ? GetRotation(frameWpf) : 0); - } - } - catch - { - // .Net 2.0 fallback - return GetThumbnailBmp(filename, size, useEmbeddedThumbnails, - useExifOrientation ? GetRotation(filename) : 0); - } -#else - // .Net 2.0 fallback - return GetThumbnailBmp(filename, size, useEmbeddedThumbnails, - useExifOrientation ? GetRotation(filename) : 0); -#endif - } - else - { - // .Net 2.0 fallback - return GetThumbnailBmp(filename, size, useEmbeddedThumbnails, - useExifOrientation ? GetRotation(filename) : 0); - } - } - #endregion - - #region Helper Methods - /// - /// Creates a thumbnail from the given image. - /// - /// The source image. - /// Requested image size. - /// Rotation angle. - /// The image from the given file or null if an error occurs. - internal static Image GetThumbnailBmp(Image image, Size size, int rotate) - { - if (size.Width <= 0 || size.Height <= 0) - throw new ArgumentException(); - - Image thumb = null; - try - { - double scale; - if (rotate % 180 != 0) - { - scale = Math.Min(size.Height / (double)image.Width, - size.Width / (double)image.Height); - } - else - { - scale = Math.Min(size.Width / (double)image.Width, - size.Height / (double)image.Height); - } - - thumb = ScaleDownRotateBitmap(image, scale, rotate); - } - catch - { - if (thumb != null) - thumb.Dispose(); - thumb = null; - } - - return thumb; - } - /// - /// [IGChange] Creates a thumbnail from the given image file. - /// - /// The filename pointing to an image. - /// Requested image size. - /// Embedded thumbnail usage. - /// Rotation angle. - /// The image from the given file or null if an error occurs. - internal static Image GetThumbnailBmp(string filename, Size size, UseEmbeddedThumbnails useEmbeddedThumbnails, int rotate) - { - if (size.Width <= 0 || size.Height <= 0) - throw new ArgumentException(); - - var source = Heart.Photo.GetThumbnail(filename, size, useEmbeddedThumbnails != UseEmbeddedThumbnails.Never); - - // If all failed, return null. - if (source == null) - return null; - - // Create the thumbnail - Image thumb = null; - try - { - thumb = GetThumbnailBmp(source, size, rotate); - } - finally - { - if (source != null) - source.Dispose(); - } - - return thumb; - } -#if USEWIC - /// - /// Returns Exif rotation in degrees. Returns 0 if the metadata - /// does not exist or could not be read. A negative value means - /// the image needs to be mirrored about the vertical axis. - /// - /// Image source. - private static int GetRotation(BitmapFrame frameWpf) - { - BitmapMetadata data = frameWpf.Metadata as BitmapMetadata; - if (data != null) - { - try - { - // read orientation metadata - object obj = GetMetadataObject(data, WICPathOrientation); - if (obj == null) - return 0; - ushort orientationFlag = (ushort)obj; - if (orientationFlag == 1) - return 0; - else if (orientationFlag == 2) - return -360; - else if (orientationFlag == 3) - return 180; - else if (orientationFlag == 4) - return -180; - else if (orientationFlag == 5) - return -90; - else if (orientationFlag == 6) - return 90; - else if (orientationFlag == 7) - return -270; - else if (orientationFlag == 8) - return 270; - } - catch - { - ; - } - } - - return 0; - } - /// - /// Returns the metadata for the given query. - /// - /// The image metadata. - /// A list of query strings. - /// Metadata object or null if the metadata is not found. - private static object GetMetadataObject(BitmapMetadata metadata, params string[] query) - { - foreach (string q in query) - { - object val = metadata.GetQuery(q); - if (val != null) - return val; - } - return null; - } - /// - /// Creates a thumbnail from the given bitmap. - /// - /// Source bitmap. - /// Requested image size. - /// Embedded thumbnail usage. - /// Rotation angle in degrees. - private static Image GetThumbnail(BitmapFrame bmp, Size size, UseEmbeddedThumbnails useEmbeddedThumbnails, int rotate) - { - Image thumb = null; - // Try to read the thumbnail. - if (bmp.Thumbnail != null) - { - try - { - BitmapSource sourceWpf = bmp.Thumbnail; - double scale; - if (rotate % 180 != 0) - { - scale = Math.Min(size.Height / (double)sourceWpf.PixelWidth, - size.Width / (double)sourceWpf.PixelHeight); - } - else - { - scale = Math.Min(size.Width / (double)sourceWpf.PixelWidth, - size.Height / (double)sourceWpf.PixelHeight); - } - if (bmp.Decoder == null || - (bmp.Decoder.Preview == null && bmp.Decoder.Frames == null) || - useEmbeddedThumbnails == UseEmbeddedThumbnails.Always) - { - // Take the thumbnail if nothing else is available or if ALWAYS - thumb = ConvertToBitmap(ScaleDownRotateBitmap(sourceWpf, scale, rotate)); - } - else if (useEmbeddedThumbnails == UseEmbeddedThumbnails.Auto) - { - // Check that the embedded thumbnail is large enough. - if ((float)scale <= 1.0f) - { - thumb = ConvertToBitmap(ScaleDownRotateBitmap(sourceWpf, scale, rotate)); - } - } - } - catch - { - if (thumb != null) - { - thumb.Dispose(); - thumb = null; - } - } - } - - // Try to read the preview. - if (bmp.Decoder != null && - bmp.Decoder.Preview != null && - thumb == null) - { - try - { - BitmapSource sourceWpf = bmp.Decoder.Preview; - double scale; - if (rotate % 180 != 0) - { - scale = Math.Min(size.Height / (double)sourceWpf.PixelWidth, - size.Width / (double)sourceWpf.PixelHeight); - } - else - { - scale = Math.Min(size.Width / (double)sourceWpf.PixelWidth, - size.Height / (double)sourceWpf.PixelHeight); - } - if (bmp.Decoder.Frames == null || - useEmbeddedThumbnails == UseEmbeddedThumbnails.Always) - { - // Take the thumbnail if nothing else is available or if ALWAYS - thumb = ConvertToBitmap(ScaleDownRotateBitmap(sourceWpf, scale, rotate)); - } - else if (useEmbeddedThumbnails == UseEmbeddedThumbnails.Auto) - { - // Check that the embedded thumbnail is large enough. - if ((float)scale <= 1.0f) - { - thumb = ConvertToBitmap(ScaleDownRotateBitmap(sourceWpf, scale, rotate)); - } - } - } - catch - { - if (thumb != null) - { - thumb.Dispose(); - thumb = null; - } - } - } - - // Use source image if nothings else fits. - if (bmp.Decoder != null && - bmp.Decoder.Frames != null && - thumb == null) - { - try - { - BitmapSource sourceWpf = bmp.Decoder.Frames[0]; - double scale; - if (rotate % 180 != 0) - { - scale = Math.Min(size.Height / (double)sourceWpf.PixelWidth, - size.Width / (double)sourceWpf.PixelHeight); - } - else - { - scale = Math.Min(size.Width / (double)sourceWpf.PixelWidth, - size.Height / (double)sourceWpf.PixelHeight); - } - thumb = ConvertToBitmap(ScaleDownRotateBitmap(sourceWpf, scale, rotate)); - } - catch - { - if (thumb != null) - { - thumb.Dispose(); - thumb = null; - } - } - } - - return thumb; - } - - /// - /// Scales down and rotates a Wpf bitmap. - /// - /// Original Wpf bitmap - /// Uniform scaling factor - /// Rotation angle - /// Scaled and rotated Wpf bitmap - private static BitmapSource ScaleDownRotateBitmap(BitmapSource sourceWpf, double scale, int angle) - { - if (angle % 90 != 0) - { - throw new ArgumentException("Rotation angle should be a multiple of 90 degrees.", "angle"); - } - - // Do not upscale and no rotation. - if ((float)scale >= 1.0f && angle == 0) - { - return sourceWpf; - } - - // Set up the transformed thumbnail - TransformedBitmap thumbWpf = new TransformedBitmap(); - thumbWpf.BeginInit(); - thumbWpf.Source = sourceWpf; - TransformGroup transform = new TransformGroup(); - - // Rotation - if (Math.Abs(angle) % 360 != 0) - transform.Children.Add(new RotateTransform(Math.Abs(angle))); - - // Scale - if ((float)scale < 1.0f || angle < 0) // Only downscale - { - double xScale = Math.Min(1.0, Math.Max(1.0 / (double)sourceWpf.PixelWidth, scale)); - double yScale = Math.Min(1.0, Math.Max(1.0 / (double)sourceWpf.PixelHeight, scale)); - - if (angle < 0) - xScale = -xScale; - transform.Children.Add(new ScaleTransform(xScale, yScale)); - } - - // Apply the tranformation - thumbWpf.Transform = transform; - thumbWpf.EndInit(); - - return thumbWpf; - } - - /// - /// Converts BitmapSource to Bitmap. - /// - /// BitmapSource - /// Bitmap - private static Bitmap ConvertToBitmap(BitmapSource sourceWpf) - { - BitmapSource bmpWpf = sourceWpf; - - // PixelFormat settings/conversion - System.Drawing.Imaging.PixelFormat formatBmp = System.Drawing.Imaging.PixelFormat.Format32bppArgb; - if (sourceWpf.Format == PixelFormats.Bgr24) - { - formatBmp = System.Drawing.Imaging.PixelFormat.Format24bppRgb; - } - else if (sourceWpf.Format == System.Windows.Media.PixelFormats.Pbgra32) - { - formatBmp = System.Drawing.Imaging.PixelFormat.Format32bppPArgb; - } - else if (sourceWpf.Format != System.Windows.Media.PixelFormats.Bgra32) - { - // Convert BitmapSource - FormatConvertedBitmap convertWpf = new FormatConvertedBitmap(); - convertWpf.BeginInit(); - convertWpf.Source = sourceWpf; - convertWpf.DestinationFormat = PixelFormats.Bgra32; - convertWpf.EndInit(); - bmpWpf = convertWpf; - } - - // Copy/Convert to Bitmap - Bitmap bmp = new Bitmap(bmpWpf.PixelWidth, bmpWpf.PixelHeight, formatBmp); - Rectangle rect = new Rectangle(Point.Empty, bmp.Size); - BitmapData data = bmp.LockBits(rect, ImageLockMode.WriteOnly, formatBmp); - bmpWpf.CopyPixels(System.Windows.Int32Rect.Empty, data.Scan0, data.Height * data.Stride, data.Stride); - bmp.UnlockBits(data); - - return bmp; - } -#endif - /// - /// Returns Exif rotation in degrees. Returns 0 if the metadata - /// does not exist or could not be read. A negative value means - /// the image needs to be mirrored about the vertical axis. - /// - /// Image. - private static int GetRotation(Image img) - { - try - { - foreach (PropertyItem prop in img.PropertyItems) - { - if (prop.Id == TagOrientation) - { - ushort orientationFlag = BitConverter.ToUInt16(prop.Value, 0); - if (orientationFlag == 1) - return 0; - else if (orientationFlag == 2) - return -360; - else if (orientationFlag == 3) - return 180; - else if (orientationFlag == 4) - return -180; - else if (orientationFlag == 5) - return -90; - else if (orientationFlag == 6) - return 90; - else if (orientationFlag == 7) - return -270; - else if (orientationFlag == 8) - return 270; - } - } - } - catch - { - ; - } - - return 0; - } - /// - /// Returns Exif rotation in degrees. Returns 0 if the metadata - /// does not exist or could not be read. A negative value means - /// the image needs to be mirrored about the vertical axis. - /// - /// Image. - private static int GetRotation(string filename) - { - try - { - using (FileStream stream = new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.Read)) - { - using (Image img = Image.FromStream(stream, false, false)) - { - return GetRotation(img); - } - } - } - catch - { - ; - } - - return 0; - } - - /// - /// Scales down and rotates an image. - /// - /// Original image - /// Uniform scaling factor - /// Rotation angle - /// Scaled and rotated image - private static Image ScaleDownRotateBitmap(Image source, double scale, int angle) - { - if (angle % 90 != 0) - { - throw new ArgumentException("Rotation angle should be a multiple of 90 degrees.", "angle"); - } - - // Do not upscale and no rotation. - if ((float)scale >= 1.0f && angle == 0) - { - return new Bitmap(source); - } - - int sourceWidth = source.Width; - int sourceHeight = source.Height; - - // Scale - double xScale = Math.Min(1.0, Math.Max(1.0 / (double)sourceWidth, scale)); - double yScale = Math.Min(1.0, Math.Max(1.0 / (double)sourceHeight, scale)); - - int width = (int)((double)sourceWidth * xScale); - int height = (int)((double)sourceHeight * yScale); - int thumbWidth = Math.Abs(angle) % 180 == 0 ? width : height; - int thumbHeight = Math.Abs(angle) % 180 == 0 ? height : width; - - Bitmap thumb = new Bitmap(thumbWidth, thumbHeight); - thumb.SetResolution(source.HorizontalResolution, source.VerticalResolution); - using (Graphics g = Graphics.FromImage(thumb)) - { - g.PixelOffsetMode = PixelOffsetMode.None; - g.InterpolationMode = InterpolationMode.HighQualityBicubic; - g.Clear(System.Drawing.Color.Transparent); - - g.TranslateTransform(-sourceWidth / 2, -sourceHeight / 2, MatrixOrder.Append); - if (Math.Abs(angle) % 360 != 0) - g.RotateTransform(Math.Abs(angle), MatrixOrder.Append); - if (angle < 0) - xScale = -xScale; - g.ScaleTransform((float)xScale, (float)yScale, MatrixOrder.Append); - g.TranslateTransform(thumbWidth / 2, thumbHeight / 2, MatrixOrder.Append); - - g.DrawImage(source, 0, 0); - } - - return thumb; - } - #endregion - } -} diff --git a/Source/Components/ImageGlass.ImageListView/Utility.cs b/Source/Components/ImageGlass.ImageListView/Utility.cs deleted file mode 100644 index d71a5c415..000000000 --- a/Source/Components/ImageGlass.ImageListView/Utility.cs +++ /dev/null @@ -1,637 +0,0 @@ -// ImageListView - A listview control for image files -// Copyright (C) 2009 Ozgur Ozcitak -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// Ozgur Ozcitak (ozcitak@yahoo.com) - -using System; -using System.Drawing; -using System.IO; -using System.Drawing.Drawing2D; -using System.Text; - -namespace ImageGlass.ImageListView -{ - /// - /// Contains utility functions. - /// - public static class Utility - { - #region Text Utilities - /// - /// Formats the given file size as a human readable string. - /// - /// File size in bytes. - /// The formatted string. - public static string FormatSize(long size) - { - double mod = 1024; - double sized = size; - - // string[] units = new string[] { "B", "KiB", "MiB", "GiB", "TiB", "PiB" }; - string[] units = new string[] { "B", "KB", "MB", "GB", "TB", "PB" }; - int i; - for (i = 0; sized > mod; i++) - { - sized /= mod; - } - - return string.Format("{0} {1}", Math.Round(sized, 2), units[i]); - } - #endregion - - #region Group Formating - /// - /// Formats the given date as a human readable string. For use with - /// grouping with past dates. - /// - /// Date to format. - internal static Tuple GroupTextDate(DateTime date) - { - DateTime now = DateTime.Now; - DateTime weekStart = now - new TimeSpan((int)now.DayOfWeek, now.Hour, now.Minute, now.Second, now.Millisecond); - DateTime monthStart = now - new TimeSpan((int)now.Day, now.Hour, now.Minute, now.Second, now.Millisecond); - DateTime yearStart = now - new TimeSpan((int)now.DayOfYear, now.Hour, now.Minute, now.Second, now.Millisecond); - double secs = (now - date).TotalSeconds; - - int order = 0; - string txt = string.Empty; - if (secs < 0) - { - order = 0; - txt = "Not Yet"; - } - else if (secs < 60) - { - order = 1; - txt = "Just now"; - } - else if (date.Year == now.Year && date.Month == now.Month && date.Day == now.Day) - { - order = 2; - txt = "Today"; - } - else if (date.Year == now.Year && date.Month == now.Month && date.Day == now.Day - 1) - { - order = 3; - txt = "Yesterday"; - } - else if (date > weekStart) - { - order = 4; - txt = "This week"; - } - else if (date > weekStart.AddDays(-7)) - { - order = 5; - txt = "Last week"; - } - else if (date > weekStart.AddDays(-14)) - { - order = 6; - txt = "Two weeks ago"; - } - else if (date > weekStart.AddDays(-21)) - { - order = 7; - txt = "Three weeks ago"; - } - else if (date > monthStart) - { - order = 8; - txt = "Earlier this month"; - } - else if (date > monthStart.AddMonths(-1)) - { - order = 9; - txt = "Last month"; - } - else if (date > yearStart) - { - order = 10; - txt = "Earlier this year"; - } - else if (date > yearStart.AddYears(-1)) - { - order = 11; - txt = "Last year"; - } - else - { - order = 12; - txt = "Older"; - } - - return Tuple.Create(order, txt); - } - /// - /// Formats the given file size as a human readable string. For use in grouping. - /// - /// File size in bytes. - internal static Tuple GroupTextFileSize(long size) - { - int order = 0; - string txt = string.Empty; - if (size < 10 * 1024) - { - order = 0; - txt = "< 10 KB"; - } - else if (size < 100 * 1024) - { - order = 1; - txt = "10 - 100 KB"; - } - else if (size < 1024 * 1024) - { - order = 2; - txt = "100 KB - 1 MB"; - } - else if (size < 10 * 1024 * 1024) - { - order = 3; - txt = "1 - 10 MB"; - } - else if (size < 100 * 1024 * 1024) - { - order = 4; - txt = "10 - 100 MB"; - } - else if (size < 1024 * 1024 * 1024) - { - order = 5; - txt = "100 MB - 1 GB"; - } - else - { - order = 6; - txt = "> 1 GB"; - } - return Tuple.Create(order, txt); - } - /// - /// Formats the given image size as a human readable string. - /// - /// Image dimension. - internal static Tuple GroupTextDimension(Size size) - { - int order = 0; - string txt = string.Empty; - if (size.Width <= 32 && size.Height <= 32) - { - order = 0; - txt = "Icon"; - } - else if (size.Width <= 240 && size.Height <= 240) - { - order = 1; - txt = "Small"; - } - else if (size.Width <= 640 && size.Height <= 640) - { - order = 2; - txt = "Medium"; - } - else if (size.Width <= 1280 && size.Height <= 1280) - { - order = 3; - txt = "Large"; - } - else - { - order = 4; - txt = "Very large"; - } - return Tuple.Create(order, txt); - } - /// - /// Formats the given text for display in grouping. Currently returns - /// the first letter of the text. - /// - /// The text to format. - internal static Tuple GroupTextAlpha(string text) - { - string txt = text.Substring(0, 1).ToUpperInvariant(); - char order = txt[0]; - return Tuple.Create((int)order, txt); - } - #endregion - - #region Graphics Utilities - /// - /// Checks the stream header if it matches with - /// any of the supported image file types. - /// - /// An open stream pointing to an image file. - /// true if the stream is an image file (BMP, TIFF, PNG, GIF, JPEG, WMF, EMF, ICO, CUR); - /// false otherwise. - internal static bool IsImage(Stream stream) - { - // Sniff some bytes from the start of the stream - // and check against magic numbers of supported - // image file formats - byte[] header = new byte[10]; - stream.Seek(0, SeekOrigin.Begin); - if (stream.Read(header, 0, header.Length) != header.Length) - return false; - - // BMP - string bmpHeader = Encoding.ASCII.GetString(header, 0, 2); - if (bmpHeader == "BM") // BM - Windows bitmap - return true; - else if (bmpHeader == "BA") // BA - Bitmap array - return true; - else if (bmpHeader == "CI") // CI - Color Icon - return true; - else if (bmpHeader == "CP") // CP - Color Pointer - return true; - else if (bmpHeader == "IC") // IC - Icon - return true; - else if (bmpHeader == "PT") // PI - Pointer - return true; - - // TIFF - string tiffHeader = Encoding.ASCII.GetString(header, 0, 4); - if (tiffHeader == "MM\x00\x2a") // Big-endian - return true; - else if (tiffHeader == "II\x2a\x00") // Little-endian - return true; - - // PNG - if (header[0] == 0x89 && header[1] == 0x50 && header[2] == 0x4E && header[3] == 0x47 && - header[4] == 0x0D && header[5] == 0x0A && header[6] == 0x1A && header[7] == 0x0A) - return true; - - // GIF - string gifHeader = Encoding.ASCII.GetString(header, 0, 4); - if (gifHeader == "GIF8") - return true; - - // JPEG - if (header[0] == 0xFF && header[1] == 0xD8) - return true; - - // WMF - if (header[0] == 0xD7 && header[1] == 0xCD && header[2] == 0xC6 && header[3] == 0x9A) - return true; - - // EMF - if (header[0] == 0x01 && header[1] == 0x00 && header[2] == 0x00 && header[3] == 0x00) - return true; - - // Windows Icons - if (header[0] == 0x00 && header[1] == 0x00 && header[2] == 0x01 && header[3] == 0x00) // ICO - return true; - else if (header[0] == 0x00 && header[1] == 0x00 && header[2] == 0x02 && header[3] == 0x00) // CUR - return true; - - // HDR - string hdrHeader = Encoding.ASCII.GetString(header, 2, 8); - if (hdrHeader == "RADIANCE") - return true; - - return false; - } - /// - /// Draws the given caption and text inside the given rectangle. - /// - internal static int DrawStringPair(Graphics g, Rectangle r, string caption, string text, Font font, Brush captionBrush, Brush textBrush) - { - using (StringFormat sf = new StringFormat()) - { - sf.Alignment = StringAlignment.Near; - sf.LineAlignment = StringAlignment.Near; - sf.Trimming = StringTrimming.EllipsisCharacter; - sf.FormatFlags = StringFormatFlags.NoWrap; - - SizeF szc = g.MeasureString(caption, font, r.Size, sf); - int y = (int)szc.Height; - if (szc.Width > r.Width) szc.Width = r.Width; - Rectangle txrect = new Rectangle(r.Location, Size.Ceiling(szc)); - g.DrawString(caption, font, captionBrush, txrect, sf); - txrect.X += txrect.Width; - txrect.Width = r.Width; - if (txrect.X < r.Right) - { - SizeF szt = g.MeasureString(text, font, r.Size, sf); - y = Math.Max(y, (int)szt.Height); - txrect = Rectangle.Intersect(r, txrect); - g.DrawString(text, font, textBrush, txrect, sf); - } - - return y; - } - } - /// - /// Gets the scaled size of an image required to fit - /// in to the given size keeping the image aspect ratio. - /// - /// The source image. - /// The size to fit in to. - /// New image size. - internal static Size GetSizedImageBounds(Image image, Size fit) - { - float f = System.Math.Max((float)image.Width / (float)fit.Width, (float)image.Height / (float)fit.Height); - if (f < 1.0f) f = 1.0f; // Do not upsize small images - int width = (int)System.Math.Round((float)image.Width / f); - int height = (int)System.Math.Round((float)image.Height / f); - return new Size(width, height); - } - /// - /// Gets the bounding rectangle of an image required to fit - /// in to the given rectangle keeping the image aspect ratio. - /// - /// The source image. - /// The rectangle to fit in to. - /// Horizontal image aligment in percent. - /// Vertical image aligment in percent. - /// New image size. - public static Rectangle GetSizedImageBounds(Image image, Rectangle fit, float hAlign, float vAlign) - { - if (hAlign < 0 || hAlign > 100.0f) - throw new ArgumentException("hAlign must be between 0.0 and 100.0 (inclusive).", "hAlign"); - if (vAlign < 0 || vAlign > 100.0f) - throw new ArgumentException("vAlign must be between 0.0 and 100.0 (inclusive).", "vAlign"); - Size scaled = GetSizedImageBounds(image, fit.Size); - int x = fit.Left + (int)(hAlign / 100.0f * (float)(fit.Width - scaled.Width)); - int y = fit.Top + (int)(vAlign / 100.0f * (float)(fit.Height - scaled.Height)); - - return new Rectangle(x, y, scaled.Width, scaled.Height); - } - /// - /// Gets the bounding rectangle of an image required to fit - /// in to the given rectangle keeping the image aspect ratio. - /// The image will be centered in the fit box. - /// - /// The source image. - /// The rectangle to fit in to. - /// New image size. - public static Rectangle GetSizedImageBounds(Image image, Rectangle fit) - { - return GetSizedImageBounds(image, fit, 50.0f, 50.0f); - } - /// - /// Gets a path representing a rounded rectangle. - /// - private static GraphicsPath GetRoundedRectanglePath(int x, int y, int width, int height, int radius) - { - GraphicsPath path = new GraphicsPath(); - path.AddLine(x + radius, y, x + width - radius, y); - if (radius > 0) - path.AddArc(x + width - 2 * radius, y, 2 * radius, 2 * radius, 270.0f, 90.0f); - path.AddLine(x + width, y + radius, x + width, y + height - radius); - if (radius > 0) - path.AddArc(x + width - 2 * radius, y + height - 2 * radius, 2 * radius, 2 * radius, 0.0f, 90.0f); - path.AddLine(x + width - radius, y + height, x + radius, y + height); - if (radius > 0) - path.AddArc(x, y + height - 2 * radius, 2 * radius, 2 * radius, 90.0f, 90.0f); - path.AddLine(x, y + height - radius, x, y + radius); - if (radius > 0) - path.AddArc(x, y, 2 * radius, 2 * radius, 180.0f, 90.0f); - return path; - } - /// - /// Fills the interior of a rounded rectangle. - /// - /// The graphics to draw on. - /// The brush to use to fill the rectangle. - /// The x-coordinate of the upper-left corner of the rectangle to draw. - /// The y-coordinate of the upper-left corner of the rectangle to draw. - /// Width of the rectangle to draw. - /// Height of the rectangle to draw. - /// The radius of rounded corners. - public static void FillRoundedRectangle(System.Drawing.Graphics graphics, Brush brush, int x, int y, int width, int height, int radius) - { - using (GraphicsPath path = GetRoundedRectanglePath(x, y, width, height, radius)) - { - graphics.FillPath(brush, path); - } - } - /// - /// Fills the interior of a rounded rectangle. - /// - /// The graphics to draw on. - /// The brush to use to fill the rectangle. - /// The x-coordinate of the upper-left corner of the rectangle to draw. - /// The y-coordinate of the upper-left corner of the rectangle to draw. - /// Width of the rectangle to draw. - /// Height of the rectangle to draw. - /// The radius of rounded corners. - public static void FillRoundedRectangle(System.Drawing.Graphics graphics, Brush brush, float x, float y, float width, float height, float radius) - { - FillRoundedRectangle(graphics, brush, (int)x, (int)y, (int)width, (int)height, (int)radius); - } - /// - /// Fills the interior of a rounded rectangle. - /// - /// The graphics to draw on. - /// The brush to use to fill the rectangle. - /// The rectangle to draw. - /// The radius of rounded corners. - public static void FillRoundedRectangle(System.Drawing.Graphics graphics, Brush brush, Rectangle rect, int radius) - { - FillRoundedRectangle(graphics, brush, rect.Left, rect.Top, rect.Width, rect.Height, radius); - } - /// - /// Fills the interior of a rounded rectangle. - /// - /// The graphics to draw on. - /// The brush to use to fill the rectangle. - /// The rectangle to draw. - /// The radius of rounded corners. - public static void FillRoundedRectangle(System.Drawing.Graphics graphics, Brush brush, RectangleF rect, float radius) - { - FillRoundedRectangle(graphics, brush, (int)rect.Left, (int)rect.Top, (int)rect.Width, (int)rect.Height, (int)radius); - } - /// - /// Draws the outline of a rounded rectangle. - /// - /// The graphics to draw on. - /// The pen to use to draw the rectangle. - /// The x-coordinate of the upper-left corner of the rectangle to draw. - /// The y-coordinate of the upper-left corner of the rectangle to draw. - /// Width of the rectangle to draw. - /// Height of the rectangle to draw. - /// The radius of rounded corners. - public static void DrawRoundedRectangle(System.Drawing.Graphics graphics, Pen pen, int x, int y, int width, int height, int radius) - { - using (GraphicsPath path = GetRoundedRectanglePath(x, y, width, height, radius)) - { - graphics.DrawPath(pen, path); - } - } - /// - /// Draws the outline of a rounded rectangle. - /// - /// The graphics to draw on. - /// The pen to use to draw the rectangle. - /// The x-coordinate of the upper-left corner of the rectangle to draw. - /// The y-coordinate of the upper-left corner of the rectangle to draw. - /// Width of the rectangle to draw. - /// Height of the rectangle to draw. - /// The radius of rounded corners. - public static void DrawRoundedRectangle(System.Drawing.Graphics graphics, Pen pen, float x, float y, float width, float height, float radius) - { - DrawRoundedRectangle(graphics, pen, (int)x, (int)y, (int)width, (int)height, (int)radius); - } - /// - /// Draws the outline of a rounded rectangle. - /// - /// The graphics to draw on. - /// The pen to use to draw the rectangle. - /// The rectangle to draw. - /// The radius of rounded corners. - public static void DrawRoundedRectangle(System.Drawing.Graphics graphics, Pen pen, Rectangle rect, int radius) - { - DrawRoundedRectangle(graphics, pen, rect.Left, rect.Top, rect.Width, rect.Height, radius); - } - /// - /// Draws the outline of a rounded rectangle. - /// - /// The graphics to draw on. - /// The pen to use to draw the rectangle. - /// The rectangle to draw. - /// The radius of rounded corners. - public static void DrawRoundedRectangle(System.Drawing.Graphics graphics, Pen pen, RectangleF rect, float radius) - { - DrawRoundedRectangle(graphics, pen, (int)rect.Left, (int)rect.Top, (int)rect.Width, (int)rect.Height, (int)radius); - } - #endregion - - #region Tuples - /// - /// Represents a factory class for creating tuples. - /// - public static class Tuple - { - /// - /// Creates a new 1-tuple. - /// - /// The type of the only component of the tuple. - /// The value of the only component of the tuple. - /// - /// A 1-tuple whose value is (). - /// - public static Tuple Create(T1 item1) - { - return new Tuple(item1); - } - /// - /// Creates a new 2-tuple. - /// - /// The type of the first component of the tuple. - /// The type of the second component of the tuple. - /// The value of the first component of the tuple. - /// The value of the second component of the tuple. - /// - /// A 2-tuple whose value is (, ). - /// - public static Tuple Create(T1 item1, T2 item2) - { - return new Tuple(item1, item2); - } - /// - /// Creates a new 3-tuple. - /// - /// The type of the first component of the tuple. - /// The type of the second component of the tuple. - /// The type of the third component of the tuple. - /// The value of the first component of the tuple. - /// The value of the second component of the tuple. - /// The value of the third component of the tuple. - /// - /// A 3-tuple whose value is (, , ). - /// - public static Tuple Create(T1 item1, T2 item2, T3 item3) - { - return new Tuple(item1, item2, item3); - } - } - /// - /// Represents a tuple with one element. - /// - /// The type of the first element of the tuple. - public class Tuple - { - private T1 mItem1; - - /// - /// Gets the value of the first component. - /// - public T1 Item1 { get { return mItem1; } } - - /// - /// Initializes a new instance of the class. - /// - /// The value of the first component of the tuple. - public Tuple(T1 item1) - { - mItem1 = item1; - } - } - /// - /// Represents a tuple with two elements. - /// - /// The type of the first element of the tuple. - /// The type of the second element of the tuple. - public class Tuple : Tuple - { - private T2 mItem2; - - /// - /// Gets the value of the second component. - /// - public T2 Item2 { get { return mItem2; } } - - /// - /// Initializes a new instance of the class. - /// - /// The value of the first component of the tuple. - /// The value of the second component of the tuple. - public Tuple(T1 item1, T2 item2) - : base(item1) - { - mItem2 = item2; - } - } - /// - /// Represents a tuple with three elements. - /// - /// The type of the first element of the tuple. - /// The type of the second element of the tuple. - /// The type of the third element of the tuple. - public class Tuple : Tuple - { - private T3 mItem3; - - /// - /// Gets the value of the third component. - /// - public T3 Item3 { get { return mItem3; } } - - /// - /// Initializes a new instance of the class. - /// - /// The value of the first component of the tuple. - /// The value of the second component of the tuple. - /// The value of the third component of the tuple. - public Tuple(T1 item1, T2 item2, T3 item3) - : base(item1, item2) - { - mItem3 = item3; - } - } - #endregion - } -} diff --git a/Source/Components/ImageGlass.ImageListView/app.config b/Source/Components/ImageGlass.ImageListView/app.config deleted file mode 100644 index 285226535..000000000 --- a/Source/Components/ImageGlass.ImageListView/app.config +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/Source/Components/ImageGlass.Library/Comparer/DictionaryEntryComparer.cs b/Source/Components/ImageGlass.Library/Comparer/DictionaryEntryComparer.cs deleted file mode 100644 index 68daa7baf..000000000 --- a/Source/Components/ImageGlass.Library/Comparer/DictionaryEntryComparer.cs +++ /dev/null @@ -1,44 +0,0 @@ -/* -ImageGlass Project - Image viewer for Windows -Copyright (C) 2013 DUONG DIEU PHAP -Project homepage: http://imageglass.org - -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 . -*/ - -using System; -using System.Collections; - -namespace ImageGlass.Library.Comparer -{ - public class DictionaryEntryComparer : IComparer - { - private IComparer nc = null; - - public DictionaryEntryComparer(IComparer nc) - { - if (nc == null) throw new Exception("Null IComparer"); - this.nc = nc; - } - - public int Compare(object x, object y) - { - if ((x is DictionaryEntry) && (y is DictionaryEntry)) - { - return nc.Compare(((DictionaryEntry)x).Key, ((DictionaryEntry)y).Key); - } - return -1; - } - } -} diff --git a/Source/Components/ImageGlass.Library/Comparer/FileLogicalComparer.cs b/Source/Components/ImageGlass.Library/Comparer/FileLogicalComparer.cs deleted file mode 100644 index b6d160fff..000000000 --- a/Source/Components/ImageGlass.Library/Comparer/FileLogicalComparer.cs +++ /dev/null @@ -1,93 +0,0 @@ -/* -ImageGlass Project - Image viewer for Windows -Copyright (C) 2013 DUONG DIEU PHAP -Project homepage: http://imageglass.org - -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 . -*/ - -using System.Collections; -using System.IO; - -namespace ImageGlass.Library.Comparer -{ - public class FileLogicalComparer - { - private ArrayList _files = null; - - public ArrayList Files - { - get { return _files; } - set { _files = value; } - } - - #region Local Functions - public void AddFile(string file) - { - if (file == null) return; - if (_files == null) _files = new ArrayList(); - _files.Add(new DictionaryEntry(Path.GetFileName(file), file)); - } - - - public void AddFiles(string[] f) - { - if (f == null) return; - for (int i = 0; i < f.Length; i++) - { - AddFile(f[i]); - } - } - - public ArrayList GetSorted() - { - if (_files != null) - { - _files.Sort(new DictionaryEntryComparer(new NumericComparer())); - } - return _files; - } - #endregion - - - /// - /// Sort an string array - /// - /// String array - /// - public static string[] Sort(string[] stringArray) - { - if (stringArray == null) return null; - - FileLogicalComparer fc = new FileLogicalComparer(); - fc.AddFiles(stringArray); - ArrayList ds = fc.GetSorted(); - - if (ds == null) return stringArray; - - for (int i = 0; i < ds.Count; i++) - { - stringArray[i] = (string)((DictionaryEntry)ds[i]).Value; - } - - return stringArray; - } - - } - - - - - -} \ No newline at end of file diff --git a/Source/Components/ImageGlass.Library/Comparer/StringLogicalComparer.cs b/Source/Components/ImageGlass.Library/Comparer/StringLogicalComparer.cs deleted file mode 100644 index b8e0e8842..000000000 --- a/Source/Components/ImageGlass.Library/Comparer/StringLogicalComparer.cs +++ /dev/null @@ -1,154 +0,0 @@ -/* -ImageGlass Project - Image viewer for Windows -Copyright (C) 2013 DUONG DIEU PHAP -Project homepage: http://imageglass.org - -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 . -*/ - -//(c) Vasian Cepa 2005 -// Version 2 - -using System; - -namespace ImageGlass.Library.Comparer -{ - - /// - /// Emulates StrCmpLogicalW, but not fully - /// - public class StringLogicalComparer - { - public static int Compare(string s1, string s2) - { - //get rid of special cases - if ((s1 == null) && (s2 == null)) return 0; - else if (s1 == null) return -1; - else if (s2 == null) return 1; - - if ((s1.Equals(string.Empty) && (s2.Equals(string.Empty)))) return 0; - else if (s1.Equals(string.Empty)) return -1; - else if (s2.Equals(string.Empty)) return -1; - - //WE style, special case - bool sp1 = Char.IsLetterOrDigit(s1, 0); - bool sp2 = Char.IsLetterOrDigit(s2, 0); - if (sp1 && !sp2) return 1; - if (!sp1 && sp2) return -1; - - int i1 = 0, i2 = 0; //current index - int r = 0; // temp result - while (true) - { - bool c1 = Char.IsDigit(s1, i1); - bool c2 = Char.IsDigit(s2, i2); - if (!c1 && !c2) - { - bool letter1 = Char.IsLetter(s1, i1); - bool letter2 = Char.IsLetter(s2, i2); - if ((letter1 && letter2) || (!letter1 && !letter2)) - { - if (letter1 && letter2) - { - r = Char.ToLower(s1[i1]).CompareTo(Char.ToLower(s2[i2])); - } - else - { - r = s1[i1].CompareTo(s2[i2]); - } - if (r != 0) return r; - } - else if (!letter1 && letter2) return -1; - else if (letter1 && !letter2) return 1; - } - else if (c1 && c2) - { - r = CompareNum(s1, ref i1, s2, ref i2); - if (r != 0) return r; - } - else if (c1) - { - return -1; - } - else if (c2) - { - return 1; - } - i1++; - i2++; - if ((i1 >= s1.Length) && (i2 >= s2.Length)) - { - return 0; - } - else if (i1 >= s1.Length) - { - return -1; - } - else if (i2 >= s2.Length) - { - return -1; - } - } - } - - - private static int CompareNum(string s1, ref int i1, string s2, ref int i2) - { - int nzStart1 = i1, nzStart2 = i2; // nz = non zero - int end1 = i1, end2 = i2; - - ScanNumEnd(s1, i1, ref end1, ref nzStart1); - ScanNumEnd(s2, i2, ref end2, ref nzStart2); - int start1 = i1; i1 = end1 - 1; - int start2 = i2; i2 = end2 - 1; - - int nzLength1 = end1 - nzStart1; - int nzLength2 = end2 - nzStart2; - - if (nzLength1 < nzLength2) return -1; - else if (nzLength1 > nzLength2) return 1; - - for (int j1 = nzStart1, j2 = nzStart2; j1 <= i1; j1++, j2++) - { - int r = s1[j1].CompareTo(s2[j2]); - if (r != 0) return r; - } - // the nz parts are equal - int length1 = end1 - start1; - int length2 = end2 - start2; - if (length1 == length2) return 0; - if (length1 > length2) return -1; - return 1; - } - - //lookahead - private static void ScanNumEnd(string s, int start, ref int end, ref int nzStart) - { - nzStart = start; - end = start; - bool countZeros = true; - while (Char.IsDigit(s, end)) - { - if (countZeros && s[end].Equals('0')) - { - nzStart++; - } - else countZeros = false; - end++; - if (end >= s.Length) break; - } - } - - }//EOC -} diff --git a/Source/Components/ImageGlass.Library/Comparer/WindowsNaturalSort.cs b/Source/Components/ImageGlass.Library/Comparer/WindowsNaturalSort.cs deleted file mode 100644 index d29e5780e..000000000 --- a/Source/Components/ImageGlass.Library/Comparer/WindowsNaturalSort.cs +++ /dev/null @@ -1,56 +0,0 @@ -/* -ImageGlass Project - Image viewer for Windows -Copyright (C) 2017-2019 DUONG DIEU PHAP -Project homepage: https://imageglass.org - -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 . -*/ -using System; -using System.Collections.Generic; -using System.IO; -using System.Runtime.InteropServices; - -namespace ImageGlass.Library.Comparer -{ - public class WindowsNaturalSort : IComparer - { - [DllImport("shlwapi.dll", CharSet = CharSet.Unicode, ExactSpelling = true)] - static extern int StrCmpLogicalW(String x, String y); - - public int Compare(string filePath1, string filePath2) - { - var basename1 = Path.GetFileName(filePath1); - var basename2 = Path.GetFileName(filePath2); - - return StrCmpLogicalW(basename1, basename2); - } - - } - - public class ReverseWindowsNaturalSort : IComparer - { - [DllImport("shlwapi.dll", CharSet = CharSet.Unicode, ExactSpelling = true)] - static extern int StrCmpLogicalW(String x, String y); - - public int Compare(string filePath1, string filePath2) - { - var basename1 = Path.GetFileName(filePath2); - var basename2 = Path.GetFileName(filePath1); - - return StrCmpLogicalW(basename1, basename2); - } - - } - -} diff --git a/Source/Components/ImageGlass.Library/DirectoryFinder/DirectoryFinder.cs b/Source/Components/ImageGlass.Library/DirectoryFinder/DirectoryFinder.cs deleted file mode 100644 index 325432e68..000000000 --- a/Source/Components/ImageGlass.Library/DirectoryFinder/DirectoryFinder.cs +++ /dev/null @@ -1,157 +0,0 @@ -using System; -using System.Collections.Concurrent; -using System.Collections.Generic; -using System.IO; -using System.Threading.Tasks; - -namespace ImageGlass.Library -{ - public static class DirectoryFinder - { - #region DirectoryList - /// - /// Returns a list of directories under RootDirectory - /// - /// starting directory - /// when true, all sub directories will be searched as well - /// filter to be done on directory. use null for no filtering - /// - public static ConcurrentBag FindDirectories(string RootDirectory, - bool SearchAllDirectories, Predicate Filter) - { - ConcurrentBag retList = new ConcurrentBag(); - - try - { - // create a directory info object - DirectoryInfo di = new DirectoryInfo(RootDirectory); - - // loop through directories populating the list - Parallel.ForEach(di.GetDirectories(), folder => - { - try - { - // add the folder if it passes the filter - if ((Filter == null) || (Filter(folder.FullName))) - { - // add the folder - retList.Add(folder.FullName); - - // get its sub folders - if (SearchAllDirectories) - { - foreach (var dir in FindDirectories(folder.FullName, true, Filter)) - retList.Add(dir); - } - } - } - - catch (UnauthorizedAccessException) - { - // don't really need to do anything - // user just doesn't have access - } - -#pragma warning disable CS0168 // Variable is declared but never used - catch (Exception ex) -#pragma warning restore CS0168 // Variable is declared but never used - { - // TODO: log the exception - } - }); - } - -#pragma warning disable CS0168 // Variable is declared but never used - catch (Exception ex) -#pragma warning restore CS0168 // Variable is declared but never used - { - // TODO: save exception - } - - // return the list - return retList; - } - - // DirectoryList - #endregion - - #region FileList - - /// - /// Returns a list of files under RootDirectory - /// - /// >starting directory - /// >when true, all sub directories will be searched as well - /// filter to be done on files/directory. use null for no filtering - /// - public static ConcurrentBag FindFiles(string RootDirectory, - bool SearchAllDirectories, Predicate Filter) - { - ConcurrentBag retList = new ConcurrentBag(); - - try - { - // get the list of directories - List DirList = new List { RootDirectory }; - - // get sub directories if allowed - if (SearchAllDirectories) - DirList.AddRange(FindDirectories(RootDirectory, true, null)); - - // loop through directories populating the list - Parallel.ForEach(DirList, folder => - { - // get a directory object - DirectoryInfo di = new DirectoryInfo(folder); - - try - { - // loop through the files in this directory - foreach (FileInfo file in di.GetFiles()) - { - try - { - // add the file if it passes the filter - if ((Filter == null) || (Filter(file))) - retList.Add(file.FullName); - } - -#pragma warning disable CS0168 // Variable is declared but never used - catch (Exception ex) -#pragma warning restore CS0168 // Variable is declared but never used - { - // TODO: log the exception - } - } - } - - catch (UnauthorizedAccessException) - { - // don't really need to do anything - // user just doesn't have access - } - -#pragma warning disable CS0168 // Variable is declared but never used - catch (Exception ex) -#pragma warning restore CS0168 // Variable is declared but never used - { - // TODO: log the exception - } - }); - } - -#pragma warning disable CS0168 // Variable is declared but never used - catch (Exception ex) -#pragma warning restore CS0168 // Variable is declared but never used - { - // TODO: save exception - } - - // return the list - return retList; - } - - // FileList - #endregion - } -} diff --git a/Source/Components/ImageGlass.Library/FileAssociations/RegistryHelper.cs b/Source/Components/ImageGlass.Library/FileAssociations/RegistryHelper.cs deleted file mode 100644 index 6e3d4ad4f..000000000 --- a/Source/Components/ImageGlass.Library/FileAssociations/RegistryHelper.cs +++ /dev/null @@ -1,273 +0,0 @@ -/* -ImageGlass Project - Image viewer for Windows -Copyright (C) 2017 DUONG DIEU PHAP -Project homepage: http://imageglass.org - -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 . -*/ -using Microsoft.Win32; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Windows.Forms; - -namespace ImageGlass.Library.FileAssociations -{ - /// - /// An useful class to read/write/delete/count registry keys - /// - public class RegistryHelper - { - - private bool showError = false; - /// - /// A property to show or hide error messages - /// (default = false) - /// - public bool ShowError - { - get { return showError; } - set { showError = value; } - } - - private string subKey = @"SOFTWARE\PhapSoftware\ImageGlass"; - - /// - /// A property to set the SubKey value - /// (default = "SOFTWARE\PhapSoftware\ImageGlass") - /// - public string SubKey - { - get { return subKey; } - set { subKey = value; } - } - - private RegistryKey baseRegistryKey = Registry.LocalMachine; - /// - /// A property to set the BaseRegistryKey value. - /// (default = Registry.LocalMachine) - /// - public RegistryKey BaseRegistryKey - { - get { return baseRegistryKey; } - set { baseRegistryKey = value; } - } - - - /// - /// To read a registry key. - /// input: KeyName (string) - /// output: value (string) - /// - public string Read(string KeyName) - { - // Opening the registry key - RegistryKey rk = baseRegistryKey; - // Open a subKey as read-only - RegistryKey sk1 = rk.OpenSubKey(subKey); - // If the RegistrySubKey doesn't exist -> (null) - if (sk1 == null) - { - return null; - } - else - { - try - { - // If the RegistryKey exists I get its value - // or null is returned. - return (string)sk1.GetValue(KeyName); - } - catch (Exception e) - { - // AAAAAAAAAAARGH, an error! - ShowErrorMessage(e, "Reading registry " + KeyName); - return null; - } - } - } - - - /// - /// To write into a registry key. - /// input: KeyName (string) , Value (object) - /// output: true or false - /// - public bool Write(string KeyName, object Value) - { - try - { - // Setting - RegistryKey rk = baseRegistryKey; - // I have to use CreateSubKey - // (create or open it if already exits), - // 'cause OpenSubKey open a subKey as read-only - RegistryKey sk1 = rk.CreateSubKey(subKey); - // Save the value - sk1.SetValue(KeyName, Value); - - return true; - } - catch (Exception e) - { - // AAAAAAAAAAARGH, an error! - ShowErrorMessage(e, "Writing registry " + KeyName); - return false; - } - } - - - /// - /// To delete a registry key. - /// input: KeyName (string) - /// output: true or false - /// - public bool DeleteKey(string KeyName) - { - try - { - // Setting - RegistryKey rk = baseRegistryKey; - RegistryKey sk1 = rk.CreateSubKey(subKey); - // If the RegistrySubKey doesn't exists -> (true) - if (sk1 == null) - return true; - else - sk1.DeleteValue(KeyName); - - return true; - } - catch (Exception e) - { - // AAAAAAAAAAARGH, an error! - ShowErrorMessage(e, "Deleting SubKey " + subKey); - return false; - } - } - - - /// - /// To delete a sub key and any child. - /// input: void - /// output: true or false - /// - public bool DeleteSubKeyTree() - { - try - { - // Setting - RegistryKey rk = baseRegistryKey; - RegistryKey sk1 = rk.OpenSubKey(subKey); - // If the RegistryKey exists, I delete it - if (sk1 != null) - rk.DeleteSubKeyTree(subKey); - - return true; - } - catch (Exception e) - { - // AAAAAAAAAAARGH, an error! - ShowErrorMessage(e, "Deleting SubKey " + subKey); - return false; - } - } - - - /// - /// Retrieve the count of subkeys at the current key. - /// input: void - /// output: number of subkeys - /// - public int SubKeyCount() - { - try - { - // Setting - RegistryKey rk = baseRegistryKey; - RegistryKey sk1 = rk.OpenSubKey(subKey); - // If the RegistryKey exists... - if (sk1 != null) - return sk1.SubKeyCount; - else - return 0; - } - catch (Exception e) - { - // AAAAAAAAAAARGH, an error! - ShowErrorMessage(e, "Retrieving subkeys of " + subKey); - return 0; - } - } - - - /// - /// Retrieve the count of values in the key. - /// input: void - /// output: number of keys - /// - public int ValueCount() - { - try - { - // Setting - RegistryKey rk = baseRegistryKey; - RegistryKey sk1 = rk.OpenSubKey(subKey); - // If the RegistryKey exists... - if (sk1 != null) - return sk1.ValueCount; - else - return 0; - } - catch (Exception e) - { - // AAAAAAAAAAARGH, an error! - ShowErrorMessage(e, "Retrieving keys of " + subKey); - return 0; - } - } - - /// - /// Retrieve all value names in the key - /// - /// - public string[] GetValueNames() - { - try - { - // Setting - RegistryKey rk = baseRegistryKey; - RegistryKey sk1 = rk.OpenSubKey(subKey); - // If the RegistryKey exists... - if (sk1 != null) - return sk1.GetValueNames(); - else - return new string[0]; - } - catch (Exception e) - { - // AAAAAAAAAAARGH, an error! - ShowErrorMessage(e, "Retrieving keys of " + subKey); - return new string[0]; - } - } - - - private void ShowErrorMessage(Exception e, string Title) - { - if (showError == true) - MessageBox.Show(e.Message, Title, MessageBoxButtons.OK, MessageBoxIcon.Error); - } - } -} \ No newline at end of file diff --git a/Source/Components/ImageGlass.Library/Helper.cs b/Source/Components/ImageGlass.Library/Helper.cs deleted file mode 100644 index a27d7fdc7..000000000 --- a/Source/Components/ImageGlass.Library/Helper.cs +++ /dev/null @@ -1,142 +0,0 @@ -/* -ImageGlass Project - Image viewer for Windows -Copyright (C) 2020 DUONG DIEU PHAP -Project homepage: http://imageglass.org - -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 . -*/ -using ImageGlass.Library.WinAPI; -using System.Collections.Generic; -using System.Drawing; -using System.IO; -using System.Linq; -using System.Runtime.InteropServices; -using System.Text; -using System.Windows.Forms; - -namespace ImageGlass.Library -{ - public static class Helper - { - /// - /// Check if the given form's location is visible on screen - /// - /// The location of form to check - /// - public static bool IsOnScreen(Point location) - { - Screen[] screens = Screen.AllScreens; - foreach (Screen screen in screens) - { - if (screen.WorkingArea.Contains(location)) - { - return true; - } - } - - return false; - } - - /// - /// Is the form's rectangle _anywhere_ on screen. Allows the form to - /// be off the edge of the screen, which is legit. - /// - /// - /// - public static bool IsAnyPartOnScreen(Rectangle bounds) - { - Screen[] screens = Screen.AllScreens; - foreach (Screen screen in screens) - { - if (screen.WorkingArea.IntersectsWith(bounds)) - { - return true; - } - } - - return false; - } - - [DllImport("shlwapi.dll", CharSet = CharSet.Auto)] - static extern bool PathCompactPathEx([Out] StringBuilder pszOut, string szPath, int cchMax, int dwFlags); - - /// - /// Shorten and ellipsis the path - /// - /// - /// - /// - public static string ShortenPath(string path, int length) - { - StringBuilder sb = new StringBuilder(length); - PathCompactPathEx(sb, path, length, 0); - return sb.ToString(); - } - - - /// - /// Get distinct directories list from paths list - /// - /// Paths list - /// - public static List GetDistinctDirsFromPaths(IEnumerable pathList) - { - if (pathList.Count() == 0) return new List(); - - var hashedDirsList = new HashSet(); - - foreach (var path in pathList) - { - if (File.Exists(path)) - { - string dir; - if (Path.GetExtension(path).ToLower() == ".lnk") - { - var shortcutPath = Shortcuts.GetTargetPathFromShortcut(path); - - // get the DIR path of shortcut target - if (File.Exists(shortcutPath)) - { - dir = Path.GetDirectoryName(shortcutPath); - } - else if (Directory.Exists(shortcutPath)) - { - dir = shortcutPath; - } - else - { - continue; - } - } - else - { - dir = Path.GetDirectoryName(path); - } - - hashedDirsList.Add(dir); - } - else if (Directory.Exists(path)) - { - hashedDirsList.Add(path); - } - else - { - continue; - } - } - - return hashedDirsList.ToList(); - } - } -} diff --git a/Source/Components/ImageGlass.Library/Image/Animation.cs b/Source/Components/ImageGlass.Library/Image/Animation.cs deleted file mode 100644 index f002e33f0..000000000 --- a/Source/Components/ImageGlass.Library/Image/Animation.cs +++ /dev/null @@ -1,126 +0,0 @@ -/* -ImageGlass Project - Image viewer for Windows -Copyright (C) 2013 - 2019 DUONG DIEU PHAP -Project homepage: https://imageglass.org - -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 . -*/ - -using System.IO; -using System.Drawing; -using System.Drawing.Imaging; -using System; -using System.Threading.Tasks; - -namespace ImageGlass.Library.Image -{ - public class Animation - { - private Bitmap _img; - private bool _isAnimating = false; - private int _i; - private string _filename; - private string _desFolder; - private ExtractCallback _extractFinished; - - public delegate void ExtractCallback(); - - /// - /// Extract all frames of animation - /// - /// File name - /// Output folder - public void ExtractAllFrames(string animationFile, string destinationFolder, ExtractCallback callback) - { - //initiate class - - _isAnimating = false; - _filename = animationFile; - _desFolder = destinationFolder; - _extractFinished = callback; - - Task.Run(() => - { - _img = new Bitmap(animationFile); - _i = 1; - - //begin extract - AnimateImage(); - }); - } - - /// - /// This method begins the animation. - /// - private void AnimateImage() - { - if (!_isAnimating) - { - //Begin the animation only once. - ImageAnimator.Animate(_img, new EventHandler(SaveFrames)); - _isAnimating = true; - } - - } - - /// - /// Save current frame - /// - /// - /// - private void SaveFrames(object sender, EventArgs e) - { - if (!_isAnimating) return; - - var frameCount = System.Drawing.Image.FromFile(_filename).GetFrameCount(FrameDimension.Time); - var numberIndex = frameCount.ToString().Length; - - // Check current frame - if (_i > frameCount) - { - _isAnimating = false; - ImageAnimator.StopAnimate(_img, null); - - // Issue #565 callback to let the user know the extract has finished - _extractFinished?.Invoke(); - _extractFinished = null; - return; - } - - //Begin the animation. - AnimateImage(); - - //Get the next frame ready for rendering. - ImageAnimator.UpdateFrames(); - - //Draw the next frame in the animation. - _img.Save( - Path.Combine( - _desFolder, - Path.GetFileNameWithoutExtension(_filename) + " - " + - _i.ToString($"D{numberIndex}") + ".png" - ), - ImageFormat.Png - ); - - //go to next frame - _i += 1; - - } - - } - - - -} diff --git a/Source/Components/ImageGlass.Library/Image/DesktopWallapaper.cs b/Source/Components/ImageGlass.Library/Image/DesktopWallapaper.cs deleted file mode 100644 index 2c2117cb3..000000000 --- a/Source/Components/ImageGlass.Library/Image/DesktopWallapaper.cs +++ /dev/null @@ -1,179 +0,0 @@ -/* -ImageGlass Project - Image viewer for Windows -Copyright (C) 2013-2018 DUONG DIEU PHAP -Project homepage: http://imageglass.org - -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 . -*/ - -using System; -using Microsoft.Win32; -using System.IO; -using System.Runtime.InteropServices; - -namespace ImageGlass.Library.Image -{ - public class DesktopWallapaper - { - const int SPI_SETDESKWALLPAPER = 20; - const int SPIF_UPDATEINIFILE = 0x01; - const int SPIF_SENDWININICHANGE = 0x02; - - [DllImport("user32.dll", CharSet = CharSet.Unicode)] - static extern int SystemParametersInfo(int uAction, int uParam, string lpvParam, int fuWinIni); - - public enum Style : int - { - /// - /// Current windows wallpaper style - /// - Current = -1, - /// - /// 0 - /// - Centered = 0, - /// - /// 1 - /// - Stretched = 1, - /// - /// 2 - /// - Tiled = 2 - } - - /// - /// Set desktop wallpaper - /// - /// Image filename - /// Style of wallpaper - public static void Set(Uri uri, Style style) - { - Stream s = new System.Net.WebClient().OpenRead(uri.ToString()); - - System.Drawing.Image img = System.Drawing.Image.FromStream(s); - Set(img, style); - } - - /// - /// Set desktop wallpaper - /// - /// Image data - /// Style of wallpaper - public static void Set(System.Drawing.Image img, Style style) - { - try - { - string tempPath = Path.Combine(Path.GetTempPath(), "imageglass.jpg"); - img.Save(tempPath, System.Drawing.Imaging.ImageFormat.Jpeg); - - RegistryKey key = Registry.CurrentUser.OpenSubKey(@"Control Panel\Desktop", true); - if (key == null) - return; - - if (style == Style.Stretched) - { - key.SetValue(@"WallpaperStyle", "2"); - key.SetValue(@"TileWallpaper", "0"); - } - - if (style == Style.Centered) - { - key.SetValue(@"WallpaperStyle", "1"); - key.SetValue(@"TileWallpaper", "0"); - } - - if (style == Style.Tiled) - { - key.SetValue(@"WallpaperStyle", "1"); - key.SetValue(@"TileWallpaper", "1"); - } - - SystemParametersInfo(SPI_SETDESKWALLPAPER, 0, tempPath, SPIF_UPDATEINIFILE | SPIF_SENDWININICHANGE); - } - catch (Exception) { } - } - - public enum Result - { - Success=0, // Wallpaper successfully set - PrivsFail, // Wallpaper failure due to privileges - can re-attempt with Admin privs. - Fail // Wallpaper failure - no point in re-attempting - } - - /// - /// Set the desktop wallpaper. - /// - /// File system path to the image - /// Style of wallpaper - /// Success/failure indication. - public static Result Set(string path, Style style) - { - //System.Diagnostics.Debugger.Break(); - - // TODO use ImageMagick to load image - var tempPath = Path.Combine(Path.GetTempPath(), "imageglass.bmp"); - try - { - using (var img = System.Drawing.Image.FromFile(path)) - { - // SPI_SETDESKWALLPAPER will *only* work consistently if image is a Bitmap! (Issue #327) - img.Save(tempPath, System.Drawing.Imaging.ImageFormat.Bmp); - } - } - catch - { - // Couldn't open/save image file: Fail, and don't re-try - return Result.Fail; - } - - try - { - using (RegistryKey key = Registry.CurrentUser.OpenSubKey(@"Control Panel\Desktop", true)) - { - if (key == null) - return Result.Fail; - - string tileVal = "0"; // default not-tiled - string winStyle = "1"; // default centered - switch (style) - { - case Style.Tiled: - tileVal = "1"; - break; - case Style.Stretched: - winStyle = "2"; - break; - case Style.Current: - tileVal = (string)key.GetValue("TileWallpaper"); - winStyle = (string)key.GetValue("WallpaperStyle"); - break; - } - key.SetValue("TileWallpaper", tileVal); - key.SetValue("WallpaperStyle", winStyle); - key.SetValue("Wallpaper", tempPath); - } - SystemParametersInfo(SPI_SETDESKWALLPAPER, 0, tempPath, SPIF_UPDATEINIFILE | SPIF_SENDWININICHANGE); - } - catch (Exception ex) - { - if (ex is System.Security.SecurityException || - ex is UnauthorizedAccessException) - return Result.PrivsFail; - return Result.Fail; - } - return Result.Success; - } - } -} diff --git a/Source/Components/ImageGlass.Library/Image/ExifThumbReader.cs b/Source/Components/ImageGlass.Library/Image/ExifThumbReader.cs deleted file mode 100644 index 9edf98c01..000000000 --- a/Source/Components/ImageGlass.Library/Image/ExifThumbReader.cs +++ /dev/null @@ -1,174 +0,0 @@ -// Please do not remove :) -// Written by Kourosh Derakshan -// -using System; -using System.IO; -using System.Runtime.InteropServices; - -namespace ImageGlass.Library.Image -{ - /// - /// Allows reading of embedded thumbnail image from the EXIF information in an image. - /// - public abstract class ExifThumbReader - { - // GDI plus functions - [DllImport("gdiplus.dll", CharSet = CharSet.Unicode, ExactSpelling = true)] - internal static extern int GdipGetPropertyItem(IntPtr image, int propid, int size, IntPtr buffer); - - [DllImport("gdiplus.dll", CharSet = CharSet.Unicode, ExactSpelling = true)] - internal static extern int GdipGetPropertyItemSize(IntPtr image, int propid, out int size); - - [DllImport("gdiplus.dll", CharSet = CharSet.Unicode, ExactSpelling = true)] - internal static extern int GdipLoadImageFromFile(string filename, out IntPtr image); - - [DllImport("gdiplus.dll", EntryPoint = "GdipDisposeImage", CharSet = CharSet.Unicode, ExactSpelling = true)] - private static extern int GdipDisposeImage(IntPtr image); - - - - - - // EXIT tag value for thumbnail data. Value specified by EXIF standard - private static int THUMBNAIL_DATA = 0x501B; - - /// - /// Reads the thumbnail in the given image. If no thumbnail is found, returns null - /// - public static System.Drawing.Image ReadThumb(string imagePath) - { - const int GDI_ERR_PROP_NOT_FOUND = 19; // Property not found error - const int GDI_ERR_OUT_OF_MEMORY = 3; - - IntPtr hImage = IntPtr.Zero; - IntPtr buffer = IntPtr.Zero; // Holds the thumbnail data - int ret; - ret = GdipLoadImageFromFile(imagePath, out hImage); - - try - { - if (ret != 0) - throw createException(ret); - - int propSize; - ret = GdipGetPropertyItemSize(hImage, THUMBNAIL_DATA, out propSize); - // Image has no thumbnail data in it. Return null - if (ret == GDI_ERR_PROP_NOT_FOUND) - return null; - if (ret != 0) - throw createException(ret); - - - // Allocate a buffer in memory - buffer = Marshal.AllocHGlobal(propSize); - if (buffer == IntPtr.Zero) - throw createException(GDI_ERR_OUT_OF_MEMORY); - - ret = GdipGetPropertyItem(hImage, THUMBNAIL_DATA, propSize, buffer); - if (ret != 0) - throw createException(ret); - - // buffer has the thumbnail data. Now we have to convert it to - // an Image - return convertFromMemory(buffer); - } - - finally - { - // Free the buffer - if (buffer != IntPtr.Zero) - Marshal.FreeHGlobal(buffer); - - GdipDisposeImage(hImage); - } - } - - /// - /// Generates an exception depending on the GDI+ error codes (I removed some error - /// codes) - /// - private static Exception createException(int gdipErrorCode) - { - switch (gdipErrorCode) - { - case 1: - return new ExternalException("Gdiplus Generic Error", -2147467259); - case 2: - return new ArgumentException("Gdiplus Invalid Parameter"); - case 3: - return new OutOfMemoryException("Gdiplus Out Of Memory"); - case 4: - return new InvalidOperationException("Gdiplus Object Busy"); - case 5: - return new OutOfMemoryException("Gdiplus Insufficient Buffer"); - case 7: - return new ExternalException("Gdiplus Generic Error", -2147467259); - case 8: - return new InvalidOperationException("Gdiplus Wrong State"); - case 9: - return new ExternalException("Gdiplus Aborted", -2147467260); - case 10: - return new FileNotFoundException("Gdiplus File Not Found"); - case 11: - return new OverflowException("Gdiplus Over flow"); - case 12: - return new ExternalException("Gdiplus Access Denied", -2147024891); - case 13: - return new ArgumentException("Gdiplus Unknown Image Format"); - case 18: - return new ExternalException("Gdiplus Not Initialized", -2147467259); - case 20: - return new ArgumentException("Gdiplus Property Not Supported Error"); - } - - return new ExternalException("Gdiplus Unknown Error", -2147418113); - } - - - - /// - /// Converts the IntPtr buffer to a property item and then converts its - /// value to a Drawing.Image item - /// - private static System.Drawing.Image convertFromMemory(IntPtr thumbData) - { - propertyItemInternal prop = - (propertyItemInternal)Marshal.PtrToStructure - (thumbData, typeof(propertyItemInternal)); - - // The image data is in the form of a byte array. Write all - // the bytes to a stream and create a new image from that stream - byte[] imageBytes = prop.Value; - MemoryStream stream = new MemoryStream(imageBytes.Length); - stream.Write(imageBytes, 0, imageBytes.Length); - - return System.Drawing.Image.FromStream(stream); - } - - /// - /// Used in Marshal.PtrToStructure(). - /// We need this dummy class because Imaging.PropertyItem is not a "blittable" - /// class and Marshal.PtrToStructure only accepted blittable classes. - /// (It's not blitable because it uses a byte[] array and that's not a blittable - /// type. See MSDN for a definition of Blittable.) - /// - [StructLayout(LayoutKind.Sequential)] - private class propertyItemInternal - { - public int id = 0; - public int len = 0; - public short type = 0; - public IntPtr value = IntPtr.Zero; - - public byte[] Value - { - get - { - byte[] bytes = new byte[(uint)len]; - Marshal.Copy(value, bytes, 0, len); - return bytes; - } - } - } - } -} \ No newline at end of file diff --git a/Source/Components/ImageGlass.Library/Image/ImageInfo.cs b/Source/Components/ImageGlass.Library/Image/ImageInfo.cs deleted file mode 100644 index 79acb9de2..000000000 --- a/Source/Components/ImageGlass.Library/Image/ImageInfo.cs +++ /dev/null @@ -1,301 +0,0 @@ -/* -ImageGlass Project - Image viewer for Windows -Copyright (C) 2014 DUONG DIEU PHAP -Project homepage: http://imageglass.org - -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 . -*/ - -using System; -using System.IO; -using System.Drawing; -using System.Runtime.InteropServices; -using Microsoft.VisualBasic.FileIO; - -namespace ImageGlass.Library.Image -{ - public class ImageInfo - { - [StructLayout(LayoutKind.Sequential)] - private struct SHELLEXECUTEINFO - { - public int cbSize; - public int fMask; - public IntPtr hwnd; - [MarshalAs(UnmanagedType.LPWStr)] - public string lpVerb; - [MarshalAs(UnmanagedType.LPWStr)] - public string lpFile; - [MarshalAs(UnmanagedType.LPWStr)] - public string lpParameters; - [MarshalAs(UnmanagedType.LPWStr)] - public string lpDirectory; - public int nShow; - public IntPtr hInstApp; - public IntPtr lpIDList; - public string lpClass; - public IntPtr hkeyClass; - public int dwHotKey; - public IntPtr hIcon; - public IntPtr hProcess; - } - - [DllImport("shell32.dll", CharSet = CharSet.Auto)] - private static extern int ShellExecuteEx(ref SHELLEXECUTEINFO s); - - /// - /// Show file property dialog - /// - /// file name - /// - public static void DisplayFileProperties(string fileName, IntPtr hwnd) - { - const int SEE_MASK_INVOKEIDLIST = 0xc; - const int SW_SHOW = 5; - SHELLEXECUTEINFO shInfo = new SHELLEXECUTEINFO(); - - shInfo.cbSize = Marshal.SizeOf(shInfo); - shInfo.lpFile = fileName; - shInfo.nShow = SW_SHOW; - shInfo.fMask = SEE_MASK_INVOKEIDLIST; - shInfo.lpVerb = "properties"; - shInfo.lpParameters = "Details"; - shInfo.hwnd = hwnd; - - ShellExecuteEx(ref shInfo); - } - - - /// - /// Get image type name - /// - /// file name - /// - public static string GetImageFileType(string filename) - { - string ext = Path.GetExtension(filename).Replace(".", "").ToLower(); - - switch (ext) - { - case "bmp": - return "Bitmap Image File"; - case "dib": - return "Device Independent Bitmap File"; - case "jpg": - return "JPEG Image File"; - case "jpeg": - return "Joint Photographic Experts Group"; - case "jfif": - return "JPEG File Interchange Format"; - case "jpe": - return "JPEG Image File"; - case "png": - return "Portable Network Graphics"; - case "gif": - return "Graphics Interchange Format File"; - case "ico": - return "Icon File"; - case "emf": - return "Enhanced Windows Metafile"; - case "exif": - return "Exchangeable Image Information File"; - case "wmf": - return "Windows Metafile"; - case "tif": - return "Tagged Image File"; - case "tiff": - return "Tagged Image File Format"; - default: - return ext.ToUpper() + " File"; - } - } - - - /// - /// Get file size format - /// - /// - /// - public static string GetFileSize(string filename) - { - try - { - double mod = 1024; - string[] units = new string[] { "B", "KB", "MB", "GB", "TB", "PB" }; - - FileInfo fi = new FileInfo(filename); - double sized = fi.Length * 1.0f; - int i; - - for (i = 0; sized > mod; i++) - { - sized /= mod; - } - - return string.Format("{0} {1}", Math.Round(sized, 2), units[i]); - } - catch { } - - return " "; - } - - /// - /// Get image size, Width x height string - /// - /// file name - /// - public static string GetWxHSize(string filename) - { - try - { - if (Path.GetExtension(filename).ToLower() != ".ico") - { - using (System.Drawing.Image img = System.Drawing.Image.FromFile(filename)) - { - //get Width x Height - return Convert.ToString(img.Width) + " x " + Convert.ToString(img.Height); - } - } - else - { - Icon ico = new Icon(filename); - //get Width x Height - return Convert.ToString(ico.Width) + " x " + Convert.ToString(ico.Height); - } - } - catch - { - return string.Empty; - } - - } - - /// - /// Get image resolution - /// - /// - /// - public static string GetImageResolution(string filename) - { - try - { - double h = 0; - double v = 0; - - if (Path.GetExtension(filename).ToLower() != ".ico") - { - using (System.Drawing.Image img = System.Drawing.Image.FromFile(filename)) - { - - //get HorizontalResolution - h = Math.Round((double)img.HorizontalResolution, 2); - - //get VerticalResolution - v = Math.Round((double)img.VerticalResolution, 2); - } - } - else - { - Icon ico = new Icon(filename); - - //get HorizontalResolution - h = Math.Round(ico.ToBitmap().HorizontalResolution, 2); - - //get VerticalResolution - v = Math.Round(ico.ToBitmap().VerticalResolution, 2); - } - - return string.Format("{0} x {1}", h, v); - } - catch {} - - return " "; - } - - - /// - /// Get file creation time - /// - /// file name - /// - public static DateTime GetCreateTime(string filename) - { - FileInfo fi = new FileInfo(filename); - - //get Create Time - return fi.CreationTime; - } - - /// - /// Get file last access - /// - /// file name - /// - public static DateTime GetLastAccess(string filename) - { - FileInfo fi = new FileInfo(filename); - //get Create Time - return fi.LastAccessTime; - } - - /// - /// Get file write time - /// - /// file name - /// - public static DateTime GetWriteTime(string filename) - { - FileInfo fi = new FileInfo(filename); - - return fi.LastWriteTime; - } - - /// - /// Rename file - /// - /// old file name - /// new file name - public static void RenameFile(string oldFileName, string newFileName) - { - // Issue 73: Windows ignores case-only changes - if (oldFileName.ToLowerInvariant() == newFileName.ToLowerInvariant()) - { - // user changing only the case of the filename. Need to perform a trick. - File.Move(oldFileName, oldFileName + "_imgglass_extra"); - File.Move(oldFileName + "_imgglass_extra", newFileName); - } - else - { - File.Move(oldFileName, newFileName); - } - } - - - /// - /// Delete file - /// - /// file name - /// True: Move to Recycle bin | False: Delete permanently - /// - public static void DeleteFile(string fileName, bool isMoveToRecycleBin = true) - { - var option = isMoveToRecycleBin ? RecycleOption.SendToRecycleBin : RecycleOption.DeletePermanently; - - FileSystem.DeleteFile(fileName, UIOption.OnlyErrorDialogs, option); - } - - - - } -} diff --git a/Source/Components/ImageGlass.Library/ImageGlass.Library.csproj b/Source/Components/ImageGlass.Library/ImageGlass.Library.csproj deleted file mode 100644 index 07c16ac16..000000000 --- a/Source/Components/ImageGlass.Library/ImageGlass.Library.csproj +++ /dev/null @@ -1,137 +0,0 @@ - - - - - Debug - AnyCPU - {4BB719ED-B68B-4CB1-AAAF-BA0E3BC5FE81} - Library - Properties - ImageGlass.Library - ImageGlass.Library - v4.7.1 - 512 - - - - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - false - - - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - false - - - true - bin\x64\Debug\ - DEBUG;TRACE - full - x64 - prompt - MinimumRecommendedRules.ruleset - false - - - bin\x64\Release\ - TRACE - true - pdbonly - x64 - prompt - MinimumRecommendedRules.ruleset - false - - - true - bin\x86\Debug\ - DEBUG;TRACE - full - x86 - 7.3 - prompt - MinimumRecommendedRules.ruleset - - - bin\x86\Release\ - TRACE - true - pdbonly - x86 - 7.3 - prompt - MinimumRecommendedRules.ruleset - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - {F935DC20-1CF0-11D0-ADB9-00C04FD58A0B} - 1 - 0 - 0 - tlbimp - False - True - - - - - {6cc96a70-6773-41b5-9fca-4f0ab6fad8ca} - ImageGlass.Base - - - - - \ No newline at end of file diff --git a/Source/Components/ImageGlass.Library/Language/Language.cs b/Source/Components/ImageGlass.Library/Language/Language.cs deleted file mode 100644 index 7078a6d36..000000000 --- a/Source/Components/ImageGlass.Library/Language/Language.cs +++ /dev/null @@ -1,736 +0,0 @@ -/* -ImageGlass Project - Image viewer for Windows -Copyright (C) 2020 DUONG DIEU PHAP -Project homepage: https://imageglass.org - -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 . -*/ - -using System.IO; -using System.Windows.Forms; -using System.Xml; - -namespace ImageGlass.Library -{ - public class Language - { - private string _langCode; - private string _langName; - private string _author; - private string _description; - private string _minVersion; - private string _fileName; - private RightToLeft _isRightToLeftLayout; - //private Dictionary _Items; - - private LanguageItem _Items; - - #region Properties - /// - /// Get, set code of language - /// - public string LangCode - { - get { return _langCode; } - set { _langCode = value; } - } - - //Get, set name of language - public string LangName - { - get { return _langName; } - set { _langName = value; } - } - - //Get, set author - public string Author - { - get { return _author; } - set { _author = value; } - } - - /// - /// Get, set description - /// - public string Description - { - get { return _description; } - set { _description = value; } - } - - /// - /// Get, set language file path - /// - public string FileName - { - get { return _fileName; } - set { _fileName = value; } - } - - /// - /// Get, set list of language string - /// - public LanguageItem Items - { - get { return _Items; } - set { _Items = value; } - } - - /// - /// Gets, sets minimum version of ImageGlass that compatible with. - /// - public string MinVersion - { - get { return _minVersion; } - set { _minVersion = value; } - } - - /// - /// Gets, sets the value that indicates right-to-left layout style - /// - public RightToLeft IsRightToLeftLayout - { - get { return _isRightToLeftLayout; } - set { _isRightToLeftLayout = value; } - } - #endregion - - - /// - /// Set default values of Language - /// - public Language() - { - _langCode = "en-US"; - _langName = "Local name of the language"; - _author = "ImageGlass community"; - _description = "English name of language"; - _minVersion = "7.5.1.1"; - _fileName = ""; - _isRightToLeftLayout = RightToLeft.No; - - _Items = new LanguageItem(); - InitDefaultLanguageDictionary(); - } - - - - /// - /// Set values of Language - /// - /// *.igLang path - /// The directory path contains language file (for relative filename) - public Language(string fileName, string dirPath = "") - { - _Items = new LanguageItem(); - InitDefaultLanguageDictionary(); - - _fileName = Path.Combine(dirPath, fileName); - - if (File.Exists(_fileName)) - { - ReadLanguageFile(); - } - } - - - - /// - /// Read language strings from file (new format) - /// - public void ReadLanguageFile() - { - XmlDocument doc = new XmlDocument(); - doc.Load(_fileName); - XmlElement root = (XmlElement)doc.DocumentElement;// - XmlElement nType = (XmlElement)root.SelectNodes("Language")[0]; // - XmlElement n = (XmlElement)nType.SelectNodes("Info")[0];// - - //Get Attributes - LangCode = n.GetAttribute("langCode"); - LangName = n.GetAttribute("langName"); - Author = n.GetAttribute("author"); - Description = n.GetAttribute("description"); - MinVersion = n.GetAttribute("minVersion"); - - bool.TryParse(n.GetAttribute("isRightToLeftLayout"), out bool _isRightToLeftLayout); - IsRightToLeftLayout = _isRightToLeftLayout ? RightToLeft.Yes : RightToLeft.No; //v3.2 - - //Get element - XmlElement nContent = (XmlElement)nType.SelectNodes("Content")[0];// - - //Get all lang items - XmlNodeList nLangList = nContent.SelectNodes("Item");// - - foreach (var item in nLangList) - { - XmlElement nItem = (XmlElement)item; - string _key = nItem.GetAttribute("key"); - string _value = nItem.GetAttribute("value").Replace("\\n", "\n"); - - try - { - Items[_key] = _value; - } - catch { } - } - } - - - - /// - /// Export all language strings to xml file - /// - /// - public void ExportLanguageToXML(string filename) - { - XmlDocument doc = new XmlDocument(); - XmlElement root = doc.CreateElement("ImageGlass");// - XmlElement nType = doc.CreateElement("Language");// - - XmlElement nInfo = doc.CreateElement("Info");// - nInfo.SetAttribute("langCode", LangCode); - nInfo.SetAttribute("langName", LangName); - nInfo.SetAttribute("author", Author); - nInfo.SetAttribute("description", Description); - nInfo.SetAttribute("minVersion", MinVersion); - nInfo.SetAttribute("isRightToLeftLayout", IsRightToLeftLayout.ToString()); - nType.AppendChild(nInfo);// - - XmlElement nContent = doc.CreateElement("Content");// - foreach (var item in Items) - { - XmlElement n = doc.CreateElement("Item"); // - n.SetAttribute("key", item.Key); - n.SetAttribute("value", item.Value); - nContent.AppendChild(n);// - } - nType.AppendChild(nContent); - - root.AppendChild(nType);// - doc.AppendChild(root);// - - doc.Save(filename); - } - - - - /// - /// This is default language of ImageGlass - /// - private void InitDefaultLanguageDictionary() - { - Items.Add("_IncompatibleConfigs", "Some settings are not compatible with your ImageGlass {0}. It's recommended to update them before continuing.\r\n\n- Click Yes to learn about the changes.\r\n- Click No to launch ImageGlass with default settings."); //v7.5 - - - #region frmMain - - #region Main menu - - #region File - Items.Add("frmMain.mnuMainFile", "File"); //v7.0 - Items.Add("frmMain.mnuMainOpenFile", "Open file"); //v3.0 - Items.Add("frmMain.mnuMainOpenImageData", "Open image data from clipboard"); //v3.0 - Items.Add("frmMain.mnuMainNewWindow", "Open new window"); //v7.0 - Items.Add("frmMain.mnuMainNewWindow._Error", "Cannot open new window because only one instance allowed"); //v7.0 - Items.Add("frmMain.mnuMainSaveAs", "Save image as ..."); //v3.0 - Items.Add("frmMain.mnuMainRefresh", "Refresh"); //v3.0 - Items.Add("frmMain.mnuMainReloadImage", "Reload image"); //v5.5 - Items.Add("frmMain.mnuMainReloadImageList", "Reload image list"); //v7.0 - Items.Add("frmMain.mnuMainEditImage", "Edit image {0}"); //v3.0, updated 4.0 - Items.Add("frmMain.mnuMainPrint", "Print"); //v3.0 - #endregion - - - #region Navigation - Items.Add("frmMain.mnuMainNavigation", "Navigation"); //v3.0 - Items.Add("frmMain.mnuMainViewNext", "View next image"); //v3.0 - Items.Add("frmMain.mnuMainViewNext.Shortcut", "Right Arrow / PageDown"); //v6.0 - Items.Add("frmMain.mnuMainViewPrevious", "View previous image"); //v3.0 - Items.Add("frmMain.mnuMainViewPrevious.Shortcut", "Left Arrow / PageUp"); // V6.0 - - Items.Add("frmMain.mnuMainGoto", "Go to ..."); //v3.0 - Items.Add("frmMain.mnuMainGotoFirst", "Go to the first image"); //v3.0 - Items.Add("frmMain.mnuMainGotoLast", "Go to the last image"); //v3.0 - - Items.Add("frmMain.mnuMainNextPage", "View next page"); //v7.5 - Items.Add("frmMain.mnuMainPrevPage", "View previous page"); //v7.5 - Items.Add("frmMain.mnuMainFirstPage", "View the first page"); //v7.5 - Items.Add("frmMain.mnuMainLastPage", "View the last page"); //v7.5 - #endregion - - - #region Zoom - Items.Add("frmMain.mnuMainZoom", "Zoom"); //v7.0 - Items.Add("frmMain.mnuMainZoomIn", "Zoom in"); //v3.0 - Items.Add("frmMain.mnuMainZoomOut", "Zoom out"); //v3.0 - Items.Add("frmMain.mnuMainScaleToFit", "Scale to fit"); //v3.5 - Items.Add("frmMain.mnuMainScaleToFill", "Scale to fill"); //v7.5 - Items.Add("frmMain.mnuMainActualSize", "Actual size"); //v3.0 - Items.Add("frmMain.mnuMainLockZoomRatio", "Lock zoom ratio"); //v3.0 - Items.Add("frmMain.mnuMainAutoZoom", "Auto zoom"); //v5.5 - Items.Add("frmMain.mnuMainScaleToWidth", "Scale to width"); //v3.0 - Items.Add("frmMain.mnuMainScaleToHeight", "Scale to height"); //v3.0 - #endregion - - - #region Image - Items.Add("frmMain.mnuMainImage", "Image"); //v7.0 - Items.Add("frmMain.mnuMainChannels", "View channels"); //v7.0 - Items.Add("frmMain.mnuMainChannels._All", "All"); //v7.0 - Items.Add("frmMain.mnuMainChannels._Red", "Red"); //v7.0 - Items.Add("frmMain.mnuMainChannels._Green", "Green"); //v7.0 - Items.Add("frmMain.mnuMainChannels._Blue", "Blue"); //v7.0 - Items.Add("frmMain.mnuMainChannels._Black", "Black"); //v7.0 - Items.Add("frmMain.mnuMainChannels._Alpha", "Alpha"); //v7.0 - Items.Add("frmMain.mnuMainRotateLeft", "Rotate left"); //v7.5 - Items.Add("frmMain.mnuMainRotateRight", "Rotate right"); //v7.5 - Items.Add("frmMain.mnuMainFlipHorz", "Flip Horizontal"); // V6.0 - Items.Add("frmMain.mnuMainFlipVert", "Flip Vertical"); // V6.0 - Items.Add("frmMain.mnuMainRename", "Rename image"); //v3.0 - Items.Add("frmMain.mnuMainMoveToRecycleBin", "Move to recycle bin"); //v3.0 - Items.Add("frmMain.mnuMainDeleteFromHardDisk", "Delete from hard disk"); //v3.0 - Items.Add("frmMain.mnuMainExtractPages", "Extract image pages ({0})"); //v7.5 - Items.Add("frmMain.mnuMainStartStopAnimating", "Start / Stop animating image"); //v3.0 - Items.Add("frmMain.mnuMainSetAsDesktop", "Set as Desktop background"); //v3.0 - Items.Add("frmMain.mnuMainSetAsLockImage", "Set as Lock screen image"); // V6.0 - Items.Add("frmMain.mnuMainImageLocation", "Open image location"); //v3.0 - Items.Add("frmMain.mnuMainImageProperties", "Image properties"); //v3.0 - #endregion - - - #region Clipboard - Items.Add("frmMain.mnuMainClipboard", "Clipboard"); //v3.0 - Items.Add("frmMain.mnuMainCopy", "Copy"); //v3.0 - Items.Add("frmMain.mnuMainCopyImageData", "Copy image data"); //v5.0 - Items.Add("frmMain.mnuMainCut", "Cut"); //v3.0 - Items.Add("frmMain.mnuMainCopyImagePath", "Copy image path"); //v3.0 - Items.Add("frmMain.mnuMainClearClipboard", "Clear clipboard"); //v3.0 - #endregion - - - Items.Add("frmMain.mnuWindowFit", "Window fit"); //v7.5 - Items.Add("frmMain.mnuMainFullScreen", "Full screen"); //v3.0 - Items.Add("frmMain.mnuFrameless", "Frameless"); //v7.5 - - - #region Slideshow - Items.Add("frmMain.mnuMainSlideShow", "Slideshow"); //v3.0 - Items.Add("frmMain.mnuMainSlideShowStart", "Start slideshow"); //v3.0 - Items.Add("frmMain.mnuMainSlideShowPause", "Pause / Resume slideshow"); //v3.0 - Items.Add("frmMain.mnuMainSlideShowExit", "Exit slideshow"); //v3.0 - #endregion - - - Items.Add("frmMain.mnuMainShare", "Share ..."); //v3.0 - - - #region Layout - Items.Add("frmMain.mnuMainLayout", "Layout"); //v3.0 - Items.Add("frmMain.mnuMainToolbar", "Toolbar"); //v3.0 - Items.Add("frmMain.mnuMainThumbnailBar", "Thumbnail panel"); //v3.0 - Items.Add("frmMain.mnuMainCheckBackground", "Checkerboard background"); //v3.0, updated v5.0 - Items.Add("frmMain.mnuMainAlwaysOnTop", "Keep window always on top"); //v3.2 - #endregion - - - #region Tools - Items.Add("frmMain.mnuMainTools", "Tools"); //v3.0 - Items.Add("frmMain.mnuMainColorPicker", "Color picker"); //v5.0 - Items.Add("frmMain.mnuMainPageNav", "Page navigation"); // V7.5 - #endregion - - - Items.Add("frmMain.mnuMainSettings", "Settings"); //v3.0 - - - #region Help - Items.Add("frmMain.mnuMainHelp", "Help"); //v7.0 - Items.Add("frmMain.mnuMainAbout", "About"); //v3.0 - Items.Add("frmMain.mnuMainFirstLaunch", "First-launch configurations"); //v5.0 - Items.Add("frmMain.mnuMainCheckForUpdate._NoUpdate", "Check for update"); //v5.0 - Items.Add("frmMain.mnuMainCheckForUpdate._NewVersion", "A new version is available!"); //v5.0 - Items.Add("frmMain.mnuMainReportIssue", "Report an issue"); //v3.0 - - - Items.Add("frmMain.mnuMainExitApplication", "Exit ImageGlass"); //v7.0 - #endregion - - #endregion - - - #region Form message texts - Items.Add("frmMain.picMain._ErrorText", "ImageGlass cannot open this picture because the file appears to be damaged, corrupted or not supported.");// v2.0 beta, updated 4.0 - Items.Add("frmMain._ImageNotExist", "The viewing image doesn't exist.");// v4.5 - Items.Add("frmMain.btnMenu", "Menu (Hotkey: `)"); // v3.0 - - Items.Add("frmMain._OpenFileDialog", "All supported files"); - Items.Add("frmMain._Files", "file(s)"); // v7.5 - Items.Add("frmMain._Pages", "pages"); // v7.5 - Items.Add("frmMain._ImageData", "Image data"); // v5.0 - Items.Add("frmMain._RenameDialogText", "Rename"); // v3.5 - Items.Add("frmMain._RenameDialog", "Enter new filename"); - Items.Add("frmMain._GotoDialogText", "Enter the image index to view it. Press ENTER"); - Items.Add("frmMain._DeleteDialogText", "Delete file '{0}' ?"); - Items.Add("frmMain._DeleteDialogTitle", "Confirm"); - - Items.Add("frmMain._ExtractPageText", "Extracting image pages. Please select output folder."); - Items.Add("frmMain._FullScreenMessage", "Press ALT+ENTER to exit full screen mode.");// v2.0 beta, v6.0 - Items.Add("frmMain._SlideshowMessage", "Press ESC to exit slideshow.\n Right click to open context menu."); // v2.0 beta - Items.Add("frmMain._SlideshowMessagePause", "Slideshow is paused"); // v4.0 - Items.Add("frmMain._SlideshowMessageResume", "Slideshow is resumed"); // v4.0 - Items.Add("frmMain._CopyFileText", "Copied {0} file(s)"); // v2.0 final - Items.Add("frmMain._CutFileText", "Cut {0} file(s)"); // v2.0 final - Items.Add("frmMain._CopyImageData", "Image was copied to clipboard"); // v5.0 - Items.Add("frmMain._ClearClipboard", "Clipboard was cleared"); // v2.0 final - Items.Add("frmMain._SaveChanges", "Saving change..."); // v2.0 final - Items.Add("frmMain._SaveImage", "Image was saved to\r\n{0}"); // v5.0 - Items.Add("frmMain._SaveImageError", "Unable to save image\r\n{0}."); // v5.0 - Items.Add("frmMain._Loading", "Loading..."); // v3.0 - Items.Add("frmMain._FirstItemOfList", "Reached the first image"); // v4.0 - Items.Add("frmMain._LastItemOfList", "Reached the last image"); // v4.0 - Items.Add("frmMain._CannotRotateAnimatedFile", "Modification for animated format is not supported"); // Added V5.0; Modified V6.0 - Items.Add("frmMain._SetLockImage_Error", "There was an error while setting lock screen image"); // v6.0 - Items.Add("frmMain._SetLockImage_Success", "Lock screen image was set successfully"); //v6.0 - Items.Add("frmMain._SetBackground_Error", "There was an error while setting desktop background"); // v6.0 - Items.Add("frmMain._SetBackground_Success", "Desktop background was set successfully"); // v6.0 - - Items.Add("frmMain._PageExtractComplete", "Page extraction completed."); // v7.5 - Items.Add("frmMain._Frameless", "Hold SHIFT to move the window."); // v7.5 - #endregion - - #endregion - - - #region frmAbout - Items.Add("frmAbout.lblSlogant", "A lightweight, versatile image viewer"); //changed 4.0 - Items.Add("frmAbout.lblInfo", "Information"); - Items.Add("frmAbout.lblComponent", "Components"); - Items.Add("frmAbout.lblReferences", "References"); - Items.Add("frmAbout.lblVersion", "Version: {0}"); - Items.Add("frmAbout.lblInfoContact", "Contact"); - Items.Add("frmAbout.lblSoftwareUpdate", "Software updates"); - Items.Add("frmAbout.lnkCheckUpdate", "» Check for update"); - Items.Add("frmAbout._Text", "About"); - Items.Add("frmAbout._PortableText", "[Portable]"); //v4.0 - #endregion - - - #region frmSetting - Items.Add("frmSetting._Text", "Settings"); - - Items.Add("frmSetting.btnSave", "Save"); //v4.1 - Items.Add("frmSetting.btnCancel", "Cancel"); //v4.1 - Items.Add("frmSetting.btnApply", "Apply"); //v4.1 - - - #region Tab names - Items.Add("frmSetting.lblGeneral", "General"); - Items.Add("frmSetting.lblImage", "Image"); //v4.0 - Items.Add("frmSetting.lblEdit", "Edit"); //v6.0 - Items.Add("frmSetting.lblFileTypeAssoc", "File Type Associations"); //v2.0 final - Items.Add("frmSetting.lblToolbar", "Toolbar"); //v5.0 - Items.Add("frmSetting.lblLanguage", "Language"); - Items.Add("frmSetting.lblTheme", "Theme"); //v5.0 - Items.Add("frmSetting.lblKeyboard", "Keyboard"); // v7.0 - #endregion - - - #region TAB General - #region Start up - Items.Add("frmSetting.lblHeadStartup", "Start up"); //v4.0 - Items.Add("frmSetting.chkWelcomePicture", "Show welcome picture"); - Items.Add("frmSetting.chkLastSeenImage", "Open last seen image"); //v6.0 - Items.Add("frmSetting.chkShowToolBar", "Show toolbar when starting up"); //v4.0 - - #endregion - - - #region Portable mode - //Items.Add("frmSetting.lblHeadPortableMode", "Portable mode"); //v4.0, removed 5.5.x - - //Items.Add("frmSetting.chkPortableMode", "Enable Portable mode"); //remove v4.0 - //Items.Add("frmSetting.chkPortableMode._Enabled", "Portable mode is enabled"); //v4.5, removed 5.5.x - //Items.Add("frmSetting.chkPortableMode._Disabled", "Portable mode is disabled on the installed folder:\r\n{0}"); //v4.5, removed 5.5.x - - Items.Add("frmSetting.lblHeadConfigDir", "Configuration directory"); // 5.5.x - #endregion - - - #region Others - Items.Add("frmSetting.lblHeadOthers", "Others"); //v4.0 - Items.Add("frmSetting.chkAutoUpdate", "Check for update automatically"); - Items.Add("frmSetting.chkAllowMultiInstances", "Allow multiple instances of the program"); //v3.0 - Items.Add("frmSetting.chkESCToQuit", "Allow to press ESC to quit application"); //v2.0 final - Items.Add("frmSetting.chkConfirmationDelete", "Display Delete confirmation dialog"); //v4.0 - Items.Add("frmSetting.chkShowScrollbar", "Display viewer scrollbars"); //v4.1 - Items.Add("frmSetting.chkDisplayBasename", "Display basename of the viewing image on title bar"); //v5.0 - Items.Add("frmSetting.chkShowNavButtons", "Display navigation arrow buttons"); //v6.0 - Items.Add("frmSetting.chkShowCheckerboardOnlyImage", "Display checkerboard only in the image region"); //v6.0 - Items.Add("frmSetting.chkCenterWindowFit", "Auto-center the window in Window Fit mode"); //v7.5 - Items.Add("frmSetting.chkShowToast", "Show toast message"); //v7.5 - Items.Add("frmSetting.lblBackGroundColor", "Background color"); - Items.Add("frmSetting.lnkResetBackgroundColor", "Reset"); // v4.0 - #endregion - #endregion - - - #region TAB Image - #region Image loading - Items.Add("frmSetting.lblHeadImageLoading", "Image loading"); //v4.0 - Items.Add("frmSetting.chkFindChildFolder", "Find images in child folder"); - Items.Add("frmSetting.chkShowHiddenImages", "Show hidden images"); //v4.5 - Items.Add("frmSetting.chkLoopViewer", "Loop back viewer to the first image when reaching the end of the list"); //v4.0 - Items.Add("frmSetting.chkIsCenterImage", "Center image on viewer"); //v7.0 - // Items.Add("frmSetting.chkImageBoosterBack", "Turn on Image Booster when navigate back (need more ~20% RAM)"); //v2.0 final // removed 7.0 - - Items.Add("frmSetting.lblImageLoadingOrder", "Image loading order"); - Items.Add("frmSetting.cmbImageOrder._Name", "Name (default)"); - Items.Add("frmSetting.cmbImageOrder._Length", "Length"); - Items.Add("frmSetting.cmbImageOrder._CreationTime", "Creation time"); - Items.Add("frmSetting.cmbImageOrder._LastAccessTime", "Last access time"); - Items.Add("frmSetting.cmbImageOrder._LastWriteTime", "Last write time"); - Items.Add("frmSetting.cmbImageOrder._Extension", "Extension"); - Items.Add("frmSetting.cmbImageOrder._Random", "Random"); - - Items.Add("frmSetting.cmbImageOrderType._Asc", "Ascending"); // V7.0 - Items.Add("frmSetting.cmbImageOrderType._Desc", "Descending"); // V7.0 - Items.Add("frmSetting.chkUseFileExplorerSortOrder", "Use Windows File Explorer sort order if possible"); //v7.0 - Items.Add("frmSetting.lblImageBoosterCachedCount", "Number of images cached by ImageBooster (one direction)"); //v7.0 - #endregion - - - #region Color Management - Items.Add("frmSetting.lblColorManagement", "Color management"); //v6.0 - Items.Add("frmSetting.chkApplyColorProfile", "Apply also for images without embedded color profile"); //v6.0 - Items.Add("frmSetting.lblColorProfile", "Color profile:"); //v6.0 - Items.Add("frmSetting.lnkColorProfileBrowse", "Browse"); //v6.0 - Items.Add("frmSetting.cmbColorProfile._None", "None"); //v6.0 - Items.Add("frmSetting.cmbColorProfile._CustomProfileFile", "Custom..."); //v6.0 - - #endregion - - - #region Mouse wheel actions - Items.Add("frmSetting.lblHeadMouseWheelActions", "Mouse wheel actions"); - Items.Add("frmSetting.lblMouseWheel", "Mouse wheel"); - Items.Add("frmSetting.lblMouseWheelAlt", "Mouse wheel + Alt"); - Items.Add("frmSetting.lblMouseWheelCtrl", "Mouse wheel + Ctrl"); - Items.Add("frmSetting.lblMouseWheelShift", "Mouse wheel + Shift"); - Items.Add("frmSetting.cmbMouseWheel._DoNothing", "Do nothing"); - Items.Add("frmSetting.cmbMouseWheel._Zoom", "Zoom"); - Items.Add("frmSetting.cmbMouseWheel._ScrollVertically", "Scroll vertically"); - Items.Add("frmSetting.cmbMouseWheel._ScrollHorizontally", "Scroll horizontally"); - Items.Add("frmSetting.cmbMouseWheel._BrowseImages", "Previous/next image"); - #endregion - - - #region Zooming - Items.Add("frmSetting.lblHeadZooming", "Zooming"); //v4.0 - //Items.Add("frmSetting.chkMouseNavigation", "Use the mouse wheel to browse images, hold CTRL for zooming"); //+3.5 - Items.Add("frmSetting.lblGeneral_ZoomOptimization", "Zoom optimization"); //-3.0, +3.5 - Items.Add("frmSetting.cmbZoomOptimization._Auto", "Auto"); //-3.2, +3.5 - Items.Add("frmSetting.cmbZoomOptimization._SmoothPixels", "Smooth pixels"); //-3.2, +3.5 - Items.Add("frmSetting.cmbZoomOptimization._ClearPixels", "Clear pixels"); //-3.2, +3.5 - - Items.Add("frmSetting.lblZoomLevels", "Zoom levels"); //v7.0 - Items.Add("frmSetting.txtZoomLevels._Error", "There was error updating Zoom levels. Error message:\r\n\n{0}"); //v7.0 - #endregion - - - #region Thumbnail bar - Items.Add("frmSetting.lblHeadThumbnailBar", "Thumbnail bar"); //v4.0 - Items.Add("frmSetting.chkThumbnailVertical", "Show thumbnails on right side"); - Items.Add("frmSetting.chkShowThumbnailScrollbar", "Show thumbnails scroll bar"); //v5.5 - //Items.Add("frmSetting.lblGeneral_MaxFileSize", "Maximum thumbnail file size (MB)"); //removed v5.0 - Items.Add("frmSetting.lblGeneral_ThumbnailSize", "Thumbnail dimension (pixel)"); // v3.0 - #endregion - - - #region Slideshow - Items.Add("frmSetting.lblHeadSlideshow", "Slideshow"); // v4.0 - Items.Add("frmSetting.chkLoopSlideshow", "Loop back slideshow to the first image when reaching the end of the list"); // v2.0 final - Items.Add("frmSetting.chkShowSlideshowCountdown", "Show slideshow countdown"); // v7.5 - Items.Add("frmSetting.lblSlideshowInterval", "Slideshow interval: {0}"); - #endregion - - - - #endregion - - - #region TAB Edit - //Items.Add("frmSetting.lblHeadImageEditing", "Image editing"); //v4.0, removed v6.0 - Items.Add("frmSetting.chkSaveOnRotate", "Save the viewing image after rotating"); //v4.5 - Items.Add("frmSetting.lblSelectAppForEdit", "Select application for image editing"); //v4.5 - Items.Add("frmSetting.btnEditEditExt", "Edit"); //v4.0 - Items.Add("frmSetting.btnEditResetExt", "Reset to default"); //v4.0 - Items.Add("frmSetting.btnEditEditAllExt", "Edit all extensions"); //v4.1 - Items.Add("frmSetting._allExtensions", "all extensions"); //v4.1 - Items.Add("frmSetting.lvImageEditing.clnFileExtension", "File extension"); //v4.0 - Items.Add("frmSetting.lvImageEditing.clnAppName", "App name"); //v4.0 - Items.Add("frmSetting.lvImageEditing.clnAppPath", "App path"); //v4.0 - Items.Add("frmSetting.lvImageEditing.clnAppArguments", "App arguments"); //v4.0 - - Items.Add("frmSetting.chkSaveModifyDate", "Preserve the image's Modify Date on save"); //v5.5 - #endregion - - - #region TAB File Associations - Items.Add("frmSetting.lblSupportedExtension", "Supported formats: {0}"); // v3.0, updated v4.0 - Items.Add("frmSetting.lnkOpenFileAssoc", "Open File Type Associations"); // 4.0 - - Items.Add("frmSetting.btnAddNewExt", "Add"); // 4.0 - Items.Add("frmSetting.btnRegisterExt", "Set as Default photo viewer"); // 4.0, updated v5.0 - Items.Add("frmSetting.btnDeleteExt", "Delete"); // 4.0 - Items.Add("frmSetting.btnResetExt", "Reset to default"); // 4.0 - Items.Add("frmSetting._RegisterWebToApp_Error", "Unable to register Web-to-App linking"); // 7.0 - Items.Add("frmSetting._RegisterAppExtensions_Error", "Unable to register file extensions for ImageGlass app"); // 6.0 - Items.Add("frmSetting._RegisterAppExtensions_Success", "All file extensions are registered successfully! To set ImageGlass as Default photo viewer, please open Windows Settings > Default Apps, and manually select ImageGlass app under Photo Viewer section."); // 6.0 - #endregion - - - #region TAB Toolbar - Items.Add("frmSetting.lblToolbarPosition", "Toolbar position:"); // v5.5 - Items.Add("frmSetting.cmbToolbarPosition._Top", "Top"); // v5.5 - Items.Add("frmSetting.cmbToolbarPosition._Bottom", "Bottom"); // v5.5 - - // V5.0 - Items.Add("frmSetting._separator", "Separator"); // i.e. 'toolbar separator' - Items.Add("frmSetting.lblToolbar._Tooltip", "Configure toolbar buttons"); // tooltip - Items.Add("frmSetting.lblUsedBtns", "Current Buttons:"); - Items.Add("frmSetting.lblAvailBtns", "Available Buttons:"); - Items.Add("frmSetting.btnMoveDown._Tooltip", "Move selected button down"); // tooltip - Items.Add("frmSetting.btnMoveLeft._Tooltip", "Remove selected button(s) from the toolbar"); // tooltip - Items.Add("frmSetting.btnMoveRight._Tooltip", "Add selected button(s) to the toolbar"); // tooltip - Items.Add("frmSetting.btnMoveUp._Tooltip", "Move selected button up"); // tooltip - - Items.Add("frmSetting.chkHorzCenterToolbarBtns", "Center toolbar buttons horizontally in window"); // V6.0 - #endregion - - - #region TAB Tools - Items.Add("frmSetting.chkColorUseRGBA", "Use RGBA format"); //v5.0 - Items.Add("frmSetting.chkColorUseHEXA", "Use HEX with alpha format"); //v5.0 - Items.Add("frmSetting.chkColorUseHSLA", "Use HSLA format"); //v5.0 - Items.Add("frmSetting.lblDefaultColorCode", "Default color code format when copying"); //v5.0 - - Items.Add("frmSetting.chkShowPageNavAuto", "Auto-show Page navigation tool for multi-page image"); //v7.5 - #endregion - - - #region TAB Language - Items.Add("frmSetting.lblLanguageText", "Installed languages"); - Items.Add("frmSetting.lnkRefresh", "> Refresh"); - Items.Add("frmSetting.lblLanguageWarning", "This language pack may be not compatible with {0}"); //v3.2 - - Items.Add("frmSetting.lnkInstallLanguage", "> Install new language pack (*.iglang)"); //v2.0 final - Items.Add("frmSetting.lnkCreateNew", "> Create new language pack"); - Items.Add("frmSetting.lnkEdit", "> Edit selected language pack"); - Items.Add("frmSetting.lnkGetMoreLanguage", "> Get more language packs"); - #endregion - - - #region TAB Theme - - Items.Add("frmSetting.lblInstalledThemes", "Installed themes: {0}"); //v5.0 - Items.Add("frmSetting.lnkThemeDownload", "Download themes"); //v5.0 - Items.Add("frmSetting.btnThemeRefresh", "Refresh"); //v5.0 - Items.Add("frmSetting.btnThemeInstall", "Install"); //v5.0 - Items.Add("frmSetting.btnThemeUninstall", "Uninstall"); //v5.0 - Items.Add("frmSetting.btnThemeSaveAs", "Save As"); //v5.0 - Items.Add("frmSetting.btnThemeFolderOpen", "Open Theme Folder"); //v5.0 - Items.Add("frmSetting.btnThemeEdit._Edit", "Edit Selected Theme"); //v5.0 - Items.Add("frmSetting.btnThemeEdit._New", "Create New Theme"); //v5.0 - Items.Add("frmSetting.btnThemeApply", "Apply Theme"); //v5.0 - - Items.Add("frmSetting.txtThemeInfo._Name", "Name"); //v5.0 - Items.Add("frmSetting.txtThemeInfo._Version", "Version"); //v5.0 - Items.Add("frmSetting.txtThemeInfo._Author", "Author"); //v5.0 - Items.Add("frmSetting.txtThemeInfo._Email", "Email"); //v5.0 - Items.Add("frmSetting.txtThemeInfo._Website", "Website"); //v5.0 - Items.Add("frmSetting.txtThemeInfo._Compatibility", "Compatibility"); //v5.0 - Items.Add("frmSetting.txtThemeInfo._Description", "Description"); //v5.0 - - Items.Add("frmSetting.btnThemeInstall._Success", "Your theme was installed successfully!"); //v5.0 - Items.Add("frmSetting.btnThemeInstall._Error", "Unable to install your theme."); //v5.0 - Items.Add("frmSetting.btnThemeUninstall._Error", "Unable to uninstall the selected theme."); //v5.0 - Items.Add("frmSetting.btnThemeSaveAs._Success", "Your selected theme has been saved in {0}"); //v5.0 - Items.Add("frmSetting.btnThemeSaveAs._Error", "Unable to save your selected theme."); //v5.0 - Items.Add("frmSetting.btnThemeApply._Success", "The selected theme was applied successfully!"); //v5.0 - Items.Add("frmSetting.btnThemeApply._Error", "Unable to apply the selected theme."); //v5.0 - - #endregion - - - #region TAB Keyboard - Items.Add("frmSetting.btnKeyReset", "Reset to default"); // v7.0 - Items.Add("frmSetting.lblKeysSpaceBack", "Space / Backspace"); // v7.0 - Items.Add("frmSetting.lblKeysPageUpDown", "PageUp / PageDown"); // v7.0 - Items.Add("frmSetting.lblKeysUpDown", "Up / Down arrows"); // v7.0 - Items.Add("frmSetting.lblKeysLeftRight", "Left / Right arrows"); // v7.0 - - #region Actions Combo Values - Items.Add("frmSetting.KeyActions._PrevNextImage","Previous / Next Image"); // v7.0 - Items.Add("frmSetting.KeyActions._PanLeftRight", "Pan Left / Right"); // v7.0 - Items.Add("frmSetting.KeyActions._PanUpDown", "Pan Up / Down"); // v7.0 - Items.Add("frmSetting.KeyActions._ZoomInOut", "Zoom In / Out"); // v7.0 - Items.Add("frmSetting.KeyActions._PauseSlideshow", "Pause slideshow"); // v7.0 - Items.Add("frmSetting.KeyActions._DoNothing", "Do nothing"); // v7.0 - #endregion - - #endregion - - #endregion - - - #region frmAddNewFormat - Items.Add("frmAddNewFormat.lblFileExtension", "File extension"); // 4.0 - Items.Add("frmAddNewFormat.btnOK", "OK"); // 4.0 - Items.Add("frmAddNewFormat.btnClose", "Close"); // 4.0 - #endregion - - - #region frmEditApp - Items.Add("frmEditApp.lblFileExtension", "File extension"); // 4.0 - Items.Add("frmEditApp.lblAppName", "App name"); // 4.0 - Items.Add("frmEditApp.lblAppPath", "App path"); // 4.0 - Items.Add("frmEditApp.lblAppArguments", "App arguments"); // 4.0 - Items.Add("frmEditApp.btnReset", "Reset"); // 4.0 - Items.Add("frmEditApp.btnOK", "OK"); // 4.0 - Items.Add("frmEditApp.btnClose", "Close"); // 4.0 - Items.Add("frmEditApp.lblPreviewLabel", "Preview"); // 5.0 - #endregion - - - #region frmFirstLaunch - Items.Add("frmFirstLaunch._Text", "First-Launch Configurations"); //v5.0 - Items.Add("frmFirstLaunch._ConfirmCloseProcess", "ImageGlass needs to close all its processes to apply the new settings, do you want to continue?"); //v7.5 - Items.Add("frmFirstLaunch.lblStepNumber", "Step {0}/{1}"); //v5.0 - Items.Add("frmFirstLaunch.btnNextStep", "Next"); //v5.0 - Items.Add("frmFirstLaunch.btnNextStep._Done", "Done!"); //v5.0 - Items.Add("frmFirstLaunch.lnkSkip", "Skip this and Launch ImageGlass"); //v5.0 - - Items.Add("frmFirstLaunch.lblLanguage", "Select Language"); //v5.0 - Items.Add("frmFirstLaunch.lblLayout", "Select Layout"); //v5.0 - Items.Add("frmFirstLaunch.cmbLayout._Standard", "Standard"); //v5.0 - Items.Add("frmFirstLaunch.cmbLayout._Designer", "Designer"); //v5.0 - Items.Add("frmFirstLaunch.lblTheme", "Select Theme"); //v5.0 - Items.Add("frmFirstLaunch.lblDefaultApp", "Set ImageGlass as Default Photo Viewer?"); //v5.0 - Items.Add("frmFirstLaunch.btnSetDefaultApp", "Yes"); //v5.0 - #endregion - - } - } -} diff --git a/Source/Components/ImageGlass.Library/Language/LanguageItem.cs b/Source/Components/ImageGlass.Library/Language/LanguageItem.cs deleted file mode 100644 index a89509ece..000000000 --- a/Source/Components/ImageGlass.Library/Language/LanguageItem.cs +++ /dev/null @@ -1,59 +0,0 @@ -/* -ImageGlass Project - Image viewer for Windows -Copyright (C) 2016 DUONG DIEU PHAP -Project homepage: http://imageglass.org - -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 . -*/ - -using System; -using System.Collections.Generic; - -namespace ImageGlass.Library -{ - public enum LanguageItemState - { - Inactive = 0, - Active = 1 - } - - public class LanguageItem : Dictionary - { - /// - /// ImageGlass version that supported - /// - public Version Version { get; set; } - - /// - /// Gets, sets value that indicates if this language string is active or not - /// - public LanguageItemState State { get; set; } - - /// - /// Author remarks - /// - public string Remarks { get; set; } - - /// - /// Language text object - /// - public LanguageItem() - { - Version = new Version("3.5.0.0"); - State = LanguageItemState.Inactive; - Remarks = string.Empty; - } - } - -} diff --git a/Source/Components/ImageGlass.Library/Menu.cs b/Source/Components/ImageGlass.Library/Menu.cs deleted file mode 100644 index 76b677f57..000000000 --- a/Source/Components/ImageGlass.Library/Menu.cs +++ /dev/null @@ -1,95 +0,0 @@ -/* -ImageGlass Project - Image viewer for Windows -Copyright (C) 2020 DUONG DIEU PHAP -Project homepage: http://imageglass.org - -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 . -*/ - -using System.ComponentModel; -using System.Drawing; -using System.Reflection; -using System.Windows.Forms; - -namespace ImageGlass.Library -{ - public static class Menu - { - /// - /// Clone ToolStripMenu item - /// - /// ToolStripMenuItem - /// - public static ToolStripMenuItem Clone(ToolStripMenuItem mnu) - { - ToolStripMenuItem m = new ToolStripMenuItem(); - - //clone all events - var eventsField = typeof(Component).GetField("events", BindingFlags.NonPublic | BindingFlags.Instance); - var eventHandlerList = eventsField.GetValue(mnu); - eventsField.SetValue(m, eventHandlerList); - - //clone all properties - m.AccessibleName = mnu.AccessibleName; - m.AccessibleRole = mnu.AccessibleRole; - m.Alignment = mnu.Alignment; - m.AllowDrop = mnu.AllowDrop; - m.Anchor = mnu.Anchor; - m.AutoSize = mnu.AutoSize; - m.AutoToolTip = mnu.AutoToolTip; - m.BackColor = Color.Transparent; - m.BackgroundImage = mnu.BackgroundImage; - m.BackgroundImageLayout = mnu.BackgroundImageLayout; - m.Checked = mnu.Checked; - m.CheckOnClick = mnu.CheckOnClick; - m.CheckState = mnu.CheckState; - m.DisplayStyle = mnu.DisplayStyle; - m.Dock = mnu.Dock; - m.DoubleClickEnabled = mnu.DoubleClickEnabled; - m.DropDown = mnu.DropDown; - m.Enabled = mnu.Enabled; - m.Font = mnu.Font; - m.ForeColor = mnu.ForeColor; - m.Image = mnu.Image; - m.ImageAlign = mnu.ImageAlign; - m.ImageScaling = mnu.ImageScaling; - m.ImageTransparentColor = mnu.ImageTransparentColor; - m.Margin = mnu.Margin; - m.MergeAction = mnu.MergeAction; - m.MergeIndex = mnu.MergeIndex; - m.Name = mnu.Name; - m.Overflow = mnu.Overflow; - m.Padding = mnu.Padding; - m.RightToLeft = mnu.RightToLeft; - - m.ShortcutKeys = mnu.ShortcutKeys; - m.ShowShortcutKeys = mnu.ShowShortcutKeys; - m.ShortcutKeyDisplayString = mnu.ShortcutKeyDisplayString; - m.Tag = mnu.Tag; - m.Text = mnu.Text; - m.TextAlign = mnu.TextAlign; - m.TextDirection = mnu.TextDirection; - m.TextImageRelation = mnu.TextImageRelation; - m.ToolTipText = mnu.ToolTipText; - - m.Available = mnu.Available; - - if (!mnu.AutoSize) - { - m.Size = mnu.Size; - } - return m; - } - } -} diff --git a/Source/Components/ImageGlass.Library/Net/DownloadFile.cs b/Source/Components/ImageGlass.Library/Net/DownloadFile.cs deleted file mode 100644 index 5dee9a9e5..000000000 --- a/Source/Components/ImageGlass.Library/Net/DownloadFile.cs +++ /dev/null @@ -1,221 +0,0 @@ -/* -ImageGlass Project - Image viewer for Windows -Copyright (C) 2013 DUONG DIEU PHAP -Project homepage: http://imageglass.org - -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 . -*/ - -using System; -using System.Net; -using System.IO; - -namespace ImageGlass.Library.Net -{ - public class FileDownloader - { - - public event AmountDownloadedChangedEventHandler AmountDownloadedChanged; - public delegate void AmountDownloadedChangedEventHandler(long iNewProgress); - public event FileDownloadSizeObtainedEventHandler FileDownloadSizeObtained; - public delegate void FileDownloadSizeObtainedEventHandler(long iFileSize); - public event FileDownloadCompleteEventHandler FileDownloadComplete; - public delegate void FileDownloadCompleteEventHandler(); - public event FileDownloadFailedEventHandler FileDownloadFailed; - public delegate void FileDownloadFailedEventHandler(Exception ex); - - private string _currentFile = string.Empty; - - /// - /// Tập tin hiện tại - /// - public string CurrentFile - { - get { return _currentFile; } - } - - /// - /// Tải 1 tập tin - /// - /// Liên kết của tập tin - /// Nơi lưu - /// - public bool DownloadFile(string URL, string filename) - { - try - { - _currentFile = GetFileName(URL); - WebClient WC = new WebClient(); - WC.DownloadFile(URL, filename); - if (FileDownloadComplete != null) - { - FileDownloadComplete(); - } - return true; - } - catch (Exception ex) - { - if (FileDownloadFailed != null) - { - FileDownloadFailed(ex); - } - return false; - } - } - - /// - /// Lấy tên tập tin từ liên kết - /// - /// Liên kết - /// - private string GetFileName(string URL) - { - try - { - return URL.Substring(URL.LastIndexOf("/") + 1); - } - catch - { - return URL; - } - } - - /// - /// Tải 1 tập tin (hỗ trợ thông tin dung lượng tải) - /// - /// Liên kết của tập tin - /// Đương dẫn lưu tập tin - /// - public bool DownloadFileWithProgress(string URL, string filename) - { - FileStream fs = default(FileStream); - try - { - _currentFile = GetFileName(URL); - WebRequest wRemote = default(WebRequest); - byte[] bBuffer = null; - bBuffer = new byte[257]; - int iBytesRead = 0; - int iTotalBytesRead = 0; - - fs = new FileStream(filename, FileMode.Create, FileAccess.Write); - wRemote = WebRequest.Create(URL); - WebResponse myWebResponse = wRemote.GetResponse(); - - if (FileDownloadSizeObtained != null) - { - FileDownloadSizeObtained(myWebResponse.ContentLength); - } - Stream sChunks = myWebResponse.GetResponseStream(); - - do - { - iBytesRead = sChunks.Read(bBuffer, 0, 256); - fs.Write(bBuffer, 0, iBytesRead); - iTotalBytesRead += iBytesRead; - - if (myWebResponse.ContentLength < iTotalBytesRead) - { - if (AmountDownloadedChanged != null) - { - AmountDownloadedChanged(myWebResponse.ContentLength); - } - } - else - { - if (AmountDownloadedChanged != null) - { - AmountDownloadedChanged(iTotalBytesRead); - } - } - } while (!(iBytesRead == 0)); - - sChunks.Close(); - fs.Close(); - - if (FileDownloadComplete != null) - { - FileDownloadComplete(); - } - - return true; - } - catch (Exception ex) - { - if ((fs != null)) - { - fs.Close(); - fs = null; - } - - if (FileDownloadFailed != null) - { - FileDownloadFailed(ex); - } - return false; - } - } - - - /// - /// Định dạng đơn vị dung lượng tập tin - /// - /// Kích thước tập tin dạng số - /// Chuỗi đơn vị xuất ra - /// - public static string FormatFileSize(double size, ref string donVi) - { - try - { - int KB = 1024; - long MB = KB * KB; - - // Return size of file in kilobytes. - if (size < KB) - { - donVi = " bytes"; - return size.ToString("D"); - } - else - { - double fs = size / KB; - - if (fs < 1000) - { - donVi = " KB"; - return fs.ToString("N"); - } - else if (fs < 1000000) - { - donVi = " MB"; - return (size / MB).ToString("N"); - } - else if (fs < 10000000) - { - donVi = " GB"; - return (size / MB / KB).ToString("N"); - } - } - } - catch - { - return size.ToString(); - } - - return ""; - } - - - } -} diff --git a/Source/Components/ImageGlass.Library/Properties/AssemblyInfo.cs b/Source/Components/ImageGlass.Library/Properties/AssemblyInfo.cs deleted file mode 100644 index a1536f3f8..000000000 --- a/Source/Components/ImageGlass.Library/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,35 +0,0 @@ -using System.Reflection; -using System.Runtime.InteropServices; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyTitle("ImageGlass.Library")] -[assembly: AssemblyDescription("ImageGlass library")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("Duong Dieu Phap")] -[assembly: AssemblyProduct("ImageGlass.Library")] -[assembly: AssemblyCopyright("Copyright © 2014-2020 Duong Dieu Phap")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. -[assembly: ComVisible(false)] - -// The following GUID is for the ID of the typelib if this project is exposed to COM -[assembly: Guid("46efad4a-5253-4bce-95fc-86e20966116b")] - -// Version information for an assembly consists of the following four values: -// -// Major Version -// Minor Version -// Build Number -// Revision -// -// You can specify all the values or you can default the Build and Revision Numbers -// by using the '*' as shown below: -// [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("7.5.*")] -//[assembly: AssemblyFileVersion("4.0.0.0")] diff --git a/Source/Components/ImageGlass.Library/WinAPI/FormBorder.cs b/Source/Components/ImageGlass.Library/WinAPI/FormBorder.cs deleted file mode 100644 index 2467da76c..000000000 --- a/Source/Components/ImageGlass.Library/WinAPI/FormBorder.cs +++ /dev/null @@ -1,73 +0,0 @@ -/* -ImageGlass Project - Image viewer for Windows -Copyright (C) 2019 DUONG DIEU PHAP -Project homepage: http://imageglass.org - -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 . -*/ - -using System; -using System.Runtime.InteropServices; - -namespace ImageGlass.Library.WinAPI -{ - /// - /// Adjust client border of the form - /// - public static class FormBorder - { - /// - /// Struct for box shadow - /// - private struct MARGINS - { - public int leftWidth; - public int rightWidth; - public int topHeight; - public int bottomHeight; - } - - const int DWMWA_NCRENDERING_POLICY = 2; - - - [DllImport("dwmapi.dll")] - private static extern int DwmExtendFrameIntoClientArea(IntPtr hWnd, ref MARGINS pMarInset); - - [DllImport("dwmapi.dll")] - private static extern int DwmSetWindowAttribute(IntPtr hwnd, int attr, ref int attrValue, int attrSize); - - - - /// - /// Set window border - /// - /// The pointer of the form - /// The border width - public static void Set(IntPtr handle, int borderWidth = 1) - { - var attrValue = DWMWA_NCRENDERING_POLICY; - DwmSetWindowAttribute(handle, DWMWA_NCRENDERING_POLICY, ref attrValue, 4); - - var margins = new MARGINS() - { - bottomHeight = borderWidth, - leftWidth = borderWidth, - rightWidth = borderWidth, - topHeight = borderWidth - }; - - DwmExtendFrameIntoClientArea(handle, ref margins); - } - } -} diff --git a/Source/Components/ImageGlass.Library/WinAPI/MovableForm.cs b/Source/Components/ImageGlass.Library/WinAPI/MovableForm.cs deleted file mode 100644 index 0183cdb60..000000000 --- a/Source/Components/ImageGlass.Library/WinAPI/MovableForm.cs +++ /dev/null @@ -1,176 +0,0 @@ -/* -ImageGlass Project - Image viewer for Windows -Copyright (C) 2019 DUONG DIEU PHAP -Project homepage: http://imageglass.org - -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 . -*/ - -using System; -using System.Collections.Generic; -using System.Runtime.InteropServices; -using System.Windows.Forms; - -namespace ImageGlass.Library.WinAPI -{ - /// - /// Make the frameless form movable when dragging itself or its controls - /// - public class MovableForm - { - private const int WM_NCLBUTTONDOWN = 0xA1; - private const int HT_CAPTION = 0x2; - - [DllImport("user32.dll")] - private static extern int SendMessage(IntPtr hWnd, int Msg, int wParam, int lParam); - [DllImport("user32.dll")] - private static extern bool ReleaseCapture(); - - - - private Form _form; - private bool _isKeyDown = true; - - - #region Public props - - /// - /// Manually enable / disable moving - /// - public bool IsAllowMoving { get; set; } = true; - - /// - /// Gets, sets the mouse button press for moving - /// - public MouseButtons MouseButton { get; set; } = MouseButtons.Left; - - /// - /// Gets, sets the Key press for moving - /// - public Keys Key { get; set; } = Keys.None; - - /// - /// Gets, sets the controls that do not require special Key holding to move - /// - public HashSet FreeMoveControlNames { get; set; } = new HashSet(); - - #endregion - - - - /// - /// Initialize the MovableForm - /// - /// The form to make it movable - public MovableForm(Form form) - { - _form = form; - } - - - #region Public methods - - /// - /// Enable moving ability on this form - /// - public void Enable() - { - _isKeyDown = this.Key == Keys.None; - - _form.KeyDown += this.Form_KeyDown; - _form.KeyUp += this.Form_KeyUp; - _form.MouseDown += Event_MouseDown; - } - - /// - /// Enable moving ability on the given controls - /// - /// - public void Enable(params Control[] controls) - { - _isKeyDown = this.Key == Keys.None; - - foreach (var item in controls) - { - item.MouseDown += Event_MouseDown; - } - } - - /// - /// Disable moving ability on this form - /// - public void Disable() - { - _form.KeyDown -= Form_KeyDown; - _form.KeyUp -= Form_KeyUp; - _form.MouseDown -= Event_MouseDown; - } - - - /// - /// Disable moving ability on the given controls - /// - /// - public void Disable(params Control[] controls) - { - foreach (var item in controls) - { - item.MouseDown -= Event_MouseDown; - } - } - - #endregion - - - #region Events: Frameless form moving - - private void Form_KeyDown(object sender, KeyEventArgs e) - { - if (this.Key == Keys.None) - { - _isKeyDown = true; - } - else - { - _isKeyDown = e.KeyData == this.Key; - } - } - - private void Form_KeyUp(object sender, KeyEventArgs e) - { - _isKeyDown = this.Key == Keys.None; - } - - private void Event_MouseDown(object sender, MouseEventArgs e) - { - // check if 'sender' can move without keydown event - var control = (Control) sender; - var isFreeMove = this.FreeMoveControlNames.Count > 0 - && this.FreeMoveControlNames.Contains(control.Name); - - - if (e.Clicks == 1 - && e.Button == this.MouseButton - && this.IsAllowMoving - && (_isKeyDown || isFreeMove)) - { - ReleaseCapture(); - SendMessage(_form.Handle, WM_NCLBUTTONDOWN, HT_CAPTION, 0); - } - } - #endregion - - - } -} diff --git a/Source/Components/ImageGlass.Library/WinAPI/Shortcuts.cs b/Source/Components/ImageGlass.Library/WinAPI/Shortcuts.cs deleted file mode 100644 index bc5ad5c40..000000000 --- a/Source/Components/ImageGlass.Library/WinAPI/Shortcuts.cs +++ /dev/null @@ -1,51 +0,0 @@ -/* -ImageGlass Project - Image viewer for Windows -Copyright (C) 2018 DUONG DIEU PHAP -Project homepage: http://imageglass.org - -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 . -*/ - -/********************************* - * Access the target path from a Windows Shortcut. - * Based on code from - * https://astoundingprogramming.wordpress.com/2012/12/17/how-to-get-the-target-of-a-windows-shortcut-c/ - ********************************/ - -namespace ImageGlass.Library.WinAPI -{ - public static class Shortcuts - { - /// - /// Get the target path from shortcut (*.lnk) - /// - /// Path of shortcut (*.lnk) - /// - public static string GetTargetPathFromShortcut(string shortcutPath) - { - IWshRuntimeLibrary.WshShell shell = new IWshRuntimeLibrary.WshShell(); - - try - { - IWshRuntimeLibrary.IWshShortcut shortcut = (IWshRuntimeLibrary.IWshShortcut)shell.CreateShortcut(shortcutPath); - return shortcut.TargetPath; - } - catch //(COMException) - { - // A COMException is thrown if the file is not a valid shortcut (.lnk) file - return null; - } - } - } -} diff --git a/Source/Components/ImageGlass.Library/WinAPI/TimerAPI.cs b/Source/Components/ImageGlass.Library/WinAPI/TimerAPI.cs deleted file mode 100755 index 520b3677b..000000000 --- a/Source/Components/ImageGlass.Library/WinAPI/TimerAPI.cs +++ /dev/null @@ -1,128 +0,0 @@ -/* -ImageGlass Project - Image viewer for Windows -Copyright (C) 2017 DUONG DIEU PHAP -Project homepage: http://imageglass.org - -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 . -*/ - - -/****************************************** -* THANKS [Meowski] FOR THIS CONTRIBUTION -*******************************************/ - -using System.Collections.Generic; -using System.Runtime.InteropServices; - -namespace ImageGlass.Library.WinAPI { - /// - /// Used to make requests for obtaining and setting timer resolution. - /// This is a global request shared by all processes on the computer. All - /// requests are revoked when this process ends. - /// - public static class TimerAPI { - // locks ourCurRequests - // - private static readonly object ourLock; - - [System.Runtime.InteropServices.DllImport("winmm.dll")] - private static extern int timeBeginPeriod(int msec); - - [System.Runtime.InteropServices.DllImport("winmm.dll")] - private static extern int timeEndPeriod(int msec); - - [System.Runtime.InteropServices.DllImport("winmm.dll")] - private static extern int timeGetDevCaps(ref TIMECAPS ptc, int cbtc); - - private static readonly int ourMinPeriod; - private static readonly int ourMaxPeriod; - private static readonly List ourCurRequests; - - [StructLayout(LayoutKind.Sequential)] - private struct TIMECAPS { - public int periodMin; - public int periodMax; - } - - static TimerAPI() { - ourLock = new object(); - - TIMECAPS tc = new TIMECAPS(); - timeGetDevCaps(ref tc, Marshal.SizeOf(tc)); - ourMinPeriod = tc.periodMin; - ourMaxPeriod = tc.periodMax; - ourCurRequests = new List(); - } - - /// - /// Request a rate from the system clock. - /// - /// the time in milliseconds - /// true if we succesfully acquired a clock of - /// the given rate, otherwise returns false. - public static bool TimeBeginPeriod(int timeInMilliseconds) { - if (timeInMilliseconds < ourMinPeriod || timeInMilliseconds > ourMaxPeriod) - return false; - - bool successfullyRequestedPeriod; - lock (ourLock) { - successfullyRequestedPeriod = timeBeginPeriod(timeInMilliseconds) == 0; - if (successfullyRequestedPeriod) - ourCurRequests.Add(timeInMilliseconds); - } - - return successfullyRequestedPeriod; - } - - /// - /// Revoke request for a rate from the system clock. - /// - /// the time in milliseconds - /// true if we revoked a previous request, otherwise returns false - public static bool TimeEndPeriod(int timeInMilliseconds) { - bool successfullyEndedPeriod; - lock (ourLock) { - successfullyEndedPeriod = ourCurRequests.Remove(timeInMilliseconds) && timeEndPeriod(timeInMilliseconds) == 0; - } - - return successfullyEndedPeriod; - } - - /// - /// Determines whether the current rate has already been requested. - /// - /// the time in milliseconds - public static bool HasRequestedRateAlready(int timeInMilliseconds) { - bool hasRequestedAlready; - lock (ourLock) { - hasRequestedAlready = ourCurRequests.Contains(timeInMilliseconds); - } - - return hasRequestedAlready; - } - - /// - /// Determines whether a rate at least as fast as the given has been requested - /// - /// the time in milliseconds - public static bool HasRequestedRateAtLeastAsFastAs(int timeInMilliseconds) { - bool result; - lock (ourLock) { - result = ourCurRequests.Exists(elt => elt <= timeInMilliseconds); - } - - return result; - } - } -} \ No newline at end of file diff --git a/Source/Components/ImageGlass.Library/WinAPI/Touch.cs b/Source/Components/ImageGlass.Library/WinAPI/Touch.cs deleted file mode 100644 index 70d65be1c..000000000 --- a/Source/Components/ImageGlass.Library/WinAPI/Touch.cs +++ /dev/null @@ -1,324 +0,0 @@ -/* -ImageGlass Project - Image viewer for Windows -Copyright (C) 2019 DUONG DIEU PHAP -Project homepage: http://imageglass.org - -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 . - -Author: Kevin Routley - August 2019 -*/ - -/******************************************** - * Windows functions and structures required - * to handle touch support (WM_GESTURE). - * - * Based on the Microsoft documentation and the - * Windows 7 Sample: MTGestures - ********************************************/ - -using ImageGlass.Base; -using System; -using System.Drawing; -using System.IO; -using System.Runtime.InteropServices; -using System.Windows.Forms; - -namespace ImageGlass.Library.WinAPI -{ - public static class Touch - { - public const int WM_GESTURE = 0x0119; - public const int WM_GESTURENOTIFY = 0x011A; - - public enum Action - { - None, - SwipeLeft, - SwipeRight, - RotateCCW, - RotateCW, - ZoomIn, - ZoomOut, - SwipeUp, - SwipeDown, - } - - #region P/Invoke functions - [DllImport("user32")] - [return: MarshalAs(UnmanagedType.Bool)] - private static extern bool SetGestureConfig(IntPtr hWnd, int dwReserved, int cIDs, ref GESTURECONFIG pGestureConfig, int cbSize); - - [DllImport("user32")] - [return: MarshalAs(UnmanagedType.Bool)] - private static extern bool GetGestureInfo(IntPtr hGestureInfo, ref GESTUREINFO pGestureInfo); - #endregion - - - #region Windows Structures - [StructLayout(LayoutKind.Sequential)] - private struct GESTURECONFIG - { - public int dwID; // gesture ID - public int dwWant; // settings related to gesture ID that are to be - - // turned on - public int dwBlock; // settings related to gesture ID that are to be - - #region Other - - // turned off - - #endregion Other - } - - [StructLayout(LayoutKind.Sequential)] - private struct POINTS - { - public short x; - public short y; - } - - [StructLayout(LayoutKind.Sequential)] - private struct GESTUREINFO - { - public int cbSize; // size, in bytes, of this structure - - // (including variable length Args - // field) - public int dwFlags; // see GF_* flags - public int dwID; // gesture ID, see GID_* defines - public IntPtr hwndTarget; // handle to window targeted by this - - // gesture - [MarshalAs(UnmanagedType.Struct)] - internal POINTS ptsLocation; // current location of this gesture - public int dwInstanceID; // internally used - public int dwSequenceID; // internally used - public Int64 ullArguments; // arguments for gestures whose - - // arguments fit in 8 BYTES - public int cbExtraArgs; // size, in bytes, of extra arguments, - - #region Other - - // if any, that accompany this gesture - - #endregion Other - } - #endregion - - - #region State - private static GESTURECONFIG TouchConfig = new GESTURECONFIG - { - dwID = 0, - dwWant = 1, - dwBlock=0 - }; - - private static readonly int ConfigSize = Marshal.SizeOf(new GESTURECONFIG()); - - private static GESTUREINFO gi = new GESTUREINFO() - { - cbSize = Marshal.SizeOf(new GESTUREINFO()) - }; - - private static bool _isSwipe = false; - private static Point _ptFirst = new Point(); - private static Point _ptSecond = new Point(); - - private static Form _touchForm; - private static int _iArgs; - - #endregion - - - #region Constants - private const Int64 ULL_ARGUMENTS_BIT_MASK = 0x00000000FFFFFFFF; - - // Gesture message ids - private const int GID_BEGIN = 1; - private const int GID_END = 2; - private const int GID_ZOOM = 3; - private const int GID_PAN = 4; - private const int GID_ROTATE = 5; - - // Gesture info ids - private const int GF_BEGIN = 1; - private const int GF_INERTIA = 2; - private const int GF_END = 4; - #endregion - - - /// - /// The point at which the Zoom action is taking place. - /// NOTE: valid *only* when action is zoom/pinch - /// - public static Point ZoomLocation { get; private set; } - - /// - /// The 'size' of the zoom/pinch action. Essentially, - /// the number of zoom steps to take. - /// NOTE: valid *only* when action is zoom/pinch - /// - public static int ZoomFactor { get; private set; } - - private static double ArgToRadians(long arg) - { - return ((arg / 65535.0) * 4.0 * Math.PI) - 2.0 * Math.PI; - } - - - - /// - /// Let Windows know we are accepting any and all WM_GESTURE - /// (touch) messages. - /// - /// the main form - /// false if something failed - public static bool AcceptTouch(Form form) - { - App.LogIt("WM_GESTURENOTIFY"); - _touchForm = form; - return SetGestureConfig(form.Handle, 0, 1, ref TouchConfig, ConfigSize); - } - - /// - /// Translate a WM_GESTURE (touch) message into a supported - /// action. We will get a lot of "intermediate" messages - /// which don't result in an action, the action takes place - /// on the _end_ of the touch gesture. - /// - /// the message - /// the resulting touch action - /// - public static bool DecodeTouch(Message m, out Action act) - { - act = Action.None; - - if (!GetGestureInfo(m.LParam, ref gi)) - { - return false; - } - - switch ((int)m.WParam) - { - case GID_END: - // Empirically I found this is the 'best' way to handle - // swipe end, instead of GF_END under GID_PAN. - if (_isSwipe) - { - _isSwipe = false; - _ptSecond.X = gi.ptsLocation.x; - _ptSecond.Y = gi.ptsLocation.y; - _ptSecond = _touchForm.PointToClient(_ptSecond); - - App.LogIt(string.Format("PANNING.END ({0},{1})", _ptSecond.X, _ptSecond.Y)); - - int dVert = (_ptSecond.Y - _ptFirst.Y); - int dHorz = (_ptSecond.X - _ptFirst.X); - - if (Math.Abs(dVert) > Math.Abs(dHorz)) - { - if (dVert > 0) - act = Action.SwipeDown; - else - act = Action.SwipeUp; - } - else - { - if (dHorz > 0) - act = Action.SwipeRight; - else - act = Action.SwipeLeft; - } - } - break; - case GID_ROTATE: - switch (gi.dwFlags) - { - case GF_BEGIN: - App.LogIt("GID_ROTATE.GF_BEG"); - break; - case GF_END: - double rads = ArgToRadians(gi.ullArguments & ULL_ARGUMENTS_BIT_MASK); - App.LogIt(string.Format("GID_ROTATE.GF_END ({0})", rads)); - - if (rads > 0.0) - act = Action.RotateCCW; - else - act = Action.RotateCW; - break; - } - break; - case GID_PAN: - if (gi.dwFlags == GF_BEGIN) - { - _ptFirst.X = gi.ptsLocation.x; - _ptFirst.Y = gi.ptsLocation.y; - _ptFirst = _touchForm.PointToClient(_ptFirst); - App.LogIt(string.Format("GID_PAN.GF_BEGIN ({0},{1})", _ptFirst.X, _ptFirst.Y)); - _isSwipe = true; - } - break; - case GID_ZOOM: - if (gi.dwFlags == GF_BEGIN) - { - // The zoom center and factor are derived from the first and last data points - _ptFirst.X = gi.ptsLocation.x; - _ptFirst.Y = gi.ptsLocation.y; - _ptFirst = _touchForm.PointToClient(_ptFirst); - _iArgs = (int)(gi.ullArguments & ULL_ARGUMENTS_BIT_MASK); - - App.LogIt(string.Format("GID_ZOOM.GF_BEGIN ({0},{1})", _ptFirst.X, _ptFirst.Y)); - } - if (gi.dwFlags == GF_END) - { - _ptSecond.X = gi.ptsLocation.x; - _ptSecond.Y = gi.ptsLocation.y; - _ptSecond = _touchForm.PointToClient(_ptSecond); - - // This is the center of the zoom - ZoomLocation = new Point((_ptFirst.X + _ptSecond.X)/2, - (_ptFirst.Y + _ptSecond.Y)/2); - - // This is the size of the spread/pinch. The direction - // dictates whether this is a spread or a pinch; the - // size indicates the magnitude. - var factor = (double)(gi.ullArguments & ULL_ARGUMENTS_BIT_MASK) / _iArgs; - - if (factor < 1.0) // pinch - { - act = Action.ZoomOut; - ZoomFactor = (int)(1.0 / factor); - } - else // zoom - { - act = Action.ZoomIn; - ZoomFactor = (int)factor; - } - - App.LogIt($"GID_ZOOM.GF_END ({factor}:{ZoomFactor})"); - } - break; - default: - App.LogIt("GID_?"); - break; - } - - return true; - } - - } -} diff --git a/Source/Components/ImageGlass.Services/ExplorerSortOrder.cs b/Source/Components/ImageGlass.Services/ExplorerSortOrder.cs deleted file mode 100644 index 1e6008b8a..000000000 --- a/Source/Components/ImageGlass.Services/ExplorerSortOrder.cs +++ /dev/null @@ -1,116 +0,0 @@ -/* -ImageGlass Project - Image viewer for Windows -Copyright (C) 2020 DUONG DIEU PHAP -Project homepage: https://imageglass.org - -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 . - -Author: Kevin Routley (aka fire-eggs) -*/ -using System; -using System.Collections.Generic; -using System.IO; -using System.Runtime.InteropServices; -using System.Text; -using ImageGlass.Base; - -namespace ImageGlass.Services -{ - public static class ExplorerSortOrder - { - /// - /// Convert an Explorer column name to one of our currently available sorting orders. - /// - private static readonly Dictionary SortTranslation = new Dictionary() - { - { "System.DateModified", ImageOrderBy.LastWriteTime }, - { "System.ItemDate", ImageOrderBy.LastWriteTime }, - { "System.ItemTypeText", ImageOrderBy.Extension}, - { "System.FileExtension", ImageOrderBy.Extension}, - { "System.FileName", ImageOrderBy.Name}, - { "System.ItemNameDisplay", ImageOrderBy.Name}, - { "System.Size", ImageOrderBy.Length }, - { "System.DateCreated",ImageOrderBy.CreationTime}, - { "System.DateAccessed",ImageOrderBy.LastAccessTime}, - }; - - [DllImport("ExplorerSortOrder32.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode, EntryPoint = "GetExplorerSortOrder")] - private static extern int GetExplorerSortOrder32(string folderPath, ref StringBuilder columnName, int columnNameMaxLen, ref int isAscending); - - [DllImport("ExplorerSortOrder64.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode, EntryPoint = "GetExplorerSortOrder")] - private static extern int GetExplorerSortOrder64(string folderPath, ref StringBuilder columnName, int columnNameMaxLen, ref int isAscending); - - /// - /// Determines the sorting order of a Windows Explorer window which matches - /// the given file path. - /// - /// "Failure" situations are: - /// 1. unable to find an open Explorer window matching the file path - /// 2. the Explorer sort order doesn't match one of our existing sort orders - /// - /// full path to file/folder in question - /// the resulting sort order or null - /// the resulting sort direction or null - /// false on failure - out parameters will be null! - public static bool GetExplorerSortOrder(string fullPath, out ImageOrderBy? loadOrder, out bool? isAscending) - { - // assume failure - loadOrder = null; - isAscending = null; - - try - { - var folderPath = Path.GetDirectoryName(fullPath); - - var sb = new StringBuilder(200); // arbitrary length should fit any - int explorerSortResult; - int ascend = -1; - - if (IntPtr.Size == 8) // 64 bit platform - { - explorerSortResult = GetExplorerSortOrder64(folderPath, ref sb, sb.Capacity, ref ascend); - } - else - { - explorerSortResult = GetExplorerSortOrder32(folderPath, ref sb, sb.Capacity, ref ascend); - } - - if (explorerSortResult != 0) // failure - { - return false; - } - - // Success! Attempt to translate the Explorer column to our supported - // sort order values. - var column = sb.ToString(); - if (SortTranslation.ContainsKey(column)) - { - loadOrder = SortTranslation[column]; - } - - isAscending = ascend > 0; - - return loadOrder != null; // will be false on not-yet-supported column - } -#pragma warning disable 168 - catch (Exception e) -#pragma warning restore 168 - { - return false; // failure - } - } - - - } -} diff --git a/Source/Components/ImageGlass.Services/ExplorerSortOrder32.dll b/Source/Components/ImageGlass.Services/ExplorerSortOrder32.dll deleted file mode 100644 index b7bb108c6..000000000 Binary files a/Source/Components/ImageGlass.Services/ExplorerSortOrder32.dll and /dev/null differ diff --git a/Source/Components/ImageGlass.Services/ExplorerSortOrder64.dll b/Source/Components/ImageGlass.Services/ExplorerSortOrder64.dll deleted file mode 100644 index c4ea0aade..000000000 Binary files a/Source/Components/ImageGlass.Services/ExplorerSortOrder64.dll and /dev/null differ diff --git a/Source/Components/ImageGlass.Services/ImageGlass.Services.csproj b/Source/Components/ImageGlass.Services/ImageGlass.Services.csproj deleted file mode 100644 index 643b44178..000000000 --- a/Source/Components/ImageGlass.Services/ImageGlass.Services.csproj +++ /dev/null @@ -1,125 +0,0 @@ - - - - Debug - AnyCPU - 8.0.30703 - 2.0 - {886DC568-C83E-443E-89FA-84CF420B2C68} - Library - Properties - ImageGlass.Services - ImageGlass.Services - v4.7.1 - 512 - - - - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - false - - - pdbonly - false - bin\Release\ - TRACE - prompt - 4 - false - - - true - bin\x64\Debug\ - DEBUG;TRACE - full - x64 - prompt - MinimumRecommendedRules.ruleset - false - - - bin\x64\Release\ - TRACE - true - pdbonly - x64 - prompt - MinimumRecommendedRules.ruleset - false - - - true - bin\x86\Debug\ - DEBUG;TRACE - full - x86 - 7.3 - prompt - MinimumRecommendedRules.ruleset - - - bin\x86\Release\ - TRACE - pdbonly - x86 - 7.3 - prompt - MinimumRecommendedRules.ruleset - - - - - - - - - - - - - - - - - - - - - - - {6cc96a70-6773-41b5-9fca-4f0ab6fad8ca} - ImageGlass.Base - - - {51493b09-7a0e-461f-be18-a6cf629a8fab} - ImageGlass.Heart - - - {4bb719ed-b68b-4cb1-aaaf-ba0e3bc5fe81} - ImageGlass.Library - - - - - PreserveNewest - - - PreserveNewest - - - - - - \ No newline at end of file diff --git a/Source/Components/ImageGlass.Services/InfoUpdate.cs b/Source/Components/ImageGlass.Services/InfoUpdate.cs deleted file mode 100644 index cca697f1d..000000000 --- a/Source/Components/ImageGlass.Services/InfoUpdate.cs +++ /dev/null @@ -1,98 +0,0 @@ -/* -ImageGlass Project - Image viewer for Windows -Copyright (C) 2020 DUONG DIEU PHAP -Project homepage: http://imageglass.org - -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 . -*/ - -using System; - -namespace ImageGlass.Services -{ - - - public class InfoUpdate - { - private Version _newVersion; - private string _versionType; - private string _level; - private Uri _link; - private string _size; - private DateTime _pubDate; - private string _decription; - - #region Properties - public Version NewVersion - { - get { return _newVersion; } - set { _newVersion = value; } - } - - public string VersionType - { - get { return _versionType; } - set { _versionType = value; } - } - - public string Level - { - get { return _level; } - set { _level = value; } - } - - public Uri Link - { - get { return _link; } - set { _link = value; } - } - - public string Size - { - get { return _size; } - set { _size = value; } - } - - /// - /// Get, set publish date - /// - public DateTime PublishDate - { - get { return _pubDate; } - set { _pubDate = value; } - } - - public string Decription - { - get { return _decription; } - set { _decription = value; } - } - #endregion - - /// - /// Provides information of element 'Info> in 'Update> - /// - public InfoUpdate() - { - _newVersion = new System.Version("1.0.0.0"); - _versionType = "Stable"; - _level = "Recommended"; - _link = new Uri("https://imageglass.org"); - _size = "0 MB"; - _pubDate = DateTime.Now; - _decription = string.Empty; - } - - } -} diff --git a/Source/Components/ImageGlass.Services/InstanceManagement/SingleInstance.cs b/Source/Components/ImageGlass.Services/InstanceManagement/SingleInstance.cs deleted file mode 100644 index 18b4489e0..000000000 --- a/Source/Components/ImageGlass.Services/InstanceManagement/SingleInstance.cs +++ /dev/null @@ -1,173 +0,0 @@ -/* -ImageGlass Project - Image viewer for Windows -Copyright (C) 2020 DUONG DIEU PHAP -Project homepage: http://imageglass.org - -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 . -*/ - -using System; -using System.Collections.Generic; -using System.IO; -using System.IO.Pipes; -using System.Threading; - -namespace ImageGlass.Services.InstanceManagement -{ - /// - /// Enforces single instance for an application. - /// - public class SingleInstance : IDisposable - { - private Mutex mutex = null; - private Boolean ownsMutex = false; - private Guid identifier = Guid.Empty; - - /// - /// Enforces single instance for an application. - /// - /// An identifier unique to this application. - public SingleInstance(Guid identifier) - { - this.identifier = identifier; - mutex = new Mutex(true, identifier.ToString(), out ownsMutex); - } - - /// - /// Indicates whether this is the first instance of this application. - /// - public Boolean IsFirstInstance { get { return ownsMutex; } } - - /// - /// Passes the given arguments to the first running instance of the application. - /// - /// The arguments to pass. - /// Return true if the operation succeded, false otherwise. - public Boolean PassArgumentsToFirstInstance(String[] arguments) - { - if (IsFirstInstance) - throw new InvalidOperationException("This is the first instance."); - - try - { - using (NamedPipeClientStream client = new NamedPipeClientStream(identifier.ToString())) - using (StreamWriter writer = new StreamWriter(client)) - { - client.Connect(200); - - foreach (String argument in arguments) - writer.WriteLine(argument); - } - return true; - } - catch (TimeoutException) { } //Couldn't connect to server - catch (IOException) { } //Pipe was broken - - return false; - } - - /// - /// Listens for arguments being passed from successive instances of the applicaiton. - /// - public void ListenForArgumentsFromSuccessiveInstances() - { - if (!IsFirstInstance) - throw new InvalidOperationException("This is not the first instance."); - ThreadPool.QueueUserWorkItem(new WaitCallback(ListenForArguments)); - } - - /// - /// Listens for arguments on a named pipe. - /// - /// State object required by WaitCallback delegate. - private void ListenForArguments(Object state) - { - try - { - using (NamedPipeServerStream server = new NamedPipeServerStream(identifier.ToString())) - using (StreamReader reader = new StreamReader(server)) - { - server.WaitForConnection(); - - List arguments = new List(); - while (server.IsConnected) - arguments.Add(reader.ReadLine()); - - ThreadPool.QueueUserWorkItem(new WaitCallback(CallOnArgumentsReceived), arguments.ToArray()); - } - } - catch (IOException) { } //Pipe was broken - finally - { - ListenForArguments(null); - } - } - - - /// - /// Calls the OnArgumentsReceived method casting the state Object to String[]. - /// - /// The arguments to pass. - private void CallOnArgumentsReceived(Object state) - { - OnArgumentsReceived((String[])state); - } - - - /// - /// Event raised when arguments are received from successive instances. - /// - public event EventHandler ArgumentsReceived; - - - /// - /// Fires the ArgumentsReceived event. - /// - /// The arguments to pass with the ArgumentsReceivedEventArgs. - private void OnArgumentsReceived(String[] arguments) - { - if (ArgumentsReceived != null) - ArgumentsReceived(this, new ArgumentsReceivedEventArgs() { Args = arguments }); - } - - - #region IDisposable - private Boolean disposed = false; - - protected virtual void Dispose(bool disposing) - { - if (!disposed) - { - if (mutex != null && ownsMutex) - { - mutex.ReleaseMutex(); - mutex = null; - } - disposed = true; - } - } - - ~SingleInstance() - { - Dispose(false); - } - - public void Dispose() - { - Dispose(true); - GC.SuppressFinalize(this); - } - #endregion - } -} diff --git a/Source/Components/ImageGlass.Services/Properties/AssemblyInfo.cs b/Source/Components/ImageGlass.Services/Properties/AssemblyInfo.cs deleted file mode 100644 index d6d21bdd0..000000000 --- a/Source/Components/ImageGlass.Services/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,35 +0,0 @@ -using System.Reflection; -using System.Runtime.InteropServices; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyTitle("ImageGlass.Services")] -[assembly: AssemblyDescription("ImageGlass services")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("Duong Dieu Phap")] -[assembly: AssemblyProduct("ImageGlass.Services")] -[assembly: AssemblyCopyright("Copyright © 2014-2020 by Duong Dieu Phap")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. -[assembly: ComVisible(false)] - -// The following GUID is for the ID of the typelib if this project is exposed to COM -[assembly: Guid("352c14bc-34c1-49af-9214-0c66ed79d993")] - -// Version information for an assembly consists of the following four values: -// -// Major Version -// Minor Version -// Build Number -// Revision -// -// You can specify all the values or you can default the Build and Revision Numbers -// by using the '*' as shown below: -// [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("7.5.*")] -//[assembly: AssemblyFileVersion("4.0.0.0")] diff --git a/Source/Components/ImageGlass.Services/Update.cs b/Source/Components/ImageGlass.Services/Update.cs deleted file mode 100644 index cfa3beb01..000000000 --- a/Source/Components/ImageGlass.Services/Update.cs +++ /dev/null @@ -1,192 +0,0 @@ -/* -ImageGlass Project - Image viewer for Windows -Copyright (C) 2020 DUONG DIEU PHAP -Project homepage: http://imageglass.org - -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 . -*/ - -using System; -using System.Xml; -using System.Net; -using System.IO; -using System.Diagnostics; - -namespace ImageGlass.Services -{ - public class Update - { - private InfoUpdate _info; - private bool _isError; - - #region Properties - /// - /// Get / set information of info update - /// - public InfoUpdate Info - { - get { return _info; } - set { _info = value; } - } - - /// - /// Gets value if checking for update is error - /// - public bool IsError - { - get { return _isError; } - } - #endregion - - /// - /// Provides structure, method of Update - /// - public Update(Uri link, string savedPath) - { - _info = new InfoUpdate(); - - //Get information update pack - _isError = !GetUpdateConfig(link, savedPath); - } - - /// - /// Provides structure, method of Update - /// - public Update() - { - _isError = true; - _info = new InfoUpdate(); - } - - - /// - /// Get update data from server - /// - /// - /// - /// - private bool GetUpdateConfig(Uri link, string savedPath) - { - //Get config file - try - { - if (File.Exists(savedPath)) { File.Delete(savedPath); } - - System.Net.WebClient w = new WebClient(); - w.DownloadFile(link, savedPath); - } - catch (Exception ex) { return false; } - - //return FALSE if config file is not exist - if (!File.Exists(savedPath)) { return false; } - - //Init - checking for access error - if (!LoadUpdateConfig(savedPath)) - return false; - - //error on downloading - if (_info.NewVersion.ToString() == "1.0.0.0") - { - return false; - } - - return true; - } - - /// - /// Load update data from XML file - /// - /// - /// false on load failure - public bool LoadUpdateConfig(string xmlFilename) - { - try - { - XmlDocument xmlDoc = new XmlDocument(); - // Issue #520: the xml document was locked somehow. Open it read-only to prevent lock issues - using (Stream s = File.OpenRead(xmlFilename)) - { - xmlDoc.Load(s); - } - XmlElement root = xmlDoc.DocumentElement;// - XmlElement nType = (XmlElement)root.SelectNodes("Update")[0]; // - XmlElement n = (XmlElement)nType.SelectNodes("Info")[0];// - - //Get Attributes - _info.NewVersion = new Version(n.GetAttribute("newVersion")); - _info.VersionType = n.GetAttribute("versionType"); - _info.Level = n.GetAttribute("level"); - _info.Link = new Uri(n.GetAttribute("link")); - _info.Size = n.GetAttribute("size"); - _info.PublishDate = DateTime.Parse(n.GetAttribute("pubDate")); - _info.Decription = n.GetAttribute("decription"); - return true; - } - catch (Exception ex) - { - // access error; corrupted file - return false; - } - } - - - /// - /// Load current ImageGlass.exe file and compare to the latest version. - /// Equal is TRUE, else FALSE - /// - /// - /// - public bool CheckForUpdate(string exePath) - { - FileVersionInfo fv = FileVersionInfo.GetVersionInfo(exePath); - Version currentVersion = new Version(fv.FileVersion); - - // Version = [Major.Minor.Build.Revision] - - // [6.1.12.3] > [5.1.12.3] - if (Info.NewVersion.Major > currentVersion.Major) - { - return true; - } - // [6.1.12.3] > [6.0.12.3] - else if (Info.NewVersion.Major == currentVersion.Major && - Info.NewVersion.Minor > currentVersion.Minor) - { - return true; - } - // [6.1.12.3] > [6.1.10.3] - else if (Info.NewVersion.Major == currentVersion.Major && - Info.NewVersion.Minor == currentVersion.Minor && - Info.NewVersion.Build > currentVersion.Build) - { - return true; - } - // [6.1.12.3] > [6.1.12.0] - else if (Info.NewVersion.Major == currentVersion.Major && - Info.NewVersion.Minor == currentVersion.Minor && - Info.NewVersion.Build == currentVersion.Build && - Info.NewVersion.Revision > currentVersion.Revision) - { - return true; - } - - - //default don't need to update - return false; - } - - - } - -} diff --git a/Source/Components/ImageGlass.Settings/Config.cs b/Source/Components/ImageGlass.Settings/Config.cs new file mode 100644 index 000000000..331d6a2a3 --- /dev/null +++ b/Source/Components/ImageGlass.Settings/Config.cs @@ -0,0 +1,2324 @@ +/* +ImageGlass Project - Image viewer for Windows +Copyright (C) 2010 - 2026 DUONG DIEU PHAP +Project homepage: https://imageglass.org + +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 . +*/ + +using Cysharp.Text; +using DirectN; +using ImageGlass.Base; +using ImageGlass.Base.Actions; +using ImageGlass.Base.PhotoBox; +using ImageGlass.Base.Photoing.Codecs; +using ImageGlass.Base.WinApi; +using ImageGlass.UI; +using Microsoft.Extensions.Configuration; +using Microsoft.Win32; +using System.Collections.Frozen; +using System.Diagnostics; +using System.Dynamic; +using System.Reflection; + +namespace ImageGlass.Settings; + +/// +/// Provides app configuration +/// +public static class Config +{ + + #region Internal properties + private static CancellationTokenSource _requestUpdatingColorModeCancelToken = new(); + private static bool _isDarkMode = WinColorsApi.IsDarkMode; + private static float Version = 9; + + + /// + /// The default image info tags + /// + public static List DefaultImageInfoTags => [ + nameof(ImageInfo.Name), + nameof(ImageInfo.ListCount), + nameof(ImageInfo.FrameCount), + nameof(ImageInfo.Zoom), + nameof(ImageInfo.Dimension), + nameof(ImageInfo.FileSize), + nameof(ImageInfo.ColorSpace), + nameof(ImageInfo.ExifRating), + nameof(ImageInfo.DateTimeAuto), + nameof(ImageInfo.AppName), + ]; + + + /// + /// Gets, sets current theme. + /// + public static IgTheme Theme { get; set; } = new(); + + + /// + /// Occurs when the system app color is changed and does not match the current 's dark mode. + /// + public static event RequestUpdatingColorModeHandler? RequestUpdatingColorMode; + public delegate void RequestUpdatingColorModeHandler(SystemColorModeChangedEventArgs e); + + + /// + /// Occurs when the is requested to change. + /// + public static event RequestUpdatingThemeHandler? RequestUpdatingTheme; + public delegate void RequestUpdatingThemeHandler(RequestUpdatingThemeEventArgs e); + + + /// + /// Occurs when the is requested to change. + /// + public static event RequestUpdatingLanguageHandler? RequestUpdatingLanguage; + public delegate void RequestUpdatingLanguageHandler(); + + + #endregion + + + #region Setting items + + /// + /// Gets, sets the config section of tool settings. + /// + public static ExpandoObject ToolSettings { get; set; } = new(); + + + #region Boolean items + + /// + /// Gets, sets value indicating whether the slideshow mode is enabled or not. + /// + public static bool EnableSlideshow { get; set; } = false; + + /// + /// Gets, sets value indicating whether the FrmMain should be hidden when is on. + /// + public static bool HideMainWindowInSlideshow { get; set; } = true; + + /// + /// Gets, sets value if the countdown timer is shown or not. + /// + public static bool ShowSlideshowCountdown { get; set; } = true; + + /// + /// Gets, sets value indicates whether the slide show interval is random. + /// + public static bool UseRandomIntervalForSlideshow { get; set; } = false; + + /// + /// Gets, sets value indicates that slideshow will loop back to the first image when reaching the end of list. + /// + public static bool EnableLoopSlideshow { get; set; } = true; + + /// + /// Gets, sets value indicates that slideshow is played in full screen, not window mode. + /// + public static bool EnableFullscreenSlideshow { get; set; } = true; + + /// + /// Gets, sets value of FrmMain's frameless mode. + /// + public static bool EnableFrameless { get; set; } = false; + + /// + /// Gets, sets value indicating whether the full screen mode is enabled or not. + /// + public static bool EnableFullScreen { get; set; } = false; + + /// + /// Gets, sets value indicates that the toolbar should be hidden in Full screen mode + /// + public static bool HideToolbarInFullscreen { get; set; } = false; + + /// + /// Gets, sets value indicates that the gallery should be hidden in Full screen mode + /// + public static bool HideGalleryInFullscreen { get; set; } = false; + + /// + /// Gets, sets value of gallery visibility + /// + public static bool ShowGallery { get; set; } = true; + + /// + /// Gets, sets value whether gallery scrollbars visible + /// + public static bool ShowGalleryScrollbars { get; set; } = false; + + /// + /// Gets, sets value indicates that showing image file name on gallery + /// + public static bool ShowGalleryFileName { get; set; } = true; + + /// + /// Gets, sets welcome picture value + /// + public static bool ShowWelcomeImage { get; set; } = true; + + /// + /// Gets, sets value of visibility of toolbar on start up + /// + public static bool ShowToolbar { get; set; } = true; + + /// + /// Gets, sets value of visibility of Frame Navigation tool on startup + /// + public static bool ShowFrameNavTool { get; set; } = false; + + /// + /// Gets, sets value of visibility of app icon + /// + public static bool ShowAppIcon { get; set; } = true; + + /// + /// Gets, sets value indicating that ImageGlass will loop back viewer to the first image when reaching the end of the list. + /// + public static bool EnableLoopBackNavigation { get; set; } = true; + + /// + /// Gets, sets value indicating that checker board is shown or not + /// + public static bool ShowCheckerboard { get; set; } = false; + + /// + /// Gets, sets the value indicates whether to show checkerboard in the image region only + /// + public static bool ShowCheckerboardOnlyImageRegion { get; set; } = false; + + /// + /// Gets, sets value indicating that multi instances is allowed or not + /// + public static bool EnableMultiInstances { get; set; } = true; + + /// + /// Gets, sets value indicating that FrmMain is always on top or not. + /// + public static bool EnableWindowTopMost { get; set; } = false; + + /// + /// Gets, sets value indicates that Confirmation dialog is displayed when deleting image + /// + public static bool ShowDeleteConfirmation { get; set; } = true; + + /// + /// Gets, sets value indicates that Confirmation dialog is displayed when overriding the viewing image + /// + public static bool ShowSaveOverrideConfirmation { get; set; } = true; + + /// + /// Gets, sets the setting to control whether the image's original modified date value is preserved on save + /// + public static bool ShouldPreserveModifiedDate { get; set; } = false; + + /// + /// Gets, sets value indicates that Save dialog should use the current image folder as initial directory + /// + public static bool OpenSaveAsDialogInTheCurrentImageDir { get; set; } = true; + + /// + /// Gets, sets the value indicates that there is a new version + /// + public static bool ShowNewVersionIndicator { get; set; } = false; + + /// + /// Gets, sets the value indicates that to toolbar buttons to be centered horizontally + /// + public static bool EnableCenterToolbar { get; set; } = true; + + /// + /// Gets, sets the value indicates that to show last seen image on startup + /// + public static bool ShouldOpenLastSeenImage { get; set; } = true; + + /// + /// Gets, sets the value indicates that the ColorProfile will be applied for all or only the images with embedded profile + /// + public static bool ShouldUseColorProfileForAll { get; set; } = false; + + /// + /// Gets, sets the value indicates whether to show or hide the Navigation Buttons on viewer + /// + public static bool EnableNavigationButtons { get; set; } = true; + + /// + /// Gets, sets recursive value + /// + public static bool EnableRecursiveLoading { get; set; } = false; + + /// + /// Gets, sets the value indicates that Windows File Explorer sort order is used if possible + /// + public static bool ShouldUseExplorerSortOrder { get; set; } = true; + + /// + /// Gets, sets the value indicates that images order should be grouped by directory + /// + public static bool ShouldGroupImagesByDirectory { get; set; } = false; + + /// + /// Gets, sets showing/loading hidden images + /// + public static bool ShouldLoadHiddenImages { get; set; } = false; + + /// + /// Gets, sets value specifying that Window Fit mode is on + /// + public static bool EnableWindowFit { get; set; } = false; + + /// + /// Gets, sets value indicates the window should be always center in Window Fit mode + /// + public static bool CenterWindowFit { get; set; } = true; + + /// + /// Displays the embedded thumbnail for RAW formats if found. + /// + public static bool UseEmbeddedThumbnailRawFormats { get; set; } = false; + + /// + /// Displays the embedded thumbnail for other formats if found. + /// + public static bool UseEmbeddedThumbnailOtherFormats { get; set; } = false; + + /// + /// Gets, sets value indicates that image preview is shown while the image is being loaded. + /// + public static bool ShowImagePreview { get; set; } = true; + + /// + /// Gets, sets value indicates that images should be loaded asynchronously. + /// + public static bool EnableImageAsyncLoading { get; set; } = true; + + /// + /// Enables / Disables copy multiple files. + /// + public static bool EnableCopyMultipleFiles { get; set; } = true; + + /// + /// Enables / Disables cut multiple files. + /// + public static bool EnableCutMultipleFiles { get; set; } = true; + + /// + /// Enables / Disables the file system watcher. + /// + public static bool EnableRealTimeFileUpdate { get; set; } = true; + + /// + /// Gets, sets value indicates that ImageGlass should open the new image file added in the viewing folder. + /// + public static bool ShouldAutoOpenNewAddedImage { get; set; } = false; + + /// + /// Uses Webview2 for viewing SVG format. + /// + public static bool UseWebview2ForSvg { get; set; } = true; + + /// + /// Enables, disables debug mode. + /// + public static bool EnableDebug { get; set; } = false; + + #endregion // Boolean items + + + #region Number items + + /// + /// Gets, sets the version that requires to open Quick setup ImageGlass dialog. + /// + public static float QuickSetupVersion { get; set; } = 0f; + + /// + /// Gets, sets 'Left' position of main window + /// + public static int FrmMainPositionX { get; set; } = 200; + + /// + /// Gets, sets 'Top' position of main window + /// + public static int FrmMainPositionY { get; set; } = 200; + + /// + /// Gets, sets width of main window + /// + public static int FrmMainWidth { get; set; } = 1300; + + /// + /// Gets, sets height of main window + /// + public static int FrmMainHeight { get; set; } = 800; + + /// + /// Gets, sets 'Left' position of settings window + /// + public static int FrmSettingsPositionX { get; set; } = 200; + + /// + /// Gets, sets 'Top' position of settings window + /// + public static int FrmSettingsPositionY { get; set; } = 200; + + /// + /// Gets, sets width of settings window + /// + public static int FrmSettingsWidth { get; set; } = 1300; + + /// + /// Gets, sets height of settings window + /// + public static int FrmSettingsHeight { get; set; } = 800; + + /// + /// Gets, sets the panning speed. + /// Value range is from 0 to 100. + /// + public static float PanSpeed { get; set; } = 20f; + + /// + /// Gets, sets the zooming speed. + /// Value range is from -500 to 500. + /// + public static float ZoomSpeed { get; set; } = 0; + + /// + /// Gets, sets slide show interval (minimum value if it's random) + /// + public static float SlideshowInterval { get; set; } = 5f; + + /// + /// Gets, sets the maximum slide show interval value + /// + public static float SlideshowIntervalTo { get; set; } = 5f; + + /// + /// Gets, sets the number of image changes to notify sound in slideshow mode. + /// + public static int SlideshowImagesToNotifySound { get; set; } = 0; + + /// + /// Gets, sets value of thumbnail dimension in pixel + /// + public static int ThumbnailSize { get; set; } = 50; + + /// + /// Gets, sets the maximum size in MB of thumbnail persistent cache. + /// + public static int GalleryCacheSizeInMb { get; set; } = 400; + + /// + /// Gets, sets number of thumbnail columns displayed in vertical gallery. + /// + public static int GalleryColumns { get; set; } = 3; + + /// + /// Gets, sets the minimum image dimension to use WIC decoder if the format is supported. + /// + public static int MinDimensionToUseWIC { get; set; } = 16_000; + + /// + /// Gets, sets the number of images cached by . + /// + public static int ImageBoosterCacheCount { get; set; } = 1; + + /// + /// Gets, sets the maximum image dimension when caching by . + /// If this value is less than or equals 0, the option will be ignored. + /// + public static int ImageBoosterCacheMaxDimension { get; set; } = 8_000; + + /// + /// Gets, sets the maximum image file size (in MB) when caching by . + /// If this value is less than or equals 0, the option will be ignored. + /// + public static float ImageBoosterCacheMaxFileSizeInMb { get; set; } = 100f; + + /// + /// Gets, sets fixed width on zooming + /// + public static float ZoomLockValue { get; set; } = 100f; + + /// + /// Gets, sets toolbar icon height + /// + public static uint ToolbarIconHeight { get; set; } = Const.TOOLBAR_ICON_HEIGHT; + + /// + /// Gets, sets value of image quality for editting + /// + public static uint ImageEditQuality { get; set; } = 80; + + /// + /// Gets, sets value of duration to display the in-app message + /// + public static int InAppMessageDuration { get; set; } = 2000; + + /// + /// Gets, sets the minimum width of the embedded thumbnail to use for displaying + /// image when the setting or is true. + /// + public static int EmbeddedThumbnailMinWidth { get; set; } = 0; + + /// + /// Gets, sets the minimum height of the embedded thumbnail to use for displaying + /// image when the setting or is true. + /// + public static int EmbeddedThumbnailMinHeight { get; set; } = 0; + + #endregion // Number items + + + #region String items + + /// + /// Gets, sets color profile string. It can be a defined name or ICC/ICM file path + /// + public static string ColorProfile { get; set; } = nameof(ColorProfileOption.CurrentMonitorProfile); + + /// + /// Gets, sets the last time to check for update. Set it to 0 to disable auto-update. + /// + public static string AutoUpdate { get; set; } = DateTime.UtcNow.Subtract(TimeSpan.FromDays(30)).ToISO8601String(); + + /// + /// Gets, sets the absolute file path of the last seen image + /// + public static string LastSeenImagePath { get; set; } = ""; + + /// + /// Gets, sets the last view of settings window. + /// + public static string LastOpenedSetting { get; set; } = string.Empty; + + /// + /// Gets, sets the theme name for dark mode. + /// + public static string DarkTheme { get; set; } = Const.DEFAULT_THEME; + + /// + /// Gets, sets the theme name for light mode. + /// + public static string LightTheme { get; set; } = "Kobe-Light"; + + #endregion + + + #region Array items + + /// + /// Gets, sets zoom levels of the viewer + /// + public static float[] ZoomLevels { get; set; } = []; + + /// + /// Gets, sets the list of apps for edit action. + /// + public static Dictionary EditApps { get; set; } = []; + + /// + /// Gets, sets the list of supported image formats + /// + public static HashSet FileFormats { get; set; } = []; + + /// + /// Gets, sets the list of formats that only load the first frame forcefully + /// + public static HashSet SingleFrameFormats { get; set; } = [".avif", ".heic", ".heif", ".psd", ".jxl"]; + + /// + /// Gets, sets the list of toolbar buttons + /// + public static List ToolbarButtons { get; set; } = []; + + /// + /// Gets, sets the tags for displaying image info + /// + public static List ImageInfoTags { get; set; } = DefaultImageInfoTags; + + /// + /// Gets, sets hotkeys list of menu + /// + public static Dictionary> MenuHotkeys { get; set; } = []; + + /// + /// Gets, sets mouse click actions + /// + public static Dictionary MouseClickActions { get; set; } = []; + + /// + /// Gets, sets mouse wheel actions + /// + public static Dictionary MouseWheelActions { get; set; } = []; + + /// + /// Gets, sets layout for FrmMain. Syntax: + /// Dictionary["ControlName", "DockStyle;order"] + /// + public static Dictionary Layout { get; set; } = []; + + /// + /// Gets, sets tools. + /// + public static List Tools { get; set; } = [ + new IgTool() + { + ToolId = Const.IGTOOL_EXIFTOOL, + ToolName = "ExifGlass - EXIF metadata viewer", + Executable = "exifglass", + Argument = Const.FILE_MACRO, + IsIntegrated = true, + Hotkeys = [new Hotkey(Keys.X)], + }, + ]; + + /// + /// Gets, sets the list of disabled menus + /// + public static FrozenSet DisabledMenus { get; set; } = FrozenSet.Empty; + + #endregion // Array items + + + #region Enum items + + /// + /// Gets, sets state of main window + /// + public static FormWindowState FrmMainState { get; set; } = FormWindowState.Normal; + + /// + /// Gets, sets state of settings window + /// + public static FormWindowState FrmSettingsState { get; set; } = FormWindowState.Normal; + + /// + /// Gets, sets image loading order + /// + public static ImageOrderBy ImageLoadingOrder { get; set; } = ImageOrderBy.Name; + + /// + /// Gets, sets image loading order type + /// + public static ImageOrderType ImageLoadingOrderType { get; set; } = ImageOrderType.Asc; + + /// + /// Gets, sets zoom mode value + /// + public static ZoomMode ZoomMode { get; set; } = ZoomMode.AutoZoom; + + /// + /// Gets, sets the interpolation mode to render the viewing image when the zoom factor is less than or equals 100%. + /// + public static ImageInterpolation ImageInterpolationScaleDown { get; set; } = ImageInterpolation.MultiSampleLinear; + + /// + /// Gets, sets the interpolation mode to render the viewing image when the zoom factor is greater than 100%. + /// + public static ImageInterpolation ImageInterpolationScaleUp { get; set; } = ImageInterpolation.NearestNeighbor; + + /// + /// Gets, sets value indicates what happens after clicking Edit menu + /// + public static AfterEditAppAction AfterEditingAction { get; set; } = AfterEditAppAction.Nothing; + + /// + /// Gets, sets the interpolation mode to render the viewing image when the zoom factor is greater than 100%. + /// + public static BackdropStyle WindowBackdrop { get; set; } = BackdropStyle.Mica; + + #endregion // Enum items + + + #region Other types items + + /// + /// Gets, sets background color of of the main window + /// + public static Color BackgroundColor { get; set; } = Color.Empty; + + /// + /// Gets, sets background color of slideshow + /// + public static Color SlideshowBackgroundColor { get; set; } = Color.Black; + + /// + /// Gets, sets language pack + /// + public static IgLang Language { get; set; } + + #endregion // Other types items + + #endregion // Setting items + + + + #region Public static functions + + /// + /// Loads and parsse configs from file + /// + public static void Load(IConfigurationRoot? items = null) + { +#nullable disable + items ??= Source.LoadUserConfigs(); + + // get user config version + Version = items.GetValue($"_Metadata:{nameof(Version)}"); + + + // save the config for all tools + ToolSettings = items.GetValueObj(nameof(ToolSettings)).GetValue(nameof(ToolSettings), new ExpandoObject()); + + + // Boolean values + #region Boolean items + + EnableSlideshow = items.GetValueEx(nameof(EnableSlideshow), EnableSlideshow); + HideMainWindowInSlideshow = items.GetValueEx(nameof(HideMainWindowInSlideshow), HideMainWindowInSlideshow); + ShowSlideshowCountdown = items.GetValueEx(nameof(ShowSlideshowCountdown), ShowSlideshowCountdown); + UseRandomIntervalForSlideshow = items.GetValueEx(nameof(UseRandomIntervalForSlideshow), UseRandomIntervalForSlideshow); + EnableLoopSlideshow = items.GetValueEx(nameof(EnableLoopSlideshow), EnableLoopSlideshow); + EnableFullscreenSlideshow = items.GetValueEx(nameof(EnableFullscreenSlideshow), EnableFullscreenSlideshow); + EnableFrameless = items.GetValueEx(nameof(EnableFrameless), EnableFrameless); + EnableFullScreen = items.GetValueEx(nameof(EnableFullScreen), EnableFullScreen); + ShowGallery = items.GetValueEx(nameof(ShowGallery), ShowGallery); + ShowGalleryScrollbars = items.GetValueEx(nameof(ShowGalleryScrollbars), ShowGalleryScrollbars); + ShowGalleryFileName = items.GetValueEx(nameof(ShowGalleryFileName), ShowGalleryFileName); + ShowWelcomeImage = items.GetValueEx(nameof(ShowWelcomeImage), ShowWelcomeImage); + ShowToolbar = items.GetValueEx(nameof(ShowToolbar), ShowToolbar); + ShowFrameNavTool = items.GetValueEx(nameof(ShowFrameNavTool), ShowFrameNavTool); + ShowAppIcon = items.GetValueEx(nameof(ShowAppIcon), ShowAppIcon); + EnableLoopBackNavigation = items.GetValueEx(nameof(EnableLoopBackNavigation), EnableLoopBackNavigation); + ShowCheckerboard = items.GetValueEx(nameof(ShowCheckerboard), ShowCheckerboard); + ShowCheckerboardOnlyImageRegion = items.GetValueEx(nameof(ShowCheckerboardOnlyImageRegion), ShowCheckerboardOnlyImageRegion); + EnableMultiInstances = items.GetValueEx(nameof(EnableMultiInstances), EnableMultiInstances); + EnableWindowTopMost = items.GetValueEx(nameof(EnableWindowTopMost), EnableWindowTopMost); + ShowDeleteConfirmation = items.GetValueEx(nameof(ShowDeleteConfirmation), ShowDeleteConfirmation); + ShowSaveOverrideConfirmation = items.GetValueEx(nameof(ShowSaveOverrideConfirmation), ShowSaveOverrideConfirmation); + ShouldPreserveModifiedDate = items.GetValueEx(nameof(ShouldPreserveModifiedDate), ShouldPreserveModifiedDate); + OpenSaveAsDialogInTheCurrentImageDir = items.GetValueEx(nameof(OpenSaveAsDialogInTheCurrentImageDir), OpenSaveAsDialogInTheCurrentImageDir); + ShowNewVersionIndicator = items.GetValueEx(nameof(ShowNewVersionIndicator), ShowNewVersionIndicator); + EnableCenterToolbar = items.GetValueEx(nameof(EnableCenterToolbar), EnableCenterToolbar); + ShouldOpenLastSeenImage = items.GetValueEx(nameof(ShouldOpenLastSeenImage), ShouldOpenLastSeenImage); + ShouldUseColorProfileForAll = items.GetValueEx(nameof(ShouldUseColorProfileForAll), ShouldUseColorProfileForAll); + EnableNavigationButtons = items.GetValueEx(nameof(EnableNavigationButtons), EnableNavigationButtons); + EnableRecursiveLoading = items.GetValueEx(nameof(EnableRecursiveLoading), EnableRecursiveLoading); + ShouldUseExplorerSortOrder = items.GetValueEx(nameof(ShouldUseExplorerSortOrder), ShouldUseExplorerSortOrder); + ShouldGroupImagesByDirectory = items.GetValueEx(nameof(ShouldGroupImagesByDirectory), ShouldGroupImagesByDirectory); + ShouldLoadHiddenImages = items.GetValueEx(nameof(ShouldLoadHiddenImages), ShouldLoadHiddenImages); + EnableWindowFit = items.GetValueEx(nameof(EnableWindowFit), EnableWindowFit); + CenterWindowFit = items.GetValueEx(nameof(CenterWindowFit), CenterWindowFit); + UseEmbeddedThumbnailRawFormats = items.GetValueEx(nameof(UseEmbeddedThumbnailRawFormats), UseEmbeddedThumbnailRawFormats); + UseEmbeddedThumbnailOtherFormats = items.GetValueEx(nameof(UseEmbeddedThumbnailOtherFormats), UseEmbeddedThumbnailOtherFormats); + ShowImagePreview = items.GetValueEx(nameof(ShowImagePreview), ShowImagePreview); + EnableImageAsyncLoading = items.GetValueEx(nameof(EnableImageAsyncLoading), EnableImageAsyncLoading); + EnableCopyMultipleFiles = items.GetValueEx(nameof(EnableCopyMultipleFiles), EnableCopyMultipleFiles); + EnableCutMultipleFiles = items.GetValueEx(nameof(EnableCutMultipleFiles), EnableCutMultipleFiles); + EnableRealTimeFileUpdate = items.GetValueEx(nameof(EnableRealTimeFileUpdate), EnableRealTimeFileUpdate); + ShouldAutoOpenNewAddedImage = items.GetValueEx(nameof(ShouldAutoOpenNewAddedImage), ShouldAutoOpenNewAddedImage); + UseWebview2ForSvg = items.GetValueEx(nameof(UseWebview2ForSvg), UseWebview2ForSvg); + EnableDebug = items.GetValueEx(nameof(EnableDebug), EnableDebug); + + HideToolbarInFullscreen = items.GetValueEx(nameof(HideToolbarInFullscreen), HideToolbarInFullscreen); + HideGalleryInFullscreen = items.GetValueEx(nameof(HideGalleryInFullscreen), HideGalleryInFullscreen); + + #endregion + + + // Number values + #region Number items + + QuickSetupVersion = items.GetValueEx(nameof(QuickSetupVersion), QuickSetupVersion); + + // FrmMain + FrmMainPositionX = items.GetValueEx(nameof(FrmMainPositionX), FrmMainPositionX); + FrmMainPositionY = items.GetValueEx(nameof(FrmMainPositionY), FrmMainPositionY); + FrmMainWidth = items.GetValueEx(nameof(FrmMainWidth), FrmMainWidth); + FrmMainHeight = items.GetValueEx(nameof(FrmMainHeight), FrmMainHeight); + + // FrmSettings + FrmSettingsPositionX = items.GetValueEx(nameof(FrmSettingsPositionX), FrmSettingsPositionX); + FrmSettingsPositionY = items.GetValueEx(nameof(FrmSettingsPositionY), FrmSettingsPositionY); + FrmSettingsWidth = items.GetValueEx(nameof(FrmSettingsWidth), FrmSettingsWidth); + FrmSettingsHeight = items.GetValueEx(nameof(FrmSettingsHeight), FrmSettingsHeight); + + PanSpeed = items.GetValueEx(nameof(PanSpeed), PanSpeed); + ZoomSpeed = items.GetValueEx(nameof(ZoomSpeed), ZoomSpeed); + + #region Slideshow + SlideshowInterval = items.GetValueEx(nameof(SlideshowInterval), SlideshowInterval); + if (SlideshowInterval <= 0) SlideshowInterval = 5f; + + SlideshowIntervalTo = items.GetValueEx(nameof(SlideshowIntervalTo), SlideshowIntervalTo); + SlideshowIntervalTo = Math.Max(SlideshowIntervalTo, SlideshowInterval); + + SlideshowImagesToNotifySound = items.GetValueEx(nameof(SlideshowImagesToNotifySound), SlideshowImagesToNotifySound); + #endregion + + #region Load gallery thumbnail width & position + ThumbnailSize = items.GetValueEx(nameof(ThumbnailSize), ThumbnailSize); + ThumbnailSize = Math.Max(20, ThumbnailSize); + GalleryCacheSizeInMb = items.GetValueEx(nameof(GalleryCacheSizeInMb), GalleryCacheSizeInMb); + + GalleryColumns = items.GetValueEx(nameof(GalleryColumns), GalleryColumns); + GalleryColumns = Math.Max(1, GalleryColumns); + #endregion + + MinDimensionToUseWIC = items.GetValueEx(nameof(MinDimensionToUseWIC), MinDimensionToUseWIC); + MinDimensionToUseWIC = Math.Max(0, MinDimensionToUseWIC); + + ImageBoosterCacheCount = items.GetValueEx(nameof(ImageBoosterCacheCount), ImageBoosterCacheCount); + ImageBoosterCacheCount = Math.Max(0, Math.Min(ImageBoosterCacheCount, 10)); + + ImageBoosterCacheMaxDimension = items.GetValueEx(nameof(ImageBoosterCacheMaxDimension), ImageBoosterCacheMaxDimension); + ImageBoosterCacheMaxFileSizeInMb = items.GetValueEx(nameof(ImageBoosterCacheMaxFileSizeInMb), ImageBoosterCacheMaxFileSizeInMb); + + ZoomLockValue = items.GetValueEx(nameof(ZoomLockValue), ZoomLockValue); + if (ZoomLockValue < 0) ZoomLockValue = 100f; + + ToolbarIconHeight = items.GetValueEx(nameof(ToolbarIconHeight), ToolbarIconHeight); + ImageEditQuality = items.GetValueEx(nameof(ImageEditQuality), ImageEditQuality); + InAppMessageDuration = items.GetValueEx(nameof(InAppMessageDuration), InAppMessageDuration); + EmbeddedThumbnailMinWidth = items.GetValueEx(nameof(EmbeddedThumbnailMinWidth), EmbeddedThumbnailMinWidth); + EmbeddedThumbnailMinHeight = items.GetValueEx(nameof(EmbeddedThumbnailMinHeight), EmbeddedThumbnailMinHeight); + + #endregion + + + // Enum values + #region Enum items + + FrmMainState = items.GetValueEx(nameof(FrmMainState), FrmMainState); + FrmSettingsState = items.GetValueEx(nameof(FrmSettingsState), FrmSettingsState); + ImageLoadingOrder = items.GetValueEx(nameof(ImageLoadingOrder), ImageLoadingOrder); + ImageLoadingOrderType = items.GetValueEx(nameof(ImageLoadingOrderType), ImageLoadingOrderType); + ZoomMode = items.GetValueEx(nameof(ZoomMode), ZoomMode); + ImageInterpolationScaleDown = items.GetValueEx(nameof(ImageInterpolationScaleDown), ImageInterpolationScaleDown); + ImageInterpolationScaleUp = items.GetValueEx(nameof(ImageInterpolationScaleUp), ImageInterpolationScaleUp); + AfterEditingAction = items.GetValueEx(nameof(AfterEditingAction), AfterEditingAction); + WindowBackdrop = items.GetValueEx(nameof(WindowBackdrop), WindowBackdrop); + + #endregion + + + // String values + #region String items + + ColorProfile = items.GetValueEx(nameof(ColorProfile), ColorProfile); + ColorProfile = BHelper.GetCorrectColorProfileName(ColorProfile); + + AutoUpdate = items.GetValueEx(nameof(AutoUpdate), AutoUpdate); + LastSeenImagePath = items.GetValueEx(nameof(LastSeenImagePath), LastSeenImagePath); + LastOpenedSetting = items.GetValueEx(nameof(LastOpenedSetting), LastOpenedSetting); + DarkTheme = items.GetValueEx(nameof(DarkTheme), DarkTheme); + LightTheme = items.GetValueEx(nameof(LightTheme), LightTheme); + + #endregion + + + // Array values + #region Array items + + // ZoomLevels + ZoomLevels = items.GetSection(nameof(ZoomLevels)) + .GetChildren() + .Select(i => + { + // convert % to float + try { return i.Get() / 100f; } catch { } + return -1; + }) + .OrderBy(i => i) + .Where(i => i > 0) + .Distinct() + .ToArray(); + + #region EditApps + + EditApps = items.GetSection(nameof(EditApps)) + .GetChildren() + .ToDictionary( + i => i.Key.ToLowerInvariant(), + i => i.Get() + ); + + #endregion + + #region ImageFormats + + var formats = items.GetValueEx(nameof(FileFormats), Const.IMAGE_FORMATS); + if (string.IsNullOrWhiteSpace(formats)) formats = Const.IMAGE_FORMATS; + FileFormats = GetImageFormats(formats); + + formats = items.GetValueEx(nameof(SingleFrameFormats), ZString.Join(';', SingleFrameFormats)); + SingleFrameFormats = GetImageFormats(formats); + + #endregion + + + // toolbar buttons + var toolbarItems = items.GetSection(nameof(ToolbarButtons)) + .GetChildren() + .Select(i => + { + var item = i.Get(); + var hotkeysArr = i.GetChildren() + .FirstOrDefault(i => i.Key == nameof(ToolbarItemModel.Hotkeys)) + ?.Get() ?? []; + + item.Hotkeys = hotkeysArr.Distinct() + .Where(i => !string.IsNullOrEmpty(i)) + .Select(i => new Hotkey(i)) + .ToList(); + + return item; + }) + .Where(i => i != null); + ToolbarButtons = toolbarItems.ToList(); + + + // info items + var infoTagsHasValue = items.GetValueObj(nameof(ImageInfoTags)) is not null; + if (infoTagsHasValue) + { + ImageInfoTags = items.GetSection(nameof(ImageInfoTags)) + .GetChildren() + .Select(i => i.Get()) + .ToList(); + } + + + // hotkeys for menu + var stringArrDict = items.GetSection(nameof(MenuHotkeys)) + .GetChildren() + .ToDictionary( + i => i.Key, + i => i.GetChildren().Select(i => i.Value).ToArray() + ); + MenuHotkeys = ParseHotkeys(stringArrDict); + + + // MouseClickActions + MouseClickActions = items.GetSection(nameof(MouseClickActions)) + .GetChildren() + .ToDictionary( + i => BHelper.ParseEnum(i.Key), + i => ParseToggleAction(i)); + + + // MouseWheelActions + MouseWheelActions = items.GetSection(nameof(MouseWheelActions)) + .GetChildren() + .ToDictionary( + i => BHelper.ParseEnum(i.Key), + i => BHelper.ParseEnum(i.Value)); + + // Layout + Layout = items.GetSection(nameof(Layout)) + .GetChildren() + .ToDictionary( + i => i.Key, + i => i.Get() + ); + + + // Tools + var toolList = items.GetSection(nameof(Tools)) + .GetChildren() + .Select(i => + { + var tool = i.Get(); + var hotkeysArr = i.GetChildren() + .FirstOrDefault(i => i.Key == "Hotkeys") + ?.Get() ?? []; + + tool.Hotkeys = hotkeysArr.Distinct() + .Where(i => !string.IsNullOrEmpty(i)) + .Select(i => new Hotkey(i)) + .ToList(); + + return tool; + }) + .Where(i => i != null && !i.IsEmpty); + if (toolList != null && toolList.Any()) + { + Tools.Clear(); + Tools = toolList.ToList(); + } + + + // DisabledMenus + DisabledMenus = items.GetSection(nameof(DisabledMenus)) + .GetChildren() + .Select(i => i.Get()) + .ToFrozenSet(); + + #endregion // Array items + + + // Other types values + #region Other types items + + #region Language + var langPath = items.GetValueEx(nameof(Language), "English"); + Language = new IgLang(langPath, App.StartUpDir(Dir.Language)); + #endregion + + + // must load before Theme + #region BackgroundColor + + var bgValue = items.GetValueEx(nameof(BackgroundColor), string.Empty); + + if (string.IsNullOrEmpty(bgValue)) + { + BackgroundColor = Theme.Colors.BgColor; + } + else + { + BackgroundColor = BHelper.ColorFromHex(bgValue); + } + #endregion + + + // load theme + LoadThemePack(WinColorsApi.IsDarkMode, true, true, false); + + + #region SlideshowBackgroundColor + + bgValue = items.GetValueEx(nameof(SlideshowBackgroundColor), string.Empty); + if (!string.IsNullOrWhiteSpace(bgValue)) + { + SlideshowBackgroundColor = BHelper.ColorFromHex(bgValue); + } + + #endregion + + #endregion // Other types items + + + // migrate user config file if config version is changed + MigrateUserConfigFile(); + + + Task.Run(() => + { + // initialize Magick.NET + PhotoCodec.InitMagickNET(); + + // listen to system events + SystemEvents.UserPreferenceChanged += SystemEvents_UserPreferenceChanged; + }); + +#nullable enable + } + + + /// + /// Parses and writes configs to file + /// + public static async Task WriteAsync() + { + var jsonFile = App.ConfigDir(PathType.File, Source.UserFilename); + var jsonObj = PrepareJsonSettingsObject(); + + await BHelper.WriteJsonAsync(jsonFile, jsonObj); + } + + + /// + /// Converts all settings to ExpandoObject for parsing JSON. + /// + public static ExpandoObject PrepareJsonSettingsObject(bool useAbsoluteFileUrl = false) + { + var settings = new ExpandoObject(); + + var metadata = new ConfigMetadata() + { + Description = Source.Description, + Version = Source.Version, + }; + + _ = settings.TryAdd("_Metadata", metadata); + + + #region Boolean items + + _ = settings.TryAdd(nameof(EnableSlideshow), EnableSlideshow); + _ = settings.TryAdd(nameof(HideMainWindowInSlideshow), HideMainWindowInSlideshow); + _ = settings.TryAdd(nameof(ShowSlideshowCountdown), ShowSlideshowCountdown); + _ = settings.TryAdd(nameof(UseRandomIntervalForSlideshow), UseRandomIntervalForSlideshow); + _ = settings.TryAdd(nameof(EnableLoopSlideshow), EnableLoopSlideshow); + _ = settings.TryAdd(nameof(EnableFullscreenSlideshow), EnableFullscreenSlideshow); + _ = settings.TryAdd(nameof(EnableFrameless), EnableFrameless); + _ = settings.TryAdd(nameof(EnableFullScreen), EnableFullScreen); + _ = settings.TryAdd(nameof(ShowGallery), ShowGallery); + _ = settings.TryAdd(nameof(ShowGalleryScrollbars), ShowGalleryScrollbars); + _ = settings.TryAdd(nameof(ShowGalleryFileName), ShowGalleryFileName); + _ = settings.TryAdd(nameof(ShowWelcomeImage), ShowWelcomeImage); + _ = settings.TryAdd(nameof(ShowToolbar), ShowToolbar); + _ = settings.TryAdd(nameof(ShowFrameNavTool), ShowFrameNavTool); + _ = settings.TryAdd(nameof(ShowAppIcon), ShowAppIcon); + _ = settings.TryAdd(nameof(EnableLoopBackNavigation), EnableLoopBackNavigation); + _ = settings.TryAdd(nameof(ShowCheckerboard), ShowCheckerboard); + _ = settings.TryAdd(nameof(ShowCheckerboardOnlyImageRegion), ShowCheckerboardOnlyImageRegion); + _ = settings.TryAdd(nameof(EnableMultiInstances), EnableMultiInstances); + _ = settings.TryAdd(nameof(EnableWindowTopMost), EnableWindowTopMost); + _ = settings.TryAdd(nameof(ShowDeleteConfirmation), ShowDeleteConfirmation); + _ = settings.TryAdd(nameof(ShowSaveOverrideConfirmation), ShowSaveOverrideConfirmation); + _ = settings.TryAdd(nameof(ShouldPreserveModifiedDate), ShouldPreserveModifiedDate); + _ = settings.TryAdd(nameof(OpenSaveAsDialogInTheCurrentImageDir), OpenSaveAsDialogInTheCurrentImageDir); + _ = settings.TryAdd(nameof(ShowNewVersionIndicator), ShowNewVersionIndicator); + _ = settings.TryAdd(nameof(EnableCenterToolbar), EnableCenterToolbar); + _ = settings.TryAdd(nameof(ShouldOpenLastSeenImage), ShouldOpenLastSeenImage); + _ = settings.TryAdd(nameof(ShouldUseColorProfileForAll), ShouldUseColorProfileForAll); + _ = settings.TryAdd(nameof(EnableNavigationButtons), EnableNavigationButtons); + _ = settings.TryAdd(nameof(EnableRecursiveLoading), EnableRecursiveLoading); + _ = settings.TryAdd(nameof(ShouldUseExplorerSortOrder), ShouldUseExplorerSortOrder); + _ = settings.TryAdd(nameof(ShouldGroupImagesByDirectory), ShouldGroupImagesByDirectory); + _ = settings.TryAdd(nameof(ShouldLoadHiddenImages), ShouldLoadHiddenImages); + _ = settings.TryAdd(nameof(EnableWindowFit), EnableWindowFit); + _ = settings.TryAdd(nameof(CenterWindowFit), CenterWindowFit); + _ = settings.TryAdd(nameof(UseEmbeddedThumbnailRawFormats), UseEmbeddedThumbnailRawFormats); + _ = settings.TryAdd(nameof(UseEmbeddedThumbnailOtherFormats), UseEmbeddedThumbnailOtherFormats); + _ = settings.TryAdd(nameof(ShowImagePreview), ShowImagePreview); + _ = settings.TryAdd(nameof(EnableImageAsyncLoading), EnableImageAsyncLoading); + _ = settings.TryAdd(nameof(EnableCopyMultipleFiles), EnableCopyMultipleFiles); + _ = settings.TryAdd(nameof(EnableCutMultipleFiles), EnableCutMultipleFiles); + _ = settings.TryAdd(nameof(EnableRealTimeFileUpdate), EnableRealTimeFileUpdate); + _ = settings.TryAdd(nameof(ShouldAutoOpenNewAddedImage), ShouldAutoOpenNewAddedImage); + _ = settings.TryAdd(nameof(UseWebview2ForSvg), UseWebview2ForSvg); + _ = settings.TryAdd(nameof(EnableDebug), EnableDebug); + + _ = settings.TryAdd(nameof(HideToolbarInFullscreen), HideToolbarInFullscreen); + _ = settings.TryAdd(nameof(HideGalleryInFullscreen), HideGalleryInFullscreen); + + #endregion + + + #region Number items + + _ = settings.TryAdd(nameof(QuickSetupVersion), QuickSetupVersion); + + // FrmMain + _ = settings.TryAdd(nameof(FrmMainPositionX), FrmMainPositionX); + _ = settings.TryAdd(nameof(FrmMainPositionY), FrmMainPositionY); + _ = settings.TryAdd(nameof(FrmMainWidth), FrmMainWidth); + _ = settings.TryAdd(nameof(FrmMainHeight), FrmMainHeight); + + // FrmSettings + _ = settings.TryAdd(nameof(FrmSettingsPositionX), FrmSettingsPositionX); + _ = settings.TryAdd(nameof(FrmSettingsPositionY), FrmSettingsPositionY); + _ = settings.TryAdd(nameof(FrmSettingsWidth), FrmSettingsWidth); + _ = settings.TryAdd(nameof(FrmSettingsHeight), FrmSettingsHeight); + + _ = settings.TryAdd(nameof(PanSpeed), PanSpeed); + _ = settings.TryAdd(nameof(ZoomSpeed), ZoomSpeed); + _ = settings.TryAdd(nameof(SlideshowInterval), SlideshowInterval); + _ = settings.TryAdd(nameof(SlideshowIntervalTo), SlideshowIntervalTo); + _ = settings.TryAdd(nameof(SlideshowImagesToNotifySound), SlideshowImagesToNotifySound); + _ = settings.TryAdd(nameof(ThumbnailSize), ThumbnailSize); + _ = settings.TryAdd(nameof(GalleryCacheSizeInMb), GalleryCacheSizeInMb); + _ = settings.TryAdd(nameof(GalleryColumns), GalleryColumns); + _ = settings.TryAdd(nameof(ImageBoosterCacheCount), ImageBoosterCacheCount); + _ = settings.TryAdd(nameof(MinDimensionToUseWIC), MinDimensionToUseWIC); + _ = settings.TryAdd(nameof(ImageBoosterCacheMaxDimension), ImageBoosterCacheMaxDimension); + _ = settings.TryAdd(nameof(ImageBoosterCacheMaxFileSizeInMb), ImageBoosterCacheMaxFileSizeInMb); + _ = settings.TryAdd(nameof(ZoomLockValue), ZoomLockValue); + _ = settings.TryAdd(nameof(ToolbarIconHeight), ToolbarIconHeight); + _ = settings.TryAdd(nameof(ImageEditQuality), ImageEditQuality); + _ = settings.TryAdd(nameof(InAppMessageDuration), InAppMessageDuration); + _ = settings.TryAdd(nameof(EmbeddedThumbnailMinWidth), EmbeddedThumbnailMinWidth); + _ = settings.TryAdd(nameof(EmbeddedThumbnailMinHeight), EmbeddedThumbnailMinHeight); + + #endregion + + + #region Enum items + + _ = settings.TryAdd(nameof(FrmMainState), FrmMainState.ToString()); + _ = settings.TryAdd(nameof(FrmSettingsState), FrmSettingsState.ToString()); + _ = settings.TryAdd(nameof(ImageLoadingOrder), ImageLoadingOrder.ToString()); + _ = settings.TryAdd(nameof(ImageLoadingOrderType), ImageLoadingOrderType.ToString()); + _ = settings.TryAdd(nameof(ZoomMode), ZoomMode.ToString()); + _ = settings.TryAdd(nameof(ImageInterpolationScaleDown), ImageInterpolationScaleDown); + _ = settings.TryAdd(nameof(ImageInterpolationScaleUp), ImageInterpolationScaleUp); + _ = settings.TryAdd(nameof(AfterEditingAction), AfterEditingAction.ToString()); + _ = settings.TryAdd(nameof(WindowBackdrop), WindowBackdrop); + + #endregion + + + #region String items + + _ = settings.TryAdd(nameof(ColorProfile), ColorProfile); + _ = settings.TryAdd(nameof(AutoUpdate), AutoUpdate); + _ = settings.TryAdd(nameof(LastSeenImagePath), LastSeenImagePath); + _ = settings.TryAdd(nameof(LastOpenedSetting), LastOpenedSetting); + _ = settings.TryAdd(nameof(DarkTheme), DarkTheme); + _ = settings.TryAdd(nameof(LightTheme), LightTheme); + + #endregion + + + #region Other types items + if (BackgroundColor == Theme.Colors.BgColor || BackgroundColor.IsEmpty) + { + _ = settings.TryAdd(nameof(BackgroundColor), ""); // follow theme background + } + else + { + _ = settings.TryAdd(nameof(BackgroundColor), BackgroundColor.ToHex()); + } + + _ = settings.TryAdd(nameof(SlideshowBackgroundColor), SlideshowBackgroundColor.ToHex()); + _ = settings.TryAdd(nameof(Language), Language.FileName); + + #endregion + + + #region Array items + + _ = settings.TryAdd(nameof(ZoomLevels), ZoomLevels.Select(i => Math.Round(i * 100, 2))); + _ = settings.TryAdd(nameof(EditApps), EditApps); + _ = settings.TryAdd(nameof(FileFormats), GetImageFormats(FileFormats)); + _ = settings.TryAdd(nameof(SingleFrameFormats), GetImageFormats(SingleFrameFormats)); + _ = settings.TryAdd(nameof(ImageInfoTags), ImageInfoTags); + _ = settings.TryAdd(nameof(MenuHotkeys), ParseHotkeys(MenuHotkeys)); + _ = settings.TryAdd(nameof(MouseClickActions), MouseClickActions); + _ = settings.TryAdd(nameof(MouseWheelActions), MouseWheelActions); + _ = settings.TryAdd(nameof(Layout), Layout); + _ = settings.TryAdd(nameof(Tools), Tools); + _ = settings.TryAdd(nameof(DisabledMenus), DisabledMenus); + + // ToolbarButtons + _ = settings.TryAdd(nameof(ToolbarButtons), useAbsoluteFileUrl + ? ConvertToolbarButtonsToExpandoObjList(ToolbarButtons) + : ToolbarButtons); + + #endregion + + + // Tools' settings + _ = settings.TryAdd(nameof(ToolSettings), (object)ToolSettings); + + return settings; + } + + + /// + /// Converts List{ToolbarItemModel} to List{ExpandoObject}. + /// Also adds ImageUrl property to the item. + /// + public static List ConvertToolbarButtonsToExpandoObjList(IEnumerable list) + { + var items = list.Select(btn => + { + var obj = btn.ToExpandoObject(); + + // set hotkeys + obj.Set(nameof(ToolbarItemModel.Hotkeys), btn.Hotkeys.Select(hk => hk.ToString())); + + // set image url + if (string.IsNullOrWhiteSpace(btn.Image)) return obj; + + var filePath = Theme.GetToolbarIconFilePath(btn.Image); + if (string.IsNullOrWhiteSpace(filePath)) filePath = btn.Image; + + try + { + var fileUrl = new Uri(filePath).AbsoluteUri; + if (!string.IsNullOrWhiteSpace(fileUrl)) + { + obj.TryAdd("ImageUrl", fileUrl); + return obj; + } + } + catch { } + + return obj; + }).ToList(); + + return items; + } + + + /// + /// Gets property by name. + /// + public static PropertyInfo? GetProp(string? name) + { + if (string.IsNullOrEmpty(name)) + return null; + + // Find the public property in Config + var prop = typeof(Config) + .GetProperties(BindingFlags.Public | BindingFlags.Static) + .FirstOrDefault(i => i.Name == name); + + return prop; + } + + + /// + /// Set user settings from JSON dictionary. + /// + /// JSON dictionary + /// Config name + public static (bool Done, bool Unsupported) SetFromJson(IDictionary settings, string configName) + { + var Done = false; + var Unsupported = false; + + if (!settings.ContainsKey(configName)) return (Done, Unsupported); + + var prop = Config.GetProp(configName); + if (prop == null) return (Done, Unsupported); + + var propValue = prop?.GetValue(null); + if (!settings.TryGetValue(configName, out var newValue)) return (Done, Unsupported); + newValue ??= string.Empty; + + + // BackgroundColor + if (configName == nameof(Config.BackgroundColor)) + { + BackgroundColor = BHelper.ColorFromHex(newValue); + Done = true; + } + + // SlideshowBackgroundColor + else if (configName == nameof(Config.SlideshowBackgroundColor)) + { + SlideshowBackgroundColor = BHelper.ColorFromHex(newValue); + Done = true; + } + + // Zoom levels + else if (configName == nameof(Config.ZoomLevels)) + { + try + { + var floats = BHelper.ParseJson(newValue); + if (floats != null) + { + Config.ZoomLevels = floats.Select(i => + { + // convert % to float + try { return i / 100f; } catch { } + return -1; + }) + .OrderBy(i => i) + .Where(i => i > 0) + .Distinct() + .ToArray(); + + Done = true; + } + } + catch { } + } + + // Language + else if (configName == nameof(Config.Language)) + { + Config.Language = new IgLang(newValue, App.StartUpDir(Dir.Language)); + Done = true; + } + + // MouseWheelActions + else if (configName == nameof(Config.MouseWheelActions)) + { + var dict = BHelper.ParseJson>(newValue); + if (dict != null) + { + foreach (var key in dict.Keys) + { + if (Config.MouseWheelActions.ContainsKey(key)) + { + Config.MouseWheelActions[key] = dict[key]; + } + else + { + Config.MouseWheelActions.TryAdd(key, dict[key]); + } + } + Done = true; + } + } + + // MouseClickActions + else if (configName == nameof(Config.MouseClickActions)) + { + var dict = BHelper.ParseJson>(newValue); + if (dict != null) + { + foreach (var key in dict.Keys) + { + if (Config.MouseClickActions.ContainsKey(key)) + { + Config.MouseClickActions[key] = dict[key]; + } + else + { + Config.MouseClickActions.TryAdd(key, dict[key]); + } + } + Done = true; + } + } + + // MenuHotkeys + else if (configName == nameof(Config.MenuHotkeys)) + { + var dict = BHelper.ParseJson>(newValue); + if (dict != null) + { + foreach (var key in dict.Keys) + { + // Config.MenuHotkeys[key] = + } + Done = true; + } + } + + // Tools + else if (configName == nameof(Config.Tools)) + { + var toolList = BHelper.ParseJson(newValue); + if (toolList != null) + { + Config.Tools.Clear(); + Config.Tools = [.. toolList]; + } + Done = true; + } + + // Layout + else if (configName == nameof(Config.Layout)) + { + var dict = BHelper.ParseJson>(newValue); + if (dict != null) + { + Config.Layout.Clear(); + foreach (var item in dict) + { + _ = Config.Layout.TryAdd(item.Key, item.Value); + } + + Done = true; + } + } + + // ToolbarButtons + else if (configName == nameof(Config.ToolbarButtons)) + { + var btnList = BHelper.ParseJson(newValue); + if (btnList != null) + { + Config.ToolbarButtons.Clear(); + Config.ToolbarButtons = [.. btnList]; + } + Done = true; + } + + // ImageInfoTags + else if (configName == nameof(Config.ImageInfoTags)) + { + try + { + var strArr = BHelper.ParseJson(newValue); + if (strArr != null) + { + Config.ImageInfoTags.Clear(); + Config.ImageInfoTags.AddRange(strArr); + + Done = true; + } + } + catch { } + } + + // EditApps + else if (configName == nameof(Config.EditApps)) + { + var dict = BHelper.ParseJson>(newValue); + if (dict != null) + { + Config.EditApps.Clear(); + foreach (var item in dict) + { + _ = Config.EditApps.TryAdd(item.Key, item.Value); + } + + Done = true; + } + } + + // FileFormats + else if (configName == nameof(Config.FileFormats)) + { + FileFormats = GetImageFormats(newValue); + Done = true; + } + + // bool + else if (prop.PropertyType.Equals(typeof(bool))) + { + if (bool.TryParse(newValue, out var value)) + { + prop.SetValue(null, value); + Done = true; + } + } + // int + else if (prop.PropertyType.Equals(typeof(int))) + { + if (int.TryParse(newValue, out var value)) + { + prop.SetValue(null, value); + Done = true; + } + } + // uint + else if (prop.PropertyType.Equals(typeof(uint))) + { + if (uint.TryParse(newValue, out var value)) + { + prop.SetValue(null, value); + Done = true; + } + } + // float + else if (prop.PropertyType.Equals(typeof(float))) + { + if (float.TryParse(newValue, out var value)) + { + prop.SetValue(null, value); + Done = true; + } + } + // string + else if (prop.PropertyType.Equals(typeof(string))) + { + prop.SetValue(null, newValue); + Done = true; + } + // enum + else if (prop.PropertyType.IsEnum) + { + if (Enum.TryParse(prop.PropertyType, newValue, true, out var value)) + { + prop.SetValue(null, value); + Done = true; + } + } + else + { + // unsupported type + Unsupported = true; + } + + return (Done, Unsupported); + } + + + /// + /// Loads theme pack and only theme colors. + /// + /// + /// Determine which theme should be loaded: or . + /// + /// + /// If theme pack is invalid, should load the default theme pack ? + /// + /// + /// If theme pack is invalid, should throw exception? + /// + /// Force updating background according to theme value + /// + public static void LoadThemePack(bool darkMode, bool useFallBackTheme, bool throwIfThemeInvalid, bool forceUpdateBackground) + { + var themeFolderName = darkMode ? DarkTheme : LightTheme; + if (string.IsNullOrEmpty(themeFolderName)) + { + themeFolderName = Const.DEFAULT_THEME; + } + + + // theme pack is already updated + if (themeFolderName.Equals(Theme.FolderName, StringComparison.InvariantCultureIgnoreCase)) + { + return; + } + + // load theme pack + var th = FindAndLoadThemePack(themeFolderName, useFallBackTheme, throwIfThemeInvalid); + + // update the name of dark/light theme + if (darkMode) DarkTheme = th.FolderName; + else LightTheme = th.FolderName; + + // load theme settings + th.LoadThemeSettings(); + + // load theme colors + th.LoadThemeColors(); + + + // load background color + if (Config.BackgroundColor == Theme.Colors.BgColor || forceUpdateBackground) + { + Config.BackgroundColor = th.Colors.BgColor; + } + + + // set to the current theme + Theme?.Dispose(); + Theme = th; + } + + + /// + /// Finds the correct location of theme name and loads it. + /// + /// + private static IgTheme? FindAndLoadThemePack(string themeFolderName, bool useFallBackTheme, bool throwIfThemeInvalid) + { + // look for theme pack in the Config dir + var th = new IgTheme(App.ConfigDir(PathType.Dir, Dir.Themes, themeFolderName)); + var themeConfigPath = th.ConfigFilePath; + + if (!th.IsValid) + { + // look for theme pack in the Startup dir + th.Dispose(); + th = null; + th = new(App.StartUpDir(Dir.Themes, themeFolderName)); + + // cannot find theme, use fall back theme + if (!th.IsValid && useFallBackTheme) + { + th.Dispose(); + th = null; + + // load default theme + th = new(App.StartUpDir(Dir.Themes, Const.DEFAULT_THEME)); + } + } + + + if (!th.IsValid && throwIfThemeInvalid) + { + th.Dispose(); + th = null; + + throw new InvalidDataException($"Unable to load '{themeFolderName}' theme pack. " + + $"Please make sure '{themeConfigPath}' file is valid."); + } + + return th; + } + + + /// + /// Triggers event. + /// + public static void TriggerRequestUpdatingTheme() + { + RequestUpdatingTheme?.Invoke(new RequestUpdatingThemeEventArgs(Config.Theme)); + } + + + /// + /// Triggers event. + /// + public static void TriggerRequestUpdatingLanguage() + { + RequestUpdatingLanguage?.Invoke(); + } + + + /// + /// Updates form icon using theme setting. + /// + public static async Task UpdateFormIcon(Form? frm) + { + if (frm is null) return; + + // Icon theming + if (Config.Theme.Settings.AppLogo?.GetHicon() is not IntPtr hIcon) return; + frm.Icon = Icon.FromHandle(hIcon); + + await Task.Delay(200); + frm.ShowIcon = Config.ShowAppIcon; + } + + + /// + /// Parses string dictionary to hotkey dictionary + /// + public static Dictionary> ParseHotkeys(Dictionary? dict) + { + var result = new Dictionary>(); + if (dict == null) return result; + + foreach (var item in dict) + { + var keyList = new List(); + + // sample item: { "MnuOpen": ["O", "Ctrl+O"] } + foreach (var strKey in item.Value) + { + try + { + keyList.Add(new Hotkey(strKey)); + } + catch { } + } + + + if (result.TryGetValue(item.Key, out List? value)) + { + value.Clear(); + value.AddRange(keyList); + } + else + { + result.Add(item.Key, keyList); + } + } + + return result; + } + + + /// + /// Parses hotkey dictionary to string dictionary. + /// + public static Dictionary ParseHotkeys(Dictionary> dict) + { + var result = dict.Select(i => new + { + i.Key, + Value = i.Value.Select(k => k.ToString()), + }).ToDictionary(i => i.Key, i => i.Value.ToArray()); + + return result; + } + + + /// + /// Gets all hotkeys by merging + /// and into . + /// + public static Dictionary> GetAllHotkeys(Dictionary> defaultDict) + { + var result = defaultDict; + + // merge menu hotkeys + foreach (var item in Config.MenuHotkeys) + { + if (result.ContainsKey(item.Key)) + { + result[item.Key] = item.Value; + } + else + { + result.Add(item.Key, item.Value); + } + } + + + // merge tool hotkeys + var toolHotkeys = Config.Tools + .ToDictionary(i => i.ToolId, i => i.Hotkeys); + foreach (var item in toolHotkeys) + { + if (result.ContainsKey(item.Key)) + { + result[item.Key] = item.Value; + } + else + { + result.Add(item.Key, item.Value); + } + } + + + // merge toolbar hotkeys + var toolbarHotkeys = Config.ToolbarButtons + .Where(i => i.Type == ToolbarItemModelType.Button && i.Hotkeys.Count > 0) + .ToDictionary(i => i.Id, i => i.Hotkeys); + + foreach (var item in toolbarHotkeys) + { + if (result.ContainsKey(item.Key)) + { + result[item.Key] = item.Value; + } + else + { + result.Add(item.Key, item.Value); + } + } + + + return result; + } + + + /// + /// Gets hotkeys string from the action. + /// + public static string GetHotkeyString(Dictionary> dict, string action) + { + dict.TryGetValue(action, out var hotkeyList); + + if (hotkeyList != null) + { + var str = ZString.Join(", ", hotkeyList); + + return str ?? string.Empty; + } + + + return string.Empty; + } + + + /// + /// Gets hotkeys from the action. + /// + public static List GetHotkey(Dictionary> dict, string action) + { + dict.TryGetValue(action, out var hotkeyList); + + return hotkeyList ?? []; + } + + + /// + /// Gets hotkey's KeyData. + /// + public static List GetHotkeyData(Dictionary> dict, string action, Keys defaultValue) + { + var keyDataList = GetHotkey(dict, action) + .Select(k => k.KeyData).ToList(); + + return keyDataList ?? [defaultValue]; + } + + + /// + /// Gets actions from the input hotkey. + /// + public static List GetHotkeyActions(Dictionary> dict, Hotkey hotkey) + { + var actions = new HashSet(); + + foreach (var item in dict) + { + foreach (var key in item.Value) + { + var result = string.Compare(key.ToString(), hotkey.ToString(), StringComparison.OrdinalIgnoreCase); + if (result == 0) + { + actions.Add(item.Key); + } + } + } + + return [.. actions]; + } + + + /// + /// Loads language list. It auto-adds the first item as the default language pack. + /// + public static List LoadLanguageList() + { + var list = new List() { new IgLang(), }; + var langDir = App.StartUpDir(Dir.Language); + + if (!Directory.Exists(langDir)) return list; + + var files = Directory.EnumerateFiles(langDir, "*.iglang.json") + .Select(path => new IgLang(path)); + list.AddRange(files); + + return list; + } + + + /// + /// Loads all theme packs from default folder and user folder. + /// + public static List LoadThemeList() + { + var defaultThemeFolder = App.StartUpDir(Dir.Themes); + var userThemeFolder = App.ConfigDir(PathType.Dir, Dir.Themes); + + // Create theme folder if not exist + Directory.CreateDirectory(userThemeFolder); + + var userThemeNames = Directory.EnumerateDirectories(userThemeFolder); + var defaultThemeNames = Directory.EnumerateDirectories(defaultThemeFolder); + + // merge and distinct all themes + var allThemeNames = defaultThemeNames.ToList(); + allThemeNames.AddRange(userThemeNames); + allThemeNames = allThemeNames.Distinct().ToList(); + + var allThemes = new List(allThemeNames.Count); + + Parallel.ForEach(allThemeNames, dir => + { + var configFile = Path.Combine(dir, IgTheme.CONFIG_FILE); + var th = new IgTheme(themeFolderPath: dir); + + // valid theme + if (th.IsValid) + { + allThemes.Add(th); + } + }); + + + // get default theme dir + var defaultThemePath = App.StartUpDir(Dir.Themes, Const.DEFAULT_THEME, IgTheme.CONFIG_FILE); + + allThemes = [.. allThemes.OrderBy(i => i.ConfigFilePath != defaultThemePath)]; + + return allThemes; + } + + + /// + /// Builds the command line from config value. + /// Example: /EnableFullScreen=True + /// + public static string BuildConfigCmdLine(string configName, object? configValue) + { + if (configValue == null) return string.Empty; + + return $"{Const.CONFIG_CMD_PREFIX}{configName}=\"{configValue}\""; + } + + + /// + /// Sets default photo viewer. + /// + public static async Task SetDefaultPhotoViewerAsync(bool enable) + { + var extensions = Config.GetImageFormats(Config.FileFormats); + + var cmd = enable + ? IgCommands.SET_DEFAULT_PHOTO_VIEWER + : IgCommands.REMOVE_DEFAULT_PHOTO_VIEWER; + + // run command and show the results + _ = await Config.RunIgcmd($"{cmd} {extensions} {IgCommands.SHOW_UI}"); + } + + + /// + /// Gets from the given extension. + /// + /// An extension. E.g. .jpg + public static EditApp? GetEditAppFromExtension(string ext) + { + var appItem = Config.EditApps.FirstOrDefault(i => + { + var exts = i.Key.Split(";", StringSplitOptions.TrimEntries | StringSplitOptions.RemoveEmptyEntries); + return exts.Contains(ext); + }); + + return appItem.Value; + } + + + /// + /// Runs a command from igcmd.exe, supports auto-elevating process privilege + /// if admin permission is required. + /// + public static async Task RunIgcmd(string args, bool waitForExit = true) + { + var exePath = App.StartUpDir("igcmd.exe"); + + // create command-lines for the current settings + var lightThemeCmd = Config.BuildConfigCmdLine(nameof(Config.LightTheme), Config.LightTheme); + var darkThemeCmd = Config.BuildConfigCmdLine(nameof(Config.DarkTheme), Config.DarkTheme); + var langCmd = Config.BuildConfigCmdLine(nameof(Config.Language), Config.Language.FileName); + + var allArgs = $"{args} {lightThemeCmd} {darkThemeCmd} {langCmd}"; + + return await BHelper.RunExeCmd(exePath, allArgs, waitForExit, true); + } + + + // Popup functions + #region Popup functions + + /// + /// Shows information popup widow. + /// + /// Popup title. + /// Popup heading text. + /// Popup description. + /// Other details + /// Note text. + /// Popup buttons. + public static PopupResult ShowInfo( + Form? formOwner, + string description = "", + string title = "", + string heading = "", + string details = "", + string note = "", + StockIconId? icon = StockIconId.Info, + Image? thumbnail = null, + PopupButton buttons = PopupButton.OK, + string optionText = "") + { + return Popup.ShowDialog(description, title, heading, details, note, ColorStatusType.Info, buttons, icon, thumbnail, optionText, Config.EnableWindowTopMost, formOwner); + } + + + /// + /// Shows warning popup widow. + /// + /// Popup title. + /// Popup heading text. + /// Popup description. + /// Other details + /// Note text. + /// Popup buttons. + public static PopupResult ShowWarning( + Form? formOwner, + string description = "", + string title = "", + string? heading = null, + string details = "", + string note = "", + StockIconId? icon = StockIconId.Warning, + Image? thumbnail = null, + PopupButton buttons = PopupButton.OK, + string optionText = "") + { + heading ??= Language["_._Warning"]; + + return Popup.ShowDialog(description, title, heading, details, note, ColorStatusType.Warning, buttons, icon, thumbnail, optionText, Config.EnableWindowTopMost, formOwner); + } + + + /// + /// Shows error popup widow. + /// + /// Popup title. + /// Popup heading text. + /// Popup description. + /// Other details + /// Note text. + /// Popup buttons. + public static PopupResult ShowError( + Form? formOwner, + string description = "", + string title = "", + string? heading = null, + string details = "", + string note = "", + StockIconId? icon = StockIconId.Error, + Image? thumbnail = null, + PopupButton buttons = PopupButton.OK, + string optionText = "") + { + heading ??= Language["_._Error"]; + + return Popup.ShowDialog(description, title, heading, details, note, ColorStatusType.Danger, buttons, icon, thumbnail, optionText, Config.EnableWindowTopMost, formOwner); + } + + + /// + /// Show the default error popup for igcmd.exe + /// + /// + public static int ShowDefaultIgCommandError(string igcmdExeName) + { + var url = "https://imageglass.org/docs/command-line-utilities"; + var langPath = $"_._IgCommandExe._DefaultError"; + + var result = ShowError(null, + title: Application.ProductName + " v" + Application.ProductVersion, + heading: Language[$"{langPath}._Heading"], + description: ZString.Format(Language[$"{langPath}._Description"], url), + buttons: PopupButton.LearnMore_Close); + + + if (result.ExitResult == PopupExitResult.OK) + { + _ = BHelper.OpenUrlAsync(url, $"from_{igcmdExeName}_invalid_command"); + } + + return (int)IgExitCode.Error; + } + + + /// + /// Shows unhandled exception popup + /// + public static void HandleException(Exception ex) + { + var osInfo = Environment.OSVersion.VersionString + " " + (Environment.Is64BitOperatingSystem ? "64-bit" : "32-bit"); + var exeVersion = FileVersionInfo.GetVersionInfo(Application.ExecutablePath).FileVersion; + var appInfo = Application.ProductName + " v" + exeVersion; + if (BHelper.IsRunningAsUwp()) appInfo += " (Store)"; + + var langPath = $"_._UnhandledException"; + var description = Language[$"{langPath}._Description"]; + var details = + $"Version: {appInfo}\r\n" + + $"Release code: {Const.APP_CODE}\r\n" + + $"Magick.NET: {ImageMagick.MagickNET.Version}\r\n" + + $"WebView2 Runtime: {Web2.Webview2Version?.ToString()}\r\n" + + $"OS: {osInfo}\r\n\r\n" + + + $"----------------------------------------------------\r\n" + + $"Error:\r\n\r\n" + + $"{ex.Message}\r\n" + + $"----------------------------------------------------\r\n\r\n" + + + ex.ToString(); + + var result = ShowError(null, + title: Application.ProductName + " - " + Language[langPath], + heading: ex.Message, + description: description, + details: details, + buttons: PopupButton.Continue_Quit); + + if (result.ExitResult == PopupExitResult.Cancel) + { + Application.Exit(); + } + } + + + #endregion // Popup functions + + + #endregion // Public static functions + + + + + #region Private functions + + // Config file migration + #region Config file migration + + /// + /// Migrate user config file + /// + private static void MigrateUserConfigFile() + { + // no change + if (Source.Version <= Version) return; + + + // migrate from 9.0 + if (Version == 9) + { + // MouseClickActions + if (MouseClickActions.TryGetValue(MouseClickEvent.WheelClick, out var action1) + && action1?.ToggleOn?.Executable == "IG_Refresh") + { + MouseClickActions[MouseClickEvent.WheelClick] = new(new("MnuRefresh")); + } + if (MouseClickActions.TryGetValue(MouseClickEvent.XButton1Click, out var action2) + && action2?.ToggleOn?.Executable == "IG_ViewPreviousImage") + { + MouseClickActions[MouseClickEvent.XButton1Click] = new(new("MnuViewPrevious")); + } + if (MouseClickActions.TryGetValue(MouseClickEvent.XButton2Click, out var action3) + && action3?.ToggleOn?.Executable == "IG_ViewNextImage") + { + MouseClickActions[MouseClickEvent.XButton2Click] = new(new("MnuViewNext")); + } + } + + + // migrate from < 9.3 + if (Version < 9.3) + { + FileFormats.AddRange([".jxr", ".hdp", ".wdp"]); + } + + // migrate from < 9.4 + if (Version < 9.4) + { + FileFormats.Add(".hif"); + } + } + + #endregion // Config file migration + + + // ToggleAction, SingleAction Parser + #region ToggleAction, SingleAction Parser + + private static ToggleAction? ParseToggleAction(IConfigurationSection sec) + { + if (!sec.Exists()) return null; + + var toggleOn = ParseSingleAction(sec.GetSection(nameof(ToggleAction.ToggleOn))); + var toggleOff = ParseSingleAction(sec.GetSection(nameof(ToggleAction.ToggleOff))); + + return new ToggleAction(toggleOn) + { + ToggleOff = toggleOff, + }; + } + + + private static SingleAction? ParseSingleAction(IConfigurationSection sec) + { + if (!sec.Exists()) return null; + + var exe = sec.GetValueEx(nameof(SingleAction.Executable), ""); + var args = Array.Empty(); + SingleAction? nextAc = null; + + // get Arguments + var argsSec = sec.GetSection(nameof(SingleAction.Arguments)); + if (argsSec.Exists()) + { + args = argsSec.Get().ToArray(); + } + + // get NextAction + var nextSec = sec.GetSection(nameof(SingleAction.NextAction)); + if (nextSec.Exists()) + { + nextAc = ParseSingleAction(nextSec); + } + + return new SingleAction(exe, args, nextAc); + } + + #endregion // ToggleAction, SingleAction Parser + + + // ImageFormats + #region ImageFormats + + /// + /// Returns distinc list of image formats. + /// + /// The format string. E.g: .bpm;.jpg; + public static HashSet GetImageFormats(string formats) + { + var formatList = formats + .Split(';', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries) + .ToHashSet(); + + return formatList; + } + + /// + /// Returns the image formats string. Example: .png;.jpg; + /// + /// The input HashSet + public static string GetImageFormats(HashSet list) + { + using var sb = ZString.CreateStringBuilder(); + foreach (var item in list) + { + sb.Append(item); + sb.Append(';'); + } + + return sb.ToString(); + } + + #endregion // ImageFormats + + + // System events + #region System events + + private static void SystemEvents_UserPreferenceChanged(object sender, UserPreferenceChangedEventArgs e) + { + // User settings changed: + // - Color mode: dark / light + // - Transparency + // - Accent color + // - others... + if (e.Category == UserPreferenceCategory.General) + { + DelayTriggerRequestUpdatingColorModeEvent(); + } + } + + + /// + /// Delays triggering event. + /// + private static void DelayTriggerRequestUpdatingColorModeEvent() + { + _requestUpdatingColorModeCancelToken.Cancel(); + _requestUpdatingColorModeCancelToken = new(); + + _ = TriggerRequestUpdatingColorModeEventAsync(_requestUpdatingColorModeCancelToken.Token); + } + + + /// + /// Triggers event. + /// + private static async Task TriggerRequestUpdatingColorModeEventAsync(CancellationToken token = default) + { + try + { + // since the message is triggered multiple times (3 - 5 times) + await Task.Delay(10, token); + token.ThrowIfCancellationRequested(); + + + var isDarkMode = WinColorsApi.IsDarkMode; + if (_isDarkMode != isDarkMode) + { + _isDarkMode = isDarkMode; + + // emit event here + RequestUpdatingColorMode?.Invoke(new SystemColorModeChangedEventArgs(_isDarkMode)); + } + } + catch (OperationCanceledException) { } + } + #endregion // System events + + #endregion // Private functions + + +} diff --git a/Source/Components/ImageGlass.Settings/ConfigSource.cs b/Source/Components/ImageGlass.Settings/ConfigSource.cs deleted file mode 100644 index c6091cc51..000000000 --- a/Source/Components/ImageGlass.Settings/ConfigSource.cs +++ /dev/null @@ -1,263 +0,0 @@ -/* -ImageGlass Project - Image viewer for Windows -Copyright (C) 2020 DUONG DIEU PHAP -Project homepage: http://imageglass.org - -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 . -*/ - -using ImageGlass.Base; -using System; -using System.Collections.Generic; -using System.Xml; - -namespace ImageGlass.Settings -{ - /// - /// A unified list of default/user/admin settings, provides read/write the settings to source file. - /// - [Serializable] - public class ConfigSource : Dictionary - { - - #region Public properties - - /// - /// User config file - /// - public string Filename { get => App.ConfigDir("igconfig.xml"); } - - - /// - /// The default config file located in StartUpDir, the default configs if it does not exist in user's configs - /// - public string DefaultConfigFilename { get => App.StartUpDir("igconfig.default.xml"); } - - - /// - /// The admin config file located in StartUpDir. All configs here will override user's configs and default configs - /// - public string AdminConfigFilename { get => App.StartUpDir("igconfig.admin.xml"); } - - - /// - /// Gets the admin configs - /// - public Dictionary AdminConfigs { get; private set; } = new Dictionary(); - - - /// - /// Config file description - /// - public string Description { get; set; } = "ImageGlass Configuration file"; - - - /// - /// Config file version - /// - public string Version { get; set; } = "7.5"; - - - /// - /// Gets, sets value indicates that the config file is compatible with this ImageGlass version or not - /// - public bool IsCompatible { get; set; } = true; - - #endregion - - - #region Private methods - /// - /// Reads XML file and returns the Document object - /// - /// - private XmlDocument ReadXMLFile(string filename) - { - var doc = new XmlDocument(); - - try - { - doc.Load(filename); - } - catch (Exception) - { - return null; - } - - return doc; - } - - - /// - /// Loads the given filename, returns all configs - /// - /// - private Dictionary LoadConfigFile(string filename, bool isUserConfigFile = false) - { - var list = new Dictionary(); - var doc = ReadXMLFile(filename); - - // config file is invalid - if (doc == null) - { - this.IsCompatible = !isUserConfigFile; - return list; - } - - XmlElement root = doc.DocumentElement;// - XmlElement nType = (XmlElement)root.SelectNodes("Configuration")[0]; // - - if (isUserConfigFile) - { - // Get element - XmlElement nInfo = (XmlElement)nType.SelectNodes("Info")[0];// - var version = nInfo.GetAttribute("version"); - this.IsCompatible = version == this.Version; - this.Version = this.IsCompatible ? version : this.Version; - } - - - // Get element - XmlElement nContent = (XmlElement)nType.SelectNodes("Content")[0];// - - // Get all config items - XmlNodeList nItems = nContent.SelectNodes("Item");// - - foreach (var item in nItems) - { - var nItem = (XmlElement)item; - string key = nItem.GetAttribute("key"); - string value = nItem.GetAttribute("value").Replace("\\n", "\n"); - - if (list.ContainsKey(key)) - { - // override the existing key - list[key] = value; - } - else - { - list.Add(key, value); - } - } - - return list; - } - - - /// - /// Write configs to the given filename - /// - /// - private void WriteConfigFile(Dictionary configs, string filename) - { - var doc = new XmlDocument(); - XmlElement root = doc.CreateElement("ImageGlass"); // - XmlElement nConfig = doc.CreateElement("Configuration"); // - - - XmlElement nInfo = doc.CreateElement("Info"); // - nInfo.SetAttribute("description", this.Description); - nInfo.SetAttribute("version", this.Version); - nConfig.AppendChild(nInfo); // - - - // Write config items - XmlElement nContent = doc.CreateElement("Content"); // - - foreach (var item in configs) - { - XmlElement nItem = doc.CreateElement("Item"); // - nItem.SetAttribute("key", item.Key); - nItem.SetAttribute("value", item.Value); - nContent.AppendChild(nItem); // - } - - nConfig.AppendChild(nContent); // - root.AppendChild(nConfig); // - doc.AppendChild(root); // - - try - { - doc.Save(filename); - } - catch { } - } - - - #endregion - - - #region Public methods - - public ConfigSource() { } - - - /// - /// Throws NotImplementedException exception. It's not used! - /// - /// - /// - protected ConfigSource(System.Runtime.Serialization.SerializationInfo serializationInfo, System.Runtime.Serialization.StreamingContext streamingContext) - { - throw new NotImplementedException(); - } - - - /// - /// Loads all config files: user, default, admin, then unify configs for user - /// - public void LoadUserConfigs() - { - var userConfigs = LoadConfigFile(this.Filename, true); - var defaultConfigs = LoadConfigFile(this.DefaultConfigFilename); - this.AdminConfigs = LoadConfigFile(this.AdminConfigFilename); - - // take default config items if they don not exist in user configs - foreach (var item in defaultConfigs) - { - if (!userConfigs.ContainsKey(item.Key)) - { - userConfigs[item.Key] = item.Value; - } - } - - // override user configs by admin configs - foreach (var item in this.AdminConfigs) - { - userConfigs[item.Key] = item.Value; - } - - - // set user configs to the dictionary - this.Clear(); - foreach (var item in userConfigs) - { - this.Add(item.Key, item.Value); - } - } - - - /// - /// Write user configs to file - /// - public void WriteUserConfigs() - { - WriteConfigFile(this, this.Filename); - } - - - #endregion - - } -} diff --git a/Source/Components/ImageGlass.Settings/Configs.cs b/Source/Components/ImageGlass.Settings/Configs.cs deleted file mode 100644 index d8b9cac3d..000000000 --- a/Source/Components/ImageGlass.Settings/Configs.cs +++ /dev/null @@ -1,1170 +0,0 @@ -/* -ImageGlass Project - Image viewer for Windows -Copyright (C) 2020 DUONG DIEU PHAP -Project homepage: http://imageglass.org - -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 . -*/ - -using ImageGlass.Base; -using ImageGlass.Library; -using ImageGlass.Library.FileAssociations; -using ImageGlass.UI; -using Microsoft.Win32; -using System; -using System.Collections.Generic; -using System.Drawing; -using System.IO; -using System.Linq; -using System.Text; -using System.Windows.Forms; - -namespace ImageGlass.Settings -{ - /// - /// Provide all the settings of the app - /// - public static class Configs - { - /// - /// Configuration Source file - /// - private static ConfigSource Source { get; set; } = new ConfigSource(); - - - /// - /// Check if the config file is compatible with this ImageGlass version or not. - /// - public static bool IsCompatible { get => Source.IsCompatible; } - - - - #region Public configs - - #region Boolean items - /// - /// Gets, sets value of slideshow state - /// - public static bool IsSlideshow { get; set; } = false; - - - /// - /// Gets, sets value if the countdown timer is shown or not - /// - public static bool IsShowSlideshowCountdown { get; set; } = true; - - - /// - /// Gets, sets value indicating that wheather the window is full screen or not - /// - public static bool IsFullScreen { get; set; } = false; - - - /// - /// Gets, sets value of thumbnail visibility - /// - public static bool IsShowThumbnail { get; set; } = false; - - - /// - /// Gets, sets the value that indicates if the default position of image in the viewer is center or top left - /// - public static bool IsCenterImage { get; set; } = true; - - - /// - /// Check if user wants to display RGBA color code for Color Picker tool - /// - public static bool IsColorPickerRGBA { get; set; } = true; - - - /// - /// Check if user wants to display HEX with Alpha color code for Color Picker tool - /// - public static bool IsColorPickerHEXA { get; set; } = true; - - - /// - /// Check if user wants to display HSL with Alpha color code for Color Picker tool - /// - public static bool IsColorPickerHSLA { get; set; } = true; - - - /// - /// Gets, sets welcome picture value - /// - public static bool IsShowWelcome { get; set; } = true; - - - /// - /// Gets, sets value of visibility of toolbar when start up - /// - public static bool IsShowToolBar { get; set; } = true; - - - /// - /// Gets, sets value whether thumbnail scrollbars visible - /// - public static bool IsShowThumbnailScrollbar { get; set; } = false; - - - /// - /// Gets, sets value that allows user to loop back to the first image when reaching the end of list - /// - public static bool IsLoopBackSlideshow { get; set; } = true; - - - /// - /// Gets, sets value indicating that ImageGlass will loop back viewer to the first image when reaching the end of the list. - /// - public static bool IsLoopBackViewer { get; set; } = true; - - - /// - /// Gets, sets value indicating that allow quit application by ESC - /// - public static bool IsPressESCToQuit { get; set; } = true; - - - /// - /// Gets, sets value indicating that checker board is shown or not - /// - public static bool IsShowCheckerBoard { get; set; } = false; - - - /// - /// Gets, sets value indicating that multi instances is allowed or not - /// - public static bool IsAllowMultiInstances { get; set; } = true; - - - /// - /// Gets, sets value indicating that frmMain is always on top or not. - /// - public static bool IsWindowAlwaysOnTop { get; set; } = false; - - - /// - /// Gets, sets value of frmMain's frameless mode. - /// - public static bool IsWindowFrameless { get; set; } = false; - - - /// - /// Gets, sets the direction of thumbnail bar - /// - public static bool IsThumbnailHorizontal { get; set; } = true; - - - /// - /// Gets, sets value indicating that Confirmation dialog is displayed when deleting image - /// - public static bool IsConfirmationDelete { get; set; } = false; - - - /// - /// Gets, sets the value indicates that viewer scrollbars are visible - /// - public static bool IsScrollbarsVisible { get; set; } = false; - - - /// - /// Gets, sets the value indicates that the viewing image is auto-saved after rotating - /// - public static bool IsSaveAfterRotating { get; set; } = false; - - - /// - /// Gets, sets the setting to control whether the image's original modified date value is preserved on save - /// - public static bool IsPreserveModifiedDate { get; set; } = true; - - - /// - /// Gets, sets the value indicates that there is a new version - /// - public static bool IsNewVersionAvailable { get; set; } = false; - - - /// - /// Gets, sets the value indicates that to show full image path or only base name - /// - public static bool IsDisplayBasenameOfImage { get; set; } = false; - - - /// - /// Gets, sets the value indicates that to toolbar buttons to be centered horizontally - /// - public static bool IsCenterToolbar { get; set; } = true; - - - /// - /// Gets, sets the value indicates that to show last seen image on startup - /// - public static bool IsOpenLastSeenImage { get; set; } = false; - - - /// - /// Gets, sets the value indicates that the ColorProfile will be applied for all or only the images with embedded profile - /// - public static bool IsApplyColorProfileForAll { get; set; } = false; - - - /// - /// Gets, sets the value indicates that to show or hide the Navigation Buttons on viewer - /// - public static bool IsShowNavigationButtons { get; set; } = false; - - - /// - /// Gets, sets the value indicates that to checkerboard in the image region only - /// - public static bool IsShowCheckerboardOnlyImageRegion { get; set; } = false; - - - /// - /// Gets, sets recursive value - /// - public static bool IsRecursiveLoading { get; set; } = false; - - - /// - /// Gets, sets the value indicates that Windows File Explorer sort order is used if possible - /// - public static bool IsUseFileExplorerSortOrder { get; set; } = true; - - - /// - /// Gets, sets showing/loading hidden images - /// - public static bool IsShowingHiddenImages { get; set; } = false; - - - /// - /// Gets, sets value that indicates frmColorPicker tool will be open on startup - /// - public static bool IsShowColorPickerOnStartup { get; set; } = false; - - - /// - /// Gets, sets value that indicates frmPageNav tool will be open on startup - /// - public static bool IsShowPageNavOnStartup { get; set; } = false; - - - /// - /// Gets, sets value that indicates page navigation tool auto-show on the multiple pages image - /// - public static bool IsShowPageNavAuto { get; set; } = false; - - - /// - /// Gets, sets value specifying that Window Fit mode is on - /// - public static bool IsWindowFit { get; set; } = false; - - - /// - /// Gets, sets value indicates the window should be always center in Window Fit mode - /// - public static bool IsCenterWindowFit { get; set; } = true; - - - /// - /// Gets, sets value indicates that toast message will show - /// - public static bool IsShowToast { get; set; } = true; - - - #endregion - - - #region Number items - - /// - /// Gets, sets the version that requires to launch First-Launch Configs screen - /// - public static int FirstLaunchVersion { get; set; } = 0; - - - /// - /// Gets, sets slide show interval - /// - public static uint SlideShowInterval { get; set; } = 5; - - - /// - /// Gets, sets value of thumbnail dimension in pixel - /// - public static uint ThumbnailDimension { get; set; } = 96; - - - /// - /// Gets, sets width of horizontal thumbnail bar - /// - public static uint ThumbnailBarWidth { get; set; } = new ThumbnailItemInfo(ThumbnailDimension, true).GetTotalDimension(); - - - /// - /// Gets, sets the number of images cached by Image - /// - public static uint ImageBoosterCachedCount { get; set; } = 1; - - - /// - /// Gets, sets fixed width on zooming - /// - public static double ZoomLockValue { get; set; } = 100f; - - - #endregion - - - #region String items - - /// - /// Gets, sets color profile string. It can be a defined name or ICC/ICM file path - /// - public static string ColorProfile { get; set; } = "sRGB"; - - - /// - /// Gets, sets the last time to check for update. Set it to "0" to disable auto-update. - /// - public static string AutoUpdate { get; set; } = "7/26/1991 12:13:08"; - - - /// - /// Gets, sets the absolute file path of the last seen image - /// - public static string LastSeenImagePath { get; set; } = ""; - - - #endregion - - - #region Array items - - /// - /// Gets, sets zoom levels of the viewer - /// - public static int[] ZoomLevels { get; set; } = new int[] { 5, 10, 15, 20, 30, 40, 50, 60, 70, 80, 90, 100, 125, 150, 175, 200, 250, 300, 350, 400, 500, 600, 700, 800, 1000, 1200, 1500, 1800, 2100, 2500, 3000, 3500 }; - - - /// - /// Gets, sets the list of Image Editing Association - /// - public static List EditApps { get; set; } = new List(); - - - /// - /// Gets, sets the list of supported image formats - /// - public static HashSet AllFormats { get; set; } = new HashSet(); - - - /// - /// Gets, sets the list of keycombo actions - /// - public static Dictionary KeyComboActions = Constants.DefaultKeycomboActions; - - - /// - /// Gets, sets the list of toolbar buttons - /// - public static List ToolbarButtons { get; set; } = Constants.DefaultToolbarButtons; - - #endregion - - - #region Enum items - - /// - /// Gets, sets state of main window - /// - public static FormWindowState FrmMainWindowState { get; set; } = FormWindowState.Normal; - - - /// - /// Gets, sets state of settings window - /// - public static FormWindowState FrmSettingsWindowState { get; set; } = FormWindowState.Normal; - - - /// - /// Gets, sets image loading order - /// - public static ImageOrderBy ImageLoadingOrder { get; set; } = ImageOrderBy.Name; - - - /// - /// Gets, sets image loading order type - /// - public static ImageOrderType ImageLoadingOrderType { get; set; } = ImageOrderType.Asc; - - - /// - /// Gets, sets action to be performed when user spins the mouse wheel - /// - public static MouseWheelActions MouseWheelAction { get; set; } = MouseWheelActions.Zoom; - - - /// - /// Gets, sets action to be performed when user spins the mouse wheel while holding Ctrl key - /// - public static MouseWheelActions MouseWheelCtrlAction { get; set; } = MouseWheelActions.ScrollVertically; - - - /// - /// Gets, sets action to be performed when user spins the mouse wheel while holding Shift key - /// - public static MouseWheelActions MouseWheelShiftAction { get; set; } = MouseWheelActions.ScrollHorizontally; - - - /// - /// Gets, sets action to be performed when user spins the mouse wheel while holding Alt key - /// - public static MouseWheelActions MouseWheelAltAction { get; set; } = MouseWheelActions.BrowseImages; - - - /// - /// Gets, sets zoom mode value - /// - public static ZoomMode ZoomMode { get; set; } = ZoomMode.AutoZoom; - - - /// - /// Gets, sets zoom optimization value - /// - public static ZoomOptimizationMethods ZoomOptimizationMethod { get; set; } = ZoomOptimizationMethods.Auto; - - - /// - /// Gets, sets toolbar position - /// - public static ToolbarPosition ToolbarPosition { get; set; } = ToolbarPosition.Top; - - - - #endregion - - - #region Other types items - - /// - /// Gets, sets background color - /// - public static Color BackgroundColor { get; set; } = Color.Black; - - - /// - /// Gets, sets window bound of main form - /// - public static Rectangle FrmMainWindowsBound { get; set; } = new Rectangle(280, 125, 1000, 800); - - - /// - /// Gets, sets window bound of main form - /// - public static Rectangle FrmSettingsWindowsBound { get; set; } = new Rectangle(280, 125, 900, 700); - - - - /// - /// Gets, sets language pack - /// - public static Language Language { get; set; } = new Language(); - - - /// - /// Gets, sets theme - /// - public static Theme Theme { get; set; } = new Theme(); - - - #endregion - - #endregion - - - - #region Private methods - - /// - /// Convert the given object to Enum type - /// - /// Enum type - /// Value - /// - private static T ParseEnum(object value) - { - return (T)Enum.Parse(typeof(T), value.ToString(), true); - } - - - /// - /// Gets config item from ConfigSource - /// - /// Type - /// Key of the config - /// Default value - /// - private static T Get(string key, object defaultValue) - { - try - { - return ConvertType(Source[key]); - } - catch { } - - // return default value - return ConvertType(defaultValue); - } - - - /// - /// Set the given config to ConfigSource - /// - /// Key of the config - /// Value - private static void Set(string key, object value) - { - if (Source.ContainsKey(key)) - { - Source[key] = value.ToString(); - } - else - { - Source.Add(key, value.ToString()); - } - } - - #endregion - - - - #region Public methods - - /// - /// Load and parse configs from file - /// - public static void Load() - { - // load user configs from file - Source.LoadUserConfigs(); - - - // load configs to public properties - #region Boolean items - - IsSlideshow = Get(nameof(IsSlideshow), IsSlideshow); - IsShowSlideshowCountdown = Get(nameof(IsShowSlideshowCountdown), IsShowSlideshowCountdown); - IsFullScreen = Get(nameof(IsFullScreen), IsFullScreen); - IsShowThumbnail = Get(nameof(IsShowThumbnail), IsShowThumbnail); - IsCenterImage = Get(nameof(IsCenterImage), IsCenterImage); - IsColorPickerRGBA = Get(nameof(IsColorPickerRGBA), IsColorPickerRGBA); - IsColorPickerHEXA = Get(nameof(IsColorPickerHEXA), IsColorPickerHEXA); - IsColorPickerHSLA = Get(nameof(IsColorPickerHSLA), IsColorPickerHSLA); - IsShowWelcome = Get(nameof(IsShowWelcome), IsShowWelcome); - IsShowToolBar = Get(nameof(IsShowToolBar), IsShowToolBar); - IsShowThumbnailScrollbar = Get(nameof(IsShowThumbnailScrollbar), IsShowThumbnailScrollbar); - IsLoopBackSlideshow = Get(nameof(IsLoopBackSlideshow), IsLoopBackSlideshow); - IsLoopBackViewer = Get(nameof(IsLoopBackViewer), IsLoopBackViewer); - IsPressESCToQuit = Get(nameof(IsPressESCToQuit), IsPressESCToQuit); - IsShowCheckerBoard = Get(nameof(IsShowCheckerBoard), IsShowCheckerBoard); - IsAllowMultiInstances = Get(nameof(IsAllowMultiInstances), IsAllowMultiInstances); - IsWindowAlwaysOnTop = Get(nameof(IsWindowAlwaysOnTop), IsWindowAlwaysOnTop); - IsWindowFrameless = Get(nameof(IsWindowFrameless), IsWindowFrameless); - IsThumbnailHorizontal = Get(nameof(IsThumbnailHorizontal), IsThumbnailHorizontal); - IsConfirmationDelete = Get(nameof(IsConfirmationDelete), IsConfirmationDelete); - IsScrollbarsVisible = Get(nameof(IsScrollbarsVisible), IsScrollbarsVisible); - IsSaveAfterRotating = Get(nameof(IsSaveAfterRotating), IsSaveAfterRotating); - IsPreserveModifiedDate = Get(nameof(IsPreserveModifiedDate), IsPreserveModifiedDate); - IsNewVersionAvailable = Get(nameof(IsNewVersionAvailable), IsNewVersionAvailable); - IsDisplayBasenameOfImage = Get(nameof(IsDisplayBasenameOfImage), IsDisplayBasenameOfImage); - IsCenterToolbar = Get(nameof(IsCenterToolbar), IsCenterToolbar); - IsOpenLastSeenImage = Get(nameof(IsOpenLastSeenImage), IsOpenLastSeenImage); - IsApplyColorProfileForAll = Get(nameof(IsApplyColorProfileForAll), IsApplyColorProfileForAll); - IsShowNavigationButtons = Get(nameof(IsShowNavigationButtons), IsShowNavigationButtons); - IsShowCheckerboardOnlyImageRegion = Get(nameof(IsShowCheckerboardOnlyImageRegion), IsShowCheckerboardOnlyImageRegion); - IsRecursiveLoading = Get(nameof(IsRecursiveLoading), IsRecursiveLoading); - IsUseFileExplorerSortOrder = Get(nameof(IsUseFileExplorerSortOrder), IsUseFileExplorerSortOrder); - IsShowingHiddenImages = Get(nameof(IsShowingHiddenImages), IsShowingHiddenImages); - IsShowColorPickerOnStartup = Get(nameof(IsShowColorPickerOnStartup), IsShowColorPickerOnStartup); - IsShowPageNavOnStartup = Get(nameof(IsShowPageNavOnStartup), IsShowPageNavOnStartup); - IsShowPageNavAuto = Get(nameof(IsShowPageNavAuto), IsShowPageNavAuto); - IsWindowFit = Get(nameof(IsWindowFit), IsWindowFit); - IsCenterWindowFit = Get(nameof(IsCenterWindowFit), IsCenterWindowFit); - IsShowToast = Get(nameof(IsShowToast), IsShowToast); - - #endregion - - - #region Number items - - FirstLaunchVersion = Get(nameof(FirstLaunchVersion), FirstLaunchVersion); - SlideShowInterval = Get(nameof(SlideShowInterval), SlideShowInterval); - if (SlideShowInterval < 1) SlideShowInterval = 5; - - #region Load thumbnail bar width & position - ThumbnailDimension = Get(nameof(ThumbnailDimension), ThumbnailDimension); - - if (IsThumbnailHorizontal) - { - // Get minimum width needed for thumbnail dimension - var tbMinWidth = new ThumbnailItemInfo(ThumbnailDimension, true).GetTotalDimension(); - - // Get the greater width value - ThumbnailBarWidth = Math.Max(ThumbnailBarWidth, tbMinWidth); - } - else - { - ThumbnailBarWidth = Get(nameof(ThumbnailBarWidth), ThumbnailBarWidth); - } - #endregion - - ImageBoosterCachedCount = Get(nameof(ImageBoosterCachedCount), ImageBoosterCachedCount); - ImageBoosterCachedCount = Math.Max(0, Math.Min(ImageBoosterCachedCount, 10)); - - ZoomLockValue = Get(nameof(ZoomLockValue), ZoomLockValue); - if (ZoomLockValue < 0) ZoomLockValue = 100f; - - #endregion - - - #region Enum items - - FrmMainWindowState = Get(nameof(FrmMainWindowState), FrmMainWindowState); - FrmSettingsWindowState = Get(nameof(FrmSettingsWindowState), FrmSettingsWindowState); - ImageLoadingOrder = Get(nameof(ImageLoadingOrder), ImageLoadingOrder); - ImageLoadingOrderType = Get(nameof(ImageLoadingOrderType), ImageLoadingOrderType); - MouseWheelAction = Get(nameof(MouseWheelAction), MouseWheelAction); - MouseWheelCtrlAction = Get(nameof(MouseWheelCtrlAction), MouseWheelCtrlAction); - MouseWheelShiftAction = Get(nameof(MouseWheelShiftAction), MouseWheelShiftAction); - MouseWheelAltAction = Get(nameof(MouseWheelAltAction), MouseWheelAltAction); - ZoomMode = Get(nameof(ZoomMode), ZoomMode); - ZoomOptimizationMethod = Get(nameof(ZoomOptimizationMethod), ZoomOptimizationMethod); - ToolbarPosition = Get(nameof(ToolbarPosition), ToolbarPosition); - - #endregion - - - #region String items - - ColorProfile = Get(nameof(ColorProfile), ColorProfile); - ColorProfile = Heart.Helpers.GetCorrectColorProfileName(ColorProfile); - - AutoUpdate = Get(nameof(AutoUpdate), AutoUpdate); - LastSeenImagePath = Get(nameof(LastSeenImagePath), LastSeenImagePath); - - #endregion - - - #region Array items - - #region ZoomLevels - - var zoomLevelStr = Get(nameof(ZoomLevels), ""); - var zoomLevels = Helpers.StringToIntArray(zoomLevelStr, unsignedOnly: true, distinct: true); - - if (zoomLevels.Length > 0) ZoomLevels = zoomLevels; - - #endregion - - - #region EditApps - - var appStr = Get(nameof(EditApps), ""); - EditApps = GetEditApps(appStr); - - #endregion - - - #region ImageFormats - - var formats = Get(nameof(AllFormats), Constants.IMAGE_FORMATS); - AllFormats = GetImageFormats(formats); - - #endregion - - - #region KeyComboActions - - var keyActionStr = Get(nameof(KeyComboActions), ""); - if (!string.IsNullOrEmpty(keyActionStr)) - { - KeyComboActions = GetKeyComboActions(keyActionStr); - } - - #endregion - - - #region ToolbarButtons - - var buttonStr = Get(nameof(ToolbarButtons), ""); - var btnList = GetToolbarButtons(buttonStr); - if (btnList.Count > 0) ToolbarButtons = btnList; - - #endregion - - #endregion - - - #region Other types items - - #region FrmMainWindowsBound - var boundStr = Get(nameof(FrmMainWindowsBound), ""); - if (!string.IsNullOrEmpty(boundStr)) - { - var rc = Helpers.StringToRect(boundStr); - if (!Helper.IsAnyPartOnScreen(rc)) - { - rc = new Rectangle(280, 125, 1000, 800); - } - - FrmMainWindowsBound = rc; - } - #endregion - - - #region FrmSettingsWindowsBound - boundStr = Get(nameof(FrmSettingsWindowsBound), ""); - if (!string.IsNullOrEmpty(boundStr)) - { - var rc = Helpers.StringToRect(boundStr); - - if (!Helper.IsOnScreen(rc.Location)) - { - rc.Location = new Point(280, 125); - } - - FrmSettingsWindowsBound = rc; - } - #endregion - - - #region Lang - var langPath = Get(nameof(Language), "English"); - Language = new Language(langPath, App.StartUpDir(Dir.Languages)); - #endregion - - - #region Theme - var themeFolderName = Get(nameof(Theme), Dir.DefaultTheme); - var th = new Theme(App.ConfigDir(Dir.Themes, themeFolderName)); - - if (th.IsValid) - { - Theme = th; - } - #endregion - - - #region BackgroundColor - // must load after Theme - var bgValue = Get(nameof(BackgroundColor), Theme.ConvertColorToHEX(Theme.BackgroundColor, true)); - BackgroundColor = Theme.ConvertHexStringToColor(bgValue, true); - #endregion - - #endregion - - } - - - /// - /// Parse and write configs to file - /// - public static void Write() - { - // save public properties to configs - #region Boolean items - - Set(nameof(IsSlideshow), IsSlideshow); - Set(nameof(IsShowSlideshowCountdown), IsShowSlideshowCountdown); - Set(nameof(IsFullScreen), IsFullScreen); - Set(nameof(IsShowThumbnail), IsShowThumbnail); - Set(nameof(IsCenterImage), IsCenterImage); - Set(nameof(IsColorPickerRGBA), IsColorPickerRGBA); - Set(nameof(IsColorPickerHEXA), IsColorPickerHEXA); - Set(nameof(IsColorPickerHSLA), IsColorPickerHSLA); - Set(nameof(IsShowWelcome), IsShowWelcome); - Set(nameof(IsShowToolBar), IsShowToolBar); - Set(nameof(IsShowThumbnailScrollbar), IsShowThumbnailScrollbar); - Set(nameof(IsLoopBackSlideshow), IsLoopBackSlideshow); - Set(nameof(IsLoopBackViewer), IsLoopBackViewer); - Set(nameof(IsPressESCToQuit), IsPressESCToQuit); - Set(nameof(IsShowCheckerBoard), IsShowCheckerBoard); - Set(nameof(IsAllowMultiInstances), IsAllowMultiInstances); - Set(nameof(IsWindowAlwaysOnTop), IsWindowAlwaysOnTop); - Set(nameof(IsWindowFrameless), IsWindowFrameless); - Set(nameof(IsThumbnailHorizontal), IsThumbnailHorizontal); - Set(nameof(IsConfirmationDelete), IsConfirmationDelete); - Set(nameof(IsScrollbarsVisible), IsScrollbarsVisible); - Set(nameof(IsSaveAfterRotating), IsSaveAfterRotating); - Set(nameof(IsPreserveModifiedDate), IsPreserveModifiedDate); - Set(nameof(IsNewVersionAvailable), IsNewVersionAvailable); - Set(nameof(IsDisplayBasenameOfImage), IsDisplayBasenameOfImage); - Set(nameof(IsCenterToolbar), IsCenterToolbar); - Set(nameof(IsOpenLastSeenImage), IsOpenLastSeenImage); - Set(nameof(IsApplyColorProfileForAll), IsApplyColorProfileForAll); - Set(nameof(IsShowNavigationButtons), IsShowNavigationButtons); - Set(nameof(IsShowCheckerboardOnlyImageRegion), IsShowCheckerboardOnlyImageRegion); - Set(nameof(IsRecursiveLoading), IsRecursiveLoading); - Set(nameof(IsUseFileExplorerSortOrder), IsUseFileExplorerSortOrder); - Set(nameof(IsShowingHiddenImages), IsShowingHiddenImages); - Set(nameof(IsShowColorPickerOnStartup), IsShowColorPickerOnStartup); - Set(nameof(IsShowPageNavOnStartup), IsShowPageNavOnStartup); - Set(nameof(IsShowPageNavAuto), IsShowPageNavAuto); - Set(nameof(IsWindowFit), IsWindowFit); - Set(nameof(IsCenterWindowFit), IsCenterWindowFit); - Set(nameof(IsShowToast), IsShowToast); - - #endregion - - - #region Number items - - Set(nameof(FirstLaunchVersion), FirstLaunchVersion); - Set(nameof(SlideShowInterval), SlideShowInterval); - Set(nameof(ThumbnailDimension), ThumbnailDimension); - Set(nameof(ThumbnailBarWidth), ThumbnailBarWidth); - Set(nameof(ImageBoosterCachedCount), ImageBoosterCachedCount); - Set(nameof(ZoomLockValue), ZoomLockValue); - - #endregion - - - #region Enum items - - Set(nameof(FrmMainWindowState), FrmMainWindowState); - Set(nameof(FrmSettingsWindowState), FrmSettingsWindowState); - Set(nameof(ImageLoadingOrder), ImageLoadingOrder); - Set(nameof(ImageLoadingOrderType), ImageLoadingOrderType); - Set(nameof(MouseWheelAction), MouseWheelAction); - Set(nameof(MouseWheelCtrlAction), MouseWheelCtrlAction); - Set(nameof(MouseWheelShiftAction), MouseWheelShiftAction); - Set(nameof(MouseWheelAltAction), MouseWheelAltAction); - Set(nameof(ZoomMode), ZoomMode); - Set(nameof(ZoomOptimizationMethod), ZoomOptimizationMethod); - Set(nameof(ToolbarPosition), ToolbarPosition); - - #endregion - - - #region String items - - Set(nameof(ColorProfile), ColorProfile); - Set(nameof(ToolbarButtons), ToolbarButtons); - Set(nameof(AutoUpdate), AutoUpdate); - Set(nameof(LastSeenImagePath), LastSeenImagePath); - - #endregion - - - #region Array items - - Set(nameof(ZoomLevels), Helpers.IntArrayToString(ZoomLevels)); - Set(nameof(EditApps), GetEditApps(EditApps)); - Set(nameof(AllFormats), GetImageFormats(AllFormats)); - Set(nameof(KeyComboActions), GetKeyComboActions(KeyComboActions)); - Set(nameof(ToolbarButtons), GetToolbarButtons(ToolbarButtons)); - - #endregion - - - #region Other types items - - Set(nameof(BackgroundColor), Theme.ConvertColorToHEX(BackgroundColor, true)); - Set(nameof(FrmMainWindowsBound), Helpers.RectToString(FrmMainWindowsBound)); - Set(nameof(FrmSettingsWindowsBound), Helpers.RectToString(FrmSettingsWindowsBound)); - Set(nameof(Language), Path.GetFileName(Language.FileName)); - Set(nameof(Theme), Theme.FolderName); - - #endregion - - - // write user configs to file - Source.WriteUserConfigs(); - } - - - - #region Helper functions - - /// - /// Convert the given value to specific type - /// - /// Type - /// Value - /// - public static T ConvertType(object value) - { - var type = typeof(T); - - if (type.IsEnum) - { - return ParseEnum(value); - } - else - { - return (T)Convert.ChangeType(value, type); - } - } - - - /// - /// Get the registered file extensions from registry - /// Ex: *.svg;*.png; - /// - /// - public static string GetRegisteredExtensions() - { - var reg = new RegistryHelper() - { - BaseRegistryKey = Registry.LocalMachine, - SubKey = @"SOFTWARE\PhapSoftware\ImageGlass\Capabilities\FileAssociations" - }; - - var extList = reg.GetValueNames(); - var exts = new StringBuilder(); - - foreach (var ext in extList) - { - exts.Append($"*{ext};"); - } - - return exts.ToString(); - } - - #endregion - - - #region Config functions - - #region EditApp - - /// - /// Get ImageEditingAssociation from ImageEditingAssociationList - /// - /// An extension to search. Ex: .png - /// - public static EditApp GetEditApp(string ext) - { - if (EditApps.Count > 0) - { - return EditApps.FirstOrDefault(v => v.Extension.CompareTo(ext) == 0); - } - - return null; - } - - - /// - /// Returns string from the given apps - /// - /// - /// - public static List GetEditApps(string apps) - { - var appStr = apps.Split("[]".ToCharArray(), StringSplitOptions.RemoveEmptyEntries); - var list = new List(); - - if (appStr.Length > 0) - { - foreach (var item in appStr) - { - try - { - var extAssoc = new EditApp(item); - list.Add(extAssoc); - } - catch (InvalidCastException) { } - } - } - - return list; - } - - - /// - /// Returns string from the given apps - /// - /// - /// - public static string GetEditApps(List apps) - { - var appStr = new StringBuilder(); - foreach (var item in apps) - { - appStr.Append($"[{item.ToString()}]"); - } - - return appStr.ToString(); - } - - #endregion - - - #region ImageFormats - - /// - /// Returns distinc list of image formats - /// - /// The format string. E.g: *.bpm;*.jpg; - /// - public static HashSet GetImageFormats(string formats) - { - var list = new HashSet(); - var formatList = formats.Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries); - char[] wildTrim = { '*' }; - - foreach (var ext in formatList) - { - list.Add(ext.Trim(wildTrim)); - } - - return list; - } - - - /// - /// Returns the image formats string - /// - /// The input HashSet - /// - public static string GetImageFormats(HashSet list) - { - var sb = new StringBuilder(list.Count); - foreach (var item in list) - { - sb.Append($"*{item.ToString()};"); - } - - return sb.ToString(); - } - - #endregion - - - #region KeyComboActions - - /// - /// Returns the keycombo actions from string - /// - /// The input string. E.g. "combo1:action1;combo2:action2" - /// - public static Dictionary GetKeyComboActions(string keyActions) - { - var pairs = keyActions.Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries); - var dic = new Dictionary(); - - try - { - foreach (var pair in pairs) - { - var parts = pair.Split(new[] { ':' }, StringSplitOptions.RemoveEmptyEntries); - - var keyCombo = ParseEnum(parts[0]); - var action = ParseEnum(parts[1]); - - dic.Add(keyCombo, action); - } - } - catch - { - // reset to default set on error - dic = Constants.DefaultKeycomboActions; - } - - return dic; - } - - - /// - /// Returns the string from keycombo actions - /// - /// The input keycombo actions - /// - public static string GetKeyComboActions(Dictionary keyActions) - { - var sb = new StringBuilder(); - - foreach (var key in keyActions.Keys) - { - sb.Append(key.ToString()); - sb.Append(':'); - sb.Append(keyActions[key].ToString()); - sb.Append(';'); - } - - return sb.ToString(); - } - - #endregion - - - #region ToolbarButtons - - /// - /// Returns list of toolbar buttons from string - /// - /// The input string - /// - public static List GetToolbarButtons(string buttons) - { - var list = new List(); - string[] splitvals = buttons.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries); - - foreach (var item in splitvals) - { - try - { - var btn = ParseEnum(item); - list.Add(btn); - } - // ignore invalid values - catch { } - } - - return list; - } - - - /// - /// Returns string from toolbar buttons list - /// - /// The input toolbar buttons - /// - public static string GetToolbarButtons(List list) - { - var sb = new StringBuilder(list.Count); - foreach (var item in list) - { - sb.Append($"{item.ToString()};"); - } - - return sb.ToString(); - } - - - #endregion - - - #endregion - - - #endregion - - } -} diff --git a/Source/Components/ImageGlass.Settings/ConfigurationExtensions.cs b/Source/Components/ImageGlass.Settings/ConfigurationExtensions.cs new file mode 100644 index 000000000..715ac811c --- /dev/null +++ b/Source/Components/ImageGlass.Settings/ConfigurationExtensions.cs @@ -0,0 +1,121 @@ +/* +ImageGlass Project - Image viewer for Windows +Copyright (C) 2010 - 2026 DUONG DIEU PHAP +Project homepage: https://imageglass.org + +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 . +*/ +using Microsoft.Extensions.Configuration; +using System.Dynamic; + +namespace ImageGlass; + +public static class ConfigurationExtensions +{ + /// + /// Gets config section as dynamic object. + /// + public static ExpandoObject? GetValueObj(this IConfiguration config, string keyName) + { + var result = new ExpandoObject(); + + // retrieve all keys from your settings + var configs = config.AsEnumerable().Where(_ => _.Key.StartsWith(keyName)); + if (!configs.Any()) return null; + + foreach (var kvp in configs) + { + var parent = result as IDictionary; + var path = kvp.Key.Split(':'); + + // create or retrieve the hierarchy (keep last path item for later) + var i = 0; + for (i = 0; i < path.Length - 1; i++) + { + if (!parent.ContainsKey(path[i])) + { + parent.Add(path[i], new ExpandoObject()); + } + + parent = parent[path[i]] as IDictionary; + } + + if (kvp.Value == null) + continue; + + // add the value to the parent + // note: in case of an array, key will be an integer and will be dealt with later + var key = path[i]; + parent.Add(key, kvp.Value); + } + + // at this stage, all arrays are seen as dictionaries with integer keys + ReplaceWithArray(null, null, result); + + return result; + } + + + /// + /// Gets config value, returns on error. + /// + public static T GetValueEx(this IConfiguration config, string keyName, T defaultValue) + { + try + { + return config.GetValue(keyName, defaultValue); + } + catch { } + + return defaultValue; + } + + + private static void ReplaceWithArray(ExpandoObject? parent, string? key, ExpandoObject input) + { + if (input == null) + return; + + var dict = input as IDictionary; + var keys = dict.Keys.ToArray(); + + // it's an array if all keys are integers + if (keys.All(k => int.TryParse(k, out var dummy))) + { + var array = new object[keys.Length]; + foreach (var kvp in dict) + { + array[int.Parse(kvp.Key)] = kvp.Value; + + // Edit: If structure is nested deeper we need this next line + ReplaceWithArray(input, kvp.Key, kvp.Value as ExpandoObject); + } + + if (parent != null) + { + var parentDict = parent as IDictionary; + parentDict.Remove(key); + parentDict.Add(key, array); + } + } + else + { + foreach (var childKey in dict.Keys.ToList()) + { + ReplaceWithArray(input, childKey, dict[childKey] as ExpandoObject); + } + } + } + +} diff --git a/Source/Components/ImageGlass.Settings/Events/RequestUpdatingThemeEventArgs.cs b/Source/Components/ImageGlass.Settings/Events/RequestUpdatingThemeEventArgs.cs new file mode 100644 index 000000000..ad2b25172 --- /dev/null +++ b/Source/Components/ImageGlass.Settings/Events/RequestUpdatingThemeEventArgs.cs @@ -0,0 +1,37 @@ +/* +ImageGlass Project - Image viewer for Windows +Copyright (C) 2010 - 2026 DUONG DIEU PHAP +Project homepage: https://imageglass.org + +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 . +*/ + + +using ImageGlass.UI; + +namespace ImageGlass.Settings; + +public class RequestUpdatingThemeEventArgs(IgTheme theme, bool handled = false) +{ + /// + /// Gets the theme pack. + /// + public IgTheme Theme { get; } = theme; + + + /// + /// Gets, sets value indicates that the event is already handled. + /// + public bool Handled { get; set; } = handled; +} diff --git a/Source/Components/ImageGlass.Settings/Events/SystemColorModeChangedEventArgs.cs b/Source/Components/ImageGlass.Settings/Events/SystemColorModeChangedEventArgs.cs new file mode 100644 index 000000000..3aa935c8c --- /dev/null +++ b/Source/Components/ImageGlass.Settings/Events/SystemColorModeChangedEventArgs.cs @@ -0,0 +1,36 @@ +/* +ImageGlass Project - Image viewer for Windows +Copyright (C) 2010 - 2026 DUONG DIEU PHAP +Project homepage: https://imageglass.org + +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 . +*/ + + +namespace ImageGlass.Settings; + +public class SystemColorModeChangedEventArgs(bool isDarkMode, bool handled = false) +{ + /// + /// Checks if the app color mode is dark. + /// + public bool IsDarkMode { get; } = isDarkMode; + + + /// + /// Gets, sets value indicates that the event is already handled. + /// + public bool Handled { get; set; } = handled; + +} diff --git a/Source/Components/ImageGlass.Settings/Events/ToolFormEvents.cs b/Source/Components/ImageGlass.Settings/Events/ToolFormEvents.cs new file mode 100644 index 000000000..f66aa8b80 --- /dev/null +++ b/Source/Components/ImageGlass.Settings/Events/ToolFormEvents.cs @@ -0,0 +1,57 @@ +/* +ImageGlass Project - Image viewer for Windows +Copyright (C) 2010 - 2026 DUONG DIEU PHAP +Project homepage: https://imageglass.org + +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 . +*/ +using System.ComponentModel; + +namespace ImageGlass.Settings; + + +/// +/// Provides data for the event. +/// +public class ToolFormClosingEventArgs(string name, CloseReason closeReason, bool cancel) : CancelEventArgs(cancel) +{ + /// + /// Gets the name of the tool form. + /// + public string Name { get; } = name; + + /// + /// Provides the reason for the Form Close. + /// + public CloseReason CloseReason { get; } = closeReason; +} + + +/// +/// Provides data for the event. +/// +public class ToolFormClosedEventArgs(string name, CloseReason closeReason) : EventArgs +{ + /// + /// Gets the name of the tool form. + /// + public string Name { get; } = name; + + /// + /// Provides the reason for the Form Close. + /// + public CloseReason CloseReason { get; } = closeReason; + +} + diff --git a/Source/Components/ImageGlass.Settings/Forms/DialogForm.Designer.cs b/Source/Components/ImageGlass.Settings/Forms/DialogForm.Designer.cs new file mode 100644 index 000000000..9787f4c7b --- /dev/null +++ b/Source/Components/ImageGlass.Settings/Forms/DialogForm.Designer.cs @@ -0,0 +1,52 @@ +namespace ImageGlass.Settings +{ + partial class DialogForm + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + SuspendLayout(); + // + // DialogForm + // + AutoScaleDimensions = new SizeF(7F, 17F); + AutoScaleMode = AutoScaleMode.Font; + ClientSize = new Size(359, 240); + KeyPreview = true; + Margin = new Padding(1, 1, 1, 1); + MaximizeBox = false; + MinimizeBox = false; + Name = "DialogForm"; + ShowIcon = false; + ShowInTaskbar = false; + StartPosition = FormStartPosition.CenterParent; + Text = ""; + ResumeLayout(false); + } + + #endregion + } +} \ No newline at end of file diff --git a/Source/Components/ImageGlass.Settings/Forms/DialogForm.cs b/Source/Components/ImageGlass.Settings/Forms/DialogForm.cs new file mode 100644 index 000000000..e9d9ef566 --- /dev/null +++ b/Source/Components/ImageGlass.Settings/Forms/DialogForm.cs @@ -0,0 +1,418 @@ +/* +ImageGlass Project - Image viewer for Windows +Copyright (C) 2010 - 2026 DUONG DIEU PHAP +Project homepage: https://imageglass.org + +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 . +*/ + +using ImageGlass.Base; +using ImageGlass.UI; +using System.ComponentModel; + +namespace ImageGlass.Settings; + + +/// +/// Dialog form with theme support. +/// +public partial class DialogForm : ThemedForm +{ + private bool _showAcceptButton = true; + private bool _showCancelButton = true; + private bool _showApplyButton = false; + + + // Public properties + #region Public properties + + /// + /// Gets, sets 's text. + /// + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public string AcceptButtonText + { + get => BtnAccept.Text; + set => BtnAccept.Text = value; + } + + + /// + /// Shows or hides the Shield icon for the . + /// + [DefaultValue(false)] + public bool ShowAcceptButtonShieldIcon + { + get => BtnAccept.SystemIcon == StockIconId.Shield; + set => BtnAccept.SystemIcon = value ? StockIconId.Shield : null; + } + + + /// + /// Gets, sets visibility value of the . + /// + [DefaultValue(true)] + public bool ShowAcceptButton + { + get => _showAcceptButton; + set + { + _showAcceptButton = value; + BtnAccept.Visible = value; + } + } + + + /// + /// Gets, sets 's text. + /// + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public string CancelButtonText + { + get => BtnCancel.Text; + set => BtnCancel.Text = value; + } + + + /// + /// Gets, sets visibility value of the . + /// + [DefaultValue(true)] + public bool ShowCancelButton + { + get => _showCancelButton; + set + { + _showCancelButton = value; + BtnCancel.Visible = value; + } + } + + + /// + /// Gets, sets 's text. + /// + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public string ApplyButtonText + { + get => BtnApply.Text; + set => BtnApply.Text = value; + } + + + /// + /// Gets, sets visibility value of the . + /// + [DefaultValue(false)] + public bool ShowApplyButton + { + get => _showApplyButton; + set + { + _showApplyButton = value; + BtnApply.Visible = value; + } + } + + public override Keys CloseFormHotkey => Keys.Escape; + + #endregion // Public properties + + + /// + /// Initializes the new instance of . This appends + /// an action bar with and + /// to the bottom of the form. + /// + public DialogForm() : base() + { + InitializeComponent(); + + AppendActionBar(); + } + + + // Action bar codes + #region Action bar codes + + public TableLayoutPanel TableFooter = new TableLayoutPanel(); + public ModernButton BtnAccept = new ModernButton(); + public ModernButton BtnCancel = new ModernButton(); + public ModernButton BtnApply = new ModernButton(); + + + /// + /// Adds action bar with OK and Cancel buttons to the form. + /// + private void AppendActionBar() + { + this.TableFooter.SuspendLayout(); + this.SuspendLayout(); + // + // TableActions + // + this.TableFooter.AutoSize = true; + this.TableFooter.AutoSizeMode = AutoSizeMode.GrowAndShrink; + this.TableFooter.ColumnCount = 4; + this.TableFooter.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100F)); + this.TableFooter.ColumnStyles.Add(new ColumnStyle()); + this.TableFooter.ColumnStyles.Add(new ColumnStyle()); + this.TableFooter.Controls.Add(this.BtnAccept, 1, 0); + this.TableFooter.Controls.Add(this.BtnCancel, 2, 0); + this.TableFooter.Controls.Add(this.BtnApply, 3, 0); + this.TableFooter.Dock = DockStyle.Bottom; + this.TableFooter.Location = new Point(0, 367); + this.TableFooter.Margin = new Padding(0); + this.TableFooter.Padding = this.ScaleToDpi(new Padding(16)); + this.TableFooter.Name = "TableFooter"; + this.TableFooter.RowCount = 1; + this.TableFooter.RowStyles.Add(new RowStyle()); + this.TableFooter.Size = new Size(800, 83); + this.TableFooter.TabIndex = 2; + // + // BtnAccept + // + this.BtnAccept.AutoSize = true; + this.BtnAccept.DarkMode = false; + this.BtnAccept.ImagePadding = 2; + this.BtnAccept.Location = new Point(500, 20); + this.BtnAccept.Margin = this.ScaleToDpi(new Padding(8, 0, 0, 0)); + this.BtnAccept.Name = "BtnAccept"; + this.BtnAccept.Text = "[OK]"; + this.BtnAccept.Size = this.ScaleToDpi(new Size(90, 30)); + this.BtnAccept.SystemIcon = null; + this.BtnAccept.TabIndex = 1; + this.BtnAccept.Text = AcceptButtonText; + this.BtnAccept.TextImageRelation = TextImageRelation.ImageBeforeText; + this.BtnAccept.Visible = _showAcceptButton; + this.BtnAccept.Click += BtnAccept_Click; + // + // BtnCancel + // + this.BtnCancel.AutoSize = true; + this.BtnCancel.DarkMode = false; + this.BtnCancel.ImagePadding = 2; + this.BtnCancel.Location = new Point(650, 20); + this.BtnCancel.Margin = this.ScaleToDpi(new Padding(8, 0, 0, 0)); + this.BtnCancel.Name = "BtnCancel"; + this.BtnCancel.Text = "[Cancel]"; + this.BtnCancel.Size = this.ScaleToDpi(new Size(90, 30)); + this.BtnCancel.SystemIcon = null; + this.BtnCancel.TabIndex = 2; + this.BtnCancel.Text = CancelButtonText; + this.BtnCancel.TextImageRelation = TextImageRelation.ImageBeforeText; + this.BtnCancel.Visible = _showCancelButton; + this.BtnCancel.Click += BtnCancel_Click; + // + // BtnApply + // + this.BtnApply.AutoSize = true; + this.BtnApply.DarkMode = false; + this.BtnApply.ImagePadding = 2; + this.BtnApply.Location = new Point(800, 20); + this.BtnApply.Margin = this.ScaleToDpi(new Padding(8, 0, 0, 0)); + this.BtnApply.Name = "BtnApply"; + this.BtnApply.Text = "[Apply]"; + this.BtnApply.Size = this.ScaleToDpi(new Size(90, 30)); + this.BtnApply.SystemIcon = null; + this.BtnApply.TabIndex = 3; + this.BtnApply.Text = ApplyButtonText; + this.BtnApply.TextImageRelation = TextImageRelation.ImageBeforeText; + this.BtnApply.Visible = _showApplyButton; + this.BtnApply.Click += BtnApply_Click; + + + this.TableFooter.ResumeLayout(false); + this.TableFooter.PerformLayout(); + + this.Controls.Add(this.TableFooter); + this.AcceptButton = BtnAccept; + this.CancelButton = BtnCancel; + this.ResumeLayout(false); + this.PerformLayout(); + } + + + private void BtnAccept_Click(object? sender, EventArgs e) + { + OnAcceptButtonClicked(); + } + + + private void BtnCancel_Click(object? sender, EventArgs e) + { + OnCancelButtonClicked(); + } + + + private void BtnApply_Click(object? sender, EventArgs e) + { + OnApplyButtonClicked(); + } + + #endregion // Action bar codes + + + // Override / Virtual methods + #region Override / Virtual methods + + protected override void ApplyTheme(bool darkMode, BackdropStyle? style = null) + { + SuspendLayout(); + + // show backdrop effect for title and footer + BackdropMargin = new Padding(0, 0, 0, this.TableFooter.Height); + + if (EnableTransparent) + { + TableFooter.BackColor = darkMode + ? Color.White.WithAlpha(10) + : Color.White.WithAlpha(200); + } + else + { + var colorPalatte = BHelper.GetThemeColorPalatte(darkMode); + BackColor = colorPalatte.AppBg; + + TableFooter.BackColor = darkMode + ? Color.White.WithAlpha(15) + : Color.Black.WithAlpha(15); + } + + base.ApplyTheme(darkMode, style); + ResumeLayout(); + } + + + protected override void OnRequestUpdatingColorMode(SystemColorModeChangedEventArgs e) + { + base.OnRequestUpdatingColorMode(e); + + // update theme + ApplyTheme(Config.Theme.Settings.IsDarkMode); + Invalidate(true); + } + + + protected override void OnDpiChanged(DpiChangedEventArgs e) + { + base.OnDpiChanged(e); + + OnUpdateHeight(); + ApplyTheme(DarkMode); + } + + + protected override void OnLoad(EventArgs e) + { + // update size and padding + this.BtnAccept.Size = + this.BtnCancel.Size = + this.BtnApply.Size = this.ScaleToDpi(new Size(90, 30)); + + this.TableFooter.Padding = this.ScaleToDpi(new Padding(16)); + this.BtnAccept.Margin = + this.BtnCancel.Margin = + this.BtnApply.Margin = this.ScaleToDpi(new Padding(8, 0, 0, 0)); + + var buttonPadding = this.ScaleToDpi(new Padding( + ModernButton.DefaultPadding.Left * 2, + ModernButton.DefaultPadding.Top, + ModernButton.DefaultPadding.Right * 2, + ModernButton.DefaultPadding.Bottom)); + this.BtnAccept.Padding = buttonPadding; + this.BtnCancel.Padding = buttonPadding; + this.BtnApply.Padding = buttonPadding; + + + // adjust form size + _ = OnUpdateHeight(); + + base.OnLoad(e); + + this.TableFooter.BringToFront(); + + // enable free form moving + EnableFormFreeMoving(this); + } + + + protected override void OnFormClosing(FormClosingEventArgs e) + { + base.OnFormClosing(e); + + DisableFormFreeMoving(this); + } + + + protected override void CloseFormByKeys() + { + // Closes the form and returns code. + DialogResult = DialogResult.Abort; + + base.CloseFormByKeys(); + } + + + /// + /// Recalculates and updates window height on event. + /// + protected virtual int OnUpdateHeight(bool performUpdate = true) + { + // calculate form height + var formNonClientHeight = Padding.Vertical; + var contentHeight = TableFooter.Height + TableFooter.Padding.Vertical; + var formHeight = formNonClientHeight + contentHeight; + + if (performUpdate && Height != formHeight) + { + Height = formHeight; + } + + return formHeight; + } + + + /// + /// Closes the form and returns code. + /// + protected virtual void OnAcceptButtonClicked() + { + DialogResult = DialogResult.OK; + Close(); + } + + + /// + /// Closes the form and returns code. + /// + protected virtual void OnCancelButtonClicked() + { + DialogResult = DialogResult.Cancel; + Close(); + } + + + /// + /// Occurs when is clicked. + /// + protected virtual void OnApplyButtonClicked() + { + // + } + + #endregion // Override / Virtual methods + + +} diff --git a/Source/Components/ImageGlass.UI/frmDialogBox.resx b/Source/Components/ImageGlass.Settings/Forms/DialogForm.resx similarity index 85% rename from Source/Components/ImageGlass.UI/frmDialogBox.resx rename to Source/Components/ImageGlass.Settings/Forms/DialogForm.resx index 93707234a..af32865ec 100644 --- a/Source/Components/ImageGlass.UI/frmDialogBox.resx +++ b/Source/Components/ImageGlass.Settings/Forms/DialogForm.resx @@ -1,17 +1,17 @@  - @@ -117,12 +117,4 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - - iVBORw0KGgoAAAANSUhEUgAAAAgAAAB4CAYAAADPLbNKAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO - vgAADr4B6kKxwAAAADhJREFUWEftyjERADAMA7HwJxkKZuAOvwdA7wdtmt3tZZL0YoABBhhggAEGGGCA - AQYYYIABP4T0AXQ0R3sUNnksAAAAAElFTkSuQmCC - - \ No newline at end of file diff --git a/Source/Components/ImageGlass.Settings/Forms/ModernColorDialog.Designer.cs b/Source/Components/ImageGlass.Settings/Forms/ModernColorDialog.Designer.cs new file mode 100644 index 000000000..68d7f3f28 --- /dev/null +++ b/Source/Components/ImageGlass.Settings/Forms/ModernColorDialog.Designer.cs @@ -0,0 +1,66 @@ +namespace ImageGlass.Settings +{ + partial class ModernColorDialog + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + ColorPicker = new UI.ModernColorPicker(); + SuspendLayout(); + // + // ColorPicker + // + ColorPicker.BackColor = Color.Transparent; + ColorPicker.ColorMode = UI.ColorMode.Luminance; + ColorPicker.ColorValue = Color.White; + ColorPicker.DarkMode = false; + ColorPicker.Dock = DockStyle.Top; + ColorPicker.Location = new Point(0, 0); + ColorPicker.Margin = new Padding(0); + ColorPicker.Name = "ColorPicker"; + ColorPicker.Padding = new Padding(40, 40, 20, 20); + ColorPicker.Size = new Size(1434, 836); + ColorPicker.TabIndex = 3; + // + // ModernColorDialog + // + AutoScaleDimensions = new SizeF(18F, 45F); + AutoScaleMode = AutoScaleMode.Font; + ClientSize = new Size(1434, 1132); + Controls.Add(ColorPicker); + FormBorderStyle = FormBorderStyle.FixedDialog; + Name = "ModernColorDialog"; + Text = "[Color picker]"; + Controls.SetChildIndex(ColorPicker, 0); + ResumeLayout(false); + PerformLayout(); + } + + #endregion + + private UI.ModernColorPicker ColorPicker; + } +} \ No newline at end of file diff --git a/Source/Components/ImageGlass.Settings/Forms/ModernColorDialog.cs b/Source/Components/ImageGlass.Settings/Forms/ModernColorDialog.cs new file mode 100644 index 000000000..7a0ffd5f4 --- /dev/null +++ b/Source/Components/ImageGlass.Settings/Forms/ModernColorDialog.cs @@ -0,0 +1,117 @@ +/* +ImageGlass Project - Image viewer for Windows +Copyright (C) 2010 - 2026 DUONG DIEU PHAP +Project homepage: https://imageglass.org + +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 . +*/ +using ImageGlass.Base; +using ImageGlass.UI; +using System.ComponentModel; + +namespace ImageGlass.Settings; + + +/// +/// A modern color picker dialog with transparency support. +/// +public partial class ModernColorDialog : DialogForm +{ + // Public properties + #region Public properties + + /// + /// Gets, sets the selected color value. + /// + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public Color ColorValue + { + get => ColorPicker.ColorValue; + set => ColorPicker.ColorValue = value; + } + + + /// + /// Gets, sets color mode. + /// + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public ColorMode ColorMode + { + get => ColorPicker.ColorMode; + set => ColorPicker.ColorMode = value; + } + + #endregion // Public properties + + + public ModernColorDialog() + { + InitializeComponent(); + } + + + // Override / Virtual methods + #region Override / Virtual methods + + protected override void OnLoad(EventArgs e) + { + // must be before base.OnLoad() + ApplyLanguage(); + + // update form height + base.OnLoad(e); + + // must be after base.OnLoad() + ApplyTheme(Config.Theme.Settings.IsDarkMode); + } + + + protected override void ApplyTheme(bool darkMode, BackdropStyle? style = null) + { + SuspendLayout(); + + ColorPicker.BackColor = Config.Theme.ColorPalatte.AppBg; + ColorPicker.DarkMode = darkMode; + + base.ApplyTheme(darkMode, style); + ResumeLayout(); + } + + + protected override int OnUpdateHeight(bool performUpdate = true) + { + var baseHeight = base.OnUpdateHeight(false); + var formHeight = ColorPicker.Height + baseHeight; + + if (performUpdate && Height != formHeight) + { + Height = formHeight; + } + + return formHeight; + } + + + #endregion // Override / Virtual methods + + + private void ApplyLanguage() + { + BtnAccept.Text = Config.Language["_._OK"]; + BtnCancel.Text = Config.Language["_._Cancel"]; + + Text = Config.Language["FrmMain.MnuColorPicker"]; + } + +} diff --git a/Source/Ultilities/igtasks/Properties/Resources.resx b/Source/Components/ImageGlass.Settings/Forms/ModernColorDialog.resx similarity index 85% rename from Source/Ultilities/igtasks/Properties/Resources.resx rename to Source/Components/ImageGlass.Settings/Forms/ModernColorDialog.resx index af7dbebba..af32865ec 100644 --- a/Source/Ultilities/igtasks/Properties/Resources.resx +++ b/Source/Components/ImageGlass.Settings/Forms/ModernColorDialog.resx @@ -1,17 +1,17 @@  - + @@ -68,9 +69,10 @@ - + + @@ -85,9 +87,10 @@ - + + @@ -109,9 +112,9 @@ 2.0 - System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 \ No newline at end of file diff --git a/Source/Components/ImageGlass.Settings/Forms/Popup.Designer.cs b/Source/Components/ImageGlass.Settings/Forms/Popup.Designer.cs new file mode 100644 index 000000000..ff540bf25 --- /dev/null +++ b/Source/Components/ImageGlass.Settings/Forms/Popup.Designer.cs @@ -0,0 +1,186 @@ +using ImageGlass.UI; + +namespace ImageGlass.Settings +{ + partial class Popup + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + tableMain = new TableLayoutPanel(); + lblHeading = new ModernLabel(); + lblNote = new ModernLabel(); + txtValue = new ModernTextBox(); + lblDescription = new ModernLabel(); + picThumbnail = new PictureBox(); + ChkOption = new ModernCheckBox(); + tableMain.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)picThumbnail).BeginInit(); + SuspendLayout(); + // + // tableMain + // + tableMain.AutoSize = true; + tableMain.AutoSizeMode = AutoSizeMode.GrowAndShrink; + tableMain.BackColor = Color.Transparent; + tableMain.ColumnCount = 2; + tableMain.ColumnStyles.Add(new ColumnStyle()); + tableMain.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100F)); + tableMain.Controls.Add(lblHeading, 1, 1); + tableMain.Controls.Add(lblNote, 0, 4); + tableMain.Controls.Add(txtValue, 1, 3); + tableMain.Controls.Add(lblDescription, 1, 2); + tableMain.Controls.Add(picThumbnail, 0, 1); + tableMain.Controls.Add(ChkOption, 1, 5); + tableMain.Dock = DockStyle.Top; + tableMain.Location = new Point(0, 0); + tableMain.Margin = new Padding(0); + tableMain.Name = "tableMain"; + tableMain.Padding = new Padding(0, 15, 0, 15); + tableMain.RowCount = 7; + tableMain.RowStyles.Add(new RowStyle()); + tableMain.RowStyles.Add(new RowStyle()); + tableMain.RowStyles.Add(new RowStyle()); + tableMain.RowStyles.Add(new RowStyle()); + tableMain.RowStyles.Add(new RowStyle()); + tableMain.RowStyles.Add(new RowStyle()); + tableMain.RowStyles.Add(new RowStyle()); + tableMain.Size = new Size(478, 230); + tableMain.TabIndex = 1; + // + // lblHeading + // + lblHeading.AutoSize = true; + lblHeading.BackColor = Color.Transparent; + lblHeading.DarkMode = false; + lblHeading.Font = new Font("Segoe UI", 12F); + lblHeading.Location = new Point(106, 15); + lblHeading.Margin = new Padding(12, 0, 16, 15); + lblHeading.Name = "lblHeading"; + lblHeading.Size = new Size(78, 21); + lblHeading.TabIndex = 100; + lblHeading.Text = "[Heading]"; + // + // lblNote + // + lblNote.AutoSize = true; + lblNote.BackColor = Color.Transparent; + tableMain.SetColumnSpan(lblNote, 2); + lblNote.DarkMode = false; + lblNote.Dock = DockStyle.Top; + lblNote.Location = new Point(16, 138); + lblNote.Margin = new Padding(16, 15, 16, 0); + lblNote.Name = "lblNote"; + lblNote.Padding = new Padding(8); + lblNote.Size = new Size(446, 33); + lblNote.TabIndex = 5; + // + // txtValue + // + txtValue.BackColor = SystemColors.Window; + txtValue.DarkMode = false; + txtValue.Dock = DockStyle.Fill; + txtValue.ForeColor = SystemColors.WindowText; + txtValue.Location = new Point(110, 83); + txtValue.Margin = new Padding(16, 0, 16, 15); + txtValue.Name = "txtValue"; + txtValue.ScrollBars = ScrollBars.Vertical; + txtValue.Size = new Size(352, 25); + txtValue.TabIndex = 0; + txtValue.TextChanged += TxtValue_TextChanged; + // + // lblDescription + // + lblDescription.AutoSize = true; + lblDescription.BackColor = Color.Transparent; + lblDescription.DarkMode = false; + lblDescription.Location = new Point(106, 51); + lblDescription.Margin = new Padding(12, 0, 16, 15); + lblDescription.Name = "lblDescription"; + lblDescription.Size = new Size(61, 17); + lblDescription.TabIndex = 101; + lblDescription.Text = "[Content]"; + // + // picThumbnail + // + picThumbnail.BackColor = Color.Transparent; + picThumbnail.BackgroundImageLayout = ImageLayout.Center; + picThumbnail.Location = new Point(16, 15); + picThumbnail.Margin = new Padding(16, 0, 0, 15); + picThumbnail.MaximumSize = new Size(78, 74); + picThumbnail.Name = "picThumbnail"; + tableMain.SetRowSpan(picThumbnail, 4); + picThumbnail.Size = new Size(78, 74); + picThumbnail.TabIndex = 4; + picThumbnail.TabStop = false; + picThumbnail.Visible = false; + // + // ChkOption + // + ChkOption.AutoSize = true; + ChkOption.BackColor = Color.Transparent; + tableMain.SetColumnSpan(ChkOption, 2); + ChkOption.DarkMode = true; + ChkOption.Location = new Point(16, 179); + ChkOption.Margin = new Padding(16, 8, 16, 15); + ChkOption.Name = "ChkOption"; + ChkOption.Size = new Size(225, 21); + ChkOption.TabIndex = 1; + ChkOption.Text = "[Do not show this message again]"; + ChkOption.UseVisualStyleBackColor = false; + // + // Popup + // + AutoScaleDimensions = new SizeF(7F, 17F); + AutoScaleMode = AutoScaleMode.Font; + ClientSize = new Size(478, 325); + ControlBox = false; + Controls.Add(tableMain); + DarkMode = false; + DoubleBuffered = true; + FormBorderStyle = FormBorderStyle.FixedDialog; + Margin = new Padding(5); + Name = "Popup"; + Text = "[Title]"; + Controls.SetChildIndex(tableMain, 0); + tableMain.ResumeLayout(false); + tableMain.PerformLayout(); + ((System.ComponentModel.ISupportInitialize)picThumbnail).EndInit(); + ResumeLayout(false); + PerformLayout(); + } + + #endregion + + private TableLayoutPanel tableMain; + private ModernLabel lblDescription; + private ModernTextBox txtValue; + private PictureBox picThumbnail; + private ModernLabel lblHeading; + private ModernCheckBox ChkOption; + private ModernLabel lblNote; + } +} \ No newline at end of file diff --git a/Source/Components/ImageGlass.Settings/Forms/Popup.cs b/Source/Components/ImageGlass.Settings/Forms/Popup.cs new file mode 100644 index 000000000..66344a806 --- /dev/null +++ b/Source/Components/ImageGlass.Settings/Forms/Popup.cs @@ -0,0 +1,782 @@ +/* +ImageGlass Project - Image viewer for Windows +Copyright (C) 2010 - 2026 DUONG DIEU PHAP +Project homepage: https://imageglass.org + +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 . +*/ +using ImageGlass.Base; +using ImageGlass.Base.WinApi; +using ImageGlass.UI; +using System.ComponentModel; +using System.Globalization; +using System.Text.RegularExpressions; + +namespace ImageGlass.Settings; + + +public partial class Popup : DialogForm +{ + private bool _intValueOnly = false; + private bool _unsignedIntValueOnly = false; + private bool _floatValueOnly = false; + private bool _unsignedFloatValueOnly = false; + private ColorStatusType _noteStatusType = ColorStatusType.Neutral; + + + // Public properties + #region Public properties + + /// + /// Form title + /// + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public string Title + { + get => Text; + set + { + if (string.IsNullOrEmpty(value)) + { + Text = " "; + } + else + { + Text = value; + } + } + } + + + /// + /// Heading text + /// + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public string Heading + { + get => lblHeading.Text; + set + { + lblHeading.Text = value; + var isVisible = !string.IsNullOrEmpty(value); + var rowIndex = tableMain.GetRow(lblHeading); + + if (isVisible) + { + lblHeading.Visible = true; + tableMain.RowStyles[rowIndex].SizeType = SizeType.AutoSize; + } + else + { + lblHeading.Visible = false; + tableMain.RowStyles[rowIndex].SizeType = SizeType.Absolute; + tableMain.RowStyles[rowIndex].Height = 0; + } + } + } + + + /// + /// Description text + /// + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public string Description + { + get => lblDescription.Text; + set + { + lblDescription.Text = value; + var isVisible = !string.IsNullOrEmpty(value); + var rowIndex = tableMain.GetRow(lblDescription); + + if (isVisible) + { + lblDescription.Visible = true; + tableMain.RowStyles[rowIndex].SizeType = SizeType.AutoSize; + } + else + { + lblDescription.Visible = false; + tableMain.RowStyles[rowIndex].SizeType = SizeType.Absolute; + tableMain.RowStyles[rowIndex].Height = 0; + } + } + } + + + /// + /// Form value. + /// + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public string Value + { + get => txtValue.Text; + set => txtValue.Text = value; + } + + + /// + /// Note text. + /// + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public string Note + { + get => lblNote.Text; + set + { + lblNote.Text = value; + var isVisible = !string.IsNullOrEmpty(value); + var rowIndex = tableMain.GetRow(lblNote); + + if (isVisible) + { + lblNote.Visible = true; + tableMain.RowStyles[rowIndex].SizeType = SizeType.AutoSize; + + // need to set the following row AutoSize to make this row visible + var chkOptionRowIndex = tableMain.GetRow(ChkOption); + tableMain.RowStyles[chkOptionRowIndex].SizeType = SizeType.AutoSize; + } + else + { + lblNote.Visible = false; + tableMain.RowStyles[rowIndex].SizeType = SizeType.Absolute; + tableMain.RowStyles[rowIndex].Height = 0; + } + } + } + + + /// + /// Gets, sets the type of the note. + /// + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public ColorStatusType NoteStatusType + { + get => _noteStatusType; + set + { + _noteStatusType = value; + + lblNote.BackColor = BHelper.GetBackgroundColorForStatus(value, DarkMode); + lblNote.ForeColor = Config.Theme.ColorPalatte.AppText; + } + } + + + /// + /// Shows or hides text input. + /// + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public bool ShowTextInput + { + get => txtValue.Visible; + set => txtValue.Visible = value; + } + + + /// + /// Gets, set the value indicates that text input Multiline is enabled. + /// + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public bool TextInputMultiLine + { + get => txtValue.Multiline; + set + { + txtValue.Multiline = value; + txtValue.Font = new Font("Consolas", Font.Size); + txtValue.Height = 300; + } + } + + + /// + /// Gets, set the value indicates that text input ReadOnly is enabled. + /// + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public bool TextInputReadOnly + { + get => txtValue.ReadOnly; + set => txtValue.ReadOnly = value; + } + + + /// + /// Gets, sets check state of . + /// + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public bool OptionCheckBoxChecked + { + get => ChkOption.Checked; + set => ChkOption.Checked = value; + } + + + /// + /// Gets, sets text of the . + /// + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public string OptionCheckBoxText + { + get => ChkOption.Text; + set + { + ChkOption.Text = value; + var isVisible = !string.IsNullOrEmpty(value); + var rowIndex = tableMain.GetRow(ChkOption); + + if (isVisible) + { + ChkOption.Visible = true; + tableMain.RowStyles[rowIndex].SizeType = SizeType.AutoSize; + } + else + { + ChkOption.Visible = false; + tableMain.RowStyles[rowIndex].SizeType = SizeType.Absolute; + tableMain.RowStyles[rowIndex].Height = 0; + } + } + } + + + /// + /// Gets, sets the thumbnail overlay image. + /// + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public Image? ThumbnailOverlay + { + get => picThumbnail.Image; + set + { + if (value == null) + { + picThumbnail.Image = null; + return; + } + ; + + // draw thumbnail overlay + var bmp = new Bitmap(picThumbnail.Width, picThumbnail.Height); + var g = Graphics.FromImage(bmp); + + g.DrawImageUnscaled(value, new Point( + bmp.Width - value.Width, + bmp.Height - value.Height)); + + picThumbnail.Image = bmp; + } + } + + + /// + /// Gets, sets the thumbnail image + /// + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public Image? Thumbnail + { + get => picThumbnail.BackgroundImage; + set + { + if (value != null && picThumbnail.Width >= Math.Max(value.Width, value.Height)) + { + // image is smaller than picThumbnail + picThumbnail.BackgroundImageLayout = ImageLayout.Center; + } + else + { + // image is bigger than picThumbnail + picThumbnail.BackgroundImageLayout = ImageLayout.Zoom; + } + + picThumbnail.BackgroundImage = value; + } + } + + + /// + /// Pattern for validation + /// + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public string RegexPattern { get; set; } = string.Empty; + + + /// + /// Limit the number of characters the user can enter + /// + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public int MaxLimit + { + set => txtValue.MaxLength = value; + } + + + /// + /// Allows integer number value only + /// + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public bool IntValueOnly + { + get => _intValueOnly; + set + { + _intValueOnly = value; + + if (_intValueOnly) + { + var negativeSign = NumberFormatInfo.CurrentInfo.NegativeSign; + var positiveSign = NumberFormatInfo.CurrentInfo.PositiveSign; + + RegexPattern = $"^[{positiveSign}{negativeSign}]?[0-9]+$"; + } + } + } + + + /// + /// Allows unsigned integer number only + /// + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public bool UnsignedIntValueOnly + { + get => _unsignedIntValueOnly; + set + { + _unsignedIntValueOnly = value; + + if (_unsignedIntValueOnly) + { + RegexPattern = $"^[0-9]+$"; + } + } + } + + + /// + /// Allows float number only + /// + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public bool FloatValueOnly + { + get => _unsignedFloatValueOnly; + set + { + _unsignedFloatValueOnly = value; + + if (_unsignedFloatValueOnly) + { + var decSeparator = NumberFormatInfo.CurrentInfo.NumberDecimalSeparator; + + RegexPattern = $"^([0-9]+([{decSeparator}][0-9]*)?|[{decSeparator}][0-9]+)$"; + } + } + } + + + /// + /// Allows unsigned float number only + /// + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public bool UnsignedFloatValueOnly + { + get => _floatValueOnly; + set + { + _floatValueOnly = value; + + if (_floatValueOnly) + { + var negativeSign = NumberFormatInfo.CurrentInfo.NegativeSign; + var positiveSign = NumberFormatInfo.CurrentInfo.PositiveSign; + var decSeparator = NumberFormatInfo.CurrentInfo.NumberDecimalSeparator; + + RegexPattern = $"^[{positiveSign}{negativeSign}]?([0-9]+([{decSeparator}][0-9]*)?|[{decSeparator}][0-9]+)$"; + } + } + } + + + /// + /// Allow valid filename only + /// + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public bool FileNameValueOnly { get; set; } = false; + + + #endregion // Public properties + + + public Popup() : base() + { + InitializeComponent(); + + lblHeading.Font = new Font(lblHeading.Font.FontFamily, SystemInformation.MenuFont.SizeInPoints * 1.35f); + CloseFormHotkey = Keys.Escape; + ShowInTaskbar = false; + Heading = ""; + Description = ""; + Title = ""; + OptionCheckBoxText = ""; + Note = ""; + Thumbnail = null; // hide thumbnail by default + + ApplyLanguage(); + } + + + // Override / Virtual methods + #region Override / Virtual methods + + protected override void OnLoad(EventArgs e) + { + // show thumbnail + var showThumbnail = Thumbnail != null || ThumbnailOverlay != null; + var columnIndex = tableMain.GetColumn(picThumbnail); + + if (showThumbnail) + { + picThumbnail.Visible = true; + tableMain.ColumnStyles[columnIndex].SizeType = SizeType.AutoSize; + } + else + { + picThumbnail.Visible = false; + + tableMain.ColumnStyles[columnIndex].SizeType = SizeType.Absolute; + tableMain.ColumnStyles[columnIndex].Width = 0; + } + + base.OnLoad(e); + + ApplyTheme(Config.Theme.Settings.IsDarkMode); + } + + + protected override void OnShown(EventArgs e) + { + base.OnShown(e); + + SetFocus(); + } + + + protected override void ApplyTheme(bool darkMode, BackdropStyle? style = null) + { + SuspendLayout(); + + + lblNote.BackColor = BHelper.GetBackgroundColorForStatus(NoteStatusType, darkMode); + lblNote.ForeColor = Config.Theme.ColorPalatte.AppText; + SetTextInputStyle(ValidateInput(), darkMode); + + lblHeading.ForeColor = WinColorsApi.GetAccentColor(false) + .WithBrightness(darkMode ? 0.4f : 0f); + + tableMain.BackColor = Config.Theme.ColorPalatte.AppBg; + + + base.ApplyTheme(darkMode, style); + ResumeLayout(); + } + + + protected override void OnSystemAccentColorChanged(SystemAccentColorChangedEventArgs e) + { + base.OnSystemAccentColorChanged(e); + + // update the heading color to match system accent color + lblHeading.ForeColor = SystemAccentColorChangedEventArgs.AccentColor + .NoAlpha() + .WithBrightness(DarkMode ? 0.4f : 0f); + } + + + protected override int OnUpdateHeight(bool performUpdate = true) + { + var baseHeight = base.OnUpdateHeight(false); + + // calculate form height + var contentHeight = tableMain.Height; + var formHeight = contentHeight + baseHeight; + + if (performUpdate && Height != formHeight) + { + Height = formHeight; + } + + return formHeight; + } + + + protected override void CloseFormByKeys() + { + // Closes the form and returns code. + DialogResult = DialogResult.Abort; + + base.CloseFormByKeys(); + } + + #endregion // Override / Virtual methods + + + // Form and control events + #region Form and control events + + private void TxtValue_TextChanged(object sender, EventArgs e) + { + var isValid = ValidateInput(); + SetTextInputStyle(isValid, DarkMode); + } + + #endregion // Form and control events + + + // Private methods + #region Private methods + + /// + /// Apply language pack + /// + private void ApplyLanguage() + { + BtnAccept.Text = Config.Language["_._OK"]; + BtnCancel.Text = Config.Language["_._Cancel"]; + } + + + /// + /// Set default focus to the form + /// + private void SetFocus() + { + // set default focus + if (ShowTextInput && !TextInputReadOnly) + { + txtValue.Focus(); + txtValue.SelectAll(); + } + else + { + if (ShowAcceptButton) + { + BtnAccept.Focus(); + } + else + { + BtnCancel.Focus(); + } + } + } + + + /// + /// Validates the input and shows error. + /// + private bool ValidateInput() + { + var isValid = true; + + if (!string.IsNullOrEmpty(RegexPattern)) + { + isValid = Regex.IsMatch(txtValue.Text, RegexPattern); + } + else if (FileNameValueOnly) + { + var badChars = Path.GetInvalidFileNameChars(); + + foreach (var c in badChars) + { + if (txtValue.Text.Contains(c)) + { + isValid = false; + break; + } + } + } + + return isValid; + } + + + /// + /// Sets text input style + /// + private void SetTextInputStyle(bool isValid, bool darkMode) + { + // invalid char + if (!isValid) + { + BtnAccept.Enabled = false; + + txtValue.BackColor = BHelper.GetBackgroundColorForStatus(ColorStatusType.Danger, darkMode); + } + else + { + BtnAccept.Enabled = true; + txtValue.DarkMode = darkMode; + } + } + + #endregion // Private methods + + + // Static functions + #region Static functions + + /// + /// Shows popup widow. + /// + /// Popup theme. + /// Popup language. + /// Popup title. + /// Popup heading text. + /// Popup description. + /// Other details + /// Note text. + /// Background color of the note. + /// Popup buttons. + /// Popup icon. + /// + /// + public static PopupResult ShowDialog( + string description = "", + string title = "", + string heading = "", + string details = "", + string note = "", + ColorStatusType? noteStatusType = null, + PopupButton buttons = PopupButton.OK, + StockIconId? icon = null, + Image? thumbnail = null, + string optionText = "", + bool topMost = false, + Form? formOwner = null) + { + var sysIcon = SystemIconApi.GetSystemIcon(icon); + var hasDetails = !string.IsNullOrEmpty(details); + + using var frm = new Popup() + { + Title = title, + Heading = heading, + Description = description, + NoteStatusType = noteStatusType ?? ColorStatusType.Neutral, + + TextInputReadOnly = hasDetails, + TextInputMultiLine = hasDetails, + ShowTextInput = hasDetails, + + Thumbnail = thumbnail ?? sysIcon, + ThumbnailOverlay = (thumbnail != null && sysIcon != null) ? sysIcon : null, + ShowInTaskbar = true, + + TopMost = topMost, + }; + + if (sysIcon != null) + { + var formIconHandle = sysIcon.GetHicon(); + frm.Icon = Icon.FromHandle(formIconHandle); + + FormIconApi.SetTaskbarIcon(frm, formIconHandle); + } + + if (hasDetails) + { + frm.Value = details; + frm.Width += 200; + } + + if (!string.IsNullOrEmpty(optionText)) + { + frm.OptionCheckBoxText = optionText; + } + + if (!string.IsNullOrEmpty(note)) + { + frm.Note = note; + } + + if (buttons == PopupButton.OK_Cancel) + { + frm.AcceptButtonText = Config.Language["_._OK"]; + frm.ShowAcceptButton = true; + + frm.CancelButtonText = Config.Language["_._Cancel"]; + frm.ShowCancelButton = true; + } + else if (buttons == PopupButton.OK_Close) + { + frm.AcceptButtonText = Config.Language["_._OK"]; + frm.ShowAcceptButton = true; + + frm.CancelButtonText = Config.Language["_._Close"]; + frm.ShowCancelButton = true; + } + else if (buttons == PopupButton.Yes_No) + { + frm.AcceptButtonText = Config.Language["_._Yes"]; + frm.ShowAcceptButton = true; + + frm.CancelButtonText = Config.Language["_._No"]; + frm.ShowCancelButton = true; + } + else if (buttons == PopupButton.LearnMore_Close) + { + frm.AcceptButtonText = Config.Language["_._LearnMore"]; + frm.ShowAcceptButton = true; + + frm.CancelButtonText = Config.Language["_._Close"]; + frm.ShowCancelButton = true; + } + else if (buttons == PopupButton.Continue_Quit) + { + frm.AcceptButtonText = Config.Language["_._Continue"]; + frm.ShowAcceptButton = true; + + frm.CancelButtonText = Config.Language["_._Quit"]; + frm.ShowCancelButton = true; + } + else if (buttons == PopupButton.Close) + { + frm.ShowAcceptButton = false; + + frm.CancelButtonText = Config.Language["_._Close"]; + frm.ShowCancelButton = true; + } + else + { + frm.CancelButtonText = Config.Language["_._OK"]; + frm.ShowAcceptButton = true; + + frm.ShowCancelButton = false; + } + + var exitResult = (PopupExitResult)frm.ShowDialog(formOwner); + + + return new PopupResult() + { + ExitResult = exitResult, + Value = frm.Value, + IsOptionChecked = frm.OptionCheckBoxChecked, + }; + } + + + + #endregion + +} diff --git a/Source/Ultilities/igcmd/Properties/Resources.resx b/Source/Components/ImageGlass.Settings/Forms/Popup.resx similarity index 78% rename from Source/Ultilities/igcmd/Properties/Resources.resx rename to Source/Components/ImageGlass.Settings/Forms/Popup.resx index f39e5276d..af32865ec 100644 --- a/Source/Ultilities/igcmd/Properties/Resources.resx +++ b/Source/Components/ImageGlass.Settings/Forms/Popup.resx @@ -1,17 +1,17 @@  - @@ -117,17 +117,4 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - ..\Resources\loading.gif;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a - - - ..\Resources\ok.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a - - - ..\Resources\recommend.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a - - - ..\Resources\warning.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a - \ No newline at end of file diff --git a/Source/Components/ImageGlass.Settings/Forms/PopupEnums.cs b/Source/Components/ImageGlass.Settings/Forms/PopupEnums.cs new file mode 100644 index 000000000..947d4cf57 --- /dev/null +++ b/Source/Components/ImageGlass.Settings/Forms/PopupEnums.cs @@ -0,0 +1,79 @@ +/* +ImageGlass Project - Image viewer for Windows +Copyright (C) 2010 - 2026 DUONG DIEU PHAP +Project homepage: https://imageglass.org + +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 . +*/ +namespace ImageGlass.Settings; + +public enum PopupExitResult +{ + /// + /// Nothing is returned from the popup. This means that the modal dialog continues running. + /// + None = 0, + + /// + /// The popup return value is OK. + /// + OK = 1, + + /// + /// The popup return value is Cancel. + /// + Cancel = 2, + + /// + /// The popup return value is Abort when user closes by ESC key. + /// + Abort = 3, +} + + +/// +/// Specifies identifiers to indicate the return data of a popup. +/// +public class PopupResult +{ + /// + /// Gets the exit result of the popup + /// + public PopupExitResult ExitResult { get; internal set; } = PopupExitResult.None; + + /// + /// Gets + /// + public string Value { get; internal set; } = ""; + + /// + /// Gets the check state of the + /// + public bool IsOptionChecked { get; internal set; } = false; +} + + +/// +/// The built-in buttons for Popup. +/// +public enum PopupButton : uint +{ + OK = 0, + Close = 1, + Yes_No = 2, + OK_Cancel = 3, + OK_Close = 4, + LearnMore_Close = 5, + Continue_Quit = 6, +} diff --git a/Source/Components/ImageGlass.Settings/Forms/ThemedForm.cs b/Source/Components/ImageGlass.Settings/Forms/ThemedForm.cs new file mode 100644 index 000000000..b36d12572 --- /dev/null +++ b/Source/Components/ImageGlass.Settings/Forms/ThemedForm.cs @@ -0,0 +1,140 @@ +/* +ImageGlass Project - Image viewer for Windows +Copyright (C) 2010 - 2026 DUONG DIEU PHAP +Project homepage: https://imageglass.org + +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 . +*/ +using ImageGlass.UI; + +namespace ImageGlass.Settings; + +/// +/// Modern form with theme support. +/// +public class ThemedForm : ModernForm +{ + /// + /// Occurs when the system app color is changed and does not match the value. + /// + public event RequestUpdatingColorModeHandler? RequestUpdatingColorMode; + public delegate void RequestUpdatingColorModeHandler(SystemColorModeChangedEventArgs e); + + + /// + /// Occurs when the is requested to change. + /// + public static event RequestUpdatingThemeHandler? RequestUpdatingTheme; + public delegate void RequestUpdatingThemeHandler(RequestUpdatingThemeEventArgs e); + + + /// + /// Occurs when the is requested to change. + /// + public static event RequestUpdatingLanguageHandler? RequestUpdatingLanguage; + public delegate void RequestUpdatingLanguageHandler(); + + + public ThemedForm() : base() + { + } + + protected override void OnShown(EventArgs e) + { + base.OnShown(e); + + Config.RequestUpdatingColorMode += Config_RequestUpdatingColorMode; + Config.RequestUpdatingTheme += Config_RequestUpdatingTheme; + Config.RequestUpdatingLanguage += Config_RequestUpdatingLanguage; + } + + + private void Config_RequestUpdatingColorMode(SystemColorModeChangedEventArgs e) + { + if (InvokeRequired) + { + Invoke(Config_RequestUpdatingColorMode, e); + return; + } + + OnRequestUpdatingColorMode(e); + } + + private void Config_RequestUpdatingTheme(RequestUpdatingThemeEventArgs e) + { + if (InvokeRequired) + { + Invoke(Config_RequestUpdatingTheme, e); + return; + } + + OnRequestUpdatingTheme(e); + } + + + private void Config_RequestUpdatingLanguage() + { + if (InvokeRequired) + { + Invoke(Config_RequestUpdatingLanguage); + return; + } + + OnRequestUpdatingLanguage(); + } + + + /// + /// Triggers event. + /// + protected virtual void OnRequestUpdatingColorMode(SystemColorModeChangedEventArgs e) + { + // theme mode is changed, need to load the corresponding theme pack + Config.LoadThemePack(e.IsDarkMode, true, true, false); + + // emits the event + RequestUpdatingColorMode?.Invoke(e); + } + + + /// + /// Triggers event. + /// + protected virtual void OnRequestUpdatingTheme(RequestUpdatingThemeEventArgs e) + { + RequestUpdatingTheme?.Invoke(e); + + if (e.Handled) return; + OnDpiChanged(); + ApplyTheme(e.Theme.Settings.IsDarkMode); + } + + + /// + /// Triggers event. + /// + protected virtual void OnRequestUpdatingLanguage() + { + RequestUpdatingLanguage?.Invoke(); + } + + + protected override void OnFormClosing(FormClosingEventArgs e) + { + base.OnFormClosing(e); + + Config.RequestUpdatingColorMode -= Config_RequestUpdatingColorMode; + } + +} diff --git a/Source/Components/ImageGlass.Settings/Forms/ToolForm.Designer.cs b/Source/Components/ImageGlass.Settings/Forms/ToolForm.Designer.cs new file mode 100644 index 000000000..d80ab148f --- /dev/null +++ b/Source/Components/ImageGlass.Settings/Forms/ToolForm.Designer.cs @@ -0,0 +1,51 @@ +namespace ImageGlass.Settings +{ + partial class ToolForm + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.SuspendLayout(); + // + // ToolForm + // + this.AutoScaleDimensions = new System.Drawing.SizeF(9F, 23F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.BackdropStyle = ImageGlass.Base.BackdropStyle.MicaAlt; + this.ClientSize = new System.Drawing.Size(421, 295); + this.MaximizeBox = false; + this.MinimizeBox = false; + this.Name = "ToolForm"; + this.ShowIcon = false; + this.ShowInTaskbar = false; + this.Text = "[Tool form]"; + this.ResumeLayout(false); + + } + + #endregion + } +} \ No newline at end of file diff --git a/Source/Components/ImageGlass.Settings/Forms/ToolForm.cs b/Source/Components/ImageGlass.Settings/Forms/ToolForm.cs new file mode 100644 index 000000000..ea9572c87 --- /dev/null +++ b/Source/Components/ImageGlass.Settings/Forms/ToolForm.cs @@ -0,0 +1,404 @@ +/* +ImageGlass Project - Image viewer for Windows +Copyright (C) 2010 - 2026 DUONG DIEU PHAP +Project homepage: https://imageglass.org + +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 . +*/ +using ImageGlass.UI; +using System.ComponentModel; + +namespace ImageGlass.Settings; + + +/// +/// Common functionalities for floating tool window +/// +public partial class ToolForm : ThemedForm +{ + protected Form _currentOwner; + + + #region Public properties + + /// + /// Gets, sets the init location. + /// + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public Point InitLocation { get; set; } + + + /// + /// Occurs when the tool form is being closed. + /// + public event ToolFormClosingHandler? ToolFormClosing; + public delegate void ToolFormClosingHandler(ToolFormClosingEventArgs e); + + + /// + /// Occurs when the tool form is closed. + /// + public event ToolFormClosedHandler? ToolFormClosed; + public delegate void ToolFormClosedHandler(ToolFormClosedEventArgs e); + + #endregion // public properties + + + #region Make a tool window + + [Browsable(false)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public new Size MinimumSize => new Size(); + + + [Browsable(false)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public new Size MaximumSize => new Size(); + + + protected override bool ShowWithoutActivation => true; + + + protected override CreateParams CreateParams + { + get + { + var cp = base.CreateParams; + + const int WS_EX_NOACTIVATE = 0x08000000; + const int WS_MINIMIZEBOX = 0x20000; + + cp.ExStyle |= WS_EX_NOACTIVATE; + cp.Style ^= WS_MINIMIZEBOX; // hide Minimize box + + return cp; + } + } + + #endregion // Make a tool window + + + #region Events to manage the form location relative to parent + + private bool _isFormOwnerMoving; + protected Point OwnerPosition = Point.Empty; + protected Point FormPosition; + + private void AttachEventsToParent(ModernForm frmOwner) + { + if (DesignMode) return; + if (frmOwner is not ModernForm owner) return; + + owner.Move += Owner_Move; + owner.SizeChanged += Owner_Move; + owner.VisibleChanged += Owner_Move; + owner.LocationChanged += Owner_LocationChanged; + } + + private void Owner_LocationChanged(object? sender, EventArgs e) + { + _isFormOwnerMoving = false; + } + + private void DetachEventsFromParent(Form frmOwner) + { + if (frmOwner == null) return; + + frmOwner.Move -= Owner_Move; + frmOwner.SizeChanged -= Owner_Move; + frmOwner.VisibleChanged -= Owner_Move; + frmOwner.LocationChanged -= Owner_LocationChanged; + } + + private void Owner_Move(object? sender, EventArgs e) + { + if (Owner == null) return; + + _isFormOwnerMoving = true; + + + if (Owner.WindowState == FormWindowState.Normal) + { + SetLocationBasedOnParent(); + } + } + + // The tool windows itself has moved; track its location relative to parent + private void Form_Move(object? sender, EventArgs e) + { + if (!_isFormOwnerMoving) + { + FormPosition = new Point(Left - Owner.Left, Top - Owner.Top); + OwnerPosition = FormPosition; + } + } + + protected override void OnShown(EventArgs e) + { + if (!DesignMode && Owner != null && Owner != _currentOwner) + { + DetachEventsFromParent(_currentOwner); + _currentOwner = Owner; + AttachEventsToParent(_currentOwner as ModernForm); + } + + base.OnShown(e); + } + + #endregion + + + public ToolForm() : base() + { + InitializeComponent(); + Opacity = 0.95; + } + + + #region Override / Virtual methods + + /// + /// Recalculates and updates window height on event. + /// + protected virtual int OnUpdateHeight(bool performUpdate = true) + { + // calculate form height + var formHeight = Padding.Vertical; + + if (performUpdate) + { + Height = formHeight; + } + + return formHeight; + } + + + protected override void OnLoad(EventArgs e) + { + // adjust form size + _ = OnUpdateHeight(); + + base.OnLoad(e); + if (DesignMode) return; + + AddFormEvents(); + + EnableFormFreeMoving(this); + SetLocationBasedOnParent(InitLocation); + } + + + protected override void OnRequestUpdatingColorMode(SystemColorModeChangedEventArgs e) + { + base.OnRequestUpdatingColorMode(e); + + // update theme + ApplyTheme(Config.Theme.Settings.IsDarkMode); + Invalidate(true); + } + + + protected override void OnFormClosing(FormClosingEventArgs e) + { + base.OnFormClosing(e); + if (DesignMode) return; + + var args = new ToolFormClosingEventArgs(Name, e.CloseReason, e.Cancel); + OnToolFormClosing(args); + + DisableFormFreeMoving(this); + RemoveFormEvents(); + } + + + protected override void OnFormClosed(FormClosedEventArgs e) + { + base.OnFormClosed(e); + if (DesignMode) return; + + var args = new ToolFormClosedEventArgs(Name, e.CloseReason); + OnToolFormClosed(args); + } + + + /// + /// Raises the event. + /// + protected virtual void OnToolFormClosing(ToolFormClosingEventArgs e) + { + ToolFormClosing?.Invoke(e); + } + + + /// + /// Raises the event. + /// + protected virtual void OnToolFormClosed(ToolFormClosedEventArgs e) + { + ToolFormClosed?.Invoke(e); + } + + + /// + /// Initialize all event handlers required to manage borderless window movement. + /// + protected virtual void AddFormEvents() + { + if (DesignMode) return; + + Move += Form_Move; + + Activated += Form_Activated; + Deactivate += Form_Deactivate; + MouseEnter += Form_MouseEnter; + MouseLeave += Form_MouseLeave; + + AddFormControlsEvents(this); + } + + + /// + /// Removes all tool form events initialized by . + /// + protected virtual void RemoveFormEvents() + { + Move -= Form_Move; + + Activated -= Form_Activated; + Deactivate -= Form_Deactivate; + MouseEnter -= Form_MouseEnter; + MouseLeave -= Form_MouseLeave; + + RemoveFormControlsEvents(this); + } + + + /// + /// Sets window location to parent's location. + /// + protected virtual void SetLocationBasedOnParent(Point initLoc = default) + { + if (DesignMode || Owner == null) return; + + if (Owner.WindowState == FormWindowState.Minimized || !Owner.Visible) + { + Visible = false; + return; + } + + // set location based on the main form + var loc = Owner.Location; + loc.Offset(OwnerPosition); + + loc.X += initLoc.X; + loc.Y += initLoc.Y; + + + if (loc.X < 0) { loc.X = 0; } + if (loc.Y < 0) { loc.Y = 0; } + + var workingArea = Screen.FromControl(Owner).WorkingArea; + if (loc.X + Width > workingArea.Right) + { + loc.X = workingArea.Right - Width; + } + if (loc.Y + Height > workingArea.Bottom) + { + loc.Y = workingArea.Bottom - Height; + } + + Location = loc; + } + + #endregion // Override / Virtual methods + + + #region Private methods + + private void AddFormControlsEvents(Control c) + { + foreach (Control childControl in c.Controls) + { + childControl.MouseEnter += Form_MouseEnter; + childControl.MouseLeave += Form_MouseLeave; + + AddFormControlsEvents(childControl); + } + } + + + private void RemoveFormControlsEvents(Control c) + { + foreach (Control childControl in c.Controls) + { + childControl.MouseEnter -= Form_MouseEnter; + childControl.MouseLeave -= Form_MouseLeave; + + RemoveFormControlsEvents(childControl); + } + } + + + private void Form_MouseEnter(object? sender, EventArgs e) + { + Opacity = 1; + } + + private void Form_MouseLeave(object? sender, EventArgs e) + { + if (ActiveForm != this) + { + try + { + Opacity = 0.95; + } + catch { } + } + } + + private void Form_Activated(object? sender, EventArgs e) + { + Opacity = 1; + } + + private void Form_Deactivate(object? sender, EventArgs e) + { + try + { + Opacity = 0.95; + } + catch { } + } + + #endregion // Private methods + + +} + + +public interface IToolForm +{ + /// + /// Gets the ID of the tool. + /// + string ToolId { get; } + + + /// + /// Gets, sets settings for this tool, written in app's config file. + /// + T Settings { get; set; } + +} diff --git a/Source/Components/ImageGlass.Settings/Forms/ToolForm.resx b/Source/Components/ImageGlass.Settings/Forms/ToolForm.resx new file mode 100644 index 000000000..f298a7be8 --- /dev/null +++ b/Source/Components/ImageGlass.Settings/Forms/ToolForm.resx @@ -0,0 +1,60 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/Source/Components/ImageGlass.Settings/Forms/WebForm.Designer.cs b/Source/Components/ImageGlass.Settings/Forms/WebForm.Designer.cs new file mode 100644 index 000000000..6adb59759 --- /dev/null +++ b/Source/Components/ImageGlass.Settings/Forms/WebForm.Designer.cs @@ -0,0 +1,67 @@ +namespace ImageGlass +{ + partial class WebForm + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + Web2 = new Base.Web2(); + ((System.ComponentModel.ISupportInitialize)Web2).BeginInit(); + SuspendLayout(); + // + // Web2 + // + Web2.AccentColor = Color.Blue; + Web2.AllowExternalDrop = true; + Web2.CreationProperties = null; + Web2.DarkMode = true; + Web2.DefaultBackgroundColor = Color.Transparent; + Web2.Dock = DockStyle.Fill; + Web2.Location = new Point(0, 0); + Web2.Name = "Web2"; + Web2.PageName = "unknown"; + Web2.Size = new Size(1468, 1312); + Web2.TabIndex = 1; + Web2.ZoomFactor = 1D; + // + // WebForm + // + AutoScaleDimensions = new SizeF(18F, 45F); + AutoScaleMode = AutoScaleMode.Font; + ClientSize = new Size(1468, 1312); + Controls.Add(Web2); + MaximizeBox = false; + Name = "WebForm"; + Text = "[WebForm]"; + ((System.ComponentModel.ISupportInitialize)Web2).EndInit(); + ResumeLayout(false); + } + + #endregion + + protected Base.Web2 Web2; + } +} \ No newline at end of file diff --git a/Source/Components/ImageGlass.Settings/Forms/WebForm.cs b/Source/Components/ImageGlass.Settings/Forms/WebForm.cs new file mode 100644 index 000000000..58330a242 --- /dev/null +++ b/Source/Components/ImageGlass.Settings/Forms/WebForm.cs @@ -0,0 +1,303 @@ +/* +ImageGlass Project - Image viewer for Windows +Copyright (C) 2010 - 2026 DUONG DIEU PHAP +Project homepage: https://imageglass.org + +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 . +*/ +using ImageGlass.Base; +using ImageGlass.Settings; +using ImageGlass.UI; + +namespace ImageGlass; + +public partial class WebForm : ThemedForm +{ + /// + /// Checks if WebView2 runtime is installed. + /// + public static bool IsWebView2Installed => Web2.CheckWebview2Installed(); + + // Public events + #region Public events + + /// + /// Occurs when is ready to use. + /// + public event EventHandler Web2Ready; + + /// + /// Occurs when navigation is completed + /// + public event EventHandler Web2NavigationCompleted; + + /// + /// Occurs when receives a message from web view. + /// + public event EventHandler Web2MessageReceived; + + #endregion // Public events + + + public WebForm() + { + InitializeComponent(); + Web2.Web2Ready += Web2_Web2Ready; + Web2.Web2NavigationCompleted += Web2_Web2NavigationCompleted; + Web2.Web2MessageReceived += Web2_Web2MessageReceived; + Web2.Web2KeyDown += Web2_Web2KeyDown; + + // hide the control by default + // we will show it when the navigation is completed + Web2.Visible = false; + Web2.EnableDebug = Config.EnableDebug; + + if (IsWebView2Installed) + { + _ = Web2.EnsureWeb2Async(); + } + } + + + // Protected / override methods + #region Protected / override methods + + protected override void OnLoad(EventArgs e) + { + base.OnLoad(e); + if (DesignMode) return; + + + // show message if WebView2 runtime is not found + if (!IsWebView2Installed) + { + this.Padding = this.ScaleToDpi(new Padding(5)); + + var lnkWebView2NotFound = new ModernLinkLabel() + { + Name = "LnkWebView2NotFound", + Text = Config.Language["_._Webview2._NotFound"], + Dock = DockStyle.Top, + AutoSize = true, + TextAlign = ContentAlignment.TopLeft, + Padding = this.ScaleToDpi(new Padding(5)), + Font = new Font(this.Font.FontFamily, this.Font.Size * 1.2f), + }; + lnkWebView2NotFound.LinkClicked += LnkWebView2NotFound_LinkClicked; + + Controls.Add(lnkWebView2NotFound); + } + + _ = Config.UpdateFormIcon(this); + ApplyTheme(Config.Theme.Settings.IsDarkMode); + } + + + private void LnkWebView2NotFound_LinkClicked(object? sender, LinkLabelLinkClickedEventArgs e) + { + _ = BHelper.OpenUrlAsync("https://developer.microsoft.com/microsoft-edge/webview2"); + } + + + protected override void ApplyTheme(bool darkMode, BackdropStyle? style = null) + { + if (DesignMode) return; + + if (!EnableTransparent) + { + BackColor = Config.Theme.ColorPalatte.AppBg; + } + + Web2.DarkMode = darkMode; + Web2.AccentColor = Config.Theme.ColorPalatte.Accent; + + base.ApplyTheme(darkMode, style); + } + + + protected override void OnRequestUpdatingColorMode(SystemColorModeChangedEventArgs e) + { + base.OnRequestUpdatingColorMode(e); + + // apply theme to controls + ApplyTheme(Config.Theme.Settings.IsDarkMode); + } + + + protected override void OnSystemAccentColorChanged(SystemAccentColorChangedEventArgs e) + { + base.OnSystemAccentColorChanged(e); + _ = Web2.SetWeb2AccentColorAsync(SystemAccentColorChangedEventArgs.AccentColor); + } + + + protected override void OnRequestUpdatingTheme(RequestUpdatingThemeEventArgs e) + { + base.OnRequestUpdatingTheme(e); + _ = Web2.SetWeb2DarkModeAsync(e.Theme.Settings.IsDarkMode); + _ = SetThemeAsync(); + } + + + protected override void OnRequestUpdatingLanguage() + { + base.OnRequestUpdatingLanguage(); + + _ = LoadLanguageAsync(true); + } + + + protected override void OnWindowStateChanging(WindowStateChangedEventArgs e) + { + base.OnWindowStateChanging(e); + + if (e.State == FormWindowState.Minimized) + { + _ = Web2.TrySuspendWeb2Async(); + } + } + + + protected override void OnActivated(EventArgs e) + { + base.OnActivated(e); + _ = Web2.SetWeb2WindowFocusAsync(true); + } + + + protected override void OnDeactivate(EventArgs e) + { + base.OnDeactivate(e); + _ = Web2.SetWeb2WindowFocusAsync(false); + } + + + #endregion // Protected / override methods + + + // Virtual methods + #region Virtual methods + + /// + /// Occurs when the control is ready. + /// + protected virtual async Task OnWeb2ReadyAsync() + { + Web2Ready?.Invoke(this, EventArgs.Empty); + await Task.CompletedTask; + } + + + /// + /// Occurs when the navigation is completed. + /// + protected virtual async Task OnWeb2NavigationCompleted() + { + await Task.WhenAll([ + SetPageVariablesAsync(), + SetThemeAsync(), + LoadLanguageAsync(false), + ]); + + + Web2NavigationCompleted?.Invoke(this, EventArgs.Empty); + + // show the control when the navigation is completed + Web2.Visible = true; + } + + + /// + /// Triggers event. + /// + protected virtual async Task OnWeb2MessageReceivedAsync(Web2MessageReceivedEventArgs e) + { + Web2MessageReceived?.Invoke(this, e); + await Task.CompletedTask; + } + + #endregion // Virtual methods + + + // Web2 events + #region Web2 events + + private void Web2_Web2Ready(object? sender, EventArgs e) + { + _ = OnWeb2ReadyAsync(); + } + + private void Web2_Web2NavigationCompleted(object? sender, EventArgs e) + { + _ = OnWeb2NavigationCompleted(); + } + + private void Web2_Web2MessageReceived(object? sender, Web2MessageReceivedEventArgs e) + { + _ = OnWeb2MessageReceivedAsync(e); + } + + private void Web2_Web2KeyDown(object? sender, KeyEventArgs e) + { + if (e.KeyData == CloseFormHotkey) + { + CloseFormByKeys(); + } + else + { + this.OnKeyDown(e); + } + } + + #endregion // Web2 events + + + /// + /// Updates language + /// + public async Task LoadLanguageAsync(bool forced) + { + // get language as json string + var langJson = BHelper.ToJson(Config.Language); + + await Web2.ExecuteScriptAsync($""" + window._page.lang = {langJson}; + window._page.loadLanguage(); + """); + } + + + /// + /// Sets _page.theme to the value. + /// + public async Task SetThemeAsync() + { + await Web2.ExecuteScriptAsync($""" + window._page.theme = '{Config.Theme.FolderName}'; + """); + } + + + /// + /// Sets environment variables for _page object. + /// + public async Task SetPageVariablesAsync() + { + await Web2.ExecuteScriptAsync($""" + window._page.isWindows10 = {BHelper.IsOS(WindowsOS.Win10).ToString().ToLowerInvariant()}; + window._page.isUwpApp = {BHelper.IsRunningAsUwp().ToString().ToLowerInvariant()}; + """); + } + +} diff --git a/Source/Components/ImageGlass.Settings/Forms/WebForm.resx b/Source/Components/ImageGlass.Settings/Forms/WebForm.resx new file mode 100644 index 000000000..af32865ec --- /dev/null +++ b/Source/Components/ImageGlass.Settings/Forms/WebForm.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/Source/Components/ImageGlass.Settings/ImageGlass.Settings.csproj b/Source/Components/ImageGlass.Settings/ImageGlass.Settings.csproj index b7c5f2891..4c121784c 100644 --- a/Source/Components/ImageGlass.Settings/ImageGlass.Settings.csproj +++ b/Source/Components/ImageGlass.Settings/ImageGlass.Settings.csproj @@ -1,118 +1,104 @@ - - - - - Debug - AnyCPU - {4BAD780F-8071-4034-9020-ECC9F4352422} - Library - Properties - ImageGlass.Settings - ImageGlass.Settings - v4.7.1 - 512 - true - - - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - - - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - - - true - bin\x86\Debug\ - DEBUG;TRACE - full - x86 - 7.3 - prompt - MinimumRecommendedRules.ruleset - - - bin\x86\Release\ - TRACE - true - pdbonly - x86 - 7.3 - prompt - MinimumRecommendedRules.ruleset - - - true - bin\x64\Debug\ - DEBUG;TRACE - full - x64 - 7.3 - prompt - MinimumRecommendedRules.ruleset - - - bin\x64\Release\ - TRACE - true - pdbonly - x64 - 7.3 - prompt - MinimumRecommendedRules.ruleset - - - - - - - - - - - - - - - - - - - - - - - - - {6cc96a70-6773-41b5-9fca-4f0ab6fad8ca} - ImageGlass.Base - - - {51493b09-7a0e-461f-be18-a6cf629a8fab} - ImageGlass.Heart - - - {4bb719ed-b68b-4cb1-aaaf-ba0e3bc5fe81} - ImageGlass.Library - - - {886dc568-c83e-443e-89fa-84cf420b2c68} - ImageGlass.Services - - - {76486f88-aa16-4d7d-bbf6-0f1c604d5853} - ImageGlass.UI - - - - - \ No newline at end of file + + + + net10.0-windows10.0.17763.0 + enable + true + enable + x64;ARM64 + 9.4.0.1120 + $(Version) + Copyright © 2010 - 2026 Duong Dieu Phap + Debug;Release;Publish_Release + latest + true + true + en + + + + embedded + + + + embedded + + + + embedded + + + + embedded + + + + embedded + + + + embedded + + + + embedded + + + + embedded + + + + embedded + + + + embedded + + + + embedded + + + + embedded + + + + + + + + + + + + + + + + + + + + + + + + + + + True + True + Resources.resx + + + + + + PublicResXFileCodeGenerator + Resources.Designer.cs + + + + diff --git a/Source/Components/ImageGlass.Settings/Properties/AssemblyInfo.cs b/Source/Components/ImageGlass.Settings/Properties/AssemblyInfo.cs deleted file mode 100644 index daff22484..000000000 --- a/Source/Components/ImageGlass.Settings/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,36 +0,0 @@ -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyTitle("ImageGlass.Settings")] -[assembly: AssemblyDescription("ImageGlass settings provider")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("Duong Dieu Phap")] -[assembly: AssemblyProduct("ImageGlass.Settings")] -[assembly: AssemblyCopyright("Copyright © 2020 Duong Dieu Phap")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. -[assembly: ComVisible(false)] - -// The following GUID is for the ID of the typelib if this project is exposed to COM -[assembly: Guid("4bad780f-8071-4034-9020-ecc9f4352422")] - -// Version information for an assembly consists of the following four values: -// -// Major Version -// Minor Version -// Build Number -// Revision -// -// You can specify all the values or you can default the Build and Revision Numbers -// by using the '*' as shown below: -// [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.0.0.0")] -[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/Source/Ultilities/igcmd/Properties/Resources.Designer.cs b/Source/Components/ImageGlass.Settings/Properties/Resources.Designer.cs similarity index 56% rename from Source/Ultilities/igcmd/Properties/Resources.Designer.cs rename to Source/Components/ImageGlass.Settings/Properties/Resources.Designer.cs index 7abbd446e..f78d756dd 100644 --- a/Source/Ultilities/igcmd/Properties/Resources.Designer.cs +++ b/Source/Components/ImageGlass.Settings/Properties/Resources.Designer.cs @@ -8,7 +8,7 @@ // //------------------------------------------------------------------------------ -namespace igcmd.Properties { +namespace ImageGlass.Settings.Properties { using System; @@ -19,10 +19,10 @@ namespace igcmd.Properties { // class via a tool like ResGen or Visual Studio. // To add or remove a member, edit your .ResX file then rerun ResGen // with the /str option, or rebuild your VS project. - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "15.0.0.0")] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] - internal class Resources { + public class Resources { private static global::System.Resources.ResourceManager resourceMan; @@ -36,10 +36,10 @@ internal Resources() { /// Returns the cached ResourceManager instance used by this class. /// [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - internal static global::System.Resources.ResourceManager ResourceManager { + public static global::System.Resources.ResourceManager ResourceManager { get { if (object.ReferenceEquals(resourceMan, null)) { - global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("igcmd.Properties.Resources", typeof(Resources).Assembly); + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("ImageGlass.Settings.Properties.Resources", typeof(Resources).Assembly); resourceMan = temp; } return resourceMan; @@ -51,7 +51,7 @@ internal Resources() { /// resource lookups using this strongly typed resource class. /// [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - internal static global::System.Globalization.CultureInfo Culture { + public static global::System.Globalization.CultureInfo Culture { get { return resourceCulture; } @@ -59,45 +59,5 @@ internal Resources() { resourceCulture = value; } } - - /// - /// Looks up a localized resource of type System.Drawing.Bitmap. - /// - internal static System.Drawing.Bitmap loading { - get { - object obj = ResourceManager.GetObject("loading", resourceCulture); - return ((System.Drawing.Bitmap)(obj)); - } - } - - /// - /// Looks up a localized resource of type System.Drawing.Bitmap. - /// - internal static System.Drawing.Bitmap ok { - get { - object obj = ResourceManager.GetObject("ok", resourceCulture); - return ((System.Drawing.Bitmap)(obj)); - } - } - - /// - /// Looks up a localized resource of type System.Drawing.Bitmap. - /// - internal static System.Drawing.Bitmap recommend { - get { - object obj = ResourceManager.GetObject("recommend", resourceCulture); - return ((System.Drawing.Bitmap)(obj)); - } - } - - /// - /// Looks up a localized resource of type System.Drawing.Bitmap. - /// - internal static System.Drawing.Bitmap warning { - get { - object obj = ResourceManager.GetObject("warning", resourceCulture); - return ((System.Drawing.Bitmap)(obj)); - } - } } } diff --git a/Source/Components/ImageGlass.UI/ToolForms/ToolForm.resx b/Source/Components/ImageGlass.Settings/Properties/Resources.resx similarity index 100% rename from Source/Components/ImageGlass.UI/ToolForms/ToolForm.resx rename to Source/Components/ImageGlass.Settings/Properties/Resources.resx diff --git a/Source/Components/ImageGlass.Settings/Source.cs b/Source/Components/ImageGlass.Settings/Source.cs new file mode 100644 index 000000000..ec569d822 --- /dev/null +++ b/Source/Components/ImageGlass.Settings/Source.cs @@ -0,0 +1,167 @@ +/* +ImageGlass Project - Image viewer for Windows +Copyright (C) 2010 - 2026 DUONG DIEU PHAP +Project homepage: https://imageglass.org + +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 . +*/ +using ImageGlass.Base; +using Microsoft.Extensions.Configuration; + +namespace ImageGlass.Settings; + +public class Source +{ + #region Public properties + + /// + /// Gets the user config file name. + /// + public static string UserFilename => "igconfig.json"; + + + /// + /// Gets the default config file located. + /// + public static string DefaultFilename => "igconfig.default.json"; + + + /// + /// Gets the admin config file name. + /// + public static string AdminFilename => "igconfig.admin.json"; + + + /// + /// Config file description + /// + public static string Description => "ImageGlass configuration file"; + + + /// + /// Config file version + /// + public static float Version => 9.4f; + + + /// + /// Gets user settings from command line arguments + /// + public static string[] SettingsFromCmdLine => Environment.GetCommandLineArgs() + // filter the command lines begin with '/' + // example: ImageGlass.exe /FrmMainWidth=900 + .Where(cmd => cmd.StartsWith(Const.CONFIG_CMD_PREFIX)) + .Select(cmd => cmd[1..]) // trim '/' from the command + .ToArray(); + + #endregion + + + + #region Public methods + + /// + /// Loads all config files: default, user, command-lines, admin; + /// then unify configs. + /// + public static IConfigurationRoot LoadUserConfigs() + { + var startUpDir = App.StartUpDir(); + var configDir = App.ConfigDir(PathType.Dir); + + try + { + // igconfig.default.json + var defaultConfig = new ConfigurationBuilder() + .SetBasePath(startUpDir) + .AddJsonFile(DefaultFilename, optional: true) + .Build(); + + // admin.igconfig.json + var adminConfig = new ConfigurationBuilder() + .SetBasePath(startUpDir) + .AddJsonFile(AdminFilename, optional: true) + .Build(); + + // final config + var userConfig = new ConfigurationBuilder() + .AddConfiguration(defaultConfig) + + // igconfig.json + .SetBasePath(configDir) + .AddJsonFile(UserFilename, optional: true) + + // command line + .AddCommandLine(SettingsFromCmdLine) + + .AddConfiguration(adminConfig) + .Build(); + + return userConfig; + } + catch { } + + + // fall back to default config if user config is invalid + var fallBackConfig = new ConfigurationBuilder() + .SetBasePath(startUpDir) + .AddJsonFile(DefaultFilename, optional: true) // igconfig.default.json + .AddCommandLine(SettingsFromCmdLine) // command line + .AddJsonFile(AdminFilename, optional: true) // igconfig.admin.json + .Build(); + + return fallBackConfig; + } + + + /// + /// Loads configs, takes pre-defined settings from + /// and . + /// + public static IConfigurationRoot LoadNonUserConfigs() + { + var startUpDir = App.StartUpDir(); + + // igconfig.default.json + var defaultConfig = new ConfigurationBuilder() + .SetBasePath(startUpDir) + .AddJsonFile(DefaultFilename, optional: true) + .Build(); + + // admin.igconfig.json + var adminConfig = new ConfigurationBuilder() + .SetBasePath(startUpDir) + .AddJsonFile(AdminFilename, optional: true) + .Build(); + + // final config + var userConfig = new ConfigurationBuilder() + .AddConfiguration(defaultConfig) + .AddCommandLine(SettingsFromCmdLine) + .AddConfiguration(adminConfig) + .Build(); + + return userConfig; + } + + #endregion + +} + + +public record ConfigMetadata +{ + public string Description { get; set; } = string.Empty; + public float Version { get; set; } = 9.0f; +} diff --git a/Source/Components/ImageGlass.Settings/ToolConfigs/ColorPickerConfig.cs b/Source/Components/ImageGlass.Settings/ToolConfigs/ColorPickerConfig.cs new file mode 100644 index 000000000..17fa3d1f2 --- /dev/null +++ b/Source/Components/ImageGlass.Settings/ToolConfigs/ColorPickerConfig.cs @@ -0,0 +1,88 @@ +/* +ImageGlass Project - Image viewer for Windows +Copyright (C) 2010 - 2026 DUONG DIEU PHAP +Project homepage: https://imageglass.org + +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 . +*/ +using ImageGlass.Base; +using ImageGlass.Settings; +using ImageGlass.UI; +using System.Dynamic; + +namespace ImageGlass; + + +/// +/// Provides settings for Color Picker tool. +/// +public class ColorPickerConfig(string toolId) : IToolConfig +{ + public string ToolId { get; init; } = toolId; + + + /// + /// Shows alpha value of RGB code. + /// + public bool ShowRgbWithAlpha { get; set; } = true; + + /// + /// Shows alpha value of HEX code. + /// + public bool ShowHexWithAlpha { get; set; } = true; + + /// + /// Shows alpha value of HSL code. + /// + public bool ShowHslWithAlpha { get; set; } = true; + + /// + /// Shows alpha value of HSV code. + /// + public bool ShowHsvWithAlpha { get; set; } = true; + + /// + /// Shows alpha value of CIELAB code. + /// + public bool ShowCIELabWithAlpha { get; set; } = true; + + + public void LoadFromAppConfig() + { + var toolConfig = Config.ToolSettings.GetValue(ToolId); + if (toolConfig is not ExpandoObject config) return; + + // load configs + ShowRgbWithAlpha = config.GetValue(nameof(ShowRgbWithAlpha), ShowRgbWithAlpha); + ShowHexWithAlpha = config.GetValue(nameof(ShowHexWithAlpha), ShowHexWithAlpha); + ShowHslWithAlpha = config.GetValue(nameof(ShowHslWithAlpha), ShowHslWithAlpha); + ShowHsvWithAlpha = config.GetValue(nameof(ShowHsvWithAlpha), ShowHsvWithAlpha); + ShowCIELabWithAlpha = config.GetValue(nameof(ShowCIELabWithAlpha), ShowCIELabWithAlpha); + } + + + public void SaveToAppConfig() + { + var settings = new ExpandoObject(); + + _ = settings.TryAdd(nameof(ShowRgbWithAlpha), ShowRgbWithAlpha); + _ = settings.TryAdd(nameof(ShowHexWithAlpha), ShowHexWithAlpha); + _ = settings.TryAdd(nameof(ShowHslWithAlpha), ShowHslWithAlpha); + _ = settings.TryAdd(nameof(ShowHsvWithAlpha), ShowHsvWithAlpha); + _ = settings.TryAdd(nameof(ShowCIELabWithAlpha), ShowCIELabWithAlpha); + + // save to app config + Config.ToolSettings.Set(ToolId, settings); + } +} \ No newline at end of file diff --git a/Source/Components/ImageGlass.Settings/ToolConfigs/CropToolConfig.cs b/Source/Components/ImageGlass.Settings/ToolConfigs/CropToolConfig.cs new file mode 100644 index 000000000..2489b0342 --- /dev/null +++ b/Source/Components/ImageGlass.Settings/ToolConfigs/CropToolConfig.cs @@ -0,0 +1,172 @@ +/* +ImageGlass Project - Image viewer for Windows +Copyright (C) 2010 - 2026 DUONG DIEU PHAP +Project homepage: https://imageglass.org + +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 . +*/ +using ImageGlass.Base; +using ImageGlass.Settings; +using ImageGlass.UI; +using Microsoft.Extensions.Configuration; +using System.Dynamic; + +namespace ImageGlass; + +/// +/// Provides settings for Crop tool. +/// +public class CropToolConfig(string toolId) : IToolConfig +{ + public string ToolId { get; init; } = toolId; + + + /// + /// Gets, sets the aspect ratio type. + /// + public SelectionAspectRatio AspectRatio { get; set; } = SelectionAspectRatio.FreeRatio; + + + /// + /// Gets, sets the aspect ratio values. + /// + public int[] AspectRatioValues { get; set; } = [0, 0]; + + + /// + /// Gets, sets the option to close the Crop tool after the selected area is saved. + /// + public bool CloseToolAfterSaving { get; set; } = false; + + + /// + /// Gets, sets the default selection type. + /// + public DefaultSelectionType InitSelectionType { get; set; } = DefaultSelectionType.Select50Percent; + + + /// + /// Gets, sets the custom selection area is used for . + /// + public Rectangle InitSelectedArea { get; set; } = Rectangle.Empty; + + + /// + /// Gets, sets the option to center the . + /// + public bool AutoCenterSelection { get; set; } = true; + + + public void LoadFromAppConfig() + { + var toolConfig = Config.ToolSettings.GetValue(ToolId); + if (toolConfig is not ExpandoObject config) return; + + + // Bool configs + CloseToolAfterSaving = config.GetValue(nameof(CloseToolAfterSaving), CloseToolAfterSaving); + AutoCenterSelection = config.GetValue(nameof(AutoCenterSelection), AutoCenterSelection); + + // Enum configs + AspectRatio = config.GetValue(nameof(AspectRatio), AspectRatio); + InitSelectionType = config.GetValue(nameof(InitSelectionType), InitSelectionType); + + + #region Array configs + + // load AspectRatioValues + if (config.GetValue(nameof(AspectRatioValues)) is Array ratioValues) + { + // ratioValues can be object[] or int[] + var numArr = ratioValues + .Cast() + .Select(i => int.Parse(i.ToString())) + .ToArray(); + + if (numArr.Length == 2) + { + AspectRatioValues = [numArr[0], numArr[1]]; + } + } + + + // load SelectionArea + var bounds = config.GetValue(nameof(InitSelectedArea)) as dynamic as IEnumerable; + if (bounds != null) + { + var numArr = bounds.Select(i => int.Parse((string)i)).ToArray(); + if (numArr.Length == 4) + { + InitSelectedArea = new Rectangle(numArr[0], numArr[1], numArr[2], numArr[3]); + } + } + + #endregion // Array config + + } + + + public void SaveToAppConfig() + { + var settings = new ExpandoObject(); + + // Bool configs + _ = settings.TryAdd(nameof(CloseToolAfterSaving), CloseToolAfterSaving); + _ = settings.TryAdd(nameof(AutoCenterSelection), AutoCenterSelection); + + // Enum configs + _ = settings.TryAdd(nameof(AspectRatio), AspectRatio); + _ = settings.TryAdd(nameof(InitSelectionType), InitSelectionType); + + // Array configs + _ = settings.TryAdd(nameof(AspectRatioValues), AspectRatioValues); + _ = settings.TryAdd(nameof(InitSelectedArea), new int[] + { + InitSelectedArea.Left, + InitSelectedArea.Top, + InitSelectedArea.Width, + InitSelectedArea.Height, + }); + + + // save to app config + Config.ToolSettings.Set(ToolId, settings); + } + +} + + +/// +/// Options for Crop tool's default selection +/// +public enum DefaultSelectionType +{ + UseTheLastSelection, + CustomArea, + SelectAll, + SelectNone, + Select10Percent, + Select20Percent, + Select25Percent, + Select30Percent, + SelectOneThird, + Select40Percent, + Select50Percent, + Select60Percent, + SelectTwoThirds, + Select70Percent, + Select75Percent, + Select80Percent, + Select90Percent, +} diff --git a/Source/Components/ImageGlass.Settings/ToolConfigs/IToolConfig.cs b/Source/Components/ImageGlass.Settings/ToolConfigs/IToolConfig.cs new file mode 100644 index 000000000..7c5e221cf --- /dev/null +++ b/Source/Components/ImageGlass.Settings/ToolConfigs/IToolConfig.cs @@ -0,0 +1,42 @@ +/* +ImageGlass Project - Image viewer for Windows +Copyright (C) 2010 - 2026 DUONG DIEU PHAP +Project homepage: https://imageglass.org + +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 . +*/ +using ImageGlass.Settings; + +namespace ImageGlass.UI; + +public interface IToolConfig +{ + /// + /// Gets tool id. + /// + string ToolId { get; init; } + + + /// + /// Loads and parse tool's config from app's . + /// + void LoadFromAppConfig(); + + + /// + /// Saves the tool's config to app's . + /// + void SaveToAppConfig(); + +} diff --git a/Source/Components/ImageGlass.Settings/WebUI.cs b/Source/Components/ImageGlass.Settings/WebUI.cs new file mode 100644 index 000000000..e023fa524 --- /dev/null +++ b/Source/Components/ImageGlass.Settings/WebUI.cs @@ -0,0 +1,192 @@ +/* +ImageGlass Project - Image viewer for Windows +Copyright (C) 2010 - 2026 DUONG DIEU PHAP +Project homepage: https://imageglass.org + +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 . +*/ +using ImageGlass.Base; +using ImageGlass.Base.PhotoBox; +using ImageGlass.UI; +using System.Dynamic; + +namespace ImageGlass.Settings; + +public static class WebUI +{ + // Public properties + #region Public properties + + /// + /// Gets all SVG icons. + /// + public static Dictionary? SvgIcons { get; internal set; } = null; + + + /// + /// Gets all language packs. + /// + public static IEnumerable? LangList { get; internal set; } = null; + + + /// + /// Gets all theme packs. + /// + public static IEnumerable? ThemeList { get; internal set; } = null; + + + /// + /// Gets all enums. + /// + public static ExpandoObject Enums + { + get + { + var enumObj = new ExpandoObject(); + var enums = new Type[] { + typeof(ImageOrderBy), + typeof(ImageOrderType), + typeof(ColorProfileOption), + typeof(AfterEditAppAction), + typeof(ImageInterpolation), + typeof(MouseWheelAction), + typeof(MouseWheelEvent), + typeof(MouseClickEvent), + typeof(Base.BackdropStyle), + typeof(ToolbarItemModelType), + typeof(ImageInfoUpdateTypes), + }; + + foreach (var item in enums) + { + var keys = Enum.GetNames(item); + _ = enumObj.TryAdd(item.Name, keys); + } + + return enumObj; + } + } + + #endregion // Public properties + + + + /// + /// Updates value of . + /// + public static async Task UpdateSvgIconsAsync(bool forced = false) + { + if (SvgIcons != null && !forced) return; + + var iconNames = new Dictionary() + { + { IconName.Edit, string.Empty }, + { IconName.Delete, string.Empty }, + { IconName.ArrowUp, string.Empty }, + { IconName.ArrowDown, string.Empty }, + { IconName.ArrowLeft, string.Empty }, + { IconName.ArrowRight, string.Empty }, + { IconName.ArrowExchange, string.Empty }, + { IconName.Sun, string.Empty }, + { IconName.Moon, string.Empty }, + { IconName.Info, string.Empty }, + { IconName.Warning, string.Empty }, + }; + + + await Parallel.ForEachAsync(iconNames, + new ParallelOptions { MaxDegreeOfParallelism = 3 }, + async (item, _) => iconNames[item.Key] = await IconFile.ReadIconTextAsync(item.Key)); + + SvgIcons = iconNames; + } + + + /// + /// Updates value of . + /// + public static void UpdateLangListJson(bool forced = false) + { + if (LangList != null && !forced) return; + + LangList = Config.LoadLanguageList().Select(i => + { + var obj = new ExpandoObject(); + + _ = obj.TryAdd(nameof(i.FileName), i.FileName); + _ = obj.TryAdd(nameof(i.Metadata), i.Metadata); + + return obj; + }); + } + + + /// + /// Updates value of . + /// + public static void UpdateThemeListJson(bool forced = false) + { + if (ThemeList != null && !forced) return; + + var thList = Config.LoadThemeList(); + ThemeList = thList.Select(th => + { + th.LoadThemeColors(); + var obj = new ExpandoObject(); + + _ = obj.TryAdd(nameof(th.ConfigFilePath), th.ConfigFilePath); + _ = obj.TryAdd(nameof(th.FolderName), th.FolderName); + _ = obj.TryAdd(nameof(th.FolderPath), th.FolderPath); + _ = obj.TryAdd(nameof(th.Info), th.JsonModel.Info); + _ = obj.TryAdd(nameof(IgTheme.Colors.BgColor), th.Colors.BgColor.ToHex()); + + + // IsDarkMode + var isDarkMode = true; + if (th.JsonModel.Settings.TryGetValue(nameof(IgThemeSettings.IsDarkMode), out var darkMode)) + { + isDarkMode = !darkMode.ToString().Equals("false", StringComparison.InvariantCultureIgnoreCase); + } + _ = obj.TryAdd(nameof(IgThemeSettings.IsDarkMode), isDarkMode); + + + // PreviewImage + if (th.JsonModel.Settings.TryGetValue(nameof(th.Settings.PreviewImage), out var previewImgName)) + { + var previewImgPath = Path.Combine(th.FolderPath, previewImgName.ToString()); + var previewImgUri = new Uri(previewImgPath); + + _ = obj.TryAdd(nameof(IgThemeSettings.PreviewImage), previewImgUri.AbsoluteUri); + } + + + // Toolbar buttons icon path + var buttons = new ExpandoObject(); + foreach (var item in th.JsonModel.ToolbarIcons) + { + var iconFileUrl = th.GetToolbarIconFilePath(item.Key); + if (!string.IsNullOrWhiteSpace(iconFileUrl)) + { + iconFileUrl = new Uri(iconFileUrl).AbsoluteUri; + } + + _ = buttons.TryAdd(item.Key, iconFileUrl); + } + _ = obj.TryAdd(nameof(th.JsonModel.ToolbarIcons), buttons); + + return obj; + }); + } + +} diff --git a/Source/Components/ImageGlass.Settings/WebUI/.babelrc b/Source/Components/ImageGlass.Settings/WebUI/.babelrc new file mode 100644 index 000000000..cedf24f1a --- /dev/null +++ b/Source/Components/ImageGlass.Settings/WebUI/.babelrc @@ -0,0 +1,5 @@ +{ + "presets": [ + "@babel/preset-env" + ] +} \ No newline at end of file diff --git a/Source/Components/ImageGlass.Settings/WebUI/.eslintignore b/Source/Components/ImageGlass.Settings/WebUI/.eslintignore new file mode 100644 index 000000000..3dd8c4a3f --- /dev/null +++ b/Source/Components/ImageGlass.Settings/WebUI/.eslintignore @@ -0,0 +1,3 @@ + +# dependencies +node_modules \ No newline at end of file diff --git a/Source/Components/ImageGlass.Settings/WebUI/.eslintrc.js b/Source/Components/ImageGlass.Settings/WebUI/.eslintrc.js new file mode 100644 index 000000000..b143c7085 --- /dev/null +++ b/Source/Components/ImageGlass.Settings/WebUI/.eslintrc.js @@ -0,0 +1,63 @@ +const isProduction = process.env.NODE_ENV === 'production'; + +module.exports = { + root: true, + env: { + browser: true, + es2021: true, + }, + parser: '@typescript-eslint/parser', + parserOptions: { + ecmaVersion: 12, + sourceType: 'module', + tsconfigRootDir: './', + project: 'tsconfig.json', + }, + settings: { + // To kill annoyed React warning: + // https://github.com/DRD4-7R/eslint-config-7r-building/issues/1#issuecomment-714491844 + react: { + version: '999.999.999', + }, + }, + rules: { + 'react/jsx-filename-extension': 'off', + 'no-multiple-empty-lines': ["error", { + max: 2, + maxEOF: 1, + maxBOF: 1, + }], + '@typescript-eslint/ban-types': 'off', + '@typescript-eslint/ban-ts-comment': 'off', + '@typescript-eslint/brace-style': 'off', + '@typescript-eslint/lines-between-class-members': 'off', + '@typescript-eslint/naming-convention': 'off', + '@typescript-eslint/no-explicit-any': 'off', + 'arrow-parens': 'off', + 'brace-style': ['error', 'stroustrup', { allowSingleLine: true }], + camelcase: 'off', + 'class-methods-use-this': 'off', + 'import/extensions': 'off', + 'import/no-cycle': 'off', + 'import/no-unresolved': 'off', + 'linebreak-style': 'off', + 'lines-between-class-members': 'off', + 'max-classes-per-file': 'off', + 'no-await-in-loop': 'off', + 'no-console': [ + isProduction ? 'error' : 'warn', + { + allow: ['info', 'warn', 'error'], + }, + ], + 'no-continue': 'off', + 'no-debugger': isProduction ? 'error' : 'warn', + 'no-empty': 'off', + 'no-param-reassign': 'off', + 'no-plusplus': 'off', + 'no-restricted-globals': 'off', + // https://github.com/typescript-eslint/typescript-eslint/blob/main/docs/linting/TROUBLESHOOTING.md#i-get-errors-from-the-no-undef-rule-about-global-variables-not-being-defined-even-though-there-are-no-typescript-errors + 'no-undef': 'off', + 'prefer-object-spread': 'off', + }, +}; diff --git a/Source/Components/ImageGlass.Settings/WebUI/.gitignore b/Source/Components/ImageGlass.Settings/WebUI/.gitignore new file mode 100644 index 000000000..32c04e1a1 --- /dev/null +++ b/Source/Components/ImageGlass.Settings/WebUI/.gitignore @@ -0,0 +1,106 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +lerna-debug.log* + +# Diagnostic reports (https://nodejs.org/api/report.html) +report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json + +# Runtime data +pids +*.pid +*.seed +*.pid.lock + +# Directory for instrumented libs generated by jscoverage/JSCover +lib-cov + +# Coverage directory used by tools like istanbul +coverage +*.lcov + +# nyc test coverage +.nyc_output + +# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) +.grunt + +# Bower dependency directory (https://bower.io/) +bower_components + +# node-waf configuration +.lock-wscript + +# Compiled binary addons (https://nodejs.org/api/addons.html) +build/Release + +# Dependency directories +node_modules/ +jspm_packages/ + +# TypeScript v1 declaration files +typings/ + +# TypeScript cache +*.tsbuildinfo + +# Optional npm cache directory +.npm + +# Optional eslint cache +.eslintcache + +# Microbundle cache +.rpt2_cache/ +.rts2_cache_cjs/ +.rts2_cache_es/ +.rts2_cache_umd/ + +# Optional REPL history +.node_repl_history + +# Output of 'npm pack' +*.tgz + +# Yarn Integrity file +.yarn-integrity + +# dotenv environment variables file +.env +.env.test + +# parcel-bundler cache (https://parceljs.org/) +.cache + +# Next.js build output +.next + +# Nuxt.js build / generate output +.nuxt + +# Gatsby files +.cache/ +# Comment in the public line in if your project uses Gatsby and *not* Next.js +# https://nextjs.org/blog/next-9-1#public-directory-support +# public + +# vuepress build output +.vuepress/dist + +# Serverless directories +.serverless/ + +# FuseBox cache +.fusebox/ + +# DynamoDB Local files +.dynamodb/ + +# TernJS port file +.tern-port +.DS_Store + +dist/ diff --git a/Source/Components/ImageGlass.Settings/WebUI/.npmignore b/Source/Components/ImageGlass.Settings/WebUI/.npmignore new file mode 100644 index 000000000..7f6127ca8 --- /dev/null +++ b/Source/Components/ImageGlass.Settings/WebUI/.npmignore @@ -0,0 +1,4 @@ +# Exclude files/folders for publishing package + +demo/ +src/ diff --git a/Source/Components/ImageGlass.Settings/WebUI/.vscode/settings.json b/Source/Components/ImageGlass.Settings/WebUI/.vscode/settings.json new file mode 100644 index 000000000..1e2ec298d --- /dev/null +++ b/Source/Components/ImageGlass.Settings/WebUI/.vscode/settings.json @@ -0,0 +1,5 @@ +{ + "editor.tabSize": 2, + "javascript.preferences.quoteStyle": "single", + "typescript.preferences.quoteStyle": "single" +} \ No newline at end of file diff --git a/Source/Components/ImageGlass.Settings/WebUI/DXCanvas_Webview2.html b/Source/Components/ImageGlass.Settings/WebUI/DXCanvas_Webview2.html new file mode 100644 index 000000000..c89662e6f --- /dev/null +++ b/Source/Components/ImageGlass.Settings/WebUI/DXCanvas_Webview2.html @@ -0,0 +1,31 @@ + + + + + + + ImageGlass DXCanvas_Webview2 + + + + + + + +
+ + +
+ + + + diff --git a/Source/Components/ImageGlass.Settings/WebUI/FrmAbout.html b/Source/Components/ImageGlass.Settings/WebUI/FrmAbout.html new file mode 100644 index 000000000..72172f691 --- /dev/null +++ b/Source/Components/ImageGlass.Settings/WebUI/FrmAbout.html @@ -0,0 +1,213 @@ + + + + + + + About ImageGlass + + + + +
+ + +
+

+ ImageGlass [AppCode] +

+

[Slogan]


+ +
+

+ [Version] + [9.0.0.0] ([64-bit]) +

+ +
+ [7.00]
+ .NET Runtime: [.NET 10]
+ WebView2 Runtime: [1.0.1111] +
+
+ +

+ Copyright © [2010-2023] by Dương Diệu Pháp.
+ All rights reserved. +

+ +

+ + [Donate] + + + + [License] + + + + [Privacy] + +

+ +

+ +

+ +

+ [Thanks] +

+ + +

[Contact]

+
+ + +
+ +

[Credits]

+
+ +
+

D2Phap.DXControl

+
    +
  • Distributed under the terms of the + MIT license.
  • +
  • Copyright © 2022-2026 Dương Diệu Pháp
  • +
+ +

D2Phap.EggShell

+
    +
  • Distributed under the terms of the + Apache License 2.0.
  • +
  • Copyright © 2024-2026 Dương Diệu Pháp.
  • +
+ +

D2Phap.FileWatcher

+
    +
  • Distributed under the terms of the + MIT license.
  • +
  • Copyright © 2018-2026 Dương Diệu Pháp
  • +
+ +

Magick.NET

+
    +
  • Distributed under the terms of the + Apache License 2.0.
  • +
  • Copyright © 2013-2026 Dirk Lemstra.
  • +
+ +

PhotoSauce.MagicScaler

+
    +
  • Distributed under the terms of the + MIT license.
  • +
  • Copyright © 2015-2024 Clinton Ingram and Contributors.
  • +
+ +

WicNet

+
    +
  • Distributed under the terms of the + MIT license.
  • +
  • Copyright © 2024 Simon Mourier
  • +
+ +

DirectN

+
    +
  • Distributed under the terms of the + MIT license.
  • +
  • Copyright © 2024 Simon Mourier
  • +
+ +

ImageGlass.Gallery

+
    +
  • This software uses code of ImageListView licensed under the + Apache License 2.0.
  • +
  • Copyright © 2013 Özgür Özçıtak.
  • +
+ +

ZString

+
    +
  • Distributed under the terms of the + MIT license.
  • +
  • Copyright © 2020 Cysharp, Inc.
  • +
+ +

libwebp

+ + +

Microsoft.Web.WebView2

+ + +

Microsoft.Windows.CsWin32

+
    +
  • Distributed under the terms of the + MIT license.
  • +
  • Copyright © Microsoft Corporation
  • +
+
+
+
+
+
+ + +
+ + + +
+ + + + + + + \ No newline at end of file diff --git a/Source/Components/ImageGlass.Settings/WebUI/FrmQuickSetup.html b/Source/Components/ImageGlass.Settings/WebUI/FrmQuickSetup.html new file mode 100644 index 000000000..f6f11c0e3 --- /dev/null +++ b/Source/Components/ImageGlass.Settings/WebUI/FrmQuickSetup.html @@ -0,0 +1,111 @@ + + + + + + + Quick Setup + + + + +
+ + +
+
+
[Display language]
+
+ +
+ +
+ + + + + + +
+
+ + + + + + + \ No newline at end of file diff --git a/Source/Components/ImageGlass.Settings/WebUI/FrmSettings.html b/Source/Components/ImageGlass.Settings/WebUI/FrmSettings.html new file mode 100644 index 000000000..205eda51e --- /dev/null +++ b/Source/Components/ImageGlass.Settings/WebUI/FrmSettings.html @@ -0,0 +1,1138 @@ + + + + + + + ImageGlass settings + + + + + + + +
+ +
+ +
+
[General]
+ + + +
+ + +
+
[Startup]
+
+ +
+
+ +
+ + +
+
+ [Startup Boost] + +
+
+ + [Preload ImageGlass in the background during Windows startup to accelerate the first launch. The app will automatically exit after 3 seconds.] + +
+
+ + + + + [Open Startup apps setting] + +
+
+
+ + +
+
[Real-time file update]
+
+ +
+
+ +
+
+ + +
+
[Others]
+
+ +
+
+ +
+
+ +
+ +
+
[InAppMessageDuration]
+ +
+ + +
+
+ [Image information tags] +
+ + +
+
[Available tags:]
+
+
+
+
+
+ + + +
+ +
+
[Image loading]
+
+
+
[ImageLoadingOrder]
+ +
+
+ +
+
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+ + +
+
+ [Embedded thumbnail] +
+
+ +
+
+ +
+
+
[Minimum size of embedded + thumbnail]
+
+
+
[Width]
+ +
+
+
[Height]
+ +
+
+
+
+
+ + + +
+
[Image booster]
+
+
[ImageBoosterCacheCount]
+ +
+
+
+ [ImageBoosterCacheMaxDimension]
+ +
+
+
+ [ImageBoosterCacheMaxFileSizeInMb] +
+ +
+
+ + + +
+
[Color management]
+
+ +
+
+
+
+
[ColorProfile]
+ +
+ +
+
+ +
+ +
+
+
+ + + +
+ +
+
[Slideshow]
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+ + +
+
+ [Slideshow interval:] + +
+
+
+
+
[From]
+ +
+
+
[To]
+ +
+
+
+
+ + + +
+
+
+ [SlideshowBackgroundColor] + +
+ + + + [Reset] + +
+
+
+ + + +
+
[Slideshow notification]
+
+
+ [Number of images to trigger a notification sound] +
+ +
+
+
+ + + +
+ +
+
[Edit]
+
+ +
+
+ +
+
+ +
+
+ +
+
+
[ImageEditQuality]
+ +
+
+
[AfterEditingAction]
+ +
+
+ + +
+
[Clipboard]
+
+ +
+
+ +
+
+ + +
+
[Image editing apps]
+
+ +
+
+ + + + + + + + + + + +
[File extension][App name][Executable][Argument]
+
+
+
+ + + +
+ +
+
[Layout]
+ +
+ +
+
+ +
+
+
+
+
+ +
+
+
+ +
+
+
+ +
+
+
+
+
+
+ + + +
+
+
+
[Toolbar Position]
+ +
+
+
[Order]
+ +
+
+ +
+
+
[Contextual toolbar position]
+ +
+
+
[Order]
+ +
+
+ +
+
+
[Gallery position]
+ +
+
+
[Order]
+ +
+
+
+
+
+ + + +
+ +
+
[Viewer]
+
+ +
+
+ +
+
+ +
+
+ +
+
+
[PanSpeed]
+ +
+
+ + + +
+
[Zooming]
+ +
+
+ [Image interpolation] + + + [Learn more] + +
+
+
+ [ImageInterpolationScaleDown]
+ +
+
+
[ImageInterpolationScaleUp] +
+ +
+
+ +
+
[ZoomSpeed]
+ +
+
+
[ZoomLevels]
+
+ +
+ + +
+
+
+ + + +
+ +
+
[Toolbar]
+
+ +
+
+ +
+
+
[ToolbarIconHeight]
+ +
+
+ + +
+
[Toolbar buttons]
+
+ + +
+ +
+
+ + + +
+ +
+
[Gallery]
+
+ +
+
+ +
+
+ +
+ +
+
[ThumbnailSize]
+ +
+
+
[GalleryCacheSizeInMb]
+ +
+
+
[GalleryColumns]
+ +
+
+
+ + + +
+ +
+
[Mouse wheel action]
+
+
[Scroll]
+ +
+
+
[CtrlAndScroll]
+ +
+
+
[ShiftAndScroll]
+ +
+
+
[AltAndScroll]
+ +
+
+ +
+
+
+ + + +
+ +
+
[Keyboard]
+
+
+
+
+ + + +
+ +
+
[File extension icons]
+
+
+ [For customizing file extension icons, download an icon pack, place all .ICO files in the extension icon folder, and click the 'Make default' button. This will also set ImageGlass as default photo viewer.] +
+
+ + + [Get extension icon packs...] + +
+
+
+ + + +
+
+ [Default photo viewer] + +
+
+
+ [You can set ImageGlass as your default photo viewer using the buttons below. If necessary, open the Default apps settings to manually choose ImageGlass as the default.] +
+
+ + + + + [Open Default apps setting] + +
+
+
+ + +
+
[File formats]
+
+
+ + +
+
+ + [Total supported formats: ...] + +
+
+
+ + + + + + + + +
[File extension]
+
+
+
+ + + +
+ +
+
[Tools]
+
+
+ +
+ + [Get more tools...] + +
+
+ + + + + + + + + + + + + +
[ID][Name][Integrated][Hotkeys][Executable][Argument]
+
+
+
+ + + +
+ +
+
[Language]
+
+
[Display language]
+
+ + +
+
+ + + +
+ + +
+
[Contributors]
+
+ [Duong Dieu Phap] +
+
+
+ + + +
+ +
+
[Appearance]
+
+
[WindowBackdrop]
+ +
+
+
+
+ [BackgroundColor] + +
+ + + + [Reset] + +
+
+
+ + +
+
[Theme]
+ + + +
+
+ + + +
+ + + [Get more theme packs...] + +
+ +
    +
    +
    + + + + + + +
    + + +
    + + + +
    + + + + + + \ No newline at end of file diff --git a/Source/Components/ImageGlass.Settings/WebUI/FrmUpdate.html b/Source/Components/ImageGlass.Settings/WebUI/FrmUpdate.html new file mode 100644 index 000000000..1572c81f9 --- /dev/null +++ b/Source/Components/ImageGlass.Settings/WebUI/FrmUpdate.html @@ -0,0 +1,77 @@ + + + + + + + Check for update + + + + +
    + + +
    +

    + [Checking for update…] + [You are using the latest version!] + [A new update is available!] +

    + +

    +

    + + [Current version:] + [9.0.0.0] + +
    +
    + + [Latest version:] + [9.0.0.0] + +
    +
    + + [Published date:] + [2023/01/01] + +
    +

    + +

    + +

    + + +

    + + [ReleaseTitle] + +

    +
    + + [ReleaseDetails] + +
    +
    +
    +
    + + +
    + + +
    + + + + + \ No newline at end of file diff --git a/Source/Components/ImageGlass.Settings/WebUI/img/MsStoreBadge.svg b/Source/Components/ImageGlass.Settings/WebUI/img/MsStoreBadge.svg new file mode 100644 index 000000000..7a8ccb5af --- /dev/null +++ b/Source/Components/ImageGlass.Settings/WebUI/img/MsStoreBadge.svg @@ -0,0 +1,142 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Source/Components/ImageGlass.Settings/WebUI/package-lock.json b/Source/Components/ImageGlass.Settings/WebUI/package-lock.json new file mode 100644 index 000000000..86d77f7b7 --- /dev/null +++ b/Source/Components/ImageGlass.Settings/WebUI/package-lock.json @@ -0,0 +1,6119 @@ +{ + "name": "ig-ui", + "version": "9.4.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "ig-ui", + "version": "9.4.0", + "license": "MIT", + "dependencies": { + "lodash.merge": "^4.6.2" + }, + "devDependencies": { + "@babel/core": "^7.28.5", + "@babel/preset-env": "^7.28.5", + "@types/lodash.merge": "^4.6.9", + "@typescript-eslint/eslint-plugin": "^8.46.4", + "@typescript-eslint/parser": "^8.46.4", + "babel-loader": "^10.0.0", + "clean-webpack-plugin": "^4.0.0", + "copy-webpack-plugin": "^13.0.1", + "css-loader": "^7.1.2", + "eslint": "^9.39.1", + "eslint-webpack-plugin": "^5.0.2", + "sass": "^1.94.0", + "sass-loader": "^16.0.6", + "style-loader": "^4.0.0", + "ts-loader": "^9.5.4", + "tsconfig-paths-webpack-plugin": "^4.2.0", + "typescript": "^5.9.3", + "webpack": "^5.102.1", + "webpack-cli": "^6.0.1", + "webpack-utf8-bom": "^1.4.0" + } + }, + "node_modules/@aashutoshrathi/word-wrap": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz", + "integrity": "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz", + "integrity": "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.27.1", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.28.5.tgz", + "integrity": "sha512-6uFXyCayocRbqhZOB+6XcuZbkMNimwfVGFji8CTZnCzOHVGvDqzvitu1re2AU5LROliz7eQPhB8CpAMvnx9EjA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.5.tgz", + "integrity": "sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.27.1", + "@babel/generator": "^7.28.5", + "@babel/helper-compilation-targets": "^7.27.2", + "@babel/helper-module-transforms": "^7.28.3", + "@babel/helpers": "^7.28.4", + "@babel/parser": "^7.28.5", + "@babel/template": "^7.27.2", + "@babel/traverse": "^7.28.5", + "@babel/types": "^7.28.5", + "@jridgewell/remapping": "^2.3.5", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/generator": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.28.5.tgz", + "integrity": "sha512-3EwLFhZ38J4VyIP6WNtt2kUdW9dokXA9Cr4IVIFHuCpZ3H8/YFOl5JjZHisrn1fATPBmKKqXzDFvh9fUwHz6CQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.28.5", + "@babel/types": "^7.28.5", + "@jridgewell/gen-mapping": "^0.3.12", + "@jridgewell/trace-mapping": "^0.3.28", + "jsesc": "^3.0.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-annotate-as-pure": { + "version": "7.27.3", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.27.3.tgz", + "integrity": "sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.27.3" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.27.2", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.27.2.tgz", + "integrity": "sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.27.2", + "@babel/helper-validator-option": "^7.27.1", + "browserslist": "^4.24.0", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets/node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/@babel/helper-compilation-targets/node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true, + "license": "ISC" + }, + "node_modules/@babel/helper-create-class-features-plugin": { + "version": "7.28.3", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.28.3.tgz", + "integrity": "sha512-V9f6ZFIYSLNEbuGA/92uOvYsGCJNsuA8ESZ4ldc09bWk/j8H8TKiPw8Mk1eG6olpnO0ALHJmYfZvF4MEE4gajg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.27.3", + "@babel/helper-member-expression-to-functions": "^7.27.1", + "@babel/helper-optimise-call-expression": "^7.27.1", + "@babel/helper-replace-supers": "^7.27.1", + "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", + "@babel/traverse": "^7.28.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-create-regexp-features-plugin": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.27.1.tgz", + "integrity": "sha512-uVDC72XVf8UbrH5qQTc18Agb8emwjTiZrQE11Nv3CuBEZmVvTwwE9CBUEvHku06gQCAyYf8Nv6ja1IN+6LMbxQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.27.1", + "regexpu-core": "^6.2.0", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-define-polyfill-provider": { + "version": "0.6.5", + "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.6.5.tgz", + "integrity": "sha512-uJnGFcPsWQK8fvjgGP5LZUZZsYGIoPeRjSF5PGwrelYgq7Q15/Ft9NGFp1zglwgIv//W0uG4BevRuSJRyylZPg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-compilation-targets": "^7.27.2", + "@babel/helper-plugin-utils": "^7.27.1", + "debug": "^4.4.1", + "lodash.debounce": "^4.0.8", + "resolve": "^1.22.10" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/@babel/helper-globals": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz", + "integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-member-expression-to-functions": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.27.1.tgz", + "integrity": "sha512-E5chM8eWjTp/aNoVpcbfM7mLxu9XGLWYise2eBKGQomAk/Mb4XoxyqXTZbuTohbsl8EKqdlMhnDI2CCLfcs9wA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.27.1", + "@babel/types": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.27.1.tgz", + "integrity": "sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.27.1", + "@babel/types": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.28.3", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.3.tgz", + "integrity": "sha512-gytXUbs8k2sXS9PnQptz5o0QnpLL51SwASIORY6XaBKF88nsOT0Zw9szLqlSGQDP/4TljBAD5y98p2U1fqkdsw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.27.1", + "@babel/helper-validator-identifier": "^7.27.1", + "@babel/traverse": "^7.28.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-optimise-call-expression": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.27.1.tgz", + "integrity": "sha512-URMGH08NzYFhubNSGJrpUEphGKQwMQYBySzat5cAByY1/YgIRkULnIy3tAMeszlL/so2HbeilYloUmSpd7GdVw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.27.1.tgz", + "integrity": "sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-remap-async-to-generator": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.27.1.tgz", + "integrity": "sha512-7fiA521aVw8lSPeI4ZOD3vRFkoqkJcS+z4hFo82bFSH/2tNd6eJ5qCVMS5OzDmZh/kaHQeBaeyxK6wljcPtveA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.27.1", + "@babel/helper-wrap-function": "^7.27.1", + "@babel/traverse": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-replace-supers": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.27.1.tgz", + "integrity": "sha512-7EHz6qDZc8RYS5ElPoShMheWvEgERonFCs7IAonWLLUTXW59DP14bCZt89/GKyreYn8g3S83m21FelHKbeDCKA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-member-expression-to-functions": "^7.27.1", + "@babel/helper-optimise-call-expression": "^7.27.1", + "@babel/traverse": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-skip-transparent-expression-wrappers": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.27.1.tgz", + "integrity": "sha512-Tub4ZKEXqbPjXgWLl2+3JpQAYBJ8+ikpQ2Ocj/q/r0LwE3UhENh7EUabyHjz2kCEsrRY83ew2DQdHluuiDQFzg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.27.1", + "@babel/types": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", + "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", + "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz", + "integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-wrap-function": { + "version": "7.28.3", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.28.3.tgz", + "integrity": "sha512-zdf983tNfLZFletc0RRXYrHrucBEg95NIFMkn6K9dbeMYnsgHaSBGcQqdsCSStG2PYwRre0Qc2NNSCXbG+xc6g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/template": "^7.27.2", + "@babel/traverse": "^7.28.3", + "@babel/types": "^7.28.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.28.4.tgz", + "integrity": "sha512-HFN59MmQXGHVyYadKLVumYsA9dBFun/ldYxipEjzA4196jpLZd8UjEEBLkbEkvfYreDqJhZxYAWFPtrfhNpj4w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/template": "^7.27.2", + "@babel/types": "^7.28.4" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.5.tgz", + "integrity": "sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.28.5" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-firefox-class-in-computed-class-key": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-firefox-class-in-computed-class-key/-/plugin-bugfix-firefox-class-in-computed-class-key-7.28.5.tgz", + "integrity": "sha512-87GDMS3tsmMSi/3bWOte1UblL+YUTFMV8SZPZ2eSEL17s74Cw/l63rR6NmGVKMYW2GYi85nE+/d6Hw5N0bEk2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/traverse": "^7.28.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-safari-class-field-initializer-scope": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-class-field-initializer-scope/-/plugin-bugfix-safari-class-field-initializer-scope-7.27.1.tgz", + "integrity": "sha512-qNeq3bCKnGgLkEXUuFry6dPlGfCdQNZbn7yUAPCInwAJHMU7THJfrBSozkcWq5sNM6RcF3S8XyQL2A52KNR9IA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.27.1.tgz", + "integrity": "sha512-g4L7OYun04N1WyqMNjldFwlfPCLVkgB54A/YCXICZYBsvJJE3kByKv9c9+R/nAfmIfjl2rKYLNyMHboYbZaWaA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.27.1.tgz", + "integrity": "sha512-oO02gcONcD5O1iTLi/6frMJBIwWEHceWGSGqrpCmEL8nogiS6J9PBlE48CaK20/Jx1LuRml9aDftLgdjXT8+Cw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", + "@babel/plugin-transform-optional-chaining": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.13.0" + } + }, + "node_modules/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": { + "version": "7.28.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly/-/plugin-bugfix-v8-static-class-fields-redefine-readonly-7.28.3.tgz", + "integrity": "sha512-b6YTX108evsvE4YgWyQ921ZAFFQm3Bn+CA3+ZXlNVnPhx+UfsVURoPjfGAPCjBgrqo30yX/C2nZGX96DxvR9Iw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/traverse": "^7.28.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-proposal-private-property-in-object": { + "version": "7.21.0-placeholder-for-preset-env.2", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.0-placeholder-for-preset-env.2.tgz", + "integrity": "sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w==", + "dev": true, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-assertions": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.27.1.tgz", + "integrity": "sha512-UT/Jrhw57xg4ILHLFnzFpPDlMbcdEicaAtjPQpbj9wa8T4r5KVWCimHcL/460g8Ht0DMxDyjsLgiWSkVjnwPFg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-attributes": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.27.1.tgz", + "integrity": "sha512-oFT0FrKHgF53f4vOsZGi2Hh3I35PfSmVs4IBFLFj4dnafP+hIWDLg3VyKmUHfLoLHlyxY4C7DGtmHuJgn+IGww==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-unicode-sets-regex": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-unicode-sets-regex/-/plugin-syntax-unicode-sets-regex-7.18.6.tgz", + "integrity": "sha512-727YkEAPwSIQTv5im8QHz3upqp92JTWhidIC81Tdx4VJYIte/VndKf1qKrfnnhPLiPghStWfvC/iFaMCQu7Nqg==", + "dev": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-transform-arrow-functions": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.27.1.tgz", + "integrity": "sha512-8Z4TGic6xW70FKThA5HYEKKyBpOOsucTOD1DjU3fZxDg+K3zBJcXMFnt/4yQiZnf5+MiOMSXQ9PaEK/Ilh1DeA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-async-generator-functions": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.28.0.tgz", + "integrity": "sha512-BEOdvX4+M765icNPZeidyADIvQ1m1gmunXufXxvRESy/jNNyfovIqUyE7MVgGBjWktCoJlzvFA1To2O4ymIO3Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-remap-async-to-generator": "^7.27.1", + "@babel/traverse": "^7.28.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-async-to-generator": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.27.1.tgz", + "integrity": "sha512-NREkZsZVJS4xmTr8qzE5y8AfIPqsdQfRuUiLRTEzb7Qii8iFWCyDKaUV2c0rCuh4ljDZ98ALHP/PetiBV2nddA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-remap-async-to-generator": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-block-scoped-functions": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.27.1.tgz", + "integrity": "sha512-cnqkuOtZLapWYZUYM5rVIdv1nXYuFVIltZ6ZJ7nIj585QsjKM5dhL2Fu/lICXZ1OyIAFc7Qy+bvDAtTXqGrlhg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-block-scoping": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.28.5.tgz", + "integrity": "sha512-45DmULpySVvmq9Pj3X9B+62Xe+DJGov27QravQJU1LLcapR6/10i+gYVAucGGJpHBp5mYxIMK4nDAT/QDLr47g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-class-properties": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.27.1.tgz", + "integrity": "sha512-D0VcalChDMtuRvJIu3U/fwWjf8ZMykz5iZsg77Nuj821vCKI3zCyRLwRdWbsuJ/uRwZhZ002QtCqIkwC/ZkvbA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-class-static-block": { + "version": "7.28.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.28.3.tgz", + "integrity": "sha512-LtPXlBbRoc4Njl/oh1CeD/3jC+atytbnf/UqLoqTDcEYGUPj022+rvfkbDYieUrSj3CaV4yHDByPE+T2HwfsJg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.28.3", + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.12.0" + } + }, + "node_modules/@babel/plugin-transform-classes": { + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.28.4.tgz", + "integrity": "sha512-cFOlhIYPBv/iBoc+KS3M6et2XPtbT2HiCRfBXWtfpc9OAyostldxIf9YAYB6ypURBBbx+Qv6nyrLzASfJe+hBA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.27.3", + "@babel/helper-compilation-targets": "^7.27.2", + "@babel/helper-globals": "^7.28.0", + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-replace-supers": "^7.27.1", + "@babel/traverse": "^7.28.4" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-computed-properties": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.27.1.tgz", + "integrity": "sha512-lj9PGWvMTVksbWiDT2tW68zGS/cyo4AkZ/QTp0sQT0mjPopCmrSkzxeXkznjqBxzDI6TclZhOJbBmbBLjuOZUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/template": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-destructuring": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.28.5.tgz", + "integrity": "sha512-Kl9Bc6D0zTUcFUvkNuQh4eGXPKKNDOJQXVyyM4ZAQPMveniJdxi8XMJwLo+xSoW3MIq81bD33lcUe9kZpl0MCw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/traverse": "^7.28.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-dotall-regex": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.27.1.tgz", + "integrity": "sha512-gEbkDVGRvjj7+T1ivxrfgygpT7GUd4vmODtYpbs0gZATdkX8/iSnOtZSxiZnsgm1YjTgjI6VKBGSJJevkrclzw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-duplicate-keys": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.27.1.tgz", + "integrity": "sha512-MTyJk98sHvSs+cvZ4nOauwTTG1JeonDjSGvGGUNHreGQns+Mpt6WX/dVzWBHgg+dYZhkC4X+zTDfkTU+Vy9y7Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-duplicate-named-capturing-groups-regex": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-named-capturing-groups-regex/-/plugin-transform-duplicate-named-capturing-groups-regex-7.27.1.tgz", + "integrity": "sha512-hkGcueTEzuhB30B3eJCbCYeCaaEQOmQR0AdvzpD4LoN0GXMWzzGSuRrxR2xTnCrvNbVwK9N6/jQ92GSLfiZWoQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-transform-dynamic-import": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.27.1.tgz", + "integrity": "sha512-MHzkWQcEmjzzVW9j2q8LGjwGWpG2mjwaaB0BNQwst3FIjqsg8Ct/mIZlvSPJvfi9y2AC8mi/ktxbFVL9pZ1I4A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-explicit-resource-management": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-explicit-resource-management/-/plugin-transform-explicit-resource-management-7.28.0.tgz", + "integrity": "sha512-K8nhUcn3f6iB+P3gwCv/no7OdzOZQcKchW6N389V6PD8NUWKZHzndOd9sPDVbMoBsbmjMqlB4L9fm+fEFNVlwQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/plugin-transform-destructuring": "^7.28.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-exponentiation-operator": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.28.5.tgz", + "integrity": "sha512-D4WIMaFtwa2NizOp+dnoFjRez/ClKiC2BqqImwKd1X28nqBtZEyCYJ2ozQrrzlxAFrcrjxo39S6khe9RNDlGzw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-export-namespace-from": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.27.1.tgz", + "integrity": "sha512-tQvHWSZ3/jH2xuq/vZDy0jNn+ZdXJeM8gHvX4lnJmsc3+50yPlWdZXIc5ay+umX+2/tJIqHqiEqcJvxlmIvRvQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-for-of": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.27.1.tgz", + "integrity": "sha512-BfbWFFEJFQzLCQ5N8VocnCtA8J1CLkNTe2Ms2wocj75dd6VpiqS5Z5quTYcUoo4Yq+DN0rtikODccuv7RU81sw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-function-name": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.27.1.tgz", + "integrity": "sha512-1bQeydJF9Nr1eBCMMbC+hdwmRlsv5XYOMu03YSWFwNs0HsAmtSxxF1fyuYPqemVldVyFmlCU7w8UE14LupUSZQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-compilation-targets": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/traverse": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-json-strings": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.27.1.tgz", + "integrity": "sha512-6WVLVJiTjqcQauBhn1LkICsR2H+zm62I3h9faTDKt1qP4jn2o72tSvqMwtGFKGTpojce0gJs+76eZ2uCHRZh0Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-literals": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.27.1.tgz", + "integrity": "sha512-0HCFSepIpLTkLcsi86GG3mTUzxV5jpmbv97hTETW3yzrAij8aqlD36toB1D0daVFJM8NK6GvKO0gslVQmm+zZA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-logical-assignment-operators": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.28.5.tgz", + "integrity": "sha512-axUuqnUTBuXyHGcJEVVh9pORaN6wC5bYfE7FGzPiaWa3syib9m7g+/IT/4VgCOe2Upef43PHzeAvcrVek6QuuA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-member-expression-literals": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.27.1.tgz", + "integrity": "sha512-hqoBX4dcZ1I33jCSWcXrP+1Ku7kdqXf1oeah7ooKOIiAdKQ+uqftgCFNOSzA5AMS2XIHEYeGFg4cKRCdpxzVOQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-amd": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.27.1.tgz", + "integrity": "sha512-iCsytMg/N9/oFq6n+gFTvUYDZQOMK5kEdeYxmxt91fcJGycfxVP9CnrxoliM0oumFERba2i8ZtwRUCMhvP1LnA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-transforms": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-commonjs": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.27.1.tgz", + "integrity": "sha512-OJguuwlTYlN0gBZFRPqwOGNWssZjfIUdS7HMYtN8c1KmwpwHFBwTeFZrg9XZa+DFTitWOW5iTAG7tyCUPsCCyw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-transforms": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-systemjs": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.28.5.tgz", + "integrity": "sha512-vn5Jma98LCOeBy/KpeQhXcV2WZgaRUtjwQmjoBuLNlOmkg0fB5pdvYVeWRYI69wWKwK2cD1QbMiUQnoujWvrew==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-transforms": "^7.28.3", + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-validator-identifier": "^7.28.5", + "@babel/traverse": "^7.28.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-umd": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.27.1.tgz", + "integrity": "sha512-iQBE/xC5BV1OxJbp6WG7jq9IWiD+xxlZhLrdwpPkTX3ydmXdvoCpyfJN7acaIBZaOqTfr76pgzqBJflNbeRK+w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-transforms": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-named-capturing-groups-regex": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.27.1.tgz", + "integrity": "sha512-SstR5JYy8ddZvD6MhV0tM/j16Qds4mIpJTOd1Yu9J9pJjH93bxHECF7pgtc28XvkzTD6Pxcm/0Z73Hvk7kb3Ng==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-transform-new-target": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.27.1.tgz", + "integrity": "sha512-f6PiYeqXQ05lYq3TIfIDu/MtliKUbNwkGApPUvyo6+tc7uaR4cPjPe7DFPr15Uyycg2lZU6btZ575CuQoYh7MQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-nullish-coalescing-operator": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.27.1.tgz", + "integrity": "sha512-aGZh6xMo6q9vq1JGcw58lZ1Z0+i0xB2x0XaauNIUXd6O1xXc3RwoWEBlsTQrY4KQ9Jf0s5rgD6SiNkaUdJegTA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-numeric-separator": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.27.1.tgz", + "integrity": "sha512-fdPKAcujuvEChxDBJ5c+0BTaS6revLV7CJL08e4m3de8qJfNIuCc2nc7XJYOjBoTMJeqSmwXJ0ypE14RCjLwaw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-object-rest-spread": { + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.28.4.tgz", + "integrity": "sha512-373KA2HQzKhQCYiRVIRr+3MjpCObqzDlyrM6u4I201wL8Mp2wHf7uB8GhDwis03k2ti8Zr65Zyyqs1xOxUF/Ew==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-compilation-targets": "^7.27.2", + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/plugin-transform-destructuring": "^7.28.0", + "@babel/plugin-transform-parameters": "^7.27.7", + "@babel/traverse": "^7.28.4" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-object-super": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.27.1.tgz", + "integrity": "sha512-SFy8S9plRPbIcxlJ8A6mT/CxFdJx/c04JEctz4jf8YZaVS2px34j7NXRrlGlHkN/M2gnpL37ZpGRGVFLd3l8Ng==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-replace-supers": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-optional-catch-binding": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.27.1.tgz", + "integrity": "sha512-txEAEKzYrHEX4xSZN4kJ+OfKXFVSWKB2ZxM9dpcE3wT7smwkNmXo5ORRlVzMVdJbD+Q8ILTgSD7959uj+3Dm3Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-optional-chaining": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.28.5.tgz", + "integrity": "sha512-N6fut9IZlPnjPwgiQkXNhb+cT8wQKFlJNqcZkWlcTqkcqx6/kU4ynGmLFoa4LViBSirn05YAwk+sQBbPfxtYzQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-parameters": { + "version": "7.27.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.27.7.tgz", + "integrity": "sha512-qBkYTYCb76RRxUM6CcZA5KRu8K4SM8ajzVeUgVdMVO9NN9uI/GaVmBg/WKJJGnNokV9SY8FxNOVWGXzqzUidBg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-private-methods": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.27.1.tgz", + "integrity": "sha512-10FVt+X55AjRAYI9BrdISN9/AQWHqldOeZDUoLyif1Kn05a56xVBXb8ZouL8pZ9jem8QpXaOt8TS7RHUIS+GPA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-private-property-in-object": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.27.1.tgz", + "integrity": "sha512-5J+IhqTi1XPa0DXF83jYOaARrX+41gOewWbkPyjMNRDqgOCqdffGh8L3f/Ek5utaEBZExjSAzcyjmV9SSAWObQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.27.1", + "@babel/helper-create-class-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-property-literals": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.27.1.tgz", + "integrity": "sha512-oThy3BCuCha8kDZ8ZkgOg2exvPYUlprMukKQXI1r1pJ47NCvxfkEy8vK+r/hT9nF0Aa4H1WUPZZjHTFtAhGfmQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-regenerator": { + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.28.4.tgz", + "integrity": "sha512-+ZEdQlBoRg9m2NnzvEeLgtvBMO4tkFBw5SQIUgLICgTrumLoU7lr+Oghi6km2PFj+dbUt2u1oby2w3BDO9YQnA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-regexp-modifiers": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regexp-modifiers/-/plugin-transform-regexp-modifiers-7.27.1.tgz", + "integrity": "sha512-TtEciroaiODtXvLZv4rmfMhkCv8jx3wgKpL68PuiPh2M4fvz5jhsA7697N1gMvkvr/JTF13DrFYyEbY9U7cVPA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-transform-reserved-words": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.27.1.tgz", + "integrity": "sha512-V2ABPHIJX4kC7HegLkYoDpfg9PVmuWy/i6vUM5eGK22bx4YVFD3M5F0QQnWQoDs6AGsUWTVOopBiMFQgHaSkVw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-shorthand-properties": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.27.1.tgz", + "integrity": "sha512-N/wH1vcn4oYawbJ13Y/FxcQrWk63jhfNa7jef0ih7PHSIHX2LB7GWE1rkPrOnka9kwMxb6hMl19p7lidA+EHmQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-spread": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.27.1.tgz", + "integrity": "sha512-kpb3HUqaILBJcRFVhFUs6Trdd4mkrzcGXss+6/mxUd273PfbWqSDHRzMT2234gIg2QYfAjvXLSquP1xECSg09Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-sticky-regex": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.27.1.tgz", + "integrity": "sha512-lhInBO5bi/Kowe2/aLdBAawijx+q1pQzicSgnkB6dUPc1+RC8QmJHKf2OjvU+NZWitguJHEaEmbV6VWEouT58g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-template-literals": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.27.1.tgz", + "integrity": "sha512-fBJKiV7F2DxZUkg5EtHKXQdbsbURW3DZKQUWphDum0uRP6eHGGa/He9mc0mypL680pb+e/lDIthRohlv8NCHkg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-typeof-symbol": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.27.1.tgz", + "integrity": "sha512-RiSILC+nRJM7FY5srIyc4/fGIwUhyDuuBSdWn4y6yT6gm652DpCHZjIipgn6B7MQ1ITOUnAKWixEUjQRIBIcLw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-escapes": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.27.1.tgz", + "integrity": "sha512-Ysg4v6AmF26k9vpfFuTZg8HRfVWzsh1kVfowA23y9j/Gu6dOuahdUVhkLqpObp3JIv27MLSii6noRnuKN8H0Mg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-property-regex": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.27.1.tgz", + "integrity": "sha512-uW20S39PnaTImxp39O5qFlHLS9LJEmANjMG7SxIhap8rCHqu0Ik+tLEPX5DKmHn6CsWQ7j3lix2tFOa5YtL12Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-regex": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.27.1.tgz", + "integrity": "sha512-xvINq24TRojDuyt6JGtHmkVkrfVV3FPT16uytxImLeBZqW3/H52yN+kM1MGuyPkIQxrzKwPHs5U/MP3qKyzkGw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-sets-regex": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.27.1.tgz", + "integrity": "sha512-EtkOujbc4cgvb0mlpQefi4NTPBzhSIevblFevACNLUspmrALgmEBdL/XfnyyITfd8fKBZrZys92zOWcik7j9Tw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/preset-env": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.28.5.tgz", + "integrity": "sha512-S36mOoi1Sb6Fz98fBfE+UZSpYw5mJm0NUHtIKrOuNcqeFauy1J6dIvXm2KRVKobOSaGq4t/hBXdN4HGU3wL9Wg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.28.5", + "@babel/helper-compilation-targets": "^7.27.2", + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-validator-option": "^7.27.1", + "@babel/plugin-bugfix-firefox-class-in-computed-class-key": "^7.28.5", + "@babel/plugin-bugfix-safari-class-field-initializer-scope": "^7.27.1", + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.27.1", + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.27.1", + "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "^7.28.3", + "@babel/plugin-proposal-private-property-in-object": "7.21.0-placeholder-for-preset-env.2", + "@babel/plugin-syntax-import-assertions": "^7.27.1", + "@babel/plugin-syntax-import-attributes": "^7.27.1", + "@babel/plugin-syntax-unicode-sets-regex": "^7.18.6", + "@babel/plugin-transform-arrow-functions": "^7.27.1", + "@babel/plugin-transform-async-generator-functions": "^7.28.0", + "@babel/plugin-transform-async-to-generator": "^7.27.1", + "@babel/plugin-transform-block-scoped-functions": "^7.27.1", + "@babel/plugin-transform-block-scoping": "^7.28.5", + "@babel/plugin-transform-class-properties": "^7.27.1", + "@babel/plugin-transform-class-static-block": "^7.28.3", + "@babel/plugin-transform-classes": "^7.28.4", + "@babel/plugin-transform-computed-properties": "^7.27.1", + "@babel/plugin-transform-destructuring": "^7.28.5", + "@babel/plugin-transform-dotall-regex": "^7.27.1", + "@babel/plugin-transform-duplicate-keys": "^7.27.1", + "@babel/plugin-transform-duplicate-named-capturing-groups-regex": "^7.27.1", + "@babel/plugin-transform-dynamic-import": "^7.27.1", + "@babel/plugin-transform-explicit-resource-management": "^7.28.0", + "@babel/plugin-transform-exponentiation-operator": "^7.28.5", + "@babel/plugin-transform-export-namespace-from": "^7.27.1", + "@babel/plugin-transform-for-of": "^7.27.1", + "@babel/plugin-transform-function-name": "^7.27.1", + "@babel/plugin-transform-json-strings": "^7.27.1", + "@babel/plugin-transform-literals": "^7.27.1", + "@babel/plugin-transform-logical-assignment-operators": "^7.28.5", + "@babel/plugin-transform-member-expression-literals": "^7.27.1", + "@babel/plugin-transform-modules-amd": "^7.27.1", + "@babel/plugin-transform-modules-commonjs": "^7.27.1", + "@babel/plugin-transform-modules-systemjs": "^7.28.5", + "@babel/plugin-transform-modules-umd": "^7.27.1", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.27.1", + "@babel/plugin-transform-new-target": "^7.27.1", + "@babel/plugin-transform-nullish-coalescing-operator": "^7.27.1", + "@babel/plugin-transform-numeric-separator": "^7.27.1", + "@babel/plugin-transform-object-rest-spread": "^7.28.4", + "@babel/plugin-transform-object-super": "^7.27.1", + "@babel/plugin-transform-optional-catch-binding": "^7.27.1", + "@babel/plugin-transform-optional-chaining": "^7.28.5", + "@babel/plugin-transform-parameters": "^7.27.7", + "@babel/plugin-transform-private-methods": "^7.27.1", + "@babel/plugin-transform-private-property-in-object": "^7.27.1", + "@babel/plugin-transform-property-literals": "^7.27.1", + "@babel/plugin-transform-regenerator": "^7.28.4", + "@babel/plugin-transform-regexp-modifiers": "^7.27.1", + "@babel/plugin-transform-reserved-words": "^7.27.1", + "@babel/plugin-transform-shorthand-properties": "^7.27.1", + "@babel/plugin-transform-spread": "^7.27.1", + "@babel/plugin-transform-sticky-regex": "^7.27.1", + "@babel/plugin-transform-template-literals": "^7.27.1", + "@babel/plugin-transform-typeof-symbol": "^7.27.1", + "@babel/plugin-transform-unicode-escapes": "^7.27.1", + "@babel/plugin-transform-unicode-property-regex": "^7.27.1", + "@babel/plugin-transform-unicode-regex": "^7.27.1", + "@babel/plugin-transform-unicode-sets-regex": "^7.27.1", + "@babel/preset-modules": "0.1.6-no-external-plugins", + "babel-plugin-polyfill-corejs2": "^0.4.14", + "babel-plugin-polyfill-corejs3": "^0.13.0", + "babel-plugin-polyfill-regenerator": "^0.6.5", + "core-js-compat": "^3.43.0", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/preset-modules": { + "version": "0.1.6-no-external-plugins", + "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.6-no-external-plugins.tgz", + "integrity": "sha512-HrcgcIESLm9aIR842yhJ5RWan/gebQUJ6E/E5+rf0y9o6oj7w0Br+sWuL6kEQ/o/AdfvR1Je9jG18/gnpwjEyA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/types": "^7.4.4", + "esutils": "^2.0.2" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/@babel/template": { + "version": "7.27.2", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.2.tgz", + "integrity": "sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.27.1", + "@babel/parser": "^7.27.2", + "@babel/types": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.28.5.tgz", + "integrity": "sha512-TCCj4t55U90khlYkVV/0TfkJkAkUg3jZFA3Neb7unZT8CPok7iiRfaX0F+WnqWqt7OxhOn0uBKXCw4lbL8W0aQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.27.1", + "@babel/generator": "^7.28.5", + "@babel/helper-globals": "^7.28.0", + "@babel/parser": "^7.28.5", + "@babel/template": "^7.27.2", + "@babel/types": "^7.28.5", + "debug": "^4.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.5.tgz", + "integrity": "sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.27.1", + "@babel/helper-validator-identifier": "^7.28.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@discoveryjs/json-ext": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.6.3.tgz", + "integrity": "sha512-4B4OijXeVNOPZlYA2oEwWOTkzyltLao+xbotHQeqN++Rv27Y6s818+n2Qkp8q+Fxhn0t/5lA5X1Mxktud8eayQ==", + "dev": true, + "engines": { + "node": ">=14.17.0" + } + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.8.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.8.0.tgz", + "integrity": "sha512-MJQFqrZgcW0UNYLGOuQpey/oTN59vyWwplvCGZztn1cKz9agZPPYpJB7h2OMmuu7VLqkvEjN8feFZJmxNF9D+Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.1.tgz", + "integrity": "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==", + "dev": true, + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/config-array": { + "version": "0.21.1", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.21.1.tgz", + "integrity": "sha512-aw1gNayWpdI/jSYVgzN5pL0cfzU02GT3NBpeT/DXbx1/1x7ZKxFPd9bwrzygx/qiwIQiJ1sw/zD8qY/kRvlGHA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/object-schema": "^2.1.7", + "debug": "^4.3.1", + "minimatch": "^3.1.2" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/config-helpers": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.4.2.tgz", + "integrity": "sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^0.17.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/core": { + "version": "0.17.0", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.17.0.tgz", + "integrity": "sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@types/json-schema": "^7.0.15" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.1.tgz", + "integrity": "sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^10.0.1", + "globals": "^14.0.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/eslintrc/node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/@eslint/js": { + "version": "9.39.1", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.39.1.tgz", + "integrity": "sha512-S26Stp4zCy88tH94QbBv3XCuzRQiZ9yXofEILmglYTh/Ug/a9/umqvgFtYBAo3Lp0nsI/5/qH1CCrbdK3AP1Tw==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + } + }, + "node_modules/@eslint/object-schema": { + "version": "2.1.7", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.7.tgz", + "integrity": "sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/plugin-kit": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.4.1.tgz", + "integrity": "sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^0.17.0", + "levn": "^0.4.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@humanfs/core": { + "version": "0.19.1", + "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", + "integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==", + "dev": true, + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/node": { + "version": "0.16.6", + "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.6.tgz", + "integrity": "sha512-YuI2ZHQL78Q5HbhDiBA1X4LmYdXCKCMQIfw0pw7piHJwyREFebJUvrQN4cMssyES6x+vfUbx1CIpaQUKYdQZOw==", + "dev": true, + "dependencies": { + "@humanfs/core": "^0.19.1", + "@humanwhocodes/retry": "^0.3.0" + }, + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/node/node_modules/@humanwhocodes/retry": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.3.1.tgz", + "integrity": "sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA==", + "dev": true, + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/retry": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.2.tgz", + "integrity": "sha512-xeO57FpIu4p1Ri3Jq/EXq4ClRm86dVF2z/+kvFnyqVYRavTZmaFaUBbWCOuuTh0o/g7DSsk6kc2vrS4Vl5oPOQ==", + "dev": true, + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@jest/schemas": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz", + "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==", + "dev": true, + "dependencies": { + "@sinclair/typebox": "^0.27.8" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/types": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", + "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", + "dev": true, + "dependencies": { + "@jest/schemas": "^29.6.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/types/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@jest/types/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@jest/types/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/@jest/types/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/@jest/types/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/remapping": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", + "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", + "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/source-map": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.6.tgz", + "integrity": "sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ==", + "dev": true, + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "dev": true, + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.30", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.30.tgz", + "integrity": "sha512-GQ7Nw5G2lTu/BtHTKfXhKHok2WGetd4XYcVKGx00SjAk8GMwgJM3zr6zORiPGuOE+/vkc90KtTosSSvaCjKb2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@parcel/watcher": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher/-/watcher-2.4.1.tgz", + "integrity": "sha512-HNjmfLQEVRZmHRET336f20H/8kOozUGwk7yajvsonjNxbj2wBTK1WsQuHkD5yYh9RxFGL2EyDHryOihOwUoKDA==", + "dev": true, + "optional": true, + "dependencies": { + "detect-libc": "^1.0.3", + "is-glob": "^4.0.3", + "micromatch": "^4.0.5", + "node-addon-api": "^7.0.0" + }, + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "@parcel/watcher-android-arm64": "2.4.1", + "@parcel/watcher-darwin-arm64": "2.4.1", + "@parcel/watcher-darwin-x64": "2.4.1", + "@parcel/watcher-freebsd-x64": "2.4.1", + "@parcel/watcher-linux-arm-glibc": "2.4.1", + "@parcel/watcher-linux-arm64-glibc": "2.4.1", + "@parcel/watcher-linux-arm64-musl": "2.4.1", + "@parcel/watcher-linux-x64-glibc": "2.4.1", + "@parcel/watcher-linux-x64-musl": "2.4.1", + "@parcel/watcher-win32-arm64": "2.4.1", + "@parcel/watcher-win32-ia32": "2.4.1", + "@parcel/watcher-win32-x64": "2.4.1" + } + }, + "node_modules/@parcel/watcher-android-arm64": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-android-arm64/-/watcher-android-arm64-2.4.1.tgz", + "integrity": "sha512-LOi/WTbbh3aTn2RYddrO8pnapixAziFl6SMxHM69r3tvdSm94JtCenaKgk1GRg5FJ5wpMCpHeW+7yqPlvZv7kg==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-darwin-arm64": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-arm64/-/watcher-darwin-arm64-2.4.1.tgz", + "integrity": "sha512-ln41eihm5YXIY043vBrrHfn94SIBlqOWmoROhsMVTSXGh0QahKGy77tfEywQ7v3NywyxBBkGIfrWRHm0hsKtzA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-darwin-x64": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-x64/-/watcher-darwin-x64-2.4.1.tgz", + "integrity": "sha512-yrw81BRLjjtHyDu7J61oPuSoeYWR3lDElcPGJyOvIXmor6DEo7/G2u1o7I38cwlcoBHQFULqF6nesIX3tsEXMg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-freebsd-x64": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-freebsd-x64/-/watcher-freebsd-x64-2.4.1.tgz", + "integrity": "sha512-TJa3Pex/gX3CWIx/Co8k+ykNdDCLx+TuZj3f3h7eOjgpdKM+Mnix37RYsYU4LHhiYJz3DK5nFCCra81p6g050w==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm-glibc": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-glibc/-/watcher-linux-arm-glibc-2.4.1.tgz", + "integrity": "sha512-4rVYDlsMEYfa537BRXxJ5UF4ddNwnr2/1O4MHM5PjI9cvV2qymvhwZSFgXqbS8YoTk5i/JR0L0JDs69BUn45YA==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm64-glibc": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-glibc/-/watcher-linux-arm64-glibc-2.4.1.tgz", + "integrity": "sha512-BJ7mH985OADVLpbrzCLgrJ3TOpiZggE9FMblfO65PlOCdG++xJpKUJ0Aol74ZUIYfb8WsRlUdgrZxKkz3zXWYA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm64-musl": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-musl/-/watcher-linux-arm64-musl-2.4.1.tgz", + "integrity": "sha512-p4Xb7JGq3MLgAfYhslU2SjoV9G0kI0Xry0kuxeG/41UfpjHGOhv7UoUDAz/jb1u2elbhazy4rRBL8PegPJFBhA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-x64-glibc": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-glibc/-/watcher-linux-x64-glibc-2.4.1.tgz", + "integrity": "sha512-s9O3fByZ/2pyYDPoLM6zt92yu6P4E39a03zvO0qCHOTjxmt3GHRMLuRZEWhWLASTMSrrnVNWdVI/+pUElJBBBg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-x64-musl": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-musl/-/watcher-linux-x64-musl-2.4.1.tgz", + "integrity": "sha512-L2nZTYR1myLNST0O632g0Dx9LyMNHrn6TOt76sYxWLdff3cB22/GZX2UPtJnaqQPdCRoszoY5rcOj4oMTtp5fQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-win32-arm64": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-arm64/-/watcher-win32-arm64-2.4.1.tgz", + "integrity": "sha512-Uq2BPp5GWhrq/lcuItCHoqxjULU1QYEcyjSO5jqqOK8RNFDBQnenMMx4gAl3v8GiWa59E9+uDM7yZ6LxwUIfRg==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-win32-ia32": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-ia32/-/watcher-win32-ia32-2.4.1.tgz", + "integrity": "sha512-maNRit5QQV2kgHFSYwftmPBxiuK5u4DXjbXx7q6eKjq5dsLXZ4FJiVvlcw35QXzk0KrUecJmuVFbj4uV9oYrcw==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-win32-x64": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-x64/-/watcher-win32-x64-2.4.1.tgz", + "integrity": "sha512-+DvS92F9ezicfswqrvIRM2njcYJbd5mb9CUgtrHCHmvn7pPPa+nMDRu1o1bYYz/l5IB2NVGNJWiH7h1E58IF2A==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@sinclair/typebox": { + "version": "0.27.8", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", + "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==", + "dev": true + }, + "node_modules/@types/eslint": { + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-9.6.1.tgz", + "integrity": "sha512-FXx2pKgId/WyYo2jXw63kk7/+TY7u7AziEJxJAnSFzHlqTAS3Ync6SvgYAN/k4/PQpnnVuzoMuVnByKK2qp0ag==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "*", + "@types/json-schema": "*" + } + }, + "node_modules/@types/eslint-scope": { + "version": "3.7.7", + "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.7.tgz", + "integrity": "sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==", + "dev": true, + "dependencies": { + "@types/eslint": "*", + "@types/estree": "*" + } + }, + "node_modules/@types/estree": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", + "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/glob": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.1.3.tgz", + "integrity": "sha512-SEYeGAIQIQX8NN6LDKprLjbrd5dARM5EXsd8GI/A5l0apYI1fGMWgPHSe4ZKL4eozlAyI+doUE9XbYS4xCkQ1w==", + "dev": true, + "dependencies": { + "@types/minimatch": "*", + "@types/node": "*" + } + }, + "node_modules/@types/istanbul-lib-coverage": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz", + "integrity": "sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==", + "dev": true + }, + "node_modules/@types/istanbul-lib-report": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.3.tgz", + "integrity": "sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==", + "dev": true, + "dependencies": { + "@types/istanbul-lib-coverage": "*" + } + }, + "node_modules/@types/istanbul-reports": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.4.tgz", + "integrity": "sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==", + "dev": true, + "dependencies": { + "@types/istanbul-lib-report": "*" + } + }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true + }, + "node_modules/@types/lodash": { + "version": "4.14.195", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.195.tgz", + "integrity": "sha512-Hwx9EUgdwf2GLarOjQp5ZH8ZmblzcbTBC2wtQWNKARBSxM9ezRIAUpeDTgoQRAFB0+8CNWXVA9+MaSOzOF3nPg==", + "dev": true + }, + "node_modules/@types/lodash.merge": { + "version": "4.6.9", + "resolved": "https://registry.npmjs.org/@types/lodash.merge/-/lodash.merge-4.6.9.tgz", + "integrity": "sha512-23sHDPmzd59kUgWyKGiOMO2Qb9YtqRO/x4IhkgNUiPQ1+5MUVqi6bCZeq9nBJ17msjIMbEIO5u+XW4Kz6aGUhQ==", + "dev": true, + "dependencies": { + "@types/lodash": "*" + } + }, + "node_modules/@types/minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-1z8k4wzFnNjVK/tlxvrWuK5WMt6mydWWP7+zvH5eFep4oj+UkrfiJTRtjCeBXNpwaA/FYqqtb4/QS4ianFpIRA==", + "dev": true + }, + "node_modules/@types/node": { + "version": "15.0.2", + "resolved": "https://registry.npmjs.org/@types/node/-/node-15.0.2.tgz", + "integrity": "sha512-p68+a+KoxpoB47015IeYZYRrdqMUcpbK8re/zpFB8Ld46LHC1lPEbp3EXgkEhAYEcPvjJF6ZO+869SQ0aH1dcA==", + "dev": true + }, + "node_modules/@types/yargs": { + "version": "17.0.32", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.32.tgz", + "integrity": "sha512-xQ67Yc/laOG5uMfX/093MRlGGCIBzZMarVa+gfNKJxWAIgykYpVGkBdbqEzGDDfCrVUj6Hiff4mTZ5BA6TmAog==", + "dev": true, + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/@types/yargs-parser": { + "version": "21.0.3", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.3.tgz", + "integrity": "sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==", + "dev": true + }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "8.46.4", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.46.4.tgz", + "integrity": "sha512-R48VhmTJqplNyDxCyqqVkFSZIx1qX6PzwqgcXn1olLrzxcSBDlOsbtcnQuQhNtnNiJ4Xe5gREI1foajYaYU2Vg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/regexpp": "^4.10.0", + "@typescript-eslint/scope-manager": "8.46.4", + "@typescript-eslint/type-utils": "8.46.4", + "@typescript-eslint/utils": "8.46.4", + "@typescript-eslint/visitor-keys": "8.46.4", + "graphemer": "^1.4.0", + "ignore": "^7.0.0", + "natural-compare": "^1.4.0", + "ts-api-utils": "^2.1.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^8.46.4", + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/parser": { + "version": "8.46.4", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.46.4.tgz", + "integrity": "sha512-tK3GPFWbirvNgsNKto+UmB/cRtn6TZfyw0D6IKrW55n6Vbs7KJoZtI//kpTKzE/DUmmnAFD8/Ca46s7Obs92/w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/scope-manager": "8.46.4", + "@typescript-eslint/types": "8.46.4", + "@typescript-eslint/typescript-estree": "8.46.4", + "@typescript-eslint/visitor-keys": "8.46.4", + "debug": "^4.3.4" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/project-service": { + "version": "8.46.4", + "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.46.4.tgz", + "integrity": "sha512-nPiRSKuvtTN+no/2N1kt2tUh/HoFzeEgOm9fQ6XQk4/ApGqjx0zFIIaLJ6wooR1HIoozvj2j6vTi/1fgAz7UYQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/tsconfig-utils": "^8.46.4", + "@typescript-eslint/types": "^8.46.4", + "debug": "^4.3.4" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "8.46.4", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.46.4.tgz", + "integrity": "sha512-tMDbLGXb1wC+McN1M6QeDx7P7c0UWO5z9CXqp7J8E+xGcJuUuevWKxuG8j41FoweS3+L41SkyKKkia16jpX7CA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.46.4", + "@typescript-eslint/visitor-keys": "8.46.4" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/tsconfig-utils": { + "version": "8.46.4", + "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.46.4.tgz", + "integrity": "sha512-+/XqaZPIAk6Cjg7NWgSGe27X4zMGqrFqZ8atJsX3CWxH/jACqWnrWI68h7nHQld0y+k9eTTjb9r+KU4twLoo9A==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "8.46.4", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.46.4.tgz", + "integrity": "sha512-V4QC8h3fdT5Wro6vANk6eojqfbv5bpwHuMsBcJUJkqs2z5XnYhJzyz9Y02eUmF9u3PgXEUiOt4w4KHR3P+z0PQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.46.4", + "@typescript-eslint/typescript-estree": "8.46.4", + "@typescript-eslint/utils": "8.46.4", + "debug": "^4.3.4", + "ts-api-utils": "^2.1.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/types": { + "version": "8.46.4", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.46.4.tgz", + "integrity": "sha512-USjyxm3gQEePdUwJBFjjGNG18xY9A2grDVGuk7/9AkjIF1L+ZrVnwR5VAU5JXtUnBL/Nwt3H31KlRDaksnM7/w==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "8.46.4", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.46.4.tgz", + "integrity": "sha512-7oV2qEOr1d4NWNmpXLR35LvCfOkTNymY9oyW+lUHkmCno7aOmIf/hMaydnJBUTBMRCOGZh8YjkFOc8dadEoNGA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/project-service": "8.46.4", + "@typescript-eslint/tsconfig-utils": "8.46.4", + "@typescript-eslint/types": "8.46.4", + "@typescript-eslint/visitor-keys": "8.46.4", + "debug": "^4.3.4", + "fast-glob": "^3.3.2", + "is-glob": "^4.0.3", + "minimatch": "^9.0.4", + "semver": "^7.6.0", + "ts-api-utils": "^2.1.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/semver": { + "version": "7.7.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", + "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@typescript-eslint/utils": { + "version": "8.46.4", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.46.4.tgz", + "integrity": "sha512-AbSv11fklGXV6T28dp2Me04Uw90R2iJ30g2bgLz529Koehrmkbs1r7paFqr1vPCZi7hHwYxYtxfyQMRC8QaVSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.7.0", + "@typescript-eslint/scope-manager": "8.46.4", + "@typescript-eslint/types": "8.46.4", + "@typescript-eslint/typescript-estree": "8.46.4" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "8.46.4", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.46.4.tgz", + "integrity": "sha512-/++5CYLQqsO9HFGLI7APrxBJYo+5OCMpViuhV8q5/Qa3o5mMrF//eQHks+PXcsAVaLdn817fMuS7zqoXNNZGaw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.46.4", + "eslint-visitor-keys": "^4.2.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/visitor-keys/node_modules/eslint-visitor-keys": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", + "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@webassemblyjs/ast": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.14.1.tgz", + "integrity": "sha512-nuBEDgQfm1ccRp/8bCQrx1frohyufl4JlbMMZ4P1wpeOfDhF6FQkxZJ1b/e+PLwr6X1Nhw6OLme5usuBWYBvuQ==", + "dev": true, + "dependencies": { + "@webassemblyjs/helper-numbers": "1.13.2", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2" + } + }, + "node_modules/@webassemblyjs/floating-point-hex-parser": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.13.2.tgz", + "integrity": "sha512-6oXyTOzbKxGH4steLbLNOu71Oj+C8Lg34n6CqRvqfS2O71BxY6ByfMDRhBytzknj9yGUPVJ1qIKhRlAwO1AovA==", + "dev": true + }, + "node_modules/@webassemblyjs/helper-api-error": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.13.2.tgz", + "integrity": "sha512-U56GMYxy4ZQCbDZd6JuvvNV/WFildOjsaWD3Tzzvmw/mas3cXzRJPMjP83JqEsgSbyrmaGjBfDtV7KDXV9UzFQ==", + "dev": true + }, + "node_modules/@webassemblyjs/helper-buffer": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.14.1.tgz", + "integrity": "sha512-jyH7wtcHiKssDtFPRB+iQdxlDf96m0E39yb0k5uJVhFGleZFoNw1c4aeIcVUPPbXUVJ94wwnMOAqUHyzoEPVMA==", + "dev": true + }, + "node_modules/@webassemblyjs/helper-numbers": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.13.2.tgz", + "integrity": "sha512-FE8aCmS5Q6eQYcV3gI35O4J789wlQA+7JrqTTpJqn5emA4U2hvwJmvFRC0HODS+3Ye6WioDklgd6scJ3+PLnEA==", + "dev": true, + "dependencies": { + "@webassemblyjs/floating-point-hex-parser": "1.13.2", + "@webassemblyjs/helper-api-error": "1.13.2", + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webassemblyjs/helper-wasm-bytecode": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.13.2.tgz", + "integrity": "sha512-3QbLKy93F0EAIXLh0ogEVR6rOubA9AoZ+WRYhNbFyuB70j3dRdwH9g+qXhLAO0kiYGlg3TxDV+I4rQTr/YNXkA==", + "dev": true + }, + "node_modules/@webassemblyjs/helper-wasm-section": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.14.1.tgz", + "integrity": "sha512-ds5mXEqTJ6oxRoqjhWDU83OgzAYjwsCV8Lo/N+oRsNDmx/ZDpqalmrtgOMkHwxsG0iI//3BwWAErYRHtgn0dZw==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-buffer": "1.14.1", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2", + "@webassemblyjs/wasm-gen": "1.14.1" + } + }, + "node_modules/@webassemblyjs/ieee754": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.13.2.tgz", + "integrity": "sha512-4LtOzh58S/5lX4ITKxnAK2USuNEvpdVV9AlgGQb8rJDHaLeHciwG4zlGr0j/SNWlr7x3vO1lDEsuePvtcDNCkw==", + "dev": true, + "dependencies": { + "@xtuc/ieee754": "^1.2.0" + } + }, + "node_modules/@webassemblyjs/leb128": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.13.2.tgz", + "integrity": "sha512-Lde1oNoIdzVzdkNEAWZ1dZ5orIbff80YPdHx20mrHwHrVNNTjNr8E3xz9BdpcGqRQbAEa+fkrCb+fRFTl/6sQw==", + "dev": true, + "dependencies": { + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webassemblyjs/utf8": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.13.2.tgz", + "integrity": "sha512-3NQWGjKTASY1xV5m7Hr0iPeXD9+RDobLll3T9d2AO+g3my8xy5peVyjSag4I50mR1bBSN/Ct12lo+R9tJk0NZQ==", + "dev": true + }, + "node_modules/@webassemblyjs/wasm-edit": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.14.1.tgz", + "integrity": "sha512-RNJUIQH/J8iA/1NzlE4N7KtyZNHi3w7at7hDjvRNm5rcUXa00z1vRz3glZoULfJ5mpvYhLybmVcwcjGrC1pRrQ==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-buffer": "1.14.1", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2", + "@webassemblyjs/helper-wasm-section": "1.14.1", + "@webassemblyjs/wasm-gen": "1.14.1", + "@webassemblyjs/wasm-opt": "1.14.1", + "@webassemblyjs/wasm-parser": "1.14.1", + "@webassemblyjs/wast-printer": "1.14.1" + } + }, + "node_modules/@webassemblyjs/wasm-gen": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.14.1.tgz", + "integrity": "sha512-AmomSIjP8ZbfGQhumkNvgC33AY7qtMCXnN6bL2u2Js4gVCg8fp735aEiMSBbDR7UQIj90n4wKAFUSEd0QN2Ukg==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2", + "@webassemblyjs/ieee754": "1.13.2", + "@webassemblyjs/leb128": "1.13.2", + "@webassemblyjs/utf8": "1.13.2" + } + }, + "node_modules/@webassemblyjs/wasm-opt": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.14.1.tgz", + "integrity": "sha512-PTcKLUNvBqnY2U6E5bdOQcSM+oVP/PmrDY9NzowJjislEjwP/C4an2303MCVS2Mg9d3AJpIGdUFIQQWbPds0Sw==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-buffer": "1.14.1", + "@webassemblyjs/wasm-gen": "1.14.1", + "@webassemblyjs/wasm-parser": "1.14.1" + } + }, + "node_modules/@webassemblyjs/wasm-parser": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.14.1.tgz", + "integrity": "sha512-JLBl+KZ0R5qB7mCnud/yyX08jWFw5MsoalJ1pQ4EdFlgj9VdXKGuENGsiCIjegI1W7p91rUlcB/LB5yRJKNTcQ==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-api-error": "1.13.2", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2", + "@webassemblyjs/ieee754": "1.13.2", + "@webassemblyjs/leb128": "1.13.2", + "@webassemblyjs/utf8": "1.13.2" + } + }, + "node_modules/@webassemblyjs/wast-printer": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.14.1.tgz", + "integrity": "sha512-kPSSXE6De1XOR820C90RIo2ogvZG+c3KiHzqUoO/F34Y2shGzesfqv7o57xrxovZJH/MetF5UjroJ/R/3isoiw==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.14.1", + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webpack-cli/configtest": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-3.0.1.tgz", + "integrity": "sha512-u8d0pJ5YFgneF/GuvEiDA61Tf1VDomHHYMjv/wc9XzYj7nopltpG96nXN5dJRstxZhcNpV1g+nT6CydO7pHbjA==", + "dev": true, + "engines": { + "node": ">=18.12.0" + }, + "peerDependencies": { + "webpack": "^5.82.0", + "webpack-cli": "6.x.x" + } + }, + "node_modules/@webpack-cli/info": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@webpack-cli/info/-/info-3.0.1.tgz", + "integrity": "sha512-coEmDzc2u/ffMvuW9aCjoRzNSPDl/XLuhPdlFRpT9tZHmJ/039az33CE7uH+8s0uL1j5ZNtfdv0HkfaKRBGJsQ==", + "dev": true, + "engines": { + "node": ">=18.12.0" + }, + "peerDependencies": { + "webpack": "^5.82.0", + "webpack-cli": "6.x.x" + } + }, + "node_modules/@webpack-cli/serve": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-3.0.1.tgz", + "integrity": "sha512-sbgw03xQaCLiT6gcY/6u3qBDn01CWw/nbaXl3gTdTFuJJ75Gffv3E3DBpgvY2fkkrdS1fpjaXNOmJlnbtKauKg==", + "dev": true, + "engines": { + "node": ">=18.12.0" + }, + "peerDependencies": { + "webpack": "^5.82.0", + "webpack-cli": "6.x.x" + }, + "peerDependenciesMeta": { + "webpack-dev-server": { + "optional": true + } + } + }, + "node_modules/@xtuc/ieee754": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", + "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==", + "dev": true + }, + "node_modules/@xtuc/long": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", + "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", + "dev": true + }, + "node_modules/acorn": { + "version": "8.15.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", + "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", + "dev": true, + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-import-phases": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/acorn-import-phases/-/acorn-import-phases-1.0.4.tgz", + "integrity": "sha512-wKmbr/DDiIXzEOiWrTTUcDm24kQ2vGfZQvM2fwg2vXqR5uW6aapr7ObPtj1th32b9u90/Pf4AItvdTh42fBmVQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10.13.0" + }, + "peerDependencies": { + "acorn": "^8.14.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ajv-formats": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", + "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", + "dev": true, + "dependencies": { + "ajv": "^8.0.0" + }, + "peerDependencies": { + "ajv": "^8.0.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } + } + }, + "node_modules/ajv-formats/node_modules/ajv": { + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", + "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ajv-formats/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true, + "license": "Python-2.0" + }, + "node_modules/array-uniq": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz", + "integrity": "sha1-r2rId6Jcx/dOBYiUdThY39sk/bY=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/babel-loader": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-10.0.0.tgz", + "integrity": "sha512-z8jt+EdS61AMw22nSfoNJAZ0vrtmhPRVi6ghL3rCeRZI8cdNYFiV5xeV3HbE7rlZZNmGH8BVccwWt8/ED0QOHA==", + "dev": true, + "dependencies": { + "find-up": "^5.0.0" + }, + "engines": { + "node": "^18.20.0 || ^20.10.0 || >=22.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.12.0", + "webpack": ">=5.61.0" + } + }, + "node_modules/babel-plugin-polyfill-corejs2": { + "version": "0.4.14", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.14.tgz", + "integrity": "sha512-Co2Y9wX854ts6U8gAAPXfn0GmAyctHuK8n0Yhfjd6t30g7yvKjspvvOo9yG+z52PZRgFErt7Ka2pYnXCjLKEpg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.27.7", + "@babel/helper-define-polyfill-provider": "^0.6.5", + "semver": "^6.3.1" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/babel-plugin-polyfill-corejs3": { + "version": "0.13.0", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.13.0.tgz", + "integrity": "sha512-U+GNwMdSFgzVmfhNm8GJUX88AadB3uo9KpJqS3FaqNIPKgySuvMb+bHPsOmmuWyIcuqZj/pzt1RUIUZns4y2+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-define-polyfill-provider": "^0.6.5", + "core-js-compat": "^3.43.0" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/babel-plugin-polyfill-regenerator": { + "version": "0.6.5", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.6.5.tgz", + "integrity": "sha512-ISqQ2frbiNU9vIJkzg7dlPpznPZ4jOiUQ1uSmB0fEHeowtN3COYRsXr/xexn64NpU13P06jc/L5TgiJXOgrbEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-define-polyfill-provider": "^0.6.5" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "node_modules/baseline-browser-mapping": { + "version": "2.8.26", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.8.26.tgz", + "integrity": "sha512-73lC1ugzwoaWCLJ1LvOgrR5xsMLTqSKIEoMHVtL9E/HNk0PXtTM76ZIm84856/SF7Nv8mPZxKoBsgpm0tR1u1Q==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "baseline-browser-mapping": "dist/cli.js" + } + }, + "node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browserslist": { + "version": "4.28.0", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.0.tgz", + "integrity": "sha512-tbydkR/CxfMwelN0vwdP/pLkDwyAASZ+VfWm4EOwlB6SWhx1sYnWLqo8N5j0rAzPfzfRaxt0mM/4wPU/Su84RQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "baseline-browser-mapping": "^2.8.25", + "caniuse-lite": "^1.0.30001754", + "electron-to-chromium": "^1.5.249", + "node-releases": "^2.0.27", + "update-browserslist-db": "^1.1.4" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "dev": true + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001754", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001754.tgz", + "integrity": "sha512-x6OeBXueoAceOmotzx3PO4Zpt4rzpeIFsSr6AAePTZxSkXiYDUmpypEl7e2+8NCd9bD7bXjqyef8CJYPC1jfxg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0" + }, + "node_modules/chokidar": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.1.tgz", + "integrity": "sha512-n8enUVCED/KVRQlab1hr3MVpcVMvxtZjmEa956u+4YijlmQED223XMSYj2tLuKvr4jcCTzNNMpQDUer72MMmzA==", + "dev": true, + "dependencies": { + "readdirp": "^4.0.1" + }, + "engines": { + "node": ">= 14.16.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/chrome-trace-event": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz", + "integrity": "sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==", + "dev": true, + "engines": { + "node": ">=6.0" + } + }, + "node_modules/ci-info": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz", + "integrity": "sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "engines": { + "node": ">=8" + } + }, + "node_modules/clean-webpack-plugin": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/clean-webpack-plugin/-/clean-webpack-plugin-4.0.0.tgz", + "integrity": "sha512-WuWE1nyTNAyW5T7oNyys2EN0cfP2fdRxhxnIQWiAp0bMabPdHhoGxM8A6YL2GhqwgrPnnaemVE7nv5XJ2Fhh2w==", + "dev": true, + "dependencies": { + "del": "^4.1.1" + }, + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "webpack": ">=4.0.0 <6.0.0" + } + }, + "node_modules/clone-deep": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", + "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", + "dev": true, + "dependencies": { + "is-plain-object": "^2.0.4", + "kind-of": "^6.0.2", + "shallow-clone": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/colorette": { + "version": "2.0.20", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", + "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", + "dev": true + }, + "node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true + }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true + }, + "node_modules/copy-webpack-plugin": { + "version": "13.0.1", + "resolved": "https://registry.npmjs.org/copy-webpack-plugin/-/copy-webpack-plugin-13.0.1.tgz", + "integrity": "sha512-J+YV3WfhY6W/Xf9h+J1znYuqTye2xkBUIGyTPWuBAT27qajBa5mR4f8WBmfDY3YjRftT2kqZZiLi1qf0H+UOFw==", + "dev": true, + "license": "MIT", + "dependencies": { + "glob-parent": "^6.0.1", + "normalize-path": "^3.0.0", + "schema-utils": "^4.2.0", + "serialize-javascript": "^6.0.2", + "tinyglobby": "^0.2.12" + }, + "engines": { + "node": ">= 18.12.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.1.0" + } + }, + "node_modules/core-js-compat": { + "version": "3.45.1", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.45.1.tgz", + "integrity": "sha512-tqTt5T4PzsMIZ430XGviK4vzYSoeNJ6CXODi6c/voxOT6IZqBht5/EKaSNnYiEjjRYxjVz7DQIsOsY0XNi8PIA==", + "dev": true, + "license": "MIT", + "dependencies": { + "browserslist": "^4.25.3" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "dev": true, + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/css-loader": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-7.1.2.tgz", + "integrity": "sha512-6WvYYn7l/XEGN8Xu2vWFt9nVzrCn39vKyTEFf/ExEyoksJjjSZV/0/35XPlMbpnr6VGhZIUg5yJrL8tGfes/FA==", + "dev": true, + "dependencies": { + "icss-utils": "^5.1.0", + "postcss": "^8.4.33", + "postcss-modules-extract-imports": "^3.1.0", + "postcss-modules-local-by-default": "^4.0.5", + "postcss-modules-scope": "^3.2.0", + "postcss-modules-values": "^4.0.0", + "postcss-value-parser": "^4.2.0", + "semver": "^7.5.4" + }, + "engines": { + "node": ">= 18.12.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "@rspack/core": "0.x || 1.x", + "webpack": "^5.27.0" + }, + "peerDependenciesMeta": { + "@rspack/core": { + "optional": true + }, + "webpack": { + "optional": true + } + } + }, + "node_modules/css-loader/node_modules/semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/cssesc": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", + "dev": true, + "bin": { + "cssesc": "bin/cssesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/debug": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz", + "integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true + }, + "node_modules/del": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/del/-/del-4.1.1.tgz", + "integrity": "sha512-QwGuEUouP2kVwQenAsOof5Fv8K9t3D8Ca8NxcXKrIpEHjTXK5J2nXLdP+ALI1cgv8wj7KuwBhTwBkOZSJKM5XQ==", + "dev": true, + "dependencies": { + "@types/glob": "^7.1.1", + "globby": "^6.1.0", + "is-path-cwd": "^2.0.0", + "is-path-in-cwd": "^2.0.0", + "p-map": "^2.0.0", + "pify": "^4.0.1", + "rimraf": "^2.6.3" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/del/node_modules/array-union": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz", + "integrity": "sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=", + "dev": true, + "dependencies": { + "array-uniq": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/del/node_modules/globby": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-6.1.0.tgz", + "integrity": "sha1-9abXDoOV4hyFj7BInWTfAkJNUGw=", + "dev": true, + "dependencies": { + "array-union": "^1.0.1", + "glob": "^7.0.3", + "object-assign": "^4.0.1", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/del/node_modules/globby/node_modules/pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/detect-libc": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", + "integrity": "sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==", + "dev": true, + "optional": true, + "bin": { + "detect-libc": "bin/detect-libc.js" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/electron-to-chromium": { + "version": "1.5.250", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.250.tgz", + "integrity": "sha512-/5UMj9IiGDMOFBnN4i7/Ry5onJrAGSbOGo3s9FEKmwobGq6xw832ccET0CE3CkkMBZ8GJSlUIesZofpyurqDXw==", + "dev": true, + "license": "ISC" + }, + "node_modules/enhanced-resolve": { + "version": "5.18.3", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.18.3.tgz", + "integrity": "sha512-d4lC8xfavMeBjzGr2vECC3fsGXziXZQyJxD868h2M/mBI3PwAuODxAkLkq5HYuvrPYcUtiLzsTo8U3PgX3Ocww==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.4", + "tapable": "^2.2.0" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/envinfo": { + "version": "7.14.0", + "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.14.0.tgz", + "integrity": "sha512-CO40UI41xDQzhLB1hWyqUKgFhs250pNcGbyGKe1l/e4FSaI/+YE4IMG76GDt0In67WLPACIITC+sOi08x4wIvg==", + "dev": true, + "bin": { + "envinfo": "dist/cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/es-module-lexer": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.2.1.tgz", + "integrity": "sha512-9978wrXM50Y4rTMmW5kXIC09ZdXQZqkE4mxhwkd8VbzsGkXGPgV4zWuqQJgCEzYngdo2dYDa0l8xhX4fkSwJSg==", + "dev": true + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/eslint": { + "version": "9.39.1", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.39.1.tgz", + "integrity": "sha512-BhHmn2yNOFA9H9JmmIVKJmd288g9hrVRDkdoIgRCRuSySRUHH7r/DI6aAXW9T1WwUuY3DFgrcaqB+deURBLR5g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.8.0", + "@eslint-community/regexpp": "^4.12.1", + "@eslint/config-array": "^0.21.1", + "@eslint/config-helpers": "^0.4.2", + "@eslint/core": "^0.17.0", + "@eslint/eslintrc": "^3.3.1", + "@eslint/js": "9.39.1", + "@eslint/plugin-kit": "^0.4.1", + "@humanfs/node": "^0.16.6", + "@humanwhocodes/module-importer": "^1.0.1", + "@humanwhocodes/retry": "^0.4.2", + "@types/estree": "^1.0.6", + "ajv": "^6.12.4", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.6", + "debug": "^4.3.2", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^8.4.0", + "eslint-visitor-keys": "^4.2.1", + "espree": "^10.4.0", + "esquery": "^1.5.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^8.0.0", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "jiti": "*" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + } + } + }, + "node_modules/eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-webpack-plugin": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/eslint-webpack-plugin/-/eslint-webpack-plugin-5.0.2.tgz", + "integrity": "sha512-cB7EO2o+4gPUzK6zxgegSet8uu/hHwzOiG+2976MHWiwWFj9mmPbTrzlW0InFl6hl89S1D9MPKK5F7vNFpZc4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/eslint": "^9.6.1", + "flatted": "^3.3.3", + "jest-worker": "^29.7.0", + "micromatch": "^4.0.8", + "normalize-path": "^3.0.0", + "schema-utils": "^4.3.0" + }, + "engines": { + "node": ">= 18.12.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "eslint": "^8.0.0 || ^9.0.0", + "webpack": "^5.0.0" + } + }, + "node_modules/eslint/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/eslint/node_modules/chalk": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", + "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/eslint/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/eslint/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/eslint/node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/eslint-scope": { + "version": "8.4.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.4.0.tgz", + "integrity": "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/eslint-visitor-keys": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", + "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/eslint/node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/eslint/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/espree": { + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz", + "integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "acorn": "^8.15.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^4.2.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/espree/node_modules/eslint-visitor-keys": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", + "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esquery": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", + "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", + "dev": true, + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esquery/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esrecurse/node_modules/estraverse": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", + "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "dev": true, + "engines": { + "node": ">=0.8.x" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, + "node_modules/fast-glob": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", + "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.8" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-glob/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true + }, + "node_modules/fastest-levenshtein": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.12.tgz", + "integrity": "sha512-On2N+BpYJ15xIC974QNVuYGMOlEVt4s0EOI3wwMqOmK1fdDY+FN/zltPV8vosq4ad4c/gJ1KHScUn/6AWIgiow==", + "dev": true + }, + "node_modules/fastq": { + "version": "1.19.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.19.1.tgz", + "integrity": "sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/file-entry-cache": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", + "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", + "dev": true, + "dependencies": { + "flat-cache": "^4.0.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", + "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", + "dev": true, + "bin": { + "flat": "cli.js" + } + }, + "node_modules/flat-cache": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", + "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", + "dev": true, + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.4" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/flatted": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz", + "integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==", + "dev": true, + "license": "ISC" + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "dev": true + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/glob": { + "version": "7.1.7", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.7.tgz", + "integrity": "sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/glob-to-regexp": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", + "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", + "dev": true, + "license": "BSD-2-Clause" + }, + "node_modules/globals": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", + "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true + }, + "node_modules/graphemer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", + "dev": true + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/icss-utils": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-5.1.0.tgz", + "integrity": "sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==", + "dev": true, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/ignore": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz", + "integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/immutable": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-5.0.3.tgz", + "integrity": "sha512-P8IdPQHq3lA1xVeBRi5VPqUm5HDgKnx0Ru51wZz5mjxHr5n3RWhjIpOFU7ybkUxfB+5IToy+OLaHYDBIWsv+uw==", + "dev": true + }, + "node_modules/import-fresh": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", + "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/import-local": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.0.2.tgz", + "integrity": "sha512-vjL3+w0oulAVZ0hBHnxa/Nm5TAurf9YLQJDhqRZyqb+VKGOB6LU8t9H1Nr5CIo16vh9XfJTOoHwU0B71S557gA==", + "dev": true, + "dependencies": { + "pkg-dir": "^4.2.0", + "resolve-cwd": "^3.0.0" + }, + "bin": { + "import-local-fixture": "fixtures/cli.js" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", + "dev": true, + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dev": true, + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "node_modules/interpret": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-3.1.1.tgz", + "integrity": "sha512-6xwYfHbajpoF0xLW+iwLkhwgvLoZDfjYfoFNu8ftMoXINzwuymNLd9u/KmwtdT2GbR+/Cz66otEGEVVUHX9QLQ==", + "dev": true, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/is-core-module": { + "version": "2.16.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", + "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", + "dev": true, + "license": "MIT", + "dependencies": { + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-path-cwd": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-2.2.0.tgz", + "integrity": "sha512-w942bTcih8fdJPJmQHFzkS76NEP8Kzzvmw92cXsazb8intwLqPibPPdXf4ANdKV3rYMuuQYGIWtvz9JilB3NFQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/is-path-in-cwd": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-path-in-cwd/-/is-path-in-cwd-2.1.0.tgz", + "integrity": "sha512-rNocXHgipO+rvnP6dk3zI20RpOtrAM/kzbB258Uw5BWr3TpXi861yzjo16Dn4hUox07iw5AyeMLHWsujkjzvRQ==", + "dev": true, + "dependencies": { + "is-path-inside": "^2.1.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/is-path-inside": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-2.1.0.tgz", + "integrity": "sha512-wiyhTzfDWsvwAW53OBWF5zuvaOGlZ6PwYxAbPVDhpm+gM09xKQGjBq/8uYN12aDvMxnAnq3dxTyoSoRNmg5YFg==", + "dev": true, + "dependencies": { + "path-is-inside": "^1.0.2" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "dev": true + }, + "node_modules/isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/jest-util": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.7.0.tgz", + "integrity": "sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==", + "dev": true, + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-util/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-util/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-util/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/jest-util/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/jest-util/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-worker": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.7.0.tgz", + "integrity": "sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==", + "dev": true, + "dependencies": { + "@types/node": "*", + "jest-util": "^29.7.0", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsesc": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.0.2.tgz", + "integrity": "sha512-xKqzzWXDttJuOcawBt4KnKHHIf5oQ/Cxax+0PWFG+DFDgHNAdi+TXECADI+RYiFUMmx8792xsMbbgXj4CwnP4g==", + "dev": true, + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true + }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "dev": true + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", + "dev": true + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/loader-runner": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.2.0.tgz", + "integrity": "sha512-92+huvxMvYlMzMt0iIOukcwYBFpkYJdpl2xsZ7LrlayO7E8SOv+JJUEK17B/dJIHAOLMfh2dZZ/Y18WgmGtYNw==", + "dev": true, + "engines": { + "node": ">=6.11.5" + } + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash.debounce": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", + "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==" + }, + "node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "dev": true, + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mime-db": { + "version": "1.47.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.47.0.tgz", + "integrity": "sha512-QBmA/G2y+IfeS4oktet3qRZ+P5kPhCKRXxXnQEudYqUaEioAU1/Lq2us3D/t1Jfo4hE9REQPrbB7K5sOczJVIw==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.30", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.30.tgz", + "integrity": "sha512-crmjA4bLtR8m9qLpHvgxSChT+XoSlZi8J4n/aIdn3z92e/U47Z0V/yl+Wh9W046GgFVAmoNR/fmdbZYcSSIUeg==", + "dev": true, + "dependencies": { + "mime-db": "1.47.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/nanoid": { + "version": "3.3.8", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.8.tgz", + "integrity": "sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", + "dev": true + }, + "node_modules/neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", + "dev": true + }, + "node_modules/node-addon-api": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-7.1.1.tgz", + "integrity": "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==", + "dev": true, + "optional": true + }, + "node_modules/node-releases": { + "version": "2.0.27", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.27.tgz", + "integrity": "sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dev": true, + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/optionator": { + "version": "0.9.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz", + "integrity": "sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==", + "dev": true, + "dependencies": { + "@aashutoshrathi/word-wrap": "^1.2.3", + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-map": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-2.1.0.tgz", + "integrity": "sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "license": "MIT", + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-is-inside": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", + "integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=", + "dev": true + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/pinkie": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", + "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/pinkie-promise": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", + "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", + "dev": true, + "dependencies": { + "pinkie": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dev": true, + "dependencies": { + "find-up": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-dir/node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-dir/node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-dir/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pkg-dir/node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/postcss": { + "version": "8.4.33", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.33.tgz", + "integrity": "sha512-Kkpbhhdjw2qQs2O2DGX+8m5OVqEcbB9HRBvuYM9pgrjEFUg30A9LmXNlTAUj4S9kgtGyrMbTzVjH7E+s5Re2yg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "nanoid": "^3.3.7", + "picocolors": "^1.0.0", + "source-map-js": "^1.0.2" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/postcss-modules-extract-imports": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.1.0.tgz", + "integrity": "sha512-k3kNe0aNFQDAZGbin48pL2VNidTF0w4/eASDsxlyspobzU3wZQLOGj7L9gfRe0Jo9/4uud09DsjFNH7winGv8Q==", + "dev": true, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-modules-local-by-default": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.0.5.tgz", + "integrity": "sha512-6MieY7sIfTK0hYfafw1OMEG+2bg8Q1ocHCpoWLqOKj3JXlKu4G7btkmM/B7lFubYkYWmRSPLZi5chid63ZaZYw==", + "dev": true, + "dependencies": { + "icss-utils": "^5.0.0", + "postcss-selector-parser": "^6.0.2", + "postcss-value-parser": "^4.1.0" + }, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-modules-scope": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-3.2.0.tgz", + "integrity": "sha512-oq+g1ssrsZOsx9M96c5w8laRmvEu9C3adDSjI8oTcbfkrTE8hx/zfyobUoWIxaKPO8bt6S62kxpw5GqypEw1QQ==", + "dev": true, + "dependencies": { + "postcss-selector-parser": "^6.0.4" + }, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-modules-values": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-values/-/postcss-modules-values-4.0.0.tgz", + "integrity": "sha512-RDxHkAiEGI78gS2ofyvCsu7iycRv7oqw5xMWn9iMoR0N/7mf9D50ecQqUo5BZ9Zh2vH4bCUR/ktCqbB9m8vJjQ==", + "dev": true, + "dependencies": { + "icss-utils": "^5.0.0" + }, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-selector-parser": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.0.tgz", + "integrity": "sha512-UMz42UD0UY0EApS0ZL9o1XnLhSTtvvvLe5Dc2H2O56fvRZi+KulDyf5ctDhhtYJBGKStV2FL1fy6253cmLgqVQ==", + "dev": true, + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-value-parser": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", + "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", + "dev": true + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, + "dependencies": { + "safe-buffer": "^5.1.0" + } + }, + "node_modules/readdirp": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.0.2.tgz", + "integrity": "sha512-yDMz9g+VaZkqBYS/ozoBJwaBhTbZo3UNYQHNRw1D3UFQB8oHB4uS/tAODO+ZLjGWmUbKnIlOWO+aaIiAxrUWHA==", + "dev": true, + "engines": { + "node": ">= 14.16.0" + }, + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/rechoir": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.8.0.tgz", + "integrity": "sha512-/vxpCXddiX8NGfGO/mTafwjq4aFa/71pvamip0++IQk3zG8cbCj0fifNPrjjF1XMXUne91jL9OoxmdykoEtifQ==", + "dev": true, + "dependencies": { + "resolve": "^1.20.0" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/regenerate": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", + "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==", + "dev": true, + "license": "MIT" + }, + "node_modules/regenerate-unicode-properties": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.2.0.tgz", + "integrity": "sha512-DqHn3DwbmmPVzeKj9woBadqmXxLvQoQIwu7nopMc72ztvxVmVk2SBhSnx67zuye5TP+lJsb/TBQsjLKhnDf3MA==", + "dev": true, + "license": "MIT", + "dependencies": { + "regenerate": "^1.4.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/regexpu-core": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-6.2.0.tgz", + "integrity": "sha512-H66BPQMrv+V16t8xtmq+UC0CBpiTBA60V8ibS1QVReIp8T1z8hwFxqcGzm9K6lgsN7sB5edVH8a+ze6Fqm4weA==", + "dev": true, + "license": "MIT", + "dependencies": { + "regenerate": "^1.4.2", + "regenerate-unicode-properties": "^10.2.0", + "regjsgen": "^0.8.0", + "regjsparser": "^0.12.0", + "unicode-match-property-ecmascript": "^2.0.0", + "unicode-match-property-value-ecmascript": "^2.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/regjsgen": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.8.0.tgz", + "integrity": "sha512-RvwtGe3d7LvWiDQXeQw8p5asZUmfU1G/l6WbUXeHta7Y2PEIvBTwH6E2EfmYUK8pxcxEdEmaomqyp0vZZ7C+3Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/regjsparser": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.12.0.tgz", + "integrity": "sha512-cnE+y8bz4NhMjISKbgeVJtqNbtf5QpjZP+Bslo+UqkIt9QPnX9q095eiRRASJG1/tz6dlNr6Z5NsBiWYokp6EQ==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "jsesc": "~3.0.2" + }, + "bin": { + "regjsparser": "bin/parser" + } + }, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/resolve": { + "version": "1.22.10", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz", + "integrity": "sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-core-module": "^2.16.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-cwd": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", + "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", + "dev": true, + "dependencies": { + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve-cwd/node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/reusify": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", + "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", + "dev": true, + "license": "MIT", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + }, + "node_modules/sass": { + "version": "1.94.0", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.94.0.tgz", + "integrity": "sha512-Dqh7SiYcaFtdv5Wvku6QgS5IGPm281L+ZtVD1U2FJa7Q0EFRlq8Z3sjYtz6gYObsYThUOz9ArwFqPZx+1azILQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "chokidar": "^4.0.0", + "immutable": "^5.0.2", + "source-map-js": ">=0.6.2 <2.0.0" + }, + "bin": { + "sass": "sass.js" + }, + "engines": { + "node": ">=14.0.0" + }, + "optionalDependencies": { + "@parcel/watcher": "^2.4.1" + } + }, + "node_modules/sass-loader": { + "version": "16.0.6", + "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-16.0.6.tgz", + "integrity": "sha512-sglGzId5gmlfxNs4gK2U3h7HlVRfx278YK6Ono5lwzuvi1jxig80YiuHkaDBVsYIKFhx8wN7XSCI0M2IDS/3qA==", + "dev": true, + "license": "MIT", + "dependencies": { + "neo-async": "^2.6.2" + }, + "engines": { + "node": ">= 18.12.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "@rspack/core": "0.x || 1.x", + "node-sass": "^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0 || ^9.0.0", + "sass": "^1.3.0", + "sass-embedded": "*", + "webpack": "^5.0.0" + }, + "peerDependenciesMeta": { + "@rspack/core": { + "optional": true + }, + "node-sass": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "webpack": { + "optional": true + } + } + }, + "node_modules/schema-utils": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.3.3.tgz", + "integrity": "sha512-eflK8wEtyOE6+hsaRVPxvUKYCpRgzLqDTb8krvAsRIwOGlHoSgYLgBXoubGgLd2fT41/OUYdb48v4k4WWHQurA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.9.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.1.0" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/schema-utils/node_modules/ajv": { + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", + "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/schema-utils/node_modules/ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.3" + }, + "peerDependencies": { + "ajv": "^8.8.2" + } + }, + "node_modules/schema-utils/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + }, + "node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/serialize-javascript": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz", + "integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==", + "dev": true, + "dependencies": { + "randombytes": "^2.1.0" + } + }, + "node_modules/shallow-clone": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", + "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==", + "dev": true, + "dependencies": { + "kind-of": "^6.0.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-js": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", + "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "dev": true, + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/style-loader": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/style-loader/-/style-loader-4.0.0.tgz", + "integrity": "sha512-1V4WqhhZZgjVAVJyt7TdDPZoPBPNHbekX4fWnCJL1yQukhCeZhJySUL+gL9y6sNdN95uEOS83Y55SqHcP7MzLA==", + "dev": true, + "engines": { + "node": ">= 18.12.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.27.0" + } + }, + "node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/tapable": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.0.tgz", + "integrity": "sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/terser": { + "version": "5.39.0", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.39.0.tgz", + "integrity": "sha512-LBAhFyLho16harJoWMg/nZsQYgTrg5jXOn2nCYjRUcZZEdE3qa2zb8QEDRUGVZBW4rlazf2fxkg8tztybTaqWw==", + "dev": true, + "dependencies": { + "@jridgewell/source-map": "^0.3.3", + "acorn": "^8.8.2", + "commander": "^2.20.0", + "source-map-support": "~0.5.20" + }, + "bin": { + "terser": "bin/terser" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/terser-webpack-plugin": { + "version": "5.3.14", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.14.tgz", + "integrity": "sha512-vkZjpUjb6OMS7dhV+tILUW6BhpDR7P2L/aQSAv+Uwk+m8KATX9EccViHTJR2qDtACKPIYndLGCyl3FMo+r2LMw==", + "dev": true, + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.25", + "jest-worker": "^27.4.5", + "schema-utils": "^4.3.0", + "serialize-javascript": "^6.0.2", + "terser": "^5.31.1" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.1.0" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "esbuild": { + "optional": true + }, + "uglify-js": { + "optional": true + } + } + }, + "node_modules/terser-webpack-plugin/node_modules/jest-worker": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", + "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", + "dev": true, + "dependencies": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/tinyglobby": { + "version": "0.2.12", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.12.tgz", + "integrity": "sha512-qkf4trmKSIiMTs/E63cxH+ojC2unam7rJ0WrauAzpT3ECNTxGRMlaXxVbfxMUC/w0LaYk6jQ4y/nGR9uBO3tww==", + "dev": true, + "dependencies": { + "fdir": "^6.4.3", + "picomatch": "^4.0.2" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/tinyglobby/node_modules/fdir": { + "version": "6.4.3", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.4.3.tgz", + "integrity": "sha512-PMXmW2y1hDDfTSRc9gaXIuCCRpuoz3Kaz8cUelp3smouvfT632ozg2vrT6lJsHKKOF59YLbOGfAWGUcKEfRMQw==", + "dev": true, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/tinyglobby/node_modules/picomatch": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz", + "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/ts-api-utils": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.1.0.tgz", + "integrity": "sha512-CUgTZL1irw8u29bzrOD/nH85jqyc74D6SshFgujOIA7osm2Rz7dYH77agkx7H4FBNxDq7Cjf+IjaX/8zwFW+ZQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18.12" + }, + "peerDependencies": { + "typescript": ">=4.8.4" + } + }, + "node_modules/ts-loader": { + "version": "9.5.4", + "resolved": "https://registry.npmjs.org/ts-loader/-/ts-loader-9.5.4.tgz", + "integrity": "sha512-nCz0rEwunlTZiy6rXFByQU1kVVpCIgUpc/psFiKVrUwrizdnIbRFu8w7bxhUF0X613DYwT4XzrZHpVyMe758hQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.1.0", + "enhanced-resolve": "^5.0.0", + "micromatch": "^4.0.0", + "semver": "^7.3.4", + "source-map": "^0.7.4" + }, + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "typescript": "*", + "webpack": "^5.0.0" + } + }, + "node_modules/ts-loader/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/ts-loader/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/ts-loader/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/ts-loader/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/ts-loader/node_modules/semver": { + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/ts-loader/node_modules/source-map": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz", + "integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/ts-loader/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/tsconfig-paths-webpack-plugin": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/tsconfig-paths-webpack-plugin/-/tsconfig-paths-webpack-plugin-4.2.0.tgz", + "integrity": "sha512-zbem3rfRS8BgeNK50Zz5SIQgXzLafiHjOwUAvk/38/o1jHn/V5QAgVUcz884or7WYcPaH3N2CIfUc2u0ul7UcA==", + "dev": true, + "dependencies": { + "chalk": "^4.1.0", + "enhanced-resolve": "^5.7.0", + "tapable": "^2.2.1", + "tsconfig-paths": "^4.1.2" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/tsconfig-paths-webpack-plugin/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/tsconfig-paths-webpack-plugin/node_modules/chalk": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", + "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/tsconfig-paths-webpack-plugin/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/tsconfig-paths-webpack-plugin/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/tsconfig-paths-webpack-plugin/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/tsconfig-paths-webpack-plugin/node_modules/tsconfig-paths": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-4.2.0.tgz", + "integrity": "sha512-NoZ4roiN7LnbKn9QqE1amc9DJfzvZXxF4xDavcOWt1BPkdx+m+0gJuPM+S0vCe7zTJMYUP0R8pO2XMr+Y8oLIg==", + "dev": true, + "dependencies": { + "json5": "^2.2.2", + "minimist": "^1.2.6", + "strip-bom": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/unicode-canonical-property-names-ecmascript": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.1.tgz", + "integrity": "sha512-dA8WbNeb2a6oQzAQ55YlT5vQAWGV9WXOsi3SskE3bcCdM0P4SDd+24zS/OCacdRq5BkdsRj9q3Pg6YyQoxIGqg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-match-property-ecmascript": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz", + "integrity": "sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "unicode-canonical-property-names-ecmascript": "^2.0.0", + "unicode-property-aliases-ecmascript": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-match-property-value-ecmascript": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.2.0.tgz", + "integrity": "sha512-4IehN3V/+kkr5YeSSDDQG8QLqO26XpL2XP3GQtqwlT/QYSECAwFztxVHjlbh0+gjJ3XmNLS0zDsbgs9jWKExLg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-property-aliases-ecmascript": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.1.0.tgz", + "integrity": "sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.4.tgz", + "integrity": "sha512-q0SPT4xyU84saUX+tomz1WLkxUbuaJnR1xWt17M7fJtEJigJeWUNGUqrauFXsHnqev9y9JTRGwk13tFBuKby4A==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "escalade": "^3.2.0", + "picocolors": "^1.1.1" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", + "dev": true + }, + "node_modules/watchpack": { + "version": "2.4.4", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.4.tgz", + "integrity": "sha512-c5EGNOiyxxV5qmTtAB7rbiXxi1ooX1pQKMLX/MIabJjRA0SJBQOjKF+KSVfHkr9U1cADPon0mRiVe/riyaiDUA==", + "dev": true, + "license": "MIT", + "dependencies": { + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.1.2" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/webpack": { + "version": "5.102.1", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.102.1.tgz", + "integrity": "sha512-7h/weGm9d/ywQ6qzJ+Xy+r9n/3qgp/thalBbpOi5i223dPXKi04IBtqPN9nTd+jBc7QKfvDbaBnFipYp4sJAUQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/eslint-scope": "^3.7.7", + "@types/estree": "^1.0.8", + "@types/json-schema": "^7.0.15", + "@webassemblyjs/ast": "^1.14.1", + "@webassemblyjs/wasm-edit": "^1.14.1", + "@webassemblyjs/wasm-parser": "^1.14.1", + "acorn": "^8.15.0", + "acorn-import-phases": "^1.0.3", + "browserslist": "^4.26.3", + "chrome-trace-event": "^1.0.2", + "enhanced-resolve": "^5.17.3", + "es-module-lexer": "^1.2.1", + "eslint-scope": "5.1.1", + "events": "^3.2.0", + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.2.11", + "json-parse-even-better-errors": "^2.3.1", + "loader-runner": "^4.2.0", + "mime-types": "^2.1.27", + "neo-async": "^2.6.2", + "schema-utils": "^4.3.3", + "tapable": "^2.3.0", + "terser-webpack-plugin": "^5.3.11", + "watchpack": "^2.4.4", + "webpack-sources": "^3.3.3" + }, + "bin": { + "webpack": "bin/webpack.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependenciesMeta": { + "webpack-cli": { + "optional": true + } + } + }, + "node_modules/webpack-cli": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-6.0.1.tgz", + "integrity": "sha512-MfwFQ6SfwinsUVi0rNJm7rHZ31GyTcpVE5pgVA3hwFRb7COD4TzjUUwhGWKfO50+xdc2MQPuEBBJoqIMGt3JDw==", + "dev": true, + "dependencies": { + "@discoveryjs/json-ext": "^0.6.1", + "@webpack-cli/configtest": "^3.0.1", + "@webpack-cli/info": "^3.0.1", + "@webpack-cli/serve": "^3.0.1", + "colorette": "^2.0.14", + "commander": "^12.1.0", + "cross-spawn": "^7.0.3", + "envinfo": "^7.14.0", + "fastest-levenshtein": "^1.0.12", + "import-local": "^3.0.2", + "interpret": "^3.1.1", + "rechoir": "^0.8.0", + "webpack-merge": "^6.0.1" + }, + "bin": { + "webpack-cli": "bin/cli.js" + }, + "engines": { + "node": ">=18.12.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.82.0" + }, + "peerDependenciesMeta": { + "webpack-bundle-analyzer": { + "optional": true + }, + "webpack-dev-server": { + "optional": true + } + } + }, + "node_modules/webpack-cli/node_modules/commander": { + "version": "12.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-12.1.0.tgz", + "integrity": "sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==", + "dev": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/webpack-merge": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-6.0.1.tgz", + "integrity": "sha512-hXXvrjtx2PLYx4qruKl+kyRSLc52V+cCvMxRjmKwoA+CBbbF5GfIBtR6kCvl0fYGqTUPKB+1ktVmTHqMOzgCBg==", + "dev": true, + "dependencies": { + "clone-deep": "^4.0.1", + "flat": "^5.0.2", + "wildcard": "^2.0.1" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/webpack-sources": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.3.3.tgz", + "integrity": "sha512-yd1RBzSGanHkitROoPFd6qsrxt+oFhg/129YzheDGqeustzX0vTZJZsSsQjVQC4yzBQ56K55XU8gaNCtIzOnTg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/webpack-utf8-bom": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/webpack-utf8-bom/-/webpack-utf8-bom-1.4.0.tgz", + "integrity": "sha512-VsGG9GKqcXtOk9028DLPuoTzsdGPUUpCJkK6EV//1LrkthrDQO7+mrQl6Zq9B+KuOXGdbzsFU7ADuMYpaiUaZg==", + "dev": true, + "peerDependencies": { + "webpack": "^4.x.x || ^5.0.0" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/wildcard": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.1.tgz", + "integrity": "sha512-CC1bOL87PIWSBhDcTrdeLo6eGT7mCFtrg0uIJtqJUFyK+eJnzl8A1niH56uu7KMa5XFrtiV+AQuHO3n7DsHnLQ==", + "dev": true + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true + }, + "node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + } + } +} diff --git a/Source/Components/ImageGlass.Settings/WebUI/package.json b/Source/Components/ImageGlass.Settings/WebUI/package.json new file mode 100644 index 000000000..c4d19b9c5 --- /dev/null +++ b/Source/Components/ImageGlass.Settings/WebUI/package.json @@ -0,0 +1,54 @@ +{ + "name": "ig-ui", + "displayName": "ImageGlass Web UI", + "version": "9.4.0", + "description": "ImageGlass Web UI", + "scripts": { + "start": "webpack --watch --config ./webpack.config.js --progress --mode=production", + "build": "webpack --config ./webpack.config.js --progress --mode=production", + "css": "sass ./src/styles/main.scss ./dist/main.css" + }, + "keywords": [ + "npm", + "npm-package", + "babel", + "typescript", + "eslint", + "webpack" + ], + "author": "Duong Dieu Phap", + "license": "MIT", + "bugs": { + "url": "https://github.com/d2phap/ImageGlass/issues" + }, + "repository": { + "type": "git", + "url": "https://github.com/d2phap/ImageGlass.git" + }, + "homepage": "https://imageglass.org", + "devDependencies": { + "@babel/core": "^7.28.5", + "@babel/preset-env": "^7.28.5", + "@types/lodash.merge": "^4.6.9", + "@typescript-eslint/eslint-plugin": "^8.46.4", + "@typescript-eslint/parser": "^8.46.4", + "babel-loader": "^10.0.0", + "clean-webpack-plugin": "^4.0.0", + "copy-webpack-plugin": "^13.0.1", + "css-loader": "^7.1.2", + "eslint": "^9.39.1", + "eslint-webpack-plugin": "^5.0.2", + "sass": "^1.94.0", + "sass-loader": "^16.0.6", + "style-loader": "^4.0.0", + "ts-loader": "^9.5.4", + "tsconfig-paths-webpack-plugin": "^4.2.0", + "typescript": "^5.9.3", + "webpack": "^5.102.1", + "webpack-cli": "^6.0.1", + "webpack-utf8-bom": "^1.4.0" + }, + "dependencies": { + "lodash.merge": "^4.6.2" + } +} diff --git a/Source/Components/ImageGlass.Settings/WebUI/src/@types/FrmSettings.ts b/Source/Components/ImageGlass.Settings/WebUI/src/@types/FrmSettings.ts new file mode 100644 index 000000000..792c4579f --- /dev/null +++ b/Source/Components/ImageGlass.Settings/WebUI/src/@types/FrmSettings.ts @@ -0,0 +1,102 @@ +export type ILanguage = { + FileName: string, + Metadata: Record & { + Code: string, + EnglishName: string, + LocalName: string, + Author: string, + MinVersion: string, + }, +}; + +export type ITool = { + ToolId: string, + ToolName: string, + Executable: string, + Argument: string, + IsIntegrated?: boolean, + Hotkeys?: string[], +}; + +export type ITheme = { + ConfigFilePath: string, + FolderName: string, + FolderPath: string, + BgColor: string, + IsDarkMode: boolean, + PreviewImage: string, + Info: Record & { + Name: string, + Version: string, + Author: string, + Email: string, + Website: string, + Description: string, + }, + ToolbarIcons: Record, +}; + +export type SingleAction = { + Executable: string, + Arguments: Array, + NextAction?: SingleAction, +}; + +export type IToolbarButton = { + Type: 'Button' | 'Separator', + Id: string, + Text: string, + DisplayStyle: 'Image' | 'ImageAndText', + CheckableConfigBinding: string, + Alignment: 'Left' | 'Right', + Image: string, + ImageUrl: string, + OnClick: SingleAction, + Hotkeys: string[], +}; + +export type IEditApp = { + AppName: string, + Executable: string, + Argument: string, +} + +export type IPageSettings = Record & { + config: Record, + langList: ILanguage[], + toolList: ITool[], + themeList: ITheme[], + startUpDir: string, + configDir: string, + userConfigFilePath: string, + defaultThemeDir: string, + defaultImageInfoTags: string[], + builtInToolbarButtons: IToolbarButton[], + enums: Record & { + ImageOrderBy: string[], + ImageOrderType: string[], + ColorProfileOption: string[], + AfterEditAppAction: string[], + ImageInterpolation: string[], + MouseWheelAction: string[], + MouseWheelEvent: string[], + MouseClickEvent: string[], + BackdropStyle: string[], + ToolbarItemModelType: string[], + ImageInfoUpdateTypes: string[], + }, + icons: Record & { + Delete: string, + Edit: string, + ArrowUp: string, + ArrowDown: string, + ArrowLeft: string, + ArrowRight: string, + ArrowExchange: string, + Sun: string, + Moon: string, + Info: string, + Warning: string, + }, + FILE_MACRO: string; +}; diff --git a/Source/Components/ImageGlass.Settings/WebUI/src/@types/global.d.ts b/Source/Components/ImageGlass.Settings/WebUI/src/@types/global.d.ts new file mode 100644 index 000000000..f154d70f1 --- /dev/null +++ b/Source/Components/ImageGlass.Settings/WebUI/src/@types/global.d.ts @@ -0,0 +1,46 @@ +import { IPageSettings } from './FrmSettings'; +import { Webview } from '@/helpers/webview'; +import Language from '@/common/Language'; + +import { + query as QueryFn, + queryAll as QueryAllFn, + on as OnFn, + post as PostFn, + postAsync as PostAsyncFn, +} from '../helpers/globalHelpers'; + + +export type IPage = Record & { + lang: Record, + theme: string, + isWindows10: boolean, + + loadLanguage?: typeof Language.load, +}; + +declare global { + interface Window { + _webview: Webview; + _pageSettings: IPageSettings, + + query: typeof QueryFn, + queryAll: typeof QueryAllFn, + + on: typeof OnFn, + post: typeof PostFn, + postAsync: typeof PostAsyncFn, + } + + var _webview: Webview; + var _page: IPage; + var _pageSettings: IPageSettings; + + var query: typeof QueryFn; + var queryAll: typeof QueryAllFn; + + var on: typeof OnFn; + var post: typeof PostFn; + var postAsync: typeof PostAsyncFn; +} + diff --git a/Source/Components/ImageGlass.Settings/WebUI/src/DXCanvas_Webview2.ts b/Source/Components/ImageGlass.Settings/WebUI/src/DXCanvas_Webview2.ts new file mode 100644 index 000000000..0df398af4 --- /dev/null +++ b/Source/Components/ImageGlass.Settings/WebUI/src/DXCanvas_Webview2.ts @@ -0,0 +1,7 @@ +import './main'; + +import HapplaBoxViewer from './DXCanvas_Webview2/HapplaBoxViewer'; + + +// initialize the viewer +HapplaBoxViewer.initialize(); diff --git a/Source/Components/ImageGlass.Settings/WebUI/src/DXCanvas_Webview2/HapplaBoxViewer.ts b/Source/Components/ImageGlass.Settings/WebUI/src/DXCanvas_Webview2/HapplaBoxViewer.ts new file mode 100644 index 000000000..cbe8233cb --- /dev/null +++ b/Source/Components/ImageGlass.Settings/WebUI/src/DXCanvas_Webview2/HapplaBoxViewer.ts @@ -0,0 +1,322 @@ +import { HapplaBoxHTMLElement, defineHapplaBoxHTMLElement } from './webComponents/HapplaBoxHTMLElement'; +import { + IMouseEventArgs, + ILoadContentRequestedEventArgs, + IZoomEventArgs, + ZoomMode, + PanDirection, +} from './webComponents/happlajs/HapplaBoxTypes'; + + +enum Web2BackendMsgNames { + SET_HTML = 'SET_HTML', + SET_IMAGE = 'SET_IMAGE', + SET_ZOOM_MODE = 'SET_ZOOM_MODE', + SET_ZOOM_FACTOR = 'SET_ZOOM_FACTOR', + START_PANNING_ANIMATION = 'START_PANNING_ANIMATION', + START_ZOOMING_ANIMATION = 'START_ZOOMING_ANIMATION', + STOP_ANIMATIONS = 'STOP_ANIMATIONS', + SET_MESSAGE = 'SET_MESSAGE', + SET_NAVIGATION = 'SET_NAVIGATION', +} + +enum Web2FrontendMsgNames { + ON_ZOOM_CHANGED = 'ON_ZOOM_CHANGED', + ON_POINTER_DOWN = 'ON_POINTER_DOWN', + ON_MOUSE_WHEEL = 'ON_MOUSE_WHEEL', + ON_CONTENT_SIZE_CHANGED = 'ON_CONTENT_SIZE_CHANGED', + ON_FILE_DROP = 'ON_FILE_DROP', + ON_NAV_CLICK = 'ON_NAV_CLICK', +} + +const _transitionDuration = 300; +let _boxEl: HapplaBoxHTMLElement = undefined; +let _zoomMode: ZoomMode = ZoomMode.AutoZoom; +let _isPointerDown = false; +let _navHitTest: 'left' | 'right' | '' = ''; + +export default class HapplaBoxViewer { + + static initialize() { + defineHapplaBoxHTMLElement(); + _boxEl = document.querySelector('happla-box').shadowRoot.host as HapplaBoxHTMLElement; + + _boxEl.initialize({ + zoomFactor: 1, + onAfterZoomChanged: HapplaBoxViewer.onAfterZoomChanged, + onMouseWheel: HapplaBoxViewer.onMouseWheel, + onContentSizeChanged: HapplaBoxViewer.onContentSizeChanged, + }); + + _boxEl.addEventListener('dragenter', HapplaBoxViewer.onFileDragEntered); + _boxEl.addEventListener('dragover', HapplaBoxViewer.onFileDragOver); + _boxEl.addEventListener('drop', HapplaBoxViewer.onFileDropped); + + _boxEl.addEventListener('pointerleave', HapplaBoxViewer.onPointerLeave); + _boxEl.addEventListener('pointerup', HapplaBoxViewer.onPointerUp); + _boxEl.addEventListener('pointerdown', HapplaBoxViewer.onPointerDown); + _boxEl.addEventListener('pointermove', HapplaBoxViewer.onPointerMove); + _boxEl.focus(); + + // listen to Web2 Backend message + on(Web2BackendMsgNames.SET_IMAGE, HapplaBoxViewer.onWeb2LoadContentRequested); + on(Web2BackendMsgNames.SET_HTML, HapplaBoxViewer.onWeb2LoadContentRequested); + on(Web2BackendMsgNames.SET_ZOOM_MODE, HapplaBoxViewer.onWeb2ZoomModeChanged); + on(Web2BackendMsgNames.SET_ZOOM_FACTOR, HapplaBoxViewer.onWeb2ZoomFactorChanged); + on(Web2BackendMsgNames.START_PANNING_ANIMATION, HapplaBoxViewer.onWeb2StartPanAnimationRequested); + on(Web2BackendMsgNames.START_ZOOMING_ANIMATION, HapplaBoxViewer.onWeb2StartZoomAnimationRequested); + on(Web2BackendMsgNames.STOP_ANIMATIONS, HapplaBoxViewer.onWeb2StopAnimationsRequested); + on(Web2BackendMsgNames.SET_MESSAGE, HapplaBoxViewer.onWeb2SetMessage); + on(Web2BackendMsgNames.SET_NAVIGATION, HapplaBoxViewer.onWeb2SetNavigation); + } + + private static onFileDragEntered(e: DragEvent) { + e.stopPropagation(); + e.preventDefault(); + } + + private static onFileDragOver(e: DragEvent) { + e.stopPropagation(); + e.preventDefault(); + e.dataTransfer.dropEffect = 'link'; + } + + private static onFileDropped(e: DragEvent) { + e.stopPropagation(); + e.preventDefault(); + + post(Web2FrontendMsgNames.ON_FILE_DROP, e.dataTransfer.files, false); + } + + + private static onPointerLeave(e: PointerEvent) { + e.preventDefault(); + + const navLeftEl = query('#layerNavigation .nav-left'); + const navRightEl = query('#layerNavigation .nav-right'); + navLeftEl.classList.remove('is--visible'); + navRightEl.classList.remove('is--visible'); + } + + private static onPointerDown(e: PointerEvent) { + e.preventDefault(); + _isPointerDown = true; + + const navLeftEl = query('#layerNavigation .nav-left'); + const navRightEl = query('#layerNavigation .nav-right'); + _navHitTest = HapplaBoxViewer.hitTestNav(e); + + navLeftEl.classList.toggle('is--visible', _navHitTest === 'left'); + navRightEl.classList.toggle('is--visible', _navHitTest === 'right'); + navLeftEl.classList.toggle('is--active', _navHitTest === 'left'); + navRightEl.classList.toggle('is--active', _navHitTest === 'right'); + + post(Web2FrontendMsgNames.ON_POINTER_DOWN, { + Dpi: _boxEl.options.scaleRatio, + Button: e.button, + X: e.pageX, + Y: e.pageY, + Delta: 0, + } as IMouseEventArgs, true); + } + + private static onPointerUp(e: PointerEvent) { + e.preventDefault(); + + const navLeftEl = query('#layerNavigation .nav-left'); + const navRightEl = query('#layerNavigation .nav-right'); + navLeftEl.classList.toggle('is--active', false); + navRightEl.classList.toggle('is--active', false); + + const nav = HapplaBoxViewer.hitTestNav(e); + if (_isPointerDown && _navHitTest !== '' && _navHitTest === nav) { + post(Web2FrontendMsgNames.ON_NAV_CLICK, { + NavigationButton: nav, + Button: e.button, + X: e.pageX, + Y: e.pageY, + Delta: 0, + } as IMouseEventArgs, true); + } + + _isPointerDown = false; + _navHitTest = ''; + } + + private static onPointerMove(e: PointerEvent) { + e.preventDefault(); + + const navLeftEl = query('#layerNavigation .nav-left'); + const navRightEl = query('#layerNavigation .nav-right'); + const nav = HapplaBoxViewer.hitTestNav(e); + + if (!_isPointerDown) { + navLeftEl.classList.toggle('is--visible', nav === 'left'); + navRightEl.classList.toggle('is--visible', nav === 'right'); + } + else { + navLeftEl.classList.toggle('is--active', _navHitTest === 'left'); + navRightEl.classList.toggle('is--active', _navHitTest === 'right'); + } + } + + private static onMouseWheel(e: WheelEvent) { + post(Web2FrontendMsgNames.ON_MOUSE_WHEEL, { + Dpi: _boxEl.options.scaleRatio, + Button: e.button, + Delta: e.deltaY, + X: e.pageX, + Y: e.pageY, + } as IMouseEventArgs, true); + } + + private static onContentSizeChanged(rect: DOMRect) { + post(Web2FrontendMsgNames.ON_CONTENT_SIZE_CHANGED, { + Dpi: _boxEl.options.scaleRatio, + X: rect.x, + Y: rect.y, + Width: rect.width, + Height: rect.height, + }, true); + } + + private static onAfterZoomChanged(e: IZoomEventArgs) { + post(Web2FrontendMsgNames.ON_ZOOM_CHANGED, { + ZoomFactor: e.zoomFactor, + IsManualZoom: e.isManualZoom, + IsZoomModeChanged: e.isZoomModeChanged, + X: e.x, + Y: e.y, + }, true); + } + + private static async onWeb2LoadContentRequested( + eventName: Web2BackendMsgNames, + e: ILoadContentRequestedEventArgs, + ) { + _zoomMode = e.ZoomMode; + + if (eventName === Web2BackendMsgNames.SET_IMAGE) { + await _boxEl.loadImage(e.Url, _zoomMode, e.ZoomFactor, e.DirPath); + } + else if (eventName === Web2BackendMsgNames.SET_HTML) { + await _boxEl.loadHtml(e.Html, _zoomMode, e.ZoomFactor, e.DirPath); + } + } + + private static async onWeb2ZoomModeChanged(_: Web2BackendMsgNames, e: { + ZoomMode: ZoomMode, + IsManualZoom: boolean, + }) { + _zoomMode = e.ZoomMode; + await _boxEl.setZoomMode(e.ZoomMode, -1, _transitionDuration); + } + + private static async onWeb2ZoomFactorChanged(_: Web2BackendMsgNames, e: { + ZoomFactor: number, + IsManualZoom: boolean, + ZoomDelta: number, + }) { + await _boxEl.setZoomFactor(e.ZoomFactor, e.IsManualZoom, e.ZoomDelta, _transitionDuration); + } + + private static async onWeb2StartPanAnimationRequested(_: Web2BackendMsgNames, e: { + PanSpeed: number, + Direction: PanDirection, + }) { + await _boxEl.startPanningAnimation(e.Direction, e.PanSpeed); + } + + private static async onWeb2StartZoomAnimationRequested(_: Web2BackendMsgNames, e: { + IsZoomOut: boolean, + ZoomSpeed: number, + }) { + await _boxEl.startZoomingAnimation(e.IsZoomOut, e.ZoomSpeed); + } + + private static async onWeb2StopAnimationsRequested() { + _boxEl.stopAnimations(); + } + + private static onWeb2SetMessage(_: Web2BackendMsgNames, e: { + Heading: string, + Text: string, + }) { + const msgLayerEl = query('#layerMessage'); + const headingEl = query('.message-heading', msgLayerEl); + const textEl = query('.message-text', msgLayerEl); + + // update text + headingEl.innerText = e.Heading; + textEl.innerText = e.Text; + + const isHeadingHidden = !e.Heading; + const isTextHidden = !e.Text; + const isLayerHidden = isHeadingHidden && isTextHidden; + + // update visibility + msgLayerEl.hidden = isLayerHidden; + headingEl.hidden = isHeadingHidden; + textEl.hidden = isTextHidden; + } + + private static onWeb2SetNavigation(_: Web2BackendMsgNames, e: { + Visible: boolean, + LeftImageUrl: string, + RightImageUrl: string, + NavButtonColor: number[], + }) { + const navLayerEl = query('#layerNavigation'); + const navLeftImgEl = query('.nav-left img', navLayerEl); + const navRightImgEl = query('.nav-right img', navLayerEl); + + const [r, g, b] = e.NavButtonColor; + const rgbaColor = [r, g, b].join(' '); + + navLayerEl.hidden = !e.Visible; + navLayerEl.style.setProperty('--nav-button-color', rgbaColor); + navLeftImgEl.src = e.LeftImageUrl; + navRightImgEl.src = e.RightImageUrl; + } + + private static hitTestNav(e: PointerEvent) { + if (e.button > 0) return ''; // only check if left-mouse clicked or no button clicked + + const boxBounds = _boxEl.getBoundingClientRect(); + const layerNavEl = query('#layerNavigation'); + const navLeftEl = query('#layerNavigation .nav-left'); + const navRightEl = query('#layerNavigation .nav-right'); + + if (boxBounds.width < navLeftEl.clientWidth + navRightEl.clientWidth + || layerNavEl.hidden) return ''; + + + // check right nav + // right clickable region + const rectRight = new DOMRect( + navRightEl.offsetLeft, + 0, + boxBounds.width - navRightEl.offsetLeft, + boxBounds.height, + ); + const isRightNav = rectRight.x <= e.x && e.x < rectRight.right + && rectRight.y <= e.y && e.y < rectRight.bottom; + if (isRightNav) return 'right'; + + + // check left nav + // left clickable region + const rectLeft = new DOMRect( + 0, + 0, + navLeftEl.offsetLeft + navLeftEl.clientWidth, + boxBounds.height, + ); + const isLeftNav = rectLeft.x <= e.x && e.x < rectLeft.right + && rectLeft.y <= e.y && e.y < rectLeft.bottom; + if (isLeftNav) return 'left'; + + + return ''; + } +} diff --git a/Source/Components/ImageGlass.Settings/WebUI/src/DXCanvas_Webview2/webComponents/HapplaBoxHTMLElement.ts b/Source/Components/ImageGlass.Settings/WebUI/src/DXCanvas_Webview2/webComponents/HapplaBoxHTMLElement.ts new file mode 100644 index 000000000..e2a86d811 --- /dev/null +++ b/Source/Components/ImageGlass.Settings/WebUI/src/DXCanvas_Webview2/webComponents/HapplaBoxHTMLElement.ts @@ -0,0 +1,206 @@ + +import { HapplaBox } from './happlajs/HapplaBox'; +import { IHapplaBoxOptions, PanDirection, ZoomMode } from './happlajs/HapplaBoxTypes'; +import { taggedTemplate } from '@/helpers'; + +const styles = ` + :host * { + -webkit-user-drag: none; + user-select: none; + } + + .hp-box { + margin: auto; + max-width: 100vw; + max-height: 100vh; + width: 100vw; + height: 100vh; + } + .hp-box:focus, + .hp-box:focus-visible { + outline: none; + } + + :host([checkerboard=true i]) .hp-box { + background-size: 1.5rem 1.5rem; + background-image: conic-gradient( + rgb(255 255 255 / 0.1) 25%, + rgb(0 0 0 / 0.1) 0 50%, + rgb(255 255 255 / 0.1) 0 75%, + rgb(0 0 0 / 0.1) 0 + ); + } + + .hp-box-wrapper { + width: 100%; + height: 100%; + opacity: 0; + transition: all 100ms ease; + } + + .hp-box-content { + display: inline-flex; + } +`; + + +const imgTemplate = taggedTemplate<{ + src: string, + alt?: string, +}>`${'alt'}`; + + +export class HapplaBoxHTMLElement extends HTMLElement { + #box: HapplaBox; + + #boxEl: HTMLDivElement; + #wrapperEl: HTMLDivElement; + #boxContentEl: HTMLDivElement; + + constructor() { + super(); + + // private methods + this.createTemplate = this.createTemplate.bind(this); + + // initialize template + this.createTemplate(); + } + + get options() { + return this.#box.options; + } + + private disconnectedCallback() { + this.#box.disable(); + } + + + private createTemplate() { + // initialize component + this.attachShadow({ mode: 'open' }); + + const css = new CSSStyleSheet(); + css.replaceSync(styles); + this.shadowRoot.adoptedStyleSheets = [css]; + + + // content + const boxContentEl = document.createElement('div'); + boxContentEl.classList.add('hp-box-content'); + + // wrapper + const wrapperEl = document.createElement('div'); + wrapperEl.classList.add('hp-box-wrapper'); + wrapperEl.appendChild(boxContentEl); + + // container + const boxEl = document.createElement('div'); + boxEl.tabIndex = 0; + boxEl.classList.add('hp-box'); + boxEl.appendChild(wrapperEl); + + this.#boxContentEl = boxContentEl; + this.#wrapperEl = wrapperEl; + this.#boxEl = boxEl; + + this.shadowRoot.appendChild(this.#boxEl); + } + + + public initialize(options: IHapplaBoxOptions = {}) { + this.#box = new HapplaBox(this.#boxEl, this.#boxContentEl, options); + + this.#box.enable(); + } + + public async loadImage(url: string, zoomMode: ZoomMode = ZoomMode.AutoZoom, zoomLockFactor = -1, dirPath = '') { + const html = imgTemplate({ src: url }); + await this.loadHtml(html, zoomMode, zoomLockFactor); + } + + public async loadHtml(html: string, zoomMode: ZoomMode = ZoomMode.AutoZoom, zoomLockFactor = -1, dirPath = '') { + this.#wrapperEl.style.transition = 'none'; + this.#boxContentEl.style.transform = 'scale(0.01)'; + this.#wrapperEl.style.opacity = '0'; + + await this.#box.loadHtmlContent(html); + + // fixed size of SVG + const svgEls = Array.from(this.#boxContentEl.querySelectorAll('svg:not([width]), svg:not([height])')); + svgEls.forEach((svgEl: SVGMarkerElement) => { + const { width, height } = svgEl.viewBox.baseVal; + + if (width === 0 || height === 0) { + svgEl.style.width = '100vw'; + svgEl.style.height = '100vw'; + } + else { + svgEl.setAttribute('width', width.toString()); + svgEl.setAttribute('height', height.toString()); + } + }); + + // fix the path of image + const imageEls = Array.from(this.#boxContentEl.querySelectorAll('image[href]')); + imageEls.forEach((img: SVGImageElement) => { + const href = img.getAttribute('href') ?? ''; + + // check if the href is valid + if (!URL.canParse(href)) { + try { + const newHref = new URL(href, dirPath); + img.setAttribute('href', newHref.toString()); + } + catch {} + } + }); + + + await this.setZoomMode(zoomMode, zoomLockFactor); + + this.#wrapperEl.style.transition = ''; + this.#wrapperEl.style.opacity = '1'; + } + + public setZoomMode(mode: ZoomMode = ZoomMode.AutoZoom, zoomLockFactor = -1, duration = 0) { + return this.#box.setZoomMode(mode, zoomLockFactor, duration); + } + + public setZoomFactor(zoomFactor: number, isManualZoom: boolean, zoomDelta = 1, duration = 0) { + const x = this.#box.pointerLocation.x ?? -1; + const y = this.#box.pointerLocation.y ?? -1; + + if (zoomDelta !== 1 && x >= 0 && y >= 0) { + return this.#box.zoomByDelta(zoomDelta, x, y, isManualZoom, duration / 3); + } + + return this.#box.zoomToCenter(zoomFactor, { isManualZoom, duration }); + } + + public startPanningAnimation(direction: PanDirection, speed: number) { + return this.#box.startPanningAnimation(direction, speed); + } + + public startZoomingAnimation(isZoomOut: boolean, speed: number) { + return this.#box.startZoomingAnimation(isZoomOut, speed); + } + + public stopAnimations() { + this.#box.stopPanningAnimation(); + this.#box.stopZoomingAnimation(); + } + + public focus() { + this.#boxEl.focus({ preventScroll: true }); + } +} + + +/** + * Creates and registers HapplaBoxHTMLElement to DOM. + */ +export const defineHapplaBoxHTMLElement = () => window.customElements.define( + 'happla-box', + HapplaBoxHTMLElement, +); diff --git a/Source/Components/ImageGlass.Settings/WebUI/src/DXCanvas_Webview2/webComponents/happlajs/DOMPadding.ts b/Source/Components/ImageGlass.Settings/WebUI/src/DXCanvas_Webview2/webComponents/happlajs/DOMPadding.ts new file mode 100644 index 000000000..d1abcfe06 --- /dev/null +++ b/Source/Components/ImageGlass.Settings/WebUI/src/DXCanvas_Webview2/webComponents/happlajs/DOMPadding.ts @@ -0,0 +1,35 @@ + +export class DOMPadding { + left = 0; + right = 0; + top = 0; + bottom = 0; + + constructor(left = 0, top = 0, right = 0, bottom = 0) { + this.left = left; + this.top = top; + this.right = right; + this.bottom = bottom; + + this.multiply = this.multiply.bind(this); + } + + get horizontal() { + return this.left + this.right; + } + + get vertical() { + return this.top + this.bottom; + } + + multiply(value: number) { + if (value < 0) return this; + + return new DOMPadding( + this.left * value, + this.top * value, + this.right * value, + this.bottom * value, + ); + } +} diff --git a/Source/Components/ImageGlass.Settings/WebUI/src/DXCanvas_Webview2/webComponents/happlajs/HapplaBox.ts b/Source/Components/ImageGlass.Settings/WebUI/src/DXCanvas_Webview2/webComponents/happlajs/HapplaBox.ts new file mode 100644 index 000000000..7d153cb53 --- /dev/null +++ b/Source/Components/ImageGlass.Settings/WebUI/src/DXCanvas_Webview2/webComponents/happlajs/HapplaBox.ts @@ -0,0 +1,642 @@ +import merge from 'lodash.merge'; +import { IHapplaBoxOptions, InterpolationMode, PanDirection, ZoomMode } from './HapplaBoxTypes'; +import { pause } from '@/helpers'; +import { DOMPadding } from './DOMPadding'; + +export class HapplaBox { + private boxEl: HTMLElement; + private boxContentEl: HTMLElement; + private domMatrix: DOMMatrix; + private isPointerDown = false; + + #contentDOMObserver: MutationObserver; + #resizeObserver: ResizeObserver; + + #isContentElDOMChanged = false; + #pointerLocation: { x?: number, y?: number } = {}; + + private panningAnimationFrame: number; + private zoomingAnimationFrame: number; + private isPanning = false; + private isZooming = false; + + #options: IHapplaBoxOptions = {}; + #defaultOptions: IHapplaBoxOptions = { + imageRendering: InterpolationMode.Auto, + + allowZoom: true, + minZoom: 0.01, + maxZoom: 100, + zoomFactor: 1, + panOffset: new DOMPoint(0, 0), + + allowPan: true, + scaleRatio: window.devicePixelRatio, + padding: new DOMPadding(), + + onBeforeContentReady() {}, + onContentReady() {}, + onResizing() {}, + onMouseWheel() {}, + + onBeforeZoomChanged() {}, + onAfterZoomChanged() {}, + onAfterTransformed() {}, + + onPanning() {}, + onAfterPanned() {}, + }; + + + /** + * Initializes HapplaBox element. + * @param boxEl Box element + * @param boxContentEl Content element + * @param options Options + */ + constructor(boxEl: HTMLElement, boxContentEl: HTMLElement, options?: IHapplaBoxOptions) { + this.boxEl = boxEl; + this.boxContentEl = boxContentEl; + this.#options = merge({}, this.#defaultOptions, options); + + // correct zoomFactor after calculating scaleRatio + this.#options.zoomFactor /= this.#options.scaleRatio; + + this.domMatrix = new DOMMatrix() + .scaleSelf(this.dpi(this.zoomFactor)) + .translateSelf(this.#options.panOffset.x, this.#options.panOffset.y); + + + this.dpi = this.dpi.bind(this); + this.updateImageRendering = this.updateImageRendering.bind(this); + this.checkIfNeedRecenter = this.checkIfNeedRecenter.bind(this); + this.getCenterPoint = this.getCenterPoint.bind(this); + this.animatePanning = this.animatePanning.bind(this); + this.animateZooming = this.animateZooming.bind(this); + + this.enable = this.enable.bind(this); + this.disable = this.disable.bind(this); + this.startPanningAnimation = this.startPanningAnimation.bind(this); + this.stopPanningAnimation = this.stopPanningAnimation.bind(this); + this.startZoomingAnimation = this.startZoomingAnimation.bind(this); + this.stopZoomingAnimation = this.stopZoomingAnimation.bind(this); + this.zoomToCenter = this.zoomToCenter.bind(this); + this.zoomByDelta = this.zoomByDelta.bind(this); + this.zoomToPoint = this.zoomToPoint.bind(this); + this.recenter = this.recenter.bind(this); + this.panToDistance = this.panToDistance.bind(this); + this.panTo = this.panTo.bind(this); + this.applyTransform = this.applyTransform.bind(this); + + this.onContentElDOMChanged = this.onContentElDOMChanged.bind(this); + this.onResizing = this.onResizing.bind(this); + this.onMouseWheel = this.onMouseWheel.bind(this); + this.onPointerEnter = this.onPointerEnter.bind(this); + this.onPointerLeave = this.onPointerLeave.bind(this); + this.onPointerDown = this.onPointerDown.bind(this); + this.onPointerUp = this.onPointerUp.bind(this); + this.onPointerMove = this.onPointerMove.bind(this); + + // create content DOM observer + this.#contentDOMObserver = new MutationObserver(this.onContentElDOMChanged); + this.#resizeObserver = new ResizeObserver(this.onResizing); + + this.disable(); + + this.boxContentEl.style.transformOrigin = 'top left'; + this.boxEl.style.touchAction = 'none'; + this.boxEl.style.overflow = 'hidden'; + + // emit event onBeforeContentReady + this.#options.onBeforeContentReady(); + } + + // #region Getters & Setters + get options() { + return this.#options; + } + + get pointerLocation(): { x?: number, y?: number } { + return this.#pointerLocation || {}; + } + + get imageRendering() { + return this.#options.imageRendering; + } + + set imageRendering(value: InterpolationMode) { + this.#options.imageRendering = value; + + this.updateImageRendering(); + } + + get scaleRatio() { + return this.#options.scaleRatio; + } + + set scaleRatio(value: number) { + this.#options.scaleRatio = value; + } + + get padding() { + return this.#options.padding; + } + + set padding(value: DOMPadding) { + this.#options.padding = value; + } + + /** + * Gets zoom factor after computing device ratio (DPI) + */ + get zoomFactor() { + return this.#options.zoomFactor * this.#options.scaleRatio; + } + // #endregion + + + // #region Private functions + private onContentElDOMChanged(mutations: MutationRecord[]) { + let isContentElDOMChanged = false; + + mutations.forEach(m => { + if (m.type === 'childList') { + isContentElDOMChanged = true; + } + }); + + this.#isContentElDOMChanged = isContentElDOMChanged; + } + + private async onResizing() { + if (this.checkIfNeedRecenter()) { + await this.recenter(); + + // raise event onContentSizeChanged + const bound = this.boxContentEl.getBoundingClientRect(); + this.#options.onContentSizeChanged(bound); + } + + this.#options.onResizing(); + } + + private onMouseWheel(e: WheelEvent) { + // ignore horizontal scroll events + if (e.deltaY === 0) return; + + this.#options.onMouseWheel(e); + } + + private onPointerEnter(e: PointerEvent) { + this.#pointerLocation = { x: e.pageX, y: e.pageY }; + } + + private onPointerLeave(e: PointerEvent) { + this.#pointerLocation = {}; + this.onPointerUp(e); + } + + private onPointerDown(e: PointerEvent) { + // ignore right clicks + if (e.button !== 0) { + return; + } + + this.boxEl.setPointerCapture(e.pointerId); + this.isPointerDown = true; + + // We get the pointer position on click so we can get the value once the user starts to drag + this.#options.panOffset.x = e.clientX; + this.#options.panOffset.y = e.clientY; + } + + private async onPointerMove(e: PointerEvent) { + this.#pointerLocation = { x: e.pageX, y: e.pageY }; + + // Only run this function if the pointer is down + if (!this.isPointerDown) return; + + await this.panToDistance( + e.clientX - this.#options.panOffset.x, + e.clientY - this.#options.panOffset.y, + ); + + this.#options.panOffset.x = e.clientX; + this.#options.panOffset.y = e.clientY; + } + + private onPointerUp(e: PointerEvent) { + if (!this.isPointerDown) { + return; + } + + this.boxEl.releasePointerCapture(e.pointerId); + this.isPointerDown = false; + + this.#options.panOffset.x += e.clientX - this.#options.panOffset.x; + this.#options.panOffset.y += e.clientY - this.#options.panOffset.y; + + this.#options.onAfterPanned(this.domMatrix.e, this.domMatrix.f); + } + + private dpi(value: number) { + return value / this.#options.scaleRatio; + } + + private updateImageRendering() { + switch (this.imageRendering) { + case InterpolationMode.Auto: + if (this.zoomFactor <= 1.0) { + this.boxContentEl.style.imageRendering = InterpolationMode.CrispEdges; + } + else { + this.boxContentEl.style.imageRendering = InterpolationMode.Pixelated; + } + break; + + default: + this.boxContentEl.style.imageRendering = this.imageRendering; + break; + } + } + + private getCenterPoint(zoomFactor: number) { + const fullW = this.boxContentEl.scrollWidth * zoomFactor; + const fullH = this.boxContentEl.scrollHeight * zoomFactor; + const scaledPadding = this.padding.multiply(1 / this.scaleRatio); + + // center point + const x = (this.boxEl.offsetWidth - fullW) / 2 + scaledPadding.left / 2 - scaledPadding.right / 2; + const y = (this.boxEl.offsetHeight - fullH) / 2 + scaledPadding.top / 2 - scaledPadding.bottom / 2; + + return new DOMPoint(x, y); + } + + private checkIfNeedRecenter() { + const boxBounds = this.boxEl.getBoundingClientRect(); + const contentBounds = this.boxContentEl.getBoundingClientRect(); + const isInsideBox = contentBounds.left >= boxBounds.left + || contentBounds.top >= boxBounds.top + || contentBounds.right <= boxBounds.right + || contentBounds.bottom <= boxBounds.bottom; + + return isInsideBox; + } + + private async animatePanning(direction: PanDirection, panSpeed = 20) { + const speed = this.dpi(panSpeed || 20); + let x = 0; + let y = 0; + + if (direction === 'left') { + x = speed; + } + else if (direction === 'right') { + x = -speed; + } + + if (direction === 'up') { + y = speed; + } + else if (direction === 'down') { + y = -speed; + } + + await this.panToDistance(x, y); + + this.panningAnimationFrame = requestAnimationFrame(() => this.animatePanning(direction, panSpeed)); + } + + private async animateZooming(isZoomOut: boolean, zoomSpeed = 20) { + const zoomDelta = isZoomOut ? -20 : 20; + const speed = zoomDelta / (501 - zoomSpeed); + let newZoomFactor = this.#options.zoomFactor; + + // zoom out + if (isZoomOut) { + newZoomFactor = this.#options.zoomFactor / (1 - speed); + } + // zoom in + else { + newZoomFactor = this.#options.zoomFactor * (1 + speed); + } + + const newDelta = newZoomFactor / this.#options.zoomFactor; + const x = this.pointerLocation.x ?? -1; + const y = this.pointerLocation.y ?? -1; + + await this.zoomByDelta(newDelta, x, y, true); + + this.zoomingAnimationFrame = requestAnimationFrame(() => this.animateZooming(isZoomOut, zoomSpeed)); + } + // #endregion + + + // #region Public functions + public async loadHtmlContent(html: string) { + this.#isContentElDOMChanged = false; + this.boxContentEl.innerHTML = html; + + while (!this.#isContentElDOMChanged) { + await pause(10); + } + + const list = this.boxContentEl.querySelectorAll('img'); + const imgs = Array.from(list); + + while (imgs.some((i) => !i.complete)) { + await pause(10); + } + + // emit event onContentReady + this.#options.onContentReady(); + } + + public async startPanningAnimation(direction: PanDirection, panSpeed = 20) { + if (this.isPanning) return; + + this.isPanning = true; + this.animatePanning(direction, panSpeed); + } + + public stopPanningAnimation() { + cancelAnimationFrame(this.panningAnimationFrame); + this.isPanning = false; + } + + public async startZoomingAnimation(isZoomOut: boolean, zoomSpeed = 20) { + if (this.isZooming) return; + + this.isZooming = true; + this.animateZooming(isZoomOut, zoomSpeed); + } + + public stopZoomingAnimation() { + cancelAnimationFrame(this.zoomingAnimationFrame); + this.isZooming = false; + } + + public async recenter(duration?: number) { + const { x, y } = this.getCenterPoint(this.#options.zoomFactor); + this.domMatrix.e = x; + this.domMatrix.f = y; + + await this.applyTransform(duration); + } + + public panToDistance(dx = 0, dy = 0, duration?: number) { + const x = this.domMatrix.e + dx; + const y = this.domMatrix.f + dy; + + return this.panTo(x, y, duration); + } + + public async panTo(x: number, y: number, duration?: number) { + const boxBounds = this.boxEl.getBoundingClientRect(); + const contentBounds = this.boxContentEl.getBoundingClientRect(); + let newX = x; + let newY = y; + + const scaledPadding = this.padding.multiply(1 / this.scaleRatio); + + // left bound + if (newX > scaledPadding.left) newX = scaledPadding.left; + + // right bound + if (newX + contentBounds.width < boxBounds.right - scaledPadding.right) newX = this.domMatrix.e; + + // top bound + if (newY > scaledPadding.top) newY = scaledPadding.top; + + // bottom bound + if (newY + contentBounds.height < boxBounds.bottom - scaledPadding.bottom) newY = this.domMatrix.f; + + this.domMatrix.e = newX; + this.domMatrix.f = newY; + + this.#options.onPanning(newX, newY); + await this.applyTransform(duration); + } + + public async zoomByDelta( + delta: number, // zoom in: delta > 1, zoom out: delta < 1 + pageX?: number, + pageY?: number, + isManualZoom = false, + duration: number = 0, + ) { + if (!this.#options.allowZoom) return; + + const oldZoom = this.#options.zoomFactor * this.scaleRatio; + const newZoom = oldZoom * delta; + + const x = (pageX ?? this.boxEl.offsetLeft) - this.boxEl.offsetLeft; + const y = (pageY ?? this.boxEl.offsetTop) - this.boxEl.offsetTop; + + return this.zoomToPoint(newZoom, { + x, y, + duration, + isManualZoom, + useDelta: true, + isZoomModeChanged: false, + }); + } + + public async setZoomMode(mode: ZoomMode = ZoomMode.AutoZoom, zoomLockFactor = -1, duration = 0) { + const fullW = this.boxContentEl.scrollWidth / this.scaleRatio; + const fullH = this.boxContentEl.scrollHeight / this.scaleRatio; + if (fullW === 0 || fullH === 0) return; + + const scaledPadding = this.padding.multiply(1 / this.scaleRatio); + const widthScale = (this.boxEl.clientWidth - scaledPadding.horizontal) / fullW; + const heightScale = (this.boxEl.clientHeight - scaledPadding.vertical) / fullH; + let zoomFactor = 1; + + if (mode === ZoomMode.ScaleToWidth) { + zoomFactor = widthScale; + } + else if (mode === ZoomMode.ScaleToHeight) { + zoomFactor = heightScale; + } + else if (mode === ZoomMode.ScaleToFit) { + zoomFactor = Math.min(widthScale, heightScale); + } + else if (mode === ZoomMode.ScaleToFill) { + zoomFactor = Math.max(widthScale, heightScale); + } + else if (mode === ZoomMode.LockZoom) { + zoomFactor = zoomLockFactor > 0 ? zoomLockFactor : this.zoomFactor; + } + // AutoZoom + else { + // viewport size >= content size + if (widthScale >= 1 && heightScale >= 1) { + zoomFactor = 1; // show original size + } + else { + zoomFactor = Math.min(widthScale, heightScale); + } + } + + this.zoomToCenter(zoomFactor, { + isManualZoom: false, + duration, + isZoomModeChanged: true, + }); + } + + public async zoomToCenter(factor: number, options: { + isManualZoom?: boolean, + duration?: number, + isZoomModeChanged?: boolean, + } = {}) { + const fullW = this.boxContentEl.scrollWidth / this.scaleRatio * factor; + const fullH = this.boxContentEl.scrollHeight / this.scaleRatio * factor; + const scaledPadding = this.padding.multiply(1 / this.scaleRatio); + + // center point + const x = (this.boxEl.offsetWidth - fullW) / 2 + scaledPadding.left / 2 - scaledPadding.right / 2; + const y = (this.boxEl.offsetHeight - fullH) / 2 + scaledPadding.top / 2 - scaledPadding.bottom / 2; + + // change zoom factor + this.zoomToPoint(factor, { + x, y, + duration: options.duration, + isManualZoom: options.isManualZoom, + isZoomModeChanged: options.isZoomModeChanged, + }); + } + + public async zoomToPoint(factor: number, options: { + x?: number, + y?: number, + duration?: number, + useDelta?: boolean, + isManualZoom?: boolean, + isZoomModeChanged?: boolean, + } = {}) { + let { x, y } = options; + let newZoomFactor = this.dpi(factor); + const oldZoomFactor = this.#options.zoomFactor; + const needRecenter = this.checkIfNeedRecenter(); + + // when useDelta = false, we must set an init location for the matrix + const setInitLocation = !(options.useDelta ?? true); + + // restrict the zoom factor + newZoomFactor = Math.min( + Math.max(this.#options.minZoom, newZoomFactor), + this.#options.maxZoom, + ); + + // raise event onBeforeZoomChanged + this.#options.onBeforeZoomChanged({ + zoomFactor: this.zoomFactor, + x: this.domMatrix.e, + y: this.domMatrix.f, + isManualZoom: options.isManualZoom || false, + isZoomModeChanged: options.isZoomModeChanged || false, + }); + + // recenter the content + if (needRecenter) { + const center = this.getCenterPoint(newZoomFactor); + x = center.x; + y = center.y; + } + + // use delta to transform the matrix + const delta = newZoomFactor / oldZoomFactor; + this.#options.zoomFactor = newZoomFactor; + + if (setInitLocation || needRecenter) { + this.domMatrix.e = x; + this.domMatrix.f = y; + } + + // apply scale and translate value using zoom delta value + this.domMatrix = new DOMMatrix() + .translateSelf(x, y) + .scaleSelf(delta) + .translateSelf(-x, -y) + .multiplySelf(this.domMatrix); + + this.updateImageRendering(); + await this.applyTransform(options.duration); + + // raise event onAfterZoomChanged + this.#options.onAfterZoomChanged({ + zoomFactor: this.zoomFactor, + x: this.domMatrix.e, + y: this.domMatrix.f, + isManualZoom: options.isManualZoom || false, + isZoomModeChanged: options.isZoomModeChanged || false, + }); + + // raise event onContentSizeChanged + const bound = this.boxContentEl.getBoundingClientRect(); + this.#options.onContentSizeChanged(bound); + } + + public async applyTransform(duration = 0) { + await new Promise((resolve) => { + this.boxContentEl.style.transform = `${this.domMatrix.toString()}`; + + // apply animation + if (duration > 0) { + const transition = `transform ${duration}ms ease, opacity ${duration}ms ease`; + this.boxContentEl.style.transition = transition; + + setTimeout(resolve, duration); + } + else { + this.boxContentEl.style.transition = ''; + resolve(undefined); + } + }); + + // raise event + this.#options.onAfterTransformed(this.domMatrix); + } + + public enable() { + this.applyTransform(); + + this.#resizeObserver.observe(this.boxEl); + this.#contentDOMObserver.observe(this.boxContentEl, { + attributes: false, + childList: true, + }); + + this.boxEl.addEventListener('wheel', this.onMouseWheel, { passive: true }); + + this.boxEl.addEventListener('pointerenter', this.onPointerEnter); + this.boxEl.addEventListener('pointerleave', this.onPointerLeave); + this.boxEl.addEventListener('pointerdown', this.onPointerDown); + this.boxEl.addEventListener('pointerup', this.onPointerUp); + this.boxEl.addEventListener('pointermove', this.onPointerMove); + + // this.boxEl.addEventListener('keydown', this.onKeyDown); + // this.boxEl.addEventListener('keyup', this.onKeyUp); + } + + public disable() { + this.#resizeObserver.disconnect(); + this.#contentDOMObserver.disconnect(); + + this.boxEl.removeEventListener('mousewheel', this.onMouseWheel); + + this.boxEl.removeEventListener('pointerenter', this.onPointerEnter); + this.boxEl.removeEventListener('pointerleave', this.onPointerLeave); + this.boxEl.removeEventListener('pointerdown', this.onPointerDown); + this.boxEl.removeEventListener('pointerup', this.onPointerUp); + this.boxEl.removeEventListener('pointermove', this.onPointerMove); + + // this.boxEl.removeEventListener('keydown', this.onKeyDown); + // this.boxEl.removeEventListener('keyup', this.onKeyUp); + } + // #endregion +} + + +export default { HapplaBox }; diff --git a/Source/Components/ImageGlass.Settings/WebUI/src/DXCanvas_Webview2/webComponents/happlajs/HapplaBoxTypes.ts b/Source/Components/ImageGlass.Settings/WebUI/src/DXCanvas_Webview2/webComponents/happlajs/HapplaBoxTypes.ts new file mode 100644 index 000000000..5aadda608 --- /dev/null +++ b/Source/Components/ImageGlass.Settings/WebUI/src/DXCanvas_Webview2/webComponents/happlajs/HapplaBoxTypes.ts @@ -0,0 +1,75 @@ +import { DOMPadding } from './DOMPadding'; + +export type IMouseEventArgs = { + Dpi: number; + Button: number; + X: number; + Y: number; + Delta: number; + NavigationButton?: 'left' | 'right' | ''; +}; + +export type IZoomEventArgs = { + zoomFactor: number, + x: number, + y: number, + isManualZoom: boolean, + isZoomModeChanged: boolean, +}; + +export type ZoomEventFunction = (e: IZoomEventArgs) => void; +export type TransformEventFunction = (matrix: DOMMatrix) => void; +export type PanEventFunction = (x: number, y: number) => void; +export type PanDirection = 'left' | 'right' | 'up' | 'down'; + +export enum InterpolationMode { + Pixelated = 'pixelated', + Auto = 'auto', + CrispEdges = 'auto', // 'crisp-edges', +} + +export enum ZoomMode { + AutoZoom = 'AutoZoom', + LockZoom = 'LockZoom', + ScaleToWidth = 'ScaleToWidth', + ScaleToHeight = 'ScaleToHeight', + ScaleToFit = 'ScaleToFit', + ScaleToFill = 'ScaleToFill', +} + +export type ILoadContentRequestedEventArgs = { + ZoomMode: ZoomMode, + ZoomFactor: number, + FilePath: string, + DirPath: string, + Html?: string, + Url?: string, +}; + + +export interface IHapplaBoxOptions { + allowZoom?: boolean; + zoomFactor?: number; + minZoom?: number; + maxZoom?: number; + + allowPan?: boolean; + panOffset?: DOMPoint; + + imageRendering?: InterpolationMode; + scaleRatio?: number; + padding?: DOMPadding, + + onBeforeContentReady?: () => void; + onContentReady?: () => void; + onContentSizeChanged?: (e: DOMRect) => void; + onResizing?: () => void; + onMouseWheel?: (e: WheelEvent) => void; + + onBeforeZoomChanged?: ZoomEventFunction; + onAfterZoomChanged?: ZoomEventFunction; + onAfterTransformed?: TransformEventFunction; + + onPanning?: PanEventFunction; + onAfterPanned?: PanEventFunction; +} diff --git a/Source/Components/ImageGlass.Settings/WebUI/src/FrmAbout.ts b/Source/Components/ImageGlass.Settings/WebUI/src/FrmAbout.ts new file mode 100644 index 000000000..8182f14b6 --- /dev/null +++ b/Source/Components/ImageGlass.Settings/WebUI/src/FrmAbout.ts @@ -0,0 +1,42 @@ +import './main'; + + +const onButtonClicked = (e: Event) => { + e.preventDefault(); + e.stopPropagation(); + const btnEl = e.target as HTMLButtonElement; + + post(btnEl.id); +}; + +query('#BtnImageGlassStore').addEventListener('click', onButtonClicked, false); +query('#BtnCheckForUpdate').addEventListener('click', onButtonClicked, false); +query('#BtnDonate').addEventListener('click', onButtonClicked, false); +query('#BtnClose').addEventListener('click', onButtonClicked, false); +queryAll('[data-license]').forEach(el => { + el.addEventListener('click', () => post('ViewLicenseFile', el.getAttribute('data-license')), false); +}); + +query('#BtnCheckForUpdate').focus(); + + +window._page.loadData = (data: Record = {}) => { + console.info('🔵 Loading data', data); + + query('#Lbl_CopyrightsYear').innerText = `2010-${new Date().getUTCFullYear()}`; + + query('#Img_AppLogo').setAttribute('src', data.AppLogo || ''); + query('#Img_AppLogo').toggleAttribute('hidden', false); + query('#Img_AppLogo').addEventListener('click', async () => { + const isNotEnabled = !query('#app').style.filter; + query('#app').style.filter = isNotEnabled ? 'url("#effectWaving")' : ''; + }); + + query('#Lbl_AppCode').innerText = data.AppCode || ''; + query('#Lbl_AppVersion').innerText = data.AppVersion || ''; + query('#Lbl_AppArchitecture').innerText = data.AppArchitecture || ''; + query('#Lbl_AppRuntime').innerText = data.AppRuntime || ''; + query('#Lbl_MagickNET').innerText = data.MagickNET || ''; + query('#Lbl_WebView2Runtime').innerText = data.WebView2Runtime || ''; +}; + diff --git a/Source/Components/ImageGlass.Settings/WebUI/src/FrmQuickSetup.ts b/Source/Components/ImageGlass.Settings/WebUI/src/FrmQuickSetup.ts new file mode 100644 index 000000000..fec378504 --- /dev/null +++ b/Source/Components/ImageGlass.Settings/WebUI/src/FrmQuickSetup.ts @@ -0,0 +1,129 @@ +import { ILanguage } from './@types/FrmSettings'; +import './main'; + +const _stepCount = queryAll('.page-content .step').length; +let _currentStep = 1; + +let _langList: ILanguage[] = []; +let _currentLang = ''; +let _loadLanguageTimer: any = null; + +// Navigates to step +const goToStep = (stepNumber: number) => { + _currentStep = Math.max(1, Math.min(stepNumber, _stepCount)); + const isLastStep = _currentStep >= _stepCount; + + queryAll('.page-content .step').forEach(el => { + el.hidden = el.getAttribute('step') !== `${_currentStep}`; + }); + + query('#LblStepInfo').innerText = `${_currentStep}/${_stepCount}`; + query('#BtnNext').innerText = _page.lang[isLastStep ? '_._Save' : '_._Next'] || '[Next]'; + query('#BtnBack').hidden = _currentStep <= 1; +}; + + +// Loads language list to select box. +const loadLanguageList = () => { + const selectEl = query('#Cmb_LanguageList'); + + // clear current list + while (selectEl.options.length) selectEl.remove(0); + + _langList.forEach((lang: ILanguage) => { + let displayText = `${lang.Metadata.LocalName} (${lang.Metadata.EnglishName})`; + if (!lang.FileName || lang.FileName.length === 0) { + displayText = lang.Metadata.EnglishName; + } + + const optionEl = new Option(displayText, lang.FileName); + selectEl.add(optionEl); + }); + + selectEl.value = _currentLang; +}; + + +// Loads language +const requestToUpdateLanguage = async (langName: string) => { + _currentLang = langName; + await postAsync('LOAD_LANGUAGE', _currentLang); +}; + + +// delays loading language +const delayRequestToUpdateLanguage = (langName: string) => { + clearTimeout(_loadLanguageTimer); + + return new Promise((resolve) => { + _loadLanguageTimer = setTimeout(async () => { + clearTimeout(_loadLanguageTimer); + + await requestToUpdateLanguage(langName); + resolve(undefined); + }, 100); + }); +}; + + +// load initial data +window._page.loadData = (data: Record = {}) => { + console.info('🔵 Loading data', data); + + _currentLang = data.currentLangName; + _langList = data.langList || []; + loadLanguageList(); + + query('#Img_AppLogo').setAttribute('src', data.appLogo || ''); + query('#Img_AppLogo').toggleAttribute('hidden', false); +}; + + +// setting profile options +queryAll('[name="_SettingProfile"]').forEach(el => { + el.addEventListener('change', () => { + const profileName = query('[name="_SettingProfile"]:checked').value; + const isProfessional = profileName === 'professional'; + + query('#ChkColorProfile').checked = isProfessional; + query('#ChkShouldUseExplorerSortOrder').checked = isProfessional; + query('#ChkUseEmbeddedThumbnailRawFormats').checked = !isProfessional; + }); +}); + + +// language option +query('#Cmb_LanguageList').addEventListener('change', (e) => { + delayRequestToUpdateLanguage((e.target as HTMLInputElement).value); +}, false); + + +// default viewer +query('#BtnSetDefaultViewer').addEventListener('click', () => post('SET_DEFAULT_VIEWER'), false); + + +// footer actions +query('#LnkSkip').addEventListener('click', () => post('SKIP_AND_LAUNCH'), false); +query('#BtnBack').addEventListener('click', () => { + _currentStep--; + goToStep(_currentStep); +}, false); + +query('#BtnNext').addEventListener('click', () => { + if (_currentStep >= _stepCount) { + const enableColorProfile = query('#ChkColorProfile').checked; + const shouldUseExplorerSortOrder = query('#ChkShouldUseExplorerSortOrder').checked; + const useThumbnailRawFormats = query('#ChkUseEmbeddedThumbnailRawFormats').checked; + + post('APPLY_SETTINGS', { + Language: _currentLang, + ColorProfile: enableColorProfile, + ShouldUseExplorerSortOrder: shouldUseExplorerSortOrder, + UseEmbeddedThumbnailRawFormats: useThumbnailRawFormats, + }, true); + } + else { + _currentStep++; + goToStep(_currentStep); + } +}, false); diff --git a/Source/Components/ImageGlass.Settings/WebUI/src/FrmSettings.ts b/Source/Components/ImageGlass.Settings/WebUI/src/FrmSettings.ts new file mode 100644 index 000000000..23984b51f --- /dev/null +++ b/Source/Components/ImageGlass.Settings/WebUI/src/FrmSettings.ts @@ -0,0 +1,68 @@ +import './main'; + +import Sidebar from './FrmSettings/Sidebar'; +import Settings from './FrmSettings/Settings'; +import TabAppearance from './FrmSettings/TabAppearance'; +import { defineEditAppDialogHtmlElement } from './FrmSettings/webComponents/EditAppDialogHtmlElement'; +import { defineToolDialogHtmlElement } from './FrmSettings/webComponents/ToolDialogHtmlElement'; +import { defineToolbarEditorHtmlElement } from './FrmSettings/webComponents/ToolbarEditorHtmlElement'; +import { defineToolbarButtonEditDialogHtmlElement } from './FrmSettings/webComponents/ToolbarButtonEditDialogHtmlElement'; +import { defineFileFormatDialogHtmlElement } from './FrmSettings/webComponents/FileFormatDialogHtmlElement'; + + +if (!window._pageSettings) { + window._pageSettings = { + config: {}, + langList: [], + toolList: [], + themeList: [], + builtInToolbarButtons: [], + enums: { + ImageOrderBy: [], + ImageOrderType: [], + ColorProfileOption: [], + AfterEditAppAction: [], + ImageInterpolation: [], + MouseWheelAction: [], + MouseWheelEvent: [], + MouseClickEvent: [], + BackdropStyle: [], + ToolbarItemModelType: [], + ImageInfoUpdateTypes: [], + }, + icons: { + Delete: '', + Edit: '', + ArrowDown: '', + ArrowUp: '', + ArrowLeft: '', + ArrowRight: '', + ArrowExchange: '', + Moon: '', + Sun: '', + Info: '', + Warning: '', + }, + startUpDir: '', + configDir: '', + userConfigFilePath: '', + defaultThemeDir: '', + defaultImageInfoTags: [], + FILE_MACRO: '', + }; +} +_page.loadSettings = Settings.load; +_page.setActiveMenu = Sidebar.setActiveMenu; +_page.loadBackgroundColorConfig = TabAppearance.loadBackgroundColorConfig; + + +// register web components +defineEditAppDialogHtmlElement(); +defineToolDialogHtmlElement(); +defineToolbarEditorHtmlElement(); +defineToolbarButtonEditDialogHtmlElement(); +defineFileFormatDialogHtmlElement(); + + +// sidebar +Sidebar.addEvents(); diff --git a/Source/Components/ImageGlass.Settings/WebUI/src/FrmSettings/Settings.ts b/Source/Components/ImageGlass.Settings/WebUI/src/FrmSettings/Settings.ts new file mode 100644 index 000000000..37846f34c --- /dev/null +++ b/Source/Components/ImageGlass.Settings/WebUI/src/FrmSettings/Settings.ts @@ -0,0 +1,229 @@ +import TabGeneral from './TabGeneral'; +import TabImage from './TabImage'; +import TabSlideshow from './TabSlideshow'; +import TabMouse from './TabMouse'; +import TabKeyboard from './TabKeyboard'; +import TabLanguage from './TabLanguage'; +import TabEdit from './TabEdit'; +import TabViewer from './TabViewer'; +import TabToolbar from './TabToolbar'; +import TabGallery from './TabGallery'; +import TabFileAssocs from './TabFileAssocs'; +import TabTools from './TabTools'; +import TabAppearance from './TabAppearance'; +import TabLayout from './TabLayout'; + +export default class Settings { + /** + * Loads settings. + */ + static load() { + console.info('🔵 Loading settings from `_pageSettings.config`'); + + Settings.loadSelectBoxEnums(); + TabLanguage.loadLanguageList(); + + + // auto loads settings for String, Number, Boolean + for (const configKey in _pageSettings.config) { + if (!Object.prototype.hasOwnProperty.call(_pageSettings.config, configKey)) { + continue; + } + + const configValue = _pageSettings.config[configKey]; + + // only auto load the settings if the value type is supported + const canAutoSet = typeof configValue === 'string' + || typeof configValue === 'number' + || typeof configValue === 'boolean'; + if (!canAutoSet) continue; + + + // find the html element + const el = query(`[name="${configKey}"]`, null, true); + if (!el) { + console.info(`🔵 >> Settings.load(): config '${configKey}' not found`); + continue; + } + + + // check the tag name and type + const tagName = el.tagName.toLowerCase(); + if (tagName === 'select') { + (el as HTMLSelectElement).value = configValue.toString(); + } + else if (tagName === 'input') { + const inputType = el.getAttribute('type').toLowerCase(); + const inputEl = el as HTMLInputElement; + + if (inputType === 'radio' || inputType === 'checkbox') { + inputEl.checked = Boolean(configValue); + } + else if (inputType === 'color') { + const colorHex = configValue.toString() || '#00000000'; + + // remove alpha + inputEl.value = colorHex.substring(0, colorHex.length - 2); + } + else { + inputEl.value = configValue.toString(); + } + } + } + + + // load icon element: + queryAll('i[icon]').forEach(el => { + const iconName = el.getAttribute('icon'); + const iconSvg = _pageSettings.icons[iconName]; + + if (iconSvg) { + el.innerHTML = iconSvg; + } + }); + + + // load specific settings + TabGeneral.loadSettings(); + TabImage.loadSettings(); + TabSlideshow.loadSettings(); + TabEdit.loadSettings(); + + TabLayout.loadSettings(); + TabViewer.loadSettings(); + TabToolbar.loadSettings(); + TabGallery.loadSettings(); + + TabMouse.loadSettings(); + TabKeyboard.loadSettings(); + TabFileAssocs.loadSettings(); + TabTools.loadSettings(); + TabLanguage.loadSettings(); + TabAppearance.loadSettings(); + + // Adds event listeners for all settings. + Settings.addEventListeners(); + } + + + /** + * Adds event listeners for all settings. + */ + private static addEventListeners() { + Settings.addGeneralEvents(); + + TabGeneral.addEvents(); + TabImage.addEvents(); + TabSlideshow.addEvents(); + TabEdit.addEvents(); + + TabLayout.addEvents(); + TabViewer.addEvents(); + TabToolbar.addEvents(); + TabGallery.addEvents(); + + TabMouse.addEvents(); + TabFileAssocs.addEvents(); + TabTools.addEvents(); + TabLanguage.addEvents(); + TabAppearance.addEvents(); + } + + + /** + * Adds general events for the setting. + */ + private static addGeneralEvents() { + query('#LnkHelp').addEventListener('click', () => post('LnkHelp'), false); + query('#LnkResetSettings').addEventListener('click', () => post('LnkResetSettings'), false); + + query('#BtnCancel').addEventListener('click', () => post('BtnCancel'), false); + + query('#BtnOK').addEventListener('click', () => { + const allSettings = Settings.getAllSettings(); + Settings.updateInitSettings(allSettings); + + post('BtnOK', allSettings, true); + }, false); + + query('#BtnApply').addEventListener('click', () => { + const allSettings = Settings.getAllSettings(); + Settings.updateInitSettings(allSettings); + + post('BtnApply', allSettings, true); + }, false); + } + + + /** + * Gets all settings as an object. + */ + static getAllSettings() { + console.info('🔵 Calling Settings.getAllSettings()'); + + const settings: Record = { + ...TabGeneral.exportSettings(), + ...TabImage.exportSettings(), + ...TabSlideshow.exportSettings(), + ...TabEdit.exportSettings(), + + ...TabLayout.exportSettings(), + ...TabViewer.exportSettings(), + ...TabToolbar.exportSettings(), + ...TabGallery.exportSettings(), + + ...TabMouse.exportSettings(), + ...TabKeyboard.exportSettings(), + ...TabFileAssocs.exportSettings(), + ...TabTools.exportSettings(), + ...TabLanguage.exportSettings(), + ...TabAppearance.exportSettings(), + }; + + return settings; + } + + + /** + * Updates the `_pageSettings.config`. + */ + static updateInitSettings(newSettings: Record) { + console.info('🔵 Calling Settings.updateInitSettings()'); + + const settingKeys = Object.keys(newSettings); + settingKeys.forEach(key => { + if (_pageSettings.config.hasOwnProperty(key)) { + _pageSettings.config[key] = newSettings[key]; + } + }); + + // update settings UI for some tabs + TabTools._areToolsChanged = false; + } + + + /** + * Loads select box items. + */ + private static loadSelectBoxEnums() { + // load enums + for (const enumName in _pageSettings.enums) { + if (!Object.prototype.hasOwnProperty.call(_pageSettings.enums, enumName)) { + continue; + } + + const enumKeys = _pageSettings.enums[enumName]; + const selectEls = queryAll(`select[data-enum="${enumName}"]`, null, true); + + for (const el of selectEls) { + enumKeys.forEach(key => { + const optionEl = new Option(`${key}`, key); + optionEl.setAttribute('lang-text', `_.${enumName}._${key}`); + + el.add(optionEl); + }); + } + } + } + +} diff --git a/Source/Components/ImageGlass.Settings/WebUI/src/FrmSettings/Sidebar.ts b/Source/Components/ImageGlass.Settings/WebUI/src/FrmSettings/Sidebar.ts new file mode 100644 index 000000000..c5fc285b4 --- /dev/null +++ b/Source/Components/ImageGlass.Settings/WebUI/src/FrmSettings/Sidebar.ts @@ -0,0 +1,51 @@ +import TabAppearance from './TabAppearance'; + +export default class Sidebar { + /** + * Adds click events to sidebar menu. + */ + static addEvents() { + // navigation bar event + const navItems = Array.from(document.querySelectorAll('input[name="nav"]')); + for (let i = 0; i < navItems.length; i++) { + const itemEl = navItems[i] as HTMLInputElement; + + itemEl.addEventListener('change', (e) => { + const activeTabName = (e.target as HTMLInputElement).value; + Sidebar.setActiveMenu(activeTabName); + }, false); + } + } + + + /** + * Set the active menu for sidebar + */ + static setActiveMenu(tabPageName: string) { + tabPageName ||= 'general'; + + const tabPageEl = query(`.tab-page[tab="${tabPageName}"]`); + if (!tabPageEl) return; + + // hide all tabs + const allTabPages = queryAll('.tab-page'); + allTabPages.forEach(el => el.classList.remove('active')); + + // show the selected tab + tabPageEl.classList.add('active'); + + // select the active nav item + const allNavItems = queryAll('input[type="radio"]'); + allNavItems.forEach((item: HTMLInputElement) => item.checked = false); + const navItem = query(`input[type="radio"][value="${tabPageName}"]`) as HTMLInputElement; + if (navItem) navItem.checked = true; + + if (tabPageName === 'appearance') { + TabAppearance.loadThemeListStatus(); + } + + // update backend tab name + post('Sidebar_Changed', tabPageName); + } + +} diff --git a/Source/Components/ImageGlass.Settings/WebUI/src/FrmSettings/TabAppearance.ts b/Source/Components/ImageGlass.Settings/WebUI/src/FrmSettings/TabAppearance.ts new file mode 100644 index 000000000..bb7027fd2 --- /dev/null +++ b/Source/Components/ImageGlass.Settings/WebUI/src/FrmSettings/TabAppearance.ts @@ -0,0 +1,249 @@ +import { ITheme } from '@/@types/FrmSettings'; +import { getChangedSettingsFromTab } from '@/helpers'; +import Language from '../common/Language'; + +export default class TabAppearance { + /** + * Gets current selected theme. + */ + static get currentTheme() { + return _pageSettings.themeList.find(i => i.FolderName === _page.theme); + } + + /** + * Loads settings for tab Appearance. + */ + static loadSettings() { + if (_page.isWindows10) { + query(`[name="WindowBackdrop"]`).setAttribute('disabled', 'true'); + } + + TabAppearance.loadThemeList(); + TabAppearance.loadThemeListStatus(); + TabAppearance.handleBackgroundColorChanged(); + } + + + /** + * Loads theme list check status + */ + static loadThemeListStatus() { + const darkTheme = query('[name="DarkTheme"]').value; + const lightTheme = query('[name="LightTheme"]').value; + + const darkEl = query(`[name="_DarkThemeOptions"][value="${darkTheme}"]`); + const lightEl = query(`[name="_LightThemeOptions"][value="${lightTheme}"]`); + if (darkEl) darkEl.checked = true; + if (lightEl) lightEl.checked = true; + } + + + /** + * Adds events for tab Appearance. + */ + static addEvents() { + // remove old events + query('#Lnk_ResetBackgroundColor').removeEventListener('click', TabAppearance.resetBackgroundColor, false); + query('#Btn_BackgroundColor').removeEventListener('click', TabAppearance.onBtn_BackgroundColor, false); + query('#Btn_InstallTheme').removeEventListener('click', TabAppearance.onBtn_InstallTheme, false); + query('#Btn_RefreshThemeList').removeEventListener('click', TabAppearance.onBtn_RefreshThemeList, false); + query('#Btn_OpenThemeFolder').removeEventListener('click', TabAppearance.onBtn_OpenThemeFolder, false); + + // add new events + query('#Lnk_ResetBackgroundColor').addEventListener('click', TabAppearance.resetBackgroundColor, false); + query('#Btn_BackgroundColor').addEventListener('click', TabAppearance.onBtn_BackgroundColor, false); + query('#Btn_InstallTheme').addEventListener('click', TabAppearance.onBtn_InstallTheme, false); + query('#Btn_RefreshThemeList').addEventListener('click', TabAppearance.onBtn_RefreshThemeList, false); + query('#Btn_OpenThemeFolder').addEventListener('click', TabAppearance.onBtn_OpenThemeFolder, false); + } + + + /** + * Save settings as JSON object. + */ + static exportSettings() { + const settings = getChangedSettingsFromTab('appearance'); + + // DarkTheme + settings.DarkTheme = query('[name="DarkTheme"]').value; + if (settings.DarkTheme === _pageSettings.config.DarkTheme) { + delete settings.DarkTheme; + } + + // LightTheme + settings.LightTheme = query('[name="LightTheme"]').value; + if (settings.LightTheme === _pageSettings.config.LightTheme) { + delete settings.LightTheme; + } + + return settings; + } + + + /** + * Updates `_pageSettings.config.BackgroundColor` value and load UI. + */ + static loadBackgroundColorConfig(hexColor: string) { + _pageSettings.config.BackgroundColor = hexColor; + query('[name="BackgroundColor"]').value = hexColor; + TabAppearance.handleBackgroundColorChanged(); + } + + + /** + * Loads all themes into the list. + */ + private static loadThemeList(list?: ITheme[]) { + if (Array.isArray(list) && list.length > 0) { + _pageSettings.themeList = list; + } + const themeList = _pageSettings.themeList || []; + + const ulEl = query('#List_ThemeList'); + let ulHtml = ''; + + for (const th of themeList) { + const liHtml = ` +
  • +
    +
    +
    + ${th.Info.Name} + + ${th.IsDarkMode ? '🌙' : '☀️'} + +
    +
    +
    +
    + ${th.Info.Name} + ${th.Info.Version} +
    +
    ${th.Info.Description}
    +
    + + [Author]: + ${th.Info.Author || '?'} + + + [Website]: + ${th.Info.Website || '?'} + + + [Email]: + ${th.Info.Email || '?'} + +
    +
    + + + + +
    +
    +
    +
  • `; + + ulHtml += liHtml; + } + + ulEl.innerHTML = ulHtml; + Language.loadForEl(ulEl); + TabAppearance.loadThemeListStatus(); + + queryAll('[name="_DarkThemeOptions"]').forEach(el => { + el.addEventListener('change', (e) => { + const themeName = (e.target as HTMLInputElement).value; + query('[name="DarkTheme"]').value = themeName; + }, false); + }); + + queryAll('[name="_LightThemeOptions"]').forEach(el => { + el.addEventListener('change', (e) => { + const themeName = (e.target as HTMLInputElement).value; + query('[name="LightTheme"]').value = themeName; + }, false); + }); + + queryAll('[data-delete-theme]').forEach(el => { + el.addEventListener('click', async (e) => { + const themeDir = (e.target as HTMLButtonElement).getAttribute('data-delete-theme'); + + const newThemeList = await postAsync('Delete_Theme_Pack', themeDir); + TabAppearance.loadThemeList(newThemeList); + }, false); + }); + } + + + /** + * Resets the background color to the current theme's background color. + */ + private static resetBackgroundColor() { + if (!TabAppearance.currentTheme) return; + + const colorHex = TabAppearance.currentTheme.BgColor || '#00000000'; + + query('[name="BackgroundColor"]').value = colorHex; + TabAppearance.handleBackgroundColorChanged(); + } + + + /** + * Handles when `BackgroundColor` is changed. + */ + private static handleBackgroundColorChanged() { + let colorHex = query('[name="BackgroundColor"]').value; + if (!colorHex) { + colorHex = TabAppearance.currentTheme.BgColor; + } + + query('#Btn_BackgroundColor > .color-display').style.setProperty('--color-picker-value', colorHex); + query('#Lbl_BackgroundColorValue').innerText = colorHex; + } + + private static async onBtn_BackgroundColor() { + const colorEl = query('[name="BackgroundColor"]'); + const colorHex = colorEl.value || TabAppearance.currentTheme.BgColor; + + const newColorHex = await postAsync('Btn_BackgroundColor', colorHex); + + if (newColorHex && newColorHex !== colorHex) { + colorEl.value = newColorHex; + TabAppearance.handleBackgroundColorChanged(); + } + } + + private static async onBtn_InstallTheme() { + const newThemeList = await postAsync('Btn_InstallTheme'); + TabAppearance.loadThemeList(newThemeList); + } + + private static async onBtn_RefreshThemeList() { + const newThemeList = await postAsync('Btn_RefreshThemeList'); + TabAppearance.loadThemeList(newThemeList); + } + + private static onBtn_OpenThemeFolder() { + post('Btn_OpenThemeFolder'); + } + +} diff --git a/Source/Components/ImageGlass.Settings/WebUI/src/FrmSettings/TabEdit.ts b/Source/Components/ImageGlass.Settings/WebUI/src/FrmSettings/TabEdit.ts new file mode 100644 index 000000000..c102dbe39 --- /dev/null +++ b/Source/Components/ImageGlass.Settings/WebUI/src/FrmSettings/TabEdit.ts @@ -0,0 +1,183 @@ +import { IEditApp } from '@/@types/FrmSettings'; +import Language from '@/common/Language'; +import { escapeHtml, getChangedSettingsFromTab, pause } from '@/helpers'; +import { EditAppDialogHtmlElement } from './webComponents/EditAppDialogHtmlElement'; + + +export default class TabEdit { + static _areEditAppsChanged = false; + static #editAppDialog = query('[is="edit-app-dialog"]'); + + /** + * Loads settings for tab Edit. + */ + static loadSettings() { + TabEdit.loadEditApps(); + } + + + /** + * Adds events for tab Edit. + */ + static addEvents() { + query('#Btn_AddEditApp').addEventListener('click', () => TabEdit.openEditAppDialog(), false); + } + + + /** + * Save settings as JSON object. + */ + static exportSettings() { + const settings = getChangedSettingsFromTab('edit'); + + if (TabEdit._areEditAppsChanged) { + // get new EditApps settings + settings.EditApps = TabEdit.getEditAppsFromDom(); + } + else { + delete settings.EditApps; + } + + return settings; + } + + + // Loads edit app list but do not update `_pageSettings.config.EditApps` + private static loadEditApps(apps?: Record, extKeyHighlight = '') { + const editApps = apps || _pageSettings.config.EditApps || {}; + const extensions = Object.keys(editApps).sort(); + + const tbodyEl = query('#Table_EditApps > tbody'); + let tbodyHtml = ''; + + for (const extKey of extensions) { + const item = editApps[extKey]; + if (!item) continue; + + let args = ''; + if (item.Argument) { + args = `${escapeHtml(item.Argument)}`; + } + + const trHtml = ` + + + + + + + + ${escapeHtml(extKey)} + + ${item.AppName} + + ${escapeHtml(item.Executable)} + + ${args} + + + + + + `; + + tbodyHtml += trHtml; + } + + tbodyEl.innerHTML = tbodyHtml; + Language.loadForEl(tbodyEl); + + queryAll('#Table_EditApps button[data-action]').forEach(el => { + el.addEventListener('click', async () => { + const action = el.getAttribute('data-action'); + const trEl = el.closest('tr'); + const extKey = trEl.getAttribute('data-extkey'); + + if (action === 'delete') { + trEl.remove(); + TabEdit._areEditAppsChanged = true; + } + else if (action === 'edit') { + await TabEdit.openEditAppDialog(extKey); + el.focus(); + } + }, false); + }); + + + // scroll to & highlight the extension row + if (extKeyHighlight) { + const highlightedTrEl = query(`#Table_EditApps tr[data-extkey="${extKeyHighlight}"]`); + if (!highlightedTrEl) return; + + highlightedTrEl.scrollIntoView({ block: 'center', behavior: 'smooth' }); + highlightedTrEl.classList.add('row--highlight'); + pause(2000).then(() => { + if (highlightedTrEl) highlightedTrEl.classList.remove('row--highlight'); + }); + } + } + + + // Gets edit app list from DOM + private static getEditAppsFromDom() { + const trEls = queryAll('#Table_EditApps > tbody > tr'); + const editApps: Record = {}; + + trEls.forEach(trEl => { + const extKey = trEl.getAttribute('data-extkey') || ''; + const appName = query('[name="_AppName"]', trEl).innerText || ''; + const appExecutable = query('[name="_Executable"]', trEl).innerText || ''; + const appArgument = query('[name="_Argument"]', trEl).innerText || ''; + + editApps[extKey] = { + AppName: appName, + Executable: appExecutable, + Argument: appArgument, + }; + }); + + return editApps; + } + + + private static async openEditAppDialog(extKey?: string) { + let isSubmitted = false; + + if (extKey) { + isSubmitted = await TabEdit.#editAppDialog.openEdit(extKey); + } + else { + isSubmitted = await TabEdit.#editAppDialog.openCreate(); + } + + if (isSubmitted) { + TabEdit._areEditAppsChanged = true; + + const data = TabEdit.#editAppDialog.getDialogData(); + TabEdit.setEditAppToList(data.app, data.extKey, extKey); + } + } + + + /** + * Sets the edit app to the list. + * @param oldExtKey If not found, the app will be inserted into the list. + */ + private static setEditAppToList(app: IEditApp, newExtKey: string, oldExtKey?: string) { + if (!app.AppName || !app.Executable) return; + const editApps = TabEdit.getEditAppsFromDom(); + + // edit + if (oldExtKey) { + delete editApps[oldExtKey]; + } + + editApps[newExtKey] = app; + TabEdit.loadEditApps(editApps, newExtKey); + } +} diff --git a/Source/Components/ImageGlass.Settings/WebUI/src/FrmSettings/TabFileAssocs.ts b/Source/Components/ImageGlass.Settings/WebUI/src/FrmSettings/TabFileAssocs.ts new file mode 100644 index 000000000..712a10247 --- /dev/null +++ b/Source/Components/ImageGlass.Settings/WebUI/src/FrmSettings/TabFileAssocs.ts @@ -0,0 +1,172 @@ +import Language from '@/common/Language'; +import { escapeHtml, getChangedSettingsFromTab, pause } from '@/helpers'; +import { FileFormatDialogHtmlElement } from './webComponents/FileFormatDialogHtmlElement'; + +export default class TabFileAssocs { + static _areFileFormatsChanged = false; + static #fileFormatDialog = query('[is="file-format-dialog"]'); + + /** + * Loads settings for tab FileAssocs. + */ + static loadSettings() { + TabFileAssocs.loadFileFormatList(); + } + + + /** + * Adds events for tab FileAssocs. + */ + static addEvents() { + query('#Btn_OpenExtIconFolder').addEventListener('click', TabFileAssocs.onBtn_OpenExtIconFolderClicked, false); + + query('#Btn_MakeDefaultViewer').addEventListener('click', TabFileAssocs.onBtn_MakeDefaultViewerClicked, false); + query('#Btn_RemoveDefaultViewer').addEventListener('click', TabFileAssocs.onBtn_RemoveDefaultViewerClicked, false); + query('#Lnk_OpenDefaultAppsSetting').addEventListener('click', TabFileAssocs.onLnk_OpenDefaultAppsSettingClicked, false); + + query('#Btn_AddFileFormat').addEventListener('click', () => TabFileAssocs.openFileFormatDialog(), false); + query('#Btn_ResetFileFormats').addEventListener('click', TabFileAssocs.onBtn_ResetFileFormatsClicked, false); + } + + + /** + * Save settings as JSON object. + */ + static exportSettings() { + const settings = getChangedSettingsFromTab('file_assocs'); + + if (TabFileAssocs._areFileFormatsChanged) { + // get new formats settings + settings.FileFormats = TabFileAssocs.getFileFormatListFromDom().join(';'); + } + else { + delete settings.FileFormats; + } + + return settings; + } + + private static onBtn_OpenExtIconFolderClicked() { + post('Btn_OpenExtIconFolder'); + } + + private static onBtn_MakeDefaultViewerClicked() { + post('Btn_MakeDefaultViewer'); + } + + private static onBtn_RemoveDefaultViewerClicked() { + post('Btn_RemoveDefaultViewer'); + } + + private static onLnk_OpenDefaultAppsSettingClicked() { + post('Lnk_OpenDefaultAppsSetting'); + } + + private static async onBtn_ResetFileFormatsClicked() { + const extStr = await postAsync('Btn_ResetFileFormats') || ''; + const exts = extStr.split(';').sort(); + + TabFileAssocs._areFileFormatsChanged = true; + TabFileAssocs.loadFileFormatList(exts); + } + + + // Loads formats list but do not update `_pageSettings.config.FileFormats`. + private static loadFileFormatList(extensions?: string[], extHighlight = '') { + let exts = extensions + || (_pageSettings.config.FileFormats as string || '').split(';').filter(Boolean) + || []; + exts = exts.sort(); + + const tbodyEl = query('#Table_FileFormats > tbody'); + let tbodyHtml = ''; + + for (const ext of exts) { + const trHtml = ` + + + + + ${escapeHtml(ext)} + + + + + + `; + + tbodyHtml += trHtml; + } + + tbodyEl.innerHTML = tbodyHtml; + Language.loadForEl(tbodyEl); + + query('#Lbl_TotalSupportedFormats').innerText = exts.length.toString(); + queryAll('#Table_FileFormats button[data-action]').forEach(el => { + el.addEventListener('click', async () => { + const action = el.getAttribute('data-action'); + const trEl = el.closest('tr'); + + if (action === 'delete') { + trEl.remove(); + query('#Lbl_TotalSupportedFormats').innerText = queryAll('#Table_FileFormats > tbody > tr').length.toString(); + TabFileAssocs._areFileFormatsChanged = true; + } + }, false); + }); + + // scroll to & highlight the extension row + if (extHighlight) { + const highlightedTrEl = query(`#Table_FileFormats tr[data-ext="${extHighlight}"]`); + if (!highlightedTrEl) return; + + highlightedTrEl.scrollIntoView({ block: 'center', behavior: 'smooth' }); + highlightedTrEl.classList.add('row--highlight'); + pause(2000).then(() => { + if (highlightedTrEl) highlightedTrEl.classList.remove('row--highlight'); + }); + } + } + + + // Open file format dialog for create. + private static async openFileFormatDialog() { + const isSubmitted = await TabFileAssocs.#fileFormatDialog.openCreate(); + + if (isSubmitted) { + TabFileAssocs._areFileFormatsChanged = true; + + const ext = TabFileAssocs.#fileFormatDialog.getDialogData(); + TabFileAssocs.addNewFileFormat(ext); + } + } + + + private static addNewFileFormat(ext: string) { + if (!ext) return; + const exts = TabFileAssocs.getFileFormatListFromDom(); + const extIndex = exts.indexOf(ext); + + // edit + if (extIndex !== -1) { + exts[extIndex] = ext; + } + // create + else { + exts.push(ext); + } + + TabFileAssocs.loadFileFormatList(exts, ext); + } + + + private static getFileFormatListFromDom() { + const trEls = queryAll('#Table_FileFormats > tbody > tr'); + const exts = trEls.map(trEl => trEl.getAttribute('data-ext') || '') + .filter(Boolean); + + return exts; + } +} diff --git a/Source/Components/ImageGlass.Settings/WebUI/src/FrmSettings/TabGallery.ts b/Source/Components/ImageGlass.Settings/WebUI/src/FrmSettings/TabGallery.ts new file mode 100644 index 000000000..0f477eb2c --- /dev/null +++ b/Source/Components/ImageGlass.Settings/WebUI/src/FrmSettings/TabGallery.ts @@ -0,0 +1,24 @@ +import { getChangedSettingsFromTab } from '@/helpers'; + +export default class TabGallery { + /** + * Loads settings for tab Gallery. + */ + static loadSettings() { + } + + + /** + * Adds events for tab Gallery. + */ + static addEvents() { + } + + + /** + * Save settings as JSON object. + */ + static exportSettings() { + return getChangedSettingsFromTab('gallery'); + } +} diff --git a/Source/Components/ImageGlass.Settings/WebUI/src/FrmSettings/TabGeneral.ts b/Source/Components/ImageGlass.Settings/WebUI/src/FrmSettings/TabGeneral.ts new file mode 100644 index 000000000..c3eec86c6 --- /dev/null +++ b/Source/Components/ImageGlass.Settings/WebUI/src/FrmSettings/TabGeneral.ts @@ -0,0 +1,105 @@ +import { getChangedSettingsFromTab } from '@/helpers'; + +export default class TabGeneral { + private static get isOriginalAutoUpdateEnabled() { + return _pageSettings.config.AutoUpdate !== '0'; + } + + /** + * Loads settings for tab General. + */ + static loadSettings() { + query('#Lnk_StartupDir').title = _pageSettings.startUpDir || '(unknown)'; + query('#Lnk_ConfigDir').title = _pageSettings.configDir || '(unknown)'; + query('#Lnk_UserConfigFile').title = _pageSettings.userConfigFilePath || '(unknown)'; + + // AutoUpdate is a string + query('[name="AutoUpdate"]').checked = TabGeneral.isOriginalAutoUpdateEnabled; + + // ImageInfoTags is a string array + const imgTags = _pageSettings.config.ImageInfoTags as number[] || []; + query('[name="ImageInfoTags"]').value = imgTags.join('; '); + + // load available image info tags + query('#LblAvailableTags').innerHTML = _pageSettings.enums.ImageInfoUpdateTypes.map(tag => `${tag}`).join('; '); + } + + + /** + * Adds events for tab General. + */ + static addEvents() { + query('#Lnk_StartupDir').addEventListener('click', () => post('Lnk_StartupDir', _pageSettings.startUpDir), false); + query('#Lnk_ConfigDir').addEventListener('click', () => post('Lnk_ConfigDir', _pageSettings.configDir), false); + query('#Lnk_UserConfigFile').addEventListener('click', () => post('Lnk_UserConfigFile', _pageSettings.userConfigFilePath), false); + query('#Btn_EnableStartupBoost').addEventListener('click', () => post('Btn_EnableStartupBoost'), false); + query('#Btn_DisableStartupBoost').addEventListener('click', () => post('Btn_DisableStartupBoost'), false); + query('#Lnk_OpenStartupAppsSetting').addEventListener('click', () => post('Lnk_OpenStartupAppsSetting'), false); + + query('[name="ImageInfoTags"]').addEventListener('blur', TabGeneral.onImageInfoTagsBlur, false); + query('#LnkResetImageInfoTags').addEventListener('click', TabGeneral.resetImageInfoTags, false); + } + + + /** + * Save settings as JSON object. + */ + static exportSettings() { + const settings = getChangedSettingsFromTab('general'); + + // convert AutoUpdate back to string + const isNewAutoUpdateEnabled = settings.AutoUpdate === true; + if (isNewAutoUpdateEnabled !== TabGeneral.isOriginalAutoUpdateEnabled) { + settings.AutoUpdate = settings.AutoUpdate + ? new Date().toISOString() + : '0'; + } + else { + delete settings.AutoUpdate; + } + + + // ImageInfoTags + settings.ImageInfoTags = TabGeneral.getImageInfoTags(); + + if (query('[name="ImageInfoTags"]').checkValidity()) { + const originalTagsString = _pageSettings.config.ImageInfoTags?.toString(); + const newTagsString = settings.ImageInfoTags?.toString(); + + if (newTagsString === originalTagsString) { + delete settings.ImageInfoTags; + } + } + else { + delete settings.ImageInfoTags; + } + + return settings; + } + + + // reset image info tags to default + private static resetImageInfoTags() { + const el = query('[name="ImageInfoTags"]'); + const defaultTags = _pageSettings.defaultImageInfoTags as string[] || []; + + el.value = defaultTags.join('; '); + } + + + // Handle when the ImageInfoTags box is blur. + private static onImageInfoTagsBlur() { + const el = query('[name="ImageInfoTags"]'); + if (!el.checkValidity()) return; + + el.value = TabGeneral.getImageInfoTags().join('; '); + } + + // gets image info tags + private static getImageInfoTags() { + const el = query('[name="ImageInfoTags"]'); + const tags = el.value.split(';').map(i => i.trim()).filter(Boolean); + + return tags; + } +} diff --git a/Source/Components/ImageGlass.Settings/WebUI/src/FrmSettings/TabImage.ts b/Source/Components/ImageGlass.Settings/WebUI/src/FrmSettings/TabImage.ts new file mode 100644 index 000000000..09d9e240d --- /dev/null +++ b/Source/Components/ImageGlass.Settings/WebUI/src/FrmSettings/TabImage.ts @@ -0,0 +1,89 @@ +import { getChangedSettingsFromTab } from '@/helpers'; + +export default class TabImage { + /** + * Loads settings for tab Image. + */ + static loadSettings() { + const colorProfile = (_pageSettings.config.ColorProfile as string || ''); + if (colorProfile.includes('.')) { + query('[name="ColorProfile"]').value = 'Custom'; + query('#Lnk_CustomColorProfile').innerText = colorProfile; + } + + TabImage.handleColorProfileChanged(); + TabImage.handleUseEmbeddedThumbnailOptionsChanged(); + } + + + /** + * Add events for tab Image. + */ + static addEvents() { + query('#Btn_BrowseColorProfile').addEventListener('click', async () => { + const profileFilePath = await postAsync('Btn_BrowseColorProfile'); + query('#Lnk_CustomColorProfile').innerText = profileFilePath; + }, false); + + query('#Lnk_CustomColorProfile').addEventListener('click', () => { + const profileFilePath = query('#Lnk_CustomColorProfile').innerText.trim(); + post('Lnk_CustomColorProfile', profileFilePath); + }, false); + + query('[name="ColorProfile"]').addEventListener('change', TabImage.handleColorProfileChanged, false); + + query('[name="UseEmbeddedThumbnailRawFormats"]').addEventListener('input', TabImage.handleUseEmbeddedThumbnailOptionsChanged, false); + query('[name="UseEmbeddedThumbnailOtherFormats"]').addEventListener('input', TabImage.handleUseEmbeddedThumbnailOptionsChanged, false); + } + + + /** + * Save settings as JSON object. + */ + static exportSettings() { + const settings = getChangedSettingsFromTab('image'); + + // ImageBoosterCacheCount + settings.ImageBoosterCacheCount = +(settings.ImageBoosterCacheCount || 0); + if (settings.ImageBoosterCacheCount === _pageSettings.config.ImageBoosterCacheCount) { + delete settings.ImageBoosterCacheCount; + } + + + // ColorProfile + const originalColorProfile = _pageSettings.config.ColorProfile; + if (settings.ColorProfile === 'Custom') { + settings.ColorProfile = query('#Lnk_CustomColorProfile').innerText.trim(); + } + if (!settings.ColorProfile || settings.ColorProfile === originalColorProfile) { + delete settings.ColorProfile; + } + + return settings; + } + + + /** + * Handles when color profile option is changed. + */ + static handleColorProfileChanged() { + const selectEl = query('[name="ColorProfile"]'); + const useCustomProfile = selectEl.value === 'Custom'; + + query('#Btn_BrowseColorProfile').hidden = !useCustomProfile; + query('#Section_CustomColorProfile').hidden = !useCustomProfile; + query('#Section_CurrentMonitorProfile').hidden = selectEl.value !== 'CurrentMonitorProfile'; + } + + + /** + * Handle when the embedded thumbnail options are changed. + */ + static handleUseEmbeddedThumbnailOptionsChanged() { + const enableForRaw = query('[name="UseEmbeddedThumbnailRawFormats"]').checked; + const enableForOthers = query('[name="UseEmbeddedThumbnailOtherFormats"]').checked; + const showSizeSection = enableForRaw || enableForOthers; + + query('#Section_EmbeddedThumbnailSize').hidden = !showSizeSection; + } +} diff --git a/Source/Components/ImageGlass.Settings/WebUI/src/FrmSettings/TabKeyboard.ts b/Source/Components/ImageGlass.Settings/WebUI/src/FrmSettings/TabKeyboard.ts new file mode 100644 index 000000000..1e3f79ab8 --- /dev/null +++ b/Source/Components/ImageGlass.Settings/WebUI/src/FrmSettings/TabKeyboard.ts @@ -0,0 +1,24 @@ +import { getChangedSettingsFromTab } from '@/helpers'; + +export default class TabKeyboard { + /** + * Loads settings for tab Keyboard. + */ + static loadSettings() { + } + + + /** + * Adds events for tab Keyboard. + */ + static addEvents() { + } + + + /** + * Save settings as JSON object. + */ + static exportSettings() { + return getChangedSettingsFromTab('keyboard'); + } +} diff --git a/Source/Components/ImageGlass.Settings/WebUI/src/FrmSettings/TabLanguage.ts b/Source/Components/ImageGlass.Settings/WebUI/src/FrmSettings/TabLanguage.ts new file mode 100644 index 000000000..8df5e4616 --- /dev/null +++ b/Source/Components/ImageGlass.Settings/WebUI/src/FrmSettings/TabLanguage.ts @@ -0,0 +1,83 @@ +import { ILanguage } from '@/@types/FrmSettings'; +import { getChangedSettingsFromTab } from '@/helpers'; + +export default class TabLanguage { + /** + * Loads settings for tab Language. + */ + static loadSettings() { + TabLanguage.handleLanguageChanged(); + } + + + /** + * Adds events for tab Language. + */ + static addEvents() { + query('#Cmb_LanguageList').addEventListener('change', TabLanguage.handleLanguageChanged, false); + query('#Btn_RefreshLanguageList').addEventListener('click', TabLanguage.onBtn_RefreshLanguageList, false); + query('#Lnk_InstallLanguage').addEventListener('click', TabLanguage.onLnk_InstallLanguage, false); + query('#Lnk_ExportLanguage').addEventListener('click', () => post('Lnk_ExportLanguage', query('#Cmb_LanguageList').value), false); + } + + + private static async onBtn_RefreshLanguageList() { + const newLangList = await postAsync('Btn_RefreshLanguageList'); + TabLanguage.loadLanguageList(newLangList); + } + + + private static async onLnk_InstallLanguage() { + const newLangList = await postAsync('Lnk_InstallLanguage'); + TabLanguage.loadLanguageList(newLangList); + } + + + /** + * Save settings as JSON object. + */ + static exportSettings() { + return getChangedSettingsFromTab('language'); + } + + + /** + * Handles when language is changed. + */ + private static handleLanguageChanged() { + const langFileName = query('#Cmb_LanguageList').value; + const lang = _pageSettings.langList.find(i => i.FileName === langFileName); + if (!lang) return; + + query('#Section_LanguageContributors').innerText = lang.Metadata.Author; + } + + + /** + * Loads language list to select box. + * @param list If defined, it overrides `_pageSettings.langList`. + */ + static loadLanguageList(list?: ILanguage[]) { + const selectEl = query('#Cmb_LanguageList'); + + // clear current list + while (selectEl.options.length) selectEl.remove(0); + + if (Array.isArray(list) && list.length > 0) { + _pageSettings.langList = list; + } + + _pageSettings.langList.forEach(lang => { + let displayText = `${lang.Metadata.LocalName} (${lang.Metadata.EnglishName})`; + if (!lang.FileName || lang.FileName.length === 0) { + displayText = lang.Metadata.EnglishName; + } + + const optionEl = new Option(displayText, lang.FileName); + selectEl.add(optionEl); + }); + + selectEl.value = _pageSettings.config.Language; + TabLanguage.handleLanguageChanged(); + } +} diff --git a/Source/Components/ImageGlass.Settings/WebUI/src/FrmSettings/TabLayout.ts b/Source/Components/ImageGlass.Settings/WebUI/src/FrmSettings/TabLayout.ts new file mode 100644 index 000000000..a66b3dbcc --- /dev/null +++ b/Source/Components/ImageGlass.Settings/WebUI/src/FrmSettings/TabLayout.ts @@ -0,0 +1,289 @@ +import { getChangedSettingsFromTab } from '@/helpers'; +import Language from '../common/Language'; + +type LayoutControlName = 'Toolbar' | 'ToolbarContext' | 'Gallery'; +type ILayoutObject = Record; + +export default class TabLayout { + private static get defaultLayout(): ILayoutObject { + return { + Toolbar: { position: 'Top', order: '0' }, + ToolbarContext: { position: 'Bottom', order: '1' }, + Gallery: { position: 'Bottom', order: '0' }, + }; + } + + + /** + * Loads settings for tab Layout. + */ + static loadSettings() { + TabLayout.loadLayoutConfigs(); + } + + + /** + * Adds events for tab Layout. + */ + static addEvents() { + query('[name="_Layout.Toolbar.Position"]').removeEventListener('change', TabLayout.handleLayoutInputsChanged, false); + query('[name="_Layout.Toolbar.Position"]').addEventListener('change', TabLayout.handleLayoutInputsChanged, false); + query('[name="_Layout.Toolbar.Order"]').removeEventListener('change', TabLayout.handleLayoutInputsChanged, false); + query('[name="_Layout.Toolbar.Order"]').addEventListener('change', TabLayout.handleLayoutInputsChanged, false); + + query('[name="_Layout.ToolbarContext.Position"]').removeEventListener('change', TabLayout.handleLayoutInputsChanged, false); + query('[name="_Layout.ToolbarContext.Position"]').addEventListener('change', TabLayout.handleLayoutInputsChanged, false); + query('[name="_Layout.ToolbarContext.Order"]').removeEventListener('change', TabLayout.handleLayoutInputsChanged, false); + query('[name="_Layout.ToolbarContext.Order"]').addEventListener('change', TabLayout.handleLayoutInputsChanged, false); + + query('[name="_Layout.Gallery.Position"]').removeEventListener('change', TabLayout.handleLayoutInputsChanged, false); + query('[name="_Layout.Gallery.Position"]').addEventListener('change', TabLayout.handleLayoutInputsChanged, false); + query('[name="_Layout.Gallery.Order"]').removeEventListener('change', TabLayout.handleLayoutInputsChanged, false); + query('[name="_Layout.Gallery.Order"]').addEventListener('change', TabLayout.handleLayoutInputsChanged, false); + } + + + /** + * Save settings as JSON object. + */ + static exportSettings() { + const settings = getChangedSettingsFromTab('layout'); + const oldLayout = TabLayout.convertRawLayoutToLayoutObject(); + + // get layout settings + let hasChanged = false; + const layout: Record = {}; + TabLayout.getLayoutSettingObjectFromDOM(item => { + if (oldLayout[item.controlName].position !== item.position) hasChanged = true; + if (oldLayout[item.controlName].order !== item.order) hasChanged = true; + + layout[item.controlName] = [item.position, item.order].join(';'); + }); + + if (hasChanged) settings.Layout = layout; + + return settings; + } + + + private static loadLayoutConfigs() { + const layout = TabLayout.convertRawLayoutToLayoutObject(); + + Object.keys(layout).forEach((controlName: LayoutControlName) => { + const { position, order } = layout[controlName]; + + query(`[name="_Layout.${controlName}.Position"]`).value = position; + query(`[name="_Layout.${controlName}.Order"]`).value = order; + }); + + TabLayout.loadLayoutMapDOM(layout); + } + + + private static loadLayoutMapDOM(layout?: ILayoutObject) { + layout ||= TabLayout.getLayoutSettingObjectFromDOM(); + + // clear all DOM buttons + queryAll('.app-layout .region-drop[data-order]').forEach(el => el.innerHTML = ''); + + for (const controlName in layout) { + if (!Object.prototype.hasOwnProperty.call(layout, controlName)) continue; + const item = layout[controlName as LayoutControlName]; + + const regionEl = query(`.app-layout [data-position="${item.position}"i] .region-drop[data-order="${item.order}"]`); + if (regionEl === null) continue; + + regionEl.innerHTML = ` + `; + } + + Language.loadFor('.app-layout'); + + // add drag/drop events + queryAll('.app-layout button[draggable="true"]').forEach(btnEl => { + btnEl.removeEventListener('dragstart', TabLayout.handleLayoutItemDragStart, false); + btnEl.addEventListener('dragstart', TabLayout.handleLayoutItemDragStart, false); + }); + + queryAll('.app-layout .region-drop').forEach(el => { + el.removeEventListener('dragover', (e) => TabLayout.handleLayoutItemDragOver(e), false); + el.addEventListener('dragover', (e) => TabLayout.handleLayoutItemDragOver(e), false); + + el.removeEventListener('dragenter', (e) => TabLayout.handleLayoutItemDragEnter(e, el), false); + el.addEventListener('dragenter', (e) => TabLayout.handleLayoutItemDragEnter(e, el), false); + + el.removeEventListener('dragleave', (e) => TabLayout.handleLayoutItemDragLeave(e, el), false); + el.addEventListener('dragleave', (e) => TabLayout.handleLayoutItemDragLeave(e, el), false); + el.removeEventListener('dragend', (e) => TabLayout.handleLayoutItemDragEnd(e), false); + el.addEventListener('dragend', (e) => TabLayout.handleLayoutItemDragEnd(e), false); + + el.removeEventListener('drop', (e) => TabLayout.handleLayoutItemDrop(e, el), false); + el.addEventListener('drop', (e) => TabLayout.handleLayoutItemDrop(e, el), false); + }); + } + + + private static convertRawLayoutToLayoutObject(rawLayout?: Partial>): ILayoutObject { + rawLayout ||= _pageSettings.config?.Layout || {}; + const layout = TabLayout.defaultLayout; + + for (const key in layout) { + if (!Object.prototype.hasOwnProperty.call(layout, key)) continue; + const controlName = key as LayoutControlName; + + const arr = rawLayout[controlName]?.split(';').filter(Boolean) || []; + const position = arr[0] ?? layout[controlName].position; + const order = arr[1] ?? layout[controlName].order; + + layout[controlName] = { position, order }; + } + + return layout as ILayoutObject; + } + + + private static getLayoutSettingObjectFromDOM(callbackFn?: (item: { + controlName: LayoutControlName, + position: string, + order: string, + }) => any): ILayoutObject { + const layout: Partial = {}; + + ['Toolbar', 'ToolbarContext', 'Gallery'].forEach((controlName: LayoutControlName) => { + const position = query(`[name="_Layout.${controlName}.Position"]`).value || '0'; + const order = query(`[name="_Layout.${controlName}.Order"]`).value || '0'; + if (callbackFn) callbackFn({ controlName, position, order }); + + layout[controlName] = { position, order }; + }); + + return layout as ILayoutObject; + } + + + private static handleLayoutInputsChanged(e: Event) { + e.preventDefault(); + + const layout = TabLayout.getLayoutSettingObjectFromDOM(); + TabLayout.loadLayoutMapDOM(layout); + + // hide gallery order if the position is either left / right + const hideGalleryOrder = layout.Gallery.position === 'Left' || layout.Gallery.position === 'Right'; + query('#Section_LayoutGalleryOrder').toggleAttribute('hidden', hideGalleryOrder); + } + + + private static handleLayoutItemDragStart(e: DragEvent) { + const btnEl = e.target as HTMLButtonElement; + const fromControlName = btnEl.getAttribute('data-control'); + const fromPosition = btnEl.closest('[data-position]').getAttribute('data-position'); + const fromOrder = btnEl.closest('[data-order]').getAttribute('data-order'); + + const data = JSON.stringify({ fromControlName, fromPosition, fromOrder }); + e.dataTransfer.setData('application/json', data); + e.dataTransfer.effectAllowed = 'move'; + + // set custom drag image + const btnContentEl = btnEl.querySelector('*') as HTMLElement; + e.dataTransfer.setDragImage(btnContentEl, -20, 0); + + // don't allow to drop toolbar to left/right position + if (fromControlName.toLowerCase().includes('toolbar')) { + query('[data-position="Left"i] .region-drop').classList.add('nodrop'); + query('[data-position="Right"i] .region-drop').classList.add('nodrop'); + } + + // disable child el to receive drag events + queryAll('.app-layout button[draggable="true"]').forEach(el => { + el.style.pointerEvents = 'none'; + }); + btnEl.style.pointerEvents = ''; + } + + + private static handleLayoutItemDragOver(e: DragEvent) { + e.preventDefault(); + e.dataTransfer.dropEffect = 'move'; + } + + + private static handleLayoutItemDragEnter(e: DragEvent, dropEL: HTMLElement) { + e.preventDefault(); + dropEL.classList.add('drag--enter'); + } + + + private static handleLayoutItemDragLeave(e: DragEvent, dropEL: HTMLElement) { + e.preventDefault(); + dropEL.classList.remove('drag--enter'); + } + + + private static handleLayoutItemDragEnd(e: DragEvent) { + e.preventDefault(); + + query('[data-position="Left"i] .region-drop').classList.remove('nodrop'); + query('[data-position="Right"i] .region-drop').classList.remove('nodrop'); + + // re-enable child el to receive drag events + queryAll('.app-layout button[draggable="true"]').forEach(el => { + el.style.pointerEvents = ''; + }); + } + + + private static handleLayoutItemDrop(e: DragEvent, toDropEl: HTMLElement) { + e.stopImmediatePropagation(); + e.preventDefault(); + toDropEl.classList.remove('drag--enter'); + + const toBtnEl = toDropEl.querySelector('button[draggable="true"]') as (HTMLButtonElement | null); + const toControlName = (toBtnEl?.getAttribute('data-control') || '') as LayoutControlName; + + // get the drop data + const jsonData = e.dataTransfer.getData('application/json') || '{}'; + const { fromControlName, fromPosition, fromOrder } = JSON.parse(jsonData) || {}; + if (!fromControlName || !fromPosition || !fromOrder) return; + + // get the new drop data + const position = toDropEl.closest('[data-position]').getAttribute('data-position'); + const order = toDropEl.getAttribute('data-order'); + + + // don't allow to drop toolbar to left/right position + if ((fromControlName.toLowerCase().includes('toolbar') && (position === 'Left' || position === 'Right')) + || toControlName.toLowerCase().includes('toolbar') && (fromPosition === 'Left' || fromPosition === 'Right')) { + return; + } + + + const fromDropEl = query(`.app-layout [data-position="${fromPosition}"i] .region-drop[data-order="${fromOrder}"]`) as HTMLElement; + const fromBtnEl = fromDropEl.querySelector('button[draggable="true"]') as HTMLButtonElement; + + // if the drop region is already occupied + if (toBtnEl) { + // swap the elements + fromDropEl?.appendChild(toBtnEl); + + query(`[name="_Layout.${toControlName}.Position"]`).value = fromPosition; + query(`[name="_Layout.${toControlName}.Order"]`).value = fromOrder; + } + + // drop the btn to the drop target + toDropEl.appendChild(fromBtnEl); + + query(`[name="_Layout.${fromControlName}.Position"]`).value = position; + query(`[name="_Layout.${fromControlName}.Order"]`).value = order; + + // hide gallery order if the position is either left / right + if (fromControlName === 'Gallery') { + const hideGalleryOrder = position === 'Left' || position === 'Right'; + query('#Section_LayoutGalleryOrder').toggleAttribute('hidden', hideGalleryOrder); + } + } +} diff --git a/Source/Components/ImageGlass.Settings/WebUI/src/FrmSettings/TabMouse.ts b/Source/Components/ImageGlass.Settings/WebUI/src/FrmSettings/TabMouse.ts new file mode 100644 index 000000000..8d05a84da --- /dev/null +++ b/Source/Components/ImageGlass.Settings/WebUI/src/FrmSettings/TabMouse.ts @@ -0,0 +1,69 @@ +import { getChangedSettingsFromTab } from '@/helpers'; + +export default class TabMouse { + /** + * Loads settings for tab Mouse. + */ + static loadSettings() { + query('#Cmb_MouseWheel_Scroll').value = _pageSettings.config.MouseWheelActions?.Scroll || 'DoNothing'; + query('#Cmb_MouseWheel_CtrlAndScroll').value = _pageSettings.config.MouseWheelActions?.CtrlAndScroll || 'DoNothing'; + query('#Cmb_MouseWheel_ShiftAndScroll').value = _pageSettings.config.MouseWheelActions?.ShiftAndScroll || 'DoNothing'; + query('#Cmb_MouseWheel_AltAndScroll').value = _pageSettings.config.MouseWheelActions?.AltAndScroll || 'DoNothing'; + } + + + /** + * Adds events for tab Mouse. + */ + static addEvents() { + query('#Btn_ResetMouseWheelAction').addEventListener('click', TabMouse.resetDefaultMouseWheelActions, false); + } + + + /** + * Save settings as JSON object. + */ + static exportSettings() { + const settings = getChangedSettingsFromTab('mouse'); + + // MouseWheelActions + const newWheelScrollValue = query('#Cmb_MouseWheel_Scroll').value; + const newWheelCtrlAndScrollValue = query('#Cmb_MouseWheel_CtrlAndScroll').value; + const newWheelShiftAndScrollValue = query('#Cmb_MouseWheel_ShiftAndScroll').value; + const newWheelAltAndScrollValue = query('#Cmb_MouseWheel_AltAndScroll').value; + + const mouseWheelActions: Record = {}; + if (newWheelScrollValue !== _pageSettings.config.MouseWheelActions?.Scroll) { + mouseWheelActions.Scroll = newWheelScrollValue; + } + if (newWheelCtrlAndScrollValue !== _pageSettings.config.MouseWheelActions?.CtrlAndScroll) { + mouseWheelActions.CtrlAndScroll = newWheelCtrlAndScrollValue; + } + if (newWheelShiftAndScrollValue !== _pageSettings.config.MouseWheelActions?.ShiftAndScroll) { + mouseWheelActions.ShiftAndScroll = newWheelShiftAndScrollValue; + } + if (newWheelAltAndScrollValue !== _pageSettings.config.MouseWheelActions?.AltAndScroll) { + mouseWheelActions.AltAndScroll = newWheelAltAndScrollValue; + } + + if (Object.keys(mouseWheelActions).length > 0) { + settings.MouseWheelActions = mouseWheelActions; + } + else { + delete settings.MouseWheelActions; + } + + return settings; + } + + + /** + * Resets the mouse wheel actions to the default settings. + */ + private static resetDefaultMouseWheelActions() { + query('#Cmb_MouseWheel_Scroll').value = 'Zoom'; + query('#Cmb_MouseWheel_CtrlAndScroll').value = 'PanVertically'; + query('#Cmb_MouseWheel_ShiftAndScroll').value = 'PanHorizontally'; + query('#Cmb_MouseWheel_AltAndScroll').value = 'BrowseImages'; + } +} diff --git a/Source/Components/ImageGlass.Settings/WebUI/src/FrmSettings/TabSlideshow.ts b/Source/Components/ImageGlass.Settings/WebUI/src/FrmSettings/TabSlideshow.ts new file mode 100644 index 000000000..6d5d38642 --- /dev/null +++ b/Source/Components/ImageGlass.Settings/WebUI/src/FrmSettings/TabSlideshow.ts @@ -0,0 +1,124 @@ +import { getChangedSettingsFromTab } from '@/helpers'; + +export default class TabSlideshow { + /** + * Loads settings for tab Slideshow. + */ + static loadSettings() { + TabSlideshow.handleUseRandomIntervalForSlideshowChanged(); + TabSlideshow.handleSlideshowIntervalsChanged(); + TabSlideshow.handleSlideshowBackgroundColorChanged(); + } + + + /** + * Adds events for tab Slideshow. + */ + static addEvents() { + query('[name="UseRandomIntervalForSlideshow"]').addEventListener('input', TabSlideshow.handleUseRandomIntervalForSlideshowChanged, false); + query('[name="SlideshowInterval"]').addEventListener('input', TabSlideshow.handleSlideshowIntervalsChanged, false); + query('[name="SlideshowIntervalTo"]').addEventListener('input', TabSlideshow.handleSlideshowIntervalsChanged, false); + query('#Lnk_ResetSlideshowBackgroundColor').addEventListener('click', TabSlideshow.resetSlideshowBackgroundColor, false); + query('#Btn_SlideshowBackgroundColor').addEventListener('click', TabSlideshow.onBtn_SlideshowBackgroundColor, false); + } + + + /** + * Save settings as JSON object. + */ + static exportSettings() { + return getChangedSettingsFromTab('slideshow'); + } + + + /** + * Handle when slideshow intervals are changed. + */ + private static handleSlideshowIntervalsChanged() { + const fromEl = query('[name="SlideshowInterval"]'); + const toEl = query('[name="SlideshowIntervalTo"]'); + const useRandomInterval = query('[name="UseRandomIntervalForSlideshow"]').checked; + + if (useRandomInterval) { + fromEl.max = toEl.value; + toEl.min = fromEl.value; + } + else { + fromEl.max = ''; + } + + const intervalFrom = +fromEl.value || 5; + const intervalTo = +toEl.value || 5; + const intervalFromText = TabSlideshow.toTimeString(intervalFrom); + const intervalToText = TabSlideshow.toTimeString(intervalTo); + + if (useRandomInterval) { + query('#Lbl_SlideshowInterval').innerText = `${intervalFromText} - ${intervalToText}`; + } + else { + query('#Lbl_SlideshowInterval').innerText = intervalFromText; + } + } + + + /** + * handle when `UseRandomIntervalForSlideshow` is changed. + */ + private static handleUseRandomIntervalForSlideshowChanged() { + const fromEl = query('[name="SlideshowInterval"]'); + const toEl = query('[name="SlideshowIntervalTo"]'); + const useRandomInterval = query('[name="UseRandomIntervalForSlideshow"]').checked; + + query('#Lbl_SlideshowIntervalFrom').hidden = !useRandomInterval; + query('#Section_SlideshowIntervalTo').hidden = !useRandomInterval; + + const intervalFrom = +fromEl.value || 5; + const intervalTo = +toEl.value || 5; + if (useRandomInterval && intervalFrom > intervalTo) { + toEl.min = intervalFrom.toString(); + toEl.value = intervalFrom.toString(); + } + } + + + // Formats total seconds to time format: `mm:ss.fff`. + private static toTimeString(totalSeconds: number) { + const dt = new Date(totalSeconds * 1000); + let minutes = dt.getUTCMinutes().toString(); + let seconds = dt.getUTCSeconds().toString(); + const msSeconds = dt.getUTCMilliseconds().toString(); + + if (minutes.length < 2) minutes = `0${minutes}`; + if (seconds.length < 2) seconds = `0${seconds}`; + + return `${minutes}:${seconds}.${msSeconds}`; + } + + + // Reset slideshow background color to black + private static resetSlideshowBackgroundColor() { + query('[name="SlideshowBackgroundColor"]').value = '#000000'; + TabSlideshow.handleSlideshowBackgroundColorChanged(); + } + + + // Handles when `SlideshowBackgroundColor` is changed. + private static handleSlideshowBackgroundColorChanged() { + const colorHex = query('[name="SlideshowBackgroundColor"]').value; + if (!colorHex) return; + + query('#Btn_SlideshowBackgroundColor > .color-display').style.setProperty('--color-picker-value', colorHex); + query('#Lbl_SlideshowBackgroundColorValue').innerText = colorHex; + } + + + private static async onBtn_SlideshowBackgroundColor() { + const colorEL = query('[name="SlideshowBackgroundColor"]'); + const colorValue = await postAsync('Btn_SlideshowBackgroundColor', colorEL.value); + + if (colorValue) { + colorEL.value = colorValue; + TabSlideshow.handleSlideshowBackgroundColorChanged(); + } + } +} diff --git a/Source/Components/ImageGlass.Settings/WebUI/src/FrmSettings/TabToolbar.ts b/Source/Components/ImageGlass.Settings/WebUI/src/FrmSettings/TabToolbar.ts new file mode 100644 index 000000000..f58e3617d --- /dev/null +++ b/Source/Components/ImageGlass.Settings/WebUI/src/FrmSettings/TabToolbar.ts @@ -0,0 +1,98 @@ +import { getChangedSettingsFromTab } from '@/helpers'; +import { ToolbarEditorHtmlElement } from './webComponents/ToolbarEditorHtmlElement'; +import { ToolbarButtonEditDialogHtmlElement } from './webComponents/ToolbarButtonEditDialogHtmlElement'; +import { IToolbarButton } from '@/@types/FrmSettings'; + +export default class TabToolbar { + static #toolbarEditor = query('#ToolbarEditor'); + static #toolbarBtnDialog = query('[is="edit-toolbar-dialog"]'); + + /** + * Gets current selected theme. + */ + static get currentTheme() { + return _pageSettings.themeList.find(i => i.FolderName === _page.theme); + } + + + /** + * Loads settings for tab Toolbar. + */ + static loadSettings() { + TabToolbar.#toolbarEditor.initialize(TabToolbar.onEditToolbarButton); + } + + + /** + * Adds events for tab Toolbar. + */ + static addEvents() { + query('#Btn_AddCustomToolbarButton').addEventListener('click', TabToolbar.onBtnAddCustomToolbarButtonClick, false); + query('#Btn_ResetToolbarButtons').addEventListener('click', TabToolbar.onBtnResetToolbarButtonsClick, false); + } + + + /** + * Save settings as JSON object. + */ + static exportSettings() { + const settings = getChangedSettingsFromTab('toolbar'); + + if (TabToolbar.#toolbarEditor.hasChanges) { + settings.ToolbarButtons = TabToolbar.#toolbarEditor.currentButtons; + } + else { + delete settings.ToolbarButtons; + } + + return settings; + } + + + private static async onBtnResetToolbarButtonsClick() { + const defaultToolbarIds = await postAsync('Btn_ResetToolbarButtons'); + TabToolbar.#toolbarEditor.loadItemsByIds(defaultToolbarIds); + } + + private static async onBtnAddCustomToolbarButtonClick() { + const isSubmitted = await TabToolbar.#toolbarBtnDialog.openCreate(); + if (!isSubmitted) return; + + const data = TabToolbar.#toolbarBtnDialog.getDialogData(); + const btn = JSON.parse(data.ButtonJson) as IToolbarButton; + const themeBtnIconUrl = TabToolbar.currentTheme.ToolbarIcons[btn.Image]; + + // image is theme icon + if (themeBtnIconUrl) { + btn.ImageUrl = themeBtnIconUrl; + } + else { + // image is an external file + const imgUrl = new URL(`file:///${btn.Image}`); + btn.ImageUrl = imgUrl.toString(); + } + + TabToolbar.#toolbarEditor.insertItems(btn, 0); + } + + private static async onEditToolbarButton(toolbarBtn: IToolbarButton) { + const isSubmitted = await TabToolbar.#toolbarBtnDialog.openEdit(toolbarBtn); + if (!isSubmitted) return null; + + const data = TabToolbar.#toolbarBtnDialog.getDialogData(); + const btn = JSON.parse(data.ButtonJson) as IToolbarButton; + const themeBtnIconUrl = TabToolbar.currentTheme.ToolbarIcons[btn.Image]; + + // image is theme icon + if (themeBtnIconUrl) { + btn.ImageUrl = themeBtnIconUrl; + } + else { + // image is an external file + const imgUrl = new URL(`file:///${btn.Image}`); + btn.ImageUrl = imgUrl.toString(); + } + + return btn; + } +} diff --git a/Source/Components/ImageGlass.Settings/WebUI/src/FrmSettings/TabTools.ts b/Source/Components/ImageGlass.Settings/WebUI/src/FrmSettings/TabTools.ts new file mode 100644 index 000000000..92b36383e --- /dev/null +++ b/Source/Components/ImageGlass.Settings/WebUI/src/FrmSettings/TabTools.ts @@ -0,0 +1,218 @@ +import { ITool } from '@/@types/FrmSettings'; +import { + escapeHtml, + getChangedSettingsFromTab, + pause, +} from '@/helpers'; +import Language from '../common/Language'; +import { ToolDialogHtmlElement } from './webComponents/ToolDialogHtmlElement'; + + +export default class TabTools { + static HOTKEY_SEPARATOR = '#'; + static _areToolsChanged = false; + static #toolDialog = query('[is="tool-dialog"]'); + + /** + * Loads settings for tab Tools. + */ + static loadSettings() { + TabTools.loadToolList(); + } + + + /** + * Adds events for tab Tools. + */ + static addEvents() { + query('#Btn_AddTool').addEventListener('click', () => TabTools.openToolDialog(), false); + } + + + /** + * Save settings as JSON object. + */ + static exportSettings() { + const settings = getChangedSettingsFromTab('tools'); + + if (TabTools._areToolsChanged) { + // get new tool settings + settings.Tools = TabTools.getToolListFromDom(); + } + else { + delete settings.Tools; + } + + return settings; + } + + + /** + * Loads tool list but do not update `_pageSettings.toolList`. + */ + private static loadToolList(list?: ITool[], toolIdHighlight = '') { + const toolList: ITool[] = list ?? _pageSettings.toolList ?? []; + + const tbodyEl = query('#Table_ToolList > tbody'); + let tbodyHtml = ''; + const btnDeleteHtml = ` + + `; + + for (const item of toolList) { + let args = ''; + if (item.Argument) { + args = `${escapeHtml(item.Argument)}`; + } + + const hotkeysHtml = (item.Hotkeys || []) + .map((key, index) => { + const margin = index === 0 ? '' : 'ms-1'; + return `${key}`; + }).join(''); + + const chkIntegratedHtml = ` + + `; + + const trHtml = ` + + + + + + + + + ${item.ToolId} + ${item.ToolName} + ${chkIntegratedHtml} + ${hotkeysHtml} + + ${escapeHtml(item.Executable)} + + ${args} + + + ${item.ToolId !== 'Tool_ExifGlass' ? btnDeleteHtml : ''} + + + `; + + tbodyHtml += trHtml; + } + + tbodyEl.innerHTML = tbodyHtml; + Language.loadForEl(tbodyEl); + + queryAll('#Table_ToolList button[data-action]').forEach(el => { + el.addEventListener('click', async () => { + const action = el.getAttribute('data-action'); + const trEl = el.closest('tr'); + const toolId = trEl.getAttribute('data-toolId'); + + if (action === 'delete') { + trEl.remove(); + TabTools._areToolsChanged = true; + } + else if (action === 'edit') { + await TabTools.openToolDialog(toolId); + el.focus(); + } + }, false); + }); + + + // scroll to & highlight the extension row + if (toolIdHighlight) { + const highlightedTrEl = query(`#Table_ToolList tr[data-toolId="${toolIdHighlight}"]`); + if (!highlightedTrEl) return; + + highlightedTrEl.scrollIntoView({ block: 'center', behavior: 'smooth' }); + highlightedTrEl.classList.add('row--highlight'); + pause(2000).then(() => { + if (highlightedTrEl) highlightedTrEl.classList.remove('row--highlight'); + }); + } + } + + + /** + * Gets tool list from DOM. + */ + private static getToolListFromDom() { + const trEls = queryAll('#Table_ToolList > tbody > tr'); + const toolList = trEls.map(trEl => { + const toolId = trEl.getAttribute('data-toolId') || ''; + const toolName = query('[name="_ToolName"]', trEl).innerText || ''; + const toolIntegrated = (query('[name="_IsIntegrated"]', trEl).innerText) === 'true'; + const toolExecutable = query('[name="_Executable"]', trEl).innerText || ''; + const toolArgument = query('[name="_Argument"]', trEl).innerText || ''; + + const hotkeysStr = query('[name="_Hotkeys"]', trEl).innerText || ''; + const toolHotkeys = hotkeysStr.split(TabTools.HOTKEY_SEPARATOR).filter(Boolean); + + return { + ToolId: toolId, + ToolName: toolName, + IsIntegrated: toolIntegrated, + Executable: toolExecutable, + Argument: toolArgument, + Hotkeys: toolHotkeys, + } as ITool; + }); + + return toolList; + } + + + /** + * Open tool dialog for create or edit. + */ + private static async openToolDialog(toolId?: string) { + let isSubmitted = false; + + if (toolId) { + isSubmitted = await TabTools.#toolDialog.openEdit(toolId); + } + else { + isSubmitted = await TabTools.#toolDialog.openCreate(); + } + + if (isSubmitted) { + TabTools._areToolsChanged = true; + + const tool = TabTools.#toolDialog.getDialogData(); + TabTools.setToolItemToList(tool.ToolId, tool); + } + } + + + /** + * Sets the tool item to the list. + * @param oldToolId If not found, the tool will be inserted into the list. + */ + private static setToolItemToList(oldToolId: string, tool: ITool) { + if (!tool.ToolId || !tool.ToolName || !tool.Executable) return; + const toolList = TabTools.getToolListFromDom(); + const toolIndex = toolList.findIndex(i => i.ToolId === oldToolId); + + // edit + if (toolIndex !== -1) { + toolList[toolIndex] = tool; + } + // create + else { + toolList.push(tool); + } + + TabTools.loadToolList(toolList, tool.ToolId); + } +} diff --git a/Source/Components/ImageGlass.Settings/WebUI/src/FrmSettings/TabViewer.ts b/Source/Components/ImageGlass.Settings/WebUI/src/FrmSettings/TabViewer.ts new file mode 100644 index 000000000..7946104af --- /dev/null +++ b/Source/Components/ImageGlass.Settings/WebUI/src/FrmSettings/TabViewer.ts @@ -0,0 +1,109 @@ +import { getChangedSettingsFromTab } from '@/helpers'; + +export default class TabViewer { + /** + * Loads settings for tab Viewer. + */ + static loadSettings() { + const zoomLevels = _pageSettings.config.ZoomLevels as number[] || []; + query('[name="ZoomLevels"]').value = zoomLevels.join('; '); + query('[name="_UseSmoothZooming"]').checked = zoomLevels.length === 0; + TabViewer.onUseSmoothZoomingChanged(); + } + + + /** + * Adds events for tab Viewer. + */ + static addEvents() { + query('[name="_UseSmoothZooming"]').addEventListener('input', TabViewer.onUseSmoothZoomingChanged, false); + query('[name="ZoomLevels"]').addEventListener('input', TabViewer.handleZoomLevelsChanged, false); + query('[name="ZoomLevels"]').addEventListener('blur', TabViewer.handleZoomLevelsBlur, false); + + query('#LnkLoadDefaultZoomLevels').addEventListener('click', TabViewer.onLoadDefaultZoomLevelsClicked, false); + } + + + /** + * Save settings as JSON object. + */ + static exportSettings() { + const settings = getChangedSettingsFromTab('viewer'); + + // ZoomLevels + settings.ZoomLevels = TabViewer.getZoomLevels(); + + if (query('[name="ZoomLevels"]').checkValidity()) { + const originalLevelsString = _pageSettings.config.ZoomLevels?.toString(); + const newLevelsString = settings.ZoomLevels?.toString(); + + if (newLevelsString === originalLevelsString) { + delete settings.ZoomLevels; + } + } + else { + delete settings.ZoomLevels; + } + + return settings; + } + + + private static onUseSmoothZoomingChanged() { + const isDisabled = query('[name="_UseSmoothZooming"]').checked; + + query('[name="ZoomLevels"]').toggleAttribute('disabled', isDisabled); + query('#LnkLoadDefaultZoomLevels').toggleAttribute('disabled', isDisabled); + query('#LnkLoadDefaultZoomLevels').setAttribute('tabindex', isDisabled ? '-1' : '0'); + } + + + /** + * Handle when ZoomLevels is changed. + */ + private static handleZoomLevelsChanged() { + const el = query('[name="ZoomLevels"]'); + const levels = TabViewer.getZoomLevels(); + + // validate + if (levels.some(i => !Number.isFinite(i))) { + el.setCustomValidity('Value contains invalid characters. Only number, semi-colon are allowed.'); + } + else { + el.setCustomValidity(''); + } + } + + + /** + * Handle when the ZoomLevels box is blur. + */ + private static handleZoomLevelsBlur() { + const el = query('[name="ZoomLevels"]'); + if (!el.checkValidity()) return; + + el.value = TabViewer.getZoomLevels().join('; '); + } + + + /** + * Gets zoom levels + */ + private static getZoomLevels() { + const isEnabled = query('[name="_UseSmoothZooming"]').checked; + if (isEnabled) return []; + + const el = query('[name="ZoomLevels"]'); + const levels = el.value.split(';').map(i => i.trim()).filter(Boolean) + .map(i => parseFloat(i)); + + return levels; + } + + + private static onLoadDefaultZoomLevelsClicked() { + const defaultLevels = '5; 10; 15; 20; 30; 40; 50; 60; 70; 80; 90; 100; 125; 150; 175; 200; 250; 300; 350; 400; 500; 600; 700; 800; 1000; 1200; 1500; 1800; 2100; 2500; 3000; 3500; 4500; 6000; 8000; 10000'; + + query('[name="ZoomLevels"]').value = defaultLevels; + } +} diff --git a/Source/Components/ImageGlass.Settings/WebUI/src/FrmSettings/webComponents/EditAppDialogHtmlElement.ts b/Source/Components/ImageGlass.Settings/WebUI/src/FrmSettings/webComponents/EditAppDialogHtmlElement.ts new file mode 100644 index 000000000..61292cb13 --- /dev/null +++ b/Source/Components/ImageGlass.Settings/WebUI/src/FrmSettings/webComponents/EditAppDialogHtmlElement.ts @@ -0,0 +1,177 @@ +import { IEditApp } from '@/@types/FrmSettings'; +import { openFilePicker, openModalDialogEl } from '@/helpers'; + + +export class EditAppDialogHtmlElement extends HTMLDialogElement { + constructor() { + super(); + + // private methods + this.openCreate = this.openCreate.bind(this); + this.openEdit = this.openEdit.bind(this); + this.getDialogData = this.getDialogData.bind(this); + this.addDialogEvents = this.addDialogEvents.bind(this); + this.updateToolCommandPreview = this.updateToolCommandPreview.bind(this); + this.handleBtnBrowseAppClickEvent = this.handleBtnBrowseAppClickEvent.bind(this); + } + + + private connectedCallback() { + this.innerHTML = ` +
    +
    + [Add a new app] + [Edit app] +
    +
    +
    +
    [File extension]
    + +
    +
    +
    [App name]
    + +
    +
    +
    [Executable]
    +
    + + +
    +
    +
    +
    [Argument]
    + +
    +
    +
    [Command preview]
    +
    +
    +
    +
    + + +
    +
    `; + } + + + /** + * Opens EditApp dialog for create. + */ + public async openCreate() { + const data = { + FileExtension: '', + AppName: '', + Executable: '', + Argument: _pageSettings.FILE_MACRO, + } as IEditApp; + + const isSubmitted = await openModalDialogEl(this, 'create', data, async () => { + this.addDialogEvents(); + this.updateToolCommandPreview(); + }); + + return isSubmitted; + } + + + /** + * Opens EditApp dialog for edit. + * @param extKey Extension key + */ + public async openEdit(extKey: string) { + const trEl = query(`#Table_EditApps tr[data-extkey="${extKey}"]`); + + const data = { + FileExtension: extKey, + AppName: query('[name="_AppName"]', trEl).innerText || '', + Executable: query('[name="_Executable"]', trEl).innerText || '', + Argument: query('[name="_Argument"]', trEl).innerText || '', + } as IEditApp; + + // open dialog + const isSubmitted = await openModalDialogEl(this, 'edit', data, async () => { + this.addDialogEvents(); + this.updateToolCommandPreview(); + }); + + return isSubmitted; + } + + + /** + * Gets data from the tool dialog. + */ + public getDialogData() { + // get data + const extKey = query('[name="_FileExtension"]', this).value.trim(); + const app: IEditApp = { + AppName: query('[name="_AppName"]', this).value.trim(), + Executable: query('[name="_Executable"]', this).value.trim(), + Argument: query('[name="_Argument"]', this).value.trim(), + }; + + return { extKey, app }; + } + + + private addDialogEvents() { + query('[name="_Executable"]', this).removeEventListener('input', this.updateToolCommandPreview, false); + query('[name="_Executable"]', this).addEventListener('input', this.updateToolCommandPreview, false); + + query('[name="_Argument"]', this).removeEventListener('input', this.updateToolCommandPreview, false); + query('[name="_Argument"]', this).addEventListener('input', this.updateToolCommandPreview, false); + + query('#BtnBrowseApp', this).removeEventListener('click', this.handleBtnBrowseAppClickEvent, false); + query('#BtnBrowseApp', this).addEventListener('click', this.handleBtnBrowseAppClickEvent, false); + } + + + private updateToolCommandPreview() { + const fakePath = 'C:\\fake dir\\photo.jpg'; + let joinChar = ' '; + + let executable = query('[name="_Executable"]', this).value || ''; + executable = executable.trim(); + + let args = query('[name="_Argument"]', this).value || ''; + args = args.trim(); + + // app protocol + if (executable.endsWith(':')) { + args = args.replaceAll('', fakePath); + joinChar = ''; + } + // app executable file + else { + args = args.replaceAll('', `"${fakePath}"`); + joinChar = ' '; + } + + query('#App_CommandPreview', this).innerText = [executable, args].filter(Boolean).join(joinChar); + } + + + private async handleBtnBrowseAppClickEvent() { + const filePaths = await openFilePicker() ?? []; + if (!filePaths.length) return; + + query('[name="_Executable"]', this).value = filePaths[0]; + this.updateToolCommandPreview(); + } +} + + +/** + * Creates and registers EditAppDialogHtmlElement to DOM. + */ +export const defineEditAppDialogHtmlElement = () => window.customElements.define( + 'edit-app-dialog', + EditAppDialogHtmlElement, + { extends: 'dialog' }, +); diff --git a/Source/Components/ImageGlass.Settings/WebUI/src/FrmSettings/webComponents/FileFormatDialogHtmlElement.ts b/Source/Components/ImageGlass.Settings/WebUI/src/FrmSettings/webComponents/FileFormatDialogHtmlElement.ts new file mode 100644 index 000000000..b8b0f3ff7 --- /dev/null +++ b/Source/Components/ImageGlass.Settings/WebUI/src/FrmSettings/webComponents/FileFormatDialogHtmlElement.ts @@ -0,0 +1,64 @@ +import { openModalDialogEl } from '@/helpers'; + + +export class FileFormatDialogHtmlElement extends HTMLDialogElement { + constructor() { + super(); + + // private methods + this.openCreate = this.openCreate.bind(this); + this.getDialogData = this.getDialogData.bind(this); + } + + + private connectedCallback() { + this.innerHTML = ` +
    +
    + [Add new file extension] +
    +
    +
    +
    [File extension]
    + +
    +
    +
    + + +
    +
    `; + } + + + /** + * Opens file format dialog for create. + */ + public openCreate() { + return openModalDialogEl(this, 'create', { Extension: '' }, null); + } + + + /** + * Gets data from the tool dialog. + */ + public getDialogData() { + // get data + const ext = query('[name="_Extension"]').value || ''; + + return ext; + } +} + + +/** + * Creates and registers FileFormatDialogHtmlElement to DOM. + */ +export const defineFileFormatDialogHtmlElement = () => window.customElements.define( + 'file-format-dialog', + FileFormatDialogHtmlElement, + { extends: 'dialog' }, +); diff --git a/Source/Components/ImageGlass.Settings/WebUI/src/FrmSettings/webComponents/ToolDialogHtmlElement.ts b/Source/Components/ImageGlass.Settings/WebUI/src/FrmSettings/webComponents/ToolDialogHtmlElement.ts new file mode 100644 index 000000000..621d10845 --- /dev/null +++ b/Source/Components/ImageGlass.Settings/WebUI/src/FrmSettings/webComponents/ToolDialogHtmlElement.ts @@ -0,0 +1,205 @@ +import { ITool } from '@/@types/FrmSettings'; +import { openFilePicker, openModalDialogEl, renderHotkeyListEl } from '@/helpers'; + +const HOTKEY_SEPARATOR = '#'; + +export class ToolDialogHtmlElement extends HTMLDialogElement { + constructor() { + super(); + + // private methods + this.openCreate = this.openCreate.bind(this); + this.openEdit = this.openEdit.bind(this); + this.getDialogData = this.getDialogData.bind(this); + this.addDialogEvents = this.addDialogEvents.bind(this); + this.updateToolCommandPreview = this.updateToolCommandPreview.bind(this); + this.handleBtnBrowseToolClickEvent = this.handleBtnBrowseToolClickEvent.bind(this); + } + + + private connectedCallback() { + this.innerHTML = ` +
    +
    + [Add a new external tool] + [Edit external tool] +
    +
    +
    +
    [ID]
    + +
    +
    +
    [Name]
    + +
    +
    +
    [Executable]
    +
    + + +
    +
    +
    +
    [Argument]
    + +
    +
    +
    [Hotkeys]
    +
      +
      +
      + +
      +
      +
      [Command preview]
      +
      +
      +
      +
      + + +
      +
      `; + } + + + /** + * Opens tool dialog for create. + */ + public async openCreate() { + const defaultTool = { + ToolId: '', + ToolName: '', + Executable: '', + Argument: _pageSettings.FILE_MACRO, + Hotkeys: [], + IsIntegrated: false, + } as ITool; + + const isSubmitted = await openModalDialogEl(this, 'create', defaultTool, async () => { + this.addDialogEvents(); + this.updateToolCommandPreview(); + query('[name="_ToolId"]', this).toggleAttribute('disabled', false); + + const hotkeyListEl = query('.ig-list-horizontal', this); + await renderHotkeyListEl(hotkeyListEl, defaultTool.Hotkeys); + }); + + return isSubmitted; + } + + + /** + * Opens tool dialog for edit. + * @param toolId Tool ID + */ + public async openEdit(toolId: string) { + const trEl = query(`#Table_ToolList tr[data-toolId="${toolId}"]`); + + const hotkeysStr = query('[name="_Hotkeys"]', trEl).innerText || ''; + const toolHotkeys = hotkeysStr.split(HOTKEY_SEPARATOR).filter(Boolean); + + const tool: ITool = { + ToolId: toolId, + ToolName: query('[name="_ToolName"]', trEl).innerText || '', + Executable: query('[name="_Executable"]', trEl).innerText || '', + Argument: query('[name="_Argument"]', trEl).innerText || '', + IsIntegrated: query('[name="_IsIntegrated"]', trEl).innerText === 'true', + Hotkeys: toolHotkeys, + }; + + // open dialog + const isSubmitted = await openModalDialogEl(this, 'edit', tool, async () => { + this.addDialogEvents(); + this.updateToolCommandPreview(); + query('[name="_ToolId"]', this).toggleAttribute('disabled', true); + + const hotkeyListEl = query('.ig-list-horizontal', this); + await renderHotkeyListEl(hotkeyListEl, tool.Hotkeys); + }); + + return isSubmitted; + } + + + /** + * Gets data from the tool dialog. + */ + public getDialogData() { + // get data + const tool: ITool = { + ToolId: query('[name="_ToolId"]', this).value.trim(), + ToolName: query('[name="_ToolName"]', this).value.trim(), + Executable: query('[name="_Executable"]', this).value.trim(), + Argument: query('[name="_Argument"]', this).value.trim(), + Hotkeys: queryAll('.ig-list-horizontal > .hotkey-item > kbd', this).map(el => el.innerText), + IsIntegrated: query('[name="_IsIntegrated"]', this).checked, + }; + + return tool; + } + + + private addDialogEvents() { + query('[name="_Executable"]', this).removeEventListener('input', this.updateToolCommandPreview, false); + query('[name="_Executable"]', this).addEventListener('input', this.updateToolCommandPreview, false); + + query('[name="_Argument"]', this).removeEventListener('input', this.updateToolCommandPreview, false); + query('[name="_Argument"]', this).addEventListener('input', this.updateToolCommandPreview, false); + + query('#BtnBrowseTool', this).removeEventListener('click', this.handleBtnBrowseToolClickEvent, false); + query('#BtnBrowseTool', this).addEventListener('click', this.handleBtnBrowseToolClickEvent, false); + } + + + private updateToolCommandPreview() { + const fakePath = 'C:\\fake dir\\photo.jpg'; + let joinChar = ' '; + + let executable = query('[name="_Executable"]', this).value || ''; + executable = executable.trim(); + + let args = query('[name="_Argument"]', this).value || ''; + args = args.trim(); + + // app protocol + if (executable.endsWith(':')) { + args = args.replaceAll('', fakePath); + joinChar = ''; + } + // app executable file + else { + args = args.replaceAll('', `"${fakePath}"`); + joinChar = ' '; + } + + query('#Tool_CommandPreview', this).innerText = [executable, args].filter(Boolean).join(joinChar); + } + + + private async handleBtnBrowseToolClickEvent() { + const filePaths = await openFilePicker() ?? []; + if (!filePaths.length) return; + + query('[name="_Executable"]', this).value = filePaths[0]; + this.updateToolCommandPreview(); + } +} + + +/** + * Creates and registers ToolDialogHtmlElement to DOM. + */ +export const defineToolDialogHtmlElement = () => window.customElements.define( + 'tool-dialog', + ToolDialogHtmlElement, + { extends: 'dialog' }, +); diff --git a/Source/Components/ImageGlass.Settings/WebUI/src/FrmSettings/webComponents/ToolbarButtonEditDialogHtmlElement.ts b/Source/Components/ImageGlass.Settings/WebUI/src/FrmSettings/webComponents/ToolbarButtonEditDialogHtmlElement.ts new file mode 100644 index 000000000..2aba68754 --- /dev/null +++ b/Source/Components/ImageGlass.Settings/WebUI/src/FrmSettings/webComponents/ToolbarButtonEditDialogHtmlElement.ts @@ -0,0 +1,121 @@ +import { IToolbarButton } from '@/@types/FrmSettings'; +import { openModalDialogEl } from '@/helpers'; + +export class ToolbarButtonEditDialogHtmlElement extends HTMLDialogElement { + constructor() { + super(); + + // private methods + this.openCreate = this.openCreate.bind(this); + this.getDialogData = this.getDialogData.bind(this); + } + + + private connectedCallback() { + this.innerHTML = ` +
      +
      + [Add a custom toolbar button] + [Edit toolbar button] +
      +
      +
      +
      [Button JSON]
      + +
      +
      +
      + + +
      +
      `; + } + + + /** + * Opens tool dialog for create. + */ + public async openCreate() { + const defaultBtn = { + Id: '', + Type: 'Button', + Text: '', + Image: 'C:\\path\\to\\icon.svg', + Alignment: 'Left', + CheckableConfigBinding: '', + DisplayStyle: 'Image', + OnClick: { + Executable: '', + Arguments: [''], + }, + Hotkeys: [], + } as IToolbarButton; + const json = JSON.stringify(defaultBtn, null, 2); + + const isSubmitted = await openModalDialogEl(this, 'create', { ButtonJson: json }, null, + async () => { + const data = this.getDialogData(); + const isValid = await postAsync('Btn_AddCustomToolbarButton_ValidateJson_Create', data.ButtonJson); + return isValid; + }); + + return isSubmitted; + } + + + /** + * Opens tool dialog for edit. + */ + public async openEdit(btn: IToolbarButton) { + const json = JSON.stringify(btn, null, 2); + + const isSubmitted = await openModalDialogEl(this, 'edit', { ButtonJson: json }, null, + async () => { + const data = this.getDialogData(); + const isValid = await postAsync('Btn_AddCustomToolbarButton_ValidateJson_Edit', data.ButtonJson); + return isValid; + }); + + return isSubmitted; + } + + + /** + * Gets data from the tool dialog. + */ + public getDialogData() { + // get data + const json = query('[name="_ButtonJson"]').value || ''; + + return { + ButtonJson: json.trim(), + }; + } +} + + +/** + * Creates and registers ToolbarButtonEditDialogHtmlElement to DOM. + */ +export const defineToolbarButtonEditDialogHtmlElement = () => window.customElements.define( + 'edit-toolbar-dialog', + ToolbarButtonEditDialogHtmlElement, + { extends: 'dialog' }, +); diff --git a/Source/Components/ImageGlass.Settings/WebUI/src/FrmSettings/webComponents/ToolbarEditorHtmlElement.ts b/Source/Components/ImageGlass.Settings/WebUI/src/FrmSettings/webComponents/ToolbarEditorHtmlElement.ts new file mode 100644 index 000000000..9e5b39656 --- /dev/null +++ b/Source/Components/ImageGlass.Settings/WebUI/src/FrmSettings/webComponents/ToolbarEditorHtmlElement.ts @@ -0,0 +1,466 @@ +import { IToolbarButton } from '@/@types/FrmSettings'; +import Language from '@/common/Language'; +import { arrayMoveMutable, pause } from '@/helpers'; + +export type TEditButtonFn = (btn: IToolbarButton) => Promise; + +export class ToolbarEditorHtmlElement extends HTMLElement { + #listAvailableEl: HTMLUListElement; + + #itemsCurrent: IToolbarButton[]; + #listCurrentEl: HTMLUListElement; + + #hasChanges = false; + #dragData: { fromSource: string, fromIndex: number } = { + fromSource: '', + fromIndex: -1, + }; + + #editButtonFn: TEditButtonFn; + + constructor() { + super(); + + // methods + this.initialize = this.initialize.bind(this); + this.loadItems = this.loadItems.bind(this); + this.loadItemsByIds = this.loadItemsByIds.bind(this); + this.insertItems = this.insertItems.bind(this); + this.reloadAvailableItems = this.reloadAvailableItems.bind(this); + this.reloadCurrentItems = this.reloadCurrentItems.bind(this); + this.isBuiltInButton = this.isBuiltInButton.bind(this); + this.onToolbarActionButtonClicked = this.onToolbarActionButtonClicked.bind(this); + + this.onBtnToolbarDragStart = this.onBtnToolbarDragStart.bind(this); + this.onToolbarItemDragEnter = this.onToolbarItemDragEnter.bind(this); + this.onToolbarItemDragOver = this.onToolbarItemDragOver.bind(this); + this.onToolbarItemDragLeave = this.onToolbarItemDragLeave.bind(this); + this.onToolbarItemDragEnd = this.onToolbarItemDragEnd.bind(this); + this.onToolbarItemDrop = this.onToolbarItemDrop.bind(this); + + this.moveToolbarButton = this.moveToolbarButton.bind(this); + this.deleteToolbarButton = this.deleteToolbarButton.bind(this); + this.insertButtonFromAvailableList = this.insertButtonFromAvailableList.bind(this); + this.editToolbarButton = this.editToolbarButton.bind(this); + } + + get hasChanges() { + return this.#hasChanges; + } + + get currentButtons() { + return this.#itemsCurrent; + } + + get builtInButtons() { + return _pageSettings.builtInToolbarButtons || []; + } + + get availableButtons() { + const availableItems: IToolbarButton[] = [ + { Type: 'Separator' } as IToolbarButton, + ]; + + for (let icon = 0; icon < this.builtInButtons.length; icon++) { + const btn = this.builtInButtons[icon]; + if (this.#itemsCurrent.some(i => i.Type === 'Button' && i.Id === btn.Id)) { + continue; + } + + availableItems.push(btn); + } + + return availableItems.sort((a, b) => { + if (a.Text < b.Text) return -1; + if (a.Text > b.Text) return 1; + return 0; + }); + } + + private connectedCallback() { + this.innerHTML = ` +
      +
      [Available buttons:]
      +
        +
      +
      +
      + +
      +
      +
      [Current buttons:]
      +
        +
      +
      `; + + this.#listAvailableEl = query('.section-available .toolbar-list', this); + this.#listCurrentEl = query('.section-current .toolbar-list', this); + } + + + /** + * Initializes and loads data into the toolbar editor. + */ + public initialize(onEditButton: TEditButtonFn) { + this.#editButtonFn = onEditButton.bind(this); + this.#hasChanges = false; + this.loadItems(); + } + + private loadItems(items?: IToolbarButton[]) { + this.#itemsCurrent = items || _pageSettings.config.ToolbarButtons || []; + + this.reloadAvailableItems(); + this.reloadCurrentItems(); + } + + public loadItemsByIds(btnIds: string[]) { + if (!Array.isArray(btnIds) || btnIds.length === 0) return; + + const items: IToolbarButton[] = []; + btnIds.forEach(id => { + if (id === 'Separator') { + items.push({ Type: 'Separator' } as IToolbarButton); + } + else { + const btn = this.builtInButtons.find(i => i.Id === id); + if (btn) items.push(btn); + } + }); + + this.loadItems(items); + this.#hasChanges = true; + } + + public insertItems(btn: IToolbarButton, toIndex: number) { + this.#itemsCurrent.splice(toIndex, 0, btn); + this.#hasChanges = true; + + // reload buttons list + this.reloadCurrentItems(toIndex); + } + + private reloadAvailableItems() { + let html = ''; + + this.availableButtons.forEach((item, index) => { + let imageHtml = ''; + let textLang = item.Text; + + if (item.Type === 'Separator') { + textLang = '_._Separator'; + imageHtml = '
      '; + } + else { + if (!textLang) { + textLang = `FrmMain.${item.OnClick.Executable}`; + } + + imageHtml = ``; + } + + + html += ` +
    • +
      + ${imageHtml} + + +
      + +
      +
      +
    • `; + }); + + // render toolbar buttons list + this.#listAvailableEl.innerHTML = html; + + // load language + Language.loadForEl(this.#listAvailableEl); + + // add drag/drop events + queryAll('.btn-toolbar[draggable="true"]', this.#listAvailableEl).forEach(btnEl => { + btnEl.removeEventListener('dragstart', this.onBtnToolbarDragStart, false); + btnEl.addEventListener('dragstart', this.onBtnToolbarDragStart, false); + }); + + queryAll('.toolbar-item', this.#listAvailableEl).forEach(el => { + el.removeEventListener('dragend', this.onToolbarItemDragEnd, false); + el.addEventListener('dragend', this.onToolbarItemDragEnd, false); + }); + + // add action events + queryAll('[data-action]', this.#listAvailableEl).forEach(el => { + el.addEventListener('click', this.onToolbarActionButtonClicked, false); + }); + } + + private reloadCurrentItems(focusButtonIndex = -1) { + let html = ''; + + this.#itemsCurrent.forEach((item, index) => { + let imageHtml = ''; + let textLang = item.Text; + const disableEditing = this.isBuiltInButton(item) || item.Type === 'Separator'; + + if (item.Type === 'Separator') { + textLang = '_._Separator'; + imageHtml = '
      '; + } + else { + if (!textLang) { + textLang = `FrmMain.${item.OnClick.Executable}`; + } + + imageHtml = ``; + } + + + html += ` +
    • +
      + ${imageHtml} + ${textLang} + +
      + + + + + +
      +
      +
    • `; + }); + + // render toolbar buttons list + this.#listCurrentEl.innerHTML = html; + + // load language + Language.loadForEl(this.#listCurrentEl); + + // set focus to the item + if (focusButtonIndex >= 0) { + const movedItem = query(`.toolbar-item[data-index="${focusButtonIndex}"]`, this.#listCurrentEl); + + if (movedItem) { + movedItem.classList.add('drag--drop'); + pause(1000).then(() => { + if (movedItem) movedItem.classList.remove('drag--drop'); + }); + + query('.btn-toolbar', movedItem).focus(); + } + } + + // add drag/drop events + queryAll('.btn-toolbar[draggable="true"]', this.#listCurrentEl).forEach(btnEl => { + btnEl.removeEventListener('dragstart', this.onBtnToolbarDragStart, false); + btnEl.addEventListener('dragstart', this.onBtnToolbarDragStart, false); + }); + + queryAll('.toolbar-item', this.#listCurrentEl).forEach(el => { + el.removeEventListener('dragover', this.onToolbarItemDragOver, false); + el.addEventListener('dragover', this.onToolbarItemDragOver, false); + + el.removeEventListener('dragenter', (e) => this.onToolbarItemDragEnter(e, el), false); + el.addEventListener('dragenter', (e) => this.onToolbarItemDragEnter(e, el), false); + + el.removeEventListener('dragleave', (e) => this.onToolbarItemDragLeave(e, el), false); + el.addEventListener('dragleave', (e) => this.onToolbarItemDragLeave(e, el), false); + el.removeEventListener('dragend', this.onToolbarItemDragEnd, false); + el.addEventListener('dragend', this.onToolbarItemDragEnd, false); + + el.removeEventListener('drop', (e) => this.onToolbarItemDrop(e, el), false); + el.addEventListener('drop', (e) => this.onToolbarItemDrop(e, el), false); + }); + + // add action events + queryAll('[data-action]', this.#listCurrentEl).forEach(el => { + el.addEventListener('click', this.onToolbarActionButtonClicked, false); + }); + } + + private isBuiltInButton(btn: IToolbarButton) { + return this.builtInButtons.some(i => i.Id === btn.Id); + } + + + private onBtnToolbarDragStart(e: DragEvent) { + const btnEl = e.target as HTMLButtonElement; + const fromIndex = +btnEl.parentElement.getAttribute('data-index'); + const source = btnEl.closest('.toolbar-list').getAttribute('data-source'); + + // set drag data + this.#dragData = { fromSource: source, fromIndex }; + e.dataTransfer.effectAllowed = 'move'; + + // set custom drag image + e.dataTransfer.setDragImage(btnEl, -20, 0); + + // disable child el to receive drag events + queryAll('.btn-toolbar[draggable="true"]', this.#listCurrentEl).forEach(el => { + el.style.pointerEvents = 'none'; + }); + btnEl.style.pointerEvents = ''; + btnEl.style.opacity = '0.4'; + } + + private onToolbarItemDragEnter(e: DragEvent, dropEl: HTMLElement) { + e.preventDefault(); + const { fromSource, fromIndex } = this.#dragData; + const toIndex = +dropEl.getAttribute('data-index'); + const toSource = dropEl.closest('.toolbar-list').getAttribute('data-source'); + if (fromIndex === toIndex) return; + + const cssClass = ['drag--enter']; + if (fromIndex < toIndex && fromSource === toSource) { + cssClass.push('position--after'); + } + + dropEl.classList.add(...cssClass); + } + + private onToolbarItemDragOver(e: DragEvent) { + e.preventDefault(); + e.dataTransfer.dropEffect = 'move'; + } + + private onToolbarItemDragLeave(e: DragEvent, dropEL: HTMLElement) { + e.preventDefault(); + dropEL.classList.remove('drag--enter', 'position--after'); + } + + private onToolbarItemDragEnd(e: DragEvent) { + e.preventDefault(); + + // re-enable child el to receive drag events + queryAll('.btn-toolbar[draggable="true"]').forEach(el => { + el.style.pointerEvents = ''; + el.style.opacity = '1'; + }); + } + + private onToolbarItemDrop(e: DragEvent, toDropEl: HTMLElement) { + e.preventDefault(); + toDropEl.classList.remove('drag--enter', 'position--after'); + if (this.#dragData.fromIndex === -1) return; + + const { fromSource, fromIndex } = this.#dragData; + const toIndex = +toDropEl.getAttribute('data-index'); + const toSource = toDropEl.closest('.toolbar-list').getAttribute('data-source'); + this.#dragData = { fromSource: '', fromIndex: -1 }; + + // move item + if (fromSource === toSource) { + this.moveToolbarButton(fromIndex, toIndex); + } + // add item + else { + this.insertButtonFromAvailableList(fromIndex, toIndex); + } + } + + + private onToolbarActionButtonClicked(e: Event) { + e.stopPropagation(); + e.preventDefault(); + + const el = e.target as HTMLButtonElement; + const action = el.getAttribute('data-action').toLocaleLowerCase(); + const btnIndex = +el.closest('.toolbar-item').getAttribute('data-index'); + + if (action === 'move_up') { + this.moveToolbarButton(btnIndex, btnIndex - 1); + } + else if (action === 'move_down') { + this.moveToolbarButton(btnIndex, btnIndex + 1); + } + else if (action === 'edit') { + this.editToolbarButton(btnIndex); + } + else if (action === 'delete') { + this.deleteToolbarButton(btnIndex); + } + // add a button from the available buttons list to the current list + else if (action === 'add') { + this.insertButtonFromAvailableList(btnIndex); + } + } + + private moveToolbarButton(fromIndex: number, toIndex: number) { + if (toIndex < 0 ) toIndex = 0; + else if (toIndex > this.#itemsCurrent.length - 1) toIndex = this.#itemsCurrent.length - 1; + if (fromIndex === toIndex) return; + + // move button + arrayMoveMutable(this.#itemsCurrent, fromIndex, toIndex); + this.#hasChanges = true; + + // reload buttons list + this.reloadCurrentItems(toIndex); + + // set focus to the action button + const action = fromIndex < toIndex ? 'move_down' : 'move_up'; + query(`.toolbar-item[data-index="${toIndex}"] [data-action="${action}"]`)?.focus(); + } + + private deleteToolbarButton(btnIndex: number) { + // remove button + this.#itemsCurrent.splice(btnIndex, 1); + this.#hasChanges = true; + + // reload buttons list + this.reloadCurrentItems(btnIndex - 1); + this.reloadAvailableItems(); + } + + private insertButtonFromAvailableList(availableBtnIndex: number, toIndex?: number) { + const btn = this.availableButtons[availableBtnIndex]; + if (!btn) return; + + toIndex ??= this.#itemsCurrent.length; + this.#itemsCurrent.splice(toIndex, 0, btn); + this.#hasChanges = true; + + // reload buttons list + this.reloadCurrentItems(toIndex); + this.reloadAvailableItems(); + } + + private async editToolbarButton(btnIndex: number) { + const btn = this.#itemsCurrent[btnIndex]; + if (!btn || !this.#editButtonFn) return; + + const newBtn = await Promise.resolve(this.#editButtonFn({ + ...btn, + ImageUrl: undefined, + })); + if (!newBtn) return; + + this.#itemsCurrent[btnIndex] = newBtn; + this.#hasChanges = true; + this.reloadCurrentItems(btnIndex); + } +} + + +/** + * Creates and registers ToolbarEditorHtmlElement to DOM. + */ +export const defineToolbarEditorHtmlElement = () => window.customElements.define( + 'toolbar-editor', + ToolbarEditorHtmlElement, +); diff --git a/Source/Components/ImageGlass.Settings/WebUI/src/FrmUpdate.ts b/Source/Components/ImageGlass.Settings/WebUI/src/FrmUpdate.ts new file mode 100644 index 000000000..ec10bb7fa --- /dev/null +++ b/Source/Components/ImageGlass.Settings/WebUI/src/FrmUpdate.ts @@ -0,0 +1,29 @@ +import './main'; + + +const onButtonClicked = (e: Event) => { + e.preventDefault(); + e.stopPropagation(); + const btnEl = e.target as HTMLButtonElement; + + post(btnEl.id); +}; + +query('#BtnImageGlassStore').addEventListener('click', onButtonClicked, false); +query('#BtnUpdate').addEventListener('click', onButtonClicked, false); +query('#BtnClose').addEventListener('click', onButtonClicked, false); + +query('#BtnUpdate').focus(); + + +window._page.loadData = (data: Record = {}) => { + console.info('🔵 Loading data', data); + + query('#Lbl_CurrentVersion').innerText = data.CurrentVersion || ''; + query('#LbL_LatestVersion').innerText = data.LatestVersion || ''; + query('#Lbl_PublishedDate').innerText = data.PublishedDate || ''; + query('#Lnk_ReleaseLink').innerText = data.ReleaseTitle || ''; + query('#Lnk_ReleaseLink').setAttribute('href', data.ReleaseLink || ''); + query('#Section_ReleaseDetails').innerHTML = data.ReleaseDetails || ''; +}; + diff --git a/Source/Components/ImageGlass.Settings/WebUI/src/common/Language.ts b/Source/Components/ImageGlass.Settings/WebUI/src/common/Language.ts new file mode 100644 index 000000000..d35b759e1 --- /dev/null +++ b/Source/Components/ImageGlass.Settings/WebUI/src/common/Language.ts @@ -0,0 +1,84 @@ + +export default class Language { + /** + * Loads language for all elements. + */ + static load() { + for (const langKey in _page.lang) { + if (!Object.prototype.hasOwnProperty.call(_page.lang, langKey)) { + continue; + } + + const langValue = _page.lang[langKey]; + + queryAll(`[lang-text="${langKey}"]`, null, true).forEach(el => { + el.innerText = langValue; + }); + + queryAll(`[lang-title="${langKey}"]`, null, true).forEach(el => { + el.title = langValue; + }); + + queryAll(`[lang-html="${langKey}"]`, null, true).forEach(el => { + let html = langValue; + + for (let i = 0; i < el.childElementCount; i++) { + html = html.replaceAll(`{${i}}`, el.children.item(i).outerHTML); + } + + el.innerHTML = html; + }); + } + } + + + /** + * Loads language for the given element. + */ + static loadForEl(parentEl: HTMLElement) { + // lang text + const langTextEls = queryAll('[lang-text]', parentEl); + [parentEl, ...langTextEls].forEach(el => { + const langKey = el.getAttribute('lang-text') || ''; + const langValue = _page.lang[langKey] || ''; + if (langValue) { + el.innerText = langValue; + } + }); + + // lang title + const langTitleEls = queryAll('[lang-title]', parentEl); + [parentEl, ...langTitleEls].forEach(el => { + const langKey = el.getAttribute('lang-title') || ''; + const langValue = _page.lang[langKey] || ''; + if (langValue) { + el.title = langValue; + } + }); + + // lang html + const langHtmlEls = queryAll('[lang-html]', parentEl); + [parentEl, ...langHtmlEls].forEach(el => { + const langKey = el.getAttribute('lang-html') || ''; + const langValue = _page.lang[langKey] || ''; + if (langValue) { + let html = langValue; + + for (let i = 0; i < el.childElementCount; i++) { + html = html.replaceAll(`{${i}}`, el.children.item(i).outerHTML); + } + + el.innerHTML = html; + } + }); + } + + + /** + * Loads language for the given element. + */ + static loadFor(selector: string) { + const parentEl = query(selector); + Language.loadForEl(parentEl); + } +} diff --git a/Source/Components/ImageGlass.Settings/WebUI/src/helpers/globalHelpers.ts b/Source/Components/ImageGlass.Settings/WebUI/src/helpers/globalHelpers.ts new file mode 100644 index 000000000..d7747a4c8 --- /dev/null +++ b/Source/Components/ImageGlass.Settings/WebUI/src/helpers/globalHelpers.ts @@ -0,0 +1,112 @@ +import { pause } from '.'; +import { WebviewEventHandlerFn } from './webview'; + + +/** + * Gets the first matched element with the query selector. + */ +export const query = ( + selector: string, + parentEl: HTMLElement = null, + hideWarning = false, +): T | null => { + try { + const fromEl = parentEl ?? document; + const el = fromEl.querySelector(selector) as T; + + if (!el && !hideWarning) { + console.warn(`🟠 query() returns NULL with selector '${selector}'`); + } + + return el; + } + catch {} + + return null; +}; + + +/** + * Gets all matched elements with the query selector. + */ +export const queryAll = ( + selector: string, + parentEl: HTMLElement = null, + hideWarning = false, +) => { + try { + const fromEl = parentEl ?? document; + const els = Array.from(fromEl.querySelectorAll(selector)) as T[]; + + if (els.length === 0 && !hideWarning) { + console.info(`🔵 queryAll() returns ZERO elements with selector '${selector}'`); + } + + return els; + } + catch {} + + return []; +}; + + +/** + * Add event listerner from backend. + * @param name Event name + * @param handler Function to handle the event + */ +export const on = (name: string, handler: WebviewEventHandlerFn) => { + _webview.addEvent(name, handler); +}; + + +/** + * Send an event to backend. + * @param name Event name. + * @param data Data to send to backend, it will be converted to JSON string. + * @param convertToJson Converts {@link data} to JSON. Default value is `false`. + */ +export const post = (name: string, data?: any, convertToJson = false) => { + if (data instanceof FileList && !convertToJson) { + console.info('🔵 Calling webview.postMessageWithAdditionalObjects(): ', name, data); + + // @ts-ignore + window.chrome.webview?.postMessageWithAdditionalObjects({ name, data: null }, data); + return; + } + + const msgData = convertToJson ? JSON.stringify(data) : data; + console.info('🔵 Calling webview.postMessage(): ', name, msgData); + + // @ts-ignore + window.chrome.webview?.postMessage({ name, data: msgData }); +}; + + +/** + * Send an event to backend and wait for the returned data. + * @param name Event name + * @param data Data to send to backend, it will be converted to JSON string. + * @param convertToJson Converts {@link data} to JSON. Default value is `false`. + */ +export const postAsync = async (name: string, data?: any, convertToJson = false) => { + let hasResult = false; + let result: T = null; + + on(name, (eventName, eventData) => { + if (eventName !== name) return; + + hasResult = true; + result = eventData; + _webview.removeEvent(name); + }); + + post(name, data, convertToJson); + + // wait for the returned data + while (!hasResult) { + await pause(100); + } + + return result; +}; diff --git a/Source/Components/ImageGlass.Settings/WebUI/src/helpers/index.ts b/Source/Components/ImageGlass.Settings/WebUI/src/helpers/index.ts new file mode 100644 index 000000000..64ff38d66 --- /dev/null +++ b/Source/Components/ImageGlass.Settings/WebUI/src/helpers/index.ts @@ -0,0 +1,314 @@ +import Language from '@/common/Language'; + + +/** + * Pauses the thread for a period + * @param time Duration to pause in millisecond + * @param data Data to return after resuming + * @returns a promise + */ +export const pause = (time: number, data?: T): Promise => new Promise((resolve) => { + setTimeout(() => resolve(data as T), time); +}); + + +/** + * Gets the settings that are changed by user (`_pageSettings.config`) from the input tab. + */ +export const getChangedSettingsFromTab = (tab: string) => { + const result: Record = {}; + const inputEls = queryAll(`[tab="${tab}"] input[name]`); + const selectEls = queryAll(`[tab="${tab}"] select[name]`); + const allEls = [...inputEls, ...selectEls]; + + for (const el of allEls) { + const configName = el.name; + let configValue: boolean | number | string = ''; + if (el.name.startsWith('_')) continue; + if (!el.checkValidity()) continue; + + + // bool value + if (el.type === 'checkbox') { + configValue = (el as HTMLInputElement).checked; + } + // number value + else if (el.type === 'number') { + configValue = +el.value; + } + // string value + else { + configValue = el.value; + } + + if (configValue !== _pageSettings.config[configName]) { + result[configName] = configValue; + } + } + + return result; +}; + + +/** + * Escapes HTML characters. + */ +export const escapeHtml = (html: string) => { + return html + .replace(/&/g, '&') // & + .replace(//g, '>') // > + .replace(/"/g, '"'); // " +}; + + +/** + * Creates tagged template function. + * @example + * ```ts + * const imgTemplate = taggedTemplate`${'alt'}`; + * const html = imgTemplate({ + * src: 'https://imageglass.org/photo.jpg', + * alt: 'Photo from imageglass.org', + * }); + * ``` + * which is compiled as: + * ```html + * Photo from imageglass.org + * ``` + */ +export const taggedTemplate = >(strings: TemplateStringsArray, ...keys: string[]) => { + return (data: T) => { + const dict: Record = data || {}; + const result = [strings[0]]; + + keys.forEach((key, i) => { + const value = dict[key]; + result.push(value, strings[i + 1]); + }); + + return result.join(''); + }; +}; + + +/** + * Moves the item to the new position in the input array. + * Useful for huge arrays where absolute performance is needed. + * @param array - The array to modify. + * @param fromIndex - The index of the item to move. If negative, it will begin that many elements from the end. + * @param toIndex - The index of where to move the item. If negative, it will begin that many elements from the end. + * @example + * ```ts + * const input = ['a', 'b', 'c']; + * arrayMoveMutable(input, 1, 2); + * + * console.log(input); // => ['a', 'c', 'b'] + * ``` + */ +export const arrayMoveMutable = (array: Array, fromIndex: number, toIndex: number) => { + const startIndex = fromIndex < 0 ? array.length + fromIndex : fromIndex; + + if (startIndex >= 0 && startIndex < array.length) { + const endIndex = toIndex < 0 ? array.length + toIndex : toIndex; + + const [item] = array.splice(fromIndex, 1); + array.splice(endIndex, 0, item); + } +}; + + +/** + * Opens modal dialog. + * It returns `true` if the dialog form is submitted, otherwise `false`. + * @param dialogEl Dialog HTML element. + * @param data The data to pass to the dialog. + */ +export const openModalDialogEl = async ( + dialogEl: HTMLDialogElement, + purpose: 'create' | 'edit', + data: Record = {}, + onOpen?: (el: HTMLDialogElement) => any, + onSubmit?: (e: SubmitEvent) => boolean | Promise) => { + dialogEl.returnValue = ''; + dialogEl.classList.remove('dialog--create', 'dialog--edit'); + dialogEl.classList.add(`dialog--${purpose}`); + + // add shaking effect when clicking outside of dialog + dialogEl.addEventListener('click', async (e) => { + const el = e.target as HTMLDialogElement; + const rect = el.getBoundingClientRect(); + + // click on backdrop + if (rect.left > e.clientX + || rect.right < e.clientX + || rect.top > e.clientY + || rect.bottom < e.clientY) { + // shake the modal for 500ms + el.classList.add('ani-shaking'); + await pause(500); + el.classList.remove('ani-shaking'); + } + }, false); + + + const cancelDialogFn = () => dialogEl.close('false'); + const formSubmitFn = async (e: SubmitEvent) => { + if (onSubmit) { + e.stopImmediatePropagation(); + e.preventDefault(); + + const canProceed = await Promise.resolve(onSubmit(e)); + if (!canProceed) return; + } + + // isSubmitted = true; + dialogEl.close('true'); + }; + + // on submit + query('form', dialogEl).removeEventListener('submit', formSubmitFn, false); + query('form', dialogEl).addEventListener('submit', formSubmitFn, false); + + // on cancel + query('[data-dialog-action="close"]', dialogEl).removeEventListener('click', cancelDialogFn, false); + query('[data-dialog-action="close"]', dialogEl).addEventListener('click', cancelDialogFn, false); + + Object.keys(data).forEach(key => { + const inputEl = query(`[name="_${key}"]`, dialogEl); + if (inputEl) { + if (inputEl.type === 'checkbox') { + inputEl.checked = data[key] === true; + } + else { + inputEl.value = data[key]; + } + } + }); + + // on open + if (onOpen) await Promise.resolve(onOpen(dialogEl)); + + // open modal dialog + dialogEl.showModal(); + + while (!dialogEl.returnValue) { + await pause(100); + } + + return dialogEl.returnValue === 'true'; +}; + + +/** + * Opens modal dialog. + * It returns `true` if the dialog form is submitted, otherwise `false`. + * @param selector Dialog selector. + * @param data The data to pass to the dialog. + */ +export const openModalDialog = ( + selector: string, + purpose: 'create' | 'edit', + data: Record = {}, + onOpen?: (el: HTMLDialogElement) => any, + onSubmit?: (e: SubmitEvent) => boolean | Promise) => { + const dialogEl = query(selector); + return openModalDialogEl(dialogEl, purpose, data, onOpen, onSubmit); +}; + + +/** + * Open file picker. + */ +export const openFilePicker = async (options?: { + multiple?: boolean, + filter?: string, +}) => { + const filePaths = await postAsync('OpenFilePicker', options || {}, true); + + return filePaths; +}; + + +/** + * Open hotkey picker. + */ +export const openHotkeyPicker = async (): Promise => { + const hotkey = await postAsync('OpenHotkeyPicker'); + + return hotkey; +}; + + +/** + * Renders hotkey list + * @param ulEl The list HTML element + * @param hotkeys Hotkey list to render + */ +export const renderHotkeyListEl = async ( + ulEl: HTMLUListElement, + hotkeys: string[], + onChange?: (action: 'delete' | 'add') => any, +) => { + let ulHtml = ''; + + // load list of hotkeys + for (const key of hotkeys) { + ulHtml += ` +
    • + ${key} + +
    • `; + } + + // load 'Add hotkey' button + ulHtml += `
    • + +
    • `; + + ulEl.innerHTML = ulHtml; + Language.loadForEl(ulEl); + + // add event listerner for 'Delete' hotkey + queryAll('button[data-action]', ulEl).forEach(el => { + el.addEventListener('click', async () => { + const action = el.getAttribute('data-action'); + const newHotkeys = queryAll('.hotkey-item > kbd', ulEl) + .map(kbdEl => kbdEl.innerText); + + if (action === 'delete') { + const hotkeyItemEl = el.closest('.hotkey-item'); + hotkeyItemEl?.remove(); + if (onChange) await Promise.resolve(onChange(action)); + } + else if (action === 'add') { + const hotkey = await openHotkeyPicker(); + if (!hotkey) return; + + + renderHotkeyListEl(ulEl, [...newHotkeys, hotkey], onChange); + if (onChange) await Promise.resolve(onChange(action)); + + // set focus to the 'Add hotkey' button + query('button[data-action="add"]', ulEl)?.focus(); + } + }, false); + }); +}; + + +/** + * Renders hotkey list + * @param ulSelector CSS selector of the list element + * @param hotkeys Hotkey list to render + */ +export const renderHotkeyList = async ( + ulSelector: string, + hotkeys: string[], + onChange?: (action: 'delete' | 'add') => any, +) => { + const ulEl = query(ulSelector); + await renderHotkeyListEl(ulEl, hotkeys, onChange); +}; diff --git a/Source/Components/ImageGlass.Settings/WebUI/src/helpers/webview.ts b/Source/Components/ImageGlass.Settings/WebUI/src/helpers/webview.ts new file mode 100644 index 000000000..155d880d8 --- /dev/null +++ b/Source/Components/ImageGlass.Settings/WebUI/src/helpers/webview.ts @@ -0,0 +1,30 @@ + +export type WebviewEventHandlerFn = (name: string, data?: any) => void; + +export class Webview { + public eventHandlers: Record = {}; + + addEvent(name: string, handler: WebviewEventHandlerFn) { + this.eventHandlers[name] = handler; + } + + removeEvent(name: string) { + delete this.eventHandlers[name]; + } + + startListening() { + // @ts-ignore + window.chrome.webview?.addEventListener('message', ({ data }) => { + const eName = data?.Name ?? ''; + const eData = data?.Data ?? ''; + const handler = this.eventHandlers[eName]; + const hasHandler = handler !== undefined; + + console.info(`🔵 Received event '${eName}' (handler=${hasHandler}) with data:`, + typeof(eData) === 'string' ? `${eData.substring(0, 100)}...` : eData); + + if (!hasHandler) return; + handler(eName, eData); + }); + } +} diff --git a/Source/Components/ImageGlass.Settings/WebUI/src/main.ts b/Source/Components/ImageGlass.Settings/WebUI/src/main.ts new file mode 100644 index 000000000..3c23a615f --- /dev/null +++ b/Source/Components/ImageGlass.Settings/WebUI/src/main.ts @@ -0,0 +1,91 @@ +import './styles/main.scss'; + +import { Webview } from './helpers/webview'; +import { query, queryAll, on, post, postAsync } from './helpers/globalHelpers'; +import Language from './common/Language'; +import { pause } from './helpers'; + +// initialize webview event listeners +window._webview = new Webview(); +_webview.startListening(); + + +// export to global +window.query = query; +window.queryAll = queryAll; +window.on = on; +window.post = post; +window.postAsync = postAsync; + +if (!window._page) { + window._page = { + lang: {}, + theme: '', + isWindows10: false, + }; +} +_page.loadLanguage = Language.load; + + +// enable transition after 1 second +pause(1000).then(() => { + document.documentElement.style.setProperty('--transitionMs', '300ms'); +}); + + +const getHotkeys = (e: KeyboardEvent) => { + let key = e.key.toLowerCase(); + + const ctrl = e.ctrlKey + ? 'ctrl' + : (key === 'control' ? 'ctrl' : ''); + const shift = e.shiftKey + ? 'shift' + : (key === 'shift' ? 'shift' : ''); + const alt = e.altKey + ? 'alt' + : (key === 'alt' ? 'alt' : ''); + + + const keyMaps: Record = { + control: '', + shift: '', + alt: '', + arrowleft: 'left', + arrowright: 'right', + arrowup: 'up', + arrowdown: 'down', + backspace: 'back', + ' ': 'space', + }; + + if (keyMaps[key] !== undefined) { + key = keyMaps[key]; + } + + const hotkeys = [ctrl, shift, alt, key].filter(Boolean).join('+'); + + return hotkeys; +}; + +// handle keydown event +window.onkeydown = (e: KeyboardEvent) => { + const hotkeys = getHotkeys(e); + + // preserve ESCAPE key for closing HTML5 dialog + if (hotkeys === 'escape' && document.querySelector('dialog[open]')) { + return; + } + + if (!hotkeys) return; + post('KEYDOWN', hotkeys); +}; + + +// handle keyup event +window.onkeyup = (e: KeyboardEvent) => { + const hotkeys = getHotkeys(e); + + if (!hotkeys) return; + post('KEYUP', hotkeys); +}; diff --git a/Source/Components/ImageGlass.Settings/WebUI/src/styles/basis/_mixins.scss b/Source/Components/ImageGlass.Settings/WebUI/src/styles/basis/_mixins.scss new file mode 100644 index 000000000..54536e691 --- /dev/null +++ b/Source/Components/ImageGlass.Settings/WebUI/src/styles/basis/_mixins.scss @@ -0,0 +1,60 @@ + + +@mixin focusAnimation() { + animation: aniFocus 1000ms ease forwards; +} + + +@mixin baseControl() { + --focus-color: var(--Accent); + + min-width: calc(var(--controlHeight) * 1px); + width: calc(var(--controlWidth) * 1px); + min-height: calc(var(--controlHeight) * 1px); + padding: 0.325rem; + font-size: inherit; + font-family: var(--fontBase); + color: rgb(var(--AppText)); + background-color: rgb(var(--ControlBg)); + border-radius: var(--borderRadius); + border: 0.1rem solid var(--ControlBorder); + transition: background ease var(--transitionMs), + border ease var(--transitionMs), + box-shadow ease var(--transitionMs); + + &::selection { + background-color: rgb(var(--Accent) / 0.55); + } + + &:hover { + background-color: rgb(var(--ControlBgHover)); + border-color: var(--ControlBorderHover); + } + &:focus { + outline: none; + border-color: rgb(var(--Accent)); + } + &:focus-visible { + @include focusAnimation(); + } + &:active { + background-color: rgb(var(--ControlBgPressed)); + border-color: rgb(var(--Accent)); + transition: background ease 80ms, border ease 80ms, shadow ease 80ms; + } + &:invalid { + border-color: rgb(var(--BgDanger)); + + &:focus-visible { + --focus-color: var(--BgDanger); + @include focusAnimation(); + } + } + + &[disabled], + &:disabled { + color: rgb(var(--AppText) / 0.45); + border-color: var(--ControlBorderDisabled); + background-color: rgb(var(--ControlBgDisabled)); + } +} diff --git a/Source/Components/ImageGlass.Settings/WebUI/src/styles/basis/_vars.scss b/Source/Components/ImageGlass.Settings/WebUI/src/styles/basis/_vars.scss new file mode 100644 index 000000000..f898a8a03 --- /dev/null +++ b/Source/Components/ImageGlass.Settings/WebUI/src/styles/basis/_vars.scss @@ -0,0 +1,67 @@ + +// theme colors (dark is default) +:root, +::backdrop { + --InvertColor: 255 255 255; + --AppBg: 20 25 28; + --AppText: 210 210 210; + --AppTextDisabled: 140 140 140; + --Accent: 173 96 69; + --ControlBg: 60 63 64; + --ControlBgHover: 87 91 92; + --ControlBgPressed: 43 43 43; + --ControlBgPressed2: 49 51 53; + --ControlBgDisabled: 78 78 78; + + --ControlCtaBg: rgb(var(--Accent) / 0.2); + --ControlCtaBgHover: rgb(var(--Accent) / 0.3); + --ControlBorder: rgb(var(--InvertColor) / 0.2); + --ControlBorderHover: rgb(var(--InvertColor) / 0.3); + --ControlBorderDisabled: rgb(var(--InvertColor) / 0.02); + --ControlCtaBorder: rgb(var(--InvertColor) / 0.2); + --ControlCtaBorderHover: rgb(var(--InvertColor) / 0.4); + + --BgNeutral: 32 38 43; + --BgInfo: 0 134 214; + --BgSuccess: 0 210 80; + --BgWarning: 255 139 0; + --BgDanger: 255 0 83; + + --controlWidth: calc(200 * var(--fontScale)); + --controlHeight: calc(28 * var(--fontScale)); + --baseBorderRadius: 0.2rem; + --borderRadius: calc(var(--baseBorderRadius) * var(--fontScale)); + --shadow: 0 0.1rem 0.8rem -0.4rem rgb(0 0 0 / 50%); + --scrollbarSizePx: calc(0.875rem * var(--fontScale)); + --transitionMs: 0ms; // disable from the begining + + --fontSize: 12.5; + --designFontSize: 12.5; + --fontScale: var(--fontSize) / var(--designFontSize); + --fontBase: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI Variant", "Segoe UI"; + --fontCode: ui-monospace, SFMono-Regular, "SF Mono", Consolas, "Liberation Mono", Menlo, monospace; +} + +// light mode +html[color-mode=light], +html[color-mode=light] ::backdrop { + --InvertColor: 0 0 0; + --AppBg: 255 255 255; + --AppText: 30 30 30; + --AppTextDisabled: 113 113 113; + --ControlBg: 245 245 250; + --ControlBgHover: 235 235 240; + --ControlBgPressed: 220 220 220; + --ControlBgPressed2: 230 231 234; + --ControlBgDisabled: 220 220 220; + + --ControlCtaBg: rgb(var(--Accent) / 0.15); + --ControlCtaBgHover: rgb(var(--Accent) / 0.25); + --ControlBorder: rgb(var(--InvertColor) / 0.2); + --ControlBorderHover: rgb(var(--InvertColor) / 0.3); + --ControlCtaBorder: rgb(var(--InvertColor) / 0.2); + --ControlCtaBorderHover: rgb(var(--InvertColor) / 0.3); + + --BgNeutral: 242 242 242; +} + diff --git a/Source/Components/ImageGlass.Settings/WebUI/src/styles/basis/animation.scss b/Source/Components/ImageGlass.Settings/WebUI/src/styles/basis/animation.scss new file mode 100644 index 000000000..0c8294672 --- /dev/null +++ b/Source/Components/ImageGlass.Settings/WebUI/src/styles/basis/animation.scss @@ -0,0 +1,43 @@ +.aniFadeIn { + animation: animationFadeIn ease 500ms forwards; +} + +@keyframes animationFadeIn { + from { opacity: 0; } + to { opacity: 1; } +} + + +.ani-shaking { + animation: animationShaking 500ms cubic-bezier(0.36, 0.07, 0.19, 0.97) both; + transform: translate3d(0, 0, 0); + backface-visibility: hidden; + perspective: 1000px; + perspective-origin: center; +} + +@keyframes animationShaking { + 10%, 90% { + transform: translateX(-2px); + } + 20%, 80% { + transform: translateX(1px); + } + 30%, 50%, 70% { + transform: translateX(-1px); + } + 40%, 60% { + transform: translateX(2px); + } +} + + +@keyframes aniFocus { + 0% { + border-color: rgb(var(--focus-color, var(--Accent))); + box-shadow: 0 0 0 0.1rem rgb(var(--focus-color, var(--Accent))); + } + 100% { + box-shadow: 0 0 0 0 rgb(var(--focus-color, var(--Accent))); + } +} diff --git a/Source/Components/ImageGlass.Settings/WebUI/src/styles/basis/reset.scss b/Source/Components/ImageGlass.Settings/WebUI/src/styles/basis/reset.scss new file mode 100644 index 000000000..9e51086b2 --- /dev/null +++ b/Source/Components/ImageGlass.Settings/WebUI/src/styles/basis/reset.scss @@ -0,0 +1,368 @@ +*, +*::before, +*::after { + box-sizing: border-box; + -webkit-user-select: none; + user-select: none; +} +*:not([draggable]) { + -webkit-user-drag: none; + user-drag: none; +} + +html { + font-family: var(--fontBase); + font-size: calc(var(--fontSize) * 1px); + color: rgb(var(--AppText)); + accent-color: rgb(var(--Accent)); + overflow: hidden; + transition: background ease var(--transitionMs); +} +body { + margin: 0; + height: 100vh; + max-height: 100vh; + overflow: auto; + line-height: normal; +} + +pre, +code, +kbd, +samp { + font-family: var(--fontCode); + font-size: 1em; +} + +pre { + overflow-x: hidden; + white-space: pre-wrap; + word-wrap: break-word; +} + +sup, +sub { + font-size: 60%; +} + +kbd { + display: inline-block; + padding: 3px 5px; + font-size: 85%; + font-family: var(--fontCode); + vertical-align: middle; + white-space: nowrap; + + background-color: rgb(var(--ControlBg) / 1); + border: solid 1px rgb(var(--InvertColor) / 0.1); + border-bottom-color: rgb(var(--InvertColor) / 0.1); + border-radius: var(--borderRadius); + box-shadow: inset 0 -1px 0 rgb(var(--InvertColor) / 0.1); +} + +b, +strong { + font-weight: 500; +} + +p { + margin-top: 0.5em; + margin-bottom: 1em; +} + +p:last-of-type { + margin-bottom: 0; +} + +hr { + margin: 1rem 0; + height: 0.05rem; + background-color: rgb(var(--AppText) / 0.3); + border: 0; +} + +ul { + padding-left: 1.5rem; + margin-top: 0; +} + +h1, +h2, +h3, +h4, +h5 { + font-weight: 500; +} + +a, +a:visited { + display: inline-block; + text-underline-position: under; + transition: background ease var(--transitionMs); + color: rgb(var(--Accent)); + border-radius: var(--borderRadius); + padding: 0 0.125em 0.1em 0.125em; +} +a { + --focus-color: var(--Accent); + cursor: default; + + &:focus-visible, + &:hover { + color: rgb(var(--Accent)); + background-color: rgb(var(--InvertColor) / 0.1); + filter: brightness(1.2); + } + &:focus-visible { + outline: none; + box-shadow: inset 0 0 0 1px rgb(var(--Accent) / 0.1); + @include focusAnimation(); + } + &:active { + background-color: rgb(var(--InvertColor) / 0.05); + filter: brightness(0.95); + transition: background ease calc(var(--transitionMs) / 3); + } + + &[disabled] { + opacity: 0.5; + pointer-events: none; + color: var(--AppText); + } +} +html[color-mode=light] a { + &:focus-visible, + &:hover { + filter: brightness(0.8); + } + &:active { + filter: brightness(1.05); + } +} + + +// Figures +// +// Apply a consistent margin strategy (matches our type styles). +figure { + margin: 0 0 1rem; +} + + +// Images and content +img, +svg { + vertical-align: middle; +} + + +// Tables +// +// Prevent double borders +table { + caption-side: bottom; + border-collapse: collapse; +} + +// 1. Removes font-weight bold by inheriting +// 2. Matches default `` alignment by inheriting `text-align`. +// 3. Fix alignment for Safari +th { + font-weight: 500; // 1 + text-align: inherit; // 2 + text-align: match-parent; // 3 + text-align: -webkit-match-parent; // 3 +} +thead, +tbody, +tfoot, +tr, +td, +th { + border-color: inherit; + border-style: solid; + border-width: 0; +} + + +// Forms +// +// 1. Allow labels to use `margin` for spacing. +label { + display: inline-block; // 1 +} + + +// 1. Remove the margin in Firefox and Safari +input, +button, +select, +optgroup, +textarea { + margin: 0; // 1 + font-family: inherit; + line-height: inherit; +} + + +// Remove the inheritance of text transform in Firefox +button, +select { + text-transform: none; +} +// Set the cursor for non-`